summaryrefslogtreecommitdiff
path: root/chromium/components
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2022-05-12 15:59:20 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2022-05-25 06:57:22 +0000
commitf7eaed5286974984ba5f9e3189d8f49d03e99f81 (patch)
treecaed19b2af2024f35449fb0b781d0a25e09d4f8f /chromium/components
parent9729c4479fe23554eae6e6dd1f30ff488f470c84 (diff)
downloadqtwebengine-chromium-f7eaed5286974984ba5f9e3189d8f49d03e99f81.tar.gz
BASELINE: Update Chromium to 100.0.4896.167
Change-Id: I98cbeb5d7543d966ffe04d8cefded0c493a11333 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/components')
-rw-r--r--chromium/components/BUILD.gn109
-rw-r--r--chromium/components/about_ui/resources/about_credits.css129
-rw-r--r--chromium/components/about_ui/resources/about_credits.tmpl105
-rw-r--r--chromium/components/account_manager_core/BUILD.gn1
-rw-r--r--chromium/components/account_manager_core/account_addition_options.h24
-rw-r--r--chromium/components/account_manager_core/account_manager_facade_impl.cc63
-rw-r--r--chromium/components/account_manager_core/account_manager_facade_impl.h25
-rw-r--r--chromium/components/account_manager_core/account_manager_facade_impl_unittest.cc107
-rw-r--r--chromium/components/account_manager_core/account_manager_util.cc15
-rw-r--r--chromium/components/account_manager_core/account_manager_util.h6
-rw-r--r--chromium/components/account_manager_core/chromeos/account_manager.cc165
-rw-r--r--chromium/components/account_manager_core/chromeos/account_manager.h95
-rw-r--r--chromium/components/account_manager_core/chromeos/account_manager_mojo_service.cc3
-rw-r--r--chromium/components/account_manager_core/chromeos/account_manager_mojo_service.h3
-rw-r--r--chromium/components/account_manager_core/chromeos/account_manager_mojo_service_unittest.cc22
-rw-r--r--chromium/components/account_manager_core/chromeos/account_manager_ui.h5
-rw-r--r--chromium/components/account_manager_core/chromeos/account_manager_unittest.cc29
-rw-r--r--chromium/components/account_manager_core/chromeos/fake_account_manager_ui.cc1
-rw-r--r--chromium/components/account_manager_core/chromeos/fake_account_manager_ui.h4
-rw-r--r--chromium/components/account_manager_core/pref_names.cc5
-rw-r--r--chromium/components/account_manager_core/pref_names.h3
-rw-r--r--chromium/components/accuracy_tips/accuracy_service.cc13
-rw-r--r--chromium/components/android_autofill/browser/java/src/org/chromium/components/autofill/AutofillManagerWrapper.java4
-rw-r--r--chromium/components/android_autofill/browser/java/src/org/chromium/components/autofill/AutofillProvider.java4
-rw-r--r--chromium/components/android_autofill/browser/java/src/org/chromium/components/autofill_public/ViewType.java5
-rw-r--r--chromium/components/android_autofill/browser/test_support/java/src/org/chromium/components/autofill/AutofillProviderTestHelper.java5
-rw-r--r--chromium/components/app_constants/BUILD.gn16
-rw-r--r--chromium/components/app_constants/DIR_METADATA1
-rw-r--r--chromium/components/app_constants/OWNERS1
-rw-r--r--chromium/components/app_constants/constants.cc14
-rw-r--r--chromium/components/app_constants/constants.h26
-rw-r--r--chromium/components/app_restore/BUILD.gn9
-rw-r--r--chromium/components/app_restore/DEPS4
-rw-r--r--chromium/components/app_restore/app_restore_data.cc50
-rw-r--r--chromium/components/app_restore/app_restore_utils.cc71
-rw-r--r--chromium/components/app_restore/app_restore_utils.h27
-rw-r--r--chromium/components/app_restore/arc_read_handler.cc11
-rw-r--r--chromium/components/app_restore/arc_read_handler.h23
-rw-r--r--chromium/components/app_restore/arc_save_handler.h15
-rw-r--r--chromium/components/app_restore/desk_template_read_handler.cc12
-rw-r--r--chromium/components/app_restore/desk_template_read_handler.h4
-rw-r--r--chromium/components/app_restore/features.cc18
-rw-r--r--chromium/components/app_restore/features.h14
-rw-r--r--chromium/components/app_restore/full_restore_info.cc4
-rw-r--r--chromium/components/app_restore/full_restore_info.h18
-rw-r--r--chromium/components/app_restore/full_restore_read_and_save_unittest.cc300
-rw-r--r--chromium/components/app_restore/full_restore_read_handler.cc129
-rw-r--r--chromium/components/app_restore/full_restore_read_handler.h49
-rw-r--r--chromium/components/app_restore/full_restore_save_handler.cc139
-rw-r--r--chromium/components/app_restore/full_restore_save_handler.h44
-rw-r--r--chromium/components/app_restore/full_restore_utils.cc47
-rw-r--r--chromium/components/app_restore/full_restore_utils.h17
-rw-r--r--chromium/components/app_restore/lacros_read_handler.cc158
-rw-r--r--chromium/components/app_restore/lacros_read_handler.h122
-rw-r--r--chromium/components/app_restore/lacros_save_handler.cc154
-rw-r--r--chromium/components/app_restore/lacros_save_handler.h89
-rw-r--r--chromium/components/app_restore/restore_data.cc43
-rw-r--r--chromium/components/app_restore/restore_data.h7
-rw-r--r--chromium/components/app_restore/restore_data_unittest.cc10
-rw-r--r--chromium/components/app_restore/window_properties.cc1
-rw-r--r--chromium/components/app_restore/window_properties.h4
-rw-r--r--chromium/components/arc/BUILD.gn18
-rw-r--r--chromium/components/arc/DEPS2
-rw-r--r--chromium/components/arc/common/BUILD.gn34
-rw-r--r--chromium/components/arc/common/intent_helper/DEPS6
-rw-r--r--chromium/components/arc/common/intent_helper/activity_icon_loader.cc44
-rw-r--r--chromium/components/arc/common/intent_helper/arc_icon_cache_delegate.cc46
-rw-r--r--chromium/components/arc/common/intent_helper/arc_icon_cache_delegate.h55
-rw-r--r--chromium/components/arc/common/intent_helper/arc_intent_helper_mojo_delegate.cc63
-rw-r--r--chromium/components/arc/common/intent_helper/arc_intent_helper_mojo_delegate.h150
-rw-r--r--chromium/components/arc/common/intent_helper/arc_intent_helper_package.h18
-rw-r--r--chromium/components/arc/common/intent_helper/link_handler_model.cc (renamed from chromium/components/arc/intent_helper/link_handler_model.cc)106
-rw-r--r--chromium/components/arc/common/intent_helper/link_handler_model.h (renamed from chromium/components/arc/intent_helper/link_handler_model.h)28
-rw-r--r--chromium/components/arc/common/intent_helper/link_handler_model_unittest.cc (renamed from chromium/components/arc/intent_helper/link_handler_model_unittest.cc)2
-rw-r--r--chromium/components/arc/intent_helper/arc_intent_helper_bridge.cc58
-rw-r--r--chromium/components/arc/intent_helper/arc_intent_helper_bridge.h50
-rw-r--r--chromium/components/arc/intent_helper/arc_intent_helper_bridge_unittest.cc166
-rw-r--r--chromium/components/arc/intent_helper/arc_intent_helper_observer.h6
-rw-r--r--chromium/components/arc/intent_helper/intent_filter.cc100
-rw-r--r--chromium/components/arc/intent_helper/intent_filter.h7
-rw-r--r--chromium/components/arc/intent_helper/intent_filter_unittest.cc375
-rw-r--r--chromium/components/assist_ranker/BUILD.gn4
-rw-r--r--chromium/components/assist_ranker/OWNERS2
-rw-r--r--chromium/components/assist_ranker/binary_classifier_predictor.h13
-rw-r--r--chromium/components/assist_ranker/classifier_predictor.h14
-rw-r--r--chromium/components/assist_ranker/predictor_config_definitions.cc5
-rw-r--r--chromium/components/assist_ranker/predictor_config_definitions.h4
-rw-r--r--chromium/components/assist_ranker/ranker_example_util.h19
-rw-r--r--chromium/components/assist_ranker/ranker_model_loader_impl.cc4
-rw-r--r--chromium/components/autofill/android/BUILD.gn51
-rw-r--r--chromium/components/autofill/android/payments/java/res/drawable-hdpi/amex_card.pngbin0 -> 739 bytes
-rw-r--r--chromium/components/autofill/android/payments/java/res/drawable-hdpi/diners_card.pngbin0 -> 1377 bytes
-rw-r--r--chromium/components/autofill/android/payments/java/res/drawable-hdpi/jcb_card.pngbin0 -> 751 bytes
-rw-r--r--chromium/components/autofill/android/payments/java/res/drawable-hdpi/mc_card.pngbin0 -> 965 bytes
-rw-r--r--chromium/components/autofill/android/payments/java/res/drawable-hdpi/troy_card.pngbin0 -> 1634 bytes
-rw-r--r--chromium/components/autofill/android/payments/java/res/drawable-hdpi/unionpay_card.pngbin0 -> 1298 bytes
-rw-r--r--chromium/components/autofill/android/payments/java/res/drawable-mdpi/amex_card.pngbin0 -> 447 bytes
-rw-r--r--chromium/components/autofill/android/payments/java/res/drawable-mdpi/diners_card.pngbin0 -> 876 bytes
-rw-r--r--chromium/components/autofill/android/payments/java/res/drawable-mdpi/jcb_card.pngbin0 -> 479 bytes
-rw-r--r--chromium/components/autofill/android/payments/java/res/drawable-mdpi/mc_card.pngbin0 -> 669 bytes
-rw-r--r--chromium/components/autofill/android/payments/java/res/drawable-mdpi/troy_card.pngbin0 -> 970 bytes
-rw-r--r--chromium/components/autofill/android/payments/java/res/drawable-mdpi/unionpay_card.pngbin0 -> 800 bytes
-rw-r--r--chromium/components/autofill/android/payments/java/res/drawable-xhdpi/amex_card.pngbin0 -> 1010 bytes
-rw-r--r--chromium/components/autofill/android/payments/java/res/drawable-xhdpi/diners_card.pngbin0 -> 1669 bytes
-rw-r--r--chromium/components/autofill/android/payments/java/res/drawable-xhdpi/jcb_card.pngbin0 -> 823 bytes
-rw-r--r--chromium/components/autofill/android/payments/java/res/drawable-xhdpi/mc_card.pngbin0 -> 1318 bytes
-rw-r--r--chromium/components/autofill/android/payments/java/res/drawable-xhdpi/troy_card.pngbin0 -> 2410 bytes
-rw-r--r--chromium/components/autofill/android/payments/java/res/drawable-xhdpi/unionpay_card.pngbin0 -> 1617 bytes
-rw-r--r--chromium/components/autofill/android/payments/java/res/drawable-xxhdpi/amex_card.pngbin0 -> 1531 bytes
-rw-r--r--chromium/components/autofill/android/payments/java/res/drawable-xxhdpi/diners_card.pngbin0 -> 2209 bytes
-rw-r--r--chromium/components/autofill/android/payments/java/res/drawable-xxhdpi/jcb_card.pngbin0 -> 1193 bytes
-rw-r--r--chromium/components/autofill/android/payments/java/res/drawable-xxhdpi/mc_card.pngbin0 -> 1692 bytes
-rw-r--r--chromium/components/autofill/android/payments/java/res/drawable-xxhdpi/troy_card.pngbin0 -> 3581 bytes
-rw-r--r--chromium/components/autofill/android/payments/java/res/drawable-xxhdpi/unionpay_card.pngbin0 -> 2120 bytes
-rw-r--r--chromium/components/autofill/android/payments/java/res/drawable-xxxhdpi/amex_card.pngbin0 -> 1901 bytes
-rw-r--r--chromium/components/autofill/android/payments/java/res/drawable-xxxhdpi/diners_card.pngbin0 -> 2803 bytes
-rw-r--r--chromium/components/autofill/android/payments/java/res/drawable-xxxhdpi/jcb_card.pngbin0 -> 1583 bytes
-rw-r--r--chromium/components/autofill/android/payments/java/res/drawable-xxxhdpi/mc_card.pngbin0 -> 2088 bytes
-rw-r--r--chromium/components/autofill/android/payments/java/res/drawable-xxxhdpi/troy_card.pngbin0 -> 5289 bytes
-rw-r--r--chromium/components/autofill/android/payments/java/res/drawable-xxxhdpi/unionpay_card.pngbin0 -> 2646 bytes
-rw-r--r--chromium/components/autofill/android/payments/java/res/drawable/discover_card.xml13
-rw-r--r--chromium/components/autofill/android/payments/java/res/drawable/elo_card.xml15
-rw-r--r--chromium/components/autofill/android/payments/java/res/drawable/google_pay_plex.xml34
-rw-r--r--chromium/components/autofill/android/payments/java/res/drawable/ic_credit_card_black.xml24
-rw-r--r--chromium/components/autofill/android/payments/java/res/drawable/mir_card.xml9
-rw-r--r--chromium/components/autofill/android/payments/java/res/drawable/visa_card.xml7
-rw-r--r--chromium/components/autofill/content/browser/content_autofill_driver.cc52
-rw-r--r--chromium/components/autofill/content/browser/content_autofill_driver.h8
-rw-r--r--chromium/components/autofill/content/browser/content_autofill_driver_factory_unittest.cc31
-rw-r--r--chromium/components/autofill/content/browser/content_autofill_driver_test_api.h4
-rw-r--r--chromium/components/autofill/content/browser/content_autofill_driver_unittest.cc64
-rw-r--r--chromium/components/autofill/content/browser/content_autofill_router.cc1
-rw-r--r--chromium/components/autofill/content/browser/form_forest.cc14
-rw-r--r--chromium/components/autofill/content/browser/form_forest.h6
-rw-r--r--chromium/components/autofill/content/browser/form_forest_unittest.cc104
-rw-r--r--chromium/components/autofill/content/browser/risk/fingerprint.cc25
-rw-r--r--chromium/components/autofill/content/browser/risk/fingerprint_browsertest.cc6
-rw-r--r--chromium/components/autofill/content/common/mojom/autofill_agent.mojom5
-rw-r--r--chromium/components/autofill/content/renderer/autofill_agent.cc169
-rw-r--r--chromium/components/autofill/content/renderer/autofill_agent.h11
-rw-r--r--chromium/components/autofill/content/renderer/focus_test_utils.cc7
-rw-r--r--chromium/components/autofill/content/renderer/form_autofill_util.cc88
-rw-r--r--chromium/components/autofill/content/renderer/form_autofill_util.h8
-rw-r--r--chromium/components/autofill/content/renderer/form_autofill_util_browsertest.cc56
-rw-r--r--chromium/components/autofill/content/renderer/form_cache.cc31
-rw-r--r--chromium/components/autofill/content/renderer/form_cache_browsertest.cc9
-rw-r--r--chromium/components/autofill/content/renderer/form_cache_test_api.h1
-rw-r--r--chromium/components/autofill/content/renderer/form_tracker.cc7
-rw-r--r--chromium/components/autofill/content/renderer/html_based_username_detector.cc20
-rw-r--r--chromium/components/autofill/content/renderer/html_based_username_detector_browsertest.cc4
-rw-r--r--chromium/components/autofill/content/renderer/page_form_analyser_logger.cc22
-rw-r--r--chromium/components/autofill/content/renderer/page_passwords_analyser.cc20
-rw-r--r--chromium/components/autofill/content/renderer/password_autofill_agent.cc187
-rw-r--r--chromium/components/autofill/content/renderer/password_autofill_agent.h9
-rw-r--r--chromium/components/autofill/content/renderer/password_form_conversion_utils.cc11
-rw-r--r--chromium/components/autofill/content/renderer/password_generation_agent.cc32
-rw-r--r--chromium/components/autofill/core/browser/BUILD.gn42
-rw-r--r--chromium/components/autofill/core/browser/OWNERS2
-rw-r--r--chromium/components/autofill/core/browser/address_profile_save_manager.cc17
-rw-r--r--chromium/components/autofill/core/browser/address_profile_save_manager.h6
-rw-r--r--chromium/components/autofill/core/browser/address_profile_save_manager_unittest.cc159
-rw-r--r--chromium/components/autofill/core/browser/autocomplete_history_manager_unittest.cc2
-rw-r--r--chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.css256
-rw-r--r--chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.html259
-rw-r--r--chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.js6
-rw-r--r--chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals_ios.html51
-rw-r--r--chromium/components/autofill/core/browser/autofill_client.cc35
-rw-r--r--chromium/components/autofill/core/browser/autofill_client.h51
-rw-r--r--chromium/components/autofill/core/browser/autofill_download_manager.cc27
-rw-r--r--chromium/components/autofill/core/browser/autofill_download_manager_unittest.cc2
-rw-r--r--chromium/components/autofill/core/browser/autofill_driver.h4
-rw-r--r--chromium/components/autofill/core/browser/autofill_experiments.cc6
-rw-r--r--chromium/components/autofill/core/browser/autofill_external_delegate.cc38
-rw-r--r--chromium/components/autofill/core/browser/autofill_external_delegate.h3
-rw-r--r--chromium/components/autofill/core/browser/autofill_external_delegate_unittest.cc52
-rw-r--r--chromium/components/autofill/core/browser/autofill_field.h15
-rw-r--r--chromium/components/autofill/core/browser/autofill_form_test_utils.cc138
-rw-r--r--chromium/components/autofill/core/browser/autofill_form_test_utils.h36
-rw-r--r--chromium/components/autofill/core/browser/autofill_manager.cc3
-rw-r--r--chromium/components/autofill/core/browser/autofill_manager.h9
-rw-r--r--chromium/components/autofill/core/browser/autofill_merge_unittest.cc7
-rw-r--r--chromium/components/autofill/core/browser/autofill_profile_import_process.cc22
-rw-r--r--chromium/components/autofill/core/browser/autofill_profile_import_process.h8
-rw-r--r--chromium/components/autofill/core/browser/autofill_profile_sync_util.cc12
-rw-r--r--chromium/components/autofill/core/browser/autofill_profile_sync_util_unittest.cc6
-rw-r--r--chromium/components/autofill/core/browser/autofill_profile_validation_util.cc371
-rw-r--r--chromium/components/autofill/core/browser/autofill_profile_validation_util.h37
-rw-r--r--chromium/components/autofill/core/browser/autofill_profile_validation_util_unittest.cc1133
-rw-r--r--chromium/components/autofill/core/browser/autofill_profile_validator.cc128
-rw-r--r--chromium/components/autofill/core/browser/autofill_profile_validator.h104
-rw-r--r--chromium/components/autofill/core/browser/autofill_regex_constants.cc4
-rw-r--r--chromium/components/autofill/core/browser/autofill_suggestion_generator.cc22
-rw-r--r--chromium/components/autofill/core/browser/autofill_suggestion_generator_unittest.cc1
-rw-r--r--chromium/components/autofill/core/browser/autofill_test_utils.cc45
-rw-r--r--chromium/components/autofill/core/browser/autofill_test_utils.h14
-rw-r--r--chromium/components/autofill/core/browser/browser_autofill_manager.cc110
-rw-r--r--chromium/components/autofill/core/browser/browser_autofill_manager.h22
-rw-r--r--chromium/components/autofill/core/browser/browser_autofill_manager_unittest.cc498
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_data_model.cc6
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_data_model.h4
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_profile.cc275
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_profile.h82
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_profile_unittest.cc874
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_structured_address_regex_provider.cc1
-rw-r--r--chromium/components/autofill/core/browser/data_model/autofill_structured_address_utils.cc1
-rw-r--r--chromium/components/autofill/core/browser/data_model/credit_card.cc38
-rw-r--r--chromium/components/autofill/core/browser/data_model/credit_card.h33
-rw-r--r--chromium/components/autofill/core/browser/data_model/credit_card_test_api.h29
-rw-r--r--chromium/components/autofill/core/browser/data_model/credit_card_unittest.cc10
-rw-r--r--chromium/components/autofill/core/browser/field_filler.cc165
-rw-r--r--chromium/components/autofill/core/browser/field_filler.h11
-rw-r--r--chromium/components/autofill/core/browser/field_filler_unittest.cc317
-rw-r--r--chromium/components/autofill/core/browser/form_data_importer.cc244
-rw-r--r--chromium/components/autofill/core/browser/form_data_importer.h100
-rw-r--r--chromium/components/autofill/core/browser/form_data_importer_unittest.cc336
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/address_field.cc153
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/address_field.h7
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/autofill_parsing_utils.h90
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/credit_card_field.cc48
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/email_field.cc3
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/form_field.cc198
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/form_field.h117
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/form_field_unittest.cc68
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/merchant_promo_code_field.cc3
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/merchant_promo_code_field_unittest.cc46
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/name_field.cc18
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/phone_field.cc13
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/price_field.cc10
-rw-r--r--chromium/components/autofill/core/browser/form_parsing/search_field.cc3
-rw-r--r--chromium/components/autofill/core/browser/form_structure.cc11
-rw-r--r--chromium/components/autofill/core/browser/form_structure_unittest.cc8
-rw-r--r--chromium/components/autofill/core/browser/geo/alternative_state_name_map.cc1
-rw-r--r--chromium/components/autofill/core/browser/geo/alternative_state_name_map_updater_unittest.cc1
-rw-r--r--chromium/components/autofill/core/browser/geo/autofill_country.cc7
-rw-r--r--chromium/components/autofill/core/browser/geo/autofill_country_unittest.cc21
-rw-r--r--chromium/components/autofill/core/browser/geo/country_names.cc2
-rw-r--r--chromium/components/autofill/core/browser/geo/country_names_for_locale_unittest.cc6
-rw-r--r--chromium/components/autofill/core/browser/geo/phone_number_i18n.h28
-rw-r--r--chromium/components/autofill/core/browser/logging/log_buffer_submitter_unittest.cc9
-rw-r--r--chromium/components/autofill/core/browser/logging/log_router.h5
-rw-r--r--chromium/components/autofill/core/browser/metrics/autofill_metrics.cc47
-rw-r--r--chromium/components/autofill/core/browser/metrics/autofill_metrics.h49
-rw-r--r--chromium/components/autofill/core/browser/metrics/autofill_metrics_unittest.cc303
-rw-r--r--chromium/components/autofill/core/browser/metrics/form_events/credit_card_form_event_logger.cc20
-rw-r--r--chromium/components/autofill/core/browser/metrics/form_events/form_events.h5
-rw-r--r--chromium/components/autofill/core/browser/metrics/payments/virtual_card_enrollment_metrics.cc153
-rw-r--r--chromium/components/autofill/core/browser/metrics/payments/virtual_card_enrollment_metrics.h127
-rw-r--r--chromium/components/autofill/core/browser/pattern_provider/default_regex_patterns_unittest.cc9
-rw-r--r--chromium/components/autofill/core/browser/pattern_provider/pattern_configuration_parser.cc56
-rw-r--r--chromium/components/autofill/core/browser/pattern_provider/pattern_configuration_parser_unittest.cc136
-rw-r--r--chromium/components/autofill/core/browser/pattern_provider/pattern_provider.cc14
-rw-r--r--chromium/components/autofill/core/browser/pattern_provider/pattern_provider.h10
-rw-r--r--chromium/components/autofill/core/browser/pattern_provider/pattern_provider_unittest.cc71
-rw-r--r--chromium/components/autofill/core/browser/pattern_provider/resources/regex_patterns.json1303
-rwxr-xr-xchromium/components/autofill/core/browser/pattern_provider/transpile_default_regex_patterns.py31
-rw-r--r--chromium/components/autofill/core/browser/payments/OWNERS3
-rw-r--r--chromium/components/autofill/core/browser/payments/autofill_credit_card_filling_infobar_delegate_mobile.cc8
-rw-r--r--chromium/components/autofill/core/browser/payments/autofill_offer_manager.cc12
-rw-r--r--chromium/components/autofill/core/browser/payments/autofill_offer_manager.h30
-rw-r--r--chromium/components/autofill/core/browser/payments/autofill_offer_manager_unittest.cc1
-rw-r--r--chromium/components/autofill/core/browser/payments/autofill_save_card_infobar_delegate_mobile.cc11
-rw-r--r--chromium/components/autofill/core/browser/payments/autofill_save_card_infobar_delegate_mobile.h4
-rw-r--r--chromium/components/autofill/core/browser/payments/autofill_virtual_card_enrollment_infobar_delegate_mobile.cc144
-rw-r--r--chromium/components/autofill/core/browser/payments/autofill_virtual_card_enrollment_infobar_delegate_mobile.h88
-rw-r--r--chromium/components/autofill/core/browser/payments/autofill_virtual_card_enrollment_infobar_mobile.h25
-rw-r--r--chromium/components/autofill/core/browser/payments/autofill_wallet_model_type_controller.cc4
-rw-r--r--chromium/components/autofill/core/browser/payments/credit_card_access_manager.cc52
-rw-r--r--chromium/components/autofill/core/browser/payments/credit_card_access_manager.h16
-rw-r--r--chromium/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc63
-rw-r--r--chromium/components/autofill/core/browser/payments/credit_card_cvc_authenticator.cc2
-rw-r--r--chromium/components/autofill/core/browser/payments/credit_card_cvc_authenticator.h4
-rw-r--r--chromium/components/autofill/core/browser/payments/credit_card_cvc_authenticator_unittest.cc1
-rw-r--r--chromium/components/autofill/core/browser/payments/credit_card_fido_authenticator.cc46
-rw-r--r--chromium/components/autofill/core/browser/payments/credit_card_fido_authenticator.h9
-rw-r--r--chromium/components/autofill/core/browser/payments/credit_card_fido_authenticator_unittest.cc5
-rw-r--r--chromium/components/autofill/core/browser/payments/credit_card_otp_authenticator.cc9
-rw-r--r--chromium/components/autofill/core/browser/payments/credit_card_otp_authenticator_unittest.cc1
-rw-r--r--chromium/components/autofill/core/browser/payments/credit_card_save_manager.cc76
-rw-r--r--chromium/components/autofill/core/browser/payments/credit_card_save_manager.h18
-rw-r--r--chromium/components/autofill/core/browser/payments/credit_card_save_manager_unittest.cc223
-rw-r--r--chromium/components/autofill/core/browser/payments/full_card_request.cc4
-rw-r--r--chromium/components/autofill/core/browser/payments/full_card_request.h8
-rw-r--r--chromium/components/autofill/core/browser/payments/full_card_request_unittest.cc2
-rw-r--r--chromium/components/autofill/core/browser/payments/legal_message_line.cc6
-rw-r--r--chromium/components/autofill/core/browser/payments/local_card_migration_manager.cc1
-rw-r--r--chromium/components/autofill/core/browser/payments/local_card_migration_manager_unittest.cc16
-rw-r--r--chromium/components/autofill/core/browser/payments/offer_notification_handler.cc79
-rw-r--r--chromium/components/autofill/core/browser/payments/offer_notification_handler.h44
-rw-r--r--chromium/components/autofill/core/browser/payments/payments_client.cc159
-rw-r--r--chromium/components/autofill/core/browser/payments/payments_client.h161
-rw-r--r--chromium/components/autofill/core/browser/payments/payments_client_unittest.cc488
-rw-r--r--chromium/components/autofill/core/browser/payments/payments_requests/get_details_for_enrollment_request.cc123
-rw-r--r--chromium/components/autofill/core/browser/payments/payments_requests/get_details_for_enrollment_request.h57
-rw-r--r--chromium/components/autofill/core/browser/payments/payments_requests/get_details_for_enrollment_request_unittest.cc77
-rw-r--r--chromium/components/autofill/core/browser/payments/payments_requests/payments_request.cc2
-rw-r--r--chromium/components/autofill/core/browser/payments/payments_requests/unmask_card_request.cc18
-rw-r--r--chromium/components/autofill/core/browser/payments/payments_requests/update_virtual_card_enrollment_request.cc185
-rw-r--r--chromium/components/autofill/core/browser/payments/payments_requests/update_virtual_card_enrollment_request.h64
-rw-r--r--chromium/components/autofill/core/browser/payments/payments_service_url.cc9
-rw-r--r--chromium/components/autofill/core/browser/payments/payments_service_url.h4
-rw-r--r--chromium/components/autofill/core/browser/payments/test_authentication_requester.cc4
-rw-r--r--chromium/components/autofill/core/browser/payments/test_authentication_requester.h8
-rw-r--r--chromium/components/autofill/core/browser/payments/test_credit_card_fido_authenticator.cc12
-rw-r--r--chromium/components/autofill/core/browser/payments/test_credit_card_save_manager.cc15
-rw-r--r--chromium/components/autofill/core/browser/payments/test_credit_card_save_manager.h12
-rw-r--r--chromium/components/autofill/core/browser/payments/test_payments_client.cc41
-rw-r--r--chromium/components/autofill/core/browser/payments/test_payments_client.h54
-rw-r--r--chromium/components/autofill/core/browser/payments/test_virtual_card_enrollment_manager.cc44
-rw-r--r--chromium/components/autofill/core/browser/payments/test_virtual_card_enrollment_manager.h84
-rw-r--r--chromium/components/autofill/core/browser/payments/virtual_card_enrollment_flow.h43
-rw-r--r--chromium/components/autofill/core/browser/payments/virtual_card_enrollment_manager.cc325
-rw-r--r--chromium/components/autofill/core/browser/payments/virtual_card_enrollment_manager.h279
-rw-r--r--chromium/components/autofill/core/browser/payments/virtual_card_enrollment_manager_unittest.cc507
-rw-r--r--chromium/components/autofill/core/browser/payments/virtual_card_enrollment_strike_database.cc61
-rw-r--r--chromium/components/autofill/core/browser/payments/virtual_card_enrollment_strike_database.h37
-rw-r--r--chromium/components/autofill/core/browser/payments/virtual_card_enrollment_strike_database_unittest.cc74
-rw-r--r--chromium/components/autofill/core/browser/personal_data_manager.cc209
-rw-r--r--chromium/components/autofill/core/browser/personal_data_manager.h61
-rw-r--r--chromium/components/autofill/core/browser/personal_data_manager_cleaner.cc6
-rw-r--r--chromium/components/autofill/core/browser/personal_data_manager_unittest.cc723
-rw-r--r--chromium/components/autofill/core/browser/proto/server.proto6
-rw-r--r--chromium/components/autofill/core/browser/test_autofill_client.cc25
-rw-r--r--chromium/components/autofill/core/browser/test_autofill_client.h38
-rw-r--r--chromium/components/autofill/core/browser/test_autofill_driver.cc4
-rw-r--r--chromium/components/autofill/core/browser/test_autofill_driver.h10
-rw-r--r--chromium/components/autofill/core/browser/test_autofill_profile_validator.cc67
-rw-r--r--chromium/components/autofill/core/browser/test_autofill_profile_validator.h37
-rw-r--r--chromium/components/autofill/core/browser/test_autofill_profile_validator_delayed.cc39
-rw-r--r--chromium/components/autofill/core/browser/test_autofill_profile_validator_delayed.h44
-rw-r--r--chromium/components/autofill/core/browser/test_form_data_importer.cc4
-rw-r--r--chromium/components/autofill/core/browser/test_form_data_importer.h1
-rw-r--r--chromium/components/autofill/core/browser/test_personal_data_manager.h2
-rw-r--r--chromium/components/autofill/core/browser/ui/autofill_popup_delegate.h6
-rw-r--r--chromium/components/autofill/core/browser/ui/country_combobox_model.cc2
-rw-r--r--chromium/components/autofill/core/browser/ui/label_formatter.cc4
-rw-r--r--chromium/components/autofill/core/browser/ui/label_formatter_utils.h1
-rw-r--r--chromium/components/autofill/core/browser/ui/payments/card_name_fix_flow_controller_impl.cc2
-rw-r--r--chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller.h2
-rw-r--r--chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.cc12
-rw-r--r--chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.h2
-rw-r--r--chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl_unittest.cc26
-rw-r--r--chromium/components/autofill/core/browser/ui/payments/virtual_card_enroll_bubble_controller.h75
-rw-r--r--chromium/components/autofill/core/browser/ui/suggestion.h8
-rw-r--r--chromium/components/autofill/core/browser/ui/suggestion_selection.cc11
-rw-r--r--chromium/components/autofill/core/browser/ui/suggestion_selection_unittest.cc43
-rw-r--r--chromium/components/autofill/core/browser/validation.cc8
-rw-r--r--chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc15
-rw-r--r--chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge_unittest.cc6
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_change.h9
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge.cc2
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge_unittest.cc9
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_profile_sync_difference_tracker.cc28
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util.cc23
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util_unittest.cc6
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_table.cc133
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_table.h23
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc81
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.cc30
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge_unittest.cc8
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_wallet_offer_sync_bridge_unittest.cc6
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.cc11
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge_unittest.cc3
-rw-r--r--chromium/components/autofill/core/common/BUILD.gn1
-rw-r--r--chromium/components/autofill/core/common/autofill_features.cc134
-rw-r--r--chromium/components/autofill/core/common/autofill_features.h61
-rw-r--r--chromium/components/autofill/core/common/autofill_payments_features.cc44
-rw-r--r--chromium/components/autofill/core/common/autofill_payments_features.h7
-rw-r--r--chromium/components/autofill/core/common/autofill_prefs.cc8
-rw-r--r--chromium/components/autofill/core/common/autofill_prefs.h2
-rw-r--r--chromium/components/autofill/core/common/autofill_prefs_unittest.cc4
-rw-r--r--chromium/components/autofill/core/common/autofill_util.cc8
-rw-r--r--chromium/components/autofill/core/common/dense_set.h27
-rw-r--r--chromium/components/autofill/core/common/dense_set_unittest.cc61
-rw-r--r--chromium/components/autofill/core/common/form_data.h2
-rw-r--r--chromium/components/autofill/core/common/form_field_data.cc3
-rw-r--r--chromium/components/autofill/core/common/form_field_data.h2
-rw-r--r--chromium/components/autofill/core/common/logging/log_buffer.cc12
-rw-r--r--chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits_unittest.cc4
-rw-r--r--chromium/components/autofill/core/common/password_form_generation_data.h2
-rw-r--r--chromium/components/autofill/core/common/signatures.cc5
-rw-r--r--chromium/components/autofill/core/common/signatures_unittest.cc40
-rw-r--r--chromium/components/autofill/core/common/unique_ids.h2
-rw-r--r--chromium/components/autofill/ios/browser/BUILD.gn1
-rw-r--r--chromium/components/autofill/ios/browser/autofill_java_script_feature.mm1
-rw-r--r--chromium/components/autofill/ios/browser/autofill_util.mm27
-rw-r--r--chromium/components/autofill/ios/browser/suggestion_controller_java_script_feature.mm1
-rw-r--r--chromium/components/autofill/ios/form_util/BUILD.gn3
-rw-r--r--chromium/components/autofill/ios/form_util/form_handlers_java_script_feature.mm1
-rw-r--r--chromium/components/autofill/ios/form_util/form_util_java_script_feature.mm1
-rw-r--r--chromium/components/autofill/ios/form_util/unique_id_data_tab_helper_unittest.mm8
-rw-r--r--chromium/components/autofill_assistant/OWNERS2
-rw-r--r--chromium/components/autofill_assistant/android/BUILD.gn55
-rw-r--r--chromium/components/autofill_assistant/android/internal/java/res/drawable-v23/autofill_assistant_actions_gradient.xml (renamed from chromium/components/autofill_assistant/android/internal/java/res/drawable/autofill_assistant_actions_gradient.xml)2
-rw-r--r--chromium/components/autofill_assistant/android/internal/java/res/drawable-v31/autofill_assistant_actions_gradient.xml14
-rw-r--r--chromium/components/autofill_assistant/android/internal/java/res/layout/autofill_assistant_base_onboarding.xml28
-rw-r--r--chromium/components/autofill_assistant/android/internal/java/res/layout/autofill_assistant_datetime.xml28
-rw-r--r--chromium/components/autofill_assistant/android/internal/java/res/layout/autofill_assistant_form_counter.xml2
-rw-r--r--chromium/components/autofill_assistant/android/internal/java/res/layout/autofill_assistant_form_counter_input.xml4
-rw-r--r--chromium/components/autofill_assistant/android/internal/java/res/layout/autofill_assistant_onboarding_terms.xml20
-rw-r--r--chromium/components/autofill_assistant/android/internal/java/res_poodle/drawable/ic_autofill_assistant_24dp.xml2
-rw-r--r--chromium/components/autofill_assistant/android/internal/java/src/org/chromium/chrome/browser/autofill_assistant/header/AnimatedPoodle.java4
-rw-r--r--chromium/components/autofill_assistant/android/internal/java/strings/translations/android_chrome_autofill_assistant_strings_de.xtb10
-rw-r--r--chromium/components/autofill_assistant/android/internal/java/strings/translations/android_chrome_autofill_assistant_strings_es.xtb2
-rw-r--r--chromium/components/autofill_assistant/android/internal/java/strings/translations/android_chrome_autofill_assistant_strings_kn.xtb12
-rw-r--r--chromium/components/autofill_assistant/android/internal/java/strings/translations/android_chrome_autofill_assistant_strings_pt-BR.xtb2
-rw-r--r--chromium/components/autofill_assistant/browser/BUILD.gn53
-rw-r--r--chromium/components/autofill_assistant/browser/DEPS2
-rw-r--r--chromium/components/autofill_assistant/browser/actions/action.cc3
-rw-r--r--chromium/components/autofill_assistant/browser/actions/action_delegate.h11
-rw-r--r--chromium/components/autofill_assistant/browser/actions/action_delegate_util.cc2
-rw-r--r--chromium/components/autofill_assistant/browser/actions/collect_user_data_action.cc465
-rw-r--r--chromium/components/autofill_assistant/browser/actions/collect_user_data_action.h24
-rw-r--r--chromium/components/autofill_assistant/browser/actions/collect_user_data_action_unittest.cc411
-rw-r--r--chromium/components/autofill_assistant/browser/actions/execute_js_action.cc58
-rw-r--r--chromium/components/autofill_assistant/browser/actions/execute_js_action.h42
-rw-r--r--chromium/components/autofill_assistant/browser/actions/execute_js_action_unittest.cc150
-rw-r--r--chromium/components/autofill_assistant/browser/actions/expect_navigation_action_unittest.cc41
-rw-r--r--chromium/components/autofill_assistant/browser/actions/mock_action_delegate.h9
-rw-r--r--chromium/components/autofill_assistant/browser/actions/navigate_action_unittest.cc134
-rw-r--r--chromium/components/autofill_assistant/browser/actions/prompt_action.cc51
-rw-r--r--chromium/components/autofill_assistant/browser/actions/prompt_action.h8
-rw-r--r--chromium/components/autofill_assistant/browser/actions/prompt_action_unittest.cc8
-rw-r--r--chromium/components/autofill_assistant/browser/actions/save_generated_password_action.cc8
-rw-r--r--chromium/components/autofill_assistant/browser/actions/save_generated_password_action_unittest.cc17
-rw-r--r--chromium/components/autofill_assistant/browser/actions/save_submitted_password_action.cc8
-rw-r--r--chromium/components/autofill_assistant/browser/actions/save_submitted_password_action_unittest.cc26
-rw-r--r--chromium/components/autofill_assistant/browser/actions/show_generic_ui_action.cc155
-rw-r--r--chromium/components/autofill_assistant/browser/actions/show_generic_ui_action.h15
-rw-r--r--chromium/components/autofill_assistant/browser/actions/show_generic_ui_action_unittest.cc201
-rw-r--r--chromium/components/autofill_assistant/browser/actions/wait_for_document_action_unittest.cc2
-rw-r--r--chromium/components/autofill_assistant/browser/actions/wait_for_dom_action.cc10
-rw-r--r--chromium/components/autofill_assistant/browser/actions/wait_for_dom_action.h3
-rw-r--r--chromium/components/autofill_assistant/browser/actions/wait_for_dom_action_unittest.cc6
-rw-r--r--chromium/components/autofill_assistant/browser/actions/wait_for_navigation_action_unittest.cc94
-rw-r--r--chromium/components/autofill_assistant/browser/autofill_assistant_factory.cc23
-rw-r--r--chromium/components/autofill_assistant/browser/autofill_assistant_impl.cc122
-rw-r--r--chromium/components/autofill_assistant/browser/autofill_assistant_impl.h52
-rw-r--r--chromium/components/autofill_assistant/browser/autofill_assistant_impl_unittest.cc131
-rw-r--r--chromium/components/autofill_assistant/browser/autofill_assistant_onboarding_fetcher.cc20
-rw-r--r--chromium/components/autofill_assistant/browser/autofill_assistant_onboarding_fetcher.h19
-rw-r--r--chromium/components/autofill_assistant/browser/base_browsertest.cc46
-rw-r--r--chromium/components/autofill_assistant/browser/base_browsertest.h33
-rw-r--r--chromium/components/autofill_assistant/browser/basic_interactions.cc60
-rw-r--r--chromium/components/autofill_assistant/browser/basic_interactions.h13
-rw-r--r--chromium/components/autofill_assistant/browser/basic_interactions_unittest.cc47
-rw-r--r--chromium/components/autofill_assistant/browser/batch_element_checker.cc382
-rw-r--r--chromium/components/autofill_assistant/browser/batch_element_checker.h155
-rw-r--r--chromium/components/autofill_assistant/browser/batch_element_checker_unittest.cc379
-rw-r--r--chromium/components/autofill_assistant/browser/client.h17
-rw-r--r--chromium/components/autofill_assistant/browser/client_context.h2
-rw-r--r--chromium/components/autofill_assistant/browser/client_settings.cc4
-rw-r--r--chromium/components/autofill_assistant/browser/client_settings.h7
-rw-r--r--chromium/components/autofill_assistant/browser/controller.cc1243
-rw-r--r--chromium/components/autofill_assistant/browser/controller.h293
-rw-r--r--chromium/components/autofill_assistant/browser/controller_observer.h83
-rw-r--r--chromium/components/autofill_assistant/browser/controller_unittest.cc1534
-rw-r--r--chromium/components/autofill_assistant/browser/devtools/devtools_client.cc16
-rw-r--r--chromium/components/autofill_assistant/browser/devtools/value_conversions.h4
-rw-r--r--chromium/components/autofill_assistant/browser/dom_action.proto22
-rw-r--r--chromium/components/autofill_assistant/browser/element_area.cc2
-rw-r--r--chromium/components/autofill_assistant/browser/element_area.h5
-rw-r--r--chromium/components/autofill_assistant/browser/element_precondition.cc176
-rw-r--r--chromium/components/autofill_assistant/browser/element_precondition.h101
-rw-r--r--chromium/components/autofill_assistant/browser/element_precondition_unittest.cc329
-rw-r--r--chromium/components/autofill_assistant/browser/execution_delegate.h124
-rw-r--r--chromium/components/autofill_assistant/browser/fake_script_executor_delegate.cc168
-rw-r--r--chromium/components/autofill_assistant/browser/fake_script_executor_delegate.h87
-rw-r--r--chromium/components/autofill_assistant/browser/fake_script_executor_ui_delegate.cc161
-rw-r--r--chromium/components/autofill_assistant/browser/fake_script_executor_ui_delegate.h113
-rw-r--r--chromium/components/autofill_assistant/browser/field_formatter_unittest.cc1
-rw-r--r--chromium/components/autofill_assistant/browser/js_flow_executor.h156
-rw-r--r--chromium/components/autofill_assistant/browser/js_flow_executor_impl.cc (renamed from chromium/components/autofill_assistant/browser/js_flow_executor.cc)140
-rw-r--r--chromium/components/autofill_assistant/browser/js_flow_executor_impl.h168
-rw-r--r--chromium/components/autofill_assistant/browser/js_flow_executor_impl_browsertest.cc (renamed from chromium/components/autofill_assistant/browser/js_flow_executor_unittest.cc)231
-rw-r--r--chromium/components/autofill_assistant/browser/metrics.cc10
-rw-r--r--chromium/components/autofill_assistant/browser/metrics.h17
-rw-r--r--chromium/components/autofill_assistant/browser/mock_client.h7
-rw-r--r--chromium/components/autofill_assistant/browser/mock_controller_observer.h44
-rw-r--r--chromium/components/autofill_assistant/browser/mock_execution_delegate.cc12
-rw-r--r--chromium/components/autofill_assistant/browser/mock_execution_delegate.h52
-rw-r--r--chromium/components/autofill_assistant/browser/mock_script_executor_delegate.h97
-rw-r--r--chromium/components/autofill_assistant/browser/mock_ui_controller_observer.cc12
-rw-r--r--chromium/components/autofill_assistant/browser/mock_ui_controller_observer.h59
-rw-r--r--chromium/components/autofill_assistant/browser/model.proto11
-rw-r--r--chromium/components/autofill_assistant/browser/parse_jspb.cc193
-rw-r--r--chromium/components/autofill_assistant/browser/parse_jspb.h42
-rw-r--r--chromium/components/autofill_assistant/browser/parse_jspb_test.proto45
-rw-r--r--chromium/components/autofill_assistant/browser/parse_jspb_unittest.cc197
-rw-r--r--chromium/components/autofill_assistant/browser/protocol_utils.cc327
-rw-r--r--chromium/components/autofill_assistant/browser/protocol_utils.h18
-rw-r--r--chromium/components/autofill_assistant/browser/protocol_utils_unittest.cc63
-rw-r--r--chromium/components/autofill_assistant/browser/public/BUILD.gn4
-rw-r--r--chromium/components/autofill_assistant/browser/public/autofill_assistant.cc23
-rw-r--r--chromium/components/autofill_assistant/browser/public/autofill_assistant.h56
-rw-r--r--chromium/components/autofill_assistant/browser/public/autofill_assistant_factory.h24
-rw-r--r--chromium/components/autofill_assistant/browser/public/runtime_manager_impl.cc3
-rw-r--r--chromium/components/autofill_assistant/browser/script_executor.cc185
-rw-r--r--chromium/components/autofill_assistant/browser/script_executor.h19
-rw-r--r--chromium/components/autofill_assistant/browser/script_executor_delegate.h88
-rw-r--r--chromium/components/autofill_assistant/browser/script_executor_ui_delegate.h95
-rw-r--r--chromium/components/autofill_assistant/browser/script_executor_unittest.cc112
-rw-r--r--chromium/components/autofill_assistant/browser/script_parameters.cc26
-rw-r--r--chromium/components/autofill_assistant/browser/script_parameters.h11
-rw-r--r--chromium/components/autofill_assistant/browser/script_parameters_unittest.cc22
-rw-r--r--chromium/components/autofill_assistant/browser/script_precondition.cc5
-rw-r--r--chromium/components/autofill_assistant/browser/script_precondition.h3
-rw-r--r--chromium/components/autofill_assistant/browser/script_tracker.cc6
-rw-r--r--chromium/components/autofill_assistant/browser/script_tracker.h2
-rw-r--r--chromium/components/autofill_assistant/browser/script_tracker_unittest.cc4
-rw-r--r--chromium/components/autofill_assistant/browser/service.proto249
-rw-r--r--chromium/components/autofill_assistant/browser/service/cup.cc105
-rw-r--r--chromium/components/autofill_assistant/browser/service/cup.h62
-rw-r--r--chromium/components/autofill_assistant/browser/service/cup_factory.cc18
-rw-r--r--chromium/components/autofill_assistant/browser/service/cup_factory.h41
-rw-r--r--chromium/components/autofill_assistant/browser/service/cup_factory_unittest.cc31
-rw-r--r--chromium/components/autofill_assistant/browser/service/cup_impl.cc149
-rw-r--r--chromium/components/autofill_assistant/browser/service/cup_impl.h66
-rw-r--r--chromium/components/autofill_assistant/browser/service/cup_impl_unittest.cc113
-rw-r--r--chromium/components/autofill_assistant/browser/service/cup_unittest.cc156
-rw-r--r--chromium/components/autofill_assistant/browser/service/java_service_request_sender.cc3
-rw-r--r--chromium/components/autofill_assistant/browser/service/java_service_request_sender.h3
-rw-r--r--chromium/components/autofill_assistant/browser/service/mock_cup.cc21
-rw-r--r--chromium/components/autofill_assistant/browser/service/mock_cup.h41
-rw-r--r--chromium/components/autofill_assistant/browser/service/mock_service_request_sender.h10
-rw-r--r--chromium/components/autofill_assistant/browser/service/mock_url_loader.h3
-rw-r--r--chromium/components/autofill_assistant/browser/service/rpc_type.h2
-rw-r--r--chromium/components/autofill_assistant/browser/service/server_url_fetcher.cc7
-rw-r--r--chromium/components/autofill_assistant/browser/service/server_url_fetcher.h2
-rw-r--r--chromium/components/autofill_assistant/browser/service/server_url_fetcher_unittest.cc6
-rw-r--r--chromium/components/autofill_assistant/browser/service/service_impl.cc8
-rw-r--r--chromium/components/autofill_assistant/browser/service/service_impl_unittest.cc14
-rw-r--r--chromium/components/autofill_assistant/browser/service/service_request_sender.h4
-rw-r--r--chromium/components/autofill_assistant/browser/service/service_request_sender_impl.cc48
-rw-r--r--chromium/components/autofill_assistant/browser/service/service_request_sender_impl.h20
-rw-r--r--chromium/components/autofill_assistant/browser/service/service_request_sender_impl_unittest.cc202
-rw-r--r--chromium/components/autofill_assistant/browser/service/service_request_sender_local_impl.cc3
-rw-r--r--chromium/components/autofill_assistant/browser/service/service_request_sender_local_impl.h3
-rw-r--r--chromium/components/autofill_assistant/browser/service/service_request_sender_local_impl_unittest.cc8
-rw-r--r--chromium/components/autofill_assistant/browser/starter.cc10
-rw-r--r--chromium/components/autofill_assistant/browser/starter_heuristic.cc4
-rw-r--r--chromium/components/autofill_assistant/browser/starter_unittest.cc56
-rw-r--r--chromium/components/autofill_assistant/browser/state.h6
-rw-r--r--chromium/components/autofill_assistant/browser/switches.cc9
-rw-r--r--chromium/components/autofill_assistant/browser/switches.h2
-rw-r--r--chromium/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator.cc3
-rw-r--r--chromium/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator_unittest.cc171
-rw-r--r--chromium/components/autofill_assistant/browser/ui_controller.cc1137
-rw-r--r--chromium/components/autofill_assistant/browser/ui_controller.h338
-rw-r--r--chromium/components/autofill_assistant/browser/ui_controller_observer.cc14
-rw-r--r--chromium/components/autofill_assistant/browser/ui_controller_observer.h99
-rw-r--r--chromium/components/autofill_assistant/browser/ui_controller_unittest.cc1105
-rw-r--r--chromium/components/autofill_assistant/browser/ui_delegate.h130
-rw-r--r--chromium/components/autofill_assistant/browser/user_data.cc15
-rw-r--r--chromium/components/autofill_assistant/browser/user_data.h34
-rw-r--r--chromium/components/autofill_assistant/browser/user_data_util.cc226
-rw-r--r--chromium/components/autofill_assistant/browser/user_data_util.h40
-rw-r--r--chromium/components/autofill_assistant/browser/user_data_util_unittest.cc281
-rw-r--r--chromium/components/autofill_assistant/browser/view_layout.proto6
-rw-r--r--chromium/components/autofill_assistant/browser/web/batch_element_checker_browsertest.cc462
-rw-r--r--chromium/components/autofill_assistant/browser/web/element.cc31
-rw-r--r--chromium/components/autofill_assistant/browser/web/element.h21
-rw-r--r--chromium/components/autofill_assistant/browser/web/element_finder.cc480
-rw-r--r--chromium/components/autofill_assistant/browser/web/element_finder.h138
-rw-r--r--chromium/components/autofill_assistant/browser/web/element_rect_getter.cc4
-rw-r--r--chromium/components/autofill_assistant/browser/web/js_filter_builder.cc223
-rw-r--r--chromium/components/autofill_assistant/browser/web/js_filter_builder.h87
-rw-r--r--chromium/components/autofill_assistant/browser/web/mock_web_controller.cc3
-rw-r--r--chromium/components/autofill_assistant/browser/web/mock_web_controller.h4
-rw-r--r--chromium/components/autofill_assistant/browser/web/selector_observer.cc903
-rw-r--r--chromium/components/autofill_assistant/browser/web/selector_observer.h322
-rw-r--r--chromium/components/autofill_assistant/browser/web/selector_observer_script.h221
-rw-r--r--chromium/components/autofill_assistant/browser/web/web_controller.cc129
-rw-r--r--chromium/components/autofill_assistant/browser/web/web_controller.h40
-rw-r--r--chromium/components/autofill_assistant/browser/web/web_controller_browsertest.cc392
-rw-r--r--chromium/components/autofill_assistant/browser/website_login_manager_impl.cc2
-rw-r--r--chromium/components/autofill_assistant/browser/website_login_manager_impl_unittest.cc110
-rw-r--r--chromium/components/autofill_assistant/content/browser/annotate_dom_model_service.cc8
-rw-r--r--chromium/components/autofill_assistant/content/browser/content_autofill_assistant_driver.cc48
-rw-r--r--chromium/components/autofill_assistant/content/browser/content_autofill_assistant_driver.h11
-rw-r--r--chromium/components/autofill_assistant/content/common/autofill_assistant_agent.mojom2
-rw-r--r--chromium/components/autofill_assistant/content/renderer/BUILD.gn60
-rw-r--r--chromium/components/autofill_assistant/content/renderer/DEPS6
-rw-r--r--chromium/components/autofill_assistant/content/renderer/autofill_assistant_agent.cc95
-rw-r--r--chromium/components/autofill_assistant/content/renderer/autofill_assistant_agent.h12
-rw-r--r--chromium/components/autofill_assistant/content/renderer/autofill_assistant_agent_browsertest.cc76
-rw-r--r--chromium/components/autofill_assistant/content/renderer/autofill_assistant_model_executor.cc281
-rw-r--r--chromium/components/autofill_assistant/content/renderer/autofill_assistant_model_executor.h109
-rw-r--r--chromium/components/autofill_assistant/content/renderer/autofill_assistant_model_executor_unittest.cc90
-rw-r--r--chromium/components/autofill_assistant/content/renderer/model_metadata.proto71
-rw-r--r--chromium/components/autofill_payments_strings.grdp38
-rw-r--r--chromium/components/autofill_payments_strings_grdp/IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_ACCEPT_BUTTON_LABEL.png.sha11
-rw-r--r--chromium/components/autofill_payments_strings_grdp/IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_DECLINE_BUTTON_LABEL.png.sha11
-rw-r--r--chromium/components/autofill_payments_strings_grdp/IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_DIALOG_CONTENT_LABEL.png.sha11
-rw-r--r--chromium/components/autofill_payments_strings_grdp/IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_DIALOG_TITLE_LABEL.png.sha11
-rw-r--r--chromium/components/autofill_payments_strings_grdp/IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_FALLBACK_ICON_TOOLTIP.png.sha11
-rw-r--r--chromium/components/autofill_payments_strings_grdp/IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL.png.sha11
-rw-r--r--chromium/components/autofill_payments_strings_grdp/IDS_AUTOFILL_VIRTUAL_CARD_ENTRY_PREFIX_TWO.png.sha11
-rw-r--r--chromium/components/autofill_payments_strings_grdp/IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_EDUCATIONAL_BODY_LABEL.png.sha12
-rw-r--r--chromium/components/autofill_payments_strings_grdp/IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL.png.sha11
-rw-r--r--chromium/components/autofill_payments_strings_grdp/IDS_AUTOFILL_VIRTUAL_CARD_NUMBER_SWITCH_LABEL.png.sha11
-rw-r--r--chromium/components/autofill_payments_strings_grdp/IDS_AUTOFILL_VIRTUAL_CARD_SUGGESTION_IPH_BUBBLE_LABEL.png.sha11
-rw-r--r--chromium/components/background_fetch/background_fetch_delegate_base.cc14
-rw-r--r--chromium/components/background_fetch/background_fetch_delegate_base.h2
-rw-r--r--chromium/components/background_sync/background_sync_controller_impl.cc13
-rw-r--r--chromium/components/background_sync/background_sync_delegate.h4
-rw-r--r--chromium/components/background_task_scheduler/background_task.h4
-rw-r--r--chromium/components/background_task_scheduler/background_task_scheduler_factory.cc4
-rw-r--r--chromium/components/background_task_scheduler/internal/android/javatests/src/org/chromium/components/background_task_scheduler/internal/BackgroundTaskSchedulerJobServiceTest.java2
-rw-r--r--chromium/components/background_task_scheduler/internal/android/javatests/src/org/chromium/components/background_task_scheduler/internal/BundleToPersistableBundleConverterTest.java2
-rw-r--r--chromium/components/background_task_scheduler/internal/android/junit/src/org/chromium/components/background_task_scheduler/internal/BackgroundTaskSchedulerPrefsTest.java2
-rw-r--r--chromium/components/background_task_scheduler/internal/android/junit/src/org/chromium/components/background_task_scheduler/internal/BackgroundTaskSchedulerUmaTest.java3
-rw-r--r--chromium/components/background_task_scheduler/internal/android/junit/src/org/chromium/components/background_task_scheduler/internal/BroadcastReceiverRobolectricTest.java2
-rw-r--r--chromium/components/background_task_scheduler/task_ids.h1
-rw-r--r--chromium/components/base32/base32.cc3
-rw-r--r--chromium/components/base32/base32.h3
-rw-r--r--chromium/components/blocked_content/android/popup_blocked_helper.cc2
-rw-r--r--chromium/components/blocked_content/popup_opener_tab_helper.cc8
-rw-r--r--chromium/components/blocked_content/safe_browsing_triggered_popup_blocker.cc2
-rw-r--r--chromium/components/blocklist/opt_out_blocklist/sql/opt_out_store_sql.cc4
-rw-r--r--chromium/components/bookmarks/browser/bookmark_codec.cc75
-rw-r--r--chromium/components/bookmarks/browser/bookmark_codec.h7
-rw-r--r--chromium/components/bookmarks/browser/bookmark_codec_unittest.cc38
-rw-r--r--chromium/components/bookmarks/browser/bookmark_expanded_state_tracker.cc2
-rw-r--r--chromium/components/bookmarks/browser/bookmark_model.cc23
-rw-r--r--chromium/components/bookmarks/browser/bookmark_model_unittest.cc4
-rw-r--r--chromium/components/bookmarks/browser/bookmark_node_data.cc13
-rw-r--r--chromium/components/bookmarks/browser/bookmark_node_data.h6
-rw-r--r--chromium/components/bookmarks/browser/bookmark_node_data_unittest.cc24
-rw-r--r--chromium/components/bookmarks/browser/bookmark_utils.cc6
-rw-r--r--chromium/components/bookmarks/browser/bookmark_utils_unittest.cc16
-rw-r--r--chromium/components/bookmarks/browser/titled_url_index.cc191
-rw-r--r--chromium/components/bookmarks/browser/titled_url_index.h23
-rw-r--r--chromium/components/bookmarks/browser/titled_url_index_unittest.cc276
-rw-r--r--chromium/components/bookmarks/managed/managed_bookmarks_policy_handler.cc7
-rw-r--r--chromium/components/bookmarks/managed/managed_bookmarks_tracker.cc6
-rw-r--r--chromium/components/bookmarks/managed/managed_bookmarks_tracker_unittest.cc10
-rw-r--r--chromium/components/breadcrumbs/core/breadcrumb_manager.cc16
-rw-r--r--chromium/components/breadcrumbs/core/breadcrumb_manager.h3
-rw-r--r--chromium/components/breadcrumbs/core/breadcrumb_manager_keyed_service.cc3
-rw-r--r--chromium/components/breadcrumbs/core/breadcrumb_persistent_storage_manager.cc63
-rw-r--r--chromium/components/breadcrumbs/core/breadcrumb_persistent_storage_manager.h6
-rw-r--r--chromium/components/breadcrumbs/core/breadcrumb_persistent_storage_util.cc16
-rw-r--r--chromium/components/breadcrumbs/core/breadcrumb_persistent_storage_util.h3
-rw-r--r--chromium/components/breadcrumbs/core/crash_reporter_breadcrumb_observer.cc7
-rw-r--r--chromium/components/browser_sync/BUILD.gn5
-rw-r--r--chromium/components/browser_sync/README.md1
-rw-r--r--chromium/components/browser_sync/browser_sync_client.h8
-rw-r--r--chromium/components/browser_sync/browser_sync_switches.cc52
-rw-r--r--chromium/components/browser_sync/browser_sync_switches.h41
-rw-r--r--chromium/components/browser_sync/sync_api_component_factory_impl.cc (renamed from chromium/components/browser_sync/profile_sync_components_factory_impl.cc)49
-rw-r--r--chromium/components/browser_sync/sync_api_component_factory_impl.h (renamed from chromium/components/browser_sync/profile_sync_components_factory_impl.h)20
-rw-r--r--chromium/components/browser_ui/accessibility/DEPS6
-rw-r--r--chromium/components/browser_ui/accessibility/DIR_METADATA1
-rw-r--r--chromium/components/browser_ui/accessibility/OWNERS1
-rw-r--r--chromium/components/browser_ui/accessibility/android/BUILD.gn62
-rw-r--r--chromium/components/browser_ui/accessibility/android/font_size_prefs_android.cc97
-rw-r--r--chromium/components/browser_ui/accessibility/android/font_size_prefs_android.h66
-rw-r--r--chromium/components/browser_ui/bottomsheet/android/internal/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetControllerImpl.java6
-rw-r--r--chromium/components/browser_ui/bottomsheet/android/internal/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetObserverTest.java6
-rw-r--r--chromium/components/browser_ui/client_certificate/android/BUILD.gn1
-rw-r--r--chromium/components/browser_ui/client_certificate/android/ssl_client_certificate_request.cc5
-rw-r--r--chromium/components/browser_ui/notifications/android/BUILD.gn1
-rw-r--r--chromium/components/browser_ui/notifications/android/DEPS (renamed from chromium/components/guest_view/common/DEPS)4
-rw-r--r--chromium/components/browser_ui/photo_picker/android/BUILD.gn3
-rw-r--r--chromium/components/browser_ui/photo_picker/android/features.cc4
-rw-r--r--chromium/components/browser_ui/settings/android/BUILD.gn2
-rw-r--r--chromium/components/browser_ui/settings/android/widget/java/src/org/chromium/components/browser_ui/settings/ButtonPreference.java7
-rw-r--r--chromium/components/browser_ui/settings/android/widget/java/src/org/chromium/components/browser_ui/settings/ChromeBasePreference.java8
-rw-r--r--chromium/components/browser_ui/settings/android/widget/java/src/org/chromium/components/browser_ui/settings/ImageButtonPreference.java66
-rw-r--r--chromium/components/browser_ui/settings/android/widget/java/src/org/chromium/components/browser_ui/settings/LearnMorePreference.java2
-rw-r--r--chromium/components/browser_ui/share/android/BUILD.gn2
-rw-r--r--chromium/components/browser_ui/site_settings/android/storage_info_fetcher.cc1
-rw-r--r--chromium/components/browser_ui/site_settings/android/website_preference_bridge.cc49
-rw-r--r--chromium/components/browser_ui/strings/android/browser_ui_strings.grd54
-rw-r--r--chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_ACCESSIBILITY_CAPTIONS_TITLE.png.sha11
-rw-r--r--chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_ACCESSIBILITY_LIST_REMOVE_BUTTON.png.sha11
-rw-r--r--chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_ACCESSIBILITY_TAB_SWITCHER_SUMMARY.png.sha11
-rw-r--r--chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_ACCESSIBILITY_TAB_SWITCHER_TITLE.png.sha11
-rw-r--r--chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_CHIP_REMOVE_ICON_CONTENT_DESCRIPTION.png.sha11
-rw-r--r--chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_FONT_SIZE.png.sha11
-rw-r--r--chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_FONT_SIZE_PREVIEW_TEXT.png.sha11
-rw-r--r--chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_FORCE_ENABLE_ZOOM_SUMMARY.png.sha11
-rw-r--r--chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_FORCE_ENABLE_ZOOM_TITLE.png.sha11
-rw-r--r--chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_AD_PERSONALIZATION_DESCRIPTION.png.sha11
-rw-r--r--chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_INFO_ABOUT_THIS_SITE_TITLE.png.sha12
-rw-r--r--chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_INFO_AD_MANAGE_INTERESTS.png.sha11
-rw-r--r--chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_INFO_AD_PERSONALIZATION_TITLE.png.sha11
-rw-r--r--chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PREFS_ACCESSIBILITY.png.sha11
-rw-r--r--chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_READER_FOR_ACCESSIBILITY_SUMMARY.png.sha11
-rw-r--r--chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_READER_FOR_ACCESSIBILITY_TITLE.png.sha11
-rw-r--r--chromium/components/browser_ui/strings/android/site_settings.grdp4
-rw-r--r--chromium/components/browser_ui/strings/android/site_settings_grdp/IDS_WEBSITE_SETTINGS_CATEGORY_NFC_ASK.png.sha12
-rw-r--r--chromium/components/browser_ui/strings/android/site_settings_grdp/IDS_WEBSITE_SETTINGS_CATEGORY_NFC_BLOCKED.png.sha12
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_af.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_am.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ar.xtb27
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_as.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_az.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_be.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_bg.xtb24
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_bn.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_bs.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ca.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_cs.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_da.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_de.xtb80
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_el.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_en-GB.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_es-419.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_es.xtb30
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_et.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_eu.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_fa.xtb32
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_fi.xtb24
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_fil.xtb24
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_fr-CA.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_fr.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_gl.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_gu.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_hi.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_hr.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_hu.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_hy.xtb32
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_id.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_is.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_it.xtb36
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_iw.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ja.xtb24
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ka.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_kk.xtb30
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_km.xtb24
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_kn.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ko.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ky.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_lo.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_lt.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_lv.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_mk.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ml.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_mn.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_mr.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ms.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_my.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ne.xtb30
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_nl.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_no.xtb24
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_or.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_pa.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_pl.xtb24
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_pt-BR.xtb38
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_pt-PT.xtb36
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ro.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ru.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_si.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sk.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sl.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sq.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sr-Latn.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sr.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sv.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sw.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ta.xtb24
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_te.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_th.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_tr.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_uk.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ur.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_uz.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_vi.xtb24
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_zh-CN.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_zh-HK.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_zh-TW.xtb22
-rw-r--r--chromium/components/browser_ui/strings/android/translations/browser_ui_strings_zu.xtb22
-rw-r--r--chromium/components/browser_ui/styles/android/BUILD.gn25
-rw-r--r--chromium/components/browser_ui/util/android/url_constants.cc4
-rw-r--r--chromium/components/browser_ui/util/android/url_constants.h4
-rw-r--r--chromium/components/browser_ui/webshare/android/BUILD.gn1
-rw-r--r--chromium/components/browser_ui/widget/android/BUILD.gn39
-rw-r--r--chromium/components/browser_watcher/activity_report_extractor_unittest.cc5
-rw-r--r--chromium/components/browser_watcher/extended_crash_reporting.cc3
-rw-r--r--chromium/components/browser_watcher/extended_crash_reporting_win_unittest.cc2
-rw-r--r--chromium/components/browsing_data/content/browsing_data_helper.cc2
-rw-r--r--chromium/components/browsing_data/content/canonical_cookie_hash.cc9
-rw-r--r--chromium/components/browsing_data/content/cookie_helper.cc1
-rw-r--r--chromium/components/browsing_data/content/cookie_helper_unittest.cc9
-rw-r--r--chromium/components/browsing_data/content/database_helper_browsertest.cc3
-rw-r--r--chromium/components/browsing_data/content/mock_cookie_helper.cc23
-rw-r--r--chromium/components/browsing_data/content/mock_cookie_helper.h14
-rw-r--r--chromium/components/browsing_data/content/service_worker_helper_unittest.cc9
-rw-r--r--chromium/components/browsing_data/core/counters/history_counter.cc2
-rw-r--r--chromium/components/browsing_data/core/counters/passwords_counter.cc6
-rw-r--r--chromium/components/browsing_data/core/counters/passwords_counter.h5
-rw-r--r--chromium/components/browsing_data/core/features.cc2
-rw-r--r--chromium/components/browsing_data/core/pref_names.cc4
-rw-r--r--chromium/components/captive_portal/content/captive_portal_service.cc2
-rw-r--r--chromium/components/cast/message_port/message_port_unittest.cc18
-rw-r--r--chromium/components/cast/message_port/platform_message_port.cc4
-rw-r--r--chromium/components/cast_certificate/cast_cert_reader.cc1
-rw-r--r--chromium/components/cast_certificate/cast_cert_validator.cc7
-rw-r--r--chromium/components/cast_certificate/cast_cert_validator.h9
-rw-r--r--chromium/components/cast_certificate/cast_crl.cc3
-rw-r--r--chromium/components/cast_channel/BUILD.gn2
-rw-r--r--chromium/components/cast_channel/cast_channel_enum.cc4
-rw-r--r--chromium/components/cast_channel/cast_message_handler.cc8
-rw-r--r--chromium/components/cast_channel/cast_message_handler.h5
-rw-r--r--chromium/components/cast_channel/cast_message_handler_unittest.cc2
-rw-r--r--chromium/components/cast_channel/cast_message_util.cc17
-rw-r--r--chromium/components/cast_channel/cast_message_util.h3
-rw-r--r--chromium/components/cast_channel/cast_socket_service.cc9
-rw-r--r--chromium/components/cast_channel/cast_socket_service.h4
-rw-r--r--chromium/components/cast_channel/cast_socket_unittest.cc29
-rw-r--r--chromium/components/cast_channel/cast_test_util.h6
-rw-r--r--chromium/components/cast_channel/enum_table.h6
-rw-r--r--chromium/components/cast_streaming/browser/cast_message_port_impl_unittest.cc2
-rw-r--r--chromium/components/cast_streaming/browser/public/receiver_session.h20
-rw-r--r--chromium/components/cast_streaming/browser/receiver_session_impl.cc29
-rw-r--r--chromium/components/cast_streaming/browser/receiver_session_impl.h5
-rw-r--r--chromium/components/cast_streaming/browser/rpc_call_translator.cc2
-rw-r--r--chromium/components/cast_streaming/browser/rpc_call_translator.h2
-rw-r--r--chromium/components/cast_streaming/renderer/cast_streaming_demuxer.cc7
-rw-r--r--chromium/components/cast_streaming/renderer/playback_command_forwarding_renderer.cc285
-rw-r--r--chromium/components/cast_streaming/renderer/playback_command_forwarding_renderer.h94
-rw-r--r--chromium/components/cast_streaming/renderer/playback_command_forwarding_renderer_unittest.cc238
-rw-r--r--chromium/components/cdm/browser/cdm_message_filter_android.cc4
-rw-r--r--chromium/components/cdm/browser/media_drm_storage_impl.cc25
-rw-r--r--chromium/components/cdm/browser/media_drm_storage_impl.h2
-rw-r--r--chromium/components/cdm/browser/media_drm_storage_impl_unittest.cc4
-rw-r--r--chromium/components/cdm/common/cdm_manifest.cc2
-rw-r--r--chromium/components/cdm/common/cdm_message_generator.h2
-rw-r--r--chromium/components/cdm/renderer/widevine_key_system_properties.cc21
-rw-r--r--chromium/components/certificate_transparency/BUILD.gn7
-rw-r--r--chromium/components/certificate_transparency/OWNERS5
-rw-r--r--chromium/components/certificate_transparency/certificate_transparency_config.proto5
-rw-r--r--chromium/components/certificate_transparency/chrome_ct_policy_enforcer.cc27
-rw-r--r--chromium/components/certificate_transparency/chrome_ct_policy_enforcer.h21
-rw-r--r--chromium/components/certificate_transparency/chrome_ct_policy_enforcer_unittest.cc776
-rw-r--r--chromium/components/certificate_transparency/chrome_require_ct_delegate.cc6
-rw-r--r--chromium/components/certificate_transparency/chrome_require_ct_delegate.h3
-rw-r--r--chromium/components/certificate_transparency/ct_features.cc4
-rw-r--r--chromium/components/certificate_transparency/ct_features.h4
-rw-r--r--chromium/components/certificate_transparency/ct_known_logs.cc6
-rw-r--r--chromium/components/certificate_transparency/ct_known_logs.h10
-rw-r--r--chromium/components/certificate_transparency/ct_known_logs_unittest.cc2
-rw-r--r--chromium/components/certificate_transparency/data/log_list.json148
-rw-r--r--chromium/components/certificate_transparency/pref_names.h14
-rwxr-xr-xchromium/components/certificate_transparency/tools/make_ct_known_logs_list.py13
-rwxr-xr-xchromium/components/certificate_transparency/tools/make_ct_known_logs_list_unittest.py12
-rw-r--r--chromium/components/client_hints/OWNERS1
-rw-r--r--chromium/components/client_hints/browser/BUILD.gn14
-rw-r--r--chromium/components/client_hints/browser/DEPS2
-rw-r--r--chromium/components/client_hints/browser/client_hints.cc31
-rw-r--r--chromium/components/client_hints/browser/client_hints.h7
-rw-r--r--chromium/components/client_hints/browser/in_memory_client_hints_controller_delegate.cc102
-rw-r--r--chromium/components/client_hints/browser/in_memory_client_hints_controller_delegate.h95
-rw-r--r--chromium/components/client_hints/common/client_hints.cc2
-rw-r--r--chromium/components/cloud_devices/common/description_items_inl.h4
-rw-r--r--chromium/components/cloud_devices/common/printer_description.cc22
-rw-r--r--chromium/components/cloud_devices/common/printer_description.h4
-rw-r--r--chromium/components/cloud_devices/common/printer_description_unittest.cc9
-rw-r--r--chromium/components/commerce/OWNERS1
-rw-r--r--chromium/components/commerce/content/BUILD.gn19
-rw-r--r--chromium/components/commerce/content/DEPS6
-rw-r--r--chromium/components/commerce/content/metrics/commerce_metrics_tab_helper.cc62
-rw-r--r--chromium/components/commerce/content/metrics/commerce_metrics_tab_helper.h65
-rw-r--r--chromium/components/commerce/core/BUILD.gn31
-rw-r--r--chromium/components/commerce/core/DEPS6
-rw-r--r--chromium/components/commerce/core/commerce_feature_list.cc70
-rw-r--r--chromium/components/commerce/core/commerce_feature_list.h89
-rw-r--r--chromium/components/commerce/core/flag_descriptions.cc13
-rw-r--r--chromium/components/commerce/core/flag_descriptions.h18
-rw-r--r--chromium/components/commerce/core/metrics/metrics_utils.cc59
-rw-r--r--chromium/components/commerce/core/metrics/metrics_utils.h39
-rw-r--r--chromium/components/component_updater/android/component_loader_policy.cc6
-rw-r--r--chromium/components/component_updater/component_installer.cc30
-rw-r--r--chromium/components/component_updater/component_installer.h17
-rw-r--r--chromium/components/component_updater/component_installer_unittest.cc109
-rw-r--r--chromium/components/component_updater/component_updater_command_line_config_policy.cc6
-rw-r--r--chromium/components/component_updater/configurator_impl.cc31
-rw-r--r--chromium/components/component_updater/configurator_impl.h5
-rw-r--r--chromium/components/component_updater/installer_policies/client_side_phishing_component_installer_policy.cc25
-rw-r--r--chromium/components/component_updater/installer_policies/client_side_phishing_component_installer_policy.h2
-rw-r--r--chromium/components/component_updater/pref_names.cc2
-rw-r--r--chromium/components/component_updater/pref_names.h2
-rw-r--r--chromium/components/components_chromium_strings.grd4
-rw-r--r--chromium/components/components_google_chrome_strings.grd17
-rw-r--r--chromium/components/components_locale_settings.grd4
-rw-r--r--chromium/components/components_strings.grd7
-rw-r--r--chromium/components/consent_auditor/consent_auditor_impl.cc12
-rw-r--r--chromium/components/consent_auditor/consent_auditor_impl_unittest.cc2
-rw-r--r--chromium/components/constrained_window/constrained_window_views.cc18
-rw-r--r--chromium/components/constrained_window/constrained_window_views_unittest.cc2
-rw-r--r--chromium/components/content_capture/android/junit/BUILD.gn1
-rw-r--r--chromium/components/content_capture/android/junit/src/org/chromium/components/content_capture/PlatformContentCaptureControllerTest.java5
-rw-r--r--chromium/components/content_capture/android/test_support/content_capture_test_support_android.cc4
-rw-r--r--chromium/components/content_capture/browser/BUILD.gn34
-rw-r--r--chromium/components/content_capture/browser/DEPS9
-rw-r--r--chromium/components/content_capture/browser/content_capture_receiver_browsertest.cc112
-rw-r--r--chromium/components/content_capture/browser/content_capture_receiver_test.cc651
-rw-r--r--chromium/components/content_capture/browser/content_capture_test_helper.cc177
-rw-r--r--chromium/components/content_capture/browser/content_capture_test_helper.h161
-rw-r--r--chromium/components/content_capture/browser/onscreen_content_provider.cc10
-rw-r--r--chromium/components/content_capture/common/content_capture_features.cc2
-rw-r--r--chromium/components/content_creation/notes/core/note_features.h1
-rw-r--r--chromium/components/content_creation/notes/core/note_prefs.cc2
-rw-r--r--chromium/components/content_settings/browser/page_specific_content_settings.cc79
-rw-r--r--chromium/components/content_settings/browser/page_specific_content_settings.h29
-rw-r--r--chromium/components/content_settings/browser/page_specific_content_settings_unittest.cc22
-rw-r--r--chromium/components/content_settings/browser/ui/cookie_controls_controller.cc10
-rw-r--r--chromium/components/content_settings/core/browser/BUILD.gn4
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_default_provider.cc107
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_default_provider.h17
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_info.cc4
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_policy_provider.cc30
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_policy_provider.h2
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_pref.cc100
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_pref.h6
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_pref_provider.cc37
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_pref_provider.h2
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_pref_unittest.cc29
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_provider.h2
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_provider_unittest.cc33
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_registry.cc24
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_registry_unittest.cc18
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_utils.cc23
-rw-r--r--chromium/components/content_settings/core/browser/cookie_settings.cc15
-rw-r--r--chromium/components/content_settings/core/browser/cookie_settings_policy_handler.cc2
-rw-r--r--chromium/components/content_settings/core/browser/cookie_settings_policy_handler_unittest.cc7
-rw-r--r--chromium/components/content_settings/core/browser/cookie_settings_unittest.cc8
-rw-r--r--chromium/components/content_settings/core/browser/host_content_settings_map.cc101
-rw-r--r--chromium/components/content_settings/core/browser/host_content_settings_map.h30
-rw-r--r--chromium/components/content_settings/core/browser/uma_util.cc45
-rw-r--r--chromium/components/content_settings/core/browser/uma_util.h16
-rw-r--r--chromium/components/content_settings/core/browser/website_settings_info.cc22
-rw-r--r--chromium/components/content_settings/core/browser/website_settings_info.h13
-rw-r--r--chromium/components/content_settings/core/browser/website_settings_registry.cc115
-rw-r--r--chromium/components/content_settings/core/browser/website_settings_registry.h2
-rw-r--r--chromium/components/content_settings/core/browser/website_settings_registry_unittest.cc38
-rw-r--r--chromium/components/content_settings/core/common/content_settings.cc2
-rw-r--r--chromium/components/content_settings/core/common/content_settings_pattern.cc2
-rw-r--r--chromium/components/content_settings/core/common/content_settings_utils.cc28
-rw-r--r--chromium/components/content_settings/core/common/content_settings_utils.h13
-rw-r--r--chromium/components/content_settings/core/common/cookie_settings_base.cc2
-rw-r--r--chromium/components/content_settings/core/common/features.cc8
-rw-r--r--chromium/components/content_settings/core/common/features.h5
-rw-r--r--chromium/components/content_settings/core/common/pref_names.cc15
-rw-r--r--chromium/components/content_settings/core/common/pref_names.h8
-rw-r--r--chromium/components/content_settings/renderer/content_settings_agent_impl.cc1
-rw-r--r--chromium/components/content_settings/renderer/content_settings_agent_impl_browsertest.cc52
-rw-r--r--chromium/components/cookie_config/cookie_store_util.cc14
-rw-r--r--chromium/components/country_codes/country_codes.cc22
-rw-r--r--chromium/components/crash/android/BUILD.gn67
-rw-r--r--chromium/components/crash/android/DEPS2
-rw-r--r--chromium/components/crash/android/anr_data.proto73
-rw-r--r--chromium/components/crash/android/anr_skipped_reason.h21
-rw-r--r--chromium/components/crash/android/javatests/src/org/chromium/components/crash/DEPS3
-rw-r--r--chromium/components/crash/android/javatests/src/org/chromium/components/crash/PureJavaExceptionReporterTest.java132
-rw-r--r--chromium/components/crash/android/junit/src/org/chromium/components/crash/LogcatCrashExtractorTest.java132
-rw-r--r--chromium/components/crash/android/junit/src/org/chromium/components/crash/anr/AnrCollectorTest.java1085
-rw-r--r--chromium/components/crash/android/pure_java_exception_handler.cc12
-rw-r--r--chromium/components/crash/android/pure_java_exception_handler.h10
-rw-r--r--chromium/components/crash/content/browser/crash_handler_host_linux.cc18
-rw-r--r--chromium/components/crash/content/browser/crash_handler_host_linux.h8
-rw-r--r--chromium/components/crash/content/browser/error_reporting/mock_crash_endpoint.cc2
-rwxr-xr-xchromium/components/crash/content/tools/generate_breakpad_symbols.py30
-rw-r--r--chromium/components/crash/core/app/BUILD.gn12
-rw-r--r--chromium/components/crash/core/app/breakpad_linux.cc85
-rw-r--r--chromium/components/crash/core/app/breakpad_linux.h4
-rw-r--r--chromium/components/crash/core/app/client_upload_info.cc4
-rw-r--r--chromium/components/crash/core/app/client_upload_info.h2
-rw-r--r--chromium/components/crash/core/app/crash_reporter_client.cc26
-rw-r--r--chromium/components/crash/core/app/crash_reporter_client.h24
-rw-r--r--chromium/components/crash/core/app/crash_switches.cc3
-rw-r--r--chromium/components/crash/core/app/crash_switches.h4
-rw-r--r--chromium/components/crash/core/app/crashpad.cc60
-rw-r--r--chromium/components/crash/core/app/crashpad.h65
-rw-r--r--chromium/components/crash/core/app/crashpad_android.cc48
-rw-r--r--chromium/components/crash/core/app/crashpad_ios.mm75
-rw-r--r--chromium/components/crash/core/app/crashpad_ios_unittest.mm94
-rw-r--r--chromium/components/crash/core/app/crashpad_linux.cc42
-rw-r--r--chromium/components/crash/core/browser/crashes_ui_util.cc19
-rw-r--r--chromium/components/crash/core/common/BUILD.gn6
-rw-r--r--chromium/components/crash/core/common/crash_key_breakpad.cc2
-rw-r--r--chromium/components/crash/core/common/crash_keys.cc2
-rw-r--r--chromium/components/crash/core/common/objc_zombie.h4
-rw-r--r--chromium/components/crash/core/common/objc_zombie.mm4
-rw-r--r--chromium/components/cronet/BUILD.gn1
-rw-r--r--chromium/components/cronet/android/BUILD.gn4
-rw-r--r--chromium/components/crx_file/id_util.cc2
-rw-r--r--chromium/components/custom_handlers/BUILD.gn52
-rw-r--r--chromium/components/custom_handlers/DEPS10
-rw-r--r--chromium/components/custom_handlers/protocol_handler_registry.cc31
-rw-r--r--chromium/components/custom_handlers/protocol_handler_registry.h28
-rw-r--r--chromium/components/custom_handlers/protocol_handler_registry_unittest.cc1189
-rw-r--r--chromium/components/custom_handlers/protocol_handler_throttle.cc50
-rw-r--r--chromium/components/custom_handlers/protocol_handler_throttle.h44
-rw-r--r--chromium/components/custom_handlers/register_protocol_handler_permission_request.cc86
-rw-r--r--chromium/components/custom_handlers/register_protocol_handler_permission_request.h60
-rw-r--r--chromium/components/custom_handlers/test_protocol_handler_registry_delegate.cc75
-rw-r--r--chromium/components/custom_handlers/test_protocol_handler_registry_delegate.h55
-rw-r--r--chromium/components/data_reduction_proxy/DEPS1
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/BUILD.gn98
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.cc890
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.h306
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats_unittest.cc1080
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs.cc92
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs.h31
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs_unittest.cc81
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.cc236
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h154
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.cc296
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h198
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_test_utils.cc136
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_test_utils.h88
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_unittest.cc347
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc311
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h228
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_store.cc35
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_store.h48
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_store_impl.cc159
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_store_impl.h61
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_usage_store.cc302
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_usage_store.h117
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_usage_store_unittest.cc518
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/db_data_owner.cc68
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/db_data_owner.h72
-rw-r--r--chromium/components/data_reduction_proxy/core/common/BUILD.gn41
-rw-r--r--chromium/components/data_reduction_proxy/core/common/chrome_proxy_header.txt114
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_features.cc23
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_features.h18
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc96
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h39
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc70
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params.h29
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params_unittest.cc108
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.cc81
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h36
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_switches.cc9
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h2
-rw-r--r--chromium/components/data_reduction_proxy/core/common/version.h.in12
-rw-r--r--chromium/components/data_reduction_proxy/proto/BUILD.gn9
-rw-r--r--chromium/components/data_reduction_proxy/proto/data_store.proto41
-rw-r--r--chromium/components/data_use_measurement/DIR_METADATA3
-rw-r--r--chromium/components/data_use_measurement/OWNERS1
-rw-r--r--chromium/components/data_use_measurement/core/BUILD.gn52
-rw-r--r--chromium/components/data_use_measurement/core/DEPS7
-rw-r--r--chromium/components/data_use_measurement/core/data_use.cc23
-rw-r--r--chromium/components/data_use_measurement/core/data_use.h77
-rw-r--r--chromium/components/data_use_measurement/core/data_use_measurement.cc380
-rw-r--r--chromium/components/data_use_measurement/core/data_use_measurement.h202
-rw-r--r--chromium/components/data_use_measurement/core/data_use_measurement_unittest.cc113
-rw-r--r--chromium/components/data_use_measurement/core/data_use_pref_names.h26
-rw-r--r--chromium/components/data_use_measurement/core/data_use_tracker_prefs.cc131
-rw-r--r--chromium/components/data_use_measurement/core/data_use_tracker_prefs.h70
-rw-r--r--chromium/components/data_use_measurement/core/data_use_tracker_prefs_unittest.cc172
-rw-r--r--chromium/components/data_use_measurement/core/data_use_user_data.cc27
-rw-r--r--chromium/components/data_use_measurement/core/data_use_user_data.h70
-rw-r--r--chromium/components/database_utils/OWNERS1
-rw-r--r--chromium/components/dbus/menu/menu_property_list_unittest.cc4
-rw-r--r--chromium/components/desks_storage/BUILD.gn6
-rw-r--r--chromium/components/desks_storage/DEPS2
-rw-r--r--chromium/components/desks_storage/core/desk_model.cc62
-rw-r--r--chromium/components/desks_storage/core/desk_model.h38
-rw-r--r--chromium/components/desks_storage/core/desk_sync_bridge.cc149
-rw-r--r--chromium/components/desks_storage/core/desk_sync_bridge.h5
-rw-r--r--chromium/components/desks_storage/core/desk_sync_bridge_unittest.cc323
-rw-r--r--chromium/components/desks_storage/core/desk_template_conversion.cc16
-rw-r--r--chromium/components/desks_storage/core/desk_template_conversion_unittests.cc12
-rw-r--r--chromium/components/desks_storage/core/desk_template_util.cc45
-rw-r--r--chromium/components/desks_storage/core/desk_template_util.h25
-rw-r--r--chromium/components/desks_storage/core/desk_template_util_unittests.cc44
-rw-r--r--chromium/components/desks_storage/core/local_desk_data_manager.cc62
-rw-r--r--chromium/components/desks_storage/core/local_desk_data_manager.h3
-rw-r--r--chromium/components/desks_storage/core/local_desks_data_manager_unittests.cc72
-rw-r--r--chromium/components/device_event_log/device_event_log.h2
-rw-r--r--chromium/components/device_event_log/device_event_log_impl.cc8
-rw-r--r--chromium/components/device_event_log/device_event_log_impl_unittest.cc2
-rw-r--r--chromium/components/digital_asset_links/digital_asset_links_handler.cc6
-rw-r--r--chromium/components/discardable_memory/client/client_discardable_shared_memory_manager.cc12
-rw-r--r--chromium/components/discardable_memory/service/discardable_shared_memory_manager.cc6
-rw-r--r--chromium/components/dom_distiller/content/browser/distillability_driver.cc4
-rw-r--r--chromium/components/dom_distiller/content/browser/distillable_page_utils_browsertest.cc6
-rw-r--r--chromium/components/dom_distiller/content/browser/distiller_page_web_contents_browsertest.cc20
-rw-r--r--chromium/components/dom_distiller/content/browser/dom_distiller_viewer_source.cc4
-rw-r--r--chromium/components/dom_distiller/core/distiller.cc2
-rw-r--r--chromium/components/dom_distiller/core/dom_distiller_service.cc4
-rw-r--r--chromium/components/dom_distiller/core/dom_distiller_service.h2
-rw-r--r--chromium/components/dom_distiller/core/experiments.cc1
-rw-r--r--chromium/components/dom_distiller/core/page_features_unittest.cc7
-rw-r--r--chromium/components/dom_distiller/core/viewer.cc8
-rw-r--r--chromium/components/dom_distiller/ios/distiller_page_ios.mm2
-rw-r--r--chromium/components/domain_reliability/context_unittest.cc4
-rw-r--r--chromium/components/domain_reliability/monitor_unittest.cc16
-rw-r--r--chromium/components/domain_reliability/quic_error_mapping.cc2
-rw-r--r--chromium/components/domain_reliability/uploader.cc4
-rw-r--r--chromium/components/domain_reliability/uploader_unittest.cc16
-rw-r--r--chromium/components/domain_reliability/util.cc2
-rw-r--r--chromium/components/download/content/factory/download_service_factory_helper.cc8
-rw-r--r--chromium/components/download/database/download_db_conversions.cc6
-rw-r--r--chromium/components/download/database/download_db_conversions_unittest.cc2
-rw-r--r--chromium/components/download/database/in_progress/in_progress_info.cc4
-rw-r--r--chromium/components/download/database/in_progress/in_progress_info.h4
-rw-r--r--chromium/components/download/database/proto/download_entry.proto3
-rw-r--r--chromium/components/download/internal/background_service/driver_entry.h8
-rw-r--r--chromium/components/download/internal/background_service/scheduler/device_status_listener.cc2
-rw-r--r--chromium/components/download/internal/background_service/scheduler/device_status_listener_unittest.cc2
-rw-r--r--chromium/components/download/internal/common/BUILD.gn4
-rw-r--r--chromium/components/download/internal/common/DEPS1
-rw-r--r--chromium/components/download/internal/common/base_file.cc39
-rw-r--r--chromium/components/download/internal/common/base_file_unittest.cc14
-rw-r--r--chromium/components/download/internal/common/download_create_info.cc1
-rw-r--r--chromium/components/download/internal/common/download_file_impl.cc8
-rw-r--r--chromium/components/download/internal/common/download_file_unittest.cc10
-rw-r--r--chromium/components/download/internal/common/download_item_impl.cc71
-rw-r--r--chromium/components/download/internal/common/download_item_impl_delegate.cc2
-rw-r--r--chromium/components/download/internal/common/download_item_impl_unittest.cc16
-rw-r--r--chromium/components/download/internal/common/download_path_reservation_tracker.cc28
-rw-r--r--chromium/components/download/internal/common/download_path_reservation_tracker_unittest.cc40
-rw-r--r--chromium/components/download/internal/common/download_response_handler.cc12
-rw-r--r--chromium/components/download/internal/common/download_stats.cc12
-rw-r--r--chromium/components/download/internal/common/download_task_runner.cc2
-rw-r--r--chromium/components/download/internal/common/download_utils.cc21
-rw-r--r--chromium/components/download/internal/common/in_progress_download_manager.cc83
-rw-r--r--chromium/components/download/internal/common/resource_downloader.cc32
-rw-r--r--chromium/components/download/internal/common/resource_downloader.h11
-rw-r--r--chromium/components/download/internal/common/url_download_handler_factory.cc5
-rw-r--r--chromium/components/download/public/background_service/download_metadata.h4
-rw-r--r--chromium/components/download/public/common/BUILD.gn3
-rw-r--r--chromium/components/download/public/common/base_file.h2
-rw-r--r--chromium/components/download/public/common/download_create_info.h8
-rw-r--r--chromium/components/download/public/common/download_features.cc10
-rw-r--r--chromium/components/download/public/common/download_features.h2
-rw-r--r--chromium/components/download/public/common/download_file.h4
-rw-r--r--chromium/components/download/public/common/download_file_impl.h8
-rw-r--r--chromium/components/download/public/common/download_item.h12
-rw-r--r--chromium/components/download/public/common/download_item_factory.h2
-rw-r--r--chromium/components/download/public/common/download_item_impl.h17
-rw-r--r--chromium/components/download/public/common/download_item_impl_delegate.h2
-rw-r--r--chromium/components/download/public/common/download_response_handler.h5
-rw-r--r--chromium/components/download/public/common/download_stats.h8
-rw-r--r--chromium/components/download/public/common/in_progress_download_manager.h13
-rw-r--r--chromium/components/download/public/common/mock_download_file.h4
-rw-r--r--chromium/components/download/public/common/mock_download_item.h3
-rw-r--r--chromium/components/download/public/common/mock_download_item_impl.cc2
-rw-r--r--chromium/components/download/public/common/storage_partition_config.cc59
-rw-r--r--chromium/components/download/public/common/storage_partition_config.h50
-rw-r--r--chromium/components/download/public/common/storage_partition_config_unittest.cc99
-rw-r--r--chromium/components/embedder_support/android/delegate/web_contents_delegate_android.cc2
-rw-r--r--chromium/components/embedder_support/android/javatests/src/org/chromium/components/embedder_support/delegate/ColorPickerDialogRenderTest.java6
-rw-r--r--chromium/components/embedder_support/android/metrics/BUILD.gn1
-rw-r--r--chromium/components/embedder_support/android/metrics/DEPS1
-rw-r--r--chromium/components/embedder_support/android/metrics/android_metrics_service_client.cc10
-rw-r--r--chromium/components/embedder_support/android/metrics/android_metrics_service_client.h7
-rw-r--r--chromium/components/embedder_support/android/metrics/android_metrics_service_client_unittest.cc17
-rw-r--r--chromium/components/embedder_support/android/metrics/memory_metrics_logger.cc6
-rw-r--r--chromium/components/embedder_support/android/util/android_stream_reader_url_loader.cc5
-rw-r--r--chromium/components/embedder_support/content_settings_utils.cc4
-rw-r--r--chromium/components/embedder_support/origin_trials/component_updater_utils.cc28
-rw-r--r--chromium/components/embedder_support/origin_trials/component_updater_utils_unittest.cc21
-rw-r--r--chromium/components/embedder_support/permission_context_utils.cc20
-rw-r--r--chromium/components/embedder_support/permission_context_utils.h8
-rw-r--r--chromium/components/embedder_support/pref_names.cc6
-rw-r--r--chromium/components/embedder_support/pref_names.h1
-rw-r--r--chromium/components/embedder_support/user_agent_utils.cc266
-rw-r--r--chromium/components/embedder_support/user_agent_utils.h50
-rw-r--r--chromium/components/embedder_support/user_agent_utils_unittest.cc438
-rw-r--r--chromium/components/enterprise/BUILD.gn43
-rw-r--r--chromium/components/enterprise/OWNERS2
-rw-r--r--chromium/components/enterprise/browser/controller/chrome_browser_cloud_management_controller.cc19
-rw-r--r--chromium/components/enterprise/browser/controller/chrome_browser_cloud_management_controller.h3
-rw-r--r--chromium/components/enterprise/browser/device_trust/device_trust_key_manager.h12
-rw-r--r--chromium/components/enterprise/browser/reporting/OWNERS3
-rw-r--r--chromium/components/enterprise/browser/reporting/browser_report_generator.cc35
-rw-r--r--chromium/components/enterprise/browser/reporting/chrome_profile_request_generator.cc56
-rw-r--r--chromium/components/enterprise/browser/reporting/chrome_profile_request_generator.h54
-rw-r--r--chromium/components/enterprise/browser/reporting/chrome_profile_request_generator_unittest.cc152
-rw-r--r--chromium/components/enterprise/browser/reporting/cloud_profile_reporting_policy_handler.cc57
-rw-r--r--chromium/components/enterprise/browser/reporting/cloud_profile_reporting_policy_handler.h32
-rw-r--r--chromium/components/enterprise/browser/reporting/cloud_reporting_frequency_policy_handler.cc60
-rw-r--r--chromium/components/enterprise/browser/reporting/cloud_reporting_frequency_policy_handler.h32
-rw-r--r--chromium/components/enterprise/browser/reporting/cloud_reporting_policy_handler.cc9
-rw-r--r--chromium/components/enterprise/browser/reporting/cloud_reporting_policy_handler_unittest.cc9
-rw-r--r--chromium/components/enterprise/browser/reporting/common_pref_names.cc9
-rw-r--r--chromium/components/enterprise/browser/reporting/common_pref_names.h4
-rw-r--r--chromium/components/enterprise/browser/reporting/os_report_generator.cc21
-rw-r--r--chromium/components/enterprise/browser/reporting/os_report_generator.h20
-rw-r--r--chromium/components/enterprise/browser/reporting/profile_report_generator.cc17
-rw-r--r--chromium/components/enterprise/browser/reporting/real_time_uploader.cc5
-rw-r--r--chromium/components/enterprise/browser/reporting/report_generator.cc52
-rw-r--r--chromium/components/enterprise/browser/reporting/report_generator.h13
-rw-r--r--chromium/components/enterprise/browser/reporting/report_request.cc61
-rw-r--r--chromium/components/enterprise/browser/reporting/report_request.h69
-rw-r--r--chromium/components/enterprise/browser/reporting/report_request_definition.h30
-rw-r--r--chromium/components/enterprise/browser/reporting/report_request_queue_generator.cc54
-rw-r--r--chromium/components/enterprise/browser/reporting/report_request_queue_generator.h12
-rw-r--r--chromium/components/enterprise/browser/reporting/report_scheduler.cc160
-rw-r--r--chromium/components/enterprise/browser/reporting/report_scheduler.h47
-rw-r--r--chromium/components/enterprise/browser/reporting/report_uploader.cc30
-rw-r--r--chromium/components/enterprise/browser/reporting/report_uploader.h13
-rw-r--r--chromium/components/enterprise/browser/reporting/report_uploader_unittest.cc99
-rw-r--r--chromium/components/enterprise/content/clipboard_restriction_service.cc11
-rw-r--r--chromium/components/enterprise/content/clipboard_restriction_service.h1
-rw-r--r--chromium/components/enterprise/content/copy_prevention_settings_policy_handler.cc2
-rw-r--r--chromium/components/error_page/common/localized_error.cc91
-rw-r--r--chromium/components/error_page/common/localized_error.h11
-rw-r--r--chromium/components/error_page/content/browser/net_error_auto_reloader_browsertest.cc2
-rw-r--r--chromium/components/error_page_strings.grdp3
-rw-r--r--chromium/components/error_page_strings_grdp/IDS_ERRORPAGES_HEADING_BLOCKED_SCHEME.png.sha11
-rw-r--r--chromium/components/exo/BUILD.gn10
-rw-r--r--chromium/components/exo/DEPS1
-rw-r--r--chromium/components/exo/OWNERS4
-rw-r--r--chromium/components/exo/buffer.cc51
-rw-r--r--chromium/components/exo/buffer.h26
-rw-r--r--chromium/components/exo/buffer_unittest.cc56
-rw-r--r--chromium/components/exo/buildflags.gni5
-rw-r--r--chromium/components/exo/capabilities.h1
-rw-r--r--chromium/components/exo/client_controlled_shell_surface_unittest.cc90
-rw-r--r--chromium/components/exo/data_device.cc5
-rw-r--r--chromium/components/exo/data_device.h4
-rw-r--r--chromium/components/exo/data_device_unittest.cc16
-rw-r--r--chromium/components/exo/data_offer.cc46
-rw-r--r--chromium/components/exo/data_offer_unittest.cc209
-rw-r--r--chromium/components/exo/data_source.cc20
-rw-r--r--chromium/components/exo/data_source.h2
-rw-r--r--chromium/components/exo/data_source_unittest.cc33
-rw-r--r--chromium/components/exo/display_unittest.cc87
-rw-r--r--chromium/components/exo/drag_drop_operation.cc106
-rw-r--r--chromium/components/exo/drag_drop_operation.h13
-rw-r--r--chromium/components/exo/drag_drop_operation_unittest.cc184
-rw-r--r--chromium/components/exo/extended_drag_source.cc58
-rw-r--r--chromium/components/exo/extended_drag_source.h1
-rw-r--r--chromium/components/exo/extended_drag_source_unittest.cc190
-rw-r--r--chromium/components/exo/keyboard.cc9
-rw-r--r--chromium/components/exo/keyboard_unittest.cc1
-rw-r--r--chromium/components/exo/layer_tree_frame_sink_holder.cc6
-rw-r--r--chromium/components/exo/notification_surface.cc3
-rw-r--r--chromium/components/exo/pointer.cc230
-rw-r--r--chromium/components/exo/pointer.h56
-rw-r--r--chromium/components/exo/pointer_constraint_delegate.h28
-rw-r--r--chromium/components/exo/pointer_unittest.cc620
-rw-r--r--chromium/components/exo/protected_native_pixmap_query_delegate.h28
-rw-r--r--chromium/components/exo/seat.cc52
-rw-r--r--chromium/components/exo/seat.h21
-rw-r--r--chromium/components/exo/seat_observer.h13
-rw-r--r--chromium/components/exo/seat_unittest.cc160
-rw-r--r--chromium/components/exo/server/BUILD.gn1
-rw-r--r--chromium/components/exo/server/wayland_server_controller.cc2
-rw-r--r--chromium/components/exo/server/wayland_server_controller.h8
-rw-r--r--chromium/components/exo/shell_surface.cc55
-rw-r--r--chromium/components/exo/shell_surface_base.cc81
-rw-r--r--chromium/components/exo/shell_surface_base.h10
-rw-r--r--chromium/components/exo/shell_surface_unittest.cc354
-rw-r--r--chromium/components/exo/sub_surface_unittest.cc39
-rw-r--r--chromium/components/exo/surface.cc129
-rw-r--r--chromium/components/exo/surface.h35
-rw-r--r--chromium/components/exo/surface_observer.h11
-rw-r--r--chromium/components/exo/surface_test_util.cc12
-rw-r--r--chromium/components/exo/surface_test_util.h37
-rw-r--r--chromium/components/exo/surface_tree_host.cc29
-rw-r--r--chromium/components/exo/surface_unittest.cc40
-rw-r--r--chromium/components/exo/text_input.cc59
-rw-r--r--chromium/components/exo/text_input.h17
-rw-r--r--chromium/components/exo/text_input_unittest.cc19
-rw-r--r--chromium/components/exo/ui_lock_controller.cc308
-rw-r--r--chromium/components/exo/ui_lock_controller.h23
-rw-r--r--chromium/components/exo/ui_lock_controller_unittest.cc200
-rw-r--r--chromium/components/exo/wayland/BUILD.gn36
-rw-r--r--chromium/components/exo/wayland/clients/hdr.cc2
-rw-r--r--chromium/components/exo/wayland/protocol/aura-shell.xml15
-rw-r--r--chromium/components/exo/wayland/protocol/chrome-color-management.xml1
-rw-r--r--chromium/components/exo/wayland/protocol/surface-augmenter.xml6
-rw-r--r--chromium/components/exo/wayland/server.cc17
-rw-r--r--chromium/components/exo/wayland/server.h14
-rw-r--r--chromium/components/exo/wayland/wayland_pointer_delegate.cc6
-rw-r--r--chromium/components/exo/wayland/wayland_watcher.cc20
-rw-r--r--chromium/components/exo/wayland/wayland_watcher.h6
-rw-r--r--chromium/components/exo/wayland/weston_test.cc119
-rw-r--r--chromium/components/exo/wayland/weston_test.h36
-rw-r--r--chromium/components/exo/wayland/weston_test_stub.cc18
-rw-r--r--chromium/components/exo/wayland/zaura_shell.cc12
-rw-r--r--chromium/components/exo/wayland/zaura_shell.h3
-rw-r--r--chromium/components/exo/wayland/zcr_color_manager.cc424
-rw-r--r--chromium/components/exo/wayland/zcr_color_manager.h6
-rw-r--r--chromium/components/exo/wayland/zcr_remote_shell.cc1
-rw-r--r--chromium/components/exo/wayland/zcr_remote_shell_event_mapping.h1
-rw-r--r--chromium/components/exo/wayland/zcr_remote_shell_impl.cc35
-rw-r--r--chromium/components/exo/wayland/zcr_remote_shell_impl_unittest.cc16
-rw-r--r--chromium/components/exo/wayland/zcr_remote_shell_v2.cc1
-rw-r--r--chromium/components/exo/wayland/zcr_touchpad_haptics.cc74
-rw-r--r--chromium/components/exo/wayland/zwp_linux_dmabuf.cc27
-rw-r--r--chromium/components/exo/wayland/zwp_pointer_constraints.cc64
-rw-r--r--chromium/components/exo/wayland/zwp_text_input_manager.cc8
-rw-r--r--chromium/components/exo/window_properties.cc8
-rw-r--r--chromium/components/exo/window_properties.h9
-rw-r--r--chromium/components/exo/wm_helper.h8
-rw-r--r--chromium/components/exo/wm_helper_chromeos.cc10
-rw-r--r--chromium/components/exo/wm_helper_chromeos.h2
-rw-r--r--chromium/components/exo/wm_helper_chromeos_unittest.cc9
-rw-r--r--chromium/components/exo/xdg_shell_surface.cc8
-rw-r--r--chromium/components/external_intents/android/BUILD.gn2
-rw-r--r--chromium/components/external_intents/android/javatests/src/org/chromium/components/external_intents/ExternalNavigationHandlerTest.java302
-rw-r--r--chromium/components/external_intents/android/javatests/src/org/chromium/components/external_intents/RedirectHandlerTest.java50
-rw-r--r--chromium/components/favicon/content/content_favicon_driver.cc4
-rw-r--r--chromium/components/favicon/content/content_favicon_driver_unittest.cc5
-rw-r--r--chromium/components/favicon/core/favicon_database.cc18
-rw-r--r--chromium/components/favicon/core/favicon_database_unittest.cc2
-rw-r--r--chromium/components/favicon/core/favicon_driver_impl.cc2
-rw-r--r--chromium/components/favicon/ios/web_favicon_driver.h8
-rw-r--r--chromium/components/favicon/ios/web_favicon_driver.mm69
-rw-r--r--chromium/components/favicon_base/favicon_url_parser.cc2
-rw-r--r--chromium/components/favicon_base/favicon_util.cc8
-rw-r--r--chromium/components/favicon_base/favicon_util.h2
-rw-r--r--chromium/components/favicon_base/select_favicon_frames_unittest.cc4
-rw-r--r--chromium/components/feature_engagement/README.md35
-rw-r--r--chromium/components/feature_engagement/internal/android/tracker_impl_android.cc46
-rw-r--r--chromium/components/feature_engagement/internal/android/tracker_impl_android.h16
-rw-r--r--chromium/components/feature_engagement/internal/condition_validator.cc4
-rw-r--r--chromium/components/feature_engagement/internal/condition_validator.h13
-rw-r--r--chromium/components/feature_engagement/internal/condition_validator_unittest.cc6
-rw-r--r--chromium/components/feature_engagement/internal/feature_config_condition_validator.cc16
-rw-r--r--chromium/components/feature_engagement/internal/feature_config_condition_validator.h7
-rw-r--r--chromium/components/feature_engagement/internal/feature_config_condition_validator_unittest.cc44
-rw-r--r--chromium/components/feature_engagement/internal/never_condition_validator.cc10
-rw-r--r--chromium/components/feature_engagement/internal/never_condition_validator.h4
-rw-r--r--chromium/components/feature_engagement/internal/never_condition_validator_unittest.cc1
-rw-r--r--chromium/components/feature_engagement/internal/once_condition_validator.cc15
-rw-r--r--chromium/components/feature_engagement/internal/once_condition_validator.h7
-rw-r--r--chromium/components/feature_engagement/internal/once_condition_validator_unittest.cc16
-rw-r--r--chromium/components/feature_engagement/internal/tracker_impl.cc41
-rw-r--r--chromium/components/feature_engagement/internal/tracker_impl.h10
-rw-r--r--chromium/components/feature_engagement/internal/tracker_impl_unittest.cc81
-rw-r--r--chromium/components/feature_engagement/public/android/wrapping_test_tracker.cc16
-rw-r--r--chromium/components/feature_engagement/public/android/wrapping_test_tracker.h7
-rw-r--r--chromium/components/feature_engagement/public/event_constants.cc18
-rw-r--r--chromium/components/feature_engagement/public/event_constants.h22
-rw-r--r--chromium/components/feature_engagement/public/feature_configurations.cc206
-rw-r--r--chromium/components/feature_engagement/public/feature_constants.cc68
-rw-r--r--chromium/components/feature_engagement/public/feature_constants.h41
-rw-r--r--chromium/components/feature_engagement/public/feature_list.cc36
-rw-r--r--chromium/components/feature_engagement/public/feature_list.h65
-rw-r--r--chromium/components/feature_engagement/public/tracker.h35
-rw-r--r--chromium/components/federated_learning/BUILD.gn45
-rw-r--r--chromium/components/federated_learning/COMMON_METADATA1
-rw-r--r--chromium/components/federated_learning/DEPS6
-rw-r--r--chromium/components/federated_learning/DIR_METADATA1
-rw-r--r--chromium/components/federated_learning/OWNERS4
-rw-r--r--chromium/components/federated_learning/README.md7
-rw-r--r--chromium/components/federated_learning/features/features.cc45
-rw-r--r--chromium/components/federated_learning/features/features.h25
-rw-r--r--chromium/components/federated_learning/floc_constants.cc54
-rw-r--r--chromium/components/federated_learning/floc_constants.h48
-rw-r--r--chromium/components/federated_learning/floc_id.cc169
-rw-r--r--chromium/components/federated_learning/floc_id.h158
-rw-r--r--chromium/components/federated_learning/floc_id_unittest.cc304
-rw-r--r--chromium/components/federated_learning/floc_sorting_lsh_clusters_service.cc180
-rw-r--r--chromium/components/federated_learning/floc_sorting_lsh_clusters_service.h85
-rw-r--r--chromium/components/federated_learning/floc_sorting_lsh_clusters_service_unittest.cc284
-rw-r--r--chromium/components/federated_learning/sim_hash.cc91
-rw-r--r--chromium/components/federated_learning/sim_hash.h34
-rw-r--r--chromium/components/federated_learning/sim_hash_unittest.cc228
-rw-r--r--chromium/components/feed/content/renderer/rss_link_reader.cc6
-rw-r--r--chromium/components/feed/core/common/pref_names.cc49
-rw-r--r--chromium/components/feed/core/common/pref_names.h5
-rw-r--r--chromium/components/feed/core/proto/v2/store.proto28
-rw-r--r--chromium/components/feed/core/proto/v2/wire/action_payload.proto2
-rw-r--r--chromium/components/feed/core/proto/v2/wire/chrome_feed_response_metadata.proto2
-rw-r--r--chromium/components/feed/core/proto/v2/wire/reliability_logging_enums.proto9
-rw-r--r--chromium/components/feed/core/proto/v2/wire/upload_actions_request.proto2
-rw-r--r--chromium/components/feed/core/proto/v2/wire/web_feeds.proto1
-rw-r--r--chromium/components/feed/core/v2/BUILD.gn14
-rw-r--r--chromium/components/feed/core/v2/api_test/feed_api_notice_card_unittest.cc227
-rw-r--r--chromium/components/feed/core/v2/api_test/feed_api_reliability_logging_unittest.cc8
-rw-r--r--chromium/components/feed/core/v2/api_test/feed_api_stream_unittest.cc298
-rw-r--r--chromium/components/feed/core/v2/api_test/feed_api_subscriptions_unittest.cc473
-rw-r--r--chromium/components/feed/core/v2/api_test/feed_api_test.cc95
-rw-r--r--chromium/components/feed/core/v2/api_test/feed_api_test.h31
-rw-r--r--chromium/components/feed/core/v2/config.h2
-rw-r--r--chromium/components/feed/core/v2/enums.cc68
-rw-r--r--chromium/components/feed/core/v2/enums.h37
-rw-r--r--chromium/components/feed/core/v2/feed_network.h30
-rw-r--r--chromium/components/feed/core/v2/feed_network_impl.cc157
-rw-r--r--chromium/components/feed/core/v2/feed_network_impl.h20
-rw-r--r--chromium/components/feed/core/v2/feed_network_impl_unittest.cc256
-rw-r--r--chromium/components/feed/core/v2/feed_store.cc50
-rw-r--r--chromium/components/feed/core/v2/feed_store.h12
-rw-r--r--chromium/components/feed/core/v2/feed_stream.cc273
-rw-r--r--chromium/components/feed/core/v2/feed_stream.h47
-rw-r--r--chromium/components/feed/core/v2/ios_shared_prefs.h3
-rw-r--r--chromium/components/feed/core/v2/metrics_reporter.cc62
-rw-r--r--chromium/components/feed/core/v2/metrics_reporter.h13
-rw-r--r--chromium/components/feed/core/v2/metrics_reporter_unittest.cc151
-rw-r--r--chromium/components/feed/core/v2/operation_token.cc31
-rw-r--r--chromium/components/feed/core/v2/operation_token.h48
-rw-r--r--chromium/components/feed/core/v2/operation_token_unittest.cc47
-rw-r--r--chromium/components/feed/core/v2/persistent_key_value_store_impl.h1
-rw-r--r--chromium/components/feed/core/v2/prefs.cc3
-rw-r--r--chromium/components/feed/core/v2/proto_util.cc10
-rw-r--r--chromium/components/feed/core/v2/protocol_translator.cc12
-rw-r--r--chromium/components/feed/core/v2/protocol_translator.h6
-rw-r--r--chromium/components/feed/core/v2/protocol_translator_unittest.cc22
-rw-r--r--chromium/components/feed/core/v2/public/common_enums.cc2
-rw-r--r--chromium/components/feed/core/v2/public/common_enums.h4
-rw-r--r--chromium/components/feed/core/v2/public/feed_api.h18
-rw-r--r--chromium/components/feed/core/v2/public/feed_service.cc25
-rw-r--r--chromium/components/feed/core/v2/public/feed_service.h9
-rw-r--r--chromium/components/feed/core/v2/public/ios/notice_card_tracker_unittest.cc4
-rw-r--r--chromium/components/feed/core/v2/public/logging_parameters.cc74
-rw-r--r--chromium/components/feed/core/v2/public/logging_parameters.h48
-rw-r--r--chromium/components/feed/core/v2/public/logging_parameters_unittest.cc42
-rw-r--r--chromium/components/feed/core/v2/public/public_types.cc47
-rw-r--r--chromium/components/feed/core/v2/public/public_types_unittest.cc6
-rw-r--r--chromium/components/feed/core/v2/public/stream_type.cc18
-rw-r--r--chromium/components/feed/core/v2/public/stream_type.h29
-rw-r--r--chromium/components/feed/core/v2/public/types.h88
-rw-r--r--chromium/components/feed/core/v2/public/web_feed_subscriptions.h10
-rw-r--r--chromium/components/feed/core/v2/scheduling.cc2
-rw-r--r--chromium/components/feed/core/v2/stream/privacy_notice_card_tracker.cc13
-rw-r--r--chromium/components/feed/core/v2/stream/upload_criteria.cc57
-rw-r--r--chromium/components/feed/core/v2/stream/upload_criteria.h42
-rw-r--r--chromium/components/feed/core/v2/stream_model.cc7
-rw-r--r--chromium/components/feed/core/v2/stream_model.h10
-rw-r--r--chromium/components/feed/core/v2/stream_model_unittest.cc45
-rw-r--r--chromium/components/feed/core/v2/surface_updater.cc31
-rw-r--r--chromium/components/feed/core/v2/surface_updater.h4
-rw-r--r--chromium/components/feed/core/v2/tasks/load_more_task.cc26
-rw-r--r--chromium/components/feed/core/v2/tasks/load_stream_from_store_task.cc21
-rw-r--r--chromium/components/feed/core/v2/tasks/load_stream_from_store_task.h2
-rw-r--r--chromium/components/feed/core/v2/tasks/load_stream_task.cc96
-rw-r--r--chromium/components/feed/core/v2/tasks/load_stream_task.h11
-rw-r--r--chromium/components/feed/core/v2/tasks/prefetch_images_task.cc2
-rw-r--r--chromium/components/feed/core/v2/tasks/upload_actions_task.cc66
-rw-r--r--chromium/components/feed/core/v2/tasks/upload_actions_task.h10
-rw-r--r--chromium/components/feed/core/v2/tasks/wait_for_store_initialize_task.cc4
-rw-r--r--chromium/components/feed/core/v2/types.cc39
-rw-r--r--chromium/components/feed/core/v2/types.h31
-rw-r--r--chromium/components/feed/core/v2/types_unittest.cc31
-rw-r--r--chromium/components/feed/core/v2/web_feed_subscription_coordinator.cc475
-rw-r--r--chromium/components/feed/core/v2/web_feed_subscription_coordinator.h77
-rw-r--r--chromium/components/feed/core/v2/web_feed_subscriptions/fetch_recommended_web_feeds_task.cc12
-rw-r--r--chromium/components/feed/core/v2/web_feed_subscriptions/fetch_recommended_web_feeds_task.h3
-rw-r--r--chromium/components/feed/core/v2/web_feed_subscriptions/fetch_subscribed_web_feeds_task.cc13
-rw-r--r--chromium/components/feed/core/v2/web_feed_subscriptions/fetch_subscribed_web_feeds_task.h3
-rw-r--r--chromium/components/feed/core/v2/web_feed_subscriptions/subscribe_to_web_feed_task.cc20
-rw-r--r--chromium/components/feed/core/v2/web_feed_subscriptions/subscribe_to_web_feed_task.h5
-rw-r--r--chromium/components/feed/core/v2/web_feed_subscriptions/unsubscribe_from_web_feed_task.cc13
-rw-r--r--chromium/components/feed/core/v2/web_feed_subscriptions/unsubscribe_from_web_feed_task.h3
-rw-r--r--chromium/components/feed/core/v2/web_feed_subscriptions/web_feed_index.cc5
-rw-r--r--chromium/components/feed/core/v2/web_feed_subscriptions/web_feed_index.h1
-rw-r--r--chromium/components/feed/core/v2/web_feed_subscriptions/web_feed_metadata_model.cc107
-rw-r--r--chromium/components/feed/core/v2/web_feed_subscriptions/web_feed_metadata_model.h62
-rw-r--r--chromium/components/feed/core/v2/web_feed_subscriptions/web_feed_subscription_model.cc132
-rw-r--r--chromium/components/feed/core/v2/web_feed_subscriptions/web_feed_subscription_model.h70
-rw-r--r--chromium/components/feed/core/v2/web_feed_subscriptions/web_feed_types.cc52
-rw-r--r--chromium/components/feed/core/v2/web_feed_subscriptions/web_feed_types.h65
-rw-r--r--chromium/components/feed/core/v2/wire_response_translator.cc4
-rw-r--r--chromium/components/feed/core/v2/wire_response_translator.h3
-rw-r--r--chromium/components/feed/feed_feature_list.cc16
-rw-r--r--chromium/components/feed/feed_feature_list.h13
-rw-r--r--chromium/components/feedback/BUILD.gn1
-rw-r--r--chromium/components/feedback/feedback_data.cc10
-rw-r--r--chromium/components/feedback/feedback_data.h8
-rw-r--r--chromium/components/feedback/feedback_data_unittest.cc5
-rw-r--r--chromium/components/feedback/feedback_uploader.cc21
-rw-r--r--chromium/components/feedback/feedback_uploader_unittest.cc2
-rw-r--r--chromium/components/feedback/feedback_util.cc5
-rw-r--r--chromium/components/feedback/feedback_util.h2
-rw-r--r--chromium/components/feedback/pii_types.h66
-rw-r--r--chromium/components/feedback/redaction_tool.cc217
-rw-r--r--chromium/components/feedback/redaction_tool.h62
-rw-r--r--chromium/components/feedback/redaction_tool_unittest.cc534
-rw-r--r--chromium/components/filename_generation/filename_generation.cc4
-rw-r--r--chromium/components/filename_generation/filename_generation_unittest.cc16
-rw-r--r--chromium/components/find_in_page/android/BUILD.gn1
-rw-r--r--chromium/components/find_in_page/find_tab_helper.cc2
-rw-r--r--chromium/components/find_in_page/find_tab_helper.h2
-rw-r--r--chromium/components/flags_ui/feature_entry.cc81
-rw-r--r--chromium/components/flags_ui/feature_entry.h4
-rw-r--r--chromium/components/flags_ui/flags_state.cc52
-rw-r--r--chromium/components/flags_ui/flags_state_unittest.cc31
-rw-r--r--chromium/components/flags_ui/flags_test_helpers.cc10
-rw-r--r--chromium/components/flags_ui/flags_ui_constants.cc6
-rw-r--r--chromium/components/flags_ui/flags_ui_constants.h6
-rw-r--r--chromium/components/flags_ui/pref_service_flags_storage.cc4
-rw-r--r--chromium/components/flags_ui/resources/flags.css31
-rw-r--r--chromium/components/flags_ui/resources/flags.html2
-rw-r--r--chromium/components/fullscreen_control/subtle_notification_view.cc50
-rw-r--r--chromium/components/fullscreen_control/subtle_notification_view.h10
-rw-r--r--chromium/components/fullscreen_control_strings.grdp13
-rw-r--r--chromium/components/fullscreen_control_strings_grdp/IDS_FULLSCREEN_HOLD_TO_EXIT_FULLSCREEN.png.sha1 (renamed from chromium/components/fullscreen_control_strings_grdp/IDS_FULLSCREEN_HOLD_ESC_TO_EXIT_FULLSCREEN.png.sha1)0
-rw-r--r--chromium/components/fullscreen_control_strings_grdp/IDS_FULLSCREEN_PRESS_TO_EXIT_FULLSCREEN.png.sha1 (renamed from chromium/components/fullscreen_control_strings_grdp/IDS_FULLSCREEN_PRESS_ESC_TO_EXIT_FULLSCREEN.png.sha1)0
-rw-r--r--chromium/components/fullscreen_control_strings_grdp/IDS_FULLSCREEN_PRESS_TO_EXIT_FULLSCREEN_TWO_KEYS.png.sha11
-rw-r--r--chromium/components/fullscreen_control_strings_grdp/IDS_PRESS_TO_EXIT_MOUSELOCK.png.sha11
-rw-r--r--chromium/components/fullscreen_control_strings_grdp/IDS_PRESS_TO_EXIT_MOUSELOCK_TWO_KEYS.png.sha11
-rw-r--r--chromium/components/gcm_driver/crypto/BUILD.gn2
-rw-r--r--chromium/components/gcm_driver/crypto/gcm_message_cryptographer.h33
-rw-r--r--chromium/components/gcm_driver/crypto/p256_key_util.h16
-rw-r--r--chromium/components/gcm_driver/features.cc1
-rw-r--r--chromium/components/gcm_driver/features.h4
-rw-r--r--chromium/components/gcm_driver/gcm_desktop_utils.cc10
-rw-r--r--chromium/components/global_media_controls/public/media_item_manager.h1
-rw-r--r--chromium/components/global_media_controls/public/views/media_item_ui_view_unittest.cc4
-rw-r--r--chromium/components/grpc_support/bidirectional_stream_unittest.cc4
-rw-r--r--chromium/components/guest_view/browser/BUILD.gn8
-rw-r--r--chromium/components/guest_view/browser/DEPS3
-rw-r--r--chromium/components/guest_view/browser/bad_message.cc7
-rw-r--r--chromium/components/guest_view/browser/bad_message.h7
-rw-r--r--chromium/components/guest_view/browser/guest_view_base.cc65
-rw-r--r--chromium/components/guest_view/browser/guest_view_base.h21
-rw-r--r--chromium/components/guest_view/browser/guest_view_manager.h2
-rw-r--r--chromium/components/guest_view/browser/guest_view_message_filter.cc177
-rw-r--r--chromium/components/guest_view/browser/guest_view_message_filter.h88
-rw-r--r--chromium/components/guest_view/browser/guest_view_message_handler.cc123
-rw-r--r--chromium/components/guest_view/browser/guest_view_message_handler.h64
-rw-r--r--chromium/components/guest_view/common/BUILD.gn15
-rw-r--r--chromium/components/guest_view/common/OWNERS6
-rw-r--r--chromium/components/guest_view/common/guest_view.mojom32
-rw-r--r--chromium/components/guest_view/common/guest_view_message_generator.cc29
-rw-r--r--chromium/components/guest_view/common/guest_view_message_generator.h8
-rw-r--r--chromium/components/guest_view/common/guest_view_messages.h45
-rw-r--r--chromium/components/guest_view/renderer/BUILD.gn10
-rw-r--r--chromium/components/guest_view/renderer/guest_view_container.cc47
-rw-r--r--chromium/components/guest_view/renderer/guest_view_container.h24
-rw-r--r--chromium/components/guest_view/renderer/guest_view_container_dispatcher.cc41
-rw-r--r--chromium/components/guest_view/renderer/guest_view_container_dispatcher.h34
-rw-r--r--chromium/components/guest_view/renderer/guest_view_request.cc60
-rw-r--r--chromium/components/guest_view/renderer/guest_view_request.h51
-rw-r--r--chromium/components/guest_view/renderer/iframe_guest_view_container.cc30
-rw-r--r--chromium/components/guest_view/renderer/iframe_guest_view_container.h31
-rw-r--r--chromium/components/guest_view/renderer/iframe_guest_view_request.cc47
-rw-r--r--chromium/components/guest_view/renderer/iframe_guest_view_request.h47
-rw-r--r--chromium/components/gwp_asan/client/guarded_page_allocator.cc13
-rw-r--r--chromium/components/gwp_asan/client/guarded_page_allocator_posix.cc3
-rw-r--r--chromium/components/gwp_asan/client/guarded_page_allocator_unittest.cc4
-rw-r--r--chromium/components/gwp_asan/client/guarded_page_allocator_win.cc5
-rw-r--r--chromium/components/gwp_asan/client/gwp_asan.cc12
-rw-r--r--chromium/components/gwp_asan/client/sampling_malloc_shims.cc3
-rw-r--r--chromium/components/gwp_asan/client/sampling_malloc_shims_unittest.cc30
-rw-r--r--chromium/components/gwp_asan/client/sampling_partitionalloc_shims_unittest.cc2
-rw-r--r--chromium/components/gwp_asan/client/sampling_state.h2
-rw-r--r--chromium/components/gwp_asan/crash_handler/crash_analyzer.cc12
-rw-r--r--chromium/components/gwp_asan/crash_handler/crash_analyzer_unittest.cc11
-rw-r--r--chromium/components/gwp_asan/crash_handler/crash_handler.cc4
-rw-r--r--chromium/components/gwp_asan/crash_handler/crash_handler_unittest.cc30
-rw-r--r--chromium/components/handoff/handoff_manager.h6
-rw-r--r--chromium/components/handoff/handoff_manager.mm12
-rw-r--r--chromium/components/heap_profiling/in_process/heap_profiler_controller.cc63
-rw-r--r--chromium/components/heap_profiling/in_process/heap_profiler_controller.h9
-rw-r--r--chromium/components/heap_profiling/in_process/heap_profiler_controller_unittest.cc290
-rw-r--r--chromium/components/heap_profiling/multi_process/supervisor.h1
-rw-r--r--chromium/components/heap_profiling/multi_process/test_driver.cc31
-rw-r--r--chromium/components/heavy_ad_intervention/heavy_ad_helper.cc14
-rw-r--r--chromium/components/history/core/browser/BUILD.gn3
-rw-r--r--chromium/components/history/core/browser/browsing_history_service.cc12
-rw-r--r--chromium/components/history/core/browser/download_database.cc53
-rw-r--r--chromium/components/history/core/browser/download_database.h4
-rw-r--r--chromium/components/history/core/browser/download_row.cc5
-rw-r--r--chromium/components/history/core/browser/download_row.h5
-rw-r--r--chromium/components/history/core/browser/download_types.h4
-rw-r--r--chromium/components/history/core/browser/expire_history_backend.cc2
-rw-r--r--chromium/components/history/core/browser/history_backend.cc67
-rw-r--r--chromium/components/history/core/browser/history_backend.h17
-rw-r--r--chromium/components/history/core/browser/history_backend_db_unittest.cc108
-rw-r--r--chromium/components/history/core/browser/history_backend_unittest.cc152
-rw-r--r--chromium/components/history/core/browser/history_database.cc44
-rw-r--r--chromium/components/history/core/browser/history_database.h9
-rw-r--r--chromium/components/history/core/browser/history_service.cc50
-rw-r--r--chromium/components/history/core/browser/history_service.h31
-rw-r--r--chromium/components/history/core/browser/history_service_observer.h7
-rw-r--r--chromium/components/history/core/browser/history_types.cc7
-rw-r--r--chromium/components/history/core/browser/history_types.h42
-rw-r--r--chromium/components/history/core/browser/in_memory_database.cc7
-rw-r--r--chromium/components/history/core/browser/sync/delete_directive_handler.cc31
-rw-r--r--chromium/components/history/core/browser/sync/delete_directive_handler.h17
-rw-r--r--chromium/components/history/core/browser/sync/delete_directive_handler_unittest.cc3
-rw-r--r--chromium/components/history/core/browser/sync/typed_url_sync_bridge.cc299
-rw-r--r--chromium/components/history/core/browser/sync/typed_url_sync_bridge.h73
-rw-r--r--chromium/components/history/core/browser/sync/typed_url_sync_bridge_unittest.cc222
-rw-r--r--chromium/components/history/core/browser/top_sites_database.cc11
-rw-r--r--chromium/components/history/core/browser/top_sites_impl.cc4
-rw-r--r--chromium/components/history/core/browser/url_database.cc11
-rw-r--r--chromium/components/history/core/browser/url_row.cc42
-rw-r--r--chromium/components/history/core/browser/url_row.h36
-rw-r--r--chromium/components/history/core/browser/url_row_unittest.cc39
-rw-r--r--chromium/components/history/core/browser/visit_annotations_database.cc59
-rw-r--r--chromium/components/history/core/browser/visit_annotations_database.h8
-rw-r--r--chromium/components/history/core/browser/visit_annotations_database_unittest.cc28
-rw-r--r--chromium/components/history/metrics/domain_diversity_reporter.cc14
-rw-r--r--chromium/components/history/metrics/domain_diversity_reporter_unittest.cc104
-rw-r--r--chromium/components/history_clusters/core/BUILD.gn10
-rw-r--r--chromium/components/history_clusters/core/clusterer.cc42
-rw-r--r--chromium/components/history_clusters/core/clusterer_unittest.cc79
-rw-r--r--chromium/components/history_clusters/core/clustering_backend.h3
-rw-r--r--chromium/components/history_clusters/core/clustering_test_utils.cc68
-rw-r--r--chromium/components/history_clusters/core/clustering_test_utils.h27
-rw-r--r--chromium/components/history_clusters/core/features.cc5
-rw-r--r--chromium/components/history_clusters/core/features.h12
-rw-r--r--chromium/components/history_clusters/core/history_clusters_db_tasks.cc2
-rw-r--r--chromium/components/history_clusters/core/history_clusters_db_tasks.h11
-rw-r--r--chromium/components/history_clusters/core/history_clusters_service.cc351
-rw-r--r--chromium/components/history_clusters/core/history_clusters_service.h47
-rw-r--r--chromium/components/history_clusters/core/history_clusters_service_test_api.cc20
-rw-r--r--chromium/components/history_clusters/core/history_clusters_service_test_api.h10
-rw-r--r--chromium/components/history_clusters/core/history_clusters_service_unittest.cc347
-rw-r--r--chromium/components/history_clusters/core/history_clusters_types.cc21
-rw-r--r--chromium/components/history_clusters/core/history_clusters_types.h61
-rw-r--r--chromium/components/history_clusters/core/history_clusters_util.cc209
-rw-r--r--chromium/components/history_clusters/core/history_clusters_util.h47
-rw-r--r--chromium/components/history_clusters/core/history_clusters_util_unittest.cc151
-rw-r--r--chromium/components/history_clusters/core/keyword_cluster_finalizer.cc1
-rw-r--r--chromium/components/history_clusters/core/keyword_cluster_finalizer_unittest.cc10
-rw-r--r--chromium/components/history_clusters/core/noisy_cluster_finalizer.cc3
-rw-r--r--chromium/components/history_clusters/core/noisy_cluster_finalizer_unittest.cc14
-rw-r--r--chromium/components/history_clusters/core/on_device_clustering_backend.cc208
-rw-r--r--chromium/components/history_clusters/core/on_device_clustering_backend.h40
-rw-r--r--chromium/components/history_clusters/core/on_device_clustering_backend_unittest.cc335
-rw-r--r--chromium/components/history_clusters/core/on_device_clustering_features.cc24
-rw-r--r--chromium/components/history_clusters/core/on_device_clustering_features.h16
-rw-r--r--chromium/components/history_clusters/core/on_device_clustering_util.cc44
-rw-r--r--chromium/components/history_clusters/core/on_device_clustering_util.h12
-rw-r--r--chromium/components/history_clusters/core/on_device_clustering_util_unittest.cc113
-rw-r--r--chromium/components/history_clusters/core/proto/BUILD.gn9
-rw-r--r--chromium/components/history_clusters/core/proto/clusters.proto67
-rw-r--r--chromium/components/history_clusters/core/query_clusters_state.cc148
-rw-r--r--chromium/components/history_clusters/core/query_clusters_state.h107
-rw-r--r--chromium/components/history_clusters/core/query_clusters_state_unittest.cc130
-rw-r--r--chromium/components/history_clusters/core/ranking_cluster_finalizer.cc62
-rw-r--r--chromium/components/history_clusters/core/ranking_cluster_finalizer.h25
-rw-r--r--chromium/components/history_clusters/core/ranking_cluster_finalizer_unittest.cc97
-rw-r--r--chromium/components/history_clusters/core/similar_visit_deduper_cluster_finalizer.cc55
-rw-r--r--chromium/components/history_clusters/core/similar_visit_deduper_cluster_finalizer_unittest.cc16
-rw-r--r--chromium/components/history_clusters/core/single_visit_cluster_finalizer.cc21
-rw-r--r--chromium/components/history_clusters/core/single_visit_cluster_finalizer_unittest.cc4
-rw-r--r--chromium/components/history_clusters/core/url_deduper_cluster_finalizer.cc45
-rw-r--r--chromium/components/history_clusters/core/url_deduper_cluster_finalizer_unittest.cc18
-rw-r--r--chromium/components/image_fetcher/BUILD.gn3
-rw-r--r--chromium/components/image_fetcher/android/junit/src/org/chromium/components/image_fetcher/ImageFetcherBridgeTest.java4
-rw-r--r--chromium/components/image_fetcher/android/junit/src/org/chromium/components/image_fetcher/ImageFetcherTest.java13
-rw-r--r--chromium/components/infobars/README.md4
-rw-r--r--chromium/components/infobars/android/BUILD.gn1
-rw-r--r--chromium/components/infobars/android/res/layout/infobar_control_icon_with_title.xml28
-rw-r--r--chromium/components/infobars/android/res/layout/infobar_control_message.xml2
-rw-r--r--chromium/components/infobars/core/confirm_infobar_delegate.cc11
-rw-r--r--chromium/components/infobars/core/confirm_infobar_delegate.h10
-rw-r--r--chromium/components/infobars/core/infobar_delegate.cc6
-rw-r--r--chromium/components/infobars/core/infobar_delegate.h11
-rw-r--r--chromium/components/javascript_dialogs/app_modal_dialog_controller.cc2
-rw-r--r--chromium/components/js_injection/browser/js_communication_host.cc18
-rw-r--r--chromium/components/js_injection/browser/js_to_browser_messaging.cc1
-rw-r--r--chromium/components/js_injection/browser/web_message_reply_proxy.h7
-rw-r--r--chromium/components/js_injection/common/origin_matcher.cc6
-rw-r--r--chromium/components/keep_alive_registry/keep_alive_registry.cc6
-rw-r--r--chromium/components/keep_alive_registry/keep_alive_types.cc18
-rw-r--r--chromium/components/keep_alive_registry/keep_alive_types.h5
-rw-r--r--chromium/components/keyed_service/content/browser_context_dependency_manager.h6
-rw-r--r--chromium/components/keyed_service/core/dependency_graph.h9
-rw-r--r--chromium/components/keyed_service/core/dependency_manager.cc10
-rw-r--r--chromium/components/keyed_service/core/dependency_manager.h4
-rw-r--r--chromium/components/keyed_service/core/simple_key_map.cc1
-rw-r--r--chromium/components/language/content/browser/geo_language_provider.cc9
-rw-r--r--chromium/components/language/content/browser/geo_language_provider_unittest.cc9
-rw-r--r--chromium/components/language/content/browser/ulp_language_code_locator/ulp_language_code_locator.cc8
-rw-r--r--chromium/components/language/core/browser/BUILD.gn2
-rw-r--r--chromium/components/language/core/browser/DEPS1
-rw-r--r--chromium/components/language/core/browser/language_model_manager.cc10
-rw-r--r--chromium/components/language/core/browser/language_model_manager.h3
-rw-r--r--chromium/components/language/core/browser/language_model_manager_unittest.cc77
-rw-r--r--chromium/components/language/core/browser/language_prefs.cc6
-rw-r--r--chromium/components/language/core/browser/locale_util.cc2
-rw-r--r--chromium/components/language/core/browser/locale_util.h4
-rw-r--r--chromium/components/language/core/browser/pref_names.cc2
-rw-r--r--chromium/components/language/core/browser/pref_names.h2
-rw-r--r--chromium/components/language/core/browser/url_language_histogram.cc43
-rw-r--r--chromium/components/language/core/common/language_experiments.cc26
-rw-r--r--chromium/components/language/core/common/language_experiments.h5
-rw-r--r--chromium/components/language/core/common/language_util.cc4
-rw-r--r--chromium/components/language/core/common/locale_util_unittest.cc16
-rw-r--r--chromium/components/language/core/language_model/BUILD.gn7
-rw-r--r--chromium/components/language/core/language_model/baseline_language_model.cc70
-rw-r--r--chromium/components/language/core/language_model/baseline_language_model.h53
-rw-r--r--chromium/components/language/core/language_model/baseline_language_model_unittest.cc135
-rw-r--r--chromium/components/lens/lens_features.cc43
-rw-r--r--chromium/components/lens/lens_features.h14
-rw-r--r--chromium/components/leveldb_proto/internal/proto_database_perftest.cc16
-rw-r--r--chromium/components/leveldb_proto/internal/proto_database_selector.cc2
-rw-r--r--chromium/components/leveldb_proto/internal/proto_leveldb_wrapper.cc2
-rw-r--r--chromium/components/leveldb_proto/internal/shared_proto_database_client.cc121
-rw-r--r--chromium/components/leveldb_proto/internal/shared_proto_database_client.h42
-rw-r--r--chromium/components/leveldb_proto/internal/shared_proto_database_client_unittest.cc22
-rw-r--r--chromium/components/leveldb_proto/internal/shared_proto_database_unittest.cc2
-rw-r--r--chromium/components/leveldb_proto/public/shared_proto_database_client_list.cc5
-rw-r--r--chromium/components/leveldb_proto/public/shared_proto_database_client_list.h2
-rw-r--r--chromium/components/link_header_util/link_header_util_fuzzer.cc3
-rw-r--r--chromium/components/live_caption/live_caption_controller.cc11
-rw-r--r--chromium/components/live_caption/live_caption_controller.h2
-rw-r--r--chromium/components/live_caption/pref_names.cc2
-rw-r--r--chromium/components/live_caption/views/caption_bubble.cc4
-rw-r--r--chromium/components/login/base_screen_handler_utils.cc2
-rw-r--r--chromium/components/login/base_screen_handler_utils.h8
-rw-r--r--chromium/components/login/localized_values_builder.cc16
-rw-r--r--chromium/components/lookalikes/DEPS1
-rw-r--r--chromium/components/lookalikes/core/BUILD.gn2
-rw-r--r--chromium/components/lookalikes/core/lookalike_url_ui_util.cc2
-rw-r--r--chromium/components/lookalikes/core/lookalike_url_util.cc71
-rw-r--r--chromium/components/lookalikes/core/lookalike_url_util.h12
-rw-r--r--chromium/components/lookalikes/core/lookalike_url_util_unittest.cc122
-rw-r--r--chromium/components/management_strings.grdp27
-rw-r--r--chromium/components/management_strings_grdp/IDS_MANAGEMENT_PAGE_PRINTED_EVENT.png.sha11
-rw-r--r--chromium/components/management_strings_grdp/IDS_MANAGEMENT_PAGE_PRINTED_VISIBLE_DATA.png.sha11
-rw-r--r--chromium/components/management_strings_grdp/IDS_MANAGEMENT_REPORT_CRD_SESSIONS.png.sha11
-rw-r--r--chromium/components/management_strings_grdp/IDS_MANAGEMENT_REPORT_DEVICE_AUDIO_STATUS.png.sha11
-rw-r--r--chromium/components/management_strings_grdp/IDS_MANAGEMENT_REPORT_DEVICE_NETWORK_DATA.png.sha12
-rw-r--r--chromium/components/media_message_center/media_controls_progress_view_unittest.cc4
-rw-r--r--chromium/components/media_message_center/media_notification_view_impl_unittest.cc2
-rw-r--r--chromium/components/media_message_center/media_notification_view_modern_impl_unittest.cc2
-rw-r--r--chromium/components/media_router/OWNERS7
-rw-r--r--chromium/components/media_router/browser/android/junit/src/org/chromium/components/media_router/caf/CafBaseMediaRouteProviderTest.java6
-rw-r--r--chromium/components/media_router/browser/android/media_router_android.cc9
-rw-r--r--chromium/components/media_router/browser/issue_manager.cc1
-rw-r--r--chromium/components/media_router/browser/logger_impl.cc2
-rw-r--r--chromium/components/media_router/browser/logger_impl.h3
-rw-r--r--chromium/components/media_router/browser/logger_impl_unittest.cc2
-rw-r--r--chromium/components/media_router/browser/media_router.h17
-rw-r--r--chromium/components/media_router/browser/media_router_base.cc48
-rw-r--r--chromium/components/media_router/browser/media_router_base.h11
-rw-r--r--chromium/components/media_router/browser/media_router_base_unittest.cc14
-rw-r--r--chromium/components/media_router/browser/media_router_dialog_controller_unittest.cc6
-rw-r--r--chromium/components/media_router/browser/media_router_metrics.cc14
-rw-r--r--chromium/components/media_router/browser/media_router_metrics.h20
-rw-r--r--chromium/components/media_router/browser/media_router_metrics_unittest.cc12
-rw-r--r--chromium/components/media_router/browser/media_routes_observer.cc5
-rw-r--r--chromium/components/media_router/browser/media_routes_observer.h15
-rw-r--r--chromium/components/media_router/browser/presentation/local_presentation_manager_unittest.cc5
-rw-r--r--chromium/components/media_router/browser/presentation/presentation_service_delegate_impl.cc17
-rw-r--r--chromium/components/media_router/browser/presentation/presentation_service_delegate_impl.h2
-rw-r--r--chromium/components/media_router/common/discovery/media_sink_internal.h6
-rw-r--r--chromium/components/media_router/common/media_route.cc9
-rw-r--r--chromium/components/media_router/common/media_route.h11
-rw-r--r--chromium/components/media_router/common/media_route_unittest.cc16
-rw-r--r--chromium/components/media_router/common/media_source.h4
-rw-r--r--chromium/components/media_router/common/mojom/logger.mojom4
-rw-r--r--chromium/components/media_router/common/mojom/media_router.mojom36
-rw-r--r--chromium/components/media_router/common/mojom/media_router_mojom_traits.cc1
-rw-r--r--chromium/components/media_router/common/mojom/media_router_mojom_traits.h14
-rw-r--r--chromium/components/media_router/common/mojom/route_request_result_code.mojom3
-rw-r--r--chromium/components/media_router/common/pref_names.cc7
-rw-r--r--chromium/components/media_router/common/pref_names.h2
-rw-r--r--chromium/components/media_router/common/providers/cast/cast_media_source.cc8
-rw-r--r--chromium/components/media_router/common/providers/cast/cast_media_source.h8
-rw-r--r--chromium/components/media_router/common/route_request_result.h2
-rw-r--r--chromium/components/memory_pressure/system_memory_pressure_evaluator.cc14
-rw-r--r--chromium/components/memory_pressure/system_memory_pressure_evaluator_fuchsia.cc1
-rw-r--r--chromium/components/memory_pressure/system_memory_pressure_evaluator_win_unittest.cc2
-rw-r--r--chromium/components/messages/OWNERS2
-rw-r--r--chromium/components/messages/README.md236
-rw-r--r--chromium/components/messages/android/internal/BUILD.gn4
-rw-r--r--chromium/components/messages/android/internal/java/res/drawable-v23/message_bg_tinted.xml (renamed from chromium/components/messages/android/internal/java/res/drawable/message_bg_tinted.xml)2
-rw-r--r--chromium/components/messages/android/internal/java/res/drawable-v31/message_bg_tinted.xml12
-rw-r--r--chromium/components/messages/android/internal/java/res/layout/message_banner_view.xml9
-rw-r--r--chromium/components/messages/android/internal/java/res/values-night/dimens.xml8
-rw-r--r--chromium/components/messages/android/internal/java/res/values/dimens.xml5
-rw-r--r--chromium/components/messages/android/internal/java/src/org/chromium/components/messages/MessageBannerMediator.java15
-rw-r--r--chromium/components/messages/android/internal/java/src/org/chromium/components/messages/MessageBannerMediatorUnitTest.java56
-rw-r--r--chromium/components/messages/android/internal/java/src/org/chromium/components/messages/MessageBannerRenderTest.java6
-rw-r--r--chromium/components/messages/android/internal/java/src/org/chromium/components/messages/MessageBannerView.java32
-rw-r--r--chromium/components/messages/android/internal/java/src/org/chromium/components/messages/MessageBannerViewBinder.java12
-rw-r--r--chromium/components/messages/android/internal/java/src/org/chromium/components/messages/MessageBannerViewTest.java6
-rw-r--r--chromium/components/messages/android/internal/java/src/org/chromium/components/messages/SingleActionMessageTest.java6
-rw-r--r--chromium/components/messages/android/message_dispatcher_bridge.cc6
-rw-r--r--chromium/components/messages/android/message_dispatcher_bridge.h5
-rw-r--r--chromium/components/messages/android/message_enums.h2
-rw-r--r--chromium/components/messages/android/messages_feature.cc16
-rw-r--r--chromium/components/messages/android/messages_feature.h6
-rw-r--r--chromium/components/messages/android/mock_message_dispatcher_bridge.cc5
-rw-r--r--chromium/components/messages/android/mock_message_dispatcher_bridge.h1
-rw-r--r--chromium/components/messages/android/test/BUILD.gn18
-rw-r--r--chromium/components/metal_util/BUILD.gn2
-rw-r--r--chromium/components/metal_util/hdr_copier_layer.mm6
-rw-r--r--chromium/components/metal_util/switches.cc11
-rw-r--r--chromium/components/metal_util/switches.h16
-rw-r--r--chromium/components/metal_util/test_shader.mm11
-rw-r--r--chromium/components/metrics/BUILD.gn8
-rw-r--r--chromium/components/metrics/call_stack_profile_builder.cc4
-rw-r--r--chromium/components/metrics/call_stack_profile_builder_unittest.cc70
-rw-r--r--chromium/components/metrics/call_stack_profile_metadata_unittest.cc19
-rw-r--r--chromium/components/metrics/clean_exit_beacon.cc228
-rw-r--r--chromium/components/metrics/clean_exit_beacon.h67
-rw-r--r--chromium/components/metrics/clean_exit_beacon_unittest.cc322
-rw-r--r--chromium/components/metrics/content/DEPS4
-rw-r--r--chromium/components/metrics/content/content_stability_metrics_provider.cc163
-rw-r--r--chromium/components/metrics/content/content_stability_metrics_provider.h62
-rw-r--r--chromium/components/metrics/content/content_stability_metrics_provider_browsertest.cc124
-rw-r--r--chromium/components/metrics/content/content_stability_metrics_provider_unittest.cc82
-rw-r--r--chromium/components/metrics/data_use_tracker.cc31
-rw-r--r--chromium/components/metrics/demographics/user_demographics.cc7
-rw-r--r--chromium/components/metrics/drive_metrics_provider_win.cc3
-rw-r--r--chromium/components/metrics/field_trials_provider_unittest.cc9
-rw-r--r--chromium/components/metrics/file_metrics_provider.cc8
-rw-r--r--chromium/components/metrics/file_metrics_provider.h1
-rw-r--r--chromium/components/metrics/generate_expired_histograms_array.gni7
-rw-r--r--chromium/components/metrics/machine_id_provider_nonwin_unittest.cc2
-rw-r--r--chromium/components/metrics/machine_id_provider_win.cc4
-rw-r--r--chromium/components/metrics/metrics_data_validation.h1
-rw-r--r--chromium/components/metrics/metrics_log.cc24
-rw-r--r--chromium/components/metrics/metrics_log.h6
-rw-r--r--chromium/components/metrics/metrics_log_store_unittest.cc2
-rw-r--r--chromium/components/metrics/metrics_log_unittest.cc14
-rw-r--r--chromium/components/metrics/metrics_pref_names.cc11
-rw-r--r--chromium/components/metrics/metrics_pref_names.h2
-rw-r--r--chromium/components/metrics/metrics_scheduler.cc2
-rw-r--r--chromium/components/metrics/metrics_service.cc58
-rw-r--r--chromium/components/metrics/metrics_service.h25
-rw-r--r--chromium/components/metrics/metrics_service_accessor.cc16
-rw-r--r--chromium/components/metrics/metrics_service_accessor.h22
-rw-r--r--chromium/components/metrics/metrics_service_client.cc13
-rw-r--r--chromium/components/metrics/metrics_service_client.h22
-rw-r--r--chromium/components/metrics/metrics_service_unittest.cc46
-rw-r--r--chromium/components/metrics/metrics_state_manager.cc17
-rw-r--r--chromium/components/metrics/metrics_state_manager.h12
-rw-r--r--chromium/components/metrics/metrics_state_manager_unittest.cc4
-rw-r--r--chromium/components/metrics/net/cellular_logic_helper.cc6
-rw-r--r--chromium/components/metrics/net/network_metrics_provider.cc4
-rw-r--r--chromium/components/metrics/net/network_metrics_provider_unittest.cc6
-rw-r--r--chromium/components/metrics/persistent_histograms.cc12
-rw-r--r--chromium/components/metrics/psi_memory_parser.h114
-rw-r--r--chromium/components/metrics/psi_memory_parser_linux.cc185
-rw-r--r--chromium/components/metrics/psi_memory_parser_linux_unittest.cc163
-rw-r--r--chromium/components/metrics/single_sample_metrics_factory_impl_unittest.cc2
-rw-r--r--chromium/components/metrics/stability_metrics_helper.cc64
-rw-r--r--chromium/components/metrics/stability_metrics_helper.h24
-rw-r--r--chromium/components/metrics/stability_metrics_helper_unittest.cc22
-rw-r--r--chromium/components/metrics/stability_metrics_provider.cc24
-rw-r--r--chromium/components/metrics/stability_metrics_provider.h2
-rw-r--r--chromium/components/metrics/stability_metrics_provider_unittest.cc2
-rw-r--r--chromium/components/metrics/structured/external_metrics_unittest.cc13
-rw-r--r--chromium/components/metrics/structured/histogram_util.cc5
-rw-r--r--chromium/components/metrics/structured/histogram_util.h2
-rw-r--r--chromium/components/metrics/structured/recorder.cc1
-rw-r--r--chromium/components/metrics/structured/structured_metrics_features.cc2
-rw-r--r--chromium/components/metrics/structured/structured_metrics_provider.cc8
-rw-r--r--chromium/components/metrics/structured/structured_metrics_provider_unittest.cc18
-rw-r--r--chromium/components/metrics/ui/screen_info_metrics_provider.cc8
-rw-r--r--chromium/components/metrics/unsent_log_store.cc30
-rw-r--r--chromium/components/metrics/unsent_log_store.h4
-rw-r--r--chromium/components/metrics/unsent_log_store_unittest.cc4
-rw-r--r--chromium/components/metrics/version_utils.cc4
-rw-r--r--chromium/components/minidump_uploader/BUILD.gn5
-rw-r--r--chromium/components/minidump_uploader/DEPS3
-rw-r--r--chromium/components/minidump_uploader/OWNERS3
-rw-r--r--chromium/components/minidump_uploader/rewrite_minidumps_as_mimes.cc86
-rw-r--r--chromium/components/mirroring/browser/single_client_video_capture_host.cc5
-rw-r--r--chromium/components/mirroring/browser/single_client_video_capture_host.h1
-rw-r--r--chromium/components/mirroring/browser/single_client_video_capture_host_unittest.cc51
-rw-r--r--chromium/components/mirroring/service/fake_network_service.h22
-rw-r--r--chromium/components/mirroring/service/remoting_sender.cc17
-rw-r--r--chromium/components/mirroring/service/remoting_sender_unittest.cc19
-rw-r--r--chromium/components/mirroring/service/session.cc4
-rw-r--r--chromium/components/mirroring/service/session_unittest.cc2
-rw-r--r--chromium/components/mirroring/service/value_util.cc4
-rw-r--r--chromium/components/mirroring/service/video_capture_client.cc6
-rw-r--r--chromium/components/nacl/broker/BUILD.gn2
-rw-r--r--chromium/components/nacl/common/BUILD.gn2
-rw-r--r--chromium/components/nacl/loader/BUILD.gn8
-rw-r--r--chromium/components/nacl/loader/sandbox_linux/BUILD.gn1
-rw-r--r--chromium/components/navigation_interception/intercept_navigation_delegate.cc15
-rw-r--r--chromium/components/navigation_interception/intercept_navigation_delegate.h5
-rw-r--r--chromium/components/navigation_interception/intercept_navigation_throttle.cc22
-rw-r--r--chromium/components/navigation_interception/intercept_navigation_throttle.h4
-rw-r--r--chromium/components/navigation_interception/intercept_navigation_throttle_unittest.cc4
-rw-r--r--chromium/components/navigation_interception/navigation_params_android.cc5
-rw-r--r--chromium/components/navigation_interception/navigation_params_android.h3
-rw-r--r--chromium/components/net_log/chrome_net_log.cc20
-rw-r--r--chromium/components/net_log/net_export_file_writer.cc11
-rw-r--r--chromium/components/net_log/net_export_file_writer_unittest.cc32
-rw-r--r--chromium/components/network_hints/renderer/dns_prefetch_queue_unittest.cc3
-rw-r--r--chromium/components/network_hints/renderer/renderer_dns_prefetch.cc1
-rw-r--r--chromium/components/network_session_configurator/android/BUILD.gn22
-rw-r--r--chromium/components/network_session_configurator/android/NetworkSessionSwitches.java.tmpl18
-rw-r--r--chromium/components/network_session_configurator/browser/network_session_configurator.cc28
-rw-r--r--chromium/components/network_session_configurator/browser/network_session_configurator_unittest.cc63
-rw-r--r--chromium/components/network_session_configurator/common/network_switch_list.h7
-rw-r--r--chromium/components/network_session_configurator/common/network_switches.cc7
-rw-r--r--chromium/components/network_session_configurator/common/network_switches.h11
-rw-r--r--chromium/components/network_time/BUILD.gn7
-rw-r--r--chromium/components/network_time/historical_latencies_container.cc66
-rw-r--r--chromium/components/network_time/historical_latencies_container.h35
-rw-r--r--chromium/components/network_time/historical_latencies_container_unittest.cc73
-rw-r--r--chromium/components/network_time/network_time_test_utils.cc14
-rw-r--r--chromium/components/network_time/network_time_test_utils.h6
-rw-r--r--chromium/components/network_time/network_time_tracker.cc90
-rw-r--r--chromium/components/network_time/network_time_tracker.h32
-rw-r--r--chromium/components/network_time/network_time_tracker_unittest.cc111
-rw-r--r--chromium/components/new_or_sad_tab_strings.grdp90
-rw-r--r--chromium/components/new_or_sad_tab_strings_grdp/IDS_NEW_TAB_OTR_NOT_SAVED.png.sha12
-rw-r--r--chromium/components/new_or_sad_tab_strings_grdp/IDS_REVAMPED_INCOGNITO_NTP_DOES_DESCRIPTION.png.sha12
-rw-r--r--chromium/components/new_or_sad_tab_strings_grdp/IDS_REVAMPED_INCOGNITO_NTP_DOES_HEADER.png.sha12
-rw-r--r--chromium/components/new_or_sad_tab_strings_grdp/IDS_REVAMPED_INCOGNITO_NTP_DOES_NOT_DESCRIPTION.png.sha12
-rw-r--r--chromium/components/new_or_sad_tab_strings_grdp/IDS_REVAMPED_INCOGNITO_NTP_DOES_NOT_HEADER.png.sha12
-rw-r--r--chromium/components/new_or_sad_tab_strings_grdp/IDS_REVAMPED_INCOGNITO_NTP_LEARN_MORE.png.sha12
-rw-r--r--chromium/components/new_or_sad_tab_strings_grdp/IDS_REVAMPED_INCOGNITO_NTP_OTR_THIRD_PARTY_COOKIE.png.sha11
-rw-r--r--chromium/components/new_or_sad_tab_strings_grdp/IDS_REVAMPED_INCOGNITO_NTP_OTR_THIRD_PARTY_COOKIE_SUBLABEL.png.sha11
-rw-r--r--chromium/components/new_or_sad_tab_strings_grdp/IDS_REVAMPED_INCOGNITO_NTP_TITLE.png.sha12
-rw-r--r--chromium/components/no_state_prefetch/browser/no_state_prefetch_handle.cc8
-rw-r--r--chromium/components/no_state_prefetch/browser/no_state_prefetch_handle.h6
-rw-r--r--chromium/components/no_state_prefetch/browser/no_state_prefetch_link_manager.cc4
-rw-r--r--chromium/components/no_state_prefetch/browser/no_state_prefetch_manager.cc23
-rw-r--r--chromium/components/no_state_prefetch/browser/prerender_history.cc4
-rw-r--r--chromium/components/no_state_prefetch/browser/prerender_history_unittest.cc20
-rw-r--r--chromium/components/no_state_prefetch/common/BUILD.gn7
-rw-r--r--chromium/components/no_state_prefetch/common/DEPS1
-rw-r--r--chromium/components/no_state_prefetch/common/no_state_prefetch_utils.cc9
-rw-r--r--chromium/components/no_state_prefetch/common/prerender_url_loader_throttle.cc4
-rw-r--r--chromium/components/ntp_snippets/category_rankers/click_based_category_ranker.cc12
-rw-r--r--chromium/components/ntp_snippets/content_suggestions_service.cc5
-rw-r--r--chromium/components/ntp_snippets/features.cc4
-rw-r--r--chromium/components/ntp_snippets/pref_util.cc4
-rw-r--r--chromium/components/ntp_snippets/remote/json_request.cc22
-rw-r--r--chromium/components/ntp_snippets/remote/json_to_categories.cc4
-rw-r--r--chromium/components/ntp_snippets/remote/remote_suggestion.cc42
-rw-r--r--chromium/components/ntp_snippets/remote/remote_suggestion_unittest.cc22
-rw-r--r--chromium/components/ntp_snippets/remote/remote_suggestions_provider_impl.cc27
-rw-r--r--chromium/components/ntp_tiles/BUILD.gn9
-rw-r--r--chromium/components/ntp_tiles/DEPS1
-rw-r--r--chromium/components/ntp_tiles/custom_links_manager_impl_unittest.cc7
-rw-r--r--chromium/components/ntp_tiles/custom_links_store.cc5
-rw-r--r--chromium/components/ntp_tiles/icon_cacher_impl_unittest.cc2
-rw-r--r--chromium/components/ntp_tiles/most_visited_sites.cc15
-rw-r--r--chromium/components/ntp_tiles/most_visited_sites_unittest.cc7
-rw-r--r--chromium/components/ntp_tiles/popular_sites_impl.cc71
-rw-r--r--chromium/components/ntp_tiles/popular_sites_impl_unittest.cc4
-rw-r--r--chromium/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.cc8
-rw-r--r--chromium/components/offline_items_collection/core/BUILD.gn6
-rw-r--r--chromium/components/offline_items_collection/core/android/offline_item_bridge.cc3
-rw-r--r--chromium/components/offline_items_collection/core/offline_content_aggregator.cc14
-rw-r--r--chromium/components/offline_items_collection/core/offline_content_aggregator_unittest.cc83
-rw-r--r--chromium/components/offline_pages/content/background_loader/background_loader_contents.cc10
-rw-r--r--chromium/components/offline_pages/content/background_loader/background_loader_contents.h5
-rw-r--r--chromium/components/offline_pages/content/background_loader/background_loader_contents_unittest.cc12
-rw-r--r--chromium/components/offline_pages/core/archive_manager.cc2
-rw-r--r--chromium/components/offline_pages/core/archive_validator.cc11
-rw-r--r--chromium/components/offline_pages/core/archive_validator_unittest.cc20
-rw-r--r--chromium/components/offline_pages/core/background_snapshot_controller.cc15
-rw-r--r--chromium/components/offline_pages/core/background_snapshot_controller.h4
-rw-r--r--chromium/components/offline_pages/core/background_snapshot_controller_unittest.cc10
-rw-r--r--chromium/components/offline_pages/core/model/offline_page_model_taskified_unittest.cc12
-rw-r--r--chromium/components/offline_pages/core/model/offline_page_model_utils.cc6
-rw-r--r--chromium/components/offline_pages/core/model/offline_page_model_utils_unittest.cc2
-rw-r--r--chromium/components/offline_pages/core/model/persistent_page_consistency_check_task_unittest.cc4
-rw-r--r--chromium/components/offline_pages/core/model/startup_maintenance_task_unittest.cc8
-rw-r--r--chromium/components/offline_pages/core/offline_page_client_policy.cc2
-rw-r--r--chromium/components/offline_pages/core/offline_page_feature.cc2
-rw-r--r--chromium/components/offline_pages/core/offline_page_metadata_store.h1
-rw-r--r--chromium/components/offline_pages/core/prefetch/prefetch_importer_impl_unittest.cc5
-rw-r--r--chromium/components/offline_pages/core/prefetch/store/prefetch_store.h1
-rw-r--r--chromium/components/offline_pages/core/prefetch/tasks/add_unique_urls_task.cc7
-rw-r--r--chromium/components/offline_pages/core/prefetch/test_download_service.h1
-rw-r--r--chromium/components/offline_pages/core/snapshot_controller.cc4
-rw-r--r--chromium/components/offline_pages/core/snapshot_controller.h8
-rw-r--r--chromium/components/offline_pages/core/snapshot_controller_unittest.cc26
-rw-r--r--chromium/components/offline_pages/task/task.h1
-rw-r--r--chromium/components/offline_pages/task/task_queue.cc60
-rw-r--r--chromium/components/offline_pages/task/task_queue.h11
-rw-r--r--chromium/components/omnibox/browser/BUILD.gn25
-rw-r--r--chromium/components/omnibox_strings.grdp32
-rw-r--r--chromium/components/omnibox_strings_grdp/IDS_ANDROID_ACC_OMNIBOX_PEDAL_LAUNCH_INCOGNITO.png.sha11
-rw-r--r--chromium/components/omnibox_strings_grdp/IDS_ANDROID_ACC_OMNIBOX_PEDAL_LAUNCH_INCOGNITO_SUFFIX.png.sha11
-rw-r--r--chromium/components/omnibox_strings_grdp/IDS_ANDROID_OMNIBOX_PEDAL_LAUNCH_INCOGNITO_HINT.png.sha11
-rw-r--r--chromium/components/omnibox_strings_grdp/IDS_ANDROID_OMNIBOX_PEDAL_LAUNCH_INCOGNITO_SUGGESTION_CONTENTS.png.sha11
-rw-r--r--chromium/components/omnibox_strings_grdp/IDS_ANDROID_OMNIBOX_PEDAL_RUN_CHROME_SAFETY_CHECK_HINT.png.sha11
-rw-r--r--chromium/components/on_load_script_injector/browser/on_load_script_injector_host.cc4
-rw-r--r--chromium/components/onc/DIR_METADATA6
-rw-r--r--chromium/components/onc/docs/onc_spec.md19
-rw-r--r--chromium/components/onc/onc_constants.cc2
-rw-r--r--chromium/components/onc/onc_constants.h2
-rw-r--r--chromium/components/open_from_clipboard/clipboard_recent_content_generic.cc6
-rw-r--r--chromium/components/open_from_clipboard/clipboard_recent_content_generic_unittest.cc4
-rw-r--r--chromium/components/optimization_guide/DEPS2
-rw-r--r--chromium/components/optimization_guide/content/browser/BUILD.gn8
-rw-r--r--chromium/components/optimization_guide/content/browser/page_content_annotations_model_manager.cc102
-rw-r--r--chromium/components/optimization_guide/content/browser/page_content_annotations_model_manager.h23
-rw-r--r--chromium/components/optimization_guide/content/browser/page_content_annotations_model_manager_unittest.cc260
-rw-r--r--chromium/components/optimization_guide/content/browser/page_content_annotations_service.cc194
-rw-r--r--chromium/components/optimization_guide/content/browser/page_content_annotations_service.h103
-rw-r--r--chromium/components/optimization_guide/content/browser/page_content_annotations_web_contents_observer.cc101
-rw-r--r--chromium/components/optimization_guide/content/browser/page_content_annotations_web_contents_observer.h3
-rw-r--r--chromium/components/optimization_guide/content/browser/page_content_annotations_web_contents_observer_unittest.cc62
-rw-r--r--chromium/components/optimization_guide/content/browser/test_page_content_annotator.cc4
-rw-r--r--chromium/components/optimization_guide/content/browser/test_page_content_annotator.h4
-rw-r--r--chromium/components/optimization_guide/core/BUILD.gn127
-rw-r--r--chromium/components/optimization_guide/core/DEPS2
-rw-r--r--chromium/components/optimization_guide/core/base_model_executor.h6
-rw-r--r--chromium/components/optimization_guide/core/base_model_executor_helpers.h29
-rw-r--r--chromium/components/optimization_guide/core/bert_model_executor.cc17
-rw-r--r--chromium/components/optimization_guide/core/bloom_filter_unittest.cc2
-rw-r--r--chromium/components/optimization_guide/core/decision_tree_prediction_model.cc237
-rw-r--r--chromium/components/optimization_guide/core/decision_tree_prediction_model.h97
-rw-r--r--chromium/components/optimization_guide/core/decision_tree_prediction_model_unittest.cc434
-rw-r--r--chromium/components/optimization_guide/core/entity_annotator_native_library.cc445
-rw-r--r--chromium/components/optimization_guide/core/entity_annotator_native_library.h143
-rw-r--r--chromium/components/optimization_guide/core/entity_annotator_native_library_unittest.cc22
-rw-r--r--chromium/components/optimization_guide/core/entity_metadata.cc1
-rw-r--r--chromium/components/optimization_guide/core/entity_metadata_provider.h1
-rw-r--r--chromium/components/optimization_guide/core/hints_fetcher.cc106
-rw-r--r--chromium/components/optimization_guide/core/hints_fetcher.h20
-rw-r--r--chromium/components/optimization_guide/core/hints_fetcher_factory.cc12
-rw-r--r--chromium/components/optimization_guide/core/hints_fetcher_factory.h12
-rw-r--r--chromium/components/optimization_guide/core/hints_fetcher_unittest.cc67
-rw-r--r--chromium/components/optimization_guide/core/hints_manager.cc130
-rw-r--r--chromium/components/optimization_guide/core/hints_manager.h13
-rw-r--r--chromium/components/optimization_guide/core/hints_manager_unittest.cc132
-rw-r--r--chromium/components/optimization_guide/core/local_page_entities_metadata_provider.cc93
-rw-r--r--chromium/components/optimization_guide/core/local_page_entities_metadata_provider.h67
-rw-r--r--chromium/components/optimization_guide/core/local_page_entities_metadata_provider_unittest.cc134
-rw-r--r--chromium/components/optimization_guide/core/model_enums.h57
-rw-r--r--chromium/components/optimization_guide/core/model_executor.h28
-rw-r--r--chromium/components/optimization_guide/core/model_handler.h74
-rw-r--r--chromium/components/optimization_guide/core/model_info.cc4
-rw-r--r--chromium/components/optimization_guide/core/model_util.cc86
-rw-r--r--chromium/components/optimization_guide/core/model_util.h37
-rw-r--r--chromium/components/optimization_guide/core/model_validator.cc14
-rw-r--r--chromium/components/optimization_guide/core/model_validator.h6
-rw-r--r--chromium/components/optimization_guide/core/model_validator_unittest.cc18
-rw-r--r--chromium/components/optimization_guide/core/optimization_guide_constants.cc3
-rw-r--r--chromium/components/optimization_guide/core/optimization_guide_constants.h3
-rw-r--r--chromium/components/optimization_guide/core/optimization_guide_enums.h45
-rw-r--r--chromium/components/optimization_guide/core/optimization_guide_features.cc194
-rw-r--r--chromium/components/optimization_guide/core/optimization_guide_features.h50
-rw-r--r--chromium/components/optimization_guide/core/optimization_guide_features_unittest.cc103
-rw-r--r--chromium/components/optimization_guide/core/optimization_guide_logger.cc32
-rw-r--r--chromium/components/optimization_guide/core/optimization_guide_logger.h45
-rw-r--r--chromium/components/optimization_guide/core/optimization_guide_permissions_util.cc13
-rw-r--r--chromium/components/optimization_guide/core/optimization_guide_permissions_util_unittest.cc38
-rw-r--r--chromium/components/optimization_guide/core/optimization_guide_store.cc272
-rw-r--r--chromium/components/optimization_guide/core/optimization_guide_store.h99
-rw-r--r--chromium/components/optimization_guide/core/optimization_guide_store_unittest.cc553
-rw-r--r--chromium/components/optimization_guide/core/optimization_guide_switches.cc33
-rw-r--r--chromium/components/optimization_guide/core/optimization_guide_switches.h14
-rw-r--r--chromium/components/optimization_guide/core/optimization_guide_switches_unittest.cc2
-rw-r--r--chromium/components/optimization_guide/core/optimization_guide_test_util.cc2
-rw-r--r--chromium/components/optimization_guide/core/optimization_guide_util.cc69
-rw-r--r--chromium/components/optimization_guide/core/optimization_guide_util.h32
-rw-r--r--chromium/components/optimization_guide/core/optimization_guide_util_unittest.cc2
-rw-r--r--chromium/components/optimization_guide/core/optimization_hints_component_update_listener.cc1
-rw-r--r--chromium/components/optimization_guide/core/page_content_annotation_job.cc49
-rw-r--r--chromium/components/optimization_guide/core/page_content_annotation_job.h13
-rw-r--r--chromium/components/optimization_guide/core/page_content_annotation_job_executor.cc2
-rw-r--r--chromium/components/optimization_guide/core/page_content_annotation_job_executor_unittest.cc2
-rw-r--r--chromium/components/optimization_guide/core/page_content_annotations_common.cc30
-rw-r--r--chromium/components/optimization_guide/core/page_content_annotations_common.h30
-rw-r--r--chromium/components/optimization_guide/core/page_entities_model_executor.h2
-rw-r--r--chromium/components/optimization_guide/core/page_entities_model_executor_impl.cc230
-rw-r--r--chromium/components/optimization_guide/core/page_entities_model_executor_impl.h115
-rw-r--r--chromium/components/optimization_guide/core/page_entities_model_executor_impl_unittest.cc268
-rw-r--r--chromium/components/optimization_guide/core/page_topics_model_executor.cc33
-rw-r--r--chromium/components/optimization_guide/core/page_topics_model_executor.h3
-rw-r--r--chromium/components/optimization_guide/core/page_topics_model_executor_unittest.cc34
-rw-r--r--chromium/components/optimization_guide/core/prediction_model.cc82
-rw-r--r--chromium/components/optimization_guide/core/prediction_model.h70
-rw-r--r--chromium/components/optimization_guide/core/prediction_model_fetcher_impl.cc12
-rw-r--r--chromium/components/optimization_guide/core/prediction_model_fetcher_impl.h8
-rw-r--r--chromium/components/optimization_guide/core/prediction_model_fetcher_unittest.cc38
-rw-r--r--chromium/components/optimization_guide/core/prediction_model_unittest.cc134
-rw-r--r--chromium/components/optimization_guide/core/store_update_data.cc69
-rw-r--r--chromium/components/optimization_guide/core/store_update_data.h16
-rw-r--r--chromium/components/optimization_guide/core/store_update_data_unittest.cc39
-rw-r--r--chromium/components/optimization_guide/core/test_model_executor.cc4
-rw-r--r--chromium/components/optimization_guide/core/test_model_executor.h5
-rw-r--r--chromium/components/optimization_guide/core/test_model_info_builder.cc2
-rw-r--r--chromium/components/optimization_guide/core/test_tflite_model_executor.cc12
-rw-r--r--chromium/components/optimization_guide/core/test_tflite_model_executor.h6
-rw-r--r--chromium/components/optimization_guide/core/tflite_model_executor.h79
-rw-r--r--chromium/components/optimization_guide/core/tflite_model_executor_unittest.cc15
-rw-r--r--chromium/components/optimization_guide/core/tflite_op_resolver.cc4
-rw-r--r--chromium/components/optimization_guide/features.gni14
-rw-r--r--chromium/components/optimization_guide/optimization_guide_internals/resources/BUILD.gn71
-rw-r--r--chromium/components/optimization_guide/optimization_guide_internals/resources/OWNERS1
-rw-r--r--chromium/components/optimization_guide/optimization_guide_internals/resources/optimization_guide_internals.html29
-rw-r--r--chromium/components/optimization_guide/optimization_guide_internals/resources/optimization_guide_internals.ts80
-rw-r--r--chromium/components/optimization_guide/optimization_guide_internals/resources/optimization_guide_internals_browser_proxy.ts26
-rw-r--r--chromium/components/optimization_guide/optimization_guide_internals/resources/tsconfig_base.json6
-rw-r--r--chromium/components/optimization_guide/optimization_guide_internals/webui/BUILD.gn30
-rw-r--r--chromium/components/optimization_guide/optimization_guide_internals/webui/DEPS7
-rw-r--r--chromium/components/optimization_guide/optimization_guide_internals/webui/OWNERS4
-rw-r--r--chromium/components/optimization_guide/optimization_guide_internals/webui/optimization_guide_internals.mojom24
-rw-r--r--chromium/components/optimization_guide/optimization_guide_internals/webui/optimization_guide_internals_page_handler_impl.cc31
-rw-r--r--chromium/components/optimization_guide/optimization_guide_internals/webui/optimization_guide_internals_page_handler_impl.h44
-rw-r--r--chromium/components/optimization_guide/optimization_guide_internals/webui/optimization_guide_internals_ui.cc38
-rw-r--r--chromium/components/optimization_guide/optimization_guide_internals/webui/optimization_guide_internals_ui.h59
-rw-r--r--chromium/components/optimization_guide/optimization_guide_internals/webui/url_constants.cc12
-rw-r--r--chromium/components/optimization_guide/optimization_guide_internals/webui/url_constants.h15
-rw-r--r--chromium/components/optimization_guide/proto/BUILD.gn1
-rw-r--r--chromium/components/optimization_guide/proto/hint_cache.proto2
-rw-r--r--chromium/components/optimization_guide/proto/models.proto37
-rw-r--r--chromium/components/optimization_guide/proto/page_entities_metadata.proto11
-rw-r--r--chromium/components/optimization_guide/proto/page_entities_model_metadata.proto25
-rw-r--r--chromium/components/optimization_guide/proto/page_topics_model_metadata.proto19
-rw-r--r--chromium/components/os_crypt/BUILD.gn10
-rw-r--r--chromium/components/os_crypt/features.gni2
-rw-r--r--chromium/components/os_crypt/key_storage_kwallet.cc4
-rw-r--r--chromium/components/os_crypt/kwallet_dbus.h114
-rw-r--r--chromium/components/os_crypt/os_crypt.h95
-rw-r--r--chromium/components/os_crypt/os_crypt_linux.cc140
-rw-r--r--chromium/components/os_crypt/os_crypt_linux_unittest.cc55
-rw-r--r--chromium/components/os_crypt/os_crypt_mocker.cc13
-rw-r--r--chromium/components/os_crypt/os_crypt_mocker.h4
-rw-r--r--chromium/components/os_crypt/os_crypt_mocker_linux.cc8
-rw-r--r--chromium/components/os_crypt/os_crypt_posix.cc15
-rw-r--r--chromium/components/os_crypt/os_crypt_switches.cc4
-rw-r--r--chromium/components/os_crypt/os_crypt_switches.h4
-rw-r--r--chromium/components/os_crypt/os_crypt_unittest.cc10
-rw-r--r--chromium/components/os_crypt/os_crypt_win.cc69
-rw-r--r--chromium/components/ownership/BUILD.gn2
-rw-r--r--chromium/components/page_info/DEPS1
-rw-r--r--chromium/components/page_info/android/BUILD.gn11
-rw-r--r--chromium/components/page_info/android/page_info_controller_android.cc9
-rw-r--r--chromium/components/page_info/core/BUILD.gn7
-rw-r--r--chromium/components/page_info/core/about_this_site_service.cc2
-rw-r--r--chromium/components/page_info/core/features.cc13
-rw-r--r--chromium/components/page_info/core/features.h11
-rw-r--r--chromium/components/page_info/core/page_info_history_data_source.cc100
-rw-r--r--chromium/components/page_info/core/page_info_history_data_source.h69
-rw-r--r--chromium/components/page_info/core/page_info_history_data_source_unittest.cc204
-rw-r--r--chromium/components/page_info/page_info.cc110
-rw-r--r--chromium/components/page_info/page_info.h7
-rw-r--r--chromium/components/page_info/page_info_delegate.h4
-rw-r--r--chromium/components/page_info/page_info_ui.cc30
-rw-r--r--chromium/components/page_info/page_info_ui.h16
-rw-r--r--chromium/components/page_info/page_info_ui_delegate.h2
-rw-r--r--chromium/components/page_info_strings.grdp34
-rw-r--r--chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_ABOUT_THIS_SITE_HEADER.png.sha12
-rw-r--r--chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_ABOUT_THIS_SITE_TOOLTIP.png.sha12
-rw-r--r--chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_APP_SETTINGS_LINK.png.sha11
-rw-r--r--chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_APP_SETTINGS_TOOLTIP.png.sha11
-rw-r--r--chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_HID_DEVICE_ALLOWED_BY_POLICY_LABEL.png.sha11
-rw-r--r--chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_HISTORY.png.sha11
-rw-r--r--chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_HISTORY_LAST_VISIT_DATE.png.sha11
-rw-r--r--chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_HISTORY_LAST_VISIT_DAYS.png.sha11
-rw-r--r--chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_HISTORY_LAST_VISIT_TODAY.png.sha11
-rw-r--r--chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_HISTORY_LAST_VISIT_YESTERDAY.png.sha11
-rw-r--r--chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_STATE_TEXT_WINDOW_PLACEMENT_ASK.png.sha12
-rw-r--r--chromium/components/page_load_metrics/browser/metrics_web_contents_observer.cc23
-rw-r--r--chromium/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc75
-rw-r--r--chromium/components/page_load_metrics/browser/observers/README.md1
-rw-r--r--chromium/components/page_load_metrics/browser/observers/ad_metrics/ads_page_load_metrics_observer.cc6
-rw-r--r--chromium/components/page_load_metrics/browser/observers/ad_metrics/ads_page_load_metrics_observer.h1
-rw-r--r--chromium/components/page_load_metrics/browser/observers/back_forward_cache_page_load_metrics_observer.cc10
-rw-r--r--chromium/components/page_load_metrics/browser/observers/back_forward_cache_page_load_metrics_observer_unittest.cc60
-rw-r--r--chromium/components/page_load_metrics/browser/observers/core/largest_contentful_paint_handler.cc18
-rw-r--r--chromium/components/page_load_metrics/browser/observers/core/largest_contentful_paint_handler.h15
-rw-r--r--chromium/components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer.cc33
-rw-r--r--chromium/components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer.h10
-rw-r--r--chromium/components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer_unittest.cc47
-rw-r--r--chromium/components/page_load_metrics/browser/observers/layout_page_load_metrics_observer.cc7
-rw-r--r--chromium/components/page_load_metrics/browser/observers/page_load_metrics_observer_tester.cc4
-rw-r--r--chromium/components/page_load_metrics/browser/observers/prerender_page_load_metrics_observer.cc2
-rw-r--r--chromium/components/page_load_metrics/browser/observers/use_counter/ukm_features.cc1
-rw-r--r--chromium/components/page_load_metrics/browser/page_load_metrics_embedder_base.cc2
-rw-r--r--chromium/components/page_load_metrics/browser/page_load_metrics_embedder_interface.h1
-rw-r--r--chromium/components/page_load_metrics/browser/page_load_metrics_memory_tracker_unittest.cc3
-rw-r--r--chromium/components/page_load_metrics/browser/page_load_metrics_observer.h4
-rw-r--r--chromium/components/page_load_metrics/browser/page_load_metrics_test_waiter.cc4
-rw-r--r--chromium/components/page_load_metrics/browser/page_load_metrics_test_waiter.h1
-rw-r--r--chromium/components/page_load_metrics/browser/page_load_metrics_update_dispatcher.cc36
-rw-r--r--chromium/components/page_load_metrics/browser/page_load_metrics_update_dispatcher.h2
-rw-r--r--chromium/components/page_load_metrics/browser/page_load_tracker.cc116
-rw-r--r--chromium/components/page_load_metrics/browser/page_load_tracker.h35
-rw-r--r--chromium/components/page_load_metrics/browser/responsiveness_metrics_normalization.h2
-rw-r--r--chromium/components/page_load_metrics/browser/responsiveness_metrics_normalization_unittest.cc53
-rw-r--r--chromium/components/page_load_metrics/browser/test_metrics_web_contents_observer_embedder.cc5
-rw-r--r--chromium/components/page_load_metrics/browser/test_metrics_web_contents_observer_embedder.h1
-rw-r--r--chromium/components/page_load_metrics/common/page_load_metrics.mojom14
-rw-r--r--chromium/components/page_load_metrics/renderer/metrics_render_frame_observer.cc19
-rw-r--r--chromium/components/page_load_metrics/renderer/metrics_render_frame_observer.h14
-rw-r--r--chromium/components/page_load_metrics/renderer/page_resource_data_use.cc6
-rw-r--r--chromium/components/page_load_metrics/renderer/page_resource_data_use.h5
-rw-r--r--chromium/components/page_load_metrics/renderer/page_timing_metrics_sender.cc24
-rw-r--r--chromium/components/page_load_metrics/renderer/page_timing_metrics_sender.h5
-rw-r--r--chromium/components/page_load_metrics/renderer/page_timing_metrics_sender_unittest.cc6
-rw-r--r--chromium/components/paint_preview/browser/paint_preview_base_service_unittest.cc3
-rw-r--r--chromium/components/paint_preview/browser/paint_preview_client_unittest.cc2
-rw-r--r--chromium/components/paint_preview/common/glyph_usage.cc2
-rw-r--r--chromium/components/paint_preview/common/recording_map.cc2
-rw-r--r--chromium/components/paint_preview/common/serial_utils.cc2
-rw-r--r--chromium/components/paint_preview/common/serial_utils_unittest.cc4
-rw-r--r--chromium/components/paint_preview/common/subset_font_unittest.cc2
-rw-r--r--chromium/components/paint_preview/player/android/javatests/src/org/chromium/components/paintpreview/player/PaintPreviewPlayerTest.java4
-rw-r--r--chromium/components/paint_preview/renderer/paint_preview_recorder_browsertest.cc5
-rw-r--r--chromium/components/password_manager/OWNERS2
-rw-r--r--chromium/components/password_manager/content/browser/content_password_manager_driver.cc21
-rw-r--r--chromium/components/password_manager/content/browser/content_password_manager_driver.h5
-rw-r--r--chromium/components/password_manager/content/browser/content_password_manager_driver_factory.cc20
-rw-r--r--chromium/components/password_manager/content/browser/content_password_manager_driver_unittest.cc59
-rw-r--r--chromium/components/password_manager/content/common/credential_manager_mojom_traits.cc23
-rw-r--r--chromium/components/password_manager/core/browser/BUILD.gn28
-rw-r--r--chromium/components/password_manager/core/browser/DEPS1
-rw-r--r--chromium/components/password_manager/core/browser/android_affiliation/fake_affiliation_api.cc4
-rw-r--r--chromium/components/password_manager/core/browser/android_affiliation/lookup_affiliation_response_parser.cc7
-rw-r--r--chromium/components/password_manager/core/browser/android_affiliation/lookup_affiliation_response_parser.h2
-rw-r--r--chromium/components/password_manager/core/browser/android_affiliation/lookup_affiliation_response_parser_fuzzer.cc2
-rw-r--r--chromium/components/password_manager/core/browser/built_in_backend_to_android_backend_migrator.cc288
-rw-r--r--chromium/components/password_manager/core/browser/built_in_backend_to_android_backend_migrator.h49
-rw-r--r--chromium/components/password_manager/core/browser/built_in_backend_to_android_backend_migrator_unittest.cc292
-rw-r--r--chromium/components/password_manager/core/browser/capabilities_service.h35
-rw-r--r--chromium/components/password_manager/core/browser/capabilities_service_impl.cc109
-rw-r--r--chromium/components/password_manager/core/browser/capabilities_service_impl.h41
-rw-r--r--chromium/components/password_manager/core/browser/capabilities_service_impl_unittest.cc215
-rw-r--r--chromium/components/password_manager/core/browser/credential_manager_impl.cc6
-rw-r--r--chromium/components/password_manager/core/browser/export/csv_writer.cc2
-rw-r--r--chromium/components/password_manager/core/browser/export/csv_writer_unittest.cc2
-rw-r--r--chromium/components/password_manager/core/browser/export/password_manager_exporter.cc2
-rw-r--r--chromium/components/password_manager/core/browser/export/password_manager_exporter_unittest.cc4
-rw-r--r--chromium/components/password_manager/core/browser/fake_password_store_backend.cc8
-rw-r--r--chromium/components/password_manager/core/browser/fake_password_store_backend.h3
-rw-r--r--chromium/components/password_manager/core/browser/field_info_manager.cc4
-rw-r--r--chromium/components/password_manager/core/browser/field_info_manager_unittest.cc10
-rw-r--r--chromium/components/password_manager/core/browser/field_info_table.cc26
-rw-r--r--chromium/components/password_manager/core/browser/field_info_table_unittest.cc4
-rw-r--r--chromium/components/password_manager/core/browser/form_fetcher_impl.cc2
-rw-r--r--chromium/components/password_manager/core/browser/form_fetcher_impl_unittest.cc2
-rw-r--r--chromium/components/password_manager/core/browser/form_parsing/BUILD.gn4
-rw-r--r--chromium/components/password_manager/core/browser/form_parsing/form_parser.cc2
-rw-r--r--chromium/components/password_manager/core/browser/form_parsing/form_parser_unittest.cc6
-rw-r--r--chromium/components/password_manager/core/browser/form_parsing/password_field_prediction.cc3
-rw-r--r--chromium/components/password_manager/core/browser/form_parsing/password_field_prediction.h2
-rw-r--r--chromium/components/password_manager/core/browser/hash_password_manager.cc15
-rw-r--r--chromium/components/password_manager/core/browser/hash_password_manager_unittest.cc16
-rw-r--r--chromium/components/password_manager/core/browser/leak_detection/BUILD.gn4
-rw-r--r--chromium/components/password_manager/core/browser/leak_detection/encryption_utils.cc22
-rw-r--r--chromium/components/password_manager/core/browser/leak_detection/encryption_utils_unittest.cc4
-rw-r--r--chromium/components/password_manager/core/browser/leak_detection/leak_detection_request_utils.h5
-rw-r--r--chromium/components/password_manager/core/browser/leak_detection_delegate.cc22
-rw-r--r--chromium/components/password_manager/core/browser/leak_detection_delegate.h9
-rw-r--r--chromium/components/password_manager/core/browser/leak_detection_delegate_helper.cc3
-rw-r--r--chromium/components/password_manager/core/browser/leak_detection_delegate_unittest.cc135
-rw-r--r--chromium/components/password_manager/core/browser/leak_detection_dialog_utils.cc4
-rw-r--r--chromium/components/password_manager/core/browser/leak_detection_dialog_utils_unittest.cc91
-rw-r--r--chromium/components/password_manager/core/browser/login_database.cc106
-rw-r--r--chromium/components/password_manager/core/browser/login_database.h85
-rw-r--r--chromium/components/password_manager/core/browser/login_database_async_helper.cc453
-rw-r--r--chromium/components/password_manager/core/browser/login_database_async_helper.h149
-rw-r--r--chromium/components/password_manager/core/browser/login_database_ios_unittest.cc9
-rw-r--r--chromium/components/password_manager/core/browser/login_database_posix.cc8
-rw-r--r--chromium/components/password_manager/core/browser/login_database_unittest.cc149
-rw-r--r--chromium/components/password_manager/core/browser/mock_password_change_success_tracker.cc13
-rw-r--r--chromium/components/password_manager/core/browser/mock_password_change_success_tracker.h31
-rw-r--r--chromium/components/password_manager/core/browser/mock_password_store_backend.cc3
-rw-r--r--chromium/components/password_manager/core/browser/mock_password_store_backend.h19
-rw-r--r--chromium/components/password_manager/core/browser/mock_webauthn_credentials_delegate.cc13
-rw-r--r--chromium/components/password_manager/core/browser/mock_webauthn_credentials_delegate.h41
-rw-r--r--chromium/components/password_manager/core/browser/password_autofill_manager.cc8
-rw-r--r--chromium/components/password_manager/core/browser/password_autofill_manager.h3
-rw-r--r--chromium/components/password_manager/core/browser/password_autofill_manager_unittest.cc38
-rw-r--r--chromium/components/password_manager/core/browser/password_change_success_tracker.h78
-rw-r--r--chromium/components/password_manager/core/browser/password_change_success_tracker_impl.cc29
-rw-r--r--chromium/components/password_manager/core/browser/password_change_success_tracker_impl.h31
-rw-r--r--chromium/components/password_manager/core/browser/password_form.cc9
-rw-r--r--chromium/components/password_manager/core/browser/password_form.h4
-rw-r--r--chromium/components/password_manager/core/browser/password_form_filling.cc8
-rw-r--r--chromium/components/password_manager/core/browser/password_form_filling_unittest.cc33
-rw-r--r--chromium/components/password_manager/core/browser/password_form_manager.cc66
-rw-r--r--chromium/components/password_manager/core/browser/password_form_manager.h21
-rw-r--r--chromium/components/password_manager/core/browser/password_form_manager_unittest.cc72
-rw-r--r--chromium/components/password_manager/core/browser/password_form_metrics_recorder.cc4
-rw-r--r--chromium/components/password_manager/core/browser/password_form_metrics_recorder_unittest.cc2
-rw-r--r--chromium/components/password_manager/core/browser/password_form_prediction_waiter.cc49
-rw-r--r--chromium/components/password_manager/core/browser/password_form_prediction_waiter.h67
-rw-r--r--chromium/components/password_manager/core/browser/password_form_prediction_waiter_unittest.cc81
-rw-r--r--chromium/components/password_manager/core/browser/password_list_sorter.cc5
-rw-r--r--chromium/components/password_manager/core/browser/password_manager.cc42
-rw-r--r--chromium/components/password_manager/core/browser/password_manager.h11
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_client.h4
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_driver.h13
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_features_util.cc8
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_interface.h2
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_metrics_recorder.cc17
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_metrics_recorder.h22
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_metrics_recorder_unittest.cc2
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_metrics_util.h4
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_unittest.cc47
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_util.cc12
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_util.h7
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_util_unittest.cc214
-rw-r--r--chromium/components/password_manager/core/browser/password_reuse_detection_manager.cc2
-rw-r--r--chromium/components/password_manager/core/browser/password_reuse_detection_manager.h2
-rw-r--r--chromium/components/password_manager/core/browser/password_reuse_detection_manager_unittest.cc2
-rw-r--r--chromium/components/password_manager/core/browser/password_reuse_manager_impl_unittest.cc30
-rw-r--r--chromium/components/password_manager/core/browser/password_save_manager_impl.cc6
-rw-r--r--chromium/components/password_manager/core/browser/password_save_manager_impl_unittest.cc5
-rw-r--r--chromium/components/password_manager/core/browser/password_scripts_fetcher.h13
-rw-r--r--chromium/components/password_manager/core/browser/password_scripts_fetcher_impl.cc3
-rw-r--r--chromium/components/password_manager/core/browser/password_scripts_fetcher_impl.h13
-rw-r--r--chromium/components/password_manager/core/browser/password_scripts_fetcher_impl_unittests.cc8
-rw-r--r--chromium/components/password_manager/core/browser/password_store.cc138
-rw-r--r--chromium/components/password_manager/core/browser/password_store.h56
-rw-r--r--chromium/components/password_manager/core/browser/password_store_backend.h43
-rw-r--r--chromium/components/password_manager/core/browser/password_store_backend_migration_decorator.cc59
-rw-r--r--chromium/components/password_manager/core/browser/password_store_backend_migration_decorator.h10
-rw-r--r--chromium/components/password_manager/core/browser/password_store_backend_migration_decorator_unittest.cc155
-rw-r--r--chromium/components/password_manager/core/browser/password_store_built_in_backend.cc653
-rw-r--r--chromium/components/password_manager/core/browser/password_store_built_in_backend.h152
-rw-r--r--chromium/components/password_manager/core/browser/password_store_built_in_backend_unittest.cc22
-rw-r--r--chromium/components/password_manager/core/browser/password_store_proxy_backend.cc364
-rw-r--r--chromium/components/password_manager/core/browser/password_store_proxy_backend.h16
-rw-r--r--chromium/components/password_manager/core/browser/password_store_proxy_backend_unittest.cc488
-rw-r--r--chromium/components/password_manager/core/browser/password_store_signin_notifier_impl_unittest.cc4
-rw-r--r--chromium/components/password_manager/core/browser/password_store_sync.h13
-rw-r--r--chromium/components/password_manager/core/browser/password_store_unittest.cc296
-rw-r--r--chromium/components/password_manager/core/browser/password_store_util.cc24
-rw-r--r--chromium/components/password_manager/core/browser/password_store_util.h17
-rw-r--r--chromium/components/password_manager/core/browser/password_ui_utils_unittest.cc12
-rw-r--r--chromium/components/password_manager/core/browser/saved_passwords_capabilities_fetcher.cc284
-rw-r--r--chromium/components/password_manager/core/browser/saved_passwords_capabilities_fetcher.h114
-rw-r--r--chromium/components/password_manager/core/browser/saved_passwords_capabilities_fetcher_unittest.cc512
-rw-r--r--chromium/components/password_manager/core/browser/site_affiliation/affiliation_fetcher_base.cc7
-rw-r--r--chromium/components/password_manager/core/browser/site_affiliation/affiliation_service_impl.cc1
-rw-r--r--chromium/components/password_manager/core/browser/site_affiliation/asset_link_data.cc2
-rw-r--r--chromium/components/password_manager/core/browser/store_metrics_reporter.cc115
-rw-r--r--chromium/components/password_manager/core/browser/store_metrics_reporter_unittest.cc273
-rw-r--r--chromium/components/password_manager/core/browser/stub_password_manager_client.cc7
-rw-r--r--chromium/components/password_manager/core/browser/stub_password_manager_client.h4
-rw-r--r--chromium/components/password_manager/core/browser/stub_password_manager_driver.cc4
-rw-r--r--chromium/components/password_manager/core/browser/stub_password_manager_driver.h3
-rw-r--r--chromium/components/password_manager/core/browser/sync/password_proto_utils.cc8
-rw-r--r--chromium/components/password_manager/core/browser/sync/password_sync_bridge.cc91
-rw-r--r--chromium/components/password_manager/core/browser/sync/password_sync_bridge.h10
-rw-r--r--chromium/components/password_manager/core/browser/sync/password_sync_bridge_unittest.cc129
-rw-r--r--chromium/components/password_manager/core/browser/sync_credentials_filter_unittest.cc8
-rw-r--r--chromium/components/password_manager/core/browser/test_password_store.cc8
-rw-r--r--chromium/components/password_manager/core/browser/test_password_store.h4
-rw-r--r--chromium/components/password_manager/core/browser/ui/insecure_credentials_manager.cc84
-rw-r--r--chromium/components/password_manager/core/browser/ui/insecure_credentials_manager.h20
-rw-r--r--chromium/components/password_manager/core/browser/ui/insecure_credentials_manager_unittest.cc247
-rw-r--r--chromium/components/password_manager/core/browser/votes_uploader.cc8
-rw-r--r--chromium/components/password_manager/core/browser/votes_uploader.h4
-rw-r--r--chromium/components/password_manager/core/browser/votes_uploader_unittest.cc80
-rw-r--r--chromium/components/password_manager/core/browser/webauthn_credentials_delegate.h9
-rw-r--r--chromium/components/password_manager/core/common/BUILD.gn23
-rw-r--r--chromium/components/password_manager/core/common/features.gni10
-rw-r--r--chromium/components/password_manager/core/common/password_manager_features.cc72
-rw-r--r--chromium/components/password_manager/core/common/password_manager_features.h29
-rw-r--r--chromium/components/password_manager/core/common/password_manager_pref_names.cc12
-rw-r--r--chromium/components/password_manager/core/common/password_manager_pref_names.h14
-rw-r--r--chromium/components/password_manager/ios/BUILD.gn1
-rw-r--r--chromium/components/password_manager/ios/password_manager_java_script_feature.mm1
-rw-r--r--chromium/components/password_manager_strings.grdp3
-rw-r--r--chromium/components/password_manager_strings_grdp/IDS_PASSWORD_MANAGER_PASSWORD_FOR_ACCOUNT.png.sha11
-rw-r--r--chromium/components/payments/content/android/BUILD.gn1
-rw-r--r--chromium/components/payments/content/android/minimal_java_res/drawable/google_pay.xml2
-rw-r--r--chromium/components/payments/content/android/payment_app_service_bridge.cc11
-rw-r--r--chromium/components/payments/content/android/payment_app_service_bridge.h3
-rw-r--r--chromium/components/payments/content/manifest_verifier.cc5
-rw-r--r--chromium/components/payments/content/payment_app_service.cc7
-rw-r--r--chromium/components/payments/content/payment_app_service.h2
-rw-r--r--chromium/components/payments/content/payment_request.h4
-rw-r--r--chromium/components/payments/content/payment_request_dialog.h6
-rw-r--r--chromium/components/payments/content/payment_request_spec_unittest.cc72
-rw-r--r--chromium/components/payments/content/payment_request_state_unittest.cc474
-rw-r--r--chromium/components/payments/content/payment_response_helper_unittest.cc106
-rw-r--r--chromium/components/payments/content/secure_payment_confirmation_app.cc6
-rw-r--r--chromium/components/payments/content/secure_payment_confirmation_app.h3
-rw-r--r--chromium/components/payments/content/secure_payment_confirmation_app_unittest.cc3
-rw-r--r--chromium/components/payments/content/secure_payment_confirmation_controller.cc6
-rw-r--r--chromium/components/payments/content/secure_payment_confirmation_controller.h2
-rw-r--r--chromium/components/payments/content/secure_payment_confirmation_no_creds.cc4
-rw-r--r--chromium/components/payments/content/service_worker_payment_app.cc5
-rw-r--r--chromium/components/payments/content/service_worker_payment_app_finder_unittest.cc89
-rw-r--r--chromium/components/payments/content/service_worker_payment_app_unittest.cc59
-rw-r--r--chromium/components/payments/content/utility/payment_manifest_parser.cc107
-rw-r--r--chromium/components/payments/core/error_strings.cc2
-rw-r--r--chromium/components/payments/core/features.cc6
-rw-r--r--chromium/components/payments/core/features.h2
-rw-r--r--chromium/components/payments/core/payment_details.cc15
-rw-r--r--chromium/components/payments/core/payment_details_modifier.cc4
-rw-r--r--chromium/components/payments/core/payment_details_unittest.cc4
-rw-r--r--chromium/components/payments/core/payment_method_data.cc2
-rw-r--r--chromium/components/payments/core/payment_method_data_unittest.cc4
-rw-r--r--chromium/components/payments/core/payment_request_data_util_unittest.cc4
-rw-r--r--chromium/components/pdf/browser/BUILD.gn1
-rw-r--r--chromium/components/pdf/browser/mock_url_loader_client.h3
-rw-r--r--chromium/components/pdf/browser/pdf_web_contents_helper.cc51
-rw-r--r--chromium/components/pdf/browser/pdf_web_contents_helper.h42
-rw-r--r--chromium/components/pdf/browser/pdf_web_contents_helper_browsertest.cc44
-rw-r--r--chromium/components/pdf/browser/pdf_web_contents_helper_client.h6
-rw-r--r--chromium/components/pdf/browser/plugin_response_writer.cc10
-rw-r--r--chromium/components/pdf/browser/plugin_response_writer_unittest.cc3
-rw-r--r--chromium/components/pdf/renderer/BUILD.gn4
-rw-r--r--chromium/components/pdf/renderer/internal_plugin_renderer_helpers.cc11
-rw-r--r--chromium/components/pdf/renderer/internal_plugin_renderer_helpers.h3
-rw-r--r--chromium/components/pdf/renderer/pdf_accessibility_tree.cc8
-rw-r--r--chromium/components/pdf/renderer/pdf_accessibility_tree.h2
-rw-r--r--chromium/components/pdf/renderer/pdf_accessibility_tree_browsertest.cc2
-rw-r--r--chromium/components/pdf/renderer/pdf_find_in_page.cc106
-rw-r--r--chromium/components/pdf/renderer/pdf_find_in_page.h58
-rw-r--r--chromium/components/performance_manager/decorators/page_load_tracker_decorator.cc6
-rw-r--r--chromium/components/performance_manager/decorators/process_metrics_decorator.cc4
-rw-r--r--chromium/components/performance_manager/features.cc28
-rw-r--r--chromium/components/performance_manager/graph/graph_impl_unittest.cc2
-rw-r--r--chromium/components/performance_manager/graph/policies/bfcache_policy.cc162
-rw-r--r--chromium/components/performance_manager/graph/policies/bfcache_policy.h43
-rw-r--r--chromium/components/performance_manager/graph/policies/bfcache_policy_unittest.cc55
-rw-r--r--chromium/components/performance_manager/graph/process_node_impl_describer.cc14
-rw-r--r--chromium/components/performance_manager/graph_features.cc4
-rw-r--r--chromium/components/performance_manager/graph_features_unittest.cc2
-rw-r--r--chromium/components/performance_manager/metrics/metrics_collector_unittest.cc2
-rw-r--r--chromium/components/performance_manager/persistence/site_data/leveldb_site_data_store.cc4
-rw-r--r--chromium/components/performance_manager/persistence/site_data/leveldb_site_data_store_unittest.cc4
-rw-r--r--chromium/components/performance_manager/persistence/site_data/site_data_cache_factory.h1
-rw-r--r--chromium/components/performance_manager/persistence/site_data/site_data_cache_impl.cc2
-rw-r--r--chromium/components/performance_manager/persistence/site_data/site_data_reader.cc27
-rw-r--r--chromium/components/performance_manager/persistence/site_data/site_data_reader_unittest.cc16
-rw-r--r--chromium/components/performance_manager/prerendering_browsertest.cc2
-rw-r--r--chromium/components/performance_manager/public/features.h53
-rw-r--r--chromium/components/performance_manager/public/graph/node_attached_data.h2
-rw-r--r--chromium/components/performance_manager/public/persistence/site_data/site_data_reader.h35
-rw-r--r--chromium/components/performance_manager/render_process_user_data.cc2
-rw-r--r--chromium/components/performance_manager/service_worker_context_adapter.cc9
-rw-r--r--chromium/components/performance_manager/service_worker_context_adapter.h5
-rw-r--r--chromium/components/performance_manager/v8_memory/v8_context_tracker_helpers.h28
-rw-r--r--chromium/components/performance_manager/v8_memory/v8_context_tracker_internal.h32
-rw-r--r--chromium/components/performance_manager/v8_memory/v8_detailed_memory_unittest.cc19
-rw-r--r--chromium/components/permissions/BUILD.gn4
-rw-r--r--chromium/components/permissions/README.md55
-rw-r--r--chromium/components/permissions/android/BUILD.gn11
-rw-r--r--chromium/components/permissions/android/permission_prompt_android.cc16
-rw-r--r--chromium/components/permissions/android/permission_prompt_android.h5
-rw-r--r--chromium/components/permissions/android/permissions_android_feature_list.cc1
-rw-r--r--chromium/components/permissions/android/res/color/item_chooser_row_icon_color.xml2
-rw-r--r--chromium/components/permissions/android/res/drawable/gm_filled_bluetooth_searching_20.xml19
-rw-r--r--chromium/components/permissions/android/res/drawable/gm_filled_cardboard_20.xml12
-rw-r--r--chromium/components/permissions/android/res/drawable/gm_filled_content_paste_20.xml12
-rw-r--r--chromium/components/permissions/android/res/drawable/gm_filled_devices_20.xml15
-rw-r--r--chromium/components/permissions/android/res/drawable/gm_filled_location_on_20.xml12
-rw-r--r--chromium/components/permissions/android/res/drawable/gm_filled_mic_20.xml15
-rw-r--r--chromium/components/permissions/android/res/drawable/gm_filled_nfc_20.xml15
-rw-r--r--chromium/components/permissions/android/res/drawable/gm_filled_notifications_20.xml15
-rw-r--r--chromium/components/permissions/android/res/drawable/gm_filled_piano_20.xml12
-rw-r--r--chromium/components/permissions/android/res/drawable/gm_filled_usb_20.xml12
-rw-r--r--chromium/components/permissions/android/res/drawable/gm_filled_videocam_20.xml12
-rw-r--r--chromium/components/permissions/android/res/layout/bluetooth_scanning_permission_dialog.xml2
-rw-r--r--chromium/components/permissions/android/res/layout/item_chooser_dialog.xml2
-rw-r--r--chromium/components/permissions/android/translations/permissions_android_strings_as.xtb4
-rw-r--r--chromium/components/permissions/android/translations/permissions_android_strings_de.xtb18
-rw-r--r--chromium/components/permissions/android/translations/permissions_android_strings_it.xtb2
-rw-r--r--chromium/components/permissions/android/translations/permissions_android_strings_ne.xtb6
-rw-r--r--chromium/components/permissions/android/translations/permissions_android_strings_pt-PT.xtb2
-rw-r--r--chromium/components/permissions/android/translations/permissions_android_strings_te.xtb2
-rw-r--r--chromium/components/permissions/bluetooth_chooser_controller.cc11
-rw-r--r--chromium/components/permissions/chooser_title_util.cc3
-rw-r--r--chromium/components/permissions/chooser_title_util.h5
-rw-r--r--chromium/components/permissions/chooser_title_util_unittest.cc41
-rw-r--r--chromium/components/permissions/contexts/DEPS6
-rw-r--r--chromium/components/permissions/contexts/bluetooth_chooser_context.cc5
-rw-r--r--chromium/components/permissions/contexts/geolocation_permission_context.h7
-rw-r--r--chromium/components/permissions/contexts/geolocation_permission_context_android.cc4
-rw-r--r--chromium/components/permissions/contexts/geolocation_permission_context_unittest.cc34
-rw-r--r--chromium/components/permissions/contexts/nfc_permission_context.cc3
-rw-r--r--chromium/components/permissions/contexts/nfc_permission_context.h4
-rw-r--r--chromium/components/permissions/contexts/nfc_permission_context_unittest.cc12
-rw-r--r--chromium/components/permissions/contexts/webxr_permission_context.cc7
-rw-r--r--chromium/components/permissions/contexts/webxr_permission_context.h2
-rw-r--r--chromium/components/permissions/contexts/window_placement_permission_context.cc49
-rw-r--r--chromium/components/permissions/contexts/window_placement_permission_context.h34
-rw-r--r--chromium/components/permissions/features.cc15
-rw-r--r--chromium/components/permissions/features.h8
-rw-r--r--chromium/components/permissions/object_permission_context_base.cc17
-rw-r--r--chromium/components/permissions/permission_actions_history.cc7
-rw-r--r--chromium/components/permissions/permission_context_base.cc24
-rw-r--r--chromium/components/permissions/permission_context_base_unittest.cc26
-rw-r--r--chromium/components/permissions/permission_decision_auto_blocker.cc14
-rw-r--r--chromium/components/permissions/permission_manager.cc2
-rw-r--r--chromium/components/permissions/permission_manager_unittest.cc22
-rw-r--r--chromium/components/permissions/permission_prompt.h6
-rw-r--r--chromium/components/permissions/permission_request.cc8
-rw-r--r--chromium/components/permissions/permission_request.h4
-rw-r--r--chromium/components/permissions/permission_request_manager.cc26
-rw-r--r--chromium/components/permissions/permission_request_manager.h9
-rw-r--r--chromium/components/permissions/permission_request_manager_unittest.cc12
-rw-r--r--chromium/components/permissions/permission_uma_util.cc160
-rw-r--r--chromium/components/permissions/permission_uma_util.h19
-rw-r--r--chromium/components/permissions/permission_util.cc4
-rw-r--r--chromium/components/permissions/permissions_client.cc25
-rw-r--r--chromium/components/permissions/permissions_client.h23
-rw-r--r--chromium/components/permissions/prediction_service/BUILD.gn27
-rw-r--r--chromium/components/permissions/prediction_service/DEPS2
-rw-r--r--chromium/components/permissions/prediction_service/prediction_common.cc (renamed from chromium/components/permissions/prediction_service/prediction_service_common.cc)134
-rw-r--r--chromium/components/permissions/prediction_service/prediction_common.h73
-rw-r--r--chromium/components/permissions/prediction_service/prediction_model_executor.cc147
-rw-r--r--chromium/components/permissions/prediction_service/prediction_model_executor.h39
-rw-r--r--chromium/components/permissions/prediction_service/prediction_model_handler.cc35
-rw-r--r--chromium/components/permissions/prediction_service/prediction_model_handler.h29
-rw-r--r--chromium/components/permissions/prediction_service/prediction_service.cc103
-rw-r--r--chromium/components/permissions/prediction_service/prediction_service.h15
-rw-r--r--chromium/components/permissions/prediction_service/prediction_service_base.h8
-rw-r--r--chromium/components/permissions/prediction_service/prediction_service_common.h35
-rw-r--r--chromium/components/permissions/prediction_service/prediction_service_messages.proto15
-rw-r--r--chromium/components/permissions/prediction_service/prediction_service_unittest.cc53
-rw-r--r--chromium/components/permissions/pref_names.cc4
-rw-r--r--chromium/components/permissions/pref_names.h2
-rw-r--r--chromium/components/permissions/quota_permission_context_impl.cc8
-rw-r--r--chromium/components/permissions/request_type.cc53
-rw-r--r--chromium/components/permissions/request_type.h18
-rw-r--r--chromium/components/permissions_strings.grdp6
-rw-r--r--chromium/components/permissions_strings_grdp/IDS_NFC_INFOBAR_TEXT.png.sha12
-rw-r--r--chromium/components/permissions_strings_grdp/IDS_WINDOW_PLACEMENT_PERMISSION_FRAGMENT.png.sha12
-rw-r--r--chromium/components/plugins/renderer/plugin_placeholder.cc2
-rw-r--r--chromium/components/plugins/renderer/webview_plugin.cc1
-rw-r--r--chromium/components/policy/content/BUILD.gn1
-rw-r--r--chromium/components/policy/core/browser/BUILD.gn16
-rw-r--r--chromium/components/policy/core/common/BUILD.gn5
-rw-r--r--chromium/components/policy/test_support/BUILD.gn48
-rw-r--r--chromium/components/policy_strings.grdp29
-rw-r--r--chromium/components/policy_strings_grdp/IDS_POLICY_CLOUD_USER_ONLY_ERROR.png.sha11
-rw-r--r--chromium/components/policy_strings_grdp/IDS_POLICY_DEVICE_SCHEDULED_REBOOT_DIALOG_MESSAGE.png.sha11
-rw-r--r--chromium/components/policy_strings_grdp/IDS_POLICY_DEVICE_SCHEDULED_REBOOT_MESSAGE.png.sha11
-rw-r--r--chromium/components/policy_strings_grdp/IDS_POLICY_DEVICE_SCHEDULED_REBOOT_TITLE.png.sha11
-rw-r--r--chromium/components/policy_strings_grdp/IDS_POLICY_REBOOT_BUTTON.png.sha11
-rw-r--r--chromium/components/policy_strings_grdp/IDS_REBOOT_SCHEDULED_TITLE_MINUTES.png.sha11
-rw-r--r--chromium/components/policy_strings_grdp/IDS_REBOOT_SCHEDULED_TITLE_SECONDS.png.sha11
-rw-r--r--chromium/components/power_metrics/BUILD.gn3
-rw-r--r--chromium/components/power_metrics/iopm_power_source_sampling_event_source.cc4
-rw-r--r--chromium/components/power_metrics/iopm_power_source_sampling_event_source.h4
-rw-r--r--chromium/components/power_metrics/m1_sensors_internal_types_mac.h26
-rw-r--r--chromium/components/power_metrics/m1_sensors_mac.h48
-rw-r--r--chromium/components/power_metrics/m1_sensors_mac.mm123
-rw-r--r--chromium/components/power_metrics/resource_coalition_internal_types_mac.h1
-rw-r--r--chromium/components/power_metrics/resource_coalition_mac.h33
-rw-r--r--chromium/components/power_metrics/resource_coalition_mac.mm73
-rw-r--r--chromium/components/power_metrics/resource_coalition_mac_unittest.mm333
-rw-r--r--chromium/components/power_metrics/sampling_event_source.cc4
-rw-r--r--chromium/components/power_metrics/sampling_event_source.h4
-rw-r--r--chromium/components/power_metrics/timer_sampling_event_source.cc4
-rw-r--r--chromium/components/power_metrics/timer_sampling_event_source.h4
-rw-r--r--chromium/components/power_metrics/timer_sampling_event_source_unittest.cc4
-rw-r--r--chromium/components/power_scheduler/power_scheduler.cc1
-rw-r--r--chromium/components/power_scheduler/power_scheduler.h1
-rw-r--r--chromium/components/prefs/BUILD.gn2
-rw-r--r--chromium/components/prefs/in_memory_pref_store_unittest.cc4
-rw-r--r--chromium/components/prefs/json_pref_store.cc18
-rw-r--r--chromium/components/prefs/json_pref_store_unittest.cc6
-rw-r--r--chromium/components/prefs/mock_pref_change_callback.h8
-rw-r--r--chromium/components/prefs/overlay_user_pref_store_unittest.cc32
-rw-r--r--chromium/components/prefs/pref_member.cc2
-rw-r--r--chromium/components/prefs/pref_member_unittest.cc11
-rw-r--r--chromium/components/prefs/pref_service.cc115
-rw-r--r--chromium/components/prefs/pref_service.h38
-rw-r--r--chromium/components/prefs/pref_service_factory.cc10
-rw-r--r--chromium/components/prefs/pref_service_factory.h5
-rw-r--r--chromium/components/prefs/pref_service_unittest.cc66
-rw-r--r--chromium/components/prefs/pref_value_store.cc15
-rw-r--r--chromium/components/prefs/pref_value_store.h18
-rw-r--r--chromium/components/prefs/pref_value_store_unittest.cc64
-rw-r--r--chromium/components/prefs/scoped_user_pref_update.h29
-rw-r--r--chromium/components/prefs/scoped_user_pref_update_unittest.cc34
-rw-r--r--chromium/components/prefs/segregated_pref_store.cc3
-rw-r--r--chromium/components/prefs/segregated_pref_store_unittest.cc6
-rw-r--r--chromium/components/prefs/testing_pref_service.cc5
-rw-r--r--chromium/components/prefs/testing_pref_service.h31
-rw-r--r--chromium/components/previous_session_info/previous_session_info.h13
-rw-r--r--chromium/components/previous_session_info/previous_session_info.mm20
-rw-r--r--chromium/components/printing/browser/print_manager.cc4
-rw-r--r--chromium/components/printing/browser/print_manager.h8
-rw-r--r--chromium/components/printing/browser/print_to_pdf/pdf_print_manager.cc3
-rw-r--r--chromium/components/printing/browser/print_to_pdf/pdf_print_manager.h2
-rw-r--r--chromium/components/printing/common/cloud_print_cdd_conversion.cc13
-rw-r--r--chromium/components/printing/renderer/print_render_frame_helper.cc203
-rw-r--r--chromium/components/printing/renderer/print_render_frame_helper.h32
-rw-r--r--chromium/components/printing_component_strings.grdp2
-rw-r--r--chromium/components/privacy_sandbox/BUILD.gn66
-rw-r--r--chromium/components/privacy_sandbox/DEPS8
-rw-r--r--chromium/components/privacy_sandbox/canonical_topic.cc412
-rw-r--r--chromium/components/privacy_sandbox/canonical_topic.h47
-rw-r--r--chromium/components/privacy_sandbox/canonical_topic_unittest.cc93
-rw-r--r--chromium/components/privacy_sandbox/privacy_sandbox_features.cc22
-rw-r--r--chromium/components/privacy_sandbox/privacy_sandbox_features.h30
-rw-r--r--chromium/components/privacy_sandbox/privacy_sandbox_prefs.cc26
-rw-r--r--chromium/components/privacy_sandbox/privacy_sandbox_prefs.h29
-rw-r--r--chromium/components/privacy_sandbox/privacy_sandbox_settings.cc364
-rw-r--r--chromium/components/privacy_sandbox/privacy_sandbox_settings.h169
-rw-r--r--chromium/components/privacy_sandbox/privacy_sandbox_settings_unittest.cc783
-rw-r--r--chromium/components/privacy_sandbox/privacy_sandbox_test_util.cc89
-rw-r--r--chromium/components/privacy_sandbox/privacy_sandbox_test_util.h54
-rw-r--r--chromium/components/privacy_sandbox_strings.grdp1054
-rw-r--r--chromium/components/protocol_handler_strings.grdp41
-rw-r--r--chromium/components/protocol_handler_strings_grdp/IDS_PROTOCOL_HANDLER_INTENT_PICKER_QUESTION.png.sha11
-rw-r--r--chromium/components/proxy_config/pref_proxy_config_tracker_impl.cc2
-rw-r--r--chromium/components/proxy_config/proxy_policy_handler.cc4
-rw-r--r--chromium/components/query_tiles/BUILD.gn10
-rw-r--r--chromium/components/query_tiles/android/tile_conversion_bridge.cc7
-rw-r--r--chromium/components/query_tiles/internal/tile_service_scheduler_impl.cc2
-rw-r--r--chromium/components/query_tiles/internal/tile_service_scheduler_unittest.cc2
-rw-r--r--chromium/components/quirks/quirks_manager.cc2
-rw-r--r--chromium/components/reading_list/core/reading_list_model.h5
-rw-r--r--chromium/components/reading_list/core/reading_list_model_impl.h6
-rw-r--r--chromium/components/reading_list/core/reading_list_pref_names.cc6
-rw-r--r--chromium/components/reading_list/core/reading_list_pref_names.h4
-rw-r--r--chromium/components/reading_list/features/reading_list_switches.cc19
-rw-r--r--chromium/components/reading_list/features/reading_list_switches.h6
-rw-r--r--chromium/components/remote_cocoa/app_shim/application_bridge.mm9
-rw-r--r--chromium/components/remote_cocoa/app_shim/bridged_content_view.mm2
-rw-r--r--chromium/components/remote_cocoa/app_shim/color_panel_bridge.mm14
-rw-r--r--chromium/components/remote_cocoa/app_shim/mouse_capture.h4
-rw-r--r--chromium/components/remote_cocoa/app_shim/mouse_capture.mm7
-rw-r--r--chromium/components/remote_cocoa/app_shim/mouse_capture_delegate.h13
-rw-r--r--chromium/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.h8
-rw-r--r--chromium/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm45
-rw-r--r--chromium/components/remote_cocoa/common/native_widget_ns_window.mojom6
-rw-r--r--chromium/components/remote_cocoa/common/native_widget_ns_window_host.mojom5
-rw-r--r--chromium/components/renderer_context_menu/render_view_context_menu_base.cc2
-rw-r--r--chromium/components/reporting/DIR_METADATA1
-rw-r--r--chromium/components/reporting/client/empty_dm_token_retriever.cc2
-rw-r--r--chromium/components/reporting/client/empty_dm_token_retriever.h1
-rw-r--r--chromium/components/reporting/client/empty_dm_token_retriever_unittest.cc2
-rw-r--r--chromium/components/reporting/client/mock_dm_token_retriever.cc4
-rw-r--r--chromium/components/reporting/client/mock_dm_token_retriever.h3
-rw-r--r--chromium/components/reporting/client/mock_report_queue.h2
-rw-r--r--chromium/components/reporting/client/mock_report_queue_provider.cc62
-rw-r--r--chromium/components/reporting/client/mock_report_queue_provider.h31
-rw-r--r--chromium/components/reporting/client/report_queue_configuration.cc1
-rw-r--r--chromium/components/reporting/client/report_queue_configuration.h24
-rw-r--r--chromium/components/reporting/client/report_queue_factory.cc9
-rw-r--r--chromium/components/reporting/client/report_queue_factory_unittest.cc82
-rw-r--r--chromium/components/reporting/client/report_queue_impl.cc2
-rw-r--r--chromium/components/reporting/client/report_queue_impl.h1
-rw-r--r--chromium/components/reporting/client/report_queue_provider.cc2
-rw-r--r--chromium/components/reporting/client/report_queue_provider_test_helper.cc2
-rw-r--r--chromium/components/reporting/client/report_queue_provider_unittest.cc4
-rw-r--r--chromium/components/reporting/encryption/encryption_module.cc1
-rw-r--r--chromium/components/reporting/encryption/encryption_module.h2
-rw-r--r--chromium/components/reporting/encryption/encryption_module_interface.cc2
-rw-r--r--chromium/components/reporting/metrics/fake_metric_report_queue.h4
-rw-r--r--chromium/components/reporting/metrics/fake_reporting_settings.cc3
-rw-r--r--chromium/components/reporting/metrics/fake_reporting_settings.h2
-rw-r--r--chromium/components/reporting/metrics/fake_sampler.cc2
-rw-r--r--chromium/components/reporting/metrics/metric_data_collector.cc9
-rw-r--r--chromium/components/reporting/metrics/metric_data_collector.h3
-rw-r--r--chromium/components/reporting/metrics/metric_data_collector_unittest.cc234
-rw-r--r--chromium/components/reporting/metrics/metric_event_observer_manager.cc3
-rw-r--r--chromium/components/reporting/metrics/metric_event_observer_manager.h3
-rw-r--r--chromium/components/reporting/metrics/metric_event_observer_manager_unittest.cc57
-rw-r--r--chromium/components/reporting/metrics/metric_rate_controller_unittest.cc6
-rw-r--r--chromium/components/reporting/metrics/metric_report_queue.cc9
-rw-r--r--chromium/components/reporting/metrics/metric_report_queue.h6
-rw-r--r--chromium/components/reporting/metrics/metric_report_queue_unittest.cc84
-rw-r--r--chromium/components/reporting/metrics/metric_reporting_controller.cc4
-rw-r--r--chromium/components/reporting/metrics/metric_reporting_controller.h2
-rw-r--r--chromium/components/reporting/metrics/metric_reporting_controller_unittest.cc59
-rw-r--r--chromium/components/reporting/proto/synced/metric_data.proto111
-rw-r--r--chromium/components/reporting/proto/synced/record_constants.proto4
-rw-r--r--chromium/components/reporting/storage/BUILD.gn3
-rw-r--r--chromium/components/reporting/storage/storage.cc69
-rw-r--r--chromium/components/reporting/storage/storage_queue.cc108
-rw-r--r--chromium/components/reporting/storage/storage_queue.h6
-rw-r--r--chromium/components/reporting/storage/storage_queue_unittest.cc516
-rw-r--r--chromium/components/reporting/storage/storage_unittest.cc513
-rw-r--r--chromium/components/reporting/util/BUILD.gn24
-rw-r--r--chromium/components/reporting/util/disconnectable_client.cc77
-rw-r--r--chromium/components/reporting/util/disconnectable_client.h73
-rw-r--r--chromium/components/reporting/util/disconnectable_client_unittest.cc249
-rw-r--r--chromium/components/reporting/util/file.cc43
-rw-r--r--chromium/components/reporting/util/file.h34
-rw-r--r--chromium/components/reporting/util/file_unittest.cc88
-rw-r--r--chromium/components/reporting/util/status.h3
-rw-r--r--chromium/components/reporting/util/statusor.h9
-rw-r--r--chromium/components/reputation/core/safety_tip_test_utils.cc11
-rw-r--r--chromium/components/reputation/core/safety_tip_test_utils.h6
-rw-r--r--chromium/components/reputation/core/safety_tips.proto33
-rw-r--r--chromium/components/resources/about_ui_resources.grdp1
-rw-r--r--chromium/components/resources/autofill_and_password_manager_internals_resources.grdp8
-rw-r--r--chromium/components/resources/autofill_scaled_resources.grdp2
-rw-r--r--chromium/components/resources/components_resources.grd1
-rw-r--r--chromium/components/resources/default_100_percent/autofill/virtual_card_enroll.pngbin0 -> 2947 bytes
-rw-r--r--chromium/components/resources/default_100_percent/autofill/virtual_card_enroll_dark.pngbin0 -> 3011 bytes
-rw-r--r--chromium/components/resources/default_200_percent/autofill/virtual_card_enroll.pngbin0 -> 5715 bytes
-rw-r--r--chromium/components/resources/default_200_percent/autofill/virtual_card_enroll_dark.pngbin0 -> 5764 bytes
-rw-r--r--chromium/components/resources/default_300_percent/autofill/virtual_card_enroll.pngbin0 -> 8316 bytes
-rw-r--r--chromium/components/resources/default_300_percent/autofill/virtual_card_enroll_dark.pngbin0 -> 8541 bytes
-rw-r--r--chromium/components/resources/web_app_default_offline.grdp4
-rw-r--r--chromium/components/safe_browsing/DEPS2
-rw-r--r--chromium/components/safe_browsing/android/safe_browsing_api_handler_util.cc2
-rw-r--r--chromium/components/safe_browsing/content/browser/BUILD.gn1
-rw-r--r--chromium/components/safe_browsing/content/browser/base_ui_manager.cc56
-rw-r--r--chromium/components/safe_browsing/content/browser/client_side_detection_service.cc4
-rw-r--r--chromium/components/safe_browsing/content/browser/client_side_phishing_model_unittest.cc4
-rw-r--r--chromium/components/safe_browsing/content/browser/password_protection/BUILD.gn6
-rw-r--r--chromium/components/safe_browsing/content/browser/password_protection/password_protection_commit_deferring_condition.cc51
-rw-r--r--chromium/components/safe_browsing/content/browser/password_protection/password_protection_commit_deferring_condition.h81
-rw-r--r--chromium/components/safe_browsing/content/browser/password_protection/password_protection_commit_deferring_condition_unittest.cc106
-rw-r--r--chromium/components/safe_browsing/content/browser/password_protection/password_protection_navigation_throttle.cc76
-rw-r--r--chromium/components/safe_browsing/content/browser/password_protection/password_protection_navigation_throttle.h64
-rw-r--r--chromium/components/safe_browsing/content/browser/password_protection/password_protection_navigation_throttle_unittest.cc150
-rw-r--r--chromium/components/safe_browsing/content/browser/password_protection/password_protection_request_content.cc29
-rw-r--r--chromium/components/safe_browsing/content/browser/password_protection/password_protection_request_content.h35
-rw-r--r--chromium/components/safe_browsing/content/browser/password_protection/password_protection_service.cc41
-rw-r--r--chromium/components/safe_browsing/content/browser/password_protection/password_protection_service.h18
-rw-r--r--chromium/components/safe_browsing/content/browser/password_protection/password_protection_service_unittest.cc129
-rw-r--r--chromium/components/safe_browsing/content/browser/safe_browsing_blocking_page.cc31
-rw-r--r--chromium/components/safe_browsing/content/browser/safe_browsing_blocking_page.h4
-rw-r--r--chromium/components/safe_browsing/content/browser/safe_browsing_navigation_observer.cc4
-rw-r--r--chromium/components/safe_browsing/content/browser/safe_browsing_navigation_observer.h3
-rw-r--r--chromium/components/safe_browsing/content/browser/safe_browsing_navigation_observer_manager.cc3
-rw-r--r--chromium/components/safe_browsing/content/browser/safe_browsing_navigation_observer_unittest.cc55
-rw-r--r--chromium/components/safe_browsing/content/browser/safe_browsing_service_interface.h2
-rw-r--r--chromium/components/safe_browsing/content/browser/threat_details.cc26
-rw-r--r--chromium/components/safe_browsing/content/browser/threat_details.h16
-rw-r--r--chromium/components/safe_browsing/content/browser/threat_details_cache.cc7
-rw-r--r--chromium/components/safe_browsing/content/browser/threat_details_cache.h8
-rw-r--r--chromium/components/safe_browsing/content/browser/threat_details_history.cc6
-rw-r--r--chromium/components/safe_browsing/content/browser/threat_details_history.h9
-rw-r--r--chromium/components/safe_browsing/content/browser/triggers/BUILD.gn2
-rw-r--r--chromium/components/safe_browsing/content/browser/triggers/ad_sampler_trigger.cc6
-rw-r--r--chromium/components/safe_browsing/content/browser/triggers/ad_sampler_trigger.h4
-rw-r--r--chromium/components/safe_browsing/content/browser/triggers/ad_sampler_trigger_unittest.cc16
-rw-r--r--chromium/components/safe_browsing/content/browser/triggers/mock_trigger_manager.h8
-rw-r--r--chromium/components/safe_browsing/content/browser/triggers/suspicious_site_trigger.cc7
-rw-r--r--chromium/components/safe_browsing/content/browser/triggers/suspicious_site_trigger.h4
-rw-r--r--chromium/components/safe_browsing/content/browser/triggers/suspicious_site_trigger_unittest.cc28
-rw-r--r--chromium/components/safe_browsing/content/browser/triggers/trigger_manager.cc10
-rw-r--r--chromium/components/safe_browsing/content/browser/triggers/trigger_manager.h4
-rw-r--r--chromium/components/safe_browsing/content/browser/triggers/trigger_manager_unittest.cc4
-rw-r--r--chromium/components/safe_browsing/content/browser/triggers/trigger_throttler.cc4
-rw-r--r--chromium/components/safe_browsing/content/browser/triggers/trigger_throttler_unittest.cc6
-rw-r--r--chromium/components/safe_browsing/content/browser/ui_manager.cc18
-rw-r--r--chromium/components/safe_browsing/content/browser/ui_manager.h8
-rw-r--r--chromium/components/safe_browsing/content/browser/ui_manager_unittest.cc4
-rw-r--r--chromium/components/safe_browsing/content/browser/web_ui/safe_browsing_ui.cc214
-rw-r--r--chromium/components/safe_browsing/content/browser/web_ui/safe_browsing_ui.h56
-rw-r--r--chromium/components/safe_browsing/content/common/BUILD.gn22
-rw-r--r--chromium/components/safe_browsing/content/common/file_type_policies.cc92
-rw-r--r--chromium/components/safe_browsing/content/common/file_type_policies.h19
-rw-r--r--chromium/components/safe_browsing/content/common/file_type_policies_policy_util.cc77
-rw-r--r--chromium/components/safe_browsing/content/common/file_type_policies_policy_util.h21
-rw-r--r--chromium/components/safe_browsing/content/common/file_type_policies_policy_util_unittest.cc161
-rw-r--r--chromium/components/safe_browsing/content/common/file_type_policies_prefs.cc26
-rw-r--r--chromium/components/safe_browsing/content/common/file_type_policies_prefs.h21
-rw-r--r--chromium/components/safe_browsing/content/common/file_type_policies_unittest.cc26
-rw-r--r--chromium/components/safe_browsing/content/renderer/phishing_classifier/flatbuffer_scorer.cc17
-rw-r--r--chromium/components/safe_browsing/content/renderer/phishing_classifier/flatbuffer_scorer.h4
-rw-r--r--chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier.cc7
-rw-r--r--chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier.h4
-rw-r--r--chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier_delegate.cc6
-rw-r--r--chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier_delegate.h2
-rw-r--r--chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_term_feature_extractor_unittest.cc2
-rw-r--r--chromium/components/safe_browsing/content/renderer/phishing_classifier/protobuf_scorer.cc27
-rw-r--r--chromium/components/safe_browsing/content/renderer/phishing_classifier/protobuf_scorer.h4
-rw-r--r--chromium/components/safe_browsing/content/renderer/phishing_classifier/scorer.cc56
-rw-r--r--chromium/components/safe_browsing/content/renderer/phishing_classifier/scorer.h30
-rw-r--r--chromium/components/safe_browsing/content/resources/download_file_types.asciipb8
-rw-r--r--chromium/components/safe_browsing/content/resources/download_file_types_experiment.asciipb8
-rw-r--r--chromium/components/safe_browsing/core/browser/BUILD.gn4
-rw-r--r--chromium/components/safe_browsing/core/browser/DEPS1
-rw-r--r--chromium/components/safe_browsing/core/browser/db/v4_database.cc4
-rw-r--r--chromium/components/safe_browsing/core/browser/db/v4_get_hash_protocol_manager_unittest.cc2
-rw-r--r--chromium/components/safe_browsing/core/browser/db/v4_local_database_manager.cc2
-rw-r--r--chromium/components/safe_browsing/core/browser/db/v4_local_database_manager_unittest.cc2
-rw-r--r--chromium/components/safe_browsing/core/browser/db/v4_protocol_manager_util.cc8
-rw-r--r--chromium/components/safe_browsing/core/browser/db/v4_rice.cc4
-rw-r--r--chromium/components/safe_browsing/core/browser/db/v4_store.h1
-rw-r--r--chromium/components/safe_browsing/core/browser/password_protection/password_protection_request.cc29
-rw-r--r--chromium/components/safe_browsing/core/browser/password_protection/password_protection_request.h10
-rw-r--r--chromium/components/safe_browsing/core/browser/password_protection/password_protection_service_base.cc14
-rw-r--r--chromium/components/safe_browsing/core/browser/password_protection/password_protection_service_base.h15
-rw-r--r--chromium/components/safe_browsing/core/browser/ping_manager.cc62
-rw-r--r--chromium/components/safe_browsing/core/browser/ping_manager.h55
-rw-r--r--chromium/components/safe_browsing/core/browser/ping_manager_unittest.cc3
-rw-r--r--chromium/components/safe_browsing/core/browser/realtime/policy_engine.cc2
-rw-r--r--chromium/components/safe_browsing/core/browser/realtime/policy_engine_unittest.cc16
-rw-r--r--chromium/components/safe_browsing/core/browser/realtime/url_lookup_service.cc18
-rw-r--r--chromium/components/safe_browsing/core/browser/realtime/url_lookup_service.h14
-rw-r--r--chromium/components/safe_browsing/core/browser/realtime/url_lookup_service_base.cc68
-rw-r--r--chromium/components/safe_browsing/core/browser/realtime/url_lookup_service_base.h21
-rw-r--r--chromium/components/safe_browsing/core/browser/realtime/url_lookup_service_unittest.cc96
-rw-r--r--chromium/components/safe_browsing/core/browser/safe_browsing_metrics_collector.cc46
-rw-r--r--chromium/components/safe_browsing/core/browser/safe_browsing_metrics_collector.h5
-rw-r--r--chromium/components/safe_browsing/core/browser/safe_browsing_metrics_collector_unittest.cc45
-rw-r--r--chromium/components/safe_browsing/core/browser/safe_browsing_token_fetch_tracker.h2
-rw-r--r--chromium/components/safe_browsing/core/browser/safe_browsing_url_checker_impl.cc34
-rw-r--r--chromium/components/safe_browsing/core/browser/safe_browsing_url_checker_impl.h11
-rw-r--r--chromium/components/safe_browsing/core/browser/safe_browsing_url_checker_impl_unittest.cc9
-rw-r--r--chromium/components/safe_browsing/core/browser/tailored_security_service/tailored_security_service.cc34
-rw-r--r--chromium/components/safe_browsing/core/browser/tailored_security_service/tailored_security_service.h2
-rw-r--r--chromium/components/safe_browsing/core/browser/tailored_security_service/tailored_security_service_unittest.cc4
-rw-r--r--chromium/components/safe_browsing/core/browser/user_population_unittest.cc5
-rw-r--r--chromium/components/safe_browsing/core/browser/verdict_cache_manager.cc66
-rw-r--r--chromium/components/safe_browsing/core/browser/verdict_cache_manager_unittest.cc10
-rw-r--r--chromium/components/safe_browsing/core/common/features.cc56
-rw-r--r--chromium/components/safe_browsing/core/common/features.h16
-rw-r--r--chromium/components/safe_browsing/core/common/proto/csd.proto12
-rw-r--r--chromium/components/safe_browsing/core/common/proto/realtimeapi.proto21
-rw-r--r--chromium/components/safe_browsing/core/common/safe_browsing_prefs.cc25
-rw-r--r--chromium/components/safe_browsing/core/common/safe_browsing_prefs.h2
-rw-r--r--chromium/components/safe_browsing/core/common/safe_browsing_prefs_unittest.cc24
-rw-r--r--chromium/components/safe_browsing/core/common/utils.cc8
-rw-r--r--chromium/components/safe_browsing/core/common/visual_utils.cc2
-rw-r--r--chromium/components/safe_search_api/safe_search/safe_search_url_checker_client.cc5
-rw-r--r--chromium/components/scheduling_metrics/total_duration_metric_reporter.cc5
-rw-r--r--chromium/components/search/BUILD.gn1
-rw-r--r--chromium/components/search/DEPS1
-rw-r--r--chromium/components/search/ntp_features.cc140
-rw-r--r--chromium/components/search/ntp_features.h118
-rw-r--r--chromium/components/search/search.cc2
-rw-r--r--chromium/components/search/search_unittest.cc4
-rw-r--r--chromium/components/search_engines/BUILD.gn2
-rw-r--r--chromium/components/search_engines/DEPS3
-rw-r--r--chromium/components/search_engines/android/template_url_service_android.cc18
-rw-r--r--chromium/components/search_engines/android/template_url_service_android.h2
-rw-r--r--chromium/components/search_engines/default_search_manager.cc7
-rw-r--r--chromium/components/search_engines/default_search_manager_unittest.cc41
-rw-r--r--chromium/components/search_engines/default_search_policy_handler_unittest.cc8
-rw-r--r--chromium/components/search_engines/keyword_table.cc2
-rw-r--r--chromium/components/search_engines/keyword_web_data_service.cc2
-rw-r--r--chromium/components/search_engines/search_terms_data.cc102
-rw-r--r--chromium/components/search_engines/search_terms_data.h7
-rw-r--r--chromium/components/search_engines/template_url.cc155
-rw-r--r--chromium/components/search_engines/template_url.h4
-rw-r--r--chromium/components/search_engines/template_url_data.cc2
-rw-r--r--chromium/components/search_engines/template_url_data_util.cc16
-rw-r--r--chromium/components/search_engines/template_url_data_util.h2
-rw-r--r--chromium/components/search_engines/template_url_parser.cc18
-rw-r--r--chromium/components/search_engines/template_url_prepopulate_data.cc8
-rw-r--r--chromium/components/search_engines/template_url_prepopulate_data.h2
-rw-r--r--chromium/components/search_engines/template_url_service.cc7
-rw-r--r--chromium/components/search_engines/template_url_service.h8
-rw-r--r--chromium/components/search_engines/template_url_service_unittest.cc4
-rw-r--r--chromium/components/search_engines/template_url_unittest.cc12
-rw-r--r--chromium/components/search_provider_logos/google_logo_api.cc165
-rw-r--r--chromium/components/search_provider_logos/logo_service_impl.cc4
-rw-r--r--chromium/components/security_interstitials/content/android/BUILD.gn5
-rw-r--r--chromium/components/security_interstitials/content/captive_portal_blocking_page.cc8
-rw-r--r--chromium/components/security_interstitials/content/certificate_error_report.cc18
-rw-r--r--chromium/components/security_interstitials/content/certificate_error_report_unittest.cc16
-rw-r--r--chromium/components/security_interstitials/content/connection_help_ui.cc2
-rw-r--r--chromium/components/security_interstitials/content/security_interstitial_tab_helper.cc6
-rw-r--r--chromium/components/security_interstitials/content/security_interstitial_tab_helper_unittest.cc13
-rw-r--r--chromium/components/security_interstitials/content/ssl_error_handler.cc6
-rw-r--r--chromium/components/security_interstitials/content/ssl_error_handler_unittest.cc8
-rw-r--r--chromium/components/security_interstitials/content/ssl_error_navigation_throttle.cc26
-rw-r--r--chromium/components/security_interstitials/content/stateful_ssl_host_state_delegate.cc77
-rw-r--r--chromium/components/security_interstitials/content/stateful_ssl_host_state_delegate.h4
-rw-r--r--chromium/components/security_interstitials/content/utils.cc14
-rw-r--r--chromium/components/security_interstitials/core/safe_browsing_loud_error_ui.cc2
-rw-r--r--chromium/components/security_interstitials/core/ssl_error_ui.cc2
-rw-r--r--chromium/components/security_state/core/security_state.cc4
-rw-r--r--chromium/components/security_state/ios/BUILD.gn1
-rw-r--r--chromium/components/segmentation_platform/OWNERS2
-rw-r--r--chromium/components/segmentation_platform/README.md7
-rw-r--r--chromium/components/segmentation_platform/components_unittests.filter6
-rw-r--r--chromium/components/segmentation_platform/internal/BUILD.gn22
-rw-r--r--chromium/components/segmentation_platform/internal/DEPS4
-rw-r--r--chromium/components/segmentation_platform/internal/android/segmentation_platform_service_android.cc10
-rw-r--r--chromium/components/segmentation_platform/internal/android/segmentation_platform_service_android.h5
-rw-r--r--chromium/components/segmentation_platform/internal/data_collection/training_data_collector.cc26
-rw-r--r--chromium/components/segmentation_platform/internal/data_collection/training_data_collector.h40
-rw-r--r--chromium/components/segmentation_platform/internal/database/database_maintenance_impl.cc20
-rw-r--r--chromium/components/segmentation_platform/internal/database/database_maintenance_impl.h8
-rw-r--r--chromium/components/segmentation_platform/internal/database/metadata_utils.cc139
-rw-r--r--chromium/components/segmentation_platform/internal/database/metadata_utils.h19
-rw-r--r--chromium/components/segmentation_platform/internal/database/metadata_utils_unittest.cc201
-rw-r--r--chromium/components/segmentation_platform/internal/database/segment_info_database.cc6
-rw-r--r--chromium/components/segmentation_platform/internal/database/segment_info_database.h7
-rw-r--r--chromium/components/segmentation_platform/internal/database/segment_info_database_unittest.cc27
-rw-r--r--chromium/components/segmentation_platform/internal/database/signal_key.h5
-rw-r--r--chromium/components/segmentation_platform/internal/database/signal_key_internal.h12
-rw-r--r--chromium/components/segmentation_platform/internal/database/signal_storage_config.cc12
-rw-r--r--chromium/components/segmentation_platform/internal/database/signal_storage_config_unittest.cc4
-rw-r--r--chromium/components/segmentation_platform/internal/database/test_segment_info_database.cc11
-rw-r--r--chromium/components/segmentation_platform/internal/dummy_segmentation_platform_service.cc8
-rw-r--r--chromium/components/segmentation_platform/internal/dummy_segmentation_platform_service.h2
-rw-r--r--chromium/components/segmentation_platform/internal/dummy_segmentation_platform_service_unittest.cc2
-rw-r--r--chromium/components/segmentation_platform/internal/execution/custom_input_processor.cc60
-rw-r--r--chromium/components/segmentation_platform/internal/execution/custom_input_processor.h43
-rw-r--r--chromium/components/segmentation_platform/internal/execution/feature_list_query_processor.cc84
-rw-r--r--chromium/components/segmentation_platform/internal/execution/feature_list_query_processor.h71
-rw-r--r--chromium/components/segmentation_platform/internal/execution/feature_list_query_processor_unittest.cc561
-rw-r--r--chromium/components/segmentation_platform/internal/execution/feature_processor_state.cc47
-rw-r--r--chromium/components/segmentation_platform/internal/execution/feature_processor_state.h73
-rw-r--r--chromium/components/segmentation_platform/internal/execution/mock_feature_aggregator.cc12
-rw-r--r--chromium/components/segmentation_platform/internal/execution/mock_feature_aggregator.h38
-rw-r--r--chromium/components/segmentation_platform/internal/execution/model_execution_manager_factory.cc23
-rw-r--r--chromium/components/segmentation_platform/internal/execution/model_execution_manager_factory.h4
-rw-r--r--chromium/components/segmentation_platform/internal/execution/model_execution_manager_factory_unittest.cc13
-rw-r--r--chromium/components/segmentation_platform/internal/execution/model_execution_manager_impl.cc181
-rw-r--r--chromium/components/segmentation_platform/internal/execution/model_execution_manager_impl.h45
-rw-r--r--chromium/components/segmentation_platform/internal/execution/model_execution_manager_impl_unittest.cc364
-rw-r--r--chromium/components/segmentation_platform/internal/execution/segmentation_model_executor.cc32
-rw-r--r--chromium/components/segmentation_platform/internal/execution/segmentation_model_executor.h6
-rw-r--r--chromium/components/segmentation_platform/internal/execution/segmentation_model_executor_unittest.cc2
-rw-r--r--chromium/components/segmentation_platform/internal/execution/segmentation_model_handler.cc17
-rw-r--r--chromium/components/segmentation_platform/internal/execution/segmentation_model_handler.h4
-rw-r--r--chromium/components/segmentation_platform/internal/execution/uma_feature_processor.cc118
-rw-r--r--chromium/components/segmentation_platform/internal/execution/uma_feature_processor.h65
-rw-r--r--chromium/components/segmentation_platform/internal/proto/PRESUBMIT.py30
-rw-r--r--chromium/components/segmentation_platform/internal/proto/model_metadata.proto164
-rw-r--r--chromium/components/segmentation_platform/internal/scheduler/model_execution_scheduler_impl.cc17
-rw-r--r--chromium/components/segmentation_platform/internal/scheduler/model_execution_scheduler_impl.h5
-rw-r--r--chromium/components/segmentation_platform/internal/segmentation_platform_service_impl.cc63
-rw-r--r--chromium/components/segmentation_platform/internal/segmentation_platform_service_impl.h19
-rw-r--r--chromium/components/segmentation_platform/internal/segmentation_platform_service_impl_unittest.cc75
-rw-r--r--chromium/components/segmentation_platform/internal/segmentation_ukm_helper.cc131
-rw-r--r--chromium/components/segmentation_platform/internal/segmentation_ukm_helper.h48
-rw-r--r--chromium/components/segmentation_platform/internal/segmentation_ukm_helper_unittest.cc180
-rw-r--r--chromium/components/segmentation_platform/internal/selection/segment_score_provider.cc5
-rw-r--r--chromium/components/segmentation_platform/internal/selection/segment_selector.h8
-rw-r--r--chromium/components/segmentation_platform/internal/selection/segment_selector_impl.cc31
-rw-r--r--chromium/components/segmentation_platform/internal/selection/segment_selector_impl.h24
-rw-r--r--chromium/components/segmentation_platform/internal/selection/segment_selector_unittest.cc32
-rw-r--r--chromium/components/segmentation_platform/internal/selection/segmentation_result_prefs.cc4
-rw-r--r--chromium/components/segmentation_platform/internal/service_proxy_impl.cc176
-rw-r--r--chromium/components/segmentation_platform/internal/service_proxy_impl.h52
-rw-r--r--chromium/components/segmentation_platform/internal/service_proxy_impl_unittest.cc176
-rw-r--r--chromium/components/segmentation_platform/internal/signals/histogram_signal_handler.cc23
-rw-r--r--chromium/components/segmentation_platform/internal/signals/histogram_signal_handler.h21
-rw-r--r--chromium/components/segmentation_platform/internal/signals/histogram_signal_handler_unittest.cc36
-rw-r--r--chromium/components/segmentation_platform/internal/signals/signal_filter_processor.cc10
-rw-r--r--chromium/components/segmentation_platform/internal/signals/signal_filter_processor.h9
-rw-r--r--chromium/components/segmentation_platform/internal/stats.cc39
-rw-r--r--chromium/components/segmentation_platform/internal/stats.h40
-rw-r--r--chromium/components/segmentation_platform/internal/ukm_data_manager.cc44
-rw-r--r--chromium/components/segmentation_platform/internal/ukm_data_manager.h59
-rw-r--r--chromium/components/segmentation_platform/public/BUILD.gn1
-rw-r--r--chromium/components/segmentation_platform/public/config.h13
-rw-r--r--chromium/components/segmentation_platform/public/features.cc7
-rw-r--r--chromium/components/segmentation_platform/public/features.h6
-rw-r--r--chromium/components/segmentation_platform/public/segmentation_platform_service.h16
-rw-r--r--chromium/components/segmentation_platform/public/service_proxy.cc26
-rw-r--r--chromium/components/segmentation_platform/public/service_proxy.h48
-rw-r--r--chromium/components/send_tab_to_self/BUILD.gn1
-rw-r--r--chromium/components/send_tab_to_self/features.cc57
-rw-r--r--chromium/components/send_tab_to_self/features.h17
-rw-r--r--chromium/components/send_tab_to_self/features_unittest.cc31
-rw-r--r--chromium/components/send_tab_to_self/metrics_util.cc8
-rw-r--r--chromium/components/send_tab_to_self/metrics_util.h3
-rw-r--r--chromium/components/send_tab_to_self/send_tab_to_self_bridge.cc2
-rw-r--r--chromium/components/send_tab_to_self/send_tab_to_self_bridge_unittest.cc2
-rw-r--r--chromium/components/send_tab_to_self/send_tab_to_self_model_type_controller.cc4
-rw-r--r--chromium/components/services/app_service/BUILD.gn1
-rw-r--r--chromium/components/services/app_service/app_service_mojom_impl.cc11
-rw-r--r--chromium/components/services/app_service/app_service_mojom_impl.h4
-rw-r--r--chromium/components/services/app_service/public/cpp/BUILD.gn27
-rw-r--r--chromium/components/services/app_service/public/cpp/app_registry_cache.cc95
-rw-r--r--chromium/components/services/app_service/public/cpp/app_registry_cache.h31
-rw-r--r--chromium/components/services/app_service/public/cpp/app_registry_cache_mojom_unittest.cc63
-rw-r--r--chromium/components/services/app_service/public/cpp/app_registry_cache_unittest.cc681
-rw-r--r--chromium/components/services/app_service/public/cpp/app_types.cc326
-rw-r--r--chromium/components/services/app_service/public/cpp/app_types.h163
-rw-r--r--chromium/components/services/app_service/public/cpp/app_update.cc265
-rw-r--r--chromium/components/services/app_service/public/cpp/app_update.h28
-rw-r--r--chromium/components/services/app_service/public/cpp/app_update_mojom_unittest.cc203
-rw-r--r--chromium/components/services/app_service/public/cpp/app_update_unittest.cc722
-rw-r--r--chromium/components/services/app_service/public/cpp/browser_app_instance_update.h6
-rw-r--r--chromium/components/services/app_service/public/cpp/browser_window_instance_update.h4
-rw-r--r--chromium/components/services/app_service/public/cpp/features.cc16
-rw-r--r--chromium/components/services/app_service/public/cpp/features.h19
-rw-r--r--chromium/components/services/app_service/public/cpp/icon_loader.h6
-rw-r--r--chromium/components/services/app_service/public/cpp/icon_types.h3
-rw-r--r--chromium/components/services/app_service/public/cpp/instance_update.cc7
-rw-r--r--chromium/components/services/app_service/public/cpp/intent_filter.cc318
-rw-r--r--chromium/components/services/app_service/public/cpp/intent_filter.h167
-rw-r--r--chromium/components/services/app_service/public/cpp/intent_filter_util.cc11
-rw-r--r--chromium/components/services/app_service/public/cpp/intent_filter_util.h7
-rw-r--r--chromium/components/services/app_service/public/cpp/intent_filter_util_unittest.cc106
-rw-r--r--chromium/components/services/app_service/public/cpp/intent_util.cc32
-rw-r--r--chromium/components/services/app_service/public/cpp/macros.h33
-rw-r--r--chromium/components/services/app_service/public/cpp/permission.cc213
-rw-r--r--chromium/components/services/app_service/public/cpp/permission.h117
-rw-r--r--chromium/components/services/app_service/public/cpp/preferred_apps_converter.cc6
-rw-r--r--chromium/components/services/app_service/public/cpp/preferred_apps_converter_unittest.cc11
-rw-r--r--chromium/components/services/app_service/public/cpp/publisher_base.cc6
-rw-r--r--chromium/components/services/app_service/public/cpp/publisher_base.h3
-rw-r--r--chromium/components/services/app_service/public/cpp/run_on_os_login_types.cc62
-rw-r--r--chromium/components/services/app_service/public/cpp/run_on_os_login_types.h64
-rw-r--r--chromium/components/services/app_service/public/mojom/BUILD.gn3
-rw-r--r--chromium/components/services/app_service/public/mojom/app_service.mojom15
-rw-r--r--chromium/components/services/app_service/public/mojom/types.mojom27
-rw-r--r--chromium/components/services/filesystem/directory_impl.cc2
-rw-r--r--chromium/components/services/filesystem/file_impl.cc6
-rw-r--r--chromium/components/services/filesystem/file_impl.h4
-rw-r--r--chromium/components/services/filesystem/lock_table.cc8
-rw-r--r--chromium/components/services/filesystem/util.cc6
-rw-r--r--chromium/components/services/font/BUILD.gn1
-rw-r--r--chromium/components/services/font/font_service_app.cc93
-rw-r--r--chromium/components/services/font/font_service_app.h33
-rw-r--r--chromium/components/services/heap_profiling/heap_profiling_service.cc1
-rw-r--r--chromium/components/services/heap_profiling/json_exporter_unittest.cc54
-rw-r--r--chromium/components/services/heap_profiling/public/cpp/heap_profiling_trace_source.cc1
-rw-r--r--chromium/components/services/heap_profiling/public/cpp/profiling_client.cc14
-rw-r--r--chromium/components/services/paint_preview_compositor/paint_preview_compositor_collection_impl.cc16
-rw-r--r--chromium/components/services/paint_preview_compositor/paint_preview_compositor_collection_impl.h4
-rw-r--r--chromium/components/services/patch/content/patch_service.cc1
-rw-r--r--chromium/components/services/print_compositor/print_compositor_impl.cc14
-rw-r--r--chromium/components/services/quarantine/BUILD.gn2
-rw-r--r--chromium/components/services/quarantine/OWNERS1
-rw-r--r--chromium/components/services/quarantine/README.md6
-rw-r--r--chromium/components/services/quarantine/public/cpp/BUILD.gn16
-rw-r--r--chromium/components/services/quarantine/public/cpp/quarantine_features_win.cc15
-rw-r--r--chromium/components/services/quarantine/public/cpp/quarantine_features_win.h16
-rw-r--r--chromium/components/services/quarantine/quarantine.cc2
-rw-r--r--chromium/components/services/quarantine/quarantine.h2
-rw-r--r--chromium/components/services/quarantine/quarantine_impl.cc7
-rw-r--r--chromium/components/services/quarantine/quarantine_impl.h8
-rw-r--r--chromium/components/services/quarantine/quarantine_unittest.cc6
-rw-r--r--chromium/components/services/quarantine/quarantine_win.cc1
-rw-r--r--chromium/components/services/quarantine/quarantine_win_unittest.cc1
-rw-r--r--chromium/components/services/quarantine/test_support.cc2
-rw-r--r--chromium/components/services/storage/BUILD.gn31
-rw-r--r--chromium/components/services/storage/DEPS2
-rw-r--r--chromium/components/services/storage/dom_storage/local_storage_impl.cc4
-rw-r--r--chromium/components/services/storage/dom_storage/local_storage_impl_unittest.cc5
-rw-r--r--chromium/components/services/storage/dom_storage/session_storage_data_map_unittest.cc4
-rw-r--r--chromium/components/services/storage/dom_storage/session_storage_impl.cc2
-rw-r--r--chromium/components/services/storage/dom_storage/storage_area_impl_unittest.cc6
-rw-r--r--chromium/components/services/storage/dom_storage/testing_legacy_session_storage_database.cc2
-rw-r--r--chromium/components/services/storage/indexed_db/leveldb/leveldb_factory.cc7
-rw-r--r--chromium/components/services/storage/indexed_db/scopes/leveldb_scope.h20
-rw-r--r--chromium/components/services/storage/indexed_db/scopes/leveldb_scopes.cc10
-rw-r--r--chromium/components/services/storage/indexed_db/scopes/leveldb_scopes_tasks.h31
-rw-r--r--chromium/components/services/storage/indexed_db/scopes/leveldb_scopes_test_utils.cc8
-rw-r--r--chromium/components/services/storage/indexed_db/scopes/varint_coding.h2
-rw-r--r--chromium/components/services/storage/indexed_db/transactional_leveldb/transactional_leveldb_database.cc2
-rw-r--r--chromium/components/services/storage/indexed_db/transactional_leveldb/transactional_leveldb_iterator.cc8
-rw-r--r--chromium/components/services/storage/indexed_db/transactional_leveldb/transactional_leveldb_iterator.h8
-rw-r--r--chromium/components/services/storage/indexed_db/transactional_leveldb/transactional_leveldb_transaction.h25
-rw-r--r--chromium/components/services/storage/indexed_db/transactional_leveldb/transactional_leveldb_transaction_unittest.cc1
-rw-r--r--chromium/components/services/storage/partition_impl.cc2
-rw-r--r--chromium/components/services/storage/public/cpp/BUILD.gn1
-rw-r--r--chromium/components/services/storage/public/cpp/constants.cc4
-rw-r--r--chromium/components/services/storage/public/cpp/constants.h3
-rw-r--r--chromium/components/services/storage/public/cpp/filesystem/filesystem_impl.cc17
-rw-r--r--chromium/components/services/storage/public/cpp/filesystem/filesystem_proxy.cc13
-rw-r--r--chromium/components/services/storage/public/cpp/quota_client_callback_wrapper.cc35
-rw-r--r--chromium/components/services/storage/public/cpp/quota_client_callback_wrapper.h19
-rw-r--r--chromium/components/services/storage/public/cpp/storage_key_quota_client.h29
-rw-r--r--chromium/components/services/storage/public/mojom/quota_client.mojom30
-rw-r--r--chromium/components/services/storage/service_worker/service_worker_database.cc51
-rw-r--r--chromium/components/services/storage/service_worker/service_worker_storage.cc7
-rw-r--r--chromium/components/services/storage/service_worker/service_worker_storage_control_impl.cc5
-rw-r--r--chromium/components/services/storage/service_worker/service_worker_storage_control_impl_unittest.cc106
-rw-r--r--chromium/components/services/storage/service_worker/service_worker_storage_unittest.cc2
-rw-r--r--chromium/components/services/storage/shared_storage/DIR_METADATA12
-rw-r--r--chromium/components/services/storage/shared_storage/OWNERS6
-rw-r--r--chromium/components/services/storage/shared_storage/async_shared_storage_database.cc196
-rw-r--r--chromium/components/services/storage/shared_storage/async_shared_storage_database.h237
-rw-r--r--chromium/components/services/storage/shared_storage/async_shared_storage_database_unittest.cc1648
-rw-r--r--chromium/components/services/storage/shared_storage/shared_storage_database.cc900
-rw-r--r--chromium/components/services/storage/shared_storage/shared_storage_database.h388
-rw-r--r--chromium/components/services/storage/shared_storage/shared_storage_database_unittest.cc835
-rw-r--r--chromium/components/services/storage/shared_storage/shared_storage_options.cc80
-rw-r--r--chromium/components/services/storage/shared_storage/shared_storage_options.h104
-rw-r--r--chromium/components/services/storage/shared_storage/shared_storage_test_utils.cc369
-rw-r--r--chromium/components/services/storage/shared_storage/shared_storage_test_utils.h210
-rw-r--r--chromium/components/services/storage/storage_service_impl.cc8
-rw-r--r--chromium/components/services/storage/storage_service_impl.h6
-rw-r--r--chromium/components/services/unzip/BUILD.gn16
-rw-r--r--chromium/components/services/unzip/DEPS1
-rw-r--r--chromium/components/services/unzip/OWNERS3
-rw-r--r--chromium/components/services/unzip/public/cpp/unzip.cc133
-rw-r--r--chromium/components/services/unzip/public/cpp/unzip.h6
-rw-r--r--chromium/components/services/unzip/public/cpp/unzip_unittest.cc145
-rw-r--r--chromium/components/services/unzip/public/mojom/unzipper.mojom19
-rw-r--r--chromium/components/services/unzip/unzipper_impl.cc131
-rw-r--r--chromium/components/services/unzip/unzipper_impl.h8
-rw-r--r--chromium/components/session_manager/session_manager_types.h3
-rw-r--r--chromium/components/sessions/BUILD.gn12
-rw-r--r--chromium/components/sessions/content/DEPS4
-rw-r--r--chromium/components/sessions/content/session_tab_helper.cc18
-rw-r--r--chromium/components/sessions/content/session_tab_helper.h8
-rw-r--r--chromium/components/sessions/core/command_storage_backend.cc4
-rw-r--r--chromium/components/sessions/core/command_storage_backend.h1
-rw-r--r--chromium/components/sessions/core/serialized_navigation_entry.cc9
-rw-r--r--chromium/components/sessions/core/session_command.cc2
-rw-r--r--chromium/components/sessions/core/session_service_commands.cc4
-rw-r--r--chromium/components/sessions/core/tab_restore_service.h1
-rw-r--r--chromium/components/sessions/core/tab_restore_service_helper.cc91
-rw-r--r--chromium/components/sessions/core/tab_restore_service_helper.h4
-rw-r--r--chromium/components/sessions/core/tab_restore_service_impl.cc7
-rw-r--r--chromium/components/sessions/ios/ios_serialized_navigation_builder.mm10
-rw-r--r--chromium/components/sessions/ios/ios_serialized_navigation_builder_unittest.mm9
-rw-r--r--chromium/components/shared_highlighting/core/common/BUILD.gn16
-rw-r--r--chromium/components/shared_highlighting/core/common/disabled_sites.cc13
-rw-r--r--chromium/components/shared_highlighting/core/common/disabled_sites.h4
-rw-r--r--chromium/components/shared_highlighting/core/common/disabled_sites_unittest.cc32
-rw-r--r--chromium/components/shared_highlighting/core/common/fragment_directives_utils_unittest.cc12
-rw-r--r--chromium/components/shared_highlighting/core/common/shared_highlighting_data_driven_test.cc6
-rw-r--r--chromium/components/shared_highlighting/core/common/shared_highlighting_features.cc5
-rw-r--r--chromium/components/shared_highlighting/core/common/shared_highlighting_features.h3
-rw-r--r--chromium/components/shared_highlighting/core/common/shared_highlighting_metrics.cc98
-rw-r--r--chromium/components/shared_highlighting/core/common/shared_highlighting_metrics.h102
-rw-r--r--chromium/components/shared_highlighting/core/common/shared_highlighting_metrics_unittest.cc128
-rw-r--r--chromium/components/shared_highlighting/ios/BUILD.gn32
-rw-r--r--chromium/components/shared_highlighting/ios/DEPS3
-rw-r--r--chromium/components/shared_highlighting/ios/parsing_utils.h43
-rw-r--r--chromium/components/shared_highlighting/ios/parsing_utils.mm76
-rw-r--r--chromium/components/shared_highlighting/ios/parsing_utils_unittest.mm74
-rw-r--r--chromium/components/shared_highlighting/ios/shared_highlighting_constants.h15
-rw-r--r--chromium/components/shared_highlighting/ios/shared_highlighting_constants.mm16
-rw-r--r--chromium/components/signin/core/browser/BUILD.gn10
-rw-r--r--chromium/components/signin/core/browser/account_investigator_unittest.cc4
-rw-r--r--chromium/components/signin/core/browser/account_reconcilor.cc11
-rw-r--r--chromium/components/signin/core/browser/account_reconcilor.h24
-rw-r--r--chromium/components/signin/core/browser/chrome_connected_header_helper.cc24
-rw-r--r--chromium/components/signin/core/browser/consistency_cookie_manager.cc106
-rw-r--r--chromium/components/signin/core/browser/consistency_cookie_manager.h77
-rw-r--r--chromium/components/signin/core/browser/consistency_cookie_manager_unittest.cc133
-rw-r--r--chromium/components/signin/core/browser/mirror_account_reconcilor_delegate.cc2
-rw-r--r--chromium/components/signin/core/browser/mirror_account_reconcilor_delegate.h2
-rw-r--r--chromium/components/signin/core/browser/mirror_landing_account_reconcilor_delegate.cc74
-rw-r--r--chromium/components/signin/core/browser/mirror_landing_account_reconcilor_delegate.h47
-rw-r--r--chromium/components/signin/core/browser/mirror_landing_account_reconcilor_delegate_unittest.cc90
-rw-r--r--chromium/components/signin/core/browser/signin_header_helper.h2
-rw-r--r--chromium/components/signin/core/browser/signin_header_helper_unittest.cc49
-rw-r--r--chromium/components/signin/internal/identity_manager/account_capabilities_constants.cc3
-rw-r--r--chromium/components/signin/internal/identity_manager/account_capabilities_constants.h1
-rw-r--r--chromium/components/signin/internal/identity_manager/account_fetcher_service.cc18
-rw-r--r--chromium/components/signin/internal/identity_manager/account_fetcher_service.h10
-rw-r--r--chromium/components/signin/internal/identity_manager/account_info_util.cc2
-rw-r--r--chromium/components/signin/internal/identity_manager/account_tracker_service.cc85
-rw-r--r--chromium/components/signin/internal/identity_manager/account_tracker_service.h7
-rw-r--r--chromium/components/signin/internal/identity_manager/account_tracker_service_unittest.cc58
-rw-r--r--chromium/components/signin/internal/identity_manager/accounts_cookie_mutator_impl.cc2
-rw-r--r--chromium/components/signin/internal/identity_manager/accounts_cookie_mutator_impl.h2
-rw-r--r--chromium/components/signin/internal/identity_manager/device_accounts_synchronizer_impl.cc3
-rw-r--r--chromium/components/signin/internal/identity_manager/device_accounts_synchronizer_impl.h2
-rw-r--r--chromium/components/signin/internal/identity_manager/fake_profile_oauth2_token_service_delegate.cc3
-rw-r--r--chromium/components/signin/internal/identity_manager/fake_profile_oauth2_token_service_delegate.h2
-rw-r--r--chromium/components/signin/internal/identity_manager/gaia_cookie_manager_service.cc8
-rw-r--r--chromium/components/signin/internal/identity_manager/mutable_profile_oauth2_token_service_delegate_unittest.cc28
-rw-r--r--chromium/components/signin/internal/identity_manager/primary_account_manager.cc52
-rw-r--r--chromium/components/signin/internal/identity_manager/primary_account_manager.h15
-rw-r--r--chromium/components/signin/internal/identity_manager/primary_account_manager_unittest.cc80
-rw-r--r--chromium/components/signin/internal/identity_manager/primary_account_mutator_impl.cc36
-rw-r--r--chromium/components/signin/internal/identity_manager/profile_oauth2_token_service.cc4
-rw-r--r--chromium/components/signin/internal/identity_manager/profile_oauth2_token_service_builder.cc39
-rw-r--r--chromium/components/signin/internal/identity_manager/profile_oauth2_token_service_builder.h10
-rw-r--r--chromium/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate.h13
-rw-r--r--chromium/components/signin/ios/browser/BUILD.gn1
-rw-r--r--chromium/components/signin/ios/browser/account_consistency_service.h2
-rw-r--r--chromium/components/signin/ios/browser/account_consistency_service.mm48
-rw-r--r--chromium/components/signin/ios/browser/account_consistency_service_unittest.mm156
-rw-r--r--chromium/components/signin/ios/browser/features.cc7
-rw-r--r--chromium/components/signin/ios/browser/features.h6
-rw-r--r--chromium/components/signin/ios/browser/manage_accounts_delegate.h62
-rw-r--r--chromium/components/signin/public/android/BUILD.gn1
-rw-r--r--chromium/components/signin/public/android/junit/src/org/chromium/components/signin/AccountManagerFacadeImplTest.java32
-rw-r--r--chromium/components/signin/public/android/junit/src/org/chromium/components/signin/AccountRenameCheckerTest.java2
-rw-r--r--chromium/components/signin/public/android/junit/src/org/chromium/components/signin/AccountUtilsTest.java12
-rw-r--r--chromium/components/signin/public/android/junit/src/org/chromium/components/signin/identitymanager/AccountTrackerServiceTest.java2
-rw-r--r--chromium/components/signin/public/base/account_consistency_method.cc8
-rw-r--r--chromium/components/signin/public/base/account_consistency_method.h7
-rw-r--r--chromium/components/signin/public/base/signin_metrics.cc14
-rw-r--r--chromium/components/signin/public/base/signin_metrics.h18
-rw-r--r--chromium/components/signin/public/base/signin_metrics_unittest.cc2
-rw-r--r--chromium/components/signin/public/base/signin_switches.cc35
-rw-r--r--chromium/components/signin/public/base/signin_switches.h23
-rw-r--r--chromium/components/signin/public/identity_manager/access_token_constants.cc4
-rw-r--r--chromium/components/signin/public/identity_manager/access_token_fetcher.cc2
-rw-r--r--chromium/components/signin/public/identity_manager/access_token_fetcher.h2
-rw-r--r--chromium/components/signin/public/identity_manager/access_token_fetcher_unittest.cc78
-rw-r--r--chromium/components/signin/public/identity_manager/account_info.cc6
-rw-r--r--chromium/components/signin/public/identity_manager/account_info.h4
-rw-r--r--chromium/components/signin/public/identity_manager/accounts_cookie_mutator.h2
-rw-r--r--chromium/components/signin/public/identity_manager/accounts_cookie_mutator_unittest.cc2
-rw-r--r--chromium/components/signin/public/identity_manager/device_accounts_synchronizer.h2
-rw-r--r--chromium/components/signin/public/identity_manager/identity_manager.cc18
-rw-r--r--chromium/components/signin/public/identity_manager/identity_manager.h39
-rw-r--r--chromium/components/signin/public/identity_manager/identity_manager_builder.cc19
-rw-r--r--chromium/components/signin/public/identity_manager/identity_manager_builder.h10
-rw-r--r--chromium/components/signin/public/identity_manager/identity_manager_builder_unittest.cc10
-rw-r--r--chromium/components/signin/public/identity_manager/identity_manager_unittest.cc13
-rw-r--r--chromium/components/signin/public/identity_manager/identity_mutator.cc13
-rw-r--r--chromium/components/signin/public/identity_manager/identity_mutator.h8
-rw-r--r--chromium/components/signin/public/identity_manager/identity_test_environment.cc10
-rw-r--r--chromium/components/signin/public/identity_manager/identity_test_utils.cc16
-rw-r--r--chromium/components/signin/public/identity_manager/identity_test_utils.h4
-rw-r--r--chromium/components/signin/public/identity_manager/primary_account_access_token_fetcher_unittest.cc3
-rw-r--r--chromium/components/signin/public/identity_manager/primary_account_change_event.cc8
-rw-r--r--chromium/components/signin/public/identity_manager/primary_account_change_event.h4
-rw-r--r--chromium/components/signin/public/identity_manager/primary_account_mutator_unittest.cc23
-rw-r--r--chromium/components/signin/public/identity_manager/ubertoken_fetcher.h4
-rw-r--r--chromium/components/signin/public/webdata/token_web_data.h1
-rw-r--r--chromium/components/site_engagement/content/site_engagement_score.cc10
-rw-r--r--chromium/components/site_engagement/content/site_engagement_service.cc10
-rw-r--r--chromium/components/site_engagement/content/site_engagement_service.h6
-rw-r--r--chromium/components/site_isolation/features.cc4
-rw-r--r--chromium/components/site_isolation/site_isolation_policy.cc17
-rw-r--r--chromium/components/site_isolation/site_isolation_policy_unittest.cc22
-rw-r--r--chromium/components/soda/constants.cc37
-rw-r--r--chromium/components/soda/constants.h20
-rw-r--r--chromium/components/soda/soda_installer.cc10
-rw-r--r--chromium/components/soda/soda_installer_impl_chromeos.cc40
-rw-r--r--chromium/components/soda/soda_installer_impl_chromeos.h3
-rw-r--r--chromium/components/soda/soda_installer_impl_chromeos_unittest.cc16
-rw-r--r--chromium/components/spellcheck/browser/spell_check_host_impl.cc14
-rw-r--r--chromium/components/spellcheck/browser/spell_check_host_impl.h10
-rw-r--r--chromium/components/spellcheck/browser/spellcheck_host_metrics.cc4
-rw-r--r--chromium/components/spellcheck/browser/spellcheck_host_metrics.h8
-rw-r--r--chromium/components/spellcheck/browser/spellcheck_host_metrics_unittest.cc6
-rw-r--r--chromium/components/spellcheck/browser/spellcheck_platform.h20
-rw-r--r--chromium/components/spellcheck/browser/spellcheck_platform_win.cc5
-rw-r--r--chromium/components/spellcheck/browser/spelling_service_client.cc51
-rw-r--r--chromium/components/spellcheck/common/spellcheck_features.cc10
-rw-r--r--chromium/components/spellcheck/common/spellcheck_features.h8
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck.cc22
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck_provider.cc32
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck_provider.h16
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck_provider_hunspell_unittest.cc8
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck_provider_test.cc18
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck_provider_test.h14
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck_provider_unittest.cc12
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck_renderer_metrics.cc8
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck_renderer_metrics.h4
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck_unittest.cc38
-rw-r--r--chromium/components/spellcheck/renderer/spelling_engine.cc2
-rw-r--r--chromium/components/ssl_errors/error_classification.cc2
-rw-r--r--chromium/components/startup_metric_utils/browser/startup_metric_utils.cc14
-rw-r--r--chromium/components/storage_monitor/image_capture_device.mm6
-rw-r--r--chromium/components/storage_monitor/media_storage_util.cc6
-rw-r--r--chromium/components/storage_monitor/mtp_manager_client_chromeos.cc4
-rw-r--r--chromium/components/storage_monitor/removable_device_constants.cc4
-rw-r--r--chromium/components/storage_monitor/removable_device_constants.h4
-rw-r--r--chromium/components/storage_monitor/storage_monitor.h2
-rw-r--r--chromium/components/storage_monitor/storage_monitor_linux_unittest.cc52
-rw-r--r--chromium/components/storage_monitor/test_storage_monitor.cc2
-rw-r--r--chromium/components/storage_monitor/test_storage_monitor.h2
-rw-r--r--chromium/components/storage_monitor/volume_mount_watcher_win.cc1
-rw-r--r--chromium/components/strings/components_chromium_strings_de.xtb16
-rw-r--r--chromium/components/strings/components_chromium_strings_hy.xtb2
-rw-r--r--chromium/components/strings/components_google_chrome_strings_af.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_am.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_ar.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_as.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_az.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_be.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_bg.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_bn.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_bs.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_ca.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_cs.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_da.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_de.xtb19
-rw-r--r--chromium/components/strings/components_google_chrome_strings_el.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_en-GB.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_es-419.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_es.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_et.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_eu.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_fa.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_fi.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_fil.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_fr-CA.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_fr.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_gl.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_gu.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_hi.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_hr.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_hu.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_hy.xtb3
-rw-r--r--chromium/components/strings/components_google_chrome_strings_id.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_is.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_it.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_iw.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_ja.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_ka.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_kk.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_km.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_kn.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_ko.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_ky.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_lo.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_lt.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_lv.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_mk.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_ml.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_mn.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_mr.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_ms.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_my.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_ne.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_nl.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_no.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_or.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_pa.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_pl.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_pt-BR.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_pt-PT.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_ro.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_ru.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_si.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_sk.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_sl.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_sq.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_sr-Latn.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_sr.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_sv.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_sw.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_ta.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_te.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_th.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_tr.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_uk.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_ur.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_uz.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_vi.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_zh-CN.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_zh-HK.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_zh-TW.xtb1
-rw-r--r--chromium/components/strings/components_google_chrome_strings_zu.xtb1
-rw-r--r--chromium/components/strings/components_strings_af.xtb121
-rw-r--r--chromium/components/strings/components_strings_am.xtb121
-rw-r--r--chromium/components/strings/components_strings_ar.xtb133
-rw-r--r--chromium/components/strings/components_strings_as.xtb125
-rw-r--r--chromium/components/strings/components_strings_az.xtb119
-rw-r--r--chromium/components/strings/components_strings_be.xtb121
-rw-r--r--chromium/components/strings/components_strings_bg.xtb121
-rw-r--r--chromium/components/strings/components_strings_bn.xtb119
-rw-r--r--chromium/components/strings/components_strings_bs.xtb127
-rw-r--r--chromium/components/strings/components_strings_ca.xtb129
-rw-r--r--chromium/components/strings/components_strings_cs.xtb119
-rw-r--r--chromium/components/strings/components_strings_da.xtb121
-rw-r--r--chromium/components/strings/components_strings_de.xtb1101
-rw-r--r--chromium/components/strings/components_strings_el.xtb123
-rw-r--r--chromium/components/strings/components_strings_en-GB.xtb123
-rw-r--r--chromium/components/strings/components_strings_es-419.xtb119
-rw-r--r--chromium/components/strings/components_strings_es.xtb143
-rw-r--r--chromium/components/strings/components_strings_et.xtb123
-rw-r--r--chromium/components/strings/components_strings_eu.xtb137
-rw-r--r--chromium/components/strings/components_strings_fa.xtb133
-rw-r--r--chromium/components/strings/components_strings_fi.xtb125
-rw-r--r--chromium/components/strings/components_strings_fil.xtb121
-rw-r--r--chromium/components/strings/components_strings_fr-CA.xtb119
-rw-r--r--chromium/components/strings/components_strings_fr.xtb135
-rw-r--r--chromium/components/strings/components_strings_gl.xtb119
-rw-r--r--chromium/components/strings/components_strings_gu.xtb118
-rw-r--r--chromium/components/strings/components_strings_hi.xtb125
-rw-r--r--chromium/components/strings/components_strings_hr.xtb129
-rw-r--r--chromium/components/strings/components_strings_hu.xtb121
-rw-r--r--chromium/components/strings/components_strings_hy.xtb133
-rw-r--r--chromium/components/strings/components_strings_id.xtb121
-rw-r--r--chromium/components/strings/components_strings_is.xtb119
-rw-r--r--chromium/components/strings/components_strings_it.xtb207
-rw-r--r--chromium/components/strings/components_strings_iw.xtb121
-rw-r--r--chromium/components/strings/components_strings_ja.xtb121
-rw-r--r--chromium/components/strings/components_strings_ka.xtb121
-rw-r--r--chromium/components/strings/components_strings_kk.xtb121
-rw-r--r--chromium/components/strings/components_strings_km.xtb119
-rw-r--r--chromium/components/strings/components_strings_kn.xtb121
-rw-r--r--chromium/components/strings/components_strings_ko.xtb119
-rw-r--r--chromium/components/strings/components_strings_ky.xtb123
-rw-r--r--chromium/components/strings/components_strings_lo.xtb119
-rw-r--r--chromium/components/strings/components_strings_lt.xtb119
-rw-r--r--chromium/components/strings/components_strings_lv.xtb127
-rw-r--r--chromium/components/strings/components_strings_mk.xtb123
-rw-r--r--chromium/components/strings/components_strings_ml.xtb119
-rw-r--r--chromium/components/strings/components_strings_mn.xtb121
-rw-r--r--chromium/components/strings/components_strings_mr.xtb121
-rw-r--r--chromium/components/strings/components_strings_ms.xtb121
-rw-r--r--chromium/components/strings/components_strings_my.xtb127
-rw-r--r--chromium/components/strings/components_strings_ne.xtb129
-rw-r--r--chromium/components/strings/components_strings_nl.xtb123
-rw-r--r--chromium/components/strings/components_strings_no.xtb121
-rw-r--r--chromium/components/strings/components_strings_or.xtb119
-rw-r--r--chromium/components/strings/components_strings_pa.xtb119
-rw-r--r--chromium/components/strings/components_strings_pl.xtb121
-rw-r--r--chromium/components/strings/components_strings_pt-BR.xtb135
-rw-r--r--chromium/components/strings/components_strings_pt-PT.xtb209
-rw-r--r--chromium/components/strings/components_strings_ro.xtb133
-rw-r--r--chromium/components/strings/components_strings_ru.xtb126
-rw-r--r--chromium/components/strings/components_strings_si.xtb121
-rw-r--r--chromium/components/strings/components_strings_sk.xtb119
-rw-r--r--chromium/components/strings/components_strings_sl.xtb119
-rw-r--r--chromium/components/strings/components_strings_sq.xtb121
-rw-r--r--chromium/components/strings/components_strings_sr-Latn.xtb121
-rw-r--r--chromium/components/strings/components_strings_sr.xtb121
-rw-r--r--chromium/components/strings/components_strings_sv.xtb121
-rw-r--r--chromium/components/strings/components_strings_sw.xtb121
-rw-r--r--chromium/components/strings/components_strings_ta.xtb133
-rw-r--r--chromium/components/strings/components_strings_te.xtb177
-rw-r--r--chromium/components/strings/components_strings_th.xtb121
-rw-r--r--chromium/components/strings/components_strings_tr.xtb121
-rw-r--r--chromium/components/strings/components_strings_uk.xtb123
-rw-r--r--chromium/components/strings/components_strings_ur.xtb120
-rw-r--r--chromium/components/strings/components_strings_uz.xtb119
-rw-r--r--chromium/components/strings/components_strings_vi.xtb133
-rw-r--r--chromium/components/strings/components_strings_zh-CN.xtb121
-rw-r--r--chromium/components/strings/components_strings_zh-HK.xtb119
-rw-r--r--chromium/components/strings/components_strings_zh-TW.xtb125
-rw-r--r--chromium/components/strings/components_strings_zu.xtb119
-rw-r--r--chromium/components/subresource_filter/content/browser/BUILD.gn3
-rw-r--r--chromium/components/subresource_filter/content/browser/DEPS2
-rw-r--r--chromium/components/subresource_filter/content/browser/ads_blocked_message_delegate.cc5
-rw-r--r--chromium/components/subresource_filter/content/browser/ads_blocked_message_delegate.h2
-rw-r--r--chromium/components/subresource_filter/content/browser/ads_intervention_manager.cc7
-rw-r--r--chromium/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.h6
-rw-r--r--chromium/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager_unittest.cc489
-rw-r--r--chromium/components/subresource_filter/content/browser/content_subresource_filter_web_contents_helper.cc190
-rw-r--r--chromium/components/subresource_filter/content/browser/content_subresource_filter_web_contents_helper.h58
-rw-r--r--chromium/components/subresource_filter/content/browser/navigation_console_logger.cc6
-rw-r--r--chromium/components/subresource_filter/content/browser/profile_interaction_manager.cc18
-rw-r--r--chromium/components/subresource_filter/content/browser/profile_interaction_manager.h14
-rw-r--r--chromium/components/subresource_filter/content/browser/subframe_navigation_filtering_throttle.cc2
-rw-r--r--chromium/components/subresource_filter/content/browser/subresource_filter_configuration_unittest.cc12
-rw-r--r--chromium/components/subresource_filter/content/browser/subresource_filter_content_settings_manager.cc14
-rw-r--r--chromium/components/subresource_filter/content/browser/subresource_filter_content_settings_manager_unittest.cc4
-rw-r--r--chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle_unittest.cc103
-rw-r--r--chromium/components/subresource_filter/content/browser/subresource_filter_test_harness.cc8
-rw-r--r--chromium/components/subresource_filter/content/browser/subresource_filter_test_harness.h7
-rw-r--r--chromium/components/subresource_filter/content/renderer/web_document_subresource_filter_impl.cc8
-rw-r--r--chromium/components/subresource_filter/content/renderer/web_document_subresource_filter_impl.h2
-rw-r--r--chromium/components/subresource_filter/core/common/indexed_ruleset_unittest.cc6
-rw-r--r--chromium/components/subresource_filter/core/common/test_ruleset_utils.cc28
-rw-r--r--chromium/components/subresource_filter/core/common/test_ruleset_utils.h12
-rw-r--r--chromium/components/subresource_filter/tools/filter_tool_main.cc2
-rw-r--r--chromium/components/subresource_filter/tools/rule_parser/rule.cc9
-rw-r--r--chromium/components/subresource_filter/tools/ruleset_converter/ruleset_converter.cc2
-rw-r--r--chromium/components/subresource_filter/tools/ruleset_converter/ruleset_converter_unittest.cc2
-rw-r--r--chromium/components/subresource_redirect/BUILD.gn29
-rw-r--r--chromium/components/subresource_redirect/DEPS9
-rw-r--r--chromium/components/subresource_redirect/DIR_METADATA3
-rw-r--r--chromium/components/subresource_redirect/OWNERS1
-rw-r--r--chromium/components/subresource_redirect/common/BUILD.gn13
-rw-r--r--chromium/components/subresource_redirect/common/subresource_redirect_features.cc92
-rw-r--r--chromium/components/subresource_redirect/common/subresource_redirect_features.h40
-rw-r--r--chromium/components/subresource_redirect/common/subresource_redirect_result.h77
-rw-r--r--chromium/components/subresource_redirect/proto/BUILD.gn9
-rw-r--r--chromium/components/subresource_redirect/proto/robots_rules.proto26
-rw-r--r--chromium/components/subresource_redirect/subresource_redirect_browser_test_util.cc177
-rw-r--r--chromium/components/subresource_redirect/subresource_redirect_browser_test_util.h119
-rw-r--r--chromium/components/subresource_redirect/subresource_redirect_test_util.cc24
-rw-r--r--chromium/components/subresource_redirect/subresource_redirect_test_util.h29
-rw-r--r--chromium/components/sync/BUILD.gn6
-rw-r--r--chromium/components/sync/android/BUILD.gn1
-rw-r--r--chromium/components/sync/base/BUILD.gn13
-rw-r--r--chromium/components/sync/base/node_ordinal.h56
-rw-r--r--chromium/components/sync/base/ordinal.h4
-rw-r--r--chromium/components/sync/driver/BUILD.gn3
-rw-r--r--chromium/components/sync/engine/BUILD.gn8
-rw-r--r--chromium/components/sync/invalidations/BUILD.gn2
-rw-r--r--chromium/components/sync/protocol/BUILD.gn2
-rw-r--r--chromium/components/sync/trusted_vault/BUILD.gn2
-rw-r--r--chromium/components/sync_bookmarks/BUILD.gn4
-rw-r--r--chromium/components/sync_bookmarks/README.md1
-rw-r--r--chromium/components/sync_bookmarks/bookmark_local_changes_builder.cc27
-rw-r--r--chromium/components/sync_bookmarks/bookmark_model_merger.cc259
-rw-r--r--chromium/components/sync_bookmarks/bookmark_model_merger.h21
-rw-r--r--chromium/components/sync_bookmarks/bookmark_model_merger_unittest.cc38
-rw-r--r--chromium/components/sync_bookmarks/bookmark_model_observer_impl_unittest.cc53
-rw-r--r--chromium/components/sync_bookmarks/bookmark_model_type_processor.cc11
-rw-r--r--chromium/components/sync_bookmarks/bookmark_model_type_processor_unittest.cc9
-rw-r--r--chromium/components/sync_bookmarks/bookmark_remote_updates_handler.cc132
-rw-r--r--chromium/components/sync_bookmarks/bookmark_remote_updates_handler.h5
-rw-r--r--chromium/components/sync_bookmarks/bookmark_remote_updates_handler_unittest.cc69
-rw-r--r--chromium/components/sync_bookmarks/bookmark_specifics_conversions.cc42
-rw-r--r--chromium/components/sync_bookmarks/bookmark_specifics_conversions_unittest.cc63
-rw-r--r--chromium/components/sync_bookmarks/bookmark_sync_service.cc1
-rw-r--r--chromium/components/sync_bookmarks/parent_guid_preprocessing.cc240
-rw-r--r--chromium/components/sync_bookmarks/parent_guid_preprocessing.h32
-rw-r--r--chromium/components/sync_bookmarks/parent_guid_preprocessing_unittest.cc233
-rw-r--r--chromium/components/sync_bookmarks/switches.cc20
-rw-r--r--chromium/components/sync_bookmarks/switches.h8
-rw-r--r--chromium/components/sync_bookmarks/synced_bookmark_tracker.cc63
-rw-r--r--chromium/components/sync_bookmarks/synced_bookmark_tracker.h21
-rw-r--r--chromium/components/sync_bookmarks/synced_bookmark_tracker_unittest.cc39
-rw-r--r--chromium/components/sync_device_info/DEPS1
-rw-r--r--chromium/components/sync_device_info/README.md1
-rw-r--r--chromium/components/sync_device_info/device_count_metrics_provider.cc12
-rw-r--r--chromium/components/sync_device_info/device_info_prefs.cc15
-rw-r--r--chromium/components/sync_device_info/device_info_prefs_unittest.cc8
-rw-r--r--chromium/components/sync_device_info/device_info_sync_bridge.cc37
-rw-r--r--chromium/components/sync_device_info/device_info_sync_bridge_unittest.cc6
-rw-r--r--chromium/components/sync_device_info/fake_device_info_tracker.cc4
-rw-r--r--chromium/components/sync_device_info/local_device_info_provider.h4
-rw-r--r--chromium/components/sync_device_info/local_device_info_util.cc8
-rw-r--r--chromium/components/sync_preferences/README.md1
-rw-r--r--chromium/components/sync_preferences/pref_model_associator.cc34
-rw-r--r--chromium/components/sync_preferences/pref_model_associator.h6
-rw-r--r--chromium/components/sync_preferences/pref_model_associator_client.h2
-rw-r--r--chromium/components/sync_preferences/pref_model_associator_unittest.cc134
-rw-r--r--chromium/components/sync_preferences/pref_service_syncable.cc12
-rw-r--r--chromium/components/sync_preferences/pref_service_syncable.h1
-rw-r--r--chromium/components/sync_preferences/pref_service_syncable_factory.cc11
-rw-r--r--chromium/components/sync_preferences/pref_service_syncable_unittest.cc93
-rw-r--r--chromium/components/sync_preferences/testing_pref_service_syncable.cc7
-rw-r--r--chromium/components/sync_preferences/testing_pref_service_syncable.h2
-rw-r--r--chromium/components/sync_sessions/BUILD.gn2
-rw-r--r--chromium/components/sync_sessions/README.md1
-rw-r--r--chromium/components/sync_sessions/local_session_event_handler_impl.cc40
-rw-r--r--chromium/components/sync_sessions/local_session_event_handler_impl_unittest.cc55
-rw-r--r--chromium/components/sync_sessions/open_tabs_ui_delegate_impl.h1
-rw-r--r--chromium/components/sync_sessions/session_store.cc5
-rw-r--r--chromium/components/sync_sessions/session_store_unittest.cc6
-rw-r--r--chromium/components/sync_sessions/session_sync_bridge.cc7
-rw-r--r--chromium/components/sync_sessions/session_sync_bridge_unittest.cc25
-rw-r--r--chromium/components/sync_sessions/session_sync_service.h5
-rw-r--r--chromium/components/sync_sessions/session_sync_service_impl.h4
-rw-r--r--chromium/components/sync_sessions/session_sync_test_helper.cc12
-rw-r--r--chromium/components/sync_sessions/switches.cc14
-rw-r--r--chromium/components/sync_sessions/switches.h16
-rw-r--r--chromium/components/sync_sessions/synced_session.cc5
-rw-r--r--chromium/components/sync_sessions/synced_session_tracker.cc94
-rw-r--r--chromium/components/sync_sessions/synced_session_tracker.h8
-rw-r--r--chromium/components/sync_sessions/synced_session_tracker_unittest.cc77
-rw-r--r--chromium/components/sync_sessions/synced_tab_delegate.h7
-rw-r--r--chromium/components/sync_sessions/tab_node_pool.cc59
-rw-r--r--chromium/components/sync_sessions/tab_node_pool.h12
-rw-r--r--chromium/components/sync_sessions/tab_node_pool_unittest.cc36
-rw-r--r--chromium/components/sync_sessions/test_matchers.cc9
-rw-r--r--chromium/components/sync_sessions/test_synced_window_delegates_getter.cc38
-rw-r--r--chromium/components/sync_sessions/test_synced_window_delegates_getter.h14
-rw-r--r--chromium/components/sync_user_events/README.md1
-rw-r--r--chromium/components/sync_user_events/user_event_sync_bridge.cc4
-rw-r--r--chromium/components/sync_user_events/user_event_sync_bridge_unittest.cc9
-rw-r--r--chromium/components/system_media_controls/linux/system_media_controls_linux.cc150
-rw-r--r--chromium/components/system_media_controls/linux/system_media_controls_linux.h23
-rw-r--r--chromium/components/system_media_controls/linux/system_media_controls_linux_unittest.cc282
-rw-r--r--chromium/components/system_media_controls/mock_system_media_controls.h1
-rw-r--r--chromium/components/system_media_controls/system_media_controls.h1
-rw-r--r--chromium/components/system_media_controls/system_media_controls_observer.h17
-rw-r--r--chromium/components/tab_groups/tab_group_color.h5
-rw-r--r--chromium/components/thin_webview/internal/thin_webview.cc5
-rw-r--r--chromium/components/thin_webview/internal/thin_webview.h3
-rw-r--r--chromium/components/tracing/BUILD.gn16
-rw-r--r--chromium/components/tracing/DEPS3
-rw-r--r--chromium/components/tracing/common/background_tracing_metrics_provider.cc64
-rw-r--r--chromium/components/tracing/common/background_tracing_metrics_provider.h53
-rw-r--r--chromium/components/tracing/common/trace_startup_config.cc48
-rw-r--r--chromium/components/tracing/common/trace_startup_config.h2
-rw-r--r--chromium/components/translate/content/browser/BUILD.gn3
-rw-r--r--chromium/components/translate/core/browser/BUILD.gn15
-rw-r--r--chromium/components/translate/ios/browser/BUILD.gn1
-rw-r--r--chromium/components/translate_strings.grdp3
-rw-r--r--chromium/components/translate_strings_grdp/IDS_TRANSLATE_UNKNOWN_SOURCE_LANGUAGE.png.sha11
-rw-r--r--chromium/components/ui_devtools/BUILD.gn4
-rw-r--r--chromium/components/ui_devtools/devtools_server_unittest.cc2
-rw-r--r--chromium/components/ui_devtools/inspector_protocol_config.json2
-rw-r--r--chromium/components/ui_devtools/views/BUILD.gn1
-rw-r--r--chromium/components/ui_devtools/views/element_utility.cc2
-rw-r--r--chromium/components/ui_devtools/views/overlay_agent_views.cc6
-rw-r--r--chromium/components/ukm/BUILD.gn2
-rw-r--r--chromium/components/ukm/ios/BUILD.gn1
-rw-r--r--chromium/components/ukm/ukm_recorder_impl.cc341
-rw-r--r--chromium/components/ukm/ukm_recorder_impl.h62
-rw-r--r--chromium/components/ukm/ukm_recorder_impl_unittest.cc166
-rw-r--r--chromium/components/ukm/ukm_recorder_observer.cc19
-rw-r--r--chromium/components/ukm/ukm_recorder_observer.h46
-rw-r--r--chromium/components/ukm/ukm_reporting_service.cc4
-rw-r--r--chromium/components/ukm/ukm_service.cc3
-rw-r--r--chromium/components/ukm/ukm_service.h2
-rw-r--r--chromium/components/ukm/ukm_service_unittest.cc223
-rw-r--r--chromium/components/undo/undo_manager.cc6
-rw-r--r--chromium/components/unified_consent/README.md2
-rw-r--r--chromium/components/unified_consent/unified_consent_metrics.cc19
-rw-r--r--chromium/components/update_client/BUILD.gn8
-rw-r--r--chromium/components/update_client/command_line_config_policy.cc2
-rw-r--r--chromium/components/update_client/component.cc4
-rw-r--r--chromium/components/update_client/component_patcher.cc4
-rw-r--r--chromium/components/update_client/component_patcher_operation.cc32
-rw-r--r--chromium/components/update_client/configurator.h15
-rw-r--r--chromium/components/update_client/crx_downloader.cc2
-rw-r--r--chromium/components/update_client/crx_downloader_factory.cc4
-rw-r--r--chromium/components/update_client/net/network_impl.cc3
-rw-r--r--chromium/components/update_client/ping_manager.cc4
-rw-r--r--chromium/components/update_client/ping_manager_unittest.cc61
-rw-r--r--chromium/components/update_client/protocol_definition.cc3
-rw-r--r--chromium/components/update_client/protocol_definition.h14
-rw-r--r--chromium/components/update_client/protocol_parser_json.cc8
-rw-r--r--chromium/components/update_client/protocol_serializer.cc50
-rw-r--r--chromium/components/update_client/protocol_serializer.h3
-rw-r--r--chromium/components/update_client/protocol_serializer_fuzzer.cc14
-rw-r--r--chromium/components/update_client/protocol_serializer_json.cc8
-rw-r--r--chromium/components/update_client/protocol_serializer_json_unittest.cc56
-rw-r--r--chromium/components/update_client/test_configurator.cc52
-rw-r--r--chromium/components/update_client/test_configurator.h10
-rw-r--r--chromium/components/update_client/update_checker.cc51
-rw-r--r--chromium/components/update_client/update_checker_unittest.cc133
-rw-r--r--chromium/components/update_client/update_client_unittest.cc16
-rw-r--r--chromium/components/update_client/update_engine.h1
-rw-r--r--chromium/components/update_client/update_query_params.cc16
-rw-r--r--chromium/components/update_client/updater_state.cc102
-rw-r--r--chromium/components/update_client/updater_state.h69
-rw-r--r--chromium/components/update_client/updater_state_mac.mm117
-rw-r--r--chromium/components/update_client/updater_state_unittest.cc127
-rw-r--r--chromium/components/update_client/updater_state_win.cc135
-rw-r--r--chromium/components/update_client/utils_unittest.cc1
-rw-r--r--chromium/components/upload_list/text_log_upload_list.cc5
-rw-r--r--chromium/components/url_formatter/elide_url.cc54
-rw-r--r--chromium/components/url_formatter/elide_url.h4
-rw-r--r--chromium/components/url_formatter/elide_url_unittest.cc10
-rw-r--r--chromium/components/url_formatter/spoof_checks/idn_spoof_checker.cc4
-rw-r--r--chromium/components/url_formatter/spoof_checks/idn_spoof_checker_unittest.cc4
-rw-r--r--chromium/components/url_formatter/spoof_checks/top_domains/make_top_domain_list_variables.cc2
-rw-r--r--chromium/components/url_formatter/spoof_checks/top_domains/top_domain_generator.cc2
-rw-r--r--chromium/components/url_formatter/url_fixer.cc22
-rw-r--r--chromium/components/url_formatter/url_fixer_unittest.cc40
-rw-r--r--chromium/components/url_formatter/url_formatter.cc43
-rw-r--r--chromium/components/url_formatter/url_formatter_unittest.cc24
-rw-r--r--chromium/components/url_matcher/BUILD.gn8
-rw-r--r--chromium/components/url_matcher/DEPS3
-rw-r--r--chromium/components/url_matcher/url_matcher_factory.cc9
-rw-r--r--chromium/components/url_matcher/url_matcher_helpers.cc31
-rw-r--r--chromium/components/url_matcher/url_matcher_helpers.h27
-rw-r--r--chromium/components/url_matcher/url_util.cc495
-rw-r--r--chromium/components/url_matcher/url_util.h133
-rw-r--r--chromium/components/url_matcher/url_util_unittest.cc676
-rw-r--r--chromium/components/url_pattern_index/flat/url_pattern_index.fbs10
-rw-r--r--chromium/components/url_pattern_index/proto/rules.proto2
-rw-r--r--chromium/components/url_pattern_index/url_pattern.cc4
-rw-r--r--chromium/components/url_pattern_index/url_pattern_index.cc81
-rw-r--r--chromium/components/url_pattern_index/url_pattern_index.h25
-rw-r--r--chromium/components/url_pattern_index/url_pattern_index_unittest.cc17
-rw-r--r--chromium/components/url_pattern_index/url_rule_test_support.cc7
-rw-r--r--chromium/components/url_pattern_index/url_rule_test_support.h10
-rw-r--r--chromium/components/url_pattern_index/url_rule_util.cc16
-rw-r--r--chromium/components/url_pattern_index/url_rule_util_unittest.cc2
-rw-r--r--chromium/components/url_rewrite/browser/url_request_rewrite_rules_manager.cc16
-rw-r--r--chromium/components/url_rewrite/browser/url_request_rewrite_rules_manager.h5
-rw-r--r--chromium/components/url_rewrite/browser/url_request_rewrite_rules_manager_browsertest.cc22
-rw-r--r--chromium/components/user_manager/fake_user_manager.cc7
-rw-r--r--chromium/components/user_manager/known_user.cc725
-rw-r--r--chromium/components/user_manager/known_user.h327
-rw-r--r--chromium/components/user_manager/known_user_unittest.cc205
-rw-r--r--chromium/components/user_manager/user.cc5
-rw-r--r--chromium/components/user_manager/user_manager_base.cc78
-rw-r--r--chromium/components/user_manager/user_manager_base.h4
-rw-r--r--chromium/components/value_store/leveldb_value_store_unittest.cc4
-rw-r--r--chromium/components/value_store/value_store_test_suite.cc17
-rw-r--r--chromium/components/variations/BUILD.gn6
-rw-r--r--chromium/components/variations/DEPS1
-rw-r--r--chromium/components/variations/android/BUILD.gn1
-rw-r--r--chromium/components/variations/android/junit/src/org/chromium/components/variations/firstrun/VariationsSeedFetcherTest.java4
-rw-r--r--chromium/components/variations/client_filterable_state.cc14
-rw-r--r--chromium/components/variations/fake_crash.cc35
-rw-r--r--chromium/components/variations/fake_crash.h17
-rw-r--r--chromium/components/variations/field_trial_config/field_trial_util.cc34
-rw-r--r--chromium/components/variations/field_trial_config/field_trial_util_unittest.cc137
-rw-r--r--chromium/components/variations/metrics.cc5
-rw-r--r--chromium/components/variations/metrics.h8
-rw-r--r--chromium/components/variations/processed_study.cc16
-rw-r--r--chromium/components/variations/processed_study.h2
-rw-r--r--chromium/components/variations/service/BUILD.gn7
-rw-r--r--chromium/components/variations/service/variations_field_trial_creator.cc175
-rw-r--r--chromium/components/variations/service/variations_field_trial_creator.h45
-rw-r--r--chromium/components/variations/service/variations_field_trial_creator_unittest.cc704
-rw-r--r--chromium/components/variations/service/variations_safe_mode_constants.cc8
-rw-r--r--chromium/components/variations/service/variations_service.cc36
-rw-r--r--chromium/components/variations/service/variations_service.h4
-rw-r--r--chromium/components/variations/service/variations_service_unittest.cc13
-rw-r--r--chromium/components/variations/study_filtering_unittest.cc6
-rw-r--r--chromium/components/variations/synthetic_trial_registry.cc11
-rw-r--r--chromium/components/variations/synthetic_trial_registry.h23
-rw-r--r--chromium/components/variations/synthetic_trial_registry_unittest.cc49
-rw-r--r--chromium/components/variations/synthetic_trials.cc6
-rw-r--r--chromium/components/variations/synthetic_trials.h21
-rw-r--r--chromium/components/variations/variations_crash_keys.cc2
-rw-r--r--chromium/components/variations/variations_crash_keys_unittest.cc12
-rw-r--r--chromium/components/variations/variations_ids_provider.cc2
-rw-r--r--chromium/components/variations/variations_ids_provider.h4
-rw-r--r--chromium/components/variations/variations_murmur_hash.cc4
-rw-r--r--chromium/components/variations/variations_request_scheduler.cc4
-rw-r--r--chromium/components/variations/variations_seed_simulator_unittest.cc1
-rw-r--r--chromium/components/variations/variations_seed_store.cc23
-rw-r--r--chromium/components/variations/variations_seed_store.h95
-rw-r--r--chromium/components/variations/variations_seed_store_unittest.cc26
-rw-r--r--chromium/components/variations/variations_switches.cc11
-rw-r--r--chromium/components/variations/variations_switches.h2
-rw-r--r--chromium/components/variations/variations_test_utils.cc93
-rw-r--r--chromium/components/variations/variations_test_utils.h11
-rw-r--r--chromium/components/vector_icons/BUILD.gn11
-rw-r--r--chromium/components/vector_icons/dogfood.icon50
-rw-r--r--chromium/components/vector_icons/google_color.icon95
-rw-r--r--chromium/components/vector_icons/history.icon43
-rw-r--r--chromium/components/vector_icons/qr_code.icon75
-rw-r--r--chromium/components/vector_icons/settings_outline.icon91
-rw-r--r--chromium/components/vector_icons/videogame_asset_outline.icon63
-rw-r--r--chromium/components/vector_icons/warning_outline.icon30
-rw-r--r--chromium/components/version_info/android/BUILD.gn1
-rw-r--r--chromium/components/version_info/version_info.cc18
-rw-r--r--chromium/components/version_ui/resources/about_version.js4
-rw-r--r--chromium/components/version_ui/version_ui_constants.cc15
-rw-r--r--chromium/components/version_ui/version_ui_constants.h14
-rw-r--r--chromium/components/visitedlink/browser/visitedlink_writer.cc4
-rw-r--r--chromium/components/visitedlink/browser/visitedlink_writer.h2
-rw-r--r--chromium/components/viz/BUILD.gn1
-rw-r--r--chromium/components/viz/client/client_resource_provider.cc4
-rw-r--r--chromium/components/viz/client/client_resource_provider.h2
-rw-r--r--chromium/components/viz/client/frame_eviction_manager.cc2
-rw-r--r--chromium/components/viz/common/BUILD.gn11
-rw-r--r--chromium/components/viz/common/display/de_jelly.cc6
-rw-r--r--chromium/components/viz/common/display/renderer_settings.h3
-rw-r--r--chromium/components/viz/common/features.cc63
-rw-r--r--chromium/components/viz/common/features.h27
-rw-r--r--chromium/components/viz/common/frame_sinks/begin_frame_source.h2
-rw-r--r--chromium/components/viz/common/frame_sinks/delay_based_time_source.cc5
-rw-r--r--chromium/components/viz/common/frame_sinks/delay_based_time_source.h2
-rw-r--r--chromium/components/viz/common/frame_sinks/delay_based_time_source_unittest.cc123
-rw-r--r--chromium/components/viz/common/gl_i420_converter.h2
-rw-r--r--chromium/components/viz/common/gl_nv12_converter.h2
-rw-r--r--chromium/components/viz/common/gl_scaler.h25
-rw-r--r--chromium/components/viz/common/gl_scaler_overscan_pixeltest.cc2
-rw-r--r--chromium/components/viz/common/gl_scaler_pixeltest.cc6
-rw-r--r--chromium/components/viz/common/gl_scaler_shader_pixeltest.cc6
-rw-r--r--chromium/components/viz/common/gpu/DEPS2
-rw-r--r--chromium/components/viz/common/gpu/dawn_context_provider.cc28
-rw-r--r--chromium/components/viz/common/gpu/dawn_context_provider.h6
-rw-r--r--chromium/components/viz/common/gpu/vulkan_in_process_context_provider.cc17
-rw-r--r--chromium/components/viz/common/hit_test/hit_test_region_list.h3
-rw-r--r--chromium/components/viz/common/quads/compositor_frame_metadata.h4
-rw-r--r--chromium/components/viz/common/quads/compositor_frame_metadata_unittest.cc8
-rw-r--r--chromium/components/viz/common/quads/compositor_frame_transition_directive.cc3
-rw-r--r--chromium/components/viz/common/quads/compositor_frame_transition_directive.h9
-rw-r--r--chromium/components/viz/common/quads/compositor_frame_transition_directive_unittest.cc4
-rw-r--r--chromium/components/viz/common/quads/draw_quad_unittest.cc17
-rw-r--r--chromium/components/viz/common/quads/render_pass_io.cc79
-rw-r--r--chromium/components/viz/common/quads/render_pass_io_unittest.cc14
-rw-r--r--chromium/components/viz/common/resources/DEPS2
-rw-r--r--chromium/components/viz/common/resources/bitmap_allocation.cc2
-rw-r--r--chromium/components/viz/common/resources/resource_format_utils.cc26
-rw-r--r--chromium/components/viz/common/resources/resource_format_utils.h12
-rw-r--r--chromium/components/viz/common/resources/transferable_resource.h8
-rw-r--r--chromium/components/viz/common/surfaces/region_capture_bounds.cc12
-rw-r--r--chromium/components/viz/common/surfaces/region_capture_bounds.h10
-rw-r--r--chromium/components/viz/common/switches.cc12
-rw-r--r--chromium/components/viz/common/switches.h4
-rw-r--r--chromium/components/viz/common/viz_utils.cc15
-rw-r--r--chromium/components/viz/common/viz_utils.h2
-rw-r--r--chromium/components/viz/common/yuv_readback_unittest.cc4
-rw-r--r--chromium/components/viz/demo/demo_main.cc4
-rw-r--r--chromium/components/viz/host/client_frame_sink_video_capturer.cc21
-rw-r--r--chromium/components/viz/host/client_frame_sink_video_capturer.h4
-rw-r--r--chromium/components/viz/host/gpu_host_impl.cc29
-rw-r--r--chromium/components/viz/host/gpu_host_impl.h10
-rw-r--r--chromium/components/viz/host/hit_test/hit_test_query.cc4
-rw-r--r--chromium/components/viz/host/host_display_client.cc13
-rw-r--r--chromium/components/viz/host/host_display_client.h10
-rw-r--r--chromium/components/viz/host/host_frame_sink_manager.cc7
-rw-r--r--chromium/components/viz/host/host_gpu_memory_buffer_manager_unittest.cc15
-rw-r--r--chromium/components/viz/host/renderer_settings_creation.cc14
-rw-r--r--chromium/components/viz/service/BUILD.gn27
-rw-r--r--chromium/components/viz/service/DEPS6
-rw-r--r--chromium/components/viz/service/debugger/viz_debugger.cc2
-rw-r--r--chromium/components/viz/service/debugger/viz_debugger.h26
-rw-r--r--chromium/components/viz/service/debugger/viz_debugger_unittest.cc34
-rw-r--r--chromium/components/viz/service/display/ca_layer_overlay.cc226
-rw-r--r--chromium/components/viz/service/display/ca_layer_overlay.h31
-rw-r--r--chromium/components/viz/service/display/delegated_ink_point_renderer_base.cc5
-rw-r--r--chromium/components/viz/service/display/delegated_ink_point_renderer_base.h2
-rw-r--r--chromium/components/viz/service/display/delegated_ink_point_renderer_skia.cc9
-rw-r--r--chromium/components/viz/service/display/delegated_ink_point_renderer_skia.h2
-rw-r--r--chromium/components/viz/service/display/delegated_ink_trail_data.cc2
-rw-r--r--chromium/components/viz/service/display/direct_renderer.cc7
-rw-r--r--chromium/components/viz/service/display/direct_renderer.h6
-rw-r--r--chromium/components/viz/service/display/display.cc47
-rw-r--r--chromium/components/viz/service/display/display_resource_provider.cc25
-rw-r--r--chromium/components/viz/service/display/display_resource_provider.h5
-rw-r--r--chromium/components/viz/service/display/display_resource_provider_skia.cc6
-rw-r--r--chromium/components/viz/service/display/display_resource_provider_skia.h3
-rw-r--r--chromium/components/viz/service/display/display_resource_provider_skia_unittest.cc21
-rw-r--r--chromium/components/viz/service/display/display_scheduler.cc39
-rw-r--r--chromium/components/viz/service/display/display_scheduler.h10
-rw-r--r--chromium/components/viz/service/display/display_scheduler_unittest.cc4
-rw-r--r--chromium/components/viz/service/display/display_unittest.cc1
-rw-r--r--chromium/components/viz/service/display/draw_polygon.cc2
-rw-r--r--chromium/components/viz/service/display/draw_polygon_unittest.cc2
-rw-r--r--chromium/components/viz/service/display/external_use_client.h3
-rw-r--r--chromium/components/viz/service/display/frame_rate_decider.cc11
-rw-r--r--chromium/components/viz/service/display/frame_rate_decider_unittest.cc17
-rw-r--r--chromium/components/viz/service/display/gl_renderer.cc73
-rw-r--r--chromium/components/viz/service/display/gl_renderer.h24
-rw-r--r--chromium/components/viz/service/display/gl_renderer_copier_pixeltest.cc4
-rw-r--r--chromium/components/viz/service/display/gl_renderer_unittest.cc106
-rw-r--r--chromium/components/viz/service/display/output_surface_frame.h4
-rw-r--r--chromium/components/viz/service/display/overlay_ca_unittest.cc84
-rw-r--r--chromium/components/viz/service/display/overlay_candidate.cc102
-rw-r--r--chromium/components/viz/service/display/overlay_candidate.h9
-rw-r--r--chromium/components/viz/service/display/overlay_processor_android.cc3
-rw-r--r--chromium/components/viz/service/display/overlay_processor_android.h2
-rw-r--r--chromium/components/viz/service/display/overlay_processor_delegated.cc76
-rw-r--r--chromium/components/viz/service/display/overlay_processor_interface.cc22
-rw-r--r--chromium/components/viz/service/display/overlay_processor_interface.h24
-rw-r--r--chromium/components/viz/service/display/overlay_processor_mac.cc15
-rw-r--r--chromium/components/viz/service/display/overlay_processor_mac.h5
-rw-r--r--chromium/components/viz/service/display/overlay_processor_on_gpu.cc26
-rw-r--r--chromium/components/viz/service/display/overlay_processor_on_gpu.h10
-rw-r--r--chromium/components/viz/service/display/overlay_processor_ozone.cc24
-rw-r--r--chromium/components/viz/service/display/overlay_processor_ozone.h3
-rw-r--r--chromium/components/viz/service/display/overlay_processor_ozone_unittest.cc2
-rw-r--r--chromium/components/viz/service/display/overlay_processor_strategy.cc26
-rw-r--r--chromium/components/viz/service/display/overlay_processor_strategy.h102
-rw-r--r--chromium/components/viz/service/display/overlay_processor_stub.cc4
-rw-r--r--chromium/components/viz/service/display/overlay_processor_stub.h1
-rw-r--r--chromium/components/viz/service/display/overlay_processor_surface_control.cc2
-rw-r--r--chromium/components/viz/service/display/overlay_processor_surface_control.h2
-rw-r--r--chromium/components/viz/service/display/overlay_processor_using_strategy.cc482
-rw-r--r--chromium/components/viz/service/display/overlay_processor_using_strategy.h215
-rw-r--r--chromium/components/viz/service/display/overlay_proposed_candidate.h40
-rw-r--r--chromium/components/viz/service/display/overlay_strategy_fullscreen.cc6
-rw-r--r--chromium/components/viz/service/display/overlay_strategy_fullscreen.h5
-rw-r--r--chromium/components/viz/service/display/overlay_strategy_single_on_top.cc4
-rw-r--r--chromium/components/viz/service/display/overlay_strategy_single_on_top.h5
-rw-r--r--chromium/components/viz/service/display/overlay_strategy_underlay.cc2
-rw-r--r--chromium/components/viz/service/display/overlay_strategy_underlay.h5
-rw-r--r--chromium/components/viz/service/display/overlay_strategy_underlay_cast.cc2
-rw-r--r--chromium/components/viz/service/display/overlay_strategy_underlay_cast.h2
-rw-r--r--chromium/components/viz/service/display/overlay_unittest.cc1104
-rw-r--r--chromium/components/viz/service/display/program_binding.h2
-rw-r--r--chromium/components/viz/service/display/renderer_perftest.cc2
-rw-r--r--chromium/components/viz/service/display/renderer_pixeltest.cc27
-rw-r--r--chromium/components/viz/service/display/resolved_frame_data.cc4
-rw-r--r--chromium/components/viz/service/display/resolved_frame_data.h10
-rw-r--r--chromium/components/viz/service/display/scoped_gpu_memory_buffer_texture.cc6
-rw-r--r--chromium/components/viz/service/display/scoped_render_pass_texture.cc9
-rw-r--r--chromium/components/viz/service/display/shader.cc2
-rw-r--r--chromium/components/viz/service/display/skia_output_surface.h14
-rw-r--r--chromium/components/viz/service/display/skia_readback_pixeltest.cc4
-rw-r--r--chromium/components/viz/service/display/skia_renderer.cc158
-rw-r--r--chromium/components/viz/service/display/skia_renderer.h12
-rw-r--r--chromium/components/viz/service/display/software_renderer.cc3
-rw-r--r--chromium/components/viz/service/display/surface_aggregator.cc450
-rw-r--r--chromium/components/viz/service/display/surface_aggregator.h126
-rw-r--r--chromium/components/viz/service/display/surface_aggregator_pixeltest.cc4
-rw-r--r--chromium/components/viz/service/display/surface_aggregator_unittest.cc98
-rw-r--r--chromium/components/viz/service/display_embedder/DEPS2
-rw-r--r--chromium/components/viz/service/display_embedder/buffer_queue.cc2
-rw-r--r--chromium/components/viz/service/display_embedder/buffer_queue_unittest.cc2
-rw-r--r--chromium/components/viz/service/display_embedder/compositor_gpu_thread.cc89
-rw-r--r--chromium/components/viz/service/display_embedder/compositor_gpu_thread.h4
-rw-r--r--chromium/components/viz/service/display_embedder/gl_output_surface_buffer_queue.cc2
-rw-r--r--chromium/components/viz/service/display_embedder/gl_output_surface_buffer_queue_unittest.cc50
-rw-r--r--chromium/components/viz/service/display_embedder/image_context_impl.cc11
-rw-r--r--chromium/components/viz/service/display_embedder/image_context_impl.h4
-rw-r--r--chromium/components/viz/service/display_embedder/output_presenter.cc3
-rw-r--r--chromium/components/viz/service/display_embedder/output_presenter.h6
-rw-r--r--chromium/components/viz/service/display_embedder/output_presenter_fuchsia.cc8
-rw-r--r--chromium/components/viz/service/display_embedder/output_presenter_gl.cc75
-rw-r--r--chromium/components/viz/service/display_embedder/output_presenter_gl.h13
-rw-r--r--chromium/components/viz/service/display_embedder/output_surface_provider_impl.cc33
-rw-r--r--chromium/components/viz/service/display_embedder/output_surface_provider_impl.h8
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_device_buffer_queue.cc184
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_device_buffer_queue.h16
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_device_dawn.cc4
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_device_dawn.h6
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_device_gl.cc10
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_device_vulkan.cc11
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_device_vulkan.h2
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_device_vulkan_secondary_cb_offscreen.cc87
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_device_vulkan_secondary_cb_offscreen.h36
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_surface_dependency.h2
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_surface_dependency_impl.cc4
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_surface_dependency_impl.h2
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_surface_impl.cc71
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_surface_impl.h12
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc115
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h6
-rw-r--r--chromium/components/viz/service/display_embedder/software_output_surface.cc4
-rw-r--r--chromium/components/viz/service/display_embedder/software_output_surface.h4
-rw-r--r--chromium/components/viz/service/display_embedder/viz_process_context_provider.cc6
-rw-r--r--chromium/components/viz/service/frame_sinks/DEPS4
-rw-r--r--chromium/components/viz/service/frame_sinks/compositor_frame_sink_impl.cc2
-rw-r--r--chromium/components/viz/service/frame_sinks/compositor_frame_sink_impl.h2
-rw-r--r--chromium/components/viz/service/frame_sinks/compositor_frame_sink_support.cc110
-rw-r--r--chromium/components/viz/service/frame_sinks/compositor_frame_sink_support.h27
-rw-r--r--chromium/components/viz/service/frame_sinks/compositor_frame_sink_support_unittest.cc9
-rw-r--r--chromium/components/viz/service/frame_sinks/external_begin_frame_source_android.cc240
-rw-r--r--chromium/components/viz/service/frame_sinks/external_begin_frame_source_android.h10
-rw-r--r--chromium/components/viz/service/frame_sinks/external_begin_frame_source_android_unittest.cc13
-rw-r--r--chromium/components/viz/service/frame_sinks/external_begin_frame_source_mojo.cc31
-rw-r--r--chromium/components/viz/service/frame_sinks/external_begin_frame_source_mojo.h3
-rw-r--r--chromium/components/viz/service/frame_sinks/frame_sink_bundle_impl.cc68
-rw-r--r--chromium/components/viz/service/frame_sinks/frame_sink_bundle_impl.h7
-rw-r--r--chromium/components/viz/service/frame_sinks/frame_sink_bundle_impl_unittest.cc19
-rw-r--r--chromium/components/viz/service/frame_sinks/frame_sink_manager_impl.cc55
-rw-r--r--chromium/components/viz/service/frame_sinks/frame_sink_manager_impl.h14
-rw-r--r--chromium/components/viz/service/frame_sinks/frame_sink_manager_unittest.cc2
-rw-r--r--chromium/components/viz/service/frame_sinks/gmb_video_frame_pool_context_provider.h35
-rw-r--r--chromium/components/viz/service/frame_sinks/gmb_video_frame_pool_context_provider_impl.cc178
-rw-r--r--chromium/components/viz/service/frame_sinks/gmb_video_frame_pool_context_provider_impl.h43
-rw-r--r--chromium/components/viz/service/frame_sinks/gpu_vsync_begin_frame_source.cc1
-rw-r--r--chromium/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc93
-rw-r--r--chromium/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.h23
-rw-r--r--chromium/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc284
-rw-r--r--chromium/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.h67
-rw-r--r--chromium/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl_unittest.cc262
-rw-r--r--chromium/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_manager.h6
-rw-r--r--chromium/components/viz/service/frame_sinks/video_capture/gpu_memory_buffer_video_frame_pool.cc91
-rw-r--r--chromium/components/viz/service/frame_sinks/video_capture/gpu_memory_buffer_video_frame_pool.h75
-rw-r--r--chromium/components/viz/service/frame_sinks/video_capture/video_capture_overlay.cc111
-rw-r--r--chromium/components/viz/service/frame_sinks/video_capture/video_capture_overlay.h20
-rw-r--r--chromium/components/viz/service/frame_sinks/video_capture/video_capture_overlay_unittest.cc157
-rw-r--r--chromium/components/viz/service/frame_sinks/video_capture/video_frame_pool.cc5
-rw-r--r--chromium/components/viz/service/frame_sinks/video_detector.cc13
-rw-r--r--chromium/components/viz/service/frame_sinks/video_detector_unittest.cc87
-rw-r--r--chromium/components/viz/service/gl/gpu_service_impl.cc71
-rw-r--r--chromium/components/viz/service/gl/gpu_service_impl.h20
-rw-r--r--chromium/components/viz/service/gl/gpu_service_impl_unittest.cc6
-rw-r--r--chromium/components/viz/service/hit_test/hit_test_aggregator.cc85
-rw-r--r--chromium/components/viz/service/hit_test/hit_test_aggregator.h12
-rw-r--r--chromium/components/viz/service/hit_test/hit_test_manager.cc34
-rw-r--r--chromium/components/viz/service/hit_test/hit_test_manager.h25
-rw-r--r--chromium/components/viz/service/java/src/org/chromium/components/viz/service/frame_sinks/ExternalBeginFrameSourceAndroid.java95
-rw-r--r--chromium/components/viz/service/main/viz_compositor_thread_runner.h1
-rw-r--r--chromium/components/viz/service/main/viz_compositor_thread_runner_impl.cc26
-rw-r--r--chromium/components/viz/service/main/viz_compositor_thread_runner_impl.h11
-rw-r--r--chromium/components/viz/service/main/viz_main_impl.cc4
-rw-r--r--chromium/components/viz/service/main/viz_main_impl.h10
-rw-r--r--chromium/components/viz/service/performance_hint/hint_session.cc7
-rw-r--r--chromium/components/viz/service/performance_hint/utils.cc4
-rw-r--r--chromium/components/viz/service/surfaces/referenced_surface_tracker.cc34
-rw-r--r--chromium/components/viz/service/surfaces/surface.cc67
-rw-r--r--chromium/components/viz/service/surfaces/surface.h5
-rw-r--r--chromium/components/viz/service/surfaces/surface_saved_frame.cc45
-rw-r--r--chromium/components/viz/service/surfaces/surface_saved_frame.h12
-rw-r--r--chromium/components/viz/service/surfaces/surface_saved_frame_storage.cc6
-rw-r--r--chromium/components/viz/service/surfaces/surface_saved_frame_storage.h10
-rw-r--r--chromium/components/viz/service/surfaces/surface_saved_frame_unittest.cc10
-rw-r--r--chromium/components/viz/service/surfaces/surface_unittest.cc129
-rw-r--r--chromium/components/viz/service/transitions/surface_animation_manager.cc70
-rw-r--r--chromium/components/viz/service/transitions/surface_animation_manager.h22
-rw-r--r--chromium/components/viz/service/transitions/surface_animation_manager_unittest.cc56
-rw-r--r--chromium/components/viz/viz.gni3
-rw-r--r--chromium/components/web_app_resources/OWNERS1
-rw-r--r--chromium/components/web_app_resources/web_app_default_offline.css31
-rw-r--r--chromium/components/web_app_resources/web_app_default_offline.html24
-rw-r--r--chromium/components/web_cache/browser/web_cache_manager.cc1
-rw-r--r--chromium/components/web_modal/web_contents_modal_dialog_manager_unittest.cc2
-rw-r--r--chromium/components/web_resource/eula_accepted_notifier.cc2
-rw-r--r--chromium/components/webapk/webapk.proto2
-rw-r--r--chromium/components/webapps/browser/BUILD.gn14
-rw-r--r--chromium/components/webapps/browser/android/add_to_homescreen_data_fetcher.h2
-rw-r--r--chromium/components/webapps/browser/android/add_to_homescreen_data_fetcher_unittest.cc20
-rw-r--r--chromium/components/webapps/browser/android/app_banner_manager_android.cc30
-rw-r--r--chromium/components/webapps/browser/android/app_banner_manager_android.h15
-rw-r--r--chromium/components/webapps/browser/android/translations/android_webapps_strings_de.xtb2
-rw-r--r--chromium/components/webapps/browser/android/translations/android_webapps_strings_eu.xtb2
-rw-r--r--chromium/components/webapps/browser/android/webapk/webapk_proto_builder.cc39
-rw-r--r--chromium/components/webapps/browser/android/webapk/webapk_proto_builder.h9
-rw-r--r--chromium/components/webapps/browser/banners/app_banner_manager.cc32
-rw-r--r--chromium/components/webapps/browser/banners/app_banner_settings_helper.cc15
-rw-r--r--chromium/components/webapps/browser/install_result_code.cc83
-rw-r--r--chromium/components/webapps/browser/install_result_code.h96
-rw-r--r--chromium/components/webapps/browser/install_result_code_unittest.cc19
-rw-r--r--chromium/components/webapps/browser/installable/installable_manager.cc14
-rw-r--r--chromium/components/webapps/browser/installable/installable_manager_unittest.cc4
-rw-r--r--chromium/components/webapps/browser/webapps_client.h2
-rw-r--r--chromium/components/webapps/services/web_app_origin_association/public/mojom/web_app_origin_association_parser.mojom2
-rw-r--r--chromium/components/webapps/services/web_app_origin_association/web_app_origin_association_parser.cc4
-rw-r--r--chromium/components/webapps/services/web_app_origin_association/web_app_origin_association_parser.h2
-rw-r--r--chromium/components/webauthn/android/BUILD.gn10
-rw-r--r--chromium/components/webauthn/android/fido2api_native_android.cc (renamed from chromium/components/webauthn/android/fido2helper_native_android.cc)6
-rw-r--r--chromium/components/webauthn/android/internal_authenticator_android.cc12
-rw-r--r--chromium/components/webcrypto/algorithms/aes_cbc_unittest.cc12
-rw-r--r--chromium/components/webcrypto/algorithms/aes_ctr_unittest.cc8
-rw-r--r--chromium/components/webcrypto/algorithms/aes_gcm_unittest.cc8
-rw-r--r--chromium/components/webcrypto/algorithms/aes_kw_unittest.cc32
-rw-r--r--chromium/components/webcrypto/algorithms/ecdh_unittest.cc22
-rw-r--r--chromium/components/webcrypto/algorithms/ecdsa_unittest.cc40
-rw-r--r--chromium/components/webcrypto/algorithms/hmac_unittest.cc8
-rw-r--r--chromium/components/webcrypto/algorithms/rsa_oaep_unittest.cc8
-rw-r--r--chromium/components/webcrypto/algorithms/rsa_pss_unittest.cc17
-rw-r--r--chromium/components/webcrypto/algorithms/rsa_ssa_unittest.cc32
-rw-r--r--chromium/components/webcrypto/algorithms/sha_unittest.cc8
-rw-r--r--chromium/components/webcrypto/algorithms/test_helpers.cc41
-rw-r--r--chromium/components/webcrypto/algorithms/test_helpers.h19
-rw-r--r--chromium/components/webcrypto/jwk.cc2
-rw-r--r--chromium/components/webdata/common/BUILD.gn2
-rw-r--r--chromium/components/webdata/common/web_data_results.h4
-rw-r--r--chromium/components/webdata/common/web_database.cc4
-rw-r--r--chromium/components/webdata/common/web_database_migration_unittest.cc94
-rw-r--r--chromium/components/webdata/common/webdata_constants.cc6
-rw-r--r--chromium/components/webdata/common/webdata_constants.h4
-rw-r--r--chromium/components/webdata_services/web_data_service_wrapper.cc23
-rw-r--r--chromium/components/webdata_services/web_data_service_wrapper.h6
-rw-r--r--chromium/components/webrtc/BUILD.gn98
-rw-r--r--chromium/components/webrtc/DEPS3
-rw-r--r--chromium/components/webrtc/fake_ssl_client_socket.cc378
-rw-r--r--chromium/components/webrtc/fake_ssl_client_socket.h125
-rw-r--r--chromium/components/webrtc/fake_ssl_client_socket_unittest.cc359
-rw-r--r--chromium/components/webrtc/media_stream_devices_controller.cc16
-rw-r--r--chromium/components/webrtc/media_stream_devices_controller.h4
-rw-r--r--chromium/components/webrtc/net_address_utils.cc118
-rw-r--r--chromium/components/webrtc/net_address_utils.h46
-rw-r--r--chromium/components/webrtc/thread_wrapper.cc493
-rw-r--r--chromium/components/webrtc/thread_wrapper.h204
-rw-r--r--chromium/components/webrtc/thread_wrapper_unittest.cc347
-rw-r--r--chromium/components/webrtc_logging/BUILD.gn16
-rw-r--r--chromium/components/webrtc_logging/DEPS5
-rw-r--r--chromium/components/webrtc_logging/logging_unittest.cc155
-rw-r--r--chromium/components/webxr/OWNERS5
-rw-r--r--chromium/components/webxr/README.md21
-rw-r--r--chromium/components/webxr/android/BUILD.gn6
-rw-r--r--chromium/components/webxr/android/DEPS2
-rw-r--r--chromium/components/webxr/android/arcore_device_provider.cc17
-rw-r--r--chromium/components/webxr/android/arcore_device_provider.h11
-rw-r--r--chromium/components/webxr/android/arcore_install_helper.cc90
-rw-r--r--chromium/components/webxr/android/arcore_install_helper.h15
-rw-r--r--chromium/components/webxr/android/xr_install_helper_delegate.h42
-rw-r--r--chromium/components/webxr/android/xr_install_infobar.cc65
-rw-r--r--chromium/components/webxr/android/xr_install_infobar.h58
-rw-r--r--chromium/components/webxr_strings.grdp13
-rw-r--r--chromium/components/webxr_strings_grdp/IDS_AR_CORE_CHECK_INFOBAR_INSTALL_TEXT.png.sha11
-rw-r--r--chromium/components/webxr_strings_grdp/IDS_AR_CORE_CHECK_INFOBAR_UPDATE_TEXT.png.sha11
-rw-r--r--chromium/components/webxr_strings_grdp/IDS_AR_CORE_CHECK_MESSAGE_DESCRIPTION.png.sha11
-rw-r--r--chromium/components/webxr_strings_grdp/IDS_AR_CORE_CHECK_MESSAGE_INSTALL_TITLE.png.sha11
-rw-r--r--chromium/components/webxr_strings_grdp/IDS_AR_CORE_CHECK_MESSAGE_UPDATE_TITLE.png.sha11
-rw-r--r--chromium/components/wifi/network_properties.cc2
-rw-r--r--chromium/components/wifi/wifi_service.h1
-rw-r--r--chromium/components/wifi/wifi_service_win.cc1
-rw-r--r--chromium/components/wifi/wifi_test.cc8
-rw-r--r--chromium/components/winhttp/network_fetcher.cc7
-rw-r--r--chromium/components/winhttp/network_fetcher.h3
-rw-r--r--chromium/components/winhttp/network_fetcher_unittest.cc12
-rw-r--r--chromium/components/zucchini/abs32_utils.cc10
-rw-r--r--chromium/components/zucchini/abs32_utils.h12
-rw-r--r--chromium/components/zucchini/abs32_utils_unittest.cc28
-rw-r--r--chromium/components/zucchini/disassembler_elf.h2
-rw-r--r--chromium/components/zucchini/disassembler_win32.h2
-rw-r--r--chromium/components/zucchini/image_index_unittest.cc36
-rw-r--r--chromium/components/zucchini/main_utils.cc22
-rw-r--r--chromium/components/zucchini/mapped_file.cc8
-rw-r--r--chromium/components/zucchini/rel32_finder.cc2
-rw-r--r--chromium/components/zucchini/rel32_finder.h8
-rw-r--r--chromium/components/zucchini/rel32_finder_unittest.cc25
-rw-r--r--chromium/components/zucchini/suffix_array.h7
-rw-r--r--chromium/components/zucchini/zucchini_main.cc8
4018 files changed, 118490 insertions, 61606 deletions
diff --git a/chromium/components/BUILD.gn b/chromium/components/BUILD.gn
index b24bdc8e562..d44063abd18 100644
--- a/chromium/components/BUILD.gn
+++ b/chromium/components/BUILD.gn
@@ -41,6 +41,34 @@ if (is_ios) {
}
}
+# Omit Lacros because it allows //components to depend on //chrome, which in
+# turn depends on //extensions.
+if (!is_chromeos_lacros) {
+ disallowed_extension_deps_ = [
+ # Components should largely not depend on //extensions. Since // extensions
+ # is not a component target and is linked with //chrome, depending on most
+ # //extensions targets will result in duplicate code. See
+ # //docs/component_build.md#dependencies-between-targets and
+ # https://bugs.chromium.org/p/chromium/issues/detail?id=1215550#c6 for an
+ # example of this going awry.
+ # However, there are two //extensions targets we allow:
+ # //extensions/buildflags (needed to see if extensions are enabled) and
+ # //extensions/common:common_constants (which *is* a component target, and
+ # is needed by a number of components).
+ # Since there's no way to say "no //extensions targets _except_", we
+ # instead list ~all the other targets here.
+ "//extensions/browser/*",
+ "//extensions/common",
+ "//extensions/common:mojom",
+ "//extensions/common:core_api_provider",
+ "//extensions/common/api/*",
+ "//extensions/renderer/*",
+ "//extensions/shell/*",
+ "//extensions/components/*",
+ "//extensions/strings/*",
+ ]
+}
+
# To add a unit test to this target, make a "unit_tests" source_set in your
# component(it's important to use a source_set instead of a static library or
# no tests will run) and add a reference here.You can add more than one unit
@@ -53,6 +81,7 @@ test("components_unittests") {
}
if (is_fuchsia) {
+ use_cfv2 = false
additional_manifest_fragments = [
"//build/config/fuchsia/test/font_capabilities.test-cmx",
@@ -236,6 +265,7 @@ test("components_unittests") {
deps += [
"//components/autofill/ios/browser:unit_tests",
"//components/autofill/ios/form_util:unit_tests",
+ "//components/crash/core/app:unit_tests",
"//components/feed/core/v2/public/ios:feed_ios_unit_tests",
"//components/image_fetcher/ios:unit_tests",
"//components/language/ios/browser:unit_tests",
@@ -244,6 +274,7 @@ test("components_unittests") {
"//components/previous_session_info:unit_tests",
"//components/safe_browsing/ios/browser:unit_tests",
"//components/security_state/ios:unit_tests",
+ "//components/shared_highlighting/ios:unit_tests",
"//components/signin/ios/browser:unit_tests",
"//components/signin/public/identity_manager/objc:unit_tests",
"//components/translate/ios/browser:unit_tests",
@@ -267,7 +298,7 @@ test("components_unittests") {
"//components/contextual_search/core:unit_tests",
"//components/continuous_search/browser:unit_tests",
"//components/continuous_search/common:unit_tests",
- "//components/data_use_measurement/core:unit_tests",
+ "//components/custom_handlers:unit_tests",
"//components/digital_asset_links:unit_tests",
"//components/discardable_memory/client:unit_tests",
"//components/discardable_memory/common:unit_tests",
@@ -278,7 +309,6 @@ test("components_unittests") {
"//components/embedder_support:unit_tests",
"//components/enterprise/content:unit_tests",
"//components/favicon/content:unit_tests",
- "//components/federated_learning:unit_tests",
"//components/feed:unit_tests",
"//components/gcm_driver/instance_id:unit_tests",
"//components/heavy_ad_intervention:unit_tests",
@@ -315,6 +345,7 @@ test("components_unittests") {
"//components/permissions:unit_tests",
"//components/permissions/prediction_service:unit_tests",
"//components/policy/content:unit_tests",
+ "//components/privacy_sandbox:unit_tests",
"//components/query_tiles:unit_tests",
# TODO(chromium: 1169835) components / reporting / storage / resources: unit_tests
@@ -352,6 +383,8 @@ test("components_unittests") {
"//components/webapps/browser:unit_tests",
"//components/webapps/services/web_app_origin_association:unit_tests",
"//components/webcrypto:unit_tests",
+ "//components/webrtc:unit_tests",
+ "//components/webrtc_logging:unit_tests",
"//components/webrtc_logging/browser:unit_tests",
"//components/webrtc_logging/common:unit_tests",
]
@@ -367,8 +400,6 @@ test("components_unittests") {
deps += [
"//components/crash/content/browser:unit_tests",
"//components/crash/core/app:unit_tests",
- "//components/data_reduction_proxy/core/browser:unit_tests",
- "//components/data_reduction_proxy/core/common:unit_tests",
]
}
@@ -392,6 +423,7 @@ test("components_unittests") {
"//base:base_java_unittest_support",
"//components/android_autofill/browser:unit_tests",
"//components/autofill_assistant/browser:unit_tests",
+ "//components/autofill_assistant/content/renderer:unit_tests",
"//components/browser_ui/sms/android:unit_tests",
"//components/cdm/browser:unit_tests",
"//components/component_updater/android:embedded_component_loader_java",
@@ -435,8 +467,7 @@ test("components_unittests") {
]
if (use_v8_context_snapshot) {
deps += [ "//tools/v8_context_snapshot:v8_context_snapshot_assets" ]
- }
- if (!use_v8_context_snapshot || include_both_v8_snapshots) {
+ } else {
deps += [ "//v8:v8_external_startup_data_assets" ]
}
@@ -474,10 +505,6 @@ test("components_unittests") {
if (is_chromeos_ash) {
deps += [
- # TODO(b/206686476): Move this target to //ash/components:unit_tests
- "//ash/components/arc:unit_tests",
- "//ash/components/arc/mojom:unit_tests",
- "//ash/components/arc/session:unit_tests",
"//components/arc:unit_tests",
"//components/desks_storage:unit_tests",
"//components/guest_os:unit_tests",
@@ -531,6 +558,10 @@ test("components_unittests") {
]
}
+ if (safe_browsing_mode != 0 && !is_ios && !is_fuchsia) {
+ deps += [ "//components/safe_browsing/content/common:file_type_policies_policy_util_unittest" ]
+ }
+
if (safe_browsing_mode == 1) {
deps += [
"//components/safe_browsing/content/renderer:websocket_sb_handshake_throttle_unittest",
@@ -572,8 +603,11 @@ test("components_unittests") {
# On LaCrOS, tests use ash - chrome as a window manager, thus the dependency.
# On other platforms, no components should depend on Chrome.
+ # Since //chrome depends on //extensions, we also only assert_no_deps on
+ # extensions targets for non-lacros builds.
if (!is_chromeos_lacros) {
assert_no_deps = [ "//chrome/*" ]
+ assert_no_deps += disallowed_extension_deps_
}
if (is_ios) {
@@ -625,8 +659,7 @@ if (is_android) {
]
if (use_v8_context_snapshot) {
deps += [ "//tools/v8_context_snapshot:v8_context_snapshot_assets" ]
- }
- if (!use_v8_context_snapshot || include_both_v8_snapshots) {
+ } else {
deps += [ "//v8:v8_external_startup_data_assets" ]
}
}
@@ -718,6 +751,7 @@ if (!is_ios) {
"//components/autofill/content/renderer:test_support",
"//components/autofill/core/browser",
"//components/browsing_data/content",
+ "//components/content_capture/browser:browser_tests",
"//components/content_settings/core/common",
"//components/content_settings/renderer",
"//components/continuous_search/common/public/mojom",
@@ -783,20 +817,26 @@ if (!is_ios) {
if (is_android) {
sources += [
- "autofill_assistant/browser/js_flow_executor_unittest.cc",
+ "autofill_assistant/browser/base_browsertest.cc",
+ "autofill_assistant/browser/base_browsertest.h",
+ "autofill_assistant/browser/fake_script_executor_ui_delegate.cc",
+ "autofill_assistant/browser/fake_script_executor_ui_delegate.h",
+ "autofill_assistant/browser/js_flow_executor_impl_browsertest.cc",
"autofill_assistant/browser/mock_script_executor_delegate.cc",
"autofill_assistant/browser/mock_script_executor_delegate.h",
+ "autofill_assistant/browser/web/batch_element_checker_browsertest.cc",
"autofill_assistant/browser/web/web_controller_browsertest.cc",
- "autofill_assistant/content/renderer/autofill_assistant_agent_browsertest.cc",
"browser_ui/client_certificate/android/ssl_client_certificate_request_browsertest.cc",
"test/android/browsertests_apk/components_browser_tests_jni_onload.cc",
]
- sources -= [ "autofill/content/browser/risk/fingerprint_browsertest.cc" ]
deps += [
"//components/autofill_assistant/browser",
"//components/autofill_assistant/browser:proto",
+ "//components/autofill_assistant/browser/devtools:devtools",
+ "//components/autofill_assistant/browser/devtools:gen_devtools_client_api",
+ "//components/autofill_assistant/content/common",
"//components/autofill_assistant/content/common:mojo_interfaces",
- "//components/autofill_assistant/content/renderer",
+ "//components/autofill_assistant/content/renderer:browser_tests",
"//components/browser_ui/client_certificate/android",
"//components/browser_ui/client_certificate/android:java",
"//components/download/internal/common:internal_java",
@@ -834,10 +874,39 @@ if (!is_ios) {
]
}
- # On LaCrOS, tests use ash - chrome as a window manager, thus the dependency.
- # On other platforms, no components should depend on Chrome.
+ # On LaCrOS, tests use ash - chrome as a window manager, thus the
+ # dependency. On other platforms, no components should depend on Chrome.
+ # Since //chrome depends on //extensions, we also only assert_no_deps on
+ # extensions targets for non-lacros builds.
if (!is_chromeos_lacros) {
assert_no_deps = [ "//chrome/*" ]
+ assert_no_deps += disallowed_extension_deps_
+ }
+
+ if (is_fuchsia) {
+ use_cfv2 = false
+ additional_manifest_fragments = [
+ "//build/config/fuchsia/test/font_capabilities.test-cmx",
+ "//build/config/fuchsia/test/jit_capabilities.test-cmx",
+ "//build/config/fuchsia/test/network_capabilities.test-cmx",
+ "//build/config/fuchsia/test/present_view_capabilities.test-cmx",
+ ]
+ }
+
+ # This test won't work as-is on POSIX platforms, where fork()+exec() is
+ # used to launch child processes, failure does not happen until exec().
+ # See also ServiceProcessLauncherTest.FailToLaunchProcess and
+ # UtilityProcessHostBrowserTest.FailToLaunchProcess.
+ if (!is_posix || is_mac) {
+ sources += [
+ "metrics/content/content_stability_metrics_provider_browsertest.cc",
+ ]
+ deps += [
+ "//components/prefs:test_support",
+ "//components/variations",
+ "//content/test:content_test_mojo_bindings",
+ "//sandbox",
+ ]
}
}
@@ -886,8 +955,7 @@ if (!is_ios) {
deps += [ "//ui/android:ui_java" ]
if (use_v8_context_snapshot) {
deps += [ "//tools/v8_context_snapshot:v8_context_snapshot_assets" ]
- }
- if (!use_v8_context_snapshot || include_both_v8_snapshots) {
+ } else {
deps += [ "//v8:v8_external_startup_data_assets" ]
}
}
@@ -916,6 +984,7 @@ if (is_android) {
"//components/browser_ui/webshare/android:junit",
"//components/browser_ui/widget/android:junit",
"//components/content_capture/android/junit:components_content_capture_junit_tests",
+ "//components/crash/android:junit",
"//components/embedder_support/android:components_embedder_support_junit_tests",
"//components/gcm_driver/android:components_gcm_driver_junit_tests",
"//components/image_fetcher:junit",
diff --git a/chromium/components/about_ui/resources/about_credits.css b/chromium/components/about_ui/resources/about_credits.css
new file mode 100644
index 00000000000..30e23d0adf4
--- /dev/null
+++ b/chromium/components/about_ui/resources/about_credits.css
@@ -0,0 +1,129 @@
+/* Copyright 2022 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. */
+
+html {
+ --google-blue-50: rgb(232, 240, 254);
+ --google-blue-300: rgb(138, 180, 248);
+ --google-blue-600: rgb(26, 115, 232);
+ --google-blue-900: rgb(23, 78, 166);
+ --google-grey-200: rgb(232, 234, 237);
+ --google-grey-800: rgb(60, 64, 67);
+ --google-grey-900: rgb(32, 33, 36);
+
+ --interactive-color: var(--google-blue-600);
+ --primary-color: var(--google-grey-900);
+
+ --product-background: var(--google-blue-50);
+ --product-text-color: var(--google-blue-900);
+
+ background: white;
+}
+
+@media (prefers-color-scheme: dark) {
+ html {
+ --interactive-color: var(--google-blue-300);
+ --primary-color: var(--google-grey-200);
+
+ --product-background: var(--google-grey-800);
+ --product-text-color: var(--google-grey-200);
+
+ background: var(--google-grey-900);
+ }
+}
+
+body {
+ color: var(--primary-color);
+ font-size: 84%;
+ max-width: 1020px;
+}
+a {
+ color: var(--interactive-color);
+}
+.page-title {
+ font-size: 164%;
+ font-weight: bold;
+}
+.product {
+ background-color: var(--product-background);
+ border-radius: 5px;
+ color: var(--product-text-color);
+ margin-top: 16px;
+ overflow: auto;
+ padding: 2px;
+}
+.product .title {
+ float: left;
+ font-size: 110%;
+ font-weight: bold;
+ margin: 3px;
+}
+.product .homepage {
+ color: var(--interactive-color);
+ float: right;
+ margin: 3px;
+ text-align: end;
+}
+.product .homepage::before {
+ content: ' - ';
+}
+.product .show {
+ color: var(--interactive-color);
+ float: right;
+ margin: 3px;
+ text-align: end;
+ text-decoration: underline;
+}
+.licence {
+ border-radius: 3px;
+ clear: both;
+ display: none;
+ padding: 16px;
+}
+.licence h3 {
+ margin-top: 0;
+}
+.licence pre {
+ white-space: pre-wrap;
+}
+.dialog #print-link,
+.dialog .homepage {
+ display: none;
+}
+input + label + div {
+ display: none;
+}
+input + label::after {
+ content: 'show license';
+ cursor: pointer;
+}
+input:checked + label + div {
+ display: block;
+}
+input:checked + label::after {
+ content: 'hide license';
+ cursor: pointer;
+}
+
+/* Strip out color and style when printing. We want dense B&W text. */
+@media print {
+ .licence {
+ display: block;
+ }
+ .product,
+ a,
+ body {
+ color: black;
+ }
+ .product {
+ background-color: white;
+ }
+ a {
+ text-decoration: none;
+ }
+ .show,
+ .product .homepage::before,
+ #print-link {
+ display: none;
+ }
+}
diff --git a/chromium/components/about_ui/resources/about_credits.tmpl b/chromium/components/about_ui/resources/about_credits.tmpl
index a03ba3ed71e..6eb23ada835 100644
--- a/chromium/components/about_ui/resources/about_credits.tmpl
+++ b/chromium/components/about_ui/resources/about_credits.tmpl
@@ -6,110 +6,7 @@
<meta name="color-scheme" content="light dark">
<title>Credits</title>
<link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
-<style>
-html {
- --google-blue-50: rgb(232, 240, 254);
- --google-blue-300: rgb(138, 180, 248);
- --google-blue-600: rgb(26, 115, 232);
- --google-blue-900: rgb(23, 78, 166);
- --google-grey-200: rgb(232, 234, 237);
- --google-grey-800: rgb(60, 64, 67);
- --google-grey-900: rgb(32, 33, 36);
-
- --interactive-color: var(--google-blue-600);
- --primary-color: var(--google-grey-900);
-
- --product-background: var(--google-blue-50);
- --product-text-color: var(--google-blue-900);
-
- background: white;
-}
-
-@media (prefers-color-scheme: dark) {
- html {
- --interactive-color: var(--google-blue-300);
- --primary-color: var(--google-grey-200);
-
- --product-background: var(--google-grey-800);
- --product-text-color: var(--google-grey-200);
-
- background: var(--google-grey-900);
- }
-}
-
-body {
- color: var(--primary-color);
- font-size: 84%;
- max-width: 1020px;
-}
-a {
- color: var(--interactive-color);
-}
-.page-title {
- font-size: 164%;
- font-weight: bold;
-}
-.product {
- background-color: var(--product-background);
- color: var(--product-text-color);
- border-radius: 5px;
- margin-top: 16px;
- overflow: auto;
- padding: 2px;
-}
-.product .title {
- float: left;
- font-size: 110%;
- font-weight: bold;
- margin: 3px;
-}
-.product .homepage {
- color: var(--interactive-color);
- float: right;
- margin: 3px;
- text-align: right;
-}
-.product .homepage::before {
- content: " - ";
-}
-.product .show {
- color: var(--interactive-color);
- float: right;
- margin: 3px;
- text-align: right;
- text-decoration: underline;
-}
-.licence {
- border-radius: 3px;
- clear: both;
- display: none;
- padding: 16px;
-}
-.licence h3 {
- margin-top: 0;
-}
-.licence pre {
- white-space: pre-wrap;
-}
-.dialog #print-link,
-.dialog .homepage {
- display: none;
-}
-input + label + div {
- display: none;
-}
-input + label::after {
- content: "show license";
- cursor: pointer;
-}
-input:checked + label + div {
- display: block;
-}
-input:checked + label::after {
- content: "hide license";
- cursor: pointer;
-}
-</style>
+<link rel="stylesheet" href="chrome://credits/credits.css">
</head>
<body>
<span class="page-title" style="float:left;">Credits</span>
diff --git a/chromium/components/account_manager_core/BUILD.gn b/chromium/components/account_manager_core/BUILD.gn
index dc11587339d..c342842955f 100644
--- a/chromium/components/account_manager_core/BUILD.gn
+++ b/chromium/components/account_manager_core/BUILD.gn
@@ -12,6 +12,7 @@ component("account_manager_core") {
sources = [
"account.cc",
"account.h",
+ "account_addition_options.h",
"account_addition_result.cc",
"account_addition_result.h",
"account_manager_facade.cc",
diff --git a/chromium/components/account_manager_core/account_addition_options.h b/chromium/components/account_manager_core/account_addition_options.h
new file mode 100644
index 00000000000..2d18d8552c4
--- /dev/null
+++ b/chromium/components/account_manager_core/account_addition_options.h
@@ -0,0 +1,24 @@
+// Copyright 2021 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.
+
+#ifndef COMPONENTS_ACCOUNT_MANAGER_CORE_ACCOUNT_ADDITION_OPTIONS_H_
+#define COMPONENTS_ACCOUNT_MANAGER_CORE_ACCOUNT_ADDITION_OPTIONS_H_
+
+#include "base/component_export.h"
+
+namespace account_manager {
+
+// Options passed to the account addition request.
+struct COMPONENT_EXPORT(ACCOUNT_MANAGER_CORE) AccountAdditionOptions {
+ // The default value for ARC availability for the account to be added.
+ bool is_available_in_arc = false;
+ // Whether the account picker that allows to change ARC availability should be
+ // shown. When set to `true` - the ARC availability toggle in account addition
+ // flow will be hidden.
+ bool show_arc_availability_picker = false;
+};
+
+} // namespace account_manager
+
+#endif // COMPONENTS_ACCOUNT_MANAGER_CORE_ACCOUNT_ADDITION_OPTIONS_H_
diff --git a/chromium/components/account_manager_core/account_manager_facade_impl.cc b/chromium/components/account_manager_core/account_manager_facade_impl.cc
index 58b83364159..dc3a2d91567 100644
--- a/chromium/components/account_manager_core/account_manager_facade_impl.cc
+++ b/chromium/components/account_manager_core/account_manager_facade_impl.cc
@@ -33,9 +33,11 @@ namespace {
using RemoteMinVersions = crosapi::mojom::AccountManager::MethodMinVersions;
-// UMA histogram name.
+// UMA histogram names.
const char kAccountAdditionResultStatus[] =
"AccountManager.AccountAdditionResultStatus";
+const char kGetAccountsMojoStatus[] =
+ "AccountManager.FacadeGetAccountsMojoStatus";
void UnmarshalAccounts(
base::OnceCallback<void(const std::vector<Account>&)> callback,
@@ -69,6 +71,36 @@ void UnmarshalPersistentError(
std::move(callback).Run(maybe_error.value());
}
+// Returns whether an account should be available in ARC after it's added
+// in-session.
+bool GetIsAvailableInArcBySource(
+ AccountManagerFacade::AccountAdditionSource source) {
+ switch (source) {
+ // Accounts added from Ash should be available in ARC.
+ case AccountManagerFacade::AccountAdditionSource::kSettingsAddAccountButton:
+ case AccountManagerFacade::AccountAdditionSource::
+ kAccountManagerMigrationWelcomeScreen:
+ case AccountManagerFacade::AccountAdditionSource::kArc:
+ case AccountManagerFacade::AccountAdditionSource::kOnboarding:
+ return true;
+ // Accounts added from the browser should not be available in ARC.
+ case AccountManagerFacade::AccountAdditionSource::kPrintPreviewDialog:
+ case AccountManagerFacade::AccountAdditionSource::kChromeProfileCreation:
+ case AccountManagerFacade::AccountAdditionSource::kOgbAddAccount:
+ return false;
+ // These are reauthentication cases. ARC visibility shouldn't change for
+ // reauthentication.
+ case AccountManagerFacade::AccountAdditionSource::kContentAreaReauth:
+ case AccountManagerFacade::AccountAdditionSource::
+ kSettingsReauthAccountButton:
+ case AccountManagerFacade::AccountAdditionSource::
+ kAvatarBubbleReauthAccountButton:
+ case AccountManagerFacade::AccountAdditionSource::kChromeExtensionReauth:
+ NOTREACHED();
+ return false;
+ }
+}
+
} // namespace
// Fetches access tokens over the Mojo remote to `AccountManager`.
@@ -244,10 +276,22 @@ void AccountManagerFacadeImpl::RemoveObserver(Observer* observer) {
void AccountManagerFacadeImpl::GetAccounts(
base::OnceCallback<void(const std::vector<Account>&)> callback) {
+ // Record the status of the mojo connection, to get more information about
+ // https://crbug.com/1287297
+ FacadeMojoStatus mojo_status = FacadeMojoStatus::kOk;
+ if (!account_manager_remote_)
+ mojo_status = FacadeMojoStatus::kNoRemote;
+ else if (remote_version_ < RemoteMinVersions::kGetAccountsMinVersion)
+ mojo_status = FacadeMojoStatus::kVersionMismatch;
+ else if (!is_initialized_)
+ mojo_status = FacadeMojoStatus::kUninitialized;
+ base::UmaHistogramEnumeration(kGetAccountsMojoStatus, mojo_status);
+
if (!account_manager_remote_ ||
remote_version_ < RemoteMinVersions::kGetAccountsMinVersion) {
- // Remote side doesn't support GetAccounts, return an empty list.
- std::move(callback).Run({});
+ // Remote side is disconnected or doesn't support GetAccounts. Do not return
+ // an empty list as that may cause Lacros to delete user profiles.
+ // TODO(https://crbug.com/1287297): Try to reconnect, or return an error.
return;
}
RunAfterInitializationSequence(
@@ -293,7 +337,14 @@ void AccountManagerFacadeImpl::ShowAddAccountDialog(
base::UmaHistogramEnumeration(kAccountAdditionSource, source);
+ crosapi::mojom::AccountAdditionOptionsPtr options =
+ crosapi::mojom::AccountAdditionOptions::New();
+ options->is_available_in_arc = GetIsAvailableInArcBySource(source);
+ options->show_arc_availability_picker =
+ (source == AccountManagerFacade::AccountAdditionSource::kArc);
+
account_manager_remote_->ShowAddAccountDialog(
+ std::move(options),
base::BindOnce(&AccountManagerFacadeImpl::OnShowAddAccountDialogFinished,
weak_factory_.GetWeakPtr(), std::move(callback)));
}
@@ -369,6 +420,12 @@ std::string AccountManagerFacadeImpl::
return kAccountAdditionResultStatus;
}
+// static
+std::string
+AccountManagerFacadeImpl::GetAccountsMojoStatusHistogramNameForTesting() {
+ return kGetAccountsMojoStatus;
+}
+
void AccountManagerFacadeImpl::OnReceiverReceived(
mojo::PendingReceiver<AccountManagerObserver> receiver) {
receiver_ =
diff --git a/chromium/components/account_manager_core/account_manager_facade_impl.h b/chromium/components/account_manager_core/account_manager_facade_impl.h
index 51025f1d1bd..6fe4a04e201 100644
--- a/chromium/components/account_manager_core/account_manager_facade_impl.h
+++ b/chromium/components/account_manager_core/account_manager_facade_impl.h
@@ -80,9 +80,20 @@ class COMPONENT_EXPORT(ACCOUNT_MANAGER_CORE) AccountManagerFacadeImpl
FRIEND_TEST_ALL_PREFIXES(AccountManagerFacadeImplTest,
ShowAddAccountDialogCallsMojo);
FRIEND_TEST_ALL_PREFIXES(AccountManagerFacadeImplTest,
+ GetAccountsHangsWhenRemoteIsNull);
+ FRIEND_TEST_ALL_PREFIXES(AccountManagerFacadeImplTest,
ShowAddAccountDialogUMA);
FRIEND_TEST_ALL_PREFIXES(AccountManagerFacadeImplTest,
ShowReauthAccountDialogCallsMojo);
+ FRIEND_TEST_ALL_PREFIXES(
+ AccountManagerFacadeImplTest,
+ ShowAddAccountDialogSetsCorrectOptionsForAdditionFromAsh);
+ FRIEND_TEST_ALL_PREFIXES(
+ AccountManagerFacadeImplTest,
+ ShowAddAccountDialogSetsCorrectOptionsForAdditionFromLacros);
+ FRIEND_TEST_ALL_PREFIXES(
+ AccountManagerFacadeImplTest,
+ ShowAddAccountDialogSetsCorrectOptionsForAdditionFromArc);
FRIEND_TEST_ALL_PREFIXES(AccountManagerFacadeImplTest,
ShowReauthAccountDialogUMA);
FRIEND_TEST_ALL_PREFIXES(AccountManagerFacadeImplTest,
@@ -92,7 +103,21 @@ class COMPONENT_EXPORT(ACCOUNT_MANAGER_CORE) AccountManagerFacadeImpl
FRIEND_TEST_ALL_PREFIXES(
AccountManagerFacadeImplTest,
AccessTokenFetcherCanBeCreatedBeforeAccountManagerFacadeInitialization);
+
+ // Status of the mojo connection.
+ // These values are persisted to logs. Entries should not be renumbered and
+ // numeric values should never be reused.
+ enum class FacadeMojoStatus {
+ kOk = 0,
+ kUninitialized = 1,
+ kNoRemote = 2,
+ kVersionMismatch = 3,
+
+ kMaxValue = kVersionMismatch
+ };
+
static std::string GetAccountAdditionResultStatusHistogramNameForTesting();
+ static std::string GetAccountsMojoStatusHistogramNameForTesting();
// A utility class to fetch access tokens over Mojo.
class AccessTokenFetcher;
diff --git a/chromium/components/account_manager_core/account_manager_facade_impl_unittest.cc b/chromium/components/account_manager_core/account_manager_facade_impl_unittest.cc
index c1408347118..c8735273437 100644
--- a/chromium/components/account_manager_core/account_manager_facade_impl_unittest.cc
+++ b/chromium/components/account_manager_core/account_manager_facade_impl_unittest.cc
@@ -7,6 +7,7 @@
#include <limits>
#include <memory>
+#include "base/callback_helpers.h"
#include "base/run_loop.h"
#include "base/test/bind.h"
#include "base/test/gmock_callback_support.h"
@@ -16,6 +17,7 @@
#include "base/time/time.h"
#include "chromeos/crosapi/mojom/account_manager.mojom.h"
#include "components/account_manager_core/account.h"
+#include "components/account_manager_core/account_addition_options.h"
#include "components/account_manager_core/account_addition_result.h"
#include "components/account_manager_core/account_manager_facade.h"
#include "components/account_manager_core/account_manager_test_util.h"
@@ -157,8 +159,10 @@ class FakeAccountManager : public crosapi::mojom::AccountManager {
ToMojoGoogleServiceAuthError(GoogleServiceAuthError::AuthErrorNone()));
}
- void ShowAddAccountDialog(ShowAddAccountDialogCallback callback) override {
+ void ShowAddAccountDialog(crosapi::mojom::AccountAdditionOptionsPtr options,
+ ShowAddAccountDialogCallback callback) override {
show_add_account_dialog_calls_++;
+ show_add_account_dialog_options_ = FromMojoAccountAdditionOptions(options);
std::move(callback).Run(
account_manager::ToMojoAccountAdditionResult(*add_account_result_));
}
@@ -228,6 +232,11 @@ class FakeAccountManager : public crosapi::mojom::AccountManager {
return show_add_account_dialog_calls_;
}
+ absl::optional<account_manager::AccountAdditionOptions>
+ show_add_account_dialog_options() const {
+ return show_add_account_dialog_options_;
+ }
+
int show_reauth_account_dialog_calls() const {
return show_reauth_account_dialog_calls_;
}
@@ -238,6 +247,8 @@ class FakeAccountManager : public crosapi::mojom::AccountManager {
private:
int show_add_account_dialog_calls_ = 0;
+ absl::optional<account_manager::AccountAdditionOptions>
+ show_add_account_dialog_options_;
int show_reauth_account_dialog_calls_ = 0;
int show_manage_accounts_settings_calls_ = 0;
bool is_initialized_ = false;
@@ -373,19 +384,35 @@ TEST_F(AccountManagerFacadeImplTest,
run_loop.Run();
}
-TEST_F(AccountManagerFacadeImplTest,
- GetAccountsReturnsEmptyListOfAccountsWhenRemoteIsNull) {
+// Regression test for https://crbug.com/1287297
+// Do not return empty accounts when the remote is not available.
+TEST_F(AccountManagerFacadeImplTest, GetAccountsHangsWhenRemoteIsNull) {
+ base::HistogramTester tester;
auto account_manager_facade = std::make_unique<AccountManagerFacadeImpl>(
mojo::Remote<crosapi::mojom::AccountManager>(),
/*remote_version=*/std::numeric_limits<uint32_t>::max(),
/*account_manager_for_tests=*/nullptr);
- MockOnceCallback<void(const std::vector<Account>&)> callback;
- base::RunLoop run_loop;
- EXPECT_CALL(callback, Run(testing::IsEmpty()))
- .WillOnce(base::test::RunClosure(run_loop.QuitClosure()));
- account_manager_facade->GetAccounts(callback.Get());
- run_loop.Run();
+ bool callback_was_dropped = false;
+ // scoped_closure that sets `callback_was_dropped` when it is destroyed.
+ base::ScopedClosureRunner scoped_closure(base::BindLambdaForTesting(
+ [&callback_was_dropped]() { callback_was_dropped = true; }));
+ // Pass ownership of the scopped closure to the main callback, so that the
+ // scoped closure is run when the callback is destroyed.
+ // This callback should not be run.
+ base::OnceCallback<void(const std::vector<Account>&)> dropped_callback =
+ base::BindLambdaForTesting(
+ [scoped_closure = std::move(scoped_closure)](
+ const std::vector<Account>&) { NOTREACHED(); });
+ EXPECT_FALSE(callback_was_dropped);
+ account_manager_facade->GetAccounts(std::move(dropped_callback));
+ // `dropped_callback` was destroyed without being run.
+ EXPECT_TRUE(callback_was_dropped);
+
+ tester.ExpectUniqueSample(
+ AccountManagerFacadeImpl::GetAccountsMojoStatusHistogramNameForTesting(),
+ /*sample=*/AccountManagerFacadeImpl::FacadeMojoStatus::kNoRemote,
+ /*expected_count=*/1);
}
TEST_F(AccountManagerFacadeImplTest, GetPersistentErrorMarshalsAuthErrorNone) {
@@ -436,6 +463,68 @@ TEST_F(AccountManagerFacadeImplTest, ShowAddAccountDialogCallsMojo) {
EXPECT_EQ(1, account_manager().show_add_account_dialog_calls());
}
+TEST_F(AccountManagerFacadeImplTest,
+ ShowAddAccountDialogSetsCorrectOptionsForAdditionFromAsh) {
+ std::unique_ptr<AccountManagerFacadeImpl> account_manager_facade =
+ CreateFacade();
+ account_manager().SetAccountAdditionResult(
+ account_manager::AccountAdditionResult::FromStatus(
+ account_manager::AccountAdditionResult::Status::kUnexpectedResponse));
+ EXPECT_EQ(0, account_manager().show_add_account_dialog_calls());
+ account_manager_facade->ShowAddAccountDialog(
+ account_manager::AccountManagerFacade::AccountAdditionSource::
+ kSettingsAddAccountButton);
+ account_manager_facade->FlushMojoForTesting();
+ EXPECT_EQ(1, account_manager().show_add_account_dialog_calls());
+ EXPECT_TRUE(account_manager().show_add_account_dialog_options().has_value());
+ EXPECT_TRUE(
+ account_manager().show_add_account_dialog_options()->is_available_in_arc);
+ EXPECT_FALSE(account_manager()
+ .show_add_account_dialog_options()
+ ->show_arc_availability_picker);
+}
+
+TEST_F(AccountManagerFacadeImplTest,
+ ShowAddAccountDialogSetsCorrectOptionsForAdditionFromLacros) {
+ std::unique_ptr<AccountManagerFacadeImpl> account_manager_facade =
+ CreateFacade();
+ account_manager().SetAccountAdditionResult(
+ account_manager::AccountAdditionResult::FromStatus(
+ account_manager::AccountAdditionResult::Status::kUnexpectedResponse));
+ EXPECT_EQ(0, account_manager().show_add_account_dialog_calls());
+ account_manager_facade->ShowAddAccountDialog(
+ account_manager::AccountManagerFacade::AccountAdditionSource::
+ kOgbAddAccount);
+ account_manager_facade->FlushMojoForTesting();
+ EXPECT_EQ(1, account_manager().show_add_account_dialog_calls());
+ EXPECT_TRUE(account_manager().show_add_account_dialog_options().has_value());
+ EXPECT_FALSE(
+ account_manager().show_add_account_dialog_options()->is_available_in_arc);
+ EXPECT_FALSE(account_manager()
+ .show_add_account_dialog_options()
+ ->show_arc_availability_picker);
+}
+
+TEST_F(AccountManagerFacadeImplTest,
+ ShowAddAccountDialogSetsCorrectOptionsForAdditionFromArc) {
+ std::unique_ptr<AccountManagerFacadeImpl> account_manager_facade =
+ CreateFacade();
+ account_manager().SetAccountAdditionResult(
+ account_manager::AccountAdditionResult::FromStatus(
+ account_manager::AccountAdditionResult::Status::kUnexpectedResponse));
+ EXPECT_EQ(0, account_manager().show_add_account_dialog_calls());
+ account_manager_facade->ShowAddAccountDialog(
+ account_manager::AccountManagerFacade::AccountAdditionSource::kArc);
+ account_manager_facade->FlushMojoForTesting();
+ EXPECT_EQ(1, account_manager().show_add_account_dialog_calls());
+ EXPECT_TRUE(account_manager().show_add_account_dialog_options().has_value());
+ EXPECT_TRUE(
+ account_manager().show_add_account_dialog_options()->is_available_in_arc);
+ EXPECT_TRUE(account_manager()
+ .show_add_account_dialog_options()
+ ->show_arc_availability_picker);
+}
+
TEST_F(AccountManagerFacadeImplTest, ShowAddAccountDialogUMA) {
base::HistogramTester tester;
std::unique_ptr<AccountManagerFacadeImpl> account_manager_facade =
diff --git a/chromium/components/account_manager_core/account_manager_util.cc b/chromium/components/account_manager_core/account_manager_util.cc
index 560cf9f8ae1..895d3d2d580 100644
--- a/chromium/components/account_manager_core/account_manager_util.cc
+++ b/chromium/components/account_manager_core/account_manager_util.cc
@@ -6,6 +6,7 @@
#include "absl/types/optional.h"
#include "components/account_manager_core/account.h"
+#include "components/account_manager_core/account_addition_options.h"
#include "components/account_manager_core/account_addition_result.h"
#include "google_apis/gaia/google_service_auth_error.h"
@@ -306,4 +307,18 @@ crosapi::mojom::AccountAdditionResultPtr ToMojoAccountAdditionResult(
return mojo_result;
}
+absl::optional<account_manager::AccountAdditionOptions>
+FromMojoAccountAdditionOptions(
+ const crosapi::mojom::AccountAdditionOptionsPtr& mojo_options) {
+ if (!mojo_options)
+ return absl::nullopt;
+
+ account_manager::AccountAdditionOptions result;
+ result.is_available_in_arc = mojo_options->is_available_in_arc;
+ result.show_arc_availability_picker =
+ mojo_options->show_arc_availability_picker;
+
+ return result;
+}
+
} // namespace account_manager
diff --git a/chromium/components/account_manager_core/account_manager_util.h b/chromium/components/account_manager_core/account_manager_util.h
index 690d6969b5a..c6ef0f42096 100644
--- a/chromium/components/account_manager_core/account_manager_util.h
+++ b/chromium/components/account_manager_core/account_manager_util.h
@@ -7,6 +7,7 @@
#include "chromeos/crosapi/mojom/account_manager.mojom.h"
#include "components/account_manager_core/account.h"
+#include "components/account_manager_core/account_addition_options.h"
#include "components/account_manager_core/account_addition_result.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
@@ -60,6 +61,11 @@ FromMojoAccountAdditionResult(
COMPONENT_EXPORT(ACCOUNT_MANAGER_CORE)
crosapi::mojom::AccountAdditionResultPtr ToMojoAccountAdditionResult(
account_manager::AccountAdditionResult result);
+
+COMPONENT_EXPORT(ACCOUNT_MANAGER_CORE)
+absl::optional<account_manager::AccountAdditionOptions>
+FromMojoAccountAdditionOptions(
+ const crosapi::mojom::AccountAdditionOptionsPtr& mojo_options);
} // namespace account_manager
#endif // COMPONENTS_ACCOUNT_MANAGER_CORE_ACCOUNT_MANAGER_UTIL_H_
diff --git a/chromium/components/account_manager_core/chromeos/account_manager.cc b/chromium/components/account_manager_core/chromeos/account_manager.cc
index c557d45e5d8..5a1e7b91973 100644
--- a/chromium/components/account_manager_core/chromeos/account_manager.cc
+++ b/chromium/components/account_manager_core/chromeos/account_manager.cc
@@ -51,6 +51,9 @@ constexpr int kTokensFileMaxSizeInBytes = 100000; // ~100 KB.
constexpr char kNumAccountsMetricName[] = "AccountManager.NumAccounts";
constexpr int kMaxNumAccountsMetric = 10;
+// The value `all` means that all usages of managed accounts are allowed.
+constexpr char kDefaultSecondaryGoogleAccountUsage[] = "all";
+
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
// Note: Enums labels are at |AccountManagerTokenLoadStatus|.
@@ -275,7 +278,9 @@ AccountManager::AccountManager() = default;
void AccountManager::RegisterPrefs(PrefRegistrySimple* registry) {
registry->RegisterBooleanPref(
::account_manager::prefs::kSecondaryGoogleAccountSigninAllowed,
- true /* default_value */);
+ /*default_value=*/true);
+ registry->RegisterStringPref(prefs::kSecondaryGoogleAccountUsage,
+ kDefaultSecondaryGoogleAccountUsage);
}
void AccountManager::SetPrefService(PrefService* pref_service) {
@@ -472,38 +477,36 @@ void AccountManager::RunOnInitialization(base::OnceClosure closure) {
}
void AccountManager::GetAccounts(AccountListCallback callback) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK_NE(init_state_, InitializationState::kNotStarted);
- base::OnceClosure closure =
- base::BindOnce(&AccountManager::GetAccountsInternal,
- weak_factory_.GetWeakPtr(), std::move(callback));
- RunOnInitialization(std::move(closure));
-}
+ if (init_state_ != InitializationState::kInitialized) {
+ base::OnceClosure closure =
+ base::BindOnce(&AccountManager::GetAccounts, weak_factory_.GetWeakPtr(),
+ std::move(callback));
+ RunOnInitialization(std::move(closure));
+ return;
+ }
-void AccountManager::GetAccountsInternal(AccountListCallback callback) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK_EQ(init_state_, InitializationState::kInitialized);
-
- std::move(callback).Run(GetAccounts());
+ std::move(callback).Run(GetAccountsView());
}
void AccountManager::GetAccountEmail(
const ::account_manager::AccountKey& account_key,
base::OnceCallback<void(const std::string&)> callback) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK_NE(init_state_, InitializationState::kNotStarted);
- base::OnceClosure closure = base::BindOnce(
- &AccountManager::GetAccountEmailInternal, weak_factory_.GetWeakPtr(),
- account_key, std::move(callback));
- RunOnInitialization(std::move(closure));
-}
+ if (init_state_ != InitializationState::kInitialized) {
+ base::OnceClosure closure = base::BindOnce(
+ &AccountManager::GetAccountEmail, weak_factory_.GetWeakPtr(),
+ account_key, std::move(callback));
+ RunOnInitialization(std::move(closure));
+ return;
+ }
-void AccountManager::GetAccountEmailInternal(
- const ::account_manager::AccountKey& account_key,
- base::OnceCallback<void(const std::string&)> callback) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK_EQ(init_state_, InitializationState::kInitialized);
-
auto it = accounts_.find(account_key);
if (it == accounts_.end()) {
std::move(callback).Run(std::string());
@@ -515,19 +518,18 @@ void AccountManager::GetAccountEmailInternal(
void AccountManager::RemoveAccount(
const ::account_manager::AccountKey& account_key) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK_NE(init_state_, InitializationState::kNotStarted);
- base::OnceClosure closure =
- base::BindOnce(&AccountManager::RemoveAccountInternal,
- weak_factory_.GetWeakPtr(), account_key);
- RunOnInitialization(std::move(closure));
-}
+ if (init_state_ != InitializationState::kInitialized) {
+ base::OnceClosure closure =
+ base::BindOnce(&AccountManager::RemoveAccount,
+ weak_factory_.GetWeakPtr(), account_key);
+ RunOnInitialization(std::move(closure));
+ return;
+ }
-void AccountManager::RemoveAccountInternal(
- const ::account_manager::AccountKey& account_key) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK_EQ(init_state_, InitializationState::kInitialized);
-
auto it = accounts_.find(account_key);
if (it == accounts_.end()) {
return;
@@ -542,28 +544,6 @@ void AccountManager::RemoveAccountInternal(
MaybeRevokeTokenOnServer(account_key, old_token);
}
-void AccountManager::RemoveAccount(const std::string& email) {
- DCHECK_NE(init_state_, InitializationState::kNotStarted);
-
- base::OnceClosure closure =
- base::BindOnce(&AccountManager::RemoveAccountByEmailInternal,
- weak_factory_.GetWeakPtr(), email);
- RunOnInitialization(std::move(closure));
-}
-
-void AccountManager::RemoveAccountByEmailInternal(const std::string& email) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK_EQ(init_state_, InitializationState::kInitialized);
-
- for (const std::pair<::account_manager::AccountKey, AccountInfo> account :
- accounts_) {
- if (gaia::AreEmailsSame(account.second.raw_email, email)) {
- RemoveAccountInternal(account.first /* account_key */);
- return;
- }
- }
-}
-
void AccountManager::UpsertAccount(
const ::account_manager::AccountKey& account_key,
const std::string& raw_email,
@@ -580,6 +560,7 @@ void AccountManager::UpsertAccount(
void AccountManager::UpdateToken(
const ::account_manager::AccountKey& account_key,
const std::string& token) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK_NE(init_state_, InitializationState::kNotStarted);
if (account_key.account_type() ==
@@ -587,48 +568,21 @@ void AccountManager::UpdateToken(
DCHECK_EQ(token, kActiveDirectoryDummyToken);
}
- base::OnceClosure closure =
- base::BindOnce(&AccountManager::UpdateTokenInternal,
- weak_factory_.GetWeakPtr(), account_key, token);
- RunOnInitialization(std::move(closure));
-}
+ if (init_state_ != InitializationState::kInitialized) {
+ base::OnceClosure closure =
+ base::BindOnce(&AccountManager::UpdateToken, weak_factory_.GetWeakPtr(),
+ account_key, token);
+ RunOnInitialization(std::move(closure));
+ return;
+ }
-void AccountManager::UpdateTokenInternal(
- const ::account_manager::AccountKey& account_key,
- const std::string& token) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK_EQ(init_state_, InitializationState::kInitialized);
-
auto it = accounts_.find(account_key);
DCHECK(it != accounts_.end())
<< "UpdateToken cannot be used for adding accounts";
UpsertAccountInternal(account_key, AccountInfo{it->second.raw_email, token});
}
-void AccountManager::UpdateEmail(
- const ::account_manager::AccountKey& account_key,
- const std::string& raw_email) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK_NE(init_state_, InitializationState::kNotStarted);
-
- base::OnceClosure closure =
- base::BindOnce(&AccountManager::UpdateEmailInternal,
- weak_factory_.GetWeakPtr(), account_key, raw_email);
- RunOnInitialization(std::move(closure));
-}
-
-void AccountManager::UpdateEmailInternal(
- const ::account_manager::AccountKey& account_key,
- const std::string& raw_email) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK_EQ(init_state_, InitializationState::kInitialized);
-
- auto it = accounts_.find(account_key);
- DCHECK(it != accounts_.end())
- << "UpdateEmail cannot be used for adding accounts";
- UpsertAccountInternal(account_key, AccountInfo{raw_email, it->second.token});
-}
-
void AccountManager::UpsertAccountInternal(
const ::account_manager::AccountKey& account_key,
const AccountInfo& account) {
@@ -704,7 +658,9 @@ std::string AccountManager::GetSerializedAccounts() {
return accounts_proto.SerializeAsString();
}
-std::vector<::account_manager::Account> AccountManager::GetAccounts() {
+std::vector<::account_manager::Account> AccountManager::GetAccountsView() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
std::vector<::account_manager::Account> accounts;
accounts.reserve(accounts_.size());
@@ -773,20 +729,18 @@ bool AccountManager::IsTokenAvailable(
void AccountManager::HasDummyGaiaToken(
const ::account_manager::AccountKey& account_key,
base::OnceCallback<void(bool)> callback) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK_NE(init_state_, InitializationState::kNotStarted);
- base::OnceClosure closure = base::BindOnce(
- &AccountManager::HasDummyGaiaTokenInternal, weak_factory_.GetWeakPtr(),
- account_key, std::move(callback));
- RunOnInitialization(std::move(closure));
-}
+ if (init_state_ != InitializationState::kInitialized) {
+ base::OnceClosure closure = base::BindOnce(
+ &AccountManager::HasDummyGaiaToken, weak_factory_.GetWeakPtr(),
+ account_key, std::move(callback));
+ RunOnInitialization(std::move(closure));
+ return;
+ }
-void AccountManager::HasDummyGaiaTokenInternal(
- const ::account_manager::AccountKey& account_key,
- base::OnceCallback<void(bool)> callback) const {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK_EQ(init_state_, InitializationState::kInitialized);
-
auto it = accounts_.find(account_key);
std::move(callback).Run(it != accounts_.end() &&
it->second.token == kInvalidToken);
@@ -796,21 +750,18 @@ void AccountManager::CheckDummyGaiaTokenForAllAccounts(
base::OnceCallback<
void(const std::vector<std::pair<::account_manager::Account, bool>>&)>
callback) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK_NE(init_state_, InitializationState::kNotStarted);
- base::OnceClosure closure =
- base::BindOnce(&AccountManager::CheckDummyGaiaTokenForAllAccountsInternal,
- weak_factory_.GetWeakPtr(), std::move(callback));
- RunOnInitialization(std::move(closure));
-}
+ if (init_state_ != InitializationState::kInitialized) {
+ base::OnceClosure closure =
+ base::BindOnce(&AccountManager::CheckDummyGaiaTokenForAllAccounts,
+ weak_factory_.GetWeakPtr(), std::move(callback));
+ RunOnInitialization(std::move(closure));
+ return;
+ }
-void AccountManager::CheckDummyGaiaTokenForAllAccountsInternal(
- base::OnceCallback<
- void(const std::vector<std::pair<::account_manager::Account, bool>>&)>
- callback) const {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK_EQ(init_state_, InitializationState::kInitialized);
-
std::vector<std::pair<::account_manager::Account, bool>> accounts_list;
accounts_list.reserve(accounts_.size());
diff --git a/chromium/components/account_manager_core/chromeos/account_manager.h b/chromium/components/account_manager_core/chromeos/account_manager.h
index 8a72406ad10..f7042510e60 100644
--- a/chromium/components/account_manager_core/chromeos/account_manager.h
+++ b/chromium/components/account_manager_core/chromeos/account_manager.h
@@ -110,7 +110,7 @@ class COMPONENT_EXPORT(ACCOUNT_MANAGER_CORE) AccountManager {
// |AccountManager| does not persist any data to disk.
// |request_context| is a non-owning pointer.
// |delay_network_call_runner| is basically a wrapper for
- // |chromeos::DelayNetworkCall|. Cannot use |chromeos::DelayNetworkCall| due
+ // |ash::DelayNetworkCall|. Cannot use |ash::DelayNetworkCall| due
// to linking/dependency constraints.
// This method MUST be called at least once in the lifetime of AccountManager.
void Initialize(
@@ -146,57 +146,46 @@ class COMPONENT_EXPORT(ACCOUNT_MANAGER_CORE) AccountManager {
// Returns |true| if |AccountManager| has been fully initialized.
bool IsInitialized() const;
- // Gets (async) a list of account keys known to |AccountManager|. Note that
- // |callback| will be immediately called in the same thread if
- // |AccountManager| has been fully initialized and hence it may not be safe to
+ // Gets (async) a list of account keys known to `AccountManager`. Note that
+ // `callback` will be immediately called in the same thread if
+ // `AccountManager` has been fully initialized and hence it may not be safe to
// call this method directly in some class's constructor, with a callback on
// the same class, since it may result in a method call on a partially
// constructed object.
void GetAccounts(AccountListCallback callback);
// Gets (async) the raw, un-canonicalized email id corresponding to
- // |account_key|. |callback| is called with an empty string if |account_key|
+ // `account_key`. `callback` is called with an empty string if `account_key`
// is not known to Account Manager.
void GetAccountEmail(const ::account_manager::AccountKey& account_key,
base::OnceCallback<void(const std::string&)> callback);
- // Removes an account. Does not do anything if |account_key| is not known by
- // |AccountManager|.
+ // Removes an account. Does not do anything if `account_key` is not known by
+ // `AccountManager`.
// Observers are notified about an account removal through
- // |Observer::OnAccountRemoved|.
+ // `Observer::OnAccountRemoved`.
// If the account being removed is a GAIA account, a token revocation with
// GAIA is also attempted, on a best effort basis. Even if token revocation
// with GAIA fails, AccountManager will forget the account.
void RemoveAccount(const ::account_manager::AccountKey& account_key);
- // Similar to |RemoveAccount(AccountKey)| except that it accepts |email| as
- // the account identifier instead of |account_key|. |email| can be the raw
- // email or the canonical email.
- void RemoveAccount(const std::string& email);
-
- // Updates or inserts an account. |raw_email| is the raw, un-canonicalized
- // email id for |account_key|. |raw_email| must not be empty. Use
- // |AccountManager::kActiveDirectoryDummyToken| as the |token| for Active
- // Directory accounts, and |AccountManager::kInvalidToken| for Gaia accounts
+ // Updates or inserts an account. `raw_email` is the raw, un-canonicalized
+ // email id for `account_key`. `raw_email` must not be empty. Use
+ // `AccountManager::kActiveDirectoryDummyToken` as the `token` for Active
+ // Directory accounts, and `AccountManager::kInvalidToken` for Gaia accounts
// with unknown tokens.
// Note: This API is idempotent.
void UpsertAccount(const ::account_manager::AccountKey& account_key,
const std::string& raw_email,
const std::string& token);
- // Updates the token for the account corresponding to the given |account_key|.
- // The account must be known to Account Manager. See |UpsertAccount| for
+ // Updates the token for the account corresponding to the given `account_key`.
+ // The account must be known to Account Manager. See `UpsertAccount` for
// information about adding an account.
// Note: This API is idempotent.
void UpdateToken(const ::account_manager::AccountKey& account_key,
const std::string& token);
- // Updates the email associated with |account_key|. The account must be known
- // to Account Manager. See |UpsertAccount| for information about adding an
- // account.
- void UpdateEmail(const ::account_manager::AccountKey& account_key,
- const std::string& raw_email);
-
// Add a non owning pointer to an |AccountManager::Observer|.
void AddObserver(Observer* observer);
@@ -223,15 +212,15 @@ class COMPONENT_EXPORT(ACCOUNT_MANAGER_CORE) AccountManager {
// initialized yet.
bool IsTokenAvailable(const ::account_manager::AccountKey& account_key) const;
- // Calls the |callback| with true if the token stored against |account_key| is
+ // Calls the `callback` with true if the token stored against `account_key` is
// a dummy Gaia token.
void HasDummyGaiaToken(const ::account_manager::AccountKey& account_key,
base::OnceCallback<void(bool)> callback);
- // Calls the |callback| with a list of pairs of |account_key| and boolean
- // which is set to true if the token stored against |account_key| is a dummy
+ // Calls the `callback` with a list of pairs of `account_key` and boolean
+ // which is set to true if the token stored against `account_key` is a dummy
// Gaia token, for all accounts stored in AccountManager. See
- // |HasDummyGaiaToken|.
+ // `HasDummyGaiaToken`.
void CheckDummyGaiaTokenForAllAccounts(
base::OnceCallback<
void(const std::vector<std::pair<::account_manager::Account, bool>>&)>
@@ -292,33 +281,6 @@ class COMPONENT_EXPORT(ACCOUNT_MANAGER_CORE) AccountManager {
// class is initialized.
void RunOnInitialization(base::OnceClosure closure);
- // Does the actual work of getting a list of accounts. Assumes that
- // |AccountManager| initialization (|init_state_|) is complete.
- void GetAccountsInternal(AccountListCallback callback);
-
- // Does the actual work of fetching the email for |account_key|. Assumes that
- // |AccountManager| initialization (|init_state_|) is complete.
- void GetAccountEmailInternal(
- const ::account_manager::AccountKey& account_key,
- base::OnceCallback<void(const std::string&)> callback);
-
- // Does the actual work of removing an account. Assumes that
- // |AccountManager| initialization (|init_state_|) is complete.
- void RemoveAccountInternal(const ::account_manager::AccountKey& account_key);
-
- // Does the actual work of removing an account. Assumes that |AccountManager|
- // initialization (|init_state_|) is complete. |email| can be the raw email or
- // the canonical email.
- void RemoveAccountByEmailInternal(const std::string& email);
-
- // Assumes that |AccountManager| initialization (|init_state_|) is complete.
- void UpdateTokenInternal(const ::account_manager::AccountKey& account_key,
- const std::string& token);
-
- // Assumes that |AccountManager| initialization (|init_state_|) is complete.
- void UpdateEmailInternal(const ::account_manager::AccountKey& account_key,
- const std::string& raw_email);
-
// Does the actual work of upserting an account and performing related tasks
// like revoking old tokens and informing observers. All account updates
// funnel through to this method. Assumes that |AccountManager| initialization
@@ -333,8 +295,8 @@ class COMPONENT_EXPORT(ACCOUNT_MANAGER_CORE) AccountManager {
// Gets a serialized representation of accounts.
std::string GetSerializedAccounts();
- // Gets the publicly viewable information stored in |accounts_|.
- std::vector<::account_manager::Account> GetAccounts();
+ // Gets the publicly viewable information stored in `accounts_`.
+ std::vector<::account_manager::Account> GetAccountsView();
// Notifies |Observer|s about a token update for |account|.
void NotifyTokenObservers(const ::account_manager::Account& account);
@@ -362,19 +324,6 @@ class COMPONENT_EXPORT(ACCOUNT_MANAGER_CORE) AccountManager {
// mode, and not persisting anything to disk.
bool IsEphemeralMode() const;
- // Does the actual work of checking dummy token for |account_key|. Assumes
- // that |AccountManager| initialization (|init_state_|) is complete.
- void HasDummyGaiaTokenInternal(
- const ::account_manager::AccountKey& account_key,
- base::OnceCallback<void(bool)> callback) const;
-
- // Does the actual work of checking dummy token for all accounts. Assumes that
- // |AccountManager| initialization (|init_state_|) is complete.
- void CheckDummyGaiaTokenForAllAccountsInternal(
- base::OnceCallback<
- void(const std::vector<std::pair<::account_manager::Account, bool>>&)>
- callback) const;
-
// Returns the refresh token for `account_key`, if present. `account_key` must
// be a Gaia account. Assumes that `AccountManager` initialization
// (`init_state_`) is complete.
@@ -391,8 +340,8 @@ class COMPONENT_EXPORT(ACCOUNT_MANAGER_CORE) AccountManager {
// All tokens, if channel bound, are bound to |url_loader_factory_|.
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
- // An indirect way to access |chromeos::DelayNetworkCall|. We cannot use
- // |chromeos::DelayNetworkCall| directly here due to linking/dependency
+ // An indirect way to access `ash::DelayNetworkCall`. We cannot use
+ // `ash::DelayNetworkCall` directly here due to linking/dependency
// issues.
DelayNetworkCallRunner delay_network_call_runner_;
diff --git a/chromium/components/account_manager_core/chromeos/account_manager_mojo_service.cc b/chromium/components/account_manager_core/chromeos/account_manager_mojo_service.cc
index c078f941cb7..1dcb9a7b602 100644
--- a/chromium/components/account_manager_core/chromeos/account_manager_mojo_service.cc
+++ b/chromium/components/account_manager_core/chromeos/account_manager_mojo_service.cc
@@ -108,6 +108,7 @@ void AccountManagerMojoService::GetPersistentErrorForAccount(
}
void AccountManagerMojoService::ShowAddAccountDialog(
+ crosapi::mojom::AccountAdditionOptionsPtr options,
ShowAddAccountDialogCallback callback) {
DCHECK(account_manager_ui_);
if (account_manager_ui_->IsDialogShown()) {
@@ -121,7 +122,9 @@ void AccountManagerMojoService::ShowAddAccountDialog(
DCHECK(!account_addition_in_progress_);
account_addition_in_progress_ = true;
account_addition_callback_ = std::move(callback);
+ auto maybe_options = account_manager::FromMojoAccountAdditionOptions(options);
account_manager_ui_->ShowAddAccountDialog(
+ maybe_options.value_or(account_manager::AccountAdditionOptions{}),
base::BindOnce(&AccountManagerMojoService::OnAddAccountDialogClosed,
weak_ptr_factory_.GetWeakPtr()));
}
diff --git a/chromium/components/account_manager_core/chromeos/account_manager_mojo_service.h b/chromium/components/account_manager_core/chromeos/account_manager_mojo_service.h
index a3b1abdd5a4..107e2e89c80 100644
--- a/chromium/components/account_manager_core/chromeos/account_manager_mojo_service.h
+++ b/chromium/components/account_manager_core/chromeos/account_manager_mojo_service.h
@@ -55,7 +55,8 @@ class COMPONENT_EXPORT(ACCOUNT_MANAGER_CORE) AccountManagerMojoService
void GetPersistentErrorForAccount(
mojom::AccountKeyPtr mojo_account_key,
GetPersistentErrorForAccountCallback callback) override;
- void ShowAddAccountDialog(ShowAddAccountDialogCallback callback) override;
+ void ShowAddAccountDialog(mojom::AccountAdditionOptionsPtr options,
+ ShowAddAccountDialogCallback callback) override;
void ShowReauthAccountDialog(const std::string& email,
base::OnceClosure closure) override;
void ShowManageAccountsSettings() override;
diff --git a/chromium/components/account_manager_core/chromeos/account_manager_mojo_service_unittest.cc b/chromium/components/account_manager_core/chromeos/account_manager_mojo_service_unittest.cc
index 06fcff7ffdd..ee9c466d388 100644
--- a/chromium/components/account_manager_core/chromeos/account_manager_mojo_service_unittest.cc
+++ b/chromium/components/account_manager_core/chromeos/account_manager_mojo_service_unittest.cc
@@ -189,15 +189,17 @@ class AccountManagerMojoServiceTest : public ::testing::Test {
mojom::AccountAdditionResultPtr ShowAddAccountDialog(
base::OnceClosure quit_closure) {
auto add_account_result = mojom::AccountAdditionResult::New();
- account_manager_mojo_service_->ShowAddAccountDialog(base::BindOnce(
- [](base::OnceClosure quit_closure,
- mojom::AccountAdditionResultPtr* add_account_result,
- mojom::AccountAdditionResultPtr result) {
- (*add_account_result)->status = result->status;
- (*add_account_result)->account = std::move(result->account);
- std::move(quit_closure).Run();
- },
- std::move(quit_closure), &add_account_result));
+ account_manager_mojo_service_->ShowAddAccountDialog(
+ crosapi::mojom::AccountAdditionOptions::New(),
+ base::BindOnce(
+ [](base::OnceClosure quit_closure,
+ mojom::AccountAdditionResultPtr* add_account_result,
+ mojom::AccountAdditionResultPtr result) {
+ (*add_account_result)->status = result->status;
+ (*add_account_result)->account = std::move(result->account);
+ std::move(quit_closure).Run();
+ },
+ std::move(quit_closure), &add_account_result));
return add_account_result;
}
@@ -369,7 +371,7 @@ TEST_F(AccountManagerMojoServiceTest,
GetFakeAccountManagerUI()->SetIsDialogShown(true);
mojom::AccountAdditionResultPtr account_addition_result;
account_manager_async_waiter()->ShowAddAccountDialog(
- &account_addition_result);
+ crosapi::mojom::AccountAdditionOptions::New(), &account_addition_result);
// Check status.
EXPECT_EQ(mojom::AccountAdditionResult::Status::kAlreadyInProgress,
diff --git a/chromium/components/account_manager_core/chromeos/account_manager_ui.h b/chromium/components/account_manager_core/chromeos/account_manager_ui.h
index 5354a602c38..eb80b4f95b4 100644
--- a/chromium/components/account_manager_core/chromeos/account_manager_ui.h
+++ b/chromium/components/account_manager_core/chromeos/account_manager_ui.h
@@ -8,6 +8,7 @@
#include "base/callback.h"
#include "base/callback_forward.h"
#include "base/component_export.h"
+#include "components/account_manager_core/account_addition_options.h"
namespace account_manager {
@@ -21,8 +22,10 @@ class COMPONENT_EXPORT(ACCOUNT_MANAGER_CORE) AccountManagerUI {
virtual ~AccountManagerUI();
// Show system dialog for account addition.
+ // `options` are parameters that define the dialog UI.
// `close_dialog_closure` callback will be called when dialog is closed.
- virtual void ShowAddAccountDialog(base::OnceClosure close_dialog_closure) = 0;
+ virtual void ShowAddAccountDialog(const AccountAdditionOptions& options,
+ base::OnceClosure close_dialog_closure) = 0;
// Show system dialog for account reauthentication.
// `email` is the email of account that will be reauthenticated.
diff --git a/chromium/components/account_manager_core/chromeos/account_manager_unittest.cc b/chromium/components/account_manager_core/chromeos/account_manager_unittest.cc
index dc77d0a600d..ed02814b9e0 100644
--- a/chromium/components/account_manager_core/chromeos/account_manager_unittest.cc
+++ b/chromium/components/account_manager_core/chromeos/account_manager_unittest.cc
@@ -456,18 +456,6 @@ TEST_F(AccountManagerTest, TestAccountEmailPersistence) {
EXPECT_EQ(kRawUserEmail, raw_email);
}
-TEST_F(AccountManagerTest, UpdatingAccountEmailShouldNotOverwriteTokens) {
- const std::string new_email = "new-email@example.org";
- account_manager()->UpsertAccount(kGaiaAccountKey, kRawUserEmail, kGaiaToken);
- account_manager()->UpdateEmail(kGaiaAccountKey, new_email);
- RunAllPendingTasks();
-
- ResetAndInitializeAccountManager();
- const std::string raw_email = GetAccountEmailBlocking(kGaiaAccountKey);
- EXPECT_EQ(new_email, raw_email);
- EXPECT_EQ(kGaiaToken, account_manager()->accounts_[kGaiaAccountKey].token);
-}
-
TEST_F(AccountManagerTest, UpsertAccountCanUpdateEmail) {
const std::string new_email = "new-email@example.org";
account_manager()->UpsertAccount(kGaiaAccountKey, kRawUserEmail, kGaiaToken);
@@ -552,23 +540,6 @@ TEST_F(AccountManagerTest, RemovedAccountsAreImmediatelyUnavailable) {
EXPECT_TRUE(GetAccountsBlocking().empty());
}
-TEST_F(AccountManagerTest, AccountsCanBeRemovedByRawEmail) {
- account_manager()->UpsertAccount(kGaiaAccountKey, kRawUserEmail, kGaiaToken);
-
- account_manager()->RemoveAccount(kRawUserEmail);
- EXPECT_TRUE(GetAccountsBlocking().empty());
-}
-
-TEST_F(AccountManagerTest, AccountsCanBeRemovedByCanonicalEmail) {
- const std::string raw_email = "abc.123.456@gmail.com";
- const std::string canonical_email = "abc123456@gmail.com";
-
- account_manager()->UpsertAccount(kGaiaAccountKey, raw_email, kGaiaToken);
-
- account_manager()->RemoveAccount(canonical_email);
- EXPECT_TRUE(GetAccountsBlocking().empty());
-}
-
TEST_F(AccountManagerTest, AccountRemovalIsPersistedToDisk) {
account_manager()->UpsertAccount(kGaiaAccountKey, kRawUserEmail, kGaiaToken);
account_manager()->RemoveAccount(kGaiaAccountKey);
diff --git a/chromium/components/account_manager_core/chromeos/fake_account_manager_ui.cc b/chromium/components/account_manager_core/chromeos/fake_account_manager_ui.cc
index 0a454253676..9561678d254 100644
--- a/chromium/components/account_manager_core/chromeos/fake_account_manager_ui.cc
+++ b/chromium/components/account_manager_core/chromeos/fake_account_manager_ui.cc
@@ -29,6 +29,7 @@ void FakeAccountManagerUI::CloseDialog() {
}
void FakeAccountManagerUI::ShowAddAccountDialog(
+ const account_manager::AccountAdditionOptions& options,
base::OnceClosure close_dialog_closure) {
close_dialog_closure_ = std::move(close_dialog_closure);
show_account_addition_dialog_calls_++;
diff --git a/chromium/components/account_manager_core/chromeos/fake_account_manager_ui.h b/chromium/components/account_manager_core/chromeos/fake_account_manager_ui.h
index 91d626f32f7..ccb202d7b94 100644
--- a/chromium/components/account_manager_core/chromeos/fake_account_manager_ui.h
+++ b/chromium/components/account_manager_core/chromeos/fake_account_manager_ui.h
@@ -46,7 +46,9 @@ class FakeAccountManagerUI : public account_manager::AccountManagerUI {
}
// AccountManagerUI overrides:
- void ShowAddAccountDialog(base::OnceClosure close_dialog_closure) override;
+ void ShowAddAccountDialog(
+ const account_manager::AccountAdditionOptions& options,
+ base::OnceClosure close_dialog_closure) override;
void ShowReauthAccountDialog(const std::string& email,
base::OnceClosure close_dialog_closure) override;
bool IsDialogShown() override;
diff --git a/chromium/components/account_manager_core/pref_names.cc b/chromium/components/account_manager_core/pref_names.cc
index d483a0a6f6e..533f37b526d 100644
--- a/chromium/components/account_manager_core/pref_names.cc
+++ b/chromium/components/account_manager_core/pref_names.cc
@@ -21,5 +21,10 @@ const char kAccountAppsAvailability[] =
// Keys for `kAccountAppsAvailability`.
const char kIsAvailableInArcKey[] = "is_available_in_arc";
+// Decides whether a Enterprise account can be added to a session as a Secondary
+// Account at OS level.
+const char kSecondaryGoogleAccountUsage[] =
+ "account_manager.secondary_google_account_usage";
+
} // namespace prefs
} // namespace account_manager
diff --git a/chromium/components/account_manager_core/pref_names.h b/chromium/components/account_manager_core/pref_names.h
index afaccf5bb6f..efbaec0c778 100644
--- a/chromium/components/account_manager_core/pref_names.h
+++ b/chromium/components/account_manager_core/pref_names.h
@@ -19,6 +19,9 @@ extern const char kAccountAppsAvailability[];
COMPONENT_EXPORT(ACCOUNT_MANAGER_CORE)
extern const char kIsAvailableInArcKey[];
+COMPONENT_EXPORT(ACCOUNT_MANAGER_CORE)
+extern const char kSecondaryGoogleAccountUsage[];
+
} // namespace prefs
} // namespace account_manager
diff --git a/chromium/components/accuracy_tips/accuracy_service.cc b/chromium/components/accuracy_tips/accuracy_service.cc
index d033e7efea3..0719bd70d3f 100644
--- a/chromium/components/accuracy_tips/accuracy_service.cc
+++ b/chromium/components/accuracy_tips/accuracy_service.cc
@@ -115,7 +115,7 @@ void AccuracyService::CheckAccuracyStatus(const GURL& url,
pref_service_->Get(GetPreviousInteractionsPrefName(disable_ui_));
const base::Value opt_out_value(
static_cast<int>(AccuracyTipInteraction::kOptOut));
- if (base::Contains(last_interactions->GetList(), opt_out_value)) {
+ if (base::Contains(last_interactions->GetListDeprecated(), opt_out_value)) {
return std::move(callback).Run(AccuracyTipStatus::kOptOut);
}
@@ -162,7 +162,7 @@ void AccuracyService::MaybeShowAccuracyTip(content::WebContents* web_contents) {
bool show_opt_out =
pref_service_->GetList(GetPreviousInteractionsPrefName(disable_ui_))
- ->GetList()
+ ->GetListDeprecated()
.size() >= static_cast<size_t>(features::kNumIgnorePrompts.Get());
url_for_last_shown_tip_ = web_contents->GetLastCommittedURL();
@@ -182,7 +182,8 @@ void AccuracyService::MaybeShowSurvey() {
if (CanShowSurvey()) {
auto* interactions_list =
pref_service_->GetList(GetPreviousInteractionsPrefName(disable_ui_));
- const int last_interaction = interactions_list->GetList().back().GetInt();
+ const int last_interaction =
+ interactions_list->GetListDeprecated().back().GetInt();
const bool ukm_enabled = pref_service_->GetBoolean(
unified_consent::prefs::kUrlKeyedAnonymizedDataCollectionEnabled);
std::string url_parameter_for_hats =
@@ -242,7 +243,7 @@ void AccuracyService::OnAccuracyTipClosed(base::TimeTicks time_opened,
base::UmaHistogramEnumeration("Privacy.AccuracyTip.AccuracyTipInteraction",
interaction);
base::UmaHistogramCounts100("Privacy.AccuracyTip.NumDialogsShown",
- interaction_list->GetList().size());
+ interaction_list->GetListDeprecated().size());
ukm::builders::AccuracyTipDialog ukm_builder(ukm_source_id);
ukm_builder.SetInteraction(static_cast<int>(interaction));
@@ -255,7 +256,7 @@ void AccuracyService::OnAccuracyTipClosed(base::TimeTicks time_opened,
const std::string suffix = GetHistogramSuffix(interaction);
base::UmaHistogramCounts100("Privacy.AccuracyTip.NumDialogsShown." + suffix,
- interaction_list->GetList().size());
+ interaction_list->GetListDeprecated().size());
base::UmaHistogramMediumTimes(
"Privacy.AccuracyTip.AccuracyTipTimeOpen." + suffix, time_open);
}
@@ -287,7 +288,7 @@ bool AccuracyService::CanShowSurvey() {
int interactions_count =
pref_service_->GetList(GetPreviousInteractionsPrefName(disable_ui_))
- ->GetList()
+ ->GetListDeprecated()
.size();
return interactions_count >= features::kMinPromptCountRequiredForSurvey.Get();
}
diff --git a/chromium/components/android_autofill/browser/java/src/org/chromium/components/autofill/AutofillManagerWrapper.java b/chromium/components/android_autofill/browser/java/src/org/chromium/components/autofill/AutofillManagerWrapper.java
index 237cf244e98..dd77c726088 100644
--- a/chromium/components/android_autofill/browser/java/src/org/chromium/components/autofill/AutofillManagerWrapper.java
+++ b/chromium/components/android_autofill/browser/java/src/org/chromium/components/autofill/AutofillManagerWrapper.java
@@ -4,7 +4,6 @@
package org.chromium.components.autofill;
-import android.annotation.TargetApi;
import android.content.ComponentName;
import android.content.Context;
import android.graphics.Rect;
@@ -13,6 +12,7 @@ import android.view.View;
import android.view.autofill.AutofillManager;
import android.view.autofill.AutofillValue;
+import androidx.annotation.RequiresApi;
import androidx.annotation.VisibleForTesting;
import org.chromium.base.CollectionUtil;
@@ -24,7 +24,7 @@ import java.util.ArrayList;
/**
* The class to call Android's AutofillManager.
*/
-@TargetApi(Build.VERSION_CODES.O)
+@RequiresApi(Build.VERSION_CODES.O)
public class AutofillManagerWrapper {
// Don't change TAG, it is used for runtime log.
// NOTE: As a result of the above, the tag below still references the name of this class from
diff --git a/chromium/components/android_autofill/browser/java/src/org/chromium/components/autofill/AutofillProvider.java b/chromium/components/android_autofill/browser/java/src/org/chromium/components/autofill/AutofillProvider.java
index 9cf929c4381..280e62e3f09 100644
--- a/chromium/components/android_autofill/browser/java/src/org/chromium/components/autofill/AutofillProvider.java
+++ b/chromium/components/android_autofill/browser/java/src/org/chromium/components/autofill/AutofillProvider.java
@@ -4,7 +4,6 @@
package org.chromium.components.autofill;
-import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Matrix;
import android.graphics.Rect;
@@ -17,6 +16,7 @@ import android.view.ViewGroup;
import android.view.ViewStructure;
import android.view.autofill.AutofillValue;
+import androidx.annotation.RequiresApi;
import androidx.annotation.VisibleForTesting;
import org.chromium.base.ContextUtils;
@@ -57,7 +57,7 @@ import java.util.ArrayList;
* VerifiesOnO since it causes class verification errors, see crbug.com/991851.
*/
@VerifiesOnO
-@TargetApi(Build.VERSION_CODES.O)
+@RequiresApi(Build.VERSION_CODES.O)
@JNINamespace("autofill")
public class AutofillProvider {
private static final String TAG = "AutofillProvider";
diff --git a/chromium/components/android_autofill/browser/java/src/org/chromium/components/autofill_public/ViewType.java b/chromium/components/android_autofill/browser/java/src/org/chromium/components/autofill_public/ViewType.java
index fe0d9e18e28..bc411e37c71 100644
--- a/chromium/components/android_autofill/browser/java/src/org/chromium/components/autofill_public/ViewType.java
+++ b/chromium/components/android_autofill/browser/java/src/org/chromium/components/autofill_public/ViewType.java
@@ -4,12 +4,13 @@
package org.chromium.components.autofill_public;
-import android.annotation.TargetApi;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.view.autofill.AutofillId;
+import androidx.annotation.RequiresApi;
+
import org.chromium.base.annotations.VerifiesOnO;
/**
@@ -18,7 +19,7 @@ import org.chromium.base.annotations.VerifiesOnO;
* components/autofill/core/browser/field_types.cc. Note that the list of possibly returned strings
* can and will change in the future.
*/
-@TargetApi(Build.VERSION_CODES.O)
+@RequiresApi(Build.VERSION_CODES.O)
@VerifiesOnO
public class ViewType implements Parcelable {
/**
diff --git a/chromium/components/android_autofill/browser/test_support/java/src/org/chromium/components/autofill/AutofillProviderTestHelper.java b/chromium/components/android_autofill/browser/test_support/java/src/org/chromium/components/autofill/AutofillProviderTestHelper.java
index 5db6332bce7..e233f1296f4 100644
--- a/chromium/components/android_autofill/browser/test_support/java/src/org/chromium/components/autofill/AutofillProviderTestHelper.java
+++ b/chromium/components/android_autofill/browser/test_support/java/src/org/chromium/components/autofill/AutofillProviderTestHelper.java
@@ -4,9 +4,10 @@
package org.chromium.components.autofill;
-import android.annotation.TargetApi;
import android.os.Build;
+import androidx.annotation.RequiresApi;
+
import org.chromium.base.annotations.JNINamespace;
import org.chromium.base.annotations.NativeMethods;
import org.chromium.base.annotations.VerifiesOnO;
@@ -16,7 +17,7 @@ import org.chromium.content_public.browser.WebContents;
* The help class for Autofill Provider test to access the native code.
*/
@VerifiesOnO
-@TargetApi(Build.VERSION_CODES.O)
+@RequiresApi(Build.VERSION_CODES.O)
@JNINamespace("autofill")
public class AutofillProviderTestHelper {
/**
diff --git a/chromium/components/app_constants/BUILD.gn b/chromium/components/app_constants/BUILD.gn
new file mode 100644
index 00000000000..3d42d53ff4e
--- /dev/null
+++ b/chromium/components/app_constants/BUILD.gn
@@ -0,0 +1,16 @@
+# Copyright 2022 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.
+
+component("app_constants") {
+ output_name = "app_constants_lib"
+
+ sources = [
+ "constants.cc",
+ "constants.h",
+ ]
+
+ defines = [ "IS_APP_CONSTANTS_IMPL" ]
+
+ deps = [ "//base" ]
+}
diff --git a/chromium/components/app_constants/DIR_METADATA b/chromium/components/app_constants/DIR_METADATA
new file mode 100644
index 00000000000..0f723e54df1
--- /dev/null
+++ b/chromium/components/app_constants/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//apps/COMMON_METADATA"
diff --git a/chromium/components/app_constants/OWNERS b/chromium/components/app_constants/OWNERS
new file mode 100644
index 00000000000..6ccbbd6c6d0
--- /dev/null
+++ b/chromium/components/app_constants/OWNERS
@@ -0,0 +1 @@
+file://apps/OWNERS
diff --git a/chromium/components/app_constants/constants.cc b/chromium/components/app_constants/constants.cc
new file mode 100644
index 00000000000..51fb72c3113
--- /dev/null
+++ b/chromium/components/app_constants/constants.cc
@@ -0,0 +1,14 @@
+// Copyright 2022 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.
+
+#include "components/app_constants/constants.h"
+
+namespace app_constants {
+
+const char kChromeAppId[] = "mgndgikekgjfcpckkfioiadnlibdjbkf";
+
+// Generated by: echo "lacros-chrome" | sha256sum | head -c32 | tr 0-9a-f a-p
+const char kLacrosAppId[] = "jaimifaeiicidiikhmjedcgdimealfbh";
+
+} // namespace app_constants
diff --git a/chromium/components/app_constants/constants.h b/chromium/components/app_constants/constants.h
new file mode 100644
index 00000000000..47da2ba79c5
--- /dev/null
+++ b/chromium/components/app_constants/constants.h
@@ -0,0 +1,26 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_APP_CONSTANTS_CONSTANTS_H_
+#define COMPONENTS_APP_CONSTANTS_CONSTANTS_H_
+
+#include "base/component_export.h"
+
+namespace app_constants {
+
+// App IDs are a unique internal identifier for apps on Chrome OS. For
+// historical reasons, they are a SHA hash of some uniquely identifying
+// constant associated with an app, transposed from the [0-9a-f] range to [a-p]
+// (the same format used by Chrome's extension IDs). The following are app IDs
+// for the Chrome browser application on Chrome OS.
+
+// The ID of the Chrome component application as part of ash.
+COMPONENT_EXPORT(APP_CONSTANTS) extern const char kChromeAppId[];
+
+// The ID of the Lacros Chrome browser application that runs outside of ash.
+COMPONENT_EXPORT(APP_CONSTANTS) extern const char kLacrosAppId[];
+
+} // namespace app_constants
+
+#endif // COMPONENTS_APP_CONSTANTS_CONSTANTS_H_
diff --git a/chromium/components/app_restore/BUILD.gn b/chromium/components/app_restore/BUILD.gn
index efc2efec4a6..b037f42e487 100644
--- a/chromium/components/app_restore/BUILD.gn
+++ b/chromium/components/app_restore/BUILD.gn
@@ -31,6 +31,10 @@ component("app_restore") {
"full_restore_save_handler.h",
"full_restore_utils.cc",
"full_restore_utils.h",
+ "lacros_read_handler.cc",
+ "lacros_read_handler.h",
+ "lacros_save_handler.cc",
+ "lacros_save_handler.h",
"restore_data.cc",
"restore_data.h",
"window_info.cc",
@@ -50,10 +54,11 @@ component("app_restore") {
"//components/services/app_service/public/cpp:intents",
"//components/services/app_service/public/mojom",
"//components/sessions:session_id",
- "//extensions/common:common_constants",
"//ui/aura",
"//ui/views",
]
+
+ deps = [ "//components/app_constants" ]
}
source_set("unit_tests") {
@@ -67,8 +72,10 @@ source_set("unit_tests") {
deps = [
":app_restore",
+ "//components/app_constants",
"//content/test:test_support",
"//testing/gtest",
"//ui/aura:test_support",
+ "//ui/views:test_support",
]
}
diff --git a/chromium/components/app_restore/DEPS b/chromium/components/app_restore/DEPS
index a371940521e..48bc9b6b18a 100644
--- a/chromium/components/app_restore/DEPS
+++ b/chromium/components/app_restore/DEPS
@@ -1,10 +1,10 @@
include_rules = [
"+ash/constants",
"+chromeos/ui/base/window_state_type.h",
+ "+components/app_constants/constants.h",
"+components/account_id/account_id.h",
"+components/services/app_service/public",
"+components/sessions/core/session_id.h",
"+content/public/test",
- "+extensions/common/constants.h",
"+ui",
-] \ No newline at end of file
+]
diff --git a/chromium/components/app_restore/app_restore_data.cc b/chromium/components/app_restore/app_restore_data.cc
index b33b5eb8782..e79bfc9fddc 100644
--- a/chromium/components/app_restore/app_restore_data.cc
+++ b/chromium/components/app_restore/app_restore_data.cc
@@ -66,13 +66,13 @@ base::Value ConvertUintToValue(uint32_t number) {
// true.
absl::optional<bool> GetBoolValueFromDict(const base::DictionaryValue& dict,
const std::string& key_name) {
- return dict.HasKey(key_name) ? dict.FindBoolKey(key_name) : absl::nullopt;
+ return dict.FindBoolKey(key_name);
}
// Gets int value from base::DictionaryValue, e.g. { "key": 100 } returns 100.
absl::optional<int32_t> GetIntValueFromDict(const base::DictionaryValue& dict,
const std::string& key_name) {
- return dict.HasKey(key_name) ? dict.FindIntKey(key_name) : absl::nullopt;
+ return dict.FindIntKey(key_name);
}
// Gets uint32_t value from base::DictionaryValue, e.g. { "key": "123" } returns
@@ -80,7 +80,7 @@ absl::optional<int32_t> GetIntValueFromDict(const base::DictionaryValue& dict,
absl::optional<uint32_t> GetUIntValueFromDict(const base::DictionaryValue& dict,
const std::string& key_name) {
uint32_t result = 0;
- if (!dict.HasKey(key_name) ||
+ if (!dict.FindKey(key_name) ||
!base::StringToUint(dict.FindStringKey(key_name)->c_str(), &result)) {
return absl::nullopt;
}
@@ -90,8 +90,6 @@ absl::optional<uint32_t> GetUIntValueFromDict(const base::DictionaryValue& dict,
absl::optional<std::string> GetStringValueFromDict(
const base::DictionaryValue& dict,
const std::string& key_name) {
- if (!dict.HasKey(key_name))
- return absl::nullopt;
const std::string* value = dict.FindStringKey(key_name);
return value ? absl::optional<std::string>(*value) : absl::nullopt;
}
@@ -100,10 +98,8 @@ absl::optional<std::u16string> GetU16StringValueFromDict(
const base::DictionaryValue& dict,
const std::string& key_name) {
std::u16string result;
- if (!dict.HasKey(key_name))
- return absl::nullopt;
const std::string* value = dict.FindStringKey(key_name);
- if (!base::UTF8ToUTF16(value->c_str(), value->length(), &result))
+ if (!value || !base::UTF8ToUTF16(value->c_str(), value->length(), &result))
return absl::nullopt;
return result;
}
@@ -112,9 +108,6 @@ absl::optional<std::u16string> GetU16StringValueFromDict(
// returns 22000000.
absl::optional<int64_t> GetDisplayIdFromDict(
const base::DictionaryValue& dict) {
- if (!dict.HasKey(kDisplayIdKey))
- return absl::nullopt;
-
const std::string* display_id_str = dict.FindStringKey(kDisplayIdKey);
int64_t display_id_value;
if (display_id_str &&
@@ -128,17 +121,14 @@ absl::optional<int64_t> GetDisplayIdFromDict(
// Gets urls from the dictionary value.
absl::optional<std::vector<GURL>> GetUrlsFromDict(
const base::DictionaryValue& dict) {
- if (!dict.HasKey(kUrlsKey))
- return absl::nullopt;
-
const base::Value* urls_path_value = dict.FindListKey(kUrlsKey);
if (!urls_path_value || !urls_path_value->is_list() ||
- urls_path_value->GetList().empty()) {
+ urls_path_value->GetListDeprecated().empty()) {
return absl::nullopt;
}
std::vector<GURL> url_paths;
- for (const auto& item : urls_path_value->GetList()) {
+ for (const auto& item : urls_path_value->GetListDeprecated()) {
if (item.GetString().empty())
continue;
GURL url(item.GetString());
@@ -155,16 +145,13 @@ absl::optional<std::vector<GURL>> GetUrlsFromDict(
// std::vector<base::FilePath>{"aa.cc", "bb.h", ...}.
absl::optional<std::vector<base::FilePath>> GetFilePathsFromDict(
const base::DictionaryValue& dict) {
- if (!dict.HasKey(kFilePathsKey))
- return absl::nullopt;
-
const base::Value* file_paths_value = dict.FindListKey(kFilePathsKey);
if (!file_paths_value || !file_paths_value->is_list() ||
- file_paths_value->GetList().empty())
+ file_paths_value->GetListDeprecated().empty())
return absl::nullopt;
std::vector<base::FilePath> file_paths;
- for (const auto& item : file_paths_value->GetList()) {
+ for (const auto& item : file_paths_value->GetListDeprecated()) {
if (item.GetString().empty())
continue;
file_paths.push_back(base::FilePath(item.GetString()));
@@ -177,17 +164,14 @@ absl::optional<std::vector<base::FilePath>> GetFilePathsFromDict(
// gfx::Size(100, 300).
absl::optional<gfx::Size> GetSizeFromDict(const base::DictionaryValue& dict,
const std::string& key_name) {
- if (!dict.HasKey(key_name))
- return absl::nullopt;
-
const base::Value* size_value = dict.FindListKey(key_name);
if (!size_value || !size_value->is_list() ||
- size_value->GetList().size() != 2) {
+ size_value->GetListDeprecated().size() != 2) {
return absl::nullopt;
}
std::vector<int> size;
- for (const auto& item : size_value->GetList())
+ for (const auto& item : size_value->GetListDeprecated())
size.push_back(item.GetInt());
return gfx::Size(size[0], size[1]);
@@ -198,15 +182,13 @@ absl::optional<gfx::Size> GetSizeFromDict(const base::DictionaryValue& dict,
absl::optional<gfx::Rect> GetBoundsRectFromDict(
const base::DictionaryValue& dict,
const std::string& key_name) {
- if (!dict.HasKey(key_name))
- return absl::nullopt;
-
const base::Value* rect_value = dict.FindListKey(key_name);
- if (!rect_value || !rect_value->is_list() || rect_value->GetList().empty())
+ if (!rect_value || !rect_value->is_list() ||
+ rect_value->GetListDeprecated().empty())
return absl::nullopt;
std::vector<int> rect;
- for (const auto& item : rect_value->GetList())
+ for (const auto& item : rect_value->GetListDeprecated())
rect.push_back(item.GetInt());
if (rect.size() != 4)
@@ -219,7 +201,7 @@ absl::optional<gfx::Rect> GetBoundsRectFromDict(
// 2 } returns WindowStateType::kMinimized.
absl::optional<chromeos::WindowStateType> GetWindowStateTypeFromDict(
const base::DictionaryValue& dict) {
- return dict.HasKey(kWindowStateTypeKey)
+ return dict.FindKey(kWindowStateTypeKey)
? absl::make_optional(static_cast<chromeos::WindowStateType>(
dict.FindIntKey(kWindowStateTypeKey).value()))
: absl::nullopt;
@@ -227,7 +209,7 @@ absl::optional<chromeos::WindowStateType> GetWindowStateTypeFromDict(
absl::optional<ui::WindowShowState> GetPreMinimizedShowStateTypeFromDict(
const base::DictionaryValue& dict) {
- return dict.HasKey(kPreMinimizedShowStateTypeKey)
+ return dict.FindKey(kPreMinimizedShowStateTypeKey)
? absl::make_optional(static_cast<ui::WindowShowState>(
dict.FindIntKey(kPreMinimizedShowStateTypeKey).value()))
: absl::nullopt;
@@ -268,7 +250,7 @@ AppRestoreData::AppRestoreData(base::Value&& value) {
primary_color = GetUIntValueFromDict(*data_dict, kPrimaryColorKey);
status_bar_color = GetUIntValueFromDict(*data_dict, kStatusBarColorKey);
- if (data_dict->HasKey(kIntentKey)) {
+ if (data_dict->FindKey(kIntentKey)) {
intent = apps_util::ConvertValueToIntent(
std::move(*data_dict->FindDictKey(kIntentKey)));
}
diff --git a/chromium/components/app_restore/app_restore_utils.cc b/chromium/components/app_restore/app_restore_utils.cc
index 68ced6dd0da..10bf84efbdc 100644
--- a/chromium/components/app_restore/app_restore_utils.cc
+++ b/chromium/components/app_restore/app_restore_utils.cc
@@ -11,6 +11,7 @@
#include "components/app_restore/features.h"
#include "components/app_restore/full_restore_info.h"
#include "components/app_restore/full_restore_read_handler.h"
+#include "components/app_restore/full_restore_save_handler.h"
#include "components/app_restore/window_info.h"
#include "components/app_restore/window_properties.h"
#include "ui/aura/client/aura_constants.h"
@@ -19,6 +20,10 @@
namespace app_restore {
namespace {
+const char kCrxAppPrefix[] = "_crx_";
+
+static int32_t session_id_counter = kArcSessionIdOffsetForRestoredLaunching;
+
// Always use the full restore ARC data if ARC apps for desks templates is not
// enabled.
bool ShouldUseFullRestoreArcData() {
@@ -30,6 +35,16 @@ bool ShouldUseFullRestoreArcData() {
} // namespace
+bool IsArcWindow(aura::Window* window) {
+ return window->GetProperty(aura::client::kAppType) ==
+ static_cast<int>(ash::AppType::ARC_APP);
+}
+
+bool IsLacrosWindow(aura::Window* window) {
+ return window->GetProperty(aura::client::kAppType) ==
+ static_cast<int>(ash::AppType::LACROS);
+}
+
void ApplyProperties(app_restore::WindowInfo* window_info,
ui::PropertyHandler* property_handler) {
DCHECK(window_info);
@@ -61,9 +76,6 @@ void ApplyProperties(app_restore::WindowInfo* window_info,
void ModifyWidgetParams(int32_t restore_window_id,
views::Widget::InitParams* out_params) {
- if (!full_restore::features::IsFullRestoreEnabled())
- return;
-
DCHECK(out_params);
const bool is_arc_app =
@@ -125,9 +137,6 @@ void ModifyWidgetParams(int32_t restore_window_id,
}
int32_t FetchRestoreWindowId(const std::string& app_id) {
- if (!full_restore::features::IsFullRestoreEnabled())
- return 0;
-
// If full restore is not running, check if desk templates can get a viable
// window id, otherwise default to checking full restore.
auto* full_restore_read_handler =
@@ -143,12 +152,14 @@ int32_t FetchRestoreWindowId(const std::string& app_id) {
->FetchRestoreWindowId(app_id);
}
-int32_t GetArcSessionId() {
- if (ShouldUseFullRestoreArcData()) {
- return full_restore::FullRestoreReadHandler::GetInstance()
- ->GetArcSessionId();
+int32_t CreateArcSessionId() {
+ // ARC session id offset start counting from a large number. When the counter
+ // overflow, it will less the start number.
+ if (session_id_counter < kArcSessionIdOffsetForRestoredLaunching) {
+ LOG(WARNING) << "ARC session id is overflow: " << session_id_counter;
+ session_id_counter = kArcSessionIdOffsetForRestoredLaunching;
}
- return DeskTemplateReadHandler::Get()->GetArcSessionId();
+ return ++session_id_counter;
}
void SetArcSessionIdForWindowId(int32_t arc_session_id, int32_t window_id) {
@@ -161,9 +172,6 @@ void SetArcSessionIdForWindowId(int32_t arc_session_id, int32_t window_id) {
}
int32_t GetArcRestoreWindowIdForTaskId(int32_t task_id) {
- if (!full_restore::features::IsFullRestoreEnabled())
- return 0;
-
if (ShouldUseFullRestoreArcData()) {
return full_restore::FullRestoreReadHandler::GetInstance()
->GetArcRestoreWindowIdForTaskId(task_id);
@@ -173,9 +181,6 @@ int32_t GetArcRestoreWindowIdForTaskId(int32_t task_id) {
}
int32_t GetArcRestoreWindowIdForSessionId(int32_t session_id) {
- if (!full_restore::features::IsFullRestoreEnabled())
- return 0;
-
if (ShouldUseFullRestoreArcData()) {
return full_restore::FullRestoreReadHandler::GetInstance()
->GetArcRestoreWindowIdForSessionId(session_id);
@@ -184,4 +189,36 @@ int32_t GetArcRestoreWindowIdForSessionId(int32_t session_id) {
session_id);
}
+std::string GetAppIdFromAppName(const std::string& app_name) {
+ std::string prefix(kCrxAppPrefix);
+ if (app_name.substr(0, prefix.length()) != prefix)
+ return std::string();
+ return app_name.substr(prefix.length());
+}
+
+const std::string GetLacrosWindowId(aura::Window* window) {
+ const std::string* lacros_window_id =
+ window->GetProperty(app_restore::kLacrosWindowId);
+ DCHECK(lacros_window_id);
+ return *lacros_window_id;
+}
+
+int32_t GetLacrosRestoreWindowId(const std::string& lacros_window_id) {
+ return full_restore::FullRestoreReadHandler::GetInstance()
+ ->GetLacrosRestoreWindowId(lacros_window_id);
+}
+
+void OnLacrosWindowAdded(aura::Window* const window,
+ uint32_t browser_session_id,
+ uint32_t restored_browser_session_id) {
+ if (!IsLacrosWindow(window))
+ return;
+
+ full_restore::FullRestoreReadHandler::GetInstance()
+ ->OnLacrosBrowserWindowAdded(window, restored_browser_session_id);
+
+ full_restore::FullRestoreSaveHandler::GetInstance()
+ ->OnLacrosBrowserWindowAdded(window, browser_session_id);
+}
+
} // namespace app_restore
diff --git a/chromium/components/app_restore/app_restore_utils.h b/chromium/components/app_restore/app_restore_utils.h
index 2e493c82f3d..1194d8dc239 100644
--- a/chromium/components/app_restore/app_restore_utils.h
+++ b/chromium/components/app_restore/app_restore_utils.h
@@ -24,6 +24,12 @@ constexpr int32_t kArcSessionIdOffsetForRestoredLaunching = 1000000000;
// restore window id as -1, to add the ARC app window to the hidden container.
constexpr int32_t kParentToHiddenContainer = -1;
+// Returns true if `window` is an ARC window. Otherwise, returns false.
+bool IsArcWindow(aura::Window* window);
+
+// Returns true if `window` is a Lacros window. Otherwise, returns false.
+bool IsLacrosWindow(aura::Window* window);
+
// Applies properties from `window_info` to the given `property_handler`.
// This is called from `GetWindowInfo()` when window is
// created, or from the ArcReadHandler when a task is ready for a full
@@ -45,7 +51,7 @@ int32_t FetchRestoreWindowId(const std::string& app_id);
// Generates the ARC session id (1,000,000,001 - INT_MAX) for restored ARC
// apps.
-COMPONENT_EXPORT(APP_RESTORE) int32_t GetArcSessionId();
+COMPONENT_EXPORT(APP_RESTORE) int32_t CreateArcSessionId();
// Sets `arc_session_id` for `window_id`. `arc session id` is assigned when ARC
// apps are restored.
@@ -60,6 +66,25 @@ int32_t GetArcRestoreWindowIdForTaskId(int32_t task_id);
COMPONENT_EXPORT(APP_RESTORE)
int32_t GetArcRestoreWindowIdForSessionId(int32_t session_id);
+// Remove the "_crx_" prefix from a given `app_name` to get the app id.
+COMPONENT_EXPORT(APP_RESTORE)
+std::string GetAppIdFromAppName(const std::string& app_name);
+
+// Returns the Lacros window id for `window`.
+const std::string GetLacrosWindowId(aura::Window* window);
+
+// Returns the restore window id for the Lacros window with `lacros_window_id`.
+COMPONENT_EXPORT(APP_RESTORE)
+int32_t GetLacrosRestoreWindowId(const std::string& lacros_window_id);
+
+// Invoked when Lacros window is created. `browser_session_id` is the
+// current browser session id. `restored_browser_session_id` is the restored
+// browser session id.
+COMPONENT_EXPORT(APP_RESTORE)
+void OnLacrosWindowAdded(aura::Window* const window,
+ uint32_t browser_session_id,
+ uint32_t restored_browser_session_id);
+
} // namespace app_restore
#endif // COMPONENTS_APP_RESTORE_APP_RESTORE_UTILS_H_
diff --git a/chromium/components/app_restore/arc_read_handler.cc b/chromium/components/app_restore/arc_read_handler.cc
index c8fa7f40f42..fb679158ee6 100644
--- a/chromium/components/app_restore/arc_read_handler.cc
+++ b/chromium/components/app_restore/arc_read_handler.cc
@@ -160,15 +160,6 @@ int32_t ArcReadHandler::GetArcRestoreWindowIdForSessionId(int32_t session_id) {
return it == session_id_to_window_id_.end() ? 0 : it->second;
}
-int32_t ArcReadHandler::GetArcSessionId() {
- if (session_id_ < kArcSessionIdOffsetForRestoredLaunching) {
- LOG(WARNING) << "ARC session id is overflow: " << session_id_;
- session_id_ = kArcSessionIdOffsetForRestoredLaunching;
- }
-
- return ++session_id_;
-}
-
void ArcReadHandler::SetArcSessionIdForWindowId(int32_t session_id,
int32_t window_id) {
DCHECK_GT(session_id, kArcSessionIdOffsetForRestoredLaunching);
@@ -215,7 +206,7 @@ void ArcReadHandler::UpdateWindowCandidates(int32_t task_id,
// Remove the window from the hidden container.
if ((*window_it)->GetProperty(kParentToHiddenContainerKey)) {
full_restore::FullRestoreInfo::GetInstance()
- ->OnARCTaskReadyForUnparentedWindow(*window_it);
+ ->OnParentWindowToValidContainer(*window_it);
}
arc_window_candidates_.erase(*window_it);
diff --git a/chromium/components/app_restore/arc_read_handler.h b/chromium/components/app_restore/arc_read_handler.h
index 339fcf7c97b..929e0cb82c8 100644
--- a/chromium/components/app_restore/arc_read_handler.h
+++ b/chromium/components/app_restore/arc_read_handler.h
@@ -28,6 +28,23 @@ struct WindowInfo;
// ArcReadHandler is a helper class for a Delegate to read the app and window
// info of ARC apps, which have special cases, e.g. ARC task creation, ARC
// session id, etc.
+//
+// Android is responsible for restoring ARC window bounds, so full restore won't
+// restore window bounds, but restore activation_index, desk_id, window_state,
+// etc, when the widget has initialized by calling OnWidgetInitialized. For
+// ghost windows, when the ghost window is created, all window properties are
+// restored by ghost window.
+//
+// Task id is saved as the window id. So only when the task id is received, the
+// window can be restored. Task id and window init are two separate threads, so
+// there could be 2 scenarios:
+// 1. Window is initialized first, then `window` is added to the hidden
+// container, and saved in `arc_window_candidates_`. When the task is created,
+// OnTaskCreated callback applies the restore window properties, and remove the
+// window from the hidden container.
+// 2. Task is created first, then Window is initialized. So before `window` is
+// initialized, ModifyWidgetParams is called to apply the restore window
+// properties, and when `window` is initialized, it can be restored directly.
class COMPONENT_EXPORT(APP_RESTORE) ArcReadHandler {
public:
// A delegate class which allows an owner of ArcReadHandler to have some
@@ -98,10 +115,6 @@ class COMPONENT_EXPORT(APP_RESTORE) ArcReadHandler {
// Returns the restore window id for the ARC app's `session_id`.
int32_t GetArcRestoreWindowIdForSessionId(int32_t session_id);
- // Generates the ARC session id (1,000,000,001 - INT_MAX) for restored ARC
- // apps.
- int32_t GetArcSessionId();
-
// Sets |session_id| for |window_id| to |session_id_to_window_id_|.
// |session_id| is assigned when ARC apps are restored.
void SetArcSessionIdForWindowId(int32_t session_id, int32_t window_id);
@@ -123,8 +136,6 @@ class COMPONENT_EXPORT(APP_RESTORE) ArcReadHandler {
// is saved in the window property |kRestoreWindowIdKey|.
std::map<int32_t, std::string> window_id_to_app_id_;
- int32_t session_id_ = kArcSessionIdOffsetForRestoredLaunching;
-
// The map from the arc session id to the window id.
std::map<int32_t, int32_t> session_id_to_window_id_;
diff --git a/chromium/components/app_restore/arc_save_handler.h b/chromium/components/app_restore/arc_save_handler.h
index 576c03409df..d3cecc944e2 100644
--- a/chromium/components/app_restore/arc_save_handler.h
+++ b/chromium/components/app_restore/arc_save_handler.h
@@ -34,6 +34,19 @@ namespace full_restore {
// ArcSaveHandler is a helper class for FullRestoreSaveHandler to handle ARC app
// windows special cases, e.g. ARC task creation, ARC session id, etc.
+//
+// Task id is saved as the window id. Session id is generated when launch the
+// ARC app, and sent back as a parameter of OnTaskCreated, to connect the launch
+// parameters with the task id. `session_id_to_app_launch_info_` saves the
+// mapping from the session id to the launch parameter.
+//
+// When the task is created, in OnTaskCreated callback, get the launch info from
+// `session_id_to_app_launch_info_` with `session id`, and save the launch info
+// using the task is as the window id.
+//
+// For ghost window, session id is used as the the window id before the task is
+// created. When the task is created, window id is modified to use the task id
+// as the window id.
class COMPONENT_EXPORT(APP_RESTORE) ArcSaveHandler {
public:
using AppLaunchInfoPtr = std::unique_ptr<app_restore::AppLaunchInfo>;
@@ -74,7 +87,7 @@ class COMPONENT_EXPORT(APP_RESTORE) ArcSaveHandler {
uint32_t primary_color,
uint32_t status_bar_color);
- // Generates the ARC session id (0 - 1,000,000,000) for ARC apps.
+ // Generates the ARC session id (0 - 1,000,000,000) for save ARC apps.
int32_t GetArcSessionId();
// Returns the app id that associates with |window|.
diff --git a/chromium/components/app_restore/desk_template_read_handler.cc b/chromium/components/app_restore/desk_template_read_handler.cc
index aead62f8f13..ae80470b6d4 100644
--- a/chromium/components/app_restore/desk_template_read_handler.cc
+++ b/chromium/components/app_restore/desk_template_read_handler.cc
@@ -11,6 +11,7 @@
#include "base/no_destructor.h"
#include "components/app_restore/app_launch_info.h"
#include "components/app_restore/app_restore_data.h"
+#include "components/app_restore/app_restore_utils.h"
#include "components/app_restore/restore_data.h"
#include "components/app_restore/window_info.h"
#include "components/app_restore/window_properties.h"
@@ -100,10 +101,6 @@ void DeskTemplateReadHandler::SetNextRestoreWindowIdForChromeApp(
restore_data_->SetNextRestoreWindowIdForChromeApp(app_id);
}
-int32_t DeskTemplateReadHandler::GetArcSessionId() {
- return arc_read_handler_ ? arc_read_handler_->GetArcSessionId() : 0;
-}
-
void DeskTemplateReadHandler::SetArcSessionIdForWindowId(int32_t arc_session_id,
int32_t window_id) {
if (arc_read_handler_)
@@ -127,14 +124,9 @@ int32_t DeskTemplateReadHandler::GetArcRestoreWindowIdForSessionId(
void DeskTemplateReadHandler::OnWindowInitialized(aura::Window* window) {
// If there isn't restore data for ARC apps, we don't need to handle ARC app
// windows restoration.
- if (!arc_read_handler_)
+ if (!arc_read_handler_ || !IsArcWindow(window))
return;
- if (window->GetProperty(aura::client::kAppType) !=
- static_cast<int>(ash::AppType::ARC_APP)) {
- return;
- }
-
const int32_t window_id = window->GetProperty(kRestoreWindowIdKey);
if (window_id == app_restore::kParentToHiddenContainer ||
arc_read_handler_->HasRestoreData(window_id)) {
diff --git a/chromium/components/app_restore/desk_template_read_handler.h b/chromium/components/app_restore/desk_template_read_handler.h
index 76153ab0900..41568d4bd29 100644
--- a/chromium/components/app_restore/desk_template_read_handler.h
+++ b/chromium/components/app_restore/desk_template_read_handler.h
@@ -60,10 +60,6 @@ class COMPONENT_EXPORT(APP_RESTORE) DeskTemplateReadHandler
// chrome app with `app_id`.
void SetNextRestoreWindowIdForChromeApp(const std::string& app_id);
- // Generates the ARC session id (1,000,000,001 - INT_MAX) for restored ARC
- // apps.
- int32_t GetArcSessionId();
-
// Sets `arc_session_id` for `window_id`. `arc session id` is assigned when
// ARC apps are restored.
void SetArcSessionIdForWindowId(int32_t arc_session_id, int32_t window_id);
diff --git a/chromium/components/app_restore/features.cc b/chromium/components/app_restore/features.cc
index 9b114cc536c..c4a294b6fab 100644
--- a/chromium/components/app_restore/features.cc
+++ b/chromium/components/app_restore/features.cc
@@ -10,16 +10,22 @@ namespace features {
const base::Feature kArcGhostWindow{"ArcGhostWindow",
base::FEATURE_ENABLED_BY_DEFAULT};
-const base::Feature kFullRestore{"FullRestore",
- base::FEATURE_ENABLED_BY_DEFAULT};
+const base::Feature kArcWindowPredictor{"ArcWindowPredictor",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+const base::Feature kFullRestoreForLacros{"FullRestoreForLacros",
+ base::FEATURE_DISABLED_BY_DEFAULT};
bool IsArcGhostWindowEnabled() {
- return IsFullRestoreEnabled() &&
- base::FeatureList::IsEnabled(kArcGhostWindow);
+ return base::FeatureList::IsEnabled(kArcGhostWindow);
+}
+
+bool IsArcWindowPredictorEnabled() {
+ return base::FeatureList::IsEnabled(kArcWindowPredictor);
}
-bool IsFullRestoreEnabled() {
- return base::FeatureList::IsEnabled(kFullRestore);
+bool IsFullRestoreForLacrosEnabled() {
+ return base::FeatureList::IsEnabled(kFullRestoreForLacros);
}
} // namespace features
diff --git a/chromium/components/app_restore/features.h b/chromium/components/app_restore/features.h
index 7528a1371e1..e0d35ae562a 100644
--- a/chromium/components/app_restore/features.h
+++ b/chromium/components/app_restore/features.h
@@ -15,13 +15,19 @@ namespace features {
// full restore process.
COMPONENT_EXPORT(APP_RESTORE) extern const base::Feature kArcGhostWindow;
-// Enables the full restore feature. If this is enabled, we will restore apps
-// and app windows after a crash or reboot.
-COMPONENT_EXPORT(APP_RESTORE) extern const base::Feature kFullRestore;
+// Enables the window state and bounds predictor and full ghost window for ARC++
+// apps.
+COMPONENT_EXPORT(APP_RESTORE) extern const base::Feature kArcWindowPredictor;
+
+// Enables the full restore for Lacros feature. If this is enabled, we will
+// restore apps and app windows opened with Lacros after a crash or reboot.
+COMPONENT_EXPORT(APP_RESTORE) extern const base::Feature kFullRestoreForLacros;
COMPONENT_EXPORT(APP_RESTORE) bool IsArcGhostWindowEnabled();
-COMPONENT_EXPORT(APP_RESTORE) bool IsFullRestoreEnabled();
+COMPONENT_EXPORT(APP_RESTORE) bool IsArcWindowPredictorEnabled();
+
+COMPONENT_EXPORT(APP_RESTORE) bool IsFullRestoreForLacrosEnabled();
} // namespace features
} // namespace full_restore
diff --git a/chromium/components/app_restore/full_restore_info.cc b/chromium/components/app_restore/full_restore_info.cc
index ce2c5e4d32a..0a449a57fd5 100644
--- a/chromium/components/app_restore/full_restore_info.cc
+++ b/chromium/components/app_restore/full_restore_info.cc
@@ -79,9 +79,9 @@ void FullRestoreInfo::OnWidgetInitialized(views::Widget* widget) {
observer.OnWidgetInitialized(widget);
}
-void FullRestoreInfo::OnARCTaskReadyForUnparentedWindow(aura::Window* window) {
+void FullRestoreInfo::OnParentWindowToValidContainer(aura::Window* window) {
for (auto& observer : observers_)
- observer.OnARCTaskReadyForUnparentedWindow(window);
+ observer.OnParentWindowToValidContainer(window);
}
} // namespace full_restore
diff --git a/chromium/components/app_restore/full_restore_info.h b/chromium/components/app_restore/full_restore_info.h
index d53f0d9b26d..051fccdd28d 100644
--- a/chromium/components/app_restore/full_restore_info.h
+++ b/chromium/components/app_restore/full_restore_info.h
@@ -64,10 +64,14 @@ class COMPONENT_EXPORT(APP_RESTORE) FullRestoreInfo {
// ARC task also may not be created yet at this point.
virtual void OnWidgetInitialized(views::Widget* widget) {}
- // Called once a window which was created without an associated task is now
- // associated with a ARC task. Will not be called for non-ARC windows, or
- // ARC windows created with an associated task.
- virtual void OnARCTaskReadyForUnparentedWindow(aura::Window* window) {}
+ // Called when `window` is ready to be parented to a valid desk container.
+ //
+ // For Lacros windows, called when `window` is associated with a Lacros
+ // window id.
+ //
+ // For ARC app windows, called once a window which was created without an
+ // associated task is now associated with a ARC task.
+ virtual void OnParentWindowToValidContainer(aura::Window* window) {}
protected:
~Observer() override = default;
@@ -112,9 +116,9 @@ class COMPONENT_EXPORT(APP_RESTORE) FullRestoreInfo {
// Notifies observers that |widget| has been initialized.
void OnWidgetInitialized(views::Widget* widget);
- // Notifies observers that `window`, which previously had no associated task,
- // now has one.
- void OnARCTaskReadyForUnparentedWindow(aura::Window* window);
+ // Notifies observers that `window` is ready to be parented to a valid desk
+ // container..
+ void OnParentWindowToValidContainer(aura::Window* window);
private:
base::ObserverList<Observer> observers_;
diff --git a/chromium/components/app_restore/full_restore_read_and_save_unittest.cc b/chromium/components/app_restore/full_restore_read_and_save_unittest.cc
index 36d2bdf25c3..5bd2cad8d53 100644
--- a/chromium/components/app_restore/full_restore_read_and_save_unittest.cc
+++ b/chromium/components/app_restore/full_restore_read_and_save_unittest.cc
@@ -13,6 +13,7 @@
#include "base/test/bind.h"
#include "base/test/scoped_feature_list.h"
#include "base/timer/timer.h"
+#include "components/app_constants/constants.h"
#include "components/app_restore/app_launch_info.h"
#include "components/app_restore/app_restore_data.h"
#include "components/app_restore/features.h"
@@ -22,12 +23,16 @@
#include "components/app_restore/restore_data.h"
#include "components/app_restore/window_info.h"
#include "components/app_restore/window_properties.h"
+#include "components/services/app_service/public/mojom/types.mojom.h"
#include "content/public/test/browser_task_environment.h"
-#include "extensions/common/constants.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/aura/client/aura_constants.h"
+#include "ui/aura/test/aura_test_helper.h"
#include "ui/aura/test/test_windows.h"
#include "ui/aura/window.h"
+#include "ui/base/window_open_disposition.h"
+#include "ui/display/types/display_constants.h"
+#include "ui/views/test/test_views_delegate.h"
#include "url/gurl.h"
namespace full_restore {
@@ -58,6 +63,10 @@ constexpr char kHandlerId[] = "audio";
constexpr char kExampleUrl1[] = "https://www.example1.com";
constexpr char kExampleUrl2[] = "https://www.example2.com";
+constexpr char kLacrosWindowId[] = "123";
+
+constexpr uint32_t kBrowserSessionId = 56;
+
} // namespace
class FullRestoreReadHandlerTestApi {
@@ -148,6 +157,31 @@ class FullRestoreSaveHandlerTestApi {
void CheckArcTasks() { arc_save_handler()->CheckTasksForAppLaunching(); }
+ const LacrosSaveHandler* GetLacrosSaveHander() const {
+ DCHECK(save_handler_);
+ return save_handler_->lacros_save_handler_.get();
+ }
+
+ const std::map<std::string, LacrosSaveHandler::WindowData>&
+ GetLacrosWindowCandidates() const {
+ const auto* lacros_save_handler = GetLacrosSaveHander();
+ DCHECK(lacros_save_handler);
+ return lacros_save_handler->window_candidates_;
+ }
+
+ const std::map<std::string, std::string>& GetLacrosWindowIdToAppIdMap()
+ const {
+ const auto* lacros_save_handler = GetLacrosSaveHander();
+ DCHECK(lacros_save_handler);
+ return lacros_save_handler->lacros_window_id_to_app_id_;
+ }
+
+ int32_t GetLacrosWindowId(std::string lacros_window_id) const {
+ const auto& window_candidates = GetLacrosWindowCandidates();
+ auto it = window_candidates.find(lacros_window_id);
+ return it != window_candidates.end() ? it->second.window_id : -1;
+ }
+
void ClearRestoreData() {
save_handler_->profile_path_to_restore_data_.clear();
}
@@ -173,8 +207,10 @@ class FullRestoreReadAndSaveTest : public testing::Test {
delete;
void SetUp() override {
- scoped_feature_list_.InitAndEnableFeature(features::kFullRestore);
+ scoped_feature_list_.InitAndEnableFeature(features::kFullRestoreForLacros);
ASSERT_TRUE(tmp_dir_.CreateUniqueTempDir());
+
+ aura_test_helper_.SetUp();
}
void TearDown() override {
@@ -229,7 +265,7 @@ class FullRestoreReadAndSaveTest : public testing::Test {
std::vector<GURL> urls,
int32_t active_tab_index = 0) {
auto launch_info = std::make_unique<app_restore::AppLaunchInfo>(
- extension_misc::kChromeAppId, id);
+ app_constants::kChromeAppId, id);
launch_info->urls = urls;
launch_info->active_tab_index = active_tab_index;
SaveAppLaunchInfo(file_path, std::move(launch_info));
@@ -244,6 +280,43 @@ class FullRestoreReadAndSaveTest : public testing::Test {
SaveAppLaunchInfo(file_path, std::move(app_launch_info));
}
+ std::unique_ptr<views::Widget> CreateLacrosWidget(
+ const std::string& lacros_window_id) {
+ views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
+
+ params.bounds = gfx::Rect(5, 5, 20, 20);
+ params.context = aura_test_helper_.GetContext();
+ params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+
+ params.init_properties_container.SetProperty(
+ aura::client::kAppType, static_cast<int>(ash::AppType::LACROS));
+ params.init_properties_container.SetProperty(app_restore::kLacrosWindowId,
+ lacros_window_id);
+ auto widget = std::make_unique<views::Widget>();
+ widget->Init(std::move(params));
+
+ widget->Show();
+ return widget;
+ }
+
+ std::unique_ptr<aura::Window> CreateLacrosWindow(
+ const std::string& lacros_window_id) {
+ auto window = std::make_unique<aura::Window>(
+ nullptr, aura::client::WINDOW_TYPE_NORMAL);
+ window->SetProperty(aura::client::kAppType,
+ static_cast<int>(ash::AppType::LACROS));
+ window->SetProperty(app_restore::kLacrosWindowId,
+ std::string(kLacrosWindowId));
+ return window;
+ }
+
+ void SaveWindowInfo(aura::Window* window, int32_t activation_index) {
+ app_restore::WindowInfo window_info;
+ window_info.window = window;
+ window_info.activation_index = activation_index;
+ full_restore::SaveWindowInfo(window_info);
+ }
+
std::unique_ptr<aura::Window> CreateWindowInfo(
int32_t id,
int32_t index,
@@ -255,7 +328,7 @@ class FullRestoreReadAndSaveTest : public testing::Test {
window->SetProperty(aura::client::kAppType, static_cast<int>(app_type));
window->SetProperty(app_restore::kWindowIdKey, id);
window_info.activation_index = index;
- SaveWindowInfo(window_info);
+ full_restore::SaveWindowInfo(window_info);
return window;
}
@@ -305,6 +378,9 @@ class FullRestoreReadAndSaveTest : public testing::Test {
base::test::ScopedFeatureList scoped_feature_list_;
std::unique_ptr<app_restore::RestoreData> restore_data_;
+
+ views::TestViewsDelegate test_views_delegate_;
+ aura::test::AuraTestHelper aura_test_helper_;
};
TEST_F(FullRestoreReadAndSaveTest, ReadEmptyRestoreData) {
@@ -811,7 +887,7 @@ TEST_F(FullRestoreReadAndSaveTest, ReadBrowserRestoreData) {
ASSERT_TRUE(restore_data);
const auto& launch_list = restore_data->app_id_to_launch_list();
EXPECT_EQ(1u, launch_list.size());
- const auto launch_list_it = launch_list.find(extension_misc::kChromeAppId);
+ const auto launch_list_it = launch_list.find(app_constants::kChromeAppId);
EXPECT_TRUE(launch_list_it != launch_list.end());
EXPECT_EQ(1u, launch_list_it->second.size());
const auto app_restore_data_it = launch_list_it->second.find(kId1);
@@ -859,4 +935,218 @@ TEST_F(FullRestoreReadAndSaveTest, ReadChromeAppRestoreData) {
EXPECT_EQ(base::FilePath(kFilePath2), data->file_paths.value()[1]);
}
+// Verify the Lacros browser window is saved correctly when the window is
+// created first, then OnLacrosWindowAdded is called.
+TEST_F(FullRestoreReadAndSaveTest, LacrosBrowserWindowSavingCreateWindowFirst) {
+ FullRestoreSaveHandler* save_handler = GetSaveHandler();
+ FullRestoreSaveHandlerTestApi test_api(save_handler);
+
+ save_handler->SetPrimaryProfilePath(GetPath());
+ base::OneShotTimer* timer = save_handler->GetTimerForTesting();
+
+ const LacrosSaveHandler* lacros_save_handler = test_api.GetLacrosSaveHander();
+ ASSERT_TRUE(lacros_save_handler);
+
+ // Create a browser window first, then OnLacrosWindowAdded is called later.
+ auto widget = CreateLacrosWidget(kLacrosWindowId);
+ auto* window = widget->GetNativeWindow();
+ SaveWindowInfo(window, kActivationIndex1);
+ app_restore::OnLacrosWindowAdded(window, kBrowserSessionId,
+ /*restored_browser_session_id=*/0);
+
+ // Verify the browser window is saved.
+ EXPECT_EQ(app_constants::kLacrosAppId,
+ save_handler->GetAppId(widget->GetNativeWindow()));
+ auto window_info = save_handler->GetWindowInfo(
+ GetPath(), app_constants::kLacrosAppId, kBrowserSessionId);
+ EXPECT_EQ(kActivationIndex1, window_info->activation_index.value());
+
+ // Modify the window info.
+ SaveWindowInfo(window, kActivationIndex2);
+ window_info = save_handler->GetWindowInfo(
+ GetPath(), app_constants::kLacrosAppId, kBrowserSessionId);
+ EXPECT_EQ(kActivationIndex2, window_info->activation_index.value());
+
+ widget.reset();
+ ASSERT_FALSE(save_handler->GetWindowInfo(
+ GetPath(), app_constants::kLacrosAppId, kBrowserSessionId));
+
+ timer->FireNow();
+ // Wait for the restore data to be written to the full restore file.
+ task_environment().RunUntilIdle();
+
+ ReadFromFile(GetPath());
+
+ // Verify there is not restore data.
+ const auto* restore_data = GetRestoreData(GetPath());
+ ASSERT_TRUE(restore_data);
+ EXPECT_TRUE(restore_data->app_id_to_launch_list().empty());
+}
+
+// Verify the Lacros Chrome app window is saved correctly when
+// OnLacrosWindowAdded is called first, then the window is init later.
+TEST_F(FullRestoreReadAndSaveTest,
+ LacrosBrowserWindowSavingOnLacrosWindowAddedCalledFirst) {
+ FullRestoreSaveHandler* save_handler = GetSaveHandler();
+ FullRestoreSaveHandlerTestApi test_api(save_handler);
+
+ save_handler->SetPrimaryProfilePath(GetPath());
+ base::OneShotTimer* timer = save_handler->GetTimerForTesting();
+ const LacrosSaveHandler* lacros_save_handler = test_api.GetLacrosSaveHander();
+ ASSERT_TRUE(lacros_save_handler);
+
+ // OnLacrosWindowAdded is called first, then init the browser window later.
+ auto window = CreateLacrosWindow(kLacrosWindowId);
+ app_restore::OnLacrosWindowAdded(window.get(), kBrowserSessionId,
+ /*restored_browser_session_id=*/0);
+ window->Init(ui::LAYER_NOT_DRAWN);
+
+ SaveWindowInfo(window.get(), kActivationIndex1);
+
+ // Verify the browser window is saved.
+ EXPECT_EQ(app_constants::kLacrosAppId, save_handler->GetAppId(window.get()));
+ auto window_info = save_handler->GetWindowInfo(
+ GetPath(), app_constants::kLacrosAppId, kBrowserSessionId);
+ EXPECT_EQ(kActivationIndex1, window_info->activation_index.value());
+
+ // Modify the window info.
+ SaveWindowInfo(window.get(), kActivationIndex2);
+ window_info = save_handler->GetWindowInfo(
+ GetPath(), app_constants::kLacrosAppId, kBrowserSessionId);
+ EXPECT_EQ(kActivationIndex2, window_info->activation_index.value());
+
+ window.reset();
+
+ // Wait for `save_handler` to fresh the full restore file.
+ timer->FireNow();
+ task_environment().RunUntilIdle();
+
+ ReadFromFile(GetPath());
+
+ // Verify there is not restore data.
+ const auto* restore_data = GetRestoreData(GetPath());
+ ASSERT_TRUE(restore_data);
+ EXPECT_TRUE(restore_data->app_id_to_launch_list().empty());
+}
+
+// Verify the Lacros Chrome app window is saved correctly when the window is
+// created first, then OnAppWindowAdded is called.
+TEST_F(FullRestoreReadAndSaveTest,
+ LacrosChromeAppWindowSavingCreateWindowFirst) {
+ FullRestoreSaveHandler* save_handler = GetSaveHandler();
+ FullRestoreSaveHandlerTestApi test_api(save_handler);
+
+ save_handler->SetPrimaryProfilePath(GetPath());
+ base::OneShotTimer* timer = save_handler->GetTimerForTesting();
+
+ // Add a Chrome app launch info.
+ SaveAppLaunchInfo(
+ GetPath(), std::make_unique<app_restore::AppLaunchInfo>(
+ kAppId, apps::mojom::LaunchContainer::kLaunchContainerNone,
+ WindowOpenDisposition::UNKNOWN, display::kInvalidDisplayId,
+ std::vector<base::FilePath>{}, nullptr));
+ const LacrosSaveHandler* lacros_save_handler = test_api.GetLacrosSaveHander();
+ ASSERT_TRUE(lacros_save_handler);
+
+ // Create a Chrome app window first, then the crosapi OnAppWindowAdded is
+ // called later.
+ auto widget = CreateLacrosWidget(kLacrosWindowId);
+ auto* window = widget->GetNativeWindow();
+ EXPECT_FALSE(test_api.GetLacrosWindowCandidates().empty());
+ SaveWindowInfo(window, kActivationIndex1);
+ OnLacrosChromeAppWindowAdded(kAppId, kLacrosWindowId);
+
+ // Verify the Chrome app window is saved.
+ EXPECT_TRUE(test_api.GetLacrosWindowIdToAppIdMap().empty());
+ EXPECT_EQ(save_handler->GetAppId(widget->GetNativeWindow()), kAppId);
+ auto window_info = save_handler->GetWindowInfo(
+ GetPath(), kAppId, test_api.GetLacrosWindowId(kLacrosWindowId));
+ EXPECT_EQ(kActivationIndex1, window_info->activation_index.value());
+
+ // Modify the window info.
+ SaveWindowInfo(window, kActivationIndex2);
+ window_info = save_handler->GetWindowInfo(
+ GetPath(), kAppId, test_api.GetLacrosWindowId(kLacrosWindowId));
+ EXPECT_EQ(kActivationIndex2, window_info->activation_index.value());
+
+ // Destroy the window first, then call the crosapi OnAppWindowRemoved.
+ widget.reset();
+ OnLacrosChromeAppWindowRemoved(kAppId, kLacrosWindowId);
+ EXPECT_TRUE(test_api.GetLacrosWindowCandidates().empty());
+ EXPECT_TRUE(test_api.GetLacrosWindowIdToAppIdMap().empty());
+
+ // Wait for `save_handler` to fresh the full restore file.
+ timer->FireNow();
+ task_environment().RunUntilIdle();
+
+ ReadFromFile(GetPath());
+
+ // Verify there is not restore data.
+ const auto* restore_data = GetRestoreData(GetPath());
+ ASSERT_TRUE(restore_data);
+ EXPECT_TRUE(restore_data->app_id_to_launch_list().empty());
+}
+
+// Verify the Lacros Chrome app window is saved correctly when OnAppWindowAdded
+// is called first, then the window is created later.
+TEST_F(FullRestoreReadAndSaveTest,
+ LacrosChromeAppWindowSavingOnAppWindowCalledFirst) {
+ FullRestoreSaveHandler* save_handler = GetSaveHandler();
+ FullRestoreSaveHandlerTestApi test_api(save_handler);
+
+ save_handler->SetPrimaryProfilePath(GetPath());
+ base::OneShotTimer* timer = save_handler->GetTimerForTesting();
+
+ // Add a Chrome app launch info.
+ auto intent = apps::mojom::Intent::New();
+ intent->activity_name = "activity_name";
+ SaveAppLaunchInfo(
+ GetPath(),
+ std::make_unique<app_restore::AppLaunchInfo>(
+ kAppId, apps::mojom::LaunchContainer::kLaunchContainerNone,
+ WindowOpenDisposition::CURRENT_TAB, display::kInvalidDisplayId,
+ std::vector<base::FilePath>{base::FilePath(kFilePath1),
+ base::FilePath(kFilePath2)},
+ std::move(intent)));
+ const LacrosSaveHandler* lacros_save_handler = test_api.GetLacrosSaveHander();
+ ASSERT_TRUE(lacros_save_handler);
+
+ // The crosapi OnAppWindowAdded is called first, then create a Chrome app
+ // window later.
+ OnLacrosChromeAppWindowAdded(kAppId, kLacrosWindowId);
+ EXPECT_FALSE(test_api.GetLacrosWindowIdToAppIdMap().empty());
+ auto widget = CreateLacrosWidget(kLacrosWindowId);
+ auto* window = widget->GetNativeWindow();
+ EXPECT_FALSE(test_api.GetLacrosWindowCandidates().empty());
+ SaveWindowInfo(window, kActivationIndex1);
+
+ // Verify the Chrome app window is saved.
+ EXPECT_EQ(save_handler->GetAppId(widget->GetNativeWindow()), kAppId);
+ auto window_info = save_handler->GetWindowInfo(
+ GetPath(), kAppId, test_api.GetLacrosWindowId(kLacrosWindowId));
+ EXPECT_EQ(kActivationIndex1, window_info->activation_index.value());
+
+ // Modify the window info.
+ SaveWindowInfo(window, kActivationIndex2);
+ window_info = save_handler->GetWindowInfo(
+ GetPath(), kAppId, test_api.GetLacrosWindowId(kLacrosWindowId));
+ EXPECT_EQ(kActivationIndex2, window_info->activation_index.value());
+
+ // Call the crosapi OnAppWindowRemoved first, then destroy the window.
+ OnLacrosChromeAppWindowRemoved(kAppId, kLacrosWindowId);
+ widget.reset();
+ EXPECT_TRUE(test_api.GetLacrosWindowCandidates().empty());
+ EXPECT_TRUE(test_api.GetLacrosWindowIdToAppIdMap().empty());
+
+ timer->FireNow();
+ task_environment().RunUntilIdle();
+
+ ReadFromFile(GetPath());
+
+ // Verify there is not restore data.
+ const auto* restore_data = GetRestoreData(GetPath());
+ ASSERT_TRUE(restore_data);
+ EXPECT_TRUE(restore_data->app_id_to_launch_list().empty());
+}
+
} // namespace full_restore
diff --git a/chromium/components/app_restore/full_restore_read_handler.cc b/chromium/components/app_restore/full_restore_read_handler.cc
index fd56e034382..da7ff1842c5 100644
--- a/chromium/components/app_restore/full_restore_read_handler.cc
+++ b/chromium/components/app_restore/full_restore_read_handler.cc
@@ -13,16 +13,19 @@
#include "base/no_destructor.h"
#include "base/task/post_task.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "components/app_constants/constants.h"
#include "components/app_restore/app_launch_info.h"
+#include "components/app_restore/app_restore_utils.h"
#include "components/app_restore/desk_template_read_handler.h"
+#include "components/app_restore/features.h"
#include "components/app_restore/full_restore_file_handler.h"
#include "components/app_restore/full_restore_info.h"
#include "components/app_restore/full_restore_save_handler.h"
+#include "components/app_restore/lacros_read_handler.h"
#include "components/app_restore/restore_data.h"
#include "components/app_restore/window_info.h"
#include "components/app_restore/window_properties.h"
#include "components/sessions/core/session_id.h"
-#include "extensions/common/constants.h"
#include "ui/aura/client/aura_constants.h"
namespace full_restore {
@@ -32,7 +35,8 @@ namespace {
// These are temporary estimate of how long it takes full restore to launch
// apps.
constexpr base::TimeDelta kFullRestoreEstimateDuration = base::Seconds(5);
-constexpr base::TimeDelta kFullRestoreARCEstimateDuration = base::Minutes(5);
+constexpr base::TimeDelta kFullRestoreARCEstimateDuration = base::Minutes(3);
+constexpr base::TimeDelta kFullRestoreLacrosEstimateDuration = base::Minutes(1);
} // namespace
@@ -52,8 +56,7 @@ FullRestoreReadHandler::~FullRestoreReadHandler() = default;
void FullRestoreReadHandler::OnWindowInitialized(aura::Window* window) {
int32_t window_id = window->GetProperty(app_restore::kRestoreWindowIdKey);
- if (window->GetProperty(aura::client::kAppType) ==
- static_cast<int>(ash::AppType::ARC_APP)) {
+ if (app_restore::IsArcWindow(window)) {
// If there isn't restore data for ARC apps, we don't need to handle ARC app
// windows restoration.
if (!arc_read_handler_)
@@ -68,6 +71,17 @@ void FullRestoreReadHandler::OnWindowInitialized(aura::Window* window) {
return;
}
+ if (app_restore::IsLacrosWindow(window)) {
+ // If the Lacros `window` is added to the hidden container, observe `window`
+ // to restore and remove it from the hidden container in
+ // OnWindowAddedToRootWindow callback.
+ if (lacros_read_handler_ &&
+ window_id == app_restore::kParentToHiddenContainer) {
+ observed_windows_.AddObservation(window);
+ }
+ return;
+ }
+
if (!SessionID::IsValidValue(window_id)) {
return;
}
@@ -76,17 +90,29 @@ void FullRestoreReadHandler::OnWindowInitialized(aura::Window* window) {
FullRestoreInfo::GetInstance()->OnWindowInitialized(window);
}
+void FullRestoreReadHandler::OnWindowAddedToRootWindow(aura::Window* window) {
+ // If the Lacros `window` is added to the hidden container, call
+ // OnWindowAddedToRootWindow to restore and remove it from the hidden
+ // container.
+ if (app_restore::IsLacrosWindow(window) && lacros_read_handler_ &&
+ window->GetProperty(app_restore::kParentToHiddenContainerKey)) {
+ lacros_read_handler_->OnWindowAddedToRootWindow(window);
+ }
+}
+
void FullRestoreReadHandler::OnWindowDestroyed(aura::Window* window) {
DCHECK(observed_windows_.IsObservingSource(window));
observed_windows_.RemoveObservation(window);
- if (window->GetProperty(aura::client::kAppType) ==
- static_cast<int>(ash::AppType::ARC_APP)) {
+ if (app_restore::IsArcWindow(window)) {
if (arc_read_handler_)
arc_read_handler_->OnWindowDestroyed(window);
return;
}
+ if (app_restore::IsLacrosWindow(window) && lacros_read_handler_)
+ lacros_read_handler_->OnWindowDestroyed(window);
+
int32_t restore_window_id =
window->GetProperty(app_restore::kRestoreWindowIdKey);
DCHECK(SessionID::IsValidValue(restore_window_id));
@@ -139,6 +165,38 @@ void FullRestoreReadHandler::OnTaskDestroyed(int32_t task_id) {
arc_read_handler_->OnTaskDestroyed(task_id);
}
+void FullRestoreReadHandler::OnLacrosBrowserWindowAdded(
+ aura::Window* const window,
+ uint32_t restored_browser_session_id) {
+ if (lacros_read_handler_) {
+ lacros_read_handler_->OnLacrosBrowserWindowAdded(
+ window, restored_browser_session_id);
+ }
+}
+
+void FullRestoreReadHandler::OnLacrosChromeAppWindowAdded(
+ const std::string& app_id,
+ const std::string& window_id) {
+ if (lacros_read_handler_)
+ lacros_read_handler_->OnAppWindowAdded(app_id, window_id);
+}
+
+void FullRestoreReadHandler::OnLacrosChromeAppWindowRemoved(
+ const std::string& app_id,
+ const std::string& window_id) {
+ if (lacros_read_handler_)
+ lacros_read_handler_->OnAppWindowRemoved(app_id, window_id);
+}
+
+void FullRestoreReadHandler::SetPrimaryProfilePath(
+ const base::FilePath& profile_path) {
+ primary_profile_path_ = profile_path;
+ if (::full_restore::features::IsFullRestoreForLacrosEnabled()) {
+ lacros_read_handler_ =
+ std::make_unique<app_restore::LacrosReadHandler>(profile_path);
+ }
+}
+
void FullRestoreReadHandler::SetActiveProfilePath(
const base::FilePath& profile_path) {
active_profile_path_ = profile_path;
@@ -235,8 +293,7 @@ std::unique_ptr<app_restore::WindowInfo> FullRestoreReadHandler::GetWindowInfo(
const int32_t restore_window_id =
window->GetProperty(app_restore::kRestoreWindowIdKey);
- if (window->GetProperty(aura::client::kAppType) ==
- static_cast<int>(ash::AppType::ARC_APP)) {
+ if (app_restore::IsArcWindow(window)) {
return arc_read_handler_
? arc_read_handler_->GetWindowInfo(restore_window_id)
: nullptr;
@@ -286,8 +343,11 @@ int32_t FullRestoreReadHandler::GetArcRestoreWindowIdForSessionId(
return arc_read_handler_->GetArcRestoreWindowIdForSessionId(session_id);
}
-int32_t FullRestoreReadHandler::GetArcSessionId() {
- return arc_read_handler_ ? arc_read_handler_->GetArcSessionId() : 0;
+int32_t FullRestoreReadHandler::GetLacrosRestoreWindowId(
+ const std::string& lacros_window_id) const {
+ return IsLacrosRestoreRunning()
+ ? lacros_read_handler_->GetLacrosRestoreWindowId(lacros_window_id)
+ : 0;
}
void FullRestoreReadHandler::SetArcSessionIdForWindowId(int32_t arc_session_id,
@@ -306,19 +366,19 @@ bool FullRestoreReadHandler::IsFullRestoreRunning() const {
if (it == profile_path_to_start_time_data_.end())
return false;
- base::TimeDelta elapsed_time = base::TimeTicks::Now() - it->second;
+ if (IsArcRestoreRunning() || IsLacrosRestoreRunning())
+ return true;
+
// We estimate that full restore is still running if it has been less than
- // five seconds since it started, or five minutes if there is at least one ARC
- // app.
- return arc_read_handler_ ? elapsed_time < kFullRestoreARCEstimateDuration
- : elapsed_time < kFullRestoreEstimateDuration;
+ // five seconds since it started.
+ return base::TimeTicks::Now() - it->second < kFullRestoreEstimateDuration;
}
void FullRestoreReadHandler::AddChromeBrowserLaunchInfoForTesting(
const base::FilePath& profile_path) {
auto session_id = SessionID::NewUnique();
auto app_launch_info = std::make_unique<app_restore::AppLaunchInfo>(
- extension_misc::kChromeAppId, session_id.id());
+ app_constants::kChromeAppId, session_id.id());
app_launch_info->app_type_browser = true;
if (profile_path_to_restore_data_.find(profile_path) ==
@@ -330,7 +390,7 @@ void FullRestoreReadHandler::AddChromeBrowserLaunchInfoForTesting(
profile_path_to_restore_data_[profile_path]->AddAppLaunchInfo(
std::move(app_launch_info));
window_id_to_app_restore_info_[session_id.id()] =
- std::make_pair(profile_path, extension_misc::kChromeAppId);
+ std::make_pair(profile_path, app_constants::kChromeAppId);
}
std::unique_ptr<app_restore::WindowInfo> FullRestoreReadHandler::GetWindowInfo(
@@ -347,13 +407,40 @@ std::unique_ptr<app_restore::WindowInfo> FullRestoreReadHandler::GetWindowInfo(
return GetWindowInfo(profile_path, app_id, restore_window_id);
}
+bool FullRestoreReadHandler::IsArcRestoreRunning() const {
+ if (!arc_read_handler_ || active_profile_path_ != primary_profile_path_)
+ return false;
+
+ auto it = profile_path_to_start_time_data_.find(primary_profile_path_);
+ if (it == profile_path_to_start_time_data_.end())
+ return false;
+
+ // We estimate that full restore is still running for ARC windows if it has
+ // been less than five minutes since it started, when there is at least one
+ // ARC app, since it might take long time to boot ARC.
+ return base::TimeTicks::Now() - it->second < kFullRestoreARCEstimateDuration;
+}
+
+bool FullRestoreReadHandler::IsLacrosRestoreRunning() const {
+ if (!lacros_read_handler_ || active_profile_path_ != primary_profile_path_)
+ return false;
+
+ auto it = profile_path_to_start_time_data_.find(primary_profile_path_);
+ if (it == profile_path_to_start_time_data_.end())
+ return false;
+
+ // We estimate that full restore is still running if it has been less than
+ // one minute since it started, when Lacros is available.
+ return base::TimeTicks::Now() - it->second <
+ kFullRestoreLacrosEstimateDuration;
+}
+
void FullRestoreReadHandler::OnGetRestoreData(
const base::FilePath& profile_path,
Callback callback,
std::unique_ptr<app_restore::RestoreData> restore_data) {
if (restore_data) {
profile_path_to_restore_data_[profile_path] = restore_data->Clone();
-
for (auto it = restore_data->app_id_to_launch_list().begin();
it != restore_data->app_id_to_launch_list().end(); it++) {
const std::string& app_id = it->first;
@@ -370,6 +457,12 @@ void FullRestoreReadHandler::OnGetRestoreData(
} else {
window_id_to_app_restore_info_[window_id] =
std::make_pair(profile_path, app_id);
+ // TODO(crbug.com/1239984): Remove restore data from
+ // `lacros_read_handler_` for ash browser apps.
+ if (lacros_read_handler_ && app_id != app_constants::kChromeAppId &&
+ primary_profile_path_ == profile_path) {
+ lacros_read_handler_->AddRestoreData(app_id, window_id);
+ }
}
}
}
diff --git a/chromium/components/app_restore/full_restore_read_handler.h b/chromium/components/app_restore/full_restore_read_handler.h
index 6b513725952..ec3607cd054 100644
--- a/chromium/components/app_restore/full_restore_read_handler.h
+++ b/chromium/components/app_restore/full_restore_read_handler.h
@@ -5,12 +5,12 @@
#ifndef COMPONENTS_APP_RESTORE_FULL_RESTORE_READ_HANDLER_H_
#define COMPONENTS_APP_RESTORE_FULL_RESTORE_READ_HANDLER_H_
-#include <map>
#include <memory>
#include <utility>
#include "base/callback.h"
#include "base/component_export.h"
+#include "base/containers/flat_map.h"
#include "base/files/file_path.h"
#include "base/memory/weak_ptr.h"
#include "base/scoped_multi_source_observation.h"
@@ -25,6 +25,7 @@
namespace app_restore {
struct AppLaunchInfo;
+class LacrosReadHandler;
class RestoreData;
struct WindowInfo;
} // namespace app_restore
@@ -71,6 +72,7 @@ class COMPONENT_EXPORT(APP_RESTORE) FullRestoreReadHandler
void OnWindowInitialized(aura::Window* window) override;
// aura::WindowObserver:
+ void OnWindowAddedToRootWindow(aura::Window* window) override;
void OnWindowDestroyed(aura::Window* window) override;
// app_restore::ArcReadHandler::Delegate:
@@ -92,6 +94,25 @@ class COMPONENT_EXPORT(APP_RESTORE) FullRestoreReadHandler
int32_t session_id) override;
void OnTaskDestroyed(int32_t task_id) override;
+ // Invoked when Lacros window is created. `restored_browser_session_id` is the
+ // restored browser session id.
+ void OnLacrosBrowserWindowAdded(aura::Window* const window,
+ uint32_t restored_browser_session_id);
+
+ // Invoked when an Chrome app Lacros window is created. `app_id` is the
+ // AppService id, and `window_id` is the wayland app_id property for the
+ // window.
+ void OnLacrosChromeAppWindowAdded(const std::string& app_id,
+ const std::string& window_id);
+
+ // Invoked when an Chrome app Lacros window is removed. `app_id` is the
+ // AppService id, and `window_id` is the wayland app_id property for the
+ // window.
+ void OnLacrosChromeAppWindowRemoved(const std::string& app_id,
+ const std::string& window_id);
+
+ void SetPrimaryProfilePath(const base::FilePath& profile_path);
+
void SetActiveProfilePath(const base::FilePath& profile_path);
// Sets whether we should check the restore data for `profile_path`. If the
@@ -149,9 +170,9 @@ class COMPONENT_EXPORT(APP_RESTORE) FullRestoreReadHandler
// Returns the restore window id for the ARC app's |session_id|.
int32_t GetArcRestoreWindowIdForSessionId(int32_t session_id);
- // Generates the ARC session id (1,000,000,001 - INT_MAX) for restored ARC
- // apps.
- int32_t GetArcSessionId();
+ // Returns the restore window id for the Lacros window with
+ // `lacros_window_id`.
+ int32_t GetLacrosRestoreWindowId(const std::string& lacros_window_id) const;
// Sets |arc session id| for |window_id| to |arc_session_id_to_window_id_|.
// |arc session id| is assigned when ARC apps are restored.
@@ -179,6 +200,14 @@ class COMPONENT_EXPORT(APP_RESTORE) FullRestoreReadHandler
std::unique_ptr<app_restore::WindowInfo> GetWindowInfo(
int32_t restore_window_id);
+ // Returns true if ARC restore launching is thought to be underway on
+ // `primary_profile_path_`.
+ bool IsArcRestoreRunning() const;
+
+ // Returns true if Lacros restore launching is thought to be underway on
+ // `primary_profile_path_`.
+ bool IsLacrosRestoreRunning() const;
+
// Invoked when reading the restore data from |profile_path| is finished, and
// calls |callback| to notify that the reading operation is done.
void OnGetRestoreData(const base::FilePath& profile_path,
@@ -190,26 +219,32 @@ class COMPONENT_EXPORT(APP_RESTORE) FullRestoreReadHandler
app_restore::RestoreData* GetRestoreData(const base::FilePath& profile_path);
+ // The primary user profile path.
+ base::FilePath primary_profile_path_;
+
// The current active user profile path.
base::FilePath active_profile_path_;
// The restore data read from the full restore files.
- std::map<base::FilePath, std::unique_ptr<app_restore::RestoreData>>
+ base::flat_map<base::FilePath, std::unique_ptr<app_restore::RestoreData>>
profile_path_to_restore_data_;
// The map from the window id to the full restore file path and the
// app id. The window id is saved in the window property
// |kRestoreWindowIdKey|. This map is used to find the file path and the app
// id when get the window info. This map is not used for ARC app windows.
- std::map<int32_t, std::pair<base::FilePath, std::string>>
+ base::flat_map<int32_t, std::pair<base::FilePath, std::string>>
window_id_to_app_restore_info_;
// The start time of full restore for each profile. There won't be an entry if
// full restore hasn't started for the profile.
- std::map<base::FilePath, base::TimeTicks> profile_path_to_start_time_data_;
+ base::flat_map<base::FilePath, base::TimeTicks>
+ profile_path_to_start_time_data_;
std::unique_ptr<app_restore::ArcReadHandler> arc_read_handler_;
+ std::unique_ptr<app_restore::LacrosReadHandler> lacros_read_handler_;
+
// Records whether we need to check the restore data for the profile path. If
// the profile path is recorded, we should check the restore data. Otherwise,
// we don't need to check the restore data, because the restore process hasn't
diff --git a/chromium/components/app_restore/full_restore_save_handler.cc b/chromium/components/app_restore/full_restore_save_handler.cc
index 06c69a491ab..d3c86a0ad68 100644
--- a/chromium/components/app_restore/full_restore_save_handler.cc
+++ b/chromium/components/app_restore/full_restore_save_handler.cc
@@ -11,7 +11,10 @@
#include "base/no_destructor.h"
#include "base/task/sequenced_task_runner.h"
#include "base/time/time.h"
+#include "components/app_constants/constants.h"
#include "components/app_restore/app_launch_info.h"
+#include "components/app_restore/app_restore_utils.h"
+#include "components/app_restore/features.h"
#include "components/app_restore/full_restore_file_handler.h"
#include "components/app_restore/full_restore_info.h"
#include "components/app_restore/full_restore_read_handler.h"
@@ -21,7 +24,6 @@
#include "components/app_restore/window_properties.h"
#include "components/services/app_service/public/cpp/app_registry_cache.h"
#include "components/sessions/core/session_id.h"
-#include "extensions/common/constants.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/env.h"
@@ -36,15 +38,6 @@ constexpr base::TimeDelta kSaveDelay = base::Milliseconds(2500);
// Delay starting `save_timer_` during the system startup phase.
constexpr base::TimeDelta kWaitDelay = base::Seconds(120);
-const char kCrxAppPrefix[] = "_crx_";
-
-std::string GetAppIdFromAppName(const std::string& app_name) {
- std::string prefix(kCrxAppPrefix);
- if (app_name.substr(0, prefix.length()) != prefix)
- return std::string();
- return app_name.substr(prefix.length());
-}
-
} // namespace
FullRestoreSaveHandler* FullRestoreSaveHandler::GetInstance() {
@@ -62,8 +55,10 @@ FullRestoreSaveHandler::~FullRestoreSaveHandler() = default;
void FullRestoreSaveHandler::SetPrimaryProfilePath(
const base::FilePath& profile_path) {
- primary_profile_path_ = profile_path;
- arc_save_handler_ = std::make_unique<ArcSaveHandler>(primary_profile_path_);
+ arc_save_handler_ = std::make_unique<ArcSaveHandler>(profile_path);
+ if (::full_restore::features::IsFullRestoreForLacrosEnabled()) {
+ lacros_save_handler_ = std::make_unique<LacrosSaveHandler>(profile_path);
+ }
}
void FullRestoreSaveHandler::SetActiveProfilePath(
@@ -100,8 +95,7 @@ void FullRestoreSaveHandler::SetShutDown() {
}
void FullRestoreSaveHandler::OnWindowInitialized(aura::Window* window) {
- if (window->GetProperty(aura::client::kAppType) ==
- static_cast<int>(ash::AppType::ARC_APP)) {
+ if (app_restore::IsArcWindow(window)) {
observed_windows_.AddObservation(window);
if (arc_save_handler_)
@@ -110,6 +104,14 @@ void FullRestoreSaveHandler::OnWindowInitialized(aura::Window* window) {
return;
}
+ if (app_restore::IsLacrosWindow(window)) {
+ observed_windows_.AddObservation(window);
+
+ if (lacros_save_handler_)
+ lacros_save_handler_->OnWindowInitialized(window);
+ return;
+ }
+
int32_t window_id = window->GetProperty(app_restore::kWindowIdKey);
if (!SessionID::IsValidValue(window_id))
return;
@@ -122,25 +124,15 @@ void FullRestoreSaveHandler::OnWindowInitialized(aura::Window* window) {
if (app_id_str) {
// For Chrome apps, launched via event, get the app id from the window's
// property, then find the app launch info from
- // |app_id_to_app_launch_infos_| to save the app launch info for |app_id|
+ // `app_id_to_app_launch_infos_` to save the app launch info for |app_id|
// and |window_id|.
- auto it = app_id_to_app_launch_infos_.find(*app_id_str);
- if (it == app_id_to_app_launch_infos_.end())
- return;
-
- auto launch_it = it->second.find(active_profile_path_);
- if (launch_it == it->second.end())
+ app_launch_info = FetchAppLaunchInfo(active_profile_path_, *app_id_str);
+ if (!app_launch_info)
return;
-
- DCHECK(!launch_it->second.empty());
- app_launch_info = std::move(*launch_it->second.begin());
app_launch_info->window_id = window_id;
- it->second.erase(active_profile_path_);
- if (it->second.empty())
- app_id_to_app_launch_infos_.erase(it);
} else {
app_launch_info = std::make_unique<app_restore::AppLaunchInfo>(
- extension_misc::kChromeAppId, window_id);
+ app_constants::kChromeAppId, window_id);
// If the window is an app type browser window, set `app_type_browser` as
// true, to call the browser session restore to restore apps for the next
@@ -151,7 +143,8 @@ void FullRestoreSaveHandler::OnWindowInitialized(aura::Window* window) {
std::string* browser_app_name =
window->GetProperty(app_restore::kBrowserAppNameKey);
if (browser_app_name) {
- std::string app_id = GetAppIdFromAppName(*browser_app_name);
+ std::string app_id =
+ app_restore::GetAppIdFromAppName(*browser_app_name);
auto it =
profile_path_to_app_registry_cache_.find(active_profile_path_);
if (it != profile_path_to_app_registry_cache_.end() && it->second &&
@@ -174,15 +167,19 @@ void FullRestoreSaveHandler::OnWindowDestroyed(aura::Window* window) {
DCHECK(observed_windows_.IsObservingSource(window));
observed_windows_.RemoveObservation(window);
- int32_t window_id = window->GetProperty(app_restore::kWindowIdKey);
-
- if (window->GetProperty(aura::client::kAppType) ==
- static_cast<int>(ash::AppType::ARC_APP)) {
+ if (app_restore::IsArcWindow(window)) {
if (arc_save_handler_)
arc_save_handler_->OnWindowDestroyed(window);
return;
}
+ if (app_restore::IsLacrosWindow(window)) {
+ if (lacros_save_handler_)
+ lacros_save_handler_->OnWindowDestroyed(window);
+ return;
+ }
+
+ int32_t window_id = window->GetProperty(app_restore::kWindowIdKey);
DCHECK(SessionID::IsValidValue(window_id));
RemoveAppRestoreData(window_id);
@@ -279,19 +276,17 @@ void FullRestoreSaveHandler::SaveAppLaunchInfo(
const int window_id = app_launch_info->window_id.value();
std::unique_ptr<app_restore::WindowInfo> window_info;
- if (app_id != extension_misc::kChromeAppId) {
+ if (app_id != app_constants::kChromeAppId) {
// For browser windows, it could have been saved as
- // extension_misc::kChromeAppId in OnWindowInitialized. However, for the
+ // app_constants::kChromeAppId in OnWindowInitialized. However, for the
// system web apps, we need to save as the system web app app id and the
// launch parameter, because system web apps can't be restored by the
// browser session restore. So remove the record in
- // extension_misc::kChromeAppId, save the launch info as the system web
+ // app_constants::kChromeAppId, save the launch info as the system web
// app id, and move window info to the record of the system web app id.
auto it = window_id_to_app_restore_info_.find(window_id);
if (it != window_id_to_app_restore_info_.end()) {
- window_info =
- profile_path_to_restore_data_[it->second.first].GetWindowInfo(
- it->second.second, window_id);
+ window_info = GetWindowInfo(profile_path, app_id, window_id);
RemoveAppRestoreData(window_id);
}
}
@@ -309,13 +304,18 @@ void FullRestoreSaveHandler::SaveWindowInfo(
if (!window_info.window)
return;
- if (window_info.window->GetProperty(aura::client::kAppType) ==
- static_cast<int>(ash::AppType::ARC_APP)) {
+ if (app_restore::IsArcWindow(window_info.window)) {
if (arc_save_handler_)
arc_save_handler_->ModifyWindowInfo(window_info);
return;
}
+ if (app_restore::IsLacrosWindow(window_info.window)) {
+ if (lacros_save_handler_)
+ lacros_save_handler_->ModifyWindowInfo(window_info);
+ return;
+ }
+
int32_t window_id =
window_info.window->GetProperty(app_restore::kWindowIdKey);
@@ -325,6 +325,27 @@ void FullRestoreSaveHandler::SaveWindowInfo(
ModifyWindowInfo(window_id, window_info);
}
+void FullRestoreSaveHandler::OnLacrosBrowserWindowAdded(
+ aura::Window* const window,
+ uint32_t browser_session_id) {
+ if (lacros_save_handler_)
+ lacros_save_handler_->OnBrowserWindowAdded(window, browser_session_id);
+}
+
+void FullRestoreSaveHandler::OnLacrosChromeAppWindowAdded(
+ const std::string& app_id,
+ const std::string& window_id) {
+ if (lacros_save_handler_)
+ lacros_save_handler_->OnAppWindowAdded(app_id, window_id);
+}
+
+void FullRestoreSaveHandler::OnLacrosChromeAppWindowRemoved(
+ const std::string& app_id,
+ const std::string& window_id) {
+ if (lacros_save_handler_)
+ lacros_save_handler_->OnAppWindowRemoved(app_id, window_id);
+}
+
void FullRestoreSaveHandler::Flush(const base::FilePath& profile_path) {
if (save_running_.find(profile_path) != save_running_.end())
return;
@@ -495,10 +516,12 @@ const app_restore::RestoreData* FullRestoreSaveHandler::GetRestoreData(
std::string FullRestoreSaveHandler::GetAppId(aura::Window* window) {
DCHECK(window);
- if (window->GetProperty(aura::client::kAppType) ==
- static_cast<int>(ash::AppType::ARC_APP)) {
+ if (app_restore::IsArcWindow(window)) {
return arc_save_handler_ ? arc_save_handler_->GetAppId(window)
: std::string();
+ } else if (app_restore::IsLacrosWindow(window)) {
+ return lacros_save_handler_ ? lacros_save_handler_->GetAppId(window)
+ : std::string();
} else {
// For other window types (browser, PWAs, SWAs, Chrome apps), get its
// corresponding app id from |window_id_to_app_restore_info_|.
@@ -509,11 +532,39 @@ std::string FullRestoreSaveHandler::GetAppId(aura::Window* window) {
}
}
+std::unique_ptr<app_restore::AppLaunchInfo>
+FullRestoreSaveHandler::FetchAppLaunchInfo(const base::FilePath& profile_path,
+ const std::string& app_id) {
+ auto it = app_id_to_app_launch_infos_.find(app_id);
+ if (it == app_id_to_app_launch_infos_.end())
+ return nullptr;
+
+ auto launch_it = it->second.find(profile_path);
+ if (launch_it == it->second.end())
+ return nullptr;
+
+ DCHECK(!launch_it->second.empty());
+ auto app_launch_info = std::move(*launch_it->second.begin());
+ it->second.erase(profile_path);
+ if (it->second.empty())
+ app_id_to_app_launch_infos_.erase(it);
+ return app_launch_info;
+}
+
+std::unique_ptr<app_restore::WindowInfo> FullRestoreSaveHandler::GetWindowInfo(
+ const base::FilePath& profile_path,
+ const std::string& app_id,
+ int window_id) {
+ auto it = profile_path_to_restore_data_.find(profile_path);
+ return it != profile_path_to_restore_data_.end()
+ ? it->second.GetWindowInfo(app_id, window_id)
+ : nullptr;
+}
+
void FullRestoreSaveHandler::ClearForTesting() {
profile_path_to_file_handler_.clear();
profile_path_to_restore_data_.clear();
app_id_to_app_launch_infos_.clear();
- primary_profile_path_.clear();
save_running_.clear();
pending_save_profile_paths_.clear();
window_id_to_app_restore_info_.clear();
diff --git a/chromium/components/app_restore/full_restore_save_handler.h b/chromium/components/app_restore/full_restore_save_handler.h
index 689706e9493..56bd013b2b1 100644
--- a/chromium/components/app_restore/full_restore_save_handler.h
+++ b/chromium/components/app_restore/full_restore_save_handler.h
@@ -5,12 +5,14 @@
#ifndef COMPONENTS_APP_RESTORE_FULL_RESTORE_SAVE_HANDLER_H_
#define COMPONENTS_APP_RESTORE_FULL_RESTORE_SAVE_HANDLER_H_
+#include <list>
#include <map>
#include <memory>
#include <set>
#include <utility>
#include "base/component_export.h"
+#include "base/containers/flat_map.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/scoped_multi_source_observation.h"
@@ -18,6 +20,7 @@
#include "base/timer/timer.h"
#include "components/app_restore/app_restore_arc_info.h"
#include "components/app_restore/arc_save_handler.h"
+#include "components/app_restore/lacros_save_handler.h"
#include "ui/aura/env.h"
#include "ui/aura/env_observer.h"
#include "ui/aura/window.h"
@@ -107,6 +110,23 @@ class COMPONENT_EXPORT(APP_RESTORE) FullRestoreSaveHandler
// Saves |window_info| to |profile_path_to_restore_data_|.
void SaveWindowInfo(const app_restore::WindowInfo& window_info);
+ // Invoked when Lacros window is created. `browser_session_id` is the
+ // current browser session id for `window`.
+ void OnLacrosBrowserWindowAdded(aura::Window* const window,
+ uint32_t browser_session_id);
+
+ // Invoked when an Chrome app Lacros window is created. `app_id` is the
+ // AppService id, and `window_id` is the wayland app_id property for the
+ // window.
+ void OnLacrosChromeAppWindowAdded(const std::string& app_id,
+ const std::string& window_id);
+
+ // Invoked when an Chrome app Lacros window is removed. `app_id` is the
+ // AppService id, and `window_id` is the wayland app_id property for the
+ // window.
+ void OnLacrosChromeAppWindowRemoved(const std::string& app_id,
+ const std::string& window_id);
+
// Flushes the full restore file in |profile_path| with the current restore
// data.
void Flush(const base::FilePath& profile_path);
@@ -172,6 +192,18 @@ class COMPONENT_EXPORT(APP_RESTORE) FullRestoreSaveHandler
// the window's associated AppRestoreData.
std::string GetAppId(aura::Window* window);
+ // Fetches the app launch information from `app_id_to_app_launch_infos_` for
+ // the given `profile_path` and `app_id`. `app_id` should be a Chrome app id.
+ AppLaunchInfoPtr FetchAppLaunchInfo(const base::FilePath& profile_path,
+ const std::string& app_id);
+
+ // Returns the window information from the restore data of `profile_path` for
+ // `app_id` and `window_id`.
+ std::unique_ptr<app_restore::WindowInfo> GetWindowInfo(
+ const base::FilePath& profile_path,
+ const std::string& app_id,
+ int window_id);
+
base::OneShotTimer* GetTimerForTesting() { return &save_timer_; }
// Since this is a singleton, tests may need to clear it between tests.
@@ -183,7 +215,8 @@ class COMPONENT_EXPORT(APP_RESTORE) FullRestoreSaveHandler
friend class ash::full_restore::FullRestoreAppLaunchHandlerArcAppBrowserTest;
// Map from a profile path to AppLaunchInfos.
- using AppLaunchInfos = std::map<base::FilePath, std::list<AppLaunchInfoPtr>>;
+ using AppLaunchInfos =
+ base::flat_map<base::FilePath, std::list<AppLaunchInfoPtr>>;
// Starts the timer that invokes Save (if timer isn't already running).
void MaybeStartSaveTimer(const base::FilePath& profile_path);
@@ -224,11 +257,11 @@ class COMPONENT_EXPORT(APP_RESTORE) FullRestoreSaveHandler
// The file handler for each user's profile to write the restore data to the
// full restore file for each user. The key is the profile path.
- std::map<base::FilePath, scoped_refptr<FullRestoreFileHandler>>
+ base::flat_map<base::FilePath, scoped_refptr<FullRestoreFileHandler>>
profile_path_to_file_handler_;
// The AppRegistryCache for each user's profile. The key is the profile path.
- std::map<base::FilePath, apps::AppRegistryCache*>
+ base::flat_map<base::FilePath, apps::AppRegistryCache*>
profile_path_to_app_registry_cache_;
// The map from the window id to the full restore file path and the app id.
@@ -245,9 +278,6 @@ class COMPONENT_EXPORT(APP_RESTORE) FullRestoreSaveHandler
// The current active user profile path.
base::FilePath active_profile_path_;
- // The primary user profile path for ARC apps.
- base::FilePath primary_profile_path_;
-
// Timer used to delay the restore data writing to the full restore file.
base::OneShotTimer save_timer_;
@@ -262,6 +292,8 @@ class COMPONENT_EXPORT(APP_RESTORE) FullRestoreSaveHandler
std::unique_ptr<ArcSaveHandler> arc_save_handler_;
+ std::unique_ptr<LacrosSaveHandler> lacros_save_handler_;
+
bool is_shut_down_ = false;
// Due to the system crash or upgrading, the system might restart or reboot
diff --git a/chromium/components/app_restore/full_restore_utils.cc b/chromium/components/app_restore/full_restore_utils.cc
index cd3fa4df15b..471b8d99876 100644
--- a/chromium/components/app_restore/full_restore_utils.cc
+++ b/chromium/components/app_restore/full_restore_utils.cc
@@ -18,7 +18,7 @@ namespace full_restore {
void SaveAppLaunchInfo(
const base::FilePath& profile_path,
std::unique_ptr<app_restore::AppLaunchInfo> app_launch_info) {
- if (!full_restore::features::IsFullRestoreEnabled() || !app_launch_info)
+ if (!app_launch_info)
return;
FullRestoreSaveHandler::GetInstance()->SaveAppLaunchInfo(
@@ -26,38 +26,28 @@ void SaveAppLaunchInfo(
}
void SaveWindowInfo(const app_restore::WindowInfo& window_info) {
- if (!full_restore::features::IsFullRestoreEnabled())
- return;
-
FullRestoreSaveHandler::GetInstance()->SaveWindowInfo(window_info);
}
void SetActiveProfilePath(const base::FilePath& profile_path) {
- if (!full_restore::features::IsFullRestoreEnabled())
- return;
-
FullRestoreSaveHandler::GetInstance()->SetActiveProfilePath(profile_path);
FullRestoreReadHandler::GetInstance()->SetActiveProfilePath(profile_path);
}
-bool HasAppTypeBrowser(const base::FilePath& profile_path) {
- if (!full_restore::features::IsFullRestoreEnabled())
- return false;
+void SetPrimaryProfilePath(const base::FilePath& profile_path) {
+ FullRestoreSaveHandler::GetInstance()->SetPrimaryProfilePath(profile_path);
+ FullRestoreReadHandler::GetInstance()->SetPrimaryProfilePath(profile_path);
+}
+bool HasAppTypeBrowser(const base::FilePath& profile_path) {
return FullRestoreReadHandler::GetInstance()->HasAppTypeBrowser(profile_path);
}
bool HasBrowser(const base::FilePath& profile_path) {
- if (!full_restore::features::IsFullRestoreEnabled())
- return false;
-
return FullRestoreReadHandler::GetInstance()->HasBrowser(profile_path);
}
bool HasWindowInfo(int32_t restore_window_id) {
- if (!full_restore::features::IsFullRestoreEnabled())
- return false;
-
return FullRestoreReadHandler::GetInstance()->HasWindowInfo(
restore_window_id);
}
@@ -69,10 +59,29 @@ void AddChromeBrowserLaunchInfoForTesting(const base::FilePath& profile_path) {
}
std::string GetAppId(aura::Window* window) {
- if (!full_restore::features::IsFullRestoreEnabled())
- return std::string();
-
return FullRestoreSaveHandler::GetInstance()->GetAppId(window);
}
+void OnLacrosChromeAppWindowAdded(const std::string& app_id,
+ const std::string& window_id) {
+ if (!full_restore::features::IsFullRestoreForLacrosEnabled())
+ return;
+
+ FullRestoreReadHandler::GetInstance()->OnLacrosChromeAppWindowAdded(
+ app_id, window_id);
+ FullRestoreSaveHandler::GetInstance()->OnLacrosChromeAppWindowAdded(
+ app_id, window_id);
+}
+
+void OnLacrosChromeAppWindowRemoved(const std::string& app_id,
+ const std::string& window_id) {
+ if (!full_restore::features::IsFullRestoreForLacrosEnabled())
+ return;
+
+ FullRestoreReadHandler::GetInstance()->OnLacrosChromeAppWindowRemoved(
+ app_id, window_id);
+ FullRestoreSaveHandler::GetInstance()->OnLacrosChromeAppWindowRemoved(
+ app_id, window_id);
+}
+
} // namespace full_restore
diff --git a/chromium/components/app_restore/full_restore_utils.h b/chromium/components/app_restore/full_restore_utils.h
index 4b53591b9a7..f324b9f3968 100644
--- a/chromium/components/app_restore/full_restore_utils.h
+++ b/chromium/components/app_restore/full_restore_utils.h
@@ -35,10 +35,15 @@ void SaveAppLaunchInfo(
// Saves the window information to the full restore file.
COMPONENT_EXPORT(APP_RESTORE)
void SaveWindowInfo(const app_restore::WindowInfo& window_info);
+
// Sets the current active profile path.
COMPONENT_EXPORT(APP_RESTORE)
void SetActiveProfilePath(const base::FilePath& profile_path);
+// Sets the primary user profile path.
+COMPONENT_EXPORT(APP_RESTORE)
+void SetPrimaryProfilePath(const base::FilePath& profile_path);
+
// Returns true if there are app type browsers from the full restore file.
// Otherwise, returns false.
COMPONENT_EXPORT(APP_RESTORE)
@@ -66,6 +71,18 @@ void AddChromeBrowserLaunchInfoForTesting(const base::FilePath& profile_path);
COMPONENT_EXPORT(APP_RESTORE)
std::string GetAppId(aura::Window* window);
+// Invoked when an Chrome app Lacros window is created. `app_id` is the
+// AppService id, and `window_id` is the wayland app_id property for the window.
+COMPONENT_EXPORT(APP_RESTORE)
+void OnLacrosChromeAppWindowAdded(const std::string& app_id,
+ const std::string& window_id);
+
+// Invoked when an Chrome app Lacros window is removed. `app_id` is the
+// AppService id, and `window_id` is the wayland app_id property for the window.
+COMPONENT_EXPORT(APP_RESTORE)
+void OnLacrosChromeAppWindowRemoved(const std::string& app_id,
+ const std::string& window_id);
+
} // namespace full_restore
#endif // COMPONENTS_APP_RESTORE_FULL_RESTORE_UTILS_H_
diff --git a/chromium/components/app_restore/lacros_read_handler.cc b/chromium/components/app_restore/lacros_read_handler.cc
new file mode 100644
index 00000000000..97e3124a04f
--- /dev/null
+++ b/chromium/components/app_restore/lacros_read_handler.cc
@@ -0,0 +1,158 @@
+// Copyright 2022 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.
+
+#include "components/app_restore/lacros_read_handler.h"
+
+#include "ash/constants/app_types.h"
+#include "components/app_restore/app_restore_utils.h"
+#include "components/app_restore/full_restore_info.h"
+#include "components/app_restore/full_restore_read_handler.h"
+#include "components/app_restore/window_info.h"
+#include "components/app_restore/window_properties.h"
+#include "components/sessions/core/session_id.h"
+#include "ui/aura/client/aura_constants.h"
+#include "ui/aura/window.h"
+
+namespace app_restore {
+
+LacrosReadHandler::LacrosReadHandler(const base::FilePath& profile_path)
+ : profile_path_(profile_path) {}
+
+LacrosReadHandler::~LacrosReadHandler() = default;
+
+void LacrosReadHandler::AddRestoreData(const std::string& app_id,
+ int32_t window_id) {
+ restore_window_id_to_app_id_[window_id] = app_id;
+}
+
+void LacrosReadHandler::OnLacrosBrowserWindowAdded(
+ aura::Window* const window,
+ int32_t restored_browser_session_id) {
+ if (!IsLacrosWindow(window))
+ return;
+
+ auto it = window_to_window_data_.find(window);
+ if (it != window_to_window_data_.end() &&
+ it->second.restore_window_id == restored_browser_session_id) {
+ // `window` has been restored.
+ return;
+ }
+
+ window_to_window_data_[window].restore_window_id =
+ restored_browser_session_id;
+
+ // If there is a restore data, set the app id to restore `window`.
+ auto restore_it =
+ restore_window_id_to_app_id_.find(restored_browser_session_id);
+ if (restore_it != restore_window_id_to_app_id_.end())
+ window_to_window_data_[window].app_id = restore_it->second;
+
+ // If `window` is added to a hidden container, call UpdateWindow to restore
+ // and remove `window` from the hidden container.
+ if (base::Contains(window_candidates_, window))
+ UpdateWindow(window);
+}
+
+void LacrosReadHandler::OnAppWindowAdded(const std::string& app_id,
+ const std::string& lacros_window_id) {
+ lacros_window_id_to_app_id_[lacros_window_id] = app_id;
+
+ auto window_it =
+ std::find_if(window_candidates_.begin(), window_candidates_.end(),
+ [lacros_window_id](aura::Window* window) {
+ return GetLacrosWindowId(window) == lacros_window_id;
+ });
+ if (window_it == window_candidates_.end())
+ return;
+
+ SetWindowData(
+ *window_it, app_id,
+ full_restore::FullRestoreReadHandler::GetInstance()->FetchRestoreWindowId(
+ app_id));
+ UpdateWindow(*window_it);
+}
+
+void LacrosReadHandler::OnAppWindowRemoved(
+ const std::string& app_id,
+ const std::string& lacros_window_id) {
+ lacros_window_id_to_app_id_.erase(lacros_window_id);
+}
+
+void LacrosReadHandler::OnWindowAddedToRootWindow(aura::Window* window) {
+ if (!window->GetProperty(app_restore::kParentToHiddenContainerKey)) {
+ // If `window` has been removed from the hidden container, we don't need to
+ // restore it, because it has been restored.
+ return;
+ }
+
+ auto window_it = window_to_window_data_.find(window);
+ if (window_it != window_to_window_data_.end()) {
+ // We have received the restore window, so restore and remove `window` from
+ // the hidden container.
+ UpdateWindow(window);
+ return;
+ }
+
+ const auto lacros_window_id = GetLacrosWindowId(window);
+ auto it = lacros_window_id_to_app_id_.find(lacros_window_id);
+ if (it != lacros_window_id_to_app_id_.end()) {
+ // We have received the app id for the Chrome app window, so restore and
+ // remove `window` from the hidden container.
+ SetWindowData(window, it->second,
+ full_restore::FullRestoreReadHandler::GetInstance()
+ ->FetchRestoreWindowId(it->second));
+ UpdateWindow(window);
+ return;
+ }
+
+ // We haven't received the restore window id, add `window` to
+ // `window_candidates_` to wait for the restore window id.
+ window_candidates_.insert(window);
+}
+
+void LacrosReadHandler::OnWindowDestroyed(aura::Window* window) {
+ window_candidates_.erase(window);
+ window_to_window_data_.erase(window);
+}
+
+int32_t LacrosReadHandler::GetLacrosRestoreWindowId(
+ const std::string& lacros_window_id) const {
+ auto it = lacros_window_id_to_app_id_.find(lacros_window_id);
+ return it == lacros_window_id_to_app_id_.end()
+ ? kParentToHiddenContainer
+ : full_restore::FullRestoreReadHandler::GetInstance()
+ ->FetchRestoreWindowId(it->second);
+}
+
+void LacrosReadHandler::SetWindowData(aura::Window* const window,
+ const std::string& app_id,
+ int32_t restore_window_id) {
+ if (base::Contains(restore_window_id_to_app_id_, restore_window_id))
+ window_to_window_data_[window].app_id = app_id;
+ window_to_window_data_[window].restore_window_id = restore_window_id;
+}
+
+void LacrosReadHandler::UpdateWindow(aura::Window* const window) {
+ auto it = window_to_window_data_.find(window);
+ if (it != window_to_window_data_.end() && !it->second.app_id.empty()) {
+ // `window` is restored, so set the window property `kRestoreWindowIdKey`
+ // and `kWindowInfoKey` to restore `window`.
+ window->SetProperty(kRestoreWindowIdKey, it->second.restore_window_id);
+ auto window_info =
+ full_restore::FullRestoreReadHandler::GetInstance()->GetWindowInfo(
+ profile_path_, it->second.app_id, it->second.restore_window_id);
+ if (window_info)
+ ApplyProperties(window_info.get(), window);
+
+ restore_window_id_to_app_id_.erase(it->second.restore_window_id);
+ }
+
+ // Remove the window from the hidden container.
+ full_restore::FullRestoreInfo::GetInstance()->OnParentWindowToValidContainer(
+ window);
+
+ window_candidates_.erase(window);
+}
+
+} // namespace app_restore
diff --git a/chromium/components/app_restore/lacros_read_handler.h b/chromium/components/app_restore/lacros_read_handler.h
new file mode 100644
index 00000000000..c354c97fae7
--- /dev/null
+++ b/chromium/components/app_restore/lacros_read_handler.h
@@ -0,0 +1,122 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_APP_RESTORE_LACROS_READ_HANDLER_H_
+#define COMPONENTS_APP_RESTORE_LACROS_READ_HANDLER_H_
+
+#include <map>
+#include <set>
+
+#include "base/component_export.h"
+#include "base/files/file_path.h"
+
+namespace aura {
+class Window;
+}
+
+namespace app_restore {
+
+// LacrosSaveHandler is a helper class for FullRestoreReadHandler to restore
+// Lacros windows.
+//
+// For Lacros browser window, the restored browser session id is used as the
+// restore window id. So only when the restored browser session id is received
+// via mojom calls, the window can be restored. OnLacrosBrowserWindowAdded is
+// called when both `window` is initialized, and the restored browser session id
+// is received. So there could be 2 scenarios:
+//
+// 1. `window` is initialized first, then `window` is added to the hidden
+// container, and OnWindowAddedToRootWindow is called to save `window` in
+// `window_candidates_` to wait for the restored browser session id. When
+// OnLacrosBrowserWindowAdded is called, call UpdateWindow to apply the restore
+// window properties, and remove `window` from the hidden container.
+//
+// 2. The restored browser session id is received first, then
+// OnLacrosBrowserWindowAdded is called when `window` is initialized. We have to
+// wait for the OnWindowAddedToRootWindow callback, because `window`'s root is
+// not set yet in the OnWindowInitialized/OnLacrosBrowserWindowAdded callback,
+// and we can't remove `window` from the hidden container. When
+// OnWindowAddedToRootWindow is called, `window` can be restored and removed
+// from the hidden container.
+//
+// TODO(crbug.com/1239984): Restore Lacros windows.
+class COMPONENT_EXPORT(APP_RESTORE) LacrosReadHandler {
+ public:
+ LacrosReadHandler(const base::FilePath& profile_path);
+ LacrosReadHandler(const LacrosReadHandler&) = delete;
+ LacrosReadHandler& operator=(const LacrosReadHandler&) = delete;
+ ~LacrosReadHandler();
+
+ // Sets `app_id` and `window_id` to `restore_window_id_to_app_id_` to record
+ // that there is a restore data for `app_id` and `window_id`.
+ void AddRestoreData(const std::string& app_id, int32_t window_id);
+
+ // Invoked when Lacros window is created. `restored_browser_session_id` is the
+ // restored browser session id.
+ void OnLacrosBrowserWindowAdded(aura::Window* const window,
+ int32_t restored_browser_session_id);
+
+ // Invoked when an Chrome app Lacros window is created. `app_id` is the
+ // AppService id, and `window_id` is the wayland app_id property for the
+ // window.
+ void OnAppWindowAdded(const std::string& app_id,
+ const std::string& lacros_window_id);
+
+ // Invoked when an Chrome app Lacros window is removed. `app_id` is the
+ // AppService id, and `window_id` is the wayland app_id property for the
+ // window.
+ void OnAppWindowRemoved(const std::string& app_id,
+ const std::string& lacros_window_id);
+
+ // Invoked when `window` is added to the root window.
+ void OnWindowAddedToRootWindow(aura::Window* window);
+
+ // Invoked when `window` is destroyed.
+ void OnWindowDestroyed(aura::Window* window);
+
+ // Returns the restore window id for the Lacros window with
+ // `lacros_window_id`.
+ int32_t GetLacrosRestoreWindowId(const std::string& lacros_window_id) const;
+
+ private:
+ struct WindowData {
+ std::string app_id;
+ int32_t restore_window_id = -1;
+ };
+
+ // Sets `app_id` and `restore_window_id` for `window` in
+ // `window_to_window_data_`. If there is no restore data for
+ // `restore_window_id`, `app_id` won't be set to skip setting the restore data
+ // for `window`.
+ void SetWindowData(aura::Window* const window,
+ const std::string& app_id,
+ int32_t restore_window_id);
+
+ // Sets `kRestoreWindowIdKey` and `kWindowInfoKey` to restore and remove
+ // `window from the hidden container`.
+ void UpdateWindow(aura::Window* const window);
+
+ // The user profile path for Lacros windows.
+ base::FilePath profile_path_;
+
+ // The map from the restore window id to the app id for Lacros windows.
+ std::map<int32_t, std::string> restore_window_id_to_app_id_;
+
+ // The map from the window to the app id and the restore window id.
+ std::map<aura::Window*, WindowData> window_to_window_data_;
+
+ // The mojom call to forward the restore window id could be received later
+ // than the OnWindowAddedToRootWindow callback. So add windows to
+ // `window_candidates_` to record window candidates. Once the restore window
+ // id is received, the window can be restored and removed from the hidden
+ // container.
+ std::set<aura::Window*> window_candidates_;
+
+ // The map from the lacros window id to the app id for Chrome app windows.
+ std::map<std::string, std::string> lacros_window_id_to_app_id_;
+};
+
+} // namespace app_restore
+
+#endif // COMPONENTS_APP_RESTORE_LACROS_READ_HANDLER_H_
diff --git a/chromium/components/app_restore/lacros_save_handler.cc b/chromium/components/app_restore/lacros_save_handler.cc
new file mode 100644
index 00000000000..8fd494ce84f
--- /dev/null
+++ b/chromium/components/app_restore/lacros_save_handler.cc
@@ -0,0 +1,154 @@
+// Copyright 2022 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.
+
+#include "components/app_restore/lacros_save_handler.h"
+
+#include "components/app_constants/constants.h"
+#include "components/app_restore/app_launch_info.h"
+#include "components/app_restore/app_restore_utils.h"
+#include "components/app_restore/full_restore_save_handler.h"
+#include "components/app_restore/window_info.h"
+#include "ui/aura/window.h"
+
+namespace full_restore {
+
+LacrosSaveHandler::LacrosSaveHandler(const base::FilePath& profile_path)
+ : profile_path_(profile_path) {}
+
+LacrosSaveHandler::~LacrosSaveHandler() = default;
+
+void LacrosSaveHandler::OnWindowInitialized(aura::Window* window) {
+ const std::string lacros_window_id = app_restore::GetLacrosWindowId(window);
+
+ // If `window` has been saved by OnBrowserWindowAdded, we don't need to save
+ // again.
+ if (base::Contains(window_candidates_, lacros_window_id))
+ return;
+
+ std::string app_id;
+ int32_t window_id = ++window_id_;
+ std::unique_ptr<app_restore::AppLaunchInfo> app_launch_info;
+
+ auto it = lacros_window_id_to_app_id_.find(lacros_window_id);
+ if (it != lacros_window_id_to_app_id_.end()) {
+ // For Chrome app windows, get the app launch info and set the Chrome app
+ // id.
+ app_id = it->second;
+ app_launch_info = FullRestoreSaveHandler::GetInstance()->FetchAppLaunchInfo(
+ profile_path_, app_id);
+ app_launch_info->window_id = window_id;
+ } else {
+ app_id = app_constants::kLacrosAppId;
+ app_launch_info =
+ std::make_unique<app_restore::AppLaunchInfo>(app_id, window_id);
+ }
+
+ window_candidates_[lacros_window_id].app_id = app_id;
+ window_candidates_[lacros_window_id].window_id = window_id;
+
+ FullRestoreSaveHandler::GetInstance()->AddAppLaunchInfo(
+ profile_path_, std::move(app_launch_info));
+}
+
+void LacrosSaveHandler::OnWindowDestroyed(aura::Window* window) {
+ const std::string lacros_window_id = app_restore::GetLacrosWindowId(window);
+ lacros_window_id_to_app_id_.erase(lacros_window_id);
+
+ auto it = window_candidates_.find(lacros_window_id);
+ if (it == window_candidates_.end())
+ return;
+
+ FullRestoreSaveHandler::GetInstance()->RemoveAppRestoreData(
+ profile_path_, it->second.app_id, it->second.window_id);
+
+ window_candidates_.erase(it);
+}
+
+void LacrosSaveHandler::OnBrowserWindowAdded(aura::Window* const window,
+ uint32_t browser_session_id) {
+ const std::string lacros_window_id = app_restore::GetLacrosWindowId(window);
+ std::unique_ptr<app_restore::WindowInfo> window_info;
+ auto* save_handler = FullRestoreSaveHandler::GetInstance();
+ DCHECK(save_handler);
+
+ auto it = window_candidates_.find(lacros_window_id);
+ if (it != window_candidates_.end() &&
+ it->second.window_id != browser_session_id) {
+ // If the window has been created and saved using different window id, get
+ // the current window info, then remove the restore data for the old window
+ // id, and re-save the restore data with the new `browser_session_id`.
+ window_info = save_handler->GetWindowInfo(profile_path_, it->second.app_id,
+ it->second.window_id);
+
+ save_handler->RemoveAppRestoreData(profile_path_, it->second.app_id,
+ it->second.window_id);
+ }
+
+ window_candidates_[lacros_window_id].app_id = app_constants::kLacrosAppId;
+ window_candidates_[lacros_window_id].window_id = browser_session_id;
+
+ save_handler->AddAppLaunchInfo(
+ profile_path_, std::make_unique<app_restore::AppLaunchInfo>(
+ app_constants::kLacrosAppId, browser_session_id));
+
+ if (window_info) {
+ save_handler->ModifyWindowInfo(profile_path_, app_constants::kLacrosAppId,
+ browser_session_id, *window_info);
+ }
+}
+
+void LacrosSaveHandler::OnAppWindowAdded(const std::string& app_id,
+ const std::string& lacros_window_id) {
+ auto it = window_candidates_.find(lacros_window_id);
+ if (it == window_candidates_.end()) {
+ // If the window is not created yet, save the app id to
+ // `lacros_window_id_to_app_id_` to wait for the window.
+ lacros_window_id_to_app_id_[lacros_window_id] = app_id;
+ return;
+ }
+
+ // If the window has been created, get the app launch info and the current
+ // window info, then remove the restore data for lacros browser app id, and
+ // re-save the restore data for the Chrome app id.
+
+ auto* save_handler = FullRestoreSaveHandler::GetInstance();
+ DCHECK(save_handler);
+ auto window_info = save_handler->GetWindowInfo(
+ profile_path_, it->second.app_id, it->second.window_id);
+
+ save_handler->RemoveAppRestoreData(profile_path_, it->second.app_id,
+ it->second.window_id);
+
+ it->second.app_id = app_id;
+ auto app_launch_info =
+ save_handler->FetchAppLaunchInfo(profile_path_, app_id);
+ app_launch_info->window_id = it->second.window_id;
+
+ save_handler->AddAppLaunchInfo(profile_path_, std::move(app_launch_info));
+ save_handler->ModifyWindowInfo(profile_path_, app_id, it->second.window_id,
+ *window_info);
+}
+
+void LacrosSaveHandler::OnAppWindowRemoved(
+ const std::string& app_id,
+ const std::string& lacros_window_id) {
+ lacros_window_id_to_app_id_.erase(lacros_window_id);
+}
+
+void LacrosSaveHandler::ModifyWindowInfo(
+ const app_restore::WindowInfo& window_info) {
+ auto it = window_candidates_.find(
+ app_restore::GetLacrosWindowId(window_info.window));
+ if (it != window_candidates_.end()) {
+ FullRestoreSaveHandler::GetInstance()->ModifyWindowInfo(
+ profile_path_, it->second.app_id, it->second.window_id, window_info);
+ }
+}
+
+std::string LacrosSaveHandler::GetAppId(aura::Window* window) {
+ auto it = window_candidates_.find(app_restore::GetLacrosWindowId(window));
+ return it != window_candidates_.end() ? it->second.app_id : std::string();
+}
+
+} // namespace full_restore
diff --git a/chromium/components/app_restore/lacros_save_handler.h b/chromium/components/app_restore/lacros_save_handler.h
new file mode 100644
index 00000000000..94bbe905731
--- /dev/null
+++ b/chromium/components/app_restore/lacros_save_handler.h
@@ -0,0 +1,89 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_APP_RESTORE_LACROS_SAVE_HANDLER_H_
+#define COMPONENTS_APP_RESTORE_LACROS_SAVE_HANDLER_H_
+
+#include <map>
+
+#include "base/component_export.h"
+#include "base/files/file_path.h"
+
+namespace app_restore {
+struct WindowInfo;
+} // namespace app_restore
+
+namespace aura {
+class Window;
+} // namespace aura
+
+namespace full_restore {
+
+// LacrosSaveHandler is a helper class for FullRestoreSaveHandler to handle
+// Lacros windows special cases, e.g. Lacros window id, etc.
+class COMPONENT_EXPORT(APP_RESTORE) LacrosSaveHandler {
+ public:
+ explicit LacrosSaveHandler(const base::FilePath& profile_path);
+ LacrosSaveHandler(const LacrosSaveHandler&) = delete;
+ LacrosSaveHandler& operator=(const LacrosSaveHandler&) = delete;
+ ~LacrosSaveHandler();
+
+ // Invoked when `window` is initialized.
+ void OnWindowInitialized(aura::Window* window);
+
+ // Invoked when `window` is destroyed.
+ void OnWindowDestroyed(aura::Window* window);
+
+ // Invoked when Lacros browser window is created. `browser_session_id` is the
+ // current browser session id.
+ void OnBrowserWindowAdded(aura::Window* const window,
+ uint32_t browser_session_id);
+
+ // Invoked when an Chrome app Lacros window is created. `app_id` is the
+ // AppService id, and `window_id` is the wayland app_id property for the
+ // window.
+ void OnAppWindowAdded(const std::string& app_id,
+ const std::string& lacros_window_id);
+
+ // Invoked when an Chrome app Lacros window is removed. `app_id` is the
+ // AppService id, and `window_id` is the wayland app_id property for the
+ // window.
+ void OnAppWindowRemoved(const std::string& app_id,
+ const std::string& lacros_window_id);
+
+ // Saves `window_info`.
+ void ModifyWindowInfo(const app_restore::WindowInfo& window_info);
+
+ // Returns the app id that associates with `window`.
+ std::string GetAppId(aura::Window* window);
+
+ private:
+ friend class FullRestoreSaveHandlerTestApi;
+
+ struct WindowData {
+ std::string app_id;
+ uint32_t window_id = 0;
+ };
+
+ // The primary user profile path.
+ base::FilePath profile_path_;
+
+ // `window_id_` is used to record the current used window id. When a new
+ // Lacros window is created, ++window_id to generate the new window id.
+ uint32_t window_id_ = 0;
+
+ // |window_candidates_| is used to record the map from the exo application id
+ // to `app_id` and `window_id`. `app_id` might be changed for Chrome app
+ // windows because the Lacros app id is set for all Lacros windows, and when
+ // OnAppWindowAdded is called, `app_id` is modified to the Chrome app id. The
+ // record is removed when the window is destroyed.
+ std::map<std::string, WindowData> window_candidates_;
+
+ // The map from the lacros window id to the app id for Chrome app windows.
+ std::map<std::string, std::string> lacros_window_id_to_app_id_;
+};
+
+} // namespace full_restore
+
+#endif // COMPONENTS_APP_RESTORE_LACROS_SAVE_HANDLER_H_
diff --git a/chromium/components/app_restore/restore_data.cc b/chromium/components/app_restore/restore_data.cc
index d5477ba51a0..8be1dbb5e03 100644
--- a/chromium/components/app_restore/restore_data.cc
+++ b/chromium/components/app_restore/restore_data.cc
@@ -6,49 +6,43 @@
#include <utility>
+#include "base/i18n/number_formatting.h"
#include "base/strings/string_number_conversions.h"
#include "base/values.h"
+#include "components/app_constants/constants.h"
#include "components/app_restore/app_launch_info.h"
#include "components/app_restore/window_info.h"
-#include "extensions/common/constants.h"
namespace app_restore {
RestoreData::RestoreData() = default;
RestoreData::RestoreData(std::unique_ptr<base::Value> restore_data_value) {
- base::DictionaryValue* restore_data_dict = nullptr;
- if (!restore_data_value || !restore_data_value->is_dict() ||
- !restore_data_value->GetAsDictionary(&restore_data_dict) ||
- !restore_data_dict) {
+ if (!restore_data_value || !restore_data_value->is_dict()) {
DVLOG(0) << "Fail to parse full restore data. "
<< "Cannot find the full restore data dict.";
return;
}
- for (base::DictionaryValue::Iterator iter(*restore_data_dict);
- !iter.IsAtEnd(); iter.Advance()) {
- const std::string& app_id = iter.key();
- base::Value* value = restore_data_dict->FindDictKey(app_id);
- base::DictionaryValue* data_dict = nullptr;
- if (!value || !value->is_dict() || !value->GetAsDictionary(&data_dict) ||
- !data_dict) {
+ for (auto iter : restore_data_value->DictItems()) {
+ const std::string& app_id = iter.first;
+ base::Value* value = restore_data_value->FindDictKey(app_id);
+ if (!value || !value->is_dict()) {
DVLOG(0) << "Fail to parse full restore data. "
<< "Cannot find the app restore data dict.";
continue;
}
- for (base::DictionaryValue::Iterator data_iter(*data_dict);
- !data_iter.IsAtEnd(); data_iter.Advance()) {
+ for (auto data_iter : value->DictItems()) {
int window_id = 0;
- if (!base::StringToInt(data_iter.key(), &window_id)) {
+ if (!base::StringToInt(data_iter.first, &window_id)) {
DVLOG(0) << "Fail to parse full restore data. "
<< "Cannot find the valid id.";
continue;
}
app_id_to_launch_list_[app_id][window_id] =
std::make_unique<AppRestoreData>(
- std::move(*data_dict->FindDictKey(data_iter.key())));
+ std::move(*value->FindDictKey(data_iter.first)));
}
}
}
@@ -84,7 +78,7 @@ base::Value RestoreData::ConvertToValue() const {
}
bool RestoreData::HasAppTypeBrowser() const {
- auto it = app_id_to_launch_list_.find(extension_misc::kChromeAppId);
+ auto it = app_id_to_launch_list_.find(app_constants::kChromeAppId);
if (it == app_id_to_launch_list_.end())
return false;
@@ -98,7 +92,7 @@ bool RestoreData::HasAppTypeBrowser() const {
}
bool RestoreData::HasBrowser() const {
- auto it = app_id_to_launch_list_.find(extension_misc::kChromeAppId);
+ auto it = app_id_to_launch_list_.find(app_constants::kChromeAppId);
if (it == app_id_to_launch_list_.end())
return false;
@@ -251,6 +245,19 @@ const AppRestoreData* RestoreData::GetAppRestoreData(const std::string& app_id,
return data_it->second.get();
}
+std::string RestoreData::ToString() const {
+ if (app_id_to_launch_list_.empty())
+ return "empty";
+
+ std::string result = "( ";
+ for (const auto& entry : app_id_to_launch_list_) {
+ result += base::StringPrintf(
+ "(App ID: %s, Count: %s)", entry.first.c_str(),
+ base::UTF16ToUTF8(base::FormatNumber(entry.second.size())).c_str());
+ }
+ return result + " )";
+}
+
AppRestoreData* RestoreData::GetAppRestoreDataMutable(const std::string& app_id,
int window_id) {
return const_cast<AppRestoreData*>(GetAppRestoreData(app_id, window_id));
diff --git a/chromium/components/app_restore/restore_data.h b/chromium/components/app_restore/restore_data.h
index 1623fd3f424..0310df800ef 100644
--- a/chromium/components/app_restore/restore_data.h
+++ b/chromium/components/app_restore/restore_data.h
@@ -23,11 +23,6 @@ struct WindowInfo;
// This class is responsible for saving all app launch and app windows
// information. It can be converted to JSON format to be written to the
// FullRestoreData file.
-//
-// TODO(crbug.com/1146900):
-// 1. Add the interface to modify LaunchAndWindowInfo when the window
-// information is updated.
-// 2. Add the interface to remove LaunchAndWindowInfo.
class COMPONENT_EXPORT(APP_RESTORE) RestoreData {
public:
// Map from a window id to AppRestoreData.
@@ -174,6 +169,8 @@ class COMPONENT_EXPORT(APP_RESTORE) RestoreData {
const AppRestoreData* GetAppRestoreData(const std::string& app_id,
int window_id) const;
+ std::string ToString() const;
+
const AppIdToLaunchList& app_id_to_launch_list() const {
return app_id_to_launch_list_;
}
diff --git a/chromium/components/app_restore/restore_data_unittest.cc b/chromium/components/app_restore/restore_data_unittest.cc
index f904dd43313..d543bd72f7d 100644
--- a/chromium/components/app_restore/restore_data_unittest.cc
+++ b/chromium/components/app_restore/restore_data_unittest.cc
@@ -10,11 +10,11 @@
#include "base/containers/contains.h"
#include "base/values.h"
#include "chromeos/ui/base/window_state_type.h"
+#include "components/app_constants/constants.h"
#include "components/app_restore/app_launch_info.h"
#include "components/app_restore/app_restore_data.h"
#include "components/app_restore/window_info.h"
#include "components/services/app_service/public/mojom/types.mojom.h"
-#include "extensions/common/constants.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/base/window_open_disposition.h"
@@ -693,12 +693,12 @@ TEST_F(RestoreDataTest, FetchRestoreWindowId) {
TEST_F(RestoreDataTest, HasAppTypeBrowser) {
std::unique_ptr<AppLaunchInfo> app_launch_info1 =
- std::make_unique<AppLaunchInfo>(extension_misc::kChromeAppId, kWindowId1);
+ std::make_unique<AppLaunchInfo>(app_constants::kChromeAppId, kWindowId1);
restore_data().AddAppLaunchInfo(std::move(app_launch_info1));
EXPECT_FALSE(restore_data().HasAppTypeBrowser());
std::unique_ptr<AppLaunchInfo> app_launch_info2 =
- std::make_unique<AppLaunchInfo>(extension_misc::kChromeAppId, kWindowId2);
+ std::make_unique<AppLaunchInfo>(app_constants::kChromeAppId, kWindowId2);
app_launch_info2->app_type_browser = true;
restore_data().AddAppLaunchInfo(std::move(app_launch_info2));
EXPECT_TRUE(restore_data().HasAppTypeBrowser());
@@ -706,13 +706,13 @@ TEST_F(RestoreDataTest, HasAppTypeBrowser) {
TEST_F(RestoreDataTest, HasBrowser) {
std::unique_ptr<AppLaunchInfo> app_launch_info1 =
- std::make_unique<AppLaunchInfo>(extension_misc::kChromeAppId, kWindowId1);
+ std::make_unique<AppLaunchInfo>(app_constants::kChromeAppId, kWindowId1);
app_launch_info1->app_type_browser = true;
restore_data().AddAppLaunchInfo(std::move(app_launch_info1));
EXPECT_FALSE(restore_data().HasBrowser());
std::unique_ptr<AppLaunchInfo> app_launch_info2 =
- std::make_unique<AppLaunchInfo>(extension_misc::kChromeAppId, kWindowId2);
+ std::make_unique<AppLaunchInfo>(app_constants::kChromeAppId, kWindowId2);
restore_data().AddAppLaunchInfo(std::move(app_launch_info2));
EXPECT_TRUE(restore_data().HasBrowser());
}
diff --git a/chromium/components/app_restore/window_properties.cc b/chromium/components/app_restore/window_properties.cc
index 160ebf7d30a..5cda130db6d 100644
--- a/chromium/components/app_restore/window_properties.cc
+++ b/chromium/components/app_restore/window_properties.cc
@@ -17,6 +17,7 @@ DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(std::string, kAppIdKey, nullptr)
DEFINE_UI_CLASS_PROPERTY_KEY(bool, kAppTypeBrowser, false)
DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(std::string, kBrowserAppNameKey, nullptr)
DEFINE_UI_CLASS_PROPERTY_KEY(int32_t, kGhostWindowSessionIdKey, 0)
+DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(std::string, kLacrosWindowId, nullptr)
DEFINE_UI_CLASS_PROPERTY_KEY(bool, kLaunchedFromFullRestoreKey, false)
DEFINE_UI_CLASS_PROPERTY_KEY(bool, kParentToHiddenContainerKey, false)
DEFINE_UI_CLASS_PROPERTY_KEY(bool, kRealArcTaskWindow, true)
diff --git a/chromium/components/app_restore/window_properties.h b/chromium/components/app_restore/window_properties.h
index f4f94d93595..551813adcb5 100644
--- a/chromium/components/app_restore/window_properties.h
+++ b/chromium/components/app_restore/window_properties.h
@@ -41,6 +41,10 @@ extern const ui::ClassProperty<std::string*>* const kBrowserAppNameKey;
COMPONENT_EXPORT(APP_RESTORE)
extern const ui::ClassProperty<int32_t>* const kGhostWindowSessionIdKey;
+// A property key to store the window id for a Lacros window.
+COMPONENT_EXPORT(APP_RESTORE)
+extern const ui::ClassProperty<std::string*>* const kLacrosWindowId;
+
// A property key indicating whether a window was launched from full restore.
// These windows will not be activatable until they are shown.
COMPONENT_EXPORT(APP_RESTORE)
diff --git a/chromium/components/arc/BUILD.gn b/chromium/components/arc/BUILD.gn
index 2bc11e54fb5..fb538443395 100644
--- a/chromium/components/arc/BUILD.gn
+++ b/chromium/components/arc/BUILD.gn
@@ -17,8 +17,6 @@ static_library("arc") {
"intent_helper/intent_constants.h",
"intent_helper/intent_filter.cc",
"intent_helper/intent_filter.h",
- "intent_helper/link_handler_model.cc",
- "intent_helper/link_handler_model.h",
"intent_helper/open_url_delegate.h",
]
@@ -26,13 +24,9 @@ static_library("arc") {
"//ash/components/arc",
"//ash/public/cpp",
"//components/arc/common",
+ "//components/arc/common:arc_intent_helper_constants",
"//components/exo",
"//components/google/core/common",
-
- # TODO(crbug.com/853604): After fully migrating the intent picker to query
- # directly from App Service, we will deprecated the match functionality
- # in intent_filter and this dependency will be removed.
- "//components/services/app_service/public/cpp:intents",
"//components/url_formatter",
]
}
@@ -40,11 +34,16 @@ static_library("arc") {
static_library("arc_test_support") {
testonly = true
sources = [
+ "test/fake_intent_helper_host.cc",
+ "test/fake_intent_helper_host.h",
"test/fake_intent_helper_instance.cc",
"test/fake_intent_helper_instance.h",
]
- deps = [ "//ash/components/arc/mojom" ]
+ deps = [
+ "//ash/components/arc/mojom",
+ "//ash/components/arc/session:connection_holder",
+ ]
}
source_set("unit_tests") {
@@ -52,8 +51,6 @@ source_set("unit_tests") {
sources = [
"intent_helper/arc_intent_helper_bridge_unittest.cc",
"intent_helper/custom_tab_unittest.cc",
- "intent_helper/intent_filter_unittest.cc",
- "intent_helper/link_handler_model_unittest.cc",
]
deps = [
@@ -62,6 +59,7 @@ source_set("unit_tests") {
"//ash/components/arc/mojom",
"//ash/components/arc/session",
"//base/test:test_support",
+ "//components/arc/common:arc_intent_helper_constants",
"//testing/gmock",
"//testing/gtest",
"//ui/aura:test_support",
diff --git a/chromium/components/arc/DEPS b/chromium/components/arc/DEPS
index 11a7184d62b..11e8d5c8a71 100644
--- a/chromium/components/arc/DEPS
+++ b/chromium/components/arc/DEPS
@@ -1,9 +1,9 @@
include_rules = [
"+ash/components/arc",
+ "+ash/components/cryptohome",
"+ash/constants",
"+ash/public/cpp",
"+chromeos/components/sensors",
- "+chromeos/cryptohome",
"+chromeos/dbus",
"+chromeos/memory",
"+chromeos/system",
diff --git a/chromium/components/arc/common/BUILD.gn b/chromium/components/arc/common/BUILD.gn
index 5e4067e64c4..f14d54dbf78 100644
--- a/chromium/components/arc/common/BUILD.gn
+++ b/chromium/components/arc/common/BUILD.gn
@@ -10,11 +10,19 @@ static_library("common") {
"intent_helper/activity_icon_loader.cc",
"intent_helper/activity_icon_loader.h",
"intent_helper/adaptive_icon_delegate.h",
+ "intent_helper/arc_icon_cache_delegate.cc",
+ "intent_helper/arc_icon_cache_delegate.h",
+ "intent_helper/arc_intent_helper_mojo_delegate.cc",
+ "intent_helper/arc_intent_helper_mojo_delegate.h",
+ "intent_helper/link_handler_model.cc",
+ "intent_helper/link_handler_model.h",
]
deps = [
+ ":arc_intent_helper_constants",
"//base",
"//build:chromeos_buildflags",
+ "//components/google/core/common",
"//ui/base",
"//ui/gfx",
"//url:url",
@@ -22,7 +30,9 @@ static_library("common") {
if (is_chromeos_ash) {
deps += [
+ "//ash/components/arc",
"//ash/components/arc:arc_base_utils",
+ "//ash/components/arc:arc_metrics_constants",
"//ash/components/arc/mojom",
"//ash/components/arc/session",
]
@@ -36,14 +46,36 @@ static_library("common") {
}
}
+static_library("arc_intent_helper_constants") {
+ sources = [ "intent_helper/arc_intent_helper_package.h" ]
+}
+
+static_library("arc_test_support") {
+ testonly = true
+ sources = [
+ "test/fake_arc_icon_cache.cc",
+ "test/fake_arc_icon_cache.h",
+ "test/fake_arc_intent_helper_mojo.cc",
+ "test/fake_arc_intent_helper_mojo.h",
+ ]
+ deps = [
+ "//components/arc/common",
+ "//ui/base",
+ ]
+}
+
source_set("unit_tests") {
testonly = true
- sources = [ "intent_helper/activity_icon_loader_unittest.cc" ]
+ sources = [
+ "intent_helper/activity_icon_loader_unittest.cc",
+ "intent_helper/link_handler_model_unittest.cc",
+ ]
deps = [
":common",
"//base/test:test_support",
"//testing/gtest",
"//ui/gfx",
+ "//url:url",
]
}
diff --git a/chromium/components/arc/common/intent_helper/DEPS b/chromium/components/arc/common/intent_helper/DEPS
index a80fe55ee50..78adacd3352 100644
--- a/chromium/components/arc/common/intent_helper/DEPS
+++ b/chromium/components/arc/common/intent_helper/DEPS
@@ -1,9 +1,11 @@
include_rules = [
"+ash/components/arc/arc_util.h",
+ "+ash/components/arc/metrics",
+ "+ash/components/arc/mojom",
+ "+ash/components/arc/session",
"+chromeos/crosapi/mojom",
"+chromeos/lacros",
- "+components/arc/mojom",
- "+components/arc/session",
+ "+components/google/core/common/google_util.h",
"+ui/base",
"+ui/gfx",
]
diff --git a/chromium/components/arc/common/intent_helper/activity_icon_loader.cc b/chromium/components/arc/common/intent_helper/activity_icon_loader.cc
index 58b9fe75f25..4eb11b50109 100644
--- a/chromium/components/arc/common/intent_helper/activity_icon_loader.cc
+++ b/chromium/components/arc/common/intent_helper/activity_icon_loader.cc
@@ -82,8 +82,47 @@ GetInstanceForRequestActivityIcons() {
return instance;
}
#else // BUILDFLAG(IS_CHROMEOS_LACROS)
+// Adapter class for wrapping crosapi::mojom::Arc used in lacros-chrome.
+// This is returned from GetInstanceForRequestActivityIcons().
+class Adapter {
+ public:
+ explicit Adapter(crosapi::mojom::Arc* instance) : instance_(instance) {}
+ ~Adapter() = default;
+
+ using OnRequestActivityIconsSucceededCallback =
+ base::OnceCallback<void(std::vector<crosapi::mojom::ActivityIconPtr>)>;
+
+ // If status is not kSuccess, immediately return callback.
+ void RequestActivityIcons(
+ std::vector<crosapi::mojom::ActivityNamePtr> activities,
+ crosapi::mojom::ScaleFactor scale_factor,
+ OnRequestActivityIconsSucceededCallback cb) {
+ instance_->RequestActivityIcons(
+ std::move(activities), scale_factor,
+ base::BindOnce(
+ [](OnRequestActivityIconsSucceededCallback cb,
+ std::vector<crosapi::mojom::ActivityIconPtr> icons,
+ crosapi::mojom::RequestActivityIconsStatus status) {
+ // If status is not kSuccess, immediately return callback.
+ if (status == crosapi::mojom::RequestActivityIconsStatus::
+ kArcNotAvailable) {
+ LOG(ERROR) << "Failed to connect to ARC in ash-chrome.";
+ std::move(cb).Run(
+ std::vector<crosapi::mojom::ActivityIconPtr>());
+ return;
+ }
+
+ std::move(cb).Run(std::move(icons));
+ },
+ std::move(cb)));
+ }
+
+ private:
+ crosapi::mojom::Arc* instance_;
+};
+
// Lacros requests icons to ash-chrome via crosapi.
-absl::variant<crosapi::mojom::Arc*, ActivityIconLoader::GetResult>
+absl::variant<std::unique_ptr<Adapter>, ActivityIconLoader::GetResult>
GetInstanceForRequestActivityIcons() {
auto* service = chromeos::LacrosService::Get();
@@ -101,7 +140,8 @@ GetInstanceForRequestActivityIcons() {
return ActivityIconLoader::GetResult::FAILED_ARC_NOT_SUPPORTED;
}
- return service->GetRemote<crosapi::mojom::Arc>().get();
+ return std::make_unique<Adapter>(
+ service->GetRemote<crosapi::mojom::Arc>().get());
}
#endif
diff --git a/chromium/components/arc/common/intent_helper/arc_icon_cache_delegate.cc b/chromium/components/arc/common/intent_helper/arc_icon_cache_delegate.cc
new file mode 100644
index 00000000000..3e8772d53f2
--- /dev/null
+++ b/chromium/components/arc/common/intent_helper/arc_icon_cache_delegate.cc
@@ -0,0 +1,46 @@
+// Copyright 2022 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.
+
+#include "components/arc/common/intent_helper/arc_icon_cache_delegate.h"
+
+#include "base/logging.h"
+
+namespace arc {
+
+namespace {
+ArcIconCacheDelegateProvider* g_delegate_provider = nullptr;
+}
+
+// static
+ArcIconCacheDelegate* ArcIconCacheDelegate::GetInstance() {
+ if (!g_delegate_provider)
+ return nullptr;
+ return g_delegate_provider->GetInstance();
+}
+
+ArcIconCacheDelegate::~ArcIconCacheDelegate() = default;
+
+ArcIconCacheDelegateProvider::ArcIconCacheDelegateProvider(
+ ArcIconCacheDelegate* delegate)
+ : delegate_(delegate) {
+ if (g_delegate_provider) {
+ LOG(ERROR) << "Overwriting g_delegate_provider. "
+ << "This should not happend except for testing.";
+ }
+ g_delegate_provider = this;
+}
+
+ArcIconCacheDelegateProvider::~ArcIconCacheDelegateProvider() {
+ if (g_delegate_provider != this) {
+ LOG(ERROR) << "g_delegate_provider was not properly set. "
+ << "This should not happend except for testing.";
+ }
+ g_delegate_provider = nullptr;
+}
+
+ArcIconCacheDelegate* ArcIconCacheDelegateProvider::GetInstance() {
+ return delegate_;
+}
+
+} // namespace arc
diff --git a/chromium/components/arc/common/intent_helper/arc_icon_cache_delegate.h b/chromium/components/arc/common/intent_helper/arc_icon_cache_delegate.h
new file mode 100644
index 00000000000..8826a773b88
--- /dev/null
+++ b/chromium/components/arc/common/intent_helper/arc_icon_cache_delegate.h
@@ -0,0 +1,55 @@
+// Copyright 2021 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.
+
+#ifndef COMPONENTS_ARC_COMMON_INTENT_HELPER_ARC_ICON_CACHE_DELEGATE_H_
+#define COMPONENTS_ARC_COMMON_INTENT_HELPER_ARC_ICON_CACHE_DELEGATE_H_
+
+#include <vector>
+
+#include "components/arc/common/intent_helper/activity_icon_loader.h"
+
+namespace arc {
+
+// This class stores activity icon cache for ARC and provides API to handle and
+// access to the cache.
+class ArcIconCacheDelegate {
+ public:
+ virtual ~ArcIconCacheDelegate();
+
+ // internal::ActivityIconLoader types.
+ using ActivityIconLoader = internal::ActivityIconLoader;
+ using ActivityName = internal::ActivityIconLoader::ActivityName;
+ using ActivityToIconsMap = internal::ActivityIconLoader::ActivityToIconsMap;
+ using GetResult = internal::ActivityIconLoader::GetResult;
+ using OnIconsReadyCallback =
+ internal::ActivityIconLoader::OnIconsReadyCallback;
+
+ // Return ArcIconCacheDelegate instance.
+ static ArcIconCacheDelegate* GetInstance();
+
+ // Retrieves icons for the |activities| and calls |callback|.
+ // See internal::ActivityIconLoader::GetActivityIcons() for more details.
+ virtual GetResult GetActivityIcons(
+ const std::vector<ActivityName>& activities,
+ OnIconsReadyCallback callback) = 0;
+};
+
+// Provides ArcIconCacheDelegate implementation.
+class ArcIconCacheDelegateProvider {
+ public:
+ explicit ArcIconCacheDelegateProvider(ArcIconCacheDelegate* delegate);
+ ArcIconCacheDelegateProvider(const ArcIconCacheDelegateProvider&) = delete;
+ ArcIconCacheDelegateProvider& operator=(const ArcIconCacheDelegateProvider&) =
+ delete;
+ ~ArcIconCacheDelegateProvider();
+
+ ArcIconCacheDelegate* GetInstance();
+
+ private:
+ ArcIconCacheDelegate* delegate_;
+};
+
+} // namespace arc
+
+#endif // COMPONENTS_ARC_COMMON_INTENT_HELPER_ARC_ICON_CACHE_DELEGATE_H_
diff --git a/chromium/components/arc/common/intent_helper/arc_intent_helper_mojo_delegate.cc b/chromium/components/arc/common/intent_helper/arc_intent_helper_mojo_delegate.cc
new file mode 100644
index 00000000000..54af1c3c35d
--- /dev/null
+++ b/chromium/components/arc/common/intent_helper/arc_intent_helper_mojo_delegate.cc
@@ -0,0 +1,63 @@
+// Copyright 2021 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.
+
+#include "components/arc/common/intent_helper/arc_intent_helper_mojo_delegate.h"
+
+namespace arc {
+
+ArcIntentHelperMojoDelegate::IntentInfo::IntentInfo(
+ std::string action,
+ absl::optional<std::vector<std::string>> categories,
+ absl::optional<std::string> data,
+ absl::optional<std::string> type,
+ bool ui_bypassed,
+ absl::optional<base::flat_map<std::string, std::string>> extras)
+ : action(std::move(action)),
+ categories(std::move(categories)),
+ data(std::move(data)),
+ type(std::move(type)),
+ ui_bypassed(ui_bypassed),
+ extras(std::move(extras)) {}
+
+ArcIntentHelperMojoDelegate::IntentInfo::IntentInfo(const IntentInfo& other) =
+ default;
+
+ArcIntentHelperMojoDelegate::IntentInfo::~IntentInfo() = default;
+
+ArcIntentHelperMojoDelegate::TextSelectionAction::TextSelectionAction(
+ std::string app_id,
+ gfx::ImageSkia icon,
+ ActivityName activity,
+ std::string title,
+ IntentInfo action_intent)
+ : app_id(std::move(app_id)),
+ icon(std::move(icon)),
+ activity(std::move(activity)),
+ title(std::move(title)),
+ action_intent(std::move(action_intent)) {}
+
+ArcIntentHelperMojoDelegate::TextSelectionAction::TextSelectionAction(
+ const TextSelectionAction& other) = default;
+
+ArcIntentHelperMojoDelegate::TextSelectionAction::~TextSelectionAction() =
+ default;
+
+ArcIntentHelperMojoDelegate::IntentHandlerInfo::IntentHandlerInfo(
+ std::string name,
+ std::string package_name,
+ std::string activity_name,
+ bool is_preferred,
+ absl::optional<std::string> fallback_url)
+ : name(std::move(name)),
+ package_name(std::move(package_name)),
+ activity_name(std::move(activity_name)),
+ is_preferred(is_preferred),
+ fallback_url(std::move(fallback_url)) {}
+
+ArcIntentHelperMojoDelegate::IntentHandlerInfo::IntentHandlerInfo(
+ const IntentHandlerInfo& other) = default;
+
+ArcIntentHelperMojoDelegate::IntentHandlerInfo::~IntentHandlerInfo() = default;
+
+} // namespace arc
diff --git a/chromium/components/arc/common/intent_helper/arc_intent_helper_mojo_delegate.h b/chromium/components/arc/common/intent_helper/arc_intent_helper_mojo_delegate.h
new file mode 100644
index 00000000000..92f439f7fb5
--- /dev/null
+++ b/chromium/components/arc/common/intent_helper/arc_intent_helper_mojo_delegate.h
@@ -0,0 +1,150 @@
+// Copyright 2021 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.
+
+#ifndef COMPONENTS_ARC_COMMON_INTENT_HELPER_ARC_INTENT_HELPER_MOJO_DELEGATE_H_
+#define COMPONENTS_ARC_COMMON_INTENT_HELPER_ARC_INTENT_HELPER_MOJO_DELEGATE_H_
+
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/containers/flat_map.h"
+#include "components/arc/common/intent_helper/activity_icon_loader.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "ui/base/resource/resource_scale_factor.h"
+#include "ui/gfx/image/image_skia.h"
+
+namespace arc {
+
+// This class provides API to use mojo connection.
+// For ash-chrome, it connects to ARC. For lacros-chrome, it connects to
+// ash-chrome which forwards to ARC.
+class ArcIntentHelperMojoDelegate {
+ public:
+ virtual ~ArcIntentHelperMojoDelegate() = default;
+
+ // To make ActivityName type consistent between ArcIconCacheDelegate, use
+ // internal::ActivityIconLoader::ActivityName.
+ using ActivityName = internal::ActivityIconLoader::ActivityName;
+
+ // Following structs basically refer to //ash/components/arc/mojom.
+ // Convert arc::mojom and crosapi::mojom into common structs available from
+ // both ash and lacros.
+ // Some unnecessary parameters are dropped here.
+
+ // Describes an intent.
+ // See //ash/components/arc/mojom/intent_helper.mojom for more details.
+ struct IntentInfo {
+ IntentInfo(std::string action,
+ absl::optional<std::vector<std::string>> categories,
+ absl::optional<std::string> data,
+ absl::optional<std::string> type,
+ bool ui_bypassed,
+ absl::optional<base::flat_map<std::string, std::string>> extras);
+ IntentInfo(const IntentInfo& other);
+ IntentInfo& operator=(const IntentInfo&) = delete;
+ ~IntentInfo();
+
+ std::string action;
+ absl::optional<std::vector<std::string>> categories;
+ absl::optional<std::string> data;
+ absl::optional<std::string> type;
+ bool ui_bypassed;
+ absl::optional<base::flat_map<std::string, std::string>> extras;
+ };
+
+ // Describes an action given by the android text selection delegate (e.g. open
+ // maps).
+ // See //ash/components/arc/mojom/intent_helper.mojom for more details.
+ struct TextSelectionAction {
+ TextSelectionAction(std::string app_id,
+ gfx::ImageSkia icon,
+ ActivityName activity,
+ std::string title,
+ IntentInfo action_intent);
+ TextSelectionAction(const TextSelectionAction& other);
+ TextSelectionAction& operator=(const TextSelectionAction&) = delete;
+ ~TextSelectionAction();
+
+ // App ID of the package.
+ // Note that this parameter is not set in arc::mojom::TextSelectionAction,
+ // but required in this struct.
+ std::string app_id;
+
+ // ImageSkia icon of the package.
+ // Note that this parameter is not set in arc::mojom::TextSelectionAction,
+ // but required in this struct.
+ gfx::ImageSkia icon;
+
+ ActivityName activity;
+ std::string title;
+ IntentInfo action_intent;
+ };
+
+ // Describes a package that can handle an intent.
+ // See //ash/components/arc/mojom/intent_helper.mojom for more details.
+ struct IntentHandlerInfo {
+ IntentHandlerInfo(std::string name,
+ std::string package_name,
+ std::string activity_name,
+ bool is_preferred,
+ absl::optional<std::string> fallback_url);
+ IntentHandlerInfo(const IntentHandlerInfo& other);
+ IntentHandlerInfo& operator=(const IntentHandlerInfo&) = delete;
+ ~IntentHandlerInfo();
+
+ // The name of the package used as a description text.
+ std::string name;
+ // The name of the package used as an ID.
+ std::string package_name;
+ // A hint for retrieving the package's icon.
+ std::string activity_name;
+ // Set to true if the package is set as a preferred package.
+ bool is_preferred;
+ // RequestUrlHandlerList may fill |fallback_url| when it is called with an
+ // intent: URL.
+ absl::optional<std::string> fallback_url;
+ };
+
+ using RequestUrlHandlerListCallback =
+ base::OnceCallback<void(std::vector<IntentHandlerInfo>)>;
+
+ using RequestTextSelectionActionsCallback =
+ base::OnceCallback<void(std::vector<TextSelectionAction>)>;
+
+ // Returns true if ARC is available.
+ virtual bool IsArcAvailable() = 0;
+
+ // Returns true if RequestUrlHandlerList is available.
+ virtual bool IsRequestUrlHandlerListAvailable() = 0;
+
+ // Returns true if RequestTextSelectionActions is available.
+ virtual bool IsRequestTextSelectionActionsAvailable() = 0;
+
+ // Calls RequestUrlHandlerList mojo API.
+ virtual bool RequestUrlHandlerList(
+ const std::string& url,
+ RequestUrlHandlerListCallback callback) = 0;
+
+ // Calls RequestTextSelectionActions mojo API.
+ virtual bool RequestTextSelectionActions(
+ const std::string& text,
+ ui::ResourceScaleFactor scale_factor,
+ RequestTextSelectionActionsCallback callback) = 0;
+
+ // Calls HandleUrl mojo API.
+ virtual bool HandleUrl(const std::string& url,
+ const std::string& package_name) = 0;
+
+ // Calls HandleIntent mojo API.
+ virtual bool HandleIntent(const IntentInfo& intent,
+ const ActivityName& activity) = 0;
+
+ // Calls AddPreferredPackage mojo API.
+ virtual bool AddPreferredPackage(const std::string& package_name) = 0;
+};
+
+} // namespace arc
+
+#endif // COMPONENTS_ARC_COMMON_INTENT_HELPER_ARC_INTENT_HELPER_MOJO_DELEGATE_H_
diff --git a/chromium/components/arc/common/intent_helper/arc_intent_helper_package.h b/chromium/components/arc/common/intent_helper/arc_intent_helper_package.h
new file mode 100644
index 00000000000..23488b6e03e
--- /dev/null
+++ b/chromium/components/arc/common/intent_helper/arc_intent_helper_package.h
@@ -0,0 +1,18 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_ARC_COMMON_INTENT_HELPER_ARC_INTENT_HELPER_PACKAGE_H_
+#define COMPONENTS_ARC_COMMON_INTENT_HELPER_ARC_INTENT_HELPER_PACKAGE_H_
+
+namespace arc {
+
+// The name of intent helper package which is used by ARC to send URLs to
+// Chrome.
+// This package does not count as a candidate to open ARC apps, so it should be
+// removed from candidate list such as context menu.
+constexpr char kArcIntentHelperPackageName[] = "org.chromium.arc.intent_helper";
+
+} // namespace arc
+
+#endif // COMPONENTS_ARC_COMMON_INTENT_HELPER_ARC_INTENT_HELPER_PACKAGE_H_
diff --git a/chromium/components/arc/intent_helper/link_handler_model.cc b/chromium/components/arc/common/intent_helper/link_handler_model.cc
index 971badd661e..0b4f03f4e5b 100644
--- a/chromium/components/arc/intent_helper/link_handler_model.cc
+++ b/chromium/components/arc/common/intent_helper/link_handler_model.cc
@@ -2,22 +2,25 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/arc/intent_helper/link_handler_model.h"
+#include "components/arc/common/intent_helper/link_handler_model.h"
#include <utility>
-#include "ash/components/arc/metrics/arc_metrics_constants.h"
-#include "ash/components/arc/metrics/arc_metrics_service.h"
-#include "ash/components/arc/session/arc_bridge_service.h"
-#include "ash/components/arc/session/arc_service_manager.h"
#include "base/bind.h"
#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
+#include "base/notreached.h"
#include "base/strings/utf_string_conversions.h"
-#include "components/arc/intent_helper/arc_intent_helper_bridge.h"
+#include "build/chromeos_buildflags.h"
+#include "components/arc/common/intent_helper/arc_intent_helper_package.h"
#include "components/google/core/common/google_util.h"
#include "url/url_util.h"
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "ash/components/arc/metrics/arc_metrics_constants.h"
+#include "ash/components/arc/metrics/arc_metrics_service.h"
+#endif
+
namespace arc {
namespace {
@@ -55,8 +58,10 @@ bool GetQueryValue(const GURL& url,
// static
std::unique_ptr<LinkHandlerModel> LinkHandlerModel::Create(
content::BrowserContext* context,
- const GURL& link_url) {
- auto impl = base::WrapUnique(new LinkHandlerModel());
+ const GURL& link_url,
+ std::unique_ptr<ArcIntentHelperMojoDelegate> mojo_delegate) {
+ CHECK(mojo_delegate);
+ auto impl = base::WrapUnique(new LinkHandlerModel(std::move(mojo_delegate)));
if (!impl->Init(context, link_url))
return nullptr;
return impl;
@@ -69,33 +74,26 @@ void LinkHandlerModel::AddObserver(Observer* observer) {
}
void LinkHandlerModel::OpenLinkWithHandler(uint32_t handler_id) {
- auto* arc_service_manager = ArcServiceManager::Get();
- if (!arc_service_manager)
- return;
- auto* instance = ARC_GET_INSTANCE_FOR_METHOD(
- arc_service_manager->arc_bridge_service()->intent_helper(), HandleUrl);
- if (!instance)
- return;
if (handler_id >= handlers_.size())
return;
- instance->HandleUrl(url_.spec(), handlers_[handler_id]->package_name);
+ if (!mojo_delegate_->HandleUrl(url_.spec(),
+ handlers_[handler_id].package_name)) {
+ return;
+ }
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+ // TODO(crbug.com/1275075): Take metrics in Lacros as well.
ArcMetricsService::RecordArcUserInteraction(
context_, arc::UserInteractionType::APP_STARTED_FROM_LINK_CONTEXT_MENU);
+#endif
}
-LinkHandlerModel::LinkHandlerModel() = default;
+LinkHandlerModel::LinkHandlerModel(
+ std::unique_ptr<ArcIntentHelperMojoDelegate> mojo_delegate)
+ : mojo_delegate_(std::move(mojo_delegate)) {}
bool LinkHandlerModel::Init(content::BrowserContext* context, const GURL& url) {
- auto* arc_service_manager = ArcServiceManager::Get();
- if (!arc_service_manager)
- return false;
- auto* instance = ARC_GET_INSTANCE_FOR_METHOD(
- arc_service_manager->arc_bridge_service()->intent_helper(),
- RequestUrlHandlerList);
- if (!instance)
- return false;
-
DCHECK(context);
context_ = context;
@@ -104,32 +102,44 @@ bool LinkHandlerModel::Init(content::BrowserContext* context, const GURL& url) {
// callback function, OnUrlHandlerList, is called within a few milliseconds
// even on the slowest Chromebook we support.
url_ = RewriteUrlFromQueryIfAvailable(url);
- instance->RequestUrlHandlerList(
+
+ return mojo_delegate_->RequestUrlHandlerList(
url_.spec(), base::BindOnce(&LinkHandlerModel::OnUrlHandlerList,
weak_ptr_factory_.GetWeakPtr()));
- return true;
}
void LinkHandlerModel::OnUrlHandlerList(
- std::vector<mojom::IntentHandlerInfoPtr> handlers) {
- handlers_ = ArcIntentHelperBridge::FilterOutIntentHelper(std::move(handlers));
+ std::vector<ArcIntentHelperMojoDelegate::IntentHandlerInfo> handlers) {
+ for (auto& handler : handlers) {
+ if (handler.package_name == kArcIntentHelperPackageName)
+ continue;
+ handlers_.push_back(std::move(handler));
+ }
bool icon_info_notified = false;
- auto* intent_helper_bridge =
- ArcIntentHelperBridge::GetForBrowserContext(context_);
- if (intent_helper_bridge) {
- std::vector<ArcIntentHelperBridge::ActivityName> activities;
- for (size_t i = 0; i < handlers_.size(); ++i) {
- activities.emplace_back(handlers_[i]->package_name,
- handlers_[i]->activity_name);
- }
- const ArcIntentHelperBridge::GetResult result =
- intent_helper_bridge->GetActivityIcons(
- activities, base::BindOnce(&LinkHandlerModel::NotifyObserver,
- weak_ptr_factory_.GetWeakPtr()));
- icon_info_notified =
- internal::ActivityIconLoader::HasIconsReadyCallbackRun(result);
+ if (!ArcIconCacheDelegate::GetInstance()) {
+ // ArcIconCacheDelegate instance should be already set on the product.
+ // It is not set for some tests such as browser_tests since crosapi is
+ // disabled. In this case, ignore the step to get icons and immediately
+ // notify observers with no result.
+ LOG(ERROR) << "ArcIconCacheDelegate is not set. "
+ << "This should not happen except for testing.";
+ NotifyObserver(nullptr);
+ return;
+ }
+
+ std::vector<ArcIconCacheDelegate::ActivityName> activities;
+ for (size_t i = 0; i < handlers_.size(); ++i) {
+ activities.emplace_back(handlers_[i].package_name,
+ handlers_[i].activity_name);
}
+ const ArcIconCacheDelegate::GetResult result =
+ ArcIconCacheDelegate::GetInstance()->GetActivityIcons(
+ activities, base::BindOnce(&LinkHandlerModel::NotifyObserver,
+ weak_ptr_factory_.GetWeakPtr()));
+ icon_info_notified =
+ ArcIconCacheDelegate::ActivityIconLoader::HasIconsReadyCallbackRun(
+ result);
if (!icon_info_notified) {
// Call NotifyObserver() without icon information, unless
@@ -140,7 +150,7 @@ void LinkHandlerModel::OnUrlHandlerList(
}
void LinkHandlerModel::NotifyObserver(
- std::unique_ptr<ArcIntentHelperBridge::ActivityToIconsMap> icons) {
+ std::unique_ptr<ArcIconCacheDelegate::ActivityToIconsMap> icons) {
if (icons) {
icons_.insert(icons->begin(), icons->end());
icons.reset();
@@ -149,13 +159,13 @@ void LinkHandlerModel::NotifyObserver(
std::vector<LinkHandlerInfo> handlers;
for (size_t i = 0; i < handlers_.size(); ++i) {
gfx::Image icon;
- const ArcIntentHelperBridge::ActivityName activity(
- handlers_[i]->package_name, handlers_[i]->activity_name);
+ const ArcIconCacheDelegate::ActivityName activity(
+ handlers_[i].package_name, handlers_[i].activity_name);
const auto it = icons_.find(activity);
if (it != icons_.end())
icon = it->second.icon16;
// Use the handler's index as an ID.
- LinkHandlerInfo handler = {base::UTF8ToUTF16(handlers_[i]->name), icon,
+ LinkHandlerInfo handler = {base::UTF8ToUTF16(handlers_[i].name), icon,
static_cast<uint32_t>(i)};
handlers.push_back(handler);
}
diff --git a/chromium/components/arc/intent_helper/link_handler_model.h b/chromium/components/arc/common/intent_helper/link_handler_model.h
index 7d63af27f01..b73fd39d701 100644
--- a/chromium/components/arc/intent_helper/link_handler_model.h
+++ b/chromium/components/arc/common/intent_helper/link_handler_model.h
@@ -2,17 +2,17 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef COMPONENTS_ARC_INTENT_HELPER_LINK_HANDLER_MODEL_H_
-#define COMPONENTS_ARC_INTENT_HELPER_LINK_HANDLER_MODEL_H_
+#ifndef COMPONENTS_ARC_COMMON_INTENT_HELPER_LINK_HANDLER_MODEL_H_
+#define COMPONENTS_ARC_COMMON_INTENT_HELPER_LINK_HANDLER_MODEL_H_
#include <memory>
#include <string>
#include <vector>
-#include "ash/components/arc/mojom/intent_helper.mojom.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
-#include "components/arc/intent_helper/arc_intent_helper_bridge.h"
+#include "components/arc/common/intent_helper/arc_icon_cache_delegate.h"
+#include "components/arc/common/intent_helper/arc_intent_helper_mojo_delegate.h"
#include "url/gurl.h"
namespace content {
@@ -40,7 +40,8 @@ class LinkHandlerModel {
// Creates and inits a model. Will return null if Init() fails.
static std::unique_ptr<LinkHandlerModel> Create(
content::BrowserContext* context,
- const GURL& link_url);
+ const GURL& link_url,
+ std::unique_ptr<ArcIntentHelperMojoDelegate> mojo_delegate);
LinkHandlerModel(const LinkHandlerModel&) = delete;
LinkHandlerModel& operator=(const LinkHandlerModel&) = delete;
@@ -53,16 +54,18 @@ class LinkHandlerModel {
static GURL RewriteUrlFromQueryIfAvailableForTesting(const GURL& url);
private:
- LinkHandlerModel();
+ explicit LinkHandlerModel(
+ std::unique_ptr<ArcIntentHelperMojoDelegate> mojo_delegate);
// Starts retrieving handler information for the |url| and returns true.
// Returns false when the information cannot be retrieved. In that case,
// the caller should delete |this| object.
bool Init(content::BrowserContext* context, const GURL& url);
- void OnUrlHandlerList(std::vector<mojom::IntentHandlerInfoPtr> handlers);
+ void OnUrlHandlerList(
+ std::vector<ArcIntentHelperMojoDelegate::IntentHandlerInfo> handlers);
void NotifyObserver(
- std::unique_ptr<ArcIntentHelperBridge::ActivityToIconsMap> icons);
+ std::unique_ptr<ArcIconCacheDelegate::ActivityToIconsMap> icons);
// Checks if the |url| matches the following pattern:
// "http(s)://<valid_google_hostname>/url?...&url=<valid_url>&..."
@@ -77,13 +80,16 @@ class LinkHandlerModel {
base::ObserverList<Observer>::Unchecked observer_list_;
// Url handler info passed from ARC.
- std::vector<mojom::IntentHandlerInfoPtr> handlers_;
+ std::vector<ArcIntentHelperMojoDelegate::IntentHandlerInfo> handlers_;
// Activity icon info passed from ARC.
- ArcIntentHelperBridge::ActivityToIconsMap icons_;
+ ArcIconCacheDelegate::ActivityToIconsMap icons_;
+
+ // a delegate instance for calling mojo API.
+ std::unique_ptr<ArcIntentHelperMojoDelegate> mojo_delegate_;
base::WeakPtrFactory<LinkHandlerModel> weak_ptr_factory_{this};
};
} // namespace arc
-#endif // COMPONENTS_ARC_INTENT_HELPER_LINK_HANDLER_MODEL_H_
+#endif // COMPONENTS_ARC_COMMON_INTENT_HELPER_LINK_HANDLER_MODEL_H_
diff --git a/chromium/components/arc/intent_helper/link_handler_model_unittest.cc b/chromium/components/arc/common/intent_helper/link_handler_model_unittest.cc
index 56bb968ba55..1745dd96e17 100644
--- a/chromium/components/arc/intent_helper/link_handler_model_unittest.cc
+++ b/chromium/components/arc/common/intent_helper/link_handler_model_unittest.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/arc/intent_helper/link_handler_model.h"
+#include "components/arc/common/intent_helper/link_handler_model.h"
#include <string>
diff --git a/chromium/components/arc/intent_helper/arc_intent_helper_bridge.cc b/chromium/components/arc/intent_helper/arc_intent_helper_bridge.cc
index fa25fcb217b..3cb1d142880 100644
--- a/chromium/components/arc/intent_helper/arc_intent_helper_bridge.cc
+++ b/chromium/components/arc/intent_helper/arc_intent_helper_bridge.cc
@@ -20,6 +20,7 @@
#include "base/metrics/histogram_macros.h"
#include "base/strings/string_util.h"
#include "base/values.h"
+#include "components/arc/common/intent_helper/arc_intent_helper_package.h"
#include "components/arc/intent_helper/control_camera_app_delegate.h"
#include "components/arc/intent_helper/intent_constants.h"
#include "components/arc/intent_helper/open_url_delegate.h"
@@ -113,10 +114,6 @@ bool CanOpenWebAppForUrl(const GURL& url) {
} // namespace
// static
-const char ArcIntentHelperBridge::kArcIntentHelperPackageName[] =
- "org.chromium.arc.intent_helper";
-
-// static
ArcIntentHelperBridge* ArcIntentHelperBridge::GetForBrowserContext(
content::BrowserContext* context) {
return ArcIntentHelperBridgeFactory::GetForBrowserContext(context);
@@ -165,8 +162,11 @@ ArcIntentHelperBridge::ArcIntentHelperBridge(content::BrowserContext* context,
ArcIntentHelperBridge::~ArcIntentHelperBridge() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
arc_bridge_service_->intent_helper()->SetHost(nullptr);
+}
+
+void ArcIntentHelperBridge::Shutdown() {
for (auto& observer : observer_list_)
- observer.OnArcIntentHelperBridgeDestruction();
+ observer.OnArcIntentHelperBridgeShutdown();
}
void ArcIntentHelperBridge::OnIconInvalidated(const std::string& package_name) {
@@ -321,15 +321,6 @@ void ArcIntentHelperBridge::IsChromeAppEnabled(
std::move(callback).Run(false);
}
-void ArcIntentHelperBridge::OnPreferredAppsChangedDeprecated(
- std::vector<IntentFilter> added,
- std::vector<IntentFilter> deleted) {
- added_preferred_apps_ = std::move(added);
- deleted_preferred_apps_ = std::move(deleted);
- for (auto& observer : observer_list_)
- observer.OnPreferredAppsChanged();
-}
-
void ArcIntentHelperBridge::OnSupportedLinksChanged(
std::vector<arc::mojom::SupportedLinksPtr> added_packages,
std::vector<arc::mojom::SupportedLinksPtr> removed_packages,
@@ -376,27 +367,6 @@ ArcIntentHelperBridge::GetResult ArcIntentHelperBridge::GetActivityIcons(
return icon_loader_.GetActivityIcons(activities, std::move(callback));
}
-bool ArcIntentHelperBridge::ShouldChromeHandleUrl(const GURL& url) {
- if (!url.SchemeIsHTTPOrHTTPS()) {
- // Chrome will handle everything that is not http and https.
- return true;
- }
-
- for (auto& package_filters : intent_filters_) {
- // The intent helper package is used by ARC to send URLs to Chrome, so it
- // does not count as a candidate.
- if (IsIntentHelperPackage(package_filters.first))
- continue;
- for (auto& filter : package_filters.second) {
- if (filter.Match(url))
- return false;
- }
- }
-
- // Didn't find any matches for Android so let Chrome handle it.
- return true;
-}
-
void ArcIntentHelperBridge::SetAdaptiveIconDelegate(
AdaptiveIconDelegate* delegate) {
icon_loader_.SetAdaptiveIconDelegate(delegate);
@@ -464,18 +434,12 @@ void ArcIntentHelperBridge::SendNewCaptureBroadcast(bool is_video,
}
// static
-bool ArcIntentHelperBridge::IsIntentHelperPackage(
- const std::string& package_name) {
- return package_name == kArcIntentHelperPackageName;
-}
-
-// static
std::vector<mojom::IntentHandlerInfoPtr>
ArcIntentHelperBridge::FilterOutIntentHelper(
std::vector<mojom::IntentHandlerInfoPtr> handlers) {
std::vector<mojom::IntentHandlerInfoPtr> handlers_filtered;
for (auto& handler : handlers) {
- if (IsIntentHelperPackage(handler->package_name))
+ if (handler->package_name == kArcIntentHelperPackageName)
continue;
handlers_filtered.push_back(std::move(handler));
}
@@ -488,14 +452,4 @@ ArcIntentHelperBridge::GetIntentFilterForPackage(
return intent_filters_[package_name];
}
-const std::vector<IntentFilter>&
-ArcIntentHelperBridge::GetAddedPreferredApps() {
- return added_preferred_apps_;
-}
-
-const std::vector<IntentFilter>&
-ArcIntentHelperBridge::GetDeletedPreferredApps() {
- return deleted_preferred_apps_;
-}
-
} // namespace arc
diff --git a/chromium/components/arc/intent_helper/arc_intent_helper_bridge.h b/chromium/components/arc/intent_helper/arc_intent_helper_bridge.h
index 04bda767472..082412c293b 100644
--- a/chromium/components/arc/intent_helper/arc_intent_helper_bridge.h
+++ b/chromium/components/arc/intent_helper/arc_intent_helper_bridge.h
@@ -12,9 +12,10 @@
#include <vector>
#include "ash/components/arc/mojom/intent_helper.mojom.h"
+#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/threading/thread_checker.h"
-#include "components/arc/common/intent_helper/activity_icon_loader.h"
+#include "components/arc/common/intent_helper/arc_icon_cache_delegate.h"
#include "components/arc/intent_helper/arc_intent_helper_observer.h"
#include "components/keyed_service/core/keyed_service.h"
#include "url/gurl.h"
@@ -35,7 +36,8 @@ class OpenUrlDelegate;
// Receives intents from ARC.
class ArcIntentHelperBridge : public KeyedService,
- public mojom::IntentHelperHost {
+ public mojom::IntentHelperHost,
+ public ArcIconCacheDelegate {
public:
class Delegate {
public:
@@ -72,6 +74,9 @@ class ArcIntentHelperBridge : public KeyedService,
ArcIntentHelperBridge& operator=(const ArcIntentHelperBridge&) = delete;
~ArcIntentHelperBridge() override;
+ // KeyedService:
+ void Shutdown() override;
+
// mojom::IntentHelperHost
void OnIconInvalidated(const std::string& package_name) override;
void OnIntentFiltersUpdated(
@@ -99,9 +104,6 @@ class ArcIntentHelperBridge : public KeyedService,
void CloseCameraApp() override;
void IsChromeAppEnabled(arc::mojom::ChromeApp app,
IsChromeAppEnabledCallback callback) override;
- void OnPreferredAppsChangedDeprecated(
- std::vector<IntentFilter> added,
- std::vector<IntentFilter> deleted) override;
void OnSupportedLinksChanged(
std::vector<arc::mojom::SupportedLinksPtr> added_packages,
std::vector<arc::mojom::SupportedLinksPtr> removed_packages,
@@ -111,24 +113,9 @@ class ArcIntentHelperBridge : public KeyedService,
void OnOpenAppWithIntent(const GURL& start_url,
arc::mojom::LaunchIntentPtr intent) override;
- // Retrieves icons for the |activities| and calls |callback|.
- // See ActivityIconLoader::GetActivityIcons() for more details.
- using ActivityName = internal::ActivityIconLoader::ActivityName;
- // A part of OnIconsReadyCallback signature.
- using ActivityToIconsMap = internal::ActivityIconLoader::ActivityToIconsMap;
- using OnIconsReadyCallback =
- internal::ActivityIconLoader::OnIconsReadyCallback;
- using GetResult = internal::ActivityIconLoader::GetResult;
+ // ArcIconCacheDelegete:
GetResult GetActivityIcons(const std::vector<ActivityName>& activities,
- OnIconsReadyCallback callback);
-
- // Returns true when |url| can only be handled by Chrome. Otherwise, which is
- // when there might be one or more ARC apps that can handle |url|, returns
- // false. This function synchronously checks the |url| without making any IPC
- // to ARC side. Note that this function only supports http and https. If url's
- // scheme is neither http nor https, the function immediately returns true
- // without checking the filters.
- bool ShouldChromeHandleUrl(const GURL& url);
+ OnIconsReadyCallback callback) override;
void SetAdaptiveIconDelegate(AdaptiveIconDelegate* delegate);
@@ -144,30 +131,21 @@ class ArcIntentHelperBridge : public KeyedService,
void SendNewCaptureBroadcast(bool is_video, std::string file_path);
- // Returns false if |package_name| is for the intent_helper apk.
- static bool IsIntentHelperPackage(const std::string& package_name);
-
// Filters out handlers that belong to the intent_helper apk and returns
// a new array.
static std::vector<mojom::IntentHandlerInfoPtr> FilterOutIntentHelper(
std::vector<mojom::IntentHandlerInfoPtr> handlers);
- static const char kArcIntentHelperPackageName[];
-
const std::vector<IntentFilter>& GetIntentFilterForPackage(
const std::string& package_name);
- const std::vector<IntentFilter>& GetAddedPreferredApps();
-
- const std::vector<IntentFilter>& GetDeletedPreferredApps();
-
private:
THREAD_CHECKER(thread_checker_);
content::BrowserContext* const context_;
ArcBridgeService* const arc_bridge_service_; // Owned by ArcServiceManager.
- internal::ActivityIconLoader icon_loader_;
+ ActivityIconLoader icon_loader_;
// A map of each package name to the intent filters for that package.
// Used to determine if Chrome should handle a URL without handing off to
@@ -182,13 +160,9 @@ class ArcIntentHelperBridge : public KeyedService,
// Schemes that ARC is known to send via OnOpenUrl.
const std::set<std::string> allowed_arc_schemes_;
- // The preferred app added in ARC.
- std::vector<IntentFilter> added_preferred_apps_;
-
- // The preferred app deleted in ARC.
- std::vector<IntentFilter> deleted_preferred_apps_;
-
std::unique_ptr<Delegate> delegate_;
+
+ base::WeakPtrFactory<ArcIntentHelperBridge> weak_ptr_factory_{this};
};
} // namespace arc
diff --git a/chromium/components/arc/intent_helper/arc_intent_helper_bridge_unittest.cc b/chromium/components/arc/intent_helper/arc_intent_helper_bridge_unittest.cc
index f3911cbc0b5..9c03ff48d06 100644
--- a/chromium/components/arc/intent_helper/arc_intent_helper_bridge_unittest.cc
+++ b/chromium/components/arc/intent_helper/arc_intent_helper_bridge_unittest.cc
@@ -16,6 +16,7 @@
#include "base/files/file_path.h"
#include "base/memory/ptr_util.h"
#include "base/test/metrics/histogram_tester.h"
+#include "components/arc/common/intent_helper/arc_intent_helper_package.h"
#include "components/arc/intent_helper/intent_constants.h"
#include "components/arc/intent_helper/open_url_delegate.h"
#include "mojo/public/cpp/bindings/clone_traits.h"
@@ -25,23 +26,6 @@
namespace arc {
-namespace {
-
-constexpr char kPackageName[] = "default.package.name";
-
-IntentFilter GetIntentFilter(const std::string& host,
- const std::string& pkg_name) {
- std::vector<IntentFilter::AuthorityEntry> authorities;
- authorities.emplace_back(host, /*port=*/-1);
- return IntentFilter(pkg_name, /*actions=*/std::vector<std::string>(),
- std::move(authorities),
- std::vector<IntentFilter::PatternMatcher>(),
- /*schemes=*/std::vector<std::string>(),
- /*mime_types=*/std::vector<std::string>());
-}
-
-} // namespace
-
class ArcIntentHelperTest : public testing::Test {
protected:
ArcIntentHelperTest() = default;
@@ -106,19 +90,6 @@ class ArcIntentHelperTest : public testing::Test {
}
};
-// Tests if IsIntentHelperPackage works as expected. Probably too trivial
-// to test but just in case.
-TEST_F(ArcIntentHelperTest, TestIsIntentHelperPackage) {
- EXPECT_FALSE(ArcIntentHelperBridge::IsIntentHelperPackage(""));
- EXPECT_FALSE(ArcIntentHelperBridge::IsIntentHelperPackage(
- ArcIntentHelperBridge::kArcIntentHelperPackageName + std::string("a")));
- EXPECT_FALSE(ArcIntentHelperBridge::IsIntentHelperPackage(
- ArcIntentHelperBridge::kArcIntentHelperPackageName +
- std::string("/.ArcIntentHelperActivity")));
- EXPECT_TRUE(ArcIntentHelperBridge::IsIntentHelperPackage(
- ArcIntentHelperBridge::kArcIntentHelperPackageName));
-}
-
// Tests if FilterOutIntentHelper removes handlers as expected.
TEST_F(ArcIntentHelperTest, TestFilterOutIntentHelper) {
{
@@ -147,7 +118,7 @@ TEST_F(ArcIntentHelperTest, TestFilterOutIntentHelper) {
std::vector<mojom::IntentHandlerInfoPtr> orig;
orig.push_back(mojom::IntentHandlerInfo::New());
orig[0]->name = "0";
- orig[0]->package_name = ArcIntentHelperBridge::kArcIntentHelperPackageName;
+ orig[0]->package_name = kArcIntentHelperPackageName;
orig.push_back(mojom::IntentHandlerInfo::New());
orig[1]->name = "1";
orig[1]->package_name = "package_name1";
@@ -164,13 +135,13 @@ TEST_F(ArcIntentHelperTest, TestFilterOutIntentHelper) {
std::vector<mojom::IntentHandlerInfoPtr> orig;
orig.push_back(mojom::IntentHandlerInfo::New());
orig[0]->name = "0";
- orig[0]->package_name = ArcIntentHelperBridge::kArcIntentHelperPackageName;
+ orig[0]->package_name = kArcIntentHelperPackageName;
orig.push_back(mojom::IntentHandlerInfo::New());
orig[1]->name = "1";
orig[1]->package_name = "package_name1";
orig.push_back(mojom::IntentHandlerInfo::New());
orig[2]->name = "2";
- orig[2]->package_name = ArcIntentHelperBridge::kArcIntentHelperPackageName;
+ orig[2]->package_name = kArcIntentHelperPackageName;
// FilterOutIntentHelper should remove two elements.
std::vector<mojom::IntentHandlerInfoPtr> filtered =
@@ -184,10 +155,10 @@ TEST_F(ArcIntentHelperTest, TestFilterOutIntentHelper) {
std::vector<mojom::IntentHandlerInfoPtr> orig;
orig.push_back(mojom::IntentHandlerInfo::New());
orig[0]->name = "0";
- orig[0]->package_name = ArcIntentHelperBridge::kArcIntentHelperPackageName;
+ orig[0]->package_name = kArcIntentHelperPackageName;
orig.push_back(mojom::IntentHandlerInfo::New());
orig[1]->name = "1";
- orig[1]->package_name = ArcIntentHelperBridge::kArcIntentHelperPackageName;
+ orig[1]->package_name = kArcIntentHelperPackageName;
// FilterOutIntentHelper should remove all elements.
std::vector<mojom::IntentHandlerInfoPtr> filtered =
@@ -209,7 +180,6 @@ TEST_F(ArcIntentHelperTest, TestObserver) {
OnIntentFiltersUpdated,
(const absl::optional<std::string>& package_name),
(override));
- MOCK_METHOD(void, OnPreferredAppsChanged, (), (override));
MOCK_METHOD(
void,
OnArcSupportedLinksChanged,
@@ -251,13 +221,6 @@ TEST_F(ArcIntentHelperTest, TestObserver) {
}
{
- // Observer should be called when preferred apps change.
- EXPECT_CALL(observer, OnPreferredAppsChanged);
- instance_->OnPreferredAppsChangedDeprecated(/*added=*/{}, /*deleted=*/{});
- testing::Mock::VerifyAndClearExpectations(&observer);
- }
-
- {
// Observer should be called when supported links change.
EXPECT_CALL(observer, OnArcSupportedLinksChanged);
instance_->OnSupportedLinksChanged(
@@ -272,127 +235,12 @@ TEST_F(ArcIntentHelperTest, TestObserver) {
instance_->OnDownloadAdded(/*relative_path=*/"Download/foo/bar.pdf",
/*owner_package_name=*/"owner_package_name");
instance_->OnIntentFiltersUpdated(/*filters=*/{});
- instance_->OnPreferredAppsChangedDeprecated(/*added=*/{}, /*deleted=*/{});
instance_->OnSupportedLinksChanged(
/*added_packages=*/{},
/*removed_packages=*/{},
arc::mojom::SupportedLinkChangeSource::kArcSystem);
}
-// Tests that ShouldChromeHandleUrl returns true by default.
-TEST_F(ArcIntentHelperTest, TestDefault) {
- EXPECT_TRUE(instance_->ShouldChromeHandleUrl(GURL("http://www.google.com")));
- EXPECT_TRUE(instance_->ShouldChromeHandleUrl(GURL("https://www.google.com")));
- EXPECT_TRUE(instance_->ShouldChromeHandleUrl(GURL("file:///etc/password")));
- EXPECT_TRUE(instance_->ShouldChromeHandleUrl(GURL("chrome://help")));
- EXPECT_TRUE(instance_->ShouldChromeHandleUrl(GURL("about://chrome")));
-}
-
-// Tests that ShouldChromeHandleUrl returns false when there's a match.
-TEST_F(ArcIntentHelperTest, TestSingleFilter) {
- std::vector<IntentFilter> array;
- array.emplace_back(GetIntentFilter("www.google.com", kPackageName));
- instance_->OnIntentFiltersUpdated(std::move(array));
-
- EXPECT_FALSE(instance_->ShouldChromeHandleUrl(GURL("http://www.google.com")));
- EXPECT_FALSE(
- instance_->ShouldChromeHandleUrl(GURL("https://www.google.com")));
-
- EXPECT_TRUE(
- instance_->ShouldChromeHandleUrl(GURL("https://www.google.co.uk")));
-}
-
-// Tests the same with multiple filters.
-TEST_F(ArcIntentHelperTest, TestMultipleFilters) {
- std::vector<IntentFilter> array;
- array.emplace_back(GetIntentFilter("www.google.com", kPackageName));
- array.emplace_back(GetIntentFilter("www.google.co.uk", kPackageName));
- array.emplace_back(GetIntentFilter("dev.chromium.org", kPackageName));
- instance_->OnIntentFiltersUpdated(std::move(array));
-
- EXPECT_FALSE(instance_->ShouldChromeHandleUrl(GURL("http://www.google.com")));
- EXPECT_FALSE(
- instance_->ShouldChromeHandleUrl(GURL("https://www.google.com")));
- EXPECT_FALSE(
- instance_->ShouldChromeHandleUrl(GURL("http://www.google.co.uk")));
- EXPECT_FALSE(
- instance_->ShouldChromeHandleUrl(GURL("https://www.google.co.uk")));
- EXPECT_FALSE(
- instance_->ShouldChromeHandleUrl(GURL("http://dev.chromium.org")));
- EXPECT_FALSE(
- instance_->ShouldChromeHandleUrl(GURL("https://dev.chromium.org")));
-
- EXPECT_TRUE(instance_->ShouldChromeHandleUrl(GURL("http://www.android.com")));
-}
-
-// Tests that ShouldChromeHandleUrl returns true for non http(s) URLs.
-TEST_F(ArcIntentHelperTest, TestNonHttp) {
- std::vector<IntentFilter> array;
- array.emplace_back(GetIntentFilter("www.google.com", kPackageName));
- instance_->OnIntentFiltersUpdated(std::move(array));
-
- EXPECT_TRUE(
- instance_->ShouldChromeHandleUrl(GURL("chrome://www.google.com")));
- EXPECT_TRUE(
- instance_->ShouldChromeHandleUrl(GURL("custom://www.google.com")));
-}
-
-// Tests that ShouldChromeHandleUrl discards the previous filters when
-// UpdateIntentFilters is called with new ones.
-TEST_F(ArcIntentHelperTest, TestMultipleUpdate) {
- std::vector<IntentFilter> array;
- array.emplace_back(GetIntentFilter("www.google.com", kPackageName));
- array.emplace_back(GetIntentFilter("dev.chromium.org", kPackageName));
- instance_->OnIntentFiltersUpdated(std::move(array));
-
- std::vector<IntentFilter> array2;
- array2.emplace_back(GetIntentFilter("www.google.co.uk", kPackageName));
- array2.emplace_back(GetIntentFilter("dev.chromium.org", kPackageName));
- array2.emplace_back(GetIntentFilter("www.android.com", kPackageName));
- instance_->OnIntentFiltersUpdated(std::move(array2));
-
- EXPECT_TRUE(instance_->ShouldChromeHandleUrl(GURL("http://www.google.com")));
- EXPECT_TRUE(instance_->ShouldChromeHandleUrl(GURL("https://www.google.com")));
- EXPECT_FALSE(
- instance_->ShouldChromeHandleUrl(GURL("http://www.google.co.uk")));
- EXPECT_FALSE(
- instance_->ShouldChromeHandleUrl(GURL("https://www.google.co.uk")));
- EXPECT_FALSE(
- instance_->ShouldChromeHandleUrl(GURL("http://dev.chromium.org")));
- EXPECT_FALSE(
- instance_->ShouldChromeHandleUrl(GURL("https://dev.chromium.org")));
- EXPECT_FALSE(
- instance_->ShouldChromeHandleUrl(GURL("http://www.android.com")));
- EXPECT_FALSE(
- instance_->ShouldChromeHandleUrl(GURL("https://www.android.com")));
-}
-
-// Tests that intent helper app (on ARC) is not taken as an app candidate, other
-// suitable app candidates should still match if possible.
-TEST_F(ArcIntentHelperTest, TestIntentHelperAppIsNotAValidCandidate) {
- std::vector<IntentFilter> array;
- array.emplace_back(GetIntentFilter(
- "www.google.com", ArcIntentHelperBridge::kArcIntentHelperPackageName));
- array.emplace_back(GetIntentFilter(
- "www.android.com", ArcIntentHelperBridge::kArcIntentHelperPackageName));
- // Let the package name start with "z" to ensure the intent helper package
- // is not always the last package checked in the ShouldChromeHandleUrl
- // filter matching logic. This is to ensure this unit test tests the package
- // name checking logic properly.
- array.emplace_back(GetIntentFilter("dev.chromium.org", "z.package.name"));
- instance_->OnIntentFiltersUpdated(std::move(array));
-
- EXPECT_TRUE(instance_->ShouldChromeHandleUrl(GURL("http://www.google.com")));
- EXPECT_TRUE(instance_->ShouldChromeHandleUrl(GURL("https://www.google.com")));
- EXPECT_TRUE(instance_->ShouldChromeHandleUrl(GURL("http://www.android.com")));
- EXPECT_TRUE(
- instance_->ShouldChromeHandleUrl(GURL("https://www.android.com")));
- EXPECT_FALSE(
- instance_->ShouldChromeHandleUrl(GURL("http://dev.chromium.org")));
- EXPECT_FALSE(
- instance_->ShouldChromeHandleUrl(GURL("https://dev.chromium.org")));
-}
-
// Tests that OnOpenUrl opens the URL in Chrome browser.
TEST_F(ArcIntentHelperTest, TestOnOpenUrl) {
instance_->OnOpenUrl("http://google.com");
@@ -470,7 +318,7 @@ TEST_F(ArcIntentHelperTest, TestOnOpenAppWithIntent) {
// Tests that AppendStringToIntentHelperPackageName works.
TEST_F(ArcIntentHelperTest, TestAppendStringToIntentHelperPackageName) {
- std::string package_name = ArcIntentHelperBridge::kArcIntentHelperPackageName;
+ std::string package_name = kArcIntentHelperPackageName;
std::string fake_activity = "this_is_a_fake_activity";
EXPECT_EQ(ArcIntentHelperBridge::AppendStringToIntentHelperPackageName(
fake_activity),
diff --git a/chromium/components/arc/intent_helper/arc_intent_helper_observer.h b/chromium/components/arc/intent_helper/arc_intent_helper_observer.h
index 68ce1f4a159..59599cf268b 100644
--- a/chromium/components/arc/intent_helper/arc_intent_helper_observer.h
+++ b/chromium/components/arc/intent_helper/arc_intent_helper_observer.h
@@ -33,8 +33,6 @@ class ArcIntentHelperObserver {
// package whose filters were changed.
virtual void OnIntentFiltersUpdated(
const absl::optional<std::string>& package_name) {}
- // Called when the preferred apps changed in ARC.
- virtual void OnPreferredAppsChanged() {}
// Called when the supported links setting ("Open Supported Links" under
// "Open by default" in ARC Settings) is changed for one or more packages.
@@ -47,8 +45,8 @@ class ArcIntentHelperObserver {
virtual void OnIconInvalidated(const std::string& package_name) {}
- // Called when ArcIntentHelperBridge is destroyed.
- virtual void OnArcIntentHelperBridgeDestruction() {}
+ // Called when ArcIntentHelperBridge is shut down.
+ virtual void OnArcIntentHelperBridgeShutdown() {}
};
} // namespace arc
diff --git a/chromium/components/arc/intent_helper/intent_filter.cc b/chromium/components/arc/intent_helper/intent_filter.cc
index e12127ef9c1..de8712c285e 100644
--- a/chromium/components/arc/intent_helper/intent_filter.cc
+++ b/chromium/components/arc/intent_helper/intent_filter.cc
@@ -11,7 +11,6 @@
#include "base/compiler_specific.h"
#include "base/strings/string_util.h"
#include "components/arc/intent_helper/intent_constants.h"
-#include "components/services/app_service/public/cpp/intent_util.h"
#include "url/gurl.h"
namespace arc {
@@ -61,57 +60,6 @@ IntentFilter::~IntentFilter() = default;
IntentFilter& IntentFilter::operator=(IntentFilter&& other) = default;
-// Logically, this maps to IntentFilter#match, but this code only deals with
-// view intents for http/https URLs and so it really only implements the
-// #matchData part of the match code.
-bool IntentFilter::Match(const GURL& url) const {
- // Chrome-side code only receives view intents for http/https URLs, so this
- // match code really only implements the matchData part of the android
- // IntentFilter class.
- if (!url.SchemeIsHTTPOrHTTPS()) {
- return false;
- }
-
- // Don't return match for filters for sharing.
- if (std::any_of(actions_.begin(), actions_.end(),
- [](const std::string action) {
- return action == kIntentActionSend ||
- action == kIntentActionSendMultiple;
- })) {
- return false;
- }
-
- // Match the authority and the path. If there are no authorities for this
- // filter, we can treat this as a match, since we already know this filter
- // has a http(s) scheme and it doesn't corresponds to a MIME type.
- if (!authorities_.empty()) {
- return MatchDataAuthority(url) && (paths_.empty() || HasDataPath(url));
- }
-
- return true;
-}
-
-// Transcribed from android's IntentFilter#hasDataPath.
-bool IntentFilter::HasDataPath(const GURL& url) const {
- const std::string path = url.path();
- for (const PatternMatcher& pattern : paths_) {
- if (pattern.Match(path)) {
- return true;
- }
- }
- return false;
-}
-
-// Transcribed from android's IntentFilter#matchDataAuthority.
-bool IntentFilter::MatchDataAuthority(const GURL& url) const {
- for (const AuthorityEntry& authority : authorities_) {
- if (authority.Match(url)) {
- return true;
- }
- }
- return false;
-}
-
IntentFilter::AuthorityEntry::AuthorityEntry() = default;
IntentFilter::AuthorityEntry::AuthorityEntry(
IntentFilter::AuthorityEntry&& other) = default;
@@ -132,36 +80,6 @@ IntentFilter::AuthorityEntry::AuthorityEntry(const std::string& host, int port)
host_ = base::ToLowerASCII(host_);
}
-// Transcribed from android's IntentFilter.AuthorityEntry#match.
-bool IntentFilter::AuthorityEntry::Match(const GURL& url) const {
- if (!url.has_host()) {
- return false;
- }
-
- // Note: On android, intent filters with explicit port specifications only
- // match URLs with explict ports, even if the specified port is the default
- // port. Using GURL::EffectiveIntPort instead of GURL::IntPort means that
- // this code differs in behaviour (i.e. it just matches the effective port,
- // ignoring whether it was implicitly or explicitly specified).
- //
- // We do this because it provides an optimistic match - ensuring that the
- // disambiguation code doesn't miss URLs that might be handled by android
- // apps. This doesn't cause misrouted intents because this check is followed
- // up by a mojo call that actually verifies the list of packages that could
- // accept the given intent.
- if (port_ >= 0 && port_ != url.EffectiveIntPort()) {
- return false;
- }
-
- if (wild_) {
- return base::EndsWith(url.host_piece(), host_,
- base::CompareCase::INSENSITIVE_ASCII);
- }
- // TODO(kenobi): Not i18n-friendly. Figure out how to correctly deal with
- // IDNs.
- return host_ == base::ToLowerASCII(url.host_piece());
-}
-
IntentFilter::PatternMatcher::PatternMatcher() = default;
IntentFilter::PatternMatcher::PatternMatcher(
IntentFilter::PatternMatcher&& other) = default;
@@ -173,22 +91,4 @@ IntentFilter::PatternMatcher::PatternMatcher(const std::string& pattern,
IntentFilter::PatternMatcher& IntentFilter::PatternMatcher::operator=(
IntentFilter::PatternMatcher&& other) = default;
-// Transcribed from android's PatternMatcher#matchPattern.
-bool IntentFilter::PatternMatcher::Match(const std::string& str) const {
- if (str.empty()) {
- return false;
- }
- switch (match_type_) {
- case mojom::PatternType::PATTERN_LITERAL:
- return str == pattern_;
- case mojom::PatternType::PATTERN_PREFIX:
- return base::StartsWith(str, pattern_,
- base::CompareCase::INSENSITIVE_ASCII);
- case mojom::PatternType::PATTERN_SIMPLE_GLOB:
- return apps_util::MatchGlob(str, pattern_);
- }
-
- return false;
-}
-
} // namespace arc
diff --git a/chromium/components/arc/intent_helper/intent_filter.h b/chromium/components/arc/intent_helper/intent_filter.h
index e0544785656..6c1c13369fa 100644
--- a/chromium/components/arc/intent_helper/intent_filter.h
+++ b/chromium/components/arc/intent_helper/intent_filter.h
@@ -32,8 +32,6 @@ class IntentFilter {
AuthorityEntry& operator=(const AuthorityEntry&) = delete;
AuthorityEntry& operator=(AuthorityEntry&& other);
- bool Match(const GURL& url) const;
-
const std::string& host() const { return host_; }
int port() const { return port_; }
@@ -53,8 +51,6 @@ class IntentFilter {
PatternMatcher& operator=(const PatternMatcher&) = delete;
PatternMatcher& operator=(PatternMatcher&& other);
- bool Match(const std::string& match) const;
-
const std::string& pattern() const { return pattern_; }
mojom::PatternType match_type() const { return match_type_; }
@@ -98,9 +94,6 @@ class IntentFilter {
const std::vector<std::string>& mime_types() const { return mime_types_; }
private:
- bool MatchDataAuthority(const GURL& url) const;
- bool HasDataPath(const GURL& url) const;
-
std::string package_name_;
std::string activity_name_;
std::string activity_label_;
diff --git a/chromium/components/arc/intent_helper/intent_filter_unittest.cc b/chromium/components/arc/intent_helper/intent_filter_unittest.cc
deleted file mode 100644
index c39c1722cad..00000000000
--- a/chromium/components/arc/intent_helper/intent_filter_unittest.cc
+++ /dev/null
@@ -1,375 +0,0 @@
-// 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.
-
-#include <memory>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "ash/components/arc/mojom/intent_helper.mojom.h"
-#include "base/bind.h"
-#include "base/memory/ref_counted.h"
-#include "components/arc/intent_helper/intent_filter.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "url/gurl.h"
-
-namespace arc {
-
-namespace {
-
-constexpr char kPackageName[] = "default.package.name";
-
-class IntentFilterBuilder {
- public:
- IntentFilterBuilder() = default;
- IntentFilterBuilder(const IntentFilterBuilder&) = delete;
- IntentFilterBuilder& operator=(const IntentFilterBuilder&) = delete;
-
- IntentFilterBuilder& authority(const std::string& host) {
- return authority(host, -1);
- }
-
- IntentFilterBuilder& authority(const std::string& host, int port) {
- authorities_.emplace_back(host, port);
- return *this;
- }
-
- IntentFilterBuilder& path(const std::string& path,
- const mojom::PatternType& type) {
- paths_.emplace_back(path, type);
- return *this;
- }
-
- operator IntentFilter() {
- return IntentFilter(kPackageName,
- /*actions=*/std::vector<std::string>(),
- std::move(authorities_), std::move(paths_),
- /*schemes=*/std::vector<std::string>(),
- /*mime_types=*/std::vector<std::string>());
- }
-
- private:
- std::vector<IntentFilter::AuthorityEntry> authorities_;
- std::vector<IntentFilter::PatternMatcher> paths_;
-};
-
-} // namespace
-
-TEST(IntentFilterTest, TestAuthorityEntry_empty) {
- // Empty URL shouldn't match a filter with an authority.
- IntentFilter filter = IntentFilterBuilder().authority("authority1");
-
- EXPECT_FALSE(filter.Match(GURL()));
-
- // Empty URL shouldn't match a filter with an authority and port.
- IntentFilter filter_port_100 =
- IntentFilterBuilder().authority("authority1", 100);
-
- EXPECT_FALSE(filter_port_100.Match(GURL()));
-}
-
-TEST(IntentFilterTest, TestAuthorityEntry_simple) {
- // URL authority should match the filter authority.
- IntentFilter filter = IntentFilterBuilder().authority("authority1");
-
- EXPECT_FALSE(filter.Match(GURL("http://authority2")));
- EXPECT_FALSE(filter.Match(GURL("https://authority2")));
-
- EXPECT_TRUE(filter.Match(GURL("http://authority1")));
- EXPECT_TRUE(filter.Match(GURL("https://authority1")));
-}
-
-TEST(IntentFilterTest, TestNoAuthorityEntry_simple) {
- // An empty authority will act as a wildcard, so any http(s) URL will match.
- IntentFilter filter = IntentFilterBuilder();
-
- EXPECT_TRUE(filter.Match(GURL("http://validscheme1")));
- EXPECT_TRUE(filter.Match(GURL("http://validscheme1/path")));
- EXPECT_TRUE(filter.Match(GURL("https://validscheme2")));
- EXPECT_TRUE(filter.Match(GURL("https://validscheme2/path")));
-
- EXPECT_FALSE(filter.Match(GURL("ftp://wedontsupportallschemes")));
- EXPECT_FALSE(filter.Match(GURL("ftp://wedontsupportallschemes/path")));
-}
-
-TEST(IntentFilterTest, TestAuthorityEntry_no_port) {
- // A filter with no port should accept matching authority URLs with any port.
- IntentFilter filter_no_port = IntentFilterBuilder().authority("authority1");
-
- EXPECT_TRUE(filter_no_port.Match(GURL("http://authority1:0")));
- EXPECT_TRUE(filter_no_port.Match(GURL("https://authority1:0")));
- EXPECT_TRUE(filter_no_port.Match(GURL("http://authority1:22")));
- EXPECT_TRUE(filter_no_port.Match(GURL("https://authority1:22")));
- EXPECT_TRUE(filter_no_port.Match(GURL("http://authority1:1024")));
- EXPECT_TRUE(filter_no_port.Match(GURL("https://authority1:1024")));
- EXPECT_TRUE(filter_no_port.Match(GURL("http://authority1:65535")));
- EXPECT_TRUE(filter_no_port.Match(GURL("https://authority1:65535")));
-}
-
-TEST(IntentFilterTest, TestNoAuthorityEntry_no_port) {
- // A filter with no port and no authority is still considered a wildcard.
- IntentFilter filter = IntentFilterBuilder();
-
- EXPECT_TRUE(filter.Match(GURL("http://validscheme1:0")));
- EXPECT_TRUE(filter.Match(GURL("http://validscheme1:0/path")));
- EXPECT_TRUE(filter.Match(GURL("https://validscheme2:420")));
- EXPECT_TRUE(filter.Match(GURL("https://validscheme2:420/path")));
-
- EXPECT_FALSE(filter.Match(GURL("custom-scheme://unvalidscheme:0")));
- EXPECT_FALSE(filter.Match(GURL("custom-scheme://unvalidscheme:0/path")));
-}
-
-TEST(IntentFilterTest, TestAuthorityEntry_with_port) {
- // A filter with a specified port should only match URLs with that port.
- IntentFilter filter_port_100 =
- IntentFilterBuilder().authority("authority1", 100);
-
- EXPECT_FALSE(filter_port_100.Match(GURL("http://authority1")));
- EXPECT_FALSE(filter_port_100.Match(GURL("https://authority1")));
- EXPECT_FALSE(filter_port_100.Match(GURL("http://authority1:0")));
- EXPECT_FALSE(filter_port_100.Match(GURL("https://authority1:0")));
- EXPECT_FALSE(filter_port_100.Match(GURL("http://authority1:22")));
- EXPECT_FALSE(filter_port_100.Match(GURL("https://authority1:22")));
- EXPECT_FALSE(filter_port_100.Match(GURL("http://authority1:1024")));
- EXPECT_FALSE(filter_port_100.Match(GURL("https://authority1:1024")));
- EXPECT_FALSE(filter_port_100.Match(GURL("http://authority1:65535")));
- EXPECT_FALSE(filter_port_100.Match(GURL("https://authority1:65535")));
-
- EXPECT_TRUE(filter_port_100.Match(GURL("http://authority1:100")));
- EXPECT_TRUE(filter_port_100.Match(GURL("https://authority1:100")));
-}
-
-TEST(IntentFilterTest, TestAuthorityEntry_default_port) {
- // Intent filters with explicit default ports match URLs with or without
- // explicit ports. This diverges from android's intent filter behaviour. See
- // the IntentFilter::AuthorityEntry::match code for details.
- IntentFilter filter_default_port = IntentFilterBuilder()
- .authority("authority1", 80)
- .authority("authority1", 443);
-
- EXPECT_TRUE(filter_default_port.Match(GURL("http://authority1")));
- EXPECT_TRUE(filter_default_port.Match(GURL("https://authority1")));
- EXPECT_TRUE(filter_default_port.Match(GURL("http://authority1:80")));
- EXPECT_TRUE(filter_default_port.Match(GURL("https://authority1:443")));
-}
-
-TEST(IntentFilterTest, TestAuthorityEntry_multiple) {
- // A filter with multiple authorities should match URLs that match any of
- // those authorities.
- IntentFilter filter = IntentFilterBuilder()
- .authority("authority1", 100)
- .authority("authority2");
-
- EXPECT_FALSE(filter.Match(GURL("http://authority1")));
- EXPECT_FALSE(filter.Match(GURL("http://authority3")));
-
- EXPECT_TRUE(filter.Match(GURL("http://authority1:100")));
- EXPECT_TRUE(filter.Match(GURL("http://authority2")));
-}
-
-TEST(IntentFilterTest, TestAuthorityEntry_substring) {
- // Make sure substrings don't match in non-wildcard cases.
- IntentFilter filter = IntentFilterBuilder().authority("authority1");
-
- EXPECT_FALSE(filter.Match(GURL("http://authority")));
- EXPECT_FALSE(filter.Match(GURL("http://authority12")));
-}
-
-TEST(IntentFilterTest, TestAuthorityEntry_wild) {
- // Make sure wildcards work
- IntentFilter filter = IntentFilterBuilder().authority("*.authority1");
-
- EXPECT_FALSE(filter.Match(GURL("http://.authority")));
- EXPECT_FALSE(filter.Match(GURL("http://.authority12")));
-
- EXPECT_TRUE(filter.Match(GURL("http://.authority1")));
- EXPECT_TRUE(filter.Match(GURL("http://foo.authority1")));
- EXPECT_TRUE(filter.Match(GURL("http://bar.authority1")));
- EXPECT_TRUE(filter.Match(GURL("http://foo.bar.authority1")));
- EXPECT_TRUE(filter.Match(GURL("http://foo.authority1.authority1")));
-}
-
-TEST(IntentFilterTest, TestDataPath_literal) {
- IntentFilter filter =
- IntentFilterBuilder()
- .authority("host.com")
- .path("/path1", mojom::PatternType::PATTERN_LITERAL);
-
- // Empty paths, prefix-, and substring-matches should fail.
- EXPECT_FALSE(filter.Match(GURL()));
- EXPECT_FALSE(filter.Match(GURL("http://host.com")));
- EXPECT_FALSE(filter.Match(GURL("http://host.com/")));
- EXPECT_FALSE(filter.Match(GURL("http://host.com/path")));
- EXPECT_FALSE(filter.Match(GURL("http://host.com/path12")));
-
- EXPECT_TRUE(filter.Match(GURL("http://host.com/path1")));
-}
-
-TEST(IntentFilterTest, TestNoAuthorityDataPath_literal) {
- IntentFilter filter =
- IntentFilterBuilder().path("/path", mojom::PatternType::PATTERN_LITERAL);
-
- // A filter with no authority and a custom path must still match our URL.
- EXPECT_TRUE(filter.Match(GURL("http://validscheme1")));
- EXPECT_TRUE(filter.Match(GURL("http://validscheme1:0")));
- EXPECT_TRUE(filter.Match(GURL("http://validscheme1:0/path")));
- EXPECT_TRUE(filter.Match(GURL("http://validscheme1:10/other/path")));
-}
-
-TEST(IntentFilterTest, TestDataPath_prefix) {
- IntentFilter filter = IntentFilterBuilder()
- .authority("host.com")
- .path("/path1", mojom::PatternType::PATTERN_PREFIX);
-
- // Empty paths and substring-matches should fail.
- EXPECT_FALSE(filter.Match(GURL()));
- EXPECT_FALSE(filter.Match(GURL("http://host.com")));
- EXPECT_FALSE(filter.Match(GURL("http://host.com/")));
- EXPECT_FALSE(filter.Match(GURL("http://host.com/path")));
-
- EXPECT_TRUE(filter.Match(GURL("http://host.com/path1")));
- EXPECT_TRUE(filter.Match(GURL("http://host.com/path12")));
-}
-
-// Glob tests based loosely on android's CTS IntentFilterTest#testPaths.
-TEST(IntentFilterTest, TestDataPath_globSuffix) {
- IntentFilter filter =
- IntentFilterBuilder()
- .authority("host.com")
- .path("/path1.*", mojom::PatternType::PATTERN_SIMPLE_GLOB);
-
- // Empty paths and substring-matches should fail.
- EXPECT_FALSE(filter.Match(GURL()));
- EXPECT_FALSE(filter.Match(GURL("http://host.com")));
- EXPECT_FALSE(filter.Match(GURL("http://host.com/")));
- EXPECT_FALSE(filter.Match(GURL("http://host.com/path")));
-
- // Glob should match any substring including the empty susbstring.
- EXPECT_TRUE(filter.Match(GURL("http://host.com/path1")));
- EXPECT_TRUE(filter.Match(GURL("http://host.com/path11")));
- EXPECT_TRUE(filter.Match(GURL("http://host.com/path112345")));
- EXPECT_TRUE(filter.Match(GURL("http://host.com/path1.")));
- EXPECT_TRUE(filter.Match(GURL("http://host.com/path1.....")));
- EXPECT_TRUE(filter.Match(GURL("http://host.com/path1path")));
-}
-
-// Glob tests based loosely on android's CTS IntentFilterTest#testPaths.
-TEST(IntentFilterTest, TestDataPath_globInfix) {
- IntentFilter filter =
- IntentFilterBuilder()
- .authority("host.com")
- .path("/a.*b", mojom::PatternType::PATTERN_SIMPLE_GLOB);
-
- // Empty paths and substring-matches should fail.
- EXPECT_FALSE(filter.Match(GURL()));
- EXPECT_FALSE(filter.Match(GURL("http://host.com")));
- EXPECT_FALSE(filter.Match(GURL("http://host.com/")));
- EXPECT_FALSE(filter.Match(GURL("http://host.com/a")));
-
- // Extra junk on the end should fail.
- EXPECT_FALSE(filter.Match(GURL("http://host.com/abc")));
-
- // Glob should match any substring including the empty susbstring.
- EXPECT_TRUE(filter.Match(GURL("http://host.com/ab")));
- EXPECT_TRUE(filter.Match(GURL("http://host.com/a1b")));
- EXPECT_TRUE(filter.Match(GURL("http://host.com/a12345b")));
- EXPECT_TRUE(filter.Match(GURL("http://host.com/a.b")));
- EXPECT_TRUE(filter.Match(GURL("http://host.com/a.....b")));
- EXPECT_TRUE(filter.Match(GURL("http://host.com/aab")));
- EXPECT_TRUE(filter.Match(GURL("http://host.com/aaaaab")));
- EXPECT_TRUE(filter.Match(GURL("http://host.com/a/foo/b")));
-
- // TODO(kenobi): These cases don't work correctly. However, the chrome-side
- // intent filter matching code needs to replicate the results of the
- // android-side pattern matcher, otherwise chrome will attempt to send URLs to
- // android that won't successfully match with any installed app. See
- // b/30160040.
- // EXPECT_TRUE(filter.Match(GURL("http://host.com/abb")));
- // EXPECT_TRUE(filter.Match(GURL("http://host.com/abbbbb")));
-}
-
-// Glob tests based loosely on android's CTS IntentFilterTest#testPaths.
-TEST(IntentFilterTest, TestDataPath_globOnly) {
- IntentFilter filter =
- IntentFilterBuilder()
- .authority("host.com")
- .path("/.*", mojom::PatternType::PATTERN_SIMPLE_GLOB);
-
- // Empty URLs should fail.
- EXPECT_FALSE(filter.Match(GURL()));
-
- // Any path should match.
- EXPECT_TRUE(filter.Match(GURL("http://host.com")));
- EXPECT_TRUE(filter.Match(GURL("http://host.com/")));
- EXPECT_TRUE(filter.Match(GURL("http://host.com/a")));
- EXPECT_TRUE(filter.Match(GURL("http://host.com/aaa")));
- EXPECT_TRUE(filter.Match(GURL("http://host.com/aaa/bbb")));
- EXPECT_TRUE(filter.Match(GURL("http://host.com/.")));
-}
-
-// Glob tests based loosely on android's CTS IntentFilterTest#testPaths.
-TEST(IntentFilterTest, TestDataPath_globSingleChar) {
- IntentFilter filter =
- IntentFilterBuilder()
- .authority("host.com")
- .path("/a1*b", mojom::PatternType::PATTERN_SIMPLE_GLOB);
-
- EXPECT_FALSE(filter.Match(GURL()));
- EXPECT_FALSE(filter.Match(GURL("http://host.com")));
- EXPECT_FALSE(filter.Match(GURL("http://host.com/")));
- EXPECT_FALSE(filter.Match(GURL("http://host.com/a")));
- EXPECT_FALSE(filter.Match(GURL("http://host.com/a12b")));
- EXPECT_FALSE(filter.Match(GURL("http://host.com/ab12b")));
-
- EXPECT_TRUE(filter.Match(GURL("http://host.com/ab")));
- EXPECT_TRUE(filter.Match(GURL("http://host.com/a1b")));
- EXPECT_TRUE(filter.Match(GURL("http://host.com/a111b")));
-}
-
-// Glob tests based loosely on android's CTS IntentFilterTest#testPaths.
-TEST(IntentFilterTest, TestDataPath_globEscapedChar) {
- IntentFilter filter =
- IntentFilterBuilder()
- .authority("host.com")
- .path("/a\\.*b", mojom::PatternType::PATTERN_SIMPLE_GLOB);
-
- EXPECT_FALSE(filter.Match(GURL()));
- EXPECT_FALSE(filter.Match(GURL("http://host.com")));
- EXPECT_FALSE(filter.Match(GURL("http://host.com/")));
- EXPECT_FALSE(filter.Match(GURL("http://host.com/a")));
- EXPECT_FALSE(filter.Match(GURL("http://host.com/a1b")));
- EXPECT_FALSE(filter.Match(GURL("http://host.com/a111b")));
- EXPECT_FALSE(filter.Match(GURL("http://host.com/abc")));
- EXPECT_FALSE(filter.Match(GURL("http://host.com/a.bc")));
- EXPECT_FALSE(filter.Match(GURL("http://host.com/a...bc")));
-
- EXPECT_TRUE(filter.Match(GURL("http://host.com/ab")));
- EXPECT_TRUE(filter.Match(GURL("http://host.com/a.b")));
- EXPECT_TRUE(filter.Match(GURL("http://host.com/a...b")));
-}
-
-// Glob tests based loosely on android's CTS IntentFilterTest#testPaths.
-TEST(IntentFilterTest, TestDataPath_globEscapedStar) {
- IntentFilter filter =
- IntentFilterBuilder()
- .authority("host.com")
- .path("/a.\\*b", mojom::PatternType::PATTERN_SIMPLE_GLOB);
-
- EXPECT_FALSE(filter.Match(GURL()));
- EXPECT_FALSE(filter.Match(GURL("http://host.com")));
- EXPECT_FALSE(filter.Match(GURL("http://host.com/")));
- EXPECT_FALSE(filter.Match(GURL("http://host.com/a")));
- EXPECT_FALSE(filter.Match(GURL("http://host.com/ab")));
- EXPECT_FALSE(filter.Match(GURL("http://host.com/a.b")));
- EXPECT_FALSE(filter.Match(GURL("http://host.com/a*b")));
- EXPECT_FALSE(filter.Match(GURL("http://host.com/a1b")));
- EXPECT_FALSE(filter.Match(GURL("http://host.com/a.*bc")));
- EXPECT_FALSE(filter.Match(GURL("http://host.com/a1*bc")));
-
- EXPECT_TRUE(filter.Match(GURL("http://host.com/a.*b")));
- EXPECT_TRUE(filter.Match(GURL("http://host.com/a1*b")));
- EXPECT_TRUE(filter.Match(GURL("http://host.com/a2*b")));
-}
-
-} // namespace arc
diff --git a/chromium/components/assist_ranker/BUILD.gn b/chromium/components/assist_ranker/BUILD.gn
index dd11864c26a..e889121d075 100644
--- a/chromium/components/assist_ranker/BUILD.gn
+++ b/chromium/components/assist_ranker/BUILD.gn
@@ -15,8 +15,6 @@ static_library("assist_ranker") {
"classifier_predictor.h",
"example_preprocessing.cc",
"example_preprocessing.h",
- "fake_ranker_model_loader.cc",
- "fake_ranker_model_loader.h",
"generic_logistic_regression_inference.cc",
"generic_logistic_regression_inference.h",
"nn_classifier.cc",
@@ -59,6 +57,8 @@ source_set("unit_tests") {
"binary_classifier_predictor_unittest.cc",
"classifier_predictor_unittest.cc",
"example_preprocessing_unittest.cc",
+ "fake_ranker_model_loader.cc",
+ "fake_ranker_model_loader.h",
"generic_logistic_regression_inference_unittest.cc",
"nn_classifier_test_util.cc",
"nn_classifier_test_util.h",
diff --git a/chromium/components/assist_ranker/OWNERS b/chromium/components/assist_ranker/OWNERS
index c97b762115f..e6ccec7b356 100644
--- a/chromium/components/assist_ranker/OWNERS
+++ b/chromium/components/assist_ranker/OWNERS
@@ -1,4 +1,2 @@
charleszhao@chromium.org
-hamelphi@chromium.org
jiameng@chromium.org
-rogerm@chromium.org
diff --git a/chromium/components/assist_ranker/binary_classifier_predictor.h b/chromium/components/assist_ranker/binary_classifier_predictor.h
index 5d2e8ea39aa..ab91dc72ed8 100644
--- a/chromium/components/assist_ranker/binary_classifier_predictor.h
+++ b/chromium/components/assist_ranker/binary_classifier_predictor.h
@@ -5,7 +5,6 @@
#ifndef COMPONENTS_ASSIST_RANKER_BINARY_CLASSIFIER_PREDICTOR_H_
#define COMPONENTS_ASSIST_RANKER_BINARY_CLASSIFIER_PREDICTOR_H_
-#include "base/compiler_specific.h"
#include "components/assist_ranker/base_predictor.h"
#include "components/assist_ranker/proto/ranker_example.pb.h"
@@ -33,21 +32,19 @@ class BinaryClassifierPredictor : public BasePredictor {
// Returns an new predictor instance with the given |config| and initialize
// its model loader. The |request_context getter| is passed to the
// predictor's model_loader which holds it as scoped_refptr.
- static std::unique_ptr<BinaryClassifierPredictor> Create(
+ [[nodiscard]] static std::unique_ptr<BinaryClassifierPredictor> Create(
const PredictorConfig& config,
const base::FilePath& model_path,
- scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
- WARN_UNUSED_RESULT;
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory);
// Fills in a boolean decision given a RankerExample. Returns false if a
// prediction could not be made (e.g. the model is not loaded yet).
- bool Predict(const RankerExample& example,
- bool* prediction) WARN_UNUSED_RESULT;
+ [[nodiscard]] bool Predict(const RankerExample& example, bool* prediction);
// Returns a score between 0 and 1. Returns false if a
// prediction could not be made (e.g. the model is not loaded yet).
- bool PredictScore(const RankerExample& example,
- float* prediction) WARN_UNUSED_RESULT;
+ [[nodiscard]] bool PredictScore(const RankerExample& example,
+ float* prediction);
// Validates that the loaded RankerModel is a valid BinaryClassifier model.
static RankerModelStatus ValidateModel(const RankerModel& model);
diff --git a/chromium/components/assist_ranker/classifier_predictor.h b/chromium/components/assist_ranker/classifier_predictor.h
index 85aad1a568c..34c3ba1ba4b 100644
--- a/chromium/components/assist_ranker/classifier_predictor.h
+++ b/chromium/components/assist_ranker/classifier_predictor.h
@@ -8,7 +8,6 @@
#include <memory>
#include <vector>
-#include "base/compiler_specific.h"
#include "components/assist_ranker/base_predictor.h"
#include "components/assist_ranker/nn_classifier.h"
#include "components/assist_ranker/proto/ranker_example.pb.h"
@@ -34,22 +33,21 @@ class ClassifierPredictor : public BasePredictor {
// Returns an new predictor instance with the given |config| and initialize
// its model loader. The |request_context getter| is passed to the
// predictor's model_loader which holds it as scoped_refptr.
- static std::unique_ptr<ClassifierPredictor> Create(
+ [[nodiscard]] static std::unique_ptr<ClassifierPredictor> Create(
const PredictorConfig& config,
const base::FilePath& model_path,
- scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
- WARN_UNUSED_RESULT;
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory);
// Performs inferencing on the specified RankerExample. The example is first
// preprocessed using the model config. Returns false if a prediction could
// not be made (e.g. the model is not loaded yet).
- bool Predict(RankerExample example,
- std::vector<float>* prediction) WARN_UNUSED_RESULT;
+ [[nodiscard]] bool Predict(RankerExample example,
+ std::vector<float>* prediction);
// Performs inferencing on the specified feature vector. Returns false if
// a prediction could not be made.
- bool Predict(const std::vector<float>& features,
- std::vector<float>* prediction) WARN_UNUSED_RESULT;
+ [[nodiscard]] bool Predict(const std::vector<float>& features,
+ std::vector<float>* prediction);
// Validates that the loaded RankerModel is a valid BinaryClassifier model.
static RankerModelStatus ValidateModel(const RankerModel& model);
diff --git a/chromium/components/assist_ranker/predictor_config_definitions.cc b/chromium/components/assist_ranker/predictor_config_definitions.cc
index 3b8890dd843..0d2c38c79c4 100644
--- a/chromium/components/assist_ranker/predictor_config_definitions.cc
+++ b/chromium/components/assist_ranker/predictor_config_definitions.cc
@@ -5,11 +5,12 @@
#include "components/assist_ranker/predictor_config_definitions.h"
#include "base/metrics/field_trial_params.h"
+#include "build/build_config.h"
#include "components/assist_ranker/base_predictor.h"
namespace assist_ranker {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
const base::Feature kContextualSearchRankerQuery{
"ContextualSearchRankerQuery", base::FEATURE_DISABLED_BY_DEFAULT};
@@ -94,6 +95,6 @@ const PredictorConfig GetContextualSearchPredictorConfig() {
GetContextualSearchRankerThresholdFeatureParam()));
return kContextualSearchPredictorConfig;
}
-#endif // OS_ANDROID
+#endif // BUILDFLAG(IS_ANDROID)
} // namespace assist_ranker
diff --git a/chromium/components/assist_ranker/predictor_config_definitions.h b/chromium/components/assist_ranker/predictor_config_definitions.h
index 34ae1c414df..b020fb016bb 100644
--- a/chromium/components/assist_ranker/predictor_config_definitions.h
+++ b/chromium/components/assist_ranker/predictor_config_definitions.h
@@ -12,10 +12,10 @@
namespace assist_ranker {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
extern const base::Feature kContextualSearchRankerQuery;
const PredictorConfig GetContextualSearchPredictorConfig();
-#endif // OS_ANDROID
+#endif // BUILDFLAG(IS_ANDROID)
} // namespace assist_ranker
diff --git a/chromium/components/assist_ranker/ranker_example_util.h b/chromium/components/assist_ranker/ranker_example_util.h
index c75bb393522..05243002b16 100644
--- a/chromium/components/assist_ranker/ranker_example_util.h
+++ b/chromium/components/assist_ranker/ranker_example_util.h
@@ -5,7 +5,6 @@
#ifndef COMPONENTS_ASSIST_RANKER_RANKER_EXAMPLE_UTIL_H_
#define COMPONENTS_ASSIST_RANKER_RANKER_EXAMPLE_UTIL_H_
-#include "base/compiler_specific.h"
#include "components/assist_ranker/proto/ranker_example.pb.h"
namespace assist_ranker {
@@ -14,16 +13,16 @@ namespace assist_ranker {
// Returns false if the feature is not found. |feature| can be nullptr. In such
// a case, the return value is not changed, but |feature| will not be filled in.
// This can be used to check for the presence of a key.
-bool SafeGetFeature(const std::string& key,
- const RankerExample& example,
- Feature* feature) WARN_UNUSED_RESULT;
+[[nodiscard]] bool SafeGetFeature(const std::string& key,
+ const RankerExample& example,
+ Feature* feature);
// Extract value from |feature| for scalar feature types. Returns true and fills
// in |value| if the feature is found and has a float, int32 or bool value.
// Returns false otherwise.
-bool GetFeatureValueAsFloat(const std::string& key,
- const RankerExample& example,
- float* value) WARN_UNUSED_RESULT;
+[[nodiscard]] bool GetFeatureValueAsFloat(const std::string& key,
+ const RankerExample& example,
+ float* value);
// Converts a Ranker Feature to an int64. For feature list, this converts the
// index-th value of the list.
@@ -42,9 +41,9 @@ bool FeatureToInt64(const Feature& feature, int64_t* res, int index = 0);
// Extract category from one-hot feature. Returns true and fills
// in |value| if the feature is found and is of type string_value. Returns false
// otherwise.
-bool GetOneHotValue(const std::string& key,
- const RankerExample& example,
- std::string* value) WARN_UNUSED_RESULT;
+[[nodiscard]] bool GetOneHotValue(const std::string& key,
+ const RankerExample& example,
+ std::string* value);
// Converts a string to a hex ahsh string.
std::string HashFeatureName(const std::string& feature_name);
diff --git a/chromium/components/assist_ranker/ranker_model_loader_impl.cc b/chromium/components/assist_ranker/ranker_model_loader_impl.cc
index 6a973712e5b..65199d9ccf8 100644
--- a/chromium/components/assist_ranker/ranker_model_loader_impl.cc
+++ b/chromium/components/assist_ranker/ranker_model_loader_impl.cc
@@ -121,7 +121,7 @@ void RankerModelLoaderImpl::NotifyOfRankerActivity() {
// There was no configured model path. Switch the state to IDLE and
// fall through to consider the URL.
state_ = LoaderState::IDLE;
- FALLTHROUGH;
+ [[fallthrough]];
case LoaderState::IDLE:
if (model_url_.is_valid()) {
StartLoadFromURL();
@@ -130,7 +130,7 @@ void RankerModelLoaderImpl::NotifyOfRankerActivity() {
// There was no configured model URL. Switch the state to FINISHED and
// fall through.
state_ = LoaderState::FINISHED;
- FALLTHROUGH;
+ [[fallthrough]];
case LoaderState::FINISHED:
case LoaderState::LOADING_FROM_FILE:
case LoaderState::LOADING_FROM_URL:
diff --git a/chromium/components/autofill/android/BUILD.gn b/chromium/components/autofill/android/BUILD.gn
index e85be9cf4c3..c7a6d101974 100644
--- a/chromium/components/autofill/android/BUILD.gn
+++ b/chromium/components/autofill/android/BUILD.gn
@@ -14,6 +14,48 @@ java_strings_grd("autofill_strings_grd") {
[ "values-{{source_name_part}}/autofill_strings.xml" ])
}
+android_resources("autofill_payments_java_resources") {
+ sources = [
+ "payments/java/res/drawable-hdpi/amex_card.png",
+ "payments/java/res/drawable-hdpi/diners_card.png",
+ "payments/java/res/drawable-hdpi/jcb_card.png",
+ "payments/java/res/drawable-hdpi/mc_card.png",
+ "payments/java/res/drawable-hdpi/troy_card.png",
+ "payments/java/res/drawable-hdpi/unionpay_card.png",
+ "payments/java/res/drawable-mdpi/amex_card.png",
+ "payments/java/res/drawable-mdpi/diners_card.png",
+ "payments/java/res/drawable-mdpi/jcb_card.png",
+ "payments/java/res/drawable-mdpi/mc_card.png",
+ "payments/java/res/drawable-mdpi/troy_card.png",
+ "payments/java/res/drawable-mdpi/unionpay_card.png",
+ "payments/java/res/drawable-xhdpi/amex_card.png",
+ "payments/java/res/drawable-xhdpi/diners_card.png",
+ "payments/java/res/drawable-xhdpi/jcb_card.png",
+ "payments/java/res/drawable-xhdpi/mc_card.png",
+ "payments/java/res/drawable-xhdpi/troy_card.png",
+ "payments/java/res/drawable-xhdpi/unionpay_card.png",
+ "payments/java/res/drawable-xxhdpi/amex_card.png",
+ "payments/java/res/drawable-xxhdpi/diners_card.png",
+ "payments/java/res/drawable-xxhdpi/jcb_card.png",
+ "payments/java/res/drawable-xxhdpi/mc_card.png",
+ "payments/java/res/drawable-xxhdpi/troy_card.png",
+ "payments/java/res/drawable-xxhdpi/unionpay_card.png",
+ "payments/java/res/drawable-xxxhdpi/amex_card.png",
+ "payments/java/res/drawable-xxxhdpi/diners_card.png",
+ "payments/java/res/drawable-xxxhdpi/jcb_card.png",
+ "payments/java/res/drawable-xxxhdpi/mc_card.png",
+ "payments/java/res/drawable-xxxhdpi/troy_card.png",
+ "payments/java/res/drawable-xxxhdpi/unionpay_card.png",
+ "payments/java/res/drawable/discover_card.xml",
+ "payments/java/res/drawable/elo_card.xml",
+ "payments/java/res/drawable/google_pay_plex.xml",
+ "payments/java/res/drawable/ic_credit_card_black.xml",
+ "payments/java/res/drawable/mir_card.xml",
+ "payments/java/res/drawable/visa_card.xml",
+ ]
+ deps = [ "//ui/android:ui_java_resources" ]
+}
+
android_resources("autofill_java_resources") {
sources = [
"java/res/layout/autofill_dropdown_footer_item_refresh.xml",
@@ -21,7 +63,6 @@ android_resources("autofill_java_resources") {
"java/res/layout/autofill_dropdown_item_refresh.xml",
"java/res/values/colors.xml",
"java/res/values/dimens.xml",
- "java/res/values/styles.xml",
]
deps = [
":autofill_strings_grd",
@@ -31,6 +72,8 @@ android_resources("autofill_java_resources") {
java_cpp_enum("autofill_core_browser_java_enums") {
sources = [
+ "../core/browser/data_model/credit_card.h",
+ "../core/browser/metrics/payments/virtual_card_enrollment_metrics.h",
"../core/browser/ui/accessory_sheet_enums.h",
"../core/browser/ui/popup_item_ids.h",
]
@@ -46,7 +89,9 @@ java_cpp_features("java_features_srcjar") {
"//components/autofill/android/java_templates/AutofillFeatures.java.tmpl"
}
-android_library("full_autofill_java") {
+# We intentionally do not include :autofill_payments_java_resources not to
+# bloat targets that may not require it.
+android_library("main_autofill_java") {
deps = [
":autofill_java_resources",
":payments_autofill_java",
@@ -86,7 +131,7 @@ android_library("payments_autofill_java") {
java_group("autofill_java") {
deps = [
- ":full_autofill_java",
+ ":main_autofill_java",
":payments_autofill_java",
]
}
diff --git a/chromium/components/autofill/android/payments/java/res/drawable-hdpi/amex_card.png b/chromium/components/autofill/android/payments/java/res/drawable-hdpi/amex_card.png
new file mode 100644
index 00000000000..c561395b0bb
--- /dev/null
+++ b/chromium/components/autofill/android/payments/java/res/drawable-hdpi/amex_card.png
Binary files differ
diff --git a/chromium/components/autofill/android/payments/java/res/drawable-hdpi/diners_card.png b/chromium/components/autofill/android/payments/java/res/drawable-hdpi/diners_card.png
new file mode 100644
index 00000000000..2d70ba1726e
--- /dev/null
+++ b/chromium/components/autofill/android/payments/java/res/drawable-hdpi/diners_card.png
Binary files differ
diff --git a/chromium/components/autofill/android/payments/java/res/drawable-hdpi/jcb_card.png b/chromium/components/autofill/android/payments/java/res/drawable-hdpi/jcb_card.png
new file mode 100644
index 00000000000..b21781d7926
--- /dev/null
+++ b/chromium/components/autofill/android/payments/java/res/drawable-hdpi/jcb_card.png
Binary files differ
diff --git a/chromium/components/autofill/android/payments/java/res/drawable-hdpi/mc_card.png b/chromium/components/autofill/android/payments/java/res/drawable-hdpi/mc_card.png
new file mode 100644
index 00000000000..462866c6490
--- /dev/null
+++ b/chromium/components/autofill/android/payments/java/res/drawable-hdpi/mc_card.png
Binary files differ
diff --git a/chromium/components/autofill/android/payments/java/res/drawable-hdpi/troy_card.png b/chromium/components/autofill/android/payments/java/res/drawable-hdpi/troy_card.png
new file mode 100644
index 00000000000..1c3715c40d3
--- /dev/null
+++ b/chromium/components/autofill/android/payments/java/res/drawable-hdpi/troy_card.png
Binary files differ
diff --git a/chromium/components/autofill/android/payments/java/res/drawable-hdpi/unionpay_card.png b/chromium/components/autofill/android/payments/java/res/drawable-hdpi/unionpay_card.png
new file mode 100644
index 00000000000..698d6ae2267
--- /dev/null
+++ b/chromium/components/autofill/android/payments/java/res/drawable-hdpi/unionpay_card.png
Binary files differ
diff --git a/chromium/components/autofill/android/payments/java/res/drawable-mdpi/amex_card.png b/chromium/components/autofill/android/payments/java/res/drawable-mdpi/amex_card.png
new file mode 100644
index 00000000000..10a6ed2263c
--- /dev/null
+++ b/chromium/components/autofill/android/payments/java/res/drawable-mdpi/amex_card.png
Binary files differ
diff --git a/chromium/components/autofill/android/payments/java/res/drawable-mdpi/diners_card.png b/chromium/components/autofill/android/payments/java/res/drawable-mdpi/diners_card.png
new file mode 100644
index 00000000000..040a387c5df
--- /dev/null
+++ b/chromium/components/autofill/android/payments/java/res/drawable-mdpi/diners_card.png
Binary files differ
diff --git a/chromium/components/autofill/android/payments/java/res/drawable-mdpi/jcb_card.png b/chromium/components/autofill/android/payments/java/res/drawable-mdpi/jcb_card.png
new file mode 100644
index 00000000000..627235f95d1
--- /dev/null
+++ b/chromium/components/autofill/android/payments/java/res/drawable-mdpi/jcb_card.png
Binary files differ
diff --git a/chromium/components/autofill/android/payments/java/res/drawable-mdpi/mc_card.png b/chromium/components/autofill/android/payments/java/res/drawable-mdpi/mc_card.png
new file mode 100644
index 00000000000..9ed8928b599
--- /dev/null
+++ b/chromium/components/autofill/android/payments/java/res/drawable-mdpi/mc_card.png
Binary files differ
diff --git a/chromium/components/autofill/android/payments/java/res/drawable-mdpi/troy_card.png b/chromium/components/autofill/android/payments/java/res/drawable-mdpi/troy_card.png
new file mode 100644
index 00000000000..8ff90b187f2
--- /dev/null
+++ b/chromium/components/autofill/android/payments/java/res/drawable-mdpi/troy_card.png
Binary files differ
diff --git a/chromium/components/autofill/android/payments/java/res/drawable-mdpi/unionpay_card.png b/chromium/components/autofill/android/payments/java/res/drawable-mdpi/unionpay_card.png
new file mode 100644
index 00000000000..a30a8e13e02
--- /dev/null
+++ b/chromium/components/autofill/android/payments/java/res/drawable-mdpi/unionpay_card.png
Binary files differ
diff --git a/chromium/components/autofill/android/payments/java/res/drawable-xhdpi/amex_card.png b/chromium/components/autofill/android/payments/java/res/drawable-xhdpi/amex_card.png
new file mode 100644
index 00000000000..de2f12f7166
--- /dev/null
+++ b/chromium/components/autofill/android/payments/java/res/drawable-xhdpi/amex_card.png
Binary files differ
diff --git a/chromium/components/autofill/android/payments/java/res/drawable-xhdpi/diners_card.png b/chromium/components/autofill/android/payments/java/res/drawable-xhdpi/diners_card.png
new file mode 100644
index 00000000000..2fe01352acb
--- /dev/null
+++ b/chromium/components/autofill/android/payments/java/res/drawable-xhdpi/diners_card.png
Binary files differ
diff --git a/chromium/components/autofill/android/payments/java/res/drawable-xhdpi/jcb_card.png b/chromium/components/autofill/android/payments/java/res/drawable-xhdpi/jcb_card.png
new file mode 100644
index 00000000000..e800b7af81b
--- /dev/null
+++ b/chromium/components/autofill/android/payments/java/res/drawable-xhdpi/jcb_card.png
Binary files differ
diff --git a/chromium/components/autofill/android/payments/java/res/drawable-xhdpi/mc_card.png b/chromium/components/autofill/android/payments/java/res/drawable-xhdpi/mc_card.png
new file mode 100644
index 00000000000..31a4bbc7bad
--- /dev/null
+++ b/chromium/components/autofill/android/payments/java/res/drawable-xhdpi/mc_card.png
Binary files differ
diff --git a/chromium/components/autofill/android/payments/java/res/drawable-xhdpi/troy_card.png b/chromium/components/autofill/android/payments/java/res/drawable-xhdpi/troy_card.png
new file mode 100644
index 00000000000..595bbdbdad1
--- /dev/null
+++ b/chromium/components/autofill/android/payments/java/res/drawable-xhdpi/troy_card.png
Binary files differ
diff --git a/chromium/components/autofill/android/payments/java/res/drawable-xhdpi/unionpay_card.png b/chromium/components/autofill/android/payments/java/res/drawable-xhdpi/unionpay_card.png
new file mode 100644
index 00000000000..9166219f161
--- /dev/null
+++ b/chromium/components/autofill/android/payments/java/res/drawable-xhdpi/unionpay_card.png
Binary files differ
diff --git a/chromium/components/autofill/android/payments/java/res/drawable-xxhdpi/amex_card.png b/chromium/components/autofill/android/payments/java/res/drawable-xxhdpi/amex_card.png
new file mode 100644
index 00000000000..1365ab88afe
--- /dev/null
+++ b/chromium/components/autofill/android/payments/java/res/drawable-xxhdpi/amex_card.png
Binary files differ
diff --git a/chromium/components/autofill/android/payments/java/res/drawable-xxhdpi/diners_card.png b/chromium/components/autofill/android/payments/java/res/drawable-xxhdpi/diners_card.png
new file mode 100644
index 00000000000..6bbba315f19
--- /dev/null
+++ b/chromium/components/autofill/android/payments/java/res/drawable-xxhdpi/diners_card.png
Binary files differ
diff --git a/chromium/components/autofill/android/payments/java/res/drawable-xxhdpi/jcb_card.png b/chromium/components/autofill/android/payments/java/res/drawable-xxhdpi/jcb_card.png
new file mode 100644
index 00000000000..16192cee7c9
--- /dev/null
+++ b/chromium/components/autofill/android/payments/java/res/drawable-xxhdpi/jcb_card.png
Binary files differ
diff --git a/chromium/components/autofill/android/payments/java/res/drawable-xxhdpi/mc_card.png b/chromium/components/autofill/android/payments/java/res/drawable-xxhdpi/mc_card.png
new file mode 100644
index 00000000000..171c1298117
--- /dev/null
+++ b/chromium/components/autofill/android/payments/java/res/drawable-xxhdpi/mc_card.png
Binary files differ
diff --git a/chromium/components/autofill/android/payments/java/res/drawable-xxhdpi/troy_card.png b/chromium/components/autofill/android/payments/java/res/drawable-xxhdpi/troy_card.png
new file mode 100644
index 00000000000..a2eebafe0c2
--- /dev/null
+++ b/chromium/components/autofill/android/payments/java/res/drawable-xxhdpi/troy_card.png
Binary files differ
diff --git a/chromium/components/autofill/android/payments/java/res/drawable-xxhdpi/unionpay_card.png b/chromium/components/autofill/android/payments/java/res/drawable-xxhdpi/unionpay_card.png
new file mode 100644
index 00000000000..b37d3185cef
--- /dev/null
+++ b/chromium/components/autofill/android/payments/java/res/drawable-xxhdpi/unionpay_card.png
Binary files differ
diff --git a/chromium/components/autofill/android/payments/java/res/drawable-xxxhdpi/amex_card.png b/chromium/components/autofill/android/payments/java/res/drawable-xxxhdpi/amex_card.png
new file mode 100644
index 00000000000..823548efa3d
--- /dev/null
+++ b/chromium/components/autofill/android/payments/java/res/drawable-xxxhdpi/amex_card.png
Binary files differ
diff --git a/chromium/components/autofill/android/payments/java/res/drawable-xxxhdpi/diners_card.png b/chromium/components/autofill/android/payments/java/res/drawable-xxxhdpi/diners_card.png
new file mode 100644
index 00000000000..eba2434f24a
--- /dev/null
+++ b/chromium/components/autofill/android/payments/java/res/drawable-xxxhdpi/diners_card.png
Binary files differ
diff --git a/chromium/components/autofill/android/payments/java/res/drawable-xxxhdpi/jcb_card.png b/chromium/components/autofill/android/payments/java/res/drawable-xxxhdpi/jcb_card.png
new file mode 100644
index 00000000000..e07b5f5e8ed
--- /dev/null
+++ b/chromium/components/autofill/android/payments/java/res/drawable-xxxhdpi/jcb_card.png
Binary files differ
diff --git a/chromium/components/autofill/android/payments/java/res/drawable-xxxhdpi/mc_card.png b/chromium/components/autofill/android/payments/java/res/drawable-xxxhdpi/mc_card.png
new file mode 100644
index 00000000000..c46ab352465
--- /dev/null
+++ b/chromium/components/autofill/android/payments/java/res/drawable-xxxhdpi/mc_card.png
Binary files differ
diff --git a/chromium/components/autofill/android/payments/java/res/drawable-xxxhdpi/troy_card.png b/chromium/components/autofill/android/payments/java/res/drawable-xxxhdpi/troy_card.png
new file mode 100644
index 00000000000..9ea79c33dea
--- /dev/null
+++ b/chromium/components/autofill/android/payments/java/res/drawable-xxxhdpi/troy_card.png
Binary files differ
diff --git a/chromium/components/autofill/android/payments/java/res/drawable-xxxhdpi/unionpay_card.png b/chromium/components/autofill/android/payments/java/res/drawable-xxxhdpi/unionpay_card.png
new file mode 100644
index 00000000000..746b6984dba
--- /dev/null
+++ b/chromium/components/autofill/android/payments/java/res/drawable-xxxhdpi/unionpay_card.png
Binary files differ
diff --git a/chromium/components/autofill/android/payments/java/res/drawable/discover_card.xml b/chromium/components/autofill/android/payments/java/res/drawable/discover_card.xml
new file mode 100644
index 00000000000..be643967ce8
--- /dev/null
+++ b/chromium/components/autofill/android/payments/java/res/drawable/discover_card.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--Copyright 2019 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.-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="32dp" android:height="20dp" android:viewportWidth="32" android:viewportHeight="20">
+ <path android:pathData="M3 1h26a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V3a2 2 0 0 1 2-2z" android:strokeWidth="1" android:fillColor="#FFFFFF" android:fillType="evenOdd"/>
+ <path android:pathData="M9 19h20.997C30.551 19 31 18.553 31 18.004V11.5S22.722 16.774 9 19z" android:strokeWidth="1" android:fillColor="#F68221" android:fillType="evenOdd"/>
+ <path android:pathData="M4.201 7H3.014v4h1.18c0.629 0 1.083-0.144 1.48-0.463 0.473-0.377 0.753-0.947 0.753-1.535C6.427 7.822 5.513 7 4.2 7zm0.945 3.004c-0.255 0.222-0.585 0.318-1.107 0.318H3.822V7.677H4.04c0.522 0 0.84 0.09 1.107 0.324 0.28 0.24 0.447 0.612 0.447 0.995 0.001 0.384-0.167 0.768-0.447 1.008zM6.799 7h1v4h-1zm2.787 1.54C9.1 8.366 8.958 8.252 8.958 8.035c0-0.253 0.253-0.445 0.602-0.445 0.242 0 0.442 0.096 0.653 0.325l0.423-0.536c-0.348-0.295-0.764-0.446-1.218-0.446-0.734 0-1.294 0.494-1.294 1.15 0 0.554 0.26 0.838 1.02 1.102 0.316 0.108 0.477 0.18 0.56 0.228 0.16 0.102 0.24 0.247 0.24 0.417 0 0.325-0.267 0.567-0.627 0.567-0.386 0-0.697-0.187-0.883-0.536l-0.522 0.488c0.373 0.53 0.82 0.764 1.435 0.764 0.84 0 1.43-0.54 1.43-1.319 0-0.638-0.273-0.926-1.192-1.253zm1.447 0.47c0 1.18 0.957 2.095 2.189 2.095 0.348 0 0.646-0.066 1.013-0.234V9.95c-0.323 0.313-0.61 0.44-0.976 0.44-0.814 0-1.393-0.573-1.393-1.386 0-0.77 0.597-1.379 1.356-1.379 0.385 0 0.677 0.133 1.013 0.452V7.155C13.88 6.981 13.588 6.91 13.241 6.91c-1.226 0-2.208 0.934-2.208 2.101zm9.615 0.688l-1.106-2.699h-0.883l1.76 4.12h0.435L22.644 7h-0.876z" android:strokeWidth="1" android:fillColor="#231F20" android:fillType="evenOdd"/>
+ <path android:pathData="M14.431 9.01a2.248 2.18 0 1 0 4.496 0 2.248 2.18 0 1 0-4.496 0z" android:strokeWidth="1" android:fillColor="#F68221" android:fillType="evenOdd"/>
+ <path android:pathData="M23.01 11h2.294v-0.678h-1.486v-1.08h1.43V8.566h-1.43V7.677h1.486V7H23.01zm5.496-2.82c0-0.748-0.535-1.18-1.467-1.18h-1.2v4h0.808V9.393h0.105L27.872 11h0.994l-1.305-1.685c0.61-0.12 0.945-0.522 0.945-1.134zm-1.622 0.66h-0.236V7.63h0.249c0.503 0 0.777 0.203 0.777 0.592 0 0.402-0.274 0.619-0.79 0.619z" android:strokeWidth="1" android:fillColor="#231F20" android:fillType="evenOdd"/>
+ <path android:pathData="M9 19h20.997C30.551 19 31 18.553 31 18.004V11.5S22.722 16.774 9 19z" android:strokeWidth="1" android:fillColor="#F68221" android:fillType="evenOdd"/>
+ <path android:pathData="M4.201 7H3.014v4h1.18c0.629 0 1.083-0.144 1.48-0.463 0.473-0.377 0.753-0.947 0.753-1.535C6.427 7.822 5.513 7 4.2 7zm0.945 3.004c-0.255 0.222-0.585 0.318-1.107 0.318H3.822V7.677H4.04c0.522 0 0.84 0.09 1.107 0.324 0.28 0.24 0.447 0.612 0.447 0.995 0.001 0.384-0.167 0.768-0.447 1.008zM6.799 7h1v4h-1zm2.787 1.54C9.1 8.366 8.958 8.252 8.958 8.035c0-0.253 0.253-0.445 0.602-0.445 0.242 0 0.442 0.096 0.653 0.325l0.423-0.536c-0.348-0.295-0.764-0.446-1.218-0.446-0.734 0-1.294 0.494-1.294 1.15 0 0.554 0.26 0.838 1.02 1.102 0.316 0.108 0.477 0.18 0.56 0.228 0.16 0.102 0.24 0.247 0.24 0.417 0 0.325-0.267 0.567-0.627 0.567-0.386 0-0.697-0.187-0.883-0.536l-0.522 0.488c0.373 0.53 0.82 0.764 1.435 0.764 0.84 0 1.43-0.54 1.43-1.319 0-0.638-0.273-0.926-1.192-1.253zm1.447 0.47c0 1.18 0.957 2.095 2.189 2.095 0.348 0 0.646-0.066 1.013-0.234V9.95c-0.323 0.313-0.61 0.44-0.976 0.44-0.814 0-1.393-0.573-1.393-1.386 0-0.77 0.597-1.379 1.356-1.379 0.385 0 0.677 0.133 1.013 0.452V7.155C13.88 6.981 13.588 6.91 13.241 6.91c-1.226 0-2.208 0.934-2.208 2.101zm9.615 0.688l-1.106-2.699h-0.883l1.76 4.12h0.435L22.644 7h-0.876z" android:strokeWidth="1" android:fillColor="#231F20" android:fillType="evenOdd"/>
+ <path android:pathData="M14.431 9.01a2.248 2.18 0 1 0 4.496 0 2.248 2.18 0 1 0-4.496 0z" android:strokeWidth="1" android:fillColor="#F68221" android:fillType="evenOdd"/>
+ <path android:pathData="M23.01 11h2.294v-0.678h-1.486v-1.08h1.43V8.566h-1.43V7.677h1.486V7H23.01zm5.496-2.82c0-0.748-0.535-1.18-1.467-1.18h-1.2v4h0.808V9.393h0.105L27.872 11h0.994l-1.305-1.685c0.61-0.12 0.945-0.522 0.945-1.134zm-1.622 0.66h-0.236V7.63h0.249c0.503 0 0.777 0.203 0.777 0.592 0 0.402-0.274 0.619-0.79 0.619z" android:strokeWidth="1" android:fillColor="#231F20" android:fillType="evenOdd"/>
+</vector>
diff --git a/chromium/components/autofill/android/payments/java/res/drawable/elo_card.xml b/chromium/components/autofill/android/payments/java/res/drawable/elo_card.xml
new file mode 100644
index 00000000000..e50e4ca22d9
--- /dev/null
+++ b/chromium/components/autofill/android/payments/java/res/drawable/elo_card.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--Copyright 2019 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.-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="32dp" android:height="20dp" android:viewportWidth="32" android:viewportHeight="20">
+ <path android:pathData="M3 1h26a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V3a2 2 0 0 1 2-2z" android:strokeWidth="1" android:fillColor="#FFFFFF" android:fillType="evenOdd"/>
+ <path android:pathData="M9 10c0-3.867 3.134-7 7-7s7 3.133 7 7-3.134 7-7 7-7-3.133-7-7" android:strokeWidth="1" android:fillColor="#000000" android:fillType="evenOdd"/>
+ <path android:pathData="M13.87 10.85c-0.216 0.213-0.511 0.341-0.836 0.337-0.224-0.004-0.43-0.07-0.606-0.182l-0.436 0.694c0.298 0.189 0.65 0.3 1.03 0.307 0.552 0.008 1.055-0.21 1.421-0.568l-0.572-0.587zm-1.984-0.713c-0.005-0.046-0.008-0.094-0.007-0.142 0.01-0.648 0.544-1.165 1.191-1.154 0.353 0.005 0.666 0.166 0.877 0.416l-2.061 0.88zm1.196-2.116c-1.1-0.017-2.005 0.862-2.021 1.962-0.007 0.412 0.112 0.797 0.322 1.118l3.608-1.543c-0.203-0.869-0.976-1.522-1.91-1.537zm3.04-0.898v3.847l0.668 0.277-0.316 0.758-0.66-0.274c-0.148-0.064-0.249-0.162-0.325-0.273-0.073-0.113-0.128-0.268-0.128-0.477V7.123h0.761z" android:strokeWidth="1" android:fillColor="#FFFFFF" android:fillType="evenOdd"/>
+ <path android:pathData="M18.128 10.897c-0.225-0.214-0.402-0.55-0.402-0.883 0-0.351 0.157-0.663 0.4-0.878L17.58 8.522c-0.412 0.365-0.673 0.897-0.673 1.492 0 0.602 0.268 1.14 0.69 1.506l0.532-0.623" android:strokeWidth="1" android:fillColor="#00A6E0" android:fillType="evenOdd"/>
+ <path android:pathData="M18.508 8.91c0.127-0.047 0.246-0.07 0.39-0.07 0.567 0 1.038 0.401 1.149 0.934l0.802-0.167c-0.187-0.905-0.989-1.586-1.951-1.586-0.232 0-0.455 0.041-0.663 0.115l0.273 0.774s0.005-0.002 0 0" android:strokeWidth="1" android:fillColor="#FFF000" android:fillType="evenOdd"/>
+ <path android:pathData="M18.898 11.186c-0.157 0-0.382-0.067-0.382-0.067l-0.262 0.778c0.202 0.07 0.419 0.109 0.644 0.109 0.973 0 1.782-0.697 1.957-1.619l-0.806-0.152c-0.104 0.542-0.579 0.951-1.151 0.951" android:strokeWidth="1" android:fillColor="#FF0217" android:fillType="evenOdd"/>
+ <path android:pathData="M9 10c0-3.867 3.134-7 7-7s7 3.133 7 7-3.134 7-7 7-7-3.133-7-7" android:strokeWidth="1" android:fillColor="#000000" android:fillType="evenOdd"/>
+ <path android:pathData="M13.87 10.85c-0.216 0.213-0.511 0.341-0.836 0.337-0.224-0.004-0.43-0.07-0.606-0.182l-0.436 0.694c0.298 0.189 0.65 0.3 1.03 0.307 0.552 0.008 1.055-0.21 1.421-0.568l-0.572-0.587zm-1.984-0.713c-0.005-0.046-0.008-0.094-0.007-0.142 0.01-0.648 0.544-1.165 1.191-1.154 0.353 0.005 0.666 0.166 0.877 0.416l-2.061 0.88zm1.196-2.116c-1.1-0.017-2.005 0.862-2.021 1.962-0.007 0.412 0.112 0.797 0.322 1.118l3.608-1.543c-0.203-0.869-0.976-1.522-1.91-1.537zm3.04-0.898v3.847l0.668 0.277-0.316 0.758-0.66-0.274c-0.148-0.064-0.249-0.162-0.325-0.273-0.073-0.113-0.128-0.268-0.128-0.477V7.123h0.761z" android:strokeWidth="1" android:fillColor="#FFFFFF" android:fillType="evenOdd"/>
+ <path android:pathData="M18.128 10.897c-0.225-0.214-0.402-0.55-0.402-0.883 0-0.351 0.157-0.663 0.4-0.878L17.58 8.522c-0.412 0.365-0.673 0.897-0.673 1.492 0 0.602 0.268 1.14 0.69 1.506l0.532-0.623" android:strokeWidth="1" android:fillColor="#00A6E0" android:fillType="evenOdd"/>
+ <path android:pathData="M18.508 8.91c0.127-0.047 0.246-0.07 0.39-0.07 0.567 0 1.038 0.401 1.149 0.934l0.802-0.167c-0.187-0.905-0.989-1.586-1.951-1.586-0.232 0-0.455 0.041-0.663 0.115l0.273 0.774s0.005-0.002 0 0" android:strokeWidth="1" android:fillColor="#FFF000" android:fillType="evenOdd"/>
+ <path android:pathData="M18.898 11.186c-0.157 0-0.382-0.067-0.382-0.067l-0.262 0.778c0.202 0.07 0.419 0.109 0.644 0.109 0.973 0 1.782-0.697 1.957-1.619l-0.806-0.152c-0.104 0.542-0.579 0.951-1.151 0.951" android:strokeWidth="1" android:fillColor="#FF0217" android:fillType="evenOdd"/>
+</vector>
diff --git a/chromium/components/autofill/android/payments/java/res/drawable/google_pay_plex.xml b/chromium/components/autofill/android/payments/java/res/drawable/google_pay_plex.xml
new file mode 100644
index 00000000000..ce7537696db
--- /dev/null
+++ b/chromium/components/autofill/android/payments/java/res/drawable/google_pay_plex.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2021 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. -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="32dp"
+ android:height="20dp"
+ android:viewportWidth="32"
+ android:viewportHeight="20">
+ <path
+ android:pathData="M2,0L30,0A2,2 0,0 1,32 2L32,18A2,2 0,0 1,30 20L2,20A2,2 0,0 1,0 18L0,2A2,2 0,0 1,2 0z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M18.8265,7.1284L19.7068,7.6356C20.409,8.0397 20.6499,8.9378 20.244,9.6391L17.9584,13.5869L18.9118,14.1363C19.6149,14.5413 20.5131,14.3003 20.9199,13.5981L23.1371,9.7684C23.8806,8.484 23.4418,6.8434 22.1584,6.0981C21.0212,5.4503 19.5728,5.8403 18.9174,6.9719L18.8265,7.1284Z"
+ android:strokeWidth="1.5"
+ android:fillColor="#00000000"
+ android:strokeColor="#EA4335"/>
+ <path
+ android:pathData="M19.7097,7.6364L19.1519,7.3148C18.9728,7.2117 18.7441,7.2726 18.64,7.4517L15.746,12.4504C15.28,13.2558 14.2506,13.5314 13.4444,13.0673L12.6813,12.6276C12.011,13.8042 12.3663,15.2883 13.4781,16.0355C14.7625,16.748 16.3872,16.3036 17.125,15.0295L20.2469,9.637C20.651,8.9367 20.411,8.0404 19.7097,7.6364Z"
+ android:strokeWidth="1.5"
+ android:fillColor="#00000000"
+ android:strokeColor="#FBBC04"/>
+ <path
+ android:pathData="M12.864,12.7346L13.4415,13.0674C14.2487,13.5324 15.28,13.2558 15.7468,12.4496L18.9184,6.9718C19.5756,5.8365 21.0306,5.4474 22.1687,6.1027L20.1081,4.9159L18.6493,4.0759C17.0359,3.1468 14.9734,3.6981 14.0415,5.3068L13.5437,6.1665L14.4353,6.6783C15.1384,7.0824 15.3793,7.9758 14.9734,8.6752L12.7862,12.4439C12.7281,12.5461 12.7628,12.6755 12.864,12.7346Z"
+ android:strokeWidth="1.5"
+ android:fillColor="#00000000"
+ android:strokeColor="#34A853"/>
+ <path
+ android:pathData="M14.4362,6.6793L12.8594,5.7736C12.1562,5.3696 11.2581,5.6096 10.8522,6.3089L8.9603,9.5686C8.0294,11.1736 8.5816,13.2258 10.195,14.1521L11.3959,14.8421L12.8519,15.6783L13.4837,16.0402C12.3616,15.2911 12.0062,13.7911 12.6916,12.6099L13.1809,11.7661L14.9744,8.6752C15.3794,7.9768 15.1394,7.0824 14.4362,6.6793Z"
+ android:strokeWidth="1.5"
+ android:fillColor="#00000000"
+ android:strokeColor="#4285F4"/>
+</vector>
diff --git a/chromium/components/autofill/android/payments/java/res/drawable/ic_credit_card_black.xml b/chromium/components/autofill/android/payments/java/res/drawable/ic_credit_card_black.xml
new file mode 100644
index 00000000000..a0d1442f813
--- /dev/null
+++ b/chromium/components/autofill/android/payments/java/res/drawable/ic_credit_card_black.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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. -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="32dp"
+ android:height="20dp"
+ android:viewportWidth="128"
+ android:viewportHeight="80">
+
+ <path
+ android:fillType="evenOdd"
+ android:strokeWidth="1"
+ android:pathData="M 0 0 L 128 0 L 128 80 L 0 80 Z" />
+ <path
+ android:fillColor="#000000"
+ android:fillAlpha="0.54"
+ android:fillType="evenOdd"
+ android:strokeWidth="1"
+ android:pathData="M96,8 L32,8 C27.56,8 24.04,11.56 24.04,16 L24,64 C24,68.44 27.56,72 32,72 L96,72
+C100.44,72 104,68.44 104,64 L104,16 C104,11.56 100.44,8 96,8 Z M96,64 L32,64
+L32,40 L96,40 L96,64 Z M96,24 L32,24 L32,16 L96,16 L96,24 Z" />
+</vector>
diff --git a/chromium/components/autofill/android/payments/java/res/drawable/mir_card.xml b/chromium/components/autofill/android/payments/java/res/drawable/mir_card.xml
new file mode 100644
index 00000000000..76c2da5cec2
--- /dev/null
+++ b/chromium/components/autofill/android/payments/java/res/drawable/mir_card.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--Copyright 2019 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.-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="32dp" android:height="20dp" android:viewportWidth="32" android:viewportHeight="20">
+ <path android:pathData="M5.328 6.5l0.138 0.007c0.502 0.049 0.935 0.362 1.122 0.81l0.045 0.126 0.952 3.187c0.021 0.071 0.112 0.083 0.157 0.035l0.02-0.035 0.952-3.187C8.868 6.928 9.334 6.56 9.88 6.507L10.019 6.5h2.328v7H10.02V9.405c0-0.086-0.109-0.115-0.16-0.06L9.84 9.379 8.48 13.5H6.868l-1.36-4.121C5.48 9.296 5.368 9.3 5.336 9.367L5.328 9.405V13.5H3v-7h2.328zm10.357 0v4.025c0 0.079 0.094 0.112 0.149 0.07l0.027-0.033 1.6-3.315c0.199-0.414 0.61-0.693 1.076-0.74L18.678 6.5h1.97v7H18.32V9.254c0-0.082-0.1-0.114-0.154-0.067l-0.022 0.031-1.622 3.535c-0.19 0.412-0.594 0.692-1.055 0.74l-0.14 0.007h-1.97v-7h2.328zm13.103 3.226c-0.355 0.899-1.262 1.538-2.325 1.538h-2.477V13.5h-2.328V9.726z" android:strokeWidth="1" android:fillColor="#3BA536" android:fillType="evenOdd"/>
+ <path android:pathData="M26.463 6.5h-5.108c0.18 1.62 1.61 2.882 3.347 2.882h4.192c0.036-0.161 0.055-0.328 0.055-0.5 0-1.316-1.113-2.382-2.486-2.382" android:strokeWidth="1" android:fillColor="#0093D3" android:fillType="evenOdd"/>
+ <path android:pathData="M3 1h26a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V3a2 2 0 0 1 2-2z" android:strokeWidth="1" android:fillColor="#FFFFFF" android:fillType="evenOdd"/>
+ <path android:pathData="M5.328 6.5l0.138 0.007c0.502 0.049 0.935 0.362 1.122 0.81l0.045 0.126 0.952 3.187c0.021 0.071 0.112 0.083 0.157 0.035l0.02-0.035 0.952-3.187C8.868 6.928 9.334 6.56 9.88 6.507L10.019 6.5h2.328v7H10.02V9.405c0-0.086-0.109-0.115-0.16-0.06L9.84 9.379 8.48 13.5H6.868l-1.36-4.121C5.48 9.296 5.368 9.3 5.336 9.367L5.328 9.405V13.5H3v-7h2.328zm10.357 0v4.025c0 0.079 0.094 0.112 0.149 0.07l0.027-0.033 1.6-3.315c0.199-0.414 0.61-0.693 1.076-0.74L18.678 6.5h1.97v7H18.32V9.254c0-0.082-0.1-0.114-0.154-0.067l-0.022 0.031-1.622 3.535c-0.19 0.412-0.594 0.692-1.055 0.74l-0.14 0.007h-1.97v-7h2.328zm13.103 3.226c-0.355 0.899-1.262 1.538-2.325 1.538h-2.477V13.5h-2.328V9.726z" android:strokeWidth="1" android:fillColor="#3BA536" android:fillType="evenOdd"/>
+ <path android:pathData="M26.463 6.5h-5.108c0.18 1.62 1.61 2.882 3.347 2.882h4.192c0.036-0.161 0.055-0.328 0.055-0.5 0-1.316-1.113-2.382-2.486-2.382" android:strokeWidth="1" android:fillColor="#0093D3" android:fillType="evenOdd"/>
+</vector>
diff --git a/chromium/components/autofill/android/payments/java/res/drawable/visa_card.xml b/chromium/components/autofill/android/payments/java/res/drawable/visa_card.xml
new file mode 100644
index 00000000000..8fc27a87151
--- /dev/null
+++ b/chromium/components/autofill/android/payments/java/res/drawable/visa_card.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--Copyright 2019 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.-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="32dp" android:height="20dp" android:viewportWidth="32" android:viewportHeight="20">
+ <path android:pathData="M3 1h26a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V3a2 2 0 0 1 2-2z" android:strokeWidth="1" android:fillColor="#FFFFFF" android:fillType="evenOdd"/>
+ <path android:pathData="M15.873 5.996l-1.737 7.999h-2.1l1.736-7.999h2.101zm8.84 5.166l1.106-3.005 0.636 3.005h-1.742zm2.344 2.833H29l-1.695-7.999h-1.794c-0.403 0-0.745 0.23-0.894 0.587l-3.152 7.412h2.205l0.44-1.193h2.694l0.253 1.193zm-5.482-2.611c0.008-2.113-2.965-2.228-2.945-3.17 0.006-0.29 0.285-0.593 0.891-0.671 0.3-0.038 1.13-0.07 2.072 0.357l0.368-1.695c-0.505-0.182-1.156-0.355-1.964-0.355-2.076 0-3.539 1.087-3.551 2.646-0.014 1.149 1.042 1.791 1.84 2.174 0.818 0.393 1.092 0.645 1.09 0.995-0.006 0.537-0.654 0.772-1.256 0.781-1.057 0.018-1.67-0.28-2.16-0.503l-0.38 1.75c0.49 0.224 1.396 0.417 2.337 0.427 2.206 0 3.649-1.073 3.657-2.736zM9.47 13.993H7.248L5.573 7.612C5.47 7.218 5.38 7.074 5.073 6.909 4.567 6.639 3.733 6.385 3 6.227l0.05-0.23h3.575c0.456 0 0.865 0.297 0.97 0.815l0.883 4.628 2.187-5.444h2.207L9.47 13.995z" android:strokeWidth="1" android:fillColor="#10347E" android:fillType="evenOdd"/>
+ <path android:pathData="M15.873 5.996l-1.737 7.999h-2.1l1.736-7.999h2.101zm8.84 5.166l1.106-3.005 0.636 3.005h-1.742zm2.344 2.833H29l-1.695-7.999h-1.794c-0.403 0-0.745 0.23-0.894 0.587l-3.152 7.412h2.205l0.44-1.193h2.694l0.253 1.193zm-5.482-2.611c0.008-2.113-2.965-2.228-2.945-3.17 0.006-0.29 0.285-0.593 0.891-0.671 0.3-0.038 1.13-0.07 2.072 0.357l0.368-1.695c-0.505-0.182-1.156-0.355-1.964-0.355-2.076 0-3.539 1.087-3.551 2.646-0.014 1.149 1.042 1.791 1.84 2.174 0.818 0.393 1.092 0.645 1.09 0.995-0.006 0.537-0.654 0.772-1.256 0.781-1.057 0.018-1.67-0.28-2.16-0.503l-0.38 1.75c0.49 0.224 1.396 0.417 2.337 0.427 2.206 0 3.649-1.073 3.657-2.736zM9.47 13.993H7.248L5.573 7.612C5.47 7.218 5.38 7.074 5.073 6.909 4.567 6.639 3.733 6.385 3 6.227l0.05-0.23h3.575c0.456 0 0.865 0.297 0.97 0.815l0.883 4.628 2.187-5.444h2.207L9.47 13.995z" android:strokeWidth="1" android:fillColor="#10347E" android:fillType="evenOdd"/>
+</vector>
diff --git a/chromium/components/autofill/content/browser/content_autofill_driver.cc b/chromium/components/autofill/content/browser/content_autofill_driver.cc
index 0dff8fc4f2e..ff2abd79bbc 100644
--- a/chromium/components/autofill/content/browser/content_autofill_driver.cc
+++ b/chromium/components/autofill/content/browser/content_autofill_driver.cc
@@ -112,6 +112,11 @@ ContentAutofillDriver* ContentAutofillDriver::GetForRenderFrameHost(
void ContentAutofillDriver::BindPendingReceiver(
mojo::PendingAssociatedReceiver<mojom::AutofillDriver> pending_receiver) {
+ if (!base::FeatureList::IsEnabled(
+ features::kAutofillEnableWithinFencedFrame) &&
+ render_frame_host_->IsNestedWithinFencedFrame()) {
+ return;
+ }
receiver_.Bind(std::move(pending_receiver));
}
@@ -625,7 +630,14 @@ void ContentAutofillDriver::DidNavigateFrame(
return;
}
- ShowOfferNotificationIfApplicable(navigation_handle);
+ // If the navigation happened in the main frame and the BrowserAutofillManager
+ // exists (not in Android Webview), and the AutofillOfferManager exists (not
+ // in Incognito windows), notifies the navigation event.
+ if (navigation_handle->IsInPrimaryMainFrame() && browser_autofill_manager_ &&
+ browser_autofill_manager_->offer_manager()) {
+ browser_autofill_manager_->offer_manager()->OnDidNavigateFrame(
+ browser_autofill_manager_->client());
+ }
// When IsServedFromBackForwardCache or IsPrerendererdPageActivation, the form
// data is not parsed again. So, we should keep and use the autofill manager's
@@ -776,44 +788,6 @@ void ContentAutofillDriver::ReportAutofillWebOTPMetrics(
static_cast<PhoneCollectionMetricState>(phone_collection_metric_state_));
}
-void ContentAutofillDriver::ShowOfferNotificationIfApplicable(
- content::NavigationHandle* navigation_handle) {
- if (!navigation_handle->IsInPrimaryMainFrame())
- return;
-
- // Android webview does not have |browser_autofill_manager_|, so flow is not
- // enabled in Android Webview.
- if (!browser_autofill_manager_)
- return;
-
- AutofillOfferManager* offer_manager =
- browser_autofill_manager_->offer_manager();
- // This happens in the Incognito mode.
- if (!offer_manager)
- return;
-
- GURL url = browser_autofill_manager_->client()->GetLastCommittedURL();
- if (!offer_manager->IsUrlEligible(url))
- return;
-
- // Try to show offer notification when the last committed URL has the domain
- // that an offer is applicable for.
- // TODO(crbug.com/1203811): GetOfferForUrl needs to know whether to give
- // precedence to card-linked offers or promo code offers. Eventually, promo
- // code offers should take precedence if a bubble is shown. Currently, if a
- // url has both types of offers and the promo code offer is selected, no
- // bubble will end up being shown (due to not yet being implemented).
- AutofillOfferData* offer = offer_manager->GetOfferForUrl(url);
-
- if (!offer || offer->merchant_origins.empty() ||
- (offer->IsCardLinkedOffer() && offer->eligible_instrument_id.empty()) ||
- (offer->IsPromoCodeOffer() && offer->promo_code.empty())) {
- return;
- }
-
- browser_autofill_manager_->client()->ShowOfferNotificationIfApplicable(offer);
-}
-
ContentAutofillRouter& ContentAutofillDriver::GetAutofillRouter() {
DCHECK(content::RenderFrameHost::LifecycleState::kPrerendering !=
render_frame_host_->GetLifecycleState());
diff --git a/chromium/components/autofill/content/browser/content_autofill_driver.h b/chromium/components/autofill/content/browser/content_autofill_driver.h
index 00a4df54794..0211ed15b11 100644
--- a/chromium/components/autofill/content/browser/content_autofill_driver.h
+++ b/chromium/components/autofill/content/browser/content_autofill_driver.h
@@ -389,18 +389,12 @@ class ContentAutofillDriver : public AutofillDriver,
// received from the renderer.
void SetFrameAndFormMetaData(FormData& form,
FormFieldData* optional_field) const;
- FormData GetFormWithFrameAndFormMetaData(FormData form) const
- WARN_UNUSED_RESULT;
+ [[nodiscard]] FormData GetFormWithFrameAndFormMetaData(FormData form) const;
// Returns whether navigator.credentials.get({otp: {transport:"sms"}}) has
// been used.
bool DocumentUsedWebOTP() const;
- // Show a bubble or infobar indicating that the current page has an eligible
- // offer or reward, if the bubble/infobar is not currently being visible.
- void ShowOfferNotificationIfApplicable(
- content::NavigationHandle* navigation_handle);
-
// Returns the AutofillRouter and confirms that it may be accessed (we should
// not be using the router if we're prerendering).
ContentAutofillRouter& GetAutofillRouter();
diff --git a/chromium/components/autofill/content/browser/content_autofill_driver_factory_unittest.cc b/chromium/components/autofill/content/browser/content_autofill_driver_factory_unittest.cc
index 354f6a2ca74..2c961c735ed 100644
--- a/chromium/components/autofill/content/browser/content_autofill_driver_factory_unittest.cc
+++ b/chromium/components/autofill/content/browser/content_autofill_driver_factory_unittest.cc
@@ -165,39 +165,40 @@ TEST_F(ContentAutofillDriverFactoryTest, TabHidden) {
factory_->OnVisibilityChanged(content::Visibility::HIDDEN);
}
-// Test case with one frame, with BFcache enabled or disabled depending on the
-// parameter.
-class ContentAutofillDriverFactoryTest_WithOrWithoutBfCache
+// Test case with one frame, with BFcache and AutofillAcrossIframes enabled or
+// disabled depending on the parameter.
+class ContentAutofillDriverFactoryTest_WithOrWithoutBfCacheAndIframes
: public ContentAutofillDriverFactoryTest,
- public ::testing::WithParamInterface<bool> {
+ public ::testing::WithParamInterface<std::tuple<bool, bool>> {
public:
- ContentAutofillDriverFactoryTest_WithOrWithoutBfCache() {
+ ContentAutofillDriverFactoryTest_WithOrWithoutBfCacheAndIframes() {
std::vector<base::Feature> enabled;
// Allow BackForwardCache for all devices regardless of their memory.
std::vector<base::Feature> disabled{
::features::kBackForwardCacheMemoryControls};
+ (autofill_across_iframes() ? enabled : disabled)
+ .push_back(features::kAutofillAcrossIframes);
(use_bfcache() ? enabled : disabled)
.push_back(::features::kBackForwardCache);
scoped_feature_list_.InitWithFeatures(enabled, disabled);
}
- bool use_bfcache() { return GetParam(); }
+ bool use_bfcache() { return std::get<0>(GetParam()); }
+ bool autofill_across_iframes() { return std::get<1>(GetParam()); }
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
-INSTANTIATE_TEST_SUITE_P(,
- ContentAutofillDriverFactoryTest_WithOrWithoutBfCache,
- testing::Bool());
+INSTANTIATE_TEST_SUITE_P(
+ ,
+ ContentAutofillDriverFactoryTest_WithOrWithoutBfCacheAndIframes,
+ testing::Combine(testing::Bool(), testing::Bool()));
// Tests that that a same-documentation navigation does not touch the factory's
// router.
-TEST_P(ContentAutofillDriverFactoryTest_WithOrWithoutBfCache,
+TEST_P(ContentAutofillDriverFactoryTest_WithOrWithoutBfCacheAndIframes,
SameDocumentNavigation) {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitAndEnableFeature(features::kAutofillAcrossIframes);
-
content::RenderFrameHost* orig_rfh = main_rfh();
ContentAutofillDriver* orig_driver = factory_->DriverForFrame(orig_rfh);
@@ -222,7 +223,7 @@ TEST_P(ContentAutofillDriverFactoryTest_WithOrWithoutBfCache,
// Tests that that a driver survives a same-origin navigation but is reset
// afterwards.
-TEST_P(ContentAutofillDriverFactoryTest_WithOrWithoutBfCache,
+TEST_P(ContentAutofillDriverFactoryTest_WithOrWithoutBfCacheAndIframes,
SameOriginNavigation) {
content::RenderFrameHost* orig_rfh = main_rfh();
ContentAutofillDriver* orig_driver = factory_->DriverForFrame(orig_rfh);
@@ -246,7 +247,7 @@ TEST_P(ContentAutofillDriverFactoryTest_WithOrWithoutBfCache,
// Tests that that a driver is removed and replaced with a fresh one after a
// cross-origin navigation.
-TEST_P(ContentAutofillDriverFactoryTest_WithOrWithoutBfCache,
+TEST_P(ContentAutofillDriverFactoryTest_WithOrWithoutBfCacheAndIframes,
CrossOriginNavigation) {
content::RenderFrameHost* orig_rfh = main_rfh();
content::GlobalRenderFrameHostId orig_rfh_id = orig_rfh->GetGlobalId();
diff --git a/chromium/components/autofill/content/browser/content_autofill_driver_test_api.h b/chromium/components/autofill/content/browser/content_autofill_driver_test_api.h
index fefd2407907..fdf7102b9d3 100644
--- a/chromium/components/autofill/content/browser/content_autofill_driver_test_api.h
+++ b/chromium/components/autofill/content/browser/content_autofill_driver_test_api.h
@@ -32,6 +32,10 @@ class ContentAutofillDriverTestApi {
return driver_->GetFormWithFrameAndFormMetaData(form);
}
+ const mojo::AssociatedReceiver<mojom::AutofillDriver>& receiver() const {
+ return driver_->receiver_;
+ }
+
private:
// Non-null pointer to wrapped ContentAutofillDriver.
raw_ptr<ContentAutofillDriver> driver_;
diff --git a/chromium/components/autofill/content/browser/content_autofill_driver_unittest.cc b/chromium/components/autofill/content/browser/content_autofill_driver_unittest.cc
index ae35ab7aa91..b82978b262b 100644
--- a/chromium/components/autofill/content/browser/content_autofill_driver_unittest.cc
+++ b/chromium/components/autofill/content/browser/content_autofill_driver_unittest.cc
@@ -37,11 +37,13 @@
#include "content/public/test/navigation_simulator.h"
#include "content/public/test/test_renderer_host.h"
#include "mojo/public/cpp/bindings/associated_receiver_set.h"
+#include "mojo/public/cpp/bindings/associated_remote.h"
#include "net/base/net_errors.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
+#include "third_party/blink/public/common/features.h"
namespace autofill {
@@ -405,6 +407,65 @@ class ContentAutofillDriverTest : public content::RenderViewHostTestHarness,
FakeAutofillAgent fake_agent_;
};
+class ContentAutofillDriverFencedFramesTest
+ : public content::RenderViewHostTestHarness,
+ public ::testing::WithParamInterface<bool> {
+ public:
+ class TestContentAutofillDriver : public ContentAutofillDriver {
+ public:
+ explicit TestContentAutofillDriver(content::RenderFrameHost* rfh)
+ : ContentAutofillDriver(rfh) {}
+ };
+
+ ContentAutofillDriverFencedFramesTest()
+ : autofill_enabled_in_fencedframe_(GetParam()) {
+ std::vector<base::test::ScopedFeatureList::FeatureAndParams> enabled;
+ std::vector<base::Feature> disabled;
+ enabled.push_back(
+ {blink::features::kFencedFrames, {{"implementation_type", "mparch"}}});
+ if (autofill_enabled_in_fencedframe_) {
+ enabled.push_back({features::kAutofillEnableWithinFencedFrame, {}});
+ } else {
+ disabled.push_back(features::kAutofillEnableWithinFencedFrame);
+ }
+ scoped_feature_list_.InitWithFeaturesAndParameters(enabled, disabled);
+ }
+
+ ~ContentAutofillDriverFencedFramesTest() override = default;
+ void NavigateAndCommitInFrame(const std::string& url,
+ content::RenderFrameHost* rfh) {
+ auto navigation =
+ content::NavigationSimulator::CreateRendererInitiated(GURL(url), rfh);
+ // These tests simulate loading events manually.
+ // TODO(crbug.com/1294378): Consider refactoring to rely on load events
+ // dispatched by NavigationSimulator.
+ navigation->SetKeepLoading(true);
+ navigation->Start();
+ navigation->Commit();
+ }
+
+ protected:
+ bool autofill_enabled_in_fencedframe_;
+
+ private:
+ base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+TEST_P(ContentAutofillDriverFencedFramesTest, ToggleAutofillWithinFencedFrame) {
+ base::RunLoop().RunUntilIdle();
+ NavigateAndCommitInFrame("http://test.org", main_rfh());
+ content::RenderFrameHost* fenced_frame_root =
+ content::RenderFrameHostTester::For(main_rfh())->AppendFencedFrame();
+
+ TestContentAutofillDriver test_content_autofill_driver(fenced_frame_root);
+ mojo::AssociatedRemote<mojom::AutofillDriver> host_remote;
+
+ test_content_autofill_driver.BindPendingReceiver(
+ host_remote.BindNewEndpointAndPassDedicatedReceiver());
+ ContentAutofillDriverTestApi test_api(&test_content_autofill_driver);
+ EXPECT_EQ(autofill_enabled_in_fencedframe_, test_api.receiver().is_bound());
+}
+
TEST_P(ContentAutofillDriverTest, NavigatedMainFrameDifferentDocument) {
EXPECT_CALL(*driver_->mock_browser_autofill_manager(), Reset());
Navigate(NavigationType::kNormal);
@@ -701,5 +762,8 @@ TEST_P(ContentAutofillDriverTest, EnableHeavyFormDataScraping) {
INSTANTIATE_TEST_SUITE_P(ContentAutofillDriverTest,
ContentAutofillDriverTest,
testing::Bool());
+INSTANTIATE_TEST_SUITE_P(ContentAutofillDriverTest,
+ ContentAutofillDriverFencedFramesTest,
+ testing::Bool());
} // namespace autofill
diff --git a/chromium/components/autofill/content/browser/content_autofill_router.cc b/chromium/components/autofill/content/browser/content_autofill_router.cc
index 542e8bf6554..886d7cf5a1d 100644
--- a/chromium/components/autofill/content/browser/content_autofill_router.cc
+++ b/chromium/components/autofill/content/browser/content_autofill_router.cc
@@ -6,6 +6,7 @@
#include <algorithm>
+#include "base/containers/contains.h"
#include "base/debug/dump_without_crashing.h"
#include "base/functional/invoke.h"
#include "base/ranges/algorithm.h"
diff --git a/chromium/components/autofill/content/browser/form_forest.cc b/chromium/components/autofill/content/browser/form_forest.cc
index 0c78bb3a1db..edcd033b427 100644
--- a/chromium/components/autofill/content/browser/form_forest.cc
+++ b/chromium/components/autofill/content/browser/form_forest.cc
@@ -4,6 +4,7 @@
#include "components/autofill/content/browser/form_forest.h"
+#include "base/containers/contains.h"
#include "base/containers/cxx20_erase_vector.h"
#include "base/containers/stack.h"
#include "base/debug/dump_without_crashing.h"
@@ -35,8 +36,7 @@
#define AFCRASHDUMP() base::debug::DumpWithoutCrashing()
#endif
-namespace autofill {
-namespace internal {
+namespace autofill::internal {
namespace {
@@ -611,8 +611,8 @@ std::vector<FormData> FormForest::GetRendererFormsOfBrowserForm(
};
// Fields in frames whose permissions policy allows shared-autofill may
// be filled if the |triggered_origin| is the main origin.
- auto has_shared_autofill_permission = [&mutable_this](
- LocalFrameToken frame_token) {
+ auto HasSharedAutofillPermission = [&mutable_this](
+ LocalFrameToken frame_token) {
FrameData* frame = mutable_this.GetFrameData(frame_token);
return frame && frame->driver && frame->driver->render_frame_host() &&
frame->driver->render_frame_host()->IsFeatureEnabled(
@@ -625,9 +625,10 @@ std::vector<FormData> FormForest::GetRendererFormsOfBrowserForm(
it != field_type_map.end() ? it->second : UNKNOWN_TYPE;
return field.origin == triggered_origin ||
(field.origin == main_origin &&
+ HasSharedAutofillPermission(renderer_form->host_frame) &&
!IsSensitiveFieldType(field_type)) ||
(triggered_origin == main_origin &&
- has_shared_autofill_permission(renderer_form->host_frame));
+ HasSharedAutofillPermission(renderer_form->host_frame));
};
renderer_form->fields.push_back(browser_field);
@@ -638,5 +639,4 @@ std::vector<FormData> FormForest::GetRendererFormsOfBrowserForm(
return renderer_forms;
}
-} // namespace internal
-} // namespace autofill
+} // namespace autofill::internal
diff --git a/chromium/components/autofill/content/browser/form_forest.h b/chromium/components/autofill/content/browser/form_forest.h
index 397872e9897..a0b26cb6f9c 100644
--- a/chromium/components/autofill/content/browser/form_forest.h
+++ b/chromium/components/autofill/content/browser/form_forest.h
@@ -17,8 +17,7 @@
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/abseil-cpp/absl/types/variant.h"
-namespace autofill {
-namespace internal {
+namespace autofill::internal {
// FormForest converts renderer forms into a browser form and vice versa.
//
@@ -371,7 +370,6 @@ class FormForest {
frame_datas_;
};
-} // namespace internal
-} // namespace autofill
+} // namespace autofill::internal
#endif // COMPONENTS_AUTOFILL_CONTENT_BROWSER_FORM_FOREST_H_
diff --git a/chromium/components/autofill/content/browser/form_forest_unittest.cc b/chromium/components/autofill/content/browser/form_forest_unittest.cc
index 30728c669b6..98700db55ad 100644
--- a/chromium/components/autofill/content/browser/form_forest_unittest.cc
+++ b/chromium/components/autofill/content/browser/form_forest_unittest.cc
@@ -299,9 +299,18 @@ class MockContentAutofillDriver : public ContentAutofillDriver {
// RemoteFrameTokens.)
class FormForestTest : public content::RenderViewHostTestHarness {
public:
- // The frame's permissions policy affects which fields may be filled (see
+ // "Shared-autofill" may be enabled or disabled per frame for certain origins.
+ // The enum constants correspond to the following permission policies:
+ // - kDefault is the default policy, which enables shared-autofill on the
+ // main frame origin.
+ // - kSharedAutofill explicitly enables shared-autofill on a (child-) frame
+ // for its current origin.
+ // - kNoSharedAutofill explicitly disables shared-autofill on a frame for all
+ // origins.
+ // Child frames inherit the policy from their parents.
+ // "Shared-autofill" restricts cross-origin filling (see
// FormForest::GetBrowserFormOfRendererForm() for details).
- enum class Policy { kNone, kSharedAutofill };
+ enum class Policy { kDefault, kSharedAutofill, kNoSharedAutofill };
void SetUp() override {
RenderViewHostTestHarness::SetUp();
@@ -314,9 +323,22 @@ class FormForestTest : public content::RenderViewHostTestHarness {
}
protected:
- MockContentAutofillDriver* NavigateMainFrame(const GURL& url) {
- content::NavigationSimulator::CreateBrowserInitiated(url, web_contents())
- ->Commit();
+ MockContentAutofillDriver* NavigateMainFrame(
+ const GURL& url,
+ Policy policy = Policy::kDefault) {
+ auto simulator = content::NavigationSimulator::CreateBrowserInitiated(
+ url, web_contents());
+ switch (policy) {
+ case Policy::kDefault:
+ break;
+ case Policy::kSharedAutofill:
+ simulator->SetPermissionsPolicyHeader(AllowSharedAutofill(Origin(url)));
+ break;
+ case Policy::kNoSharedAutofill:
+ simulator->SetPermissionsPolicyHeader(DisallowSharedAutofill());
+ break;
+ }
+ simulator->Commit();
return GetOrCreateDriver(main_rfh());
}
@@ -327,20 +349,41 @@ class FormForestTest : public content::RenderViewHostTestHarness {
const GURL& url,
Policy policy,
base::StringPiece name) {
- auto permissions =
- policy != Policy::kSharedAutofill
- ? blink::ParsedPermissionsPolicy()
- : blink::ParsedPermissionsPolicy(
- {blink::ParsedPermissionsPolicyDeclaration(
- blink::mojom::PermissionsPolicyFeature::kSharedAutofill,
- {Origin(url)}, false, false)});
+ blink::ParsedPermissionsPolicy declared_policy;
+ switch (policy) {
+ case Policy::kDefault:
+ declared_policy = {};
+ break;
+ case Policy::kSharedAutofill:
+ declared_policy = AllowSharedAutofill(Origin(url));
+ break;
+ case Policy::kNoSharedAutofill:
+ declared_policy = DisallowSharedAutofill();
+ break;
+ }
content::RenderFrameHost* rfh =
content::RenderFrameHostTester::For(parent->render_frame_host())
- ->AppendChildWithPolicy(std::string(name), permissions);
+ ->AppendChildWithPolicy(static_cast<std::string>(name),
+ declared_policy);
return NavigateFrame(rfh, url);
}
private:
+ // Explicitly allows shared-autofill on |origin|.
+ static blink::ParsedPermissionsPolicy AllowSharedAutofill(
+ url::Origin origin) {
+ return {blink::ParsedPermissionsPolicyDeclaration(
+ blink::mojom::PermissionsPolicyFeature::kSharedAutofill, {origin},
+ false, false)};
+ }
+
+ // Explicitly disallows shared-autofill on all origins.
+ static blink::ParsedPermissionsPolicy DisallowSharedAutofill() {
+ return {blink::ParsedPermissionsPolicyDeclaration(
+ blink::mojom::PermissionsPolicyFeature::kSharedAutofill, {}, false,
+ false)};
+ }
+
MockContentAutofillDriver* NavigateFrame(content::RenderFrameHost* rfh,
const GURL& url) {
rfh = content::NavigationSimulator::NavigateAndCommitFromDocument(url, rfh);
@@ -376,7 +419,7 @@ class FormForestTestWithMockedTree : public FormForestTest {
// MockFormForest().
std::string url = "";
std::vector<FormInfo> forms = {};
- FormForestTest::Policy policy = FormForestTest::Policy::kNone;
+ FormForestTest::Policy policy = FormForestTest::Policy::kDefault;
// The index of the last field from the parent form that precedes this
// frame. This is analogous to FormData::child_frames[i].predecessor.
int field_predecessor = std::numeric_limits<int>::max();
@@ -414,12 +457,12 @@ class FormForestTestWithMockedTree : public FormForestTest {
: (!parent_driver ? kMainUrl : kIframeUrl));
MockContentAutofillDriver* driver =
!parent_driver
- ? NavigateMainFrame(url)
+ ? NavigateMainFrame(url, frame_info.policy)
: CreateAndNavigateChildFrame(parent_driver, url, frame_info.policy,
frame_info.name);
if (!frame_info.name.empty()) {
CHECK(!base::Contains(drivers_, frame_info.name));
- drivers_.emplace(std::string(frame_info.name), driver);
+ drivers_.emplace(frame_info.name, driver);
}
std::vector<FormData> forms;
@@ -1480,8 +1523,9 @@ TEST_F(FormForestTestUnflatten, InterruptedSameOriginPolicy) {
UnorderedArrayEquals(expectation));
}
-// Tests that (only) non-sensitive fields are filled cross-origin into the main
-// frame's origin.
+// Tests that (only) non-sensitive fields are filled across origin into the main
+// frame's origin (since the main frame has the shared-autofill policy by
+// default).
TEST_F(FormForestTestUnflatten, MainOriginPolicy) {
MockFormForest(
{.url = kMainUrl,
@@ -1504,6 +1548,26 @@ TEST_F(FormForestTestUnflatten, MainOriginPolicy) {
UnorderedArrayEquals(expectation));
}
+// Tests that no fields are filled across origin into frames where
+// shared-autofill is disabled (not even into non-sensitive fields).
+TEST_F(FormForestTestUnflatten, MainOriginPolicyWithoutSharedAutofill) {
+ MockFormForest(
+ {.url = kMainUrl,
+ .forms = {{.name = "main",
+ .frames = {{.url = kMainUrl, .forms = {{.name = "child1"}}},
+ {.url = kIframeUrl,
+ .forms = {{.name = "child2"}}}}}},
+ .policy = Policy::kNoSharedAutofill});
+ MockFlattening({{"main"}, {"child1"}, {"child2"}});
+ std::vector<FormData> expectation = {
+ WithoutValues(GetMockedForm("main")),
+ WithoutValues(GetMockedForm("child1")),
+ WithValues(GetMockedForm("child2"), Profile(2))};
+ EXPECT_THAT(GetRendererFormsOfBrowserForm("main", Origin(kIframeUrl),
+ FieldTypeMap("main")),
+ UnorderedArrayEquals(expectation));
+}
+
// Fixture for the shared-autofill policy tests.
class FormForestTestUnflattenSharedAutofillPolicy
: public FormForestTestUnflatten {
@@ -1549,8 +1613,8 @@ TEST_F(FormForestTestUnflattenSharedAutofillPolicy, FromOtherOrigin) {
TEST(FormForestTest, FrameDataComparator) {
FrameData::CompareByFrameToken less;
std::unique_ptr<FrameData> null;
- auto x = std::make_unique<FrameData>(test::GetLocalFrameToken());
- auto xx = std::make_unique<FrameData>(test::GetLocalFrameToken());
+ auto x = std::make_unique<FrameData>(test::MakeLocalFrameToken());
+ auto xx = std::make_unique<FrameData>(test::MakeLocalFrameToken());
auto y = std::make_unique<FrameData>(
LocalFrameToken(base::UnguessableToken::Deserialize(
x->frame_token->GetHighForSerialization() + 1,
diff --git a/chromium/components/autofill/content/browser/risk/fingerprint.cc b/chromium/components/autofill/content/browser/risk/fingerprint.cc
index 10edc0fa4a9..9b474a64008 100644
--- a/chromium/components/autofill/content/browser/risk/fingerprint.cc
+++ b/chromium/components/autofill/content/browser/risk/fingerprint.cc
@@ -46,6 +46,7 @@
#include "services/device/public/mojom/geolocation_context.mojom.h"
#include "services/device/public/mojom/geoposition.mojom.h"
#include "ui/display/display.h"
+#include "ui/display/display_util.h"
#include "ui/display/screen.h"
#include "ui/gfx/geometry/rect.h"
#include "url/gurl.h"
@@ -89,12 +90,12 @@ std::string GetOperatingSystemVersion() {
// Adds the list of |fonts| to the |machine|.
void AddFontsToFingerprint(const base::ListValue& fonts,
Fingerprint::MachineCharacteristics* machine) {
- for (const auto& it : fonts.GetList()) {
+ for (const auto& it : fonts.GetListDeprecated()) {
// Each item in the list is a two-element list such that the first element
// is the font family and the second is the font name.
DCHECK(it.is_list());
- std::string font_name = it.GetList()[1].GetString();
+ std::string font_name = it.GetListDeprecated()[1].GetString();
machine->add_font(font_name);
}
@@ -474,13 +475,21 @@ void GetFingerprint(
const std::string& app_locale,
const std::string& user_agent,
base::OnceCallback<void(std::unique_ptr<Fingerprint>)> callback) {
- gfx::Rect content_bounds = web_contents->GetContainerBounds();
-
+ gfx::Rect content_bounds;
display::ScreenInfo screen_info;
- content::RenderWidgetHostView* host_view =
- web_contents->GetRenderWidgetHostView();
- if (host_view)
- screen_info = host_view->GetRenderWidgetHost()->GetScreenInfo();
+
+ // |web_contents| can be nullptr in the Clank settings page, as a user can
+ // open Clank settings without opening a tab. Thus, we will need to populate
+ // |screen_info| using display::DisplayUtil::GetDefaultScreenInfo().
+ if (web_contents) {
+ content_bounds = web_contents->GetContainerBounds();
+ base::raw_ptr<content::RenderWidgetHostView> host_view =
+ web_contents->GetRenderWidgetHostView();
+ if (host_view)
+ screen_info = host_view->GetRenderWidgetHost()->GetScreenInfo();
+ } else {
+ display::DisplayUtil::GetDefaultScreenInfo(&screen_info);
+ }
internal::GetFingerprintInternal(
obfuscated_gaia_id, window_bounds, content_bounds, screen_info, version,
diff --git a/chromium/components/autofill/content/browser/risk/fingerprint_browsertest.cc b/chromium/components/autofill/content/browser/risk/fingerprint_browsertest.cc
index f9ac936b081..851b40ca07c 100644
--- a/chromium/components/autofill/content/browser/risk/fingerprint_browsertest.cc
+++ b/chromium/components/autofill/content/browser/risk/fingerprint_browsertest.cc
@@ -95,7 +95,13 @@ class AutofillRiskFingerprintTest : public content::ContentBrowserTest {
fingerprint->machine_characteristics();
EXPECT_TRUE(machine.has_operating_system_build());
EXPECT_TRUE(machine.has_browser_install_time_hours());
+
+#if BUILDFLAG(IS_FUCHSIA) || BUILDFLAG(IS_ANDROID)
+ // GetFontList() returns an empty list on Fuchsia and Android.
+ EXPECT_EQ(machine.font_size(), 0);
+#else
EXPECT_GT(machine.font_size(), 0);
+#endif // BUILDFLAG(IS_FUCHSIA) || BUILDFLAG(IS_ANDROID)
// TODO(isherman): http://crbug.com/358548 and EXPECT_EQ.
EXPECT_GE(machine.plugin_size(), 0);
diff --git a/chromium/components/autofill/content/common/mojom/autofill_agent.mojom b/chromium/components/autofill/content/common/mojom/autofill_agent.mojom
index 0a4e5ce6593..0e35c55bc15 100644
--- a/chromium/components/autofill/content/common/mojom/autofill_agent.mojom
+++ b/chromium/components/autofill/content/common/mojom/autofill_agent.mojom
@@ -115,8 +115,13 @@ interface PasswordAutofillAgent {
// Informs the renderer that the Touch To Fill sheet has been closed.
// Indicates whether the virtual keyboard should be shown instead.
+ [EnableIf=is_android]
TouchToFillClosed(bool show_virtual_keyboard);
+ // Triggers a form submission on the last interacted element.
+ [EnableIf=is_android]
+ TriggerFormSubmission();
+
// Annotate password related (username, password) DOM input elements with
// corresponding HTML attributes. It is used only for debugging.
AnnotateFieldsWithParsingResult(ParsingResult parsing_result);
diff --git a/chromium/components/autofill/content/renderer/autofill_agent.cc b/chromium/components/autofill/content/renderer/autofill_agent.cc
index 213847310bd..ddd2cf1543e 100644
--- a/chromium/components/autofill/content/renderer/autofill_agent.cc
+++ b/chromium/components/autofill/content/renderer/autofill_agent.cc
@@ -97,9 +97,9 @@ using GenerationShowing = PasswordAutofillAgent::GenerationShowing;
namespace {
-// Time to wait, in ms, o ensure that only a single select change will be acted
-// upon, instead of multiple in close succession (debounce time).
-size_t kWaitTimeForSelectOptionsChangesMs = 50;
+// Time to wait in ms to ensure that only a single select or datalist change
+// will be acted upon, instead of multiple in close succession (debounce time).
+size_t kWaitTimeForOptionsChangesMs = 50;
// Helper function to return EXTRACT_DATALIST if kAutofillExtractAllDatalist is
// enabled, otherwise EXTRACT_NONE is returned.
@@ -321,11 +321,11 @@ void AutofillAgent::FocusedElementChanged(const WebElement& element) {
return;
}
- const WebInputElement* input = ToWebInputElement(&element);
+ const WebInputElement input = element.DynamicTo<WebInputElement>();
bool focus_moved_to_new_form = false;
if (!last_interacted_form_.IsNull() &&
- (!input || last_interacted_form_ != input->Form())) {
+ (input.IsNull() || last_interacted_form_ != input.Form())) {
// The focused element is not part of the last interacted form (could be
// in a different form).
GetAutofillDriver().FocusNoLongerOnForm(/*had_interacted_form=*/true);
@@ -347,11 +347,11 @@ void AutofillAgent::FocusedElementChanged(const WebElement& element) {
if (focus_moved_to_new_form)
return;
- if (!input || !input->IsEnabled() || input->IsReadOnly() ||
- !input->IsTextField())
+ if (input.IsNull() || !input.IsEnabled() || input.IsReadOnly() ||
+ !input.IsTextField())
return;
- element_ = *input;
+ element_ = input;
FormData form;
FormFieldData field;
@@ -482,13 +482,36 @@ void AutofillAgent::OpenTextDataListChooser(const WebInputElement& element) {
ShowSuggestions(element, options);
}
+// Notifies the AutofillDriver about changes in the <datalist> options in
+// batches.
+//
+// A batch ends if no event occurred for `kWaitTimeForOptionsChangesMs`
+// milliseconds. For a given batch, the AutofillDriver is informed only about
+// the last field. That is, if within one batch the options of different
+// fields changed, all but one of these events will be lost.
void AutofillAgent::DataListOptionsChanged(const WebInputElement& element) {
DCHECK(IsOwnedByFrame(element, render_frame()));
- if (!is_popup_possibly_visible_ || !element.Focused())
+ if (element.GetDocument().IsNull() || !is_popup_possibly_visible_ ||
+ !element.Focused()) {
return;
+ }
+
+ if (datalist_option_change_batch_timer_.IsRunning())
+ datalist_option_change_batch_timer_.AbandonAndStop();
+
+ datalist_option_change_batch_timer_.Start(
+ FROM_HERE, base::Milliseconds(kWaitTimeForOptionsChangesMs),
+ base::BindRepeating(&AutofillAgent::BatchDataListOptionChange,
+ weak_ptr_factory_.GetWeakPtr(), element));
+}
- OnProvisionallySaveForm(WebFormElement(), element,
+void AutofillAgent::BatchDataListOptionChange(
+ const blink::WebFormControlElement& element) {
+ if (element.GetDocument().IsNull())
+ return;
+
+ OnProvisionallySaveForm(element.Form(), element,
ElementChangeSource::TEXTFIELD_CHANGED);
}
@@ -610,10 +633,10 @@ void AutofillAgent::FillFieldWithValue(FieldRendererId field_id,
return;
}
- WebInputElement* input_element = ToWebInputElement(&element_);
- if (input_element) {
- DoFillFieldWithValue(value, *input_element);
- input_element->SetAutofillState(WebAutofillState::kAutofilled);
+ WebInputElement input_element = element_.DynamicTo<WebInputElement>();
+ if (!input_element.IsNull()) {
+ DoFillFieldWithValue(value, input_element);
+ input_element.SetAutofillState(WebAutofillState::kAutofilled);
}
}
@@ -624,9 +647,9 @@ void AutofillAgent::PreviewFieldWithValue(FieldRendererId field_id,
return;
}
- WebInputElement* input_element = ToWebInputElement(&element_);
- if (input_element)
- DoPreviewFieldWithValue(value, *input_element);
+ WebInputElement input_element = element_.DynamicTo<WebInputElement>();
+ if (!input_element.IsNull())
+ DoPreviewFieldWithValue(value, input_element);
}
void AutofillAgent::SetSuggestionAvailability(
@@ -637,21 +660,21 @@ void AutofillAgent::SetSuggestionAvailability(
return;
}
- WebInputElement* input_element = ToWebInputElement(&element_);
- if (input_element) {
+ WebInputElement input_element = element_.DynamicTo<WebInputElement>();
+ if (!input_element.IsNull()) {
switch (state) {
case autofill::mojom::AutofillState::kAutofillAvailable:
- WebAXObject::FromWebNode(*input_element)
+ WebAXObject::FromWebNode(input_element)
.HandleAutofillStateChanged(
blink::WebAXAutofillState::kAutofillAvailable);
return;
case autofill::mojom::AutofillState::kAutocompleteAvailable:
- WebAXObject::FromWebNode(*input_element)
+ WebAXObject::FromWebNode(input_element)
.HandleAutofillStateChanged(
blink::WebAXAutofillState::kAutocompleteAvailable);
return;
case autofill::mojom::AutofillState::kNoSuggestions:
- WebAXObject::FromWebNode(*input_element)
+ WebAXObject::FromWebNode(input_element)
.HandleAutofillStateChanged(
blink::WebAXAutofillState::kNoSuggestions);
return;
@@ -668,8 +691,8 @@ void AutofillAgent::AcceptDataListSuggestion(
return;
}
- WebInputElement* input_element = ToWebInputElement(&element_);
- if (!input_element) {
+ WebInputElement input_element = element_.DynamicTo<WebInputElement>();
+ if (input_element.IsNull()) {
// For reasons not understood yet, this is triggered on elements which are
// not input elements.
@@ -683,8 +706,8 @@ void AutofillAgent::AcceptDataListSuggestion(
std::u16string new_value = suggested_value;
// If this element takes multiple values then replace the last part with
// the suggestion.
- if (input_element->IsMultiple() && input_element->IsEmailField()) {
- std::u16string value = input_element->EditingValue().Utf16();
+ if (input_element.IsMultiple() && input_element.IsEmailField()) {
+ std::u16string value = input_element.EditingValue().Utf16();
std::vector<base::StringPiece16> parts = base::SplitStringPiece(
value, u",", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
if (parts.size() == 0)
@@ -703,7 +726,7 @@ void AutofillAgent::AcceptDataListSuggestion(
new_value = base::JoinString(parts, u",");
}
- DoFillFieldWithValue(new_value, *input_element);
+ DoFillFieldWithValue(new_value, input_element);
}
void AutofillAgent::FillPasswordSuggestion(const std::u16string& username,
@@ -761,15 +784,15 @@ void AutofillAgent::ShowSuggestions(const WebFormControlElement& element,
if (!element.SuggestedValue().IsEmpty())
return;
- const WebInputElement* input_element = ToWebInputElement(&element);
- if (input_element) {
- if (!input_element->IsTextField())
+ const WebInputElement input_element = element.DynamicTo<WebInputElement>();
+ if (!input_element.IsNull()) {
+ if (!input_element.IsTextField())
return;
- if (!input_element->SuggestedValue().IsEmpty())
+ if (!input_element.SuggestedValue().IsEmpty())
return;
} else {
DCHECK(form_util::IsTextAreaElement(element));
- if (!element.ToConst<WebFormControlElement>().SuggestedValue().IsEmpty())
+ if (!element.To<WebFormControlElement>().SuggestedValue().IsEmpty())
return;
}
@@ -789,7 +812,7 @@ void AutofillAgent::ShowSuggestions(const WebFormControlElement& element,
element_ = element;
if (form_util::IsAutofillableInputElement(input_element) &&
password_autofill_agent_->ShowSuggestions(
- *input_element, ShowAll(options.show_full_suggestion_list),
+ input_element, ShowAll(options.show_full_suggestion_list),
GenerationShowing(is_generation_popup_possibly_visible_))) {
is_popup_possibly_visible_ = true;
return;
@@ -806,8 +829,8 @@ void AutofillAgent::ShowSuggestions(const WebFormControlElement& element,
// match a regex). In this specific case we are actually interested in whether
// the field is currently a password field, not whether it has ever been a
// password field.
- if (input_element &&
- input_element->IsPasswordField /*disable presubmit*/ () &&
+ if (!input_element.IsNull() &&
+ input_element.IsPasswordField /*disable presubmit*/ () &&
!query_password_suggestion_) {
return;
}
@@ -884,7 +907,8 @@ void AutofillAgent::QueryAutofillSuggestions(
if (!frame)
return;
- DCHECK(ToWebInputElement(&element) || form_util::IsTextAreaElement(element));
+ DCHECK(!element.DynamicTo<WebInputElement>().IsNull() ||
+ form_util::IsTextAreaElement(element));
static int query_counter = 0;
autofill_query_id_ = query_counter++;
@@ -914,9 +938,10 @@ void AutofillAgent::QueryAutofillSuggestions(
}
if (!base::FeatureList::IsEnabled(features::kAutofillExtractAllDatalists)) {
- if (const WebInputElement* input_element = ToWebInputElement(&element)) {
+ const WebInputElement input_element = element.DynamicTo<WebInputElement>();
+ if (!input_element.IsNull()) {
// Find the datalist values and send them to the browser process.
- form_util::GetDataListSuggestions(*input_element, &field.datalist_values,
+ form_util::GetDataListSuggestions(input_element, &field.datalist_values,
&field.datalist_labels);
}
}
@@ -1032,25 +1057,44 @@ void AutofillAgent::SelectControlDidChange(
form_tracker_.SelectControlDidChange(element);
}
+// Notifies the AutofillDriver about changes in the <select> options in batches.
+//
+// A batch ends if no event occurred for `kWaitTimeForOptionsChangesMs`
+// milliseconds. For a given batch, the AutofillDriver is informed only about
+// the last FormData. That is, if within one batch the options of different
+// forms changed, all but one of these events will be lost.
void AutofillAgent::SelectFieldOptionsChanged(
const blink::WebFormControlElement& element) {
+ DCHECK(IsOwnedByFrame(element, render_frame()));
+
if (!was_last_action_fill_ || element_.IsNull())
return;
- // Since a change of a select options often come in batches, use a timer
- // to wait for other changes. Stop the timer if it was already running. It
- // will be started again for this change.
- if (on_select_update_timer_.IsRunning())
- on_select_update_timer_.AbandonAndStop();
-
- // Start the timer to notify the driver that the select field was updated
- // after the options have finished changing,
- on_select_update_timer_.Start(
- FROM_HERE, base::Milliseconds(kWaitTimeForSelectOptionsChangesMs),
- base::BindRepeating(&AutofillAgent::SelectWasUpdated,
+ if (select_option_change_batch_timer_.IsRunning())
+ select_option_change_batch_timer_.AbandonAndStop();
+
+ select_option_change_batch_timer_.Start(
+ FROM_HERE, base::Milliseconds(kWaitTimeForOptionsChangesMs),
+ base::BindRepeating(&AutofillAgent::BatchSelectOptionChange,
weak_ptr_factory_.GetWeakPtr(), element));
}
+void AutofillAgent::BatchSelectOptionChange(
+ const blink::WebFormControlElement& element) {
+ if (element.GetDocument().IsNull())
+ return;
+
+ // Look for the form and field associated with the select element. If they are
+ // found, notify the driver that the form was modified dynamically.
+ FormData form;
+ FormFieldData field;
+ if (FindFormAndFieldForFormControlElement(element, field_data_manager_.get(),
+ &form, &field) &&
+ !field.options.empty()) {
+ GetAutofillDriver().SelectFieldOptionsDidChange(form);
+ }
+}
+
bool AutofillAgent::ShouldSuppressKeyboard(
const WebFormControlElement& element) {
// Note: Consider supporting other autofill types in the future as well.
@@ -1071,19 +1115,6 @@ void AutofillAgent::PasswordFieldReset(const WebInputElement& element) {
password_autofill_agent_->InformAboutFieldClearing(element);
}
-void AutofillAgent::SelectWasUpdated(
- const blink::WebFormControlElement& element) {
- // Look for the form and field associated with the select element. If they are
- // found, notify the driver that the the form was modified dynamically.
- FormData form;
- FormFieldData field;
- if (FindFormAndFieldForFormControlElement(element, field_data_manager_.get(),
- &form, &field) &&
- !field.options.empty()) {
- GetAutofillDriver().SelectFieldOptionsDidChange(form);
- }
-}
-
bool AutofillAgent::IsPrerendering() const {
return blink::features::IsPrerender2Enabled() &&
render_frame()->GetWebFrame()->GetDocument().IsPrerendering();
@@ -1095,8 +1126,8 @@ void AutofillAgent::FormControlElementClicked(
FieldRendererId(element.UniqueRendererFormControlId());
was_last_action_fill_ = false;
- const WebInputElement* input_element = ToWebInputElement(&element);
- if (!input_element && !form_util::IsTextAreaElement(element))
+ const WebInputElement input_element = element.DynamicTo<WebInputElement>();
+ if (input_element.IsNull() && !form_util::IsTextAreaElement(element))
return;
#if defined(ANDROID)
@@ -1126,9 +1157,9 @@ void AutofillAgent::HandleFocusChangeComplete() {
// to ensure focus is on a field where text can be entered.
if ((focused_node_was_last_clicked_ || is_screen_reader_enabled_) &&
!focused_element.IsNull() && focused_element.IsFormControlElement() &&
- (form_util::IsTextInput(blink::ToWebInputElement(&focused_element)) ||
+ (form_util::IsTextInput(focused_element.DynamicTo<WebInputElement>()) ||
focused_element.HasHTMLTagName("textarea"))) {
- FormControlElementClicked(focused_element.ToConst<WebFormControlElement>());
+ FormControlElementClicked(focused_element.To<WebFormControlElement>());
}
focused_node_was_last_clicked_ = false;
@@ -1184,7 +1215,7 @@ void AutofillAgent::OnProvisionallySaveForm(
}
if (source == ElementChangeSource::TEXTFIELD_CHANGED) {
- OnTextFieldDidChange(*ToWebInputElement(&element));
+ OnTextFieldDidChange(element.To<WebInputElement>());
} else {
FormData form_data;
FormFieldData field;
@@ -1275,9 +1306,7 @@ absl::optional<FormData> AutofillAgent::GetSubmittedForm() const {
} else if (provisionally_saved_form_.has_value()) {
return absl::make_optional(provisionally_saved_form_.value());
}
- } else if ((base::FeatureList::IsEnabled(
- features::kAutofillRecordMetricsOfUnownedForms) &&
- formless_elements_were_autofilled_) ||
+ } else if (formless_elements_were_autofilled_ ||
(formless_elements_user_edited_.size() != 0 &&
!form_util::IsSomeControlElementVisible(
render_frame()->GetWebFrame(),
diff --git a/chromium/components/autofill/content/renderer/autofill_agent.h b/chromium/components/autofill/content/renderer/autofill_agent.h
index dbf991293cc..5fb4867be2c 100644
--- a/chromium/components/autofill/content/renderer/autofill_agent.h
+++ b/chromium/components/autofill/content/renderer/autofill_agent.h
@@ -149,8 +149,6 @@ class AutofillAgent : public content::RenderFrameObserver,
return is_heavy_form_data_scraping_enabled_;
}
- void SelectWasUpdated(const blink::WebFormControlElement& element);
-
bool IsPrerendering() const;
protected:
@@ -307,6 +305,12 @@ class AutofillAgent : public content::RenderFrameObserver,
// label, visibility, control type) have changed after an autofill.
void TriggerRefillIfNeeded(const FormData& form);
+ // Helpers for SelectFieldOptionsChanged() and DataListOptionsChanged(), which
+ // get called after a timer that is restarted when another event of the same
+ // type started.
+ void BatchSelectOptionChange(const blink::WebFormControlElement& element);
+ void BatchDataListOptionChange(const blink::WebFormControlElement& element);
+
// Formerly cached forms for all frames, now only caches forms for the current
// frame.
FormCache form_cache_;
@@ -391,7 +395,8 @@ class AutofillAgent : public content::RenderFrameObserver,
bool was_last_action_fill_ = false;
// Timers for throttling handling of frequent events.
- base::OneShotTimer on_select_update_timer_;
+ base::OneShotTimer select_option_change_batch_timer_;
+ base::OneShotTimer datalist_option_change_batch_timer_;
base::OneShotTimer reparse_timer_;
// Will be set when accessibility mode changes, depending on what the new mode
diff --git a/chromium/components/autofill/content/renderer/focus_test_utils.cc b/chromium/components/autofill/content/renderer/focus_test_utils.cc
index 04a4dbb3a83..3f77d6b06c3 100644
--- a/chromium/components/autofill/content/renderer/focus_test_utils.cc
+++ b/chromium/components/autofill/content/renderer/focus_test_utils.cc
@@ -43,10 +43,11 @@ std::string FocusTestUtils::GetFocusLog(const blink::WebDocument& document) {
document.GetElementById(blink::WebString::FromUTF8("event_log"));
if (element.IsNull())
return "event_log_element_id not found";
- blink::WebInputElement* input_element = blink::ToWebInputElement(&element);
- if (!input_element)
+ blink::WebInputElement input_element =
+ element.DynamicTo<blink::WebInputElement>();
+ if (input_element.IsNull())
return "event_log_element_id does not point to input element";
- return input_element->Value().Utf8();
+ return input_element.Value().Utf8();
}
} // namespace test
diff --git a/chromium/components/autofill/content/renderer/form_autofill_util.cc b/chromium/components/autofill/content/renderer/form_autofill_util.cc
index 5860aafe919..49910e0ad75 100644
--- a/chromium/components/autofill/content/renderer/form_autofill_util.cc
+++ b/chromium/components/autofill/content/renderer/form_autofill_util.cc
@@ -144,7 +144,7 @@ bool IsNoScriptElement(const WebElement& element) {
}
bool HasTagName(const WebNode& node, const blink::WebString& tag) {
- return node.IsElementNode() && node.ToConst<WebElement>().HasHTMLTagName(tag);
+ return node.IsElementNode() && node.To<WebElement>().HasHTMLTagName(tag);
}
bool IsElementInControlElementSet(
@@ -153,7 +153,7 @@ bool IsElementInControlElementSet(
if (!element.IsFormControlElement())
return false;
const WebFormControlElement form_control_element =
- element.ToConst<WebFormControlElement>();
+ element.To<WebFormControlElement>();
return base::Contains(control_elements, form_control_element);
}
@@ -179,7 +179,7 @@ bool IsTraversableContainerElement(const WebNode& node) {
if (!node.IsElementNode())
return false;
- const WebElement element = node.ToConst<WebElement>();
+ const WebElement element = node.To<WebElement>();
return element.HasHTMLTagName("dd") || element.HasHTMLTagName("div") ||
element.HasHTMLTagName("fieldset") || element.HasHTMLTagName("li") ||
element.HasHTMLTagName("td") || element.HasHTMLTagName("table");
@@ -254,11 +254,11 @@ std::u16string FindChildTextInner(const WebNode& node,
// Ignore elements known not to contain inferable labels.
if (node.IsElementNode()) {
- const WebElement element = node.ToConst<WebElement>();
+ const WebElement element = node.To<WebElement>();
if (IsOptionElement(element) || IsScriptElement(element) ||
IsNoScriptElement(element) ||
(element.IsFormControlElement() &&
- IsAutofillableElement(element.ToConst<WebFormControlElement>()))) {
+ IsAutofillableElement(element.To<WebFormControlElement>()))) {
return std::u16string();
}
@@ -809,7 +809,7 @@ std::vector<std::string> AncestorTagNames(
bool InferLabelForElement(const WebFormControlElement& element,
std::u16string* label,
FormFieldData::LabelSource* label_source) {
- if (IsCheckableElement(ToWebInputElement(&element))) {
+ if (IsCheckableElement(element.DynamicTo<WebInputElement>())) {
if (InferLabelFromNext(element, label, label_source))
return true;
}
@@ -932,8 +932,7 @@ ButtonTitleList InferButtonTitlesForForm(const WebElement& root_element) {
!item.IsNull() && total_length < kMaxLengthForAllButtonTitles;
item = input_elements.NextItem()) {
DCHECK(item.IsFormControlElement());
- WebFormControlElement control_element =
- item.ToConst<WebFormControlElement>();
+ WebFormControlElement control_element = item.To<WebFormControlElement>();
if (only_formless_elements && !control_element.Form().IsNull())
continue;
bool is_submit_input =
@@ -1003,7 +1002,7 @@ void GetOptionStringsFromElement(const WebSelectElement& select_element,
options->reserve(list_items.size());
for (const auto& list_item : list_items) {
if (IsOptionElement(list_item)) {
- const WebOptionElement option = list_item.ToConst<WebOptionElement>();
+ const WebOptionElement option = list_item.To<WebOptionElement>();
options->push_back({.value = option.Value().Utf16(),
.content = option.GetText().Utf16()});
}
@@ -1109,7 +1108,7 @@ std::vector<WebFormControlElement> ForEachMatchingFormFieldCommon(
// Only autofill empty fields (or those with the field's default value
// attribute) and the field that initiated the filling, i.e. the field the
// user is currently editing and interacting with.
- const WebInputElement* input_element = ToWebInputElement(&element);
+ const WebInputElement input_element = element.DynamicTo<WebInputElement>();
static base::NoDestructor<WebString> kValue("value");
static base::NoDestructor<WebString> kPlaceholder("placeholder");
@@ -1250,16 +1249,16 @@ void FillFormField(const FormFieldData& data,
if (!data.is_autofilled)
return;
- WebInputElement* input_element = ToWebInputElement(field);
+ WebInputElement input_element = field->DynamicTo<WebInputElement>();
if (IsCheckableElement(input_element)) {
- input_element->SetChecked(IsChecked(data.check_status), true);
+ input_element.SetChecked(IsChecked(data.check_status), true);
} else {
std::u16string value = data.value;
if (IsTextInput(input_element) || IsMonthInput(input_element)) {
// If the maxlength attribute contains a negative value, maxLength()
// returns the default maxlength value.
- TruncateString(&value, input_element->MaxLength());
+ TruncateString(&value, input_element.MaxLength());
}
field->SetAutofillValue(blink::WebString::FromUTF16(value));
}
@@ -1295,13 +1294,13 @@ void PreviewFormField(const FormFieldData& data,
// Preview input, textarea and select fields. For input fields, excludes
// checkboxes and radio buttons, as there is no provision for
// setSuggestedCheckedValue in WebInputElement.
- WebInputElement* input_element = ToWebInputElement(field);
+ WebInputElement input_element = field->DynamicTo<WebInputElement>();
if (IsTextInput(input_element) || IsMonthInput(input_element)) {
// If the maxlength attribute contains a negative value, maxLength()
// returns the default maxlength value.
- input_element->SetSuggestedValue(blink::WebString::FromUTF16(
- data.value.substr(0, input_element->MaxLength())));
- input_element->SetAutofillState(WebAutofillState::kPreviewed);
+ input_element.SetSuggestedValue(blink::WebString::FromUTF16(
+ data.value.substr(0, input_element.MaxLength())));
+ input_element.SetAutofillState(WebAutofillState::kPreviewed);
} else if (IsTextAreaElement(*field) || IsSelectElement(*field)) {
field->SetSuggestedValue(blink::WebString::FromUTF16(data.value));
field->SetAutofillState(WebAutofillState::kPreviewed);
@@ -1830,45 +1829,39 @@ GURL GetDocumentUrlWithoutAuth(const WebDocument& document) {
return full_origin.ReplaceComponents(rep);
}
-bool IsMonthInput(const WebInputElement* element) {
- static base::NoDestructor<WebString> kMonth("month");
- return element && !element->IsNull() &&
- element->FormControlTypeForAutofill() == *kMonth;
+bool IsMonthInput(const WebInputElement& element) {
+ return !element.IsNull() && element.FormControlTypeForAutofill() == "month";
}
// All text fields, including password fields, should be extracted.
-bool IsTextInput(const WebInputElement* element) {
- return element && !element->IsNull() && element->IsTextField();
+bool IsTextInput(const WebInputElement& element) {
+ return !element.IsNull() && element.IsTextField();
}
bool IsSelectElement(const WebFormControlElement& element) {
- // Static for improved performance.
- static base::NoDestructor<WebString> kSelectOne("select-one");
return !element.IsNull() &&
- element.FormControlTypeForAutofill() == *kSelectOne;
+ element.FormControlTypeForAutofill() == "select-one";
}
bool IsTextAreaElement(const WebFormControlElement& element) {
- // Static for improved performance.
- static base::NoDestructor<WebString> kTextArea("textarea");
return !element.IsNull() &&
- element.FormControlTypeForAutofill() == *kTextArea;
+ element.FormControlTypeForAutofill() == "textarea";
}
-bool IsCheckableElement(const WebInputElement* element) {
- if (!element || element->IsNull())
+bool IsCheckableElement(const WebInputElement& element) {
+ if (element.IsNull())
return false;
- return element->IsCheckbox() || element->IsRadioButton();
+ return element.IsCheckbox() || element.IsRadioButton();
}
-bool IsAutofillableInputElement(const WebInputElement* element) {
+bool IsAutofillableInputElement(const WebInputElement& element) {
return IsTextInput(element) || IsMonthInput(element) ||
IsCheckableElement(element);
}
bool IsAutofillableElement(const WebFormControlElement& element) {
- const WebInputElement* input_element = ToWebInputElement(&element);
+ const WebInputElement input_element = element.DynamicTo<WebInputElement>();
return IsAutofillableInputElement(input_element) ||
IsSelectElement(element) || IsTextAreaElement(element);
}
@@ -2006,7 +1999,7 @@ void WebFormControlElementToFormField(
if (!IsAutofillableElement(element))
return;
- const WebInputElement* input_element = ToWebInputElement(&element);
+ const WebInputElement input_element = element.DynamicTo<WebInputElement>();
if (IsAutofillableInputElement(input_element) || IsTextAreaElement(element) ||
IsSelectElement(element)) {
// The browser doesn't need to differentiate between preview and autofill.
@@ -2021,16 +2014,16 @@ void WebFormControlElementToFormField(
if (IsAutofillableInputElement(input_element)) {
if (IsTextInput(input_element))
- field->max_length = input_element->MaxLength();
+ field->max_length = input_element.MaxLength();
SetCheckStatus(field, IsCheckableElement(input_element),
- input_element->IsChecked());
+ input_element.IsChecked());
} else if (IsTextAreaElement(element)) {
// Nothing more to do in this case.
} else if (extract_mask & EXTRACT_OPTIONS) {
// Set option strings on the field if available.
DCHECK(IsSelectElement(element));
- const WebSelectElement select_element = element.ToConst<WebSelectElement>();
+ const WebSelectElement select_element = element.To<WebSelectElement>();
GetOptionStringsFromElement(select_element, &field->options);
}
if (extract_mask & EXTRACT_BOUNDS) {
@@ -2042,8 +2035,9 @@ void WebFormControlElementToFormField(
}
}
if (extract_mask & EXTRACT_DATALIST) {
- if (auto* input = blink::ToWebInputElement(&element)) {
- GetDataListSuggestions(*input, &field->datalist_values,
+ if (WebInputElement input = element.DynamicTo<WebInputElement>();
+ !input.IsNull()) {
+ GetDataListSuggestions(input, &field->datalist_values,
&field->datalist_labels);
}
}
@@ -2054,13 +2048,13 @@ void WebFormControlElementToFormField(
std::u16string value = element.Value().Utf16();
if (IsSelectElement(element) && (extract_mask & EXTRACT_OPTION_TEXT)) {
- const WebSelectElement select_element = element.ToConst<WebSelectElement>();
+ const WebSelectElement select_element = element.To<WebSelectElement>();
// Convert the |select_element| value to text if requested.
WebVector<WebElement> list_items = select_element.GetListItems();
for (const auto& list_item : list_items) {
if (IsOptionElement(list_item)) {
const WebOptionElement option_element =
- list_item.ToConst<WebOptionElement>();
+ list_item.To<WebOptionElement>();
if (option_element.Value().Utf16() == value) {
value = option_element.GetText().Utf16();
break;
@@ -2328,7 +2322,8 @@ void ClearPreviewedElements(
// Clear the suggested value. For the initiating node, also restore the
// original value.
- WebInputElement* input_element = ToWebInputElement(&control_element);
+ WebInputElement input_element =
+ control_element.DynamicTo<WebInputElement>();
if (IsTextInput(input_element) || IsMonthInput(input_element) ||
IsTextAreaElement(control_element)) {
control_element.SetSuggestedValue(WebString());
@@ -2421,12 +2416,7 @@ ButtonTitleList GetButtonTitles(const WebFormElement& web_form,
return ButtonTitleList();
}
- // True if the cache has no entry for |web_form|.
- bool cache_miss = true;
- // Iterator pointing to the entry for |web_form| if the entry for |web_form|
- // is found.
- ButtonTitlesCache::iterator form_position;
- std::tie(form_position, cache_miss) = button_titles_cache->emplace(
+ auto [form_position, cache_miss] = button_titles_cache->emplace(
GetFormRendererId(web_form), ButtonTitleList());
if (!cache_miss)
return form_position->second;
diff --git a/chromium/components/autofill/content/renderer/form_autofill_util.h b/chromium/components/autofill/content/renderer/form_autofill_util.h
index 8a9bb28c262..19b97e12368 100644
--- a/chromium/components/autofill/content/renderer/form_autofill_util.h
+++ b/chromium/components/autofill/content/renderer/form_autofill_util.h
@@ -146,10 +146,10 @@ GURL GetCanonicalActionForForm(const blink::WebFormElement& form);
GURL GetDocumentUrlWithoutAuth(const blink::WebDocument& document);
// Returns true if |element| is a month input element.
-bool IsMonthInput(const blink::WebInputElement* element);
+bool IsMonthInput(const blink::WebInputElement& element);
// Returns true if |element| is a text input element.
-bool IsTextInput(const blink::WebInputElement* element);
+bool IsTextInput(const blink::WebInputElement& element);
// Returns true if |element| is a select element.
bool IsSelectElement(const blink::WebFormControlElement& element);
@@ -158,11 +158,11 @@ bool IsSelectElement(const blink::WebFormControlElement& element);
bool IsTextAreaElement(const blink::WebFormControlElement& element);
// Returns true if |element| is a checkbox or a radio button element.
-bool IsCheckableElement(const blink::WebInputElement* element);
+bool IsCheckableElement(const blink::WebInputElement& element);
// Returns true if |element| is one of the input element types that can be
// autofilled. {Text, Radiobutton, Checkbox}.
-bool IsAutofillableInputElement(const blink::WebInputElement* element);
+bool IsAutofillableInputElement(const blink::WebInputElement& element);
// Returns true if |element| is one of the element types that can be autofilled.
// {Text, Radiobutton, Checkbox, Select, TextArea}.
diff --git a/chromium/components/autofill/content/renderer/form_autofill_util_browsertest.cc b/chromium/components/autofill/content/renderer/form_autofill_util_browsertest.cc
index 753cda9ffb8..9ec880b3273 100644
--- a/chromium/components/autofill/content/renderer/form_autofill_util_browsertest.cc
+++ b/chromium/components/autofill/content/renderer/form_autofill_util_browsertest.cc
@@ -13,6 +13,7 @@
#include "base/test/scoped_feature_list.h"
#include "components/autofill/content/renderer/test_utils.h"
#include "components/autofill/core/common/autofill_features.h"
+#include "components/autofill/core/common/field_data_manager.h"
#include "components/autofill/core/common/mojom/autofill_types.mojom-shared.h"
#include "components/autofill/core/common/unique_ids.h"
#include "content/public/renderer/render_frame.h"
@@ -1538,6 +1539,61 @@ TEST_F(FormAutofillUtilsTestWithIframesEnabled,
}
}
+// Fills a form, resets the form using <input type=reset>, and fills it again.
+// Tests that the form is actually filled on the second fill
+// (crbug.com/1291619).
+TEST_F(FormAutofillUtilsTest, FillAndResetAndFillAgainForm) {
+ LoadHTML(R"(
+ <body>
+ <form id="f">
+ <input id="f0">
+ <select id="f1">
+ <option value="Bar">Bar</option>
+ <option value="Foo">Foo</option>
+ <option value="Zoo">Zoo</option>
+ </select>
+ <input id="reset" type="reset">
+ </form>
+ </body>
+ )");
+ WebDocument doc = GetMainFrame()->GetDocument();
+ auto field_manager = base::MakeRefCounted<FieldDataManager>();
+
+ FormData form;
+ ExtractFormData(GetFormElementById(doc, "f"), *field_manager, &form);
+ ASSERT_EQ(form.fields.size(), 2u);
+ form.fields[0].value = u"Foo";
+ form.fields[1].value = u"Foo";
+ form.fields[0].is_autofilled = true;
+ form.fields[1].is_autofilled = true;
+
+ // First fill of the form.
+ FillOrPreviewForm(form, GetFormControlElementById(doc, "f0"),
+ mojom::RendererFormDataAction::kFill);
+ // Autofilling f0 leaves f0.UserHasEditedTheField() == false.
+ // TODO(crbug.com/1291619): Is this desired?
+ EXPECT_TRUE(GetFormControlElementById(doc, "f1").UserHasEditedTheField());
+ EXPECT_EQ(GetFormControlElementById(doc, "f0").Value().Ascii(), "Foo");
+ EXPECT_EQ(GetFormControlElementById(doc, "f1").Value().Ascii(), "Foo");
+
+ // Click reset button.
+ GetFormControlElementById(doc, "reset").SimulateClick();
+ content::RunAllTasksUntilIdle();
+ EXPECT_FALSE(GetFormControlElementById(doc, "f0").UserHasEditedTheField());
+ EXPECT_FALSE(GetFormControlElementById(doc, "f1").UserHasEditedTheField());
+ EXPECT_EQ(GetFormControlElementById(doc, "f0").Value().Ascii(), "");
+ EXPECT_EQ(GetFormControlElementById(doc, "f1").Value().Ascii(), "Bar");
+
+ // Fill form again.
+ FillOrPreviewForm(form, GetFormControlElementById(doc, "f0"),
+ mojom::RendererFormDataAction::kFill);
+ // Autofilling f0 leaves f0.UserHasEditedTheField() == false.
+ // TODO(crbug.com/1291619): Is this desired?
+ EXPECT_TRUE(GetFormControlElementById(doc, "f1").UserHasEditedTheField());
+ EXPECT_EQ(GetFormControlElementById(doc, "f0").Value().Ascii(), "Foo");
+ EXPECT_EQ(GetFormControlElementById(doc, "f1").Value().Ascii(), "Foo");
+}
+
} // namespace
} // namespace form_util
} // namespace autofill
diff --git a/chromium/components/autofill/content/renderer/form_cache.cc b/chromium/components/autofill/content/renderer/form_cache.cc
index 775509e68d3..1126220117a 100644
--- a/chromium/components/autofill/content/renderer/form_cache.cc
+++ b/chromium/components/autofill/content/renderer/form_cache.cc
@@ -403,16 +403,17 @@ void FormCache::ClearElement(WebFormControlElement& control_element,
control_element.SetAutofillState(WebAutofillState::kNotFilled);
- WebInputElement* web_input_element = ToWebInputElement(&control_element);
+ WebInputElement web_input_element =
+ control_element.DynamicTo<WebInputElement>();
if (form_util::IsTextInput(web_input_element) ||
form_util::IsMonthInput(web_input_element)) {
- web_input_element->SetAutofillValue(blink::WebString());
+ web_input_element.SetAutofillValue(blink::WebString());
// Clearing the value in the focused node (above) can cause the selection
// to be lost. We force the selection range to restore the text cursor.
- if (element == *web_input_element) {
- size_t length = web_input_element->Value().length();
- web_input_element->SetSelectionRange(length, length);
+ if (element == web_input_element) {
+ size_t length = web_input_element.Value().length();
+ web_input_element.SetSelectionRange(length, length);
}
} else if (form_util::IsTextAreaElement(control_element)) {
control_element.SetAutofillValue(blink::WebString());
@@ -428,7 +429,7 @@ void FormCache::ClearElement(WebFormControlElement& control_element,
}
} else {
WebInputElement input_element = control_element.To<WebInputElement>();
- DCHECK(form_util::IsCheckableElement(&input_element));
+ DCHECK(form_util::IsCheckableElement(input_element));
auto checkable_element_it = initial_checked_state_.find(
FieldRendererId(input_element.UniqueRendererFormControlId()));
if (checkable_element_it != initial_checked_state_.end() &&
@@ -605,8 +606,8 @@ size_t FormCache::ScanFormControlElements(
form_util::IsTextAreaElement(element)) {
++num_editable_elements;
} else {
- const WebInputElement input_element = element.ToConst<WebInputElement>();
- if (!form_util::IsCheckableElement(&input_element))
+ const WebInputElement input_element = element.To<WebInputElement>();
+ if (!form_util::IsCheckableElement(input_element))
++num_editable_elements;
}
}
@@ -617,17 +618,17 @@ void FormCache::SaveInitialValues(
const std::vector<WebFormControlElement>& control_elements) {
for (const WebFormControlElement& element : control_elements) {
if (form_util::IsSelectElement(element)) {
- const WebSelectElement select_element =
- element.ToConst<WebSelectElement>();
+ const WebSelectElement select_element = element.To<WebSelectElement>();
initial_select_values_.insert(
- std::make_pair(select_element.UniqueRendererFormControlId(),
- select_element.Value().Utf16()));
+ {FieldRendererId(select_element.UniqueRendererFormControlId()),
+ select_element.Value().Utf16()});
} else {
- const WebInputElement* input_element = ToWebInputElement(&element);
+ const WebInputElement input_element =
+ element.DynamicTo<WebInputElement>();
if (form_util::IsCheckableElement(input_element)) {
initial_checked_state_.insert(
- std::make_pair(input_element->UniqueRendererFormControlId(),
- input_element->IsChecked()));
+ {FieldRendererId(input_element.UniqueRendererFormControlId()),
+ input_element.IsChecked()});
}
}
}
diff --git a/chromium/components/autofill/content/renderer/form_cache_browsertest.cc b/chromium/components/autofill/content/renderer/form_cache_browsertest.cc
index 4b67f0a648c..7601dbc35e7 100644
--- a/chromium/components/autofill/content/renderer/form_cache_browsertest.cc
+++ b/chromium/components/autofill/content/renderer/form_cache_browsertest.cc
@@ -6,6 +6,7 @@
#include "base/ranges/algorithm.h"
#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
#include "components/autofill/content/renderer/focus_test_utils.h"
#include "components/autofill/content/renderer/form_autofill_util.h"
#include "components/autofill/content/renderer/form_cache.h"
@@ -771,7 +772,13 @@ TEST_P(FormCacheIframeBrowserTest, FrameLimit) {
// - the forms [kMaxParseableChildFrames, kMaxParseableFields) should have
// empty FormData::child_frames,
// - the forms [kMaxParseableFields, end) should be skipped.
-TEST_P(FormCacheIframeBrowserTest, FieldAndFrameLimit) {
+// TODO(https://crbug.com/1287782): Flaky on android.
+#if BUILDFLAG(IS_ANDROID)
+#define MAYBE_FieldAndFrameLimit DISABLED_FieldAndFrameLimit
+#else
+#define MAYBE_FieldAndFrameLimit FieldAndFrameLimit
+#endif
+TEST_P(FormCacheIframeBrowserTest, MAYBE_FieldAndFrameLimit) {
ASSERT_LE(kMaxParseableChildFrames, kMaxParseableFields);
std::string html;
diff --git a/chromium/components/autofill/content/renderer/form_cache_test_api.h b/chromium/components/autofill/content/renderer/form_cache_test_api.h
index 1bff306fa7e..9889921d019 100644
--- a/chromium/components/autofill/content/renderer/form_cache_test_api.h
+++ b/chromium/components/autofill/content/renderer/form_cache_test_api.h
@@ -7,6 +7,7 @@
#include <stddef.h>
+#include "base/containers/contains.h"
#include "components/autofill/content/renderer/form_cache.h"
#include "third_party/blink/public/web/web_form_control_element.h"
diff --git a/chromium/components/autofill/content/renderer/form_tracker.cc b/chromium/components/autofill/content/renderer/form_tracker.cc
index 6a4ed038e8b..334a1690a42 100644
--- a/chromium/components/autofill/content/renderer/form_tracker.cc
+++ b/chromium/components/autofill/content/renderer/form_tracker.cc
@@ -53,7 +53,8 @@ void FormTracker::AjaxSucceeded() {
void FormTracker::TextFieldDidChange(const WebFormControlElement& element) {
DCHECK_CALLED_ON_VALID_SEQUENCE(form_tracker_sequence_checker_);
- DCHECK(ToWebInputElement(&element) || form_util::IsTextAreaElement(element));
+ DCHECK(!element.DynamicTo<WebInputElement>().IsNull() ||
+ form_util::IsTextAreaElement(element));
if (ignore_control_changes_)
return;
@@ -63,8 +64,8 @@ void FormTracker::TextFieldDidChange(const WebFormControlElement& element) {
if (!element.Focused())
return;
- const WebInputElement* input_element = ToWebInputElement(&element);
- if (!input_element)
+ const WebInputElement input_element = element.DynamicTo<WebInputElement>();
+ if (input_element.IsNull())
return;
// Disregard text changes that aren't caused by user gestures or pastes. Note
diff --git a/chromium/components/autofill/content/renderer/html_based_username_detector.cc b/chromium/components/autofill/content/renderer/html_based_username_detector.cc
index 8942575fc77..33ab4fb8ad0 100644
--- a/chromium/components/autofill/content/renderer/html_based_username_detector.cc
+++ b/chromium/components/autofill/content/renderer/html_based_username_detector.cc
@@ -6,7 +6,6 @@
#include <algorithm>
#include <string>
-#include <tuple>
#include <utility>
#include "base/containers/contains.h"
@@ -129,23 +128,22 @@ void InferUsernameFieldData(
for (const blink::WebFormControlElement& control_element :
all_control_elements) {
- const blink::WebInputElement* input_element =
- ToWebInputElement(&control_element);
- if (!input_element || input_element->IsPasswordFieldForAutofill())
+ const WebInputElement input_element =
+ control_element.DynamicTo<WebInputElement>();
+ if (input_element.IsNull() || input_element.IsPasswordFieldForAutofill())
continue;
- const std::u16string element_name =
- input_element->NameForAutofill().Utf16();
+ const std::u16string element_name = input_element.NameForAutofill().Utf16();
for (size_t i = next_element_range_begin; i < form_data.fields.size();
++i) {
const FormFieldData& field_data = form_data.fields[i];
- if (input_element->NameForAutofill().IsEmpty())
+ if (input_element.NameForAutofill().IsEmpty())
continue;
// Find matching field data and web input element.
if (field_data.name == element_name) {
next_element_range_begin = i + 1;
possible_usernames_data->push_back(
- ComputeUsernameFieldData(*input_element, field_data));
+ ComputeUsernameFieldData(input_element, field_data));
break;
}
}
@@ -286,11 +284,7 @@ const std::vector<FieldRendererId>& GetPredictionsFieldBasedOnHtmlAttributes(
DCHECK(!all_control_elements.empty());
- // True if the cache has no entry for |form|.
- bool cache_miss = true;
- // Iterator pointing to the entry for |form| if the entry for |form| is found.
- UsernameDetectorCache::iterator form_position;
- std::tie(form_position, cache_miss) = username_detector_cache->emplace(
+ auto [form_position, cache_miss] = username_detector_cache->emplace(
form_util::GetFormRendererId(form), std::vector<FieldRendererId>());
if (cache_miss) {
diff --git a/chromium/components/autofill/content/renderer/html_based_username_detector_browsertest.cc b/chromium/components/autofill/content/renderer/html_based_username_detector_browsertest.cc
index c37394c4111..e31dc6f51b9 100644
--- a/chromium/components/autofill/content/renderer/html_based_username_detector_browsertest.cc
+++ b/chromium/components/autofill/content/renderer/html_based_username_detector_browsertest.cc
@@ -75,8 +75,8 @@ class HtmlBasedUsernameDetectorTest : public content::RenderViewTest {
const WebLocalFrame* frame = GetMainFrame();
const WebElement& element = frame->GetDocument().GetElementById(id);
EXPECT_FALSE(element.IsNull());
- return FieldRendererId(element.ToConst<blink::WebInputElement>()
- .UniqueRendererFormControlId());
+ return FieldRendererId(
+ element.To<blink::WebInputElement>().UniqueRendererFormControlId());
}
WebFormElement GetFormElement() {
diff --git a/chromium/components/autofill/content/renderer/page_form_analyser_logger.cc b/chromium/components/autofill/content/renderer/page_form_analyser_logger.cc
index 88821bf6f22..4623192385c 100644
--- a/chromium/components/autofill/content/renderer/page_form_analyser_logger.cc
+++ b/chromium/components/autofill/content/renderer/page_form_analyser_logger.cc
@@ -43,30 +43,30 @@ void PageFormAnalyserLogger::Flush() {
text += "[DOM] ";
text += entry.message;
- std::vector<blink::WebNode> nodesToLog;
+ std::vector<blink::WebNode> nodes_to_log;
for (unsigned i = 0; i < entry.nodes.size(); ++i) {
if (entry.nodes[i].IsElementNode()) {
const blink::WebElement element =
- entry.nodes[i].ToConst<blink::WebElement>();
- const blink::WebInputElement* webInputElement =
- blink::ToWebInputElement(&element);
+ entry.nodes[i].To<blink::WebElement>();
+ const blink::WebInputElement input_element =
+ element.DynamicTo<blink::WebInputElement>();
// Filter out password inputs with values from being logged, as their
// values are also logged.
- const bool shouldObfuscate =
- webInputElement &&
- webInputElement->IsPasswordFieldForAutofill() &&
- !webInputElement->Value().IsEmpty();
+ const bool should_obfuscate =
+ !input_element.IsNull() &&
+ input_element.IsPasswordFieldForAutofill() &&
+ !input_element.Value().IsEmpty();
- if (!shouldObfuscate) {
+ if (!should_obfuscate) {
text += " %o";
- nodesToLog.push_back(element);
+ nodes_to_log.push_back(element);
}
}
}
blink::WebConsoleMessage message(level, blink::WebString::FromUTF8(text));
- message.nodes = std::move(nodesToLog); // avoids copying node vectors.
+ message.nodes = std::move(nodes_to_log); // avoids copying node vectors.
frame_->AddMessageToConsole(message);
}
}
diff --git a/chromium/components/autofill/content/renderer/page_passwords_analyser.cc b/chromium/components/autofill/content/renderer/page_passwords_analyser.cc
index 436e3ac76bb..b5c91f721f8 100644
--- a/chromium/components/autofill/content/renderer/page_passwords_analyser.cc
+++ b/chromium/components/autofill/content/renderer/page_passwords_analyser.cc
@@ -11,6 +11,7 @@
#include "base/containers/contains.h"
#include "base/lazy_instance.h"
+#include "base/strings/strcat.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/content/renderer/form_autofill_util.h"
@@ -221,13 +222,13 @@ std::vector<FormInputCollection> ExtractFormsForAnalysis(
// Check for password fields that are not contained inside forms.
auto password_inputs = document.QuerySelectorAll("input[type=\"password\"]");
for (unsigned i = 0; i < password_inputs.size(); ++i) {
- const WebInputElement* input_element =
- ToWebInputElement(&password_inputs[i]);
- if (!input_element || input_element->IsNull())
+ const WebInputElement input_element =
+ password_inputs[i].DynamicTo<WebInputElement>();
+ if (input_element.IsNull())
continue;
if (TrackElementByRendererIdIfUntracked(
password_inputs[i],
- FieldRendererId(input_element->UniqueRendererFormControlId()),
+ FieldRendererId(input_element.UniqueRendererFormControlId()),
skip_control_ids, &nodes_for_id))
continue;
// Any password fields inside <form> elements will have been skipped,
@@ -241,15 +242,16 @@ std::vector<FormInputCollection> ExtractFormsForAnalysis(
// inside forms.
std::string selector = "input:not([type])";
for (const char* text_type : kTypeTextAttributes)
- selector += ", input[type=\"" + std::string(text_type) + "\"]";
+ base::StrAppend(&selector, {", input[type=\"", text_type, "\"]"});
auto text_inputs = document.QuerySelectorAll(WebString::FromUTF8(selector));
for (const WebElement& text_input : text_inputs) {
- const WebInputElement* input_element = ToWebInputElement(&text_input);
- if (!input_element || input_element->IsNull())
+ const WebInputElement input_element =
+ text_input.DynamicTo<WebInputElement>();
+ if (input_element.IsNull())
continue;
TrackElementByRendererIdIfUntracked(
text_input,
- FieldRendererId(input_element->UniqueRendererFormControlId()),
+ FieldRendererId(input_element.UniqueRendererFormControlId()),
skip_control_ids, &nodes_for_id);
}
// Warn against elements sharing an id attribute. Duplicate id attributes both
@@ -331,7 +333,7 @@ void GuessAutocompleteAttributesForPasswordFields(
switch (password_count) {
case 3:
(*autocomplete_suggestions)[password_inputs[0]] = "current-password";
- FALLTHROUGH; // To match the last two password fields.
+ [[fallthrough]]; // To match the last two password fields.
case 2:
(*autocomplete_suggestions)[password_inputs[password_count - 2]] =
"new-password";
diff --git a/chromium/components/autofill/content/renderer/password_autofill_agent.cc b/chromium/components/autofill/content/renderer/password_autofill_agent.cc
index 7e25f40f28d..2036e7054db 100644
--- a/chromium/components/autofill/content/renderer/password_autofill_agent.cc
+++ b/chromium/components/autofill/content/renderer/password_autofill_agent.cc
@@ -62,7 +62,6 @@
#include "ui/events/keycodes/keyboard_codes.h"
#include "url/gurl.h"
-using blink::ToWebInputElement;
using blink::WebAutofillState;
using blink::WebDocument;
using blink::WebElement;
@@ -360,23 +359,17 @@ WebInputElement FindUsernameElementPrecedingPasswordElement(
for (auto begin = elements.begin(); iter != begin;) {
--iter;
- const WebInputElement* input = ToWebInputElement(&*iter);
- if (input && input->IsTextField() && !input->IsPasswordFieldForAutofill() &&
- IsElementEditable(*input) && IsWebElementVisible(*input)) {
- return *input;
+ const WebInputElement input = iter->DynamicTo<WebInputElement>();
+ if (!input.IsNull() && input.IsTextField() &&
+ !input.IsPasswordFieldForAutofill() && IsElementEditable(input) &&
+ IsWebElementVisible(input)) {
+ return input;
}
}
return WebInputElement();
}
-WebInputElement ConvertToWebInput(const WebFormControlElement& element) {
- if (element.IsNull())
- return WebInputElement();
- const WebInputElement* input = ToWebInputElement(&element);
- return input ? *input : WebInputElement();
-}
-
// Returns true if |element|'s frame origin is not PSL matched with the origin
// of any parent frame.
bool IsInCrossOriginIframe(const WebInputElement& element) {
@@ -739,15 +732,15 @@ bool PasswordAutofillAgent::FillSuggestion(
const std::u16string& username,
const std::u16string& password) {
// The element in context of the suggestion popup.
- const WebInputElement* element = ToWebInputElement(&control_element);
- if (!element)
+ WebInputElement element = control_element.DynamicTo<WebInputElement>();
+ if (element.IsNull())
return false;
WebInputElement username_element;
WebInputElement password_element;
PasswordInfo* password_info = nullptr;
- if (!FindPasswordInfoForElement(*element, UseFallbackData(true),
+ if (!FindPasswordInfoForElement(element, UseFallbackData(true),
&username_element, &password_element,
&password_info) ||
(!password_element.IsNull() && !IsElementEditable(password_element))) {
@@ -755,7 +748,7 @@ bool PasswordAutofillAgent::FillSuggestion(
}
password_info->password_was_edited_last = false;
- if (element->IsPasswordFieldForAutofill()) {
+ if (element.IsPasswordFieldForAutofill()) {
password_info->password_field_suggestion_was_accepted = true;
password_info->password_field = password_element;
}
@@ -766,8 +759,8 @@ bool PasswordAutofillAgent::FillSuggestion(
password_generation_agent_->OnFieldAutofilled(password_element);
if (IsUsernameAmendable(username_element,
- element->IsPasswordFieldForAutofill()) &&
- !(username.empty() && element->IsPasswordFieldForAutofill()) &&
+ element.IsPasswordFieldForAutofill()) &&
+ !(username.empty() && element.IsPasswordFieldForAutofill()) &&
username_element.Value().Utf16() != username) {
FillField(&username_element, username);
}
@@ -775,9 +768,7 @@ bool PasswordAutofillAgent::FillSuggestion(
if (!password_element.IsNull())
FillPasswordFieldAndSave(&password_element, password);
- WebInputElement mutable_filled_element = *element;
- mutable_filled_element.SetSelectionRange(element->Value().length(),
- element->Value().length());
+ element.SetSelectionRange(element.Value().length(), element.Value().length());
return true;
}
@@ -821,15 +812,15 @@ bool PasswordAutofillAgent::PreviewSuggestion(
const WebString& username,
const WebString& password) {
// The element in context of the suggestion popup.
- const WebInputElement* element = ToWebInputElement(&control_element);
- if (!element)
+ const WebInputElement element = control_element.DynamicTo<WebInputElement>();
+ if (element.IsNull())
return false;
WebInputElement username_element;
WebInputElement password_element;
PasswordInfo* password_info;
- if (!FindPasswordInfoForElement(*element, UseFallbackData(true),
+ if (!FindPasswordInfoForElement(element, UseFallbackData(true),
&username_element, &password_element,
&password_info) ||
(!password_element.IsNull() && !IsElementEditable(password_element))) {
@@ -837,7 +828,7 @@ bool PasswordAutofillAgent::PreviewSuggestion(
}
if (IsUsernameAmendable(username_element,
- element->IsPasswordFieldForAutofill())) {
+ element.IsPasswordFieldForAutofill())) {
if (username_query_prefix_.empty())
username_query_prefix_ = username_element.Value().Utf16();
@@ -858,15 +849,15 @@ bool PasswordAutofillAgent::PreviewSuggestion(
bool PasswordAutofillAgent::DidClearAutofillSelection(
const WebFormControlElement& control_element) {
- const WebInputElement* element = ToWebInputElement(&control_element);
- if (!element)
+ const WebInputElement element = control_element.DynamicTo<WebInputElement>();
+ if (element.IsNull())
return false;
WebInputElement username_element;
WebInputElement password_element;
PasswordInfo* password_info;
- if (!FindPasswordInfoForElement(*element, UseFallbackData(true),
+ if (!FindPasswordInfoForElement(element, UseFallbackData(true),
&username_element, &password_element,
&password_info)) {
return false;
@@ -964,12 +955,13 @@ bool PasswordAutofillAgent::TryToShowTouchToFill(
if (touch_to_fill_state_ != TouchToFillState::kShouldShow)
return false;
- const WebInputElement* input_element = ToWebInputElement(&control_element);
+ const WebInputElement input_element =
+ control_element.DynamicTo<WebInputElement>();
WebInputElement username_element;
WebInputElement password_element;
PasswordInfo* password_info = nullptr;
- if (!input_element ||
- !FindPasswordInfoForElement(*input_element, UseFallbackData(false),
+ if (input_element.IsNull() ||
+ !FindPasswordInfoForElement(input_element, UseFallbackData(false),
&username_element, &password_element,
&password_info)) {
return false;
@@ -983,7 +975,7 @@ bool PasswordAutofillAgent::TryToShowTouchToFill(
// Highlight the fields that are about to be filled by the user and remember
// the old autofill state of |username_element| and |password_element|.
if (IsUsernameAmendable(username_element,
- input_element->IsPasswordFieldForAutofill())) {
+ input_element.IsPasswordFieldForAutofill())) {
username_autofill_state_ = username_element.GetAutofillState();
username_element.SetAutofillState(WebAutofillState::kPreviewed);
}
@@ -991,7 +983,7 @@ bool PasswordAutofillAgent::TryToShowTouchToFill(
password_autofill_state_ = password_element.GetAutofillState();
password_element.SetAutofillState(WebAutofillState::kPreviewed);
- focused_input_element_ = *input_element;
+ focused_input_element_ = input_element;
GetPasswordManagerDriver().ShowTouchToFill();
touch_to_fill_state_ = TouchToFillState::kIsShowing;
return true;
@@ -1272,7 +1264,7 @@ void PasswordAutofillAgent::SendPasswordForms(bool only_visible) {
}
}
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
// Provide warnings about the accessibility of password forms on the page.
if (!password_forms_data.empty() &&
(frame->GetDocument().Url().ProtocolIs(url::kHttpScheme) ||
@@ -1396,6 +1388,48 @@ void PasswordAutofillAgent::SetLoggingState(bool active) {
logging_state_active_ = active;
}
+void PasswordAutofillAgent::AnnotateFieldsWithParsingResult(
+ const ParsingResult& parsing_result) {
+ WebDocument doc = render_frame()->GetWebFrame()->GetDocument();
+ AnnotateFieldWithParsingResult(doc, parsing_result.username_renderer_id,
+ "username_element");
+ AnnotateFieldWithParsingResult(doc, parsing_result.password_renderer_id,
+ "password_element");
+ AnnotateFieldWithParsingResult(doc, parsing_result.new_password_renderer_id,
+ "new_password_element");
+ AnnotateFieldWithParsingResult(doc,
+ parsing_result.confirm_password_renderer_id,
+ "confirmation_password_element");
+}
+
+void PasswordAutofillAgent::InformNoSavedCredentials(
+ bool should_show_popup_without_passwords) {
+ should_show_popup_without_passwords_ = should_show_popup_without_passwords;
+
+ autofilled_elements_cache_.clear();
+
+ // Clear the actual field values.
+ WebDocument doc = render_frame()->GetWebFrame()->GetDocument();
+ std::vector<WebFormControlElement> elements =
+ FindFormControlElementsByUniqueRendererId(
+ doc, std::vector<FieldRendererId>(all_autofilled_elements_.begin(),
+ all_autofilled_elements_.end()));
+ for (WebFormControlElement& element : elements) {
+ if (element.IsNull())
+ continue;
+ element.SetSuggestedValue(blink::WebString());
+ // Don't clear the actual value of fields that the user has edited manually
+ // (which changes the autofill state back to kNotFilled).
+ if (element.GetAutofillState() == WebAutofillState::kAutofilled)
+ element.SetValue(blink::WebString());
+ element.SetAutofillState(WebAutofillState::kNotFilled);
+ }
+ all_autofilled_elements_.clear();
+
+ field_data_manager_->ClearData();
+}
+
+#if BUILDFLAG(IS_ANDROID)
void PasswordAutofillAgent::TouchToFillClosed(bool show_virtual_keyboard) {
touch_to_fill_state_ = TouchToFillState::kWasShown;
@@ -1432,46 +1466,29 @@ void PasswordAutofillAgent::TouchToFillClosed(bool show_virtual_keyboard) {
}
}
-void PasswordAutofillAgent::AnnotateFieldsWithParsingResult(
- const ParsingResult& parsing_result) {
- WebDocument doc = render_frame()->GetWebFrame()->GetDocument();
- AnnotateFieldWithParsingResult(doc, parsing_result.username_renderer_id,
- "username_element");
- AnnotateFieldWithParsingResult(doc, parsing_result.password_renderer_id,
- "password_element");
- AnnotateFieldWithParsingResult(doc, parsing_result.new_password_renderer_id,
- "new_password_element");
- AnnotateFieldWithParsingResult(doc,
- parsing_result.confirm_password_renderer_id,
- "confirmation_password_element");
-}
+void PasswordAutofillAgent::TriggerFormSubmission() {
+ // Find the last interacted element to simulate an enter keystroke at.
+ WebFormControlElement form_control = FindFormControlElementByUniqueRendererId(
+ render_frame()->GetWebFrame()->GetDocument(),
+ last_updated_field_renderer_id_, last_updated_form_renderer_id_);
+ if (form_control.IsNull()) {
+ // The target field doesn't exist anymore. Don't try to submit it.
+ return;
+ }
-void PasswordAutofillAgent::InformNoSavedCredentials(
- bool should_show_popup_without_passwords) {
- should_show_popup_without_passwords_ = should_show_popup_without_passwords;
+ // TODO(crbug.com/1283004): Support submission for <form>less forms too.
+ if (!form_control.Form().IsNull()) {
+ // |form_control| can only be |WebInputElement|, not |WebSelectElement|.
+ WebInputElement input = form_control.To<WebInputElement>();
- autofilled_elements_cache_.clear();
+ // TODO(crbug.com/1283004): Support filling single username fields too.
+ DCHECK(input.IsPasswordFieldForAutofill())
+ << "Form submission attempt for a non-password element";
- // Clear the actual field values.
- WebDocument doc = render_frame()->GetWebFrame()->GetDocument();
- std::vector<WebFormControlElement> elements =
- FindFormControlElementsByUniqueRendererId(
- doc, std::vector<FieldRendererId>(all_autofilled_elements_.begin(),
- all_autofilled_elements_.end()));
- for (WebFormControlElement& element : elements) {
- if (element.IsNull())
- continue;
- element.SetSuggestedValue(blink::WebString());
- // Don't clear the actual value of fields that the user has edited manually
- // (which changes the autofill state back to kNotFilled).
- if (element.GetAutofillState() == WebAutofillState::kAutofilled)
- element.SetValue(blink::WebString());
- element.SetAutofillState(WebAutofillState::kNotFilled);
+ input.DispatchSimulatedEnterIfLastInputInForm();
}
- all_autofilled_elements_.clear();
-
- field_data_manager_->ClearData();
}
+#endif
void PasswordAutofillAgent::FocusedNodeHasChanged(const blink::WebNode& node) {
DCHECK(!node.IsNull());
@@ -1483,39 +1500,39 @@ void PasswordAutofillAgent::FocusedNodeHasChanged(const blink::WebNode& node) {
return;
}
- auto element = node.ToConst<WebElement>();
+ auto element = node.To<WebElement>();
if (element.IsFormControlElement() &&
- form_util::IsTextAreaElement(element.ToConst<WebFormControlElement>())) {
+ form_util::IsTextAreaElement(element.To<WebFormControlElement>())) {
FieldRendererId textarea_id(
- element.ToConst<WebFormControlElement>().UniqueRendererFormControlId());
+ element.To<WebFormControlElement>().UniqueRendererFormControlId());
focus_state_notifier_.FocusedInputChanged(
textarea_id, FocusedFieldType::kFillableTextArea);
return;
}
- auto* input_element = ToWebInputElement(&element);
- if (!input_element) {
+ WebInputElement input_element = element.DynamicTo<WebInputElement>();
+ if (input_element.IsNull()) {
focus_state_notifier_.FocusedInputChanged(
FieldRendererId(), FocusedFieldType::kUnfillableElement);
return;
}
auto focused_field_type = FocusedFieldType::kUnfillableElement;
- if (input_element->IsTextField() && IsElementEditable(*input_element)) {
- focused_input_element_ = *input_element;
+ if (input_element.IsTextField() && IsElementEditable(input_element)) {
+ focused_input_element_ = input_element;
- WebString type = input_element->GetAttribute("type");
+ WebString type = input_element.GetAttribute("type");
if (!type.IsNull() && type == "search")
focused_field_type = FocusedFieldType::kFillableSearchField;
- else if (input_element->IsPasswordFieldForAutofill())
+ else if (input_element.IsPasswordFieldForAutofill())
focused_field_type = FocusedFieldType::kFillablePasswordField;
- else if (base::Contains(web_input_to_password_info_, *input_element))
+ else if (base::Contains(web_input_to_password_info_, input_element))
focused_field_type = FocusedFieldType::kFillableUsernameField;
else
focused_field_type = FocusedFieldType::kFillableNonSearchField;
}
- const FieldRendererId input_id(input_element->UniqueRendererFormControlId());
+ const FieldRendererId input_id(input_element.UniqueRendererFormControlId());
focus_state_notifier_.FocusedInputChanged(input_id, focused_field_type);
field_data_manager_->UpdateFieldDataMapWithNullValue(
input_id, FieldPropertiesFlags::kHadFocus);
@@ -1640,7 +1657,7 @@ void PasswordAutofillAgent::CleanupOnDocumentShutdown() {
last_updated_field_renderer_id_ = FieldRendererId();
last_updated_form_renderer_id_ = FormRendererId();
touch_to_fill_state_ = TouchToFillState::kShouldShow;
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
page_passwords_analyser_.Reset();
#endif
}
@@ -1825,9 +1842,7 @@ void PasswordAutofillAgent::OnProvisionallySaveForm(
if (source == ElementChangeSource::SELECT_CHANGED)
return;
- WebInputElement input_element;
- if (!element.IsNull() && element.HasHTMLTagName("input"))
- input_element = *ToWebInputElement(&element);
+ WebInputElement input_element = element.DynamicTo<WebInputElement>();
if (source == ElementChangeSource::TEXTFIELD_CHANGED) {
DCHECK(!input_element.IsNull());
@@ -1931,12 +1946,12 @@ PasswordAutofillAgent::FindUsernamePasswordElements(
WebInputElement password_field;
size_t current_index = 0;
if (is_password_present)
- password_field = ConvertToWebInput(elements[current_index++]);
+ password_field = elements[current_index++].DynamicTo<WebInputElement>();
// Set username element.
WebInputElement username_field;
if (is_username_present)
- username_field = ConvertToWebInput(elements[current_index++]);
+ username_field = elements[current_index++].DynamicTo<WebInputElement>();
return std::make_pair(username_field, password_field);
}
diff --git a/chromium/components/autofill/content/renderer/password_autofill_agent.h b/chromium/components/autofill/content/renderer/password_autofill_agent.h
index a372ccb1010..74864a1a8cf 100644
--- a/chromium/components/autofill/content/renderer/password_autofill_agent.h
+++ b/chromium/components/autofill/content/renderer/password_autofill_agent.h
@@ -32,7 +32,7 @@
#include "third_party/blink/public/common/associated_interfaces/associated_interface_registry.h"
#include "third_party/blink/public/web/web_input_element.h"
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
#include "components/autofill/content/renderer/page_passwords_analyser.h"
#endif
@@ -136,9 +136,12 @@ class PasswordAutofillAgent : public content::RenderFrameObserver,
void FillIntoFocusedField(bool is_password,
const std::u16string& credential) override;
void SetLoggingState(bool active) override;
- void TouchToFillClosed(bool show_virtual_keyboard) override;
void AnnotateFieldsWithParsingResult(
const ParsingResult& parsing_result) override;
+#if BUILDFLAG(IS_ANDROID)
+ void TouchToFillClosed(bool show_virtual_keyboard) override;
+ void TriggerFormSubmission() override;
+#endif
// FormTracker::Observer
void OnProvisionallySaveForm(const blink::WebFormElement& form,
@@ -555,7 +558,7 @@ class PasswordAutofillAgent : public content::RenderFrameObserver,
PasswordGenerationAgent* password_generation_agent_; // Weak reference.
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
PagePasswordsAnalyser page_passwords_analyser_;
#endif
diff --git a/chromium/components/autofill/content/renderer/password_form_conversion_utils.cc b/chromium/components/autofill/content/renderer/password_form_conversion_utils.cc
index 02dbc21363f..9367f0b5900 100644
--- a/chromium/components/autofill/content/renderer/password_form_conversion_utils.cc
+++ b/chromium/components/autofill/content/renderer/password_form_conversion_utils.cc
@@ -93,19 +93,18 @@ bool IsGaiaReauthenticationForm(const blink::WebFormElement& form) {
for (const WebFormControlElement& element : form.GetFormControlElements()) {
// We're only interested in the presence
// of <input type="hidden" /> elements.
- static base::NoDestructor<WebString> kHidden("hidden");
- const blink::WebInputElement* input = blink::ToWebInputElement(&element);
- if (!input || input->FormControlTypeForAutofill() != *kHidden)
+ const WebInputElement input = element.DynamicTo<WebInputElement>();
+ if (input.IsNull() || input.FormControlTypeForAutofill() != "hidden")
continue;
// There must be a hidden input named "rart".
- if (input->FormControlName() == "rart")
+ if (input.FormControlName() == "rart")
has_rart_field = true;
// There must be a hidden input named "continue", whose value points
// to a password (or password testing) site.
- if (input->FormControlName() == "continue" &&
- re2::RE2::PartialMatch(input->Value().Utf8(),
+ if (input.FormControlName() == "continue" &&
+ re2::RE2::PartialMatch(input.Value().Utf8(),
g_password_site_matcher.Get())) {
has_continue_field = true;
}
diff --git a/chromium/components/autofill/content/renderer/password_generation_agent.cc b/chromium/components/autofill/content/renderer/password_generation_agent.cc
index 46d59909cc3..ffdaef209c5 100644
--- a/chromium/components/autofill/content/renderer/password_generation_agent.cc
+++ b/chromium/components/autofill/content/renderer/password_generation_agent.cc
@@ -64,9 +64,9 @@ FieldRendererId FindConfirmationPasswordFieldId(
++iter;
for (; iter != control_elements.end(); ++iter) {
- const WebInputElement* input_element = ToWebInputElement(&(*iter));
- if (input_element && input_element->IsPasswordFieldForAutofill())
- return FieldRendererId(input_element->UniqueRendererFormControlId());
+ const WebInputElement input_element = iter->DynamicTo<WebInputElement>();
+ if (!input_element.IsNull() && input_element.IsPasswordFieldForAutofill())
+ return FieldRendererId(input_element.UniqueRendererFormControlId());
}
return FieldRendererId();
}
@@ -451,26 +451,26 @@ bool PasswordGenerationAgent::FocusedNodeHasChanged(
return false;
}
- const blink::WebElement web_element = node.ToConst<blink::WebElement>();
+ const blink::WebElement web_element = node.To<blink::WebElement>();
if (!web_element.GetDocument().GetFrame()) {
return false;
}
- const WebInputElement* element = ToWebInputElement(&web_element);
- if (!element)
+ const WebInputElement element = web_element.DynamicTo<WebInputElement>();
+ if (element.IsNull())
return false;
- if (element->IsPasswordFieldForAutofill())
- last_focused_password_element_ = *element;
+ if (element.IsPasswordFieldForAutofill())
+ last_focused_password_element_ = element;
auto it = generation_enabled_fields_.find(
- FieldRendererId(element->UniqueRendererFormControlId()));
+ FieldRendererId(element.UniqueRendererFormControlId()));
if (it != generation_enabled_fields_.end()) {
MaybeCreateCurrentGenerationItem(
- *element, it->second.confirmation_password_renderer_id);
+ element, it->second.confirmation_password_renderer_id);
}
if (!current_generation_item_ ||
- *element != current_generation_item_->generation_element_) {
+ element != current_generation_item_->generation_element_) {
return false;
}
@@ -493,8 +493,8 @@ bool PasswordGenerationAgent::FocusedNodeHasChanged(
// Assume that if the password field has less than
// |kMaximumCharsForGenerationOffer| characters then the user is not finished
// typing their password and display the password suggestion.
- if (!element->IsReadOnly() && element->IsEnabled() &&
- element->Value().length() <= kMaximumCharsForGenerationOffer) {
+ if (!element.IsReadOnly() && element.IsEnabled() &&
+ element.Value().length() <= kMaximumCharsForGenerationOffer) {
MaybeOfferAutomaticGeneration();
return true;
}
@@ -693,9 +693,9 @@ void PasswordGenerationAgent::MaybeCreateCurrentGenerationItem(
generation_element.GetDocument(), confirmation_password_renderer_id);
if (!confirmation_password.IsNull()) {
- WebInputElement* input = ToWebInputElement(&confirmation_password);
- if (input)
- passwords.push_back(*input);
+ WebInputElement input = confirmation_password.DynamicTo<WebInputElement>();
+ if (!input.IsNull())
+ passwords.push_back(input);
}
current_generation_item_ = std::make_unique<GenerationItemInfo>(
diff --git a/chromium/components/autofill/core/browser/BUILD.gn b/chromium/components/autofill/core/browser/BUILD.gn
index de78c9909fc..59be3cab805 100644
--- a/chromium/components/autofill/core/browser/BUILD.gn
+++ b/chromium/components/autofill/core/browser/BUILD.gn
@@ -25,11 +25,9 @@ action("default_regex_patterns_cc") {
visibility = [ ":*" ]
sources = [ "pattern_provider/resources/regex_patterns.json" ]
script = "pattern_provider/transpile_default_regex_patterns.py"
- args = [
- rebase_path("pattern_provider/resources/regex_patterns.json"),
- rebase_path("$target_gen_dir/pattern_provider/default_regex_patterns.cc"),
- ]
outputs = [ "$target_gen_dir/pattern_provider/default_regex_patterns.cc" ]
+ args = rebase_path(sources, root_build_dir) +
+ rebase_path(outputs, root_build_dir)
}
static_library("browser") {
@@ -80,10 +78,6 @@ static_library("browser") {
"autofill_profile_sync_util.h",
"autofill_profile_update_strike_database.cc",
"autofill_profile_update_strike_database.h",
- "autofill_profile_validation_util.cc",
- "autofill_profile_validation_util.h",
- "autofill_profile_validator.cc",
- "autofill_profile_validator.h",
"autofill_regex_constants.cc",
"autofill_regex_constants.h",
"autofill_regexes.cc",
@@ -195,8 +189,6 @@ static_library("browser") {
"geo/country_names.h",
"geo/country_names_for_locale.cc",
"geo/country_names_for_locale.h",
- "geo/mock_alternative_state_name_map_updater.cc",
- "geo/mock_alternative_state_name_map_updater.h",
"geo/phone_number_i18n.cc",
"geo/phone_number_i18n.h",
"geo/region_data_loader.h",
@@ -223,6 +215,8 @@ static_library("browser") {
"metrics/form_events/form_event_logger_base.cc",
"metrics/form_events/form_event_logger_base.h",
"metrics/form_events/form_events.h",
+ "metrics/payments/virtual_card_enrollment_metrics.cc",
+ "metrics/payments/virtual_card_enrollment_metrics.h",
"pattern_provider/default_regex_patterns.h",
"pattern_provider/pattern_configuration_parser.cc",
"pattern_provider/pattern_configuration_parser.h",
@@ -250,22 +244,33 @@ static_library("browser") {
"payments/full_card_request.h",
"payments/legal_message_line.cc",
"payments/legal_message_line.h",
+ "payments/offer_notification_handler.cc",
+ "payments/offer_notification_handler.h",
"payments/otp_unmask_delegate.h",
"payments/otp_unmask_result.h",
"payments/payments_client.cc",
"payments/payments_client.h",
"payments/payments_customer_data.h",
+ "payments/payments_requests/get_details_for_enrollment_request.cc",
+ "payments/payments_requests/get_details_for_enrollment_request.h",
"payments/payments_requests/payments_request.cc",
"payments/payments_requests/payments_request.h",
"payments/payments_requests/select_challenge_option_request.cc",
"payments/payments_requests/select_challenge_option_request.h",
"payments/payments_requests/unmask_card_request.cc",
"payments/payments_requests/unmask_card_request.h",
+ "payments/payments_requests/update_virtual_card_enrollment_request.cc",
+ "payments/payments_requests/update_virtual_card_enrollment_request.h",
"payments/payments_service_url.cc",
"payments/payments_service_url.h",
"payments/payments_util.cc",
"payments/payments_util.h",
"payments/risk_data_loader.h",
+ "payments/virtual_card_enrollment_flow.h",
+ "payments/virtual_card_enrollment_manager.cc",
+ "payments/virtual_card_enrollment_manager.h",
+ "payments/virtual_card_enrollment_strike_database.cc",
+ "payments/virtual_card_enrollment_strike_database.h",
"payments/wait_for_signal_or_timeout.cc",
"payments/wait_for_signal_or_timeout.h",
"payments/webauthn_callback_types.h",
@@ -320,6 +325,7 @@ static_library("browser") {
"ui/payments/card_unmask_prompt_controller_impl.h",
"ui/payments/card_unmask_prompt_view.h",
"ui/payments/payments_bubble_closed_reasons.h",
+ "ui/payments/virtual_card_enroll_bubble_controller.h",
"ui/popup_item_ids.h",
"ui/popup_types.h",
"ui/region_combobox_model.cc",
@@ -396,6 +402,9 @@ static_library("browser") {
"payments/autofill_save_card_infobar_mobile.h",
"payments/autofill_save_card_ui_utils_mobile.cc",
"payments/autofill_save_card_ui_utils_mobile.h",
+ "payments/autofill_virtual_card_enrollment_infobar_delegate_mobile.cc",
+ "payments/autofill_virtual_card_enrollment_infobar_delegate_mobile.h",
+ "payments/autofill_virtual_card_enrollment_infobar_mobile.h",
"ui/mobile_label_formatter.cc",
"ui/mobile_label_formatter.h",
"ui/payments/card_expiration_date_fix_flow_controller.h",
@@ -541,6 +550,8 @@ static_library("test_support") {
"autofill_test_utils.h",
"geo/alternative_state_name_map_test_utils.cc",
"geo/alternative_state_name_map_test_utils.h",
+ "geo/mock_alternative_state_name_map_updater.cc",
+ "geo/mock_alternative_state_name_map_updater.h",
"geo/test_region_data_loader.cc",
"geo/test_region_data_loader.h",
"logging/stub_log_manager.cc",
@@ -562,6 +573,8 @@ static_library("test_support") {
"payments/test_payments_client.h",
"payments/test_strike_database.cc",
"payments/test_strike_database.h",
+ "payments/test_virtual_card_enrollment_manager.cc",
+ "payments/test_virtual_card_enrollment_manager.h",
"test_address_normalizer.cc",
"test_address_normalizer.h",
"test_autofill_async_observer.cc",
@@ -576,10 +589,6 @@ static_library("test_support") {
"test_autofill_driver.h",
"test_autofill_external_delegate.cc",
"test_autofill_external_delegate.h",
- "test_autofill_profile_validator.cc",
- "test_autofill_profile_validator.h",
- "test_autofill_profile_validator_delayed.cc",
- "test_autofill_profile_validator_delayed.h",
"test_autofill_tick_clock.cc",
"test_autofill_tick_clock.h",
"test_browser_autofill_manager.cc",
@@ -717,8 +726,6 @@ source_set("unit_tests") {
"autofill_profile_save_strike_database_unittest.cc",
"autofill_profile_sync_util_unittest.cc",
"autofill_profile_update_strike_database_unittest.cc",
- "autofill_profile_validation_util_unittest.cc",
- "autofill_profile_validator_unittest.cc",
"autofill_regexes_unittest.cc",
"autofill_subject_unittest.cc",
"autofill_suggestion_generator_unittest.cc",
@@ -779,8 +786,11 @@ source_set("unit_tests") {
"payments/full_card_request_unittest.cc",
"payments/legal_message_line_unittest.cc",
"payments/payments_client_unittest.cc",
+ "payments/payments_requests/get_details_for_enrollment_request_unittest.cc",
"payments/payments_service_url_unittest.cc",
"payments/payments_util_unittest.cc",
+ "payments/virtual_card_enrollment_manager_unittest.cc",
+ "payments/virtual_card_enrollment_strike_database_unittest.cc",
"payments/wait_for_signal_or_timeout_unittest.cc",
"personal_data_manager_unittest.cc",
"randomized_encoder_unittest.cc",
diff --git a/chromium/components/autofill/core/browser/OWNERS b/chromium/components/autofill/core/browser/OWNERS
deleted file mode 100644
index 711aa7cc667..00000000000
--- a/chromium/components/autofill/core/browser/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-per-file *type_controller*=jkrcal@chromium.org
-per-file *type_controller*=file://components/sync/OWNERS
diff --git a/chromium/components/autofill/core/browser/address_profile_save_manager.cc b/chromium/components/autofill/core/browser/address_profile_save_manager.cc
index b4939ff0297..d90810f7a28 100644
--- a/chromium/components/autofill/core/browser/address_profile_save_manager.cc
+++ b/chromium/components/autofill/core/browser/address_profile_save_manager.cc
@@ -25,7 +25,8 @@ void AddressProfileSaveManager::ImportProfileFromForm(
const AutofillProfile& observed_profile,
const std::string& app_locale,
const GURL& url,
- bool allow_only_silent_updates) {
+ bool allow_only_silent_updates,
+ bool did_complement_country) {
// Without a personal data manager, profile storage is not possible.
if (!personal_data_manager_)
return;
@@ -34,8 +35,9 @@ void AddressProfileSaveManager::ImportProfileFromForm(
// behavior and directly import the observed profile without recording any
// additional metrics. However, if only silent updates are allowed, proceed
// with the profile import process.
- if (!base::FeatureList::IsEnabled(
- features::kAutofillAddressProfileSavePrompt) &&
+ if ((!base::FeatureList::IsEnabled(
+ features::kAutofillAddressProfileSavePrompt) ||
+ personal_data_manager_->auto_accept_address_imports_for_testing()) &&
!allow_only_silent_updates) {
personal_data_manager_->SaveImportedProfile(observed_profile);
return;
@@ -43,7 +45,7 @@ void AddressProfileSaveManager::ImportProfileFromForm(
auto process_ptr = std::make_unique<ProfileImportProcess>(
observed_profile, app_locale, url, personal_data_manager_,
- allow_only_silent_updates);
+ allow_only_silent_updates, did_complement_country);
MaybeOfferSavePrompt(std::move(process_ptr));
}
@@ -71,13 +73,6 @@ void AddressProfileSaveManager::MaybeOfferSavePrompt(
case AutofillProfileImportType::kNewProfile:
case AutofillProfileImportType::kConfirmableMerge:
case AutofillProfileImportType::kConfirmableMergeAndSilentUpdate:
- // Emulates manually accepting new profiles and profile updates for
- // testing purposes. This should only be applied in tests.
- if (personal_data_manager_->auto_accept_address_imports_for_testing()) {
- import_process->AcceptWithoutEdits();
- FinalizeProfileImport(std::move(import_process));
- return;
- }
OfferSavePrompt(std::move(import_process));
return;
diff --git a/chromium/components/autofill/core/browser/address_profile_save_manager.h b/chromium/components/autofill/core/browser/address_profile_save_manager.h
index 637cb3852e5..063f2175ac2 100644
--- a/chromium/components/autofill/core/browser/address_profile_save_manager.h
+++ b/chromium/components/autofill/core/browser/address_profile_save_manager.h
@@ -40,10 +40,14 @@ class AddressProfileSaveManager {
// |allow_only_silent_updates| allows only for silent updates of profiles
// that have either a structured name or address or both but do not fulfill
// the import requirements.
+ // |did_complement_country| is passed through, to collect metrics on whether
+ // the profile is accepted/edited.
+ // TODO(crbug.com/1297032): Cleanup when launched.
void ImportProfileFromForm(const AutofillProfile& profile,
const std::string& app_locale,
const GURL& url,
- bool allow_only_silent_updates);
+ bool allow_only_silent_updates,
+ bool did_complement_country = false);
protected:
// Initiates showing the prompt to the user.
diff --git a/chromium/components/autofill/core/browser/address_profile_save_manager_unittest.cc b/chromium/components/autofill/core/browser/address_profile_save_manager_unittest.cc
index 4a32d003e19..945d5c3c570 100644
--- a/chromium/components/autofill/core/browser/address_profile_save_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/address_profile_save_manager_unittest.cc
@@ -48,6 +48,16 @@ constexpr char kProfileUpdateNumberOfEditsHistogram[] =
"Autofill.ProfileImport.UpdateProfileNumberOfEditedFields";
constexpr char kProfileUpdateNumberOfAffectedTypesHistogram[] =
"Autofill.ProfileImport.UpdateProfileNumberOfAffectedFields";
+// Histograms related to kAutofillComplementCountryCodeOnImport
+// TODO(crbug.com/1297032): Cleanup when launched.
+constexpr char kNewProfileWithComplementedCountryDecisionHistogram[] =
+ "Autofill.ProfileImport.NewProfileWithComplementedCountryDecision";
+constexpr char kProfileUpdateWithComplementedCountryDecisionHistogram[] =
+ "Autofill.ProfileImport.UpdateProfileWithComplementedCountryDecision";
+constexpr char kNewProfileEditComplementedCountryHistogram[] =
+ "Autofill.ProfileImport.NewProfileEditedComplementedCountry";
+constexpr char kProfileUpdateEditComplementedCountryHistogram[] =
+ "Autofill.ProfileImport.UpdateProfileEditedComplementedCountry";
class MockPersonalDataManager : public TestPersonalDataManager {
public:
@@ -146,9 +156,12 @@ struct ImportScenarioTestCase {
bool allow_only_silent_updates = false;
};
-class AddressProfileSaveManagerTest : public testing::Test {
+class AddressProfileSaveManagerTest
+ : public testing::Test,
+ public testing::WithParamInterface<std::tuple<bool>> {
public:
void SetUp() override {
+ complement_country_ = std::get<0>(GetParam());
// Enable both explicit save prompts and structured names.
// The latter is needed to test the concept of silent updates.
scoped_feature_list_.InitWithFeatures(
@@ -171,6 +184,7 @@ class AddressProfileSaveManagerTest : public testing::Test {
TestAutofillClient autofill_client_;
MockPersonalDataManager mock_personal_data_manager_;
base::test::ScopedFeatureList scoped_feature_list_;
+ bool complement_country_;
};
void AddressProfileSaveManagerTest::TestImportScenario(
@@ -231,7 +245,8 @@ void AddressProfileSaveManagerTest::TestImportScenario(
// Initiate the profile import.
save_manager.ImportProfileFromForm(
test_scenario.observed_profile, "en-US", url,
- /*allow_only_silent_updates=*/test_scenario.allow_only_silent_updates);
+ /*allow_only_silent_updates=*/test_scenario.allow_only_silent_updates,
+ /*did_complement_country=*/complement_country_);
// Assert that there is a finished import process on record.
ASSERT_NE(save_manager.last_import(), nullptr);
@@ -273,8 +288,12 @@ void AddressProfileSaveManagerTest::TestImportScenario(
if (!is_new_profile && !is_confirmable_merge) {
histogram_tester.ExpectTotalCount(kNewProfileEditsHistogram, 0);
histogram_tester.ExpectTotalCount(kNewProfileDecisionHistogram, 0);
+ histogram_tester.ExpectTotalCount(
+ kNewProfileWithComplementedCountryDecisionHistogram, 0);
histogram_tester.ExpectTotalCount(kProfileUpdateEditsHistogram, 0);
histogram_tester.ExpectTotalCount(kProfileUpdateDecisionHistogram, 0);
+ histogram_tester.ExpectTotalCount(
+ kProfileUpdateWithComplementedCountryDecisionHistogram, 0);
} else {
DCHECK(!is_new_profile || !is_confirmable_merge);
@@ -308,6 +327,48 @@ void AddressProfileSaveManagerTest::TestImportScenario(
affected_edits_histo,
test_scenario.expected_edited_types_for_metrics.size());
+ // Metrics related to country complemention.
+ if (complement_country_) {
+ histogram_tester.ExpectTotalCount(
+ !is_new_profile
+ ? kNewProfileWithComplementedCountryDecisionHistogram
+ : kProfileUpdateWithComplementedCountryDecisionHistogram,
+ 0);
+ histogram_tester.ExpectUniqueSample(
+ is_new_profile
+ ? kNewProfileWithComplementedCountryDecisionHistogram
+ : kProfileUpdateWithComplementedCountryDecisionHistogram,
+ test_scenario.user_decision, 1);
+
+ // In case the country was edited, expect increased metrics.
+ if (base::Contains(
+ test_scenario.expected_edited_types_for_metrics,
+ AutofillMetrics::SettingsVisibleFieldTypeForMetrics::kCountry)) {
+ histogram_tester.ExpectTotalCount(
+ !is_new_profile ? kNewProfileEditComplementedCountryHistogram
+ : kProfileUpdateEditComplementedCountryHistogram,
+ 0);
+ histogram_tester.ExpectTotalCount(
+ is_new_profile ? kNewProfileEditComplementedCountryHistogram
+ : kProfileUpdateEditComplementedCountryHistogram,
+ 1);
+ } else {
+ histogram_tester.ExpectTotalCount(
+ kNewProfileEditComplementedCountryHistogram, 0);
+ histogram_tester.ExpectTotalCount(
+ kProfileUpdateEditComplementedCountryHistogram, 0);
+ }
+ } else {
+ histogram_tester.ExpectTotalCount(
+ kNewProfileWithComplementedCountryDecisionHistogram, 0);
+ histogram_tester.ExpectTotalCount(
+ kProfileUpdateWithComplementedCountryDecisionHistogram, 0);
+ histogram_tester.ExpectTotalCount(
+ kNewProfileEditComplementedCountryHistogram, 0);
+ histogram_tester.ExpectTotalCount(
+ kProfileUpdateEditComplementedCountryHistogram, 0);
+ }
+
for (auto edited_type : test_scenario.expected_edited_types_for_metrics) {
histogram_tester.ExpectBucketCount(affected_edits_histo, edited_type, 1);
}
@@ -395,7 +456,7 @@ void AddressProfileSaveManagerTest::TestImportScenario(
// Test that a profile is correctly imported when no other profile is stored
// yet.
-TEST_F(AddressProfileSaveManagerTest, SaveNewProfile) {
+TEST_P(AddressProfileSaveManagerTest, SaveNewProfile) {
AutofillProfile observed_profile = test::StandardProfile();
ImportScenarioTestCase test_scenario{
@@ -414,7 +475,7 @@ TEST_F(AddressProfileSaveManagerTest, SaveNewProfile) {
// Test that a profile is correctly imported when no other profile is stored
// yet but another profile is added while waiting for the user response.
-TEST_F(AddressProfileSaveManagerTest, SaveNewProfile_ProfileAddedWhileWaiting) {
+TEST_P(AddressProfileSaveManagerTest, SaveNewProfile_ProfileAddedWhileWaiting) {
AutofillProfile observed_profile = test::StandardProfile();
AutofillProfile profile_added_while_waiting =
test::DifferentFromStandardProfile();
@@ -436,8 +497,8 @@ TEST_F(AddressProfileSaveManagerTest, SaveNewProfile_ProfileAddedWhileWaiting) {
}
// Test that a profile is not imported and that the user is not prompted if the
-// domain is blocked for imorting new profiles.
-TEST_F(AddressProfileSaveManagerTest, SaveNewProfileOnBlockedDomain) {
+// domain is blocked for importing new profiles.
+TEST_P(AddressProfileSaveManagerTest, SaveNewProfileOnBlockedDomain) {
AutofillProfile observed_profile = test::StandardProfile();
ImportScenarioTestCase test_scenario{
@@ -458,7 +519,7 @@ TEST_F(AddressProfileSaveManagerTest, SaveNewProfileOnBlockedDomain) {
// Test that a profile is correctly imported when no other profile is stored
// yet. Here, `kUserNotAsked` is supplied which is done as a fallback in case
// the UI is unavailable for technical reasons.
-TEST_F(AddressProfileSaveManagerTest, SaveNewProfile_UserNotAskedFallback) {
+TEST_P(AddressProfileSaveManagerTest, SaveNewProfile_UserNotAskedFallback) {
AutofillProfile observed_profile = test::StandardProfile();
ImportScenarioTestCase test_scenario{
@@ -477,7 +538,7 @@ TEST_F(AddressProfileSaveManagerTest, SaveNewProfile_UserNotAskedFallback) {
// Test that a profile is correctly imported when no other profile is stored
// yet. Here, the profile is edited by the user.
-TEST_F(AddressProfileSaveManagerTest, SaveNewProfile_Edited) {
+TEST_P(AddressProfileSaveManagerTest, SaveNewProfile_Edited) {
AutofillProfile observed_profile = test::StandardProfile();
AutofillProfile edited_profile = test::DifferentFromStandardProfile();
// The edited profile must have the same GUID then the observed one.
@@ -503,8 +564,32 @@ TEST_F(AddressProfileSaveManagerTest, SaveNewProfile_Edited) {
TestImportScenario(test_scenario);
}
+// Test that the country complemention metric is correctly increased.
+TEST_P(AddressProfileSaveManagerTest, SaveNewProfile_EditedCountry) {
+ AutofillProfile observed_profile = test::StandardProfile();
+ AutofillProfile edited_profile = observed_profile;
+ edited_profile.SetRawInfoWithVerificationStatus(
+ ADDRESS_HOME_COUNTRY, u"DE", VerificationStatus::kObserved);
+
+ ImportScenarioTestCase test_scenario{
+ .existing_profiles = {},
+ .observed_profile = observed_profile,
+ .is_prompt_expected = true,
+ .user_decision = UserDecision::kEditAccepted,
+ .edited_profile = edited_profile,
+ .expected_import_type = AutofillProfileImportType::kNewProfile,
+ .is_profile_change_expected = true,
+ .merge_candidate = absl::nullopt,
+ .import_candidate = observed_profile,
+ .expected_final_profiles = {edited_profile},
+ .expected_edited_types_for_metrics = {
+ AutofillMetrics::SettingsVisibleFieldTypeForMetrics::kCountry}};
+
+ TestImportScenario(test_scenario);
+}
+
// Test that a decline to import a new profile is handled correctly.
-TEST_F(AddressProfileSaveManagerTest, SaveNewProfile_Declined) {
+TEST_P(AddressProfileSaveManagerTest, SaveNewProfile_Declined) {
AutofillProfile observed_profile = test::StandardProfile();
ImportScenarioTestCase test_scenario{
@@ -523,7 +608,7 @@ TEST_F(AddressProfileSaveManagerTest, SaveNewProfile_Declined) {
// Test that a decline to import a new profile in the message UI is handled
// correctly.
-TEST_F(AddressProfileSaveManagerTest, SaveNewProfile_MessageDeclined) {
+TEST_P(AddressProfileSaveManagerTest, SaveNewProfile_MessageDeclined) {
AutofillProfile observed_profile = test::StandardProfile();
ImportScenarioTestCase test_scenario{
@@ -541,7 +626,7 @@ TEST_F(AddressProfileSaveManagerTest, SaveNewProfile_MessageDeclined) {
}
// Test that the observation of a duplicate profile has no effect.
-TEST_F(AddressProfileSaveManagerTest, ImportDuplicateProfile) {
+TEST_P(AddressProfileSaveManagerTest, ImportDuplicateProfile) {
// Note that the profile is created twice to enforce different GUIDs.
AutofillProfile existing_profile = test::StandardProfile();
AutofillProfile observed_profile = test::StandardProfile();
@@ -562,7 +647,7 @@ TEST_F(AddressProfileSaveManagerTest, ImportDuplicateProfile) {
// Test that the observation of quasi identical profile that has a different
// structure in the name will result in a silent update.
-TEST_F(AddressProfileSaveManagerTest, SilentlyUpdateProfile) {
+TEST_P(AddressProfileSaveManagerTest, SilentlyUpdateProfile) {
AutofillProfile observed_profile = test::StandardProfile();
AutofillProfile updateable_profile = test::UpdateableStandardProfile();
AutofillProfile final_profile = observed_profile;
@@ -583,7 +668,7 @@ TEST_F(AddressProfileSaveManagerTest, SilentlyUpdateProfile) {
// Test that the observation of quasi identical profile that has a different
// structure in the name will result in a silent update even though the domain
// is blocked for new profile imports.
-TEST_F(AddressProfileSaveManagerTest, SilentlyUpdateProfileOnBlockedDomain) {
+TEST_P(AddressProfileSaveManagerTest, SilentlyUpdateProfileOnBlockedDomain) {
AutofillProfile observed_profile = test::StandardProfile();
AutofillProfile updateable_profile = test::UpdateableStandardProfile();
AutofillProfile final_profile = observed_profile;
@@ -605,7 +690,7 @@ TEST_F(AddressProfileSaveManagerTest, SilentlyUpdateProfileOnBlockedDomain) {
// Test that the observation of quasi identical profile that has a different
// structure in the name will result in a silent update even when the profile
// has the legacy property of being verified.
-TEST_F(AddressProfileSaveManagerTest, SilentlyUpdateVerifiedProfile) {
+TEST_P(AddressProfileSaveManagerTest, SilentlyUpdateVerifiedProfile) {
AutofillProfile observed_profile = test::StandardProfile();
AutofillProfile updateable_profile = test::UpdateableStandardProfile();
@@ -630,7 +715,7 @@ TEST_F(AddressProfileSaveManagerTest, SilentlyUpdateVerifiedProfile) {
// Test the observation of a profile that can only be merged with a
// settings-visible change. Here, `kUserNotAsked` is returned as the fallback
// mechanism when the UI is not available for technical reasons.
-TEST_F(AddressProfileSaveManagerTest,
+TEST_P(AddressProfileSaveManagerTest,
UserConfirmableMerge_UserNotAskedFallback) {
AutofillProfile observed_profile = test::StandardProfile();
AutofillProfile mergeable_profile = test::SubsetOfStandardProfile();
@@ -653,7 +738,7 @@ TEST_F(AddressProfileSaveManagerTest,
// Test the observation of a profile that can only be merged with a
// settings-visible change.
-TEST_F(AddressProfileSaveManagerTest, UserConfirmableMerge) {
+TEST_P(AddressProfileSaveManagerTest, UserConfirmableMerge) {
AutofillProfile observed_profile = test::StandardProfile();
AutofillProfile mergeable_profile = test::SubsetOfStandardProfile();
AutofillProfile final_profile = observed_profile;
@@ -678,7 +763,7 @@ TEST_F(AddressProfileSaveManagerTest, UserConfirmableMerge) {
// Test the observation of a profile that can only be merged with a
// settings-visible change but the mergeable profile is blocked for updates.
-TEST_F(AddressProfileSaveManagerTest, UserConfirmableMerge_BlockedProfile) {
+TEST_P(AddressProfileSaveManagerTest, UserConfirmableMerge_BlockedProfile) {
AutofillProfile observed_profile = test::StandardProfile();
AutofillProfile mergeable_profile = test::SubsetOfStandardProfile();
AutofillProfile final_profile = observed_profile;
@@ -701,7 +786,7 @@ TEST_F(AddressProfileSaveManagerTest, UserConfirmableMerge_BlockedProfile) {
// Test the observation of a profile that can only be merged with a
// settings-visible change. The existing profile has the legacy property of
// being verified.
-TEST_F(AddressProfileSaveManagerTest, UserConfirmableMerge_VerifiedProfile) {
+TEST_P(AddressProfileSaveManagerTest, UserConfirmableMerge_VerifiedProfile) {
AutofillProfile observed_profile = test::StandardProfile();
AutofillProfile mergeable_profile = test::SubsetOfStandardProfile();
@@ -730,7 +815,7 @@ TEST_F(AddressProfileSaveManagerTest, UserConfirmableMerge_VerifiedProfile) {
// Test the observation of a profile that can only be merged with a
// settings-visible change.
-TEST_F(AddressProfileSaveManagerTest, UserConfirmableMerge_Edited) {
+TEST_P(AddressProfileSaveManagerTest, UserConfirmableMerge_Edited) {
AutofillProfile observed_profile = test::StandardProfile();
AutofillProfile mergeable_profile = test::SubsetOfStandardProfile();
AutofillProfile edited_profile = test::DifferentFromStandardProfile();
@@ -761,7 +846,7 @@ TEST_F(AddressProfileSaveManagerTest, UserConfirmableMerge_Edited) {
// Test the observation of a profile that can only be merged with a
// settings-visible change but the import is declined by the user.
-TEST_F(AddressProfileSaveManagerTest, UserConfirmableMerge_Declined) {
+TEST_P(AddressProfileSaveManagerTest, UserConfirmableMerge_Declined) {
AutofillProfile observed_profile = test::StandardProfile();
AutofillProfile mergeable_profile = test::SubsetOfStandardProfile();
AutofillProfile final_profile = observed_profile;
@@ -783,7 +868,7 @@ TEST_F(AddressProfileSaveManagerTest, UserConfirmableMerge_Declined) {
// Test a mixed scenario in which a duplicate profile already exists, but a
// another profile is mergeable with the observed profile.
-TEST_F(AddressProfileSaveManagerTest, UserConfirmableMergeAndDuplicate) {
+TEST_P(AddressProfileSaveManagerTest, UserConfirmableMergeAndDuplicate) {
AutofillProfile observed_profile = test::StandardProfile();
AutofillProfile existing_duplicate = test::StandardProfile();
AutofillProfile mergeable_profile = test::SubsetOfStandardProfile();
@@ -812,7 +897,7 @@ TEST_F(AddressProfileSaveManagerTest, UserConfirmableMergeAndDuplicate) {
// another profile is mergeable with the observed profile. The result should not
// be affected by the fact that the domain is blocked for the import of new
// profiles.
-TEST_F(AddressProfileSaveManagerTest,
+TEST_P(AddressProfileSaveManagerTest,
UserConfirmableMergeAndDuplicateOnBlockedDomain) {
AutofillProfile observed_profile = test::StandardProfile();
AutofillProfile existing_duplicate = test::StandardProfile();
@@ -842,7 +927,7 @@ TEST_F(AddressProfileSaveManagerTest,
// Test a mixed scenario in which a duplicate profile already exists, but a
// another profile is mergeable with the observed profile and yet another
// profile can be silently updated.
-TEST_F(AddressProfileSaveManagerTest,
+TEST_P(AddressProfileSaveManagerTest,
UserConfirmableMergeAndUpdateAndDuplicate) {
AutofillProfile observed_profile = test::StandardProfile();
AutofillProfile existing_duplicate = test::StandardProfile();
@@ -878,7 +963,7 @@ TEST_F(AddressProfileSaveManagerTest,
}
// Same as above, but the merge candidate is blocked for updates.
-TEST_F(AddressProfileSaveManagerTest,
+TEST_P(AddressProfileSaveManagerTest,
UserConfirmableMergeAndUpdateAndDuplicate_Blocked) {
AutofillProfile observed_profile = test::StandardProfile();
AutofillProfile existing_duplicate = test::StandardProfile();
@@ -912,7 +997,7 @@ TEST_F(AddressProfileSaveManagerTest,
// Test a mixed scenario in which a duplicate profile already exists, but a
// another profile is mergeable with the observed profile and yet another
// profile can be silently updated. Here, the merge is declined.
-TEST_F(AddressProfileSaveManagerTest,
+TEST_P(AddressProfileSaveManagerTest,
UserConfirmableMergeAndUpdateAndDuplicate_Declined) {
AutofillProfile observed_profile = test::StandardProfile();
AutofillProfile existing_duplicate = test::StandardProfile();
@@ -947,7 +1032,7 @@ TEST_F(AddressProfileSaveManagerTest,
// Test a mixed scenario in which a duplicate profile already exists, but a
// another profile is mergeable with the observed profile and yet another
// profile can be silently updated. Here, the merge is accepted with edits.
-TEST_F(AddressProfileSaveManagerTest,
+TEST_P(AddressProfileSaveManagerTest,
UserConfirmableMergeAndUpdateAndDuplicate_Edited) {
AutofillProfile observed_profile = test::StandardProfile();
AutofillProfile existing_duplicate = test::StandardProfile();
@@ -987,7 +1072,7 @@ TEST_F(AddressProfileSaveManagerTest,
TestImportScenario(test_scenario);
}
-TEST_F(AddressProfileSaveManagerTest, SaveProfileWhenNoSavePrompt) {
+TEST_P(AddressProfileSaveManagerTest, SaveProfileWhenNoSavePrompt) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndDisableFeature(
features::kAutofillAddressProfileSavePrompt);
@@ -1003,7 +1088,7 @@ TEST_F(AddressProfileSaveManagerTest, SaveProfileWhenNoSavePrompt) {
// Tests that a new profile is not imported when only silent updates are
// allowed.
-TEST_F(AddressProfileSaveManagerTest, SilentlyUpdateProfile_SaveNewProfile) {
+TEST_P(AddressProfileSaveManagerTest, SilentlyUpdateProfile_SaveNewProfile) {
AutofillProfile observed_profile = test::StandardProfile();
ImportScenarioTestCase test_scenario{
@@ -1023,7 +1108,7 @@ TEST_F(AddressProfileSaveManagerTest, SilentlyUpdateProfile_SaveNewProfile) {
// Test that the observation of quasi identical profile that has a different
// structure in the name will result in a silent update when only silent updates
// are allowed.
-TEST_F(AddressProfileSaveManagerTest,
+TEST_P(AddressProfileSaveManagerTest,
SilentlyUpdateProfile_WithIncompleteProfile) {
AutofillProfile observed_profile = test::StandardProfile();
AutofillProfile updateable_profile = test::UpdateableStandardProfile();
@@ -1045,7 +1130,7 @@ TEST_F(AddressProfileSaveManagerTest,
// Tests that the profile's structured name information is silently updated when
// an updated profile is observed with no settings visible difference.
// Silent Update is enabled for the test.
-TEST_F(AddressProfileSaveManagerTest,
+TEST_P(AddressProfileSaveManagerTest,
SilentlyUpdateProfile_UpdateStructuredName) {
AutofillProfile updateable_profile;
test::SetProfileTestValues(
@@ -1094,7 +1179,7 @@ TEST_F(AddressProfileSaveManagerTest,
// an updated profile with no address data is observed with no settings visible
// difference.
// Silent Update is enabled for the test.
-TEST_F(AddressProfileSaveManagerTest,
+TEST_P(AddressProfileSaveManagerTest,
SilentlyUpdateProfile_UpdateStructuredNameWithIncompleteProfile) {
AutofillProfile updateable_profile;
test::SetProfileTestValues(
@@ -1148,7 +1233,7 @@ TEST_F(AddressProfileSaveManagerTest,
// Test that the observation of quasi identical profile that has a different
// structure in the name will result in a silent update even though the domain
// is blocked for new profile imports when silent updates are enforced.
-TEST_F(AddressProfileSaveManagerTest, SilentlyUpdateProfile_OnBlockedDomain) {
+TEST_P(AddressProfileSaveManagerTest, SilentlyUpdateProfile_OnBlockedDomain) {
AutofillProfile observed_profile = test::StandardProfile();
AutofillProfile updateable_profile = test::UpdateableStandardProfile();
AutofillProfile final_profile = observed_profile;
@@ -1171,7 +1256,7 @@ TEST_F(AddressProfileSaveManagerTest, SilentlyUpdateProfile_OnBlockedDomain) {
// another profile is mergeable with the observed profile and yet another
// profile can be silently updated. Only silent updates are allowed for this
// test.
-TEST_F(AddressProfileSaveManagerTest,
+TEST_P(AddressProfileSaveManagerTest,
SilentlyUpdateProfile_UserConfirmableMergeAndUpdateAndDuplicate) {
AutofillProfile observed_profile = test::StandardProfile();
AutofillProfile existing_duplicate = test::StandardProfile();
@@ -1200,7 +1285,7 @@ TEST_F(AddressProfileSaveManagerTest,
// Tests that the mergeable profiles are not merged when only silent updates
// are allowed.
-TEST_F(AddressProfileSaveManagerTest,
+TEST_P(AddressProfileSaveManagerTest,
SilentlyUpdateProfile_UserConfirmableMergeNotAllowed) {
AutofillProfile observed_profile = test::StandardProfile();
AutofillProfile mergeable_profile = test::SubsetOfStandardProfile();
@@ -1219,6 +1304,12 @@ TEST_F(AddressProfileSaveManagerTest,
TestImportScenario(test_scenario);
}
+// Runs the suite as if the the country was (not) complemented using
+// |kAutofillComplementCountryCodeOnImport|.
+INSTANTIATE_TEST_SUITE_P(,
+ AddressProfileSaveManagerTest,
+ testing::Combine(testing::Bool()));
+
} // namespace
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autocomplete_history_manager_unittest.cc b/chromium/components/autofill/core/browser/autocomplete_history_manager_unittest.cc
index 60da4caed52..e296b91493c 100644
--- a/chromium/components/autofill/core/browser/autocomplete_history_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/autocomplete_history_manager_unittest.cc
@@ -338,7 +338,7 @@ TEST_F(AutocompleteHistoryManagerTest, Incognito) {
/*is_autocomplete_enabled=*/true);
}
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
// Tests that fields that are no longer focusable but still have user typed
// input are sent to the WebDatabase to be saved. Will not work for iOS
// because |properties_mask| is not set on iOS.
diff --git a/chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.css b/chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.css
deleted file mode 100644
index c5059c2ed25..00000000000
--- a/chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.css
+++ /dev/null
@@ -1,256 +0,0 @@
-/* Copyright 2019 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.
- */
-
-html {
- scroll-behavior: smooth;
-}
-
-.sticky-bar {
- background-color: white;
- border-bottom: 1px solid black;
- color: black;
- overflow: auto;
- padding-bottom: 1.5ex;
- position: sticky;
- top: 0;
-}
-
-#log-display-config {
- display: none; /* only visible for Autofill, not for Password Manager */
- font-size: 120%;
- padding: 1ex;
-}
-
-#log-display-config label {
- padding-inline-end: 1em;
-}
-
-.fake-button {
- background-color: lightgray;
- border: 1px solid black;
- margin-inline-end: 1em;
- padding: .5ex;
-}
-
-#logging-note {
- font-style: italic;
-}
-
-#logging-note-incognito {
- font-style: italic;
-}
-
-/* Initially, nothing is visible, to avoid flicker. */
-#log-entries,
-#logging-note,
-#logging-note-incognito {
- display: none;
-}
-
-/* Visibility settings for non-Incognito tabs. */
-[data-incognito=false] #log-entries,
-[data-incognito=false] #logging-note {
- display: block;
-}
-
-/* Visibility settings for Incognito tabs. */
-[data-incognito=true] #logging-note-incognito {
- display: block;
-}
-
-#version-info {
- margin: 3px;
- padding: 3px;
-}
-
-.version {
- font-family: monospace;
- max-width: 430px;
- padding-inline-start: 5px;
- vertical-align: top;
- word-break: break-word;
-}
-
-.label {
- font-family: monospace;
- font-weight: 200;
- vertical-align: top;
-}
-
-.log-entry,
-.marker {
- padding: 3px;
-}
-
-.marker {
- background-color: red;
- font-size: 200%;
- overflow-wrap: break-word;
- white-space: normal;
- word-wrap: break-word;
-}
-
-.marker::before {
- content: 'Position marked: ';
-}
-
-/*
- * Colors can be taken from
- * https://material.io/design/color/#tools-for-picking-colors
- * Pick the rows of entries labeled with 100
- */
-
-.log-entry[scope='Context'] {
- background-color: #F5F5F5;
-}
-
-.log-entry[scope='Parsing'] {
- background-color: #FFECB3;
-}
-
-.log-entry[scope='AbortParsing'] {
- background-color: #FFCDD2;
-}
-
-.log-entry[scope='Filling'] {
- background-color: #D1C4E9;
-}
-
-.log-entry[scope='Submission'] {
- background-color: #BBDEFB;
-}
-
-.log-entry[scope='AutofillServer'] {
- background-color: #D7CCC8;
-}
-
-.log-entry[scope='Metrics'] {
- background-color: #B2EBF2;
-}
-
-.log-entry[scope='AddressProfileFormImport'] {
- background-color: #BFFBF2;
-}
-
-.log-entry[scope='CreditCardUploadStatus'] {
- background-color: #4DB6AC;
-}
-
-.log-entry[scope='CardUploadDecision'] {
- background-color: #4DD0E1;
-}
-
-.log-entry[scope='Rationalization'] {
- background-color: #F8BBD0;
-}
-
-/*
- * Checkboxes add/remove hide-<Scope> classes to the #log-entries. Hiding of the
- * relevant <div>'s and adjacent <hr>'s is implemented by these classes.
- */
-
-.hide-Context .log-entry[scope='Context'],
-.hide-Context .log-entry[scope='Context'] + hr {
- display: none;
-}
-
-.hide-Parsing .log-entry[scope='Parsing'],
-.hide-Parsing .log-entry[scope='Parsing'] + hr {
- display: none;
-}
-
-.hide-AbortParsing .log-entry[scope='AbortParsing'],
-.hide-AbortParsing .log-entry[scope='AbortParsing'] + hr {
- display: none;
-}
-
-.hide-Filling .log-entry[scope='Filling'],
-.hide-Filling .log-entry[scope='Filling'] + hr {
- display: none;
-}
-
-.hide-Submission .log-entry[scope='Submission'],
-.hide-Submission .log-entry[scope='Submission'] + hr {
- display: none;
-}
-
-.hide-AutofillServer .log-entry[scope='AutofillServer'],
-.hide-AutofillServer .log-entry[scope='AutofillServer'] + hr {
- display: none;
-}
-
-.hide-Metrics .log-entry[scope='Metrics'],
-.hide-Metrics .log-entry[scope='Metrics'] + hr {
- display: none;
-}
-
-.hide-AddressProfileFormImport .log-entry[scope='AddressProfileFormImport'],
-.hide-AddressProfileFormImport .log-entry[scope='AddressProfileFormImport'] + hr {
- display: none;
-}
-
-.hide-CreditCardUploadStatus .log-entry[scope='CreditCardUploadStatus'],
-.hide-CreditCardUploadStatus .log-entry[scope='CreditCardUploadStatus'] + hr {
- display: none;
-}
-
-.hide-CardUploadDecision .log-entry[scope='CardUploadDecision'],
-.hide-CardUploadDecision .log-entry[scope='CardUploadDecision'] + hr {
- display: none;
-}
-
-.form {
- border: 1px black solid;
- margin: 3px;
- padding: 3px;
-}
-
-.form td {
- vertical-align: text-top;
-}
-
-.profile_import_from_form_section {
- border: 1px black solid;
- margin: 3px;
- padding: 3px;
-}
-
-.profile_import_from_form_section td {
- vertical-align: text-top;
-}
-
-.country_data {
- border: 1px black solid;
- margin: 3px;
- padding: 3px;
-}
-
-.country_data td {
- vertical-align: text-top;
-}
-
-.modal-dialog {
- background-color: rgb(255, 255, 255);
- border: 1px solid rgb(0, 0, 0);
- display: block;
- height: 100px;
- left: 10%;
- overflow: auto;
- position: fixed;
- right: 10%;
- top: 10%;
- width: 80%;
- z-index: 1;
-}
-
-.modal-dialog-content {
- padding: 20px;
-}
-
-.modal-dialog-close-button {
- bottom: 20px;
- position: absolute;
- right: 20px;
-}
diff --git a/chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.html b/chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.html
index 053bce9837c..3f3c331071b 100644
--- a/chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.html
+++ b/chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.html
@@ -7,7 +7,264 @@
<meta charset="utf-8">
<script type="module" src="autofill_and_password_manager_internals.js"></script>
<link rel="stylesheet" href="chrome://resources/css/chrome_shared.css">
-<link rel="stylesheet" href="autofill_and_password_manager_internals.css">
+<!--
+ The style sheets are inlined to get a prettier export if the user presses
+ Ctrl/Cmd + S to save the site or presses the download button.
+-->
+<style>
+html {
+ scroll-behavior: smooth;
+}
+
+.sticky-bar {
+ background-color: white;
+ border-bottom: 1px solid black;
+ color: black;
+ overflow: auto;
+ padding-bottom: 1.5ex;
+ position: sticky;
+ top: 0;
+}
+
+#log-display-config {
+ display: none; /* only visible for Autofill, not for Password Manager */
+ font-size: 120%;
+ padding: 1ex;
+}
+
+#log-display-config label {
+ padding-inline-end: 1em;
+}
+
+.fake-button {
+ background-color: lightgray;
+ border: 1px solid black;
+ margin-inline-end: 1em;
+ padding: .5ex;
+}
+
+#logging-note {
+ font-style: italic;
+}
+
+#logging-note-incognito {
+ font-style: italic;
+}
+
+/* Initially, nothing is visible, to avoid flicker. */
+#log-entries,
+#logging-note,
+#logging-note-incognito {
+ display: none;
+}
+
+/* Visibility settings for non-Incognito tabs. */
+[data-incognito=false] #log-entries,
+[data-incognito=false] #logging-note {
+ display: block;
+}
+
+/* Visibility settings for Incognito tabs. */
+[data-incognito=true] #logging-note-incognito {
+ display: block;
+}
+
+#version-info {
+ margin: 3px;
+ padding: 3px;
+}
+
+.version {
+ font-family: monospace;
+ max-width: 430px;
+ padding-inline-start: 5px;
+ vertical-align: top;
+ word-break: break-word;
+}
+
+.label {
+ font-family: monospace;
+ font-weight: 200;
+ vertical-align: top;
+}
+
+.log-entry,
+.marker {
+ padding: 3px;
+}
+
+.marker {
+ background-color: red;
+ font-size: 200%;
+ overflow-wrap: break-word;
+ white-space: normal;
+ word-wrap: break-word;
+}
+
+.marker::before {
+ content: 'Position marked: ';
+}
+
+/*
+ * Colors can be taken from
+ * https://material.io/design/color/#tools-for-picking-colors
+ * Pick the rows of entries labeled with 100
+ */
+
+.log-entry[scope='Context'] {
+ background-color: #F5F5F5;
+}
+
+.log-entry[scope='Parsing'] {
+ background-color: #FFECB3;
+}
+
+.log-entry[scope='AbortParsing'] {
+ background-color: #FFCDD2;
+}
+
+.log-entry[scope='Filling'] {
+ background-color: #D1C4E9;
+}
+
+.log-entry[scope='Submission'] {
+ background-color: #BBDEFB;
+}
+
+.log-entry[scope='AutofillServer'] {
+ background-color: #D7CCC8;
+}
+
+.log-entry[scope='Metrics'] {
+ background-color: #B2EBF2;
+}
+
+.log-entry[scope='AddressProfileFormImport'] {
+ background-color: #BFFBF2;
+}
+
+.log-entry[scope='CreditCardUploadStatus'] {
+ background-color: #4DB6AC;
+}
+
+.log-entry[scope='CardUploadDecision'] {
+ background-color: #4DD0E1;
+}
+
+.log-entry[scope='Rationalization'] {
+ background-color: #F8BBD0;
+}
+
+/*
+ * Checkboxes add/remove hide-<Scope> classes to the #log-entries. Hiding of the
+ * relevant <div>'s and adjacent <hr>'s is implemented by these classes.
+ */
+
+.hide-Context .log-entry[scope='Context'],
+.hide-Context .log-entry[scope='Context'] + hr {
+ display: none;
+}
+
+.hide-Parsing .log-entry[scope='Parsing'],
+.hide-Parsing .log-entry[scope='Parsing'] + hr {
+ display: none;
+}
+
+.hide-AbortParsing .log-entry[scope='AbortParsing'],
+.hide-AbortParsing .log-entry[scope='AbortParsing'] + hr {
+ display: none;
+}
+
+.hide-Filling .log-entry[scope='Filling'],
+.hide-Filling .log-entry[scope='Filling'] + hr {
+ display: none;
+}
+
+.hide-Submission .log-entry[scope='Submission'],
+.hide-Submission .log-entry[scope='Submission'] + hr {
+ display: none;
+}
+
+.hide-AutofillServer .log-entry[scope='AutofillServer'],
+.hide-AutofillServer .log-entry[scope='AutofillServer'] + hr {
+ display: none;
+}
+
+.hide-Metrics .log-entry[scope='Metrics'],
+.hide-Metrics .log-entry[scope='Metrics'] + hr {
+ display: none;
+}
+
+.hide-AddressProfileFormImport .log-entry[scope='AddressProfileFormImport'],
+.hide-AddressProfileFormImport .log-entry[scope='AddressProfileFormImport'] + hr {
+ display: none;
+}
+
+.hide-CreditCardUploadStatus .log-entry[scope='CreditCardUploadStatus'],
+.hide-CreditCardUploadStatus .log-entry[scope='CreditCardUploadStatus'] + hr {
+ display: none;
+}
+
+.hide-CardUploadDecision .log-entry[scope='CardUploadDecision'],
+.hide-CardUploadDecision .log-entry[scope='CardUploadDecision'] + hr {
+ display: none;
+}
+
+.form {
+ border: 1px black solid;
+ margin: 3px;
+ padding: 3px;
+}
+
+.form td {
+ vertical-align: text-top;
+}
+
+.profile_import_from_form_section {
+ border: 1px black solid;
+ margin: 3px;
+ padding: 3px;
+}
+
+.profile_import_from_form_section td {
+ vertical-align: text-top;
+}
+
+.country_data {
+ border: 1px black solid;
+ margin: 3px;
+ padding: 3px;
+}
+
+.country_data td {
+ vertical-align: text-top;
+}
+
+.modal-dialog {
+ background-color: rgb(255, 255, 255);
+ border: 1px solid rgb(0, 0, 0);
+ display: block;
+ height: 100px;
+ left: 10%;
+ overflow: auto;
+ position: fixed;
+ right: 10%;
+ top: 10%;
+ width: 80%;
+ z-index: 1;
+}
+
+.modal-dialog-content {
+ padding: 20px;
+}
+
+.modal-dialog-close-button {
+ bottom: 20px;
+ position: absolute;
+ right: 20px;
+}
+
+</style>
</head>
<body>
<div>
diff --git a/chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.js b/chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.js
index bd58b706bb9..c0d974393ed 100644
--- a/chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.js
+++ b/chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.js
@@ -300,6 +300,12 @@ function setUpLogDisplayConfig() {
window.URL.revokeObjectURL(url);
a.remove();
});
+// <if expr="is_ios">
+ // Hide this until downloading a file works on iOS, see
+ // https://bugs.webkit.org/show_bug.cgi?id=167341
+ // https://bugs.chromium.org/p/chromium/issues/detail?id=1252380
+ downloadFakeButton.style = 'display: none';
+// </if>
}
document.addEventListener('DOMContentLoaded', function(event) {
diff --git a/chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals_ios.html b/chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals_ios.html
deleted file mode 100644
index e88900fcce9..00000000000
--- a/chromium/components/autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals_ios.html
+++ /dev/null
@@ -1,51 +0,0 @@
-<!doctype html>
-<html>
-<head>
-<!-- Copyright 2019 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. -->
-<meta charset="utf-8">
-<script type="module" src="autofill_and_password_manager_internals.js"></script>
-<link rel="stylesheet" href="chrome://resources/css/chrome_shared.css">
-<link rel="stylesheet" href="autofill_and_password_manager_internals.css">
-</head>
-<body>
-<div>
- <h1 id="h1-title"></h1>
- <div id="log-display-config">
- <span id="marker-fake-button">Add Marker</span>
- <input type="checkbox" id="enable-autoscroll" checked><label for="enable-autoscroll">Enable autoscroll</label>
- </div>
-</div>
-<div id="logging-note"></div>
-<div id="logging-note-incognito"></div>
-<div id="version-info">
- <table>
- <tr>
- <td class="label">Version:</td>
- <td class="version"><span>$i18n{version}</span>
- (<span>$i18n{official}</span>)
- <span>$i18n{version_modifier}</span></td>
- </tr>
- <tr>
- <td class="label">Revision:</td>
- <td class="version"><span>$i18n{cl}</span></td>
- </tr>
- <tr>
- <td class="label">User Agent:</td>
- <td class="version"><span>$i18n{useragent}</span></td>
- </tr>
- <tr>
- <td class="label">App Locale:</td>
- <td class="version"><span>$i18n{app_locale}</span></td>
- </tr>
- <tr>
- <td class="label">Variations:</td>
- <td class="version" id="variations-list"></td>
- </tr>
- </table>
-</div>
-<div id="log-entries">
-</div>
-</body>
-</html>
diff --git a/chromium/components/autofill/core/browser/autofill_client.cc b/chromium/components/autofill/core/browser/autofill_client.cc
index 8574bad181c..babc0f11685 100644
--- a/chromium/components/autofill/core/browser/autofill_client.cc
+++ b/chromium/components/autofill/core/browser/autofill_client.cc
@@ -5,8 +5,10 @@
#include "components/autofill/core/browser/autofill_client.h"
#include "base/no_destructor.h"
+#include "build/build_config.h"
#include "components/autofill/core/browser/autofill_ablation_study.h"
#include "components/autofill/core/browser/payments/credit_card_access_manager.h"
+#include "components/autofill/core/browser/payments/virtual_card_enrollment_manager.h"
#include "components/autofill/core/browser/single_field_form_fill_router.h"
#include "components/autofill/core/browser/ui/suggestion.h"
#include "components/version_info/channel.h"
@@ -74,7 +76,29 @@ void AutofillClient::DismissUnmaskAuthenticatorSelectionDialog(
// ChromeAutofillClient (Chrome Desktop and Clank) implements this.
}
-#if !defined(OS_IOS)
+raw_ptr<VirtualCardEnrollmentManager>
+AutofillClient::GetVirtualCardEnrollmentManager() {
+ // This is overridden by platform subclasses. Currently only
+ // ChromeAutofillClient (Chrome Desktop and Clank) implements this.
+ return nullptr;
+}
+
+void AutofillClient::ShowVirtualCardEnrollDialog(
+ const VirtualCardEnrollmentFields& virtual_card_enrollment_fields,
+ base::OnceClosure accept_virtual_card_callback,
+ base::OnceClosure decline_virtual_card_callback) {
+ // This is overridden by platform subclasses. Currently only
+ // ChromeAutofillClient (Chrome Desktop and Clank) implements this.
+}
+
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
+void AutofillClient::HideVirtualCardEnrollBubbleAndIconIfVisible() {
+ // This is overridden by platform subclasses. Currently only
+ // ChromeAutofillClient (Chrome Desktop) implements this.
+}
+#endif
+
+#if !BUILDFLAG(IS_IOS)
std::unique_ptr<webauthn::InternalAuthenticator>
AutofillClient::CreateCreditCardInternalAuthenticator(
content::RenderFrameHost* rfh) {
@@ -95,8 +119,13 @@ void AutofillClient::OnUnmaskOtpVerificationResult(
// ChromeAutofillClient (Chrome Desktop and Clank) implements this.
}
-void AutofillClient::ShowOfferNotificationIfApplicable(
- const AutofillOfferData* offer) {
+void AutofillClient::UpdateOfferNotification(const AutofillOfferData* offer,
+ bool notification_has_been_shown) {
+ // This is overridden by platform subclasses. Currently only
+ // ChromeAutofillClient (Chrome Desktop and Clank) implement this.
+}
+
+void AutofillClient::DismissOfferNotification() {
// This is overridden by platform subclasses. Currently only
// ChromeAutofillClient (Chrome Desktop and Clank) implements this.
}
diff --git a/chromium/components/autofill/core/browser/autofill_client.h b/chromium/components/autofill/core/browser/autofill_client.h
index 12582c581c2..c6e4fd3d173 100644
--- a/chromium/components/autofill/core/browser/autofill_client.h
+++ b/chromium/components/autofill/core/browser/autofill_client.h
@@ -29,7 +29,7 @@
#include "ui/gfx/image/image.h"
#include "url/gurl.h"
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
#include "components/webauthn/core/browser/internal_authenticator.h"
#endif
@@ -59,10 +59,12 @@ namespace autofill {
class AddressNormalizer;
class AutofillAblationStudy;
+struct AutofillOfferData;
class AutofillProfile;
class AutocompleteHistoryManager;
class AutofillOfferManager;
class AutofillPopupDelegate;
+struct CardUnmaskChallengeOption;
class CardUnmaskDelegate;
class CreditCard;
enum class CreditCardFetchResult;
@@ -75,11 +77,11 @@ enum class OtpUnmaskResult;
class PersonalDataManager;
class SingleFieldFormFillRouter;
class StrikeDatabase;
+struct Suggestion;
+struct VirtualCardEnrollmentFields;
+class VirtualCardEnrollmentManager;
enum class WebauthnDialogCallbackType;
enum class WebauthnDialogState;
-struct AutofillOfferData;
-struct CardUnmaskChallengeOption;
-struct Suggestion;
namespace payments {
class PaymentsClient;
@@ -369,7 +371,7 @@ class AutofillClient : public RiskDataLoader {
// Returns the profile type of the session.
virtual profile_metrics::BrowserProfileType GetProfileType() const;
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
// Creates the appropriate implementation of InternalAuthenticator. May be
// null for platforms that don't support this, in which case standard CVC
// authentication will be used instead.
@@ -411,7 +413,23 @@ class AutofillClient : public RiskDataLoader {
// and we can move on to the next portion of this flow.
virtual void DismissUnmaskAuthenticatorSelectionDialog(bool server_success);
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+ // Returns a pointer to a VirtualCardEnrollmentManager that is owned by
+ // AutofillClient. VirtualCardEnrollmentManager is used for virtual card
+ // enroll and unenroll related flows. This function may return a nullptr on
+ // some platforms.
+ virtual raw_ptr<VirtualCardEnrollmentManager>
+ GetVirtualCardEnrollmentManager();
+
+ // Shows a dialog for the user to enroll in a virtual card.
+ virtual void ShowVirtualCardEnrollDialog(
+ const VirtualCardEnrollmentFields& virtual_card_enrollment_fields,
+ base::OnceClosure accept_virtual_card_callback,
+ base::OnceClosure decline_virtual_card_callback);
+
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
+ // Hides the virtual card enroll bubble and icon if it is visible.
+ virtual void HideVirtualCardEnrollBubbleAndIconIfVisible();
+
// Returns the list of allowed merchants and BIN ranges for virtual cards.
virtual std::vector<std::string> GetAllowedMerchantsForVirtualCards() = 0;
virtual std::vector<std::string> GetAllowedBinRangesForVirtualCards() = 0;
@@ -480,7 +498,7 @@ class AutofillClient : public RiskDataLoader {
const std::vector<CreditCard*>& candidates,
base::OnceCallback<void(const std::string&)> callback) = 0;
-#else // defined(OS_ANDROID) || defined(OS_IOS)
+#else // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
// Display the cardholder name fix flow prompt and run the |callback| if
// the card should be uploaded to payments with updated name from the user.
virtual void ConfirmAccountNameFixFlow(
@@ -587,12 +605,14 @@ class AutofillClient : public RiskDataLoader {
// TODO(crbug.com/1093057): Rename all the "domain" in this flow to origin.
// The server is passing down full origin of the
// urls. "Domain" is no longer accurate.
- // Will show a bubble or infobar indicating that the current web domain has an
- // eligible offer or reward if no other notification bubble is currently
- // visible. See bubble controller for details. The bubble is sticky over a set
- // of domains given in the offer.
- virtual void ShowOfferNotificationIfApplicable(
- const AutofillOfferData* offer);
+ // Notifies the client to update the offer notification when the |offer| is
+ // available. |notification_has_been_shown| indicates whether this
+ // notification has been shown since profile start-up.
+ virtual void UpdateOfferNotification(const AutofillOfferData* offer,
+ bool notification_has_been_shown);
+
+ // Dismiss any visible offer notification on the current tab.
+ virtual void DismissOfferNotification();
// Called when the virtual card has been fetched successfully.
// |masked_card_identifier_string| is the network + last four digits of
@@ -622,6 +642,9 @@ class AutofillClient : public RiskDataLoader {
// Whether the Autocomplete feature of Autofill should be enabled.
virtual bool IsAutocompleteEnabled() = 0;
+ // Returns whether password management is enabled as per the user preferences.
+ virtual bool IsPasswordManagerEnabled() = 0;
+
// Pass the form structures to the password manager to choose correct username
// and to the password generation manager to detect account creation forms.
virtual void PropagateAutofillPredictions(
@@ -652,7 +675,7 @@ class AutofillClient : public RiskDataLoader {
virtual const AutofillAblationStudy& GetAblationStudy() const;
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
// Checks whether the current query is the most recent one.
virtual bool IsQueryIDRelevant(int query_id) = 0;
#endif
diff --git a/chromium/components/autofill/core/browser/autofill_download_manager.cc b/chromium/components/autofill/core/browser/autofill_download_manager.cc
index 37a26b31ef7..ee7d430c303 100644
--- a/chromium/components/autofill/core/browser/autofill_download_manager.cc
+++ b/chromium/components/autofill/core/browser/autofill_download_manager.cc
@@ -5,7 +5,6 @@
#include "components/autofill/core/browser/autofill_download_manager.h"
#include <algorithm>
-#include <tuple>
#include <utility>
#include "base/base64url.h"
@@ -361,17 +360,6 @@ std::ostream& operator<<(std::ostream& out,
}
out << "]";
- out << "\n (autofill_type, validity_states): [";
- for (const auto& type_validities : field.autofill_type_validities()) {
- out << "(type: " << type_validities.type() << ", validities: {";
- for (int i = 0; i < type_validities.validity_size(); ++i) {
- if (i)
- out << ", ";
- out << type_validities.validity(i);
- }
- out << "})";
- }
- out << "]\n";
if (!field.name().empty())
out << "\n name: " << field.name();
if (!field.autocomplete().empty())
@@ -448,15 +436,6 @@ LogBuffer& operator<<(LogBuffer& out,
types_as_strings.emplace_back(FieldTypeToString(type));
out << Tr{} << "autofill_type:" << types_as_strings;
- LogBuffer validities;
- validities << Tag{"span"} << "[";
- for (const auto& type_validities : field.autofill_type_validities()) {
- validities << "(type: " << type_validities.type()
- << ", validities: " << type_validities.validity() << ")";
- }
- validities << "]";
- out << Tr{} << "validity_states" << std::move(validities);
-
if (!field.name().empty())
out << Tr{} << "name:" << field.name();
if (!field.autocomplete().empty())
@@ -829,9 +808,7 @@ bool AutofillDownloadManager::StartRequest(FormRequestData request_data) {
DCHECK(url_loader_factory);
// Get the URL and method to use for this request.
- std::string method;
- GURL request_url;
- std::tie(request_url, method) = GetRequestURLAndMethod(request_data);
+ auto [request_url, method] = GetRequestURLAndMethod(request_data);
// Track the URL length for GET queries because the URL length can be in the
// thousands when rich metadata is enabled.
@@ -849,7 +826,7 @@ bool AutofillDownloadManager::StartRequest(FormRequestData request_data) {
// On iOS we have a single, shared URLLoaderFactory provided by BrowserState.
// As it is shared, it is not trusted and we cannot assign trusted_params
// to the network request.
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
// Do not call IsolationInfo() for REQUEST_UPLOADs because Password Manager
// uploads when RenderFrameHostImpl::DidCommitNavigation() is called, in which
// case IsolationInfo() may crash because there is no committing
diff --git a/chromium/components/autofill/core/browser/autofill_download_manager_unittest.cc b/chromium/components/autofill/core/browser/autofill_download_manager_unittest.cc
index 14b4bec32df..ee86766a314 100644
--- a/chromium/components/autofill/core/browser/autofill_download_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_download_manager_unittest.cc
@@ -1409,7 +1409,7 @@ class AutofillServerCommunicationTest
case COMMAND_LINE_URL:
scoped_command_line_.GetProcessCommandLine()->AppendSwitchASCII(
switches::kAutofillServerURL, autofill_server_url.spec());
- FALLTHROUGH;
+ [[fallthrough]];
case DEFAULT_URL:
scoped_feature_list_2_.InitAndEnableFeature(
features::kAutofillServerCommunication);
diff --git a/chromium/components/autofill/core/browser/autofill_driver.h b/chromium/components/autofill/core/browser/autofill_driver.h
index 1860516de0a..5506d33dd45 100644
--- a/chromium/components/autofill/core/browser/autofill_driver.h
+++ b/chromium/components/autofill/core/browser/autofill_driver.h
@@ -17,7 +17,7 @@
#include "ui/accessibility/ax_tree_id.h"
#include "url/origin.h"
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
#include "components/webauthn/core/browser/internal_authenticator.h"
#endif
@@ -60,7 +60,7 @@ class AutofillDriver {
// Returns true iff the renderer is available for communication.
virtual bool RendererIsAvailable() = 0;
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
// Gets or creates a pointer to an implementation of InternalAuthenticator.
virtual webauthn::InternalAuthenticator*
GetOrCreateCreditCardInternalAuthenticator() = 0;
diff --git a/chromium/components/autofill/core/browser/autofill_experiments.cc b/chromium/components/autofill/core/browser/autofill_experiments.cc
index 7e251252569..ae24637c54e 100644
--- a/chromium/components/autofill/core/browser/autofill_experiments.cc
+++ b/chromium/components/autofill/core/browser/autofill_experiments.cc
@@ -35,7 +35,7 @@
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/ui_base_features.h"
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
#include "base/mac/mac_util.h"
#endif
@@ -255,10 +255,10 @@ bool IsCreditCardFidoAuthenticationEnabled() {
if (base::FeatureList::IsEnabled(features::kAutofillCreditCardAuthentication))
return true;
-#if defined(OS_WIN) || defined(OS_ANDROID)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_ANDROID)
// Better Auth project is fully launched on Windows and Clank.
return true;
-#elif defined(OS_MAC)
+#elif BUILDFLAG(IS_MAC)
// Mac OS X 10.12 and earlier has a OS-level bug that causes crashes,
// therefore only enable for 10.13+.
return base::mac::IsAtLeastOS10_13();
diff --git a/chromium/components/autofill/core/browser/autofill_external_delegate.cc b/chromium/components/autofill/core/browser/autofill_external_delegate.cc
index a6e66c8b47f..c523feb77e6 100644
--- a/chromium/components/autofill/core/browser/autofill_external_delegate.cc
+++ b/chromium/components/autofill/core/browser/autofill_external_delegate.cc
@@ -32,7 +32,7 @@
#include "ui/accessibility/platform/ax_platform_node.h"
#include "ui/base/l10n/l10n_util.h"
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
#include "ui/native_theme/native_theme.h" // nogncheck
#endif
@@ -89,7 +89,7 @@ void AutofillExternalDelegate::OnSuggestionsReturned(
bool is_all_server_suggestions) {
if (query_id != query_id_)
return;
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
if (!manager_->client()->IsQueryIDRelevant(query_id))
return;
#endif
@@ -129,8 +129,8 @@ void AutofillExternalDelegate::OnSuggestionsReturned(
// Append the "Hide Suggestions" menu item for only Autofill Address and
// Autocomplete popups.
-#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_APPLE) || \
- defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_APPLE) || \
+ BUILDFLAG(IS_CHROMEOS)
if (base::FeatureList::IsEnabled(
features::kAutofillEnableHideSuggestionsUI)) {
// If the user has selected a suggestion, it indicates the suggestions are
@@ -231,16 +231,23 @@ void AutofillExternalDelegate::OnPopupSuppressed() {
manager_->DidSuppressPopup(query_form_, query_field_);
}
-void AutofillExternalDelegate::DidSelectSuggestion(const std::u16string& value,
- int frontend_id) {
+void AutofillExternalDelegate::DidSelectSuggestion(
+ const std::u16string& value,
+ int frontend_id,
+ const std::string& backend_id) {
ClearPreviewedForm();
- // Only preview the data if it is a profile.
- if (frontend_id > 0)
+ // Only preview the data if it is a profile or a virtual card.
+ if (frontend_id > 0) {
FillAutofillFormData(frontend_id, true);
- else if (frontend_id == POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY)
+ } else if (frontend_id == POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY) {
driver_->RendererShouldPreviewFieldWithValue(query_field_.global_id(),
value);
+ } else if (frontend_id == POPUP_ITEM_ID_VIRTUAL_CREDIT_CARD_ENTRY) {
+ manager_->FillOrPreviewVirtualCardInformation(
+ mojom::RendererFormDataAction::kPreview, backend_id, query_id_,
+ query_form_, query_field_);
+ }
}
void AutofillExternalDelegate::DidAcceptSuggestion(
@@ -279,7 +286,7 @@ void AutofillExternalDelegate::DidAcceptSuggestion(
// No-op as the popup will be closed in the end of the method.
manager_->OnUserHideSuggestions(query_form_, query_field_);
} else if (frontend_id == POPUP_ITEM_ID_USE_VIRTUAL_CARD) {
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
manager_->FetchVirtualCardCandidates();
#else
NOTREACHED();
@@ -288,8 +295,9 @@ void AutofillExternalDelegate::DidAcceptSuggestion(
// There can be multiple virtual credit cards that all rely on
// POPUP_ITEM_ID_VIRTUAL_CREDIT_CARD_ENTRY as a frontend_id. In this case,
// the backend_id identifies the actually chosen credit card.
- manager_->FillVirtualCardInformation(backend_id, query_id_, query_form_,
- query_field_);
+ manager_->FillOrPreviewVirtualCardInformation(
+ mojom::RendererFormDataAction::kFill, backend_id, query_id_,
+ query_form_, query_field_);
} else {
if (frontend_id > 0) { // Denotes an Autofill suggestion.
AutofillMetrics::LogAutofillSuggestionAcceptedIndex(
@@ -420,7 +428,7 @@ void AutofillExternalDelegate::ApplyAutofillOptions(
if (query_field_.is_autofilled) {
std::u16string value =
l10n_util::GetStringUTF16(IDS_AUTOFILL_CLEAR_FORM_MENU_ITEM);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
if (IsKeyboardAccessoryEnabled())
value = base::i18n::ToUpper(value);
#endif
@@ -446,7 +454,7 @@ void AutofillExternalDelegate::ApplyAutofillOptions(
// On Android and Desktop, Google Pay branding is shown along with Settings.
// So Google Pay Icon is just attached to an existing menu item.
if (is_all_server_suggestions) {
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
suggestions->back().icon = "googlePay";
#else
suggestions->back().store_indicator_icon =
@@ -471,7 +479,7 @@ void AutofillExternalDelegate::InsertDataListValues(
base::Contains(data_list_set, suggestion.value);
});
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
// Insert the separator between the datalist and Autofill/Autocomplete values
// (if there are any).
if (!suggestions->empty()) {
diff --git a/chromium/components/autofill/core/browser/autofill_external_delegate.h b/chromium/components/autofill/core/browser/autofill_external_delegate.h
index 667f4291b51..268b63e84d4 100644
--- a/chromium/components/autofill/core/browser/autofill_external_delegate.h
+++ b/chromium/components/autofill/core/browser/autofill_external_delegate.h
@@ -47,7 +47,8 @@ class AutofillExternalDelegate : public AutofillPopupDelegate {
void OnPopupHidden() override;
void OnPopupSuppressed() override;
void DidSelectSuggestion(const std::u16string& value,
- int frontend_id) override;
+ int frontend_id,
+ const std::string& backend_id) override;
void DidAcceptSuggestion(const std::u16string& value,
int frontend_id,
const std::string& backend_id,
diff --git a/chromium/components/autofill/core/browser/autofill_external_delegate_unittest.cc b/chromium/components/autofill/core/browser/autofill_external_delegate_unittest.cc
index ba6c64461e5..fd63b0cb728 100644
--- a/chromium/components/autofill/core/browser/autofill_external_delegate_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_external_delegate_unittest.cc
@@ -126,8 +126,9 @@ class MockBrowserAutofillManager : public BrowserAutofillManager {
(const FormData& form, const FormFieldData& field),
(override));
MOCK_METHOD(void,
- FillVirtualCardInformation,
- (const std::string& guid,
+ FillOrPreviewVirtualCardInformation,
+ (mojom::RendererFormDataAction action,
+ const std::string& guid,
int query_id,
const FormData& form,
const FormFieldData& field),
@@ -363,7 +364,7 @@ TEST_F(AutofillExternalDelegateUnitTest, ExternalDelegateDataList) {
// The enums must be cast to ints to prevent compile errors on linux_rel.
auto element_ids = testing::ElementsAre(
static_cast<int>(POPUP_ITEM_ID_DATALIST_ENTRY),
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
static_cast<int>(POPUP_ITEM_ID_SEPARATOR),
#endif
kAutofillProfileId, static_cast<int>(POPUP_ITEM_ID_AUTOFILL_OPTIONS));
@@ -418,7 +419,7 @@ TEST_F(AutofillExternalDelegateUnitTest, UpdateDataListWhileShowingPopup) {
// The enums must be cast to ints to prevent compile errors on linux_rel.
auto element_ids = testing::ElementsAre(
static_cast<int>(POPUP_ITEM_ID_DATALIST_ENTRY),
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
static_cast<int>(POPUP_ITEM_ID_SEPARATOR),
#endif
kAutofillProfileId, static_cast<int>(POPUP_ITEM_ID_AUTOFILL_OPTIONS));
@@ -469,7 +470,7 @@ TEST_F(AutofillExternalDelegateUnitTest, DuplicateAutofillDatalistValues) {
auto element_ids = testing::ElementsAre(
static_cast<int>(POPUP_ITEM_ID_DATALIST_ENTRY),
static_cast<int>(POPUP_ITEM_ID_DATALIST_ENTRY),
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
static_cast<int>(POPUP_ITEM_ID_SEPARATOR),
#endif
kAutofillProfileId, static_cast<int>(POPUP_ITEM_ID_AUTOFILL_OPTIONS));
@@ -509,7 +510,7 @@ TEST_F(AutofillExternalDelegateUnitTest, DuplicateAutocompleteDatalistValues) {
// We are expecting only two data list entries.
static_cast<int>(POPUP_ITEM_ID_DATALIST_ENTRY),
static_cast<int>(POPUP_ITEM_ID_DATALIST_ENTRY),
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
static_cast<int>(POPUP_ITEM_ID_SEPARATOR),
#endif
static_cast<int>(POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY));
@@ -598,7 +599,7 @@ TEST_F(AutofillExternalDelegateUnitTest, ExternalDelegateInvalidUniqueId) {
EXPECT_CALL(*browser_autofill_manager_, FillOrPreviewForm(_, _, _, _, _))
.Times(0);
EXPECT_CALL(*autofill_driver_, RendererShouldClearPreviewedForm()).Times(1);
- external_delegate_->DidSelectSuggestion(std::u16string(), -1);
+ external_delegate_->DidSelectSuggestion(std::u16string(), -1, std::string());
// Ensure it doesn't try to fill the form in with the negative id.
EXPECT_CALL(autofill_client_,
@@ -616,21 +617,30 @@ TEST_F(AutofillExternalDelegateUnitTest, ExternalDelegateClearPreviewedForm) {
// cause any previews to get cleared.
IssueOnQuery(123);
EXPECT_CALL(*autofill_driver_, RendererShouldClearPreviewedForm()).Times(1);
- external_delegate_->DidSelectSuggestion(u"baz foo",
- POPUP_ITEM_ID_PASSWORD_ENTRY);
+ external_delegate_->DidSelectSuggestion(
+ u"baz foo", POPUP_ITEM_ID_PASSWORD_ENTRY, std::string());
EXPECT_CALL(*autofill_driver_, RendererShouldClearPreviewedForm()).Times(1);
EXPECT_CALL(
*browser_autofill_manager_,
FillOrPreviewForm(mojom::RendererFormDataAction::kPreview, _, _, _, _));
- external_delegate_->DidSelectSuggestion(u"baz foo", 1);
+ external_delegate_->DidSelectSuggestion(u"baz foo", 1, std::string());
// Ensure selecting an autocomplete entry will cause any previews to
// get cleared.
EXPECT_CALL(*autofill_driver_, RendererShouldClearPreviewedForm()).Times(1);
EXPECT_CALL(*autofill_driver_, RendererShouldPreviewFieldWithValue(
field_id_, std::u16string(u"baz foo")));
- external_delegate_->DidSelectSuggestion(u"baz foo",
- POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY);
+ external_delegate_->DidSelectSuggestion(
+ u"baz foo", POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY, std::string());
+
+ // Ensure selecting a virtual card entry will cause any previews to
+ // get cleared.
+ EXPECT_CALL(*autofill_driver_, RendererShouldClearPreviewedForm()).Times(1);
+ EXPECT_CALL(*browser_autofill_manager_,
+ FillOrPreviewVirtualCardInformation(
+ mojom::RendererFormDataAction::kPreview, _, _, _, _));
+ external_delegate_->DidSelectSuggestion(
+ std::u16string(), POPUP_ITEM_ID_VIRTUAL_CREDIT_CARD_ENTRY, std::string());
}
// Test that the popup is hidden once we are done editing the autofill field.
@@ -848,7 +858,7 @@ TEST_F(AutofillExternalDelegateUnitTest, ShouldShowGooglePayIcon) {
true);
// On Desktop, the GPay icon should be stored in the store indicator icon.
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
EXPECT_THAT(open_args.suggestions, SuggestionVectorIconsAre(element_icons));
#else
EXPECT_THAT(open_args.suggestions,
@@ -905,14 +915,24 @@ TEST_F(AutofillExternalDelegateUnitTest, ShouldUseNewSettingName) {
// Test that browser autofill manager will handle the unmasking request for the
// virtual card after users accept the suggestion to use a virtual card.
-TEST_F(AutofillExternalDelegateUnitTest, VirtualCardOptionItem) {
+TEST_F(AutofillExternalDelegateUnitTest, AcceptVirtualCardOptionItem) {
+ FormData form;
EXPECT_CALL(*browser_autofill_manager_,
- FillVirtualCardInformation(_, _, _, _));
+ FillOrPreviewVirtualCardInformation(
+ mojom::RendererFormDataAction::kFill, _, _, _, _));
external_delegate_->DidAcceptSuggestion(
std::u16string(), POPUP_ITEM_ID_VIRTUAL_CREDIT_CARD_ENTRY, std::string(),
0);
}
+TEST_F(AutofillExternalDelegateUnitTest, SelectVirtualCardOptionItem) {
+ EXPECT_CALL(*browser_autofill_manager_,
+ FillOrPreviewVirtualCardInformation(
+ mojom::RendererFormDataAction::kPreview, _, _, _, _));
+ external_delegate_->DidSelectSuggestion(
+ std::u16string(), POPUP_ITEM_ID_VIRTUAL_CREDIT_CARD_ENTRY, std::string());
+}
+
// Tests that the prompt to show account cards shows up when the corresponding
// bit is set, including any suggestions that are passed along and the "Manage"
// row in the footer.
@@ -960,7 +980,7 @@ TEST_F(AutofillExternalDelegateCardsFromAccountTest,
EXPECT_EQ(open_args.popup_type, PopupType::kPersonalInformation);
}
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
// Tests that outdated returned suggestions are discarded.
TEST_F(AutofillExternalDelegateCardsFromAccountTest,
ShouldDiscardOutdatedSuggestions) {
diff --git a/chromium/components/autofill/core/browser/autofill_field.h b/chromium/components/autofill/core/browser/autofill_field.h
index 33ccb1ac499..cdb802dce05 100644
--- a/chromium/components/autofill/core/browser/autofill_field.h
+++ b/chromium/components/autofill/core/browser/autofill_field.h
@@ -202,6 +202,17 @@ class AutofillField : public FormFieldData {
return single_username_vote_type_;
}
+ // Getter and Setter methods for
+ // |value_not_autofilled_over_existing_value_hash_|.
+ void set_value_not_autofilled_over_existing_value_hash(
+ absl::optional<size_t> value_not_autofilled_over_existing_value_hash) {
+ value_not_autofilled_over_existing_value_hash_ =
+ value_not_autofilled_over_existing_value_hash;
+ }
+ absl::optional<size_t> value_not_autofilled_over_existing_value_hash() const {
+ return value_not_autofilled_over_existing_value_hash_;
+ }
+
// For each type in |possible_types_| that's missing from
// |possible_types_validities_|, will add it to the
// |possible_types_validities_| and will set its validity to UNVALIDATED. This
@@ -299,6 +310,10 @@ class AutofillField : public FormFieldData {
// Strength of the single username vote signal, if applicable.
absl::optional<AutofillUploadContents::Field::SingleUsernameVoteType>
single_username_vote_type_;
+
+ // Stores the hash of the value which is supposed to be autofilled in the
+ // field but was not due to a prefilled value.
+ absl::optional<size_t> value_not_autofilled_over_existing_value_hash_;
};
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_form_test_utils.cc b/chromium/components/autofill/core/browser/autofill_form_test_utils.cc
index 5f634781649..e151487a517 100644
--- a/chromium/components/autofill/core/browser/autofill_form_test_utils.cc
+++ b/chromium/components/autofill/core/browser/autofill_form_test_utils.cc
@@ -24,7 +24,6 @@ testing::Message DescribeFormData(const FormData& form_data) {
FormFieldData CreateFieldByRole(ServerFieldType role) {
FormFieldData field;
-
switch (role) {
case ServerFieldType::USERNAME:
field.label = u"Username";
@@ -82,57 +81,42 @@ FormFieldData CreateFieldByRole(ServerFieldType role) {
default:
break;
}
-
return field;
}
-FormData GetFormData(const TestFormAttributes& test_form_attributes) {
- FormData form_data;
-
- form_data.url = GURL(test_form_attributes.url);
- form_data.action = GURL(test_form_attributes.action);
- form_data.name = test_form_attributes.name.data();
- form_data.host_frame =
- test_form_attributes.host_frame.value_or(GetLocalFrameToken());
- form_data.unique_renderer_id =
- test_form_attributes.unique_renderer_id.value_or(MakeFormRendererId());
- if (test_form_attributes.main_frame_origin)
- form_data.main_frame_origin = *test_form_attributes.main_frame_origin;
-
- for (const FieldDataDescription& field_description :
- test_form_attributes.fields) {
- FormFieldData field = CreateFieldByRole(field_description.role);
- field.form_control_type = field_description.form_control_type.data();
- // Add selection options if the field control type is "select-one".
- if (field.form_control_type == "select-one" &&
- field_description.select_options.size() > 0) {
- field.options = field_description.select_options;
- }
- field.host_frame =
- field_description.host_frame.value_or(form_data.host_frame);
- field.unique_renderer_id =
- field_description.unique_renderer_id.value_or(MakeFieldRendererId());
- field.is_focusable = field_description.is_focusable;
- if (!field_description.autocomplete_attribute.empty()) {
- field.autocomplete_attribute =
- field_description.autocomplete_attribute.data();
- }
- if (field_description.label != kLabelText)
- field.label = field_description.label.data();
- if (field_description.name != kNameText)
- field.name = field_description.name.data();
- if (field_description.value)
- field.value = *field_description.value;
- if (field_description.is_autofilled)
- field.is_autofilled = *field_description.is_autofilled;
- field.origin =
- field_description.origin.value_or(form_data.main_frame_origin);
- field.should_autocomplete = field_description.should_autocomplete;
- form_data.fields.push_back(field);
+FormData GetFormData(const FormDataDescription& d) {
+ FormData f;
+ f.url = GURL(d.url);
+ f.action = GURL(d.action);
+ f.name = d.name;
+ f.host_frame = d.host_frame.value_or(MakeLocalFrameToken());
+ f.unique_renderer_id = d.unique_renderer_id.value_or(MakeFormRendererId());
+ if (d.main_frame_origin)
+ f.main_frame_origin = *d.main_frame_origin;
+ f.is_form_tag = d.is_form_tag;
+ for (const FieldDataDescription& dd : d.fields) {
+ FormFieldData ff = CreateFieldByRole(dd.role);
+ ff.form_control_type = dd.form_control_type;
+ if (ff.form_control_type == "select-one" && !dd.select_options.empty())
+ ff.options = dd.select_options;
+ ff.host_frame = dd.host_frame.value_or(f.host_frame);
+ ff.unique_renderer_id =
+ dd.unique_renderer_id.value_or(MakeFieldRendererId());
+ ff.is_focusable = dd.is_focusable;
+ if (!dd.autocomplete_attribute.empty())
+ ff.autocomplete_attribute = dd.autocomplete_attribute;
+ if (dd.label)
+ ff.label = *dd.label;
+ if (dd.name)
+ ff.name = *dd.name;
+ if (dd.value)
+ ff.value = *dd.value;
+ ff.is_autofilled = dd.is_autofilled.value_or(false);
+ ff.origin = dd.origin.value_or(f.main_frame_origin);
+ ff.should_autocomplete = dd.should_autocomplete;
+ f.fields.push_back(ff);
}
- form_data.is_form_tag = test_form_attributes.is_form_tag;
-
- return form_data;
+ return f;
}
// static
@@ -161,52 +145,46 @@ void FormStructureTest::CheckFormStructureTestData(
if (test_case.form_flags.has_author_specified_upi_vpa_hint)
EXPECT_TRUE(form_structure->has_author_specified_upi_vpa_hint());
- if (test_case.form_flags.is_complete_credit_card_form.first) {
- if (test_case.form_flags.is_complete_credit_card_form.second)
- EXPECT_TRUE(form_structure->IsCompleteCreditCardForm());
- else
- EXPECT_FALSE(form_structure->IsCompleteCreditCardForm());
+ if (test_case.form_flags.is_complete_credit_card_form.has_value()) {
+ EXPECT_EQ(form_structure->IsCompleteCreditCardForm(),
+ *test_case.form_flags.is_complete_credit_card_form);
}
-
- if (test_case.form_flags.field_count)
+ if (test_case.form_flags.field_count) {
ASSERT_EQ(*test_case.form_flags.field_count,
static_cast<int>(form_structure->field_count()));
- if (test_case.form_flags.autofill_count)
+ }
+ if (test_case.form_flags.autofill_count) {
ASSERT_EQ(*test_case.form_flags.autofill_count,
static_cast<int>(form_structure->autofill_count()));
+ }
if (test_case.form_flags.section_count) {
std::set<std::string> section_names;
- for (size_t i = 0; i < 9; ++i) {
- section_names.insert(form_structure->field(i)->section);
- }
+ for (const auto& field : *form_structure)
+ section_names.insert(field->section);
EXPECT_EQ(*test_case.form_flags.section_count,
static_cast<int>(section_names.size()));
}
- if (!test_case.expected_field_types.expected_html_type.empty()) {
- for (size_t i = 0;
- i < test_case.expected_field_types.expected_html_type.size(); i++)
- EXPECT_EQ(test_case.expected_field_types.expected_html_type[i],
- form_structure->field(i)->html_type());
+ for (size_t i = 0;
+ i < test_case.expected_field_types.expected_html_type.size(); i++) {
+ EXPECT_EQ(test_case.expected_field_types.expected_html_type[i],
+ form_structure->field(i)->html_type());
}
- if (!test_case.expected_field_types.expected_phone_part.empty()) {
- for (size_t i = 0;
- i < test_case.expected_field_types.expected_phone_part.size(); i++)
- EXPECT_EQ(test_case.expected_field_types.expected_phone_part[i],
- form_structure->field(i)->phone_part());
+ for (size_t i = 0;
+ i < test_case.expected_field_types.expected_phone_part.size(); i++) {
+ EXPECT_EQ(test_case.expected_field_types.expected_phone_part[i],
+ form_structure->field(i)->phone_part());
}
- if (!test_case.expected_field_types.expected_heuristic_type.empty()) {
- for (size_t i = 0;
- i < test_case.expected_field_types.expected_heuristic_type.size();
- i++)
- EXPECT_EQ(test_case.expected_field_types.expected_heuristic_type[i],
- form_structure->field(i)->heuristic_type());
+ for (size_t i = 0;
+ i < test_case.expected_field_types.expected_heuristic_type.size();
+ i++) {
+ EXPECT_EQ(test_case.expected_field_types.expected_heuristic_type[i],
+ form_structure->field(i)->heuristic_type());
}
- if (!test_case.expected_field_types.expected_overall_type.empty()) {
- for (size_t i = 0;
- i < test_case.expected_field_types.expected_overall_type.size(); i++)
- EXPECT_EQ(test_case.expected_field_types.expected_overall_type[i],
- form_structure->field(i)->Type().GetStorableType());
+ for (size_t i = 0;
+ i < test_case.expected_field_types.expected_overall_type.size(); i++) {
+ EXPECT_EQ(test_case.expected_field_types.expected_overall_type[i],
+ form_structure->field(i)->Type().GetStorableType());
}
}
}
diff --git a/chromium/components/autofill/core/browser/autofill_form_test_utils.h b/chromium/components/autofill/core/browser/autofill_form_test_utils.h
index 2bf698d1425..b8c68f858a2 100644
--- a/chromium/components/autofill/core/browser/autofill_form_test_utils.h
+++ b/chromium/components/autofill/core/browser/autofill_form_test_utils.h
@@ -20,12 +20,6 @@ namespace test {
namespace {
-// Default label assigned to fields.
-constexpr char16_t kLabelText[] = u"label";
-
-// Default name attribute assigned to fields.
-constexpr char16_t kNameText[] = u"name";
-
// Default form url.
constexpr char kFormUrl[] = "http://example.com/form.html";
@@ -43,11 +37,11 @@ struct FieldDataDescription {
absl::optional<LocalFrameToken> host_frame;
absl::optional<FieldRendererId> unique_renderer_id;
bool is_focusable = true;
- const base::StringPiece16 label = kLabelText;
- const base::StringPiece16 name = kNameText;
- absl::optional<const char16_t*> value;
- const base::StringPiece autocomplete_attribute;
- const base::StringPiece form_control_type = "text";
+ absl::optional<std::u16string> label;
+ absl::optional<std::u16string> name;
+ absl::optional<std::u16string> value;
+ const std::string autocomplete_attribute;
+ const std::string form_control_type = "text";
bool should_autocomplete = true;
absl::optional<bool> is_autofilled;
absl::optional<url::Origin> origin;
@@ -56,14 +50,14 @@ struct FieldDataDescription {
// Attributes provided to the test form.
template <typename = void>
-struct TestFormAttributes {
- const base::StringPiece description_for_logging;
+struct FormDataDescription {
+ const std::string description_for_logging;
std::vector<FieldDataDescription<>> fields;
absl::optional<LocalFrameToken> host_frame;
absl::optional<FormRendererId> unique_renderer_id;
- const base::StringPiece16 name = u"TestForm";
- const base::StringPiece url = kFormUrl;
- const base::StringPiece action = kFormActionUrl;
+ const std::u16string name = u"TestForm";
+ const std::string url = kFormUrl;
+ const std::string action = kFormActionUrl;
absl::optional<url::Origin> main_frame_origin;
bool is_form_tag = true;
};
@@ -82,10 +76,8 @@ struct TestFormFlags {
bool should_be_uploaded = false;
bool has_author_specified_types = false;
bool has_author_specified_upi_vpa_hint = false;
- // first value denotes whether the comparison is to be done while second
- // denotes EXPECT_TRUE for true and EXPECT_FALSE for false.
- std::pair<bool, bool> is_complete_credit_card_form = {false, false};
// The implicit default value `absl::nullopt` means no checking.
+ absl::optional<bool> is_complete_credit_card_form;
absl::optional<int> field_count;
absl::optional<int> autofill_count;
absl::optional<int> section_count;
@@ -104,7 +96,7 @@ struct ExpectedFieldTypeValues {
// Describes a test case for the parser.
template <typename = void>
struct FormStructureTestCase {
- TestFormAttributes<> form_attributes;
+ FormDataDescription<> form_attributes;
TestFormFlags<> form_flags;
ExpectedFieldTypeValues<> expected_field_types;
};
@@ -112,7 +104,7 @@ struct FormStructureTestCase {
} // namespace internal
using FieldDataDescription = internal::FieldDataDescription<>;
-using TestFormAttributes = internal::TestFormAttributes<>;
+using FormDataDescription = internal::FormDataDescription<>;
using FormStructureTestCase = internal::FormStructureTestCase<>;
// Describes the |form_data|. Use this in SCOPED_TRACE if other logging
@@ -123,7 +115,7 @@ testing::Message DescribeFormData(const FormData& form_data);
FormFieldData CreateFieldByRole(ServerFieldType role);
// Creates a FormData to be fed to the parser.
-FormData GetFormData(const TestFormAttributes& test_form_attributes);
+FormData GetFormData(const FormDataDescription& test_form_attributes);
class FormStructureTest : public testing::Test {
protected:
diff --git a/chromium/components/autofill/core/browser/autofill_manager.cc b/chromium/components/autofill/core/browser/autofill_manager.cc
index b11722f7784..48d68f8a87e 100644
--- a/chromium/components/autofill/core/browser/autofill_manager.cc
+++ b/chromium/components/autofill/core/browser/autofill_manager.cc
@@ -141,8 +141,7 @@ AutofillManager::~AutofillManager() {
void AutofillManager::OnLanguageDetermined(
const translate::LanguageDetectionDetails& details) {
- if (!base::FeatureList::IsEnabled(
- features::kAutofillParsingPatternsLanguageDetection)) {
+ if (!base::FeatureList::IsEnabled(features::kAutofillPageLanguageDetection)) {
return;
}
for (auto& p : form_structures_) {
diff --git a/chromium/components/autofill/core/browser/autofill_manager.h b/chromium/components/autofill/core/browser/autofill_manager.h
index 8310c82331b..508238f2d57 100644
--- a/chromium/components/autofill/core/browser/autofill_manager.h
+++ b/chromium/components/autofill/core/browser/autofill_manager.h
@@ -11,7 +11,6 @@
#include <vector>
#include "base/cancelable_callback.h"
-#include "base/compiler_specific.h"
#include "base/memory/raw_ptr.h"
#include "base/scoped_observation.h"
#include "base/time/time.h"
@@ -186,10 +185,10 @@ class AutofillManager
// corresponding to |form| and |field|. This might have the side-effect of
// updating the cache. Returns false if the |form| is not autofillable, or if
// it is not already present in the cache and the cache is full.
- bool GetCachedFormAndField(const FormData& form,
- const FormFieldData& field,
- FormStructure** form_structure,
- AutofillField** autofill_field) WARN_UNUSED_RESULT;
+ [[nodiscard]] bool GetCachedFormAndField(const FormData& form,
+ const FormFieldData& field,
+ FormStructure** form_structure,
+ AutofillField** autofill_field);
// Returns nullptr if no cached form structure is found with a matching
// |form_id|. Runs in logarithmic time.
diff --git a/chromium/components/autofill/core/browser/autofill_merge_unittest.cc b/chromium/components/autofill/core/browser/autofill_merge_unittest.cc
index e993cb78d48..7a3c022a50d 100644
--- a/chromium/components/autofill/core/browser/autofill_merge_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_merge_unittest.cc
@@ -32,7 +32,7 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
#include "base/mac/foundation_util.h"
#endif
@@ -92,9 +92,9 @@ const std::vector<base::FilePath> GetTestFiles() {
}
std::sort(files.begin(), files.end());
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
base::mac::ClearAmIBundledCache();
-#endif // defined(OS_APPLE)
+#endif // BUILDFLAG(IS_APPLE)
return files;
}
@@ -227,6 +227,7 @@ AutofillMergeTest::~AutofillMergeTest() = default;
void AutofillMergeTest::SetUp() {
test::DisableSystemServices(nullptr);
+ personal_data_.set_auto_accept_address_imports_for_testing(true);
form_data_importer_ = std::make_unique<FormDataImporter>(
&autofill_client_,
/*payments::PaymentsClient=*/nullptr, &personal_data_, "en");
diff --git a/chromium/components/autofill/core/browser/autofill_profile_import_process.cc b/chromium/components/autofill/core/browser/autofill_profile_import_process.cc
index 17fe5516ea0..1ecd3a68a15 100644
--- a/chromium/components/autofill/core/browser/autofill_profile_import_process.cc
+++ b/chromium/components/autofill/core/browser/autofill_profile_import_process.cc
@@ -29,13 +29,15 @@ ProfileImportProcess::ProfileImportProcess(
const std::string& app_locale,
const GURL& form_source_url,
const PersonalDataManager* personal_data_manager,
- bool allow_only_silent_updates)
+ bool allow_only_silent_updates,
+ bool did_complement_country)
: import_id_(GetImportId()),
observed_profile_(observed_profile),
app_locale_(app_locale),
form_source_url_(form_source_url),
personal_data_manager_(personal_data_manager),
- allow_only_silent_updates_(allow_only_silent_updates) {
+ allow_only_silent_updates_(allow_only_silent_updates),
+ did_complement_country_(did_complement_country) {
DetermineProfileImportType();
}
@@ -354,10 +356,18 @@ void ProfileImportProcess::CollectMetrics() const {
// decision.
if (import_type_ == AutofillProfileImportType::kNewProfile) {
AutofillMetrics::LogNewProfileImportDecision(user_decision_);
+ if (did_complement_country_) {
+ AutofillMetrics::LogNewProfileWithComplementedCountryImportDecision(
+ user_decision_);
+ }
} else if (import_type_ == AutofillProfileImportType::kConfirmableMerge ||
import_type_ ==
AutofillProfileImportType::kConfirmableMergeAndSilentUpdate) {
AutofillMetrics::LogProfileUpdateImportDecision(user_decision_);
+ if (did_complement_country_) {
+ AutofillMetrics::LogProfileUpdateWithComplementedCountryImportDecision(
+ user_decision_);
+ }
DCHECK(merge_candidate_.has_value() && import_candidate_.has_value());
@@ -387,8 +397,16 @@ void ProfileImportProcess::CollectMetrics() const {
for (const auto& difference : edit_difference) {
if (import_type_ == AutofillProfileImportType::kNewProfile) {
AutofillMetrics::LogNewProfileEditedType(difference.type);
+ if (did_complement_country_ &&
+ difference.type == ServerFieldType::ADDRESS_HOME_COUNTRY) {
+ AutofillMetrics::LogNewProfileEditedComplementedCountry();
+ }
} else {
AutofillMetrics::LogProfileUpdateEditedType(difference.type);
+ if (did_complement_country_ &&
+ difference.type == ServerFieldType::ADDRESS_HOME_COUNTRY) {
+ AutofillMetrics::LogProfileUpdateEditedComplementedCountry();
+ }
}
}
if (import_type_ == AutofillProfileImportType::kNewProfile) {
diff --git a/chromium/components/autofill/core/browser/autofill_profile_import_process.h b/chromium/components/autofill/core/browser/autofill_profile_import_process.h
index 1a21c994bdd..7b90710a49d 100644
--- a/chromium/components/autofill/core/browser/autofill_profile_import_process.h
+++ b/chromium/components/autofill/core/browser/autofill_profile_import_process.h
@@ -78,7 +78,8 @@ class ProfileImportProcess {
const std::string& app_locale,
const GURL& form_source_url,
const PersonalDataManager* personal_data_manager,
- bool allow_only_silent_updates);
+ bool allow_only_silent_updates,
+ bool did_complement_country = false);
ProfileImportProcess(const ProfileImportProcess&);
ProfileImportProcess& operator=(const ProfileImportProcess& other);
@@ -220,6 +221,11 @@ class ProfileImportProcess {
// If true, denotes that the import process allows only silent updates.
bool allow_only_silent_updates_;
+
+ // Passed through from FormDataImporter, to collect metrics on whether the
+ // profile is accepted/edited.
+ // TODO(crbug.com/1297032): Cleanup when launched.
+ bool did_complement_country_;
};
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_profile_sync_util.cc b/chromium/components/autofill/core/browser/autofill_profile_sync_util.cc
index db5b7bebe6e..3cf3031593c 100644
--- a/chromium/components/autofill/core/browser/autofill_profile_sync_util.cc
+++ b/chromium/components/autofill/core/browser/autofill_profile_sync_util.cc
@@ -18,7 +18,7 @@
#include "components/autofill/core/browser/geo/country_names.h"
#include "components/autofill/core/browser/proto/autofill_sync.pb.h"
#include "components/autofill/core/browser/webdata/autofill_table.h"
-#include "components/sync/engine/entity_data.h"
+#include "components/sync/protocol/entity_data.h"
using autofill::data_util::TruncateUTF8;
using base::UTF16ToUTF8;
@@ -103,10 +103,6 @@ std::unique_ptr<EntityData> CreateEntityDataFromAutofillProfile(
specifics->set_use_date(entry.use_date().ToTimeT());
specifics->set_address_home_language_code(
TruncateUTF8(entry.language_code()));
- specifics->set_validity_state_bitfield(
- entry.GetClientValidityBitfieldValue());
- specifics->set_is_client_validity_states_updated(
- entry.is_client_validity_states_updated());
// Set name-related values.
specifics->add_name_honorific(
@@ -255,8 +251,6 @@ std::unique_ptr<AutofillProfile> CreateAutofillProfileFromSpecifics(
profile->set_use_count(specifics.use_count());
profile->set_use_date(base::Time::FromTimeT(specifics.use_date()));
profile->set_language_code(specifics.address_home_language_code());
- profile->SetClientValidityFromBitfieldValue(
- specifics.validity_state_bitfield());
// Set the profile label if it exists.
if (specifics.has_profile_label())
@@ -463,10 +457,6 @@ std::unique_ptr<AutofillProfile> CreateAutofillProfileFromSpecifics(
ConvertSpecificsToProfileVerificationStatus(
specifics.address_home_subpremise_name_status()));
- // This has to be the last one, otherwise setting the raw info may change it.
- profile->set_is_client_validity_states_updated(
- specifics.is_client_validity_states_updated());
-
// The profile may be in a legacy state. By calling |FinalizeAfterImport()|
// * The profile is migrated if the name structure is in legacy state.
// * Nothing happens if the profile is already migrated and therefore
diff --git a/chromium/components/autofill/core/browser/autofill_profile_sync_util_unittest.cc b/chromium/components/autofill/core/browser/autofill_profile_sync_util_unittest.cc
index edb5cc8d352..610afc0ed89 100644
--- a/chromium/components/autofill/core/browser/autofill_profile_sync_util_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_profile_sync_util_unittest.cc
@@ -13,8 +13,8 @@
#include "components/autofill/core/browser/webdata/autofill_table.h"
#include "components/autofill/core/common/autofill_constants.h"
#include "components/autofill/core/common/autofill_features.h"
-#include "components/sync/engine/entity_data.h"
#include "components/sync/protocol/autofill_specifics.pb.h"
+#include "components/sync/protocol/entity_data.h"
#include "components/sync/protocol/entity_specifics.pb.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace autofill {
@@ -122,8 +122,6 @@ AutofillProfile ConstructCompleteProfile() {
profile.SetRawInfoWithVerificationStatus(
ADDRESS_HOME_PREMISE_NAME, u"Premise", VerificationStatus::kFormatted);
profile.set_language_code("en");
- profile.SetClientValidityFromBitfieldValue(1984);
- profile.set_is_client_validity_states_updated(true);
return profile;
}
@@ -256,8 +254,6 @@ AutofillProfileSpecifics ConstructCompleteSpecifics() {
sync_pb::AutofillProfileSpecifics_VerificationStatus_OBSERVED);
specifics.set_address_home_language_code("en");
- specifics.set_validity_state_bitfield(1984);
- specifics.set_is_client_validity_states_updated(true);
return specifics;
}
diff --git a/chromium/components/autofill/core/browser/autofill_profile_validation_util.cc b/chromium/components/autofill/core/browser/autofill_profile_validation_util.cc
deleted file mode 100644
index 437fb53d36a..00000000000
--- a/chromium/components/autofill/core/browser/autofill_profile_validation_util.cc
+++ /dev/null
@@ -1,371 +0,0 @@
-// Copyright 2017 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.
-
-#include "components/autofill/core/browser/autofill_profile_validation_util.h"
-
-#include <string>
-#include <utility>
-
-#include "base/check.h"
-#include "base/containers/contains.h"
-#include "base/i18n/case_conversion.h"
-#include "base/strings/utf_string_conversions.h"
-#include "components/autofill/core/browser/geo/address_i18n.h"
-#include "components/autofill/core/browser/geo/country_data.h"
-#include "components/autofill/core/browser/validation.h"
-#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_data.h"
-#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_validator.h"
-#include "third_party/libphonenumber/dist/cpp/src/phonenumbers/phonenumberutil.h"
-
-namespace autofill {
-
-namespace {
-
-using ::i18n::addressinput::COUNTRY;
-using ::i18n::addressinput::ADMIN_AREA;
-using ::i18n::addressinput::LOCALITY;
-using ::i18n::addressinput::DEPENDENT_LOCALITY;
-using ::i18n::addressinput::SORTING_CODE;
-using ::i18n::addressinput::POSTAL_CODE;
-using ::i18n::addressinput::STREET_ADDRESS;
-using ::i18n::addressinput::RECIPIENT;
-
-using i18nAddressData = ::i18n::addressinput::AddressData;
-using i18nAddressField = ::i18n::addressinput::AddressField;
-using i18nAddressProblem = ::i18n::addressinput::AddressProblem;
-using i18nFieldProblemMap = ::i18n::addressinput::FieldProblemMap;
-
-using ::i18n::addressinput::INVALID_FORMAT;
-using ::i18n::addressinput::MISMATCHING_VALUE;
-using ::i18n::addressinput::MISSING_REQUIRED_FIELD;
-using ::i18n::addressinput::UNEXPECTED_FIELD;
-using ::i18n::addressinput::UNKNOWN_VALUE;
-using ::i18n::addressinput::UNSUPPORTED_FIELD;
-
-using ::i18n::phonenumbers::PhoneNumberUtil;
-
-const i18nAddressField kFields[] = {COUNTRY, ADMIN_AREA, LOCALITY,
- DEPENDENT_LOCALITY, POSTAL_CODE};
-const i18nAddressProblem kProblems[] = {
- UNEXPECTED_FIELD, MISSING_REQUIRED_FIELD, UNKNOWN_VALUE,
- INVALID_FORMAT, MISMATCHING_VALUE, UNSUPPORTED_FIELD};
-
-// If the |address_field| is valid, set the validity state of the
-// |address_field| in the |profile| to the |state| and return true.
-// Otherwise, return false.
-bool SetValidityStateForAddressField(const AutofillProfile* profile,
- i18nAddressField address_field,
- AutofillDataModel::ValidityState state) {
- ServerFieldType server_field = i18n::TypeForField(address_field,
- /*billing=*/false);
- if (server_field == UNKNOWN_TYPE)
- return false;
- DCHECK(profile);
- profile->SetValidityState(server_field, state, AutofillDataModel::CLIENT);
- return true;
-}
-
-// Set the validity state of all address fields in the |profile| to |state|.
-void SetAllAddressValidityStates(const AutofillProfile* profile,
- AutofillDataModel::ValidityState state) {
- DCHECK(profile);
- for (auto field : kFields)
- SetValidityStateForAddressField(profile, field, state);
-}
-
-// Returns all relevant pairs of (field, problem), where field is in
-// |kFields|, and problem is in |kProblems|.
-i18nFieldProblemMap* CreateFieldProblemMap() {
- i18nFieldProblemMap* filter = new i18nFieldProblemMap();
- for (auto field : kFields) {
- for (auto problem : kProblems) {
- filter->insert(std::make_pair(field, problem));
- }
- }
- return filter;
-}
-
-// GetFilter() will make sure that the validation only returns problems that
-// are relevant.
-const i18nFieldProblemMap* GetFilter() {
- static const i18nFieldProblemMap* const filter = CreateFieldProblemMap();
- return filter;
-}
-
-// Initializes |address| data from the address info in the |profile|.
-void InitializeAddressFromProfile(const AutofillProfile& profile,
- i18nAddressData* address) {
- address->region_code =
- base::UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_COUNTRY));
- address->administrative_area =
- base::UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_STATE));
- address->locality = base::UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_CITY));
- address->dependent_locality =
- base::UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY));
- // The validation is case insensitive, and the postal codes are always upper
- // case.
- address->postal_code = base::UTF16ToUTF8(
- base::i18n::ToUpper(profile.GetRawInfo(ADDRESS_HOME_ZIP)));
-}
-
-void SetEmptyValidityIfEmpty(const AutofillProfile* profile) {
- if (profile->GetRawInfo(ADDRESS_HOME_COUNTRY).empty())
- profile->SetValidityState(ADDRESS_HOME_COUNTRY, AutofillDataModel::EMPTY,
- AutofillDataModel::CLIENT);
- if (profile->GetRawInfo(ADDRESS_HOME_STATE).empty())
- profile->SetValidityState(ADDRESS_HOME_STATE, AutofillDataModel::EMPTY,
- AutofillDataModel::CLIENT);
- if (profile->GetRawInfo(ADDRESS_HOME_CITY).empty())
- profile->SetValidityState(ADDRESS_HOME_CITY, AutofillDataModel::EMPTY,
- AutofillDataModel::CLIENT);
- if (profile->GetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY).empty())
- profile->SetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
- AutofillDataModel::EMPTY,
- AutofillDataModel::CLIENT);
- if (profile->GetRawInfo(ADDRESS_HOME_ZIP).empty())
- profile->SetValidityState(ADDRESS_HOME_ZIP, AutofillDataModel::EMPTY,
- AutofillDataModel::CLIENT);
-}
-
-void SetInvalidIfUnvalidated(const AutofillProfile* profile) {
- if (profile->GetValidityState(ADDRESS_HOME_COUNTRY,
- AutofillDataModel::CLIENT) ==
- AutofillDataModel::UNVALIDATED) {
- profile->SetValidityState(ADDRESS_HOME_COUNTRY, AutofillDataModel::INVALID,
- AutofillDataModel::CLIENT);
- }
-
- if (profile->GetValidityState(ADDRESS_HOME_STATE,
- AutofillDataModel::CLIENT) ==
- AutofillDataModel::UNVALIDATED) {
- profile->SetValidityState(ADDRESS_HOME_STATE, AutofillDataModel::INVALID,
- AutofillDataModel::CLIENT);
- }
-
- if (profile->GetValidityState(ADDRESS_HOME_CITY, AutofillDataModel::CLIENT) ==
- AutofillDataModel::UNVALIDATED) {
- profile->SetValidityState(ADDRESS_HOME_CITY, AutofillDataModel::INVALID,
- AutofillDataModel::CLIENT);
- }
-
- if (profile->GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
- AutofillDataModel::CLIENT) ==
- AutofillDataModel::UNVALIDATED) {
- profile->SetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
- AutofillDataModel::INVALID,
- AutofillDataModel::CLIENT);
- }
-
- if (profile->GetValidityState(ADDRESS_HOME_ZIP, AutofillDataModel::CLIENT) ==
- AutofillDataModel::UNVALIDATED) {
- profile->SetValidityState(ADDRESS_HOME_ZIP, AutofillDataModel::INVALID,
- AutofillDataModel::CLIENT);
- }
-}
-
-void MaybeApplyValidToFields(const AutofillProfile* profile) {
- // The metadata works from top to bottom. Therefore, a so far UNVALIDATED
- // subregion can only be validated if its super-region is VALID. In this
- // case, it's VALID if it has not been marked as INVALID or EMPTY.
-
- if (profile->GetValidityState(ADDRESS_HOME_STATE,
- AutofillDataModel::CLIENT) ==
- AutofillDataModel::UNVALIDATED) {
- profile->SetValidityState(ADDRESS_HOME_STATE, AutofillDataModel::VALID,
- AutofillDataModel::CLIENT);
- }
-
- if (profile->GetValidityState(ADDRESS_HOME_CITY, AutofillDataModel::CLIENT) ==
- AutofillDataModel::UNVALIDATED &&
- profile->GetValidityState(ADDRESS_HOME_STATE,
- AutofillDataModel::CLIENT) ==
- AutofillDataModel::VALID) {
- profile->SetValidityState(ADDRESS_HOME_CITY, AutofillDataModel::VALID,
- AutofillDataModel::CLIENT);
- }
-
- if (profile->GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
- AutofillDataModel::CLIENT) ==
- AutofillDataModel::UNVALIDATED &&
- profile->GetValidityState(ADDRESS_HOME_CITY, AutofillDataModel::CLIENT) ==
- AutofillDataModel::VALID) {
- profile->SetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
- AutofillDataModel::VALID,
- AutofillDataModel::CLIENT);
- }
-
- // ZIP only depends on COUNTRY. If it's not so far marked as INVALID or EMPTY,
- // then it's VALID.
- if (profile->GetValidityState(ADDRESS_HOME_ZIP, AutofillDataModel::CLIENT) ==
- AutofillDataModel::UNVALIDATED) {
- profile->SetValidityState(ADDRESS_HOME_ZIP, AutofillDataModel::VALID,
- AutofillDataModel::CLIENT);
- }
-}
-
-void ApplyValidOnlyIfAllChildrenNotInvalid(const AutofillProfile* profile) {
- if (profile->GetValidityState(ADDRESS_HOME_STATE,
- AutofillDataModel::CLIENT) ==
- AutofillDataModel::INVALID &&
- profile->GetValidityState(ADDRESS_HOME_ZIP, AutofillDataModel::CLIENT) ==
- AutofillDataModel::INVALID) {
- profile->SetValidityState(ADDRESS_HOME_COUNTRY, AutofillDataModel::INVALID,
- AutofillDataModel::CLIENT);
- }
-
- if (profile->GetValidityState(ADDRESS_HOME_CITY, AutofillDataModel::CLIENT) ==
- AutofillDataModel::INVALID) {
- profile->SetValidityState(ADDRESS_HOME_STATE, AutofillDataModel::INVALID,
- AutofillDataModel::CLIENT);
- }
-
- if (profile->GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
- AutofillDataModel::CLIENT) ==
- AutofillDataModel::INVALID) {
- profile->SetValidityState(ADDRESS_HOME_CITY, AutofillDataModel::INVALID,
- AutofillDataModel::CLIENT);
- }
-}
-
-} // namespace
-
-namespace profile_validation_util {
-
-void ValidateProfile(const AutofillProfile* profile,
- AddressValidator* address_validator) {
- DCHECK(address_validator);
- DCHECK(profile);
- ValidateAddressStrictly(profile, address_validator);
- ValidatePhoneNumber(profile);
- ValidateEmailAddress(profile);
-}
-
-AddressValidator::Status ValidateAddress(const AutofillProfile* profile,
- AddressValidator* address_validator) {
- DCHECK(address_validator);
- DCHECK(profile);
-
- SetAllAddressValidityStates(profile, AutofillDataModel::UNVALIDATED);
-
- if (!base::Contains(
- CountryDataMap::GetInstance()->country_codes(),
- base::UTF16ToUTF8(profile->GetRawInfo(ADDRESS_HOME_COUNTRY)))) {
- // If the country code is not in the database, the country code and the
- // profile are invalid, and other fields cannot be validated, because it is
- // unclear which, if any, rule should apply.
- SetValidityStateForAddressField(profile, COUNTRY,
- AutofillDataModel::INVALID);
- SetEmptyValidityIfEmpty(profile);
- return AddressValidator::SUCCESS;
- }
-
- // The COUNTRY was already listed in the CountryDataMap, therefore it's valid.
- SetValidityStateForAddressField(profile, COUNTRY, AutofillDataModel::VALID);
-
- i18nAddressData address;
- InitializeAddressFromProfile(*profile, &address);
- i18nFieldProblemMap problems;
- // status denotes if the rule was successfully loaded before validation.
- AddressValidator::Status status =
- address_validator->ValidateAddress(address, GetFilter(), &problems);
-
- // The address fields for which validation is not supported by the metadata
- // will be marked as UNSUPPORTED_FIELDs. These fields should be treated like
- // VALID fields to stay consistent. INVALID_FORMATs, MISMATCHING_VALUEs or
- // UNKNOWN_VALUEs are INVALID. MISSING_REQUIRED_FIELD would be marked as EMPTY
- // along other empty fields. UNEXPECTED_FIELD would mean that there is also no
- // metadata for validation, therefore, they are also UNSUPPORTED_FIELDs, and
- // thus they would be treated as VALID fields.
- for (auto problem : problems) {
- if (problem.second == UNSUPPORTED_FIELD) {
- SetValidityStateForAddressField(profile, problem.first,
- AutofillDataModel::VALID);
-
- } else if (problem.second == INVALID_FORMAT ||
- problem.second == MISMATCHING_VALUE ||
- problem.second == UNKNOWN_VALUE) {
- SetValidityStateForAddressField(profile, problem.first,
- AutofillDataModel::INVALID);
- }
- }
-
- SetEmptyValidityIfEmpty(profile);
-
- // Fields (except COUNTRY) could be VALID, only if the rules were available.
- if (status == AddressValidator::SUCCESS)
- MaybeApplyValidToFields(profile);
-
- return status;
-}
-
-void ValidateAddressStrictly(const AutofillProfile* profile,
- AddressValidator* address_validator) {
- DCHECK(address_validator);
- DCHECK(profile);
-
- // If the rules were loaded successfully, add a second layer of validation:
- // 1. For a field to stay valid after the first run, all the fields that
- // depend on that field for validation need to not be invalid on the first
- // run, otherwise there is a chance that the data on that field was also
- // invalid (incorrect.)
- // Example: 1225 Notre-Dame Ouest, Montreal, Quebec, H3C 2A3, United States.
- // A human validator can see that the country is most probably the invalid
- // field. The first step helps us validate the rules interdependently.
- // 2. All the address fields that could not be validated (UNVALIDATED),
- // should be considered as invalid.
-
- if (ValidateAddress(profile, address_validator) ==
- AddressValidator::SUCCESS) {
- ApplyValidOnlyIfAllChildrenNotInvalid(profile);
- SetInvalidIfUnvalidated(profile);
- }
-}
-
-void ValidateEmailAddress(const AutofillProfile* profile) {
- const std::u16string& email = profile->GetRawInfo(EMAIL_ADDRESS);
- if (email.empty()) {
- profile->SetValidityState(EMAIL_ADDRESS, AutofillDataModel::EMPTY,
- AutofillDataModel::CLIENT);
- return;
- }
-
- profile->SetValidityState(EMAIL_ADDRESS,
- autofill::IsValidEmailAddress(email)
- ? AutofillDataModel::VALID
- : AutofillDataModel::INVALID,
- AutofillDataModel::CLIENT);
-}
-
-void ValidatePhoneNumber(const AutofillProfile* profile) {
- const std::string& phone_number =
- base::UTF16ToUTF8(profile->GetRawInfo(PHONE_HOME_WHOLE_NUMBER));
- if (phone_number.empty()) {
- profile->SetValidityState(PHONE_HOME_WHOLE_NUMBER, AutofillDataModel::EMPTY,
- AutofillDataModel::CLIENT);
- return;
- }
-
- const std::string& country_code =
- base::UTF16ToUTF8(profile->GetRawInfo(ADDRESS_HOME_COUNTRY));
- if (!base::Contains(CountryDataMap::GetInstance()->country_codes(),
- country_code)) {
- // If the country code is not in the database, the phone number cannot be
- // validated.
- profile->SetValidityState(PHONE_HOME_WHOLE_NUMBER,
- AutofillDataModel::UNVALIDATED,
- AutofillDataModel::CLIENT);
- return;
- }
-
- PhoneNumberUtil* phone_util = PhoneNumberUtil::GetInstance();
- profile->SetValidityState(
- PHONE_HOME_WHOLE_NUMBER,
- phone_util->IsPossibleNumberForString(phone_number, country_code)
- ? AutofillDataModel::VALID
- : AutofillDataModel::INVALID,
- AutofillDataModel::CLIENT);
-}
-
-} // namespace profile_validation_util
-} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_profile_validation_util.h b/chromium/components/autofill/core/browser/autofill_profile_validation_util.h
deleted file mode 100644
index 9b19817df12..00000000000
--- a/chromium/components/autofill/core/browser/autofill_profile_validation_util.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2017 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.
-
-#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_PROFILE_VALIDATION_UTIL_H_
-#define COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_PROFILE_VALIDATION_UTIL_H_
-
-#include "components/autofill/core/browser/data_model/autofill_profile.h"
-#include "third_party/libaddressinput/chromium/chrome_address_validator.h"
-
-namespace autofill {
-namespace profile_validation_util {
-
-// Sets the validity state of the autofill |profile|.
-void ValidateProfile(const AutofillProfile* profile,
- AddressValidator* address_validator);
-
-// Sets the validity state of the address fields of the |profile|.
-AddressValidator::Status ValidateAddress(const AutofillProfile* profile,
- AddressValidator* address_validator);
-
-// Sets the validity state of the address fields of the |profile| in two passes.
-// First runs the ValidateAddress, then adds a second layer of validation based
-// on the results.
-void ValidateAddressStrictly(const AutofillProfile* profile,
- AddressValidator* address_validator);
-
-// Sets the validity state of the phone number field of the |profile|.
-void ValidatePhoneNumber(const AutofillProfile* profile);
-
-// Sets the validity state of the email address field of the |profile|.
-void ValidateEmailAddress(const AutofillProfile* profile);
-
-} // namespace profile_validation_util
-} // namespace autofill
-
-#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_PROFILE_VALIDATION_UTIL_H_
diff --git a/chromium/components/autofill/core/browser/autofill_profile_validation_util_unittest.cc b/chromium/components/autofill/core/browser/autofill_profile_validation_util_unittest.cc
deleted file mode 100644
index af875003392..00000000000
--- a/chromium/components/autofill/core/browser/autofill_profile_validation_util_unittest.cc
+++ /dev/null
@@ -1,1133 +0,0 @@
-// Copyright 2017 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.
-
-#include "components/autofill/core/browser/autofill_profile_validation_util.h"
-
-#include <memory>
-#include <string>
-
-#include "base/base_paths.h"
-#include "base/bind.h"
-#include "base/files/file_path.h"
-#include "base/path_service.h"
-#include "base/strings/utf_string_conversions.h"
-#include "components/autofill/core/browser/autofill_test_utils.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/libaddressinput/src/cpp/include/libaddressinput/null_storage.h"
-#include "third_party/libaddressinput/src/cpp/test/testdata_source.h"
-
-namespace autofill {
-
-namespace {
-
-using ::i18n::addressinput::Source;
-using ::i18n::addressinput::Storage;
-using ::i18n::addressinput::NullStorage;
-using ::i18n::addressinput::TestdataSource;
-
-} // namespace
-
-class AutofillProfileValidationUtilTest : public testing::Test,
- public LoadRulesListener {
- public:
- AutofillProfileValidationUtilTest(const AutofillProfileValidationUtilTest&) =
- delete;
- AutofillProfileValidationUtilTest& operator=(
- const AutofillProfileValidationUtilTest&) = delete;
-
- protected:
- AutofillProfileValidationUtilTest() {
- base::FilePath file_path;
- CHECK(base::PathService::Get(base::DIR_SOURCE_ROOT, &file_path));
- file_path = file_path.Append(FILE_PATH_LITERAL("third_party"))
- .Append(FILE_PATH_LITERAL("libaddressinput"))
- .Append(FILE_PATH_LITERAL("src"))
- .Append(FILE_PATH_LITERAL("testdata"))
- .Append(FILE_PATH_LITERAL("countryinfo.txt"));
-
- validator_ = std::make_unique<AddressValidator>(
- std::unique_ptr<Source>(
- new TestdataSource(true, file_path.AsUTF8Unsafe())),
- std::unique_ptr<Storage>(new NullStorage), this);
- validator_->LoadRules("CA");
- // China has rules for locality/dependent locality fields.
- validator_->LoadRules("CN");
- }
-
- void ValidateProfileTest(AutofillProfile* profile) {
- profile_validation_util::ValidateProfile(profile, validator_.get());
- }
-
- void ValidateAddressTest(AutofillProfile* profile) {
- profile_validation_util::ValidateAddressStrictly(profile, validator_.get());
- }
-
- void ValidatePhoneTest(AutofillProfile* profile) {
- profile_validation_util::ValidatePhoneNumber(profile);
- }
-
- void ValidateEmailTest(AutofillProfile* profile) {
- profile_validation_util::ValidateEmailAddress(profile);
- }
-
- ~AutofillProfileValidationUtilTest() override {}
-
- private:
- std::unique_ptr<AddressValidator> validator_;
-
- // LoadRulesListener implementation.
- void OnAddressValidationRulesLoaded(const std::string& country_code,
- bool success) override {}
-};
-
-TEST_F(AutofillProfileValidationUtilTest, ValidateFullValidProfileForCanada) {
- // This is a valid profile according to the rules in contryinfo.txt:
- // Address Line 1: "666 Notre-Dame Ouest",
- // Address Line 2: "Apt 8", City: "Montreal", Province: "QC",
- // Postal Code: "H3B 2T9", Country Code: "CA",
- AutofillProfile profile(autofill::test::GetFullValidProfileForCanada());
- ValidateAddressTest(&profile);
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_COUNTRY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_STATE, AutofillDataModel::CLIENT));
- // For Canada, there is no rule and data to validate the city.
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_CITY, AutofillDataModel::CLIENT));
- // Canada doesn't have a dependent locality. It's not filled, and yet the
- // profile is valid.
- EXPECT_EQ(AutofillDataModel::EMPTY,
- profile.GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_ZIP, AutofillDataModel::CLIENT));
-}
-
-TEST_F(AutofillProfileValidationUtilTest,
- ValidateFullProfile_CountryCodeNotExist) {
- // This is a profile with invalid country code, therefore it cannot be
- // validated according to contryinfo.txt.
- const std::string country_code = "PP";
- AutofillProfile profile(autofill::test::GetFullValidProfileForCanada());
- profile.SetRawInfo(ADDRESS_HOME_COUNTRY, base::UTF8ToUTF16(country_code));
- ValidateAddressTest(&profile);
- EXPECT_EQ(AutofillDataModel::INVALID,
- profile.GetValidityState(ADDRESS_HOME_COUNTRY,
- AutofillDataModel::CLIENT));
- // The zip, the state and the city can't be validated, because we don't know
- // the country, in the strict validation this is considered as invalid.
- EXPECT_EQ(
- AutofillDataModel::INVALID,
- profile.GetValidityState(ADDRESS_HOME_STATE, AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::INVALID,
- profile.GetValidityState(ADDRESS_HOME_CITY, AutofillDataModel::CLIENT));
- EXPECT_EQ(AutofillDataModel::EMPTY,
- profile.GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::INVALID,
- profile.GetValidityState(ADDRESS_HOME_ZIP, AutofillDataModel::CLIENT));
-}
-
-TEST_F(AutofillProfileValidationUtilTest,
- ValidateFullProfile_EmptyCountryCode) {
- // This is a profile with no country code, therefore it cannot be validated
- // according to contryinfo.txt.
- AutofillProfile profile(autofill::test::GetFullValidProfileForCanada());
- profile.SetRawInfo(ADDRESS_HOME_COUNTRY, u"");
- ValidateAddressTest(&profile);
- EXPECT_EQ(AutofillDataModel::EMPTY,
- profile.GetValidityState(ADDRESS_HOME_COUNTRY,
- AutofillDataModel::CLIENT));
- // The zip, the state and the city can't be validated, because we don't know
- // the country, in the strict validation this is considered as invalid.
- EXPECT_EQ(
- AutofillDataModel::INVALID,
- profile.GetValidityState(ADDRESS_HOME_STATE, AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::INVALID,
- profile.GetValidityState(ADDRESS_HOME_CITY, AutofillDataModel::CLIENT));
- EXPECT_EQ(AutofillDataModel::EMPTY,
- profile.GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::INVALID,
- profile.GetValidityState(ADDRESS_HOME_ZIP, AutofillDataModel::CLIENT));
-}
-
-TEST_F(AutofillProfileValidationUtilTest,
- ValidateFullProfile_RuleNotAvailable) {
- // This is a profile with valid country code, but the rule is not available in
- // the contryinfo.txt.
- const std::string country_code = "US";
- AutofillProfile profile(autofill::test::GetFullValidProfileForCanada());
- profile.SetRawInfo(ADDRESS_HOME_COUNTRY, base::UTF8ToUTF16(country_code));
- ValidateAddressTest(&profile);
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_COUNTRY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::UNVALIDATED,
- profile.GetValidityState(ADDRESS_HOME_STATE, AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::UNVALIDATED,
- profile.GetValidityState(ADDRESS_HOME_CITY, AutofillDataModel::CLIENT));
- EXPECT_EQ(AutofillDataModel::EMPTY,
- profile.GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::UNVALIDATED,
- profile.GetValidityState(ADDRESS_HOME_ZIP, AutofillDataModel::CLIENT));
-}
-
-TEST_F(AutofillProfileValidationUtilTest, ValidateAddress_AdminAreaNotExists) {
- const std::string admin_area_code = "QQ";
- AutofillProfile profile(autofill::test::GetFullValidProfileForCanada());
- profile.SetRawInfo(ADDRESS_HOME_STATE, base::UTF8ToUTF16(admin_area_code));
-
- ValidateAddressTest(&profile);
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_COUNTRY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::INVALID,
- profile.GetValidityState(ADDRESS_HOME_STATE, AutofillDataModel::CLIENT));
- // The city can't be validated, because we don't know the state, in the strict
- // validation this is considered as invalid.
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_CITY, AutofillDataModel::CLIENT));
- EXPECT_EQ(AutofillDataModel::EMPTY,
- profile.GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_ZIP, AutofillDataModel::CLIENT));
-}
-
-TEST_F(AutofillProfileValidationUtilTest, ValidateAddress_EmptyAdminArea) {
- AutofillProfile profile(autofill::test::GetFullValidProfileForCanada());
- profile.SetRawInfo(ADDRESS_HOME_STATE, u"");
-
- ValidateAddressTest(&profile);
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_COUNTRY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::EMPTY,
- profile.GetValidityState(ADDRESS_HOME_STATE, AutofillDataModel::CLIENT));
- // The city can't be validated, because we don't know the state, in the strict
- // validation this is considered as invalid.
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_CITY, AutofillDataModel::CLIENT));
- EXPECT_EQ(AutofillDataModel::EMPTY,
- profile.GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_ZIP, AutofillDataModel::CLIENT));
-}
-
-TEST_F(AutofillProfileValidationUtilTest, ValidateAddress_AdminAreaFullName) {
- const std::string admin_area = "Quebec";
- AutofillProfile profile(autofill::test::GetFullValidProfileForCanada());
- profile.SetRawInfo(ADDRESS_HOME_STATE, base::UTF8ToUTF16(admin_area));
-
- ValidateAddressTest(&profile);
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_COUNTRY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_STATE, AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_CITY, AutofillDataModel::CLIENT));
- EXPECT_EQ(AutofillDataModel::EMPTY,
- profile.GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_ZIP, AutofillDataModel::CLIENT));
-}
-
-TEST_F(AutofillProfileValidationUtilTest, ValidateAddress_AdminAreaLowerCase) {
- const std::string admin_area = "qc";
- AutofillProfile profile(autofill::test::GetFullValidProfileForCanada());
- profile.SetRawInfo(ADDRESS_HOME_STATE, base::UTF8ToUTF16(admin_area));
-
- ValidateAddressTest(&profile);
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_COUNTRY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_STATE, AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_CITY, AutofillDataModel::CLIENT));
- EXPECT_EQ(AutofillDataModel::EMPTY,
- profile.GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_ZIP, AutofillDataModel::CLIENT));
-}
-
-TEST_F(AutofillProfileValidationUtilTest,
- ValidateAddress_AdminAreaSpecialLetter) {
- const std::string admin_area = "Québec";
- AutofillProfile profile(autofill::test::GetFullValidProfileForCanada());
- profile.SetRawInfo(ADDRESS_HOME_STATE, base::UTF8ToUTF16(admin_area));
-
- ValidateAddressTest(&profile);
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_COUNTRY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_STATE, AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_CITY, AutofillDataModel::CLIENT));
- EXPECT_EQ(AutofillDataModel::EMPTY,
- profile.GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_ZIP, AutofillDataModel::CLIENT));
-}
-
-TEST_F(AutofillProfileValidationUtilTest,
- ValidateAddress_AdminAreaNonDefaultLanguage) {
- // For this profile, different fields are in different available languages of
- // the country (Canada), and the language is not set. This is considered as
- // valid.
- const std::string admin_area = "Nouveau-Brunswick";
- const std::string postal_code = "E1A 8R5"; // A valid postal code for NB.
- AutofillProfile profile(autofill::test::GetFullValidProfileForCanada());
- profile.SetRawInfo(ADDRESS_HOME_STATE, base::UTF8ToUTF16(admin_area));
- profile.SetRawInfo(ADDRESS_HOME_ZIP, base::UTF8ToUTF16(postal_code));
-
- ValidateAddressTest(&profile);
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_COUNTRY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_STATE, AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_CITY, AutofillDataModel::CLIENT));
- EXPECT_EQ(AutofillDataModel::EMPTY,
- profile.GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_ZIP, AutofillDataModel::CLIENT));
-}
-
-TEST_F(AutofillProfileValidationUtilTest, ValidateAddress_ValidZipNoSpace) {
- const std::string postal_code = "H3C6S3";
- AutofillProfile profile(autofill::test::GetFullValidProfileForCanada());
- profile.SetRawInfo(ADDRESS_HOME_ZIP, base::UTF8ToUTF16(postal_code));
-
- ValidateAddressTest(&profile);
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_COUNTRY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_STATE, AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_CITY, AutofillDataModel::CLIENT));
- EXPECT_EQ(AutofillDataModel::EMPTY,
- profile.GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_ZIP, AutofillDataModel::CLIENT));
-}
-
-TEST_F(AutofillProfileValidationUtilTest, ValidateAddress_ValidZipLowerCase) {
- // Postal codes in lower case letters should also be considered valid.
- const std::string postal_code = "h3c 6s3";
- AutofillProfile profile(autofill::test::GetFullValidProfileForCanada());
- profile.SetRawInfo(ADDRESS_HOME_ZIP, base::UTF8ToUTF16(postal_code));
-
- ValidateAddressTest(&profile);
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_COUNTRY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_STATE, AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_CITY, AutofillDataModel::CLIENT));
- EXPECT_EQ(AutofillDataModel::EMPTY,
- profile.GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_ZIP, AutofillDataModel::CLIENT));
-}
-
-TEST_F(AutofillProfileValidationUtilTest, ValidateAddress_InvalidZip) {
- const std::string postal_code = "ABC 123";
- AutofillProfile profile(autofill::test::GetFullValidProfileForCanada());
- profile.SetRawInfo(ADDRESS_HOME_ZIP, base::UTF8ToUTF16(postal_code));
-
- ValidateAddressTest(&profile);
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_COUNTRY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_STATE, AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_CITY, AutofillDataModel::CLIENT));
- EXPECT_EQ(AutofillDataModel::EMPTY,
- profile.GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::INVALID,
- profile.GetValidityState(ADDRESS_HOME_ZIP, AutofillDataModel::CLIENT));
-}
-
-TEST_F(AutofillProfileValidationUtilTest, ValidateAddress_EmptyZip) {
- AutofillProfile profile(autofill::test::GetFullValidProfileForCanada());
- profile.SetRawInfo(ADDRESS_HOME_ZIP, u"");
-
- ValidateAddressTest(&profile);
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_COUNTRY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_STATE, AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_CITY, AutofillDataModel::CLIENT));
- EXPECT_EQ(AutofillDataModel::EMPTY,
- profile.GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::EMPTY,
- profile.GetValidityState(ADDRESS_HOME_ZIP, AutofillDataModel::CLIENT));
-}
-
-TEST_F(AutofillProfileValidationUtilTest, ValidateAddress_EmptyCity) {
- // Although, for Canada, there is no rule to validate the city (aka locality)
- // field, the field is required. Therefore, a profile without a city field
- // would be an invalid profile.
- AutofillProfile profile(autofill::test::GetFullValidProfileForCanada());
- profile.SetRawInfo(ADDRESS_HOME_CITY, u"");
-
- ValidateAddressTest(&profile);
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_COUNTRY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_STATE, AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::EMPTY,
- profile.GetValidityState(ADDRESS_HOME_CITY, AutofillDataModel::CLIENT));
- EXPECT_EQ(AutofillDataModel::EMPTY,
- profile.GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_ZIP, AutofillDataModel::CLIENT));
-}
-
-TEST_F(AutofillProfileValidationUtilTest, ValidateFullProfile_EmptyFields) {
- AutofillProfile profile(autofill::test::GetFullValidProfileForCanada());
- profile.SetRawInfo(ADDRESS_HOME_COUNTRY, u"");
- profile.SetRawInfo(ADDRESS_HOME_STATE, u"");
- profile.SetRawInfo(ADDRESS_HOME_CITY, u"");
- profile.SetRawInfo(ADDRESS_HOME_ZIP, u"");
-
- ValidateAddressTest(&profile);
- EXPECT_EQ(AutofillDataModel::EMPTY,
- profile.GetValidityState(ADDRESS_HOME_COUNTRY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::EMPTY,
- profile.GetValidityState(ADDRESS_HOME_STATE, AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::EMPTY,
- profile.GetValidityState(ADDRESS_HOME_CITY, AutofillDataModel::CLIENT));
- EXPECT_EQ(AutofillDataModel::EMPTY,
- profile.GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::EMPTY,
- profile.GetValidityState(ADDRESS_HOME_ZIP, AutofillDataModel::CLIENT));
-}
-
-TEST_F(AutofillProfileValidationUtilTest, ValidateFullValidProfileForChina) {
- // This is a valid profile according to the rules in countryinfo.txt:
- // Address Address: "100 Century Avenue",
- // District: "赫章县", City: "毕节地区", Province: "贵州çœ",
- // Postal Code: "200120", Country Code: "CN",
- AutofillProfile profile(autofill::test::GetFullValidProfileForChina());
-
- ValidateAddressTest(&profile);
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_COUNTRY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_STATE, AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_CITY, AutofillDataModel::CLIENT));
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_ZIP, AutofillDataModel::CLIENT));
-}
-
-TEST_F(AutofillProfileValidationUtilTest,
- ValidateFullValidProfile_InvalidCity) {
- const std::string invalid_city = "毕节";
- AutofillProfile profile(autofill::test::GetFullValidProfileForChina());
- profile.SetRawInfo(ADDRESS_HOME_CITY, base::UTF8ToUTF16(invalid_city));
-
- ValidateAddressTest(&profile);
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_COUNTRY,
- AutofillDataModel::CLIENT));
- // The city which is the only dependent field on state is invalid, in the
- // strict validation the state would also be considered as invalid.
- EXPECT_EQ(
- AutofillDataModel::INVALID,
- profile.GetValidityState(ADDRESS_HOME_STATE, AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::INVALID,
- profile.GetValidityState(ADDRESS_HOME_CITY, AutofillDataModel::CLIENT));
- // The dependent locality can't be validated, because we don't know the city,
- // in the strict validation this is considered as invalid.
- EXPECT_EQ(AutofillDataModel::INVALID,
- profile.GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_ZIP, AutofillDataModel::CLIENT));
-}
-
-TEST_F(AutofillProfileValidationUtilTest,
- ValidateFullValidProfile_MisplacedCity) {
- // "æ­é˜³å¸‚" is a valid city name, but not in the "贵州çœ" province. Therefore,
- // the city would be considered as INVALID.
-
- const std::string city = "æ­é˜³å¸‚";
- AutofillProfile profile(autofill::test::GetFullValidProfileForChina());
- profile.SetRawInfo(ADDRESS_HOME_CITY, base::UTF8ToUTF16(city));
-
- ValidateAddressTest(&profile);
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_COUNTRY,
- AutofillDataModel::CLIENT));
- // The city which is the only dependent field on state is invalid, in the
- // strict validation the state would also be considered as invalid.
- EXPECT_EQ(
- AutofillDataModel::INVALID,
- profile.GetValidityState(ADDRESS_HOME_STATE, AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::INVALID,
- profile.GetValidityState(ADDRESS_HOME_CITY, AutofillDataModel::CLIENT));
- // The dependent locality can't be validated, because we don't know the city,
- // in the strict validation this is considered as invalid.
- EXPECT_EQ(AutofillDataModel::INVALID,
- profile.GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_ZIP, AutofillDataModel::CLIENT));
-}
-
-TEST_F(AutofillProfileValidationUtilTest,
- ValidateFullValidProfile_LatinNameForCity) {
- const std::string admin_area = "Guizhou Sheng";
- const std::string city = "Bijie Diqu";
- const std::string district = "Weining Xian";
- AutofillProfile profile(autofill::test::GetFullValidProfileForChina());
- profile.SetRawInfo(ADDRESS_HOME_STATE, base::UTF8ToUTF16(admin_area));
- profile.SetRawInfo(ADDRESS_HOME_CITY, base::UTF8ToUTF16(city));
- profile.SetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY,
- base::UTF8ToUTF16(district));
-
- ValidateAddressTest(&profile);
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_COUNTRY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_STATE, AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_CITY, AutofillDataModel::CLIENT));
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_ZIP, AutofillDataModel::CLIENT));
-}
-
-TEST_F(AutofillProfileValidationUtilTest,
- ValidateFullValidProfile_EmptyDistrict) {
- // China has a dependent locality field (aka district), but it's not required.
-
- AutofillProfile profile(autofill::test::GetFullValidProfileForChina());
- profile.SetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY, u"");
-
- ValidateAddressTest(&profile);
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_COUNTRY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_STATE, AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_CITY, AutofillDataModel::CLIENT));
- EXPECT_EQ(AutofillDataModel::EMPTY,
- profile.GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_ZIP, AutofillDataModel::CLIENT));
-}
-
-TEST_F(AutofillProfileValidationUtilTest,
- ValidateFullValidProfile_InvalidDistrict) {
- // Though the dependent locality (aka district) field is not a required field,
- // but we should still validate it.
-
- AutofillProfile profile(autofill::test::GetFullValidProfileForChina());
- profile.SetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY, u"赫");
-
- ValidateAddressTest(&profile);
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_COUNTRY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_STATE, AutofillDataModel::CLIENT));
- // The dependent locality which is the only dependent field on city is
- // invalid, in the strict validation the city would also be invalid.
- EXPECT_EQ(
- AutofillDataModel::INVALID,
- profile.GetValidityState(ADDRESS_HOME_CITY, AutofillDataModel::CLIENT));
- EXPECT_EQ(AutofillDataModel::INVALID,
- profile.GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_ZIP, AutofillDataModel::CLIENT));
-}
-
-TEST_F(AutofillProfileValidationUtilTest,
- ValidateFullValidProfile_MisplacedDistrict) {
- // "蒙城县" is a valid district name, but not in the "æ­é˜³å¸‚" city. Therefore,
- // the district should be considered as INVALID.
-
- AutofillProfile profile(autofill::test::GetFullValidProfileForChina());
- profile.SetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY, u"蒙城县");
-
- ValidateAddressTest(&profile);
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_COUNTRY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_STATE, AutofillDataModel::CLIENT));
- // The only that depend on city (dependent locality) is invalid,
- // in the strict validation city would also be considered as invalid.
- EXPECT_EQ(
- AutofillDataModel::INVALID,
- profile.GetValidityState(ADDRESS_HOME_CITY, AutofillDataModel::CLIENT));
- EXPECT_EQ(AutofillDataModel::INVALID,
- profile.GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_ZIP, AutofillDataModel::CLIENT));
-}
-
-TEST_F(AutofillProfileValidationUtilTest, ValidatePhone_FullValidProfile) {
- // This is a full valid profile:
- // Country Code: "CA", Phone Number: "15141112233"
- AutofillProfile profile(autofill::test::GetFullValidProfileForCanada());
- ValidatePhoneTest(&profile);
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(PHONE_HOME_WHOLE_NUMBER,
- AutofillDataModel::CLIENT));
-}
-
-TEST_F(AutofillProfileValidationUtilTest, ValidatePhone_EmptyPhoneNumber) {
- AutofillProfile profile(autofill::test::GetFullValidProfileForCanada());
- profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, std::u16string());
- ValidatePhoneTest(&profile);
- EXPECT_EQ(AutofillDataModel::EMPTY,
- profile.GetValidityState(PHONE_HOME_WHOLE_NUMBER,
- AutofillDataModel::CLIENT));
-}
-
-TEST_F(AutofillProfileValidationUtilTest,
- ValidatePhone_ValidPhoneCountryCodeNotExist) {
- // This is a profile with invalid country code, therefore the phone number
- // cannot be validated.
- const std::string country_code = "PP";
- AutofillProfile profile(autofill::test::GetFullValidProfileForCanada());
- profile.SetRawInfo(ADDRESS_HOME_COUNTRY, base::UTF8ToUTF16(country_code));
- ValidatePhoneTest(&profile);
- EXPECT_EQ(AutofillDataModel::UNVALIDATED,
- profile.GetValidityState(PHONE_HOME_WHOLE_NUMBER,
- AutofillDataModel::CLIENT));
-}
-
-TEST_F(AutofillProfileValidationUtilTest,
- ValidatePhone_EmptyPhoneCountryCodeNotExist) {
- // This is a profile with invalid country code, but a missing phone number.
- // Therefore, it's an invalid phone number.
- const std::string country_code = "PP";
- AutofillProfile profile(autofill::test::GetFullValidProfileForCanada());
- profile.SetRawInfo(ADDRESS_HOME_COUNTRY, base::UTF8ToUTF16(country_code));
- profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, std::u16string());
- ValidatePhoneTest(&profile);
- EXPECT_EQ(AutofillDataModel::EMPTY,
- profile.GetValidityState(PHONE_HOME_WHOLE_NUMBER,
- AutofillDataModel::CLIENT));
-}
-
-TEST_F(AutofillProfileValidationUtilTest, ValidatePhone_InvalidPhoneNumber) {
- AutofillProfile profile(autofill::test::GetFullValidProfileForCanada());
- profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, u"33");
- ValidatePhoneTest(&profile);
- EXPECT_EQ(AutofillDataModel::INVALID,
- profile.GetValidityState(PHONE_HOME_WHOLE_NUMBER,
- AutofillDataModel::CLIENT));
-
- profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, u"151411122334");
- ValidatePhoneTest(&profile);
- EXPECT_EQ(AutofillDataModel::INVALID,
- profile.GetValidityState(PHONE_HOME_WHOLE_NUMBER,
- AutofillDataModel::CLIENT));
-
- profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, u"1(514)111-22-334");
- ValidatePhoneTest(&profile);
- EXPECT_EQ(AutofillDataModel::INVALID,
- profile.GetValidityState(PHONE_HOME_WHOLE_NUMBER,
- AutofillDataModel::CLIENT));
-
- profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, u"251411122334");
- ValidatePhoneTest(&profile);
- EXPECT_EQ(AutofillDataModel::INVALID,
- profile.GetValidityState(PHONE_HOME_WHOLE_NUMBER,
- AutofillDataModel::CLIENT));
-
- profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, u"Hello!");
- ValidatePhoneTest(&profile);
- EXPECT_EQ(AutofillDataModel::INVALID,
- profile.GetValidityState(PHONE_HOME_WHOLE_NUMBER,
- AutofillDataModel::CLIENT));
-}
-
-TEST_F(AutofillProfileValidationUtilTest, ValidatePhone_ValidPhoneNumber) {
- AutofillProfile profile(autofill::test::GetFullValidProfileForCanada());
- profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, u"5141112233");
- ValidatePhoneTest(&profile);
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(PHONE_HOME_WHOLE_NUMBER,
- AutofillDataModel::CLIENT));
-
- profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, u"514-111-2233");
- ValidatePhoneTest(&profile);
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(PHONE_HOME_WHOLE_NUMBER,
- AutofillDataModel::CLIENT));
-
- profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, u"1(514)111-22-33");
- ValidatePhoneTest(&profile);
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(PHONE_HOME_WHOLE_NUMBER,
- AutofillDataModel::CLIENT));
-
- profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, u"+1 514 111 22 33");
- ValidatePhoneTest(&profile);
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(PHONE_HOME_WHOLE_NUMBER,
- AutofillDataModel::CLIENT));
-
- profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, u"+1 (514)-111-22-33");
- ValidatePhoneTest(&profile);
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(PHONE_HOME_WHOLE_NUMBER,
- AutofillDataModel::CLIENT));
-
- profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, u"(514)-111-22-33");
- ValidatePhoneTest(&profile);
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(PHONE_HOME_WHOLE_NUMBER,
- AutofillDataModel::CLIENT));
-
- profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, u"+1 650 GOO OGLE");
- ValidatePhoneTest(&profile);
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(PHONE_HOME_WHOLE_NUMBER,
- AutofillDataModel::CLIENT));
-
- profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, u"778 111 22 33");
- ValidatePhoneTest(&profile);
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(PHONE_HOME_WHOLE_NUMBER,
- AutofillDataModel::CLIENT));
-}
-
-TEST_F(AutofillProfileValidationUtilTest, ValidateEmail_FullValidProfile) {
- // This is a full valid profile:
- // Email: "alice@wonderland.ca"
- AutofillProfile profile(autofill::test::GetFullValidProfileForCanada());
- ValidateEmailTest(&profile);
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(EMAIL_ADDRESS, AutofillDataModel::CLIENT));
-}
-
-TEST_F(AutofillProfileValidationUtilTest, ValidateEmail_EmptyEmailAddress) {
- AutofillProfile profile(autofill::test::GetFullValidProfileForCanada());
- profile.SetRawInfo(EMAIL_ADDRESS, std::u16string());
- ValidateEmailTest(&profile);
- EXPECT_EQ(AutofillDataModel::EMPTY,
- profile.GetValidityState(EMAIL_ADDRESS, AutofillDataModel::CLIENT));
-}
-
-TEST_F(AutofillProfileValidationUtilTest,
- ValidateEmail_ValidateInvalidEmailAddress) {
- AutofillProfile profile(autofill::test::GetFullValidProfileForCanada());
- profile.SetRawInfo(EMAIL_ADDRESS, u"Hello!");
- ValidateEmailTest(&profile);
- EXPECT_EQ(AutofillDataModel::INVALID,
- profile.GetValidityState(EMAIL_ADDRESS, AutofillDataModel::CLIENT));
-
- profile.SetRawInfo(EMAIL_ADDRESS, u"alice.wonderland");
- ValidateEmailTest(&profile);
- EXPECT_EQ(AutofillDataModel::INVALID,
- profile.GetValidityState(EMAIL_ADDRESS, AutofillDataModel::CLIENT));
-
- profile.SetRawInfo(EMAIL_ADDRESS, u"alice@");
- ValidateEmailTest(&profile);
- EXPECT_EQ(AutofillDataModel::INVALID,
- profile.GetValidityState(EMAIL_ADDRESS, AutofillDataModel::CLIENT));
-
- profile.SetRawInfo(EMAIL_ADDRESS, u"alice@=wonderland.com");
- ValidateEmailTest(&profile);
- EXPECT_EQ(AutofillDataModel::INVALID,
- profile.GetValidityState(EMAIL_ADDRESS, AutofillDataModel::CLIENT));
-}
-
-TEST_F(AutofillProfileValidationUtilTest, ValidateEmail_ValidEmailAddress) {
- AutofillProfile profile(autofill::test::GetFullValidProfileForCanada());
-
- profile.SetRawInfo(EMAIL_ADDRESS, u"alice@wonderland");
- ValidateEmailTest(&profile);
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(EMAIL_ADDRESS, AutofillDataModel::CLIENT));
-
- profile.SetRawInfo(EMAIL_ADDRESS, u"alice@wonderland.fiction");
- ValidateEmailTest(&profile);
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(EMAIL_ADDRESS, AutofillDataModel::CLIENT));
-
- profile.SetRawInfo(EMAIL_ADDRESS, u"alice+cat@wonderland.fiction.book");
- ValidateEmailTest(&profile);
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(EMAIL_ADDRESS, AutofillDataModel::CLIENT));
-}
-
-TEST_F(AutofillProfileValidationUtilTest, ValidateProfile_FullValidProfile) {
- // This is a full valid profile:
- AutofillProfile profile(autofill::test::GetFullValidProfileForCanada());
- ValidateProfileTest(&profile);
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_COUNTRY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_STATE, AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_ZIP, AutofillDataModel::CLIENT));
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(EMAIL_ADDRESS, AutofillDataModel::CLIENT));
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(PHONE_HOME_WHOLE_NUMBER,
- AutofillDataModel::CLIENT));
-}
-
-TEST_F(AutofillProfileValidationUtilTest,
- ValidateProfile_FullValidProfileWithInvalidZip) {
- // This is a full valid profile:
- AutofillProfile profile(autofill::test::GetFullValidProfileForCanada());
- profile.SetRawInfo(ADDRESS_HOME_ZIP, u"ABC 123");
- ValidateProfileTest(&profile);
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_COUNTRY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_STATE, AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_CITY, AutofillDataModel::CLIENT));
- EXPECT_EQ(AutofillDataModel::EMPTY,
- profile.GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::INVALID,
- profile.GetValidityState(ADDRESS_HOME_ZIP, AutofillDataModel::CLIENT));
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(EMAIL_ADDRESS, AutofillDataModel::CLIENT));
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(PHONE_HOME_WHOLE_NUMBER,
- AutofillDataModel::CLIENT));
-}
-
-TEST_F(AutofillProfileValidationUtilTest,
- ValidateProfile_FullValidProfileWithInvalidPhone) {
- // This is a full valid profile:
- AutofillProfile profile(autofill::test::GetFullValidProfileForCanada());
- profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, u"33");
- ValidateProfileTest(&profile);
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_COUNTRY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_STATE, AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_CITY, AutofillDataModel::CLIENT));
- EXPECT_EQ(AutofillDataModel::EMPTY,
- profile.GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_ZIP, AutofillDataModel::CLIENT));
- EXPECT_EQ(AutofillDataModel::INVALID,
- profile.GetValidityState(PHONE_HOME_WHOLE_NUMBER,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(EMAIL_ADDRESS, AutofillDataModel::CLIENT));
-}
-
-TEST_F(AutofillProfileValidationUtilTest,
- ValidateProfile_FullValidProfileWithInvalidEmail) {
- // This is a full valid profile:
- AutofillProfile profile(autofill::test::GetFullValidProfileForCanada());
- profile.SetRawInfo(EMAIL_ADDRESS, u"fakeaddress");
- ValidateProfileTest(&profile);
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_COUNTRY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_STATE, AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_CITY, AutofillDataModel::CLIENT));
- EXPECT_EQ(AutofillDataModel::EMPTY,
- profile.GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_ZIP, AutofillDataModel::CLIENT));
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(PHONE_HOME_WHOLE_NUMBER,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(AutofillDataModel::INVALID,
- profile.GetValidityState(EMAIL_ADDRESS, AutofillDataModel::CLIENT));
-}
-
-TEST_F(AutofillProfileValidationUtilTest,
- ValidateProfile_TopToBottomValidationCanada) {
- // This is a full valid profile, with the wrong country:
- // Address Line 1: "666 Notre-Dame Ouest",
- // Address Line 2: "Apt 8", City: "Montreal", Province: "QC",
- // Postal Code: "H3B 2T9", Country Code: "CN",
- AutofillProfile profile(autofill::test::GetFullValidProfileForCanada());
- profile.SetRawInfo(ADDRESS_HOME_COUNTRY, u"CN");
-
- ValidateProfileTest(&profile);
- // The fields that depend on country (state and zip) are both invalid,
- // therefore in the strict validation this is considered as invalid.
- EXPECT_EQ(AutofillDataModel::INVALID,
- profile.GetValidityState(ADDRESS_HOME_COUNTRY,
- AutofillDataModel::CLIENT));
- // The state is not a Chinese state, so it's considered as invalid.
- EXPECT_EQ(
- AutofillDataModel::INVALID,
- profile.GetValidityState(ADDRESS_HOME_STATE, AutofillDataModel::CLIENT));
- // The city can't be validated, because the state value is not
- // valid, in the strict validation this is considered as invalid.
- EXPECT_EQ(
- AutofillDataModel::INVALID,
- profile.GetValidityState(ADDRESS_HOME_CITY, AutofillDataModel::CLIENT));
-
- EXPECT_EQ(AutofillDataModel::EMPTY,
- profile.GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(AutofillDataModel::UNSUPPORTED,
- profile.GetValidityState(ADDRESS_HOME_STREET_ADDRESS,
- AutofillDataModel::CLIENT));
- // The zip is not a Chinese one, therefore it's invalid.
- EXPECT_EQ(
- AutofillDataModel::INVALID,
- profile.GetValidityState(ADDRESS_HOME_ZIP, AutofillDataModel::CLIENT));
- // Phone number is validated regardless of the country.
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(PHONE_HOME_WHOLE_NUMBER,
- AutofillDataModel::CLIENT));
-}
-
-TEST_F(AutofillProfileValidationUtilTest,
- ValidateProfile_TopToBottomValidationChina) {
- // This is a full valid profile, with the wrong country:
- // Address Address: "100 Century Avenue",
- // District: "赫章县", City: "毕节地区", Province: "贵州çœ",
- // Postal Code: "200120", Country Code: "CA",
- AutofillProfile profile(autofill::test::GetFullValidProfileForChina());
- profile.SetRawInfo(ADDRESS_HOME_COUNTRY, u"CA");
-
- ValidateProfileTest(&profile);
-
- // The fields that depend on Country (state and zip) are both invalid,
- // therefore in the strict validation this is considered as invalid.
- EXPECT_EQ(AutofillDataModel::INVALID,
- profile.GetValidityState(ADDRESS_HOME_COUNTRY,
- AutofillDataModel::CLIENT));
- // The state is not a Canadian state, so it's considered as invalid.
- EXPECT_EQ(
- AutofillDataModel::INVALID,
- profile.GetValidityState(ADDRESS_HOME_STATE, AutofillDataModel::CLIENT));
- // We can't validate city, because state is not valid, in the strict
- // validation this is considered as invalid.
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_CITY, AutofillDataModel::CLIENT));
- // The dependent locality is not a Canadian field, so it's considered as
- // invalid.
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(AutofillDataModel::UNSUPPORTED,
- profile.GetValidityState(ADDRESS_HOME_STREET_ADDRESS,
- AutofillDataModel::CLIENT));
-
- // The zip is not a Canadian one, therefore it's invalid.
- EXPECT_EQ(
- AutofillDataModel::INVALID,
- profile.GetValidityState(ADDRESS_HOME_ZIP, AutofillDataModel::CLIENT));
- // Phone number is validated regardless of the country.
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(PHONE_HOME_WHOLE_NUMBER,
- AutofillDataModel::CLIENT));
-}
-
-TEST_F(AutofillProfileValidationUtilTest,
- ValidateProfile_TopToBottomValidationChina_StateWrong) {
- // This is a full valid profile, with the wrong province:
- // Address Address: "100 Century Avenue",
- // District: "赫章县", City: "毕节地区", Province: "æµ·å—çœ",
- // Postal Code: "200120", Country Code: "CN",
- AutofillProfile profile(autofill::test::GetFullValidProfileForChina());
- profile.SetRawInfo(ADDRESS_HOME_STATE, u"æµ·å—çœ");
-
- ValidateProfileTest(&profile);
-
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_COUNTRY,
- AutofillDataModel::CLIENT));
- // The only field that depends on state (city) is invalid, in the strict
- // validation this makes state also invalid.
- EXPECT_EQ(
- AutofillDataModel::INVALID,
- profile.GetValidityState(ADDRESS_HOME_STATE, AutofillDataModel::CLIENT));
- // The city is in another province.
- EXPECT_EQ(
- AutofillDataModel::INVALID,
- profile.GetValidityState(ADDRESS_HOME_CITY, AutofillDataModel::CLIENT));
- // The dependent locality can't be validated, because the city value is not
- // valid, in the strict validation this is considered as invalid.
- EXPECT_EQ(AutofillDataModel::INVALID,
- profile.GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(AutofillDataModel::UNSUPPORTED,
- profile.GetValidityState(ADDRESS_HOME_STREET_ADDRESS,
- AutofillDataModel::CLIENT));
-
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_ZIP, AutofillDataModel::CLIENT));
- // Phone number is validated regardless of the country.
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(PHONE_HOME_WHOLE_NUMBER,
- AutofillDataModel::CLIENT));
-}
-
-TEST_F(AutofillProfileValidationUtilTest,
- ValidateProfile_TopToBottomValidationChina_StateMissing) {
- // This is a full valid profile, with the empty province:
- // Address Address: "100 Century Avenue",
- // District: "赫章县", City: "毕节地区", Province: "",
- // Postal Code: "200120", Country Code: "CN",
- AutofillProfile profile(autofill::test::GetFullValidProfileForChina());
- profile.SetRawInfo(ADDRESS_HOME_STATE, u"");
-
- ValidateProfileTest(&profile);
-
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_COUNTRY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::EMPTY,
- profile.GetValidityState(ADDRESS_HOME_STATE, AutofillDataModel::CLIENT));
- // City can't be validated, because the state is missing, in the strict
- // validation this is considered as invalid.
- EXPECT_EQ(
- AutofillDataModel::INVALID,
- profile.GetValidityState(ADDRESS_HOME_CITY, AutofillDataModel::CLIENT));
- // The dependent locality can't be validated, because we don't know the city,
- // in the strict validation this is considered as invalid.
- EXPECT_EQ(AutofillDataModel::INVALID,
- profile.GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(AutofillDataModel::UNSUPPORTED,
- profile.GetValidityState(ADDRESS_HOME_STREET_ADDRESS,
- AutofillDataModel::CLIENT));
-
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_ZIP, AutofillDataModel::CLIENT));
- // Phone number is validated regardless of the country.
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(PHONE_HOME_WHOLE_NUMBER,
- AutofillDataModel::CLIENT));
-}
-
-} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_profile_validator.cc b/chromium/components/autofill/core/browser/autofill_profile_validator.cc
deleted file mode 100644
index 6cd26a818d7..00000000000
--- a/chromium/components/autofill/core/browser/autofill_profile_validator.cc
+++ /dev/null
@@ -1,128 +0,0 @@
-// Copyright 2017 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.
-
-#include "components/autofill/core/browser/autofill_profile_validator.h"
-
-#include <memory>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/callback_helpers.h"
-#include "base/cancelable_callback.h"
-#include "base/check.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/threading/sequenced_task_runner_handle.h"
-#include "base/time/time.h"
-#include "components/autofill/core/browser/autofill_profile_validation_util.h"
-#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_data.h"
-#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_validator.h"
-
-namespace autofill {
-namespace {
-
-using ::i18n::addressinput::COUNTRY;
-using ::i18n::addressinput::ADMIN_AREA;
-using ::i18n::addressinput::LOCALITY;
-using ::i18n::addressinput::DEPENDENT_LOCALITY;
-using ::i18n::addressinput::SORTING_CODE;
-using ::i18n::addressinput::POSTAL_CODE;
-using ::i18n::addressinput::STREET_ADDRESS;
-using ::i18n::addressinput::RECIPIENT;
-
-const int kRulesLoadingTimeoutSeconds = 5;
-
-} // namespace
-
-AutofillProfileValidator::ValidationRequest::ValidationRequest(
- base::WeakPtr<const AutofillProfile> profile,
- autofill::AddressValidator* validator,
- AutofillProfileValidatorCallback on_validated)
- : profile_(*profile),
- validator_(validator),
- on_validated_(std::move(on_validated)),
- has_responded_(false) {
- on_timeout_.Reset(base::BindOnce(&ValidationRequest::OnRulesLoaded,
- weak_factory_.GetWeakPtr()));
- base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
- FROM_HERE, on_timeout_.callback(),
- base::Seconds(kRulesLoadingTimeoutSeconds));
-}
-
-AutofillProfileValidator::ValidationRequest::~ValidationRequest() {
- on_timeout_.Cancel();
-}
-
-void AutofillProfileValidator::ValidationRequest::OnRulesLoaded() {
- on_timeout_.Cancel();
- // Check if the timeout happened before the rules were loaded.
- if (has_responded_)
- return;
- has_responded_ = true;
-
- profile_validation_util::ValidateProfile(&profile_, validator_);
- std::move(on_validated_).Run(&profile_);
-}
-
-AutofillProfileValidator::AutofillProfileValidator(
- std::unique_ptr<::i18n::addressinput::Source> source,
- std::unique_ptr<::i18n::addressinput::Storage> storage)
- : address_validator_(std::move(source), std::move(storage), this) {}
-
-AutofillProfileValidator::~AutofillProfileValidator() {}
-
-void AutofillProfileValidator::StartProfileValidation(
- const AutofillProfile* profile,
- AutofillProfileValidatorCallback cb) {
- DCHECK(profile);
- if (!profile)
- return;
-
- std::unique_ptr<ValidationRequest> request(
- std::make_unique<ValidationRequest>(profile->GetWeakPtr(),
- &address_validator_, std::move(cb)));
-
- // If the |region_code| is not a valid code according to our source, calling
- // LoadRules would result in calling OnAddressValidationRulesLoaded with
- // success = false. Thus, we can handle illegitimate |region_code|'s as well.
- std::string region_code =
- base::UTF16ToUTF8(profile->GetRawInfo(ADDRESS_HOME_COUNTRY));
- if (address_validator_.AreRulesLoadedForRegion(region_code)) {
- request->OnRulesLoaded();
- } else {
- // Setup the variables to start validation when the rules are loaded.
- pending_requests_[region_code].push_back(std::move(request));
-
- // Start loading the rules for the region. If the rules were already in the
- // process of being loaded, this call will do nothing.
- LoadRulesForRegion(region_code);
- }
-}
-
-void AutofillProfileValidator::OnAddressValidationRulesLoaded(
- const std::string& region_code,
- bool success) {
- // Even if success = false, we can still validate address partially. We can
- // check for missing fields or unexpected fields. We can also validate
- // non-address fields.
-
- // Check if there is any request for that region code.
- auto it = pending_requests_.find(region_code);
- if (it != pending_requests_.end()) {
- for (auto& request : it->second) {
- request->OnRulesLoaded();
- }
- pending_requests_.erase(it);
- }
-}
-
-bool AutofillProfileValidator::AreRulesLoadedForRegion(
- const std::string& region_code) {
- return address_validator_.AreRulesLoadedForRegion(region_code);
-}
-
-void AutofillProfileValidator::LoadRulesForRegion(
- const std::string& region_code) {
- address_validator_.LoadRules(region_code);
-}
-} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_profile_validator.h b/chromium/components/autofill/core/browser/autofill_profile_validator.h
deleted file mode 100644
index 3774c6cb001..00000000000
--- a/chromium/components/autofill/core/browser/autofill_profile_validator.h
+++ /dev/null
@@ -1,104 +0,0 @@
-// Copyright 2017 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.
-
-#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_PROFILE_VALIDATOR_H_
-#define COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_PROFILE_VALIDATOR_H_
-
-#include <stddef.h>
-
-#include <map>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/cancelable_callback.h"
-#include "base/memory/raw_ptr.h"
-#include "components/autofill/core/browser/data_model/autofill_profile.h"
-#include "third_party/libaddressinput/chromium/chrome_address_validator.h"
-#include "third_party/libaddressinput/src/cpp/include/libaddressinput/source.h"
-#include "third_party/libaddressinput/src/cpp/include/libaddressinput/storage.h"
-
-namespace autofill {
-
-using AutofillProfileValidatorCallback =
- base::OnceCallback<void(const AutofillProfile*)>;
-
-// AutofillProfileValidator Loads Rules from the server and validates an
-// autofill profile. For a given autofill profile, it will set the ValidityState
-// of several fields in the profile such as country, administrative area, etc.
-// See implementation for more details.
-class AutofillProfileValidator : public autofill::LoadRulesListener {
- public:
- // Takes ownership of |source| and |storage|.
- AutofillProfileValidator(
- std::unique_ptr<::i18n::addressinput::Source> source,
- std::unique_ptr<::i18n::addressinput::Storage> storage);
-
- AutofillProfileValidator(const AutofillProfileValidator&) = delete;
- AutofillProfileValidator& operator=(const AutofillProfileValidator&) = delete;
-
- ~AutofillProfileValidator() override;
-
- // If the rule corresponding to the |profile| is loaded, this validates the
- // profile, synchronously. If it is not loaded yet, it sets up a
- // task to validate the profile when the rule is loaded (asynchronous). If the
- // loading has not yet started, it will also start loading the rules.
- void StartProfileValidation(const AutofillProfile* profile,
- AutofillProfileValidatorCallback cb);
-
- protected:
- // Starts loading the rules for the specified |region_code|.
- virtual void LoadRulesForRegion(const std::string& region_code);
-
- // The address validator used to load rules.
- AddressValidator address_validator_;
-
- private:
- // ValidationRequest loads Rules from the server and validates various fields
- // in an autofill profile.
- class ValidationRequest {
- public:
- ValidationRequest(base::WeakPtr<const AutofillProfile> profile,
- AddressValidator* validator,
- AutofillProfileValidatorCallback on_validated);
-
- ValidationRequest(const ValidationRequest&) = delete;
- ValidationRequest& operator=(const ValidationRequest&) = delete;
-
- ~ValidationRequest();
-
- // Validates various fields of the |profile_|, and calls |on_validated_|.
- void OnRulesLoaded();
-
- private:
- AutofillProfile profile_;
-
- // Not owned. Outlives this object.
- raw_ptr<AddressValidator> validator_;
-
- AutofillProfileValidatorCallback on_validated_;
-
- bool has_responded_ = false;
- base::CancelableOnceCallback<void()> on_timeout_;
- base::WeakPtrFactory<ValidationRequest> weak_factory_{this};
- };
-
- friend class AutofillProfileValidatorTest;
-
- // Returns whether the rules for the specified |region_code| is loaded.
- bool AreRulesLoadedForRegion(const std::string& region_code);
-
- // Implementation of the LoadRulesListener interface. Called when the address
- // rules for the |region_code| have finished loading.
- void OnAddressValidationRulesLoaded(const std::string& region_code,
- bool success) override;
-
- // A map of the region code and the pending requests for that region code.
- std::map<std::string, std::vector<std::unique_ptr<ValidationRequest>>>
- pending_requests_;
-};
-
-} // namespace autofill
-
-#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_PROFILE_VALIDATOR_H_
diff --git a/chromium/components/autofill/core/browser/autofill_regex_constants.cc b/chromium/components/autofill/core/browser/autofill_regex_constants.cc
index 8dc591511f8..cb7da829459 100644
--- a/chromium/components/autofill/core/browser/autofill_regex_constants.cc
+++ b/chromium/components/autofill/core/browser/autofill_regex_constants.cc
@@ -603,8 +603,10 @@ const char16_t kHiddenValueRe[] = u"^(\\W)\\1+$";
/////////////////////////////////////////////////////////////////////////////
// merchant_promo_code_field.cc
/////////////////////////////////////////////////////////////////////////////
+// "promo code", "promotion code", "promotional code" are all acceptable
+// keywords.
const char16_t kMerchantPromoCodeRe[] =
- u"\\bpromo.*code\\b|\\bcoupon code\\b|\\bgift code\\b";
+ u"(promo(tion|tional)?|gift|discount|coupon)[-_. ]*code";
/////////////////////////////////////////////////////////////////////////////
// votes_uploader.cc
diff --git a/chromium/components/autofill/core/browser/autofill_suggestion_generator.cc b/chromium/components/autofill/core/browser/autofill_suggestion_generator.cc
index e9594ff4dca..1bc88e27d45 100644
--- a/chromium/components/autofill/core/browser/autofill_suggestion_generator.cc
+++ b/chromium/components/autofill/core/browser/autofill_suggestion_generator.cc
@@ -113,9 +113,7 @@ AutofillSuggestionGenerator::GetSuggestionsForCreditCards(
// the suggestion represents a credit card that has activated offers.
AutofillOfferManager* offer_manager =
autofill_client_->GetAutofillOfferManager();
- if (base::FeatureList::IsEnabled(
- features::kAutofillEnableOffersInDownstream) &&
- offer_manager) {
+ if (offer_manager) {
offer_manager->UpdateSuggestionsWithOffers(
autofill_client_->GetLastCommittedURL(), suggestions);
}
@@ -209,12 +207,12 @@ Suggestion AutofillSuggestionGenerator::CreateCreditCardSuggestion(
suggestion.value = credit_card.CardIdentifierStringForAutofillDisplay(
suggestion_nickname, obfuscation_length);
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
suggestion.label = credit_card.GetInfo(
AutofillType(CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR), app_locale);
#else
suggestion.label = credit_card.DescriptiveExpiration(app_locale);
-#endif // defined(OS_ANDROID) || defined(OS_IOS)
+#endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
} else if (credit_card.number().empty()) {
DCHECK_EQ(credit_card.record_type(), CreditCard::LOCAL_CARD);
@@ -225,7 +223,7 @@ Suggestion AutofillSuggestionGenerator::CreateCreditCardSuggestion(
credit_card.GetInfo(AutofillType(CREDIT_CARD_NAME_FULL), app_locale);
}
} else {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// On Android devices, the label is formatted as
// "Nickname/Network ••••1234" when the keyboard accessory experiment
// is disabled and as "••1234" when it's enabled.
@@ -234,7 +232,7 @@ Suggestion AutofillSuggestionGenerator::CreateCreditCardSuggestion(
? credit_card.ObfuscatedLastFourDigits(obfuscation_length)
: credit_card.CardIdentifierStringForAutofillDisplay(
suggestion_nickname);
-#elif defined(OS_IOS)
+#elif BUILDFLAG(IS_IOS)
// E.g. "••••1234"".
suggestion.label = credit_card.ObfuscatedLastFourDigits();
#else
@@ -245,15 +243,13 @@ Suggestion AutofillSuggestionGenerator::CreateCreditCardSuggestion(
}
if (virtual_card_option) {
-#if defined(OS_ANDROID)
- // Set the IPH feature in order to show the IPH bubble when the virtual
- // card is presented in the keyboard accessory.
- suggestion.feature_for_iph =
- feature_engagement::kIPHKeyboardAccessoryPaymentVirtualCardFeature.name;
+#if BUILDFLAG(IS_ANDROID)
suggestion.custom_icon_url = credit_card.card_art_url();
-#endif // OS_ANDROID
+#endif // BUILDFLAG(IS_ANDROID)
suggestion.frontend_id = POPUP_ITEM_ID_VIRTUAL_CREDIT_CARD_ENTRY;
+ suggestion.feature_for_iph =
+ feature_engagement::kIPHAutofillVirtualCardSuggestionFeature.name;
gfx::Image* image = personal_data_->GetCreditCardArtImageForUrl(
card_art_url_for_virtual_card_option);
diff --git a/chromium/components/autofill/core/browser/autofill_suggestion_generator_unittest.cc b/chromium/components/autofill/core/browser/autofill_suggestion_generator_unittest.cc
index 91728abbab6..5f8adc071e4 100644
--- a/chromium/components/autofill/core/browser/autofill_suggestion_generator_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_suggestion_generator_unittest.cc
@@ -41,7 +41,6 @@ class AutofillSuggestionGeneratorTest : public testing::Test {
/*pref_service=*/autofill_client_.GetPrefs(),
/*local_state=*/autofill_client_.GetPrefs(),
/*identity_manager=*/nullptr,
- /*client_profile_validator=*/nullptr,
/*history_service=*/nullptr,
/*strike_database=*/nullptr,
/*image_fetcher=*/nullptr,
diff --git a/chromium/components/autofill/core/browser/autofill_test_utils.cc b/chromium/components/autofill/core/browser/autofill_test_utils.cc
index fe3a80f9c9e..f3f42588b94 100644
--- a/chromium/components/autofill/core/browser/autofill_test_utils.cc
+++ b/chromium/components/autofill/core/browser/autofill_test_utils.cc
@@ -16,6 +16,7 @@
#include "components/autofill/core/browser/autofill_external_delegate.h"
#include "components/autofill/core/browser/data_model/autofill_profile.h"
#include "components/autofill/core/browser/data_model/credit_card.h"
+#include "components/autofill/core/browser/data_model/credit_card_test_api.h"
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/randomized_encoder.h"
#include "components/autofill/core/browser/webdata/autofill_table.h"
@@ -61,8 +62,6 @@ namespace test {
namespace {
-const int kValidityStateBitfield = 1984;
-
std::string GetRandomCardNumber() {
const size_t length = 16;
std::string value;
@@ -74,7 +73,7 @@ std::string GetRandomCardNumber() {
} // namespace
-LocalFrameToken GetLocalFrameToken(RandomizeFrame randomize) {
+LocalFrameToken MakeLocalFrameToken(RandomizeFrame randomize) {
if (*randomize) {
return LocalFrameToken(base::UnguessableToken::Create());
} else {
@@ -93,11 +92,11 @@ FieldRendererId MakeFieldRendererId() {
}
FormGlobalId MakeFormGlobalId(RandomizeFrame randomize) {
- return {GetLocalFrameToken(randomize), MakeFormRendererId()};
+ return {MakeLocalFrameToken(randomize), MakeFormRendererId()};
}
FieldGlobalId MakeFieldGlobalId(RandomizeFrame randomize) {
- return {GetLocalFrameToken(randomize), MakeFieldRendererId()};
+ return {MakeLocalFrameToken(randomize), MakeFieldRendererId()};
}
void SetFormGroupValues(FormGroup& form_group,
@@ -154,7 +153,7 @@ void CreateTestFormField(const char* label,
const char* value,
const char* type,
FormFieldData* field) {
- field->host_frame = GetLocalFrameToken();
+ field->host_frame = MakeLocalFrameToken();
field->unique_renderer_id = MakeFieldRendererId();
field->label = ASCIIToUTF16(label);
field->name = ASCIIToUTF16(name);
@@ -217,7 +216,7 @@ void CreateTestAddressFormData(FormData* form, const char* unique_id) {
void CreateTestAddressFormData(FormData* form,
std::vector<ServerFieldTypeSet>* types,
const char* unique_id) {
- form->host_frame = GetLocalFrameToken();
+ form->host_frame = MakeLocalFrameToken();
form->unique_renderer_id = MakeFormRendererId();
form->name = u"MyForm" + ASCIIToUTF16(unique_id ? unique_id : "");
form->button_titles = {std::make_pair(
@@ -446,8 +445,6 @@ AutofillProfile GetServerProfile() {
profile.SetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY, u"Santa Clara");
profile.set_language_code("en");
- profile.SetClientValidityFromBitfieldValue(kValidityStateBitfield);
- profile.set_is_client_validity_states_updated(true);
profile.set_use_count(7);
profile.set_use_date(base::Time::FromTimeT(54321));
@@ -468,8 +465,6 @@ AutofillProfile GetServerProfile2() {
profile.SetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY, u"Santa Monica");
profile.set_language_code("en");
- profile.SetClientValidityFromBitfieldValue(kValidityStateBitfield);
- profile.set_is_client_validity_states_updated(true);
profile.set_use_count(14);
profile.set_use_date(base::Time::FromTimeT(98765));
@@ -528,6 +523,24 @@ CreditCard GetMaskedServerCard() {
return credit_card;
}
+CreditCard GetMaskedServerCardWithLegacyId() {
+ CreditCard credit_card(CreditCard::MASKED_SERVER_CARD, "a123");
+ test::SetCreditCardInfo(&credit_card, "Bonnie Parker",
+ "2109" /* Mastercard */, NextMonth().c_str(),
+ NextYear().c_str(), "1");
+ credit_card.SetNetworkForMaskedCard(kMasterCard);
+ return credit_card;
+}
+
+CreditCard GetMaskedServerCardWithNonLegacyId() {
+ CreditCard credit_card(CreditCard::MASKED_SERVER_CARD, 1);
+ test::SetCreditCardInfo(&credit_card, "Bonnie Parker",
+ "2109" /* Mastercard */, NextMonth().c_str(),
+ NextYear().c_str(), "1");
+ credit_card.SetNetworkForMaskedCard(kMasterCard);
+ return credit_card;
+}
+
CreditCard GetMaskedServerCardAmex() {
CreditCard credit_card(CreditCard::MASKED_SERVER_CARD, "b456");
test::SetCreditCardInfo(&credit_card, "Justin Thyme", "8431" /* Amex */,
@@ -562,6 +575,16 @@ CreditCard GetFullServerCard() {
return credit_card;
}
+CreditCard GetVirtualCard() {
+ CreditCard credit_card;
+ test::SetCreditCardInfo(&credit_card, "Lorem Ipsum",
+ "5555555555554444", // Mastercard
+ "10", test::NextYear().c_str(), "1");
+ credit_card.set_record_type(CreditCard::RecordType::VIRTUAL_CARD);
+ CreditCardTestApi(&credit_card).set_network_for_virtual_card(kMasterCard);
+ return credit_card;
+}
+
CreditCard GetRandomCreditCard(CreditCard::RecordType record_type) {
static const char* const kNetworks[] = {
kAmericanExpressCard,
diff --git a/chromium/components/autofill/core/browser/autofill_test_utils.h b/chromium/components/autofill/core/browser/autofill_test_utils.h
index 6af219a2b25..9f000123c99 100644
--- a/chromium/components/autofill/core/browser/autofill_test_utils.h
+++ b/chromium/components/autofill/core/browser/autofill_test_utils.h
@@ -70,9 +70,9 @@ using FormGroupValues = std::vector<FormGroupValue>;
using RandomizeFrame = base::StrongAlias<struct RandomizeFrameTag, bool>;
-// Creates non-empty LocalFrameToken. If `randomize` is true, the
-// LocalFrameToken is generated randomly, otherwise it is stable.
-LocalFrameToken GetLocalFrameToken(
+// Creates non-empty LocalFrameToken. If `randomize` is false, the
+// LocalFrameToken is stable across multiple calls.
+LocalFrameToken MakeLocalFrameToken(
RandomizeFrame randomize = RandomizeFrame(false));
// Creates new, pairwise distinct FormRendererIds.
@@ -82,7 +82,8 @@ FormRendererId MakeFormRendererId();
FieldRendererId MakeFieldRendererId();
// Creates new, pairwise distinct FormGlobalIds. If `randomize` is true, the
-// LocalFrameToken is generated randomly, otherwise it is stable.
+// LocalFrameToken is generated randomly, otherwise it is stable across multiple
+// calls.
FormGlobalId MakeFormGlobalId(
RandomizeFrame randomize_frame = RandomizeFrame(false));
@@ -216,6 +217,8 @@ CreditCard GetIncompleteCreditCard();
// Returns a masked server card full of dummy info.
CreditCard GetMaskedServerCard();
+CreditCard GetMaskedServerCardWithNonLegacyId();
+CreditCard GetMaskedServerCardWithLegacyId();
CreditCard GetMaskedServerCardAmex();
CreditCard GetMaskedServerCardWithNickname();
CreditCard GetMaskedServerCardWithInvalidNickname();
@@ -223,6 +226,9 @@ CreditCard GetMaskedServerCardWithInvalidNickname();
// Returns a full server card full of dummy info.
CreditCard GetFullServerCard();
+// Returns a virtual card full of dummy info.
+CreditCard GetVirtualCard();
+
// Returns a randomly generated credit card of |record_type|. Note that the
// card is not guaranteed to be valid/sane from a card validation standpoint.
CreditCard GetRandomCreditCard(CreditCard::RecordType record_Type);
diff --git a/chromium/components/autofill/core/browser/browser_autofill_manager.cc b/chromium/components/autofill/core/browser/browser_autofill_manager.cc
index a1b9eeff7f9..cde8c2e3b36 100644
--- a/chromium/components/autofill/core/browser/browser_autofill_manager.cc
+++ b/chromium/components/autofill/core/browser/browser_autofill_manager.cc
@@ -27,6 +27,7 @@
#include "base/feature_list.h"
#include "base/files/file_util.h"
#include "base/guid.h"
+#include "base/hash/hash.h"
#include "base/i18n/rtl.h"
#include "base/memory/weak_ptr.h"
#include "base/metrics/histogram_functions.h"
@@ -100,7 +101,7 @@
#include "ui/gfx/image/image.h"
#include "url/gurl.h"
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
#include "components/autofill/core/browser/keyboard_accessory_metrics_logger.h"
#endif
@@ -309,7 +310,7 @@ bool ContainsAutofillableValue(const autofill::FormStructure& form) {
});
}
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
// Retrieves all valid credit card candidates for virtual card selection. A
// valid candidate must have exactly one cloud token.
std::vector<CreditCard*> GetVirtualCardCandidates(
@@ -603,7 +604,7 @@ void BrowserAutofillManager::RefetchCardsAndUpdatePopup(
/*autoselect_first_suggestion=*/false, should_display_gpay_logo);
}
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
void BrowserAutofillManager::FetchVirtualCardCandidates() {
const std::vector<CreditCard*>& candidates =
GetVirtualCardCandidates(personal_data_);
@@ -629,6 +630,10 @@ void BrowserAutofillManager::OnVirtualCardCandidateSelected(
bool BrowserAutofillManager::ShouldParseForms(
const std::vector<FormData>& forms) {
bool autofill_enabled = IsAutofillEnabled();
+ // If autofill is disabled but the password manager is enabled, we still
+ // need to parse the forms and query the server as the password manager
+ // depends on server classifications.
+ bool password_manager_enabled = client()->IsPasswordManagerEnabled();
sync_state_ = personal_data_ ? personal_data_->GetSyncSigninState()
: AutofillSyncSigninState::kNumSyncStates;
if (!has_logged_autofill_enabled_) {
@@ -641,7 +646,14 @@ bool BrowserAutofillManager::ShouldParseForms(
has_logged_autofill_enabled_ = true;
}
- return autofill_enabled;
+ // TODO(crbug.com/1293341): Enable the experiment by default.
+ // The placement of the IsEnabled() call is chosen very intentionally.
+ // Only users with disabled autofill will go into the control or experiment
+ // group.
+ return autofill_enabled ||
+ (base::FeatureList::IsEnabled(
+ features::kAutofillFixServerQueriesIfPasswordManagerIsEnabled) &&
+ password_manager_enabled);
}
void BrowserAutofillManager::OnFormSubmittedImpl(const FormData& form,
@@ -688,14 +700,26 @@ void BrowserAutofillManager::OnFormSubmittedImpl(const FormData& form,
}
}
- // However, if Autofill has recognized a field as CVC, that shouldn't be
- // saved.
FormData form_for_autocomplete = submitted_form->ToFormData();
for (size_t i = 0; i < submitted_form->field_count(); ++i) {
if (submitted_form->field(i)->Type().GetStorableType() ==
CREDIT_CARD_VERIFICATION_CODE) {
+ // However, if Autofill has recognized a field as CVC, that shouldn't be
+ // saved.
form_for_autocomplete.fields[i].should_autocomplete = false;
}
+
+ if (submitted_form->field(i)
+ ->value_not_autofilled_over_existing_value_hash()) {
+ // Compare and record if the currently filled value is same as the
+ // non-empty value that was to be autofilled in the field.
+ AutofillMetrics::
+ LogIsValueNotAutofilledOverExistingValueSameAsSubmittedValue(
+ *submitted_form->field(i)
+ ->value_not_autofilled_over_existing_value_hash() ==
+ base::FastHash(
+ base::UTF16ToUTF8(submitted_form->field(i)->value)));
+ }
}
single_field_form_fill_router_->OnWillSubmitForm(
form_for_autocomplete, client()->IsAutocompleteEnabled());
@@ -752,7 +776,6 @@ bool BrowserAutofillManager::MaybeStartVoteUploadProcess(
// Only upload server statistics and UMA metrics if at least some local data
// is available to use as a baseline.
std::vector<AutofillProfile*> profiles = personal_data_->GetProfiles();
- personal_data_->UpdateProfilesServerValidityMapsIfNeeded(profiles);
if (observed_submission && form_structure->IsAutofillable()) {
AutofillMetrics::LogNumberOfProfilesAtAutofillableFormSubmission(
personal_data_->GetProfiles().size());
@@ -1063,7 +1086,8 @@ void BrowserAutofillManager::FillOrPreviewCreditCardForm(
}
FillOrPreviewDataModelForm(action, query_id, form, field, &credit_card_,
- /*cvc=*/nullptr, form_structure, autofill_field);
+ /*optional_cvc=*/nullptr, form_structure,
+ autofill_field);
}
void BrowserAutofillManager::FillOrPreviewProfileForm(
@@ -1131,7 +1155,8 @@ void BrowserAutofillManager::FillProfileForm(
/*query_id=*/kNoQueryId, form, field, profile);
}
-void BrowserAutofillManager::FillVirtualCardInformation(
+void BrowserAutofillManager::FillOrPreviewVirtualCardInformation(
+ mojom::RendererFormDataAction action,
const std::string& guid,
int query_id,
const FormData& form,
@@ -1145,8 +1170,7 @@ void BrowserAutofillManager::FillVirtualCardInformation(
if (credit_card) {
CreditCard copy = *credit_card;
copy.set_record_type(CreditCard::VIRTUAL_CARD);
- FillOrPreviewCreditCardForm(mojom::RendererFormDataAction::kFill, query_id,
- form, field, &copy);
+ FillOrPreviewCreditCardForm(action, query_id, form, field, &copy);
}
}
@@ -1715,14 +1739,6 @@ void BrowserAutofillManager::FillOrPreviewDataModelForm(
continue;
}
- // Do not override prefilled field values.
- if (base::FeatureList::IsEnabled(
- features::kAutofillPreventOverridingPrefilledValues) &&
- !form_structure->field(i)->value.empty()) {
- buffer << Tr{} << field_number << "Skipped: value is prefilled";
- continue;
- }
-
if (form_structure->field(i)->only_fill_when_focused() &&
!form_structure->field(i)->SameFieldAs(field)) {
buffer << Tr{} << field_number << "Skipped: only fill when focused";
@@ -1750,6 +1766,39 @@ void BrowserAutofillManager::FillOrPreviewDataModelForm(
}
}
+ // Do not override prefilled text/input field values. Selection fields are
+ // excluded from this check because they may have a non-empty value.
+ // If the initiating element had a prefilled value but the autofill
+ // suggestion is present that includes the currently filled value in the
+ // field as a substring, Autofill would override the filled value in that
+ // case.
+ if (base::FeatureList::IsEnabled(
+ features::kAutofillPreventOverridingPrefilledValues)) {
+ if (form.fields[i].form_control_type != "select-one" &&
+ !form.fields[i].value.empty() &&
+ !FormFieldData::DeepEqual(form.fields[i], field)) {
+ buffer << Tr{} << field_number << "Skipped: value is prefilled";
+ std::string unused_failure_to_fill;
+ const std::u16string kEmptyCvc{};
+ const std::u16string fill_value = field_filler_.GetValueForFilling(
+ *cached_field, profile_or_credit_card, &result.fields[i],
+ optional_cvc ? *optional_cvc : kEmptyCvc, action,
+ &unused_failure_to_fill);
+ if (action == mojom::RendererFormDataAction::kFill &&
+ !fill_value.empty() && fill_value != form.fields[i].value) {
+ // Save the value that was supposed to be autofilled for this field.
+ form_structure->field(i)
+ ->set_value_not_autofilled_over_existing_value_hash(
+ base::FastHash(base::UTF16ToUTF8(fill_value)));
+ }
+ continue;
+ }
+
+ // Clear out the value in case the autofill happens for the field.
+ form_structure->field(i)
+ ->set_value_not_autofilled_over_existing_value_hash(absl::nullopt);
+ }
+
// Do not fill fields that have been edited by the user, except if the field
// is empty and its initial value (= cached value) was empty as well. A
// similar check is done in ForEachMatchingFormFieldCommon(), which
@@ -1846,7 +1895,7 @@ void BrowserAutofillManager::FillOrPreviewDataModelForm(
buffer << Tr{} << field_number
<< base::StringPrintf(
"Fillable - has value: %d->%d; autofilled: %d->%d. %s",
- has_value_before, is_autofilled_before, has_value_after,
+ has_value_before, has_value_after, is_autofilled_before,
is_autofilled_after, failure_to_fill.c_str());
if (!cached_field->IsVisible() && result.fields[i].is_autofilled)
@@ -2079,7 +2128,7 @@ void BrowserAutofillManager::OnAfterProcessParsedForms(
AutofillMetrics::FORMS_LOADED, form_types,
client()->GetSecurityLevelForUmaHistograms(),
/*profile_form_bitmask=*/0);
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
// Log this from same location as AutofillMetrics::FORMS_LOADED to ensure
// that KeyboardAccessoryButtonsIOS and UserHappiness UMA metrics will be
// directly comparable.
@@ -2181,10 +2230,7 @@ void BrowserAutofillManager::DeterminePossibleFieldTypesForUpload(
base::TrimWhitespace(field->value, base::TRIM_ALL, &value);
for (const AutofillProfile& profile : profiles) {
- ServerFieldTypeValidityStateMap matching_types_validities;
- profile.GetMatchingTypesAndValidities(value, app_locale, &matching_types,
- &matching_types_validities);
- field->add_possible_types_validities(matching_types_validities);
+ profile.GetMatchingTypes(value, app_locale, &matching_types);
}
// TODO(crbug/880531) set possible_types_validities for credit card too.
@@ -2536,15 +2582,17 @@ void BrowserAutofillManager::TriggerRefill(const FormData& form) {
.second,
form_structure, autofill_field,
/*is_refill=*/true);
- }
- if (absl::holds_alternative<AutofillProfile>(
- filling_context->profile_or_credit_card_with_cvc)) {
+ } else if (absl::holds_alternative<AutofillProfile>(
+ filling_context->profile_or_credit_card_with_cvc)) {
FillOrPreviewDataModelForm(
mojom::RendererFormDataAction::kFill,
/*query_id=*/-1, form, field,
&absl::get<AutofillProfile>(
filling_context->profile_or_credit_card_with_cvc),
- /*cvc=*/nullptr, form_structure, autofill_field, /*is_refill=*/true);
+ /*optional_cvc=*/nullptr, form_structure, autofill_field,
+ /*is_refill=*/true);
+ } else {
+ NOTREACHED();
}
}
@@ -2663,7 +2711,7 @@ void BrowserAutofillManager::GetAvailableSuggestions(
if (suggestions->empty() || !context->is_filling_credit_card)
return;
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
// This section adds the "Use a virtual card number" option in the autofill
// dropdown menu, if applicable.
if (ShouldShowVirtualCardOption(context->form_structure)) {
@@ -2688,7 +2736,7 @@ void BrowserAutofillManager::GetAvailableSuggestions(
}
}
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
// TODO(crbug.com/1020740): Add metrics logging.
bool BrowserAutofillManager::ShouldShowVirtualCardOption(
FormStructure* form_structure) {
diff --git a/chromium/components/autofill/core/browser/browser_autofill_manager.h b/chromium/components/autofill/core/browser/browser_autofill_manager.h
index 53b2df6b1da..2eb1701f61f 100644
--- a/chromium/components/autofill/core/browser/browser_autofill_manager.h
+++ b/chromium/components/autofill/core/browser/browser_autofill_manager.h
@@ -12,7 +12,6 @@
#include <vector>
#include "base/callback_forward.h"
-#include "base/compiler_specific.h"
#include "base/containers/circular_deque.h"
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
@@ -115,7 +114,7 @@ class BrowserAutofillManager : public AutofillManager,
const FormData& form,
const FormFieldData& field_data);
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
// Returns the list of credit cards that have associated cloud token data.
virtual void FetchVirtualCardCandidates();
@@ -154,10 +153,12 @@ class BrowserAutofillManager : public AutofillManager,
// Fetches the related virtual card information given the related actual card
// |guid| and fills the information into the form.
- virtual void FillVirtualCardInformation(const std::string& guid,
- int query_id,
- const FormData& form,
- const FormFieldData& field);
+ virtual void FillOrPreviewVirtualCardInformation(
+ mojom::RendererFormDataAction action,
+ const std::string& guid,
+ int query_id,
+ const FormData& form,
+ const FormFieldData& field);
// Returns true if the value/identifier is deletable. Fills out
// |title| and |body| with relevant user-facing text.
@@ -540,13 +541,12 @@ class BrowserAutofillManager : public AutofillManager,
// Returns the field corresponding to |form| and |field| that can be
// autofilled. Returns NULL if the field cannot be autofilled.
- AutofillField* GetAutofillField(const FormData& form,
- const FormFieldData& field)
- WARN_UNUSED_RESULT;
+ [[nodiscard]] AutofillField* GetAutofillField(const FormData& form,
+ const FormFieldData& field);
// Returns true if any form in the field corresponds to an address
// |FieldTypeGroup|.
- bool FormHasAddressField(const FormData& form) WARN_UNUSED_RESULT;
+ [[nodiscard]] bool FormHasAddressField(const FormData& form);
// Returns Suggestions corresponding to both the |autofill_field| type and
// stored profiles whose values match the contents of |field|. |form| stores
@@ -662,7 +662,7 @@ class BrowserAutofillManager : public AutofillManager,
const std::vector<AutofillProfile>& profiles,
FormStructure* form_structure);
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
// Whether to show the option to use virtual card in the autofill popup.
bool ShouldShowVirtualCardOption(FormStructure* form_structure);
#endif
diff --git a/chromium/components/autofill/core/browser/browser_autofill_manager_unittest.cc b/chromium/components/autofill/core/browser/browser_autofill_manager_unittest.cc
index d8d6787106f..df10e182b41 100644
--- a/chromium/components/autofill/core/browser/browser_autofill_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/browser_autofill_manager_unittest.cc
@@ -17,6 +17,7 @@
#include "base/command_line.h"
#include "base/cxx17_backports.h"
#include "base/feature_list.h"
+#include "base/hash/hash.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/metrics/field_trial.h"
@@ -118,6 +119,7 @@ class MockAutofillClient : public TestAutofillClient {
MockAutofillClient() {
ON_CALL(*this, GetChannel())
.WillByDefault(Return(version_info::Channel::UNKNOWN));
+ ON_CALL(*this, IsPasswordManagerEnabled()).WillByDefault(Return(true));
}
MockAutofillClient(const MockAutofillClient&) = delete;
MockAutofillClient& operator=(const MockAutofillClient&) = delete;
@@ -125,7 +127,7 @@ class MockAutofillClient : public TestAutofillClient {
MOCK_METHOD(bool, ShouldShowSigninPromo, (), (override));
MOCK_METHOD(version_info::Channel, GetChannel, (), (const override));
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
MOCK_METHOD(void,
ConfirmSaveUpiIdLocally,
(const std::string& upi_id,
@@ -136,6 +138,7 @@ class MockAutofillClient : public TestAutofillClient {
GetProfileType,
(),
(const override));
+ MOCK_METHOD(bool, IsPasswordManagerEnabled, (), (override));
};
class MockAutofillDownloadManager : public TestAutofillDownloadManager {
@@ -346,12 +349,12 @@ class BrowserAutofillManagerTest : public testing::Test {
void SetUp() override {
autofill_client_.SetPrefs(test::PrefServiceForTesting());
+ personal_data_.set_auto_accept_address_imports_for_testing(true);
personal_data_.Init(/*profile_database=*/database_,
/*account_database=*/nullptr,
/*pref_service=*/autofill_client_.GetPrefs(),
/*local_state=*/autofill_client_.GetPrefs(),
/*identity_manager=*/nullptr,
- /*client_profile_validator=*/nullptr,
/*history_service=*/nullptr,
/*strike_database=*/nullptr,
/*image_fetcher=*/nullptr,
@@ -533,6 +536,22 @@ class BrowserAutofillManagerTest : public testing::Test {
FillAutofillFormData(input_query_id, input_form, input_field, unique_id);
}
+ void PreviewVirtualCardDataAndSaveResults(
+ mojom::RendererFormDataAction action,
+ const std::string& guid,
+ int input_query_id,
+ const FormData& input_form,
+ const FormFieldData& input_field,
+ int* response_query_id,
+ FormData* response_data) {
+ EXPECT_CALL(*autofill_driver_, FillOrPreviewForm(_, _, _, _, _))
+ .WillOnce((DoAll(testing::SaveArg<0>(response_query_id),
+ testing::SaveArg<2>(response_data),
+ testing::ReturnArg<4>())));
+ browser_autofill_manager_->FillOrPreviewVirtualCardInformation(
+ action, guid, input_query_id, input_form, input_field);
+ }
+
int MakeFrontendID(const std::string& cc_sid,
const std::string& profile_sid) const {
return browser_autofill_manager_->MakeFrontendID(cc_sid, profile_sid);
@@ -820,11 +839,11 @@ class SuggestionMatchingTest
InitializeFeatures();
}
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
void InitializeFeatures();
#else
void InitializeFeatures();
-#endif // defined(OS_ANDROID) || defined(OS_IOS)
+#endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
std::string MakeLabel(const std::vector<std::string>& parts);
std::string MakeMobileLabel(const std::vector<std::string>& parts);
@@ -834,7 +853,7 @@ class SuggestionMatchingTest
base::test::ScopedFeatureList features_;
};
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
void SuggestionMatchingTest::InitializeFeatures() {
if (std::get<0>(GetParam())) {
std::string variant = std::get<1>(GetParam());
@@ -867,7 +886,7 @@ void SuggestionMatchingTest::InitializeFeatures() {
features::kAutofillUseImprovedLabelDisambiguation,
std::get<0>(GetParam()));
}
-#endif // defined(OS_ANDROID) || defined(OS_IOS)
+#endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
std::string SuggestionMatchingTest::MakeLabel(
const std::vector<std::string>& parts) {
@@ -894,7 +913,7 @@ class CreditCardSuggestionTest : public BrowserAutofillManagerTest,
}
int ObfuscationLength() {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
return is_keyboard_accessory_enabled_ ? 2 : 4;
#else
return 4;
@@ -944,7 +963,7 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
// Different form structure.
FormData form2;
- form2.host_frame = test::GetLocalFrameToken();
+ form2.host_frame = test::MakeLocalFrameToken();
form2.unique_renderer_id = test::MakeFormRendererId();
form2.name = u"MyForm";
form2.url = GURL("https://myform.com/form.html");
@@ -977,7 +996,7 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
FormData form2;
FormFieldData field;
test::CreateTestFormField("Querty", "qwerty", "", "text", &field);
- form2.host_frame = test::GetLocalFrameToken();
+ form2.host_frame = test::MakeLocalFrameToken();
form2.unique_renderer_id = test::MakeFormRendererId();
form2.name = u"NonQueryable";
form2.url = form1.url;
@@ -1005,7 +1024,7 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
FormData form2;
FormFieldData field;
test::CreateTestFormField("Querty", "qwerty", "", "text", &field);
- form2.host_frame = test::GetLocalFrameToken();
+ form2.host_frame = test::MakeLocalFrameToken();
form2.unique_renderer_id = test::MakeFormRendererId();
form2.name = u"NonQueryable";
form2.url = form1.url;
@@ -1460,7 +1479,7 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
FormFieldData field = form.fields[1];
GetAutofillSuggestions(form, field);
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
const std::string visa_label = std::string("04/99");
const std::string master_card_label = std::string("10/98");
#else
@@ -1495,7 +1514,7 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
field.value = u" ";
GetAutofillSuggestions(form, field);
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
const std::string visa_label = std::string("04/99");
const std::string master_card_label = std::string("10/98");
#else
@@ -1530,7 +1549,7 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
field.value = u"____-____-____-____";
GetAutofillSuggestions(form, field);
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
const std::string visa_label = std::string("04/99");
const std::string master_card_label = std::string("10/98");
#else
@@ -1565,7 +1584,7 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
field.value = std::u16string({0x200E, 0x200F});
GetAutofillSuggestions(form, field);
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
const std::string visa_label = std::string("04/99");
const std::string master_card_label = std::string("10/98");
#else
@@ -1609,7 +1628,7 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
field.value = u"5255-66__-____-____";
GetAutofillSuggestions(form, field);
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
const std::string master_card_label = std::string("08/17");
#else
const std::string master_card_label = std::string("Expires on 08/17");
@@ -1638,7 +1657,7 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
test::CreateTestFormField("Card Number", "cardnumber", "78", "text", &field);
GetAutofillSuggestions(form, field);
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
const std::string visa_label = std::string("04/99");
#else
const std::string visa_label = std::string("Expires on 04/99");
@@ -1680,7 +1699,7 @@ TEST_P(CreditCardSuggestionTest, GetCreditCardSuggestions_CCNumber) {
kArbitraryNickname + " " +
test::ObfuscatedCardDigitsAsUTF8("8765", obfuscation_length);
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
const std::string visa_label = std::string("04/99");
const std::string master_card_label = std::string("10/98");
#else
@@ -1717,7 +1736,7 @@ TEST_P(CreditCardSuggestionTest, GetCreditCardSuggestions_NonCCNumber) {
const std::string obfuscated_last_four_digits2 =
test::ObfuscatedCardDigitsAsUTF8("8765", ObfuscationLength());
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// For Android, when keyboard accessary is enabled, always show obfuscated
// last four. When keyboard accessary is not enabled (drop-down suggestion):
// 1) if nickname feature is enabled and nickname is available, show nickname
@@ -1733,7 +1752,7 @@ TEST_P(CreditCardSuggestionTest, GetCreditCardSuggestions_NonCCNumber) {
? obfuscated_last_four_digits2
: kArbitraryNickname + " " + obfuscated_last_four_digits2;
-#elif defined(OS_IOS)
+#elif BUILDFLAG(IS_IOS)
const std::string visa_label = obfuscated_last_four_digits1;
const std::string master_card_label = obfuscated_last_four_digits2;
@@ -1782,7 +1801,7 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
const FormFieldData& credit_card_number_field = form.fields[1];
const std::string google_issued_card_value = base::JoinString(
{"Plex Mastercard ", test::ObfuscatedCardDigitsAsUTF8("4444")}, "");
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
const std::string google_issued_card_label = std::string("10/98");
#else
const std::string google_issued_card_label = std::string("Expires on 10/98");
@@ -1820,10 +1839,10 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
FormsSeen(forms);
// Set the field being edited to the cardholder name field.
const FormFieldData& cardholder_name_field = form.fields[0];
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
const std::string google_issued_card_label = base::JoinString(
{"Plex Mastercard ", test::ObfuscatedCardDigitsAsUTF8("4444")}, "");
-#elif defined(OS_IOS)
+#elif BUILDFLAG(IS_IOS)
const std::string google_issued_card_label =
test::ObfuscatedCardDigitsAsUTF8("4444");
#else
@@ -1952,7 +1971,7 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
FormFieldData field = form.fields[1];
GetAutofillSuggestions(form, field);
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
const std::string visa_label = std::string("04/99");
const std::string master_card_label = std::string("10/98");
#else
@@ -1988,7 +2007,7 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
FormFieldData field = form.fields[1];
GetAutofillSuggestions(form, field);
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
const std::string visa_label = std::string("04/99");
const std::string master_card_label = std::string("10/98");
#else
@@ -2032,7 +2051,7 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
FormFieldData field = form.fields[1];
GetAutofillSuggestions(form, field);
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
const std::string visa_label = std::string("04/99");
const std::string master_card_label1 = std::string("10/98");
const std::string master_card_label2 = std::string("05/99");
@@ -2134,7 +2153,7 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
FormFieldData field = form.fields[1];
GetAutofillSuggestions(form, field);
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
const std::string visa_label = std::string("01/11");
const std::string master_card_label = std::string("04/55");
const std::string amex_card_label = std::string("04/10");
@@ -2218,12 +2237,12 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
FormFieldData field = form.fields[0];
GetAutofillSuggestions(form, field);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
const std::string mastercard_label =
std::string("Mastercard ") + test::ObfuscatedCardDigitsAsUTF8("5100");
const std::string visa_label =
std::string("Visa ") + test::ObfuscatedCardDigitsAsUTF8("3456");
-#elif defined(OS_IOS)
+#elif BUILDFLAG(IS_IOS)
const std::string mastercard_label =
test::ObfuscatedCardDigitsAsUTF8("5100");
const std::string visa_label = test::ObfuscatedCardDigitsAsUTF8("3456");
@@ -2250,10 +2269,10 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
field.value = u"B";
GetAutofillSuggestions(form, field);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
const std::string mastercard_label =
std::string("Mastercard ") + test::ObfuscatedCardDigitsAsUTF8("5100");
-#elif defined(OS_IOS)
+#elif BUILDFLAG(IS_IOS)
const std::string mastercard_label =
test::ObfuscatedCardDigitsAsUTF8("5100");
#else
@@ -2274,10 +2293,10 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
field.value = u"Cl";
GetAutofillSuggestions(form, field);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
const std::string visa_label =
std::string("Visa ") + test::ObfuscatedCardDigitsAsUTF8("3456");
-#elif defined(OS_IOS)
+#elif BUILDFLAG(IS_IOS)
const std::string visa_label = test::ObfuscatedCardDigitsAsUTF8("3456");
#else
const std::string visa_label = std::string("Visa ") +
@@ -2297,10 +2316,10 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
field.value = u"Jo";
GetAutofillSuggestions(form, field);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
const std::string amex_label =
std::string("Amex ") + test::ObfuscatedCardDigitsAsUTF8("0005");
-#elif defined(OS_IOS)
+#elif BUILDFLAG(IS_IOS)
const std::string amex_label = test::ObfuscatedCardDigitsAsUTF8("0005");
#else
const std::string amex_label = std::string("Amex ") +
@@ -2322,7 +2341,7 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
field.value = u"4234";
GetAutofillSuggestions(form, field);
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
const std::string visa_label1 = std::string("04/10");
const std::string visa_label2 = std::string("01/10");
#else
@@ -2382,7 +2401,7 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
// Sublabel is expiration date when filling card number. The second card
// doesn't have a number so it should not be included in the suggestions.
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
const std::string amex_card_exp_label = std::string("04/99");
#else
const std::string amex_card_exp_label = std::string("Expires on 04/99");
@@ -2399,10 +2418,10 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
field = form.fields[0];
GetAutofillSuggestions(form, field);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
const std::string amex_card_label =
std::string("Amex ") + test::ObfuscatedCardDigitsAsUTF8("0005");
-#elif defined(OS_IOS)
+#elif BUILDFLAG(IS_IOS)
const std::string amex_card_label = test::ObfuscatedCardDigitsAsUTF8("0005");
#else
const std::string amex_card_label = std::string("Amex ") +
@@ -2464,7 +2483,7 @@ TEST_P(SuggestionMatchingTest, GetAddressAndCreditCardSuggestions) {
test::CreateTestFormField("Card Number", "cardnumber", "", "text", &field);
GetAutofillSuggestions(kPageID2, form, field);
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
const std::string visa_label = std::string("04/99");
const std::string master_card_label = std::string("10/98");
#else
@@ -3005,6 +3024,60 @@ TEST_F(BrowserAutofillManagerTest, DetermineStateFieldTypeForUpload) {
EXPECT_TRUE(form_structure.field(1)->state_is_a_matching_type());
}
+// Test fixture which enables
+// features::kAutofillFixServerQueriesIfPasswordManagerIsEnabled.
+// TODO(crbug.com/1293341) Once enabled by default, delete this test
+// fixture and use BrowserAutofillManagerTest in the test below.
+class BrowserAutofillManagerTestWithFixForQueries
+ : public BrowserAutofillManagerTest {
+ public:
+ BrowserAutofillManagerTestWithFixForQueries() {
+ features_.InitAndEnableFeature(
+ features::kAutofillFixServerQueriesIfPasswordManagerIsEnabled);
+ }
+ ~BrowserAutofillManagerTestWithFixForQueries() override = default;
+
+ private:
+ base::test::ScopedFeatureList features_;
+};
+
+// Ensures that if autofill is disabled but the password manager is enabled,
+// Autofill still performs a lookup to the server.
+TEST_F(BrowserAutofillManagerTestWithFixForQueries,
+ OnFormsSeen_AutofillDisabledPasswordManagerEnabled) {
+ // Set up our form data.
+ FormData form;
+ test::CreateTestAddressFormData(&form);
+ std::vector<FormData> forms(1, form);
+
+ // Disable autofill and the password manager.
+ browser_autofill_manager_->SetAutofillCreditCardEnabled(false);
+ browser_autofill_manager_->SetAutofillProfileEnabled(false);
+ ON_CALL(autofill_client_, IsPasswordManagerEnabled())
+ .WillByDefault(Return(false));
+
+ // As neither autofill nor password manager are enabled, the form should
+ // not be parsed.
+ {
+ base::HistogramTester histogram_tester;
+ FormsSeen(forms);
+ EXPECT_EQ(0, histogram_tester.GetBucketCount("Autofill.UserHappiness",
+ 0 /* FORMS_LOADED */));
+ }
+
+ // Now enable the password manager.
+ ON_CALL(autofill_client_, IsPasswordManagerEnabled())
+ .WillByDefault(Return(true));
+ // If the password manager is enabled, that's enough to parse the form.
+ {
+ base::HistogramTester histogram_tester;
+ FormsSeen(forms);
+ histogram_tester.ExpectUniqueSample("Autofill.UserHappiness",
+ 0 /* FORMS_LOADED */, 1);
+ download_manager_->VerifyLastQueriedForms(forms);
+ }
+}
+
// Test that we return normal Autofill suggestions when trying to autofill
// already filled forms.
TEST_P(SuggestionMatchingTest, GetFieldSuggestionsWhenFormIsAutofilled) {
@@ -4238,7 +4311,7 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
FillCreditCardForm_VirtualCard) {
personal_data_.ClearCreditCards();
CreditCard masked_server_card;
- test::SetCreditCardInfo(&masked_server_card, "Lorem Ispum",
+ test::SetCreditCardInfo(&masked_server_card, "Lorem Ipsum",
"5555555555554444", // Mastercard
"10", test::NextYear().c_str(), "1");
masked_server_card.set_guid("00000000-0000-0000-0000-000000000007");
@@ -4252,8 +4325,9 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
std::vector<FormData> forms(1, form);
FormsSeen(forms);
- browser_autofill_manager_->FillVirtualCardInformation(
- masked_server_card.guid(), kDefaultPageID, form, form.fields[1]);
+ browser_autofill_manager_->FillOrPreviewVirtualCardInformation(
+ mojom::RendererFormDataAction::kFill, masked_server_card.guid(),
+ kDefaultPageID, form, form.fields[1]);
CardUnmaskDelegate::UserProvidedUnmaskDetails details;
details.cvc = u"123";
@@ -4268,6 +4342,42 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
GURL("https://example.test/"));
}
+TEST_P(BrowserAutofillManagerStructuredProfileTest,
+ PreviewCreditCardForm_VirtualCard) {
+ personal_data_.ClearCreditCards();
+ CreditCard virtual_card = test::GetVirtualCard();
+ personal_data_.AddServerCreditCard(virtual_card);
+ // Set up our form data.
+ FormData form;
+ CreateTestCreditCardFormData(&form, true, false);
+ std::vector<FormData> forms(1, form);
+ FormsSeen(forms);
+
+ int response_page_id = 0;
+ FormData response_data;
+ PreviewVirtualCardDataAndSaveResults(
+ mojom::RendererFormDataAction::kPreview, virtual_card.guid(),
+ kDefaultPageID, form, form.fields[1], &response_page_id, &response_data);
+
+ std::u16string expected_cardholder_name = u"Lorem Ipsum";
+ // Virtual card number using obfuscated dots only: Virtual card Mastercard
+ // ••••4444
+ std::u16string expected_card_number =
+ u"Virtual card Mastercard " + virtual_card.ObfuscatedLastFourDigits();
+ // Virtual card expiration month using obfuscated dots: ••
+ std::u16string expected_exp_month = CreditCard::GetMidlineEllipsisDots(2);
+ // Virtual card expiration year using obfuscated dots: ••••
+ std::u16string expected_exp_year = CreditCard::GetMidlineEllipsisDots(4);
+ // Virtual card cvc using obfuscated dots: •••
+ std::u16string expected_cvc = CreditCard::GetMidlineEllipsisDots(3);
+
+ EXPECT_EQ(response_data.fields[0].value, expected_cardholder_name);
+ EXPECT_EQ(response_data.fields[1].value, expected_card_number);
+ EXPECT_EQ(response_data.fields[2].value, expected_exp_month);
+ EXPECT_EQ(response_data.fields[3].value, expected_exp_year);
+ EXPECT_EQ(response_data.fields[4].value, expected_cvc);
+}
+
// Test that non-focusable field is ignored while inferring boundaries between
// sections, but not filled.
TEST_P(BrowserAutofillManagerStructuredProfileTest,
@@ -5898,7 +6008,7 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
OnLoadedServerPredictionsFromApi) {
// First form on the page.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"MyForm";
form.url = GURL("https://myform.com/form.html");
@@ -5924,7 +6034,7 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
// Second form on the page.
FormData form2;
- form2.host_frame = test::GetLocalFrameToken();
+ form2.host_frame = test::MakeLocalFrameToken();
form2.unique_renderer_id = test::MakeFormRendererId();
form2.name = u"MyForm2";
form2.url = GURL("https://myform.com/form.html");
@@ -6299,8 +6409,6 @@ class ProfileMatchingTypesTest
: public BrowserAutofillManagerTest,
public ::testing::WithParamInterface<
std::tuple<ProfileMatchingTypesTestCase,
- int, // AutofillDataModel::ValidityState
- bool, // AutofillDataModel::ValidationSource
bool>> { // kAutofillEnableSupportForMoreStructureInNames
protected:
void SetUp() override {
@@ -6320,7 +6428,7 @@ class ProfileMatchingTypesTest
};
void ProfileMatchingTypesTest::InitializeFeatures() {
- structured_names_and_addresses_ = std::get<2>(GetParam());
+ structured_names_and_addresses_ = std::get<1>(GetParam());
std::vector<base::Feature> features = {
features::kAutofillEnableSupportForMoreStructureInAddresses,
@@ -6443,22 +6551,15 @@ const ProfileMatchingTypesTestCase kProfileMatchingTypesTestCases[] = {
};
// Tests that DeterminePossibleFieldTypesForUpload finds accurate possible
-// types and validities.
+// types.
TEST_P(ProfileMatchingTypesTest, DeterminePossibleFieldTypesForUpload) {
// Unpack the test parameters
const auto& test_case = std::get<0>(GetParam());
- auto validity_state =
- static_cast<AutofillDataModel::ValidityState>(std::get<1>(GetParam()));
- const auto& validation_source =
- static_cast<AutofillDataModel::ValidationSource>(std::get<2>(GetParam()));
SCOPED_TRACE(base::StringPrintf(
- "Test: input_value='%s', field_type=%s, validity_state=%d, "
- "validation_source=%d "
- "structured_names=%s ",
+ "Test: input_value='%s', field_type=%s, structured_names=%s ",
test_case.input_value,
AutofillType(*test_case.field_types.begin()).ToString().c_str(),
- validity_state, validation_source,
StructuredNamesAndAddresses() ? "true" : "false"));
// Take the field types depending on the state of the structured names
@@ -6467,9 +6568,6 @@ TEST_P(ProfileMatchingTypesTest, DeterminePossibleFieldTypesForUpload) {
StructuredNamesAndAddresses() ? test_case.structured_field_types
: test_case.field_types;
- ASSERT_LE(AutofillDataModel::UNVALIDATED, validity_state);
- ASSERT_LE(validity_state, AutofillDataModel::UNSUPPORTED);
-
// Set up the test profiles.
std::vector<AutofillProfile> profiles;
profiles.resize(3);
@@ -6490,24 +6588,6 @@ TEST_P(ProfileMatchingTypesTest, DeterminePossibleFieldTypesForUpload) {
"+33 2 49 19 70 70");
profiles[2].set_guid("00000000-0000-0000-0000-000000000001");
- // Set the validity state for the matching field type.
- for (auto type : expected_possible_types) {
- if (GroupTypeOfServerFieldType(type) != FieldTypeGroup::kCreditCard) {
- for (auto& profile : profiles) {
- ASSERT_GT(test_case.field_types.size(), 0U);
- if (type == UNKNOWN_TYPE) {
- // An UNKNOWN type is always UNVALIDATED
- validity_state = AutofillDataModel::UNVALIDATED;
- } else if (profile.IsAnInvalidPhoneNumber(type)) {
- // A phone field is a compound field, and an invalid part makes
- // the phone number invalid.
- validity_state = AutofillDataModel::INVALID;
- }
- profile.SetValidityState(type, validity_state, validation_source);
- }
- }
- }
-
// Set up the test credit cards.
std::vector<CreditCard> credit_cards;
CreditCard credit_card;
@@ -6536,22 +6616,6 @@ TEST_P(ProfileMatchingTypesTest, DeterminePossibleFieldTypesForUpload) {
ServerFieldTypeSet possible_types = form_structure.field(0)->possible_types();
EXPECT_EQ(possible_types, expected_possible_types);
-
- for (auto type : expected_possible_types) {
- // We don't add validity states for credit card fields.
- if (GroupTypeOfServerFieldType(type) != FieldTypeGroup::kCreditCard) {
- ServerFieldTypeValidityStatesMap possible_types_validities =
- form_structure.field(0)->possible_types_validities();
- ASSERT_EQ(expected_possible_types.size(),
- possible_types_validities.size());
- EXPECT_NE(possible_types_validities.end(),
- possible_types_validities.find(type));
- EXPECT_EQ(possible_types_validities[type][0],
- (validation_source == AutofillDataModel::SERVER)
- ? validity_state
- : AutofillDataModel::UNVALIDATED);
- }
- }
}
// Tests that DeterminePossibleFieldTypesForUpload is called when a form is
@@ -6606,115 +6670,6 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
FormSubmitted(form);
}
-// Test that the possible field types with multiple validities are determined
-// correctly.
-TEST_P(BrowserAutofillManagerStructuredProfileTest,
- DeterminePossibleFieldTypesWithMultipleValidities) {
- // Set up the user's profiles.
- std::vector<AutofillProfile> profiles;
- {
- AutofillProfile profile;
- test::SetProfileInfo(&profile, "Elvis", "Aaron", "Presley",
- "theking@gmail.com", "RCA", "3734 Elvis Presley Blvd.",
- "", "Memphis", "Tennessee", "38116", "US",
- "(234) 567-8901");
- profile.set_guid("00000000-0000-0000-0000-000000000001");
- profile.SetValidityState(ADDRESS_HOME_STATE, AutofillDataModel::VALID,
- AutofillDataModel::SERVER);
- profiles.push_back(profile);
- }
- {
- AutofillProfile profile;
- test::SetProfileInfo(&profile, "Alice", "", "Munro", "munro@gmail.com", "",
- "1331 W Georgia", "", "Vancouver", "Tennessee",
- "V4D 4S4", "CA", "(778) 567-8901");
- profile.set_guid("00000000-0000-0000-0000-000000000002");
- profile.SetValidityState(ADDRESS_HOME_STATE, AutofillDataModel::INVALID,
- AutofillDataModel::SERVER);
- profiles.push_back(profile);
- }
-
- // Set up the test cases:
- typedef struct {
- std::u16string input_value;
- ServerFieldType field_type;
- std::vector<AutofillDataModel::ValidityState> expected_validity_states;
- } TestFieldData;
-
- std::vector<TestFieldData> test_cases[3];
- // Tennessee appears in both of the user's profile as ADDRESS_HOME_STATE. In
- // the first one, it's VALID, and for the other, it's INVALID. Therefore, the
- // possible_field_types would only include the type ADDRESS_HOME_STATE, and
- // the corresponding validity of that type would include both VALID and
- // INVALID.
- test_cases[0].push_back(
- {u"Tennessee",
- ADDRESS_HOME_STATE,
- {AutofillDataModel::VALID, AutofillDataModel::INVALID}});
- // Alice appears only in the second profile as a NAME_FIRST, and it's
- // UNVALIDATED.
- test_cases[1].push_back(
- {u"Alice", NAME_FIRST, {AutofillDataModel::UNVALIDATED}});
- // An UNKNOWN type is always UNVALIDATED.
- test_cases[2].push_back({u"What a beautiful day!",
- UNKNOWN_TYPE,
- {AutofillDataModel::UNVALIDATED}});
-
- for (const std::vector<TestFieldData>& test_fields : test_cases) {
- FormData form;
- form.name = u"MyForm";
- form.url = GURL("https://myform.com/form.html");
- form.action = GURL("https://myform.com/submit.html");
-
- // Create the form fields specified in the test case.
- FormFieldData field;
- ServerFieldTypeSet possible_types;
- ServerFieldTypeValidityStatesMap possible_types_validities;
- for (const TestFieldData& test_field : test_fields) {
- test::CreateTestFormField("", "1", "", "text", &field);
- field.value = test_field.input_value;
- form.fields.push_back(field);
- }
-
- // Assign the specified predicted type for each field in the test case.
- FormStructure form_structure(form);
- for (size_t i = 0; i < test_fields.size(); ++i) {
- AutofillQueryResponse::FormSuggestion::FieldSuggestion::FieldPrediction
- prediction;
- prediction.set_type(test_fields[i].field_type);
- form_structure.field(i)->set_server_predictions({prediction});
- }
-
- BrowserAutofillManager::DeterminePossibleFieldTypesForUploadForTest(
- profiles, {}, std::u16string(), "en-us", &form_structure);
-
- ASSERT_EQ(test_fields.size(), form_structure.field_count());
-
- for (size_t i = 0; i < test_fields.size(); ++i) {
- possible_types = form_structure.field(i)->possible_types();
- // For both cases we only expect one possible type.
- EXPECT_EQ(1U, possible_types.size());
- // Expect to see the field_type as the possible type.
- EXPECT_NE(possible_types.end(),
- possible_types.find(test_fields[i].field_type));
-
- // Expect the same for possible_types_validities.
- possible_types_validities =
- form_structure.field(i)->possible_types_validities();
- EXPECT_EQ(1U, possible_types_validities.size());
- EXPECT_NE(possible_types_validities.end(),
- possible_types_validities.find(test_fields[i].field_type));
- // Check for the expected validity states for the possible type.
- EXPECT_EQ(test_fields[i].expected_validity_states.size(),
- possible_types_validities[test_fields[i].field_type].size());
- for (size_t j = 0; j < test_fields[i].expected_validity_states.size();
- ++j)
- EXPECT_EQ(possible_types_validities[test_fields[i].field_type][j],
- test_fields[i].expected_validity_states[j]);
- }
- }
-}
-
// Tests that DisambiguateUploadTypes makes the correct choices.
TEST_P(BrowserAutofillManagerStructuredProfileTest, DisambiguateUploadTypes) {
// Set up the test profile.
@@ -7535,7 +7490,7 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
// Get the suggestions for already filled credit card |number_field|.
GetAutofillSuggestions(form, number_field);
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
const std::string visa_label = std::string("04/99");
const std::string master_card_label = std::string("10/98");
#else
@@ -7844,7 +7799,7 @@ TEST_P(CreditCardSuggestionTest,
credit_card.SetNickname(kArbitraryNickname16);
personal_data_.AddCreditCard(credit_card);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// When keyboard accessary is enabled, always show "7777".
// When keyboard accessary is disabled, if nickname is valid, show "Nickname
// ****7777", otherwise, show "Visa ****7777".
@@ -7854,7 +7809,7 @@ TEST_P(CreditCardSuggestionTest,
: kArbitraryNickname + " " +
test::ObfuscatedCardDigitsAsUTF8("7777", ObfuscationLength());
-#elif defined(OS_IOS)
+#elif BUILDFLAG(IS_IOS)
const std::string visa_label =
test::ObfuscatedCardDigitsAsUTF8("7777", ObfuscationLength());
@@ -8439,7 +8394,7 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
FormFieldData field = form.fields[1];
GetAutofillSuggestions(form, field);
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
std::string label = std::string("04/99");
#else
std::string label = std::string("Expires on 04/99");
@@ -8460,9 +8415,9 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
field = form.fields[0];
GetAutofillSuggestions(form, field);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
label = std::string("nickname ") + test::ObfuscatedCardDigitsAsUTF8("3456");
-#elif defined(OS_IOS)
+#elif BUILDFLAG(IS_IOS)
label = test::ObfuscatedCardDigitsAsUTF8("3456");
#else
label = std::string("nickname ") + test::ObfuscatedCardDigitsAsUTF8("3456") +
@@ -9180,13 +9135,13 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeature(features::kAutofillSaveAndFillVPA);
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
EXPECT_CALL(autofill_client_, ConfirmSaveUpiIdLocally(test_upi_id_value, _))
.WillOnce([](std::string upi_id,
base::OnceCallback<void(bool user_decision)> callback) {
std::move(callback).Run(true);
});
-#endif // #if !defined(OS_ANDROID) && !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
FormData form;
form.url = GURL("https://wwww.foo.com");
@@ -9205,7 +9160,7 @@ TEST_P(BrowserAutofillManagerStructuredProfileTest,
form.fields[0].value = base::UTF8ToUTF16(test_upi_id_value);
FormSubmitted(form);
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
// The feature is not implemented for mobile.
EXPECT_EQ(0, personal_data_.num_times_save_upi_id_called());
#else
@@ -9219,9 +9174,9 @@ TEST_F(BrowserAutofillManagerTest, DontImportUpiIdWhenIncognito) {
scoped_feature_list.InitAndEnableFeature(features::kAutofillSaveAndFillVPA);
autofill_driver_->SetIsIncognito(true);
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
EXPECT_CALL(autofill_client_, ConfirmSaveUpiIdLocally(_, _)).Times(0);
-#endif // #if !defined(OS_ANDROID) && !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
FormData form;
form.url = GURL("https://wwww.foo.com");
@@ -9266,7 +9221,7 @@ TEST_F(BrowserAutofillManagerTest, PageLanguageGetsCorrectlySet) {
TEST_F(BrowserAutofillManagerTest, PageLanguageGetsCorrectlyDetected) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeature(
- features::kAutofillParsingPatternsLanguageDetection);
+ features::kAutofillPageLanguageDetection);
FormData form;
test::CreateTestAddressFormData(&form);
@@ -9432,7 +9387,7 @@ TEST_F(BrowserAutofillManagerTest, GetSuggestions_AboutBlankTarget) {
EXPECT_FALSE(external_delegate_->on_suggestions_returned_seen());
}
-// Test that the Autofill does not override field values that were already
+// Test that the Autofill does not override input field values that were already
// prefilled.
TEST_F(BrowserAutofillManagerTest, PreventOverridingOfPrefilledValues) {
base::test::ScopedFeatureList features;
@@ -9444,13 +9399,20 @@ TEST_F(BrowserAutofillManagerTest, PreventOverridingOfPrefilledValues) {
form.url = GURL("https://myform.com/form.html");
form.action = GURL("about:blank");
FormFieldData field;
- test::CreateTestFormField("Name", "name", "Test Name", "text", &field);
+ test::CreateTestFormField("Name", "name", "", "text", &field);
form.fields.push_back(field);
test::CreateTestFormField("City", "city", "Test City", "text", &field);
form.fields.push_back(field);
+ test::CreateTestSelectField("State", "state", "California",
+ {"Washington", "Tennessee", "California"},
+ {"DC", "TN", "CA"}, 3, &field);
+ form.fields.push_back(field);
test::CreateTestFormField("Country", "country", "Test Country", "text",
&field);
form.fields.push_back(field);
+ test::CreateTestFormField("Phone Number", "phonenumber", "12345678901", "tel",
+ &field);
+ form.fields.push_back(field);
std::vector<FormData> forms(1, form);
FormsSeen(forms);
@@ -9460,9 +9422,42 @@ TEST_F(BrowserAutofillManagerTest, PreventOverridingOfPrefilledValues) {
FillAutofillFormDataAndSaveResults(kDefaultPageID, form, form.fields[0],
MakeFrontendID(std::string(), guid),
&response_page_id, &response_data);
- EXPECT_EQ(response_data.fields[0].value, u"Test Name");
+ EXPECT_EQ(response_data.fields[0].value, u"Elvis Aaron Presley");
EXPECT_EQ(response_data.fields[1].value, u"Test City");
- EXPECT_EQ(response_data.fields[2].value, u"Test Country");
+ EXPECT_EQ(response_data.fields[2].value, u"Tennessee");
+ EXPECT_EQ(response_data.fields[3].value, u"Test Country");
+ EXPECT_EQ(response_data.fields[4].value, u"12345678901");
+
+ {
+ FormStructure* form_structure;
+ AutofillField* autofill_field;
+ std::vector<std::string> expected_values = {"", "Memphis", "",
+ "United States", ""};
+ bool found = browser_autofill_manager_->GetCachedFormAndField(
+ form, form.fields[0], &form_structure, &autofill_field);
+ ASSERT_TRUE(found);
+ for (size_t i = 0; i < form.fields.size(); ++i) {
+ ASSERT_TRUE(form_structure->field(i)->SameFieldAs(form.fields[i]));
+ if (!expected_values[i].empty()) {
+ EXPECT_TRUE(form_structure->field(i)
+ ->value_not_autofilled_over_existing_value_hash()
+ .has_value());
+ EXPECT_FALSE(form_structure->field(i)->is_autofilled);
+ EXPECT_EQ(form_structure->field(i)
+ ->value_not_autofilled_over_existing_value_hash(),
+ base::FastHash(expected_values[i]));
+ }
+ }
+
+ EXPECT_TRUE(form_structure->field(0)->is_autofilled); // No prefilled value
+ EXPECT_TRUE(form_structure->field(2)->is_autofilled); // Selection field.
+
+ // Prefilled value is same as the value to be autofilled so
+ // |value_not_autofilled_over_existing_value_hash| is not set for the field.
+ EXPECT_FALSE(form_structure->field(4)->is_autofilled);
+ EXPECT_FALSE(form_structure->field(4)
+ ->value_not_autofilled_over_existing_value_hash());
+ }
features.Reset();
features.InitAndDisableFeature(
@@ -9473,11 +9468,58 @@ TEST_F(BrowserAutofillManagerTest, PreventOverridingOfPrefilledValues) {
&response_page_id, &response_data);
EXPECT_EQ(response_data.fields[0].value, u"Elvis Aaron Presley");
EXPECT_EQ(response_data.fields[1].value, u"Memphis");
- EXPECT_EQ(response_data.fields[2].value, u"United States");
+ EXPECT_EQ(response_data.fields[2].value, u"Tennessee");
+ EXPECT_EQ(response_data.fields[3].value, u"United States");
+ EXPECT_EQ(response_data.fields[4].value, u"12345678901");
+}
+
+// Tests that the Autofill does override the prefilled field value since the
+// field is the initiating field for the Autofill and has a prefilled value
+// which is a substring of the autofillable value.
+TEST_F(BrowserAutofillManagerTest, AutofillOverridePrefilledValue) {
+ base::test::ScopedFeatureList features;
+ features.InitAndEnableFeature(
+ autofill::features::kAutofillPreventOverridingPrefilledValues);
+ // Set up our form data.
+ FormData form;
+ form.name = u"MyForm";
+ form.url = GURL("https://myform.com/form.html");
+ form.action = GURL("about:blank");
+ FormFieldData field;
+ test::CreateTestFormField("Name", "name", "Test Name", "text", &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("City", "city", "Test City", "text", &field);
+ form.fields.push_back(field);
+ test::CreateTestSelectField("State", "state", "California",
+ {"Washington", "Tennessee", "California"},
+ {"DC", "TN", "CA"}, 3, &field);
+ form.fields.push_back(field);
+ test::CreateTestFormField("Country", "country", "Test Country", "text",
+ &field);
+ form.fields.push_back(field);
+ std::vector<FormData> forms(1, form);
+ FormsSeen(forms);
+
+ // "Elv" is a substring of "Elvis Aaron Presley".
+ form.fields[0].value = u"Elv";
+ // Simulate editing a field.
+ browser_autofill_manager_->OnTextFieldDidChange(
+ form, form.fields.front(), gfx::RectF(), AutofillTickClock::NowTicks());
+
+ const char guid[] = "00000000-0000-0000-0000-000000000001";
+ int response_page_id = 0;
+ FormData response_data;
+ FillAutofillFormDataAndSaveResults(kDefaultPageID, form, form.fields[0],
+ MakeFrontendID(std::string(), guid),
+ &response_page_id, &response_data);
+ EXPECT_EQ(response_data.fields[0].value, u"Elvis Aaron Presley");
+ EXPECT_EQ(response_data.fields[1].value, u"Test City");
+ EXPECT_EQ(response_data.fields[2].value, u"Tennessee");
+ EXPECT_EQ(response_data.fields[3].value, u"Test Country");
}
// Desktop only tests.
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
class BrowserAutofillManagerTestForVirtualCardOption
: public BrowserAutofillManagerTest {
protected:
@@ -9915,12 +9957,8 @@ TEST_P(OnFocusOnFormFieldTest, CreditCardSuggestions_Ablation) {
INSTANTIATE_TEST_SUITE_P(
BrowserAutofillManagerTest,
ProfileMatchingTypesTest,
- testing::Combine(
- testing::ValuesIn(kProfileMatchingTypesTestCases),
- testing::Range(static_cast<int>(AutofillDataModel::UNVALIDATED),
- static_cast<int>(AutofillDataModel::UNSUPPORTED) + 1),
- testing::Bool(),
- testing::Bool()));
+ testing::Combine(testing::ValuesIn(kProfileMatchingTypesTestCases),
+ testing::Bool()));
INSTANTIATE_TEST_SUITE_P(All, OnFocusOnFormFieldTest, testing::Bool());
@@ -9930,7 +9968,7 @@ INSTANTIATE_TEST_SUITE_P(,
BrowserAutofillManagerStructuredProfileTest,
testing::Bool());
-#if defined(OS_IOS) || defined(OS_ANDROID)
+#if BUILDFLAG(IS_IOS) || BUILDFLAG(IS_ANDROID)
INSTANTIATE_TEST_SUITE_P(,
SuggestionMatchingTest,
testing::Values(std::make_tuple(0, ""),
@@ -9941,7 +9979,7 @@ INSTANTIATE_TEST_SUITE_P(All,
SuggestionMatchingTest,
testing::Values(std::make_tuple(0, ""),
std::make_tuple(1, "")));
-#endif // defined(OS_IOS) || defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_IOS) || BUILDFLAG(IS_ANDROID)
// The parameter indicates whether the AutofillKeyboardAccessory feature is
// enabled or disabled.
@@ -10020,7 +10058,7 @@ TEST_P(BrowserAutofillManagerTestForSharingNickname,
FormFieldData field = form.fields[1];
GetAutofillSuggestions(form, field);
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
const std::string exp_label = std::string("04/99");
#else
const std::string exp_label = std::string("Expires on 04/99");
@@ -10060,7 +10098,7 @@ TEST_P(BrowserAutofillManagerTestForSharingNickname,
FormFieldData field = form.fields[1];
GetAutofillSuggestions(form, field);
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
const std::string exp_label = std::string("04/99");
#else
const std::string exp_label = std::string("Expires on 04/99");
diff --git a/chromium/components/autofill/core/browser/data_model/autofill_data_model.cc b/chromium/components/autofill/core/browser/data_model/autofill_data_model.cc
index b0ea8bd395f..865f1e7d6f6 100644
--- a/chromium/components/autofill/core/browser/data_model/autofill_data_model.cc
+++ b/chromium/components/autofill/core/browser/data_model/autofill_data_model.cc
@@ -81,10 +81,4 @@ bool AutofillDataModel::IsDeletable() const {
return IsAutofillEntryWithUseDateDeletable(use_date_);
}
-AutofillDataModel::ValidityState AutofillDataModel::GetValidityState(
- ServerFieldType type,
- AutofillDataModel::ValidationSource source) const {
- return AutofillDataModel::UNSUPPORTED;
-}
-
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/data_model/autofill_data_model.h b/chromium/components/autofill/core/browser/data_model/autofill_data_model.h
index 0d85ae3fccb..9cf913a6f49 100644
--- a/chromium/components/autofill/core/browser/data_model/autofill_data_model.h
+++ b/chromium/components/autofill/core/browser/data_model/autofill_data_model.h
@@ -89,10 +89,6 @@ class AutofillDataModel : public FormGroup {
// longer than |kDisusedCreditCardDeletionTimeDelta|.
virtual bool IsDeletable() const;
- // Returns the validity state of the specified autofill type.
- virtual ValidityState GetValidityState(ServerFieldType type,
- ValidationSource source) const;
-
protected:
// Called to update |use_count_| and |use_date_| when this data model is
// the subject of user interaction (usually, when it's used to fill a form).
diff --git a/chromium/components/autofill/core/browser/data_model/autofill_profile.cc b/chromium/components/autofill/core/browser/data_model/autofill_profile.cc
index 3139416cad8..439ef76f42e 100644
--- a/chromium/components/autofill/core/browser/data_model/autofill_profile.cc
+++ b/chromium/components/autofill/core/browser/data_model/autofill_profile.cc
@@ -209,36 +209,6 @@ void GetFieldsForDistinguishingProfiles(
}
}
-// Constants for the validity bitfield.
-const size_t kValidityBitsPerType = 2;
-// The order is important to ensure a consistent bitfield value. New values
-// should be added at the end NOT at the start or middle.
-const ServerFieldType kSupportedTypesByClientForValidation[] = {
- ADDRESS_HOME_COUNTRY,
- ADDRESS_HOME_STATE,
- ADDRESS_HOME_ZIP,
- ADDRESS_HOME_CITY,
- ADDRESS_HOME_DEPENDENT_LOCALITY,
- EMAIL_ADDRESS,
- PHONE_HOME_WHOLE_NUMBER};
-
-const size_t kNumSupportedTypesForValidation =
- sizeof(kSupportedTypesByClientForValidation) /
- sizeof(kSupportedTypesByClientForValidation[0]);
-
-static_assert(kNumSupportedTypesForValidation * kValidityBitsPerType <= 64,
- "Not enough bits to encode profile validity information!");
-
-// Some types are specializations of other types. Normalize these back to the
-// main stored type for used to mark field validity .
-ServerFieldType NormalizeTypeForValidityCheck(ServerFieldType type) {
- auto field_type_group = AutofillType(type).group();
- if (field_type_group == FieldTypeGroup::kPhoneHome ||
- field_type_group == FieldTypeGroup::kPhoneBilling)
- return PHONE_HOME_WHOLE_NUMBER;
- return type;
-}
-
} // namespace
AutofillProfile::AutofillProfile(const std::string& guid,
@@ -305,10 +275,6 @@ AutofillProfile& AutofillProfile::operator=(const AutofillProfile& profile) {
server_id_ = profile.server_id();
has_converted_ = profile.has_converted();
- is_client_validity_states_updated_ =
- profile.is_client_validity_states_updated();
- SetClientValidityFromBitfieldValue(profile.GetClientValidityBitfieldValue());
- server_validity_states_ = profile.GetServerValidityMap();
return *this;
}
@@ -351,31 +317,6 @@ void AutofillProfile::GetMatchingTypes(
}
}
-void AutofillProfile::GetMatchingTypesAndValidities(
- const std::u16string& text,
- const std::string& app_locale,
- ServerFieldTypeSet* matching_types,
- ServerFieldTypeValidityStateMap* matching_types_validities) const {
- if (!matching_types && !matching_types_validities)
- return;
-
- ServerFieldTypeSet matching_types_in_this_profile;
- for (const auto* form_group : FormGroups()) {
- form_group->GetMatchingTypes(text, app_locale,
- &matching_types_in_this_profile);
- }
-
- for (auto type : matching_types_in_this_profile) {
- if (matching_types_validities) {
- // TODO(crbug.com/879655): Set the client validities and look them up when
- // the server validities are not available.
- (*matching_types_validities)[type] = GetValidityState(type, SERVER);
- }
- if (matching_types)
- matching_types->insert(type);
- }
-}
-
std::u16string AutofillProfile::GetRawInfo(ServerFieldType type) const {
const FormGroup* form_group = FormGroupForType(AutofillType(type));
if (!form_group)
@@ -390,8 +331,6 @@ void AutofillProfile::SetRawInfoWithVerificationStatus(
VerificationStatus status) {
FormGroup* form_group = MutableFormGroupForType(AutofillType(type));
if (form_group) {
- is_client_validity_states_updated_ &=
- !IsClientValidationSupportedForType(type);
form_group->SetRawInfoWithVerificationStatus(type, value, status);
}
}
@@ -538,16 +477,6 @@ bool AutofillProfile::EqualsForUpdatePurposes(
Compare(new_profile) == 0;
}
-bool AutofillProfile::EqualsForClientValidationPurpose(
- const AutofillProfile& profile) const {
- for (ServerFieldType type : kSupportedTypesByClientForValidation) {
- if (GetRawInfo(type).compare(profile.GetRawInfo(type))) {
- return false;
- }
- }
- return true;
-}
-
bool AutofillProfile::EqualsIncludingUsageStatsForTesting(
const AutofillProfile& profile) const {
return use_count() == profile.use_count() &&
@@ -794,8 +723,6 @@ bool AutofillProfile::MergeDataFrom(const AutofillProfile& profile,
modified = true;
}
- is_client_validity_states_updated_ &= !modified;
-
return modified;
}
@@ -994,198 +921,6 @@ void AutofillProfile::LogVerificationStatuses() {
AutofillMetrics::LogVerificationStatusOfAddressTokensOnProfileUsage(*this);
}
-bool AutofillProfile::HasGreaterFrescocencyThan(
- const AutofillProfile* other,
- base::Time comparison_time,
- bool use_client_validation,
- bool use_server_validation) const {
- double score = GetFrecencyScore(comparison_time);
- double other_score = other->GetFrecencyScore(comparison_time);
-
- const double kEpsilon = 0.001;
- if (std::fabs(score - other_score) > kEpsilon)
- return score > other_score;
-
- bool is_valid = (!use_client_validation || IsValidByClient()) &&
- (!use_server_validation || IsValidByServer());
- bool other_is_valid = (!use_client_validation || other->IsValidByClient()) &&
- (!use_server_validation || other->IsValidByServer());
-
- if (is_valid == other_is_valid) {
- if (use_date() != other->use_date())
- return use_date() > other->use_date();
- return guid() > other->guid();
- }
-
- if (is_valid && !other_is_valid)
- return true;
- return false;
-}
-
-bool AutofillProfile::IsValidByClient() const {
- for (auto const& it : client_validity_states_) {
- if (it.second == INVALID)
- return false;
- }
- return true;
-}
-
-bool AutofillProfile::IsValidByServer() const {
- for (auto const& it : server_validity_states_) {
- if (it.second == INVALID)
- return false;
- }
- return true;
-}
-
-bool AutofillProfile::IsAnInvalidPhoneNumber(ServerFieldType type) const {
- if (GetValidityState(type, SERVER) == VALID ||
- (type != PHONE_HOME_WHOLE_NUMBER && type != PHONE_HOME_NUMBER &&
- type != PHONE_BILLING_WHOLE_NUMBER && type != PHONE_BILLING_NUMBER))
- return false;
- if (GetValidityState(type, SERVER) == INVALID)
- return true;
-
- ServerFieldTypeSet types;
- if (GroupTypeOfServerFieldType(type) == FieldTypeGroup::kPhoneHome) {
- types = {PHONE_HOME_NUMBER, PHONE_HOME_CITY_CODE,
- PHONE_HOME_CITY_AND_NUMBER};
- if (type == PHONE_HOME_WHOLE_NUMBER) {
- types.insert(PHONE_HOME_WHOLE_NUMBER);
- types.insert(PHONE_HOME_COUNTRY_CODE);
- }
- } else if (GroupTypeOfServerFieldType(type) ==
- FieldTypeGroup::kPhoneBilling) {
- types = {PHONE_BILLING_NUMBER, PHONE_BILLING_CITY_CODE,
- PHONE_BILLING_CITY_AND_NUMBER};
- if (type == PHONE_BILLING_WHOLE_NUMBER) {
- types.insert(PHONE_BILLING_WHOLE_NUMBER);
- types.insert(PHONE_BILLING_COUNTRY_CODE);
- }
- }
-
- for (auto cur_type : types) {
- if (GetValidityState(cur_type, SERVER) == INVALID)
- return true;
- }
- return false;
-}
-
-AutofillDataModel::ValidityState AutofillProfile::GetValidityState(
- ServerFieldType type,
- ValidationSource validation_source) const {
- if (validation_source == CLIENT) {
- type = NormalizeTypeForValidityCheck(type);
- // Return UNSUPPORTED for types that autofill does not validate.
- if (!IsClientValidationSupportedForType(type))
- return UNSUPPORTED;
-
- auto it = client_validity_states_.find(type);
- return (it == client_validity_states_.end()) ? UNVALIDATED : it->second;
- }
- DCHECK_EQ(SERVER, validation_source);
-
- auto it = server_validity_states_.find(type);
- return (it == server_validity_states_.end()) ? UNVALIDATED : it->second;
-}
-
-void AutofillProfile::SetValidityState(
- ServerFieldType type,
- ValidityState validity,
- ValidationSource validation_source) const {
- if (validation_source == CLIENT) {
- // Do not save validity of unsupported types.
- if (!IsClientValidationSupportedForType(type))
- return;
- client_validity_states_[type] = validity;
- return;
- }
- DCHECK_EQ(SERVER, validation_source);
- server_validity_states_[type] = validity;
-}
-
-void AutofillProfile::UpdateServerValidityMap(
- const ProfileValidityMap& validity_map) const {
- server_validity_states_.clear();
- const auto& field_validity_states = validity_map.field_validity_states();
- for (const auto& current_pair : field_validity_states) {
- const auto field_type =
- ToSafeServerFieldType(current_pair.first, UNKNOWN_TYPE);
- const auto field_validity = static_cast<ValidityState>(current_pair.second);
- server_validity_states_[field_type] = field_validity;
- }
-}
-
-// static
-bool AutofillProfile::IsClientValidationSupportedForType(ServerFieldType type) {
- for (auto supported_type : kSupportedTypesByClientForValidation) {
- if (type == supported_type)
- return true;
- }
- return false;
-}
-
-int AutofillProfile::GetClientValidityBitfieldValue() const {
- int validity_value = 0;
- size_t field_type_shift = 0;
- for (ServerFieldType supported_type : kSupportedTypesByClientForValidation) {
- validity_value |= GetValidityState(supported_type, CLIENT)
- << field_type_shift;
- field_type_shift += kValidityBitsPerType;
- }
-
- // Check the the shift is still in range.
- DCHECK_LE(field_type_shift, 64U);
-
- return validity_value;
-}
-
-void AutofillProfile::SetClientValidityFromBitfieldValue(
- int bitfield_value) const {
- // Compute the bitmask based on the number a bits per type. For example, this
- // could be the two least significant bits (0b11).
- const int kBitmask = (1 << kValidityBitsPerType) - 1;
-
- for (ServerFieldType supported_type : kSupportedTypesByClientForValidation) {
- // Apply the bitmask to the bitfield value to get the validity value of the
- // current |supported_type|.
- int validity_value = bitfield_value & kBitmask;
- if (validity_value < 0 || validity_value >= UNSUPPORTED) {
- NOTREACHED();
- continue;
- }
-
- SetValidityState(supported_type, static_cast<ValidityState>(validity_value),
- CLIENT);
-
- // Shift the bitfield value to access the validity of the next field type.
- bitfield_value = bitfield_value >> kValidityBitsPerType;
- }
-}
-
-bool AutofillProfile::ShouldSkipFillingOrSuggesting(
- ServerFieldType type) const {
- if (base::FeatureList::IsEnabled(
- autofill::features::kAutofillProfileServerValidation) &&
- GetValidityState(type, AutofillProfile::SERVER) ==
- AutofillProfile::INVALID) {
- return true;
- }
-
- // We are making an exception and skipping the validation check for address
- // fields when the country is empty.
- if (base::FeatureList::IsEnabled(
- autofill::features::kAutofillProfileClientValidation) &&
- GetValidityState(type, AutofillProfile::CLIENT) ==
- AutofillProfile::INVALID &&
- (GroupTypeOfServerFieldType(type) != FieldTypeGroup::kAddressHome ||
- !GetRawInfo(ADDRESS_HOME_COUNTRY).empty())) {
- return true;
- }
-
- return false;
-}
-
VerificationStatus AutofillProfile::GetVerificationStatusImpl(
const ServerFieldType type) const {
const FormGroup* form_group = FormGroupForType(AutofillType(type));
@@ -1225,9 +960,6 @@ bool AutofillProfile::SetInfoWithVerificationStatusImpl(
if (!form_group)
return false;
- is_client_validity_states_updated_ &=
- !IsClientValidationSupportedForType(type.GetStorableType());
-
std::u16string trimmed_value;
base::TrimWhitespace(value, base::TRIM_ALL, &trimmed_value);
@@ -1363,10 +1095,9 @@ std::ostream& operator<<(std::ostream& os, const AutofillProfile& profile) {
: base::HexEncode(profile.server_id().data(),
profile.server_id().size()))
<< " " << profile.origin() << " "
- << "label: " << profile.profile_label() << " "
- << profile.GetClientValidityBitfieldValue() << " "
- << profile.has_converted() << " " << profile.use_count() << " "
- << profile.use_date() << " " << profile.language_code() << std::endl;
+ << "label: " << profile.profile_label() << " " << profile.has_converted()
+ << " " << profile.use_count() << " " << profile.use_date() << " "
+ << profile.language_code() << std::endl;
// Lambda to print the value and verification status for |type|.
auto print_values_lambda = [&os, &profile](ServerFieldType type) {
diff --git a/chromium/components/autofill/core/browser/data_model/autofill_profile.h b/chromium/components/autofill/core/browser/data_model/autofill_profile.h
index 0f547d1ff59..98394b3c6bc 100644
--- a/chromium/components/autofill/core/browser/data_model/autofill_profile.h
+++ b/chromium/components/autofill/core/browser/data_model/autofill_profile.h
@@ -69,13 +69,6 @@ class AutofillProfile : public AutofillDataModel {
const std::string& app_locale,
ServerFieldTypeSet* matching_types) const override;
- void GetMatchingTypesAndValidities(
- const std::u16string& text,
- const std::string& app_locale,
- ServerFieldTypeSet* matching_types,
- std::map<ServerFieldType, AutofillProfile::ValidityState>*
- matching_types_validities) const;
-
std::u16string GetRawInfo(ServerFieldType type) const override;
void SetRawInfoWithVerificationStatus(
ServerFieldType type,
@@ -114,9 +107,6 @@ class AutofillProfile : public AutofillDataModel {
// the |new_profile|.
bool EqualsForUpdatePurposes(const AutofillProfile& new_profile) const;
- // Compares the values of kSupportedTypesByClientForValidation fields.
- bool EqualsForClientValidationPurpose(const AutofillProfile& profile) const;
-
// Same as operator==, but cares about differences in usage stats.
bool EqualsIncludingUsageStatsForTesting(
const AutofillProfile& profile) const;
@@ -214,23 +204,6 @@ class AutofillProfile : public AutofillDataModel {
// tokens. Should be called when a profile is used to fill a form.
void LogVerificationStatuses();
- // Returns true if the current profile has greater frescocency than the
- // |other|. Frescocency is a combination of validation score and frecency to
- // determine the relevance of the profile. Frescocency is a total order: it
- // puts all the valid profiles before the invalid ones in case of frecency
- // tie. Please see AutofillDataModel::HasGreaterFrecencyThan.
- bool HasGreaterFrescocencyThan(const AutofillProfile* other,
- base::Time comparison_time,
- bool use_client_validation,
- bool use_server_validation) const;
-
- // Returns false if the profile has any invalid field, according to the client
- // source of validation.
- bool IsValidByClient() const;
- // Returns false if the profile has any invalid field, according to the server
- // source of validation.
- bool IsValidByServer() const;
-
const base::Time& previous_use_date() const { return previous_use_date_; }
void set_previous_use_date(const base::Time& time) {
previous_use_date_ = time;
@@ -240,52 +213,6 @@ class AutofillProfile : public AutofillDataModel {
bool has_converted() const { return has_converted_; }
void set_has_converted(bool has_converted) { has_converted_ = has_converted; }
- // Returns the validity state of the specified autofill type.
- ValidityState GetValidityState(ServerFieldType type,
- ValidationSource source) const override;
-
- // Sets the validity state of the specified autofill type.
- // This should only be called from autofill profile validtion API or in tests.
- void SetValidityState(ServerFieldType type,
- ValidityState validity,
- ValidationSource validation_source) const;
-
- // Update the validity map based on the server side validity maps from the
- // prefs.
- void UpdateServerValidityMap(const ProfileValidityMap& validity_states) const;
-
- // Returns whether autofill does the validation of the specified |type|.
- static bool IsClientValidationSupportedForType(ServerFieldType type);
-
- // Returns the bitfield value representing the validity state of this profile
- // based on client validation source.
- int GetClientValidityBitfieldValue() const;
-
- // Sets the validity state of the profile based on the specified
- // |bitfield_value| based on client validation source.
- void SetClientValidityFromBitfieldValue(int bitfield_value) const;
-
- // Returns true if type is a phone type and it's invalid, either explicitly,
- // or by looking at its components.
- bool IsAnInvalidPhoneNumber(ServerFieldType type) const;
-
- const std::map<ServerFieldType, ValidityState>& GetServerValidityMap() const {
- return server_validity_states_;
- }
-
- bool is_client_validity_states_updated() const {
- return is_client_validity_states_updated_;
- }
-
- void set_is_client_validity_states_updated(
- bool is_client_validity_states_updated) const {
- is_client_validity_states_updated_ = is_client_validity_states_updated;
- }
-
- // Check for the validity of the data. Leave the field empty if the data is
- // invalid and the relevant feature is enabled.
- bool ShouldSkipFillingOrSuggesting(ServerFieldType type) const;
-
base::WeakPtr<const AutofillProfile> GetWeakPtr() const {
return weak_ptr_factory_.GetWeakPtr();
}
@@ -397,15 +324,6 @@ class AutofillProfile : public AutofillDataModel {
// converted to a local profile.
bool has_converted_;
- // This flag denotes whether the client_validity_states_ are updated according
- // to the changes in the autofill profile values.
- mutable bool is_client_validity_states_updated_ = false;
-
- // A map identifying what fields are valid according to server validation.
- mutable std::map<ServerFieldType, ValidityState> server_validity_states_;
-
- // A map identifying what fields are valid according to client validation.
- mutable std::map<ServerFieldType, ValidityState> client_validity_states_;
mutable base::WeakPtrFactory<AutofillProfile> weak_ptr_factory_{this};
};
diff --git a/chromium/components/autofill/core/browser/data_model/autofill_profile_unittest.cc b/chromium/components/autofill/core/browser/data_model/autofill_profile_unittest.cc
index 540acf9954f..bb98e3524bc 100644
--- a/chromium/components/autofill/core/browser/data_model/autofill_profile_unittest.cc
+++ b/chromium/components/autofill/core/browser/data_model/autofill_profile_unittest.cc
@@ -44,14 +44,12 @@ std::u16string GetSuggestionLabel(AutofillProfile* profile) {
return labels[0];
}
-void SetupValidatedTestProfile(AutofillProfile& profile) {
+void SetupTestProfile(AutofillProfile& profile) {
profile.set_guid(base::GenerateGUID());
profile.set_origin(kSettingsOrigin);
test::SetProfileInfo(&profile, "Marion", "Mitchell", "Morrison",
"marion@me.xyz", "Fox", "123 Zoo St.", "unit 5",
"Hollywood", "CA", "91601", "US", "12345678910");
- profile.SetClientValidityFromBitfieldValue(1984);
- profile.set_is_client_validity_states_updated(true);
}
std::vector<AutofillProfile*> ToRawPointerVector(
@@ -1075,25 +1073,9 @@ TEST_P(AutofillProfileTest, SetAndGetInfoWithValidationStatus) {
EXPECT_EQ(profile.GetRawInfo(NAME_MIDDLE_INITIAL), u"CS");
}
-TEST_P(AutofillProfileTest, SetRawInfo_UpdateValidityFlag) {
- AutofillProfile a;
- SetupValidatedTestProfile(a);
- EXPECT_TRUE(a.is_client_validity_states_updated());
-
- a.SetRawInfo(NAME_FULL, u"Alice Munro");
- // NAME_FULL is NOT validated through the client API (not supported),
- // therefore it should not change the validity flag.
- EXPECT_TRUE(a.is_client_validity_states_updated());
-
- a.SetRawInfo(ADDRESS_HOME_CITY, u"Ooz");
- // ADDRESS_HOME_CITY IS validated through the client API, therefore it should
- // change the flag to false.
- EXPECT_FALSE(a.is_client_validity_states_updated());
-}
-
TEST_P(AutofillProfileTest, MergeDataFrom_DifferentProfile) {
AutofillProfile a;
- SetupValidatedTestProfile(a);
+ SetupTestProfile(a);
// Create an identical profile except that the new profile:
// (1) Has a different origin,
@@ -1119,7 +1101,6 @@ TEST_P(AutofillProfileTest, MergeDataFrom_DifferentProfile) {
EXPECT_TRUE(a.MergeDataFrom(b, "en-US"));
// Merge has modified profile a, the validation is not updated.
- EXPECT_FALSE(a.is_client_validity_states_updated());
EXPECT_EQ(kSettingsOrigin, a.origin());
EXPECT_EQ("Unit 5, area 51",
base::UTF16ToUTF8(a.GetRawInfo(ADDRESS_HOME_LINE2)));
@@ -1131,7 +1112,7 @@ TEST_P(AutofillProfileTest, MergeDataFrom_DifferentProfile) {
TEST_P(AutofillProfileTest, MergeDataFrom_SameProfile) {
AutofillProfile a;
- SetupValidatedTestProfile(a);
+ SetupTestProfile(a);
// The profile has no full name yet. Merge will add it.
AutofillProfile b = a;
@@ -1145,20 +1126,15 @@ TEST_P(AutofillProfileTest, MergeDataFrom_SameProfile) {
b.set_guid(base::GenerateGUID());
EXPECT_TRUE(a.MergeDataFrom(b, "en-US"));
// Merge has modified profile a, the validation is not updated.
- EXPECT_FALSE(a.is_client_validity_states_updated());
EXPECT_EQ(1u, a.use_count());
- // pretend that the profile is re-validated.
- a.set_is_client_validity_states_updated(true);
-
// Now the profile is fully populated. Merging it again has no effect (except
// for usage statistics).
AutofillProfile c = a;
c.set_guid(base::GenerateGUID());
c.set_use_count(3);
EXPECT_FALSE(a.MergeDataFrom(c, "en-US"));
- // Merge has not modified anything, the validation should not changed.
- EXPECT_TRUE(a.is_client_validity_states_updated());
+ // Merge has not modified anything.
EXPECT_EQ(3u, a.use_count());
}
@@ -1563,528 +1539,6 @@ TEST_P(AutofillProfileTest, SaveAdditionalInfo_Name_ComplementaryInformation) {
EXPECT_EQ(u"Marion Mitchell Morrison", a.GetRawInfo(NAME_FULL));
}
-TEST_P(AutofillProfileTest, IsAnInvalidPhoneNumber) {
- {
- AutofillProfile profile;
- // When all fields are unvalidated, none of them is an invalid phone type.
- EXPECT_EQ(false, profile.IsAnInvalidPhoneNumber(NAME_FULL));
-
- EXPECT_EQ(false, profile.IsAnInvalidPhoneNumber(PHONE_HOME_NUMBER));
- EXPECT_EQ(false, profile.IsAnInvalidPhoneNumber(PHONE_HOME_WHOLE_NUMBER));
- EXPECT_EQ(false, profile.IsAnInvalidPhoneNumber(PHONE_BILLING_NUMBER));
- EXPECT_EQ(false,
- profile.IsAnInvalidPhoneNumber(PHONE_BILLING_WHOLE_NUMBER));
- }
-
- {
- AutofillProfile profile;
- profile.SetValidityState(PHONE_HOME_CITY_AND_NUMBER,
- AutofillDataModel::INVALID,
- AutofillDataModel::CLIENT);
-
- // It's based on the server side validation.
- EXPECT_EQ(false, profile.IsAnInvalidPhoneNumber(ADDRESS_HOME_LINE1));
-
- EXPECT_EQ(false, profile.IsAnInvalidPhoneNumber(PHONE_HOME_NUMBER));
- EXPECT_EQ(false, profile.IsAnInvalidPhoneNumber(PHONE_HOME_WHOLE_NUMBER));
- EXPECT_EQ(false, profile.IsAnInvalidPhoneNumber(PHONE_BILLING_NUMBER));
- EXPECT_EQ(false,
- profile.IsAnInvalidPhoneNumber(PHONE_BILLING_WHOLE_NUMBER));
- }
-
- {
- AutofillProfile profile;
- profile.SetValidityState(PHONE_HOME_CITY_CODE, AutofillDataModel::INVALID,
- AutofillDataModel::SERVER);
- EXPECT_EQ(false, profile.IsAnInvalidPhoneNumber(ADDRESS_HOME_LINE2));
-
- EXPECT_EQ(true, profile.IsAnInvalidPhoneNumber(PHONE_HOME_NUMBER));
- EXPECT_EQ(true, profile.IsAnInvalidPhoneNumber(PHONE_HOME_WHOLE_NUMBER));
- EXPECT_EQ(false, profile.IsAnInvalidPhoneNumber(PHONE_BILLING_NUMBER));
- EXPECT_EQ(false,
- profile.IsAnInvalidPhoneNumber(PHONE_BILLING_WHOLE_NUMBER));
- }
- {
- AutofillProfile profile;
- profile.SetValidityState(PHONE_BILLING_COUNTRY_CODE,
- AutofillDataModel::INVALID,
- AutofillDataModel::SERVER);
- EXPECT_EQ(false, profile.IsAnInvalidPhoneNumber(ADDRESS_HOME_LINE2));
-
- EXPECT_EQ(false, profile.IsAnInvalidPhoneNumber(PHONE_HOME_NUMBER));
- EXPECT_EQ(false, profile.IsAnInvalidPhoneNumber(PHONE_HOME_WHOLE_NUMBER));
- EXPECT_EQ(false, profile.IsAnInvalidPhoneNumber(PHONE_BILLING_NUMBER));
- EXPECT_EQ(true, profile.IsAnInvalidPhoneNumber(PHONE_BILLING_WHOLE_NUMBER));
- }
- {
- AutofillProfile profile;
- profile.SetValidityState(PHONE_BILLING_NUMBER, AutofillDataModel::EMPTY,
- AutofillDataModel::SERVER);
- EXPECT_EQ(false, profile.IsAnInvalidPhoneNumber(PHONE_HOME_CITY_CODE));
-
- EXPECT_EQ(false, profile.IsAnInvalidPhoneNumber(PHONE_HOME_NUMBER));
- EXPECT_EQ(false, profile.IsAnInvalidPhoneNumber(PHONE_HOME_WHOLE_NUMBER));
- EXPECT_EQ(false, profile.IsAnInvalidPhoneNumber(PHONE_BILLING_NUMBER));
- EXPECT_EQ(false,
- profile.IsAnInvalidPhoneNumber(PHONE_BILLING_WHOLE_NUMBER));
- }
- {
- AutofillProfile profile;
- profile.SetValidityState(PHONE_BILLING_WHOLE_NUMBER,
- AutofillDataModel::VALID,
- AutofillDataModel::SERVER);
- EXPECT_EQ(false,
- profile.IsAnInvalidPhoneNumber(PHONE_BILLING_COUNTRY_CODE));
-
- EXPECT_EQ(false, profile.IsAnInvalidPhoneNumber(PHONE_HOME_NUMBER));
- EXPECT_EQ(false, profile.IsAnInvalidPhoneNumber(PHONE_HOME_WHOLE_NUMBER));
- EXPECT_EQ(false, profile.IsAnInvalidPhoneNumber(PHONE_BILLING_NUMBER));
- EXPECT_EQ(false,
- profile.IsAnInvalidPhoneNumber(PHONE_BILLING_WHOLE_NUMBER));
- }
-}
-
-TEST_P(AutofillProfileTest, ValidityStatesClients) {
- AutofillProfile profile;
-
- // The default validity state should be UNVALIDATED.
- EXPECT_EQ(AutofillDataModel::UNVALIDATED,
- profile.GetValidityState(ADDRESS_HOME_COUNTRY,
- AutofillDataModel::CLIENT));
-
- // Make sure setting the validity state works.
- profile.SetValidityState(ADDRESS_HOME_COUNTRY, AutofillDataModel::VALID,
- AutofillDataModel::CLIENT);
- profile.SetValidityState(ADDRESS_HOME_CITY, AutofillDataModel::INVALID,
- AutofillDataModel::CLIENT);
- profile.SetValidityState(ADDRESS_HOME_STATE, AutofillDataModel::EMPTY,
- AutofillDataModel::CLIENT);
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_COUNTRY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::INVALID,
- profile.GetValidityState(ADDRESS_HOME_CITY, AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::EMPTY,
- profile.GetValidityState(ADDRESS_HOME_STATE, AutofillDataModel::CLIENT));
- EXPECT_FALSE(profile.IsValidByClient());
-}
-
-TEST_P(AutofillProfileTest, ValidityStatesServer) {
- AutofillProfile profile;
- EXPECT_TRUE(test::GetFullProfile().IsValidByServer());
-
- // The default validity state should be UNVALIDATED.
- EXPECT_EQ(AutofillDataModel::UNVALIDATED,
- profile.GetValidityState(ADDRESS_HOME_COUNTRY,
- AutofillDataModel::SERVER));
-
- // Make sure setting the validity state works.
- profile.SetValidityState(ADDRESS_HOME_COUNTRY, AutofillDataModel::VALID,
- AutofillDataModel::SERVER);
- profile.SetValidityState(ADDRESS_HOME_CITY, AutofillDataModel::INVALID,
- AutofillDataModel::SERVER);
- profile.SetValidityState(ADDRESS_HOME_STATE, AutofillDataModel::EMPTY,
- AutofillDataModel::SERVER);
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_COUNTRY,
- AutofillDataModel::SERVER));
- EXPECT_EQ(
- AutofillDataModel::INVALID,
- profile.GetValidityState(ADDRESS_HOME_CITY, AutofillDataModel::SERVER));
- EXPECT_EQ(
- AutofillDataModel::EMPTY,
- profile.GetValidityState(ADDRESS_HOME_STATE, AutofillDataModel::SERVER));
- EXPECT_FALSE(profile.IsValidByServer());
-}
-
-TEST_P(AutofillProfileTest, ValidityStates_ClientUnsupportedTypes) {
- AutofillProfile profile;
-
- // The validity state of unsupported types should be UNSUPPORTED.
- EXPECT_EQ(
- AutofillDataModel::UNSUPPORTED,
- profile.GetValidityState(ADDRESS_HOME_LINE1, AutofillDataModel::CLIENT));
-
- // Make sure setting the validity state of an unsupported type does nothing.
- profile.SetValidityState(ADDRESS_HOME_LINE1, AutofillDataModel::VALID,
- AutofillDataModel::CLIENT);
- profile.SetValidityState(ADDRESS_HOME_LINE2, AutofillDataModel::INVALID,
- AutofillDataModel::CLIENT);
- profile.SetValidityState(PHONE_HOME_CITY_AND_NUMBER,
- AutofillDataModel::UNVALIDATED,
- AutofillDataModel::CLIENT);
- EXPECT_EQ(
- AutofillDataModel::UNSUPPORTED,
- profile.GetValidityState(ADDRESS_HOME_LINE1, AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::UNSUPPORTED,
- profile.GetValidityState(ADDRESS_HOME_LINE2, AutofillDataModel::CLIENT));
- EXPECT_EQ(AutofillDataModel::UNVALIDATED,
- profile.GetValidityState(PHONE_HOME_CITY_AND_NUMBER,
- AutofillDataModel::CLIENT));
-}
-
-TEST_P(AutofillProfileTest, GetClientValidityBitfieldValue_Country) {
- AutofillProfile profile;
-
- // By default all validity statuses should be set to UNVALIDATED, thus the
- // bitfield value should be empty.
- EXPECT_EQ(0, profile.GetClientValidityBitfieldValue());
-
- profile.SetValidityState(ADDRESS_HOME_COUNTRY, AutofillDataModel::EMPTY,
- AutofillDataModel::CLIENT);
- // 0b01
- EXPECT_EQ(1, profile.GetClientValidityBitfieldValue());
-
- profile.SetValidityState(ADDRESS_HOME_COUNTRY, AutofillDataModel::VALID,
- AutofillDataModel::CLIENT);
- // 0b10
- EXPECT_EQ(2, profile.GetClientValidityBitfieldValue());
-
- profile.SetValidityState(ADDRESS_HOME_COUNTRY, AutofillDataModel::INVALID,
- AutofillDataModel::CLIENT);
- // 0b11
- EXPECT_EQ(3, profile.GetClientValidityBitfieldValue());
-}
-
-TEST_P(AutofillProfileTest, GetClientValidityBitfieldValue_State) {
- AutofillProfile profile;
-
- // By default all validity statuses should be set to UNVALIDATED, thus the
- // bitfield value should be empty.
- EXPECT_EQ(0, profile.GetClientValidityBitfieldValue());
-
- profile.SetValidityState(ADDRESS_HOME_STATE, AutofillDataModel::EMPTY,
- AutofillDataModel::CLIENT);
- // 0b0100
- EXPECT_EQ(4, profile.GetClientValidityBitfieldValue());
-
- profile.SetValidityState(ADDRESS_HOME_STATE, AutofillDataModel::VALID,
- AutofillDataModel::CLIENT);
- // 0b1000
- EXPECT_EQ(8, profile.GetClientValidityBitfieldValue());
-
- profile.SetValidityState(ADDRESS_HOME_STATE, AutofillDataModel::INVALID,
- AutofillDataModel::CLIENT);
- // 0b1100
- EXPECT_EQ(12, profile.GetClientValidityBitfieldValue());
-}
-
-TEST_P(AutofillProfileTest, GetClientValidityBitfieldValue_Zip) {
- AutofillProfile profile;
-
- // By default all validity statuses should be set to UNVALIDATED, thus the
- // bitfield value should be empty.
- EXPECT_EQ(0, profile.GetClientValidityBitfieldValue());
-
- profile.SetValidityState(ADDRESS_HOME_ZIP, AutofillDataModel::EMPTY,
- AutofillDataModel::CLIENT);
- // 0b010000
- EXPECT_EQ(16, profile.GetClientValidityBitfieldValue());
-
- profile.SetValidityState(ADDRESS_HOME_ZIP, AutofillDataModel::VALID,
- AutofillDataModel::CLIENT);
- // 0b100000
- EXPECT_EQ(32, profile.GetClientValidityBitfieldValue());
-
- profile.SetValidityState(ADDRESS_HOME_ZIP, AutofillDataModel::INVALID,
- AutofillDataModel::CLIENT);
- // 0b110000
- EXPECT_EQ(48, profile.GetClientValidityBitfieldValue());
-}
-
-TEST_P(AutofillProfileTest, GetClientValidityBitfieldValue_City) {
- AutofillProfile profile;
-
- // By default all validity statuses should be set to UNVALIDATED, thus the
- // bitfield value should be empty.
- EXPECT_EQ(0, profile.GetClientValidityBitfieldValue());
-
- profile.SetValidityState(ADDRESS_HOME_CITY, AutofillDataModel::EMPTY,
- AutofillDataModel::CLIENT);
- // 0b01000000
- EXPECT_EQ(64, profile.GetClientValidityBitfieldValue());
-
- profile.SetValidityState(ADDRESS_HOME_CITY, AutofillDataModel::VALID,
- AutofillDataModel::CLIENT);
- // 0b10000000
- EXPECT_EQ(128, profile.GetClientValidityBitfieldValue());
-
- profile.SetValidityState(ADDRESS_HOME_CITY, AutofillDataModel::INVALID,
- AutofillDataModel::CLIENT);
- // 0b11000000
- EXPECT_EQ(192, profile.GetClientValidityBitfieldValue());
-}
-
-TEST_P(AutofillProfileTest, GetClientValidityBitfieldValue_DependentLocality) {
- AutofillProfile profile;
-
- // By default all validity statuses should be set to UNVALIDATED, thus the
- // bitfield value should be empty.
- EXPECT_EQ(0, profile.GetClientValidityBitfieldValue());
-
- profile.SetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
- AutofillDataModel::EMPTY, AutofillDataModel::CLIENT);
- // 0b0100000000
- EXPECT_EQ(256, profile.GetClientValidityBitfieldValue());
-
- profile.SetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
- AutofillDataModel::VALID, AutofillDataModel::CLIENT);
- // 0b1000000000
- EXPECT_EQ(512, profile.GetClientValidityBitfieldValue());
-
- profile.SetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
- AutofillDataModel::INVALID,
- AutofillDataModel::CLIENT);
- // 0b1100000000
- EXPECT_EQ(768, profile.GetClientValidityBitfieldValue());
-}
-
-TEST_P(AutofillProfileTest, GetClientValidityBitfieldValue_Email) {
- AutofillProfile profile;
-
- // By default all validity statuses should be set to UNVALIDATED, thus the
- // bitfield value should be empty.
- EXPECT_EQ(0, profile.GetClientValidityBitfieldValue());
-
- profile.SetValidityState(EMAIL_ADDRESS, AutofillDataModel::EMPTY,
- AutofillDataModel::CLIENT);
- // 0b010000000000
- EXPECT_EQ(1024, profile.GetClientValidityBitfieldValue());
-
- profile.SetValidityState(EMAIL_ADDRESS, AutofillDataModel::VALID,
- AutofillDataModel::CLIENT);
- // 0b100000000000
- EXPECT_EQ(2048, profile.GetClientValidityBitfieldValue());
-
- profile.SetValidityState(EMAIL_ADDRESS, AutofillDataModel::INVALID,
- AutofillDataModel::CLIENT);
- // 0b110000000000
- EXPECT_EQ(3072, profile.GetClientValidityBitfieldValue());
-}
-
-TEST_P(AutofillProfileTest, GetClientValidityBitfieldValue_Phone) {
- AutofillProfile profile;
-
- // By default all validity statuses should be set to UNVALIDATED, thus the
- // bitfield value should be empty.
- EXPECT_EQ(0, profile.GetClientValidityBitfieldValue());
-
- profile.SetValidityState(PHONE_HOME_WHOLE_NUMBER, AutofillDataModel::EMPTY,
- AutofillDataModel::CLIENT);
- // 0b01000000000000
- EXPECT_EQ(4096, profile.GetClientValidityBitfieldValue());
-
- profile.SetValidityState(PHONE_HOME_WHOLE_NUMBER, AutofillDataModel::VALID,
- AutofillDataModel::CLIENT);
- // 0b10000000000000
- EXPECT_EQ(8192, profile.GetClientValidityBitfieldValue());
-
- profile.SetValidityState(PHONE_HOME_WHOLE_NUMBER, AutofillDataModel::INVALID,
- AutofillDataModel::CLIENT);
- // 0b11000000000000
- EXPECT_EQ(12288, profile.GetClientValidityBitfieldValue());
-}
-
-TEST_P(AutofillProfileTest, GetClientValidityBitfieldValue_Mixed) {
- AutofillProfile profile;
-
- // By default all validity statuses should be set to UNVALIDATED, thus the
- // bitfield value should be empty.
- EXPECT_EQ(0, profile.GetClientValidityBitfieldValue());
-
- profile.SetValidityState(ADDRESS_HOME_COUNTRY, AutofillDataModel::VALID,
- AutofillDataModel::CLIENT);
- profile.SetValidityState(ADDRESS_HOME_STATE, AutofillDataModel::UNVALIDATED,
- AutofillDataModel::CLIENT);
- profile.SetValidityState(ADDRESS_HOME_ZIP, AutofillDataModel::EMPTY,
- AutofillDataModel::CLIENT);
- profile.SetValidityState(ADDRESS_HOME_CITY, AutofillDataModel::INVALID,
- AutofillDataModel::CLIENT);
- profile.SetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
- AutofillDataModel::UNVALIDATED,
- AutofillDataModel::CLIENT);
- profile.SetValidityState(EMAIL_ADDRESS, AutofillDataModel::INVALID,
- AutofillDataModel::CLIENT);
- profile.SetValidityState(PHONE_HOME_WHOLE_NUMBER, AutofillDataModel::EMPTY,
- AutofillDataModel::CLIENT);
- EXPECT_FALSE(profile.IsValidByClient());
- // 0b01110011010010
- EXPECT_EQ(7378, profile.GetClientValidityBitfieldValue());
-
- profile.SetValidityState(ADDRESS_HOME_COUNTRY, AutofillDataModel::EMPTY,
- AutofillDataModel::CLIENT);
- profile.SetValidityState(ADDRESS_HOME_STATE, AutofillDataModel::INVALID,
- AutofillDataModel::CLIENT);
- profile.SetValidityState(ADDRESS_HOME_ZIP, AutofillDataModel::VALID,
- AutofillDataModel::CLIENT);
- profile.SetValidityState(ADDRESS_HOME_CITY, AutofillDataModel::VALID,
- AutofillDataModel::CLIENT);
- profile.SetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
- AutofillDataModel::INVALID,
- AutofillDataModel::CLIENT);
- profile.SetValidityState(EMAIL_ADDRESS, AutofillDataModel::UNVALIDATED,
- AutofillDataModel::CLIENT);
- profile.SetValidityState(PHONE_HOME_WHOLE_NUMBER, AutofillDataModel::INVALID,
- AutofillDataModel::CLIENT);
- EXPECT_FALSE(profile.IsValidByClient());
- // 0b11001110101101
- EXPECT_EQ(13229, profile.GetClientValidityBitfieldValue());
-}
-
-TEST_P(AutofillProfileTest, SetClientValidityFromBitfieldValue_Country) {
- AutofillProfile profile;
-
- // By default all validity statuses should be set to UNVALIDATED, thus the
- // bitfield value should be empty.
- EXPECT_EQ(0, profile.GetClientValidityBitfieldValue());
- EXPECT_TRUE(profile.IsValidByClient());
-
- // 0b01
- profile.SetClientValidityFromBitfieldValue(1);
- EXPECT_EQ(AutofillDataModel::EMPTY,
- profile.GetValidityState(ADDRESS_HOME_COUNTRY,
- AutofillDataModel::CLIENT));
- EXPECT_TRUE(profile.IsValidByClient());
-
- // 0b10
- profile.SetClientValidityFromBitfieldValue(2);
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_COUNTRY,
- AutofillDataModel::CLIENT));
- EXPECT_TRUE(profile.IsValidByClient());
-
- // 0b11
- profile.SetClientValidityFromBitfieldValue(3);
- EXPECT_EQ(AutofillDataModel::INVALID,
- profile.GetValidityState(ADDRESS_HOME_COUNTRY,
- AutofillDataModel::CLIENT));
- EXPECT_FALSE(profile.IsValidByClient());
-}
-
-TEST_P(AutofillProfileTest, SetClientValidityFromBitfieldValue_State) {
- AutofillProfile profile;
-
- // By default all validity statuses should be set to UNVALIDATED, thus the
- // bitfield value should be empty.
- EXPECT_EQ(0, profile.GetClientValidityBitfieldValue());
- EXPECT_TRUE(profile.IsValidByClient());
-
- // 0b0100
- profile.SetClientValidityFromBitfieldValue(4);
- EXPECT_EQ(
- AutofillDataModel::EMPTY,
- profile.GetValidityState(ADDRESS_HOME_STATE, AutofillDataModel::CLIENT));
- EXPECT_TRUE(profile.IsValidByClient());
-
- // 0b1000
- profile.SetClientValidityFromBitfieldValue(8);
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_STATE, AutofillDataModel::CLIENT));
- EXPECT_TRUE(profile.IsValidByClient());
-
- // 0b1100
- profile.SetClientValidityFromBitfieldValue(12);
- EXPECT_EQ(
- AutofillDataModel::INVALID,
- profile.GetValidityState(ADDRESS_HOME_STATE, AutofillDataModel::CLIENT));
- EXPECT_FALSE(profile.IsValidByClient());
-}
-
-TEST_P(AutofillProfileTest, SetClientValidityFromBitfieldValue_Zip) {
- AutofillProfile profile;
-
- // By default all validity statuses should be set to UNVALIDATED, thus the
- // bitfield value should be empty.
- EXPECT_EQ(0, profile.GetClientValidityBitfieldValue());
- EXPECT_TRUE(profile.IsValidByClient());
-
- // 0b010000
- profile.SetClientValidityFromBitfieldValue(16);
- EXPECT_EQ(
- AutofillDataModel::EMPTY,
- profile.GetValidityState(ADDRESS_HOME_ZIP, AutofillDataModel::CLIENT));
- EXPECT_TRUE(profile.IsValidByClient());
-
- // 0b100000
- profile.SetClientValidityFromBitfieldValue(32);
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_ZIP, AutofillDataModel::CLIENT));
- EXPECT_TRUE(profile.IsValidByClient());
-
- // 0b110000
- profile.SetClientValidityFromBitfieldValue(48);
- EXPECT_EQ(
- AutofillDataModel::INVALID,
- profile.GetValidityState(ADDRESS_HOME_ZIP, AutofillDataModel::CLIENT));
- EXPECT_FALSE(profile.IsValidByClient());
-}
-
-TEST_P(AutofillProfileTest, SetClientValidityFromBitfieldValue_City) {
- AutofillProfile profile;
-
- // By default all validity statuses should be set to UNVALIDATED, thus the
- // bitfield value should be empty.
- EXPECT_EQ(0, profile.GetClientValidityBitfieldValue());
- EXPECT_TRUE(profile.IsValidByClient());
-
- // 0b01000000
- profile.SetClientValidityFromBitfieldValue(64);
- EXPECT_EQ(
- AutofillDataModel::EMPTY,
- profile.GetValidityState(ADDRESS_HOME_CITY, AutofillDataModel::CLIENT));
- EXPECT_TRUE(profile.IsValidByClient());
-
- // 0b10000000
- profile.SetClientValidityFromBitfieldValue(128);
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_CITY, AutofillDataModel::CLIENT));
- EXPECT_TRUE(profile.IsValidByClient());
-
- // 0b11000000
- profile.SetClientValidityFromBitfieldValue(192);
- EXPECT_EQ(
- AutofillDataModel::INVALID,
- profile.GetValidityState(ADDRESS_HOME_CITY, AutofillDataModel::CLIENT));
- EXPECT_FALSE(profile.IsValidByClient());
-}
-
-TEST(AutofillProfileTest,
- SetClientValidityFromBitfieldValue_DependentLocality) {
- AutofillProfile profile;
-
- // By default all validity statuses should be set to UNVALIDATED, thus the
- // bitfield value should be empty.
- EXPECT_EQ(0, profile.GetClientValidityBitfieldValue());
- EXPECT_TRUE(profile.IsValidByClient());
-
- // 0b0100000000
- profile.SetClientValidityFromBitfieldValue(256);
- EXPECT_EQ(AutofillDataModel::EMPTY,
- profile.GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
- AutofillDataModel::CLIENT));
- EXPECT_TRUE(profile.IsValidByClient());
-
- // 0b1000000000
- profile.SetClientValidityFromBitfieldValue(512);
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
- AutofillDataModel::CLIENT));
- EXPECT_TRUE(profile.IsValidByClient());
-
- // 0b1100000000
- profile.SetClientValidityFromBitfieldValue(768);
- EXPECT_EQ(AutofillDataModel::INVALID,
- profile.GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
- AutofillDataModel::CLIENT));
- EXPECT_FALSE(profile.IsValidByClient());
-}
-
// Test that the label is correctly set and retrieved from the profile.
TEST_P(AutofillProfileTest, SetAndGetProfileLabels) {
AutofillProfile p;
@@ -2139,120 +1593,6 @@ TEST_P(AutofillProfileTest, LockStateInAssignmentAndComparisonOperator) {
EXPECT_NE(p1, p2);
}
-TEST_P(AutofillProfileTest, SetClientValidityFromBitfieldValue_Email) {
- AutofillProfile profile;
-
- // By default all validity statuses should be set to UNVALIDATED, thus the
- // bitfield value should be empty.
- EXPECT_EQ(0, profile.GetClientValidityBitfieldValue());
- EXPECT_TRUE(profile.IsValidByClient());
-
- // 0b010000000000
- profile.SetClientValidityFromBitfieldValue(1024);
- EXPECT_EQ(AutofillDataModel::EMPTY,
- profile.GetValidityState(EMAIL_ADDRESS, AutofillDataModel::CLIENT));
- EXPECT_TRUE(profile.IsValidByClient());
-
- // 0b100000000000
- profile.SetClientValidityFromBitfieldValue(2048);
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(EMAIL_ADDRESS, AutofillDataModel::CLIENT));
- EXPECT_TRUE(profile.IsValidByClient());
-
- // 0b110000000000
- profile.SetClientValidityFromBitfieldValue(3072);
- EXPECT_EQ(AutofillDataModel::INVALID,
- profile.GetValidityState(EMAIL_ADDRESS, AutofillDataModel::CLIENT));
- EXPECT_FALSE(profile.IsValidByClient());
-}
-
-TEST_P(AutofillProfileTest, SetClientValidityFromBitfieldValue_Phone) {
- AutofillProfile profile;
-
- // By default all validity statuses should be set to UNVALIDATED, thus the
- // bitfield value should be empty.
- EXPECT_EQ(0, profile.GetClientValidityBitfieldValue());
- EXPECT_TRUE(profile.IsValidByClient());
-
- // 0b01000000000000
- profile.SetClientValidityFromBitfieldValue(4096);
- EXPECT_EQ(AutofillDataModel::EMPTY,
- profile.GetValidityState(PHONE_HOME_WHOLE_NUMBER,
- AutofillDataModel::CLIENT));
- EXPECT_TRUE(profile.IsValidByClient());
-
- // 0b10000000000000
- profile.SetClientValidityFromBitfieldValue(8192);
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(PHONE_HOME_WHOLE_NUMBER,
- AutofillDataModel::CLIENT));
- EXPECT_TRUE(profile.IsValidByClient());
-
- // 0b11000000000000
- profile.SetClientValidityFromBitfieldValue(12288);
- EXPECT_EQ(AutofillDataModel::INVALID,
- profile.GetValidityState(PHONE_HOME_WHOLE_NUMBER,
- AutofillDataModel::CLIENT));
- EXPECT_FALSE(profile.IsValidByClient());
-}
-
-TEST_P(AutofillProfileTest, SetClientValidityFromBitfieldValue_Mixed) {
- AutofillProfile profile;
-
- // By default all validity statuses should be set to UNVALIDATED, thus the
- // bitfield value should be empty.
- EXPECT_EQ(0, profile.GetClientValidityBitfieldValue());
-
- // 0b01110011010010
- profile.SetClientValidityFromBitfieldValue(7378);
- EXPECT_EQ(AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_COUNTRY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::UNVALIDATED,
- profile.GetValidityState(ADDRESS_HOME_STATE, AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::EMPTY,
- profile.GetValidityState(ADDRESS_HOME_ZIP, AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::INVALID,
- profile.GetValidityState(ADDRESS_HOME_CITY, AutofillDataModel::CLIENT));
- EXPECT_EQ(AutofillDataModel::UNVALIDATED,
- profile.GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(AutofillDataModel::INVALID,
- profile.GetValidityState(EMAIL_ADDRESS, AutofillDataModel::CLIENT));
- EXPECT_EQ(AutofillDataModel::EMPTY,
- profile.GetValidityState(PHONE_HOME_WHOLE_NUMBER,
- AutofillDataModel::CLIENT));
-
- EXPECT_FALSE(profile.IsValidByClient());
-
- // 0b11001110101101
- profile.SetClientValidityFromBitfieldValue(13229);
- EXPECT_EQ(AutofillDataModel::EMPTY,
- profile.GetValidityState(ADDRESS_HOME_COUNTRY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::INVALID,
- profile.GetValidityState(ADDRESS_HOME_STATE, AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_ZIP, AutofillDataModel::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profile.GetValidityState(ADDRESS_HOME_CITY, AutofillDataModel::CLIENT));
- EXPECT_EQ(AutofillDataModel::INVALID,
- profile.GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
- AutofillDataModel::CLIENT));
- EXPECT_EQ(AutofillDataModel::UNVALIDATED,
- profile.GetValidityState(EMAIL_ADDRESS, AutofillDataModel::CLIENT));
- EXPECT_EQ(AutofillDataModel::INVALID,
- profile.GetValidityState(PHONE_HOME_WHOLE_NUMBER,
- AutofillDataModel::CLIENT));
- EXPECT_FALSE(profile.IsValidByClient());
-}
-
TEST_P(AutofillProfileTest, GetMetadata) {
AutofillProfile local_profile = test::GetFullProfile();
local_profile.set_use_count(2);
@@ -2351,69 +1691,6 @@ TEST_P(AutofillProfileTest, IsDeletable) {
EXPECT_FALSE(profile.IsDeletable());
}
-// Tests that the two profiles can be compared for validation purposes.
-TEST_P(AutofillProfileTest, EqualsForClientValidationPurpose) {
- AutofillProfile profile = test::GetFullProfile();
-
- AutofillProfile profile2(profile);
- profile2.SetRawInfo(EMAIL_ADDRESS, u"different@email.com");
-
- AutofillProfile profile3(profile);
- profile3.SetRawInfo(NAME_FULL, u"Alice Munro");
-
- // For client validation purposes,
- // profile2 != profile, because they differ in the email, which is validated
- // by the client.
- // profile3 == profile, because they only differ in name, and name is not
- // validated by the client.
- EXPECT_FALSE(profile.EqualsForClientValidationPurpose(profile2));
- EXPECT_TRUE(profile.EqualsForClientValidationPurpose(profile3));
-}
-
-// Tests that the skip decision is made correctly.
-TEST_P(AutofillProfileTest, ShouldSkipFillingOrSuggesting) {
- base::test::ScopedFeatureList scoped_features;
- scoped_features.InitWithFeatures(
- /*enabled_features=*/{features::kAutofillProfileServerValidation,
- features::kAutofillProfileClientValidation},
- /*disabled_features=*/{});
-
- AutofillProfile profile = test::GetFullProfile();
- profile.SetValidityState(ADDRESS_HOME_STATE, AutofillProfile::VALID,
- AutofillProfile::SERVER);
- profile.SetValidityState(ADDRESS_HOME_CITY, AutofillProfile::VALID,
- AutofillProfile::CLIENT);
- profile.SetValidityState(ADDRESS_HOME_LINE1, AutofillProfile::UNSUPPORTED,
- AutofillProfile::CLIENT);
-
- EXPECT_FALSE(profile.ShouldSkipFillingOrSuggesting(ADDRESS_HOME_CITY));
- EXPECT_FALSE(profile.ShouldSkipFillingOrSuggesting(ADDRESS_HOME_STATE));
- EXPECT_FALSE(profile.ShouldSkipFillingOrSuggesting(ADDRESS_HOME_COUNTRY));
- EXPECT_FALSE(profile.ShouldSkipFillingOrSuggesting(ADDRESS_HOME_LINE1));
- EXPECT_FALSE(profile.ShouldSkipFillingOrSuggesting(EMAIL_ADDRESS));
-
- profile.SetValidityState(EMAIL_ADDRESS, AutofillProfile::INVALID,
- AutofillProfile::CLIENT);
- profile.SetValidityState(ADDRESS_HOME_STATE, AutofillProfile::INVALID,
- AutofillProfile::SERVER);
- profile.SetValidityState(ADDRESS_HOME_CITY, AutofillProfile::INVALID,
- AutofillProfile::CLIENT);
-
- profile.SetRawInfo(ADDRESS_HOME_COUNTRY, u"");
- EXPECT_FALSE(profile.ShouldSkipFillingOrSuggesting(ADDRESS_HOME_CITY));
- EXPECT_TRUE(profile.ShouldSkipFillingOrSuggesting(ADDRESS_HOME_STATE));
- EXPECT_FALSE(profile.ShouldSkipFillingOrSuggesting(ADDRESS_HOME_COUNTRY));
- EXPECT_FALSE(profile.ShouldSkipFillingOrSuggesting(ADDRESS_HOME_LINE1));
- EXPECT_TRUE(profile.ShouldSkipFillingOrSuggesting(EMAIL_ADDRESS));
-
- profile.SetRawInfo(ADDRESS_HOME_COUNTRY, u"CA");
- EXPECT_TRUE(profile.ShouldSkipFillingOrSuggesting(ADDRESS_HOME_CITY));
- EXPECT_TRUE(profile.ShouldSkipFillingOrSuggesting(ADDRESS_HOME_STATE));
- EXPECT_FALSE(profile.ShouldSkipFillingOrSuggesting(ADDRESS_HOME_COUNTRY));
- EXPECT_FALSE(profile.ShouldSkipFillingOrSuggesting(ADDRESS_HOME_LINE1));
- EXPECT_TRUE(profile.ShouldSkipFillingOrSuggesting(EMAIL_ADDRESS));
-}
-
// Tests that the |HasStructuredData| returns whether the profile has structured
// data or not.
TEST_P(AutofillProfileTest, HasStructuredData) {
@@ -2430,149 +1707,6 @@ TEST_P(AutofillProfileTest, HasStructuredData) {
enum Expectation { GREATER, LESS, EQUAL };
-struct HasGreaterFrescocencyTestCase {
- const AutofillDataModel::ValidityState client_validity_state_a;
- const AutofillDataModel::ValidityState server_validity_state_a;
- const AutofillDataModel::ValidityState client_validity_state_b;
- const AutofillDataModel::ValidityState server_validity_state_b;
-
- const bool use_client_validation;
- const bool use_server_validation;
- Expectation expectation;
-};
-
-class HasGreaterFrescocencyTest
- : public testing::TestWithParam<HasGreaterFrescocencyTestCase> {};
-
-TEST_P(HasGreaterFrescocencyTest, HasGreaterFrescocency) {
- auto test_case = GetParam();
- AutofillProfile profile_a("00000000-0000-0000-0000-000000000001", "");
- AutofillProfile profile_b("00000000-0000-0000-0000-000000000002", "");
-
- profile_a.SetValidityState(EMAIL_ADDRESS, test_case.client_validity_state_a,
- AutofillDataModel::CLIENT);
- profile_a.SetValidityState(ADDRESS_HOME_ZIP,
- test_case.server_validity_state_a,
- AutofillDataModel::SERVER);
-
- profile_b.SetValidityState(ADDRESS_HOME_CITY,
- test_case.client_validity_state_b,
- AutofillDataModel::CLIENT);
- profile_b.SetValidityState(PHONE_HOME_NUMBER,
- test_case.server_validity_state_b,
- AutofillDataModel::SERVER);
-
- const base::Time now = AutofillClock::Now();
-
- if (test_case.expectation == EQUAL) {
- EXPECT_EQ(profile_a.HasGreaterFrecencyThan(&profile_b, now),
- profile_a.HasGreaterFrescocencyThan(
- &profile_b, now, test_case.use_client_validation,
- test_case.use_server_validation));
- return;
- }
-
- EXPECT_EQ(test_case.expectation == GREATER,
- profile_a.HasGreaterFrescocencyThan(
- &profile_b, now, test_case.use_client_validation,
- test_case.use_server_validation));
- EXPECT_NE(test_case.expectation == GREATER,
- profile_b.HasGreaterFrescocencyThan(
- &profile_a, now, test_case.use_client_validation,
- test_case.use_server_validation));
-}
-
-// Validity is only checked in case of tie in frecency. Frecency has greater
-// priority than validity in frescocency.
-TEST_P(HasGreaterFrescocencyTest, PriorityCheck) {
- AutofillProfile profile_invalid("00000000-0000-0000-0000-000000000001", "");
- AutofillProfile profile_valid("00000000-0000-0000-0000-000000000002", "");
-
- profile_invalid.SetValidityState(EMAIL_ADDRESS, AutofillDataModel::INVALID,
- AutofillDataModel::CLIENT);
- profile_valid.SetValidityState(ADDRESS_HOME_ZIP, AutofillDataModel::INVALID,
- AutofillDataModel::SERVER);
-
- profile_valid.SetValidityState(ADDRESS_HOME_CITY, AutofillDataModel::VALID,
- AutofillDataModel::CLIENT);
- profile_valid.SetValidityState(PHONE_HOME_NUMBER, AutofillDataModel::VALID,
- AutofillDataModel::SERVER);
-
- profile_invalid.set_use_count(100);
- profile_valid.set_use_count(10);
-
- const base::Time now = AutofillClock::Now();
- const base::Time past = now - base::Days(1);
-
- profile_invalid.set_use_date(now);
- profile_valid.set_use_date(past);
-
- EXPECT_TRUE(profile_invalid.HasGreaterFrecencyThan(&profile_valid, now));
- EXPECT_TRUE(profile_invalid.HasGreaterFrescocencyThan(&profile_valid, now,
- true, true));
-}
-
-INSTANTIATE_TEST_SUITE_P(
- AutofillProfileTest,
- HasGreaterFrescocencyTest,
- testing::Values(
- HasGreaterFrescocencyTestCase{
- AutofillDataModel::VALID, AutofillDataModel::INVALID,
- AutofillDataModel::VALID, AutofillDataModel::UNVALIDATED, false,
- false, EQUAL},
- HasGreaterFrescocencyTestCase{
- AutofillDataModel::INVALID, AutofillDataModel::VALID,
- AutofillDataModel::VALID, AutofillDataModel::INVALID, false, false,
- EQUAL},
- HasGreaterFrescocencyTestCase{
- AutofillDataModel::INVALID, AutofillDataModel::VALID,
- AutofillDataModel::VALID, AutofillDataModel::INVALID, false, true,
- GREATER},
- HasGreaterFrescocencyTestCase{
- AutofillDataModel::INVALID, AutofillDataModel::INVALID,
- AutofillDataModel::VALID, AutofillDataModel::INVALID, false, true,
- EQUAL},
- HasGreaterFrescocencyTestCase{
- AutofillDataModel::INVALID, AutofillDataModel::VALID,
- AutofillDataModel::VALID, AutofillDataModel::VALID, false, true,
- EQUAL},
- HasGreaterFrescocencyTestCase{
- AutofillDataModel::INVALID, AutofillDataModel::INVALID,
- AutofillDataModel::VALID, AutofillDataModel::UNVALIDATED, false,
- true, LESS},
- HasGreaterFrescocencyTestCase{
- AutofillDataModel::INVALID, AutofillDataModel::VALID,
- AutofillDataModel::VALID, AutofillDataModel::INVALID, true, true,
- EQUAL},
- HasGreaterFrescocencyTestCase{
- AutofillDataModel::INVALID, AutofillDataModel::INVALID,
- AutofillDataModel::UNVALIDATED, AutofillDataModel::VALID, true,
- true, LESS},
- HasGreaterFrescocencyTestCase{
- AutofillDataModel::VALID, AutofillDataModel::VALID,
- AutofillDataModel::VALID, AutofillDataModel::VALID, true, true,
- EQUAL},
- HasGreaterFrescocencyTestCase{
- AutofillDataModel::VALID, AutofillDataModel::UNVALIDATED,
- AutofillDataModel::VALID, AutofillDataModel::INVALID, true, true,
- GREATER},
- HasGreaterFrescocencyTestCase{
- AutofillDataModel::VALID, AutofillDataModel::INVALID,
- AutofillDataModel::INVALID, AutofillDataModel::VALID, true, false,
- GREATER},
- HasGreaterFrescocencyTestCase{
- AutofillDataModel::INVALID, AutofillDataModel::INVALID,
- AutofillDataModel::UNVALIDATED, AutofillDataModel::VALID, true,
- false, LESS},
- HasGreaterFrescocencyTestCase{
- AutofillDataModel::VALID, AutofillDataModel::INVALID,
- AutofillDataModel::VALID, AutofillDataModel::VALID, true, false,
- EQUAL},
- HasGreaterFrescocencyTestCase{
- AutofillDataModel::VALID, AutofillDataModel::UNVALIDATED,
- AutofillDataModel::INVALID, AutofillDataModel::INVALID, true, false,
- GREATER}));
-
INSTANTIATE_TEST_SUITE_P(All, AutofillProfileTest, testing::Bool());
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/data_model/autofill_structured_address_regex_provider.cc b/chromium/components/autofill/core/browser/data_model/autofill_structured_address_regex_provider.cc
index 82aab62d170..58036086fb8 100644
--- a/chromium/components/autofill/core/browser/data_model/autofill_structured_address_regex_provider.cc
+++ b/chromium/components/autofill/core/browser/data_model/autofill_structured_address_regex_provider.cc
@@ -6,6 +6,7 @@
#include <utility>
+#include "base/no_destructor.h"
#include "base/strings/strcat.h"
#include "components/autofill/core/browser/data_model/autofill_structured_address_constants.h"
#include "components/autofill/core/browser/data_model/autofill_structured_address_utils.h"
diff --git a/chromium/components/autofill/core/browser/data_model/autofill_structured_address_utils.cc b/chromium/components/autofill/core/browser/data_model/autofill_structured_address_utils.cc
index 3fe9d8eaec5..4ca9616ac4e 100644
--- a/chromium/components/autofill/core/browser/data_model/autofill_structured_address_utils.cc
+++ b/chromium/components/autofill/core/browser/data_model/autofill_structured_address_utils.cc
@@ -15,6 +15,7 @@
#include "base/feature_list.h"
#include "base/i18n/case_conversion.h"
#include "base/i18n/char_iterator.h"
+#include "base/no_destructor.h"
#include "base/strings/strcat.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_split.h"
diff --git a/chromium/components/autofill/core/browser/data_model/credit_card.cc b/chromium/components/autofill/core/browser/data_model/credit_card.cc
index 5cd27b35b94..50029fb3c79 100644
--- a/chromium/components/autofill/core/browser/data_model/credit_card.cc
+++ b/chromium/components/autofill/core/browser/data_model/credit_card.cc
@@ -49,14 +49,7 @@ using structured_address::VerificationStatus;
// - \u2022 - Bullet.
// - \u2006 - SIX-PER-EM SPACE (small space between bullets).
// - \u2060 - WORD-JOINER (makes obfuscated string undivisible).
-constexpr char16_t kMidlineEllipsis4Dots[] =
- u"\u2022\u2060\u2006\u2060"
- u"\u2022\u2060\u2006\u2060"
- u"\u2022\u2060\u2006\u2060"
- u"\u2022\u2060\u2006\u2060";
-constexpr char16_t kMidlineEllipsis2Dots[] =
- u"\u2022\u2060\u2006\u2060"
- u"\u2022\u2060\u2006\u2060";
+constexpr char16_t kMidlineEllipsisDot[] = u"\u2022\u2060\u2006\u2060";
constexpr char16_t kMidlineEllipsisPlainDot = u'\u2022';
namespace {
@@ -141,11 +134,9 @@ namespace internal {
std::u16string GetObfuscatedStringForCardDigits(const std::u16string& digits,
int obfuscation_length) {
- DCHECK(obfuscation_length == 2 || obfuscation_length == 4);
std::u16string obfuscated_string =
- std::u16string(obfuscation_length == 2 ? kMidlineEllipsis2Dots
- : kMidlineEllipsis4Dots) +
- digits;
+ CreditCard::GetMidlineEllipsisDots(obfuscation_length);
+ obfuscated_string.append(digits);
base::i18n::WrapStringWithLTRFormatting(&obfuscated_string);
return obfuscated_string;
}
@@ -168,6 +159,13 @@ CreditCard::CreditCard(RecordType type, const std::string& server_id)
server_id_ = server_id;
}
+CreditCard::CreditCard(RecordType type, const int64_t& instrument_id)
+ : CreditCard() {
+ DCHECK(type == MASKED_SERVER_CARD || type == FULL_SERVER_CARD);
+ record_type_ = type;
+ instrument_id_ = instrument_id;
+}
+
CreditCard::CreditCard() : CreditCard(base::GenerateGUID(), std::string()) {}
CreditCard::CreditCard(const CreditCard& credit_card) : CreditCard() {
@@ -366,6 +364,18 @@ bool CreditCard::IsNicknameValid(const std::u16string& nickname) {
return true;
}
+// static
+std::u16string CreditCard::GetMidlineEllipsisDots(size_t num_dots) {
+ DCHECK(num_dots > 0);
+ std::u16string dots;
+ dots.reserve(sizeof(kMidlineEllipsisDot) * num_dots);
+
+ for (size_t i = 0; i < num_dots; i++) {
+ dots.append(kMidlineEllipsisDot);
+ }
+ return dots;
+}
+
void CreditCard::SetNetworkForMaskedCard(base::StringPiece network) {
DCHECK_EQ(MASKED_SERVER_CARD, record_type());
network_ = std::string(network);
@@ -939,7 +949,7 @@ std::u16string CreditCard::CardIdentifierStringForAutofillDisplay(
return networkAndLastFourDigits;
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
std::u16string CreditCard::CardIdentifierStringForManualFilling() const {
std::u16string obfuscated_number = ObfuscatedLastFourDigits();
if (record_type_ == VIRTUAL_CARD) {
@@ -949,7 +959,7 @@ std::u16string CreditCard::CardIdentifierStringForManualFilling() const {
}
return obfuscated_number;
}
-#endif // OS_ANDROID
+#endif // BUILDFLAG(IS_ANDROID)
std::u16string CreditCard::CardIdentifierStringAndDescriptiveExpiration(
const std::string& app_locale,
diff --git a/chromium/components/autofill/core/browser/data_model/credit_card.h b/chromium/components/autofill/core/browser/data_model/credit_card.h
index 922ef946851..a8a3592423b 100644
--- a/chromium/components/autofill/core/browser/data_model/credit_card.h
+++ b/chromium/components/autofill/core/browser/data_model/credit_card.h
@@ -9,7 +9,6 @@
#include <string>
#include <utility>
-#include "base/compiler_specific.h"
#include "base/gtest_prod_util.h"
#include "base/strings/string_piece_forward.h"
#include "build/build_config.h"
@@ -21,8 +20,7 @@ namespace autofill {
struct AutofillMetadata;
// A midline horizontal ellipsis (U+22EF).
-extern const char16_t kMidlineEllipsis4Dots[];
-extern const char16_t kMidlineEllipsis2Dots[];
+extern const char16_t kMidlineEllipsisDot[];
namespace internal {
@@ -67,23 +65,33 @@ class CreditCard : public AutofillDataModel {
};
// Whether the card has been enrolled in the virtual card feature. This must
- // stay in sync with the proto enum in autofill_specifics.proto.
+ // stay in sync with the proto enum in autofill_specifics.proto. A java
+ // IntDef@ is generated from this.
+ // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.components.autofill
enum VirtualCardEnrollmentState {
// State unspecified. This is the default value of this enum. Should not be
// ever used with cards.
UNSPECIFIED = 0,
- // Card is not enrolled and does not have related virtual card.
+ // Deprecated. Card is not enrolled and does not have related virtual card.
UNENROLLED = 1,
// Card is enrolled and has related virtual cards.
ENROLLED = 2,
+ // Card is not enrolled and is not eligible for enrollment.
+ UNENROLLED_AND_NOT_ELIGIBLE = 3,
+ // Card is not enrolled but is eligible for enrollment.
+ UNENROLLED_AND_ELIGIBLE = 4,
};
CreditCard(const std::string& guid, const std::string& origin);
- // Creates a server card. The type must be MASKED_SERVER_CARD or
+ // Creates a server card. The type must be MASKED_SERVER_CARD or
// FULL_SERVER_CARD.
CreditCard(RecordType type, const std::string& server_id);
+ // Creates a server card with non-legacy instrument id. The type must be
+ // MASKED_SERVER_CARD or FULL_SERVER_CARD.
+ CreditCard(RecordType type, const int64_t& instrument_id);
+
// For use in STL containers.
CreditCard();
CreditCard(const CreditCard& credit_card);
@@ -112,6 +120,9 @@ class CreditCard : public AutofillDataModel {
// because they are not required.
static bool IsNicknameValid(const std::u16string& nickname);
+ // Returns string of dots for hidden card information.
+ static std::u16string GetMidlineEllipsisDots(size_t num_dots);
+
// Network issuer strings are defined at the bottom of this file, e.g.
// kVisaCard.
void SetNetworkForMaskedCard(base::StringPiece network);
@@ -177,8 +188,8 @@ class CreditCard : public AutofillDataModel {
// two wouldn't result in unverified data overwriting verified data,
// overwrites |this| card's data with the data in |imported_card|. Returns
// true if the card numbers match, false otherwise.
- bool UpdateFromImportedCard(const CreditCard& imported_card,
- const std::string& app_locale) WARN_UNUSED_RESULT;
+ [[nodiscard]] bool UpdateFromImportedCard(const CreditCard& imported_card,
+ const std::string& app_locale);
// Comparison for Sync. Returns 0 if the card is the same as |this|, or < 0,
// or > 0 if it is different. The implied ordering can be used for culling
@@ -296,10 +307,10 @@ class CreditCard : public AutofillDataModel {
std::u16string customized_nickname = std::u16string(),
int obfuscation_length = 4) const;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Label for the card to be displayed in the manual filling view on Android.
std::u16string CardIdentifierStringForManualFilling() const;
-#endif // OS_ANDROID
+#endif // BUILDFLAG(IS_ANDROID)
// A label for this card formatted as 'Nickname - ****2345, expires on MM/YY'
// if nickname experiment is turned on and nickname is available; otherwise,
@@ -356,6 +367,8 @@ class CreditCard : public AutofillDataModel {
}
private:
+ friend class CreditCardTestApi;
+
FRIEND_TEST_ALL_PREFIXES(CreditCardTest, SetExpirationDateFromString);
FRIEND_TEST_ALL_PREFIXES(CreditCardTest, SetExpirationYearFromString);
diff --git a/chromium/components/autofill/core/browser/data_model/credit_card_test_api.h b/chromium/components/autofill/core/browser/data_model/credit_card_test_api.h
new file mode 100644
index 00000000000..52a35c75fc0
--- /dev/null
+++ b/chromium/components/autofill/core/browser/data_model/credit_card_test_api.h
@@ -0,0 +1,29 @@
+// Copyright 2021 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.
+
+#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_DATA_MODEL_CREDIT_CARD_TEST_API_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_DATA_MODEL_CREDIT_CARD_TEST_API_H_
+
+#include "components/autofill/core/browser/data_model/credit_card.h"
+
+namespace autofill {
+
+// Exposes some testing operations for CreditCard.
+class CreditCardTestApi {
+ public:
+ explicit CreditCardTestApi(CreditCard* creditcard) : creditcard_(creditcard) {
+ DCHECK(creditcard_);
+ }
+ void set_network_for_virtual_card(base::StringPiece network) {
+ DCHECK_EQ(CreditCard::VIRTUAL_CARD, creditcard_->record_type());
+ creditcard_->network_ = std::string(network);
+ }
+
+ private:
+ CreditCard* creditcard_;
+};
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_DATA_MODEL_CREDIT_CARD_TEST_API_H_ \ No newline at end of file
diff --git a/chromium/components/autofill/core/browser/data_model/credit_card_unittest.cc b/chromium/components/autofill/core/browser/data_model/credit_card_unittest.cc
index aa75e67fb3b..580a8bbd19c 100644
--- a/chromium/components/autofill/core/browser/data_model/credit_card_unittest.cc
+++ b/chromium/components/autofill/core/browser/data_model/credit_card_unittest.cc
@@ -93,7 +93,8 @@ TEST(CreditCardTest, GetObfuscatedStringForCardDigits) {
const std::u16string digits = u"1235";
const std::u16string expected =
std::u16string() + base::i18n::kLeftToRightEmbeddingMark +
- kMidlineEllipsis4Dots + digits + base::i18n::kPopDirectionalFormatting;
+ CreditCard::GetMidlineEllipsisDots(4) + digits +
+ base::i18n::kPopDirectionalFormatting;
EXPECT_EQ(expected, internal::GetObfuscatedStringForCardDigits(
digits, /*obfuscation_length=*/4));
}
@@ -1845,7 +1846,7 @@ INSTANTIATE_TEST_SUITE_P(
ShouldUpdateExpirationTestCase{false, kOneYear,
CreditCard::FULL_SERVER_CARD}));
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
class CreditCardTestForKeyboardAccessory : public testing::Test {
public:
void SetUp() override {
@@ -1861,11 +1862,12 @@ TEST_F(CreditCardTestForKeyboardAccessory, GetObfuscatedStringForCardDigits) {
const std::u16string digits = u"1235";
const std::u16string expected =
std::u16string() + base::i18n::kLeftToRightEmbeddingMark +
- kMidlineEllipsis2Dots + digits + base::i18n::kPopDirectionalFormatting;
+ CreditCard::GetMidlineEllipsisDots(2) + digits +
+ base::i18n::kPopDirectionalFormatting;
EXPECT_EQ(expected, internal::GetObfuscatedStringForCardDigits(
digits, /*obfuscation_length=*/2));
}
-#endif // OS_ANDROID
+#endif // BUILDFLAG(IS_ANDROID)
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/field_filler.cc b/chromium/components/autofill/core/browser/field_filler.cc
index 61e06c9eb34..a2931e766f8 100644
--- a/chromium/components/autofill/core/browser/field_filler.cc
+++ b/chromium/components/autofill/core/browser/field_filler.cc
@@ -497,9 +497,9 @@ bool FillCreditCardTypeSelectControl(const std::u16string& value,
return false;
}
-// Return the appropriate credit card number from |credit_card|. Truncates the
+// Returns the appropriate credit card number from |credit_card|. Truncates the
// credit card number to be split across HTML form input fields depending on if
-// |field.credit_card_number_offset()| is less than the length of the credit
+// 'field.credit_card_number_offset()' is less than the length of the credit
// card number.
std::u16string GetCreditCardNumberForInput(
const CreditCard& credit_card,
@@ -517,7 +517,9 @@ std::u16string GetCreditCardNumberForInput(
field.max_length >= credit_card.ObfuscatedLastFourDigits().length()));
// If previewing a credit card number that needs to be split, pad the number
- // to 16 digits rather than displaying a fancy string with RTL support.
+ // to 16 digits rather than displaying a fancy string with RTL support. This
+ // also returns 16 digits if there is only one field and it cannot fit the
+ // longer version CC number.
value = is_single_field
? credit_card.ObfuscatedLastFourDigits()
: credit_card.ObfuscatedLastFourDigitsForSplitFields();
@@ -537,6 +539,40 @@ std::u16string GetCreditCardNumberForInput(
return value;
}
+// Returns the appropriate credit card number from |virtual_card|. Truncates the
+// credit card number to be split across HTML form input fields depending on if
+// 'field.credit_card_number_offset()' is less than the length of the credit
+// card number.
+std::u16string GetVirtualCardNumberForPreviewInput(
+ const CreditCard& virtual_card,
+ const AutofillField& field) {
+ std::u16string value =
+ l10n_util::GetStringUTF16(
+ IDS_AUTOFILL_VIRTUAL_CARD_SUGGESTION_OPTION_VALUE) +
+ u" " + virtual_card.CardIdentifierStringForAutofillDisplay();
+
+ // |field|'s max_length truncates the credit card number to fit within.
+ if (field.credit_card_number_offset() < value.length()) {
+ // A single field is detected when the offset begins at 0 and the field's
+ // max_length can hold the entire obfuscated credit card number.
+ bool is_single_field =
+ (field.credit_card_number_offset() == 0 &&
+ (field.max_length == 0 || field.max_length >= value.length()));
+
+ if (!is_single_field)
+ value = virtual_card.ObfuscatedLastFourDigitsForSplitFields();
+
+ // Take the substring of the credit card number starting from the offset and
+ // ending at the field's max_length (or the entire string if max_length is
+ // 0).
+ value = value.substr(
+ field.credit_card_number_offset(),
+ field.max_length > 0 ? field.max_length : std::u16string::npos);
+ }
+
+ return value;
+}
+
// Fills in the select control |field| with |value|. If an exact match is not
// found, falls back to alternate filling strategies based on the |type|.
bool FillSelectControl(const AutofillType& type,
@@ -677,6 +713,27 @@ std::u16string GetExpirationYearForInput(const CreditCard& credit_card,
return value;
}
+// Returns the appropriate virtual card expiration year for the field. Uses the
+// |field_type| and the |field|'s max_length attribute to determine if the year
+// needs to be truncated.
+std::u16string GetExpirationYearForVirtualCardPreviewInput(
+ ServerFieldType storable_type,
+ const AutofillField& field) {
+ if (storable_type == CREDIT_CARD_EXP_2_DIGIT_YEAR &&
+ (field.max_length == 2 || field.max_length == 0)) {
+ return CreditCard::GetMidlineEllipsisDots(2);
+ } else if (storable_type == CREDIT_CARD_EXP_4_DIGIT_YEAR &&
+ (field.max_length == 4 || field.max_length == 0)) {
+ return CreditCard::GetMidlineEllipsisDots(4);
+ }
+
+ if (field.max_length > 4) {
+ return CreditCard::GetMidlineEllipsisDots(4);
+ } else {
+ return CreditCard::GetMidlineEllipsisDots(field.max_length);
+ }
+}
+
// Returns the appropriate expiration date from |credit_card| for the field
// based on the |field_type|. Uses the |field|'s max_length attribute to
// determine if the |value| needs to be truncated or padded. Returns an empty
@@ -720,6 +777,38 @@ std::u16string GetExpirationDateForInput(const CreditCard& credit_card,
}
}
+// Returns the appropriate virtual_card expiration date from for the field based
+// on the |field|'s max_length. Returns an empty string in case of a failure.
+std::u16string GetExpirationDateForVirtualCardPreviewInput(
+ const AutofillField& field,
+ std::string* failure_to_fill) {
+ switch (field.max_length) {
+ case 1:
+ case 2:
+ case 3:
+ if (failure_to_fill) {
+ *failure_to_fill +=
+ "Field to fill must have a max length of at least 4. ";
+ }
+ return std::u16string();
+ case 4:
+ // Expects MMYY
+ return CreditCard::GetMidlineEllipsisDots(4);
+ case 5:
+ // Expects MM/YY
+ return CreditCard::GetMidlineEllipsisDots(2) + u"/" +
+ CreditCard::GetMidlineEllipsisDots(2);
+ case 6:
+ // Expects MMYYYY
+ return CreditCard::GetMidlineEllipsisDots(2) +
+ CreditCard::GetMidlineEllipsisDots(4);
+ default:
+ // Return MM/YYYY for default case
+ return CreditCard::GetMidlineEllipsisDots(2) + u"/" +
+ CreditCard::GetMidlineEllipsisDots(4);
+ }
+}
+
std::u16string RemoveWhitespace(const std::u16string& value) {
std::u16string stripped_value;
base::RemoveChars(value, base::kWhitespaceUTF16, &stripped_value);
@@ -828,6 +917,41 @@ std::u16string GetValueForProfile(const AutofillProfile& profile,
return value;
}
+// Returns the appropriate |virtual_card| value based on |storable_type| to
+// preview into |field|.
+std::u16string GetValueForVirtualCardPreview(const CreditCard& virtual_card,
+ const std::string& app_locale,
+ const AutofillField& field,
+ std::string* failure_to_fill) {
+ DCHECK_EQ(virtual_card.record_type(), CreditCard::VIRTUAL_CARD);
+
+ ServerFieldType storable_type = field.Type().GetStorableType();
+
+ switch (storable_type) {
+ case CREDIT_CARD_VERIFICATION_CODE:
+ // For preview virtual card CVC, return three dots unless for American
+ // Express, which uses 4-digit CVCs.
+ return virtual_card.network() == kAmericanExpressCard
+ ? CreditCard::GetMidlineEllipsisDots(4)
+ : CreditCard::GetMidlineEllipsisDots(3);
+ case CREDIT_CARD_NUMBER:
+ return GetVirtualCardNumberForPreviewInput(virtual_card, field);
+ case CREDIT_CARD_EXP_MONTH:
+ // Expects MM
+ return CreditCard::GetMidlineEllipsisDots(2);
+ case CREDIT_CARD_EXP_2_DIGIT_YEAR:
+ case CREDIT_CARD_EXP_4_DIGIT_YEAR:
+ return GetExpirationYearForVirtualCardPreviewInput(storable_type, field);
+ case CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR:
+ case CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR:
+ return GetExpirationDateForVirtualCardPreviewInput(field,
+ failure_to_fill);
+ default:
+ // All other cases handled here.
+ return virtual_card.GetInfo(storable_type, app_locale);
+ }
+}
+
} // namespace
FieldFiller::FieldFiller(const std::string& app_locale,
@@ -836,7 +960,7 @@ FieldFiller::FieldFiller(const std::string& app_locale,
FieldFiller::~FieldFiller() {}
-bool FieldFiller::FillFormField(
+std::u16string FieldFiller::GetValueForFilling(
const AutofillField& field,
absl::variant<const AutofillProfile*, const CreditCard*>
profile_or_credit_card,
@@ -844,15 +968,21 @@ bool FieldFiller::FillFormField(
const std::u16string& cvc,
mojom::RendererFormDataAction action,
std::string* failure_to_fill) {
- const AutofillType type = field.Type();
std::u16string value;
+ DCHECK(field_data);
if (absl::holds_alternative<const CreditCard*>(profile_or_credit_card)) {
const CreditCard* credit_card =
absl::get<const CreditCard*>(profile_or_credit_card);
- value = GetValueForCreditCard(*credit_card, cvc, app_locale_, action, field,
- failure_to_fill);
+ if (credit_card->record_type() == CreditCard::VIRTUAL_CARD &&
+ action == mojom::RendererFormDataAction::kPreview) {
+ value = GetValueForVirtualCardPreview(*credit_card, app_locale_, field,
+ failure_to_fill);
+ } else {
+ value = GetValueForCreditCard(*credit_card, cvc, app_locale_, action,
+ field, failure_to_fill);
+ }
}
// Grab AutofillProfile data.
@@ -861,16 +991,27 @@ bool FieldFiller::FillFormField(
profile_or_credit_card));
const AutofillProfile* profile =
absl::get<const AutofillProfile*>(profile_or_credit_card);
- if (profile->ShouldSkipFillingOrSuggesting(type.GetStorableType())) {
- if (failure_to_fill)
- *failure_to_fill += "ShouldSkipFillingOrSuggesting() returned true. ";
- return false;
- }
value = GetValueForProfile(*profile, app_locale_, field, field_data,
failure_to_fill);
}
+ return value;
+}
+
+bool FieldFiller::FillFormField(
+ const AutofillField& field,
+ absl::variant<const AutofillProfile*, const CreditCard*>
+ profile_or_credit_card,
+ FormFieldData* field_data,
+ const std::u16string& cvc,
+ mojom::RendererFormDataAction action,
+ std::string* failure_to_fill) {
+ const AutofillType type = field.Type();
+
+ std::u16string value = GetValueForFilling(
+ field, profile_or_credit_card, field_data, cvc, action, failure_to_fill);
+
// Do not attempt to fill empty values as it would skew the metrics.
if (value.empty()) {
if (failure_to_fill)
diff --git a/chromium/components/autofill/core/browser/field_filler.h b/chromium/components/autofill/core/browser/field_filler.h
index df2e159bd02..7871af3c15e 100644
--- a/chromium/components/autofill/core/browser/field_filler.h
+++ b/chromium/components/autofill/core/browser/field_filler.h
@@ -26,6 +26,17 @@ class FieldFiller {
AddressNormalizer* address_normalizer);
~FieldFiller();
+ // Based on |field.Type()|, returns value that is supposed to be filled in the
+ // |field_data|.
+ std::u16string GetValueForFilling(
+ const AutofillField& field,
+ absl::variant<const AutofillProfile*, const CreditCard*>
+ profile_or_credit_card,
+ FormFieldData* field_data,
+ const std::u16string& cvc,
+ mojom::RendererFormDataAction action,
+ std::string* failure_to_fill);
+
// Set |field_data|'s value to the right value in |profile_or_credit_card|.
// Uses |field| to determine which field type should be filled, and
// |app_locale_| as hint when filling exceptional cases like phone number
diff --git a/chromium/components/autofill/core/browser/field_filler_unittest.cc b/chromium/components/autofill/core/browser/field_filler_unittest.cc
index 399b17cc7a7..39d83690471 100644
--- a/chromium/components/autofill/core/browser/field_filler_unittest.cc
+++ b/chromium/components/autofill/core/browser/field_filler_unittest.cc
@@ -26,6 +26,7 @@
#include "components/autofill/core/browser/autofill_type.h"
#include "components/autofill/core/browser/data_model/autofill_profile.h"
#include "components/autofill/core/browser/data_model/credit_card.h"
+#include "components/autofill/core/browser/data_model/credit_card_test_api.h"
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/geo/alternative_state_name_map_test_utils.h"
#include "components/autofill/core/browser/geo/country_names.h"
@@ -46,6 +47,10 @@ using ::i18n::addressinput::Source;
using ::i18n::addressinput::Storage;
using ::i18n::addressinput::TestdataSource;
+std::u16string kMidlineEllipsis2Dots = CreditCard::GetMidlineEllipsisDots(2);
+std::u16string kMidlineEllipsis3Dots = CreditCard::GetMidlineEllipsisDots(3);
+std::u16string kMidlineEllipsis4Dots = CreditCard::GetMidlineEllipsisDots(4);
+
const std::vector<const char*> NotNumericMonthsContentsNoPlaceholder() {
const std::vector<const char*> result = {"Jan", "Feb", "Mar", "Apr",
"May", "Jun", "Jul", "Aug",
@@ -109,31 +114,6 @@ void TestFillingExpirationMonth(const std::vector<const char*>& values,
EXPECT_EQ(u"Nov", field.options[content_index].content);
}
-void TestFillingInvalidFields(const std::u16string& state,
- const std::u16string& city) {
- AutofillProfile profile = test::GetFullProfile();
- profile.SetValidityState(ADDRESS_HOME_STATE, AutofillProfile::INVALID,
- AutofillProfile::SERVER);
- profile.SetValidityState(ADDRESS_HOME_CITY, AutofillProfile::INVALID,
- AutofillProfile::CLIENT);
-
- AutofillField field_state;
- field_state.set_heuristic_type(ADDRESS_HOME_STATE);
- AutofillField field_city;
- field_city.set_heuristic_type(ADDRESS_HOME_CITY);
-
- FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
- filler.FillFormField(field_state, &profile, &field_state,
- /*cvc=*/std::u16string(),
- mojom::RendererFormDataAction::kFill);
- EXPECT_EQ(state, field_state.value);
-
- filler.FillFormField(field_city, &profile, &field_city,
- /*cvc=*/std::u16string(),
- mojom::RendererFormDataAction::kFill);
- EXPECT_EQ(city, field_city.value);
-}
-
struct CreditCardTestCase {
std::u16string card_number_;
size_t total_splits_;
@@ -509,84 +489,6 @@ TEST_F(AutofillFieldFillerTest, FillFormField_Preview_CreditCardField) {
EXPECT_EQ(4u, num_digits);
}
-// Verify that when the relevant feature is enabled, the invalid fields don't
-// get filled.
-TEST_F(AutofillFieldFillerTest, FillFormField_Validity_ServerClient) {
- base::test::ScopedFeatureList scoped_features;
- scoped_features.InitWithFeatures(
- /*enabled_features=*/{features::kAutofillProfileServerValidation,
- features::kAutofillProfileClientValidation},
- /*disabled_features=*/{});
- // State's validity is set by server and city's validity by client.
- TestFillingInvalidFields(/*state=*/std::u16string(),
- /*city=*/std::u16string());
-}
-
-TEST_F(AutofillFieldFillerTest, FillFormField_Validity_OnlyServer) {
- base::test::ScopedFeatureList scoped_features;
- scoped_features.InitWithFeatures(
- /*enabled_features=*/{features::kAutofillProfileServerValidation},
- /*disabled_features=*/{features::kAutofillProfileClientValidation});
- // State's validity is set by server and city's validity by client.
- TestFillingInvalidFields(/*state=*/std::u16string(),
- /*city=*/u"Elysium");
-}
-
-TEST_F(AutofillFieldFillerTest, FillFormField_Validity_OnlyClient) {
- base::test::ScopedFeatureList scoped_features;
- scoped_features.InitWithFeatures(
- /*enabled_features=*/{features::kAutofillProfileClientValidation},
- /*disabled_features=*/{features::kAutofillProfileServerValidation});
- // State's validity is set by server and city's validity by client.
- TestFillingInvalidFields(/*state=*/u"CA",
- /*city=*/std::u16string());
-}
-
-TEST_F(AutofillFieldFillerTest, FillFormField_NoValidity) {
- base::test::ScopedFeatureList scoped_features;
- scoped_features.InitWithFeatures(
- /*enabled_features=*/{},
- /*disabled_features=*/{features::kAutofillProfileServerValidation,
- features::kAutofillProfileClientValidation});
- // State's validity is set by server and city's validity by client.
- TestFillingInvalidFields(/*state=*/u"CA",
- /*city=*/u"Elysium");
-}
-
-// Tests that using only client side validation, if the country is empty, the
-// address fields will get filled regardless of their invalidity.
-TEST_F(AutofillFieldFillerTest, FillFormField_Validity_CountryEmpty) {
- base::test::ScopedFeatureList scoped_features;
- scoped_features.InitWithFeatures(
- /*enabled_features=*/{features::kAutofillProfileClientValidation},
- /*disabled_features=*/{features::kAutofillProfileServerValidation});
- AutofillProfile profile = test::GetFullProfile();
- profile.SetRawInfo(ADDRESS_HOME_COUNTRY, u"");
- profile.SetValidityState(ADDRESS_HOME_STATE, AutofillProfile::INVALID,
- AutofillProfile::CLIENT);
- profile.SetValidityState(EMAIL_ADDRESS, AutofillProfile::INVALID,
- AutofillProfile::CLIENT);
-
- AutofillField field_state;
- field_state.set_heuristic_type(ADDRESS_HOME_STATE);
- AutofillField field_email;
- field_email.set_heuristic_type(EMAIL_ADDRESS);
-
- FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
- // State is filled, because it's an address field.
- filler.FillFormField(field_state, &profile, &field_state,
- /*cvc=*/std::u16string(),
- mojom::RendererFormDataAction::kFill);
- EXPECT_EQ(u"CA", field_state.value);
-
- // Email is not filled, because it's not an address field, and it doesn't
- // depend on the country.
- filler.FillFormField(field_email, &profile, &field_email,
- /*cvc=*/std::u16string(),
- mojom::RendererFormDataAction::kFill);
- EXPECT_EQ(u"", field_email.value);
-}
-
struct AutofillFieldFillerTestCase {
HtmlFieldType field_type;
size_t field_max_length;
@@ -2021,4 +1923,213 @@ TEST_F(AutofillFieldFillerTest, FillUpperCaseAbbreviationInStateTextField) {
EXPECT_EQ(u"BY", field.value);
}
+TEST_F(AutofillFieldFillerTest, PreviewVirtualMonth) {
+ AutofillField field;
+ field.form_control_type = "text";
+ FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
+ field.set_heuristic_type(CREDIT_CARD_EXP_MONTH);
+
+ // A month with two digits should return two dots.
+ CreditCard card = test::GetVirtualCard();
+ card.SetExpirationDateFromString(u"12/2017");
+ filler.FillFormField(field, &card, &field, /*cvc=*/std::u16string(),
+ mojom::RendererFormDataAction::kPreview,
+ /*failure_to_fill*/ nullptr);
+ EXPECT_EQ(kMidlineEllipsis2Dots, field.value);
+
+ // A month with one digit should still return two dots.
+ card.SetExpirationDateFromString(u"03/2019");
+ filler.FillFormField(field, &card, &field, /*cvc=*/std::u16string(),
+ mojom::RendererFormDataAction::kPreview,
+ /*failure_to_fill*/ nullptr);
+ EXPECT_EQ(kMidlineEllipsis2Dots, field.value);
+}
+
+TEST_F(AutofillFieldFillerTest, PreviewVirtualYear) {
+ AutofillField field;
+ field.form_control_type = "text";
+ FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
+ field.set_heuristic_type(CREDIT_CARD_EXP_4_DIGIT_YEAR);
+
+ CreditCard card = test::GetVirtualCard();
+ card.SetExpirationDateFromString(u"12/2017");
+ filler.FillFormField(field, &card, &field, /*cvc=*/std::u16string(),
+ mojom::RendererFormDataAction::kPreview,
+ /*failure_to_fill*/ nullptr);
+ EXPECT_EQ(kMidlineEllipsis4Dots, field.value);
+
+ field.set_heuristic_type(CREDIT_CARD_EXP_2_DIGIT_YEAR);
+ filler.FillFormField(field, &card, &field, /*cvc=*/std::u16string(),
+ mojom::RendererFormDataAction::kPreview,
+ /*failure_to_fill*/ nullptr);
+ EXPECT_EQ(kMidlineEllipsis2Dots, field.value);
+}
+
+TEST_F(AutofillFieldFillerTest, PreviewVirtualShortenedYear) {
+ // Test reducing 4 digit year to 2 digits.
+ AutofillField field;
+ field.max_length = 2;
+ field.form_control_type = "text";
+ FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
+ field.set_heuristic_type(CREDIT_CARD_EXP_4_DIGIT_YEAR);
+
+ CreditCard card = test::GetVirtualCard();
+ card.SetExpirationDateFromString(u"12/2017");
+ filler.FillFormField(field, &card, &field, /*cvc=*/std::u16string(),
+ mojom::RendererFormDataAction::kPreview,
+ /*failure_to_fill*/ nullptr);
+ EXPECT_EQ(kMidlineEllipsis2Dots, field.value);
+}
+
+TEST_F(AutofillFieldFillerTest, PreviewVirtualDate) {
+ AutofillField field;
+ field.form_control_type = "text";
+ FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
+ field.set_heuristic_type(CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR);
+ field.max_length = 7;
+
+ // A date that has a year containing four digits should return two dots for
+ // month and four dots for year.
+ CreditCard card = test::GetVirtualCard();
+ card.SetExpirationDateFromString(u"12/2017");
+ filler.FillFormField(field, &card, &field, /*cvc=*/std::u16string(),
+ mojom::RendererFormDataAction::kPreview,
+ /*failure_to_fill*/ nullptr);
+ std::u16string slash = u"/";
+ std::u16string expected =
+ kMidlineEllipsis2Dots + slash + kMidlineEllipsis4Dots;
+ EXPECT_EQ(expected, field.value);
+
+ // A date that has a year containing two digits should return two dots for
+ // month and two for year.
+ field.set_heuristic_type(CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR);
+ field.max_length = 5;
+ filler.FillFormField(field, &card, &field, /*cvc=*/std::u16string(),
+ mojom::RendererFormDataAction::kPreview,
+ /*failure_to_fill*/ nullptr);
+
+ expected = kMidlineEllipsis2Dots + slash + kMidlineEllipsis2Dots;
+ EXPECT_EQ(expected, field.value);
+}
+
+TEST_F(AutofillFieldFillerTest, PreviewVirtualShortenedDate) {
+ // Test reducing dates to various max length field values.
+ AutofillField field;
+ field.form_control_type = "text";
+ field.max_length = 4;
+ FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
+ field.set_heuristic_type(CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR);
+
+ CreditCard card = test::GetVirtualCard();
+ card.SetExpirationDateFromString(u"12/2017");
+ filler.FillFormField(field, &card, &field, /*cvc=*/std::u16string(),
+ mojom::RendererFormDataAction::kPreview,
+ /*failure_to_fill*/ nullptr);
+
+ // Expected: MMYY = ••••. Unlikely case
+ std::u16string expected = kMidlineEllipsis4Dots;
+ EXPECT_EQ(expected, field.value);
+
+ field.max_length = 5;
+ std::u16string slash = u"/";
+ filler.FillFormField(field, &card, &field, /*cvc=*/std::u16string(),
+ mojom::RendererFormDataAction::kPreview,
+ /*failure_to_fill*/ nullptr);
+
+ // Expected: MM/YY = ••/••.
+ expected = kMidlineEllipsis2Dots + slash + kMidlineEllipsis2Dots;
+ EXPECT_EQ(expected, field.value);
+
+ field.max_length = 6;
+ filler.FillFormField(field, &card, &field, /*cvc=*/std::u16string(),
+ mojom::RendererFormDataAction::kPreview,
+ /*failure_to_fill*/ nullptr);
+
+ // Expected: MMYYYY = ••••••.
+ expected = kMidlineEllipsis2Dots + std::u16string() + kMidlineEllipsis4Dots;
+ EXPECT_EQ(expected, field.value);
+
+ field.max_length = 7;
+ filler.FillFormField(field, &card, &field, /*cvc=*/std::u16string(),
+ mojom::RendererFormDataAction::kPreview,
+ /*failure_to_fill*/ nullptr);
+
+ // Expected: MM/YYYY = ••/••••.
+ expected = kMidlineEllipsis2Dots + slash + kMidlineEllipsis4Dots;
+ EXPECT_EQ(expected, field.value);
+}
+
+TEST_F(AutofillFieldFillerTest, PreviewVirtualCVC) {
+ AutofillField field;
+ field.form_control_type = "text";
+ FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
+ field.set_heuristic_type(CREDIT_CARD_VERIFICATION_CODE);
+
+ CreditCard card = test::GetVirtualCard();
+ CreditCardTestApi(&card).set_network_for_virtual_card(kMasterCard);
+ filler.FillFormField(field, &card, &field, /*cvc=*/std::u16string(),
+ mojom::RendererFormDataAction::kPreview,
+ /*failure_to_fill*/ nullptr);
+ EXPECT_EQ(kMidlineEllipsis3Dots, field.value);
+}
+
+TEST_F(AutofillFieldFillerTest, PreviewVirtualCVCAmericanExpress) {
+ const char kAmericanExpressCard[] = "americanExpressCC";
+ AutofillField field;
+ field.form_control_type = "text";
+ FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
+ field.set_heuristic_type(CREDIT_CARD_VERIFICATION_CODE);
+
+ CreditCard card = test::GetVirtualCard();
+ CreditCardTestApi(&card).set_network_for_virtual_card(kAmericanExpressCard);
+ filler.FillFormField(field, &card, &field, /*cvc=*/std::u16string(),
+ mojom::RendererFormDataAction::kPreview,
+ /*failure_to_fill*/ nullptr);
+ EXPECT_EQ(kMidlineEllipsis4Dots, field.value);
+}
+
+TEST_F(AutofillFieldFillerTest, PreviewVirtualCardNumber) {
+ AutofillField field;
+ field.set_heuristic_type(CREDIT_CARD_NUMBER);
+ field.set_credit_card_number_offset(50);
+ field.form_control_type = "text";
+ const char kMasterCard[] = "masterCardCC";
+
+ CreditCard card = test::GetVirtualCard();
+ card.SetNumber(u"5454545454545454");
+ CreditCardTestApi(&card).set_network_for_virtual_card(kMasterCard);
+ FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
+ filler.FillFormField(field, &card, &field,
+ /*cvc=*/std::u16string(),
+ mojom::RendererFormDataAction::kPreview,
+ /*failure_to_fill*/ nullptr);
+
+ // Virtual card Mastercard ••••5454‬
+ std::u16string expected =
+ u"Virtual card Mastercard "
+ u"\x202A\x2022\x2060\x2006\x2060\x2022\x2060\x2006\x2060\x2022\x2060"
+ u"\x2006\x2060\x2022\x2060\x2006\x2060"
+ u"5454\x202C";
+
+ EXPECT_EQ(expected, field.value);
+}
+
+TEST_F(AutofillFieldFillerTest, PreviewVirtualCardholderName) {
+ std::u16string name = u"Jone Doe";
+
+ AutofillField field;
+ field.form_control_type = "text";
+ FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
+ field.set_heuristic_type(CREDIT_CARD_NAME_FULL);
+
+ CreditCard card = test::GetVirtualCard();
+ card.SetRawInfoWithVerificationStatus(
+ CREDIT_CARD_NAME_FULL, name,
+ structured_address::VerificationStatus::kFormatted);
+ filler.FillFormField(field, &card, &field, /*cvc=*/std::u16string(),
+ mojom::RendererFormDataAction::kPreview,
+ /*failure_to_fill*/ nullptr);
+ EXPECT_EQ(name, field.value);
+}
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/form_data_importer.cc b/chromium/components/autofill/core/browser/form_data_importer.cc
index af83aab9c3c..9a59bc0e670 100644
--- a/chromium/components/autofill/core/browser/form_data_importer.cc
+++ b/chromium/components/autofill/core/browser/form_data_importer.cc
@@ -32,6 +32,7 @@
#include "components/autofill/core/browser/geo/phone_number_i18n.h"
#include "components/autofill/core/browser/logging/log_manager.h"
#include "components/autofill/core/browser/metrics/autofill_metrics.h"
+#include "components/autofill/core/browser/payments/virtual_card_enrollment_manager.h"
#include "components/autofill/core/browser/personal_data_manager.h"
#include "components/autofill/core/browser/validation.h"
#include "components/autofill/core/common/autofill_features.h"
@@ -104,39 +105,10 @@ bool IsValidFieldTypeAndValue(const ServerFieldTypeSet types_seen,
// No verification of validity of the contents is performed. This is an
// existence check only.
bool IsMinimumAddress(const AutofillProfile& profile,
- const std::string& variation_country_code,
+ const std::string& predicted_country_code,
const std::string& app_locale,
LogBuffer* import_log_buffer) {
- // Try to acquire the country code form the filled form.
- std::string country_code =
- base::UTF16ToASCII(profile.GetRawInfo(ADDRESS_HOME_COUNTRY));
-
- if (import_log_buffer && !country_code.empty()) {
- *import_log_buffer << LogMessage::kImportAddressProfileFromFormCountrySource
- << "Country entry in form." << CTag{};
- }
-
- // As a fallback, use the finch state to get a country code.
- if (country_code.empty() && !variation_country_code.empty()) {
- country_code = variation_country_code;
- if (import_log_buffer && !country_code.empty()) {
- *import_log_buffer
- << LogMessage::kImportAddressProfileFromFormCountrySource
- << "Variations service." << CTag{};
- }
- }
-
- // As the last resort, derive the country code from the app_locale.
- if (country_code.empty()) {
- country_code = AutofillCountry::CountryCodeForLocale(app_locale);
- if (import_log_buffer && !country_code.empty()) {
- *import_log_buffer
- << LogMessage::kImportAddressProfileFromFormCountrySource
- << "App locale." << CTag{};
- }
- }
-
- AutofillCountry country(country_code, app_locale);
+ AutofillCountry country(predicted_country_code, app_locale);
// Include the details of the country to the log.
if (import_log_buffer)
@@ -258,7 +230,7 @@ FormDataImporter::FormDataImporter(AutofillClient* client,
address_profile_save_manager_(
std::make_unique<AddressProfileSaveManager>(client,
personal_data_manager)),
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
local_card_migration_manager_(
std::make_unique<LocalCardMigrationManager>(client,
payments_client,
@@ -266,9 +238,13 @@ FormDataImporter::FormDataImporter(AutofillClient* client,
personal_data_manager)),
upi_vpa_save_manager_(
std::make_unique<UpiVpaSaveManager>(client, personal_data_manager)),
-#endif // #if !defined(OS_ANDROID) && !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
personal_data_manager_(personal_data_manager),
- app_locale_(app_locale) {
+ app_locale_(app_locale),
+ virtual_card_enrollment_manager_(
+ std::make_unique<VirtualCardEnrollmentManager>(personal_data_manager,
+ payments_client,
+ client)) {
}
FormDataImporter::~FormDataImporter() = default;
@@ -283,10 +259,7 @@ void FormDataImporter::ImportFormData(const FormStructure& submitted_form,
bool is_credit_card_upstream_enabled =
credit_card_save_manager_->IsCreditCardUploadEnabled();
- // ImportFormData will set the |imported_credit_card_record_type_|. If the
- // imported card is invalid or already a server card, or if
- // |credit_card_save_manager_| does not allow uploading,
- // |imported_credit_card| will be nullptr.
+
ImportFormData(submitted_form, profile_autofill_enabled,
credit_card_autofill_enabled,
/*should_return_local_card=*/is_credit_card_upstream_enabled,
@@ -321,14 +294,52 @@ CreditCard FormDataImporter::ExtractCreditCardFromForm(
}
// static
-bool FormDataImporter::IsValidLearnableProfile(
+std::string FormDataImporter::GetPredictedCountryCode(
const AutofillProfile& profile,
const std::string& variation_country_code,
const std::string& app_locale,
LogBuffer* import_log_buffer) {
+ // Try to acquire the country code form the filled form.
+ std::string country_code =
+ base::UTF16ToASCII(profile.GetRawInfo(ADDRESS_HOME_COUNTRY));
+
+ if (import_log_buffer && !country_code.empty()) {
+ *import_log_buffer << LogMessage::kImportAddressProfileFromFormCountrySource
+ << "Country entry in form." << CTag{};
+ }
+
+ // As a fallback, use the variation service state to get a country code.
+ if (country_code.empty() && !variation_country_code.empty()) {
+ country_code = variation_country_code;
+ if (import_log_buffer) {
+ *import_log_buffer
+ << LogMessage::kImportAddressProfileFromFormCountrySource
+ << "Variations service." << CTag{};
+ }
+ }
+
+ // As the last resort, derive the country code from the app_locale.
+ if (country_code.empty()) {
+ country_code = AutofillCountry::CountryCodeForLocale(app_locale);
+ if (import_log_buffer && !country_code.empty()) {
+ *import_log_buffer
+ << LogMessage::kImportAddressProfileFromFormCountrySource
+ << "App locale." << CTag{};
+ }
+ }
+
+ return country_code;
+}
+
+// static
+bool FormDataImporter::IsValidLearnableProfile(
+ const AutofillProfile& profile,
+ const std::string& predicted_country_code,
+ const std::string& app_locale,
+ LogBuffer* import_log_buffer) {
// Check if the imported address qualifies as a minimum address.
bool is_not_minimum_address = false;
- if (!IsMinimumAddress(profile, variation_country_code, app_locale,
+ if (!IsMinimumAddress(profile, predicted_country_code, app_locale,
import_log_buffer)) {
is_not_minimum_address = true;
}
@@ -661,15 +672,55 @@ bool FormDataImporter::ImportAddressProfileForSection(
}
}
+ const std::string predicted_country_code = GetPredictedCountryCode(
+ candidate_profile, client_->GetVariationConfigCountryCode(), app_locale_,
+ import_log_buffer);
+ bool did_complement_country = false;
+ // If the form doesn't contain a country field, complement the profile using
+ // |predicted_country_code|. To give users the opportunity to edit, this is
+ // only done with explicit save prompts enabled.
+ // TODO(crbug.com/1297032): Cleanup kAutofillComplementCountryCodeOnImport
+ // check when launched.
+ if (!has_invalid_country &&
+ candidate_profile.GetRawInfo(ADDRESS_HOME_COUNTRY).empty() &&
+ base::FeatureList::IsEnabled(
+ features::kAutofillAddressProfileSavePrompt) &&
+ base::FeatureList::IsEnabled(
+ features::kAutofillComplementCountryCodeOnImport)) {
+ candidate_profile.SetInfoWithVerificationStatus(
+ AutofillType(ADDRESS_HOME_COUNTRY),
+ base::ASCIIToUTF16(predicted_country_code), app_locale_,
+ VerificationStatus::kObserved);
+ did_complement_country = true;
+ }
+
// Construct the phone number. Reject the whole profile if the number is
// invalid.
if (!combined_phone.IsEmpty()) {
+ const std::string predicted_country_code_without_variation =
+ GetPredictedCountryCode(candidate_profile, "", app_locale_, nullptr);
+ // If kAutofillConsiderVariationCountryCodeForPhoneNumbers is enabled,
+ // a consistent country code prediction for addresses and phone numbers is
+ // used. Otherwise the variation service state is not considered for phone
+ // numbers. This makes a difference, if the country code cannot be found
+ // in the profile.
+ // ParseNumber() implicity accepts both a country code and a locale. This
+ // will be refactored with crbug/1296077. The parameter for
+ // SetInfoWithVerificationStatus() has to be consistent with ParseNumber().
+ // TODO(crbug.com/1295721): Cleanup when launched.
+ const std::string& phone_number_region =
+ predicted_country_code != predicted_country_code_without_variation &&
+ base::FeatureList::IsEnabled(
+ features::
+ kAutofillConsiderVariationCountryCodeForPhoneNumbers)
+ ? predicted_country_code
+ : app_locale_;
std::u16string constructed_number;
- if (!combined_phone.ParseNumber(candidate_profile, app_locale_,
+ if (!combined_phone.ParseNumber(candidate_profile, phone_number_region,
&constructed_number) ||
!candidate_profile.SetInfoWithVerificationStatus(
AutofillType(PHONE_HOME_WHOLE_NUMBER), constructed_number,
- app_locale_, VerificationStatus::kObserved)) {
+ phone_number_region, VerificationStatus::kObserved)) {
if (import_log_buffer) {
*import_log_buffer << LogMessage::kImportAddressProfileFromFormFailed
<< "Invalid phone number." << CTag{};
@@ -680,10 +731,8 @@ bool FormDataImporter::ImportAddressProfileForSection(
// Reject the profile if minimum address and validation requirements are not
// met.
- const std::string variation_country_code =
- client_->GetVariationConfigCountryCode();
bool is_invalid_learnable_profile =
- !IsValidLearnableProfile(candidate_profile, variation_country_code,
+ !IsValidLearnableProfile(candidate_profile, predicted_country_code,
app_locale_, import_log_buffer);
// Do not import a profile if any of the requirements is violated.
@@ -740,7 +789,10 @@ bool FormDataImporter::ImportAddressProfileForSection(
DCHECK(!personal_data_manager_->IsOffTheRecord());
import_candidates.push_back(AddressProfileImportCandidate{
- candidate_profile, form.source_url(), all_fulfilled});
+ .profile = candidate_profile,
+ .url = form.source_url(),
+ .all_requirements_fulfilled = all_fulfilled,
+ .did_complement_country = did_complement_country});
// Return true if a compelete importable profile was found.
return all_fulfilled;
@@ -760,7 +812,8 @@ bool FormDataImporter::ProcessAddressProfileImportCandidates(
continue;
address_profile_save_manager_->ImportProfileFromForm(
candidate.profile, app_locale_, candidate.url,
- /*allow_only_silent_updates=*/false);
+ /*allow_only_silent_updates=*/false,
+ candidate.did_complement_country);
// Limit the number of importable profiles to 2.
if (++imported_profiles >= 2)
return true;
@@ -786,12 +839,12 @@ bool FormDataImporter::ProcessCreditCardImportCandidate(
absl::optional<std::string> detected_upi_id,
bool credit_card_autofill_enabled,
bool is_credit_card_upstream_enabled) {
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
if (detected_upi_id && credit_card_autofill_enabled &&
base::FeatureList::IsEnabled(features::kAutofillSaveAndFillVPA)) {
upi_vpa_save_manager_->OfferLocalSave(*detected_upi_id);
}
-#endif // #if !defined(OS_ANDROID) && !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
// If no card was successfully imported from the form, return.
if (imported_credit_card_record_type_ ==
@@ -808,7 +861,18 @@ bool FormDataImporter::ProcessCreditCardImportCandidate(
if (client_->IsAutofillAssistantShowing())
return false;
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+ if (base::FeatureList::IsEnabled(
+ features::kAutofillEnableUpdateVirtualCardEnrollment)) {
+ if (imported_credit_card &&
+ imported_credit_card->virtual_card_enrollment_state() ==
+ CreditCard::VirtualCardEnrollmentState::UNENROLLED_AND_ELIGIBLE) {
+ virtual_card_enrollment_manager_->OfferVirtualCardEnroll(
+ *imported_credit_card, VirtualCardEnrollmentSource::kDownstream);
+ return true;
+ }
+ }
+
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
// A credit card was successfully imported, but it's possible it is already a
// local or server card. First, check to see if we should offer local card
// migration in this case, as local cards could go either way.
@@ -819,12 +883,15 @@ bool FormDataImporter::ProcessCreditCardImportCandidate(
/*is_from_settings_page=*/false);
return true;
}
-#endif // #if !defined(OS_ANDROID) && !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
- // Local card migration will not be offered. If we do not have a new card to
- // save (or a local card to upload save), return.
- if (!imported_credit_card)
+ // Local card migration will not be offered. We check to see if it is valid to
+ // offer upload save or local card save, which will happen below if we do not
+ // early return false in this if-statement.
+ if (!ShouldOfferUploadCardOrLocalCardSave(imported_credit_card.get(),
+ is_credit_card_upstream_enabled)) {
return false;
+ }
// We have a card to save; decide what type of save flow to display.
if (is_credit_card_upstream_enabled) {
@@ -856,6 +923,7 @@ bool FormDataImporter::ProcessCreditCardImportCandidate(
return false;
}
+
bool FormDataImporter::ImportCreditCard(
const FormStructure& form,
bool should_return_local_card,
@@ -894,7 +962,7 @@ bool FormDataImporter::ImportCreditCard(
return false;
}
- // If the imported card is a known virtual card, abort saving.
+ // If the imported card is a known virtual card, abort importing.
if (fetched_virtual_cards_.contains(candidate_credit_card.LastFourDigits()))
return false;
@@ -902,6 +970,14 @@ bool FormDataImporter::ImportCreditCard(
// overwrite this type if we discover it is already a local or server card.
imported_credit_card_record_type_ = ImportedCreditCardRecordType::NEW_CARD;
+ // Denotes whether the extracted card matches a local card. Used to help
+ // determine the return value of this function for use by tests. This will be
+ // used to ensure if we found a matched local card and
+ // |should_return_local_card| is false, that we return true so that this
+ // function matches the legacy implementation.
+ // TODO(crbug.com/1291243): Deprecate returning bool values.
+ bool matched_local_card = false;
+
// Attempt to merge with an existing credit card. Don't present a prompt if we
// have already saved this card number, unless |should_return_local_card| is
// true which indicates that upload is enabled. In this case, it's useful to
@@ -913,6 +989,7 @@ bool FormDataImporter::ImportCreditCard(
// modified directly by the UpdateFromImportedCard() call.
CreditCard card_copy(*card);
if (card_copy.UpdateFromImportedCard(candidate_credit_card, app_locale_)) {
+ matched_local_card = true;
personal_data_manager_->UpdateCreditCard(card_copy);
// Mark that the credit card imported from the submitted form is
// already a local card.
@@ -923,28 +1000,22 @@ bool FormDataImporter::ImportCreditCard(
// database, copy the nickname to the |candidate_credit_card| so that the
// nickname also shows in the Upstream bubble.
candidate_credit_card.SetNickname(card_copy.nickname());
-
- // If we should not return the local card, return that we merged it,
- // without setting |imported_credit_card|.
- if (!should_return_local_card)
- return true;
-
- break;
}
}
- // Also don't offer to save if we already have this stored as a server
- // card. We only check the number because if the new card has the same number
- // as the server card, upload is guaranteed to fail. There's no mechanism for
- // entries with the same number but different names or expiration dates as
- // there is for local cards.
+ // If we are able to find a matching server card for the imported card, we set
+ // |imported_credit_card_record_type_| to SERVER_CARD, and set
+ // |imported_credit_card| to point to the corresponding CreditCard. Note: if a
+ // local card was found in the previous for-loop, this will override
+ // |imported_credit_card| to the server card data (it would previously be set
+ // to the local card data) as we want the server to be the source of truth.
for (const CreditCard* card :
personal_data_manager_->GetServerCreditCards()) {
if ((card->record_type() == CreditCard::MASKED_SERVER_CARD &&
card->LastFourDigits() == candidate_credit_card.LastFourDigits()) ||
(card->record_type() == CreditCard::FULL_SERVER_CARD &&
candidate_credit_card.HasSameNumberAs(*card))) {
- // Don't update card if the expiration date is missing
+ // Don't import the card if the expiration date is missing.
if (candidate_credit_card.expiration_month() == 0 ||
candidate_credit_card.expiration_year() == 0) {
return false;
@@ -968,7 +1039,13 @@ bool FormDataImporter::ImportCreditCard(
: AutofillMetrics::
MASKED_SERVER_CARD_EXPIRATION_DATE_DID_NOT_MATCH);
}
- return false;
+ // We found a server card that matches the data in the form. Set
+ // |imported_credit_card| to point to the corresponding CreditCard so that
+ // a future flow that would need this data can use it (such as virtual
+ // card enrollment flow).
+ *imported_credit_card = std::make_unique<CreditCard>(*card);
+
+ return matched_local_card && !should_return_local_card;
}
}
*imported_credit_card = std::make_unique<CreditCard>(candidate_credit_card);
@@ -1047,4 +1124,33 @@ absl::optional<std::string> FormDataImporter::ImportUpiId(
return absl::nullopt;
}
+bool FormDataImporter::ShouldOfferUploadCardOrLocalCardSave(
+ const CreditCard* imported_credit_card,
+ bool is_credit_card_upload_enabled) {
+ // If we have an invalid card in the form, a duplicate field type, or we have
+ // entered a virtual card, |imported_credit_card| will be set
+ // to nullptr and thus we do not want to offer upload save or local card save.
+ if (!imported_credit_card)
+ return false;
+
+ // We do not want to offer upload save or local card save for server cards.
+ if (imported_credit_card_record_type_ ==
+ ImportedCreditCardRecordType::SERVER_CARD) {
+ return false;
+ }
+
+ // If we have a local card but credit card upload is not enabled, we do not
+ // want to offer upload save as it is disabled and we do not want to offer
+ // local card save as it is already saved as a local card.
+ if (!is_credit_card_upload_enabled &&
+ imported_credit_card_record_type_ ==
+ ImportedCreditCardRecordType::LOCAL_CARD) {
+ return false;
+ }
+
+ // We know |imported_credit_card| is either a new card, or a local card with
+ // upload enabled.
+ return true;
+}
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/form_data_importer.h b/chromium/components/autofill/core/browser/form_data_importer.h
index 0ac049f10b8..05b3d19f2a8 100644
--- a/chromium/components/autofill/core/browser/form_data_importer.h
+++ b/chromium/components/autofill/core/browser/form_data_importer.h
@@ -19,6 +19,7 @@
#include "components/autofill/core/browser/payments/local_card_migration_manager.h"
#include "components/autofill/core/browser/payments/payments_client.h"
#include "components/autofill/core/browser/payments/upi_vpa_save_manager.h"
+#include "components/autofill/core/browser/payments/virtual_card_enrollment_manager.h"
#include "components/autofill/core/browser/personal_data_manager.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
@@ -55,7 +56,7 @@ class FormDataImporter {
FormDataImporter(const FormDataImporter&) = delete;
FormDataImporter& operator=(const FormDataImporter&) = delete;
- ~FormDataImporter();
+ virtual ~FormDataImporter();
// Imports the form data, submitted by the user, into
// |personal_data_manager_|. If a new credit card was detected and
@@ -69,9 +70,22 @@ class FormDataImporter {
// duplicated field types in the form.
CreditCard ExtractCreditCardFromForm(const FormStructure& form);
+ // Tries to infer the country |profile| is from, which can be useful to
+ // verify whether the data is sensible. Returns a two-letter ISO country code
+ // by considering, in decreasing order of priority:
+ // - The country specified in |profile|
+ // - The country determined by the variation service stored in
+ // |variation_country_code|
+ // - The country code corresponding to |app_locale|
+ static std::string GetPredictedCountryCode(
+ const AutofillProfile& profile,
+ const std::string& variation_country_code,
+ const std::string& app_locale,
+ LogBuffer* import_log_buffer);
+
// Checks suitability of |profile| for adding to the user's set of profiles.
static bool IsValidLearnableProfile(const AutofillProfile& profile,
- const std::string& finch_country_code,
+ const std::string& predicted_country_code,
const std::string& app_locale,
LogBuffer* import_log_buffer);
@@ -79,11 +93,15 @@ class FormDataImporter {
// them.
void CacheFetchedVirtualCard(const std::u16string& last_four);
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
LocalCardMigrationManager* local_card_migration_manager() {
return local_card_migration_manager_.get();
}
-#endif // #if !defined(OS_ANDROID) && !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
+
+ raw_ptr<VirtualCardEnrollmentManager> GetVirtualCardEnrollmentManager() {
+ return virtual_card_enrollment_manager_.get();
+ }
protected:
// Exposed for testing.
@@ -92,13 +110,13 @@ class FormDataImporter {
credit_card_save_manager_ = std::move(credit_card_save_manager);
}
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
// Exposed for testing.
void set_local_card_migration_manager(
std::unique_ptr<LocalCardMigrationManager> local_card_migration_manager) {
local_card_migration_manager_ = std::move(local_card_migration_manager);
}
-#endif // #if !defined(OS_ANDROID) && !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
private:
// Defines a candidate for address profile import.
@@ -109,6 +127,9 @@ class FormDataImporter {
GURL url;
// Indicates if all import requirements have been fulfilled.
bool all_requirements_fulfilled;
+ // Whether the profile's country was complemented automatically.
+ // TODO(crbug.com/1297032): Cleanup when launched.
+ bool did_complement_country;
AddressProfileImportCandidate(AddressProfileImportCandidate&& other) =
default;
AddressProfileImportCandidate& operator=(
@@ -116,17 +137,12 @@ class FormDataImporter {
};
// Scans the given |form| for importable Autofill data. If the form includes
- // sufficient address data for a new profile, it is immediately imported. If
- // the form includes sufficient credit card data for a new credit card and
- // |credit_card_autofill_enabled| is set to |true|, it is stored into
- // |imported_credit_card| so that we can prompt the user whether to save this
- // data. If the form contains credit card data already present in a local
- // credit card entry *and* |should_return_local_card| is true, the data is
- // stored into |imported_credit_card| so that we can prompt the user whether
- // to upload it. If the form contains UPI data and
- // |credit_card_autofill_enabled| is true, the UPI ID will be stored into
- // |imported_upi_id|. Returns |true| if sufficient address or credit card data
- // was found. Exposed for testing.
+ // sufficient address data for a new profile, it is immediately imported and
+ // this function returns true. This function also returns true in cases where
+ // FormDataImporter::ImportCreditCard() returns true, please refer to the
+ // comment above that function for more details. If the form contains UPI data
+ // and |credit_card_autofill_enabled| is true, the UPI ID will be stored into
+ // |imported_upi_id| and this function will also return true.
bool ImportFormData(const FormStructure& form,
bool profile_autofill_enabled,
bool credit_card_autofill_enabled,
@@ -155,10 +171,20 @@ class FormDataImporter {
LogBuffer* import_log_buffer);
// Go through the |form| fields and attempt to extract a new credit card in
- // |imported_credit_card|, or update an existing card.
- // |should_return_local_card| will indicate whether |imported_credit_card| is
- // filled even if an existing card was updated. Success is defined as having
- // a new card to import, or having merged with an existing card.
+ // |imported_credit_card|, or update an existing card. If we can find a local
+ // card or server card that matches the card in the form, then it will always
+ // be set in |imported_credit_card| and |imported_credit_card_record_type_|
+ // will be set to the corresponding credit card record type (for example,
+ // LOCAL_CARD). If we cannot find a local card or server card that matches the
+ // card in the form, we will set |imported_credit_card| to the extracted card
+ // from the form and |imported_credit_card_record_type_| will be set to
+ // NEW_CARD. In cases where we have both a server card and local card entry
+ // for |imported_credit_card|, we will update the local card entry but set
+ // |imported_credit_card| to the server card data as that is the source of
+ // truth, and |imported_credit_card_record_type_| will be SERVER_CARD. This
+ // function returns true if the extracted card is saveable (such as if it is a
+ // new card or a local card with upload enabled) or if it resulted in updating
+ // the data of a local card.
bool ImportCreditCard(const FormStructure& form,
bool should_return_local_card,
std::unique_ptr<CreditCard>* imported_credit_card);
@@ -193,6 +219,18 @@ class FormDataImporter {
// will be empty if no UPI ID was found.
absl::optional<std::string> ImportUpiId(const FormStructure& form);
+ // |imported_credit_card| stores a pointer to the card imported from the form.
+ // If no valid card was imported, it is set to nullptr. It might be set to a
+ // copy of a LOCAL_CARD or SERVER_CARD we have already saved if we were able
+ // to find a matching copy. |is_credit_card_upstream_enabled| denotes whether
+ // the user has credit card upload enabled. This function is used to prevent
+ // offering upload card save or local card save in situations where it would
+ // be invalid to offer them. For example, we should not offer to upload card
+ // if it is already a server card.
+ bool ShouldOfferUploadCardOrLocalCardSave(
+ const CreditCard* imported_credit_card,
+ bool is_credit_card_upload_enabled);
+
// Whether a dynamic change form is imported.
bool from_dynamic_change_form_ = false;
@@ -209,13 +247,13 @@ class FormDataImporter {
// Responsible for managing address profiles save flows.
std::unique_ptr<AddressProfileSaveManager> address_profile_save_manager_;
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
// Responsible for migrating locally saved credit cards to Google Pay.
std::unique_ptr<LocalCardMigrationManager> local_card_migration_manager_;
// Responsible for managing UPI/VPA save flows.
std::unique_ptr<UpiVpaSaveManager> upi_vpa_save_manager_;
-#endif // #if !defined(OS_ANDROID) && !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
// The personal data manager, used to save and load personal data to/from the
// web database. This is overridden by the BrowserAutofillManagerTest.
@@ -233,6 +271,10 @@ class FormDataImporter {
// Used to store the last four digits of the fetched virtual cards.
base::flat_set<std::u16string> fetched_virtual_cards_;
+ // Responsible for managing the virtual card enrollment flow through chrome.
+ std::unique_ptr<VirtualCardEnrollmentManager>
+ virtual_card_enrollment_manager_;
+
friend class AutofillMergeTest;
friend class FormDataImporterTest;
friend class FormDataImporterTestBase;
@@ -243,8 +285,16 @@ class FormDataImporter {
FRIEND_TEST_ALL_PREFIXES(AutofillMergeTest, MergeProfiles);
FRIEND_TEST_ALL_PREFIXES(FormDataImporterTest,
AllowDuplicateMaskedServerCardIfFlagEnabled);
- FRIEND_TEST_ALL_PREFIXES(FormDataImporterTest, DontDuplicateFullServerCard);
- FRIEND_TEST_ALL_PREFIXES(FormDataImporterTest, DontDuplicateMaskedServerCard);
+ FRIEND_TEST_ALL_PREFIXES(
+ FormDataImporterTest,
+ DuplicateFullServerCardWhileContainingLocalCardCopies);
+ FRIEND_TEST_ALL_PREFIXES(FormDataImporterTest, DuplicateMaskedServerCard);
+ FRIEND_TEST_ALL_PREFIXES(
+ FormDataImporterTest,
+ ImportCreditCard_DuplicateServerCards_ExtractFullCard);
+ FRIEND_TEST_ALL_PREFIXES(
+ FormDataImporterTest,
+ ImportCreditCard_DuplicateServerCards_ExtractMaskedCard);
FRIEND_TEST_ALL_PREFIXES(FormDataImporterTest,
ImportFormData_AddressesDisabledOneCreditCard);
FRIEND_TEST_ALL_PREFIXES(FormDataImporterTest,
diff --git a/chromium/components/autofill/core/browser/form_data_importer_unittest.cc b/chromium/components/autofill/core/browser/form_data_importer_unittest.cc
index 54a097c87ed..fdb6e10650d 100644
--- a/chromium/components/autofill/core/browser/form_data_importer_unittest.cc
+++ b/chromium/components/autofill/core/browser/form_data_importer_unittest.cc
@@ -78,8 +78,9 @@ constexpr char kDefaultZip[] = "94102";
constexpr char kDefaultCity[] = "Los Angeles";
constexpr char kDefaultDependentLocality[] = "Nob Hill";
constexpr char kDefaultState[] = "California";
-constexpr char kDefaultPhone[] = "+16505550000";
-constexpr char kDefaultPhoneAlternativeFormatting[] = "+1-650-555-0000";
+constexpr char kDefaultPhone[] = "+1 650-555-0000";
+constexpr char kDefaultPhoneAlternativeFormatting[] = "650-555-0000";
+constexpr char kDefaultPhoneDomesticFormatting[] = "(650) 555-0000";
constexpr char kDefaultPhoneAreaCode[] = "650";
constexpr char kDefaultPhonePrefix[] = "555";
constexpr char kDefaultPhoneSuffix[] = "0000";
@@ -93,7 +94,7 @@ constexpr char kSecondZip[] = "94106";
constexpr char kSecondCity[] = "Los Angeles";
constexpr char kSecondDependentLocality[] = "Down Town";
constexpr char kSecondState[] = "California";
-constexpr char kSecondPhone[] = "+16516661111";
+constexpr char kSecondPhone[] = "+1 651-666-1111";
constexpr char kSecondPhoneAreaCode[] = "651";
constexpr char kSecondPhonePrefix[] = "666";
constexpr char kSecondPhoneSuffix[] = "1111";
@@ -107,7 +108,7 @@ constexpr char kThirdZip[] = "65619";
constexpr char kThirdCity[] = "Springfield";
constexpr char kThirdDependentLocality[] = "Down Town";
constexpr char kThirdState[] = "Oregon";
-constexpr char kThirdPhone[] = "+18517772222";
+constexpr char kThirdPhone[] = "+1 851-777-2222";
constexpr char kDefaultCreditCardNumber[] = "4111 1111 1111 1111";
@@ -193,6 +194,12 @@ AutofillProfile ConstructProfileFromTypeValuePairs(
std::vector<std::pair<ServerFieldType, std::string>> type_value_pairs) {
AutofillProfile profile;
for (const auto& type_value_pair : type_value_pairs) {
+ if (type_value_pair.first == ADDRESS_HOME_DEPENDENT_LOCALITY &&
+ !base::FeatureList::IsEnabled(
+ features::kAutofillEnableDependentLocalityParsing)) {
+ continue;
+ }
+
profile.SetRawInfoWithVerificationStatus(
type_value_pair.first, base::UTF8ToUTF16(type_value_pair.second),
structured_address::VerificationStatus::kObserved);
@@ -220,6 +227,15 @@ GetDefaultProfileTypeValuePairs() {
};
}
+// Same as |GetDefaultProfileTypeValuePairs()| but with ADDRESS_HOME_COUNTRY
+// set to |country|.
+std::vector<std::pair<ServerFieldType, std::string>>
+GetDefaultProfileTypeValuePairsWithCountry(const std::string& country) {
+ auto profile_typed_value_pairs = GetDefaultProfileTypeValuePairs();
+ profile_typed_value_pairs.emplace_back(ADDRESS_HOME_COUNTRY, country);
+ return profile_typed_value_pairs;
+}
+
// Same as |GetDefaultProfileTypeValuePairs()| but with the second profile
// information.
std::vector<std::pair<ServerFieldType, std::string>>
@@ -259,6 +275,12 @@ AutofillProfile ConstructDefaultProfile() {
return ConstructProfileFromTypeValuePairs(GetDefaultProfileTypeValuePairs());
}
+// Same as |ConstructDefaultProfile()| but with |country|.
+AutofillProfile ConstructDefaultProfileWithCountry(const std::string& country) {
+ return ConstructProfileFromTypeValuePairs(
+ GetDefaultProfileTypeValuePairsWithCountry(country));
+}
+
// Returns the second AutofillProfile used in this test file.
AutofillProfile ConstructSecondProfile() {
return ConstructProfileFromTypeValuePairs(GetSecondProfileTypeValuePairs());
@@ -277,6 +299,13 @@ std::unique_ptr<FormStructure> ConstructDefaultProfileFormStructure() {
GetDefaultProfileTypeValuePairs());
}
+// Same as |ConstructDefaultFormStructure()| but with |country|.
+std::unique_ptr<FormStructure> ConstructDefaultProfileFormStructureWithCountry(
+ const std::string& country) {
+ return ConstructFormStructureFromTypeValuePairs(
+ GetDefaultProfileTypeValuePairsWithCountry(country));
+}
+
// Same as |ConstructDefaultFormStructure()| but for the second profile.
std::unique_ptr<FormStructure> ConstructSecondProfileFormStructure() {
return ConstructFormStructureFromTypeValuePairs(
@@ -349,13 +378,13 @@ class FormDataImporterTestBase {
void ResetPersonalDataManager(UserMode user_mode) {
personal_data_manager_ = std::make_unique<PersonalDataManager>("en", "US");
+ personal_data_manager_->set_auto_accept_address_imports_for_testing(true);
personal_data_manager_->Init(
scoped_refptr<AutofillWebDataService>(autofill_database_service_),
/*account_database=*/nullptr,
/*pref_service=*/prefs_.get(),
/*local_state=*/prefs_.get(),
/*identity_manager=*/nullptr,
- /*client_profile_validator=*/nullptr,
/*history_service=*/nullptr,
/*strike_database=*/nullptr,
/*image_fetcher=*/nullptr,
@@ -444,12 +473,18 @@ class FormDataImporterTestBase {
// Note, that order is taken into account.
void VerifyExpectationForImportedAddressProfiles(
const std::vector<AutofillProfile>& expected_profiles) {
- std::vector<AutofillProfile> imported_profiles;
- size_t expected_profile_index = 0;
- for (const auto* profile : personal_data_manager_->GetProfiles()) {
- ASSERT_LT(expected_profile_index, expected_profiles.size());
- profile->Compare(expected_profiles[expected_profile_index++]);
+ std::vector<AutofillProfile> expected_non_const_copy = expected_profiles;
+
+ std::vector<AutofillProfile*> imported_profiles_ptrs =
+ personal_data_manager_->GetProfiles();
+ ASSERT_EQ(expected_profiles.size(), imported_profiles_ptrs.size());
+
+ std::vector<AutofillProfile*> expected_profile_ptrs;
+ for (auto& profile : expected_non_const_copy) {
+ expected_profile_ptrs.emplace_back(&profile);
}
+
+ ExpectSameElements(expected_profile_ptrs, imported_profiles_ptrs);
}
// Convenience wrapper that calls |FormDataImporter::ImportFormData()| and
@@ -555,8 +590,13 @@ class FormDataImporterTest
public testing::Test,
public testing::WithParamInterface<std::tuple<bool, bool, bool>> {
protected:
- bool StructuredNames() const { return structured_names_enabled_; }
- bool StructuredAddresses() const { return structured_addresses_enabled_; }
+ bool DependentLocalityParsingEnabled() {
+ return support_for_depending_locality_;
+ }
+
+ bool ConsiderVariationCountryCodeForPhoneNumbers() {
+ return consider_variation_country_code_for_phone_numbers_;
+ }
private:
void SetUp() override {
@@ -600,44 +640,89 @@ class FormDataImporterTest
}
void InitializeFeatures() {
- structured_names_enabled_ = std::get<0>(GetParam());
- structured_addresses_enabled_ = std::get<1>(GetParam());
- support_for_apartment_numbers_ = std::get<2>(GetParam());
+ support_for_apartment_numbers_ = std::get<0>(GetParam());
+ support_for_depending_locality_ = std::get<1>(GetParam());
+ consider_variation_country_code_for_phone_numbers_ =
+ std::get<2>(GetParam());
+
+ // Enable all those features by default.
+ std::vector<base::Feature> enabled_features{
+ features::kAutofillEnableSupportForMoreStructureInAddresses,
+ features::kAutofillEnableSupportForMoreStructureInNames};
- std::vector<base::Feature> enabled_features;
std::vector<base::Feature> disabled_features;
- if (structured_names_enabled_) {
- enabled_features.push_back(
- features::kAutofillEnableSupportForMoreStructureInNames);
- } else {
- disabled_features.push_back(
- features::kAutofillEnableSupportForMoreStructureInNames);
- }
+ (support_for_depending_locality_ ? enabled_features : disabled_features)
+ .push_back(features::kAutofillEnableDependentLocalityParsing);
- if (structured_addresses_enabled_) {
- enabled_features.push_back(
- features::kAutofillEnableSupportForMoreStructureInAddresses);
- } else {
- disabled_features.push_back(
- features::kAutofillEnableSupportForMoreStructureInAddresses);
- }
+ (support_for_apartment_numbers_ ? enabled_features : disabled_features)
+ .push_back(features::kAutofillEnableSupportForApartmentNumbers);
+
+ (consider_variation_country_code_for_phone_numbers_ ? enabled_features
+ : disabled_features)
+ .push_back(
+ features::kAutofillConsiderVariationCountryCodeForPhoneNumbers);
- if (support_for_apartment_numbers_) {
- enabled_features.push_back(
- features::kAutofillEnableSupportForApartmentNumbers);
- } else {
- disabled_features.push_back(
- features::kAutofillEnableSupportForApartmentNumbers);
- }
scoped_feature_list_.InitWithFeatures(enabled_features, disabled_features);
}
- bool structured_names_enabled_;
- bool structured_addresses_enabled_;
bool support_for_apartment_numbers_;
+ bool support_for_depending_locality_;
+ bool consider_variation_country_code_for_phone_numbers_;
};
+TEST_P(FormDataImporterTest, GetPredictedCountryCode) {
+ const AutofillProfile us_profile =
+ ConstructProfileFromTypeValuePairs({{ADDRESS_HOME_COUNTRY, "US"}});
+ const AutofillProfile empty_profile;
+ // Test prioritization: profile > variation service state > app locale
+ EXPECT_EQ(FormDataImporter::GetPredictedCountryCode(us_profile, "DE", "de-AT",
+ nullptr),
+ "US");
+ EXPECT_EQ(FormDataImporter::GetPredictedCountryCode(us_profile, "", "de-AT",
+ nullptr),
+ "US");
+ EXPECT_EQ(FormDataImporter::GetPredictedCountryCode(empty_profile, "DE",
+ "de-AT", nullptr),
+ "DE");
+ EXPECT_EQ(FormDataImporter::GetPredictedCountryCode(empty_profile, "",
+ "de-AT", nullptr),
+ "AT");
+}
+
+TEST_P(FormDataImporterTest, ComplementCountry) {
+ base::test::ScopedFeatureList complement_country_feature;
+ complement_country_feature.InitAndEnableFeature(
+ features::kAutofillComplementCountryCodeOnImport);
+
+ auto import_with_country =
+ [this](const std::string& form_country,
+ const std::vector<AutofillProfile>& expected_profiles) {
+ // Remove existing profiles, to prevent an update instead of an import.
+ personal_data_manager_->ClearAllLocalData();
+
+ std::unique_ptr<FormStructure> form_structure =
+ form_country.empty()
+ ? ConstructDefaultProfileFormStructure()
+ : ConstructDefaultProfileFormStructureWithCountry(form_country);
+ ImportAddressProfilesAndVerifyExpectation(*form_structure,
+ expected_profiles);
+ };
+
+ // Country part of the form:
+ // If a valid country was entered, use that.
+ import_with_country("Germany", {ConstructDefaultProfileWithCountry("DE")});
+ // Reject the profile if an invalid country was entered.
+ import_with_country("Somewhere", {});
+ // Country not part of the form: Complement using
+ // FormDataImporter::GetPredictedCountryCode
+ // If no variation config country code is available, default to locale (US)
+ import_with_country("", {ConstructDefaultProfileWithCountry("US")});
+ // Prefer variation config country code over locale
+ autofill_client_->SetVariationConfigCountryCode("DE");
+ import_with_country("", {ConstructDefaultProfileWithCountry("DE")});
+}
+
// ImportAddressProfiles tests.
TEST_P(FormDataImporterTest, ImportStructuredNameProfile) {
base::test::ScopedFeatureList structured_addresses_feature;
@@ -793,10 +878,6 @@ TEST_P(
TEST_P(FormDataImporterTest,
ImportStructuredAddressProfile_GermanStreetNameAndHouseNumber) {
- // This test is only applicable if structured addresses are enabled.
- if (!StructuredAddresses())
- return;
-
FormData form;
form.url = GURL("https://wwww.foo.com");
@@ -1088,7 +1169,20 @@ TEST_P(FormDataImporterTest,
std::unique_ptr<FormStructure> form_structure =
ConstructFormStructureFromFormData(form_data);
- ImportAddressProfileAndVerifyImportOfDefaultProfile(*form_structure);
+
+ ImportAddressProfilesAndVerifyExpectation(
+ *form_structure,
+ {ConstructProfileFromTypeValuePairs(
+ {{NAME_FIRST, kDefaultFirstName},
+ {NAME_LAST, kDefaultLastName},
+ {EMAIL_ADDRESS, kDefaultMail},
+ // Note that this formatting is without a country code.
+ {PHONE_HOME_WHOLE_NUMBER, kDefaultPhoneDomesticFormatting},
+ {ADDRESS_HOME_DEPENDENT_LOCALITY, kDefaultDependentLocality},
+ {ADDRESS_HOME_LINE1, kDefaultAddressLine1},
+ {ADDRESS_HOME_CITY, kDefaultCity},
+ {ADDRESS_HOME_STATE, kDefaultState},
+ {ADDRESS_HOME_ZIP, kDefaultZip}})});
}
// Tests that not enough filled fields will result in not importing an address.
@@ -1178,7 +1272,18 @@ TEST_P(FormDataImporterTest,
std::unique_ptr<FormStructure> form_structure =
ConstructFormStructureFromFormData(form_data);
- ImportAddressProfileAndVerifyImportOfDefaultProfile(*form_structure);
+ ImportAddressProfilesAndVerifyExpectation(
+ *form_structure,
+ {ConstructProfileFromTypeValuePairs(
+ {{NAME_FIRST, kDefaultFirstName},
+ {NAME_LAST, kDefaultLastName},
+ {EMAIL_ADDRESS, kDefaultMail},
+ {PHONE_HOME_WHOLE_NUMBER, kDefaultPhoneDomesticFormatting},
+ {ADDRESS_HOME_LINE1, kDefaultAddressLine1},
+ {ADDRESS_HOME_DEPENDENT_LOCALITY, kDefaultDependentLocality},
+ {ADDRESS_HOME_CITY, kDefaultCity},
+ {ADDRESS_HOME_STATE, kDefaultState},
+ {ADDRESS_HOME_ZIP, kDefaultZip}})});
}
TEST_P(FormDataImporterTest, ImportAddressProfiles_UnFocussableFields) {
@@ -1247,13 +1352,14 @@ TEST_P(FormDataImporterTest, ImportAddressProfiles_TwoValidProfilesSameForm) {
std::vector<std::pair<ServerFieldType, std::string>>
profile_type_value_pairs = GetDefaultProfileTypeValuePairs();
std::vector<std::pair<ServerFieldType, std::string>>
- second_profile_type_value_pairs = GetDefaultProfileTypeValuePairs();
+ second_profile_type_value_pairs = GetSecondProfileTypeValuePairs();
// Now combine the two vectors and construct the single FormStructure that
// holds both profiles.
profile_type_value_pairs.insert(profile_type_value_pairs.end(),
second_profile_type_value_pairs.begin(),
second_profile_type_value_pairs.end());
+
std::unique_ptr<FormStructure> form_structure =
ConstructFormStructureFromTypeValuePairs(profile_type_value_pairs);
@@ -1283,15 +1389,18 @@ TEST_P(FormDataImporterTest,
}
// A maximum of two address profiles are imported per form.
-TEST_P(FormDataImporterTest, ImportAddressProfiles_ThreeValidProfilesSameForm) {
+// This test is flaky for an unknown reason.
+// TODO(crbug.com/1297212): Understand flakiness.
+TEST_P(FormDataImporterTest,
+ DISABLED_ImportAddressProfiles_ThreeValidProfilesSameForm) {
std::vector<std::pair<ServerFieldType, std::string>>
profile_type_value_pairs = GetDefaultProfileTypeValuePairs();
std::vector<std::pair<ServerFieldType, std::string>>
- second_profile_type_value_pairs = GetDefaultProfileTypeValuePairs();
+ second_profile_type_value_pairs = GetSecondProfileTypeValuePairs();
std::vector<std::pair<ServerFieldType, std::string>>
- third_profile_type_value_pairs = GetDefaultProfileTypeValuePairs();
+ third_profile_type_value_pairs = GetThirdProfileTypeValuePairs();
// Merge the type value pairs into one and construct the corresponding form
// structure.
@@ -1301,6 +1410,7 @@ TEST_P(FormDataImporterTest, ImportAddressProfiles_ThreeValidProfilesSameForm) {
profile_type_value_pairs.insert(profile_type_value_pairs.end(),
third_profile_type_value_pairs.begin(),
third_profile_type_value_pairs.end());
+
std::unique_ptr<FormStructure> form_structure =
ConstructFormStructureFromTypeValuePairs(profile_type_value_pairs);
@@ -1318,7 +1428,7 @@ TEST_P(FormDataImporterTest, ImportAddressProfiles_SameProfileWithConflict) {
{ADDRESS_HOME_CITY, kDefaultCity},
{ADDRESS_HOME_STATE, kDefaultState},
{ADDRESS_HOME_ZIP, kDefaultZip},
- {PHONE_HOME_WHOLE_NUMBER, kDefaultPhone},
+ {PHONE_HOME_WHOLE_NUMBER, kDefaultPhoneDomesticFormatting},
});
AutofillProfile initial_profile =
ConstructProfileFromTypeValuePairs(initial_type_value_pairs);
@@ -1347,13 +1457,25 @@ TEST_P(FormDataImporterTest, ImportAddressProfiles_SameProfileWithConflict) {
// Verify that the initial profile and the conflicting profile are not the
// same.
ASSERT_FALSE(initial_profile.Compare(conflicting_profile) == 0);
-
std::unique_ptr<FormStructure> conflicting_form_structure =
ConstructFormStructureFromTypeValuePairs(conflicting_type_value_pairs);
+
+ std::vector<std::pair<ServerFieldType, std::string>>
+ resulting_type_value_pairs({{NAME_FULL, kDefaultFullName},
+ {ADDRESS_HOME_LINE1, kDefaultAddressLine1},
+ {ADDRESS_HOME_CITY, kDefaultCity},
+ {ADDRESS_HOME_STATE, kDefaultState},
+ {ADDRESS_HOME_ZIP, kDefaultZip},
+ // The phone number is spelled differently.
+ {PHONE_HOME_WHOLE_NUMBER, kDefaultPhone},
+ // Country information is added.
+ {ADDRESS_HOME_COUNTRY, "US"}});
+
// Verify that importing the conflicting profile will result in an update of
// the existing profile rather than creating a new one.
- ImportAddressProfilesAndVerifyExpectation(*conflicting_form_structure,
- {conflicting_profile});
+ ImportAddressProfilesAndVerifyExpectation(
+ *conflicting_form_structure,
+ {ConstructProfileFromTypeValuePairs(resulting_type_value_pairs)});
}
TEST_P(FormDataImporterTest, ImportAddressProfiles_MissingInfoInOld) {
@@ -2152,10 +2274,10 @@ TEST_P(FormDataImporterTest, ImportCreditCard_2DigitYear) {
"4111111111111111", "05", "2045");
}
-// Tests that a credit card is not extracted because the
-// card matches a masked server card.
+// Tests that a credit card is extracted when the card matches a masked server
+// card.
TEST_P(FormDataImporterTest,
- ImportCreditCard_DuplicateServerCards_MaskedCard_DontExtract) {
+ ImportCreditCard_DuplicateServerCards_ExtractMaskedCard) {
// Add a masked server card.
std::vector<CreditCard> server_cards;
server_cards.push_back(CreditCard(CreditCard::MASKED_SERVER_CARD, "a123"));
@@ -2182,12 +2304,15 @@ TEST_P(FormDataImporterTest,
form_structure.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card;
EXPECT_FALSE(ImportCreditCard(form_structure, false, &imported_credit_card));
- ASSERT_FALSE(imported_credit_card);
+ ASSERT_TRUE(imported_credit_card);
+ ASSERT_TRUE(imported_credit_card->record_type() ==
+ CreditCard::MASKED_SERVER_CARD);
}
-// Tests that a credit card is not extracted because it matches a full server
+// Tests that a credit card is extracted when it matches a full server
// card.
-TEST_P(FormDataImporterTest, ImportCreditCard_DuplicateServerCards_FullCard) {
+TEST_P(FormDataImporterTest,
+ ImportCreditCard_DuplicateServerCards_ExtractFullCard) {
// Add a full server card.
std::vector<CreditCard> server_cards;
server_cards.push_back(CreditCard(CreditCard::FULL_SERVER_CARD, "c789"));
@@ -2213,7 +2338,9 @@ TEST_P(FormDataImporterTest, ImportCreditCard_DuplicateServerCards_FullCard) {
form_structure.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card;
EXPECT_FALSE(ImportCreditCard(form_structure, false, &imported_credit_card));
- ASSERT_FALSE(imported_credit_card);
+ ASSERT_TRUE(imported_credit_card);
+ ASSERT_TRUE(imported_credit_card->record_type() ==
+ CreditCard::RecordType::FULL_SERVER_CARD);
}
TEST_P(FormDataImporterTest, ImportCreditCard_SameCreditCardWithConflict) {
@@ -2253,7 +2380,7 @@ TEST_P(FormDataImporterTest, ImportCreditCard_SameCreditCardWithConflict) {
form_structure2.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card2;
EXPECT_TRUE(ImportCreditCard(form_structure2, false, &imported_credit_card2));
- EXPECT_FALSE(imported_credit_card2);
+ EXPECT_TRUE(imported_credit_card2);
WaitForOnPersonalDataChanged();
@@ -2414,7 +2541,7 @@ TEST_P(FormDataImporterTest, ImportCreditCard_MissingInfoInNew) {
form_structure2.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card2;
EXPECT_TRUE(ImportCreditCard(form_structure2, false, &imported_credit_card2));
- EXPECT_FALSE(imported_credit_card2);
+ EXPECT_TRUE(imported_credit_card2);
// Since no refresh is expected, reload the data from the database to make
// sure no changes were written out.
@@ -2485,7 +2612,7 @@ TEST_P(FormDataImporterTest, ImportCreditCard_MissingInfoInOld) {
form_structure.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card;
EXPECT_TRUE(ImportCreditCard(form_structure, false, &imported_credit_card));
- EXPECT_FALSE(imported_credit_card);
+ EXPECT_TRUE(imported_credit_card);
WaitForOnPersonalDataChanged();
@@ -2528,7 +2655,7 @@ TEST_P(FormDataImporterTest, ImportCreditCard_SameCardWithSeparators) {
form_structure.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card;
EXPECT_TRUE(ImportCreditCard(form_structure, false, &imported_credit_card));
- EXPECT_FALSE(imported_credit_card);
+ EXPECT_TRUE(imported_credit_card);
// Since no refresh is expected, reload the data from the database to make
// sure no changes were written out.
@@ -2570,7 +2697,7 @@ TEST_P(FormDataImporterTest,
form_structure.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card;
EXPECT_TRUE(ImportCreditCard(form_structure, false, &imported_credit_card));
- ASSERT_FALSE(imported_credit_card);
+ ASSERT_TRUE(imported_credit_card);
// Since no refresh is expected, reload the data from the database to make
// sure no changes were written out.
@@ -2781,7 +2908,7 @@ TEST_P(FormDataImporterTest,
/*credit_card_autofill_enabled=*/true,
/*should_return_local_card=*/true, &imported_credit_card,
&imported_upi_id));
- ASSERT_FALSE(imported_credit_card);
+ ASSERT_TRUE(imported_credit_card);
// |imported_credit_card_record_type_| should be SERVER_CARD.
ASSERT_TRUE(form_data_importer_->imported_credit_card_record_type_ ==
FormDataImporter::ImportedCreditCardRecordType::SERVER_CARD);
@@ -2819,7 +2946,7 @@ TEST_P(FormDataImporterTest,
/*credit_card_autofill_enabled=*/true,
/*should_return_local_card=*/true, &imported_credit_card,
&imported_upi_id));
- ASSERT_FALSE(imported_credit_card);
+ ASSERT_TRUE(imported_credit_card);
// |imported_credit_card_record_type_| should be SERVER_CARD.
ASSERT_TRUE(form_data_importer_->imported_credit_card_record_type_ ==
FormDataImporter::ImportedCreditCardRecordType::SERVER_CARD);
@@ -3000,8 +3127,7 @@ TEST_P(FormDataImporterTest, ImportFormData_OneAddressOneCreditCard) {
AutofillProfile expected_address(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&expected_address, "George", nullptr, "Washington",
"theprez@gmail.com", nullptr, "21 Laussat St", nullptr,
- "San Francisco", "California", "94102", nullptr,
- nullptr);
+ "San Francisco", "California", "94102", "", nullptr);
const std::vector<AutofillProfile*>& results_addr =
personal_data_manager_->GetProfiles();
ASSERT_EQ(1U, results_addr.size());
@@ -3262,8 +3388,7 @@ TEST_P(FormDataImporterTest, ImportFormData_OneAddressCreditCardDisabled) {
AutofillProfile expected_address(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&expected_address, "George", nullptr, "Washington",
"theprez@gmail.com", nullptr, "21 Laussat St", nullptr,
- "San Francisco", "California", "94102", nullptr,
- nullptr);
+ "San Francisco", "California", "94102", "", nullptr);
const std::vector<AutofillProfile*>& results_addr =
personal_data_manager_->GetProfiles();
ASSERT_EQ(1U, results_addr.size());
@@ -3327,7 +3452,7 @@ TEST_P(FormDataImporterTest, ImportFormData_AddressCreditCardDisabled) {
ASSERT_EQ(0U, results_cards.size());
}
-TEST_P(FormDataImporterTest, DontDuplicateMaskedServerCard) {
+TEST_P(FormDataImporterTest, DuplicateMaskedServerCard) {
std::vector<CreditCard> server_cards;
server_cards.push_back(CreditCard(CreditCard::MASKED_SERVER_CARD, "a123"));
test::SetCreditCardInfo(&server_cards.back(), "John Dillinger",
@@ -3372,7 +3497,7 @@ TEST_P(FormDataImporterTest, DontDuplicateMaskedServerCard) {
/*credit_card_autofill_enabled=*/true,
/*should_return_local_card=*/false, &imported_credit_card,
&imported_upi_id));
- ASSERT_FALSE(imported_credit_card);
+ ASSERT_TRUE(imported_credit_card);
}
// Tests that a credit card form that is hidden after receiving input still
@@ -3450,7 +3575,8 @@ TEST_P(FormDataImporterTest,
ASSERT_FALSE(imported_upi_id.has_value());
}
-TEST_P(FormDataImporterTest, DontDuplicateFullServerCard) {
+TEST_P(FormDataImporterTest,
+ DuplicateFullServerCardWhileContainingLocalCardCopies) {
std::vector<CreditCard> server_cards;
server_cards.push_back(CreditCard(CreditCard::MASKED_SERVER_CARD, "a123"));
test::SetCreditCardInfo(&server_cards.back(), "John Dillinger",
@@ -3464,10 +3590,24 @@ TEST_P(FormDataImporterTest, DontDuplicateFullServerCard) {
test::SetServerCreditCards(autofill_table_, server_cards);
+ // Add two local cards to the credit cards to ensure that in the case where we
+ // have separate copies of a server card and a local card, we still only set
+ // |imported_credit_card| to the server card details as we want the server
+ // to be the source of truth. Adding two cards also helps us ensure that we
+ // will update both.
+ for (int i = 0; i < 2; i++) {
+ CreditCard local_card = test::GetCreditCard();
+ test::SetCreditCardInfo(&local_card, "Clyde Barrow",
+ "378282246310005" /* American Express */, "05",
+ "2999", "1");
+ local_card.set_record_type(CreditCard::RecordType::LOCAL_CARD);
+ personal_data_manager_->AddCreditCard(local_card);
+ }
+
// Make sure everything is set up correctly.
personal_data_manager_->Refresh();
WaitForOnPersonalDataChanged();
- EXPECT_EQ(2U, personal_data_manager_->GetCreditCards().size());
+ EXPECT_EQ(4U, personal_data_manager_->GetCreditCards().size());
// A user re-types (or fills with) an unmasked card. Don't offer to save
// here, either. Since it's unmasked, we know for certain that it's the same
@@ -3491,13 +3631,27 @@ TEST_P(FormDataImporterTest, DontDuplicateFullServerCard) {
form_structure.DetermineHeuristicTypes(nullptr, nullptr);
std::unique_ptr<CreditCard> imported_credit_card;
absl::optional<std::string> imported_upi_id;
- EXPECT_FALSE(ImportFormDataAndProcessAddressCandidates(
+ EXPECT_TRUE(ImportFormDataAndProcessAddressCandidates(
form_structure,
/*profile_autofill_enabled=*/true,
/*credit_card_autofill_enabled=*/true,
/*should_return_local_card=*/false, &imported_credit_card,
&imported_upi_id));
- EXPECT_FALSE(imported_credit_card);
+ EXPECT_TRUE(imported_credit_card);
+ // Ensure that we imported the server version of the card, not the local
+ // version.
+ EXPECT_TRUE(imported_credit_card->record_type() ==
+ CreditCard::FULL_SERVER_CARD);
+
+ // Check that both of the local cards we have added were updated.
+ int matched_local_cards = 0;
+ for (const CreditCard* card : personal_data_manager_->GetCreditCards()) {
+ if (card->record_type() == CreditCard::RecordType::LOCAL_CARD) {
+ matched_local_cards++;
+ EXPECT_EQ(card->expiration_month(), 4);
+ }
+ }
+ EXPECT_EQ(matched_local_cards, 2);
}
TEST_P(FormDataImporterTest,
@@ -3542,7 +3696,7 @@ TEST_P(FormDataImporterTest,
/*credit_card_autofill_enabled=*/true,
/*should_return_local_card=*/false, &imported_credit_card,
&imported_upi_id));
- EXPECT_FALSE(imported_credit_card);
+ EXPECT_TRUE(imported_credit_card);
histogram_tester.ExpectUniqueSample(
"Autofill.SubmittedServerCardExpirationStatus",
AutofillMetrics::FULL_SERVER_CARD_EXPIRATION_DATE_MATCHED, 1);
@@ -3730,7 +3884,7 @@ TEST_P(FormDataImporterTest,
/*credit_card_autofill_enabled=*/true,
/*should_return_local_card=*/false, &imported_credit_card,
&imported_upi_id));
- EXPECT_FALSE(imported_credit_card);
+ EXPECT_TRUE(imported_credit_card);
histogram_tester.ExpectUniqueSample(
"Autofill.SubmittedServerCardExpirationStatus",
AutofillMetrics::FULL_SERVER_CARD_EXPIRATION_DATE_DID_NOT_MATCH, 1);
@@ -3779,7 +3933,7 @@ TEST_P(FormDataImporterTest,
/*credit_card_autofill_enabled=*/true,
/*should_return_local_card=*/false, &imported_credit_card,
&imported_upi_id));
- EXPECT_FALSE(imported_credit_card);
+ EXPECT_TRUE(imported_credit_card);
histogram_tester.ExpectUniqueSample(
"Autofill.SubmittedServerCardExpirationStatus",
AutofillMetrics::MASKED_SERVER_CARD_EXPIRATION_DATE_MATCHED, 1);
@@ -3828,7 +3982,7 @@ TEST_P(FormDataImporterTest,
/*credit_card_autofill_enabled=*/true,
/*should_return_local_card=*/false, &imported_credit_card,
&imported_upi_id));
- EXPECT_FALSE(imported_credit_card);
+ EXPECT_TRUE(imported_credit_card);
histogram_tester.ExpectUniqueSample(
"Autofill.SubmittedServerCardExpirationStatus",
AutofillMetrics::MASKED_SERVER_CARD_EXPIRATION_DATE_DID_NOT_MATCH, 1);
@@ -3908,10 +4062,6 @@ TEST_P(FormDataImporterTest, ImportUpiIdIgnoreNonUpiId) {
}
TEST_P(FormDataImporterTest, SilentlyUpdateExistingProfileByIncompleteProfile) {
- // This test is only applicable when structured names are enabled.
- if (!StructuredNames())
- return;
-
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeature(
features::kAutofillSilentProfileUpdateForInsufficientImport);
@@ -3969,10 +4119,6 @@ TEST_P(FormDataImporterTest, SilentlyUpdateExistingProfileByIncompleteProfile) {
TEST_P(
FormDataImporterTest,
SilentlyUpdateExistingProfileByIncompleteProfile_DespiteDisallowedPrompts) {
- // This test is only applicable when structured names are enabled.
- if (!StructuredNames())
- return;
-
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitWithFeatures(
{features::kAutofillSilentProfileUpdateForInsufficientImport,
@@ -4032,10 +4178,6 @@ TEST_P(
}
TEST_P(FormDataImporterTest, UnusableIncompleteProfile) {
- // This test is only applicable when structured names are enabled.
- if (!StructuredNames())
- return;
-
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeature(
features::kAutofillSilentProfileUpdateForInsufficientImport);
@@ -4091,9 +4233,11 @@ TEST_P(FormDataImporterTest, UnusableIncompleteProfile) {
EXPECT_EQ(results[0]->GetRawInfo(NAME_LAST), u"Morrison");
}
-// Runs the suite with the feature |kAutofillSupportForMoreStructuredNames|,
-// |kAutofillSupportForMoreStructuredAddresses| and
-// |kAutofillEnableSupportForApartmentNumbers| enabled and disabled.
+// Runs the suite with the feature |kAutofillEnableSupportForApartmentNumbers|,
+// |kAutofillEnableDependentLocalityParsing| and
+// |kAutofillConsiderVariationCountryCodeForPhoneNumbers| enabled and disabled.
+// TODO(crbug.com/1295721): Remove
+// |kAutofillConsiderVariationCountryCodeForPhoneNumbers| when launched.
INSTANTIATE_TEST_SUITE_P(,
FormDataImporterTest,
testing::Combine(testing::Bool(),
diff --git a/chromium/components/autofill/core/browser/form_parsing/address_field.cc b/chromium/components/autofill/core/browser/form_parsing/address_field.cc
index a6a0d820ba9..0794e721b5e 100644
--- a/chromium/components/autofill/core/browser/form_parsing/address_field.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/address_field.cc
@@ -28,22 +28,53 @@ bool SetFieldAndAdvanceCursor(AutofillScanner* scanner, AutofillField** field) {
return true;
}
-} // namespace
+// Removes the |attribute| from all |patterns|.
+// TODO(crbug/1142936): This is necessary for
+// AddressField::ParseNameAndLabelSeparately().
+MatchParams WithoutAttribute(MatchParams match_type, MatchAttribute attribute) {
+ match_type.attributes.erase(attribute);
+ return match_type;
+}
+
+// Removes the |attribute| from all |patterns|.
+// TODO(crbug/1142936): This is necessary for
+// AddressField::ParseNameAndLabelSeparately().
+std::vector<MatchingPattern> WithoutAttribute(
+ std::vector<MatchingPattern> patterns,
+ MatchAttribute attribute) {
+ for (MatchingPattern& p : patterns)
+ p.match_field_attributes.erase(attribute);
+ return patterns;
+}
+
+// Adds the |field_type| to all |patterns|.
+// TODO(crbug/1142936): This is necessary for AddressField::ParseAddressLines()
+// and AddressField::Parse().
+std::vector<MatchingPattern> WithFieldType(
+ std::vector<MatchingPattern> patterns,
+ MatchFieldType field_type) {
+ for (MatchingPattern& p : patterns)
+ p.match_field_input_types.insert(field_type);
+ return patterns;
+}
// Some sites use type="tel" for zip fields (to get a numerical input).
// http://crbug.com/426958
-const int AddressField::kZipCodeMatchType =
- MATCH_DEFAULT | MATCH_TELEPHONE | MATCH_NUMBER;
+constexpr MatchParams kZipCodeMatchType =
+ kDefaultMatchParamsWith<MatchFieldType::kTelephone,
+ MatchFieldType::kNumber>;
-const int AddressField::kDependentLocalityMatchType =
- MATCH_DEFAULT | MATCH_SELECT | MATCH_SEARCH;
+constexpr MatchParams kDependentLocalityMatchType =
+ kDefaultMatchParamsWith<MatchFieldType::kSelect, MatchFieldType::kSearch>;
// Select fields are allowed here. This occurs on top-100 site rediff.com.
-const int AddressField::kCityMatchType =
- MATCH_DEFAULT | MATCH_SELECT | MATCH_SEARCH;
+constexpr MatchParams kCityMatchType =
+ kDefaultMatchParamsWith<MatchFieldType::kSelect, MatchFieldType::kSearch>;
-const int AddressField::kStateMatchType =
- MATCH_DEFAULT | MATCH_SELECT | MATCH_SEARCH;
+constexpr MatchParams kStateMatchType =
+ kDefaultMatchParamsWith<MatchFieldType::kSelect, MatchFieldType::kSearch>;
+
+} // namespace
std::unique_ptr<FormField> AddressField::Parse(
AutofillScanner* scanner,
@@ -89,9 +120,10 @@ std::unique_ptr<FormField> AddressField::Parse(
continue;
// Ignore email addresses.
} else if (ParseFieldSpecifics(
- scanner, kEmailRe, MATCH_DEFAULT | MATCH_TEXT_AREA,
- email_patterns, nullptr, {log_manager, "kEmailRe"},
- {.augment_types = MATCH_TEXT_AREA})) {
+ scanner, kEmailRe,
+ kDefaultMatchParamsWith<MatchFieldType::kTextArea>,
+ WithFieldType(email_patterns, MatchFieldType::kTextArea),
+ nullptr, {log_manager, "kEmailRe"})) {
continue;
} else if (address_field->ParseAddress(scanner, page_language) ||
address_field->ParseDependentLocalityCityStateCountryZipCode(
@@ -230,13 +262,15 @@ bool AddressField::ParseAddressFieldSequence(
while (!scanner->IsEnd()) {
if (!street_name_ &&
ParseFieldSpecifics(scanner, kStreetNameRe,
- MATCH_DEFAULT | MATCH_SEARCH, street_name_patterns,
- &street_name_, {log_manager_, "kStreetNameRe"})) {
+ kDefaultMatchParamsWith<MatchFieldType::kSearch>,
+ street_name_patterns, &street_name_,
+ {log_manager_, "kStreetNameRe"})) {
continue;
}
if (!house_number_ &&
ParseFieldSpecifics(scanner, kHouseNumberRe,
- MATCH_DEFAULT | MATCH_NUMBER | MATCH_TELEPHONE,
+ kDefaultMatchParamsWith<MatchFieldType::kNumber,
+ MatchFieldType::kTelephone>,
house_number_patterns, &house_number_,
{log_manager_, "kHouseNumberRe"})) {
continue;
@@ -247,7 +281,8 @@ bool AddressField::ParseAddressFieldSequence(
features::kAutofillEnableSupportForApartmentNumbers) &&
!apartment_number_ &&
ParseFieldSpecifics(scanner, kApartmentNumberRe,
- MATCH_DEFAULT | MATCH_NUMBER | MATCH_TELEPHONE,
+ kDefaultMatchParamsWith<MatchFieldType::kNumber,
+ MatchFieldType::kTelephone>,
apartment_number_patterns, &apartment_number_,
{log_manager_, "kApartmentNumberRe"})) {
continue;
@@ -298,24 +333,34 @@ bool AddressField::ParseAddressLines(AutofillScanner* scanner,
PatternProvider::GetInstance().GetMatchPatterns("ADDRESS_LINE_1",
page_language);
- if (!ParseFieldSpecifics(scanner, pattern, MATCH_DEFAULT | MATCH_SEARCH,
+ // TODO(crbug.com/1121990): Remove duplicate calls when launching
+ // AutofillParsingPatternProvider. The old code calls ParseFieldSpecifics()
+ // for two different patterns, |pattern| and |label_pattern|. The new code
+ // handles both patterns at once in the |address_line1_patterns|.
+ if (!ParseFieldSpecifics(scanner, pattern,
+ kDefaultMatchParamsWith<MatchFieldType::kSearch>,
address_line1_patterns, &address1_,
{log_manager_, "kAddressLine1Re"}) &&
- !ParseFieldSpecifics(scanner, label_pattern,
- MATCH_LABEL | MATCH_SEARCH | MATCH_TEXT,
- address_line1_patterns, &address1_,
- {log_manager_, "kAddressLine1LabelRe"}) &&
- !ParseFieldSpecifics(scanner, pattern,
- MATCH_DEFAULT | MATCH_SEARCH | MATCH_TEXT_AREA,
- address_line1_patterns, &street_address_,
- {log_manager_, "kAddressLine1Re"},
- {.augment_types = MATCH_TEXT_AREA}) &&
- !ParseFieldSpecifics(scanner, label_pattern,
- MATCH_LABEL | MATCH_SEARCH | MATCH_TEXT_AREA,
- address_line1_patterns, &street_address_,
- {log_manager_, "kAddressLine1LabelRe"},
- {.augment_types = MATCH_TEXT_AREA}))
+ !ParseFieldSpecifics(
+ scanner, label_pattern,
+ MatchParams({MatchAttribute::kLabel},
+ {MatchFieldType::kSearch, MatchFieldType::kText}),
+ address_line1_patterns, &address1_,
+ {log_manager_, "kAddressLine1LabelRe"}) &&
+ !ParseFieldSpecifics(
+ scanner, pattern,
+ kDefaultMatchParamsWith<MatchFieldType::kSearch,
+ MatchFieldType::kTextArea>,
+ WithFieldType(address_line1_patterns, MatchFieldType::kTextArea),
+ &street_address_, {log_manager_, "kAddressLine1Re"}) &&
+ !ParseFieldSpecifics(
+ scanner, label_pattern,
+ MatchParams({MatchAttribute::kLabel},
+ {MatchFieldType::kSearch, MatchFieldType::kTextArea}),
+ WithFieldType(address_line1_patterns, MatchFieldType::kTextArea),
+ &street_address_, {log_manager_, "kAddressLine1LabelRe"})) {
return false;
+ }
if (street_address_)
return true;
@@ -332,9 +377,11 @@ bool AddressField::ParseAddressLines(AutofillScanner* scanner,
if (!ParseField(scanner, pattern, address_line2_patterns, &address2_,
{log_manager_, "kAddressLine2Re"}) &&
- !ParseFieldSpecifics(scanner, label_pattern, MATCH_LABEL | MATCH_TEXT,
- address_line2_patterns, &address2_,
- {log_manager_, "kAddressLine2LabelRe"}))
+ !ParseFieldSpecifics(
+ scanner, label_pattern,
+ MatchParams({MatchAttribute::kLabel}, {MatchFieldType::kText}),
+ address_line2_patterns, &address2_,
+ {log_manager_, "kAddressLine2LabelRe"}))
return true;
const std::vector<MatchingPattern>& address_line_extra_patterns =
@@ -346,10 +393,13 @@ bool AddressField::ParseAddressLines(AutofillScanner* scanner,
pattern = kAddressLinesExtraRe;
if (!ParseField(scanner, pattern, address_line_extra_patterns, &address3_,
{log_manager_, "kAddressLinesExtraRe"}) &&
- !ParseFieldSpecifics(scanner, label_pattern, MATCH_LABEL | MATCH_TEXT,
- address_line2_patterns, &address3_,
- {log_manager_, "kAddressLine2LabelRe"}))
+ !ParseFieldSpecifics(
+ scanner, label_pattern,
+ MatchParams({MatchAttribute::kLabel}, {MatchFieldType::kText}),
+ address_line2_patterns, &address3_,
+ {log_manager_, "kAddressLine2LabelRe"})) {
return true;
+ }
// Try for surplus lines, which we will promptly discard. Some pages have 4
// address lines (e.g. uk/ShoesDirect2.html)!
@@ -376,9 +426,11 @@ bool AddressField::ParseCountry(AutofillScanner* scanner,
page_language);
scanner->SaveCursor();
- if (ParseFieldSpecifics(
- scanner, kCountryRe, MATCH_DEFAULT | MATCH_SELECT | MATCH_SEARCH,
- country_patterns, &country_, {log_manager_, "kCountryRe"})) {
+ if (ParseFieldSpecifics(scanner, kCountryRe,
+ kDefaultMatchParamsWith<MatchFieldType::kSelect,
+ MatchFieldType::kSearch>,
+ country_patterns, &country_,
+ {log_manager_, "kCountryRe"})) {
return true;
}
@@ -387,8 +439,9 @@ bool AddressField::ParseCountry(AutofillScanner* scanner,
scanner->Rewind();
return ParseFieldSpecifics(
scanner, kCountryLocationRe,
- MATCH_LABEL | MATCH_NAME | MATCH_SELECT | MATCH_SEARCH, country_patternsl,
- &country_, {log_manager_, "kCountryLocationRe"});
+ MatchParams({MatchAttribute::kLabel, MatchAttribute::kName},
+ {MatchFieldType::kSelect, MatchFieldType::kSearch}),
+ country_patternsl, &country_, {log_manager_, "kCountryLocationRe"});
}
bool AddressField::ParseZipCode(AutofillScanner* scanner,
@@ -459,7 +512,7 @@ bool AddressField::ParseState(AutofillScanner* scanner,
AddressField::ParseNameLabelResult AddressField::ParseNameAndLabelSeparately(
AutofillScanner* scanner,
const std::u16string& pattern,
- int match_type,
+ MatchParams match_type,
const std::vector<MatchingPattern>& patterns,
AutofillField** match,
const RegExLogging& logging) {
@@ -469,12 +522,12 @@ AddressField::ParseNameLabelResult AddressField::ParseNameAndLabelSeparately(
AutofillField* cur_match = nullptr;
size_t saved_cursor = scanner->SaveCursor();
bool parsed_name = ParseFieldSpecifics(
- scanner, pattern, match_type & ~MATCH_LABEL, patterns, &cur_match,
- logging, {.restrict_attributes = MATCH_NAME});
+ scanner, pattern, WithoutAttribute(match_type, MatchAttribute::kLabel),
+ WithoutAttribute(patterns, MatchAttribute::kLabel), &cur_match, logging);
scanner->RewindTo(saved_cursor);
bool parsed_label = ParseFieldSpecifics(
- scanner, pattern, match_type & ~MATCH_NAME, patterns, &cur_match, logging,
- {.restrict_attributes = MATCH_LABEL});
+ scanner, pattern, WithoutAttribute(match_type, MatchAttribute::kName),
+ WithoutAttribute(patterns, MatchAttribute::kName), &cur_match, logging);
if (parsed_name && parsed_label) {
if (match)
*match = cur_match;
@@ -699,7 +752,8 @@ AddressField::ParseNameLabelResult AddressField::ParseNameAndLabelForCountry(
page_language);
ParseNameLabelResult country_result = ParseNameAndLabelSeparately(
- scanner, kCountryRe, MATCH_DEFAULT | MATCH_SELECT | MATCH_SEARCH,
+ scanner, kCountryRe,
+ kDefaultMatchParamsWith<MatchFieldType::kSelect, MatchFieldType::kSearch>,
country_patterns, &country_, {log_manager_, "kCountryRe"});
if (country_result != RESULT_MATCH_NONE)
return country_result;
@@ -708,7 +762,8 @@ AddressField::ParseNameLabelResult AddressField::ParseNameAndLabelForCountry(
// "location". However, this only makes sense for select tags.
return ParseNameAndLabelSeparately(
scanner, kCountryLocationRe,
- MATCH_LABEL | MATCH_NAME | MATCH_SELECT | MATCH_SEARCH,
+ MatchParams({MatchAttribute::kLabel, MatchAttribute::kName},
+ {MatchFieldType::kSelect, MatchFieldType::kSearch}),
country_location_patterns, &country_,
{log_manager_, "kCountryLocationRe"});
}
diff --git a/chromium/components/autofill/core/browser/form_parsing/address_field.h b/chromium/components/autofill/core/browser/form_parsing/address_field.h
index 72b1d0d8523..5757fdd5479 100644
--- a/chromium/components/autofill/core/browser/form_parsing/address_field.h
+++ b/chromium/components/autofill/core/browser/form_parsing/address_field.h
@@ -44,11 +44,6 @@ class AddressField : public FormField {
RESULT_MATCH_NAME_LABEL // Name and label both match the pattern.
};
- static const int kZipCodeMatchType;
- static const int kCityMatchType;
- static const int kStateMatchType;
- static const int kDependentLocalityMatchType;
-
explicit AddressField(LogManager* log_manager);
bool ParseCompany(AutofillScanner* scanner,
@@ -91,7 +86,7 @@ class AddressField : public FormField {
ParseNameLabelResult ParseNameAndLabelSeparately(
AutofillScanner* scanner,
const std::u16string& pattern,
- int match_type,
+ MatchParams match_type,
const std::vector<MatchingPattern>& patterns,
AutofillField** match,
const RegExLogging& logging);
diff --git a/chromium/components/autofill/core/browser/form_parsing/autofill_parsing_utils.h b/chromium/components/autofill/core/browser/form_parsing/autofill_parsing_utils.h
index d300e746bd3..022aa02942f 100644
--- a/chromium/components/autofill/core/browser/form_parsing/autofill_parsing_utils.h
+++ b/chromium/components/autofill/core/browser/form_parsing/autofill_parsing_utils.h
@@ -7,38 +7,76 @@
#include <string>
+#include "components/autofill/core/common/dense_set.h"
#include "components/autofill/core/common/language_code.h"
namespace autofill {
-// A bit-field used for matching specific parts of a field in question.
-// Attributes.
-enum MatchAttributes {
- MATCH_LABEL = 1 << 0,
- MATCH_NAME = 1 << 1,
- MATCH_ATTRIBUTES_DEFAULT = MATCH_LABEL | MATCH_NAME,
+// The sources from which strings are matched: the field's label or its name or
+// id attribute value.
+//
+// For example, in
+// <label for="mobile">Cellphone number:</label> <input type="tel" id="mobile">
+// the kLabel is "Cellphone number" and the kName is "mobile".
+enum class MatchAttribute { kLabel, kName, kMaxValue = kName };
+
+// The types of fields which may be matched.
+//
+// For example, in
+// <label for="mobile">Cellphone number:</label> <input type="tel" id="mobile">
+// the MatchFieldType is kTelephone.
+enum class MatchFieldType {
+ kText,
+ kEmail,
+ kTelephone,
+ kSelect,
+ kTextArea,
+ kPassword,
+ kNumber,
+ kSearch,
+ kMaxValue = kSearch
};
-// A bit-field used for matching specific parts of a field in question.
-// Input types.
-enum MatchFieldTypes {
- MATCH_TEXT = 1 << 2,
- MATCH_EMAIL = 1 << 3,
- MATCH_TELEPHONE = 1 << 4,
- MATCH_SELECT = 1 << 5,
- MATCH_TEXT_AREA = 1 << 6,
- MATCH_PASSWORD = 1 << 7,
- MATCH_NUMBER = 1 << 8,
- MATCH_SEARCH = 1 << 9,
- MATCH_ALL_INPUTS = MATCH_TEXT | MATCH_EMAIL | MATCH_TELEPHONE | MATCH_SELECT |
- MATCH_TEXT_AREA | MATCH_PASSWORD | MATCH_NUMBER |
- MATCH_SEARCH,
-
- // By default match label and name for input/text types.
- MATCH_INPUTS_DEFAULT = MATCH_TEXT,
+// Contains all MatchAttribute constants.
+constexpr DenseSet<MatchAttribute> kAllMatchAttributes{MatchAttribute::kLabel,
+ MatchAttribute::kName};
+
+// Contains all MatchFieldType constants.
+constexpr DenseSet<MatchFieldType> kAllMatchFieldTypes{
+ MatchFieldType::kText, MatchFieldType::kEmail,
+ MatchFieldType::kTelephone, MatchFieldType::kSelect,
+ MatchFieldType::kTextArea, MatchFieldType::kPassword,
+ MatchFieldType::kNumber, MatchFieldType::kSearch};
+
+// A pair of sets of MatchAttributes and MatchFieldTypes.
+struct MatchParams {
+ inline constexpr MatchParams(DenseSet<MatchAttribute> attributes,
+ DenseSet<MatchFieldType> field_types);
+ inline constexpr MatchParams(const MatchParams&);
+ inline constexpr MatchParams& operator=(const MatchParams&);
+ inline constexpr MatchParams(MatchParams&&);
+ inline constexpr MatchParams& operator=(MatchParams&&);
+
+ DenseSet<MatchAttribute> attributes;
+ DenseSet<MatchFieldType> field_types;
};
-constexpr int MATCH_DEFAULT = MATCH_ATTRIBUTES_DEFAULT | MATCH_INPUTS_DEFAULT;
+inline constexpr MatchParams::MatchParams(DenseSet<MatchAttribute> attributes,
+ DenseSet<MatchFieldType> field_types)
+ : attributes(attributes), field_types(field_types) {}
+inline constexpr MatchParams::MatchParams(const MatchParams&) = default;
+inline constexpr MatchParams& MatchParams::operator=(const MatchParams&) =
+ default;
+inline constexpr MatchParams::MatchParams(MatchParams&&) = default;
+inline constexpr MatchParams& MatchParams::operator=(MatchParams&&) = default;
+
+// By default match label and name for <input type="text"> elements.
+template <MatchFieldType... additional_match_field_types>
+constexpr MatchParams kDefaultMatchParamsWith{
+ kAllMatchAttributes,
+ {MatchFieldType::kText, additional_match_field_types...}};
+
+constexpr MatchParams kDefaultMatchParams = kDefaultMatchParamsWith<>;
// Structure for a better organization of data and regular expressions
// for autofill regex_constants. In the future, to implement faster
@@ -56,8 +94,8 @@ struct MatchingPattern {
std::u16string positive_pattern;
std::u16string negative_pattern;
float positive_score = 1.1;
- uint8_t match_field_attributes;
- uint16_t match_field_input_types;
+ DenseSet<MatchAttribute> match_field_attributes;
+ DenseSet<MatchFieldType> match_field_input_types;
};
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/form_parsing/credit_card_field.cc b/chromium/components/autofill/core/browser/form_parsing/credit_card_field.cc
index 21bd0b84926..adad0bc95f4 100644
--- a/chromium/components/autofill/core/browser/form_parsing/credit_card_field.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/credit_card_field.cc
@@ -147,8 +147,10 @@ std::unique_ptr<FormField> CreditCardField::Parse(
// below.
// Note: Some sites use type="tel" or type="number" for numerical inputs.
// They also sometimes use type="password" for sensitive types.
- const int kMatchNumTelAndPwd =
- MATCH_DEFAULT | MATCH_NUMBER | MATCH_TELEPHONE | MATCH_PASSWORD;
+ const auto kMatchNumTelAndPwd =
+ kDefaultMatchParamsWith<MatchFieldType::kNumber,
+ MatchFieldType::kTelephone,
+ MatchFieldType::kPassword>;
if (!credit_card_field->verification_ &&
ParseFieldSpecifics(scanner, kCardCvcRe, kMatchNumTelAndPwd,
@@ -290,9 +292,11 @@ bool CreditCardField::LikelyCardMonthSelectField(AutofillScanner* scanner) {
return false;
AutofillField* field = scanner->Cursor();
- if (!MatchesFormControlType(field->form_control_type,
- MATCH_SELECT | MATCH_SEARCH))
+ if (!MatchesFormControlType(
+ field->form_control_type,
+ {MatchFieldType::kSelect, MatchFieldType::kSearch})) {
return false;
+ }
if (field->options.size() < 12 || field->options.size() > 13)
return false;
@@ -330,9 +334,11 @@ bool CreditCardField::LikelyCardYearSelectField(
return false;
AutofillField* field = scanner->Cursor();
- if (!MatchesFormControlType(field->form_control_type,
- MATCH_SELECT | MATCH_SEARCH))
+ if (!MatchesFormControlType(
+ field->form_control_type,
+ {MatchFieldType::kSelect, MatchFieldType::kSearch})) {
return false;
+ }
// Filter out days - elements for date entries would have
// numbers 1 to 9 as well in them, which we can filter on.
@@ -346,9 +352,9 @@ bool CreditCardField::LikelyCardYearSelectField(
// Another way to eliminate days - filter out 'day' fields.
const std::vector<MatchingPattern>& day_patterns =
PatternProvider::GetInstance().GetMatchPatterns("DAY", page_language);
- if (FormField::ParseFieldSpecifics(scanner, kDayRe,
- MATCH_DEFAULT | MATCH_SELECT, day_patterns,
- nullptr, {log_manager, "kDayRe"})) {
+ if (FormField::ParseFieldSpecifics(
+ scanner, kDayRe, kDefaultMatchParamsWith<MatchFieldType::kSelect>,
+ day_patterns, nullptr, {log_manager, "kDayRe"})) {
return false;
}
@@ -394,8 +400,9 @@ bool CreditCardField::LikelyCardTypeSelectField(AutofillScanner* scanner) {
AutofillField* field = scanner->Cursor();
- if (!MatchesFormControlType(field->form_control_type,
- MATCH_SELECT | MATCH_SEARCH))
+ if (!MatchesFormControlType(
+ field->form_control_type,
+ {MatchFieldType::kSelect, MatchFieldType::kSearch}))
return false;
// We set |ignore_whitespace| to true on these calls because this is actually
@@ -416,11 +423,12 @@ bool CreditCardField::IsGiftCardField(AutofillScanner* scanner,
if (scanner->IsEnd())
return false;
- // kMatchFieldTypes should subsume kMatchNumTelAndPwd used for
+ // kMatchFieldType should subsume kMatchNumTelAndPwd used for
// CREDIT_CARD_NUMBER matching. Otherwise, a gift card field may not match the
// GIFT_CARD pattern but erroneously do match the CREDIT_CARD_NUMBER pattern.
- const int kMatchFieldTypes = MATCH_DEFAULT | MATCH_NUMBER | MATCH_TELEPHONE |
- MATCH_SEARCH | MATCH_PASSWORD;
+ const auto kMatchFieldType = kDefaultMatchParamsWith<
+ MatchFieldType::kNumber, MatchFieldType::kTelephone,
+ MatchFieldType::kSearch, MatchFieldType::kPassword>;
size_t saved_cursor = scanner->SaveCursor();
const std::vector<MatchingPattern>& debit_cards_patterns =
@@ -435,20 +443,20 @@ bool CreditCardField::IsGiftCardField(AutofillScanner* scanner,
PatternProvider::GetInstance().GetMatchPatterns("GIFT_CARD",
page_language);
- if (ParseFieldSpecifics(scanner, kDebitCardRe, kMatchFieldTypes,
+ if (ParseFieldSpecifics(scanner, kDebitCardRe, kMatchFieldType,
debit_cards_patterns, nullptr,
{log_manager, "kDebitCardRe"})) {
scanner->RewindTo(saved_cursor);
return false;
}
- if (ParseFieldSpecifics(scanner, kDebitGiftCardRe, kMatchFieldTypes,
+ if (ParseFieldSpecifics(scanner, kDebitGiftCardRe, kMatchFieldType,
debit_gift_card_patterns, nullptr,
{log_manager, "kDebitGiftCardRe"})) {
scanner->RewindTo(saved_cursor);
return false;
}
- return ParseFieldSpecifics(scanner, kGiftCardRe, kMatchFieldTypes,
+ return ParseFieldSpecifics(scanner, kGiftCardRe, kMatchFieldType,
gift_card_patterns, nullptr,
{log_manager, "kGiftCardRe"});
}
@@ -538,8 +546,10 @@ bool CreditCardField::ParseExpirationDate(AutofillScanner* scanner,
// If that fails, do a general regex search.
scanner->RewindTo(month_year_saved_cursor);
- const int kMatchCCType = MATCH_DEFAULT | MATCH_NUMBER | MATCH_TELEPHONE |
- MATCH_SELECT | MATCH_SEARCH;
+ const auto kMatchCCType =
+ kDefaultMatchParamsWith<MatchFieldType::kNumber,
+ MatchFieldType::kTelephone,
+ MatchFieldType::kSelect, MatchFieldType::kSearch>;
const std::vector<MatchingPattern>& cc_exp_month_patterns =
PatternProvider::GetInstance().GetMatchPatterns(CREDIT_CARD_EXP_MONTH,
diff --git a/chromium/components/autofill/core/browser/form_parsing/email_field.cc b/chromium/components/autofill/core/browser/form_parsing/email_field.cc
index 00498313fe8..493261923fc 100644
--- a/chromium/components/autofill/core/browser/form_parsing/email_field.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/email_field.cc
@@ -17,7 +17,8 @@ std::unique_ptr<FormField> EmailField::Parse(AutofillScanner* scanner,
const std::vector<MatchingPattern>& email_patterns =
PatternProvider::GetInstance().GetMatchPatterns("EMAIL_ADDRESS",
page_language);
- if (ParseFieldSpecifics(scanner, kEmailRe, MATCH_DEFAULT | MATCH_EMAIL,
+ if (ParseFieldSpecifics(scanner, kEmailRe,
+ kDefaultMatchParamsWith<MatchFieldType::kEmail>,
email_patterns, &field, {log_manager, "kEmailRe"})) {
return std::make_unique<EmailField>(field);
}
diff --git a/chromium/components/autofill/core/browser/form_parsing/form_field.cc b/chromium/components/autofill/core/browser/form_parsing/form_field.cc
index 4932d8efa8b..322a2ab6181 100644
--- a/chromium/components/autofill/core/browser/form_parsing/form_field.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/form_field.cc
@@ -18,6 +18,7 @@
#include "components/autofill/core/browser/autofill_regexes.h"
#include "components/autofill/core/browser/autofill_type.h"
#include "components/autofill/core/browser/form_parsing/address_field.h"
+#include "components/autofill/core/browser/form_parsing/autofill_parsing_utils.h"
#include "components/autofill/core/browser/form_parsing/autofill_scanner.h"
#include "components/autofill/core/browser/form_parsing/credit_card_field.h"
#include "components/autofill/core/browser/form_parsing/email_field.h"
@@ -37,19 +38,6 @@
namespace autofill {
-// There's an implicit precedence determined by the values assigned here. Email
-// is currently the most important followed by Phone, Travel, Address,
-// Credit Card, Price, Name, Merchant promo code, and Search.
-const float FormField::kBaseEmailParserScore = 1.4f;
-const float FormField::kBasePhoneParserScore = 1.3f;
-const float FormField::kBaseTravelParserScore = 1.2f;
-const float FormField::kBaseAddressParserScore = 1.1f;
-const float FormField::kBaseCreditCardParserScore = 1.0f;
-const float FormField::kBasePriceParserScore = 0.95f;
-const float FormField::kBaseNameParserScore = 0.9f;
-const float FormField::kBaseMerchantPromoCodeParserScore = 0.85f;
-const float FormField::kBaseSearchParserScore = 0.8f;
-
// static
FieldCandidatesMap FormField::ParseFormFields(
const std::vector<std::unique_ptr<AutofillField>>& fields,
@@ -167,53 +155,35 @@ FieldCandidatesMap FormField::ParseFormFieldsForPromoCodes(
// static
bool FormField::ParseField(AutofillScanner* scanner,
base::StringPiece16 pattern,
- AutofillField** match,
- const RegExLogging& logging) {
- return ParseFieldSpecifics(scanner, pattern, MATCH_DEFAULT, match, logging);
-}
-
-bool FormField::ParseField(AutofillScanner* scanner,
const std::vector<MatchingPattern>& patterns,
AutofillField** match,
const RegExLogging& logging) {
- return ParseFieldSpecifics(scanner, patterns, match, logging);
+ return ParseFieldSpecifics(scanner, pattern, kDefaultMatchParams, patterns,
+ match, logging);
}
-bool FormField::ParseField(AutofillScanner* scanner,
- base::StringPiece16 pattern,
- const std::vector<MatchingPattern>& patterns,
- AutofillField** match,
- const RegExLogging& logging) {
- if (base::FeatureList::IsEnabled(
- features::kAutofillParsingPatternsLanguageDependent) ||
- base::FeatureList::IsEnabled(
- features::kAutofillParsingPatternsNegativeMatching)) {
- return ParseField(scanner, patterns, match, logging);
- } else {
- return ParseField(scanner, pattern, match, logging);
- }
-}
-
-bool FormField::ParseFieldSpecifics(AutofillScanner* scanner,
- base::StringPiece16 pattern,
- int match_field_attributes,
- int match_field_input_types,
- AutofillField** match,
- const RegExLogging& logging) {
+// static
+bool FormField::ParseFieldSpecificsWithLegacyPattern(
+ AutofillScanner* scanner,
+ base::StringPiece16 pattern,
+ MatchParams match_type,
+ AutofillField** match,
+ const RegExLogging& logging) {
if (scanner->IsEnd())
return false;
const AutofillField* field = scanner->Cursor();
if (!MatchesFormControlType(field->form_control_type,
- match_field_input_types))
+ match_type.field_types)) {
return false;
+ }
- return MatchAndAdvance(scanner, pattern, match_field_attributes,
- match_field_input_types, match, logging);
+ return MatchAndAdvance(scanner, pattern, match_type, match, logging);
}
-bool FormField::ParseFieldSpecifics(
+// static
+bool FormField::ParseFieldSpecificsWithNewPatterns(
AutofillScanner* scanner,
const std::vector<MatchingPattern>& patterns,
AutofillField** match,
@@ -229,74 +199,56 @@ bool FormField::ParseFieldSpecifics(
continue;
}
- // TODO(crbug.com/1132831): Remove feature check once launched.
- if (base::FeatureList::IsEnabled(
- features::kAutofillParsingPatternsNegativeMatching)) {
- if (!pattern.negative_pattern.empty() &&
- FormField::Match(field, pattern.negative_pattern,
- pattern.match_field_attributes,
- pattern.match_field_input_types, logging)) {
- continue;
+ // For each of the two match field attributes, kName and kLabel,
+ // that are active for the current pattern, test if it matches the negative
+ // pattern. If yes, remove it from the attributes that are considered for
+ // positive matching.
+ MatchParams match_type(pattern.match_field_attributes,
+ pattern.match_field_input_types);
+
+ if (!pattern.negative_pattern.empty()) {
+ for (MatchAttribute attribute : pattern.match_field_attributes) {
+ if (FormField::Match(field, pattern.negative_pattern,
+ MatchParams({attribute}, match_type.field_types),
+ logging)) {
+ match_type.attributes.erase(attribute);
+ }
}
}
+ if (match_type.attributes.empty())
+ continue;
+
+ // Apply the positive matching against all remaining match field attributes.
if (!pattern.positive_pattern.empty() &&
- MatchAndAdvance(scanner, pattern.positive_pattern,
- pattern.match_field_attributes,
- pattern.match_field_input_types, match, logging)) {
+ MatchAndAdvance(scanner, pattern.positive_pattern, match_type, match,
+ logging)) {
return true;
}
}
return false;
}
-// static
-bool FormField::ParseFieldSpecifics(AutofillScanner* scanner,
- base::StringPiece16 pattern,
- int match_type,
- AutofillField** match,
- const RegExLogging& logging) {
- int match_field_attributes = match_type & 0b11;
- int match_field_types = match_type & ~0b11;
-
- return ParseFieldSpecifics(scanner, pattern, match_field_attributes,
- match_field_types, match, logging);
-}
-
bool FormField::ParseFieldSpecifics(
AutofillScanner* scanner,
base::StringPiece16 pattern,
- int match_type,
+ const MatchParams& match_type,
const std::vector<MatchingPattern>& patterns,
AutofillField** match,
- const RegExLogging& logging,
- MatchFieldBitmasks match_field_bitmasks) {
- if (base::FeatureList::IsEnabled(
- features::kAutofillParsingPatternsLanguageDependent) ||
- base::FeatureList::IsEnabled(
- features::kAutofillParsingPatternsNegativeMatching)) {
- // TODO(crbug/1142936): This hack is to allow
- // AddressField::ParseNameAndLabelSeparately().
- if (match_field_bitmasks.restrict_attributes != ~0 ||
- match_field_bitmasks.augment_types != 0) {
- std::vector<MatchingPattern> modified_patterns = patterns;
- for (MatchingPattern& mp : modified_patterns) {
- mp.match_field_attributes &= match_field_bitmasks.restrict_attributes;
- mp.match_field_input_types |= match_field_bitmasks.augment_types;
- }
- return ParseFieldSpecifics(scanner, modified_patterns, match, logging);
- }
- return ParseFieldSpecifics(scanner, patterns, match, logging);
- } else {
- return ParseFieldSpecifics(scanner, pattern, match_type, match, logging);
- }
+ const RegExLogging& logging) {
+ return base::FeatureList::IsEnabled(features::kAutofillParsingPatternProvider)
+ ? ParseFieldSpecificsWithNewPatterns(scanner, patterns, match,
+ logging)
+ : ParseFieldSpecificsWithLegacyPattern(scanner, pattern,
+ match_type, match, logging);
}
// static
bool FormField::ParseEmptyLabel(AutofillScanner* scanner,
AutofillField** match) {
- return ParseFieldSpecifics(scanner, u"^$", MATCH_LABEL | MATCH_ALL_INPUTS,
- match);
+ return ParseFieldSpecificsWithLegacyPattern(
+ scanner, u"^$",
+ MatchParams({MatchAttribute::kLabel}, kAllMatchFieldTypes), match);
}
// static
@@ -333,15 +285,14 @@ std::vector<AutofillField*> FormField::RemoveCheckableFields(
return processed_fields;
}
+// static
bool FormField::MatchAndAdvance(AutofillScanner* scanner,
base::StringPiece16 pattern,
- int match_field_attributes,
- int match_field_input_types,
+ MatchParams match_type,
AutofillField** match,
const RegExLogging& logging) {
AutofillField* field = scanner->Cursor();
- if (FormField::Match(field, pattern, match_field_attributes,
- match_field_input_types, logging)) {
+ if (FormField::Match(field, pattern, match_type, logging)) {
if (match)
*match = field;
scanner->Advance();
@@ -351,23 +302,9 @@ bool FormField::MatchAndAdvance(AutofillScanner* scanner,
return false;
}
-// static
-bool FormField::MatchAndAdvance(AutofillScanner* scanner,
- base::StringPiece16 pattern,
- int match_type,
- AutofillField** match,
- const RegExLogging& logging) {
- int match_field_attributes = match_type & 0b11;
- int match_field_types = match_type & ~0b11;
-
- return MatchAndAdvance(scanner, pattern, match_field_attributes,
- match_field_types, match, logging);
-}
-
bool FormField::Match(const AutofillField* field,
base::StringPiece16 pattern,
- int match_field_attributes,
- int match_field_input_types,
+ MatchParams match_type,
const RegExLogging& logging) {
bool found_match = false;
base::StringPiece match_type_string;
@@ -383,12 +320,12 @@ bool FormField::Match(const AutofillField* field,
const std::u16string& name = field->parseable_name();
- if ((match_field_attributes & MATCH_LABEL) &&
+ if (match_type.attributes.contains(MatchAttribute::kLabel) &&
MatchesPattern(label, pattern, &match)) {
found_match = true;
match_type_string = "Match in label";
value = label;
- } else if ((match_field_attributes & MATCH_NAME) &&
+ } else if (match_type.attributes.contains(MatchAttribute::kName) &&
MatchesPattern(name, pattern, &match)) {
found_match = true;
match_type_string = "Match in name";
@@ -412,18 +349,6 @@ bool FormField::Match(const AutofillField* field,
}
// static
-bool FormField::Match(const AutofillField* field,
- base::StringPiece16 pattern,
- int match_type,
- const RegExLogging& logging) {
- int match_field_attributes = match_type & 0b11;
- int match_field_types = match_type & ~0b11;
-
- return Match(field, pattern, match_field_attributes, match_field_types,
- logging);
-}
-
-// static
void FormField::ParseFormFieldsPass(ParseFunction parse,
const std::vector<AutofillField*>& fields,
FieldCandidatesMap* field_candidates,
@@ -443,30 +368,31 @@ void FormField::ParseFormFieldsPass(ParseFunction parse,
}
}
-bool FormField::MatchesFormControlType(const std::string& type,
- int match_type) {
- if ((match_type & MATCH_TEXT) && type == "text")
+// static
+bool FormField::MatchesFormControlType(base::StringPiece type,
+ DenseSet<MatchFieldType> match_type) {
+ if (match_type.contains(MatchFieldType::kText) && type == "text")
return true;
- if ((match_type & MATCH_EMAIL) && type == "email")
+ if (match_type.contains(MatchFieldType::kEmail) && type == "email")
return true;
- if ((match_type & MATCH_TELEPHONE) && type == "tel")
+ if (match_type.contains(MatchFieldType::kTelephone) && type == "tel")
return true;
- if ((match_type & MATCH_SELECT) && type == "select-one")
+ if (match_type.contains(MatchFieldType::kSelect) && type == "select-one")
return true;
- if ((match_type & MATCH_TEXT_AREA) && type == "textarea")
+ if (match_type.contains(MatchFieldType::kTextArea) && type == "textarea")
return true;
- if ((match_type & MATCH_PASSWORD) && type == "password")
+ if (match_type.contains(MatchFieldType::kPassword) && type == "password")
return true;
- if ((match_type & MATCH_NUMBER) && type == "number")
+ if (match_type.contains(MatchFieldType::kNumber) && type == "number")
return true;
- if ((match_type & MATCH_SEARCH) && type == "search")
+ if (match_type.contains(MatchFieldType::kSearch) && type == "search")
return true;
return false;
diff --git a/chromium/components/autofill/core/browser/form_parsing/form_field.h b/chromium/components/autofill/core/browser/form_parsing/form_field.h
index 6d9cd75e0bc..d4a383699f2 100644
--- a/chromium/components/autofill/core/browser/form_parsing/form_field.h
+++ b/chromium/components/autofill/core/browser/form_parsing/form_field.h
@@ -23,8 +23,8 @@ class AutofillField;
class AutofillScanner;
class LogManager;
-// This helper struct allows passing information into ParseField /
-// ParseFieldSpecifics that can be used to create a log entry in
+// This helper struct allows passing information into ParseField() and
+// ParseFieldSpecifics() that can be used to create a log entry in
// chrome://autofill-internals explaining which regular expressions
// were matched by local heuristics.
struct RegExLogging {
@@ -32,7 +32,7 @@ struct RegExLogging {
const char* regex_name = "";
};
-// Represents a logical form field in a web form. Classes that implement this
+// Represents a logical form field in a web form. Classes that implement this
// interface can identify themselves as a particular type of form field, e.g.
// name, phone number, or address field.
class FormField {
@@ -69,30 +69,24 @@ class FormField {
protected:
// Initial values assigned to FieldCandidates by their corresponding parsers.
- static const float kBaseEmailParserScore;
- static const float kBasePhoneParserScore;
- static const float kBaseTravelParserScore;
- static const float kBaseAddressParserScore;
- static const float kBaseCreditCardParserScore;
- static const float kBasePriceParserScore;
- static const float kBaseNameParserScore;
- static const float kBaseMerchantPromoCodeParserScore;
- static const float kBaseSearchParserScore;
+ // There's an implicit precedence determined by the values assigned here.
+ // Email is currently the most important followed by Phone, Travel, Address,
+ // Credit Card, Price, Name, Merchant promo code, and Search.
+ static constexpr float kBaseEmailParserScore = 1.4f;
+ static constexpr float kBasePhoneParserScore = 1.3f;
+ static constexpr float kBaseTravelParserScore = 1.2f;
+ static constexpr float kBaseAddressParserScore = 1.1f;
+ static constexpr float kBaseCreditCardParserScore = 1.0f;
+ static constexpr float kBasePriceParserScore = 0.95f;
+ static constexpr float kBaseNameParserScore = 0.9f;
+ static constexpr float kBaseMerchantPromoCodeParserScore = 0.85f;
+ static constexpr float kBaseSearchParserScore = 0.8f;
// Only derived classes may instantiate.
FormField() = default;
// Attempts to parse a form field with the given pattern. Returns true on
// success and fills |match| with a pointer to the field.
- static bool ParseField(AutofillScanner* scanner,
- base::StringPiece16 pattern,
- AutofillField** match,
- const RegExLogging& logging = {});
-
- static bool ParseField(AutofillScanner* scanner,
- const std::vector<MatchingPattern>& patterns,
- AutofillField** match,
- const RegExLogging& logging = {});
static bool ParseField(AutofillScanner* scanner,
base::StringPiece16 pattern,
@@ -100,45 +94,12 @@ class FormField {
AutofillField** match,
const RegExLogging& logging = {});
- // Parses the stream of fields in |scanner| with regular expression |pattern|
- // as specified in the |match_type| bit field (see |MatchType|). If |match|
- // is non-NULL and the pattern matches, |match| will be set to the matched
- // field, and the scanner would advance by one step. A |true| result is
- // returned in the case of a successful match, false otherwise.
static bool ParseFieldSpecifics(AutofillScanner* scanner,
base::StringPiece16 pattern,
- int match_type,
- AutofillField** match,
- const RegExLogging& logging = {});
-
- static bool ParseFieldSpecifics(AutofillScanner* scanner,
+ const MatchParams& match_type,
const std::vector<MatchingPattern>& patterns,
AutofillField** match,
- const RegExLogging& logging = {});
-
- // The same as ParseFieldSpecifics but with splitted match_types into
- // MatchAttributes and MatchFieldTypes.
- static bool ParseFieldSpecifics(AutofillScanner* scanner,
- base::StringPiece16 pattern,
- int match_field_attributes,
- int match_field_input_types,
- AutofillField** match,
- const RegExLogging& logging = {});
-
- struct MatchFieldBitmasks {
- int restrict_attributes = ~0;
- int augment_types = 0;
- };
-
- static bool ParseFieldSpecifics(AutofillScanner* scanner,
- base::StringPiece16 pattern,
- int match_type,
- const std::vector<MatchingPattern>& patterns,
- AutofillField** match,
- const RegExLogging& logging,
- MatchFieldBitmasks match_field_bitmasks = {
- .restrict_attributes = ~0,
- .augment_types = 0});
+ const RegExLogging& logging);
// Attempts to parse a field with an empty label. Returns true
// on success and fills |match| with a pointer to the field.
@@ -153,7 +114,8 @@ class FormField {
FieldCandidatesMap* field_candidates);
// Returns true iff |type| matches |match_type|.
- static bool MatchesFormControlType(const std::string& type, int match_type);
+ static bool MatchesFormControlType(base::StringPiece type,
+ DenseSet<MatchFieldType> match_type);
// Derived classes must implement this interface to supply field type
// information. |ParseFormFields| coordinates the parsing and extraction
@@ -173,6 +135,24 @@ class FormField {
const LanguageCode& page_language,
LogManager* log_manager);
+ static bool ParseFieldSpecificsWithNewPatterns(
+ AutofillScanner* scanner,
+ const std::vector<MatchingPattern>& patterns,
+ AutofillField** match,
+ const RegExLogging& logging = {});
+
+ // Parses the stream of fields in |scanner| with regular expression |pattern|
+ // as specified in |match_type|. If |match| is non-NULL and the pattern
+ // matches, |match| will be set to the matched field, and the scanner would
+ // advance by one step. A |true| result is returned in the case of a
+ // successful match, false otherwise.
+ static bool ParseFieldSpecificsWithLegacyPattern(
+ AutofillScanner* scanner,
+ base::StringPiece16 pattern,
+ MatchParams match_type,
+ AutofillField** match,
+ const RegExLogging& logging = {});
+
// Removes checkable fields and returns fields to be processed for field
// detection.
static std::vector<AutofillField*> RemoveCheckableFields(
@@ -184,32 +164,15 @@ class FormField {
// otherwise.
static bool MatchAndAdvance(AutofillScanner* scanner,
base::StringPiece16 pattern,
- int match_type,
- AutofillField** match,
- const RegExLogging& logging = {});
-
- // The same as MatchAndAdvance but with splitted match_types into
- // MatchAttributes and MatchFieldTypes.
- static bool MatchAndAdvance(AutofillScanner* scanner,
- base::StringPiece16 pattern,
- int match_field_attributes,
- int match_field_input_types,
+ MatchParams match_type,
AutofillField** match,
const RegExLogging& logging = {});
// Matches the regular expression |pattern| against the components of
- // |field| as specified in the |match_type| bit field (see |MatchType|).
- static bool Match(const AutofillField* field,
- base::StringPiece16 pattern,
- int match_type,
- const RegExLogging& logging = {});
-
- // The same as Match but with splitted match_types into MatchAttributes
- // and MatchFieldTypes.
+ // |field| as specified in |match_type|.
static bool Match(const AutofillField* field,
base::StringPiece16 pattern,
- int match_field_attributes,
- int match_field_input_types,
+ MatchParams match_type,
const RegExLogging& logging = {});
// Perform a "pass" over the |fields| where each pass uses the supplied
diff --git a/chromium/components/autofill/core/browser/form_parsing/form_field_unittest.cc b/chromium/components/autofill/core/browser/form_parsing/form_field_unittest.cc
index 47d365d4950..7355e2c635d 100644
--- a/chromium/components/autofill/core/browser/form_parsing/form_field_unittest.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/form_field_unittest.cc
@@ -34,83 +34,85 @@ void SetFieldLabels(AutofillField* field, const std::u16string& label) {
} // namespace
TEST(FormFieldTest, Match) {
+ constexpr MatchParams kMatchLabel{{MatchAttribute::kLabel}, {}};
+
AutofillField field;
// Empty strings match.
- EXPECT_TRUE(FormField::Match(&field, std::u16string(), MATCH_LABEL));
+ EXPECT_TRUE(FormField::Match(&field, std::u16string(), kMatchLabel));
// Empty pattern matches non-empty string.
SetFieldLabels(&field, u"a");
- EXPECT_TRUE(FormField::Match(&field, std::u16string(), MATCH_LABEL));
+ EXPECT_TRUE(FormField::Match(&field, std::u16string(), kMatchLabel));
// Strictly empty pattern matches empty string.
SetFieldLabels(&field, u"");
- EXPECT_TRUE(FormField::Match(&field, u"^$", MATCH_LABEL));
+ EXPECT_TRUE(FormField::Match(&field, u"^$", kMatchLabel));
// Strictly empty pattern does not match non-empty string.
SetFieldLabels(&field, u"a");
- EXPECT_FALSE(FormField::Match(&field, u"^$", MATCH_LABEL));
+ EXPECT_FALSE(FormField::Match(&field, u"^$", kMatchLabel));
// Non-empty pattern doesn't match empty string.
SetFieldLabels(&field, u"");
- EXPECT_FALSE(FormField::Match(&field, u"a", MATCH_LABEL));
+ EXPECT_FALSE(FormField::Match(&field, u"a", kMatchLabel));
// Beginning of line.
SetFieldLabels(&field, u"head_tail");
- EXPECT_TRUE(FormField::Match(&field, u"^head", MATCH_LABEL));
- EXPECT_FALSE(FormField::Match(&field, u"^tail", MATCH_LABEL));
+ EXPECT_TRUE(FormField::Match(&field, u"^head", kMatchLabel));
+ EXPECT_FALSE(FormField::Match(&field, u"^tail", kMatchLabel));
// End of line.
SetFieldLabels(&field, u"head_tail");
- EXPECT_FALSE(FormField::Match(&field, u"head$", MATCH_LABEL));
- EXPECT_TRUE(FormField::Match(&field, u"tail$", MATCH_LABEL));
+ EXPECT_FALSE(FormField::Match(&field, u"head$", kMatchLabel));
+ EXPECT_TRUE(FormField::Match(&field, u"tail$", kMatchLabel));
// Exact.
SetFieldLabels(&field, u"head_tail");
- EXPECT_FALSE(FormField::Match(&field, u"^head$", MATCH_LABEL));
- EXPECT_FALSE(FormField::Match(&field, u"^tail$", MATCH_LABEL));
- EXPECT_TRUE(FormField::Match(&field, u"^head_tail$", MATCH_LABEL));
+ EXPECT_FALSE(FormField::Match(&field, u"^head$", kMatchLabel));
+ EXPECT_FALSE(FormField::Match(&field, u"^tail$", kMatchLabel));
+ EXPECT_TRUE(FormField::Match(&field, u"^head_tail$", kMatchLabel));
// Escaped dots.
SetFieldLabels(&field, u"m.i.");
// Note: This pattern is misleading as the "." characters are wild cards.
- EXPECT_TRUE(FormField::Match(&field, u"m.i.", MATCH_LABEL));
- EXPECT_TRUE(FormField::Match(&field, u"m\\.i\\.", MATCH_LABEL));
+ EXPECT_TRUE(FormField::Match(&field, u"m.i.", kMatchLabel));
+ EXPECT_TRUE(FormField::Match(&field, u"m\\.i\\.", kMatchLabel));
SetFieldLabels(&field, u"mXiX");
- EXPECT_TRUE(FormField::Match(&field, u"m.i.", MATCH_LABEL));
- EXPECT_FALSE(FormField::Match(&field, u"m\\.i\\.", MATCH_LABEL));
+ EXPECT_TRUE(FormField::Match(&field, u"m.i.", kMatchLabel));
+ EXPECT_FALSE(FormField::Match(&field, u"m\\.i\\.", kMatchLabel));
// Repetition.
SetFieldLabels(&field, u"headtail");
- EXPECT_TRUE(FormField::Match(&field, u"head.*tail", MATCH_LABEL));
+ EXPECT_TRUE(FormField::Match(&field, u"head.*tail", kMatchLabel));
SetFieldLabels(&field, u"headXtail");
- EXPECT_TRUE(FormField::Match(&field, u"head.*tail", MATCH_LABEL));
+ EXPECT_TRUE(FormField::Match(&field, u"head.*tail", kMatchLabel));
SetFieldLabels(&field, u"headXXXtail");
- EXPECT_TRUE(FormField::Match(&field, u"head.*tail", MATCH_LABEL));
+ EXPECT_TRUE(FormField::Match(&field, u"head.*tail", kMatchLabel));
SetFieldLabels(&field, u"headtail");
- EXPECT_FALSE(FormField::Match(&field, u"head.+tail", MATCH_LABEL));
+ EXPECT_FALSE(FormField::Match(&field, u"head.+tail", kMatchLabel));
SetFieldLabels(&field, u"headXtail");
- EXPECT_TRUE(FormField::Match(&field, u"head.+tail", MATCH_LABEL));
+ EXPECT_TRUE(FormField::Match(&field, u"head.+tail", kMatchLabel));
SetFieldLabels(&field, u"headXXXtail");
- EXPECT_TRUE(FormField::Match(&field, u"head.+tail", MATCH_LABEL));
+ EXPECT_TRUE(FormField::Match(&field, u"head.+tail", kMatchLabel));
// Alternation.
SetFieldLabels(&field, u"head_tail");
- EXPECT_TRUE(FormField::Match(&field, u"head|other", MATCH_LABEL));
- EXPECT_TRUE(FormField::Match(&field, u"tail|other", MATCH_LABEL));
- EXPECT_FALSE(FormField::Match(&field, u"bad|good", MATCH_LABEL));
+ EXPECT_TRUE(FormField::Match(&field, u"head|other", kMatchLabel));
+ EXPECT_TRUE(FormField::Match(&field, u"tail|other", kMatchLabel));
+ EXPECT_FALSE(FormField::Match(&field, u"bad|good", kMatchLabel));
// Case sensitivity.
SetFieldLabels(&field, u"xxxHeAd_tAiLxxx");
- EXPECT_TRUE(FormField::Match(&field, u"head_tail", MATCH_LABEL));
+ EXPECT_TRUE(FormField::Match(&field, u"head_tail", kMatchLabel));
// Word boundaries.
SetFieldLabels(&field, u"contains word:");
- EXPECT_TRUE(FormField::Match(&field, u"\\bword\\b", MATCH_LABEL));
- EXPECT_FALSE(FormField::Match(&field, u"\\bcon\\b", MATCH_LABEL));
+ EXPECT_TRUE(FormField::Match(&field, u"\\bword\\b", kMatchLabel));
+ EXPECT_FALSE(FormField::Match(&field, u"\\bcon\\b", kMatchLabel));
// Make sure the circumflex in 'crêpe' is not treated as a word boundary.
field.label = u"crêpe";
- EXPECT_FALSE(FormField::Match(&field, u"\\bcr\\b", MATCH_LABEL));
+ EXPECT_FALSE(FormField::Match(&field, u"\\bcr\\b", kMatchLabel));
}
// Test that we ignore checkable elements.
@@ -214,15 +216,15 @@ TEST(FormFieldTest, TestParseableLabels) {
base::test::ScopedFeatureList feature_list;
feature_list.InitAndEnableFeature(
features::kAutofillEnableSupportForParsingWithSharedLabels);
- EXPECT_TRUE(
- FormField::Match(autofill_field.get(), u"First Name", MATCH_LABEL));
+ EXPECT_TRUE(FormField::Match(autofill_field.get(), u"First Name",
+ MatchParams({MatchAttribute::kLabel}, {})));
}
{
base::test::ScopedFeatureList feature_list;
feature_list.InitAndDisableFeature(
features::kAutofillEnableSupportForParsingWithSharedLabels);
- EXPECT_FALSE(
- FormField::Match(autofill_field.get(), u"First Name", MATCH_LABEL));
+ EXPECT_FALSE(FormField::Match(autofill_field.get(), u"First Name",
+ MatchParams({MatchAttribute::kLabel}, {})));
}
}
diff --git a/chromium/components/autofill/core/browser/form_parsing/merchant_promo_code_field.cc b/chromium/components/autofill/core/browser/form_parsing/merchant_promo_code_field.cc
index 4d7653c699d..3db2d4ea9b9 100644
--- a/chromium/components/autofill/core/browser/form_parsing/merchant_promo_code_field.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/merchant_promo_code_field.cc
@@ -27,7 +27,8 @@ std::unique_ptr<FormField> MerchantPromoCodeField::Parse(
page_language);
if (ParseFieldSpecifics(scanner, kMerchantPromoCodeRe,
- MATCH_DEFAULT | MATCH_NUMBER | MATCH_TEXT_AREA,
+ kDefaultMatchParamsWith<MatchFieldType::kNumber,
+ MatchFieldType::kTextArea>,
merchant_promo_code_patterns, &field,
{log_manager, "kMerchantPromoCodeRe"})) {
return std::make_unique<MerchantPromoCodeField>(field);
diff --git a/chromium/components/autofill/core/browser/form_parsing/merchant_promo_code_field_unittest.cc b/chromium/components/autofill/core/browser/form_parsing/merchant_promo_code_field_unittest.cc
index 0374ae3cf61..f835c3d96f7 100644
--- a/chromium/components/autofill/core/browser/form_parsing/merchant_promo_code_field_unittest.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/merchant_promo_code_field_unittest.cc
@@ -19,7 +19,14 @@ class MerchantPromoCodeFieldTest : public FormFieldTest {
MerchantPromoCodeFieldTest& operator=(const MerchantPromoCodeFieldTest&) =
delete;
+ void SetUp() override {
+ scoped_feature_list_.InitAndEnableFeature(
+ features::kAutofillParseMerchantPromoCodeFields);
+ }
+
protected:
+ base::test::ScopedFeatureList scoped_feature_list_;
+
std::unique_ptr<FormField> Parse(
AutofillScanner* scanner,
const LanguageCode& page_language = LanguageCode("en")) override {
@@ -27,50 +34,55 @@ class MerchantPromoCodeFieldTest : public FormFieldTest {
}
};
+// Match promo(tion|tional)?[-_. ]*code
TEST_F(MerchantPromoCodeFieldTest, ParsePromoCode) {
- base::test::ScopedFeatureList scoped_feature_list;
- scoped_feature_list.InitAndEnableFeature(
- features::kAutofillParseMerchantPromoCodeFields);
AddTextFormFieldData("Enter promo code here", "promoCodeField",
MERCHANT_PROMO_CODE);
ClassifyAndVerify(ParseResult::PARSED);
}
+// Match promo(tion|tional)?[-_. ]*code
TEST_F(MerchantPromoCodeFieldTest, ParsePromotionalCode) {
- base::test::ScopedFeatureList scoped_feature_list;
- scoped_feature_list.InitAndEnableFeature(
- features::kAutofillParseMerchantPromoCodeFields);
AddTextFormFieldData("Use the promotional code here", "promoCodeField",
MERCHANT_PROMO_CODE);
ClassifyAndVerify(ParseResult::PARSED);
}
+// Match promo(tion|tional)?[-_. ]*code
+TEST_F(MerchantPromoCodeFieldTest, ParsePromoCodeWithPrefixAndSuffix) {
+ AddTextFormFieldData("mypromocodefield", "promoCodeField",
+ MERCHANT_PROMO_CODE);
+
+ ClassifyAndVerify(ParseResult::PARSED);
+}
+
+// Match coupon[-_. ]*code
TEST_F(MerchantPromoCodeFieldTest, ParseCouponCode) {
- base::test::ScopedFeatureList scoped_feature_list;
- scoped_feature_list.InitAndEnableFeature(
- features::kAutofillParseMerchantPromoCodeFields);
- AddTextFormFieldData("Enter coupon code", "couponCodeField",
+ AddTextFormFieldData("Enter new coupon__code", "couponCodeField",
MERCHANT_PROMO_CODE);
ClassifyAndVerify(ParseResult::PARSED);
}
+// Match gift[-_. ]*code
TEST_F(MerchantPromoCodeFieldTest, ParseGiftCode) {
- base::test::ScopedFeatureList scoped_feature_list;
- scoped_feature_list.InitAndEnableFeature(
- features::kAutofillParseMerchantPromoCodeFields);
- AddTextFormFieldData("Check out with gift code", "giftCodeField",
+ AddTextFormFieldData("Check out with gift.codes", "giftCodeField",
+ MERCHANT_PROMO_CODE);
+
+ ClassifyAndVerify(ParseResult::PARSED);
+}
+
+// Match discount[-_. ]*code
+TEST_F(MerchantPromoCodeFieldTest, ParseDiscountCode) {
+ AddTextFormFieldData("Check out with discount-code", "discountCodeField",
MERCHANT_PROMO_CODE);
ClassifyAndVerify(ParseResult::PARSED);
}
TEST_F(MerchantPromoCodeFieldTest, ParseNonPromoCode) {
- base::test::ScopedFeatureList scoped_feature_list;
- scoped_feature_list.InitAndEnableFeature(
- features::kAutofillParseMerchantPromoCodeFields);
// Regex relies on "promo/coupon/gift" + "code" together.
AddTextFormFieldData("Field for gift card or promo details", "otherField",
UNKNOWN_TYPE);
diff --git a/chromium/components/autofill/core/browser/form_parsing/name_field.cc b/chromium/components/autofill/core/browser/form_parsing/name_field.cc
index 80a167398a3..f1df1c6dbf6 100644
--- a/chromium/components/autofill/core/browser/form_parsing/name_field.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/name_field.cc
@@ -228,9 +228,9 @@ FirstTwoLastNamesField::ParseComponentNames(AutofillScanner* scanner,
while (!scanner->IsEnd()) {
// Skip over address label fields, which can have misleading names
// e.g. "title" or "name".
- if (ParseFieldSpecifics(scanner, kAddressNameIgnoredRe, MATCH_DEFAULT,
- address_name_ignored_patterns, nullptr,
- {log_manager, "kAddressNameIgnoredRe"})) {
+ if (ParseField(scanner, kAddressNameIgnoredRe,
+ address_name_ignored_patterns, nullptr,
+ {log_manager, "kAddressNameIgnoredRe"})) {
continue;
}
@@ -248,7 +248,8 @@ FirstTwoLastNamesField::ParseComponentNames(AutofillScanner* scanner,
// Skip over any unrelated fields, e.g. "username" or "nickname".
if (ParseFieldSpecifics(scanner, kNameIgnoredRe,
- MATCH_DEFAULT | MATCH_SELECT | MATCH_SEARCH,
+ kDefaultMatchParamsWith<MatchFieldType::kSelect,
+ MatchFieldType::kSearch>,
name_ignored_patterns, nullptr,
{log_manager, "kNameIgnoredRe"})) {
continue;
@@ -436,9 +437,9 @@ FirstLastNameField::ParseSpecificComponentSequence(
while (!scanner->IsEnd()) {
// Skip over address label fields, which can have misleading names
// e.g. "title" or "name".
- if (ParseFieldSpecifics(scanner, kAddressNameIgnoredRe, MATCH_DEFAULT,
- address_name_ignored_patterns, nullptr,
- {log_manager, "kAddressNameIgnoredRe"})) {
+ if (ParseField(scanner, kAddressNameIgnoredRe,
+ address_name_ignored_patterns, nullptr,
+ {log_manager, "kAddressNameIgnoredRe"})) {
continue;
}
@@ -459,7 +460,8 @@ FirstLastNameField::ParseSpecificComponentSequence(
// Skip over any unrelated name fields, e.g. "username" or "nickname".
if (ParseFieldSpecifics(scanner, kNameIgnoredRe,
- MATCH_DEFAULT | MATCH_SELECT | MATCH_SEARCH,
+ kDefaultMatchParamsWith<MatchFieldType::kSelect,
+ MatchFieldType::kSearch>,
name_ignored_patterns, nullptr,
{log_manager, "kNameIgnoredRe"})) {
continue;
diff --git a/chromium/components/autofill/core/browser/form_parsing/phone_field.cc b/chromium/components/autofill/core/browser/form_parsing/phone_field.cc
index a042ddb03c1..c9cb5b305eb 100644
--- a/chromium/components/autofill/core/browser/form_parsing/phone_field.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/phone_field.cc
@@ -162,7 +162,8 @@ bool PhoneField::LikelyAugmentedPhoneCountryCode(
AutofillField* field = scanner->Cursor();
// Return false if the field is not a selection box.
- if (!MatchesFormControlType(field->form_control_type, MATCH_SELECT))
+ if (!MatchesFormControlType(field->form_control_type,
+ {MatchFieldType::kSelect}))
return false;
// If the number of the options is less than the minimum limit or more than
@@ -453,10 +454,14 @@ bool PhoneField::ParsePhoneField(AutofillScanner* scanner,
const bool is_country_code_field,
const std::string& json_field_type,
const LanguageCode& page_language) {
- int match_type = MATCH_DEFAULT | MATCH_TELEPHONE | MATCH_NUMBER;
+ MatchParams match_type = kDefaultMatchParamsWith<MatchFieldType::kTelephone,
+ MatchFieldType::kNumber>;
// Include the selection boxes too for the matching of the phone country code.
- if (is_country_code_field)
- match_type |= MATCH_SELECT;
+ if (is_country_code_field) {
+ match_type = kDefaultMatchParamsWith<MatchFieldType::kTelephone,
+ MatchFieldType::kNumber,
+ MatchFieldType::kSelect>;
+ }
const std::vector<MatchingPattern>& patterns =
PatternProvider::GetInstance().GetMatchPatterns(json_field_type,
diff --git a/chromium/components/autofill/core/browser/form_parsing/price_field.cc b/chromium/components/autofill/core/browser/form_parsing/price_field.cc
index 84704eb7c45..a3606d853ee 100644
--- a/chromium/components/autofill/core/browser/form_parsing/price_field.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/price_field.cc
@@ -18,10 +18,12 @@ std::unique_ptr<FormField> PriceField::Parse(AutofillScanner* scanner,
const std::vector<MatchingPattern>& price_patterns =
PatternProvider::GetInstance().GetMatchPatterns("PRICE", page_language);
- if (ParseFieldSpecifics(scanner, kPriceRe,
- MATCH_DEFAULT | MATCH_NUMBER | MATCH_SELECT |
- MATCH_TEXT_AREA | MATCH_SEARCH,
- price_patterns, &field, {log_manager, "kPriceRe"})) {
+ if (ParseFieldSpecifics(
+ scanner, kPriceRe,
+ kDefaultMatchParamsWith<
+ MatchFieldType::kNumber, MatchFieldType::kSelect,
+ MatchFieldType::kTextArea, MatchFieldType::kSearch>,
+ price_patterns, &field, {log_manager, "kPriceRe"})) {
return std::make_unique<PriceField>(field);
}
diff --git a/chromium/components/autofill/core/browser/form_parsing/search_field.cc b/chromium/components/autofill/core/browser/form_parsing/search_field.cc
index 00ac6dd663e..4f4ca2dcb7a 100644
--- a/chromium/components/autofill/core/browser/form_parsing/search_field.cc
+++ b/chromium/components/autofill/core/browser/form_parsing/search_field.cc
@@ -19,7 +19,8 @@ std::unique_ptr<FormField> SearchField::Parse(AutofillScanner* scanner,
SEARCH_TERM, page_language);
if (ParseFieldSpecifics(scanner, kSearchTermRe,
- MATCH_DEFAULT | MATCH_SEARCH | MATCH_TEXT_AREA,
+ kDefaultMatchParamsWith<MatchFieldType::kSearch,
+ MatchFieldType::kTextArea>,
patterns, &field, {log_manager, "kSearchTermRe"})) {
return std::make_unique<SearchField>(field);
}
diff --git a/chromium/components/autofill/core/browser/form_structure.cc b/chromium/components/autofill/core/browser/form_structure.cc
index 73ac6b339bb..c77a227e503 100644
--- a/chromium/components/autofill/core/browser/form_structure.cc
+++ b/chromium/components/autofill/core/browser/form_structure.cc
@@ -7,6 +7,7 @@
#include <stdint.h>
#include <algorithm>
+#include <deque>
#include <map>
#include <memory>
#include <unordered_map>
@@ -16,13 +17,13 @@
#include "base/base64.h"
#include "base/command_line.h"
+#include "base/containers/contains.h"
#include "base/containers/fixed_flat_map.h"
#include "base/feature_list.h"
#include "base/i18n/case_conversion.h"
#include "base/logging.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/histogram_macros.h"
-#include "base/no_destructor.h"
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
@@ -731,8 +732,7 @@ void FormStructure::DetermineHeuristicTypes(
1 << AutofillMetrics::FORM_CONTAINS_UPI_VPA_HINT;
}
- if (base::FeatureList::IsEnabled(
- features::kAutofillParsingPatternsLanguageDetection)) {
+ if (base::FeatureList::IsEnabled(features::kAutofillPageLanguageDetection)) {
RationalizeRepeatedFields(form_interactions_ukm_logger, log_manager);
}
RationalizeFieldTypePredictions(log_manager);
@@ -1222,6 +1222,11 @@ void FormStructure::RetrieveFromCache(
field->set_server_predictions(cached_field->server_predictions());
field->set_previously_autofilled(cached_field->previously_autofilled());
+ if (cached_field->value_not_autofilled_over_existing_value_hash()) {
+ field->set_value_not_autofilled_over_existing_value_hash(
+ *cached_field->value_not_autofilled_over_existing_value_hash());
+ }
+
// Only retrieve an overall prediction from cache if a server prediction
// is set.
if (base::FeatureList::IsEnabled(
diff --git a/chromium/components/autofill/core/browser/form_structure_unittest.cc b/chromium/components/autofill/core/browser/form_structure_unittest.cc
index a0e005fb655..63eb25b058c 100644
--- a/chromium/components/autofill/core/browser/form_structure_unittest.cc
+++ b/chromium/components/autofill/core/browser/form_structure_unittest.cc
@@ -863,7 +863,7 @@ TEST_F(FormStructureTestImpl, IsCompleteCreditCardForm_Minimal) {
{.label = u"Expiration", .name = u"cc_exp"},
{.role = ServerFieldType::ADDRESS_HOME_ZIP}}},
{.determine_heuristic_type = true,
- .is_complete_credit_card_form = {true, true}},
+ .is_complete_credit_card_form = true},
{}}});
}
@@ -879,7 +879,7 @@ TEST_F(FormStructureTestImpl, IsCompleteCreditCardForm_Full) {
.name = u"submit",
.form_control_type = "submit"}}},
{.determine_heuristic_type = true,
- .is_complete_credit_card_form = {true, true}},
+ .is_complete_credit_card_form = true},
{}}});
}
@@ -889,7 +889,7 @@ TEST_F(FormStructureTestImpl, IsCompleteCreditCardForm_OnlyCCNumber) {
{{{.description_for_logging = "IsCompleteCreditCardForm_OnlyCCNumber",
.fields = {{.role = ServerFieldType::CREDIT_CARD_NUMBER}}},
{.determine_heuristic_type = true,
- .is_complete_credit_card_form = {true, false}},
+ .is_complete_credit_card_form = false},
{}}});
}
@@ -905,7 +905,7 @@ TEST_F(FormStructureTestImpl, IsCompleteCreditCardForm_AddressForm) {
{.label = u"Address", .name = u""},
{.role = ServerFieldType::ADDRESS_HOME_ZIP, .name = u""}}},
{.determine_heuristic_type = true,
- .is_complete_credit_card_form = {true, false}},
+ .is_complete_credit_card_form = false},
{}}});
}
diff --git a/chromium/components/autofill/core/browser/geo/alternative_state_name_map.cc b/chromium/components/autofill/core/browser/geo/alternative_state_name_map.cc
index 5b5add9d56b..469e3fc1686 100644
--- a/chromium/components/autofill/core/browser/geo/alternative_state_name_map.cc
+++ b/chromium/components/autofill/core/browser/geo/alternative_state_name_map.cc
@@ -4,6 +4,7 @@
#include "components/autofill/core/browser/geo/alternative_state_name_map.h"
+#include "base/no_destructor.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
diff --git a/chromium/components/autofill/core/browser/geo/alternative_state_name_map_updater_unittest.cc b/chromium/components/autofill/core/browser/geo/alternative_state_name_map_updater_unittest.cc
index 5b3d0c4fae4..e648ab0be0b 100644
--- a/chromium/components/autofill/core/browser/geo/alternative_state_name_map_updater_unittest.cc
+++ b/chromium/components/autofill/core/browser/geo/alternative_state_name_map_updater_unittest.cc
@@ -44,7 +44,6 @@ class AlternativeStateNameMapUpdaterTest : public ::testing::Test {
/*pref_service=*/autofill_client_.GetPrefs(),
/*local_state=*/autofill_client_.GetPrefs(),
/*identity_manager=*/nullptr,
- /*client_profile_validator=*/nullptr,
/*history_service=*/nullptr,
/*strike_database=*/nullptr,
/*image_fetcher=*/nullptr,
diff --git a/chromium/components/autofill/core/browser/geo/autofill_country.cc b/chromium/components/autofill/core/browser/geo/autofill_country.cc
index 2dc8e9792c0..4a95ddd481a 100644
--- a/chromium/components/autofill/core/browser/geo/autofill_country.cc
+++ b/chromium/components/autofill/core/browser/geo/autofill_country.cc
@@ -34,13 +34,6 @@ AutofillCountry::AutofillCountry(const std::string& country_code,
? country_data_map->GetCountryCodeForAlias(country_code)
: country_code;
- // If there is no entry in the |CountryDataMap| for the
- // |country_code_for_country_data| use the country code derived from the
- // locale. This reverts to US.
- country_data_map->HasRequiredFieldsForAddressImport(country_code_)
- ? country_code_
- : CountryCodeForLocale(locale);
-
// Acquire the country address data.
required_fields_for_address_import_ =
country_data_map->GetRequiredFieldsForAddressImport(country_code_);
diff --git a/chromium/components/autofill/core/browser/geo/autofill_country_unittest.cc b/chromium/components/autofill/core/browser/geo/autofill_country_unittest.cc
index 5ee6e2dc0ec..93c068ffc14 100644
--- a/chromium/components/autofill/core/browser/geo/autofill_country_unittest.cc
+++ b/chromium/components/autofill/core/browser/geo/autofill_country_unittest.cc
@@ -41,6 +41,10 @@ TEST(AutofillCountryTest, AutofillCountry) {
AutofillCountry canada_hu("CA", "hu");
EXPECT_EQ("CA", canada_hu.country_code());
EXPECT_EQ(u"Kanada", canada_hu.name());
+
+ // Unrecognizable country codes remain that way.
+ AutofillCountry unknown("Unknown", "en_US");
+ EXPECT_EQ("Unknown", unknown.country_code());
}
// Test locale to country code mapping.
@@ -66,6 +70,23 @@ TEST(AutofillCountryTest, UsaAddressRequirements) {
EXPECT_TRUE(us_autofill_country.requires_line1());
}
+// Test that unknown country codes have US requirements.
+TEST(AutofillCountryTest, UnknownAddressRequirements) {
+ AutofillCountry us_autofill_country("US", "en_US");
+ AutofillCountry unknown_autofill_country("Unknown", "en_US");
+
+ EXPECT_EQ(us_autofill_country.requires_zip_or_state(),
+ unknown_autofill_country.requires_zip_or_state());
+ EXPECT_EQ(us_autofill_country.requires_zip(),
+ unknown_autofill_country.requires_zip());
+ EXPECT_EQ(us_autofill_country.requires_state(),
+ unknown_autofill_country.requires_state());
+ EXPECT_EQ(us_autofill_country.requires_city(),
+ unknown_autofill_country.requires_city());
+ EXPECT_EQ(us_autofill_country.requires_line1(),
+ unknown_autofill_country.requires_line1());
+}
+
// Test the address requirement method for Brazil.
TEST(AutofillCountryTest, BrAddressRequirements) {
// Brazil only requires a zip entry.
diff --git a/chromium/components/autofill/core/browser/geo/country_names.cc b/chromium/components/autofill/core/browser/geo/country_names.cc
index a62d5483eee..49bba61d62d 100644
--- a/chromium/components/autofill/core/browser/geo/country_names.cc
+++ b/chromium/components/autofill/core/browser/geo/country_names.cc
@@ -47,7 +47,7 @@ std::map<std::string, std::string> GetCommonNames() {
common_names.insert(std::make_pair("UK", "GB"));
common_names.insert(std::make_pair("BRASIL", "BR"));
common_names.insert(std::make_pair("DEUTSCHLAND", "DE"));
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
// iOS uses the Foundation API to get the localized display name, in which
// "China" is named "Chine mainland".
common_names.insert(std::make_pair("CHINA", "CN"));
diff --git a/chromium/components/autofill/core/browser/geo/country_names_for_locale_unittest.cc b/chromium/components/autofill/core/browser/geo/country_names_for_locale_unittest.cc
index e62db32f409..019c5d9ca11 100644
--- a/chromium/components/autofill/core/browser/geo/country_names_for_locale_unittest.cc
+++ b/chromium/components/autofill/core/browser/geo/country_names_for_locale_unittest.cc
@@ -2,11 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "components/autofill/core/browser/geo/country_names_for_locale.h"
+
#include <string>
#include <utility>
#include "base/strings/utf_string_conversions.h"
-#include "components/autofill/core/browser/geo/country_names_for_locale.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
using base::ASCIIToUTF16;
@@ -47,7 +49,7 @@ TEST(CountryNamesForLocaleTest, EmptyCountryCodeForInvalidLocale) {
// The behavior depends on the platform. On Android the locale reverts back to
// the standard locale.
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
// Test that an empty string is returned for an empty locale.
TEST(CountryNamesForLocaleTest, EmptyCountryCodeForEmptyLocale) {
TestCountryNamesForLocale empty_locale_names("");
diff --git a/chromium/components/autofill/core/browser/geo/phone_number_i18n.h b/chromium/components/autofill/core/browser/geo/phone_number_i18n.h
index b608e66c29b..678c61539f8 100644
--- a/chromium/components/autofill/core/browser/geo/phone_number_i18n.h
+++ b/chromium/components/autofill/core/browser/geo/phone_number_i18n.h
@@ -8,8 +8,6 @@
#include <memory>
#include <string>
-#include "base/compiler_specific.h"
-
namespace i18n {
namespace phonenumbers {
class PhoneNumber;
@@ -52,14 +50,14 @@ bool IsPossiblePhoneNumber(const std::string& phone_number,
// |default_region| if |value| has an international country code, for example).
// This is an internal function, exposed in the header file so that it can be
// tested.
-bool ParsePhoneNumber(const std::u16string& value,
- const std::string& default_region,
- std::u16string* country_code,
- std::u16string* city_code,
- std::u16string* number,
- std::string* inferred_region,
- ::i18n::phonenumbers::PhoneNumber* i18n_number)
- WARN_UNUSED_RESULT;
+[[nodiscard]] bool ParsePhoneNumber(
+ const std::u16string& value,
+ const std::string& default_region,
+ std::u16string* country_code,
+ std::u16string* city_code,
+ std::u16string* number,
+ std::string* inferred_region,
+ ::i18n::phonenumbers::PhoneNumber* i18n_number);
// Normalizes phone number, by changing digits in the extended fonts
// (such as \xFF1x) into '0'-'9'. Also strips out non-digit characters.
@@ -74,11 +72,11 @@ std::u16string NormalizePhoneNumber(const std::u16string& value,
// |whole_number| - constructed whole number.
// Separator characters are stripped before parsing the digits.
// Returns true if parsing was successful, false otherwise.
-bool ConstructPhoneNumber(const std::u16string& country_code,
- const std::u16string& city_code,
- const std::u16string& number,
- const std::string& default_region,
- std::u16string* whole_number) WARN_UNUSED_RESULT;
+[[nodiscard]] bool ConstructPhoneNumber(const std::u16string& country_code,
+ const std::u16string& city_code,
+ const std::u16string& number,
+ const std::string& default_region,
+ std::u16string* whole_number);
// Returns true if |number_a| and |number_b| parse to the same phone number in
// the given |region|.
diff --git a/chromium/components/autofill/core/browser/logging/log_buffer_submitter_unittest.cc b/chromium/components/autofill/core/browser/logging/log_buffer_submitter_unittest.cc
index 522b885acee..03b293d4dab 100644
--- a/chromium/components/autofill/core/browser/logging/log_buffer_submitter_unittest.cc
+++ b/chromium/components/autofill/core/browser/logging/log_buffer_submitter_unittest.cc
@@ -4,9 +4,10 @@
#include "components/autofill/core/browser/logging/log_buffer_submitter.h"
+#include <tuple>
+
#include "base/callback.h"
#include "base/callback_helpers.h"
-#include "base/ignore_result.h"
#include "base/values.h"
#include "components/autofill/core/browser/logging/log_manager.h"
#include "components/autofill/core/browser/logging/log_receiver.h"
@@ -29,7 +30,7 @@ TEST(LogBufferSubmitter, VerifySubmissionOnDestruction) {
MockLogReceiver receiver;
LogRouter router;
- ignore_result(router.RegisterReceiver(&receiver));
+ std::ignore = router.RegisterReceiver(&receiver);
std::unique_ptr<LogManager> log_manager =
LogManager::Create(&router, base::NullCallback());
@@ -42,7 +43,7 @@ TEST(LogBufferSubmitter, VerifySubmissionOnDestruction) {
TEST(LogBufferSubmitter, NoEmptySubmission) {
MockLogReceiver receiver;
LogRouter router;
- ignore_result(router.RegisterReceiver(&receiver));
+ std::ignore = router.RegisterReceiver(&receiver);
std::unique_ptr<LogManager> log_manager =
LogManager::Create(&router, base::NullCallback());
@@ -59,7 +60,7 @@ TEST(LogBufferSubmitter, CorrectActivation) {
LogRouter router;
MockLogReceiver receiver;
- ignore_result(router.RegisterReceiver(&receiver));
+ std::ignore = router.RegisterReceiver(&receiver);
std::unique_ptr<LogManager> log_manager_2 =
LogManager::Create(&router, base::NullCallback());
EXPECT_TRUE(log_manager_2->Log().buffer().active());
diff --git a/chromium/components/autofill/core/browser/logging/log_router.h b/chromium/components/autofill/core/browser/logging/log_router.h
index 1cb7121962f..2ef73cc25d7 100644
--- a/chromium/components/autofill/core/browser/logging/log_router.h
+++ b/chromium/components/autofill/core/browser/logging/log_router.h
@@ -8,7 +8,6 @@
#include <string>
#include <vector>
-#include "base/compiler_specific.h"
#include "base/observer_list.h"
#include "base/values.h"
#include "components/keyed_service/core/keyed_service.h"
@@ -54,8 +53,8 @@ class LogRouter : public KeyedService {
// RegisterReceiver adds |receiver| to the right observer list, and returns
// the logs accumulated so far. (It returns by value, not const ref, to
// provide a snapshot as opposed to a link to |accumulated_logs_|.)
- const std::vector<base::Value>& RegisterReceiver(LogReceiver* receiver)
- WARN_UNUSED_RESULT;
+ [[nodiscard]] const std::vector<base::Value>& RegisterReceiver(
+ LogReceiver* receiver);
// Remove |receiver| from the observers list.
void UnregisterReceiver(LogReceiver* receiver);
diff --git a/chromium/components/autofill/core/browser/metrics/autofill_metrics.cc b/chromium/components/autofill/core/browser/metrics/autofill_metrics.cc
index ba2c58ede3b..6e273d7d224 100644
--- a/chromium/components/autofill/core/browser/metrics/autofill_metrics.cc
+++ b/chromium/components/autofill/core/browser/metrics/autofill_metrics.cc
@@ -523,7 +523,7 @@ const char* GetQualityMetricTypeSuffix(
switch (metric_type) {
default:
NOTREACHED();
- FALLTHROUGH;
+ [[fallthrough]];
case AutofillMetrics::TYPE_SUBMISSION:
return "";
case AutofillMetrics::TYPE_NO_SUBMISSION:
@@ -2090,6 +2090,12 @@ void AutofillMetrics::LogStoredProfileCount(size_t num_profiles) {
}
// static
+void AutofillMetrics::LogStoredProfilesWithoutCountry(size_t num_profiles) {
+ UMA_HISTOGRAM_COUNTS_1M("Autofill.StoredProfileWithoutCountryCount",
+ num_profiles);
+}
+
+// static
void AutofillMetrics::LogStoredProfileDisusedCount(size_t num_profiles) {
UMA_HISTOGRAM_COUNTS_1000("Autofill.StoredProfileDisusedCount", num_profiles);
}
@@ -2300,6 +2306,11 @@ void AutofillMetrics::LogAddressSuggestionsCount(size_t num_suggestions) {
}
// static
+void AutofillMetrics::LogSuggestionClick(SuggestionClickResult value) {
+ base::UmaHistogramEnumeration("Autofill.SuggestionClick", value);
+}
+
+// static
void AutofillMetrics::LogAutofillSuggestionAcceptedIndex(int index,
PopupType popup_type,
bool off_the_record) {
@@ -3056,12 +3067,25 @@ void AutofillMetrics::LogNewProfileImportDecision(
decision);
}
+void AutofillMetrics::LogNewProfileWithComplementedCountryImportDecision(
+ AutofillClient::SaveAddressProfileOfferUserDecision decision) {
+ base::UmaHistogramEnumeration(
+ "Autofill.ProfileImport.NewProfileWithComplementedCountryDecision",
+ decision);
+}
+
void AutofillMetrics::LogNewProfileEditedType(ServerFieldType edited_type) {
base::UmaHistogramEnumeration(
"Autofill.ProfileImport.NewProfileEditedType",
ConvertSettingsVisibleFieldTypeForMetrics(edited_type));
}
+void AutofillMetrics::LogNewProfileEditedComplementedCountry() {
+ base::UmaHistogramEnumeration(
+ "Autofill.ProfileImport.NewProfileEditedComplementedCountry",
+ AutofillMetrics::SettingsVisibleFieldTypeForMetrics::kCountry);
+}
+
void AutofillMetrics::LogNewProfileNumberOfEditedFields(
int number_of_edited_fields) {
base::UmaHistogramExactLinear(
@@ -3075,6 +3099,13 @@ void AutofillMetrics::LogProfileUpdateImportDecision(
decision);
}
+void AutofillMetrics::LogProfileUpdateWithComplementedCountryImportDecision(
+ AutofillClient::SaveAddressProfileOfferUserDecision decision) {
+ base::UmaHistogramEnumeration(
+ "Autofill.ProfileImport.UpdateProfileWithComplementedCountryDecision",
+ decision);
+}
+
void AutofillMetrics::LogProfileUpdateAffectedType(
ServerFieldType affected_type,
AutofillClient::SaveAddressProfileOfferUserDecision decision) {
@@ -3106,6 +3137,12 @@ void AutofillMetrics::LogProfileUpdateEditedType(ServerFieldType edited_type) {
ConvertSettingsVisibleFieldTypeForMetrics(edited_type));
}
+void AutofillMetrics::LogProfileUpdateEditedComplementedCountry() {
+ base::UmaHistogramEnumeration(
+ "Autofill.ProfileImport.UpdateProfileEditedComplementedCountry",
+ AutofillMetrics::SettingsVisibleFieldTypeForMetrics::kCountry);
+}
+
void AutofillMetrics::LogUpdateProfileNumberOfEditedFields(
int number_of_edited_fields) {
base::UmaHistogramExactLinear(
@@ -3272,4 +3309,12 @@ void AutofillMetrics::LogOtpInputDialogNewOtpRequested() {
true);
}
+// static
+void AutofillMetrics::
+ LogIsValueNotAutofilledOverExistingValueSameAsSubmittedValue(bool is_same) {
+ base::UmaHistogramBoolean(
+ "Autofill.IsValueNotAutofilledOverExistingValueSameAsSubmittedValue",
+ is_same);
+}
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/metrics/autofill_metrics.h b/chromium/components/autofill/core/browser/metrics/autofill_metrics.h
index 9f141688bd0..348556cc97c 100644
--- a/chromium/components/autofill/core/browser/metrics/autofill_metrics.h
+++ b/chromium/components/autofill/core/browser/metrics/autofill_metrics.h
@@ -1209,6 +1209,15 @@ class AutofillMetrics {
kMaxValue = kPartialFill,
};
+ // These values are persisted to logs. Entries should not be renumbered and
+ // numeric values should never be reused.
+ enum class SuggestionClickResult {
+ kAccepted = 0,
+ kIgnored = 1,
+ kAcceptedAfterIgnored = 2,
+ kMaxValue = kAcceptedAfterIgnored
+ };
+
// Utility to log URL keyed form interaction events.
class FormInteractionsUkmLogger {
public:
@@ -1656,10 +1665,14 @@ class AutofillMetrics {
// This should be called each time a new chrome profile is launched.
static void LogIsAutofillCreditCardEnabledAtStartup(bool enabled);
- // Records the number of stored address profiles. This is be called each time
- // a new chrome profile is launched.
+ // Records the number of stored address profiles. This is called each time a
+ // new Chrome profile is launched.
static void LogStoredProfileCount(size_t num_profiles);
+ // Records the number of profiles without a country. This is called each time
+ // a new Chrome profile is launched.
+ static void LogStoredProfilesWithoutCountry(size_t num_profiles);
+
// Records the number of stored address profiles which have not been used in
// a long time. This is be called each time a new chrome profile is launched.
static void LogStoredProfileDisusedCount(size_t num_profiles);
@@ -1718,6 +1731,10 @@ class AutofillMetrics {
// filling a form.
static void LogAddressSuggestionsCount(size_t num_suggestions);
+ // Log whether a click was handled, ignored, or the followup of an ignored
+ // click.
+ static void LogSuggestionClick(SuggestionClickResult value);
+
// Log the index of the selected Autofill suggestion in the popup.
static void LogAutofillSuggestionAcceptedIndex(int index,
PopupType popup_type,
@@ -1918,13 +1935,23 @@ class AutofillMetrics {
static void LogSilentUpdatesProfileImportType(
AutofillProfileImportType import_type);
- // Logs the user decision for importing a new profile
+ // Logs the user decision for importing a new profile.
static void LogNewProfileImportDecision(
AutofillClient::SaveAddressProfileOfferUserDecision decision);
+ // Logs the user decision for importing a new profile with auto complemented
+ // country.
+ // TODO(crbug.com/1297032): Cleanup when launched.
+ static void LogNewProfileWithComplementedCountryImportDecision(
+ AutofillClient::SaveAddressProfileOfferUserDecision decision);
+
// Logs that a specific type was edited in a save prompt.
static void LogNewProfileEditedType(ServerFieldType edited_type);
+ // Logs that the auto complemented country was edited in a save prompt.
+ // TODO(crbug.com/1297032): Cleanup when launched.
+ static void LogNewProfileEditedComplementedCountry();
+
// Logs the number of edited fields for an accepted profile save.
static void LogNewProfileNumberOfEditedFields(int number_of_edited_fields);
@@ -1932,6 +1959,12 @@ class AutofillMetrics {
static void LogProfileUpdateImportDecision(
AutofillClient::SaveAddressProfileOfferUserDecision decision);
+ // Logs the user decision for updating an exiting profile with auto
+ // complemented country.
+ // TODO(crbug.com/1297032): Cleanup when launched.
+ static void LogProfileUpdateWithComplementedCountryImportDecision(
+ AutofillClient::SaveAddressProfileOfferUserDecision decision);
+
// Logs that a specific type changed in a profile update that received the
// user |decision|. Note that additional manual edits in the update prompt are
// not accounted for in this metric.
@@ -1942,6 +1975,10 @@ class AutofillMetrics {
// Logs that a specific type was edited in an update prompt.
static void LogProfileUpdateEditedType(ServerFieldType edited_type);
+ // Logs that the auto complemented country was edited in an update prompt.
+ // TODO(crbug.com/1297032): Cleanup when launched.
+ static void LogProfileUpdateEditedComplementedCountry();
+
// Logs the number of edited fields for an accepted profile update.
static void LogUpdateProfileNumberOfEditedFields(int number_of_edited_fields);
@@ -2009,6 +2046,12 @@ class AutofillMetrics {
// updated each time a new value is added.
static const int kNumCardUploadDecisionMetrics = 19;
+ // Logs whether the submitted field value is same as the non-empty value
+ // to be autofilled in the field, when the field had a different prefilled
+ // value.
+ static void LogIsValueNotAutofilledOverExistingValueSameAsSubmittedValue(
+ bool is_same);
+
private:
static void Log(AutocompleteEvent event);
};
diff --git a/chromium/components/autofill/core/browser/metrics/autofill_metrics_unittest.cc b/chromium/components/autofill/core/browser/metrics/autofill_metrics_unittest.cc
index 300b5475b6b..748c621cfea 100644
--- a/chromium/components/autofill/core/browser/metrics/autofill_metrics_unittest.cc
+++ b/chromium/components/autofill/core/browser/metrics/autofill_metrics_unittest.cc
@@ -72,7 +72,7 @@
#include "url/gurl.h"
#include "url/url_canon.h"
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
#include "components/autofill/core/browser/payments/test_credit_card_fido_authenticator.h"
#endif
@@ -296,7 +296,7 @@ void TestAddressProfileImportCountrySpecificFieldRequirements(
}
void CreateSimpleForm(const GURL& origin, FormData& form) {
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -409,6 +409,7 @@ void AutofillMetricsTest::SetUp() {
autofill_client_.SetPrefs(test::PrefServiceForTesting());
personal_data_ = std::make_unique<TestPersonalDataManager>();
+ personal_data_->set_auto_accept_address_imports_for_testing(true);
personal_data_->SetPrefService(autofill_client_.GetPrefs());
personal_data_->OnSyncServiceInitialized(&sync_service_);
@@ -440,7 +441,7 @@ void AutofillMetricsTest::SetUp() {
browser_autofill_manager_->SetExternalDelegateForTest(
std::move(external_delegate));
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
browser_autofill_manager_->credit_card_access_manager()
->set_fido_authenticator_for_testing(
std::make_unique<TestCreditCardFIDOAuthenticator>(
@@ -500,7 +501,7 @@ void AutofillMetricsTest::RecreateProfile(bool is_server) {
void AutofillMetricsTest::SetFidoEligibility(bool is_verifiable) {
CreditCardAccessManager* access_manager =
browser_autofill_manager_->credit_card_access_manager();
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
static_cast<TestCreditCardFIDOAuthenticator*>(
access_manager->GetOrCreateFIDOAuthenticator())
->SetUserVerifiable(is_verifiable);
@@ -1926,7 +1927,7 @@ TEST_F(AutofillMetricsTest,
QualityMetrics_LoggedCorrecltyForRationalizationOk) {
// Set up our form data.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -2008,7 +2009,7 @@ TEST_F(AutofillMetricsTest,
QualityMetrics_LoggedCorrecltyForRationalizationGood) {
// Set up our form data.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -2077,7 +2078,7 @@ TEST_F(AutofillMetricsTest, LogHiddenRepresentationalFieldSkipDecision) {
// Set up our form data.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -2233,7 +2234,7 @@ void AddFieldSuggestionToForm(
TEST_F(AutofillMetricsTest, LogRepeatedAddressTypeRationalized) {
// Set up our form data.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -2341,7 +2342,7 @@ TEST_F(AutofillMetricsTest, LogRepeatedAddressTypeRationalized) {
TEST_F(AutofillMetricsTest, LogRepeatedStateCountryTypeRationalized) {
// Set up our form data.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -2482,7 +2483,7 @@ TEST_F(AutofillMetricsTest,
QualityMetrics_LoggedCorrecltyForRationalizationBad) {
// Set up our form data.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -2550,7 +2551,7 @@ TEST_F(AutofillMetricsTest,
QualityMetrics_LoggedCorrecltyForOnlyFillWhenFocusedField) {
// Set up our form data.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -2859,7 +2860,7 @@ TEST_P(QualityMetricsTest, Classification) {
// Set up our form data.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -3036,7 +3037,7 @@ TEST_F(AutofillMetricsTest, TimingMetrics) {
base::HistogramTester histogram_tester;
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -3080,7 +3081,7 @@ TEST_F(AutofillMetricsTest, TimingMetrics) {
TEST_F(AutofillMetricsTest, QualityMetrics_NoSubmission) {
// Set up our form data.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -3271,7 +3272,7 @@ TEST_F(AutofillMetricsTest, QualityMetrics_NoSubmission) {
// on autocomplete attributes present on the fields.
TEST_F(AutofillMetricsTest, QualityMetrics_BasedOnAutocomplete) {
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"MyForm";
form.url = GURL("http://myform.com/form.html");
@@ -3388,7 +3389,7 @@ TEST_F(AutofillMetricsTest, QualityMetrics_BasedOnAutocomplete) {
TEST_F(AutofillMetricsTest, UpiVirtualPaymentAddress) {
// Set up our form data.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -3441,7 +3442,7 @@ TEST_F(AutofillMetricsTest, UpiVirtualPaymentAddress) {
TEST_F(AutofillMetricsTest, SaneMetricsWithCacheMismatch) {
// Set up our form data.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -3544,7 +3545,7 @@ TEST_F(AutofillMetricsTest, SaneMetricsWithCacheMismatch) {
TEST_F(AutofillMetricsTest, StoredProfileCountAutofillableFormSubmission) {
// Construct a fillable form.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -3581,7 +3582,7 @@ TEST_F(AutofillMetricsTest, StoredProfileCountAutofillableFormSubmission) {
TEST_F(AutofillMetricsTest, StoredProfileCountNonAutofillableFormSubmission) {
// Construct a non-fillable form.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -3754,7 +3755,7 @@ TEST_F(AutofillMetricsTest, TypeOfEditedAutofilledFieldsUmaLogging) {
TEST_F(AutofillMetricsTest, NumberOfEditedAutofilledFields) {
// Construct a fillable form.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -3810,7 +3811,7 @@ TEST_F(AutofillMetricsTest, NumberOfEditedAutofilledFields) {
TEST_F(AutofillMetricsTest, NumberOfEditedAutofilledFields_NoSubmission) {
// Construct a fillable form.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -3861,7 +3862,7 @@ TEST_F(AutofillMetricsTest, NumberOfEditedAutofilledFields_NoSubmission) {
TEST_F(AutofillMetricsTest, DeveloperEngagement) {
// Start with a non-fillable form.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -3958,7 +3959,7 @@ TEST_F(AutofillMetricsTest,
UkmDeveloperEngagement_LogFillableFormParsedWithoutTypeHints) {
// Start with a non-fillable form.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -4005,7 +4006,7 @@ TEST_F(AutofillMetricsTest,
TEST_F(AutofillMetricsTest,
UkmDeveloperEngagement_LogFillableFormParsedWithTypeHints) {
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -4057,7 +4058,7 @@ TEST_F(AutofillMetricsTest,
// developer engagement.
TEST_F(AutofillMetricsTest, UkmDeveloperEngagement_LogUpiVpaTypeHint) {
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -4311,7 +4312,6 @@ TEST_F(AutofillMetricsTest, AutofillProfileIsEnabledAtStartup) {
/*pref_service=*/autofill_client_.GetPrefs(),
/*local_state=*/autofill_client_.GetPrefs(),
/*identity_manager=*/nullptr,
- /*client_profile_validator=*/nullptr,
/*history_service=*/nullptr,
/*strike_database=*/nullptr,
/*image_fetcher=*/nullptr,
@@ -4329,7 +4329,6 @@ TEST_F(AutofillMetricsTest, AutofillProfileIsDisabledAtStartup) {
/*pref_service=*/autofill_client_.GetPrefs(),
/*local_state=*/autofill_client_.GetPrefs(),
/*identity_manager=*/nullptr,
- /*client_profile_validator=*/nullptr,
/*history_service=*/nullptr,
/*strike_database=*/nullptr,
/*image_fetcher=*/nullptr,
@@ -4347,7 +4346,6 @@ TEST_F(AutofillMetricsTest, AutofillCreditCardIsEnabledAtStartup) {
/*pref_service=*/autofill_client_.GetPrefs(),
/*local_state=*/autofill_client_.GetPrefs(),
/*identity_manager=*/nullptr,
- /*client_profile_validator=*/nullptr,
/*history_service=*/nullptr,
/*strike_database=*/nullptr,
/*image_fetcher=*/nullptr,
@@ -4365,7 +4363,6 @@ TEST_F(AutofillMetricsTest, AutofillCreditCardIsDisabledAtStartup) {
/*pref_service=*/autofill_client_.GetPrefs(),
/*local_state=*/autofill_client_.GetPrefs(),
/*identity_manager=*/nullptr,
- /*client_profile_validator=*/nullptr,
/*history_service=*/nullptr,
/*strike_database=*/nullptr,
/*image_fetcher=*/nullptr,
@@ -4378,7 +4375,7 @@ TEST_F(AutofillMetricsTest, AutofillCreditCardIsDisabledAtStartup) {
TEST_F(AutofillMetricsTest, AddressSuggestionsCount) {
// Set up our form data.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("https://example.com/form.html");
@@ -4452,7 +4449,7 @@ TEST_F(AutofillMetricsTest, AddressSuggestionsCount) {
TEST_F(AutofillMetricsTest, CompanyNameSuggestions) {
// Set up our form data.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("https://example.com/form.html");
@@ -4495,7 +4492,7 @@ TEST_F(AutofillMetricsTest, CreditCardCheckoutFlowUserActions) {
// Set up our form data.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("https://example.com/form.html");
@@ -4684,7 +4681,7 @@ TEST_F(AutofillMetricsTest, CreditCardCheckoutFlowUserActions) {
// Test that the UPI Checkout flow form submit is correctly logged
TEST_F(AutofillMetricsTest, UpiVpaUkmTest) {
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -4718,7 +4715,7 @@ TEST_F(AutofillMetricsTest, ProfileCheckoutFlowUserActions) {
// Set up our form data.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("https://example.com/form.html");
@@ -4863,7 +4860,7 @@ TEST_F(AutofillMetricsTest, PolledCreditCardSuggestions_DebounceLogs) {
// Set up the form data.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://www.foo.com/");
@@ -4926,7 +4923,7 @@ TEST_F(AutofillMetricsTest, QueriedCreditCardFormIsSecure) {
// Set up the form data.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -4947,7 +4944,7 @@ TEST_F(AutofillMetricsTest, QueriedCreditCardFormIsSecure) {
{
// Simulate having seen this insecure form on page load.
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.url = GURL("http://example.com/form.html");
form.action = GURL("http://example.com/submit.html");
@@ -4978,7 +4975,7 @@ TEST_F(AutofillMetricsTest, QueriedCreditCardFormIsSecure) {
{
// Simulate having seen this secure form on page load.
browser_autofill_manager_->Reset();
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.url = GURL("https://example.com/form.html");
form.action = GURL("https://example.com/submit.html");
@@ -5003,7 +5000,7 @@ TEST_F(AutofillMetricsTest, PolledProfileSuggestions_DebounceLogs) {
// Set up the form data.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("https://example.com/form.html");
@@ -5062,7 +5059,7 @@ TEST_F(AutofillMetricsTest, PolledProfileSuggestions_DebounceLogs) {
TEST_P(AutofillMetricsIFrameTest, CreditCardParsedFormEvents) {
// Set up our form data.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -5097,7 +5094,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardParsedFormEvents) {
TEST_P(AutofillMetricsIFrameTest, CreditCardInteractedFormEvents) {
// Set up our form data.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -5155,7 +5152,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardInteractedFormEvents) {
TEST_P(AutofillMetricsIFrameTest, CreditCardPopupSuppressedFormEvents) {
// Set up our form data.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -5215,7 +5212,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardPopupSuppressedFormEvents) {
TEST_P(AutofillMetricsIFrameTest, CreditCardShownFormEvents) {
// Set up our form data.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -5481,7 +5478,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardSelectedFormEvents) {
true /* masked_card_is_enrolled_for_virtual_card */);
// Set up our form data.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -5564,8 +5561,9 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardSelectedFormEvents) {
// option based on the enrolled masked card.
base::HistogramTester histogram_tester;
std::string guid("10000000-0000-0000-0000-000000000002"); // masked card
- browser_autofill_manager_->FillVirtualCardInformation(guid, kDefaultPageID,
- form, form.fields[2]);
+ browser_autofill_manager_->FillOrPreviewVirtualCardInformation(
+ mojom::RendererFormDataAction::kFill, guid, kDefaultPageID, form,
+ form.fields[2]);
OnDidGetRealPan(AutofillClient::PaymentsRpcResult::kSuccess,
"6011000990139424");
histogram_tester.ExpectBucketCount(
@@ -5590,12 +5588,14 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardSelectedFormEvents) {
// Simulating selecting a virtual card multiple times.
base::HistogramTester histogram_tester;
std::string guid("10000000-0000-0000-0000-000000000002"); // masked card
- browser_autofill_manager_->FillVirtualCardInformation(guid, kDefaultPageID,
- form, form.fields[2]);
+ browser_autofill_manager_->FillOrPreviewVirtualCardInformation(
+ mojom::RendererFormDataAction::kFill, guid, kDefaultPageID, form,
+ form.fields[2]);
OnDidGetRealPan(AutofillClient::PaymentsRpcResult::kSuccess,
"6011000990139424");
- browser_autofill_manager_->FillVirtualCardInformation(guid, kDefaultPageID,
- form, form.fields[2]);
+ browser_autofill_manager_->FillOrPreviewVirtualCardInformation(
+ mojom::RendererFormDataAction::kFill, guid, kDefaultPageID, form,
+ form.fields[2]);
OnDidGetRealPan(AutofillClient::PaymentsRpcResult::kSuccess,
"6011000990139424");
histogram_tester.ExpectBucketCount(
@@ -5622,7 +5622,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardFilledFormEvents) {
true /* masked_card_is_enrolled_for_virtual_card */);
// Set up our form data.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -5673,8 +5673,9 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardFilledFormEvents) {
// based on the enrolled masked card.
base::HistogramTester histogram_tester;
std::string guid("10000000-0000-0000-0000-000000000002"); // masked card
- browser_autofill_manager_->FillVirtualCardInformation(
- guid, kDefaultPageID, form, form.fields.front());
+ browser_autofill_manager_->FillOrPreviewVirtualCardInformation(
+ mojom::RendererFormDataAction::kFill, guid, kDefaultPageID, form,
+ form.fields.front());
OnDidGetRealPan(AutofillClient::PaymentsRpcResult::kSuccess,
"6011000990139424");
histogram_tester.ExpectBucketCount(
@@ -5865,7 +5866,7 @@ TEST_F(AutofillMetricsTest, CreditCardUnmaskingPreflightCall) {
browser_autofill_manager_->MakeFrontendIDForTest(guid, std::string()));
// Preflight call is made only if a masked server card is available and the
// user is eligible for FIDO authentication (except iOS).
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
histogram_tester.ExpectTotalCount(preflight_call_metric, 0);
histogram_tester.ExpectTotalCount(preflight_latency_metric, 0);
#else
@@ -5892,7 +5893,7 @@ TEST_F(AutofillMetricsTest, CreditCardUnmaskingPreflightCall) {
browser_autofill_manager_->MakeFrontendIDForTest(guid, std::string()));
// Preflight call is made only if a masked server card is available and the
// user is eligible for FIDO authentication (except iOS).
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
histogram_tester.ExpectTotalCount(preflight_call_metric, 0);
histogram_tester.ExpectTotalCount(preflight_latency_metric, 0);
#else
@@ -5911,7 +5912,7 @@ TEST_F(AutofillMetricsTest, CreditCardGetRealPanDuration_ServerCard) {
false /* masked_card_is_enrolled_for_virtual_card */);
// Set up our form data.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -6111,7 +6112,7 @@ TEST_F(AutofillMetricsTest,
// Set up our form data.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -6157,7 +6158,7 @@ TEST_P(AutofillMetricsIFrameTest,
// Set up our form data.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -6205,7 +6206,7 @@ TEST_P(AutofillMetricsIFrameTest,
// Set up our form data.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -6254,7 +6255,7 @@ TEST_P(AutofillMetricsIFrameTest,
// Set up our form data.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -6304,7 +6305,7 @@ TEST_P(AutofillMetricsIFrameTest,
// Set up our form data.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -6354,7 +6355,7 @@ TEST_P(AutofillMetricsIFrameTest,
// Set up our form data.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -6416,7 +6417,7 @@ TEST_F(AutofillMetricsTest, ShouldNotLogFormEventNoCardForAddressForm) {
RecreateProfile(/*is_server=*/false);
// Set up our form data.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -6461,7 +6462,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardSubmittedFormEvents) {
true /* masked_card_is_enrolled_for_virtual_card */);
// Set up our form data.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -6664,8 +6665,9 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardSubmittedFormEvents) {
browser_autofill_manager_->OnAskForValuesToFill(
0, form, field, gfx::RectF(), /*autoselect_first_suggestion=*/false);
std::string guid("10000000-0000-0000-0000-000000000002"); // masked card
- browser_autofill_manager_->FillVirtualCardInformation(
- guid, kDefaultPageID, form, form.fields.front());
+ browser_autofill_manager_->FillOrPreviewVirtualCardInformation(
+ mojom::RendererFormDataAction::kFill, guid, kDefaultPageID, form,
+ form.fields.front());
OnDidGetRealPan(AutofillClient::PaymentsRpcResult::kSuccess,
"6011000990139424");
browser_autofill_manager_->OnFormSubmitted(
@@ -7011,7 +7013,7 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardWillSubmitFormEvents) {
true /* masked_card_is_enrolled_for_virtual_card */);
// Set up our form data.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -7122,8 +7124,9 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardWillSubmitFormEvents) {
browser_autofill_manager_->OnAskForValuesToFill(
0, form, field, gfx::RectF(), /*autoselect_first_suggestion=*/false);
std::string guid("10000000-0000-0000-0000-000000000002"); // masked card
- browser_autofill_manager_->FillVirtualCardInformation(
- guid, kDefaultPageID, form, form.fields.front());
+ browser_autofill_manager_->FillOrPreviewVirtualCardInformation(
+ mojom::RendererFormDataAction::kFill, guid, kDefaultPageID, form,
+ form.fields.front());
OnDidGetRealPan(AutofillClient::PaymentsRpcResult::kSuccess,
"6011000990139424");
browser_autofill_manager_->OnFormSubmitted(
@@ -7359,9 +7362,6 @@ TEST_P(AutofillMetricsIFrameTest, CreditCardWillSubmitFormEvents) {
// Test that we log form events for masked server card with offers.
TEST_F(AutofillMetricsTest, LogServerOfferFormEvents) {
- scoped_feature_list_.InitAndEnableFeature(
- features::kAutofillEnableOffersInDownstream);
-
// Set up our form data.
FormData form;
form.name = u"TestForm";
@@ -7828,7 +7828,7 @@ TEST_F(AutofillMetricsTest, LogServerOfferFormEvents) {
TEST_F(AutofillMetricsTest, MixedParsedFormEvents) {
// Set up our form data.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -7874,7 +7874,7 @@ TEST_F(AutofillMetricsTest, MixedParsedFormEvents) {
TEST_F(AutofillMetricsTest, AddressParsedFormEvents) {
// Set up our form data.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -7919,7 +7919,7 @@ TEST_F(AutofillMetricsTest, AddressParsedFormEvents) {
TEST_F(AutofillMetricsTest, AddressInteractedFormEvents) {
// Set up our form data.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -7997,7 +7997,7 @@ TEST_F(AutofillMetricsTest, AddressSuppressedFormEvents) {
RecreateProfile(/*is_server=*/false);
// Set up our form data.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -8092,7 +8092,7 @@ TEST_F(AutofillMetricsTest, AddressShownFormEvents) {
RecreateProfile(/*is_server=*/false);
// Set up our form data.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -8208,7 +8208,7 @@ TEST_F(AutofillMetricsTest, AddressFilledFormEvents) {
RecreateProfile(/*is_server=*/false);
// Set up our form data.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -8329,7 +8329,7 @@ TEST_F(AutofillMetricsTest, AddressSubmittedFormEvents) {
RecreateProfile(/*is_server=*/false);
// Set up our form data.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -8545,7 +8545,7 @@ TEST_F(AutofillMetricsTest, AddressWillSubmitFormEvents) {
RecreateProfile(/*is_server=*/false);
// Set up our form data.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -8733,7 +8733,7 @@ TEST_F(AutofillMetricsTest, AddressWillSubmitFormEvents) {
TEST_F(AutofillMetricsTest, RecordStandalonePhoneField) {
// Set up our form data.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -8758,7 +8758,7 @@ TEST_F(AutofillMetricsTest, RecordStandalonePhoneField) {
TEST_F(AutofillMetricsTest, CreditCardFormEventsAreSegmented) {
// Set up our form data.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -8876,7 +8876,7 @@ TEST_F(AutofillMetricsTest, CreditCardFormEventsAreSegmented) {
TEST_F(AutofillMetricsTest, AddressFormEventsAreSegmented) {
// Set up our form data.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -9079,7 +9079,7 @@ TEST_F(AutofillMetricsTest, LogVerificationStatusesOfAddressTokens) {
TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
// Start with a form with insufficiently many fields.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -9346,7 +9346,7 @@ TEST_F(
AutofillMetricsTest,
AutofillFormSubmittedState_DontCountUnfilledFieldsWithOnlyFillWhenFocused) {
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -9484,7 +9484,7 @@ TEST_F(AutofillMetricsTest, LogUserHappinessMetric_UnknownForm) {
TEST_F(AutofillMetricsTest, UserHappinessFormInteraction_EmptyForm) {
// Load a fillable form.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -9514,7 +9514,7 @@ TEST_F(AutofillMetricsTest, UserHappinessFormInteraction_CreditCardForm) {
// Load a fillable form.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("https://example.com/form.html");
@@ -9686,7 +9686,7 @@ TEST_F(AutofillMetricsTest, UserHappinessFormInteraction_CreditCardForm) {
TEST_F(AutofillMetricsTest, UserHappinessFormInteraction_AddressForm) {
// Load a fillable form.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -9947,7 +9947,7 @@ TEST_F(AutofillMetricsTest, FormFillDuration) {
// Load a fillable form.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -9966,7 +9966,7 @@ TEST_F(AutofillMetricsTest, FormFillDuration) {
// Fill additional form.
FormData second_form = form;
- second_form.host_frame = test::GetLocalFrameToken();
+ second_form.host_frame = test::MakeLocalFrameToken();
second_form.unique_renderer_id = test::MakeFormRendererId();
test::CreateTestFormField("Second Phone", "second_phone", "", "text", &field);
second_form.fields.push_back(field);
@@ -10383,7 +10383,7 @@ TEST_F(AutofillMetricsTest, ProfileActionOnFormSubmitted) {
// Load a fillable form.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -10515,7 +10515,7 @@ class AutofillMetricsParseQueryResponseTest : public testing::Test {
public:
void SetUp() override {
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.url = GURL("http://foo.com");
form.main_frame_origin = url::Origin::Create(GURL("http://foo_root.com"));
@@ -10675,7 +10675,7 @@ TEST_F(AutofillMetricsTest, NonsecureCreditCardForm) {
// Set up our form data.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -10736,7 +10736,7 @@ TEST_F(AutofillMetricsTest,
// Set up our form data.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("https://example.com/form.html");
@@ -10865,7 +10865,7 @@ TEST_F(AutofillMetricsTest, DISABLED_AutofillSuggestionShownTest) {
false /* include_full_server_credit_card */,
false /* masked_card_is_enrolled_for_virtual_card */);
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example_cc.com/form.html");
@@ -10903,7 +10903,7 @@ TEST_F(AutofillMetricsTest, DISABLED_AutofillSuggestionShownTest) {
TEST_F(AutofillMetricsTest, DynamicFormMetrics) {
// Set up our form data.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -11028,7 +11028,7 @@ TEST_F(AutofillMetricsTest, LogUserHappinessBySecurityLevel) {
TEST_F(AutofillMetricsTest, LogUserHappinessBySecurityLevel_FromFormEvents) {
// Load a fillable form.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -11334,7 +11334,7 @@ TEST_F(AutofillMetricsTest, FrameHasNoForm) {
// autocomplete="one-time-code".
TEST_F(AutofillMetricsTest, FrameHasAutocompleteOneTimeCode) {
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -11368,7 +11368,7 @@ TEST_F(AutofillMetricsTest, FrameHasAutocompleteOneTimeCode) {
// autocomplete="one-time-code".
TEST_F(AutofillMetricsTest, FrameDoesNotHaveAutocompleteOneTimeCode) {
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -11397,7 +11397,7 @@ TEST_F(AutofillMetricsTest, FrameDoesNotHaveAutocompleteOneTimeCode) {
// autocomplete attribute but there are at least 3 fields in the form.
TEST_F(AutofillMetricsTest, FrameHasPhoneNumberFieldWithoutAutocomplete) {
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -11433,7 +11433,7 @@ TEST_F(AutofillMetricsTest, FrameHasPhoneNumberFieldWithoutAutocomplete) {
// autocomplete attribute and there are less than 3 fields in the form.
TEST_F(AutofillMetricsTest, FrameHasSinglePhoneNumberFieldWithoutAutocomplete) {
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -11485,7 +11485,7 @@ TEST_F(AutofillMetricsTest, FrameHasPhoneNumberFieldWithAutocomplete) {
// field.
TEST_F(AutofillMetricsTest, FrameDoesNotHavePhoneNumberField) {
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -11512,7 +11512,7 @@ TEST_F(AutofillMetricsTest, FrameDoesNotHavePhoneNumberField) {
// ContentAutofillDriver is not visible to TestAutofillDriver on iOS.
// In addition, WebOTP will not ship on iOS.
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
// Verify that we correctly log PhoneCollectionMetricState::kNone.
TEST_F(AutofillMetricsTest, WebOTPPhoneCollectionMetricsStateNone) {
FormData form;
@@ -11714,7 +11714,7 @@ TEST_F(AutofillMetricsTest, AutocompleteOneTimeCodeFormFilledDuration) {
test_clock.SetNowTicks(now);
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -11769,7 +11769,7 @@ TEST_F(AutofillMetricsTest, AutocompleteOneTimeCodeFormFilledDuration) {
}
}
-#endif // !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_IOS)
TEST_F(AutofillMetricsTest, LogAutocompleteSuggestionAcceptedIndex_WithIndex) {
base::HistogramTester histogram_tester;
@@ -11970,7 +11970,7 @@ TEST_P(AutofillMetricsFunnelTest, LogFunnelMetrics) {
// Load a fillable form.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("http://example.com/form.html");
@@ -12126,7 +12126,7 @@ TEST_F(AutofillMetricsFunnelTest, AblationState) {
// Load a fillable form.
FormData form;
- form.host_frame = test::GetLocalFrameToken();
+ form.host_frame = test::MakeLocalFrameToken();
form.unique_renderer_id = test::MakeFormRendererId();
form.name = u"TestForm";
form.url = GURL("https://example.com/form.html");
@@ -12523,6 +12523,95 @@ TEST_F(AutofillMetricsTest, AutofilledStateFieldSource) {
1);
}
+// Tests the following 4 cases when |kAutofillPreventOverridingPrefilledValues|
+// is enabled:
+// 1. The field is not autofilled since it has a prefilled value but the value
+// is edited before the form submission and is same as the value that was
+// to be autofilled in the field.
+// |Autofill.IsValueNotAutofilledOverExistingValueSameAsSubmittedValue|
+// should emit true for this case.
+// 2. The field is not autofilled since it has a prefilled value but the value
+// is edited before the form submission and is different than the value that
+// was to be autofilled in the field.
+// |Autofill.IsValueNotAutofilledOverExistingValueSameAsSubmittedValue|
+// should emit false for this case.
+// 3. The field had a prefilled value that was similar to the value to be
+// autofilled in the field.
+// |Autofill.IsValueNotAutofilledOverExistingValueSameAsSubmittedValue|
+// should not record anything in this case.
+// 4. Selection fields are always overridden by Autofill.
+// |Autofill.IsValueNotAutofilledOverExistingValueSameAsSubmittedValue|
+// should not record anything in this case.
+TEST_F(AutofillMetricsTest,
+ IsValueNotAutofilledOverExistingValueSameAsSubmittedValue) {
+ base::test::ScopedFeatureList features;
+ features.InitAndEnableFeature(
+ autofill::features::kAutofillPreventOverridingPrefilledValues);
+ RecreateProfile(false);
+
+ FormData form = test::GetFormData(
+ {.description_for_logging = "AutofilledStateFieldSource",
+ .fields = {{.role = ServerFieldType::NAME_FULL},
+ {.role = ServerFieldType::ADDRESS_HOME_CITY,
+ .value = u"Sacremento"}, // Case #1
+ {.role = ServerFieldType::ADDRESS_HOME_STATE,
+ .value = u"CA",
+ .form_control_type = "select-one",
+ .select_options = {{u"TN", u"Tennesse"},
+ {u"CA", u"California"},
+ {u"WA", u"Washington DC"}}}, // Case #4
+ {.role = ServerFieldType::ADDRESS_HOME_ZIP,
+ .value = u"00000"}, // Case #2
+ {.role = ServerFieldType::PHONE_HOME_WHOLE_NUMBER,
+ .value = u"12345678901"}, // Case #3
+ {.role = ServerFieldType::ADDRESS_HOME_COUNTRY}}});
+
+ std::vector<ServerFieldType> heuristic_types = {
+ NAME_FULL, ADDRESS_HOME_CITY, ADDRESS_HOME_STATE,
+ ADDRESS_HOME_ZIP, PHONE_HOME_WHOLE_NUMBER, ADDRESS_HOME_COUNTRY};
+ std::vector<ServerFieldType> server_types = {
+ NAME_FULL, ADDRESS_HOME_CITY, ADDRESS_HOME_STATE,
+ ADDRESS_HOME_ZIP, PHONE_HOME_WHOLE_NUMBER, ADDRESS_HOME_COUNTRY};
+
+ // Simulate having seen this form on page load.
+ browser_autofill_manager_->AddSeenForm(form, heuristic_types, server_types);
+
+ browser_autofill_manager_->OnAskForValuesToFill(
+ 0, form, form.fields[0], gfx::RectF(),
+ /*autoselect_first_suggestion=*/false);
+ browser_autofill_manager_->DidShowSuggestions(
+ /*has_autofill_suggestions=*/true, form, form.fields[0]);
+
+ std::string guid(kTestGuid);
+ browser_autofill_manager_->FillOrPreviewForm(
+ mojom::RendererFormDataAction::kFill, 0, form, form.fields.front(),
+ browser_autofill_manager_->MakeFrontendIDForTest(std::string(), guid));
+
+ // Case #1: Change submitted value to expected autofilled value for the field.
+ // The histogram should emit true for this.
+ form.fields[1].value = u"Memphis";
+ browser_autofill_manager_->OnTextFieldDidChange(form, form.fields[1],
+ gfx::RectF(), TimeTicks());
+
+ // Case #2: Change submitted value such that it different than expected
+ // autofilled value for the field. The histogram should emit false for this.
+ form.fields[3].value = u"00001";
+ browser_autofill_manager_->OnTextFieldDidChange(form, form.fields[3],
+ gfx::RectF(), TimeTicks());
+
+ // Simulate form submission.
+ base::HistogramTester histogram_tester;
+ browser_autofill_manager_->OnFormSubmitted(form, /*known_success=*/false,
+ SubmissionSource::FORM_SUBMISSION);
+
+ histogram_tester.ExpectBucketCount(
+ "Autofill.IsValueNotAutofilledOverExistingValueSameAsSubmittedValue",
+ true, 1);
+ histogram_tester.ExpectBucketCount(
+ "Autofill.IsValueNotAutofilledOverExistingValueSameAsSubmittedValue",
+ false, 1);
+}
+
// Base class for cross-frame filling metrics, in particular for
// Autofill.CreditCard.SeamlessFills.* and Autofill.CreditCard.NumberFills.*.
class AutofillMetricsCrossFrameFormTest : public AutofillMetricsTest {
diff --git a/chromium/components/autofill/core/browser/metrics/form_events/credit_card_form_event_logger.cc b/chromium/components/autofill/core/browser/metrics/form_events/credit_card_form_event_logger.cc
index ecb0d709fb7..da83914d118 100644
--- a/chromium/components/autofill/core/browser/metrics/form_events/credit_card_form_event_logger.cc
+++ b/chromium/components/autofill/core/browser/metrics/form_events/credit_card_form_event_logger.cc
@@ -163,6 +163,26 @@ void CreditCardFormEventLogger::OnDidFillSuggestion(
break;
}
Log(e, form);
+
+ // In a multi-frame form, a cross-origin field is only filled if
+ // shared-autofill is enabled in the field's frame. If Autofill was
+ // triggered on the main origin, shared-autofill is even sufficient for the
+ // fill. We therefore log how often enabling shared-autofill would suffice
+ // to fix Autofill.
+ //
+ // Shared-autofill is a policy-controlled feature. As such, a parent frame
+ // can enable it in a child frame with in the iframe's "allow" attribute:
+ // <iframe allow="shared-autofill">.
+ const url::Origin& triggered_origin = field.origin;
+ if (triggered_origin == form.main_frame_origin() &&
+ base::ranges::any_of(form, [&](const auto& f) {
+ FieldGlobalId id = f->global_id();
+ return f->origin != form.main_frame_origin() &&
+ field_types_to_be_filled_before_security_policy.contains(id) &&
+ !field_types_filled_after_security_policy.contains(id);
+ })) {
+ Log(FORM_EVENT_CREDIT_CARD_MISSING_SHARED_AUTOFILL, form);
+ }
}
switch (record_type) {
diff --git a/chromium/components/autofill/core/browser/metrics/form_events/form_events.h b/chromium/components/autofill/core/browser/metrics/form_events/form_events.h
index 3a953e72965..6a36695b478 100644
--- a/chromium/components/autofill/core/browser/metrics/form_events/form_events.h
+++ b/chromium/components/autofill/core/browser/metrics/form_events/form_events.h
@@ -121,6 +121,11 @@ enum FormEvent {
FORM_EVENT_CREDIT_CARD_SEAMLESSNESS_FULL_FILL_BUT_EXPDATE_MISSING,
FORM_EVENT_CREDIT_CARD_SEAMLESSNESS_PARTIAL_FILL,
+ // A cross-origin fill was prevented only because shared-autofill was disabled
+ // in the field's frame. Shared-autofill is a policy-controlled feature by
+ // which a frame can allow a child-frame to be autofilled across origin.
+ FORM_EVENT_CREDIT_CARD_MISSING_SHARED_AUTOFILL,
+
NUM_FORM_EVENTS,
};
diff --git a/chromium/components/autofill/core/browser/metrics/payments/virtual_card_enrollment_metrics.cc b/chromium/components/autofill/core/browser/metrics/payments/virtual_card_enrollment_metrics.cc
new file mode 100644
index 00000000000..e4bed0107a6
--- /dev/null
+++ b/chromium/components/autofill/core/browser/metrics/payments/virtual_card_enrollment_metrics.cc
@@ -0,0 +1,153 @@
+// Copyright 2022 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.
+
+#include "components/autofill/core/browser/metrics/payments/virtual_card_enrollment_metrics.h"
+
+#include "base/metrics/histogram_functions.h"
+#include "base/notreached.h"
+#include "base/strings/strcat.h"
+#include "base/strings/string_util.h"
+#include "components/autofill/core/browser/payments/virtual_card_enrollment_flow.h"
+
+namespace autofill {
+
+namespace {
+
+// Converts the VirtualCardEnrollmentRequestType to string to be used in
+// histograms.
+const char* GetVirtualCardEnrollmentRequestType(
+ VirtualCardEnrollmentRequestType type) {
+ switch (type) {
+ case VirtualCardEnrollmentRequestType::kEnroll:
+ return "Enroll";
+ case VirtualCardEnrollmentRequestType::kUnenroll:
+ return "Unenroll";
+ case VirtualCardEnrollmentRequestType::kNone:
+ return "Unknown";
+ }
+}
+
+} // namespace
+
+void LogVirtualCardEnrollmentBubbleShownMetric(
+ VirtualCardEnrollmentBubbleSource source,
+ bool is_reshow) {
+ base::UmaHistogramBoolean(
+ "Autofill.VirtualCardEnrollBubble.Shown." +
+ VirtualCardEnrollmentBubbleSourceToMetricSuffix(source),
+ is_reshow);
+}
+
+void LogVirtualCardEnrollmentBubbleResultMetric(
+ VirtualCardEnrollmentBubbleResult result,
+ VirtualCardEnrollmentBubbleSource source,
+ bool is_reshow) {
+ base::UmaHistogramEnumeration(
+ "Autofill.VirtualCardEnrollBubble.Result." +
+ VirtualCardEnrollmentBubbleSourceToMetricSuffix(source) +
+ (is_reshow ? ".Reshows" : ".FirstShow"),
+ result);
+}
+
+void LogGetDetailsForEnrollmentRequestAttempt(
+ VirtualCardEnrollmentSource source) {
+ base::UmaHistogramBoolean(
+ base::StrCat({"Autofill.VirtualCard.GetDetailsForEnrollment.Attempt.",
+ VirtualCardEnrollmentSourceToMetricSuffix(source)}),
+ true);
+}
+
+void LogGetDetailsForEnrollmentRequestResult(VirtualCardEnrollmentSource source,
+ bool succeeded) {
+ base::UmaHistogramBoolean(
+ base::StrCat({"Autofill.VirtualCard.GetDetailsForEnrollment.Result.",
+ VirtualCardEnrollmentSourceToMetricSuffix(source)}),
+ succeeded);
+}
+
+void LogUpdateVirtualCardEnrollmentRequestAttempt(
+ VirtualCardEnrollmentSource source,
+ VirtualCardEnrollmentRequestType type) {
+ base::UmaHistogramBoolean(
+ base::JoinString(
+ {"Autofill.VirtualCard", GetVirtualCardEnrollmentRequestType(type),
+ "Attempt", VirtualCardEnrollmentSourceToMetricSuffix(source)},
+ "."),
+ true);
+}
+
+void LogUpdateVirtualCardEnrollmentRequestResult(
+ VirtualCardEnrollmentSource source,
+ VirtualCardEnrollmentRequestType type,
+ bool succeeded) {
+ base::UmaHistogramBoolean(
+ base::JoinString(
+ {"Autofill.VirtualCard", GetVirtualCardEnrollmentRequestType(type),
+ "Result", VirtualCardEnrollmentSourceToMetricSuffix(source)},
+ "."),
+ succeeded);
+}
+
+void LogVirtualCardEnrollmentLinkClickedMetric(
+ VirtualCardEnrollmentLinkType link_type,
+ VirtualCardEnrollmentBubbleSource source) {
+ base::UmaHistogramBoolean(
+ "Autofill.VirtualCardEnroll.LinkClicked." +
+ VirtualCardEnrollmentBubbleSourceToMetricSuffix(source) + "." +
+ VirtualCardEnrollmentLinkTypeToMetricSuffix(link_type),
+ true);
+}
+
+void LogVirtualCardEnrollBubbleLatencySinceUpstream(
+ const base::TimeDelta& latency) {
+ base::UmaHistogramTimes(
+ "Autofill.VirtualCardEnrollBubble.LatencySinceUpstream", latency);
+}
+
+std::string VirtualCardEnrollmentBubbleSourceToMetricSuffix(
+ VirtualCardEnrollmentBubbleSource source) {
+ switch (source) {
+ case VirtualCardEnrollmentBubbleSource::
+ VIRTUAL_CARD_ENROLLMENT_UNKNOWN_SOURCE:
+ return "Unknown";
+ case VirtualCardEnrollmentBubbleSource::
+ VIRTUAL_CARD_ENROLLMENT_UPSTREAM_SOURCE:
+ return "Upstream";
+ case VirtualCardEnrollmentBubbleSource::
+ VIRTUAL_CARD_ENROLLMENT_DOWNSTREAM_SOURCE:
+ return "Downstream";
+ case VirtualCardEnrollmentBubbleSource::
+ VIRTUAL_CARD_ENROLLMENT_SETTINGS_PAGE_SOURCE:
+ return "SettingsPage";
+ }
+}
+
+const std::string VirtualCardEnrollmentLinkTypeToMetricSuffix(
+ VirtualCardEnrollmentLinkType link_type) {
+ switch (link_type) {
+ case VirtualCardEnrollmentLinkType::
+ VIRTUAL_CARD_ENROLLMENT_GOOGLE_PAYMENTS_TOS_LINK:
+ return "GoogleLegalMessageLink";
+ case VirtualCardEnrollmentLinkType::VIRTUAL_CARD_ENROLLMENT_ISSUER_TOS_LINK:
+ return "IssuerLegalMessageLink";
+ case VirtualCardEnrollmentLinkType::VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK:
+ return "LearnMoreLink";
+ }
+}
+
+const std::string VirtualCardEnrollmentSourceToMetricSuffix(
+ VirtualCardEnrollmentSource source) {
+ switch (source) {
+ case VirtualCardEnrollmentSource::kUpstream:
+ return "Upstream";
+ case VirtualCardEnrollmentSource::kDownstream:
+ return "Downstream";
+ case VirtualCardEnrollmentSource::kSettingsPage:
+ return "SettingsPage";
+ case VirtualCardEnrollmentSource::kNone:
+ return "Unknown";
+ }
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/metrics/payments/virtual_card_enrollment_metrics.h b/chromium/components/autofill/core/browser/metrics/payments/virtual_card_enrollment_metrics.h
new file mode 100644
index 00000000000..a8a991883af
--- /dev/null
+++ b/chromium/components/autofill/core/browser/metrics/payments/virtual_card_enrollment_metrics.h
@@ -0,0 +1,127 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_METRICS_PAYMENTS_VIRTUAL_CARD_ENROLLMENT_METRICS_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_METRICS_PAYMENTS_VIRTUAL_CARD_ENROLLMENT_METRICS_H_
+
+#include "components/autofill/core/browser/payments/virtual_card_enrollment_flow.h"
+
+#include <string>
+
+namespace base {
+class TimeDelta;
+}
+
+namespace autofill {
+
+// Metrics to record user interaction with the virtual card enrollment bubble.
+enum class VirtualCardEnrollmentBubbleResult {
+ // These values are persisted to logs. Entries should not be renumbered and
+ // numeric values should never be reused.
+
+ // The reason why the bubble is closed is not clear. Possible reason is the
+ // logging function is invoked before the closed reason is correctly set.
+ VIRTUAL_CARD_ENROLLMENT_BUBBLE_RESULT_UNKNOWN = 0,
+ // The user accepted the bubble.
+ VIRTUAL_CARD_ENROLLMENT_BUBBLE_ACCEPTED = 1,
+ // The user explicitly closed the bubble with the close button or ESC.
+ VIRTUAL_CARD_ENROLLMENT_BUBBLE_CLOSED = 2,
+ // The user did not interact with the bubble.
+ VIRTUAL_CARD_ENROLLMENT_BUBBLE_NOT_INTERACTED = 3,
+ // The bubble lost focus and was deactivated.
+ VIRTUAL_CARD_ENROLLMENT_BUBBLE_LOST_FOCUS = 4,
+ kMaxValue = VIRTUAL_CARD_ENROLLMENT_BUBBLE_LOST_FOCUS,
+};
+
+// Metrics to record the source that prompted the virtual card enrollment
+// bubble.
+enum class VirtualCardEnrollmentBubbleSource {
+ // These values are persisted to logs. Entries should not be renumbered and
+ // numeric values should never be reused.
+
+ // The source of the bubble is unknown.
+ VIRTUAL_CARD_ENROLLMENT_UNKNOWN_SOURCE = 0,
+ // Bubble began after an unenrolled VCN-eligible card was saved via credit
+ // card upload save (Upstream).
+ VIRTUAL_CARD_ENROLLMENT_UPSTREAM_SOURCE = 1,
+ // Bubble began after an unenrolled VCN-eligible card was unmasked during a
+ // checkout flow (Downstream).
+ VIRTUAL_CARD_ENROLLMENT_DOWNSTREAM_SOURCE = 2,
+ // Bubble began when the enrollment is started by user in Chrome settings
+ // page.
+ VIRTUAL_CARD_ENROLLMENT_SETTINGS_PAGE_SOURCE = 3,
+ kMaxValue = VIRTUAL_CARD_ENROLLMENT_SETTINGS_PAGE_SOURCE,
+};
+
+// Used to determine the type of link that was clicked for logging purposes. A
+// java IntDef@ is generated from this.
+// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.components.autofill
+enum class VirtualCardEnrollmentLinkType {
+ // These values are persisted to logs. Entries should not be renumbered and
+ // numeric values should never be reused.
+
+ // User selected the Google Payments terms of service link.
+ VIRTUAL_CARD_ENROLLMENT_GOOGLE_PAYMENTS_TOS_LINK = 0,
+ // User selected the issuer terms of service link.
+ VIRTUAL_CARD_ENROLLMENT_ISSUER_TOS_LINK = 1,
+ // User selected the learn more about virtual cards link.
+ VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK = 2,
+ kMaxValue = VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK,
+};
+
+// Bubble shown and closed related metrics.
+void LogVirtualCardEnrollmentBubbleShownMetric(
+ VirtualCardEnrollmentBubbleSource source,
+ bool is_reshow);
+void LogVirtualCardEnrollmentBubbleResultMetric(
+ VirtualCardEnrollmentBubbleResult result,
+ VirtualCardEnrollmentBubbleSource source,
+ bool is_reshow);
+
+// GetDetailsForEnrollmentRequest related metrics. Attempts and results should
+// be 1:1 mapping.
+void LogGetDetailsForEnrollmentRequestAttempt(
+ VirtualCardEnrollmentSource source);
+void LogGetDetailsForEnrollmentRequestResult(VirtualCardEnrollmentSource source,
+ bool succeeded);
+
+// UpdateVirtualCardEnrollmentRequest related metrics. Attempts and results
+// should be 1:1 mapping.
+void LogUpdateVirtualCardEnrollmentRequestAttempt(
+ VirtualCardEnrollmentSource source,
+ VirtualCardEnrollmentRequestType type);
+void LogUpdateVirtualCardEnrollmentRequestResult(
+ VirtualCardEnrollmentSource source,
+ VirtualCardEnrollmentRequestType type,
+ bool succeeded);
+
+// Virtual card enrollment bubble link clicked metrics.
+void LogVirtualCardEnrollmentLinkClickedMetric(
+ VirtualCardEnrollmentLinkType link_type,
+ VirtualCardEnrollmentBubbleSource source);
+
+// Latency Since Upstream metrics. Used to determine the time that it takes for
+// the server calls that need to be made between Save Card Bubble accept and
+// when the Virtual Card Enroll Bubble is shown.
+void LogVirtualCardEnrollBubbleLatencySinceUpstream(
+ const base::TimeDelta& latency);
+
+// Helper function used to convert VirtualCardEnrollmentBubbleSource enum to
+// name suffix.
+std::string VirtualCardEnrollmentBubbleSourceToMetricSuffix(
+ VirtualCardEnrollmentBubbleSource source);
+
+// Helper function used to convert VirtualCardEnrollmentLinkType enum to
+// name suffix.
+const std::string VirtualCardEnrollmentLinkTypeToMetricSuffix(
+ VirtualCardEnrollmentLinkType link_type);
+
+// Helper function used to convert VirtualCardEnrollmentSource enum to
+// name suffix.
+const std::string VirtualCardEnrollmentSourceToMetricSuffix(
+ VirtualCardEnrollmentSource source);
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_METRICS_PAYMENTS_VIRTUAL_CARD_ENROLLMENT_METRICS_H_
diff --git a/chromium/components/autofill/core/browser/pattern_provider/default_regex_patterns_unittest.cc b/chromium/components/autofill/core/browser/pattern_provider/default_regex_patterns_unittest.cc
index 0601e8da495..58a65ddbfe7 100644
--- a/chromium/components/autofill/core/browser/pattern_provider/default_regex_patterns_unittest.cc
+++ b/chromium/components/autofill/core/browser/pattern_provider/default_regex_patterns_unittest.cc
@@ -86,10 +86,11 @@ void DefaultRegExPatternsTest::Validate(const std::string& pattern_name,
TEST_P(DefaultRegExPatternsTest, TestPositiveAndNegativeCases) {
base::test::ScopedFeatureList scoped_feature_list;
- scoped_feature_list.InitWithFeatures(
- /*enabled_features=*/{features::kAutofillParsingPatternsLanguageDependent,
- features::kAutofillParsingPatternsNegativeMatching},
- /*disabled_features=*/{});
+ base::FieldTrialParams feature_parameters{
+ {features::kAutofillParsingWithLanguageSpecificPatternsParam.name,
+ "true"}};
+ scoped_feature_list.InitAndEnableFeatureWithParameters(
+ features::kAutofillParsingPatternProvider, feature_parameters);
PatternTestCase test_case = GetParam();
diff --git a/chromium/components/autofill/core/browser/pattern_provider/pattern_configuration_parser.cc b/chromium/components/autofill/core/browser/pattern_provider/pattern_configuration_parser.cc
index 52f329e8581..e045e01d4c5 100644
--- a/chromium/components/autofill/core/browser/pattern_provider/pattern_configuration_parser.cc
+++ b/chromium/components/autofill/core/browser/pattern_provider/pattern_configuration_parser.cc
@@ -31,6 +31,27 @@ const char kMatchFieldAttributesKey[] = "match_field_attributes";
const char kMatchFieldInputTypesKey[] = "match_field_input_types";
const char kVersionKey[] = "version";
+// Converts a JSON list like [1,2,3] to a DenseSet<Enum>{1,2,3}, provided that
+// the values are in the range [0, ..., Enum::kMaxValue].
+template <typename Enum>
+absl::optional<DenseSet<Enum>> JsonListToDenseSet(
+ const base::Value* list_value) {
+ if (!list_value)
+ return absl::nullopt;
+
+ DenseSet<Enum> set;
+ for (const base::Value& v : list_value->GetListDeprecated()) {
+ if (!v.is_int())
+ return absl::nullopt;
+ int i = v.GetInt();
+ auto attribute = static_cast<Enum>(i);
+ if (i < 0 || attribute > Enum::kMaxValue)
+ return absl::nullopt;
+ set.insert(attribute);
+ }
+ return set;
+}
+
bool ParseMatchingPattern(PatternProvider::Map& patterns,
const std::string& field_type,
const LanguageCode& language,
@@ -44,31 +65,27 @@ bool ParseMatchingPattern(PatternProvider::Map& patterns,
value.FindStringKey(kNegativePatternKey);
absl::optional<double> positive_score =
value.FindDoubleKey(kPositiveScoreKey);
- absl::optional<int> match_field_attributes =
- value.FindIntKey(kMatchFieldAttributesKey);
- absl::optional<int> match_field_input_types =
- value.FindIntKey(kMatchFieldInputTypesKey);
+ absl::optional<DenseSet<MatchAttribute>> match_field_attributes =
+ JsonListToDenseSet<MatchAttribute>(
+ value.FindListKey(kMatchFieldAttributesKey));
+ absl::optional<DenseSet<MatchFieldType>> match_field_input_types =
+ JsonListToDenseSet<MatchFieldType>(
+ value.FindListKey(kMatchFieldInputTypesKey));
if (!positive_pattern || !positive_score || !match_field_attributes ||
- !match_field_input_types)
+ !match_field_input_types) {
return false;
+ }
- autofill::MatchingPattern new_pattern;
+ MatchingPattern new_pattern;
new_pattern.positive_pattern = base::UTF8ToUTF16(*positive_pattern);
new_pattern.positive_score = *positive_score;
- if (negative_pattern != nullptr) {
- new_pattern.negative_pattern = base::UTF8ToUTF16(*negative_pattern);
- } else {
- new_pattern.negative_pattern = u"";
- }
- new_pattern.match_field_attributes = match_field_attributes.value();
- new_pattern.match_field_input_types = match_field_input_types.value();
+ new_pattern.negative_pattern =
+ negative_pattern ? base::UTF8ToUTF16(*negative_pattern) : u"";
+ new_pattern.match_field_attributes = *match_field_attributes;
+ new_pattern.match_field_input_types = *match_field_input_types;
new_pattern.language = language;
- // Shift to the right to match the MatchFieldTypes enum, which temporarily
- // starts at 1<<2 instead of 1<<0.
- new_pattern.match_field_input_types <<= 2;
-
std::vector<MatchingPattern>* pattern_list = &patterns[field_type][language];
pattern_list->push_back(new_pattern);
@@ -83,8 +100,7 @@ bool ParseMatchingPattern(PatternProvider::Map& patterns,
// are equal or both unspecified (i.e. set to 0) this prioritizes the remote
// configuration over the local one.
void OnJsonParsed(data_decoder::DataDecoder::ValueOrError result) {
- if (!base::FeatureList::IsEnabled(
- features::kAutofillParsingPatternsFromRemote)) {
+ if (features::kAutofillParsingWithRemotePatternsParam.Get()) {
DVLOG(1) << "Remote patterns are disabled.";
return;
}
@@ -138,7 +154,7 @@ absl::optional<PatternProvider::Map> GetConfigurationFromJsonObject(
return absl::nullopt;
}
- for (const auto& matchingPatternObj : inner_list->GetList()) {
+ for (const auto& matchingPatternObj : inner_list->GetListDeprecated()) {
bool success = ParseMatchingPattern(patterns, field_type, language,
matchingPatternObj);
if (!success) {
diff --git a/chromium/components/autofill/core/browser/pattern_provider/pattern_configuration_parser_unittest.cc b/chromium/components/autofill/core/browser/pattern_provider/pattern_configuration_parser_unittest.cc
index 32ed87e0611..68744937fcc 100644
--- a/chromium/components/autofill/core/browser/pattern_provider/pattern_configuration_parser_unittest.cc
+++ b/chromium/components/autofill/core/browser/pattern_provider/pattern_configuration_parser_unittest.cc
@@ -33,8 +33,8 @@ TEST(PatternConfigurationParserTest, WellFormedParsedCorrectly) {
"positive_pattern": "name|full name",
"positive_score": 2.0,
"negative_pattern": "company",
- "match_field_attributes": 2,
- "match_field_input_types": 3
+ "match_field_attributes": [1],
+ "match_field_input_types": [0,1]
}
],
"fr": [
@@ -43,8 +43,8 @@ TEST(PatternConfigurationParserTest, WellFormedParsedCorrectly) {
"positive_pattern": "nom|prenom",
"positive_score": 2.0,
"negative_pattern": "compagne",
- "match_field_attributes": 2,
- "match_field_input_types": 3
+ "match_field_attributes": [1],
+ "match_field_input_types": [0,1]
}
]
},
@@ -55,8 +55,8 @@ TEST(PatternConfigurationParserTest, WellFormedParsedCorrectly) {
"positive_pattern": "address",
"positive_score": 2.0,
"negative_pattern": "email",
- "match_field_attributes": 4,
- "match_field_input_types": 3
+ "match_field_attributes": [1],
+ "match_field_input_types": [0,1]
}
]
}
@@ -94,8 +94,6 @@ TEST(PatternConfigurationParserTest, WellFormedParsedCorrectly) {
ASSERT_EQ(u"compagne", pattern->negative_pattern);
ASSERT_EQ(LanguageCode("fr"), pattern->language);
ASSERT_NEAR(2.0, pattern->positive_score, 1e-6);
- ASSERT_EQ(2, pattern->match_field_attributes);
- ASSERT_EQ(3 << 2, pattern->match_field_input_types);
}
// Test that the parser does not return anything if some |MatchingPattern|
@@ -111,8 +109,8 @@ TEST(PatternConfigurationParserTest, MalformedMissingProperty) {
"positive_pattern": "name|full name",
"positive_score": 2.0,
"negative_pattern": "company",
- "match_field_attributes": 2,
- "match_field_input_types": 3
+ "match_field_attributes": [1],
+ "match_field_input_types": [0,1]
}
],
"fr": [
@@ -120,8 +118,8 @@ TEST(PatternConfigurationParserTest, MalformedMissingProperty) {
"pattern_identifier": "Name_fr",
"positive_pattern": "nom|prenom",
"negative_pattern": "compagne",
- "match_field_attributes": 2,
- "match_field_input_types": 3
+ "match_field_attributes": [1],
+ "match_field_input_types": [0,1]
}
]
}
@@ -148,8 +146,8 @@ TEST(PatternConfigurationParserTest, MalformedMissingVersion) {
"positive_pattern": "name|full name",
"positive_score": 2.0,
"negative_pattern": "company",
- "match_field_attributes": 2,
- "match_field_input_types": 3
+ "match_field_attributes": [1],
+ "match_field_input_types": [0,1]
}
]
}
@@ -166,7 +164,7 @@ TEST(PatternConfigurationParserTest, MalformedMissingVersion) {
// Test that the parser does not return anything if the inner key points
// to a single object instead of a list.
-TEST(PatternConfigurationParserTest, MalformedNotList) {
+TEST(PatternConfigurationParserTest, MalformedNotListPerLanguage) {
std::string json_message = R"(
{
"FULL_NAME": {
@@ -174,8 +172,112 @@ TEST(PatternConfigurationParserTest, MalformedNotList) {
"positive_pattern": "name|full name",
"positive_score": 2.0,
"negative_pattern": "company",
- "match_field_attributes": 2,
- "match_field_input_types": 3
+ "match_field_attributes": [1],
+ "match_field_input_types": [0,1]
+ }
+ }
+ })";
+ absl::optional<base::Value> json_object =
+ base::JSONReader::Read(json_message);
+
+ ASSERT_TRUE(json_object) << "Incorrectly formatted JSON string.";
+
+ absl::optional<PatternProvider::Map> optional_patterns =
+ GetConfigurationFromJsonObject(json_object.value());
+
+ ASSERT_FALSE(optional_patterns);
+}
+
+// Test that the parser does not return anything if the match_field_attributes
+// are not a list.
+TEST(PatternConfigurationParserTest, MalformedNotListMatchFieldAttributes) {
+ std::string json_message = R"(
+ {
+ "FULL_NAME": {
+ "en": {
+ "positive_pattern": "name|full name",
+ "positive_score": 2.0,
+ "negative_pattern": "company",
+ "match_field_attributes": 1,
+ "match_field_input_types": [0,1]
+ }
+ }
+ })";
+ absl::optional<base::Value> json_object =
+ base::JSONReader::Read(json_message);
+
+ ASSERT_TRUE(json_object) << "Incorrectly formatted JSON string.";
+
+ absl::optional<PatternProvider::Map> optional_patterns =
+ GetConfigurationFromJsonObject(json_object.value());
+
+ ASSERT_FALSE(optional_patterns);
+}
+
+// Test that the parser does not return anything if the match_field_attributes
+// are not a list.
+TEST(PatternConfigurationParserTest, MalformedNotListMatchFieldInputTypes) {
+ std::string json_message = R"(
+ {
+ "FULL_NAME": {
+ "en": {
+ "positive_pattern": "name|full name",
+ "positive_score": 2.0,
+ "negative_pattern": "company",
+ "match_field_attributes": [0],
+ "match_field_input_types": 0
+ }
+ }
+ })";
+ absl::optional<base::Value> json_object =
+ base::JSONReader::Read(json_message);
+
+ ASSERT_TRUE(json_object) << "Incorrectly formatted JSON string.";
+
+ absl::optional<PatternProvider::Map> optional_patterns =
+ GetConfigurationFromJsonObject(json_object.value());
+
+ ASSERT_FALSE(optional_patterns);
+}
+
+// Test that the parser does not return anything if the match_field_attributes
+// are out of bounds.
+TEST(PatternConfigurationParserTest, MalformedInvalidMatchingAttributes) {
+ std::string json_message = R"(
+ {
+ "FULL_NAME": {
+ "en": {
+ "positive_pattern": "name|full name",
+ "positive_score": 2.0,
+ "negative_pattern": "company",
+ "match_field_attributes": [-1],
+ "match_field_input_types": [0,1]
+ }
+ }
+ })";
+ absl::optional<base::Value> json_object =
+ base::JSONReader::Read(json_message);
+
+ ASSERT_TRUE(json_object) << "Incorrectly formatted JSON string.";
+
+ absl::optional<PatternProvider::Map> optional_patterns =
+ GetConfigurationFromJsonObject(json_object.value());
+
+ ASSERT_FALSE(optional_patterns);
+}
+
+// Test that the parser does not return anything if the match_field_input_types
+// are out of bounds.
+TEST(PatternConfigurationParserTest, MalformedInvalidMatchingFieldTypes) {
+ std::string json_message = R"(
+ {
+ "FULL_NAME": {
+ "en": {
+ "positive_pattern": "name|full name",
+ "positive_score": 2.0,
+ "negative_pattern": "company",
+ "match_field_attributes": [0],
+ "match_field_input_types": [0,999]
}
}
})";
diff --git a/chromium/components/autofill/core/browser/pattern_provider/pattern_provider.cc b/chromium/components/autofill/core/browser/pattern_provider/pattern_provider.cc
index f1e0d9090f4..b4e7d34f49e 100644
--- a/chromium/components/autofill/core/browser/pattern_provider/pattern_provider.cc
+++ b/chromium/components/autofill/core/browser/pattern_provider/pattern_provider.cc
@@ -22,7 +22,7 @@ namespace autofill {
namespace {
const char* kSourceCodeLanguage = "en";
-// Adds the English patterns, restricted to MatchFieldType MATCH_NAME, to
+// Adds the English patterns, restricted to MatchAttribute::kName, to
// every other language.
void EnrichPatternsWithEnVersion(
PatternProvider::Map* type_and_lang_to_patterns) {
@@ -36,7 +36,7 @@ void EnrichPatternsWithEnVersion(
continue;
std::vector<MatchingPattern> en_patterns = it->second;
for (MatchingPattern& en_pattern : en_patterns) {
- en_pattern.match_field_attributes = MATCH_NAME;
+ en_pattern.match_field_attributes = {MatchAttribute::kName};
}
for (auto& q : lang_to_patterns) {
@@ -99,8 +99,7 @@ const std::vector<MatchingPattern> PatternProvider::GetMatchPatterns(
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// TODO(crbug.com/1134496): Remove feature check once launched.
- if (base::FeatureList::IsEnabled(
- features::kAutofillParsingPatternsLanguageDependent)) {
+ if (features::kAutofillParsingWithLanguageSpecificPatternsParam.Get()) {
auto outer_it = patterns_.find(pattern_name);
if (outer_it != patterns_.end()) {
const std::map<LanguageCode, std::vector<MatchingPattern>>&
@@ -113,13 +112,8 @@ const std::vector<MatchingPattern> PatternProvider::GetMatchPatterns(
}
}
}
- return GetAllPatternsByType(pattern_name);
- } else if (base::FeatureList::IsEnabled(
- features::kAutofillParsingPatternsNegativeMatching)) {
- return GetAllPatternsByType(pattern_name);
- } else {
- return {};
}
+ return GetAllPatternsByType(pattern_name);
}
const std::vector<MatchingPattern> PatternProvider::GetMatchPatterns(
diff --git a/chromium/components/autofill/core/browser/pattern_provider/pattern_provider.h b/chromium/components/autofill/core/browser/pattern_provider/pattern_provider.h
index 129aa3d4518..4c33a74eee1 100644
--- a/chromium/components/autofill/core/browser/pattern_provider/pattern_provider.h
+++ b/chromium/components/autofill/core/browser/pattern_provider/pattern_provider.h
@@ -35,22 +35,24 @@ class PatternProvider {
// Setter for loading patterns from external storage.
void SetPatterns(const Map patterns, const base::Version& version);
- // Find the patterns for a given ServerFieldType and for a given
+ // Finds the patterns for a given ServerFieldType and for a given
// |page_language|.
const std::vector<MatchingPattern> GetMatchPatterns(
ServerFieldType type,
const LanguageCode& page_language) const;
- // Find the patterns for a given |pattern_name| and a given |page_language|.
+ // Finds the patterns for a given |pattern_name| and a given |page_language|.
+ // If there are no patterns for a given |page_language|, returns all patterns
+ // for |pattern_name| for any language.
const std::vector<MatchingPattern> GetMatchPatterns(
const std::string& pattern_name,
const LanguageCode& page_language) const;
- // Find all patterns, across all languages, for a given server field |type|.
+ // Finds all patterns, across all languages, for a given server field |type|.
const std::vector<MatchingPattern> GetAllPatternsByType(
ServerFieldType type) const;
- // Find all patterns, across all languages, for a given server field |type|.
+ // Finds all patterns, across all languages, for a given server field |type|.
const std::vector<MatchingPattern> GetAllPatternsByType(
const std::string& type) const;
diff --git a/chromium/components/autofill/core/browser/pattern_provider/pattern_provider_unittest.cc b/chromium/components/autofill/core/browser/pattern_provider/pattern_provider_unittest.cc
index a51a6df6942..dd5ddbfe500 100644
--- a/chromium/components/autofill/core/browser/pattern_provider/pattern_provider_unittest.cc
+++ b/chromium/components/autofill/core/browser/pattern_provider/pattern_provider_unittest.cc
@@ -32,13 +32,20 @@ namespace {
LanguageCode kLanguageDe("de");
LanguageCode kLanguageEn("en");
+base::FieldTrialParams GetFeatureParams(bool language_dependent) {
+ base::FieldTrialParams feature_parameters{
+ {features::kAutofillParsingWithLanguageSpecificPatternsParam.name,
+ language_dependent ? "true" : "false"}};
+ return feature_parameters;
+}
+
MatchingPattern GetCompanyPatternEn() {
autofill::MatchingPattern m_p;
m_p.positive_pattern = u"company|business|organization|organisation";
m_p.positive_score = 1.1;
m_p.negative_pattern = u"";
- m_p.match_field_attributes = MATCH_NAME;
- m_p.match_field_input_types = MATCH_TEXT;
+ m_p.match_field_attributes = {MatchAttribute::kName};
+ m_p.match_field_input_types = {MatchFieldType::kText};
m_p.language = kLanguageEn;
return m_p;
}
@@ -48,8 +55,8 @@ MatchingPattern GetCompanyPatternDe() {
m_p.positive_pattern = u"|(?<!con)firma|firmenname";
m_p.positive_score = 1.1;
m_p.negative_pattern = u"";
- m_p.match_field_attributes = MATCH_LABEL | MATCH_NAME;
- m_p.match_field_input_types = MATCH_TEXT;
+ m_p.match_field_attributes = {MatchAttribute::kLabel, MatchAttribute::kName};
+ m_p.match_field_input_types = {MatchFieldType::kText};
m_p.language = kLanguageDe;
return m_p;
}
@@ -119,8 +126,9 @@ bool operator==(const MatchingPattern& mp1, const MatchingPattern& mp2) {
TEST(AutofillPatternProviderTest, Single_Match) {
base::test::ScopedFeatureList scoped_feature_list;
- scoped_feature_list.InitAndEnableFeature(
- features::kAutofillParsingPatternsLanguageDependent);
+ scoped_feature_list.InitAndEnableFeatureWithParameters(
+ features::kAutofillParsingPatternProvider,
+ GetFeatureParams(/*language_dependent=*/true));
UnitTestPatternProvider p;
EXPECT_THAT(p.GetMatchPatterns("COMPANY_NAME", kLanguageEn),
@@ -164,12 +172,10 @@ TEST(AutofillPatternProviderTest, TestDefaultEqualsJson) {
TEST(AutofillPatternProviderTest, UnknownLanguages) {
{
- base::test::ScopedFeatureList feature;
- feature.InitWithFeatures(
- // enabled
- {features::kAutofillParsingPatternsLanguageDependent},
- // disabled
- {features::kAutofillParsingPatternsNegativeMatching});
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeatureWithParameters(
+ features::kAutofillParsingPatternProvider,
+ GetFeatureParams(/*language_dependent=*/true));
UnitTestPatternProvider p;
EXPECT_EQ(p.GetMatchPatterns(COMPANY_NAME, LanguageCode("")),
p.GetAllPatternsByType(COMPANY_NAME));
@@ -178,12 +184,10 @@ TEST(AutofillPatternProviderTest, UnknownLanguages) {
}
{
- base::test::ScopedFeatureList feature;
- feature.InitWithFeatures(
- // enabled
- {features::kAutofillParsingPatternsNegativeMatching},
- // disabled
- {features::kAutofillParsingPatternsLanguageDependent});
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeatureWithParameters(
+ features::kAutofillParsingPatternProvider,
+ GetFeatureParams(/*language_dependent=*/false));
UnitTestPatternProvider p;
EXPECT_EQ(p.GetMatchPatterns(COMPANY_NAME, LanguageCode("")),
p.GetAllPatternsByType(COMPANY_NAME));
@@ -194,12 +198,10 @@ TEST(AutofillPatternProviderTest, UnknownLanguages) {
TEST(AutofillPatternProviderTest, EnrichPatternsWithEnVersion) {
{
- base::test::ScopedFeatureList feature;
- feature.InitWithFeatures(
- // enabled
- {features::kAutofillParsingPatternsLanguageDependent},
- // disabled
- {features::kAutofillParsingPatternsNegativeMatching});
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeatureWithParameters(
+ features::kAutofillParsingPatternProvider,
+ GetFeatureParams(/*language_dependent=*/true));
UnitTestPatternProvider p;
EXPECT_EQ(p.GetMatchPatterns(COMPANY_NAME, kLanguageEn),
std::vector<MatchingPattern>{GetCompanyPatternEn()});
@@ -209,12 +211,10 @@ TEST(AutofillPatternProviderTest, EnrichPatternsWithEnVersion) {
}
{
- base::test::ScopedFeatureList feature;
- feature.InitWithFeatures(
- // enabled
- {features::kAutofillParsingPatternsNegativeMatching},
- // disabled
- {features::kAutofillParsingPatternsLanguageDependent});
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeatureWithParameters(
+ features::kAutofillParsingPatternProvider,
+ GetFeatureParams(/*language_dependent=*/false));
UnitTestPatternProvider p;
EXPECT_EQ(p.GetMatchPatterns(COMPANY_NAME, kLanguageEn),
std::vector<MatchingPattern>(
@@ -226,13 +226,10 @@ TEST(AutofillPatternProviderTest, EnrichPatternsWithEnVersion) {
}
TEST(AutofillPatternProviderTest, SortPatternsByScore) {
- base::test::ScopedFeatureList feature;
- feature.InitWithFeatures(
- // enabled
- {features::kAutofillParsingPatternsLanguageDependent,
- features::kAutofillParsingPatternsNegativeMatching},
- // disabled
- {});
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeatureWithParameters(
+ features::kAutofillParsingPatternProvider,
+ GetFeatureParams(/*language_dependent=*/true));
std::vector<MatchingPattern> de_input_patterns;
de_input_patterns.push_back(GetCompanyPatternDe());
de_input_patterns.push_back(GetCompanyPatternDe());
diff --git a/chromium/components/autofill/core/browser/pattern_provider/resources/regex_patterns.json b/chromium/components/autofill/core/browser/pattern_provider/resources/regex_patterns.json
index 76643233896..a02aeb86b0f 100644
--- a/chromium/components/autofill/core/browser/pattern_provider/resources/regex_patterns.json
+++ b/chromium/components/autofill/core/browser/pattern_provider/resources/regex_patterns.json
@@ -6,8 +6,8 @@
"positive_pattern": "street",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 129
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 7]
}
],
"de" : [
@@ -16,8 +16,8 @@
"positive_pattern": "stra(ss|ß)e",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 129
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 7]
}
],
"es" : [
@@ -26,8 +26,8 @@
"positive_pattern": "calle",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 129
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 7]
}
],
"ru" : [
@@ -36,8 +36,8 @@
"positive_pattern": "улица|название.?улицы",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 129
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 7]
}
],
"pt" : [
@@ -46,8 +46,8 @@
"positive_pattern": "rua|avenida|((?<!do |de )endereço)",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 129
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 7]
}
]
},
@@ -58,8 +58,8 @@
"positive_pattern": "apartment",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 69
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 6]
}
],
"es": [
@@ -68,8 +68,8 @@
"positive_pattern": "interior|número.*apartamento",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 69
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 6]
}
],
"de": [
@@ -78,8 +78,8 @@
"positive_pattern": "wohnung",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 69
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 6]
}
],
"ru": [
@@ -88,8 +88,8 @@
"positive_pattern": "квартир",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 69
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 6]
}
],
"it": [
@@ -98,8 +98,8 @@
"positive_pattern": "numero.*appartamento",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 69
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 6]
}
],
"fr": [
@@ -108,8 +108,8 @@
"positive_pattern": "numéro.*appartement",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 69
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 6]
}
]
},
@@ -120,8 +120,8 @@
"positive_pattern": "(house.?|street.?|^)number",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 69
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 6]
}
],
"de": [
@@ -130,8 +130,8 @@
"positive_pattern": "(haus|^)(nummer|nr\\.?)",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 69
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 6]
}
],
"pt": [
@@ -140,8 +140,8 @@
"positive_pattern": "^\\*?.?número(.?\\*?$| da residência)",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 69
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 6]
}
],
"es": [
@@ -150,8 +150,8 @@
"positive_pattern": "n(u|ú)mero.*apartamento|exterior",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 69
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 6]
}
],
"ru": [
@@ -160,8 +160,8 @@
"positive_pattern": "дом|номер.?дома",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 69
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 6]
}
]
},
@@ -172,8 +172,8 @@
"positive_pattern": "attention|attn",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
]
},
@@ -184,8 +184,8 @@
"positive_pattern": "province|region|other",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"es": [
@@ -194,8 +194,8 @@
"positive_pattern": "provincia",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"pt": [
@@ -204,8 +204,8 @@
"positive_pattern": "bairro|suburb",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
]
},
@@ -216,8 +216,8 @@
"positive_pattern": "address.*nickname|address.*label",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"tr": [
@@ -226,8 +226,8 @@
"positive_pattern": "adres ([İi]sim|başlığı|adı)",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"pt": [
@@ -236,8 +236,8 @@
"positive_pattern": "identificação do endereço",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"id": [
@@ -246,8 +246,8 @@
"positive_pattern": "(label|judul|nama) alamat",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
]
},
@@ -258,8 +258,8 @@
"positive_pattern": "company|business|organization|organisation",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"de": [
@@ -268,8 +268,8 @@
"positive_pattern": "(?<!con)firma|firmenname",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"es": [
@@ -278,8 +278,8 @@
"positive_pattern": "empresa",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"fr": [
@@ -288,8 +288,8 @@
"positive_pattern": "societe|société",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"it": [
@@ -298,8 +298,8 @@
"positive_pattern": "ragione.?sociale",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"ja": [
@@ -308,8 +308,8 @@
"positive_pattern": "会社",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"ru": [
@@ -318,8 +318,8 @@
"positive_pattern": "название.?компании",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"zh-CN": [
@@ -328,8 +328,8 @@
"positive_pattern": "å•ä½|å…¬å¸",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"fa": [
@@ -338,8 +338,8 @@
"positive_pattern": "شرکت",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"ko": [
@@ -348,8 +348,8 @@
"positive_pattern": "회사|ì§ìž¥",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"id": [
@@ -358,8 +358,8 @@
"positive_pattern": "(nama.?)?perusahaan",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
]
},
@@ -370,16 +370,16 @@
"positive_pattern": "^address$|address[_-]?line(one)?|address1|addr1|street|(?:shipping|billing)address$|house.?name",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 129
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 7]
},
{
"pattern_identifier": "en_address_line_1_label_preserving",
"positive_pattern": "(^\\W*address)|(address\\W*$)|(?:shipping|billing|mailing|pick.?up|drop.?off|delivery|sender|postal|recipient|home|work|office|school|business|mail)[\\s\\-]+address|address\\s+(of|for|to|from)|street.*(house|building|apartment|floor)|(house|building|apartment|floor).*street",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 1,
- "match_field_input_types": 129
+ "match_field_attributes": [0],
+ "match_field_input_types": [0, 7]
}
],
"de": [
@@ -388,8 +388,8 @@
"positive_pattern": "strasse|straße",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 129
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 7]
}
],
"es": [
@@ -398,8 +398,8 @@
"positive_pattern": "direccion|dirección",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 129
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 7]
}
],
"fr": [
@@ -408,16 +408,16 @@
"positive_pattern": "adresse",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 129
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 7]
},
{
"pattern_identifier": "fr_address_line_1_label_preserving",
"positive_pattern": "adresse",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 1,
- "match_field_input_types": 129
+ "match_field_attributes": [0],
+ "match_field_input_types": [0, 7]
}
],
"it": [
@@ -426,16 +426,16 @@
"positive_pattern": "indirizzo",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 129
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 7]
},
{
"pattern_identifier": "it_address_line_1_label_preserving",
"positive_pattern": "indirizzo",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 1,
- "match_field_input_types": 129
+ "match_field_attributes": [0],
+ "match_field_input_types": [0, 7]
}
],
"ja": [
@@ -444,16 +444,16 @@
"positive_pattern": "^ä½æ‰€$|ä½æ‰€1",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 129
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 7]
},
{
"pattern_identifier": "ja_address_line_1_label_preserving",
"positive_pattern": "ä½æ‰€",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 1,
- "match_field_input_types": 129
+ "match_field_attributes": [0],
+ "match_field_input_types": [0, 7]
}
],
"pt": [
@@ -462,8 +462,8 @@
"positive_pattern": "morada|((?<!do |de )endereço)",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 129
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 7]
}
],
"ru": [
@@ -472,16 +472,16 @@
"positive_pattern": "ÐдреÑ",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 129
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 7]
},
{
"pattern_identifier": "ru_address_line_1_label_preserving",
"positive_pattern": "улиц.*(дом|корпуÑ|квартир|Ñтаж)|(дом|корпуÑ|квартир|Ñтаж).*улиц",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 1,
- "match_field_input_types": 129
+ "match_field_attributes": [0],
+ "match_field_input_types": [0, 7]
}
],
"zh-CN": [
@@ -490,8 +490,8 @@
"positive_pattern": "地å€",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 129
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 7]
}
],
"tr": [
@@ -500,16 +500,16 @@
"positive_pattern": "(\\b|_)adres(?! tarifi)(\\b|_)",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 129
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 7]
},
{
"pattern_identifier": "tr_address_line_1_label_preserving",
"positive_pattern": "(\\b|_)adres(?! tarifi)(\\b|_)|(sokak|cadde).*(apartman|bina|daire|mahalle)|(apartman|bina|daire|mahalle).*(sokak|cadde)",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 1,
- "match_field_input_types": 129
+ "match_field_attributes": [0],
+ "match_field_input_types": [0, 7]
}
],
"ko": [
@@ -518,8 +518,8 @@
"positive_pattern": "^주소.?$|주소.?1",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 129
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 7]
}
,
{
@@ -527,8 +527,8 @@
"positive_pattern": "주소",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 1,
- "match_field_input_types": 129
+ "match_field_attributes": [0],
+ "match_field_input_types": [0, 7]
}
],
"id": [
@@ -537,8 +537,8 @@
"positive_pattern": "^alamat",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 129
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 7]
}
,
{
@@ -546,8 +546,8 @@
"positive_pattern": "^alamat",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 1,
- "match_field_input_types": 129
+ "match_field_attributes": [0],
+ "match_field_input_types": [0, 7]
}
]
},
@@ -558,16 +558,16 @@
"positive_pattern": "address[_-]?line(2|two)|address2|addr2|street|suite|unit",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
},
{
"pattern_identifier": "en_address_line_2_label_preserving",
"positive_pattern": "address|line",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 1,
- "match_field_input_types": 1
+ "match_field_attributes": [0],
+ "match_field_input_types": [0]
}
],
"de": [
@@ -576,8 +576,8 @@
"positive_pattern": "adresszusatz|ergänzende.?angaben",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"es": [
@@ -586,8 +586,8 @@
"positive_pattern": "direccion2|colonia|adicional",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"fr": [
@@ -596,16 +596,16 @@
"positive_pattern": "addresssuppl|complementnom|appartement",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
},
{
"pattern_identifier": "fr_address_line_2_label_preserving",
"positive_pattern": "adresse",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 1,
- "match_field_input_types": 1
+ "match_field_attributes": [0],
+ "match_field_input_types": [0]
}
],
"it": [
@@ -614,16 +614,16 @@
"positive_pattern": "indirizzo2",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
},
{
"pattern_identifier": "it_address_line_2_label_preserving",
"positive_pattern": "indirizzo",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 1,
- "match_field_input_types": 1
+ "match_field_attributes": [0],
+ "match_field_input_types": [0]
}
],
"ja": [
@@ -632,8 +632,8 @@
"positive_pattern": "ä½æ‰€2",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"pt": [
@@ -642,8 +642,8 @@
"positive_pattern": "complemento|addrcomplement",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"ru": [
@@ -652,8 +652,8 @@
"positive_pattern": "Улица",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"zh-CN": [
@@ -662,16 +662,16 @@
"positive_pattern": "地å€2",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
},
{
"pattern_identifier": "zh_address_line_2_label_preserving",
"positive_pattern": "地å€",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 1,
- "match_field_input_types": 1
+ "match_field_attributes": [0],
+ "match_field_input_types": [0]
}
],
"ko": [
@@ -680,16 +680,16 @@
"positive_pattern": "주소.?2",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
},
{
"pattern_identifier": "ko_address_line_2_label_preserving",
"positive_pattern": "주소",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 1,
- "match_field_input_types": 1
+ "match_field_attributes": [0],
+ "match_field_input_types": [0]
}
]
},
@@ -700,8 +700,8 @@
"positive_pattern": "address.*line[3-9]|address[3-9]|addr[3-9]|street|line[3-9]",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"es": [
@@ -710,8 +710,8 @@
"positive_pattern": "municipio",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"fr": [
@@ -720,8 +720,8 @@
"positive_pattern": "batiment|residence",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"it": [
@@ -730,8 +730,8 @@
"positive_pattern": "indirizzo[3-9]",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
]
},
@@ -742,8 +742,8 @@
"positive_pattern": "lookup",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
]
},
@@ -754,8 +754,8 @@
"positive_pattern": "country|countries",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 137
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 3, 7]
}
],
"es": [
@@ -764,8 +764,8 @@
"positive_pattern": "país|pais",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 137
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 3, 7]
}
],
"de": [
@@ -774,8 +774,8 @@
"positive_pattern": "(\\b|_)land(\\b|_)(?!.*(mark.*))",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 137
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 3, 7]
}
],
"ja": [
@@ -784,8 +784,8 @@
"positive_pattern": "(?<!(入|出))国",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 137
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 3, 7]
}
],
"zh-CN": [
@@ -794,8 +794,8 @@
"positive_pattern": "国家",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 137
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 3, 7]
}
],
"ko": [
@@ -804,8 +804,8 @@
"positive_pattern": "êµ­ê°€|나ë¼",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 137
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 3, 7]
}
],
"tr": [
@@ -814,8 +814,8 @@
"positive_pattern": "(\\b|_)(ülke|ulce|ulke)(\\b|_)",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 137
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 3, 7]
}
],
"fa": [
@@ -824,8 +824,8 @@
"positive_pattern": "کشور",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 137
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 3, 7]
}
],
"id": [
@@ -834,8 +834,8 @@
"positive_pattern": "negara",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 137
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 3, 7]
}
]
},
@@ -846,8 +846,8 @@
"positive_pattern": "location",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 136
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [3, 7]
}
]
},
@@ -857,10 +857,19 @@
"pattern_identifier": "en_zip_code_preserving",
"positive_pattern": "zip|postal|post.*code|pcode|pin.?code",
"positive_score": 1.1,
- "negative_pattern": "\\.zip",
- "negative_patterns_explainer": ".zip refers to a file extension",
- "match_field_attributes": 3,
- "match_field_input_types": 69
+ "negative_pattern": "\\.zip\\b",
+ "negative_patterns_explainer": ".zip refers to a file extension. However, there are field billingAddress.zip",
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 6]
+ },
+ {
+ "pattern_identifier": "en_zip_code_preserving",
+ "positive_pattern": "address\\.zip",
+ "positive_score": 1.1,
+ "negative_pattern": null,
+ "negative_patterns_explainer": "",
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 6]
}
],
"de": [
@@ -869,8 +878,8 @@
"positive_pattern": "postleitzahl",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 69
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 6]
}
],
"es": [
@@ -879,8 +888,8 @@
"positive_pattern": "\\bcp\\b",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 69
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 6]
}
],
"fr": [
@@ -889,8 +898,8 @@
"positive_pattern": "\\bcdp\\b",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 69
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 6]
}
],
"it": [
@@ -899,8 +908,8 @@
"positive_pattern": "\\bcap\\b",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 69
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 6]
}
],
"ja": [
@@ -909,8 +918,8 @@
"positive_pattern": "郵便番å·",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 69
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 6]
}
],
"pt": [
@@ -919,8 +928,8 @@
"positive_pattern": "codigo|codpos|\\bcep\\b",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 69
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 6]
}
],
"ru": [
@@ -929,8 +938,8 @@
"positive_pattern": "Почтовый.?ИндекÑ",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 69
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 6]
}
],
"hi": [
@@ -939,8 +948,8 @@
"positive_pattern": "पिन.?कोड",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 69
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 6]
}
],
"ml": [
@@ -949,8 +958,8 @@
"positive_pattern": "പിനàµâ€à´•àµ‹à´¡àµ",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 69
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 6]
}
],
"zh-CN": [
@@ -959,8 +968,8 @@
"positive_pattern": "邮政编ç |邮编",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 69
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 6]
}
],
"zh-TW": [
@@ -969,8 +978,8 @@
"positive_pattern": "郵éžå€è™Ÿ",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 69
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 6]
}
],
"tr": [
@@ -979,8 +988,8 @@
"positive_pattern": "(\\b|_)posta kodu(\\b|_)",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 69
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 6]
}
],
"ko": [
@@ -989,8 +998,8 @@
"positive_pattern": "우편.?번호",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 69
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 6]
}
],
"id": [
@@ -999,8 +1008,8 @@
"positive_pattern": "kode.?pos",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 69
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 6]
}
]
},
@@ -1012,8 +1021,8 @@
"positive_score": 1.1,
"negative_pattern": "\\.zip",
"negative_patterns_explainer": ".zip refers to a file extension",
- "match_field_attributes": 3,
- "match_field_input_types": 69
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 6]
}
],
"pt": [
@@ -1022,8 +1031,8 @@
"positive_pattern": "codpos2",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 69
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 6]
}
]
},
@@ -1034,8 +1043,8 @@
"positive_pattern": "neighbo(u)?rhood",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 137
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 3, 7]
}
],
"pt": [
@@ -1044,8 +1053,8 @@
"positive_pattern": "bairro",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 137
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 3, 7]
}
],
"tr": [
@@ -1054,8 +1063,8 @@
"positive_pattern": "mahalle|köy",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 137
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 3, 7]
}
],
"id": [
@@ -1064,8 +1073,8 @@
"positive_pattern": "kecamatan",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 137
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 3, 7]
}
]
},
@@ -1076,8 +1085,8 @@
"positive_pattern": "city|town|suburb",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 137
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 3, 7]
}
],
"de": [
@@ -1086,8 +1095,8 @@
"positive_pattern": "\\bort\\b|stadt",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 137
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 3, 7]
}
],
"es": [
@@ -1096,8 +1105,8 @@
"positive_pattern": "ciudad|provincia|localidad|poblacion",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 137
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 3, 7]
}
],
"fr": [
@@ -1106,8 +1115,8 @@
"positive_pattern": "ville|commune",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 137
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 3, 7]
}
],
"it": [
@@ -1116,8 +1125,8 @@
"positive_pattern": "localita",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 137
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 3, 7]
}
],
"ja": [
@@ -1126,8 +1135,8 @@
"positive_pattern": "市区町æ‘",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 137
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 3, 7]
}
],
"pt": [
@@ -1136,8 +1145,8 @@
"positive_pattern": "cidade|município",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 137
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 3, 7]
}
],
"ru": [
@@ -1146,8 +1155,8 @@
"positive_pattern": "Город|ÐаÑел(е|Ñ‘)нный.?пункт",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 137
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 3, 7]
}
],
"zh-TW": [
@@ -1156,8 +1165,8 @@
"positive_pattern": "市|分å€",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 137
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 3, 7]
}
],
"fa": [
@@ -1166,8 +1175,8 @@
"positive_pattern": "شهر",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 137
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 3, 7]
}
],
"hi": [
@@ -1176,8 +1185,8 @@
"positive_pattern": "शहर|गà¥à¤°à¤¾à¤®|गाà¤à¤µ",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 137
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 3, 7]
}
],
"ml": [
@@ -1186,8 +1195,8 @@
"positive_pattern": "നഗരം|à´—àµà´°à´¾à´®à´‚",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 137
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 3, 7]
}
],
"tr": [
@@ -1196,8 +1205,8 @@
"positive_pattern": "((\\b|_|\\*)([İii̇]l[cç]e(miz|niz)?)(\\b|_|\\*))",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 137
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 3, 7]
}
],
"ko": [
@@ -1206,8 +1215,8 @@
"positive_pattern": "^ì‹œ[^ë„·・]|ì‹œ[·・]?êµ°[·・]?구",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 137
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 3, 7]
}
],
"id": [
@@ -1216,8 +1225,8 @@
"positive_pattern": "kota|kabupaten",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 137
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 3, 7]
}
]
},
@@ -1228,8 +1237,8 @@
"positive_pattern": "(?<!(united|hist|history).?)state|county|region|province|county|principality",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 137
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 3, 7]
}
],
"ja": [
@@ -1238,8 +1247,8 @@
"positive_pattern": "都é“府県",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 137
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 3, 7]
}
],
"pt": [
@@ -1248,8 +1257,8 @@
"positive_pattern": "estado|provincia",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 137
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 3, 7]
}
],
"ru": [
@@ -1258,8 +1267,8 @@
"positive_pattern": "облаÑÑ‚ÑŒ",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 137
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 3, 7]
}
],
"zh-TW": [
@@ -1268,8 +1277,8 @@
"positive_pattern": "çœ|地å€",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 137
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 3, 7]
}
],
"ml": [
@@ -1278,8 +1287,8 @@
"positive_pattern": "സംസàµà´¥à´¾à´¨à´‚",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 137
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 3, 7]
}
],
"fa": [
@@ -1288,8 +1297,8 @@
"positive_pattern": "استان",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 137
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 3, 7]
}
],
"hi": [
@@ -1298,8 +1307,8 @@
"positive_pattern": "राजà¥à¤¯",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 137
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 3, 7]
}
],
"tr": [
@@ -1308,8 +1317,8 @@
"positive_pattern": "((\\b|_|\\*)(eyalet|[şs]ehir|[İii̇]l(imiz)?|kent)(\\b|_|\\*))",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 137
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 3, 7]
}
],
"ko": [
@@ -1318,8 +1327,8 @@
"positive_pattern": "^ì‹œ[·・]?ë„",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 137
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 3, 7]
}
],
"id": [
@@ -1328,8 +1337,8 @@
"positive_pattern": "provinci",
"positive_score": 1.1,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 137
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 3, 7]
}
]
},
@@ -1340,8 +1349,8 @@
"positive_pattern": "^q$|search|query|qry",
"positive_score": 0.8,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 145
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 4, 7]
}
],
"de": [
@@ -1350,8 +1359,8 @@
"positive_pattern": "suche.*",
"positive_score": 0.8,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 145
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 4, 7]
}
],
"zh-CN": [
@@ -1360,8 +1369,8 @@
"positive_pattern": "æœç´¢",
"positive_score": 0.8,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 145
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 4, 7]
}
],
"ja": [
@@ -1370,8 +1379,8 @@
"positive_pattern": "探ã™|検索",
"positive_score": 0.8,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 145
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 4, 7]
}
],
"fr": [
@@ -1380,8 +1389,8 @@
"positive_pattern": "recherch.*",
"positive_score": 0.8,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 145
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 4, 7]
}
],
"pt": [
@@ -1390,8 +1399,8 @@
"positive_pattern": "busca",
"positive_score": 0.8,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 145
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 4, 7]
}
],
"fa": [
@@ -1400,8 +1409,8 @@
"positive_pattern": "جستجو",
"positive_score": 0.8,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 145
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 4, 7]
}
],
"ru": [
@@ -1410,8 +1419,8 @@
"positive_pattern": "иÑкать|найти|поиÑк",
"positive_score": 0.8,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 145
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 4, 7]
}
]
},
@@ -1422,8 +1431,8 @@
"positive_pattern": "\\bprice\\b|\\brate\\b|\\bcost\\b",
"positive_score": 0.95,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 217
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 3, 4, 6, 7]
}
],
"ar": [
@@ -1432,8 +1441,8 @@
"positive_pattern": "قیمة‎|سعر‎",
"positive_score": 0.95,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 217
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 3, 4, 6, 7]
}
],
"fa": [
@@ -1442,8 +1451,8 @@
"positive_pattern": "قیمت",
"positive_score": 0.95,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 217
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 3, 4, 6, 7]
}
],
"fr": [
@@ -1452,8 +1461,8 @@
"positive_pattern": "\\bprix\\b|\\bcoût\\b|\\bcout\\b|\\btarif\\b",
"positive_score": 0.95,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 217
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 3, 4, 6, 7]
}
]
},
@@ -1464,8 +1473,8 @@
"positive_pattern": "card.?(?:holder|owner)|name.*(\\b)?on(\\b)?.*card|(?:card|cc).?name|cc.?full.?name",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"de": [
@@ -1474,8 +1483,8 @@
"positive_pattern": "karteninhaber",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"es": [
@@ -1484,8 +1493,8 @@
"positive_pattern": "nombre.*tarjeta",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"fr": [
@@ -1494,8 +1503,8 @@
"positive_pattern": "nom.*carte",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"it": [
@@ -1504,8 +1513,8 @@
"positive_pattern": "nome.*cart",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"ja": [
@@ -1514,8 +1523,8 @@
"positive_pattern": "åå‰",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"ru": [
@@ -1524,8 +1533,8 @@
"positive_pattern": "ИмÑ.*карты",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"zh-CN": [
@@ -1534,8 +1543,8 @@
"positive_pattern": "信用å¡å¼€æˆ·å|开户å|æŒå¡äººå§“å|æŒå¡äººå§“å",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"id": [
@@ -1544,8 +1553,8 @@
"positive_pattern": "nama.*kartu",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
]
},
@@ -1556,8 +1565,8 @@
"positive_pattern": "name",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
]
},
@@ -1568,8 +1577,8 @@
"positive_pattern": "(add)?(?:card|cc|acct).?(?:number|#|no|num|field|pan)",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 101
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 5, 6]
}
],
"de": [
@@ -1578,8 +1587,8 @@
"positive_pattern": "(?<!telefon|haus|person|fødsels|kunden)nummer",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 101
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 5, 6]
}
],
"ja": [
@@ -1588,8 +1597,8 @@
"positive_pattern": "カード番å·",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 101
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 5, 6]
}
],
"ru": [
@@ -1598,8 +1607,8 @@
"positive_pattern": "Ðомер.*карты",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 101
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 5, 6]
}
],
"zh-CN": [
@@ -1608,8 +1617,8 @@
"positive_pattern": "信用å¡å·|信用å¡å·ç ",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 101
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 5, 6]
}
],
"zh-TW": [
@@ -1618,8 +1627,8 @@
"positive_pattern": "信用å¡å¡è™Ÿ",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 101
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 5, 6]
}
],
"ko": [
@@ -1628,8 +1637,8 @@
"positive_pattern": "카드",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 101
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 5, 6]
}
],
"es": [
@@ -1638,8 +1647,8 @@
"positive_pattern": "(numero|número|numéro)(?!.*(document|fono|phone|réservation))",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 101
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 5, 6]
}
],
"pt": [
@@ -1648,8 +1657,8 @@
"positive_pattern": "(numero|número|numéro)(?!.*(document|fono|phone|réservation))",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 101
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 5, 6]
}
],
"fr": [
@@ -1658,8 +1667,8 @@
"positive_pattern": "(numero|número|numéro)(?!.*(document|fono|phone|réservation))",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 101
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 5, 6]
}
],
"id": [
@@ -1668,8 +1677,8 @@
"positive_pattern": "no.*kartu",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 101
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 5, 6]
}
]
},
@@ -1680,8 +1689,8 @@
"positive_pattern": "verification|card.?identification|security.?code|card.?code|security.?value|security.?number|card.?pin|c-v-v|(cvn|cvv|cvc|csc|cvd|cid|ccv)(field)?|\\bcid\\b",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 101
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 5, 6]
}
]
},
@@ -1692,8 +1701,8 @@
"positive_pattern": "expir|exp.*mo|exp.*date|ccmonth|cardmonth|addmonth",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 205
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 3, 6, 7]
}
],
"de": [
@@ -1702,8 +1711,8 @@
"positive_pattern": "gueltig|gültig|monat",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 205
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 3, 6, 7]
}
],
"es": [
@@ -1712,8 +1721,8 @@
"positive_pattern": "fecha",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 205
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 3, 6, 7]
}
],
"fr": [
@@ -1722,8 +1731,8 @@
"positive_pattern": "date.*exp",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 205
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 3, 6, 7]
}
],
"it": [
@@ -1732,8 +1741,8 @@
"positive_pattern": "scadenza",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 205
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 3, 6, 7]
}
],
"ja": [
@@ -1742,8 +1751,8 @@
"positive_pattern": "有効期é™",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 205
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 3, 6, 7]
}
],
"pt": [
@@ -1752,8 +1761,8 @@
"positive_pattern": "validade",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 205
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 3, 6, 7]
}
],
"ru": [
@@ -1762,8 +1771,8 @@
"positive_pattern": "Срок дейÑÑ‚Ð²Ð¸Ñ ÐºÐ°Ñ€Ñ‚Ñ‹",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 205
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 3, 6, 7]
}
],
"zh-CN": [
@@ -1772,8 +1781,8 @@
"positive_pattern": "月",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 205
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 3, 6, 7]
}
],
"id": [
@@ -1782,8 +1791,8 @@
"positive_pattern": "masa berlaku|berlaku hingga",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 205
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 3, 6, 7]
}
]
},
@@ -1794,8 +1803,8 @@
"positive_pattern": "exp|^/|(add)?year",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 205
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 3, 6, 7]
}
],
"de": [
@@ -1804,8 +1813,8 @@
"positive_pattern": "ablaufdatum|gueltig|gültig|jahr",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 205
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 3, 6, 7]
}
],
"es": [
@@ -1814,8 +1823,8 @@
"positive_pattern": "fecha",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 205
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 3, 6, 7]
}
],
"it": [
@@ -1824,8 +1833,8 @@
"positive_pattern": "scadenza",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 205
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 3, 6, 7]
}
],
"ja": [
@@ -1834,8 +1843,8 @@
"positive_pattern": "有効期é™",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 205
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 3, 6, 7]
}
],
"pt": [
@@ -1844,8 +1853,8 @@
"positive_pattern": "validade",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 205
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 3, 6, 7]
}
],
"ru": [
@@ -1854,8 +1863,8 @@
"positive_pattern": "Срок дейÑÑ‚Ð²Ð¸Ñ ÐºÐ°Ñ€Ñ‚Ñ‹",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 205
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 3, 6, 7]
}
],
"zh-CN": [
@@ -1864,8 +1873,18 @@
"positive_pattern": "年|有效期",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 205
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 3, 6, 7]
+ }
+ ],
+ "id": [
+ {
+ "pattern_identifier": "id_card_exp_date_preserving",
+ "positive_pattern": "masa berlaku|berlaku hingga",
+ "positive_score": 1.0,
+ "negative_pattern": null,
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 3, 6, 7]
}
]
},
@@ -1876,8 +1895,8 @@
"positive_pattern": "(?:exp.*date[^y\\n\\r]*|mm\\s*[-/]?\\s*)yy(?:[^y]|$)",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 205
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 3, 6, 7]
}
]
},
@@ -1888,8 +1907,8 @@
"positive_pattern": "(?:exp.*date[^y\\n\\r]*|mm\\s*[-/]?\\s*)yyyy(?:[^y]|$)",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 205
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 3, 6, 7]
}
]
},
@@ -1900,8 +1919,8 @@
"positive_pattern": "expir|exp.*date|^expfield$",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 205
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 3, 6, 7]
}
],
"de": [
@@ -1910,8 +1929,8 @@
"positive_pattern": "gueltig|gültig",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 205
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 3, 6, 7]
}
],
"es": [
@@ -1920,8 +1939,8 @@
"positive_pattern": "fecha",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 205
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 3, 6, 7]
}
],
"fr": [
@@ -1930,8 +1949,8 @@
"positive_pattern": "date.*exp",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 205
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 3, 6, 7]
}
],
"it": [
@@ -1940,8 +1959,8 @@
"positive_pattern": "scadenza",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 205
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 3, 6, 7]
}
],
"ja": [
@@ -1950,8 +1969,8 @@
"positive_pattern": "有効期é™",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 205
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 3, 6, 7]
}
],
"pt": [
@@ -1960,8 +1979,8 @@
"positive_pattern": "validade",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 205
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 3, 6, 7]
}
],
"ru": [
@@ -1970,18 +1989,8 @@
"positive_pattern": "Срок дейÑÑ‚Ð²Ð¸Ñ ÐºÐ°Ñ€Ñ‚Ñ‹",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 205
- }
- ],
- "id": [
- {
- "pattern_identifier": "id_card_exp_date_preserving",
- "positive_pattern": "masa berlaku|berlaku hingga",
- "positive_score": 1.0,
- "negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 205
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 3, 6, 7]
}
]
},
@@ -1992,8 +2001,8 @@
"positive_pattern": "^mm$",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 205
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 3, 6, 7]
}
]
},
@@ -2004,8 +2013,8 @@
"positive_pattern": "^(yy|yyyy)$",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 205
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 3, 6, 7]
}
]
},
@@ -2016,8 +2025,8 @@
"positive_pattern": "gift.?(card|cert)",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 197
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 6, 7]
}
]
},
@@ -2028,8 +2037,8 @@
"positive_pattern": "(?:visa|mastercard|discover|amex|american express).*gift.?card",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 197
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 6, 7]
}
]
},
@@ -2040,8 +2049,8 @@
"positive_pattern": "debit.*card",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 197
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 6, 7]
}
]
},
@@ -2052,8 +2061,8 @@
"positive_pattern": "day",
"positive_score": 1.0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 9
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 3]
}
]
},
@@ -2064,8 +2073,8 @@
"positive_pattern": "e.?mail",
"positive_score": 1.4,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 3
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 1]
}
],
"fr": [
@@ -2074,8 +2083,8 @@
"positive_pattern": "courriel",
"positive_score": 1.4,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 3
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 1]
}
],
"es": [
@@ -2084,8 +2093,8 @@
"positive_pattern": "correo.*electr(o|ó)nico",
"positive_score": 1.4,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 3
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 1]
}
],
"ja": [
@@ -2094,8 +2103,8 @@
"positive_pattern": "メールアドレス",
"positive_score": 1.4,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 3
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 1]
}
],
"ru": [
@@ -2104,8 +2113,8 @@
"positive_pattern": "Электронн(аÑ|ой).?Почт(а|Ñ‹)",
"positive_score": 1.4,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 3
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 1]
}
],
"zh-CN": [
@@ -2114,8 +2123,8 @@
"positive_pattern": "邮件|邮箱|é›»å­éƒµä»¶",
"positive_score": 1.4,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 3
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 1]
}
],
"zh-TW": [
@@ -2124,8 +2133,8 @@
"positive_pattern": "電郵地å€|é›»å­ä¿¡ç®±",
"positive_score": 1.4,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 3
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 1]
}
],
"ml": [
@@ -2134,8 +2143,8 @@
"positive_pattern": "à´‡-മെയിലàµâ€|ഇലകàµà´Ÿàµà´°àµ‹à´£à´¿à´•àµ.?മെയിൽ",
"positive_score": 1.4,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 3
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 1]
}
],
"fa": [
@@ -2144,8 +2153,8 @@
"positive_pattern": "ایمیل|پست.*الکترونیک",
"positive_score": 1.4,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 3
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 1]
}
],
"hi": [
@@ -2154,8 +2163,8 @@
"positive_pattern": "ईमेल|इलॅकà¥à¤Ÿà¥à¤°à¥‰à¤¨à¤¿à¤•.?मेल",
"positive_score": 1.4,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 3
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 1]
}
],
"tr": [
@@ -2164,8 +2173,8 @@
"positive_pattern": "(\\b|_)eposta(\\b|_)",
"positive_score": 1.4,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 3
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 1]
}
],
"ko": [
@@ -2174,8 +2183,8 @@
"positive_pattern": "(?:ì´ë©”ì¼|ì „ìž.?우편|[Ee]-?mail)(.?주소)?",
"positive_score": 1.4,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 3
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 1]
}
]
},
@@ -2186,8 +2195,8 @@
"positive_pattern": "user.?name|user.?id|nickname|maiden name|title|prefix|suffix|mail",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 137
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 3, 7]
}
],
"de": [
@@ -2196,8 +2205,8 @@
"positive_pattern": "vollständiger.?name",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 137
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 3, 7]
}
],
"zh-CN": [
@@ -2206,8 +2215,8 @@
"positive_pattern": "用户å",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 137
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 3, 7]
}
],
"ko": [
@@ -2216,8 +2225,8 @@
"positive_pattern": "(?:사용ìž.?)?ì•„ì´ë””|사용ìž.?ID",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 137
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 3, 7]
}
]
},
@@ -2228,8 +2237,8 @@
"positive_pattern": "^name|full.?name|your.?name|customer.?name|bill.?name|ship.?name|name.*first.*last|firstandlastname|contact.?(name|person)",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"es": [
@@ -2238,8 +2247,8 @@
"positive_pattern": "nombre.*y.*apellidos",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"fr": [
@@ -2248,8 +2257,8 @@
"positive_pattern": "^nom(?![a-zA-Z])",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"ja": [
@@ -2258,8 +2267,8 @@
"positive_pattern": "ãŠåå‰|æ°å",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"pt": [
@@ -2268,8 +2277,8 @@
"positive_pattern": "^nome",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"fa": [
@@ -2278,8 +2287,8 @@
"positive_pattern": "نام.*نام.*خانوادگی",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"zh-CN": [
@@ -2288,8 +2297,8 @@
"positive_pattern": "姓\\s*å",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"ru": [
@@ -2298,8 +2307,8 @@
"positive_pattern": "контактное.?лицо",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"tr": [
@@ -2308,8 +2317,8 @@
"positive_pattern": "(\\b|_|\\*)ad[ı]? soyad[ı]?(\\b|_|\\*)",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"ko": [
@@ -2318,8 +2327,8 @@
"positive_pattern": "성명",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"id": [
@@ -2328,8 +2337,8 @@
"positive_pattern": "nama.?(lengkap|penerima|kamu)",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
]
},
@@ -2340,8 +2349,8 @@
"positive_pattern": "^name",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"fr": [
@@ -2350,8 +2359,8 @@
"positive_pattern": "^nom",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"pt": [
@@ -2360,8 +2369,8 @@
"positive_pattern": "^nome",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
]
},
@@ -2372,8 +2381,8 @@
"positive_pattern": "first.*name|initials|fname|first$|given.*name",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"de": [
@@ -2382,8 +2391,8 @@
"positive_pattern": "vorname",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"es": [
@@ -2392,8 +2401,8 @@
"positive_pattern": "nombre",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"fr": [
@@ -2402,8 +2411,8 @@
"positive_pattern": "forename|prénom|prenom",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"ja": [
@@ -2412,8 +2421,8 @@
"positive_pattern": "å",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"pt": [
@@ -2422,8 +2431,8 @@
"positive_pattern": "nome",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"ru": [
@@ -2432,8 +2441,8 @@
"positive_pattern": "ИмÑ",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"fa": [
@@ -2442,8 +2451,8 @@
"positive_pattern": "نام",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"ko": [
@@ -2452,8 +2461,8 @@
"positive_pattern": "ì´ë¦„",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"ml": [
@@ -2462,8 +2471,8 @@
"positive_pattern": "പേരàµ",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"tr": [
@@ -2472,8 +2481,8 @@
"positive_pattern": "(\\b|_|\\*)(isim|ad|ad(i|ı|iniz|ınız)?)(\\b|_|\\*)",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"hi": [
@@ -2482,8 +2491,8 @@
"positive_pattern": "नाम",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"id": [
@@ -2492,8 +2501,8 @@
"positive_pattern": "nama depan",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
]
},
@@ -2504,8 +2513,8 @@
"positive_pattern": "middle.*initial|m\\.i\\.|mi$|\\bmi\\b",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
]
},
@@ -2516,8 +2525,8 @@
"positive_pattern": "middle.*name|mname|middle$",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
]
},
@@ -2528,8 +2537,8 @@
"positive_pattern": "last.*name|lname|surname(?!\\d)|last$|secondname|family.*name",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"de": [
@@ -2538,8 +2547,8 @@
"positive_pattern": "nachname",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"es": [
@@ -2548,8 +2557,8 @@
"positive_pattern": "apellidos?",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"fr": [
@@ -2558,8 +2567,8 @@
"positive_pattern": "famille|^nom(?![a-zA-Z])",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"it": [
@@ -2568,8 +2577,8 @@
"positive_pattern": "cognome",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"ja": [
@@ -2578,8 +2587,8 @@
"positive_pattern": "姓",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"pt": [
@@ -2588,8 +2597,8 @@
"positive_pattern": "apelidos|surename|sobrenome",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"ru": [
@@ -2598,8 +2607,8 @@
"positive_pattern": "ФамилиÑ",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"fa": [
@@ -2608,8 +2617,8 @@
"positive_pattern": "نام.*خانوادگی",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"hi": [
@@ -2618,8 +2627,8 @@
"positive_pattern": "उपनाम",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"ml": [
@@ -2628,8 +2637,8 @@
"positive_pattern": "മറàµà´ªàµ‡à´°àµ",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"tr": [
@@ -2638,8 +2647,8 @@
"positive_pattern": "(\\b|_|\\*)(soyisim|soyad(i|ı|iniz|ınız)?)(\\b|_|\\*)",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"ko": [
@@ -2648,8 +2657,8 @@
"positive_pattern": "\\b성(?:[^명]|\\b)",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"id": [
@@ -2658,8 +2667,8 @@
"positive_pattern": "nama belakang",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
]
},
@@ -2670,8 +2679,8 @@
"positive_pattern": "(primer.*apellido)|(apellido1)|(apellido.*paterno)|surname_?1|first(\\s|_)?surname",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
]
},
@@ -2682,8 +2691,8 @@
"positive_pattern": "(segund.*apellido)|(apellido2)|(apellido.*materno)|surname_?2|second(\\s|_)?surname",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
]
},
@@ -2694,8 +2703,8 @@
"positive_pattern": "^title:?$|(salutation(?! and given name))",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"de": [
@@ -2704,8 +2713,8 @@
"positive_pattern": "anrede|titel",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"es": [
@@ -2714,8 +2723,8 @@
"positive_pattern": "tratamiento|encabezamiento",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"it": [
@@ -2724,8 +2733,8 @@
"positive_pattern": "titolo",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"fr": [
@@ -2734,8 +2743,8 @@
"positive_pattern": "titre",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"ru": [
@@ -2744,8 +2753,8 @@
"positive_pattern": "обращение|звание",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"el": [
@@ -2754,8 +2763,8 @@
"positive_pattern": "Ï€Ïοσφώνηση",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"tr": [
@@ -2764,8 +2773,8 @@
"positive_pattern": "hitap",
"positive_score": 0.9,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
]
},
@@ -2776,8 +2785,8 @@
"positive_pattern": "phone|mobile|contact.?number",
"positive_score": 1.2,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 69
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 6]
}
],
"de": [
@@ -2786,8 +2795,8 @@
"positive_pattern": "telefonnummer",
"positive_score": 1.2,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 69
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 6]
}
],
"es": [
@@ -2796,8 +2805,8 @@
"positive_pattern": "telefono|teléfono",
"positive_score": 1.2,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 69
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 6]
}
],
"fr": [
@@ -2806,8 +2815,8 @@
"positive_pattern": "telfixe",
"positive_score": 1.2,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 69
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 6]
}
],
"ja": [
@@ -2816,8 +2825,8 @@
"positive_pattern": "電話",
"positive_score": 1.2,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 69
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 6]
}
],
"pt": [
@@ -2826,8 +2835,8 @@
"positive_pattern": "telefone|telemovel",
"positive_score": 1.2,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 69
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 6]
}
],
"ru": [
@@ -2836,8 +2845,8 @@
"positive_pattern": "телефон",
"positive_score": 1.2,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 69
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 6]
}
],
"hi": [
@@ -2846,8 +2855,8 @@
"positive_pattern": "मोबाइल",
"positive_score": 1.2,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 69
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 6]
}
],
"tr": [
@@ -2856,8 +2865,8 @@
"positive_pattern": "(\\b|_|\\*)telefon(\\b|_|\\*)",
"positive_score": 1.2,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 69
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 6]
}
],
"zh-CN": [
@@ -2866,8 +2875,8 @@
"positive_pattern": "电è¯",
"positive_score": 1.2,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 69
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 6]
}
],
"ml": [
@@ -2876,8 +2885,8 @@
"positive_pattern": "മൊബൈലàµâ€",
"positive_score": 1.2,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 69
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 6]
}
],
"ko": [
@@ -2886,8 +2895,8 @@
"positive_pattern": "(?:ì „í™”|핸드í°|휴대í°|휴대전화)(?:.?번호)?",
"positive_score": 1.2,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 69
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 6]
}
],
"id": [
@@ -2896,8 +2905,8 @@
"positive_pattern": "telepon|ponsel|(nomor|no\\.?).?(hp|handphone)",
"positive_score": 1.2,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 69
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 6]
}
]
},
@@ -2908,8 +2917,8 @@
"positive_pattern": "^[^0-9+]*(?:\\+|00)\\s*([1-9]\\d{0,3})\\D*$",
"positive_score": 1.3,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
]
},
@@ -2920,8 +2929,8 @@
"positive_pattern": "country.*code|ccode|_cc|phone.*code|user.*phone.*code",
"positive_score": 1.3,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 77
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 3, 6]
}
]
},
@@ -2932,8 +2941,8 @@
"positive_pattern": "^\\($",
"positive_score": 1.3,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 69
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 6]
}
]
},
@@ -2944,8 +2953,8 @@
"positive_pattern": "area.*code|acode|area",
"positive_score": 1.3,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 69
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 6]
}
],
"ko": [
@@ -2954,8 +2963,8 @@
"positive_pattern": "지역.?번호",
"positive_score": 1.3,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 69
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 6]
}
]
},
@@ -2966,8 +2975,8 @@
"positive_pattern": "^-$|^\\)$",
"positive_score": 1.3,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 69
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 6]
}
]
},
@@ -2978,8 +2987,8 @@
"positive_pattern": "^-$",
"positive_score": 1.3,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 69
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 6]
}
]
},
@@ -2990,8 +2999,8 @@
"positive_pattern": "prefix|exchange",
"positive_score": 1.3,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 69
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 6]
}
],
"fr": [
@@ -3000,8 +3009,8 @@
"positive_pattern": "preselection",
"positive_score": 1.3,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 69
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 6]
}
],
"pt": [
@@ -3010,8 +3019,8 @@
"positive_pattern": "ddd",
"positive_score": 1.3,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 69
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 6]
}
]
},
@@ -3022,8 +3031,8 @@
"positive_pattern": "suffix",
"positive_score": 1.3,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 69
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 6]
}
]
},
@@ -3034,8 +3043,8 @@
"positive_pattern": "\\bext|ext\\b|extension",
"positive_score": 1.3,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 69
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 6]
}
],
"pt": [
@@ -3044,8 +3053,8 @@
"positive_pattern": "ramal",
"positive_score": 1.3,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 69
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0, 2, 6]
}
]
},
@@ -3056,8 +3065,8 @@
"positive_pattern": "document.*number|passport",
"positive_score": 1.2,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"fr": [
@@ -3066,8 +3075,8 @@
"positive_pattern": "passeport",
"positive_score": 1.2,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"es": [
@@ -3076,8 +3085,8 @@
"positive_pattern": "numero.*documento|pasaporte",
"positive_score": 1.2,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"ja": [
@@ -3086,8 +3095,8 @@
"positive_pattern": "書類",
"positive_score": 1.2,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
]
},
@@ -3098,8 +3107,8 @@
"positive_pattern": "point.*of.*entry|arrival",
"positive_score": 1.2,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"es": [
@@ -3108,8 +3117,8 @@
"positive_pattern": "punto.*internaci(o|ó)n|fecha.*llegada",
"positive_score": 1.2,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"ja": [
@@ -3118,8 +3127,8 @@
"positive_pattern": "入国",
"positive_score": 1.2,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
]
},
@@ -3130,8 +3139,8 @@
"positive_pattern": "departure",
"positive_score": 1.2,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"es": [
@@ -3140,8 +3149,8 @@
"positive_pattern": "fecha.*salida|destino",
"positive_score": 1.2,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"ja": [
@@ -3150,8 +3159,8 @@
"positive_pattern": "出国",
"positive_score": 1.2,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
]
},
@@ -3162,8 +3171,8 @@
"positive_pattern": "airline|flight",
"positive_score": 1.2,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"es": [
@@ -3172,8 +3181,8 @@
"positive_pattern": "aerol(i|í)nea|n(u|ú)mero.*vuelo",
"positive_score": 1.2,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
],
"ja": [
@@ -3182,8 +3191,8 @@
"positive_pattern": "便å|航空会社",
"positive_score": 1.2,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
]
},
@@ -3194,16 +3203,16 @@
"positive_pattern": "^[\\w.+-_]+@(\\w+\\.ifsc\\.npci|aadhaar\\.npci|mobile\\.npci|rupay\\.npci)$",
"positive_score": 0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
},
{
"pattern_identifier": "en_upi_virtual_payment_address_user@(bank_list)_preserving",
"positive_pattern": "^[\\w.+-_]+@(airtel|airtelpaymentsbank|albk|allahabadbank|allbank|andb|apb|apl|axis|axisbank|axisgo|bandhan|barodampay|birla|boi|cbin|cboi|centralbank|cmsidfc|cnrb|csbcash|csbpay|cub|dbs|dcb|dcbbank|denabank|dlb|eazypay|equitas|ezeepay|fbl|federal|finobank|hdfcbank|hsbc|icici|idbi|idbibank|idfc|idfcbank|idfcnetc|ikwik|imobile|indbank|indianbank|indianbk|indus|iob|jkb|jsb|jsbp|karb|karurvysyabank|kaypay|kbl|kbl052|kmb|kmbl|kotak|kvb|kvbank|lime|lvb|lvbank|mahb|obc|okaxis|okbizaxis|okhdfcbank|okicici|oksbi|paytm|payzapp|pingpay|pnb|pockets|psb|purz|rajgovhdfcbank|rbl|sbi|sc|scb|scbl|scmobile|sib|srcb|synd|syndbank|syndicate|tjsb|tjsp|ubi|uboi|uco|unionbank|unionbankofindia|united|upi|utbi|vijayabank|vijb|vjb|ybl|yesbank|yesbankltd)$",
"positive_score": 0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
]
},
@@ -3214,8 +3223,8 @@
"positive_pattern": "^[a-zA-Z]{2}[0-9]{2}[a-zA-Z0-9]{4}[0-9]{7}([a-zA-Z0-9]?){0,16}$",
"positive_score": 0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
]
},
@@ -3226,8 +3235,8 @@
"positive_pattern": "^\\d{3,4}$",
"positive_score": 0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
]
},
@@ -3238,8 +3247,8 @@
"positive_pattern": "^[2][0][1-9][0-9]$",
"positive_score": 0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
]
},
@@ -3250,8 +3259,8 @@
"positive_pattern": "/search(/|((\\w*\\.\\w+)?$))",
"positive_score": 0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
]
},
@@ -3262,8 +3271,8 @@
"positive_pattern": "ssn|social.?security.?(num(ber)?|#)*",
"positive_score": 0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
]
},
@@ -3274,8 +3283,8 @@
"positive_pattern": "one.?time|sms.?(code|token|password|pwd|pass)",
"positive_score": 0,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
]
},
@@ -3283,11 +3292,11 @@
"en": [
{
"pattern_identifier": "en_merchant_promo_code_preserving",
- "positive_pattern": "\\bpromo.*code\\b|\\bcoupon code\\b|\\bgift code\\b",
+ "positive_pattern": "(promo(tion|tional)?|gift|discount|coupon)[-_. ]*code",
"positive_score": 0.85,
"negative_pattern": null,
- "match_field_attributes": 3,
- "match_field_input_types": 1
+ "match_field_attributes": [0, 1],
+ "match_field_input_types": [0]
}
]
}
diff --git a/chromium/components/autofill/core/browser/pattern_provider/transpile_default_regex_patterns.py b/chromium/components/autofill/core/browser/pattern_provider/transpile_default_regex_patterns.py
index 37f3950cca5..cc0e3e84ff7 100755
--- a/chromium/components/autofill/core/browser/pattern_provider/transpile_default_regex_patterns.py
+++ b/chromium/components/autofill/core/browser/pattern_provider/transpile_default_regex_patterns.py
@@ -16,7 +16,7 @@ def build_cpp_map_population(input):
def output(line):
lines.append(line)
- output('JsonPattern patterns[] = {')
+ output('constexpr JsonPattern patterns[] = {')
for key1 in input:
for key2 in input[key1]:
for pattern in input[key1][key2]:
@@ -35,9 +35,17 @@ def build_cpp_map_population(input):
else:
negative_pattern = 'u' + to_string_literal(negative_pattern)
- # Shift to the right to match the MatchFieldTypes enum, which
- # temporarily starts at 1<<2 instead of 1<<0.
- match_field_input_types = '{} << 2'.format(match_field_input_types)
+ match_field_attributes = map(
+ lambda i: 'To<MatchAttribute, {}>()'.format(i),
+ match_field_attributes)
+ match_field_input_types = map(
+ lambda i: 'To<MatchFieldType, {}>()'.format(i),
+ match_field_input_types)
+
+ match_field_attributes = '{{ {} }}'.format(
+ ','.join(match_field_attributes))
+ match_field_input_types = '{{ {} }}'.format(
+ ','.join(match_field_input_types))
output('{')
output('.name = {},'.format(name))
@@ -72,6 +80,17 @@ def build_cpp_function(cpp, output_handle):
output('\n')
output('namespace autofill {\n')
output('\n')
+ output('namespace {\n')
+ output('\n')
+ output('template<typename Enum, int i>\n')
+ output('constexpr Enum To() {\n')
+ output(' static_assert(0 <= i);\n')
+ output(' static_assert(static_cast<Enum>(i) <= Enum::kMaxValue);\n')
+ output(' return static_cast<Enum>(i);\n')
+ output('}\n')
+ output('\n')
+ output('} // namespace\n')
+ output('\n')
output('PatternProvider::Map CreateDefaultRegexPatterns() {\n')
output(' struct JsonPattern {\n')
output(' const char* name;\n')
@@ -79,8 +98,8 @@ def build_cpp_function(cpp, output_handle):
output(' const char16_t* positive_pattern;\n')
output(' const char16_t* negative_pattern;\n')
output(' float positive_score;\n')
- output(' uint8_t match_field_attributes;\n')
- output(' uint16_t match_field_input_types;\n')
+ output(' DenseSet<MatchAttribute> match_field_attributes;\n')
+ output(' DenseSet<MatchFieldType> match_field_input_types;\n')
output(' };\n')
output('\n')
for line in build_cpp_map_population(cpp):
diff --git a/chromium/components/autofill/core/browser/payments/OWNERS b/chromium/components/autofill/core/browser/payments/OWNERS
index 8b40deb104f..3d29c995654 100644
--- a/chromium/components/autofill/core/browser/payments/OWNERS
+++ b/chromium/components/autofill/core/browser/payments/OWNERS
@@ -1,2 +1,5 @@
jsaul@google.com
siyua@chromium.org
+
+per-file autofill_wallet_model_type_controller*=jkrcal@chromium.org
+per-file autofill_wallet_model_type_controller*=file://components/sync/OWNERS
diff --git a/chromium/components/autofill/core/browser/payments/autofill_credit_card_filling_infobar_delegate_mobile.cc b/chromium/components/autofill/core/browser/payments/autofill_credit_card_filling_infobar_delegate_mobile.cc
index 7452164d5e9..75cceaf95c3 100644
--- a/chromium/components/autofill/core/browser/payments/autofill_credit_card_filling_infobar_delegate_mobile.cc
+++ b/chromium/components/autofill/core/browser/payments/autofill_credit_card_filling_infobar_delegate_mobile.cc
@@ -24,10 +24,10 @@ AutofillCreditCardFillingInfoBarDelegateMobile::
had_user_interaction_(false),
was_shown_(false),
issuer_icon_id_(CreditCard::IconResourceId(card.network())),
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
card_label_(card.NetworkAndLastFourDigits()),
#else
- card_label_(std::u16string(kMidlineEllipsis4Dots) +
+ card_label_(CreditCard::GetMidlineEllipsisDots(4) +
card.LastFourDigits()),
#endif
card_sub_label_(card.AbbreviatedExpirationDateForDisplay(false)) {
@@ -49,10 +49,10 @@ int AutofillCreditCardFillingInfoBarDelegateMobile::GetIconId() const {
std::u16string AutofillCreditCardFillingInfoBarDelegateMobile::GetMessageText()
const {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
return l10n_util::GetStringUTF16(
IDS_AUTOFILL_CREDIT_CARD_FILLING_INFOBAR_TITLE);
-#elif defined(OS_IOS)
+#elif BUILDFLAG(IS_IOS)
// On iOS the card details are in the title of the infobar.
return l10n_util::GetStringFUTF16(
IDS_AUTOFILL_CREDIT_CARD_FILLING_INFOBAR_FORMATTED_TITLE, card_label_);
diff --git a/chromium/components/autofill/core/browser/payments/autofill_offer_manager.cc b/chromium/components/autofill/core/browser/payments/autofill_offer_manager.cc
index ae68d83d00d..ccafc384568 100644
--- a/chromium/components/autofill/core/browser/payments/autofill_offer_manager.cc
+++ b/chromium/components/autofill/core/browser/payments/autofill_offer_manager.cc
@@ -4,23 +4,17 @@
#include "components/autofill/core/browser/payments/autofill_offer_manager.h"
-#include <map>
-
#include "base/bind.h"
#include "base/containers/contains.h"
-#include "base/ranges/algorithm.h"
#include "base/ranges/ranges.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/time/time.h"
-#include "base/timer/timer.h"
#include "components/autofill/core/browser/autofill_client.h"
#include "components/autofill/core/browser/data_model/autofill_offer_data.h"
#include "components/autofill/core/browser/data_model/credit_card.h"
#include "components/autofill/core/browser/payments/payments_client.h"
+#include "components/autofill/core/browser/personal_data_manager.h"
#include "components/autofill/core/common/autofill_payments_features.h"
#include "components/strings/grit/components_strings.h"
#include "ui/base/l10n/l10n_util.h"
-#include "url/gurl.h"
namespace autofill {
@@ -41,6 +35,10 @@ void AutofillOfferManager::OnPersonalDataChanged() {
UpdateEligibleMerchantDomains();
}
+void AutofillOfferManager::OnDidNavigateFrame(AutofillClient* client) {
+ notification_handler_.UpdateOfferNotificationVisibility(client);
+}
+
void AutofillOfferManager::UpdateSuggestionsWithOffers(
const GURL& last_committed_url,
std::vector<Suggestion>& suggestions) {
diff --git a/chromium/components/autofill/core/browser/payments/autofill_offer_manager.h b/chromium/components/autofill/core/browser/payments/autofill_offer_manager.h
index 16b36096e1e..30041b62a03 100644
--- a/chromium/components/autofill/core/browser/payments/autofill_offer_manager.h
+++ b/chromium/components/autofill/core/browser/payments/autofill_offer_manager.h
@@ -8,22 +8,25 @@
#include <stdint.h>
#include <map>
+#include <set>
#include <string>
-#include <tuple>
#include <vector>
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
-#include "base/timer/timer.h"
-#include "components/autofill/core/browser/autofill_client.h"
-#include "components/autofill/core/browser/data_model/autofill_offer_data.h"
-#include "components/autofill/core/browser/personal_data_manager.h"
+#include "components/autofill/core/browser/payments/offer_notification_handler.h"
#include "components/autofill/core/browser/personal_data_manager_observer.h"
#include "components/keyed_service/core/keyed_service.h"
#include "url/gurl.h"
namespace autofill {
+class AutofillClient;
+struct AutofillOfferData;
+class OfferNotificationHandler;
+class PersonalDataManager;
+struct Suggestion;
+
// A delegate class to expose relevant CouponService functionalities.
class CouponServiceDelegate {
public:
@@ -39,8 +42,8 @@ class CouponServiceDelegate {
virtual ~CouponServiceDelegate() = default;
};
-// Manages all Autofill related offers. One per frame; owned by the
-// BrowserAutofillManager.
+// Manages all Autofill related offers. One per browser context. Owned and
+// created by the AutofillOfferManagerFactory.
class AutofillOfferManager : public KeyedService,
public PersonalDataManagerObserver {
public:
@@ -56,6 +59,9 @@ class AutofillOfferManager : public KeyedService,
// PersonalDataManagerObserver:
void OnPersonalDataChanged() override;
+ // Invoked when the navigation happens.
+ void OnDidNavigateFrame(AutofillClient* client);
+
// Modifies any suggestion in |suggestions| if it has related offer data.
void UpdateSuggestionsWithOffers(const GURL& last_committed_url,
std::vector<Suggestion>& suggestions);
@@ -71,6 +77,8 @@ class AutofillOfferManager : public KeyedService,
AutofillOfferManagerTest,
CreateCardLinkedOffersMap_ReturnsOnlyCardLinkedOffers);
FRIEND_TEST_ALL_PREFIXES(AutofillOfferManagerTest, IsUrlEligible);
+ friend class OfferNotificationBubbleViewsInteractiveUiTest;
+ friend class OfferNotificationInfoBarControllerImplBrowserTest;
// Queries |personal_data_| to reset the elements of
// |eligible_merchant_domains_|
@@ -83,7 +91,15 @@ class AutofillOfferManager : public KeyedService,
raw_ptr<PersonalDataManager> personal_data_;
raw_ptr<CouponServiceDelegate> coupon_service_delegate_;
+
+ // This set includes all the eligible domains where offers are applicable.
+ // This is used as a local cache and will be updated whenever the data in the
+ // database changes.
std::set<GURL> eligible_merchant_domains_ = {};
+
+ // The handler for offer notification UI. It is a sub-level component of
+ // AutofillOfferManager to decide whether to show the offer notification.
+ OfferNotificationHandler notification_handler_{this};
};
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/payments/autofill_offer_manager_unittest.cc b/chromium/components/autofill/core/browser/payments/autofill_offer_manager_unittest.cc
index 4d1d5a4ce96..1789e7a5950 100644
--- a/chromium/components/autofill/core/browser/payments/autofill_offer_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/payments/autofill_offer_manager_unittest.cc
@@ -49,7 +49,6 @@ class AutofillOfferManagerTest : public testing::Test {
/*pref_service=*/autofill_client_.GetPrefs(),
/*local_state=*/autofill_client_.GetPrefs(),
/*identity_manager=*/nullptr,
- /*client_profile_validator=*/nullptr,
/*history_service=*/nullptr,
/*strike_database=*/nullptr,
/*image_fetcher=*/nullptr,
diff --git a/chromium/components/autofill/core/browser/payments/autofill_save_card_infobar_delegate_mobile.cc b/chromium/components/autofill/core/browser/payments/autofill_save_card_infobar_delegate_mobile.cc
index d578b994a6e..9795d7da3e1 100644
--- a/chromium/components/autofill/core/browser/payments/autofill_save_card_infobar_delegate_mobile.cc
+++ b/chromium/components/autofill/core/browser/payments/autofill_save_card_infobar_delegate_mobile.cc
@@ -11,6 +11,7 @@
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "build/branding_buildflags.h"
+#include "build/build_config.h"
#include "components/autofill/core/browser/autofill_experiments.h"
#include "components/autofill/core/browser/data_model/credit_card.h"
#include "components/autofill/core/browser/payments/autofill_save_card_ui_utils_mobile.h"
@@ -129,7 +130,7 @@ AutofillSaveCardInfoBarDelegateMobile::GetIdentifier() const {
bool AutofillSaveCardInfoBarDelegateMobile::ShouldExpire(
const NavigationDetails& details) const {
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
if (base::FeatureList::IsEnabled(
features::kAutofillSaveCardDismissOnNavigation)) {
// Expire the Infobar unless the navigation was triggered by the form that
@@ -139,12 +140,12 @@ bool AutofillSaveCardInfoBarDelegateMobile::ShouldExpire(
// Use the default behavior used by Android.
return false;
}
-#else // defined(OS_IOS)
+#else // BUILDFLAG(IS_IOS)
// The user has submitted a form, causing the page to navigate elsewhere. We
// don't want the infobar to be expired at this point, because the user won't
// get a chance to answer the question.
return false;
-#endif // defined(OS_IOS)
+#endif // BUILDFLAG(IS_IOS)
}
void AutofillSaveCardInfoBarDelegateMobile::InfoBarDismissed() {
@@ -196,7 +197,7 @@ bool AutofillSaveCardInfoBarDelegateMobile::Accept() {
return true;
}
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
bool AutofillSaveCardInfoBarDelegateMobile::UpdateAndAccept(
std::u16string cardholder_name,
std::u16string expiration_date_month,
@@ -211,7 +212,7 @@ bool AutofillSaveCardInfoBarDelegateMobile::UpdateAndAccept(
LogUserAction(AutofillMetrics::INFOBAR_ACCEPTED);
return true;
}
-#endif // defined(OS_IOS)
+#endif // BUILDFLAG(IS_IOS)
void AutofillSaveCardInfoBarDelegateMobile::RunSaveCardPromptCallback(
AutofillClient::SaveCardOfferUserDecision user_decision,
diff --git a/chromium/components/autofill/core/browser/payments/autofill_save_card_infobar_delegate_mobile.h b/chromium/components/autofill/core/browser/payments/autofill_save_card_infobar_delegate_mobile.h
index d0697646717..7c200c2ec9e 100644
--- a/chromium/components/autofill/core/browser/payments/autofill_save_card_infobar_delegate_mobile.h
+++ b/chromium/components/autofill/core/browser/payments/autofill_save_card_infobar_delegate_mobile.h
@@ -103,14 +103,14 @@ class AutofillSaveCardInfoBarDelegateMobile : public ConfirmInfoBarDelegate {
bool Accept() override;
bool Cancel() override;
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
// Updates and then saves the card using |cardholder_name|,
// |expiration_date_month| and |expiration_date_year|, which were provided
// as part of the iOS save card Infobar dialog.
virtual bool UpdateAndAccept(std::u16string cardholder_name,
std::u16string expiration_date_month,
std::u16string expiration_date_year);
-#endif // defined(OS_IOS)
+#endif // BUILDFLAG(IS_IOS)
private:
// Runs the appropriate local or upload save callback with the given
diff --git a/chromium/components/autofill/core/browser/payments/autofill_virtual_card_enrollment_infobar_delegate_mobile.cc b/chromium/components/autofill/core/browser/payments/autofill_virtual_card_enrollment_infobar_delegate_mobile.cc
new file mode 100644
index 00000000000..1bb7295c2c0
--- /dev/null
+++ b/chromium/components/autofill/core/browser/payments/autofill_virtual_card_enrollment_infobar_delegate_mobile.cc
@@ -0,0 +1,144 @@
+// Copyright 2022 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.
+
+#include "components/autofill/core/browser/payments/autofill_virtual_card_enrollment_infobar_delegate_mobile.h"
+
+#include <utility>
+
+#include "base/notreached.h"
+#include "components/grit/components_scaled_resources.h"
+#include "url/gurl.h"
+
+namespace autofill {
+
+AutofillVirtualCardEnrollmentInfoBarDelegateMobile::
+ AutofillVirtualCardEnrollmentInfoBarDelegateMobile(
+ VirtualCardEnrollBubbleController*
+ virtual_card_enroll_bubble_controller)
+ : ConfirmInfoBarDelegate(),
+ virtual_card_enroll_bubble_controller_(
+ virtual_card_enroll_bubble_controller) {}
+
+AutofillVirtualCardEnrollmentInfoBarDelegateMobile::
+ ~AutofillVirtualCardEnrollmentInfoBarDelegateMobile() {
+ if (!had_user_interaction_)
+ OnInfobarClosed(PaymentsBubbleClosedReason::kNotInteracted);
+}
+
+// static
+AutofillVirtualCardEnrollmentInfoBarDelegateMobile*
+AutofillVirtualCardEnrollmentInfoBarDelegateMobile::FromInfobarDelegate(
+ infobars::InfoBarDelegate* delegate) {
+ return delegate->GetIdentifier() ==
+ AUTOFILL_VIRTUAL_CARD_ENROLLMENT_INFOBAR_DELEGATE_MOBILE
+ ? static_cast<AutofillVirtualCardEnrollmentInfoBarDelegateMobile*>(
+ delegate)
+ : nullptr;
+}
+
+std::u16string
+AutofillVirtualCardEnrollmentInfoBarDelegateMobile::GetDescriptionText() const {
+ return virtual_card_enroll_bubble_controller_->GetExplanatoryMessage();
+}
+
+std::u16string
+AutofillVirtualCardEnrollmentInfoBarDelegateMobile::GetLearnMoreLinkText()
+ const {
+ return virtual_card_enroll_bubble_controller_->GetLearnMoreLinkText();
+}
+
+const raw_ptr<gfx::Image>
+AutofillVirtualCardEnrollmentInfoBarDelegateMobile::GetIssuerIcon() const {
+ return virtual_card_enroll_bubble_controller_
+ ->GetVirtualCardEnrollmentFields()
+ .card_art_image.get();
+}
+
+std::u16string
+AutofillVirtualCardEnrollmentInfoBarDelegateMobile::GetCardLabel() const {
+ return virtual_card_enroll_bubble_controller_
+ ->GetVirtualCardEnrollmentFields()
+ .credit_card.CardIdentifierStringForAutofillDisplay();
+}
+
+LegalMessageLines
+AutofillVirtualCardEnrollmentInfoBarDelegateMobile::GetGoogleLegalMessage()
+ const {
+ return virtual_card_enroll_bubble_controller_
+ ->GetVirtualCardEnrollmentFields()
+ .google_legal_message;
+}
+
+LegalMessageLines
+AutofillVirtualCardEnrollmentInfoBarDelegateMobile::GetIssuerLegalMessage()
+ const {
+ return virtual_card_enroll_bubble_controller_
+ ->GetVirtualCardEnrollmentFields()
+ .issuer_legal_message;
+}
+
+void AutofillVirtualCardEnrollmentInfoBarDelegateMobile::OnInfobarLinkClicked(
+ GURL url,
+ VirtualCardEnrollmentLinkType link_type) {
+ virtual_card_enroll_bubble_controller_->OnLinkClicked(link_type, url);
+}
+
+infobars::InfoBarDelegate::InfoBarIdentifier
+AutofillVirtualCardEnrollmentInfoBarDelegateMobile::GetIdentifier() const {
+ return AUTOFILL_VIRTUAL_CARD_ENROLLMENT_INFOBAR_DELEGATE_MOBILE;
+}
+
+int AutofillVirtualCardEnrollmentInfoBarDelegateMobile::GetIconId() const {
+ // TODO(crbug.com/1298224): Change the icon to
+ // IDR_AUTOFILL_GOOGLE_PAY_WITH_DIVIDER after adding the top icon as the
+ // divider currently causes the title to wrap to second line.
+ return IDR_AUTOFILL_GOOGLE_PAY;
+}
+
+std::u16string
+AutofillVirtualCardEnrollmentInfoBarDelegateMobile::GetMessageText() const {
+ return virtual_card_enroll_bubble_controller_->GetWindowTitle();
+}
+
+int AutofillVirtualCardEnrollmentInfoBarDelegateMobile::GetButtons() const {
+ return BUTTON_OK | BUTTON_CANCEL;
+}
+
+std::u16string
+AutofillVirtualCardEnrollmentInfoBarDelegateMobile::GetButtonLabel(
+ InfoBarButton button) const {
+ if (button == BUTTON_OK)
+ return virtual_card_enroll_bubble_controller_->GetAcceptButtonText();
+ if (button == BUTTON_CANCEL)
+ return virtual_card_enroll_bubble_controller_->GetDeclineButtonText();
+ NOTREACHED() << "Unsupported button label requested.";
+ return std::u16string();
+}
+
+void AutofillVirtualCardEnrollmentInfoBarDelegateMobile::InfoBarDismissed() {
+ OnInfobarClosed(PaymentsBubbleClosedReason::kClosed);
+ virtual_card_enroll_bubble_controller_->OnDeclineButton();
+}
+
+bool AutofillVirtualCardEnrollmentInfoBarDelegateMobile::Cancel() {
+ OnInfobarClosed(PaymentsBubbleClosedReason::kClosed);
+ virtual_card_enroll_bubble_controller_->OnDeclineButton();
+ return true;
+}
+
+bool AutofillVirtualCardEnrollmentInfoBarDelegateMobile::Accept() {
+ OnInfobarClosed(PaymentsBubbleClosedReason::kAccepted);
+ virtual_card_enroll_bubble_controller_->OnAcceptButton();
+ return true;
+}
+
+void AutofillVirtualCardEnrollmentInfoBarDelegateMobile::OnInfobarClosed(
+ PaymentsBubbleClosedReason closed_reason) {
+ DCHECK(!had_user_interaction_);
+
+ virtual_card_enroll_bubble_controller_->OnBubbleClosed(closed_reason);
+ had_user_interaction_ = true;
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/payments/autofill_virtual_card_enrollment_infobar_delegate_mobile.h b/chromium/components/autofill/core/browser/payments/autofill_virtual_card_enrollment_infobar_delegate_mobile.h
new file mode 100644
index 00000000000..e23140c59bd
--- /dev/null
+++ b/chromium/components/autofill/core/browser/payments/autofill_virtual_card_enrollment_infobar_delegate_mobile.h
@@ -0,0 +1,88 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_INFOBAR_DELEGATE_MOBILE_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_INFOBAR_DELEGATE_MOBILE_H_
+
+#include <memory>
+#include <string>
+
+#include "components/autofill/core/browser/metrics/payments/virtual_card_enrollment_metrics.h"
+#include "components/autofill/core/browser/payments/legal_message_line.h"
+#include "components/autofill/core/browser/ui/payments/virtual_card_enroll_bubble_controller.h"
+#include "components/infobars/core/confirm_infobar_delegate.h"
+#include "ui/gfx/image/image.h"
+
+namespace autofill {
+
+// An InfoBarDelegate that enables the user to enroll their payment method into
+// virtual card. Only used on mobile.
+class AutofillVirtualCardEnrollmentInfoBarDelegateMobile
+ : public ConfirmInfoBarDelegate {
+ public:
+ AutofillVirtualCardEnrollmentInfoBarDelegateMobile(
+ VirtualCardEnrollBubbleController* virtual_card_enroll_bubble_controller);
+
+ AutofillVirtualCardEnrollmentInfoBarDelegateMobile(
+ const AutofillVirtualCardEnrollmentInfoBarDelegateMobile&) = delete;
+ AutofillVirtualCardEnrollmentInfoBarDelegateMobile& operator=(
+ const AutofillVirtualCardEnrollmentInfoBarDelegateMobile&) = delete;
+
+ ~AutofillVirtualCardEnrollmentInfoBarDelegateMobile() override;
+
+ // Returns |delegate| as an
+ // AutofillVirtualCardEnrollmentInfoBarDelegateMobile, or nullptr if it is of
+ // another type.
+ static AutofillVirtualCardEnrollmentInfoBarDelegateMobile*
+ FromInfobarDelegate(infobars::InfoBarDelegate* delegate);
+
+ // Description text to be shown above the card information in the infobar.
+ std::u16string GetDescriptionText() const;
+
+ // Text of the learn more link in the description.
+ std::u16string GetLearnMoreLinkText() const;
+
+ // Issuer icon for the card.
+ const raw_ptr<gfx::Image> GetIssuerIcon() const;
+
+ // The label for the card to show in the content of the infobar.
+ std::u16string GetCardLabel() const;
+
+ // The Google-specific legal messages that the user must accept before
+ // opting-in to virtual card enrollment.
+ LegalMessageLines GetGoogleLegalMessage() const;
+
+ // The Issuer-specific legal messages that the user must accept before
+ // opting-in to virtual card enrollment. Empty for some issuers.
+ LegalMessageLines GetIssuerLegalMessage() const;
+
+ // Called when a link in the legal message text was clicked.
+ virtual void OnInfobarLinkClicked(GURL url,
+ VirtualCardEnrollmentLinkType link_type);
+
+ // ConfirmInfoBarDelegate:
+ infobars::InfoBarDelegate::InfoBarIdentifier GetIdentifier() const override;
+ int GetIconId() const override;
+ std::u16string GetMessageText() const override;
+ int GetButtons() const override;
+ std::u16string GetButtonLabel(InfoBarButton button) const override;
+ void InfoBarDismissed() override;
+ bool Cancel() override;
+ bool Accept() override;
+
+ private:
+ // Logs metrics via the native controller.
+ void OnInfobarClosed(PaymentsBubbleClosedReason closed_reason);
+
+ // Pointer to the native controller.
+ raw_ptr<VirtualCardEnrollBubbleController>
+ virtual_card_enroll_bubble_controller_;
+
+ // Did the user ever explicitly accept or dismiss this infobar?
+ bool had_user_interaction_ = false;
+};
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_INFOBAR_DELEGATE_MOBILE_H_
diff --git a/chromium/components/autofill/core/browser/payments/autofill_virtual_card_enrollment_infobar_mobile.h b/chromium/components/autofill/core/browser/payments/autofill_virtual_card_enrollment_infobar_mobile.h
new file mode 100644
index 00000000000..4854bb1ea8c
--- /dev/null
+++ b/chromium/components/autofill/core/browser/payments/autofill_virtual_card_enrollment_infobar_mobile.h
@@ -0,0 +1,25 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_INFOBAR_MOBILE_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_INFOBAR_MOBILE_H_
+
+#include <memory>
+
+namespace infobars {
+class InfoBar;
+}
+
+namespace autofill {
+
+class AutofillVirtualCardEnrollmentInfoBarDelegateMobile;
+
+// Creates an Infobar for saving a credit card on a mobile device.
+std::unique_ptr<infobars::InfoBar> CreateVirtualCardEnrollmentInfoBarMobile(
+ std::unique_ptr<AutofillVirtualCardEnrollmentInfoBarDelegateMobile>
+ delegate);
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_INFOBAR_MOBILE_H_
diff --git a/chromium/components/autofill/core/browser/payments/autofill_wallet_model_type_controller.cc b/chromium/components/autofill/core/browser/payments/autofill_wallet_model_type_controller.cc
index 34327f02a5c..f47117768a7 100644
--- a/chromium/components/autofill/core/browser/payments/autofill_wallet_model_type_controller.cc
+++ b/chromium/components/autofill/core/browser/payments/autofill_wallet_model_type_controller.cc
@@ -13,7 +13,7 @@
#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/autofill_prefs.h"
#include "components/prefs/pref_service.h"
-#include "components/sync/driver/sync_driver_switches.h"
+#include "components/sync/base/features.h"
#include "components/sync/driver/sync_service.h"
#include "components/sync/driver/sync_user_settings.h"
#include "google_apis/gaia/google_service_auth_error.h"
@@ -99,7 +99,7 @@ bool AutofillWalletModelTypeController::ShouldRunInTransportOnlyMode() const {
}
if (sync_service_->GetUserSettings()->IsUsingExplicitPassphrase() &&
!base::FeatureList::IsEnabled(
- switches::kSyncAllowWalletDataInTransportModeWithCustomPassphrase)) {
+ syncer::kSyncAllowWalletDataInTransportModeWithCustomPassphrase)) {
return false;
}
return true;
diff --git a/chromium/components/autofill/core/browser/payments/credit_card_access_manager.cc b/chromium/components/autofill/core/browser/payments/credit_card_access_manager.cc
index 96e3ee5116b..3a36119e9fe 100644
--- a/chromium/components/autofill/core/browser/payments/credit_card_access_manager.cc
+++ b/chromium/components/autofill/core/browser/payments/credit_card_access_manager.cc
@@ -33,7 +33,7 @@
#include "components/strings/grit/components_strings.h"
#include "ui/base/l10n/l10n_util.h"
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
#include "components/autofill/core/browser/payments/fido_authentication_strike_database.h"
#endif
@@ -164,7 +164,7 @@ CreditCard* CreditCardAccessManager::GetCreditCard(std::string guid) {
}
void CreditCardAccessManager::PrepareToFetchCreditCard() {
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
// No need to fetch details if there are no server cards.
if (!ServerCardsAvailable())
return;
@@ -244,7 +244,7 @@ void CreditCardAccessManager::OnDidGetUnmaskDetails(
delay_ms = request_timeout->GetInt();
}
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
opt_in_intention_ =
GetOrCreateFIDOAuthenticator()->GetUserOptInIntention(unmask_details);
#endif
@@ -313,7 +313,7 @@ void CreditCardAccessManager::FetchCreditCard(
if (card->record_type() != CreditCard::MASKED_SERVER_CARD &&
card->record_type() != CreditCard::VIRTUAL_CARD) {
accessor->OnCreditCardFetched(CreditCardFetchResult::kSuccess, card);
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
// Latency metrics should only be logged if the user is verifiable.
if (is_user_verifiable_.value_or(false)) {
AutofillMetrics::LogUserPerceivedLatencyOnCardSelection(
@@ -339,7 +339,7 @@ void CreditCardAccessManager::FetchCreditCard(
}
void CreditCardAccessManager::FIDOAuthOptChange(bool opt_in) {
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
return;
#else
if (opt_in) {
@@ -355,7 +355,7 @@ void CreditCardAccessManager::FIDOAuthOptChange(bool opt_in) {
}
void CreditCardAccessManager::OnSettingsPageFIDOAuthToggled(bool opt_in) {
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
return;
#else
// TODO(crbug/949269): Add a rate limiter to counter spam clicking.
@@ -379,7 +379,7 @@ void CreditCardAccessManager::CacheUnmaskedCardInfo(const CreditCard& card,
}
void CreditCardAccessManager::GetAuthenticationType(bool fido_auth_enabled) {
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
// There is no FIDO auth available on iOS and there are no virtual cards on
// iOS either, so offer CVC auth immediately.
OnDidGetAuthenticationType(UnmaskAuthFlowType::kCvc);
@@ -400,7 +400,7 @@ void CreditCardAccessManager::GetAuthenticationTypeForVirtualCard(
// auth was provided by issuer, we prefer FIDO auth. Remove FIDO preference
// and allow user selections later.
if (fido_auth_enabled) {
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
ShowVerifyPendingDialog();
#endif
OnDidGetAuthenticationType(UnmaskAuthFlowType::kFido);
@@ -430,7 +430,7 @@ void CreditCardAccessManager::GetAuthenticationTypeForVirtualCard(
void CreditCardAccessManager::GetAuthenticationTypeForMaskedServerCard(
bool fido_auth_enabled) {
UnmaskAuthFlowType flow_type;
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
// There is no FIDO auth available on iOS, so offer CVC auth immediately.
flow_type = UnmaskAuthFlowType::kCvc;
#else
@@ -493,7 +493,7 @@ void CreditCardAccessManager::Authenticate() {
switch (unmask_auth_flow_type_) {
case UnmaskAuthFlowType::kFido: {
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
NOTREACHED();
#else
// If |is_authentication_in_progress_| is false, it means the process has
@@ -529,7 +529,7 @@ void CreditCardAccessManager::Authenticate() {
case UnmaskAuthFlowType::kCvcThenFido:
case UnmaskAuthFlowType::kCvc:
case UnmaskAuthFlowType::kCvcFallbackFromFido: {
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
// Close the Webauthn verify pending dialog if it enters CVC
// authentication flow since the card unmask prompt will pop up.
client_->CloseWebauthnDialog();
@@ -587,7 +587,7 @@ CreditCardAccessManager::GetOrCreateCVCAuthenticator() {
return cvc_authenticator_.get();
}
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
CreditCardFIDOAuthenticator*
CreditCardAccessManager::GetOrCreateFIDOAuthenticator() {
if (!fido_authenticator_)
@@ -637,7 +637,7 @@ void CreditCardAccessManager::OnCVCAuthenticationComplete(
// immediately.
bool should_respond_immediately =
!response.did_succeed || response.card_authorization_token.empty();
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// GetRealPan did not return RequestOptions (user did not specify intent to
// opt-in) AND flow is not registering a new card, also fill the form
// directly.
@@ -659,7 +659,7 @@ void CreditCardAccessManager::OnCVCAuthenticationComplete(
// both be true).
bool should_authorize_with_fido =
unmask_auth_flow_type_ == UnmaskAuthFlowType::kCvcThenFido;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// For Android, we will delay the form filling for both intent-to-opt-in user
// opting in and opted-in user registering a new card (kCvcThenFido). So we
// check one more scenario for Android here. If the GetRealPan response
@@ -680,7 +680,7 @@ void CreditCardAccessManager::OnCVCAuthenticationComplete(
bool should_offer_fido_auth = false;
// For iOS, FIDO auth is not supported yet. For Android, users have already
// been offered opt-in at this point.
-#if !defined(OS_IOS) && !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_IOS) && !BUILDFLAG(IS_ANDROID)
should_offer_fido_auth = unmask_details_.offer_fido_opt_in &&
!response.card_authorization_token.empty() &&
!GetOrCreateFIDOAuthenticator()
@@ -713,7 +713,7 @@ void CreditCardAccessManager::OnCVCAuthenticationComplete(
// remove the two variables and use a function.
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
bool CreditCardAccessManager::ShouldOfferFidoAuth() const {
// If the user opted-in through the settings page, do not show checkbox.
return unmask_details_.offer_fido_opt_in &&
@@ -726,10 +726,10 @@ bool CreditCardAccessManager::UserOptedInToFidoFromSettingsPageOnMobile()
}
#endif
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
void CreditCardAccessManager::OnFIDOAuthenticationComplete(
const CreditCardFIDOAuthenticator::FidoAuthenticationResponse& response) {
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
// Close the Webauthn verify pending dialog. If FIDO authentication succeeded,
// card is filled to the form, otherwise fall back to CVC authentication which
// does not need the verify pending dialog either.
@@ -863,7 +863,7 @@ bool CreditCardAccessManager::IsLocalCard(const CreditCard* card) {
}
bool CreditCardAccessManager::IsUserOptedInToFidoAuth() {
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
return false;
#else
return is_user_verifiable_.value_or(false) &&
@@ -887,7 +887,7 @@ bool CreditCardAccessManager::IsSelectedCardFidoAuthorized() {
void CreditCardAccessManager::ShowWebauthnOfferDialog(
std::string card_authorization_token) {
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
GetOrCreateFIDOAuthenticator()->OnWebauthnOfferDialogRequested(
card_authorization_token);
client_->ShowWebauthnOfferDialog(
@@ -896,7 +896,7 @@ void CreditCardAccessManager::ShowWebauthnOfferDialog(
#endif
}
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
void CreditCardAccessManager::ShowVerifyPendingDialog() {
client_->ShowWebauthnVerifyPendingDialog(
base::BindRepeating(&CreditCardAccessManager::HandleDialogUserResponse,
@@ -936,7 +936,7 @@ void CreditCardAccessManager::HandleDialogUserResponse(
void CreditCardAccessManager::AdditionallyPerformFidoAuth(
const CreditCardCVCAuthenticator::CVCAuthenticationResponse& response,
base::Value request_options) {
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
// Save credit card for after authorization.
card_ = std::make_unique<CreditCard>(*(response.card));
cvc_ = response.cvc;
@@ -963,7 +963,7 @@ void CreditCardAccessManager::FetchMaskedServerCard() {
IsUserOptedInToFidoAuth() && !get_unmask_details_returned;
// Latency metrics should only be logged if the user is verifiable.
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
if (is_user_verifiable_.value_or(false)) {
AutofillMetrics::LogUserPerceivedLatencyOnCardSelection(
get_unmask_details_returned
@@ -975,7 +975,7 @@ void CreditCardAccessManager::FetchMaskedServerCard() {
}
#endif
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
// On desktop, show the verify pending dialog for opted-in user, unless it is
// already known that selected card requires CVC.
if (IsUserOptedInToFidoAuth() &&
@@ -1190,7 +1190,7 @@ void CreditCardAccessManager::Reset() {
preflight_call_timestamp_ = absl::nullopt;
card_selected_without_unmask_details_timestamp_ = absl::nullopt;
is_user_verifiable_called_timestamp_ = absl::nullopt;
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
opt_in_intention_ = UserOptInIntention::kUnspecified;
#endif
unmask_details_ = payments::PaymentsClient::UnmaskDetails();
@@ -1206,7 +1206,7 @@ void CreditCardAccessManager::Reset() {
}
void CreditCardAccessManager::HandleFidoOptInStatusChange() {
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
// If user intended to opt out, we will opt user out after CVC/OTP auth
// completes (no matter it succeeded or failed).
if (opt_in_intention_ == UserOptInIntention::kIntentToOptOut) {
diff --git a/chromium/components/autofill/core/browser/payments/credit_card_access_manager.h b/chromium/components/autofill/core/browser/payments/credit_card_access_manager.h
index a88d5633c68..f7f0e15c293 100644
--- a/chromium/components/autofill/core/browser/payments/credit_card_access_manager.h
+++ b/chromium/components/autofill/core/browser/payments/credit_card_access_manager.h
@@ -26,7 +26,7 @@
#include "components/autofill/core/browser/payments/wait_for_signal_or_timeout.h"
#include "components/autofill/core/browser/personal_data_manager.h"
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
#include "components/autofill/core/browser/payments/credit_card_fido_authenticator.h"
#endif
@@ -79,7 +79,7 @@ struct CachedServerCardInfo {
// Manages logic for accessing credit cards either stored locally or stored
// with Google Payments. Owned by BrowserAutofillManager.
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
class CreditCardAccessManager : public CreditCardCVCAuthenticator::Requester,
public CreditCardOtpAuthenticator::Requester {
#else
@@ -167,7 +167,7 @@ class CreditCardAccessManager : public CreditCardCVCAuthenticator::Requester,
// authenticators if they do not exist. Otherwise the accessors will simply
// return references to the authenticators.
CreditCardCVCAuthenticator* GetOrCreateCVCAuthenticator();
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
CreditCardFIDOAuthenticator* GetOrCreateFIDOAuthenticator();
#endif
CreditCardOtpAuthenticator* GetOrCreateOtpAuthenticator();
@@ -217,7 +217,7 @@ class CreditCardAccessManager : public CreditCardCVCAuthenticator::Requester,
friend class AutofillMetricsTest;
friend class CreditCardAccessManagerTest;
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
void set_fido_authenticator_for_testing(
std::unique_ptr<CreditCardFIDOAuthenticator> fido_authenticator) {
fido_authenticator_ = std::move(fido_authenticator);
@@ -275,12 +275,12 @@ class CreditCardAccessManager : public CreditCardCVCAuthenticator::Requester,
void OnCVCAuthenticationComplete(
const CreditCardCVCAuthenticator::CVCAuthenticationResponse& response)
override;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
bool ShouldOfferFidoAuth() const override;
bool UserOptedInToFidoFromSettingsPageOnMobile() const override;
#endif
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
// CreditCardFIDOAuthenticator::Requester:
void OnFIDOAuthenticationComplete(
const CreditCardFIDOAuthenticator::FidoAuthenticationResponse& response)
@@ -316,7 +316,7 @@ class CreditCardAccessManager : public CreditCardCVCAuthenticator::Requester,
// Offer the option to use WebAuthn for authenticating future card unmasking.
void ShowWebauthnOfferDialog(std::string card_authorization_token);
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
// After card verification starts, shows the verify pending dialog if WebAuthn
// is enabled, indicating some verification steps are in progress.
void ShowVerifyPendingDialog();
@@ -414,7 +414,7 @@ class CreditCardAccessManager : public CreditCardCVCAuthenticator::Requester,
// Authenticators for card unmasking.
std::unique_ptr<CreditCardCVCAuthenticator> cvc_authenticator_;
std::unique_ptr<CreditCardOtpAuthenticator> otp_authenticator_;
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
std::unique_ptr<CreditCardFIDOAuthenticator> fido_authenticator_;
// User opt in/out intention when local pref and payments mismatch.
diff --git a/chromium/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc b/chromium/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc
index f44bdad1cb7..ce16d63ee24 100644
--- a/chromium/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc
@@ -69,7 +69,7 @@
#include "ui/gfx/geometry/rect.h"
#include "url/gurl.h"
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
#include "components/autofill/core/browser/payments/fido_authentication_strike_database.h"
#include "components/autofill/core/browser/payments/test_credit_card_fido_authenticator.h"
#include "components/autofill/core/browser/payments/test_internal_authenticator.h"
@@ -91,7 +91,7 @@ const char16_t kTestCvc16[] = u"123";
const char kTestServerId[] = "server_id_1";
const char kTestServerId2[] = "server_id_2";
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
const char kTestCvc[] = "123";
// Base64 encoding of "This is a test challenge".
constexpr char kTestChallenge[] = "VGhpcyBpcyBhIHRlc3QgY2hhbGxlbmdl";
@@ -178,7 +178,6 @@ class CreditCardAccessManagerTest : public testing::Test {
/*pref_service=*/autofill_client_.GetPrefs(),
/*local_state=*/autofill_client_.GetPrefs(),
/*identity_manager=*/nullptr,
- /*client_profile_validator=*/nullptr,
/*history_service=*/nullptr,
/*strike_database=*/nullptr,
/*image_fetcher=*/nullptr,
@@ -200,7 +199,7 @@ class CreditCardAccessManagerTest : public testing::Test {
credit_card_access_manager_ =
browser_autofill_manager_->credit_card_access_manager();
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
autofill_driver_->SetBrowserAutofillManager(
std::move(browser_autofill_manager_));
autofill_driver_->SetAuthenticator(new TestInternalAuthenticator());
@@ -278,7 +277,7 @@ class CreditCardAccessManagerTest : public testing::Test {
// Mock user response.
payments::FullCardRequest::UserProvidedUnmaskDetails details;
details.cvc = cvc;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
details.enable_fido_auth = enable_fido;
#endif
full_card_request->OnUnmaskPromptAccepted(details);
@@ -300,7 +299,7 @@ class CreditCardAccessManagerTest : public testing::Test {
MockUserResponseForCvcAuth(kTestCvc16, follow_with_fido_auth);
payments::PaymentsClient::UnmaskResponseDetails response;
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
response.card_authorization_token = "dummy_card_authorization_token";
if (fido_opt_in) {
response.fido_creation_options = GetTestCreationOptions();
@@ -317,7 +316,7 @@ class CreditCardAccessManagerTest : public testing::Test {
return true;
}
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
void ClearStrikes() {
return GetFIDOAuthenticator()
->GetOrCreateFidoAuthenticationStrikeDatabase()
@@ -401,7 +400,7 @@ class CreditCardAccessManagerTest : public testing::Test {
}
#endif
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
// Mocks user response for the offer dialog.
void AcceptWebauthnOfferDialog(bool did_accept) {
GetFIDOAuthenticator()->OnWebauthnOfferDialogUserResponse(did_accept);
@@ -448,7 +447,7 @@ class CreditCardAccessManagerTest : public testing::Test {
credit_card_access_manager_->GetCreditCard(kTestGUID);
virtual_card->set_record_type(CreditCard::VIRTUAL_CARD);
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
fido_authenticator_->set_is_user_opted_in(
fido_authenticator_is_user_opted_in);
#endif
@@ -474,14 +473,14 @@ class CreditCardAccessManagerTest : public testing::Test {
.type = CardUnmaskChallengeOptionType::kSmsOtp,
.challenge_info = u"fake challenge info"};
response.card_unmask_challenge_options.emplace_back(challenge_option);
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
if (fido_authenticator_is_user_opted_in)
response.fido_request_options = GetTestRequestOptions();
#endif
credit_card_access_manager_->OnVirtualCardUnmaskResponseReceived(
AutofillClient::PaymentsRpcResult::kSuccess, response);
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
// This if-statement ensures that fido-related flows run correctly.
if (fido_authenticator_is_user_opted_in) {
// Expect the CreditCardAccessManager invokes the FIDO authenticator
@@ -536,7 +535,7 @@ class CreditCardAccessManagerTest : public testing::Test {
std::unique_ptr<BrowserAutofillManager> browser_autofill_manager_;
raw_ptr<CreditCardAccessManager> credit_card_access_manager_;
raw_ptr<TestCreditCardOtpAuthenticator> otp_authenticator_;
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
raw_ptr<TestCreditCardFIDOAuthenticator> fido_authenticator_;
#endif
};
@@ -727,7 +726,7 @@ TEST_F(CreditCardAccessManagerTest, CardUnmaskPreflightCalledMetric) {
base::HistogramTester histogram_tester;
ClearCards();
CreateLocalCard(kTestGUID, kTestNumber);
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
GetFIDOAuthenticator()->SetUserVerifiable(true);
#endif
ResetFetchCreditCard();
@@ -748,7 +747,7 @@ TEST_F(CreditCardAccessManagerTest, CardUnmaskPreflightCalledMetric) {
base::HistogramTester histogram_tester;
ClearCards();
CreateServerCard(kTestGUID, kTestNumber);
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
GetFIDOAuthenticator()->SetUserVerifiable(false);
#endif
ResetFetchCreditCard();
@@ -759,7 +758,7 @@ TEST_F(CreditCardAccessManagerTest, CardUnmaskPreflightCalledMetric) {
// Server cards are available, check for verifiability is made.
// But since user is not verifiable, no preflight call is made.
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
histogram_tester.ExpectTotalCount(verifiability_check_metric, 0);
#else
histogram_tester.ExpectTotalCount(verifiability_check_metric, 1);
@@ -773,7 +772,7 @@ TEST_F(CreditCardAccessManagerTest, CardUnmaskPreflightCalledMetric) {
base::HistogramTester histogram_tester;
ClearCards();
CreateServerCard(kTestGUID, kTestNumber);
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
GetFIDOAuthenticator()->SetUserVerifiable(true);
#endif
ResetFetchCreditCard();
@@ -784,7 +783,7 @@ TEST_F(CreditCardAccessManagerTest, CardUnmaskPreflightCalledMetric) {
// Preflight call is made only if a server card is available and the user is
// eligible for FIDO authentication, except on iOS.
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
histogram_tester.ExpectTotalCount(verifiability_check_metric, 0);
histogram_tester.ExpectTotalCount(preflight_call_metric, 0);
histogram_tester.ExpectTotalCount(preflight_latency_metric, 0);
@@ -796,7 +795,7 @@ TEST_F(CreditCardAccessManagerTest, CardUnmaskPreflightCalledMetric) {
}
}
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
// Ensures that FetchCreditCard() returns the full PAN upon a successful
// WebAuthn verification and response from payments.
TEST_F(CreditCardAccessManagerTest, FetchServerCardFIDOSuccess) {
@@ -1409,7 +1408,7 @@ TEST_F(CreditCardAccessManagerTest,
CreditCardFormEventLogger::UnmaskAuthFlowEvent::kPromptCompleted, 1);
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Ensures that the WebAuthn verification prompt is invoked after user opts in
// on unmask card checkbox.
TEST_F(CreditCardAccessManagerTest, FIDOOptInSuccess_Android) {
@@ -1601,7 +1600,7 @@ TEST_F(CreditCardAccessManagerTest, FIDOSettingsPageOptInSuccess_Android) {
payments_client_->unmask_request()->user_response.enable_fido_auth);
}
-#else // defined(OS_ANDROID)
+#else // BUILDFLAG(IS_ANDROID)
// Ensures that the WebAuthn enrollment prompt is invoked after user opts in. In
// this case, the user is not yet enrolled server-side, and thus receives
// |creation_options|.
@@ -1911,7 +1910,7 @@ TEST_F(CreditCardAccessManagerTest, SettingsPage_OptOut) {
EXPECT_FALSE(IsCreditCardFIDOAuthEnabled());
histogram_tester.ExpectTotalCount(histogram_name, 1);
}
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
// Ensure that when unmask detail response is delayed, we will automatically
// fall back to CVC even if local pref and Payments mismatch.
@@ -2067,7 +2066,7 @@ TEST_F(CreditCardAccessManagerTest, IntentToOptOut_OptOutFailure) {
}
// TODO(crbug.com/1109296) Debug issues and re-enable this test on MacOS.
-#if !defined(OS_APPLE)
+#if !BUILDFLAG(IS_APPLE)
// Ensures that PrepareToFetchCreditCard() is properly rate limited.
TEST_F(CreditCardAccessManagerTest, PreflightCallRateLimited) {
// Create server card and set user as eligible for FIDO auth.
@@ -2104,8 +2103,8 @@ TEST_F(CreditCardAccessManagerTest, PreflightCallRateLimited) {
// logged.
histogram_tester.ExpectTotalCount(preflight_call_metric, 2);
}
-#endif // !defined(OS_APPLE)
-#endif // !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_APPLE)
+#endif // !BUILDFLAG(IS_IOS)
// Ensures that |is_authentication_in_progress_| is set correctly.
TEST_F(CreditCardAccessManagerTest, AuthenticationInProgress) {
@@ -2277,7 +2276,7 @@ TEST_F(CreditCardAccessManagerTest,
AutofillMetrics::ServerCardUnmaskResult::kAuthenticationUnmasked, 1);
}
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
// Ensures that the virtual card risk-based unmasking response is handled
// correctly and authentication is delegated to the FIDO authenticator, when
// only the FIDO challenge options is returned.
@@ -2517,7 +2516,7 @@ TEST_F(
1);
}
-#endif // !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_IOS)
// Ensures that the virtual card risk-based unmasking response is handled
// correctly if there is no challenge option returned by the server.
@@ -2537,7 +2536,7 @@ TEST_F(CreditCardAccessManagerTest,
// |is_user_verifiable_| related logic from CreditCardAccessManager to
// CreditCardFidoAuthenticator.
credit_card_access_manager_->is_user_verifiable_ = true;
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
fido_authenticator_->set_is_user_opted_in(true);
#endif
@@ -2559,7 +2558,7 @@ TEST_F(CreditCardAccessManagerTest,
// Expect the CreditCardAccessManager to end the session.
EXPECT_EQ(accessor_->result(), CreditCardFetchResult::kTransientError);
EXPECT_FALSE(otp_authenticator_->on_challenge_option_selected_invoked());
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
EXPECT_FALSE(fido_authenticator_->authenticate_invoked());
#endif
@@ -2589,7 +2588,7 @@ TEST_F(CreditCardAccessManagerTest,
// is_user_veriable_ related logic from CreditCardAccessManager to
// CreditCardFidoAuthenticator.
credit_card_access_manager_->is_user_verifiable_ = true;
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
fido_authenticator_->set_is_user_opted_in(true);
#endif
@@ -2611,7 +2610,7 @@ TEST_F(CreditCardAccessManagerTest,
// Expect the CreditCardAccessManager to end the session.
EXPECT_EQ(accessor_->result(), CreditCardFetchResult::kTransientError);
EXPECT_FALSE(otp_authenticator_->on_challenge_option_selected_invoked());
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
EXPECT_FALSE(fido_authenticator_->authenticate_invoked());
#endif
@@ -2639,7 +2638,7 @@ TEST_F(CreditCardAccessManagerTest,
// is_user_veriable_ related logic from CreditCardAccessManager to
// CreditCardFidoAuthenticator.
credit_card_access_manager_->is_user_verifiable_ = true;
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
fido_authenticator_->set_is_user_opted_in(true);
#endif
@@ -2657,7 +2656,7 @@ TEST_F(CreditCardAccessManagerTest,
EXPECT_EQ(accessor_->result(), CreditCardFetchResult::kTransientError);
EXPECT_FALSE(otp_authenticator_->on_challenge_option_selected_invoked());
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
EXPECT_FALSE(fido_authenticator_->authenticate_invoked());
#endif
diff --git a/chromium/components/autofill/core/browser/payments/credit_card_cvc_authenticator.cc b/chromium/components/autofill/core/browser/payments/credit_card_cvc_authenticator.cc
index 3f22e722569..c9541c061f4 100644
--- a/chromium/components/autofill/core/browser/payments/credit_card_cvc_authenticator.cc
+++ b/chromium/components/autofill/core/browser/payments/credit_card_cvc_authenticator.cc
@@ -83,7 +83,7 @@ void CreditCardCVCAuthenticator::OnUnmaskVerificationResult(
client_->OnUnmaskVerificationResult(result);
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
bool CreditCardCVCAuthenticator::ShouldOfferFidoAuth() const {
return requester_ && requester_->ShouldOfferFidoAuth();
}
diff --git a/chromium/components/autofill/core/browser/payments/credit_card_cvc_authenticator.h b/chromium/components/autofill/core/browser/payments/credit_card_cvc_authenticator.h
index f3182567a38..146323d36d8 100644
--- a/chromium/components/autofill/core/browser/payments/credit_card_cvc_authenticator.h
+++ b/chromium/components/autofill/core/browser/payments/credit_card_cvc_authenticator.h
@@ -66,7 +66,7 @@ class CreditCardCVCAuthenticator
virtual void OnCVCAuthenticationComplete(
const CVCAuthenticationResponse& response) = 0;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Returns whether or not the user, while on the CVC prompt, should be
// offered to switch to FIDO authentication for card unmasking. This will
// always be false for Desktop since FIDO authentication is offered as a
@@ -109,7 +109,7 @@ class CreditCardCVCAuthenticator
base::WeakPtr<CardUnmaskDelegate> delegate) override;
void OnUnmaskVerificationResult(
AutofillClient::PaymentsRpcResult result) override;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
bool ShouldOfferFidoAuth() const override;
bool UserOptedInToFidoFromSettingsPageOnMobile() const override;
#endif
diff --git a/chromium/components/autofill/core/browser/payments/credit_card_cvc_authenticator_unittest.cc b/chromium/components/autofill/core/browser/payments/credit_card_cvc_authenticator_unittest.cc
index d71eeccceca..20683e684c1 100644
--- a/chromium/components/autofill/core/browser/payments/credit_card_cvc_authenticator_unittest.cc
+++ b/chromium/components/autofill/core/browser/payments/credit_card_cvc_authenticator_unittest.cc
@@ -82,7 +82,6 @@ class CreditCardCVCAuthenticatorTest : public testing::Test {
/*pref_service=*/autofill_client_.GetPrefs(),
/*local_state=*/autofill_client_.GetPrefs(),
/*identity_manager=*/nullptr,
- /*client_profile_validator=*/nullptr,
/*history_service=*/nullptr,
/*strike_database=*/nullptr,
/*image_fetcher=*/nullptr,
diff --git a/chromium/components/autofill/core/browser/payments/credit_card_fido_authenticator.cc b/chromium/components/autofill/core/browser/payments/credit_card_fido_authenticator.cc
index b9a4a9ee4c6..0c67d246414 100644
--- a/chromium/components/autofill/core/browser/payments/credit_card_fido_authenticator.cc
+++ b/chromium/components/autofill/core/browser/payments/credit_card_fido_authenticator.cc
@@ -9,7 +9,9 @@
#include <utility>
#include <vector>
-#if defined(OS_ANDROID)
+#include "build/build_config.h"
+
+#if BUILDFLAG(IS_ANDROID)
#include "base/android/build_info.h"
#endif
#include "base/base64.h"
@@ -148,7 +150,7 @@ void CreditCardFIDOAuthenticator::IsUserVerifiable(
std::move(callback).Run(false);
return;
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Because Payments servers only accept WebAuthn credentials for Android P
// and above, this returns false if the build version is O or below.
if (base::android::BuildInfo::GetInstance()->sdk_int() <
@@ -156,7 +158,7 @@ void CreditCardFIDOAuthenticator::IsUserVerifiable(
std::move(callback).Run(false);
return;
}
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
authenticator()->IsUserVerifyingPlatformAuthenticatorAvailable(
std::move(callback));
}
@@ -178,7 +180,7 @@ UserOptInIntention CreditCardFIDOAuthenticator::GetUserOptInIntention(
// If payments is offering to opt-in, then that means user is not opted in
// from Payments. Only take action if the local pref mismatches.
if (unmask_details.offer_fido_opt_in && user_local_opt_in_status) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// For Android, if local pref says user is opted in while payments not, it
// denotes that user intended to opt in from settings page. We will opt user
// in and hide the checkbox in the next checkout flow.
@@ -217,7 +219,7 @@ void CreditCardFIDOAuthenticator::CancelVerification() {
full_card_request_->OnFIDOVerificationCancelled();
}
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
void CreditCardFIDOAuthenticator::OnWebauthnOfferDialogRequested(
std::string card_authorization_token) {
card_authorization_token_ = card_authorization_token;
@@ -278,7 +280,7 @@ CreditCardFIDOAuthenticator::GetOrCreateFidoAuthenticationStrikeDatabase() {
void CreditCardFIDOAuthenticator::GetAssertion(
PublicKeyCredentialRequestOptionsPtr request_options) {
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
// On desktop, during an opt-in flow, close the WebAuthn offer dialog and get
// ready to show the OS level authentication dialog. If dialog is already
// closed, then the offer was declined during the fetching challenge process,
@@ -304,7 +306,7 @@ void CreditCardFIDOAuthenticator::GetAssertion(
void CreditCardFIDOAuthenticator::MakeCredential(
PublicKeyCredentialCreationOptionsPtr creation_options) {
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
// On desktop, close the WebAuthn offer dialog and get ready to show the OS
// level authentication dialog. If dialog is already closed, then the offer
// was declined during the fetching challenge process, and thus returned
@@ -392,7 +394,8 @@ void CreditCardFIDOAuthenticator::OptChange(
void CreditCardFIDOAuthenticator::OnDidGetAssertion(
AuthenticatorStatus status,
- GetAssertionAuthenticatorResponsePtr assertion_response) {
+ GetAssertionAuthenticatorResponsePtr assertion_response,
+ WebAuthnDOMExceptionDetailsPtr dom_exception_details) {
LogWebauthnResult(status);
// End the flow if there was an authentication error.
@@ -408,11 +411,11 @@ void CreditCardFIDOAuthenticator::OnDidGetAssertion(
// Treat failure to perform user verification as a strong signal not to
// offer opt-in in the future.
if (current_flow_ == OPT_IN_WITH_CHALLENGE_FLOW) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// For Android, even if GetAssertion fails for opting-in, we still report
// success to |requester_| to fill the form with the fetched card info.
requester_->OnFidoAuthorizationComplete(/*did_succeed=*/true);
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
GetOrCreateFidoAuthenticationStrikeDatabase()->AddStrikes(
FidoAuthenticationStrikeDatabase::
kStrikesToAddWhenUserVerificationFailsOnOptInAttempt);
@@ -449,7 +452,7 @@ void CreditCardFIDOAuthenticator::OnDidGetAssertion(
// reported so that the form can be filled.
bool should_respond_to_requester =
(current_flow_ == FOLLOWUP_AFTER_CVC_AUTH_FLOW);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// For Android, opt-in flow (OPT_IN_WITH_CHALLENGE_FLOW) also delays form
// filling.
should_respond_to_requester |=
@@ -467,7 +470,8 @@ void CreditCardFIDOAuthenticator::OnDidGetAssertion(
void CreditCardFIDOAuthenticator::OnDidMakeCredential(
AuthenticatorStatus status,
- MakeCredentialAuthenticatorResponsePtr attestation_response) {
+ MakeCredentialAuthenticatorResponsePtr attestation_response,
+ WebAuthnDOMExceptionDetailsPtr dom_exception_details) {
LogWebauthnResult(status);
// End the flow if there was an authentication error.
@@ -509,7 +513,7 @@ void CreditCardFIDOAuthenticator::OnDidGetOptChangeResult(
// End the flow if the server responded with an error.
if (result != AutofillClient::PaymentsRpcResult::kSuccess) {
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
if (current_flow_ == OPT_IN_FETCH_CHALLENGE_FLOW)
autofill_client_->UpdateWebauthnOfferDialogWithError();
#endif
@@ -575,7 +579,7 @@ CreditCardFIDOAuthenticator::ParseRequestOptions(
const auto* key_info_list =
request_options.FindKeyOfType("key_info", base::Value::Type::LIST);
DCHECK(key_info_list);
- for (const base::Value& key_info : key_info_list->GetList()) {
+ for (const base::Value& key_info : key_info_list->GetListDeprecated()) {
options->allow_credentials.push_back(ParseCredentialDescriptor(key_info));
}
@@ -624,7 +628,8 @@ CreditCardFIDOAuthenticator::ParseCreationOptions(
const auto* identifier_list = creation_options.FindKeyOfType(
"algorithm_identifier", base::Value::Type::LIST);
if (identifier_list) {
- for (const base::Value& algorithm_identifier : identifier_list->GetList()) {
+ for (const base::Value& algorithm_identifier :
+ identifier_list->GetListDeprecated()) {
device::PublicKeyCredentialParams::CredentialInfo parameter;
parameter.type = device::CredentialType::kPublicKey;
parameter.algorithm = algorithm_identifier.GetInt();
@@ -660,7 +665,8 @@ CreditCardFIDOAuthenticator::ParseCreationOptions(
const auto* excluded_keys_list =
creation_options.FindKeyOfType("key_info", base::Value::Type::LIST);
if (excluded_keys_list) {
- for (const base::Value& key_info : excluded_keys_list->GetList()) {
+ for (const base::Value& key_info :
+ excluded_keys_list->GetListDeprecated()) {
options->exclude_credentials.push_back(
ParseCredentialDescriptor(key_info));
}
@@ -680,8 +686,8 @@ CreditCardFIDOAuthenticator::ParseCredentialDescriptor(
base::flat_set<FidoTransportProtocol> authenticator_transports;
const auto* transports = key_info.FindKeyOfType(
"authenticator_transport_support", base::Value::Type::LIST);
- if (transports && !transports->GetList().empty()) {
- for (const base::Value& transport_type : transports->GetList()) {
+ if (transports && !transports->GetListDeprecated().empty()) {
+ for (const base::Value& transport_type : transports->GetListDeprecated()) {
absl::optional<FidoTransportProtocol> protocol =
device::ConvertToFidoTransportProtocol(
base::ToLowerASCII(transport_type.GetString()));
@@ -745,10 +751,10 @@ bool CreditCardFIDOAuthenticator::IsValidRequestOptions(
const auto* key_info_list =
request_options.FindKeyOfType("key_info", base::Value::Type::LIST);
- if (key_info_list->GetList().empty())
+ if (key_info_list->GetListDeprecated().empty())
return false;
- for (const base::Value& key_info : key_info_list->GetList()) {
+ for (const base::Value& key_info : key_info_list->GetListDeprecated()) {
if (!key_info.is_dict() || !key_info.FindStringKey("credential_id"))
return false;
}
diff --git a/chromium/components/autofill/core/browser/payments/credit_card_fido_authenticator.h b/chromium/components/autofill/core/browser/payments/credit_card_fido_authenticator.h
index ef265d91108..29498ddae70 100644
--- a/chromium/components/autofill/core/browser/payments/credit_card_fido_authenticator.h
+++ b/chromium/components/autofill/core/browser/payments/credit_card_fido_authenticator.h
@@ -33,6 +33,7 @@ using blink::mojom::PublicKeyCredentialCreationOptions;
using blink::mojom::PublicKeyCredentialCreationOptionsPtr;
using blink::mojom::PublicKeyCredentialRequestOptions;
using blink::mojom::PublicKeyCredentialRequestOptionsPtr;
+using blink::mojom::WebAuthnDOMExceptionDetailsPtr;
using device::AttestationConveyancePreference;
using device::AuthenticatorAttachment;
using device::AuthenticatorSelectionCriteria;
@@ -153,7 +154,7 @@ class CreditCardFIDOAuthenticator
// and in the FullCardRequest if any.
void CancelVerification();
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
// Invoked when a Webauthn offer dialog is about to be shown.
void OnWebauthnOfferDialogRequested(std::string card_authorization_token);
@@ -200,14 +201,16 @@ class CreditCardFIDOAuthenticator
// card details.
void OnDidGetAssertion(
AuthenticatorStatus status,
- GetAssertionAuthenticatorResponsePtr assertion_response);
+ GetAssertionAuthenticatorResponsePtr assertion_response,
+ WebAuthnDOMExceptionDetailsPtr dom_exception_details);
// The callback invoked from the WebAuthn prompt including the
// |attestation_response|, which will be sent to Google Payments to enroll the
// credential for this user.
void OnDidMakeCredential(
AuthenticatorStatus status,
- MakeCredentialAuthenticatorResponsePtr attestation_response);
+ MakeCredentialAuthenticatorResponsePtr attestation_response,
+ WebAuthnDOMExceptionDetailsPtr dom_exception_details);
// Sets prefstore to enable credit card authentication if rpc was successful.
void OnDidGetOptChangeResult(
diff --git a/chromium/components/autofill/core/browser/payments/credit_card_fido_authenticator_unittest.cc b/chromium/components/autofill/core/browser/payments/credit_card_fido_authenticator_unittest.cc
index 845bd8fd9ac..26b3dde6073 100644
--- a/chromium/components/autofill/core/browser/payments/credit_card_fido_authenticator_unittest.cc
+++ b/chromium/components/autofill/core/browser/payments/credit_card_fido_authenticator_unittest.cc
@@ -112,7 +112,6 @@ class CreditCardFIDOAuthenticatorTest : public testing::Test {
/*pref_service=*/autofill_client_.GetPrefs(),
/*local_state=*/autofill_client_.GetPrefs(),
/*identity_manager=*/nullptr,
- /*client_profile_validator=*/nullptr,
/*history_service=*/nullptr,
/*strike_database=*/nullptr,
/*image_fetcher=*/nullptr,
@@ -274,7 +273,7 @@ TEST_F(CreditCardFIDOAuthenticatorTest, IsUserOptedIn_True) {
EXPECT_TRUE(fido_authenticator_->IsUserOptedIn());
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
TEST_F(CreditCardFIDOAuthenticatorTest,
GetUserOptInIntention_IntentToOptIn_Android) {
scoped_feature_list_.InitAndEnableFeature(
@@ -624,7 +623,7 @@ TEST_F(CreditCardFIDOAuthenticatorTest,
AutofillMetrics::WebauthnOptInParameters::kWithCreationChallenge, 1);
}
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
// This test is not applicable for Android (we won't opt-in with Register).
TEST_F(CreditCardFIDOAuthenticatorTest,
Register_OptInAttemptReturnsRequestOptions) {
diff --git a/chromium/components/autofill/core/browser/payments/credit_card_otp_authenticator.cc b/chromium/components/autofill/core/browser/payments/credit_card_otp_authenticator.cc
index cd4b6e7f06f..022ce0acf17 100644
--- a/chromium/components/autofill/core/browser/payments/credit_card_otp_authenticator.cc
+++ b/chromium/components/autofill/core/browser/payments/credit_card_otp_authenticator.cc
@@ -144,8 +144,8 @@ void CreditCardOtpAuthenticator::OnDidSelectChallengeOption(
}
bool server_success = result == AutofillClient::PaymentsRpcResult::kSuccess;
- // Dismiss the pending authentication selection dialog so that other dialogs
- // can be shown.
+ // Dismiss the pending authentication selection dialog if it is visible so
+ // that other dialogs can be shown.
autofill_client_->DismissUnmaskAuthenticatorSelectionDialog(server_success);
if (server_success) {
DCHECK(!context_token.empty());
@@ -156,6 +156,11 @@ void CreditCardOtpAuthenticator::OnDidSelectChallengeOption(
return;
}
+ // If the OTP input dialog is visible, also dismiss it. The two dialogs will
+ // not be shown at the same time but either one of them can be visible when
+ // this function is invoked.
+ autofill_client_->OnUnmaskOtpVerificationResult(
+ OtpUnmaskResult::kPermanentFailure);
// Show the virtual card permanent error dialog if server explicitly returned
// vcn permanent error, show temporary error dialog for the rest failure cases
// since currently only virtual card is supported.
diff --git a/chromium/components/autofill/core/browser/payments/credit_card_otp_authenticator_unittest.cc b/chromium/components/autofill/core/browser/payments/credit_card_otp_authenticator_unittest.cc
index 11fe19d16bf..ab7e2270b60 100644
--- a/chromium/components/autofill/core/browser/payments/credit_card_otp_authenticator_unittest.cc
+++ b/chromium/components/autofill/core/browser/payments/credit_card_otp_authenticator_unittest.cc
@@ -39,7 +39,6 @@ class CreditCardOtpAuthenticatorTest : public testing::Test {
/*pref_service=*/autofill_client_.GetPrefs(),
/*local_state=*/autofill_client_.GetPrefs(),
/*identity_manager=*/nullptr,
- /*client_profile_validator=*/nullptr,
/*history_service=*/nullptr,
/*strike_database=*/nullptr,
/*image_fetcher=*/nullptr,
diff --git a/chromium/components/autofill/core/browser/payments/credit_card_save_manager.cc b/chromium/components/autofill/core/browser/payments/credit_card_save_manager.cc
index 8898ed45d72..7c3846fa4c2 100644
--- a/chromium/components/autofill/core/browser/payments/credit_card_save_manager.cc
+++ b/chromium/components/autofill/core/browser/payments/credit_card_save_manager.cc
@@ -35,6 +35,7 @@
#include "components/autofill/core/browser/metrics/autofill_metrics.h"
#include "components/autofill/core/browser/payments/payments_client.h"
#include "components/autofill/core/browser/payments/payments_util.h"
+#include "components/autofill/core/browser/payments/virtual_card_enrollment_manager.h"
#include "components/autofill/core/browser/personal_data_manager.h"
#include "components/autofill/core/browser/strike_database.h"
#include "components/autofill/core/browser/validation.h"
@@ -50,7 +51,7 @@
#include "components/signin/public/identity_manager/identity_manager.h"
#include "url/gurl.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "components/messages/android/messages_feature.h"
#endif
@@ -91,8 +92,7 @@ CreditCardSaveManager::CreditCardSaveManager(
: client_(client),
payments_client_(payments_client),
app_locale_(app_locale),
- personal_data_manager_(personal_data_manager) {
-}
+ personal_data_manager_(personal_data_manager) {}
CreditCardSaveManager::~CreditCardSaveManager() = default;
@@ -219,7 +219,7 @@ void CreditCardSaveManager::AttemptToOfferCardUploadSave(
DetectedValue::USER_PROVIDED_EXPIRATION_DATE) {
upload_decision_metrics_ |=
AutofillMetrics::USER_REQUESTED_TO_PROVIDE_EXPIRATION_DATE;
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
// iOS should always provide a valid expiration date when attempting to
// upload a Saved Card. Calling LogSaveCardRequestExpirationDateReasonMetric
// would trigger a DCHECK.
@@ -234,7 +234,7 @@ void CreditCardSaveManager::AttemptToOfferCardUploadSave(
should_request_expiration_date_from_user_ = true;
}
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
if (base::FeatureList::IsEnabled(
features::kAutofillSaveCardInfobarEditSupport)) {
// iOS's new credit card save dialog requires the user to enter both
@@ -245,7 +245,7 @@ void CreditCardSaveManager::AttemptToOfferCardUploadSave(
should_request_name_from_user_ = false;
should_request_expiration_date_from_user_ = false;
}
-#endif // defined(OS_IOS)
+#endif // BUILDFLAG(IS_IOS)
// The cardholder name and expiration date fix flows cannot both be
// active at the same time. If they are, abort offering upload.
@@ -288,17 +288,18 @@ void CreditCardSaveManager::AttemptToOfferCardUploadSave(
base::BindOnce(&CreditCardSaveManager::OnDidGetUploadDetails,
weak_ptr_factory_.GetWeakPtr()),
payments::kUploadCardBillableServiceNumber,
+ payments::GetBillingCustomerId(personal_data_manager_),
payments::PaymentsClient::UploadCardSource::UPSTREAM_CHECKOUT_FLOW);
}
bool CreditCardSaveManager::IsCreditCardUploadEnabled() {
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
// If observer_for_testing_ is set, assume we are in a browsertest and
// credit card upload should be enabled by default.
// TODO(crbug.com/859761): Remove dependency from iOS tests on this behavior.
if (observer_for_testing_)
return true;
-#endif // defined(OS_IOS)
+#endif // BUILDFLAG(IS_IOS)
return ::autofill::IsCreditCardUploadEnabled(
client_->GetPrefs(), client_->GetSyncService(),
personal_data_manager_->GetAccountInfoForPaymentsServer().email,
@@ -308,7 +309,8 @@ bool CreditCardSaveManager::IsCreditCardUploadEnabled() {
void CreditCardSaveManager::OnDidUploadCard(
AutofillClient::PaymentsRpcResult result,
- const std::string& server_id) {
+ const payments::PaymentsClient::UploadCardResponseDetails&
+ upload_card_response_details) {
if (observer_for_testing_)
observer_for_testing_->OnReceivedUploadCardResponse();
@@ -334,6 +336,28 @@ void CreditCardSaveManager::OnDidUploadCard(
// |personal_data_manager_|. PDM uses this information to update the avatar
// button UI.
personal_data_manager_->OnCreditCardSaved(/*is_local_card=*/false);
+
+ if (base::FeatureList::IsEnabled(
+ features::kAutofillEnableUpdateVirtualCardEnrollment)) {
+ // After a card is successfully saved to the server, offer virtual card
+ // enrollment if the card is eligible. |upload_card_response_details| has
+ // fields in the response that will be required for server requests in the
+ // virtual card enrollment flow, so we set them here and start the flow.
+ if (upload_card_response_details.virtual_card_enrollment_state ==
+ CreditCard::VirtualCardEnrollmentState::UNENROLLED_AND_ELIGIBLE) {
+ DCHECK(!upload_card_response_details.card_art_url.is_empty());
+ DCHECK(upload_card_response_details.instrument_id.has_value());
+ raw_ptr<CreditCard> uploaded_card = &upload_request_.card;
+ uploaded_card->set_card_art_url(
+ upload_card_response_details.card_art_url);
+ uploaded_card->set_virtual_card_enrollment_state(
+ upload_card_response_details.virtual_card_enrollment_state);
+ uploaded_card->set_instrument_id(
+ upload_card_response_details.instrument_id.value());
+ client_->GetVirtualCardEnrollmentManager()->OfferVirtualCardEnroll(
+ *uploaded_card, VirtualCardEnrollmentSource::kUpstream);
+ }
+ }
} else if (show_save_prompt_.has_value() && show_save_prompt_.value()) {
// If the upload failed and the bubble was actually shown (NOT just the
// icon), count that as a strike against offering upload in the future.
@@ -361,7 +385,7 @@ CreditCardSaveManager::GetCreditCardSaveStrikeDatabase() {
return credit_card_save_strike_database_.get();
}
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
LocalCardMigrationStrikeDatabase*
CreditCardSaveManager::GetLocalCardMigrationStrikeDatabase() {
if (local_card_migration_strike_database_.get() == nullptr) {
@@ -371,7 +395,7 @@ CreditCardSaveManager::GetLocalCardMigrationStrikeDatabase() {
}
return local_card_migration_strike_database_.get();
}
-#endif // !defined(OS_ANDROID) && !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
void CreditCardSaveManager::OnDidGetUploadDetails(
AutofillClient::PaymentsRpcResult result,
@@ -450,11 +474,11 @@ void CreditCardSaveManager::OnDidGetUploadDetails(
}
void CreditCardSaveManager::OfferCardLocalSave() {
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
bool is_mobile_build = true;
#else
bool is_mobile_build = false;
-#endif // #if defined(OS_ANDROID) || defined(OS_IOS)
+#endif // #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
// If |show_save_prompt_|'s value is false, desktop builds will still offer
// save in the omnibox without popping-up the bubble. Mobile builds, however,
@@ -483,11 +507,11 @@ void CreditCardSaveManager::OfferCardLocalSave() {
}
void CreditCardSaveManager::OfferCardUploadSave() {
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
bool is_mobile_build = true;
#else
bool is_mobile_build = false;
-#endif // #if defined(OS_ANDROID) || defined(OS_IOS)
+#endif // #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
// If |show_save_prompt_|'s value is false, desktop builds will still offer
// save in the omnibox without popping-up the bubble. Mobile builds, however,
// should not display the offer-to-save infobar at all.
@@ -550,12 +574,12 @@ void CreditCardSaveManager::OnUserDidDecideOnLocalSave(
GetCreditCardSaveStrikeDatabase()->ClearStrikes(
base::UTF16ToUTF8(local_card_save_candidate_.LastFourDigits()));
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
// Clear some local card migration strikes, as there is now a new card
// eligible for migration.
GetLocalCardMigrationStrikeDatabase()->RemoveStrikes(
LocalCardMigrationStrikeDatabase::kStrikesToRemoveWhenLocalCardAdded);
-#endif // !defined(OS_ANDROID) && !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
personal_data_manager_->OnAcceptedLocalCreditCardSave(
local_card_save_candidate_);
@@ -790,13 +814,13 @@ int CreditCardSaveManager::GetDetectedValues() const {
// On iOS if the new Infobar UI is enabled, it won't be possible to save the
// card unless the user provides both a valid cardholder name and expiration
// date.
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
if (base::FeatureList::IsEnabled(
features::kAutofillSaveCardInfobarEditSupport)) {
detected_values |= DetectedValue::USER_PROVIDED_NAME;
detected_values |= DetectedValue::USER_PROVIDED_EXPIRATION_DATE;
}
-#endif // defined(OS_IOS)
+#endif // BUILDFLAG(IS_IOS)
return detected_values;
}
@@ -807,14 +831,14 @@ void CreditCardSaveManager::OnUserDidDecideOnUploadSave(
switch (user_decision) {
case AutofillClient::SaveCardOfferUserDecision::kAccepted:
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
if (messages::IsSaveCardMessagesUiEnabled()) {
OnUserDidAcceptUploadHelper(user_provided_card_details);
break;
}
#endif
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
// On mobile, requesting cardholder name is a two step flow.
if (should_request_name_from_user_) {
client_->ConfirmAccountNameFixFlow(base::BindOnce(
@@ -832,7 +856,7 @@ void CreditCardSaveManager::OnUserDidDecideOnUploadSave(
}
#else
OnUserDidAcceptUploadHelper(user_provided_card_details);
-#endif // defined(OS_ANDROID) || defined(OS_IOS)
+#endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
break;
case AutofillClient::SaveCardOfferUserDecision::kDeclined:
@@ -844,7 +868,7 @@ void CreditCardSaveManager::OnUserDidDecideOnUploadSave(
personal_data_manager_->OnUserAcceptedUpstreamOffer();
}
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
void CreditCardSaveManager::OnUserDidAcceptAccountNameFixFlow(
const std::u16string& cardholder_name) {
DCHECK(should_request_name_from_user_);
@@ -860,7 +884,7 @@ void CreditCardSaveManager::OnUserDidAcceptExpirationDateFixFlow(
OnUserDidAcceptUploadHelper(
{/*cardholder_name=*/std::u16string(), month, year});
}
-#endif // defined(OS_ANDROID) || defined(OS_IOS)
+#endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
void CreditCardSaveManager::OnUserDidAcceptUploadHelper(
const AutofillClient::UserProvidedCardDetails& user_provided_card_details) {
@@ -869,7 +893,7 @@ void CreditCardSaveManager::OnUserDidAcceptUploadHelper(
// that it is possible a name already existed on the card if conflicting names
// were found, which this intentionally overwrites.)
if (!user_provided_card_details.cardholder_name.empty()) {
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
// On iOS if the new Infobar UI is enabled, cardholder name was provided by
// the user, but not through the fix flow triggered via
// |should_request_name_from_user_|.
@@ -889,7 +913,7 @@ void CreditCardSaveManager::OnUserDidAcceptUploadHelper(
// the expiration date on |upload_request_.card| with the selected date.
if (!user_provided_card_details.expiration_date_month.empty() &&
!user_provided_card_details.expiration_date_year.empty()) {
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
// On iOS if the new Infobar UI is enabled, expiration date was provided by
// the user, but not through the fix flow triggered via
// |should_request_expiration_date_from_user_|.
diff --git a/chromium/components/autofill/core/browser/payments/credit_card_save_manager.h b/chromium/components/autofill/core/browser/payments/credit_card_save_manager.h
index 43c437029e5..eb36d6a97b4 100644
--- a/chromium/components/autofill/core/browser/payments/credit_card_save_manager.h
+++ b/chromium/components/autofill/core/browser/payments/credit_card_save_manager.h
@@ -152,8 +152,10 @@ class CreditCardSaveManager {
// |AutofillClient::PaymentsRpcResult::kSuccess|, clears strikes for the saved
// card. Additionally, |server_id| may, optionally, contain the opaque
// identifier for the card on the server. Exposed for testing.
- virtual void OnDidUploadCard(AutofillClient::PaymentsRpcResult result,
- const std::string& server_id);
+ virtual void OnDidUploadCard(
+ AutofillClient::PaymentsRpcResult result,
+ const payments::PaymentsClient::UploadCardResponseDetails&
+ upload_card_response_details);
private:
friend class CreditCardSaveManagerTest;
@@ -174,10 +176,10 @@ class CreditCardSaveManager {
// Returns the CreditCardSaveStrikeDatabase for |client_|.
CreditCardSaveStrikeDatabase* GetCreditCardSaveStrikeDatabase();
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
// Returns the GetLocalCardMigrationStrikeDatabase for |client_|.
LocalCardMigrationStrikeDatabase* GetLocalCardMigrationStrikeDatabase();
-#endif // !defined(OS_ANDROID) && !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
// Returns the legal message retrieved from Payments. On failure or not
// meeting Payments's conditions for upload, |legal_message| will contain
@@ -240,7 +242,7 @@ class CreditCardSaveManager {
const AutofillClient::UserProvidedCardDetails&
user_provided_card_details);
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
// Upload the card details with the user provided cardholder_name.
// Only relevant for mobile as fix flow is two steps on mobile compared to
// one step on desktop.
@@ -251,7 +253,7 @@ class CreditCardSaveManager {
// to one step on desktop.
void OnUserDidAcceptExpirationDateFixFlow(const std::u16string& month,
const std::u16string& year);
-#endif // defined(OS_ANDROID) || defined(OS_IOS)
+#endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
// Helper function that calls SendUploadCardRequest by setting
// UserProvidedCardDetails.
@@ -376,10 +378,10 @@ class CreditCardSaveManager {
// card.
std::vector<AutofillProfile> preliminarily_imported_address_profiles_;
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
std::unique_ptr<LocalCardMigrationStrikeDatabase>
local_card_migration_strike_database_;
-#endif // !defined(OS_ANDROID) && !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
// May be null.
raw_ptr<ObserverForTest> observer_for_testing_ = nullptr;
diff --git a/chromium/components/autofill/core/browser/payments/credit_card_save_manager_unittest.cc b/chromium/components/autofill/core/browser/payments/credit_card_save_manager_unittest.cc
index 7a62f2751bc..3eb059028cf 100644
--- a/chromium/components/autofill/core/browser/payments/credit_card_save_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/payments/credit_card_save_manager_unittest.cc
@@ -31,6 +31,7 @@
#include "components/autofill/core/browser/data_model/credit_card.h"
#include "components/autofill/core/browser/metrics/autofill_metrics.h"
#include "components/autofill/core/browser/payments/payments_customer_data.h"
+#include "components/autofill/core/browser/payments/payments_util.h"
#include "components/autofill/core/browser/payments/test_credit_card_save_manager.h"
#include "components/autofill/core/browser/payments/test_credit_card_save_strike_database.h"
#include "components/autofill/core/browser/payments/test_payments_client.h"
@@ -73,9 +74,11 @@ namespace {
using UkmCardUploadDecisionType = ukm::builders::Autofill_CardUploadDecision;
using UkmDeveloperEngagementType = ukm::builders::Autofill_DeveloperEngagement;
+#if !BUILDFLAG(IS_IOS)
// time_t representation of 9th Sep, 2001 01:46:40 GMT
-const base::Time kArbitraryTime = base::Time::FromTimeT(1000000000);
-const base::Time kMuchLaterTime = base::Time::FromTimeT(1234567890);
+constexpr base::Time kArbitraryTime = base::Time::FromTimeT(1000000000);
+constexpr base::Time kMuchLaterTime = base::Time::FromTimeT(1234567890);
+#endif
// Used to configure form for |CreateTestCreditCardFormData|.
struct CreditCardFormOptions {
@@ -127,12 +130,12 @@ class CreditCardSaveManagerTest : public testing::Test {
std::make_unique<TestStrikeDatabase>();
strike_database_ = test_strike_database.get();
autofill_client_.set_test_strike_database(std::move(test_strike_database));
+ personal_data_.set_auto_accept_address_imports_for_testing(true);
personal_data_.Init(/*profile_database=*/database_,
/*account_database=*/nullptr,
/*pref_service=*/autofill_client_.GetPrefs(),
/*local_state=*/autofill_client_.GetPrefs(),
/*identity_manager=*/nullptr,
- /*client_profile_validator=*/nullptr,
/*history_service=*/nullptr,
/*strike_database=*/nullptr,
/*image_fetcher=*/nullptr,
@@ -344,6 +347,7 @@ class CreditCardSaveManagerTest : public testing::Test {
scoped_refptr<AutofillWebDataService> database_;
MockPersonalDataManager personal_data_;
syncer::TestSyncService sync_service_;
+ // TODO(crbug.com/1291003): Refactor to use the real CreditCardSaveManager.
// Ends up getting owned (and destroyed) by TestFormDataImporter:
raw_ptr<TestCreditCardSaveManager> credit_card_save_manager_;
// Ends up getting owned (and destroyed) by TestAutofillClient:
@@ -364,7 +368,7 @@ class CreditCardSaveManagerTest : public testing::Test {
// Tests that credit card data are saved for forms on https
// TODO(crbug.com/666704): Flaky on android_n5x_swarming_rel bot.
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#define MAYBE_ImportFormDataCreditCardHTTPS \
DISABLED_ImportFormDataCreditCardHTTPS
#else
@@ -377,7 +381,7 @@ TEST_F(CreditCardSaveManagerTest, MAYBE_ImportFormDataCreditCardHTTPS) {
// Tests that credit card data are saved for forms on http
// TODO(crbug.com/666704): Flaky on android_n5x_swarming_rel bot.
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#define MAYBE_ImportFormDataCreditCardHTTP DISABLED_ImportFormDataCreditCardHTTP
#else
#define MAYBE_ImportFormDataCreditCardHTTP ImportFormDataCreditCardHTTP
@@ -389,7 +393,7 @@ TEST_F(CreditCardSaveManagerTest, MAYBE_ImportFormDataCreditCardHTTP) {
// Tests that credit card data are saved when autocomplete=off for CC field.
// TODO(crbug.com/666704): Flaky on android_n5x_swarming_rel bot.
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#define MAYBE_CreditCardSavedWhenAutocompleteOff \
DISABLED_CreditCardSavedWhenAutocompleteOff
#else
@@ -473,7 +477,7 @@ TEST_F(CreditCardSaveManagerTest, CreditCardDisabledDoesNotSave) {
// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest, UploadCreditCard_OnlyCountryInAddresses) {
// Create, fill and submit an address form in order to establish a recent
// profile which can be selected for the upload request.
@@ -676,7 +680,7 @@ TEST_F(CreditCardSaveManagerTest, LocalCreditCard_ExpirationDateMissing) {
// Tests metrics for supporting unfocused card form.
// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest, UploadCreditCard_WithNonFocusableField) {
credit_card_save_manager_->SetCreditCardUploadEnabled(true);
@@ -1099,7 +1103,7 @@ TEST_F(CreditCardSaveManagerTest, SaveCreditCardOptions_WithoutDynamicForms) {
// last name can be uploaded.
// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest, UploadCreditCard_FirstAndLastName) {
// Create, fill and submit an address form in order to establish a recent
// profile which can be selected for the upload request.
@@ -1155,7 +1159,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_FirstAndLastName) {
// form.
// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest, UploadCreditCard_LastAndFirstName) {
// Create, fill and submit an address form in order to establish a recent
// profile which can be selected for the upload request.
@@ -1234,8 +1238,11 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NotSavedLocally) {
credit_card_save_manager_->SetCreditCardUploadEnabled(true);
- const char* const server_id = "InstrumentData:1234";
- payments_client_->SetServerIdForCardUpload(server_id);
+ payments::PaymentsClient::UploadCardResponseDetails
+ upload_card_response_details;
+ upload_card_response_details.server_id = "InstrumentData:1234";
+ payments_client_->SetUploadCardResponseDetailsForUploadCard(
+ upload_card_response_details);
// Create, fill and submit an address form in order to establish a recent
// profile which can be selected for the upload request.
@@ -1302,7 +1309,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_FeatureNotEnabled) {
// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest, UploadCreditCard_CvcUnavailable) {
// Create, fill and submit an address form in order to establish a recent
// profile which can be selected for the upload request.
@@ -1347,7 +1354,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_CvcUnavailable) {
// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest, UploadCreditCard_CvcInvalidLength) {
// Create, fill and submit an address form in order to establish a recent
// profile which can be selected for the upload request.
@@ -1389,7 +1396,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_CvcInvalidLength) {
// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest, UploadCreditCard_MultipleCvcFields) {
// Create, fill and submit an address form in order to establish a recent
// profile which can be selected for the upload request.
@@ -1448,7 +1455,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_MultipleCvcFields) {
// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoCvcFieldOnForm) {
// Create, fill and submit an address form in order to establish a recent
// profile which can be selected for the upload request.
@@ -1504,7 +1511,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoCvcFieldOnForm) {
// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest,
UploadCreditCard_NoCvcFieldOnForm_InvalidCvcInNonCvcField) {
// Create, fill and submit an address form in order to establish a recent
@@ -1564,7 +1571,7 @@ TEST_F(CreditCardSaveManagerTest,
// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest,
UploadCreditCard_NoCvcFieldOnForm_CvcInNonCvcField) {
// Create, fill and submit an address form in order to establish a recent
@@ -1626,7 +1633,7 @@ TEST_F(CreditCardSaveManagerTest,
// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest,
UploadCreditCard_NoCvcFieldOnForm_CvcInAddressField) {
// Create, fill and submit an address form in order to establish a recent
@@ -1686,7 +1693,7 @@ TEST_F(CreditCardSaveManagerTest,
// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoProfileAvailable) {
// Don't fill or submit an address form.
@@ -1723,7 +1730,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoProfileAvailable) {
// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoRecentlyUsedProfile) {
// Create the test clock and set the time to a specific value.
TestAutofillClock test_clock;
@@ -1774,7 +1781,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoRecentlyUsedProfile) {
// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest,
UploadCreditCard_CvcUnavailableAndNoProfileAvailable) {
// Don't fill or submit an address form.
@@ -1814,7 +1821,7 @@ TEST_F(CreditCardSaveManagerTest,
// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoNameAvailable) {
// Create, fill and submit an address form in order to establish a recent
// profile which can be selected for the upload request.
@@ -1861,7 +1868,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoNameAvailable) {
// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest,
UploadCreditCard_NoNameAvailableAndNoProfileAvailable) {
// Don't fill or submit an address form.
@@ -1905,7 +1912,7 @@ TEST_F(CreditCardSaveManagerTest,
// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest, UploadCreditCard_ZipCodesConflict) {
// Create, fill and submit two address forms with different zip codes.
FormData address_form1, address_form2;
@@ -1958,7 +1965,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_ZipCodesConflict) {
// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest,
UploadCreditCard_ZipCodesDoNotDiscardWhitespace) {
// Create two separate profiles with different zip codes. Must directly add
@@ -2010,7 +2017,7 @@ TEST_F(CreditCardSaveManagerTest,
// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest, UploadCreditCard_ZipCodesHavePrefixMatch) {
// Create, fill and submit two address forms with different zip codes.
FormData address_form1, address_form2;
@@ -2057,7 +2064,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_ZipCodesHavePrefixMatch) {
// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoZipCodeAvailable) {
// Create, fill and submit an address form in order to establish a recent
// profile which can be selected for the upload request.
@@ -2106,7 +2113,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoZipCodeAvailable) {
// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest, UploadCreditCard_CCFormHasMiddleInitial) {
// Create, fill and submit two address forms with different names.
FormData address_form1, address_form2;
@@ -2152,7 +2159,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_CCFormHasMiddleInitial) {
// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoMiddleInitialInCCForm) {
// Create, fill and submit two address forms with different names.
FormData address_form1, address_form2;
@@ -2195,7 +2202,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoMiddleInitialInCCForm) {
// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest,
UploadCreditCard_CCFormHasCardholderMiddleName) {
// Create, fill and submit address form without middle name.
@@ -2242,7 +2249,7 @@ TEST_F(CreditCardSaveManagerTest,
// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest, UploadCreditCard_CCFormHasAddressMiddleName) {
// Create, fill and submit address form with middle name.
FormData address_form;
@@ -2288,7 +2295,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_CCFormHasAddressMiddleName) {
// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NamesCanMismatch) {
// Create, fill and submit two address forms with different names.
FormData address_form1, address_form2;
@@ -2343,7 +2350,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NamesCanMismatch) {
// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest, UploadCreditCard_IgnoreOldProfiles) {
// Create the test clock and set the time to a specific value.
TestAutofillClock test_clock;
@@ -2541,7 +2548,7 @@ TEST_F(
UploadCreditCard_DoNotRequestCardholderNameIfNameExistsAndNoPaymentsCustomer) {
// On iOS the cardholder name fix flow and expiration date fix flow no longer
// apply since the user is forced to always set correct data before submitting.
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
// Create, fill and submit an address form in order to establish a recent
// profile which can be selected for the upload request.
FormData address_form;
@@ -2584,7 +2591,7 @@ TEST_F(
// On iOS the cardholder name fix flow and expiration date fix flow no longer
// apply since the user is forced to always set correct data before
// submitting.
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
// Set the billing_customer_number to designate existence of a Payments
// account.
personal_data_.SetPaymentsCustomerData(
@@ -2634,7 +2641,7 @@ TEST_F(
// On iOS the cardholder name fix flow and expiration date fix flow no longer
// apply since the user is forced to always set correct data before
// submitting.
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
// Set the billing_customer_number to designate existence of a Payments
// account.
personal_data_.SetPaymentsCustomerData(
@@ -2686,7 +2693,7 @@ TEST_F(
// On iOS the cardholder name fix flow and expiration date fix flow no longer
// apply since the user is forced to always set correct data before
// submitting.
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
// Create, fill and submit an address form in order to establish a recent
// profile which can be selected for the upload request.
FormData address_form;
@@ -2740,7 +2747,7 @@ TEST_F(
// On iOS the cardholder name fix flow and expiration date fix flow no longer
// apply since the user is forced to always set correct data before
// submitting.
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
// Create, fill and submit an address form in order to establish a recent
// profile which can be selected for the upload request.
FormData address_form;
@@ -2793,7 +2800,7 @@ TEST_F(
// On iOS the cardholder name fix flow and expiration date fix flow no longer
// apply since the user is forced to always set correct data before
// submitting.
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
// Wallet Sync Transport is enabled.
personal_data_.SetSyncAndSignInState(
AutofillSyncSigninState::kSignedInAndWalletSyncTransportEnabled);
@@ -2835,7 +2842,7 @@ TEST_F(
// On iOS the cardholder name fix flow and expiration date fix flow no longer
// apply since the user is forced to always set correct data before
// submitting.
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
// Wallet Sync Transport is not enabled.
personal_data_.SetSyncAndSignInState(
AutofillSyncSigninState::kSignedInAndSyncFeatureEnabled);
@@ -2878,7 +2885,7 @@ TEST_F(
// On iOS the cardholder name fix flow and expiration date fix flow no longer
// apply since the user is forced to always set correct data before
// submitting.
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
// Create, fill and submit an address form in order to establish a recent
// profile which can be selected for the upload request.
FormData address_form;
@@ -2912,7 +2919,7 @@ TEST_F(
// upload a Saved Card due to the Messages SaveCard modal.
TEST_F(CreditCardSaveManagerTest,
UploadCreditCard_AlwaysRequestCardholderNameAndExpirationDateOnIOS) {
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
// Create, fill and submit an address form in order to establish a recent
// profile which can be selected for the upload request.
FormData address_form;
@@ -2949,7 +2956,7 @@ TEST_F(CreditCardSaveManagerTest,
TEST_F(CreditCardSaveManagerTest,
UploadCreditCard_RequestExpirationDateViaExpDateFixFlow) {
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
// iOS should always provide a valid expiration date when attempting to
// upload a Saved Card due to the Messages SaveCard modal. The manager
// shouldn't handle expired dates.
@@ -3000,7 +3007,7 @@ TEST_F(CreditCardSaveManagerTest,
TEST_F(CreditCardSaveManagerTest,
UploadCreditCard_RequestExpirationDateIfOnlyMonthMissing) {
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
// iOS should always provide a valid expiration date when attempting to
// upload a Saved Card due to the Messages SaveCard modal. The manager
// shouldn't handle expired dates.
@@ -3051,7 +3058,7 @@ TEST_F(CreditCardSaveManagerTest,
TEST_F(CreditCardSaveManagerTest,
UploadCreditCard_RequestExpirationDateIfOnlyYearMissing) {
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
// iOS should always provide a valid expiration date when attempting to
// upload a Saved Card due to the Messages SaveCard modal. The manager
// shouldn't handle expired dates.
@@ -3102,7 +3109,7 @@ TEST_F(CreditCardSaveManagerTest,
TEST_F(CreditCardSaveManagerTest,
UploadCreditCard_RequestExpirationDateIfExpirationDateInputIsExpired) {
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
// iOS should always provide a valid expiration date when attempting to
// upload a Saved Card due to the Messages SaveCard modal. The manager
// shouldn't handle expired dates.
@@ -3154,7 +3161,7 @@ TEST_F(CreditCardSaveManagerTest,
TEST_F(
CreditCardSaveManagerTest,
UploadCreditCard_RequestExpirationDateIfExpirationDateInputIsTwoDigitAndExpired) {
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
// iOS should always provide a valid expiration date when attempting to
// upload a Saved Card due to the Messages SaveCard modal. The manager
// shouldn't handle expired dates.
@@ -3205,7 +3212,7 @@ TEST_F(
// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest, UploadCreditCard_UploadDetailsFails) {
// Anything other than "en-US" will cause GetUploadDetails to return a failure
// response.
@@ -3773,7 +3780,7 @@ TEST_F(CreditCardSaveManagerTest, DetectAddressComponentsAcrossProfiles) {
// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest,
UploadCreditCard_LogAdditionalErrorsWithUploadDetailsFailure) {
// Anything other than "en-US" will cause GetUploadDetails to return a failure
@@ -3959,7 +3966,7 @@ TEST_F(
// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest,
UploadCreditCard_PaymentsDecidesOfferToSaveIfNoCvc) {
// Create, fill and submit an address form in order to establish a recent
@@ -4005,7 +4012,7 @@ TEST_F(CreditCardSaveManagerTest,
// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest,
UploadCreditCard_PaymentsDecidesOfferToSaveIfNoName) {
// Create, fill and submit an address form in order to establish a recent
@@ -4057,7 +4064,7 @@ TEST_F(CreditCardSaveManagerTest,
// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest,
UploadCreditCard_PaymentsDecidesOfferToSaveIfConflictingNames) {
// Create, fill and submit an address form in order to establish a recent
@@ -4108,7 +4115,7 @@ TEST_F(CreditCardSaveManagerTest,
// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest,
UploadCreditCard_PaymentsDecidesOfferToSaveIfNoZip) {
// Set up a new address profile without a postal code.
@@ -4156,7 +4163,7 @@ TEST_F(CreditCardSaveManagerTest,
// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest,
UploadCreditCard_PaymentsDecidesOfferToSaveIfConflictingZips) {
// Set up two new address profiles with conflicting postal codes.
@@ -4214,7 +4221,7 @@ TEST_F(CreditCardSaveManagerTest,
// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
TEST_F(CreditCardSaveManagerTest,
UploadCreditCard_PaymentsDecidesOfferToSaveIfNothingFound) {
// Set up a new address profile without a name or postal code.
@@ -4442,7 +4449,7 @@ TEST_F(CreditCardSaveManagerTest,
}
TEST_F(CreditCardSaveManagerTest,
- UploadCreditCard_ShouldAddUploadCardBillableServiceNumberInRequest) {
+ UploadCreditCard_ShouldAddBillableServiceNumberInRequest) {
// Create, fill and submit an address form in order to establish a recent
// profile which can be selected for the upload request.
FormData address_form;
@@ -4471,6 +4478,39 @@ TEST_F(CreditCardSaveManagerTest,
}
TEST_F(CreditCardSaveManagerTest,
+ UploadCreditCard_ShouldAddBillingCustomerNumberInRequest) {
+ // Set the billing_customer_number to designate existence of a Payments
+ // account.
+ personal_data_.SetPaymentsCustomerData(
+ std::make_unique<PaymentsCustomerData>(/*customer_id=*/"123456"));
+
+ // Create, fill and submit an address form in order to establish a recent
+ // profile which can be selected for the upload request.
+ FormData address_form;
+ test::CreateTestAddressFormData(&address_form);
+ FormsSeen(std::vector<FormData>(1, address_form));
+ ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
+ FormSubmitted(address_form);
+
+ // Set up our credit card form data.
+ FormData credit_card_form;
+ CreateTestCreditCardFormData(&credit_card_form, CreditCardFormOptions());
+ FormsSeen(std::vector<FormData>(1, credit_card_form));
+
+ // Edit the data, and submit.
+ credit_card_form.fields[0].value = u"Flo Master";
+ credit_card_form.fields[1].value = u"4111111111111111";
+ credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
+ credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
+ credit_card_form.fields[4].value = u"123";
+
+ // Confirm that the preflight request contained billing customer number in the
+ // request.
+ FormSubmitted(credit_card_form);
+ EXPECT_EQ(123456L, payments_client_->billing_customer_number_in_request());
+}
+
+TEST_F(CreditCardSaveManagerTest,
UploadCreditCard_ShouldAddUploadCardSourceInRequest) {
// Create, fill and submit an address form in order to establish a recent
// profile which can be selected for the upload request.
@@ -4587,7 +4627,7 @@ TEST_F(CreditCardSaveManagerTest,
"Autofill.StrikeDatabase.CreditCardSaveNotOfferedDueToMaxStrikes", 0);
}
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
// Tests that a card with max strikes does not offer save on mobile at all.
TEST_F(CreditCardSaveManagerTest,
LocallySaveCreditCard_MaxStrikesDisallowsSave) {
@@ -4629,7 +4669,7 @@ TEST_F(CreditCardSaveManagerTest,
// TODO(crbug.com/1113034): Create an equivalent test for iOS, or skip
// permanently if the test doesn't apply to iOS flow.
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
// Tests that a card with max strikes does not offer save on mobile at all.
TEST_F(CreditCardSaveManagerTest, UploadCreditCard_MaxStrikesDisallowsSave) {
TestCreditCardSaveStrikeDatabase credit_card_save_strike_database =
@@ -4684,7 +4724,7 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_MaxStrikesDisallowsSave) {
}
#endif
-#else // !defined(OS_ANDROID) && !defined(OS_IOS)
+#else // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
// Tests that a card with max strikes should still offer to save on Desktop via
// the omnibox icon, but that the offer-to-save bubble itself is not shown.
TEST_F(CreditCardSaveManagerTest,
@@ -5035,8 +5075,11 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NumStrikesLoggedOnAdd) {
// bubble is shown.
TEST_F(CreditCardSaveManagerTest,
UploadCreditCard_NumStrikesLoggedOnUploadNotSuccess) {
- const char* const server_id = "InstrumentData:1234";
- payments_client_->SetServerIdForCardUpload(server_id);
+ payments::PaymentsClient::UploadCardResponseDetails
+ upload_card_response_details;
+ upload_card_response_details.server_id = "InstrumentData:1234";
+ payments_client_->SetUploadCardResponseDetailsForUploadCard(
+ upload_card_response_details);
TestCreditCardSaveStrikeDatabase credit_card_save_strike_database =
TestCreditCardSaveStrikeDatabase(strike_database_);
EXPECT_EQ(0, credit_card_save_strike_database.GetStrikes("1111"));
@@ -5047,7 +5090,8 @@ TEST_F(CreditCardSaveManagerTest,
credit_card_save_manager_->set_upload_request_card_number(
u"4111111111111111");
credit_card_save_manager_->OnDidUploadCard(
- AutofillClient::PaymentsRpcResult::kTryAgainFailure, server_id);
+ AutofillClient::PaymentsRpcResult::kTryAgainFailure,
+ upload_card_response_details);
EXPECT_EQ(1, credit_card_save_strike_database.GetStrikes("1111"));
}
@@ -5182,4 +5226,57 @@ TEST_F(CreditCardSaveManagerTest, InvalidLegalMessageInOnDidGetUploadDetails) {
AutofillMetrics::UPLOAD_NOT_OFFERED_INVALID_LEGAL_MESSAGE);
}
+// Tests that the fields in the card are set correctly and virtual card
+// enrollment is offered when a card becomes eligible after upload.
+TEST_F(CreditCardSaveManagerTest, OnDidUploadCard_VirtualCardEnrollment) {
+ for (CreditCard::VirtualCardEnrollmentState enrollment_state :
+ {CreditCard::VirtualCardEnrollmentState::UNENROLLED,
+ CreditCard::VirtualCardEnrollmentState::UNENROLLED_AND_ELIGIBLE,
+ CreditCard::VirtualCardEnrollmentState::ENROLLED}) {
+ for (bool is_update_virtual_card_enrollment_enabled : {true, false}) {
+ base::test::ScopedFeatureList feature_list;
+ if (is_update_virtual_card_enrollment_enabled) {
+ feature_list.InitAndEnableFeature(
+ features::kAutofillEnableUpdateVirtualCardEnrollment);
+ } else {
+ feature_list.InitAndDisableFeature(
+ features::kAutofillEnableUpdateVirtualCardEnrollment);
+ }
+ payments::PaymentsClient::UploadCardResponseDetails
+ upload_card_response_details;
+ upload_card_response_details.card_art_url =
+ GURL("https://www.example.com/");
+ upload_card_response_details.instrument_id = 9223372036854775807;
+ upload_card_response_details.virtual_card_enrollment_state =
+ enrollment_state;
+
+ credit_card_save_manager_->set_upload_request_card(test::GetCreditCard());
+ credit_card_save_manager_->OnDidUploadCard(
+ AutofillClient::PaymentsRpcResult::kSuccess,
+ upload_card_response_details);
+
+ CreditCard uploaded_card =
+ credit_card_save_manager_->upload_request()->card;
+
+ // The condition inside of this if-statement is true if virtual card
+ // enrollment should be offered.
+ if (is_update_virtual_card_enrollment_enabled &&
+ enrollment_state ==
+ CreditCard::VirtualCardEnrollmentState::UNENROLLED_AND_ELIGIBLE) {
+ EXPECT_EQ(uploaded_card.card_art_url(),
+ upload_card_response_details.card_art_url);
+ EXPECT_EQ(uploaded_card.instrument_id(),
+ upload_card_response_details.instrument_id);
+ EXPECT_EQ(uploaded_card.virtual_card_enrollment_state(),
+ upload_card_response_details.virtual_card_enrollment_state);
+ } else {
+ EXPECT_TRUE(uploaded_card.card_art_url().is_empty());
+ EXPECT_EQ(uploaded_card.instrument_id(), 0);
+ EXPECT_EQ(uploaded_card.virtual_card_enrollment_state(),
+ CreditCard::VirtualCardEnrollmentState::UNSPECIFIED);
+ }
+ }
+ }
+}
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/payments/full_card_request.cc b/chromium/components/autofill/core/browser/payments/full_card_request.cc
index f71c1acb14c..f0bd94ada07 100644
--- a/chromium/components/autofill/core/browser/payments/full_card_request.cc
+++ b/chromium/components/autofill/core/browser/payments/full_card_request.cc
@@ -165,7 +165,7 @@ void FullCardRequest::OnUnmaskPromptAccepted(
}
request_->user_response = user_response;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
if (ui_delegate_) {
// An opt-in request to Payments must be included either if the user chose
// to opt-in through the CVC prompt or if the UI delegate indicates that the
@@ -190,7 +190,7 @@ void FullCardRequest::OnUnmaskPromptClosed() {
bool FullCardRequest::ShouldOfferFidoAuth() const {
// FIDO opt-in is only handled from card unmask on mobile. Desktop platforms
// provide a separate opt-in bubble.
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
return ui_delegate_ && ui_delegate_->ShouldOfferFidoAuth();
#else
return false;
diff --git a/chromium/components/autofill/core/browser/payments/full_card_request.h b/chromium/components/autofill/core/browser/payments/full_card_request.h
index 838dc6f4fdf..e7a0f6a6809 100644
--- a/chromium/components/autofill/core/browser/payments/full_card_request.h
+++ b/chromium/components/autofill/core/browser/payments/full_card_request.h
@@ -81,7 +81,7 @@ class FullCardRequest final : public CardUnmaskDelegate {
virtual void OnUnmaskVerificationResult(
AutofillClient::PaymentsRpcResult result) = 0;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Returns whether or not the user, while on the CVC prompt, should be
// offered to switch to FIDO authentication for card unmasking. This will
// always be false for Desktop since FIDO authentication is offered as a
@@ -130,9 +130,9 @@ class FullCardRequest final : public CardUnmaskDelegate {
// Delegate::OnFullCardRequestFailed(). Only one request should be active at a
// time. |last_committed_url_origin| is the full origin of the url where the
// card retrieval happens. |context_token| is used for providing context of
- // the request to the server to link related
- // requests. |last_committed_url_origin| and |context_token| are populated if
- // the full card request is for a virtual card.
+ // the request to the server to link related requests.
+ // |last_committed_url_origin| and |context_token| are populated if the full
+ // card request is for a virtual card.
//
// If the card is local, has a non-empty GUID, and the user has updated its
// expiration date, then this function will write the new information to
diff --git a/chromium/components/autofill/core/browser/payments/full_card_request_unittest.cc b/chromium/components/autofill/core/browser/payments/full_card_request_unittest.cc
index e8573fbda01..7bc67ca5a8a 100644
--- a/chromium/components/autofill/core/browser/payments/full_card_request_unittest.cc
+++ b/chromium/components/autofill/core/browser/payments/full_card_request_unittest.cc
@@ -65,7 +65,7 @@ class MockUIDelegate : public FullCardRequest::UIDelegate,
OnUnmaskVerificationResult,
(AutofillClient::PaymentsRpcResult),
(override));
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
MOCK_METHOD(bool, ShouldOfferFidoAuth, (), (const override));
MOCK_METHOD(bool,
UserOptedInToFidoFromSettingsPageOnMobile,
diff --git a/chromium/components/autofill/core/browser/payments/legal_message_line.cc b/chromium/components/autofill/core/browser/payments/legal_message_line.cc
index 9eda6187838..84d946d1735 100644
--- a/chromium/components/autofill/core/browser/payments/legal_message_line.cc
+++ b/chromium/components/autofill/core/browser/payments/legal_message_line.cc
@@ -85,8 +85,8 @@ bool LegalMessageLine::Parse(const base::Value& legal_message,
legal_message.FindKeyOfType("line", base::Value::Type::LIST);
if (lines_list) {
LegalMessageLines lines;
- lines.reserve(lines_list->GetList().size());
- for (const base::Value& single_line : lines_list->GetList()) {
+ lines.reserve(lines_list->GetListDeprecated().size());
+ for (const base::Value& single_line : lines_list->GetListDeprecated()) {
lines.emplace_back(LegalMessageLine());
if (!single_line.is_dict() ||
!lines.back().ParseLine(single_line, escape_apostrophes))
@@ -113,7 +113,7 @@ bool LegalMessageLine::ParseLine(const base::Value& line,
line.FindKeyOfType("template_parameter", base::Value::Type::LIST);
if (template_parameters) {
base::Value::ConstListView template_parameters_view =
- template_parameters->GetList();
+ template_parameters->GetListDeprecated();
display_texts.reserve(template_parameters_view.size());
links_.reserve(template_parameters_view.size());
diff --git a/chromium/components/autofill/core/browser/payments/local_card_migration_manager.cc b/chromium/components/autofill/core/browser/payments/local_card_migration_manager.cc
index 47786c94c18..30b27b9ea49 100644
--- a/chromium/components/autofill/core/browser/payments/local_card_migration_manager.cc
+++ b/chromium/components/autofill/core/browser/payments/local_card_migration_manager.cc
@@ -142,6 +142,7 @@ void LocalCardMigrationManager::AttemptToOfferLocalCardMigration(
base::BindOnce(&LocalCardMigrationManager::OnDidGetUploadDetails,
weak_ptr_factory_.GetWeakPtr(), is_from_settings_page),
payments::kMigrateCardsBillableServiceNumber,
+ payments::GetBillingCustomerId(personal_data_manager_),
is_from_settings_page ? payments::PaymentsClient::UploadCardSource::
LOCAL_CARD_MIGRATION_SETTINGS_PAGE
: payments::PaymentsClient::UploadCardSource::
diff --git a/chromium/components/autofill/core/browser/payments/local_card_migration_manager_unittest.cc b/chromium/components/autofill/core/browser/payments/local_card_migration_manager_unittest.cc
index afb288ac830..d1ed735f3f5 100644
--- a/chromium/components/autofill/core/browser/payments/local_card_migration_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/payments/local_card_migration_manager_unittest.cc
@@ -29,6 +29,7 @@
#include "components/autofill/core/browser/data_model/credit_card.h"
#include "components/autofill/core/browser/metrics/autofill_metrics.h"
#include "components/autofill/core/browser/payments/payments_customer_data.h"
+#include "components/autofill/core/browser/payments/payments_util.h"
#include "components/autofill/core/browser/payments/test_credit_card_save_manager.h"
#include "components/autofill/core/browser/payments/test_local_card_migration_manager.h"
#include "components/autofill/core/browser/payments/test_payments_client.h"
@@ -606,6 +607,21 @@ TEST_F(LocalCardMigrationManagerTest,
}
TEST_F(LocalCardMigrationManagerTest,
+ MigrateCreditCard_ShouldAddMigrateCardsBillingCustomerNumberInRequest) {
+ // Set the billing_customer_number to designate existence of a Payments
+ // account.
+ personal_data_.SetPaymentsCustomerData(
+ std::make_unique<PaymentsCustomerData>(/*customer_id=*/"123456"));
+
+ // Use one local card with more valid local cards available.
+ UseLocalCardWithOtherLocalCardsOnFile();
+
+ // Confirm that the preflight request contained
+ // billing customer number in the request.
+ EXPECT_EQ(123456L, payments_client_->billing_customer_number_in_request());
+}
+
+TEST_F(LocalCardMigrationManagerTest,
MigrateCreditCard_ShouldAddUploadCardSourceInRequest_CheckoutFlow) {
// Use one local card with more valid local cards available.
UseLocalCardWithOtherLocalCardsOnFile();
diff --git a/chromium/components/autofill/core/browser/payments/offer_notification_handler.cc b/chromium/components/autofill/core/browser/payments/offer_notification_handler.cc
new file mode 100644
index 00000000000..6a833fe7d2b
--- /dev/null
+++ b/chromium/components/autofill/core/browser/payments/offer_notification_handler.cc
@@ -0,0 +1,79 @@
+// Copyright 2022 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.
+
+#include "components/autofill/core/browser/payments/offer_notification_handler.h"
+
+#include "components/autofill/core/browser/autofill_client.h"
+#include "components/autofill/core/browser/data_model/autofill_offer_data.h"
+#include "components/autofill/core/browser/data_model/credit_card.h"
+#include "components/autofill/core/browser/payments/autofill_offer_manager.h"
+#include "components/autofill/core/common/autofill_payments_features.h"
+
+namespace autofill {
+
+namespace {
+
+bool IsOfferValid(AutofillOfferData* offer) {
+ if (!offer)
+ return false;
+
+ if (offer->merchant_origins.empty())
+ return false;
+
+ if (offer->IsPromoCodeOffer() &&
+ !base::FeatureList::IsEnabled(
+ features::kAutofillEnableOfferNotificationForPromoCodes)) {
+ return false;
+ }
+
+ if (offer->GetOfferType() == AutofillOfferData::OfferType::UNKNOWN)
+ return false;
+
+ return true;
+}
+
+} // namespace
+
+OfferNotificationHandler::OfferNotificationHandler(
+ AutofillOfferManager* offer_manager)
+ : offer_manager_(offer_manager) {}
+
+OfferNotificationHandler::~OfferNotificationHandler() = default;
+
+void OfferNotificationHandler::UpdateOfferNotificationVisibility(
+ AutofillClient* client) {
+ GURL url = client->GetLastCommittedURL();
+ if (!offer_manager_->IsUrlEligible(url)) {
+ client->DismissOfferNotification();
+ return;
+ }
+
+ // Try to show offer notification when the last committed URL has the domain
+ // that an offer is applicable for.
+ // TODO(crbug.com/1203811): GetOfferForUrl needs to know whether to give
+ // precedence to card-linked offers or promo code offers. Eventually, promo
+ // code offers should take precedence if a bubble is shown. Currently, if a
+ // url has both types of offers and the promo code offer is selected, no
+ // bubble will end up being shown (due to not yet being implemented).
+ AutofillOfferData* offer = offer_manager_->GetOfferForUrl(url);
+ if (!IsOfferValid(offer)) {
+ client->DismissOfferNotification();
+ return;
+ }
+
+ client->UpdateOfferNotification(
+ offer, shown_notification_ids_.contains(offer->offer_id));
+ shown_notification_ids_.insert(offer->offer_id);
+}
+
+void OfferNotificationHandler::ClearShownNotificationIdForTesting() {
+ shown_notification_ids_.clear();
+}
+
+void OfferNotificationHandler::AddShownNotificationIdForTesting(
+ int64_t shown_notification_id) {
+ shown_notification_ids_.insert(shown_notification_id);
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/payments/offer_notification_handler.h b/chromium/components/autofill/core/browser/payments/offer_notification_handler.h
new file mode 100644
index 00000000000..8897141a972
--- /dev/null
+++ b/chromium/components/autofill/core/browser/payments/offer_notification_handler.h
@@ -0,0 +1,44 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_OFFER_NOTIFICATION_HANDLER_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_OFFER_NOTIFICATION_HANDLER_H_
+
+#include "base/containers/flat_set.h"
+#include "base/memory/raw_ptr.h"
+
+namespace autofill {
+
+class AutofillClient;
+class AutofillOfferManager;
+
+// The class to handle actions related to the offer notifications. It is owned
+// by the AutofillOfferManager and it is one per browser context.
+class OfferNotificationHandler {
+ public:
+ explicit OfferNotificationHandler(AutofillOfferManager* offer_manager);
+ OfferNotificationHandler(const OfferNotificationHandler&) = delete;
+ OfferNotificationHandler& operator=(const OfferNotificationHandler&) = delete;
+ ~OfferNotificationHandler();
+
+ // Dismisses or updates the offer notification.
+ void UpdateOfferNotificationVisibility(AutofillClient* client);
+
+ // Clears and set the |shown_notification_ids_| set. Only for tests.
+ void ClearShownNotificationIdForTesting();
+ void AddShownNotificationIdForTesting(int64_t shown_notification_id);
+
+ private:
+ // The reference to the offer manager that owns |this|.
+ raw_ptr<AutofillOfferManager> offer_manager_;
+
+ // This set includes the unique id of shown offer notifications in the
+ // current browser context. It serves as a cross-tab status tracker for the
+ // notification UI.
+ base::flat_set<int64_t> shown_notification_ids_;
+};
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_OFFER_NOTIFICATION_HANDLER_H_
diff --git a/chromium/components/autofill/core/browser/payments/payments_client.cc b/chromium/components/autofill/core/browser/payments/payments_client.cc
index d75fe250785..d8735a9e178 100644
--- a/chromium/components/autofill/core/browser/payments/payments_client.cc
+++ b/chromium/components/autofill/core/browser/payments/payments_client.cc
@@ -27,9 +27,11 @@
#include "components/autofill/core/browser/data_model/credit_card.h"
#include "components/autofill/core/browser/payments/account_info_getter.h"
#include "components/autofill/core/browser/payments/local_card_migration_manager.h"
+#include "components/autofill/core/browser/payments/payments_requests/get_details_for_enrollment_request.h"
#include "components/autofill/core/browser/payments/payments_requests/payments_request.h"
#include "components/autofill/core/browser/payments/payments_requests/select_challenge_option_request.h"
#include "components/autofill/core/browser/payments/payments_requests/unmask_card_request.h"
+#include "components/autofill/core/browser/payments/payments_requests/update_virtual_card_enrollment_request.h"
#include "components/autofill/core/browser/payments/payments_service_url.h"
#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/autofill_payments_features.h"
@@ -46,8 +48,7 @@
#include "services/network/public/cpp/simple_url_loader.h"
#include "services/network/public/mojom/url_response_head.mojom.h"
-namespace autofill {
-namespace payments {
+namespace autofill::payments {
namespace {
@@ -138,7 +139,7 @@ base::Value BuildAddressDictionary(const AutofillProfile& profile,
address_lines);
AppendStringIfNotEmpty(profile, ADDRESS_HOME_LINE3, app_locale,
address_lines);
- if (!address_lines.GetList().empty())
+ if (!address_lines.GetListDeprecated().empty())
postal_address.SetKey("address_line", std::move(address_lines));
SetStringIfNotEmpty(profile, ADDRESS_HOME_CITY, app_locale, "locality_name",
@@ -224,7 +225,7 @@ class GetUnmaskDetailsRequest : public PaymentsRequest {
GetUnmaskDetailsRequest(const GetUnmaskDetailsRequest&) = delete;
GetUnmaskDetailsRequest& operator=(const GetUnmaskDetailsRequest&) = delete;
- ~GetUnmaskDetailsRequest() override {}
+ ~GetUnmaskDetailsRequest() override = default;
std::string GetRequestUrlPath() override {
return kGetUnmaskDetailsRequestPath;
@@ -276,7 +277,8 @@ class GetUnmaskDetailsRequest : public PaymentsRequest {
const auto* fido_eligible_card_ids = response.FindKeyOfType(
"fido_eligible_card_id", base::Value::Type::LIST);
if (fido_eligible_card_ids) {
- for (const base::Value& result : fido_eligible_card_ids->GetList()) {
+ for (const base::Value& result :
+ fido_eligible_card_ids->GetListDeprecated()) {
unmask_details_.fido_eligible_card_ids.insert(result.GetString());
}
}
@@ -318,7 +320,7 @@ class OptChangeRequest : public PaymentsRequest {
OptChangeRequest(const OptChangeRequest&) = delete;
OptChangeRequest& operator=(const OptChangeRequest&) = delete;
- ~OptChangeRequest() override {}
+ ~OptChangeRequest() override = default;
std::string GetRequestUrlPath() override { return kOptChangeRequestPath; }
@@ -430,6 +432,7 @@ class GetUploadDetailsRequest : public PaymentsRequest {
std::unique_ptr<base::Value>,
std::vector<std::pair<int, int>>)> callback,
const int billable_service_number,
+ const int64_t billing_customer_number,
PaymentsClient::UploadCardSource upload_card_source)
: addresses_(addresses),
detected_values_(detected_values),
@@ -438,12 +441,13 @@ class GetUploadDetailsRequest : public PaymentsRequest {
app_locale_(app_locale),
callback_(std::move(callback)),
billable_service_number_(billable_service_number),
- upload_card_source_(upload_card_source) {}
+ upload_card_source_(upload_card_source),
+ billing_customer_number_(billing_customer_number) {}
GetUploadDetailsRequest(const GetUploadDetailsRequest&) = delete;
GetUploadDetailsRequest& operator=(const GetUploadDetailsRequest&) = delete;
- ~GetUploadDetailsRequest() override {}
+ ~GetUploadDetailsRequest() override = default;
std::string GetRequestUrlPath() override {
return kGetUploadDetailsRequestPath;
@@ -456,6 +460,12 @@ class GetUploadDetailsRequest : public PaymentsRequest {
base::Value context(base::Value::Type::DICTIONARY);
context.SetKey("language_code", base::Value(app_locale_));
context.SetKey("billable_service", base::Value(billable_service_number_));
+ if (base::FeatureList::IsEnabled(
+ features::kAutofillEnableSendingBcnInGetUploadDetails) &&
+ billing_customer_number_ != 0) {
+ context.SetKey("customer_context",
+ BuildCustomerContextDictionary(billing_customer_number_));
+ }
request_dict.SetKey("context", std::move(context));
base::Value chrome_user_context(base::Value::Type::DICTIONARY);
@@ -563,12 +573,12 @@ class GetUploadDetailsRequest : public PaymentsRequest {
int start;
base::StringToInt(range[0], &start);
if (range.size() == 1) {
- supported_card_bin_ranges.push_back(std::make_pair(start, start));
+ supported_card_bin_ranges.emplace_back(start, start);
} else {
int end;
base::StringToInt(range[1], &end);
DCHECK_LE(start, end);
- supported_card_bin_ranges.push_back(std::make_pair(start, end));
+ supported_card_bin_ranges.emplace_back(start, end);
}
}
return supported_card_bin_ranges;
@@ -589,14 +599,17 @@ class GetUploadDetailsRequest : public PaymentsRequest {
std::vector<std::pair<int, int>> supported_card_bin_ranges_;
const int billable_service_number_;
PaymentsClient::UploadCardSource upload_card_source_;
+ const int64_t billing_customer_number_;
};
class UploadCardRequest : public PaymentsRequest {
public:
- UploadCardRequest(const PaymentsClient::UploadRequestDetails& request_details,
- const bool full_sync_enabled,
- base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
- const std::string&)> callback)
+ UploadCardRequest(
+ const PaymentsClient::UploadRequestDetails& request_details,
+ const bool full_sync_enabled,
+ base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
+ const PaymentsClient::UploadCardResponseDetails&)>
+ callback)
: request_details_(request_details),
full_sync_enabled_(full_sync_enabled),
callback_(std::move(callback)) {}
@@ -604,7 +617,7 @@ class UploadCardRequest : public PaymentsRequest {
UploadCardRequest(const UploadCardRequest&) = delete;
UploadCardRequest& operator=(const UploadCardRequest&) = delete;
- ~UploadCardRequest() override {}
+ ~UploadCardRequest() override = default;
std::string GetRequestUrlPath() override { return kUploadCardRequestPath; }
@@ -692,22 +705,57 @@ class UploadCardRequest : public PaymentsRequest {
void ParseResponse(const base::Value& response) override {
const std::string* credit_card_id =
response.FindStringKey("credit_card_id");
- server_id_ = credit_card_id ? *credit_card_id : std::string();
+ upload_card_response_details_.server_id =
+ credit_card_id ? *credit_card_id : std::string();
+
+ const std::string* response_instrument_id =
+ response.FindStringKey("instrument_id");
+ if (response_instrument_id) {
+ int64_t instrument_id;
+ if (base::StringToInt64(base::StringPiece(*response_instrument_id),
+ &instrument_id)) {
+ upload_card_response_details_.instrument_id = instrument_id;
+ }
+ }
+
+ const auto* virtual_card_metadata = response.FindKeyOfType(
+ "virtual_card_metadata", base::Value::Type::DICTIONARY);
+ if (virtual_card_metadata) {
+ const std::string* virtual_card_enrollment_status =
+ virtual_card_metadata->FindStringKey("status");
+ if (virtual_card_enrollment_status) {
+ if (*virtual_card_enrollment_status == "ENROLLED") {
+ upload_card_response_details_.virtual_card_enrollment_state =
+ CreditCard::VirtualCardEnrollmentState::ENROLLED;
+ } else if (*virtual_card_enrollment_status == "ENROLLMENT_ELIGIBLE") {
+ upload_card_response_details_.virtual_card_enrollment_state =
+ CreditCard::VirtualCardEnrollmentState::UNENROLLED_AND_ELIGIBLE;
+ } else {
+ upload_card_response_details_.virtual_card_enrollment_state =
+ CreditCard::VirtualCardEnrollmentState::
+ UNENROLLED_AND_NOT_ELIGIBLE;
+ }
+ }
+ }
+
+ const std::string* card_art_url = response.FindStringKey("card_art_url");
+ upload_card_response_details_.card_art_url =
+ card_art_url ? GURL(*card_art_url) : GURL();
}
bool IsResponseComplete() override { return true; }
void RespondToDelegate(AutofillClient::PaymentsRpcResult result) override {
- std::move(callback_).Run(result, server_id_);
+ std::move(callback_).Run(result, upload_card_response_details_);
}
private:
const PaymentsClient::UploadRequestDetails request_details_;
const bool full_sync_enabled_;
base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
- const std::string&)>
+ const PaymentsClient::UploadCardResponseDetails&)>
callback_;
- std::string server_id_;
+ PaymentsClient::UploadCardResponseDetails upload_card_response_details_;
};
class MigrateCardsRequest : public PaymentsRequest {
@@ -725,7 +773,7 @@ class MigrateCardsRequest : public PaymentsRequest {
MigrateCardsRequest(const MigrateCardsRequest&) = delete;
MigrateCardsRequest& operator=(const MigrateCardsRequest&) = delete;
- ~MigrateCardsRequest() override {}
+ ~MigrateCardsRequest() override = default;
std::string GetRequestUrlPath() override { return kMigrateCardsRequestPath; }
@@ -791,7 +839,7 @@ class MigrateCardsRequest : public PaymentsRequest {
save_result_ =
std::make_unique<std::unordered_map<std::string, std::string>>();
- for (const base::Value& result : found_list->GetList()) {
+ for (const base::Value& result : found_list->GetListDeprecated()) {
if (result.is_dict()) {
const std::string* unique_id = result.FindStringKey("unique_id");
const std::string* status = result.FindStringKey("status");
@@ -890,8 +938,9 @@ PaymentsClient::UnmaskResponseDetails::UnmaskResponseDetails(
*this = other;
}
PaymentsClient::UnmaskResponseDetails::~UnmaskResponseDetails() = default;
-PaymentsClient::UnmaskResponseDetails& PaymentsClient::UnmaskResponseDetails::
-operator=(const PaymentsClient::UnmaskResponseDetails& other) {
+PaymentsClient::UnmaskResponseDetails&
+PaymentsClient::UnmaskResponseDetails::operator=(
+ const PaymentsClient::UnmaskResponseDetails& other) {
real_pan = other.real_pan;
if (other.fido_creation_options.has_value()) {
fido_creation_options = other.fido_creation_options->Clone();
@@ -960,6 +1009,33 @@ PaymentsClient::SelectChallengeOptionRequestDetails::
PaymentsClient::SelectChallengeOptionRequestDetails::
~SelectChallengeOptionRequestDetails() = default;
+PaymentsClient::GetDetailsForEnrollmentRequestDetails::
+ GetDetailsForEnrollmentRequestDetails() = default;
+PaymentsClient::GetDetailsForEnrollmentRequestDetails::
+ GetDetailsForEnrollmentRequestDetails(
+ const GetDetailsForEnrollmentRequestDetails& other) = default;
+PaymentsClient::GetDetailsForEnrollmentRequestDetails::
+ ~GetDetailsForEnrollmentRequestDetails() = default;
+
+PaymentsClient::GetDetailsForEnrollmentResponseDetails::
+ GetDetailsForEnrollmentResponseDetails() = default;
+PaymentsClient::GetDetailsForEnrollmentResponseDetails::
+ GetDetailsForEnrollmentResponseDetails(
+ const GetDetailsForEnrollmentResponseDetails& other) = default;
+PaymentsClient::GetDetailsForEnrollmentResponseDetails::
+ ~GetDetailsForEnrollmentResponseDetails() = default;
+
+PaymentsClient::UpdateVirtualCardEnrollmentRequestDetails::
+ UpdateVirtualCardEnrollmentRequestDetails() = default;
+PaymentsClient::UpdateVirtualCardEnrollmentRequestDetails::
+ UpdateVirtualCardEnrollmentRequestDetails(
+ const UpdateVirtualCardEnrollmentRequestDetails&) = default;
+PaymentsClient::UpdateVirtualCardEnrollmentRequestDetails&
+PaymentsClient::UpdateVirtualCardEnrollmentRequestDetails::operator=(
+ const UpdateVirtualCardEnrollmentRequestDetails&) = default;
+PaymentsClient::UpdateVirtualCardEnrollmentRequestDetails::
+ ~UpdateVirtualCardEnrollmentRequestDetails() = default;
+
PaymentsClient::PaymentsClient(
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
signin::IdentityManager* identity_manager,
@@ -1020,19 +1096,20 @@ void PaymentsClient::GetUploadDetails(
std::unique_ptr<base::Value>,
std::vector<std::pair<int, int>>)> callback,
const int billable_service_number,
+ const int64_t billing_customer_number,
UploadCardSource upload_card_source) {
- IssueRequest(
- std::make_unique<GetUploadDetailsRequest>(
- addresses, detected_values, active_experiments,
- account_info_getter_->IsSyncFeatureEnabled(), app_locale,
- std::move(callback), billable_service_number, upload_card_source),
- /*authenticate=*/false);
+ IssueRequest(std::make_unique<GetUploadDetailsRequest>(
+ addresses, detected_values, active_experiments,
+ account_info_getter_->IsSyncFeatureEnabled(), app_locale,
+ std::move(callback), billable_service_number,
+ billing_customer_number, upload_card_source),
+ /*authenticate=*/false);
}
void PaymentsClient::UploadCard(
const PaymentsClient::UploadRequestDetails& request_details,
base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
- const std::string&)> callback) {
+ const UploadCardResponseDetails&)> callback) {
IssueRequest(
std::make_unique<UploadCardRequest>(
request_details, account_info_getter_->IsSyncFeatureEnabled(),
@@ -1060,6 +1137,25 @@ void PaymentsClient::SelectChallengeOption(
/*authenticate=*/true);
}
+void PaymentsClient::GetVirtualCardEnrollmentDetails(
+ const GetDetailsForEnrollmentRequestDetails& request_details,
+ base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
+ const payments::PaymentsClient::
+ GetDetailsForEnrollmentResponseDetails&)>
+ callback) {
+ IssueRequest(std::make_unique<GetDetailsForEnrollmentRequest>(
+ request_details, std::move(callback)),
+ /*authenticate=*/true);
+}
+
+void PaymentsClient::UpdateVirtualCardEnrollment(
+ const UpdateVirtualCardEnrollmentRequestDetails& request_details,
+ base::OnceCallback<void(AutofillClient::PaymentsRpcResult)> callback) {
+ IssueRequest(std::make_unique<UpdateVirtualCardEnrollmentRequest>(
+ request_details, std::move(callback)),
+ /*authenticate=*/true);
+}
+
void PaymentsClient::CancelRequest() {
request_.reset();
resource_request_.reset();
@@ -1306,5 +1402,4 @@ void PaymentsClient::StartRequest() {
base::Unretained(this)));
}
-} // namespace payments
-} // namespace autofill
+} // namespace autofill::payments
diff --git a/chromium/components/autofill/core/browser/payments/payments_client.h b/chromium/components/autofill/core/browser/payments/payments_client.h
index e97f9e1645b..dcf49741938 100644
--- a/chromium/components/autofill/core/browser/payments/payments_client.h
+++ b/chromium/components/autofill/core/browser/payments/payments_client.h
@@ -20,6 +20,7 @@
#include "components/autofill/core/browser/data_model/credit_card.h"
#include "components/autofill/core/browser/payments/card_unmask_challenge_option.h"
#include "components/autofill/core/browser/payments/card_unmask_delegate.h"
+#include "components/autofill/core/browser/payments/virtual_card_enrollment_flow.h"
#include "components/signin/public/identity_manager/access_token_fetcher.h"
#include "components/signin/public/identity_manager/access_token_info.h"
#include "google_apis/gaia/google_service_auth_error.h"
@@ -109,7 +110,7 @@ class PaymentsClient {
// An opaque token used to chain consecutive payments requests together.
std::string context_token;
// The url origin of the website where the unmasking happened. Should be
- // populated when the unmasking is for a virtual card.
+ // populated when the unmasking is for a virtual-card.
absl::optional<GURL> last_committed_url_origin;
};
@@ -133,11 +134,11 @@ class PaymentsClient {
std::string real_pan;
std::string dcvv;
// The expiration month of the card. It falls in between 1 - 12. Should be
- // populated when the card is a virtual card which does not necessarily have
+ // populated when the card is a virtual-card which does not necessarily have
// the same expiration date as its related actual card.
std::string expiration_month;
// The four-digit expiration year of the card. Should be populated when the
- // card is a virtual card which does not necessarily have the same
+ // card is a virtual-card which does not necessarily have the same
// expiration date as its related actual card.
std::string expiration_year;
// Challenge required for enrolling user into FIDO authentication for future
@@ -277,6 +278,117 @@ class PaymentsClient {
LOCAL_CARD_MIGRATION_SETTINGS_PAGE,
};
+ // TODO(crbug.com/1285086): Remove the |server_id| field from
+ // UploadCardResponseDetails since it is never used.
+ // A collection of information received in the response for an
+ // UploadCardRequest.
+ struct UploadCardResponseDetails {
+ std::string server_id;
+ // |instrument_id| is used by the server as an identifier for the card that
+ // was uploaded. Currently, we have it in the UploadCardResponseDetails so
+ // that we can send it in the GetDetailsForEnrollRequest in the virtual card
+ // enrollment flow. Will only not be populated in the case of an imperfect
+ // conversion from string to int64_t, or if the server does not return an
+ // instrument id.
+ absl::optional<int64_t> instrument_id;
+ // |virtual_card_enrollment_state| is used to determine whether we want to
+ // pursue further action with the credit card that was uploaded regarding
+ // virtual card enrollment. For example, if the state is
+ // UNENROLLED_AND_ELIGIBLE we might offer the user the option to enroll the
+ // card that was uploaded into virtual card.
+ CreditCard::VirtualCardEnrollmentState virtual_card_enrollment_state =
+ CreditCard::VirtualCardEnrollmentState::UNSPECIFIED;
+ // |card_art_url| is the mapping that would be used by PersonalDataManager
+ // to try to get the card art for the credit card that was uploaded. It is
+ // used in flows where after uploading a card we want to display its card
+ // art. Since chrome sync does not instantly sync the card art with the url,
+ // the actual card art image might not always be present. Flows that use
+ // |card_art_url| need to make sure they handle the case where the image has
+ // not been synced yet. For virtual card eligible cards this should not be
+ // empty. If using this field use DCHECKs to ensure it is populated.
+ GURL card_art_url;
+ };
+
+ // A collection of information needed for the
+ // UpdateVirtualCardEnrollmentRequest.
+ struct UpdateVirtualCardEnrollmentRequestDetails {
+ UpdateVirtualCardEnrollmentRequestDetails();
+ UpdateVirtualCardEnrollmentRequestDetails(
+ const UpdateVirtualCardEnrollmentRequestDetails&);
+ UpdateVirtualCardEnrollmentRequestDetails& operator=(
+ const UpdateVirtualCardEnrollmentRequestDetails&);
+ ~UpdateVirtualCardEnrollmentRequestDetails();
+ // Denotes the source that the corresponding
+ // UpdateVirtualCardEnrollmentRequest for this
+ // UpdateVirtualCardEnrollmentRequestDetails originated from, i.e., a
+ // |virtual_card_enrollment_source| of kUpstream means the request happens
+ // after a user saved a card in the upstream flow.
+ VirtualCardEnrollmentSource virtual_card_enrollment_source =
+ VirtualCardEnrollmentSource::kNone;
+ // Denotes the type of this specific UpdateVirtualCardEnrollmentRequest,
+ // i.e., a type of VirtualCardEnrollmentRequestType::kEnroll would mean this
+ // is an enroll request.
+ VirtualCardEnrollmentRequestType virtual_card_enrollment_request_type =
+ VirtualCardEnrollmentRequestType::kNone;
+ // The billing customer number for the account this request is sent to. If
+ // |billing_customer_number| is non-zero, it means the user has a Google
+ // Payments account.
+ int64_t billing_customer_number = 0;
+ // Populated if it is an unenroll request. |instrument_id| lets the server
+ // know which card to unenroll from VCN.
+ absl::optional<int64_t> instrument_id;
+ // Populated if it is an enroll request. Based on the |vcn_context_token|
+ // the server is able to retrieve the instrument id, and using
+ // |vcn_context_token| for enroll allows the server to link a
+ // GetDetailsForEnroll call with the corresponding Enroll call.
+ absl::optional<std::string> vcn_context_token;
+ };
+
+ // The struct to hold all detailed information to construct a
+ // GetDetailsForEnrollmentRequest.
+ struct GetDetailsForEnrollmentRequestDetails {
+ GetDetailsForEnrollmentRequestDetails();
+ GetDetailsForEnrollmentRequestDetails(
+ const GetDetailsForEnrollmentRequestDetails& other);
+ ~GetDetailsForEnrollmentRequestDetails();
+
+ // The type of the enrollment this request is for.
+ VirtualCardEnrollmentSource source = VirtualCardEnrollmentSource::kNone;
+
+ // |instrument_id| is used by the server to identify a specific card to get
+ // details for.
+ int64_t instrument_id = 0;
+
+ // The billing customer number of the account this request is sent to.
+ int64_t billing_customer_number = 0;
+
+ // |risk_data| contains some fingerprint data for the user and the device.
+ std::string risk_data;
+
+ // |app_locale| is the Chrome locale.
+ std::string app_locale;
+ };
+
+ // A collection of information received in the response for a
+ // GetDetailsForEnrollRequest.
+ struct GetDetailsForEnrollmentResponseDetails {
+ GetDetailsForEnrollmentResponseDetails();
+ GetDetailsForEnrollmentResponseDetails(
+ const GetDetailsForEnrollmentResponseDetails& other);
+ ~GetDetailsForEnrollmentResponseDetails();
+ // |vcn_context_token| is used in the sequential Enroll call, where it
+ // allows the server to get the instrument id for this |vcn_context_token|
+ // and link this specific GetDetailsForEnroll call with its corresponding
+ // enroll call.
+ std::string vcn_context_token;
+ // Google's legal message lines in the virtual-card enroll flow for this
+ // specific card based on |vcn_context_token|.
+ LegalMessageLines google_legal_message;
+ // The issuer's legal message lines in the virtual-card enroll flow for this
+ // specific card based on |vcn_context_token|.
+ LegalMessageLines issuer_legal_message;
+ };
+
// |url_loader_factory| is reference counted so it has no lifetime or
// ownership requirements. |identity_manager| and |account_info_getter| must
// all outlive |this|. Either delegate might be nullptr. |is_off_the_record|
@@ -321,16 +433,17 @@ class PaymentsClient {
// Determine if the user meets the Payments service's conditions for upload.
// The service uses |addresses| (from which names and phone numbers are
- // removed) and |app_locale| to determine which legal message to display.
- // |detected_values| is a bitmask of CreditCardSaveManager::DetectedValue
- // values that relays what data is actually available for upload in order to
- // make more informed upload decisions. |callback| is the callback function
- // when get response from server. |billable_service_number| is used to set the
- // billable service number in the GetUploadDetails request. If the conditions
- // are met, the legal message will be returned via |callback|.
- // |active_experiments| is used by Payments server to track requests that were
- // triggered by enabled features. |upload_card_source| is used by Payments
- // server metrics to track the source of the request.
+ // removed) and |app_locale| and |billing_customer_number| to determine which
+ // legal message to display. |detected_values| is a bitmask of
+ // CreditCardSaveManager::DetectedValue values that relays what data is
+ // actually available for upload in order to make more informed upload
+ // decisions. |callback| is the callback function when get response from
+ // server. |billable_service_number| is used to set the billable service
+ // number in the GetUploadDetails request. If the conditions are met, the
+ // legal message will be returned via |callback|. |active_experiments| is used
+ // by Payments server to track requests that were triggered by enabled
+ // features. |upload_card_source| is used by Payments server metrics to track
+ // the source of the request.
virtual void GetUploadDetails(
const std::vector<AutofillProfile>& addresses,
const int detected_values,
@@ -341,6 +454,7 @@ class PaymentsClient {
std::unique_ptr<base::Value>,
std::vector<std::pair<int, int>>)> callback,
const int billable_service_number,
+ const int64_t billing_customer_number,
UploadCardSource upload_card_source =
UploadCardSource::UNKNOWN_UPLOAD_CARD_SOURCE);
@@ -350,7 +464,8 @@ class PaymentsClient {
virtual void UploadCard(
const UploadRequestDetails& details,
base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
- const std::string&)> callback);
+ const PaymentsClient::UploadCardResponseDetails&)>
+ callback);
// The user has indicated that they would like to migrate their local credit
// cards. This request will fail server-side if a successful call to
@@ -367,6 +482,24 @@ class PaymentsClient {
base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
const std::string&)> callback);
+ // Retrieve information necessary for the enrollment from the server. This is
+ // invoked before we show the bubble to request user consent for the
+ // enrollment.
+ virtual void GetVirtualCardEnrollmentDetails(
+ const GetDetailsForEnrollmentRequestDetails& request_details,
+ base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
+ const payments::PaymentsClient::
+ GetDetailsForEnrollmentResponseDetails&)>
+ callback);
+
+ // The user has chosen to change the virtual-card enrollment of a credit card.
+ // Send the necessary information for the server to identify the credit card
+ // for which virtual-card enrollment will be updated, as well as metadata so
+ // that the server understands the context for the request.
+ virtual void UpdateVirtualCardEnrollment(
+ const UpdateVirtualCardEnrollmentRequestDetails& request_details,
+ base::OnceCallback<void(AutofillClient::PaymentsRpcResult)> callback);
+
// Cancels and clears the current |request_|.
void CancelRequest();
diff --git a/chromium/components/autofill/core/browser/payments/payments_client_unittest.cc b/chromium/components/autofill/core/browser/payments/payments_client_unittest.cc
index e42e5b24293..2816353cac7 100644
--- a/chromium/components/autofill/core/browser/payments/payments_client_unittest.cc
+++ b/chromium/components/autofill/core/browser/payments/payments_client_unittest.cc
@@ -23,6 +23,7 @@
#include "components/autofill/core/browser/payments/credit_card_save_manager.h"
#include "components/autofill/core/browser/payments/local_card_migration_manager.h"
#include "components/autofill/core/browser/payments/payments_client.h"
+#include "components/autofill/core/browser/payments/virtual_card_enrollment_flow.h"
#include "components/autofill/core/browser/test_personal_data_manager.h"
#include "components/autofill/core/common/autofill_clock.h"
#include "components/autofill/core/common/autofill_features.h"
@@ -38,8 +39,7 @@
#include "services/network/test/test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
-namespace autofill {
-namespace payments {
+namespace autofill::payments {
namespace {
int kAllDetectableValues =
@@ -94,6 +94,16 @@ struct CardUnmaskOptions {
return *this;
}
+ CardUnmaskOptions& with_only_non_legacy_id() {
+ use_only_non_legacy_id = true;
+ return *this;
+ }
+
+ CardUnmaskOptions& with_only_legacy_id() {
+ use_only_legacy_id = true;
+ return *this;
+ }
+
// By default, use cvc authentication.
bool use_cvc = true;
// If true, use FIDO authentication.
@@ -109,6 +119,10 @@ struct CardUnmaskOptions {
bool virtual_card = false;
// If true, set context_token in the request.
bool set_context_token = true;
+ // If true, use only non-legacy instrument id.
+ bool use_only_non_legacy_id = false;
+ // If true, use only legacy instrument id.
+ bool use_only_legacy_id = false;
};
} // namespace
@@ -128,7 +142,7 @@ class PaymentsClientTest : public testing::Test {
switches::kWalletServiceUseSandbox, "0");
result_ = AutofillClient::PaymentsRpcResult::kNone;
- server_id_.clear();
+ upload_card_response_details_.server_id.clear();
unmask_response_details_ = nullptr;
legal_message_.reset();
has_variations_header_ = false;
@@ -148,8 +162,11 @@ class PaymentsClientTest : public testing::Test {
test_personal_data_.SetAccountInfoForPayments(
identity_test_env_.MakePrimaryAccountAvailable(
"example@gmail.com", signin::ConsentLevel::kSync));
- scoped_feature_list_.InitAndEnableFeature(
- features::kAutofillEnableVirtualCardsRiskBasedAuthentication);
+ scoped_feature_list_.InitWithFeatures(
+ /* enabled_features */
+ {features::kAutofillEnableVirtualCardsRiskBasedAuthentication,
+ features::kAutofillEnableSendingBcnInGetUploadDetails},
+ /* disabled_features */ {});
}
void TearDown() override { client_.reset(); }
@@ -200,12 +217,13 @@ class PaymentsClientTest : public testing::Test {
}
void OnDidUploadCard(AutofillClient::PaymentsRpcResult result,
- const std::string& server_id) {
+ const PaymentsClient::UploadCardResponseDetails&
+ upload_card_respone_details) {
result_ = result;
- server_id_ = server_id;
+ upload_card_response_details_ = upload_card_respone_details;
}
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
void OnDidMigrateLocalCards(
AutofillClient::PaymentsRpcResult result,
std::unique_ptr<std::unordered_map<std::string, std::string>>
@@ -215,7 +233,7 @@ class PaymentsClientTest : public testing::Test {
migration_save_results_ = std::move(migration_save_results);
display_text_ = display_text;
}
-#endif // !defined(OS_ANDROID) && !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
void OnDidSelectChallengeOption(AutofillClient::PaymentsRpcResult result,
const std::string& updated_context_token) {
@@ -223,6 +241,20 @@ class PaymentsClientTest : public testing::Test {
context_token_ = updated_context_token;
}
+ void OnDidGetVirtualCardEnrollmentDetails(
+ AutofillClient::PaymentsRpcResult result,
+ const payments::PaymentsClient::GetDetailsForEnrollmentResponseDetails&
+ get_details_for_enrollment_response_fields) {
+ result_ = result;
+ get_details_for_enrollment_response_fields_ =
+ get_details_for_enrollment_response_fields;
+ }
+
+ void OnDidGetUpdateVirtualCardEnrollmentResponse(
+ AutofillClient::PaymentsRpcResult result) {
+ result_ = result;
+ }
+
protected:
base::test::ScopedFeatureList scoped_feature_list_;
@@ -241,7 +273,12 @@ class PaymentsClientTest : public testing::Test {
PaymentsClient::UnmaskRequestDetails request_details;
request_details.billing_customer_number = 111222333444;
- request_details.card = test::GetMaskedServerCard();
+ request_details.card = options.use_only_non_legacy_id
+ ? test::GetMaskedServerCardWithNonLegacyId()
+ : options.use_only_legacy_id
+ ? test::GetMaskedServerCardWithLegacyId()
+ : test::GetMaskedServerCard();
+
request_details.risk_data = "some risk data";
if (options.use_fido) {
request_details.fido_assertion_info =
@@ -278,13 +315,15 @@ class PaymentsClientTest : public testing::Test {
// Issue a GetUploadDetails request.
void StartGettingUploadDetails(
PaymentsClient::UploadCardSource upload_card_source =
- PaymentsClient::UploadCardSource::UNKNOWN_UPLOAD_CARD_SOURCE) {
+ PaymentsClient::UploadCardSource::UNKNOWN_UPLOAD_CARD_SOURCE,
+ long long billing_customer_number = 111222333444L) {
client_->GetUploadDetails(
BuildTestProfiles(), kAllDetectableValues, std::vector<const char*>(),
"language-LOCALE",
base::BindOnce(&PaymentsClientTest::OnDidGetUploadDetails,
weak_ptr_factory_.GetWeakPtr()),
- /*billable_service_number=*/12345, upload_card_source);
+ /*billable_service_number=*/12345, billing_customer_number,
+ upload_card_source);
}
// Issue an UploadCard request. This requires an OAuth token before starting
@@ -308,7 +347,7 @@ class PaymentsClientTest : public testing::Test {
weak_ptr_factory_.GetWeakPtr()));
}
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
void StartMigrating(bool has_cardholder_name,
bool set_nickname_for_first_card = false) {
PaymentsClient::MigrationRequestDetails request_details;
@@ -325,14 +364,14 @@ class PaymentsClientTest : public testing::Test {
card1.SetRawInfo(CREDIT_CARD_NAME_FULL, u"");
card2.SetRawInfo(CREDIT_CARD_NAME_FULL, u"");
}
- migratable_credit_cards_.push_back(MigratableCreditCard(card1));
- migratable_credit_cards_.push_back(MigratableCreditCard(card2));
+ migratable_credit_cards_.emplace_back(card1);
+ migratable_credit_cards_.emplace_back(card2);
client_->MigrateCards(
request_details, migratable_credit_cards_,
base::BindOnce(&PaymentsClientTest::OnDidMigrateLocalCards,
weak_ptr_factory_.GetWeakPtr()));
}
-#endif // !defined(OS_ANDROID) && !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
void StartSelectingChallengeOption(
CardUnmaskChallengeOptionType challenge_type =
@@ -434,9 +473,12 @@ class PaymentsClientTest : public testing::Test {
raw_ptr<payments::PaymentsClient::UnmaskDetails> unmask_details_;
// Server ID of a saved card via credit card upload save.
- std::string server_id_;
+ PaymentsClient::UploadCardResponseDetails upload_card_response_details_;
// The OptChangeResponseDetails retrieved from an OptChangeRequest.
PaymentsClient::OptChangeResponseDetails opt_change_response_;
+ // The response details retrieved from an GetDetailsForEnrollmentRequest.
+ PaymentsClient::GetDetailsForEnrollmentResponseDetails
+ get_details_for_enrollment_response_fields_;
// The UnmaskResponseDetails retrieved from an UnmaskRequest. Includes PAN.
raw_ptr<PaymentsClient::UnmaskResponseDetails> unmask_response_details_ =
nullptr;
@@ -450,7 +492,7 @@ class PaymentsClientTest : public testing::Test {
// The opaque token used to chain consecutive payments requests together.
std::string context_token_;
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
// Credit cards to be upload saved during a local credit card migration call.
std::vector<MigratableCreditCard> migratable_credit_cards_;
// A mapping of results from a local credit card migration call.
@@ -458,7 +500,7 @@ class PaymentsClientTest : public testing::Test {
migration_save_results_;
// A tip message to be displayed during local card migration.
std::string display_text_;
-#endif // !defined(OS_ANDROID) && !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
base::test::TaskEnvironment task_environment_;
variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{
@@ -827,6 +869,67 @@ TEST_F(PaymentsClientTest, UnmaskIncludesChromeUserContext) {
EXPECT_TRUE(GetUploadData().find("full_sync_enabled") != std::string::npos);
}
+TEST_F(PaymentsClientTest, UnmaskIncludesLegacyAndNonLegacyId) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeature(
+ features::kAutofillEnableUnmaskCardRequestSetInstrumentId);
+
+ StartUnmasking(CardUnmaskOptions());
+ IssueOAuthToken();
+ ReturnResponse(net::HTTP_OK, "{}");
+
+ // Non-legacy Instrument id and legacy server id are both set.
+ EXPECT_TRUE(GetUploadData().find("%22instrument_id%22:%221%22") !=
+ std::string::npos);
+ EXPECT_TRUE(GetUploadData().find("%22credit_card_id%22:%22a123%22") !=
+ std::string::npos);
+}
+
+TEST_F(PaymentsClientTest, UnmaskIncludesOnlyLegacyId) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeature(
+ features::kAutofillEnableUnmaskCardRequestSetInstrumentId);
+
+ StartUnmasking(CardUnmaskOptions().with_only_legacy_id());
+ IssueOAuthToken();
+ ReturnResponse(net::HTTP_OK, "{}");
+
+ // Only legacy server id is set.
+ EXPECT_TRUE(GetUploadData().find("instrument_id") == std::string::npos);
+ EXPECT_TRUE(GetUploadData().find("%22credit_card_id%22:%22a123%22") !=
+ std::string::npos);
+}
+
+TEST_F(PaymentsClientTest, UnmaskIncludesOnlyNonLegacyId) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeature(
+ features::kAutofillEnableUnmaskCardRequestSetInstrumentId);
+
+ StartUnmasking(CardUnmaskOptions().with_only_non_legacy_id());
+ IssueOAuthToken();
+ ReturnResponse(net::HTTP_OK, "{}");
+
+ // Only non-legacy instrument id is set.
+ EXPECT_TRUE(GetUploadData().find("%22instrument_id%22:%221%22") !=
+ std::string::npos);
+ EXPECT_TRUE(GetUploadData().find("credit_card_id") == std::string::npos);
+}
+
+TEST_F(PaymentsClientTest, UnmaskDoesNotIncludeInstrumentIdIfFlagDisabled) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndDisableFeature(
+ features::kAutofillEnableUnmaskCardRequestSetInstrumentId);
+
+ StartUnmasking(CardUnmaskOptions());
+ IssueOAuthToken();
+ ReturnResponse(net::HTTP_OK, "{}");
+
+ // Instrument id is not set if flag is disabled.
+ EXPECT_TRUE(GetUploadData().find("instrument_id") == std::string::npos);
+ EXPECT_TRUE(GetUploadData().find("%22credit_card_id%22:%22a123%22") !=
+ std::string::npos);
+}
+
TEST_F(PaymentsClientTest,
UnmaskIncludesChromeUserContextIfWalletStorageFlagEnabled) {
base::test::ScopedFeatureList feature_list;
@@ -1042,6 +1145,51 @@ TEST_F(PaymentsClientTest, GetDetailsIncludeBillableServiceNumber) {
std::string::npos);
}
+TEST_F(PaymentsClientTest, GetDetailsIncludeBillingCustomerNumber) {
+ scoped_feature_list_.Reset();
+ scoped_feature_list_.InitAndEnableFeature(
+ features::kAutofillEnableSendingBcnInGetUploadDetails);
+
+ StartGettingUploadDetails();
+
+ // Verify that the billing customer number is included in the request if flag
+ // is enabled.
+ EXPECT_TRUE(
+ GetUploadData().find("\"external_customer_id\":\"111222333444\"") !=
+ std::string::npos);
+}
+
+TEST_F(PaymentsClientTest,
+ GetDetailsExcludesBillingCustomerNumberIfNoBcnExists) {
+ scoped_feature_list_.Reset();
+ scoped_feature_list_.InitAndEnableFeature(
+ features::kAutofillEnableSendingBcnInGetUploadDetails);
+
+ StartGettingUploadDetails(
+ PaymentsClient::UploadCardSource::UNKNOWN_UPLOAD_CARD_SOURCE, 0L);
+ // Verify that the billing customer number is not included in the request if
+ // billing customer number is 0.
+ EXPECT_TRUE(GetUploadData().find("\"external_customer_id\"") ==
+ std::string::npos);
+ EXPECT_TRUE(GetUploadData().find("\"customer_context\"") ==
+ std::string::npos);
+}
+
+TEST_F(PaymentsClientTest,
+ GetDetailsExcludesBillingCustomerNumberIfFlagDisabled) {
+ scoped_feature_list_.Reset();
+ scoped_feature_list_.InitAndDisableFeature(
+ features::kAutofillEnableSendingBcnInGetUploadDetails);
+
+ StartGettingUploadDetails();
+ // Verify that the billing customer number is not included in the request if
+ // flag is disabled.
+ EXPECT_TRUE(GetUploadData().find("\"external_customer_id\"") ==
+ std::string::npos);
+ EXPECT_TRUE(GetUploadData().find("\"customer_context\"") ==
+ std::string::npos);
+}
+
TEST_F(PaymentsClientTest, GetDetailsFollowedByUploadSuccess) {
StartGettingUploadDetails();
ReturnResponse(
@@ -1135,20 +1283,87 @@ TEST_F(PaymentsClientTest, UnmaskCardVariationsTest) {
EXPECT_TRUE(HasVariationsHeader());
}
-TEST_F(PaymentsClientTest, UploadSuccessWithoutServerId) {
+TEST_F(PaymentsClientTest, UploadSuccessEmptyResponse) {
StartUploading(/*include_cvc=*/true);
IssueOAuthToken();
ReturnResponse(net::HTTP_OK, "{}");
EXPECT_EQ(AutofillClient::PaymentsRpcResult::kSuccess, result_);
- EXPECT_TRUE(server_id_.empty());
+ EXPECT_TRUE(upload_card_response_details_.server_id.empty());
+ EXPECT_FALSE(upload_card_response_details_.instrument_id.has_value());
+ EXPECT_TRUE(upload_card_response_details_.virtual_card_enrollment_state ==
+ CreditCard::VirtualCardEnrollmentState::UNSPECIFIED);
+ EXPECT_TRUE(upload_card_response_details_.card_art_url.is_empty());
}
-TEST_F(PaymentsClientTest, UploadSuccessWithServerId) {
+TEST_F(PaymentsClientTest, UploadSuccessServerIdPresent) {
StartUploading(/*include_cvc=*/true);
IssueOAuthToken();
ReturnResponse(net::HTTP_OK, "{ \"credit_card_id\": \"InstrumentData:1\" }");
EXPECT_EQ(AutofillClient::PaymentsRpcResult::kSuccess, result_);
- EXPECT_EQ("InstrumentData:1", server_id_);
+ EXPECT_EQ(upload_card_response_details_.server_id, "InstrumentData:1");
+}
+
+TEST_F(PaymentsClientTest, UploadSuccessInstrumentIdPresent) {
+ StartUploading(/*include_cvc=*/true);
+ IssueOAuthToken();
+ upload_card_response_details_.instrument_id = absl::nullopt;
+
+ // Test the conversion from string to int64_t using the max value for int64_t.
+ ReturnResponse(net::HTTP_OK,
+ "{ \"instrument_id\": \"9223372036854775807\" }");
+ EXPECT_EQ(AutofillClient::PaymentsRpcResult::kSuccess, result_);
+ EXPECT_EQ(upload_card_response_details_.instrument_id, 9223372036854775807);
+}
+
+TEST_F(PaymentsClientTest, UploadSuccessVirtualCardEnrollmentStatePresent) {
+ bool oauth_token_issued = false;
+ for (CreditCard::VirtualCardEnrollmentState virtual_card_enrollment_state :
+ {CreditCard::VirtualCardEnrollmentState::UNENROLLED_AND_NOT_ELIGIBLE,
+ CreditCard::VirtualCardEnrollmentState::UNENROLLED_AND_ELIGIBLE,
+ CreditCard::VirtualCardEnrollmentState::ENROLLED}) {
+ StartUploading(/*include_cvc=*/true);
+ // An OAuthToken needs to be issued to initiate the first UploadCard call
+ // from PaymentsClientTest::StartUploading(), but only for the first call.
+ // All future calls will use the first OAuthToken. If multiple OAuthTokens
+ // are issued this test will time out.
+ if (!oauth_token_issued) {
+ IssueOAuthToken();
+ oauth_token_issued = true;
+ }
+ switch (virtual_card_enrollment_state) {
+ case CreditCard::VirtualCardEnrollmentState::UNENROLLED_AND_NOT_ELIGIBLE:
+ ReturnResponse(net::HTTP_OK,
+ "{ \"virtual_card_metadata\": { \"status\": "
+ "\"ENROLLMENT_STATUS_UNSPECIFIED\" } }");
+ break;
+ case CreditCard::VirtualCardEnrollmentState::UNENROLLED_AND_ELIGIBLE:
+ ReturnResponse(net::HTTP_OK,
+ "{ \"virtual_card_metadata\": { \"status\": "
+ "\"ENROLLMENT_ELIGIBLE\" } }");
+ break;
+ case CreditCard::VirtualCardEnrollmentState::ENROLLED:
+ ReturnResponse(
+ net::HTTP_OK,
+ "{ \"virtual_card_metadata\": { \"status\": \"ENROLLED\" } }");
+ break;
+ case CreditCard::VirtualCardEnrollmentState::UNENROLLED:
+ case CreditCard::VirtualCardEnrollmentState::UNSPECIFIED:
+ break;
+ }
+ EXPECT_EQ(AutofillClient::PaymentsRpcResult::kSuccess, result_);
+ EXPECT_EQ(upload_card_response_details_.virtual_card_enrollment_state,
+ virtual_card_enrollment_state);
+ }
+}
+
+TEST_F(PaymentsClientTest, UploadSuccessCardArtUrlPresent) {
+ StartUploading(/*include_cvc=*/true);
+ IssueOAuthToken();
+ ReturnResponse(net::HTTP_OK,
+ "{ \"card_art_url\": \"https://www.example.com/\" }");
+ EXPECT_EQ(AutofillClient::PaymentsRpcResult::kSuccess, result_);
+ EXPECT_EQ(upload_card_response_details_.card_art_url.spec(),
+ "https://www.example.com/");
}
TEST_F(PaymentsClientTest, UploadIncludesNonLocationData) {
@@ -1381,7 +1596,7 @@ TEST_F(PaymentsClientTest, UnmaskPermanentFailureWhenVcnMissingCvv) {
}
// Tests for the local card migration flow. Desktop only.
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
TEST_F(PaymentsClientTest, GetDetailsFollowedByMigrationSuccess) {
StartGettingUploadDetails();
ReturnResponse(
@@ -1487,7 +1702,7 @@ TEST_F(PaymentsClientTest,
TEST_F(PaymentsClientTest, MigrationRequestIncludesCardNickname) {
StartMigrating(/*has_cardholder_name=*/true,
- /*set_nickname_to_first_card=*/true);
+ /*set_nickname_for_first_card=*/true);
IssueOAuthToken();
// Nickname was set for the first card.
@@ -1596,5 +1811,224 @@ TEST_F(PaymentsClientTest, SelectChallengeOptionResponseMissingContextToken) {
EXPECT_EQ(AutofillClient::PaymentsRpcResult::kPermanentFailure, result_);
}
-} // namespace payments
-} // namespace autofill
+typedef std::tuple<VirtualCardEnrollmentSource,
+ VirtualCardEnrollmentRequestType,
+ AutofillClient::PaymentsRpcResult>
+ UpdateVirtualCardEnrollmentTestData;
+
+class UpdateVirtualCardEnrollmentTest
+ : public PaymentsClientTest,
+ public ::testing::WithParamInterface<
+ UpdateVirtualCardEnrollmentTestData> {
+ public:
+ UpdateVirtualCardEnrollmentTest() = default;
+ ~UpdateVirtualCardEnrollmentTest() override = default;
+
+ void TriggerFlow() {
+ VirtualCardEnrollmentSource virtual_card_enrollment_source =
+ std::get<0>(GetParam());
+ VirtualCardEnrollmentRequestType virtual_card_enrollment_request_type =
+ std::get<1>(GetParam());
+ StartUpdateVirtualCardEnrollment(virtual_card_enrollment_source,
+ virtual_card_enrollment_request_type);
+ IssueOAuthToken();
+
+ // |response_type_for_test| is the AutofillClient::PaymentsRpcResult
+ // response type we want to test for the combination of
+ // |virtual_card_enrollment_source| and
+ // |virtual_card_enrollment_request_type| we are currently on.
+ AutofillClient::PaymentsRpcResult response_type_for_test =
+ std::get<2>(GetParam());
+ switch (response_type_for_test) {
+ case AutofillClient::PaymentsRpcResult::kSuccess:
+ if (virtual_card_enrollment_request_type ==
+ VirtualCardEnrollmentRequestType::kEnroll) {
+ ReturnResponse(net::HTTP_OK,
+ "{ \"enroll_result\": \"ENROLL_SUCCESS\" }");
+ } else if (virtual_card_enrollment_request_type ==
+ VirtualCardEnrollmentRequestType::kUnenroll) {
+ ReturnResponse(net::HTTP_OK, "{}");
+ }
+ break;
+ case AutofillClient::PaymentsRpcResult::kVcnRetrievalTryAgainFailure:
+ ReturnResponse(
+ net::HTTP_OK,
+ "{ \"error\": { \"code\": \"ANYTHING_ELSE\", "
+ "\"api_error_reason\": \"virtual_card_temporary_error\"} }");
+ break;
+ case AutofillClient::PaymentsRpcResult::kTryAgainFailure:
+ ReturnResponse(net::HTTP_OK,
+ "{ \"error\": { \"code\": \"INTERNAL\", "
+ "\"api_error_reason\": \"ANYTHING_ELSE\"} }");
+ break;
+ case AutofillClient::PaymentsRpcResult::kVcnRetrievalPermanentFailure:
+ ReturnResponse(
+ net::HTTP_OK,
+ "{ \"error\": { \"code\": \"ANYTHING_ELSE\", "
+ "\"api_error_reason\": \"virtual_card_permanent_error\"} }");
+ break;
+ case AutofillClient::PaymentsRpcResult::kPermanentFailure:
+ ReturnResponse(net::HTTP_OK,
+ "{ \"error\": { \"code\": \"ANYTHING_ELSE\" } }");
+ break;
+ case AutofillClient::PaymentsRpcResult::kNetworkError:
+ ReturnResponse(net::HTTP_REQUEST_TIMEOUT, "");
+ break;
+ case AutofillClient::PaymentsRpcResult::kNone:
+ NOTREACHED();
+ break;
+ }
+ EXPECT_EQ(response_type_for_test, result_);
+ }
+
+ private:
+ void StartUpdateVirtualCardEnrollment(
+ VirtualCardEnrollmentSource virtual_card_enrollment_source,
+ VirtualCardEnrollmentRequestType virtual_card_enrollment_request_type) {
+ PaymentsClient::UpdateVirtualCardEnrollmentRequestDetails request_details;
+ request_details.virtual_card_enrollment_request_type =
+ virtual_card_enrollment_request_type;
+ request_details.virtual_card_enrollment_source =
+ virtual_card_enrollment_source;
+ request_details.billing_customer_number = 555666777888;
+ if (virtual_card_enrollment_request_type ==
+ VirtualCardEnrollmentRequestType::kEnroll) {
+ request_details.vcn_context_token = "fake context token";
+ } else if (virtual_card_enrollment_request_type ==
+ VirtualCardEnrollmentRequestType::kUnenroll) {
+ request_details.instrument_id = 12345678;
+ }
+ client_->UpdateVirtualCardEnrollment(
+ request_details,
+ base::BindOnce(
+ &PaymentsClientTest::OnDidGetUpdateVirtualCardEnrollmentResponse,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
+};
+
+// Initializes the parameterized test suite with all possible values of
+// VirtualCardEnrollmentSource, VirtualCardEnrollmentRequestType, and
+// AutofillClient::PaymentsRpcResult.
+INSTANTIATE_TEST_SUITE_P(
+ ,
+ UpdateVirtualCardEnrollmentTest,
+ testing::Combine(
+ testing::Values(VirtualCardEnrollmentSource::kUpstream,
+ VirtualCardEnrollmentSource::kDownstream,
+ VirtualCardEnrollmentSource::kSettingsPage),
+ testing::Values(VirtualCardEnrollmentRequestType::kEnroll,
+ VirtualCardEnrollmentRequestType::kUnenroll),
+ testing::Values(
+ AutofillClient::PaymentsRpcResult::kSuccess,
+ AutofillClient::PaymentsRpcResult::kVcnRetrievalTryAgainFailure,
+ AutofillClient::PaymentsRpcResult::kTryAgainFailure,
+ AutofillClient::PaymentsRpcResult::kVcnRetrievalPermanentFailure,
+ AutofillClient::PaymentsRpcResult::kPermanentFailure,
+ AutofillClient::PaymentsRpcResult::kNetworkError)));
+
+// Parameterized test that tests all combinations of
+// VirtualCardEnrollmentSource and VirtualCardEnrollmentRequestType against all
+// possible server responses in the UpdateVirtualCardEnrollmentFlow. This test
+// will be run once for each combination.
+TEST_P(UpdateVirtualCardEnrollmentTest,
+ UpdateVirtualCardEnrollmentTest_TestAllFlows) {
+ TriggerFlow();
+}
+
+class GetVirtualCardEnrollmentDetailsTest
+ : public PaymentsClientTest,
+ public ::testing::WithParamInterface<
+ std::tuple<VirtualCardEnrollmentSource,
+ AutofillClient::PaymentsRpcResult>> {
+ public:
+ GetVirtualCardEnrollmentDetailsTest() = default;
+ ~GetVirtualCardEnrollmentDetailsTest() override = default;
+};
+
+// Initializes the parameterized test suite with all possible combinations of
+// VirtualCardEnrollmentSource and AutofillClient::PaymentsRpcResult.
+INSTANTIATE_TEST_SUITE_P(
+ ,
+ GetVirtualCardEnrollmentDetailsTest,
+ testing::Combine(
+ testing::Values(VirtualCardEnrollmentSource::kUpstream,
+ VirtualCardEnrollmentSource::kDownstream,
+ VirtualCardEnrollmentSource::kSettingsPage),
+ testing::Values(
+ AutofillClient::PaymentsRpcResult::kSuccess,
+ AutofillClient::PaymentsRpcResult::kVcnRetrievalTryAgainFailure,
+ AutofillClient::PaymentsRpcResult::kTryAgainFailure,
+ AutofillClient::PaymentsRpcResult::kVcnRetrievalPermanentFailure,
+ AutofillClient::PaymentsRpcResult::kPermanentFailure,
+ AutofillClient::PaymentsRpcResult::kNetworkError)));
+
+// Parameterized test that tests all combinations of
+// VirtualCardEnrollmentSource and server PaymentsRpcResult. This test
+// will be run once for each combination.
+TEST_P(GetVirtualCardEnrollmentDetailsTest,
+ GetVirtualCardEnrollmentDetailsTest_TestAllFlows) {
+ VirtualCardEnrollmentSource source = std::get<0>(GetParam());
+
+ PaymentsClient::GetDetailsForEnrollmentRequestDetails request_details;
+ request_details.source = source;
+ request_details.instrument_id = 12345678;
+ request_details.billing_customer_number = 555666777888;
+ request_details.risk_data = "fake risk data";
+ request_details.app_locale = "en";
+
+ client_->GetVirtualCardEnrollmentDetails(
+ request_details,
+ base::BindOnce(&PaymentsClientTest::OnDidGetVirtualCardEnrollmentDetails,
+ weak_ptr_factory_.GetWeakPtr()));
+ IssueOAuthToken();
+ // Ensures the request contains the correct fields.
+ EXPECT_TRUE(!GetUploadData().empty());
+ EXPECT_TRUE(GetUploadData().find("language_code") != std::string::npos);
+ EXPECT_TRUE(GetUploadData().find("billable_service") != std::string::npos);
+ EXPECT_TRUE(GetUploadData().find("external_customer_id") !=
+ std::string::npos);
+ EXPECT_TRUE(GetUploadData().find("instrument_id") != std::string::npos);
+ EXPECT_TRUE(GetUploadData().find("risk_data_encoded") != std::string::npos);
+
+ // Ensures the PaymentsRpcResult is set correctly.
+ AutofillClient::PaymentsRpcResult result = std::get<1>(GetParam());
+ switch (result) {
+ case AutofillClient::PaymentsRpcResult::kSuccess:
+ ReturnResponse(
+ net::HTTP_OK,
+ "{ \"google_legal_message\": { \"line\" : [{ \"template\": \"This is "
+ "the entire message.\" }] }, \"external_legal_message\": {}, "
+ "\"context_token\": \"some_token\" }");
+ break;
+ case AutofillClient::PaymentsRpcResult::kVcnRetrievalTryAgainFailure:
+ ReturnResponse(
+ net::HTTP_OK,
+ "{ \"error\": { \"code\": \"ANYTHING_ELSE\", "
+ "\"api_error_reason\": \"virtual_card_temporary_error\"} }");
+ break;
+ case AutofillClient::PaymentsRpcResult::kTryAgainFailure:
+ ReturnResponse(net::HTTP_OK,
+ "{ \"error\": { \"code\": \"INTERNAL\", "
+ "\"api_error_reason\": \"ANYTHING_ELSE\"} }");
+ break;
+ case AutofillClient::PaymentsRpcResult::kVcnRetrievalPermanentFailure:
+ ReturnResponse(
+ net::HTTP_OK,
+ "{ \"error\": { \"code\": \"ANYTHING_ELSE\", "
+ "\"api_error_reason\": \"virtual_card_permanent_error\"} }");
+ break;
+ case AutofillClient::PaymentsRpcResult::kPermanentFailure:
+ ReturnResponse(net::HTTP_OK,
+ "{ \"error\": { \"code\": \"ANYTHING_ELSE\" } }");
+ break;
+ case AutofillClient::PaymentsRpcResult::kNetworkError:
+ ReturnResponse(net::HTTP_REQUEST_TIMEOUT, "");
+ break;
+ case AutofillClient::PaymentsRpcResult::kNone:
+ NOTREACHED();
+ break;
+ }
+ EXPECT_EQ(result, result_);
+}
+
+} // namespace autofill::payments
diff --git a/chromium/components/autofill/core/browser/payments/payments_requests/get_details_for_enrollment_request.cc b/chromium/components/autofill/core/browser/payments/payments_requests/get_details_for_enrollment_request.cc
new file mode 100644
index 00000000000..5a079b9f1ad
--- /dev/null
+++ b/chromium/components/autofill/core/browser/payments/payments_requests/get_details_for_enrollment_request.cc
@@ -0,0 +1,123 @@
+// Copyright 2022 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.
+
+#include "components/autofill/core/browser/payments/payments_requests/get_details_for_enrollment_request.h"
+
+#include "base/json/json_writer.h"
+#include "base/strings/string_number_conversions.h"
+
+namespace autofill::payments {
+
+namespace {
+
+// The path that the request will be sent to.
+const char kGetDetailsForEnrollmentRequestPath[] =
+ "payments/apis/virtualcardservice/getdetailsforenroll";
+
+// The billable service number for the request if the enrollment happens after
+// a local card upload.
+const int kUpstreamEnrollBillableServiceNumber =
+ kUploadCardBillableServiceNumber;
+
+// The billable service number for the request if the enrollment happens after a
+// server card retrieval or in the settings page.
+const int kDownstreamEnrollBillableServiceNumber =
+ kUnmaskCardBillableServiceNumber;
+
+} // namespace
+
+GetDetailsForEnrollmentRequest::GetDetailsForEnrollmentRequest(
+ const PaymentsClient::GetDetailsForEnrollmentRequestDetails&
+ request_details,
+ base::OnceCallback<
+ void(AutofillClient::PaymentsRpcResult,
+ const PaymentsClient::GetDetailsForEnrollmentResponseDetails&)>
+ callback)
+ : request_details_(request_details), callback_(std::move(callback)) {}
+
+GetDetailsForEnrollmentRequest::~GetDetailsForEnrollmentRequest() = default;
+
+std::string GetDetailsForEnrollmentRequest::GetRequestUrlPath() {
+ return kGetDetailsForEnrollmentRequestPath;
+}
+
+std::string GetDetailsForEnrollmentRequest::GetRequestContentType() {
+ return "application/json";
+}
+
+std::string GetDetailsForEnrollmentRequest::GetRequestContent() {
+ base::Value request_dict(base::Value::Type::DICTIONARY);
+
+ base::Value context(base::Value::Type::DICTIONARY);
+ context.SetKey("language_code", base::Value(request_details_.app_locale));
+ int billable_service_number = 0;
+ switch (request_details_.source) {
+ case VirtualCardEnrollmentSource::kUpstream:
+ billable_service_number = kUpstreamEnrollBillableServiceNumber;
+ break;
+ case VirtualCardEnrollmentSource::kDownstream:
+ case VirtualCardEnrollmentSource::kSettingsPage:
+ billable_service_number = kDownstreamEnrollBillableServiceNumber;
+ break;
+ case VirtualCardEnrollmentSource::kNone:
+ NOTREACHED();
+ break;
+ }
+ context.SetKey("billable_service", base::Value(billable_service_number));
+ if (request_details_.billing_customer_number != 0) {
+ context.SetKey("customer_context",
+ BuildCustomerContextDictionary(
+ request_details_.billing_customer_number));
+ }
+ request_dict.SetKey("context", std::move(context));
+
+ request_dict.SetKey(
+ "instrument_id",
+ base::Value(base::NumberToString(request_details_.instrument_id)));
+
+ if (!request_details_.risk_data.empty()) {
+ request_dict.SetKey("risk_data_encoded",
+ BuildRiskDictionary(request_details_.risk_data));
+ }
+
+ std::string request_content;
+ base::JSONWriter::Write(request_dict, &request_content);
+ VLOG(3) << "GetDetailsForEnrollmentRequest request body: " << request_content;
+ return request_content;
+}
+
+void GetDetailsForEnrollmentRequest::ParseResponse(
+ const base::Value& response) {
+ const base::Value* google_legal_message = response.FindKeyOfType(
+ "google_legal_message", base::Value::Type::DICTIONARY);
+ if (google_legal_message) {
+ LegalMessageLine::Parse(*google_legal_message,
+ &response_details_.google_legal_message,
+ /*escape_apostrophes=*/true);
+ }
+
+ const base::Value* external_legal_message = response.FindKeyOfType(
+ "external_legal_message", base::Value::Type::DICTIONARY);
+ if (external_legal_message) {
+ LegalMessageLine::Parse(*external_legal_message,
+ &response_details_.issuer_legal_message,
+ /*escape_apostrophes=*/true);
+ }
+
+ const auto* context_token = response.FindStringKey("context_token");
+ response_details_.vcn_context_token =
+ context_token ? *context_token : std::string();
+}
+
+bool GetDetailsForEnrollmentRequest::IsResponseComplete() {
+ return !response_details_.vcn_context_token.empty() &&
+ !response_details_.google_legal_message.empty();
+}
+
+void GetDetailsForEnrollmentRequest::RespondToDelegate(
+ AutofillClient::PaymentsRpcResult result) {
+ std::move(callback_).Run(result, response_details_);
+}
+
+} // namespace autofill::payments
diff --git a/chromium/components/autofill/core/browser/payments/payments_requests/get_details_for_enrollment_request.h b/chromium/components/autofill/core/browser/payments/payments_requests/get_details_for_enrollment_request.h
new file mode 100644
index 00000000000..88774710635
--- /dev/null
+++ b/chromium/components/autofill/core/browser/payments/payments_requests/get_details_for_enrollment_request.h
@@ -0,0 +1,57 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_PAYMENTS_REQUESTS_GET_DETAILS_FOR_ENROLLMENT_REQUEST_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_PAYMENTS_REQUESTS_GET_DETAILS_FOR_ENROLLMENT_REQUEST_H_
+
+#include "components/autofill/core/browser/payments/payments_client.h"
+#include "components/autofill/core/browser/payments/payments_requests/payments_request.h"
+
+namespace autofill::payments {
+
+// Payments request to fetch necessary information (i.e. ToS message) in
+// preparation for the virtual card enrollment.
+class GetDetailsForEnrollmentRequest : public PaymentsRequest {
+ public:
+ GetDetailsForEnrollmentRequest(
+ const PaymentsClient::GetDetailsForEnrollmentRequestDetails&
+ request_details,
+ base::OnceCallback<
+ void(AutofillClient::PaymentsRpcResult,
+ const PaymentsClient::GetDetailsForEnrollmentResponseDetails&)>
+ callback);
+ GetDetailsForEnrollmentRequest(const GetDetailsForEnrollmentRequest&) =
+ delete;
+ GetDetailsForEnrollmentRequest& operator=(
+ const GetDetailsForEnrollmentRequest&) = delete;
+ ~GetDetailsForEnrollmentRequest() override;
+
+ // PaymentsRequest:
+ std::string GetRequestUrlPath() override;
+ std::string GetRequestContentType() override;
+ std::string GetRequestContent() override;
+ void ParseResponse(const base::Value& response) override;
+ bool IsResponseComplete() override;
+ void RespondToDelegate(AutofillClient::PaymentsRpcResult result) override;
+
+ private:
+ friend class GetDetailsForEnrollmentRequestTest;
+
+ // Used to store information to be populated to the request.
+ PaymentsClient::GetDetailsForEnrollmentRequestDetails request_details_;
+
+ // Used to store information parsed from the response. Will be passed into the
+ // |callback_| function as a param.
+ PaymentsClient::GetDetailsForEnrollmentResponseDetails response_details_;
+
+ // The callback function to be invoked when the response is received.
+ base::OnceCallback<void(
+ AutofillClient::PaymentsRpcResult,
+ const PaymentsClient::GetDetailsForEnrollmentResponseDetails&)>
+ callback_;
+};
+
+} // namespace autofill::payments
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_PAYMENTS_REQUESTS_GET_DETAILS_FOR_ENROLLMENT_REQUEST_H_
diff --git a/chromium/components/autofill/core/browser/payments/payments_requests/get_details_for_enrollment_request_unittest.cc b/chromium/components/autofill/core/browser/payments/payments_requests/get_details_for_enrollment_request_unittest.cc
new file mode 100644
index 00000000000..4af47054d73
--- /dev/null
+++ b/chromium/components/autofill/core/browser/payments/payments_requests/get_details_for_enrollment_request_unittest.cc
@@ -0,0 +1,77 @@
+// Copyright 2022 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.
+
+#include <memory>
+
+#include "base/callback_helpers.h"
+#include "base/json/json_reader.h"
+#include "components/autofill/core/browser/payments/payments_requests/get_details_for_enrollment_request.h"
+#include "components/autofill/core/browser/payments/virtual_card_enrollment_flow.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace autofill::payments {
+
+class GetDetailsForEnrollmentRequestTest : public testing::Test {
+ public:
+ GetDetailsForEnrollmentRequestTest() = default;
+ GetDetailsForEnrollmentRequestTest(
+ const GetDetailsForEnrollmentRequestTest&) = delete;
+ GetDetailsForEnrollmentRequestTest& operator=(
+ const GetDetailsForEnrollmentRequestTest&) = delete;
+ ~GetDetailsForEnrollmentRequestTest() override = default;
+
+ void CreateRequest() {
+ PaymentsClient::GetDetailsForEnrollmentRequestDetails request_details;
+ request_details.instrument_id = 11223344;
+ request_details.app_locale = "en";
+ request_details.billing_customer_number = 55667788;
+ request_details.risk_data = "fake risk data";
+ request_details.source = VirtualCardEnrollmentSource::kUpstream;
+ request_ = std::make_unique<GetDetailsForEnrollmentRequest>(
+ request_details, base::DoNothing());
+ }
+
+ GetDetailsForEnrollmentRequest* GetRequest() const { return request_.get(); }
+
+ const PaymentsClient::GetDetailsForEnrollmentResponseDetails&
+ GetParsedResponse() const {
+ return request_->response_details_;
+ }
+
+ private:
+ std::unique_ptr<GetDetailsForEnrollmentRequest> request_;
+};
+
+TEST_F(GetDetailsForEnrollmentRequestTest, GetRequestContent) {
+ CreateRequest();
+ EXPECT_EQ(GetRequest()->GetRequestUrlPath(),
+ "payments/apis/virtualcardservice/getdetailsforenroll");
+ EXPECT_TRUE(!GetRequest()->GetRequestContent().empty());
+ EXPECT_TRUE(GetRequest()->GetRequestContent().find("language_code") !=
+ std::string::npos);
+ EXPECT_TRUE(GetRequest()->GetRequestContent().find("billable_service") !=
+ std::string::npos);
+ EXPECT_TRUE(GetRequest()->GetRequestContent().find("external_customer_id") !=
+ std::string::npos);
+ EXPECT_TRUE(GetRequest()->GetRequestContent().find("instrument_id") !=
+ std::string::npos);
+ EXPECT_TRUE(GetRequest()->GetRequestContent().find("risk_data_encoded") !=
+ std::string::npos);
+}
+
+TEST_F(GetDetailsForEnrollmentRequestTest, ParseResponse) {
+ CreateRequest();
+ absl::optional<base::Value> response = base::JSONReader::Read(
+ "{ \"google_legal_message\": {}, \"external_legal_message\": {}, "
+ "\"context_token\": \"some_token\" }");
+ ASSERT_TRUE(response.has_value());
+ GetRequest()->ParseResponse(response.value());
+
+ EXPECT_EQ(GetParsedResponse().vcn_context_token, "some_token");
+ EXPECT_TRUE(GetParsedResponse().issuer_legal_message.empty());
+ EXPECT_TRUE(GetParsedResponse().google_legal_message.empty());
+ EXPECT_FALSE(GetRequest()->IsResponseComplete());
+}
+
+} // namespace autofill::payments
diff --git a/chromium/components/autofill/core/browser/payments/payments_requests/payments_request.cc b/chromium/components/autofill/core/browser/payments/payments_requests/payments_request.cc
index d3e54f449a3..0de08f93f93 100644
--- a/chromium/components/autofill/core/browser/payments/payments_requests/payments_request.cc
+++ b/chromium/components/autofill/core/browser/payments/payments_requests/payments_request.cc
@@ -16,7 +16,7 @@ PaymentsRequest::~PaymentsRequest() = default;
base::Value PaymentsRequest::BuildRiskDictionary(
const std::string& encoded_risk_data) {
base::Value risk_data(base::Value::Type::DICTIONARY);
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
// Browser fingerprinting is not available on iOS. Instead, we generate
// RiskAdvisoryData.
risk_data.SetKey("message_type", base::Value("RISK_ADVISORY_DATA"));
diff --git a/chromium/components/autofill/core/browser/payments/payments_requests/unmask_card_request.cc b/chromium/components/autofill/core/browser/payments/payments_requests/unmask_card_request.cc
index d92aef0cdee..c1a1c0db810 100644
--- a/chromium/components/autofill/core/browser/payments/payments_requests/unmask_card_request.cc
+++ b/chromium/components/autofill/core/browser/payments/payments_requests/unmask_card_request.cc
@@ -86,9 +86,21 @@ std::string UnmaskCardRequest::GetRequestContentType() {
}
std::string UnmaskCardRequest::GetRequestContent() {
+ // Either non-legacy instrument id or legacy server id must be provided.
+ DCHECK(!request_details_.card.server_id().empty() ||
+ request_details_.card.instrument_id() != 0);
base::Value request_dict(base::Value::Type::DICTIONARY);
- request_dict.SetKey("credit_card_id",
- base::Value(request_details_.card.server_id()));
+ if (!request_details_.card.server_id().empty()) {
+ request_dict.SetKey("credit_card_id",
+ base::Value(request_details_.card.server_id()));
+ }
+ if (base::FeatureList::IsEnabled(
+ features::kAutofillEnableUnmaskCardRequestSetInstrumentId) &&
+ request_details_.card.instrument_id() != 0) {
+ request_dict.SetKey("instrument_id",
+ base::Value(base::NumberToString(
+ request_details_.card.instrument_id())));
+ }
if (base::FeatureList::IsEnabled(
features::kAutofillAlwaysReturnCloudTokenizedCard)) {
// See b/140727361.
@@ -214,7 +226,7 @@ void UnmaskCardRequest::ParseResponse(const base::Value& response) {
if (challenge_option_list) {
std::vector<CardUnmaskChallengeOption> card_unmask_challenge_options;
for (const base::Value& challenge_option :
- challenge_option_list->GetList()) {
+ challenge_option_list->GetListDeprecated()) {
CardUnmaskChallengeOption parsed_challenge_option =
ParseCardUnmaskChallengeOption(challenge_option);
// Only return successfully parsed challenge option.
diff --git a/chromium/components/autofill/core/browser/payments/payments_requests/update_virtual_card_enrollment_request.cc b/chromium/components/autofill/core/browser/payments/payments_requests/update_virtual_card_enrollment_request.cc
new file mode 100644
index 00000000000..d66bda2086d
--- /dev/null
+++ b/chromium/components/autofill/core/browser/payments/payments_requests/update_virtual_card_enrollment_request.cc
@@ -0,0 +1,185 @@
+// Copyright 2022 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.
+
+#include "components/autofill/core/browser/payments/payments_requests/update_virtual_card_enrollment_request.h"
+
+#include <string>
+
+#include "base/json/json_writer.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/values.h"
+#include "components/autofill/core/browser/payments/virtual_card_enrollment_flow.h"
+
+namespace autofill {
+namespace payments {
+
+namespace {
+const char kEnrollRequestPath[] = "payments/apis/virtualcardservice/enroll";
+const char kUnenrollRequestPath[] = "payments/apis/virtualcardservice/unenroll";
+} // namespace
+
+UpdateVirtualCardEnrollmentRequest::UpdateVirtualCardEnrollmentRequest(
+ const PaymentsClient::UpdateVirtualCardEnrollmentRequestDetails&
+ request_details,
+ base::OnceCallback<void(AutofillClient::PaymentsRpcResult)> callback)
+ : request_details_(request_details), callback_(std::move(callback)) {}
+
+UpdateVirtualCardEnrollmentRequest::~UpdateVirtualCardEnrollmentRequest() =
+ default;
+
+std::string UpdateVirtualCardEnrollmentRequest::GetRequestUrlPath() {
+ return request_details_.virtual_card_enrollment_request_type ==
+ VirtualCardEnrollmentRequestType::kEnroll
+ ? kEnrollRequestPath
+ : kUnenrollRequestPath;
+}
+
+std::string UpdateVirtualCardEnrollmentRequest::GetRequestContentType() {
+ return "application/json";
+}
+
+std::string UpdateVirtualCardEnrollmentRequest::GetRequestContent() {
+ base::Value request_dict(base::Value::Type::DICTIONARY);
+
+ switch (request_details_.virtual_card_enrollment_request_type) {
+ case VirtualCardEnrollmentRequestType::kEnroll:
+ BuildEnrollRequestDictionary(&request_dict);
+ break;
+ case VirtualCardEnrollmentRequestType::kUnenroll:
+ BuildUnenrollRequestDictionary(&request_dict);
+ break;
+ case VirtualCardEnrollmentRequestType::kNone:
+ NOTREACHED();
+ break;
+ }
+
+ std::string request_content;
+ base::JSONWriter::Write(request_dict, &request_content);
+ VLOG(3) << "UpdateVirtualCardEnrollmentRequest Body: " << request_content;
+ return request_content;
+}
+
+void UpdateVirtualCardEnrollmentRequest::ParseResponse(
+ const base::Value& response) {
+ // Only enroll requests have a response to parse, unenroll request responses
+ // are empty except for possible errors which are parsed in PaymentsClient.
+ if (request_details_.virtual_card_enrollment_request_type ==
+ VirtualCardEnrollmentRequestType::kEnroll) {
+ auto* enroll_result =
+ response.FindKeyOfType("enroll_result", base::Value::Type::STRING);
+ if (enroll_result) {
+ enroll_result_ = enroll_result->GetString();
+ }
+ }
+}
+
+bool UpdateVirtualCardEnrollmentRequest::IsResponseComplete() {
+ switch (request_details_.virtual_card_enrollment_request_type) {
+ case VirtualCardEnrollmentRequestType::kEnroll:
+ // If it is an enroll request, we know the response is complete if the
+ // response has an enroll result that is ENROLL_SUCCESS, as that is the
+ // only field in an enroll response other than the possible error.
+ return enroll_result_.has_value() && enroll_result_ == "ENROLL_SUCCESS";
+ case VirtualCardEnrollmentRequestType::kUnenroll:
+ // Unenroll responses are empty except for having an error. In
+ // PaymentsClient, if the response has an error it will be handled before
+ // we check IsResponseComplete(), so if we ever reach this branch we know
+ // the response completed successfully as there is no error. Thus, we
+ // always return true.
+ return true;
+ case VirtualCardEnrollmentRequestType::kNone:
+ NOTREACHED();
+ return false;
+ }
+}
+
+void UpdateVirtualCardEnrollmentRequest::RespondToDelegate(
+ AutofillClient::PaymentsRpcResult result) {
+ std::move(callback_).Run(result);
+}
+
+void UpdateVirtualCardEnrollmentRequest::BuildEnrollRequestDictionary(
+ base::Value* request_dict) {
+ DCHECK(request_details_.virtual_card_enrollment_request_type ==
+ VirtualCardEnrollmentRequestType::kEnroll);
+
+ // If it is an enroll request, we should always have a context token from the
+ // previous GetDetailsForEnroll request and we should not have an instrument
+ // id set in |request_details_|.
+ DCHECK(request_details_.vcn_context_token.has_value() &&
+ !request_details_.instrument_id.has_value());
+
+ // Builds the context and channel_type for this enroll request.
+ base::Value context(base::Value::Type::DICTIONARY);
+ switch (request_details_.virtual_card_enrollment_source) {
+ case VirtualCardEnrollmentSource::kUpstream:
+ context.SetKey("billable_service",
+ base::Value(kUploadCardBillableServiceNumber));
+ request_dict->SetKey("channel_type", base::Value("CHROME_UPSTREAM"));
+ break;
+ case VirtualCardEnrollmentSource::kDownstream:
+ // Downstream enroll is treated the same as settings page enroll because
+ // chrome client should already have a card synced from the server.
+ // Fall-through.
+ case VirtualCardEnrollmentSource::kSettingsPage:
+ context.SetKey("billable_service",
+ base::Value(kUnmaskCardBillableServiceNumber));
+ request_dict->SetKey("channel_type", base::Value("CHROME_DOWNSTREAM"));
+ break;
+ case VirtualCardEnrollmentSource::kNone:
+ NOTREACHED();
+ break;
+ }
+ if (request_details_.billing_customer_number != 0) {
+ context.SetKey("customer_context",
+ BuildCustomerContextDictionary(
+ request_details_.billing_customer_number));
+ }
+ request_dict->SetKey("context", std::move(context));
+
+ // Sets the virtual_card_enrollment_flow field in this enroll request which
+ // lets the server know whether the enrollment is happening with ToS or not.
+ // Chrome client requests will always be ENROLL_WITH_TOS. This field is
+ // necessary because virtual card enroll through other platforms enrolls
+ // without ToS, for example Web Push Provisioning.
+ request_dict->SetKey("virtual_card_enrollment_flow",
+ base::Value("ENROLL_WITH_TOS"));
+
+ // Sets the context_token field in this enroll request which is used by the
+ // server to link this enroll request to the previous
+ // GetDetailsForEnrollRequest, as well as to retrieve the specific credit card
+ // to enroll.
+ request_dict->SetKey("context_token",
+ base::Value(request_details_.vcn_context_token.value()));
+}
+
+void UpdateVirtualCardEnrollmentRequest::BuildUnenrollRequestDictionary(
+ base::Value* request_dict) {
+ DCHECK(request_details_.virtual_card_enrollment_request_type ==
+ VirtualCardEnrollmentRequestType::kUnenroll);
+
+ // If it is an unenroll request, we should always have an instrument id and we
+ // should not have a context token set in |request_details_|.
+ DCHECK(request_details_.instrument_id.has_value() &&
+ !request_details_.vcn_context_token.has_value());
+
+ // Builds the context for this unenroll request if a billing customer number
+ // is present.
+ if (request_details_.billing_customer_number != 0) {
+ base::Value context(base::Value::Type::DICTIONARY);
+ context.SetKey("customer_context",
+ BuildCustomerContextDictionary(
+ request_details_.billing_customer_number));
+ request_dict->SetKey("context", std::move(context));
+ }
+
+ // Sets the instrument_id field in this unenroll request which is used by
+ // the server to get the appropriate credit card to unenroll.
+ request_dict->SetKey("instrument_id",
+ base::Value(base::NumberToString(
+ request_details_.instrument_id.value())));
+}
+
+} // namespace payments
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/payments/payments_requests/update_virtual_card_enrollment_request.h b/chromium/components/autofill/core/browser/payments/payments_requests/update_virtual_card_enrollment_request.h
new file mode 100644
index 00000000000..4438448a922
--- /dev/null
+++ b/chromium/components/autofill/core/browser/payments/payments_requests/update_virtual_card_enrollment_request.h
@@ -0,0 +1,64 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_PAYMENTS_REQUESTS_UPDATE_VIRTUAL_CARD_ENROLLMENT_REQUEST_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_PAYMENTS_REQUESTS_UPDATE_VIRTUAL_CARD_ENROLLMENT_REQUEST_H_
+
+#include <string>
+
+#include "base/callback.h"
+#include "components/autofill/core/browser/autofill_client.h"
+#include "components/autofill/core/browser/payments/payments_client.h"
+#include "components/autofill/core/browser/payments/payments_requests/payments_request.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace base {
+class Value;
+} // namespace base
+
+namespace autofill {
+namespace payments {
+
+// Payments request to enroll or unenroll a credit card into a virtual card.
+// Virtual Card Numbers allow a user to check out online with a credit
+// card using a credit card number that is different from the credit card's
+// original number.
+class UpdateVirtualCardEnrollmentRequest : public PaymentsRequest {
+ public:
+ UpdateVirtualCardEnrollmentRequest(
+ const PaymentsClient::UpdateVirtualCardEnrollmentRequestDetails&
+ request_details,
+ base::OnceCallback<void(AutofillClient::PaymentsRpcResult)> callback);
+ UpdateVirtualCardEnrollmentRequest(
+ const UpdateVirtualCardEnrollmentRequest&) = delete;
+ UpdateVirtualCardEnrollmentRequest& operator=(
+ const UpdateVirtualCardEnrollmentRequest&) = delete;
+ ~UpdateVirtualCardEnrollmentRequest() override;
+
+ // PaymentsRequest:
+ std::string GetRequestUrlPath() override;
+ std::string GetRequestContentType() override;
+ std::string GetRequestContent() override;
+ void ParseResponse(const base::Value& response) override;
+ bool IsResponseComplete() override;
+ void RespondToDelegate(AutofillClient::PaymentsRpcResult result) override;
+
+ private:
+ // Modifies the base::Value that |request_dict| points to by setting all of
+ // the fields needed for an Enroll request.
+ void BuildEnrollRequestDictionary(base::Value* request_dict);
+
+ // Modifies the base::Value that |request_dict| points to by setting all of
+ // the fields needed for an Unenroll request.
+ void BuildUnenrollRequestDictionary(base::Value* request_dict);
+
+ PaymentsClient::UpdateVirtualCardEnrollmentRequestDetails request_details_;
+ base::OnceCallback<void(AutofillClient::PaymentsRpcResult)> callback_;
+ absl::optional<std::string> enroll_result_;
+};
+
+} // namespace payments
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_PAYMENTS_REQUESTS_UPDATE_VIRTUAL_CARD_ENROLLMENT_REQUEST_H_
diff --git a/chromium/components/autofill/core/browser/payments/payments_service_url.cc b/chromium/components/autofill/core/browser/payments/payments_service_url.cc
index d76574f73cb..165f0a43a3c 100644
--- a/chromium/components/autofill/core/browser/payments/payments_service_url.cc
+++ b/chromium/components/autofill/core/browser/payments/payments_service_url.cc
@@ -35,7 +35,10 @@ const char kSandboxPaymentsManageCardsUrl[] =
"https://pay.sandbox.google.com/payments/"
"home?utm_source=chrome&utm_medium=settings&utm_campaign=payment-methods#"
"paymentMethods";
-
+// LINT.IfChange
+const char kVirtualCardEnrollmentSupportUrl[] =
+ "https://support.google.com/googlepay/answer/11234179";
+// LINT.ThenChange(//chrome/android/java/src/org/chromium/chrome/browser/ChromeStringConstants.java)
} // namespace
namespace payments {
@@ -64,5 +67,9 @@ GURL GetManageAddressesUrl() {
return GetManageInstrumentsUrl();
}
+GURL GetVirtualCardEnrollmentSupportUrl() {
+ return GURL(kVirtualCardEnrollmentSupportUrl);
+}
+
} // namespace payments
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/payments/payments_service_url.h b/chromium/components/autofill/core/browser/payments/payments_service_url.h
index a4c5d232482..cbee4de66a0 100644
--- a/chromium/components/autofill/core/browser/payments/payments_service_url.h
+++ b/chromium/components/autofill/core/browser/payments/payments_service_url.h
@@ -24,6 +24,10 @@ GURL GetBaseSecureUrl();
GURL GetManageInstrumentsUrl();
GURL GetManageAddressesUrl();
+// Returns the support URL for users to learn more about virtual cards during
+// the virtual card enrollment bubble.
+GURL GetVirtualCardEnrollmentSupportUrl();
+
} // namespace payments
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/payments/test_authentication_requester.cc b/chromium/components/autofill/core/browser/payments/test_authentication_requester.cc
index 8daf48ead6f..17b1aa4699c 100644
--- a/chromium/components/autofill/core/browser/payments/test_authentication_requester.cc
+++ b/chromium/components/autofill/core/browser/payments/test_authentication_requester.cc
@@ -29,7 +29,7 @@ void TestAuthenticationRequester::OnCVCAuthenticationComplete(
}
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
bool TestAuthenticationRequester::ShouldOfferFidoAuth() const {
return false;
}
@@ -40,7 +40,7 @@ bool TestAuthenticationRequester::UserOptedInToFidoFromSettingsPageOnMobile()
}
#endif
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
void TestAuthenticationRequester::OnFIDOAuthenticationComplete(
const CreditCardFIDOAuthenticator::FidoAuthenticationResponse& response) {
did_succeed_ = response.did_succeed;
diff --git a/chromium/components/autofill/core/browser/payments/test_authentication_requester.h b/chromium/components/autofill/core/browser/payments/test_authentication_requester.h
index 063da0676ee..703d8cd07d5 100644
--- a/chromium/components/autofill/core/browser/payments/test_authentication_requester.h
+++ b/chromium/components/autofill/core/browser/payments/test_authentication_requester.h
@@ -14,7 +14,7 @@
#include "components/autofill/core/browser/payments/credit_card_otp_authenticator.h"
#include "components/autofill/core/browser/payments/full_card_request.h"
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
#include "components/autofill/core/browser/payments/credit_card_fido_authenticator.h"
#endif
@@ -22,7 +22,7 @@ namespace autofill {
// Test class for requesting authentication from CreditCardCVCAuthenticator or
// CreditCardFIDOAuthenticator.
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
class TestAuthenticationRequester
: public CreditCardCVCAuthenticator::Requester,
public CreditCardOtpAuthenticator::Requester {
@@ -40,12 +40,12 @@ class TestAuthenticationRequester
void OnCVCAuthenticationComplete(
const CreditCardCVCAuthenticator::CVCAuthenticationResponse& response)
override;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
bool ShouldOfferFidoAuth() const override;
bool UserOptedInToFidoFromSettingsPageOnMobile() const override;
#endif
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
// CreditCardFIDOAuthenticator::Requester:
void OnFIDOAuthenticationComplete(
const CreditCardFIDOAuthenticator::FidoAuthenticationResponse& response)
diff --git a/chromium/components/autofill/core/browser/payments/test_credit_card_fido_authenticator.cc b/chromium/components/autofill/core/browser/payments/test_credit_card_fido_authenticator.cc
index 896a9cdce32..cc7d6c3f576 100644
--- a/chromium/components/autofill/core/browser/payments/test_credit_card_fido_authenticator.cc
+++ b/chromium/components/autofill/core/browser/payments/test_credit_card_fido_authenticator.cc
@@ -58,10 +58,12 @@ void TestCreditCardFIDOAuthenticator::GetAssertion(
GetAssertionAuthenticatorResponse::New();
response->info = blink::mojom::CommonCredentialInfo::New();
fido_authenticator->OnDidGetAssertion(AuthenticatorStatus::SUCCESS,
- std::move(response));
+ std::move(response),
+ /*dom_exception_details=*/nullptr);
} else {
fido_authenticator->OnDidGetAssertion(
- AuthenticatorStatus::NOT_ALLOWED_ERROR, nullptr);
+ AuthenticatorStatus::NOT_ALLOWED_ERROR, nullptr,
+ /*dom_exception_details=*/nullptr);
}
}
@@ -74,10 +76,12 @@ void TestCreditCardFIDOAuthenticator::MakeCredential(
MakeCredentialAuthenticatorResponse::New();
response->info = blink::mojom::CommonCredentialInfo::New();
fido_authenticator->OnDidMakeCredential(AuthenticatorStatus::SUCCESS,
- std::move(response));
+ std::move(response),
+ /*dom_exception_details=*/nullptr);
} else {
fido_authenticator->OnDidMakeCredential(
- AuthenticatorStatus::NOT_ALLOWED_ERROR, nullptr);
+ AuthenticatorStatus::NOT_ALLOWED_ERROR, nullptr,
+ /*dom_exception_details=*/nullptr);
}
}
diff --git a/chromium/components/autofill/core/browser/payments/test_credit_card_save_manager.cc b/chromium/components/autofill/core/browser/payments/test_credit_card_save_manager.cc
index 6fa87d0d7ff..7d97e7b3d60 100644
--- a/chromium/components/autofill/core/browser/payments/test_credit_card_save_manager.cc
+++ b/chromium/components/autofill/core/browser/payments/test_credit_card_save_manager.cc
@@ -42,11 +42,22 @@ void TestCreditCardSaveManager::set_upload_request_card_number(
upload_request_.card.SetNumber(credit_card_number);
}
+void TestCreditCardSaveManager::set_upload_request_card(
+ const CreditCard& card) {
+ upload_request_.card = std::move(card);
+}
+
+raw_ptr<payments::PaymentsClient::UploadRequestDetails>
+TestCreditCardSaveManager::upload_request() {
+ return &upload_request_;
+}
+
void TestCreditCardSaveManager::OnDidUploadCard(
AutofillClient::PaymentsRpcResult result,
- const std::string& server_id) {
+ const payments::PaymentsClient::UploadCardResponseDetails&
+ upload_card_response_details) {
credit_card_was_uploaded_ = true;
- CreditCardSaveManager::OnDidUploadCard(result, server_id);
+ CreditCardSaveManager::OnDidUploadCard(result, upload_card_response_details);
}
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/payments/test_credit_card_save_manager.h b/chromium/components/autofill/core/browser/payments/test_credit_card_save_manager.h
index 0a90fdefd1f..4d54f6c8457 100644
--- a/chromium/components/autofill/core/browser/payments/test_credit_card_save_manager.h
+++ b/chromium/components/autofill/core/browser/payments/test_credit_card_save_manager.h
@@ -44,14 +44,22 @@ class TestCreditCardSaveManager : public CreditCardSaveManager {
void set_upload_request_card_number(const std::u16string& credit_card_number);
+ void set_upload_request_card(const CreditCard& card);
+
+ raw_ptr<payments::PaymentsClient::UploadRequestDetails> upload_request();
+
private:
- void OnDidUploadCard(AutofillClient::PaymentsRpcResult result,
- const std::string& server_id) override;
+ void OnDidUploadCard(
+ AutofillClient::PaymentsRpcResult result,
+ const payments::PaymentsClient::UploadCardResponseDetails&
+ upload_card_response_details) override;
bool credit_card_upload_enabled_ = false;
bool credit_card_was_uploaded_ = false;
FRIEND_TEST_ALL_PREFIXES(CreditCardSaveManagerTest,
+ OnDidUploadCard_VirtualCardEnrollment);
+ FRIEND_TEST_ALL_PREFIXES(CreditCardSaveManagerTest,
UploadCreditCard_NumStrikesLoggedOnUploadNotSuccess);
};
diff --git a/chromium/components/autofill/core/browser/payments/test_payments_client.cc b/chromium/components/autofill/core/browser/payments/test_payments_client.cc
index 4381fbe97a8..8956861456b 100644
--- a/chromium/components/autofill/core/browser/payments/test_payments_client.cc
+++ b/chromium/components/autofill/core/browser/payments/test_payments_client.cc
@@ -10,12 +10,11 @@
#include "base/json/json_reader.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
+#include "components/autofill/core/browser/autofill_client.h"
#include "components/autofill/core/browser/personal_data_manager.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
-namespace autofill {
-
-namespace payments {
+namespace autofill::payments {
namespace {
// Base64 encoding of "This is a test challenge".
@@ -34,7 +33,7 @@ TestPaymentsClient::TestPaymentsClient(
unmask_details_.unmask_auth_method = AutofillClient::UnmaskAuthMethod::kCvc;
}
-TestPaymentsClient::~TestPaymentsClient() {}
+TestPaymentsClient::~TestPaymentsClient() = default;
void TestPaymentsClient::GetUnmaskDetails(
base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
@@ -62,11 +61,13 @@ void TestPaymentsClient::GetUploadDetails(
std::unique_ptr<base::Value>,
std::vector<std::pair<int, int>>)> callback,
const int billable_service_number,
+ const int64_t billing_customer_number,
PaymentsClient::UploadCardSource upload_card_source) {
upload_details_addresses_ = addresses;
detected_values_ = detected_values;
active_experiments_ = active_experiments;
billable_service_number_ = billable_service_number;
+ billing_customer_number_ = billing_customer_number;
upload_card_source_ = upload_card_source;
std::move(callback).Run(
app_locale == "en-US"
@@ -79,11 +80,12 @@ void TestPaymentsClient::GetUploadDetails(
void TestPaymentsClient::UploadCard(
const payments::PaymentsClient::UploadRequestDetails& request_details,
base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
- const std::string&)> callback) {
+ const PaymentsClient::UploadCardResponseDetails&)>
+ callback) {
upload_card_addresses_ = request_details.profiles;
active_experiments_ = request_details.active_experiments;
std::move(callback).Run(AutofillClient::PaymentsRpcResult::kSuccess,
- server_id_);
+ upload_card_response_details_);
}
void TestPaymentsClient::MigrateCards(
@@ -110,6 +112,24 @@ void TestPaymentsClient::SelectChallengeOption(
"context_token from SelectChallengeOption");
}
+void TestPaymentsClient::GetVirtualCardEnrollmentDetails(
+ const GetDetailsForEnrollmentRequestDetails& request_details,
+ base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
+ const payments::PaymentsClient::
+ GetDetailsForEnrollmentResponseDetails&)>
+ callback) {
+ get_details_for_enrollment_request_details_ = std::move(request_details);
+}
+
+void TestPaymentsClient::UpdateVirtualCardEnrollment(
+ const TestPaymentsClient::UpdateVirtualCardEnrollmentRequestDetails&
+ request_details,
+ base::OnceCallback<void(AutofillClient::PaymentsRpcResult)> callback) {
+ update_virtual_card_enrollment_request_details_ = std::move(request_details);
+ std::move(callback).Run(update_virtual_card_enrollment_result_.value_or(
+ AutofillClient::PaymentsRpcResult::kSuccess));
+}
+
void TestPaymentsClient::ShouldReturnUnmaskDetailsImmediately(
bool should_return_unmask_details) {
should_return_unmask_details_ = should_return_unmask_details;
@@ -161,8 +181,10 @@ void TestPaymentsClient::AddFidoEligibleCard(std::string server_id,
->Append(std::move(key_info));
}
-void TestPaymentsClient::SetServerIdForCardUpload(std::string server_id) {
- server_id_ = server_id;
+void TestPaymentsClient::SetUploadCardResponseDetailsForUploadCard(
+ const PaymentsClient::UploadCardResponseDetails&
+ upload_card_response_details) {
+ upload_card_response_details_ = upload_card_response_details;
}
void TestPaymentsClient::SetSaveResultForCardsMigration(
@@ -209,5 +231,4 @@ std::unique_ptr<base::Value> TestPaymentsClient::LegalMessage() {
}
}
-} // namespace payments
-} // namespace autofill
+} // namespace autofill::payments
diff --git a/chromium/components/autofill/core/browser/payments/test_payments_client.h b/chromium/components/autofill/core/browser/payments/test_payments_client.h
index b4e795320cc..0f6357d40a5 100644
--- a/chromium/components/autofill/core/browser/payments/test_payments_client.h
+++ b/chromium/components/autofill/core/browser/payments/test_payments_client.h
@@ -14,13 +14,13 @@
#include "base/memory/raw_ptr.h"
#include "components/autofill/core/browser/payments/payments_client.h"
+#include "components/autofill/core/browser/payments/payments_requests/update_virtual_card_enrollment_request.h"
namespace network {
class SharedURLLoaderFactory;
} // namespace network
-namespace autofill {
-namespace payments {
+namespace autofill::payments {
class TestPaymentsClient : public payments::PaymentsClient {
public:
@@ -54,13 +54,15 @@ class TestPaymentsClient : public payments::PaymentsClient {
std::unique_ptr<base::Value>,
std::vector<std::pair<int, int>>)> callback,
const int billable_service_number,
+ const int64_t billing_customer_number,
UploadCardSource upload_card_source =
UploadCardSource::UNKNOWN_UPLOAD_CARD_SOURCE) override;
void UploadCard(
const payments::PaymentsClient::UploadRequestDetails& request_details,
base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
- const std::string&)> callback) override;
+ const PaymentsClient::UploadCardResponseDetails&)>
+ callback) override;
void MigrateCards(
const MigrationRequestDetails& details,
@@ -72,6 +74,18 @@ class TestPaymentsClient : public payments::PaymentsClient {
base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
const std::string&)> callback) override;
+ void GetVirtualCardEnrollmentDetails(
+ const GetDetailsForEnrollmentRequestDetails& request_details,
+ base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
+ const payments::PaymentsClient::
+ GetDetailsForEnrollmentResponseDetails&)>
+ callback) override;
+
+ void UpdateVirtualCardEnrollment(
+ const UpdateVirtualCardEnrollmentRequestDetails& request_details,
+ base::OnceCallback<void(AutofillClient::PaymentsRpcResult)> callback)
+ override;
+
// Some metrics are affected by the latency of GetUnmaskDetails, so it is
// useful to control whether or not GetUnmaskDetails() is responded to.
void ShouldReturnUnmaskDetailsImmediately(bool should_return_unmask_details);
@@ -82,7 +96,9 @@ class TestPaymentsClient : public payments::PaymentsClient {
std::string credential_id,
std::string relying_party_id);
- void SetServerIdForCardUpload(std::string);
+ void SetUploadCardResponseDetailsForUploadCard(
+ const PaymentsClient::UploadCardResponseDetails&
+ upload_card_response_details);
void SetSaveResultForCardsMigration(
std::unique_ptr<std::unordered_map<std::string, std::string>>
@@ -98,6 +114,11 @@ class TestPaymentsClient : public payments::PaymentsClient {
select_challenge_option_result_ = result;
}
+ void set_update_virtual_card_enrollment_result(
+ AutofillClient::PaymentsRpcResult result) {
+ update_virtual_card_enrollment_result_ = result;
+ }
+
payments::PaymentsClient::UnmaskDetails* unmask_details() {
return &unmask_details_;
}
@@ -121,12 +142,25 @@ class TestPaymentsClient : public payments::PaymentsClient {
int billable_service_number_in_request() const {
return billable_service_number_;
}
+ int64_t billing_customer_number_in_request() const {
+ return billing_customer_number_;
+ }
PaymentsClient::UploadCardSource upload_card_source_in_request() const {
return upload_card_source_;
}
+ const GetDetailsForEnrollmentRequestDetails&
+ get_details_for_enrollment_request_details() {
+ return get_details_for_enrollment_request_details_;
+ }
+
+ const UpdateVirtualCardEnrollmentRequestDetails&
+ update_virtual_card_enrollment_request_details() {
+ return update_virtual_card_enrollment_request_details_;
+ }
+
private:
- std::string server_id_;
+ PaymentsClient::UploadCardResponseDetails upload_card_response_details_;
// Some metrics are affected by the latency of GetUnmaskDetails, so it is
// useful to control whether or not GetUnmaskDetails() is responded to.
bool should_return_unmask_details_ = true;
@@ -142,15 +176,21 @@ class TestPaymentsClient : public payments::PaymentsClient {
std::string pan_first_six_;
std::vector<const char*> active_experiments_;
int billable_service_number_;
+ int64_t billing_customer_number_;
PaymentsClient::UploadCardSource upload_card_source_;
std::unique_ptr<std::unordered_map<std::string, std::string>> save_result_;
bool use_invalid_legal_message_ = false;
std::unique_ptr<base::Value> LegalMessage();
absl::optional<AutofillClient::PaymentsRpcResult>
select_challenge_option_result_;
+ absl::optional<AutofillClient::PaymentsRpcResult>
+ update_virtual_card_enrollment_result_;
+ payments::PaymentsClient::GetDetailsForEnrollmentRequestDetails
+ get_details_for_enrollment_request_details_;
+ payments::PaymentsClient::UpdateVirtualCardEnrollmentRequestDetails
+ update_virtual_card_enrollment_request_details_;
};
-} // namespace payments
-} // namespace autofill
+} // namespace autofill::payments
#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_TEST_PAYMENTS_CLIENT_H_
diff --git a/chromium/components/autofill/core/browser/payments/test_virtual_card_enrollment_manager.cc b/chromium/components/autofill/core/browser/payments/test_virtual_card_enrollment_manager.cc
new file mode 100644
index 00000000000..0fdf2515570
--- /dev/null
+++ b/chromium/components/autofill/core/browser/payments/test_virtual_card_enrollment_manager.cc
@@ -0,0 +1,44 @@
+// Copyright 2022 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.
+
+#include "components/autofill/core/browser/payments/test_virtual_card_enrollment_manager.h"
+#include "components/autofill/core/browser/payments/virtual_card_enrollment_flow.h"
+#include "components/autofill/core/browser/test_personal_data_manager.h"
+
+namespace autofill {
+
+TestVirtualCardEnrollmentManager::TestVirtualCardEnrollmentManager(
+ raw_ptr<TestPersonalDataManager> personal_data_manager,
+ raw_ptr<payments::TestPaymentsClient> payments_client,
+ raw_ptr<TestAutofillClient> autofill_client = nullptr)
+ : VirtualCardEnrollmentManager(personal_data_manager,
+ payments_client,
+ autofill_client) {}
+
+TestVirtualCardEnrollmentManager::~TestVirtualCardEnrollmentManager() = default;
+
+void TestVirtualCardEnrollmentManager::LoadRiskDataAndContinueFlow(
+ raw_ptr<PrefService> user_prefs,
+ base::OnceCallback<void(const std::string&)> callback) {
+ std::move(callback).Run("some risk data");
+}
+
+void TestVirtualCardEnrollmentManager::
+ OnDidGetUpdateVirtualCardEnrollmentResponse(
+ VirtualCardEnrollmentRequestType type,
+ AutofillClient::PaymentsRpcResult result) {
+ result_ = result;
+ VirtualCardEnrollmentManager::OnDidGetUpdateVirtualCardEnrollmentResponse(
+ type, result);
+}
+
+void TestVirtualCardEnrollmentManager::Reset() {
+ reset_called_ = true;
+}
+
+void TestVirtualCardEnrollmentManager::ShowVirtualCardEnrollBubble() {
+ bubble_shown_ = true;
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/payments/test_virtual_card_enrollment_manager.h b/chromium/components/autofill/core/browser/payments/test_virtual_card_enrollment_manager.h
new file mode 100644
index 00000000000..652d080568a
--- /dev/null
+++ b/chromium/components/autofill/core/browser/payments/test_virtual_card_enrollment_manager.h
@@ -0,0 +1,84 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_TEST_VIRTUAL_CARD_ENROLLMENT_MANAGER_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_TEST_VIRTUAL_CARD_ENROLLMENT_MANAGER_H_
+
+#include "base/memory/raw_ptr.h"
+#include "components/autofill/core/browser/payments/virtual_card_enrollment_manager.h"
+#include "components/autofill/core/browser/test_autofill_client.h"
+
+namespace autofill {
+
+class TestPersonalDataManager;
+
+class TestVirtualCardEnrollmentManager : public VirtualCardEnrollmentManager {
+ public:
+ TestVirtualCardEnrollmentManager(
+ raw_ptr<TestPersonalDataManager> personal_data_manager,
+ raw_ptr<payments::TestPaymentsClient> payments_client,
+ raw_ptr<TestAutofillClient> autofill_client);
+ TestVirtualCardEnrollmentManager(const TestVirtualCardEnrollmentManager&) =
+ delete;
+ TestVirtualCardEnrollmentManager& operator=(
+ const TestVirtualCardEnrollmentManager&) = delete;
+ ~TestVirtualCardEnrollmentManager() override;
+
+ bool GetAvatarAnimationComplete() const { return avatar_animation_complete_; }
+
+ bool GetEnrollResponseDetailsReceived() const {
+ return enroll_response_details_received_;
+ }
+
+ AutofillClient::PaymentsRpcResult GetPaymentsRpcResult() { return result_; }
+
+ void SetPaymentsRpcResult(AutofillClient::PaymentsRpcResult result) {
+ result_ = result;
+ }
+
+ bool GetResetCalled() { return reset_called_; }
+
+ void SetResetCalled(bool reset_called) { reset_called_ = reset_called; }
+
+ bool GetBubbleShown() { return bubble_shown_; }
+
+ raw_ptr<VirtualCardEnrollmentProcessState>
+ GetVirtualCardEnrollmentProcessState() {
+ return &state_;
+ }
+
+ void SetAutofillClient(raw_ptr<AutofillClient> autofill_client) {
+ autofill_client_ = autofill_client;
+ }
+
+ void SetVirtualCardEnrollmentFieldsLoadedCallback(
+ VirtualCardEnrollmentFieldsLoadedCallback
+ virtual_card_enrollment_fields_loaded_callback) {
+ virtual_card_enrollment_fields_loaded_callback_ =
+ std::move(virtual_card_enrollment_fields_loaded_callback);
+ }
+
+ bool AutofillClientIsPresent() { return autofill_client_ != nullptr; }
+
+ // VirtualCardEnrollmentManager:
+ void LoadRiskDataAndContinueFlow(
+ raw_ptr<PrefService> user_prefs,
+ base::OnceCallback<void(const std::string&)> callback) override;
+ void OnDidGetUpdateVirtualCardEnrollmentResponse(
+ VirtualCardEnrollmentRequestType type,
+ AutofillClient::PaymentsRpcResult result) override;
+ void Reset() override;
+ void ShowVirtualCardEnrollBubble() override;
+
+ private:
+ AutofillClient::PaymentsRpcResult result_;
+
+ bool reset_called_ = false;
+
+ bool bubble_shown_ = false;
+};
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_TEST_VIRTUAL_CARD_ENROLLMENT_MANAGER_H_
diff --git a/chromium/components/autofill/core/browser/payments/virtual_card_enrollment_flow.h b/chromium/components/autofill/core/browser/payments/virtual_card_enrollment_flow.h
new file mode 100644
index 00000000000..9c66297cd10
--- /dev/null
+++ b/chromium/components/autofill/core/browser/payments/virtual_card_enrollment_flow.h
@@ -0,0 +1,43 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_VIRTUAL_CARD_ENROLLMENT_FLOW_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_VIRTUAL_CARD_ENROLLMENT_FLOW_H_
+
+namespace autofill {
+
+// This enum is used to denote the specific source that the virtual card
+// enrollment process originated from.
+enum class VirtualCardEnrollmentSource {
+ // Default value, should never be used.
+ kNone = 0,
+ // Offering VCN Enrollment after Upstream, i.e., saving a card to Google
+ // Payments.
+ kUpstream = 1,
+ // Offering VCN Enrollment after Downstream, i.e., unmasking a card from
+ // Google Payments.
+ kDownstream = 2,
+ // Offering VCN Enrollment from the payment methods settings page.
+ kSettingsPage = 3,
+ // Max value, needs to be updated every time a new enum is added.
+ kMaxValue = kSettingsPage,
+};
+
+// Denotes the request type for an UpdateVirtualCardEnrollmentRequest.
+enum class VirtualCardEnrollmentRequestType {
+ // Default value, should never be used.
+ kNone = 0,
+ // The corresponding UpdateVirtualCardEnrollmentRequest is an enroll
+ // request.
+ kEnroll = 1,
+ // The corresponding UpdateVirtualCardEnrollmentRequest is an unenroll
+ // request.
+ kUnenroll = 2,
+ // Max value, needs to be updated every time a new enum is added.
+ kMaxValue = kUnenroll,
+};
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_VIRTUAL_CARD_ENROLLMENT_FLOW_H_
diff --git a/chromium/components/autofill/core/browser/payments/virtual_card_enrollment_manager.cc b/chromium/components/autofill/core/browser/payments/virtual_card_enrollment_manager.cc
new file mode 100644
index 00000000000..f6bf1fe7782
--- /dev/null
+++ b/chromium/components/autofill/core/browser/payments/virtual_card_enrollment_manager.cc
@@ -0,0 +1,325 @@
+// Copyright 2021 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.
+
+#include "components/autofill/core/browser/payments/virtual_card_enrollment_manager.h"
+
+#include "components/autofill/core/browser/autofill_client.h"
+#include "components/autofill/core/browser/data_model/credit_card.h"
+#include "components/autofill/core/browser/metrics/payments/virtual_card_enrollment_metrics.h"
+#include "components/autofill/core/browser/payments/payments_util.h"
+#include "components/autofill/core/browser/payments/virtual_card_enrollment_flow.h"
+#include "components/autofill/core/browser/personal_data_manager.h"
+#include "components/autofill/core/browser/strike_database.h"
+#include "components/autofill/core/browser/strike_database_base.h"
+#include "components/autofill/core/common/autofill_payments_features.h"
+#include "ui/gfx/image/image.h"
+
+namespace autofill {
+
+VirtualCardEnrollmentFields::VirtualCardEnrollmentFields() = default;
+VirtualCardEnrollmentFields::VirtualCardEnrollmentFields(
+ const VirtualCardEnrollmentFields&) = default;
+VirtualCardEnrollmentFields& VirtualCardEnrollmentFields::operator=(
+ const VirtualCardEnrollmentFields&) = default;
+VirtualCardEnrollmentFields::~VirtualCardEnrollmentFields() = default;
+
+VirtualCardEnrollmentProcessState::VirtualCardEnrollmentProcessState() =
+ default;
+VirtualCardEnrollmentProcessState::VirtualCardEnrollmentProcessState(
+ const VirtualCardEnrollmentProcessState&) = default;
+VirtualCardEnrollmentProcessState& VirtualCardEnrollmentProcessState::operator=(
+ const VirtualCardEnrollmentProcessState&) = default;
+
+VirtualCardEnrollmentProcessState::~VirtualCardEnrollmentProcessState() =
+ default;
+
+VirtualCardEnrollmentManager::VirtualCardEnrollmentManager(
+ raw_ptr<PersonalDataManager> personal_data_manager,
+ raw_ptr<payments::PaymentsClient> payments_client,
+ raw_ptr<AutofillClient> autofill_client)
+ : autofill_client_(autofill_client),
+ personal_data_manager_(personal_data_manager),
+ payments_client_(payments_client) {
+ if (autofill_client_) {
+ StrikeDatabaseBase* strike_database = autofill_client->GetStrikeDatabase();
+ virtual_card_enrollment_strike_database_ =
+ std::make_unique<VirtualCardEnrollmentStrikeDatabase>(strike_database);
+ }
+}
+
+VirtualCardEnrollmentManager::~VirtualCardEnrollmentManager() = default;
+
+void VirtualCardEnrollmentManager::OfferVirtualCardEnroll(
+ const CreditCard& credit_card,
+ VirtualCardEnrollmentSource virtual_card_enrollment_source,
+ const raw_ptr<PrefService> user_prefs,
+ RiskAssessmentFunction risk_assessment_function,
+ VirtualCardEnrollmentFieldsLoadedCallback
+ virtual_card_enrollment_fields_loaded_callback) {
+ Reset();
+ DCHECK_NE(virtual_card_enrollment_source, VirtualCardEnrollmentSource::kNone);
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
+ // Hide the bubble and icon if it is already showing for a previous enrollment
+ // bubble.
+ DCHECK(autofill_client_);
+ autofill_client_->HideVirtualCardEnrollBubbleAndIconIfVisible();
+#endif
+ state_.virtual_card_enrollment_fields.credit_card = credit_card;
+ risk_assessment_function_ = std::move(risk_assessment_function);
+ virtual_card_enrollment_fields_loaded_callback_ =
+ std::move(virtual_card_enrollment_fields_loaded_callback);
+ // The |card_art_image| might not be synced yet from the sync server which
+ // will result in a nullptr. This situation can occur in the upstream flow. If
+ // it is not synced, GetCreditCardArtImageForUrl() will send a fetch request
+ // to sync the |card_art_image|, and before showing the
+ // VirtualCardEnrollmentBubble we will try to fetch the |card_art_image| from
+ // the local cache.
+ state_.virtual_card_enrollment_fields.card_art_image =
+ personal_data_manager_->GetCreditCardArtImageForUrl(
+ credit_card.card_art_url());
+
+ state_.virtual_card_enrollment_fields.virtual_card_enrollment_source =
+ virtual_card_enrollment_source;
+
+ LoadRiskDataAndContinueFlow(
+ user_prefs,
+ base::BindOnce(
+ &VirtualCardEnrollmentManager::OnRiskDataLoadedForVirtualCard,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void VirtualCardEnrollmentManager::OnCardSavedAnimationComplete() {
+ if (state_.virtual_card_enrollment_fields.virtual_card_enrollment_source ==
+ VirtualCardEnrollmentSource::kUpstream) {
+ avatar_animation_complete_ = true;
+
+ if (enroll_response_details_received_)
+ ShowVirtualCardEnrollBubble();
+ }
+}
+
+void VirtualCardEnrollmentManager::Enroll() {
+ LogUpdateVirtualCardEnrollmentRequestAttempt(
+ state_.virtual_card_enrollment_fields.virtual_card_enrollment_source,
+ VirtualCardEnrollmentRequestType::kEnroll);
+ payments::PaymentsClient::UpdateVirtualCardEnrollmentRequestDetails
+ request_details;
+ request_details.virtual_card_enrollment_source =
+ state_.virtual_card_enrollment_fields.virtual_card_enrollment_source;
+ request_details.virtual_card_enrollment_request_type =
+ VirtualCardEnrollmentRequestType::kEnroll;
+ request_details.billing_customer_number =
+ payments::GetBillingCustomerId(personal_data_manager_);
+ request_details.vcn_context_token = state_.vcn_context_token;
+
+ payments_client_->UpdateVirtualCardEnrollment(
+ request_details,
+ base::BindOnce(&VirtualCardEnrollmentManager::
+ OnDidGetUpdateVirtualCardEnrollmentResponse,
+ weak_ptr_factory_.GetWeakPtr(),
+ VirtualCardEnrollmentRequestType::kEnroll));
+}
+
+void VirtualCardEnrollmentManager::Unenroll(int64_t instrument_id) {
+ LogUpdateVirtualCardEnrollmentRequestAttempt(
+ VirtualCardEnrollmentSource::kSettingsPage,
+ VirtualCardEnrollmentRequestType::kUnenroll);
+
+ payments::PaymentsClient::UpdateVirtualCardEnrollmentRequestDetails
+ request_details;
+ state_.virtual_card_enrollment_fields.virtual_card_enrollment_source =
+ VirtualCardEnrollmentSource::kSettingsPage;
+
+ // Unenroll can only happen from the settings page.
+ request_details.virtual_card_enrollment_source =
+ VirtualCardEnrollmentSource::kSettingsPage;
+
+ request_details.virtual_card_enrollment_request_type =
+ VirtualCardEnrollmentRequestType::kUnenroll;
+ request_details.billing_customer_number =
+ payments::GetBillingCustomerId(personal_data_manager_);
+ request_details.instrument_id = instrument_id;
+
+ payments_client_->UpdateVirtualCardEnrollment(
+ request_details,
+ base::BindOnce(&VirtualCardEnrollmentManager::
+ OnDidGetUpdateVirtualCardEnrollmentResponse,
+ weak_ptr_factory_.GetWeakPtr(),
+ VirtualCardEnrollmentRequestType::kUnenroll));
+}
+
+bool VirtualCardEnrollmentManager::IsVirtualCardEnrollmentBlocked(
+ const std::string& guid) const {
+ return GetVirtualCardEnrollmentStrikeDatabase() &&
+ GetVirtualCardEnrollmentStrikeDatabase()->IsMaxStrikesLimitReached(
+ guid);
+}
+
+void VirtualCardEnrollmentManager::
+ AddStrikeToBlockOfferingVirtualCardEnrollment(const std::string& guid) {
+ if (!GetVirtualCardEnrollmentStrikeDatabase())
+ return;
+
+ GetVirtualCardEnrollmentStrikeDatabase()->AddStrike(guid);
+}
+
+void VirtualCardEnrollmentManager::
+ RemoveAllStrikesToBlockOfferingVirtualCardEnrollment(
+ const std::string& guid) {
+ if (!GetVirtualCardEnrollmentStrikeDatabase())
+ return;
+
+ GetVirtualCardEnrollmentStrikeDatabase()->ClearStrikes(guid);
+}
+
+void VirtualCardEnrollmentManager::OnDidGetUpdateVirtualCardEnrollmentResponse(
+ VirtualCardEnrollmentRequestType type,
+ AutofillClient::PaymentsRpcResult result) {
+ LogUpdateVirtualCardEnrollmentRequestResult(
+ state_.virtual_card_enrollment_fields.virtual_card_enrollment_source,
+ type, result == AutofillClient::PaymentsRpcResult::kSuccess);
+ Reset();
+}
+
+void VirtualCardEnrollmentManager::Reset() {
+ payments_client_->CancelRequest();
+ weak_ptr_factory_.InvalidateWeakPtrs();
+ state_ = VirtualCardEnrollmentProcessState();
+ avatar_animation_complete_ = false;
+ enroll_response_details_received_ = false;
+}
+
+VirtualCardEnrollmentStrikeDatabase*
+VirtualCardEnrollmentManager::GetVirtualCardEnrollmentStrikeDatabase() const {
+ return virtual_card_enrollment_strike_database_.get();
+}
+
+void VirtualCardEnrollmentManager::LoadRiskDataAndContinueFlow(
+ raw_ptr<PrefService> user_prefs,
+ base::OnceCallback<void(const std::string&)> callback) {
+ if (autofill_client_) {
+ autofill_client_->LoadRiskData(std::move(callback));
+ } else {
+ // No |autofill_client_| present indicates we are in the clank settings page
+ // use case, so we load risk data using a method that does not require web
+ // contents to be present.
+ std::move(risk_assessment_function_)
+ .Run(/*obfuscated_gaia_id=*/0, user_prefs, std::move(callback), nullptr,
+ gfx::Rect());
+ }
+}
+
+void VirtualCardEnrollmentManager::ShowVirtualCardEnrollBubble() {
+ DCHECK(autofill_client_);
+ autofill_client_->ShowVirtualCardEnrollDialog(
+ state_.virtual_card_enrollment_fields,
+ base::BindOnce(&VirtualCardEnrollmentManager::Enroll,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::BindOnce(
+ &VirtualCardEnrollmentManager::OnVirtualCardEnrollmentBubbleCancelled,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void VirtualCardEnrollmentManager::OnRiskDataLoadedForVirtualCard(
+ const std::string& risk_data) {
+ state_.risk_data = risk_data;
+ GetDetailsForEnroll();
+}
+
+void VirtualCardEnrollmentManager::GetDetailsForEnroll() {
+ payments::PaymentsClient::GetDetailsForEnrollmentRequestDetails
+ request_details;
+ request_details.app_locale = personal_data_manager_->app_locale();
+ request_details.risk_data = state_.risk_data.value_or("");
+ request_details.billing_customer_number =
+ payments::GetBillingCustomerId(personal_data_manager_);
+ request_details.instrument_id =
+ state_.virtual_card_enrollment_fields.credit_card.instrument_id();
+ request_details.source =
+ state_.virtual_card_enrollment_fields.virtual_card_enrollment_source;
+ payments_client_->GetVirtualCardEnrollmentDetails(
+ request_details,
+ base::BindOnce(
+ &VirtualCardEnrollmentManager::OnDidGetDetailsForEnrollResponse,
+ weak_ptr_factory_.GetWeakPtr()));
+
+ LogGetDetailsForEnrollmentRequestAttempt(request_details.source);
+}
+
+void VirtualCardEnrollmentManager::OnDidGetDetailsForEnrollResponse(
+ AutofillClient::PaymentsRpcResult result,
+ const payments::PaymentsClient::GetDetailsForEnrollmentResponseDetails&
+ response) {
+ enroll_response_details_received_ = true;
+
+ LogGetDetailsForEnrollmentRequestResult(
+ state_.virtual_card_enrollment_fields.virtual_card_enrollment_source,
+ /*succeeded=*/result == AutofillClient::PaymentsRpcResult::kSuccess);
+
+ // Show the virtual card permanent error dialog if server explicitly returned
+ // permanent error, show temporary error dialog for the rest of the failure
+ // cases since currently only virtual card is supported.
+ if (result != AutofillClient::PaymentsRpcResult::kSuccess) {
+ // Showing an error dialog here would provide a confusing user experience as
+ // it is an error for a flow that is not user-initiated, so we fail
+ // silently.
+ Reset();
+ return;
+ }
+
+ state_.virtual_card_enrollment_fields.google_legal_message =
+ std::move(response.google_legal_message);
+ // Issuer legal message is empty for some issuers.
+ if (!response.issuer_legal_message.empty()) {
+ state_.virtual_card_enrollment_fields.issuer_legal_message =
+ std::move(response.issuer_legal_message);
+ }
+
+ // The |vcn_context_token| will be used by the server to link the previous
+ // GetDetailsForEnrollRequest to the future UpdateVirtualCardEnrollmentRequest
+ // if the user decides to enroll |state_|'s |virtual_card_enrollment_fields|'s
+ // |credit_card| as a virtual card.
+ state_.vcn_context_token = response.vcn_context_token;
+
+ // Tries to get the card art image again from the local cache. If the card art
+ // image is not available, then |state_|'s |virtual_card_enrollment_fields|'s
+ // |card_art_image| will be nullptr. The view will set it to the network image
+ // if it ends up being nullptr. The card art image might not be present
+ // in the upstream flow if the sync server has not synced the card art image
+ // yet.
+ if (!state_.virtual_card_enrollment_fields.card_art_image) {
+ state_.virtual_card_enrollment_fields.card_art_image =
+ personal_data_manager_->GetCachedCardArtImageForUrl(
+ state_.virtual_card_enrollment_fields.credit_card.card_art_url());
+ }
+
+#if !BUILDFLAG(IS_ANDROID)
+ if (base::FeatureList::IsEnabled(
+ features::kAutofillEnableToolbarStatusChip) &&
+ base::FeatureList::IsEnabled(
+ features::kAutofillCreditCardUploadFeedback) &&
+ state_.virtual_card_enrollment_fields.virtual_card_enrollment_source ==
+ VirtualCardEnrollmentSource::kUpstream &&
+ !avatar_animation_complete_) {
+ return;
+ }
+#endif
+
+ if (autofill_client_) {
+ ShowVirtualCardEnrollBubble();
+ } else {
+ // If the `autofill_client_` is not present, it means that the request is
+ // from Android settings page, thus run the callback with the
+ // `virtual_card_enrollment_fields_`, which would show the enrollment
+ // dialog.
+ std::move(virtual_card_enrollment_fields_loaded_callback_)
+ .Run(&state_.virtual_card_enrollment_fields);
+ }
+}
+
+void VirtualCardEnrollmentManager::OnVirtualCardEnrollmentBubbleCancelled() {
+ Reset();
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/payments/virtual_card_enrollment_manager.h b/chromium/components/autofill/core/browser/payments/virtual_card_enrollment_manager.h
new file mode 100644
index 00000000000..7c4635e28d6
--- /dev/null
+++ b/chromium/components/autofill/core/browser/payments/virtual_card_enrollment_manager.h
@@ -0,0 +1,279 @@
+// Copyright 2021 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.
+
+#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_VIRTUAL_CARD_ENROLLMENT_MANAGER_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_VIRTUAL_CARD_ENROLLMENT_MANAGER_H_
+
+#include <string>
+
+#include "base/memory/raw_ptr.h"
+#include "components/autofill/core/browser/autofill_client.h"
+#include "components/autofill/core/browser/payments/payments_client.h"
+#include "components/autofill/core/browser/payments/virtual_card_enrollment_flow.h"
+#include "components/autofill/core/browser/payments/virtual_card_enrollment_strike_database.h"
+#include "ui/gfx/geometry/rect.h"
+
+namespace content {
+class WebContents;
+}
+
+namespace gfx {
+class Image;
+}
+
+namespace autofill {
+
+class CreditCard;
+class PersonalDataManager;
+
+// This struct is passed into the controller when we show the
+// VirtualCardEnrollmentBubble, and it lets the controller customize the
+// bubble based on the fields in this struct. For example, we will show
+// different last 4 digits of a credit card based on the |credit_card| object
+// in this struct.
+struct VirtualCardEnrollmentFields {
+ VirtualCardEnrollmentFields();
+ VirtualCardEnrollmentFields(const VirtualCardEnrollmentFields&);
+ VirtualCardEnrollmentFields& operator=(const VirtualCardEnrollmentFields&);
+ ~VirtualCardEnrollmentFields();
+ // The credit card to enroll.
+ CreditCard credit_card;
+ // Raw pointer to the image for the card art. The |card_art_image| object is
+ // owned by PersonalDataManager.
+ raw_ptr<gfx::Image> card_art_image = nullptr;
+ // The Google-specific legal messages that the user must accept before
+ // opting-in to virtual card enrollment.
+ LegalMessageLines google_legal_message;
+ // The Issuer-specific legal messages that the user must accept before
+ // opting-in to virtual card enrollment. Empty for some issuers.
+ LegalMessageLines issuer_legal_message;
+ // The source for which the VirtualCardEnrollmentBubble will be shown.
+ VirtualCardEnrollmentSource virtual_card_enrollment_source =
+ VirtualCardEnrollmentSource::kNone;
+};
+
+// This struct is used to track the state of the virtual card enrollment
+// process, and its members are read from and written to throughout the process
+// where needed. It is created and owned by VirtualCardEnrollmentManager.
+struct VirtualCardEnrollmentProcessState {
+ VirtualCardEnrollmentProcessState();
+ VirtualCardEnrollmentProcessState(const VirtualCardEnrollmentProcessState&);
+ VirtualCardEnrollmentProcessState& operator=(
+ const VirtualCardEnrollmentProcessState&);
+ ~VirtualCardEnrollmentProcessState();
+ // Only populated once the risk engine responded.
+ absl::optional<std::string> risk_data;
+ // |virtual_card_enrollment_fields|'s |credit_card| and
+ // |virtual_card_enrollment_source| are populated in the beginning of the
+ // virtual card enrollment flow, but the rest of the fields are only populated
+ // before showing the VirtualCardEnrollmentBubble.
+ VirtualCardEnrollmentFields virtual_card_enrollment_fields;
+ // Populated after the GetDetailsForEnrollResponseDetails are received. Based
+ // on the |vcn_context_token| the server is able to retrieve the instrument
+ // id, and using |vcn_context_token| for enroll allows the server to link a
+ // GetDetailsForEnrollRequest with the corresponding
+ // UpdateVirtualCardEnrollmentRequest for the enroll process.
+ absl::optional<std::string> vcn_context_token;
+};
+
+// Owned by FormDataImporter. There is one instance of this class per tab. This
+// class manages the flow for enrolling and unenrolling in Virtual Card
+// Numbers.
+class VirtualCardEnrollmentManager {
+ public:
+ // The parameters should outlive the VirtualCardEnrollmentManager.
+ VirtualCardEnrollmentManager(
+ raw_ptr<PersonalDataManager> personal_data_manager,
+ raw_ptr<payments::PaymentsClient> payments_client,
+ raw_ptr<AutofillClient> autofill_client = nullptr);
+ VirtualCardEnrollmentManager(const VirtualCardEnrollmentManager&) = delete;
+ VirtualCardEnrollmentManager& operator=(const VirtualCardEnrollmentManager&) =
+ delete;
+ virtual ~VirtualCardEnrollmentManager();
+
+ using RiskAssessmentFunction = base::OnceCallback<void(
+ uint64_t obfuscated_gaia_id,
+ raw_ptr<PrefService> user_prefs,
+ base::OnceCallback<void(const std::string&)> callback,
+ const raw_ptr<content::WebContents> web_contents,
+ gfx::Rect window_bounds)>;
+
+ using VirtualCardEnrollmentFieldsLoadedCallback = base::OnceCallback<void(
+ VirtualCardEnrollmentFields* virtual_card_enrollment_fields)>;
+
+ // Starting point for the VCN enroll flow. The fields in |credit_card| will
+ // be used throughout the flow, such as for request fields as well as credit
+ // card specific fields for the bubble to display.
+ // |virtual_card_enrollment_source| will be used by
+ // ShowVirtualCardEnrollBubble() to differentiate different bubbles based on
+ // the source we originated from.
+ void OfferVirtualCardEnroll(
+ const CreditCard& credit_card,
+ VirtualCardEnrollmentSource virtual_card_enrollment_source,
+ // |user_prefs| will be populated if we are in the Android settings page,
+ // to then be used for loading risk data. Otherwise it will always be
+ // nullptr, and we should load risk data through |autofill_client_| as we
+ // have access to web contents.
+ const raw_ptr<PrefService> user_prefs = nullptr,
+ // Callback that will be run in the Android settings page use cases. It
+ // will take in a |callback|, |obfuscated_gaia_id|, and |user_prefs| that
+ // will end up being passed into the overloaded risk_util::LoadRiskData()
+ // call that does not require web contents.
+ RiskAssessmentFunction risk_assessment_function = base::DoNothing(),
+ // Callback that be run once the `state_.virtual_card_enrollment_fields_`
+ // is loaded from the server response. The callback would trigger the
+ // enrollment dialog in the Settings page on Android.
+ VirtualCardEnrollmentFieldsLoadedCallback = base::DoNothing());
+
+ // Updates |avatar_animation_complete| to true if the user is beginning the
+ // upstream enrollment flow. This is a prerequisite to showing the enrollment
+ // bubble.
+ void OnCardSavedAnimationComplete();
+
+ // Uses |payments_client_| to send the enroll request. |state_|'s
+ // |vcn_context_token_|, which should be set when we receive the
+ // GetDetailsForEnrollResponse, is used in the
+ // UpdateVirtualCardEnrollmentRequest to enroll the correct card.
+ void Enroll();
+
+ // Unenrolls the card mapped to the given |instrument_id|.
+ void Unenroll(int64_t instrument_id);
+
+ // Returns true if a credit card identified by its |guid| is blocked for
+ // virtual card enrollment. Does nothing if the strike database is not
+ // available.
+ bool IsVirtualCardEnrollmentBlocked(const std::string& guid) const;
+
+ // Adds a strike to block enrollment for credit card identified by its |guid|.
+ // Does nothing if the strike database is not available.
+ void AddStrikeToBlockOfferingVirtualCardEnrollment(const std::string& guid);
+
+ // Removes potential strikes to block a credit card identified by its |guid|
+ // for enrollment. Does nothing if the strike database is not available.
+ void RemoveAllStrikesToBlockOfferingVirtualCardEnrollment(
+ const std::string& guid);
+
+ protected:
+ // Handles the response from the UpdateVirtualCardEnrollmentRequest. |type|
+ // indicates the type of the request sent, i.e., enroll or unenroll.
+ // |result| represents the result from the server call to change the virtual
+ // card enrollment state for the credit card passed into
+ // OfferVirtualCardEnroll().
+ virtual void OnDidGetUpdateVirtualCardEnrollmentResponse(
+ VirtualCardEnrollmentRequestType type,
+ AutofillClient::PaymentsRpcResult result);
+
+ // Resets the state of this VirtualCardEnrollmentManager.
+ virtual void Reset();
+
+ // Data in |state_| will be populated with the data we have at the current
+ // point of the virtual card enrollment flow we are in. This data will then be
+ // used by future points of the flow for actions such as populating request
+ // fields, and sending data to the VirtualCardEnrollmentBubbleController to
+ // display in the UI. VirtualCardEnrollmentManager::Reset() will reset
+ // |state_|.
+ VirtualCardEnrollmentProcessState state_;
+
+ // The associated autofill client, used to load risk data and show the
+ // VirtualCardEnrollBubble. Weak reference. Can be nullptr, which indicates
+ // that we are in the Clank settings page, from which Autofill Client is not
+ // accessible.
+ raw_ptr<AutofillClient> autofill_client_;
+
+ // Used to get a pointer to the strike database for virtual card enrollment.
+ VirtualCardEnrollmentStrikeDatabase* GetVirtualCardEnrollmentStrikeDatabase()
+ const;
+
+ // Whether the card saved avatar animation has been completed on upstream
+ // enrollment flow.
+ bool avatar_animation_complete_ = false;
+
+ // Whether we've received GetDetailsForEnrollResponseDetails.
+ bool enroll_response_details_received_ = false;
+
+ // Loads risk data for the respective use case and then continues the virtual
+ // card enrollment flow. |user_prefs| will only be present in Clank settings
+ // page use cases, as we will not have access to web contents.
+ virtual void LoadRiskDataAndContinueFlow(
+ raw_ptr<PrefService> user_prefs,
+ base::OnceCallback<void(const std::string&)> callback);
+
+ // Shows the VirtualCardEnrollmentBubble. |state_|'s
+ // |virtual_card_enrollment_fields| will contain all of the dynamic fields
+ // VirtualCardEnrollmentBubbleController needs to display the correct bubble.
+ virtual void ShowVirtualCardEnrollBubble();
+
+ // Callback triggered after the VirtualCardEnrollmentFields are loaded from
+ // the server response. Note: This is only called when the `autofill_client_`
+ // is not available.
+ VirtualCardEnrollmentFieldsLoadedCallback
+ virtual_card_enrollment_fields_loaded_callback_;
+
+ private:
+ // Called once the risk data is loaded. The |risk_data| will be used with
+ // |state_|'s |virtual_card_enrollment_fields|'s |credit_card|'s
+ // |instrument_id_| field to make a GetDetailsForEnroll request, and
+ // |state_|'s |virtual_card_enrollment_source| will be passed down to when we
+ // show the bubble so that we show the correct bubble version.
+ void OnRiskDataLoadedForVirtualCard(const std::string& risk_data);
+
+ // Sends the GetDetailsForEnrollRequest using |payments_client_|. |state_|'s
+ // |risk_data| and its |virtual_card_enrollment_fields|'s |credit_card|'s
+ // |instrument_id| are the fields the server requires for the
+ // GetDetailsForEnrollRequest, and will be used by |payments_client_|.
+ // |state_|'s |virtual_card_enrollment_fields_|'s
+ // |virtual_card_enrollment_source| is passed here so that it can be forwarded
+ // to ShowVirtualCardEnrollBubble.
+ void GetDetailsForEnroll();
+
+ // Handles the response from the GetDetailsForEnrollRequest. |result| and
+ // |response| are received from the GetDetailsForEnroll server call response,
+ // while |state_| is passed down from GetDetailsForEnroll() to track the
+ // current process' state.
+ void OnDidGetDetailsForEnrollResponse(
+ AutofillClient::PaymentsRpcResult result,
+ const payments::PaymentsClient::GetDetailsForEnrollmentResponseDetails&
+ response);
+
+ // Cancels the entire Virtual Card Enrollment process.
+ void OnVirtualCardEnrollmentBubbleCancelled();
+
+ FRIEND_TEST_ALL_PREFIXES(VirtualCardEnrollmentManagerTest, Enroll);
+ FRIEND_TEST_ALL_PREFIXES(VirtualCardEnrollmentManagerTest,
+ OnDidGetDetailsForEnrollResponse);
+ FRIEND_TEST_ALL_PREFIXES(VirtualCardEnrollmentManagerTest,
+ OnDidGetDetailsForEnrollResponse_NoAutofillClient);
+ FRIEND_TEST_ALL_PREFIXES(VirtualCardEnrollmentManagerTest,
+ OnDidGetDetailsForEnrollResponse_Reset);
+ FRIEND_TEST_ALL_PREFIXES(VirtualCardEnrollmentManagerTest,
+ OnRiskDataLoadedForVirtualCard);
+ FRIEND_TEST_ALL_PREFIXES(VirtualCardEnrollmentManagerTest,
+ UpstreamAnimationSync_AnimationFirst);
+ FRIEND_TEST_ALL_PREFIXES(VirtualCardEnrollmentManagerTest,
+ UpstreamAnimationSync_ResponseFirst);
+
+ // The associated personal data manager, used to save and load personal data
+ // to/from the web database. Weak reference. May be nullptr, which indicates
+ // OTR.
+ raw_ptr<PersonalDataManager> personal_data_manager_;
+
+ // The associated |payments_client_| that is used for all requests to the
+ // server.
+ raw_ptr<payments::PaymentsClient> payments_client_;
+
+ // The database that is used to count guid-keyed strikes to suppress prompting
+ // users to enroll in virtual cards.
+ std::unique_ptr<VirtualCardEnrollmentStrikeDatabase>
+ virtual_card_enrollment_strike_database_;
+
+ // Used in scenarios where we do not have access to web contents, and need to
+ // pass in a callback to the overloaded risk_util::LoadRiskData.
+ RiskAssessmentFunction risk_assessment_function_;
+
+ base::WeakPtrFactory<VirtualCardEnrollmentManager> weak_ptr_factory_{this};
+};
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_VIRTUAL_CARD_ENROLLMENT_MANAGER_H_
diff --git a/chromium/components/autofill/core/browser/payments/virtual_card_enrollment_manager_unittest.cc b/chromium/components/autofill/core/browser/payments/virtual_card_enrollment_manager_unittest.cc
new file mode 100644
index 00000000000..660fed5a64d
--- /dev/null
+++ b/chromium/components/autofill/core/browser/payments/virtual_card_enrollment_manager_unittest.cc
@@ -0,0 +1,507 @@
+// Copyright 2022 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.
+
+#include <string>
+
+#include "base/callback.h"
+#include "base/test/metrics/histogram_tester.h"
+#include "base/test/mock_callback.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/test/task_environment.h"
+#include "components/autofill/core/browser/autofill_test_utils.h"
+#include "components/autofill/core/browser/data_model/credit_card.h"
+#include "components/autofill/core/browser/data_model/credit_card_art_image.h"
+#include "components/autofill/core/browser/payments/payments_requests/update_virtual_card_enrollment_request.h"
+#include "components/autofill/core/browser/payments/payments_util.h"
+#include "components/autofill/core/browser/payments/test_legal_message_line.h"
+#include "components/autofill/core/browser/payments/test_payments_client.h"
+#include "components/autofill/core/browser/payments/test_virtual_card_enrollment_manager.h"
+#include "components/autofill/core/browser/payments/virtual_card_enrollment_flow.h"
+#include "components/autofill/core/browser/test_autofill_client.h"
+#include "components/autofill/core/browser/test_autofill_driver.h"
+#include "components/autofill/core/browser/test_personal_data_manager.h"
+#include "components/autofill/core/common/autofill_payments_features.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/image/image_unittest_util.h"
+
+using testing::_;
+
+namespace autofill {
+
+namespace {
+const std::string kTestVcnContextToken = "vcn_context_token";
+const std::string kTestRiskData = "risk_data";
+} // namespace
+
+class VirtualCardEnrollmentManagerTest : public testing::Test {
+ public:
+ void SetUp() override {
+ autofill_client_ = std::make_unique<TestAutofillClient>();
+ autofill_client_->SetPrefs(test::PrefServiceForTesting());
+ user_prefs_ = autofill_client_->GetPrefs();
+ personal_data_manager_ = std::make_unique<TestPersonalDataManager>();
+ personal_data_manager_->Init(
+ /*profile_database=*/nullptr,
+ /*account_database=*/nullptr,
+ /*pref_service=*/autofill_client_->GetPrefs(),
+ /*local_state=*/autofill_client_->GetPrefs(),
+ /*identity_manager=*/nullptr,
+ /*history_service=*/nullptr,
+ /*strike_database=*/nullptr,
+ /*image_fetcher=*/nullptr,
+ /*is_off_the_record=*/false);
+ autofill_driver_ = std::make_unique<TestAutofillDriver>();
+ autofill_client_->set_test_payments_client(
+ std::make_unique<payments::TestPaymentsClient>(
+ autofill_driver_->GetURLLoaderFactory(),
+ autofill_client_->GetIdentityManager(),
+ personal_data_manager_.get()));
+ payments_client_ = static_cast<payments::TestPaymentsClient*>(
+ autofill_client_->GetPaymentsClient());
+ virtual_card_enrollment_manager_ =
+ std::make_unique<TestVirtualCardEnrollmentManager>(
+ personal_data_manager_.get(), payments_client_,
+ autofill_client_.get());
+ }
+
+ void TearDown() override {
+ // Order of destruction is important as AutofillDriver relies on
+ // PersonalDataManager to be around when it gets destroyed.
+ autofill_driver_.reset();
+ }
+
+ void SetUpCard() {
+ card_ = std::make_unique<CreditCard>(test::GetMaskedServerCard());
+ card_->set_card_art_url(autofill_client_->form_origin());
+ card_->set_instrument_id(112233445566);
+ personal_data_manager_->AddFullServerCreditCard(*card_.get());
+ }
+
+ void SetValidCardArtImageForCard(const CreditCard& card) {
+ gfx::Image expected_image = gfx::test::CreateImage(32, 20);
+ std::vector<std::unique_ptr<CreditCardArtImage>> images;
+ images.emplace_back(std::make_unique<CreditCardArtImage>());
+ images.back()->card_art_url = card.card_art_url();
+ images.back()->card_art_image = expected_image;
+ personal_data_manager_->OnCardArtImagesFetched(std::move(images));
+ }
+
+ payments::PaymentsClient::GetDetailsForEnrollmentResponseDetails
+ SetUpOnDidGetDetailsForEnrollResponse(
+ const TestLegalMessageLine& google_legal_message,
+ const TestLegalMessageLine& issuer_legal_message) {
+ personal_data_manager_->ClearCreditCardArtImages();
+ SetUpCard();
+ SetValidCardArtImageForCard(*card_);
+ raw_ptr<VirtualCardEnrollmentProcessState> state =
+ virtual_card_enrollment_manager_
+ ->GetVirtualCardEnrollmentProcessState();
+ state->virtual_card_enrollment_fields.credit_card = *card_;
+
+ payments::PaymentsClient::GetDetailsForEnrollmentResponseDetails response;
+ response.vcn_context_token = kTestVcnContextToken;
+ response.google_legal_message = {google_legal_message};
+ response.issuer_legal_message = {issuer_legal_message};
+ return response;
+ }
+
+ protected:
+ base::test::TaskEnvironment task_environment_{
+ base::test::TaskEnvironment::TimeSource::MOCK_TIME};
+ std::unique_ptr<TestAutofillClient> autofill_client_;
+ std::unique_ptr<TestAutofillDriver> autofill_driver_;
+ raw_ptr<payments::TestPaymentsClient> payments_client_;
+ std::unique_ptr<TestPersonalDataManager> personal_data_manager_;
+ std::unique_ptr<TestVirtualCardEnrollmentManager>
+ virtual_card_enrollment_manager_;
+ raw_ptr<PrefService> user_prefs_;
+
+ // The global CreditCard used throughout the tests. Each test that needs to
+ // use it will set it up for the specific test before testing it.
+ std::unique_ptr<CreditCard> card_;
+};
+
+TEST_F(VirtualCardEnrollmentManagerTest, OfferVirtualCardEnroll) {
+ for (VirtualCardEnrollmentSource virtual_card_enrollment_source :
+ {VirtualCardEnrollmentSource::kUpstream,
+ VirtualCardEnrollmentSource::kDownstream,
+ VirtualCardEnrollmentSource::kSettingsPage}) {
+ for (bool make_image_present : {true, false}) {
+ SCOPED_TRACE(testing::Message()
+ << " virtual_card_enrollment_source="
+ << static_cast<int>(virtual_card_enrollment_source)
+ << ", make_image_present=" << make_image_present);
+
+ personal_data_manager_->ClearCreditCardArtImages();
+ SetUpCard();
+ auto state = virtual_card_enrollment_manager_
+ ->GetVirtualCardEnrollmentProcessState();
+ state->risk_data.reset();
+ if (make_image_present)
+ SetValidCardArtImageForCard(*card_);
+
+#if BUILDFLAG(IS_ANDROID)
+ virtual_card_enrollment_manager_->SetAutofillClient(nullptr);
+#endif
+
+ virtual_card_enrollment_manager_->OfferVirtualCardEnroll(
+ *card_, virtual_card_enrollment_source,
+ virtual_card_enrollment_manager_->AutofillClientIsPresent()
+ ? user_prefs_
+ : nullptr,
+ base::DoNothing());
+
+ // CreditCard class overloads equality operator to check that GUIDs,
+ // origins, and the contents of the two cards are equal.
+ EXPECT_EQ(*card_, state->virtual_card_enrollment_fields.credit_card);
+
+ raw_ptr<gfx::Image> card_art_image =
+ state->virtual_card_enrollment_fields.card_art_image;
+ EXPECT_EQ(make_image_present, card_art_image != nullptr);
+ EXPECT_TRUE(state->risk_data.has_value());
+ }
+ }
+}
+
+TEST_F(VirtualCardEnrollmentManagerTest, OnRiskDataLoadedForVirtualCard) {
+ base::HistogramTester histogram_tester;
+ raw_ptr<VirtualCardEnrollmentProcessState> state =
+ virtual_card_enrollment_manager_->GetVirtualCardEnrollmentProcessState();
+ state->virtual_card_enrollment_fields.virtual_card_enrollment_source =
+ VirtualCardEnrollmentSource::kUpstream;
+ SetUpCard();
+ state->virtual_card_enrollment_fields.credit_card = *card_;
+ state->risk_data.reset();
+
+ virtual_card_enrollment_manager_->OnRiskDataLoadedForVirtualCard(
+ kTestRiskData);
+
+ payments::PaymentsClient::GetDetailsForEnrollmentRequestDetails
+ request_details =
+ payments_client_->get_details_for_enrollment_request_details();
+
+ EXPECT_EQ(request_details.risk_data, state->risk_data.value_or(""));
+ EXPECT_EQ(request_details.app_locale, personal_data_manager_->app_locale());
+ EXPECT_EQ(request_details.instrument_id,
+ state->virtual_card_enrollment_fields.credit_card.instrument_id());
+ EXPECT_EQ(request_details.billing_customer_number,
+ payments::GetBillingCustomerId(personal_data_manager_.get()));
+ EXPECT_EQ(
+ request_details.source,
+ state->virtual_card_enrollment_fields.virtual_card_enrollment_source);
+ histogram_tester.ExpectUniqueSample(
+ "Autofill.VirtualCard.GetDetailsForEnrollment.Attempt.Upstream",
+ /*succeeded=*/true, 1);
+}
+
+TEST_F(VirtualCardEnrollmentManagerTest, OnDidGetDetailsForEnrollResponse) {
+ base::HistogramTester histogram_tester;
+ const TestLegalMessageLine google_legal_message =
+ TestLegalMessageLine("google_test_legal_message");
+ const TestLegalMessageLine issuer_legal_message =
+ TestLegalMessageLine("issuer_test_legal_message");
+ payments::PaymentsClient::GetDetailsForEnrollmentResponseDetails response =
+ std::move(SetUpOnDidGetDetailsForEnrollResponse(google_legal_message,
+ issuer_legal_message));
+ auto state =
+ virtual_card_enrollment_manager_->GetVirtualCardEnrollmentProcessState();
+ state->virtual_card_enrollment_fields.virtual_card_enrollment_source =
+ VirtualCardEnrollmentSource::kDownstream;
+
+ virtual_card_enrollment_manager_->OnDidGetDetailsForEnrollResponse(
+ AutofillClient::PaymentsRpcResult::kSuccess, response);
+
+ EXPECT_TRUE(state->vcn_context_token.has_value());
+ EXPECT_EQ(state->vcn_context_token, response.vcn_context_token);
+ VirtualCardEnrollmentFields virtual_card_enrollment_fields =
+ virtual_card_enrollment_manager_->GetVirtualCardEnrollmentProcessState()
+ ->virtual_card_enrollment_fields;
+ EXPECT_TRUE(virtual_card_enrollment_fields.google_legal_message[0].text() ==
+ google_legal_message.text());
+ EXPECT_TRUE(virtual_card_enrollment_fields.issuer_legal_message[0].text() ==
+ issuer_legal_message.text());
+ EXPECT_TRUE(virtual_card_enrollment_fields.card_art_image != nullptr);
+ histogram_tester.ExpectUniqueSample(
+ "Autofill.VirtualCard.GetDetailsForEnrollment.Result.Downstream",
+ /*succeeded=*/true, 1);
+}
+
+TEST_F(VirtualCardEnrollmentManagerTest,
+ OnDidGetDetailsForEnrollResponse_NoAutofillClient) {
+ base::HistogramTester histogram_tester;
+ const TestLegalMessageLine google_legal_message =
+ TestLegalMessageLine("google_test_legal_message");
+ const TestLegalMessageLine issuer_legal_message =
+ TestLegalMessageLine("issuer_test_legal_message");
+ payments::PaymentsClient::GetDetailsForEnrollmentResponseDetails response =
+ std::move(SetUpOnDidGetDetailsForEnrollResponse(google_legal_message,
+ issuer_legal_message));
+ auto state =
+ virtual_card_enrollment_manager_->GetVirtualCardEnrollmentProcessState();
+ state->virtual_card_enrollment_fields.virtual_card_enrollment_source =
+ VirtualCardEnrollmentSource::kSettingsPage;
+
+ virtual_card_enrollment_manager_->SetAutofillClient(nullptr);
+ base::MockCallback<TestVirtualCardEnrollmentManager::
+ VirtualCardEnrollmentFieldsLoadedCallback>
+ virtual_card_enrollment_fields_loadaed_callback;
+ virtual_card_enrollment_manager_
+ ->SetVirtualCardEnrollmentFieldsLoadedCallback(
+ virtual_card_enrollment_fields_loadaed_callback.Get());
+ EXPECT_CALL(virtual_card_enrollment_fields_loadaed_callback, Run(_));
+ virtual_card_enrollment_manager_->OnDidGetDetailsForEnrollResponse(
+ AutofillClient::PaymentsRpcResult::kSuccess, response);
+
+ EXPECT_TRUE(state->vcn_context_token.has_value());
+ EXPECT_EQ(state->vcn_context_token, response.vcn_context_token);
+ VirtualCardEnrollmentFields virtual_card_enrollment_fields =
+ state->virtual_card_enrollment_fields;
+ EXPECT_TRUE(virtual_card_enrollment_fields.google_legal_message[0].text() ==
+ google_legal_message.text());
+ EXPECT_TRUE(virtual_card_enrollment_fields.issuer_legal_message[0].text() ==
+ issuer_legal_message.text());
+ EXPECT_TRUE(virtual_card_enrollment_fields.card_art_image != nullptr);
+
+ histogram_tester.ExpectUniqueSample(
+ "Autofill.VirtualCard.GetDetailsForEnrollment.Result.SettingsPage",
+ /*succeeded=*/true, 1);
+}
+
+TEST_F(VirtualCardEnrollmentManagerTest,
+ OnDidGetDetailsForEnrollResponse_Reset) {
+ base::HistogramTester histogram_tester;
+ auto state =
+ virtual_card_enrollment_manager_->GetVirtualCardEnrollmentProcessState();
+ state->virtual_card_enrollment_fields.virtual_card_enrollment_source =
+ VirtualCardEnrollmentSource::kSettingsPage;
+ for (AutofillClient::PaymentsRpcResult result :
+ {AutofillClient::PaymentsRpcResult::kVcnRetrievalTryAgainFailure,
+ AutofillClient::PaymentsRpcResult::kVcnRetrievalPermanentFailure}) {
+ virtual_card_enrollment_manager_->SetResetCalled(false);
+
+ virtual_card_enrollment_manager_->OnDidGetDetailsForEnrollResponse(
+ result,
+ payments::PaymentsClient::GetDetailsForEnrollmentResponseDetails());
+
+ EXPECT_TRUE(virtual_card_enrollment_manager_->GetResetCalled());
+ }
+
+ // Ensure the clank settings page use-case works as expected.
+ virtual_card_enrollment_manager_->SetAutofillClient(nullptr);
+ for (AutofillClient::PaymentsRpcResult result :
+ {AutofillClient::PaymentsRpcResult::kVcnRetrievalTryAgainFailure,
+ AutofillClient::PaymentsRpcResult::kVcnRetrievalPermanentFailure}) {
+ virtual_card_enrollment_manager_->SetResetCalled(false);
+
+ virtual_card_enrollment_manager_->OnDidGetDetailsForEnrollResponse(
+ result,
+ payments::PaymentsClient::GetDetailsForEnrollmentResponseDetails());
+
+ EXPECT_TRUE(virtual_card_enrollment_manager_->GetResetCalled());
+ }
+ histogram_tester.ExpectUniqueSample(
+ "Autofill.VirtualCard.GetDetailsForEnrollment.Result.SettingsPage",
+ /*succeeded=*/false, 4);
+}
+
+TEST_F(VirtualCardEnrollmentManagerTest, Enroll) {
+ raw_ptr<VirtualCardEnrollmentProcessState> state =
+ virtual_card_enrollment_manager_->GetVirtualCardEnrollmentProcessState();
+ state->vcn_context_token = kTestVcnContextToken;
+ personal_data_manager_->SetPaymentsCustomerData(
+ std::make_unique<PaymentsCustomerData>(/*customer_id=*/"123456"));
+
+ for (VirtualCardEnrollmentSource virtual_card_enrollment_source :
+ {VirtualCardEnrollmentSource::kUpstream,
+ VirtualCardEnrollmentSource::kDownstream,
+ VirtualCardEnrollmentSource::kSettingsPage}) {
+ base::HistogramTester histogram_tester;
+ SCOPED_TRACE(testing::Message()
+ << " virtual_card_enrollment_source="
+ << static_cast<int>(virtual_card_enrollment_source));
+ state->virtual_card_enrollment_fields.virtual_card_enrollment_source =
+ virtual_card_enrollment_source;
+ virtual_card_enrollment_manager_->SetPaymentsRpcResult(
+ AutofillClient::PaymentsRpcResult::kNone);
+
+ payments_client_->set_update_virtual_card_enrollment_result(
+ AutofillClient::PaymentsRpcResult::kSuccess);
+ virtual_card_enrollment_manager_->Enroll();
+
+ payments::PaymentsClient::UpdateVirtualCardEnrollmentRequestDetails
+ request_details =
+ payments_client_->update_virtual_card_enrollment_request_details();
+ EXPECT_TRUE(request_details.vcn_context_token.has_value());
+ EXPECT_EQ(request_details.vcn_context_token, kTestVcnContextToken);
+ EXPECT_EQ(request_details.virtual_card_enrollment_source,
+ virtual_card_enrollment_source);
+ EXPECT_EQ(request_details.virtual_card_enrollment_request_type,
+ VirtualCardEnrollmentRequestType::kEnroll);
+ EXPECT_EQ(request_details.billing_customer_number, 123456);
+ EXPECT_EQ(virtual_card_enrollment_manager_->GetPaymentsRpcResult(),
+ AutofillClient::PaymentsRpcResult::kSuccess);
+
+ std::string suffix;
+ switch (virtual_card_enrollment_source) {
+ case VirtualCardEnrollmentSource::kUpstream:
+ suffix = "Upstream";
+ break;
+ case VirtualCardEnrollmentSource::kDownstream:
+ suffix = "Downstream";
+ break;
+ case VirtualCardEnrollmentSource::kSettingsPage:
+ suffix = "SettingsPage";
+ break;
+ default:
+ NOTREACHED();
+ }
+
+ // Verifies the logging.
+ histogram_tester.ExpectUniqueSample(
+ "Autofill.VirtualCard.Enroll.Attempt." + suffix,
+ /*attempted=*/true, 1);
+ histogram_tester.ExpectBucketCount(
+ "Autofill.VirtualCard.Enroll.Result." + suffix,
+ /*succeeded=*/true, 1);
+
+ // Starts another request and makes sure it fails.
+ payments_client_->set_update_virtual_card_enrollment_result(
+ AutofillClient::PaymentsRpcResult::kVcnRetrievalPermanentFailure);
+ virtual_card_enrollment_manager_->Enroll();
+
+ // Verifies the logging.
+ histogram_tester.ExpectUniqueSample(
+ "Autofill.VirtualCard.Enroll.Attempt." + suffix,
+ /*attempted=*/true, 2);
+ histogram_tester.ExpectBucketCount(
+ "Autofill.VirtualCard.Enroll.Result." + suffix,
+ /*succeeded=*/false, 1);
+ }
+}
+
+TEST_F(VirtualCardEnrollmentManagerTest, Unenroll) {
+ base::HistogramTester histogram_tester;
+ personal_data_manager_->SetPaymentsCustomerData(
+ std::make_unique<PaymentsCustomerData>(/*customer_id=*/"123456"));
+ virtual_card_enrollment_manager_->SetPaymentsRpcResult(
+ AutofillClient::PaymentsRpcResult::kNone);
+
+ virtual_card_enrollment_manager_->Unenroll(
+ /*instrument_id=*/9223372036854775807);
+
+ payments::PaymentsClient::UpdateVirtualCardEnrollmentRequestDetails
+ request_details =
+ payments_client_->update_virtual_card_enrollment_request_details();
+ EXPECT_EQ(request_details.virtual_card_enrollment_source,
+ VirtualCardEnrollmentSource::kSettingsPage);
+ EXPECT_EQ(request_details.virtual_card_enrollment_request_type,
+ VirtualCardEnrollmentRequestType::kUnenroll);
+ EXPECT_EQ(request_details.billing_customer_number, 123456);
+ EXPECT_EQ(request_details.instrument_id, 9223372036854775807);
+
+ // The request should not include a context token, and should succeed.
+ EXPECT_FALSE(request_details.vcn_context_token.has_value());
+ EXPECT_EQ(virtual_card_enrollment_manager_->GetPaymentsRpcResult(),
+ AutofillClient::PaymentsRpcResult::kSuccess);
+
+ // Verifies the logging.
+ histogram_tester.ExpectUniqueSample(
+ "Autofill.VirtualCard.Unenroll.Attempt.SettingsPage",
+ /*attempted=*/true, 1);
+ histogram_tester.ExpectBucketCount(
+ "Autofill.VirtualCard.Unenroll.Result.SettingsPage",
+ /*succeeded=*/true, 1);
+
+ // Starts another request and make sure it fails.
+ payments_client_->set_update_virtual_card_enrollment_result(
+ AutofillClient::PaymentsRpcResult::kVcnRetrievalPermanentFailure);
+ virtual_card_enrollment_manager_->Unenroll(
+ /*instrument_id=*/9223372036854775807);
+
+ // Verifies the logging.
+ histogram_tester.ExpectUniqueSample(
+ "Autofill.VirtualCard.Unenroll.Attempt.SettingsPage",
+ /*attempted=*/true, 2);
+ histogram_tester.ExpectBucketCount(
+ "Autofill.VirtualCard.Unenroll.Result.SettingsPage",
+ /*succeeded=*/false, 1);
+}
+
+#if !BUILDFLAG(IS_ANDROID)
+TEST_F(VirtualCardEnrollmentManagerTest, UpstreamAnimationSync_AnimationFirst) {
+ personal_data_manager_->ClearCreditCardArtImages();
+ SetUpCard();
+ SetValidCardArtImageForCard(*card_);
+
+ raw_ptr<VirtualCardEnrollmentProcessState> state =
+ virtual_card_enrollment_manager_->GetVirtualCardEnrollmentProcessState();
+ state->virtual_card_enrollment_fields.credit_card = *card_;
+ state->vcn_context_token = kTestVcnContextToken;
+ state->virtual_card_enrollment_fields.virtual_card_enrollment_source =
+ VirtualCardEnrollmentSource::kUpstream;
+
+ payments::PaymentsClient::GetDetailsForEnrollmentResponseDetails response;
+ response.vcn_context_token = kTestVcnContextToken;
+ response.issuer_legal_message = {
+ TestLegalMessageLine("issuer_test_legal_message_line")};
+ response.google_legal_message = {
+ TestLegalMessageLine("google_test_legal_message_line")};
+
+ // Update avatar animation complete boolean.
+ virtual_card_enrollment_manager_->OnCardSavedAnimationComplete();
+ EXPECT_TRUE(virtual_card_enrollment_manager_->GetAvatarAnimationComplete());
+
+ // Ensure bubble was not shown yet.
+ EXPECT_FALSE(virtual_card_enrollment_manager_->GetBubbleShown());
+
+ // Update enrollment response complete boolean.
+ virtual_card_enrollment_manager_->OnDidGetDetailsForEnrollResponse(
+ AutofillClient::PaymentsRpcResult::kSuccess, response);
+ EXPECT_TRUE(
+ virtual_card_enrollment_manager_->GetEnrollResponseDetailsReceived());
+
+ // Ensure bubble was shown.
+ EXPECT_TRUE(virtual_card_enrollment_manager_->GetBubbleShown());
+}
+
+TEST_F(VirtualCardEnrollmentManagerTest, UpstreamAnimationSync_ResponseFirst) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitWithFeatures({features::kAutofillEnableToolbarStatusChip,
+ features::kAutofillCreditCardUploadFeedback},
+ {});
+ personal_data_manager_->ClearCreditCardArtImages();
+ SetUpCard();
+ SetValidCardArtImageForCard(*card_);
+
+ raw_ptr<VirtualCardEnrollmentProcessState> state =
+ virtual_card_enrollment_manager_->GetVirtualCardEnrollmentProcessState();
+ state->virtual_card_enrollment_fields.credit_card = *card_;
+ state->vcn_context_token = kTestVcnContextToken;
+ state->virtual_card_enrollment_fields.virtual_card_enrollment_source =
+ VirtualCardEnrollmentSource::kUpstream;
+
+ payments::PaymentsClient::GetDetailsForEnrollmentResponseDetails response;
+ response.vcn_context_token = kTestVcnContextToken;
+ response.issuer_legal_message = {
+ TestLegalMessageLine("issuer_test_legal_message_line")};
+ response.google_legal_message = {
+ TestLegalMessageLine("google_test_legal_message_line")};
+
+ // Update enrollment response complete boolean.
+ virtual_card_enrollment_manager_->OnDidGetDetailsForEnrollResponse(
+ AutofillClient::PaymentsRpcResult::kSuccess, response);
+ EXPECT_TRUE(
+ virtual_card_enrollment_manager_->GetEnrollResponseDetailsReceived());
+
+ // Ensure bubble was not shown yet.
+ EXPECT_FALSE(virtual_card_enrollment_manager_->GetBubbleShown());
+
+ // Update avatar animation complete boolean.
+ virtual_card_enrollment_manager_->OnCardSavedAnimationComplete();
+ EXPECT_TRUE(virtual_card_enrollment_manager_->GetAvatarAnimationComplete());
+}
+#endif // !BUILDFLAG(IS_ANDROID)
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/payments/virtual_card_enrollment_strike_database.cc b/chromium/components/autofill/core/browser/payments/virtual_card_enrollment_strike_database.cc
new file mode 100644
index 00000000000..5c3781d1a51
--- /dev/null
+++ b/chromium/components/autofill/core/browser/payments/virtual_card_enrollment_strike_database.cc
@@ -0,0 +1,61 @@
+// Copyright 2022 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.
+
+#include "components/autofill/core/browser/payments/virtual_card_enrollment_strike_database.h"
+
+#include "components/autofill/core/browser/proto/strike_data.pb.h"
+#include "components/autofill/core/common/autofill_payments_features.h"
+
+namespace autofill {
+
+// Limit the number of cards for which strikes are collected
+constexpr size_t kMaxStrikeEntities = 50;
+
+// Once the limit of cards is reached, delete 20 to create a bit of headroom.
+constexpr size_t kMaxStrikeEntitiesAfterCleanup = 30;
+
+// The maximum number of strikes before we stop showing virtual card enrollment
+// dialogs.
+int kCardMaximumStrikes = 3;
+
+// The number of days until strikes expire for virtual card enrollment.
+constexpr size_t kDaysUntilCardStrikeExpiry = 180;
+
+VirtualCardEnrollmentStrikeDatabase::VirtualCardEnrollmentStrikeDatabase(
+ StrikeDatabaseBase* strike_database)
+ : StrikeDatabaseIntegratorBase(strike_database) {}
+
+VirtualCardEnrollmentStrikeDatabase::~VirtualCardEnrollmentStrikeDatabase() =
+ default;
+
+absl::optional<size_t> VirtualCardEnrollmentStrikeDatabase::GetMaximumEntries()
+ const {
+ return kMaxStrikeEntities;
+}
+
+absl::optional<size_t>
+VirtualCardEnrollmentStrikeDatabase::GetMaximumEntriesAfterCleanup() const {
+ return kMaxStrikeEntitiesAfterCleanup;
+}
+
+std::string VirtualCardEnrollmentStrikeDatabase::GetProjectPrefix() const {
+ return "VirtualCardEnrollment";
+}
+
+int VirtualCardEnrollmentStrikeDatabase::GetMaxStrikesLimit() const {
+ // The default limit for strikes is 3.
+ return kCardMaximumStrikes;
+}
+
+absl::optional<base::TimeDelta>
+VirtualCardEnrollmentStrikeDatabase::GetExpiryTimeDelta() const {
+ // Expiry time is 180 days by default.
+ return base::Days(kDaysUntilCardStrikeExpiry);
+}
+
+bool VirtualCardEnrollmentStrikeDatabase::UniqueIdsRequired() const {
+ return true;
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/payments/virtual_card_enrollment_strike_database.h b/chromium/components/autofill/core/browser/payments/virtual_card_enrollment_strike_database.h
new file mode 100644
index 00000000000..cdad62beb9a
--- /dev/null
+++ b/chromium/components/autofill/core/browser/payments/virtual_card_enrollment_strike_database.h
@@ -0,0 +1,37 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_VIRTUAL_CARD_ENROLLMENT_STRIKE_DATABASE_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_VIRTUAL_CARD_ENROLLMENT_STRIKE_DATABASE_H_
+
+#include <stdint.h>
+#include <string>
+
+#include "components/autofill/core/browser/strike_database_base.h"
+#include "components/autofill/core/browser/strike_database_integrator_base.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace autofill {
+
+// Implementation of StrikeDatabaseIntegratorBase for virtual card enrollment
+// dialogs.
+class VirtualCardEnrollmentStrikeDatabase
+ : public StrikeDatabaseIntegratorBase {
+ public:
+ explicit VirtualCardEnrollmentStrikeDatabase(
+ StrikeDatabaseBase* strike_database);
+ ~VirtualCardEnrollmentStrikeDatabase() override;
+
+ absl::optional<size_t> GetMaximumEntries() const override;
+ absl::optional<size_t> GetMaximumEntriesAfterCleanup() const override;
+
+ std::string GetProjectPrefix() const override;
+ int GetMaxStrikesLimit() const override;
+ absl::optional<base::TimeDelta> GetExpiryTimeDelta() const override;
+ bool UniqueIdsRequired() const override;
+};
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_VIRTUAL_CARD_ENROLLMENT_STRIKE_DATABASE_H_
diff --git a/chromium/components/autofill/core/browser/payments/virtual_card_enrollment_strike_database_unittest.cc b/chromium/components/autofill/core/browser/payments/virtual_card_enrollment_strike_database_unittest.cc
new file mode 100644
index 00000000000..463b53c06bd
--- /dev/null
+++ b/chromium/components/autofill/core/browser/payments/virtual_card_enrollment_strike_database_unittest.cc
@@ -0,0 +1,74 @@
+// Copyright 2021 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.
+
+#include "components/autofill/core/browser/strike_database_integrator_test_strike_database.h"
+
+#include <memory>
+
+#include "base/files/scoped_temp_dir.h"
+#include "base/test/task_environment.h"
+#include "components/autofill/core/browser/payments/virtual_card_enrollment_strike_database.h"
+#include "components/autofill/core/browser/proto/strike_data.pb.h"
+#include "components/leveldb_proto/public/proto_database_provider.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace autofill {
+
+namespace {
+
+class VirtualCardEnrollmentStrikeDatabaseTest : public ::testing::Test {
+ public:
+ VirtualCardEnrollmentStrikeDatabaseTest() = default;
+
+ void SetUp() override {
+ EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
+
+ db_provider_ = std::make_unique<leveldb_proto::ProtoDatabaseProvider>(
+ temp_dir_.GetPath());
+
+ strike_database_service_ = std::make_unique<StrikeDatabase>(
+ db_provider_.get(), temp_dir_.GetPath());
+
+ strike_database_ = std::make_unique<VirtualCardEnrollmentStrikeDatabase>(
+ strike_database_service_.get());
+ }
+
+ void TearDown() override {
+ // The destruction of |strike_database_service_|'s components is posted
+ // to a task runner, requires running the loop to complete.
+ strike_database_.reset();
+ strike_database_service_.reset();
+ db_provider_.reset();
+ task_environment_.RunUntilIdle();
+ }
+
+ protected:
+ base::ScopedTempDir temp_dir_;
+ base::test::TaskEnvironment task_environment_;
+ std::unique_ptr<leveldb_proto::ProtoDatabaseProvider> db_provider_;
+ std::unique_ptr<StrikeDatabase> strike_database_service_;
+ std::unique_ptr<VirtualCardEnrollmentStrikeDatabase> strike_database_;
+};
+
+TEST_F(VirtualCardEnrollmentStrikeDatabaseTest, AddAndRemoveStrikes) {
+ int max_strikes = strike_database_->GetMaxStrikesLimit();
+ std::string test_guid = "00000000-0000-0000-0000-000000000001";
+
+ strike_database_->AddStrike(test_guid);
+ EXPECT_EQ(strike_database_->GetStrikes(test_guid), 1);
+ EXPECT_FALSE(strike_database_->IsMaxStrikesLimitReached(test_guid));
+
+ strike_database_->AddStrikes(max_strikes - 1, test_guid);
+ EXPECT_EQ(strike_database_->GetStrikes(test_guid), max_strikes);
+ EXPECT_EQ(strike_database_->GetMaxStrikesLimit(), max_strikes);
+ EXPECT_TRUE(strike_database_->IsMaxStrikesLimitReached(test_guid));
+
+ strike_database_->RemoveStrike(test_guid);
+ EXPECT_EQ(strike_database_->GetStrikes(test_guid), max_strikes - 1);
+ EXPECT_FALSE(strike_database_->IsMaxStrikesLimitReached(test_guid));
+}
+
+} // namespace
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/personal_data_manager.cc b/chromium/components/autofill/core/browser/personal_data_manager.cc
index b7f2736844f..63b91c96ef9 100644
--- a/chromium/components/autofill/core/browser/personal_data_manager.cc
+++ b/chromium/components/autofill/core/browser/personal_data_manager.cc
@@ -277,7 +277,6 @@ void PersonalDataManager::Init(
PrefService* pref_service,
PrefService* local_state,
signin::IdentityManager* identity_manager,
- AutofillProfileValidator* client_profile_validator,
history::HistoryService* history_service,
StrikeDatabaseBase* strike_database,
AutofillImageFetcher* image_fetcher,
@@ -289,10 +288,6 @@ void PersonalDataManager::Init(
// Listen for the preference changes.
pref_registrar_.Init(pref_service);
- pref_registrar_.Add(
- prefs::kAutofillProfileValidity,
- base::BindRepeating(&PersonalDataManager::ResetProfileValidity,
- base::Unretained(this)));
alternative_state_name_map_updater_ =
std::make_unique<AlternativeStateNameMapUpdater>(local_state, this);
@@ -320,8 +315,6 @@ void PersonalDataManager::Init(
IsAutofillCreditCardEnabled());
}
- client_profile_validator_ = client_profile_validator;
-
if (strike_database) {
profile_save_strike_database_ =
std::make_unique<AutofillProfileSaveStrikeDatabase>(strike_database);
@@ -1054,6 +1047,16 @@ CreditCard* PersonalDataManager::GetCreditCardByInstrumentId(
return nullptr;
}
+CreditCard* PersonalDataManager::GetCreditCardByServerId(
+ const std::string& server_id) {
+ const std::vector<CreditCard*> server_credit_cards = GetServerCreditCards();
+ for (CreditCard* credit_card : server_credit_cards) {
+ if (credit_card->server_id() == server_id)
+ return credit_card;
+ }
+ return nullptr;
+}
+
void PersonalDataManager::GetNonEmptyTypes(
ServerFieldTypeSet* non_empty_types) const {
for (AutofillProfile* profile : GetProfiles())
@@ -1074,69 +1077,6 @@ std::vector<AutofillProfile*> PersonalDataManager::GetProfiles() const {
return result;
}
-void PersonalDataManager::UpdateProfilesServerValidityMapsIfNeeded(
- const std::vector<AutofillProfile*>& profiles) {
- if (!profiles_server_validities_need_update_)
- return;
- profiles_server_validities_need_update_ = false;
- for (auto* profile : profiles) {
- profile->UpdateServerValidityMap(GetProfileValidityByGUID(profile->guid()));
- }
-}
-
-void PersonalDataManager::UpdateClientValidityStates(
- const std::vector<AutofillProfile*>& profiles) {
- if (!base::FeatureList::IsEnabled(
- autofill::features::kAutofillProfileClientValidation))
- return;
-
- if (!client_profile_validator_)
- return;
-
- // The profiles' validity states need to be updated for each major version, to
- // keep up with the validation logic.
- bool update_validation =
- pref_service_->GetInteger(prefs::kAutofillLastVersionValidated) <
- CHROME_VERSION_MAJOR;
-
- DVLOG(1) << "Autofill profile client validation "
- << (update_validation ? "needs to be" : "has already been")
- << " performed for this version";
-
- for (const auto* profile : profiles) {
- if (!profile->is_client_validity_states_updated() || update_validation) {
- profile->set_is_client_validity_states_updated(false);
- ongoing_profile_changes_[profile->guid()].push_back(
- AutofillProfileDeepChange(AutofillProfileChange::UPDATE, *profile));
- ongoing_profile_changes_[profile->guid()].back().set_enforced();
- client_profile_validator_->StartProfileValidation(
- profile, base::BindOnce(&PersonalDataManager::OnValidated,
- weak_factory_.GetWeakPtr()));
- }
- }
-
- // Set the pref to the current major version if already not set.
- if (update_validation)
- pref_service_->SetInteger(prefs::kAutofillLastVersionValidated,
- CHROME_VERSION_MAJOR);
-}
-
-bool PersonalDataManager::UpdateClientValidityStates(
- const AutofillProfile& profile) {
- if (!base::FeatureList::IsEnabled(
- autofill::features::kAutofillProfileClientValidation) ||
- !client_profile_validator_ ||
- profile.is_client_validity_states_updated()) {
- OnValidated(&profile);
- return false;
- }
-
- client_profile_validator_->StartProfileValidation(
- &profile, base::BindOnce(&PersonalDataManager::OnValidated,
- weak_factory_.GetWeakPtr()));
- return true;
-}
-
std::vector<AutofillProfile*> PersonalDataManager::GetServerProfiles() const {
std::vector<AutofillProfile*> result;
if (!IsAutofillProfileEnabled())
@@ -1238,7 +1178,17 @@ PersonalDataManager::GetActiveAutofillPromoCodeOffersForOrigin(
return promo_code_offers_for_origin;
}
-gfx::Image* PersonalDataManager::GetCreditCardArtImageForUrl(
+raw_ptr<gfx::Image> PersonalDataManager::GetCreditCardArtImageForUrl(
+ const GURL& card_art_url) const {
+ raw_ptr<gfx::Image> cached_image = GetCachedCardArtImageForUrl(card_art_url);
+ if (cached_image)
+ return cached_image;
+
+ FetchImagesForUrls({card_art_url});
+ return nullptr;
+}
+
+raw_ptr<gfx::Image> PersonalDataManager::GetCachedCardArtImageForUrl(
const GURL& card_art_url) const {
if (!IsAutofillWalletImportEnabled())
return nullptr;
@@ -1248,14 +1198,14 @@ gfx::Image* PersonalDataManager::GetCreditCardArtImageForUrl(
auto images_iterator = credit_card_art_images_.find(card_art_url);
- // Found an image and return it.
+ // If the cache contains the image, return it.
if (images_iterator != credit_card_art_images_.end()) {
- gfx::Image* image = images_iterator->second.get();
+ raw_ptr<gfx::Image> image = images_iterator->second.get();
if (!image->IsEmpty())
return image;
}
- FetchImagesForUrls({card_art_url});
+ // The cache does not contain the image, return nullptr.
return nullptr;
}
@@ -1275,21 +1225,13 @@ std::vector<AutofillProfile*> PersonalDataManager::GetProfilesToSuggest()
std::vector<AutofillProfile*> profiles = GetProfiles();
- bool use_server_validation = base::FeatureList::IsEnabled(
- autofill::features::kAutofillProfileServerValidation);
- bool use_client_validation = base::FeatureList::IsEnabled(
- autofill::features::kAutofillProfileClientValidation);
-
- // Rank the suggestions by frescocency (see AutofillDataModel for details).
- // Frescocency is frecency + validity score.
+ // Rank the suggestions by frecency.
const base::Time comparison_time = AutofillClock::Now();
- std::sort(profiles.begin(), profiles.end(),
- [comparison_time, use_client_validation, use_server_validation](
- const AutofillProfile* a, const AutofillProfile* b) {
- return a->HasGreaterFrescocencyThan(b, comparison_time,
- use_client_validation,
- use_server_validation);
- });
+ std::sort(
+ profiles.begin(), profiles.end(),
+ [comparison_time](const AutofillProfile* a, const AutofillProfile* b) {
+ return a->HasGreaterFrecencyThan(b, comparison_time);
+ });
return profiles;
}
@@ -1306,11 +1248,6 @@ std::vector<Suggestion> PersonalDataManager::GetProfileSuggestions(
std::u16string field_contents_canon =
comparator.NormalizeForComparison(field_contents);
- if (base::FeatureList::IsEnabled(
- autofill::features::kAutofillProfileServerValidation)) {
- UpdateProfilesServerValidityMapsIfNeeded(GetProfiles());
- }
-
// Get the profiles to suggest, which are already sorted.
std::vector<AutofillProfile*> sorted_profiles = GetProfilesToSuggest();
@@ -1339,13 +1276,13 @@ std::vector<Suggestion> PersonalDataManager::GetProfileSuggestions(
std::unique_ptr<LabelFormatter> formatter;
bool use_formatter;
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
use_formatter = base::FeatureList::IsEnabled(
autofill::features::kAutofillUseImprovedLabelDisambiguation);
#else
use_formatter = base::FeatureList::IsEnabled(
autofill::features::kAutofillUseMobileLabelDisambiguation);
-#endif // !defined(OS_ANDROID) && !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
// The formatter stores a constant reference to |unique_matched_profiles|.
// This is safe since the formatter is destroyed when this function returns.
@@ -1502,60 +1439,6 @@ void PersonalDataManager::SetPrefService(PrefService* pref_service) {
}
}
-void PersonalDataManager::OnValidated(const AutofillProfile* profile) {
- if (!profile)
- return;
-
- if (!ProfileChangesAreOngoing(profile->guid()))
- return;
-
- // Set the validity states updated, only when the validation has occurred. If
- // the rules were not loaded for any reason, don't set the flag.
- bool validity_updated =
- (profile->GetValidityState(ServerFieldType::ADDRESS_HOME_COUNTRY,
- AutofillProfile::CLIENT) !=
- AutofillProfile::UNVALIDATED);
-
- // For every relevant profile change on the ongoing_profile_changes_, mark the
- // change to show that the validation is done, and set the validity of the
- // profile if the validity was updated.
- for (const auto& change : ongoing_profile_changes_[profile->guid()]) {
- if (!profile->EqualsForClientValidationPurpose(*(change.profile())))
- continue;
-
- change.validation_effort_made();
-
- if (validity_updated) {
- change.profile()->set_is_client_validity_states_updated(true);
- change.profile()->SetClientValidityFromBitfieldValue(
- profile->GetClientValidityBitfieldValue());
- }
- }
-
- HandleNextProfileChange(profile->guid());
-}
-
-const ProfileValidityMap& PersonalDataManager::GetProfileValidityByGUID(
- const std::string& guid) {
- static const ProfileValidityMap& empty_validity_map = ProfileValidityMap();
- if (!synced_profile_validity_) {
- profiles_server_validities_need_update_ = true;
- synced_profile_validity_ = std::make_unique<UserProfileValidityMap>();
- if (!synced_profile_validity_->ParseFromString(
- ::autofill::prefs::GetAllProfilesValidityMapsEncodedString(
- pref_service_))) {
- return empty_validity_map;
- }
- }
-
- auto it = synced_profile_validity_->profile_validity().find(guid);
- if (it != synced_profile_validity_->profile_validity().end()) {
- return it->second;
- }
-
- return empty_validity_map;
-}
-
void PersonalDataManager::FetchImagesForUrls(
const std::vector<GURL>& updated_urls) const {
if (!image_fetcher_)
@@ -1969,8 +1852,10 @@ void PersonalDataManager::LogStoredProfileMetrics() const {
// If the user has stored addresses, log the distribution of days since
// their last use and how many would be considered disused.
+ // Additionally, track the number of profiles without a country.
if (!web_profiles_.empty()) {
size_t num_disused_profiles = 0;
+ size_t num_profiles_without_country = 0;
const base::Time now = AutofillClock::Now();
for (const std::unique_ptr<AutofillProfile>& profile : web_profiles_) {
const base::TimeDelta time_since_last_use = now - profile->use_date();
@@ -1978,8 +1863,12 @@ void PersonalDataManager::LogStoredProfileMetrics() const {
time_since_last_use.InDays());
if (time_since_last_use > kDisusedDataModelTimeDelta)
++num_disused_profiles;
+ if (profile->GetRawInfo(ADDRESS_HOME_COUNTRY).empty())
+ ++num_profiles_without_country;
}
AutofillMetrics::LogStoredProfileDisusedCount(num_disused_profiles);
+ AutofillMetrics::LogStoredProfilesWithoutCountry(
+ num_profiles_without_country);
}
// Only log this info once per chrome user profile load.
@@ -2096,8 +1985,8 @@ bool PersonalDataManager::ShouldShowCardsFromAccountOption() const {
// The feature is only for Linux, Windows, Mac, and Fuchsia.
// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
// of lacros-chrome is complete.
-#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS) || defined(OS_WIN) || \
- defined(OS_APPLE) || defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS) || \
+ BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_FUCHSIA)
// This option should only be shown for users that have not enabled the Sync
// Feature and that have server credit cards available.
if (!sync_service_ || sync_service_->IsSyncFeatureEnabled() ||
@@ -2118,8 +2007,8 @@ bool PersonalDataManager::ShouldShowCardsFromAccountOption() const {
return !is_opted_in;
#else
return false;
-#endif // #if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS) ||
- // defined(OS_WIN) || defined(OS_APPLE) || defined(OS_FUCHSIA)
+#endif // #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS) ||
+ // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_FUCHSIA)
}
void PersonalDataManager::OnUserAcceptedCardsFromAccountOption() {
@@ -2146,13 +2035,11 @@ void PersonalDataManager::OnAutofillProfileChanged(
const bool profile_exists = (existing_profile != nullptr);
switch (change_type) {
case AutofillProfileChange::ADD:
- profiles_server_validities_need_update_ = true;
if (!profile_exists && !FindByContents(web_profiles_, profile)) {
web_profiles_.push_back(std::make_unique<AutofillProfile>(profile));
}
break;
case AutofillProfileChange::UPDATE:
- profiles_server_validities_need_update_ = true;
if (profile_exists &&
(change.enforced() ||
!existing_profile->EqualsForUpdatePurposes(profile))) {
@@ -2237,11 +2124,6 @@ void PersonalDataManager::ConvertWalletAddressesAndUpdateWalletCards() {
app_locale_, GetAccountInfoForPaymentsServer().email);
}
-void PersonalDataManager::ResetProfileValidity() {
- synced_profile_validity_.reset();
- profiles_server_validities_need_update_ = true;
-}
-
void PersonalDataManager::AddProfileToDB(const AutofillProfile& profile,
bool enforced) {
if (profile.IsEmpty(app_locale_)) {
@@ -2260,7 +2142,7 @@ void PersonalDataManager::AddProfileToDB(const AutofillProfile& profile,
AutofillProfileDeepChange(AutofillProfileChange::ADD, profile));
if (enforced)
ongoing_profile_changes_[profile.guid()].back().set_enforced();
- UpdateClientValidityStates(profile);
+ HandleNextProfileChange(profile.guid());
}
void PersonalDataManager::UpdateProfileInDB(const AutofillProfile& profile,
@@ -2280,7 +2162,7 @@ void PersonalDataManager::UpdateProfileInDB(const AutofillProfile& profile,
AutofillProfileDeepChange(AutofillProfileChange::UPDATE, profile));
if (enforced)
ongoing_profile_changes_[profile.guid()].back().set_enforced();
- UpdateClientValidityStates(profile);
+ HandleNextProfileChange(profile.guid());
}
void PersonalDataManager::RemoveProfileFromDB(const std::string& guid) {
@@ -2326,9 +2208,6 @@ void PersonalDataManager::HandleNextProfileChange(const std::string& guid) {
return;
}
- if (!change.has_validation_effort_made())
- return;
-
if (change_type == AutofillProfileChange::ADD) {
if (!change.enforced() &&
(profile_exists || FindByContents(web_profiles_, profile))) {
diff --git a/chromium/components/autofill/core/browser/personal_data_manager.h b/chromium/components/autofill/core/browser/personal_data_manager.h
index b8cf8b36026..018972cf59b 100644
--- a/chromium/components/autofill/core/browser/personal_data_manager.h
+++ b/chromium/components/autofill/core/browser/personal_data_manager.h
@@ -21,7 +21,6 @@
#include "build/build_config.h"
#include "components/autofill/core/browser/autofill_profile_save_strike_database.h"
#include "components/autofill/core/browser/autofill_profile_update_strike_database.h"
-#include "components/autofill/core/browser/autofill_profile_validator.h"
#include "components/autofill/core/browser/data_model/autofill_offer_data.h"
#include "components/autofill/core/browser/data_model/autofill_profile.h"
#include "components/autofill/core/browser/data_model/credit_card.h"
@@ -105,7 +104,6 @@ class PersonalDataManager : public KeyedService,
PrefService* pref_service,
PrefService* local_state,
signin::IdentityManager* identity_manager,
- AutofillProfileValidator* client_profile_validator,
history::HistoryService* history_service,
StrikeDatabaseBase* strike_database,
AutofillImageFetcher* image_fetcher,
@@ -259,6 +257,10 @@ class PersonalDataManager : public KeyedService,
// there is no credit card with the specified |instrument_id|.
CreditCard* GetCreditCardByInstrumentId(int64_t instrument_id);
+ // Returns the credit card with the given server id, or nullptr if there is no
+ // match.
+ CreditCard* GetCreditCardByServerId(const std::string& server_id);
+
// Gets the field types available in the stored address and credit card data.
void GetNonEmptyTypes(ServerFieldTypeSet* non_empty_types) const;
@@ -294,22 +296,17 @@ class PersonalDataManager : public KeyedService,
GetActiveAutofillPromoCodeOffersForOrigin(GURL origin) const;
// Returns the customized credit card art image for the |card_art_url|.
- virtual gfx::Image* GetCreditCardArtImageForUrl(
+ virtual raw_ptr<gfx::Image> GetCreditCardArtImageForUrl(
const GURL& card_art_url) const;
- // Updates the validity states of |profiles| according to server validity map.
- void UpdateProfilesServerValidityMapsIfNeeded(
- const std::vector<AutofillProfile*>& profiles);
-
- // Requests an update for the validity states of the |profiles| according to
- // client side validation API: |client_profile_validator_|.
- void UpdateClientValidityStates(
- const std::vector<AutofillProfile*>& profiles);
-
- // Requests an update for the validity states of the |profile| according to
- // the client side validation API: |client_profile_validator_|. Returns true
- // if the validation was requested.
- bool UpdateClientValidityStates(const AutofillProfile& profile);
+ // Returns the cached card art image for the |card_art_url| if it was synced
+ // locally to the client. This function is called within
+ // GetCreditCardArtImageForUrl(), but can also be called separately as an
+ // optimization for situations where a separate fetch request after trying to
+ // retrieve local card art images is not needed. If the card art image is not
+ // present in the cache, this function will return a nullptr.
+ raw_ptr<gfx::Image> GetCachedCardArtImageForUrl(
+ const GURL& card_art_url) const;
// Returns the profiles to suggest to the user, ordered by frecency.
std::vector<AutofillProfile*> GetProfilesToSuggest() const;
@@ -438,11 +435,6 @@ class PersonalDataManager : public KeyedService,
// Returns the value of the AutofillWalletImportEnabled pref.
virtual bool IsAutofillWalletImportEnabled() const;
- void set_client_profile_validator_for_test(
- AutofillProfileValidator* validator) {
- client_profile_validator_ = validator;
- }
-
// Returns true if the PDM is in the off-the-record mode.
bool IsOffTheRecord() { return is_off_the_record_; }
@@ -496,6 +488,7 @@ class PersonalDataManager : public KeyedService,
FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest,
AddCreditCard_CrazyCharacters);
FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest, AddCreditCard_Invalid);
+ FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest, GetCreditCardByServerId);
FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest,
AddAndGetCreditCardArtImage);
FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest,
@@ -559,10 +552,6 @@ class PersonalDataManager : public KeyedService,
FRIEND_TEST_ALL_PREFIXES(
PersonalDataManagerTest,
GetCreditCardsToSuggest_NoCreditCardsAddedIfDisabled);
- FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest,
- RequestProfileServerValidity);
- FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest,
- GetProfileSuggestions_Validity);
FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest, LogStoredCreditCardMetrics);
friend class autofill::AutofillInteractiveTest;
@@ -575,6 +564,7 @@ class PersonalDataManager : public KeyedService,
friend class PersonalDataManagerHelper;
friend class PersonalDataManagerMockTest;
friend class SaveImportedProfileTest;
+ friend class VirtualCardEnrollmentManagerTest;
friend class ::RemoveAutofillTester;
friend std::default_delete<PersonalDataManager>;
friend void autofill_helper::SetProfiles(
@@ -650,13 +640,6 @@ class PersonalDataManager : public KeyedService,
// this class and must outlive |this|.
void SetPrefService(PrefService* pref_service);
- // Called when the |profile| is validated by the AutofillProfileValidator,
- // updates the profiles on the |ongoing_profile_changes_| and the DB.
- virtual void OnValidated(const AutofillProfile* profile);
-
- // Get the profiles fields validity map by |guid|.
- const ProfileValidityMap& GetProfileValidityByGUID(const std::string& guid);
-
// Asks AutofillImageFetcher to fetch images.
virtual void FetchImagesForUrls(const std::vector<GURL>& updated_urls) const;
@@ -716,9 +699,6 @@ class PersonalDataManager : public KeyedService,
std::unique_ptr<AlternativeStateNameMapUpdater>
alternative_state_name_map_updater_;
- // |profile_valditiies_need_update| whenever the profile validities are out of
- bool profiles_server_validities_need_update_ = true;
-
private:
// Saves |imported_credit_card| to the WebDB if it exists. Returns the guid of
// the new or updated card, or the empty string if no card was saved.
@@ -770,9 +750,6 @@ class PersonalDataManager : public KeyedService,
void RemoveAutofillProfileByGUIDAndBlankCreditCardReference(
const std::string& guid);
- // Resets |synced_profile_validity_|.
- void ResetProfileValidity();
-
// Add/Update/Remove |profile| on DB. |enforced| should be true when the
// add/update should happen regardless of an existing/equal profile.
void AddProfileToDB(const AutofillProfile& profile, bool enforced = false);
@@ -855,11 +832,6 @@ class PersonalDataManager : public KeyedService,
// Pref registrar for managing the change observers.
PrefChangeRegistrar pref_registrar_;
- // Profiles validity read from the prefs. They are kept updated by
- // observing changes in pref_services. We need to set the
- // |profile_validities_need_update_| whenever this is changed.
- std::unique_ptr<UserProfileValidityMap> synced_profile_validity_;
-
// PersonalDataManagerCleaner is used to apply various address and credit
// card fixes/cleanups one time at browser startup or when the sync starts.
// PersonalDataManagerCleaner is declared as a friend class.
@@ -869,9 +841,6 @@ class PersonalDataManager : public KeyedService,
std::unordered_map<std::string, std::deque<AutofillProfileDeepChange>>
ongoing_profile_changes_;
- // The client side profile validator.
- raw_ptr<AutofillProfileValidator> client_profile_validator_ = nullptr;
-
// The identity manager that this instance uses. Must outlive this instance.
raw_ptr<signin::IdentityManager> identity_manager_ = nullptr;
diff --git a/chromium/components/autofill/core/browser/personal_data_manager_cleaner.cc b/chromium/components/autofill/core/browser/personal_data_manager_cleaner.cc
index ef5062b1d42..979192224bc 100644
--- a/chromium/components/autofill/core/browser/personal_data_manager_cleaner.cc
+++ b/chromium/components/autofill/core/browser/personal_data_manager_cleaner.cc
@@ -100,9 +100,9 @@ void PersonalDataManagerCleaner::SyncStarted(syncer::ModelType model_type) {
}
void PersonalDataManagerCleaner::ApplyAddressFixesAndCleanups() {
- // Validate profiles once per major.
- personal_data_manager_->UpdateClientValidityStates(
- personal_data_manager_->GetProfiles());
+ // TODO(crbug.com/1288863): Remove prefs in M102 or above.
+ pref_service_->ClearPref(prefs::kAutofillLastVersionValidated);
+ pref_service_->ClearPref(prefs::kAutofillProfileValidity);
// One-time fix, otherwise NOP.
RemoveOrphanAutofillTableRows();
diff --git a/chromium/components/autofill/core/browser/personal_data_manager_unittest.cc b/chromium/components/autofill/core/browser/personal_data_manager_unittest.cc
index 667417dd803..b2aac8ca2d8 100644
--- a/chromium/components/autofill/core/browser/personal_data_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/personal_data_manager_unittest.cc
@@ -46,7 +46,6 @@
#include "components/autofill/core/browser/personal_data_manager_observer.h"
#include "components/autofill/core/browser/sync_utils.h"
#include "components/autofill/core/browser/test_autofill_clock.h"
-#include "components/autofill/core/browser/test_autofill_profile_validator.h"
#include "components/autofill/core/browser/test_inmemory_strike_database.h"
#include "components/autofill/core/browser/ui/label_formatter_utils.h"
#include "components/autofill/core/browser/ui/suggestion_selection.h"
@@ -112,11 +111,6 @@ class PersonalDataManagerMock : public PersonalDataManager {
: PersonalDataManager(app_locale, variations_country_code) {}
~PersonalDataManagerMock() override = default;
- MOCK_METHOD(void, OnValidated, (const AutofillProfile* profile), (override));
- void OnValidatedPDM(const AutofillProfile* profile) {
- PersonalDataManager::OnValidated(profile);
- }
-
MOCK_METHOD(void,
FetchImagesForUrls,
((const std::vector<GURL>& updated_urls)),
@@ -179,8 +173,7 @@ class PersonalDataManagerTestBase {
static std::vector<base::Feature> GetDefaultEnabledFeatures() {
// Enable account storage by default, some tests will override this to be
// false.
- return {features::kAutofillEnableAccountWalletStorage,
- features::kAutofillProfileClientValidation};
+ return {features::kAutofillEnableAccountWalletStorage};
}
PersonalDataManagerTestBase()
@@ -251,7 +244,6 @@ class PersonalDataManagerTestBase {
? scoped_refptr<AutofillWebDataService>(account_database_service_)
: nullptr,
prefs_.get(), prefs_.get(), identity_test_env_.identity_manager(),
- TestAutofillProfileValidator::GetInstance(),
/*history_service=*/nullptr, strike_database_.get(),
/*image_fetcher=*/nullptr, is_incognito);
@@ -267,8 +259,7 @@ class PersonalDataManagerTestBase {
WaitForOnPersonalDataChangedRepeatedly();
}
- bool TurnOnSyncFeature(PersonalDataManager* personal_data)
- WARN_UNUSED_RESULT {
+ [[nodiscard]] bool TurnOnSyncFeature(PersonalDataManager* personal_data) {
sync_service_.SetHasSyncConsent(true);
if (!sync_service_.IsSyncFeatureEnabled())
return false;
@@ -454,7 +445,7 @@ class PersonalDataManagerHelper : public PersonalDataManagerTestBase {
// supported.
// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
// of lacros-chrome is complete.
-#if !(defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS))
+#if !(BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS))
personal_data_->ResetFullServerCard(
personal_data_->GetCreditCards()[0]->guid());
#endif
@@ -606,12 +597,8 @@ class PersonalDataManagerMockTest : public PersonalDataManagerTestBase,
void SetUp() override {
SetUpTest();
ResetPersonalDataManager(USER_MODE_NORMAL);
- // Reset the deduping and profile validation prefs to their default value.
personal_data_->pref_service_->SetInteger(
prefs::kAutofillLastVersionDeduped, 0);
- personal_data_->pref_service_->SetInteger(
- prefs::kAutofillLastVersionValidated,
- atoi(version_info::GetVersionNumber().c_str()));
}
void TearDown() override {
@@ -640,20 +627,9 @@ class PersonalDataManagerMockTest : public PersonalDataManagerTestBase,
atoi(version_info::GetVersionNumber().c_str()));
}
- void ResetAutofillLastVersionValidated() {
- ASSERT_TRUE(personal_data_);
- personal_data_->pref_service_->SetInteger(
- prefs::kAutofillLastVersionValidated, 0);
- }
-
void AddProfileToPersonalDataManager(const AutofillProfile& profile) {
base::RunLoop run_loop;
- EXPECT_CALL(*personal_data_, OnValidated(testing::_)).Times(1);
- ON_CALL(*personal_data_, OnValidated(testing::_))
- .WillByDefault(testing::Invoke(
- personal_data_.get(), &PersonalDataManagerMock::OnValidatedPDM));
-
EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks())
.WillOnce(QuitMessageLoop(&run_loop));
EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
@@ -667,11 +643,6 @@ class PersonalDataManagerMockTest : public PersonalDataManagerTestBase,
void UpdateProfileOnPersonalDataManager(const AutofillProfile& profile) {
base::RunLoop run_loop;
- EXPECT_CALL(*personal_data_, OnValidated(testing::_)).Times(1);
- ON_CALL(*personal_data_, OnValidated(testing::_))
- .WillByDefault(testing::Invoke(
- personal_data_.get(), &PersonalDataManagerMock::OnValidatedPDM));
-
EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks())
.WillOnce(QuitMessageLoop(&run_loop));
EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
@@ -687,39 +658,6 @@ class PersonalDataManagerMockTest : public PersonalDataManagerTestBase,
guid, personal_data_.get());
}
- void UpdateClientValidityStatesOnPersonalDataManager(
- const std::vector<AutofillProfile*>& profiles) {
- int num_updates = 0;
- if (GetLastVersionValidatedUpdate() < CHROME_VERSION_MAJOR) {
- num_updates = profiles.size();
- } else {
- for (auto* profile : profiles) {
- if (!profile->is_client_validity_states_updated())
- num_updates++;
- }
- }
-
- base::RunLoop run_loop;
-
- EXPECT_CALL(*personal_data_, OnValidated(testing::_)).Times(num_updates);
- ON_CALL(*personal_data_, OnValidated(testing::_))
- .WillByDefault(testing::Invoke(
- personal_data_.get(), &PersonalDataManagerMock::OnValidatedPDM));
-
- EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks())
- .WillRepeatedly(QuitMessageLoop(&run_loop));
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
- .Times(testing::AnyNumber());
- // Validate the profiles through the client validation API.
- personal_data_->UpdateClientValidityStates(profiles);
- run_loop.Run();
- }
-
- int GetLastVersionValidatedUpdate() {
- return personal_data_->pref_service_->GetInteger(
- prefs::kAutofillLastVersionValidated);
- }
-
void AddOfferDataForTest(AutofillOfferData offer_data) {
personal_data_->AddOfferDataForTest(
std::make_unique<AutofillOfferData>(offer_data));
@@ -827,29 +765,6 @@ TEST_F(PersonalDataManagerTest, AddRemoveUpdateProfileSequence) {
EXPECT_EQ(profiles[0]->GetRawInfo(EMAIL_ADDRESS), u"newest@email.com");
}
-// The changes should happen in the same order as requested. If the later change
-// is validated before an earlier one, still we should process the earlier one
-// first.
-TEST_F(PersonalDataManagerTest, InconsistentValidationSequence) {
- auto profile = test::GetFullProfile();
- // Slow validation.
- personal_data_->set_client_profile_validator_for_test(
- TestAutofillProfileValidator::GetDelayedInstance());
- personal_data_->AddProfile(profile);
-
- // No validator, zero delay for validation.
- personal_data_->set_client_profile_validator_for_test(nullptr);
- profile.SetRawInfo(EMAIL_ADDRESS, u"new@email.com");
- personal_data_->UpdateProfile(profile);
-
- WaitForOnPersonalDataChanged();
-
- auto profiles = personal_data_->GetProfiles();
- ASSERT_EQ(1U, profiles.size());
- EXPECT_EQ(profiles[0]->GetRawInfo(EMAIL_ADDRESS), u"new@email.com");
- EXPECT_FALSE(profiles[0]->is_client_validity_states_updated());
-}
-
// Test that a new profile has its basic information set.
TEST_F(PersonalDataManagerTest, AddProfile_BasicInformation) {
// Create the test clock and set the time to a specific value.
@@ -1302,7 +1217,18 @@ TEST_F(PersonalDataManagerTest, AddCreditCard_Invalid) {
ASSERT_EQ(card, *personal_data_->GetCreditCards()[0]);
}
-#if !defined(OS_IOS)
+TEST_F(PersonalDataManagerTest, GetCreditCardByServerId) {
+ CreditCard card = test::GetFullServerCard();
+ card.set_server_id("server id");
+ personal_data_->AddFullServerCreditCard(card);
+ WaitForOnPersonalDataChanged();
+
+ ASSERT_EQ(1u, personal_data_->GetCreditCards().size());
+ EXPECT_TRUE(personal_data_->GetCreditCardByServerId("server id"));
+ EXPECT_FALSE(personal_data_->GetCreditCardByServerId("non-existing id"));
+}
+
+#if !BUILDFLAG(IS_IOS)
TEST_F(PersonalDataManagerTest, AddAndGetCreditCardArtImage) {
gfx::Image expected_image = gfx::test::CreateImage(32, 20);
std::unique_ptr<CreditCardArtImage> credit_card_art_image =
@@ -1314,10 +1240,21 @@ TEST_F(PersonalDataManagerTest, AddAndGetCreditCardArtImage) {
personal_data_->OnCardArtImagesFetched(std::move(images));
- gfx::Image* actual_image = personal_data_->GetCreditCardArtImageForUrl(
- GURL("https://www.example.com"));
+ raw_ptr<gfx::Image> actual_image =
+ personal_data_->GetCreditCardArtImageForUrl(
+ GURL("https://www.example.com"));
ASSERT_TRUE(actual_image);
EXPECT_TRUE(gfx::test::AreImagesEqual(expected_image, *actual_image));
+
+ // TODO(crbug.com/1284788): Look into integrating with PersonalDataManagerMock
+ // and checking that PersonalDataManager::FetchImagesForUrls() does not get
+ // triggered when PersonalDataManager::GetCachedCardArtImageForUrl() is
+ // called.
+ raw_ptr<gfx::Image> cached_image =
+ personal_data_->GetCachedCardArtImageForUrl(
+ GURL("https://www.example.com"));
+ ASSERT_TRUE(cached_image);
+ EXPECT_TRUE(gfx::test::AreImagesEqual(expected_image, *cached_image));
}
TEST_F(PersonalDataManagerMockTest, ProcessVirtualCardMetadataChanges) {
@@ -2274,7 +2211,7 @@ TEST_F(PersonalDataManagerTest,
EXPECT_EQ(u"12345678910", suggestions[0].value);
}
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
TEST_F(PersonalDataManagerTest,
GetProfileSuggestions_PhoneSubstring_ImprovedDisambiguation) {
base::test::ScopedFeatureList scoped_features;
@@ -2295,7 +2232,7 @@ TEST_F(PersonalDataManagerTest,
ASSERT_FALSE(suggestions.empty());
EXPECT_EQ(u"(234) 567-8910", suggestions[0].value);
}
-#endif // !defined(OS_ANDROID) && !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
TEST_F(PersonalDataManagerTest, GetProfileSuggestions_HideSubsets) {
AutofillProfile profile(base::GenerateGUID(), test::kEmptyOrigin);
@@ -2541,164 +2478,6 @@ TEST_F(PersonalDataManagerTest,
}
}
-// Tests that suggestions based on invalid data are handled correctly.
-TEST_F(PersonalDataManagerTest, GetProfileSuggestions_Validity) {
- // Set up 2 different profiles: one valid and one invalid.
- AutofillProfile valid_profile(test::GetFullValidProfileForCanada());
- valid_profile.set_use_date(AutofillClock::Now() - base::Days(1));
- valid_profile.set_use_count(1);
- AddProfileToPersonalDataManager(valid_profile);
-
- AutofillProfile invalid_profile(base::GenerateGUID(), test::kEmptyOrigin);
- test::SetProfileInfo(&invalid_profile, "Marion1", "Mitchell", "Morrison",
- "invalid email", "Fox",
- "123 Zoo St.\nSecond Line\nThird line", "unit 5",
- "Hollywood", "CA", "91601", "US", "Invalid Phone");
- invalid_profile.set_use_date(AutofillClock::Now() - base::Days(1));
- invalid_profile.set_use_count(1);
- AddProfileToPersonalDataManager(invalid_profile);
-
- auto profiles = personal_data_->GetProfiles();
- ASSERT_EQ(2U, profiles.size());
-
- // Invalid based on client, and not invalid by server. Relying on both
- // validity sources.
- {
- base::test::ScopedFeatureList scoped_features;
- scoped_features.InitWithFeatures(
- /*enabled_features=*/{features::kAutofillProfileServerValidation,
- features::kAutofillProfileClientValidation},
- /*disabled_features=*/{});
- std::vector<Suggestion> email_suggestions =
- personal_data_->GetProfileSuggestions(AutofillType(EMAIL_ADDRESS),
- std::u16string(), false,
- std::vector<ServerFieldType>());
-
- for (auto* profile : profiles) {
- ASSERT_EQ(profile->guid() == valid_profile.guid(),
- profile->IsValidByClient());
- ASSERT_TRUE(profile->IsValidByServer());
- }
- ASSERT_EQ(1U, email_suggestions.size());
- EXPECT_EQ(u"alice@wonderland.ca", email_suggestions[0].value);
-
- std::vector<Suggestion> name_suggestions =
- personal_data_->GetProfileSuggestions(AutofillType(NAME_FIRST),
- std::u16string(), false,
- std::vector<ServerFieldType>());
- ASSERT_EQ(2U, name_suggestions.size());
- EXPECT_EQ(u"Alice", name_suggestions[0].value);
- EXPECT_EQ(u"Marion1", name_suggestions[1].value);
- }
-
- // Set the validity state of ADDRESS_HOME_STATE to INVALID on the prefs.
- {
- ProfileValidityMap profile_validity_map;
- UserProfileValidityMap user_profile_validity_map;
- std::string autofill_profile_validity;
- personal_data_->pref_service_->SetString(prefs::kAutofillProfileValidity,
- autofill_profile_validity);
- (*profile_validity_map
- .mutable_field_validity_states())[static_cast<int>(EMAIL_ADDRESS)] =
- static_cast<int>(AutofillProfile::INVALID);
- (*user_profile_validity_map
- .mutable_profile_validity())[invalid_profile.guid()] =
- profile_validity_map;
- ASSERT_TRUE(user_profile_validity_map.SerializeToString(
- &autofill_profile_validity));
- base::Base64Encode(autofill_profile_validity, &autofill_profile_validity);
- personal_data_->pref_service_->SetString(prefs::kAutofillProfileValidity,
- autofill_profile_validity);
- }
- // Invalid based on client, and server. Relying on both validity sources.
- {
- base::test::ScopedFeatureList scoped_features;
- scoped_features.InitWithFeatures(
- /*enabled_features=*/{features::kAutofillProfileClientValidation,
- features::kAutofillProfileServerValidation},
- /*disabled_features=*/{});
-
- std::vector<Suggestion> email_suggestions =
- personal_data_->GetProfileSuggestions(AutofillType(EMAIL_ADDRESS),
- std::u16string(), false,
- std::vector<ServerFieldType>());
-
- for (auto* profile : profiles) {
- ASSERT_EQ(profile->guid() == valid_profile.guid(),
- profile->IsValidByClient());
- ASSERT_EQ(profile->guid() == valid_profile.guid(),
- profile->IsValidByServer());
- }
- ASSERT_EQ(1U, email_suggestions.size());
- EXPECT_EQ(u"alice@wonderland.ca", email_suggestions[0].value);
-
- std::vector<Suggestion> name_suggestions =
- personal_data_->GetProfileSuggestions(AutofillType(NAME_FIRST),
- std::u16string(), false,
- std::vector<ServerFieldType>());
- ASSERT_EQ(2U, name_suggestions.size());
- EXPECT_EQ(u"Alice", name_suggestions[0].value);
- EXPECT_EQ(u"Marion1", name_suggestions[1].value);
- }
- // Invalid based on client, and server. Relying only on the client source.
- {
- base::test::ScopedFeatureList scoped_features;
- scoped_features.InitWithFeatures(
- /*enabled_features=*/{features::kAutofillProfileClientValidation},
- /*disabled_features=*/{features::kAutofillProfileServerValidation});
- std::vector<Suggestion> email_suggestions =
- personal_data_->GetProfileSuggestions(AutofillType(EMAIL_ADDRESS),
- std::u16string(), false,
- std::vector<ServerFieldType>());
-
- for (auto* profile : profiles) {
- ASSERT_EQ(profile->guid() == valid_profile.guid(),
- profile->IsValidByClient());
- ASSERT_EQ(profile->guid() == valid_profile.guid(),
- profile->IsValidByServer());
- }
- ASSERT_EQ(1U, email_suggestions.size());
- EXPECT_EQ(u"alice@wonderland.ca", email_suggestions[0].value);
-
- std::vector<Suggestion> name_suggestions =
- personal_data_->GetProfileSuggestions(AutofillType(NAME_FIRST),
- std::u16string(), false,
- std::vector<ServerFieldType>());
- ASSERT_EQ(2U, name_suggestions.size());
- EXPECT_EQ(u"Alice", name_suggestions[0].value);
- EXPECT_EQ(u"Marion1", name_suggestions[1].value);
- }
- // Invalid based on client, and server. Relying on server as a validity
- // source.
- {
- base::test::ScopedFeatureList scoped_features;
- scoped_features.InitWithFeatures(
- /*enabled_features=*/{features::kAutofillProfileServerValidation},
- /*disabled_features=*/{features::kAutofillProfileClientValidation});
- std::vector<Suggestion> email_suggestions =
- personal_data_->GetProfileSuggestions(AutofillType(EMAIL_ADDRESS),
- std::u16string(), false,
- std::vector<ServerFieldType>());
-
- for (auto* profile : profiles) {
- ASSERT_EQ(profile->guid() == valid_profile.guid(),
- profile->IsValidByClient());
- ASSERT_EQ(profile->guid() == valid_profile.guid(),
- profile->IsValidByServer());
- }
- ASSERT_EQ(1U, email_suggestions.size());
- EXPECT_EQ(u"alice@wonderland.ca", email_suggestions[0].value);
-
- std::vector<Suggestion> name_suggestions =
- personal_data_->GetProfileSuggestions(AutofillType(NAME_FIRST),
- std::u16string(), false,
- std::vector<ServerFieldType>());
- ASSERT_EQ(2U, name_suggestions.size());
- EXPECT_EQ(u"Alice", name_suggestions[0].value);
- EXPECT_EQ(u"Marion1", name_suggestions[1].value);
- }
-}
-
// Test that local and server profiles are not shown if
// |kAutofillProfileEnabled| is set to |false|.
TEST_F(PersonalDataManagerTest, GetProfileSuggestions_ProfileAutofillDisabled) {
@@ -2814,7 +2593,7 @@ TEST_F(PersonalDataManagerTest,
EXPECT_EQ(0U, personal_data_->GetProfiles().size());
}
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
TEST_F(PersonalDataManagerTest,
GetProfileSuggestions_LogProfileSuggestionsMadeWithFormatter) {
AutofillProfile profile(base::GenerateGUID(), test::kEmptyOrigin);
@@ -2837,9 +2616,9 @@ TEST_F(PersonalDataManagerTest,
histogram_tester.ExpectUniqueSample(
"Autofill.ProfileSuggestionsMadeWithFormatter", true, 1);
}
-#endif // #if !defined(OS_ANDROID) && !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
TEST_F(PersonalDataManagerTest, GetProfileSuggestions_ForContactForm) {
AutofillProfile profile(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile, "Hoa", "", "Pham", "hoa.pham@comcast.net", "",
@@ -2862,9 +2641,9 @@ TEST_F(PersonalDataManagerTest, GetProfileSuggestions_ForContactForm) {
ConstructLabelLine({u"(978) 674-4120", u"hoa.pham@comcast.net"})),
testing::Field(&Suggestion::icon, ""))));
}
-#endif // #if !defined(OS_ANDROID) && !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
TEST_F(PersonalDataManagerTest, GetProfileSuggestions_AddressForm) {
AutofillProfile profile(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile, "Hoa", "", "Pham", "hoa.pham@comcast.net", "",
@@ -2886,9 +2665,9 @@ TEST_F(PersonalDataManagerTest, GetProfileSuggestions_AddressForm) {
u"401 Merrimack St, Lowell, MA 01852"),
testing::Field(&Suggestion::icon, ""))));
}
-#endif // #if !defined(OS_ANDROID) && !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
TEST_F(PersonalDataManagerTest, GetProfileSuggestions_AddressPhoneForm) {
AutofillProfile profile(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile, "Hoa", "", "Pham", "hoa.pham@comcast.net", "",
@@ -2911,9 +2690,9 @@ TEST_F(PersonalDataManagerTest, GetProfileSuggestions_AddressPhoneForm) {
ConstructLabelLine({u"(978) 674-4120", u"401 Merrimack St"})),
testing::Field(&Suggestion::icon, ""))));
}
-#endif // #if !defined(OS_ANDROID) && !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
TEST_F(PersonalDataManagerTest, GetProfileSuggestions_AddressEmailForm) {
AutofillProfile profile(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile, "Hoa", "", "Pham", "hoa.pham@comcast.net", "",
@@ -2935,9 +2714,9 @@ TEST_F(PersonalDataManagerTest, GetProfileSuggestions_AddressEmailForm) {
u"hoa.pham@comcast.net"})),
testing::Field(&Suggestion::icon, ""))));
}
-#endif // #if !defined(OS_ANDROID) && !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
TEST_F(PersonalDataManagerTest, GetProfileSuggestions_FormWithOneProfile) {
AutofillProfile profile(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile, "Hoa", "", "Pham", "hoa.pham@comcast.net", "",
@@ -2959,9 +2738,9 @@ TEST_F(PersonalDataManagerTest, GetProfileSuggestions_FormWithOneProfile) {
ConstructLabelLine({u"401 Merrimack St"})),
testing::Field(&Suggestion::icon, ""))));
}
-#endif // #if !defined(OS_ANDROID) && !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
TEST_F(PersonalDataManagerTest,
GetProfileSuggestions_AddressContactFormWithProfiles) {
AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
@@ -3010,9 +2789,9 @@ TEST_F(PersonalDataManagerTest,
u"hp@aol.com"})),
testing::Field(&Suggestion::icon, ""))));
}
-#endif // #if !defined(OS_ANDROID) && !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
TEST_F(PersonalDataManagerTest, GetProfileSuggestions_MobileShowOne) {
std::map<std::string, std::string> parameters;
parameters[features::kAutofillUseMobileLabelDisambiguationParameterName] =
@@ -3066,9 +2845,9 @@ TEST_F(PersonalDataManagerTest, GetProfileSuggestions_MobileShowOne) {
AllOf(testing::Field(&Suggestion::label, u"11 Elkins St"),
testing::Field(&Suggestion::icon, ""))));
}
-#endif // if defined(OS_ANDROID) || defined(OS_IOS)
+#endif // if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
TEST_F(PersonalDataManagerTest, GetProfileSuggestions_MobileShowAll) {
std::map<std::string, std::string> parameters;
parameters[features::kAutofillUseMobileLabelDisambiguationParameterName] =
@@ -3131,7 +2910,7 @@ TEST_F(PersonalDataManagerTest, GetProfileSuggestions_MobileShowAll) {
u"(617) 268-6862"})),
testing::Field(&Suggestion::icon, ""))));
}
-#endif // if defined(OS_ANDROID) || defined(OS_IOS)
+#endif // if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
TEST_F(PersonalDataManagerTest, IsKnownCard_MatchesMaskedServerCard) {
// Add a masked server card.
@@ -6004,6 +5783,8 @@ TEST_F(PersonalDataManagerTest, LogStoredProfileMetrics_NoStoredProfiles) {
histogram_tester.ExpectTotalCount("Autofill.StoredProfileCount", 1);
histogram_tester.ExpectBucketCount("Autofill.StoredProfileCount", 0, 1);
histogram_tester.ExpectTotalCount("Autofill.StoredProfileDisusedCount", 0);
+ histogram_tester.ExpectTotalCount("Autofill.StoredProfileWithoutCountryCount",
+ 0);
histogram_tester.ExpectTotalCount("Autofill.DaysSinceLastUse.StoredProfile",
0);
}
@@ -6016,11 +5797,11 @@ TEST_F(PersonalDataManagerTest, LogStoredProfileMetrics) {
profile0.set_use_date(AutofillClock::Now() - base::Days(3));
AddProfileToPersonalDataManager(profile0);
- // Add a profile used a long time (200 days) ago.
+ // Add a profile used a long time (200 days) ago without a country.
AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile1, "Seb", "", "Doe", "", "ACME",
"1234 Evergreen Terrace", "Bld. 5", "Springfield", "IL",
- "32801", "US", "15151231234");
+ "32801", "", "15151231234");
profile1.set_use_date(AutofillClock::Now() - base::Days(200));
AddProfileToPersonalDataManager(profile1);
@@ -6036,6 +5817,11 @@ TEST_F(PersonalDataManagerTest, LogStoredProfileMetrics) {
histogram_tester.ExpectBucketCount("Autofill.StoredProfileDisusedCount", 1,
1);
+ histogram_tester.ExpectTotalCount("Autofill.StoredProfileWithoutCountryCount",
+ 1);
+ histogram_tester.ExpectBucketCount(
+ "Autofill.StoredProfileWithoutCountryCount", 1, 1);
+
histogram_tester.ExpectTotalCount("Autofill.DaysSinceLastUse.StoredProfile",
2);
histogram_tester.ExpectBucketCount("Autofill.DaysSinceLastUse.StoredProfile",
@@ -6244,7 +6030,7 @@ TEST_F(PersonalDataManagerTest, CreateDataForTest) {
// cards.
// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
// of lacros-chrome is complete.
-#if !(defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS))
+#if !(BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS))
// Test that calling OnSyncServiceInitialized with a null sync service remasks
// full server cards.
TEST_F(PersonalDataManagerTest, OnSyncServiceInitialized_NoSyncService) {
@@ -6293,9 +6079,9 @@ TEST_F(PersonalDataManagerTest, OnSyncServiceInitialized_NotActiveSyncService) {
// OnSyncServiceInitialized.
personal_data_->OnSyncShutdown(&sync_service);
}
-#endif // !(defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS))
+#endif // !(BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS))
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
TEST_F(PersonalDataManagerTest, ExcludeServerSideCards) {
SetUpThreeCardTypes();
@@ -6309,11 +6095,11 @@ TEST_F(PersonalDataManagerTest, ExcludeServerSideCards) {
EXPECT_EQ(1U, personal_data_->GetLocalCreditCards().size());
EXPECT_EQ(2U, personal_data_->GetServerCreditCards().size());
}
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
// Sync Transport mode is only for Win, Mac, and Linux.
-#if defined(OS_WIN) || defined(OS_MAC) || defined(OS_LINUX) || \
- defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || \
+ BUILDFLAG(IS_CHROMEOS)
TEST_F(PersonalDataManagerTest, ServerCardsShowInTransportMode) {
// Set up PersonalDataManager in transport mode.
ResetPersonalDataManager(USER_MODE_NORMAL,
@@ -6375,8 +6161,8 @@ TEST_F(PersonalDataManagerTest, ServerCardsShowInTransportMode_NeedOptIn) {
EXPECT_EQ(1U, personal_data_->GetLocalCreditCards().size());
EXPECT_EQ(2U, personal_data_->GetServerCreditCards().size());
}
-#endif // defined(OS_WIN) || defined(OS_MAC) || defined(OS_LINUX) ||
- // defined(OS_CHROMEOS)
+#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) ||
+ // BUILDFLAG(IS_CHROMEOS)
// Tests that all the non settings origins of autofill profiles are cleared but
// that the settings origins are untouched.
@@ -6671,371 +6457,6 @@ TEST_F(PersonalDataManagerTest, UseCorrectStorageForDifferentCards) {
EXPECT_EQ(profile, *profiles[0]);
}
-// Requests profiles fields validities according to the server: empty profiles,
-// non-existent profiles, and normal ones.
-TEST_F(PersonalDataManagerTest, RequestProfileServerValidity) {
- ResetPersonalDataManager(USER_MODE_NORMAL);
-
- ProfileValidityMap profile_validity_map;
- UserProfileValidityMap user_profile_validity_map;
- std::string autofill_profile_validity;
-
- // Empty validity map.
- ASSERT_TRUE(
- user_profile_validity_map.SerializeToString(&autofill_profile_validity));
- base::Base64Encode(autofill_profile_validity, &autofill_profile_validity);
- personal_data_->pref_service_->SetString(prefs::kAutofillProfileValidity,
- autofill_profile_validity);
-
- std::string guid = "00000000-0000-0000-0000-0000000000001";
- EXPECT_TRUE(personal_data_->GetProfileValidityByGUID(guid)
- .field_validity_states()
- .empty());
-
- // Non-empty validity map.
- std::vector<ServerFieldType> types = {
- ADDRESS_HOME_LINE1, ADDRESS_HOME_STATE, ADDRESS_HOME_COUNTRY,
- EMAIL_ADDRESS, ADDRESS_HOME_ZIP, NAME_FULL};
- std::vector<AutofillDataModel::ValidityState> states = {
- AutofillDataModel::UNSUPPORTED, AutofillDataModel::EMPTY,
- AutofillDataModel::INVALID, AutofillDataModel::VALID,
- AutofillDataModel::UNVALIDATED, AutofillDataModel::INVALID};
- ASSERT_EQ(types.size(), states.size());
- for (uint64_t i = 0; i < types.size(); ++i) {
- (*profile_validity_map
- .mutable_field_validity_states())[static_cast<int>(types[i])] =
- static_cast<int>(states[i]);
- }
- (*user_profile_validity_map.mutable_profile_validity())[guid] =
- profile_validity_map;
- ASSERT_TRUE(
- user_profile_validity_map.SerializeToString(&autofill_profile_validity));
- base::Base64Encode(autofill_profile_validity, &autofill_profile_validity);
- personal_data_->pref_service_->SetString(prefs::kAutofillProfileValidity,
- autofill_profile_validity);
-
- // Add another non-empty valdity profile.
- guid = "00000000-0000-0000-0000-0000000000002";
- profile_validity_map.Clear();
- autofill_profile_validity.clear();
- (*profile_validity_map
- .mutable_field_validity_states())[static_cast<int>(EMAIL_ADDRESS)] =
- static_cast<int>(AutofillDataModel::VALID);
- (*user_profile_validity_map.mutable_profile_validity())[guid] =
- profile_validity_map;
- ASSERT_TRUE(
- user_profile_validity_map.SerializeToString(&autofill_profile_validity));
- base::Base64Encode(autofill_profile_validity, &autofill_profile_validity);
- personal_data_->pref_service_->SetString(prefs::kAutofillProfileValidity,
- autofill_profile_validity);
-
- // Profile not found.
- guid = "00000000-0000-0000-0000-0000000000003";
- EXPECT_TRUE(personal_data_->GetProfileValidityByGUID(guid)
- .field_validity_states()
- .empty());
-
- // Existing Profiles.
- guid = "00000000-0000-0000-0000-0000000000001";
- auto validities =
- personal_data_->GetProfileValidityByGUID(guid).field_validity_states();
- ASSERT_EQ(validities.size(), types.size());
- for (uint64_t i = 0; i < types.size(); ++i)
- EXPECT_EQ(validities.at(types[i]), states[i]);
-
- guid = "00000000-0000-0000-0000-0000000000002";
- validities =
- personal_data_->GetProfileValidityByGUID(guid).field_validity_states();
- ASSERT_FALSE(validities.empty());
- EXPECT_EQ(validities.at(EMAIL_ADDRESS), AutofillDataModel::VALID);
-}
-
-// Use the client side validation API to validate three PDM profiles. This one
-// doesn't test the upload process or saving to the database.
-TEST_F(PersonalDataManagerMockTest, UpdateClientValidityStates) {
- AutofillProfile profile_invalid_province(base::GenerateGUID(),
- test::kEmptyOrigin);
- test::SetProfileInfo(&profile_invalid_province, "Alice", "", "Munro",
- "alice@munro.ca", "Fox", "123 Zoo St", "unit 5",
- "Montreal", "CA", "H3C 2A3", "CA", "15142343254");
- AddProfileToPersonalDataManager(profile_invalid_province);
-
- ASSERT_EQ(1U, personal_data_->GetProfiles().size());
- auto profiles = personal_data_->GetProfiles();
- profiles[0]->set_is_client_validity_states_updated(false);
-
- UpdateClientValidityStatesOnPersonalDataManager(profiles);
-
- profiles = personal_data_->GetProfiles();
- ASSERT_EQ(1U, profiles.size());
-
- EXPECT_TRUE(profiles[0]->is_client_validity_states_updated());
- EXPECT_EQ(AutofillDataModel::VALID,
- profiles[0]->GetValidityState(ADDRESS_HOME_COUNTRY,
- AutofillProfile::CLIENT));
- EXPECT_EQ(AutofillDataModel::INVALID,
- profiles[0]->GetValidityState(ADDRESS_HOME_STATE,
- AutofillProfile::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profiles[0]->GetValidityState(ADDRESS_HOME_ZIP, AutofillProfile::CLIENT));
- EXPECT_EQ(AutofillDataModel::VALID,
- profiles[0]->GetValidityState(ADDRESS_HOME_CITY,
- AutofillProfile::CLIENT));
- EXPECT_EQ(AutofillDataModel::EMPTY,
- profiles[0]->GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
- AutofillProfile::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profiles[0]->GetValidityState(EMAIL_ADDRESS, AutofillProfile::CLIENT));
- EXPECT_EQ(AutofillDataModel::VALID,
- profiles[0]->GetValidityState(PHONE_HOME_WHOLE_NUMBER,
- AutofillProfile::CLIENT));
-}
-
-// Check the validity update status for AutofillProfiles.
-TEST_F(PersonalDataManagerMockTest, UpdateClientValidityStates_UpdatedFlag) {
- // Create two profiles and add them to personal_data_.
- AutofillProfile profile1(test::GetFullValidProfileForCanada());
- AddProfileToPersonalDataManager(profile1);
-
- AutofillProfile profile2(test::GetFullValidProfileForChina());
- AddProfileToPersonalDataManager(profile2);
-
- ASSERT_EQ(2U, personal_data_->GetProfiles().size());
-
- // The validities were set when the profiles were added.
- auto profiles = personal_data_->GetProfiles();
- ASSERT_TRUE(profiles[0]->is_client_validity_states_updated());
- ASSERT_TRUE(profiles[1]->is_client_validity_states_updated());
-
- *profiles[1] = *profiles[0];
- ASSERT_TRUE(profiles[0]->is_client_validity_states_updated());
- ASSERT_TRUE(profiles[1]->is_client_validity_states_updated());
-
- profiles[1]->SetRawInfo(PHONE_HOME_WHOLE_NUMBER, u"");
- ASSERT_TRUE(profiles[0]->is_client_validity_states_updated());
- ASSERT_FALSE(profiles[1]->is_client_validity_states_updated());
-
- profiles[0]->SetRawInfo(NAME_FULL, u"Goli Boli");
- ASSERT_TRUE(profiles[0]->is_client_validity_states_updated());
-}
-
-// Check the validity update status for AutofillProfiles.
-TEST_F(PersonalDataManagerMockTest,
- UpdateClientValidityStates_UpdatedFlag_Merge) {
- // Set the pref to the current major version.
- StopTheDedupeProcess();
-
- AutofillProfile profile1(test::GetFullValidProfileForCanada());
- AddProfileToPersonalDataManager(profile1);
-
- AutofillProfile profile2(test::GetFullValidProfileForCanada());
- profile2.set_guid("00000000-0000-0000-0000-000000002019");
- profile2.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, u"");
- profile2.FinalizeAfterImport();
- AddProfileToPersonalDataManager(profile2);
-
- // The validities were set when the profiles were added.
- auto profiles = personal_data_->GetProfiles();
- ASSERT_EQ(2U, profiles.size());
-
- // In the legacy implementation of names, the merge operation populates the
- // full name field. This results in a change of the name although the names
- // are technically the same. For structured names, this is not true anymore,
- // because a name is always in a finalized state. To enforce a non-noop merge
- // for structured names, we lift the verification status of the full name.
- // TODO(crbug.com/1103421): Make the test logic less implicit once structured
- // names are fully launched and remove feature test.
- if (base::FeatureList::IsEnabled(
- features::kAutofillEnableSupportForMoreStructureInNames)) {
- profiles[0]->SetRawInfoWithVerificationStatus(
- NAME_FULL, profiles[1]->GetRawInfo(NAME_FULL),
- structured_address::VerificationStatus::kUserVerified);
- }
- profiles[1]->MergeDataFrom(*profiles[0], "en");
- ASSERT_TRUE(profiles[0]->is_client_validity_states_updated());
- ASSERT_FALSE(profiles[1]->is_client_validity_states_updated());
-}
-
-// Check that the validity states are not updated when the validity flags are up
-// to date.
-TEST_F(PersonalDataManagerMockTest, UpdateClientValidityStates_AlreadyUpdated) {
- // Create two profiles and add them to personal_data_.
- AutofillProfile profile1(test::GetFullValidProfileForCanada());
- profile1.SetRawInfo(EMAIL_ADDRESS, u"invalid email!");
- AddProfileToPersonalDataManager(profile1);
-
- auto profiles = personal_data_->GetProfiles();
- ASSERT_EQ(1U, profiles.size());
- // The validities were updated when the profile was added.
- EXPECT_EQ(
- AutofillDataModel::INVALID,
- profiles[0]->GetValidityState(EMAIL_ADDRESS, AutofillProfile::CLIENT));
-
- // Change the email, the validity update would turn false.
- profiles[0]->SetRawInfo(EMAIL_ADDRESS, u"alice@gmail.com");
- EXPECT_FALSE(profiles[0]->is_client_validity_states_updated());
- // Pretend that the validity states are updated.
- profiles[0]->set_is_client_validity_states_updated(true);
-
- // Validating the profiles through the client validation API should not change
- // the validity states.
- personal_data_->UpdateClientValidityStates(profiles);
-
- profiles = personal_data_->GetProfiles();
- ASSERT_EQ(1U, profiles.size());
- EXPECT_EQ(
- AutofillDataModel::INVALID,
- profiles[0]->GetValidityState(EMAIL_ADDRESS, AutofillProfile::CLIENT));
-
- // Try with the flag as not updated.
- profiles[0]->set_is_client_validity_states_updated(false);
-
- UpdateClientValidityStatesOnPersonalDataManager(profiles);
-
- profiles = personal_data_->GetProfiles();
- ASSERT_EQ(1U, profiles.size());
- EXPECT_EQ(
- AutofillDataModel::VALID,
- profiles[0]->GetValidityState(EMAIL_ADDRESS, AutofillProfile::CLIENT));
-}
-
-// Verify that the fields are validated according to the version.
-TEST_F(PersonalDataManagerMockTest, UpdateClientValidityStates_Version) {
- // Create two profiles and add them to personal_data_. Set the guids
- // explicitly to preserve the order.
- AutofillProfile profile2(test::GetFullValidProfileForChina());
- profile2.SetRawInfo(ADDRESS_HOME_STATE, u"invalid state!");
- profile2.set_guid("00000000-0000-0000-0000-000000000002");
- profile2.set_use_date(AutofillClock::Now() - base::Days(200));
- AddProfileToPersonalDataManager(profile2);
-
- AutofillProfile profile1(test::GetFullValidProfileForCanada());
- profile1.SetRawInfo(EMAIL_ADDRESS, u"invalid email!");
- profile1.set_use_date(AutofillClock::Now());
- profile1.set_guid("00000000-0000-0000-0000-000000000001");
- AddProfileToPersonalDataManager(profile1);
-
- auto profiles = personal_data_->GetProfiles();
- ASSERT_EQ(2U, profiles.size());
-
- EXPECT_TRUE(profiles[0]->is_client_validity_states_updated());
- EXPECT_TRUE(profiles[1]->is_client_validity_states_updated());
- EXPECT_EQ(CHROME_VERSION_MAJOR, GetLastVersionValidatedUpdate());
-
- // No validation as both validity update flags are true, and the validation
- // version is set to this version.
- base::RunLoop run_loop;
- EXPECT_CALL(*personal_data_, OnValidated(testing::_)).Times(0);
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()).Times(0);
- personal_data_->UpdateClientValidityStates(profiles);
-
- profiles = personal_data_->GetProfiles();
- ASSERT_EQ(2U, profiles.size());
- ResetAutofillLastVersionValidated();
-
- EXPECT_EQ(0, GetLastVersionValidatedUpdate());
- EXPECT_TRUE(profiles[0]->is_client_validity_states_updated());
- EXPECT_TRUE(profiles[1]->is_client_validity_states_updated());
-
- // Should validate regardless of the validity update flag, because of the
- // major version update.
- EXPECT_CALL(*personal_data_, OnValidated(testing::_)).Times(2);
- ON_CALL(*personal_data_, OnValidated(testing::_))
- .WillByDefault(testing::Invoke(personal_data_.get(),
- &PersonalDataManagerMock::OnValidatedPDM));
-
- EXPECT_CALL(personal_data_observer_, OnPersonalDataFinishedProfileTasks())
- .WillRepeatedly(QuitMessageLoop(&run_loop));
- EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()).Times(2);
- // Validate the profiles through the client validation API.
- personal_data_->UpdateClientValidityStates(profiles);
- run_loop.Run();
-
- profiles = personal_data_->GetProfiles();
- ASSERT_EQ(2U, profiles.size());
- ASSERT_EQ(profiles[0]->guid(), profile1.guid());
-
- // Verify that the version of the last update is set to this version.
- EXPECT_EQ(CHROME_VERSION_MAJOR, GetLastVersionValidatedUpdate());
-
- EXPECT_EQ(AutofillDataModel::VALID,
- profiles[0]->GetValidityState(ADDRESS_HOME_COUNTRY,
- AutofillProfile::CLIENT));
- EXPECT_EQ(
- AutofillDataModel::INVALID,
- profiles[0]->GetValidityState(EMAIL_ADDRESS, AutofillProfile::CLIENT));
-
- EXPECT_EQ(AutofillDataModel::VALID,
- profiles[1]->GetValidityState(ADDRESS_HOME_COUNTRY,
- AutofillProfile::CLIENT));
- EXPECT_EQ(AutofillDataModel::INVALID,
- profiles[1]->GetValidityState(ADDRESS_HOME_STATE,
- AutofillProfile::CLIENT));
-}
-
-// Verifies that the profiles are validated when added, updated.
-TEST_F(PersonalDataManagerMockTest, UpdateProfilesValidityStates_AddUpdate) {
- // Add
- AutofillProfile profile1(test::GetFullValidProfileForCanada());
- AddProfileToPersonalDataManager(profile1);
-
- auto profiles = personal_data_->GetProfiles();
- ASSERT_EQ(1U, profiles.size());
- EXPECT_EQ(true, profiles[0]->is_client_validity_states_updated());
-
- // Update
- profile1.SetRawInfo(EMAIL_ADDRESS, u"email!");
- UpdateProfileOnPersonalDataManager(profile1);
-
- profiles = personal_data_->GetProfiles();
- ASSERT_EQ(1U, profiles.size());
- EXPECT_EQ(true, profiles[0]->is_client_validity_states_updated());
-}
-
-// Verify that slow delayed validation will still work.
-TEST_F(PersonalDataManagerMockTest, UpdateClientValidityStates_Delayed) {
- personal_data_->set_client_profile_validator_for_test(
- TestAutofillProfileValidator::GetDelayedInstance());
-
- AutofillProfile profile(test::GetFullProfile());
- AddProfileToPersonalDataManager(profile);
-
- auto profiles = personal_data_->GetProfiles();
- ASSERT_EQ(1U, profiles.size());
-
- profiles[0]->set_is_client_validity_states_updated(false);
-
- UpdateClientValidityStatesOnPersonalDataManager(profiles);
- profiles[0] =
- nullptr; // make sure the async task doesn't depend on the pointer.
-
- profiles = personal_data_->GetProfiles();
- ASSERT_EQ(1U, profiles.size());
- EXPECT_TRUE(profiles[0]->is_client_validity_states_updated());
-}
-
-// The validation should not happen when the feature is disabled.
-TEST_F(PersonalDataManagerTest, UpdateClientValidityStates_Disabled) {
- base::test::ScopedFeatureList scoped_features;
- scoped_features.InitAndDisableFeature(
- features::kAutofillProfileClientValidation);
-
- AutofillProfile profile1(test::GetFullValidProfileForCanada());
- AddProfileToPersonalDataManager(profile1);
-
- auto profiles = personal_data_->GetProfiles();
- EXPECT_FALSE(profiles[0]->is_client_validity_states_updated());
-
- personal_data_->UpdateClientValidityStates(profiles);
-
- EXPECT_FALSE(profiles[0]->is_client_validity_states_updated());
- EXPECT_EQ(AutofillDataModel::UNVALIDATED,
- profiles[0]->GetValidityState(ADDRESS_HOME_COUNTRY,
- AutofillProfile::CLIENT));
-}
-
// Tests that the least recently used profile of two existing profiles is
// deleted, when an update of one of the profiles makes it a duplicate of the
// other, already existing profile. Here, the less recently used profile is
@@ -7285,7 +6706,7 @@ TEST_F(PersonalDataManagerTest, ClearUrlsFromBrowsingHistoryInTimeRange) {
// On mobile, no dedicated opt-in is required for WalletSyncTransport - the
// user is always considered opted-in and thus this test doesn't make sense.
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
TEST_F(PersonalDataManagerMigrationTest,
MigrateUserOptedInWalletSyncTransportIfNeeded) {
ASSERT_EQ(
@@ -7304,9 +6725,9 @@ TEST_F(PersonalDataManagerMigrationTest,
EXPECT_TRUE(::autofill::prefs::IsUserOptedInWalletSyncTransport(
prefs_.get(), sync_service_.GetAccountInfo().account_id));
}
-#endif // !defined(OS_ANDROID) && !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
-#if !defined(OS_ANDROID) && !defined(OS_IOS) && !BUILDFLAG(IS_CHROMEOS_ASH)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) && !BUILDFLAG(IS_CHROMEOS_ASH)
TEST_F(PersonalDataManagerTest, ShouldShowCardsFromAccountOption) {
// The method should return false if one of these is not respected:
// * The sync_service is not null
@@ -7380,7 +6801,7 @@ TEST_F(PersonalDataManagerTest, ShouldShowCardsFromAccountOption) {
personal_data_->OnSyncServiceInitialized(nullptr);
EXPECT_FALSE(personal_data_->ShouldShowCardsFromAccountOption());
}
-#else // !defined(OS_ANDROID) && !defined(OS_IOS) &&
+#else // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) &&
// !BUILDFLAG(IS_CHROMEOS_ASH)
TEST_F(PersonalDataManagerTest, ShouldShowCardsFromAccountOption) {
// The method should return false if one of these is not respected:
@@ -7455,7 +6876,7 @@ TEST_F(PersonalDataManagerTest, ShouldShowCardsFromAccountOption) {
personal_data_->OnSyncServiceInitialized(nullptr);
EXPECT_FALSE(personal_data_->ShouldShowCardsFromAccountOption());
}
-#endif // !defined(OS_ANDROID) && !defined(OS_IOS) &&
+#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) &&
// !BUILDFLAG(IS_CHROMEOS_ASH)
TEST_F(PersonalDataManagerTest, GetSyncSigninState) {
@@ -7545,7 +6966,7 @@ TEST_F(PersonalDataManagerTest, GetSyncSigninState) {
// On mobile, no dedicated opt-in is required for WalletSyncTransport - the
// user is always considered opted-in and thus this test doesn't make sense.
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
TEST_F(PersonalDataManagerTest, OnUserAcceptedUpstreamOffer) {
///////////////////////////////////////////////////////////
// kSignedInAndWalletSyncTransportEnabled
@@ -7642,7 +7063,7 @@ TEST_F(PersonalDataManagerTest, OnUserAcceptedUpstreamOffer) {
prefs_.get(), active_info.account_id));
}
}
-#endif // !defined(OS_ANDROID) && !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
namespace {
diff --git a/chromium/components/autofill/core/browser/proto/server.proto b/chromium/components/autofill/core/browser/proto/server.proto
index 96ecfa74ae3..25264f3988c 100644
--- a/chromium/components/autofill/core/browser/proto/server.proto
+++ b/chromium/components/autofill/core/browser/proto/server.proto
@@ -340,8 +340,10 @@ message AutofillUploadContents {
repeated int32 validity = 2;
}
// A list of possible types for the field with their corresponding validity
- // states based on the user's data.
- repeated AutofillTypeValiditiesPair autofill_type_validities = 35;
+ // states based on the user's data. Deprecated in M99 after unsuccessful
+ // experiments.
+ repeated AutofillTypeValiditiesPair autofill_type_validities = 35
+ [deprecated = true];
// A low-entropy hash of the field's initial value before user-interactions
// or automatic fillings. This field is used to detect static
diff --git a/chromium/components/autofill/core/browser/test_autofill_client.cc b/chromium/components/autofill/core/browser/test_autofill_client.cc
index 2e1be15a104..5f1944fed85 100644
--- a/chromium/components/autofill/core/browser/test_autofill_client.cc
+++ b/chromium/components/autofill/core/browser/test_autofill_client.cc
@@ -5,13 +5,14 @@
#include "components/autofill/core/browser/test_autofill_client.h"
#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
#include "components/autofill/core/browser/metrics/autofill_metrics.h"
#include "components/autofill/core/browser/payments/local_card_migration_manager.h"
#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
#include "components/version_info/channel.h"
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
#include "components/autofill/core/browser/payments/test_internal_authenticator.h"
#endif
@@ -101,7 +102,11 @@ translate::TranslateDriver* TestAutofillClient::GetTranslateDriver() {
return &mock_translate_driver_;
}
-#if !defined(OS_IOS)
+std::string TestAutofillClient::GetVariationConfigCountryCode() const {
+ return variation_config_country_code_;
+}
+
+#if !BUILDFLAG(IS_IOS)
std::unique_ptr<webauthn::InternalAuthenticator>
TestAutofillClient::CreateCreditCardInternalAuthenticator(
content::RenderFrameHost* rfh) {
@@ -118,7 +123,12 @@ void TestAutofillClient::ShowUnmaskPrompt(
void TestAutofillClient::OnUnmaskVerificationResult(PaymentsRpcResult result) {}
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+raw_ptr<VirtualCardEnrollmentManager>
+TestAutofillClient::GetVirtualCardEnrollmentManager() {
+ return form_data_importer_->GetVirtualCardEnrollmentManager();
+}
+
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
std::vector<std::string>
TestAutofillClient::GetAllowedMerchantsForVirtualCards() {
return allowed_merchants_;
@@ -173,7 +183,7 @@ void TestAutofillClient::OfferVirtualCardOptions(
const std::vector<CreditCard*>& candidates,
base::OnceCallback<void(const std::string&)> callback) {}
-#else // defined(OS_ANDROID) || defined(OS_IOS)
+#else // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
void TestAutofillClient::ConfirmAccountNameFixFlow(
base::OnceCallback<void(const std::u16string&)> callback) {
credit_card_name_fix_flow_bubble_was_shown_ = true;
@@ -257,12 +267,17 @@ void TestAutofillClient::HideAutofillPopup(PopupHidingReason reason) {}
void TestAutofillClient::ShowVirtualCardErrorDialog(bool is_permanent_error) {
virtual_card_error_dialog_shown_ = true;
+ virtual_card_error_dialog_is_permanent_error_ = is_permanent_error;
}
bool TestAutofillClient::IsAutocompleteEnabled() {
return true;
}
+bool TestAutofillClient::IsPasswordManagerEnabled() {
+ return true;
+}
+
void TestAutofillClient::PropagateAutofillPredictions(
content::RenderFrameHost* rfh,
const std::vector<FormStructure*>& forms) {}
@@ -291,7 +306,7 @@ void TestAutofillClient::LoadRiskData(
std::move(callback).Run("some risk data");
}
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
bool TestAutofillClient::IsQueryIDRelevant(int query_id) {
return true;
}
diff --git a/chromium/components/autofill/core/browser/test_autofill_client.h b/chromium/components/autofill/core/browser/test_autofill_client.h
index 4d96be05920..c18bcbb8c36 100644
--- a/chromium/components/autofill/core/browser/test_autofill_client.h
+++ b/chromium/components/autofill/core/browser/test_autofill_client.h
@@ -31,7 +31,7 @@
#include "components/version_info/channel.h"
#include "services/metrics/public/cpp/delegating_ukm_recorder.h"
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
#include "components/webauthn/core/browser/internal_authenticator.h"
#endif
@@ -66,7 +66,8 @@ class TestAutofillClient : public AutofillClient {
security_state::SecurityLevel GetSecurityLevelForUmaHistograms() override;
translate::LanguageState* GetLanguageState() override;
translate::TranslateDriver* GetTranslateDriver() override;
-#if !defined(OS_IOS)
+ std::string GetVariationConfigCountryCode() const override;
+#if !BUILDFLAG(IS_IOS)
std::unique_ptr<webauthn::InternalAuthenticator>
CreateCreditCardInternalAuthenticator(content::RenderFrameHost* rfh) override;
#endif
@@ -76,8 +77,9 @@ class TestAutofillClient : public AutofillClient {
UnmaskCardReason reason,
base::WeakPtr<CardUnmaskDelegate> delegate) override;
void OnUnmaskVerificationResult(PaymentsRpcResult result) override;
-
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+ raw_ptr<VirtualCardEnrollmentManager> GetVirtualCardEnrollmentManager()
+ override;
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
std::vector<std::string> GetAllowedMerchantsForVirtualCards() override;
std::vector<std::string> GetAllowedBinRangesForVirtualCards() override;
@@ -105,7 +107,7 @@ class TestAutofillClient : public AutofillClient {
void OfferVirtualCardOptions(
const std::vector<CreditCard*>& candidates,
base::OnceCallback<void(const std::string&)> callback) override;
-#else // defined(OS_ANDROID) || defined(OS_IOS)
+#else // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
void ConfirmAccountNameFixFlow(
base::OnceCallback<void(const std::u16string&)> callback) override;
void ConfirmExpirationDateFixFlow(
@@ -147,6 +149,7 @@ class TestAutofillClient : public AutofillClient {
void HideAutofillPopup(PopupHidingReason reason) override;
void ShowVirtualCardErrorDialog(bool is_permanent_error) override;
bool IsAutocompleteEnabled() override;
+ bool IsPasswordManagerEnabled() override;
void PropagateAutofillPredictions(
content::RenderFrameHost* rfh,
const std::vector<FormStructure*>& forms) override;
@@ -164,7 +167,7 @@ class TestAutofillClient : public AutofillClient {
void LoadRiskData(
base::OnceCallback<void(const std::string&)> callback) override;
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
bool IsQueryIDRelevant(int query_id) override;
#endif
@@ -204,7 +207,12 @@ class TestAutofillClient : public AutofillClient {
void set_last_committed_url(const GURL& url);
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+ void SetVariationConfigCountryCode(
+ const std::string& variation_config_country_code) {
+ variation_config_country_code_ = variation_config_country_code;
+ }
+
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
void set_allowed_merchants(
const std::vector<std::string>& merchant_allowlist) {
allowed_merchants_ = merchant_allowlist;
@@ -228,10 +236,19 @@ class TestAutofillClient : public AutofillClient {
return offer_to_save_credit_card_bubble_was_shown_.value();
}
+ void set_virtual_card_error_dialog_shown(
+ bool virtual_card_error_dialog_shown) {
+ virtual_card_error_dialog_shown_ = virtual_card_error_dialog_shown;
+ }
+
bool virtual_card_error_dialog_shown() {
return virtual_card_error_dialog_shown_;
}
+ bool virtual_card_error_dialog_is_permanent_error() {
+ return virtual_card_error_dialog_is_permanent_error_;
+ }
+
SaveCreditCardOptions get_save_credit_card_options() {
return save_credit_card_options_.value();
}
@@ -273,9 +290,10 @@ class TestAutofillClient : public AutofillClient {
std::unique_ptr<PrefService> prefs_;
std::unique_ptr<TestStrikeDatabase> test_strike_database_;
std::unique_ptr<payments::PaymentsClient> payments_client_;
- std::unique_ptr<FormDataImporter> form_data_importer_;
+ std::unique_ptr<TestFormDataImporter> form_data_importer_;
GURL form_origin_;
ukm::SourceId source_id_ = -1;
+ std::string variation_config_country_code_;
security_state::SecurityLevel security_level_ =
security_state::SecurityLevel::NONE;
@@ -286,6 +304,8 @@ class TestAutofillClient : public AutofillClient {
bool virtual_card_error_dialog_shown_ = false;
+ bool virtual_card_error_dialog_is_permanent_error_ = false;
+
// Populated if save was offered. True if bubble was shown, false otherwise.
absl::optional<bool> offer_to_save_credit_card_bubble_was_shown_;
@@ -306,7 +326,7 @@ class TestAutofillClient : public AutofillClient {
// The last URL submitted by the user in the URL bar. Set in the constructor.
GURL last_committed_url_;
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
std::vector<std::string> allowed_merchants_;
std::vector<std::string> allowed_bin_ranges_;
#endif
diff --git a/chromium/components/autofill/core/browser/test_autofill_driver.cc b/chromium/components/autofill/core/browser/test_autofill_driver.cc
index aa0828b8f9d..79d9506467e 100644
--- a/chromium/components/autofill/core/browser/test_autofill_driver.cc
+++ b/chromium/components/autofill/core/browser/test_autofill_driver.cc
@@ -51,7 +51,7 @@ bool TestAutofillDriver::RendererIsAvailable() {
return true;
}
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
webauthn::InternalAuthenticator*
TestAutofillDriver::GetOrCreateCreditCardInternalAuthenticator() {
return test_authenticator_.get();
@@ -140,7 +140,7 @@ void TestAutofillDriver::SetSharedURLLoaderFactory(
test_shared_loader_factory_ = url_loader_factory;
}
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
void TestAutofillDriver::SetAuthenticator(
webauthn::InternalAuthenticator* authenticator_) {
test_authenticator_.reset(authenticator_);
diff --git a/chromium/components/autofill/core/browser/test_autofill_driver.h b/chromium/components/autofill/core/browser/test_autofill_driver.h
index 1d3f9c15dbf..8cf1c0e80a8 100644
--- a/chromium/components/autofill/core/browser/test_autofill_driver.h
+++ b/chromium/components/autofill/core/browser/test_autofill_driver.h
@@ -14,7 +14,7 @@
#include "services/network/test/test_url_loader_factory.h"
#include "url/origin.h"
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
#include "components/autofill/content/browser/content_autofill_driver.h"
#include "components/webauthn/core/browser/internal_authenticator.h"
#endif
@@ -22,7 +22,7 @@
namespace autofill {
// This class is only for easier writing of tests.
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
class TestAutofillDriver : public AutofillDriver {
#else
class TestAutofillDriver : public ContentAutofillDriver {
@@ -41,7 +41,7 @@ class TestAutofillDriver : public ContentAutofillDriver {
ui::AXTreeID GetAxTreeId() const override;
scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory() override;
bool RendererIsAvailable() override;
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
webauthn::InternalAuthenticator* GetOrCreateCreditCardInternalAuthenticator()
override;
#endif
@@ -91,7 +91,7 @@ class TestAutofillDriver : public ContentAutofillDriver {
void SetSharedURLLoaderFactory(
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory);
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
void SetAuthenticator(webauthn::InternalAuthenticator* authenticator_);
#endif
@@ -105,7 +105,7 @@ class TestAutofillDriver : public ContentAutofillDriver {
bool(const url::Origin&, FieldGlobalId, ServerFieldType)>
field_type_map_filter_;
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
std::unique_ptr<webauthn::InternalAuthenticator> test_authenticator_;
#endif
};
diff --git a/chromium/components/autofill/core/browser/test_autofill_profile_validator.cc b/chromium/components/autofill/core/browser/test_autofill_profile_validator.cc
deleted file mode 100644
index 8828311186a..00000000000
--- a/chromium/components/autofill/core/browser/test_autofill_profile_validator.cc
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright 2018 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.
-
-#include "components/autofill/core/browser/test_autofill_profile_validator.h"
-
-#include <memory>
-
-#include "base/base_paths.h"
-#include "base/bind.h"
-#include "base/files/file_path.h"
-#include "base/path_service.h"
-#include "third_party/libaddressinput/src/cpp/include/libaddressinput/null_storage.h"
-#include "third_party/libaddressinput/src/cpp/test/testdata_source.h"
-
-namespace {
-using ::i18n::addressinput::Source;
-using ::i18n::addressinput::Storage;
-using ::i18n::addressinput::NullStorage;
-using ::i18n::addressinput::TestdataSource;
-
-} // namespace
-
-namespace autofill {
-
-namespace {
-
-std::unique_ptr<::i18n::addressinput::Source> GetInputSource() {
- base::FilePath file_path;
- CHECK(base::PathService::Get(base::DIR_SOURCE_ROOT, &file_path));
- file_path = file_path.Append(FILE_PATH_LITERAL("third_party"))
- .Append(FILE_PATH_LITERAL("libaddressinput"))
- .Append(FILE_PATH_LITERAL("src"))
- .Append(FILE_PATH_LITERAL("testdata"))
- .Append(FILE_PATH_LITERAL("countryinfo.txt"));
- return std::make_unique<TestdataSource>(true, file_path.AsUTF8Unsafe());
-}
-
-std::unique_ptr<::i18n::addressinput::Storage> GetInputStorage() {
- return std::unique_ptr<Storage>(new NullStorage);
-}
-
-} // namespace
-
-// static
-AutofillProfileValidator* TestAutofillProfileValidator::GetInstance() {
- static base::LazyInstance<TestAutofillProfileValidator>::DestructorAtExit
- instance = LAZY_INSTANCE_INITIALIZER;
- return &(instance.Get().autofill_profile_validator_);
-}
-
-// static
-TestAutofillProfileValidatorDelayed*
-TestAutofillProfileValidator::GetDelayedInstance() {
- static base::LazyInstance<TestAutofillProfileValidator>::DestructorAtExit
- instance = LAZY_INSTANCE_INITIALIZER;
- return &(instance.Get().autofill_profile_validator_delayed_);
-}
-
-TestAutofillProfileValidator::TestAutofillProfileValidator()
- : autofill_profile_validator_(GetInputSource(), GetInputStorage()),
- autofill_profile_validator_delayed_(GetInputSource(), GetInputStorage()) {
-}
-
-TestAutofillProfileValidator::~TestAutofillProfileValidator() {}
-
-} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/test_autofill_profile_validator.h b/chromium/components/autofill/core/browser/test_autofill_profile_validator.h
deleted file mode 100644
index ed4672cf3e4..00000000000
--- a/chromium/components/autofill/core/browser/test_autofill_profile_validator.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2018 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.
-
-#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_AUTOFILL_PROFILE_VALIDATOR_H_
-#define COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_AUTOFILL_PROFILE_VALIDATOR_H_
-
-#include "base/lazy_instance.h"
-#include "components/autofill/core/browser/autofill_profile_validator.h"
-#include "components/autofill/core/browser/test_autofill_profile_validator_delayed.h"
-
-namespace autofill {
-
-// Singleton that owns a single AutofillProfileValidator instance.
-class TestAutofillProfileValidator {
- public:
- static AutofillProfileValidator* GetInstance();
- static TestAutofillProfileValidatorDelayed* GetDelayedInstance();
-
- TestAutofillProfileValidator(const TestAutofillProfileValidator&) = delete;
- TestAutofillProfileValidator& operator=(const TestAutofillProfileValidator&) =
- delete;
-
- private:
- friend struct base::LazyInstanceTraitsBase<TestAutofillProfileValidator>;
-
- TestAutofillProfileValidator();
- ~TestAutofillProfileValidator();
-
- // The only instance that exists of normal and delayed validators.
- AutofillProfileValidator autofill_profile_validator_;
- TestAutofillProfileValidatorDelayed autofill_profile_validator_delayed_;
-};
-
-} // namespace autofill
-
-#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_AUTOFILL_PROFILE_VALIDATOR_H_
diff --git a/chromium/components/autofill/core/browser/test_autofill_profile_validator_delayed.cc b/chromium/components/autofill/core/browser/test_autofill_profile_validator_delayed.cc
deleted file mode 100644
index 833df9c1387..00000000000
--- a/chromium/components/autofill/core/browser/test_autofill_profile_validator_delayed.cc
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2018 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.
-
-#include "components/autofill/core/browser/test_autofill_profile_validator_delayed.h"
-
-#include "base/bind.h"
-#include "base/callback_helpers.h"
-#include "base/cancelable_callback.h"
-#include "base/threading/sequenced_task_runner_handle.h"
-
-namespace autofill {
-namespace {
-
-const int kRulesDelayedLoadingTimeSeconds = 3;
-
-} // namespace
-
-TestAutofillProfileValidatorDelayed::TestAutofillProfileValidatorDelayed(
- std::unique_ptr<::i18n::addressinput::Source> source,
- std::unique_ptr<::i18n::addressinput::Storage> storage)
- : AutofillProfileValidator(std::move(source), std::move(storage)) {}
-
-TestAutofillProfileValidatorDelayed::~TestAutofillProfileValidatorDelayed() {}
-
-void TestAutofillProfileValidatorDelayed::LoadRulesInstantly(
- const std::string& region_code) {
- address_validator_.LoadRules(region_code);
-}
-
-void TestAutofillProfileValidatorDelayed::LoadRulesForRegion(
- const std::string& region_code) {
- base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
- FROM_HERE,
- base::BindOnce(&TestAutofillProfileValidatorDelayed::LoadRulesInstantly,
- base::Unretained(this), region_code),
- base::Seconds(kRulesDelayedLoadingTimeSeconds));
-}
-} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/test_autofill_profile_validator_delayed.h b/chromium/components/autofill/core/browser/test_autofill_profile_validator_delayed.h
deleted file mode 100644
index 0c395462617..00000000000
--- a/chromium/components/autofill/core/browser/test_autofill_profile_validator_delayed.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2018 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.
-
-#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_AUTOFILL_PROFILE_VALIDATOR_DELAYED_H_
-#define COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_AUTOFILL_PROFILE_VALIDATOR_DELAYED_H_
-
-#include <memory>
-#include <string>
-
-#include "components/autofill/core/browser/autofill_profile_validator.h"
-#include "third_party/libaddressinput/chromium/chrome_address_validator.h"
-#include "third_party/libaddressinput/src/cpp/include/libaddressinput/source.h"
-#include "third_party/libaddressinput/src/cpp/include/libaddressinput/storage.h"
-
-namespace autofill {
-
-// Singleton that owns a single AutofillProfileValidator instance. It's a
-// delayed validator used in tests, to make sure that the system can handle
-// possible delays in the real world.
-class TestAutofillProfileValidatorDelayed : public AutofillProfileValidator {
- public:
- // Takes ownership of |source| and |storage|.
- TestAutofillProfileValidatorDelayed(
- std::unique_ptr<::i18n::addressinput::Source> source,
- std::unique_ptr<::i18n::addressinput::Storage> storage);
-
- TestAutofillProfileValidatorDelayed(
- const TestAutofillProfileValidatorDelayed&) = delete;
- TestAutofillProfileValidatorDelayed& operator=(
- const TestAutofillProfileValidatorDelayed&) = delete;
-
- ~TestAutofillProfileValidatorDelayed() override;
-
- // Starts loading the rules for the specified |region_code|.
- void LoadRulesForRegion(const std::string& region_code) override;
-
- private:
- void LoadRulesInstantly(const std::string& region_code);
-};
-
-} // namespace autofill
-
-#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_AUTOFILL_PROFILE_VALIDATOR_DELAYED_H_
diff --git a/chromium/components/autofill/core/browser/test_form_data_importer.cc b/chromium/components/autofill/core/browser/test_form_data_importer.cc
index 9c5f119aae5..8a572a0c874 100644
--- a/chromium/components/autofill/core/browser/test_form_data_importer.cc
+++ b/chromium/components/autofill/core/browser/test_form_data_importer.cc
@@ -19,9 +19,9 @@ TestFormDataImporter::TestFormDataImporter(
personal_data_manager,
app_locale) {
set_credit_card_save_manager(std::move(credit_card_save_manager));
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
set_local_card_migration_manager(std::move(local_card_migration_manager));
-#endif // !defined(OS_ANDROID) && !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
}
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/test_form_data_importer.h b/chromium/components/autofill/core/browser/test_form_data_importer.h
index 0125a8c3fe3..775deefc9fa 100644
--- a/chromium/components/autofill/core/browser/test_form_data_importer.h
+++ b/chromium/components/autofill/core/browser/test_form_data_importer.h
@@ -22,6 +22,7 @@ class TestFormDataImporter : public FormDataImporter {
const std::string& app_locale,
std::unique_ptr<LocalCardMigrationManager> local_card_migration_manager =
nullptr);
+ ~TestFormDataImporter() override = default;
};
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/test_personal_data_manager.h b/chromium/components/autofill/core/browser/test_personal_data_manager.h
index a45b04499a5..c97952560e7 100644
--- a/chromium/components/autofill/core/browser/test_personal_data_manager.h
+++ b/chromium/components/autofill/core/browser/test_personal_data_manager.h
@@ -158,6 +158,8 @@ class TestPersonalDataManager : public PersonalDataManager {
account_info_ = account_info;
}
+ void ClearCreditCardArtImages() { credit_card_art_images_.clear(); }
+
private:
std::string timezone_country_code_;
std::string default_country_code_;
diff --git a/chromium/components/autofill/core/browser/ui/autofill_popup_delegate.h b/chromium/components/autofill/core/browser/ui/autofill_popup_delegate.h
index 46f4c6105ef..beef2b487f7 100644
--- a/chromium/components/autofill/core/browser/ui/autofill_popup_delegate.h
+++ b/chromium/components/autofill/core/browser/ui/autofill_popup_delegate.h
@@ -33,8 +33,12 @@ class AutofillPopupDelegate {
// Called when the autofill suggestion indicated by |frontend_id| has been
// temporarily selected (e.g., hovered).
+ // |value| is the suggestion's value, and is usually the main text to be
+ // shown. |frontend_id| is the frontend id of the suggestion. |backend_id| is
+ // the guid of the backend data model.
virtual void DidSelectSuggestion(const std::u16string& value,
- int frontend_id) = 0;
+ int frontend_id,
+ const std::string& backend_id) = 0;
// Inform the delegate that a row in the popup has been chosen. |value| is the
// suggestion's value, and is usually the main text to be shown. |frontend_id|
diff --git a/chromium/components/autofill/core/browser/ui/country_combobox_model.cc b/chromium/components/autofill/core/browser/ui/country_combobox_model.cc
index 2d36c2cb20d..2abb96fe50f 100644
--- a/chromium/components/autofill/core/browser/ui/country_combobox_model.cc
+++ b/chromium/components/autofill/core/browser/ui/country_combobox_model.cc
@@ -39,7 +39,7 @@ void CountryComboboxModel::SetCountries(
if (filter.is_null() || filter.Run(default_country_code)) {
countries_.push_back(
std::make_unique<AutofillCountry>(default_country_code, app_locale));
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
// The separator item. On Android, there are separators after all items, so
// this is unnecessary.
countries_.push_back(nullptr);
diff --git a/chromium/components/autofill/core/browser/ui/label_formatter.cc b/chromium/components/autofill/core/browser/ui/label_formatter.cc
index 4130bbcf283..9aa99315d2b 100644
--- a/chromium/components/autofill/core/browser/ui/label_formatter.cc
+++ b/chromium/components/autofill/core/browser/ui/label_formatter.cc
@@ -94,7 +94,7 @@ std::unique_ptr<LabelFormatter> LabelFormatter::Create(
return nullptr;
}
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
return std::make_unique<MobileLabelFormatter>(
profiles, app_locale, focused_field_type, groups, field_types);
#else
@@ -124,7 +124,7 @@ std::unique_ptr<LabelFormatter> LabelFormatter::Create(
default:
return nullptr;
}
-#endif // defined(OS_ANDROID) || defined(OS_IOS)
+#endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
}
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/ui/label_formatter_utils.h b/chromium/components/autofill/core/browser/ui/label_formatter_utils.h
index 806dd52fe03..e47c0cf50e5 100644
--- a/chromium/components/autofill/core/browser/ui/label_formatter_utils.h
+++ b/chromium/components/autofill/core/browser/ui/label_formatter_utils.h
@@ -5,7 +5,6 @@
#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_UI_LABEL_FORMATTER_UTILS_H_
#define COMPONENTS_AUTOFILL_CORE_BROWSER_UI_LABEL_FORMATTER_UTILS_H_
-#include <list>
#include <string>
#include <vector>
diff --git a/chromium/components/autofill/core/browser/ui/payments/card_name_fix_flow_controller_impl.cc b/chromium/components/autofill/core/browser/ui/payments/card_name_fix_flow_controller_impl.cc
index ff66e221672..34804037668 100644
--- a/chromium/components/autofill/core/browser/ui/payments/card_name_fix_flow_controller_impl.cc
+++ b/chromium/components/autofill/core/browser/ui/payments/card_name_fix_flow_controller_impl.cc
@@ -111,7 +111,7 @@ std::u16string CardNameFixFlowControllerImpl::GetInputPlaceholderText() const {
}
std::u16string CardNameFixFlowControllerImpl::GetSaveButtonLabel() const {
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
return l10n_util::GetStringUTF16(IDS_SAVE);
#else
return l10n_util::GetStringUTF16(
diff --git a/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller.h b/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller.h
index 213d00acf53..6aed761a891 100644
--- a/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller.h
+++ b/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller.h
@@ -33,7 +33,7 @@ class CardUnmaskPromptController {
virtual int GetCvcImageRid() const = 0;
virtual bool ShouldRequestExpirationDate() const = 0;
virtual bool GetStoreLocallyStartState() const = 0;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
virtual int GetGooglePayImageRid() const = 0;
virtual bool ShouldOfferWebauthn() const = 0;
virtual bool GetWebauthnOfferStartState() const = 0;
diff --git a/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.cc b/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.cc
index fe155b23b99..9025837a338 100644
--- a/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.cc
+++ b/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.cc
@@ -147,7 +147,7 @@ void CardUnmaskPromptControllerImpl::OnUnmaskPromptAccepted(
// On Android, FIDO authentication is fully launched and its checkbox should
// always be shown. Remember the last choice the user made on this device.
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
pending_details_.enable_fido_auth = enable_fido_auth;
pref_service_->SetBoolean(
prefs::kAutofillCreditCardFidoAuthOfferCheckboxState, enable_fido_auth);
@@ -164,7 +164,7 @@ void CardUnmaskPromptControllerImpl::NewCardLinkClicked() {
}
std::u16string CardUnmaskPromptControllerImpl::GetWindowTitle() const {
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
// The iOS UI has less room for the title so it shows a shorter string.
return l10n_util::GetStringUTF16(IDS_AUTOFILL_CARD_UNMASK_PROMPT_TITLE);
#else
@@ -190,7 +190,7 @@ std::u16string CardUnmaskPromptControllerImpl::GetWindowTitle() const {
std::u16string CardUnmaskPromptControllerImpl::GetInstructionsMessage() const {
// The prompt for server cards should reference Google Payments, whereas the
// prompt for local cards should not.
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
int ids;
if (reason_ == AutofillClient::UnmaskCardReason::kAutofill &&
ShouldRequestExpirationDate()) {
@@ -239,7 +239,7 @@ bool CardUnmaskPromptControllerImpl::GetStoreLocallyStartState() const {
prefs::kAutofillWalletImportStorageCheckboxState);
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
int CardUnmaskPromptControllerImpl::GetGooglePayImageRid() const {
return IDR_AUTOFILL_GOOGLE_PAY_WITH_DIVIDER;
}
@@ -324,7 +324,7 @@ bool CardUnmaskPromptControllerImpl::AllowsRetry(
bool CardUnmaskPromptControllerImpl::ShouldDismissUnmaskPromptUponResult(
AutofillClient::PaymentsRpcResult result) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// For virtual card errors on Android, we'd dismiss the unmask prompt and
// instead show a different error dialog.
return result ==
@@ -333,7 +333,7 @@ bool CardUnmaskPromptControllerImpl::ShouldDismissUnmaskPromptUponResult(
AutofillClient::PaymentsRpcResult::kVcnRetrievalTryAgainFailure;
#else
return false;
-#endif // OS_ANDROID
+#endif // BUILDFLAG(IS_ANDROID)
}
void CardUnmaskPromptControllerImpl::LogOnCloseEvents() {
diff --git a/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.h b/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.h
index 7381884b537..aa4e3333672 100644
--- a/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.h
+++ b/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.h
@@ -59,7 +59,7 @@ class CardUnmaskPromptControllerImpl : public CardUnmaskPromptController {
int GetCvcImageRid() const override;
bool ShouldRequestExpirationDate() const override;
bool GetStoreLocallyStartState() const override;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
int GetGooglePayImageRid() const override;
bool ShouldOfferWebauthn() const override;
bool GetWebauthnOfferStartState() const override;
diff --git a/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl_unittest.cc b/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl_unittest.cc
index 97dd4d9e875..0cd137c9748 100644
--- a/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl_unittest.cc
+++ b/chromium/components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl_unittest.cc
@@ -86,7 +86,7 @@ class TestCardUnmaskPromptController : public CardUnmaskPromptControllerImpl {
TestCardUnmaskPromptController& operator=(
const TestCardUnmaskPromptController&) = delete;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
bool ShouldOfferWebauthn() const override { return should_offer_webauthn_; }
#endif
void set_should_offer_webauthn(bool should) {
@@ -177,14 +177,14 @@ class CardUnmaskPromptControllerImplTest
CardUnmaskPromptControllerImplGenericTest::SetUp();
pref_service_->registry()->RegisterBooleanPref(
prefs::kAutofillWalletImportStorageCheckboxState, false);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
pref_service_->registry()->RegisterBooleanPref(
prefs::kAutofillCreditCardFidoAuthOfferCheckboxState, true);
#endif
}
};
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
TEST_F(CardUnmaskPromptControllerImplTest,
FidoAuthOfferCheckboxStatePersistent) {
scoped_feature_list_.InitAndEnableFeature(
@@ -278,7 +278,7 @@ TEST_F(CardUnmaskPromptControllerImplTest,
// iOS and in the title on other platforms.
TEST_F(CardUnmaskPromptControllerImplTest, DisplayCardInformation) {
ShowPrompt();
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
EXPECT_TRUE(base::UTF16ToUTF8(controller_->GetInstructionsMessage())
.find("Mastercard " + test::ObfuscatedCardDigitsAsUTF8(
"2109")) != std::string::npos);
@@ -294,7 +294,7 @@ TEST_F(CardUnmaskPromptControllerImplTest, DisplayCardInformation) {
TEST_F(CardUnmaskPromptControllerImplTest, Nickname_NicknameInvalid) {
SetCreditCardForTesting(test::GetMaskedServerCardWithInvalidNickname());
ShowPrompt();
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
EXPECT_TRUE(
base::UTF16ToUTF8(controller_->GetInstructionsMessage()).find("Visa") !=
std::string::npos);
@@ -316,7 +316,7 @@ TEST_F(CardUnmaskPromptControllerImplTest, Nickname_NicknameInvalid) {
TEST_F(CardUnmaskPromptControllerImplTest, Nickname_NicknameValid) {
SetCreditCardForTesting(test::GetMaskedServerCardWithNickname());
ShowPrompt();
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
EXPECT_FALSE(
base::UTF16ToUTF8(controller_->GetInstructionsMessage()).find("Visa") !=
std::string::npos);
@@ -348,7 +348,7 @@ class LoggingValidationTestForNickname
CardUnmaskPromptControllerImplGenericTest::SetUp();
pref_service_->registry()->RegisterBooleanPref(
prefs::kAutofillWalletImportStorageCheckboxState, false);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
pref_service_->registry()->RegisterBooleanPref(
prefs::kAutofillCreditCardFidoAuthOfferCheckboxState, true);
#endif
@@ -680,7 +680,7 @@ class CvcInputValidationTest : public CardUnmaskPromptControllerImplGenericTest,
CardUnmaskPromptControllerImplGenericTest::SetUp();
pref_service_->registry()->RegisterBooleanPref(
prefs::kAutofillWalletImportStorageCheckboxState, false);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
pref_service_->registry()->RegisterBooleanPref(
prefs::kAutofillCreditCardFidoAuthOfferCheckboxState, true);
#endif
@@ -725,7 +725,7 @@ class CvcInputAmexValidationTest
CardUnmaskPromptControllerImplGenericTest::SetUp();
pref_service_->registry()->RegisterBooleanPref(
prefs::kAutofillWalletImportStorageCheckboxState, false);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
pref_service_->registry()->RegisterBooleanPref(
prefs::kAutofillCreditCardFidoAuthOfferCheckboxState, true);
#endif
@@ -779,7 +779,7 @@ class ExpirationDateValidationTest
CardUnmaskPromptControllerImplGenericTest::SetUp();
pref_service_->registry()->RegisterBooleanPref(
prefs::kAutofillWalletImportStorageCheckboxState, false);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
pref_service_->registry()->RegisterBooleanPref(
prefs::kAutofillCreditCardFidoAuthOfferCheckboxState, true);
#endif
@@ -812,14 +812,14 @@ class VirtualCardErrorTest
CardUnmaskPromptControllerImplGenericTest::SetUp();
pref_service_->registry()->RegisterBooleanPref(
prefs::kAutofillWalletImportStorageCheckboxState, false);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
pref_service_->registry()->RegisterBooleanPref(
prefs::kAutofillCreditCardFidoAuthOfferCheckboxState, true);
#endif
}
};
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
TEST_P(VirtualCardErrorTest, VirtualCardFailureDismissesUnmaskPrompt) {
ShowPromptAndSimulateResponse(/*enable_fido_auth=*/false,
/*should_unmask_virtual_card=*/true);
@@ -847,6 +847,6 @@ INSTANTIATE_TEST_SUITE_P(
testing::Values(
AutofillClient::PaymentsRpcResult::kVcnRetrievalPermanentFailure,
AutofillClient::PaymentsRpcResult::kVcnRetrievalTryAgainFailure));
-#endif // OS_ANDROID
+#endif // BUILDFLAG(IS_ANDROID)
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/ui/payments/virtual_card_enroll_bubble_controller.h b/chromium/components/autofill/core/browser/ui/payments/virtual_card_enroll_bubble_controller.h
new file mode 100644
index 00000000000..4d5697619fb
--- /dev/null
+++ b/chromium/components/autofill/core/browser/ui/payments/virtual_card_enroll_bubble_controller.h
@@ -0,0 +1,75 @@
+// Copyright 2022 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.
+
+#include "components/autofill/core/browser/metrics/payments/virtual_card_enrollment_metrics.h"
+#include "components/autofill/core/browser/payments/legal_message_line.h"
+#include "components/autofill/core/browser/payments/virtual_card_enrollment_manager.h"
+#include "components/autofill/core/browser/ui/payments/payments_bubble_closed_reasons.h"
+#include "url/gurl.h"
+
+#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_UI_PAYMENTS_VIRTUAL_CARD_ENROLL_BUBBLE_CONTROLLER_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_UI_PAYMENTS_VIRTUAL_CARD_ENROLL_BUBBLE_CONTROLLER_H_
+
+namespace autofill {
+
+class AutofillBubbleBase;
+enum class VirtualCardEnrollmentState;
+
+// Interface that exposes controller functionality to virtual card enrollment
+// bubbles.
+class VirtualCardEnrollBubbleController {
+ public:
+ VirtualCardEnrollBubbleController() = default;
+ VirtualCardEnrollBubbleController(const VirtualCardEnrollBubbleController&) =
+ delete;
+ VirtualCardEnrollBubbleController& operator=(
+ const VirtualCardEnrollBubbleController&) = delete;
+ virtual ~VirtualCardEnrollBubbleController() = default;
+
+ // Returns a reference to the VirtualCardEnrollBubbleController associated
+ // with the given |web_contents|. If controller does not exist, this will
+ // create the controller from the |web_contents| then return the reference.
+ static VirtualCardEnrollBubbleController* GetOrCreate(
+ content::WebContents* web_contents);
+
+ // Returns the title displayed in the bubble.
+ virtual std::u16string GetWindowTitle() const = 0;
+
+ // Returns the main text displayed in the bubble.
+ virtual std::u16string GetExplanatoryMessage() const = 0;
+
+ // Returns the button label text for virtual card enroll bubbles.
+ virtual std::u16string GetAcceptButtonText() const = 0;
+ virtual std::u16string GetDeclineButtonText() const = 0;
+
+ // Returns the text used in the learn more link.
+ virtual std::u16string GetLearnMoreLinkText() const = 0;
+
+ // Returns the enrollment fields for the virtual card.
+ virtual const VirtualCardEnrollmentFields GetVirtualCardEnrollmentFields()
+ const = 0;
+
+ // Returns the currently active virtual card enroll bubble view. Can be
+ // nullptr if no bubble is visible.
+ virtual AutofillBubbleBase* GetVirtualCardEnrollBubbleView() const = 0;
+
+#if !BUILDFLAG(IS_ANDROID)
+ // Hides the bubble and icon if it is showing.
+ virtual void HideIconAndBubble() = 0;
+#endif
+
+ // Virtual card enroll button takes card information to enroll into a VCN.
+ virtual void OnAcceptButton() = 0;
+ virtual void OnDeclineButton() = 0;
+ virtual void OnLinkClicked(VirtualCardEnrollmentLinkType link_type,
+ const GURL& url) = 0;
+ virtual void OnBubbleClosed(PaymentsBubbleClosedReason closed_reason) = 0;
+
+ // Returns whether the omnibox icon should be visible.
+ virtual bool IsIconVisible() const = 0;
+};
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_UI_PAYMENTS_VIRTUAL_CARD_ENROLL_BUBBLE_CONTROLLER_H_
diff --git a/chromium/components/autofill/core/browser/ui/suggestion.h b/chromium/components/autofill/core/browser/ui/suggestion.h
index 96a63387858..6cf75f5ad9b 100644
--- a/chromium/components/autofill/core/browser/ui/suggestion.h
+++ b/chromium/components/autofill/core/browser/ui/suggestion.h
@@ -10,6 +10,7 @@
#include "base/strings/string_piece.h"
#include "base/types/strong_alias.h"
#include "build/build_config.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
#include "ui/gfx/image/image.h"
#include "url/gurl.h"
namespace autofill {
@@ -64,11 +65,11 @@ struct Suggestion {
// Contains an image to display for the suggestion.
gfx::Image custom_icon;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// The url for the custom icon. This is used by android to fetch the image as
// android does not support gfx::Image directly.
GURL custom_icon_url;
-#endif // OS_ANDROID
+#endif // BUILDFLAG(IS_ANDROID)
// TODO(crbug.com/1019660): Identify icons with enum instead of strings.
// If |custom_icon| is empty, the name of the fallback built-in icon.
@@ -85,6 +86,9 @@ struct Suggestion {
IsLoading is_loading = IsLoading(false);
// The In-Product-Help feature that should be shown for the suggestion.
std::string feature_for_iph;
+
+ // If specified, this text will be played back as voice over for a11y.
+ absl::optional<std::u16string> voice_over;
};
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/ui/suggestion_selection.cc b/chromium/components/autofill/core/browser/ui/suggestion_selection.cc
index e2414a2ac63..77930d5ab03 100644
--- a/chromium/components/autofill/core/browser/ui/suggestion_selection.cc
+++ b/chromium/components/autofill/core/browser/ui/suggestion_selection.cc
@@ -76,21 +76,18 @@ std::vector<Suggestion> GetPrefixMatchedSuggestions(
i++) {
AutofillProfile* profile = profiles[i];
- if (profile->ShouldSkipFillingOrSuggesting(type.GetStorableType()))
- continue;
-
// Don't offer to fill the exact same value again. If detailed suggestions
// with different secondary data is available, it would appear to offer
// refilling the whole form with something else. E.g. the same name with a
// work and a home address would appear twice but a click would be a noop.
// TODO(fhorschig): Consider refilling form instead (at on least Android).
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
if (base::FeatureList::IsEnabled(features::kAutofillKeyboardAccessory) &&
field_is_autofilled &&
profile->GetRawInfo(type.GetStorableType()) == raw_field_contents) {
continue;
}
-#endif // defined(OS_ANDROID) || defined(OS_IOS)
+#endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
std::u16string value =
GetInfoInOneLine(profile, type, comparator.app_locale());
@@ -107,13 +104,13 @@ std::vector<Suggestion> GetPrefixMatchedSuggestions(
if (type.group() == FieldTypeGroup::kPhoneHome) {
bool format_phone;
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
format_phone = base::FeatureList::IsEnabled(
autofill::features::kAutofillUseMobileLabelDisambiguation);
#else
format_phone = base::FeatureList::IsEnabled(
autofill::features::kAutofillUseImprovedLabelDisambiguation);
-#endif // defined(OS_ANDROID) || defined(OS_IOS)
+#endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
if (format_phone) {
// Formats, e.g., the US phone numbers 15084880800, 508 488 0800, and
diff --git a/chromium/components/autofill/core/browser/ui/suggestion_selection_unittest.cc b/chromium/components/autofill/core/browser/ui/suggestion_selection_unittest.cc
index bd10211b138..295586edc55 100644
--- a/chromium/components/autofill/core/browser/ui/suggestion_selection_unittest.cc
+++ b/chromium/components/autofill/core/browser/ui/suggestion_selection_unittest.cc
@@ -183,49 +183,6 @@ TEST_F(SuggestionSelectionTest, GetPrefixMatchedSuggestions_LimitProfiles) {
Not(u"Marie"))));
}
-TEST_F(SuggestionSelectionTest, GetPrefixMatchedSuggestions_SkipInvalid) {
- base::test::ScopedFeatureList scoped_features;
- scoped_features.InitWithFeatures(
- /*enabled_features=*/{features::kAutofillProfileServerValidation,
- features::kAutofillProfileClientValidation},
- /*disabled_features=*/{});
- const std::unique_ptr<AutofillProfile> profile_server_invalid =
- CreateProfileUniquePtr("Marion");
- const std::unique_ptr<AutofillProfile> profile_client_invalid =
- CreateProfileUniquePtr("Bob");
- const std::unique_ptr<AutofillProfile> profile_valid =
- CreateProfileUniquePtr("Rose");
- const std::unique_ptr<AutofillProfile> profile_client_invalid_country_empty =
- CreateProfileUniquePtr("Lost");
-
- profile_server_invalid->SetValidityState(
- ADDRESS_HOME_STATE, AutofillProfile::INVALID, AutofillProfile::SERVER);
- profile_client_invalid->SetValidityState(
- ADDRESS_HOME_STATE, AutofillProfile::INVALID, AutofillProfile::CLIENT);
- profile_client_invalid_country_empty->SetValidityState(
- ADDRESS_HOME_STATE, AutofillProfile::INVALID, AutofillProfile::CLIENT);
- profile_client_invalid_country_empty->SetRawInfo(ADDRESS_HOME_COUNTRY, u"");
-
- const std::vector<AutofillProfile*> profiles_data = {
- profile_server_invalid.get(), profile_client_invalid.get(),
- profile_valid.get(), profile_client_invalid_country_empty.get()};
-
- std::vector<AutofillProfile*> matched_profiles;
- auto suggestions = GetPrefixMatchedSuggestions(
- AutofillType(ADDRESS_HOME_STATE), u"C", GetCanonicalUtf16Content("C"),
- comparator_, false, profiles_data, &matched_profiles);
-
- ASSERT_EQ(2U, suggestions.size());
- ASSERT_EQ(2U, matched_profiles.size());
- EXPECT_THAT(suggestions, ElementsAre(Field(&Suggestion::value, u"CA"),
- Field(&Suggestion::value, u"CA")));
-
- std::vector<AutofillProfile*> expected_result;
- expected_result.push_back(profile_valid.get());
- expected_result.push_back(profile_client_invalid_country_empty.get());
- ExpectSameElements(matched_profiles, expected_result);
-}
-
TEST_F(SuggestionSelectionTest, GetUniqueSuggestions_SingleDedupe) {
// Give two suggestions with the same name, and no other field to compare.
// Expect only one unique suggestion.
diff --git a/chromium/components/autofill/core/browser/validation.cc b/chromium/components/autofill/core/browser/validation.cc
index 3d2a0a26c94..eef75315494 100644
--- a/chromium/components/autofill/core/browser/validation.cc
+++ b/chromium/components/autofill/core/browser/validation.cc
@@ -9,6 +9,7 @@
#include <ostream>
#include "base/check.h"
+#include "base/containers/adapters.h"
#include "base/notreached.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
@@ -102,12 +103,11 @@ bool PassesLuhnCheck(const std::u16string& number) {
// [3] http://en.wikipedia.org/wiki/Luhn_algorithm
int sum = 0;
bool odd = false;
- for (std::u16string::const_reverse_iterator iter = number.rbegin();
- iter != number.rend(); ++iter) {
- if (!base::IsAsciiDigit(*iter))
+ for (char c : base::Reversed(number)) {
+ if (!base::IsAsciiDigit(c))
return false;
- int digit = *iter - '0';
+ int digit = c - '0';
if (odd) {
digit *= 2;
sum += digit / 10 + digit % 10;
diff --git a/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc b/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc
index 9a150ab4576..aa15d0cdc92 100644
--- a/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc
+++ b/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc
@@ -19,11 +19,11 @@
#include "components/autofill/core/browser/webdata/autofill_table.h"
#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
#include "components/autofill/core/common/autofill_features.h"
-#include "components/sync/engine/entity_data.h"
#include "components/sync/model/client_tag_based_model_type_processor.h"
#include "components/sync/model/model_type_change_processor.h"
#include "components/sync/model/mutable_data_batch.h"
#include "components/sync/model/sync_metadata_store_change_list.h"
+#include "components/sync/protocol/entity_data.h"
#include "net/base/escape.h"
using absl::optional;
@@ -111,15 +111,16 @@ bool ParseStorageKey(const std::string& storage_key, AutofillKey* out_key) {
AutofillEntry CreateAutofillEntry(const AutofillSpecifics& autofill_specifics) {
AutofillKey key(base::UTF8ToUTF16(autofill_specifics.name()),
base::UTF8ToUTF16(autofill_specifics.value()));
- Time date_created, date_last_used;
const google::protobuf::RepeatedField<int64_t>& timestamps =
autofill_specifics.usage_timestamp();
- if (!timestamps.empty()) {
- auto iter_pair = std::minmax_element(timestamps.begin(), timestamps.end());
- date_created = Time::FromInternalValue(*iter_pair.first);
- date_last_used = Time::FromInternalValue(*iter_pair.second);
+ if (timestamps.empty()) {
+ return AutofillEntry(key, base::Time(), base::Time());
}
- return AutofillEntry(key, date_created, date_last_used);
+
+ auto [date_created_iter, date_last_used_iter] =
+ std::minmax_element(timestamps.begin(), timestamps.end());
+ return AutofillEntry(key, Time::FromInternalValue(*date_created_iter),
+ Time::FromInternalValue(*date_last_used_iter));
}
// This is used to respond to ApplySyncChanges() and MergeSyncData(). Attempts
diff --git a/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge_unittest.cc b/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge_unittest.cc
index b9d7a60ecdf..3ef89d2582e 100644
--- a/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge_unittest.cc
+++ b/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge_unittest.cc
@@ -113,10 +113,10 @@ MATCHER_P(HasSpecifics, expected, "") {
void VerifyDataBatch(std::map<std::string, AutofillSpecifics> expected,
std::unique_ptr<DataBatch> batch) {
while (batch->HasNext()) {
- const KeyAndData& data_pair = batch->Next();
- auto expected_iter = expected.find(data_pair.first);
+ auto [key, data] = batch->Next();
+ auto expected_iter = expected.find(key);
ASSERT_NE(expected_iter, expected.end());
- EXPECT_THAT(data_pair.second, HasSpecifics(expected_iter->second));
+ EXPECT_THAT(data, HasSpecifics(expected_iter->second));
// Removing allows us to verify we don't see the same item multiple times,
// and that we saw everything we expected.
expected.erase(expected_iter);
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_change.h b/chromium/components/autofill/core/browser/webdata/autofill_change.h
index 2507c870457..9da26e5da7c 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_change.h
+++ b/chromium/components/autofill/core/browser/webdata/autofill_change.h
@@ -95,9 +95,6 @@ class AutofillProfileDeepChange : public AutofillProfileChange {
is_ongoing_on_background_ = true;
}
- void validation_effort_made() const { validation_effort_made_ = true; }
- bool has_validation_effort_made() const { return validation_effort_made_; }
-
void set_enforced() { enforced_ = true; }
bool enforced() const { return enforced_; }
@@ -106,12 +103,6 @@ class AutofillProfileDeepChange : public AutofillProfileChange {
// Is true when the change is taking place on the database side on the
// background.
mutable bool is_ongoing_on_background_ = false;
- // Is true when the |profile_| has gone through the validation process.
- // Note: This could be different from the
- // profile_.is_client_validity_states_updated. |validation_effort_made_| shows
- // that the effort has been made, but not necessarily successful, and profile
- // validity may or may not be updated.
- mutable bool validation_effort_made_ = false;
// Is true when the change should happen regardless of an existing or equal
// profile.
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge.cc b/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge.cc
index 975b7a3b238..b8cc06b0dad 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge.cc
@@ -21,13 +21,13 @@
#include "components/autofill/core/browser/webdata/autofill_profile_sync_difference_tracker.h"
#include "components/autofill/core/browser/webdata/autofill_table.h"
#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
-#include "components/sync/engine/entity_data.h"
#include "components/sync/model/client_tag_based_model_type_processor.h"
#include "components/sync/model/metadata_change_list.h"
#include "components/sync/model/model_error.h"
#include "components/sync/model/model_type_change_processor.h"
#include "components/sync/model/mutable_data_batch.h"
#include "components/sync/model/sync_metadata_store_change_list.h"
+#include "components/sync/protocol/entity_data.h"
using absl::optional;
using base::UTF16ToUTF8;
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge_unittest.cc b/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge_unittest.cc
index 74c21c87890..381e42bc51f 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge_unittest.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_bridge_unittest.cc
@@ -33,13 +33,13 @@
#include "components/autofill/core/common/autofill_features.h"
#include "components/sync/base/client_tag_hash.h"
#include "components/sync/engine/data_type_activation_response.h"
-#include "components/sync/engine/entity_data.h"
#include "components/sync/model/client_tag_based_model_type_processor.h"
#include "components/sync/model/data_batch.h"
#include "components/sync/model/data_type_activation_request.h"
#include "components/sync/model/sync_data.h"
#include "components/sync/model/sync_error_factory.h"
#include "components/sync/protocol/autofill_specifics.pb.h"
+#include "components/sync/protocol/entity_data.h"
#include "components/sync/protocol/entity_specifics.pb.h"
#include "components/sync/protocol/model_type_state.pb.h"
#include "components/sync/test/model/mock_model_type_change_processor.h"
@@ -181,7 +181,6 @@ AutofillProfile ConstructCompleteProfile() {
profile.SetRawInfo(ADDRESS_HOME_SUBPREMISE, u"Subpremise");
profile.SetRawInfo(ADDRESS_HOME_PREMISE_NAME, u"Premise");
profile.set_language_code("en");
- profile.SetClientValidityFromBitfieldValue(kValidityStateBitfield);
profile.FinalizeAfterImport();
return profile;
}
@@ -456,7 +455,6 @@ TEST_P(AutofillProfileSyncBridgeTest,
StartSyncing({});
AutofillProfile local(kGuidA, kHttpsOrigin);
- local.SetClientValidityFromBitfieldValue(kValidityStateBitfield);
AutofillProfileChange change(AutofillProfileChange::ADD, kGuidA, &local);
EXPECT_CALL(
@@ -1266,8 +1264,6 @@ TEST_P(AutofillProfileSyncBridgeTest,
TEST_P(AutofillProfileSyncBridgeTest,
RemoteWithSameGuid_ValidityState_DefaultValueNoSync) {
AutofillProfile local(kGuidA, kHttpsOrigin);
- ASSERT_EQ(0, local.GetClientValidityBitfieldValue());
- ASSERT_FALSE(local.is_client_validity_states_updated());
AddAutofillProfilesToTable({local});
// Remote data does not have a validity state bitfield value.
@@ -1287,7 +1283,6 @@ TEST_P(AutofillProfileSyncBridgeTest,
TEST_P(AutofillProfileSyncBridgeTest,
RemoteWithSameGuid_ValidityState_ExistingRemoteWinsOverMissingLocal) {
AutofillProfile local(kGuidA, kHttpsOrigin);
- ASSERT_EQ(0, local.GetClientValidityBitfieldValue());
AddAutofillProfilesToTable({local});
// Remote data has a non default validity state bitfield value.
@@ -1307,7 +1302,6 @@ TEST_P(AutofillProfileSyncBridgeTest,
TEST_P(AutofillProfileSyncBridgeTest,
RemoteWithSameGuid_ValidityState_ExistingRemoteWinsOverExistingLocal) {
AutofillProfile local(kGuidA, kHttpsOrigin);
- local.SetClientValidityFromBitfieldValue(kValidityStateBitfield + 1);
AddAutofillProfilesToTable({local});
// Remote data has a non default validity state bitfield value.
@@ -1328,7 +1322,6 @@ TEST_P(AutofillProfileSyncBridgeTest,
TEST_P(AutofillProfileSyncBridgeTest,
RemoteWithSameGuid_ValidityState_ExistingLocalWinsOverMissingRemote) {
AutofillProfile local(kGuidA, kHttpsOrigin);
- local.SetClientValidityFromBitfieldValue(kValidityStateBitfield);
AddAutofillProfilesToTable({local});
// Remote data has a non default validity state bitfield value.
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_difference_tracker.cc b/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_difference_tracker.cc
index 1582ac242cc..55d3c24a084 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_difference_tracker.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_profile_sync_difference_tracker.cc
@@ -82,19 +82,16 @@ AutofillProfileSyncDifferenceTracker::IncorporateRemoteProfile(
// only search in local only entries but also in |update_to_local_| and
// |add_to_local_|. Likely needs a bit of refactoring to make the resulting
// code easy to understand.
- for (const auto& pair : *GetLocalOnlyEntries()) {
- const std::string& local_storage_key = pair.first;
- const AutofillProfile& local = *pair.second;
-
+ for (const auto& [local_storage_key, local] : *GetLocalOnlyEntries()) {
// Look for exact duplicates, compare only profile contents (and
// ignore origin and language code in comparison).
- if (local.Compare(*remote) == 0) {
+ if (local->Compare(*remote) == 0) {
// A duplicate found: keep the version with the bigger storage key.
DVLOG(2)
<< "[AUTOFILL SYNC] The profile "
- << base::UTF16ToUTF8(local.GetRawInfo(NAME_FIRST))
- << base::UTF16ToUTF8(local.GetRawInfo(NAME_LAST))
- << " already exists with a different storage key; keep the bigger "
+ << base::UTF16ToUTF8(local->GetRawInfo(NAME_FIRST))
+ << base::UTF16ToUTF8(local->GetRawInfo(NAME_LAST))
+ << " already exists with a different storage key*; keep the bigger "
<< (remote_storage_key > local_storage_key ? "remote" : "local")
<< " key " << std::max(remote_storage_key, local_storage_key)
<< " and delete the smaller key "
@@ -103,9 +100,9 @@ AutofillProfileSyncDifferenceTracker::IncorporateRemoteProfile(
// We keep the remote entity and delete the local one.
// Ensure that a verified profile can never revert back to an unverified
// one. In such a case, take over the old origin for the new entry.
- if (local.IsVerified() && !remote->IsVerified()) {
- remote->set_origin(local.origin());
- // Save a copy of the remote profile also to sync.
+ if (local->IsVerified() && !remote->IsVerified()) {
+ remote->set_origin(local->origin());
+ // Save a copy of the remote profile also* to sync.
save_to_sync_.push_back(std::make_unique<AutofillProfile>(*remote));
}
add_to_local_.push_back(std::move(remote));
@@ -141,8 +138,8 @@ AutofillProfileSyncDifferenceTracker::IncorporateRemoteProfile(
// there's no need to upload it: either is was already uploaded before
// (if this is incremental sync) or we'll upload it with all the
// remaining data in GetLocalOnlyEntries (if this is an initial sync).
- if (remote->IsVerified() && !local.IsVerified()) {
- auto modified_local = std::make_unique<AutofillProfile>(local);
+ if (remote->IsVerified() && !local->IsVerified()) {
+ auto modified_local = std::make_unique<AutofillProfile>(*local);
modified_local->set_origin(remote->origin());
update_to_local_.push_back(
std::make_unique<AutofillProfile>(*modified_local));
@@ -278,11 +275,10 @@ optional<ModelError> AutofillProfileInitialSyncDifferenceTracker::FlushToSync(
if (!GetLocalOnlyEntries()) {
return ModelError(FROM_HERE, "Failed reading from WebDatabase.");
}
- for (auto& pair : *GetLocalOnlyEntries()) {
- std::string storage_key = pair.first;
+ for (auto& [storage_key, data] : *GetLocalOnlyEntries()) {
// No deletions coming from remote are allowed for initial sync.
DCHECK(delete_from_local_.count(storage_key) == 0);
- profiles_to_upload_to_sync->push_back(std::move(pair.second));
+ profiles_to_upload_to_sync->push_back(std::move(data));
}
return absl::nullopt;
}
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util.cc b/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util.cc
index 988170abd9c..cecd4e6645e 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util.cc
@@ -17,7 +17,7 @@
#include "components/autofill/core/browser/payments/payments_customer_data.h"
#include "components/autofill/core/browser/webdata/autofill_table.h"
#include "components/autofill/core/common/autofill_util.h"
-#include "components/sync/engine/entity_data.h"
+#include "components/sync/protocol/entity_data.h"
using autofill::data_util::TruncateUTF8;
using sync_pb::AutofillWalletSpecifics;
@@ -103,8 +103,13 @@ CreditCard CardFromSpecifics(const sync_pb::WalletMaskedCreditCard& card) {
case sync_pb::WalletMaskedCreditCard::ENROLLED:
state = CreditCard::ENROLLED;
break;
+ case sync_pb::WalletMaskedCreditCard::UNENROLLED_AND_NOT_ELIGIBLE:
+ state = CreditCard::UNENROLLED_AND_NOT_ELIGIBLE;
+ break;
+ case sync_pb::WalletMaskedCreditCard::UNENROLLED_AND_ELIGIBLE:
+ state = CreditCard::UNENROLLED_AND_ELIGIBLE;
+ break;
case sync_pb::WalletMaskedCreditCard::UNSPECIFIED:
- state = CreditCard::UNSPECIFIED;
break;
}
result.set_virtual_card_enrollment_state(state);
@@ -275,6 +280,12 @@ void SetAutofillWalletSpecificsFromServerCard(
case CreditCard::ENROLLED:
state = sync_pb::WalletMaskedCreditCard::ENROLLED;
break;
+ case CreditCard::UNENROLLED_AND_NOT_ELIGIBLE:
+ state = sync_pb::WalletMaskedCreditCard::UNENROLLED_AND_NOT_ELIGIBLE;
+ break;
+ case CreditCard::UNENROLLED_AND_ELIGIBLE:
+ state = sync_pb::WalletMaskedCreditCard::UNENROLLED_AND_ELIGIBLE;
+ break;
case CreditCard::UNSPECIFIED:
state = sync_pb::WalletMaskedCreditCard::UNSPECIFIED;
break;
@@ -335,7 +346,7 @@ void SetAutofillOfferSpecificsFromOfferData(
(offer_data.expiry - base::Time::UnixEpoch()).InSeconds());
offer_specifics->mutable_display_strings()->set_value_prop_text(
offer_data.display_strings.value_prop_text);
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
offer_specifics->mutable_display_strings()->set_see_details_text_mobile(
offer_data.display_strings.see_details_text);
offer_specifics->mutable_display_strings()
@@ -347,7 +358,7 @@ void SetAutofillOfferSpecificsFromOfferData(
offer_specifics->mutable_display_strings()
->set_usage_instructions_text_desktop(
offer_data.display_strings.usage_instructions_text);
-#endif // defined(OS_ANDROID) || defined(OS_IOS)
+#endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
// Because card_linked_offer_data and promo_code_offer_data are a oneof,
// setting one will clear the other. We should figure out which one we care
@@ -390,7 +401,7 @@ AutofillOfferData AutofillOfferDataFromOfferSpecifics(
}
offer_data.display_strings.value_prop_text =
offer_specifics.display_strings().value_prop_text();
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
offer_data.display_strings.see_details_text =
offer_specifics.display_strings().see_details_text_mobile();
offer_data.display_strings.usage_instructions_text =
@@ -400,7 +411,7 @@ AutofillOfferData AutofillOfferDataFromOfferSpecifics(
offer_specifics.display_strings().see_details_text_desktop();
offer_data.display_strings.usage_instructions_text =
offer_specifics.display_strings().usage_instructions_text_desktop();
-#endif // defined(OS_ANDROID) || defined(OS_IOS)
+#endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
// Card-linked offer fields:
offer_data.offer_reward_amount =
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util_unittest.cc b/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util_unittest.cc
index f9b43f559be..2b2d23f7847 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util_unittest.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_sync_bridge_util_unittest.cc
@@ -19,9 +19,9 @@
#include "components/autofill/core/browser/webdata/autofill_table.h"
#include "components/autofill/core/common/autofill_constants.h"
#include "components/sync/base/client_tag_hash.h"
-#include "components/sync/engine/entity_data.h"
#include "components/sync/protocol/autofill_offer_specifics.pb.h"
#include "components/sync/protocol/autofill_specifics.pb.h"
+#include "components/sync/protocol/entity_data.h"
#include "components/sync/protocol/entity_specifics.pb.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -283,7 +283,7 @@ TEST_F(AutofillSyncBridgeUtilTest, OfferSpecificsFromOfferData) {
}
EXPECT_EQ(offer_specifics.display_strings().value_prop_text(),
offer_data.display_strings.value_prop_text);
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
EXPECT_EQ(offer_specifics.display_strings().see_details_text_mobile(),
offer_data.display_strings.see_details_text);
EXPECT_EQ(offer_specifics.display_strings().usage_instructions_text_mobile(),
@@ -293,7 +293,7 @@ TEST_F(AutofillSyncBridgeUtilTest, OfferSpecificsFromOfferData) {
offer_data.display_strings.see_details_text);
EXPECT_EQ(offer_specifics.display_strings().usage_instructions_text_desktop(),
offer_data.display_strings.usage_instructions_text);
-#endif // defined(OS_ANDROID) || defined(OS_IOS)
+#endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
}
// Test to ensure the card-linked offer-specific fields from an
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_table.cc b/chromium/components/autofill/core/browser/webdata/autofill_table.cc
index 9b36abb2363..cd3948e2ec1 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_table.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_table.cc
@@ -102,8 +102,6 @@ void BindAutofillProfileToStatement(const AutofillProfile& profile,
s->BindInt64(index++, modification_date.ToTimeT());
s->BindString(index++, profile.origin());
s->BindString(index++, profile.language_code());
- s->BindInt64(index++, profile.GetClientValidityBitfieldValue());
- s->BindBool(index++, profile.is_client_validity_states_updated());
s->BindString(index++, profile.profile_label());
s->BindBool(index++, profile.disallow_settings_visible_updates());
}
@@ -125,8 +123,6 @@ void AddAutofillProfileDetailsFromStatement(sql::Statement& s,
profile->set_modification_date(base::Time::FromTimeT(s.ColumnInt64(index++)));
profile->set_origin(s.ColumnString(index++));
profile->set_language_code(s.ColumnString(index++));
- profile->SetClientValidityFromBitfieldValue(s.ColumnInt64(index++));
- profile->set_is_client_validity_states_updated(s.ColumnBool(index++));
profile->set_profile_label(s.ColumnString(index++));
profile->set_disallow_settings_visible_updates(s.ColumnBool(index++));
}
@@ -651,11 +647,11 @@ bool AutofillTable::CreateTablesIfNecessary() {
return (InitMainTable() && InitCreditCardsTable() && InitProfilesTable() &&
InitProfileAddressesTable() && InitProfileNamesTable() &&
InitProfileEmailsTable() && InitProfilePhonesTable() &&
- InitProfileTrashTable() && InitMaskedCreditCardsTable() &&
- InitUnmaskedCreditCardsTable() && InitServerCardMetadataTable() &&
- InitServerAddressesTable() && InitServerAddressMetadataTable() &&
- InitAutofillSyncMetadataTable() && InitModelTypeStateTable() &&
- InitPaymentsCustomerDataTable() && InitPaymentsUPIVPATable() &&
+ InitMaskedCreditCardsTable() && InitUnmaskedCreditCardsTable() &&
+ InitServerCardMetadataTable() && InitServerAddressesTable() &&
+ InitServerAddressMetadataTable() && InitAutofillSyncMetadataTable() &&
+ InitModelTypeStateTable() && InitPaymentsCustomerDataTable() &&
+ InitPaymentsUPIVPATable() &&
InitServerCreditCardCloudTokenDataTable() && InitOfferDataTable() &&
InitOfferEligibleInstrumentTable() &&
InitOfferMerchantDomainTable() && InitCreditCardArtImagesTable());
@@ -777,6 +773,12 @@ bool AutofillTable::MigrateToVersion(int version,
case 98:
*update_compatible_version = true;
return MigrateToVersion98RemoveStatusColumnMaskedCreditCards();
+ case 99:
+ *update_compatible_version = true;
+ return MigrateToVersion99RemoveAutofillProfilesTrashTable();
+ case 100:
+ *update_compatible_version = true;
+ return MigrateToVersion100RemoveProfileValidityBitfieldColumn();
}
return true;
}
@@ -1110,17 +1112,13 @@ bool AutofillTable::UpdateAutofillEntries(
}
bool AutofillTable::AddAutofillProfile(const AutofillProfile& profile) {
- if (IsAutofillGUIDInTrash(profile.guid()))
- return true;
-
sql::Statement s(db_->GetUniqueStatement(
"INSERT INTO autofill_profiles"
"(guid, company_name, street_address, dependent_locality, city, state,"
" zipcode, sorting_code, country_code, use_count, use_date, "
- " date_modified, origin, language_code, validity_bitfield, "
- " is_client_validity_states_updated, label, "
- " disallow_settings_visible_updates) "
- "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"));
+ " date_modified, origin, language_code, "
+ " label, disallow_settings_visible_updates) "
+ "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"));
BindAutofillProfileToStatement(profile, AutofillClock::Now(), &s);
if (!s.Run())
@@ -1132,11 +1130,6 @@ bool AutofillTable::AddAutofillProfile(const AutofillProfile& profile) {
bool AutofillTable::UpdateAutofillProfile(const AutofillProfile& profile) {
DCHECK(base::IsValidGUID(profile.guid()));
- // Don't update anything until the trash has been emptied. There may be
- // pending modifications to process.
- if (!IsAutofillProfilesTrashEmpty())
- return true;
-
std::unique_ptr<AutofillProfile> old_profile =
GetAutofillProfile(profile.guid());
if (!old_profile)
@@ -1149,16 +1142,14 @@ bool AutofillTable::UpdateAutofillProfile(const AutofillProfile& profile) {
"SET guid=?, company_name=?, street_address=?, dependent_locality=?, "
" city=?, state=?, zipcode=?, sorting_code=?, country_code=?, "
" use_count=?, use_date=?, date_modified=?, origin=?, "
- " language_code=?, validity_bitfield=?, "
- " is_client_validity_states_updated=?, "
- " label=?, disallow_settings_visible_updates=? "
+ " language_code=?, label=?, disallow_settings_visible_updates=? "
"WHERE guid=?"));
BindAutofillProfileToStatement(profile,
update_modification_date
? AutofillClock::Now()
: old_profile->modification_date(),
&s);
- s.BindString(18, profile.guid());
+ s.BindString(16, profile.guid());
bool result = s.Run();
DCHECK_GT(db_->GetLastChangeCount(), 0);
@@ -1174,17 +1165,6 @@ bool AutofillTable::UpdateAutofillProfile(const AutofillProfile& profile) {
bool AutofillTable::RemoveAutofillProfile(const std::string& guid) {
DCHECK(base::IsValidGUID(guid));
-
- if (IsAutofillGUIDInTrash(guid)) {
- sql::Statement s_trash(db_->GetUniqueStatement(
- "DELETE FROM autofill_profiles_trash WHERE guid = ?"));
- s_trash.BindString(0, guid);
-
- bool success = s_trash.Run();
- DCHECK_GT(db_->GetLastChangeCount(), 0) << "Expected item in trash";
- return success;
- }
-
sql::Statement s(
db_->GetUniqueStatement("DELETE FROM autofill_profiles WHERE guid = ?"));
s.BindString(0, guid);
@@ -1201,8 +1181,7 @@ std::unique_ptr<AutofillProfile> AutofillTable::GetAutofillProfile(
sql::Statement s(db_->GetUniqueStatement(
"SELECT guid, company_name, street_address, dependent_locality, city,"
" state, zipcode, sorting_code, country_code, use_count, use_date,"
- " date_modified, origin, language_code, validity_bitfield,"
- " is_client_validity_states_updated, label,"
+ " date_modified, origin, language_code, label,"
" disallow_settings_visible_updates "
"FROM autofill_profiles "
"WHERE guid=?"));
@@ -1227,15 +1206,11 @@ std::unique_ptr<AutofillProfile> AutofillTable::GetAutofillProfile(
// The details should be added after the other info to make sure they don't
// change when we change the names/emails/phones.
AddAutofillProfileDetailsFromStatement(s, profile.get());
- bool validation_status = profile->is_client_validity_states_updated();
// The structured address information should be added after the street_address
// from the query above was written because this information is used to
// detect changes by a legacy client.
AddAutofillProfileAddressesToProfile(db_, profile.get());
- // Set the validation status again to prevent a change due to the repeated
- // writing.
- profile->set_is_client_validity_states_updated(validation_status);
// For more-structured profiles, the profile must be finalized to fully
// populate the name fields.
@@ -3526,6 +3501,51 @@ bool AutofillTable::MigrateToVersion98RemoveStatusColumnMaskedCreditCards() {
transaction.Commit();
}
+bool AutofillTable::MigrateToVersion99RemoveAutofillProfilesTrashTable() {
+ sql::Transaction transaction(db_);
+ return transaction.Begin() &&
+ db_->Execute("DROP TABLE autofill_profiles_trash") &&
+ transaction.Commit();
+}
+
+bool AutofillTable::MigrateToVersion100RemoveProfileValidityBitfieldColumn() {
+ // Sqlite does not support "alter table drop column" syntax, so it has be done
+ // manually.
+ sql::Transaction transaction(db_);
+
+ return transaction.Begin() &&
+ db_->Execute(
+ "CREATE TABLE autofill_profiles_tmp ( "
+ "guid VARCHAR PRIMARY KEY, "
+ "company_name VARCHAR, "
+ "street_address VARCHAR, "
+ "dependent_locality VARCHAR, "
+ "city VARCHAR, "
+ "state VARCHAR, "
+ "zipcode VARCHAR, "
+ "sorting_code VARCHAR, "
+ "country_code VARCHAR, "
+ "date_modified INTEGER NOT NULL DEFAULT 0, "
+ "origin VARCHAR DEFAULT '', "
+ "language_code VARCHAR, "
+ "use_count INTEGER NOT NULL DEFAULT 0, "
+ "use_date INTEGER NOT NULL DEFAULT 0, "
+ "label VARCHAR, "
+ "disallow_settings_visible_updates INTEGER NOT NULL DEFAULT 0)") &&
+ db_->Execute(
+ "INSERT INTO autofill_profiles_tmp "
+ "SELECT guid, company_name, street_address, dependent_locality, "
+ "city, state, zipcode, sorting_code, country_code, date_modified, "
+ "origin, language_code, use_count, use_date, label, "
+ "disallow_settings_visible_updates "
+ " FROM autofill_profiles") &&
+ db_->Execute("DROP TABLE autofill_profiles") &&
+ db_->Execute(
+ "ALTER TABLE autofill_profiles_tmp "
+ "RENAME TO autofill_profiles") &&
+ transaction.Commit();
+}
+
bool AutofillTable::AddFormFieldValuesTime(
const std::vector<FormFieldData>& elements,
std::vector<AutofillChange>* changes,
@@ -3666,21 +3686,6 @@ bool AutofillTable::InsertAutofillEntry(const AutofillEntry& entry) {
return s.Run();
}
-bool AutofillTable::IsAutofillProfilesTrashEmpty() {
- sql::Statement s(
- db_->GetUniqueStatement("SELECT guid FROM autofill_profiles_trash"));
-
- return !s.Step();
-}
-
-bool AutofillTable::IsAutofillGUIDInTrash(const std::string& guid) {
- sql::Statement s(db_->GetUniqueStatement(
- "SELECT guid FROM autofill_profiles_trash WHERE guid = ?"));
- s.BindString(0, guid);
-
- return s.Step();
-}
-
void AutofillTable::AddMaskedCreditCards(
const std::vector<CreditCard>& credit_cards) {
DCHECK_GT(db_->transaction_nesting(), 0);
@@ -3818,9 +3823,6 @@ bool AutofillTable::InitProfilesTable() {
"language_code VARCHAR, "
"use_count INTEGER NOT NULL DEFAULT 0, "
"use_date INTEGER NOT NULL DEFAULT 0, "
- "validity_bitfield UNSIGNED NOT NULL DEFAULT 0, "
- "is_client_validity_states_updated BOOL NOT NULL DEFAULT "
- "FALSE, "
"label VARCHAR, "
"disallow_settings_visible_updates INTEGER NOT NULL DEFAULT 0)")) {
NOTREACHED();
@@ -3927,17 +3929,6 @@ bool AutofillTable::InitProfilePhonesTable() {
return true;
}
-bool AutofillTable::InitProfileTrashTable() {
- if (!db_->DoesTableExist("autofill_profiles_trash")) {
- if (!db_->Execute("CREATE TABLE autofill_profiles_trash ( "
- "guid VARCHAR)")) {
- NOTREACHED();
- return false;
- }
- }
- return true;
-}
-
bool AutofillTable::InitMaskedCreditCardsTable() {
if (!db_->DoesTableExist("masked_credit_cards")) {
if (!db_->Execute("CREATE TABLE masked_credit_cards ("
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_table.h b/chromium/components/autofill/core/browser/webdata/autofill_table.h
index d89bd111c62..a0a7617b78a 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_table.h
+++ b/chromium/components/autofill/core/browser/webdata/autofill_table.h
@@ -93,13 +93,6 @@ struct PaymentsCustomerData;
// code starts with the postal code, but a JP address with
// "ja-latn" language code starts with the recipient name.
// Added in version 56.
-// validity_bitfield A bitfield representing the validity state of different
-// fields in the profile.
-// Added in version 75.
-// is_client_validity_states_updated
-// A flag indicating whether the validity states of
-// different fields according to the client validity api is
-// updated or not. Added in version 80.
// disallow_settings_visible_updates
// If true, a profile does not qualify to get merged with
// a profile observed in a form submission.
@@ -208,13 +201,6 @@ struct PaymentsCustomerData;
// phone number belongs.
// number
//
-// autofill_profiles_trash
-// This table contains guids of "trashed" autofill
-// profiles. When a profile is removed its guid is added
-// to this table so that Sync can perform deferred removal.
-//
-// guid The guid string that identifies the trashed profile.
-//
// credit_cards This table contains credit card data added by the user
// with the Autofill dialog. Most of the columns are
// standard entries in a credit card form.
@@ -721,6 +707,8 @@ class AutofillTable : public WebDatabaseTable,
bool MigrateToVersion95AddVirtualCardMetadata();
bool MigrateToVersion96AddAutofillProfileDisallowConfirmableMergesColumn();
bool MigrateToVersion98RemoveStatusColumnMaskedCreditCards();
+ bool MigrateToVersion99RemoveAutofillProfilesTrashTable();
+ bool MigrateToVersion100RemoveProfileValidityBitfieldColumn();
// Max data length saved in the table, AKA the maximum length allowed for
// form data.
@@ -794,12 +782,6 @@ class AutofillTable : public WebDatabaseTable,
// Insert a single AutofillEntry into the autofill table.
bool InsertAutofillEntry(const AutofillEntry& entry);
- // Checks if the trash is empty.
- bool IsAutofillProfilesTrashEmpty();
-
- // Checks if the guid is in the trash.
- bool IsAutofillGUIDInTrash(const std::string& guid);
-
// Adds to |masked_credit_cards| and updates |server_card_metadata|.
// Must already be in a transaction.
void AddMaskedCreditCards(const std::vector<CreditCard>& credit_cards);
@@ -819,7 +801,6 @@ class AutofillTable : public WebDatabaseTable,
bool InitProfileNamesTable();
bool InitProfileEmailsTable();
bool InitProfilePhonesTable();
- bool InitProfileTrashTable();
bool InitMaskedCreditCardsTable();
bool InitUnmaskedCreditCardsTable();
bool InitServerCardMetadataTable();
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc b/chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc
index d6f7e51bbfd..926ec41c8b8 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc
@@ -878,10 +878,6 @@ TEST_F(AutofillTableTest,
structured_name_profile.set_language_code("en");
- structured_name_profile.SetClientValidityFromBitfieldValue(6);
-
- structured_name_profile.set_is_client_validity_states_updated(true);
-
// Add the profile to the table.
EXPECT_TRUE(table_->AddAutofillProfile(structured_name_profile));
@@ -1286,8 +1282,6 @@ TEST_F(AutofillTableTest, AutofillProfile_StructuredNames) {
home_profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, u"18181234567");
home_profile.set_disallow_settings_visible_updates(true);
home_profile.set_language_code("en");
- home_profile.SetClientValidityFromBitfieldValue(6);
- home_profile.set_is_client_validity_states_updated(true);
Time pre_creation_time = AutofillClock::Now();
// Add the profile to the table.
@@ -1380,8 +1374,6 @@ TEST_F(AutofillTableTest, AutofillProfile_StructuredNames) {
billing_profile.SetRawInfo(ADDRESS_HOME_SORTING_CODE, u"123456");
billing_profile.SetRawInfo(ADDRESS_HOME_COUNTRY, u"US");
billing_profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, u"18181230000");
- billing_profile.SetClientValidityFromBitfieldValue(54);
- billing_profile.set_is_client_validity_states_updated(true);
Time pre_modification_time_2 = AutofillClock::Now();
EXPECT_TRUE(table_->UpdateAutofillProfile(billing_profile));
@@ -1435,8 +1427,6 @@ TEST_F(AutofillTableTest, AutofillProfile) {
home_profile.SetRawInfo(ADDRESS_HOME_COUNTRY, u"US");
home_profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, u"18181234567");
home_profile.set_language_code("en");
- home_profile.SetClientValidityFromBitfieldValue(6);
- home_profile.set_is_client_validity_states_updated(true);
Time pre_creation_time = AutofillClock::Now();
EXPECT_TRUE(table_->AddAutofillProfile(home_profile));
@@ -1515,8 +1505,6 @@ TEST_F(AutofillTableTest, AutofillProfile) {
billing_profile.SetRawInfo(ADDRESS_HOME_SORTING_CODE, u"123456");
billing_profile.SetRawInfo(ADDRESS_HOME_COUNTRY, u"US");
billing_profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, u"18181230000");
- billing_profile.SetClientValidityFromBitfieldValue(54);
- billing_profile.set_is_client_validity_states_updated(true);
Time pre_modification_time_2 = AutofillClock::Now();
EXPECT_TRUE(table_->UpdateAutofillProfile(billing_profile));
@@ -2371,75 +2359,6 @@ TEST_F(AutofillTableTest, Autofill_GetAllAutofillEntries_TwoSame) {
CompareAutofillEntrySets(entry_set, expected_entries);
}
-TEST_F(AutofillTableTest, AutofillProfileValidityBitfield) {
- // Add an autofill profile with a non default validity state. The value itself
- // is insignificant for this test since only the serialization and
- // deserialization are tested.
- const int kValidityBitfieldValue = 1984;
- AutofillProfile profile;
- profile.set_origin(std::string());
- profile.SetRawInfo(NAME_FIRST, u"John");
- profile.SetRawInfo(NAME_LAST, u"Smith");
- profile.SetClientValidityFromBitfieldValue(kValidityBitfieldValue);
-
- // Add the profile to the table.
- EXPECT_TRUE(table_->AddAutofillProfile(profile));
-
- // Get the profile from the table and make sure the validity was set.
- std::unique_ptr<AutofillProfile> db_profile =
- table_->GetAutofillProfile(profile.guid());
- ASSERT_TRUE(db_profile);
- EXPECT_EQ(kValidityBitfieldValue,
- db_profile->GetClientValidityBitfieldValue());
-
- // Modify the validity of the profile.
- const int kOtherValidityBitfieldValue = 1999;
- profile.SetClientValidityFromBitfieldValue(kOtherValidityBitfieldValue);
-
- // Update the profile in the table.
- EXPECT_TRUE(table_->UpdateAutofillProfile(profile));
-
- // Get the profile from the table and make sure the validity was updated.
- db_profile = table_->GetAutofillProfile(profile.guid());
- ASSERT_TRUE(db_profile);
- EXPECT_EQ(kOtherValidityBitfieldValue,
- db_profile->GetClientValidityBitfieldValue());
-}
-
-TEST_F(AutofillTableTest, AutofillProfileIsClientValidityStatesUpdatedFlag) {
- AutofillProfile profile;
- profile.set_origin(std::string());
- profile.SetRawInfo(NAME_FIRST, u"John");
- profile.SetRawInfo(NAME_LAST, u"Smith");
- profile.set_is_client_validity_states_updated(true);
-
- // Add the profile to the table.
- EXPECT_TRUE(table_->AddAutofillProfile(profile));
- // Get the profile from the table and make sure the validity was set.
- std::unique_ptr<AutofillProfile> db_profile =
- table_->GetAutofillProfile(profile.guid());
- ASSERT_TRUE(db_profile);
- EXPECT_TRUE(db_profile->is_client_validity_states_updated());
-
- // Test if turning off the validity updated flag works.
- profile.set_is_client_validity_states_updated(false);
- // Update the profile in the table.
- EXPECT_TRUE(table_->UpdateAutofillProfile(profile));
- // Get the profile from the table and make sure the validity was updated.
- db_profile = table_->GetAutofillProfile(profile.guid());
- ASSERT_TRUE(db_profile);
- EXPECT_FALSE(db_profile->is_client_validity_states_updated());
-
- // Test if turning on the validity updated flag works.
- profile.set_is_client_validity_states_updated(true);
- // Update the profile in the table.
- EXPECT_TRUE(table_->UpdateAutofillProfile(profile));
- // Get the profile from the table and make sure the validity was updated.
- db_profile = table_->GetAutofillProfile(profile.guid());
- ASSERT_TRUE(db_profile);
- EXPECT_TRUE(db_profile->is_client_validity_states_updated());
-}
-
TEST_F(AutofillTableTest, SetGetServerCards) {
std::vector<CreditCard> inputs;
inputs.push_back(CreditCard(CreditCard::FULL_SERVER_CARD, "a123"));
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.cc b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.cc
index 9c0ab12a037..066556f9e4f 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.cc
@@ -23,10 +23,10 @@
#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
#include "components/autofill/core/common/autofill_clock.h"
#include "components/autofill/core/common/autofill_util.h"
-#include "components/sync/engine/entity_data.h"
#include "components/sync/model/client_tag_based_model_type_processor.h"
#include "components/sync/model/mutable_data_batch.h"
#include "components/sync/model/sync_metadata_store_change_list.h"
+#include "components/sync/protocol/entity_data.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
namespace autofill {
@@ -249,8 +249,7 @@ bool IsMetadataWorthUpdating(AutofillMetadata existing_entry,
bool IsAnyMetadataDeletable(
const std::map<std::string, AutofillMetadata>& metadata_map) {
- for (const auto& pair : metadata_map) {
- const AutofillMetadata& metadata = pair.second;
+ for (const auto& [storage_key, metadata] : metadata_map) {
if (metadata.IsDeletable()) {
return true;
}
@@ -429,9 +428,9 @@ void AutofillWalletMetadataSyncBridge::ApplyStopSyncChanges(
// disabled, so we want to delete the data as well (i.e. the wallet metadata
// entities).
if (delete_metadata_change_list) {
- for (const std::pair<const std::string, AutofillMetadata>& pair : cache_) {
+ for (const auto& [storage_key, metadata] : cache_) {
TypeAndMetadataId parsed_storage_key =
- ParseWalletMetadataStorageKey(pair.first);
+ ParseWalletMetadataStorageKey(storage_key);
RemoveServerMetadata(GetAutofillTable(), parsed_storage_key.type,
parsed_storage_key.metadata_id);
}
@@ -492,13 +491,13 @@ void AutofillWalletMetadataSyncBridge::LoadDataCacheAndMetadata() {
{FROM_HERE, "Failed reading autofill data from WebDatabase."});
return;
}
- for (const auto& it : addresses_metadata) {
+ for (const auto& [metadata_id, metadata] : addresses_metadata) {
cache_[GetStorageKeyForWalletMetadataTypeAndId(
- WalletMetadataSpecifics::ADDRESS, it.first)] = it.second;
+ WalletMetadataSpecifics::ADDRESS, metadata_id)] = metadata;
}
- for (const auto& it : cards_metadata) {
+ for (const auto& [metadata_id, metadata] : cards_metadata) {
cache_[GetStorageKeyForWalletMetadataTypeAndId(
- WalletMetadataSpecifics::CARD, it.first)] = it.second;
+ WalletMetadataSpecifics::CARD, metadata_id)] = metadata;
}
// Load the metadata and send to the processor.
@@ -541,10 +540,9 @@ void AutofillWalletMetadataSyncBridge::DeleteOldOrphanMetadata() {
// Identify storage keys of old orphans (we delete them below to avoid
// modifying |cache_| while iterating).
std::unordered_set<std::string> old_orphan_keys;
- for (const auto& pair : cache_) {
- const AutofillMetadata& metadata = pair.second;
+ for (const auto& [storage_key, metadata] : cache_) {
if (metadata.IsDeletable() && !non_orphan_ids.count(metadata.id)) {
- old_orphan_keys.insert(pair.first);
+ old_orphan_keys.insert(storage_key);
}
}
@@ -581,9 +579,7 @@ void AutofillWalletMetadataSyncBridge::GetDataImpl(
auto batch = std::make_unique<syncer::MutableDataBatch>();
- for (const auto& pair : cache_) {
- const std::string& storage_key = pair.first;
- const AutofillMetadata& metadata = pair.second;
+ for (const auto& [storage_key, metadata] : cache_) {
TypeAndMetadataId parsed_storage_key =
ParseWalletMetadataStorageKey(storage_key);
if (!storage_keys_set || base::Contains(*storage_keys_set, storage_key)) {
@@ -600,8 +596,8 @@ void AutofillWalletMetadataSyncBridge::UploadInitialLocalData(
const syncer::EntityChangeList& entity_data) {
// First, make a copy of all local storage keys.
std::set<std::string> local_keys_to_upload;
- for (const auto& it : cache_) {
- local_keys_to_upload.insert(it.first);
+ for (const auto& [storage_key, metadata] : cache_) {
+ local_keys_to_upload.insert(storage_key);
}
// Strip |local_keys_to_upload| of the keys of data provided by the server.
for (const std::unique_ptr<EntityChange>& change : entity_data) {
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge_unittest.cc b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge_unittest.cc
index a7be983e2c5..86702559ad1 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge_unittest.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge_unittest.cc
@@ -32,10 +32,10 @@
#include "components/os_crypt/os_crypt_mocker.h"
#include "components/sync/base/client_tag_hash.h"
#include "components/sync/engine/data_type_activation_response.h"
-#include "components/sync/engine/entity_data.h"
#include "components/sync/model/client_tag_based_model_type_processor.h"
#include "components/sync/model/data_batch.h"
#include "components/sync/protocol/autofill_specifics.pb.h"
+#include "components/sync/protocol/entity_data.h"
#include "components/sync/protocol/entity_metadata.pb.h"
#include "components/sync/protocol/entity_specifics.pb.h"
#include "components/sync/protocol/model_type_state.pb.h"
@@ -451,10 +451,8 @@ class AutofillWalletMetadataSyncBridgeTest : public testing::Test {
AutofillTable* table = AutofillTable::FromWebDatabase(&db_);
syncer::MetadataBatch batch;
if (table->GetAllSyncMetadata(syncer::AUTOFILL_WALLET_METADATA, &batch)) {
- for (const std::pair<const std::string,
- std::unique_ptr<sync_pb::EntityMetadata>>& entry :
- batch.GetAllMetadata()) {
- storage_keys.push_back(entry.first);
+ for (const auto& [storage_key, metadata] : batch.GetAllMetadata()) {
+ storage_keys.push_back(storage_key);
}
}
return storage_keys;
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_offer_sync_bridge_unittest.cc b/chromium/components/autofill/core/browser/webdata/autofill_wallet_offer_sync_bridge_unittest.cc
index b17b3cd24d4..2edd5ea34e2 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_offer_sync_bridge_unittest.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_offer_sync_bridge_unittest.cc
@@ -28,11 +28,11 @@
#include "components/autofill/core/common/autofill_constants.h"
#include "components/sync/base/hash_util.h"
#include "components/sync/engine/data_type_activation_response.h"
-#include "components/sync/engine/entity_data.h"
#include "components/sync/model/client_tag_based_model_type_processor.h"
#include "components/sync/model/in_memory_metadata_change_list.h"
#include "components/sync/model/sync_data.h"
#include "components/sync/protocol/autofill_offer_specifics.pb.h"
+#include "components/sync/protocol/entity_data.h"
#include "components/sync/protocol/entity_specifics.pb.h"
#include "components/sync/protocol/model_type_state.pb.h"
#include "components/sync/test/model/mock_model_type_change_processor.h"
@@ -91,7 +91,7 @@ std::string AutofillOfferSpecificsAsDebugString(
<< ", offer_details_url: " << specifics.offer_details_url()
<< ", merchant_domain: " << domain_string << ", value_prop_text: "
<< specifics.display_strings().value_prop_text()
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
<< ", see_details_text: "
<< specifics.display_strings().see_details_text_mobile()
<< ", usage_instructions_text: "
@@ -101,7 +101,7 @@ std::string AutofillOfferSpecificsAsDebugString(
<< specifics.display_strings().see_details_text_desktop()
<< ", usage_instructions_text: "
<< specifics.display_strings().usage_instructions_text_desktop()
-#endif // defined(OS_ANDROID) || defined(OS_IOS)
+#endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
<< ", offer_reward_amount: " << offer_reward_amount_string
<< ", eligible_instrument_id: " << instrument_id_string
<< ", promo_code: " << specifics.promo_code_offer_data().promo_code()
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.cc b/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.cc
index aa13212bd3e..7349b36b9e8 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.cc
@@ -25,11 +25,10 @@
#include "components/autofill/core/common/autofill_util.h"
#include "components/sync/base/data_type_histogram.h"
#include "components/sync/base/hash_util.h"
-#include "components/sync/driver/sync_driver_switches.h"
-#include "components/sync/engine/entity_data.h"
#include "components/sync/model/client_tag_based_model_type_processor.h"
#include "components/sync/model/mutable_data_batch.h"
#include "components/sync/model/sync_metadata_store_change_list.h"
+#include "components/sync/protocol/entity_data.h"
using sync_pb::AutofillWalletSpecifics;
using syncer::EntityData;
@@ -547,13 +546,7 @@ void AutofillWalletSyncBridge::ProcessVirtualCardMetadataChanges(
const std::vector<CreditCard>& new_data) {
std::vector<std::string> updated_server_ids;
for (const CreditCard& new_card : new_data) {
- // If this new card is not enrolled for virtual cards, continue.
- if (new_card.virtual_card_enrollment_state() !=
- CreditCard::VirtualCardEnrollmentState::ENROLLED) {
- continue;
- }
-
- // Otherwise try to find the old card with same server id.
+ // Try to find the old card with same server id.
auto old_data_iterator =
std::find_if(old_data.begin(), old_data.end(),
[&new_card](const std::unique_ptr<CreditCard>& old_card) {
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge_unittest.cc b/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge_unittest.cc
index b65a8567a88..682b8d5811a 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge_unittest.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge_unittest.cc
@@ -34,13 +34,12 @@
#include "components/autofill/core/browser/webdata/mock_autofill_webdata_backend.h"
#include "components/autofill/core/common/autofill_constants.h"
#include "components/sync/base/client_tag_hash.h"
-#include "components/sync/driver/sync_driver_switches.h"
#include "components/sync/engine/data_type_activation_response.h"
-#include "components/sync/engine/entity_data.h"
#include "components/sync/model/client_tag_based_model_type_processor.h"
#include "components/sync/model/in_memory_metadata_change_list.h"
#include "components/sync/model/sync_data.h"
#include "components/sync/protocol/autofill_specifics.pb.h"
+#include "components/sync/protocol/entity_data.h"
#include "components/sync/protocol/entity_metadata.pb.h"
#include "components/sync/protocol/entity_specifics.pb.h"
#include "components/sync/protocol/model_type_state.pb.h"
diff --git a/chromium/components/autofill/core/common/BUILD.gn b/chromium/components/autofill/core/common/BUILD.gn
index c35edcff2f2..1df8b629615 100644
--- a/chromium/components/autofill/core/common/BUILD.gn
+++ b/chromium/components/autofill/core/common/BUILD.gn
@@ -107,6 +107,7 @@ source_set("unit_tests") {
"gaia_id_hash_unittest.cc",
"logging/log_buffer_unittest.cc",
"save_password_progress_logger_unittest.cc",
+ "signatures_unittest.cc",
]
deps = [
diff --git a/chromium/components/autofill/core/common/autofill_features.cc b/chromium/components/autofill/core/common/autofill_features.cc
index a09a113d261..a6708437391 100644
--- a/chromium/components/autofill/core/common/autofill_features.cc
+++ b/chromium/components/autofill/core/common/autofill_features.cc
@@ -4,10 +4,10 @@
#include "components/autofill/core/common/autofill_features.h"
+#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
-namespace autofill {
-namespace features {
+namespace autofill::features {
// Controls whether to flatten and fill cross-iframe forms.
// TODO(crbug.com/1187842) Remove once launched.
@@ -19,7 +19,7 @@ const base::Feature kAutofillAcrossIframes{"AutofillAcrossIframes",
// When enabled, a save prompt will be shown to user upon form submission before
// storing any detected address profile.
const base::Feature kAutofillAddressProfileSavePrompt{
- "AutofillAddressProfileSavePrompt", base::FEATURE_DISABLED_BY_DEFAULT};
+ "AutofillAddressProfileSavePrompt", base::FEATURE_ENABLED_BY_DEFAULT};
// This parameter controls if save profile prompts are automatically blocked for
// a given domain after N (default is 3) subsequent declines.
@@ -84,6 +84,20 @@ const base::Feature kAutofillAllowDuplicateFormSubmissions{
const base::Feature kAutofillAllowNonHttpActivation{
"AutofillAllowNonHttpActivation", base::FEATURE_DISABLED_BY_DEFAULT};
+// If enabled, whenever a form without a country field is parsed, the profile's
+// country code is complemented with the predicted country code, used to
+// determine the address requirements.
+// TODO(crbug.com/1297032): Cleanup when launched.
+const base::Feature kAutofillComplementCountryCodeOnImport{
+ "AutofillComplementCountryCodeOnImport", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// If enabled, the variation country code is used as the phone number's region,
+// instead of defaulting to app locale.
+// TODO(crbug.com/1295721): Cleanup when launched.
+const base::Feature kAutofillConsiderVariationCountryCodeForPhoneNumbers{
+ "AutofillConsiderVariationCountryCodeForPhoneNumbers",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
// If enabled, three address profiles are created for testing.
const base::Feature kAutofillCreateDataForTest{
"AutofillCreateDataForTest", base::FEATURE_DISABLED_BY_DEFAULT};
@@ -164,13 +178,6 @@ const base::Feature kAutofillEnableLabelPrecedenceForTurkishAddresses{
"AutofillEnableLabelPrecedenceForTurkishAddresses",
base::FEATURE_DISABLED_BY_DEFAULT};
-// When enabled and user is signed in, a footer indicating user's e-mail address
-// and profile picture will appear at the bottom of corresponding password
-// InfoBars.
-const base::Feature kAutofillEnablePasswordInfoBarAccountIndicationFooter{
- "AutofillEnablePasswordInfoBarAccountIndicationFooter",
- base::FEATURE_ENABLED_BY_DEFAULT};
-
// Enables the parsing of a sequence of fields that follows the pattern of Name,
// Surname.
// TODO(crbug.com/1277480): Remove once launched.
@@ -207,6 +214,11 @@ const base::Feature kAutofillEnableSupportForHonorificPrefixes{
"AutofillEnableSupportForHonorificPrefixes",
base::FEATURE_DISABLED_BY_DEFAULT};
+// Enables autofill to function within a FencedFrame, and is disabled by default
+// TODO(crbug.com/1294378): Remove once launched.
+const base::Feature kAutofillEnableWithinFencedFrame{
+ "AutofillEnableWithinFencedFrame", base::FEATURE_DISABLED_BY_DEFAULT};
+
// Controls whether or not all datalist shall be extracted into FormFieldData.
// This feature is enabled in both WebView and WebLayer where all datalists
// instead of only the focused one shall be extracted and sent to Android
@@ -227,6 +239,17 @@ const base::Feature kAutofillTypeSpecificPopupWidth{
const base::Feature kAutofillFixFillableFieldTypes{
"AutofillFixFillableFieldTypes", base::FEATURE_ENABLED_BY_DEFAULT};
+// Lookups for field classifications are gated on either Autofill for addresses
+// or payments being enabled. As a consequence, if both are disabled, the
+// password manager does not get server-side field classifications anymore
+// and its performance is reduced. When this feature is enabled, Autofill parse
+// forms and perform server lookups even if only the password manager is
+// enabled.
+// TODO(crbug.com/1293341): Remove once launched.
+const base::Feature kAutofillFixServerQueriesIfPasswordManagerIsEnabled{
+ "AutofillFixServerQueriesIfPasswordManagerIsEnabled",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
// The autocomplete attribute may prevent Autofill import, crbug/1213301. This
// feature addresses the issue. For now, the fix only concerns fields with the
// signature 2281611779.
@@ -234,6 +257,22 @@ const base::Feature kAutofillFixFillableFieldTypes{
const base::Feature kAutofillIgnoreAutocompleteForImport{
"AutofillIgnoreAutocompleteForImport", base::FEATURE_DISABLED_BY_DEFAULT};
+// When enabled, the Autofill popup ignores second clicks for a certain period
+// (kAutofillIgnoreEarlyClicksOnPopupDuration) after the Autofill popup was
+// shown. This is to prevent double clicks accidentally accepting suggestions.
+// TODO(crbug/1279268): Remove once launched.
+const base::Feature kAutofillIgnoreEarlyClicksOnPopup{
+ "AutofillIgnoreEarlyClicksOnPopup", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// The duration for which clicks on the just-shown Autofill popup should be
+// ignored if AutofillIgnoreEarlyClicksOnPopup is enabled.
+// TODO(crbug/1279268): Remove once launched. Consider also removing
+// AutofillPopupItemView::mouse_observed_outside_of_item_.
+const base::FeatureParam<base::TimeDelta>
+ kAutofillIgnoreEarlyClicksOnPopupDuration{
+ &kAutofillIgnoreEarlyClicksOnPopup, "duration",
+ base::Milliseconds(500)};
+
// When enabled, only changed values are highlighted in preview mode.
// TODO(crbug/1248585): Remove when launched.
const base::Feature kAutofillHighlightOnlyChangedValuesInPreviewMode{
@@ -286,28 +325,31 @@ extern const base::Feature kAutofillPreventOverridingPrefilledValues{
"AutofillPreventOverridingPrefilledValues",
base::FEATURE_DISABLED_BY_DEFAULT};
-// When enabled, Autofill will load remote patterns via the component updater.
+// Uses the pattern provider to retrieve parsing patterns for the heuristic
+// field type detection.
// TODO(crbug/1121990): Remove once launched.
-extern const base::Feature kAutofillParsingPatternsFromRemote{
- "AutofillParsingPatternsFromRemote", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kAutofillParsingPatternProvider{
+ "AutofillParsingPatternProvider", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Controls if language-specific patterns are used for the heuristic field type
+// detection.
+// For this to work, the feature kAutofillPageLanguageDetection must be enabled.
+// Otherwise the pattern provider will revert back to language unspecific
+// patterns.
+const base::FeatureParam<bool>
+ kAutofillParsingWithLanguageSpecificPatternsParam{
+ &kAutofillParsingPatternProvider, "use_language_specific_patterns",
+ true};
+
+// Controls if patterns retrieved with the component updater are used.
+const base::FeatureParam<bool> kAutofillParsingWithRemotePatternsParam{
+ &kAutofillParsingPatternProvider,
+ "use_patterns_retrieved_with_the_component_udpater", false};
// Enables detection of language from Translate.
// TODO(crbug/1150895): Cleanup when launched.
-const base::Feature kAutofillParsingPatternsLanguageDetection{
- "AutofillParsingPatternsLanguageDetection",
- base::FEATURE_DISABLED_BY_DEFAULT};
-
-// Controls whether negative patterns are used to parse the field type.
-// TODO(crbug.com/1132831): Remove once launched.
-const base::Feature kAutofillParsingPatternsNegativeMatching{
- "AutofillParsingPatternsNegativeMatching",
- base::FEATURE_DISABLED_BY_DEFAULT};
-
-// Controls whether page language is used to match patterns.
-// TODO(crbug.com/1134496): Remove once launched.
-const base::Feature kAutofillParsingPatternsLanguageDependent{
- "AutofillParsingPatternsLanguageDependent",
- base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kAutofillPageLanguageDetection{
+ "AutofillPageLanguageDetection", base::FEATURE_DISABLED_BY_DEFAULT};
// If the feature is enabled, FormTracker's probable-form-submission detection
// is disabled and replaced with browser-side detection.
@@ -316,24 +358,11 @@ const base::Feature kAutofillProbableFormSubmissionInBrowser{
"AutofillProbableFormSubmissionInBrowser",
base::FEATURE_DISABLED_BY_DEFAULT};
-const base::Feature kAutofillProfileClientValidation{
- "AutofillProfileClientValidation", base::FEATURE_DISABLED_BY_DEFAULT};
-
// TODO(crbug.com/1101280): Remove once feature is tested.
const base::Feature kAutofillProfileImportFromUnfocusableFields{
"AutofillProfileImportFromUnfocusableFields",
base::FEATURE_DISABLED_BY_DEFAULT};
-// Controls whether Autofill uses server-side validation to ensure that fields
-// with invalid data are not suggested.
-const base::Feature kAutofillProfileServerValidation{
- "AutofillProfileServerValidation", base::FEATURE_DISABLED_BY_DEFAULT};
-
-// Controls if the heuristic field parsing utilizes shared labels.
-// TODO(crbug/1275772): Remove if no negative consequences observed.
-const base::Feature kAutofillRecordMetricsOfUnownedForms{
- "AutofillRecordMetricsOfUnownedForms", base::FEATURE_DISABLED_BY_DEFAULT};
-
// Controls whether or not overall prediction are retrieved from the cache.
const base::Feature kAutofillRetrieveOverallPredictionsFromCache{
"AutofillRetrieveOverallPredictionsFromCache",
@@ -357,6 +386,12 @@ const base::Feature kAutofillSectionUponRedundantNameInfo{
const base::Feature kAutofillServerCommunication{
"AutofillServerCommunication", base::FEATURE_ENABLED_BY_DEFAULT};
+// Controls whether Autofill may fill across origins as part of the
+// AutofillAcrossIframes experiment.
+// TODO(crbug.com/1220038): Clean up when launched.
+const base::Feature kAutofillSharedAutofill{"AutofillSharedAutofill",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
// Controls attaching the autofill type predictions to their respective
// element in the DOM.
const base::Feature kAutofillShowTypePredictions{
@@ -434,7 +469,7 @@ const base::FeatureParam<bool> kAutofillAblationStudyEnabledForPaymentsParam{
const base::FeatureParam<int> kAutofillAblationStudyAblationWeightPerMilleParam{
&kAutofillEnableAblationStudy, "ablation_weight_per_mille", 10};
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Controls whether the Autofill manual fallback for Addresses and Payments is
// present on Android.
const base::Feature kAutofillManualFallbackAndroid{
@@ -450,17 +485,17 @@ const base::Feature kAutofillTouchToFillForCreditCardsAndroid{
"AutofillTouchToFillForCreditCardsAndroid",
base::FEATURE_DISABLED_BY_DEFAULT};
-#endif // OS_ANDROID
+#endif // BUILDFLAG(IS_ANDROID)
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
const base::Feature kAutofillUseMobileLabelDisambiguation{
"AutofillUseMobileLabelDisambiguation", base::FEATURE_DISABLED_BY_DEFAULT};
const char kAutofillUseMobileLabelDisambiguationParameterName[] = "variant";
const char kAutofillUseMobileLabelDisambiguationParameterShowAll[] = "show-all";
const char kAutofillUseMobileLabelDisambiguationParameterShowOne[] = "show-one";
-#endif // defined(OS_ANDROID) || defined(OS_IOS)
+#endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
// Controls whether the creation of new address profiles is enabled in settings
// on IOS.
// TODO(crbug/1167105): Remove once it's launched.
@@ -469,14 +504,13 @@ const base::Feature kAutofillEnableNewAddressProfileCreationInSettingsOnIOS{
base::FEATURE_DISABLED_BY_DEFAULT};
#endif
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
bool IsAutofillManualFallbackEnabled() {
return base::FeatureList::IsEnabled(
autofill::features::kAutofillKeyboardAccessory) &&
base::FeatureList::IsEnabled(
autofill::features::kAutofillManualFallbackAndroid);
}
-#endif // OS_ANDROID
+#endif // BUILDFLAG(IS_ANDROID)
-} // namespace features
-} // namespace autofill
+} // namespace autofill::features
diff --git a/chromium/components/autofill/core/common/autofill_features.h b/chromium/components/autofill/core/common/autofill_features.h
index 43da3700200..3104af5b45a 100644
--- a/chromium/components/autofill/core/common/autofill_features.h
+++ b/chromium/components/autofill/core/common/autofill_features.h
@@ -7,10 +7,11 @@
#include "base/component_export.h"
#include "base/feature_list.h"
+#include "base/metrics/field_trial_params.h"
+#include "base/time/time.h"
#include "build/build_config.h"
-namespace autofill {
-namespace features {
+namespace autofill::features {
// All features in alphabetical order.
COMPONENT_EXPORT(AUTOFILL) extern const base::Feature kAutofillAcrossIframes;
@@ -44,6 +45,12 @@ extern const base::Feature kAutofillAllowDuplicateFormSubmissions;
COMPONENT_EXPORT(AUTOFILL)
extern const base::Feature kAutofillAllowNonHttpActivation;
COMPONENT_EXPORT(AUTOFILL)
+extern const base::Feature kAutofillComplementCountryCodeOnImport;
+COMPONENT_EXPORT(AUTOFILL)
+extern const base::Feature kAutofillConsiderVariationCountryCodeForPhoneNumbers;
+COMPONENT_EXPORT(AUTOFILL)
+extern const base::Feature kAutofillEnableWithinFencedFrame;
+COMPONENT_EXPORT(AUTOFILL)
extern const base::Feature kAutofillCreateDataForTest;
COMPONENT_EXPORT(AUTOFILL)
extern const base::Feature kAutofillDelayPopupControllerDeletion;
@@ -63,9 +70,6 @@ extern const base::Feature kAutofillEnableHideSuggestionsUI;
COMPONENT_EXPORT(AUTOFILL)
extern const base::Feature kAutofillEnableImportWhenMultiplePhoneNumbers;
COMPONENT_EXPORT(AUTOFILL)
-extern const base::Feature
- kAutofillEnablePasswordInfoBarAccountIndicationFooter;
-COMPONENT_EXPORT(AUTOFILL)
extern const base::Feature kAutofillEnableSupportForApartmentNumbers;
COMPONENT_EXPORT(AUTOFILL)
extern const base::Feature kAutofillEnableLabelPrecedenceForTurkishAddresses;
@@ -90,8 +94,15 @@ extern const base::Feature kAutofillTypeSpecificPopupWidth;
COMPONENT_EXPORT(AUTOFILL)
extern const base::Feature kAutofillFixFillableFieldTypes;
COMPONENT_EXPORT(AUTOFILL)
+extern const base::Feature kAutofillFixServerQueriesIfPasswordManagerIsEnabled;
+COMPONENT_EXPORT(AUTOFILL)
extern const base::Feature kAutofillIgnoreAutocompleteForImport;
COMPONENT_EXPORT(AUTOFILL)
+extern const base::Feature kAutofillIgnoreEarlyClicksOnPopup;
+COMPONENT_EXPORT(AUTOFILL)
+extern const base::FeatureParam<base::TimeDelta>
+ kAutofillIgnoreEarlyClicksOnPopupDuration;
+COMPONENT_EXPORT(AUTOFILL)
extern const base::Feature kAutofillHighlightOnlyChangedValuesInPreviewMode;
COMPONENT_EXPORT(AUTOFILL)
extern const base::Feature kAutofillServerTypeTakesPrecedence;
@@ -108,26 +119,21 @@ COMPONENT_EXPORT(AUTOFILL)
extern const base::FeatureParam<int>
kAutofillMaxiumWidthPercentageToMoveSuggestionPopupToCenter;
COMPONENT_EXPORT(AUTOFILL)
-extern const base::Feature kAutofillParsingPatternsFromRemote;
+extern const base::Feature kAutofillParsingPatternProvider;
COMPONENT_EXPORT(AUTOFILL)
-extern const base::Feature kAutofillParsingPatternsLanguageDetection;
+extern const base::FeatureParam<bool>
+ kAutofillParsingWithLanguageSpecificPatternsParam;
COMPONENT_EXPORT(AUTOFILL)
-extern const base::Feature kAutofillParsingPatternsNegativeMatching;
+extern const base::FeatureParam<bool> kAutofillParsingWithRemotePatternsParam;
COMPONENT_EXPORT(AUTOFILL)
-extern const base::Feature kAutofillParsingPatternsLanguageDependent;
+extern const base::Feature kAutofillPageLanguageDetection;
COMPONENT_EXPORT(AUTOFILL)
extern const base::Feature kAutofillPreventOverridingPrefilledValues;
COMPONENT_EXPORT(AUTOFILL)
extern const base::Feature kAutofillProbableFormSubmissionInBrowser;
COMPONENT_EXPORT(AUTOFILL)
-extern const base::Feature kAutofillProfileClientValidation;
-COMPONENT_EXPORT(AUTOFILL)
extern const base::Feature kAutofillProfileImportFromUnfocusableFields;
COMPONENT_EXPORT(AUTOFILL)
-extern const base::Feature kAutofillProfileServerValidation;
-COMPONENT_EXPORT(AUTOFILL)
-extern const base::Feature kAutofillRecordMetricsOfUnownedForms;
-COMPONENT_EXPORT(AUTOFILL)
extern const base::Feature kAutofillRetrieveOverallPredictionsFromCache;
COMPONENT_EXPORT(AUTOFILL) extern const base::Feature kAutofillSaveAndFillVPA;
COMPONENT_EXPORT(AUTOFILL)
@@ -135,6 +141,8 @@ extern const base::Feature kAutofillSectionUponRedundantNameInfo;
COMPONENT_EXPORT(AUTOFILL)
extern const base::Feature kAutofillServerCommunication;
COMPONENT_EXPORT(AUTOFILL)
+extern const base::Feature kAutofillSharedAutofill;
+COMPONENT_EXPORT(AUTOFILL)
extern const base::Feature kAutofillShowTypePredictions;
COMPONENT_EXPORT(AUTOFILL)
extern const base::Feature kAutofillSilentProfileUpdateForInsufficientImport;
@@ -168,16 +176,16 @@ COMPONENT_EXPORT(AUTOFILL)
extern const base::FeatureParam<int>
kAutofillAblationStudyAblationWeightPerMilleParam;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
COMPONENT_EXPORT(AUTOFILL)
extern const base::Feature kAutofillManualFallbackAndroid;
COMPONENT_EXPORT(AUTOFILL)
extern const base::Feature kAutofillRefreshStyleAndroid;
COMPONENT_EXPORT(AUTOFILL)
extern const base::Feature kAutofillTouchToFillForCreditCardsAndroid;
-#endif // OS_ANDROID
+#endif // BUILDFLAG(IS_ANDROID)
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
COMPONENT_EXPORT(AUTOFILL)
extern const base::Feature kAutofillUseMobileLabelDisambiguation;
COMPONENT_EXPORT(AUTOFILL)
@@ -186,27 +194,26 @@ COMPONENT_EXPORT(AUTOFILL)
extern const char kAutofillUseMobileLabelDisambiguationParameterShowOne[];
COMPONENT_EXPORT(AUTOFILL)
extern const char kAutofillUseMobileLabelDisambiguationParameterShowAll[];
-#endif // defined(OS_ANDROID) || defined(OS_IOS)
+#endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
// Returns true if whether the views autofill popup feature is enabled or the
// we're using the views browser.
COMPONENT_EXPORT(AUTOFILL)
bool IsMacViewsAutofillPopupExperimentEnabled();
-#endif // defined(OS_APPLE)
+#endif // BUILDFLAG(IS_APPLE)
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
COMPONENT_EXPORT(AUTOFILL)
extern const base::Feature
kAutofillEnableNewAddressProfileCreationInSettingsOnIOS;
-#endif // OS_IOS
+#endif // BUILDFLAG(IS_IOS)
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
COMPONENT_EXPORT(AUTOFILL)
bool IsAutofillManualFallbackEnabled();
-#endif // OS_ANDROID
+#endif // BUILDFLAG(IS_ANDROID)
-} // namespace features
-} // namespace autofill
+} // namespace autofill::features
#endif // COMPONENTS_AUTOFILL_CORE_COMMON_AUTOFILL_FEATURES_H_
diff --git a/chromium/components/autofill/core/common/autofill_payments_features.cc b/chromium/components/autofill/core/common/autofill_payments_features.cc
index 593d56caa12..0f77a3ababa 100644
--- a/chromium/components/autofill/core/common/autofill_payments_features.cc
+++ b/chromium/components/autofill/core/common/autofill_payments_features.cc
@@ -40,7 +40,7 @@ const base::Feature kAutofillAutoTriggerManualFallbackForCards{
// credit cards from Google payments.
const base::Feature kAutofillCreditCardAuthentication{
"AutofillCreditCardAuthentication",
-#if defined(OS_WIN) || defined(OS_MAC) || defined(OS_ANDROID)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_ANDROID)
// Better Auth project is fully launched on Win/Mac/Clank.
base::FEATURE_ENABLED_BY_DEFAULT
#else
@@ -82,10 +82,11 @@ const base::Feature kAutofillEnableOffersInClankKeyboardAccessory{
"AutofillEnableOffersInClankKeyboardAccessory",
base::FEATURE_DISABLED_BY_DEFAULT};
-// When enabled, offer data will be retrieved during downstream and shown in
-// the dropdown list.
-const base::Feature kAutofillEnableOffersInDownstream{
- "kAutofillEnableOffersInDownstream", base::FEATURE_ENABLED_BY_DEFAULT};
+// Controls whether we send billing customer number in GetUploadDetails
+// preflight call.
+const base::Feature kAutofillEnableSendingBcnInGetUploadDetails{
+ "AutofillEnableSendingBcnInGetUploadDetails",
+ base::FEATURE_DISABLED_BY_DEFAULT};
// When enabled, if the user interacts with the manual fallback bottom sheet
// on Android, it'll remain sticky until the user dismisses it.
@@ -98,11 +99,32 @@ const base::Feature kAutofillEnableStickyManualFallbackForCards{
const base::Feature kAutofillEnableToolbarStatusChip{
"AutofillEnableToolbarStatusChip", base::FEATURE_DISABLED_BY_DEFAULT};
+// When enabled, UnmaskCardRequest will set instrument id, which is Chrome-side
+// field for non-legacy ID.
+const base::Feature kAutofillEnableUnmaskCardRequestSetInstrumentId{
+ "AutofillEnableUnmaskCardRequestSetInstrumentId",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+
+// When enabled, the user will have the ability to update the virtual card
+// enrollment of a credit card through their chrome browser after certain
+// autofill flows (for example, downstream and upstream), and from the settings
+// page.
+const base::Feature kAutofillEnableUpdateVirtualCardEnrollment{
+ "AutofillEnableUpdateVirtualCardEnrollment",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
// When enabled, the option of using cloud token virtual card will be offered
// when all requirements are met.
const base::Feature kAutofillEnableVirtualCard{
"AutofillEnableVirtualCard", base::FEATURE_DISABLED_BY_DEFAULT};
+// When enabled, in the payments settings page on desktop, virtual card
+// enrollment management will be provided so that the user can enroll/unenroll a
+// card in virtual card.
+const base::Feature kAutofillEnableVirtualCardManagementInDesktopSettingsPage{
+ "AutofillEnableVirtualCardManagementInDesktopSettingsPage",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+
// When enabled, virtual card retrieval will pass an optional
// authentication based on risk level.
const base::Feature kAutofillEnableVirtualCardsRiskBasedAuthentication{
@@ -158,11 +180,9 @@ const base::Feature kAutofillSuggestVirtualCardsOnIncompleteForm{
// Controls offering credit card upload to Google Payments. Cannot ever be
// ENABLED_BY_DEFAULT because the feature state depends on the user's country.
-// There are countries we simply can't turn this on for, and they change over
-// time, so it's important that we can flip a switch and be done instead of
-// having old versions of Chrome forever do the wrong thing. Enabling it by
-// default would mean that any first-run client without a Finch config won't get
-// the overriding command to NOT turn it on, which becomes an issue.
+// The set of launched countries is listed in autofill_experiments.cc, and this
+// flag remains as a way to easily enable upload credit card save for testers,
+// as well as enable non-fully-launched countries on a trial basis.
const base::Feature kAutofillUpstream{"AutofillUpstream",
base::FEATURE_DISABLED_BY_DEFAULT};
@@ -172,8 +192,8 @@ const base::Feature kAutofillUpstreamAllowAllEmailDomains{
bool ShouldShowImprovedUserConsentForCreditCardSave() {
// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
// of lacros-chrome is complete.
-#if defined(OS_WIN) || defined(OS_APPLE) || \
- (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS))
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || \
+ (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS))
// The new user consent UI is fully launched on MacOS, Windows and Linux.
return true;
#else
diff --git a/chromium/components/autofill/core/common/autofill_payments_features.h b/chromium/components/autofill/core/common/autofill_payments_features.h
index 4f46970a420..12b062bc8f3 100644
--- a/chromium/components/autofill/core/common/autofill_payments_features.h
+++ b/chromium/components/autofill/core/common/autofill_payments_features.h
@@ -6,6 +6,7 @@
#define COMPONENTS_AUTOFILL_CORE_COMMON_AUTOFILL_PAYMENTS_FEATURES_H_
#include "base/feature_list.h"
+#include "base/metrics/field_trial_params.h"
#include "build/build_config.h"
namespace base {
@@ -25,10 +26,14 @@ extern const base::Feature kAutofillEnableMerchantBoundVirtualCards;
extern const base::Feature kAutofillEnableOfferNotificationCrossTabTracking;
extern const base::Feature kAutofillEnableOfferNotificationForPromoCodes;
extern const base::Feature kAutofillEnableOffersInClankKeyboardAccessory;
-extern const base::Feature kAutofillEnableOffersInDownstream;
+extern const base::Feature kAutofillEnableSendingBcnInGetUploadDetails;
extern const base::Feature kAutofillEnableStickyManualFallbackForCards;
extern const base::Feature kAutofillEnableToolbarStatusChip;
+extern const base::Feature kAutofillEnableUnmaskCardRequestSetInstrumentId;
+extern const base::Feature kAutofillEnableUpdateVirtualCardEnrollment;
extern const base::Feature kAutofillEnableVirtualCard;
+extern const base::Feature
+ kAutofillEnableVirtualCardManagementInDesktopSettingsPage;
extern const base::Feature kAutofillEnableVirtualCardsRiskBasedAuthentication;
extern const base::Feature kAutofillFillMerchantPromoCodeFields;
extern const base::Feature kAutofillFixOfferInIncognito;
diff --git a/chromium/components/autofill/core/common/autofill_prefs.cc b/chromium/components/autofill/core/common/autofill_prefs.cc
index 2c25dae19f1..2fa47fb0e2b 100644
--- a/chromium/components/autofill/core/common/autofill_prefs.cc
+++ b/chromium/components/autofill/core/common/autofill_prefs.cc
@@ -44,7 +44,7 @@ const char kAutofillCreditCardEnabled[] = "autofill.credit_card_enabled";
const char kAutofillCreditCardFidoAuthEnabled[] =
"autofill.credit_card_fido_auth_enabled";
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Boolean that is true if FIDO Authentication is enabled for card unmasking.
const char kAutofillCreditCardFidoAuthOfferCheckboxState[] =
"autofill.credit_card_fido_auth_offer_checkbox_state";
@@ -156,7 +156,7 @@ void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
// Non-synced prefs. Used for per-device choices, e.g., signin promo.
registry->RegisterBooleanPref(prefs::kAutofillCreditCardFidoAuthEnabled,
false);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
registry->RegisterBooleanPref(
prefs::kAutofillCreditCardFidoAuthOfferCheckboxState, true);
#endif
@@ -308,7 +308,7 @@ void SetUserOptedInWalletSyncTransport(PrefService* prefs,
bool IsUserOptedInWalletSyncTransport(const PrefService* prefs,
const CoreAccountId& account_id) {
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
// On mobile, no specific opt-in is required.
return true;
#else
@@ -320,7 +320,7 @@ bool IsUserOptedInWalletSyncTransport(const PrefService* prefs,
// Return whether the wallet opt-in bit is set.
return GetSyncTransportOptInBitFieldForAccount(prefs, account_hash) &
sync_transport_opt_in::kWallet;
-#endif // OS_ANDROID || defined(OS_IOS)
+#endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
}
void ClearSyncTransportOptIns(PrefService* prefs) {
diff --git a/chromium/components/autofill/core/common/autofill_prefs.h b/chromium/components/autofill/core/common/autofill_prefs.h
index f8c62e26056..d48feaf5d55 100644
--- a/chromium/components/autofill/core/common/autofill_prefs.h
+++ b/chromium/components/autofill/core/common/autofill_prefs.h
@@ -24,7 +24,7 @@ namespace prefs {
// Do not get/set the value of this pref directly. Use provided getter/setter.
extern const char kAutofillCreditCardEnabled[];
extern const char kAutofillCreditCardFidoAuthEnabled[];
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
extern const char kAutofillCreditCardFidoAuthOfferCheckboxState[];
#endif
extern const char kAutofillCreditCardSigninPromoImpressionCount[];
diff --git a/chromium/components/autofill/core/common/autofill_prefs_unittest.cc b/chromium/components/autofill/core/common/autofill_prefs_unittest.cc
index 08e038e5437..7576fceced2 100644
--- a/chromium/components/autofill/core/common/autofill_prefs_unittest.cc
+++ b/chromium/components/autofill/core/common/autofill_prefs_unittest.cc
@@ -80,7 +80,7 @@ TEST_F(AutofillPrefsTest, MigrateDeprecatedAutofillPrefs) {
// expected.
// On mobile, no dedicated opt-in is required for WalletSyncTransport - the
// user is always considered opted-in and thus this test doesn't make sense.
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
TEST_F(AutofillPrefsTest, WalletSyncTransportPref_GetAndSet) {
const CoreAccountId account1("account1");
const CoreAccountId account2("account2");
@@ -129,7 +129,7 @@ TEST_F(AutofillPrefsTest, WalletSyncTransportPref_GetAndSet) {
->GetDictionary(prefs::kAutofillSyncTransportOptIn)
->DictSize());
}
-#endif // !defined(OS_ANDROID) && !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
// Tests that AutofillSyncTransportOptIn is not stored using the plain text
// account id.
diff --git a/chromium/components/autofill/core/common/autofill_util.cc b/chromium/components/autofill/core/common/autofill_util.cc
index 403f606a4d2..3b21aeffc6e 100644
--- a/chromium/components/autofill/core/common/autofill_util.cc
+++ b/chromium/components/autofill/core/common/autofill_util.cc
@@ -57,9 +57,9 @@ bool IsShowAutofillSignaturesEnabled() {
}
bool IsKeyboardAccessoryEnabled() {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
return base::FeatureList::IsEnabled(kAutofillKeyboardAccessory);
-#else // !defined(OS_ANDROID)
+#else // !BUILDFLAG(IS_ANDROID)
return false;
#endif
}
@@ -153,8 +153,8 @@ bool SanitizedFieldIsEmpty(const std::u16string& value) {
}
bool ShouldAutoselectFirstSuggestionOnArrowDown() {
-#if defined(OS_WIN) || defined(OS_APPLE) || defined(OS_LINUX) || \
- defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) || \
+ BUILDFLAG(IS_CHROMEOS)
return true;
#else
return false;
diff --git a/chromium/components/autofill/core/common/dense_set.h b/chromium/components/autofill/core/common/dense_set.h
index 7cf444f3c59..6839cf4bf50 100644
--- a/chromium/components/autofill/core/common/dense_set.h
+++ b/chromium/components/autofill/core/common/dense_set.h
@@ -126,6 +126,17 @@ class DenseSet {
constexpr DenseSet() = default;
+ // The `constexpr` constructor allows for compile-time initialization of
+ // DenseSets. This only works if the set fits into 64 bits. Otherwise, we
+ // fall back to a non-`constexpr` constructor.
+
+ template <size_t kMaxBit = base::checked_cast<Index>(kMaxValue),
+ std::enable_if_t<(kMaxBit < 64), bool> = true>
+ constexpr DenseSet(std::initializer_list<T> init)
+ : bitset_(initializer_list_to_bitmask(init)) {}
+
+ template <size_t kMaxBit = base::checked_cast<Index>(kMaxValue),
+ std::enable_if_t<(kMaxBit >= 64), bool> = true>
DenseSet(std::initializer_list<T> init) {
for (const auto& x : init) {
insert(x);
@@ -178,7 +189,7 @@ class DenseSet {
size_t size() const { return bitset_.count(); }
// Returns the maximum number of elements the set can have.
- size_t max_size() const { return bitset_.size(); }
+ constexpr size_t max_size() const { return bitset_.size(); }
// Modifiers.
@@ -288,6 +299,20 @@ class DenseSet {
return static_cast<T>(base::checked_cast<UnderlyingType>(i));
}
+ // Helper for `constexpr DenseSet(std::initializer_list<T>)`.
+ //
+ // While std::bitset's constructor takes an `unsigned long long`, we use
+ // `uint64_t` because Chromium bans `unsigned long long`. Both are 64 bit
+ // integers, so they're interchangeable.
+ static constexpr uint64_t initializer_list_to_bitmask(
+ const std::initializer_list<T>& init) {
+ uint64_t bitmask = 0;
+ for (const auto& x : init) {
+ bitmask |= 1ULL << value_to_index(x);
+ }
+ return bitmask;
+ }
+
static_assert(std::is_integral<T>::value || std::is_enum<T>::value, "");
static_assert(0 <= base::checked_cast<Index>(kMaxValue) + 1, "");
diff --git a/chromium/components/autofill/core/common/dense_set_unittest.cc b/chromium/components/autofill/core/common/dense_set_unittest.cc
index d99bc000495..5f8643c62aa 100644
--- a/chromium/components/autofill/core/common/dense_set_unittest.cc
+++ b/chromium/components/autofill/core/common/dense_set_unittest.cc
@@ -12,7 +12,7 @@
namespace autofill {
-TEST(DenseSet, initialization) {
+TEST(DenseSetTest, initialization) {
enum class T : size_t {
One = 1,
Two = 2,
@@ -38,7 +38,50 @@ TEST(DenseSet, initialization) {
EXPECT_EQ(DS({T::Four, T::Two, T::One}), s);
}
-TEST(DenseSet, iterators_begin_end) {
+TEST(DenseSetTest, initializer_list) {
+ // The largest value so that DenseSet offers a constexpr constructor.
+ constexpr size_t kMaxValueForConstexpr = 63;
+
+ // Each of the below blocks is a copy that only varies in `kMax` and whether
+ // or not the `set` is `constexpr`.
+
+ {
+ constexpr size_t kMax = 10;
+ constexpr DenseSet<size_t, kMax> set{0, 1, kMax - 2, kMax - 1, kMax};
+ EXPECT_THAT(std::vector<size_t>(set.begin(), set.end()),
+ ::testing::ElementsAre(0, 1, kMax - 2, kMax - 1, kMax));
+ }
+
+ {
+ constexpr size_t kMax = kMaxValueForConstexpr;
+ constexpr DenseSet<size_t, kMax> set{0, 1, kMax - 2, kMax - 1, kMax};
+ EXPECT_THAT(std::vector<size_t>(set.begin(), set.end()),
+ ::testing::ElementsAre(0, 1, kMax - 2, kMax - 1, kMax));
+ }
+
+ {
+ constexpr size_t kMax = kMaxValueForConstexpr + 1;
+ DenseSet<size_t, kMax> set{0, 1, kMax - 2, kMax - 1, kMax};
+ EXPECT_THAT(std::vector<size_t>(set.begin(), set.end()),
+ ::testing::ElementsAre(0, 1, kMax - 2, kMax - 1, kMax));
+ }
+
+ {
+ constexpr size_t kMax = kMaxValueForConstexpr + 2;
+ DenseSet<size_t, kMax> set{0, 1, kMax - 2, kMax - 1, kMax};
+ EXPECT_THAT(std::vector<size_t>(set.begin(), set.end()),
+ ::testing::ElementsAre(0, 1, kMax - 2, kMax - 1, kMax));
+ }
+
+ {
+ constexpr size_t kMax = kMaxValueForConstexpr + 100;
+ DenseSet<size_t, kMax> set{0, 1, kMax - 2, kMax - 1, kMax};
+ EXPECT_THAT(std::vector<size_t>(set.begin(), set.end()),
+ ::testing::ElementsAre(0, 1, kMax - 2, kMax - 1, kMax));
+ }
+}
+
+TEST(DenseSetTest, iterators_begin_end) {
enum class T : int {
One = 1,
Two = 2,
@@ -81,7 +124,7 @@ TEST(DenseSet, iterators_begin_end) {
EXPECT_THAT(s, ::testing::ElementsAre(T::One, T::Two, T::Four));
}
-TEST(DenseSet, iterators_begin_end_reverse) {
+TEST(DenseSetTest, iterators_begin_end_reverse) {
enum class T : char {
One = 1,
Two = 2,
@@ -122,7 +165,7 @@ TEST(DenseSet, iterators_begin_end_reverse) {
}
}
-TEST(DenseSet, iterators_rbegin_rend) {
+TEST(DenseSetTest, iterators_rbegin_rend) {
enum class T {
One = 1,
Two = 2,
@@ -166,7 +209,7 @@ TEST(DenseSet, iterators_rbegin_rend) {
::testing::ElementsAre(T::Four, T::Two, T::One));
}
-TEST(DenseSet, lookup) {
+TEST(DenseSetTest, lookup) {
enum class T {
One = 1,
Two = 2,
@@ -241,7 +284,7 @@ TEST(DenseSet, lookup) {
EXPECT_TRUE(s.contains_all({}));
}
-TEST(DenseSet, iterators_lower_upper_bound) {
+TEST(DenseSetTest, iterators_lower_upper_bound) {
enum class T { One = 1, Two = 2, Three = 3, Four = 4, Five = 5 };
using DS = DenseSet<T, T::Five>;
@@ -310,7 +353,7 @@ TEST(DenseSet, iterators_lower_upper_bound) {
EXPECT_EQ(std::next(std::next(std::next(s.begin()))), s.end());
}
-TEST(DenseSet, max_size) {
+TEST(DenseSetTest, max_size) {
const int One = 1;
const int Two = 2;
// const int Three = 3;
@@ -335,7 +378,7 @@ TEST(DenseSet, max_size) {
EXPECT_EQ(s.max_size(), 6u);
}
-TEST(DenseSet, modifiers) {
+TEST(DenseSetTest, modifiers) {
const size_t One = 1;
const size_t Two = 2;
const size_t Three = 3;
@@ -456,7 +499,7 @@ TEST(DenseSet, modifiers) {
EXPECT_EQ(t.size(), 3u);
}
-TEST(DenseSet, std_set) {
+TEST(DenseSetTest, std_set) {
constexpr size_t kMaxValue = 50;
DenseSet<size_t, kMaxValue> dense_set;
std::set<size_t> std_set;
diff --git a/chromium/components/autofill/core/common/form_data.h b/chromium/components/autofill/core/common/form_data.h
index 364b59c8e3e..ee00cd0c749 100644
--- a/chromium/components/autofill/core/common/form_data.h
+++ b/chromium/components/autofill/core/common/form_data.h
@@ -235,7 +235,7 @@ struct FormData {
std::vector<FieldRendererId> username_predictions;
// True if this is a Gaia form which should be skipped on saving.
bool is_gaia_with_skip_save_password_form = false;
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
std::string frame_id;
#endif
};
diff --git a/chromium/components/autofill/core/common/form_field_data.cc b/chromium/components/autofill/core/common/form_field_data.cc
index 2b82fd77f21..abe5b863478 100644
--- a/chromium/components/autofill/core/common/form_field_data.cc
+++ b/chromium/components/autofill/core/common/form_field_data.cc
@@ -11,6 +11,7 @@
#include "base/strings/strcat.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
+#include "build/build_config.h"
#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/autofill_util.h"
#include "components/autofill/core/common/logging/log_buffer.h"
@@ -234,7 +235,7 @@ auto IdentityTuple(const FormFieldData& f) {
std::tie(
// TODO(crbug.com/896689): On iOS the unique_id member uniquely addresses
// this field in the DOM.
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
f.unique_id,
#endif
f.autocomplete_attribute, f.placeholder, f.max_length, f.css_classes,
diff --git a/chromium/components/autofill/core/common/form_field_data.h b/chromium/components/autofill/core/common/form_field_data.h
index 640f64b05f4..ba879c29a67 100644
--- a/chromium/components/autofill/core/common/form_field_data.h
+++ b/chromium/components/autofill/core/common/form_field_data.h
@@ -135,7 +135,7 @@ struct FormFieldData {
bool HadFocus() const;
bool WasAutofilled() const;
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
// The identifier which uniquely addresses this field in the DOM. This is an
// ephemeral value which is not guaranteed to be stable across page loads. It
// serves to allow a given field to be found during the current navigation.
diff --git a/chromium/components/autofill/core/common/logging/log_buffer.cc b/chromium/components/autofill/core/common/logging/log_buffer.cc
index 2a2a26b0866..18037e67623 100644
--- a/chromium/components/autofill/core/common/logging/log_buffer.cc
+++ b/chromium/components/autofill/core/common/logging/log_buffer.cc
@@ -65,8 +65,8 @@ bool TryCoalesceString(std::vector<base::Value>* buffer,
auto* children = parent.FindListKey("children");
if (!children)
return false;
- DCHECK(!children->GetList().empty());
- auto& last_child = children->GetList().back();
+ DCHECK(!children->GetListDeprecated().empty());
+ auto& last_child = children->GetListDeprecated().back();
if (!IsTextNode(last_child))
return false;
std::string* old_text = last_child.FindStringKey("value");
@@ -99,13 +99,13 @@ base::Value LogBuffer::RetrieveResult() {
*this << CTag{};
auto* children = buffer_[0].FindListKey("children");
- if (!children || children->GetList().empty())
+ if (!children || children->GetListDeprecated().empty())
return base::Value();
// If the fragment has a single child, remove it from |children| and return
// that directly.
- if (children->GetList().size() == 1) {
- return std::move(std::move(*children).TakeList().back());
+ if (children->GetListDeprecated().size() == 1) {
+ return std::move(std::move(*children).TakeListDeprecated().back());
}
return std::exchange(buffer_.back(), CreateEmptyFragment());
@@ -197,7 +197,7 @@ LogBuffer& operator<<(LogBuffer& buf, LogBuffer&& buffer) {
auto* children = node_to_add.FindListKey("children");
if (!children)
return buf;
- for (auto& child : children->GetList())
+ for (auto& child : children->GetListDeprecated())
AppendChildToLastNode(&buf.buffer_, std::exchange(child, base::Value()));
return buf;
}
diff --git a/chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits_unittest.cc b/chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits_unittest.cc
index 93cf0ebbc05..98bfa5d86e8 100644
--- a/chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits_unittest.cc
+++ b/chromium/components/autofill/core/common/mojom/autofill_types_mojom_traits_unittest.cc
@@ -250,7 +250,7 @@ TEST_F(AutofillTypeTraitsTestImpl, PassFormFieldData) {
test::CreateTestSelectField("TestLabel", "TestName", "TestValue", kOptions,
kOptions, 4, &input);
// Set other attributes to check if they are passed correctly.
- input.host_frame = test::GetLocalFrameToken();
+ input.host_frame = test::MakeLocalFrameToken();
input.unique_renderer_id = FieldRendererId(1234);
input.id_attribute = u"id";
input.name_attribute = u"name";
@@ -283,7 +283,7 @@ TEST_F(AutofillTypeTraitsTestImpl, PassDataListFormFieldData) {
test::CreateTestDatalistField("DatalistLabel", "DatalistName",
"DatalistValue", kOptions, kOptions, &input);
// Set other attributes to check if they are passed correctly.
- input.host_frame = test::GetLocalFrameToken();
+ input.host_frame = test::MakeLocalFrameToken();
input.unique_renderer_id = FieldRendererId(1234);
input.id_attribute = u"id";
input.name_attribute = u"name";
diff --git a/chromium/components/autofill/core/common/password_form_generation_data.h b/chromium/components/autofill/core/common/password_form_generation_data.h
index e919bb8e760..a89f730c666 100644
--- a/chromium/components/autofill/core/common/password_form_generation_data.h
+++ b/chromium/components/autofill/core/common/password_form_generation_data.h
@@ -13,7 +13,7 @@ namespace autofill {
// Structure used for sending information from browser to renderer about on
// which fields password should be generated.
struct PasswordFormGenerationData {
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
FormRendererId form_renderer_id;
#endif
FieldRendererId new_password_renderer_id;
diff --git a/chromium/components/autofill/core/common/signatures.cc b/chromium/components/autofill/core/common/signatures.cc
index bbe321b7f08..afbbfc1495a 100644
--- a/chromium/components/autofill/core/common/signatures.cc
+++ b/chromium/components/autofill/core/common/signatures.cc
@@ -68,7 +68,7 @@ uint64_t PackBytes(base::span<const uint8_t, N> bytes) {
// If a form name was set by Chrome, we should ignore it when calculating
// the form signature.
std::string GetDOMFormName(const std::string& form_name) {
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
// In case of an empty form name, the synthetic name is created. Ignore it.
return (StartsWith(form_name, "gChrome~form~", base::CompareCase::SENSITIVE)
? std::string()
@@ -102,7 +102,8 @@ FormSignature CalculateFormSignature(const FormData& form_data) {
}
}
- std::string form_name = GetDOMFormName(UTF16ToUTF8(form_data.name));
+ std::string form_name =
+ StripDigitsIfRequired(GetDOMFormName(UTF16ToUTF8(form_data.name)));
std::string form_string = base::StrCat(
{scheme, "://", host, "&", form_name, form_signature_field_names});
return FormSignature(StrToHash64Bit(form_string));
diff --git a/chromium/components/autofill/core/common/signatures_unittest.cc b/chromium/components/autofill/core/common/signatures_unittest.cc
new file mode 100644
index 00000000000..a38e98075c9
--- /dev/null
+++ b/chromium/components/autofill/core/common/signatures_unittest.cc
@@ -0,0 +1,40 @@
+// Copyright 2022 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.
+
+#include "components/autofill/core/common/signatures.h"
+#include "components/autofill/core/common/form_data.h"
+#include "components/autofill/core/common/form_field_data.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace autofill {
+
+TEST(SignaturesTest, StripDigits) {
+ FormData actual_form;
+ actual_form.url = GURL("http://foo.com");
+ actual_form.name = u"form_name_12345";
+
+ FormFieldData field1;
+ field1.form_control_type = "text";
+ field1.name = u"field_name_12345";
+ actual_form.fields.push_back(field1);
+
+ FormFieldData field2;
+ field2.form_control_type = "text";
+ field2.name = u"field_name_1234";
+ actual_form.fields.push_back(field2);
+
+ // Sequences of 5 digits or longer should be stripped.
+ FormData expected_form(actual_form);
+ expected_form.name = u"form_name_";
+ expected_form.fields[0].name = u"field_name_";
+
+ EXPECT_EQ(CalculateFormSignature(expected_form).value(),
+ CalculateFormSignature(actual_form).value());
+ EXPECT_EQ(
+ StrToHash64Bit("http://foo.com&form_name_&field_name_&field_name_1234"),
+ CalculateFormSignature(actual_form).value());
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/core/common/unique_ids.h b/chromium/components/autofill/core/common/unique_ids.h
index 918843fd1f6..4fd403c98a7 100644
--- a/chromium/components/autofill/core/common/unique_ids.h
+++ b/chromium/components/autofill/core/common/unique_ids.h
@@ -55,7 +55,7 @@ using FrameToken = absl::variant<RemoteFrameToken, LocalFrameToken>;
namespace internal {
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
using FormRendererIdType = ::base::IdTypeU32<class FormRendererIdMarker>;
using FieldRendererIdType = ::base::IdTypeU32<class FieldRendererIdMarker>;
#else
diff --git a/chromium/components/autofill/ios/browser/BUILD.gn b/chromium/components/autofill/ios/browser/BUILD.gn
index e369d6b87f4..b54e4965a76 100644
--- a/chromium/components/autofill/ios/browser/BUILD.gn
+++ b/chromium/components/autofill/ios/browser/BUILD.gn
@@ -129,6 +129,7 @@ source_set("unit_tests") {
"//ios/web/public",
"//ios/web/public/js_messaging",
"//ios/web/public/test",
+ "//ios/web/public/test:test_fixture",
"//ios/web/public/test/fakes",
"//services/metrics/public/cpp:ukm_builders",
"//testing/gmock",
diff --git a/chromium/components/autofill/ios/browser/autofill_java_script_feature.mm b/chromium/components/autofill/ios/browser/autofill_java_script_feature.mm
index 2615725c3e6..f0acaf4ff5d 100644
--- a/chromium/components/autofill/ios/browser/autofill_java_script_feature.mm
+++ b/chromium/components/autofill/ios/browser/autofill_java_script_feature.mm
@@ -8,6 +8,7 @@
#include "base/command_line.h"
#include "base/feature_list.h"
+#include "base/no_destructor.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/sys_string_conversions.h"
#include "base/values.h"
diff --git a/chromium/components/autofill/ios/browser/autofill_util.mm b/chromium/components/autofill/ios/browser/autofill_util.mm
index 81f1fda22ae..9cde0ac21f7 100644
--- a/chromium/components/autofill/ios/browser/autofill_util.mm
+++ b/chromium/components/autofill/ios/browser/autofill_util.mm
@@ -101,7 +101,7 @@ bool ExtractFormsData(NSString* forms_json,
// Iterate through all the extracted forms and copy the data from JSON into
// BrowserAutofillManager structures.
- for (const auto& form_dict : forms_value->GetList()) {
+ for (const auto& form_dict : forms_value->GetListDeprecated()) {
autofill::FormData form;
if (ExtractFormData(form_dict, filtered, form_name, main_frame_url,
frame_origin, &form))
@@ -165,7 +165,7 @@ bool ExtractFormData(const base::Value& form_value,
const base::ListValue* fields_list = nullptr;
if (!form_dictionary->GetList("fields", &fields_list))
return false;
- for (const auto& field_dict : fields_list->GetList()) {
+ for (const auto& field_dict : fields_list->GetListDeprecated()) {
const base::DictionaryValue* field;
autofill::FormFieldData field_data;
if (field_dict.GetAsDictionary(&field) &&
@@ -233,17 +233,17 @@ bool ExtractFormFieldData(const base::DictionaryValue& field,
const base::ListValue* option_contents;
if (field.GetList("option_values", &option_values) &&
field.GetList("option_contents", &option_contents)) {
- auto value_list = option_values->GetList();
- auto content_list = option_contents->GetList();
+ auto value_list = option_values->GetListDeprecated();
+ auto content_list = option_contents->GetListDeprecated();
if (value_list.size() != content_list.size())
return false;
auto value_it = value_list.begin();
auto content_it = content_list.begin();
while (value_it != value_list.end() && content_it != content_list.end()) {
- std::u16string value;
- std::u16string content;
- if (value_it->GetAsString(&value) && content_it->GetAsString(&content)) {
- field_data->options.push_back({.value = value, .content = content});
+ if (value_it->is_string() && content_it->is_string()) {
+ field_data->options.push_back(
+ {.value = base::UTF8ToUTF16(value_it->GetString()),
+ .content = base::UTF8ToUTF16(content_it->GetString())});
}
++value_it;
++content_it;
@@ -308,12 +308,11 @@ bool ExtractIDs(NSString* json_string, std::vector<FieldRendererId>* ids) {
if (!ids_value->is_list())
return false;
- for (const auto& unique_id : ids_value->GetList()) {
- std::string id_string;
- if (!unique_id.GetAsString(&id_string))
+ for (const auto& unique_id : ids_value->GetListDeprecated()) {
+ if (!unique_id.is_string())
return false;
uint32_t id_num = 0;
- StringToUint(id_string, &id_num);
+ StringToUint(unique_id.GetString(), &id_num);
ids->push_back(FieldRendererId(id_num));
}
return true;
@@ -336,9 +335,7 @@ bool ExtractFillingResults(
std::string id_string = result.first;
uint32_t id_num = 0;
StringToUint(id_string, &id_num);
- std::u16string value;
- result.second.GetAsString(&value);
- (*filling_results)[id_num] = value;
+ (*filling_results)[id_num] = base::UTF8ToUTF16(result.second.GetString());
}
return true;
}
diff --git a/chromium/components/autofill/ios/browser/suggestion_controller_java_script_feature.mm b/chromium/components/autofill/ios/browser/suggestion_controller_java_script_feature.mm
index 82cddaac7ae..4e485b5de87 100644
--- a/chromium/components/autofill/ios/browser/suggestion_controller_java_script_feature.mm
+++ b/chromium/components/autofill/ios/browser/suggestion_controller_java_script_feature.mm
@@ -7,6 +7,7 @@
#import <Foundation/Foundation.h>
#include "base/bind.h"
+#include "base/no_destructor.h"
#include "base/strings/sys_string_conversions.h"
#include "base/time/time.h"
#include "base/values.h"
diff --git a/chromium/components/autofill/ios/form_util/BUILD.gn b/chromium/components/autofill/ios/form_util/BUILD.gn
index fb4e88dbf8f..a44bd46a013 100644
--- a/chromium/components/autofill/ios/form_util/BUILD.gn
+++ b/chromium/components/autofill/ios/form_util/BUILD.gn
@@ -93,6 +93,7 @@ source_set("test_support") {
"//ios/web/public",
"//ios/web/public/js_messaging",
"//ios/web/public/test",
+ "//ios/web/public/test:test_fixture",
"//testing/gtest",
]
}
@@ -116,6 +117,7 @@ source_set("unit_tests") {
"//components/autofill/ios/form_util:form_handler_feature",
"//ios/web/public/js_messaging",
"//ios/web/public/test",
+ "//ios/web/public/test:test_fixture",
"//ios/web/public/test/fakes",
"//ios/web/web_state/js",
"//testing/gtest",
@@ -137,6 +139,7 @@ if (is_ios) {
"//ios/web/public/js_messaging/fuzzer_support:js_message_proto",
"//ios/web/public/test",
"//ios/web/public/test:fuzzer_support",
+ "//ios/web/public/test:test_fixture",
"//third_party/libprotobuf-mutator",
]
}
diff --git a/chromium/components/autofill/ios/form_util/form_handlers_java_script_feature.mm b/chromium/components/autofill/ios/form_util/form_handlers_java_script_feature.mm
index 777227f9f24..74949194d8e 100644
--- a/chromium/components/autofill/ios/form_util/form_handlers_java_script_feature.mm
+++ b/chromium/components/autofill/ios/form_util/form_handlers_java_script_feature.mm
@@ -4,6 +4,7 @@
#import "components/autofill/ios/form_util/form_handlers_java_script_feature.h"
+#include "base/no_destructor.h"
#include "base/values.h"
#include "components/autofill/ios/form_util/form_activity_tab_helper.h"
#import "components/autofill/ios/form_util/form_util_java_script_feature.h"
diff --git a/chromium/components/autofill/ios/form_util/form_util_java_script_feature.mm b/chromium/components/autofill/ios/form_util/form_util_java_script_feature.mm
index 0a11c03e96d..c26a6b3a329 100644
--- a/chromium/components/autofill/ios/form_util/form_util_java_script_feature.mm
+++ b/chromium/components/autofill/ios/form_util/form_util_java_script_feature.mm
@@ -4,6 +4,7 @@
#import "components/autofill/ios/form_util/form_util_java_script_feature.h"
+#include "base/no_destructor.h"
#include "base/values.h"
#import "ios/web/public/js_messaging/java_script_feature_util.h"
diff --git a/chromium/components/autofill/ios/form_util/unique_id_data_tab_helper_unittest.mm b/chromium/components/autofill/ios/form_util/unique_id_data_tab_helper_unittest.mm
index d8f2ef397c0..b7d59003c1d 100644
--- a/chromium/components/autofill/ios/form_util/unique_id_data_tab_helper_unittest.mm
+++ b/chromium/components/autofill/ios/form_util/unique_id_data_tab_helper_unittest.mm
@@ -13,15 +13,15 @@
#error "This file requires ARC support."
#endif
-// Test fixture for TabIdTabHelper class.
+// Test fixture for UniqueIDDataTabHelper class.
class UniqueIDDataTabHelperTest : public PlatformTest {
protected:
web::FakeWebState first_web_state_;
web::FakeWebState second_web_state_;
};
-// Tests that a tab ID is returned for a WebState, and tab ID's are different
-// for different WebStates if they were once set differently.
+// Tests that a renderer ID is returned for a WebState, and rendered ID's are
+// different for different WebStates if they were once set differently.
TEST_F(UniqueIDDataTabHelperTest, UniqueIdentifiers) {
UniqueIDDataTabHelper::CreateForWebState(&first_web_state_);
UniqueIDDataTabHelper::CreateForWebState(&second_web_state_);
@@ -51,7 +51,7 @@ TEST_F(UniqueIDDataTabHelperTest, UniqueIdentifiers) {
EXPECT_NE(first_available_unique_id, second_available_unique_id);
}
-// Tests that a tab ID is stable across successive calls.
+// Tests that a renderer ID is stable across successive calls.
TEST_F(UniqueIDDataTabHelperTest, StableAcrossCalls) {
UniqueIDDataTabHelper::CreateForWebState(&first_web_state_);
UniqueIDDataTabHelper* tab_helper =
diff --git a/chromium/components/autofill_assistant/OWNERS b/chromium/components/autofill_assistant/OWNERS
index 362142f1b68..486dae3cefa 100644
--- a/chromium/components/autofill_assistant/OWNERS
+++ b/chromium/components/autofill_assistant/OWNERS
@@ -1,6 +1,4 @@
# Please keep these in alphabetical order
arbesser@google.com
hluca@google.com
-marianfe@google.com
-mcarlen@chromium.org
sandromaggi@google.com
diff --git a/chromium/components/autofill_assistant/android/BUILD.gn b/chromium/components/autofill_assistant/android/BUILD.gn
index 251403c24f9..181d9389f19 100644
--- a/chromium/components/autofill_assistant/android/BUILD.gn
+++ b/chromium/components/autofill_assistant/android/BUILD.gn
@@ -10,43 +10,58 @@ import("//build/config/zip.gni")
import("//chrome/common/features.gni")
import("//tools/grit/grit_rule.gni")
-# The animated_poodle_java target is overridden downstream and used
-# instead of this one if the enable_chrome_android_internal flag is
-# enabled.
-android_library("animated_poodle_java") {
+android_resources("animated_poodle_resources") {
+ sources =
+ [ "internal/java/res_poodle/drawable/ic_autofill_assistant_24dp.xml" ]
+}
+
+# These java targets are overridden downstream and used instead of these ones.
+android_library("autofill_assistant_public_java") {
+ resources_package = "org.chromium.chrome.autofill_assistant.common"
+
deps = [
":animated_poodle_resources",
"//base:base_java",
- "//chrome/android:chrome_java",
"//third_party/android_deps:android_support_v7_appcompat_java",
"//third_party/androidx:androidx_appcompat_appcompat_resources_java",
+ "//ui/android:ui_java",
]
- sources = [ "internal/java/src/org/chromium/chrome/browser/" +
- "autofill_assistant/header/AnimatedPoodle.java" ]
- resources_package = "org.chromium.chrome.autofill_assistant.poodle"
-}
+ sources = [
+ "internal/java/src/org/chromium/chrome/browser/autofill_assistant/header/AnimatedPoodle.java",
+ "internal/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/GmsIntegrator.java",
+ ]
-android_resources("animated_poodle_resources") {
- sources =
- [ "internal/java/res_poodle/drawable/ic_autofill_assistant_24dp.xml" ]
+ # Add the actual implementation where necessary so that downstream targets
+ # can provide their own implementations.
+ jar_excluded_patterns = [
+ "*/AnimatedPoodle.class",
+ "*/GmsIntegrator.class",
+ ]
}
-# The paments_integrator_java target is overridden downstream and used instead
-# of this one if the enable_chrome_android_internal flag is enabled.
-android_library("gms_integrator_java") {
+android_library("autofill_assistant_public_impl_java") {
+ resources_package = "org.chromium.chrome.autofill_assistant.common"
+
deps = [
+ ":animated_poodle_resources",
"//base:base_java",
- "//ui/android:ui_no_recycler_view_java",
+ "//chrome/android:chrome_java",
+ "//third_party/android_deps:android_support_v7_appcompat_java",
+ "//third_party/androidx:androidx_appcompat_appcompat_resources_java",
+ "//ui/android:ui_java",
]
- sources = [ "internal/java/src/org/chromium/chrome/browser/" +
- "autofill_assistant/user_data/GmsIntegrator.java" ]
+ sources = [
+ "internal/java/src/org/chromium/chrome/browser/autofill_assistant/header/AnimatedPoodle.java",
+ "internal/java/src/org/chromium/chrome/browser/autofill_assistant/user_data/GmsIntegrator.java",
+ ]
}
android_resources("java_resources") {
sources = [
- "internal/java/res/drawable/autofill_assistant_actions_gradient.xml",
+ "internal/java/res/drawable-v23/autofill_assistant_actions_gradient.xml",
+ "internal/java/res/drawable-v31/autofill_assistant_actions_gradient.xml",
"internal/java/res/drawable/autofill_assistant_circle_background.xml",
"internal/java/res/drawable/autofill_assistant_default_details.xml",
"internal/java/res/drawable/autofill_assistant_details_bg.xml",
@@ -84,7 +99,6 @@ android_resources("java_resources") {
"internal/java/res/layout/autofill_assistant_button_hairline.xml",
"internal/java/res/layout/autofill_assistant_contact_full.xml",
"internal/java/res/layout/autofill_assistant_contact_summary.xml",
- "internal/java/res/layout/autofill_assistant_datetime.xml",
"internal/java/res/layout/autofill_assistant_details.xml",
"internal/java/res/layout/autofill_assistant_form_checkbox.xml",
"internal/java/res/layout/autofill_assistant_form_counter.xml",
@@ -96,6 +110,7 @@ android_resources("java_resources") {
"internal/java/res/layout/autofill_assistant_info_box.xml",
"internal/java/res/layout/autofill_assistant_login.xml",
"internal/java/res/layout/autofill_assistant_onboarding_no_button.xml",
+ "internal/java/res/layout/autofill_assistant_onboarding_terms.xml",
"internal/java/res/layout/autofill_assistant_onboarding_yes_button.xml",
"internal/java/res/layout/autofill_assistant_payment_method_full.xml",
"internal/java/res/layout/autofill_assistant_payment_method_summary.xml",
diff --git a/chromium/components/autofill_assistant/android/internal/java/res/drawable/autofill_assistant_actions_gradient.xml b/chromium/components/autofill_assistant/android/internal/java/res/drawable-v23/autofill_assistant_actions_gradient.xml
index 9927f4c044d..abd22c827ca 100644
--- a/chromium/components/autofill_assistant/android/internal/java/res/drawable/autofill_assistant_actions_gradient.xml
+++ b/chromium/components/autofill_assistant/android/internal/java/res/drawable-v23/autofill_assistant_actions_gradient.xml
@@ -2,6 +2,6 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:angle="0"
- android:startColor="@color/sheet_bg_color"
+ android:startColor="@color/sheet_bg_color_baseline"
android:endColor="@android:color/transparent"/>
</shape> \ No newline at end of file
diff --git a/chromium/components/autofill_assistant/android/internal/java/res/drawable-v31/autofill_assistant_actions_gradient.xml b/chromium/components/autofill_assistant/android/internal/java/res/drawable-v31/autofill_assistant_actions_gradient.xml
new file mode 100644
index 00000000000..e67a3757f2f
--- /dev/null
+++ b/chromium/components/autofill_assistant/android/internal/java/res/drawable-v31/autofill_assistant_actions_gradient.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2022 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. -->
+
+<org.chromium.components.browser_ui.widget.SurfaceColorDrawable
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ app:surfaceElevation="@dimen/sheet_background_elev">
+ <gradient
+ android:angle="0"
+ android:startColor="@color/sheet_bg_color_baseline"
+ android:endColor="@android:color/transparent"/>
+</org.chromium.components.browser_ui.widget.SurfaceColorDrawable> \ No newline at end of file
diff --git a/chromium/components/autofill_assistant/android/internal/java/res/layout/autofill_assistant_base_onboarding.xml b/chromium/components/autofill_assistant/android/internal/java/res/layout/autofill_assistant_base_onboarding.xml
index 7813cceaf59..6d651a460e1 100644
--- a/chromium/components/autofill_assistant/android/internal/java/res/layout/autofill_assistant_base_onboarding.xml
+++ b/chromium/components/autofill_assistant/android/internal/java/res/layout/autofill_assistant_base_onboarding.xml
@@ -53,6 +53,7 @@
<!-- Subtitle (e.g., 'Google Assistant saves you time...')-->
<LinearLayout
+ android:id="@+id/onboarding_subtitle_container"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Space
@@ -89,22 +90,19 @@
android:layout_height="1dp"
android:layout_weight="0.33"/>
</LinearLayout>
- <Space android:layout_width="0dp" android:layout_height="20dp"/>
+ <!-- Space between divider and terms-->
+ <Space
+ android:id="@+id/terms_spacing_before"
+ android:layout_width="0dp"
+ android:layout_height="20dp"/>
<!-- Terms and Conditions message and link -->
- <LinearLayout
- android:layout_height="wrap_content"
- android:layout_width="match_parent"
- android:paddingBottom="9dp">
- <TextView
- android:id="@+id/google_terms_message"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_margin="0dp"
- android:layout_gravity="center"
- android:textAppearance="@style/TextAppearance.AssistantBlackCaption"
- android:text="@string/autofill_assistant_google_terms_description" />
- </LinearLayout>
- <Space android:layout_width="0dp" android:layout_height="18dp"/>
+ <include layout="@layout/autofill_assistant_onboarding_terms"/>
+
+ <!-- Some space between terms and onboarding buttons -->
+ <Space
+ android:id="@+id/terms_spacing_after"
+ android:layout_width="0dp"
+ android:layout_height="18dp"/>
</LinearLayout>
</ScrollView>
diff --git a/chromium/components/autofill_assistant/android/internal/java/res/layout/autofill_assistant_datetime.xml b/chromium/components/autofill_assistant/android/internal/java/res/layout/autofill_assistant_datetime.xml
deleted file mode 100644
index 9dd42a6bf62..00000000000
--- a/chromium/components/autofill_assistant/android/internal/java/res/layout/autofill_assistant_datetime.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2019 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. -->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="horizontal"
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
-
- <org.chromium.chrome.browser.autofill_assistant.user_data.AssistantVerticalExpander
- android:id="@+id/date_expander"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="0.5"
- android:layout_marginStart="@dimen/autofill_assistant_bottombar_horizontal_spacing"
- android:layout_marginEnd="@dimen/autofill_assistant_bottombar_horizontal_spacing">
- </org.chromium.chrome.browser.autofill_assistant.user_data.AssistantVerticalExpander>
-
- <org.chromium.chrome.browser.autofill_assistant.user_data.AssistantVerticalExpander
- android:id="@+id/time_expander"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="0.5"
- android:layout_marginStart="@dimen/autofill_assistant_bottombar_horizontal_spacing"
- android:layout_marginEnd="@dimen/autofill_assistant_bottombar_horizontal_spacing">
- </org.chromium.chrome.browser.autofill_assistant.user_data.AssistantVerticalExpander>
-</LinearLayout> \ No newline at end of file
diff --git a/chromium/components/autofill_assistant/android/internal/java/res/layout/autofill_assistant_form_counter.xml b/chromium/components/autofill_assistant/android/internal/java/res/layout/autofill_assistant_form_counter.xml
index 7ae0cf25c9e..0f46cf0e247 100644
--- a/chromium/components/autofill_assistant/android/internal/java/res/layout/autofill_assistant_form_counter.xml
+++ b/chromium/components/autofill_assistant/android/internal/java/res/layout/autofill_assistant_form_counter.xml
@@ -44,7 +44,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
- android:textAppearance="@style/TextAppearance.TextLarge.Blue"/>
+ android:textAppearance="@style/TextAppearance.TextLarge.Accent1"/>
<org.chromium.ui.widget.ChromeImageView
android:id="@+id/increase_button"
android:layout_width="@dimen/autofill_assistant_minimum_touch_target_size"
diff --git a/chromium/components/autofill_assistant/android/internal/java/res/layout/autofill_assistant_form_counter_input.xml b/chromium/components/autofill_assistant/android/internal/java/res/layout/autofill_assistant_form_counter_input.xml
index 5a5e321bbac..d8f1caa8116 100644
--- a/chromium/components/autofill_assistant/android/internal/java/res/layout/autofill_assistant_form_counter_input.xml
+++ b/chromium/components/autofill_assistant/android/internal/java/res/layout/autofill_assistant_form_counter_input.xml
@@ -34,12 +34,12 @@
android:id="@+id/expand_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:textAppearance="@style/TextAppearance.TextMedium.Blue"/>
+ android:textAppearance="@style/TextAppearance.TextMedium.Accent1"/>
<TextView
android:id="@+id/minimize_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:textAppearance="@style/TextAppearance.TextMedium.Blue"/>
+ android:textAppearance="@style/TextAppearance.TextMedium.Accent1"/>
<org.chromium.ui.widget.ChromeImageView
android:id="@+id/chevron"
android:layout_width="16dp"
diff --git a/chromium/components/autofill_assistant/android/internal/java/res/layout/autofill_assistant_onboarding_terms.xml b/chromium/components/autofill_assistant/android/internal/java/res/layout/autofill_assistant_onboarding_terms.xml
new file mode 100644
index 00000000000..c7f34b39fc8
--- /dev/null
+++ b/chromium/components/autofill_assistant/android/internal/java/res/layout/autofill_assistant_onboarding_terms.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2022 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. -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/onboarding_terms"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:paddingBottom="9dp">
+ <TextView
+ android:id="@+id/google_terms_message"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_margin="0dp"
+ android:layout_gravity="center"
+ android:textAppearance="@style/TextAppearance.AssistantBlackCaption"
+ android:text="@string/autofill_assistant_google_terms_description" />
+</LinearLayout> \ No newline at end of file
diff --git a/chromium/components/autofill_assistant/android/internal/java/res_poodle/drawable/ic_autofill_assistant_24dp.xml b/chromium/components/autofill_assistant/android/internal/java/res_poodle/drawable/ic_autofill_assistant_24dp.xml
index 1085685b1ba..d697ee89973 100644
--- a/chromium/components/autofill_assistant/android/internal/java/res_poodle/drawable/ic_autofill_assistant_24dp.xml
+++ b/chromium/components/autofill_assistant/android/internal/java/res_poodle/drawable/ic_autofill_assistant_24dp.xml
@@ -5,8 +5,6 @@
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- tools:targetApi="21"
android:width="24dp"
android:height="24dp"
android:viewportWidth="192"
diff --git a/chromium/components/autofill_assistant/android/internal/java/src/org/chromium/chrome/browser/autofill_assistant/header/AnimatedPoodle.java b/chromium/components/autofill_assistant/android/internal/java/src/org/chromium/chrome/browser/autofill_assistant/header/AnimatedPoodle.java
index 20aacf4e62b..b752174ae3e 100644
--- a/chromium/components/autofill_assistant/android/internal/java/src/org/chromium/chrome/browser/autofill_assistant/header/AnimatedPoodle.java
+++ b/chromium/components/autofill_assistant/android/internal/java/src/org/chromium/chrome/browser/autofill_assistant/header/AnimatedPoodle.java
@@ -11,7 +11,7 @@ import android.widget.ImageView;
import androidx.appcompat.content.res.AppCompatResources;
-import org.chromium.chrome.autofill_assistant.poodle.R;
+import org.chromium.chrome.autofill_assistant.common.R;
/**
* Represents a poodle that can be animated. This default implementation is a static poodle, the
@@ -48,4 +48,4 @@ import org.chromium.chrome.autofill_assistant.poodle.R;
/* package */ void setSpinEnabled(boolean enabled) {
// Do nothing.
}
-} \ No newline at end of file
+}
diff --git a/chromium/components/autofill_assistant/android/internal/java/strings/translations/android_chrome_autofill_assistant_strings_de.xtb b/chromium/components/autofill_assistant/android/internal/java/strings/translations/android_chrome_autofill_assistant_strings_de.xtb
index 2ff2ee06469..88e81a958fd 100644
--- a/chromium/components/autofill_assistant/android/internal/java/strings/translations/android_chrome_autofill_assistant_strings_de.xtb
+++ b/chromium/components/autofill_assistant/android/internal/java/strings/translations/android_chrome_autofill_assistant_strings_de.xtb
@@ -3,7 +3,7 @@
<translationbundle lang="de">
<translation id="1625889395409731085">Externen Link öffnen?</translation>
<translation id="1699570257714336246">Fehlende Informationen</translation>
-<translation id="1932278019417741381">Wenn Sie in Chrome mit Assistant Aufgaben erledigen, werden die URLs und Inhalte der Websites, auf denen Sie Assistant verwenden, sowie die Daten, die Sie über Assistant weitergeben, an Google gesendet. Diese Informationen werden unter Umständen in Ihrem Google-Konto gespeichert. Sie können Assistant in den Einstellungen von Chrome deaktivieren. <ph name="BEGIN_LINK" />Weitere Informationen<ph name="END_LINK" /></translation>
+<translation id="1932278019417741381">Wenn du in Chrome mit Assistant Aufgaben erledigst, werden die URLs und Inhalte der Websites, auf denen du Assistant verwendest, sowie die Daten, die du über Assistant weitergibst, an Google gesendet. Diese Informationen werden unter Umständen in deinem Google-Konto gespeichert. Du kannst Assistant in den Einstellungen von Chrome deaktivieren. <ph name="BEGIN_LINK" />Weitere Informationen<ph name="END_LINK" /></translation>
<translation id="2203046366315513658">Wert verringern</translation>
<translation id="2581111578809745440">Schnelles Bezahlen\nmit nur wenigen Fingertipps</translation>
<translation id="3018033505440165876">Google Assistant\nin Chrome ausprobieren</translation>
@@ -11,16 +11,16 @@
<translation id="4437727785356380473">Google Assistant für Chrome geschlossen.</translation>
<translation id="4517854969512651305">Wert erhöhen</translation>
<translation id="4850886885716139402">Anzeigen</translation>
-<translation id="4952448020231702394">Mit Google Assistant sparen Sie Zeit bei Aktionen im Web, z. B. bei der Suche oder beim Bezahlen.</translation>
+<translation id="4952448020231702394">Mit Google Assistant sparst du Zeit bei Aktionen im Web, z. B. bei der Suche oder beim Bezahlen.</translation>
<translation id="4982366513646093083">Ganz einfach\nEssen bestellen</translation>
<translation id="5267269112080050255">Google Assistant für Chrome in voller Höhe geöffnet.</translation>
<translation id="5447168050208292829">Ganz einfach\nfür einen Flug einchecken</translation>
<translation id="5801568494490449797">Einstellungen</translation>
<translation id="6555233628095991027">Google Assistant für Chrome mit halber Höhe geöffnet.</translation>
-<translation id="6785872064505734160">Google Assistant kann in Chrome Aktionen auf Websites für Sie durchführen.</translation>
-<translation id="6973932557599545801">Ich kann Ihnen leider nicht helfen. Bitte fahren Sie alleine fort.</translation>
+<translation id="6785872064505734160">Google Assistant kann in Chrome Aktionen auf Websites für dich durchführen.</translation>
+<translation id="6973932557599545801">Ich kann dir leider nicht helfen. Bitte fahre alleine fort.</translation>
<translation id="7135664311366978968">Ganz einfach\nKinokarten kaufen</translation>
-<translation id="7455021968451468078">Google Assistant kann Ihnen helfen,\nIhr Passwort zu ändern</translation>
+<translation id="7455021968451468078">Google Assistant kann dir helfen,\ndein Passwort zu ändern</translation>
<translation id="7658239707568436148">Abbrechen</translation>
<translation id="7953600313732929223">Sprachbefehle\nauf Websites ausprobieren</translation>
<translation id="8253702004019660079">Google Assistant für Chrome.</translation>
diff --git a/chromium/components/autofill_assistant/android/internal/java/strings/translations/android_chrome_autofill_assistant_strings_es.xtb b/chromium/components/autofill_assistant/android/internal/java/strings/translations/android_chrome_autofill_assistant_strings_es.xtb
index 1a355aed09d..f631b3f08c2 100644
--- a/chromium/components/autofill_assistant/android/internal/java/strings/translations/android_chrome_autofill_assistant_strings_es.xtb
+++ b/chromium/components/autofill_assistant/android/internal/java/strings/translations/android_chrome_autofill_assistant_strings_es.xtb
@@ -13,7 +13,7 @@
<translation id="4850886885716139402">Ver</translation>
<translation id="4952448020231702394">El Asistente de Google te permite ahorrar tiempo, ya que te ayuda a realizar en la Web tareas como buscar o pagar.</translation>
<translation id="4982366513646093083">Pide comida\ncon solo unos toques</translation>
-<translation id="5267269112080050255">Se ha abierto el Asistente de Google en Chrome para que ocupe toda la pantalla.</translation>
+<translation id="5267269112080050255">Se ha abierto el Asistente de Google en Chrome a altura completa.</translation>
<translation id="5447168050208292829">Haz el check‑in de tu vuelo\ncon solo unos toques</translation>
<translation id="5801568494490449797">Preferencias</translation>
<translation id="6555233628095991027">Se ha abierto el Asistente de Google en Chrome a media altura.</translation>
diff --git a/chromium/components/autofill_assistant/android/internal/java/strings/translations/android_chrome_autofill_assistant_strings_kn.xtb b/chromium/components/autofill_assistant/android/internal/java/strings/translations/android_chrome_autofill_assistant_strings_kn.xtb
index 9eda759d566..f0d56210295 100644
--- a/chromium/components/autofill_assistant/android/internal/java/strings/translations/android_chrome_autofill_assistant_strings_kn.xtb
+++ b/chromium/components/autofill_assistant/android/internal/java/strings/translations/android_chrome_autofill_assistant_strings_kn.xtb
@@ -3,27 +3,27 @@
<translationbundle lang="kn">
<translation id="1625889395409731085">ಬಾಹà³à²¯ ಲಿಂಕೠತೆರೆಯà³à²µà³à²¦à³‡?</translation>
<translation id="1699570257714336246">ಮಾಹಿತಿ ಕಾಣೆಯಾಗಿದೆ</translation>
-<translation id="1932278019417741381">ಕಾರà³à²¯à²—ಳನà³à²¨à³ ಪೂರà³à²£à²—ೊಳಿಸà³à²µà³à²¦à²•à³à²•à³† ನಿಮಗೆ ಸಹಾಯ ಮಾಡಲà³, ನೀವೠಅಸಿಸà³à²Ÿà³†à²‚ಟೠಅನà³à²¨à³ ಬಳಸಿದ ಸೈಟà³â€Œà²—ಳ URL ಗಳೠಮತà³à²¤à³ ವಿಷಯಗಳೠಹಾಗೂ ಅಸಿಸà³à²Ÿà³†à²‚ಟೠಮೂಲಕ ನೀವೠಸಲà³à²²à²¿à²¸à²¿à²¦ ಮಾಹಿತಿಯನà³à²¨à³ Google ಸà³à²µà³€à²•à²°à²¿à²¸à³à²¤à³à²¤à²¦à³†. ಈ ಮಾಹಿತಿಯನà³à²¨à³ Google ಖಾತೆಯಲà³à²²à²¿ ಸಂಗà³à²°à²¹à²¿à²¸à²¿à²°à²¬à²¹à³à²¦à³. ಅಸಿಸà³à²Ÿà³†à²‚ಟೠಅನà³à²¨à³ Chrome ಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳಲà³à²²à²¿ ಆಫೠಮಾಡಬಹà³à²¦à³. <ph name="BEGIN_LINK" />ಇನà³à²¨à²·à³à²Ÿà³ ತಿಳಿಯಿರಿ<ph name="END_LINK" /></translation>
+<translation id="1932278019417741381">ಕಾರà³à²¯à²—ಳನà³à²¨à³ ಪೂರà³à²£à²—ೊಳಿಸà³à²µà³à²¦à²•à³à²•à³† ನಿಮಗೆ ಸಹಾಯ ಮಾಡಲà³, ನೀವೠAssistant ಅನà³à²¨à³ ಬಳಸಿದ ಸೈಟà³â€Œà²—ಳ URL ಗಳೠಮತà³à²¤à³ ವಿಷಯಗಳೠಹಾಗೂ Assistant ಮೂಲಕ ನೀವೠಸಲà³à²²à²¿à²¸à²¿à²¦ ಮಾಹಿತಿಯನà³à²¨à³ Google ಸà³à²µà³€à²•à²°à²¿à²¸à³à²¤à³à²¤à²¦à³†. ಈ ಮಾಹಿತಿಯನà³à²¨à³ Google ಖಾತೆಯಲà³à²²à²¿ ಸಂಗà³à²°à²¹à²¿à²¸à²¿à²°à²¬à²¹à³à²¦à³. Assistant ಅನà³à²¨à³ Chrome ಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳಲà³à²²à²¿ ಆಫೠಮಾಡಬಹà³à²¦à³. <ph name="BEGIN_LINK" />ಇನà³à²¨à²·à³à²Ÿà³ ತಿಳಿಯಿರಿ<ph name="END_LINK" /></translation>
<translation id="2203046366315513658">ಮೌಲà³à²¯à²µà²¨à³à²¨à³ ಕಡಿಮೆ ಮಾಡಿ</translation>
<translation id="2581111578809745440">ಕೆಲವೇ ಟà³à²¯à²¾à²ªà³â€Œà²—ಳಲà³à²²à²¿\nವೇಗವಾದ ಚೆಕà³â€Œà²”ಟà³</translation>
<translation id="3018033505440165876">Chrome ನಲà³à²²à²¿\nGoogle Assistant ಬಳಸಿ ನೋಡಿ</translation>
<translation id="4130750466177569591">ನಾನೠಒಪà³à²ªà³à²¤à³à²¤à³‡à²¨à³†</translation>
-<translation id="4437727785356380473">Chrome ನಲà³à²²à²¿ Google ಅಸಿಸà³à²Ÿà³†à²‚ಟೠಅನà³à²¨à³ ಮà³à²šà³à²šà²²à²¾à²—ಿದೆ.</translation>
+<translation id="4437727785356380473">Chrome ನಲà³à²²à²¿ Google Assistant ಅನà³à²¨à³ ಮà³à²šà³à²šà²²à²¾à²—ಿದೆ.</translation>
<translation id="4517854969512651305">ಮೌಲà³à²¯à²µà²¨à³à²¨à³ ಹೆಚà³à²šà²¿à²¸à²¿</translation>
<translation id="4850886885716139402">ವೀಕà³à²·à²£à³†</translation>
-<translation id="4952448020231702394">ಹà³à²¡à³à²•à²¾à²Ÿ ಮತà³à²¤à³ ಚೆಕà³â€Œ ಔಟà³â€Œà²¨à²‚ತಹ ವೆಬà³â€Œà²¨à²²à³à²²à²¿à²¨ ಕà³à²°à²¿à²¯à³†à²—ಳನà³à²¨à³ ಪೂರà³à²£à²—ೊಳಿಸಲೠನಿಮಗೆ ಸಹಾಯ ಮಾಡà³à²µ ಮೂಲಕ Google ಅಸಿಸà³à²Ÿà³†à²‚ಟೠನಿಮà³à²® ಸಮಯವನà³à²¨à³ ಉಳಿಸà³à²¤à³à²¤à²¦à³†.</translation>
+<translation id="4952448020231702394">ಹà³à²¡à³à²•à²¾à²Ÿ ಮತà³à²¤à³ ಚೆಕà³â€Œ ಔಟà³â€Œà²¨à²‚ತಹ ವೆಬà³â€Œà²¨à²²à³à²²à²¿à²¨ ಕà³à²°à²¿à²¯à³†à²—ಳನà³à²¨à³ ಪೂರà³à²£à²—ೊಳಿಸಲೠನಿಮಗೆ ಸಹಾಯ ಮಾಡà³à²µ ಮೂಲಕ Google Assistant ನಿಮà³à²® ಸಮಯವನà³à²¨à³ ಉಳಿಸà³à²¤à³à²¤à²¦à³†.</translation>
<translation id="4982366513646093083">ಕೆಲವೇ ಟà³à²¯à²¾à²ªà³â€Œà²—ಳ ಮೂಲಕ\nಆಹಾರವನà³à²¨à³ ಆರà³à²¡à²°à³ ಮಾಡಿ</translation>
-<translation id="5267269112080050255">Chrome ನಲà³à²²à²¿ Google ಅಸಿಸà³à²Ÿà³†à²‚ಟೠಅನà³à²¨à³ ಪೂರà³à²£ ಎತà³à²¤à²°à²¦à²²à³à²²à²¿ ತೆರೆಯಲಾಗಿದೆ.</translation>
+<translation id="5267269112080050255">Chrome ನಲà³à²²à²¿ Google Assistant ಅನà³à²¨à³ ಪೂರà³à²£ ಎತà³à²¤à²°à²¦à²²à³à²²à²¿ ತೆರೆಯಲಾಗಿದೆ.</translation>
<translation id="5447168050208292829">ಕೆಲವೇ ಟà³à²¯à²¾à²ªà³â€Œà²—ಳ ಮೂಲಕ\nನಿಮà³à²® ಫà³à²²à³ˆà²Ÿà³â€Œà²—ಳ ಕà³à²°à²¿à²¤à³ ಪರಿಶೀಲಿಸಿ</translation>
<translation id="5801568494490449797">ಪà³à²°à²¾à²¶à²¸à³à²¤à³à²¯à²—ಳà³</translation>
-<translation id="6555233628095991027">Chrome ನಲà³à²²à²¿ Google ಅಸಿಸà³à²Ÿà³†à²‚ಟೠಅನà³à²¨à³ ಅರà³à²§ ಎತà³à²¤à²°à²¦à²²à³à²²à²¿ ತೆರೆಯಲಾಗಿದೆ.</translation>
+<translation id="6555233628095991027">Chrome ನಲà³à²²à²¿ Google Assistant ಅನà³à²¨à³ ಅರà³à²§ ಎತà³à²¤à²°à²¦à²²à³à²²à²¿ ತೆರೆಯಲಾಗಿದೆ.</translation>
<translation id="6785872064505734160">Chrome ನಲà³à²²à²¿à²°à³à²µ Google Assistant, ನಿಮಗಾಗಿ ವೆಬà³â€Œà²¸à³ˆà²Ÿà³â€Œà²—ಳಾದà³à²¯à²‚ತದ ಕà³à²°à²¿à²¯à³†à²—ಳನà³à²¨à³ ಪೂರà³à²£à²—ೊಳಿಸಬಲà³à²²à²¦à³</translation>
<translation id="6973932557599545801">ಕà³à²·à²®à²¿à²¸à²¿, ನನà³à²¨à²¿à²‚ದ ಸಹಾಯ ಮಾಡಲೠಸಾಧà³à²¯à²µà²¾à²—à³à²¤à³à²¤à²¿à²²à³à²², ನಿಮà³à²® ವಿವೇಚನೆಗೆ ತಕà³à²•à²‚ತೆ ಮà³à²‚ದà³à²µà²°à²¿à²¸à²¿.</translation>
<translation id="7135664311366978968">ಕೆಲವೇ ಟà³à²¯à²¾à²ªà³â€Œà²—ಳ ಮೂಲಕ\nಚಲನಚಿತà³à²° ಟಿಕೆಟà³â€Œà²—ಳನà³à²¨à³ ಖರೀದಿಸಿ</translation>
<translation id="7455021968451468078">ನಿಮà³à²® ಪಾಸà³â€Œà²µà²°à³à²¡à³ ಅನà³à²¨à³ ಬದಲಾಯಿಸà³à²µà³à²¦à²•à³à²•à²¾à²—ಿ\nನಿಮಗೆ ಸಹಾಯ ಮಾಡಲೠGoogle Assistant ಗೆ ಅನà³à²®à²¤à²¿ ನೀಡಿ</translation>
<translation id="7658239707568436148">ರದà³à²¦à³à²®à²¾à²¡à²¿</translation>
<translation id="7953600313732929223">ವೆಬà³â€Œà²¸à³ˆà²Ÿà³â€Œà²—ಳಲà³à²²à²¿\nಧà³à²µà²¨à²¿ ಕà³à²°à²¿à²¯à³†à²—ಳನà³à²¨à³ ಬಳಸಿ ನೋಡಿ</translation>
-<translation id="8253702004019660079">Chrome ನಲà³à²²à²¿ Google ಅಸಿಸà³à²Ÿà³†à²‚ಟà³.</translation>
+<translation id="8253702004019660079">Chrome ನಲà³à²²à²¿ Google Assistant.</translation>
<translation id="8500511870202433545">ಕೆಲವೇ ಟà³à²¯à²¾à²ªà³â€Œà²—ಳ ಮೂಲಕ\nಕಾರನà³à²¨à³ ಬಾಡಿಗೆಗೆ ಪಡೆಯಿರಿ</translation>
<translation id="945522503751344254">ಪà³à²°à²¤à²¿à²•à³à²°à²¿à²¯à³†à²¯à²¨à³à²¨à³ ಕಳà³à²¹à²¿à²¸à²¿</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/autofill_assistant/android/internal/java/strings/translations/android_chrome_autofill_assistant_strings_pt-BR.xtb b/chromium/components/autofill_assistant/android/internal/java/strings/translations/android_chrome_autofill_assistant_strings_pt-BR.xtb
index 98a858727dd..9ec5480ea6e 100644
--- a/chromium/components/autofill_assistant/android/internal/java/strings/translations/android_chrome_autofill_assistant_strings_pt-BR.xtb
+++ b/chromium/components/autofill_assistant/android/internal/java/strings/translations/android_chrome_autofill_assistant_strings_pt-BR.xtb
@@ -10,7 +10,7 @@
<translation id="4130750466177569591">Aceito</translation>
<translation id="4437727785356380473">Google Assistente no Chrome fechado.</translation>
<translation id="4517854969512651305">Aumentar valor</translation>
-<translation id="4850886885716139402">Visualizar</translation>
+<translation id="4850886885716139402">Ver</translation>
<translation id="4952448020231702394">O Google Assistente economiza seu tempo ao ajudar você a realizar ações na Web, como pesquisas e finalizações de compra.</translation>
<translation id="4982366513646093083">Peça comida\ncom apenas alguns toques</translation>
<translation id="5267269112080050255">Google Assistente no Chrome aberto no tamanho máximo.</translation>
diff --git a/chromium/components/autofill_assistant/browser/BUILD.gn b/chromium/components/autofill_assistant/browser/BUILD.gn
index ea05f0fccb4..7aee48a5b9c 100644
--- a/chromium/components/autofill_assistant/browser/BUILD.gn
+++ b/chromium/components/autofill_assistant/browser/BUILD.gn
@@ -21,6 +21,10 @@ proto_library("proto") {
]
}
+proto_library("test_proto") {
+ sources = [ "parse_jspb_test.proto" ]
+}
+
static_library("browser") {
sources = [
"actions/action.cc",
@@ -46,6 +50,8 @@ static_library("browser") {
"actions/dispatch_js_event_action.h",
"actions/edit_password_action.cc",
"actions/edit_password_action.h",
+ "actions/execute_js_action.cc",
+ "actions/execute_js_action.h",
"actions/expect_navigation_action.cc",
"actions/expect_navigation_action.h",
"actions/fallback_handler/required_field.cc",
@@ -118,6 +124,9 @@ static_library("browser") {
"actions/wait_for_dom_action.h",
"actions/wait_for_navigation_action.cc",
"actions/wait_for_navigation_action.h",
+ "autofill_assistant_factory.cc",
+ "autofill_assistant_impl.cc",
+ "autofill_assistant_impl.h",
"autofill_assistant_onboarding_fetcher.cc",
"autofill_assistant_onboarding_fetcher.h",
"autofill_assistant_tts_controller.cc",
@@ -151,10 +160,9 @@ static_library("browser") {
"display_strings_util.h",
"element_area.cc",
"element_area.h",
- "element_precondition.cc",
- "element_precondition.h",
"event_handler.cc",
"event_handler.h",
+ "execution_delegate.h",
"features.cc",
"features.h",
"field_formatter.cc",
@@ -168,12 +176,15 @@ static_library("browser") {
"info_box.h",
"intent_strings.cc",
"intent_strings.h",
- "js_flow_executor.cc",
"js_flow_executor.h",
+ "js_flow_executor_impl.cc",
+ "js_flow_executor_impl.h",
"metrics.cc",
"metrics.h",
"onboarding_result.h",
"overlay_state.h",
+ "parse_jspb.cc",
+ "parse_jspb.h",
"protocol_utils.cc",
"protocol_utils.h",
"radio_button_controller.cc",
@@ -187,6 +198,7 @@ static_library("browser") {
"script_executor.cc",
"script_executor.h",
"script_executor_delegate.h",
+ "script_executor_ui_delegate.h",
"script_parameters.cc",
"script_parameters.h",
"script_precondition.cc",
@@ -200,6 +212,10 @@ static_library("browser") {
"service/api_key_fetcher.h",
"service/cup.cc",
"service/cup.h",
+ "service/cup_factory.cc",
+ "service/cup_factory.h",
+ "service/cup_impl.cc",
+ "service/cup_impl.h",
"service/rpc_type.h",
"service/server_url_fetcher.cc",
"service/server_url_fetcher.h",
@@ -241,6 +257,10 @@ static_library("browser") {
"trigger_scripts/trigger_script_coordinator.cc",
"trigger_scripts/trigger_script_coordinator.h",
"tts_button_state.h",
+ "ui_controller.cc",
+ "ui_controller.h",
+ "ui_controller_observer.cc",
+ "ui_controller_observer.h",
"ui_delegate.h",
"url_utils.cc",
"url_utils.h",
@@ -274,10 +294,15 @@ static_library("browser") {
"web/element_rect_getter.h",
"web/element_store.cc",
"web/element_store.h",
+ "web/js_filter_builder.cc",
+ "web/js_filter_builder.h",
"web/js_snippets.cc",
"web/js_snippets.h",
"web/keyboard_input_data.cc",
"web/keyboard_input_data.h",
+ "web/selector_observer.cc",
+ "web/selector_observer.h",
+ "web/selector_observer_script.h",
"web/send_keyboard_input_worker.cc",
"web/send_keyboard_input_worker.h",
"web/web_controller.cc",
@@ -301,6 +326,8 @@ static_library("browser") {
"//components/autofill_assistant/browser/devtools",
"//components/autofill_assistant/browser/public:public",
"//components/autofill_assistant/content/browser",
+ "//components/autofill_assistant/content/common",
+ "//components/autofill_assistant/content/common:mojo_interfaces",
"//components/client_update_protocol",
"//components/google/core/common:common",
"//components/keyed_service/core",
@@ -328,6 +355,8 @@ static_library("unit_test_support") {
"actions/mock_action_delegate.h",
"fake_script_executor_delegate.cc",
"fake_script_executor_delegate.h",
+ "fake_script_executor_ui_delegate.cc",
+ "fake_script_executor_ui_delegate.h",
"fake_starter_platform_delegate.cc",
"fake_starter_platform_delegate.h",
"mock_autofill_assistant_tts_controller.cc",
@@ -336,8 +365,12 @@ static_library("unit_test_support") {
"mock_client.h",
"mock_controller_observer.cc",
"mock_controller_observer.h",
+ "mock_execution_delegate.cc",
+ "mock_execution_delegate.h",
"mock_personal_data_manager.cc",
"mock_personal_data_manager.h",
+ "mock_ui_controller_observer.cc",
+ "mock_ui_controller_observer.h",
"mock_user_model_observer.cc",
"mock_user_model_observer.h",
"mock_website_login_manager.cc",
@@ -356,6 +389,7 @@ static_library("unit_test_support") {
"//base",
"//base/test:test_support",
"//components/autofill/core/browser:test_support",
+ "//components/password_manager/core/browser:browser",
"//components/version_info",
"//testing/gmock",
"//testing/gtest",
@@ -377,10 +411,13 @@ source_set("unit_tests") {
"actions/delete_password_action_unittest.cc",
"actions/dispatch_js_event_action_unittest.cc",
"actions/edit_password_action_unittest.cc",
+ "actions/execute_js_action_unittest.cc",
+ "actions/expect_navigation_action_unittest.cc",
"actions/fallback_handler/required_field_unittest.cc",
"actions/fallback_handler/required_fields_fallback_handler_unittest.cc",
"actions/generate_password_for_form_field_action_unittest.cc",
"actions/get_element_status_action_unittest.cc",
+ "actions/navigate_action_unittest.cc",
"actions/perform_on_single_element_action_unittest.cc",
"actions/popup_message_action_unittest.cc",
"actions/presave_generated_password_action_unittest.cc",
@@ -408,6 +445,8 @@ source_set("unit_tests") {
"actions/use_credit_card_action_unittest.cc",
"actions/wait_for_document_action_unittest.cc",
"actions/wait_for_dom_action_unittest.cc",
+ "actions/wait_for_navigation_action_unittest.cc",
+ "autofill_assistant_impl_unittest.cc",
"autofill_assistant_onboarding_fetcher_unittest.cc",
"autofill_assistant_tts_controller_unittest.cc",
"basic_interactions_unittest.cc",
@@ -418,13 +457,13 @@ source_set("unit_tests") {
"details_unittest.cc",
"display_strings_util_unittest.cc",
"element_area_unittest.cc",
- "element_precondition_unittest.cc",
"event_handler_unittest.cc",
"field_formatter_unittest.cc",
"full_card_requester_unittest.cc",
"generic_ui_replace_placeholders_unittest.cc",
"mock_client_context.cc",
"mock_client_context.h",
+ "parse_jspb_unittest.cc",
"protocol_utils_unittest.cc",
"radio_button_controller_unittest.cc",
"retry_timer_unittest.cc",
@@ -434,9 +473,13 @@ source_set("unit_tests") {
"script_tracker_unittest.cc",
"selector_unittest.cc",
"service/api_key_fetcher_unittest.cc",
+ "service/cup_factory_unittest.cc",
+ "service/cup_impl_unittest.cc",
"service/cup_unittest.cc",
"service/mock_access_token_fetcher.cc",
"service/mock_access_token_fetcher.h",
+ "service/mock_cup.cc",
+ "service/mock_cup.h",
"service/mock_service_request_sender.cc",
"service/mock_service_request_sender.h",
"service/mock_simple_url_loader_factory.cc",
@@ -464,6 +507,7 @@ source_set("unit_tests") {
"trigger_scripts/static_trigger_conditions_unittest.cc",
"trigger_scripts/trigger_script_coordinator_unittest.cc",
"trigger_scripts/trigger_script_unittest.cc",
+ "ui_controller_unittest.cc",
"ukm_test_util.cc",
"ukm_test_util.h",
"url_utils_unittest.cc",
@@ -480,6 +524,7 @@ source_set("unit_tests") {
deps = [
":browser",
":proto",
+ ":test_proto",
":unit_test_support",
"//base",
"//base/test:test_support",
diff --git a/chromium/components/autofill_assistant/browser/DEPS b/chromium/components/autofill_assistant/browser/DEPS
index 181aa070229..db59c99f888 100644
--- a/chromium/components/autofill_assistant/browser/DEPS
+++ b/chromium/components/autofill_assistant/browser/DEPS
@@ -17,11 +17,13 @@ include_rules = [
"+components/strings/grit/components_strings.h",
"+crypto",
"+google_apis",
+ "+mojo/public/cpp/bindings",
"+net",
"+services/metrics/public",
"+services/network/public/cpp",
"+services/network/public/mojom",
"+services/network/test",
+ "+third_party/blink/public/common",
"+third_party/blink/public/common/switches.h",
"+third_party/blink/public/mojom/payments/payment_request.mojom.h",
"+third_party/icu/source/common/unicode",
diff --git a/chromium/components/autofill_assistant/browser/actions/action.cc b/chromium/components/autofill_assistant/browser/actions/action.cc
index 30523f89d93..322caacf17d 100644
--- a/chromium/components/autofill_assistant/browser/actions/action.cc
+++ b/chromium/components/autofill_assistant/browser/actions/action.cc
@@ -262,6 +262,9 @@ std::ostream& operator<<(std::ostream& out,
case ActionProto::ActionInfoCase::kSaveSubmittedPassword:
out << "SaveSubmittedPassword";
break;
+ case ActionProto::ActionInfoCase::kExecuteJs:
+ out << "ExecuteJs";
+ break;
case ActionProto::ActionInfoCase::ACTION_INFO_NOT_SET:
out << "ACTION_INFO_NOT_SET";
break;
diff --git a/chromium/components/autofill_assistant/browser/actions/action_delegate.h b/chromium/components/autofill_assistant/browser/actions/action_delegate.h
index b1c049fcca4..a5e77e3346e 100644
--- a/chromium/components/autofill_assistant/browser/actions/action_delegate.h
+++ b/chromium/components/autofill_assistant/browser/actions/action_delegate.h
@@ -35,6 +35,10 @@ struct FormFieldData;
class PersonalDataManager;
} // namespace autofill
+namespace password_manager {
+class PasswordChangeSuccessTracker;
+}
+
namespace content {
class WebContents;
} // namespace content
@@ -116,6 +120,7 @@ class ActionDelegate {
// If |allow_interrupt| interrupts can run while waiting.
virtual void WaitForDom(
base::TimeDelta max_wait_time,
+ bool allow_observer_mode,
bool allow_interrupt,
WaitForDomObserver* observer,
base::RepeatingCallback<
@@ -271,9 +276,13 @@ class ActionDelegate {
// Get current personal data manager.
virtual autofill::PersonalDataManager* GetPersonalDataManager() const = 0;
- // Get current login fetcher.
+ // Get current login manager.
virtual WebsiteLoginManager* GetWebsiteLoginManager() const = 0;
+ // Get current password change success tracker.
+ virtual password_manager::PasswordChangeSuccessTracker*
+ GetPasswordChangeSuccessTracker() const = 0;
+
// Get associated web contents.
virtual content::WebContents* GetWebContents() const = 0;
diff --git a/chromium/components/autofill_assistant/browser/actions/action_delegate_util.cc b/chromium/components/autofill_assistant/browser/actions/action_delegate_util.cc
index 93eff1aa9c7..fc923a28f16 100644
--- a/chromium/components/autofill_assistant/browser/actions/action_delegate_util.cc
+++ b/chromium/components/autofill_assistant/browser/actions/action_delegate_util.cc
@@ -186,7 +186,7 @@ void AddOptionalStep(OptionalStep optional_step,
switch (optional_step) {
case STEP_UNSPECIFIED:
NOTREACHED() << __func__ << " unspecified optional_step";
- FALLTHROUGH;
+ [[fallthrough]];
case SKIP_STEP:
break;
diff --git a/chromium/components/autofill_assistant/browser/actions/collect_user_data_action.cc b/chromium/components/autofill_assistant/browser/actions/collect_user_data_action.cc
index d476bada693..9c9c251d45b 100644
--- a/chromium/components/autofill_assistant/browser/actions/collect_user_data_action.cc
+++ b/chromium/components/autofill_assistant/browser/actions/collect_user_data_action.cc
@@ -82,7 +82,6 @@ bool OnlyLoginRequested(
!collect_user_data_options.request_payer_phone &&
!collect_user_data_options.request_shipping &&
!collect_user_data_options.request_payment_method &&
- !collect_user_data_options.request_date_time_range &&
collect_user_data_options.accept_terms_and_conditions_text.empty() &&
!collect_user_data_options.additional_model_identifier_to_check
.has_value();
@@ -102,69 +101,6 @@ bool IsValidTermsChoice(
terms_state != TermsAndConditionsState::NOT_SELECTED;
}
-// Checks |proto| and writes an error message to |error| if fields are missing.
-bool IsValidDateTimeRangeProto(
- const autofill_assistant::DateTimeRangeProto& proto,
- std::string* error) {
- std::vector<std::string> missing_fields;
- if (proto.start_date_label().empty())
- missing_fields.emplace_back("start_date_label");
- if (proto.start_time_label().empty())
- missing_fields.emplace_back("start_time_label");
- if (proto.end_date_label().empty())
- missing_fields.emplace_back("end_date_label");
- if (proto.end_time_label().empty())
- missing_fields.emplace_back("end_time_label");
- if (!proto.has_start_date())
- missing_fields.emplace_back("start_date");
- if (!proto.has_start_time_slot())
- missing_fields.emplace_back("start_time_slot");
- if (!proto.has_end_date())
- missing_fields.emplace_back("end_date");
- if (!proto.has_end_time_slot())
- missing_fields.emplace_back("end_time_slot");
- if (!proto.has_min_date())
- missing_fields.emplace_back("min_date");
- if (!proto.has_max_date())
- missing_fields.emplace_back("max_date");
- if (proto.time_slots().empty())
- missing_fields.emplace_back("time_slots");
- if (proto.date_not_set_error().empty())
- missing_fields.emplace_back("date_not_set_error");
- if (proto.time_not_set_error().empty())
- missing_fields.emplace_back("time_not_set_error");
-
- if (error != nullptr && !missing_fields.empty()) {
- error->assign("The following fields are missing or empty: ");
- error->append(base::JoinString(missing_fields, ", "));
- }
-
- return missing_fields.empty();
-}
-
-bool IsValidDateTimeRange(
- const absl::optional<autofill_assistant::DateProto>& start_date,
- const absl::optional<int> start_timeslot,
- const absl::optional<autofill_assistant::DateProto> end_date,
- const absl::optional<int> end_timeslot,
- const CollectUserDataOptions& collect_user_data_options) {
- if (!collect_user_data_options.request_date_time_range) {
- return true;
- }
- if (!start_date.has_value() || !start_timeslot.has_value() ||
- !end_date.has_value() || !end_timeslot.has_value()) {
- return false;
- }
-
- auto temp_start_date = start_date;
- auto temp_start_timeslot = start_timeslot;
- auto temp_end_date = end_date;
- auto temp_end_timeslot = end_timeslot;
- return !autofill_assistant::CollectUserDataAction::SanitizeDateTimeRange(
- &temp_start_date, &temp_start_timeslot, &temp_end_date,
- &temp_end_timeslot, collect_user_data_options, false);
-}
-
bool IsValidUserFormSection(
const autofill_assistant::UserFormSectionProto& proto) {
if (proto.title().empty()) {
@@ -396,19 +332,60 @@ bool RequiresAddress(const CollectUserDataOptions& collect_user_data_options) {
RequiresPaymentMethod(collect_user_data_options);
}
+bool RequiresPhoneNumberSeparately(
+ const CollectUserDataOptions& collect_user_data_options) {
+ return collect_user_data_options.request_phone_number_separately;
+}
+
+void AddAutofillEntryToDataModel(autofill::ServerFieldType type,
+ AutofillEntryProto entry,
+ const std::string& locale,
+ autofill::AutofillDataModel* model) {
+ if (entry.raw()) {
+ model->SetRawInfo(type, base::UTF8ToUTF16(entry.value()));
+ } else {
+ model->SetInfo(type, base::UTF8ToUTF16(entry.value()), locale);
+ }
+}
+
void AddProtoDataToAutofillDataModel(
const google::protobuf::Map<int32_t, AutofillEntryProto>& data,
const std::string& locale,
autofill::AutofillDataModel* model) {
for (const auto& it : data) {
- if (it.second.raw()) {
- model->SetRawInfo(static_cast<autofill::ServerFieldType>(it.first),
- base::UTF8ToUTF16(it.second.value()));
- } else {
- model->SetInfo(static_cast<autofill::ServerFieldType>(it.first),
- base::UTF8ToUTF16(it.second.value()), locale);
- }
+ AddAutofillEntryToDataModel(
+ static_cast<autofill::ServerFieldType>(it.first), it.second, locale,
+ model);
+ }
+}
+
+void MergePhoneNumberIntoSelectedContact(
+ UserData* user_data,
+ UserModel* user_model,
+ const CollectUserDataOptions& options,
+ const CollectUserDataProto::UserDataProto& proto_data) {
+ if (!user_data->selected_phone_number()) {
+ return;
+ }
+
+ // If there is no selected contact, we create a new one populated with the
+ // phone number.
+ if (!user_data->selected_address(options.contact_details_name)) {
+ user_model->SetSelectedAutofillProfile(
+ options.contact_details_name,
+ user_data::MakeUniqueFromProfile(*user_data->selected_phone_number()),
+ user_data);
+ return;
}
+
+ auto selected_phone_number = user_data->selected_phone_number()->GetRawInfo(
+ autofill::ServerFieldType::PHONE_HOME_WHOLE_NUMBER);
+ auto selected_contact = user_data::MakeUniqueFromProfile(
+ *user_data->selected_address(options.contact_details_name));
+ selected_contact->SetInfo(autofill::ServerFieldType::PHONE_HOME_WHOLE_NUMBER,
+ selected_phone_number, proto_data.locale());
+ user_model->SetSelectedAutofillProfile(
+ options.contact_details_name, std::move(selected_contact), user_data);
}
} // namespace
@@ -416,18 +393,22 @@ void AddProtoDataToAutofillDataModel(
CollectUserDataAction::LoginDetails::LoginDetails(
bool _choose_automatically_if_no_stored_login,
const std::string& _payload,
+ const std::string& _tag,
const WebsiteLoginManager::Login& _login)
: choose_automatically_if_no_stored_login(
_choose_automatically_if_no_stored_login),
payload(_payload),
+ tag(_tag),
login(_login) {}
CollectUserDataAction::LoginDetails::LoginDetails(
bool _choose_automatically_if_no_stored_login,
- const std::string& _payload)
+ const std::string& _payload,
+ const std::string& _tag)
: choose_automatically_if_no_stored_login(
_choose_automatically_if_no_stored_login),
- payload(_payload) {}
+ payload(_payload),
+ tag(_tag) {}
CollectUserDataAction::LoginDetails::~LoginDetails() = default;
@@ -573,7 +554,7 @@ void CollectUserDataAction::OnGetLogins(
login_details_map_.emplace(
identifier, std::make_unique<LoginDetails>(
login_option.choose_automatically_if_no_stored_login(),
- login_option.payload(), login));
+ login_option.payload(), login_option.tag(), login));
}
ShowToUser();
}
@@ -678,8 +659,6 @@ void CollectUserDataAction::OnShowToUser(UserData* user_data,
UpdatePersonalDataManagerProfiles(user_data);
UpdatePersonalDataManagerCards(user_data);
}
- UpdateDateTimeRangeStart(user_data);
- UpdateDateTimeRangeEnd(user_data);
UpdateMetrics(user_data);
@@ -722,6 +701,11 @@ void CollectUserDataAction::OnGetUserData(
delegate_->GetPersonalDataManager()->RemoveObserver(this);
WriteProcessedAction(user_data, user_model);
+ if (RequiresPhoneNumberSeparately(*collect_user_data_options_)) {
+ MergePhoneNumberIntoSelectedContact(user_data, delegate_->GetUserModel(),
+ *collect_user_data_options_,
+ proto_.collect_user_data().user_data());
+ }
if (collect_user_data_options_->should_store_data_changes) {
UpdateProfileAndCardUse(user_data);
}
@@ -850,7 +834,34 @@ bool CollectUserDataAction::CreateOptionsFromProto() {
collect_user_data_options_->contact_full_max_lines =
contact_details.max_number_full_lines();
}
- if (RequiresContact(*collect_user_data_options_)) {
+
+ if (contact_details.separate_phone_number_section()) {
+ if (contact_details.request_payer_phone()) {
+ VLOG(1) << "The phone number cannot be requested both in the contact "
+ "details and separately";
+ return false;
+ }
+ if (!collect_user_data.has_user_data()) {
+ VLOG(1)
+ << "Separate phone number request is only supported with backend "
+ "data";
+ return false;
+ }
+ if (contact_details.phone_number_section_title().empty()) {
+ VLOG(1) << "Missing title for separate phone number section";
+ return false;
+ }
+ collect_user_data_options_->request_phone_number_separately = true;
+ collect_user_data_options_->phone_number_section_title =
+ contact_details.phone_number_section_title();
+ collect_user_data_options_->required_phone_number_data_pieces =
+ std::vector<RequiredDataPiece>(
+ contact_details.phone_number_required_data_piece().begin(),
+ contact_details.phone_number_required_data_piece().end());
+ }
+
+ if (RequiresContact(*collect_user_data_options_) ||
+ RequiresPhoneNumberSeparately(*collect_user_data_options_)) {
if (!contact_details.has_contact_details_name()) {
VLOG(1) << "Contact details name missing";
return false;
@@ -921,6 +932,8 @@ bool CollectUserDataAction::CreateOptionsFromProto() {
!collect_user_data.has_user_data();
collect_user_data_options_->can_edit_contacts =
!collect_user_data.has_user_data();
+ collect_user_data_options_->use_gms_core_edit_dialogs =
+ collect_user_data.has_user_data();
collect_user_data_options_->request_login_choice =
collect_user_data.has_login_details();
@@ -962,7 +975,7 @@ bool CollectUserDataAction::CreateOptionsFromProto() {
identifier,
std::make_unique<LoginDetails>(
login_option.choose_automatically_if_no_stored_login(),
- login_option.payload()));
+ login_option.payload(), login_option.tag()));
break;
}
case LoginDetailsProto::LoginOptionProto::kPasswordManager: {
@@ -977,27 +990,6 @@ bool CollectUserDataAction::CreateOptionsFromProto() {
}
}
- if (collect_user_data.has_date_time_range()) {
- std::string error_message;
- if (!IsValidDateTimeRangeProto(collect_user_data.date_time_range(),
- &error_message)) {
- VLOG(1) << "Invalid action: " << error_message;
- return false;
- }
- if (collect_user_data.date_time_range().start_time_slot() < 0 ||
- collect_user_data.date_time_range().end_time_slot() < 0 ||
- collect_user_data.date_time_range().start_time_slot() >=
- collect_user_data.date_time_range().time_slots().size() ||
- collect_user_data.date_time_range().end_time_slot() >=
- collect_user_data.date_time_range().time_slots().size()) {
- VLOG(1) << "Invalid action: time slot index out of range";
- return false;
- }
- collect_user_data_options_->request_date_time_range = true;
- collect_user_data_options_->date_time_range =
- collect_user_data.date_time_range();
- }
-
for (const auto& section :
collect_user_data.additional_prepended_sections()) {
if (!IsValidUserFormSection(section)) {
@@ -1151,9 +1143,17 @@ void CollectUserDataAction::FillInitiallySelectedDataStateForMetrics(
DCHECK(user_data);
if (RequiresContact(*collect_user_data_options_)) {
- metrics_data_.selected_contact_field_bitmask =
- user_data::GetFieldBitArrayForAddress(user_data->selected_address(
- collect_user_data_options_->contact_details_name));
+ if (RequiresPhoneNumberSeparately(*collect_user_data_options_)) {
+ metrics_data_.selected_contact_field_bitmask =
+ user_data::GetFieldBitArrayForAddressAndPhoneNumber(
+ user_data->selected_address(
+ collect_user_data_options_->contact_details_name),
+ user_data->selected_phone_number());
+ } else {
+ metrics_data_.selected_contact_field_bitmask =
+ user_data::GetFieldBitArrayForAddress(user_data->selected_address(
+ collect_user_data_options_->contact_details_name));
+ }
}
if (RequiresShipping(*collect_user_data_options_)) {
@@ -1183,8 +1183,12 @@ bool CollectUserDataAction::IsUserDataComplete(
user_data.selected_address(options.billing_address_name);
auto* shipping_address =
user_data.selected_address(options.shipping_address_name);
+ // TODO(b/204419253): check for phone number errors
return user_data::GetContactValidationErrors(selected_profile, options)
.empty() &&
+ user_data::GetPhoneNumberValidationErrors(
+ user_data.selected_phone_number(), options)
+ .empty() &&
user_data::GetShippingAddressValidationErrors(shipping_address,
options)
.empty() &&
@@ -1193,99 +1197,10 @@ bool CollectUserDataAction::IsUserDataComplete(
.empty() &&
IsValidLoginChoice(user_data.selected_login_choice(), options) &&
IsValidTermsChoice(user_data.terms_and_conditions_, options) &&
- IsValidDateTimeRange(user_data.date_time_range_start_date_,
- user_data.date_time_range_start_timeslot_,
- user_data.date_time_range_end_date_,
- user_data.date_time_range_end_timeslot_,
- options) &&
AreAdditionalSectionsComplete(user_data, options) &&
IsValidUserModel(user_model, options);
}
-// TODO(b/148448649): Move to dedicated helper namespace.
-// static
-int CollectUserDataAction::CompareDates(const DateProto& first,
- const DateProto& second) {
- auto first_tuple = std::make_tuple(first.year(), first.month(), first.day());
- auto second_tuple =
- std::make_tuple(second.year(), second.month(), second.day());
- if (first_tuple < second_tuple) {
- return -1;
- } else if (second_tuple < first_tuple) {
- return 1;
- }
- return 0;
-}
-
-// TODO(b/148448649): Move to dedicated helper namespace.
-// static
-bool CollectUserDataAction::SanitizeDateTimeRange(
- absl::optional<DateProto>* start_date,
- absl::optional<int>* start_timeslot,
- absl::optional<DateProto>* end_date,
- absl::optional<int>* end_timeslot,
- const CollectUserDataOptions& collect_user_data_options,
- bool change_start) {
- if (!collect_user_data_options.request_date_time_range) {
- return false;
- }
- DCHECK(start_date);
- DCHECK(start_timeslot);
- DCHECK(end_date);
- DCHECK(end_timeslot);
- if (!start_date->has_value() || !end_date->has_value()) {
- return false;
- }
-
- auto date_comparison = CompareDates(**start_date, **end_date);
- if (date_comparison < 0) {
- return false;
- }
-
- // Start date > end date, reset date.
- if (date_comparison > 0) {
- if (change_start) {
- start_date->reset();
- } else {
- end_date->reset();
- }
- return true;
- }
-
- if (!start_timeslot->has_value() || !end_timeslot->has_value()) {
- return false;
- }
-
- DCHECK(**start_timeslot >= 0 &&
- **start_timeslot <
- collect_user_data_options.date_time_range.time_slots().size());
- DCHECK(**end_timeslot >= 0 &&
- **end_timeslot <
- collect_user_data_options.date_time_range.time_slots().size());
- auto start_time =
- collect_user_data_options.date_time_range.time_slots(**start_timeslot);
- auto end_time =
- collect_user_data_options.date_time_range.time_slots(**end_timeslot);
- auto time_comparison =
- start_time.comparison_value() - end_time.comparison_value();
- if (time_comparison < 0) {
- return false;
- }
-
- // Start date == end date and start time >= end time, reset time.
- if (time_comparison >= 0) {
- if (change_start) {
- start_timeslot->reset();
- } else {
- end_timeslot->reset();
- }
- return true;
- }
-
- NOTREACHED();
- return false;
-}
-
void CollectUserDataAction::WriteProcessedAction(UserData* user_data,
const UserModel* user_model) {
if (proto().collect_user_data().request_payment_method() &&
@@ -1330,33 +1245,16 @@ void CollectUserDataAction::WriteProcessedAction(UserData* user_data,
}
}
- processed_action_proto_->mutable_collect_user_data_result()
- ->set_login_payload(login_details->second->payload);
+ auto* result =
+ processed_action_proto_->mutable_collect_user_data_result();
+ if (!login_details->second->tag.empty()) {
+ result->set_login_tag(login_details->second->tag);
+ } else {
+ result->set_login_payload(login_details->second->payload);
+ }
}
}
- if (proto().collect_user_data().has_date_time_range()) {
- if (user_data->date_time_range_start_date_.has_value()) {
- *processed_action_proto_->mutable_collect_user_data_result()
- ->mutable_date_range_start_date() =
- *user_data->date_time_range_start_date_;
- }
- if (user_data->date_time_range_start_timeslot_.has_value()) {
- processed_action_proto_->mutable_collect_user_data_result()
- ->set_date_range_start_timeslot(
- *user_data->date_time_range_start_timeslot_);
- }
- if (user_data->date_time_range_end_date_.has_value()) {
- *processed_action_proto_->mutable_collect_user_data_result()
- ->mutable_date_range_end_date() =
- *user_data->date_time_range_end_date_;
- }
- if (user_data->date_time_range_end_timeslot_.has_value()) {
- processed_action_proto_->mutable_collect_user_data_result()
- ->set_date_range_end_timeslot(
- *user_data->date_time_range_end_timeslot_);
- }
- }
for (const auto& section :
proto().collect_user_data().additional_prepended_sections()) {
FillProtoForAdditionalSection(section, *user_data,
@@ -1470,6 +1368,39 @@ void CollectUserDataAction::UpdateUserDataFromProto(
}
}
+ if (RequiresPhoneNumberSeparately(*collect_user_data_options_)) {
+ user_data->available_phone_numbers_.clear();
+ for (const auto& phone_number_data : proto_data.available_phone_numbers()) {
+ auto profile = std::make_unique<autofill::AutofillProfile>();
+ AddAutofillEntryToDataModel(
+ autofill::ServerFieldType::PHONE_HOME_WHOLE_NUMBER,
+ phone_number_data.value(), proto_data.locale(), profile.get());
+ auto phone_number = std::make_unique<PhoneNumber>(std::move(profile));
+ if (phone_number_data.has_identifier()) {
+ phone_number->identifier = phone_number_data.identifier();
+ }
+ user_data->available_phone_numbers_.emplace_back(std::move(phone_number));
+ }
+ if (proto_data.has_selected_phone_number_identifier()) {
+ const auto& it = base::ranges::find_if(
+ user_data->available_phone_numbers_, [&](const auto& phone_number) {
+ return phone_number->identifier &&
+ proto_data.selected_phone_number_identifier() ==
+ *phone_number->identifier;
+ });
+ if (it == user_data->available_phone_numbers_.end()) {
+ NOTREACHED();
+ EndAction(ClientStatus(INVALID_ACTION));
+ return;
+ }
+ const auto& phone_number_to_select = *it;
+ user_data->SetSelectedPhoneNumber(
+ user_data::MakeUniqueFromProfile(*phone_number_to_select->profile));
+ } else {
+ UpdateSelectedPhoneNumber(user_data);
+ }
+ }
+
if (RequiresAddress(*collect_user_data_options_)) {
user_data->available_addresses_.clear();
for (const auto& profile_data : proto_data.available_addresses()) {
@@ -1513,6 +1444,13 @@ void CollectUserDataAction::UpdateUserDataFromProto(
credit_card->set_record_type(autofill::CreditCard::MASKED_SERVER_CARD);
AddProtoDataToAutofillDataModel(payment_data.card_values(),
proto_data.locale(), credit_card.get());
+ if (payment_data.has_instrument_id()) {
+ credit_card->set_instrument_id(payment_data.instrument_id());
+ }
+ if (!payment_data.last_four_digits().empty()) {
+ credit_card->SetNumber(
+ base::UTF8ToUTF16(payment_data.last_four_digits()));
+ }
if (!payment_data.network().empty()) {
credit_card->SetNetworkForMaskedCard(payment_data.network());
}
@@ -1660,10 +1598,8 @@ void CollectUserDataAction::UpdateSelectedContact(UserData* user_data) {
if (selected_contact != nullptr) {
found_contact = base::ranges::any_of(
user_data->available_contacts_,
- [&selected_contact, this](const std::unique_ptr<Contact>& contact) {
- return user_data::CompareContactDetails(*collect_user_data_options_,
- contact->profile.get(),
- selected_contact);
+ [&selected_contact](const std::unique_ptr<Contact>& contact) {
+ return selected_contact->guid() == contact->profile->guid();
});
}
@@ -1688,6 +1624,35 @@ void CollectUserDataAction::UpdateSelectedContact(UserData* user_data) {
}
}
+void CollectUserDataAction::UpdateSelectedPhoneNumber(UserData* user_data) {
+ DCHECK(user_data != nullptr);
+
+ bool found_phone_number = false;
+ auto* selected_phone_number = user_data->selected_phone_number();
+ if (selected_phone_number != nullptr) {
+ found_phone_number = base::ranges::any_of(
+ user_data->available_phone_numbers_,
+ [&selected_phone_number](
+ const std::unique_ptr<PhoneNumber>& phone_number) {
+ return phone_number->profile->guid() == selected_phone_number->guid();
+ });
+ }
+
+ if (!found_phone_number && selected_phone_number != nullptr) {
+ user_data->SetSelectedPhoneNumber(/* profile= */ nullptr);
+ }
+
+ if (!user_data->selected_phone_number() &&
+ RequiresPhoneNumberSeparately(*collect_user_data_options_)) {
+ int default_selection = user_data::GetDefaultPhoneNumber(
+ *collect_user_data_options_, user_data->available_phone_numbers_);
+ if (default_selection != -1) {
+ user_data->SetSelectedPhoneNumber(user_data::MakeUniqueFromProfile(
+ *user_data->available_phone_numbers_[default_selection]->profile));
+ }
+ }
+}
+
void CollectUserDataAction::UpdateSelectedShippingAddress(UserData* user_data) {
DCHECK(user_data != nullptr);
@@ -1698,7 +1663,7 @@ void CollectUserDataAction::UpdateSelectedShippingAddress(UserData* user_data) {
found_shipping_address = base::ranges::any_of(
user_data->available_addresses_,
[&selected_shipping_address](const std::unique_ptr<Address>& address) {
- return address->profile->Compare(*selected_shipping_address) == 0;
+ return selected_shipping_address->guid() == address->profile->guid();
});
}
@@ -1727,12 +1692,14 @@ void CollectUserDataAction::UpdateSelectedCreditCard(UserData* user_data) {
DCHECK(user_data != nullptr);
bool found_card = false;
- for (const std::unique_ptr<PaymentInstrument>& payment_instrument :
- user_data->available_payment_instruments_) {
- if (user_data->selected_card() != nullptr &&
- payment_instrument->card->Compare(*user_data->selected_card()) == 0) {
- found_card = true;
- }
+ auto* selected_card = user_data->selected_card();
+ if (selected_card != nullptr) {
+ found_card = base::ranges::any_of(
+ user_data->available_payment_instruments_,
+ [&selected_card](
+ const std::unique_ptr<PaymentInstrument>& payment_instrument) {
+ return selected_card->guid() == payment_instrument->card->guid();
+ });
}
if (!found_card) {
@@ -1778,50 +1745,4 @@ void CollectUserDataAction::OnPersonalDataChanged() {
weak_ptr_factory_.GetWeakPtr()));
}
-void CollectUserDataAction::UpdateDateTimeRangeStart(
- UserData* user_data,
- UserData::FieldChange* field_change) {
- DCHECK(user_data != nullptr);
- DCHECK(collect_user_data_options_ != nullptr);
-
- UserData::FieldChange changed = UserData::FieldChange::NONE;
- if (!user_data->date_time_range_start_date_.has_value()) {
- user_data->date_time_range_start_date_ =
- collect_user_data_options_->date_time_range.start_date();
- changed = UserData::FieldChange::DATE_TIME_RANGE_START;
- }
- if (!user_data->date_time_range_start_timeslot_.has_value()) {
- user_data->date_time_range_start_timeslot_ =
- collect_user_data_options_->date_time_range.start_time_slot();
- changed = UserData::FieldChange::DATE_TIME_RANGE_START;
- }
-
- if (field_change != nullptr && changed != UserData::FieldChange::NONE) {
- *field_change = changed;
- }
-}
-
-void CollectUserDataAction::UpdateDateTimeRangeEnd(
- UserData* user_data,
- UserData::FieldChange* field_change) {
- DCHECK(user_data != nullptr);
- DCHECK(collect_user_data_options_ != nullptr);
-
- UserData::FieldChange changed = UserData::FieldChange::NONE;
- if (!user_data->date_time_range_end_date_.has_value()) {
- user_data->date_time_range_end_date_ =
- collect_user_data_options_->date_time_range.end_date();
- changed = UserData::FieldChange::DATE_TIME_RANGE_END;
- }
- if (!user_data->date_time_range_end_timeslot_.has_value()) {
- user_data->date_time_range_end_timeslot_ =
- collect_user_data_options_->date_time_range.end_time_slot();
- changed = UserData::FieldChange::DATE_TIME_RANGE_END;
- }
-
- if (field_change != nullptr && changed != UserData::FieldChange::NONE) {
- *field_change = changed;
- }
-}
-
} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/actions/collect_user_data_action.h b/chromium/components/autofill_assistant/browser/actions/collect_user_data_action.h
index 5ddd78b5a7b..5979d90bb01 100644
--- a/chromium/components/autofill_assistant/browser/actions/collect_user_data_action.h
+++ b/chromium/components/autofill_assistant/browser/actions/collect_user_data_action.h
@@ -47,30 +47,19 @@ class CollectUserDataAction : public Action,
const UserModel& user_model,
const CollectUserDataOptions& collect_user_data_options);
- // Ensures that |end| is > |start| by modifying either |start| or |end|,
- // depending on |change_start|. Returns true if changes were performed.
- static bool SanitizeDateTimeRange(
- absl::optional<DateProto>* start_date,
- absl::optional<int>* start_timeslot,
- absl::optional<DateProto>* end_date,
- absl::optional<int>* end_timeslot,
- const CollectUserDataOptions& collect_user_data_options,
- bool change_start);
-
- // Comparison function for |DateProto|.
- // Returns 0 if equal, < 0 if |first| < |second|, > 0 if |second| > |first|.
- static int CompareDates(const DateProto& first, const DateProto& second);
-
private:
struct LoginDetails {
LoginDetails(bool choose_automatically_if_no_stored_login,
- const std::string& payload);
+ const std::string& payload,
+ const std::string& tag);
LoginDetails(bool choose_automatically_if_no_stored_login,
const std::string& payload,
+ const std::string& tag,
const WebsiteLoginManager::Login& login);
~LoginDetails();
bool choose_automatically_if_no_stored_login;
std::string payload;
+ std::string tag;
// Only for Chrome PWM login details.
absl::optional<WebsiteLoginManager::Login> login;
};
@@ -125,12 +114,9 @@ class CollectUserDataAction : public Action,
UserData* user_data,
UserData::FieldChange* field_change = nullptr);
void UpdateSelectedContact(UserData* user_data);
+ void UpdateSelectedPhoneNumber(UserData* user_data);
void UpdateSelectedShippingAddress(UserData* user_data);
void UpdateSelectedCreditCard(UserData* user_data);
- void UpdateDateTimeRangeStart(UserData* user_data,
- UserData::FieldChange* field_change = nullptr);
- void UpdateDateTimeRangeEnd(UserData* user_data,
- UserData::FieldChange* field_change = nullptr);
void MaybeLogMetrics();
UserDataMetrics metrics_data_;
diff --git a/chromium/components/autofill_assistant/browser/actions/collect_user_data_action_unittest.cc b/chromium/components/autofill_assistant/browser/actions/collect_user_data_action_unittest.cc
index 3df465c28d3..d494ac70a4f 100644
--- a/chromium/components/autofill_assistant/browser/actions/collect_user_data_action_unittest.cc
+++ b/chromium/components/autofill_assistant/browser/actions/collect_user_data_action_unittest.cc
@@ -70,19 +70,21 @@ MATCHER_P(MatchingAutofillVariant, guid, "") {
}
MATCHER_P(MatchesProfile, profile, "") {
- return arg.Compare(profile) == 0;
+ return arg.guid() == profile.guid() && arg.Compare(profile) == 0;
}
MATCHER_P(MatchesContact, profile, "") {
- return arg.profile->Compare(profile) == 0;
+ return arg.profile->guid() == profile.guid() &&
+ arg.profile->Compare(profile) == 0;
}
MATCHER_P(MatchesAddress, profile, "") {
- return arg.profile->Compare(profile) == 0;
+ return arg.profile->guid() == profile.guid() &&
+ arg.profile->Compare(profile) == 0;
}
MATCHER_P(MatchesCard, card, "") {
- return arg.Compare(card) == 0;
+ return arg.guid() == card.guid() && arg.Compare(card) == 0;
}
RequiredDataPiece MakeRequiredDataPiece(autofill::ServerFieldType field) {
@@ -118,12 +120,6 @@ void AddCompleteCardEntriesToMap(
(*values)[55] = MakeAutofillEntry("2050");
}
-void SetDateProto(DateProto* proto, int year, int month, int day) {
- proto->set_year(year);
- proto->set_month(month);
- proto->set_day(day);
-}
-
using ::base::test::RunOnceCallback;
using ::testing::_;
using ::testing::AnyOf;
@@ -397,14 +393,14 @@ TEST_F(CollectUserDataActionTest, PromptIsShown) {
action.ProcessAction(callback_.Get());
}
-TEST_F(CollectUserDataActionTest, SelectLogin) {
+TEST_F(CollectUserDataActionTest, SelectLoginWithTag) {
ActionProto action_proto;
auto* collect_user_data_proto = action_proto.mutable_collect_user_data();
collect_user_data_proto->set_request_terms_and_conditions(false);
auto* login_details = collect_user_data_proto->mutable_login_details();
auto* login_option = login_details->add_login_options();
login_option->mutable_password_manager();
- login_option->set_payload("payload");
+ login_option->set_tag("tag");
// Action should fetch the logins, but not the passwords.
EXPECT_CALL(mock_website_login_manager_, GetLoginsForUrl(GURL(kFakeUrl), _))
@@ -422,17 +418,51 @@ TEST_F(CollectUserDataActionTest, SelectLogin) {
.Run(&user_data_, &user_model_);
}));
- EXPECT_CALL(callback_,
- Run(Pointee(AllOf(
- Property(&ProcessedActionProto::status, ACTION_APPLIED),
- Property(&ProcessedActionProto::collect_user_data_result,
- Property(&CollectUserDataResultProto::login_payload,
- "payload")),
- Property(&ProcessedActionProto::collect_user_data_result,
- Property(&CollectUserDataResultProto::shown_to_user,
- true))))));
+ ProcessedActionProto captured_action;
+ EXPECT_CALL(callback_, Run(_))
+ .WillOnce(testing::SaveArgPointee<0>(&captured_action));
+ CollectUserDataAction action(&mock_action_delegate_, action_proto);
+ action.ProcessAction(callback_.Get());
+
+ EXPECT_EQ(ACTION_APPLIED, captured_action.status());
+ EXPECT_EQ("", captured_action.collect_user_data_result().login_payload());
+ EXPECT_EQ("tag", captured_action.collect_user_data_result().login_tag());
+ EXPECT_TRUE(captured_action.collect_user_data_result().shown_to_user());
+}
+
+TEST_F(CollectUserDataActionTest, SelectLoginWithPayload) {
+ // This test concentrate on the backward-compatibility case where login is
+ // reported using a payload instead of a case. Other aspects of login
+ // selection are covered by SelectLogin.
+
+ ActionProto action_proto;
+ auto* collect_user_data_proto = action_proto.mutable_collect_user_data();
+ collect_user_data_proto->set_request_terms_and_conditions(false);
+ auto* login_details = collect_user_data_proto->mutable_login_details();
+ auto* login_option = login_details->add_login_options();
+ login_option->mutable_password_manager();
+ login_option->set_payload("payload");
+
+ ON_CALL(mock_action_delegate_, CollectUserData(_))
+ .WillByDefault(
+ Invoke([this](CollectUserDataOptions* collect_user_data_options) {
+ user_model_.SetSelectedLoginChoice(
+ std::make_unique<LoginChoice>(
+ collect_user_data_options->login_choices[0]),
+ &user_data_);
+ std::move(collect_user_data_options->confirm_callback)
+ .Run(&user_data_, &user_model_);
+ }));
+
+ ProcessedActionProto captured_action;
+ EXPECT_CALL(callback_, Run(_))
+ .WillOnce(testing::SaveArgPointee<0>(&captured_action));
CollectUserDataAction action(&mock_action_delegate_, action_proto);
action.ProcessAction(callback_.Get());
+
+ EXPECT_EQ("payload",
+ captured_action.collect_user_data_result().login_payload());
+ EXPECT_EQ("", captured_action.collect_user_data_result().login_tag());
}
TEST_F(CollectUserDataActionTest, SelectLoginMissingUsername) {
@@ -673,36 +703,9 @@ TEST_F(CollectUserDataActionTest, EarlyActionReturnIfOnlyLoginRequested) {
action.ProcessAction(callback_.Get());
}
- // Date/time range info requested, no early return.
+ // Generic UI model identifier set, no early return.
proto->clear_request_payment_method();
proto->clear_billing_address_name();
- auto* date_time_range = proto->mutable_date_time_range();
- SetDateProto(date_time_range->mutable_start_date(), 2020, 1, 1);
- SetDateProto(date_time_range->mutable_end_date(), 2020, 1, 15);
- SetDateProto(date_time_range->mutable_min_date(), 2020, 1, 1);
- SetDateProto(date_time_range->mutable_max_date(), 2020, 12, 31);
- date_time_range->set_start_time_slot(0);
- date_time_range->set_end_time_slot(0);
- date_time_range->set_start_date_label("Start date");
- date_time_range->set_end_date_label("End date");
- date_time_range->set_start_time_label("Start time");
- date_time_range->set_end_time_label("End time");
- date_time_range->set_date_not_set_error("Date not set");
- date_time_range->set_time_not_set_error("Time not set");
- auto* time_slot = date_time_range->add_time_slots();
- time_slot->set_label("08:00 AM");
- time_slot->set_comparison_value(0);
- time_slot = date_time_range->add_time_slots();
- time_slot->set_label("09:00 AM");
- time_slot->set_comparison_value(1);
- {
- EXPECT_CALL(mock_action_delegate_, CollectUserData(_)).Times(1);
- CollectUserDataAction action(&mock_action_delegate_, action_proto);
- action.ProcessAction(callback_.Get());
- }
-
- // Generic UI model identifier set, no early return.
- proto->clear_date_time_range();
proto->set_additional_model_identifier_to_check("identifier");
{
EXPECT_CALL(mock_action_delegate_, CollectUserData(_)).Times(1);
@@ -745,18 +748,18 @@ TEST_F(CollectUserDataActionTest, EarlyActionReturnIfOnlyLoginRequested) {
section->mutable_static_text_section()->set_text("text");
{
EXPECT_CALL(mock_action_delegate_, CollectUserData(_)).Times(0);
- EXPECT_CALL(
- callback_,
- Run(Pointee(AllOf(
- Property(&ProcessedActionProto::status, ACTION_APPLIED),
- Property(
- &ProcessedActionProto::collect_user_data_result,
- Property(&CollectUserDataResultProto::login_payload, "guest")),
- Property(&ProcessedActionProto::collect_user_data_result,
- Property(&CollectUserDataResultProto::shown_to_user,
- false))))));
+
+ ProcessedActionProto captured_action;
+ EXPECT_CALL(callback_, Run(_))
+ .WillOnce(testing::SaveArgPointee<0>(&captured_action));
+
CollectUserDataAction action(&mock_action_delegate_, action_proto);
action.ProcessAction(callback_.Get());
+
+ EXPECT_EQ(ACTION_APPLIED, captured_action.status());
+ EXPECT_EQ("guest",
+ captured_action.collect_user_data_result().login_payload());
+ EXPECT_FALSE(captured_action.collect_user_data_result().shown_to_user());
}
}
@@ -1073,6 +1076,30 @@ TEST_F(CollectUserDataActionTest, UserDataCompleteContact) {
options));
}
+TEST_F(CollectUserDataActionTest, UserDataCompletePhoneNumber) {
+ UserData user_data;
+ CollectUserDataOptions options;
+ EXPECT_TRUE(CollectUserDataAction::IsUserDataComplete(user_data, user_model_,
+ options));
+
+ autofill::AutofillProfile profile(base::GenerateGUID(), kFakeUrl);
+ user_data.SetSelectedPhoneNumber(
+ std::make_unique<autofill::AutofillProfile>(profile));
+
+ options.required_phone_number_data_pieces.push_back(MakeRequiredDataPiece(
+ autofill::ServerFieldType::PHONE_HOME_WHOLE_NUMBER));
+ options.request_phone_number_separately = true;
+ EXPECT_FALSE(CollectUserDataAction::IsUserDataComplete(user_data, user_model_,
+ options));
+
+ profile.SetRawInfo(autofill::ServerFieldType::PHONE_HOME_WHOLE_NUMBER,
+ u"+1 23 456 789 01");
+ user_data.SetSelectedPhoneNumber(
+ std::make_unique<autofill::AutofillProfile>(profile));
+ EXPECT_TRUE(CollectUserDataAction::IsUserDataComplete(user_data, user_model_,
+ options));
+}
+
TEST_F(CollectUserDataActionTest, UserDataCompletePayment) {
UserData user_data;
CollectUserDataOptions options;
@@ -1222,75 +1249,6 @@ TEST_F(CollectUserDataActionTest, UserDataCompleteShippingAddress) {
options));
}
-TEST_F(CollectUserDataActionTest, UserDataCompleteDateTimeRange) {
- UserData user_data;
- CollectUserDataOptions options;
- options.request_date_time_range = true;
- auto* time_slot = options.date_time_range.add_time_slots();
- time_slot->set_label("08:00 AM");
- time_slot->set_comparison_value(0);
- time_slot = options.date_time_range.add_time_slots();
- time_slot->set_label("09:00 AM");
- time_slot->set_comparison_value(1);
-
- DateProto start_date;
- SetDateProto(&start_date, 2020, 1, 1);
- DateProto end_date;
- SetDateProto(&end_date, 2020, 1, 15);
- user_data.date_time_range_start_date_ = start_date;
- user_data.date_time_range_end_date_ = end_date;
- user_data.date_time_range_start_timeslot_ = 0;
- user_data.date_time_range_end_timeslot_ = 0;
-
- // Initial selection is valid.
- EXPECT_TRUE(CollectUserDataAction::IsUserDataComplete(user_data, user_model_,
- options));
-
- // Start date not before end date is not ok.
- SetDateProto(&*user_data.date_time_range_start_date_, 2020, 2, 7);
- SetDateProto(&*user_data.date_time_range_end_date_, 2020, 1, 15);
- EXPECT_FALSE(CollectUserDataAction::IsUserDataComplete(user_data, user_model_,
- options));
-
- // Same date with end time > start time is ok.
- SetDateProto(&*user_data.date_time_range_start_date_, 2020, 1, 15);
- SetDateProto(&*user_data.date_time_range_end_date_, 2020, 1, 15);
- user_data.date_time_range_start_timeslot_ = 0;
- user_data.date_time_range_end_timeslot_ = 1;
- EXPECT_TRUE(CollectUserDataAction::IsUserDataComplete(user_data, user_model_,
- options));
-
- // Same date and same time is not ok.
- user_data.date_time_range_start_timeslot_ = 0;
- user_data.date_time_range_end_timeslot_ = 0;
- EXPECT_FALSE(CollectUserDataAction::IsUserDataComplete(user_data, user_model_,
- options));
-
- // Same date and start time > end time is not ok.
- user_data.date_time_range_start_timeslot_ = 1;
- user_data.date_time_range_end_timeslot_ = 0;
- EXPECT_FALSE(CollectUserDataAction::IsUserDataComplete(user_data, user_model_,
- options));
-
- // Start date before end date is ok.
- SetDateProto(&*user_data.date_time_range_start_date_, 2020, 3, 1);
- SetDateProto(&*user_data.date_time_range_end_date_, 2020, 3, 31);
- user_data.date_time_range_start_timeslot_ = 0;
- user_data.date_time_range_end_timeslot_ = 1;
- EXPECT_TRUE(CollectUserDataAction::IsUserDataComplete(user_data, user_model_,
- options));
- user_data.date_time_range_start_timeslot_ = 1;
- user_data.date_time_range_end_timeslot_ = 0;
- EXPECT_TRUE(CollectUserDataAction::IsUserDataComplete(user_data, user_model_,
- options));
-
- // Proper date comparison across years.
- SetDateProto(&*user_data.date_time_range_start_date_, 2019, 11, 10);
- SetDateProto(&*user_data.date_time_range_end_date_, 2020, 1, 5);
- EXPECT_TRUE(CollectUserDataAction::IsUserDataComplete(user_data, user_model_,
- options));
-}
-
TEST_F(CollectUserDataActionTest, UserDataCompleteChecksGenericUiCompleteness) {
UserData user_data;
CollectUserDataOptions options;
@@ -1314,71 +1272,6 @@ TEST_F(CollectUserDataActionTest, UserDataCompleteChecksGenericUiCompleteness) {
options));
}
-TEST_F(CollectUserDataActionTest, SelectDateTimeRange) {
- ActionProto action_proto;
- auto* collect_user_data_proto = action_proto.mutable_collect_user_data();
- collect_user_data_proto->set_request_terms_and_conditions(false);
-
- auto* date_time_range = collect_user_data_proto->mutable_date_time_range();
- SetDateProto(date_time_range->mutable_start_date(), 2020, 1, 1);
- SetDateProto(date_time_range->mutable_end_date(), 2020, 1, 15);
- SetDateProto(date_time_range->mutable_min_date(), 2020, 1, 1);
- SetDateProto(date_time_range->mutable_max_date(), 2020, 12, 31);
- date_time_range->set_start_time_slot(0);
- date_time_range->set_end_time_slot(0);
- date_time_range->set_start_date_label("Start date");
- date_time_range->set_end_date_label("End date");
- date_time_range->set_start_time_label("Start time");
- date_time_range->set_end_time_label("End time");
- date_time_range->set_date_not_set_error("Date not set");
- date_time_range->set_time_not_set_error("Time not set");
-
- auto* time_slot = date_time_range->add_time_slots();
- time_slot->set_label("08:00 AM");
- time_slot->set_comparison_value(0);
- time_slot = date_time_range->add_time_slots();
- time_slot->set_label("09:00 AM");
- time_slot->set_comparison_value(1);
-
- DateProto actual_pickup_date;
- DateProto actual_return_date;
- SetDateProto(&actual_pickup_date, 2020, 10, 21);
- SetDateProto(&actual_return_date, 2020, 10, 25);
- int actual_pickup_time = 1;
- int actual_return_time = 1;
- ON_CALL(mock_action_delegate_, CollectUserData(_))
- .WillByDefault(
- Invoke([&](CollectUserDataOptions* collect_user_data_options) {
- user_data_.date_time_range_start_date_ = actual_pickup_date;
- user_data_.date_time_range_start_timeslot_ = actual_pickup_time;
- user_data_.date_time_range_end_date_ = actual_return_date;
- user_data_.date_time_range_end_timeslot_ = actual_return_time;
- std::move(collect_user_data_options->confirm_callback)
- .Run(&user_data_, &user_model_);
- }));
-
- EXPECT_CALL(
- callback_,
- Run(Pointee(AllOf(
- Property(&ProcessedActionProto::status, ACTION_APPLIED),
- Property(&ProcessedActionProto::collect_user_data_result,
- Property(&CollectUserDataResultProto::date_range_start_date,
- Eq(actual_pickup_date))),
- Property(
- &ProcessedActionProto::collect_user_data_result,
- Property(&CollectUserDataResultProto::date_range_start_timeslot,
- Eq(actual_pickup_time))),
- Property(&ProcessedActionProto::collect_user_data_result,
- Property(&CollectUserDataResultProto::date_range_end_date,
- Eq(actual_return_date))),
- Property(
- &ProcessedActionProto::collect_user_data_result,
- Property(&CollectUserDataResultProto::date_range_end_timeslot,
- Eq(actual_return_time)))))));
- CollectUserDataAction action(&mock_action_delegate_, action_proto);
- action.ProcessAction(callback_.Get());
-}
-
TEST_F(CollectUserDataActionTest, StaticSectionValid) {
ActionProto action_proto;
auto* collect_user_data_proto = action_proto.mutable_collect_user_data();
@@ -2027,7 +1920,8 @@ TEST_F(CollectUserDataActionTest, ResetsContactAndShippingIfNoLongerInList) {
ON_CALL(mock_action_delegate_, CollectUserData(_))
.WillByDefault(
Invoke([=](CollectUserDataOptions* collect_user_data_options) {
- ExpectSelectedProfileMatches("profile", nullptr);
+ // Default selected to newly sent profile.
+ ExpectSelectedProfileMatches("profile", &profile);
ExpectSelectedProfileMatches("shipping_address", &profile);
// Do not call the callback. We're only interested in the state.
@@ -2036,9 +1930,9 @@ TEST_F(CollectUserDataActionTest, ResetsContactAndShippingIfNoLongerInList) {
ActionProto action_proto;
auto* collect_user_data = action_proto.mutable_collect_user_data();
collect_user_data->set_request_terms_and_conditions(false);
- collect_user_data->mutable_contact_details();
collect_user_data->set_shipping_address_name("shipping_address");
auto* contact_details = collect_user_data->mutable_contact_details();
+ contact_details->set_request_payer_name(true);
contact_details->set_contact_details_name("profile");
// Set previous user data.
@@ -2059,6 +1953,50 @@ TEST_F(CollectUserDataActionTest, ResetsContactAndShippingIfNoLongerInList) {
action.ProcessAction(callback_.Get());
}
+TEST_F(CollectUserDataActionTest, ResetsMatchingButDifferentContact) {
+ ON_CALL(mock_personal_data_manager_, IsAutofillProfileEnabled)
+ .WillByDefault(Return(true));
+
+ autofill::AutofillProfile profile;
+ autofill::test::SetProfileInfo(&profile, "Adam", "", "West",
+ "adam.west@gmail.com", "", "", "", "", "", "",
+ "", "");
+
+ ON_CALL(mock_personal_data_manager_, GetProfiles)
+ .WillByDefault(
+ Return(std::vector<autofill::AutofillProfile*>({&profile})));
+
+ ON_CALL(mock_action_delegate_, CollectUserData(_))
+ .WillByDefault(
+ Invoke([=](CollectUserDataOptions* collect_user_data_options) {
+ // Default selected to newly sent profile.
+ ExpectSelectedProfileMatches("profile", &profile);
+
+ // Do not call the callback. We're only interested in the state.
+ }));
+
+ ActionProto action_proto;
+ auto* collect_user_data = action_proto.mutable_collect_user_data();
+ collect_user_data->set_request_terms_and_conditions(false);
+ auto* contact_details = collect_user_data->mutable_contact_details();
+ contact_details->set_request_payer_name(true);
+ contact_details->set_contact_details_name("profile");
+
+ // The selected profile is identical with the current one, but it has a
+ // different GUID.
+ autofill::AutofillProfile selected_profile;
+ autofill::test::SetProfileInfo(&selected_profile, "Adam", "", "West",
+ "adam.west@gmail.com", "", "", "", "", "", "",
+ "", "");
+
+ user_model_.SetSelectedAutofillProfile(
+ "profile", std::make_unique<autofill::AutofillProfile>(selected_profile),
+ &user_data_);
+
+ CollectUserDataAction action(&mock_action_delegate_, action_proto);
+ action.ProcessAction(callback_.Get());
+}
+
TEST_F(CollectUserDataActionTest, AttachesCreditCardsWithAddress) {
ON_CALL(mock_personal_data_manager_, IsAutofillCreditCardEnabled)
.WillByDefault(Return(true));
@@ -2645,6 +2583,73 @@ TEST_F(CollectUserDataActionTest, ContactDataFromProto) {
action.ProcessAction(callback_.Get());
}
+TEST_F(CollectUserDataActionTest, PhoneNumberFromProto) {
+ ON_CALL(mock_action_delegate_, CollectUserData(_))
+ .WillByDefault([&](CollectUserDataOptions* collect_user_data_options) {
+ EXPECT_FALSE(collect_user_data_options->should_store_data_changes);
+ EXPECT_FALSE(collect_user_data_options->can_edit_contacts);
+ ASSERT_EQ(user_data_.available_contacts_.size(), 1u);
+ EXPECT_THAT(user_data_.available_contacts_[0]->profile->guid(),
+ Not(IsEmpty()));
+ auto mappings = field_formatter::CreateAutofillMappings(
+ *user_data_.available_contacts_[0]->profile, "en-US");
+ // Initially the contact contains the backend data.
+ EXPECT_THAT(
+ mappings,
+ IsSupersetOf({Pair(field_formatter::Key(3), "John"),
+ Pair(field_formatter::Key(5), "Doe"),
+ Pair(field_formatter::Key(7), "John Doe"),
+ Pair(field_formatter::Key(10), "1234567890"),
+ Pair(field_formatter::Key(12), "1"),
+ Pair(field_formatter::Key(14), "+11234567890")}));
+ ASSERT_EQ(user_data_.available_contacts_.size(), 1u);
+
+ std::move(collect_user_data_options->confirm_callback)
+ .Run(&user_data_, &user_model_);
+ });
+
+ ActionProto action_proto;
+ auto* collect_user_data = action_proto.mutable_collect_user_data();
+ collect_user_data->set_request_terms_and_conditions(false);
+ collect_user_data->mutable_contact_details()->set_request_payer_name(true);
+ *collect_user_data->mutable_contact_details()->add_required_data_piece() =
+ MakeRequiredDataPiece(autofill::ServerFieldType::NAME_FULL);
+ collect_user_data->mutable_contact_details()->set_contact_details_name(
+ kMemoryLocation);
+ collect_user_data->mutable_contact_details()
+ ->set_separate_phone_number_section(true);
+ collect_user_data->mutable_contact_details()->set_phone_number_section_title(
+ "Phone number");
+ collect_user_data->mutable_user_data()->set_locale("en-US");
+ auto* profile =
+ collect_user_data->mutable_user_data()->add_available_contacts();
+ (*profile->mutable_values())[7] = MakeAutofillEntry("John Doe");
+ (*profile->mutable_values())[14] = MakeAutofillEntry("+1 123-456-7890");
+ *collect_user_data->mutable_user_data()
+ ->add_available_phone_numbers()
+ ->mutable_value() =
+ MakeAutofillEntry("+1 187-654-3210", /* raw= */ false);
+
+ EXPECT_CALL(mock_personal_data_manager_, RecordUseOf).Times(0);
+ EXPECT_CALL(
+ callback_,
+ Run(Pointee(Property(&ProcessedActionProto::status, ACTION_APPLIED))));
+
+ CollectUserDataAction action(&mock_action_delegate_, action_proto);
+ action.ProcessAction(callback_.Get());
+ // The selected phone number is merged into the selected contact.
+ auto mappings = field_formatter::CreateAutofillMappings(
+ *user_data_.selected_address(kMemoryLocation), "en-US");
+ EXPECT_THAT(mappings,
+ IsSupersetOf({Pair(field_formatter::Key(3), "John"),
+ Pair(field_formatter::Key(5), "Doe"),
+ Pair(field_formatter::Key(7), "John Doe"),
+ Pair(field_formatter::Key(10), "1876543210"),
+ Pair(field_formatter::Key(12), "1"),
+ Pair(field_formatter::Key(14), "+11876543210")}));
+ ASSERT_EQ(user_data_.available_contacts_.size(), 1u);
+}
+
TEST_F(CollectUserDataActionTest, PaymentDataFromProto) {
autofill::CountryNames::SetLocaleString("en-US");
ON_CALL(mock_action_delegate_, CollectUserData(_))
@@ -2667,7 +2672,19 @@ TEST_F(CollectUserDataActionTest, PaymentDataFromProto) {
Pair(field_formatter::Key(57), "08/2050"),
Pair(field_formatter::Key(58), "Visa"),
Pair(field_formatter::Key(-2), "visa"),
- Pair(field_formatter::Key(-5), "Visa")}));
+ Pair(field_formatter::Key(-5), "Visa"),
+ Pair(field_formatter::Key(-4), "1111")}));
+ EXPECT_EQ(
+ user_data_.available_payment_instruments_[0]->card->instrument_id(),
+ 123456);
+ // Used for card summary in UI.
+ EXPECT_EQ(user_data_.available_payment_instruments_[0]
+ ->card->NetworkForDisplay(),
+ u"Visa");
+ EXPECT_EQ(user_data_.available_payment_instruments_[0]
+ ->card->LastFourDigits(),
+ u"1111");
+
auto address_mappings = field_formatter::CreateAutofillMappings(
*user_data_.available_payment_instruments_[0]->billing_address,
"en-US");
@@ -2696,7 +2713,9 @@ TEST_F(CollectUserDataActionTest, PaymentDataFromProto) {
->add_available_payment_instruments();
AddCompleteCardEntriesToMap("John Doe",
payment_instrument->mutable_card_values());
+ payment_instrument->set_instrument_id(123456);
payment_instrument->set_network("visaCC");
+ payment_instrument->set_last_four_digits("1111");
AddCompleteAddressEntriesToMap("John Doe",
payment_instrument->mutable_address_values());
diff --git a/chromium/components/autofill_assistant/browser/actions/execute_js_action.cc b/chromium/components/autofill_assistant/browser/actions/execute_js_action.cc
new file mode 100644
index 00000000000..d2f595bcd80
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/actions/execute_js_action.cc
@@ -0,0 +1,58 @@
+// Copyright 2022 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.
+
+#include "components/autofill_assistant/browser/actions/execute_js_action.h"
+
+#include "base/location.h"
+#include "base/time/time.h"
+#include "components/autofill_assistant/browser/web/element_store.h"
+#include "components/autofill_assistant/browser/web/web_controller.h"
+
+namespace autofill_assistant {
+
+ExecuteJsAction::ExecuteJsAction(ActionDelegate* delegate,
+ const ActionProto& proto)
+ : Action(delegate, proto) {
+ DCHECK(proto.has_execute_js());
+}
+
+ExecuteJsAction::~ExecuteJsAction() = default;
+
+void ExecuteJsAction::InternalProcessAction(ProcessActionCallback callback) {
+ callback_ = std::move(callback);
+ const std::string& client_id = proto_.execute_js().client_id().identifier();
+ if (client_id.empty()) {
+ EndAction(ClientStatus(INVALID_ACTION));
+ }
+
+ ClientStatus status =
+ delegate_->GetElementStore()->GetElement(client_id, &element_);
+ if (!status.ok()) {
+ EndAction(status);
+ return;
+ }
+
+ if (proto_.execute_js().timeout_ms() > 0) {
+ timer_.Start(FROM_HERE,
+ base::Milliseconds(proto_.execute_js().timeout_ms()),
+ base::BindOnce(&ExecuteJsAction::EndAction,
+ weak_ptr_factory_.GetWeakPtr(),
+ ClientStatus(TIMED_OUT)));
+ }
+ delegate_->GetWebController()->ExecuteJS(
+ proto_.execute_js().js_snippet(), element_,
+ base::BindOnce(&ExecuteJsAction::EndAction,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void ExecuteJsAction::EndAction(const ClientStatus& status) {
+ if (!callback_) {
+ // Either the timer or the action already called here.
+ return;
+ }
+ UpdateProcessedAction(status);
+ std::move(callback_).Run(std::move(processed_action_proto_));
+}
+
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/actions/execute_js_action.h b/chromium/components/autofill_assistant/browser/actions/execute_js_action.h
new file mode 100644
index 00000000000..a2f462e3ec3
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/actions/execute_js_action.h
@@ -0,0 +1,42 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACTIONS_EXECUTE_JS_ACTION_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACTIONS_EXECUTE_JS_ACTION_H_
+
+#include "base/callback.h"
+#include "base/memory/weak_ptr.h"
+#include "base/timer/timer.h"
+#include "components/autofill_assistant/browser/actions/action.h"
+#include "components/autofill_assistant/browser/actions/action_delegate.h"
+#include "components/autofill_assistant/browser/dom_action.pb.h"
+#include "components/autofill_assistant/browser/web/element_finder.h"
+
+namespace autofill_assistant {
+
+// An action that runs the JS snippet on a single previously stored element.
+// No additional parameters are provided when running the snippet.
+class ExecuteJsAction : public Action {
+ public:
+ ExecuteJsAction(ActionDelegate* delegate, const ActionProto& proto);
+ ~ExecuteJsAction() override;
+
+ ExecuteJsAction(const ExecuteJsAction&) = delete;
+ ExecuteJsAction& operator=(const ExecuteJsAction&) = delete;
+
+ private:
+ // Overrides Action:
+ void InternalProcessAction(ProcessActionCallback callback) override;
+
+ void EndAction(const ClientStatus& status);
+
+ ElementFinder::Result element_;
+ ProcessActionCallback callback_;
+ base::OneShotTimer timer_;
+
+ base::WeakPtrFactory<ExecuteJsAction> weak_ptr_factory_{this};
+};
+
+} // namespace autofill_assistant
+#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACTIONS_EXECUTE_JS_ACTION_H_
diff --git a/chromium/components/autofill_assistant/browser/actions/execute_js_action_unittest.cc b/chromium/components/autofill_assistant/browser/actions/execute_js_action_unittest.cc
new file mode 100644
index 00000000000..2ae9f6f5cfc
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/actions/execute_js_action_unittest.cc
@@ -0,0 +1,150 @@
+// Copyright 2022 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.
+
+#include "components/autofill_assistant/browser/actions/execute_js_action.h"
+
+#include "base/test/gmock_callback_support.h"
+#include "base/test/mock_callback.h"
+#include "base/test/task_environment.h"
+#include "base/time/time.h"
+#include "components/autofill_assistant/browser/actions/action_test_utils.h"
+#include "components/autofill_assistant/browser/actions/mock_action_delegate.h"
+#include "components/autofill_assistant/browser/client_status.h"
+#include "components/autofill_assistant/browser/dom_action.pb.h"
+#include "components/autofill_assistant/browser/web/element_finder.h"
+#include "components/autofill_assistant/browser/web/element_store.h"
+#include "components/autofill_assistant/browser/web/mock_web_controller.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace autofill_assistant {
+namespace {
+
+using ::base::test::RunOnceCallback;
+using ::testing::_;
+using ::testing::Invoke;
+using ::testing::Pointee;
+using ::testing::Property;
+using ::testing::Return;
+
+const char kClientId[] = "1";
+const char kSnippet[] = "return 2;"; // ACTION_APPLIED
+
+class ExecuteJsActionTest : public testing::Test {
+ public:
+ ExecuteJsActionTest()
+ : task_environment_(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
+
+ void SetUp() override {
+ ON_CALL(mock_action_delegate_, GetWebController)
+ .WillByDefault(Return(&mock_web_controller_));
+ }
+
+ protected:
+ void Run() {
+ ActionProto action_proto;
+ *action_proto.mutable_execute_js() = proto_;
+ // Keep action alive so the timeout has a chance to expire.
+ action_ =
+ std::make_unique<ExecuteJsAction>(&mock_action_delegate_, action_proto);
+ action_->ProcessAction(callback_.Get());
+ }
+
+ base::test::TaskEnvironment task_environment_;
+ MockActionDelegate mock_action_delegate_;
+ MockWebController mock_web_controller_;
+ base::MockCallback<Action::ProcessActionCallback> callback_;
+ ExecuteJsProto proto_;
+ std::unique_ptr<ExecuteJsAction> action_;
+};
+
+TEST_F(ExecuteJsActionTest, EmptyClientIdFails) {
+ EXPECT_CALL(
+ callback_,
+ Run(Pointee(Property(&ProcessedActionProto::status, INVALID_ACTION))));
+
+ Run();
+}
+
+TEST_F(ExecuteJsActionTest, FailsIfElementDoesNotExist) {
+ EXPECT_CALL(callback_, Run(Pointee(Property(&ProcessedActionProto::status,
+ CLIENT_ID_RESOLUTION_FAILED))));
+
+ proto_.mutable_client_id()->set_identifier(kClientId);
+ Run();
+}
+
+TEST_F(ExecuteJsActionTest, ExecutesSnippetAndReturns) {
+ ElementFinder::Result element;
+ element.dom_object.object_data.object_id = "id";
+ mock_action_delegate_.GetElementStore()->AddElement(kClientId,
+ element.dom_object);
+
+ EXPECT_CALL(mock_web_controller_,
+ ExecuteJS(kSnippet, EqualsElement(element), _))
+ .WillOnce(RunOnceCallback<2>(OkClientStatus()));
+ EXPECT_CALL(
+ callback_,
+ Run(Pointee(Property(&ProcessedActionProto::status, ACTION_APPLIED))));
+
+ proto_.set_js_snippet(kSnippet);
+ proto_.mutable_client_id()->set_identifier(kClientId);
+ Run();
+}
+
+TEST_F(ExecuteJsActionTest, TimesOut) {
+ ElementFinder::Result element;
+ element.dom_object.object_data.object_id = "id";
+ mock_action_delegate_.GetElementStore()->AddElement(kClientId,
+ element.dom_object);
+
+ // Swallow the call and don't return to let the timeout trigger.
+ base::OnceCallback<void(const ClientStatus&)> captured_callback;
+ EXPECT_CALL(mock_web_controller_,
+ ExecuteJS(kSnippet, EqualsElement(element), _))
+ .WillOnce([&captured_callback](
+ const std::string& snippet,
+ const ElementFinder::Result& element,
+ base::OnceCallback<void(const ClientStatus&)> callback) {
+ captured_callback = std::move(callback);
+ });
+
+ proto_.set_js_snippet(kSnippet);
+ proto_.mutable_client_id()->set_identifier(kClientId);
+ proto_.set_timeout_ms(1000);
+ Run();
+
+ EXPECT_CALL(callback_,
+ Run(Pointee(Property(&ProcessedActionProto::status, TIMED_OUT))));
+ task_environment_.FastForwardBy(base::Milliseconds(2000));
+
+ // This callback should be ignored, it's too late. This should not report a
+ // success or crash.
+ std::move(captured_callback).Run(OkClientStatus());
+}
+
+TEST_F(ExecuteJsActionTest, DoesNotTimeOut) {
+ ElementFinder::Result element;
+ element.dom_object.object_data.object_id = "id";
+ mock_action_delegate_.GetElementStore()->AddElement(kClientId,
+ element.dom_object);
+
+ EXPECT_CALL(mock_web_controller_,
+ ExecuteJS(kSnippet, EqualsElement(element), _))
+ .WillOnce(RunOnceCallback<2>(OkClientStatus()));
+ EXPECT_CALL(
+ callback_,
+ Run(Pointee(Property(&ProcessedActionProto::status, ACTION_APPLIED))));
+
+ proto_.set_js_snippet(kSnippet);
+ proto_.mutable_client_id()->set_identifier(kClientId);
+ proto_.set_timeout_ms(1000);
+ Run();
+
+ // Moving forward in time causes the timer to expire. This should not report
+ // a failure or crash.
+ task_environment_.FastForwardBy(base::Milliseconds(2000));
+}
+
+} // namespace
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/actions/expect_navigation_action_unittest.cc b/chromium/components/autofill_assistant/browser/actions/expect_navigation_action_unittest.cc
new file mode 100644
index 00000000000..a12d8775624
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/actions/expect_navigation_action_unittest.cc
@@ -0,0 +1,41 @@
+// Copyright 2022 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.
+
+#include "components/autofill_assistant/browser/actions/expect_navigation_action.h"
+
+#include "base/test/gmock_callback_support.h"
+#include "base/test/mock_callback.h"
+#include "components/autofill_assistant/browser/actions/mock_action_delegate.h"
+#include "components/autofill_assistant/browser/service.pb.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace autofill_assistant {
+namespace {
+
+using ::testing::Property;
+
+class ExpectNavigationActionTest : public testing::Test {
+ protected:
+ void Run() {
+ ActionProto action_proto;
+ *action_proto.mutable_expect_navigation() = proto_;
+ ExpectNavigationAction action(&mock_action_delegate_, action_proto);
+ action.ProcessAction(callback_.Get());
+ }
+
+ MockActionDelegate mock_action_delegate_;
+ base::MockCallback<Action::ProcessActionCallback> callback_;
+ ExpectNavigationProto proto_;
+};
+
+TEST_F(ExpectNavigationActionTest, ExpectNavigation) {
+ EXPECT_CALL(mock_action_delegate_, ExpectNavigation);
+ EXPECT_CALL(
+ callback_,
+ Run(Pointee(Property(&ProcessedActionProto::status, ACTION_APPLIED))));
+ Run();
+}
+
+} // namespace
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/actions/mock_action_delegate.h b/chromium/components/autofill_assistant/browser/actions/mock_action_delegate.h
index 33dad0b1484..32de19640f8 100644
--- a/chromium/components/autofill_assistant/browser/actions/mock_action_delegate.h
+++ b/chromium/components/autofill_assistant/browser/actions/mock_action_delegate.h
@@ -25,6 +25,10 @@
#include "components/autofill_assistant/browser/web/web_controller.h"
#include "testing/gmock/include/gmock/gmock.h"
+namespace password_manager {
+class PasswordChangeSuccessTracker;
+}
+
namespace autofill_assistant {
class UserModel;
@@ -51,9 +55,10 @@ class MockActionDelegate : public ActionDelegate {
void(const Selector& selector,
base::OnceCallback<void(const ClientStatus&, base::TimeDelta)>&));
- MOCK_METHOD5(
+ MOCK_METHOD6(
WaitForDom,
void(base::TimeDelta max_wait_time,
+ bool allow_observer_mode,
bool allow_interrupt,
WaitForDomObserver* observer,
base::RepeatingCallback<void(
@@ -126,6 +131,8 @@ class MockActionDelegate : public ActionDelegate {
MOCK_CONST_METHOD0(GetUserData, UserData*());
MOCK_CONST_METHOD0(GetPersonalDataManager, autofill::PersonalDataManager*());
MOCK_CONST_METHOD0(GetWebsiteLoginManager, WebsiteLoginManager*());
+ MOCK_CONST_METHOD0(GetPasswordChangeSuccessTracker,
+ password_manager::PasswordChangeSuccessTracker*());
MOCK_CONST_METHOD0(GetWebContents, content::WebContents*());
MOCK_CONST_METHOD0(GetWebController, WebController*());
MOCK_CONST_METHOD0(GetEmailAddressForAccessTokenAccount, std::string());
diff --git a/chromium/components/autofill_assistant/browser/actions/navigate_action_unittest.cc b/chromium/components/autofill_assistant/browser/actions/navigate_action_unittest.cc
new file mode 100644
index 00000000000..884b4518fb9
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/actions/navigate_action_unittest.cc
@@ -0,0 +1,134 @@
+// Copyright 2022 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.
+
+#include "components/autofill_assistant/browser/actions/navigate_action.h"
+
+#include "base/test/gmock_callback_support.h"
+#include "base/test/mock_callback.h"
+#include "components/autofill_assistant/browser/actions/mock_action_delegate.h"
+#include "components/autofill_assistant/browser/service.pb.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/test/browser_task_environment.h"
+#include "content/public/test/test_browser_context.h"
+#include "content/public/test/test_renderer_host.h"
+#include "content/public/test/web_contents_tester.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "url/gurl.h"
+
+namespace autofill_assistant {
+namespace {
+
+using ::testing::Property;
+using ::testing::Return;
+
+class NavigateActionTest : public testing::Test {
+ public:
+ void SetUp() override {
+ web_contents_ = content::WebContentsTester::CreateTestWebContents(
+ &browser_context_, nullptr);
+ ON_CALL(mock_action_delegate_, GetWebContents)
+ .WillByDefault(Return(web_contents_.get()));
+ }
+
+ protected:
+ void Run() {
+ ActionProto action_proto;
+ *action_proto.mutable_navigate() = proto_;
+ NavigateAction action(&mock_action_delegate_, action_proto);
+ action.ProcessAction(callback_.Get());
+ }
+
+ content::BrowserTaskEnvironment task_environment_;
+ content::RenderViewHostTestEnabler rvh_test_enabler_;
+ content::TestBrowserContext browser_context_;
+ std::unique_ptr<content::WebContents> web_contents_;
+ MockActionDelegate mock_action_delegate_;
+ base::MockCallback<Action::ProcessActionCallback> callback_;
+ NavigateProto proto_;
+};
+
+TEST_F(NavigateActionTest, FailsForEmptyAction) {
+ EXPECT_CALL(mock_action_delegate_, ExpectNavigation).Times(0);
+ EXPECT_CALL(
+ callback_,
+ Run(Pointee(Property(&ProcessedActionProto::status, UNSUPPORTED))));
+
+ Run();
+}
+
+TEST_F(NavigateActionTest, LoadsSpecifiedUrl) {
+ EXPECT_CALL(mock_action_delegate_, ExpectNavigation);
+ EXPECT_CALL(mock_action_delegate_, LoadURL(GURL("https://navigate.com")));
+ EXPECT_CALL(
+ callback_,
+ Run(Pointee(Property(&ProcessedActionProto::status, ACTION_APPLIED))));
+
+ proto_.set_url("https://navigate.com");
+ Run();
+}
+
+TEST_F(NavigateActionTest, NavigatesBackwardIfPossible) {
+ content::WebContentsTester::For(web_contents_.get())
+ ->NavigateAndCommit(GURL("https://initial.com"));
+ content::WebContentsTester::For(web_contents_.get())
+ ->NavigateAndCommit(GURL("https://navigate.com"));
+
+ EXPECT_CALL(mock_action_delegate_, ExpectNavigation);
+ EXPECT_CALL(
+ callback_,
+ Run(Pointee(Property(&ProcessedActionProto::status, ACTION_APPLIED))));
+
+ EXPECT_EQ(web_contents_->GetLastCommittedURL(), GURL("https://navigate.com"));
+ EXPECT_TRUE(web_contents_->GetController().CanGoBack());
+ proto_.set_go_backward(true);
+ Run();
+ content::WebContentsTester::For(web_contents_.get())
+ ->CommitPendingNavigation();
+ EXPECT_EQ(web_contents_->GetLastCommittedURL(), GURL("https://initial.com"));
+}
+
+TEST_F(NavigateActionTest, FailsIfNavigatingBackwardIsNotPossible) {
+ EXPECT_CALL(mock_action_delegate_, ExpectNavigation).Times(0);
+ EXPECT_CALL(callback_, Run(Pointee(Property(&ProcessedActionProto::status,
+ PRECONDITION_FAILED))));
+
+ proto_.set_go_backward(true);
+ Run();
+}
+
+TEST_F(NavigateActionTest, NavigatesForwardIfPossible) {
+ content::WebContentsTester::For(web_contents_.get())
+ ->NavigateAndCommit(GURL("https://initial.com"));
+ content::WebContentsTester::For(web_contents_.get())
+ ->NavigateAndCommit(GURL("https://navigate.com"));
+ EXPECT_TRUE(web_contents_->GetController().CanGoBack());
+ web_contents_->GetController().GoBack();
+ content::WebContentsTester::For(web_contents_.get())
+ ->CommitPendingNavigation();
+
+ EXPECT_CALL(mock_action_delegate_, ExpectNavigation);
+ EXPECT_CALL(
+ callback_,
+ Run(Pointee(Property(&ProcessedActionProto::status, ACTION_APPLIED))));
+
+ EXPECT_EQ(web_contents_->GetLastCommittedURL(), GURL("https://initial.com"));
+ EXPECT_TRUE(web_contents_->GetController().CanGoForward());
+ proto_.set_go_forward(true);
+ Run();
+ content::WebContentsTester::For(web_contents_.get())
+ ->CommitPendingNavigation();
+ EXPECT_EQ(web_contents_->GetLastCommittedURL(), GURL("https://navigate.com"));
+}
+
+TEST_F(NavigateActionTest, FailsIfNavigatingForwardIsNotPossible) {
+ EXPECT_CALL(mock_action_delegate_, ExpectNavigation).Times(0);
+ EXPECT_CALL(callback_, Run(Pointee(Property(&ProcessedActionProto::status,
+ PRECONDITION_FAILED))));
+
+ proto_.set_go_forward(true);
+ Run();
+}
+
+} // namespace
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/actions/prompt_action.cc b/chromium/components/autofill_assistant/browser/actions/prompt_action.cc
index 5df34cf84fc..fb1d71d6b2a 100644
--- a/chromium/components/autofill_assistant/browser/actions/prompt_action.cc
+++ b/chromium/components/autofill_assistant/browser/actions/prompt_action.cc
@@ -14,7 +14,7 @@
#include "base/containers/flat_map.h"
#include "base/strings/string_number_conversions.h"
#include "components/autofill_assistant/browser/actions/action_delegate.h"
-#include "components/autofill_assistant/browser/element_precondition.h"
+#include "components/autofill_assistant/browser/service.pb.h"
#include "components/autofill_assistant/browser/web/element.h"
#include "url/gurl.h"
@@ -56,8 +56,13 @@ void PromptAction::InternalProcessAction(ProcessActionCallback callback) {
wait_time_stopwatch_.Start();
if (HasNonemptyPreconditions() || auto_select_ ||
proto_.prompt().allow_interrupt()) {
+ // TODO(b/219004758): Enable observer-based WaitForDom, which would require
+ // negating the preconditions that matched in the previous check, so that we
+ // are alerted every time one changes instead of every time one becomes
+ // true.
delegate_->WaitForDom(
- base::TimeDelta::Max(), proto_.prompt().allow_interrupt(),
+ /* max_wait_time= */ base::TimeDelta::Max(),
+ /* allow_observer_mode = */ false, proto_.prompt().allow_interrupt(),
/* observer= */ nullptr,
base::BindRepeating(&PromptAction::RegisterChecks,
weak_ptr_factory_.GetWeakPtr()),
@@ -83,15 +88,16 @@ void PromptAction::RegisterChecks(
UpdateUserActions();
for (size_t i = 0; i < preconditions_.size(); i++) {
- preconditions_[i]->Check(checker,
- base::BindOnce(&PromptAction::OnPreconditionResult,
- weak_ptr_factory_.GetWeakPtr(), i));
+ checker->AddElementConditionCheck(
+ preconditions_[i], base::BindOnce(&PromptAction::OnPreconditionResult,
+ weak_ptr_factory_.GetWeakPtr(), i));
}
if (auto_select_) {
- auto_select_->Check(checker,
- base::BindOnce(&PromptAction::OnAutoSelectCondition,
- weak_ptr_factory_.GetWeakPtr()));
+ checker->AddElementConditionCheck(
+ auto_select_.value(),
+ base::BindOnce(&PromptAction::OnAutoSelectCondition,
+ weak_ptr_factory_.GetWeakPtr()));
}
checker->AddAllDoneCallback(base::BindOnce(&PromptAction::OnElementChecksDone,
weak_ptr_factory_.GetWeakPtr(),
@@ -107,31 +113,30 @@ void PromptAction::SetupConditions() {
for (int i = 0; i < choice_count; i++) {
auto& choice_proto = proto_.prompt().choices(i);
- preconditions_[i] =
- std::make_unique<ElementPrecondition>(choice_proto.show_only_when());
- precondition_results_[i] = preconditions_[i]->empty();
+ preconditions_[i] = choice_proto.show_only_when();
+ precondition_results_[i] =
+ BatchElementChecker::IsElementConditionEmpty(preconditions_[i]);
positive_precondition_changes_[i] = false;
}
- ElementConditionsProto auto_select;
+ ElementConditionProto auto_select;
+ auto* auto_select_any_of = auto_select.mutable_any_of();
for (int i = 0; i < choice_count; i++) {
auto& choice_proto = proto_.prompt().choices(i);
if (choice_proto.has_auto_select_when()) {
- ElementConditionProto* condition = auto_select.add_conditions();
+ ElementConditionProto* condition = auto_select_any_of->add_conditions();
*condition = choice_proto.auto_select_when();
- condition->set_payload(base::NumberToString(i));
+ condition->set_tag(base::NumberToString(i));
}
}
- if (!auto_select.conditions().empty()) {
- ElementConditionProto auto_select_condition;
- *auto_select_condition.mutable_any_of() = auto_select;
- auto_select_ = std::make_unique<ElementPrecondition>(auto_select_condition);
+ if (!auto_select_any_of->conditions().empty()) {
+ auto_select_ = auto_select;
}
}
bool PromptAction::HasNonemptyPreconditions() {
for (const auto& precondition : preconditions_) {
- if (!precondition->empty())
+ if (!BatchElementChecker::IsElementConditionEmpty(precondition))
return true;
}
return false;
@@ -141,6 +146,7 @@ void PromptAction::OnPreconditionResult(
size_t choice_index,
const ClientStatus& status,
const std::vector<std::string>& ignored_payloads,
+ const std::vector<std::string>& ignored_tags,
const base::flat_map<std::string, DomObjectFrameStack>& ignored_elements) {
bool precondition_is_met = status.ok();
if (precondition_results_[choice_index] == precondition_is_met)
@@ -204,13 +210,14 @@ void PromptAction::UpdateTimings() {
void PromptAction::OnAutoSelectCondition(
const ClientStatus& status,
const std::vector<std::string>& payloads,
+ const std::vector<std::string>& tags,
const base::flat_map<std::string, DomObjectFrameStack>& ignored_elements) {
- if (payloads.empty())
+ if (tags.empty())
return;
// We want to select the first matching choice, so only the first entry of
// payloads matter.
- base::StringToInt(payloads[0], &auto_select_choice_index_);
+ base::StringToInt(tags[0], &auto_select_choice_index_);
// Calling OnSuggestionChosen() is delayed until try_done, as it indirectly
// deletes the batch element checker, which isn't supported from an element
@@ -273,6 +280,8 @@ void PromptAction::OnSuggestionChosen(int choice_index) {
processed_action_proto_->mutable_prompt_choice()->set_server_payload(
proto_.prompt().choices(choice_index).server_payload());
+ processed_action_proto_->mutable_prompt_choice()->set_choice_tag(
+ proto_.prompt().choices(choice_index).tag());
EndAction(ClientStatus(ACTION_APPLIED));
}
diff --git a/chromium/components/autofill_assistant/browser/actions/prompt_action.h b/chromium/components/autofill_assistant/browser/actions/prompt_action.h
index fa055a9dca2..742e780aa24 100644
--- a/chromium/components/autofill_assistant/browser/actions/prompt_action.h
+++ b/chromium/components/autofill_assistant/browser/actions/prompt_action.h
@@ -15,9 +15,9 @@
#include "components/autofill_assistant/browser/actions/action.h"
#include "components/autofill_assistant/browser/batch_element_checker.h"
#include "components/autofill_assistant/browser/chip.h"
-#include "components/autofill_assistant/browser/element_precondition.h"
#include "components/autofill_assistant/browser/user_action.h"
#include "components/autofill_assistant/browser/web/element.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
namespace autofill_assistant {
@@ -47,11 +47,13 @@ class PromptAction : public Action {
size_t choice_index,
const ClientStatus& status,
const std::vector<std::string>& ignored_payloads,
+ const std::vector<std::string>& ignored_tags,
const base::flat_map<std::string, DomObjectFrameStack>& ignored_elements);
void UpdateUserActions();
void OnAutoSelectCondition(
const ClientStatus& status,
const std::vector<std::string>& payloads,
+ const std::vector<std::string>& tags,
const base::flat_map<std::string, DomObjectFrameStack>& ignored_elements);
void OnElementChecksDone(
base::OnceCallback<void(const ClientStatus&)> wait_for_dom_callback);
@@ -65,7 +67,7 @@ class PromptAction : public Action {
// preconditions_[i] contains the element preconditions for
// proto.prompt.choice[i].
- std::vector<std::unique_ptr<ElementPrecondition>> preconditions_;
+ std::vector<ElementConditionProto> preconditions_;
// precondition_results_[i] contains the last result reported by
// preconditions_[i].
@@ -85,7 +87,7 @@ class PromptAction : public Action {
// The action ends once this precondition matches. The payload points
// to the specific choice that matched.
- std::unique_ptr<ElementPrecondition> auto_select_;
+ absl::optional<ElementConditionProto> auto_select_;
// If >= 0, contains the index of the Choice to auto-select. Set based or the
// payload reported by |auto_select_|.
diff --git a/chromium/components/autofill_assistant/browser/actions/prompt_action_unittest.cc b/chromium/components/autofill_assistant/browser/actions/prompt_action_unittest.cc
index 7947e07de43..f8ba70d9c84 100644
--- a/chromium/components/autofill_assistant/browser/actions/prompt_action_unittest.cc
+++ b/chromium/components/autofill_assistant/browser/actions/prompt_action_unittest.cc
@@ -48,7 +48,7 @@ class PromptActionTest : public testing::Test {
std::move(callback).Run(ClientStatus(ELEMENT_RESOLUTION_FAILED),
std::make_unique<ElementFinder::Result>());
}));
- EXPECT_CALL(mock_action_delegate_, WaitForDom(_, _, _, _, _))
+ EXPECT_CALL(mock_action_delegate_, WaitForDom)
.WillRepeatedly(Invoke(this, &PromptActionTest::FakeWaitForDom));
ON_CALL(mock_action_delegate_, Prompt(_, _, _, _, _))
.WillByDefault(
@@ -68,6 +68,7 @@ class PromptActionTest : public testing::Test {
// until it gets a successful callback, then calls done_waiting_callback.
void FakeWaitForDom(
base::TimeDelta max_wait_time,
+ bool allow_observer_mode,
bool allow_interrupt,
WaitForDomObserver* observer,
base::RepeatingCallback<
@@ -163,6 +164,7 @@ TEST_F(PromptActionTest, SelectButtons) {
chip->set_text("Ok");
chip->set_type(HIGHLIGHTED_ACTION);
ok_proto->set_server_payload("ok");
+ ok_proto->set_tag("oktag");
auto* cancel_proto = prompt_proto_->add_choices();
cancel_proto->mutable_chip()->set_text("Cancel");
@@ -187,7 +189,9 @@ TEST_F(PromptActionTest, SelectButtons) {
Property(&ProcessedActionProto::prompt_choice,
Property(&PromptProto::Result::navigation_ended, false)),
Property(&ProcessedActionProto::prompt_choice,
- Property(&PromptProto::Result::server_payload, "ok"))))));
+ Property(&PromptProto::Result::server_payload, "ok")),
+ Property(&ProcessedActionProto::prompt_choice,
+ Property(&PromptProto::Result::choice_tag, "oktag"))))));
EXPECT_TRUE((*user_actions_)[0].HasCallback());
(*user_actions_)[0].RunCallback();
}
diff --git a/chromium/components/autofill_assistant/browser/actions/save_generated_password_action.cc b/chromium/components/autofill_assistant/browser/actions/save_generated_password_action.cc
index d8f0bd799f9..0f490eafdf4 100644
--- a/chromium/components/autofill_assistant/browser/actions/save_generated_password_action.cc
+++ b/chromium/components/autofill_assistant/browser/actions/save_generated_password_action.cc
@@ -9,6 +9,9 @@
#include "components/autofill_assistant/browser/actions/action_delegate.h"
#include "components/autofill_assistant/browser/client_status.h"
+#include "components/password_manager/core/browser/password_change_success_tracker.h"
+
+using password_manager::PasswordChangeSuccessTracker;
namespace autofill_assistant {
@@ -55,6 +58,11 @@ void SaveGeneratedPasswordAction::InternalProcessAction(
delegate_->GetWebsiteLoginManager()->CommitGeneratedPassword();
+ delegate_->GetPasswordChangeSuccessTracker()->OnChangePasswordFlowCompleted(
+ delegate_->GetUserData()->selected_login_->origin,
+ delegate_->GetUserData()->selected_login_->username,
+ PasswordChangeSuccessTracker::EndEvent::kAutomatedGeneratedPasswordFlow);
+
EndAction(ClientStatus(ACTION_APPLIED));
}
diff --git a/chromium/components/autofill_assistant/browser/actions/save_generated_password_action_unittest.cc b/chromium/components/autofill_assistant/browser/actions/save_generated_password_action_unittest.cc
index 820cfe762d8..dcc79c4ea39 100644
--- a/chromium/components/autofill_assistant/browser/actions/save_generated_password_action_unittest.cc
+++ b/chromium/components/autofill_assistant/browser/actions/save_generated_password_action_unittest.cc
@@ -13,16 +13,21 @@
#include "components/autofill_assistant/browser/client_status.h"
#include "components/autofill_assistant/browser/mock_website_login_manager.h"
#include "components/autofill_assistant/browser/value_util.h"
+#include "components/password_manager/core/browser/mock_password_change_success_tracker.h"
#include "testing/gmock/include/gmock/gmock.h"
namespace {
const char kMemoryKeyForGeneratedPassword[] = "memory-key-for-generation";
+const char kOrigin[] = "https://example.com";
+const char kUsername[] = "username";
const char kGeneratedPassword[] = "mX.12pq";
} // namespace
namespace autofill_assistant {
using ::base::test::RunOnceCallback;
+using password_manager::MockPasswordChangeSuccessTracker;
+using password_manager::PasswordChangeSuccessTracker;
using ::testing::_;
using ::testing::Pointee;
using ::testing::Property;
@@ -34,6 +39,9 @@ class SaveGeneratedPasswordActionTest : public testing::Test {
ON_CALL(mock_action_delegate_, GetWebsiteLoginManager)
.WillByDefault(Return(&mock_website_login_manager_));
+ ON_CALL(mock_action_delegate_, GetPasswordChangeSuccessTracker)
+ .WillByDefault(Return(&mock_password_change_success_tracker_));
+
ON_CALL(mock_action_delegate_, GetUserData)
.WillByDefault(Return(&user_data_));
@@ -45,6 +53,7 @@ class SaveGeneratedPasswordActionTest : public testing::Test {
protected:
MockActionDelegate mock_action_delegate_;
MockWebsiteLoginManager mock_website_login_manager_;
+ MockPasswordChangeSuccessTracker mock_password_change_success_tracker_;
base::MockCallback<Action::ProcessActionCallback> callback_;
ActionProto proto_;
UserData user_data_;
@@ -55,6 +64,7 @@ TEST_F(SaveGeneratedPasswordActionTest, SavedPassword) {
proto_.mutable_save_generated_password();
save_password_proto->set_memory_key(kMemoryKeyForGeneratedPassword);
+ user_data_.selected_login_.emplace(GURL(kOrigin), kUsername);
user_data_.SetAdditionalValue(kMemoryKeyForGeneratedPassword,
SimpleValue(std::string(kGeneratedPassword)));
@@ -67,7 +77,12 @@ TEST_F(SaveGeneratedPasswordActionTest, SavedPassword) {
callback_,
Run(Pointee(Property(&ProcessedActionProto::status, ACTION_APPLIED))));
- EXPECT_CALL(mock_website_login_manager_, CommitGeneratedPassword).Times(1);
+ EXPECT_CALL(mock_website_login_manager_, CommitGeneratedPassword);
+ EXPECT_CALL(
+ mock_password_change_success_tracker_,
+ OnChangePasswordFlowCompleted(GURL(kOrigin), kUsername,
+ PasswordChangeSuccessTracker::EndEvent::
+ kAutomatedGeneratedPasswordFlow));
action.ProcessAction(callback_.Get());
diff --git a/chromium/components/autofill_assistant/browser/actions/save_submitted_password_action.cc b/chromium/components/autofill_assistant/browser/actions/save_submitted_password_action.cc
index 76b26a5f589..9fc30ffa832 100644
--- a/chromium/components/autofill_assistant/browser/actions/save_submitted_password_action.cc
+++ b/chromium/components/autofill_assistant/browser/actions/save_submitted_password_action.cc
@@ -9,6 +9,9 @@
#include "components/autofill_assistant/browser/actions/action_delegate.h"
#include "components/autofill_assistant/browser/client_status.h"
+#include "components/password_manager/core/browser/password_change_success_tracker.h"
+
+using password_manager::PasswordChangeSuccessTracker;
namespace autofill_assistant {
@@ -30,6 +33,11 @@ void SaveSubmittedPasswordAction::InternalProcessAction(
}
delegate_->GetWebsiteLoginManager()->SaveSubmittedPassword();
+ delegate_->GetPasswordChangeSuccessTracker()->OnChangePasswordFlowCompleted(
+ delegate_->GetUserData()->selected_login_->origin,
+ delegate_->GetUserData()->selected_login_->username,
+ PasswordChangeSuccessTracker::EndEvent::kAutomatedOwnPasswordFlow);
+
EndAction(ClientStatus(ACTION_APPLIED));
}
diff --git a/chromium/components/autofill_assistant/browser/actions/save_submitted_password_action_unittest.cc b/chromium/components/autofill_assistant/browser/actions/save_submitted_password_action_unittest.cc
index e424f16de08..b8123415614 100644
--- a/chromium/components/autofill_assistant/browser/actions/save_submitted_password_action_unittest.cc
+++ b/chromium/components/autofill_assistant/browser/actions/save_submitted_password_action_unittest.cc
@@ -9,10 +9,18 @@
#include "components/autofill_assistant/browser/actions/mock_action_delegate.h"
#include "components/autofill_assistant/browser/client_status.h"
#include "components/autofill_assistant/browser/mock_website_login_manager.h"
+#include "components/password_manager/core/browser/mock_password_change_success_tracker.h"
#include "testing/gmock/include/gmock/gmock.h"
+namespace {
+const char kOrigin[] = "https://example.com";
+const char kUsername[] = "username";
+} // namespace
+
namespace autofill_assistant {
+using password_manager::MockPasswordChangeSuccessTracker;
+using password_manager::PasswordChangeSuccessTracker;
using ::testing::Pointee;
using ::testing::Property;
using ::testing::Return;
@@ -22,24 +30,40 @@ class SaveSubmittedPasswordActionTest : public testing::Test {
void SetUp() override {
ON_CALL(mock_action_delegate_, GetWebsiteLoginManager)
.WillByDefault(Return(&mock_website_login_manager_));
+
+ ON_CALL(mock_action_delegate_, GetPasswordChangeSuccessTracker)
+ .WillByDefault(Return(&mock_password_change_success_tracker_));
+
+ ON_CALL(mock_action_delegate_, GetUserData)
+ .WillByDefault(Return(&user_data_));
}
protected:
MockActionDelegate mock_action_delegate_;
MockWebsiteLoginManager mock_website_login_manager_;
+ MockPasswordChangeSuccessTracker mock_password_change_success_tracker_;
base::MockCallback<Action::ProcessActionCallback> callback_;
ActionProto proto_;
+ UserData user_data_;
};
TEST_F(SaveSubmittedPasswordActionTest, SaveSubmittedPasswordSuccess) {
SaveSubmittedPasswordAction action(&mock_action_delegate_, proto_);
+ user_data_.selected_login_.emplace(GURL(kOrigin), kUsername);
+
EXPECT_CALL(mock_website_login_manager_, ReadyToCommitSubmittedPassword)
.WillOnce(Return(true));
- EXPECT_CALL(mock_website_login_manager_, SaveSubmittedPassword).Times(1);
+ EXPECT_CALL(mock_website_login_manager_, SaveSubmittedPassword);
+ EXPECT_CALL(
+ mock_password_change_success_tracker_,
+ OnChangePasswordFlowCompleted(
+ GURL(kOrigin), kUsername,
+ PasswordChangeSuccessTracker::EndEvent::kAutomatedOwnPasswordFlow));
EXPECT_CALL(
callback_,
Run(Pointee(Property(&ProcessedActionProto::status, ACTION_APPLIED))));
+
action.ProcessAction(callback_.Get());
}
diff --git a/chromium/components/autofill_assistant/browser/actions/show_generic_ui_action.cc b/chromium/components/autofill_assistant/browser/actions/show_generic_ui_action.cc
index 1829a360f42..67ba874e9f2 100644
--- a/chromium/components/autofill_assistant/browser/actions/show_generic_ui_action.cc
+++ b/chromium/components/autofill_assistant/browser/actions/show_generic_ui_action.cc
@@ -7,6 +7,7 @@
#include <utility>
#include "base/containers/flat_map.h"
+#include "base/ranges/algorithm.h"
#include "components/autofill_assistant/browser/actions/action_delegate.h"
#include "components/autofill_assistant/browser/client_status.h"
#include "components/autofill_assistant/browser/user_data_util.h"
@@ -17,79 +18,7 @@
namespace autofill_assistant {
-namespace {
-
-void WriteCreditCardsToUserModel(
- std::unique_ptr<std::vector<std::unique_ptr<autofill::CreditCard>>>
- credit_cards,
- const ShowGenericUiProto::RequestAutofillCreditCards& proto,
- UserModel* user_model) {
- DCHECK(credit_cards);
- DCHECK(user_model);
- ValueProto model_value;
- model_value.set_is_client_side_only(true);
- for (const auto& credit_card : *credit_cards) {
- DCHECK(!credit_card->guid().empty());
- model_value.mutable_credit_cards()->add_values()->set_guid(
- credit_card->guid());
- }
- user_model->SetAutofillCreditCards(std::move(credit_cards));
- user_model->SetValue(proto.model_identifier(), model_value);
-}
-
-void WriteProfilesToUserModel(
- std::unique_ptr<std::vector<std::unique_ptr<autofill::AutofillProfile>>>
- profiles,
- const ShowGenericUiProto::RequestAutofillProfiles& proto,
- UserModel* user_model) {
- DCHECK(profiles);
- DCHECK(user_model);
- ValueProto model_value;
- model_value.set_is_client_side_only(true);
- for (const auto& profile : *profiles) {
- DCHECK(!profile->guid().empty());
- model_value.mutable_profiles()->add_values()->set_guid(profile->guid());
- }
- user_model->SetAutofillProfiles(std::move(profiles));
- user_model->SetValue(proto.model_identifier(), model_value);
-}
-
-void WriteLoginOptionsToUserModel(
- const ShowGenericUiProto::RequestLoginOptions& proto,
- UserModel* user_model,
- std::vector<WebsiteLoginManager::Login> logins) {
- DCHECK(user_model);
- ValueProto model_value;
- model_value.set_is_client_side_only(true);
- for (const auto& login_option : proto.login_options()) {
- switch (login_option.type_case()) {
- case ShowGenericUiProto::RequestLoginOptions::LoginOption::
- kCustomLoginOption:
- *model_value.mutable_login_options()->add_values() =
- login_option.custom_login_option();
- break;
- case ShowGenericUiProto::RequestLoginOptions::LoginOption::
- kPasswordManagerLogins: {
- for (const auto& login : logins) {
- auto* option = model_value.mutable_login_options()->add_values();
- option->set_label(login.username);
- option->set_sublabel(
- login_option.password_manager_logins().sublabel());
- option->set_payload(login_option.password_manager_logins().payload());
- }
- break;
- }
- case ShowGenericUiProto::RequestLoginOptions::LoginOption::TYPE_NOT_SET:
- NOTREACHED();
- break;
- }
- }
- user_model->SetValue(proto.model_identifier(), model_value);
-}
-} // namespace
-
void ShowGenericUiAction::OnInterruptStarted() {
- delegate_->GetPersonalDataManager()->RemoveObserver(this);
delegate_->ClearGenericUi();
}
@@ -109,9 +38,7 @@ ShowGenericUiAction::ShowGenericUiAction(ActionDelegate* delegate,
DCHECK(proto_.has_show_generic_ui());
}
-ShowGenericUiAction::~ShowGenericUiAction() {
- delegate_->GetPersonalDataManager()->RemoveObserver(this);
-}
+ShowGenericUiAction::~ShowGenericUiAction() = default;
bool ShowGenericUiAction::ShouldInterruptOnPause() const {
return true;
@@ -155,27 +82,6 @@ void ShowGenericUiAction::InternalProcessAction(
delegate_->GetUserModel()->SetValue(additional_value.model_identifier(),
value);
}
- if (proto_.show_generic_ui().has_request_login_options()) {
- auto login_options =
- proto_.show_generic_ui().request_login_options().login_options();
- if (std::find_if(login_options.begin(), login_options.end(),
- [&](const auto& option) {
- return option.type_case() ==
- ShowGenericUiProto::RequestLoginOptions::
- LoginOption::kPasswordManagerLogins;
- }) != login_options.end()) {
- delegate_->GetWebsiteLoginManager()->GetLoginsForUrl(
- delegate_->GetWebContents()->GetLastCommittedURL(),
- base::BindOnce(&WriteLoginOptionsToUserModel,
- proto_.show_generic_ui().request_login_options(),
- delegate_->GetUserModel()));
- } else {
- WriteLoginOptionsToUserModel(
- proto_.show_generic_ui().request_login_options(),
- delegate_->GetUserModel(),
- /* logins = */ std::vector<WebsiteLoginManager::Login>());
- }
- }
base::OnceCallback<void()> end_on_navigation_callback;
if (proto_.show_generic_ui().end_on_navigation()) {
@@ -203,27 +109,29 @@ void ShowGenericUiAction::OnViewInflationFinished(bool first_inflation,
return;
}
- delegate_->GetPersonalDataManager()->AddObserver(this);
- OnPersonalDataChanged();
-
if (!first_inflation) {
return;
}
for (const auto& element_check :
proto_.show_generic_ui().periodic_element_checks().element_checks()) {
- preconditions_.emplace_back(std::make_unique<ElementPrecondition>(
- element_check.element_condition()));
+ preconditions_.emplace_back(element_check.element_condition());
}
if (proto_.show_generic_ui().allow_interrupt() ||
- std::any_of(
- preconditions_.begin(), preconditions_.end(),
- [&](const auto& precondition) { return !precondition->empty(); })) {
+ base::ranges::any_of(preconditions_, [&](const auto& precondition) {
+ return !BatchElementChecker::IsElementConditionEmpty(precondition);
+ })) {
has_pending_wait_for_dom_ = true;
+ // TODO(b/219004758): Enable observer-based WaitForDom, which would require
+ // negating the preconditions that matched in the previous check, so that we
+ // are alerted every time one changes instead of every time one becomes
+ // true.
delegate_->WaitForDom(
- base::TimeDelta::Max(), proto_.show_generic_ui().allow_interrupt(),
- this,
+ /* max_wait_time= */ base::TimeDelta::Max(),
+ /* allow_observer_mode = */ false,
+ proto_.show_generic_ui().allow_interrupt(),
+ /* observer= */ this,
base::BindRepeating(&ShowGenericUiAction::RegisterChecks,
weak_ptr_factory_.GetWeakPtr()),
base::BindOnce(&ShowGenericUiAction::OnWaitForElementTimed,
@@ -252,9 +160,10 @@ void ShowGenericUiAction::RegisterChecks(
}
for (size_t i = 0; i < preconditions_.size(); i++) {
- preconditions_[i]->Check(
- checker, base::BindOnce(&ShowGenericUiAction::OnPreconditionResult,
- weak_ptr_factory_.GetWeakPtr(), i));
+ checker->AddElementConditionCheck(
+ preconditions_[i],
+ base::BindOnce(&ShowGenericUiAction::OnPreconditionResult,
+ weak_ptr_factory_.GetWeakPtr(), i));
}
// Let WaitForDom know we're still waiting for elements.
checker->AddAllDoneCallback(base::BindOnce(
@@ -266,6 +175,7 @@ void ShowGenericUiAction::OnPreconditionResult(
size_t precondition_index,
const ClientStatus& status,
const std::vector<std::string>& ignored_payloads,
+ const std::vector<std::string>& ignored_tags,
const base::flat_map<std::string, DomObjectFrameStack>& ignored_elements) {
if (should_end_action_) {
return;
@@ -344,31 +254,4 @@ void ShowGenericUiAction::EndAction(const ClientStatus& status) {
std::move(callback_).Run(std::move(processed_action_proto_));
}
-void ShowGenericUiAction::OnPersonalDataChanged() {
- if (proto_.show_generic_ui().has_request_profiles()) {
- auto profiles = std::make_unique<
- std::vector<std::unique_ptr<autofill::AutofillProfile>>>();
- for (const auto* profile :
- delegate_->GetPersonalDataManager()->GetProfilesToSuggest()) {
- profiles->emplace_back(user_data::MakeUniqueFromProfile(*profile));
- }
- WriteProfilesToUserModel(std::move(profiles),
- proto_.show_generic_ui().request_profiles(),
- delegate_->GetUserModel());
- }
-
- if (proto_.show_generic_ui().has_request_credit_cards()) {
- auto credit_cards =
- std::make_unique<std::vector<std::unique_ptr<autofill::CreditCard>>>();
- for (const auto* credit_card :
- delegate_->GetPersonalDataManager()->GetCreditCardsToSuggest(true)) {
- credit_cards->emplace_back(
- std::make_unique<autofill::CreditCard>(*credit_card));
- }
- WriteCreditCardsToUserModel(std::move(credit_cards),
- proto_.show_generic_ui().request_credit_cards(),
- delegate_->GetUserModel());
- }
-}
-
} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/actions/show_generic_ui_action.h b/chromium/components/autofill_assistant/browser/actions/show_generic_ui_action.h
index bca744ddf8d..d0f16ff1961 100644
--- a/chromium/components/autofill_assistant/browser/actions/show_generic_ui_action.h
+++ b/chromium/components/autofill_assistant/browser/actions/show_generic_ui_action.h
@@ -8,20 +8,15 @@
#include "base/callback.h"
#include "base/containers/flat_map.h"
#include "base/memory/weak_ptr.h"
-#include "components/autofill/core/browser/personal_data_manager.h"
-#include "components/autofill/core/browser/personal_data_manager_observer.h"
#include "components/autofill_assistant/browser/actions/action.h"
-#include "components/autofill_assistant/browser/element_precondition.h"
+#include "components/autofill_assistant/browser/batch_element_checker.h"
#include "components/autofill_assistant/browser/wait_for_dom_observer.h"
#include "components/autofill_assistant/browser/web/element.h"
-#include "components/autofill_assistant/browser/website_login_manager.h"
namespace autofill_assistant {
// Action to show generic UI in the sheet.
-class ShowGenericUiAction : public Action,
- public WaitForDomObserver,
- public autofill::PersonalDataManagerObserver {
+class ShowGenericUiAction : public Action, public WaitForDomObserver {
public:
explicit ShowGenericUiAction(ActionDelegate* delegate,
const ActionProto& proto);
@@ -48,6 +43,7 @@ class ShowGenericUiAction : public Action,
size_t choice_index,
const ClientStatus& status,
const std::vector<std::string>& ignored_payloads,
+ const std::vector<std::string>& ignored_tags,
const base::flat_map<std::string, DomObjectFrameStack>& ignored_elements);
void OnElementChecksDone(
base::OnceCallback<void(const ClientStatus&)> wait_for_dom_callback);
@@ -61,13 +57,10 @@ class ShowGenericUiAction : public Action,
const ClientStatus& status);
void OnNavigationEnded();
- // From autofill::PersonalDataManagerObserver.
- void OnPersonalDataChanged() override;
-
base::TimeTicks wait_time_start_;
bool has_pending_wait_for_dom_ = false;
bool should_end_action_ = false;
- std::vector<std::unique_ptr<ElementPrecondition>> preconditions_;
+ std::vector<ElementConditionProto> preconditions_;
ProcessActionCallback callback_;
base::WeakPtrFactory<ShowGenericUiAction> weak_ptr_factory_{this};
};
diff --git a/chromium/components/autofill_assistant/browser/actions/show_generic_ui_action_unittest.cc b/chromium/components/autofill_assistant/browser/actions/show_generic_ui_action_unittest.cc
index 091a81d4162..d8066870a12 100644
--- a/chromium/components/autofill_assistant/browser/actions/show_generic_ui_action_unittest.cc
+++ b/chromium/components/autofill_assistant/browser/actions/show_generic_ui_action_unittest.cc
@@ -251,207 +251,6 @@ TEST_F(ShowGenericUiActionTest, ClientOnlyValuesDoNotLeaveDevice) {
Run();
}
-TEST_F(ShowGenericUiActionTest, RequestProfiles) {
- autofill::AutofillProfile profile_a(base::GenerateGUID(), kFakeUrl);
- autofill::test::SetProfileInfo(
- &profile_a, "Marion", "Mitchell", "Morrison", "marion@me.xyz", "Fox",
- "123 Zoo St.", "unit 5", "Hollywood", "CA", "91601", "US", "16505678910");
- AutofillProfileProto profile_a_proto;
- profile_a_proto.set_guid(profile_a.guid());
-
- ON_CALL(mock_personal_data_manager_, IsAutofillProfileEnabled)
- .WillByDefault(Return(true));
- ON_CALL(mock_personal_data_manager_, GetProfiles)
- .WillByDefault(
- Return(std::vector<autofill::AutofillProfile*>({&profile_a})));
-
- proto_.mutable_request_profiles()->set_model_identifier("profiles");
- // Keep action alive by storing it in local variable.
- auto action = Run();
-
- EXPECT_THAT(user_model_.GetProfile(profile_a_proto)->Compare(profile_a),
- Eq(0));
- ValueProto expected_value;
- expected_value.set_is_client_side_only(true);
- expected_value.mutable_profiles()->add_values()->set_guid(profile_a.guid());
- EXPECT_EQ(*user_model_.GetValue("profiles"), expected_value);
-
- // Add second profile.
- autofill::AutofillProfile profile_b(base::GenerateGUID(), kFakeUrl);
- autofill::test::SetProfileInfo(&profile_b, "John", "", "Doe",
- "editor@gmail.com", "", "203 Barfield Lane",
- "", "Mountain View", "CA", "94043", "US",
- "+12345678901");
- AutofillProfileProto profile_b_proto;
- profile_b_proto.set_guid(profile_b.guid());
- ON_CALL(mock_personal_data_manager_, GetProfiles)
- .WillByDefault(Return(
- std::vector<autofill::AutofillProfile*>({&profile_a, &profile_b})));
- mock_personal_data_manager_.NotifyPersonalDataObserver();
- EXPECT_THAT(user_model_.GetProfile(profile_a_proto)->Compare(profile_a),
- Eq(0));
- EXPECT_THAT(user_model_.GetProfile(profile_b_proto)->Compare(profile_b),
- Eq(0));
- expected_value.mutable_profiles()->add_values()->set_guid(profile_b.guid());
- EXPECT_THAT(user_model_.GetValue("profiles")->profiles().values(),
- UnorderedElementsAreArray(expected_value.profiles().values()));
-
- // Remove profile_a.
- ON_CALL(mock_personal_data_manager_, GetProfiles)
- .WillByDefault(
- Return(std::vector<autofill::AutofillProfile*>({&profile_b})));
- mock_personal_data_manager_.NotifyPersonalDataObserver();
- EXPECT_EQ(user_model_.GetProfile(profile_a_proto), nullptr);
- EXPECT_THAT(user_model_.GetProfile(profile_b_proto)->Compare(profile_b),
- Eq(0));
- expected_value.Clear();
- expected_value.set_is_client_side_only(true);
- expected_value.mutable_profiles()->add_values()->set_guid(profile_b.guid());
- EXPECT_THAT(user_model_.GetValue("profiles")->profiles().values(),
- UnorderedElementsAreArray(expected_value.profiles().values()));
-
- // After the action has ended, updates to the PDM are ignored.
- action.reset();
- ON_CALL(mock_personal_data_manager_, GetProfiles)
- .WillByDefault(Return(
- std::vector<autofill::AutofillProfile*>({&profile_a, &profile_b})));
- mock_personal_data_manager_.NotifyPersonalDataObserver();
- EXPECT_EQ(user_model_.GetProfile(profile_a_proto), nullptr);
- EXPECT_THAT(user_model_.GetProfile(profile_b_proto)->Compare(profile_b),
- Eq(0));
- expected_value.Clear();
- expected_value.set_is_client_side_only(true);
- expected_value.mutable_profiles()->add_values()->set_guid(profile_b.guid());
- EXPECT_THAT(user_model_.GetValue("profiles")->profiles().values(),
- UnorderedElementsAreArray(expected_value.profiles().values()));
-}
-
-TEST_F(ShowGenericUiActionTest, RequestCreditCards) {
- ON_CALL(mock_personal_data_manager_, IsAutofillCreditCardEnabled)
- .WillByDefault(Return(true));
- ON_CALL(mock_personal_data_manager_, ShouldSuggestServerCards)
- .WillByDefault(Return(true));
- ON_CALL(mock_personal_data_manager_, IsAutofillProfileEnabled)
- .WillByDefault(Return(true));
-
- autofill::AutofillProfile profile_a(base::GenerateGUID(), kFakeUrl);
- autofill::test::SetProfileInfo(
- &profile_a, "Marion", "Mitchell", "Morrison", "marion@me.xyz", "Fox",
- "123 Zoo St.", "unit 5", "Hollywood", "CA", "91601", "US", "16505678910");
-
- autofill::CreditCard credit_card_a(base::GenerateGUID(), kFakeUrl);
- autofill::test::SetCreditCardInfo(&credit_card_a, "Marion Mitchell",
- "4111 1111 1111 1111", "01", "2050",
- profile_a.guid());
- AutofillCreditCardProto credit_card_a_proto;
- credit_card_a_proto.set_guid(credit_card_a.guid());
- ON_CALL(mock_personal_data_manager_, GetCreditCards)
- .WillByDefault(
- Return(std::vector<autofill::CreditCard*>({&credit_card_a})));
-
- proto_.mutable_request_credit_cards()->set_model_identifier("cards");
- // Keep action alive by storing it in local variable.
- auto action = Run();
-
- EXPECT_THAT(
- user_model_.GetCreditCard(credit_card_a_proto)->Compare(credit_card_a),
- Eq(0));
- ValueProto expected_value;
- expected_value.set_is_client_side_only(true);
- expected_value.mutable_credit_cards()->add_values()->set_guid(
- credit_card_a.guid());
- EXPECT_EQ(*user_model_.GetValue("cards"), expected_value);
-
- // Add second card.
- autofill::AutofillProfile profile_b(base::GenerateGUID(), kFakeUrl);
- autofill::test::SetProfileInfo(&profile_b, "John", "", "Doe",
- "editor@gmail.com", "", "203 Barfield Lane",
- "", "Mountain View", "CA", "94043", "US",
- "+12345678901");
- autofill::CreditCard credit_card_b(base::GenerateGUID(), kFakeUrl);
- autofill::test::SetCreditCardInfo(&credit_card_b, "John Doe",
- "4111 1111 1111 1111", "01", "2050",
- profile_b.guid());
- AutofillCreditCardProto credit_card_b_proto;
- credit_card_b_proto.set_guid(credit_card_b.guid());
- ON_CALL(mock_personal_data_manager_, GetCreditCards)
- .WillByDefault(Return(std::vector<autofill::CreditCard*>(
- {&credit_card_a, &credit_card_b})));
- mock_personal_data_manager_.NotifyPersonalDataObserver();
- EXPECT_THAT(
- user_model_.GetCreditCard(credit_card_a_proto)->Compare(credit_card_a),
- Eq(0));
- EXPECT_THAT(
- user_model_.GetCreditCard(credit_card_b_proto)->Compare(credit_card_b),
- Eq(0));
- expected_value.mutable_credit_cards()->add_values()->set_guid(
- credit_card_b.guid());
- EXPECT_THAT(
- user_model_.GetValue("cards")->credit_cards().values(),
- UnorderedElementsAreArray(expected_value.credit_cards().values()));
-
- // Remove credit_card_a.
- ON_CALL(mock_personal_data_manager_, GetCreditCards)
- .WillByDefault(
- Return(std::vector<autofill::CreditCard*>({&credit_card_b})));
- mock_personal_data_manager_.NotifyPersonalDataObserver();
- EXPECT_EQ(user_model_.GetCreditCard(credit_card_a_proto), nullptr);
- EXPECT_THAT(
- user_model_.GetCreditCard(credit_card_b_proto)->Compare(credit_card_b),
- Eq(0));
- expected_value.Clear();
- expected_value.set_is_client_side_only(true);
- expected_value.mutable_credit_cards()->add_values()->set_guid(
- credit_card_b.guid());
- EXPECT_THAT(
- user_model_.GetValue("cards")->credit_cards().values(),
- UnorderedElementsAreArray(expected_value.credit_cards().values()));
-
- // After the action has ended, updates to the PDM are ignored.
- action.reset();
- ON_CALL(mock_personal_data_manager_, GetCreditCards)
- .WillByDefault(Return(std::vector<autofill::CreditCard*>(
- {&credit_card_a, &credit_card_b})));
- mock_personal_data_manager_.NotifyPersonalDataObserver();
- EXPECT_EQ(user_model_.GetCreditCard(credit_card_a_proto), nullptr);
- EXPECT_THAT(
- user_model_.GetCreditCard(credit_card_b_proto)->Compare(credit_card_b),
- Eq(0));
- expected_value.Clear();
- expected_value.set_is_client_side_only(true);
- expected_value.mutable_credit_cards()->add_values()->set_guid(
- credit_card_b.guid());
- EXPECT_THAT(
- user_model_.GetValue("cards")->credit_cards().values(),
- UnorderedElementsAreArray(expected_value.credit_cards().values()));
-}
-
-TEST_F(ShowGenericUiActionTest, RequestLogins) {
- auto* request_login_options = proto_.mutable_request_login_options();
- request_login_options->set_model_identifier("login_options");
- auto* login_option_a =
- request_login_options->add_login_options()->mutable_custom_login_option();
- login_option_a->set_label("label_a");
- login_option_a->set_sublabel("sublabel_a");
- login_option_a->set_payload("payload_a");
-
- auto* login_option_b = request_login_options->add_login_options()
- ->mutable_password_manager_logins();
- login_option_b->set_sublabel("sublabel_b");
- login_option_b->set_payload("payload_b");
-
- Run();
-
- ValueProto expected_value;
- expected_value.set_is_client_side_only(true);
- *expected_value.mutable_login_options()->add_values() = *login_option_a;
- auto* expected_b = expected_value.mutable_login_options()->add_values();
- expected_b->set_label("user@example.com");
- expected_b->set_sublabel("sublabel_b");
- expected_b->set_payload("payload_b");
- EXPECT_EQ(*user_model_.GetValue("login_options"), expected_value);
-}
-
TEST_F(ShowGenericUiActionTest, ElementPreconditionMissesIdentifier) {
auto* element_check =
proto_.mutable_periodic_element_checks()->add_element_checks();
diff --git a/chromium/components/autofill_assistant/browser/actions/wait_for_document_action_unittest.cc b/chromium/components/autofill_assistant/browser/actions/wait_for_document_action_unittest.cc
index e4639e5b198..94c92a976da 100644
--- a/chromium/components/autofill_assistant/browser/actions/wait_for_document_action_unittest.cc
+++ b/chromium/components/autofill_assistant/browser/actions/wait_for_document_action_unittest.cc
@@ -62,6 +62,8 @@ class WaitForDocumentActionTest : public testing::Test {
MockWebController mock_web_controller_;
WaitForDocumentProto proto_;
ProcessedActionProto processed_action_;
+
+ private:
std::unique_ptr<WaitForDocumentAction> action_;
};
diff --git a/chromium/components/autofill_assistant/browser/actions/wait_for_dom_action.cc b/chromium/components/autofill_assistant/browser/actions/wait_for_dom_action.cc
index cfea7b3e8ea..46cfede75c1 100644
--- a/chromium/components/autofill_assistant/browser/actions/wait_for_dom_action.cc
+++ b/chromium/components/autofill_assistant/browser/actions/wait_for_dom_action.cc
@@ -69,8 +69,6 @@ void WaitForDomAction::InternalProcessAction(ProcessActionCallback callback) {
ReportActionResult(std::move(callback), ClientStatus(INVALID_ACTION));
return;
}
- wait_condition_ = std::make_unique<ElementPrecondition>(
- proto_.wait_for_dom().wait_condition());
delegate_->WaitForDomWithSlowWarning(
max_wait_time, proto_.wait_for_dom().allow_interrupt(),
/* observer= */ nullptr,
@@ -86,8 +84,8 @@ void WaitForDomAction::InternalProcessAction(ProcessActionCallback callback) {
void WaitForDomAction::CheckElements(
BatchElementChecker* checker,
base::OnceCallback<void(const ClientStatus&)> callback) {
- wait_condition_->Check(
- checker,
+ checker->AddElementConditionCheck(
+ proto_.wait_for_dom().wait_condition(),
base::BindOnce(&WaitForDomAction::OnWaitConditionDone,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
@@ -96,6 +94,7 @@ void WaitForDomAction::OnWaitConditionDone(
base::OnceCallback<void(const ClientStatus&)> callback,
const ClientStatus& status,
const std::vector<std::string>& payloads,
+ const std::vector<std::string>& tags,
const base::flat_map<std::string, DomObjectFrameStack>& elements) {
// Results are first cleared, as OnWaitConditionDone can be called more
// than once. Yet, we want report only the payloads sent with the final call
@@ -106,6 +105,9 @@ void WaitForDomAction::OnWaitConditionDone(
for (const std::string& payload : payloads) {
result->add_matching_condition_payloads(payload);
}
+ for (const std::string& tag : tags) {
+ result->add_matching_condition_tags(tag);
+ }
elements_ = elements;
diff --git a/chromium/components/autofill_assistant/browser/actions/wait_for_dom_action.h b/chromium/components/autofill_assistant/browser/actions/wait_for_dom_action.h
index 7e534217443..867c9f8cdf7 100644
--- a/chromium/components/autofill_assistant/browser/actions/wait_for_dom_action.h
+++ b/chromium/components/autofill_assistant/browser/actions/wait_for_dom_action.h
@@ -13,7 +13,6 @@
#include "base/memory/weak_ptr.h"
#include "components/autofill_assistant/browser/actions/action.h"
#include "components/autofill_assistant/browser/client_status.h"
-#include "components/autofill_assistant/browser/element_precondition.h"
#include "components/autofill_assistant/browser/service.pb.h"
#include "components/autofill_assistant/browser/web/element.h"
@@ -42,12 +41,12 @@ class WaitForDomAction : public Action {
base::OnceCallback<void(const ClientStatus&)> callback,
const ClientStatus& status,
const std::vector<std::string>& payloads,
+ const std::vector<std::string>& tags,
const base::flat_map<std::string, DomObjectFrameStack>& elements);
void ReportActionResult(ProcessActionCallback callback,
const ClientStatus& status);
void UpdateElementStore();
- std::unique_ptr<ElementPrecondition> wait_condition_;
base::flat_map<std::string, DomObjectFrameStack> elements_;
base::WeakPtrFactory<WaitForDomAction> weak_ptr_factory_{this};
diff --git a/chromium/components/autofill_assistant/browser/actions/wait_for_dom_action_unittest.cc b/chromium/components/autofill_assistant/browser/actions/wait_for_dom_action_unittest.cc
index c2506b15520..df0893215d9 100644
--- a/chromium/components/autofill_assistant/browser/actions/wait_for_dom_action_unittest.cc
+++ b/chromium/components/autofill_assistant/browser/actions/wait_for_dom_action_unittest.cc
@@ -181,20 +181,24 @@ TEST_F(WaitForDomActionTest, ReportMatchesToServer) {
auto* condition1 = any_of->add_conditions();
*condition1->mutable_match() = ToSelectorProto("#element1");
condition1->set_payload("1");
+ condition1->set_tag("1tag");
auto* condition2 = any_of->add_conditions();
*condition2->mutable_none_of()->add_conditions()->mutable_match() =
ToSelectorProto("#element2");
condition2->set_payload("2");
+ condition2->set_tag("2tag");
auto* condition3 = any_of->add_conditions();
*condition3->mutable_match() = ToSelectorProto("#element3");
condition3->set_payload("3");
+ condition3->set_tag("3tag");
auto* condition4 = any_of->add_conditions();
*condition4->mutable_none_of()->add_conditions()->mutable_match() =
ToSelectorProto("#element4");
condition4->set_payload("4");
+ condition4->set_tag("4tag");
// Condition 1 and 2 are met, conditions 3 and 4 are not.
@@ -204,6 +208,8 @@ TEST_F(WaitForDomActionTest, ReportMatchesToServer) {
EXPECT_THAT(capture.wait_for_dom_result().matching_condition_payloads(),
ElementsAre("1", "2"));
+ EXPECT_THAT(capture.wait_for_dom_result().matching_condition_tags(),
+ ElementsAre("1tag", "2tag"));
}
TEST_F(WaitForDomActionTest, StoreMatchForLater) {
diff --git a/chromium/components/autofill_assistant/browser/actions/wait_for_navigation_action_unittest.cc b/chromium/components/autofill_assistant/browser/actions/wait_for_navigation_action_unittest.cc
new file mode 100644
index 00000000000..e9f5a82b3bd
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/actions/wait_for_navigation_action_unittest.cc
@@ -0,0 +1,94 @@
+// Copyright 2022 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.
+
+#include "components/autofill_assistant/browser/actions/wait_for_navigation_action.h"
+
+#include "base/test/gmock_callback_support.h"
+#include "base/test/mock_callback.h"
+#include "base/test/task_environment.h"
+#include "base/time/time.h"
+#include "components/autofill_assistant/browser/actions/mock_action_delegate.h"
+#include "components/autofill_assistant/browser/service.pb.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace autofill_assistant {
+namespace {
+
+using ::testing::Property;
+using ::testing::Return;
+
+class WaitForNavigationActionTest : public testing::Test {
+ protected:
+ WaitForNavigationActionTest()
+ : task_environment_(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
+
+ void Run() {
+ ActionProto action_proto;
+ *action_proto.mutable_wait_for_navigation() = proto_;
+ action_ = std::make_unique<WaitForNavigationAction>(&mock_action_delegate_,
+ action_proto);
+ action_->ProcessAction(callback_.Get());
+ }
+
+ base::test::TaskEnvironment task_environment_;
+
+ MockActionDelegate mock_action_delegate_;
+ base::MockCallback<Action::ProcessActionCallback> callback_;
+ WaitForNavigationProto proto_;
+
+ private:
+ std::unique_ptr<WaitForNavigationAction> action_;
+};
+
+TEST_F(WaitForNavigationActionTest, FailsForUnexpectedNavigation) {
+ EXPECT_CALL(mock_action_delegate_, WaitForNavigation).WillOnce(Return(false));
+ EXPECT_CALL(
+ callback_,
+ Run(Pointee(Property(&ProcessedActionProto::status, INVALID_ACTION))));
+ Run();
+}
+
+TEST_F(WaitForNavigationActionTest, TimesOutWithoutNavigation) {
+ EXPECT_CALL(mock_action_delegate_, WaitForNavigation).WillOnce(Return(true));
+ EXPECT_CALL(callback_,
+ Run(Pointee(Property(&ProcessedActionProto::status, TIMED_OUT))));
+
+ proto_.set_timeout_ms(1000);
+ Run();
+ task_environment_.FastForwardBy(base::Seconds(2));
+}
+
+TEST_F(WaitForNavigationActionTest, ReturnsErrorStatusForNavigationError) {
+ EXPECT_CALL(mock_action_delegate_, WaitForNavigation)
+ .WillOnce([](base::OnceCallback<void(bool)> callback) {
+ std::move(callback).Run(false);
+ return true;
+ });
+ EXPECT_CALL(
+ callback_,
+ Run(Pointee(Property(&ProcessedActionProto::status, NAVIGATION_ERROR))));
+
+ proto_.set_timeout_ms(1000);
+ Run();
+}
+
+TEST_F(WaitForNavigationActionTest, SucceedsForSuccessfulNavigation) {
+ EXPECT_CALL(mock_action_delegate_, WaitForNavigation)
+ .WillOnce([](base::OnceCallback<void(bool)> callback) {
+ std::move(callback).Run(true);
+ return true;
+ });
+ EXPECT_CALL(
+ callback_,
+ Run(Pointee(Property(&ProcessedActionProto::status, ACTION_APPLIED))));
+
+ proto_.set_timeout_ms(1000);
+ Run();
+
+ // Should not crash. The callback has already been called.
+ task_environment_.FastForwardBy(base::Seconds(2));
+}
+
+} // namespace
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/autofill_assistant_factory.cc b/chromium/components/autofill_assistant/browser/autofill_assistant_factory.cc
new file mode 100644
index 00000000000..425214f1bdc
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/autofill_assistant_factory.cc
@@ -0,0 +1,23 @@
+// Copyright 2022 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.
+
+#include "components/autofill_assistant/browser/public/autofill_assistant_factory.h"
+
+#include "components/autofill_assistant/browser/autofill_assistant_impl.h"
+#include "components/version_info/channel.h"
+
+namespace autofill_assistant {
+
+// static
+std::unique_ptr<AutofillAssistant>
+AutofillAssistantFactory::CreateForBrowserContext(
+ content::BrowserContext* browser_context,
+ version_info::Channel channel,
+ const std::string& country_code,
+ const std::string& locale) {
+ return AutofillAssistantImpl::Create(browser_context, channel, country_code,
+ locale);
+}
+
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/autofill_assistant_impl.cc b/chromium/components/autofill_assistant/browser/autofill_assistant_impl.cc
new file mode 100644
index 00000000000..6cc251c28e6
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/autofill_assistant_impl.cc
@@ -0,0 +1,122 @@
+// Copyright 2022 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.
+
+#include "components/autofill_assistant/browser/autofill_assistant_impl.h"
+
+#include <vector>
+
+#include "components/autofill_assistant/browser/protocol_utils.h"
+#include "components/autofill_assistant/browser/service.pb.h"
+#include "components/autofill_assistant/browser/service/api_key_fetcher.h"
+#include "components/autofill_assistant/browser/service/cup_impl.h"
+#include "components/autofill_assistant/browser/service/server_url_fetcher.h"
+#include "components/autofill_assistant/browser/service/service_request_sender.h"
+#include "components/autofill_assistant/browser/service/service_request_sender_impl.h"
+#include "components/autofill_assistant/browser/service/simple_url_loader_factory.h"
+#include "components/version_info/channel.h"
+#include "components/version_info/version_info.h"
+#include "content/public/browser/browser_context.h"
+#include "net/http/http_status_code.h"
+
+namespace autofill_assistant {
+
+namespace {
+
+const char kIntentScriptParameterKey[] = "INTENT";
+
+void OnCapabilitiesResponse(
+ AutofillAssistant::GetCapabilitiesResponseCallback callback,
+ int http_status,
+ const std::string& response_str) {
+ std::vector<AutofillAssistant::CapabilitiesInfo> infos;
+ GetCapabilitiesByHashPrefixResponseProto resp;
+
+ if (http_status != net::HTTP_OK) {
+ VLOG(1) << "Failed to get script capabilities."
+ << ", http-status=" << http_status;
+ // TODO(b/209429727) Record network failure metrics.
+ std::move(callback).Run(http_status, infos);
+ return;
+ }
+
+ if (!resp.ParseFromString(response_str)) {
+ LOG(ERROR) << __func__ << " returned unparsable response";
+ // TODO(b/209429727) Record parsing failure metrics.
+ std::move(callback).Run(http_status, infos);
+ return;
+ }
+
+ for (const auto& match : resp.match_info()) {
+ AutofillAssistant::CapabilitiesInfo info;
+ info.url = match.url_match();
+
+ for (const auto& param : match.script_parameters_override()) {
+ info.script_parameters[param.name()] = param.value();
+ }
+
+ infos.push_back(info);
+ }
+ std::move(callback).Run(http_status, infos);
+}
+
+} // namespace
+
+// static
+std::unique_ptr<AutofillAssistantImpl> AutofillAssistantImpl::Create(
+ content::BrowserContext* browser_context,
+ version_info::Channel channel,
+ const std::string& country_code,
+ const std::string& locale) {
+ auto request_sender = std::make_unique<ServiceRequestSenderImpl>(
+ browser_context,
+ /* access_token_fetcher = */ nullptr,
+ std::make_unique<cup::CUPImplFactory>(),
+ std::make_unique<NativeURLLoaderFactory>(),
+ ApiKeyFetcher().GetAPIKey(channel),
+ /* auth_enabled = */ false,
+ /* disable_auth_if_no_access_token = */ true);
+ const ServerUrlFetcher& url_fetcher =
+ ServerUrlFetcher(ServerUrlFetcher::GetDefaultServerUrl());
+ return std::make_unique<AutofillAssistantImpl>(
+ std::move(request_sender), url_fetcher.GetCapabilitiesByHashEndpoint(),
+ country_code, locale);
+}
+
+AutofillAssistantImpl::AutofillAssistantImpl(
+ std::unique_ptr<ServiceRequestSender> request_sender,
+ const GURL& script_server_url,
+ const std::string& country_code,
+ const std::string& locale)
+ : request_sender_(std::move(request_sender)),
+ script_server_url_(script_server_url),
+ country_code_(country_code),
+ locale_(locale) {}
+
+AutofillAssistantImpl::~AutofillAssistantImpl() = default;
+
+void AutofillAssistantImpl::GetCapabilitiesByHashPrefix(
+ uint32_t hash_prefix_length,
+ const std::vector<uint64_t>& hash_prefixes,
+ const std::string& intent,
+ GetCapabilitiesResponseCallback callback) {
+ const ScriptParameters& parameters = {
+ base::flat_map<std::string, std::string>{
+ {kIntentScriptParameterKey, intent}}};
+
+ ClientContextProto client_context;
+ client_context.set_country(country_code_);
+ client_context.set_locale(locale_);
+ client_context.mutable_chrome()->set_chrome_version(
+ version_info::GetProductNameAndVersionForUserAgent());
+
+ request_sender_->SendRequest(
+ script_server_url_,
+ ProtocolUtils::CreateCapabilitiesByHashRequest(
+ hash_prefix_length, hash_prefixes, client_context, parameters),
+ base::BindOnce(&OnCapabilitiesResponse, std::move(callback)),
+ RpcType::GET_CAPABILITIES_BY_HASH_PREFIX);
+ return;
+}
+
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/autofill_assistant_impl.h b/chromium/components/autofill_assistant/browser/autofill_assistant_impl.h
new file mode 100644
index 00000000000..2479f8a7d91
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/autofill_assistant_impl.h
@@ -0,0 +1,52 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_AUTOFILL_ASSISTANT_IMPL_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_AUTOFILL_ASSISTANT_IMPL_H_
+
+#include <vector>
+
+#include "components/autofill_assistant/browser/public/autofill_assistant.h"
+#include "components/autofill_assistant/browser/service/service_request_sender.h"
+#include "components/version_info/version_info.h"
+#include "content/public/browser/browser_context.h"
+
+namespace autofill_assistant {
+
+class AutofillAssistantImpl : public autofill_assistant::AutofillAssistant {
+ public:
+ static std::unique_ptr<AutofillAssistantImpl> Create(
+ content::BrowserContext* browser_context,
+ version_info::Channel channel,
+ const std::string& country_code,
+ const std::string& locale);
+
+ AutofillAssistantImpl(std::unique_ptr<ServiceRequestSender> request_sender,
+ const GURL& script_server_url,
+ const std::string& country_code,
+ const std::string& locale);
+ AutofillAssistantImpl(const AutofillAssistantImpl&) = delete;
+ AutofillAssistantImpl& operator=(const AutofillAssistantImpl&) = delete;
+ ~AutofillAssistantImpl() override;
+
+ void GetCapabilitiesByHashPrefix(
+ uint32_t hash_prefix_length,
+ const std::vector<uint64_t>& hash_prefixes,
+ const std::string& intent,
+ GetCapabilitiesResponseCallback callback) override;
+
+ private:
+ // The request sender responsible for communicating with a remote endpoint.
+ std::unique_ptr<ServiceRequestSender> request_sender_;
+ // The RPC endpoint to send requests to.
+ GURL script_server_url_;
+ // The client's country code.
+ std::string country_code_;
+ // The client's locale.
+ std::string locale_;
+};
+
+} // namespace autofill_assistant
+
+#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_AUTOFILL_ASSISTANT_IMPL_H_
diff --git a/chromium/components/autofill_assistant/browser/autofill_assistant_impl_unittest.cc b/chromium/components/autofill_assistant/browser/autofill_assistant_impl_unittest.cc
new file mode 100644
index 00000000000..b7eed088e5e
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/autofill_assistant_impl_unittest.cc
@@ -0,0 +1,131 @@
+// Copyright 2022 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.
+
+#include "components/autofill_assistant/browser/autofill_assistant_impl.h"
+
+#include "base/memory/raw_ptr.h"
+#include "base/test/gmock_callback_support.h"
+#include "base/test/mock_callback.h"
+#include "components/autofill_assistant/browser/service.pb.h"
+#include "components/autofill_assistant/browser/service/mock_service_request_sender.h"
+#include "components/version_info/version_info.h"
+#include "net/http/http_status_code.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace autofill_assistant {
+namespace {
+
+using ::base::test::RunOnceCallback;
+using ::testing::_;
+using ::testing::NiceMock;
+using ::testing::Return;
+using ::testing::SaveArg;
+using ::testing::UnorderedElementsAreArray;
+
+const char kScriptServerUrl[] = "https://www.fake.backend.com/script_server";
+
+class AutofillAssistantImpTest : public testing::Test {
+ public:
+ AutofillAssistantImpTest() {
+ auto mock_request_sender =
+ std::make_unique<NiceMock<MockServiceRequestSender>>();
+ mock_request_sender_ = mock_request_sender.get();
+
+ service_ = std::make_unique<AutofillAssistantImpl>(
+ std::move(mock_request_sender), GURL(kScriptServerUrl), "US", "en-US");
+ }
+ ~AutofillAssistantImpTest() override = default;
+
+ protected:
+ base::MockCallback<AutofillAssistant::GetCapabilitiesResponseCallback>
+ mock_response_callback_;
+ raw_ptr<NiceMock<MockServiceRequestSender>> mock_request_sender_;
+ std::unique_ptr<AutofillAssistantImpl> service_;
+};
+
+} // namespace
+
+bool operator==(const AutofillAssistant::CapabilitiesInfo& lhs,
+ const AutofillAssistant::CapabilitiesInfo& rhs) {
+ return std::tie(lhs.url, lhs.script_parameters) ==
+ std::tie(rhs.url, rhs.script_parameters);
+}
+
+TEST_F(AutofillAssistantImpTest, GetCapabilitiesByHashPrefixEmptyRespose) {
+ EXPECT_CALL(*mock_request_sender_,
+ OnSendRequest(GURL(kScriptServerUrl), _, _,
+ RpcType::GET_CAPABILITIES_BY_HASH_PREFIX))
+ .WillOnce(RunOnceCallback<2>(net::HTTP_OK, ""));
+
+ EXPECT_CALL(
+ mock_response_callback_,
+ Run(net::HTTP_OK, std::vector<AutofillAssistant::CapabilitiesInfo>()));
+
+ service_->GetCapabilitiesByHashPrefix(16, {1339}, "DUMMY_INTENT",
+ mock_response_callback_.Get());
+}
+
+TEST_F(AutofillAssistantImpTest, BackendRequestFailed) {
+ EXPECT_CALL(*mock_request_sender_,
+ OnSendRequest(GURL(kScriptServerUrl), _, _,
+ RpcType::GET_CAPABILITIES_BY_HASH_PREFIX))
+ .WillOnce(RunOnceCallback<2>(net::HTTP_FORBIDDEN, ""));
+
+ EXPECT_CALL(mock_response_callback_,
+ Run(net::HTTP_FORBIDDEN,
+ std::vector<AutofillAssistant::CapabilitiesInfo>()));
+
+ service_->GetCapabilitiesByHashPrefix(16, {1339}, "DUMMY_INTENT",
+ mock_response_callback_.Get());
+}
+
+TEST_F(AutofillAssistantImpTest, ParsingError) {
+ EXPECT_CALL(*mock_request_sender_,
+ OnSendRequest(GURL(kScriptServerUrl), _, _,
+ RpcType::GET_CAPABILITIES_BY_HASH_PREFIX))
+ .WillOnce(RunOnceCallback<2>(net::HTTP_OK, "invalid"));
+
+ EXPECT_CALL(
+ mock_response_callback_,
+ Run(net::HTTP_OK, std::vector<AutofillAssistant::CapabilitiesInfo>()));
+
+ service_->GetCapabilitiesByHashPrefix(16, {1339}, "DUMMY_INTENT",
+ mock_response_callback_.Get());
+}
+
+TEST_F(AutofillAssistantImpTest, GetCapabilitiesByHashPrefix) {
+ GetCapabilitiesByHashPrefixResponseProto proto;
+ GetCapabilitiesByHashPrefixResponseProto::MatchInfoProto* match_info =
+ proto.add_match_info();
+ match_info->set_url_match("http://exampleA.com");
+ ScriptParameterProto* script_parameter =
+ match_info->add_script_parameters_override();
+ script_parameter->set_name("EXPERIMENT_IDS");
+ script_parameter->set_value("3345172");
+
+ GetCapabilitiesByHashPrefixResponseProto::MatchInfoProto* match_info2 =
+ proto.add_match_info();
+ match_info2->set_url_match("http://exampleB.com");
+
+ std::string serialized_proto;
+ proto.SerializeToString(&serialized_proto);
+
+ EXPECT_CALL(*mock_request_sender_,
+ OnSendRequest(GURL(kScriptServerUrl), _, _,
+ RpcType::GET_CAPABILITIES_BY_HASH_PREFIX))
+ .WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_proto));
+
+ EXPECT_CALL(
+ mock_response_callback_,
+ Run(net::HTTP_OK,
+ UnorderedElementsAreArray(
+ std::vector<AutofillAssistant::CapabilitiesInfo>{
+ {"http://exampleA.com", {{"EXPERIMENT_IDS", "3345172"}}},
+ {"http://exampleB.com", {}}})));
+
+ service_->GetCapabilitiesByHashPrefix(16, {1339}, "DUMMY_INTENT",
+ mock_response_callback_.Get());
+}
+
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/autofill_assistant_onboarding_fetcher.cc b/chromium/components/autofill_assistant/browser/autofill_assistant_onboarding_fetcher.cc
index 3d993f05610..0509a951a4f 100644
--- a/chromium/components/autofill_assistant/browser/autofill_assistant_onboarding_fetcher.cc
+++ b/chromium/components/autofill_assistant/browser/autofill_assistant_onboarding_fetcher.cc
@@ -7,7 +7,6 @@
#include "base/callback.h"
#include "base/containers/flat_map.h"
#include "base/json/json_reader.h"
-#include "base/metrics/histogram_functions.h"
#include "base/strings/string_util.h"
#include "components/autofill_assistant/browser/features.h"
#include "services/network/public/cpp/resource_request.h"
@@ -107,23 +106,22 @@ void AutofillAssistantOnboardingFetcher::StartFetch(const std::string& locale,
void AutofillAssistantOnboardingFetcher::OnFetchComplete(
std::unique_ptr<std::string> response_body) {
url_loader_.reset();
- ResultStatus result_status = ParseResponse(std::move(response_body));
- base::UmaHistogramEnumeration(
- "AutofillAssistant.AutofillAssistantOnboardingFetcher.ResultStatus",
- result_status);
+ Metrics::OnboardingFetcherResultStatus result_status =
+ ParseResponse(std::move(response_body));
+ Metrics::RecordOnboardingFetcherResult(result_status);
for (auto& callback : pending_callbacks_) {
std::move(callback).Run();
}
pending_callbacks_.clear();
}
-AutofillAssistantOnboardingFetcher::ResultStatus
+Metrics::OnboardingFetcherResultStatus
AutofillAssistantOnboardingFetcher::ParseResponse(
std::unique_ptr<std::string> response_body) {
onboarding_strings_.clear();
if (!response_body) {
- return ResultStatus::kNoBody;
+ return Metrics::OnboardingFetcherResultStatus::kNoBody;
}
base::JSONReader::ValueWithError data =
@@ -131,14 +129,14 @@ AutofillAssistantOnboardingFetcher::ParseResponse(
if (data.value == absl::nullopt) {
DVLOG(1) << "Parse error: " << data.error_message;
- return ResultStatus::kInvalidJson;
+ return Metrics::OnboardingFetcherResultStatus::kInvalidJson;
}
if (!data.value->is_dict()) {
- return ResultStatus::kInvalidData;
+ return Metrics::OnboardingFetcherResultStatus::kInvalidData;
}
return ExtractStrings(*data.value, onboarding_strings_)
- ? ResultStatus::kOk
- : ResultStatus::kInvalidData;
+ ? Metrics::OnboardingFetcherResultStatus::kOk
+ : Metrics::OnboardingFetcherResultStatus::kInvalidData;
}
void AutofillAssistantOnboardingFetcher::RunCallback(
diff --git a/chromium/components/autofill_assistant/browser/autofill_assistant_onboarding_fetcher.h b/chromium/components/autofill_assistant/browser/autofill_assistant_onboarding_fetcher.h
index a313bd84f51..a2ceb1e0b6b 100644
--- a/chromium/components/autofill_assistant/browser/autofill_assistant_onboarding_fetcher.h
+++ b/chromium/components/autofill_assistant/browser/autofill_assistant_onboarding_fetcher.h
@@ -8,6 +8,7 @@
#include "base/callback.h"
#include "base/containers/flat_map.h"
#include "base/memory/scoped_refptr.h"
+#include "components/autofill_assistant/browser/metrics.h"
#include "components/keyed_service/core/keyed_service.h"
#include "services/network/public/cpp/simple_url_loader.h"
@@ -29,21 +30,6 @@ class AutofillAssistantOnboardingFetcher : public KeyedService {
using StringMap =
base::flat_map<std::string, base::flat_map<std::string, std::string>>;
- // This enum is used in histograms, do not remove/renumber entries. Only add
- // at the end and update kMaxValue. Also remember to update the
- // AutofillAssistantOnboardingFetcherResultStatus enum listing in
- // tools/metrics/histograms/enums.xml.
- enum class ResultStatus {
- kOk = 0,
- // No body was received from the server.
- kNoBody = 1,
- // Parsing the JSON failed.
- kInvalidJson = 1,
- // The JSON was not in the form we expected it to be.
- kInvalidData = 2,
- kMaxValue = kInvalidData
- };
-
AutofillAssistantOnboardingFetcher(
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory);
@@ -62,7 +48,8 @@ class AutofillAssistantOnboardingFetcher : public KeyedService {
void OnFetchComplete(std::unique_ptr<std::string> response_body);
// Parses the response body. Returns a result status.
- ResultStatus ParseResponse(std::unique_ptr<std::string> response_body);
+ Metrics::OnboardingFetcherResultStatus ParseResponse(
+ std::unique_ptr<std::string> response_body);
// Extracts the requested data and runs the callback.
void RunCallback(const std::string& intent, ResponseCallback callback);
diff --git a/chromium/components/autofill_assistant/browser/base_browsertest.cc b/chromium/components/autofill_assistant/browser/base_browsertest.cc
new file mode 100644
index 00000000000..cc3f4cebe68
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/base_browsertest.cc
@@ -0,0 +1,46 @@
+// Copyright 2022 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.
+
+#include "components/autofill_assistant/browser/base_browsertest.h"
+
+#include "content/public/test/content_browser_test_utils.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/switches.h"
+
+namespace autofill_assistant {
+
+// Flag to enable site per process to enforce OOPIFs.
+const char* kSitePerProcess = "site-per-process";
+
+BaseBrowserTest::BaseBrowserTest() = default;
+BaseBrowserTest::~BaseBrowserTest() {}
+
+void BaseBrowserTest::SetUpCommandLine(base::CommandLine* command_line) {
+ command_line->AppendSwitch(kSitePerProcess);
+ // Necessary to avoid flakiness or failure due to input arriving
+ // before the first compositor commit.
+ command_line->AppendSwitch(blink::switches::kAllowPreCommitInput);
+}
+
+void BaseBrowserTest::SetUpOnMainThread() {
+ ContentBrowserTest::SetUpOnMainThread();
+
+ // Start a mock server for hosting an OOPIF.
+ http_server_iframe_ = std::make_unique<net::EmbeddedTestServer>(
+ net::EmbeddedTestServer::TYPE_HTTP);
+ http_server_iframe_->ServeFilesFromSourceDirectory(
+ "components/test/data/autofill_assistant/html_iframe");
+ ASSERT_TRUE(http_server_iframe_->Start(8081));
+
+ // Start the main server hosting the test page.
+ http_server_ = std::make_unique<net::EmbeddedTestServer>(
+ net::EmbeddedTestServer::TYPE_HTTP);
+ http_server_->ServeFilesFromSourceDirectory(
+ "components/test/data/autofill_assistant/html");
+ ASSERT_TRUE(http_server_->Start(8080));
+ ASSERT_TRUE(NavigateToURL(shell(), http_server_->GetURL(kTargetWebsitePath)));
+}
+
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/base_browsertest.h b/chromium/components/autofill_assistant/browser/base_browsertest.h
new file mode 100644
index 00000000000..304871b70cf
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/base_browsertest.h
@@ -0,0 +1,33 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_BASE_BROWSERTEST_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_BASE_BROWSERTEST_H_
+
+#include <memory>
+
+#include "content/public/test/content_browser_test.h"
+
+namespace autofill_assistant {
+
+class BaseBrowserTest : public content::ContentBrowserTest {
+ public:
+ const char* kTargetWebsitePath = "/autofill_assistant_target_website.html";
+
+ BaseBrowserTest();
+ ~BaseBrowserTest() override;
+
+ BaseBrowserTest(const BaseBrowserTest&) = delete;
+ BaseBrowserTest& operator=(const BaseBrowserTest&) = delete;
+
+ void SetUpCommandLine(base::CommandLine* command_line) override;
+ void SetUpOnMainThread() override;
+
+ private:
+ std::unique_ptr<net::EmbeddedTestServer> http_server_;
+ std::unique_ptr<net::EmbeddedTestServer> http_server_iframe_;
+};
+} // namespace autofill_assistant
+
+#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_BASE_BROWSERTEST_H_
diff --git a/chromium/components/autofill_assistant/browser/basic_interactions.cc b/chromium/components/autofill_assistant/browser/basic_interactions.cc
index 6b2faaf72f3..fb5f1890684 100644
--- a/chromium/components/autofill_assistant/browser/basic_interactions.cc
+++ b/chromium/components/autofill_assistant/browser/basic_interactions.cc
@@ -382,8 +382,18 @@ bool CreateLoginOptionResponse(UserModel* user_model,
}
// The result is intentionally not client_side_only, irrespective of input.
+ const LoginOptionProto& login_option = value->login_options().values(0);
ValueProto result;
- result.set_server_payload(value->login_options().values(0).payload());
+ switch (login_option.payload_or_tag_case()) {
+ case LoginOptionProto::kPayload:
+ case LoginOptionProto::PAYLOAD_OR_TAG_NOT_SET:
+ result.set_server_payload(login_option.payload());
+ break;
+
+ case LoginOptionProto::kTag:
+ result.mutable_strings()->add_values(login_option.tag());
+ break;
+ }
user_model->SetValue(result_model_identifier, result);
return true;
}
@@ -415,26 +425,27 @@ base::WeakPtr<BasicInteractions> BasicInteractions::GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
-BasicInteractions::BasicInteractions(ScriptExecutorDelegate* delegate,
- ClientSettings* settings)
- : delegate_(delegate), settings_(settings) {}
+BasicInteractions::BasicInteractions(ScriptExecutorUiDelegate* ui_delegate,
+ ExecutionDelegate* execution_delegate)
+ : ui_delegate_(ui_delegate), execution_delegate_(execution_delegate) {}
BasicInteractions::~BasicInteractions() {}
const ClientSettings& BasicInteractions::GetClientSettings() {
- return *settings_;
+ return execution_delegate_->GetClientSettings();
}
bool BasicInteractions::SetValue(const SetModelValueProto& proto) {
if (proto.model_identifier().empty()) {
DVLOG(2) << "Error setting value: model_identifier empty";
return false;
}
- auto value = delegate_->GetUserModel()->GetValue(proto.value());
+ auto value = execution_delegate_->GetUserModel()->GetValue(proto.value());
if (!value.has_value()) {
DVLOG(2) << "Error setting value: " << proto.value() << " not found";
return false;
}
- delegate_->GetUserModel()->SetValue(proto.model_identifier(), *value);
+ execution_delegate_->GetUserModel()->SetValue(proto.model_identifier(),
+ *value);
return true;
}
@@ -451,7 +462,7 @@ bool BasicInteractions::ComputeValue(const ComputeValueProto& proto) {
"values specified";
return false;
}
- return BooleanAnd(delegate_->GetUserModel(),
+ return BooleanAnd(execution_delegate_->GetUserModel(),
proto.result_model_identifier(), proto.boolean_and());
case ComputeValueProto::kBooleanOr:
if (proto.boolean_or().values().size() == 0) {
@@ -459,7 +470,7 @@ bool BasicInteractions::ComputeValue(const ComputeValueProto& proto) {
"values specified";
return false;
}
- return BooleanOr(delegate_->GetUserModel(),
+ return BooleanOr(execution_delegate_->GetUserModel(),
proto.result_model_identifier(), proto.boolean_or());
case ComputeValueProto::kBooleanNot:
if (!proto.boolean_not().has_value()) {
@@ -467,7 +478,7 @@ bool BasicInteractions::ComputeValue(const ComputeValueProto& proto) {
"value not specified";
return false;
}
- return BooleanNot(delegate_->GetUserModel(),
+ return BooleanNot(execution_delegate_->GetUserModel(),
proto.result_model_identifier(), proto.boolean_not());
case ComputeValueProto::kToString:
if (!proto.to_string().has_value()) {
@@ -475,18 +486,18 @@ bool BasicInteractions::ComputeValue(const ComputeValueProto& proto) {
"value not specified";
return false;
}
- return ValueToString(delegate_->GetUserModel(),
+ return ValueToString(execution_delegate_->GetUserModel(),
proto.result_model_identifier(), proto.to_string());
case ComputeValueProto::kComparison:
- return Compare(delegate_->GetUserModel(), proto.result_model_identifier(),
- proto.comparison());
+ return Compare(execution_delegate_->GetUserModel(),
+ proto.result_model_identifier(), proto.comparison());
case ComputeValueProto::kIntegerSum:
if (proto.integer_sum().values().size() == 0) {
DVLOG(2) << "Error computing ComputeValue::IntegerSum: "
"no values specified";
return false;
}
- return IntegerSum(delegate_->GetUserModel(),
+ return IntegerSum(execution_delegate_->GetUserModel(),
proto.result_model_identifier(), proto.integer_sum());
case ComputeValueProto::kCreateCreditCardResponse:
if (!proto.create_credit_card_response().has_value()) {
@@ -494,7 +505,7 @@ bool BasicInteractions::ComputeValue(const ComputeValueProto& proto) {
"no value specified";
return false;
}
- return CreateCreditCardResponse(delegate_->GetUserModel(),
+ return CreateCreditCardResponse(execution_delegate_->GetUserModel(),
proto.result_model_identifier(),
proto.create_credit_card_response());
case ComputeValueProto::kCreateLoginOptionResponse:
@@ -503,7 +514,7 @@ bool BasicInteractions::ComputeValue(const ComputeValueProto& proto) {
"no value specified";
return false;
}
- return CreateLoginOptionResponse(delegate_->GetUserModel(),
+ return CreateLoginOptionResponse(execution_delegate_->GetUserModel(),
proto.result_model_identifier(),
proto.create_login_option_response());
case ComputeValueProto::kStringEmpty:
@@ -512,7 +523,7 @@ bool BasicInteractions::ComputeValue(const ComputeValueProto& proto) {
<< "Error computing ComputeValue::StringEmpty: no value specified";
return false;
}
- return StringEmpty(delegate_->GetUserModel(),
+ return StringEmpty(execution_delegate_->GetUserModel(),
proto.result_model_identifier(), proto.string_empty());
case ComputeValueProto::KIND_NOT_SET:
DVLOG(2) << "Error computing value: kind not set";
@@ -526,7 +537,7 @@ bool BasicInteractions::SetUserActions(const SetUserActionsProto& proto) {
return false;
}
auto user_actions_value =
- delegate_->GetUserModel()->GetValue(proto.user_actions());
+ execution_delegate_->GetUserModel()->GetValue(proto.user_actions());
if (!user_actions_value.has_value()) {
DVLOG(2) << "Error setting user actions: " << proto.user_actions()
<< " not found in model";
@@ -547,12 +558,12 @@ bool BasicInteractions::SetUserActions(const SetUserActionsProto& proto) {
user_actions->back().SetCallback(base::DoNothing());
}
- delegate_->SetUserActions(std::move(user_actions));
+ ui_delegate_->SetUserActions(std::move(user_actions));
return true;
}
bool BasicInteractions::ToggleUserAction(const ToggleUserActionProto& proto) {
- auto user_actions_value = delegate_->GetUserModel()->GetValue(
+ auto user_actions_value = execution_delegate_->GetUserModel()->GetValue(
proto.user_actions_model_identifier());
if (!user_actions_value.has_value()) {
DVLOG(2) << "Error evaluating " << __func__ << ": "
@@ -567,7 +578,8 @@ bool BasicInteractions::ToggleUserAction(const ToggleUserActionProto& proto) {
return false;
}
- auto enabled_value = delegate_->GetUserModel()->GetValue(proto.enabled());
+ auto enabled_value =
+ execution_delegate_->GetUserModel()->GetValue(proto.enabled());
if (!enabled_value.has_value()) {
DVLOG(2) << "Error evaluating " << __func__ << ": " << proto.enabled()
<< " not found in model";
@@ -597,8 +609,8 @@ bool BasicInteractions::ToggleUserAction(const ToggleUserActionProto& proto) {
user_actions_value->mutable_user_actions()
->mutable_values(user_action_index)
->set_enabled(enabled_value->booleans().values(0));
- delegate_->GetUserModel()->SetValue(proto.user_actions_model_identifier(),
- *user_actions_value);
+ execution_delegate_->GetUserModel()->SetValue(
+ proto.user_actions_model_identifier(), *user_actions_value);
return true;
}
@@ -666,7 +678,7 @@ bool BasicInteractions::RunConditionalCallback(
const std::string& condition_identifier,
base::RepeatingCallback<void()> callback) {
auto condition_value =
- delegate_->GetUserModel()->GetValue(condition_identifier);
+ execution_delegate_->GetUserModel()->GetValue(condition_identifier);
if (!condition_value.has_value()) {
DVLOG(2) << "Error evaluating " << __func__ << ": " << condition_identifier
<< " not found in model";
diff --git a/chromium/components/autofill_assistant/browser/basic_interactions.h b/chromium/components/autofill_assistant/browser/basic_interactions.h
index d6ea26be1cc..0760486079f 100644
--- a/chromium/components/autofill_assistant/browser/basic_interactions.h
+++ b/chromium/components/autofill_assistant/browser/basic_interactions.h
@@ -10,10 +10,12 @@
#include "base/memory/weak_ptr.h"
#include "components/autofill_assistant/browser/client_settings.h"
#include "components/autofill_assistant/browser/client_status.h"
+#include "components/autofill_assistant/browser/execution_delegate.h"
#include "components/autofill_assistant/browser/generic_ui.pb.h"
+#include "components/autofill_assistant/browser/script_executor_ui_delegate.h"
namespace autofill_assistant {
-class ScriptExecutorDelegate;
+class ScriptExecutorUiDelegate;
// Provides basic interactions for use by the generic UI framework. These
// methods are intended to be bound to by the corresponding interaction
@@ -21,7 +23,8 @@ class ScriptExecutorDelegate;
class BasicInteractions {
public:
// Constructor. |delegate| must outlive this instance.
- BasicInteractions(ScriptExecutorDelegate* delegate, ClientSettings* settings);
+ BasicInteractions(ScriptExecutorUiDelegate* ui_delegate,
+ ExecutionDelegate* execution_delegate);
~BasicInteractions();
BasicInteractions(const BasicInteractions&) = delete;
@@ -29,7 +32,7 @@ class BasicInteractions {
base::WeakPtr<BasicInteractions> GetWeakPtr();
- // Returns ClientSettings from the ScriptExecutorDelegate.
+ // Returns ClientSettings.
const ClientSettings& GetClientSettings();
// Performs the computation specified by |proto| and writes the result to
@@ -87,8 +90,8 @@ class BasicInteractions {
base::RepeatingCallback<void()> callback);
private:
- raw_ptr<ScriptExecutorDelegate> delegate_;
- raw_ptr<ClientSettings> settings_;
+ raw_ptr<ScriptExecutorUiDelegate> ui_delegate_;
+ raw_ptr<ExecutionDelegate> execution_delegate_;
// Only valid during a ShowGenericUiAction.
base::OnceCallback<void(const ClientStatus&)> end_action_callback_;
base::OnceCallback<void(const ClientStatus&)>
diff --git a/chromium/components/autofill_assistant/browser/basic_interactions_unittest.cc b/chromium/components/autofill_assistant/browser/basic_interactions_unittest.cc
index 05447459306..87d60e0ec32 100644
--- a/chromium/components/autofill_assistant/browser/basic_interactions_unittest.cc
+++ b/chromium/components/autofill_assistant/browser/basic_interactions_unittest.cc
@@ -9,8 +9,9 @@
#include "base/test/mock_callback.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
#include "components/autofill_assistant/browser/actions/action_test_utils.h"
-#include "components/autofill_assistant/browser/fake_script_executor_delegate.h"
+#include "components/autofill_assistant/browser/fake_script_executor_ui_delegate.h"
#include "components/autofill_assistant/browser/generic_ui.pb.h"
+#include "components/autofill_assistant/browser/mock_execution_delegate.h"
#include "components/autofill_assistant/browser/user_model.h"
#include "components/autofill_assistant/browser/value_util.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -22,6 +23,8 @@ using ::testing::ElementsAre;
using ::testing::Eq;
using ::testing::InSequence;
using ::testing::Property;
+using ::testing::Return;
+using ::testing::ReturnRef;
using ::testing::StrEq;
namespace {
DateProto CreateDateProto(int year, int month, int day) {
@@ -34,14 +37,23 @@ DateProto CreateDateProto(int year, int month, int day) {
} // namespace
class BasicInteractionsTest : public testing::Test {
+ public:
+ void SetUp() override {
+ ON_CALL(execution_delegate_, GetClientSettings)
+ .WillByDefault(ReturnRef(settings_));
+ ON_CALL(execution_delegate_, GetUserModel)
+ .WillByDefault(Return(&user_model_));
+ }
+
protected:
- BasicInteractionsTest() { delegate_.SetUserModel(&user_model_); }
+ BasicInteractionsTest() {}
~BasicInteractionsTest() override {}
- FakeScriptExecutorDelegate delegate_;
+ FakeScriptExecutorUiDelegate ui_delegate_;
+ MockExecutionDelegate execution_delegate_;
ClientSettings settings_;
UserModel user_model_;
- BasicInteractions basic_interactions_{&delegate_, &settings_};
+ BasicInteractions basic_interactions_{&ui_delegate_, &execution_delegate_};
};
TEST_F(BasicInteractionsTest, SetValue) {
@@ -660,6 +672,33 @@ TEST_F(BasicInteractionsTest, ComputeValueCreateLoginOptionResponse) {
EXPECT_EQ(user_model_.GetValue("result"), expected_response_value);
}
+TEST_F(BasicInteractionsTest, ComputeValueCreateLoginOptionResponseWithTag) {
+ ComputeValueProto proto;
+ proto.mutable_create_login_option_response();
+
+ // Missing fields.
+ EXPECT_FALSE(basic_interactions_.ComputeValue(proto));
+ proto.mutable_create_login_option_response()
+ ->mutable_value()
+ ->set_model_identifier("value");
+ EXPECT_FALSE(basic_interactions_.ComputeValue(proto));
+ proto.set_result_model_identifier("result");
+ EXPECT_FALSE(basic_interactions_.ComputeValue(proto));
+
+ ValueProto value;
+ value.mutable_login_options()->add_values()->set_tag("tag");
+ value.set_is_client_side_only(true);
+ user_model_.SetValue("value", value);
+ EXPECT_TRUE(basic_interactions_.ComputeValue(proto));
+
+ // LoginOptionResponseProto is allowed to extract the payload from
+ // client-only values.
+ ValueProto expected_response_value;
+ expected_response_value.mutable_strings()->add_values("tag");
+ expected_response_value.set_is_client_side_only(false);
+ EXPECT_EQ(user_model_.GetValue("result"), expected_response_value);
+}
+
TEST_F(BasicInteractionsTest, ComputeStringEmpty) {
ComputeValueProto proto;
proto.set_result_model_identifier("result");
diff --git a/chromium/components/autofill_assistant/browser/batch_element_checker.cc b/chromium/components/autofill_assistant/browser/batch_element_checker.cc
index a111ed848ff..2821f812cc8 100644
--- a/chromium/components/autofill_assistant/browser/batch_element_checker.cc
+++ b/chromium/components/autofill_assistant/browser/batch_element_checker.cc
@@ -4,31 +4,55 @@
#include "components/autofill_assistant/browser/batch_element_checker.h"
+#include <cstddef>
#include <utility>
#include "base/bind.h"
+#include "base/callback_forward.h"
+#include "base/containers/flat_map.h"
+#include "base/containers/flat_set.h"
#include "base/task/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "components/autofill_assistant/browser/web/element_action_util.h"
#include "components/autofill_assistant/browser/web/element_finder.h"
+#include "components/autofill_assistant/browser/web/selector_observer.h"
#include "components/autofill_assistant/browser/web/web_controller.h"
namespace autofill_assistant {
-BatchElementChecker::BatchElementChecker() {}
+BatchElementChecker::BatchElementChecker() = default;
-BatchElementChecker::~BatchElementChecker() {}
+BatchElementChecker::~BatchElementChecker() = default;
-void BatchElementChecker::AddElementCheck(const Selector& selector,
- bool strict,
- ElementCheckCallback callback) {
+BatchElementChecker::Result::Result() = default;
+
+BatchElementChecker::Result::~Result() = default;
+
+BatchElementChecker::Result::Result(const Result&) = default;
+
+BatchElementChecker::ElementConditionCheck::ElementConditionCheck() = default;
+
+BatchElementChecker::ElementConditionCheck::~ElementConditionCheck() = default;
+BatchElementChecker::ElementConditionCheck::ElementConditionCheck(
+ ElementConditionCheck&&) = default;
+
+void BatchElementChecker::AddElementConditionCheck(
+ const ElementConditionProto& condition,
+ ElementConditionCheckCallback callback) {
DCHECK(!started_);
+ if (IsElementConditionEmpty(condition)) {
+ std::move(callback).Run(ClientStatus(ACTION_APPLIED), {}, {}, {});
+ return;
+ }
- element_check_callbacks_[std::make_pair(selector, strict)].emplace_back(
- std::move(callback));
+ BatchElementChecker::ElementConditionCheck check;
+ check.proto = condition;
+ check.callback = std::move(callback);
+ element_condition_checks_.emplace_back(std::move(check));
}
+// TODO(b/215335501): Refactor out of BatchElementChecker.
void BatchElementChecker::AddFieldValueCheck(const Selector& selector,
GetFieldValueCallback callback) {
DCHECK(!started_);
@@ -37,7 +61,13 @@ void BatchElementChecker::AddFieldValueCheck(const Selector& selector,
}
bool BatchElementChecker::empty() const {
- return element_check_callbacks_.empty() && get_field_value_callbacks_.empty();
+ return element_condition_checks_.empty() &&
+ get_field_value_callbacks_.empty();
+}
+
+bool BatchElementChecker::IsElementConditionEmpty(
+ const ElementConditionProto& proto) {
+ return proto.type_case() == ElementConditionProto::TYPE_NOT_SET;
}
void BatchElementChecker::AddAllDoneCallback(
@@ -45,19 +75,43 @@ void BatchElementChecker::AddAllDoneCallback(
all_done_.emplace_back(std::move(all_done));
}
+void BatchElementChecker::EnableObserver(
+ base::TimeDelta max_wait_time,
+ base::TimeDelta periodic_check_interval,
+ base::TimeDelta extra_timeout) {
+ DCHECK(!use_observers_);
+ DCHECK(!started_);
+ DCHECK(get_field_value_callbacks_.empty())
+ << "Observer-based BatchElementChecker doesn't work with "
+ "AddFieldValueCheck";
+
+ use_observers_ = true;
+ observer_max_wait_time_ = max_wait_time;
+ observer_periodic_check_interval_ = periodic_check_interval;
+ observer_extra_timeout_ = extra_timeout;
+}
+
void BatchElementChecker::Run(WebController* web_controller) {
DCHECK(web_controller);
DCHECK(!started_);
+ for (size_t i = 0; i < element_condition_checks_.size(); ++i) {
+ AddElementConditionResults(element_condition_checks_[i].proto, i);
+ }
+ if (use_observers_) {
+ RunWithObserver(web_controller);
+ return;
+ }
started_ = true;
pending_checks_count_ =
- element_check_callbacks_.size() + get_field_value_callbacks_.size() + 1;
+ unique_selectors_.size() + get_field_value_callbacks_.size() + 1;
- for (auto& entry : element_check_callbacks_) {
+ for (auto& entry : unique_selectors_) {
web_controller->FindElement(
- /* selector= */ entry.first.first, /* strict= */ entry.first.second,
+ /* selector= */ entry.first.first,
+ /* strict= */ entry.first.second,
base::BindOnce(
- &BatchElementChecker::OnElementChecked,
+ &BatchElementChecker::OnSelectorChecked,
weak_ptr_factory_.GetWeakPtr(),
// Guaranteed to exist for the lifetime of this instance, because
// the map isn't modified after Run has been called.
@@ -91,14 +145,155 @@ void BatchElementChecker::Run(WebController* web_controller) {
CheckDone();
}
-void BatchElementChecker::OnElementChecked(
- std::vector<ElementCheckCallback>* callbacks,
+void BatchElementChecker::RunWithObserver(WebController* web_controller) {
+ DCHECK(get_field_value_callbacks_.empty())
+ << "Observer-based BatchElementChecker doesn't work with "
+ "AddFieldValueCheck";
+ DCHECK(!started_);
+ std::vector<SelectorObserver::ObservableSelector> selectors;
+
+ size_t index = 0;
+ for (auto& entry : unique_selectors_) {
+ selectors.emplace_back(SelectorObserver::SelectorId(index++),
+ /* proto = */ entry.first.first.proto,
+ /* strict = */ entry.first.second);
+ }
+ if (selectors.size() == 0) {
+ FinishedCallbacks();
+ return;
+ }
+ started_ = true;
+ auto result = web_controller->ObserveSelectors(
+ selectors, observer_max_wait_time_, observer_periodic_check_interval_,
+ observer_extra_timeout_,
+ base::BindRepeating(&BatchElementChecker::OnResultsUpdated,
+ weak_ptr_factory_.GetWeakPtr())
+
+ );
+ if (!result.ok()) {
+ CallAllCallbacksWithError(result);
+ }
+}
+
+void BatchElementChecker::OnResultsUpdated(
+ const ClientStatus& status,
+ const std::vector<SelectorObserver::Update>& updates,
+ SelectorObserver* selector_observer) {
+ if (!status.ok()) {
+ CallAllCallbacksWithError(status);
+ return;
+ }
+ std::vector<size_t> updated_conditions_vector;
+ // Apply updates
+ for (auto& update : updates) {
+ size_t selector_id = update.selector_id.value();
+ DCHECK_LT(selector_id, unique_selectors_.size());
+ auto& affected_results =
+ std::next(unique_selectors_.begin(), selector_id)->second;
+ for (auto& pair : affected_results) {
+ size_t condition_index = pair.first;
+ size_t result_index = pair.second;
+ auto& condition = element_condition_checks_[condition_index];
+ auto& result = condition.results[result_index];
+ result.match = {/* has_value= */ true, /* value= */ update.match};
+ result.element_id = update.match ? update.element_id : -1;
+ updated_conditions_vector.emplace_back(condition_index);
+ }
+ }
+ auto updated_conditions =
+ base::flat_set<size_t>(std::move(updated_conditions_vector));
+
+ bool any_match = false;
+ for (size_t condition_index : updated_conditions) {
+ auto& condition = element_condition_checks_[condition_index];
+ size_t index = 0;
+ if (EvaluateElementPrecondition(condition.proto, condition.results, &index,
+ nullptr, nullptr)
+ .matches()) {
+ any_match = true;
+ break;
+ }
+ }
+ if (!any_match) {
+ selector_observer->Continue();
+ return;
+ }
+ std::vector<SelectorObserver::RequestedElement> wanted_elements;
+ size_t index = 0;
+ for (auto& entry : unique_selectors_) {
+ for (auto& pair : entry.second) {
+ size_t condition_index = pair.first;
+ size_t result_index = pair.second;
+ auto& condition = element_condition_checks_[condition_index];
+ auto& result = condition.results[result_index];
+ if (result.match.matches() && result.client_id) {
+ wanted_elements.emplace_back(SelectorObserver::SelectorId(index),
+ result.element_id);
+ }
+ }
+ ++index;
+ }
+ selector_observer->GetElementsAndStop(
+ wanted_elements, base::BindOnce(&BatchElementChecker::OnGetElementsDone,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void BatchElementChecker::OnGetElementsDone(
+ const ClientStatus& status,
+ const base::flat_map<SelectorObserver::SelectorId, DomObjectFrameStack>&
+ elements) {
+ if (!status.ok()) {
+ CallAllCallbacksWithError(status);
+ return;
+ }
+ for (auto& element : elements) {
+ size_t results_index = element.first.value();
+ DCHECK_LT(results_index, unique_selectors_.size());
+ auto& affected_results =
+ std::next(unique_selectors_.begin(), results_index)->second;
+ for (auto& pair : affected_results) {
+ size_t condition_index = pair.first;
+ size_t result_index = pair.second;
+ DCHECK(condition_index < element_condition_checks_.size());
+ auto& condition = element_condition_checks_[condition_index];
+ DCHECK(result_index < condition.results.size());
+ auto& result = condition.results[result_index];
+ DCHECK(result.client_id.has_value());
+ condition.elements[result.client_id.value()] = element.second;
+ }
+ }
+ CheckElementConditions();
+ FinishedCallbacks();
+}
+
+void BatchElementChecker::CallAllCallbacksWithError(
+ const ClientStatus& status) {
+ DCHECK(!status.ok());
+ for (auto& entry : element_condition_checks_) {
+ std::move(entry.callback).Run(status, {}, {}, {});
+ }
+ FinishedCallbacks();
+}
+
+void BatchElementChecker::OnSelectorChecked(
+ std::vector<std::pair</* element_condition_index */ size_t,
+ /* result_index */ size_t>>* results,
const ClientStatus& element_status,
std::unique_ptr<ElementFinder::Result> element_result) {
- for (auto& callback : *callbacks) {
- std::move(callback).Run(element_status, *element_result);
+ for (auto& pair : *results) {
+ size_t condition_index = pair.first;
+ size_t result_index = pair.second;
+ DCHECK(condition_index < element_condition_checks_.size());
+ auto& condition = element_condition_checks_[condition_index];
+ DCHECK(result_index < condition.results.size());
+ Result& result = condition.results[result_index];
+ result.match = {/* has_value= */ true, /* value= */ element_status.ok()};
+ // TODO(szermatt): Consider reporting element_status as an unexpected error
+ // right away if it is neither success nor ELEMENT_RESOLUTION_FAILED.
+ if (element_status.ok() && result.client_id.has_value()) {
+ condition.elements[*result.client_id] = element_result->dom_object;
+ }
}
- callbacks->clear();
CheckDone();
}
@@ -117,13 +312,156 @@ void BatchElementChecker::CheckDone() {
pending_checks_count_--;
DCHECK_GE(pending_checks_count_, 0);
if (pending_checks_count_ <= 0) {
- std::vector<base::OnceCallback<void()>> all_done = std::move(all_done_);
- // Callbacks in all_done_ can delete the current instance. Nothing can
- // safely access |this| after this point.
- for (auto& callback : all_done) {
- std::move(callback).Run();
+ CheckElementConditions();
+ FinishedCallbacks();
+ }
+}
+
+void BatchElementChecker::FinishedCallbacks() {
+ std::vector<base::OnceCallback<void()>> all_done = std::move(all_done_);
+ // Callbacks in all_done_ can delete the current instance. Nothing can
+ // safely access |this| after this point.
+ for (auto& callback : all_done) {
+ std::move(callback).Run();
+ }
+}
+
+void BatchElementChecker::CheckElementConditions() {
+ for (auto& check : element_condition_checks_) {
+ std::vector<std::string> payloads;
+ std::vector<std::string> tags;
+ size_t index = 0;
+ bool match = EvaluateElementPrecondition(check.proto, check.results, &index,
+ &payloads, &tags)
+ .matches();
+ std::move(check.callback)
+ .Run(match ? ClientStatus(ACTION_APPLIED)
+ : ClientStatus(ELEMENT_RESOLUTION_FAILED),
+ payloads, tags, check.elements);
+ }
+}
+
+BatchElementChecker::MatchResult
+BatchElementChecker::EvaluateElementPrecondition(
+ const ElementConditionProto& proto,
+ const std::vector<Result>& results,
+ size_t* next_result_index,
+ std::vector<std::string>* payloads,
+ std::vector<std::string>* tags) {
+ MatchResult match{/* checked = */ true, /* match_result= */ false};
+ switch (proto.type_case()) {
+ case ElementConditionProto::kAllOf: {
+ match.match_result = true;
+ for (const ElementConditionProto& condition :
+ proto.all_of().conditions()) {
+ MatchResult result = EvaluateElementPrecondition(
+ condition, results, next_result_index, payloads, tags);
+ if (match.checked && result.checked) {
+ match.match_result = match.match_result && result.match_result;
+ } else {
+ match.checked = false;
+ }
+ }
+ break;
+ }
+ case ElementConditionProto::kAnyOf: {
+ for (const ElementConditionProto& condition :
+ proto.any_of().conditions()) {
+ if (EvaluateElementPrecondition(condition, results, next_result_index,
+ payloads, tags)
+ .matches()) {
+ match.match_result = true;
+ }
+ }
+ break;
+ }
+
+ case ElementConditionProto::kNoneOf: {
+ match.match_result = true;
+ for (const ElementConditionProto& condition :
+ proto.none_of().conditions()) {
+ MatchResult result = EvaluateElementPrecondition(
+ condition, results, next_result_index, payloads, tags);
+ if (match.checked && result.checked) {
+ match.match_result = match.match_result && !result.match_result;
+ } else {
+ match.checked = false;
+ }
+ }
+ break;
}
+
+ case ElementConditionProto::kMatch: {
+ if (*next_result_index >= results.size()) {
+ NOTREACHED();
+ break;
+ }
+ const Result& result = results[*next_result_index];
+ DCHECK_EQ(Selector(proto.match()), result.selector);
+ match = result.match;
+ (*next_result_index)++;
+ break;
+ }
+
+ case ElementConditionProto::TYPE_NOT_SET:
+ match.match_result = true; // An empty condition is true
+ break;
+ }
+ if (payloads && match.matches() && !proto.payload().empty()) {
+ payloads->emplace_back(proto.payload());
}
+ if (tags && match.matches() && !proto.tag().empty()) {
+ tags->emplace_back(proto.tag());
+ }
+ return match;
}
+void BatchElementChecker::AddElementConditionResults(
+ const ElementConditionProto& proto,
+ size_t element_condition_index) {
+ switch (proto.type_case()) {
+ case ElementConditionProto::kAllOf:
+ for (const ElementConditionProto& condition :
+ proto.all_of().conditions()) {
+ AddElementConditionResults(condition, element_condition_index);
+ }
+ break;
+
+ case ElementConditionProto::kAnyOf:
+ for (const ElementConditionProto& condition :
+ proto.any_of().conditions()) {
+ AddElementConditionResults(condition, element_condition_index);
+ }
+ break;
+
+ case ElementConditionProto::kNoneOf:
+ for (const ElementConditionProto& condition :
+ proto.none_of().conditions()) {
+ AddElementConditionResults(condition, element_condition_index);
+ }
+ break;
+
+ case ElementConditionProto::kMatch: {
+ auto& results =
+ element_condition_checks_[element_condition_index].results;
+ Result& result = results.emplace_back();
+ result.selector = Selector(proto.match());
+ if (proto.has_client_id()) {
+ result.client_id = proto.client_id().identifier();
+ }
+ result.strict = proto.require_unique_element();
+ if (result.selector.empty()) {
+ // Empty selectors never match.
+ result.match = {/* has_value= */ true, /* value= */ false};
+ } else {
+ unique_selectors_[std::make_pair(result.selector, result.strict)]
+ .emplace_back(element_condition_index, results.size() - 1);
+ }
+ break;
+ }
+
+ case ElementConditionProto::TYPE_NOT_SET:
+ break;
+ }
+}
} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/batch_element_checker.h b/chromium/components/autofill_assistant/browser/batch_element_checker.h
index 7fa8d9f6b0b..82b504d0cea 100644
--- a/chromium/components/autofill_assistant/browser/batch_element_checker.h
+++ b/chromium/components/autofill_assistant/browser/batch_element_checker.h
@@ -11,12 +11,16 @@
#include <vector>
#include "base/callback.h"
+#include "base/callback_forward.h"
#include "base/callback_helpers.h"
#include "base/containers/flat_map.h"
#include "base/memory/weak_ptr.h"
#include "components/autofill_assistant/browser/client_status.h"
#include "components/autofill_assistant/browser/selector.h"
+#include "components/autofill_assistant/browser/service.pb.h"
+#include "components/autofill_assistant/browser/web/element.h"
#include "components/autofill_assistant/browser/web/element_finder.h"
+#include "components/autofill_assistant/browser/web/selector_observer.h"
namespace autofill_assistant {
class WebController;
@@ -32,14 +36,6 @@ class BatchElementChecker {
virtual ~BatchElementChecker();
- // Callback for AddElementCheck. Arguments are an ok client status if the
- // check passed and an |ElementFinder::Result|.
- //
- // An ElementCheckCallback must not delete its calling BatchElementChecker.
- using ElementCheckCallback =
- base::OnceCallback<void(const ClientStatus&,
- const ElementFinder::Result&)>;
-
// Callback for AddFieldValueCheck. Argument is true is the element exists.
// The string contains the field value, or an empty string if accessing the
// value failed.
@@ -48,12 +44,26 @@ class BatchElementChecker {
using GetFieldValueCallback =
base::OnceCallback<void(const ClientStatus&, const std::string&)>;
- // Checks an element.
+ // Callback for AddElementConditionCheck. Arguments are a client status
+ // (Element Resolution Failed if couldn't find element), a vector of payloads,
+ // and a map of client_id's to the resulting elements.
+ //
+ // An ElementConditionCheckCallback must not delete its calling
+ // BatchElementChecker.
+ using ElementConditionCheckCallback = base::OnceCallback<void(
+ const ClientStatus&,
+ const std::vector<std::string>& payloads,
+ const std::vector<std::string>& tags,
+ const base::flat_map<std::string, DomObjectFrameStack>&)>;
+
+ // Returns true if element condition is empty.
+ static bool IsElementConditionEmpty(const ElementConditionProto& proto);
+
+ // Checks an element precondition
//
- // New element checks cannot be added once Run has been called.
- void AddElementCheck(const Selector& selector,
- bool strict,
- ElementCheckCallback callback);
+ // New element precondition checks cannot be added once Run has been called.
+ void AddElementConditionCheck(const ElementConditionProto& selector,
+ ElementConditionCheckCallback callback);
// Gets the value of |selector| and return the result through |callback|. The
// returned value will be the empty string in case of error or empty value.
@@ -63,8 +73,7 @@ class BatchElementChecker {
GetFieldValueCallback callback);
// A callback to call once all the elements have been checked. These callbacks
- // are guaranteed to be called in order, finishing with the callback passed to
- // Run().
+ // are guaranteed to be called in order.
//
// These callback are allowed to delete the current instance.
void AddAllDoneCallback(base::OnceCallback<void()> all_done);
@@ -72,15 +81,81 @@ class BatchElementChecker {
// Returns true if all there are no checks to run.
bool empty() const;
+ // Turns on observer mode. When BatchElementChecker runs in observer mode, it
+ // waits until any element condition checks or element checks become true.
+ void EnableObserver(base::TimeDelta max_wait_time,
+ base::TimeDelta periodic_check_interval,
+ base::TimeDelta extra_timeout);
+
// Runs the checks. Once all checks are done, calls the callbacks registered
// to AddAllDoneCallback().
void Run(WebController* web_controller);
private:
- // Gets called for each ElementCheck.
- void OnElementChecked(std::vector<ElementCheckCallback>* callbacks,
- const ClientStatus& element_status,
- std::unique_ptr<ElementFinder::Result> element_result);
+ // Not using absl::optional because it's hard to see what "if (var)" means.
+ struct MatchResult {
+ bool checked = false;
+ bool match_result = false;
+ bool matches() { return checked && match_result; }
+ };
+
+ // Results of one independent |Selector| within one |ElementCondition|.
+ struct Result {
+ Result();
+ ~Result();
+ Result(const Result&);
+
+ // Selector checked.
+ Selector selector;
+ // Result of checking that selector.
+ MatchResult match{/* checked= */ false, /* match_result= */ false};
+
+ // The identifier given to this result through the script. This identifier
+ // can be used to later find the element in the |ElementStore|.
+ absl::optional<std::string> client_id;
+
+ // Whether the matching should be done strict or not.
+ bool strict = false;
+
+ // Used in SelectorObserver runs, element_id to retrieve result from
+ // SelectorObserver.
+ int element_id = -1;
+ };
+
+ struct ElementConditionCheck {
+ ElementConditionCheck();
+ ~ElementConditionCheck();
+ ElementConditionCheck(ElementConditionCheck&&);
+
+ // Result of individual |Selector|s within the |ElementCondition|.
+ std::vector<Result> results;
+
+ // Callback called with the result after the check is done (if observer
+ // mode is enabled) or after one condition matches (if observer mode
+ // is disabled).
+ ElementConditionCheckCallback callback;
+
+ // |ElementConditionProto| to check.
+ ElementConditionProto proto;
+
+ // Resulting found elements. Key is the |client_id| in the |Match|
+ // |ElementCondition|s (used to refer to this element in the scripts), value
+ // is the found element.
+ base::flat_map<std::string, DomObjectFrameStack> elements;
+ };
+
+ void RunWithObserver(WebController* web_controller);
+
+ // Gets called for each Selector checked.
+ void OnSelectorChecked(
+ std::vector<std::pair</* element_condition_index */ size_t,
+ /* result_index */ size_t>>* results,
+ const ClientStatus& element_status,
+ std::unique_ptr<ElementFinder::Result> element_result);
+
+ void OnElementPreconditionChecked(
+ std::vector<ElementConditionCheckCallback>* callbacks,
+ const ClientStatus& element_status);
// Gets called for each FieldValueCheck.
void OnFieldValueChecked(std::vector<GetFieldValueCallback>* callbacks,
@@ -88,11 +163,39 @@ class BatchElementChecker {
const std::string& value);
void CheckDone();
+ void FinishedCallbacks();
+ void CallAllCallbacksWithError(const ClientStatus& status);
+
+ // Add selectors from |proto| to |results_|, doing a depth-first search.
+ void AddElementConditionResults(const ElementConditionProto& proto,
+ size_t element_condition_index);
+
+ MatchResult EvaluateElementPrecondition(const ElementConditionProto& proto,
+ const std::vector<Result>& results,
+ size_t* results_iter,
+ std::vector<std::string>* payloads,
+ std::vector<std::string>* tags);
+ void CheckElementConditions();
+ void OnResultsUpdated(const ClientStatus& status,
+ const std::vector<SelectorObserver::Update>& updates,
+ SelectorObserver* selector_observer);
+
+ void OnGetElementsDone(const ClientStatus& status,
+ const base::flat_map<SelectorObserver::SelectorId,
+ DomObjectFrameStack>& elements);
+
+ // A way to find unique selectors and what |Result|'s are affected by them.
+ //
+ // Must not be modified after |Run()| is called because it's referenced by
+ // index.
+ base::flat_map<std::pair<Selector, /* strict */ bool>,
+ std::vector<std::pair</* element_condition_index */ size_t,
+ /* result_index */ size_t>>>
+ unique_selectors_;
- // A map of ElementCheck arguments (check_type, selector) to callbacks that
- // take the result of the check.
- base::flat_map<std::pair<Selector, bool>, std::vector<ElementCheckCallback>>
- element_check_callbacks_;
+ // Must not be modified after |Run()| is called because it's referenced by
+ // index.
+ std::vector<ElementConditionCheck> element_condition_checks_;
// A map of GetFieldValue arguments (selector) to callbacks that take the
// field value.
@@ -103,6 +206,12 @@ class BatchElementChecker {
// Run() was called. Checking elements might or might not have finished yet.
bool started_ = false;
+ // Whether to wait until one of the conditions becomes true.
+ bool use_observers_ = false;
+ base::TimeDelta observer_max_wait_time_;
+ base::TimeDelta observer_periodic_check_interval_;
+ base::TimeDelta observer_extra_timeout_;
+
std::vector<base::OnceCallback<void()>> all_done_;
base::WeakPtrFactory<BatchElementChecker> weak_ptr_factory_{this};
diff --git a/chromium/components/autofill_assistant/browser/batch_element_checker_unittest.cc b/chromium/components/autofill_assistant/browser/batch_element_checker_unittest.cc
index 644a47a5d83..d5aa1288ab9 100644
--- a/chromium/components/autofill_assistant/browser/batch_element_checker_unittest.cc
+++ b/chromium/components/autofill_assistant/browser/batch_element_checker_unittest.cc
@@ -21,8 +21,11 @@ using ::testing::_;
using ::testing::Contains;
using ::testing::ElementsAre;
using ::testing::Eq;
+using ::testing::Key;
using ::testing::Not;
using ::testing::Pair;
+using ::testing::Property;
+using ::testing::UnorderedElementsAre;
using ::testing::WithArgs;
namespace autofill_assistant {
@@ -33,15 +36,32 @@ class BatchElementCheckerTest : public testing::Test {
protected:
BatchElementCheckerTest() : checks_() {}
- void SetUp() override { test_util::MockFindAnyElement(mock_web_controller_); }
+ void SetUp() override {
+ // Any other selector apart from does_not_exist and does_not_exist_either
+ // will exist.
+ test_util::MockFindAnyElement(mock_web_controller_);
+
+ ON_CALL(mock_web_controller_,
+ FindElement(Selector({"does_not_exist"}), _, _))
+ .WillByDefault(RunOnceCallback<2>(
+ ClientStatus(ELEMENT_RESOLUTION_FAILED), nullptr));
+ ON_CALL(mock_web_controller_,
+ FindElement(Selector({"does_not_exist_either"}), _, _))
+ .WillByDefault(RunOnceCallback<2>(
+ ClientStatus(ELEMENT_RESOLUTION_FAILED), nullptr));
+ }
- void OnElementExistenceCheck(const std::string& name,
- const ClientStatus& result,
- const ElementFinder::Result& ignored_element) {
+ void OnElementExistenceCheck(
+ const std::string& name,
+ const ClientStatus& result,
+ const std::vector<std::string>& ignored_payloads,
+ const std::vector<std::string>& ignored_tags,
+ const base::flat_map<std::string, DomObjectFrameStack>&
+ ignored_elements) {
element_exists_results_[name] = result.ok();
}
- BatchElementChecker::ElementCheckCallback ElementExistenceCallback(
+ BatchElementChecker::ElementConditionCheckCallback ElementExistenceCallback(
const std::string& name) {
return base::BindOnce(&BatchElementCheckerTest::OnElementExistenceCheck,
base::Unretained(this), name);
@@ -66,22 +86,48 @@ class BatchElementCheckerTest : public testing::Test {
base::Unretained(this), name);
}
+ // Runs a precondition given |exists_| and |value_match_|.
+ void CheckElementCondition() {
+ BatchElementChecker batch_checks;
+
+ batch_checks.AddElementConditionCheck(condition_, mock_callback_.Get());
+ batch_checks.Run(&mock_web_controller_);
+ }
+
void Run(const std::string& callback_name) {
checks_.AddAllDoneCallback(DoneCallback(callback_name));
checks_.Run(&mock_web_controller_);
}
+ ElementConditionProto Match(const Selector& selector, bool strict = false) {
+ ElementConditionProto condition;
+ *condition.mutable_match() = selector.proto;
+ condition.set_require_unique_element(strict);
+ return condition;
+ }
+
+ ElementConditionProto StrictMatch(const Selector& selector) {
+ return Match(selector, /* strict= */ true);
+ }
+
MockWebController mock_web_controller_;
BatchElementChecker checks_;
base::flat_map<std::string, bool> element_exists_results_;
base::flat_map<std::string, std::string> get_field_value_results_;
base::flat_set<std::string> all_done_;
+ base::MockCallback<base::OnceCallback<void(
+ const ClientStatus&,
+ const std::vector<std::string>&,
+ const std::vector<std::string>&,
+ const base::flat_map<std::string, DomObjectFrameStack>&)>>
+ mock_callback_;
+ ElementConditionProto condition_;
};
TEST_F(BatchElementCheckerTest, Empty) {
EXPECT_TRUE(checks_.empty());
- checks_.AddElementCheck(Selector({"exists"}), /* strict= */ false,
- ElementExistenceCallback("exists"));
+ checks_.AddElementConditionCheck(Match(Selector({"exists"})),
+ ElementExistenceCallback("exists"));
EXPECT_FALSE(checks_.empty());
Run("all_done");
EXPECT_THAT(all_done_, Contains("all_done"));
@@ -90,8 +136,8 @@ TEST_F(BatchElementCheckerTest, Empty) {
TEST_F(BatchElementCheckerTest, OneElementFound) {
Selector expected_selector({"exists"});
test_util::MockFindElement(mock_web_controller_, expected_selector);
- checks_.AddElementCheck(expected_selector, /* strict= */ false,
- ElementExistenceCallback("exists"));
+ checks_.AddElementConditionCheck(Match(expected_selector),
+ ElementExistenceCallback("exists"));
Run("was_run");
EXPECT_THAT(element_exists_results_, Contains(Pair("exists", true)));
@@ -100,12 +146,8 @@ TEST_F(BatchElementCheckerTest, OneElementFound) {
TEST_F(BatchElementCheckerTest, OneElementNotFound) {
Selector expected_notexists_selector({"does_not_exist"});
- EXPECT_CALL(mock_web_controller_,
- FindElement(expected_notexists_selector, /* strict= */ false, _))
- .WillOnce(
- RunOnceCallback<2>(ClientStatus(ELEMENT_RESOLUTION_FAILED), nullptr));
- checks_.AddElementCheck(expected_notexists_selector, /* strict= */ false,
- ElementExistenceCallback("does_not_exist"));
+ checks_.AddElementConditionCheck(Match(expected_notexists_selector),
+ ElementExistenceCallback("does_not_exist"));
Run("was_run");
EXPECT_THAT(element_exists_results_, Contains(Pair("does_not_exist", false)));
@@ -117,8 +159,8 @@ TEST_F(BatchElementCheckerTest, TooManyElementsForStrict) {
EXPECT_CALL(mock_web_controller_,
FindElement(expected_multiple_selector, /* strict= */ true, _))
.WillOnce(RunOnceCallback<2>(ClientStatus(TOO_MANY_ELEMENTS), nullptr));
- checks_.AddElementCheck(expected_multiple_selector, /* strict= */ true,
- ElementExistenceCallback("multiple"));
+ checks_.AddElementConditionCheck(StrictMatch(expected_multiple_selector),
+ ElementExistenceCallback("multiple"));
Run("was_run");
EXPECT_THAT(element_exists_results_, Contains(Pair("multiple", false)));
@@ -195,14 +237,14 @@ TEST_F(BatchElementCheckerTest, MultipleElements) {
.WillOnce(RunOnceCallback<1>(ClientStatus(ELEMENT_RESOLUTION_FAILED),
std::string()));
- checks_.AddElementCheck(expected_selector_1, /* strict= */ false,
- ElementExistenceCallback("1"));
- checks_.AddElementCheck(expected_selector_2, /* strict= */ false,
- ElementExistenceCallback("2"));
- checks_.AddElementCheck(expected_selector_3, /* strict= */ false,
- ElementExistenceCallback("3"));
- checks_.AddElementCheck(expected_selector_4, /* strict= */ true,
- ElementExistenceCallback("4"));
+ checks_.AddElementConditionCheck(Match(expected_selector_1),
+ ElementExistenceCallback("1"));
+ checks_.AddElementConditionCheck(Match(expected_selector_2),
+ ElementExistenceCallback("2"));
+ checks_.AddElementConditionCheck(Match(expected_selector_3),
+ ElementExistenceCallback("3"));
+ checks_.AddElementConditionCheck(StrictMatch(expected_selector_4),
+ ElementExistenceCallback("4"));
checks_.AddFieldValueCheck(expected_selector_5, FieldValueCallback("5"));
checks_.AddFieldValueCheck(expected_selector_6, FieldValueCallback("6"));
Run("was_run");
@@ -235,16 +277,16 @@ TEST_F(BatchElementCheckerTest, DeduplicateElementExists) {
std::move(callback).Run(OkClientStatus(), std::move(element_result));
}));
- checks_.AddElementCheck(expected_selector_1, /* strict= */ false,
- ElementExistenceCallback("first 1"));
- checks_.AddElementCheck(expected_selector_1, /* strict= */ false,
- ElementExistenceCallback("second 1"));
- checks_.AddElementCheck(expected_selector_2, /* strict= */ false,
- ElementExistenceCallback("2"));
- checks_.AddElementCheck(expected_selector_3, /* strict= */ true,
- ElementExistenceCallback("first 3"));
- checks_.AddElementCheck(expected_selector_3, /* strict= */ false,
- ElementExistenceCallback("second 3"));
+ checks_.AddElementConditionCheck(Match(expected_selector_1),
+ ElementExistenceCallback("first 1"));
+ checks_.AddElementConditionCheck(Match(expected_selector_1),
+ ElementExistenceCallback("second 1"));
+ checks_.AddElementConditionCheck(Match(expected_selector_2),
+ ElementExistenceCallback("2"));
+ checks_.AddElementConditionCheck(StrictMatch(expected_selector_3),
+ ElementExistenceCallback("first 3"));
+ checks_.AddElementConditionCheck(Match(expected_selector_3),
+ ElementExistenceCallback("second 3"));
Run("was_run");
@@ -259,8 +301,8 @@ TEST_F(BatchElementCheckerTest, DeduplicateElementExists) {
TEST_F(BatchElementCheckerTest, CallMultipleAllDoneCallbacks) {
Selector expected_selector({"exists"});
test_util::MockFindElement(mock_web_controller_, expected_selector);
- checks_.AddElementCheck(expected_selector, /* strict= */ false,
- ElementExistenceCallback("exists"));
+ checks_.AddElementConditionCheck(Match(expected_selector),
+ ElementExistenceCallback("exists"));
checks_.AddAllDoneCallback(DoneCallback("1"));
checks_.AddAllDoneCallback(DoneCallback("2"));
checks_.AddAllDoneCallback(DoneCallback("3"));
@@ -268,7 +310,268 @@ TEST_F(BatchElementCheckerTest, CallMultipleAllDoneCallbacks) {
EXPECT_THAT(all_done_, ElementsAre("1", "2", "3"));
}
-// Deduplicate get field
+TEST_F(BatchElementCheckerTest, IsElementConditionEmpty) {
+ EXPECT_TRUE(BatchElementChecker::IsElementConditionEmpty(condition_));
+}
+
+TEST_F(BatchElementCheckerTest, NonEmpty) {
+ *condition_.mutable_match() = ToSelectorProto("exists");
+ EXPECT_FALSE(BatchElementChecker::IsElementConditionEmpty(condition_));
+}
+
+TEST_F(BatchElementCheckerTest, NoConditions) {
+ EXPECT_CALL(
+ mock_callback_,
+ Run(Property(&ClientStatus::proto_status, ACTION_APPLIED), _, _, _));
+ CheckElementCondition();
+}
+
+TEST_F(BatchElementCheckerTest, EmptySelector) {
+ condition_.mutable_match();
+
+ EXPECT_CALL(mock_callback_, Run(Property(&ClientStatus::proto_status,
+ ELEMENT_RESOLUTION_FAILED),
+ _, _, _));
+ CheckElementCondition();
+}
+
+TEST_F(BatchElementCheckerTest, ElementExists) {
+ *condition_.mutable_match() = ToSelectorProto("exists");
+
+ EXPECT_CALL(
+ mock_callback_,
+ Run(Property(&ClientStatus::proto_status, ACTION_APPLIED), _, _, _));
+ CheckElementCondition();
+}
+
+TEST_F(BatchElementCheckerTest, ElementDoesNotExist) {
+ *condition_.mutable_match() = ToSelectorProto("does_not_exist");
+
+ EXPECT_CALL(mock_callback_, Run(Property(&ClientStatus::proto_status,
+ ELEMENT_RESOLUTION_FAILED),
+ _, _, _));
+ CheckElementCondition();
+}
+
+TEST_F(BatchElementCheckerTest, AnyOfEmpty) {
+ condition_.mutable_any_of();
+
+ EXPECT_CALL(mock_callback_, Run(Property(&ClientStatus::proto_status,
+ ELEMENT_RESOLUTION_FAILED),
+ _, _, _));
+ CheckElementCondition();
+}
+
+TEST_F(BatchElementCheckerTest, AnyOfNoneMatch) {
+ *condition_.mutable_any_of()->add_conditions()->mutable_match() =
+ ToSelectorProto("does_not_exist");
+ *condition_.mutable_any_of()->add_conditions()->mutable_match() =
+ ToSelectorProto("does_not_exist_either");
+
+ EXPECT_CALL(mock_callback_, Run(Property(&ClientStatus::proto_status,
+ ELEMENT_RESOLUTION_FAILED),
+ _, _, _));
+ CheckElementCondition();
+}
+
+TEST_F(BatchElementCheckerTest, AnyOfSomeMatch) {
+ *condition_.mutable_any_of()->add_conditions()->mutable_match() =
+ ToSelectorProto("exists");
+ *condition_.mutable_any_of()->add_conditions()->mutable_match() =
+ ToSelectorProto("does_not_exist");
+
+ EXPECT_CALL(
+ mock_callback_,
+ Run(Property(&ClientStatus::proto_status, ACTION_APPLIED), _, _, _));
+ CheckElementCondition();
+}
+
+TEST_F(BatchElementCheckerTest, AnyOfAllMatch) {
+ *condition_.mutable_any_of()->add_conditions()->mutable_match() =
+ ToSelectorProto("exists");
+ *condition_.mutable_any_of()->add_conditions()->mutable_match() =
+ ToSelectorProto("exists_too");
+
+ EXPECT_CALL(
+ mock_callback_,
+ Run(Property(&ClientStatus::proto_status, ACTION_APPLIED), _, _, _));
+ CheckElementCondition();
+}
+
+TEST_F(BatchElementCheckerTest, AllOfEmpty) {
+ condition_.mutable_all_of();
+
+ EXPECT_CALL(
+ mock_callback_,
+ Run(Property(&ClientStatus::proto_status, ACTION_APPLIED), _, _, _));
+ CheckElementCondition();
+}
+
+TEST_F(BatchElementCheckerTest, AllOfNoneMatch) {
+ *condition_.mutable_all_of()->add_conditions()->mutable_match() =
+ ToSelectorProto("does_not_exist");
+ *condition_.mutable_all_of()->add_conditions()->mutable_match() =
+ ToSelectorProto("does_not_exist_either");
+
+ EXPECT_CALL(mock_callback_, Run(Property(&ClientStatus::proto_status,
+ ELEMENT_RESOLUTION_FAILED),
+ _, _, _));
+ CheckElementCondition();
+}
+
+TEST_F(BatchElementCheckerTest, AllOfSomeMatch) {
+ *condition_.mutable_all_of()->add_conditions()->mutable_match() =
+ ToSelectorProto("exists");
+ *condition_.mutable_all_of()->add_conditions()->mutable_match() =
+ ToSelectorProto("does_not_exist");
+
+ EXPECT_CALL(mock_callback_, Run(Property(&ClientStatus::proto_status,
+ ELEMENT_RESOLUTION_FAILED),
+ _, _, _));
+ CheckElementCondition();
+}
+
+TEST_F(BatchElementCheckerTest, AllOfAllMatch) {
+ *condition_.mutable_all_of()->add_conditions()->mutable_match() =
+ ToSelectorProto("exists");
+ *condition_.mutable_all_of()->add_conditions()->mutable_match() =
+ ToSelectorProto("exists_too");
+
+ EXPECT_CALL(
+ mock_callback_,
+ Run(Property(&ClientStatus::proto_status, ACTION_APPLIED), _, _, _));
+ CheckElementCondition();
+}
+
+TEST_F(BatchElementCheckerTest, NoneOfEmpty) {
+ condition_.mutable_none_of();
+
+ EXPECT_CALL(
+ mock_callback_,
+ Run(Property(&ClientStatus::proto_status, ACTION_APPLIED), _, _, _));
+ CheckElementCondition();
+}
+
+TEST_F(BatchElementCheckerTest, NoneOfNoneMatch) {
+ *condition_.mutable_none_of()->add_conditions()->mutable_match() =
+ ToSelectorProto("does_not_exist");
+ *condition_.mutable_none_of()->add_conditions()->mutable_match() =
+ ToSelectorProto("does_not_exist_either");
+
+ EXPECT_CALL(
+ mock_callback_,
+ Run(Property(&ClientStatus::proto_status, ACTION_APPLIED), _, _, _));
+ CheckElementCondition();
+}
+
+TEST_F(BatchElementCheckerTest, NoneOfSomeMatch) {
+ *condition_.mutable_none_of()->add_conditions()->mutable_match() =
+ ToSelectorProto("exists");
+ *condition_.mutable_none_of()->add_conditions()->mutable_match() =
+ ToSelectorProto("does_not_exist");
+
+ EXPECT_CALL(mock_callback_, Run(Property(&ClientStatus::proto_status,
+ ELEMENT_RESOLUTION_FAILED),
+ _, _, _));
+ CheckElementCondition();
+}
+
+TEST_F(BatchElementCheckerTest, NoneOfAllMatch) {
+ *condition_.mutable_none_of()->add_conditions()->mutable_match() =
+ ToSelectorProto("exists");
+ *condition_.mutable_none_of()->add_conditions()->mutable_match() =
+ ToSelectorProto("exists_too");
+
+ EXPECT_CALL(mock_callback_, Run(Property(&ClientStatus::proto_status,
+ ELEMENT_RESOLUTION_FAILED),
+ _, _, _));
+ CheckElementCondition();
+}
+
+TEST_F(BatchElementCheckerTest, PayloadConditionMet) {
+ auto* exists = condition_.mutable_any_of()->add_conditions();
+ *exists->mutable_match() = ToSelectorProto("exists");
+ exists->set_payload("exists");
+
+ auto* exists_too = condition_.mutable_any_of()->add_conditions();
+ *exists_too->mutable_match() = ToSelectorProto("exists_too");
+ exists_too->set_payload("exists_too");
+
+ condition_.set_payload("any_of");
+
+ EXPECT_CALL(mock_callback_,
+ Run(Property(&ClientStatus::proto_status, ACTION_APPLIED),
+ ElementsAre("exists", "exists_too", "any_of"), _, _));
+ CheckElementCondition();
+}
+
+TEST_F(BatchElementCheckerTest, PayloadConditionNotMet) {
+ auto* exists = condition_.mutable_none_of()->add_conditions();
+ *exists->mutable_match() = ToSelectorProto("exists");
+ exists->set_payload("exists");
+
+ auto* exists_too = condition_.mutable_none_of()->add_conditions();
+ *exists_too->mutable_match() = ToSelectorProto("exists_too");
+ exists_too->set_payload("exists_too");
+
+ condition_.set_payload("none_of");
+
+ EXPECT_CALL(mock_callback_, Run(Property(&ClientStatus::proto_status,
+ ELEMENT_RESOLUTION_FAILED),
+ ElementsAre("exists", "exists_too"), _, _));
+ CheckElementCondition();
+}
+
+TEST_F(BatchElementCheckerTest, Complex) {
+ *condition_.mutable_all_of()->add_conditions()->mutable_match() =
+ ToSelectorProto("exists");
+ *condition_.mutable_all_of()->add_conditions()->mutable_match() =
+ ToSelectorProto("exists_too");
+ auto* none_of = condition_.mutable_all_of()->add_conditions();
+ none_of->set_payload("none_of");
+ auto* does_not_exist_in_none_of =
+ none_of->mutable_none_of()->add_conditions();
+ *does_not_exist_in_none_of->mutable_match() =
+ ToSelectorProto("does_not_exist");
+ does_not_exist_in_none_of->set_payload("does_not_exist in none_of");
+ *none_of->mutable_none_of()->add_conditions()->mutable_match() =
+ ToSelectorProto("does_not_exist_either");
+
+ auto* any_of = condition_.mutable_all_of()->add_conditions();
+ any_of->set_payload("any_of");
+ auto* exists_in_any_of = any_of->mutable_any_of()->add_conditions();
+ *exists_in_any_of->mutable_match() = ToSelectorProto("exists");
+ exists_in_any_of->set_payload("exists in any_of");
+
+ *any_of->mutable_any_of()->add_conditions()->mutable_match() =
+ ToSelectorProto("does_not_exist");
+
+ EXPECT_CALL(mock_callback_,
+ Run(Property(&ClientStatus::proto_status, ACTION_APPLIED),
+ ElementsAre("none_of", "exists in any_of", "any_of"), _, _));
+ CheckElementCondition();
+}
+
+TEST_F(BatchElementCheckerTest, ReturnsFoundElements) {
+ auto* exists = condition_.mutable_all_of()->add_conditions();
+ *exists->mutable_match() = ToSelectorProto("exists");
+ exists->set_payload("exists");
+ exists->set_tag("exists_tag");
+ exists->mutable_client_id()->set_identifier("exists");
+
+ auto* exists_too = condition_.mutable_all_of()->add_conditions();
+ *exists_too->mutable_match() = ToSelectorProto("exists_too");
+ exists_too->set_payload("exists_too");
+ exists_too->set_tag("exists_too_tag");
+ exists_too->mutable_client_id()->set_identifier("exists_too");
+
+ EXPECT_CALL(mock_callback_,
+ Run(Property(&ClientStatus::proto_status, ACTION_APPLIED),
+ ElementsAre("exists", "exists_too"),
+ ElementsAre("exists_tag", "exists_too_tag"),
+ UnorderedElementsAre(Key("exists"), Key("exists_too"))));
+ CheckElementCondition();
+}
} // namespace
} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/client.h b/chromium/components/autofill_assistant/browser/client.h
index f331c3f5717..8949e0c2981 100644
--- a/chromium/components/autofill_assistant/browser/client.h
+++ b/chromium/components/autofill_assistant/browser/client.h
@@ -8,9 +8,12 @@
#include <string>
#include "base/callback.h"
+#include "components/autofill_assistant/browser/client_settings.h"
#include "components/autofill_assistant/browser/device_context.h"
#include "components/autofill_assistant/browser/metrics.h"
+#include "components/autofill_assistant/browser/script_executor_ui_delegate.h"
#include "components/autofill_assistant/browser/service/service.h"
+#include "components/autofill_assistant/browser/web/web_controller.h"
#include "content/public/browser/web_contents.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
@@ -18,6 +21,10 @@ namespace autofill {
class PersonalDataManager;
} // namespace autofill
+namespace password_manager {
+class PasswordChangeSuccessTracker;
+} // namespace password_manager
+
namespace version_info {
enum class Channel;
} // namespace version_info
@@ -59,9 +66,13 @@ class Client {
// Returns the current active personal data manager.
virtual autofill::PersonalDataManager* GetPersonalDataManager() const = 0;
- // Returns the currently active login fetcher.
+ // Returns the currently active login manager.
virtual WebsiteLoginManager* GetWebsiteLoginManager() const = 0;
+ // Returns the current password change success tracker.
+ virtual password_manager::PasswordChangeSuccessTracker*
+ GetPasswordChangeSuccessTracker() const = 0;
+
// Returns the locale.
virtual std::string GetLocale() const = 0;
@@ -104,6 +115,10 @@ class Client {
// Whether this client has had an UI.
virtual bool HasHadUI() const = 0;
+ // Returns the ScriptExecutorUiDelegate if it exists, otherwise returns
+ // nullptr.
+ virtual ScriptExecutorUiDelegate* GetScriptExecutorUiDelegate() = 0;
+
protected:
Client() = default;
};
diff --git a/chromium/components/autofill_assistant/browser/client_context.h b/chromium/components/autofill_assistant/browser/client_context.h
index fa3a1728df5..d798fdb32cc 100644
--- a/chromium/components/autofill_assistant/browser/client_context.h
+++ b/chromium/components/autofill_assistant/browser/client_context.h
@@ -19,7 +19,7 @@ class ClientContext {
// Updates the client context based on the current state of the client.
virtual void Update(const TriggerContext& trigger_context) = 0;
// Updates the payments client token. This is not part of the normal update.
- virtual void SetPaymentsClientToken(const std::string& client_token);
+ virtual void SetPaymentsClientToken(const std::string& client_token) = 0;
// Returns the proto representation of this client context.
virtual ClientContextProto AsProto() const = 0;
};
diff --git a/chromium/components/autofill_assistant/browser/client_settings.cc b/chromium/components/autofill_assistant/browser/client_settings.cc
index a4000fddb52..1f4f02a8d2e 100644
--- a/chromium/components/autofill_assistant/browser/client_settings.cc
+++ b/chromium/components/autofill_assistant/browser/client_settings.cc
@@ -173,6 +173,10 @@ void ClientSettings::UpdateFromProto(const ClientSettingsProto& proto) {
} else {
integration_test_settings.reset();
}
+ if (proto.has_selector_observer_extra_timeout_ms()) {
+ selector_observer_extra_timeout =
+ base::Milliseconds(proto.selector_observer_extra_timeout_ms());
+ }
}
} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/client_settings.h b/chromium/components/autofill_assistant/browser/client_settings.h
index 1e964209a51..096e20dd03f 100644
--- a/chromium/components/autofill_assistant/browser/client_settings.h
+++ b/chromium/components/autofill_assistant/browser/client_settings.h
@@ -140,6 +140,13 @@ struct ClientSettings {
// should be concatenated.
ClientSettingsProto::SlowWarningSettings::MessageMode message_mode =
ClientSettingsProto::SlowWarningSettings::REPLACE;
+
+ // Extra time SelectorObserver has to finish. If it takes longer than
+ // max_wait_time + extra_timeout (this value) it assumes something went
+ // wrong and fails with a |TIMED_OUT| error. SelectorObserver only counts
+ // time spent waiting so a extra delay of 1 to 10 seconds for javascript
+ // execution and checking selectors is conceivable.
+ base::TimeDelta selector_observer_extra_timeout = base::Seconds(15);
};
} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/controller.cc b/chromium/components/autofill_assistant/browser/controller.cc
index 3f85bdc02e5..73d7d5a60b3 100644
--- a/chromium/components/autofill_assistant/browser/controller.cc
+++ b/chromium/components/autofill_assistant/browser/controller.cc
@@ -8,14 +8,12 @@
#include "base/bind.h"
#include "base/callback_helpers.h"
-#include "base/json/json_writer.h"
#include "base/no_destructor.h"
#include "base/ranges/algorithm.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/tick_clock.h"
#include "base/values.h"
-#include "components/autofill_assistant/browser/actions/collect_user_data_action.h"
#include "components/autofill_assistant/browser/controller_observer.h"
#include "components/autofill_assistant/browser/display_strings_util.h"
#include "components/autofill_assistant/browser/features.h"
@@ -28,7 +26,7 @@
#include "components/autofill_assistant/browser/user_data_util.h"
#include "components/autofill_assistant/browser/view_layout.pb.h"
#include "components/google/core/common/google_util.h"
-#include "components/password_manager/core/browser/password_manager_client.h"
+#include "components/password_manager/core/browser/password_change_success_tracker_impl.h"
#include "components/strings/grit/components_strings.h"
#include "components/ukm/content/source_url_recorder.h"
#include "content/public/browser/browser_task_traits.h"
@@ -43,11 +41,6 @@
namespace autofill_assistant {
namespace {
-// Experiment for non-sticky TTSButtonState. The TTSButtonState is reset to
-// DEFAULT whenever tts/status message changes even when the button was
-// DISABLED by the user tap.
-const char kNonStickyTtsButtonStateExperiment[] = "4624822";
-
bool ShouldSuppressKeyboardForState(AutofillAssistantState state) {
switch (state) {
case AutofillAssistantState::STARTING:
@@ -66,15 +59,13 @@ bool ShouldSuppressKeyboardForState(AutofillAssistantState state) {
} // namespace
-Controller::Controller(
- content::WebContents* web_contents,
- Client* client,
- const base::TickClock* tick_clock,
- base::WeakPtr<RuntimeManager> runtime_manager,
- std::unique_ptr<Service> service,
- std::unique_ptr<AutofillAssistantTtsController> tts_controller,
- ukm::UkmRecorder* ukm_recorder,
- AnnotateDomModelService* annotate_dom_model_service)
+Controller::Controller(content::WebContents* web_contents,
+ Client* client,
+ const base::TickClock* tick_clock,
+ base::WeakPtr<RuntimeManager> runtime_manager,
+ std::unique_ptr<Service> service,
+ ukm::UkmRecorder* ukm_recorder,
+ AnnotateDomModelService* annotate_dom_model_service)
: content::WebContentsObserver(web_contents),
client_(client),
tick_clock_(tick_clock),
@@ -83,40 +74,10 @@ Controller::Controller(
: ServiceImpl::Create(web_contents->GetBrowserContext(),
client_)),
navigating_to_new_document_(web_contents->IsWaitingForResponse()),
- tts_controller_(std::move(tts_controller)),
ukm_recorder_(ukm_recorder),
- annotate_dom_model_service_(annotate_dom_model_service) {
- user_model_.AddObserver(this);
- tts_controller_->SetTtsEventDelegate(weak_ptr_factory_.GetWeakPtr());
-}
-
-Controller::~Controller() {
- user_model_.RemoveObserver(this);
-}
-
-Controller::DetailsHolder::DetailsHolder(
- std::unique_ptr<Details> details,
- std::unique_ptr<base::OneShotTimer> timer)
- : details_(std::move(details)), timer_(std::move(timer)) {}
-
-Controller::DetailsHolder::~DetailsHolder() = default;
-Controller::DetailsHolder::DetailsHolder(DetailsHolder&& other) = default;
-Controller::DetailsHolder& Controller::DetailsHolder::operator=(
- DetailsHolder&& other) = default;
-
-const Details& Controller::DetailsHolder::GetDetails() const {
- return *details_;
-}
+ annotate_dom_model_service_(annotate_dom_model_service) {}
-bool Controller::DetailsHolder::CurrentlyVisible() const {
- // If there is a timer associated to these details, then they should be shown
- // only once the timer has triggered.
- return !timer_;
-}
-
-void Controller::DetailsHolder::Enable() {
- timer_.reset();
-}
+Controller::~Controller() {}
const ClientSettings& Controller::GetSettings() {
return settings_;
@@ -145,7 +106,7 @@ Service* Controller::GetService() {
WebController* Controller::GetWebController() {
if (!web_controller_) {
web_controller_ = WebController::CreateForWebContents(
- web_contents(), &user_data_, &log_info_);
+ web_contents(), &user_data_, &log_info_, annotate_dom_model_service_);
}
return web_controller_.get();
}
@@ -163,6 +124,11 @@ WebsiteLoginManager* Controller::GetWebsiteLoginManager() {
return client_->GetWebsiteLoginManager();
}
+password_manager::PasswordChangeSuccessTracker*
+Controller::GetPasswordChangeSuccessTracker() {
+ return client_->GetPasswordChangeSuccessTracker();
+}
+
content::WebContents* Controller::GetWebContents() {
return web_contents();
}
@@ -175,301 +141,14 @@ ukm::UkmRecorder* Controller::GetUkmRecorder() {
return ukm_recorder_;
}
-std::string Controller::GetDisplayStringsLocale() {
- if (GetSettings().display_strings_locale.empty()) {
- // Fallback locale
- return client_->GetLocale();
- }
- return GetSettings().display_strings_locale;
-}
-
void Controller::SetTouchableElementArea(const ElementAreaProto& area) {
touchable_element_area()->SetFromProto(area);
}
-void Controller::SetStatusMessage(const std::string& message) {
- status_message_ = message;
- for (ControllerObserver& observer : observers_) {
- observer.OnStatusMessageChanged(message);
- }
-
- // Override tts_message every time status_message changes.
- SetTtsMessage(message);
-}
-
-std::string Controller::GetStatusMessage() const {
- return status_message_;
-}
-
-void Controller::SetBubbleMessage(const std::string& message) {
- bubble_message_ = message;
- for (ControllerObserver& observer : observers_) {
- observer.OnBubbleMessageChanged(message);
- }
-}
-
-std::string Controller::GetBubbleMessage() const {
- return bubble_message_;
-}
-
-void Controller::SetTtsMessage(const std::string& message) {
- tts_message_ = message;
-
- // Stop any ongoing TTS and reset button state.
- if (tts_button_state_ == TtsButtonState::PLAYING) {
- // Will not cause any TTS event.
- tts_controller_->Stop();
- SetTtsButtonState(TtsButtonState::DEFAULT);
- }
-
- // Re-enable TTS button if "Non sticky Tts Button State" experiment is
- // enabled.
- if (tts_button_state_ == TtsButtonState::DISABLED &&
- trigger_context_ != nullptr &&
- trigger_context_->HasExperimentId(kNonStickyTtsButtonStateExperiment)) {
- SetTtsButtonState(TtsButtonState::DEFAULT);
- }
-}
-
-std::string Controller::GetTtsMessage() const {
- return tts_message_;
-}
-
-void Controller::MaybePlayTtsMessage() {
- if (!tts_enabled_) {
- return;
- }
-
- // Will fire a TTS_START event.
- tts_controller_->Speak(tts_message_, GetDisplayStringsLocale());
-}
-
-void Controller::SetDetails(std::unique_ptr<Details> details,
- base::TimeDelta delay) {
- details_.clear();
-
- // There is nothing to append: notify that we cleared the details and return.
- if (!details) {
- NotifyDetailsChanged();
- return;
- }
-
- // If there is a delay, notify now that details have been cleared. If there is
- // no delay, AppendDetails will take care of the notifying the observers after
- // appending the details.
- if (!delay.is_zero()) {
- NotifyDetailsChanged();
- }
-
- AppendDetails(std::move(details), delay);
-}
-
-void Controller::AppendDetails(std::unique_ptr<Details> details,
- base::TimeDelta delay) {
- if (!details) {
- return;
- }
-
- if (delay.is_zero()) {
- details_.push_back(DetailsHolder(std::move(details), /* timer= */ nullptr));
- NotifyDetailsChanged();
- return;
- }
-
- // Delay the addition of the new details.
- size_t details_index = details_.size();
- auto timer = std::make_unique<base::OneShotTimer>();
- timer->Start(FROM_HERE, delay,
- base::BindOnce(&Controller::MakeDetailsVisible,
- weak_ptr_factory_.GetWeakPtr(), details_index));
- details_.push_back(DetailsHolder(std::move(details), std::move(timer)));
-}
-
-void Controller::MakeDetailsVisible(size_t details_index) {
- if (details_index < details_.size()) {
- details_[details_index].Enable();
- NotifyDetailsChanged();
- }
-}
-
-void Controller::NotifyDetailsChanged() {
- std::vector<Details> details = GetDetails();
- for (ControllerObserver& observer : observers_) {
- observer.OnDetailsChanged(details);
- }
-}
-
-std::vector<Details> Controller::GetDetails() const {
- std::vector<Details> details;
- for (const auto& holder : details_) {
- if (holder.CurrentlyVisible()) {
- details.push_back(holder.GetDetails());
- }
- }
- return details;
-}
-
-int Controller::GetProgressActiveStep() const {
- return progress_active_step_;
-}
-
-ShowProgressBarProto::StepProgressBarConfiguration
-Controller::GetStepProgressBarConfiguration() const {
- return step_progress_bar_configuration_;
-}
-
-void Controller::SetInfoBox(const InfoBox& info_box) {
- if (!info_box_) {
- info_box_ = std::make_unique<InfoBox>();
- }
- *info_box_ = info_box;
- for (ControllerObserver& observer : observers_) {
- observer.OnInfoBoxChanged(info_box_.get());
- }
-}
-
-void Controller::ClearInfoBox() {
- info_box_.reset();
- for (ControllerObserver& observer : observers_) {
- observer.OnInfoBoxChanged(nullptr);
- }
-}
-
-const InfoBox* Controller::GetInfoBox() const {
- return info_box_.get();
-}
-
-bool Controller::SetProgressActiveStepIdentifier(
- const std::string& active_step_identifier) {
- const auto it = base::ranges::find_if(
- step_progress_bar_configuration_.annotated_step_icons(),
- [&](const ShowProgressBarProto::StepProgressBarIcon& icon) {
- return icon.identifier() == active_step_identifier;
- });
- if (it == step_progress_bar_configuration_.annotated_step_icons().cend()) {
- return false;
- }
-
- SetProgressActiveStep(std::distance(
- step_progress_bar_configuration_.annotated_step_icons().cbegin(), it));
- return true;
-}
-
-void Controller::SetProgressActiveStep(int active_step) {
- // Default step progress bar has 2 steps.
- int max_step = std::max(
- 2, step_progress_bar_configuration_.annotated_step_icons().size());
-
- int new_active_step = active_step;
- if (active_step < 0 || active_step > max_step) {
- new_active_step = max_step;
- }
-
- // Step can only increase.
- if (progress_active_step_ >= new_active_step) {
- return;
- }
-
- progress_active_step_ = new_active_step;
- for (ControllerObserver& observer : observers_) {
- observer.OnProgressActiveStepChanged(new_active_step);
- }
-}
-
-void Controller::SetProgressVisible(bool visible) {
- if (progress_visible_ == visible)
- return;
-
- progress_visible_ = visible;
- for (ControllerObserver& observer : observers_) {
- observer.OnProgressVisibilityChanged(visible);
- }
-}
-
-bool Controller::GetProgressVisible() const {
- return progress_visible_;
-}
-
-bool Controller::GetTtsButtonVisible() const {
- return tts_enabled_;
-}
-
-TtsButtonState Controller::GetTtsButtonState() const {
- return tts_button_state_;
-}
-
-void Controller::SetStepProgressBarConfiguration(
- const ShowProgressBarProto::StepProgressBarConfiguration& configuration) {
- step_progress_bar_configuration_ = configuration;
- if (!configuration.annotated_step_icons().empty() &&
- configuration.annotated_step_icons().size() < progress_active_step_) {
- progress_active_step_ = configuration.annotated_step_icons().size();
- }
- for (ControllerObserver& observer : observers_) {
- observer.OnStepProgressBarConfigurationChanged(configuration);
- observer.OnProgressActiveStepChanged(progress_active_step_);
- observer.OnProgressBarErrorStateChanged(progress_bar_error_state_);
- }
-}
-
-void Controller::SetProgressBarErrorState(bool error) {
- if (progress_bar_error_state_ == error) {
- return;
- }
-
- progress_bar_error_state_ = error;
- for (ControllerObserver& observer : observers_) {
- observer.OnProgressBarErrorStateChanged(error);
- }
-}
-
-bool Controller::GetProgressBarErrorState() const {
- return progress_bar_error_state_;
-}
-
-const std::vector<UserAction>& Controller::GetUserActions() const {
- static const base::NoDestructor<std::vector<UserAction>> no_user_actions_;
- return user_actions_ ? *user_actions_ : *no_user_actions_;
-}
-
-void Controller::SetUserActions(
- std::unique_ptr<std::vector<UserAction>> user_actions) {
- if (user_actions) {
- SetDefaultChipType(user_actions.get());
- }
- user_actions_ = std::move(user_actions);
- SetVisibilityAndUpdateUserActions();
-}
-
const std::vector<ScriptHandle>& Controller::GetDirectActionScripts() const {
return direct_action_scripts_;
}
-bool Controller::ShouldChipsBeVisible() {
- return !(is_keyboard_showing_ && is_focus_on_bottom_sheet_text_input_);
-}
-
-bool Controller::ShouldUpdateChipVisibility() {
- return are_chips_visible_ != ShouldChipsBeVisible();
-}
-
-void Controller::SetVisibilityAndUpdateUserActions() {
- // All non-cancel chips should be hidden while the keyboard is showing to fill
- // an input text field in the bottom sheet.
- are_chips_visible_ = ShouldChipsBeVisible();
- if (user_actions_) {
- for (UserAction& user_action : *user_actions_) {
- if (user_action.chip().type != CANCEL_ACTION) {
- user_action.chip().visible = are_chips_visible_;
- }
- }
- }
-
- for (ControllerObserver& observer : observers_) {
- observer.OnUserActionsChanged(GetUserActions());
- }
-}
-
bool Controller::IsNavigatingToNewDocument() {
return navigating_to_new_document_;
}
@@ -492,54 +171,8 @@ void Controller::SetUiShown(bool shown) {
runtime_manager_->SetUIState(shown ? UIState::kShown : UIState::kNotShown);
}
- // Stop any ongoing TTS if UI is hidden.
- if (!shown && tts_button_state_ == TtsButtonState::PLAYING) {
- // Will not cause any TTS event.
- tts_controller_->Stop();
- SetTtsButtonState(TtsButtonState::DEFAULT);
- }
-}
-
-void Controller::SetGenericUi(
- std::unique_ptr<GenericUserInterfaceProto> generic_ui,
- base::OnceCallback<void(const ClientStatus&)> end_action_callback,
- base::OnceCallback<void(const ClientStatus&)>
- view_inflation_finished_callback) {
- generic_user_interface_ = std::move(generic_ui);
- basic_interactions_.SetEndActionCallback(std::move(end_action_callback));
- basic_interactions_.SetViewInflationFinishedCallback(
- std::move(view_inflation_finished_callback));
for (ControllerObserver& observer : observers_) {
- observer.OnGenericUserInterfaceChanged(generic_user_interface_.get());
- }
-}
-
-void Controller::SetPersistentGenericUi(
- std::unique_ptr<GenericUserInterfaceProto> generic_ui,
- base::OnceCallback<void(const ClientStatus&)>
- view_inflation_finished_callback) {
- persistent_generic_user_interface_ = std::move(generic_ui);
- basic_interactions_.SetPersistentViewInflationFinishedCallback(
- std::move(view_inflation_finished_callback));
- for (ControllerObserver& observer : observers_) {
- observer.OnPersistentGenericUserInterfaceChanged(
- persistent_generic_user_interface_.get());
- }
-}
-
-void Controller::ClearGenericUi() {
- generic_user_interface_.reset();
- basic_interactions_.ClearCallbacks();
- for (ControllerObserver& observer : observers_) {
- observer.OnGenericUserInterfaceChanged(nullptr);
- }
-}
-
-void Controller::ClearPersistentGenericUi() {
- persistent_generic_user_interface_.reset();
- basic_interactions_.ClearPersistentUiCallbacks();
- for (ControllerObserver& observer : observers_) {
- observer.OnPersistentGenericUserInterfaceChanged(nullptr);
+ observer.OnUiShownChanged(shown);
}
}
@@ -552,10 +185,6 @@ bool Controller::ShouldShowWarning() {
state_ == AutofillAssistantState::PROMPT;
}
-void Controller::SetShowFeedbackChip(bool show_feedback_chip) {
- show_feedback_chip_on_graceful_shutdown_ = show_feedback_chip;
-}
-
ProcessedActionStatusDetailsProto& Controller::GetLogInfo() {
return log_info_;
}
@@ -578,10 +207,6 @@ void Controller::RemoveListener(ScriptExecutorDelegate::Listener* listener) {
listeners_.RemoveObserver(listener);
}
-void Controller::SetExpandSheetForPromptAction(bool expand) {
- expand_sheet_for_prompt_action_ = expand;
-}
-
void Controller::SetBrowseDomainsAllowlist(std::vector<std::string> domains) {
browse_domains_allowlist_ = std::move(domains);
}
@@ -604,26 +229,6 @@ bool Controller::PerformDirectAction(int index,
return true;
}
-bool Controller::PerformUserAction(int index) {
- if (!user_actions_ || index < 0 ||
- static_cast<size_t>(index) >= user_actions_->size()) {
- NOTREACHED() << "Invalid user_action index: " << index;
- return false;
- }
-
- if (!(*user_actions_)[index].enabled()) {
- NOTREACHED() << "Action at index " << index << " is disabled.";
- return false;
- }
-
- UserAction user_action = std::move((*user_actions_)[index]);
- SetUserActions(nullptr);
- user_action.RunCallback();
- event_handler_.DispatchEvent(
- {EventProto::kOnUserActionCalled, user_action.identifier()});
- return true;
-}
-
void Controller::SetViewportMode(ViewportMode mode) {
if (mode == viewport_mode_)
return;
@@ -634,42 +239,6 @@ void Controller::SetViewportMode(ViewportMode mode) {
}
}
-void Controller::SetPeekMode(ConfigureBottomSheetProto::PeekMode peek_mode) {
- if (peek_mode == peek_mode_)
- return;
-
- peek_mode_ = peek_mode;
- for (ControllerObserver& observer : observers_) {
- observer.OnPeekModeChanged(peek_mode);
- }
-}
-
-void Controller::ExpandBottomSheet() {
- for (ControllerObserver& observer : observers_) {
- // TODO(crbug/806868): The interface here and in some of the other On*
- // events should be coming from the UI layer, not the controller. Or at
- // least be renamed to something like On*Requested.
- observer.OnExpandBottomSheet();
- }
-}
-
-void Controller::CollapseBottomSheet() {
- for (ControllerObserver& observer : observers_) {
- // TODO(crbug/806868): The interface here and in some of the other On*
- // events should be coming from the UI layer, not the controller. Or at
- // least be renamed to something like On*Requested.
- observer.OnCollapseBottomSheet();
- }
-}
-
-const FormProto* Controller::GetForm() const {
- return form_.get();
-}
-
-const FormProto::Result* Controller::GetFormResult() const {
- return form_result_.get();
-}
-
void Controller::SetClientSettings(const ClientSettingsProto& client_settings) {
settings_.UpdateFromProto(client_settings);
for (ControllerObserver& observer : observers_) {
@@ -677,140 +246,12 @@ void Controller::SetClientSettings(const ClientSettingsProto& client_settings) {
}
}
-bool Controller::SetForm(
- std::unique_ptr<FormProto> form,
- base::RepeatingCallback<void(const FormProto::Result*)> changed_callback,
- base::OnceCallback<void(const ClientStatus&)> cancel_callback) {
- form_.reset();
- form_result_.reset();
- form_changed_callback_ = base::DoNothing();
- form_cancel_callback_ = base::DoNothing();
-
- if (!form) {
- for (ControllerObserver& observer : observers_) {
- observer.OnFormChanged(nullptr, nullptr);
- }
- return true;
- }
-
- // Initialize form result. This will return false if the form is invalid or
- // contains unsupported inputs.
- auto form_result = std::make_unique<FormProto::Result>();
- for (FormInputProto& input : *form->mutable_inputs()) {
- FormInputProto::Result* result = form_result->add_input_results();
- switch (input.input_type_case()) {
- case FormInputProto::InputTypeCase::kCounter:
- // Add the initial value of each counter into the form result.
- for (const CounterInputProto::Counter& counter :
- input.counter().counters()) {
- result->mutable_counter()->add_values(counter.initial_value());
- }
- break;
- case FormInputProto::InputTypeCase::kSelection: {
- // Add the initial selected state of each choice into the form result.
- bool has_selected = false;
- for (const SelectionInputProto::Choice& choice :
- input.selection().choices()) {
- if (choice.selected()) {
- if (has_selected && !input.selection().allow_multiple()) {
- // Multiple choices are initially selected even though it is not
- // allowed by the input.
- return false;
- }
- has_selected = true;
- }
- result->mutable_selection()->add_selected(choice.selected());
- }
- break;
- }
- case FormInputProto::InputTypeCase::INPUT_TYPE_NOT_SET:
- VLOG(1) << "Encountered input with INPUT_TYPE_NOT_SET";
- return false;
- // Intentionally no default case to make compilation fail if a new
- // value was added to the enum but not to this list.
- }
- }
-
- // Form is valid.
- form_ = std::move(form);
- form_result_ = std::move(form_result);
- form_changed_callback_ = changed_callback;
- form_cancel_callback_ = std::move(cancel_callback);
-
- // Call the callback with initial result.
- form_changed_callback_.Run(form_result_.get());
-
- for (ControllerObserver& observer : observers_) {
- observer.OnFormChanged(form_.get(), form_result_.get());
- }
- return true;
-}
-
-void Controller::SetCounterValue(int input_index,
- int counter_index,
- int value) {
- if (!form_result_ || input_index < 0 ||
- input_index >= form_result_->input_results_size()) {
- NOTREACHED() << "Invalid input index: " << input_index;
- return;
- }
-
- FormInputProto::Result* input_result =
- form_result_->mutable_input_results(input_index);
- if (!input_result->has_counter() || counter_index < 0 ||
- counter_index >= input_result->counter().values_size()) {
- NOTREACHED() << "Invalid counter index: " << counter_index;
- return;
- }
-
- input_result->mutable_counter()->set_values(counter_index, value);
- form_changed_callback_.Run(form_result_.get());
-}
-
-void Controller::SetChoiceSelected(int input_index,
- int choice_index,
- bool selected) {
- if (!form_result_ || input_index < 0 ||
- input_index >= form_result_->input_results_size()) {
- NOTREACHED() << "Invalid input index: " << input_index;
- return;
- }
-
- FormInputProto::Result* input_result =
- form_result_->mutable_input_results(input_index);
- if (!input_result->has_selection() || choice_index < 0 ||
- choice_index >= input_result->selection().selected_size()) {
- NOTREACHED() << "Invalid choice index: " << choice_index;
- return;
- }
-
- input_result->mutable_selection()->set_selected(choice_index, selected);
- form_changed_callback_.Run(form_result_.get());
-}
-
UserModel* Controller::GetUserModel() {
return &user_model_;
}
-EventHandler* Controller::GetEventHandler() {
- return &event_handler_;
-}
-
-bool Controller::ShouldPromptActionExpandSheet() const {
- return expand_sheet_for_prompt_action_;
-}
-
-BasicInteractions* Controller::GetBasicInteractions() {
- return &basic_interactions_;
-}
-
-const GenericUserInterfaceProto* Controller::GetGenericUiProto() const {
- return generic_user_interface_.get();
-}
-
-const GenericUserInterfaceProto* Controller::GetPersistentGenericUiProto()
- const {
- return persistent_generic_user_interface_.get();
+UserData* Controller::GetUserData() {
+ return &user_data_;
}
void Controller::AddObserver(ControllerObserver* observer) {
@@ -821,26 +262,10 @@ void Controller::RemoveObserver(const ControllerObserver* observer) {
observers_.RemoveObserver(observer);
}
-void Controller::DispatchEvent(const EventHandler::EventKey& key) {
- event_handler_.DispatchEvent(key);
-}
-
ViewportMode Controller::GetViewportMode() {
return viewport_mode_;
}
-ConfigureBottomSheetProto::PeekMode Controller::GetPeekMode() {
- return peek_mode_;
-}
-
-BottomSheetState Controller::GetBottomSheetState() {
- return bottom_sheet_state_;
-}
-
-void Controller::SetBottomSheetState(BottomSheetState state) {
- bottom_sheet_state_ = state;
-}
-
bool Controller::IsTabSelected() {
return tab_selected_;
}
@@ -869,6 +294,18 @@ void Controller::GetOverlayColors(OverlayColors* colors) const {
*colors = *overlay_colors_;
}
+void Controller::SetOverlayBehavior(
+ ConfigureUiStateProto::OverlayBehavior overlay_behavior) {
+ overlay_behavior_ = overlay_behavior;
+ for (ControllerObserver& observer : observers_) {
+ observer.OnShouldShowOverlayChanged(ShouldShowOverlay());
+ }
+}
+
+bool Controller::ShouldShowOverlay() const {
+ return overlay_behavior_ == ConfigureUiStateProto::DEFAULT;
+}
+
const ClientSettings& Controller::GetClientSettings() const {
return settings_;
}
@@ -879,6 +316,9 @@ void Controller::ShutdownIfNecessary() {
// point and therefore the reason we pass here in the argument should be
// ignored.
client_->Shutdown(Metrics::DropOutReason::UI_CLOSED_UNEXPECTEDLY);
+ } else if (NeedsUI()) {
+ needs_ui_ = false;
+ client_->DestroyUI();
}
}
@@ -888,33 +328,19 @@ void Controller::ReportNavigationStateChanged() {
}
}
-void Controller::EnterStoppedState(bool show_feedback_chip) {
+void Controller::EnterStoppedState() {
if (script_tracker_)
script_tracker_->StopScript();
-
- std::unique_ptr<std::vector<UserAction>> final_actions;
- if (base::FeatureList::IsEnabled(features::kAutofillAssistantFeedbackChip) &&
- show_feedback_chip) {
- final_actions = std::make_unique<std::vector<UserAction>>();
- UserAction feedback_action;
- Chip feedback_chip;
- feedback_chip.type = FEEDBACK_ACTION;
- feedback_chip.text =
- GetDisplayStringUTF8(ClientSettingsProto::SEND_FEEDBACK, GetSettings());
- feedback_action.SetCallback(base::BindOnce(&Controller::ShutdownIfNecessary,
- weak_ptr_factory_.GetWeakPtr()));
- feedback_action.chip() = feedback_chip;
- final_actions->emplace_back(std::move(feedback_action));
- }
-
- ClearInfoBox();
- SetDetails(nullptr, base::TimeDelta());
- SetUserActions(std::move(final_actions));
- SetCollectUserDataOptions(nullptr);
- SetForm(nullptr, base::DoNothing(), base::DoNothing());
+ SetStoppedUI();
EnterState(AutofillAssistantState::STOPPED);
}
+void Controller::SetStoppedUI() {
+ for (ControllerObserver& observer : observers_) {
+ observer.OnStop();
+ }
+}
+
bool Controller::EnterState(AutofillAssistantState state) {
if (state_ == state)
return false;
@@ -941,8 +367,6 @@ bool Controller::EnterState(AutofillAssistantState state) {
if (!ui_shown_ && StateNeedsUI(state)) {
RequireUI();
- } else if (needs_ui_ && state == AutofillAssistantState::TRACKING) {
- needs_ui_ = false;
} else if (browse_mode_invisible_ && ui_shown_ &&
state == AutofillAssistantState::BROWSE) {
needs_ui_ = false;
@@ -957,18 +381,6 @@ bool Controller::EnterState(AutofillAssistantState state) {
return true;
}
-AutofillAssistantState Controller::GetState() {
- return state_;
-}
-
-void Controller::SetOverlayBehavior(
- ConfigureUiStateProto::OverlayBehavior overlay_behavior) {
- overlay_behavior_ = overlay_behavior;
- for (ControllerObserver& observer : observers_) {
- observer.OnShouldShowOverlayChanged(ShouldShowOverlay());
- }
-}
-
void Controller::SetWebControllerForTest(
std::unique_ptr<WebController> web_controller) {
web_controller_ = std::move(web_controller);
@@ -1083,7 +495,6 @@ void Controller::OnGetScripts(const GURL& url,
#endif
OnFatalError(
GetDisplayStringUTF8(ClientSettingsProto::DEFAULT_ERROR, GetSettings()),
- /*show_feedback_chip=*/true,
Metrics::DropOutReason::GET_SCRIPTS_FAILED);
return;
}
@@ -1098,7 +509,6 @@ void Controller::OnGetScripts(const GURL& url,
#endif
OnFatalError(
GetDisplayStringUTF8(ClientSettingsProto::DEFAULT_ERROR, GetSettings()),
- /*show_feedback_chip=*/true,
Metrics::DropOutReason::GET_SCRIPTS_UNPARSABLE);
return;
}
@@ -1147,7 +557,6 @@ void Controller::OnGetScripts(const GURL& url,
if (state_ == AutofillAssistantState::TRACKING) {
OnFatalError(GetDisplayStringUTF8(ClientSettingsProto::DEFAULT_ERROR,
GetSettings()),
- /*show_feedback_chip=*/false,
Metrics::DropOutReason::NO_SCRIPTS);
return;
}
@@ -1173,19 +582,22 @@ void Controller::ExecuteScript(const std::string& script_path,
ResetState();
}
- if (!start_message.empty())
- SetStatusMessage(start_message);
-
- EnterState(AutofillAssistantState::RUNNING);
- if (needs_ui)
+ if (needs_ui) {
RequireUI();
+ } else if (needs_ui_ && state_ == AutofillAssistantState::TRACKING) {
+ needs_ui_ = false;
+ client_->DestroyUI();
+ }
+ EnterState(AutofillAssistantState::RUNNING);
- touchable_element_area()->Clear();
+ for (ControllerObserver& observer : observers_) {
+ observer.OnExecuteScript(start_message);
+ }
+ touchable_element_area()->Clear();
// Runnable scripts will be checked and reported if necessary after executing
// the script.
script_tracker_->ClearRunnableScripts();
- SetUserActions(nullptr);
direct_action_scripts_.clear();
script_tracker()->ExecuteScript(
@@ -1211,26 +623,24 @@ void Controller::OnScriptExecuted(const std::string& script_path,
return;
}
- if (result.touchable_element_area) {
- touchable_element_area()->SetFromProto(*result.touchable_element_area);
- }
-
switch (result.at_end) {
case ScriptExecutor::SHUTDOWN:
if (!tracking_) {
client_->Shutdown(Metrics::DropOutReason::SCRIPT_SHUTDOWN);
return;
}
+ needs_ui_ = false;
end_state = AutofillAssistantState::TRACKING;
break;
case ScriptExecutor::SHUTDOWN_GRACEFULLY:
if (!tracking_) {
- EnterStoppedState(
- /*show_feedback_chip=*/show_feedback_chip_on_graceful_shutdown_);
+ EnterStoppedState();
RecordDropOutOrShutdown(Metrics::DropOutReason::SCRIPT_SHUTDOWN);
return;
}
+ needs_ui_ = true;
+ SetStoppedUI();
end_state = AutofillAssistantState::TRACKING;
break;
@@ -1242,10 +652,14 @@ void Controller::OnScriptExecuted(const std::string& script_path,
client_->Shutdown(Metrics::DropOutReason::CUSTOM_TAB_CLOSED);
return;
}
+ needs_ui_ = false;
end_state = AutofillAssistantState::TRACKING;
return;
case ScriptExecutor::CONTINUE:
+ if (end_state == AutofillAssistantState::TRACKING) {
+ needs_ui_ = false;
+ }
break;
default:
@@ -1256,23 +670,12 @@ void Controller::OnScriptExecuted(const std::string& script_path,
}
void Controller::ResetState() {
- // TODO(b/204963552): this list is incomplete. It would be much better if,
- // instead of selectively clearing fields, we'd solve this in a more holistic
- // way.
- bubble_message_.clear();
- tts_message_.clear();
- status_message_.clear();
- details_.clear();
- info_box_.reset();
- progress_visible_ = true;
- progress_bar_error_state_ = false;
- progress_active_step_ = 0;
- step_progress_bar_configuration_ =
- ShowProgressBarProto::StepProgressBarConfiguration();
viewport_mode_ = ViewportMode::NO_RESIZE;
- peek_mode_ = ConfigureBottomSheetProto::HANDLE;
overlay_behavior_ = ConfigureUiStateProto::DEFAULT;
touchable_element_area()->Clear();
+ for (ControllerObserver& observer : observers_) {
+ observer.OnResetState();
+ }
}
void Controller::MaybeAutostartScript(
@@ -1313,10 +716,6 @@ void Controller::MaybeAutostartScript(
}
void Controller::InitFromParameters() {
- auto details = std::make_unique<Details>();
- if (details->UpdateFromParameters(trigger_context_->GetScriptParameters()))
- SetDetails(std::move(details), base::TimeDelta());
-
trigger_context_->GetScriptParameters().WriteToUserData(&user_data_);
const absl::optional<std::string> overlay_color =
@@ -1334,25 +733,20 @@ void Controller::InitFromParameters() {
}
// Ignore other colors, to allow future versions of the client to support
// setting more colors.
-
SetOverlayColors(std::move(colors));
}
+
const absl::optional<std::string> password_change_username =
trigger_context_->GetScriptParameters().GetPasswordChangeUsername();
if (password_change_username) {
DCHECK(GetDeeplinkURL().is_valid()); // |deeplink_url_| must be set.
user_data_.selected_login_.emplace(
GetDeeplinkURL().DeprecatedGetOriginAsURL(), *password_change_username);
- }
-
- const absl::optional<bool> enable_tts =
- trigger_context_->GetScriptParameters().GetEnableTts();
- if (enable_tts && enable_tts.value() &&
- !client_->IsSpokenFeedbackAccessibilityServiceEnabled()) {
- tts_enabled_ = true;
- for (ControllerObserver& observer : observers_) {
- observer.OnTtsButtonVisibilityChanged(/* visible= */ true);
- }
+ GetPasswordChangeSuccessTracker()->OnChangePasswordFlowStarted(
+ user_data_.selected_login_->origin,
+ user_data_.selected_login_->username,
+ password_manager::PasswordChangeSuccessTracker::StartEvent::
+ kAutomatedFlow);
}
user_model_.SetCurrentURL(GetCurrentURL());
@@ -1365,6 +759,9 @@ void Controller::Track(std::unique_ptr<TriggerContext> trigger_context,
if (state_ == AutofillAssistantState::INACTIVE) {
trigger_context_ = std::move(trigger_context);
InitFromParameters();
+ for (ControllerObserver& observer : observers_) {
+ observer.OnStart(*GetTriggerContext());
+ }
EnterState(AutofillAssistantState::TRACKING);
}
@@ -1405,15 +802,14 @@ bool Controller::Start(const GURL& deeplink_url,
return true;
}
+bool Controller::NeedsUI() const {
+ return needs_ui_;
+}
+
void Controller::ShowFirstMessageAndStart() {
- // |status_message_| may be non-empty due to a trigger script that was run.
- SetStatusMessage(
- status_message_.empty()
- ? l10n_util::GetStringFUTF8(IDS_AUTOFILL_ASSISTANT_LOADING,
- base::UTF8ToUTF16(GetCurrentURL().host()))
- : status_message_);
- SetStepProgressBarConfiguration(step_progress_bar_configuration_);
- SetProgressActiveStep(progress_active_step_);
+ for (ControllerObserver& observer : observers_) {
+ observer.OnStart(*GetTriggerContext());
+ }
EnterState(AutofillAssistantState::STARTING);
}
@@ -1421,14 +817,9 @@ AutofillAssistantState Controller::GetState() const {
return state_;
}
-bool Controller::ShouldShowOverlay() const {
- return overlay_behavior_ == ConfigureUiStateProto::DEFAULT;
-}
-
bool Controller::ShouldSuppressKeyboard() const {
return ShouldSuppressKeyboardForState(state_);
}
-
void Controller::OnScriptSelected(const ScriptHandle& handle,
std::unique_ptr<TriggerContext> context) {
ExecuteScript(handle.path, handle.start_message, handle.needs_ui,
@@ -1438,10 +829,9 @@ void Controller::OnScriptSelected(const ScriptHandle& handle,
: AutofillAssistantState::PROMPT);
}
-std::string Controller::GetDebugContext() {
+base::Value Controller::GetDebugContext() {
base::Value dict(base::Value::Type::DICTIONARY);
- dict.SetKey("status", base::Value(status_message_));
if (trigger_context_) {
std::vector<base::Value> parameters_js;
for (const auto& parameter :
@@ -1454,385 +844,7 @@ std::string Controller::GetDebugContext() {
}
dict.SetKey("scripts", script_tracker()->GetDebugContext());
- std::vector<base::Value> details_list;
- for (const auto& holder : details_) {
- details_list.push_back(holder.GetDetails().GetDebugContext());
- }
- dict.SetKey("details", base::Value(details_list));
-
- std::string output_js;
- base::JSONWriter::Write(dict, &output_js);
- return output_js;
-}
-
-const CollectUserDataOptions* Controller::GetCollectUserDataOptions() const {
- return collect_user_data_options_;
-}
-
-const UserData* Controller::GetUserData() const {
- return &user_data_;
-}
-
-void Controller::OnCollectUserDataContinueButtonClicked() {
- if (!collect_user_data_options_)
- return;
-
- auto callback = std::move(collect_user_data_options_->confirm_callback);
-
- SetCollectUserDataOptions(nullptr);
- std::move(callback).Run(&user_data_, &user_model_);
-}
-
-void Controller::OnCollectUserDataAdditionalActionTriggered(int index) {
- if (!collect_user_data_options_)
- return;
-
- auto callback =
- std::move(collect_user_data_options_->additional_actions_callback);
- SetCollectUserDataOptions(nullptr);
- std::move(callback).Run(index, &user_data_, &user_model_);
-}
-
-void Controller::OnTextLinkClicked(int link) {
- auto callback = std::move(collect_user_data_options_->terms_link_callback);
- SetCollectUserDataOptions(nullptr);
- std::move(callback).Run(link, &user_data_, &user_model_);
-}
-
-void Controller::OnFormActionLinkClicked(int link) {
- if (form_cancel_callback_ && form_result_ != nullptr) {
- form_result_->set_link(link);
- form_changed_callback_.Run(form_result_.get());
- std::move(form_cancel_callback_).Run(ClientStatus(ACTION_APPLIED));
- }
-}
-
-void Controller::OnTtsButtonClicked() {
- switch (tts_button_state_) {
- case TtsButtonState::DEFAULT:
- // Will fire a TTS_START event.
- tts_controller_->Speak(tts_message_, GetDisplayStringsLocale());
- Metrics::RecordTtsButtonAction(Metrics::TtsButtonAction::PLAY_TTS);
- break;
- case TtsButtonState::PLAYING:
- // Will not cause any TTS event.
- tts_controller_->Stop();
- SetTtsButtonState(TtsButtonState::DISABLED);
- Metrics::RecordTtsButtonAction(Metrics::TtsButtonAction::DISABLE_BUTTON);
- break;
- case TtsButtonState::DISABLED:
- SetTtsButtonState(TtsButtonState::DEFAULT);
- // Will fire a TTS_START event.
- tts_controller_->Speak(tts_message_, GetDisplayStringsLocale());
- Metrics::RecordTtsButtonAction(
- Metrics::TtsButtonAction::ENABLE_BUTTON_AND_PLAY_TTS);
- break;
- }
-}
-
-void Controller::OnTtsEvent(
- AutofillAssistantTtsController::TtsEventType event) {
- switch (event) {
- case AutofillAssistantTtsController::TTS_START:
- SetTtsButtonState(TtsButtonState::PLAYING);
- break;
- case AutofillAssistantTtsController::TTS_END:
- case AutofillAssistantTtsController::TTS_ERROR:
- SetTtsButtonState(TtsButtonState::DEFAULT);
- break;
- }
-}
-
-void Controller::SetTtsButtonState(TtsButtonState state) {
- tts_button_state_ = state;
- for (ControllerObserver& observer : observers_) {
- observer.OnTtsButtonStateChanged(tts_button_state_);
- }
-}
-
-void Controller::OnSpokenFeedbackAccessibilityServiceChanged(bool enabled) {
- if (!enabled) {
- // Nothing to do when the a11y service is disabled.
- return;
- }
-
- if (!tts_enabled_) {
- return;
- }
- // Disable TTS and hide TTS button.
- tts_enabled_ = false;
- for (ControllerObserver& observer : observers_) {
- observer.OnTtsButtonVisibilityChanged(/* visible= */ false);
- }
- // Stop any ongoing TTS and reset button state.
- if (tts_button_state_ == TtsButtonState::PLAYING) {
- // Will not cause any TTS event.
- tts_controller_->Stop();
- SetTtsButtonState(TtsButtonState::DEFAULT);
- }
-}
-
-void Controller::SetDateTimeRangeStartDate(
- const absl::optional<DateProto>& date) {
- if (user_data_.date_time_range_start_date_.has_value() && date.has_value() &&
- CollectUserDataAction::CompareDates(
- *user_data_.date_time_range_start_date_, *date) == 0) {
- return;
- }
-
- user_data_.date_time_range_start_date_ = date;
- for (ControllerObserver& observer : observers_) {
- observer.OnUserDataChanged(user_data_,
- UserData::FieldChange::DATE_TIME_RANGE_START);
- }
-
- if (CollectUserDataAction::SanitizeDateTimeRange(
- &user_data_.date_time_range_start_date_,
- &user_data_.date_time_range_start_timeslot_,
- &user_data_.date_time_range_end_date_,
- &user_data_.date_time_range_end_timeslot_,
- *collect_user_data_options_,
- /* change_start = */ false)) {
- for (ControllerObserver& observer : observers_) {
- observer.OnUserDataChanged(user_data_,
- UserData::FieldChange::DATE_TIME_RANGE_END);
- }
- }
-
- UpdateCollectUserDataActions();
-}
-
-void Controller::SetDateTimeRangeStartTimeSlot(
- const absl::optional<int>& timeslot_index) {
- if (user_data_.date_time_range_start_timeslot_.has_value() &&
- timeslot_index.has_value() &&
- *user_data_.date_time_range_start_timeslot_ == *timeslot_index) {
- return;
- }
-
- user_data_.date_time_range_start_timeslot_ = timeslot_index;
- for (ControllerObserver& observer : observers_) {
- observer.OnUserDataChanged(user_data_,
- UserData::FieldChange::DATE_TIME_RANGE_START);
- }
-
- if (CollectUserDataAction::SanitizeDateTimeRange(
- &user_data_.date_time_range_start_date_,
- &user_data_.date_time_range_start_timeslot_,
- &user_data_.date_time_range_end_date_,
- &user_data_.date_time_range_end_timeslot_,
- *collect_user_data_options_,
- /* change_start = */ false)) {
- for (ControllerObserver& observer : observers_) {
- observer.OnUserDataChanged(user_data_,
- UserData::FieldChange::DATE_TIME_RANGE_END);
- }
- }
-
- UpdateCollectUserDataActions();
-}
-
-void Controller::SetDateTimeRangeEndDate(
- const absl::optional<DateProto>& date) {
- if (user_data_.date_time_range_end_date_.has_value() && date.has_value() &&
- CollectUserDataAction::CompareDates(*user_data_.date_time_range_end_date_,
- *date) == 0) {
- return;
- }
-
- user_data_.date_time_range_end_date_ = date;
- for (ControllerObserver& observer : observers_) {
- observer.OnUserDataChanged(user_data_,
- UserData::FieldChange::DATE_TIME_RANGE_END);
- }
-
- if (CollectUserDataAction::SanitizeDateTimeRange(
- &user_data_.date_time_range_start_date_,
- &user_data_.date_time_range_start_timeslot_,
- &user_data_.date_time_range_end_date_,
- &user_data_.date_time_range_end_timeslot_,
- *collect_user_data_options_,
- /* change_start = */ true)) {
- for (ControllerObserver& observer : observers_) {
- observer.OnUserDataChanged(user_data_,
- UserData::FieldChange::DATE_TIME_RANGE_START);
- }
- }
-
- UpdateCollectUserDataActions();
-}
-
-void Controller::SetDateTimeRangeEndTimeSlot(
- const absl::optional<int>& timeslot_index) {
- if (user_data_.date_time_range_end_timeslot_.has_value() &&
- timeslot_index.has_value() &&
- *user_data_.date_time_range_end_timeslot_ == *timeslot_index) {
- return;
- }
-
- user_data_.date_time_range_end_timeslot_ = timeslot_index;
- for (ControllerObserver& observer : observers_) {
- observer.OnUserDataChanged(user_data_,
- UserData::FieldChange::DATE_TIME_RANGE_END);
- }
-
- if (CollectUserDataAction::SanitizeDateTimeRange(
- &user_data_.date_time_range_start_date_,
- &user_data_.date_time_range_start_timeslot_,
- &user_data_.date_time_range_end_date_,
- &user_data_.date_time_range_end_timeslot_,
- *collect_user_data_options_,
- /* change_start = */ true)) {
- for (ControllerObserver& observer : observers_) {
- observer.OnUserDataChanged(user_data_,
- UserData::FieldChange::DATE_TIME_RANGE_START);
- }
- }
-
- UpdateCollectUserDataActions();
-}
-
-void Controller::SetAdditionalValue(const std::string& client_memory_key,
- const ValueProto& value) {
- if (!user_data_.HasAdditionalValue(client_memory_key)) {
- NOTREACHED() << client_memory_key << " not found";
- return;
- }
- user_data_.SetAdditionalValue(client_memory_key, value);
- UpdateCollectUserDataActions();
- for (ControllerObserver& observer : observers_) {
- observer.OnUserDataChanged(user_data_,
- UserData::FieldChange::ADDITIONAL_VALUES);
- }
-}
-
-void Controller::SetShippingAddress(
- std::unique_ptr<autofill::AutofillProfile> address,
- UserDataEventType event_type) {
- if (collect_user_data_options_ == nullptr) {
- return;
- }
-
- collect_user_data_options_->selected_user_data_changed_callback.Run(
- SHIPPING_EVENT, event_type);
- DCHECK(!collect_user_data_options_->shipping_address_name.empty());
- SetProfile(collect_user_data_options_->shipping_address_name,
- UserData::FieldChange::SHIPPING_ADDRESS, std::move(address));
-}
-
-void Controller::SetContactInfo(
- std::unique_ptr<autofill::AutofillProfile> profile,
- UserDataEventType event_type) {
- if (collect_user_data_options_ == nullptr) {
- return;
- }
-
- collect_user_data_options_->selected_user_data_changed_callback.Run(
- CONTACT_EVENT, event_type);
- DCHECK(!collect_user_data_options_->contact_details_name.empty());
- SetProfile(collect_user_data_options_->contact_details_name,
- UserData::FieldChange::CONTACT_PROFILE, std::move(profile));
-}
-
-void Controller::SetCreditCard(
- std::unique_ptr<autofill::CreditCard> card,
- std::unique_ptr<autofill::AutofillProfile> billing_profile,
- UserDataEventType event_type) {
- if (collect_user_data_options_ == nullptr) {
- return;
- }
-
- collect_user_data_options_->selected_user_data_changed_callback.Run(
- CREDIT_CARD_EVENT, event_type);
- DCHECK(!collect_user_data_options_->billing_address_name.empty());
- user_model_.SetSelectedCreditCard(std::move(card), &user_data_);
- for (ControllerObserver& observer : observers_) {
- observer.OnUserDataChanged(user_data_, UserData::FieldChange::CARD);
- }
- SetProfile(collect_user_data_options_->billing_address_name,
- UserData::FieldChange::BILLING_ADDRESS,
- std::move(billing_profile));
-}
-
-void Controller::SetProfile(
- const std::string& key,
- UserData::FieldChange field_change,
- std::unique_ptr<autofill::AutofillProfile> profile) {
- user_model_.SetSelectedAutofillProfile(key, std::move(profile), &user_data_);
-
- for (ControllerObserver& observer : observers_) {
- observer.OnUserDataChanged(user_data_, field_change);
- }
- UpdateCollectUserDataActions();
-}
-
-void Controller::ReloadUserData(UserDataEventField event_field,
- UserDataEventType event_type) {
- if (collect_user_data_options_ == nullptr) {
- return;
- }
-
- collect_user_data_options_->selected_user_data_changed_callback.Run(
- event_field, event_type);
-
- auto callback = std::move(collect_user_data_options_->reload_data_callback);
- SetCollectUserDataOptions(nullptr);
- std::move(callback).Run(&user_data_);
-}
-
-void Controller::SetTermsAndConditions(
- TermsAndConditionsState terms_and_conditions) {
- user_data_.terms_and_conditions_ = terms_and_conditions;
- UpdateCollectUserDataActions();
- for (ControllerObserver& observer : observers_) {
- observer.OnUserDataChanged(user_data_,
- UserData::FieldChange::TERMS_AND_CONDITIONS);
- }
-}
-
-void Controller::SetLoginOption(const std::string& identifier) {
- if (!collect_user_data_options_)
- return;
-
- user_model_.SetSelectedLoginChoiceByIdentifier(
- identifier, *collect_user_data_options_, &user_data_);
- UpdateCollectUserDataActions();
- for (ControllerObserver& observer : observers_) {
- observer.OnUserDataChanged(user_data_, UserData::FieldChange::LOGIN_CHOICE);
- }
-}
-
-void Controller::UpdateCollectUserDataActions() {
- if (!collect_user_data_options_) {
- SetUserActions(nullptr);
- return;
- }
-
- bool confirm_button_enabled = CollectUserDataAction::IsUserDataComplete(
- user_data_, user_model_, *collect_user_data_options_);
-
- UserAction confirm(collect_user_data_options_->confirm_action);
- confirm.SetEnabled(confirm_button_enabled);
- if (confirm_button_enabled) {
- confirm.SetCallback(
- base::BindOnce(&Controller::OnCollectUserDataContinueButtonClicked,
- weak_ptr_factory_.GetWeakPtr()));
- }
-
- auto user_actions = std::make_unique<std::vector<UserAction>>();
- user_actions->emplace_back(std::move(confirm));
-
- // Add additional actions.
- for (size_t i = 0; i < collect_user_data_options_->additional_actions.size();
- ++i) {
- auto action = collect_user_data_options_->additional_actions[i];
- user_actions->push_back({action});
- user_actions->back().SetCallback(
- base::BindOnce(&Controller::OnCollectUserDataAdditionalActionTriggered,
- weak_ptr_factory_.GetWeakPtr(), i));
- }
-
- SetUserActions(std::move(user_actions));
+ return dict;
}
void Controller::GetTouchableArea(std::vector<RectF>* area) const {
@@ -1856,9 +868,10 @@ void Controller::OnScriptError(const std::string& error_message,
return;
RequireUI();
- SetStatusMessage(error_message);
- SetProgressBarErrorState(true);
- EnterStoppedState(/*show_feedback_chip=*/true);
+ for (ControllerObserver& observer : observers_) {
+ observer.OnError(error_message, reason);
+ }
+ EnterStoppedState();
if (tracking_) {
EnterState(AutofillAssistantState::TRACKING);
@@ -1869,7 +882,6 @@ void Controller::OnScriptError(const std::string& error_message,
}
void Controller::OnFatalError(const std::string& error_message,
- bool show_feedback_chip,
Metrics::DropOutReason reason) {
LOG(ERROR) << "Autofill Assistant has encountered a fatal error and is "
"shutting down, reason="
@@ -1877,9 +889,10 @@ void Controller::OnFatalError(const std::string& error_message,
if (state_ == AutofillAssistantState::STOPPED)
return;
- SetStatusMessage(error_message);
- SetProgressBarErrorState(true);
- EnterStoppedState(show_feedback_chip);
+ for (ControllerObserver& observer : observers_) {
+ observer.OnError(error_message, reason);
+ }
+ EnterStoppedState();
// If we haven't managed to check the set of scripts yet at this point, we
// never will.
@@ -2111,6 +1124,15 @@ void Controller::DidStartNavigation(
return;
}
+ // When in TRACKING state all navigation is allowed, but user-initiated
+ // navigation will close the UI if any.
+ if (state_ == AutofillAssistantState::TRACKING &&
+ is_user_initiated_or_back_forward &&
+ !navigation_handle->WasServerRedirect()) {
+ ShutdownIfNecessary();
+ return;
+ }
+
// Note that BROWSE state end conditions are in DidFinishNavigation, in order
// to be able to properly evaluate the committed url.
}
@@ -2158,8 +1180,7 @@ void Controller::DidFinishNavigation(
}
}
-void Controller::DocumentAvailableInMainFrame(
- content::RenderFrameHost* render_frame_host) {
+void Controller::PrimaryMainDocumentElementAvailable() {
OnUrlChange();
}
@@ -2193,19 +1214,6 @@ void Controller::SuppressKeyboard(bool suppress) {
}
}
-void Controller::OnValueChanged(const std::string& identifier,
- const ValueProto& new_value) {
- event_handler_.DispatchEvent({EventProto::kOnValueChanged, identifier});
- // TODO(b/145043394) Remove this once chips are part of generic UI.
- if (collect_user_data_options_ != nullptr &&
- collect_user_data_options_->additional_model_identifier_to_check
- .has_value() &&
- identifier ==
- *collect_user_data_options_->additional_model_identifier_to_check) {
- UpdateCollectUserDataActions();
- }
-}
-
void Controller::OnTouchableAreaChanged(
const RectF& visual_viewport,
const std::vector<RectF>& touchable_areas,
@@ -2216,32 +1224,6 @@ void Controller::OnTouchableAreaChanged(
}
}
-void Controller::SetCollectUserDataOptions(CollectUserDataOptions* options) {
- DCHECK(!options ||
- (options->confirm_callback && options->additional_actions_callback &&
- options->terms_link_callback));
-
- if (collect_user_data_options_ == nullptr && options == nullptr)
- return;
-
- collect_user_data_options_ = options;
- UpdateCollectUserDataActions();
- for (ControllerObserver& observer : observers_) {
- observer.OnCollectUserDataOptionsChanged(collect_user_data_options_);
- observer.OnUserDataChanged(user_data_, UserData::FieldChange::ALL);
- }
-}
-
-void Controller::SetLastSuccessfulUserDataOptions(
- std::unique_ptr<CollectUserDataOptions> collect_user_data_options) {
- last_collect_user_data_options_ = std::move(collect_user_data_options);
-}
-
-const CollectUserDataOptions* Controller::GetLastSuccessfulUserDataOptions()
- const {
- return last_collect_user_data_options_.get();
-}
-
void Controller::WriteUserData(
base::OnceCallback<void(UserData*, UserData::FieldChange*)>
write_callback) {
@@ -2250,10 +1232,13 @@ void Controller::WriteUserData(
if (field_change == UserData::FieldChange::NONE) {
return;
}
+ NotifyUserDataChange(field_change);
+}
+
+void Controller::NotifyUserDataChange(UserData::FieldChange field_change) {
for (ControllerObserver& observer : observers_) {
observer.OnUserDataChanged(user_data_, field_change);
}
- UpdateCollectUserDataActions();
}
bool Controller::StateNeedsUI(AutofillAssistantState state) {
@@ -2276,22 +1261,6 @@ bool Controller::StateNeedsUI(AutofillAssistantState state) {
}
}
-void Controller::OnKeyboardVisibilityChanged(bool visible) {
- is_keyboard_showing_ = visible;
-
- if (ShouldUpdateChipVisibility()) {
- SetVisibilityAndUpdateUserActions();
- }
-}
-
-void Controller::OnInputTextFocusChanged(bool is_text_focused) {
- is_focus_on_bottom_sheet_text_input_ = is_text_focused;
-
- if (ShouldUpdateChipVisibility()) {
- SetVisibilityAndUpdateUserActions();
- }
-}
-
ElementArea* Controller::touchable_element_area() {
if (!touchable_element_area_) {
touchable_element_area_ =
@@ -2304,8 +1273,10 @@ ElementArea* Controller::touchable_element_area() {
ScriptTracker* Controller::script_tracker() {
if (!script_tracker_) {
- script_tracker_ = std::make_unique<ScriptTracker>(/* delegate= */ this,
- /* listener= */ this);
+ script_tracker_ = std::make_unique<ScriptTracker>(
+ /* delegate= */ this,
+ /* ui_delegate= */ client_->GetScriptExecutorUiDelegate(),
+ /* listener= */ this);
}
return script_tracker_.get();
}
diff --git a/chromium/components/autofill_assistant/browser/controller.h b/chromium/components/autofill_assistant/browser/controller.h
index 15d40ef378b..f4b0e0df09b 100644
--- a/chromium/components/autofill_assistant/browser/controller.h
+++ b/chromium/components/autofill_assistant/browser/controller.h
@@ -11,13 +11,10 @@
#include "base/callback_helpers.h"
#include "base/memory/raw_ptr.h"
-#include "components/autofill_assistant/browser/autofill_assistant_tts_controller.h"
-#include "components/autofill_assistant/browser/basic_interactions.h"
-#include "components/autofill_assistant/browser/bottom_sheet_state.h"
#include "components/autofill_assistant/browser/client.h"
#include "components/autofill_assistant/browser/client_settings.h"
#include "components/autofill_assistant/browser/element_area.h"
-#include "components/autofill_assistant/browser/event_handler.h"
+#include "components/autofill_assistant/browser/execution_delegate.h"
#include "components/autofill_assistant/browser/metrics.h"
#include "components/autofill_assistant/browser/public/runtime_manager.h"
#include "components/autofill_assistant/browser/script.h"
@@ -28,6 +25,7 @@
#include "components/autofill_assistant/browser/state.h"
#include "components/autofill_assistant/browser/suppress_keyboard_raii.h"
#include "components/autofill_assistant/browser/trigger_context.h"
+#include "components/autofill_assistant/browser/ui_controller.h"
#include "components/autofill_assistant/browser/ui_delegate.h"
#include "components/autofill_assistant/browser/user_data.h"
#include "components/autofill_assistant/browser/user_model.h"
@@ -47,6 +45,10 @@ namespace base {
class TickClock;
} // namespace base
+namespace password_manager {
+class PasswordChangeSuccessTracker;
+} // namespace password_manager
+
namespace autofill_assistant {
class ControllerTest;
@@ -54,21 +56,19 @@ class ControllerTest;
// display, execution and so on. The instance of this object self deletes when
// the web contents is being destroyed.
class Controller : public ScriptExecutorDelegate,
- public virtual UiDelegate,
public ScriptTracker::Listener,
private content::WebContentsObserver,
- public UserModel::Observer,
- public AutofillAssistantTtsController::TtsEventDelegate {
+ public ExecutionDelegate {
public:
- // |web_contents|, |client|, |tick_clock| and |runtime_manager| must remain
- // valid for the lifetime of the instance. Controller will take ownership of
- // |service| if specified, otherwise will create and own the default service.
+ // |web_contents|, |client|, |tick_clock| and |script_executor_ui_delegate|
+ // must remain valid for the lifetime of the instance. Controller will take
+ // ownership of |service| if specified, otherwise will create and own the
+ // default service.
Controller(content::WebContents* web_contents,
Client* client,
const base::TickClock* tick_clock,
base::WeakPtr<RuntimeManager> runtime_manager,
std::unique_ptr<Service> service,
- std::unique_ptr<AutofillAssistantTtsController> tts_controller,
ukm::UkmRecorder* ukm_recorder,
AnnotateDomModelService* annotate_dom_model_service);
@@ -106,15 +106,9 @@ class Controller : public ScriptExecutorDelegate,
bool Start(const GURL& deeplink_url,
std::unique_ptr<TriggerContext> trigger_context);
- // Returns true if the controller is in a state where UI is necessary.
- bool NeedsUI() const { return needs_ui_; }
-
- // Called when an accessibility service with "FEEDBACK_SPOKEN" feedback type
- // is enabled or disabled.
- void OnSpokenFeedbackAccessibilityServiceChanged(bool enabled);
-
const std::vector<ScriptHandle>& GetDirectActionScripts() const;
bool PerformDirectAction(int index, std::unique_ptr<TriggerContext> context);
+ base::Value GetDebugContext();
// Overrides ScriptExecutorDelegate:
const ClientSettings& GetSettings() override;
@@ -126,65 +120,24 @@ class Controller : public ScriptExecutorDelegate,
const TriggerContext* GetTriggerContext() override;
autofill::PersonalDataManager* GetPersonalDataManager() override;
WebsiteLoginManager* GetWebsiteLoginManager() override;
+ password_manager::PasswordChangeSuccessTracker*
+ GetPasswordChangeSuccessTracker() override;
content::WebContents* GetWebContents() override;
std::string GetEmailAddressForAccessTokenAccount() override;
ukm::UkmRecorder* GetUkmRecorder() override;
-
void SetTouchableElementArea(const ElementAreaProto& area) override;
- void SetStatusMessage(const std::string& message) override;
- std::string GetStatusMessage() const override;
- void SetBubbleMessage(const std::string& message) override;
- std::string GetBubbleMessage() const override;
- void SetTtsMessage(const std::string& message) override;
- std::string GetTtsMessage() const override;
- void MaybePlayTtsMessage() override;
- void SetDetails(std::unique_ptr<Details>, base::TimeDelta delay) override;
- void AppendDetails(std::unique_ptr<Details> details,
- base::TimeDelta delay) override;
- void SetInfoBox(const InfoBox& info_box) override;
- void ClearInfoBox() override;
- bool SetProgressActiveStepIdentifier(
- const std::string& active_step_identifier) override;
- void SetProgressActiveStep(int active_step) override;
- void SetProgressVisible(bool visible) override;
- void SetProgressBarErrorState(bool error) override;
- void SetStepProgressBarConfiguration(
- const ShowProgressBarProto::StepProgressBarConfiguration& configuration)
- override;
- void SetUserActions(
- std::unique_ptr<std::vector<UserAction>> user_actions) override;
void SetViewportMode(ViewportMode mode) override;
- void SetPeekMode(ConfigureBottomSheetProto::PeekMode peek_mode) override;
- void ExpandBottomSheet() override;
- void CollapseBottomSheet() override;
void SetClientSettings(const ClientSettingsProto& client_settings) override;
- bool SetForm(
- std::unique_ptr<FormProto> form,
- base::RepeatingCallback<void(const FormProto::Result*)> changed_callback,
- base::OnceCallback<void(const ClientStatus&)> cancel_callback) override;
void ExpectNavigation() override;
bool IsNavigatingToNewDocument() override;
bool HasNavigationError() override;
- void SetGenericUi(
- std::unique_ptr<GenericUserInterfaceProto> generic_ui,
- base::OnceCallback<void(const ClientStatus&)> end_action_callback,
- base::OnceCallback<void(const ClientStatus&)>
- view_inflation_finished_callback) override;
- void SetPersistentGenericUi(
- std::unique_ptr<GenericUserInterfaceProto> generic_ui,
- base::OnceCallback<void(const ClientStatus&)>
- view_inflation_finished_callback) override;
- void ClearGenericUi() override;
- void ClearPersistentGenericUi() override;
void SetBrowseModeInvisible(bool invisible) override;
bool ShouldShowWarning() override;
- void SetShowFeedbackChip(bool show_feedback_chip) override;
ProcessedActionStatusDetailsProto& GetLogInfo() override;
// Show the UI if it's not already shown. This is only meaningful while in
// states where showing the UI is optional, such as RUNNING, in tracking mode.
void RequireUI() override;
- void SetUiShown(bool shown) override;
void AddNavigationListener(
ScriptExecutorDelegate::NavigationListener* listener) override;
@@ -193,18 +146,12 @@ class Controller : public ScriptExecutorDelegate,
void AddListener(ScriptExecutorDelegate::Listener* listener) override;
void RemoveListener(ScriptExecutorDelegate::Listener* listener) override;
- void SetExpandSheetForPromptAction(bool expand) override;
void SetBrowseDomainsAllowlist(std::vector<std::string> domains) override;
bool EnterState(AutofillAssistantState state) override;
- AutofillAssistantState GetState() override;
+ AutofillAssistantState GetState() const override;
void SetOverlayBehavior(
ConfigureUiStateProto::OverlayBehavior overlay_behavior) override;
- void SetCollectUserDataOptions(CollectUserDataOptions* options) override;
- void SetLastSuccessfulUserDataOptions(std::unique_ptr<CollectUserDataOptions>
- collect_user_data_options) override;
- const CollectUserDataOptions* GetLastSuccessfulUserDataOptions()
- const override;
void WriteUserData(
base::OnceCallback<void(UserData*, UserData::FieldChange*)>) override;
void OnScriptError(const std::string& error_message,
@@ -212,119 +159,35 @@ class Controller : public ScriptExecutorDelegate,
void OnNavigationShutdownOrError(const GURL& url,
Metrics::DropOutReason reason);
- // Overrides autofill_assistant::UiDelegate:
- AutofillAssistantState GetState() const override;
- std::vector<Details> GetDetails() const override;
- const InfoBox* GetInfoBox() const override;
- int GetProgressActiveStep() const override;
- bool GetProgressVisible() const override;
- bool GetTtsButtonVisible() const override;
- TtsButtonState GetTtsButtonState() const override;
- bool GetProgressBarErrorState() const override;
- ShowProgressBarProto::StepProgressBarConfiguration
- GetStepProgressBarConfiguration() const override;
- const std::vector<UserAction>& GetUserActions() const override;
- bool PerformUserAction(int index) override;
- std::string GetDebugContext() override;
- const CollectUserDataOptions* GetCollectUserDataOptions() const override;
- const UserData* GetUserData() const override;
- void SetShippingAddress(std::unique_ptr<autofill::AutofillProfile> address,
- UserDataEventType event_type) override;
- void SetContactInfo(std::unique_ptr<autofill::AutofillProfile> profile,
- UserDataEventType event_type) override;
- void SetCreditCard(std::unique_ptr<autofill::CreditCard> card,
- std::unique_ptr<autofill::AutofillProfile> billing_profile,
- UserDataEventType event_type) override;
- void ReloadUserData(UserDataEventField event_field,
- UserDataEventType event_type) override;
- void SetTermsAndConditions(
- TermsAndConditionsState terms_and_conditions) override;
- void SetLoginOption(const std::string& identifier) override;
- void OnTextLinkClicked(int link) override;
- void OnFormActionLinkClicked(int link) override;
- void OnTtsButtonClicked() override;
- void SetDateTimeRangeStartDate(
- const absl::optional<DateProto>& date) override;
- void SetDateTimeRangeStartTimeSlot(
- const absl::optional<int>& timeslot_index) override;
- void SetDateTimeRangeEndDate(const absl::optional<DateProto>& date) override;
- void SetDateTimeRangeEndTimeSlot(
- const absl::optional<int>& timeslot_index) override;
- void SetAdditionalValue(const std::string& client_memory_key,
- const ValueProto& value) override;
- void GetTouchableArea(std::vector<RectF>* area) const override;
- void GetRestrictedArea(std::vector<RectF>* area) const override;
- void GetVisualViewport(RectF* visual_viewport) const override;
- void OnFatalError(const std::string& error_message,
- bool show_feedback_chip,
- Metrics::DropOutReason reason) override;
+ // Overrides ExecutionDelegate:
+ bool NeedsUI() const override;
void OnStop(const std::string& message,
const std::string& button_label) override;
- void MaybeReportFirstCheckDone();
+ void GetVisualViewport(RectF* visual_viewport) const override;
ViewportMode GetViewportMode() override;
- ConfigureBottomSheetProto::PeekMode GetPeekMode() override;
- BottomSheetState GetBottomSheetState() override;
- void SetBottomSheetState(BottomSheetState state) override;
bool IsTabSelected() override;
void SetTabSelected(bool selected) override;
void GetOverlayColors(OverlayColors* colors) const override;
- const ClientSettings& GetClientSettings() const override;
- const FormProto* GetForm() const override;
- const FormProto::Result* GetFormResult() const override;
- void SetCounterValue(int input_index, int counter_index, int value) override;
- void SetChoiceSelected(int input_index,
- int choice_index,
- bool selected) override;
- void AddObserver(ControllerObserver* observer) override;
- void RemoveObserver(const ControllerObserver* observer) override;
- void DispatchEvent(const EventHandler::EventKey& key) override;
- UserModel* GetUserModel() override;
- EventHandler* GetEventHandler() override;
- bool ShouldPromptActionExpandSheet() const override;
- BasicInteractions* GetBasicInteractions() override;
- const GenericUserInterfaceProto* GetGenericUiProto() const override;
- const GenericUserInterfaceProto* GetPersistentGenericUiProto() const override;
- bool ShouldShowOverlay() const override;
bool ShouldSuppressKeyboard() const override;
void SuppressKeyboard(bool suppress) override;
+ UserData* GetUserData() override;
+ UserModel* GetUserModel() override;
+ bool ShouldShowOverlay() const override;
+ const ClientSettings& GetClientSettings() const override;
void ShutdownIfNecessary() override;
- void OnKeyboardVisibilityChanged(bool visible) override;
- void OnInputTextFocusChanged(bool is_text_focused) override;
+ void NotifyUserDataChange(UserData::FieldChange field_change) override;
+ void GetTouchableArea(std::vector<RectF>* area) const override;
+ void GetRestrictedArea(std::vector<RectF>* area) const override;
+ void OnFatalError(const std::string& error_message,
+ Metrics::DropOutReason reason) override;
+ void SetUiShown(bool shown) override;
- // Overrides AutofillAssistantTtsController::TtsEventDelegate
- void OnTtsEvent(AutofillAssistantTtsController::TtsEventType event) override;
+ void AddObserver(ControllerObserver* observer) override;
+ void RemoveObserver(const ControllerObserver* observer) override;
private:
friend ControllerTest;
- // A holder class which contains some details and, optionally, a timer that
- // will "enable" them later on.
- class DetailsHolder {
- public:
- DetailsHolder(std::unique_ptr<Details> details,
- std::unique_ptr<base::OneShotTimer> timer);
- ~DetailsHolder();
- DetailsHolder(DetailsHolder&& other);
- DetailsHolder& operator=(DetailsHolder&& other);
-
- // The details held by this object.
- const Details& GetDetails() const;
-
- // Whether the details held by this object are visible. Will return false if
- // a timer was set and was not reached yet.
- bool CurrentlyVisible() const;
-
- // Enable the details held by this object so that they are shown (i.e.
- // CurrentlyVisible() returns true).
- //
- // In practice, this is called at most once when |timer_| is triggered.
- void Enable();
-
- private:
- std::unique_ptr<Details> details_;
- std::unique_ptr<base::OneShotTimer> timer_;
- };
-
void SetWebControllerForTest(std::unique_ptr<WebController> web_controller);
// Called when the committed URL has or might have changed.
@@ -362,6 +225,8 @@ class Controller : public ScriptExecutorDelegate,
void StopPeriodicScriptChecks();
void OnPeriodicScriptCheck();
+ void MaybeReportFirstCheckDone();
+
// Runs autostart scripts from |runnable_scripts|, if the conditions are
// right. Nothing happens if an empty vector is passed.
// If none of the scripts is autostartable or too many are, it stops the
@@ -376,10 +241,6 @@ class Controller : public ScriptExecutorDelegate,
void OnScriptSelected(const ScriptHandle& handle,
std::unique_ptr<TriggerContext> context);
- void UpdateCollectUserDataActions();
- void OnCollectUserDataContinueButtonClicked();
- void OnCollectUserDataAdditionalActionTriggered(int index);
-
// Overrides ScriptTracker::Listener:
void OnNoRunnableScriptsForPage() override;
void OnRunnableScriptsChanged(
@@ -392,18 +253,13 @@ class Controller : public ScriptExecutorDelegate,
content::NavigationHandle* navigation_handle) override;
void DidFinishNavigation(
content::NavigationHandle* navigation_handle) override;
- void DocumentAvailableInMainFrame(
- content::RenderFrameHost* render_frame_host) override;
+ void PrimaryMainDocumentElementAvailable() override;
void PrimaryMainFrameRenderProcessGone(
base::TerminationStatus status) override;
void OnWebContentsFocused(
content::RenderWidgetHost* render_widget_host) override;
void WebContentsDestroyed() override;
- // Overrides autofill_assistant::UserModel::Observer:
- void OnValueChanged(const std::string& identifier,
- const ValueProto& new_value) override;
-
void OnTouchableAreaChanged(const RectF& visual_viewport,
const std::vector<RectF>& touchable_areas,
const std::vector<RectF>& restricted_areas);
@@ -418,11 +274,11 @@ class Controller : public ScriptExecutorDelegate,
void ShowFirstMessageAndStart();
// Clear out visible state and enter the stopped state.
- // If |show_feedback_chip| is true, a "Send feedback" chip will be added to
- // the bottom sheet.
- void EnterStoppedState(bool show_feedback_chip);
+ void EnterStoppedState();
- void OnFeedbackChipClicked();
+ // Configure the UI for the stopped state, clearing out visible state except
+ // for the message and possibly the "Send feedback" chip.
+ void SetStoppedUI();
ElementArea* touchable_element_area();
ScriptTracker* script_tracker();
@@ -433,23 +289,8 @@ class Controller : public ScriptExecutorDelegate,
bool StateNeedsUI(AutofillAssistantState state);
- bool ShouldChipsBeVisible();
- bool ShouldUpdateChipVisibility();
- void SetVisibilityAndUpdateUserActions();
-
- void MakeDetailsVisible(size_t details_index);
- void NotifyDetailsChanged();
-
- // This represents the display strings locale to be used for the currently
- // executing set of actions. This locale is used in two ways currently:
- // 1. Locale of backend provided display strings, if available.
- // 2. TTS Controller uses this locale for playing TTS messages.
- std::string GetDisplayStringsLocale();
- void SetTtsButtonState(TtsButtonState state);
-
// Resets the controller to the initial state.
void ResetState();
-
void SetDirectActionScripts(
const std::vector<ScriptHandle>& direct_action_scripts);
@@ -503,63 +344,19 @@ class Controller : public ScriptExecutorDelegate,
// Lazily instantiate in touchable_element_area().
std::unique_ptr<ElementArea> touchable_element_area_;
- // Current status message, may be empty.
- std::string status_message_;
-
- // Current TTS message to be played, may be empty.
- std::string tts_message_;
-
- // Current bubble / tooltip message, may be empty.
- std::string bubble_message_;
-
- // Current details, may be empty.
- std::vector<DetailsHolder> details_;
-
- // Current info box, may be null.
- std::unique_ptr<InfoBox> info_box_;
-
- // Current state of the progress bar.
- bool progress_visible_ = true;
- bool progress_bar_error_state_ = false;
- ShowProgressBarProto::StepProgressBarConfiguration
- step_progress_bar_configuration_;
- int progress_active_step_ = 0;
-
- // Current set of user actions. May be null, but never empty.
- std::unique_ptr<std::vector<UserAction>> user_actions_;
-
// Current set of direct actions.
std::vector<ScriptHandle> direct_action_scripts_;
// Current viewport mode.
ViewportMode viewport_mode_ = ViewportMode::NO_RESIZE;
- // Current peek mode.
- ConfigureBottomSheetProto::PeekMode peek_mode_ =
- ConfigureBottomSheetProto::HANDLE;
- bool auto_change_peek_mode_ = false;
-
- // The latest bottom sheet state stored.
- BottomSheetState bottom_sheet_state_ = BottomSheetState::UNDEFINED;
-
// Whether the tab associated with this controller is currently selected.
bool tab_selected_ = true;
std::unique_ptr<OverlayColors> overlay_colors_;
- // A copy of the most recently set user data options. Can be used to determine
- // which information was requested.
- std::unique_ptr<CollectUserDataOptions> last_collect_user_data_options_;
- raw_ptr<CollectUserDataOptions> collect_user_data_options_ = nullptr;
UserData user_data_;
- std::unique_ptr<FormProto> form_;
- std::unique_ptr<FormProto::Result> form_result_;
- base::RepeatingCallback<void(const FormProto::Result*)>
- form_changed_callback_ = base::DoNothing();
- base::OnceCallback<void(const ClientStatus&)> form_cancel_callback_ =
- base::DoNothing();
-
// Value for ScriptExecutorDelegate::IsNavigatingToNewDocument()
bool navigating_to_new_document_ = false;
@@ -620,26 +417,10 @@ class Controller : public ScriptExecutorDelegate,
// was taken.
absl::optional<Metrics::DropOutReason> delayed_shutdown_reason_;
- EventHandler event_handler_;
UserModel user_model_;
- BasicInteractions basic_interactions_{this, &settings_};
- bool expand_sheet_for_prompt_action_ = true;
std::vector<std::string> browse_domains_allowlist_;
bool browse_mode_invisible_ = false;
- bool is_keyboard_showing_ = false;
- bool is_focus_on_bottom_sheet_text_input_ = false;
- bool show_feedback_chip_on_graceful_shutdown_ = false;
- bool are_chips_visible_ = true;
-
- bool tts_enabled_ = false;
- std::unique_ptr<AutofillAssistantTtsController> tts_controller_;
- TtsButtonState tts_button_state_ = TtsButtonState::DEFAULT;
-
- // Only set during a ShowGenericUiAction.
- std::unique_ptr<GenericUserInterfaceProto> generic_user_interface_;
-
- std::unique_ptr<GenericUserInterfaceProto> persistent_generic_user_interface_;
// Log information about action execution. Gets reset at the start of every
// action and attached to the action result on completion.
diff --git a/chromium/components/autofill_assistant/browser/controller_observer.h b/chromium/components/autofill_assistant/browser/controller_observer.h
index 561475261be..eb49d6fef22 100644
--- a/chromium/components/autofill_assistant/browser/controller_observer.h
+++ b/chromium/components/autofill_assistant/browser/controller_observer.h
@@ -11,6 +11,7 @@
#include "base/observer_list_types.h"
#include "components/autofill_assistant/browser/details.h"
+#include "components/autofill_assistant/browser/execution_delegate.h"
#include "components/autofill_assistant/browser/info_box.h"
#include "components/autofill_assistant/browser/metrics.h"
#include "components/autofill_assistant/browser/script.h"
@@ -36,50 +37,19 @@ class ControllerObserver : public base::CheckedObserver {
virtual void OnKeyboardSuppressionStateChanged(
bool should_suppress_keyboard) = 0;
- // Report that the status message has changed.
- virtual void OnStatusMessageChanged(const std::string& message) = 0;
-
- // Report that the bubble / tooltip message has changed.
- virtual void OnBubbleMessageChanged(const std::string& message) = 0;
-
// If the current chrome activity is a custom tab activity, close it.
// Otherwise, do nothing.
virtual void CloseCustomTab() = 0;
- // Report that the set of user actions has changed.
- virtual void OnUserActionsChanged(
- const std::vector<UserAction>& user_actions) = 0;
-
- // Report that the options configuring a CollectUserDataAction have changed.
- virtual void OnCollectUserDataOptionsChanged(
- const CollectUserDataOptions* options) = 0;
+ // Report an error. This does not imply that the flow has ended and is usually
+ // followed by |OnStop|.
+ virtual void OnError(const std::string& error_message,
+ Metrics::DropOutReason reason) = 0;
// Report that a field in |user_data| has changed.
virtual void OnUserDataChanged(const UserData& user_data,
UserData::FieldChange field_change) = 0;
- // Called when details have changed. Details will be empty if they have been
- // cleared.
- virtual void OnDetailsChanged(const std::vector<Details>& details) = 0;
-
- // Called when info box has changed. |info_box| will be null if it has been
- // cleared.
- virtual void OnInfoBoxChanged(const InfoBox* info_box) = 0;
-
- // Called when the currently active progress step has changed.
- virtual void OnProgressActiveStepChanged(int active_step) = 0;
-
- // Called when the current progress bar visibility has changed. If |visible|
- // is true, then the bar is now shown.
- virtual void OnProgressVisibilityChanged(bool visible) = 0;
-
- virtual void OnStepProgressBarConfigurationChanged(
- const ShowProgressBarProto::StepProgressBarConfiguration&
- configuration) = 0;
-
- // Called when the progress bar error state changes.
- virtual void OnProgressBarErrorStateChanged(bool error) = 0;
-
// Updates the area of the visible viewport that is accessible when the
// overlay state is OverlayState::PARTIAL.
//
@@ -103,45 +73,30 @@ class ControllerObserver : public base::CheckedObserver {
// Called when the viewport mode has changed.
virtual void OnViewportModeChanged(ViewportMode mode) = 0;
- // Called when the peek mode has changed.
- virtual void OnPeekModeChanged(
- ConfigureBottomSheetProto::PeekMode peek_mode) = 0;
-
- // Called when the bottom sheet should be expanded.
- virtual void OnExpandBottomSheet() = 0;
-
- // Called when the bottom sheet should be collapsed.
- virtual void OnCollapseBottomSheet() = 0;
-
// Called when the overlay colors have changed.
virtual void OnOverlayColorsChanged(
- const UiDelegate::OverlayColors& colors) = 0;
-
- // Called when the form has changed.
- virtual void OnFormChanged(const FormProto* form,
- const FormProto::Result* result) = 0;
+ const ExecutionDelegate::OverlayColors& colors) = 0;
// Called when client settings have changed.
virtual void OnClientSettingsChanged(const ClientSettings& settings) = 0;
- // Called when the generic user interface to show has been changed or cleared.
- virtual void OnGenericUserInterfaceChanged(
- const GenericUserInterfaceProto* generic_ui) = 0;
-
- // Called when the persistent generic user interface to show has been changed
- // or cleared.
- virtual void OnPersistentGenericUserInterfaceChanged(
- const GenericUserInterfaceProto* generic_ui) = 0;
-
// Called when the desired overlay behavior has changed.
virtual void OnShouldShowOverlayChanged(bool should_show) = 0;
- // Called when the TTS button visibility has changed. If |visible| is true,
- // then the button is shown.
- virtual void OnTtsButtonVisibilityChanged(bool visible) = 0;
+ // Called before starting to execute a script.
+ virtual void OnExecuteScript(const std::string& start_message) = 0;
+
+ // Called when execution is started.
+ virtual void OnStart(const TriggerContext& trigger_context) = 0;
+
+ // Called when the flow is stopped.
+ virtual void OnStop() = 0;
+
+ // Called when the state needs to be reset.
+ virtual void OnResetState() = 0;
- // Called when Tts Button State has changed.
- virtual void OnTtsButtonStateChanged(TtsButtonState state) = 0;
+ // Called whenever the UI is shown or hidden.
+ virtual void OnUiShownChanged(bool shown) = 0;
};
} // namespace autofill_assistant
#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_CONTROLLER_OBSERVER_H_
diff --git a/chromium/components/autofill_assistant/browser/controller_unittest.cc b/chromium/components/autofill_assistant/browser/controller_unittest.cc
index 40a891a3c2b..c1ab7346caf 100644
--- a/chromium/components/autofill_assistant/browser/controller_unittest.cc
+++ b/chromium/components/autofill_assistant/browser/controller_unittest.cc
@@ -22,6 +22,7 @@
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill_assistant/browser/cud_condition.pb.h"
#include "components/autofill_assistant/browser/device_context.h"
+#include "components/autofill_assistant/browser/fake_script_executor_ui_delegate.h"
#include "components/autofill_assistant/browser/features.h"
#include "components/autofill_assistant/browser/mock_autofill_assistant_tts_controller.h"
#include "components/autofill_assistant/browser/mock_client.h"
@@ -33,6 +34,7 @@
#include "components/autofill_assistant/browser/test_util.h"
#include "components/autofill_assistant/browser/trigger_context.h"
#include "components/autofill_assistant/browser/web/mock_web_controller.h"
+#include "components/password_manager/core/browser/mock_password_change_success_tracker.h"
#include "components/strings/grit/components_strings.h"
#include "components/ukm/content/source_url_recorder.h"
#include "components/ukm/test_ukm_recorder.h"
@@ -71,28 +73,6 @@ using ::testing::StrEq;
using ::testing::UnorderedElementsAre;
using ::testing::WithArgs;
-namespace {
-
-constexpr char kClientLocale[] = "en-US";
-
-// Same as non-mock, but provides default mock callbacks.
-struct MockCollectUserDataOptions : public CollectUserDataOptions {
- MockCollectUserDataOptions() {
- base::MockOnceCallback<void(UserData*, const UserModel*)>
- mock_confirm_callback;
- confirm_callback = mock_confirm_callback.Get();
- base::MockOnceCallback<void(int, UserData*, const UserModel*)>
- mock_actions_callback;
- additional_actions_callback = mock_actions_callback.Get();
- base::MockOnceCallback<void(int, UserData*, const UserModel*)>
- mock_terms_callback;
- terms_link_callback = mock_terms_callback.Get();
- selected_user_data_changed_callback = base::DoNothing();
- }
-};
-
-} // namespace
-
class ControllerTest : public testing::Test {
public:
ControllerTest() {
@@ -107,21 +87,19 @@ class ControllerTest : public testing::Test {
mock_web_controller_ = web_controller.get();
auto service = std::make_unique<NiceMock<MockService>>();
mock_service_ = service.get();
- auto tts_controller =
- std::make_unique<NiceMock<MockAutofillAssistantTtsController>>();
- mock_tts_controller_ = tts_controller.get();
ukm::InitializeSourceUrlRecorderForWebContents(web_contents_.get());
ON_CALL(mock_client_, GetWebContents).WillByDefault(Return(web_contents()));
ON_CALL(mock_client_, HasHadUI()).WillByDefault(Return(true));
- ON_CALL(mock_client_, GetLocale()).WillByDefault(Return(kClientLocale));
+ ON_CALL(mock_client_, GetPasswordChangeSuccessTracker())
+ .WillByDefault(Return(&mock_password_change_success_tracker_));
mock_runtime_manager_ = std::make_unique<MockRuntimeManager>();
controller_ = std::make_unique<Controller>(
web_contents(), &mock_client_, task_environment()->GetMockTickClock(),
- mock_runtime_manager_->GetWeakPtr(), std::move(service),
- std::move(tts_controller), &ukm_recorder_,
+ mock_runtime_manager_->GetWeakPtr(), std::move(service), &ukm_recorder_,
/* annotate_dom_model_service= */ nullptr);
+
controller_->SetWebControllerForTest(std::move(web_controller));
ON_CALL(mock_client_, AttachUI()).WillByDefault(Invoke([this]() {
@@ -131,6 +109,8 @@ class ControllerTest : public testing::Test {
ON_CALL(mock_client_, DestroyUI()).WillByDefault(Invoke([this]() {
controller_->SetUiShown(false);
}));
+ ON_CALL(mock_client_, GetScriptExecutorUiDelegate())
+ .WillByDefault(Return(&fake_script_executor_ui_delegate_));
// Fetching scripts succeeds for all URLs, but return nothing.
ON_CALL(*mock_service_, OnGetScriptsForUrl(_, _, _))
@@ -250,25 +230,10 @@ class ControllerTest : public testing::Test {
UserData* GetUserData() { return &controller_->user_data_; }
- UiDelegate* GetUiDelegate() { return controller_.get(); }
-
void SetNavigatingToNewDocument(bool value) {
controller_->navigating_to_new_document_ = value;
}
- RequiredDataPiece MakeRequiredDataPiece(autofill::ServerFieldType field) {
- RequiredDataPiece required_data_piece;
- required_data_piece.mutable_condition()->set_key(static_cast<int>(field));
- required_data_piece.mutable_condition()->mutable_not_empty();
- return required_data_piece;
- }
-
- void EnableTtsForTest() { controller_->tts_enabled_ = true; }
-
- void SetTtsButtonStateForTest(TtsButtonState state) {
- controller_->tts_button_state_ = state;
- }
-
content::BrowserTaskEnvironment task_environment_{
base::test::TaskEnvironment::TimeSource::MOCK_TIME};
content::RenderViewHostTestEnabler rvh_test_enabler_;
@@ -280,10 +245,12 @@ class ControllerTest : public testing::Test {
std::vector<bool> keyboard_states_;
raw_ptr<MockService> mock_service_;
raw_ptr<MockWebController> mock_web_controller_;
- raw_ptr<MockAutofillAssistantTtsController> mock_tts_controller_;
NiceMock<MockClient> mock_client_;
+ FakeScriptExecutorUiDelegate fake_script_executor_ui_delegate_;
std::unique_ptr<MockRuntimeManager> mock_runtime_manager_;
NiceMock<MockControllerObserver> mock_observer_;
+ password_manager::MockPasswordChangeSuccessTracker
+ mock_password_change_success_tracker_;
ukm::TestAutoSetUkmRecorder ukm_recorder_;
std::unique_ptr<Controller> controller_;
};
@@ -453,35 +420,6 @@ TEST_F(ControllerTest, NoRelevantScriptYet) {
EXPECT_EQ(AutofillAssistantState::STARTING, controller_->GetState());
}
-TEST_F(ControllerTest, ClearUserActionsOnSelection) {
- SupportsScriptResponseProto script_response;
- AddRunnableScript(&script_response, "runnable")
- ->mutable_presentation()
- ->set_autostart(true);
-
- ActionsResponseProto runnable_script;
- auto* prompt_action = runnable_script.add_actions()->mutable_prompt();
- prompt_action->add_choices()->mutable_chip()->set_text("continue");
- prompt_action->add_choices()->mutable_chip()->set_text("other");
-
- SetupActionsForScript("runnable", runnable_script);
- SetNextScriptResponse(script_response);
-
- {
- testing::InSequence seq;
- // User actions are cleared when the script is executed.
- EXPECT_CALL(mock_observer_, OnUserActionsChanged(SizeIs(0)));
- // The prompt aciton has 2 chips.
- EXPECT_CALL(mock_observer_, OnUserActionsChanged(SizeIs(2)));
- // When one chip is selected the user actions are cleared.
- EXPECT_CALL(mock_observer_, OnUserActionsChanged(SizeIs(0)));
- // This test doesn't specify what happens after that.
- EXPECT_CALL(mock_observer_, OnUserActionsChanged(_)).Times(AnyNumber());
- }
- Start();
- EXPECT_TRUE(controller_->PerformUserAction(0));
-}
-
TEST_F(ControllerTest, ClearDirectActionsWhenRunning) {
SupportsScriptResponseProto script_response;
AddRunnableScript(&script_response, "script1");
@@ -511,16 +449,11 @@ TEST_F(ControllerTest, ScriptStartMessage) {
SetNextScriptResponse(script_response);
ActionsResponseProto script_actions;
- script_actions.add_actions()->mutable_tell()->set_message("Script running.");
SetupActionsForScript("script", script_actions);
Start("http://a.example.com/path");
- {
- testing::InSequence seq;
- EXPECT_CALL(mock_observer_, OnStatusMessageChanged("Starting Script..."));
- EXPECT_CALL(mock_observer_, OnStatusMessageChanged("Script running."));
- }
+ EXPECT_CALL(mock_observer_, OnExecuteScript("Starting Script..."));
EXPECT_TRUE(
controller_->PerformDirectAction(0, std::make_unique<TriggerContext>()));
}
@@ -566,10 +499,7 @@ TEST_F(ControllerTest, UpdateClientSettings) {
SetupActionsForScript("script", actions_response);
- EXPECT_CALL(mock_observer_,
- OnStatusMessageChanged(l10n_util::GetStringFUTF8(
- IDS_AUTOFILL_ASSISTANT_LOADING, u"a.example.com")))
- .Times(1);
+ EXPECT_CALL(mock_observer_, OnStart(_));
testing::InSequence seq;
EXPECT_CALL(mock_observer_,
OnClientSettingsChanged(
@@ -577,16 +507,14 @@ TEST_F(ControllerTest, UpdateClientSettings) {
base::Milliseconds(1)),
Field(&ClientSettings::display_strings_locale, "en-US"),
Field(&ClientSettings::display_strings,
- initial_client_settings.display_strings))))
- .Times(1);
+ initial_client_settings.display_strings))));
EXPECT_CALL(mock_observer_,
OnClientSettingsChanged(
AllOf(Field(&ClientSettings::periodic_script_check_interval,
base::Milliseconds(1)),
Field(&ClientSettings::display_strings_locale, "fr-FR"),
Field(&ClientSettings::display_strings,
- changed_client_settings.display_strings))))
- .Times(1);
+ changed_client_settings.display_strings))));
Start("http://a.example.com/path");
EXPECT_THAT(controller_->GetSettings(),
AllOf(Field(&ClientSettings::periodic_script_check_interval,
@@ -596,7 +524,7 @@ TEST_F(ControllerTest, UpdateClientSettings) {
changed_client_settings.display_strings)));
}
-TEST_F(ControllerTest, Stop) {
+TEST_F(ControllerTest, Shutdown) {
SupportsScriptResponseProto script_response;
AddRunnableScript(&script_response, "stop");
SetNextScriptResponse(script_response);
@@ -610,6 +538,8 @@ TEST_F(ControllerTest, Stop) {
Start();
ASSERT_THAT(controller_->GetDirectActionScripts(), SizeIs(1));
+ // Non-gracefuls shutdowns don't call |OnStop|, we just shut down directly.
+ EXPECT_CALL(mock_observer_, OnStop()).Times(0);
testing::InSequence seq;
EXPECT_CALL(mock_client_, Shutdown(Metrics::DropOutReason::SCRIPT_SHUTDOWN));
@@ -617,13 +547,14 @@ TEST_F(ControllerTest, Stop) {
controller_->PerformDirectAction(0, std::make_unique<TriggerContext>()));
}
-TEST_F(ControllerTest, CloseCustomTab) {
+TEST_F(ControllerTest, ShutdownGracefully) {
SupportsScriptResponseProto script_response;
AddRunnableScript(&script_response, "stop");
SetNextScriptResponse(script_response);
ActionsResponseProto actions_response;
- actions_response.add_actions()->mutable_stop()->set_close_cct(true);
+ actions_response.add_actions()->mutable_tell();
+ actions_response.add_actions()->mutable_stop();
std::string actions_response_str;
actions_response.SerializeToString(&actions_response_str);
EXPECT_CALL(*mock_service_, OnGetActions(StrEq("stop"), _, _, _, _, _))
@@ -631,29 +562,21 @@ TEST_F(ControllerTest, CloseCustomTab) {
Start();
ASSERT_THAT(controller_->GetDirectActionScripts(), SizeIs(1));
- EXPECT_CALL(mock_observer_, CloseCustomTab()).Times(1);
+ EXPECT_CALL(mock_observer_, OnStop());
- testing::InSequence seq;
EXPECT_CALL(mock_client_,
- Shutdown(Metrics::DropOutReason::CUSTOM_TAB_CLOSED));
+ RecordDropOut(Metrics::DropOutReason::SCRIPT_SHUTDOWN));
EXPECT_TRUE(
controller_->PerformDirectAction(0, std::make_unique<TriggerContext>()));
}
-TEST_F(ControllerTest, StopWithFeedbackChip) {
+TEST_F(ControllerTest, CloseCustomTab) {
SupportsScriptResponseProto script_response;
- script_response.mutable_client_settings()->set_display_strings_locale(
- "en-US");
- ClientSettingsProto::DisplayString* display_str =
- script_response.mutable_client_settings()->add_display_strings();
- display_str->set_id(ClientSettingsProto::SEND_FEEDBACK);
- display_str->set_value("send_feedback");
AddRunnableScript(&script_response, "stop");
SetNextScriptResponse(script_response);
ActionsResponseProto actions_response;
- actions_response.add_actions()->mutable_tell()->set_message("I give up");
- actions_response.add_actions()->mutable_stop()->set_show_feedback_chip(true);
+ actions_response.add_actions()->mutable_stop()->set_close_cct(true);
std::string actions_response_str;
actions_response.SerializeToString(&actions_response_str);
EXPECT_CALL(*mock_service_, OnGetActions(StrEq("stop"), _, _, _, _, _))
@@ -661,17 +584,13 @@ TEST_F(ControllerTest, StopWithFeedbackChip) {
Start();
ASSERT_THAT(controller_->GetDirectActionScripts(), SizeIs(1));
+ EXPECT_CALL(mock_observer_, CloseCustomTab());
testing::InSequence seq;
EXPECT_CALL(mock_client_,
- RecordDropOut(Metrics::DropOutReason::SCRIPT_SHUTDOWN));
+ Shutdown(Metrics::DropOutReason::CUSTOM_TAB_CLOSED));
EXPECT_TRUE(
controller_->PerformDirectAction(0, std::make_unique<TriggerContext>()));
- EXPECT_THAT(
- controller_->GetUserActions(),
- ElementsAre(Property(&UserAction::chip,
- AllOf(Field(&Chip::type, FEEDBACK_ACTION),
- Field(&Chip::text, "send_feedback")))));
}
TEST_F(ControllerTest, RefreshScriptWhenDomainChanges) {
@@ -717,38 +636,6 @@ TEST_F(ControllerTest, Autostart) {
EXPECT_THAT(keyboard_states_, ElementsAre(true, true, false));
}
-TEST_F(ControllerTest,
- AutostartFallbackWithNoRunnableScriptsShowsFeedbackChip) {
- SupportsScriptResponseProto script_response;
- auto* autostart = AddRunnableScript(&script_response, "runnable");
- autostart->mutable_presentation()->set_autostart(true);
-
- Start("http://a.example.com/path");
- ASSERT_THAT(controller_->GetUserActions(), SizeIs(1));
- EXPECT_EQ(FEEDBACK_ACTION, controller_->GetUserActions().at(0).chip().type);
-}
-
-TEST_F(ControllerTest,
- AutostartErrorDoesNotShowFeedbackChipWithFeatureFlagDisabled) {
- // Disable the feedback chip feature.
- scoped_feature_list_.Reset();
- scoped_feature_list_.InitAndDisableFeature(
- features::kAutofillAssistantFeedbackChip);
-
- SupportsScriptResponseProto script_response;
- auto* autostart =
- AddRunnableScript(&script_response, "runnable", /*direct_action=*/false);
- autostart->mutable_presentation()->set_autostart(true);
- SetRepeatedScriptResponse(script_response);
-
- EXPECT_CALL(mock_observer_, OnUserActionsChanged(SizeIs(0u)))
- .Times(AnyNumber());
- EXPECT_CALL(mock_observer_, OnUserActionsChanged(SizeIs(Gt(0u)))).Times(0);
-
- Start("http://a.example.com/path");
- EXPECT_THAT(controller_->GetUserActions(), SizeIs(0));
-}
-
TEST_F(ControllerTest, InitialUrlLoads) {
GURL initialUrl("http://a.example.com/path");
EXPECT_CALL(*mock_service_, OnGetScriptsForUrl(Eq(initialUrl), _, _))
@@ -757,127 +644,6 @@ TEST_F(ControllerTest, InitialUrlLoads) {
controller_->Start(initialUrl, std::make_unique<TriggerContext>());
}
-TEST_F(ControllerTest, ProgressSetAtStart) {
- EXPECT_CALL(mock_observer_, OnStepProgressBarConfigurationChanged(_));
- EXPECT_CALL(mock_observer_, OnProgressActiveStepChanged(0));
- Start();
- EXPECT_EQ(0, controller_->GetProgressActiveStep());
-}
-
-TEST_F(ControllerTest, SetProgressStep) {
- EXPECT_CALL(mock_observer_, OnStepProgressBarConfigurationChanged(_));
- EXPECT_CALL(mock_observer_, OnProgressActiveStepChanged(0));
- Start();
-
- ShowProgressBarProto::StepProgressBarConfiguration config;
- config.add_annotated_step_icons()->set_identifier("icon1");
- config.add_annotated_step_icons()->set_identifier("icon2");
- EXPECT_CALL(mock_observer_, OnStepProgressBarConfigurationChanged(_));
- EXPECT_CALL(mock_observer_, OnProgressActiveStepChanged(0));
- controller_->SetStepProgressBarConfiguration(config);
- EXPECT_EQ(0, controller_->GetProgressActiveStep());
-
- EXPECT_CALL(mock_observer_, OnProgressActiveStepChanged(1));
- controller_->SetProgressActiveStep(1);
- EXPECT_EQ(1, controller_->GetProgressActiveStep());
-}
-
-TEST_F(ControllerTest, IgnoreProgressStepDecreases) {
- EXPECT_CALL(mock_observer_, OnProgressActiveStepChanged(0));
- Start();
-
- EXPECT_CALL(mock_observer_, OnStepProgressBarConfigurationChanged(_));
- EXPECT_CALL(mock_observer_, OnProgressActiveStepChanged(0));
- ShowProgressBarProto::StepProgressBarConfiguration config;
- config.add_annotated_step_icons()->set_identifier("icon1");
- config.add_annotated_step_icons()->set_identifier("icon2");
- controller_->SetStepProgressBarConfiguration(config);
-
- EXPECT_CALL(mock_observer_, OnProgressActiveStepChanged(Not(1)))
- .Times(AnyNumber());
- controller_->SetProgressActiveStep(2);
- controller_->SetProgressActiveStep(1);
-}
-
-TEST_F(ControllerTest, NewProgressStepConfigurationClampsStep) {
- Start();
-
- ShowProgressBarProto::StepProgressBarConfiguration config;
- config.add_annotated_step_icons()->set_identifier("icon1");
- config.add_annotated_step_icons()->set_identifier("icon2");
- config.add_annotated_step_icons()->set_identifier("icon3");
- controller_->SetStepProgressBarConfiguration(config);
-
- EXPECT_CALL(mock_observer_, OnProgressActiveStepChanged(3));
- controller_->SetProgressActiveStep(3);
- EXPECT_EQ(3, controller_->GetProgressActiveStep());
-
- ShowProgressBarProto::StepProgressBarConfiguration new_config;
- new_config.add_annotated_step_icons()->set_identifier("icon1");
- new_config.add_annotated_step_icons()->set_identifier("icon2");
- EXPECT_CALL(mock_observer_, OnProgressActiveStepChanged(2));
- controller_->SetStepProgressBarConfiguration(new_config);
- EXPECT_EQ(2, controller_->GetProgressActiveStep());
-}
-
-TEST_F(ControllerTest, ProgressStepWrapsNegativesToMax) {
- Start();
-
- ShowProgressBarProto::StepProgressBarConfiguration config;
- config.add_annotated_step_icons()->set_identifier("icon1");
- config.add_annotated_step_icons()->set_identifier("icon2");
- config.add_annotated_step_icons()->set_identifier("icon3");
- controller_->SetStepProgressBarConfiguration(config);
-
- EXPECT_CALL(mock_observer_, OnProgressActiveStepChanged(3));
- controller_->SetProgressActiveStep(-1);
- EXPECT_EQ(3, controller_->GetProgressActiveStep());
-}
-
-TEST_F(ControllerTest, ProgressStepClampsOverflowToMax) {
- Start();
-
- ShowProgressBarProto::StepProgressBarConfiguration config;
- config.add_annotated_step_icons()->set_identifier("icon1");
- config.add_annotated_step_icons()->set_identifier("icon2");
- config.add_annotated_step_icons()->set_identifier("icon3");
- controller_->SetStepProgressBarConfiguration(config);
-
- EXPECT_CALL(mock_observer_, OnProgressActiveStepChanged(3));
- controller_->SetProgressActiveStep(std::numeric_limits<int>::max());
- EXPECT_EQ(3, controller_->GetProgressActiveStep());
-}
-
-TEST_F(ControllerTest, SetProgressStepFromIdentifier) {
- Start();
-
- ShowProgressBarProto::StepProgressBarConfiguration config;
- config.add_annotated_step_icons()->set_identifier("icon1");
- config.add_annotated_step_icons()->set_identifier("icon2");
- controller_->SetStepProgressBarConfiguration(config);
-
- EXPECT_CALL(mock_observer_, OnProgressActiveStepChanged(1));
- EXPECT_TRUE(controller_->SetProgressActiveStepIdentifier("icon2"));
- EXPECT_EQ(1, controller_->GetProgressActiveStep());
-}
-
-TEST_F(ControllerTest, SetProgressStepFromUnknownIdentifier) {
- EXPECT_CALL(mock_observer_, OnProgressActiveStepChanged(0));
- Start();
- EXPECT_EQ(0, controller_->GetProgressActiveStep());
-
- EXPECT_CALL(mock_observer_, OnStepProgressBarConfigurationChanged(_));
- EXPECT_CALL(mock_observer_, OnProgressActiveStepChanged(0));
- ShowProgressBarProto::StepProgressBarConfiguration config;
- config.add_annotated_step_icons()->set_identifier("icon1");
- config.add_annotated_step_icons()->set_identifier("icon2");
- controller_->SetStepProgressBarConfiguration(config);
-
- EXPECT_CALL(mock_observer_, OnProgressActiveStepChanged(_)).Times(0);
- EXPECT_FALSE(controller_->SetProgressActiveStepIdentifier("icon3"));
- EXPECT_EQ(0, controller_->GetProgressActiveStep());
-}
-
TEST_F(ControllerTest, AttachUIWhenStarting) {
EXPECT_CALL(mock_client_, AttachUI());
Start();
@@ -898,8 +664,7 @@ TEST_F(ControllerTest, AttachUIWhenContentsFocused) {
SimulateWebContentsFocused(); // must call AttachUI
EXPECT_CALL(mock_client_, AttachUI());
- controller_->OnFatalError("test", /*show_feedback_chip= */ false,
- Metrics::DropOutReason::TAB_CHANGED);
+ controller_->OnFatalError("test", Metrics::DropOutReason::TAB_CHANGED);
EXPECT_EQ(AutofillAssistantState::STOPPED, controller_->GetState());
SimulateWebContentsFocused(); // must call AttachUI
}
@@ -962,7 +727,7 @@ TEST_F(ControllerTest, ScriptTimeoutError) {
task_environment()->FastForwardBy(base::Seconds(1));
}
EXPECT_EQ(AutofillAssistantState::STOPPED, controller_->GetState());
- EXPECT_EQ("I give up", controller_->GetStatusMessage());
+ EXPECT_EQ("I give up", fake_script_executor_ui_delegate_.GetStatusMessage());
}
TEST_F(ControllerTest, ScriptTimeoutWarning) {
@@ -996,7 +761,8 @@ TEST_F(ControllerTest, ScriptTimeoutWarning) {
task_environment()->FastForwardBy(base::Seconds(1));
}
EXPECT_EQ(AutofillAssistantState::STARTING, controller_->GetState());
- EXPECT_EQ("This is slow", controller_->GetStatusMessage());
+ EXPECT_EQ("This is slow",
+ fake_script_executor_ui_delegate_.GetStatusMessage());
for (int i = 0; i < 10; i++) {
EXPECT_EQ(AutofillAssistantState::STARTING, controller_->GetState());
task_environment()->FastForwardBy(base::Seconds(1));
@@ -1326,11 +1092,12 @@ TEST_F(ControllerTest, TrackScriptWithNoUI) {
TEST_F(ControllerTest, TrackScriptShowUIOnTell) {
SupportsScriptResponseProto script_response;
auto* script = AddRunnableScript(&script_response, "runnable");
- script->mutable_presentation()->set_needs_ui(false);
+ script->mutable_presentation()->set_needs_ui(true);
SetupScripts(script_response);
ActionsResponseProto runnable_script;
runnable_script.add_actions()->mutable_tell()->set_message("error");
+ runnable_script.add_actions()->mutable_stop();
SetupActionsForScript("runnable", runnable_script);
// Start tracking at example.com, with one script matching
@@ -1345,7 +1112,93 @@ TEST_F(ControllerTest, TrackScriptShowUIOnTell) {
controller_->PerformDirectAction(0, std::make_unique<TriggerContext>()));
EXPECT_EQ(AutofillAssistantState::TRACKING, controller_->GetState());
- // As the controller is back in tracking mode; A UI is not needed anymore.
+ // The last tell message should still be shown to the user.
+ EXPECT_TRUE(controller_->NeedsUI());
+
+ // Check the full history of state transitions.
+ EXPECT_THAT(states_, ElementsAre(AutofillAssistantState::TRACKING,
+ AutofillAssistantState::RUNNING,
+ AutofillAssistantState::TRACKING));
+}
+
+TEST_F(ControllerTest, RunDirectActionWhileTrackingWithUi) {
+ SupportsScriptResponseProto script_response;
+ auto* script_needs_ui = AddRunnableScript(&script_response, "needs_ui");
+ script_needs_ui->mutable_presentation()->set_needs_ui(true);
+
+ auto* script_no_ui = AddRunnableScript(&script_response, "no_ui");
+ script_no_ui->mutable_presentation()->set_needs_ui(false);
+ SetupScripts(script_response);
+
+ ActionsResponseProto needs_ui_script;
+ needs_ui_script.add_actions()->mutable_tell()->set_message("error");
+ needs_ui_script.add_actions()->mutable_stop();
+ SetupActionsForScript("needs_ui", needs_ui_script);
+
+ ActionsResponseProto no_ui_script;
+ no_ui_script.add_actions()->mutable_stop();
+ SetupActionsForScript("no_ui", no_ui_script);
+
+ // Start tracking at example.com, with one script matching
+ SetLastCommittedUrl(GURL("http://example.com/"));
+
+ controller_->Track(std::make_unique<TriggerContext>(), base::DoNothing());
+ ASSERT_THAT(controller_->GetDirectActionScripts(), SizeIs(2));
+ EXPECT_EQ(controller_->GetDirectActionScripts()[0].path, "needs_ui");
+
+ EXPECT_FALSE(controller_->NeedsUI());
+ EXPECT_CALL(mock_client_, AttachUI());
+ EXPECT_TRUE(
+ controller_->PerformDirectAction(0, std::make_unique<TriggerContext>()));
+ EXPECT_EQ(AutofillAssistantState::TRACKING, controller_->GetState());
+
+ // The last tell message should still be shown to the user.
+ EXPECT_TRUE(controller_->NeedsUI());
+
+ EXPECT_CALL(mock_client_, DestroyUI());
+ EXPECT_TRUE(
+ controller_->PerformDirectAction(1, std::make_unique<TriggerContext>()));
+
+ // UI should have been cleared
+ EXPECT_FALSE(controller_->NeedsUI());
+
+ // Check the full history of state transitions.
+ EXPECT_THAT(states_, ElementsAre(AutofillAssistantState::TRACKING,
+ AutofillAssistantState::RUNNING,
+ AutofillAssistantState::TRACKING,
+ AutofillAssistantState::RUNNING,
+ AutofillAssistantState::TRACKING));
+}
+
+TEST_F(ControllerTest, TrackScriptClosesUI) {
+ SupportsScriptResponseProto script_response;
+ auto* script = AddRunnableScript(&script_response, "runnable");
+ script->mutable_presentation()->set_needs_ui(false);
+ SetupScripts(script_response);
+
+ ActionsResponseProto runnable_script;
+ runnable_script.add_actions()->mutable_tell()->set_message("hi");
+ runnable_script.add_actions()
+ ->mutable_wait_for_dom()
+ ->mutable_wait_condition();
+ runnable_script.add_actions()->mutable_stop();
+
+ SetupActionsForScript("runnable", runnable_script);
+
+ // Start tracking at example.com, with one script matching
+ SetLastCommittedUrl(GURL("http://example.com/"));
+
+ controller_->Track(std::make_unique<TriggerContext>(), base::DoNothing());
+ ASSERT_THAT(controller_->GetDirectActionScripts(), SizeIs(1));
+
+ EXPECT_FALSE(controller_->NeedsUI());
+ EXPECT_CALL(mock_client_, AttachUI());
+ EXPECT_TRUE(
+ controller_->PerformDirectAction(0, std::make_unique<TriggerContext>()));
+ EXPECT_EQ(AutofillAssistantState::TRACKING, controller_->GetState());
+
+ // The tell action wasn't the last one before close, so UI should close when
+ // the script is finished.
EXPECT_FALSE(controller_->NeedsUI());
// Check the full history of state transitions.
@@ -1377,8 +1230,8 @@ TEST_F(ControllerTest, TrackScriptShowUIOnError) {
controller_->PerformDirectAction(0, std::make_unique<TriggerContext>()));
EXPECT_EQ(AutofillAssistantState::TRACKING, controller_->GetState());
- // As the controller is back in tracking mode; A UI is not needed anymore.
- EXPECT_FALSE(controller_->NeedsUI());
+ // UI must remain visible for the user to see the error message.
+ EXPECT_TRUE(controller_->NeedsUI());
// Check the full history of state transitions.
EXPECT_THAT(states_, ElementsAre(AutofillAssistantState::TRACKING,
@@ -1678,10 +1531,14 @@ TEST_F(ControllerTest, BrowseStateWithDomainAllowlistCleanup) {
EXPECT_EQ(AutofillAssistantState::BROWSE, controller_->GetState());
// Click "continue".
- EXPECT_EQ(controller_->GetUserActions()[0].chip().text, "continue");
- controller_->PerformUserAction(0);
+ EXPECT_EQ(
+ fake_script_executor_ui_delegate_.GetUserActions()->at(0).chip().text,
+ "continue");
+ (*fake_script_executor_ui_delegate_.GetUserActions())[0].RunCallback();
- EXPECT_EQ(controller_->GetUserActions()[0].chip().text, "done");
+ EXPECT_EQ(
+ fake_script_executor_ui_delegate_.GetUserActions()->at(0).chip().text,
+ "done");
// Make sure the allowlist got reset with the second prompt action.
EXPECT_CALL(
@@ -1765,8 +1622,10 @@ TEST_F(ControllerTest, UnexpectedNavigationDuringPromptAction_Tracking) {
->add_choices()
->mutable_chip()
->set_text("continue");
- std::string never_shown = "never shown";
- runnable_script.add_actions()->mutable_tell()->set_message(never_shown);
+ runnable_script.add_actions()
+ ->mutable_configure_bottom_sheet()
+ ->set_viewport_resizing(
+ ConfigureBottomSheetProto::RESIZE_LAYOUT_VIEWPORT);
SetupActionsForScript("runnable", runnable_script);
SetLastCommittedUrl(GURL("http://example.com/"));
@@ -1780,18 +1639,18 @@ TEST_F(ControllerTest, UnexpectedNavigationDuringPromptAction_Tracking) {
// Start the script, which should show a prompt with the continue chip.
controller_->PerformDirectAction(0, std::make_unique<TriggerContext>());
EXPECT_EQ(AutofillAssistantState::PROMPT, controller_->GetState());
- ASSERT_THAT(controller_->GetUserActions(), SizeIs(1));
- EXPECT_EQ(controller_->GetUserActions()[0].chip().text, "continue");
+ ASSERT_THAT(*fake_script_executor_ui_delegate_.GetUserActions(), SizeIs(1));
+ EXPECT_EQ(
+ fake_script_executor_ui_delegate_.GetUserActions()->at(0).chip().text,
+ "continue");
// Browser (not document) initiated navigation while in prompt mode (such as
// go back): The controller stops the scripts, shows an error, then goes back
// to tracking mode.
//
- // The tell never_shown which follows the prompt action should never be
+ // The ConfigureBottomSheet action which follows the prompt should never be
// executed.
- EXPECT_CALL(mock_observer_, OnStatusMessageChanged(never_shown)).Times(0);
- EXPECT_CALL(mock_observer_, OnStatusMessageChanged(testing::Not(never_shown)))
- .Times(testing::AnyNumber());
+ EXPECT_CALL(mock_observer_, OnViewportModeChanged(_)).Times(0);
content::NavigationSimulator::NavigateAndCommitFromBrowser(
web_contents(), GURL("http://example.com/otherpage"));
@@ -1823,23 +1682,25 @@ TEST_F(ControllerTest, UnexpectedNavigationDuringPromptAction) {
->add_choices()
->mutable_chip()
->set_text("continue");
- std::string never_shown = "never shown";
- autostart_script.add_actions()->mutable_tell()->set_message(never_shown);
+ autostart_script.add_actions()
+ ->mutable_configure_bottom_sheet()
+ ->set_viewport_resizing(
+ ConfigureBottomSheetProto::RESIZE_LAYOUT_VIEWPORT);
SetupActionsForScript("autostart", autostart_script);
Start();
EXPECT_EQ(AutofillAssistantState::PROMPT, controller_->GetState());
- ASSERT_THAT(controller_->GetUserActions(), SizeIs(1));
- EXPECT_EQ(controller_->GetUserActions()[0].chip().text, "continue");
+ ASSERT_THAT(*fake_script_executor_ui_delegate_.GetUserActions(), SizeIs(1));
+ EXPECT_EQ(
+ fake_script_executor_ui_delegate_.GetUserActions()->at(0).chip().text,
+ "continue");
// Browser (not document) initiated navigation while in prompt mode (such as
// go back): The controller stops the scripts, shows an error and shuts down.
//
- // The tell never_shown which follows the prompt action should never be
+ // The ConfigureBottomSheet action which follows the prompt should never be
// executed.
- EXPECT_CALL(mock_observer_, OnStatusMessageChanged(never_shown)).Times(0);
- EXPECT_CALL(mock_observer_, OnStatusMessageChanged(testing::Not(never_shown)))
- .Times(testing::AnyNumber());
+ EXPECT_CALL(mock_observer_, OnViewportModeChanged(_)).Times(0);
// Renderer (Document) initiated navigation is allowed.
EXPECT_CALL(mock_client_, Shutdown(_)).Times(0);
@@ -1909,7 +1770,8 @@ TEST_F(ControllerTest, UnexpectedNavigationInRunningState) {
// The controller stops the scripts, shows an error and shuts down.
EXPECT_CALL(mock_client_,
RecordDropOut(Metrics::DropOutReason::NAVIGATION_WHILE_RUNNING));
- EXPECT_CALL(mock_observer_, OnStatusMessageChanged(_));
+ EXPECT_CALL(mock_observer_,
+ OnError(_, Metrics::DropOutReason::NAVIGATION_WHILE_RUNNING));
content::NavigationSimulator::NavigateAndCommitFromBrowser(
web_contents(), GURL("http://c.example.com/page"));
EXPECT_EQ(AutofillAssistantState::STOPPED, controller_->GetState());
@@ -1942,6 +1804,7 @@ TEST_F(ControllerTest, NavigationAfterStopped) {
// Unexpected browser initiated navigation will cause an error.
EXPECT_CALL(mock_client_, RecordDropOut(Metrics::DropOutReason::NAVIGATION));
+ EXPECT_CALL(mock_observer_, OnError(_, Metrics::DropOutReason::NAVIGATION));
content::NavigationSimulator::NavigateAndCommitFromBrowser(
web_contents(), GURL("http://a.example.com/page"));
EXPECT_EQ(AutofillAssistantState::STOPPED, controller_->GetState());
@@ -1959,6 +1822,41 @@ TEST_F(ControllerTest, NavigationAfterStopped) {
AutofillAssistantState::STOPPED));
}
+TEST_F(ControllerTest, NavigationWhileTrackingWithUi) {
+ SupportsScriptResponseProto script_response;
+ auto* script = AddRunnableScript(&script_response, "runnable");
+ script->mutable_presentation()->set_needs_ui(true);
+ SetupScripts(script_response);
+
+ ActionsResponseProto runnable_script;
+ runnable_script.add_actions()->mutable_tell()->set_message("error");
+ runnable_script.add_actions()->mutable_stop();
+ SetupActionsForScript("runnable", runnable_script);
+
+ // Start tracking at example.com, with one script matching
+ SetLastCommittedUrl(GURL("http://example.com/"));
+
+ controller_->Track(std::make_unique<TriggerContext>(), base::DoNothing());
+ ASSERT_THAT(controller_->GetDirectActionScripts(), SizeIs(1));
+
+ EXPECT_TRUE(
+ controller_->PerformDirectAction(0, std::make_unique<TriggerContext>()));
+ EXPECT_EQ(AutofillAssistantState::TRACKING, controller_->GetState());
+ EXPECT_TRUE(controller_->NeedsUI());
+
+ // Browser navigation will destroy the UI.
+ EXPECT_CALL(mock_client_, DestroyUI());
+ content::NavigationSimulator::NavigateAndCommitFromBrowser(
+ web_contents(), GURL("http://a.example.com/page"));
+ EXPECT_EQ(AutofillAssistantState::TRACKING, controller_->GetState());
+ EXPECT_FALSE(controller_->NeedsUI());
+
+ // Full history of state transitions.
+ EXPECT_THAT(states_, ElementsAre(AutofillAssistantState::TRACKING,
+ AutofillAssistantState::RUNNING,
+ AutofillAssistantState::TRACKING));
+}
+
TEST_F(ControllerTest, NavigationToGooglePropertyShutsDownDestroyingUI) {
SupportsScriptResponseProto script_response;
AddRunnableScript(&script_response, "autostart")
@@ -2023,306 +1921,6 @@ TEST_F(ControllerTest,
AutofillAssistantState::BROWSE));
}
-TEST_F(ControllerTest, UserDataFormEmpty) {
- auto options = std::make_unique<MockCollectUserDataOptions>();
-
- // Request nothing, expect continue button to be enabled.
- EXPECT_CALL(mock_observer_, OnUserActionsChanged(UnorderedElementsAre(
- Property(&UserAction::enabled, Eq(true)))))
- .Times(1);
- EXPECT_CALL(mock_observer_, OnCollectUserDataOptionsChanged(Not(nullptr)))
- .Times(1);
- EXPECT_CALL(mock_observer_, OnUserDataChanged(_, UserData::FieldChange::ALL))
- .Times(1);
- controller_->SetCollectUserDataOptions(options.get());
-}
-
-TEST_F(ControllerTest, UserDataFormContactInfo) {
- auto options = std::make_unique<MockCollectUserDataOptions>();
-
- options->required_contact_data_pieces.push_back(
- MakeRequiredDataPiece(autofill::ServerFieldType::NAME_FULL));
- options->required_contact_data_pieces.push_back(
- MakeRequiredDataPiece(autofill::ServerFieldType::EMAIL_ADDRESS));
- options->required_contact_data_pieces.push_back(MakeRequiredDataPiece(
- autofill::ServerFieldType::PHONE_HOME_WHOLE_NUMBER));
- options->contact_details_name = "selected_profile";
-
- testing::InSequence seq;
- EXPECT_CALL(mock_observer_, OnUserActionsChanged(UnorderedElementsAre(
- Property(&UserAction::enabled, Eq(false)))))
- .Times(1);
- controller_->SetCollectUserDataOptions(options.get());
-
- EXPECT_CALL(mock_observer_,
- OnUserDataChanged(_, UserData::FieldChange::CONTACT_PROFILE))
- .Times(1);
- EXPECT_CALL(mock_observer_, OnUserActionsChanged(UnorderedElementsAre(
- Property(&UserAction::enabled, Eq(true)))))
- .Times(1);
-
- autofill::AutofillProfile contact_profile;
- contact_profile.SetRawInfo(autofill::ServerFieldType::EMAIL_ADDRESS,
- u"joedoe@example.com");
- contact_profile.SetRawInfo(autofill::ServerFieldType::NAME_FULL, u"Joe Doe");
- contact_profile.SetRawInfo(autofill::ServerFieldType::PHONE_HOME_WHOLE_NUMBER,
- u"+1 23 456 789 01");
- controller_->SetContactInfo(
- std::make_unique<autofill::AutofillProfile>(contact_profile), UNKNOWN);
- EXPECT_THAT(controller_->GetUserData()
- ->selected_address("selected_profile")
- ->Compare(contact_profile),
- Eq(0));
-}
-
-TEST_F(ControllerTest, UserDataFormCreditCard) {
- auto options = std::make_unique<MockCollectUserDataOptions>();
-
- options->request_payment_method = true;
- options->billing_address_name = "billing_address";
- testing::InSequence seq;
- EXPECT_CALL(mock_observer_, OnUserActionsChanged(UnorderedElementsAre(
- Property(&UserAction::enabled, Eq(false)))))
- .Times(1);
- controller_->SetCollectUserDataOptions(options.get());
-
- // Credit card without billing address is invalid.
- auto credit_card = std::make_unique<autofill::CreditCard>(
- base::GenerateGUID(), "https://www.example.com");
- autofill::test::SetCreditCardInfo(credit_card.get(), "Marion Mitchell",
- "4111 1111 1111 1111", "01", "2020",
- /* billing_address_id = */ "");
- EXPECT_CALL(mock_observer_, OnUserDataChanged(_, UserData::FieldChange::CARD))
- .Times(1);
- EXPECT_CALL(mock_observer_,
- OnUserDataChanged(_, UserData::FieldChange::BILLING_ADDRESS))
- .Times(1);
- EXPECT_CALL(mock_observer_, OnUserActionsChanged(UnorderedElementsAre(
- Property(&UserAction::enabled, Eq(false)))))
- .Times(1);
- controller_->SetCreditCard(
- std::make_unique<autofill::CreditCard>(*credit_card),
- /* billing_profile =*/nullptr, UNKNOWN);
-
- // Credit card with valid billing address is ok.
- auto billing_address = std::make_unique<autofill::AutofillProfile>(
- base::GenerateGUID(), "https://www.example.com");
- autofill::test::SetProfileInfo(billing_address.get(), "Marion", "Mitchell",
- "Morrison", "marion@me.xyz", "Fox",
- "123 Zoo St.", "unit 5", "Hollywood", "CA",
- "91601", "US", "16505678910");
- credit_card->set_billing_address_id(billing_address->guid());
- EXPECT_CALL(mock_observer_, OnUserDataChanged(_, UserData::FieldChange::CARD))
- .Times(1);
- EXPECT_CALL(mock_observer_,
- OnUserDataChanged(_, UserData::FieldChange::BILLING_ADDRESS))
- .Times(1);
- EXPECT_CALL(mock_observer_, OnUserActionsChanged(UnorderedElementsAre(
- Property(&UserAction::enabled, Eq(true)))))
- .Times(1);
- controller_->SetCreditCard(
- std::make_unique<autofill::CreditCard>(*credit_card),
- std::make_unique<autofill::AutofillProfile>(*billing_address), UNKNOWN);
- EXPECT_THAT(GetUserData()->selected_card()->Compare(*credit_card), Eq(0));
- EXPECT_THAT(GetUserData()
- ->selected_address("billing_address")
- ->Compare(*billing_address),
- Eq(0));
-}
-
-TEST_F(ControllerTest, UserDataChangesByOutOfLoopWrite) {
- auto options = std::make_unique<MockCollectUserDataOptions>();
- auto user_data = std::make_unique<UserData>();
-
- options->required_contact_data_pieces.push_back(
- MakeRequiredDataPiece(autofill::ServerFieldType::NAME_FULL));
- options->required_contact_data_pieces.push_back(
- MakeRequiredDataPiece(autofill::ServerFieldType::EMAIL_ADDRESS));
- options->required_contact_data_pieces.push_back(MakeRequiredDataPiece(
- autofill::ServerFieldType::PHONE_HOME_WHOLE_NUMBER));
- options->contact_details_name = "selected_profile";
-
- testing::InSequence sequence;
-
- EXPECT_CALL(mock_observer_, OnUserActionsChanged(UnorderedElementsAre(
- Property(&UserAction::enabled, Eq(false)))))
- .Times(1);
- controller_->SetCollectUserDataOptions(options.get());
-
- EXPECT_CALL(mock_observer_, OnUserActionsChanged(UnorderedElementsAre(
- Property(&UserAction::enabled, Eq(true)))))
- .Times(1);
- autofill::AutofillProfile contact_profile;
- contact_profile.SetRawInfo(autofill::ServerFieldType::EMAIL_ADDRESS,
- u"joedoe@example.com");
- contact_profile.SetRawInfo(autofill::ServerFieldType::NAME_FULL, u"Joe Doe");
- contact_profile.SetRawInfo(autofill::ServerFieldType::PHONE_HOME_WHOLE_NUMBER,
- u"+1 23 456 789 01");
- controller_->SetContactInfo(
- std::make_unique<autofill::AutofillProfile>(contact_profile), UNKNOWN);
- EXPECT_THAT(controller_->GetUserData()
- ->selected_address("selected_profile")
- ->Compare(contact_profile),
- Eq(0));
-
- EXPECT_CALL(mock_observer_, OnUserActionsChanged(UnorderedElementsAre(
- Property(&UserAction::enabled, Eq(false)))))
- .Times(1);
- // Can be called by a PDM update.
- controller_->WriteUserData(base::BindLambdaForTesting(
- [this](UserData* user_data, UserData::FieldChange* field_change) {
- if (user_data->has_selected_address("selected_profile")) {
- controller_->GetUserModel()->SetSelectedAutofillProfile(
- "selected_profile", nullptr, user_data);
- *field_change = UserData::FieldChange::CONTACT_PROFILE;
- }
- }));
-}
-
-TEST_F(ControllerTest, UserDataFormReload) {
- auto options = std::make_unique<MockCollectUserDataOptions>();
- base::MockCallback<base::OnceCallback<void(UserData*)>> reload_callback;
- options->reload_data_callback = reload_callback.Get();
- base::MockCallback<
- base::RepeatingCallback<void(UserDataEventField, UserDataEventType)>>
- change_callback;
- options->selected_user_data_changed_callback = change_callback.Get();
-
- controller_->SetCollectUserDataOptions(options.get());
-
- EXPECT_CALL(change_callback, Run(UserDataEventField::CONTACT_EVENT,
- UserDataEventType::ENTRY_CREATED));
- EXPECT_CALL(reload_callback, Run);
- controller_->ReloadUserData(UserDataEventField::CONTACT_EVENT,
- UserDataEventType::ENTRY_CREATED);
-}
-
-TEST_F(ControllerTest, SetTermsAndConditions) {
- auto options = std::make_unique<MockCollectUserDataOptions>();
-
- options->accept_terms_and_conditions_text.assign("Accept T&C");
- testing::InSequence seq;
- EXPECT_CALL(mock_observer_, OnUserActionsChanged(UnorderedElementsAre(
- Property(&UserAction::enabled, Eq(false)))))
- .Times(1);
- controller_->SetCollectUserDataOptions(options.get());
-
- EXPECT_CALL(mock_observer_, OnUserActionsChanged(UnorderedElementsAre(
- Property(&UserAction::enabled, Eq(true)))))
- .Times(1);
- EXPECT_CALL(mock_observer_,
- OnUserDataChanged(_, UserData::FieldChange::TERMS_AND_CONDITIONS))
- .Times(1);
- controller_->SetTermsAndConditions(TermsAndConditionsState::ACCEPTED);
- EXPECT_THAT(controller_->GetUserData()->terms_and_conditions_,
- Eq(TermsAndConditionsState::ACCEPTED));
-}
-
-TEST_F(ControllerTest, SetLoginOption) {
- auto options = std::make_unique<MockCollectUserDataOptions>();
- options->request_login_choice = true;
- LoginChoice login_choice;
- login_choice.identifier = "guest";
- options->login_choices.push_back(login_choice);
-
- testing::InSequence seq;
- EXPECT_CALL(mock_observer_, OnUserActionsChanged(UnorderedElementsAre(
- Property(&UserAction::enabled, Eq(false)))))
- .Times(1);
- controller_->SetCollectUserDataOptions(options.get());
-
- EXPECT_CALL(mock_observer_, OnUserActionsChanged(UnorderedElementsAre(
- Property(&UserAction::enabled, Eq(true)))))
- .Times(1);
- EXPECT_CALL(mock_observer_,
- OnUserDataChanged(_, UserData::FieldChange::LOGIN_CHOICE))
- .Times(1);
- controller_->SetLoginOption("guest");
- EXPECT_THAT(controller_->GetUserData()->selected_login_choice()->identifier,
- Eq("guest"));
-}
-
-TEST_F(ControllerTest, SetShippingAddress) {
- auto options = std::make_unique<MockCollectUserDataOptions>();
-
- options->request_shipping = true;
- options->shipping_address_name = "shipping_address";
- testing::InSequence seq;
- EXPECT_CALL(mock_observer_, OnUserActionsChanged(UnorderedElementsAre(
- Property(&UserAction::enabled, Eq(false)))))
- .Times(1);
- controller_->SetCollectUserDataOptions(options.get());
-
- auto shipping_address = std::make_unique<autofill::AutofillProfile>(
- base::GenerateGUID(), "https://www.example.com");
- autofill::test::SetProfileInfo(shipping_address.get(), "Marion", "Mitchell",
- "Morrison", "marion@me.xyz", "Fox",
- "123 Zoo St.", "unit 5", "Hollywood", "CA",
- "91601", "US", "16505678910");
-
- EXPECT_CALL(mock_observer_,
- OnUserDataChanged(_, UserData::FieldChange::SHIPPING_ADDRESS))
- .Times(1);
- EXPECT_CALL(mock_observer_, OnUserActionsChanged(UnorderedElementsAre(
- Property(&UserAction::enabled, Eq(true)))))
- .Times(1);
- controller_->SetShippingAddress(
- std::make_unique<autofill::AutofillProfile>(*shipping_address), UNKNOWN);
- EXPECT_THAT(GetUserData()
- ->selected_address("shipping_address")
- ->Compare(*shipping_address),
- Eq(0));
-}
-
-TEST_F(ControllerTest, SetAdditionalValues) {
- auto options = std::make_unique<MockCollectUserDataOptions>();
- ValueProto value1;
- value1.mutable_strings()->add_values("123456789");
-
- base::OnceCallback<void(UserData*, UserData::FieldChange*)> callback =
- base::BindLambdaForTesting(
- [&](UserData* user_data, UserData::FieldChange* change) {
- ValueProto value2;
- value2.mutable_strings()->add_values("");
- ValueProto value3;
- value3.mutable_strings()->add_values("");
- user_data->SetAdditionalValue("key1", value1);
- user_data->SetAdditionalValue("key2", value2);
- user_data->SetAdditionalValue("key3", value3);
- *change = UserData::FieldChange::ADDITIONAL_VALUES;
- });
-
- controller_->WriteUserData(std::move(callback));
-
- testing::InSequence seq;
- EXPECT_CALL(mock_observer_, OnUserActionsChanged(UnorderedElementsAre(
- Property(&UserAction::enabled, Eq(true)))))
- .Times(1);
- controller_->SetCollectUserDataOptions(options.get());
-
- for (int i = 0; i < 2; ++i) {
- EXPECT_CALL(mock_observer_, OnUserActionsChanged(UnorderedElementsAre(
- Property(&UserAction::enabled, Eq(true)))))
- .Times(1);
- EXPECT_CALL(mock_observer_,
- OnUserDataChanged(_, UserData::FieldChange::ADDITIONAL_VALUES))
- .Times(1);
- }
- ValueProto value4;
- value4.mutable_strings()->add_values("value2");
- ValueProto value5;
- value5.mutable_strings()->add_values("value3");
- controller_->SetAdditionalValue("key2", value4);
- controller_->SetAdditionalValue("key3", value5);
- EXPECT_EQ(*controller_->GetUserData()->GetAdditionalValue("key1"), value1);
- EXPECT_EQ(*controller_->GetUserData()->GetAdditionalValue("key2"), value4);
- EXPECT_EQ(*controller_->GetUserData()->GetAdditionalValue("key3"), value5);
-
- ValueProto value6;
- value6.mutable_strings()->add_values("someValue");
- EXPECT_DCHECK_DEATH(controller_->SetAdditionalValue("key4", value6));
-}
-
TEST_F(ControllerTest, SetOverlayColors) {
EXPECT_CALL(
mock_observer_,
@@ -2340,210 +1938,6 @@ TEST_F(ControllerTest, SetOverlayColors) {
TriggerContext::Options()));
}
-TEST_F(ControllerTest, EnableTts) {
- EXPECT_CALL(mock_client_, IsSpokenFeedbackAccessibilityServiceEnabled())
- .WillOnce(Return(false));
- EXPECT_CALL(mock_observer_, OnTtsButtonVisibilityChanged(true));
-
- GURL url("http://a.example.com/path");
- controller_->Start(
- url,
- std::make_unique<TriggerContext>(
- /* parameters = */ std::make_unique<ScriptParameters>(
- base::flat_map<std::string, std::string>{{"ENABLE_TTS", "true"}}),
- TriggerContext::Options()));
-
- EXPECT_TRUE(controller_->GetTtsButtonVisible());
-}
-
-TEST_F(ControllerTest, DoNotEnableTtsWhenAccessibilityEnabled) {
- EXPECT_CALL(mock_client_, IsSpokenFeedbackAccessibilityServiceEnabled())
- .WillOnce(Return(true));
- EXPECT_CALL(mock_observer_, OnTtsButtonVisibilityChanged(true)).Times(0);
-
- GURL url("http://a.example.com/path");
- controller_->Start(
- url,
- std::make_unique<TriggerContext>(
- /* parameters = */ std::make_unique<ScriptParameters>(
- base::flat_map<std::string, std::string>{{"ENABLE_TTS", "true"}}),
- TriggerContext::Options()));
-
- EXPECT_FALSE(controller_->GetTtsButtonVisible());
-}
-
-TEST_F(ControllerTest, TtsMessageIsSetCorrectlyAtStartup) {
- Start();
- EXPECT_EQ(controller_->GetTtsMessage(), controller_->GetStatusMessage());
- EXPECT_FALSE(controller_->GetTtsMessage().empty());
-}
-
-TEST_F(ControllerTest, TtsMessageIsSetCorrectly) {
- // SetStatusMessage should override tts_message
- controller_->SetStatusMessage("message");
- EXPECT_EQ(controller_->GetTtsMessage(), "message");
-
- controller_->SetTtsMessage("tts_message");
- EXPECT_EQ(controller_->GetTtsMessage(), "tts_message");
- EXPECT_EQ(controller_->GetStatusMessage(), "message");
-}
-
-TEST_F(ControllerTest, SetTtsMessageStopsAnyOngoingTts) {
- EnableTtsForTest();
- SetTtsButtonStateForTest(TtsButtonState::PLAYING);
-
- EXPECT_CALL(*mock_tts_controller_, Stop());
- EXPECT_CALL(mock_observer_, OnTtsButtonStateChanged(TtsButtonState::DEFAULT));
- controller_->SetTtsMessage("tts_message");
- EXPECT_EQ(controller_->GetTtsButtonState(), TtsButtonState::DEFAULT);
-}
-
-TEST_F(ControllerTest, SetTtsMessageReEnablesTtsButtonWithNonStickyStateExp) {
- EXPECT_CALL(mock_client_, IsSpokenFeedbackAccessibilityServiceEnabled())
- .WillOnce(Return(false));
- GURL url("http://a.example.com/path");
- controller_->Start(
- url,
- std::make_unique<TriggerContext>(
- /* parameters = */ std::make_unique<ScriptParameters>(
- base::flat_map<std::string, std::string>{{"ENABLE_TTS", "true"}}),
- TriggerContext::Options(
- /* experiment_ids= */ "4624822", /* is_cct= */ false,
- /* onboarding_shown= */ false, /* is_direct_action= */ false,
- /* initial_url= */ "http://a.example.com/path",
- /* is_in_chrome_triggered= */ false)));
- SetTtsButtonStateForTest(TtsButtonState::DISABLED);
-
- EXPECT_CALL(mock_observer_, OnTtsButtonStateChanged(TtsButtonState::DEFAULT));
- controller_->SetTtsMessage("tts_message");
- EXPECT_EQ(controller_->GetTtsButtonState(), TtsButtonState::DEFAULT);
-}
-
-TEST_F(ControllerTest,
- SetTtsMessageKeepsTtsButtonDisabledWithoutNonStickyStateExp) {
- EXPECT_CALL(mock_client_, IsSpokenFeedbackAccessibilityServiceEnabled())
- .WillOnce(Return(false));
- GURL url("http://a.example.com/path");
- controller_->Start(
- url,
- std::make_unique<TriggerContext>(
- /* parameters = */ std::make_unique<ScriptParameters>(
- base::flat_map<std::string, std::string>{{"ENABLE_TTS", "true"}}),
- TriggerContext::Options()));
- SetTtsButtonStateForTest(TtsButtonState::DISABLED);
-
- EXPECT_CALL(mock_observer_, OnTtsButtonStateChanged(_)).Times(0);
- controller_->SetTtsMessage("tts_message");
- EXPECT_EQ(controller_->GetTtsButtonState(), TtsButtonState::DISABLED);
-}
-
-TEST_F(ControllerTest, TappingTtsButtonInDefaultStateStartsPlayingTts) {
- EnableTtsForTest();
- SetTtsButtonStateForTest(TtsButtonState::DEFAULT);
- controller_->SetTtsMessage("tts_message");
-
- EXPECT_CALL(*mock_tts_controller_, Speak("tts_message", kClientLocale));
- controller_->OnTtsButtonClicked();
-}
-
-TEST_F(ControllerTest, TappingTtsButtonWhilePlayingDisablesTtsButton) {
- EnableTtsForTest();
- SetTtsButtonStateForTest(TtsButtonState::PLAYING);
-
- EXPECT_CALL(mock_observer_,
- OnTtsButtonStateChanged(TtsButtonState::DISABLED));
- EXPECT_CALL(*mock_tts_controller_, Stop());
- controller_->OnTtsButtonClicked();
- EXPECT_EQ(controller_->GetTtsButtonState(), TtsButtonState::DISABLED);
-}
-
-TEST_F(ControllerTest, TappingDisabledTtsButtonReEnablesItAndStartsTts) {
- EnableTtsForTest();
- SetTtsButtonStateForTest(TtsButtonState::DISABLED);
- controller_->SetTtsMessage("tts_message");
-
- EXPECT_CALL(mock_observer_, OnTtsButtonStateChanged(TtsButtonState::DEFAULT));
- EXPECT_CALL(*mock_tts_controller_, Speak("tts_message", kClientLocale));
- controller_->OnTtsButtonClicked();
- EXPECT_EQ(controller_->GetTtsButtonState(), TtsButtonState::DEFAULT);
-}
-
-TEST_F(ControllerTest, MaybePlayTtsMessageDoesNotStartTtsIfTtsNotEnabled) {
- // tts_enabled_ is false by default
- controller_->SetTtsMessage("tts_message");
-
- EXPECT_CALL(*mock_tts_controller_, Speak("tts_message", kClientLocale))
- .Times(0);
- controller_->MaybePlayTtsMessage();
-}
-
-TEST_F(ControllerTest, MaybePlayTtsMessageStartsPlayingCorrectTtsMessage) {
- EnableTtsForTest();
- controller_->SetStatusMessage("message");
- controller_->SetTtsMessage("tts_message");
-
- EXPECT_CALL(*mock_tts_controller_, Speak("tts_message", kClientLocale));
- controller_->MaybePlayTtsMessage();
-
- // Change display strings locale.
- ClientSettingsProto client_settings;
- client_settings.set_display_strings_locale("test-locale");
- controller_->SetClientSettings(client_settings);
- EXPECT_CALL(*mock_tts_controller_, Speak("tts_message", "test-locale"));
- controller_->MaybePlayTtsMessage();
-}
-
-TEST_F(ControllerTest, OnTtsEventChangesTtsButtonStateCorrectly) {
- EXPECT_EQ(controller_->GetTtsButtonState(), TtsButtonState::DEFAULT);
-
- EXPECT_CALL(mock_observer_, OnTtsButtonStateChanged(TtsButtonState::PLAYING));
- controller_->OnTtsEvent(AutofillAssistantTtsController::TTS_START);
- EXPECT_EQ(controller_->GetTtsButtonState(), TtsButtonState::PLAYING);
-
- EXPECT_CALL(mock_observer_, OnTtsButtonStateChanged(TtsButtonState::DEFAULT));
- controller_->OnTtsEvent(AutofillAssistantTtsController::TTS_END);
- EXPECT_EQ(controller_->GetTtsButtonState(), TtsButtonState::DEFAULT);
-
- EXPECT_CALL(mock_observer_, OnTtsButtonStateChanged(TtsButtonState::DEFAULT));
- controller_->OnTtsEvent(AutofillAssistantTtsController::TTS_ERROR);
- EXPECT_EQ(controller_->GetTtsButtonState(), TtsButtonState::DEFAULT);
-}
-
-TEST_F(ControllerTest, EnablingAccessibilityStopsTtsAndHidesTtsButton) {
- EnableTtsForTest();
- SetTtsButtonStateForTest(TtsButtonState::PLAYING);
-
- EXPECT_CALL(*mock_tts_controller_, Stop());
- EXPECT_CALL(mock_observer_, OnTtsButtonStateChanged(TtsButtonState::DEFAULT));
- EXPECT_CALL(mock_observer_,
- OnTtsButtonVisibilityChanged(/* visibility= */ false));
- controller_->OnSpokenFeedbackAccessibilityServiceChanged(/* enabled= */ true);
- EXPECT_FALSE(controller_->GetTtsButtonVisible());
- EXPECT_EQ(controller_->GetTtsButtonState(), TtsButtonState::DEFAULT);
-}
-
-TEST_F(ControllerTest, DisablingAccessibilityShouldNotEnableTts) {
- // TTS is disabled by default.
- EXPECT_FALSE(controller_->GetTtsButtonVisible());
-
- EXPECT_CALL(mock_observer_,
- OnTtsButtonVisibilityChanged(/* visibility= */ false))
- .Times(0);
- controller_->OnSpokenFeedbackAccessibilityServiceChanged(
- /* enabled= */ false);
- EXPECT_FALSE(controller_->GetTtsButtonVisible());
-}
-
-TEST_F(ControllerTest, HidingUiStopsAnyOngoingTts) {
- EnableTtsForTest();
- SetTtsButtonStateForTest(TtsButtonState::PLAYING);
-
- EXPECT_CALL(*mock_tts_controller_, Stop());
- EXPECT_CALL(mock_observer_, OnTtsButtonStateChanged(TtsButtonState::DEFAULT));
- controller_->SetUiShown(/* shown= */ false);
- EXPECT_EQ(controller_->GetTtsButtonState(), TtsButtonState::DEFAULT);
-}
-
TEST_F(ControllerTest, AddParametersToUserData) {
auto script_parameters = std::make_unique<ScriptParameters>(
base::flat_map<std::string, std::string>{{"PARAM_A", "a"}});
@@ -2572,262 +1966,10 @@ TEST_F(ControllerTest, AddParametersToUserData) {
->is_client_side_only());
}
-TEST_F(ControllerTest, SetDateTimeRange) {
- testing::InSequence seq;
-
- auto options = std::make_unique<MockCollectUserDataOptions>();
- options->request_date_time_range = true;
- auto* time_slot = options->date_time_range.add_time_slots();
- time_slot->set_label("08:00 AM");
- time_slot->set_comparison_value(0);
- time_slot = options->date_time_range.add_time_slots();
- time_slot->set_label("09:00 AM");
- time_slot->set_comparison_value(1);
-
- controller_->SetCollectUserDataOptions(options.get());
-
- EXPECT_CALL(
- mock_observer_,
- OnUserDataChanged(_, UserData::FieldChange::DATE_TIME_RANGE_START))
- .Times(1);
- DateProto start_date;
- start_date.set_year(2020);
- start_date.set_month(1);
- start_date.set_day(20);
- controller_->SetDateTimeRangeStartDate(start_date);
- EXPECT_EQ(controller_->GetUserData()->date_time_range_start_date_->year(),
- 2020);
- EXPECT_EQ(controller_->GetUserData()->date_time_range_start_date_->month(),
- 1);
- EXPECT_EQ(controller_->GetUserData()->date_time_range_start_date_->day(), 20);
-
- EXPECT_CALL(
- mock_observer_,
- OnUserDataChanged(_, UserData::FieldChange::DATE_TIME_RANGE_START))
- .Times(1);
- controller_->SetDateTimeRangeStartTimeSlot(0);
- EXPECT_EQ(controller_->GetUserData()->date_time_range_start_timeslot_, 0);
-
- EXPECT_CALL(mock_observer_,
- OnUserDataChanged(_, UserData::FieldChange::DATE_TIME_RANGE_END))
- .Times(1);
- DateProto end_date;
- end_date.set_year(2020);
- end_date.set_month(1);
- end_date.set_day(25);
- controller_->SetDateTimeRangeEndDate(end_date);
- EXPECT_EQ(controller_->GetUserData()->date_time_range_end_date_->year(),
- 2020);
- EXPECT_EQ(controller_->GetUserData()->date_time_range_end_date_->month(), 1);
- EXPECT_EQ(controller_->GetUserData()->date_time_range_end_date_->day(), 25);
-
- EXPECT_CALL(mock_observer_,
- OnUserDataChanged(_, UserData::FieldChange::DATE_TIME_RANGE_END))
- .Times(1);
- controller_->SetDateTimeRangeEndTimeSlot(1);
- EXPECT_EQ(controller_->GetUserData()->date_time_range_end_timeslot_, 1);
-}
-
-TEST_F(ControllerTest, SetDateTimeRangeStartDateAfterEndDate) {
- testing::InSequence seq;
-
- auto options = std::make_unique<MockCollectUserDataOptions>();
- options->request_date_time_range = true;
- auto* time_slot = options->date_time_range.add_time_slots();
- time_slot->set_label("08:00 AM");
- time_slot->set_comparison_value(0);
- time_slot = options->date_time_range.add_time_slots();
- time_slot->set_label("09:00 AM");
- time_slot->set_comparison_value(1);
-
- DateProto date;
- date.set_year(2020);
- date.set_month(1);
- date.set_day(20);
- GetUserData()->date_time_range_start_date_ = date;
- GetUserData()->date_time_range_end_date_ = date;
-
- controller_->SetCollectUserDataOptions(options.get());
-
- EXPECT_CALL(
- mock_observer_,
- OnUserDataChanged(_, UserData::FieldChange::DATE_TIME_RANGE_START))
- .Times(1);
- EXPECT_CALL(mock_observer_,
- OnUserDataChanged(_, UserData::FieldChange::DATE_TIME_RANGE_END))
- .Times(1);
-
- date.set_day(21);
- controller_->SetDateTimeRangeStartDate(date);
- EXPECT_EQ(controller_->GetUserData()->date_time_range_start_date_->year(),
- 2020);
- EXPECT_EQ(controller_->GetUserData()->date_time_range_start_date_->month(),
- 1);
- EXPECT_EQ(controller_->GetUserData()->date_time_range_start_date_->day(), 21);
- EXPECT_EQ(controller_->GetUserData()->date_time_range_end_date_,
- absl::nullopt);
-}
-
-TEST_F(ControllerTest, SetDateTimeRangeEndDateBeforeStartDate) {
- testing::InSequence seq;
-
- auto options = std::make_unique<MockCollectUserDataOptions>();
- options->request_date_time_range = true;
- auto* time_slot = options->date_time_range.add_time_slots();
- time_slot->set_label("08:00 AM");
- time_slot->set_comparison_value(0);
- time_slot = options->date_time_range.add_time_slots();
- time_slot->set_label("09:00 AM");
- time_slot->set_comparison_value(1);
-
- DateProto date;
- date.set_year(2020);
- date.set_month(1);
- date.set_day(20);
- GetUserData()->date_time_range_start_date_ = date;
- GetUserData()->date_time_range_end_date_ = date;
-
- controller_->SetCollectUserDataOptions(options.get());
-
- EXPECT_CALL(mock_observer_,
- OnUserDataChanged(_, UserData::FieldChange::DATE_TIME_RANGE_END))
- .Times(1);
- EXPECT_CALL(
- mock_observer_,
- OnUserDataChanged(_, UserData::FieldChange::DATE_TIME_RANGE_START))
- .Times(1);
-
- date.set_day(19);
- controller_->SetDateTimeRangeEndDate(date);
- EXPECT_EQ(controller_->GetUserData()->date_time_range_end_date_->year(),
- 2020);
- EXPECT_EQ(controller_->GetUserData()->date_time_range_end_date_->month(), 1);
- EXPECT_EQ(controller_->GetUserData()->date_time_range_end_date_->day(), 19);
- EXPECT_EQ(controller_->GetUserData()->date_time_range_start_date_,
- absl::nullopt);
-}
-
-TEST_F(ControllerTest, SetDateTimeRangeSameDatesStartTimeAfterEndTime) {
- testing::InSequence seq;
-
- auto options = std::make_unique<MockCollectUserDataOptions>();
- options->request_date_time_range = true;
- auto* time_slot = options->date_time_range.add_time_slots();
- time_slot->set_label("08:00 AM");
- time_slot->set_comparison_value(0);
- time_slot = options->date_time_range.add_time_slots();
- time_slot->set_label("09:00 AM");
- time_slot->set_comparison_value(1);
-
- DateProto date;
- date.set_year(2020);
- date.set_month(1);
- date.set_day(20);
- GetUserData()->date_time_range_start_date_ = date;
- GetUserData()->date_time_range_end_date_ = date;
- GetUserData()->date_time_range_end_timeslot_ = 0;
-
- controller_->SetCollectUserDataOptions(options.get());
-
- EXPECT_CALL(
- mock_observer_,
- OnUserDataChanged(_, UserData::FieldChange::DATE_TIME_RANGE_START))
- .Times(1);
- EXPECT_CALL(mock_observer_,
- OnUserDataChanged(_, UserData::FieldChange::DATE_TIME_RANGE_END))
- .Times(1);
-
- controller_->SetDateTimeRangeStartTimeSlot(1);
- EXPECT_EQ(*controller_->GetUserData()->date_time_range_start_timeslot_, 1);
- EXPECT_EQ(controller_->GetUserData()->date_time_range_end_timeslot_,
- absl::nullopt);
-}
-
-TEST_F(ControllerTest, SetDateTimeRangeSameDatesEndTimeBeforeStartTime) {
- testing::InSequence seq;
-
- auto options = std::make_unique<MockCollectUserDataOptions>();
- options->request_date_time_range = true;
- auto* time_slot = options->date_time_range.add_time_slots();
- time_slot->set_label("08:00 AM");
- time_slot->set_comparison_value(0);
- time_slot = options->date_time_range.add_time_slots();
- time_slot->set_label("09:00 AM");
- time_slot->set_comparison_value(1);
-
- DateProto date;
- date.set_year(2020);
- date.set_month(1);
- date.set_day(20);
- GetUserData()->date_time_range_start_date_ = date;
- GetUserData()->date_time_range_end_date_ = date;
- GetUserData()->date_time_range_start_timeslot_ = 1;
-
- controller_->SetCollectUserDataOptions(options.get());
-
- EXPECT_CALL(mock_observer_,
- OnUserDataChanged(_, UserData::FieldChange::DATE_TIME_RANGE_END))
- .Times(1);
- EXPECT_CALL(
- mock_observer_,
- OnUserDataChanged(_, UserData::FieldChange::DATE_TIME_RANGE_START))
- .Times(1);
-
- controller_->SetDateTimeRangeEndTimeSlot(0);
- EXPECT_EQ(*controller_->GetUserData()->date_time_range_end_timeslot_, 0);
- EXPECT_EQ(controller_->GetUserData()->date_time_range_start_timeslot_,
- absl::nullopt);
-}
-
-TEST_F(ControllerTest, SetDateTimeRangeSameDateValidTime) {
- testing::InSequence seq;
-
- auto options = std::make_unique<MockCollectUserDataOptions>();
- options->request_date_time_range = true;
- auto* time_slot = options->date_time_range.add_time_slots();
- time_slot->set_label("08:00 AM");
- time_slot->set_comparison_value(0);
- time_slot = options->date_time_range.add_time_slots();
- time_slot->set_label("09:00 AM");
- time_slot->set_comparison_value(1);
-
- DateProto date;
- date.set_year(2020);
- date.set_month(1);
- date.set_day(20);
- GetUserData()->date_time_range_start_date_ = date;
- GetUserData()->date_time_range_end_date_ = date;
-
- controller_->SetCollectUserDataOptions(options.get());
+TEST_F(ControllerTest, WriteUserData) {
EXPECT_CALL(
mock_observer_,
- OnUserDataChanged(_, UserData::FieldChange::DATE_TIME_RANGE_START))
- .Times(1);
- EXPECT_CALL(mock_observer_,
- OnUserDataChanged(_, UserData::FieldChange::DATE_TIME_RANGE_END))
- .Times(1);
- controller_->SetDateTimeRangeStartTimeSlot(0);
- controller_->SetDateTimeRangeEndTimeSlot(1);
- EXPECT_EQ(controller_->GetUserData()->date_time_range_start_date_->year(),
- 2020);
- EXPECT_EQ(controller_->GetUserData()->date_time_range_start_date_->month(),
- 1);
- EXPECT_EQ(controller_->GetUserData()->date_time_range_start_date_->day(), 20);
- EXPECT_EQ(controller_->GetUserData()->date_time_range_end_date_->year(),
- 2020);
- EXPECT_EQ(controller_->GetUserData()->date_time_range_end_date_->month(), 1);
- EXPECT_EQ(controller_->GetUserData()->date_time_range_end_date_->day(), 20);
- EXPECT_EQ(controller_->GetUserData()->date_time_range_start_timeslot_, 0);
- EXPECT_EQ(*controller_->GetUserData()->date_time_range_end_timeslot_, 1);
-}
-
-TEST_F(ControllerTest, WriteUserData) {
- auto options = std::make_unique<MockCollectUserDataOptions>();
- controller_->SetCollectUserDataOptions(options.get());
-
- EXPECT_CALL(mock_observer_,
- OnUserDataChanged(_, UserData::FieldChange::TERMS_AND_CONDITIONS))
- .Times(1);
+ OnUserDataChanged(_, UserData::FieldChange::TERMS_AND_CONDITIONS));
base::OnceCallback<void(UserData*, UserData::FieldChange*)> callback =
base::BindOnce([](UserData* data, UserData::FieldChange* change) {
@@ -2840,92 +1982,26 @@ TEST_F(ControllerTest, WriteUserData) {
TermsAndConditionsState::ACCEPTED);
}
-TEST_F(ControllerTest, ExpandOrCollapseBottomSheet) {
- {
- testing::InSequence seq;
- EXPECT_CALL(mock_observer_, OnCollapseBottomSheet()).Times(1);
- EXPECT_CALL(mock_observer_, OnExpandBottomSheet()).Times(1);
- }
- controller_->CollapseBottomSheet();
- controller_->ExpandBottomSheet();
-}
-
-TEST_F(ControllerTest, ShouldPromptActionExpandSheet) {
- // Expect this to be true initially.
- EXPECT_TRUE(controller_->ShouldPromptActionExpandSheet());
-
- controller_->SetExpandSheetForPromptAction(false);
- EXPECT_FALSE(controller_->ShouldPromptActionExpandSheet());
-
- controller_->SetExpandSheetForPromptAction(true);
- EXPECT_TRUE(controller_->ShouldPromptActionExpandSheet());
-}
-
-TEST_F(ControllerTest, SecondPromptActionShouldDefaultToExpandSheet) {
- SupportsScriptResponseProto script_response;
- AddRunnableScript(&script_response, "runnable")
- ->mutable_presentation()
- ->set_autostart(true);
- SetNextScriptResponse(script_response);
-
- ActionsResponseProto runnable_script;
- // Prompt action 1 which disables auto expand.
- auto* prompt_action = runnable_script.add_actions()->mutable_prompt();
- prompt_action->add_choices()->mutable_chip()->set_text("continue");
- prompt_action->set_disable_force_expand_sheet(true);
-
- // Prompt action 2 using the default should fall back to auto expand again.
- runnable_script.add_actions()
- ->mutable_prompt()
- ->add_choices()
- ->mutable_chip()
- ->set_text("next");
-
- SetupActionsForScript("runnable", runnable_script);
- Start();
-
- // The first prompt should not auto expand.
- EXPECT_EQ(AutofillAssistantState::PROMPT, controller_->GetState());
- EXPECT_FALSE(controller_->ShouldPromptActionExpandSheet());
- ASSERT_THAT(controller_->GetUserActions(), SizeIs(1));
- EXPECT_EQ(controller_->GetUserActions()[0].chip().text, "continue");
-
- // Click "continue"
- EXPECT_TRUE(controller_->PerformUserAction(0));
-
- // The second prompt should fall back to default auto expand again.
- EXPECT_EQ(AutofillAssistantState::PROMPT, controller_->GetState());
- EXPECT_TRUE(controller_->ShouldPromptActionExpandSheet());
- ASSERT_THAT(controller_->GetUserActions(), SizeIs(1));
- EXPECT_EQ(controller_->GetUserActions()[0].chip().text, "next");
-}
-
-TEST_F(ControllerTest, SetGenericUi) {
- {
- testing::InSequence seq;
- EXPECT_CALL(mock_observer_, OnGenericUserInterfaceChanged(NotNull()));
- EXPECT_CALL(mock_observer_, OnGenericUserInterfaceChanged(nullptr));
- }
- controller_->SetGenericUi(
- std::make_unique<GenericUserInterfaceProto>(GenericUserInterfaceProto()),
- base::DoNothing(), base::DoNothing());
- controller_->ClearGenericUi();
-}
-
TEST_F(ControllerTest, StartPasswordChangeFlow) {
- GURL initialUrl("http://example.com/password");
+ const GURL initialUrl("http://example.com/password");
+ const std::string username = "test_username";
EXPECT_CALL(*mock_service_, OnGetScriptsForUrl(Eq(initialUrl), _, _))
.WillOnce(RunOnceCallback<2>(net::HTTP_OK, ""));
+ EXPECT_CALL(mock_password_change_success_tracker_,
+ OnChangePasswordFlowStarted(
+ initialUrl.DeprecatedGetOriginAsURL(), username,
+ password_manager::PasswordChangeSuccessTracker::StartEvent::
+ kAutomatedFlow));
EXPECT_TRUE(controller_->Start(
initialUrl, std::make_unique<TriggerContext>(
/* parameters = */ std::make_unique<ScriptParameters>(
base::flat_map<std::string, std::string>{
- {"PASSWORD_CHANGE_USERNAME", "test_username"}}),
+ {"PASSWORD_CHANGE_USERNAME", username}}),
TriggerContext::Options())));
// Initial navigation.
SimulateNavigateToUrl(GURL("http://b.example.com"));
- EXPECT_EQ(GetUserData()->selected_login_->username, "test_username");
+ EXPECT_EQ(GetUserData()->selected_login_->username, username);
EXPECT_EQ(GetUserData()->selected_login_->origin,
initialUrl.DeprecatedGetOriginAsURL());
EXPECT_EQ(controller_->GetCurrentURL().host(), "b.example.com");
@@ -2960,7 +2036,7 @@ TEST_F(ControllerTest, EndPromptWithOnEndNavigation) {
Start("http://a.example.com/path");
EXPECT_EQ(AutofillAssistantState::PROMPT, controller_->GetState());
- EXPECT_THAT(controller_->GetUserActions(),
+ EXPECT_THAT(*fake_script_executor_ui_delegate_.GetUserActions(),
ElementsAre(Property(&UserAction::chip,
Field(&Chip::text, StrEq("ok")))));
@@ -2976,11 +2052,11 @@ TEST_F(ControllerTest, EndPromptWithOnEndNavigation) {
simulator->Commit();
EXPECT_EQ(AutofillAssistantState::PROMPT, controller_->GetState());
- EXPECT_THAT(controller_->GetUserActions(),
+ EXPECT_THAT(*fake_script_executor_ui_delegate_.GetUserActions(),
ElementsAre(Property(&UserAction::chip,
Field(&Chip::text, StrEq("ok 2")))));
- EXPECT_TRUE(controller_->PerformUserAction(0));
+ (*fake_script_executor_ui_delegate_.GetUserActions())[0].RunCallback();
EXPECT_THAT(processed_actions_capture, SizeIs(2));
EXPECT_EQ(ACTION_APPLIED, processed_actions_capture[0].status());
@@ -3037,29 +2113,30 @@ TEST_F(ControllerTest, PauseAndResume) {
AutofillAssistantState::RUNNING,
AutofillAssistantState::PROMPT));
EXPECT_THAT(keyboard_states_, ElementsAre(true, true, false));
- EXPECT_THAT(controller_->GetStatusMessage(), StrEq("Hello World"));
- EXPECT_THAT(controller_->GetUserActions(),
+ EXPECT_THAT(fake_script_executor_ui_delegate_.GetStatusMessage(),
+ StrEq("Hello World"));
+ EXPECT_THAT(*fake_script_executor_ui_delegate_.GetUserActions(),
ElementsAre(Property(&UserAction::chip,
- AllOf(Field(&Chip::text, StrEq("ok")),
- Field(&Chip::type, NORMAL_ACTION)))));
+ Field(&Chip::text, StrEq("ok")))));
ScriptExecutorListener listener;
controller_->AddListener(&listener);
- EXPECT_CALL(mock_observer_, OnStatusMessageChanged("Stop"));
controller_->OnStop("Stop", "Undo");
EXPECT_EQ(1, listener.pause_count);
controller_->RemoveListener(&listener);
EXPECT_EQ(AutofillAssistantState::STOPPED, controller_->GetState());
- EXPECT_THAT(controller_->GetStatusMessage(), StrEq("Stop"));
+ EXPECT_THAT(fake_script_executor_ui_delegate_.GetStatusMessage(),
+ StrEq("Stop"));
EXPECT_THAT(
- controller_->GetUserActions(),
+ *fake_script_executor_ui_delegate_.GetUserActions(),
ElementsAre(Property(&UserAction::chip,
AllOf(Field(&Chip::text, StrEq("Undo")),
Field(&Chip::type, HIGHLIGHTED_ACTION)))));
- EXPECT_CALL(mock_observer_, OnStatusMessageChanged("Hello World"));
- EXPECT_TRUE(controller_->PerformUserAction(0));
+ ASSERT_NE(nullptr, fake_script_executor_ui_delegate_.GetUserActions());
+ ASSERT_THAT(*fake_script_executor_ui_delegate_.GetUserActions(), SizeIs(1));
+ (*fake_script_executor_ui_delegate_.GetUserActions())[0].RunCallback();
EXPECT_THAT(states_, ElementsAre(AutofillAssistantState::STARTING,
AutofillAssistantState::RUNNING,
@@ -3069,11 +2146,11 @@ TEST_F(ControllerTest, PauseAndResume) {
AutofillAssistantState::PROMPT));
EXPECT_THAT(keyboard_states_,
ElementsAre(true, true, false, false, true, false));
- EXPECT_THAT(controller_->GetStatusMessage(), StrEq("Hello World"));
- EXPECT_THAT(controller_->GetUserActions(),
+ EXPECT_THAT(fake_script_executor_ui_delegate_.GetStatusMessage(),
+ StrEq("Hello World"));
+ EXPECT_THAT(*fake_script_executor_ui_delegate_.GetUserActions(),
ElementsAre(Property(&UserAction::chip,
- AllOf(Field(&Chip::text, StrEq("ok")),
- Field(&Chip::type, NORMAL_ACTION)))));
+ Field(&Chip::text, StrEq("ok")))));
}
TEST_F(ControllerTest, PauseAndNavigate) {
@@ -3103,11 +2180,11 @@ TEST_F(ControllerTest, PauseAndNavigate) {
web_contents(), GURL("http://b.example.com/path"));
}
-TEST_F(ControllerTest, RegularScriptShowsDefaultInitialStatusMessage) {
+TEST_F(ControllerTest, RegularScriptNotifiesStart) {
SupportsScriptResponseProto script_response;
- AddRunnableScript(&script_response, "script")
- ->mutable_presentation()
- ->set_autostart(true);
+ auto* script = AddRunnableScript(&script_response, "script");
+ script->mutable_presentation()->set_autostart(true);
+ script->mutable_presentation()->set_start_message("start message");
SetupScripts(script_response);
ActionsResponseProto actions_response;
@@ -3116,61 +2193,17 @@ TEST_F(ControllerTest, RegularScriptShowsDefaultInitialStatusMessage) {
SetupActionsForScript("script", actions_response);
testing::InSequence seq;
- EXPECT_CALL(mock_observer_,
- OnStatusMessageChanged(l10n_util::GetStringFUTF8(
- IDS_AUTOFILL_ASSISTANT_LOADING, u"a.example.com")))
- .Times(1);
- EXPECT_CALL(mock_observer_, OnStatusMessageChanged("Hello World")).Times(1);
- Start("http://a.example.com/path");
-}
+ EXPECT_CALL(mock_observer_, OnStart(_));
+ EXPECT_CALL(mock_observer_, OnExecuteScript("start message"));
-TEST_F(ControllerTest, NotifyObserversOfInitialStatusMessageAndProgressBar) {
- SupportsScriptResponseProto script_response;
- AddRunnableScript(&script_response, "script")
- ->mutable_presentation()
- ->set_autostart(true);
- SetupScripts(script_response);
-
- ActionsResponseProto actions_response;
- actions_response.add_actions()->mutable_tell()->set_message("script message");
- SetupActionsForScript("script", actions_response);
-
- ShowProgressBarProto::StepProgressBarConfiguration progress_bar_configuration;
- progress_bar_configuration.add_annotated_step_icons()
- ->mutable_icon()
- ->set_icon(DrawableProto::PROGRESSBAR_DEFAULT_INITIAL_STEP);
- progress_bar_configuration.add_annotated_step_icons()
- ->mutable_icon()
- ->set_icon(DrawableProto::PROGRESSBAR_DEFAULT_DATA_COLLECTION);
- progress_bar_configuration.add_annotated_step_icons()
- ->mutable_icon()
- ->set_icon(DrawableProto::PROGRESSBAR_DEFAULT_PAYMENT);
- progress_bar_configuration.add_annotated_step_icons()
- ->mutable_icon()
- ->set_icon(DrawableProto::PROGRESSBAR_DEFAULT_FINAL_STEP);
-
- // When setting UI state of the controller before calling |Start|, observers
- // will be notified immediately after |Start|.
- controller_->SetStatusMessage("startup message");
- controller_->SetStepProgressBarConfiguration(progress_bar_configuration);
- controller_->SetProgressActiveStep(1);
-
- EXPECT_CALL(mock_observer_, OnStepProgressBarConfigurationChanged(
- progress_bar_configuration));
- EXPECT_CALL(mock_observer_, OnProgressActiveStepChanged(1));
- testing::Sequence s1;
- EXPECT_CALL(mock_observer_, OnStatusMessageChanged("startup message"))
- .InSequence(s1);
- EXPECT_CALL(mock_observer_, OnStatusMessageChanged("script message"))
- .InSequence(s1);
Start("http://a.example.com/path");
}
TEST_F(ControllerTest, NotifyRuntimeManagerOnUiStateChange) {
- EXPECT_CALL(*mock_runtime_manager_, SetUIState(UIState::kShown)).Times(1);
+ EXPECT_CALL(*mock_runtime_manager_, SetUIState(UIState::kShown));
controller_->SetUiShown(true);
- EXPECT_CALL(*mock_runtime_manager_, SetUIState(UIState::kNotShown)).Times(1);
+ EXPECT_CALL(*mock_runtime_manager_, SetUIState(UIState::kNotShown));
controller_->SetUiShown(false);
}
@@ -3181,130 +2214,21 @@ TEST_F(ControllerTest, RuntimeManagerDestroyed) {
}
TEST_F(ControllerTest, OnGetScriptsFailedWillShutdown) {
- EXPECT_CALL(mock_observer_,
- OnStatusMessageChanged(l10n_util::GetStringFUTF8(
- IDS_AUTOFILL_ASSISTANT_LOADING, u"initialurl.com")))
- .Times(1);
+ EXPECT_CALL(mock_observer_, OnStart(_));
EXPECT_CALL(*mock_service_, OnGetScriptsForUrl(_, _, _))
.WillOnce(RunOnceCallback<2>(net::HTTP_NOT_FOUND, ""));
- EXPECT_CALL(mock_observer_, OnStatusMessageChanged(l10n_util::GetStringUTF8(
- IDS_AUTOFILL_ASSISTANT_DEFAULT_ERROR)))
- .Times(1);
+ EXPECT_CALL(
+ mock_observer_,
+ OnError(l10n_util::GetStringUTF8(IDS_AUTOFILL_ASSISTANT_DEFAULT_ERROR),
+ Metrics::DropOutReason::GET_SCRIPTS_FAILED));
EXPECT_CALL(mock_client_, HasHadUI()).WillOnce(Return(false));
EXPECT_CALL(mock_client_,
- Shutdown(Metrics::DropOutReason::GET_SCRIPTS_FAILED))
- .Times(1);
+ Shutdown(Metrics::DropOutReason::GET_SCRIPTS_FAILED));
Start();
EXPECT_EQ(AutofillAssistantState::STOPPED, controller_->GetState());
}
-TEST_F(ControllerTest, Details) {
- // The current controller details, as notified to the observers.
- std::vector<Details> observed_details;
-
- ON_CALL(mock_observer_, OnDetailsChanged(_))
- .WillByDefault(
- Invoke([&observed_details](const std::vector<Details>& details) {
- observed_details = details;
- }));
-
- // Details are initially empty.
- EXPECT_THAT(controller_->GetDetails(), IsEmpty());
-
- // Set 2 details.
- controller_->SetDetails(std::make_unique<Details>(), base::TimeDelta());
- EXPECT_THAT(controller_->GetDetails(), SizeIs(1));
- EXPECT_THAT(observed_details, SizeIs(1));
-
- // Set 2 details in 1s (which directly clears the current details).
- controller_->SetDetails(std::make_unique<Details>(),
- base::Milliseconds(1000));
- EXPECT_THAT(controller_->GetDetails(), IsEmpty());
- EXPECT_THAT(observed_details, IsEmpty());
-
- task_environment()->FastForwardBy(base::Milliseconds(1000));
- EXPECT_THAT(controller_->GetDetails(), SizeIs(1));
- EXPECT_THAT(observed_details, SizeIs(1));
-
- controller_->AppendDetails(std::make_unique<Details>(),
- /* delay= */ base::TimeDelta());
- EXPECT_THAT(controller_->GetDetails(), SizeIs(2));
- EXPECT_THAT(observed_details, SizeIs(2));
-
- // Delay the appending of the details.
- controller_->AppendDetails(std::make_unique<Details>(),
- /* delay= */ base::Milliseconds(1000));
- EXPECT_THAT(controller_->GetDetails(), SizeIs(2));
- EXPECT_THAT(observed_details, SizeIs(2));
-
- task_environment()->FastForwardBy(base::Milliseconds(999));
- EXPECT_THAT(controller_->GetDetails(), SizeIs(2));
- EXPECT_THAT(observed_details, SizeIs(2));
-
- task_environment()->FastForwardBy(base::Milliseconds(1));
- EXPECT_THAT(controller_->GetDetails(), SizeIs(3));
- EXPECT_THAT(observed_details, SizeIs(3));
-
- // Setting the details clears the timers.
- controller_->AppendDetails(std::make_unique<Details>(),
- /* delay= */ base::Milliseconds(1000));
- controller_->SetDetails(nullptr, base::TimeDelta());
- EXPECT_THAT(controller_->GetDetails(), IsEmpty());
- EXPECT_THAT(observed_details, IsEmpty());
-
- task_environment()->FastForwardBy(base::Milliseconds(2000));
- EXPECT_THAT(controller_->GetDetails(), IsEmpty());
- EXPECT_THAT(observed_details, IsEmpty());
-}
-
-TEST_F(ControllerTest, OnScriptErrorWillAppendVanishingFeedbackChip) {
- // A script error should show the feedback chip.
- EXPECT_CALL(mock_observer_, OnUserActionsChanged(SizeIs(1)));
- EXPECT_CALL(mock_client_, RecordDropOut(Metrics::DropOutReason::NAVIGATION));
- controller_->OnScriptError("Error", Metrics::DropOutReason::NAVIGATION);
- EXPECT_EQ(AutofillAssistantState::STOPPED, controller_->GetState());
-
- // The chip should vanish once clicked.
- EXPECT_CALL(mock_observer_, OnUserActionsChanged(SizeIs(0)));
- EXPECT_CALL(mock_client_,
- Shutdown(Metrics::DropOutReason::UI_CLOSED_UNEXPECTEDLY));
- EXPECT_TRUE(controller_->PerformUserAction(0));
-}
-
-// The chip should be hidden if and only if the keyboard is visible and the
-// focus is on a bottom sheet input text.
-TEST_F(ControllerTest, UpdateChipVisibility) {
- InSequence seq;
-
- UserAction user_action(ChipProto(), true, std::string());
- EXPECT_CALL(mock_observer_,
- OnUserActionsChanged(UnorderedElementsAre(Property(
- &UserAction::chip, Field(&Chip::visible, Eq(true))))))
- .Times(1);
- auto user_actions = std::make_unique<std::vector<UserAction>>();
- user_actions->emplace_back(std::move(user_action));
- controller_->SetUserActions(std::move(user_actions));
-
- EXPECT_CALL(mock_observer_, OnUserActionsChanged(_)).Times(0);
- controller_->OnKeyboardVisibilityChanged(true);
-
- EXPECT_CALL(mock_observer_,
- OnUserActionsChanged(UnorderedElementsAre(Property(
- &UserAction::chip, Field(&Chip::visible, Eq(false))))))
- .Times(1);
- controller_->OnInputTextFocusChanged(true);
-
- EXPECT_CALL(mock_observer_,
- OnUserActionsChanged(UnorderedElementsAre(Property(
- &UserAction::chip, Field(&Chip::visible, Eq(true))))))
- .Times(1);
- controller_->OnKeyboardVisibilityChanged(false);
-
- EXPECT_CALL(mock_observer_, OnUserActionsChanged(_)).Times(0);
- controller_->OnInputTextFocusChanged(false);
-}
-
class ControllerPrerenderTest : public ControllerTest {
public:
ControllerPrerenderTest() {
diff --git a/chromium/components/autofill_assistant/browser/devtools/devtools_client.cc b/chromium/components/autofill_assistant/browser/devtools/devtools_client.cc
index 4dea4f3f509..7d201e509b8 100644
--- a/chromium/components/autofill_assistant/browser/devtools/devtools_client.cc
+++ b/chromium/components/autofill_assistant/browser/devtools/devtools_client.cc
@@ -12,6 +12,7 @@
#include "base/bind.h"
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
+#include "base/logging.h"
#include "base/strings/strcat.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
@@ -153,7 +154,7 @@ void DevtoolsClient::DispatchProtocolMessage(
bool success = message->GetAsDictionary(&message_dict);
DCHECK(success);
- success = message_dict->HasKey("id")
+ success = message_dict->FindKey("id")
? DispatchMessageReply(std::move(message), *message_dict)
: DispatchEvent(std::move(message), *message_dict);
if (!success)
@@ -277,16 +278,11 @@ void DevtoolsClient::DispatchEventTask(
void DevtoolsClient::FillReplyStatusFromErrorDict(
ReplyStatus* status,
const base::DictionaryValue& error_dict) {
- const base::Value* code;
- if (error_dict.Get("code", &code) && code->is_int()) {
- status->error_code = code->GetInt();
- } else {
- status->error_code = -1; // unknown error code
- }
+ status->error_code = error_dict.FindIntKey("code").value_or(-1);
- const base::Value* message;
- if (error_dict.Get("message", &message) && message->is_string()) {
- status->error_message = message->GetString();
+ const std::string* message = error_dict.FindStringKey("message");
+ if (message) {
+ status->error_message = *message;
} else {
status->error_message = "unknown";
}
diff --git a/chromium/components/autofill_assistant/browser/devtools/value_conversions.h b/chromium/components/autofill_assistant/browser/devtools/value_conversions.h
index 078d7998b41..288c53a85aa 100644
--- a/chromium/components/autofill_assistant/browser/devtools/value_conversions.h
+++ b/chromium/components/autofill_assistant/browser/devtools/value_conversions.h
@@ -56,7 +56,7 @@ std::unique_ptr<base::Value> ToValueImpl(const std::string& value, T*) {
template <typename T>
std::unique_ptr<base::Value> ToValueImpl(const base::Value& value, T*) {
- return value.CreateDeepCopy();
+ return std::make_unique<base::Value>(value.Clone());
}
template <typename T>
@@ -157,7 +157,7 @@ struct FromValue<std::vector<T>> {
return result;
}
errors->Push();
- for (const auto& item : value.GetList())
+ for (const auto& item : value.GetListDeprecated())
result.push_back(FromValue<T>::Parse(item, errors));
errors->Pop();
return result;
diff --git a/chromium/components/autofill_assistant/browser/dom_action.proto b/chromium/components/autofill_assistant/browser/dom_action.proto
index 35aa1a8cbc7..c65ac88a0db 100644
--- a/chromium/components/autofill_assistant/browser/dom_action.proto
+++ b/chromium/components/autofill_assistant/browser/dom_action.proto
@@ -198,3 +198,25 @@ message CheckOptionElementProto {
message Result { optional bool match = 1; }
}
+
+// Execute a snippet of JavaScript. The |js_snippet| should come as the body of
+// a "function() { .. }", where "this" refers to the element stored in
+// |client_id|. The |js_snippet| may either return nothing or an integer,
+// mapped to a client status. Any other return value will result in an
+// |INVALID_ACTION| error. The |js_snippet| may also return a Promise that
+// eventually resolves with the same limitations as the return value. When
+// returning a Promise, consider adding a |timeout_ms|. If the Promise is
+// rejected, the action will return an |UNEXPECTED_JS_ERROR|, consider
+// resolving with it a failing status code instead. In case of an error in the
+// snippet, an |UNEXPECTED_JS_ERROR| will be returned together with the line
+// and column number of the error. Note that the column number will be offset
+// by the "function() { " prefix.
+message ExecuteJsProto {
+ // The element on which to execute the JS snippet. Target of "this" in the
+ // snippet.
+ optional ClientIdProto client_id = 1;
+ optional string js_snippet = 2;
+ // Should be used when the |js_snippet| returns a Promise. If the Promise is
+ // not resolved in time, the action will report a |TIMED_OUT| error.
+ optional int32 timeout_ms = 3;
+}
diff --git a/chromium/components/autofill_assistant/browser/element_area.cc b/chromium/components/autofill_assistant/browser/element_area.cc
index d531a798971..a76c16d09c4 100644
--- a/chromium/components/autofill_assistant/browser/element_area.cc
+++ b/chromium/components/autofill_assistant/browser/element_area.cc
@@ -37,7 +37,7 @@ std::string ToDebugString(const std::vector<RectF>& rectangles) {
} // namespace
-ElementArea::ElementArea(ClientSettings* settings,
+ElementArea::ElementArea(const ClientSettings* settings,
WebController* web_controller)
: settings_(settings), web_controller_(web_controller) {
DCHECK(settings_ && web_controller_);
diff --git a/chromium/components/autofill_assistant/browser/element_area.h b/chromium/components/autofill_assistant/browser/element_area.h
index 392b8626abf..e925c446581 100644
--- a/chromium/components/autofill_assistant/browser/element_area.h
+++ b/chromium/components/autofill_assistant/browser/element_area.h
@@ -24,7 +24,8 @@ class ElementArea {
public:
// |settings| and |web_controller| must remain valid for the lifetime of this
// instance.
- explicit ElementArea(ClientSettings* settings, WebController* web_controller);
+ explicit ElementArea(const ClientSettings* settings,
+ WebController* web_controller);
ElementArea(const ElementArea&) = delete;
ElementArea& operator=(const ElementArea&) = delete;
@@ -130,7 +131,7 @@ class ElementArea {
void OnGetVisualViewport(const ClientStatus& status, const RectF& rect);
void ReportUpdate();
- const raw_ptr<ClientSettings> settings_;
+ const raw_ptr<const ClientSettings> settings_;
const raw_ptr<WebController> web_controller_;
std::vector<Rectangle> rectangles_;
diff --git a/chromium/components/autofill_assistant/browser/element_precondition.cc b/chromium/components/autofill_assistant/browser/element_precondition.cc
deleted file mode 100644
index 217025433f1..00000000000
--- a/chromium/components/autofill_assistant/browser/element_precondition.cc
+++ /dev/null
@@ -1,176 +0,0 @@
-// Copyright 2019 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.
-
-#include "components/autofill_assistant/browser/element_precondition.h"
-
-#include <utility>
-
-#include "base/bind.h"
-#include "components/autofill_assistant/browser/batch_element_checker.h"
-#include "components/autofill_assistant/browser/web/element.h"
-
-namespace autofill_assistant {
-
-ElementPrecondition::ElementPrecondition(const ElementConditionProto& proto)
- : proto_(proto) {
- AddResults(proto_);
-}
-
-ElementPrecondition::~ElementPrecondition() = default;
-
-ElementPrecondition::Result::Result() = default;
-
-ElementPrecondition::Result::~Result() = default;
-
-ElementPrecondition::Result::Result(const Result&) = default;
-
-void ElementPrecondition::Check(BatchElementChecker* batch_checks,
- Callback callback) {
- if (results_.empty()) {
- OnAllElementChecksDone(std::move(callback));
- return;
- }
-
- for (size_t i = 0; i < results_.size(); i++) {
- Result& result = results_[i];
- result.match = false;
- if (result.selector.empty()) {
- // Empty selectors never match.
- continue;
- }
- batch_checks->AddElementCheck(
- result.selector, result.strict,
- base::BindOnce(&ElementPrecondition::OnCheckElementExists,
- weak_ptr_factory_.GetWeakPtr(), i));
- }
- batch_checks->AddAllDoneCallback(
- base::BindOnce(&ElementPrecondition::OnAllElementChecksDone,
- weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
-}
-
-void ElementPrecondition::OnCheckElementExists(
- size_t result_index,
- const ClientStatus& element_status,
- const ElementFinder::Result& element_reference) {
- if (result_index >= results_.size()) {
- NOTREACHED();
- return;
- }
- Result& result = results_[result_index];
- result.match = element_status.ok();
- // TODO(szermatt): Consider reporting element_status as an unexpected error
- // right away if it is neither success nor ELEMENT_RESOLUTION_FAILED.
- if (element_status.ok() && result.client_id.has_value()) {
- elements_[*result.client_id] = element_reference.dom_object;
- }
-}
-
-void ElementPrecondition::OnAllElementChecksDone(Callback callback) {
- size_t next_result_index = 0;
- std::vector<std::string> payloads;
- bool match = EvaluateResults(proto_, &next_result_index, &payloads);
- DCHECK_EQ(next_result_index, results_.size());
- std::move(callback).Run(match ? ClientStatus(ACTION_APPLIED)
- : ClientStatus(ELEMENT_RESOLUTION_FAILED),
- payloads, elements_);
-}
-
-bool ElementPrecondition::EvaluateResults(const ElementConditionProto& proto_,
- size_t* next_result_index,
- std::vector<std::string>* payloads) {
- bool match = false;
- switch (proto_.type_case()) {
- case ElementConditionProto::kAllOf: {
- match = true;
- for (const ElementConditionProto& condition :
- proto_.all_of().conditions()) {
- if (!EvaluateResults(condition, next_result_index, payloads)) {
- match = false;
- }
- }
- break;
- }
- case ElementConditionProto::kAnyOf: {
- for (const ElementConditionProto& condition :
- proto_.any_of().conditions()) {
- if (EvaluateResults(condition, next_result_index, payloads)) {
- match = true;
- }
- }
- break;
- }
-
- case ElementConditionProto::kNoneOf: {
- match = true;
- for (const ElementConditionProto& condition :
- proto_.none_of().conditions()) {
- if (EvaluateResults(condition, next_result_index, payloads)) {
- match = false;
- }
- }
- break;
- }
-
- case ElementConditionProto::kMatch: {
- if (*next_result_index >= results_.size()) {
- NOTREACHED();
- break;
- }
- const Result& result = results_[*next_result_index];
- DCHECK_EQ(Selector(proto_.match()), result.selector);
- match = result.match;
- (*next_result_index)++;
- break;
- }
-
- case ElementConditionProto::TYPE_NOT_SET:
- match = true; // An empty condition is true
- break;
- }
- if (match && !proto_.payload().empty()) {
- payloads->emplace_back(proto_.payload());
- }
- return match;
-}
-
-void ElementPrecondition::AddResults(const ElementConditionProto& proto_) {
- switch (proto_.type_case()) {
- case ElementConditionProto::kAllOf:
- for (const ElementConditionProto& condition :
- proto_.all_of().conditions()) {
- AddResults(condition);
- }
- break;
-
- case ElementConditionProto::kAnyOf:
- for (const ElementConditionProto& condition :
- proto_.any_of().conditions()) {
- AddResults(condition);
- }
- break;
-
- case ElementConditionProto::kNoneOf:
- for (const ElementConditionProto& condition :
- proto_.none_of().conditions()) {
- AddResults(condition);
- }
- break;
-
- case ElementConditionProto::kMatch: {
- Result result;
- result.selector = Selector(proto_.match());
- if (proto_.has_client_id()) {
- result.client_id = proto_.client_id().identifier();
- }
- result.strict = proto_.require_unique_element();
- results_.emplace_back(result);
- break;
- }
-
- case ElementConditionProto::TYPE_NOT_SET:
- break;
- }
-}
-
-} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/element_precondition.h b/chromium/components/autofill_assistant/browser/element_precondition.h
deleted file mode 100644
index 532dcfc0020..00000000000
--- a/chromium/components/autofill_assistant/browser/element_precondition.h
+++ /dev/null
@@ -1,101 +0,0 @@
-// Copyright 2019 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.
-
-#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ELEMENT_PRECONDITION_H_
-#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ELEMENT_PRECONDITION_H_
-
-#include <string>
-#include <vector>
-
-#include "base/callback.h"
-#include "base/containers/flat_map.h"
-#include "base/memory/weak_ptr.h"
-#include "components/autofill_assistant/browser/client_status.h"
-#include "components/autofill_assistant/browser/selector.h"
-#include "components/autofill_assistant/browser/service.pb.h"
-#include "components/autofill_assistant/browser/web/element.h"
-#include "components/autofill_assistant/browser/web/element_finder.h"
-#include "third_party/abseil-cpp/absl/types/optional.h"
-
-namespace autofill_assistant {
-class BatchElementChecker;
-
-class ElementPrecondition {
- public:
- // Callback being called after the checks are done with the success status,
- // the matching payloads and a set of matching element lookup results.
- using Callback = base::OnceCallback<void(
- const ClientStatus&,
- const std::vector<std::string>&,
- const base::flat_map<std::string, DomObjectFrameStack>&)>;
-
- ElementPrecondition(const ElementConditionProto& proto);
-
- ElementPrecondition(const ElementPrecondition&) = delete;
- ElementPrecondition& operator=(const ElementPrecondition&) = delete;
-
- ~ElementPrecondition();
-
- // Check whether the conditions are satisfied and return the result through
- // |callback|. |batch_checks| must remain valid until the callback is run.
- //
- // Calling Check() while another check is in progress cancels the previously
- // running check.
- //
- // The callback gets a status, which is ACTION_APPLIED if the overall
- // condition matched, the payloads of specific conditions that matched and
- // a representation of element results found during the checks.
- // Note that payloads and element results can still be sent out even though
- // the overall condition did not match.
- void Check(BatchElementChecker* batch_checks, Callback callback);
-
- bool empty() {
- return proto_.type_case() == ElementConditionProto::TYPE_NOT_SET;
- }
-
- private:
- // Selector that should be checked and the result of checking that selector.
- struct Result {
- Result();
- ~Result();
- Result(const Result&);
-
- Selector selector;
- bool match = false;
-
- // The identifier given to this result through the script. This identifier
- // can be used to later find the element in the |ElementStore|.
- absl::optional<std::string> client_id;
-
- // Whether the matching should be done strict or not.
- bool strict = false;
- };
-
- // Add selectors from |proto| to |results_|, doing a depth-first search.
- void AddResults(const ElementConditionProto& proto);
-
- void OnCheckElementExists(size_t result_index,
- const ClientStatus& element_status,
- const ElementFinder::Result& element_reference);
-
- void OnAllElementChecksDone(Callback callback);
-
- bool EvaluateResults(const ElementConditionProto& proto_,
- size_t* next_result_index,
- std::vector<std::string>* payloads);
-
- const ElementConditionProto proto_;
-
- // Maps ElementConditionProto.match from proto_ to result. Results appear in
- // the same order as in proto_, assuming a depth first search.
- std::vector<Result> results_;
-
- base::flat_map<std::string, DomObjectFrameStack> elements_;
-
- base::WeakPtrFactory<ElementPrecondition> weak_ptr_factory_{this};
-};
-
-} // namespace autofill_assistant
-
-#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ELEMENT_PRECONDITION_H_
diff --git a/chromium/components/autofill_assistant/browser/element_precondition_unittest.cc b/chromium/components/autofill_assistant/browser/element_precondition_unittest.cc
deleted file mode 100644
index 021d47d640a..00000000000
--- a/chromium/components/autofill_assistant/browser/element_precondition_unittest.cc
+++ /dev/null
@@ -1,329 +0,0 @@
-// Copyright 2018 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.
-
-#include "components/autofill_assistant/browser/script_precondition.h"
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/callback_helpers.h"
-#include "base/containers/flat_map.h"
-#include "base/run_loop.h"
-#include "base/test/gmock_callback_support.h"
-#include "base/test/mock_callback.h"
-#include "components/autofill_assistant/browser/batch_element_checker.h"
-#include "components/autofill_assistant/browser/service.pb.h"
-#include "components/autofill_assistant/browser/web/element.h"
-#include "components/autofill_assistant/browser/web/mock_web_controller.h"
-#include "testing/gmock/include/gmock/gmock.h"
-
-namespace autofill_assistant {
-namespace {
-
-using ::base::test::RunOnceCallback;
-using ::testing::_;
-using ::testing::ElementsAre;
-using ::testing::Key;
-using ::testing::Property;
-using ::testing::UnorderedElementsAre;
-using ::testing::WithArgs;
-
-class ElementPreconditionTest : public testing::Test {
- public:
- void SetUp() override {
- ON_CALL(mock_web_controller_, FindElement(Selector({"exists"}), _, _))
- .WillByDefault(WithArgs<2>([](auto&& callback) {
- std::move(callback).Run(OkClientStatus(),
- std::make_unique<ElementFinder::Result>());
- }));
- ON_CALL(mock_web_controller_, FindElement(Selector({"exists_too"}), _, _))
- .WillByDefault(WithArgs<2>([](auto&& callback) {
- std::move(callback).Run(OkClientStatus(),
- std::make_unique<ElementFinder::Result>());
- }));
- ON_CALL(mock_web_controller_,
- FindElement(Selector({"does_not_exist"}), _, _))
- .WillByDefault(RunOnceCallback<2>(
- ClientStatus(ELEMENT_RESOLUTION_FAILED), nullptr));
- ON_CALL(mock_web_controller_,
- FindElement(Selector({"does_not_exist_either"}), _, _))
- .WillByDefault(RunOnceCallback<2>(
- ClientStatus(ELEMENT_RESOLUTION_FAILED), nullptr));
- }
-
- protected:
- // Runs a precondition given |exists_| and |value_match_|.
- void Check(
- base::OnceCallback<void(
- const ClientStatus&,
- const std::vector<std::string>&,
- const base::flat_map<std::string, DomObjectFrameStack>&)> callback) {
- ElementPrecondition precondition(condition_);
- BatchElementChecker batch_checks;
- precondition.Check(&batch_checks, std::move(callback));
- batch_checks.Run(&mock_web_controller_);
- }
-
- MockWebController mock_web_controller_;
- base::MockCallback<base::OnceCallback<void(
- const ClientStatus&,
- const std::vector<std::string>&,
- const base::flat_map<std::string, DomObjectFrameStack>&)>>
- mock_callback_;
- ElementConditionProto condition_;
-};
-
-TEST_F(ElementPreconditionTest, Empty) {
- EXPECT_TRUE(ElementPrecondition(condition_).empty());
-}
-
-TEST_F(ElementPreconditionTest, NonEmpty) {
- *condition_.mutable_match() = ToSelectorProto("exists");
- EXPECT_FALSE(ElementPrecondition(condition_).empty());
-}
-
-TEST_F(ElementPreconditionTest, NoConditions) {
- EXPECT_CALL(mock_callback_,
- Run(Property(&ClientStatus::proto_status, ACTION_APPLIED), _, _));
- Check(mock_callback_.Get());
-}
-
-TEST_F(ElementPreconditionTest, EmptySelector) {
- condition_.mutable_match();
-
- EXPECT_CALL(mock_callback_, Run(Property(&ClientStatus::proto_status,
- ELEMENT_RESOLUTION_FAILED),
- _, _));
- Check(mock_callback_.Get());
-}
-
-TEST_F(ElementPreconditionTest, ElementExists) {
- *condition_.mutable_match() = ToSelectorProto("exists");
-
- EXPECT_CALL(mock_callback_,
- Run(Property(&ClientStatus::proto_status, ACTION_APPLIED), _, _));
- Check(mock_callback_.Get());
-}
-
-TEST_F(ElementPreconditionTest, ElementDoes_Not_Exist) {
- *condition_.mutable_match() = ToSelectorProto("does_not_exist");
-
- EXPECT_CALL(mock_callback_, Run(Property(&ClientStatus::proto_status,
- ELEMENT_RESOLUTION_FAILED),
- _, _));
- Check(mock_callback_.Get());
-}
-
-TEST_F(ElementPreconditionTest, AnyOf_Empty) {
- condition_.mutable_any_of();
-
- EXPECT_CALL(mock_callback_, Run(Property(&ClientStatus::proto_status,
- ELEMENT_RESOLUTION_FAILED),
- _, _));
- Check(mock_callback_.Get());
-}
-
-TEST_F(ElementPreconditionTest, AnyOf_NoneMatch) {
- *condition_.mutable_any_of()->add_conditions()->mutable_match() =
- ToSelectorProto("does_not_exist");
- *condition_.mutable_any_of()->add_conditions()->mutable_match() =
- ToSelectorProto("does_not_exist_either");
-
- EXPECT_CALL(mock_callback_, Run(Property(&ClientStatus::proto_status,
- ELEMENT_RESOLUTION_FAILED),
- _, _));
- Check(mock_callback_.Get());
-}
-
-TEST_F(ElementPreconditionTest, AnyOf_SomeMatch) {
- *condition_.mutable_any_of()->add_conditions()->mutable_match() =
- ToSelectorProto("exists");
- *condition_.mutable_any_of()->add_conditions()->mutable_match() =
- ToSelectorProto("does_not_exist");
-
- EXPECT_CALL(mock_callback_,
- Run(Property(&ClientStatus::proto_status, ACTION_APPLIED), _, _));
- Check(mock_callback_.Get());
-}
-
-TEST_F(ElementPreconditionTest, AnyOf_AllMatch) {
- *condition_.mutable_any_of()->add_conditions()->mutable_match() =
- ToSelectorProto("exists");
- *condition_.mutable_any_of()->add_conditions()->mutable_match() =
- ToSelectorProto("exists_too");
-
- EXPECT_CALL(mock_callback_,
- Run(Property(&ClientStatus::proto_status, ACTION_APPLIED), _, _));
- Check(mock_callback_.Get());
-}
-
-TEST_F(ElementPreconditionTest, AllOf_Empty) {
- condition_.mutable_all_of();
-
- EXPECT_CALL(mock_callback_,
- Run(Property(&ClientStatus::proto_status, ACTION_APPLIED), _, _));
- Check(mock_callback_.Get());
-}
-
-TEST_F(ElementPreconditionTest, AllOf_NoneMatch) {
- *condition_.mutable_all_of()->add_conditions()->mutable_match() =
- ToSelectorProto("does_not_exist");
- *condition_.mutable_all_of()->add_conditions()->mutable_match() =
- ToSelectorProto("does_not_exist_either");
-
- EXPECT_CALL(mock_callback_, Run(Property(&ClientStatus::proto_status,
- ELEMENT_RESOLUTION_FAILED),
- _, _));
- Check(mock_callback_.Get());
-}
-
-TEST_F(ElementPreconditionTest, AllOf_SomeMatch) {
- *condition_.mutable_all_of()->add_conditions()->mutable_match() =
- ToSelectorProto("exists");
- *condition_.mutable_all_of()->add_conditions()->mutable_match() =
- ToSelectorProto("does_not_exist");
-
- EXPECT_CALL(mock_callback_, Run(Property(&ClientStatus::proto_status,
- ELEMENT_RESOLUTION_FAILED),
- _, _));
- Check(mock_callback_.Get());
-}
-
-TEST_F(ElementPreconditionTest, AllOf_AllMatch) {
- *condition_.mutable_all_of()->add_conditions()->mutable_match() =
- ToSelectorProto("exists");
- *condition_.mutable_all_of()->add_conditions()->mutable_match() =
- ToSelectorProto("exists_too");
-
- EXPECT_CALL(mock_callback_,
- Run(Property(&ClientStatus::proto_status, ACTION_APPLIED), _, _));
- Check(mock_callback_.Get());
-}
-
-TEST_F(ElementPreconditionTest, NoneOf_Empty) {
- condition_.mutable_none_of();
-
- EXPECT_CALL(mock_callback_,
- Run(Property(&ClientStatus::proto_status, ACTION_APPLIED), _, _));
- Check(mock_callback_.Get());
-}
-
-TEST_F(ElementPreconditionTest, NoneOf_NoneMatch) {
- *condition_.mutable_none_of()->add_conditions()->mutable_match() =
- ToSelectorProto("does_not_exist");
- *condition_.mutable_none_of()->add_conditions()->mutable_match() =
- ToSelectorProto("does_not_exist_either");
-
- EXPECT_CALL(mock_callback_,
- Run(Property(&ClientStatus::proto_status, ACTION_APPLIED), _, _));
- Check(mock_callback_.Get());
-}
-
-TEST_F(ElementPreconditionTest, NoneOf_SomeMatch) {
- *condition_.mutable_none_of()->add_conditions()->mutable_match() =
- ToSelectorProto("exists");
- *condition_.mutable_none_of()->add_conditions()->mutable_match() =
- ToSelectorProto("does_not_exist");
-
- EXPECT_CALL(mock_callback_, Run(Property(&ClientStatus::proto_status,
- ELEMENT_RESOLUTION_FAILED),
- _, _));
- Check(mock_callback_.Get());
-}
-
-TEST_F(ElementPreconditionTest, NoneOf_AllMatch) {
- *condition_.mutable_none_of()->add_conditions()->mutable_match() =
- ToSelectorProto("exists");
- *condition_.mutable_none_of()->add_conditions()->mutable_match() =
- ToSelectorProto("exists_too");
-
- EXPECT_CALL(mock_callback_, Run(Property(&ClientStatus::proto_status,
- ELEMENT_RESOLUTION_FAILED),
- _, _));
- Check(mock_callback_.Get());
-}
-
-TEST_F(ElementPreconditionTest, Payload_ConditionMet) {
- auto* exists = condition_.mutable_any_of()->add_conditions();
- *exists->mutable_match() = ToSelectorProto("exists");
- exists->set_payload("exists");
-
- auto* exists_too = condition_.mutable_any_of()->add_conditions();
- *exists_too->mutable_match() = ToSelectorProto("exists_too");
- exists_too->set_payload("exists_too");
-
- condition_.set_payload("any_of");
-
- EXPECT_CALL(mock_callback_,
- Run(Property(&ClientStatus::proto_status, ACTION_APPLIED),
- ElementsAre("exists", "exists_too", "any_of"), _));
- Check(mock_callback_.Get());
-}
-
-TEST_F(ElementPreconditionTest, Payload_ConditionNotMet) {
- auto* exists = condition_.mutable_none_of()->add_conditions();
- *exists->mutable_match() = ToSelectorProto("exists");
- exists->set_payload("exists");
-
- auto* exists_too = condition_.mutable_none_of()->add_conditions();
- *exists_too->mutable_match() = ToSelectorProto("exists_too");
- exists_too->set_payload("exists_too");
-
- condition_.set_payload("none_of");
-
- EXPECT_CALL(mock_callback_, Run(Property(&ClientStatus::proto_status,
- ELEMENT_RESOLUTION_FAILED),
- ElementsAre("exists", "exists_too"), _));
- Check(mock_callback_.Get());
-}
-
-TEST_F(ElementPreconditionTest, Complex) {
- *condition_.mutable_all_of()->add_conditions()->mutable_match() =
- ToSelectorProto("exists");
- *condition_.mutable_all_of()->add_conditions()->mutable_match() =
- ToSelectorProto("exists_too");
- auto* none_of = condition_.mutable_all_of()->add_conditions();
- none_of->set_payload("none_of");
- auto* does_not_exist_in_none_of =
- none_of->mutable_none_of()->add_conditions();
- *does_not_exist_in_none_of->mutable_match() =
- ToSelectorProto("does_not_exist");
- does_not_exist_in_none_of->set_payload("does_not_exist in none_of");
- *none_of->mutable_none_of()->add_conditions()->mutable_match() =
- ToSelectorProto("does_not_exist_either");
-
- auto* any_of = condition_.mutable_all_of()->add_conditions();
- any_of->set_payload("any_of");
- auto* exists_in_any_of = any_of->mutable_any_of()->add_conditions();
- *exists_in_any_of->mutable_match() = ToSelectorProto("exists");
- exists_in_any_of->set_payload("exists in any_of");
-
- *any_of->mutable_any_of()->add_conditions()->mutable_match() =
- ToSelectorProto("does_not_exist");
-
- EXPECT_CALL(mock_callback_,
- Run(Property(&ClientStatus::proto_status, ACTION_APPLIED),
- ElementsAre("none_of", "exists in any_of", "any_of"), _));
- Check(mock_callback_.Get());
-}
-
-TEST_F(ElementPreconditionTest, ReturnsFoundElements) {
- auto* exists = condition_.mutable_all_of()->add_conditions();
- *exists->mutable_match() = ToSelectorProto("exists");
- exists->set_payload("exists");
- exists->mutable_client_id()->set_identifier("exists");
-
- auto* exists_too = condition_.mutable_all_of()->add_conditions();
- *exists_too->mutable_match() = ToSelectorProto("exists_too");
- exists_too->set_payload("exists_too");
- exists_too->mutable_client_id()->set_identifier("exists_too");
-
- EXPECT_CALL(mock_callback_,
- Run(Property(&ClientStatus::proto_status, ACTION_APPLIED),
- ElementsAre("exists", "exists_too"),
- UnorderedElementsAre(Key("exists"), Key("exists_too"))));
- Check(mock_callback_.Get());
-}
-
-} // namespace
-} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/execution_delegate.h b/chromium/components/autofill_assistant/browser/execution_delegate.h
new file mode 100644
index 00000000000..03da9ba26cd
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/execution_delegate.h
@@ -0,0 +1,124 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_EXECUTION_DELEGATE_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_EXECUTION_DELEGATE_H_
+
+#include "components/autofill_assistant/browser/client_settings.h"
+#include "components/autofill_assistant/browser/event_handler.h"
+#include "components/autofill_assistant/browser/public/runtime_manager_impl.h"
+#include "components/autofill_assistant/browser/rectf.h"
+#include "components/autofill_assistant/browser/state.h"
+#include "components/autofill_assistant/browser/user_data.h"
+#include "components/autofill_assistant/browser/viewport_mode.h"
+
+namespace autofill_assistant {
+class ControllerObserver;
+
+// Execution delegate is used to access the current session's state and to
+// notify the Controller.
+class ExecutionDelegate {
+ public:
+ // Colors of the overlay. Empty string to use the default.
+ struct OverlayColors {
+ // Overlay background color.
+ std::string background;
+
+ // Color of the border around the highlighted portions of the overlay.
+ std::string highlight_border;
+ };
+
+ virtual ~ExecutionDelegate() = default;
+
+ // Returns the current state of the controller.
+ virtual AutofillAssistantState GetState() const = 0;
+
+ // If the controller is waiting for user data, this field contains a non-null
+ // object describing the currently selected data.
+ virtual UserData* GetUserData() = 0;
+
+ // Reports a fatal error to Autofill Assistant, which should then stop.
+ virtual void OnFatalError(const std::string& error_message,
+ Metrics::DropOutReason reason) = 0;
+
+ // Reports that Autofill Assistant should be Stopped.
+ virtual void OnStop(const std::string& message,
+ const std::string& button_label) = 0;
+
+ // Adds the rectangles that correspond to the current touchable area to
+ // the given vector.
+ //
+ // At the end of this call, |rectangles| contains one element per
+ // configured rectangles, though these can correspond to empty rectangles.
+ // Coordinates absolute CSS coordinates.
+ //
+ // Note that the vector is not cleared before rectangles are added.
+ virtual void GetTouchableArea(std::vector<RectF>* rectangles) const = 0;
+ virtual void GetRestrictedArea(std::vector<RectF>* rectangles) const = 0;
+
+ // Returns the current size of the visual viewport. May be empty if
+ // unknown.
+ //
+ // The rectangle is expressed in absolute CSS coordinates.
+ virtual void GetVisualViewport(RectF* viewport) const = 0;
+
+ // Returns whether the viewport should be resized.
+ virtual ViewportMode GetViewportMode() = 0;
+
+ // Gets whether the tab associated with this controller is currently selected.
+ virtual bool IsTabSelected() = 0;
+
+ // Sets whether the tab associated with this controller is currently selected.
+ virtual void SetTabSelected(bool selected) = 0;
+
+ // Fills in the overlay colors.
+ virtual void GetOverlayColors(OverlayColors* colors) const = 0;
+
+ // Gets the current Client Settings
+ virtual const ClientSettings& GetClientSettings() const = 0;
+
+ // Gets the trgger context
+ virtual const TriggerContext* GetTriggerContext() = 0;
+
+ // Gets the current URL
+ virtual const GURL& GetCurrentURL() = 0;
+
+ // Sets whether a UI is shown.
+ virtual void SetUiShown(bool shown) = 0;
+
+ // Returns the user model.
+ virtual UserModel* GetUserModel() = 0;
+
+ // Whether the overlay should be determined based on AA state or always
+ // hidden.
+ virtual bool ShouldShowOverlay() const = 0;
+
+ // Whether the keyboard should currently be suppressed.
+ virtual bool ShouldSuppressKeyboard() const = 0;
+
+ // Set the keyboard suppression for all frames for the current WebContent's
+ // main page.
+ virtual void SuppressKeyboard(bool suppress) = 0;
+
+ // Notifies the execution delegate that it should shut down.
+ virtual void ShutdownIfNecessary() = 0;
+
+ // Notifies the execution delegate about a change to the UserData.
+ virtual void NotifyUserDataChange(UserData::FieldChange field_change) = 0;
+
+ // Register an observer. Observers get told about changes to the
+ // controller.
+ virtual void AddObserver(ControllerObserver* observer) = 0;
+
+ // Remove a previously registered observer.
+ virtual void RemoveObserver(const ControllerObserver* observer) = 0;
+
+ // Returns true if the controller is in a state where UI is necessary.
+ virtual bool NeedsUI() const = 0;
+
+ protected:
+ ExecutionDelegate() = default;
+};
+} // namespace autofill_assistant
+#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_EXECUTION_DELEGATE_H_
diff --git a/chromium/components/autofill_assistant/browser/fake_script_executor_delegate.cc b/chromium/components/autofill_assistant/browser/fake_script_executor_delegate.cc
index efdb512d63b..35de276dbd1 100644
--- a/chromium/components/autofill_assistant/browser/fake_script_executor_delegate.cc
+++ b/chromium/components/autofill_assistant/browser/fake_script_executor_delegate.cc
@@ -6,6 +6,8 @@
#include <utility>
+#include "components/password_manager/core/browser/password_change_success_tracker.h"
+
namespace autofill_assistant {
FakeScriptExecutorDelegate::FakeScriptExecutorDelegate()
@@ -50,6 +52,11 @@ WebsiteLoginManager* FakeScriptExecutorDelegate::GetWebsiteLoginManager() {
return nullptr;
}
+password_manager::PasswordChangeSuccessTracker*
+FakeScriptExecutorDelegate::GetPasswordChangeSuccessTracker() {
+ return nullptr;
+}
+
content::WebContents* FakeScriptExecutorDelegate::GetWebContents() {
return nullptr;
}
@@ -70,7 +77,7 @@ bool FakeScriptExecutorDelegate::EnterState(AutofillAssistantState state) {
return true;
}
-AutofillAssistantState FakeScriptExecutorDelegate::GetState() {
+AutofillAssistantState FakeScriptExecutorDelegate::GetState() const {
return state_history_.empty() ? AutofillAssistantState::INACTIVE
: state_history_.back();
}
@@ -80,106 +87,9 @@ void FakeScriptExecutorDelegate::SetTouchableElementArea(
touchable_element_area_history_.emplace_back(element_area);
}
-void FakeScriptExecutorDelegate::SetStatusMessage(const std::string& message) {
- status_message_ = message;
-}
-
-std::string FakeScriptExecutorDelegate::GetStatusMessage() const {
- return status_message_;
-}
-
-void FakeScriptExecutorDelegate::SetBubbleMessage(const std::string& message) {
- bubble_message_ = message;
-}
-
-std::string FakeScriptExecutorDelegate::GetBubbleMessage() const {
- return bubble_message_;
-}
-
-void FakeScriptExecutorDelegate::SetTtsMessage(const std::string& message) {
- tts_message_ = message;
-}
-
-std::string FakeScriptExecutorDelegate::GetTtsMessage() const {
- return tts_message_;
-}
-
-TtsButtonState FakeScriptExecutorDelegate::GetTtsButtonState() const {
- return TtsButtonState::DEFAULT;
-}
-
-void FakeScriptExecutorDelegate::MaybePlayTtsMessage() {}
-
-void FakeScriptExecutorDelegate::SetDetails(std::unique_ptr<Details> details,
- base::TimeDelta delay) {
- // We ignore |delay|.
- if (details) {
- details_ = {*details};
- } else {
- details_ = {};
- }
-}
-
-void FakeScriptExecutorDelegate::AppendDetails(std::unique_ptr<Details> details,
- base::TimeDelta delay) {
- // We ignore |delay|.
- if (details) {
- details_.push_back(*details);
- }
-}
-
-void FakeScriptExecutorDelegate::SetInfoBox(const InfoBox& info_box) {
- info_box_ = std::make_unique<InfoBox>(info_box);
-}
-
-void FakeScriptExecutorDelegate::ClearInfoBox() {
- info_box_ = nullptr;
-}
-
-bool FakeScriptExecutorDelegate::SetProgressActiveStepIdentifier(
- const std::string& active_step_identifier) {
- return true;
-}
-
-void FakeScriptExecutorDelegate::SetProgressActiveStep(int active_step) {}
-
-void FakeScriptExecutorDelegate::SetProgressVisible(bool visible) {}
-
-void FakeScriptExecutorDelegate::SetProgressBarErrorState(bool error) {}
-
-void FakeScriptExecutorDelegate::SetStepProgressBarConfiguration(
- const ShowProgressBarProto::StepProgressBarConfiguration& configuration) {}
-
-void FakeScriptExecutorDelegate::SetUserActions(
- std::unique_ptr<std::vector<UserAction>> user_actions) {
- user_actions_ = std::move(user_actions);
-}
-
-void FakeScriptExecutorDelegate::SetCollectUserDataOptions(
- CollectUserDataOptions* options) {
- payment_request_options_ = options;
-}
-
-void FakeScriptExecutorDelegate::SetLastSuccessfulUserDataOptions(
- std::unique_ptr<CollectUserDataOptions> collect_user_data_options) {
- last_payment_request_options_ = std::move(collect_user_data_options);
-}
-
-const CollectUserDataOptions*
-FakeScriptExecutorDelegate::GetLastSuccessfulUserDataOptions() const {
- return last_payment_request_options_.get();
-}
-
void FakeScriptExecutorDelegate::WriteUserData(
base::OnceCallback<void(UserData*, UserData::FieldChange*)>
- write_callback) {
- if (payment_request_options_ == nullptr || payment_request_info_ == nullptr) {
- return;
- }
-
- UserData::FieldChange field_change = UserData::FieldChange::NONE;
- std::move(write_callback).Run(payment_request_info_.get(), &field_change);
-}
+ write_callback) {}
void FakeScriptExecutorDelegate::SetViewportMode(ViewportMode mode) {
viewport_mode_ = mode;
@@ -189,25 +99,6 @@ ViewportMode FakeScriptExecutorDelegate::GetViewportMode() {
return viewport_mode_;
}
-void FakeScriptExecutorDelegate::SetPeekMode(
- ConfigureBottomSheetProto::PeekMode peek_mode) {
- peek_mode_ = peek_mode;
-}
-
-ConfigureBottomSheetProto::PeekMode FakeScriptExecutorDelegate::GetPeekMode() {
- return peek_mode_;
-}
-
-void FakeScriptExecutorDelegate::ExpandBottomSheet() {
- expand_or_collapse_updated_ = true;
- expand_or_collapse_value_ = true;
-}
-
-void FakeScriptExecutorDelegate::CollapseBottomSheet() {
- expand_or_collapse_updated_ = true;
- expand_or_collapse_value_ = false;
-}
-
void FakeScriptExecutorDelegate::ExpectNavigation() {}
bool FakeScriptExecutorDelegate::HasNavigationError() {
@@ -246,10 +137,6 @@ void FakeScriptExecutorDelegate::RemoveListener(
listeners_.erase(listener);
}
-void FakeScriptExecutorDelegate::SetExpandSheetForPromptAction(bool expand) {
- expand_sheet_for_prompt_ = expand;
-}
-
void FakeScriptExecutorDelegate::SetBrowseDomainsAllowlist(
std::vector<std::string> domains) {
browse_domains_ = std::move(domains);
@@ -260,49 +147,22 @@ void FakeScriptExecutorDelegate::SetClientSettings(
client_settings_.UpdateFromProto(client_settings);
}
-bool FakeScriptExecutorDelegate::SetForm(
- std::unique_ptr<FormProto> form,
- base::RepeatingCallback<void(const FormProto::Result*)> changed_callback,
- base::OnceCallback<void(const ClientStatus&)> cancel_callback) {
- return true;
-}
-
UserModel* FakeScriptExecutorDelegate::GetUserModel() {
return user_model_;
}
-EventHandler* FakeScriptExecutorDelegate::GetEventHandler() {
- return nullptr;
-}
-
-void FakeScriptExecutorDelegate::SetGenericUi(
- std::unique_ptr<GenericUserInterfaceProto> generic_ui,
- base::OnceCallback<void(const ClientStatus&)> end_action_callback,
- base::OnceCallback<void(const ClientStatus&)>
- view_inflation_finished_callback) {}
-
-void FakeScriptExecutorDelegate::SetPersistentGenericUi(
- std::unique_ptr<GenericUserInterfaceProto> generic_ui,
- base::OnceCallback<void(const ClientStatus&)>
- view_inflation_finished_callback) {
- persistent_generic_ui_ = std::move(generic_ui);
-}
-
-void FakeScriptExecutorDelegate::ClearGenericUi() {}
-
-void FakeScriptExecutorDelegate::ClearPersistentGenericUi() {
- persistent_generic_ui_.reset();
-}
-
void FakeScriptExecutorDelegate::SetOverlayBehavior(
ConfigureUiStateProto::OverlayBehavior overaly_behavior) {}
void FakeScriptExecutorDelegate::SetBrowseModeInvisible(bool invisible) {}
-void FakeScriptExecutorDelegate::SetShowFeedbackChip(bool show_feedback_chip) {}
-
bool FakeScriptExecutorDelegate::ShouldShowWarning() {
return true;
}
+std::vector<std::string>*
+FakeScriptExecutorDelegate::GetCurrentBrowseDomainsList() {
+ return &browse_domains_;
+}
+
} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/fake_script_executor_delegate.h b/chromium/components/autofill_assistant/browser/fake_script_executor_delegate.h
index 75a19f4da53..faa23b08425 100644
--- a/chromium/components/autofill_assistant/browser/fake_script_executor_delegate.h
+++ b/chromium/components/autofill_assistant/browser/fake_script_executor_delegate.h
@@ -15,6 +15,10 @@
#include "components/autofill_assistant/browser/script_executor_delegate.h"
#include "components/autofill_assistant/browser/trigger_context.h"
+namespace password_manager {
+class PasswordChangeSuccessTracker;
+}
+
namespace autofill_assistant {
// Implementation of ScriptExecutorDelegate that's convenient to use in
@@ -38,56 +42,20 @@ class FakeScriptExecutorDelegate : public ScriptExecutorDelegate {
TriggerContext* GetTriggerContext() override;
autofill::PersonalDataManager* GetPersonalDataManager() override;
WebsiteLoginManager* GetWebsiteLoginManager() override;
+ password_manager::PasswordChangeSuccessTracker*
+ GetPasswordChangeSuccessTracker() override;
content::WebContents* GetWebContents() override;
std::string GetEmailAddressForAccessTokenAccount() override;
ukm::UkmRecorder* GetUkmRecorder() override;
bool EnterState(AutofillAssistantState state) override;
- AutofillAssistantState GetState() override;
+ AutofillAssistantState GetState() const override;
void SetTouchableElementArea(const ElementAreaProto& element) override;
- void SetStatusMessage(const std::string& message) override;
- std::string GetStatusMessage() const override;
- void SetBubbleMessage(const std::string& message) override;
- std::string GetBubbleMessage() const override;
- void SetTtsMessage(const std::string& message) override;
- std::string GetTtsMessage() const override;
- TtsButtonState GetTtsButtonState() const override;
- void MaybePlayTtsMessage() override;
- void SetDetails(std::unique_ptr<Details> details,
- base::TimeDelta delay) override;
- void AppendDetails(std::unique_ptr<Details> details,
- base::TimeDelta delay) override;
- void SetInfoBox(const InfoBox& info_box) override;
- void ClearInfoBox() override;
- bool SetProgressActiveStepIdentifier(
- const std::string& active_step_identifier) override;
- void SetProgressActiveStep(int active_step) override;
- void SetProgressVisible(bool visible) override;
- void SetProgressBarErrorState(bool error) override;
- void SetStepProgressBarConfiguration(
- const ShowProgressBarProto::StepProgressBarConfiguration& configuration)
- override;
- void SetUserActions(
- std::unique_ptr<std::vector<UserAction>> user_actions) override;
- void SetCollectUserDataOptions(CollectUserDataOptions* options) override;
- void SetLastSuccessfulUserDataOptions(std::unique_ptr<CollectUserDataOptions>
- collect_user_data_options) override;
- const CollectUserDataOptions* GetLastSuccessfulUserDataOptions()
- const override;
void WriteUserData(
base::OnceCallback<void(UserData*, UserData::FieldChange*)>) override;
void SetViewportMode(ViewportMode mode) override;
ViewportMode GetViewportMode() override;
- void SetPeekMode(ConfigureBottomSheetProto::PeekMode peek_mode) override;
- ConfigureBottomSheetProto::PeekMode GetPeekMode() override;
- void ExpandBottomSheet() override;
- void CollapseBottomSheet() override;
void SetClientSettings(const ClientSettingsProto& client_settings) override;
- bool SetForm(
- std::unique_ptr<FormProto> form,
- base::RepeatingCallback<void(const FormProto::Result*)> changed_callback,
- base::OnceCallback<void(const ClientStatus&)> cancel_callback) override;
UserModel* GetUserModel() override;
- EventHandler* GetEventHandler() override;
void ExpectNavigation() override;
bool HasNavigationError() override;
bool IsNavigatingToNewDocument() override;
@@ -98,23 +66,10 @@ class FakeScriptExecutorDelegate : public ScriptExecutorDelegate {
ScriptExecutorDelegate::NavigationListener* listener) override;
void AddListener(ScriptExecutorDelegate::Listener* listener) override;
void RemoveListener(ScriptExecutorDelegate::Listener* listener) override;
- void SetExpandSheetForPromptAction(bool expand) override;
void SetBrowseDomainsAllowlist(std::vector<std::string> domains) override;
- void SetGenericUi(
- std::unique_ptr<GenericUserInterfaceProto> generic_ui,
- base::OnceCallback<void(const ClientStatus&)> end_action_callback,
- base::OnceCallback<void(const ClientStatus&)>
- view_inflation_finished_callback) override;
- void SetPersistentGenericUi(
- std::unique_ptr<GenericUserInterfaceProto> generic_ui,
- base::OnceCallback<void(const ClientStatus&)>
- view_inflation_finished_callback) override;
- void ClearGenericUi() override;
- void ClearPersistentGenericUi() override;
void SetOverlayBehavior(
ConfigureUiStateProto::OverlayBehavior overlay_behavior) override;
void SetBrowseModeInvisible(bool invisible) override;
- void SetShowFeedbackChip(bool show_feedback_chip) override;
ProcessedActionStatusDetailsProto& GetLogInfo() override;
bool ShouldShowWarning() override;
@@ -141,18 +96,6 @@ class FakeScriptExecutorDelegate : public ScriptExecutorDelegate {
return touchable_element_area_history_;
}
- const std::vector<Details>& GetDetails() { return details_; }
-
- const GenericUserInterfaceProto* GetPersistentGenericUi() {
- return persistent_generic_ui_.get();
- }
-
- InfoBox* GetInfoBox() { return info_box_.get(); }
-
- std::vector<UserAction>* GetUserActions() { return user_actions_.get(); }
-
- CollectUserDataOptions* GetOptions() { return payment_request_options_; }
-
void UpdateNavigationState(bool navigating, bool error) {
navigating_to_new_document_ = navigating;
navigation_error_ = error;
@@ -168,6 +111,8 @@ class FakeScriptExecutorDelegate : public ScriptExecutorDelegate {
bool IsUIRequired() { return require_ui_; }
+ std::vector<std::string>* GetCurrentBrowseDomainsList();
+
private:
ClientSettings client_settings_;
GURL current_url_;
@@ -176,14 +121,6 @@ class FakeScriptExecutorDelegate : public ScriptExecutorDelegate {
std::unique_ptr<TriggerContext> trigger_context_;
std::vector<AutofillAssistantState> state_history_;
std::vector<ElementAreaProto> touchable_element_area_history_;
- std::string status_message_;
- std::string tts_message_;
- std::string bubble_message_;
- std::vector<Details> details_;
- std::unique_ptr<InfoBox> info_box_;
- std::unique_ptr<std::vector<UserAction>> user_actions_;
- std::unique_ptr<CollectUserDataOptions> last_payment_request_options_;
- raw_ptr<CollectUserDataOptions> payment_request_options_;
std::unique_ptr<UserData> payment_request_info_;
bool navigating_to_new_document_ = false;
bool navigation_error_ = false;
@@ -191,14 +128,8 @@ class FakeScriptExecutorDelegate : public ScriptExecutorDelegate {
navigation_listeners_;
base::flat_set<ScriptExecutorDelegate::Listener*> listeners_;
ViewportMode viewport_mode_ = ViewportMode::NO_RESIZE;
- ConfigureBottomSheetProto::PeekMode peek_mode_ =
- ConfigureBottomSheetProto::HANDLE;
- bool expand_or_collapse_updated_ = false;
- bool expand_or_collapse_value_ = false;
- bool expand_sheet_for_prompt_ = true;
std::vector<std::string> browse_domains_;
raw_ptr<UserModel> user_model_ = nullptr;
- std::unique_ptr<GenericUserInterfaceProto> persistent_generic_ui_;
ProcessedActionStatusDetailsProto log_info_;
bool require_ui_ = false;
diff --git a/chromium/components/autofill_assistant/browser/fake_script_executor_ui_delegate.cc b/chromium/components/autofill_assistant/browser/fake_script_executor_ui_delegate.cc
new file mode 100644
index 00000000000..ba03a35aa75
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/fake_script_executor_ui_delegate.cc
@@ -0,0 +1,161 @@
+// Copyright 2022 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.
+
+#include "components/autofill_assistant/browser/fake_script_executor_ui_delegate.h"
+
+#include <utility>
+
+namespace autofill_assistant {
+
+FakeScriptExecutorUiDelegate::FakeScriptExecutorUiDelegate() {}
+
+FakeScriptExecutorUiDelegate::~FakeScriptExecutorUiDelegate() = default;
+
+void FakeScriptExecutorUiDelegate::SetStatusMessage(
+ const std::string& message) {
+ status_message_ = message;
+}
+
+std::string FakeScriptExecutorUiDelegate::GetStatusMessage() const {
+ return status_message_;
+}
+
+void FakeScriptExecutorUiDelegate::SetBubbleMessage(
+ const std::string& message) {
+ bubble_message_ = message;
+}
+
+std::string FakeScriptExecutorUiDelegate::GetBubbleMessage() const {
+ return bubble_message_;
+}
+
+void FakeScriptExecutorUiDelegate::SetTtsMessage(const std::string& message) {
+ tts_message_ = message;
+}
+
+std::string FakeScriptExecutorUiDelegate::GetTtsMessage() const {
+ return tts_message_;
+}
+
+TtsButtonState FakeScriptExecutorUiDelegate::GetTtsButtonState() const {
+ return TtsButtonState::DEFAULT;
+}
+
+void FakeScriptExecutorUiDelegate::MaybePlayTtsMessage() {}
+
+void FakeScriptExecutorUiDelegate::SetDetails(std::unique_ptr<Details> details,
+ base::TimeDelta delay) {
+ // We ignore |delay|.
+ if (details) {
+ details_ = {*details};
+ } else {
+ details_ = {};
+ }
+}
+
+void FakeScriptExecutorUiDelegate::AppendDetails(
+ std::unique_ptr<Details> details,
+ base::TimeDelta delay) {
+ // We ignore |delay|.
+ if (details) {
+ details_.push_back(*details);
+ }
+}
+
+void FakeScriptExecutorUiDelegate::SetInfoBox(const InfoBox& info_box) {
+ info_box_ = std::make_unique<InfoBox>(info_box);
+}
+
+void FakeScriptExecutorUiDelegate::ClearInfoBox() {
+ info_box_ = nullptr;
+}
+
+bool FakeScriptExecutorUiDelegate::SetProgressActiveStepIdentifier(
+ const std::string& active_step_identifier) {
+ return true;
+}
+
+void FakeScriptExecutorUiDelegate::SetProgressActiveStep(int active_step) {}
+
+void FakeScriptExecutorUiDelegate::SetProgressVisible(bool visible) {}
+
+void FakeScriptExecutorUiDelegate::SetProgressBarErrorState(bool error) {}
+
+void FakeScriptExecutorUiDelegate::SetStepProgressBarConfiguration(
+ const ShowProgressBarProto::StepProgressBarConfiguration& configuration) {}
+
+void FakeScriptExecutorUiDelegate::SetUserActions(
+ std::unique_ptr<std::vector<UserAction>> user_actions) {
+ user_actions_ = std::move(user_actions);
+}
+
+void FakeScriptExecutorUiDelegate::SetCollectUserDataOptions(
+ CollectUserDataOptions* options) {
+ payment_request_options_ = options;
+}
+
+void FakeScriptExecutorUiDelegate::SetLastSuccessfulUserDataOptions(
+ std::unique_ptr<CollectUserDataOptions> collect_user_data_options) {
+ last_payment_request_options_ = std::move(collect_user_data_options);
+}
+
+const CollectUserDataOptions*
+FakeScriptExecutorUiDelegate::GetLastSuccessfulUserDataOptions() const {
+ return last_payment_request_options_.get();
+}
+
+void FakeScriptExecutorUiDelegate::SetPeekMode(
+ ConfigureBottomSheetProto::PeekMode peek_mode) {
+ peek_mode_ = peek_mode;
+}
+
+ConfigureBottomSheetProto::PeekMode
+FakeScriptExecutorUiDelegate::GetPeekMode() {
+ return peek_mode_;
+}
+
+void FakeScriptExecutorUiDelegate::ExpandBottomSheet() {
+ expand_or_collapse_updated_ = true;
+ expand_or_collapse_value_ = true;
+}
+
+void FakeScriptExecutorUiDelegate::CollapseBottomSheet() {
+ expand_or_collapse_updated_ = true;
+ expand_or_collapse_value_ = false;
+}
+
+void FakeScriptExecutorUiDelegate::SetExpandSheetForPromptAction(bool expand) {
+ expand_sheet_for_prompt_ = expand;
+}
+
+bool FakeScriptExecutorUiDelegate::SetForm(
+ std::unique_ptr<FormProto> form,
+ base::RepeatingCallback<void(const FormProto::Result*)> changed_callback,
+ base::OnceCallback<void(const ClientStatus&)> cancel_callback) {
+ return true;
+}
+
+void FakeScriptExecutorUiDelegate::SetGenericUi(
+ std::unique_ptr<GenericUserInterfaceProto> generic_ui,
+ base::OnceCallback<void(const ClientStatus&)> end_action_callback,
+ base::OnceCallback<void(const ClientStatus&)>
+ view_inflation_finished_callback) {}
+
+void FakeScriptExecutorUiDelegate::SetPersistentGenericUi(
+ std::unique_ptr<GenericUserInterfaceProto> generic_ui,
+ base::OnceCallback<void(const ClientStatus&)>
+ view_inflation_finished_callback) {
+ persistent_generic_ui_ = std::move(generic_ui);
+}
+
+void FakeScriptExecutorUiDelegate::ClearGenericUi() {}
+
+void FakeScriptExecutorUiDelegate::ClearPersistentGenericUi() {
+ persistent_generic_ui_.reset();
+}
+
+void FakeScriptExecutorUiDelegate::SetShowFeedbackChip(
+ bool show_feedback_chip) {}
+
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/fake_script_executor_ui_delegate.h b/chromium/components/autofill_assistant/browser/fake_script_executor_ui_delegate.h
new file mode 100644
index 00000000000..fc3106592a8
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/fake_script_executor_ui_delegate.h
@@ -0,0 +1,113 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_FAKE_SCRIPT_EXECUTOR_UI_DELEGATE_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_FAKE_SCRIPT_EXECUTOR_UI_DELEGATE_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/containers/flat_set.h"
+#include "base/memory/raw_ptr.h"
+#include "components/autofill_assistant/browser/script_executor_ui_delegate.h"
+#include "components/autofill_assistant/browser/trigger_context.h"
+
+namespace autofill_assistant {
+
+// Implementation of ScriptExecutorUiDelegate that's convenient to use in
+// unittests.
+class FakeScriptExecutorUiDelegate : public ScriptExecutorUiDelegate {
+ public:
+ FakeScriptExecutorUiDelegate();
+
+ FakeScriptExecutorUiDelegate(const FakeScriptExecutorUiDelegate&) = delete;
+ FakeScriptExecutorUiDelegate& operator=(const FakeScriptExecutorUiDelegate&) =
+ delete;
+
+ ~FakeScriptExecutorUiDelegate() override;
+ void SetStatusMessage(const std::string& message) override;
+ std::string GetStatusMessage() const override;
+ void SetBubbleMessage(const std::string& message) override;
+ std::string GetBubbleMessage() const override;
+ void SetTtsMessage(const std::string& message) override;
+ std::string GetTtsMessage() const override;
+ TtsButtonState GetTtsButtonState() const override;
+ void MaybePlayTtsMessage() override;
+ void SetDetails(std::unique_ptr<Details> details,
+ base::TimeDelta delay) override;
+ void AppendDetails(std::unique_ptr<Details> details,
+ base::TimeDelta delay) override;
+ void SetInfoBox(const InfoBox& info_box) override;
+ void ClearInfoBox() override;
+ bool SetProgressActiveStepIdentifier(
+ const std::string& active_step_identifier) override;
+ void SetProgressActiveStep(int active_step) override;
+ void SetProgressVisible(bool visible) override;
+ void SetProgressBarErrorState(bool error) override;
+ void SetStepProgressBarConfiguration(
+ const ShowProgressBarProto::StepProgressBarConfiguration& configuration)
+ override;
+ void SetUserActions(
+ std::unique_ptr<std::vector<UserAction>> user_actions) override;
+ void SetCollectUserDataOptions(CollectUserDataOptions* options) override;
+ void SetLastSuccessfulUserDataOptions(std::unique_ptr<CollectUserDataOptions>
+ collect_user_data_options) override;
+ const CollectUserDataOptions* GetLastSuccessfulUserDataOptions()
+ const override;
+ void SetPeekMode(ConfigureBottomSheetProto::PeekMode peek_mode) override;
+ ConfigureBottomSheetProto::PeekMode GetPeekMode() override;
+ void ExpandBottomSheet() override;
+ void CollapseBottomSheet() override;
+ bool SetForm(
+ std::unique_ptr<FormProto> form,
+ base::RepeatingCallback<void(const FormProto::Result*)> changed_callback,
+ base::OnceCallback<void(const ClientStatus&)> cancel_callback) override;
+ void SetExpandSheetForPromptAction(bool expand) override;
+ void SetGenericUi(
+ std::unique_ptr<GenericUserInterfaceProto> generic_ui,
+ base::OnceCallback<void(const ClientStatus&)> end_action_callback,
+ base::OnceCallback<void(const ClientStatus&)>
+ view_inflation_finished_callback) override;
+ void SetPersistentGenericUi(
+ std::unique_ptr<GenericUserInterfaceProto> generic_ui,
+ base::OnceCallback<void(const ClientStatus&)>
+ view_inflation_finished_callback) override;
+ void ClearGenericUi() override;
+ void ClearPersistentGenericUi() override;
+ void SetShowFeedbackChip(bool show_feedback_chip) override;
+
+ const std::vector<Details>& GetDetails() { return details_; }
+
+ const GenericUserInterfaceProto* GetPersistentGenericUi() {
+ return persistent_generic_ui_.get();
+ }
+
+ InfoBox* GetInfoBox() { return info_box_.get(); }
+
+ std::vector<UserAction>* GetUserActions() { return user_actions_.get(); }
+
+ CollectUserDataOptions* GetOptions() { return payment_request_options_; }
+
+ private:
+ std::string status_message_;
+ std::string tts_message_;
+ std::string bubble_message_;
+ std::vector<Details> details_;
+ std::unique_ptr<InfoBox> info_box_;
+ std::unique_ptr<std::vector<UserAction>> user_actions_;
+ std::unique_ptr<CollectUserDataOptions> last_payment_request_options_;
+ raw_ptr<CollectUserDataOptions> payment_request_options_;
+ std::unique_ptr<UserData> payment_request_info_;
+ ConfigureBottomSheetProto::PeekMode peek_mode_ =
+ ConfigureBottomSheetProto::HANDLE;
+ bool expand_or_collapse_updated_ = false;
+ bool expand_or_collapse_value_ = false;
+ bool expand_sheet_for_prompt_ = true;
+ std::unique_ptr<GenericUserInterfaceProto> persistent_generic_ui_;
+};
+
+} // namespace autofill_assistant
+
+#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_FAKE_SCRIPT_EXECUTOR_UI_DELEGATE_H_
diff --git a/chromium/components/autofill_assistant/browser/field_formatter_unittest.cc b/chromium/components/autofill_assistant/browser/field_formatter_unittest.cc
index 21a9eaab90d..a45180c290a 100644
--- a/chromium/components/autofill_assistant/browser/field_formatter_unittest.cc
+++ b/chromium/components/autofill_assistant/browser/field_formatter_unittest.cc
@@ -65,7 +65,6 @@ class FieldFormatterStateMapTest : public ::testing::Test {
/*pref_service=*/autofill_client_.GetPrefs(),
/*local_state=*/autofill_client_.GetPrefs(),
/*identity_manager=*/nullptr,
- /*client_profile_validator=*/nullptr,
/*history_service=*/nullptr,
/*strike_database=*/nullptr,
/*image_fetcher=*/nullptr,
diff --git a/chromium/components/autofill_assistant/browser/js_flow_executor.h b/chromium/components/autofill_assistant/browser/js_flow_executor.h
index 0cef5be223f..fdf999a1b8e 100644
--- a/chromium/components/autofill_assistant/browser/js_flow_executor.h
+++ b/chromium/components/autofill_assistant/browser/js_flow_executor.h
@@ -8,167 +8,37 @@
#include <memory>
#include <string>
#include "base/callback_forward.h"
-#include "base/memory/weak_ptr.h"
#include "base/values.h"
#include "components/autofill_assistant/browser/client_status.h"
-#include "components/autofill_assistant/browser/devtools/devtools_client.h"
namespace autofill_assistant {
-// Executes a JS flow in a sandbox JS context. The flow may request additional
-// native actions to be performed by its delegate.
+// Executes a JS flow. The flow may request additional native actions to be
+// performed by its delegate.
class JsFlowExecutor {
public:
class Delegate {
public:
virtual ~Delegate() = default;
- // Asks the delegate to run |native_action| and call |finished_callback|
- // when done. The contents of |native_action| depend on the JS script, but
- // will typically be a serialized protobuffer.
+ // Asks the delegate to run |action| and call |finished_callback| when done.
+ // |action| is a serialized proto whose type is defined by |action_id|.
virtual void RunNativeAction(
- std::unique_ptr<base::Value> native_action,
+ int action_id,
+ const std::string& action,
base::OnceCallback<void(const ClientStatus& result_status,
std::unique_ptr<base::Value> result_value)>
finished_callback) = 0;
};
- // |delegate| must outlive the JsFlowExecutor.
- JsFlowExecutor(content::WebContents* web_contents, Delegate* delegate);
- ~JsFlowExecutor();
- JsFlowExecutor(const JsFlowExecutor&) = delete;
- JsFlowExecutor& operator=(const JsFlowExecutor&) = delete;
+ virtual ~JsFlowExecutor() = default;
- // Starts executing |js_flow| in an isolated JS context. Once finished (or on
- // error), |result_callback| is invoked with the final result. In the case of
- // an uncaught exception during flow execution, the returned status may
- // contain a stack trace and additional information (limited to the sandbox).
- // Only one flow may run at a time.
- //
- // Flows may request additional native actions from the delegate, using the
- // following syntax:
- //
- // let [status, result] = await runNativeAction('request')
- //
- // - |status| is an int corresponding to a ProcessedActionStatusProto.
- // - [result] is a struct containing the result value, or an empty struct if
- // no result was returned. The specific contents depend on the
- // native action.
- // - |runNativeAction| is provided automatically and takes a single argument.
- // The type of the argument will depend on what the native
- // delegate expects, but will typically be a serialized
- // protobuffer.
- //
- // The flow result is one of the following, depending on the |js_flow|:
- // (1) ACTION_APPLIED and a base::Value dictionary containing the 'result' key
- // and value, as returned by the JS flow. Example for a one-liner js flow
- // 'return 12345':
- // {
- // "result": {
- // "description": "12345",
- // "type": "number",
- // "value": 12345
- // }
- // }
- // See the unit tests for further examples. Note: field names are
- // auto-generated by base::Value serializers.
- //
- // (2) UNEXPECTED_JS_ERROR in case of an execution error, along with a
- // base::Value dictionary containing the 'exceptionDetails' key and exception,
- // if available. Note that this exception originates from the sandbox JS
- // context. Example:
- // JS flow:
- // function doSomething(x) {
- // console.log('foobar says: ' + x);
- // throw new Error('Hello world!');
- // }
- // function entrypoint() {
- // doSomething('bla');
- // }
- // entrypoint();
- //
- // Returned exception details:
- // "exceptionDetails": {
- // "columnNumber": 0,
- // "exception": {
- // "className": "Error",
- // "description": "Error: Hello world!
- // at doSomething (<anonymous>:16:33)
- // at entrypoint (<anonymous>:19:27)
- // at <anonymous>:21:25
- // at <anonymous>:22:28",
- // "objectId": "-3968045700143737919.4.2",
- // "subtype": "error",
- // "type": "object"
- // },
- // "exceptionId": 2,
- // "lineNumber": 0,
- // "text": "Uncaught (in promise) Error: Hello world!"
- // }
- //
- // (3) UNEXPECTED_JS_ERROR and null in case of internal errors during script
- // execution (i.e., unrecoverable devtools errors). The status details may
- // contain additional information.
- void Start(
- const std::string& js_flow,
- base::OnceCallback<void(const ClientStatus&,
- std::unique_ptr<base::Value>)> result_callback);
-
- private:
- void InternalStart();
- void OnGetFrameTree(const DevtoolsClient::ReplyStatus& reply_status,
- std::unique_ptr<page::GetFrameTreeResult> result);
- void IsolatedWorldCreated(
- const DevtoolsClient::ReplyStatus& reply_status,
- std::unique_ptr<page::CreateIsolatedWorldResult> result);
- void RefreshNativeActionPromise();
- void OnNativeActionRequested(const DevtoolsClient::ReplyStatus& reply_status,
- std::unique_ptr<runtime::EvaluateResult> result);
- void OnNativeActionRequestActionRetrieved(
- const std::string& js_array_object_id,
- const DevtoolsClient::ReplyStatus& reply_status,
- std::unique_ptr<runtime::CallFunctionOnResult> result);
- void OnNativeActionRequestFulfillPromiseRetrieved(
- std::unique_ptr<base::Value> action_request,
- const DevtoolsClient::ReplyStatus& reply_status,
- std::unique_ptr<runtime::CallFunctionOnResult> result);
- void OnNativeActionFinished(const std::string& fulfill_promise_object_id,
- const ClientStatus& status,
- std::unique_ptr<base::Value> result);
- void OnFlowResumed(const DevtoolsClient::ReplyStatus& reply_status,
- std::unique_ptr<runtime::CallFunctionOnResult> result);
- void OnFlowFinished(const DevtoolsClient::ReplyStatus& reply_status,
- std::unique_ptr<runtime::EvaluateResult> result);
- void RunCallback(const ClientStatus& status,
- std::unique_ptr<base::Value> result_value);
-
- // Returns true if |reply_status| and |result| are ok. Else, stops the flow
- // and returns false.
- template <typename T>
- bool CheckResultAndStopOnError(
- const DevtoolsClient::ReplyStatus& reply_status,
- std::unique_ptr<T>& result,
- const char* file,
- int line) {
- ClientStatus status =
- CheckJavaScriptResult(reply_status, result.get(), file, line);
- if (!status.ok()) {
- RunCallback(status, (result != nullptr ? result->Serialize() : nullptr));
- return false;
- }
- return true;
- }
-
- Delegate* const delegate_;
- std::unique_ptr<DevtoolsClient> devtools_client_;
- int isolated_world_context_id_ = -1;
-
- // Only set during a flow.
- std::unique_ptr<std::string> js_flow_;
- base::OnceCallback<void(const ClientStatus&, std::unique_ptr<base::Value>)>
- callback_;
-
- base::WeakPtrFactory<JsFlowExecutor> weak_ptr_factory_{this};
+ // Runs the specified JS flow. Refer to the specific implementation for more
+ // details.
+ virtual void Start(const std::string& js_flow,
+ base::OnceCallback<void(const ClientStatus&,
+ std::unique_ptr<base::Value>)>
+ result_callback) = 0;
};
} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/js_flow_executor.cc b/chromium/components/autofill_assistant/browser/js_flow_executor_impl.cc
index 6f9252cde68..89cf585cbb5 100644
--- a/chromium/components/autofill_assistant/browser/js_flow_executor.cc
+++ b/chromium/components/autofill_assistant/browser/js_flow_executor_impl.cc
@@ -2,14 +2,23 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/autofill_assistant/browser/js_flow_executor.h"
+#include "components/autofill_assistant/browser/js_flow_executor_impl.h"
+#include "base/base64.h"
#include "base/json/json_writer.h"
#include "base/logging.h"
#include "base/strings/strcat.h"
+#include "components/autofill_assistant/browser/parse_jspb.h"
#include "components/autofill_assistant/browser/web/web_controller_util.h"
+namespace autofill_assistant {
namespace {
+// Messages must have a JSPB message ID starting with this prefix to be
+// parseable in JSPB wire format.
+//
+// Such a message ID is used to distinguish arrays from JSPB messages.
+constexpr char kMessageIdPrefix[] = "aa.msg";
+
// Initializes a |globalFlowState| variable on first run, and renews the
// promises that will let JS flows request native actions.
constexpr char kRunNativeAction[] = R"(
@@ -31,19 +40,39 @@ constexpr char kFulfillActionPromise[] = R"(
constexpr char kMainFrame[] = "";
+absl::optional<std::string> ConvertActionToBytes(const base::Value* action,
+ std::string* error_message) {
+ if (action == nullptr) {
+ *error_message = "Null value";
+ return absl::nullopt;
+ }
+ if (action->is_string()) {
+ std::string bytes;
+ // A base64-encoded string containing a serialized proto.
+ if (base::Base64Decode(action->GetString(), &bytes)) {
+ *error_message = "Invalid Base64-encoded string";
+ return bytes;
+ }
+ return absl::nullopt;
+ }
+ if (action->is_list()) {
+ // A JSON array containing a proto message in the JSPB wire format.
+ return ParseJspb(kMessageIdPrefix, *action, error_message);
+ }
+ *error_message = "Unexpected value type";
+ return absl::nullopt;
+}
} // namespace
-namespace autofill_assistant {
-
-JsFlowExecutor::JsFlowExecutor(content::WebContents* web_contents,
- Delegate* delegate)
+JsFlowExecutorImpl::JsFlowExecutorImpl(content::WebContents* web_contents,
+ Delegate* delegate)
: delegate_(delegate),
devtools_client_(std::make_unique<DevtoolsClient>(
content::DevToolsAgentHost::GetOrCreateFor(web_contents))) {}
-JsFlowExecutor::~JsFlowExecutor() = default;
+JsFlowExecutorImpl::~JsFlowExecutorImpl() = default;
-void JsFlowExecutor::Start(
+void JsFlowExecutorImpl::Start(
const std::string& js_flow,
base::OnceCallback<void(const ClientStatus&, std::unique_ptr<base::Value>)>
callback) {
@@ -57,14 +86,14 @@ void JsFlowExecutor::Start(
callback_ = std::move(callback);
if (isolated_world_context_id_ == -1) {
devtools_client_->GetPage()->GetFrameTree(
- kMainFrame, base::BindOnce(&JsFlowExecutor::OnGetFrameTree,
+ kMainFrame, base::BindOnce(&JsFlowExecutorImpl::OnGetFrameTree,
weak_ptr_factory_.GetWeakPtr()));
} else {
InternalStart();
}
}
-void JsFlowExecutor::OnGetFrameTree(
+void JsFlowExecutorImpl::OnGetFrameTree(
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<page::GetFrameTreeResult> result) {
if (!result) {
@@ -80,11 +109,11 @@ void JsFlowExecutor::OnGetFrameTree(
.SetFrameId(result->GetFrameTree()->GetFrame()->GetId())
.Build(),
kMainFrame,
- base::BindOnce(&JsFlowExecutor::IsolatedWorldCreated,
+ base::BindOnce(&JsFlowExecutorImpl::IsolatedWorldCreated,
weak_ptr_factory_.GetWeakPtr()));
}
-void JsFlowExecutor::IsolatedWorldCreated(
+void JsFlowExecutorImpl::IsolatedWorldCreated(
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<page::CreateIsolatedWorldResult> result) {
if (!result) {
@@ -99,7 +128,7 @@ void JsFlowExecutor::IsolatedWorldCreated(
InternalStart();
}
-void JsFlowExecutor::InternalStart() {
+void JsFlowExecutorImpl::InternalStart() {
DCHECK(isolated_world_context_id_ != -1);
DCHECK(callback_);
@@ -115,10 +144,11 @@ void JsFlowExecutor::InternalStart() {
// original js source.
js_flow_ = std::make_unique<std::string>(base::StrCat({
R"((async function() {
- function runNativeAction(native_action) {
+ function runNativeAction(native_action_id, native_action) {
return new Promise(
(fulfill, reject) => {
- globalFlowState.runNativeAction([native_action, fulfill])
+ globalFlowState.runNativeAction(
+ [{id: native_action_id, action: native_action}, fulfill])
}
)
}
@@ -135,11 +165,11 @@ void JsFlowExecutor::InternalStart() {
.SetContextId(isolated_world_context_id_)
.Build(),
kMainFrame,
- base::BindOnce(&JsFlowExecutor::OnFlowFinished,
+ base::BindOnce(&JsFlowExecutorImpl::OnFlowFinished,
weak_ptr_factory_.GetWeakPtr()));
}
-void JsFlowExecutor::RefreshNativeActionPromise() {
+void JsFlowExecutorImpl::RefreshNativeActionPromise() {
devtools_client_->GetRuntime()->Evaluate(
runtime::EvaluateParams::Builder()
.SetExpression(kRunNativeAction)
@@ -147,11 +177,11 @@ void JsFlowExecutor::RefreshNativeActionPromise() {
.SetContextId(isolated_world_context_id_)
.Build(),
kMainFrame,
- base::BindOnce(&JsFlowExecutor::OnNativeActionRequested,
+ base::BindOnce(&JsFlowExecutorImpl::OnNativeActionRequested,
weak_ptr_factory_.GetWeakPtr()));
}
-void JsFlowExecutor::OnNativeActionRequested(
+void JsFlowExecutorImpl::OnNativeActionRequested(
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::EvaluateResult> result) {
if (!CheckResultAndStopOnError(reply_status, result, __FILE__, __LINE__)) {
@@ -168,13 +198,14 @@ void JsFlowExecutor::OnNativeActionRequested(
.SetObjectId(js_array_object_id)
.SetArguments(std::move(arguments))
.SetFunctionDeclaration(std::string(kArrayGetNthElement))
+ .SetReturnByValue(true)
.Build(),
kMainFrame,
- base::BindOnce(&JsFlowExecutor::OnNativeActionRequestActionRetrieved,
+ base::BindOnce(&JsFlowExecutorImpl::OnNativeActionRequestActionRetrieved,
weak_ptr_factory_.GetWeakPtr(), js_array_object_id));
}
-void JsFlowExecutor::OnNativeActionRequestActionRetrieved(
+void JsFlowExecutorImpl::OnNativeActionRequestActionRetrieved(
const std::string& js_array_object_id,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::CallFunctionOnResult> result) {
@@ -184,18 +215,9 @@ void JsFlowExecutor::OnNativeActionRequestActionRetrieved(
auto* remote_object = result->GetResult();
if (!remote_object->HasValue()) {
- ClientStatus status(UNEXPECTED_JS_ERROR);
- auto* details = status.mutable_details()->mutable_unexpected_error_info();
- details->set_source_file(__FILE__);
- details->set_source_line_number(__LINE__);
-
- std::string stringified_result;
- base::JSONWriter::Write(*remote_object->Serialize(), &stringified_result);
- details->set_devtools_error_message(
- base::StrCat({"runNativeAction expected single JSON-compatible "
- "argument, but was called with ",
- stringified_result}));
- RunCallback(status, nullptr);
+ // This shouldn't be possible, as the argument is built by
+ // JsFlowExecutorImpl::InternalStart()
+ RunCallback(UnexpectedErrorStatus(__FILE__, __LINE__), nullptr);
return;
}
@@ -209,11 +231,12 @@ void JsFlowExecutor::OnNativeActionRequestActionRetrieved(
.Build(),
kMainFrame,
base::BindOnce(
- &JsFlowExecutor::OnNativeActionRequestFulfillPromiseRetrieved,
- weak_ptr_factory_.GetWeakPtr(), remote_object->Serialize()));
+ &JsFlowExecutorImpl::OnNativeActionRequestFulfillPromiseRetrieved,
+ weak_ptr_factory_.GetWeakPtr(),
+ base::Value::ToUniquePtrValue(remote_object->GetValue()->Clone())));
}
-void JsFlowExecutor::OnNativeActionRequestFulfillPromiseRetrieved(
+void JsFlowExecutorImpl::OnNativeActionRequestFulfillPromiseRetrieved(
std::unique_ptr<base::Value> action_request,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::CallFunctionOnResult> result) {
@@ -226,24 +249,40 @@ void JsFlowExecutor::OnNativeActionRequestFulfillPromiseRetrieved(
if (!fulfill_promise_object->HasObjectId()) {
// This should never happen, since the fulfill promise is programmatically
// provided.
- ClientStatus status(OTHER_ACTION_STATUS);
- auto* details = status.mutable_details()->mutable_unexpected_error_info();
- details->set_source_file(__FILE__);
- details->set_source_line_number(__LINE__);
- details->set_devtools_error_message(
- "Native action requested, but no fulfill promise provided");
- RunCallback(status, nullptr);
+ RunCallback(UnexpectedErrorStatus(__FILE__, __LINE__), nullptr);
return;
}
+ absl::optional<int> id;
+ base::Value* action = nullptr;
+ if (action_request->is_dict()) {
+ id = action_request->FindIntKey("id");
+ action = action_request->FindKey("action");
+ }
+ if (!id) {
+ DVLOG(1) << "id passed to runNativeAction(id, action) is not a number in "
+ << action_request->DebugString();
+ RunCallback(ClientStatus(INVALID_ACTION), nullptr);
+ return;
+ }
+ std::string error_message;
+ absl::optional<std::string> action_bytes =
+ ConvertActionToBytes(action, &error_message);
+ if (!action_bytes) {
+ DVLOG(1) << "action passed to runNativeAction(id, action) cannot "
+ << "be parsed: " << error_message << " in "
+ << action_request->DebugString();
+ RunCallback(ClientStatus(INVALID_ACTION), nullptr);
+ return;
+ }
delegate_->RunNativeAction(
- std::move(action_request),
- base::BindOnce(&JsFlowExecutor::OnNativeActionFinished,
+ *id, *action_bytes,
+ base::BindOnce(&JsFlowExecutorImpl::OnNativeActionFinished,
weak_ptr_factory_.GetWeakPtr(),
fulfill_promise_object->GetObjectId()));
}
-void JsFlowExecutor::OnNativeActionFinished(
+void JsFlowExecutorImpl::OnNativeActionFinished(
const std::string& fulfill_promise_object_id,
const ClientStatus& result_status,
std::unique_ptr<base::Value> result_value) {
@@ -272,11 +311,11 @@ void JsFlowExecutor::OnNativeActionFinished(
.SetFunctionDeclaration(std::string(kFulfillActionPromise))
.Build(),
kMainFrame,
- base::BindOnce(&JsFlowExecutor::OnFlowResumed,
+ base::BindOnce(&JsFlowExecutorImpl::OnFlowResumed,
weak_ptr_factory_.GetWeakPtr()));
}
-void JsFlowExecutor::OnFlowResumed(
+void JsFlowExecutorImpl::OnFlowResumed(
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::CallFunctionOnResult> result) {
// This should never fail, but if it does, we need to catch it here to prevent
@@ -286,7 +325,7 @@ void JsFlowExecutor::OnFlowResumed(
}
}
-void JsFlowExecutor::OnFlowFinished(
+void JsFlowExecutorImpl::OnFlowFinished(
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::EvaluateResult> result) {
// Note that the result is always serialized if available, not just if the
@@ -296,8 +335,9 @@ void JsFlowExecutor::OnFlowFinished(
(result != nullptr ? result->Serialize() : nullptr));
}
-void JsFlowExecutor::RunCallback(const ClientStatus& status,
- std::unique_ptr<base::Value> result_value) {
+void JsFlowExecutorImpl::RunCallback(
+ const ClientStatus& status,
+ std::unique_ptr<base::Value> result_value) {
if (!status.ok() && result_value) {
DVLOG(1) << "Flow failed with " << status
<< " and result: " << *result_value;
diff --git a/chromium/components/autofill_assistant/browser/js_flow_executor_impl.h b/chromium/components/autofill_assistant/browser/js_flow_executor_impl.h
new file mode 100644
index 00000000000..01adddc4097
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/js_flow_executor_impl.h
@@ -0,0 +1,168 @@
+// Copyright 2021 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.
+
+#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_JS_FLOW_EXECUTOR_IMPL_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_JS_FLOW_EXECUTOR_IMPL_H_
+
+#include <memory>
+#include <string>
+#include "base/callback_forward.h"
+#include "base/memory/weak_ptr.h"
+#include "base/values.h"
+#include "components/autofill_assistant/browser/client_status.h"
+#include "components/autofill_assistant/browser/devtools/devtools_client.h"
+#include "components/autofill_assistant/browser/js_flow_executor.h"
+
+namespace autofill_assistant {
+
+// Executes a JS flow in a sandbox JS context. The flow may request additional
+// native actions to be performed by its delegate.
+class JsFlowExecutorImpl : public JsFlowExecutor {
+ public:
+ // |delegate| must outlive the JsFlowExecutorImpl.
+ JsFlowExecutorImpl(content::WebContents* web_contents, Delegate* delegate);
+ ~JsFlowExecutorImpl() override;
+ JsFlowExecutorImpl(const JsFlowExecutorImpl&) = delete;
+ JsFlowExecutorImpl& operator=(const JsFlowExecutorImpl&) = delete;
+
+ // Starts executing |js_flow| in an isolated JS context. Once finished (or on
+ // error), |result_callback| is invoked with the final result. In the case of
+ // an uncaught exception during flow execution, the returned status may
+ // contain a stack trace and additional information (limited to the sandbox).
+ // Only one flow may run at a time.
+ //
+ // Flows may request additional native actions from the delegate, using the
+ // following syntax:
+ //
+ // let [status, result] = await runNativeAction(id, action)
+ //
+ // - [id] is a field tag number in the ActionProto.action_info oneof
+ // - [action] is a string containing a base64-encoded serialized proto of the
+ // type appropriate for [id]. It can also be a JSON array
+ // containing a proto in the JSPB wire format, though this comes
+ // with severe limitations and will not work for all protos. See
+ // parse_jspb.h for details.
+ // - |status| is an int corresponding to a ProcessedActionStatusProto.
+ // - [result] is a struct containing the result value, or an empty struct if
+ // no result was returned. The specific contents depend on the
+ // native action.
+ //
+ // The function runNativeAction() is guaranteed to be available when the
+ // JavaScript snippet |js_flow| is run.
+ //
+ // The flow result is one of the following, depending on the |js_flow|:
+ // (1) ACTION_APPLIED and a base::Value dictionary containing the 'result' key
+ // and value, as returned by the JS flow. Example for a one-liner js flow
+ // 'return 12345':
+ // {
+ // "result": {
+ // "description": "12345",
+ // "type": "number",
+ // "value": 12345
+ // }
+ // }
+ // See the unit tests for further examples. Note: field names are
+ // auto-generated by base::Value serializers.
+ //
+ // (2) UNEXPECTED_JS_ERROR in case of an execution error, along with a
+ // base::Value dictionary containing the 'exceptionDetails' key and exception,
+ // if available. Note that this exception originates from the sandbox JS
+ // context. Example:
+ // JS flow:
+ // function doSomething(x) {
+ // console.log('foobar says: ' + x);
+ // throw new Error('Hello world!');
+ // }
+ // function entrypoint() {
+ // doSomething('bla');
+ // }
+ // entrypoint();
+ //
+ // Returned exception details:
+ // "exceptionDetails": {
+ // "columnNumber": 0,
+ // "exception": {
+ // "className": "Error",
+ // "description": "Error: Hello world!
+ // at doSomething (<anonymous>:16:33)
+ // at entrypoint (<anonymous>:19:27)
+ // at <anonymous>:21:25
+ // at <anonymous>:22:28",
+ // "objectId": "-3968045700143737919.4.2",
+ // "subtype": "error",
+ // "type": "object"
+ // },
+ // "exceptionId": 2,
+ // "lineNumber": 0,
+ // "text": "Uncaught (in promise) Error: Hello world!"
+ // }
+ //
+ // (3) UNEXPECTED_JS_ERROR and null in case of internal errors during script
+ // execution (i.e., unrecoverable devtools errors). The status details may
+ // contain additional information.
+ void Start(const std::string& js_flow,
+ base::OnceCallback<void(const ClientStatus&,
+ std::unique_ptr<base::Value>)>
+ result_callback) override;
+
+ private:
+ void InternalStart();
+ void OnGetFrameTree(const DevtoolsClient::ReplyStatus& reply_status,
+ std::unique_ptr<page::GetFrameTreeResult> result);
+ void IsolatedWorldCreated(
+ const DevtoolsClient::ReplyStatus& reply_status,
+ std::unique_ptr<page::CreateIsolatedWorldResult> result);
+ void RefreshNativeActionPromise();
+ void OnNativeActionRequested(const DevtoolsClient::ReplyStatus& reply_status,
+ std::unique_ptr<runtime::EvaluateResult> result);
+ void OnNativeActionRequestActionRetrieved(
+ const std::string& js_array_object_id,
+ const DevtoolsClient::ReplyStatus& reply_status,
+ std::unique_ptr<runtime::CallFunctionOnResult> result);
+ void OnNativeActionRequestFulfillPromiseRetrieved(
+ std::unique_ptr<base::Value> action_request,
+ const DevtoolsClient::ReplyStatus& reply_status,
+ std::unique_ptr<runtime::CallFunctionOnResult> result);
+ void OnNativeActionFinished(const std::string& fulfill_promise_object_id,
+ const ClientStatus& status,
+ std::unique_ptr<base::Value> result);
+ void OnFlowResumed(const DevtoolsClient::ReplyStatus& reply_status,
+ std::unique_ptr<runtime::CallFunctionOnResult> result);
+ void OnFlowFinished(const DevtoolsClient::ReplyStatus& reply_status,
+ std::unique_ptr<runtime::EvaluateResult> result);
+ void RunCallback(const ClientStatus& status,
+ std::unique_ptr<base::Value> result_value);
+
+ // Returns true if |reply_status| and |result| are ok. Else, stops the flow
+ // and returns false.
+ template <typename T>
+ bool CheckResultAndStopOnError(
+ const DevtoolsClient::ReplyStatus& reply_status,
+ std::unique_ptr<T>& result,
+ const char* file,
+ int line) {
+ ClientStatus status =
+ CheckJavaScriptResult(reply_status, result.get(), file, line);
+ if (!status.ok()) {
+ RunCallback(status, (result != nullptr ? result->Serialize() : nullptr));
+ return false;
+ }
+ return true;
+ }
+
+ Delegate* const delegate_;
+ std::unique_ptr<DevtoolsClient> devtools_client_;
+ int isolated_world_context_id_ = -1;
+
+ // Only set during a flow.
+ std::unique_ptr<std::string> js_flow_;
+ base::OnceCallback<void(const ClientStatus&, std::unique_ptr<base::Value>)>
+ callback_;
+
+ base::WeakPtrFactory<JsFlowExecutorImpl> weak_ptr_factory_{this};
+};
+
+} // namespace autofill_assistant
+
+#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_JS_FLOW_EXECUTOR_IMPL_H_
diff --git a/chromium/components/autofill_assistant/browser/js_flow_executor_unittest.cc b/chromium/components/autofill_assistant/browser/js_flow_executor_impl_browsertest.cc
index 6760df25974..f04aa9995d9 100644
--- a/chromium/components/autofill_assistant/browser/js_flow_executor_unittest.cc
+++ b/chromium/components/autofill_assistant/browser/js_flow_executor_impl_browsertest.cc
@@ -3,26 +3,31 @@
// found in the LICENSE file.
#include "components/autofill_assistant/browser/js_flow_executor.h"
+
+#include <iosfwd>
+#include <memory>
+#include <string>
+#include <type_traits>
+
+#include "base/bind.h"
#include "base/callback.h"
+#include "base/callback_forward.h"
#include "base/json/json_reader.h"
+#include "base/run_loop.h"
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
#include "base/test/gmock_callback_support.h"
-#include "base/test/mock_callback.h"
-#include "base/test/task_environment.h"
-#include "base/time/tick_clock.h"
-#include "content/public/test/browser_task_environment.h"
+#include "base/values.h"
+#include "components/autofill_assistant/browser/base_browsertest.h"
+#include "components/autofill_assistant/browser/client_status.h"
+#include "components/autofill_assistant/browser/js_flow_executor_impl.h"
+#include "components/autofill_assistant/browser/model.pb.h"
+#include "components/autofill_assistant/browser/service.pb.h"
#include "content/public/test/browser_test.h"
-#include "content/public/test/browser_test_utils.h"
-#include "content/public/test/content_browser_test.h"
-#include "content/public/test/content_browser_test_utils.h"
-#include "content/public/test/test_browser_context.h"
-#include "content/public/test/test_renderer_host.h"
-#include "content/public/test/web_contents_tester.h"
#include "content/shell/browser/shell.h"
#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
-#include "third_party/blink/public/common/switches.h"
namespace autofill_assistant {
namespace {
@@ -39,61 +44,31 @@ using ::testing::Property;
using ::testing::SizeIs;
using ::testing::WithArg;
-// Parses |json| as a base::Value. No error handling - this will crash for
-// invalid json inputs.
-std::unique_ptr<base::Value> UniqueValueFromJson(const std::string& json) {
- return std::make_unique<base::Value>(
- std::move(*base::JSONReader::Read(json)));
-}
-
-class MockJsFlowExecutorDelegate : public JsFlowExecutor::Delegate {
+class MockJsFlowExecutorImplDelegate : public JsFlowExecutorImpl::Delegate {
public:
- MockJsFlowExecutorDelegate() = default;
- ~MockJsFlowExecutorDelegate() override = default;
+ MockJsFlowExecutorImplDelegate() = default;
+ ~MockJsFlowExecutorImplDelegate() override = default;
MOCK_METHOD(
void,
RunNativeAction,
- (std::unique_ptr<base::Value> native_action,
+ (int,
+ const std::string&,
base::OnceCallback<void(const ClientStatus& result_status,
std::unique_ptr<base::Value> result_value)>
callback),
(override));
};
-class JsFlowExecutorTest : public content::ContentBrowserTest {
+class JsFlowExecutorImplTest : public autofill_assistant::BaseBrowserTest {
public:
- JsFlowExecutorTest() {}
-
- void SetUpCommandLine(base::CommandLine* command_line) override {
- command_line->AppendSwitch("site-per-process");
- // Necessary to avoid flakiness or failure due to input arriving
- // before the first compositor commit.
- command_line->AppendSwitch(blink::switches::kAllowPreCommitInput);
- }
+ JsFlowExecutorImplTest() {}
void SetUpOnMainThread() override {
- ContentBrowserTest::SetUpOnMainThread();
-
- // Start a mock server for hosting an OOPIF.
- http_server_iframe_ = std::make_unique<net::EmbeddedTestServer>(
- net::EmbeddedTestServer::TYPE_HTTP);
- http_server_iframe_->ServeFilesFromSourceDirectory(
- "components/test/data/autofill_assistant/html_iframe");
- ASSERT_TRUE(http_server_iframe_->Start(8081));
-
- // Start the main server hosting the test page.
- http_server_ = std::make_unique<net::EmbeddedTestServer>(
- net::EmbeddedTestServer::TYPE_HTTP);
- http_server_->ServeFilesFromSourceDirectory(
- "components/test/data/autofill_assistant/html");
- ASSERT_TRUE(http_server_->Start(8080));
- ASSERT_TRUE(NavigateToURL(
- shell(),
- http_server_->GetURL("/autofill_assistant_target_website.html")));
-
- flow_executor_ = std::make_unique<JsFlowExecutor>(shell()->web_contents(),
- &mock_delegate_);
+ BaseBrowserTest::SetUpOnMainThread();
+
+ flow_executor_ = std::make_unique<JsFlowExecutorImpl>(
+ shell()->web_contents(), &mock_delegate_);
}
// Overload, ignore result value, just return the client status.
@@ -107,7 +82,7 @@ class JsFlowExecutorTest : public content::ContentBrowserTest {
ClientStatus status;
base::RunLoop run_loop;
flow_executor_->Start(
- js_flow, base::BindOnce(&JsFlowExecutorTest::OnFlowFinished,
+ js_flow, base::BindOnce(&JsFlowExecutorImplTest::OnFlowFinished,
base::Unretained(this), run_loop.QuitClosure(),
&status, std::ref(result_value)));
run_loop.Run();
@@ -125,23 +100,21 @@ class JsFlowExecutorTest : public content::ContentBrowserTest {
}
protected:
- NiceMock<MockJsFlowExecutorDelegate> mock_delegate_;
- std::unique_ptr<JsFlowExecutor> flow_executor_;
- std::unique_ptr<net::EmbeddedTestServer> http_server_;
- std::unique_ptr<net::EmbeddedTestServer> http_server_iframe_;
+ NiceMock<MockJsFlowExecutorImplDelegate> mock_delegate_;
+ std::unique_ptr<JsFlowExecutorImpl> flow_executor_;
};
-IN_PROC_BROWSER_TEST_F(JsFlowExecutorTest, SmokeTest) {
+IN_PROC_BROWSER_TEST_F(JsFlowExecutorImplTest, SmokeTest) {
EXPECT_THAT(RunTest(std::string()),
Property(&ClientStatus::proto_status, ACTION_APPLIED));
}
-IN_PROC_BROWSER_TEST_F(JsFlowExecutorTest, InvalidJs) {
+IN_PROC_BROWSER_TEST_F(JsFlowExecutorImplTest, InvalidJs) {
EXPECT_THAT(RunTest("Not valid Javascript"),
Property(&ClientStatus::proto_status, UNEXPECTED_JS_ERROR));
}
-IN_PROC_BROWSER_TEST_F(JsFlowExecutorTest, RunNativeActionWithReturnValue) {
+IN_PROC_BROWSER_TEST_F(JsFlowExecutorImplTest, RunNativeActionWithReturnValue) {
std::unique_ptr<base::Value> native_return_value =
std::make_unique<base::Value>(std::move(*base::JSONReader::Read(
R"(
@@ -159,17 +132,17 @@ IN_PROC_BROWSER_TEST_F(JsFlowExecutorTest, RunNativeActionWithReturnValue) {
)")));
EXPECT_CALL(mock_delegate_, RunNativeAction)
- .WillOnce([&](auto value, auto callback) {
- EXPECT_EQ(*value, *UniqueValueFromJson(R"(
- {"type":"string",
- "value":"test"})"));
+ .WillOnce([&](int action_id, const std::string& action, auto callback) {
+ EXPECT_EQ(12, action_id);
+ EXPECT_EQ("test", action);
std::move(callback).Run(ClientStatus(ACTION_APPLIED),
std::move(native_return_value));
});
std::unique_ptr<base::Value> js_return_value;
EXPECT_THAT(RunTest(R"(
- let [status, value] = await runNativeAction('test');
+ let [status, value] = await runNativeAction(
+ 12, "dGVzdA==" /*test*/);
if (status != 2) { // ACTION_APPLIED
return status;
}
@@ -200,18 +173,72 @@ IN_PROC_BROWSER_TEST_F(JsFlowExecutorTest, RunNativeActionWithReturnValue) {
)"));
}
-IN_PROC_BROWSER_TEST_F(JsFlowExecutorTest, RunMultipleNativeActions) {
+IN_PROC_BROWSER_TEST_F(JsFlowExecutorImplTest, RunNativeActionAsBase64String) {
+ EXPECT_CALL(mock_delegate_, RunNativeAction)
+ .WillOnce([&](int action_id, const std::string& action, auto callback) {
+ EXPECT_EQ(12, action_id);
+ EXPECT_EQ("test", action);
+ std::move(callback).Run(ClientStatus(ACTION_APPLIED), nullptr);
+ });
+
+ std::unique_ptr<base::Value> result;
+ EXPECT_THAT(RunTest(R"(
+ let [status, value] = await runNativeAction(12, "dGVzdA==" /*test*/);
+ return status;
+ )",
+ result),
+ Property(&ClientStatus::proto_status, ACTION_APPLIED));
+ EXPECT_EQ(*result, *base::JSONReader::Read(R"(
+ {
+ "result": {
+ "description": "2",
+ "type": "number",
+ "value": 2
+ }
+ }
+ )"));
+}
+
+IN_PROC_BROWSER_TEST_F(JsFlowExecutorImplTest,
+ RunNativeActionAsSerializedProto) {
+ EXPECT_CALL(mock_delegate_, RunNativeAction)
+ .WillOnce([&](int action_id, const std::string& action, auto callback) {
+ EXPECT_EQ(ActionProto::kTell, action_id);
+ TellProto tell;
+ EXPECT_TRUE(tell.ParseFromString(action));
+ EXPECT_EQ(tell.message(), "my message");
+ std::move(callback).Run(ClientStatus(ACTION_APPLIED), nullptr);
+ });
+
+ std::unique_ptr<base::Value> result;
+ EXPECT_THAT(RunTest(R"(
+ let [status, value] = await runNativeAction(
+ 11, ["aa.msg", "my message"]);
+ return status;
+ )",
+ result),
+ Property(&ClientStatus::proto_status, ACTION_APPLIED));
+ EXPECT_EQ(*result, *base::JSONReader::Read(R"(
+ {
+ "result": {
+ "description": "2",
+ "type": "number",
+ "value": 2
+ }
+ }
+ )"));
+}
+
+IN_PROC_BROWSER_TEST_F(JsFlowExecutorImplTest, RunMultipleNativeActions) {
EXPECT_CALL(mock_delegate_, RunNativeAction)
- .WillOnce([&](auto value, auto callback) {
- EXPECT_EQ(*value, *UniqueValueFromJson(R"(
- {"type":"string",
- "value":"test1"})"));
+ .WillOnce([&](int action_id, const std::string& action, auto callback) {
+ EXPECT_EQ(1, action_id);
+ EXPECT_EQ("test1", action);
std::move(callback).Run(ClientStatus(ACTION_APPLIED), nullptr);
})
- .WillOnce([&](auto value, auto callback) {
- EXPECT_EQ(*value, *UniqueValueFromJson(R"(
- {"type":"string",
- "value":"test2"})"));
+ .WillOnce([&](int action_id, const std::string& action, auto callback) {
+ EXPECT_EQ(2, action_id);
+ EXPECT_EQ("test2", action);
std::move(callback).Run(ClientStatus(OTHER_ACTION_STATUS), nullptr);
});
@@ -220,9 +247,11 @@ IN_PROC_BROWSER_TEST_F(JsFlowExecutorTest, RunMultipleNativeActions) {
// OTHER_ACTION_STATUS, i.e., 3.
std::unique_ptr<base::Value> result;
EXPECT_THAT(RunTest(R"(
- let [status, value] = await runNativeAction('test1');
+ let [status, value] = await runNativeAction(
+ 1, "dGVzdDE=" /*test1*/);
if (status == 2) { // ACTION_APPLIED
- [status, value] = await runNativeAction('test2');
+ [status, value] = await runNativeAction(
+ 2, "dGVzdDI=" /*test2*/);
}
return status;
)",
@@ -239,7 +268,7 @@ IN_PROC_BROWSER_TEST_F(JsFlowExecutorTest, RunMultipleNativeActions) {
)"));
}
-IN_PROC_BROWSER_TEST_F(JsFlowExecutorTest, ReturnInteger) {
+IN_PROC_BROWSER_TEST_F(JsFlowExecutorImplTest, ReturnInteger) {
std::unique_ptr<base::Value> result;
ClientStatus status = RunTest("return 12345;", result);
EXPECT_EQ(status.proto_status(), ACTION_APPLIED);
@@ -254,7 +283,7 @@ IN_PROC_BROWSER_TEST_F(JsFlowExecutorTest, ReturnInteger) {
)"));
}
-IN_PROC_BROWSER_TEST_F(JsFlowExecutorTest, ReturnString) {
+IN_PROC_BROWSER_TEST_F(JsFlowExecutorImplTest, ReturnString) {
std::unique_ptr<base::Value> result;
ClientStatus status = RunTest("return 'Hello world!';", result);
EXPECT_EQ(status.proto_status(), ACTION_APPLIED);
@@ -268,7 +297,7 @@ IN_PROC_BROWSER_TEST_F(JsFlowExecutorTest, ReturnString) {
)"));
}
-IN_PROC_BROWSER_TEST_F(JsFlowExecutorTest, ReturnDictionary) {
+IN_PROC_BROWSER_TEST_F(JsFlowExecutorImplTest, ReturnDictionary) {
std::unique_ptr<base::Value> result;
ClientStatus status = RunTest(
R"(
@@ -306,7 +335,7 @@ IN_PROC_BROWSER_TEST_F(JsFlowExecutorTest, ReturnDictionary) {
)"));
}
-IN_PROC_BROWSER_TEST_F(JsFlowExecutorTest, ReturnNothing) {
+IN_PROC_BROWSER_TEST_F(JsFlowExecutorImplTest, ReturnNothing) {
std::unique_ptr<base::Value> result;
ClientStatus status = RunTest("", result);
EXPECT_EQ(status.proto_status(), ACTION_APPLIED);
@@ -319,7 +348,7 @@ IN_PROC_BROWSER_TEST_F(JsFlowExecutorTest, ReturnNothing) {
)"));
}
-IN_PROC_BROWSER_TEST_F(JsFlowExecutorTest, ReturnNull) {
+IN_PROC_BROWSER_TEST_F(JsFlowExecutorImplTest, ReturnNull) {
std::unique_ptr<base::Value> result;
ClientStatus status = RunTest("return null;", result);
EXPECT_EQ(status.proto_status(), ACTION_APPLIED);
@@ -334,7 +363,7 @@ IN_PROC_BROWSER_TEST_F(JsFlowExecutorTest, ReturnNull) {
)"));
}
-IN_PROC_BROWSER_TEST_F(JsFlowExecutorTest, ExceptionReporting) {
+IN_PROC_BROWSER_TEST_F(JsFlowExecutorImplTest, ExceptionReporting) {
std::unique_ptr<base::Value> result;
ClientStatus status = RunTest("throw new Error('Hello world!');", result);
EXPECT_EQ(status.proto_status(), UNEXPECTED_JS_ERROR);
@@ -368,7 +397,7 @@ IN_PROC_BROWSER_TEST_F(JsFlowExecutorTest, ExceptionReporting) {
EXPECT_THAT(exceptionDetails->ExtractKey("exception"), Ne(absl::nullopt));
}
-IN_PROC_BROWSER_TEST_F(JsFlowExecutorTest, RunMultipleConsecutiveFlows) {
+IN_PROC_BROWSER_TEST_F(JsFlowExecutorImplTest, RunMultipleConsecutiveFlows) {
for (int i = 0; i < 10; ++i) {
std::unique_ptr<base::Value> result;
ClientStatus status =
@@ -378,26 +407,39 @@ IN_PROC_BROWSER_TEST_F(JsFlowExecutorTest, RunMultipleConsecutiveFlows) {
}
}
-IN_PROC_BROWSER_TEST_F(JsFlowExecutorTest,
- UnserializableRunNativeActionArgument) {
+IN_PROC_BROWSER_TEST_F(JsFlowExecutorImplTest,
+ UnserializableRunNativeActionString) {
std::unique_ptr<base::Value> result;
EXPECT_CALL(mock_delegate_, RunNativeAction).Times(0);
ClientStatus status = RunTest(
R"(
- function foo(){}
- // foo cannot be serialized as a JSON object, so this should fail.
- let [status, result] = await runNativeAction(foo);
+ // {} is not a string or an array, so this should fail.
+ let [status, result] = await runNativeAction(1, {});
return status;
)",
result);
EXPECT_EQ(result, nullptr);
- EXPECT_EQ(status.proto_status(), UNEXPECTED_JS_ERROR);
- EXPECT_TRUE(status.details().has_unexpected_error_info());
+ EXPECT_EQ(status.proto_status(), INVALID_ACTION);
+}
+
+IN_PROC_BROWSER_TEST_F(JsFlowExecutorImplTest,
+ UnserializableRunNativeActionId) {
+ std::unique_ptr<base::Value> result;
+ EXPECT_CALL(mock_delegate_, RunNativeAction).Times(0);
+ ClientStatus status = RunTest(
+ R"(
+ // {} is not a number, so this should fail.
+ let [status, result] = await runNativeAction({}, "");
+ return status;
+ )",
+ result);
+ EXPECT_EQ(result, nullptr);
+ EXPECT_EQ(status.proto_status(), INVALID_ACTION);
}
-IN_PROC_BROWSER_TEST_F(JsFlowExecutorTest, StartWhileAlreadyRunningFails) {
+IN_PROC_BROWSER_TEST_F(JsFlowExecutorImplTest, StartWhileAlreadyRunningFails) {
EXPECT_CALL(mock_delegate_, RunNativeAction)
- .WillOnce(WithArg<1>([&](auto callback) {
+ .WillOnce(WithArg<2>([&](auto callback) {
// Starting a second flow while the first one is running should fail.
EXPECT_EQ(RunTest(std::string()).proto_status(), INVALID_ACTION);
@@ -408,7 +450,7 @@ IN_PROC_BROWSER_TEST_F(JsFlowExecutorTest, StartWhileAlreadyRunningFails) {
std::unique_ptr<base::Value> result;
ClientStatus status = RunTest(
R"(
- let [status, result] = await runNativeAction('');
+ let [status, result] = await runNativeAction(1, "dGVzdA==" /*test*/);
return status;
)",
result);
@@ -424,7 +466,8 @@ IN_PROC_BROWSER_TEST_F(JsFlowExecutorTest, StartWhileAlreadyRunningFails) {
)"));
}
-IN_PROC_BROWSER_TEST_F(JsFlowExecutorTest, EnvironmentIsPreservedBetweenRuns) {
+IN_PROC_BROWSER_TEST_F(JsFlowExecutorImplTest,
+ EnvironmentIsPreservedBetweenRuns) {
EXPECT_EQ(RunTest("globalFlowState.i = 5;").proto_status(), ACTION_APPLIED);
std::unique_ptr<base::Value> result;
diff --git a/chromium/components/autofill_assistant/browser/metrics.cc b/chromium/components/autofill_assistant/browser/metrics.cc
index 210a64912ab..7222d3ca3d9 100644
--- a/chromium/components/autofill_assistant/browser/metrics.cc
+++ b/chromium/components/autofill_assistant/browser/metrics.cc
@@ -43,6 +43,8 @@ const char kPaymentRequestFirstNameOnly[] =
"Android.AutofillAssistant.PaymentRequest.FirstNameOnly";
const char kDependenciesInvalidated[] =
"Android.AutofillAssistant.DependenciesInvalidated";
+const char kOnboardingFetcherResultStatus[] =
+ "Android.AutofillAssistant.OnboardingFetcher.ResultStatus";
static bool DROPOUT_RECORDED = false;
std::string GetSuffixForIntent(const std::string& intent) {
@@ -442,6 +444,7 @@ void Metrics::RecordShippingMetrics(ukm::UkmRecorder* ukm_recorder,
.Record(ukm_recorder);
}
+// static
void Metrics::RecordCollectUserDataSuccess(ukm::UkmRecorder* ukm_recorder,
ukm::SourceId source_id,
bool success,
@@ -454,4 +457,11 @@ void Metrics::RecordCollectUserDataSuccess(ukm::UkmRecorder* ukm_recorder,
.Record(ukm_recorder);
}
+// static
+void Metrics::RecordOnboardingFetcherResult(
+ OnboardingFetcherResultStatus status) {
+ DCHECK_LE(status, OnboardingFetcherResultStatus::kMaxValue);
+ base::UmaHistogramEnumeration(kOnboardingFetcherResultStatus, status);
+}
+
} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/metrics.h b/chromium/components/autofill_assistant/browser/metrics.h
index b473141c02a..565a1dc60b4 100644
--- a/chromium/components/autofill_assistant/browser/metrics.h
+++ b/chromium/components/autofill_assistant/browser/metrics.h
@@ -609,6 +609,21 @@ class Metrics {
VALID_NUMBER = 1 << 5,
};
+ // This enum is used in histograms, do not remove/renumber entries. Only add
+ // at the end and update kMaxValue. Also remember to update the
+ // AutofillAssistantOnboardingFetcherResultStatus enum listing in
+ // tools/metrics/histograms/enums.xml.
+ enum class OnboardingFetcherResultStatus {
+ kOk = 0,
+ // No body was received from the server.
+ kNoBody = 1,
+ // Parsing the JSON failed.
+ kInvalidJson = 1,
+ // The JSON was not in the form we expected it to be.
+ kInvalidData = 2,
+ kMaxValue = kInvalidData
+ };
+
static void RecordDropOut(DropOutReason reason, const std::string& intent);
static void RecordPaymentRequestPrefilledSuccess(bool initially_complete,
bool success);
@@ -680,6 +695,8 @@ class Metrics {
ukm::SourceId source_id,
bool success,
int64_t time_taken_ms);
+ static void RecordOnboardingFetcherResult(
+ OnboardingFetcherResultStatus status);
// Intended for debugging: writes string representation of |reason| to
// |out|.
diff --git a/chromium/components/autofill_assistant/browser/mock_client.h b/chromium/components/autofill_assistant/browser/mock_client.h
index 102071c4e48..028077a2149 100644
--- a/chromium/components/autofill_assistant/browser/mock_client.h
+++ b/chromium/components/autofill_assistant/browser/mock_client.h
@@ -17,6 +17,10 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
+namespace password_manager {
+class PasswordChangeSuccessTracker;
+}
+
namespace autofill_assistant {
class MockClient : public Client {
@@ -38,6 +42,8 @@ class MockClient : public Client {
MOCK_CONST_METHOD0(GetWebContents, content::WebContents*());
MOCK_CONST_METHOD0(GetPersonalDataManager, autofill::PersonalDataManager*());
MOCK_CONST_METHOD0(GetWebsiteLoginManager, WebsiteLoginManager*());
+ MOCK_CONST_METHOD0(GetPasswordChangeSuccessTracker,
+ password_manager::PasswordChangeSuccessTracker*());
MOCK_METHOD0(GetAccessTokenFetcher, AccessTokenFetcher*());
MOCK_METHOD1(Shutdown, void(Metrics::DropOutReason reason));
MOCK_METHOD1(RecordDropOut, void(Metrics::DropOutReason reason));
@@ -47,6 +53,7 @@ class MockClient : public Client {
MOCK_CONST_METHOD0(IsFirstTimeTriggerScriptUser, bool());
MOCK_METHOD1(FetchPaymentsClientToken,
void(base::OnceCallback<void(const std::string&)>));
+ MOCK_METHOD0(GetScriptExecutorUiDelegate, ScriptExecutorUiDelegate*());
private:
std::unique_ptr<MockPersonalDataManager> mock_personal_data_manager_;
diff --git a/chromium/components/autofill_assistant/browser/mock_controller_observer.h b/chromium/components/autofill_assistant/browser/mock_controller_observer.h
index 79c3b72e294..85039dda71b 100644
--- a/chromium/components/autofill_assistant/browser/mock_controller_observer.h
+++ b/chromium/components/autofill_assistant/browser/mock_controller_observer.h
@@ -11,9 +11,9 @@
#include "base/callback.h"
#include "components/autofill_assistant/browser/controller_observer.h"
+#include "components/autofill_assistant/browser/execution_delegate.h"
#include "components/autofill_assistant/browser/metrics.h"
#include "components/autofill_assistant/browser/script.h"
-#include "components/autofill_assistant/browser/ui_delegate.h"
#include "testing/gmock/include/gmock/gmock.h"
namespace autofill_assistant {
@@ -23,51 +23,29 @@ class MockControllerObserver : public ControllerObserver {
MockControllerObserver();
~MockControllerObserver() override;
- MOCK_METHOD1(OnStatusMessageChanged, void(const std::string& message));
- MOCK_METHOD1(OnBubbleMessageChanged, void(const std::string& message));
- MOCK_METHOD0(CloseCustomTab, void());
MOCK_METHOD1(OnStateChanged, void(AutofillAssistantState));
MOCK_METHOD1(OnKeyboardSuppressionStateChanged, void(bool));
- MOCK_METHOD1(OnUserActionsChanged,
- void(const std::vector<UserAction>& user_actions));
- MOCK_METHOD1(OnCollectUserDataOptionsChanged,
- void(const CollectUserDataOptions* options));
+ MOCK_METHOD0(CloseCustomTab, void());
+ MOCK_METHOD2(OnError,
+ void(const std::string& error_message,
+ Metrics::DropOutReason reason));
MOCK_METHOD2(OnUserDataChanged,
void(const UserData& user_data,
UserData::FieldChange field_change));
- MOCK_METHOD1(OnDetailsChanged, void(const std::vector<Details>& details));
- MOCK_METHOD1(OnInfoBoxChanged, void(const InfoBox* info_box));
- MOCK_METHOD1(OnProgressChanged, void(int progress));
- MOCK_METHOD1(OnProgressActiveStepChanged, void(int active_step));
- MOCK_METHOD1(OnProgressVisibilityChanged, void(bool visible));
- MOCK_METHOD1(OnStepProgressBarConfigurationChanged,
- void(const ShowProgressBarProto::StepProgressBarConfiguration&
- configuration));
- MOCK_METHOD1(OnProgressBarErrorStateChanged, void(bool error));
MOCK_METHOD3(OnTouchableAreaChanged,
void(const RectF& visual_viewport,
const std::vector<RectF>& touchable_areas,
const std::vector<RectF>& restricted_areas));
- MOCK_CONST_METHOD0(Terminate, bool());
- MOCK_CONST_METHOD0(GetDropOutReason, Metrics::DropOutReason());
MOCK_METHOD1(OnViewportModeChanged, void(ViewportMode mode));
- MOCK_METHOD1(OnPeekModeChanged,
- void(ConfigureBottomSheetProto::PeekMode peek_mode));
- MOCK_METHOD0(OnExpandBottomSheet, void());
- MOCK_METHOD0(OnCollapseBottomSheet, void());
MOCK_METHOD1(OnOverlayColorsChanged,
- void(const UiDelegate::OverlayColors& colors));
- MOCK_METHOD2(OnFormChanged,
- void(const FormProto* form, const FormProto::Result* result));
+ void(const ExecutionDelegate::OverlayColors& colors));
MOCK_METHOD1(OnClientSettingsChanged, void(const ClientSettings& settings));
- MOCK_METHOD1(OnGenericUserInterfaceChanged,
- void(const GenericUserInterfaceProto* generic_ui));
- MOCK_METHOD1(OnPersistentGenericUserInterfaceChanged,
- void(const GenericUserInterfaceProto* generic_ui));
MOCK_METHOD1(OnShouldShowOverlayChanged, void(bool should_show));
- MOCK_METHOD1(OnTtsButtonVisibilityChanged, void(bool visible));
- MOCK_METHOD1(OnTtsButtonStateChanged, void(TtsButtonState state));
- MOCK_METHOD0(OnFeedbackFormRequested, void());
+ MOCK_METHOD1(OnExecuteScript, void(const std::string& start_message));
+ MOCK_METHOD1(OnStart, void(const TriggerContext& trigger_context));
+ MOCK_METHOD0(OnStop, void());
+ MOCK_METHOD0(OnResetState, void());
+ MOCK_METHOD1(OnUiShownChanged, void(bool shown));
};
} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/mock_execution_delegate.cc b/chromium/components/autofill_assistant/browser/mock_execution_delegate.cc
new file mode 100644
index 00000000000..4fe1fb3300c
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/mock_execution_delegate.cc
@@ -0,0 +1,12 @@
+// Copyright 2022 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.
+
+#include "components/autofill_assistant/browser/mock_execution_delegate.h"
+
+namespace autofill_assistant {
+MockExecutionDelegate::MockExecutionDelegate() = default;
+
+MockExecutionDelegate::~MockExecutionDelegate() = default;
+
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/mock_execution_delegate.h b/chromium/components/autofill_assistant/browser/mock_execution_delegate.h
new file mode 100644
index 00000000000..fcb2e6edc63
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/mock_execution_delegate.h
@@ -0,0 +1,52 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_MOCK_EXECUTION_DELEGATE_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_MOCK_EXECUTION_DELEGATE_H_
+
+#include "components/autofill_assistant/browser/client_settings.h"
+#include "components/autofill_assistant/browser/execution_delegate.h"
+#include "components/autofill_assistant/browser/user_model.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace autofill_assistant {
+
+class MockExecutionDelegate : public ExecutionDelegate {
+ public:
+ MockExecutionDelegate();
+ ~MockExecutionDelegate() override;
+
+ MOCK_CONST_METHOD0(GetState, AutofillAssistantState());
+ MOCK_METHOD0(GetUserData, UserData*());
+ MOCK_METHOD2(OnFatalError,
+ void(const std::string& error_message,
+ Metrics::DropOutReason reason));
+ MOCK_METHOD2(OnStop,
+ void(const std::string& message,
+ const std::string& button_label));
+ MOCK_CONST_METHOD1(GetTouchableArea, void(std::vector<RectF>* rectangles));
+ MOCK_CONST_METHOD1(GetRestrictedArea, void(std::vector<RectF>* rectangles));
+ MOCK_CONST_METHOD1(GetVisualViewport, void(RectF* viewport));
+ MOCK_METHOD0(GetViewportMode, ViewportMode());
+ MOCK_METHOD0(IsTabSelected, bool());
+ MOCK_METHOD1(SetTabSelected, void(bool selected));
+ MOCK_CONST_METHOD1(GetOverlayColors, void(OverlayColors* colors));
+ MOCK_CONST_METHOD0(GetClientSettings, const ClientSettings&());
+ MOCK_METHOD0(GetTriggerContext, const TriggerContext*());
+ MOCK_METHOD0(GetCurrentURL, const GURL&());
+ MOCK_METHOD1(SetUiShown, void(bool shown));
+ MOCK_METHOD0(GetUserModel, UserModel*());
+ MOCK_CONST_METHOD0(ShouldShowOverlay, bool());
+ MOCK_CONST_METHOD0(ShouldSuppressKeyboard, bool());
+ MOCK_METHOD1(SuppressKeyboard, void(bool suppress));
+ MOCK_METHOD0(ShutdownIfNecessary, void());
+ MOCK_METHOD1(NotifyUserDataChange, void(UserData::FieldChange field_change));
+ MOCK_METHOD1(AddObserver, void(ControllerObserver* observer));
+ MOCK_METHOD1(RemoveObserver, void(const ControllerObserver* observer));
+ MOCK_CONST_METHOD0(NeedsUI, bool());
+};
+
+} // namespace autofill_assistant
+
+#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_MOCK_EXECUTION_DELEGATE_H_
diff --git a/chromium/components/autofill_assistant/browser/mock_script_executor_delegate.h b/chromium/components/autofill_assistant/browser/mock_script_executor_delegate.h
index c93e3d68290..0076f854b67 100644
--- a/chromium/components/autofill_assistant/browser/mock_script_executor_delegate.h
+++ b/chromium/components/autofill_assistant/browser/mock_script_executor_delegate.h
@@ -7,16 +7,11 @@
#include "components/autofill/core/browser/personal_data_manager.h"
#include "components/autofill_assistant/browser/client_settings.h"
-#include "components/autofill_assistant/browser/details.h"
-#include "components/autofill_assistant/browser/event_handler.h"
-#include "components/autofill_assistant/browser/generic_ui.pb.h"
-#include "components/autofill_assistant/browser/info_box.h"
#include "components/autofill_assistant/browser/script_executor_delegate.h"
#include "components/autofill_assistant/browser/service.pb.h"
#include "components/autofill_assistant/browser/service/service.h"
#include "components/autofill_assistant/browser/state.h"
#include "components/autofill_assistant/browser/trigger_context.h"
-#include "components/autofill_assistant/browser/user_action.h"
#include "components/autofill_assistant/browser/user_data.h"
#include "components/autofill_assistant/browser/user_model.h"
#include "components/autofill_assistant/browser/viewport_mode.h"
@@ -26,6 +21,10 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "url/gurl.h"
+namespace password_manager {
+class PasswordChangeSuccessTracker;
+}
+
namespace autofill_assistant {
class MockScriptExecutorDelegate : public ScriptExecutorDelegate {
@@ -45,6 +44,10 @@ class MockScriptExecutorDelegate : public ScriptExecutorDelegate {
(),
(override));
MOCK_METHOD(WebsiteLoginManager*, GetWebsiteLoginManager, (), (override));
+ MOCK_METHOD(password_manager::PasswordChangeSuccessTracker*,
+ GetPasswordChangeSuccessTracker,
+ (),
+ (override));
MOCK_METHOD(content::WebContents*, GetWebContents, (), (override));
MOCK_METHOD(std::string,
GetEmailAddressForAccessTokenAccount,
@@ -52,7 +55,7 @@ class MockScriptExecutorDelegate : public ScriptExecutorDelegate {
(override));
MOCK_METHOD(ukm::UkmRecorder*, GetUkmRecorder, (), (override));
MOCK_METHOD(bool, EnterState, (AutofillAssistantState state), (override));
- MOCK_METHOD(AutofillAssistantState, GetState, (), (override));
+ MOCK_CONST_METHOD0(GetState, AutofillAssistantState());
MOCK_METHOD(void,
SetOverlayBehavior,
(ConfigureUiStateProto::OverlayBehavior overlay_behavior),
@@ -61,81 +64,18 @@ class MockScriptExecutorDelegate : public ScriptExecutorDelegate {
SetTouchableElementArea,
(const ElementAreaProto& element),
(override));
- MOCK_METHOD(void, SetStatusMessage, (const std::string& message), (override));
- MOCK_METHOD(std::string, GetStatusMessage, (), (const, override));
- MOCK_METHOD(void, SetBubbleMessage, (const std::string& message), (override));
- MOCK_METHOD(std::string, GetBubbleMessage, (), (const, override));
- MOCK_METHOD(void, SetTtsMessage, (const std::string& message), (override));
- MOCK_METHOD(std::string, GetTtsMessage, (), (const, override));
- MOCK_METHOD(TtsButtonState, GetTtsButtonState, (), (const, override));
- MOCK_METHOD(void, MaybePlayTtsMessage, (), (override));
- MOCK_METHOD(void,
- SetDetails,
- (std::unique_ptr<Details> details, base::TimeDelta delay),
- (override));
- MOCK_METHOD(void,
- AppendDetails,
- (std::unique_ptr<Details> details, base::TimeDelta delay),
- (override));
- MOCK_METHOD(void, SetInfoBox, (const InfoBox& info_box), (override));
- MOCK_METHOD(void, ClearInfoBox, (), (override));
- MOCK_METHOD(void,
- SetCollectUserDataOptions,
- (CollectUserDataOptions * collect_user_data_options),
- (override));
- MOCK_METHOD(
- void,
- SetLastSuccessfulUserDataOptions,
- (std::unique_ptr<CollectUserDataOptions> collect_user_data_options),
- (override));
- MOCK_METHOD(const CollectUserDataOptions*,
- GetLastSuccessfulUserDataOptions,
- (),
- (const, override));
MOCK_METHOD(void,
WriteUserData,
(base::OnceCallback<void(UserData*, UserData::FieldChange*)>
write_callback),
(override));
- MOCK_METHOD(bool,
- SetProgressActiveStepIdentifier,
- (const std::string& active_step_identifier),
- (override));
- MOCK_METHOD(void, SetProgressActiveStep, (int active_step), (override));
- MOCK_METHOD(void, SetProgressVisible, (bool visible), (override));
- MOCK_METHOD(void, SetProgressBarErrorState, (bool error), (override));
- MOCK_METHOD(
- void,
- SetStepProgressBarConfiguration,
- (const ShowProgressBarProto::StepProgressBarConfiguration& configuration),
- (override));
- MOCK_METHOD(void,
- SetUserActions,
- (std::unique_ptr<std::vector<UserAction>> user_action),
- (override));
MOCK_METHOD(ViewportMode, GetViewportMode, (), (override));
MOCK_METHOD(void, SetViewportMode, (ViewportMode mode), (override));
MOCK_METHOD(void,
- SetPeekMode,
- (ConfigureBottomSheetProto::PeekMode peek_mode),
- (override));
- MOCK_METHOD(ConfigureBottomSheetProto::PeekMode, GetPeekMode, (), (override));
- MOCK_METHOD(void, ExpandBottomSheet, (), (override));
- MOCK_METHOD(void, CollapseBottomSheet, (), (override));
- MOCK_METHOD(void,
SetClientSettings,
(const ClientSettingsProto& client_settings),
(override));
- MOCK_METHOD(
- bool,
- SetForm,
- (std::unique_ptr<FormProto> form,
- base::RepeatingCallback<void(const FormProto::Result*)> changed_callback,
- base::OnceCallback<void(const ClientStatus&)> cancel_callback),
- (override));
MOCK_METHOD(UserModel*, GetUserModel, (), (override));
- MOCK_METHOD(EventHandler*, GetEventHandler, (), (override));
- MOCK_METHOD(void, SetShowFeedbackChip, (bool show_feedback_chip), (override));
MOCK_METHOD(void, ExpectNavigation, (), (override));
MOCK_METHOD(bool, IsNavigatingToNewDocument, (), (override));
MOCK_METHOD(bool, HasNavigationError, (), (override));
@@ -150,30 +90,13 @@ class MockScriptExecutorDelegate : public ScriptExecutorDelegate {
(override));
MOCK_METHOD(void, AddListener, (Listener * listener), (override));
MOCK_METHOD(void, RemoveListener, (Listener * listener), (override));
- MOCK_METHOD(void, SetExpandSheetForPromptAction, (bool expand), (override));
MOCK_METHOD(void,
SetBrowseDomainsAllowlist,
(std::vector<std::string> domains),
(override));
- MOCK_METHOD(
- void,
- SetGenericUi,
- (std::unique_ptr<GenericUserInterfaceProto> generic_ui,
- base::OnceCallback<void(const ClientStatus&)> end_action_callback,
- base::OnceCallback<void(const ClientStatus&)>
- view_inflation_finished_callback),
- (override));
- MOCK_METHOD(void,
- SetPersistentGenericUi,
- (std::unique_ptr<GenericUserInterfaceProto> generic_ui,
- base::OnceCallback<void(const ClientStatus&)>
- view_inflation_finished_callback),
- (override));
- MOCK_METHOD(void, ClearGenericUi, (), (override));
- MOCK_METHOD(void, ClearPersistentGenericUi, (), (override));
MOCK_METHOD(void, SetBrowseModeInvisible, (bool invisible), (override));
- MOCK_METHOD(bool, ShouldShowWarning, (), (override));
MOCK_METHOD(ProcessedActionStatusDetailsProto&, GetLogInfo, (), (override));
+ MOCK_METHOD(bool, ShouldShowWarning, (), (override));
private:
ClientSettings client_settings_;
diff --git a/chromium/components/autofill_assistant/browser/mock_ui_controller_observer.cc b/chromium/components/autofill_assistant/browser/mock_ui_controller_observer.cc
new file mode 100644
index 00000000000..0035fae89db
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/mock_ui_controller_observer.cc
@@ -0,0 +1,12 @@
+// Copyright 2022 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.
+
+#include "components/autofill_assistant/browser/mock_ui_controller_observer.h"
+
+namespace autofill_assistant {
+
+MockUiControllerObserver::MockUiControllerObserver() {}
+MockUiControllerObserver::~MockUiControllerObserver() {}
+
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/mock_ui_controller_observer.h b/chromium/components/autofill_assistant/browser/mock_ui_controller_observer.h
new file mode 100644
index 00000000000..e1f59d5135c
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/mock_ui_controller_observer.h
@@ -0,0 +1,59 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_MOCK_UI_CONTROLLER_OBSERVER_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_MOCK_UI_CONTROLLER_OBSERVER_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "components/autofill_assistant/browser/execution_delegate.h"
+#include "components/autofill_assistant/browser/metrics.h"
+#include "components/autofill_assistant/browser/script.h"
+#include "components/autofill_assistant/browser/ui_controller_observer.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace autofill_assistant {
+
+class MockUiControllerObserver : public UiControllerObserver {
+ public:
+ MockUiControllerObserver();
+ ~MockUiControllerObserver() override;
+
+ MOCK_METHOD1(OnStatusMessageChanged, void(const std::string& message));
+ MOCK_METHOD1(OnBubbleMessageChanged, void(const std::string& message));
+ MOCK_METHOD1(OnStateChanged, void(AutofillAssistantState));
+ MOCK_METHOD1(OnUserActionsChanged,
+ void(const std::vector<UserAction>& user_actions));
+ MOCK_METHOD1(OnCollectUserDataOptionsChanged,
+ void(const CollectUserDataOptions* options));
+ MOCK_METHOD1(OnDetailsChanged, void(const std::vector<Details>& details));
+ MOCK_METHOD1(OnInfoBoxChanged, void(const InfoBox* info_box));
+ MOCK_METHOD1(OnProgressChanged, void(int progress));
+ MOCK_METHOD1(OnProgressActiveStepChanged, void(int active_step));
+ MOCK_METHOD1(OnProgressVisibilityChanged, void(bool visible));
+ MOCK_METHOD1(OnStepProgressBarConfigurationChanged,
+ void(const ShowProgressBarProto::StepProgressBarConfiguration&
+ configuration));
+ MOCK_METHOD1(OnProgressBarErrorStateChanged, void(bool error));
+ MOCK_METHOD1(OnPeekModeChanged,
+ void(ConfigureBottomSheetProto::PeekMode peek_mode));
+ MOCK_METHOD0(OnExpandBottomSheet, void());
+ MOCK_METHOD0(OnCollapseBottomSheet, void());
+ MOCK_METHOD2(OnFormChanged,
+ void(const FormProto* form, const FormProto::Result* result));
+ MOCK_METHOD1(OnGenericUserInterfaceChanged,
+ void(const GenericUserInterfaceProto* generic_ui));
+ MOCK_METHOD1(OnPersistentGenericUserInterfaceChanged,
+ void(const GenericUserInterfaceProto* generic_ui));
+ MOCK_METHOD1(OnTtsButtonVisibilityChanged, void(bool visible));
+ MOCK_METHOD1(OnTtsButtonStateChanged, void(TtsButtonState state));
+ MOCK_METHOD0(OnFeedbackFormRequested, void());
+};
+
+} // namespace autofill_assistant
+
+#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_MOCK_UI_CONTROLLER_OBSERVER_H_
diff --git a/chromium/components/autofill_assistant/browser/model.proto b/chromium/components/autofill_assistant/browser/model.proto
index 887799ed36b..e312340d15c 100644
--- a/chromium/components/autofill_assistant/browser/model.proto
+++ b/chromium/components/autofill_assistant/browser/model.proto
@@ -409,5 +409,14 @@ message AutofillProfileProto {
message LoginOptionProto {
optional string label = 1;
optional string sublabel = 2;
- optional bytes payload = 3;
+
+ oneof payload_or_tag {
+ // A payload to be echoed back to the caller when the option is selected.
+ //
+ // Prefer using tag.
+ bytes payload = 3;
+
+ // A tag to be echoed back to the caller when the option is selected.
+ string tag = 4;
+ }
}
diff --git a/chromium/components/autofill_assistant/browser/parse_jspb.cc b/chromium/components/autofill_assistant/browser/parse_jspb.cc
new file mode 100644
index 00000000000..ac16d9a7a9b
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/parse_jspb.cc
@@ -0,0 +1,193 @@
+// Copyright 2022 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.
+
+#include "components/autofill_assistant/browser/parse_jspb.h"
+
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
+
+#include "base/bit_cast.h"
+#include "base/strings/strcat.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+
+namespace autofill_assistant {
+namespace {
+
+// Proto buffer wire types needed in this file.
+//
+// This avoids including
+// third_party/protobuf/src/google/protobuf/wire_format_lite.h since it is
+// documented as being internal.
+enum WireType {
+ WIRETYPE_VARINT = 0,
+ WIRETYPE_LENGTH_DELIMITED = 2,
+ WIRETYPE_FIXED32 = 5,
+};
+
+// Writes a field tag, containing both tag and wire type.
+//
+// This avoids including
+// third_party/protobuf/src/google/protobuf/wire_format_lite.h since it is
+// documented as being internal.
+inline void WriteTag(uint32_t tag,
+ WireType type,
+ google::protobuf::io::CodedOutputStream* out) {
+ out->WriteTag((tag << 3) | type);
+}
+
+// Returns true if |list| contains a message.
+//
+// Support is limited to messages with a jspb id starting with the expected
+// prefix.
+bool IsJspbMessage(const std::string& jspb_id_prefix,
+ const base::Value& value,
+ std::string* error_message) {
+ if (!value.is_list()) {
+ return false;
+ }
+ base::Value::ConstListView list = value.GetListDeprecated();
+ if (list.empty() || !list.front().is_string() ||
+ !base::StartsWith(list.front().GetString(), jspb_id_prefix)) {
+ if (error_message != nullptr) {
+ *error_message =
+ base::StrCat({"Message id must start with '", jspb_id_prefix, "'"});
+ }
+ return false;
+ }
+ return true;
+}
+
+bool ParseJspbToString(const std::string& jspb_id_prefix,
+ const base::Value::ConstListView& list,
+ std::string* bytes,
+ std::string* error_message);
+
+// Assign |field_tag| to |value| in the output stream |out|.
+bool AppendFieldValue(const std::string& jspb_id_prefix,
+ uint32_t field_tag,
+ const base::Value& value,
+ google::protobuf::io::CodedOutputStream* out,
+ std::string* error_message) {
+ switch (value.type()) {
+ case base::Value::Type::BOOLEAN:
+ WriteTag(field_tag, WIRETYPE_VARINT, out);
+ out->WriteVarint32(value.GetBool() ? 1 : 0);
+ break;
+
+ case base::Value::Type::INTEGER:
+ WriteTag(field_tag, WIRETYPE_VARINT, out);
+ out->WriteVarint64(value.GetInt());
+ break;
+
+ case base::Value::Type::DOUBLE:
+ // Encode these as floats (in a fixed32)
+ WriteTag(field_tag, WIRETYPE_FIXED32, out);
+ out->WriteLittleEndian32(
+ bit_cast<uint32_t>(static_cast<float>(value.GetDouble())));
+ break;
+
+ case base::Value::Type::STRING: {
+ const std::string& string = value.GetString();
+ WriteTag(field_tag, WIRETYPE_LENGTH_DELIMITED, out);
+ out->WriteVarint32(string.size());
+ out->WriteString(string);
+ break;
+ }
+
+ case base::Value::Type::LIST:
+ if (IsJspbMessage(jspb_id_prefix, value, /* error_message= */ nullptr)) {
+ // A proto message
+ std::string bytes;
+ if (!ParseJspbToString(jspb_id_prefix, value.GetListDeprecated(),
+ &bytes, error_message)) {
+ return false;
+ }
+ WriteTag(field_tag, WIRETYPE_LENGTH_DELIMITED, out);
+ out->WriteVarint32(bytes.size());
+ out->WriteString(bytes);
+ break;
+ }
+ // A repeated field.
+ for (const base::Value& element : value.GetListDeprecated()) {
+ AppendFieldValue(jspb_id_prefix, field_tag, element, out,
+ error_message);
+ }
+ break;
+
+ default:
+ if (error_message != nullptr) {
+ *error_message = base::StrCat({"Unexpected value type for field ",
+ base::NumberToString(field_tag), ": ",
+ base::Value::GetTypeName(value.type())});
+ }
+ return false;
+ }
+ return true;
+}
+
+// Parses a message from |list| and puts the result into |bytes|.
+bool ParseJspbToString(const std::string& jspb_id_prefix,
+ const base::Value::ConstListView& list,
+ std::string* bytes,
+ std::string* error_message) {
+ google::protobuf::io::StringOutputStream string_output(bytes);
+ google::protobuf::io::CodedOutputStream coded_output(&string_output);
+
+ // IsJspbMessage has found a message_id in list[0]; the rest of the list
+ // contains fields.
+ for (size_t i = 1; i < list.size(); i++) {
+ const base::Value& array_value = list[i];
+ if (array_value.is_none()) {
+ // field has no value (null)
+ continue;
+ }
+ if (array_value.is_dict()) {
+ // The remaining fields are stored in a dict, with keys as tag numbers.
+ // Example: ["message_id", null, null, 1, {"112": 9, ...}]
+ for (const auto [field_key, field_value] : array_value.DictItems()) {
+ uint32_t tag = 0;
+ if (!base::StringToUint(field_key, &tag)) {
+ if (error_message != nullptr) {
+ *error_message = base::StrCat(
+ {"Dictionary keys should be stringified integers, not '",
+ field_key, "'"});
+ }
+ return false;
+ }
+ if (!AppendFieldValue(jspb_id_prefix, tag, field_value, &coded_output,
+ error_message)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ // Fields are stored in the array, at a position corresponding to their tag
+ // number.
+ uint32_t field_tag = static_cast<uint32_t>(i);
+ if (!AppendFieldValue(jspb_id_prefix, field_tag, array_value, &coded_output,
+ error_message)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+} // namespace
+
+absl::optional<std::string> ParseJspb(const std::string& jspb_id_prefix,
+ const base::Value& message,
+ std::string* error_message) {
+ if (!IsJspbMessage(jspb_id_prefix, message, error_message)) {
+ return absl::nullopt;
+ }
+ std::string bytes;
+ if (!ParseJspbToString(jspb_id_prefix, message.GetListDeprecated(), &bytes,
+ error_message)) {
+ return absl::nullopt;
+ }
+ return bytes;
+}
+
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/parse_jspb.h b/chromium/components/autofill_assistant/browser/parse_jspb.h
new file mode 100644
index 00000000000..5ae8ad12feb
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/parse_jspb.h
@@ -0,0 +1,42 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_PARSE_JSPB_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_PARSE_JSPB_H_
+
+#include <string>
+
+#include "base/values.h"
+
+namespace autofill_assistant {
+
+// Converts a message in JSPB wire encoding to the equivalent binary encoding,
+// without knowing what that message is.
+//
+// Only works on messages that meet the following requirements:
+// - |message| and all messages it references must have a JSPB message id
+// starting with |jspb_id_prefix|.
+// - numbers fields are all int32, int64 or float (no unsigned, fixed or double)
+// - there are no bytes fields.
+//
+// Messages that don't meet these requirements will still be parsed, but not
+// completely, depending on the type and value that the original message
+// contained.
+//
+// WARNING: In general, fields that cannot be parsed properly aren't rejected,
+// but rather silently skipped later on, during proto parsing.
+//
+// As an exception to the above, bytes field are parsed completely and reliably.
+// However, the final value is a base64-encoded version of the expected bytes.
+// This is why they should be avoided.
+//
+// If parsing is successful, returns a string containing the bytes of the
+// message. Note that an empty string is a valid serialized proto value.
+absl::optional<std::string> ParseJspb(const std::string& jspb_id_prefix,
+ const base::Value& message,
+ std::string* error_message);
+
+} // namespace autofill_assistant
+
+#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_PARSE_JSPB_H_
diff --git a/chromium/components/autofill_assistant/browser/parse_jspb_test.proto b/chromium/components/autofill_assistant/browser/parse_jspb_test.proto
new file mode 100644
index 00000000000..cac029a09d9
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/parse_jspb_test.proto
@@ -0,0 +1,45 @@
+// Copyright 2022 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.
+
+syntax = "proto2";
+
+package autofill_assistant.testing;
+
+option optimize_for = LITE_RUNTIME;
+
+message TestProto {
+ optional int32 int32_field = 1;
+ optional int64 int64_field = 2;
+ enum MyEnum {
+ MY_ENUM_0 = 0;
+ MY_ENUM_1 = 1;
+ MY_ENUM_2 = 2;
+ }
+ optional MyEnum enum_field = 3;
+ optional bool bool_field = 4;
+ optional string string_field = 5;
+ optional TestProto inner = 6;
+ repeated string repeated_string_field = 7;
+ optional float float_field = 8;
+
+ // Unsupported field types. If encountered during parsing, the resulting proto
+ // will have these fields unset.
+ optional double double_field = 9;
+ optional fixed32 fixed32_field = 10;
+ optional sfixed32 sfixed32_field = 11;
+ optional fixed64 fixed64_field = 12;
+ optional sfixed64 sfixed64_field = 13;
+
+ // Unsupported fields that are unreliable and so dangerous to use.
+ //
+ // WARNING: uint32 and uint64 are unsupported too, but the resulting proto may
+ // skip those fields depending on the values. These types should never be
+ // used!
+ optional uint32 uint32_field = 14;
+ optional uint64 uint64_field = 15;
+
+ // Bytes field are treated as string field and will contain the base64-encoded
+ // data instead of the decoded bytes.
+ optional bytes bytes_field = 16;
+}
diff --git a/chromium/components/autofill_assistant/browser/parse_jspb_unittest.cc b/chromium/components/autofill_assistant/browser/parse_jspb_unittest.cc
new file mode 100644
index 00000000000..874aeab41e1
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/parse_jspb_unittest.cc
@@ -0,0 +1,197 @@
+// Copyright 2022 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.
+
+#include "components/autofill_assistant/browser/parse_jspb.h"
+
+#include "base/json/json_reader.h"
+#include "base/logging.h"
+#include "components/autofill_assistant/browser/parse_jspb_test.pb.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+using ::testing::ElementsAre;
+using ::testing::FloatEq;
+
+namespace autofill_assistant {
+namespace {
+
+bool ParseTestProto(const std::string& json, testing::TestProto* proto) {
+ absl::optional<base::Value> value = base::JSONReader::Read(json);
+ if (!value) {
+ LOG(ERROR) << "Invalid JSON: " << json;
+ return false;
+ }
+ absl::optional<std::string> bytes =
+ ParseJspb("test.", *value, /* error_message= */ nullptr);
+ if (!bytes) {
+ LOG(ERROR) << "Cannot transform to binary: " << json;
+ return false;
+ }
+ if (!proto->ParseFromString(*bytes)) {
+ LOG(ERROR) << "Cannot parse from binary: " << json;
+ return false;
+ }
+ return true;
+}
+
+TEST(ParseJspbTest, ParseEmptyMessage) {
+ testing::TestProto message;
+ EXPECT_TRUE(ParseTestProto(R"(["test.Test"])", &message));
+ EXPECT_TRUE(ParseTestProto(R"(["test.Test", {}])", &message));
+}
+
+TEST(ParseJspbTest, ParseNumbers) {
+ testing::TestProto message;
+ EXPECT_TRUE(ParseTestProto(R"(["test.Test", -12, 2000])", &message));
+ EXPECT_EQ(-12, message.int32_field());
+ EXPECT_EQ(2000, message.int64_field());
+}
+
+TEST(ParseJspbTest, ParseEnum) {
+ testing::TestProto message;
+ EXPECT_TRUE(ParseTestProto(R"(["test.Test", null, null, 1])", &message));
+ EXPECT_EQ(testing::TestProto::MY_ENUM_1, message.enum_field());
+}
+
+TEST(ParseJspbTest, ParseTrue) {
+ testing::TestProto message;
+ EXPECT_TRUE(
+ ParseTestProto(R"(["test.Test", null, null, null, true])", &message));
+ EXPECT_TRUE(message.bool_field());
+}
+
+TEST(ParseJspbTest, ParseFalse) {
+ testing::TestProto message;
+ EXPECT_TRUE(
+ ParseTestProto(R"(["test.Test", null, null, null, false])", &message));
+ EXPECT_TRUE(message.has_bool_field());
+ EXPECT_FALSE(message.bool_field());
+}
+
+TEST(ParseJspbTest, ParseNonzeroAsBool) {
+ testing::TestProto message;
+ EXPECT_TRUE(
+ ParseTestProto(R"(["test.Test", null, null, null, 12])", &message));
+ EXPECT_TRUE(message.bool_field());
+}
+
+TEST(ParseJspbTest, ParseZeroAsBool) {
+ testing::TestProto message;
+ EXPECT_TRUE(
+ ParseTestProto(R"(["test.Test", null, null, null, 0])", &message));
+ EXPECT_TRUE(message.has_bool_field());
+ EXPECT_FALSE(message.bool_field());
+}
+
+TEST(ParseJspbTest, ParseString) {
+ testing::TestProto message;
+ EXPECT_TRUE(ParseTestProto(
+ R"(["test.Test", null, null, null, null, "foobar"])", &message));
+ EXPECT_EQ("foobar", message.string_field());
+}
+
+TEST(ParseJspbTest, ParseInner) {
+ testing::TestProto message;
+ EXPECT_TRUE(ParseTestProto(
+ R"(["test.Test", null, null, null, null, null, ["test.Test", 2]])",
+ &message));
+ EXPECT_TRUE(message.has_inner());
+ EXPECT_EQ(2, message.inner().int32_field());
+}
+
+TEST(ParseJspbTest, ParseInvalidInner) {
+ // The inner message is missing a message id. It will be parsed as an array
+ // and skipped during proto parsing.
+ testing::TestProto message;
+ ParseTestProto(R"(["test.Test", null, null, null, null, null, [1, 2]])",
+ &message);
+ EXPECT_FALSE(message.has_inner());
+}
+
+TEST(ParseJspbTest, ParseFromDict) {
+ testing::TestProto message;
+ EXPECT_TRUE(ParseTestProto(R"(["test.Test", {"5": "foobar"}])", &message));
+ EXPECT_EQ("foobar", message.string_field());
+}
+
+TEST(ParseJspbTest, ParseRepeated) {
+ testing::TestProto message;
+ EXPECT_TRUE(ParseTestProto(R"(["test.Test", {"7": ["one", "two", "three"]}])",
+ &message));
+ EXPECT_THAT(message.repeated_string_field(),
+ ElementsAre("one", "two", "three"));
+}
+
+TEST(ParseJspbTest, ParseFloat) {
+ testing::TestProto message;
+ EXPECT_TRUE(ParseTestProto(R"(["test.Test", {"8": 3.14}])", &message));
+ EXPECT_THAT(message.float_field(), FloatEq(3.14f));
+}
+
+TEST(ParseJspbTest, DoubleNotSupported) {
+ testing::TestProto message;
+ ParseTestProto(R"(["test.Test", {"9": 3.14}])", &message);
+ EXPECT_FALSE(message.has_float_field());
+}
+
+TEST(ParseJspbTest, ParseBytes) {
+ testing::TestProto message;
+ ParseTestProto(R"(["test.Test", {"16": "dGVzdAo="}])", &message);
+
+ // This isn't correct: it should have decoded the base64 and the bytes field
+ // should contain 'test', but the parser has no way of knowing that.
+ EXPECT_EQ("dGVzdAo=", message.bytes_field());
+}
+
+TEST(ParseJspbTest, UnsupportedFixedNumberTypes) {
+ testing::TestProto message;
+ ParseTestProto(
+ R"(["test.Unsupported", {"10": 1, "11": 2, "12": 3, "13": 4}])",
+ &message);
+ EXPECT_FALSE(message.has_fixed32_field());
+ EXPECT_FALSE(message.has_sfixed32_field());
+ EXPECT_FALSE(message.has_fixed64_field());
+ EXPECT_FALSE(message.has_sfixed64_field());
+}
+
+TEST(ParseJspbTest, UnsignedVarints) {
+ testing::TestProto message;
+ EXPECT_TRUE(
+ ParseTestProto(R"(["test.Unsupported", {"14": 1, "15": 2}])", &message));
+ EXPECT_EQ(1u, message.uint32_field());
+ EXPECT_EQ(2u, message.uint64_field());
+}
+
+TEST(ParseJspbTest, UnsignedVarintsTooLarge) {
+ testing::TestProto message;
+ ParseTestProto(
+ R"(["test.Unsupported", {"14": 4294967296, "15": 9223372036854775808 }])",
+ &message);
+ EXPECT_FALSE(message.has_uint32_field());
+ EXPECT_FALSE(message.has_uint64_field());
+}
+
+// Makes sure that |json| contains JSON data that's rejected by ParseJspb().
+bool InUnparseable(const std::string& json) {
+ absl::optional<base::Value> value = base::JSONReader::Read(json);
+ if (!value) {
+ LOG(ERROR) << "Invalid JSON: " << json;
+ return false;
+ }
+ absl::optional<std::string> bytes =
+ ParseJspb("test.", *value, /* error_message= */ nullptr);
+ // This should return absl::nullopt
+ return !bytes;
+}
+
+TEST(ParseJspbTest, InvalidJsonRepresentation) {
+ EXPECT_TRUE(InUnparseable(R"("invalid")"));
+ EXPECT_TRUE(InUnparseable("{}"));
+ EXPECT_TRUE(InUnparseable("[]"));
+ EXPECT_TRUE(InUnparseable("[1, 2]"));
+ EXPECT_TRUE(InUnparseable(R"([{"invalid": 1}])"));
+ EXPECT_TRUE(InUnparseable(R"(["invalid"])"));
+}
+
+} // namespace
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/protocol_utils.cc b/chromium/components/autofill_assistant/browser/protocol_utils.cc
index 59b57ec19c9..3abc98e63b2 100644
--- a/chromium/components/autofill_assistant/browser/protocol_utils.cc
+++ b/chromium/components/autofill_assistant/browser/protocol_utils.cc
@@ -6,6 +6,7 @@
#include <utility>
+#include <google/protobuf/message_lite.h>
#include "base/containers/flat_map.h"
#include "base/feature_list.h"
#include "base/logging.h"
@@ -19,6 +20,7 @@
#include "components/autofill_assistant/browser/actions/delete_password_action.h"
#include "components/autofill_assistant/browser/actions/dispatch_js_event_action.h"
#include "components/autofill_assistant/browser/actions/edit_password_action.h"
+#include "components/autofill_assistant/browser/actions/execute_js_action.h"
#include "components/autofill_assistant/browser/actions/expect_navigation_action.h"
#include "components/autofill_assistant/browser/actions/generate_password_for_form_field_action.h"
#include "components/autofill_assistant/browser/actions/get_element_status_action.h"
@@ -58,6 +60,24 @@
#include "url/gurl.h"
namespace autofill_assistant {
+namespace {
+// Parses |bytes| into |out|.
+//
+// On error, returns false and puts an error message into |error_message|.
+bool ParseActionFromString(int32_t action_id,
+ const std::string& bytes,
+ std::string* error_message,
+ google::protobuf::MessageLite* out) {
+ if (out->ParseFromString(bytes)) {
+ return true;
+ }
+ if (error_message != nullptr) {
+ *error_message = base::StrCat({"Message not parseable for action id ",
+ base::NumberToString(action_id)});
+ }
+ return false;
+}
+} // namespace
// static
std::string ProtocolUtils::CreateGetScriptsRequest(
@@ -70,7 +90,7 @@ std::string ProtocolUtils::CreateGetScriptsRequest(
script_proto.set_url(url.spec());
*script_proto.mutable_client_context() = client_context;
*script_proto.mutable_script_parameters() =
- script_parameters.ToProto(/* only_trigger_script_allowlisted = */ false);
+ script_parameters.ToProto(/* only_non_sensitive_allowlisted = */ false);
std::string serialized_script_proto;
bool success = script_proto.SerializeToString(&serialized_script_proto);
DCHECK(success);
@@ -78,6 +98,39 @@ std::string ProtocolUtils::CreateGetScriptsRequest(
}
// static
+std::string ProtocolUtils::CreateCapabilitiesByHashRequest(
+ uint32_t hash_prefix_length,
+ const std::vector<uint64_t>& hash_prefix,
+ const ClientContextProto& client_context,
+ const ScriptParameters& script_parameters) {
+ GetCapabilitiesByHashPrefixRequestProto request;
+ request.set_hash_prefix_length(hash_prefix_length);
+ for (uint64_t prefix : hash_prefix) {
+ request.add_hash_prefix(prefix);
+ }
+ *request.mutable_script_parameters() =
+ script_parameters.ToProto(/* only_non_sensitive_allowlisted = */ true);
+
+ ClientContextProto non_sensitive_context;
+ if (client_context.has_locale()) {
+ non_sensitive_context.set_locale(client_context.locale());
+ }
+ if (client_context.has_country()) {
+ non_sensitive_context.set_country(client_context.country());
+ }
+ if (client_context.chrome().has_chrome_version()) {
+ non_sensitive_context.mutable_chrome()->set_chrome_version(
+ client_context.chrome().chrome_version());
+ }
+ *request.mutable_client_context() = non_sensitive_context;
+
+ std::string serialized_request;
+ bool success = request.SerializeToString(&serialized_request);
+ DCHECK(success);
+ return serialized_request;
+}
+
+// static
void ProtocolUtils::AddScript(const SupportedScriptProto& script_proto,
std::vector<std::unique_ptr<Script>>* scripts) {
auto script = std::make_unique<Script>();
@@ -126,7 +179,7 @@ std::string ProtocolUtils::CreateInitialScriptActionsRequest(
query->set_policy(PolicyType::SCRIPT);
*request_proto.mutable_client_context() = client_context;
*initial_request_proto->mutable_script_parameters() =
- script_parameters.ToProto(/* only_trigger_script_allowlisted = */ false);
+ script_parameters.ToProto(/* only_non_sensitive_allowlisted = */ false);
if (!global_payload.empty()) {
request_proto.set_global_payload(global_payload);
}
@@ -393,6 +446,8 @@ std::unique_ptr<Action> ProtocolUtils::CreateAction(ActionDelegate* delegate,
return std::make_unique<ResetPendingCredentialsAction>(delegate, action);
case ActionProto::ActionInfoCase::kSaveSubmittedPassword:
return std::make_unique<SaveSubmittedPasswordAction>(delegate, action);
+ case ActionProto::ActionInfoCase::kExecuteJs:
+ return std::make_unique<ExecuteJsAction>(delegate, action);
case ActionProto::ActionInfoCase::ACTION_INFO_NOT_SET: {
VLOG(1) << "Encountered action with ACTION_INFO_NOT_SET";
return std::make_unique<UnsupportedAction>(delegate, action);
@@ -403,6 +458,272 @@ std::unique_ptr<Action> ProtocolUtils::CreateAction(ActionDelegate* delegate,
}
// static
+absl::optional<ActionProto> ProtocolUtils::ParseFromString(
+ int32_t action_id,
+ const std::string& bytes,
+ std::string* error_message) {
+ ActionProto proto;
+ bool success = true;
+ switch (static_cast<ActionProto::ActionInfoCase>(action_id)) {
+ case ActionProto::ActionInfoCase::kTell:
+ success = ParseActionFromString(action_id, bytes, error_message,
+ proto.mutable_tell());
+ break;
+ case ActionProto::ActionInfoCase::kShowCast:
+ success = ParseActionFromString(action_id, bytes, error_message,
+ proto.mutable_show_cast());
+ break;
+ case ActionProto::ActionInfoCase::kUseAddress:
+ success = ParseActionFromString(action_id, bytes, error_message,
+ proto.mutable_use_address());
+ break;
+ case ActionProto::ActionInfoCase::kUseCard:
+ success = ParseActionFromString(action_id, bytes, error_message,
+ proto.mutable_use_card());
+ break;
+ case ActionProto::ActionInfoCase::kWaitForDom:
+ success = ParseActionFromString(action_id, bytes, error_message,
+ proto.mutable_wait_for_dom());
+ break;
+ case ActionProto::ActionInfoCase::kSelectOption:
+ success = ParseActionFromString(action_id, bytes, error_message,
+ proto.mutable_select_option());
+ break;
+ case ActionProto::ActionInfoCase::kNavigate:
+ success = ParseActionFromString(action_id, bytes, error_message,
+ proto.mutable_navigate());
+ break;
+ case ActionProto::ActionInfoCase::kPrompt:
+ success = ParseActionFromString(action_id, bytes, error_message,
+ proto.mutable_prompt());
+ break;
+ case ActionProto::ActionInfoCase::kStop:
+ success = ParseActionFromString(action_id, bytes, error_message,
+ proto.mutable_stop());
+ break;
+ case ActionProto::ActionInfoCase::kUploadDom:
+ success = ParseActionFromString(action_id, bytes, error_message,
+ proto.mutable_upload_dom());
+ break;
+ case ActionProto::ActionInfoCase::kShowDetails:
+ success = ParseActionFromString(action_id, bytes, error_message,
+ proto.mutable_show_details());
+ break;
+ case ActionProto::ActionInfoCase::kCollectUserData:
+ success = ParseActionFromString(action_id, bytes, error_message,
+ proto.mutable_collect_user_data());
+ break;
+ case ActionProto::ActionInfoCase::kShowProgressBar:
+ success = ParseActionFromString(action_id, bytes, error_message,
+ proto.mutable_show_progress_bar());
+ break;
+ case ActionProto::ActionInfoCase::kSetAttribute:
+ success = ParseActionFromString(action_id, bytes, error_message,
+ proto.mutable_set_attribute());
+ break;
+ case ActionProto::ActionInfoCase::kShowInfoBox:
+ success = ParseActionFromString(action_id, bytes, error_message,
+ proto.mutable_show_info_box());
+ break;
+ case ActionProto::ActionInfoCase::kExpectNavigation:
+ success = ParseActionFromString(action_id, bytes, error_message,
+ proto.mutable_expect_navigation());
+ break;
+ case ActionProto::ActionInfoCase::kWaitForNavigation:
+ success = ParseActionFromString(action_id, bytes, error_message,
+ proto.mutable_wait_for_navigation());
+ break;
+ case ActionProto::ActionInfoCase::kConfigureBottomSheet:
+ success = ParseActionFromString(action_id, bytes, error_message,
+ proto.mutable_configure_bottom_sheet());
+ break;
+ case ActionProto::ActionInfoCase::kShowForm:
+ success = ParseActionFromString(action_id, bytes, error_message,
+ proto.mutable_show_form());
+ break;
+ case ActionProto::ActionInfoCase::kUpdateClientSettings:
+ success = ParseActionFromString(action_id, bytes, error_message,
+ proto.mutable_update_client_settings());
+ break;
+ case ActionProto::ActionInfoCase::kPopupMessage:
+ success = ParseActionFromString(action_id, bytes, error_message,
+ proto.mutable_popup_message());
+ break;
+ case ActionProto::ActionInfoCase::kWaitForDocument:
+ success = ParseActionFromString(action_id, bytes, error_message,
+ proto.mutable_wait_for_document());
+ break;
+ case ActionProto::ActionInfoCase::kShowGenericUi:
+ success = ParseActionFromString(action_id, bytes, error_message,
+ proto.mutable_show_generic_ui());
+ break;
+ case ActionProto::ActionInfoCase::kGeneratePasswordForFormField:
+ success = ParseActionFromString(
+ action_id, bytes, error_message,
+ proto.mutable_generate_password_for_form_field());
+ break;
+ case ActionProto::ActionInfoCase::kSaveGeneratedPassword:
+ success = ParseActionFromString(action_id, bytes, error_message,
+ proto.mutable_save_generated_password());
+ break;
+ case ActionProto::ActionInfoCase::kConfigureUiState:
+ success = ParseActionFromString(action_id, bytes, error_message,
+ proto.mutable_configure_ui_state());
+ break;
+ case ActionProto::ActionInfoCase::kPresaveGeneratedPassword:
+ success =
+ ParseActionFromString(action_id, bytes, error_message,
+ proto.mutable_presave_generated_password());
+ break;
+ case ActionProto::ActionInfoCase::kGetElementStatus:
+ success = ParseActionFromString(action_id, bytes, error_message,
+ proto.mutable_get_element_status());
+ break;
+ case ActionProto::ActionInfoCase::kScrollIntoView:
+ success = ParseActionFromString(action_id, bytes, error_message,
+ proto.mutable_scroll_into_view());
+ break;
+ case ActionProto::ActionInfoCase::kWaitForDocumentToBecomeInteractive:
+ success = ParseActionFromString(
+ action_id, bytes, error_message,
+ proto.mutable_wait_for_document_to_become_interactive());
+ break;
+ case ActionProto::ActionInfoCase::kWaitForDocumentToBecomeComplete:
+ success = ParseActionFromString(
+ action_id, bytes, error_message,
+ proto.mutable_wait_for_document_to_become_complete());
+ break;
+ case ActionProto::ActionInfoCase::kSendClickEvent:
+ success = ParseActionFromString(action_id, bytes, error_message,
+ proto.mutable_send_click_event());
+ break;
+ case ActionProto::ActionInfoCase::kSendTapEvent:
+ success = ParseActionFromString(action_id, bytes, error_message,
+ proto.mutable_send_tap_event());
+ break;
+ case ActionProto::ActionInfoCase::kJsClick:
+ success = ParseActionFromString(action_id, bytes, error_message,
+ proto.mutable_js_click());
+ break;
+ case ActionProto::ActionInfoCase::kSendKeystrokeEvents:
+ success = ParseActionFromString(action_id, bytes, error_message,
+ proto.mutable_send_keystroke_events());
+ break;
+ case ActionProto::ActionInfoCase::kSendChangeEvent:
+ success = ParseActionFromString(action_id, bytes, error_message,
+ proto.mutable_send_change_event());
+ break;
+ case ActionProto::ActionInfoCase::kSetElementAttribute:
+ success = ParseActionFromString(action_id, bytes, error_message,
+ proto.mutable_set_element_attribute());
+ break;
+ case ActionProto::ActionInfoCase::kSelectFieldValue:
+ success = ParseActionFromString(action_id, bytes, error_message,
+ proto.mutable_select_field_value());
+ break;
+ case ActionProto::ActionInfoCase::kFocusField:
+ success = ParseActionFromString(action_id, bytes, error_message,
+ proto.mutable_focus_field());
+ break;
+ case ActionProto::ActionInfoCase::kWaitForElementToBecomeStable:
+ success = ParseActionFromString(
+ action_id, bytes, error_message,
+ proto.mutable_wait_for_element_to_become_stable());
+ break;
+ case ActionProto::ActionInfoCase::kCheckElementIsOnTop:
+ success = ParseActionFromString(action_id, bytes, error_message,
+ proto.mutable_check_element_is_on_top());
+ break;
+ case ActionProto::ActionInfoCase::kReleaseElements:
+ success = ParseActionFromString(action_id, bytes, error_message,
+ proto.mutable_release_elements());
+ break;
+ case ActionProto::ActionInfoCase::kDispatchJsEvent:
+ success = ParseActionFromString(action_id, bytes, error_message,
+ proto.mutable_dispatch_js_event());
+ break;
+ case ActionProto::ActionInfoCase::kSendKeyEvent:
+ success = ParseActionFromString(action_id, bytes, error_message,
+ proto.mutable_send_key_event());
+ break;
+ case ActionProto::ActionInfoCase::kSelectOptionElement:
+ success = ParseActionFromString(action_id, bytes, error_message,
+ proto.mutable_select_option_element());
+ break;
+ case ActionProto::ActionInfoCase::kCheckElementTag:
+ success = ParseActionFromString(action_id, bytes, error_message,
+ proto.mutable_check_element_tag());
+ break;
+ case ActionProto::ActionInfoCase::kCheckOptionElement:
+ success = ParseActionFromString(action_id, bytes, error_message,
+ proto.mutable_check_option_element());
+ break;
+ case ActionProto::ActionInfoCase::kSetPersistentUi:
+ success = ParseActionFromString(action_id, bytes, error_message,
+ proto.mutable_set_persistent_ui());
+ break;
+ case ActionProto::ActionInfoCase::kClearPersistentUi:
+ success = ParseActionFromString(action_id, bytes, error_message,
+ proto.mutable_clear_persistent_ui());
+ break;
+ case ActionProto::ActionInfoCase::kScrollIntoViewIfNeeded:
+ success =
+ ParseActionFromString(action_id, bytes, error_message,
+ proto.mutable_scroll_into_view_if_needed());
+ break;
+ case ActionProto::ActionInfoCase::kScrollWindow:
+ success = ParseActionFromString(action_id, bytes, error_message,
+ proto.mutable_scroll_window());
+ break;
+ case ActionProto::ActionInfoCase::kScrollContainer:
+ success = ParseActionFromString(action_id, bytes, error_message,
+ proto.mutable_scroll_container());
+ break;
+ case ActionProto::ActionInfoCase::kSetTouchableArea:
+ success = ParseActionFromString(action_id, bytes, error_message,
+ proto.mutable_set_touchable_area());
+ break;
+ case ActionProto::ActionInfoCase::kDeletePassword:
+ success = ParseActionFromString(action_id, bytes, error_message,
+ proto.mutable_delete_password());
+ break;
+ case ActionProto::ActionInfoCase::kEditPassword:
+ success = ParseActionFromString(action_id, bytes, error_message,
+ proto.mutable_edit_password());
+ break;
+ case ActionProto::ActionInfoCase::kBlurField:
+ success = ParseActionFromString(action_id, bytes, error_message,
+ proto.mutable_blur_field());
+ break;
+ case ActionProto::ActionInfoCase::kResetPendingCredentials:
+ success =
+ ParseActionFromString(action_id, bytes, error_message,
+ proto.mutable_reset_pending_credentials());
+ break;
+ case ActionProto::ActionInfoCase::kSaveSubmittedPassword:
+ success = ParseActionFromString(action_id, bytes, error_message,
+ proto.mutable_save_submitted_password());
+ break;
+ case ActionProto::ActionInfoCase::kExecuteJs:
+ success = ParseActionFromString(action_id, bytes, error_message,
+ proto.mutable_execute_js());
+ break;
+ case ActionProto::ActionInfoCase::ACTION_INFO_NOT_SET:
+ // This is an "unknown action", handled as such in CreateAction.
+ return proto;
+ }
+ // There's an implicit default case that ends up with success=true and an
+ // empty proto if given an action_id that doesn't fit into ActionInfoCase.
+ // This is the unknown action case. Doing it without an explicit default case
+ // allows relying on exhaustive switch checks in the compiler.
+
+ if (!success) {
+ return absl::nullopt;
+ }
+ return proto;
+}
+
+// static
bool ProtocolUtils::ParseActions(ActionDelegate* delegate,
const std::string& response,
std::string* return_global_payload,
@@ -455,7 +776,7 @@ std::string ProtocolUtils::CreateGetTriggerScriptsRequest(
request_proto.set_url(url.spec());
*request_proto.mutable_client_context() = client_context;
*request_proto.mutable_script_parameters() =
- script_parameters.ToProto(/* only_trigger_script_allowlisted = */ true);
+ script_parameters.ToProto(/* only_non_sensitive_allowlisted = */ true);
std::string serialized_request_proto;
bool success = request_proto.SerializeToString(&serialized_request_proto);
diff --git a/chromium/components/autofill_assistant/browser/protocol_utils.h b/chromium/components/autofill_assistant/browser/protocol_utils.h
index b707b72b198..f0c043d6c26 100644
--- a/chromium/components/autofill_assistant/browser/protocol_utils.h
+++ b/chromium/components/autofill_assistant/browser/protocol_utils.h
@@ -31,6 +31,15 @@ class ProtocolUtils {
const ClientContextProto& client_context,
const ScriptParameters& script_parameters);
+ // Create request to get domains capabilities via their url hash prefix.
+ // Note: Only a subset of allowed fields from |client_context| will be sent to
+ // the server.
+ static std::string CreateCapabilitiesByHashRequest(
+ uint32_t hash_prefix_length,
+ const std::vector<uint64_t>& hash_prefix,
+ const ClientContextProto& client_context,
+ const ScriptParameters& script_parameters);
+
// Convert |script_proto| to a script struct and if the script is valid, add
// it to |scripts|.
static void AddScript(const SupportedScriptProto& script_proto,
@@ -67,6 +76,15 @@ class ProtocolUtils {
static std::unique_ptr<Action> CreateAction(ActionDelegate* delegate,
const ActionProto& action);
+ // Parses an individual action as ActionProto.
+ //
+ // If something goes wrong, returns nullopt. If error_message is non-null, it
+ // is filled with an error message suitable for logging.
+ static absl::optional<ActionProto> ParseFromString(
+ int32_t action_id,
+ const std::string& bytes,
+ std::string* error_message);
+
// Parse actions from the given |response|, which can be an empty string.
//
// Pass in nullptr for |return_global_payload| or |return_script_payload| to
diff --git a/chromium/components/autofill_assistant/browser/protocol_utils_unittest.cc b/chromium/components/autofill_assistant/browser/protocol_utils_unittest.cc
index 38f0e527246..4c708edfe41 100644
--- a/chromium/components/autofill_assistant/browser/protocol_utils_unittest.cc
+++ b/chromium/components/autofill_assistant/browser/protocol_utils_unittest.cc
@@ -40,6 +40,8 @@ class ProtocolUtilsTest : public testing::Test {
client_context_proto_.set_is_direct_action(false);
client_context_proto_.set_accounts_matching_status(
ClientContextProto::UNKNOWN);
+ client_context_proto_.set_country("US");
+ client_context_proto_.set_locale("en-US");
}
~ProtocolUtilsTest() override {}
@@ -158,6 +160,31 @@ TEST_F(ProtocolUtilsTest, CreateGetScriptsRequest) {
EXPECT_EQ("http://example.com/", request.url());
}
+TEST_F(ProtocolUtilsTest, CreateCapabilitiesByHashRequest) {
+ ScriptParameters parameters = {
+ {{"key_a", "value_a"}, {"INTENT", "DUMMY_INTENT"}}};
+
+ GetCapabilitiesByHashPrefixRequestProto request;
+ EXPECT_TRUE(
+ request.ParseFromString(ProtocolUtils::CreateCapabilitiesByHashRequest(
+ 16U, {13ULL, 17ULL}, client_context_proto_, parameters)));
+
+ // Note: We can only send the following approved fields on the client_context:
+ ClientContextProto client_context;
+ client_context.set_locale(client_context_proto_.locale());
+ client_context.set_country(client_context_proto_.country());
+ client_context.mutable_chrome()->set_chrome_version(
+ client_context_proto_.chrome().chrome_version());
+ EXPECT_EQ(client_context, request.client_context());
+
+ EXPECT_EQ(request.hash_prefix_length(), 16U);
+ EXPECT_THAT(request.hash_prefix(), ElementsAre(13ULL, 17ULL));
+ EXPECT_THAT(
+ request.script_parameters(),
+ UnorderedElementsAreArray(base::flat_map<std::string, std::string>{
+ {"INTENT", "DUMMY_INTENT"}}));
+}
+
TEST_F(ProtocolUtilsTest, AddScriptIgnoreInvalid) {
SupportedScriptProto script_proto;
std::vector<std::unique_ptr<Script>> scripts;
@@ -357,7 +384,7 @@ TEST_F(ProtocolUtilsTest, ParseTriggerScriptsValid) {
ASSERT_THAT(script_parameters, Ne(absl::nullopt));
EXPECT_THAT((*script_parameters)
->ToProto(
- /* only_trigger_script_allowlisted = */ false),
+ /* only_non_sensitive_allowlisted = */ false),
ElementsAre(std::make_pair("param_1", "value_1"),
std::make_pair("param_2", "value_2")));
}
@@ -523,4 +550,38 @@ TEST_F(ProtocolUtilsTest, ValidateTriggerConditionsComplexConditions) {
EXPECT_FALSE(ProtocolUtils::ValidateTriggerCondition(condition));
}
+TEST_F(ProtocolUtilsTest, ParseFromString) {
+ TellProto tell;
+ tell.set_message("test");
+ std::string bytes;
+ tell.SerializeToString(&bytes);
+
+ ActionProto expected;
+ *expected.mutable_tell() = tell;
+
+ EXPECT_THAT(ProtocolUtils::ParseFromString(11, bytes, nullptr),
+ Optional(expected));
+}
+
+TEST_F(ProtocolUtilsTest, ParseFromStringUnknownAction) {
+ EXPECT_THAT(ProtocolUtils::ParseFromString(0, "ignored", nullptr),
+ Optional(ActionProto::default_instance()));
+}
+
+TEST_F(ProtocolUtilsTest, ParseFromStringUnsupportedActionId) {
+ // This case simulates getting an action id that the client doesn't yet
+ // understand.
+ EXPECT_THAT(ProtocolUtils::ParseFromString(9999, "", nullptr),
+ Optional(ActionProto::default_instance()));
+}
+
+TEST_F(ProtocolUtilsTest, ParseFromStringBadActionId) {
+ EXPECT_THAT(ProtocolUtils::ParseFromString(-1, "", nullptr),
+ Optional(ActionProto::default_instance()));
+}
+
+TEST_F(ProtocolUtilsTest, ParseFromStringCannotParse) {
+ ASSERT_FALSE(ProtocolUtils::ParseFromString(11, "\xff\xff\xff", nullptr));
+}
+
} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/public/BUILD.gn b/chromium/components/autofill_assistant/browser/public/BUILD.gn
index b54b81b12c2..9fd7d383584 100644
--- a/chromium/components/autofill_assistant/browser/public/BUILD.gn
+++ b/chromium/components/autofill_assistant/browser/public/BUILD.gn
@@ -4,6 +4,9 @@
static_library("public") {
sources = [
+ "autofill_assistant.cc",
+ "autofill_assistant.h",
+ "autofill_assistant_factory.h",
"runtime_manager.cc",
"runtime_manager.h",
"runtime_manager_impl.cc",
@@ -14,6 +17,7 @@ static_library("public") {
deps = [
"//base",
+ "//components/version_info:channel",
"//content/public/browser",
]
}
diff --git a/chromium/components/autofill_assistant/browser/public/autofill_assistant.cc b/chromium/components/autofill_assistant/browser/public/autofill_assistant.cc
new file mode 100644
index 00000000000..ffc177ef707
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/public/autofill_assistant.cc
@@ -0,0 +1,23 @@
+// Copyright 2022 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.
+
+#include "components/autofill_assistant/browser/public/autofill_assistant.h"
+
+#include "base/containers/flat_map.h"
+
+namespace autofill_assistant {
+
+AutofillAssistant::CapabilitiesInfo::CapabilitiesInfo() = default;
+AutofillAssistant::CapabilitiesInfo::CapabilitiesInfo(
+ const std::string& url,
+ const base::flat_map<std::string, std::string>& script_parameters)
+ : url(url), script_parameters(script_parameters) {}
+AutofillAssistant::CapabilitiesInfo::~CapabilitiesInfo() = default;
+AutofillAssistant::CapabilitiesInfo::CapabilitiesInfo(
+ const CapabilitiesInfo& other) = default;
+AutofillAssistant::CapabilitiesInfo&
+AutofillAssistant::CapabilitiesInfo::operator=(const CapabilitiesInfo& other) =
+ default;
+
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/public/autofill_assistant.h b/chromium/components/autofill_assistant/browser/public/autofill_assistant.h
new file mode 100644
index 00000000000..be84bfedda1
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/public/autofill_assistant.h
@@ -0,0 +1,56 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_PUBLIC_AUTOFILL_ASSISTANT_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_PUBLIC_AUTOFILL_ASSISTANT_H_
+
+#include <string>
+#include <vector>
+
+#include "base/callback_forward.h"
+#include "base/containers/flat_map.h"
+
+namespace autofill_assistant {
+
+// Abstract interface for exported services.
+class AutofillAssistant {
+ public:
+ struct CapabilitiesInfo {
+ CapabilitiesInfo();
+ CapabilitiesInfo(
+ const std::string& url,
+ const base::flat_map<std::string, std::string>& script_parameters);
+ ~CapabilitiesInfo();
+ CapabilitiesInfo(const CapabilitiesInfo& other);
+ CapabilitiesInfo& operator=(const CapabilitiesInfo& other);
+
+ std::string url;
+ base::flat_map<std::string, std::string> script_parameters;
+ };
+
+ using GetCapabilitiesResponseCallback =
+ base::OnceCallback<void(int http_status,
+ const std::vector<CapabilitiesInfo>&)>;
+
+ virtual ~AutofillAssistant() = default;
+
+ // Allows querying for domain capabilities by sending the |hash_prefix_length|
+ // number of leading bits of the domain url hashes. CityHash64 should be used
+ // to calculate the hashes and only the leading |hash_prefix_length| bits
+ // should be sent.
+ // |intent| should contain the string representation of the enum:
+ // https://source.corp.google.com/piper///depot/google3/quality/genie/autobot/dev/proto/script/intent.proto
+ virtual void GetCapabilitiesByHashPrefix(
+ uint32_t hash_prefix_length,
+ const std::vector<uint64_t>& hash_prefix,
+ const std::string& intent,
+ GetCapabilitiesResponseCallback callback) = 0;
+
+ protected:
+ AutofillAssistant() = default;
+};
+
+} // namespace autofill_assistant
+
+#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_PUBLIC_AUTOFILL_ASSISTANT_H_
diff --git a/chromium/components/autofill_assistant/browser/public/autofill_assistant_factory.h b/chromium/components/autofill_assistant/browser/public/autofill_assistant_factory.h
new file mode 100644
index 00000000000..b96790f9db1
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/public/autofill_assistant_factory.h
@@ -0,0 +1,24 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_PUBLIC_AUTOFILL_ASSISTANT_FACTORY_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_PUBLIC_AUTOFILL_ASSISTANT_FACTORY_H_
+
+#include "components/autofill_assistant/browser/public/autofill_assistant.h"
+#include "components/version_info/channel.h"
+#include "content/public/browser/browser_context.h"
+
+namespace autofill_assistant {
+// Creates an instance of |AutofillAssistant|.
+class AutofillAssistantFactory {
+ public:
+ static std::unique_ptr<AutofillAssistant> CreateForBrowserContext(
+ content::BrowserContext* browser_context,
+ version_info::Channel channel,
+ const std::string& country_code,
+ const std::string& locale);
+};
+} // namespace autofill_assistant
+
+#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_PUBLIC_AUTOFILL_ASSISTANT_FACTORY_H_
diff --git a/chromium/components/autofill_assistant/browser/public/runtime_manager_impl.cc b/chromium/components/autofill_assistant/browser/public/runtime_manager_impl.cc
index 7b316e211c9..39daea09e3f 100644
--- a/chromium/components/autofill_assistant/browser/public/runtime_manager_impl.cc
+++ b/chromium/components/autofill_assistant/browser/public/runtime_manager_impl.cc
@@ -14,7 +14,8 @@ RuntimeManagerImpl* RuntimeManagerImpl::GetForWebContents(
return RuntimeManagerImpl::FromWebContents(contents);
}
-RuntimeManagerImpl::RuntimeManagerImpl(content::WebContents* web_contents) {}
+RuntimeManagerImpl::RuntimeManagerImpl(content::WebContents* web_contents)
+ : content::WebContentsUserData<RuntimeManagerImpl>(*web_contents) {}
RuntimeManagerImpl::~RuntimeManagerImpl() = default;
diff --git a/chromium/components/autofill_assistant/browser/script_executor.cc b/chromium/components/autofill_assistant/browser/script_executor.cc
index 345cc777d49..6c87739930d 100644
--- a/chromium/components/autofill_assistant/browser/script_executor.cc
+++ b/chromium/components/autofill_assistant/browser/script_executor.cc
@@ -12,6 +12,7 @@
#include "base/bind.h"
#include "base/callback.h"
#include "base/callback_helpers.h"
+#include "base/containers/flat_map.h"
#include "base/task/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
@@ -71,7 +72,8 @@ ScriptExecutor::ScriptExecutor(
const std::string& script_payload,
ScriptExecutor::Listener* listener,
const std::vector<std::unique_ptr<Script>>* ordered_interrupts,
- ScriptExecutorDelegate* delegate)
+ ScriptExecutorDelegate* delegate,
+ ScriptExecutorUiDelegate* ui_delegate)
: script_path_(script_path),
additional_context_(std::move(additional_context)),
last_global_payload_(global_payload),
@@ -79,10 +81,12 @@ ScriptExecutor::ScriptExecutor(
last_script_payload_(script_payload),
listener_(listener),
delegate_(delegate),
+ ui_delegate_(ui_delegate),
ordered_interrupts_(ordered_interrupts),
element_store_(
std::make_unique<ElementStore>(delegate->GetWebContents())) {
DCHECK(delegate_);
+ DCHECK(ui_delegate_);
DCHECK(ordered_interrupts_);
}
@@ -194,13 +198,13 @@ void ScriptExecutor::OnPause(const std::string& message,
}
}
- delegate_->ClearInfoBox();
- delegate_->SetDetails(nullptr, base::TimeDelta());
- delegate_->SetCollectUserDataOptions(nullptr);
- delegate_->SetForm(nullptr, base::DoNothing(), base::DoNothing());
+ ui_delegate_->ClearInfoBox();
+ ui_delegate_->SetDetails(nullptr, base::TimeDelta());
+ ui_delegate_->SetCollectUserDataOptions(nullptr);
+ ui_delegate_->SetForm(nullptr, base::DoNothing(), base::DoNothing());
last_status_message_ = GetStatusMessage();
- delegate_->SetStatusMessage(message);
+ ui_delegate_->SetStatusMessage(message);
auto user_actions = std::make_unique<std::vector<UserAction>>();
@@ -213,7 +217,7 @@ void ScriptExecutor::OnPause(const std::string& message,
weak_ptr_factory_.GetWeakPtr()));
user_actions->emplace_back(std::move(undo_action));
- delegate_->SetUserActions(std::move(user_actions));
+ ui_delegate_->SetUserActions(std::move(user_actions));
delegate_->EnterState(AutofillAssistantState::STOPPED);
is_paused_ = true;
}
@@ -223,7 +227,7 @@ void ScriptExecutor::OnResume() {
is_paused_ = false;
delegate_->EnterState(AutofillAssistantState::RUNNING);
- delegate_->SetStatusMessage(last_status_message_);
+ ui_delegate_->SetStatusMessage(last_status_message_);
if (!current_action_index_.has_value()) {
ProcessNextAction();
@@ -238,9 +242,11 @@ void ScriptExecutor::ShortWaitForElement(
const Selector& selector,
base::OnceCallback<void(const ClientStatus&, base::TimeDelta)> callback) {
current_action_data_.wait_for_dom = std::make_unique<WaitForDomOperation>(
- this, delegate_, delegate_->GetSettings().short_wait_for_element_deadline,
+ this, delegate_, ui_delegate_,
+ delegate_->GetSettings().short_wait_for_element_deadline,
+ /* allow_observer_mode */ true,
/* allow_interrupt= */ false, /* observer= */ nullptr,
- base::BindRepeating(&ScriptExecutor::CheckElementMatches,
+ base::BindRepeating(&ScriptExecutor::CheckElementConditionMatches,
weak_ptr_factory_.GetWeakPtr(), selector),
base::BindOnce(&ScriptExecutor::OnShortWaitForElement,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
@@ -251,9 +257,11 @@ void ScriptExecutor::ShortWaitForElementWithSlowWarning(
const Selector& selector,
base::OnceCallback<void(const ClientStatus&, base::TimeDelta)> callback) {
current_action_data_.wait_for_dom = std::make_unique<WaitForDomOperation>(
- this, delegate_, delegate_->GetSettings().short_wait_for_element_deadline,
+ this, delegate_, ui_delegate_,
+ delegate_->GetSettings().short_wait_for_element_deadline,
+ /* allow_observer_mode */ true,
/* allow_interrupt= */ false, /* observer= */ nullptr,
- base::BindRepeating(&ScriptExecutor::CheckElementMatches,
+ base::BindRepeating(&ScriptExecutor::CheckElementConditionMatches,
weak_ptr_factory_.GetWeakPtr(), selector),
base::BindOnce(&ScriptExecutor::OnShortWaitForElement,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
@@ -265,6 +273,7 @@ void ScriptExecutor::ShortWaitForElementWithSlowWarning(
void ScriptExecutor::WaitForDom(
base::TimeDelta max_wait_time,
+ bool allow_observer_mode,
bool allow_interrupt,
WaitForDomObserver* observer,
base::RepeatingCallback<void(BatchElementChecker*,
@@ -272,7 +281,8 @@ void ScriptExecutor::WaitForDom(
check_elements,
base::OnceCallback<void(const ClientStatus&, base::TimeDelta)> callback) {
current_action_data_.wait_for_dom = std::make_unique<WaitForDomOperation>(
- this, delegate_, max_wait_time, allow_interrupt, observer, check_elements,
+ this, delegate_, ui_delegate_, max_wait_time, allow_observer_mode,
+ allow_interrupt, observer, check_elements,
base::BindOnce(&ScriptExecutor::OnWaitForElementVisibleWithInterrupts,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
current_action_data_.wait_for_dom->Run();
@@ -287,7 +297,9 @@ void ScriptExecutor::WaitForDomWithSlowWarning(
check_elements,
base::OnceCallback<void(const ClientStatus&, base::TimeDelta)> callback) {
current_action_data_.wait_for_dom = std::make_unique<WaitForDomOperation>(
- this, delegate_, max_wait_time, allow_interrupt, observer, check_elements,
+ this, delegate_, ui_delegate_, max_wait_time,
+ /* allow_observer_mode= */ true, allow_interrupt, observer,
+ check_elements,
base::BindOnce(&ScriptExecutor::OnWaitForElementVisibleWithInterrupts,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
current_action_data_.wait_for_dom->SetTimeoutWarningCallback(
@@ -297,31 +309,31 @@ void ScriptExecutor::WaitForDomWithSlowWarning(
}
void ScriptExecutor::SetStatusMessage(const std::string& message) {
- delegate_->SetStatusMessage(message);
+ ui_delegate_->SetStatusMessage(message);
}
std::string ScriptExecutor::GetStatusMessage() const {
- return delegate_->GetStatusMessage();
+ return ui_delegate_->GetStatusMessage();
}
void ScriptExecutor::SetBubbleMessage(const std::string& message) {
- delegate_->SetBubbleMessage(message);
+ ui_delegate_->SetBubbleMessage(message);
}
std::string ScriptExecutor::GetBubbleMessage() const {
- return delegate_->GetBubbleMessage();
+ return ui_delegate_->GetBubbleMessage();
}
void ScriptExecutor::SetTtsMessage(const std::string& message) {
- delegate_->SetTtsMessage(message);
+ ui_delegate_->SetTtsMessage(message);
}
TtsButtonState ScriptExecutor::GetTtsButtonState() const {
- return delegate_->GetTtsButtonState();
+ return ui_delegate_->GetTtsButtonState();
}
void ScriptExecutor::MaybePlayTtsMessage() {
- delegate_->MaybePlayTtsMessage();
+ ui_delegate_->MaybePlayTtsMessage();
}
void ScriptExecutor::FindElement(const Selector& selector,
@@ -350,19 +362,19 @@ void ScriptExecutor::CollectUserData(
base::BindOnce(&ScriptExecutor::OnTermsAndConditionsLinkClicked,
weak_ptr_factory_.GetWeakPtr(),
std::move(collect_user_data_options->terms_link_callback));
- delegate_->SetCollectUserDataOptions(collect_user_data_options);
+ ui_delegate_->SetCollectUserDataOptions(collect_user_data_options);
delegate_->EnterState(AutofillAssistantState::PROMPT);
}
void ScriptExecutor::SetLastSuccessfulUserDataOptions(
std::unique_ptr<CollectUserDataOptions> collect_user_data_options) {
- delegate_->SetLastSuccessfulUserDataOptions(
+ ui_delegate_->SetLastSuccessfulUserDataOptions(
std::move(collect_user_data_options));
}
const CollectUserDataOptions* ScriptExecutor::GetLastSuccessfulUserDataOptions()
const {
- return delegate_->GetLastSuccessfulUserDataOptions();
+ return ui_delegate_->GetLastSuccessfulUserDataOptions();
}
void ScriptExecutor::WriteUserData(
@@ -376,7 +388,7 @@ void ScriptExecutor::OnGetUserData(
UserData* user_data,
const UserModel* user_model) {
delegate_->EnterState(AutofillAssistantState::RUNNING);
- delegate_->SetUserActions(nullptr);
+ ui_delegate_->SetUserActions(nullptr);
std::move(callback).Run(user_data, user_model);
}
@@ -433,7 +445,7 @@ void ScriptExecutor::Prompt(
bool browse_mode_invisible) {
// First communicate to the delegate that prompt actions should or should not
// expand the sheet intitially.
- delegate_->SetExpandSheetForPromptAction(!disable_force_expand_sheet);
+ ui_delegate_->SetExpandSheetForPromptAction(!disable_force_expand_sheet);
delegate_->SetBrowseModeInvisible(browse_mode_invisible);
if (browse_mode) {
delegate_->EnterState(AutofillAssistantState::BROWSE);
@@ -456,18 +468,18 @@ void ScriptExecutor::Prompt(
}
if (user_actions != nullptr) {
- delegate_->SetUserActions(std::move(user_actions));
+ ui_delegate_->SetUserActions(std::move(user_actions));
}
}
void ScriptExecutor::CleanUpAfterPrompt() {
- delegate_->SetUserActions(nullptr);
+ ui_delegate_->SetUserActions(nullptr);
// Mark touchable_elements_ as consumed, so that it won't affect the next
// prompt or the end of the script.
touchable_element_area_.reset();
delegate_->ClearTouchableElementArea();
- delegate_->SetExpandSheetForPromptAction(true);
+ ui_delegate_->SetExpandSheetForPromptAction(true);
delegate_->SetBrowseModeInvisible(false);
delegate_->EnterState(AutofillAssistantState::RUNNING);
}
@@ -499,24 +511,24 @@ void ScriptExecutor::SetTouchableElementArea(
bool ScriptExecutor::SetProgressActiveStepIdentifier(
const std::string& active_step_identifier) {
- return delegate_->SetProgressActiveStepIdentifier(active_step_identifier);
+ return ui_delegate_->SetProgressActiveStepIdentifier(active_step_identifier);
}
void ScriptExecutor::SetProgressActiveStep(int active_step) {
- delegate_->SetProgressActiveStep(active_step);
+ ui_delegate_->SetProgressActiveStep(active_step);
}
void ScriptExecutor::SetProgressVisible(bool visible) {
- delegate_->SetProgressVisible(visible);
+ ui_delegate_->SetProgressVisible(visible);
}
void ScriptExecutor::SetProgressBarErrorState(bool error) {
- delegate_->SetProgressBarErrorState(error);
+ ui_delegate_->SetProgressBarErrorState(error);
}
void ScriptExecutor::SetStepProgressBarConfiguration(
const ShowProgressBarProto::StepProgressBarConfiguration& configuration) {
- delegate_->SetStepProgressBarConfiguration(configuration);
+ ui_delegate_->SetStepProgressBarConfiguration(configuration);
}
void ScriptExecutor::ExpectNavigation() {
@@ -592,7 +604,7 @@ void ScriptExecutor::Shutdown(bool show_feedback_chip) {
// differently from just stop. TODO(b/806868): Make that difference explicit:
// add an optional message to stop and update the scripts to use that.
if (previous_action_type_ == ActionProto::kTell) {
- delegate_->SetShowFeedbackChip(show_feedback_chip);
+ ui_delegate_->SetShowFeedbackChip(show_feedback_chip);
at_end_ = SHUTDOWN_GRACEFULLY;
} else {
at_end_ = SHUTDOWN;
@@ -612,6 +624,11 @@ WebsiteLoginManager* ScriptExecutor::GetWebsiteLoginManager() const {
return delegate_->GetWebsiteLoginManager();
}
+password_manager::PasswordChangeSuccessTracker*
+ScriptExecutor::GetPasswordChangeSuccessTracker() const {
+ return delegate_->GetPasswordChangeSuccessTracker();
+}
+
content::WebContents* ScriptExecutor::GetWebContents() const {
return delegate_->GetWebContents();
}
@@ -634,20 +651,20 @@ ukm::UkmRecorder* ScriptExecutor::GetUkmRecorder() const {
void ScriptExecutor::SetDetails(std::unique_ptr<Details> details,
base::TimeDelta delay) {
- return delegate_->SetDetails(std::move(details), delay);
+ return ui_delegate_->SetDetails(std::move(details), delay);
}
void ScriptExecutor::AppendDetails(std::unique_ptr<Details> details,
base::TimeDelta delay) {
- return delegate_->AppendDetails(std::move(details), delay);
+ return ui_delegate_->AppendDetails(std::move(details), delay);
}
void ScriptExecutor::ClearInfoBox() {
- delegate_->ClearInfoBox();
+ ui_delegate_->ClearInfoBox();
}
void ScriptExecutor::SetInfoBox(const InfoBox& info_box) {
- delegate_->SetInfoBox(info_box);
+ ui_delegate_->SetInfoBox(info_box);
}
void ScriptExecutor::SetViewportMode(ViewportMode mode) {
@@ -660,19 +677,19 @@ ViewportMode ScriptExecutor::GetViewportMode() const {
void ScriptExecutor::SetPeekMode(
ConfigureBottomSheetProto::PeekMode peek_mode) {
- delegate_->SetPeekMode(peek_mode);
+ ui_delegate_->SetPeekMode(peek_mode);
}
ConfigureBottomSheetProto::PeekMode ScriptExecutor::GetPeekMode() const {
- return delegate_->GetPeekMode();
+ return ui_delegate_->GetPeekMode();
}
void ScriptExecutor::ExpandBottomSheet() {
- return delegate_->ExpandBottomSheet();
+ return ui_delegate_->ExpandBottomSheet();
}
void ScriptExecutor::CollapseBottomSheet() {
- return delegate_->CollapseBottomSheet();
+ return ui_delegate_->CollapseBottomSheet();
}
void ScriptExecutor::WaitForWindowHeightChange(
@@ -693,8 +710,8 @@ bool ScriptExecutor::SetForm(
std::unique_ptr<FormProto> form,
base::RepeatingCallback<void(const FormProto::Result*)> changed_callback,
base::OnceCallback<void(const ClientStatus&)> cancel_callback) {
- return delegate_->SetForm(std::move(form), std::move(changed_callback),
- std::move(cancel_callback));
+ return ui_delegate_->SetForm(std::move(form), std::move(changed_callback),
+ std::move(cancel_callback));
}
void ScriptExecutor::RequireUI() {
@@ -706,24 +723,25 @@ void ScriptExecutor::SetGenericUi(
base::OnceCallback<void(const ClientStatus&)> end_action_callback,
base::OnceCallback<void(const ClientStatus&)>
view_inflation_finished_callback) {
- delegate_->SetGenericUi(std::move(generic_ui), std::move(end_action_callback),
- std::move(view_inflation_finished_callback));
+ ui_delegate_->SetGenericUi(std::move(generic_ui),
+ std::move(end_action_callback),
+ std::move(view_inflation_finished_callback));
}
void ScriptExecutor::SetPersistentGenericUi(
std::unique_ptr<GenericUserInterfaceProto> generic_ui,
base::OnceCallback<void(const ClientStatus&)>
view_inflation_finished_callback) {
- delegate_->SetPersistentGenericUi(
+ ui_delegate_->SetPersistentGenericUi(
std::move(generic_ui), std::move(view_inflation_finished_callback));
}
void ScriptExecutor::ClearGenericUi() {
- delegate_->ClearGenericUi();
+ ui_delegate_->ClearGenericUi();
}
void ScriptExecutor::ClearPersistentGenericUi() {
- delegate_->ClearPersistentGenericUi();
+ ui_delegate_->ClearPersistentGenericUi();
}
void ScriptExecutor::SetOverlayBehavior(
@@ -892,7 +910,9 @@ void ScriptExecutor::RunCallback(bool success) {
Result result;
result.success = success;
result.at_end = at_end_;
- result.touchable_element_area = std::move(touchable_element_area_);
+ if (touchable_element_area_) {
+ SetTouchableElementArea(*touchable_element_area_);
+ }
RunCallbackWithResult(result);
}
@@ -995,12 +1015,15 @@ void ScriptExecutor::OnProcessedAction(
ProcessNextAction();
}
-void ScriptExecutor::CheckElementMatches(
+void ScriptExecutor::CheckElementConditionMatches(
const Selector& selector,
BatchElementChecker* checker,
base::OnceCallback<void(const ClientStatus&)> callback) {
- checker->AddElementCheck(
- selector, /* strict= */ false,
+ ElementConditionProto condition;
+ *condition.mutable_match() = selector.proto;
+ condition.set_require_unique_element(false);
+ checker->AddElementConditionCheck(
+ condition,
base::BindOnce(&ScriptExecutor::CheckElementMatchesCallback,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
@@ -1008,7 +1031,9 @@ void ScriptExecutor::CheckElementMatches(
void ScriptExecutor::CheckElementMatchesCallback(
base::OnceCallback<void(const ClientStatus&)> callback,
const ClientStatus& status,
- const ElementFinder::Result& ignored_element) {
+ const std::vector<std::string>& ignored_payloads,
+ const std::vector<std::string>& ignored_tags,
+ const base::flat_map<std::string, DomObjectFrameStack>& ignored_elements) {
std::move(callback).Run(status);
}
@@ -1046,7 +1071,9 @@ void ScriptExecutor::OnWaitForElementVisibleWithInterrupts(
ScriptExecutor::WaitForDomOperation::WaitForDomOperation(
ScriptExecutor* main_script,
ScriptExecutorDelegate* delegate,
+ ScriptExecutorUiDelegate* ui_delegate,
base::TimeDelta max_wait_time,
+ bool allow_observers,
bool allow_interrupt,
WaitForDomObserver* observer,
base::RepeatingCallback<void(BatchElementChecker*,
@@ -1055,8 +1082,13 @@ ScriptExecutor::WaitForDomOperation::WaitForDomOperation(
WaitForDomOperation::Callback callback)
: main_script_(main_script),
delegate_(delegate),
+ ui_delegate_(ui_delegate),
max_wait_time_(max_wait_time),
allow_interrupt_(allow_interrupt),
+ use_observers_(allow_observers && delegate->GetTriggerContext()
+ ->GetScriptParameters()
+ .GetEnableObserverWaitForDom()
+ .value_or(false)),
observer_(observer),
check_elements_(std::move(check_elements)),
callback_(std::move(callback)),
@@ -1151,16 +1183,22 @@ void ScriptExecutor::WaitForDomOperation::RunChecks(
FROM_HERE, timeout_warning_delay_,
base::BindOnce(&ScriptExecutor::WaitForDomOperation::TimeoutWarning,
weak_ptr_factory_.GetWeakPtr()));
- wait_time_total_ =
- (wait_time_stopwatch_.TotalElapsed() < retry_timer_.period())
- // It's the first run of the checks, set the total time waited to 0.
- ? base::Seconds(0)
- // If this is not the first run of the checks, in order to estimate
- // the real cost of periodic checks, half the duration of the retry
- // timer period is removed from the total wait time. This is to
- // account for the fact that the conditions could have been satisfied
- // at any point between the two consecutive checks.
- : wait_time_stopwatch_.TotalElapsed() - retry_timer_.period() / 2;
+
+ if (use_observers_) {
+ // Observers should stop soon after the elements are in the page.
+ wait_time_total_ = wait_time_stopwatch_.TotalElapsed();
+ } else if (wait_time_stopwatch_.TotalElapsed() < retry_timer_.period()) {
+ // It's the first run of the checks, set the total time waited to 0.
+ wait_time_total_ = base::Seconds(0);
+ } else {
+ // If this is not the first run of the checks, in order to estimate
+ // the real cost of periodic checks, half the duration of the retry
+ // timer period is removed from the total wait time. This is to
+ // account for the fact that the conditions could have been satisfied
+ // at any point between the two consecutive checks.
+ wait_time_total_ =
+ wait_time_stopwatch_.TotalElapsed() - retry_timer_.period() / 2;
+ }
// Reset state possibly left over from previous runs.
element_check_result_ = ClientStatus();
runnable_interrupts_.clear();
@@ -1188,6 +1226,15 @@ void ScriptExecutor::WaitForDomOperation::RunChecks(
batch_element_checker_->AddAllDoneCallback(
base::BindOnce(&WaitForDomOperation::OnAllChecksDone,
base::Unretained(this), std::move(report_attempt_result)));
+ if (use_observers_) {
+ batch_element_checker_->EnableObserver(
+ /* max_wait_time= */ max_wait_time_ -
+ wait_time_stopwatch_.TotalElapsed(),
+ /* periodic_check_interval= */
+ main_script_->delegate_->GetSettings().periodic_element_check_interval,
+ /* extra_timeout= */
+ main_script_->delegate_->GetSettings().selector_observer_extra_timeout);
+ }
batch_element_checker_->Run(delegate_->GetWebController());
}
@@ -1245,9 +1292,9 @@ void ScriptExecutor::WaitForDomOperation::RunInterrupt(
std::make_unique<TriggerContext>(std::vector<const TriggerContext*>{
main_script_->additional_context_.get()}),
main_script_->last_global_payload_, main_script_->initial_script_payload_,
- /* listener= */ this, &no_interrupts_, delegate_);
+ /* listener= */ this, &no_interrupts_, delegate_, ui_delegate_);
delegate_->EnterState(AutofillAssistantState::RUNNING);
- delegate_->SetUserActions(nullptr);
+ ui_delegate_->SetUserActions(nullptr);
// Note that we don't clear the touchable area in the delegate here.
// TODO(b/209732258): check whether this is a bug.
interrupt_executor_->Run(
@@ -1303,7 +1350,7 @@ void ScriptExecutor::WaitForDomOperation::SavePreInterruptState() {
return;
ExecutorState pre_interrupt_state;
- pre_interrupt_state.status_message = delegate_->GetStatusMessage();
+ pre_interrupt_state.status_message = ui_delegate_->GetStatusMessage();
pre_interrupt_state.controller_state = delegate_->GetState();
saved_pre_interrupt_state_ = pre_interrupt_state;
}
@@ -1312,7 +1359,7 @@ void ScriptExecutor::WaitForDomOperation::RestorePreInterruptState() {
if (!saved_pre_interrupt_state_)
return;
- delegate_->SetStatusMessage(saved_pre_interrupt_state_->status_message);
+ ui_delegate_->SetStatusMessage(saved_pre_interrupt_state_->status_message);
delegate_->EnterState(saved_pre_interrupt_state_->controller_state);
if (main_script_->touchable_element_area_) {
delegate_->SetTouchableElementArea(*main_script_->touchable_element_area_);
diff --git a/chromium/components/autofill_assistant/browser/script_executor.h b/chromium/components/autofill_assistant/browser/script_executor.h
index f71548dd86d..7d54cc58910 100644
--- a/chromium/components/autofill_assistant/browser/script_executor.h
+++ b/chromium/components/autofill_assistant/browser/script_executor.h
@@ -13,6 +13,7 @@
#include <vector>
#include "base/callback_forward.h"
+#include "base/containers/flat_map.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "components/autofill_assistant/browser/actions/action.h"
@@ -24,6 +25,7 @@
#include "components/autofill_assistant/browser/retry_timer.h"
#include "components/autofill_assistant/browser/script.h"
#include "components/autofill_assistant/browser/script_executor_delegate.h"
+#include "components/autofill_assistant/browser/script_executor_ui_delegate.h"
#include "components/autofill_assistant/browser/service.pb.h"
#include "components/autofill_assistant/browser/top_padding.h"
#include "components/autofill_assistant/browser/wait_for_dom_observer.h"
@@ -70,7 +72,8 @@ class ScriptExecutor : public ActionDelegate,
const std::string& script_payload,
ScriptExecutor::Listener* listener,
const std::vector<std::unique_ptr<Script>>* ordered_interrupts,
- ScriptExecutorDelegate* delegate);
+ ScriptExecutorDelegate* delegate,
+ ScriptExecutorUiDelegate* ui_delegate);
ScriptExecutor(const ScriptExecutor&) = delete;
ScriptExecutor& operator=(const ScriptExecutor&) = delete;
@@ -129,6 +132,7 @@ class ScriptExecutor : public ActionDelegate,
override;
void WaitForDom(
base::TimeDelta max_wait_time,
+ bool allow_observer_mode,
bool allow_interrupt,
WaitForDomObserver* observer,
base::RepeatingCallback<
@@ -204,6 +208,8 @@ class ScriptExecutor : public ActionDelegate,
void Close() override;
autofill::PersonalDataManager* GetPersonalDataManager() const override;
WebsiteLoginManager* GetWebsiteLoginManager() const override;
+ password_manager::PasswordChangeSuccessTracker*
+ GetPasswordChangeSuccessTracker() const override;
content::WebContents* GetWebContents() const override;
ElementStore* GetElementStore() const override;
WebController* GetWebController() const override;
@@ -279,7 +285,9 @@ class ScriptExecutor : public ActionDelegate,
WaitForDomOperation(
ScriptExecutor* main_script,
ScriptExecutorDelegate* delegate,
+ ScriptExecutorUiDelegate* ui_delegate,
base::TimeDelta max_wait_time,
+ bool allow_observer_mode,
bool allow_interrupt,
WaitForDomObserver* observer,
base::RepeatingCallback<
@@ -345,8 +353,10 @@ class ScriptExecutor : public ActionDelegate,
raw_ptr<ScriptExecutor> main_script_;
raw_ptr<ScriptExecutorDelegate> delegate_;
+ raw_ptr<ScriptExecutorUiDelegate> ui_delegate_;
const base::TimeDelta max_wait_time_;
const bool allow_interrupt_;
+ const bool use_observers_;
raw_ptr<WaitForDomObserver> observer_;
base::RepeatingCallback<void(BatchElementChecker*,
base::OnceCallback<void(const ClientStatus&)>)>
@@ -402,14 +412,16 @@ class ScriptExecutor : public ActionDelegate,
void GetNextActions();
void OnProcessedAction(base::TimeTicks start_time,
std::unique_ptr<ProcessedActionProto> action);
- void CheckElementMatches(
+ void CheckElementConditionMatches(
const Selector& selector,
BatchElementChecker* checker,
base::OnceCallback<void(const ClientStatus&)> callback);
void CheckElementMatchesCallback(
base::OnceCallback<void(const ClientStatus&)> callback,
const ClientStatus& status,
- const ElementFinder::Result& ignored_element);
+ const std::vector<std::string>& ignored_payloads,
+ const std::vector<std::string>& ignored_tags,
+ const base::flat_map<std::string, DomObjectFrameStack>& ignored_elements);
void OnShortWaitForElement(
base::OnceCallback<void(const ClientStatus&, base::TimeDelta)> callback,
const ClientStatus& element_status,
@@ -457,6 +469,7 @@ class ScriptExecutor : public ActionDelegate,
std::string last_script_payload_;
const raw_ptr<ScriptExecutor::Listener> listener_;
const raw_ptr<ScriptExecutorDelegate> delegate_;
+ const raw_ptr<ScriptExecutorUiDelegate> ui_delegate_;
// Set of interrupts that might run during wait for dom or prompt action with
// allow_interrupt. Sorted by priority; an interrupt that appears on the
// vector first should run first. Note that the content of this vector can
diff --git a/chromium/components/autofill_assistant/browser/script_executor_delegate.h b/chromium/components/autofill_assistant/browser/script_executor_delegate.h
index 8ada6c97140..1dc1e106bb7 100644
--- a/chromium/components/autofill_assistant/browser/script_executor_delegate.h
+++ b/chromium/components/autofill_assistant/browser/script_executor_delegate.h
@@ -25,6 +25,10 @@ namespace autofill {
class PersonalDataManager;
} // namespace autofill
+namespace password_manager {
+class PasswordChangeSuccessTracker;
+} // namespace password_manager
+
namespace content {
class WebContents;
} // namespace content
@@ -36,7 +40,6 @@ class WebController;
struct ClientSettings;
class TriggerContext;
class WebsiteLoginManager;
-class EventHandler;
class UserModel;
class ScriptExecutorDelegate {
@@ -64,6 +67,8 @@ class ScriptExecutorDelegate {
virtual const TriggerContext* GetTriggerContext() = 0;
virtual autofill::PersonalDataManager* GetPersonalDataManager() = 0;
virtual WebsiteLoginManager* GetWebsiteLoginManager() = 0;
+ virtual password_manager::PasswordChangeSuccessTracker*
+ GetPasswordChangeSuccessTracker() = 0;
virtual content::WebContents* GetWebContents() = 0;
virtual std::string GetEmailAddressForAccessTokenAccount() = 0;
virtual ukm::UkmRecorder* GetUkmRecorder() = 0;
@@ -71,68 +76,24 @@ class ScriptExecutorDelegate {
// Enters the given state. Returns true if the state was changed.
virtual bool EnterState(AutofillAssistantState state) = 0;
+ // Make the area of the screen that correspond to the given elements
+ // touchable.
+ virtual void SetTouchableElementArea(const ElementAreaProto& element) = 0;
+
// Returns the current state.
- virtual AutofillAssistantState GetState() = 0;
+ virtual AutofillAssistantState GetState() const = 0;
virtual void SetOverlayBehavior(
ConfigureUiStateProto::OverlayBehavior overlay_behavior) = 0;
- // Make the area of the screen that correspond to the given elements
- // touchable.
- virtual void SetTouchableElementArea(const ElementAreaProto& element) = 0;
- virtual void SetStatusMessage(const std::string& message) = 0;
- virtual std::string GetStatusMessage() const = 0;
- virtual void SetBubbleMessage(const std::string& message) = 0;
- virtual std::string GetBubbleMessage() const = 0;
- virtual void SetTtsMessage(const std::string& message) = 0;
- virtual std::string GetTtsMessage() const = 0;
- virtual TtsButtonState GetTtsButtonState() const = 0;
- virtual void MaybePlayTtsMessage() = 0;
- virtual void SetDetails(std::unique_ptr<Details> details,
- base::TimeDelta delay) = 0;
- virtual void AppendDetails(std::unique_ptr<Details> details,
- base::TimeDelta delay) = 0;
- virtual void SetInfoBox(const InfoBox& info_box) = 0;
- virtual void ClearInfoBox() = 0;
- virtual void SetCollectUserDataOptions(
- CollectUserDataOptions* collect_user_data_options) = 0;
- virtual void SetLastSuccessfulUserDataOptions(
- std::unique_ptr<CollectUserDataOptions> collect_user_data_options) = 0;
- virtual const CollectUserDataOptions* GetLastSuccessfulUserDataOptions()
- const = 0;
virtual void WriteUserData(
base::OnceCallback<void(UserData*, UserData::FieldChange*)>
write_callback) = 0;
- virtual bool SetProgressActiveStepIdentifier(
- const std::string& active_step_identifier) = 0;
- virtual void SetProgressActiveStep(int active_step) = 0;
- virtual void SetProgressVisible(bool visible) = 0;
- virtual void SetProgressBarErrorState(bool error) = 0;
- virtual void SetStepProgressBarConfiguration(
- const ShowProgressBarProto::StepProgressBarConfiguration&
- configuration) = 0;
- virtual void SetUserActions(
- std::unique_ptr<std::vector<UserAction>> user_action) = 0;
virtual ViewportMode GetViewportMode() = 0;
virtual void SetViewportMode(ViewportMode mode) = 0;
- virtual void SetPeekMode(ConfigureBottomSheetProto::PeekMode peek_mode) = 0;
- virtual ConfigureBottomSheetProto::PeekMode GetPeekMode() = 0;
- virtual void ExpandBottomSheet() = 0;
- virtual void CollapseBottomSheet() = 0;
virtual void SetClientSettings(
const ClientSettingsProto& client_settings) = 0;
- virtual bool SetForm(
- std::unique_ptr<FormProto> form,
- base::RepeatingCallback<void(const FormProto::Result*)> changed_callback,
- base::OnceCallback<void(const ClientStatus&)> cancel_callback) = 0;
virtual UserModel* GetUserModel() = 0;
- virtual EventHandler* GetEventHandler() = 0;
- virtual void SetShowFeedbackChip(bool show_feedback_chip) = 0;
-
- // Makes no area of the screen touchable.
- void ClearTouchableElementArea() {
- SetTouchableElementArea(ElementAreaProto::default_instance());
- }
// The next navigation is expected and will not cause an error.
virtual void ExpectNavigation() = 0;
@@ -160,6 +121,11 @@ class ScriptExecutorDelegate {
// Changes to this value is reported to Listener::OnNavigationStateChanged()
virtual bool HasNavigationError() = 0;
+ // Makes no area of the screen touchable.
+ void ClearTouchableElementArea() {
+ SetTouchableElementArea(ElementAreaProto::default_instance());
+ }
+
// Force showing the UI, if necessary. This is useful when executing a direct
// action which realizes it needs to interact with the user. The UI stays up
// until the end of the flow.
@@ -180,31 +146,9 @@ class ScriptExecutorDelegate {
// exists.
virtual void RemoveListener(Listener* listener) = 0;
- // Set how the sheet should behave when entering a prompt state.
- virtual void SetExpandSheetForPromptAction(bool expand) = 0;
-
// Set the domains allowlist for browse mode.
virtual void SetBrowseDomainsAllowlist(std::vector<std::string> domains) = 0;
- // Sets the generic UI to show to the user.
- virtual void SetGenericUi(
- std::unique_ptr<GenericUserInterfaceProto> generic_ui,
- base::OnceCallback<void(const ClientStatus&)> end_action_callback,
- base::OnceCallback<void(const ClientStatus&)>
- view_inflation_finished_callback) = 0;
-
- // Sets the persistent generic UI to show to the user.
- virtual void SetPersistentGenericUi(
- std::unique_ptr<GenericUserInterfaceProto> generic_ui,
- base::OnceCallback<void(const ClientStatus&)>
- view_inflation_finished_callback) = 0;
-
- // Clears the generic UI.
- virtual void ClearGenericUi() = 0;
-
- // Clears the persistent generic UI.
- virtual void ClearPersistentGenericUi() = 0;
-
// Sets whether browse mode should be invisible or not. Must be set before
// calling |EnterState(BROWSE)| to take effect.
virtual void SetBrowseModeInvisible(bool invisible) = 0;
diff --git a/chromium/components/autofill_assistant/browser/script_executor_ui_delegate.h b/chromium/components/autofill_assistant/browser/script_executor_ui_delegate.h
new file mode 100644
index 00000000000..8e5512b4874
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/script_executor_ui_delegate.h
@@ -0,0 +1,95 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SCRIPT_EXECUTOR_UI_DELEGATE_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SCRIPT_EXECUTOR_UI_DELEGATE_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/observer_list_types.h"
+#include "components/autofill_assistant/browser/client_status.h"
+#include "components/autofill_assistant/browser/details.h"
+#include "components/autofill_assistant/browser/info_box.h"
+#include "components/autofill_assistant/browser/state.h"
+#include "components/autofill_assistant/browser/tts_button_state.h"
+#include "components/autofill_assistant/browser/user_action.h"
+#include "components/autofill_assistant/browser/user_data.h"
+#include "url/gurl.h"
+
+namespace autofill_assistant {
+
+// A delegate which provides the ScriptExecutor with methods to control the
+// Autofill Assistant UI.
+class ScriptExecutorUiDelegate {
+ public:
+ virtual void SetStatusMessage(const std::string& message) = 0;
+ virtual std::string GetStatusMessage() const = 0;
+ virtual void SetBubbleMessage(const std::string& message) = 0;
+ virtual std::string GetBubbleMessage() const = 0;
+ virtual void SetTtsMessage(const std::string& message) = 0;
+ virtual std::string GetTtsMessage() const = 0;
+ virtual TtsButtonState GetTtsButtonState() const = 0;
+ virtual void MaybePlayTtsMessage() = 0;
+ virtual void SetDetails(std::unique_ptr<Details> details,
+ base::TimeDelta delay) = 0;
+ virtual void AppendDetails(std::unique_ptr<Details> details,
+ base::TimeDelta delay) = 0;
+ virtual void SetInfoBox(const InfoBox& info_box) = 0;
+ virtual void ClearInfoBox() = 0;
+ virtual void SetCollectUserDataOptions(
+ CollectUserDataOptions* collect_user_data_options) = 0;
+ virtual void SetLastSuccessfulUserDataOptions(
+ std::unique_ptr<CollectUserDataOptions> collect_user_data_options) = 0;
+ virtual const CollectUserDataOptions* GetLastSuccessfulUserDataOptions()
+ const = 0;
+ virtual bool SetProgressActiveStepIdentifier(
+ const std::string& active_step_identifier) = 0;
+ virtual void SetProgressActiveStep(int active_step) = 0;
+ virtual void SetProgressVisible(bool visible) = 0;
+ virtual void SetProgressBarErrorState(bool error) = 0;
+ virtual void SetStepProgressBarConfiguration(
+ const ShowProgressBarProto::StepProgressBarConfiguration&
+ configuration) = 0;
+ virtual void SetUserActions(
+ std::unique_ptr<std::vector<UserAction>> user_action) = 0;
+ virtual void SetPeekMode(ConfigureBottomSheetProto::PeekMode peek_mode) = 0;
+ virtual ConfigureBottomSheetProto::PeekMode GetPeekMode() = 0;
+ virtual void ExpandBottomSheet() = 0;
+ virtual void CollapseBottomSheet() = 0;
+ virtual bool SetForm(
+ std::unique_ptr<FormProto> form,
+ base::RepeatingCallback<void(const FormProto::Result*)> changed_callback,
+ base::OnceCallback<void(const ClientStatus&)> cancel_callback) = 0;
+ virtual void SetShowFeedbackChip(bool show_feedback_chip) = 0;
+
+ // Set how the sheet should behave when entering a prompt state.
+ virtual void SetExpandSheetForPromptAction(bool expand) = 0;
+
+ // Sets the generic UI to show to the user.
+ virtual void SetGenericUi(
+ std::unique_ptr<GenericUserInterfaceProto> generic_ui,
+ base::OnceCallback<void(const ClientStatus&)> end_action_callback,
+ base::OnceCallback<void(const ClientStatus&)>
+ view_inflation_finished_callback) = 0;
+
+ // Sets the persistent generic UI to show to the user.
+ virtual void SetPersistentGenericUi(
+ std::unique_ptr<GenericUserInterfaceProto> generic_ui,
+ base::OnceCallback<void(const ClientStatus&)>
+ view_inflation_finished_callback) = 0;
+
+ // Clears the generic UI.
+ virtual void ClearGenericUi() = 0;
+
+ // Clears the persistent generic UI.
+ virtual void ClearPersistentGenericUi() = 0;
+
+ protected:
+ virtual ~ScriptExecutorUiDelegate() {}
+};
+} // namespace autofill_assistant
+
+#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SCRIPT_EXECUTOR_UI_DELEGATE_H_
diff --git a/chromium/components/autofill_assistant/browser/script_executor_unittest.cc b/chromium/components/autofill_assistant/browser/script_executor_unittest.cc
index 2e3b4fe5974..0f020ed2d8f 100644
--- a/chromium/components/autofill_assistant/browser/script_executor_unittest.cc
+++ b/chromium/components/autofill_assistant/browser/script_executor_unittest.cc
@@ -13,6 +13,7 @@
#include "base/test/task_environment.h"
#include "components/autofill_assistant/browser/actions/action_test_utils.h"
#include "components/autofill_assistant/browser/fake_script_executor_delegate.h"
+#include "components/autofill_assistant/browser/fake_script_executor_ui_delegate.h"
#include "components/autofill_assistant/browser/service/mock_service.h"
#include "components/autofill_assistant/browser/service/service.h"
#include "components/autofill_assistant/browser/test_util.h"
@@ -74,7 +75,7 @@ class ScriptExecutorTest : public testing::Test,
/* global_payload= */ "initial global payload",
/* script_payload= */ "initial payload",
/* listener= */ this, &ordered_interrupts_,
- /* delegate= */ &delegate_);
+ /* delegate= */ &delegate_, /* ui_delegate= */ &ui_delegate_);
test_util::MockFindAnyElement(mock_web_controller_);
}
@@ -156,6 +157,7 @@ class ScriptExecutorTest : public testing::Test,
// creation run in that environment.
base::test::TaskEnvironment task_environment_;
FakeScriptExecutorDelegate delegate_;
+ FakeScriptExecutorUiDelegate ui_delegate_;
Script script_;
StrictMock<MockService> mock_service_;
NiceMock<MockWebController> mock_web_controller_;
@@ -295,10 +297,10 @@ TEST_F(ScriptExecutorTest, ShowsSlowConnectionWarningReplace) {
EXPECT_CALL(executor_callback_,
Run(Field(&ScriptExecutor::Result::success, true)));
executor_->Run(&user_data_, executor_callback_.Get());
- EXPECT_EQ(delegate_.GetStatusMessage(), "slow");
+ EXPECT_EQ(ui_delegate_.GetStatusMessage(), "slow");
task_environment_.FastForwardBy(
task_environment_.NextMainThreadPendingTaskDelay());
- EXPECT_EQ(delegate_.GetStatusMessage(), "2");
+ EXPECT_EQ(ui_delegate_.GetStatusMessage(), "2");
}
TEST_F(ScriptExecutorTest, ShowsSlowConnectionWarningConcatenate) {
@@ -328,10 +330,10 @@ TEST_F(ScriptExecutorTest, ShowsSlowConnectionWarningConcatenate) {
Run(Field(&ScriptExecutor::Result::success, true)));
executor_->Run(&user_data_, executor_callback_.Get());
- EXPECT_EQ(delegate_.GetStatusMessage(), "1... slow");
+ EXPECT_EQ(ui_delegate_.GetStatusMessage(), "1... slow");
task_environment_.FastForwardBy(
task_environment_.NextMainThreadPendingTaskDelay());
- EXPECT_EQ(delegate_.GetStatusMessage(), "2");
+ EXPECT_EQ(ui_delegate_.GetStatusMessage(), "2");
}
TEST_F(ScriptExecutorTest, SlowConnectionWarningTriggersOnlyOnce) {
@@ -361,9 +363,9 @@ TEST_F(ScriptExecutorTest, SlowConnectionWarningTriggersOnlyOnce) {
EXPECT_CALL(executor_callback_,
Run(Field(&ScriptExecutor::Result::success, true)));
executor_->Run(&user_data_, executor_callback_.Get());
- EXPECT_EQ(delegate_.GetStatusMessage(), "slow");
+ EXPECT_EQ(ui_delegate_.GetStatusMessage(), "slow");
task_environment_.FastForwardBy(base::Milliseconds(100));
- EXPECT_EQ(delegate_.GetStatusMessage(), "2");
+ EXPECT_EQ(ui_delegate_.GetStatusMessage(), "2");
}
TEST_F(ScriptExecutorTest, SlowConnectionWarningTriggersMultipleTimes) {
@@ -394,11 +396,11 @@ TEST_F(ScriptExecutorTest, SlowConnectionWarningTriggersMultipleTimes) {
EXPECT_CALL(executor_callback_,
Run(Field(&ScriptExecutor::Result::success, true)));
executor_->Run(&user_data_, executor_callback_.Get());
- EXPECT_EQ(delegate_.GetStatusMessage(), "slow");
+ EXPECT_EQ(ui_delegate_.GetStatusMessage(), "slow");
task_environment_.FastForwardBy(base::Milliseconds(100));
- EXPECT_EQ(delegate_.GetStatusMessage(), "slow");
+ EXPECT_EQ(ui_delegate_.GetStatusMessage(), "slow");
task_environment_.FastForwardBy(base::Milliseconds(100));
- EXPECT_EQ(delegate_.GetStatusMessage(), "2");
+ EXPECT_EQ(ui_delegate_.GetStatusMessage(), "2");
}
TEST_F(ScriptExecutorTest, SlowConnectionWarningNotShowingIfNotConsecutive) {
@@ -426,7 +428,7 @@ TEST_F(ScriptExecutorTest, SlowConnectionWarningNotShowingIfNotConsecutive) {
Run(Field(&ScriptExecutor::Result::success, true)));
executor_->Run(&user_data_, executor_callback_.Get());
- EXPECT_NE(delegate_.GetStatusMessage(), "slow");
+ EXPECT_NE(ui_delegate_.GetStatusMessage(), "slow");
}
TEST_F(ScriptExecutorTest, SlowConnectionWarningNotShowingIfOnCompleted) {
@@ -450,7 +452,7 @@ TEST_F(ScriptExecutorTest, SlowConnectionWarningNotShowingIfOnCompleted) {
Run(Field(&ScriptExecutor::Result::success, true)));
executor_->Run(&user_data_, executor_callback_.Get());
- EXPECT_NE(delegate_.GetStatusMessage(), "slow");
+ EXPECT_NE(ui_delegate_.GetStatusMessage(), "slow");
}
TEST_F(ScriptExecutorTest, SlowConnectionWarningNotShownIfSlowWebsiteFirst) {
@@ -499,10 +501,10 @@ TEST_F(ScriptExecutorTest, SlowConnectionWarningNotShownIfSlowWebsiteFirst) {
EXPECT_CALL(executor_callback_,
Run(Field(&ScriptExecutor::Result::success, true)));
executor_->Run(&user_data_, executor_callback_.Get());
- EXPECT_EQ(delegate_.GetStatusMessage(), "slow website");
+ EXPECT_EQ(ui_delegate_.GetStatusMessage(), "slow website");
task_environment_.FastForwardBy(
task_environment_.NextMainThreadPendingTaskDelay());
- EXPECT_EQ(delegate_.GetStatusMessage(), "3");
+ EXPECT_EQ(ui_delegate_.GetStatusMessage(), "3");
}
TEST_F(ScriptExecutorTest, SlowWebsiteWarningReplace) {
@@ -524,7 +526,7 @@ TEST_F(ScriptExecutorTest, SlowWebsiteWarningReplace) {
.WillOnce(Delay(&task_environment_, 2000));
executor_->Run(&user_data_, executor_callback_.Get());
- EXPECT_EQ(delegate_.GetStatusMessage(), "slow");
+ EXPECT_EQ(ui_delegate_.GetStatusMessage(), "slow");
}
TEST_F(ScriptExecutorTest, SlowWebsiteWarningConcatenate) {
@@ -547,7 +549,7 @@ TEST_F(ScriptExecutorTest, SlowWebsiteWarningConcatenate) {
.WillOnce(Delay(&task_environment_, 2000));
executor_->Run(&user_data_, executor_callback_.Get());
- EXPECT_EQ(delegate_.GetStatusMessage(), "1... slow");
+ EXPECT_EQ(ui_delegate_.GetStatusMessage(), "1... slow");
}
TEST_F(ScriptExecutorTest, SlowWebsiteWarningTriggersOnlyOnce) {
@@ -590,10 +592,10 @@ TEST_F(ScriptExecutorTest, SlowWebsiteWarningTriggersOnlyOnce) {
RunOnceCallback<5>(net::HTTP_OK, Serialize(next_actions_response)));
executor_->Run(&user_data_, executor_callback_.Get());
- EXPECT_EQ(delegate_.GetStatusMessage(), "slow");
+ EXPECT_EQ(ui_delegate_.GetStatusMessage(), "slow");
task_environment_.FastForwardBy(
task_environment_.NextMainThreadPendingTaskDelay());
- EXPECT_EQ(delegate_.GetStatusMessage(), "2");
+ EXPECT_EQ(ui_delegate_.GetStatusMessage(), "2");
}
TEST_F(ScriptExecutorTest, SlowWebsiteWarningNotShownIfSlowConnectionFirst) {
@@ -642,13 +644,13 @@ TEST_F(ScriptExecutorTest, SlowWebsiteWarningNotShownIfSlowConnectionFirst) {
EXPECT_CALL(executor_callback_,
Run(Field(&ScriptExecutor::Result::success, true)));
executor_->Run(&user_data_, executor_callback_.Get());
- EXPECT_EQ(delegate_.GetStatusMessage(), "slow connection");
+ EXPECT_EQ(ui_delegate_.GetStatusMessage(), "slow connection");
task_environment_.FastForwardBy(
task_environment_.NextMainThreadPendingTaskDelay());
- EXPECT_EQ(delegate_.GetStatusMessage(), "2");
+ EXPECT_EQ(ui_delegate_.GetStatusMessage(), "2");
task_environment_.FastForwardBy(
task_environment_.NextMainThreadPendingTaskDelay());
- EXPECT_EQ(delegate_.GetStatusMessage(), "3");
+ EXPECT_EQ(ui_delegate_.GetStatusMessage(), "3");
}
TEST_F(ScriptExecutorTest, SlowWarningsBothShownIfConfigured) {
@@ -698,15 +700,13 @@ TEST_F(ScriptExecutorTest, SlowWarningsBothShownIfConfigured) {
EXPECT_CALL(executor_callback_,
Run(Field(&ScriptExecutor::Result::success, true)));
executor_->Run(&user_data_, executor_callback_.Get());
- EXPECT_EQ(delegate_.GetStatusMessage(), "slow connection");
+ EXPECT_EQ(ui_delegate_.GetStatusMessage(), "slow connection");
task_environment_.FastForwardBy(
task_environment_.NextMainThreadPendingTaskDelay());
- EXPECT_EQ(delegate_.GetStatusMessage(), "slow website");
- // task_environment_.DescribeCurrentTasks();
- //// EXPECT_EQ(delegate_.GetStatusMessage(), "2");
+ EXPECT_EQ(ui_delegate_.GetStatusMessage(), "slow website");
task_environment_.FastForwardBy(
task_environment_.NextMainThreadPendingTaskDelay());
- EXPECT_EQ(delegate_.GetStatusMessage(), "3");
+ EXPECT_EQ(ui_delegate_.GetStatusMessage(), "3");
}
TEST_F(ScriptExecutorTest, UnsupportedAction) {
@@ -824,9 +824,9 @@ TEST_F(ScriptExecutorTest, ClearDetailsWhenFinished) {
Run(Field(&ScriptExecutor::Result::success, true)));
// empty, but not null
- delegate_.SetDetails(std::make_unique<Details>(), base::TimeDelta());
+ ui_delegate_.SetDetails(std::make_unique<Details>(), base::TimeDelta());
executor_->Run(&user_data_, executor_callback_.Get());
- EXPECT_THAT(delegate_.GetDetails(), IsEmpty());
+ EXPECT_THAT(ui_delegate_.GetDetails(), IsEmpty());
}
TEST_F(ScriptExecutorTest, DontClearDetailsIfOtherActionsAreLeft) {
@@ -845,9 +845,9 @@ TEST_F(ScriptExecutorTest, DontClearDetailsIfOtherActionsAreLeft) {
Run(Field(&ScriptExecutor::Result::success, true)));
// empty, but not null
- delegate_.SetDetails(std::make_unique<Details>(), base::TimeDelta());
+ ui_delegate_.SetDetails(std::make_unique<Details>(), base::TimeDelta());
executor_->Run(&user_data_, executor_callback_.Get());
- EXPECT_THAT(delegate_.GetDetails(), Not(IsEmpty()));
+ EXPECT_THAT(ui_delegate_.GetDetails(), Not(IsEmpty()));
}
TEST_F(ScriptExecutorTest, ClearDetailsOnError) {
@@ -861,9 +861,9 @@ TEST_F(ScriptExecutorTest, ClearDetailsOnError) {
Run(Field(&ScriptExecutor::Result::success, false)));
// empty, but not null
- delegate_.SetDetails(std::make_unique<Details>(), base::TimeDelta());
+ ui_delegate_.SetDetails(std::make_unique<Details>(), base::TimeDelta());
executor_->Run(&user_data_, executor_callback_.Get());
- EXPECT_THAT(delegate_.GetDetails(), IsEmpty());
+ EXPECT_THAT(ui_delegate_.GetDetails(), IsEmpty());
}
TEST_F(ScriptExecutorTest, ForwardLastPayloadOnSuccess) {
@@ -1289,7 +1289,7 @@ TEST_F(ScriptExecutorTest, RunInterruptDuringPrompt) {
ElementsAre(interruptible_area, interrupt_area,
ElementAreaProto::default_instance(), interruptible_area,
ElementAreaProto::default_instance()));
- EXPECT_EQ("done", delegate_.GetStatusMessage());
+ EXPECT_EQ("done", ui_delegate_.GetStatusMessage());
}
TEST_F(ScriptExecutorTest, RunPromptInBrowseMode) {
@@ -1510,9 +1510,9 @@ TEST_F(ScriptExecutorTest, RestorePreInterruptStatusMessage) {
EXPECT_CALL(executor_callback_,
Run(Field(&ScriptExecutor::Result::success, true)));
- delegate_.SetStatusMessage("pre-run status");
+ ui_delegate_.SetStatusMessage("pre-run status");
executor_->Run(&user_data_, executor_callback_.Get());
- EXPECT_EQ("pre-interrupt status", delegate_.GetStatusMessage());
+ EXPECT_EQ("pre-interrupt status", ui_delegate_.GetStatusMessage());
}
TEST_F(ScriptExecutorTest, KeepStatusMessageWhenNotInterrupted) {
@@ -1533,9 +1533,9 @@ TEST_F(ScriptExecutorTest, KeepStatusMessageWhenNotInterrupted) {
EXPECT_CALL(executor_callback_,
Run(Field(&ScriptExecutor::Result::success, true)));
- delegate_.SetStatusMessage("pre-run status");
+ ui_delegate_.SetStatusMessage("pre-run status");
executor_->Run(&user_data_, executor_callback_.Get());
- EXPECT_EQ("pre-interrupt status", delegate_.GetStatusMessage());
+ EXPECT_EQ("pre-interrupt status", ui_delegate_.GetStatusMessage());
}
TEST_F(ScriptExecutorTest, PauseWaitForDomWhileNavigating) {
@@ -1918,14 +1918,14 @@ TEST_F(ScriptExecutorTest, InterceptUserActions) {
executor_->Run(&user_data_, executor_callback_.Get());
EXPECT_EQ(AutofillAssistantState::PROMPT, delegate_.GetState());
- ASSERT_NE(nullptr, delegate_.GetUserActions());
- ASSERT_THAT(*delegate_.GetUserActions(), SizeIs(1));
+ ASSERT_NE(nullptr, ui_delegate_.GetUserActions());
+ ASSERT_THAT(*ui_delegate_.GetUserActions(), SizeIs(1));
// The prompt action must finish. We don't bother continuing with the script
// in this test.
EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _, _, _, _));
- (*delegate_.GetUserActions())[0].RunCallback();
+ (*ui_delegate_.GetUserActions())[0].RunCallback();
EXPECT_EQ(AutofillAssistantState::RUNNING, delegate_.GetState());
}
@@ -1942,21 +1942,21 @@ TEST_F(ScriptExecutorTest, PauseAndResume) {
.WillOnce(RunOnceCallback<5>(net::HTTP_OK, Serialize(actions_response)));
executor_->Run(&user_data_, executor_callback_.Get());
- EXPECT_EQ("Tell", delegate_.GetStatusMessage());
+ EXPECT_EQ("Tell", ui_delegate_.GetStatusMessage());
EXPECT_EQ(AutofillAssistantState::PROMPT, delegate_.GetState());
executor_->OnPause("Paused", "Button");
- EXPECT_EQ("Paused", delegate_.GetStatusMessage());
+ EXPECT_EQ("Paused", ui_delegate_.GetStatusMessage());
EXPECT_EQ(AutofillAssistantState::STOPPED, delegate_.GetState());
- ASSERT_THAT(*delegate_.GetUserActions(), SizeIs(1));
+ ASSERT_THAT(*ui_delegate_.GetUserActions(), SizeIs(1));
EXPECT_THAT(
- *delegate_.GetUserActions(),
+ *ui_delegate_.GetUserActions(),
ElementsAre(Property(&UserAction::chip,
AllOf(Field(&Chip::text, StrEq("Button")),
Field(&Chip::type, HIGHLIGHTED_ACTION)))));
- (*delegate_.GetUserActions())[0].RunCallback();
- EXPECT_EQ("Tell", delegate_.GetStatusMessage());
+ (*ui_delegate_.GetUserActions())[0].RunCallback();
+ EXPECT_EQ("Tell", ui_delegate_.GetStatusMessage());
EXPECT_THAT(delegate_.GetStateHistory(),
ElementsAre(AutofillAssistantState::PROMPT,
AutofillAssistantState::STOPPED,
@@ -1985,15 +1985,15 @@ TEST_F(ScriptExecutorTest, PauseAndResumeWithOngoingAction) {
RunOnceCallback<2>(ClientStatus(ELEMENT_RESOLUTION_FAILED), nullptr));
executor_->Run(&user_data_, executor_callback_.Get());
- EXPECT_EQ("Tell", delegate_.GetStatusMessage());
+ EXPECT_EQ("Tell", ui_delegate_.GetStatusMessage());
EXPECT_THAT(delegate_.GetState(), Not(Eq(AutofillAssistantState::PROMPT)));
executor_->OnPause("Paused", "Button");
- EXPECT_EQ("Paused", delegate_.GetStatusMessage());
+ EXPECT_EQ("Paused", ui_delegate_.GetStatusMessage());
EXPECT_EQ(AutofillAssistantState::STOPPED, delegate_.GetState());
- ASSERT_THAT(*delegate_.GetUserActions(), SizeIs(1));
+ ASSERT_THAT(*ui_delegate_.GetUserActions(), SizeIs(1));
EXPECT_THAT(
- *delegate_.GetUserActions(),
+ *ui_delegate_.GetUserActions(),
ElementsAre(Property(&UserAction::chip,
AllOf(Field(&Chip::text, StrEq("Button")),
Field(&Chip::type, HIGHLIGHTED_ACTION)))));
@@ -2002,8 +2002,8 @@ TEST_F(ScriptExecutorTest, PauseAndResumeWithOngoingAction) {
// not advance to the next action (i.e. |PromptAction|), so the status
// status message is the one from |TellAction|.
EXPECT_CALL(mock_web_controller_, FindElement(_, _, _)).Times(0);
- (*delegate_.GetUserActions())[0].RunCallback();
- EXPECT_EQ("Tell", delegate_.GetStatusMessage());
+ (*ui_delegate_.GetUserActions())[0].RunCallback();
+ EXPECT_EQ("Tell", ui_delegate_.GetStatusMessage());
EXPECT_EQ(AutofillAssistantState::RUNNING, delegate_.GetState());
// We have resumed, the |WaitForDom| should now finish and advance the script.
@@ -2013,7 +2013,7 @@ TEST_F(ScriptExecutorTest, PauseAndResumeWithOngoingAction) {
std::make_unique<ElementFinder::Result>());
}));
task_environment_.FastForwardBy(base::Milliseconds(1000));
- EXPECT_EQ("Prompt", delegate_.GetStatusMessage());
+ EXPECT_EQ("Prompt", ui_delegate_.GetStatusMessage());
EXPECT_EQ(AutofillAssistantState::PROMPT, delegate_.GetState());
}
@@ -2056,11 +2056,11 @@ TEST_F(ScriptExecutorTest, ClearPersistentUiOnError) {
Run(Field(&ScriptExecutor::Result::success, false)));
// empty, but not null
- delegate_.SetPersistentGenericUi(
+ ui_delegate_.SetPersistentGenericUi(
std::make_unique<GenericUserInterfaceProto>(), base::DoNothing());
- ASSERT_NE(nullptr, delegate_.GetPersistentGenericUi());
+ ASSERT_NE(nullptr, ui_delegate_.GetPersistentGenericUi());
executor_->Run(&user_data_, executor_callback_.Get());
- ASSERT_EQ(nullptr, delegate_.GetPersistentGenericUi());
+ ASSERT_EQ(nullptr, ui_delegate_.GetPersistentGenericUi());
}
} // namespace
diff --git a/chromium/components/autofill_assistant/browser/script_parameters.cc b/chromium/components/autofill_assistant/browser/script_parameters.cc
index 2d91c8e6034..8c3d099c1da 100644
--- a/chromium/components/autofill_assistant/browser/script_parameters.cc
+++ b/chromium/components/autofill_assistant/browser/script_parameters.cc
@@ -9,6 +9,7 @@
#include "base/containers/flat_map.h"
#include "base/logging.h"
+#include "base/ranges/algorithm.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "components/autofill_assistant/browser/user_data.h"
@@ -92,6 +93,9 @@ const char kIntent[] = "INTENT";
// Parameter that allows enabling Text-to-Speech functionality.
const char kEnableTtsParameterName[] = "ENABLE_TTS";
+// Allows enabling observer-based WaitForDOM.
+const char kEnableObserversParameter[] = "ENABLE_OBSERVER_WAIT_FOR_DOM";
+
// Parameter name of the CALLER script parameter. Note that the corresponding
// values are integers, corresponding to the caller proto in the backend.
const char kCallerParameterName[] = "CALLER";
@@ -103,9 +107,11 @@ const char kSourceParameterName[] = "SOURCE";
// Parameter to specify experiments.
const char kExperimentsParameterName[] = "EXPERIMENT_IDS";
-// The list of script parameters that trigger scripts are allowed to send to
-// the backend.
-constexpr std::array<const char*, 6> kAllowlistedTriggerScriptParameters = {
+// The list of non sensitive script parameters that client requests are allowed
+// to send to the backend i.e., they do not require explicit approval in the
+// autofill-assistant onboarding. Even so, please always reach out to Chrome
+// privacy when you plan to make use of this list, and/or adjust it.
+constexpr std::array<const char*, 6> kNonSensitiveScriptParameters = {
"DEBUG_BUNDLE_ID", "DEBUG_BUNDLE_VERSION", "DEBUG_SOCKET_ID",
"FALLBACK_BUNDLE_ID", "FALLBACK_BUNDLE_VERSION", kIntent};
@@ -156,10 +162,10 @@ bool ScriptParameters::Matches(const ScriptParameterMatchProto& proto) const {
}
google::protobuf::RepeatedPtrField<ScriptParameterProto>
-ScriptParameters::ToProto(bool only_trigger_script_allowlisted) const {
+ScriptParameters::ToProto(bool only_non_sensitive_allowlisted) const {
google::protobuf::RepeatedPtrField<ScriptParameterProto> out;
- if (only_trigger_script_allowlisted) {
- for (const char* key : kAllowlistedTriggerScriptParameters) {
+ if (only_non_sensitive_allowlisted) {
+ for (const char* key : kNonSensitiveScriptParameters) {
auto iter = parameters_.find(key);
if (iter == parameters_.end()) {
continue;
@@ -195,6 +201,10 @@ absl::optional<std::string> ScriptParameters::GetParameter(
return iter->second.strings().values(0);
}
+bool ScriptParameters::HasExperimentId(const std::string& experiment_id) const {
+ return base::ranges::count(GetExperiments(), experiment_id) > 0;
+}
+
absl::optional<std::string> ScriptParameters::GetOverlayColors() const {
return GetParameter(kOverlayColorParameterName);
}
@@ -243,6 +253,10 @@ absl::optional<bool> ScriptParameters::GetEnableTts() const {
return GetTypedParameter<bool>(parameters_, kEnableTtsParameterName);
}
+absl::optional<bool> ScriptParameters::GetEnableObserverWaitForDom() const {
+ return GetTypedParameter<bool>(parameters_, kEnableObserversParameter);
+}
+
absl::optional<int> ScriptParameters::GetCaller() const {
return GetTypedParameter<int>(parameters_, kCallerParameterName);
}
diff --git a/chromium/components/autofill_assistant/browser/script_parameters.h b/chromium/components/autofill_assistant/browser/script_parameters.h
index 97e489d5fa6..a3f1c2d41e9 100644
--- a/chromium/components/autofill_assistant/browser/script_parameters.h
+++ b/chromium/components/autofill_assistant/browser/script_parameters.h
@@ -32,10 +32,11 @@ class ScriptParameters {
bool Matches(const ScriptParameterMatchProto& proto) const;
// Returns a proto representation of this class. If
- // |only_trigger_script_allowlisted| is set to true, this will only return the
- // list of trigger-script-approved script parameters.
+ // |only_non_sensitive_allowlisted| is set to true, this will only return the
+ // list of non sensitive script parameters that client requests are allowed
+ // to send to the backend.
google::protobuf::RepeatedPtrField<ScriptParameterProto> ToProto(
- bool only_trigger_script_allowlisted = false) const;
+ bool only_non_sensitive_allowlisted = false) const;
// Update the device only parameters. New parameters always take precedence.
void UpdateDeviceOnlyParameters(
@@ -45,6 +46,9 @@ class ScriptParameters {
// to the additional values with a "param:" prefix.
void WriteToUserData(UserData* user_data) const;
+ // Returns whether |experiment_id| is contained in the experiments parameter.
+ bool HasExperimentId(const std::string& experiment_id) const;
+
// Getters for specific parameters.
absl::optional<std::string> GetOverlayColors() const;
absl::optional<std::string> GetPasswordChangeUsername() const;
@@ -57,6 +61,7 @@ class ScriptParameters {
absl::optional<std::string> GetIntent() const;
absl::optional<std::string> GetCallerEmail() const;
absl::optional<bool> GetEnableTts() const;
+ absl::optional<bool> GetEnableObserverWaitForDom() const;
absl::optional<int> GetCaller() const;
absl::optional<int> GetSource() const;
std::vector<std::string> GetExperiments() const;
diff --git a/chromium/components/autofill_assistant/browser/script_parameters_unittest.cc b/chromium/components/autofill_assistant/browser/script_parameters_unittest.cc
index dbc78fb81f1..570b0c66371 100644
--- a/chromium/components/autofill_assistant/browser/script_parameters_unittest.cc
+++ b/chromium/components/autofill_assistant/browser/script_parameters_unittest.cc
@@ -71,7 +71,7 @@ TEST(ScriptParametersTest, TriggerScriptAllowList) {
{"INTENT", "FAKE_INTENT"}}};
EXPECT_THAT(
- parameters.ToProto(/* only_trigger_script_allowlisted = */ false),
+ parameters.ToProto(/* only_non_sensitive_allowlisted = */ false),
UnorderedElementsAreArray(base::flat_map<std::string, std::string>(
{{"DEBUG_BUNDLE_ID", "12345"},
{"key_a", "value_a"},
@@ -83,7 +83,7 @@ TEST(ScriptParametersTest, TriggerScriptAllowList) {
{"INTENT", "FAKE_INTENT"}})));
EXPECT_THAT(
- parameters.ToProto(/* only_trigger_script_allowlisted = */ true),
+ parameters.ToProto(/* only_non_sensitive_allowlisted = */ true),
UnorderedElementsAreArray(base::flat_map<std::string, std::string>(
{{"DEBUG_BUNDLE_ID", "12345"},
{"DEBUG_BUNDLE_VERSION", "version"},
@@ -195,11 +195,11 @@ TEST(ScriptParametersTest, ToProtoRemovesEnabled) {
ScriptParameters parameters = {{{"key_a", "value_a"}, {"ENABLED", "true"}}};
EXPECT_THAT(
- parameters.ToProto(/* only_trigger_script_allowlisted = */ false),
+ parameters.ToProto(/* only_non_sensitive_allowlisted = */ false),
UnorderedElementsAreArray(
base::flat_map<std::string, std::string>({{"key_a", "value_a"}})));
- EXPECT_THAT(parameters.ToProto(/* only_trigger_script_allowlisted = */ true),
+ EXPECT_THAT(parameters.ToProto(/* only_non_sensitive_allowlisted = */ true),
IsEmpty());
}
@@ -209,7 +209,7 @@ TEST(ScriptParametersTest, ToProtoDoesNotAddDeviceOnlyParameters) {
parameters.UpdateDeviceOnlyParameters(
base::flat_map<std::string, std::string>({{"device_only", "secret"}}));
- EXPECT_THAT(parameters.ToProto(/* only_trigger_script_allowlisted = */ false),
+ EXPECT_THAT(parameters.ToProto(/* only_non_sensitive_allowlisted = */ false),
IsEmpty());
}
@@ -300,4 +300,16 @@ TEST(ScriptParametersTest, ExperimentIdParsing) {
}
}
+TEST(ScriptParametersTest, HasExperimentId) {
+ ScriptParameters parameters = {{{"EXPERIMENT_IDS", "13,123,778"}}};
+ EXPECT_THAT(
+ parameters.GetExperiments(),
+ UnorderedElementsAreArray(std::vector<std::string>{"13", "123", "778"}));
+ EXPECT_TRUE(parameters.HasExperimentId("13"));
+ EXPECT_TRUE(parameters.HasExperimentId("123"));
+ EXPECT_TRUE(parameters.HasExperimentId("778"));
+ EXPECT_FALSE(parameters.HasExperimentId("1"));
+ EXPECT_FALSE(parameters.HasExperimentId("42"));
+}
+
} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/script_precondition.cc b/chromium/components/autofill_assistant/browser/script_precondition.cc
index 3603a6b36f8..6fe8cb13954 100644
--- a/chromium/components/autofill_assistant/browser/script_precondition.cc
+++ b/chromium/components/autofill_assistant/browser/script_precondition.cc
@@ -25,6 +25,7 @@ void RunCallbackWithoutData(
base::OnceCallback<void(bool)> callback,
const ClientStatus& status,
const std::vector<std::string>& ignored_payloads,
+ const std::vector<std::string>& ignored_tags,
const base::flat_map<std::string, DomObjectFrameStack>& ignored_elements) {
std::move(callback).Run(status.ok());
}
@@ -70,8 +71,8 @@ void ScriptPrecondition::Check(
std::move(callback).Run(false);
return;
}
- element_precondition_.Check(
- batch_checks,
+ batch_checks->AddElementConditionCheck(
+ element_precondition_,
base::BindOnce(&RunCallbackWithoutData, std::move(callback)));
}
diff --git a/chromium/components/autofill_assistant/browser/script_precondition.h b/chromium/components/autofill_assistant/browser/script_precondition.h
index 2b1532a0225..ac5eba0c2fa 100644
--- a/chromium/components/autofill_assistant/browser/script_precondition.h
+++ b/chromium/components/autofill_assistant/browser/script_precondition.h
@@ -12,7 +12,6 @@
#include "base/callback.h"
#include "base/containers/flat_set.h"
#include "base/memory/weak_ptr.h"
-#include "components/autofill_assistant/browser/element_precondition.h"
#include "components/autofill_assistant/browser/service.pb.h"
#include "components/autofill_assistant/browser/web/web_controller.h"
@@ -72,7 +71,7 @@ class ScriptPrecondition {
// Condition on parameters, identified by name, as found in the intent.
std::vector<ScriptParameterMatchProto> parameter_match_;
- ElementPrecondition element_precondition_;
+ ElementConditionProto element_precondition_;
};
} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/script_tracker.cc b/chromium/components/autofill_assistant/browser/script_tracker.cc
index 1ca43b0f333..05271b2f33d 100644
--- a/chromium/components/autofill_assistant/browser/script_tracker.cc
+++ b/chromium/components/autofill_assistant/browser/script_tracker.cc
@@ -48,9 +48,11 @@ base::Value ToValueArray(const T& v) {
} // namespace
ScriptTracker::ScriptTracker(ScriptExecutorDelegate* delegate,
+ ScriptExecutorUiDelegate* ui_delegate,
ScriptTracker::Listener* listener)
- : delegate_(delegate), listener_(listener) {
+ : delegate_(delegate), ui_delegate_(ui_delegate), listener_(listener) {
DCHECK(delegate_);
+ DCHECK(ui_delegate_);
DCHECK(listener_);
}
@@ -126,7 +128,7 @@ void ScriptTracker::ExecuteScript(const std::string& script_path,
executor_ = std::make_unique<ScriptExecutor>(
script_path, std::move(context), last_global_payload_,
last_script_payload_,
- /* listener= */ this, &interrupts_, delegate_);
+ /* listener= */ this, &interrupts_, delegate_, ui_delegate_);
ScriptExecutor::RunScriptCallback run_script_callback = base::BindOnce(
&ScriptTracker::OnScriptRun, weak_ptr_factory_.GetWeakPtr(), script_path,
std::move(callback));
diff --git a/chromium/components/autofill_assistant/browser/script_tracker.h b/chromium/components/autofill_assistant/browser/script_tracker.h
index 1225bf47b1d..ab5d151e967 100644
--- a/chromium/components/autofill_assistant/browser/script_tracker.h
+++ b/chromium/components/autofill_assistant/browser/script_tracker.h
@@ -54,6 +54,7 @@ class ScriptTracker : public ScriptExecutor::Listener {
// |delegate| and |listener| should outlive this object and should not be
// nullptr.
ScriptTracker(ScriptExecutorDelegate* delegate,
+ ScriptExecutorUiDelegate* ui_delegate,
ScriptTracker::Listener* listener);
ScriptTracker(const ScriptTracker&) = delete;
@@ -131,6 +132,7 @@ class ScriptTracker : public ScriptExecutor::Listener {
std::vector<std::unique_ptr<Script>> scripts) override;
const raw_ptr<ScriptExecutorDelegate> delegate_;
+ const raw_ptr<ScriptExecutorUiDelegate> ui_delegate_;
const raw_ptr<ScriptTracker::Listener> listener_;
// If true, a set of script has already been reported to
diff --git a/chromium/components/autofill_assistant/browser/script_tracker_unittest.cc b/chromium/components/autofill_assistant/browser/script_tracker_unittest.cc
index 43592c82c0e..18c054e5c8f 100644
--- a/chromium/components/autofill_assistant/browser/script_tracker_unittest.cc
+++ b/chromium/components/autofill_assistant/browser/script_tracker_unittest.cc
@@ -10,6 +10,7 @@
#include "base/test/mock_callback.h"
#include "base/test/task_environment.h"
#include "components/autofill_assistant/browser/fake_script_executor_delegate.h"
+#include "components/autofill_assistant/browser/fake_script_executor_ui_delegate.h"
#include "components/autofill_assistant/browser/protocol_utils.h"
#include "components/autofill_assistant/browser/script_executor_delegate.h"
#include "components/autofill_assistant/browser/service/mock_service.h"
@@ -54,7 +55,7 @@ class ScriptTrackerTest : public testing::Test, public ScriptTracker::Listener {
ScriptTrackerTest()
: no_runnable_scripts_anymore_(0),
runnable_scripts_changed_(0),
- tracker_(&delegate_, /* listener=*/this) {
+ tracker_(&delegate_, &ui_delegate_, /* listener=*/this) {
delegate_.SetService(&mock_service_);
delegate_.SetWebController(&mock_web_controller_);
}
@@ -141,6 +142,7 @@ class ScriptTrackerTest : public testing::Test, public ScriptTracker::Listener {
int runnable_scripts_changed_;
std::vector<ScriptHandle> runnable_scripts_;
FakeScriptExecutorDelegate delegate_;
+ FakeScriptExecutorUiDelegate ui_delegate_;
ScriptTracker tracker_;
std::vector<std::unique_ptr<SupportedScriptProto>> scripts_proto_;
UserData user_data_;
diff --git a/chromium/components/autofill_assistant/browser/service.proto b/chromium/components/autofill_assistant/browser/service.proto
index 3e4963da03b..0f566388d2f 100644
--- a/chromium/components/autofill_assistant/browser/service.proto
+++ b/chromium/components/autofill_assistant/browser/service.proto
@@ -173,6 +173,53 @@ message SupportsScriptResponseProto {
reserved 4, 5;
}
+// A privacy sensitive way to look up Capabilities. Allows querying for
+// capabilities by hashing the requested domain urls and sending only some of
+// the leading bits, such that the recipient will be unable to reconstruct the
+// original URL.
+message GetCapabilitiesByHashPrefixRequestProto {
+ // Required. Number of bits in each hash prefix. Value must be in the range
+ // [15, 64].
+ optional uint32 hash_prefix_length = 1;
+ // Required. Hash prefixes for requested urls. The prefix will be taken as the
+ // first `hash_prefix_length` number of bits of this uint64. Other bits will
+ // be ignored. CityHash64 should be used to calculate the hashes. Encoding of
+ // the domain url prior to hashing should be UTF-8, it should include the
+ // http(s) header and exclude the last '/' character.
+ // Examples:
+ // - https://www.exampledomain.com
+ // - https://example.domain.com
+ // - https://domain.com
+ repeated uint64 hash_prefix = 2 [packed = true];
+ // The client context of the device for which you want to know script
+ // capabilities.
+ // NOTE: Currently, this will only contain the Chrome version number, locale
+ // and country for privacy reasons.
+ optional ClientContextProto client_context = 3;
+ // There is only a subset of parameters allowed to be sent from the client.
+ // INTENT parameter is required.
+ repeated ScriptParameterProto script_parameters = 4;
+}
+
+message GetCapabilitiesByHashPrefixResponseProto {
+ message MatchInfoProto {
+ // Domain url that matches one of the requested hash prefixes.
+ optional string url_match = 1;
+ // The list of script parameters for the client to use.
+ // Note: The list only contains additional or changed script parameters.
+ // This will specifically NOT include mandatory script parameters such as
+ // ENABLED or START_IMMEDIATELY, and will also not contain the INTENT.
+ // Clients are required to add those parameters themselves if needed to.
+ // They are omitted here to reduce the size of the response.
+ repeated ScriptParameterProto script_parameters_override = 2;
+ }
+ // Match information for the requested hash prefixes. No correlation should
+ // be assumed between the order of returned info and the order of requested
+ // prefixes. Clients are expected to match the returned urls to determine
+ // which responses they are interested in.
+ repeated MatchInfoProto match_info = 1;
+}
+
// Overlay image to be drawn on top of full overlays.
message OverlayImageProto {
// TODO(b/170202574): Remove legacy |image_url|.
@@ -198,7 +245,7 @@ message OverlayImageProto {
optional ClientDimensionProto text_size = 7;
}
-// Next ID: 24
+// Next ID: 25
message ClientSettingsProto {
message IntegrationTestSettings {
// Disables animations for the poodle and the progress bar.
@@ -377,6 +424,11 @@ message ClientSettingsProto {
// format, e.g. "en-US".
optional string display_strings_locale = 23;
+ // Extra time SelectorObserver has to finish. If it takes longer than
+ // max_wait_time + extra_timeout (this value) it assumes something went
+ // wrong and fails with a |TIMED_OUT| error.
+ optional int32 selector_observer_extra_timeout_ms = 24;
+
reserved 8 to 11;
}
@@ -587,7 +639,7 @@ message ActionsResponseProto {
message UpdateScriptListProto { repeated SupportedScriptProto scripts = 1; }
optional UpdateScriptListProto update_script_list = 5;
- reserved 1, 6 to 10;
+ reserved 1, 6 to 10, 12;
}
// RPC request to fetch the available trigger scripts for a particular domain.
@@ -818,6 +870,12 @@ message ActionProto {
// pass this back unchanged in the next request
optional bytes server_payload = 4;
+ // The action to be executed.
+ //
+ // WARNING: proto messages in this oneof and all protos they depend on must
+ // meet the requirements listed on jspb_parse.h to be callable conveniently
+ // from RunJsFlow. In practice, this means don't add any new fields of type
+ // bytes, uint32, uint64, fixed32, fixed64, sfixed32 or sfixed64.
oneof action_info {
SelectOptionProto select_option = 7;
NavigateProto navigate = 9;
@@ -879,6 +937,7 @@ message ActionProto {
ResetPendingCredentialsProto reset_pending_credentials = 86;
SaveSubmittedPasswordProto save_submitted_password = 87;
UpdateClientSettingsProto update_client_settings = 89;
+ ExecuteJsProto execute_js = 93;
}
// Set to true to make the client remove any contextual information if the
@@ -887,7 +946,7 @@ message ActionProto {
optional bool clean_contextual_ui = 33;
reserved 5, 6, 8, 13 to 17, 20 to 23, 25 to 27, 30, 31, 34, 38, 46 to 48, 50,
- 51, 71, 88;
+ 51, 71, 88, 90 to 92;
}
// Result of |CollectUserDataProto| to be sent to the server.
@@ -904,22 +963,19 @@ message CollectUserDataResultProto {
// If set, this means that the user clicked on one of the terms and conditions
// links.
optional int32 terms_link = 5;
- // The payload of the chosen login option.
- optional bytes login_payload = 6;
+
+ oneof payload_or_tag {
+ // The payload of the chosen login option, from LoginOptionsProto.payload.
+ bytes login_payload = 6;
+ // The payload of the chosen login option, from LoginOptionsProto.tag.
+ string login_tag = 21;
+ }
// The values obtained by the generic user interface.
optional ModelProto model = 9;
// The memory keys of all non-empty text inputs, corresponding to the memory
// keys specified in |TextInputProto|. The values themselves are stored in the
// client and do not leave the device.
repeated string set_text_input_memory_keys = 10;
- // The start date of the date/time range, if requested.
- optional DateProto date_range_start_date = 11;
- // The index of the selected timeslot for the start of the date/time range.
- optional int32 date_range_start_timeslot = 12;
- // The end date of the date/time range, if requested.
- optional DateProto date_range_end_date = 13;
- // The index of the selected timeslot for the end of the date/time range.
- optional int32 date_range_end_timeslot = 14;
// The values obtained from the additional sections.
repeated ModelProto.ModelValue additional_sections_values = 15;
// Indicates whether the UI was shown to the user. This can be false if
@@ -928,7 +984,7 @@ message CollectUserDataResultProto {
// Indicates that the chosen login option was missing the username.
optional bool login_missing_username = 17;
- reserved 7, 8, 18 to 20;
+ reserved 7, 8, 11 to 14, 18 to 20;
}
message ActionTimingStats {
@@ -1242,6 +1298,9 @@ message WebControllerErrorInfoProto {
// Blur an element that might have focus to remove its focus.
BLUR_FIELD = 28;
+ // Execute JS on an element.
+ EXECUTE_JS = 29;
+
reserved 5;
}
@@ -1267,6 +1326,16 @@ message ElementFinderInfoProto {
// If set, the document could not be resolved.
optional bool get_document_failed = 5;
+
+ message PredictedElement {
+ // Whether the inference returned the expectation.
+ optional bool matches_css_element = 1;
+ }
+ message SemanticInferenceResult {
+ // If this is empty, the model inference did not find any results.
+ repeated PredictedElement predicted_elements = 1;
+ }
+ optional SemanticInferenceResult semantic_inference_result = 6;
}
// The pseudo type values come from
@@ -1502,6 +1571,17 @@ message SelectorProto {
optional int32 index = 1;
}
+ // If set, and the model inference is enabled on the client, will run model
+ // inference and compare if the found element has been inferred along
+ // the expectation.
+ message SemanticInformation {
+ // The objective we expect this Selector to have.
+ optional int32 objective = 1;
+ // The role we expect this Selector to have.
+ optional int32 semantic_role = 2;
+ }
+ optional SemanticInformation semantic_information = 11;
+
reserved 1 to 8;
}
@@ -1783,8 +1863,11 @@ message WaitForDomProto {
// Result to include into ProcessedActionProto.
message Result {
- // Payload of all matching conditions, if one is set.
+ // Payload of all matching conditions, from ElementConditionProto.payload.
repeated bytes matching_condition_payloads = 1;
+
+ // Payload of all matching conditions, from ElementConditionProto.tag.
+ repeated string matching_condition_tags = 2;
}
}
@@ -1808,8 +1891,15 @@ message ElementConditionProto {
// A payload that identifies this condition. WaitForDom puts this payload
// into the result. This is ignored outside of WaitForDom.
+ //
+ // Prefer using tag.
optional bytes payload = 5;
+ // A tag that is echoed back to WaitForDom.Result if the condition matches.
+ //
+ // This is ignored outside of WaitForDom.
+ optional string tag = 8;
+
// Optional. If set, the element of |match| will be stored under this
// identifier on the client. If |require_unique_element| is not set to true,
// the first match will be stored.
@@ -1998,23 +2088,6 @@ message WaitForDocumentProto {
// log should contain additional information about the issue, if verbose
// logging is enabled (suggested level: 2 or 3).
message ShowGenericUiProto {
- message RequestAutofillCreditCards { optional string model_identifier = 1; }
- message RequestAutofillProfiles { optional string model_identifier = 1; }
- message RequestLoginOptions {
- message PasswordManagerLogins {
- optional string sublabel = 1;
- optional bytes payload = 2;
- }
- message LoginOption {
- oneof type {
- LoginOptionProto custom_login_option = 1;
- PasswordManagerLogins password_manager_logins = 2;
- }
- }
-
- repeated LoginOption login_options = 1;
- optional string model_identifier = 2;
- }
message RequestUserData {
message AdditionalValue {
// The client memory identifier (from |UserData|).
@@ -2040,19 +2113,6 @@ message ShowGenericUiProto {
// subset of the input model identifiers!
repeated string output_model_identifiers = 2;
- // If specified, available autofill credit cards will be provided and
- // auto-updated in the specified |model_identifier|.
- optional RequestAutofillCreditCards request_credit_cards = 3;
-
- // If specified, available autofill profiles will be provided and auto-updated
- // in the specified |model_identifier|.
- optional RequestAutofillProfiles request_profiles = 4;
-
- // If specified, available login options (including those provided by password
- // manager) will be provided and auto-updated in the specified
- // |model_identifier|.
- optional RequestLoginOptions request_login_options = 5;
-
message PeriodicElementChecks {
message ElementCheck {
// The element condition to be checked during the action.
@@ -2075,7 +2135,7 @@ message ShowGenericUiProto {
// |is_client_side_only| set to true.
optional RequestUserData request_user_data = 9;
- reserved 10;
+ reserved 3 to 5, 10;
}
// Show backend-specified user interface elements to the user until dismissed.
@@ -2133,8 +2193,13 @@ message PromptProto {
// Server payload originally sent by the server. This should
// be transmitted as-is by the client without interpreting.
+ //
+ // Prefer using tag.
optional bytes server_payload = 5;
+ // Tag set by the server. It is put into PromptProto.Result.tag
+ optional string tag = 18;
+
reserved 4, 6, 8, 12 to 14, 17;
}
repeated Choice choices = 4;
@@ -2183,6 +2248,9 @@ message PromptProto {
// transmitted as-is by the client without interpreting.
optional bytes server_payload = 5;
+ // Tag originally set in Choice.tag.
+ optional string choice_tag = 6;
+
reserved 1;
}
}
@@ -2222,6 +2290,17 @@ message ContactDetailsProto {
optional string contact_details_section_title = 9;
// Defines how to evaluate validity of this contact.
repeated RequiredDataPiece required_data_piece = 10;
+
+ // If true, the phone number will be asked in a separate section from the
+ // rest of the contact info. If true, |request_payer_phone| must be false.
+ // Only supported for backend-provided data.
+ optional bool separate_phone_number_section = 11;
+ // The title of the separate phone number section.
+ // Required if |separate_phone_number_section| is true, ignored if false.
+ optional string phone_number_section_title = 12;
+ // Defines how to evaluate the validity of the phone number in the separate
+ // section. Ignored if |separate_phone_number_section| is false.
+ repeated RequiredDataPiece phone_number_required_data_piece = 13;
}
message LoginDetailsProto {
@@ -2251,8 +2330,17 @@ message LoginDetailsProto {
// description.
optional string edit_button_content_description = 10;
- // If the option was chosen, this payload will be returned to the server.
- optional bytes payload = 1;
+ oneof payload_or_tag {
+ // The payload attached to this login option, to be echoed back to the
+ // caller when the option is chosen.
+ //
+ // Prefer using tag.
+ bytes payload = 1;
+
+ // The tag attached to this login option, to be echoed back to the
+ // caller when the option is chosen.
+ string tag = 21;
+ }
// Whether the UI should automatically choose this login option if no
// password manager login options are available.
@@ -2274,46 +2362,6 @@ message LoginDetailsProto {
repeated LoginOptionProto login_options = 2;
}
-message DateTimeRangeProto {
- message TimeSlot {
- // The label to display.
- optional string label = 1;
- // The comparison value to be used to compare this timeslot
- // to others. Smaller values indicate earlier times. This will be used to
- // prevent start > end and vice-versa.
- optional int32 comparison_value = 2;
- }
-
- // The initial start date of the date/time range.
- optional DateProto start_date = 15;
- // The index of the initial start time slot to select.
- optional int32 start_time_slot = 13;
- // The initial end date of the date/time range.
- optional DateProto end_date = 16;
- // The index of the initial end time slot to select.
- optional int32 end_time_slot = 14;
- // The minimum allowed date of the date/time range.
- optional DateProto min_date = 3;
- // The maximum allowed date of the date/time range.
- optional DateProto max_date = 4;
- // The label for the start date (e.g., 'Pick up date').
- optional string start_date_label = 8;
- // The label for the start time (e.g., 'Pick up time').
- optional string start_time_label = 9;
- // The label for the end date (e.g., 'Drop off date').
- optional string end_date_label = 10;
- // The label for the end time (e.g., 'Drop off time').
- optional string end_time_label = 11;
- // The time slots to offer (e.g., 08:00 AM, 08:30 AM, ...)
- repeated TimeSlot time_slots = 12;
- // The error message to display if the date is not set.
- optional string date_not_set_error = 17;
- // The error message to display if the time is not set.
- optional string time_not_set_error = 18;
-
- reserved 1, 2, 5, 6, 7;
-}
-
// A section showing a simple text message.
message StaticTextSectionProto {
// The text to display. Can contain markup tags like <b>.
@@ -2402,11 +2450,23 @@ message ProfileProto {
reserved 1;
}
+message PhoneNumberProto {
+ // The identifier of this phone number.
+ optional string identifier = 1;
+ // The canonical value of the phone number, including country and area code
+ // without any separators.
+ optional AutofillEntryProto value = 2;
+}
+
message PaymentInstrumentProto {
// The values for the card, where the key is one of autofill::ServerFieldType.
map<int32, AutofillEntryProto> card_values = 2;
+ // The payments instrument id used to identify and unmask the credit card.
+ optional int64 instrument_id = 7;
// The network of the card.
optional string network = 5;
+ // The last 4 digits of the card.
+ optional string last_four_digits = 6;
// The values for the billing address, where the key is one of
// autofill::ServerFieldType.
map<int32, AutofillEntryProto> address_values = 3;
@@ -2418,7 +2478,7 @@ message PaymentInstrumentProto {
// Asks to provide the data used by UseAddressAction and
// UseCreditCardAction.
-// Next: 38
+// Next: 40
message CollectUserDataProto {
enum TermsAndConditionsState {
// No choice has been made yet.
@@ -2479,8 +2539,6 @@ message CollectUserDataProto {
optional string credit_card_expired_text = 23;
// The login details that should be gathered.
optional LoginDetailsProto login_details = 16;
- // The date/time range that should be gathered.
- optional DateTimeRangeProto date_time_range = 17;
// An optional list of additional sections, which is above all other sections.
repeated UserFormSectionProto additional_prepended_sections = 18;
// An optional list of additional sections, which is below all other sections.
@@ -2535,13 +2593,20 @@ message CollectUserDataProto {
// instrument.
optional string selected_payment_instrument_identifier = 7;
+ // Available phone numbers to select.
+ repeated PhoneNumberProto available_phone_numbers = 10;
+ // The identifier of the phone number to select. If not specified,
+ // the client will use its own heuristics to select a default payment
+ // instrument.
+ optional string selected_phone_number_identifier = 11;
+
// The locale to be used when creating this data. This can have influence
// on the potential processing by Autofill.
optional string locale = 3;
}
optional UserDataProto user_data = 37;
- reserved 7, 10, 14, 15, 26;
+ reserved 7, 10, 14, 15, 17, 26;
}
// Stop Autofill Assistant.
diff --git a/chromium/components/autofill_assistant/browser/service/cup.cc b/chromium/components/autofill_assistant/browser/service/cup.cc
index 2684e02831c..2affb0a41f7 100644
--- a/chromium/components/autofill_assistant/browser/service/cup.cc
+++ b/chromium/components/autofill_assistant/browser/service/cup.cc
@@ -4,109 +4,30 @@
#include "cup.h"
-#include "base/base64.h"
#include "base/feature_list.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_split.h"
#include "components/autofill_assistant/browser/features.h"
-#include "components/autofill_assistant/browser/service.pb.h"
-#include "components/client_update_protocol/ecdsa.h"
-namespace {
-
-// This is an ECDSA prime256v1 named-curve key.
-constexpr int kKeyVersion = 11;
-constexpr char kKeyPubBytesBase64[] =
- "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEgH30WRJf4g6I2C1FKsBQF3qHANLw"
- "thwYsNt2PWTDQBS0ufSRE83piOPoJQcePzTkMfbghjnZerDjLJhBsDkfFg==";
+namespace autofill_assistant {
-std::string GetKey(const char* key_bytes_base64) {
- std::string result;
- return base::Base64Decode(std::string(key_bytes_base64), &result)
- ? result
- : std::string();
-}
+namespace cup {
-bool ShouldSignGetActionsRequests() {
- return base::FeatureList::IsEnabled(
- autofill_assistant::features::kAutofillAssistantSignGetActionsRequests);
+bool ShouldSignRequests(RpcType rpc_type) {
+ return rpc_type == RpcType::GET_ACTIONS &&
+ base::FeatureList::IsEnabled(
+ autofill_assistant::features::
+ kAutofillAssistantSignGetActionsRequests);
}
-bool ShouldVerifyGetActionsResponses() {
- return ShouldSignGetActionsRequests() &&
+bool ShouldVerifyResponses(RpcType rpc_type) {
+ return rpc_type == RpcType::GET_ACTIONS &&
+ base::FeatureList::IsEnabled(
+ autofill_assistant::features::
+ kAutofillAssistantSignGetActionsRequests) &&
base::FeatureList::IsEnabled(
autofill_assistant::features::
kAutofillAssistantVerifyGetActionsResponses);
}
-} // namespace
-
-namespace autofill_assistant {
-
-std::unique_ptr<client_update_protocol::Ecdsa> CUP::CreateQuerySigner() {
- return client_update_protocol::Ecdsa::Create(kKeyVersion,
- GetKey(kKeyPubBytesBase64));
-}
-
-bool CUP::ShouldSignRequests(RpcType rpc_type) {
- return ShouldSignGetActionsRequests() && rpc_type == RpcType::GET_ACTIONS;
-}
-
-bool CUP::ShouldVerifyResponses(RpcType rpc_type) {
- return ShouldVerifyGetActionsResponses() && rpc_type == RpcType::GET_ACTIONS;
-}
-
-CUP::CUP(std::unique_ptr<client_update_protocol::Ecdsa> query_signer)
- : query_signer_{std::move(query_signer)} {
- DCHECK(query_signer_);
-}
-
-CUP::~CUP() = default;
-
-std::string CUP::PackAndSignRequest(const std::string& original_request) {
- return PackGetActionsRequest(original_request);
-}
-
-absl::optional<std::string> CUP::UnpackResponse(
- const std::string& original_response) {
- return UnpackGetActionsResponse(original_response);
-}
-
-std::string CUP::PackGetActionsRequest(const std::string& original_request) {
- autofill_assistant::ScriptActionRequestProto actions_request;
- actions_request.mutable_cup_data()->set_request(original_request);
-
- client_update_protocol::Ecdsa::RequestParameters request_parameters =
- query_signer_->SignRequest(original_request);
- actions_request.mutable_cup_data()->set_query_cup2key(
- request_parameters.query_cup2key);
- actions_request.mutable_cup_data()->set_hash_hex(request_parameters.hash_hex);
-
- std::string serialized_request;
- actions_request.SerializeToString(&serialized_request);
- return serialized_request;
-}
-
-absl::optional<std::string> CUP::UnpackGetActionsResponse(
- const std::string& original_response) {
- autofill_assistant::ActionsResponseProto actions_response;
- if (!actions_response.ParseFromString(original_response)) {
- LOG(ERROR) << "Failed to parse server response";
- return absl::nullopt;
- }
-
- std::string serialized_response = actions_response.cup_data().response();
- if (!query_signer_->ValidateResponse(
- serialized_response, actions_response.cup_data().ecdsa_signature())) {
- LOG(ERROR) << "CUP RPC response verification failed";
- return absl::nullopt;
- }
-
- return serialized_response;
-}
-
-client_update_protocol::Ecdsa& CUP::GetQuerySigner() {
- return *query_signer_.get();
-}
+} // namespace cup
} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/service/cup.h b/chromium/components/autofill_assistant/browser/service/cup.h
index 3b52180cae5..eb4d4a82312 100644
--- a/chromium/components/autofill_assistant/browser/service/cup.h
+++ b/chromium/components/autofill_assistant/browser/service/cup.h
@@ -6,64 +6,42 @@
#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_CUP_H_
#include "components/autofill_assistant/browser/service/rpc_type.h"
-#include "components/client_update_protocol/ecdsa.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
namespace autofill_assistant {
-// Implementation of the Client Update Protocol (CUP) for the service calls in
-// |autofill_assistant|.
-// https://source.chromium.org/chromium/chromium/src/+/main:docs/updater/cup.md
-//
-// Due to server-side constraints, the CUP information cannot be exchanged over
-// HTTP headers, and is sent as part of the request and response body instead.
-//
-// This class can only be used once per service call.
-class CUP {
- public:
- static std::unique_ptr<client_update_protocol::Ecdsa> CreateQuerySigner();
+namespace cup {
- // Whether |PackAndSignRequest| should be called before the request is
- // submitted. Can be |false| because signing is disabled via feature flag,
- // or given message type doesn't support CUP signing.
- static bool ShouldSignRequests(RpcType rpc_type);
+// Whether |PackAndSignRequest| should be called before the request is
+// submitted. Can be |false| because signing is disabled via feature flag,
+// or given message type doesn't support CUP signing.
+bool ShouldSignRequests(RpcType rpc_type);
- // Whether |UnpackResponse| should be called on the response from the service
- // call. Can be false because verification is disabled via feature flag or
- // |ShouldSignRequest| returns |false|.
- static bool ShouldVerifyResponses(RpcType rpc_type);
+// Whether |UnpackResponse| should be called on the response from the service
+// call. Can be false because verification is disabled via feature flag or
+// |ShouldSignRequest| returns |false|.
+bool ShouldVerifyResponses(RpcType rpc_type);
- CUP(std::unique_ptr<client_update_protocol::Ecdsa> query_signer);
- CUP(const CUP&) = delete;
- CUP& operator=(const CUP&) = delete;
- ~CUP();
+class CUP {
+ public:
+ virtual ~CUP() = default;
// Generates a new |request| where |original_request| is packed and signed in
// its |cup_data| field.
- //
- // Should only be called if |ShouldSignRequest| returns true.
- std::string PackAndSignRequest(const std::string& original_request);
+ virtual std::string PackAndSignRequest(
+ const std::string& original_request) = 0;
// Generates a new |response| where |original_response| is unpacked from
// the |cup_data| field.
- //
- // Should only be called if |ShouldVerifyResponse| returns true.
- absl::optional<std::string> UnpackResponse(
- const std::string& original_response);
+ virtual absl::optional<std::string> UnpackResponse(
+ const std::string& original_response) = 0;
- // Gets the query signer object being used by this CUP instance. Needed for
- // testing.
- client_update_protocol::Ecdsa& GetQuerySigner();
-
- private:
- std::string PackGetActionsRequest(const std::string& original_request);
-
- absl::optional<std::string> UnpackGetActionsResponse(
- const std::string& original_response);
-
- std::unique_ptr<client_update_protocol::Ecdsa> query_signer_;
+ protected:
+ CUP() = default;
};
+} // namespace cup
+
} // namespace autofill_assistant
#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_CUP_H_
diff --git a/chromium/components/autofill_assistant/browser/service/cup_factory.cc b/chromium/components/autofill_assistant/browser/service/cup_factory.cc
new file mode 100644
index 00000000000..ee916792752
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/service/cup_factory.cc
@@ -0,0 +1,18 @@
+// Copyright 2021 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.
+
+#include "components/autofill_assistant/browser/service/cup_factory.h"
+#include "components/autofill_assistant/browser/service/cup_impl.h"
+
+namespace autofill_assistant {
+
+namespace cup {
+
+std::unique_ptr<CUP> CUPImplFactory::CreateInstance(RpcType rpc_type) const {
+ return std::make_unique<CUPImpl>(CUPImpl::CreateQuerySigner(), rpc_type);
+}
+
+} // namespace cup
+
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/service/cup_factory.h b/chromium/components/autofill_assistant/browser/service/cup_factory.h
new file mode 100644
index 00000000000..aab3b010786
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/service/cup_factory.h
@@ -0,0 +1,41 @@
+// Copyright 2021 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.
+
+#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_CUP_FACTORY_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_CUP_FACTORY_H_
+
+#include "components/autofill_assistant/browser/service/cup.h"
+
+namespace autofill_assistant {
+
+namespace cup {
+
+// Base interface for creators of CUP (Client Update Protocol) instances.
+class CUPFactory {
+ public:
+ virtual ~CUPFactory() = default;
+
+ // Creates an instance of CUP for a call of given |rpc_type|.
+ virtual std::unique_ptr<CUP> CreateInstance(RpcType rpc_type) const = 0;
+
+ protected:
+ CUPFactory() = default;
+};
+
+// Implementation of |CUPFactory| for |CUPImpl| instances.
+class CUPImplFactory : public CUPFactory {
+ public:
+ CUPImplFactory() = default;
+ ~CUPImplFactory() override = default;
+ CUPImplFactory(const CUPImplFactory&) = delete;
+ CUPImplFactory& operator=(const CUPImplFactory&) = delete;
+
+ std::unique_ptr<CUP> CreateInstance(RpcType rpc_type) const override;
+};
+
+} // namespace cup
+
+} // namespace autofill_assistant
+
+#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_CUP_FACTORY_H_
diff --git a/chromium/components/autofill_assistant/browser/service/cup_factory_unittest.cc b/chromium/components/autofill_assistant/browser/service/cup_factory_unittest.cc
new file mode 100644
index 00000000000..21f9f542425
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/service/cup_factory_unittest.cc
@@ -0,0 +1,31 @@
+// Copyright 2021 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.
+
+#include "components/autofill_assistant/browser/service/cup_factory.h"
+#include "components/autofill_assistant/browser/service/cup_impl.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace {
+
+class CUPFactoryTest : public testing::Test {
+ public:
+ CUPFactoryTest()
+ : cup_factory_{
+ std::make_unique<autofill_assistant::cup::CUPImplFactory>()} {}
+ ~CUPFactoryTest() override = default;
+
+ protected:
+ std::unique_ptr<autofill_assistant::cup::CUPFactory> cup_factory_;
+};
+
+TEST_F(CUPFactoryTest, ShouldCreateCupImplInstance) {
+ std::unique_ptr<autofill_assistant::cup::CUP> cup =
+ cup_factory_->CreateInstance(autofill_assistant::RpcType::GET_ACTIONS);
+ ASSERT_NE(cup, nullptr);
+
+ std::string packed_request = cup->PackAndSignRequest("request");
+ EXPECT_FALSE(packed_request.empty());
+}
+
+} // namespace
diff --git a/chromium/components/autofill_assistant/browser/service/cup_impl.cc b/chromium/components/autofill_assistant/browser/service/cup_impl.cc
new file mode 100644
index 00000000000..ac00b35927f
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/service/cup_impl.cc
@@ -0,0 +1,149 @@
+// Copyright 2021 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.
+
+#include "cup_impl.h"
+
+#include "base/base64.h"
+#include "base/command_line.h"
+#include "base/feature_list.h"
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "components/autofill_assistant/browser/service.pb.h"
+#include "components/autofill_assistant/browser/switches.h"
+#include "components/client_update_protocol/ecdsa.h"
+
+namespace {
+
+// This is an ECDSA prime256v1 named-curve key.
+constexpr int kKeyVersion = 11;
+constexpr char kKeyPubBytesBase64[] =
+ "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEgH30WRJf4g6I2C1FKsBQF3qHANLw"
+ "thwYsNt2PWTDQBS0ufSRE83piOPoJQcePzTkMfbghjnZerDjLJhBsDkfFg==";
+
+absl::optional<std::string> GetKey(const std::string& key_bytes_base64) {
+ std::string result;
+ return base::Base64Decode(key_bytes_base64, &result)
+ ? absl::optional<std::string>(result)
+ : absl::nullopt;
+}
+
+} // namespace
+
+namespace autofill_assistant {
+
+namespace cup {
+
+int CUPImpl::GetKeyVersion() {
+ int key_version = kKeyVersion;
+ if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kAutofillAssistantCupKeyVersion)) {
+ return key_version;
+ }
+
+ if (!base::StringToInt(
+ base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ switches::kAutofillAssistantCupKeyVersion),
+ &key_version)) {
+ LOG(ERROR) << "Error parsing command line flag "
+ << switches::kAutofillAssistantCupKeyVersion << ": not a number";
+ // If CLI key version is not valid, continue with the default one.
+ return kKeyVersion;
+ }
+ return key_version;
+}
+
+std::string CUPImpl::GetPublicKey() {
+ absl::optional<std::string> pub_key = GetKey(kKeyPubBytesBase64);
+ // The default key specified in |kKeyPubBytesBase64| must be valid base64.
+ DCHECK(pub_key.has_value());
+
+ if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kAutofillAssistantCupPublicKeyBase64)) {
+ return *pub_key;
+ }
+
+ absl::optional<std::string> switch_pub_key =
+ GetKey(base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ switches::kAutofillAssistantCupPublicKeyBase64));
+ if (!switch_pub_key.has_value()) {
+ LOG(ERROR) << "Error parsing command line flag "
+ << switches::kAutofillAssistantCupPublicKeyBase64
+ << ": not a valid base64 string";
+ // If CLI public key is not valid, continue with the default one.
+ return *pub_key;
+ }
+ return *switch_pub_key;
+}
+
+std::unique_ptr<client_update_protocol::Ecdsa> CUPImpl::CreateQuerySigner() {
+ return client_update_protocol::Ecdsa::Create(GetKeyVersion(), GetPublicKey());
+}
+
+CUPImpl::CUPImpl(std::unique_ptr<client_update_protocol::Ecdsa> query_signer,
+ RpcType rpc_type)
+ : query_signer_{std::move(query_signer)}, rpc_type_{rpc_type} {
+ DCHECK(query_signer_);
+}
+
+CUPImpl::~CUPImpl() = default;
+
+std::string CUPImpl::PackAndSignRequest(const std::string& original_request) {
+ if (rpc_type_ != RpcType::GET_ACTIONS) {
+ // Failsafe in case the method is called for a non-supported |rpc_type|.
+ return original_request;
+ }
+ return PackGetActionsRequest(original_request);
+}
+
+absl::optional<std::string> CUPImpl::UnpackResponse(
+ const std::string& original_response) {
+ if (rpc_type_ != RpcType::GET_ACTIONS) {
+ // Failsafe in case the method is called for a non-supported |rpc_type|.
+ return original_response;
+ }
+ return UnpackGetActionsResponse(original_response);
+}
+
+std::string CUPImpl::PackGetActionsRequest(
+ const std::string& original_request) {
+ autofill_assistant::ScriptActionRequestProto actions_request;
+ actions_request.mutable_cup_data()->set_request(original_request);
+
+ client_update_protocol::Ecdsa::RequestParameters request_parameters =
+ query_signer_->SignRequest(original_request);
+ actions_request.mutable_cup_data()->set_query_cup2key(
+ request_parameters.query_cup2key);
+ actions_request.mutable_cup_data()->set_hash_hex(request_parameters.hash_hex);
+
+ std::string serialized_request;
+ actions_request.SerializeToString(&serialized_request);
+ return serialized_request;
+}
+
+absl::optional<std::string> CUPImpl::UnpackGetActionsResponse(
+ const std::string& original_response) {
+ autofill_assistant::ActionsResponseProto actions_response;
+ if (!actions_response.ParseFromString(original_response)) {
+ LOG(ERROR) << "Failed to parse server response";
+ return absl::nullopt;
+ }
+
+ std::string serialized_response = actions_response.cup_data().response();
+ if (!query_signer_->ValidateResponse(
+ serialized_response, actions_response.cup_data().ecdsa_signature())) {
+ LOG(ERROR) << "CUP RPC response verification failed";
+ return absl::nullopt;
+ }
+
+ return serialized_response;
+}
+
+client_update_protocol::Ecdsa& CUPImpl::GetQuerySigner() {
+ return *query_signer_.get();
+}
+
+} // namespace cup
+
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/service/cup_impl.h b/chromium/components/autofill_assistant/browser/service/cup_impl.h
new file mode 100644
index 00000000000..a755f14880b
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/service/cup_impl.h
@@ -0,0 +1,66 @@
+// Copyright 2021 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.
+
+#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_CUP_IMPL_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_CUP_IMPL_H_
+
+#include "components/autofill_assistant/browser/service/cup.h"
+#include "components/client_update_protocol/ecdsa.h"
+
+namespace autofill_assistant {
+
+namespace cup {
+
+// Implementation of the Client Update Protocol (CUP) for the service calls in
+// |autofill_assistant|.
+// https://source.chromium.org/chromium/chromium/src/+/main:docs/updater/cup.md
+//
+// Due to server-side constraints, the CUP information cannot be exchanged over
+// HTTP headers, and is sent as part of the request and response body instead.
+//
+// This class can only be used once per service call.
+class CUPImpl : public CUP {
+ public:
+ static std::string GetPublicKey();
+ static int GetKeyVersion();
+ static std::unique_ptr<client_update_protocol::Ecdsa> CreateQuerySigner();
+
+ CUPImpl(std::unique_ptr<client_update_protocol::Ecdsa> query_signer,
+ RpcType rpc_type);
+ CUPImpl(const CUPImpl&) = delete;
+ CUPImpl& operator=(const CUPImpl&) = delete;
+ ~CUPImpl() override;
+
+ // Generates a new |request| where |original_request| is packed and signed in
+ // its |cup_data| field.
+ //
+ // Should only be called if |ShouldSignRequest| returns true.
+ std::string PackAndSignRequest(const std::string& original_request) override;
+
+ // Generates a new |response| where |original_response| is unpacked from
+ // the |cup_data| field.
+ //
+ // Should only be called if |ShouldVerifyResponse| returns true.
+ absl::optional<std::string> UnpackResponse(
+ const std::string& original_response) override;
+
+ // Gets the query signer object being used by this CUP instance. Needed for
+ // testing.
+ client_update_protocol::Ecdsa& GetQuerySigner();
+
+ private:
+ std::string PackGetActionsRequest(const std::string& original_request);
+
+ absl::optional<std::string> UnpackGetActionsResponse(
+ const std::string& original_response);
+
+ std::unique_ptr<client_update_protocol::Ecdsa> query_signer_;
+ RpcType rpc_type_;
+};
+
+} // namespace cup
+
+} // namespace autofill_assistant
+
+#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_CUP_IMPL_H_
diff --git a/chromium/components/autofill_assistant/browser/service/cup_impl_unittest.cc b/chromium/components/autofill_assistant/browser/service/cup_impl_unittest.cc
new file mode 100644
index 00000000000..1b0a2e2f2fc
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/service/cup_impl_unittest.cc
@@ -0,0 +1,113 @@
+// Copyright 2020 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.
+
+#include "cup_impl.h"
+
+#include "base/command_line.h"
+#include "base/test/scoped_feature_list.h"
+#include "components/autofill_assistant/browser/features.h"
+#include "components/autofill_assistant/browser/service.pb.h"
+#include "components/autofill_assistant/browser/switches.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace {
+
+TEST(CUPImplTest, PacksAndSignsGetActionsRequest) {
+ autofill_assistant::cup::CUPImpl cup_{
+ autofill_assistant::cup::CUPImpl::CreateQuerySigner(),
+ autofill_assistant::RpcType::GET_ACTIONS};
+ autofill_assistant::ScriptActionRequestProto user_request;
+ user_request.mutable_client_context()->set_experiment_ids("test");
+ std::string user_request_str;
+ user_request.SerializeToString(&user_request_str);
+
+ auto packed_request_str = cup_.PackAndSignRequest(user_request_str);
+
+ autofill_assistant::ScriptActionRequestProto packed_request;
+ EXPECT_TRUE(packed_request.ParseFromString(packed_request_str));
+ EXPECT_TRUE(packed_request.client_context().experiment_ids().empty());
+ EXPECT_FALSE(packed_request.cup_data().request().empty());
+ EXPECT_FALSE(packed_request.cup_data().query_cup2key().empty());
+ EXPECT_FALSE(packed_request.cup_data().hash_hex().empty());
+
+ autofill_assistant::ScriptActionRequestProto actual_user_request;
+ EXPECT_TRUE(
+ actual_user_request.ParseFromString(packed_request.cup_data().request()));
+ EXPECT_EQ(actual_user_request.client_context().experiment_ids(), "test");
+ EXPECT_FALSE(actual_user_request.has_cup_data());
+}
+
+TEST(CUPImplTest, IgnoresNonGetActionsRequest) {
+ autofill_assistant::cup::CUPImpl cup_{
+ autofill_assistant::cup::CUPImpl::CreateQuerySigner(),
+ autofill_assistant::RpcType::GET_TRIGGER_SCRIPTS};
+
+ EXPECT_EQ(cup_.PackAndSignRequest("a request"), "a request");
+}
+
+TEST(CUPImplTest, UnpacksTrustedGetActionsResponse) {
+ // TODO(b/203031699): Write test for the successful case.
+}
+
+TEST(CUPImplTest, FailsToUnpackNonTrustedGetActionsResponse) {
+ autofill_assistant::cup::CUPImpl cup_{
+ autofill_assistant::cup::CUPImpl::CreateQuerySigner(),
+ autofill_assistant::RpcType::GET_ACTIONS};
+ autofill_assistant::ScriptActionRequestProto user_request;
+ user_request.mutable_client_context()->set_experiment_ids("123");
+ std::string user_request_str;
+ user_request.SerializeToString(&user_request_str);
+
+ cup_.PackAndSignRequest(user_request_str);
+ cup_.GetQuerySigner().OverrideNonceForTesting(8, 12345);
+
+ autofill_assistant::ActionsResponseProto user_response;
+ user_response.set_global_payload("adsf");
+ std::string user_response_str;
+ user_response.SerializeToString(&user_response_str);
+ autofill_assistant::ActionsResponseProto packed_response;
+ packed_response.mutable_cup_data()->set_response(user_response_str);
+ packed_response.mutable_cup_data()->set_ecdsa_signature("not a signature");
+
+ EXPECT_EQ(cup_.UnpackResponse(user_response_str), absl::nullopt);
+}
+
+TEST(CUPImplTest, IgnoresNonGetActionsResponse) {
+ autofill_assistant::cup::CUPImpl cup_{
+ autofill_assistant::cup::CUPImpl::CreateQuerySigner(),
+ autofill_assistant::RpcType::GET_TRIGGER_SCRIPTS};
+
+ absl::optional<std::string> unpacked_response =
+ cup_.UnpackResponse("a response");
+ EXPECT_EQ(*unpacked_response, "a response");
+}
+
+TEST(CUPImplTest, OverridesEcdsaPublicKeyWithCLIValue) {
+ base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+ autofill_assistant::switches::kAutofillAssistantCupPublicKeyBase64,
+ "SGVsbG8=");
+ EXPECT_EQ(autofill_assistant::cup::CUPImpl::GetPublicKey(), "Hello");
+}
+
+TEST(CUPImplTest, HasValidEcdsaPublicKeyWithNotValidCLIValue) {
+ base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+ autofill_assistant::switches::kAutofillAssistantCupPublicKeyBase64,
+ "Not valid base64");
+ EXPECT_FALSE(autofill_assistant::cup::CUPImpl::GetPublicKey().empty());
+}
+
+TEST(CUPImplTest, OverridesEcdsaKeyVersionithCLIValue) {
+ base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+ autofill_assistant::switches::kAutofillAssistantCupKeyVersion, "15");
+ EXPECT_EQ(autofill_assistant::cup::CUPImpl::GetKeyVersion(), 15);
+}
+
+TEST(CUPImplTest, HasValidEcdsaKeyVersionWithNotValidCLIValue) {
+ base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+ autofill_assistant::switches::kAutofillAssistantCupKeyVersion,
+ "Not a number");
+ EXPECT_GT(autofill_assistant::cup::CUPImpl::GetKeyVersion(), -1);
+}
+
+} // namespace
diff --git a/chromium/components/autofill_assistant/browser/service/cup_unittest.cc b/chromium/components/autofill_assistant/browser/service/cup_unittest.cc
index cf874932f8d..2cd85994597 100644
--- a/chromium/components/autofill_assistant/browser/service/cup_unittest.cc
+++ b/chromium/components/autofill_assistant/browser/service/cup_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2021 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.
@@ -9,15 +9,16 @@
#include "components/autofill_assistant/browser/service.pb.h"
#include "testing/gmock/include/gmock/gmock.h"
-namespace {
+namespace autofill_assistant {
+
+namespace cup {
class CUPTest : public testing::Test {
public:
- CUPTest() : cup_{autofill_assistant::CUP::CreateQuerySigner()} {}
+ CUPTest() = default;
~CUPTest() override = default;
protected:
- autofill_assistant::CUP cup_;
base::test::ScopedFeatureList scoped_feature_list_;
void InitCupFeatures(bool enableSigning, bool enableVerifying) {
@@ -25,21 +26,19 @@ class CUPTest : public testing::Test {
std::vector<base::Feature> disabled_features;
if (enableSigning) {
- enabled_features.push_back(autofill_assistant::features::
- kAutofillAssistantSignGetActionsRequests);
+ enabled_features.push_back(
+ features::kAutofillAssistantSignGetActionsRequests);
} else {
- disabled_features.push_back(autofill_assistant::features::
- kAutofillAssistantSignGetActionsRequests);
+ disabled_features.push_back(
+ features::kAutofillAssistantSignGetActionsRequests);
}
if (enableVerifying) {
enabled_features.push_back(
- autofill_assistant::features::
- kAutofillAssistantVerifyGetActionsResponses);
+ features::kAutofillAssistantVerifyGetActionsResponses);
} else {
disabled_features.push_back(
- autofill_assistant::features::
- kAutofillAssistantVerifyGetActionsResponses);
+ features::kAutofillAssistantVerifyGetActionsResponses);
}
scoped_feature_list_.Reset();
@@ -47,103 +46,44 @@ class CUPTest : public testing::Test {
}
};
-TEST_F(CUPTest, ShouldSignGetActionsRequestWhenFeatureActivated) {
- InitCupFeatures(true, false);
-
- EXPECT_TRUE(autofill_assistant::CUP::ShouldSignRequests(
- autofill_assistant::RpcType::GET_ACTIONS));
-}
-
-TEST_F(CUPTest, ShouldNotSignGetActionsRequestWhenFeatureNotActivated) {
- InitCupFeatures(false, false);
-
- EXPECT_FALSE(autofill_assistant::CUP::ShouldSignRequests(
- autofill_assistant::RpcType::GET_ACTIONS));
-}
-
-TEST_F(CUPTest, ShouldNotSignNotGetActionsRequest) {
- InitCupFeatures(true, false);
-
- EXPECT_FALSE(autofill_assistant::CUP::ShouldSignRequests(
- autofill_assistant::RpcType::GET_TRIGGER_SCRIPTS));
-}
-
-TEST_F(CUPTest, ShouldVerifyGetActionsResponseWhenFeatureActivated) {
- InitCupFeatures(true, true);
-
- EXPECT_TRUE(autofill_assistant::CUP::ShouldVerifyResponses(
- autofill_assistant::RpcType::GET_ACTIONS));
-}
-
-TEST_F(CUPTest, ShouldNotVerifyGetActionsResponseWhenFeatureNotActivated) {
- InitCupFeatures(true, false);
-
- EXPECT_FALSE(autofill_assistant::CUP::ShouldVerifyResponses(
- autofill_assistant::RpcType::GET_ACTIONS));
-}
-
-TEST_F(CUPTest, ShouldNotVerifyGetActionsResponseWhenSigningNotActivated) {
- InitCupFeatures(false, true);
-
- EXPECT_FALSE(autofill_assistant::CUP::ShouldVerifyResponses(
- autofill_assistant::RpcType::GET_ACTIONS));
-}
-
-TEST_F(CUPTest, ShouldNotVerifyNotGetActionsResponse) {
- InitCupFeatures(true, true);
-
- EXPECT_FALSE(autofill_assistant::CUP::ShouldVerifyResponses(
- autofill_assistant::RpcType::GET_TRIGGER_SCRIPTS));
-}
-
-TEST_F(CUPTest, PacksAndSignsGetActionsRequest) {
- InitCupFeatures(true, false);
-
- autofill_assistant::ScriptActionRequestProto user_request;
- user_request.mutable_client_context()->set_experiment_ids("test");
- std::string user_request_str;
- user_request.SerializeToString(&user_request_str);
-
- auto packed_request_str = cup_.PackAndSignRequest(user_request_str);
-
- autofill_assistant::ScriptActionRequestProto packed_request;
- EXPECT_TRUE(packed_request.ParseFromString(packed_request_str));
- EXPECT_TRUE(packed_request.client_context().experiment_ids().empty());
- EXPECT_FALSE(packed_request.cup_data().request().empty());
- EXPECT_FALSE(packed_request.cup_data().query_cup2key().empty());
- EXPECT_FALSE(packed_request.cup_data().hash_hex().empty());
-
- autofill_assistant::ScriptActionRequestProto actual_user_request;
- EXPECT_TRUE(
- actual_user_request.ParseFromString(packed_request.cup_data().request()));
- EXPECT_EQ(actual_user_request.client_context().experiment_ids(), "test");
- EXPECT_FALSE(actual_user_request.has_cup_data());
-}
+TEST_F(CUPTest, ShouldSignAndVerify) {
+ struct TestCase {
+ bool sign_requests;
+ bool verify_responses;
+ RpcType rpc_type;
+ bool expected_should_sign;
+ bool expected_should_verify;
+ };
+ std::vector<TestCase> test_cases = {
+ {true, true, RpcType::GET_ACTIONS, true, true},
+ {true, false, RpcType::GET_ACTIONS, true, false},
+ {false, true, RpcType::GET_ACTIONS, false, false},
+ {false, false, RpcType::GET_ACTIONS, false, false},
+ {false, false, RpcType::GET_TRIGGER_SCRIPTS, false, false},
+ {true, true, RpcType::GET_TRIGGER_SCRIPTS, false, false},
+ };
+
+ RpcType unsupported_rpc_types[] = {
+ RpcType::UNKNOWN,
+ RpcType::GET_TRIGGER_SCRIPTS,
+ RpcType::SUPPORTS_SCRIPT,
+ };
+ for (const auto& unsupported_type : unsupported_rpc_types) {
+ test_cases.push_back({true, true, unsupported_type, false, false});
+ test_cases.push_back({true, false, unsupported_type, false, false});
+ test_cases.push_back({false, true, unsupported_type, false, false});
+ test_cases.push_back({false, false, unsupported_type, false, false});
+ }
-TEST_F(CUPTest, UnpacksTrustedGetActionsResponse) {
- // TODO(b/203031699): Write test for the successful case.
+ for (const auto& test_case : test_cases) {
+ InitCupFeatures(test_case.sign_requests, test_case.verify_responses);
+ EXPECT_EQ(ShouldSignRequests(test_case.rpc_type),
+ test_case.expected_should_sign);
+ EXPECT_EQ(ShouldVerifyResponses(test_case.rpc_type),
+ test_case.expected_should_verify);
+ }
}
-TEST_F(CUPTest, FailsToUnpackNonTrustedGetActionsResponse) {
- InitCupFeatures(true, true);
-
- autofill_assistant::ScriptActionRequestProto user_request;
- user_request.mutable_client_context()->set_experiment_ids("123");
- std::string user_request_str;
- user_request.SerializeToString(&user_request_str);
-
- cup_.PackAndSignRequest(user_request_str);
- cup_.GetQuerySigner().OverrideNonceForTesting(8, 12345);
-
- autofill_assistant::ActionsResponseProto user_response;
- user_response.set_global_payload("adsf");
- std::string user_response_str;
- user_response.SerializeToString(&user_response_str);
- autofill_assistant::ActionsResponseProto packed_response;
- packed_response.mutable_cup_data()->set_response(user_response_str);
- packed_response.mutable_cup_data()->set_ecdsa_signature("not a signature");
-
- EXPECT_EQ(cup_.UnpackResponse(user_response_str), absl::nullopt);
-}
+} // namespace cup
-} // namespace
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/service/java_service_request_sender.cc b/chromium/components/autofill_assistant/browser/service/java_service_request_sender.cc
index 7fa568dea8b..2d601550c6b 100644
--- a/chromium/components/autofill_assistant/browser/service/java_service_request_sender.cc
+++ b/chromium/components/autofill_assistant/browser/service/java_service_request_sender.cc
@@ -24,7 +24,8 @@ JavaServiceRequestSender::~JavaServiceRequestSender() = default;
void JavaServiceRequestSender::SendRequest(const GURL& url,
const std::string& request_body,
- ResponseCallback callback) {
+ ResponseCallback callback,
+ RpcType rpc_type) {
DCHECK(!callback_)
<< __func__
<< " invoked while still waiting for response to previous request";
diff --git a/chromium/components/autofill_assistant/browser/service/java_service_request_sender.h b/chromium/components/autofill_assistant/browser/service/java_service_request_sender.h
index 200d17a007b..f1e32626867 100644
--- a/chromium/components/autofill_assistant/browser/service/java_service_request_sender.h
+++ b/chromium/components/autofill_assistant/browser/service/java_service_request_sender.h
@@ -30,7 +30,8 @@ class JavaServiceRequestSender : public ServiceRequestSender {
void SendRequest(const GURL& url,
const std::string& request_body,
- ResponseCallback callback) override;
+ ResponseCallback callback,
+ RpcType rpc_type) override;
void OnResponse(JNIEnv* env,
const base::android::JavaParamRef<jobject>& jcaller,
diff --git a/chromium/components/autofill_assistant/browser/service/mock_cup.cc b/chromium/components/autofill_assistant/browser/service/mock_cup.cc
new file mode 100644
index 00000000000..713a7b0ff32
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/service/mock_cup.cc
@@ -0,0 +1,21 @@
+// Copyright 2021 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.
+
+#include <string>
+
+#include "components/autofill_assistant/browser/service/mock_cup.h"
+
+namespace autofill_assistant {
+
+namespace cup {
+
+MockCUP::MockCUP() = default;
+MockCUP::~MockCUP() = default;
+
+MockCUPFactory::MockCUPFactory() = default;
+MockCUPFactory::~MockCUPFactory() = default;
+
+} // namespace cup
+
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/service/mock_cup.h b/chromium/components/autofill_assistant/browser/service/mock_cup.h
new file mode 100644
index 00000000000..36217361647
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/service/mock_cup.h
@@ -0,0 +1,41 @@
+// Copyright 2021 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.
+
+#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_MOCK_CUP_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_MOCK_CUP_H_
+
+#include "components/autofill_assistant/browser/service/cup.h"
+#include "components/autofill_assistant/browser/service/cup_factory.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace autofill_assistant {
+
+namespace cup {
+
+class MockCUP : public CUP {
+ public:
+ MockCUP();
+ ~MockCUP() override;
+
+ MOCK_METHOD1(PackAndSignRequest,
+ std::string(const std::string& original_request));
+
+ MOCK_METHOD1(
+ UnpackResponse,
+ absl::optional<std::string>(const std::string& original_response));
+};
+
+class MockCUPFactory : public CUPFactory {
+ public:
+ MockCUPFactory();
+ ~MockCUPFactory() override;
+
+ MOCK_CONST_METHOD1(CreateInstance, std::unique_ptr<CUP>(RpcType rpc_type));
+};
+
+} // namespace cup
+
+} // namespace autofill_assistant
+
+#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_MOCK_CUP_H_
diff --git a/chromium/components/autofill_assistant/browser/service/mock_service_request_sender.h b/chromium/components/autofill_assistant/browser/service/mock_service_request_sender.h
index 2911f6f92b6..0f7d44d1a49 100644
--- a/chromium/components/autofill_assistant/browser/service/mock_service_request_sender.h
+++ b/chromium/components/autofill_assistant/browser/service/mock_service_request_sender.h
@@ -20,14 +20,16 @@ class MockServiceRequestSender : public ServiceRequestSender {
void SendRequest(const GURL& url,
const std::string& request_body,
- ResponseCallback callback) override {
- OnSendRequest(url, request_body, callback);
+ ResponseCallback callback,
+ RpcType rpc_type) override {
+ OnSendRequest(url, request_body, callback, rpc_type);
}
- MOCK_METHOD3(OnSendRequest,
+ MOCK_METHOD4(OnSendRequest,
void(const GURL& url,
const std::string& request_body,
- ResponseCallback& callback));
+ ResponseCallback& callback,
+ RpcType rpc_type));
};
} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/service/mock_url_loader.h b/chromium/components/autofill_assistant/browser/service/mock_url_loader.h
index 50e54b80730..1a8c2b3bccd 100644
--- a/chromium/components/autofill_assistant/browser/service/mock_url_loader.h
+++ b/chromium/components/autofill_assistant/browser/service/mock_url_loader.h
@@ -11,6 +11,7 @@
#include "testing/gmock/include/gmock/gmock.h"
namespace network {
+class SimpleURLLoaderThrottle;
namespace mojom {
class URLLoaderFactory;
} // namespace mojom
@@ -70,6 +71,7 @@ class MockURLLoader : public ::network::SimpleURLLoader {
MOCK_METHOD1(SetURLLoaderFactoryOptions, void(uint32_t options));
MOCK_METHOD1(SetRequestID, void(int32_t request_id));
MOCK_METHOD1(SetTimeoutDuration, void(base::TimeDelta timeout_duration));
+ MOCK_METHOD0(SetAllowBatching, void());
MOCK_CONST_METHOD0(NetError, int());
MOCK_CONST_METHOD0(ResponseInfo, const ::network::mojom::URLResponseHead*());
MOCK_CONST_METHOD0(CompletionStatus,
@@ -78,6 +80,7 @@ class MockURLLoader : public ::network::SimpleURLLoader {
MOCK_CONST_METHOD0(LoadedFromCache, bool());
MOCK_CONST_METHOD0(GetContentSize, int64_t());
MOCK_CONST_METHOD0(GetNumRetries, int());
+ MOCK_METHOD0(GetThrottleForTesting, ::network::SimpleURLLoaderThrottle*());
};
} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/service/rpc_type.h b/chromium/components/autofill_assistant/browser/service/rpc_type.h
index dca4bb77148..17ad3fddb6f 100644
--- a/chromium/components/autofill_assistant/browser/service/rpc_type.h
+++ b/chromium/components/autofill_assistant/browser/service/rpc_type.h
@@ -12,8 +12,8 @@ enum class RpcType {
GET_ACTIONS,
GET_TRIGGER_SCRIPTS,
SUPPORTS_SCRIPT,
+ GET_CAPABILITIES_BY_HASH_PREFIX,
};
-
}
#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_SERVICE_RPC_TYPE_H_
diff --git a/chromium/components/autofill_assistant/browser/service/server_url_fetcher.cc b/chromium/components/autofill_assistant/browser/service/server_url_fetcher.cc
index e95c131f999..0793a4ffe9c 100644
--- a/chromium/components/autofill_assistant/browser/service/server_url_fetcher.cc
+++ b/chromium/components/autofill_assistant/browser/service/server_url_fetcher.cc
@@ -16,6 +16,7 @@ const char kDefaultAutofillAssistantServerUrl[] =
const char kScriptEndpoint[] = "/v1/supportsSite2";
const char kActionEndpoint[] = "/v1/actions2";
const char kTriggersEndpoint[] = "/v1/triggers";
+const char kCapabilitiesByHashEndpoint[] = "/v1/capabilitiesByHashPrefix2";
} // namespace
namespace autofill_assistant {
@@ -57,4 +58,10 @@ GURL ServerUrlFetcher::GetTriggerScriptsEndpoint() const {
return server_url_.ReplaceComponents(trigger_replacements);
}
+GURL ServerUrlFetcher::GetCapabilitiesByHashEndpoint() const {
+ GURL::Replacements trigger_replacements;
+ trigger_replacements.SetPathStr(kCapabilitiesByHashEndpoint);
+ return server_url_.ReplaceComponents(trigger_replacements);
+}
+
} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/service/server_url_fetcher.h b/chromium/components/autofill_assistant/browser/service/server_url_fetcher.h
index 9b9e48286e9..b0aee709472 100644
--- a/chromium/components/autofill_assistant/browser/service/server_url_fetcher.h
+++ b/chromium/components/autofill_assistant/browser/service/server_url_fetcher.h
@@ -27,6 +27,8 @@ class ServerUrlFetcher {
virtual GURL GetNextActionsEndpoint() const;
// Returns the endpoint to send the GetTriggerScripts RPC to.
virtual GURL GetTriggerScriptsEndpoint() const;
+ // Returns the endpoint to send the GetCapabilitiesByHashPrefix RPC to.
+ virtual GURL GetCapabilitiesByHashEndpoint() const;
private:
GURL server_url_;
diff --git a/chromium/components/autofill_assistant/browser/service/server_url_fetcher_unittest.cc b/chromium/components/autofill_assistant/browser/service/server_url_fetcher_unittest.cc
index 5f2308247d1..ce78aeda6e5 100644
--- a/chromium/components/autofill_assistant/browser/service/server_url_fetcher_unittest.cc
+++ b/chromium/components/autofill_assistant/browser/service/server_url_fetcher_unittest.cc
@@ -54,5 +54,11 @@ TEST(ServerUrlFetcherTest, GetTriggerScriptsEndpoint) {
Eq(GURL("https://www.example.com/v1/triggers")));
}
+TEST(ServerUrlFetcherTest, GetCapabilitiesByHashEndpoint) {
+ EXPECT_THAT(ServerUrlFetcher(GURL("https://www.example.com"))
+ .GetCapabilitiesByHashEndpoint(),
+ Eq(GURL("https://www.example.com/v1/capabilitiesByHashPrefix2")));
+}
+
} // namespace
} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/service/service_impl.cc b/chromium/components/autofill_assistant/browser/service/service_impl.cc
index a9b7c531341..633a953c630 100644
--- a/chromium/components/autofill_assistant/browser/service/service_impl.cc
+++ b/chromium/components/autofill_assistant/browser/service/service_impl.cc
@@ -16,6 +16,7 @@
#include "components/autofill_assistant/browser/features.h"
#include "components/autofill_assistant/browser/protocol_utils.h"
#include "components/autofill_assistant/browser/service/api_key_fetcher.h"
+#include "components/autofill_assistant/browser/service/cup_factory.h"
#include "components/autofill_assistant/browser/service/service_request_sender_impl.h"
#include "components/autofill_assistant/browser/switches.h"
#include "components/autofill_assistant/browser/trigger_context.h"
@@ -44,6 +45,7 @@ std::unique_ptr<ServiceImpl> ServiceImpl::Create(
const ServerUrlFetcher& url_fetcher) {
auto request_sender = std::make_unique<ServiceRequestSenderImpl>(
context, client->GetAccessTokenFetcher(),
+ std::make_unique<cup::CUPImplFactory>(),
std::make_unique<NativeURLLoaderFactory>(),
ApiKeyFetcher().GetAPIKey(client->GetChannel()),
/* auth_enabled = */ "false" !=
@@ -88,7 +90,7 @@ void ServiceImpl::GetScriptsForUrl(const GURL& url,
ProtocolUtils::CreateGetScriptsRequest(
url, client_context_->AsProto(),
trigger_context.GetScriptParameters()),
- std::move(callback));
+ std::move(callback), RpcType::SUPPORTS_SCRIPT);
}
void ServiceImpl::GetActions(const std::string& script_path,
@@ -139,7 +141,7 @@ void ServiceImpl::SendGetActions(const std::string& script_path,
script_path, url, global_payload, script_payload,
client_context_->AsProto(), trigger_context.GetScriptParameters(),
script_store_config_),
- std::move(callback));
+ std::move(callback), RpcType::GET_ACTIONS);
}
void ServiceImpl::GetNextActions(
@@ -155,7 +157,7 @@ void ServiceImpl::GetNextActions(
ProtocolUtils::CreateNextScriptActionsRequest(
previous_global_payload, previous_script_payload, processed_actions,
timing_stats, client_context_->AsProto()),
- std::move(callback));
+ std::move(callback), RpcType::GET_ACTIONS);
}
} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/service/service_impl_unittest.cc b/chromium/components/autofill_assistant/browser/service/service_impl_unittest.cc
index 267f85d9e06..314d6ce4289 100644
--- a/chromium/components/autofill_assistant/browser/service/service_impl_unittest.cc
+++ b/chromium/components/autofill_assistant/browser/service/service_impl_unittest.cc
@@ -58,8 +58,8 @@ class ServiceImplTest : public testing::Test {
TEST_F(ServiceImplTest, GetScriptsForUrl) {
EXPECT_CALL(*mock_client_context_, Update);
- EXPECT_CALL(*mock_request_sender_,
- OnSendRequest(GURL(kScriptServerUrl), _, _))
+ EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kScriptServerUrl), _, _,
+ RpcType::SUPPORTS_SCRIPT))
.WillOnce(RunOnceCallback<2>(net::HTTP_OK, std::string("response")));
EXPECT_CALL(mock_response_callback_,
Run(net::HTTP_OK, std::string("response")));
@@ -74,7 +74,7 @@ TEST_F(ServiceImplTest, GetActions) {
.WillOnce(RunOnceCallback<0>("token"));
EXPECT_CALL(*mock_client_context_, SetPaymentsClientToken("token"));
EXPECT_CALL(*mock_request_sender_,
- OnSendRequest(GURL(kActionServerUrl), _, _))
+ OnSendRequest(GURL(kActionServerUrl), _, _, RpcType::GET_ACTIONS))
.WillOnce(RunOnceCallback<2>(net::HTTP_OK, std::string("response")));
EXPECT_CALL(mock_response_callback_,
Run(net::HTTP_OK, std::string("response")));
@@ -99,7 +99,7 @@ TEST_F(ServiceImplTest, GetActionsForwardsScriptStoreConfig) {
std::string get_actions_request;
EXPECT_CALL(*mock_request_sender_,
- OnSendRequest(GURL(kActionServerUrl), _, _))
+ OnSendRequest(GURL(kActionServerUrl), _, _, RpcType::GET_ACTIONS))
.WillOnce(SaveArg<1>(&get_actions_request));
ScriptStoreConfig set_config;
@@ -131,7 +131,7 @@ TEST_F(ServiceImplTest, GetActionsWithoutClientToken) {
EXPECT_CALL(mock_client_, FetchPaymentsClientToken).Times(0);
EXPECT_CALL(*mock_client_context_, SetPaymentsClientToken).Times(0);
EXPECT_CALL(*mock_request_sender_,
- OnSendRequest(GURL(kActionServerUrl), _, _))
+ OnSendRequest(GURL(kActionServerUrl), _, _, RpcType::GET_ACTIONS))
.WillOnce(RunOnceCallback<2>(net::HTTP_OK, std::string("response")));
EXPECT_CALL(mock_response_callback_,
Run(net::HTTP_OK, std::string("response")));
@@ -152,7 +152,7 @@ TEST_F(ServiceImplTest, GetActionsDoesNotReloadClientToken) {
EXPECT_CALL(mock_client_, FetchPaymentsClientToken).Times(0);
EXPECT_CALL(*mock_client_context_, SetPaymentsClientToken).Times(0);
EXPECT_CALL(*mock_request_sender_,
- OnSendRequest(GURL(kActionServerUrl), _, _))
+ OnSendRequest(GURL(kActionServerUrl), _, _, RpcType::GET_ACTIONS))
.WillOnce(RunOnceCallback<2>(net::HTTP_OK, std::string("response")));
EXPECT_CALL(mock_response_callback_,
Run(net::HTTP_OK, std::string("response")));
@@ -166,7 +166,7 @@ TEST_F(ServiceImplTest, GetActionsDoesNotReloadClientToken) {
TEST_F(ServiceImplTest, GetNextActions) {
EXPECT_CALL(*mock_client_context_, Update);
EXPECT_CALL(*mock_request_sender_,
- OnSendRequest(GURL(kActionServerUrl), _, _))
+ OnSendRequest(GURL(kActionServerUrl), _, _, RpcType::GET_ACTIONS))
.WillOnce(RunOnceCallback<2>(net::HTTP_OK, std::string("response")));
EXPECT_CALL(mock_response_callback_,
Run(net::HTTP_OK, std::string("response")));
diff --git a/chromium/components/autofill_assistant/browser/service/service_request_sender.h b/chromium/components/autofill_assistant/browser/service/service_request_sender.h
index 865e9ddd2fd..f50790d2fe6 100644
--- a/chromium/components/autofill_assistant/browser/service/service_request_sender.h
+++ b/chromium/components/autofill_assistant/browser/service/service_request_sender.h
@@ -8,6 +8,7 @@
#include <string>
#include "base/callback.h"
+#include "components/autofill_assistant/browser/service/rpc_type.h"
#include "url/gurl.h"
namespace autofill_assistant {
@@ -24,7 +25,8 @@ class ServiceRequestSender {
// response itself.
virtual void SendRequest(const GURL& url,
const std::string& request_body,
- ResponseCallback callback) = 0;
+ ResponseCallback response_callback,
+ RpcType rpc_type) = 0;
};
} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/service/service_request_sender_impl.cc b/chromium/components/autofill_assistant/browser/service/service_request_sender_impl.cc
index 7bde65e7700..b3d19e2c110 100644
--- a/chromium/components/autofill_assistant/browser/service/service_request_sender_impl.cc
+++ b/chromium/components/autofill_assistant/browser/service/service_request_sender_impl.cc
@@ -4,7 +4,12 @@
#include "components/autofill_assistant/browser/service/service_request_sender_impl.h"
+#include "base/feature_list.h"
#include "base/strings/strcat.h"
+#include "components/autofill_assistant/browser/features.h"
+#include "components/autofill_assistant/browser/service.pb.h"
+#include "components/autofill_assistant/browser/service/cup.h"
+#include "components/autofill_assistant/browser/service/cup_impl.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/storage_partition.h"
#include "net/base/load_flags.h"
@@ -115,6 +120,20 @@ void SendRequestNoAuth(
loader_factory, std::move(callback));
}
+void VerifyCupResponse(
+ std::unique_ptr<autofill_assistant::cup::CUP> cup,
+ autofill_assistant::ServiceRequestSender::ResponseCallback callback,
+ int http_status,
+ const std::string& response) {
+ absl::optional<std::string> unpacked_response = cup->UnpackResponse(response);
+ if (!unpacked_response) {
+ LOG(ERROR) << "Failed to unpack or verify a response.";
+ return std::move(callback).Run(net::HTTP_UNAUTHORIZED, std::string());
+ }
+
+ return std::move(callback).Run(http_status, *unpacked_response);
+}
+
} // namespace
namespace autofill_assistant {
@@ -122,12 +141,14 @@ namespace autofill_assistant {
ServiceRequestSenderImpl::ServiceRequestSenderImpl(
content::BrowserContext* context,
AccessTokenFetcher* access_token_fetcher,
+ std::unique_ptr<cup::CUPFactory> cup_factory,
std::unique_ptr<SimpleURLLoaderFactory> loader_factory,
const std::string& api_key,
bool auth_enabled,
bool disable_auth_if_no_access_token)
: context_(context),
access_token_fetcher_(access_token_fetcher),
+ cup_factory_(std::move(cup_factory)),
loader_factory_(std::move(loader_factory)),
api_key_(api_key),
auth_enabled_(auth_enabled),
@@ -139,7 +160,30 @@ ServiceRequestSenderImpl::~ServiceRequestSenderImpl() = default;
void ServiceRequestSenderImpl::SendRequest(const GURL& url,
const std::string& request_body,
- ResponseCallback callback) {
+ ResponseCallback callback,
+ RpcType rpc_type) {
+ if (!cup::ShouldSignRequests(rpc_type)) {
+ InternalSendRequest(url, request_body, std::move(callback));
+ return;
+ }
+
+ std::unique_ptr<cup::CUP> cup =
+ cup_factory_->CreateInstance(RpcType::GET_ACTIONS);
+ std::string signed_request = cup->PackAndSignRequest(request_body);
+
+ auto maybe_wrapped_callback = std::move(callback);
+ if (cup::ShouldVerifyResponses(rpc_type)) {
+ maybe_wrapped_callback = base::BindOnce(&VerifyCupResponse, std::move(cup),
+ std::move(maybe_wrapped_callback));
+ }
+
+ InternalSendRequest(url, signed_request, std::move(maybe_wrapped_callback));
+}
+
+void ServiceRequestSenderImpl::InternalSendRequest(
+ const GURL& url,
+ const std::string& request_body,
+ ResponseCallback callback) {
if (auth_enabled_ && access_token_fetcher_ == nullptr) {
LOG(ERROR) << "auth requested, but no access token fetcher provided";
std::move(callback).Run(net::HTTP_UNAUTHORIZED, std::string());
@@ -220,7 +264,7 @@ void ServiceRequestSenderImpl::RetryIfUnauthorized(
DCHECK(!retried_with_fresh_access_token_);
retried_with_fresh_access_token_ = true;
access_token_fetcher_->InvalidateAccessToken(access_token);
- SendRequest(url, request_body, std::move(callback));
+ InternalSendRequest(url, request_body, std::move(callback));
return;
}
std::move(callback).Run(http_status, response);
diff --git a/chromium/components/autofill_assistant/browser/service/service_request_sender_impl.h b/chromium/components/autofill_assistant/browser/service/service_request_sender_impl.h
index 4d2b305fe5f..3fd743d9c35 100644
--- a/chromium/components/autofill_assistant/browser/service/service_request_sender_impl.h
+++ b/chromium/components/autofill_assistant/browser/service/service_request_sender_impl.h
@@ -12,6 +12,7 @@
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "components/autofill_assistant/browser/service/access_token_fetcher.h"
+#include "components/autofill_assistant/browser/service/cup_factory.h"
#include "components/autofill_assistant/browser/service/service_request_sender.h"
#include "components/autofill_assistant/browser/service/simple_url_loader_factory.h"
#include "content/public/browser/browser_context.h"
@@ -33,6 +34,7 @@ class ServiceRequestSenderImpl : public ServiceRequestSender {
ServiceRequestSenderImpl(
content::BrowserContext* context,
AccessTokenFetcher* access_token_fetcher,
+ std::unique_ptr<cup::CUPFactory> cup_factory,
std::unique_ptr<SimpleURLLoaderFactory> loader_factory,
const std::string& api_key,
bool auth_enabled,
@@ -42,18 +44,27 @@ class ServiceRequestSenderImpl : public ServiceRequestSender {
ServiceRequestSenderImpl& operator=(const ServiceRequestSenderImpl&) = delete;
// Sends |request_body| to |url|. Depending on configuration, the request
- // will be authenticated either with an Oauth access token or the api key.
- // Returns the http status code and the response itself. If the returned http
- // headers could not be parsed, the http code will be 0.
+ // will be authenticated either with an Oauth access token or the api key. The
+ // |rpc_type| will be used to decide whether to use CUP verification. Returns
+ // the http status code and the response itself. If the returned http headers
+ // could not be parsed, the http code will be 0.
//
// When an auth-request first fails with a 401, the access token is
// invalidated and fetched again. If the request fails again, the request
// is considered failed and the callback is invoked.
void SendRequest(const GURL& url,
const std::string& request_body,
- ResponseCallback callback) override;
+ ResponseCallback callback,
+ RpcType rpc_type) override;
private:
+ // Unlike |ServiceRequestSenderImpl::SendRequest|, assumes that any necessary
+ // CUP signing and validation is already done or accounted for in the
+ // |callback|.
+ void InternalSendRequest(const GURL& url,
+ const std::string& request_body,
+ ResponseCallback callback);
+
void SendRequestAuth(const GURL& url,
const std::string& request_body,
const std::string& access_token,
@@ -74,6 +85,7 @@ class ServiceRequestSenderImpl : public ServiceRequestSender {
raw_ptr<content::BrowserContext> context_ = nullptr;
raw_ptr<AccessTokenFetcher> access_token_fetcher_ = nullptr;
+ std::unique_ptr<cup::CUPFactory> cup_factory_;
std::unique_ptr<SimpleURLLoaderFactory> loader_factory_;
// API key to add to the URL of unauthenticated requests.
diff --git a/chromium/components/autofill_assistant/browser/service/service_request_sender_impl_unittest.cc b/chromium/components/autofill_assistant/browser/service/service_request_sender_impl_unittest.cc
index f2586ecf8b8..896e175abb9 100644
--- a/chromium/components/autofill_assistant/browser/service/service_request_sender_impl_unittest.cc
+++ b/chromium/components/autofill_assistant/browser/service/service_request_sender_impl_unittest.cc
@@ -11,8 +11,12 @@
#include "base/strings/string_number_conversions.h"
#include "base/test/gmock_callback_support.h"
#include "base/test/mock_callback.h"
+#include "base/test/scoped_feature_list.h"
+#include "components/autofill_assistant/browser/features.h"
+#include "components/autofill_assistant/browser/service.pb.h"
#include "components/autofill_assistant/browser/service/access_token_fetcher.h"
#include "components/autofill_assistant/browser/service/mock_access_token_fetcher.h"
+#include "components/autofill_assistant/browser/service/mock_cup.h"
#include "components/autofill_assistant/browser/service/mock_simple_url_loader_factory.h"
#include "components/autofill_assistant/browser/service/mock_url_loader.h"
#include "content/public/test/browser_task_environment.h"
@@ -51,6 +55,7 @@ class ServiceRequestSenderImplTest : public testing::Test {
~ServiceRequestSenderImplTest() override = default;
protected:
+ base::test::ScopedFeatureList scoped_feature_list_;
base::MockCallback<base::OnceCallback<void(int, const std::string&)>>
mock_response_callback_;
// Note: |task_environment_| must be created before |context_|, else creation
@@ -58,9 +63,37 @@ class ServiceRequestSenderImplTest : public testing::Test {
content::BrowserTaskEnvironment task_environment_;
content::TestBrowserContext context_;
NiceMock<MockAccessTokenFetcher> mock_access_token_fetcher_;
+
+ void InitCupFeatures(bool enableSigning, bool enableVerifying) {
+ std::vector<base::Feature> enabled_features;
+ std::vector<base::Feature> disabled_features;
+
+ if (enableSigning) {
+ enabled_features.push_back(autofill_assistant::features::
+ kAutofillAssistantSignGetActionsRequests);
+ } else {
+ disabled_features.push_back(autofill_assistant::features::
+ kAutofillAssistantSignGetActionsRequests);
+ }
+
+ if (enableVerifying) {
+ enabled_features.push_back(
+ autofill_assistant::features::
+ kAutofillAssistantVerifyGetActionsResponses);
+ } else {
+ disabled_features.push_back(
+ autofill_assistant::features::
+ kAutofillAssistantVerifyGetActionsResponses);
+ }
+
+ scoped_feature_list_.Reset();
+ scoped_feature_list_.InitWithFeatures(enabled_features, disabled_features);
+ }
};
TEST_F(ServiceRequestSenderImplTest, SendUnauthenticatedRequest) {
+ auto cup_factory =
+ std::make_unique<NiceMock<autofill_assistant::cup::MockCUPFactory>>();
auto loader_factory =
std::make_unique<NiceMock<MockSimpleURLLoaderFactory>>();
auto loader = std::make_unique<NiceMock<MockURLLoader>>();
@@ -88,16 +121,19 @@ TEST_F(ServiceRequestSenderImplTest, SendUnauthenticatedRequest) {
ServiceRequestSenderImpl request_sender{
&context_,
/* access_token_fetcher = */ nullptr,
+ std::move(cup_factory),
std::move(loader_factory),
std::string("fake_api_key"),
/* auth_enabled = */ false,
/* disable_auth_if_no_access_token = */ true};
- request_sender.SendRequest(GURL("https://www.example.com"),
- std::string("request"),
- mock_response_callback_.Get());
+ request_sender.SendRequest(
+ GURL("https://www.example.com"), std::string("request"),
+ mock_response_callback_.Get(), RpcType::GET_TRIGGER_SCRIPTS);
}
TEST_F(ServiceRequestSenderImplTest, SendAuthenticatedRequest) {
+ auto cup_factory =
+ std::make_unique<NiceMock<autofill_assistant::cup::MockCUPFactory>>();
auto loader_factory =
std::make_unique<NiceMock<MockSimpleURLLoaderFactory>>();
auto loader = std::make_unique<NiceMock<MockURLLoader>>();
@@ -131,13 +167,15 @@ TEST_F(ServiceRequestSenderImplTest, SendAuthenticatedRequest) {
ServiceRequestSenderImpl request_sender{
&context_,
/* access_token_fetcher = */ &mock_access_token_fetcher_,
+ std::move(cup_factory),
std::move(loader_factory),
/* api_key = */ std::string(""),
/* auth_enabled = */ true,
/* disable_auth_if_no_access_token = */ true};
request_sender.SendRequest(GURL("https://www.example.com"),
std::string("request"),
- mock_response_callback_.Get());
+ mock_response_callback_.Get(),
+ autofill_assistant::RpcType::GET_TRIGGER_SCRIPTS);
}
TEST_F(ServiceRequestSenderImplTest,
@@ -146,6 +184,8 @@ TEST_F(ServiceRequestSenderImplTest,
.Times(1)
.WillOnce(RunOnceCallback<0>(true, /*access_token = */ ""));
+ auto cup_factory =
+ std::make_unique<NiceMock<autofill_assistant::cup::MockCUPFactory>>();
auto loader_factory =
std::make_unique<NiceMock<MockSimpleURLLoaderFactory>>();
auto loader = std::make_unique<NiceMock<MockURLLoader>>();
@@ -173,13 +213,15 @@ TEST_F(ServiceRequestSenderImplTest,
ServiceRequestSenderImpl request_sender{
&context_,
/* access_token_fetcher = */ &mock_access_token_fetcher_,
+ std::move(cup_factory),
std::move(loader_factory),
/* api_key = */ std::string("fake_api_key"),
/* auth_enabled = */ true,
/* disable_auth_if_no_access_token = */ true};
request_sender.SendRequest(GURL("https://www.example.com"),
std::string("request"),
- mock_response_callback_.Get());
+ mock_response_callback_.Get(),
+ autofill_assistant::RpcType::GET_TRIGGER_SCRIPTS);
}
TEST_F(ServiceRequestSenderImplTest,
@@ -189,6 +231,8 @@ TEST_F(ServiceRequestSenderImplTest,
.WillOnce(
RunOnceCallback<0>(/*success = */ false, /*access_token = */ ""));
+ auto cup_factory =
+ std::make_unique<NiceMock<autofill_assistant::cup::MockCUPFactory>>();
auto loader_factory =
std::make_unique<NiceMock<MockSimpleURLLoaderFactory>>();
auto loader = std::make_unique<NiceMock<MockURLLoader>>();
@@ -216,13 +260,159 @@ TEST_F(ServiceRequestSenderImplTest,
ServiceRequestSenderImpl request_sender{
&context_,
/* access_token_fetcher = */ &mock_access_token_fetcher_,
+ std::move(cup_factory),
std::move(loader_factory),
/* api_key = */ std::string("fake_api_key"),
/* auth_enabled = */ true,
/* disable_auth_if_no_access_token = */ true};
request_sender.SendRequest(GURL("https://www.example.com"),
std::string("request"),
- mock_response_callback_.Get());
+ mock_response_callback_.Get(),
+ autofill_assistant::RpcType::GET_TRIGGER_SCRIPTS);
+}
+
+TEST_F(ServiceRequestSenderImplTest,
+ DoesNotCreateInstanceWhenFeatureNotEnabled) {
+ InitCupFeatures(false, false);
+ auto cup_factory =
+ std::make_unique<NiceMock<autofill_assistant::cup::MockCUPFactory>>();
+ auto loader_factory =
+ std::make_unique<NiceMock<MockSimpleURLLoaderFactory>>();
+ auto loader = std::make_unique<NiceMock<MockURLLoader>>();
+ auto response_info = CreateResponseInfo(net::HTTP_OK, "OK");
+ EXPECT_CALL(*loader_factory, OnCreateLoader(_, _))
+ .WillOnce([&](::network::ResourceRequest* resource_request,
+ const ::net::NetworkTrafficAnnotationTag& annotation_tag) {
+ EXPECT_FALSE(resource_request->headers.HasHeader("Authorization"));
+ EXPECT_EQ(resource_request->url,
+ GURL("https://www.example.com/?key=fake_api_key"));
+ return std::move(loader);
+ });
+ EXPECT_CALL(*loader,
+ AttachStringForUpload(std::string("request"),
+ std::string("application/x-protobuffer")))
+ .Times(1);
+ EXPECT_CALL(*loader, DownloadToStringOfUnboundedSizeUntilCrashAndDie(_, _))
+ .WillOnce(WithArgs<1>([&](auto&& callback) {
+ std::move(callback).Run(std::make_unique<std::string>("response"));
+ }));
+ EXPECT_CALL(*loader, ResponseInfo)
+ .WillRepeatedly(Return(response_info.get()));
+ EXPECT_CALL(mock_response_callback_, Run(net::HTTP_OK, "response"));
+
+ EXPECT_CALL(*cup_factory, CreateInstance(_)).Times(0);
+ ServiceRequestSenderImpl request_sender{
+ &context_,
+ /* access_token_fetcher = */ nullptr,
+ std::move(cup_factory),
+ std::move(loader_factory),
+ std::string("fake_api_key"),
+ /* auth_enabled = */ false,
+ /* disable_auth_if_no_access_token = */ true};
+ request_sender.SendRequest(
+ GURL("https://www.example.com"), std::string("request"),
+ mock_response_callback_.Get(), RpcType::GET_ACTIONS);
+}
+
+TEST_F(ServiceRequestSenderImplTest, SignsGetActionsRequestWhenFeatureEnabled) {
+ InitCupFeatures(true, false);
+ auto cup_factory =
+ std::make_unique<NiceMock<autofill_assistant::cup::MockCUPFactory>>();
+ auto cup = std::make_unique<NiceMock<autofill_assistant::cup::MockCUP>>();
+ auto loader_factory =
+ std::make_unique<NiceMock<MockSimpleURLLoaderFactory>>();
+ auto loader = std::make_unique<NiceMock<MockURLLoader>>();
+ auto response_info = CreateResponseInfo(net::HTTP_OK, "OK");
+ EXPECT_CALL(*loader_factory, OnCreateLoader(_, _))
+ .WillOnce([&](::network::ResourceRequest* resource_request,
+ const ::net::NetworkTrafficAnnotationTag& annotation_tag) {
+ EXPECT_FALSE(resource_request->headers.HasHeader("Authorization"));
+ EXPECT_EQ(resource_request->url,
+ GURL("https://www.example.com/?key=fake_api_key"));
+ return std::move(loader);
+ });
+ EXPECT_CALL(*loader,
+ AttachStringForUpload(std::string("signed_request"),
+ std::string("application/x-protobuffer")))
+ .Times(1);
+ EXPECT_CALL(*loader, DownloadToStringOfUnboundedSizeUntilCrashAndDie(_, _))
+ .WillOnce(WithArgs<1>([&](auto&& callback) {
+ std::move(callback).Run(std::make_unique<std::string>("response"));
+ }));
+ EXPECT_CALL(*loader, ResponseInfo)
+ .WillRepeatedly(Return(response_info.get()));
+ EXPECT_CALL(mock_response_callback_, Run(net::HTTP_OK, "response"));
+
+ EXPECT_CALL(*cup_factory,
+ CreateInstance(autofill_assistant::RpcType::GET_ACTIONS))
+ .WillOnce([&]() { return std::move(cup); });
+ EXPECT_CALL(*cup, PackAndSignRequest("request")).WillOnce([&]() {
+ return "signed_request";
+ });
+ EXPECT_CALL(*cup, UnpackResponse(_)).Times(0);
+ ServiceRequestSenderImpl request_sender{
+ &context_,
+ /* access_token_fetcher = */ nullptr,
+ std::move(cup_factory),
+ std::move(loader_factory),
+ std::string("fake_api_key"),
+ /* auth_enabled = */ false,
+ /* disable_auth_if_no_access_token = */ true};
+ request_sender.SendRequest(
+ GURL("https://www.example.com"), std::string("request"),
+ mock_response_callback_.Get(), RpcType::GET_ACTIONS);
+}
+
+TEST_F(ServiceRequestSenderImplTest, ValidatesGetActionsResponsesWhenEnabled) {
+ InitCupFeatures(true, true);
+ auto cup_factory =
+ std::make_unique<NiceMock<autofill_assistant::cup::MockCUPFactory>>();
+ auto cup = std::make_unique<NiceMock<autofill_assistant::cup::MockCUP>>();
+ auto loader_factory =
+ std::make_unique<NiceMock<MockSimpleURLLoaderFactory>>();
+ auto loader = std::make_unique<NiceMock<MockURLLoader>>();
+ auto response_info = CreateResponseInfo(net::HTTP_OK, "OK");
+ EXPECT_CALL(*loader_factory, OnCreateLoader(_, _))
+ .WillOnce([&](::network::ResourceRequest* resource_request,
+ const ::net::NetworkTrafficAnnotationTag& annotation_tag) {
+ EXPECT_FALSE(resource_request->headers.HasHeader("Authorization"));
+ EXPECT_EQ(resource_request->url,
+ GURL("https://www.example.com/?key=fake_api_key"));
+ return std::move(loader);
+ });
+ EXPECT_CALL(*loader,
+ AttachStringForUpload(std::string("signed_request"),
+ std::string("application/x-protobuffer")))
+ .Times(1);
+ EXPECT_CALL(*loader, DownloadToStringOfUnboundedSizeUntilCrashAndDie(_, _))
+ .WillOnce(WithArgs<1>([&](auto&& callback) {
+ std::move(callback).Run(
+ std::make_unique<std::string>("packed_response"));
+ }));
+ EXPECT_CALL(*loader, ResponseInfo)
+ .WillRepeatedly(Return(response_info.get()));
+ EXPECT_CALL(mock_response_callback_, Run(net::HTTP_OK, "response"));
+
+ EXPECT_CALL(*cup_factory,
+ CreateInstance(autofill_assistant::RpcType::GET_ACTIONS))
+ .WillOnce([&]() { return std::move(cup); });
+ EXPECT_CALL(*cup, PackAndSignRequest("request")).WillOnce([&]() {
+ return "signed_request";
+ });
+ EXPECT_CALL(*cup, UnpackResponse("packed_response")).WillOnce([&]() {
+ return "response";
+ });
+ ServiceRequestSenderImpl request_sender{
+ &context_,
+ /* access_token_fetcher = */ nullptr,
+ std::move(cup_factory),
+ std::move(loader_factory),
+ std::string("fake_api_key"),
+ /* auth_enabled = */ false,
+ /* disable_auth_if_no_access_token = */ true};
+ request_sender.SendRequest(
+ GURL("https://www.example.com"), std::string("request"),
+ mock_response_callback_.Get(), autofill_assistant::RpcType::GET_ACTIONS);
}
// TODO(b/170934170): Add tests for full unit test coverage of
diff --git a/chromium/components/autofill_assistant/browser/service/service_request_sender_local_impl.cc b/chromium/components/autofill_assistant/browser/service/service_request_sender_local_impl.cc
index 8c4b7a18b84..707ea7b82d4 100644
--- a/chromium/components/autofill_assistant/browser/service/service_request_sender_local_impl.cc
+++ b/chromium/components/autofill_assistant/browser/service/service_request_sender_local_impl.cc
@@ -15,7 +15,8 @@ ServiceRequestSenderLocalImpl::~ServiceRequestSenderLocalImpl() = default;
void ServiceRequestSenderLocalImpl::SendRequest(const GURL& url,
const std::string& request_body,
- ResponseCallback callback) {
+ ResponseCallback callback,
+ RpcType rpc_type) {
std::move(callback).Run(net::HTTP_OK, response_);
}
diff --git a/chromium/components/autofill_assistant/browser/service/service_request_sender_local_impl.h b/chromium/components/autofill_assistant/browser/service/service_request_sender_local_impl.h
index a7cd8fd47d1..ff360395462 100644
--- a/chromium/components/autofill_assistant/browser/service/service_request_sender_local_impl.h
+++ b/chromium/components/autofill_assistant/browser/service/service_request_sender_local_impl.h
@@ -22,7 +22,8 @@ class ServiceRequestSenderLocalImpl : public ServiceRequestSender {
// TODO(arbesser): Make this more flexible.
void SendRequest(const GURL& url,
const std::string& request_body,
- ResponseCallback callback) override;
+ ResponseCallback callback,
+ RpcType rpc_type) override;
private:
std::string response_;
diff --git a/chromium/components/autofill_assistant/browser/service/service_request_sender_local_impl_unittest.cc b/chromium/components/autofill_assistant/browser/service/service_request_sender_local_impl_unittest.cc
index 3f36931dee3..ba85aafb79f 100644
--- a/chromium/components/autofill_assistant/browser/service/service_request_sender_local_impl_unittest.cc
+++ b/chromium/components/autofill_assistant/browser/service/service_request_sender_local_impl_unittest.cc
@@ -28,10 +28,10 @@ class ServiceRequestSenderLocalImplTest : public testing::Test {
TEST_F(ServiceRequestSenderLocalImplTest, SendRequestAlwaysReturnsResponse) {
ServiceRequestSenderLocalImpl service_request_sender = {"response"};
EXPECT_CALL(mock_response_callback_, Run(net::HTTP_OK, "response")).Times(2);
- service_request_sender.SendRequest(GURL(), "request_1",
- mock_response_callback_.Get());
- service_request_sender.SendRequest(GURL(), "request_2",
- mock_response_callback_.Get());
+ service_request_sender.SendRequest(
+ GURL(), "request_1", mock_response_callback_.Get(), RpcType::UNKNOWN);
+ service_request_sender.SendRequest(
+ GURL(), "request_2", mock_response_callback_.Get(), RpcType::UNKNOWN);
}
} // namespace
diff --git a/chromium/components/autofill_assistant/browser/starter.cc b/chromium/components/autofill_assistant/browser/starter.cc
index d573cc686ce..233eb9036c9 100644
--- a/chromium/components/autofill_assistant/browser/starter.cc
+++ b/chromium/components/autofill_assistant/browser/starter.cc
@@ -19,6 +19,7 @@
#include "components/autofill_assistant/browser/features.h"
#include "components/autofill_assistant/browser/intent_strings.h"
#include "components/autofill_assistant/browser/service/api_key_fetcher.h"
+#include "components/autofill_assistant/browser/service/cup_impl.h"
#include "components/autofill_assistant/browser/service/server_url_fetcher.h"
#include "components/autofill_assistant/browser/service/service_request_sender.h"
#include "components/autofill_assistant/browser/service/service_request_sender_impl.h"
@@ -78,6 +79,7 @@ std::unique_ptr<ServiceRequestSender> CreateRpcTriggerScriptRequestSender(
return std::make_unique<ServiceRequestSenderImpl>(
browser_context,
/* access_token_fetcher = */ nullptr,
+ std::make_unique<cup::CUPImplFactory>(),
std::make_unique<NativeURLLoaderFactory>(),
ApiKeyFetcher().GetAPIKey(delegate->GetChannel()),
/* auth_enabled = */ false,
@@ -591,9 +593,11 @@ void Starter::StartTriggerScript() {
.value();
trigger_script_coordinator_ = std::make_unique<TriggerScriptCoordinator>(
platform_delegate_, web_contents(),
- WebController::CreateForWebContents(web_contents(),
- /* user_data= */ nullptr,
- /* log_info= */ nullptr),
+ WebController::CreateForWebContents(
+ web_contents(),
+ /* user_data= */ nullptr,
+ /* log_info= */ nullptr,
+ /* annotate_dom_model_service= */ nullptr),
std::move(service_request_sender),
url_fetcher.GetTriggerScriptsEndpoint(),
std::make_unique<StaticTriggerConditions>(
diff --git a/chromium/components/autofill_assistant/browser/starter_heuristic.cc b/chromium/components/autofill_assistant/browser/starter_heuristic.cc
index 3d0c615d34a..9c1482e991c 100644
--- a/chromium/components/autofill_assistant/browser/starter_heuristic.cc
+++ b/chromium/components/autofill_assistant/browser/starter_heuristic.cc
@@ -76,7 +76,7 @@ void StarterHeuristic::InitFromTrialParams() {
url_matcher::URLMatcherConditionSet::Vector condition_sets;
base::flat_map<url_matcher::URLMatcherConditionSet::ID, std::string> mapping;
url_matcher::URLMatcherConditionSet::ID next_condition_set_id = 0;
- for (const auto& heuristic : heuristics->GetList()) {
+ for (const auto& heuristic : heuristics->GetListDeprecated()) {
auto* intent =
heuristic.FindKeyOfType(kHeuristicIntentKey, base::Value::Type::STRING);
auto* url_conditions = heuristic.FindKeyOfType(
@@ -104,7 +104,7 @@ void StarterHeuristic::InitFromTrialParams() {
auto* denylisted_domains_value = dict->FindListKey(kDenylistedDomainsKey);
base::flat_set<std::string> denylisted_domains;
if (denylisted_domains_value != nullptr) {
- for (const auto& domain : denylisted_domains_value->GetList()) {
+ for (const auto& domain : denylisted_domains_value->GetListDeprecated()) {
if (!domain.is_string()) {
VLOG(1) << "Invalid type for denylisted domain";
return;
diff --git a/chromium/components/autofill_assistant/browser/starter_unittest.cc b/chromium/components/autofill_assistant/browser/starter_unittest.cc
index 95051d5b794..b1c2dc80751 100644
--- a/chromium/components/autofill_assistant/browser/starter_unittest.cc
+++ b/chromium/components/autofill_assistant/browser/starter_unittest.cc
@@ -657,9 +657,10 @@ TEST_F(StarterTest, RpcTriggerScriptSucceeds) {
trigger_script_coordinator_->PerformTriggerScriptAction(
TriggerScriptProto::ACCEPT);
});
- EXPECT_CALL(*mock_trigger_script_service_request_sender_,
- OnSendRequest(
- GURL("https://automate-pa.googleapis.com/v1/triggers"), _, _))
+ EXPECT_CALL(
+ *mock_trigger_script_service_request_sender_,
+ OnSendRequest(GURL("https://automate-pa.googleapis.com/v1/triggers"), _,
+ _, RpcType::GET_TRIGGER_SCRIPTS))
.WillOnce(
WithArgs<1, 2>([&](const std::string& request_body,
ServiceRequestSender::ResponseCallback& callback) {
@@ -1076,9 +1077,10 @@ TEST_F(StarterTest, ImplicitStartupOnSupportedDomain) {
features::kAutofillAssistantInCCTTriggering);
starter_->CheckSettings();
- EXPECT_CALL(*mock_trigger_script_service_request_sender_,
- OnSendRequest(
- GURL("https://automate-pa.googleapis.com/v1/triggers"), _, _))
+ EXPECT_CALL(
+ *mock_trigger_script_service_request_sender_,
+ OnSendRequest(GURL("https://automate-pa.googleapis.com/v1/triggers"), _,
+ _, RpcType::GET_TRIGGER_SCRIPTS))
.WillOnce(
WithArgs<1, 2>([&](const std::string& request_body,
ServiceRequestSender::ResponseCallback& callback) {
@@ -1183,9 +1185,10 @@ TEST_F(StarterTest, ImplicitStartupOnCurrentUrlAfterSettingEnabled) {
.Times(0);
SimulateNavigateToUrl(GURL("https://www.some-website.com/cart"));
- EXPECT_CALL(*mock_trigger_script_service_request_sender_,
- OnSendRequest(
- GURL("https://automate-pa.googleapis.com/v1/triggers"), _, _))
+ EXPECT_CALL(
+ *mock_trigger_script_service_request_sender_,
+ OnSendRequest(GURL("https://automate-pa.googleapis.com/v1/triggers"), _,
+ _, RpcType::GET_TRIGGER_SCRIPTS))
.WillOnce(RunOnceCallback<2>(net::HTTP_OK,
CreateTriggerScriptResponseForTest()));
EXPECT_CALL(*mock_trigger_script_ui_delegate_, ShowTriggerScript).Times(1);
@@ -1422,9 +1425,10 @@ TEST_F(StarterTest, FailedTriggerScriptFetchesForImplicitStartupAreCached) {
features::kAutofillAssistantInCCTTriggering);
starter_->CheckSettings();
- EXPECT_CALL(*mock_trigger_script_service_request_sender_,
- OnSendRequest(
- GURL("https://automate-pa.googleapis.com/v1/triggers"), _, _))
+ EXPECT_CALL(
+ *mock_trigger_script_service_request_sender_,
+ OnSendRequest(GURL("https://automate-pa.googleapis.com/v1/triggers"), _,
+ _, RpcType::GET_TRIGGER_SCRIPTS))
.WillOnce(RunOnceCallback<2>(net::HTTP_FORBIDDEN, std::string()));
EXPECT_CALL(*mock_trigger_script_ui_delegate_, ShowTriggerScript).Times(0);
EXPECT_CALL(mock_start_regular_script_callback_, Run).Times(0);
@@ -1479,9 +1483,10 @@ TEST_F(StarterTest,
features::kAutofillAssistantInCCTTriggering);
starter_->CheckSettings();
- EXPECT_CALL(*mock_trigger_script_service_request_sender_,
- OnSendRequest(
- GURL("https://automate-pa.googleapis.com/v1/triggers"), _, _))
+ EXPECT_CALL(
+ *mock_trigger_script_service_request_sender_,
+ OnSendRequest(GURL("https://automate-pa.googleapis.com/v1/triggers"), _,
+ _, RpcType::GET_TRIGGER_SCRIPTS))
.WillOnce(RunOnceCallback<2>(net::HTTP_OK,
CreateTriggerScriptResponseForTest()));
EXPECT_CALL(*mock_trigger_script_ui_delegate_, ShowTriggerScript)
@@ -1540,9 +1545,10 @@ TEST_F(StarterTest, EmptyTriggerScriptFetchesForImplicitStartupAreCached) {
features::kAutofillAssistantInCCTTriggering);
starter_->CheckSettings();
- EXPECT_CALL(*mock_trigger_script_service_request_sender_,
- OnSendRequest(
- GURL("https://automate-pa.googleapis.com/v1/triggers"), _, _))
+ EXPECT_CALL(
+ *mock_trigger_script_service_request_sender_,
+ OnSendRequest(GURL("https://automate-pa.googleapis.com/v1/triggers"), _,
+ _, RpcType::GET_TRIGGER_SCRIPTS))
.WillOnce(
WithArg<2>([&](ServiceRequestSender::ResponseCallback& callback) {
// Empty response == no trigger scripts available.
@@ -2017,9 +2023,10 @@ TEST_F(StarterTest, CommandLineScriptParametersAreAddedToImplicitTriggers) {
mock_runtime_manager_.GetWeakPtr(),
task_environment()->GetMockTickClock());
- EXPECT_CALL(*mock_trigger_script_service_request_sender_,
- OnSendRequest(
- GURL("https://automate-pa.googleapis.com/v1/triggers"), _, _))
+ EXPECT_CALL(
+ *mock_trigger_script_service_request_sender_,
+ OnSendRequest(GURL("https://automate-pa.googleapis.com/v1/triggers"), _,
+ _, RpcType::GET_TRIGGER_SCRIPTS))
.WillOnce(WithArg<1>([&](const std::string& request_body) {
GetTriggerScriptsRequestProto request;
ASSERT_TRUE(request.ParseFromString(request_body));
@@ -2086,9 +2093,10 @@ TEST(MultipleIntentStarterTest, ImplicitTriggeringSendsAllMatchingIntents) {
fake_platform_delegate.trigger_script_request_sender_for_test_ =
std::move(service_request_sender);
- EXPECT_CALL(*service_request_sender_ptr,
- OnSendRequest(
- GURL("https://automate-pa.googleapis.com/v1/triggers"), _, _))
+ EXPECT_CALL(
+ *service_request_sender_ptr,
+ OnSendRequest(GURL("https://automate-pa.googleapis.com/v1/triggers"), _,
+ _, RpcType::GET_TRIGGER_SCRIPTS))
.WillOnce(WithArg<1>([&](const std::string& request_body) {
GetTriggerScriptsRequestProto request;
ASSERT_TRUE(request.ParseFromString(request_body));
diff --git a/chromium/components/autofill_assistant/browser/state.h b/chromium/components/autofill_assistant/browser/state.h
index eaff567278c..d02b5ae3299 100644
--- a/chromium/components/autofill_assistant/browser/state.h
+++ b/chromium/components/autofill_assistant/browser/state.h
@@ -32,8 +32,10 @@ enum class AutofillAssistantState {
// Autofill assistant is keeping track of script availability.
//
- // In this mode, no UI is shown and scripts are not autostarted. User
- // actions might be available.
+ // UI will only be shown if the previous state was RUNNING and if the script
+ // finished with tell + stop.
+ //
+ // In this mode, scripts are not autostarted. User actions might be available.
//
// Note that it is possible to go from TRACKING to STARTING to trigger
// whatever autostartable scripts is defined for a page.
diff --git a/chromium/components/autofill_assistant/browser/switches.cc b/chromium/components/autofill_assistant/browser/switches.cc
index 18a432d7718..9cd6e25ee06 100644
--- a/chromium/components/autofill_assistant/browser/switches.cc
+++ b/chromium/components/autofill_assistant/browser/switches.cc
@@ -15,6 +15,15 @@ const char kAutofillAssistantAnnotateDom[] =
// during development, as prod instances require authentication.
const char kAutofillAssistantAuth[] = "autofill-assistant-auth";
+// Sets the ECDSA public key to be used for autofill_assistant in base64.
+const char kAutofillAssistantCupPublicKeyBase64[] =
+ "autofill-assistant-cup-public-key-base64";
+
+// Sets the key version of the ECDSA public key to be used for
+// autofill_assistant.
+const char kAutofillAssistantCupKeyVersion[] =
+ "autofill-assistant-cup-key-version";
+
// Forces first-time user experience if set to 'true'. This will overwrite the
// AA preference by setting first time user to 'true' before each startup.
// Does nothing if unset or is set to false. This is only useful during testing
diff --git a/chromium/components/autofill_assistant/browser/switches.h b/chromium/components/autofill_assistant/browser/switches.h
index 19a5660eeaf..995c53d8cf7 100644
--- a/chromium/components/autofill_assistant/browser/switches.h
+++ b/chromium/components/autofill_assistant/browser/switches.h
@@ -11,6 +11,8 @@ namespace switches {
// All switches in alphabetical order.
extern const char kAutofillAssistantAnnotateDom[];
extern const char kAutofillAssistantAuth[];
+extern const char kAutofillAssistantCupPublicKeyBase64[];
+extern const char kAutofillAssistantCupKeyVersion[];
extern const char kAutofillAssistantForceFirstTimeUser[];
extern const char kAutofillAssistantForceOnboarding[];
extern const char kAutofillAssistantImplicitTriggeringDebugParameters[];
diff --git a/chromium/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator.cc b/chromium/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator.cc
index 72444229ba8..d32c05eac00 100644
--- a/chromium/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator.cc
+++ b/chromium/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator.cc
@@ -78,7 +78,8 @@ void TriggerScriptCoordinator::Start(
deeplink_url_, client_context,
trigger_context_->GetScriptParameters()),
base::BindOnce(&TriggerScriptCoordinator::OnGetTriggerScripts,
- weak_ptr_factory_.GetWeakPtr()));
+ weak_ptr_factory_.GetWeakPtr()),
+ autofill_assistant::RpcType::GET_TRIGGER_SCRIPTS);
}
void TriggerScriptCoordinator::OnGetTriggerScripts(
diff --git a/chromium/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator_unittest.cc b/chromium/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator_unittest.cc
index fd89a25dedf..25a9dcde34e 100644
--- a/chromium/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator_unittest.cc
+++ b/chromium/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator_unittest.cc
@@ -175,9 +175,12 @@ TEST_F(TriggerScriptCoordinatorTest, StartSendsOnlyApprovedFields) {
{"FALLBACK_BUNDLE_ID", "fallback_id"},
{"FALLBACK_BUNDLE_VERSION", "fallback_version"}};
- EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ EXPECT_CALL(
+ *mock_request_sender_,
+ OnSendRequest(GURL(kFakeServerUrl), _, _, RpcType::GET_TRIGGER_SCRIPTS))
.WillOnce([&](const GURL& url, const std::string& request_body,
- ServiceRequestSender::ResponseCallback& callback) {
+ ServiceRequestSender::ResponseCallback& callback,
+ RpcType rpc_type) {
GetTriggerScriptsRequestProto request;
ASSERT_TRUE(request.ParseFromString(request_body));
EXPECT_THAT(request.url(), Eq(kFakeDeepLink));
@@ -210,7 +213,9 @@ TEST_F(TriggerScriptCoordinatorTest, StartSendsOnlyApprovedFields) {
}
TEST_F(TriggerScriptCoordinatorTest, StopOnBackendRequestFailed) {
- EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ EXPECT_CALL(
+ *mock_request_sender_,
+ OnSendRequest(GURL(kFakeServerUrl), _, _, RpcType::GET_TRIGGER_SCRIPTS))
.WillOnce(RunOnceCallback<2>(net::HTTP_FORBIDDEN, ""));
EXPECT_CALL(
mock_callback_,
@@ -225,7 +230,9 @@ TEST_F(TriggerScriptCoordinatorTest, StopOnBackendRequestFailed) {
}
TEST_F(TriggerScriptCoordinatorTest, StopOnParsingError) {
- EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ EXPECT_CALL(
+ *mock_request_sender_,
+ OnSendRequest(GURL(kFakeServerUrl), _, _, RpcType::GET_TRIGGER_SCRIPTS))
.WillOnce(RunOnceCallback<2>(net::HTTP_OK, "invalid"));
EXPECT_CALL(
mock_callback_,
@@ -241,7 +248,9 @@ TEST_F(TriggerScriptCoordinatorTest, StopOnParsingError) {
}
TEST_F(TriggerScriptCoordinatorTest, StopOnNoTriggerScriptsAvailable) {
- EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ EXPECT_CALL(
+ *mock_request_sender_,
+ OnSendRequest(GURL(kFakeServerUrl), _, _, RpcType::GET_TRIGGER_SCRIPTS))
.WillOnce(RunOnceCallback<2>(net::HTTP_OK, ""));
EXPECT_CALL(
mock_callback_,
@@ -268,7 +277,9 @@ TEST_F(TriggerScriptCoordinatorTest, StartChecksStaticAndDynamicConditions) {
std::string serialized_response;
response.SerializeToString(&serialized_response);
- EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ EXPECT_CALL(
+ *mock_request_sender_,
+ OnSendRequest(GURL(kFakeServerUrl), _, _, RpcType::GET_TRIGGER_SCRIPTS))
.WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
EXPECT_CALL(*mock_dynamic_trigger_conditions_, ClearConditions).Times(1);
EXPECT_CALL(*mock_dynamic_trigger_conditions_,
@@ -296,7 +307,9 @@ TEST_F(TriggerScriptCoordinatorTest, ShowAndHideTriggerScript) {
std::string serialized_response;
response.SerializeToString(&serialized_response);
- EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ EXPECT_CALL(
+ *mock_request_sender_,
+ OnSendRequest(GURL(kFakeServerUrl), _, _, RpcType::GET_TRIGGER_SCRIPTS))
.WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
ON_CALL(*mock_dynamic_trigger_conditions_,
@@ -332,7 +345,9 @@ TEST_F(TriggerScriptCoordinatorTest, PauseAndResumeOnTabVisibilityChange) {
std::string serialized_response;
response.SerializeToString(&serialized_response);
- EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ EXPECT_CALL(
+ *mock_request_sender_,
+ OnSendRequest(GURL(kFakeServerUrl), _, _, RpcType::GET_TRIGGER_SCRIPTS))
.WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
EXPECT_CALL(*mock_dynamic_trigger_conditions_,
@@ -354,7 +369,9 @@ TEST_F(TriggerScriptCoordinatorTest, PauseAndResumeOnTabVisibilityChange) {
// When a hidden tab becomes visible again, the trigger scripts must be
// fetched again.
- EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ EXPECT_CALL(
+ *mock_request_sender_,
+ OnSendRequest(GURL(kFakeServerUrl), _, _, RpcType::GET_TRIGGER_SCRIPTS))
.WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
EXPECT_CALL(*mock_dynamic_trigger_conditions_,
OnUpdate(mock_web_controller_.get(), _))
@@ -373,7 +390,9 @@ TEST_F(TriggerScriptCoordinatorTest, PerformTriggerScriptActionNotNow) {
std::string serialized_response;
response.SerializeToString(&serialized_response);
- EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ EXPECT_CALL(
+ *mock_request_sender_,
+ OnSendRequest(GURL(kFakeServerUrl), _, _, RpcType::GET_TRIGGER_SCRIPTS))
.WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
ON_CALL(*mock_dynamic_trigger_conditions_,
OnUpdate(mock_web_controller_.get(), _))
@@ -413,7 +432,9 @@ TEST_F(TriggerScriptCoordinatorTest, PerformTriggerScriptActionCancelSession) {
std::string serialized_response;
response.SerializeToString(&serialized_response);
- EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ EXPECT_CALL(
+ *mock_request_sender_,
+ OnSendRequest(GURL(kFakeServerUrl), _, _, RpcType::GET_TRIGGER_SCRIPTS))
.WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
ON_CALL(*mock_dynamic_trigger_conditions_,
OnUpdate(mock_web_controller_.get(), _))
@@ -447,7 +468,9 @@ TEST_F(TriggerScriptCoordinatorTest, PerformTriggerScriptActionCancelForever) {
std::string serialized_response;
response.SerializeToString(&serialized_response);
- EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ EXPECT_CALL(
+ *mock_request_sender_,
+ OnSendRequest(GURL(kFakeServerUrl), _, _, RpcType::GET_TRIGGER_SCRIPTS))
.WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
ON_CALL(*mock_dynamic_trigger_conditions_,
OnUpdate(mock_web_controller_.get(), _))
@@ -482,7 +505,9 @@ TEST_F(TriggerScriptCoordinatorTest, PerformTriggerScriptActionAccept) {
std::string serialized_response;
response.SerializeToString(&serialized_response);
- EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ EXPECT_CALL(
+ *mock_request_sender_,
+ OnSendRequest(GURL(kFakeServerUrl), _, _, RpcType::GET_TRIGGER_SCRIPTS))
.WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
ON_CALL(*mock_dynamic_trigger_conditions_,
OnUpdate(mock_web_controller_.get(), _))
@@ -506,7 +531,9 @@ TEST_F(TriggerScriptCoordinatorTest, CancelOnNavigateAway) {
std::string serialized_response;
response.SerializeToString(&serialized_response);
- EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ EXPECT_CALL(
+ *mock_request_sender_,
+ OnSendRequest(GURL(kFakeServerUrl), _, _, RpcType::GET_TRIGGER_SCRIPTS))
.WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
ON_CALL(*mock_dynamic_trigger_conditions_,
OnUpdate(mock_web_controller_.get(), _))
@@ -553,7 +580,9 @@ TEST_F(TriggerScriptCoordinatorTest, IgnoreNavigationEventsWhileNotStarted) {
std::string serialized_response;
response.SerializeToString(&serialized_response);
- EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ EXPECT_CALL(
+ *mock_request_sender_,
+ OnSendRequest(GURL(kFakeServerUrl), _, _, RpcType::GET_TRIGGER_SCRIPTS))
.WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
EXPECT_CALL(*mock_dynamic_trigger_conditions_,
OnUpdate(mock_web_controller_.get(), _))
@@ -575,7 +604,9 @@ TEST_F(TriggerScriptCoordinatorTest, IgnoreNavigationEventsWhileNotStarted) {
SimulateNavigateToUrl(GURL("https://example.different.com"));
SimulateNavigateToUrl(GURL("https://also-not-supported.com"));
- EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ EXPECT_CALL(
+ *mock_request_sender_,
+ OnSendRequest(GURL(kFakeServerUrl), _, _, RpcType::GET_TRIGGER_SCRIPTS))
.WillOnce(RunOnceCallback<2>(net::HTTP_OK, /* response = */ ""));
// However, when the tab becomes visible again, the trigger script is
// restarted and thus fails if the tab is still on an unsupported domain.
@@ -600,7 +631,9 @@ TEST_F(TriggerScriptCoordinatorTest, BottomSheetClosedWithSwipe) {
std::string serialized_response;
response.SerializeToString(&serialized_response);
- EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ EXPECT_CALL(
+ *mock_request_sender_,
+ OnSendRequest(GURL(kFakeServerUrl), _, _, RpcType::GET_TRIGGER_SCRIPTS))
.WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
ON_CALL(*mock_dynamic_trigger_conditions_,
OnUpdate(mock_web_controller_.get(), _))
@@ -639,7 +672,9 @@ TEST_F(TriggerScriptCoordinatorTest, TimeoutAfterInvisibleForTooLong) {
std::string serialized_response;
response.SerializeToString(&serialized_response);
- EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ EXPECT_CALL(
+ *mock_request_sender_,
+ OnSendRequest(GURL(kFakeServerUrl), _, _, RpcType::GET_TRIGGER_SCRIPTS))
.WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
// Note: expect 4 calls: 1 initial plus 3 until timeout.
@@ -679,7 +714,9 @@ TEST_F(TriggerScriptCoordinatorTest, TimeoutResetsAfterTriggerScriptShown) {
std::string serialized_response;
response.SerializeToString(&serialized_response);
- EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ EXPECT_CALL(
+ *mock_request_sender_,
+ OnSendRequest(GURL(kFakeServerUrl), _, _, RpcType::GET_TRIGGER_SCRIPTS))
.WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
EXPECT_CALL(*mock_dynamic_trigger_conditions_,
OnUpdate(mock_web_controller_.get(), _))
@@ -725,7 +762,9 @@ TEST_F(TriggerScriptCoordinatorTest, NoTimeoutByDefault) {
std::string serialized_response;
response.SerializeToString(&serialized_response);
- EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ EXPECT_CALL(
+ *mock_request_sender_,
+ OnSendRequest(GURL(kFakeServerUrl), _, _, RpcType::GET_TRIGGER_SCRIPTS))
.WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
EXPECT_CALL(*mock_dynamic_trigger_conditions_,
OnUpdate(mock_web_controller_.get(), _))
@@ -751,7 +790,9 @@ TEST_F(TriggerScriptCoordinatorTest, KeyboardEventTriggersOutOfScheduleCheck) {
std::string serialized_response;
response.SerializeToString(&serialized_response);
- EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ EXPECT_CALL(
+ *mock_request_sender_,
+ OnSendRequest(GURL(kFakeServerUrl), _, _, RpcType::GET_TRIGGER_SCRIPTS))
.WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
EXPECT_CALL(*mock_dynamic_trigger_conditions_,
OnUpdate(mock_web_controller_.get(), _))
@@ -801,7 +842,9 @@ TEST_F(TriggerScriptCoordinatorTest, UrlChangeOutOfScheduleCheckPathMatch) {
std::string serialized_response;
response.SerializeToString(&serialized_response);
- EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ EXPECT_CALL(
+ *mock_request_sender_,
+ OnSendRequest(GURL(kFakeServerUrl), _, _, RpcType::GET_TRIGGER_SCRIPTS))
.WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
EXPECT_CALL(*mock_dynamic_trigger_conditions_,
OnUpdate(mock_web_controller_.get(), _))
@@ -830,7 +873,9 @@ TEST_F(TriggerScriptCoordinatorTest, UrlChangeOutOfScheduleCheckDomainMatch) {
std::string serialized_response;
response.SerializeToString(&serialized_response);
- EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ EXPECT_CALL(
+ *mock_request_sender_,
+ OnSendRequest(GURL(kFakeServerUrl), _, _, RpcType::GET_TRIGGER_SCRIPTS))
.WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
EXPECT_CALL(*mock_dynamic_trigger_conditions_,
OnUpdate(mock_web_controller_.get(), _))
@@ -859,7 +904,9 @@ TEST_F(TriggerScriptCoordinatorTest,
std::string serialized_response;
response.SerializeToString(&serialized_response);
- EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ EXPECT_CALL(
+ *mock_request_sender_,
+ OnSendRequest(GURL(kFakeServerUrl), _, _, RpcType::GET_TRIGGER_SCRIPTS))
.WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
EXPECT_CALL(*mock_dynamic_trigger_conditions_,
OnUpdate(mock_web_controller_.get(), _))
@@ -887,7 +934,9 @@ TEST_F(TriggerScriptCoordinatorTest, OnTriggerScriptFailedToShow) {
std::string serialized_response;
response.SerializeToString(&serialized_response);
- EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ EXPECT_CALL(
+ *mock_request_sender_,
+ OnSendRequest(GURL(kFakeServerUrl), _, _, RpcType::GET_TRIGGER_SCRIPTS))
.WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
EXPECT_CALL(*mock_dynamic_trigger_conditions_,
OnUpdate(mock_web_controller_.get(), _))
@@ -913,7 +962,9 @@ TEST_F(TriggerScriptCoordinatorTest, OnProactiveHelpSettingDisabled) {
std::string serialized_response;
response.SerializeToString(&serialized_response);
- EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ EXPECT_CALL(
+ *mock_request_sender_,
+ OnSendRequest(GURL(kFakeServerUrl), _, _, RpcType::GET_TRIGGER_SCRIPTS))
.WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
EXPECT_CALL(*mock_dynamic_trigger_conditions_,
OnUpdate(mock_web_controller_.get(), _))
@@ -946,7 +997,9 @@ TEST_F(TriggerScriptCoordinatorTest, PauseAndResumeOnTabSwitch) {
std::string serialized_response;
response.SerializeToString(&serialized_response);
- EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ EXPECT_CALL(
+ *mock_request_sender_,
+ OnSendRequest(GURL(kFakeServerUrl), _, _, RpcType::GET_TRIGGER_SCRIPTS))
.WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
EXPECT_CALL(*mock_dynamic_trigger_conditions_,
OnUpdate(mock_web_controller_.get(), _))
@@ -968,7 +1021,9 @@ TEST_F(TriggerScriptCoordinatorTest, PauseAndResumeOnTabSwitch) {
// When a non-interactable tab becomes interactable again, the trigger scripts
// must be fetched again.
- EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ EXPECT_CALL(
+ *mock_request_sender_,
+ OnSendRequest(GURL(kFakeServerUrl), _, _, RpcType::GET_TRIGGER_SCRIPTS))
.WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
EXPECT_CALL(*mock_dynamic_trigger_conditions_,
OnUpdate(mock_web_controller_.get(), _))
@@ -987,7 +1042,9 @@ TEST_F(TriggerScriptCoordinatorTest, OnboardingShownAndAccepted) {
std::string serialized_response;
response.SerializeToString(&serialized_response);
- EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ EXPECT_CALL(
+ *mock_request_sender_,
+ OnSendRequest(GURL(kFakeServerUrl), _, _, RpcType::GET_TRIGGER_SCRIPTS))
.WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
EXPECT_CALL(*mock_dynamic_trigger_conditions_,
OnUpdate(mock_web_controller_.get(), _))
@@ -1028,7 +1085,9 @@ TEST_F(TriggerScriptCoordinatorTest,
std::string serialized_response;
response.SerializeToString(&serialized_response);
- EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ EXPECT_CALL(
+ *mock_request_sender_,
+ OnSendRequest(GURL(kFakeServerUrl), _, _, RpcType::GET_TRIGGER_SCRIPTS))
.WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
EXPECT_CALL(*mock_dynamic_trigger_conditions_,
OnUpdate(mock_web_controller_.get(), _))
@@ -1094,7 +1153,9 @@ TEST_F(TriggerScriptCoordinatorTest,
std::string serialized_response;
response.SerializeToString(&serialized_response);
- EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ EXPECT_CALL(
+ *mock_request_sender_,
+ OnSendRequest(GURL(kFakeServerUrl), _, _, RpcType::GET_TRIGGER_SCRIPTS))
.WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
EXPECT_CALL(*mock_dynamic_trigger_conditions_,
OnUpdate(mock_web_controller_.get(), _))
@@ -1135,7 +1196,9 @@ TEST_F(TriggerScriptCoordinatorTest, OnboardingNotShown) {
std::string serialized_response;
response.SerializeToString(&serialized_response);
- EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ EXPECT_CALL(
+ *mock_request_sender_,
+ OnSendRequest(GURL(kFakeServerUrl), _, _, RpcType::GET_TRIGGER_SCRIPTS))
.WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
EXPECT_CALL(*mock_dynamic_trigger_conditions_,
OnUpdate(mock_web_controller_.get(), _))
@@ -1173,7 +1236,9 @@ TEST_F(TriggerScriptCoordinatorTest, RecordUkmsForCurrentUrlIfPossible) {
std::string serialized_response;
response.SerializeToString(&serialized_response);
- EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ EXPECT_CALL(
+ *mock_request_sender_,
+ OnSendRequest(GURL(kFakeServerUrl), _, _, RpcType::GET_TRIGGER_SCRIPTS))
.WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
ON_CALL(*mock_dynamic_trigger_conditions_,
OnUpdate(mock_web_controller_.get(), _))
@@ -1213,7 +1278,9 @@ TEST_F(TriggerScriptCoordinatorTest, BackendCanOverrideScriptParameters) {
std::string serialized_response;
response.SerializeToString(&serialized_response);
- EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ EXPECT_CALL(
+ *mock_request_sender_,
+ OnSendRequest(GURL(kFakeServerUrl), _, _, RpcType::GET_TRIGGER_SCRIPTS))
.WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
coordinator_->Start(
@@ -1238,7 +1305,9 @@ TEST_F(TriggerScriptCoordinatorTest, UiTimeoutWhileShown) {
std::string serialized_response;
response.SerializeToString(&serialized_response);
- EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ EXPECT_CALL(
+ *mock_request_sender_,
+ OnSendRequest(GURL(kFakeServerUrl), _, _, RpcType::GET_TRIGGER_SCRIPTS))
.WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
ON_CALL(*mock_dynamic_trigger_conditions_,
@@ -1292,7 +1361,9 @@ TEST_F(TriggerScriptCoordinatorTest, UiTimeoutInterruptedByCancelPopup) {
std::string serialized_response;
response.SerializeToString(&serialized_response);
- EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ EXPECT_CALL(
+ *mock_request_sender_,
+ OnSendRequest(GURL(kFakeServerUrl), _, _, RpcType::GET_TRIGGER_SCRIPTS))
.WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
ON_CALL(*mock_dynamic_trigger_conditions_,
@@ -1331,7 +1402,9 @@ TEST_F(TriggerScriptCoordinatorTest, UiTimeoutInterruptedByOnboarding) {
std::string serialized_response;
response.SerializeToString(&serialized_response);
- EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ EXPECT_CALL(
+ *mock_request_sender_,
+ OnSendRequest(GURL(kFakeServerUrl), _, _, RpcType::GET_TRIGGER_SCRIPTS))
.WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
ON_CALL(*mock_dynamic_trigger_conditions_,
@@ -1357,7 +1430,9 @@ TEST_F(TriggerScriptCoordinatorTest, UiTimeoutInterruptedBySkipSession) {
std::string serialized_response;
response.SerializeToString(&serialized_response);
- EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ EXPECT_CALL(
+ *mock_request_sender_,
+ OnSendRequest(GURL(kFakeServerUrl), _, _, RpcType::GET_TRIGGER_SCRIPTS))
.WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
ON_CALL(*mock_dynamic_trigger_conditions_,
@@ -1389,7 +1464,9 @@ TEST_F(TriggerScriptCoordinatorTest, UiTimeoutInterruptedByNotNow) {
std::string serialized_response;
response.SerializeToString(&serialized_response);
- EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ EXPECT_CALL(
+ *mock_request_sender_,
+ OnSendRequest(GURL(kFakeServerUrl), _, _, RpcType::GET_TRIGGER_SCRIPTS))
.WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
ON_CALL(*mock_dynamic_trigger_conditions_,
@@ -1418,7 +1495,9 @@ TEST_F(TriggerScriptCoordinatorTest, UiTimeoutInterruptedByNotNow) {
}
TEST_F(TriggerScriptCoordinatorTest, StoppingTwiceDoesNotCrash) {
- EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ EXPECT_CALL(
+ *mock_request_sender_,
+ OnSendRequest(GURL(kFakeServerUrl), _, _, RpcType::GET_TRIGGER_SCRIPTS))
.WillOnce(RunOnceCallback<2>(net::HTTP_FORBIDDEN, ""));
EXPECT_CALL(*mock_ui_delegate_, Detach).Times(2);
EXPECT_CALL(*mock_ui_delegate_, HideTriggerScript).Times(0);
@@ -1444,7 +1523,9 @@ TEST_F(TriggerScriptCoordinatorTest, RecordTriggerConditionEvaluationTime) {
std::string serialized_response;
response.SerializeToString(&serialized_response);
- EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ EXPECT_CALL(
+ *mock_request_sender_,
+ OnSendRequest(GURL(kFakeServerUrl), _, _, RpcType::GET_TRIGGER_SCRIPTS))
.WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
EXPECT_CALL(*mock_dynamic_trigger_conditions_, OnUpdate)
@@ -1479,7 +1560,9 @@ TEST_F(TriggerScriptCoordinatorTest, RecordIfPrimaryPageFailed) {
response.add_trigger_scripts();
std::string serialized_response;
response.SerializeToString(&serialized_response);
- EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ EXPECT_CALL(
+ *mock_request_sender_,
+ OnSendRequest(GURL(kFakeServerUrl), _, _, RpcType::GET_TRIGGER_SCRIPTS))
.WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
coordinator_->Start(GURL(kFakeDeepLink), std::make_unique<TriggerContext>(),
@@ -1524,7 +1607,9 @@ TEST_F(TriggerScriptCoordinatorPrerenderTest, DoNotRecordIfPrerenderingFailed) {
response.add_trigger_scripts();
std::string serialized_response;
response.SerializeToString(&serialized_response);
- EXPECT_CALL(*mock_request_sender_, OnSendRequest(GURL(kFakeServerUrl), _, _))
+ EXPECT_CALL(
+ *mock_request_sender_,
+ OnSendRequest(GURL(kFakeServerUrl), _, _, RpcType::GET_TRIGGER_SCRIPTS))
.WillOnce(RunOnceCallback<2>(net::HTTP_OK, serialized_response));
EXPECT_CALL(mock_callback_, Run).Times(0);
diff --git a/chromium/components/autofill_assistant/browser/ui_controller.cc b/chromium/components/autofill_assistant/browser/ui_controller.cc
new file mode 100644
index 00000000000..b1f59059cce
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/ui_controller.cc
@@ -0,0 +1,1137 @@
+// Copyright 2022 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.
+
+#include "components/autofill_assistant/browser/ui_controller.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/callback_helpers.h"
+#include "base/no_destructor.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "components/autofill_assistant/browser/actions/collect_user_data_action.h"
+#include "components/autofill_assistant/browser/controller_observer.h"
+#include "components/autofill_assistant/browser/display_strings_util.h"
+#include "components/autofill_assistant/browser/features.h"
+#include "components/autofill_assistant/browser/protocol_utils.h"
+#include "components/autofill_assistant/browser/service/service_impl.h"
+#include "components/autofill_assistant/browser/trigger_context.h"
+#include "components/autofill_assistant/browser/user_data.h"
+#include "components/autofill_assistant/browser/user_data_util.h"
+#include "components/autofill_assistant/browser/view_layout.pb.h"
+#include "components/google/core/common/google_util.h"
+#include "components/password_manager/core/browser/password_manager_client.h"
+#include "components/strings/grit/components_strings.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "url/gurl.h"
+
+namespace autofill_assistant {
+namespace {
+
+// Experiment for non-sticky TTSButtonState. The TTSButtonState is reset to
+// DEFAULT whenever tts/status message changes even when the button was
+// DISABLED by the user tap.
+const char kNonStickyTtsButtonStateExperiment[] = "4624822";
+
+bool ShouldShowFeedbackChipForReason(Metrics::DropOutReason reason) {
+ switch (reason) {
+ case Metrics::DropOutReason::GET_SCRIPTS_FAILED:
+ case Metrics::DropOutReason::GET_SCRIPTS_UNPARSABLE:
+ case Metrics::DropOutReason::SCRIPT_FAILED:
+ case Metrics::DropOutReason::MULTIPLE_AUTOSTARTABLE_SCRIPTS:
+ case Metrics::DropOutReason::NO_INITIAL_SCRIPTS:
+ case Metrics::DropOutReason::NAVIGATION:
+ case Metrics::DropOutReason::NAVIGATION_WHILE_RUNNING:
+ case Metrics::DropOutReason::DOMAIN_CHANGE_DURING_BROWSE_MODE:
+ return true;
+ // These are possible error reasons for which we don't want to show the
+ // feedback chip.
+ case Metrics::DropOutReason::NO_SCRIPTS:
+ case Metrics::DropOutReason::TAB_CHANGED:
+ // These are currently not used as error reasons by the Controller and we
+ // default to false.
+ case Metrics::DropOutReason::AA_START:
+ case Metrics::DropOutReason::AUTOSTART_TIMEOUT:
+ case Metrics::DropOutReason::CUSTOM_TAB_CLOSED:
+ case Metrics::DropOutReason::DECLINED:
+ case Metrics::DropOutReason::SHEET_CLOSED:
+ case Metrics::DropOutReason::OVERLAY_STOP:
+ case Metrics::DropOutReason::PR_FAILED:
+ case Metrics::DropOutReason::CONTENT_DESTROYED:
+ case Metrics::DropOutReason::RENDER_PROCESS_GONE:
+ case Metrics::DropOutReason::INTERSTITIAL_PAGE:
+ case Metrics::DropOutReason::SCRIPT_SHUTDOWN:
+ case Metrics::DropOutReason::SAFETY_NET_TERMINATE:
+ case Metrics::DropOutReason::TAB_DETACHED:
+ case Metrics::DropOutReason::DFM_INSTALL_FAILED:
+ case Metrics::DropOutReason::BACK_BUTTON_CLICKED:
+ case Metrics::DropOutReason::ONBOARDING_BACK_BUTTON_CLICKED:
+ case Metrics::DropOutReason::UI_CLOSED_UNEXPECTEDLY:
+ case Metrics::DropOutReason::ONBOARDING_NAVIGATION:
+ case Metrics::DropOutReason::ONBOARDING_DIALOG_DISMISSED:
+ return false;
+ }
+}
+
+} // namespace
+
+UiController::UiController(
+ Client* client,
+ ExecutionDelegate* execution_delegate,
+ std::unique_ptr<AutofillAssistantTtsController> tts_controller)
+ : client_(client),
+ execution_delegate_(execution_delegate),
+ tts_controller_(std::move(tts_controller)) {
+ tts_controller_->SetTtsEventDelegate(weak_ptr_factory_.GetWeakPtr());
+}
+
+UiController::~UiController() {
+ if (execution_delegate_) {
+ GetUserModel()->RemoveObserver(this);
+ execution_delegate_->RemoveObserver(this);
+ }
+}
+
+void UiController::StartListening() {
+ GetUserModel()->AddObserver(this);
+ execution_delegate_->AddObserver(this);
+}
+
+UiController::DetailsHolder::DetailsHolder(
+ std::unique_ptr<Details> details,
+ std::unique_ptr<base::OneShotTimer> timer)
+ : details_(std::move(details)), timer_(std::move(timer)) {}
+
+UiController::DetailsHolder::~DetailsHolder() = default;
+UiController::DetailsHolder::DetailsHolder(DetailsHolder&& other) = default;
+UiController::DetailsHolder& UiController::DetailsHolder::operator=(
+ DetailsHolder&& other) = default;
+
+const Details& UiController::DetailsHolder::GetDetails() const {
+ return *details_;
+}
+
+bool UiController::DetailsHolder::CurrentlyVisible() const {
+ // If there is a timer associated to these details, then they should be shown
+ // only once the timer has triggered.
+ return !timer_;
+}
+
+void UiController::DetailsHolder::Enable() {
+ timer_.reset();
+}
+
+std::string UiController::GetDisplayStringsLocale() {
+ if (execution_delegate_->GetClientSettings().display_strings_locale.empty()) {
+ // Fallback locale
+ return client_->GetLocale();
+ }
+ return execution_delegate_->GetClientSettings().display_strings_locale;
+}
+
+void UiController::SetStatusMessage(const std::string& message) {
+ status_message_ = message;
+ for (UiControllerObserver& observer : observers_) {
+ observer.OnStatusMessageChanged(message);
+ }
+
+ // Override tts_message every time status_message changes.
+ SetTtsMessage(message);
+}
+
+std::string UiController::GetStatusMessage() const {
+ return status_message_;
+}
+
+void UiController::SetBubbleMessage(const std::string& message) {
+ bubble_message_ = message;
+ for (UiControllerObserver& observer : observers_) {
+ observer.OnBubbleMessageChanged(message);
+ }
+}
+
+std::string UiController::GetBubbleMessage() const {
+ return bubble_message_;
+}
+
+void UiController::SetTtsMessage(const std::string& message) {
+ tts_message_ = message;
+
+ // Stop any ongoing TTS and reset button state.
+ if (tts_button_state_ == TtsButtonState::PLAYING) {
+ // Will not cause any TTS event.
+ tts_controller_->Stop();
+ SetTtsButtonState(TtsButtonState::DEFAULT);
+ }
+
+ // Re-enable TTS button if "Non sticky Tts Button State" experiment is
+ // enabled.
+ if (tts_button_state_ == TtsButtonState::DISABLED &&
+ execution_delegate_->GetTriggerContext() != nullptr &&
+ execution_delegate_->GetTriggerContext()->HasExperimentId(
+ kNonStickyTtsButtonStateExperiment)) {
+ SetTtsButtonState(TtsButtonState::DEFAULT);
+ }
+}
+
+std::string UiController::GetTtsMessage() const {
+ return tts_message_;
+}
+
+void UiController::MaybePlayTtsMessage() {
+ if (!tts_enabled_) {
+ return;
+ }
+
+ // Will fire a TTS_START event.
+ tts_controller_->Speak(tts_message_, GetDisplayStringsLocale());
+}
+
+void UiController::SetDetails(std::unique_ptr<Details> details,
+ base::TimeDelta delay) {
+ details_.clear();
+
+ // There is nothing to append: notify that we cleared the details and return.
+ if (!details) {
+ NotifyDetailsChanged();
+ return;
+ }
+
+ // If there is a delay, notify now that details have been cleared. If there is
+ // no delay, AppendDetails will take care of the notifying the observers after
+ // appending the details.
+ if (!delay.is_zero()) {
+ NotifyDetailsChanged();
+ }
+
+ AppendDetails(std::move(details), delay);
+}
+
+void UiController::AppendDetails(std::unique_ptr<Details> details,
+ base::TimeDelta delay) {
+ if (!details) {
+ return;
+ }
+
+ if (delay.is_zero()) {
+ details_.push_back(DetailsHolder(std::move(details), /* timer= */ nullptr));
+ NotifyDetailsChanged();
+ return;
+ }
+
+ // Delay the addition of the new details.
+ size_t details_index = details_.size();
+ auto timer = std::make_unique<base::OneShotTimer>();
+ timer->Start(FROM_HERE, delay,
+ base::BindOnce(&UiController::MakeDetailsVisible,
+ weak_ptr_factory_.GetWeakPtr(), details_index));
+ details_.push_back(DetailsHolder(std::move(details), std::move(timer)));
+}
+
+void UiController::MakeDetailsVisible(size_t details_index) {
+ if (details_index < details_.size()) {
+ details_[details_index].Enable();
+ NotifyDetailsChanged();
+ }
+}
+
+void UiController::NotifyDetailsChanged() {
+ std::vector<Details> details = GetDetails();
+ for (UiControllerObserver& observer : observers_) {
+ observer.OnDetailsChanged(details);
+ }
+}
+
+std::vector<Details> UiController::GetDetails() const {
+ std::vector<Details> details;
+ for (const auto& holder : details_) {
+ if (holder.CurrentlyVisible()) {
+ details.push_back(holder.GetDetails());
+ }
+ }
+ return details;
+}
+
+int UiController::GetProgressActiveStep() const {
+ return progress_active_step_;
+}
+
+ShowProgressBarProto::StepProgressBarConfiguration
+UiController::GetStepProgressBarConfiguration() const {
+ return step_progress_bar_configuration_;
+}
+
+void UiController::SetInfoBox(const InfoBox& info_box) {
+ if (!info_box_) {
+ info_box_ = std::make_unique<InfoBox>();
+ }
+ *info_box_ = info_box;
+ for (UiControllerObserver& observer : observers_) {
+ observer.OnInfoBoxChanged(info_box_.get());
+ }
+}
+
+void UiController::ClearInfoBox() {
+ info_box_.reset();
+ for (UiControllerObserver& observer : observers_) {
+ observer.OnInfoBoxChanged(nullptr);
+ }
+}
+
+const InfoBox* UiController::GetInfoBox() const {
+ return info_box_.get();
+}
+
+bool UiController::SetProgressActiveStepIdentifier(
+ const std::string& active_step_identifier) {
+ const auto it = base::ranges::find_if(
+ step_progress_bar_configuration_.annotated_step_icons(),
+ [&](const ShowProgressBarProto::StepProgressBarIcon& icon) {
+ return icon.identifier() == active_step_identifier;
+ });
+ if (it == step_progress_bar_configuration_.annotated_step_icons().cend()) {
+ return false;
+ }
+
+ SetProgressActiveStep(std::distance(
+ step_progress_bar_configuration_.annotated_step_icons().cbegin(), it));
+ return true;
+}
+
+void UiController::SetProgressActiveStep(int active_step) {
+ // Default step progress bar has 2 steps.
+ int max_step = std::max(
+ 2, step_progress_bar_configuration_.annotated_step_icons().size());
+
+ int new_active_step = active_step;
+ if (active_step < 0 || active_step > max_step) {
+ new_active_step = max_step;
+ }
+
+ // Step can only increase.
+ if (progress_active_step_ >= new_active_step) {
+ return;
+ }
+
+ progress_active_step_ = new_active_step;
+ for (UiControllerObserver& observer : observers_) {
+ observer.OnProgressActiveStepChanged(new_active_step);
+ }
+}
+
+void UiController::SetProgressVisible(bool visible) {
+ if (progress_visible_ == visible)
+ return;
+
+ progress_visible_ = visible;
+ for (UiControllerObserver& observer : observers_) {
+ observer.OnProgressVisibilityChanged(visible);
+ }
+}
+
+bool UiController::GetProgressVisible() const {
+ return progress_visible_;
+}
+
+bool UiController::GetTtsButtonVisible() const {
+ return tts_enabled_;
+}
+
+TtsButtonState UiController::GetTtsButtonState() const {
+ return tts_button_state_;
+}
+
+void UiController::SetStepProgressBarConfiguration(
+ const ShowProgressBarProto::StepProgressBarConfiguration& configuration) {
+ step_progress_bar_configuration_ = configuration;
+ if (!configuration.annotated_step_icons().empty() &&
+ configuration.annotated_step_icons().size() < progress_active_step_) {
+ progress_active_step_ = configuration.annotated_step_icons().size();
+ }
+ for (UiControllerObserver& observer : observers_) {
+ observer.OnStepProgressBarConfigurationChanged(configuration);
+ observer.OnProgressActiveStepChanged(progress_active_step_);
+ observer.OnProgressBarErrorStateChanged(progress_bar_error_state_);
+ }
+}
+
+void UiController::SetProgressBarErrorState(bool error) {
+ if (progress_bar_error_state_ == error) {
+ return;
+ }
+
+ progress_bar_error_state_ = error;
+ for (UiControllerObserver& observer : observers_) {
+ observer.OnProgressBarErrorStateChanged(error);
+ }
+}
+
+bool UiController::GetProgressBarErrorState() const {
+ return progress_bar_error_state_;
+}
+
+const std::vector<UserAction>& UiController::GetUserActions() const {
+ static const base::NoDestructor<std::vector<UserAction>> no_user_actions_;
+ return user_actions_ ? *user_actions_ : *no_user_actions_;
+}
+
+void UiController::SetUserActions(
+ std::unique_ptr<std::vector<UserAction>> user_actions) {
+ if (user_actions) {
+ SetDefaultChipType(user_actions.get());
+ }
+ user_actions_ = std::move(user_actions);
+ SetVisibilityAndUpdateUserActions();
+}
+
+bool UiController::ShouldChipsBeVisible() {
+ return !(is_keyboard_showing_ && is_focus_on_bottom_sheet_text_input_);
+}
+
+bool UiController::ShouldUpdateChipVisibility() {
+ return are_chips_visible_ != ShouldChipsBeVisible();
+}
+
+void UiController::SetVisibilityAndUpdateUserActions() {
+ // All non-cancel chips should be hidden while the keyboard is showing to fill
+ // an input text field in the bottom sheet.
+ are_chips_visible_ = ShouldChipsBeVisible();
+ if (user_actions_) {
+ for (UserAction& user_action : *user_actions_) {
+ if (user_action.chip().type != CANCEL_ACTION) {
+ user_action.chip().visible = are_chips_visible_;
+ }
+ }
+ }
+
+ for (UiControllerObserver& observer : observers_) {
+ observer.OnUserActionsChanged(GetUserActions());
+ }
+}
+
+void UiController::SetGenericUi(
+ std::unique_ptr<GenericUserInterfaceProto> generic_ui,
+ base::OnceCallback<void(const ClientStatus&)> end_action_callback,
+ base::OnceCallback<void(const ClientStatus&)>
+ view_inflation_finished_callback) {
+ generic_user_interface_ = std::move(generic_ui);
+ basic_interactions_.SetEndActionCallback(std::move(end_action_callback));
+ basic_interactions_.SetViewInflationFinishedCallback(
+ std::move(view_inflation_finished_callback));
+ for (UiControllerObserver& observer : observers_) {
+ observer.OnGenericUserInterfaceChanged(generic_user_interface_.get());
+ }
+}
+
+void UiController::SetPersistentGenericUi(
+ std::unique_ptr<GenericUserInterfaceProto> generic_ui,
+ base::OnceCallback<void(const ClientStatus&)>
+ view_inflation_finished_callback) {
+ persistent_generic_user_interface_ = std::move(generic_ui);
+ basic_interactions_.SetPersistentViewInflationFinishedCallback(
+ std::move(view_inflation_finished_callback));
+ for (UiControllerObserver& observer : observers_) {
+ observer.OnPersistentGenericUserInterfaceChanged(
+ persistent_generic_user_interface_.get());
+ }
+}
+
+void UiController::ClearGenericUi() {
+ generic_user_interface_.reset();
+ basic_interactions_.ClearCallbacks();
+ for (UiControllerObserver& observer : observers_) {
+ observer.OnGenericUserInterfaceChanged(nullptr);
+ }
+}
+
+void UiController::ClearPersistentGenericUi() {
+ persistent_generic_user_interface_.reset();
+ basic_interactions_.ClearPersistentUiCallbacks();
+ for (UiControllerObserver& observer : observers_) {
+ observer.OnPersistentGenericUserInterfaceChanged(nullptr);
+ }
+}
+
+void UiController::SetShowFeedbackChip(bool show_feedback_chip) {
+ show_feedback_chip_ = show_feedback_chip;
+}
+
+void UiController::SetExpandSheetForPromptAction(bool expand) {
+ expand_sheet_for_prompt_action_ = expand;
+}
+
+bool UiController::PerformUserAction(int index) {
+ if (!user_actions_ || index < 0 ||
+ static_cast<size_t>(index) >= user_actions_->size()) {
+ NOTREACHED() << "Invalid user_action index: " << index;
+ return false;
+ }
+
+ if (!(*user_actions_)[index].enabled()) {
+ NOTREACHED() << "Action at index " << index << " is disabled.";
+ return false;
+ }
+
+ UserAction user_action = std::move((*user_actions_)[index]);
+ SetUserActions(nullptr);
+ user_action.RunCallback();
+ event_handler_.DispatchEvent(
+ {EventProto::kOnUserActionCalled, user_action.identifier()});
+ return true;
+}
+
+void UiController::SetPeekMode(ConfigureBottomSheetProto::PeekMode peek_mode) {
+ if (peek_mode == peek_mode_)
+ return;
+
+ peek_mode_ = peek_mode;
+ for (UiControllerObserver& observer : observers_) {
+ observer.OnPeekModeChanged(peek_mode);
+ }
+}
+
+void UiController::ExpandBottomSheet() {
+ for (UiControllerObserver& observer : observers_) {
+ // TODO(crbug/806868): The interface here and in some of the other On*
+ // events should be coming from the UI layer, not the controller. Or at
+ // least be renamed to something like On*Requested.
+ observer.OnExpandBottomSheet();
+ }
+}
+
+void UiController::CollapseBottomSheet() {
+ for (UiControllerObserver& observer : observers_) {
+ // TODO(crbug/806868): The interface here and in some of the other On*
+ // events should be coming from the UI layer, not the controller. Or at
+ // least be renamed to something like On*Requested.
+ observer.OnCollapseBottomSheet();
+ }
+}
+
+const FormProto* UiController::GetForm() const {
+ return form_.get();
+}
+
+const FormProto::Result* UiController::GetFormResult() const {
+ return form_result_.get();
+}
+
+bool UiController::SetForm(
+ std::unique_ptr<FormProto> form,
+ base::RepeatingCallback<void(const FormProto::Result*)> changed_callback,
+ base::OnceCallback<void(const ClientStatus&)> cancel_callback) {
+ form_.reset();
+ form_result_.reset();
+ form_changed_callback_ = base::DoNothing();
+ form_cancel_callback_ = base::DoNothing();
+
+ if (!form) {
+ for (UiControllerObserver& observer : observers_) {
+ observer.OnFormChanged(nullptr, nullptr);
+ }
+ return true;
+ }
+
+ // Initialize form result. This will return false if the form is invalid or
+ // contains unsupported inputs.
+ auto form_result = std::make_unique<FormProto::Result>();
+ for (FormInputProto& input : *form->mutable_inputs()) {
+ FormInputProto::Result* result = form_result->add_input_results();
+ switch (input.input_type_case()) {
+ case FormInputProto::InputTypeCase::kCounter:
+ // Add the initial value of each counter into the form result.
+ for (const CounterInputProto::Counter& counter :
+ input.counter().counters()) {
+ result->mutable_counter()->add_values(counter.initial_value());
+ }
+ break;
+ case FormInputProto::InputTypeCase::kSelection: {
+ // Add the initial selected state of each choice into the form result.
+ bool has_selected = false;
+ for (const SelectionInputProto::Choice& choice :
+ input.selection().choices()) {
+ if (choice.selected()) {
+ if (has_selected && !input.selection().allow_multiple()) {
+ // Multiple choices are initially selected even though it is not
+ // allowed by the input.
+ return false;
+ }
+ has_selected = true;
+ }
+ result->mutable_selection()->add_selected(choice.selected());
+ }
+ break;
+ }
+ case FormInputProto::InputTypeCase::INPUT_TYPE_NOT_SET:
+ VLOG(1) << "Encountered input with INPUT_TYPE_NOT_SET";
+ return false;
+ // Intentionally no default case to make compilation fail if a new
+ // value was added to the enum but not to this list.
+ }
+ }
+
+ // Form is valid.
+ form_ = std::move(form);
+ form_result_ = std::move(form_result);
+ form_changed_callback_ = changed_callback;
+ form_cancel_callback_ = std::move(cancel_callback);
+
+ // Call the callback with initial result.
+ form_changed_callback_.Run(form_result_.get());
+
+ for (UiControllerObserver& observer : observers_) {
+ observer.OnFormChanged(form_.get(), form_result_.get());
+ }
+ return true;
+}
+
+void UiController::SetCounterValue(int input_index,
+ int counter_index,
+ int value) {
+ if (!form_result_ || input_index < 0 ||
+ input_index >= form_result_->input_results_size()) {
+ NOTREACHED() << "Invalid input index: " << input_index;
+ return;
+ }
+
+ FormInputProto::Result* input_result =
+ form_result_->mutable_input_results(input_index);
+ if (!input_result->has_counter() || counter_index < 0 ||
+ counter_index >= input_result->counter().values_size()) {
+ NOTREACHED() << "Invalid counter index: " << counter_index;
+ return;
+ }
+
+ input_result->mutable_counter()->set_values(counter_index, value);
+ form_changed_callback_.Run(form_result_.get());
+}
+
+void UiController::SetChoiceSelected(int input_index,
+ int choice_index,
+ bool selected) {
+ if (!form_result_ || input_index < 0 ||
+ input_index >= form_result_->input_results_size()) {
+ NOTREACHED() << "Invalid input index: " << input_index;
+ return;
+ }
+
+ FormInputProto::Result* input_result =
+ form_result_->mutable_input_results(input_index);
+ if (!input_result->has_selection() || choice_index < 0 ||
+ choice_index >= input_result->selection().selected_size()) {
+ NOTREACHED() << "Invalid choice index: " << choice_index;
+ return;
+ }
+
+ input_result->mutable_selection()->set_selected(choice_index, selected);
+ form_changed_callback_.Run(form_result_.get());
+}
+
+UserModel* UiController::GetUserModel() {
+ return execution_delegate_->GetUserModel();
+}
+
+EventHandler* UiController::GetEventHandler() {
+ return &event_handler_;
+}
+
+bool UiController::ShouldPromptActionExpandSheet() const {
+ return expand_sheet_for_prompt_action_;
+}
+
+BasicInteractions* UiController::GetBasicInteractions() {
+ return &basic_interactions_;
+}
+
+const GenericUserInterfaceProto* UiController::GetGenericUiProto() const {
+ return generic_user_interface_.get();
+}
+
+const GenericUserInterfaceProto* UiController::GetPersistentGenericUiProto()
+ const {
+ return persistent_generic_user_interface_.get();
+}
+
+void UiController::AddObserver(UiControllerObserver* observer) {
+ observers_.AddObserver(observer);
+}
+
+void UiController::RemoveObserver(const UiControllerObserver* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+void UiController::DispatchEvent(const EventHandler::EventKey& key) {
+ event_handler_.DispatchEvent(key);
+}
+
+ConfigureBottomSheetProto::PeekMode UiController::GetPeekMode() {
+ return peek_mode_;
+}
+
+BottomSheetState UiController::GetBottomSheetState() {
+ return bottom_sheet_state_;
+}
+
+void UiController::SetBottomSheetState(BottomSheetState state) {
+ bottom_sheet_state_ = state;
+}
+base::Value UiController::GetDebugContext() const {
+ base::Value dict(base::Value::Type::DICTIONARY);
+
+ dict.SetKey("status", base::Value(status_message_));
+
+ std::vector<base::Value> details_list;
+ for (const auto& holder : details_) {
+ details_list.push_back(holder.GetDetails().GetDebugContext());
+ }
+ dict.SetKey("details", base::Value(details_list));
+
+ return dict;
+}
+
+const CollectUserDataOptions* UiController::GetCollectUserDataOptions() const {
+ return collect_user_data_options_;
+}
+
+UserData* UiController::GetUserData() {
+ return execution_delegate_->GetUserData();
+}
+
+void UiController::OnCollectUserDataContinueButtonClicked() {
+ if (!collect_user_data_options_)
+ return;
+
+ auto callback = std::move(collect_user_data_options_->confirm_callback);
+
+ SetCollectUserDataOptions(nullptr);
+ std::move(callback).Run(GetUserData(), GetUserModel());
+}
+
+void UiController::OnCollectUserDataAdditionalActionTriggered(int index) {
+ if (!collect_user_data_options_)
+ return;
+
+ auto callback =
+ std::move(collect_user_data_options_->additional_actions_callback);
+ SetCollectUserDataOptions(nullptr);
+ std::move(callback).Run(index, GetUserData(), GetUserModel());
+}
+
+void UiController::OnTextLinkClicked(int link) {
+ auto callback = std::move(collect_user_data_options_->terms_link_callback);
+ SetCollectUserDataOptions(nullptr);
+ std::move(callback).Run(link, GetUserData(), GetUserModel());
+}
+
+void UiController::OnFormActionLinkClicked(int link) {
+ if (form_cancel_callback_ && form_result_ != nullptr) {
+ form_result_->set_link(link);
+ form_changed_callback_.Run(form_result_.get());
+ std::move(form_cancel_callback_).Run(ClientStatus(ACTION_APPLIED));
+ }
+}
+
+void UiController::OnTtsButtonClicked() {
+ switch (tts_button_state_) {
+ case TtsButtonState::DEFAULT:
+ // Will fire a TTS_START event.
+ tts_controller_->Speak(tts_message_, GetDisplayStringsLocale());
+ Metrics::RecordTtsButtonAction(Metrics::TtsButtonAction::PLAY_TTS);
+ break;
+ case TtsButtonState::PLAYING:
+ // Will not cause any TTS event.
+ tts_controller_->Stop();
+ SetTtsButtonState(TtsButtonState::DISABLED);
+ Metrics::RecordTtsButtonAction(Metrics::TtsButtonAction::DISABLE_BUTTON);
+ break;
+ case TtsButtonState::DISABLED:
+ SetTtsButtonState(TtsButtonState::DEFAULT);
+ // Will fire a TTS_START event.
+ tts_controller_->Speak(tts_message_, GetDisplayStringsLocale());
+ Metrics::RecordTtsButtonAction(
+ Metrics::TtsButtonAction::ENABLE_BUTTON_AND_PLAY_TTS);
+ break;
+ }
+}
+
+void UiController::OnTtsEvent(
+ AutofillAssistantTtsController::TtsEventType event) {
+ switch (event) {
+ case AutofillAssistantTtsController::TTS_START:
+ SetTtsButtonState(TtsButtonState::PLAYING);
+ break;
+ case AutofillAssistantTtsController::TTS_END:
+ case AutofillAssistantTtsController::TTS_ERROR:
+ SetTtsButtonState(TtsButtonState::DEFAULT);
+ break;
+ }
+}
+
+void UiController::SetTtsButtonState(TtsButtonState state) {
+ tts_button_state_ = state;
+ for (UiControllerObserver& observer : observers_) {
+ observer.OnTtsButtonStateChanged(tts_button_state_);
+ }
+}
+
+void UiController::OnSpokenFeedbackAccessibilityServiceChanged(bool enabled) {
+ if (!enabled) {
+ // Nothing to do when the a11y service is disabled.
+ return;
+ }
+
+ if (!tts_enabled_) {
+ return;
+ }
+ // Disable TTS and hide TTS button.
+ tts_enabled_ = false;
+ for (UiControllerObserver& observer : observers_) {
+ observer.OnTtsButtonVisibilityChanged(/* visible= */ false);
+ }
+ // Stop any ongoing TTS and reset button state.
+ if (tts_button_state_ == TtsButtonState::PLAYING) {
+ // Will not cause any TTS event.
+ tts_controller_->Stop();
+ SetTtsButtonState(TtsButtonState::DEFAULT);
+ }
+}
+
+void UiController::SetAdditionalValue(const std::string& client_memory_key,
+ const ValueProto& value) {
+ if (!GetUserData()->HasAdditionalValue(client_memory_key)) {
+ NOTREACHED() << client_memory_key << " not found";
+ return;
+ }
+ GetUserData()->SetAdditionalValue(client_memory_key, value);
+
+ execution_delegate_->NotifyUserDataChange(
+ UserData::FieldChange::ADDITIONAL_VALUES);
+}
+
+void UiController::HandleShippingAddressChange(
+ std::unique_ptr<autofill::AutofillProfile> address,
+ UserDataEventType event_type) {
+ if (collect_user_data_options_ == nullptr) {
+ return;
+ }
+ if (collect_user_data_options_->use_gms_core_edit_dialogs) {
+ ReloadUserData(UserDataEventField::SHIPPING_EVENT, event_type);
+ return;
+ }
+
+ collect_user_data_options_->selected_user_data_changed_callback.Run(
+ SHIPPING_EVENT, event_type);
+ DCHECK(!collect_user_data_options_->shipping_address_name.empty());
+ SetProfile(collect_user_data_options_->shipping_address_name,
+ UserData::FieldChange::SHIPPING_ADDRESS, std::move(address));
+}
+
+void UiController::HandleContactInfoChange(
+ std::unique_ptr<autofill::AutofillProfile> profile,
+ UserDataEventType event_type) {
+ if (collect_user_data_options_ == nullptr) {
+ return;
+ }
+ if (collect_user_data_options_->use_gms_core_edit_dialogs) {
+ ReloadUserData(UserDataEventField::CONTACT_EVENT, event_type);
+ return;
+ }
+
+ collect_user_data_options_->selected_user_data_changed_callback.Run(
+ CONTACT_EVENT, event_type);
+ DCHECK(!collect_user_data_options_->contact_details_name.empty());
+ SetProfile(collect_user_data_options_->contact_details_name,
+ UserData::FieldChange::CONTACT_PROFILE, std::move(profile));
+}
+
+void UiController::HandlePhoneNumberChange(
+ std::unique_ptr<autofill::AutofillProfile> profile,
+ UserDataEventType event_type) {
+ if (collect_user_data_options_ == nullptr) {
+ return;
+ }
+ if (collect_user_data_options_->use_gms_core_edit_dialogs) {
+ ReloadUserData(UserDataEventField::CONTACT_EVENT, event_type);
+ return;
+ }
+
+ // We don't notify the UserDataEvent in this case since we currently don't log
+ // metrics for the phone number.
+
+ GetUserData()->SetSelectedPhoneNumber(std::move(profile));
+ execution_delegate_->NotifyUserDataChange(
+ UserData::FieldChange::PHONE_NUMBER);
+}
+
+void UiController::HandleCreditCardChange(
+ std::unique_ptr<autofill::CreditCard> card,
+ std::unique_ptr<autofill::AutofillProfile> billing_profile,
+ UserDataEventType event_type) {
+ if (collect_user_data_options_ == nullptr) {
+ return;
+ }
+ if (collect_user_data_options_->use_gms_core_edit_dialogs) {
+ ReloadUserData(UserDataEventField::CREDIT_CARD_EVENT, event_type);
+ return;
+ }
+
+ collect_user_data_options_->selected_user_data_changed_callback.Run(
+ CREDIT_CARD_EVENT, event_type);
+ DCHECK(!collect_user_data_options_->billing_address_name.empty());
+ SetProfile(collect_user_data_options_->billing_address_name,
+ UserData::FieldChange::BILLING_ADDRESS,
+ std::move(billing_profile));
+ GetUserModel()->SetSelectedCreditCard(std::move(card), GetUserData());
+ execution_delegate_->NotifyUserDataChange(UserData::FieldChange::CARD);
+}
+
+void UiController::SetProfile(
+ const std::string& key,
+ UserData::FieldChange field_change,
+ std::unique_ptr<autofill::AutofillProfile> profile) {
+ GetUserModel()->SetSelectedAutofillProfile(key, std::move(profile),
+ GetUserData());
+
+ execution_delegate_->NotifyUserDataChange(field_change);
+}
+
+void UiController::ReloadUserData(UserDataEventField event_field,
+ UserDataEventType event_type) {
+ if (collect_user_data_options_ == nullptr) {
+ return;
+ }
+
+ collect_user_data_options_->selected_user_data_changed_callback.Run(
+ event_field, event_type);
+
+ auto callback = std::move(collect_user_data_options_->reload_data_callback);
+ std::move(callback).Run(GetUserData());
+}
+
+void UiController::SetTermsAndConditions(
+ TermsAndConditionsState terms_and_conditions) {
+ GetUserData()->terms_and_conditions_ = terms_and_conditions;
+ execution_delegate_->NotifyUserDataChange(
+ UserData::FieldChange::TERMS_AND_CONDITIONS);
+}
+
+void UiController::SetLoginOption(const std::string& identifier) {
+ if (!collect_user_data_options_)
+ return;
+
+ GetUserModel()->SetSelectedLoginChoiceByIdentifier(
+ identifier, *collect_user_data_options_, GetUserData());
+
+ execution_delegate_->NotifyUserDataChange(
+ UserData::FieldChange::LOGIN_CHOICE);
+}
+
+void UiController::UpdateCollectUserDataActions() {
+ if (!collect_user_data_options_) {
+ SetUserActions(nullptr);
+ return;
+ }
+
+ bool confirm_button_enabled = CollectUserDataAction::IsUserDataComplete(
+ *GetUserData(), *GetUserModel(), *collect_user_data_options_);
+
+ UserAction confirm(collect_user_data_options_->confirm_action);
+ confirm.SetEnabled(confirm_button_enabled);
+ if (confirm_button_enabled) {
+ confirm.SetCallback(
+ base::BindOnce(&UiController::OnCollectUserDataContinueButtonClicked,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
+
+ auto user_actions = std::make_unique<std::vector<UserAction>>();
+ user_actions->emplace_back(std::move(confirm));
+
+ // Add additional actions.
+ for (size_t i = 0; i < collect_user_data_options_->additional_actions.size();
+ ++i) {
+ auto action = collect_user_data_options_->additional_actions[i];
+ user_actions->push_back({action});
+ user_actions->back().SetCallback(base::BindOnce(
+ &UiController::OnCollectUserDataAdditionalActionTriggered,
+ weak_ptr_factory_.GetWeakPtr(), i));
+ }
+
+ SetUserActions(std::move(user_actions));
+}
+
+void UiController::OnValueChanged(const std::string& identifier,
+ const ValueProto& new_value) {
+ event_handler_.DispatchEvent({EventProto::kOnValueChanged, identifier});
+ // TODO(b/145043394) Remove this once chips are part of generic UI.
+ if (collect_user_data_options_ != nullptr &&
+ collect_user_data_options_->additional_model_identifier_to_check
+ .has_value() &&
+ identifier ==
+ *collect_user_data_options_->additional_model_identifier_to_check) {
+ UpdateCollectUserDataActions();
+ }
+}
+
+void UiController::SetCollectUserDataOptions(CollectUserDataOptions* options) {
+ DCHECK(!options ||
+ (options->confirm_callback && options->additional_actions_callback &&
+ options->terms_link_callback));
+
+ if (collect_user_data_options_ == nullptr && options == nullptr)
+ return;
+
+ collect_user_data_options_ = options;
+ for (UiControllerObserver& observer : observers_) {
+ observer.OnCollectUserDataOptionsChanged(collect_user_data_options_);
+ }
+ execution_delegate_->NotifyUserDataChange(UserData::FieldChange::ALL);
+}
+
+void UiController::SetLastSuccessfulUserDataOptions(
+ std::unique_ptr<CollectUserDataOptions> collect_user_data_options) {
+ last_collect_user_data_options_ = std::move(collect_user_data_options);
+}
+
+const CollectUserDataOptions* UiController::GetLastSuccessfulUserDataOptions()
+ const {
+ return last_collect_user_data_options_.get();
+}
+
+void UiController::OnKeyboardVisibilityChanged(bool visible) {
+ is_keyboard_showing_ = visible;
+
+ if (ShouldUpdateChipVisibility()) {
+ SetVisibilityAndUpdateUserActions();
+ }
+}
+
+void UiController::OnInputTextFocusChanged(bool is_text_focused) {
+ is_focus_on_bottom_sheet_text_input_ = is_text_focused;
+
+ if (ShouldUpdateChipVisibility()) {
+ SetVisibilityAndUpdateUserActions();
+ }
+}
+
+void UiController::OnFeedbackSent() {
+ execution_delegate_->ShutdownIfNecessary();
+}
+
+void UiController::OnStateChanged(AutofillAssistantState state) {}
+
+void UiController::OnKeyboardSuppressionStateChanged(
+ bool should_suppress_keyboard) {}
+void UiController::CloseCustomTab() {}
+void UiController::OnError(const std::string& error_message,
+ Metrics::DropOutReason reason) {
+ show_feedback_chip_ = ShouldShowFeedbackChipForReason(reason);
+ SetStatusMessage(error_message);
+ SetProgressBarErrorState(true);
+}
+
+void UiController::OnUserDataChanged(const UserData& user_data,
+ UserData::FieldChange field_change) {
+ UpdateCollectUserDataActions();
+}
+void UiController::OnTouchableAreaChanged(
+ const RectF& visual_viewport,
+ const std::vector<RectF>& touchable_areas,
+ const std::vector<RectF>& restricted_areas) {}
+void UiController::OnViewportModeChanged(ViewportMode mode) {}
+void UiController::OnOverlayColorsChanged(
+ const ExecutionDelegate::OverlayColors& colors) {}
+void UiController::OnClientSettingsChanged(const ClientSettings& settings) {}
+void UiController::OnShouldShowOverlayChanged(bool should_show) {}
+
+void UiController::OnExecuteScript(const std::string& start_message) {
+ if (!start_message.empty())
+ SetStatusMessage(start_message);
+
+ SetUserActions(nullptr);
+}
+
+void UiController::InitFromParameters(const TriggerContext& trigger_context) {
+ auto details = std::make_unique<Details>();
+ if (details->UpdateFromParameters(trigger_context.GetScriptParameters()))
+ SetDetails(std::move(details), base::TimeDelta());
+
+ const absl::optional<bool> enable_tts =
+ trigger_context.GetScriptParameters().GetEnableTts();
+ if (enable_tts && enable_tts.value() &&
+ !client_->IsSpokenFeedbackAccessibilityServiceEnabled()) {
+ tts_enabled_ = true;
+ for (UiControllerObserver& observer : observers_) {
+ observer.OnTtsButtonVisibilityChanged(/* visible= */ true);
+ }
+ }
+}
+
+void UiController::OnStart(const TriggerContext& trigger_context) {
+ InitFromParameters(trigger_context);
+
+ // |status_message_| may be non-empty due to a trigger script that was run.
+ SetStatusMessage(
+ status_message_.empty()
+ ? l10n_util::GetStringFUTF8(
+ IDS_AUTOFILL_ASSISTANT_LOADING,
+ base::UTF8ToUTF16(execution_delegate_->GetCurrentURL().host()))
+ : status_message_);
+
+ SetStepProgressBarConfiguration(step_progress_bar_configuration_);
+ SetProgressActiveStep(progress_active_step_);
+}
+
+void UiController::OnStop() {
+ std::unique_ptr<std::vector<UserAction>> final_actions;
+ if (base::FeatureList::IsEnabled(features::kAutofillAssistantFeedbackChip) &&
+ show_feedback_chip_) {
+ final_actions = std::make_unique<std::vector<UserAction>>();
+ UserAction feedback_action;
+ Chip feedback_chip;
+ feedback_chip.type = FEEDBACK_ACTION;
+ feedback_chip.text =
+ GetDisplayStringUTF8(ClientSettingsProto::SEND_FEEDBACK,
+ execution_delegate_->GetClientSettings());
+ feedback_action.SetCallback(base::BindOnce(&UiController::OnFeedbackSent,
+ weak_ptr_factory_.GetWeakPtr()));
+ feedback_action.chip() = feedback_chip;
+ final_actions->emplace_back(std::move(feedback_action));
+ }
+
+ ClearInfoBox();
+ SetDetails(nullptr, base::TimeDelta());
+ SetUserActions(std::move(final_actions));
+ SetCollectUserDataOptions(nullptr);
+ SetForm(nullptr, base::DoNothing(), base::DoNothing());
+}
+
+void UiController::OnResetState() {
+ // TODO(b/204963552): this list is incomplete. It would be much better if,
+ // instead of selectively clearing fields, we'd solve this in a more holistic
+ // way.
+ bubble_message_.clear();
+ tts_message_.clear();
+ status_message_.clear();
+ details_.clear();
+ info_box_.reset();
+ progress_visible_ = true;
+ progress_bar_error_state_ = false;
+ progress_active_step_ = 0;
+ step_progress_bar_configuration_ =
+ ShowProgressBarProto::StepProgressBarConfiguration();
+ peek_mode_ = ConfigureBottomSheetProto::HANDLE;
+}
+
+void UiController::OnUiShownChanged(bool shown) {
+ // Stop any ongoing TTS if UI is hidden.
+ if (!shown && tts_button_state_ == TtsButtonState::PLAYING) {
+ // Will not cause any TTS event.
+ tts_controller_->Stop();
+ SetTtsButtonState(TtsButtonState::DEFAULT);
+ }
+}
+
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/ui_controller.h b/chromium/components/autofill_assistant/browser/ui_controller.h
new file mode 100644
index 00000000000..0448dd3ff7a
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/ui_controller.h
@@ -0,0 +1,338 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_UI_CONTROLLER_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_UI_CONTROLLER_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/callback_helpers.h"
+#include "components/autofill_assistant/browser/autofill_assistant_tts_controller.h"
+#include "components/autofill_assistant/browser/basic_interactions.h"
+#include "components/autofill_assistant/browser/bottom_sheet_state.h"
+#include "components/autofill_assistant/browser/client.h"
+#include "components/autofill_assistant/browser/controller_observer.h"
+#include "components/autofill_assistant/browser/element_area.h"
+#include "components/autofill_assistant/browser/event_handler.h"
+#include "components/autofill_assistant/browser/execution_delegate.h"
+#include "components/autofill_assistant/browser/metrics.h"
+#include "components/autofill_assistant/browser/public/runtime_manager_impl.h"
+#include "components/autofill_assistant/browser/script_executor_ui_delegate.h"
+#include "components/autofill_assistant/browser/state.h"
+#include "components/autofill_assistant/browser/trigger_context.h"
+#include "components/autofill_assistant/browser/ui_controller_observer.h"
+#include "components/autofill_assistant/browser/ui_delegate.h"
+#include "components/autofill_assistant/browser/user_action.h"
+#include "components/autofill_assistant/browser/user_data.h"
+#include "components/autofill_assistant/browser/user_model.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace autofill_assistant {
+class UiControllerTest;
+
+// UiController controls the Autofill Assistant UI.
+// This class includes the logic and state specific to this UI.
+// Anything non-UI related or anything which is shared with other UI
+// implementations should be in Controller instead.
+class UiController : public ScriptExecutorUiDelegate,
+ public virtual UiDelegate,
+ public AutofillAssistantTtsController::TtsEventDelegate,
+ public ControllerObserver,
+ private UserModel::Observer {
+ public:
+ // |client| and |execution_delegate| must remain valid for the lifetime of the
+ // instance.
+ UiController(Client* client,
+ ExecutionDelegate* execution_delegate,
+ std::unique_ptr<AutofillAssistantTtsController> tts_controller);
+
+ UiController(const UiController&) = delete;
+ UiController& operator=(const UiController&) = delete;
+
+ ~UiController() override;
+
+ // The UiController starts listening for notifications.
+ void StartListening();
+
+ // Called when an accessibility service with "FEEDBACK_SPOKEN" feedback type
+ // is enabled or disabled.
+ void OnSpokenFeedbackAccessibilityServiceChanged(bool enabled);
+ base::Value GetDebugContext() const;
+
+ // Overrides ScriptExecutorUiDelegate
+ void SetStatusMessage(const std::string& message) override;
+ std::string GetStatusMessage() const override;
+ void SetBubbleMessage(const std::string& message) override;
+ std::string GetBubbleMessage() const override;
+ void SetTtsMessage(const std::string& message) override;
+ std::string GetTtsMessage() const override;
+ void MaybePlayTtsMessage() override;
+ void SetDetails(std::unique_ptr<Details>, base::TimeDelta delay) override;
+ void AppendDetails(std::unique_ptr<Details> details,
+ base::TimeDelta delay) override;
+ void SetInfoBox(const InfoBox& info_box) override;
+ void ClearInfoBox() override;
+ bool SetProgressActiveStepIdentifier(
+ const std::string& active_step_identifier) override;
+ void SetProgressActiveStep(int active_step) override;
+ void SetProgressVisible(bool visible) override;
+ void SetProgressBarErrorState(bool error) override;
+ void SetStepProgressBarConfiguration(
+ const ShowProgressBarProto::StepProgressBarConfiguration& configuration)
+ override;
+ void SetUserActions(
+ std::unique_ptr<std::vector<UserAction>> user_actions) override;
+ void SetPeekMode(ConfigureBottomSheetProto::PeekMode peek_mode) override;
+ void ExpandBottomSheet() override;
+ void CollapseBottomSheet() override;
+ bool SetForm(
+ std::unique_ptr<FormProto> form,
+ base::RepeatingCallback<void(const FormProto::Result*)> changed_callback,
+ base::OnceCallback<void(const ClientStatus&)> cancel_callback) override;
+ void SetGenericUi(
+ std::unique_ptr<GenericUserInterfaceProto> generic_ui,
+ base::OnceCallback<void(const ClientStatus&)> end_action_callback,
+ base::OnceCallback<void(const ClientStatus&)>
+ view_inflation_finished_callback) override;
+ void SetPersistentGenericUi(
+ std::unique_ptr<GenericUserInterfaceProto> generic_ui,
+ base::OnceCallback<void(const ClientStatus&)>
+ view_inflation_finished_callback) override;
+ void ClearGenericUi() override;
+ void ClearPersistentGenericUi() override;
+ void SetShowFeedbackChip(bool show_feedback_chip) override;
+
+ void SetExpandSheetForPromptAction(bool expand) override;
+ void SetCollectUserDataOptions(CollectUserDataOptions* options) override;
+ void SetLastSuccessfulUserDataOptions(std::unique_ptr<CollectUserDataOptions>
+ collect_user_data_options) override;
+ const CollectUserDataOptions* GetLastSuccessfulUserDataOptions()
+ const override;
+
+ // Overrides autofill_assistant::UiDelegate:
+ std::vector<Details> GetDetails() const override;
+ const InfoBox* GetInfoBox() const override;
+ int GetProgressActiveStep() const override;
+ bool GetProgressVisible() const override;
+ bool GetTtsButtonVisible() const override;
+ TtsButtonState GetTtsButtonState() const override;
+ bool GetProgressBarErrorState() const override;
+ ShowProgressBarProto::StepProgressBarConfiguration
+ GetStepProgressBarConfiguration() const override;
+ const std::vector<UserAction>& GetUserActions() const override;
+ bool PerformUserAction(int index) override;
+ const CollectUserDataOptions* GetCollectUserDataOptions() const override;
+ void HandleShippingAddressChange(
+ std::unique_ptr<autofill::AutofillProfile> address,
+ UserDataEventType event_type) override;
+ void HandleContactInfoChange(
+ std::unique_ptr<autofill::AutofillProfile> profile,
+ UserDataEventType event_type) override;
+ void HandlePhoneNumberChange(
+ std::unique_ptr<autofill::AutofillProfile> profile,
+ UserDataEventType event_type) override;
+ void HandleCreditCardChange(
+ std::unique_ptr<autofill::CreditCard> card,
+ std::unique_ptr<autofill::AutofillProfile> billing_profile,
+ UserDataEventType event_type) override;
+ void SetTermsAndConditions(
+ TermsAndConditionsState terms_and_conditions) override;
+ void SetLoginOption(const std::string& identifier) override;
+ void OnTextLinkClicked(int link) override;
+ void OnFormActionLinkClicked(int link) override;
+ void OnTtsButtonClicked() override;
+ void SetAdditionalValue(const std::string& client_memory_key,
+ const ValueProto& value) override;
+ ConfigureBottomSheetProto::PeekMode GetPeekMode() override;
+ BottomSheetState GetBottomSheetState() override;
+ void SetBottomSheetState(BottomSheetState state) override;
+ const FormProto* GetForm() const override;
+ const FormProto::Result* GetFormResult() const override;
+ void SetCounterValue(int input_index, int counter_index, int value) override;
+ void SetChoiceSelected(int input_index,
+ int choice_index,
+ bool selected) override;
+ void AddObserver(UiControllerObserver* observer) override;
+ void RemoveObserver(const UiControllerObserver* observer) override;
+ bool ShouldPromptActionExpandSheet() const override;
+ BasicInteractions* GetBasicInteractions() override;
+ const GenericUserInterfaceProto* GetGenericUiProto() const override;
+ const GenericUserInterfaceProto* GetPersistentGenericUiProto() const override;
+ void OnKeyboardVisibilityChanged(bool visible) override;
+ void OnInputTextFocusChanged(bool is_text_focused) override;
+ EventHandler* GetEventHandler() override;
+ void DispatchEvent(const EventHandler::EventKey& key) override;
+
+ // Overrides ControllerObserver.
+ void OnStateChanged(AutofillAssistantState new_state) override;
+ void OnKeyboardSuppressionStateChanged(
+ bool should_suppress_keyboard) override;
+ void CloseCustomTab() override;
+ void OnError(const std::string& error_message,
+ Metrics::DropOutReason reason) override;
+ void OnUserDataChanged(const UserData& user_data,
+ UserData::FieldChange field_change) override;
+ void OnTouchableAreaChanged(
+ const RectF& visual_viewport,
+ const std::vector<RectF>& touchable_areas,
+ const std::vector<RectF>& restricted_areas) override;
+ void OnViewportModeChanged(ViewportMode mode) override;
+ void OnOverlayColorsChanged(
+ const ExecutionDelegate::OverlayColors& colors) override;
+ void OnClientSettingsChanged(const ClientSettings& settings) override;
+ void OnShouldShowOverlayChanged(bool should_show) override;
+ void OnExecuteScript(const std::string& start_message) override;
+ void OnStart(const TriggerContext& trigger_context) override;
+ void OnStop() override;
+ void OnResetState() override;
+ void OnUiShownChanged(bool shown) override;
+
+ // Overrides AutofillAssistantTtsController::TtsEventDelegate
+ void OnTtsEvent(AutofillAssistantTtsController::TtsEventType event) override;
+
+ private:
+ friend UiControllerTest;
+
+ // A holder class which contains some details and, optionally, a timer that
+ // will "enable" them later on.
+ class DetailsHolder {
+ public:
+ DetailsHolder(std::unique_ptr<Details> details,
+ std::unique_ptr<base::OneShotTimer> timer);
+ ~DetailsHolder();
+ DetailsHolder(DetailsHolder&& other);
+ DetailsHolder& operator=(DetailsHolder&& other);
+
+ // The details held by this object.
+ const Details& GetDetails() const;
+
+ // Whether the details held by this object are visible. Will return false if
+ // a timer was set and was not reached yet.
+ bool CurrentlyVisible() const;
+
+ // Enable the details held by this object so that they are shown (i.e.
+ // CurrentlyVisible() returns true).
+ //
+ // In practice, this is called at most once when |timer_| is triggered.
+ void Enable();
+
+ private:
+ std::unique_ptr<Details> details_;
+ std::unique_ptr<base::OneShotTimer> timer_;
+ };
+
+ void InitFromParameters(const TriggerContext& trigger_context);
+ void UpdateCollectUserDataActions();
+ void OnCollectUserDataContinueButtonClicked();
+ void OnCollectUserDataAdditionalActionTriggered(int index);
+
+ // Overrides autofill_assistant::UserModel::Observer:
+ void OnValueChanged(const std::string& identifier,
+ const ValueProto& new_value) override;
+
+ void SetProfile(const std::string& key,
+ UserData::FieldChange field_change,
+ std::unique_ptr<autofill::AutofillProfile> profile);
+
+ void ReloadUserData(UserDataEventField event_field,
+ UserDataEventType event_type);
+
+ bool StateNeedsUI(AutofillAssistantState state);
+
+ bool ShouldChipsBeVisible();
+ bool ShouldUpdateChipVisibility();
+ void SetVisibilityAndUpdateUserActions();
+
+ void MakeDetailsVisible(size_t details_index);
+ void NotifyDetailsChanged();
+
+ // This represents the display strings locale to be used for the currently
+ // executing set of actions. This locale is used in two ways currently:
+ // 1. Locale of backend provided display strings, if available.
+ // 2. TTS Controller uses this locale for playing TTS messages.
+ std::string GetDisplayStringsLocale();
+ void SetTtsButtonState(TtsButtonState state);
+
+ void SetInitialState();
+ void SetStoppedState();
+ void OnFeedbackSent();
+
+ UserData* GetUserData();
+ UserModel* GetUserModel();
+
+ Client* const client_;
+
+ // Current status message, may be empty.
+ std::string status_message_;
+
+ // Current TTS message to be played, may be empty.
+ std::string tts_message_;
+
+ // Current bubble / tooltip message, may be empty.
+ std::string bubble_message_;
+
+ // Current details, may be empty.
+ std::vector<DetailsHolder> details_;
+
+ // Current info box, may be null.
+ std::unique_ptr<InfoBox> info_box_;
+
+ // Current state of the progress bar.
+ bool progress_visible_ = true;
+ bool progress_bar_error_state_ = false;
+ ShowProgressBarProto::StepProgressBarConfiguration
+ step_progress_bar_configuration_;
+ int progress_active_step_ = 0;
+
+ // Current set of user actions. May be null, but never empty.
+ std::unique_ptr<std::vector<UserAction>> user_actions_;
+
+ // Current peek mode.
+ ConfigureBottomSheetProto::PeekMode peek_mode_ =
+ ConfigureBottomSheetProto::HANDLE;
+
+ // The latest bottom sheet state stored.
+ BottomSheetState bottom_sheet_state_ = BottomSheetState::UNDEFINED;
+ // A copy of the most recently set user data options. Can be used to determine
+ // which information was requested.
+ std::unique_ptr<CollectUserDataOptions> last_collect_user_data_options_;
+ raw_ptr<CollectUserDataOptions> collect_user_data_options_ = nullptr;
+
+ std::unique_ptr<FormProto> form_;
+ std::unique_ptr<FormProto::Result> form_result_;
+ base::RepeatingCallback<void(const FormProto::Result*)>
+ form_changed_callback_ = base::DoNothing();
+ base::OnceCallback<void(const ClientStatus&)> form_cancel_callback_ =
+ base::DoNothing();
+
+ base::ObserverList<UiControllerObserver> observers_;
+
+ ExecutionDelegate* execution_delegate_;
+ EventHandler event_handler_;
+ BasicInteractions basic_interactions_{this, execution_delegate_};
+
+ bool expand_sheet_for_prompt_action_ = true;
+ bool browse_mode_invisible_ = false;
+ bool is_keyboard_showing_ = false;
+ bool is_focus_on_bottom_sheet_text_input_ = false;
+ bool show_feedback_chip_ = false;
+ bool are_chips_visible_ = true;
+
+ bool tts_enabled_ = false;
+ std::unique_ptr<AutofillAssistantTtsController> tts_controller_;
+ TtsButtonState tts_button_state_ = TtsButtonState::DEFAULT;
+
+ // Only set during a ShowGenericUiAction.
+ std::unique_ptr<GenericUserInterfaceProto> generic_user_interface_;
+
+ std::unique_ptr<GenericUserInterfaceProto> persistent_generic_user_interface_;
+
+ base::WeakPtrFactory<UiController> weak_ptr_factory_{this};
+};
+
+} // namespace autofill_assistant
+
+#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_UI_CONTROLLER_H_
diff --git a/chromium/components/autofill_assistant/browser/ui_controller_observer.cc b/chromium/components/autofill_assistant/browser/ui_controller_observer.cc
new file mode 100644
index 00000000000..0469ff91127
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/ui_controller_observer.cc
@@ -0,0 +1,14 @@
+// Copyright 2022 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.
+
+#include "components/autofill_assistant/browser/ui_controller_observer.h"
+
+#include "components/autofill/core/browser/data_model/autofill_profile.h"
+#include "components/autofill/core/browser/data_model/credit_card.h"
+
+namespace autofill_assistant {
+
+UiControllerObserver::UiControllerObserver() = default;
+UiControllerObserver::~UiControllerObserver() = default;
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/ui_controller_observer.h b/chromium/components/autofill_assistant/browser/ui_controller_observer.h
new file mode 100644
index 00000000000..daf33b94120
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/ui_controller_observer.h
@@ -0,0 +1,99 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_UI_CONTROLLER_OBSERVER_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_UI_CONTROLLER_OBSERVER_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/observer_list_types.h"
+#include "components/autofill_assistant/browser/details.h"
+#include "components/autofill_assistant/browser/execution_delegate.h"
+#include "components/autofill_assistant/browser/info_box.h"
+#include "components/autofill_assistant/browser/metrics.h"
+#include "components/autofill_assistant/browser/script.h"
+#include "components/autofill_assistant/browser/state.h"
+#include "components/autofill_assistant/browser/tts_button_state.h"
+#include "components/autofill_assistant/browser/ui_delegate.h"
+#include "components/autofill_assistant/browser/user_action.h"
+#include "components/autofill_assistant/browser/user_data.h"
+
+namespace autofill_assistant {
+
+// Observes UiController's state.
+class UiControllerObserver : public base::CheckedObserver {
+ public:
+ UiControllerObserver();
+ ~UiControllerObserver() override;
+
+ // Report that the status message has changed.
+ virtual void OnStatusMessageChanged(const std::string& message) = 0;
+
+ // Report that the bubble / tooltip message has changed.
+ virtual void OnBubbleMessageChanged(const std::string& message) = 0;
+
+ // Report that the set of user actions has changed.
+ virtual void OnUserActionsChanged(
+ const std::vector<UserAction>& user_actions) = 0;
+
+ // Report that the options configuring a CollectUserDataAction have changed.
+ virtual void OnCollectUserDataOptionsChanged(
+ const CollectUserDataOptions* options) = 0;
+
+ // Called when details have changed. Details will be empty if they have been
+ // cleared.
+ virtual void OnDetailsChanged(const std::vector<Details>& details) = 0;
+
+ // Called when info box has changed. |info_box| will be null if it has been
+ // cleared.
+ virtual void OnInfoBoxChanged(const InfoBox* info_box) = 0;
+
+ // Called when the currently active progress step has changed.
+ virtual void OnProgressActiveStepChanged(int active_step) = 0;
+
+ // Called when the current progress bar visibility has changed. If |visible|
+ // is true, then the bar is now shown.
+ virtual void OnProgressVisibilityChanged(bool visible) = 0;
+
+ virtual void OnStepProgressBarConfigurationChanged(
+ const ShowProgressBarProto::StepProgressBarConfiguration&
+ configuration) = 0;
+
+ // Called when the progress bar error state changes.
+ virtual void OnProgressBarErrorStateChanged(bool error) = 0;
+
+ // Called when the peek mode has changed.
+ virtual void OnPeekModeChanged(
+ ConfigureBottomSheetProto::PeekMode peek_mode) = 0;
+
+ // Called when the bottom sheet should be expanded.
+ virtual void OnExpandBottomSheet() = 0;
+
+ // Called when the bottom sheet should be collapsed.
+ virtual void OnCollapseBottomSheet() = 0;
+
+ // Called when the form has changed.
+ virtual void OnFormChanged(const FormProto* form,
+ const FormProto::Result* result) = 0;
+
+ // Called when the generic user interface to show has been changed or cleared.
+ virtual void OnGenericUserInterfaceChanged(
+ const GenericUserInterfaceProto* generic_ui) = 0;
+
+ // Called when the persistent generic user interface to show has been changed
+ // or cleared.
+ virtual void OnPersistentGenericUserInterfaceChanged(
+ const GenericUserInterfaceProto* generic_ui) = 0;
+
+ // Called when the TTS button visibility has changed. If |visible| is true,
+ // then the button is shown.
+ virtual void OnTtsButtonVisibilityChanged(bool visible) = 0;
+
+ // Called when Tts Button State has changed.
+ virtual void OnTtsButtonStateChanged(TtsButtonState state) = 0;
+};
+} // namespace autofill_assistant
+#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_UI_CONTROLLER_OBSERVER_H_
diff --git a/chromium/components/autofill_assistant/browser/ui_controller_unittest.cc b/chromium/components/autofill_assistant/browser/ui_controller_unittest.cc
new file mode 100644
index 00000000000..816fda3dfb0
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/ui_controller_unittest.cc
@@ -0,0 +1,1105 @@
+// Copyright 2022 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.
+
+#include "components/autofill_assistant/browser/ui_controller.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/callback_helpers.h"
+#include "base/containers/flat_map.h"
+#include "base/guid.h"
+#include "base/memory/raw_ptr.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/bind.h"
+#include "base/test/gmock_callback_support.h"
+#include "base/test/gtest_util.h"
+#include "base/test/mock_callback.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/test/task_environment.h"
+#include "components/autofill/core/browser/autofill_test_utils.h"
+#include "components/autofill/core/browser/field_types.h"
+#include "components/autofill_assistant/browser/cud_condition.pb.h"
+#include "components/autofill_assistant/browser/device_context.h"
+#include "components/autofill_assistant/browser/fake_script_executor_ui_delegate.h"
+#include "components/autofill_assistant/browser/features.h"
+#include "components/autofill_assistant/browser/mock_autofill_assistant_tts_controller.h"
+#include "components/autofill_assistant/browser/mock_client.h"
+#include "components/autofill_assistant/browser/mock_execution_delegate.h"
+#include "components/autofill_assistant/browser/mock_ui_controller_observer.h"
+#include "components/autofill_assistant/browser/test_util.h"
+#include "components/autofill_assistant/browser/trigger_context.h"
+#include "components/strings/grit/components_strings.h"
+#include "content/public/test/test_browser_context.h"
+#include "content/public/test/test_renderer_host.h"
+#include "net/http/http_status_code.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "third_party/blink/public/common/features.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace autofill_assistant {
+
+using ::base::test::RunOnceCallback;
+using ::testing::_;
+using ::testing::AllOf;
+using ::testing::AnyNumber;
+using ::testing::DoAll;
+using ::testing::ElementsAre;
+using ::testing::Eq;
+using ::testing::Field;
+using ::testing::Gt;
+using ::testing::InSequence;
+using ::testing::Invoke;
+using ::testing::IsEmpty;
+using ::testing::NiceMock;
+using ::testing::Not;
+using ::testing::NotNull;
+using ::testing::Property;
+using ::testing::Return;
+using ::testing::ReturnRef;
+using ::testing::SaveArg;
+using ::testing::Sequence;
+using ::testing::SizeIs;
+using ::testing::StrEq;
+using ::testing::UnorderedElementsAre;
+using ::testing::WithArgs;
+
+namespace {
+
+constexpr char kClientLocale[] = "en-US";
+
+// Same as non-mock, but provides default mock callbacks.
+struct FakeCollectUserDataOptions : public CollectUserDataOptions {
+ FakeCollectUserDataOptions() {
+ confirm_callback = base::DoNothing();
+ additional_actions_callback = base::DoNothing();
+ terms_link_callback = base::DoNothing();
+ selected_user_data_changed_callback = base::DoNothing();
+ }
+};
+
+} // namespace
+
+class UiControllerTest : public testing::Test {
+ public:
+ UiControllerTest() {}
+
+ void SetUp() override {
+ ON_CALL(mock_client_, GetLocale()).WillByDefault(Return(kClientLocale));
+ ON_CALL(mock_execution_delegate_, GetUserModel())
+ .WillByDefault(Return(&user_model_));
+ ON_CALL(mock_execution_delegate_, GetUserData())
+ .WillByDefault(Return(&user_data_));
+ ON_CALL(mock_execution_delegate_, GetClientSettings())
+ .WillByDefault(ReturnRef(client_settings_));
+ ON_CALL(mock_execution_delegate_, GetCurrentURL())
+ .WillByDefault(ReturnRef(current_url_));
+ ON_CALL(mock_execution_delegate_, GetTriggerContext())
+ .WillByDefault(Return(&trigger_context_));
+
+ auto tts_controller =
+ std::make_unique<NiceMock<MockAutofillAssistantTtsController>>();
+ mock_tts_controller_ = tts_controller.get();
+ ui_controller_ = std::make_unique<UiController>(
+ &mock_client_, &mock_execution_delegate_, std::move(tts_controller));
+
+ ui_controller_->AddObserver(&mock_observer_);
+ ui_controller_->StartListening();
+ }
+
+ void TearDown() override {
+ ui_controller_->RemoveObserver(&mock_observer_);
+ ui_controller_.reset();
+ }
+
+ protected:
+ RequiredDataPiece MakeRequiredDataPiece(autofill::ServerFieldType field) {
+ RequiredDataPiece required_data_piece;
+ required_data_piece.mutable_condition()->set_key(static_cast<int>(field));
+ required_data_piece.mutable_condition()->mutable_not_empty();
+ return required_data_piece;
+ }
+
+ void EnableTtsForTest() { ui_controller_->tts_enabled_ = true; }
+
+ void SetTtsButtonStateForTest(TtsButtonState state) {
+ ui_controller_->tts_button_state_ = state;
+ }
+
+ content::BrowserTaskEnvironment task_environment_{
+ base::test::TaskEnvironment::TimeSource::MOCK_TIME};
+ NiceMock<MockClient> mock_client_;
+ NiceMock<MockExecutionDelegate> mock_execution_delegate_;
+ raw_ptr<MockAutofillAssistantTtsController> mock_tts_controller_;
+ NiceMock<MockUiControllerObserver> mock_observer_;
+ std::unique_ptr<UiController> ui_controller_;
+ UserModel user_model_;
+ UserData user_data_;
+ TriggerContext trigger_context_;
+ ClientSettings client_settings_;
+ base::test::ScopedFeatureList scoped_feature_list_;
+ GURL current_url_ = GURL("http://www.example.com");
+};
+
+UserAction MakeUserAction(const std::string& text) {
+ ChipProto chip;
+ chip.set_text(text);
+
+ return UserAction(chip, true, "");
+}
+
+TEST_F(UiControllerTest, ClearUserActionsOnSelection) {
+ {
+ testing::InSequence seq;
+ // We set two chips.
+ EXPECT_CALL(mock_observer_, OnUserActionsChanged(SizeIs(2)));
+ // When one chip is selected the user actions are cleared.
+ EXPECT_CALL(mock_observer_, OnUserActionsChanged(SizeIs(0)));
+ }
+ auto actions = std::make_unique<std::vector<UserAction>>();
+ actions->push_back(MakeUserAction("Continue"));
+ actions->push_back(MakeUserAction("Cancel"));
+ ui_controller_->SetUserActions(std::move(actions));
+
+ EXPECT_TRUE(ui_controller_->PerformUserAction(0));
+}
+
+TEST_F(UiControllerTest, StopWithFeedbackChip) {
+ client_settings_.display_strings[ClientSettingsProto::SEND_FEEDBACK] =
+ "send_feedback";
+ // By default the feedback chip isn't shown on stop.
+ ui_controller_->OnStop();
+ ASSERT_THAT(ui_controller_->GetUserActions(), SizeIs(0u));
+
+ // If requested, the feedback chip should be shown.
+ ui_controller_->SetShowFeedbackChip(true);
+ ui_controller_->OnStop();
+ EXPECT_THAT(
+ ui_controller_->GetUserActions(),
+ ElementsAre(Property(&UserAction::chip,
+ AllOf(Field(&Chip::type, FEEDBACK_ACTION),
+ Field(&Chip::text, "send_feedback")))));
+}
+
+TEST_F(UiControllerTest, FeedbackChipIsShownOnSpecificErrors) {
+ client_settings_.display_strings[ClientSettingsProto::SEND_FEEDBACK] =
+ "send_feedback";
+ // For this dropout reason, the feedback chip should not be shown.
+ ui_controller_->OnError("error_message", Metrics::DropOutReason::NO_SCRIPTS);
+ ui_controller_->OnStop();
+ ASSERT_THAT(ui_controller_->GetUserActions(), SizeIs(0u));
+
+ // For this dropout reason, the feedback chip should be shown.
+ ui_controller_->OnError("error_message",
+ Metrics::DropOutReason::GET_SCRIPTS_FAILED);
+ ui_controller_->OnStop();
+ EXPECT_THAT(
+ ui_controller_->GetUserActions(),
+ ElementsAre(Property(&UserAction::chip,
+ AllOf(Field(&Chip::type, FEEDBACK_ACTION),
+ Field(&Chip::text, "send_feedback")))));
+}
+
+TEST_F(UiControllerTest, FeedbackChipNotShownWithFeatureFlagDisabled) {
+ // Disable the feedback chip feature.
+ scoped_feature_list_.Reset();
+ scoped_feature_list_.InitAndDisableFeature(
+ features::kAutofillAssistantFeedbackChip);
+
+ // With the feature disabled, the chip shouldn't be shown even if requested.
+ ui_controller_->SetShowFeedbackChip(true);
+ ui_controller_->OnStop();
+ ASSERT_THAT(ui_controller_->GetUserActions(), SizeIs(0u));
+}
+
+TEST_F(UiControllerTest, ProgressSetAtStart) {
+ EXPECT_CALL(mock_observer_, OnStepProgressBarConfigurationChanged(_));
+ EXPECT_CALL(mock_observer_, OnProgressActiveStepChanged(0));
+ ui_controller_->OnStart(trigger_context_);
+ EXPECT_EQ(0, ui_controller_->GetProgressActiveStep());
+}
+
+TEST_F(UiControllerTest, SetProgressStep) {
+ EXPECT_CALL(mock_observer_, OnStepProgressBarConfigurationChanged(_));
+ EXPECT_CALL(mock_observer_, OnProgressActiveStepChanged(0));
+ ui_controller_->OnStart(trigger_context_);
+
+ ShowProgressBarProto::StepProgressBarConfiguration config;
+ config.add_annotated_step_icons()->set_identifier("icon1");
+ config.add_annotated_step_icons()->set_identifier("icon2");
+ EXPECT_CALL(mock_observer_, OnStepProgressBarConfigurationChanged(_));
+ EXPECT_CALL(mock_observer_, OnProgressActiveStepChanged(0));
+ ui_controller_->SetStepProgressBarConfiguration(config);
+ EXPECT_EQ(0, ui_controller_->GetProgressActiveStep());
+
+ EXPECT_CALL(mock_observer_, OnProgressActiveStepChanged(1));
+ ui_controller_->SetProgressActiveStep(1);
+ EXPECT_EQ(1, ui_controller_->GetProgressActiveStep());
+}
+
+TEST_F(UiControllerTest, IgnoreProgressStepDecreases) {
+ EXPECT_CALL(mock_observer_, OnProgressActiveStepChanged(0));
+ ui_controller_->OnStart(trigger_context_);
+
+ EXPECT_CALL(mock_observer_, OnStepProgressBarConfigurationChanged(_));
+ EXPECT_CALL(mock_observer_, OnProgressActiveStepChanged(0));
+ ShowProgressBarProto::StepProgressBarConfiguration config;
+ config.add_annotated_step_icons()->set_identifier("icon1");
+ config.add_annotated_step_icons()->set_identifier("icon2");
+ ui_controller_->SetStepProgressBarConfiguration(config);
+
+ EXPECT_CALL(mock_observer_, OnProgressActiveStepChanged(Not(1)))
+ .Times(AnyNumber());
+ ui_controller_->SetProgressActiveStep(2);
+ ui_controller_->SetProgressActiveStep(1);
+}
+
+TEST_F(UiControllerTest, NewProgressStepConfigurationClampsStep) {
+ ui_controller_->OnStart(trigger_context_);
+
+ ShowProgressBarProto::StepProgressBarConfiguration config;
+ config.add_annotated_step_icons()->set_identifier("icon1");
+ config.add_annotated_step_icons()->set_identifier("icon2");
+ config.add_annotated_step_icons()->set_identifier("icon3");
+ ui_controller_->SetStepProgressBarConfiguration(config);
+
+ EXPECT_CALL(mock_observer_, OnProgressActiveStepChanged(3));
+ ui_controller_->SetProgressActiveStep(3);
+ EXPECT_EQ(3, ui_controller_->GetProgressActiveStep());
+
+ ShowProgressBarProto::StepProgressBarConfiguration new_config;
+ new_config.add_annotated_step_icons()->set_identifier("icon1");
+ new_config.add_annotated_step_icons()->set_identifier("icon2");
+ EXPECT_CALL(mock_observer_, OnProgressActiveStepChanged(2));
+ ui_controller_->SetStepProgressBarConfiguration(new_config);
+ EXPECT_EQ(2, ui_controller_->GetProgressActiveStep());
+}
+
+TEST_F(UiControllerTest, ProgressStepWrapsNegativesToMax) {
+ ui_controller_->OnStart(trigger_context_);
+
+ ShowProgressBarProto::StepProgressBarConfiguration config;
+ config.add_annotated_step_icons()->set_identifier("icon1");
+ config.add_annotated_step_icons()->set_identifier("icon2");
+ config.add_annotated_step_icons()->set_identifier("icon3");
+ ui_controller_->SetStepProgressBarConfiguration(config);
+
+ EXPECT_CALL(mock_observer_, OnProgressActiveStepChanged(3));
+ ui_controller_->SetProgressActiveStep(-1);
+ EXPECT_EQ(3, ui_controller_->GetProgressActiveStep());
+}
+
+TEST_F(UiControllerTest, ProgressStepClampsOverflowToMax) {
+ ui_controller_->OnStart(trigger_context_);
+
+ ShowProgressBarProto::StepProgressBarConfiguration config;
+ config.add_annotated_step_icons()->set_identifier("icon1");
+ config.add_annotated_step_icons()->set_identifier("icon2");
+ config.add_annotated_step_icons()->set_identifier("icon3");
+ ui_controller_->SetStepProgressBarConfiguration(config);
+
+ EXPECT_CALL(mock_observer_, OnProgressActiveStepChanged(3));
+ ui_controller_->SetProgressActiveStep(std::numeric_limits<int>::max());
+ EXPECT_EQ(3, ui_controller_->GetProgressActiveStep());
+}
+
+TEST_F(UiControllerTest, SetProgressStepFromIdentifier) {
+ ui_controller_->OnStart(trigger_context_);
+
+ ShowProgressBarProto::StepProgressBarConfiguration config;
+ config.add_annotated_step_icons()->set_identifier("icon1");
+ config.add_annotated_step_icons()->set_identifier("icon2");
+ ui_controller_->SetStepProgressBarConfiguration(config);
+
+ EXPECT_CALL(mock_observer_, OnProgressActiveStepChanged(1));
+ EXPECT_TRUE(ui_controller_->SetProgressActiveStepIdentifier("icon2"));
+ EXPECT_EQ(1, ui_controller_->GetProgressActiveStep());
+}
+
+TEST_F(UiControllerTest, SetProgressStepFromUnknownIdentifier) {
+ EXPECT_CALL(mock_observer_, OnProgressActiveStepChanged(0));
+ ui_controller_->OnStart(trigger_context_);
+ EXPECT_EQ(0, ui_controller_->GetProgressActiveStep());
+
+ EXPECT_CALL(mock_observer_, OnStepProgressBarConfigurationChanged(_));
+ EXPECT_CALL(mock_observer_, OnProgressActiveStepChanged(0));
+ ShowProgressBarProto::StepProgressBarConfiguration config;
+ config.add_annotated_step_icons()->set_identifier("icon1");
+ config.add_annotated_step_icons()->set_identifier("icon2");
+ ui_controller_->SetStepProgressBarConfiguration(config);
+
+ EXPECT_CALL(mock_observer_, OnProgressActiveStepChanged(_)).Times(0);
+ EXPECT_FALSE(ui_controller_->SetProgressActiveStepIdentifier("icon3"));
+ EXPECT_EQ(0, ui_controller_->GetProgressActiveStep());
+}
+
+TEST_F(UiControllerTest, UserDataFormEmpty) {
+ auto options = std::make_unique<FakeCollectUserDataOptions>();
+
+ // Request nothing, expect continue button to be enabled.
+ EXPECT_CALL(mock_observer_, OnCollectUserDataOptionsChanged(Not(nullptr)));
+ EXPECT_CALL(mock_execution_delegate_,
+ NotifyUserDataChange(UserData::FieldChange::ALL));
+ ui_controller_->SetCollectUserDataOptions(options.get());
+ EXPECT_CALL(mock_observer_, OnUserActionsChanged(UnorderedElementsAre(
+ Property(&UserAction::enabled, Eq(true)))));
+ ui_controller_->OnUserDataChanged(user_data_, UserData::FieldChange::ALL);
+}
+
+TEST_F(UiControllerTest, UserDataFormContactInfo) {
+ auto options = std::make_unique<FakeCollectUserDataOptions>();
+
+ options->required_contact_data_pieces.push_back(
+ MakeRequiredDataPiece(autofill::ServerFieldType::NAME_FULL));
+ options->required_contact_data_pieces.push_back(
+ MakeRequiredDataPiece(autofill::ServerFieldType::EMAIL_ADDRESS));
+ options->required_contact_data_pieces.push_back(MakeRequiredDataPiece(
+ autofill::ServerFieldType::PHONE_HOME_WHOLE_NUMBER));
+ options->contact_details_name = "selected_profile";
+
+ testing::InSequence seq;
+ EXPECT_CALL(mock_execution_delegate_,
+ NotifyUserDataChange(UserData::FieldChange::ALL));
+ ui_controller_->SetCollectUserDataOptions(options.get());
+ EXPECT_CALL(mock_observer_, OnUserActionsChanged(UnorderedElementsAre(
+ Property(&UserAction::enabled, Eq(false)))));
+ ui_controller_->OnUserDataChanged(user_data_, UserData::FieldChange::ALL);
+
+ EXPECT_CALL(mock_execution_delegate_,
+ NotifyUserDataChange(UserData::FieldChange::CONTACT_PROFILE));
+ autofill::AutofillProfile contact_profile;
+ contact_profile.SetRawInfo(autofill::ServerFieldType::EMAIL_ADDRESS,
+ u"joedoe@example.com");
+ contact_profile.SetRawInfo(autofill::ServerFieldType::NAME_FULL, u"Joe Doe");
+ contact_profile.SetRawInfo(autofill::ServerFieldType::PHONE_HOME_WHOLE_NUMBER,
+ u"+1 23 456 789 01");
+ ui_controller_->HandleContactInfoChange(
+ std::make_unique<autofill::AutofillProfile>(contact_profile), UNKNOWN);
+
+ EXPECT_CALL(mock_observer_, OnUserActionsChanged(UnorderedElementsAre(
+ Property(&UserAction::enabled, Eq(true)))));
+ ui_controller_->OnUserDataChanged(user_data_,
+ UserData::FieldChange::CONTACT_PROFILE);
+ EXPECT_THAT(
+ user_data_.selected_address("selected_profile")->Compare(contact_profile),
+ Eq(0));
+}
+
+TEST_F(UiControllerTest, UserDataFormCreditCard) {
+ testing::InSequence seq;
+
+ auto options = std::make_unique<FakeCollectUserDataOptions>();
+ options->request_payment_method = true;
+ options->billing_address_name = "billing_address";
+
+ EXPECT_CALL(mock_execution_delegate_,
+ NotifyUserDataChange(UserData::FieldChange::ALL));
+ ui_controller_->SetCollectUserDataOptions(options.get());
+ EXPECT_CALL(mock_observer_, OnUserActionsChanged(UnorderedElementsAre(
+ Property(&UserAction::enabled, Eq(false)))));
+ ui_controller_->OnUserDataChanged(user_data_, UserData::FieldChange::ALL);
+
+ // Credit card with valid billing address is ok.
+ auto billing_address = std::make_unique<autofill::AutofillProfile>(
+ base::GenerateGUID(), "https://www.example.com");
+ autofill::test::SetProfileInfo(billing_address.get(), "Marion", "Mitchell",
+ "Morrison", "marion@me.xyz", "Fox",
+ "123 Zoo St.", "unit 5", "Hollywood", "CA",
+ "91601", "US", "16505678910");
+ auto credit_card = std::make_unique<autofill::CreditCard>(
+ base::GenerateGUID(), "https://www.example.com");
+ autofill::test::SetCreditCardInfo(credit_card.get(), "Marion Mitchell",
+ "4111 1111 1111 1111", "01", "2020",
+ billing_address->guid());
+ EXPECT_CALL(mock_execution_delegate_,
+ NotifyUserDataChange(UserData::FieldChange::BILLING_ADDRESS));
+ EXPECT_CALL(mock_execution_delegate_,
+ NotifyUserDataChange(UserData::FieldChange::CARD));
+ ui_controller_->HandleCreditCardChange(
+ std::make_unique<autofill::CreditCard>(*credit_card),
+ std::make_unique<autofill::AutofillProfile>(*billing_address), UNKNOWN);
+
+ EXPECT_CALL(mock_observer_, OnUserActionsChanged(UnorderedElementsAre(
+ Property(&UserAction::enabled, Eq(true)))));
+ ui_controller_->OnUserDataChanged(user_data_, UserData::FieldChange::CARD);
+
+ EXPECT_THAT(user_data_.selected_card()->Compare(*credit_card), Eq(0));
+ EXPECT_THAT(
+ user_data_.selected_address("billing_address")->Compare(*billing_address),
+ Eq(0));
+
+ // Credit card without billing address is invalid.
+ credit_card->set_billing_address_id("");
+ EXPECT_CALL(mock_execution_delegate_,
+ NotifyUserDataChange(UserData::FieldChange::BILLING_ADDRESS));
+ EXPECT_CALL(mock_execution_delegate_,
+ NotifyUserDataChange(UserData::FieldChange::CARD));
+ ui_controller_->HandleCreditCardChange(
+ std::make_unique<autofill::CreditCard>(*credit_card),
+ /* billing_profile= */ nullptr, UNKNOWN);
+ EXPECT_CALL(mock_observer_, OnUserActionsChanged(UnorderedElementsAre(
+ Property(&UserAction::enabled, Eq(false)))));
+ ui_controller_->OnUserDataChanged(user_data_, UserData::FieldChange::CARD);
+
+ EXPECT_THAT(user_data_.selected_card()->Compare(*credit_card), Eq(0));
+ EXPECT_THAT(user_data_.selected_address("billing_address"), Eq(nullptr));
+}
+
+TEST_F(UiControllerTest, UserDataChangesByOutOfLoopWrite) {
+ auto options = std::make_unique<FakeCollectUserDataOptions>();
+ auto user_data = std::make_unique<UserData>();
+
+ options->required_contact_data_pieces.push_back(
+ MakeRequiredDataPiece(autofill::ServerFieldType::NAME_FULL));
+ options->required_contact_data_pieces.push_back(
+ MakeRequiredDataPiece(autofill::ServerFieldType::EMAIL_ADDRESS));
+ options->required_contact_data_pieces.push_back(MakeRequiredDataPiece(
+ autofill::ServerFieldType::PHONE_HOME_WHOLE_NUMBER));
+ options->contact_details_name = "selected_profile";
+
+ testing::InSequence sequence;
+ EXPECT_CALL(mock_execution_delegate_,
+ NotifyUserDataChange(UserData::FieldChange::ALL));
+ ui_controller_->SetCollectUserDataOptions(options.get());
+ EXPECT_CALL(mock_observer_, OnUserActionsChanged(UnorderedElementsAre(
+ Property(&UserAction::enabled, Eq(false)))));
+ ui_controller_->OnUserDataChanged(user_data_, UserData::FieldChange::ALL);
+
+ EXPECT_CALL(mock_execution_delegate_,
+ NotifyUserDataChange(UserData::FieldChange::CONTACT_PROFILE));
+ autofill::AutofillProfile contact_profile;
+ contact_profile.SetRawInfo(autofill::ServerFieldType::EMAIL_ADDRESS,
+ u"joedoe@example.com");
+ contact_profile.SetRawInfo(autofill::ServerFieldType::NAME_FULL, u"Joe Doe");
+ contact_profile.SetRawInfo(autofill::ServerFieldType::PHONE_HOME_WHOLE_NUMBER,
+ u"+1 23 456 789 01");
+ ui_controller_->HandleContactInfoChange(
+ std::make_unique<autofill::AutofillProfile>(contact_profile), UNKNOWN);
+
+ EXPECT_CALL(mock_observer_, OnUserActionsChanged(UnorderedElementsAre(
+ Property(&UserAction::enabled, Eq(true)))));
+ ui_controller_->OnUserDataChanged(user_data_, UserData::FieldChange::ALL);
+
+ EXPECT_THAT(
+ user_data_.selected_address("selected_profile")->Compare(contact_profile),
+ Eq(0));
+
+ EXPECT_CALL(mock_observer_, OnUserActionsChanged(UnorderedElementsAre(
+ Property(&UserAction::enabled, Eq(false)))));
+ // Can be called by a PDM update.
+ user_model_.SetSelectedAutofillProfile("selected_profile", nullptr,
+ &user_data_);
+ ui_controller_->OnUserDataChanged(user_data_,
+ UserData::FieldChange::CONTACT_PROFILE);
+}
+
+TEST_F(UiControllerTest, UserDataFormReloadFromContactChange) {
+ auto options = std::make_unique<FakeCollectUserDataOptions>();
+ base::MockCallback<base::OnceCallback<void(UserData*)>> reload_callback;
+ options->reload_data_callback = reload_callback.Get();
+ base::MockCallback<
+ base::RepeatingCallback<void(UserDataEventField, UserDataEventType)>>
+ change_callback;
+ options->selected_user_data_changed_callback = change_callback.Get();
+ options->use_gms_core_edit_dialogs = true;
+
+ ui_controller_->SetCollectUserDataOptions(options.get());
+
+ EXPECT_CALL(change_callback, Run(UserDataEventField::CONTACT_EVENT,
+ UserDataEventType::ENTRY_CREATED));
+ EXPECT_CALL(reload_callback, Run);
+ ui_controller_->HandleContactInfoChange(nullptr,
+ UserDataEventType::ENTRY_CREATED);
+}
+
+TEST_F(UiControllerTest, UserDataFormReloadFromPhoneNumberChange) {
+ auto options = std::make_unique<FakeCollectUserDataOptions>();
+ base::MockCallback<base::OnceCallback<void(UserData*)>> reload_callback;
+ options->reload_data_callback = reload_callback.Get();
+ base::MockCallback<
+ base::RepeatingCallback<void(UserDataEventField, UserDataEventType)>>
+ change_callback;
+ options->selected_user_data_changed_callback = change_callback.Get();
+ options->use_gms_core_edit_dialogs = true;
+
+ ui_controller_->SetCollectUserDataOptions(options.get());
+
+ EXPECT_CALL(change_callback, Run(UserDataEventField::CONTACT_EVENT,
+ UserDataEventType::ENTRY_CREATED));
+ EXPECT_CALL(reload_callback, Run);
+ ui_controller_->HandlePhoneNumberChange(nullptr,
+ UserDataEventType::ENTRY_CREATED);
+}
+
+TEST_F(UiControllerTest, UserDataFormReloadFromShippingAddressChange) {
+ auto options = std::make_unique<FakeCollectUserDataOptions>();
+ base::MockCallback<base::OnceCallback<void(UserData*)>> reload_callback;
+ options->reload_data_callback = reload_callback.Get();
+ base::MockCallback<
+ base::RepeatingCallback<void(UserDataEventField, UserDataEventType)>>
+ change_callback;
+ options->selected_user_data_changed_callback = change_callback.Get();
+ options->use_gms_core_edit_dialogs = true;
+
+ ui_controller_->SetCollectUserDataOptions(options.get());
+
+ EXPECT_CALL(change_callback, Run(UserDataEventField::SHIPPING_EVENT,
+ UserDataEventType::ENTRY_CREATED));
+ EXPECT_CALL(reload_callback, Run);
+ ui_controller_->HandleShippingAddressChange(nullptr,
+ UserDataEventType::ENTRY_CREATED);
+}
+
+TEST_F(UiControllerTest, UserDataFormReloadFromCreditCardChange) {
+ auto options = std::make_unique<FakeCollectUserDataOptions>();
+ base::MockCallback<base::OnceCallback<void(UserData*)>> reload_callback;
+ options->reload_data_callback = reload_callback.Get();
+ base::MockCallback<
+ base::RepeatingCallback<void(UserDataEventField, UserDataEventType)>>
+ change_callback;
+ options->selected_user_data_changed_callback = change_callback.Get();
+ options->use_gms_core_edit_dialogs = true;
+
+ ui_controller_->SetCollectUserDataOptions(options.get());
+
+ EXPECT_CALL(change_callback, Run(UserDataEventField::CREDIT_CARD_EVENT,
+ UserDataEventType::ENTRY_CREATED));
+ EXPECT_CALL(reload_callback, Run);
+ ui_controller_->HandleCreditCardChange(nullptr, nullptr,
+ UserDataEventType::ENTRY_CREATED);
+}
+
+TEST_F(UiControllerTest, SetTermsAndConditions) {
+ auto options = std::make_unique<FakeCollectUserDataOptions>();
+
+ options->accept_terms_and_conditions_text.assign("Accept T&C");
+ testing::InSequence seq;
+ EXPECT_CALL(mock_execution_delegate_,
+ NotifyUserDataChange(UserData::FieldChange::ALL));
+ ui_controller_->SetCollectUserDataOptions(options.get());
+ EXPECT_CALL(mock_observer_, OnUserActionsChanged(UnorderedElementsAre(
+ Property(&UserAction::enabled, Eq(false)))));
+ ui_controller_->OnUserDataChanged(user_data_, UserData::FieldChange::ALL);
+
+ EXPECT_CALL(
+ mock_execution_delegate_,
+ NotifyUserDataChange(UserData::FieldChange::TERMS_AND_CONDITIONS));
+ ui_controller_->SetTermsAndConditions(TermsAndConditionsState::ACCEPTED);
+ EXPECT_CALL(mock_observer_, OnUserActionsChanged(UnorderedElementsAre(
+ Property(&UserAction::enabled, Eq(true)))));
+ ui_controller_->OnUserDataChanged(
+ user_data_, UserData::FieldChange::TERMS_AND_CONDITIONS);
+
+ EXPECT_THAT(user_data_.terms_and_conditions_,
+ Eq(TermsAndConditionsState::ACCEPTED));
+}
+
+TEST_F(UiControllerTest, SetLoginOption) {
+ auto options = std::make_unique<FakeCollectUserDataOptions>();
+ options->request_login_choice = true;
+ LoginChoice login_choice;
+ login_choice.identifier = "guest";
+ options->login_choices.push_back(login_choice);
+
+ testing::InSequence seq;
+ EXPECT_CALL(mock_execution_delegate_,
+ NotifyUserDataChange(UserData::FieldChange::ALL));
+ ui_controller_->SetCollectUserDataOptions(options.get());
+ EXPECT_CALL(mock_observer_, OnUserActionsChanged(UnorderedElementsAre(
+ Property(&UserAction::enabled, Eq(false)))));
+ ui_controller_->OnUserDataChanged(user_data_, UserData::FieldChange::ALL);
+
+ EXPECT_CALL(mock_execution_delegate_,
+ NotifyUserDataChange(UserData::FieldChange::LOGIN_CHOICE));
+ ui_controller_->SetLoginOption("guest");
+ EXPECT_CALL(mock_observer_, OnUserActionsChanged(UnorderedElementsAre(
+ Property(&UserAction::enabled, Eq(true)))));
+ ui_controller_->OnUserDataChanged(user_data_,
+ UserData::FieldChange::LOGIN_CHOICE);
+
+ EXPECT_THAT(user_data_.selected_login_choice()->identifier, Eq("guest"));
+}
+
+TEST_F(UiControllerTest, SetShippingAddress) {
+ auto options = std::make_unique<FakeCollectUserDataOptions>();
+
+ options->request_shipping = true;
+ options->shipping_address_name = "shipping_address";
+ testing::InSequence seq;
+ EXPECT_CALL(mock_execution_delegate_,
+ NotifyUserDataChange(UserData::FieldChange::ALL));
+ ui_controller_->SetCollectUserDataOptions(options.get());
+ EXPECT_CALL(mock_observer_, OnUserActionsChanged(UnorderedElementsAre(
+ Property(&UserAction::enabled, Eq(false)))));
+ ui_controller_->OnUserDataChanged(user_data_, UserData::FieldChange::ALL);
+
+ auto shipping_address = std::make_unique<autofill::AutofillProfile>(
+ base::GenerateGUID(), "https://www.example.com");
+ autofill::test::SetProfileInfo(shipping_address.get(), "Marion", "Mitchell",
+ "Morrison", "marion@me.xyz", "Fox",
+ "123 Zoo St.", "unit 5", "Hollywood", "CA",
+ "91601", "US", "16505678910");
+ EXPECT_CALL(mock_execution_delegate_,
+ NotifyUserDataChange(UserData::FieldChange::SHIPPING_ADDRESS));
+ ui_controller_->HandleShippingAddressChange(
+ std::make_unique<autofill::AutofillProfile>(*shipping_address), UNKNOWN);
+
+ EXPECT_CALL(mock_observer_, OnUserActionsChanged(UnorderedElementsAre(
+ Property(&UserAction::enabled, Eq(true)))));
+ ui_controller_->OnUserDataChanged(user_data_, UserData::FieldChange::ALL);
+
+ EXPECT_THAT(user_data_.selected_address("shipping_address")
+ ->Compare(*shipping_address),
+ Eq(0));
+}
+
+TEST_F(UiControllerTest, SetAdditionalValues) {
+ auto options = std::make_unique<FakeCollectUserDataOptions>();
+ ValueProto value1;
+ value1.mutable_strings()->add_values("123456789");
+
+ ValueProto value2;
+ value2.mutable_strings()->add_values("");
+ ValueProto value3;
+ value3.mutable_strings()->add_values("");
+ user_data_.SetAdditionalValue("key1", value1);
+ user_data_.SetAdditionalValue("key2", value2);
+ user_data_.SetAdditionalValue("key3", value3);
+
+ ui_controller_->OnUserDataChanged(user_data_,
+ UserData::FieldChange::ADDITIONAL_VALUES);
+
+ testing::InSequence seq;
+ EXPECT_CALL(mock_execution_delegate_,
+ NotifyUserDataChange(UserData::FieldChange::ALL));
+ ui_controller_->SetCollectUserDataOptions(options.get());
+ EXPECT_CALL(mock_observer_, OnUserActionsChanged(UnorderedElementsAre(
+ Property(&UserAction::enabled, Eq(true)))));
+ ui_controller_->OnUserDataChanged(user_data_, UserData::FieldChange::ALL);
+
+ for (int i = 0; i < 2; ++i) {
+ EXPECT_CALL(mock_execution_delegate_,
+ NotifyUserDataChange(UserData::FieldChange::ADDITIONAL_VALUES));
+ }
+ ValueProto value4;
+ value4.mutable_strings()->add_values("value2");
+ ValueProto value5;
+ value5.mutable_strings()->add_values("value3");
+ ui_controller_->SetAdditionalValue("key2", value4);
+ ui_controller_->SetAdditionalValue("key3", value5);
+ EXPECT_EQ(*user_data_.GetAdditionalValue("key1"), value1);
+ EXPECT_EQ(*user_data_.GetAdditionalValue("key2"), value4);
+ EXPECT_EQ(*user_data_.GetAdditionalValue("key3"), value5);
+
+ ValueProto value6;
+ value6.mutable_strings()->add_values("someValue");
+ EXPECT_DCHECK_DEATH(ui_controller_->SetAdditionalValue("key4", value6));
+}
+
+TEST_F(UiControllerTest, EnableTts) {
+ EXPECT_CALL(mock_client_, IsSpokenFeedbackAccessibilityServiceEnabled())
+ .WillOnce(Return(false));
+ EXPECT_CALL(mock_observer_, OnTtsButtonVisibilityChanged(true));
+
+ TriggerContext trigger_context(
+ /* parameters = */ std::make_unique<ScriptParameters>(
+ base::flat_map<std::string, std::string>{{"ENABLE_TTS", "true"}}),
+ TriggerContext::Options());
+ ui_controller_->OnStart(trigger_context);
+
+ EXPECT_TRUE(ui_controller_->GetTtsButtonVisible());
+}
+
+TEST_F(UiControllerTest, DoNotEnableTtsWhenAccessibilityEnabled) {
+ EXPECT_CALL(mock_client_, IsSpokenFeedbackAccessibilityServiceEnabled())
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_observer_, OnTtsButtonVisibilityChanged(true)).Times(0);
+
+ TriggerContext trigger_context(
+ /* parameters = */ std::make_unique<ScriptParameters>(
+ base::flat_map<std::string, std::string>{{"ENABLE_TTS", "true"}}),
+ TriggerContext::Options());
+ ui_controller_->OnStart(trigger_context);
+
+ EXPECT_FALSE(ui_controller_->GetTtsButtonVisible());
+}
+
+TEST_F(UiControllerTest, TtsMessageIsSetCorrectlyAtStartup) {
+ ui_controller_->OnStart(trigger_context_);
+ EXPECT_EQ(ui_controller_->GetTtsMessage(),
+ ui_controller_->GetStatusMessage());
+ EXPECT_FALSE(ui_controller_->GetTtsMessage().empty());
+}
+
+TEST_F(UiControllerTest, TtsMessageIsSetCorrectly) {
+ // SetStatusMessage should override tts_message
+ ui_controller_->SetStatusMessage("message");
+ EXPECT_EQ(ui_controller_->GetTtsMessage(), "message");
+
+ ui_controller_->SetTtsMessage("tts_message");
+ EXPECT_EQ(ui_controller_->GetTtsMessage(), "tts_message");
+ EXPECT_EQ(ui_controller_->GetStatusMessage(), "message");
+}
+
+TEST_F(UiControllerTest, SetTtsMessageStopsAnyOngoingTts) {
+ EnableTtsForTest();
+ SetTtsButtonStateForTest(TtsButtonState::PLAYING);
+
+ EXPECT_CALL(*mock_tts_controller_, Stop());
+ EXPECT_CALL(mock_observer_, OnTtsButtonStateChanged(TtsButtonState::DEFAULT));
+ ui_controller_->SetTtsMessage("tts_message");
+ EXPECT_EQ(ui_controller_->GetTtsButtonState(), TtsButtonState::DEFAULT);
+}
+
+TEST_F(UiControllerTest, SetTtsMessageReEnablesTtsButtonWithNonStickyStateExp) {
+ EXPECT_CALL(mock_client_, IsSpokenFeedbackAccessibilityServiceEnabled())
+ .WillOnce(Return(false));
+
+ TriggerContext trigger_context(
+ /* parameters = */ std::make_unique<ScriptParameters>(
+ base::flat_map<std::string, std::string>{{"ENABLE_TTS", "true"}}),
+ TriggerContext::Options(
+ /* experiment_ids= */ "4624822", /* is_cct= */ false,
+ /* onboarding_shown= */ false, /* is_direct_action= */ false,
+ /* initial_url= */ "http://a.example.com/path",
+ /* is_in_chrome_triggered= */ false));
+ EXPECT_CALL(mock_execution_delegate_, GetTriggerContext())
+ .WillRepeatedly(Return(&trigger_context));
+ ui_controller_->OnStart(trigger_context);
+ SetTtsButtonStateForTest(TtsButtonState::DISABLED);
+
+ EXPECT_CALL(mock_observer_, OnTtsButtonStateChanged(TtsButtonState::DEFAULT));
+ ui_controller_->SetTtsMessage("tts_message");
+ EXPECT_EQ(ui_controller_->GetTtsButtonState(), TtsButtonState::DEFAULT);
+}
+
+TEST_F(UiControllerTest,
+ SetTtsMessageKeepsTtsButtonDisabledWithoutNonStickyStateExp) {
+ EXPECT_CALL(mock_client_, IsSpokenFeedbackAccessibilityServiceEnabled())
+ .WillOnce(Return(false));
+
+ TriggerContext trigger_context(
+ /* parameters = */ std::make_unique<ScriptParameters>(
+ base::flat_map<std::string, std::string>{{"ENABLE_TTS", "true"}}),
+ TriggerContext::Options());
+ EXPECT_CALL(mock_execution_delegate_, GetTriggerContext())
+ .WillRepeatedly(Return(&trigger_context));
+ ui_controller_->OnStart(trigger_context);
+ SetTtsButtonStateForTest(TtsButtonState::DISABLED);
+
+ EXPECT_CALL(mock_observer_, OnTtsButtonStateChanged(_)).Times(0);
+ ui_controller_->SetTtsMessage("tts_message");
+ EXPECT_EQ(ui_controller_->GetTtsButtonState(), TtsButtonState::DISABLED);
+}
+
+TEST_F(UiControllerTest, TappingTtsButtonInDefaultStateStartsPlayingTts) {
+ EnableTtsForTest();
+ SetTtsButtonStateForTest(TtsButtonState::DEFAULT);
+ ui_controller_->SetTtsMessage("tts_message");
+
+ EXPECT_CALL(*mock_tts_controller_, Speak("tts_message", kClientLocale));
+ ui_controller_->OnTtsButtonClicked();
+}
+
+TEST_F(UiControllerTest, TappingTtsButtonWhilePlayingDisablesTtsButton) {
+ EnableTtsForTest();
+ SetTtsButtonStateForTest(TtsButtonState::PLAYING);
+
+ EXPECT_CALL(mock_observer_,
+ OnTtsButtonStateChanged(TtsButtonState::DISABLED));
+ EXPECT_CALL(*mock_tts_controller_, Stop());
+ ui_controller_->OnTtsButtonClicked();
+ EXPECT_EQ(ui_controller_->GetTtsButtonState(), TtsButtonState::DISABLED);
+}
+
+TEST_F(UiControllerTest, TappingDisabledTtsButtonReEnablesItAndStartsTts) {
+ EnableTtsForTest();
+ SetTtsButtonStateForTest(TtsButtonState::DISABLED);
+ ui_controller_->SetTtsMessage("tts_message");
+
+ EXPECT_CALL(mock_observer_, OnTtsButtonStateChanged(TtsButtonState::DEFAULT));
+ EXPECT_CALL(*mock_tts_controller_, Speak("tts_message", kClientLocale));
+ ui_controller_->OnTtsButtonClicked();
+ EXPECT_EQ(ui_controller_->GetTtsButtonState(), TtsButtonState::DEFAULT);
+}
+
+TEST_F(UiControllerTest, MaybePlayTtsMessageDoesNotStartTtsIfTtsNotEnabled) {
+ // tts_enabled_ is false by default
+ ui_controller_->SetTtsMessage("tts_message");
+
+ EXPECT_CALL(*mock_tts_controller_, Speak("tts_message", kClientLocale))
+ .Times(0);
+ ui_controller_->MaybePlayTtsMessage();
+}
+
+TEST_F(UiControllerTest, MaybePlayTtsMessageStartsPlayingCorrectTtsMessage) {
+ EnableTtsForTest();
+ ui_controller_->SetStatusMessage("message");
+ ui_controller_->SetTtsMessage("tts_message");
+
+ EXPECT_CALL(*mock_tts_controller_, Speak("tts_message", kClientLocale));
+ ui_controller_->MaybePlayTtsMessage();
+
+ // Change display strings locale.
+ ClientSettingsProto client_settings_proto;
+ client_settings_proto.set_display_strings_locale("test-locale");
+ client_settings_.UpdateFromProto(client_settings_proto);
+ EXPECT_CALL(*mock_tts_controller_, Speak("tts_message", "test-locale"));
+ ui_controller_->MaybePlayTtsMessage();
+}
+
+TEST_F(UiControllerTest, OnTtsEventChangesTtsButtonStateCorrectly) {
+ EXPECT_EQ(ui_controller_->GetTtsButtonState(), TtsButtonState::DEFAULT);
+
+ EXPECT_CALL(mock_observer_, OnTtsButtonStateChanged(TtsButtonState::PLAYING));
+ ui_controller_->OnTtsEvent(AutofillAssistantTtsController::TTS_START);
+ EXPECT_EQ(ui_controller_->GetTtsButtonState(), TtsButtonState::PLAYING);
+
+ EXPECT_CALL(mock_observer_, OnTtsButtonStateChanged(TtsButtonState::DEFAULT));
+ ui_controller_->OnTtsEvent(AutofillAssistantTtsController::TTS_END);
+ EXPECT_EQ(ui_controller_->GetTtsButtonState(), TtsButtonState::DEFAULT);
+
+ EXPECT_CALL(mock_observer_, OnTtsButtonStateChanged(TtsButtonState::DEFAULT));
+ ui_controller_->OnTtsEvent(AutofillAssistantTtsController::TTS_ERROR);
+ EXPECT_EQ(ui_controller_->GetTtsButtonState(), TtsButtonState::DEFAULT);
+}
+
+TEST_F(UiControllerTest, EnablingAccessibilityStopsTtsAndHidesTtsButton) {
+ EnableTtsForTest();
+ SetTtsButtonStateForTest(TtsButtonState::PLAYING);
+
+ EXPECT_CALL(*mock_tts_controller_, Stop());
+ EXPECT_CALL(mock_observer_, OnTtsButtonStateChanged(TtsButtonState::DEFAULT));
+ EXPECT_CALL(mock_observer_,
+ OnTtsButtonVisibilityChanged(/* visibility= */ false));
+ ui_controller_->OnSpokenFeedbackAccessibilityServiceChanged(
+ /* enabled= */ true);
+ EXPECT_FALSE(ui_controller_->GetTtsButtonVisible());
+ EXPECT_EQ(ui_controller_->GetTtsButtonState(), TtsButtonState::DEFAULT);
+}
+
+TEST_F(UiControllerTest, DisablingAccessibilityShouldNotEnableTts) {
+ // TTS is disabled by default.
+ EXPECT_FALSE(ui_controller_->GetTtsButtonVisible());
+
+ EXPECT_CALL(mock_observer_,
+ OnTtsButtonVisibilityChanged(/* visibility= */ false))
+ .Times(0);
+ ui_controller_->OnSpokenFeedbackAccessibilityServiceChanged(
+ /* enabled= */ false);
+ EXPECT_FALSE(ui_controller_->GetTtsButtonVisible());
+}
+
+TEST_F(UiControllerTest, HidingUiStopsAnyOngoingTts) {
+ EnableTtsForTest();
+ SetTtsButtonStateForTest(TtsButtonState::PLAYING);
+
+ EXPECT_CALL(*mock_tts_controller_, Stop());
+ EXPECT_CALL(mock_observer_, OnTtsButtonStateChanged(TtsButtonState::DEFAULT));
+ ui_controller_->OnUiShownChanged(/* shown= */ false);
+ EXPECT_EQ(ui_controller_->GetTtsButtonState(), TtsButtonState::DEFAULT);
+}
+
+TEST_F(UiControllerTest, ExpandOrCollapseBottomSheet) {
+ {
+ testing::InSequence seq;
+ EXPECT_CALL(mock_observer_, OnCollapseBottomSheet());
+ EXPECT_CALL(mock_observer_, OnExpandBottomSheet());
+ }
+ ui_controller_->CollapseBottomSheet();
+ ui_controller_->ExpandBottomSheet();
+}
+
+TEST_F(UiControllerTest, ShouldPromptActionExpandSheet) {
+ // Expect this to be true initially.
+ EXPECT_TRUE(ui_controller_->ShouldPromptActionExpandSheet());
+
+ ui_controller_->SetExpandSheetForPromptAction(false);
+ EXPECT_FALSE(ui_controller_->ShouldPromptActionExpandSheet());
+
+ ui_controller_->SetExpandSheetForPromptAction(true);
+ EXPECT_TRUE(ui_controller_->ShouldPromptActionExpandSheet());
+}
+
+TEST_F(UiControllerTest, SetGenericUi) {
+ {
+ testing::InSequence seq;
+ EXPECT_CALL(mock_observer_, OnGenericUserInterfaceChanged(NotNull()));
+ EXPECT_CALL(mock_observer_, OnGenericUserInterfaceChanged(nullptr));
+ }
+ ui_controller_->SetGenericUi(
+ std::make_unique<GenericUserInterfaceProto>(GenericUserInterfaceProto()),
+ base::DoNothing(), base::DoNothing());
+ ui_controller_->ClearGenericUi();
+}
+
+TEST_F(UiControllerTest, OnShowFirstMessageShowsDefaultInitialStatusMessage) {
+ EXPECT_CALL(mock_observer_,
+ OnStatusMessageChanged(l10n_util::GetStringFUTF8(
+ IDS_AUTOFILL_ASSISTANT_LOADING, u"www.example.com")));
+ ui_controller_->OnStart(trigger_context_);
+}
+
+TEST_F(UiControllerTest, NotifyObserversOfInitialStatusMessageAndProgressBar) {
+ ShowProgressBarProto::StepProgressBarConfiguration progress_bar_configuration;
+ progress_bar_configuration.add_annotated_step_icons()
+ ->mutable_icon()
+ ->set_icon(DrawableProto::PROGRESSBAR_DEFAULT_INITIAL_STEP);
+ progress_bar_configuration.add_annotated_step_icons()
+ ->mutable_icon()
+ ->set_icon(DrawableProto::PROGRESSBAR_DEFAULT_DATA_COLLECTION);
+ progress_bar_configuration.add_annotated_step_icons()
+ ->mutable_icon()
+ ->set_icon(DrawableProto::PROGRESSBAR_DEFAULT_PAYMENT);
+ progress_bar_configuration.add_annotated_step_icons()
+ ->mutable_icon()
+ ->set_icon(DrawableProto::PROGRESSBAR_DEFAULT_FINAL_STEP);
+
+ // When setting UI state of the controller before calling |Start|, observers
+ // will be notified immediately after |Start|.
+ ui_controller_->SetStatusMessage("startup message");
+ ui_controller_->SetStepProgressBarConfiguration(progress_bar_configuration);
+ ui_controller_->SetProgressActiveStep(1);
+
+ EXPECT_CALL(mock_observer_, OnStepProgressBarConfigurationChanged(
+ progress_bar_configuration));
+ EXPECT_CALL(mock_observer_, OnProgressActiveStepChanged(1));
+ EXPECT_CALL(mock_observer_, OnStatusMessageChanged("startup message"));
+ ui_controller_->OnStart(trigger_context_);
+}
+
+TEST_F(UiControllerTest, Details) {
+ // The current controller details, as notified to the observers.
+ std::vector<Details> observed_details;
+
+ ON_CALL(mock_observer_, OnDetailsChanged(_))
+ .WillByDefault(
+ Invoke([&observed_details](const std::vector<Details>& details) {
+ observed_details = details;
+ }));
+
+ // Details are initially empty.
+ EXPECT_THAT(ui_controller_->GetDetails(), IsEmpty());
+
+ // Set 2 details.
+ ui_controller_->SetDetails(std::make_unique<Details>(), base::TimeDelta());
+ EXPECT_THAT(ui_controller_->GetDetails(), SizeIs(1));
+ EXPECT_THAT(observed_details, SizeIs(1));
+
+ // Set 2 details in 1s (which directly clears the current details).
+ ui_controller_->SetDetails(std::make_unique<Details>(),
+ base::Milliseconds(1000));
+ EXPECT_THAT(ui_controller_->GetDetails(), IsEmpty());
+ EXPECT_THAT(observed_details, IsEmpty());
+
+ task_environment_.FastForwardBy(base::Milliseconds(1000));
+ EXPECT_THAT(ui_controller_->GetDetails(), SizeIs(1));
+ EXPECT_THAT(observed_details, SizeIs(1));
+
+ ui_controller_->AppendDetails(std::make_unique<Details>(),
+ /* delay= */ base::TimeDelta());
+ EXPECT_THAT(ui_controller_->GetDetails(), SizeIs(2));
+ EXPECT_THAT(observed_details, SizeIs(2));
+
+ // Delay the appending of the details.
+ ui_controller_->AppendDetails(std::make_unique<Details>(),
+ /* delay= */ base::Milliseconds(1000));
+ EXPECT_THAT(ui_controller_->GetDetails(), SizeIs(2));
+ EXPECT_THAT(observed_details, SizeIs(2));
+
+ task_environment_.FastForwardBy(base::Milliseconds(999));
+ EXPECT_THAT(ui_controller_->GetDetails(), SizeIs(2));
+ EXPECT_THAT(observed_details, SizeIs(2));
+
+ task_environment_.FastForwardBy(base::Milliseconds(1));
+ EXPECT_THAT(ui_controller_->GetDetails(), SizeIs(3));
+ EXPECT_THAT(observed_details, SizeIs(3));
+
+ // Setting the details clears the timers.
+ ui_controller_->AppendDetails(std::make_unique<Details>(),
+ /* delay= */ base::Milliseconds(1000));
+ ui_controller_->SetDetails(nullptr, base::TimeDelta());
+ EXPECT_THAT(ui_controller_->GetDetails(), IsEmpty());
+ EXPECT_THAT(observed_details, IsEmpty());
+
+ task_environment_.FastForwardBy(base::Milliseconds(2000));
+ EXPECT_THAT(ui_controller_->GetDetails(), IsEmpty());
+ EXPECT_THAT(observed_details, IsEmpty());
+}
+
+TEST_F(UiControllerTest, OnScriptErrorWillAppendVanishingFeedbackChip) {
+ // A script error should show the feedback chip.
+ EXPECT_CALL(mock_observer_, OnUserActionsChanged(SizeIs(1)));
+ ui_controller_->OnError("Error", Metrics::DropOutReason::NAVIGATION);
+ ui_controller_->OnStop();
+
+ // The chip should vanish once clicked.
+ EXPECT_CALL(mock_observer_, OnUserActionsChanged(SizeIs(0)));
+ EXPECT_CALL(mock_execution_delegate_, ShutdownIfNecessary());
+ ui_controller_->PerformUserAction(0);
+}
+
+// The chip should be hidden if and only if the keyboard is visible and the
+// focus is on a bottom sheet input text.
+TEST_F(UiControllerTest, UpdateChipVisibility) {
+ InSequence seq;
+
+ UserAction user_action(ChipProto(), true, std::string());
+ EXPECT_CALL(mock_observer_,
+ OnUserActionsChanged(UnorderedElementsAre(Property(
+ &UserAction::chip, Field(&Chip::visible, Eq(true))))));
+ auto user_actions = std::make_unique<std::vector<UserAction>>();
+ user_actions->emplace_back(std::move(user_action));
+ ui_controller_->SetUserActions(std::move(user_actions));
+
+ EXPECT_CALL(mock_observer_, OnUserActionsChanged(_)).Times(0);
+ ui_controller_->OnKeyboardVisibilityChanged(true);
+
+ EXPECT_CALL(mock_observer_,
+ OnUserActionsChanged(UnorderedElementsAre(Property(
+ &UserAction::chip, Field(&Chip::visible, Eq(false))))));
+ ui_controller_->OnInputTextFocusChanged(true);
+
+ EXPECT_CALL(mock_observer_,
+ OnUserActionsChanged(UnorderedElementsAre(Property(
+ &UserAction::chip, Field(&Chip::visible, Eq(true))))));
+ ui_controller_->OnKeyboardVisibilityChanged(false);
+
+ EXPECT_CALL(mock_observer_, OnUserActionsChanged(_)).Times(0);
+ ui_controller_->OnInputTextFocusChanged(false);
+}
+
+TEST_F(UiControllerTest, UpdateUserActionsOnUserDataChanged) {
+ // Note that the UiController ignores both of the arguments of the
+ // OnUserDataChanged notification.
+
+ auto actions = std::make_unique<std::vector<UserAction>>();
+ actions->push_back(MakeUserAction("Continue"));
+ actions->push_back(MakeUserAction("Cancel"));
+ EXPECT_CALL(mock_observer_, OnUserActionsChanged(SizeIs(2)));
+ ui_controller_->SetUserActions(std::move(actions));
+
+ // If no CollectUserDataOptions are specified, the user actions are cleared.
+ EXPECT_CALL(mock_observer_, OnUserActionsChanged(SizeIs(0)));
+ ui_controller_->OnUserDataChanged(user_data_, UserData::FieldChange::ALL);
+}
+
+TEST_F(UiControllerTest, OnExecuteScriptSetMessageAndClearUserActions) {
+ ui_controller_->SetStatusMessage("initial message");
+ EXPECT_EQ(ui_controller_->GetStatusMessage(), "initial message");
+
+ EXPECT_CALL(mock_observer_, OnStatusMessageChanged("script message"));
+ EXPECT_CALL(mock_observer_, OnUserActionsChanged(SizeIs(0)));
+ ui_controller_->OnExecuteScript("script message");
+ EXPECT_EQ(ui_controller_->GetStatusMessage(), "script message");
+
+ // If the message is empty, the status message is not updated.
+ EXPECT_CALL(mock_observer_, OnStatusMessageChanged(_)).Times(0);
+ EXPECT_CALL(mock_observer_, OnUserActionsChanged(SizeIs(0)));
+ ui_controller_->OnExecuteScript("");
+ // The message should still be the last one set before this call.
+ EXPECT_EQ(ui_controller_->GetStatusMessage(), "script message");
+}
+
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/ui_delegate.h b/chromium/components/autofill_assistant/browser/ui_delegate.h
index cba3896c7e9..51985c7719a 100644
--- a/chromium/components/autofill_assistant/browser/ui_delegate.h
+++ b/chromium/components/autofill_assistant/browser/ui_delegate.h
@@ -22,7 +22,7 @@
#include "third_party/abseil-cpp/absl/types/optional.h"
namespace autofill_assistant {
-class ControllerObserver;
+class UiControllerObserver;
class Details;
class InfoBox;
class BasicInteractions;
@@ -30,24 +30,8 @@ class BasicInteractions;
// UI delegate called for script executions.
class UiDelegate {
public:
- // Colors of the overlay. Empty string to use the default.
- struct OverlayColors {
- // Overlay background color.
- std::string background;
-
- // Color of the border around the highlighted portions of the overlay.
- std::string highlight_border;
- };
-
virtual ~UiDelegate() = default;
- // Returns the current state of the controller.
- virtual AutofillAssistantState GetState() const = 0;
-
- // Returns a string describing the current execution context. This is useful
- // when analyzing feedback forms and for debugging in general.
- virtual std::string GetDebugContext() = 0;
-
// Returns the current status message.
virtual std::string GetStatusMessage() const = 0;
@@ -92,32 +76,31 @@ class UiDelegate {
// options describing the request.
virtual const CollectUserDataOptions* GetCollectUserDataOptions() const = 0;
- // If the controller is waiting for user data, this field contains a non-null
- // object describing the currently selected data.
- virtual const UserData* GetUserData() const = 0;
-
- // Sets shipping address, in response to the current collect user data
- // options.
- virtual void SetShippingAddress(
+ // Handles a change in shipping address, in response to the current collect
+ // user data options.
+ virtual void HandleShippingAddressChange(
std::unique_ptr<autofill::AutofillProfile> address,
UserDataEventType event_type) = 0;
- // Sets contact info, in response to the current collect user data options.
- virtual void SetContactInfo(
+ // Handles a change in contact info, in response to the current collect user
+ // data options.
+ virtual void HandleContactInfoChange(
std::unique_ptr<autofill::AutofillProfile> profile,
UserDataEventType event_type) = 0;
- // Sets credit card and billing profile, in response to the current collect
+ // Handles a change in the phone number, in response to the current collect
// user data options.
- virtual void SetCreditCard(
+ virtual void HandlePhoneNumberChange(
+ std::unique_ptr<autofill::AutofillProfile> profile,
+ UserDataEventType event_type) = 0;
+
+ // Handles a change in credit card and billing profile, in response to the
+ // current collect user data options.
+ virtual void HandleCreditCardChange(
std::unique_ptr<autofill::CreditCard> card,
std::unique_ptr<autofill::AutofillProfile> billing_profile,
UserDataEventType event_type) = 0;
- // Reload the user data for the collect user data action.
- virtual void ReloadUserData(UserDataEventField event_field,
- UserDataEventType event_type) = 0;
-
// Sets the state of the third party terms & conditions, pertaining to the
// current collect user data options.
virtual void SetTermsAndConditions(
@@ -137,55 +120,10 @@ class UiDelegate {
// Called when the user clicks the TTS button.
virtual void OnTtsButtonClicked() = 0;
- // Sets the start date of the date/time range.
- virtual void SetDateTimeRangeStartDate(
- const absl::optional<DateProto>& date) = 0;
-
- // Sets the start timeslot of the date/time range.
- virtual void SetDateTimeRangeStartTimeSlot(
- const absl::optional<int>& timeslot_index) = 0;
-
- // Sets the end date of the date/time range.
- virtual void SetDateTimeRangeEndDate(
- const absl::optional<DateProto>& date) = 0;
-
- // Sets the end timeslot of the date/time range.
- virtual void SetDateTimeRangeEndTimeSlot(
- const absl::optional<int>& timeslot_index) = 0;
-
// Sets an additional value.
virtual void SetAdditionalValue(const std::string& client_memory_key,
const ValueProto& value) = 0;
- // Adds the rectangles that correspond to the current touchable area to
- // the given vector.
- //
- // At the end of this call, |rectangles| contains one element per
- // configured rectangles, though these can correspond to empty rectangles.
- // Coordinates absolute CSS coordinates.
- //
- // Note that the vector is not cleared before rectangles are added.
- virtual void GetTouchableArea(std::vector<RectF>* rectangles) const = 0;
- virtual void GetRestrictedArea(std::vector<RectF>* rectangles) const = 0;
-
- // Returns the current size of the visual viewport. May be empty if
- // unknown.
- //
- // The rectangle is expressed in absolute CSS coordinates.
- virtual void GetVisualViewport(RectF* viewport) const = 0;
-
- // Reports a fatal error to Autofill Assistant, which should then stop.
- virtual void OnFatalError(const std::string& error_message,
- bool show_feedback_chip,
- Metrics::DropOutReason reason) = 0;
-
- // Reports that Autofill Assistant should be Stopped.
- virtual void OnStop(const std::string& message,
- const std::string& button_label) = 0;
-
- // Returns whether the viewport should be resized.
- virtual ViewportMode GetViewportMode() = 0;
-
// Peek mode state and whether it was changed automatically last time.
virtual ConfigureBottomSheetProto::PeekMode GetPeekMode() = 0;
@@ -195,18 +133,6 @@ class UiDelegate {
// Sets the state of the bottom sheet.
virtual void SetBottomSheetState(BottomSheetState state) = 0;
- // Gets whether the tab associated with this controller is currently selected.
- virtual bool IsTabSelected() = 0;
-
- // Sets whether the tab associated with this controller is currently selected.
- virtual void SetTabSelected(bool selected) = 0;
-
- // Fills in the overlay colors.
- virtual void GetOverlayColors(OverlayColors* colors) const = 0;
-
- // Gets the current Client Settings
- virtual const ClientSettings& GetClientSettings() const = 0;
-
// Returns the current form. May be null if there is no form to show.
virtual const FormProto* GetForm() const = 0;
@@ -223,22 +149,16 @@ class UiDelegate {
int choice_index,
bool selected) = 0;
- // Sets whether a UI is shown.
- virtual void SetUiShown(bool shown) = 0;
-
// Register an observer. Observers get told about changes to the
- // controller.
- virtual void AddObserver(ControllerObserver* observer) = 0;
+ // ui controller.
+ virtual void AddObserver(UiControllerObserver* observer) = 0;
// Remove a previously registered observer.
- virtual void RemoveObserver(const ControllerObserver* observer) = 0;
+ virtual void RemoveObserver(const UiControllerObserver* observer) = 0;
// Dispatches an event to the event handler.
virtual void DispatchEvent(const EventHandler::EventKey& key) = 0;
- // Returns the user model.
- virtual UserModel* GetUserModel() = 0;
-
// Returns the event handler.
virtual EventHandler* GetEventHandler() = 0;
@@ -255,20 +175,6 @@ class UiDelegate {
virtual const GenericUserInterfaceProto* GetPersistentGenericUiProto()
const = 0;
- // Whether the overlay should be determined based on AA state or always
- // hidden.
- virtual bool ShouldShowOverlay() const = 0;
-
- // Whether the keyboard should currently be suppressed.
- virtual bool ShouldSuppressKeyboard() const = 0;
-
- // Set the keyboard suppression for all frames for the current WebContent's
- // main page.
- virtual void SuppressKeyboard(bool suppress) = 0;
-
- // Notifies the UI delegate that it should shut down.
- virtual void ShutdownIfNecessary() = 0;
-
// Called when the visibility of the keyboard has changed.
virtual void OnKeyboardVisibilityChanged(bool visible) = 0;
diff --git a/chromium/components/autofill_assistant/browser/user_data.cc b/chromium/components/autofill_assistant/browser/user_data.cc
index 124b495024a..630637f6ecf 100644
--- a/chromium/components/autofill_assistant/browser/user_data.cc
+++ b/chromium/components/autofill_assistant/browser/user_data.cc
@@ -45,6 +45,11 @@ Contact::Contact(std::unique_ptr<autofill::AutofillProfile> _profile)
: profile(std::move(_profile)) {}
Contact::~Contact() = default;
+PhoneNumber::PhoneNumber() = default;
+PhoneNumber::PhoneNumber(std::unique_ptr<autofill::AutofillProfile> _profile)
+ : profile(std::move(_profile)) {}
+PhoneNumber::~PhoneNumber() = default;
+
Address::Address() = default;
Address::Address(std::unique_ptr<autofill::AutofillProfile> _profile)
: profile(std::move(_profile)) {}
@@ -75,6 +80,10 @@ const autofill::AutofillProfile* UserData::selected_address(
return it->second.get();
}
+const autofill::AutofillProfile* UserData::selected_phone_number() const {
+ return selected_phone_number_.get();
+}
+
const autofill::CreditCard* UserData::selected_card() const {
return selected_card_.get();
}
@@ -108,4 +117,10 @@ std::string UserData::GetAllAddressKeyNames() const {
std::sort(entries.begin(), entries.end());
return base::JoinString(entries, ",");
}
+
+void UserData::SetSelectedPhoneNumber(
+ std::unique_ptr<autofill::AutofillProfile> profile) {
+ selected_phone_number_ = std::move(profile);
+}
+
} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/user_data.h b/chromium/components/autofill_assistant/browser/user_data.h
index c1cd1c23bb7..df84f7f14b6 100644
--- a/chromium/components/autofill_assistant/browser/user_data.h
+++ b/chromium/components/autofill_assistant/browser/user_data.h
@@ -124,6 +124,17 @@ struct Contact {
std::unique_ptr<autofill::AutofillProfile> profile;
};
+// Struct for holding a phone number. This is a wrapper around AutofillProfile
+// to easily extend it for the purposes of Autofill Assistant.
+struct PhoneNumber {
+ PhoneNumber();
+ PhoneNumber(std::unique_ptr<autofill::AutofillProfile> profile);
+ ~PhoneNumber();
+
+ absl::optional<std::string> identifier;
+ std::unique_ptr<autofill::AutofillProfile> profile;
+};
+
// Struct for holding an address. This is a wrapper around AutofillProfile to
// easily extend it for the purposes of Autofill Assistant.
struct Address {
@@ -182,25 +193,21 @@ class UserData {
NONE,
ALL,
CONTACT_PROFILE,
+ PHONE_NUMBER,
CARD,
SHIPPING_ADDRESS,
BILLING_ADDRESS,
LOGIN_CHOICE,
TERMS_AND_CONDITIONS,
- DATE_TIME_RANGE_START,
- DATE_TIME_RANGE_END,
ADDITIONAL_VALUES,
AVAILABLE_PROFILES,
AVAILABLE_PAYMENT_INSTRUMENTS,
};
TermsAndConditionsState terms_and_conditions_ = NOT_SELECTED;
- absl::optional<DateProto> date_time_range_start_date_;
- absl::optional<DateProto> date_time_range_end_date_;
- absl::optional<int> date_time_range_start_timeslot_;
- absl::optional<int> date_time_range_end_timeslot_;
std::vector<std::unique_ptr<Contact>> available_contacts_;
+ std::vector<std::unique_ptr<PhoneNumber>> available_phone_numbers_;
std::vector<std::unique_ptr<Address>> available_addresses_;
std::vector<std::unique_ptr<PaymentInstrument>>
available_payment_instruments_;
@@ -219,6 +226,9 @@ class UserData {
const autofill::AutofillProfile* selected_address(
const std::string& name) const;
+ // The selected phone number.
+ const autofill::AutofillProfile* selected_phone_number() const;
+
// The selected card.
const autofill::CreditCard* selected_card() const;
@@ -242,6 +252,9 @@ class UserData {
std::string GetAllAddressKeyNames() const;
+ void SetSelectedPhoneNumber(
+ std::unique_ptr<autofill::AutofillProfile> profile);
+
private:
friend class UserModel;
// The address key requested by the autofill action.
@@ -253,6 +266,9 @@ class UserData {
// Written by |UserModel| to ensure that it stays in sync.
std::unique_ptr<autofill::CreditCard> selected_card_;
+ // The selected phone number.
+ std::unique_ptr<autofill::AutofillProfile> selected_phone_number_;
+
// The selected login choice.
// Written by |UserModel| to ensure that it stays in sync.
std::unique_ptr<LoginChoice> selected_login_choice_;
@@ -272,10 +288,10 @@ struct CollectUserDataOptions {
bool request_payer_name = false;
bool request_payer_email = false;
bool request_payer_phone = false;
+ bool request_phone_number_separately = false;
bool request_shipping = false;
bool request_payment_method = false;
bool request_login_choice = false;
- bool request_date_time_range = false;
std::vector<AutofillContactField> contact_summary_fields;
int contact_summary_max_lines;
std::vector<AutofillContactField> contact_full_fields;
@@ -286,12 +302,14 @@ struct CollectUserDataOptions {
std::string credit_card_expired_text;
std::vector<RequiredDataPiece> required_contact_data_pieces;
+ std::vector<RequiredDataPiece> required_phone_number_data_pieces;
std::vector<RequiredDataPiece> required_shipping_address_data_pieces;
std::vector<RequiredDataPiece> required_credit_card_data_pieces;
std::vector<RequiredDataPiece> required_billing_address_data_pieces;
bool should_store_data_changes = false;
bool can_edit_contacts = true;
+ bool use_gms_core_edit_dialogs = false;
// If empty, terms and conditions should not be shown.
std::string accept_terms_and_conditions_text;
@@ -309,12 +327,12 @@ struct CollectUserDataOptions {
std::vector<LoginChoice> login_choices;
std::string default_email;
std::string contact_details_section_title;
+ std::string phone_number_section_title;
std::string login_section_title;
std::string shipping_address_section_title;
UserActionProto confirm_action;
std::vector<UserActionProto> additional_actions;
TermsAndConditionsState initial_terms_and_conditions = NOT_SELECTED;
- DateTimeRangeProto date_time_range;
std::vector<UserFormSectionProto> additional_prepended_sections;
std::vector<UserFormSectionProto> additional_appended_sections;
absl::optional<GenericUserInterfaceProto> generic_user_interface_prepended;
diff --git a/chromium/components/autofill_assistant/browser/user_data_util.cc b/chromium/components/autofill_assistant/browser/user_data_util.cc
index 210ceedcd9c..ffe230609bd 100644
--- a/chromium/components/autofill_assistant/browser/user_data_util.cc
+++ b/chromium/components/autofill_assistant/browser/user_data_util.cc
@@ -9,6 +9,7 @@
#include "base/callback.h"
#include "base/containers/flat_map.h"
#include "base/i18n/case_conversion.h"
+#include "base/no_destructor.h"
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/autofill_data_util.h"
#include "components/autofill/core/browser/geo/address_i18n.h"
@@ -144,19 +145,33 @@ std::vector<std::string> GetValidationErrors(
return errors;
}
+std::vector<std::string> GetProfileValidationErrors(
+ const autofill::AutofillProfile* profile,
+ const std::vector<RequiredDataPiece>& required_data_pieces) {
+ if (required_data_pieces.empty()) {
+ return std::vector<std::string>();
+ }
+
+ return GetValidationErrors(
+ profile
+ ? field_formatter::CreateAutofillMappings(*profile, kDefaultLocale)
+ : base::flat_map<field_formatter::Key, std::string>(),
+ required_data_pieces);
+}
+
// Helper function that compares instances of AutofillProfile by completeness
// in regards to the current options. Full profiles should be ordered before
// empty ones and fall back to compare the profile's last usage.
bool CompletenessCompareContacts(
- const CollectUserDataOptions& options,
+ const std::vector<RequiredDataPiece>& required_data_pieces,
const autofill::AutofillProfile& a,
const base::flat_map<field_formatter::Key, std::string>& data_a,
const autofill::AutofillProfile& b,
const base::flat_map<field_formatter::Key, std::string>& data_b) {
int incomplete_fields_a =
- GetValidationErrors(data_a, options.required_contact_data_pieces).size();
+ GetValidationErrors(data_a, required_data_pieces).size();
int incomplete_fields_b =
- GetValidationErrors(data_b, options.required_contact_data_pieces).size();
+ GetValidationErrors(data_b, required_data_pieces).size();
if (incomplete_fields_a != incomplete_fields_b) {
return incomplete_fields_a <= incomplete_fields_b;
}
@@ -281,20 +296,43 @@ bool EvaluateNotEmpty(
return it != mapping.end() && !it->second.empty();
}
+ClientStatus MoveAutofillValueRegexpToTextFilter(
+ const UserData* user_data,
+ SelectorProto::PropertyFilter* value) {
+ if (!value->has_autofill_value_regexp()) {
+ return OkClientStatus();
+ }
+ if (user_data == nullptr) {
+ return ClientStatus(PRECONDITION_FAILED);
+ }
+ const AutofillValueRegexp& autofill_value_regexp =
+ value->autofill_value_regexp();
+ TextFilter text_filter;
+ text_filter.set_case_sensitive(
+ autofill_value_regexp.value_expression_re2().case_sensitive());
+ std::string re2;
+ ClientStatus re2_status =
+ GetFormattedClientValue(autofill_value_regexp, *user_data, &re2);
+ text_filter.set_re2(re2);
+ // Assigning text_filter will clear autofill_value_regexp.
+ *value->mutable_text_filter() = text_filter;
+ return re2_status;
+}
+
} // namespace
std::vector<std::string> GetContactValidationErrors(
const autofill::AutofillProfile* profile,
const CollectUserDataOptions& collect_user_data_options) {
- if (collect_user_data_options.required_contact_data_pieces.empty()) {
- return std::vector<std::string>();
- }
+ return GetProfileValidationErrors(
+ profile, collect_user_data_options.required_contact_data_pieces);
+}
- return GetValidationErrors(
- profile
- ? field_formatter::CreateAutofillMappings(*profile, kDefaultLocale)
- : base::flat_map<field_formatter::Key, std::string>(),
- collect_user_data_options.required_contact_data_pieces);
+std::vector<std::string> GetPhoneNumberValidationErrors(
+ const autofill::AutofillProfile* profile,
+ const CollectUserDataOptions& collect_user_data_options) {
+ return GetProfileValidationErrors(
+ profile, collect_user_data_options.required_phone_number_data_pieces);
}
std::vector<int> SortContactsByCompleteness(
@@ -312,8 +350,32 @@ std::vector<int> SortContactsByCompleteness(
indices.begin(), indices.end(),
[&collect_user_data_options, &contacts, &mapped_contacts](int i, int j) {
return CompletenessCompareContacts(
- collect_user_data_options, *contacts[i]->profile,
- mapped_contacts[i], *contacts[j]->profile, mapped_contacts[j]);
+ collect_user_data_options.required_contact_data_pieces,
+ *contacts[i]->profile, mapped_contacts[i], *contacts[j]->profile,
+ mapped_contacts[j]);
+ });
+ return indices;
+}
+
+std::vector<int> SortPhoneNumbersByCompleteness(
+ const CollectUserDataOptions& collect_user_data_options,
+ const std::vector<std::unique_ptr<PhoneNumber>>& phone_numbers) {
+ std::vector<base::flat_map<field_formatter::Key, std::string>>
+ mapped_phone_numbers;
+ for (const auto& phone_number : phone_numbers) {
+ mapped_phone_numbers.push_back(field_formatter::CreateAutofillMappings(
+ *phone_number->profile, kDefaultLocale));
+ }
+ std::vector<int> indices(phone_numbers.size());
+ std::iota(std::begin(indices), std::end(indices), 0);
+ std::stable_sort(
+ indices.begin(), indices.end(),
+ [&collect_user_data_options, &phone_numbers, &mapped_phone_numbers](
+ int i, int j) {
+ return CompletenessCompareContacts(
+ collect_user_data_options.required_phone_number_data_pieces,
+ *phone_numbers[i]->profile, mapped_phone_numbers[i],
+ *phone_numbers[j]->profile, mapped_phone_numbers[j]);
});
return indices;
}
@@ -337,6 +399,17 @@ int GetDefaultContact(const CollectUserDataOptions& collect_user_data_options,
return sorted_indices[0];
}
+int GetDefaultPhoneNumber(
+ const CollectUserDataOptions& collect_user_data_options,
+ const std::vector<std::unique_ptr<PhoneNumber>>& phone_numbers) {
+ if (phone_numbers.empty()) {
+ return -1;
+ }
+ auto sorted_indices =
+ SortPhoneNumbersByCompleteness(collect_user_data_options, phone_numbers);
+ return sorted_indices[0];
+}
+
std::vector<std::string> GetShippingAddressValidationErrors(
const autofill::AutofillProfile* profile,
const CollectUserDataOptions& collect_user_data_options) {
@@ -347,10 +420,8 @@ std::vector<std::string> GetShippingAddressValidationErrors(
if (!collect_user_data_options.required_shipping_address_data_pieces
.empty()) {
- errors = GetValidationErrors(
- profile
- ? field_formatter::CreateAutofillMappings(*profile, kDefaultLocale)
- : base::flat_map<field_formatter::Key, std::string>(),
+ errors = GetProfileValidationErrors(
+ profile,
collect_user_data_options.required_shipping_address_data_pieces);
}
@@ -421,10 +492,8 @@ std::vector<std::string> GetPaymentInstrumentValidationErrors(
}
if (!collect_user_data_options.required_billing_address_data_pieces.empty()) {
- const auto& address_errors = GetValidationErrors(
- billing_address ? field_formatter::CreateAutofillMappings(
- *billing_address, kDefaultLocale)
- : base::flat_map<field_formatter::Key, std::string>(),
+ const auto& address_errors = GetProfileValidationErrors(
+ billing_address,
collect_user_data_options.required_billing_address_data_pieces);
errors.insert(errors.end(), address_errors.begin(), address_errors.end());
}
@@ -507,37 +576,6 @@ std::unique_ptr<autofill::AutofillProfile> MakeUniqueFromProfile(
return unique_profile;
}
-bool CompareContactDetails(
- const CollectUserDataOptions& collect_user_data_options,
- const autofill::AutofillProfile* a,
- const autofill::AutofillProfile* b) {
- std::vector<autofill::ServerFieldType> types;
- if (collect_user_data_options.request_payer_name) {
- types.emplace_back(autofill::NAME_FULL);
- types.emplace_back(autofill::NAME_FIRST);
- types.emplace_back(autofill::NAME_MIDDLE);
- types.emplace_back(autofill::NAME_LAST);
- }
- if (collect_user_data_options.request_payer_phone) {
- types.emplace_back(autofill::PHONE_HOME_WHOLE_NUMBER);
- }
- if (collect_user_data_options.request_payer_email) {
- types.emplace_back(autofill::EMAIL_ADDRESS);
- }
- if (types.empty()) {
- return a->guid() == b->guid();
- }
-
- for (auto type : types) {
- int comparison = a->GetRawInfo(type).compare(b->GetRawInfo(type));
- if (comparison != 0) {
- return false;
- }
- }
-
- return true;
-}
-
ClientStatus GetFormattedClientValue(const AutofillValue& autofill_value,
const UserData& user_data,
std::string* out_value) {
@@ -691,14 +729,12 @@ Metrics::UserDataSelectionState GetNewSelectionState(
}
int GetFieldBitArrayForAddress(const autofill::AutofillProfile* profile) {
- // If the profile is nullptr, we consider all fields as missing.
- if (!profile) {
- return 0;
- }
-
- auto mapping =
- field_formatter::CreateAutofillMappings(*profile, kDefaultLocale);
+ return GetFieldBitArrayForAddressAndPhoneNumber(profile, profile);
+}
+int GetFieldBitArrayForAddressAndPhoneNumber(
+ const autofill::AutofillProfile* profile,
+ const autofill::AutofillProfile* phone_number_profile) {
// Maps from the autofill field type to the respective position in the metrics
// bitarray.
static const base::NoDestructor<std::vector<std::pair<
@@ -712,12 +748,6 @@ int GetFieldBitArrayForAddress(const autofill::AutofillProfile* profile) {
Metrics::AutofillAssistantProfileFields::NAME_FULL},
{autofill::EMAIL_ADDRESS,
Metrics::AutofillAssistantProfileFields::EMAIL_ADDRESS},
- {autofill::PHONE_HOME_NUMBER,
- Metrics::AutofillAssistantProfileFields::PHONE_HOME_NUMBER},
- {autofill::PHONE_HOME_COUNTRY_CODE,
- Metrics::AutofillAssistantProfileFields::PHONE_HOME_COUNTRY_CODE},
- {autofill::PHONE_HOME_WHOLE_NUMBER,
- Metrics::AutofillAssistantProfileFields::PHONE_HOME_WHOLE_NUMBER},
{autofill::ADDRESS_HOME_COUNTRY,
Metrics::AutofillAssistantProfileFields::ADDRESS_HOME_COUNTRY},
{autofill::ADDRESS_HOME_STATE,
@@ -729,10 +759,37 @@ int GetFieldBitArrayForAddress(const autofill::AutofillProfile* profile) {
{autofill::ADDRESS_HOME_STREET_ADDRESS,
Metrics::AutofillAssistantProfileFields::ADDRESS_HOME_LINE1}});
+ // Maps from the phone-related autofill field types to the respective position
+ // in the metrics bitarray.
+ static const base::NoDestructor<std::vector<std::pair<
+ autofill::ServerFieldType, Metrics::AutofillAssistantProfileFields>>>
+ phone_number_fields_to_log(
+ {{autofill::PHONE_HOME_NUMBER,
+ Metrics::AutofillAssistantProfileFields::PHONE_HOME_NUMBER},
+ {autofill::PHONE_HOME_COUNTRY_CODE,
+ Metrics::AutofillAssistantProfileFields::PHONE_HOME_COUNTRY_CODE},
+ {autofill::PHONE_HOME_WHOLE_NUMBER,
+ Metrics::AutofillAssistantProfileFields::PHONE_HOME_WHOLE_NUMBER}});
+
int bit_array = 0;
- for (auto fields_pair : *fields_to_log) {
- if (EvaluateNotEmpty(mapping, fields_pair.first)) {
- bit_array |= fields_pair.second;
+ // Check the non-phone fields.
+ if (profile) {
+ auto mapping =
+ field_formatter::CreateAutofillMappings(*profile, kDefaultLocale);
+ for (auto fields_pair : *fields_to_log) {
+ if (EvaluateNotEmpty(mapping, fields_pair.first)) {
+ bit_array |= fields_pair.second;
+ }
+ }
+ }
+ // Check the phone fields.
+ if (phone_number_profile) {
+ auto mapping = field_formatter::CreateAutofillMappings(
+ *phone_number_profile, kDefaultLocale);
+ for (auto fields_pair : *phone_number_fields_to_log) {
+ if (EvaluateNotEmpty(mapping, fields_pair.first)) {
+ bit_array |= fields_pair.second;
+ }
}
}
return bit_array;
@@ -781,5 +838,38 @@ int GetFieldBitArrayForCreditCard(const autofill::CreditCard* card) {
return bit_array;
}
+ClientStatus ResolveSelectorUserData(SelectorProto* selector,
+ const UserData* user_data) {
+ for (auto& filter : *selector->mutable_filters()) {
+ switch (filter.filter_case()) {
+ case SelectorProto::Filter::kProperty: {
+ ClientStatus filter_status = MoveAutofillValueRegexpToTextFilter(
+ user_data, filter.mutable_property());
+ if (!filter_status.ok()) {
+ return filter_status;
+ }
+ break;
+ }
+ case SelectorProto::Filter::kInnerText:
+ case SelectorProto::Filter::kValue:
+ case SelectorProto::Filter::kPseudoElementContent:
+ case SelectorProto::Filter::kCssStyle:
+ case SelectorProto::Filter::kCssSelector:
+ case SelectorProto::Filter::kEnterFrame:
+ case SelectorProto::Filter::kPseudoType:
+ case SelectorProto::Filter::kBoundingBox:
+ case SelectorProto::Filter::kNthMatch:
+ case SelectorProto::Filter::kLabelled:
+ case SelectorProto::Filter::kMatchCssSelector:
+ case SelectorProto::Filter::kOnTop:
+ case SelectorProto::Filter::FILTER_NOT_SET:
+ break;
+ // Do not add default here. In case a new filter gets added (that may
+ // contain a RegexpFilter) we want this to fail at compilation here.
+ }
+ }
+ return OkClientStatus();
+}
+
} // namespace user_data
} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/user_data_util.h b/chromium/components/autofill_assistant/browser/user_data_util.h
index 4bd3fc87cdf..a539895874e 100644
--- a/chromium/components/autofill_assistant/browser/user_data_util.h
+++ b/chromium/components/autofill_assistant/browser/user_data_util.h
@@ -26,6 +26,11 @@ std::vector<std::string> GetContactValidationErrors(
const autofill::AutofillProfile* profile,
const CollectUserDataOptions& collect_user_data_options);
+// Validate the completeness of a phone number.
+std::vector<std::string> GetPhoneNumberValidationErrors(
+ const autofill::AutofillProfile* profile,
+ const CollectUserDataOptions& collect_user_data_options);
+
// Sorts the given contacts based on completeness, and returns a vector of
// indices in sorted order. Full contacts will be ordered before empty ones,
// and for equally complete contacts, this falls back to sorting based on last
@@ -34,11 +39,25 @@ std::vector<int> SortContactsByCompleteness(
const CollectUserDataOptions& collect_user_data_options,
const std::vector<std::unique_ptr<Contact>>& contacts);
+// Sorts the given phone numbers based on completeness, and returns a vector of
+// indices in sorted order. Full phone numbers will be ordered before empty
+// ones, and for equally complete phone numbers, this falls back to sorting
+// based on last used.
+std::vector<int> SortPhoneNumbersByCompleteness(
+ const CollectUserDataOptions& collect_user_data_options,
+ const std::vector<std::unique_ptr<PhoneNumber>>& phone_numbers);
+
// Get the default selection for the current list of contacts. Returns -1 if no
// default selection is possible.
int GetDefaultContact(const CollectUserDataOptions& collect_user_data_options,
const std::vector<std::unique_ptr<Contact>>& contacts);
+// Get the default selection for the current list of phone numbers. Returns -1
+// if no default selection is possible.
+int GetDefaultPhoneNumber(
+ const CollectUserDataOptions& collect_user_data_options,
+ const std::vector<std::unique_ptr<PhoneNumber>>& contacts);
+
// Validate the completeness of a shipping address.
std::vector<std::string> GetShippingAddressValidationErrors(
const autofill::AutofillProfile* profile,
@@ -80,14 +99,6 @@ int GetDefaultPaymentInstrument(
std::unique_ptr<autofill::AutofillProfile> MakeUniqueFromProfile(
const autofill::AutofillProfile& profile);
-// Compare contact fields only. This comparison checks a subset of
-// AutofillProfile::Compare. Falls back to comparing the GUIDs if nothing else
-// is to be compared.
-bool CompareContactDetails(
- const CollectUserDataOptions& collect_user_data_options,
- const autofill::AutofillProfile* a,
- const autofill::AutofillProfile* b);
-
// Get a formatted client value. The replacement is treated as strict,
// meaning a missing value will lead to a failed ClientStatus.
// This method returns:
@@ -147,12 +158,25 @@ Metrics::UserDataSelectionState GetNewSelectionState(
// missing).
int GetFieldBitArrayForAddress(const autofill::AutofillProfile* profile);
+// Returns the bit array describing which fields are present in |profile|, using
+// Metrics::AutofillAssistantProfileFields as columns.
+// Phone number fields are checked on |phone_number_profile| instead of
+// |profile|.
+int GetFieldBitArrayForAddressAndPhoneNumber(
+ const autofill::AutofillProfile* profile,
+ const autofill::AutofillProfile* phone_number_profile);
+
// Returns the bit array describing which fields are present in |card|, using
// Metrics::AutofillAssistantCreditCardFields as columns.
// If |card| is nullptr, returns zero (i.e. all fields are considered
// missing).
int GetFieldBitArrayForCreditCard(const autofill::CreditCard* card);
+// Resolves |selector|'s references to user data with the actual values.
+// Modifies |selector| in place.
+ClientStatus ResolveSelectorUserData(SelectorProto* selector,
+ const UserData* user_data);
+
} // namespace user_data
} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/user_data_util_unittest.cc b/chromium/components/autofill_assistant/browser/user_data_util_unittest.cc
index 2e91e067abd..7703e8cfcfd 100644
--- a/chromium/components/autofill_assistant/browser/user_data_util_unittest.cc
+++ b/chromium/components/autofill_assistant/browser/user_data_util_unittest.cc
@@ -21,6 +21,7 @@
#include "components/autofill_assistant/browser/client_status.h"
#include "components/autofill_assistant/browser/mock_website_login_manager.h"
#include "components/autofill_assistant/browser/service.pb.h"
+#include "components/autofill_assistant/browser/test_util.h"
#include "components/autofill_assistant/browser/user_data.h"
#include "components/autofill_assistant/browser/user_model.h"
#include "components/autofill_assistant/browser/value_util.h"
@@ -275,6 +276,67 @@ TEST(UserDataUtilTest, SortsCompleteAddressesByUseDate) {
EXPECT_THAT(sorted_indices, ElementsAre(1, 0));
}
+TEST(UserDataUtilTest, SortsPhoneNumbers) {
+ auto profile_complete = std::make_unique<autofill::AutofillProfile>();
+ autofill::test::SetProfileInfo(profile_complete.get(), "Adam", "", "West",
+ "adam.west@gmail.com", "", "", "", "", "", "",
+ "", "+1 23 456 789 01");
+
+ auto profile_incomplete = std::make_unique<autofill::AutofillProfile>();
+ profile_incomplete->SetRawInfo(
+ autofill::ServerFieldType::PHONE_HOME_COUNTRY_CODE, u"1");
+
+ // Specify contacts in reverse order to force sorting.
+ std::vector<std::unique_ptr<PhoneNumber>> phone_numbers;
+ phone_numbers.emplace_back(
+ std::make_unique<PhoneNumber>(std::move(profile_incomplete)));
+ phone_numbers.emplace_back(
+ std::make_unique<PhoneNumber>(std::move(profile_complete)));
+
+ CollectUserDataOptions options;
+ options.required_phone_number_data_pieces.push_back(MakeRequiredDataPiece(
+ autofill::ServerFieldType::PHONE_HOME_WHOLE_NUMBER));
+ options.required_phone_number_data_pieces.push_back(MakeRequiredDataPiece(
+ autofill::ServerFieldType::PHONE_HOME_COUNTRY_CODE));
+
+ std::vector<int> sorted_indices =
+ SortPhoneNumbersByCompleteness(options, phone_numbers);
+ EXPECT_THAT(sorted_indices, ElementsAre(1, 0));
+}
+
+TEST(UserDataUtilTest, GetDefaultPhoneNumberSelectionForEmptyList) {
+ std::vector<std::unique_ptr<PhoneNumber>> phone_numbers;
+ CollectUserDataOptions options;
+
+ EXPECT_THAT(GetDefaultPhoneNumber(options, phone_numbers), -1);
+}
+
+TEST(UserDataUtilTest, GetDefaultPhoneNumberSelection) {
+ auto profile_complete = std::make_unique<autofill::AutofillProfile>();
+ autofill::test::SetProfileInfo(profile_complete.get(), "Adam", "", "West",
+ "adam.west@gmail.com", "", "", "", "", "", "",
+ "", "+1 23 456 789 01");
+
+ auto profile_incomplete = std::make_unique<autofill::AutofillProfile>();
+ profile_incomplete->SetRawInfo(
+ autofill::ServerFieldType::PHONE_HOME_COUNTRY_CODE, u"1");
+
+ // Specify contacts in reverse order to force sorting.
+ std::vector<std::unique_ptr<PhoneNumber>> phone_numbers;
+ phone_numbers.emplace_back(
+ std::make_unique<PhoneNumber>(std::move(profile_incomplete)));
+ phone_numbers.emplace_back(
+ std::make_unique<PhoneNumber>(std::move(profile_complete)));
+
+ CollectUserDataOptions options;
+ options.required_phone_number_data_pieces.push_back(MakeRequiredDataPiece(
+ autofill::ServerFieldType::PHONE_HOME_WHOLE_NUMBER));
+ options.required_phone_number_data_pieces.push_back(MakeRequiredDataPiece(
+ autofill::ServerFieldType::PHONE_HOME_COUNTRY_CODE));
+
+ EXPECT_THAT(GetDefaultPhoneNumber(options, phone_numbers), 1);
+}
+
TEST(UserDataUtilTest, SortsAddressesByEditorCompleteness) {
// Adding email address and phone number to demonstrate that they are not
// checked for completeness.
@@ -571,116 +633,6 @@ TEST(UserDataUtilTest, GetDefaultSelectionForCompletePaymentInstruments) {
EXPECT_THAT(GetDefaultPaymentInstrument(options, payment_instruments), 1);
}
-TEST(UserDataUtilTest, CompareContactDetailsMatch) {
- autofill::AutofillProfile profile_a;
- autofill::test::SetProfileInfo(&profile_a, "Adam", "", "West",
- "adam.west@gmail.com", "", "", "", "", "", "",
- "", "+41");
-
- autofill::AutofillProfile profile_b;
- autofill::test::SetProfileInfo(&profile_b, "Adam", "", "West",
- "adam.west@gmail.com", "", "", "", "", "", "",
- "", "+41");
-
- CollectUserDataOptions options;
- options.request_payer_name = true;
- options.request_payer_email = true;
- options.request_payer_phone = true;
-
- EXPECT_TRUE(CompareContactDetails(options, &profile_a, &profile_b));
-}
-
-TEST(UserDataUtilTest, CompareContactDetailsMismatchForNoChecks) {
- autofill::AutofillProfile profile_a;
- autofill::test::SetProfileInfo(&profile_a, "Adam", "", "West",
- "adam.west@gmail.com", "", "", "", "", "", "",
- "", "+41");
-
- autofill::AutofillProfile profile_b;
- autofill::test::SetProfileInfo(&profile_b, "Adam", "", "West",
- "adam.west@gmail.com", "", "", "", "", "", "",
- "", "+41");
-
- CollectUserDataOptions options;
-
- EXPECT_FALSE(CompareContactDetails(options, &profile_a, &profile_b));
-}
-
-TEST(UserDataUtilTest, CompareContactDetailsMismatches) {
- autofill::AutofillProfile profile_truth;
- autofill::test::SetProfileInfo(&profile_truth, "Adam", "", "West",
- "adam.west@gmail.com", "", "", "", "", "", "",
- "", "+41");
-
- autofill::AutofillProfile profile_mismatching_name;
- autofill::test::SetProfileInfo(&profile_mismatching_name, "Berta", "", "West",
- "adam.west@gmail.com", "", "", "", "", "", "",
- "", "+41");
-
- autofill::AutofillProfile profile_mismatching_email;
- autofill::test::SetProfileInfo(&profile_mismatching_email, "Adam", "", "West",
- "berta.west@gmail.com", "", "", "", "", "", "",
- "", "+41");
-
- autofill::AutofillProfile profile_mismatching_phone;
- autofill::test::SetProfileInfo(&profile_mismatching_name, "Adam", "", "West",
- "adam.west@gmail.com", "", "", "", "", "", "",
- "", "+44");
-
- CollectUserDataOptions options;
- options.request_payer_name = true;
- options.request_payer_email = true;
- options.request_payer_phone = true;
-
- EXPECT_FALSE(CompareContactDetails(options, &profile_truth,
- &profile_mismatching_name));
- EXPECT_FALSE(CompareContactDetails(options, &profile_truth,
- &profile_mismatching_email));
- EXPECT_FALSE(CompareContactDetails(options, &profile_truth,
- &profile_mismatching_phone));
-}
-
-TEST(UserDataUtilTest, CompareContactDetailsMatchesForUnqueriedFields) {
- autofill::AutofillProfile profile_truth;
- autofill::test::SetProfileInfo(&profile_truth, "Adam", "", "West",
- "adam.west@gmail.com", "", "", "", "", "", "",
- "", "+41");
-
- autofill::AutofillProfile profile_mismatching_name;
- autofill::test::SetProfileInfo(&profile_mismatching_name, "Berta", "", "West",
- "adam.west@gmail.com", "", "", "", "", "", "",
- "", "+41");
-
- autofill::AutofillProfile profile_mismatching_email;
- autofill::test::SetProfileInfo(&profile_mismatching_email, "Adam", "", "West",
- "berta.west@gmail.com", "", "", "", "", "", "",
- "", "+41");
-
- autofill::AutofillProfile profile_mismatching_phone;
- autofill::test::SetProfileInfo(&profile_mismatching_phone, "Adam", "", "West",
- "adam.west@gmail.com", "", "", "", "", "", "",
- "", "+44");
-
- CollectUserDataOptions options_no_check_name;
- options_no_check_name.request_payer_email = true;
- options_no_check_name.request_payer_phone = true;
-
- CollectUserDataOptions options_no_check_email;
- options_no_check_email.request_payer_name = true;
- options_no_check_email.request_payer_phone = true;
-
- CollectUserDataOptions options_no_check_phone;
- options_no_check_phone.request_payer_name = true;
- options_no_check_phone.request_payer_email = true;
-
- EXPECT_TRUE(CompareContactDetails(options_no_check_name, &profile_truth,
- &profile_mismatching_name));
- EXPECT_TRUE(CompareContactDetails(options_no_check_email, &profile_truth,
- &profile_mismatching_email));
- EXPECT_TRUE(CompareContactDetails(options_no_check_phone, &profile_truth,
- &profile_mismatching_phone));
-}
-
TEST(UserDataUtilTest, ContactCompletenessNotRequired) {
CollectUserDataOptions not_required_options;
EXPECT_THAT(GetContactValidationErrors(nullptr, not_required_options),
@@ -764,6 +716,30 @@ TEST(UserDataUtilTest, ContactCompletenessRequirePhone) {
IsEmpty());
}
+TEST(UserDataUtilTest, CompletePhoneNumberNotRequired) {
+ CollectUserDataOptions not_required_options;
+ not_required_options.request_phone_number_separately = false;
+
+ EXPECT_THAT(GetPhoneNumberValidationErrors(nullptr, not_required_options),
+ IsEmpty());
+}
+
+TEST(UserDataUtilTest, CompletePhoneNumber) {
+ autofill::AutofillProfile phone_number;
+ CollectUserDataOptions options;
+ options.required_phone_number_data_pieces.push_back(MakeRequiredDataPiece(
+ autofill::ServerFieldType::PHONE_HOME_WHOLE_NUMBER));
+
+ EXPECT_THAT(GetPhoneNumberValidationErrors(nullptr, options),
+ ElementsAre("14"));
+ autofill::test::SetProfileInfo(&phone_number, /* first_name= */ "",
+ /* middle_name= */ "",
+ /* last_name= */ "", "", "", "", "", "", "",
+ "", "", "+41");
+ EXPECT_THAT(GetPhoneNumberValidationErrors(&phone_number, options),
+ IsEmpty());
+}
+
TEST(UserDataUtilTest, CompleteShippingAddressNotRequired) {
CollectUserDataOptions not_required_options;
not_required_options.request_shipping = false;
@@ -1468,6 +1444,22 @@ TEST_F(UserDataUtilTextValueTest, GetAddressFieldBitArray) {
Metrics::AutofillAssistantProfileFields::PHONE_HOME_COUNTRY_CODE |
Metrics::AutofillAssistantProfileFields::PHONE_HOME_WHOLE_NUMBER,
GetFieldBitArrayForAddress(&full_profile));
+
+ autofill::AutofillProfile contact_profile;
+ autofill::test::SetProfileInfo(&contact_profile, "Adam", "", "West", "", "",
+ "", "", "", "", "", "", "");
+ autofill::AutofillProfile number_profile;
+ autofill::test::SetProfileInfo(&number_profile, "", "", "", "", "", "", "",
+ "", "", "", "", "+1 23 456 789 01");
+ EXPECT_EQ(
+ Metrics::AutofillAssistantProfileFields::NAME_FIRST |
+ Metrics::AutofillAssistantProfileFields::NAME_LAST |
+ Metrics::AutofillAssistantProfileFields::NAME_FULL |
+ Metrics::AutofillAssistantProfileFields::PHONE_HOME_NUMBER |
+ Metrics::AutofillAssistantProfileFields::PHONE_HOME_COUNTRY_CODE |
+ Metrics::AutofillAssistantProfileFields::PHONE_HOME_WHOLE_NUMBER,
+ GetFieldBitArrayForAddressAndPhoneNumber(&contact_profile,
+ &number_profile));
}
TEST_F(UserDataUtilTextValueTest, GetCreditCardFieldBitArray) {
@@ -1513,6 +1505,75 @@ TEST_F(UserDataUtilTextValueTest, GetCreditCardFieldBitArray) {
GetFieldBitArrayForCreditCard(&masked));
}
+TEST_F(UserDataUtilTextValueTest, ResolveSelectorUserData) {
+ autofill::AutofillProfile contact(base::GenerateGUID(),
+ autofill::test::kEmptyOrigin);
+ autofill::test::SetProfileInfo(&contact, "Jo.h*n", /* middle name */ "",
+ "Doe", "", "", "", "", "", "", "", "", "");
+ user_model_.SetSelectedAutofillProfile(
+ "contact", std::make_unique<autofill::AutofillProfile>(contact),
+ &user_data_);
+
+ SelectorProto selector;
+ selector.add_filters()->set_css_selector("#test");
+
+ auto* filter = selector.add_filters();
+ auto* value = filter->mutable_property()->mutable_autofill_value_regexp();
+ value->mutable_profile()->set_identifier("contact");
+ auto* expression =
+ value->mutable_value_expression_re2()->mutable_value_expression();
+ expression->add_chunk()->set_text("My name is ");
+ expression->add_chunk()->set_key(
+ static_cast<int>(autofill::ServerFieldType::NAME_LAST));
+ expression->add_chunk()->set_text(", ");
+ expression->add_chunk()->set_key(
+ static_cast<int>(autofill::ServerFieldType::NAME_FIRST));
+ expression->add_chunk()->set_text(" ");
+ expression->add_chunk()->set_key(
+ static_cast<int>(autofill::ServerFieldType::NAME_LAST));
+
+ selector.add_filters()->mutable_enter_frame();
+ selector.add_filters()->mutable_nth_match()->set_index(0);
+ SelectorProto copy = selector;
+
+ ClientStatus status = ResolveSelectorUserData(&selector, &user_data_);
+
+ ASSERT_TRUE(status.ok());
+ ASSERT_EQ(selector.filters(1).property().text_filter().re2(),
+ "My name is Doe, Jo\\.h\\*n Doe");
+ ASSERT_EQ(selector.filters().size(), copy.filters().size());
+
+ // Other filters should remain unchanged
+ ASSERT_EQ(selector.filters(0), copy.filters(0));
+ ASSERT_EQ(selector.filters(2), copy.filters(2));
+ ASSERT_EQ(selector.filters(3), copy.filters(3));
+}
+
+TEST_F(UserDataUtilTextValueTest, ResolveSelectorUserDataError) {
+ autofill::AutofillProfile contact(base::GenerateGUID(),
+ autofill::test::kEmptyOrigin);
+ autofill::test::SetProfileInfo(&contact, "Jo.h*n", /* middle name */ "",
+ "Doe", "", "", "", "", "", "", "", "", "");
+ user_model_.SetSelectedAutofillProfile(
+ "contact", std::make_unique<autofill::AutofillProfile>(contact),
+ &user_data_);
+
+ SelectorProto selector;
+ selector.add_filters()->set_css_selector("#test");
+
+ auto* filter = selector.add_filters();
+ auto* value = filter->mutable_property()->mutable_autofill_value_regexp();
+ value->mutable_profile()->set_identifier("contact");
+ auto* expression =
+ value->mutable_value_expression_re2()->mutable_value_expression();
+ expression->add_chunk()->set_key(
+ static_cast<int>(autofill::ServerFieldType::NAME_MIDDLE));
+
+ ClientStatus status = ResolveSelectorUserData(&selector, &user_data_);
+
+ ASSERT_FALSE(status.ok());
+}
+
} // namespace
} // namespace user_data
} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/view_layout.proto b/chromium/components/autofill_assistant/browser/view_layout.proto
index 1815ce42a76..1139b3b5c71 100644
--- a/chromium/components/autofill_assistant/browser/view_layout.proto
+++ b/chromium/components/autofill_assistant/browser/view_layout.proto
@@ -112,8 +112,10 @@ message DrawableProto {
ShapeDrawableProto shape = 3;
// An icon from a predefined set of known icons.
Icon icon = 4;
- // A Base64 encoded image string.
- bytes base64 = 5;
+ // Image data.
+ bytes image_data = 5;
+ // Image data encoded as a base64 string.
+ string image_data_base64 = 7;
// The favicon for a given URL.
FaviconDrawableProto favicon = 6;
}
diff --git a/chromium/components/autofill_assistant/browser/web/batch_element_checker_browsertest.cc b/chromium/components/autofill_assistant/browser/web/batch_element_checker_browsertest.cc
new file mode 100644
index 00000000000..17df9fd991c
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/web/batch_element_checker_browsertest.cc
@@ -0,0 +1,462 @@
+// Copyright 2022 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.
+
+#include "components/autofill_assistant/browser/batch_element_checker.h"
+
+#include <stddef.h>
+#include <iosfwd>
+#include <memory>
+#include <string>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/callback_forward.h"
+#include "base/containers/flat_map.h"
+#include "base/containers/flat_set.h"
+#include "base/containers/flat_tree.h"
+#include "base/numerics/clamped_math.h"
+#include "base/run_loop.h"
+#include "base/test/bind.h"
+#include "base/test/gmock_callback_support.h"
+#include "base/test/mock_callback.h"
+#include "base/time/time.h"
+#include "base/types/strong_alias.h"
+#include "components/autofill_assistant/browser/base_browsertest.h"
+#include "components/autofill_assistant/browser/client_status.h"
+#include "components/autofill_assistant/browser/selector.h"
+#include "components/autofill_assistant/browser/service.pb.h"
+#include "components/autofill_assistant/browser/user_data.h"
+#include "components/autofill_assistant/browser/user_model.h"
+#include "components/autofill_assistant/browser/web/selector_observer.h"
+#include "components/autofill_assistant/browser/web/web_controller.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "content/public/test/browser_test.h"
+#include "content/shell/browser/shell.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace autofill_assistant {
+
+using ::testing::AnyOf;
+using ::testing::IsEmpty;
+using ::testing::Return;
+
+class BatchElementCheckerBrowserTest
+ : public autofill_assistant::BaseBrowserTest,
+ public content::WebContentsObserver {
+ public:
+ BatchElementCheckerBrowserTest() {}
+
+ BatchElementCheckerBrowserTest(const BatchElementCheckerBrowserTest&) =
+ delete;
+ BatchElementCheckerBrowserTest& operator=(
+ const BatchElementCheckerBrowserTest&) = delete;
+
+ ~BatchElementCheckerBrowserTest() override {}
+
+ void SetUpOnMainThread() override {
+ BaseBrowserTest::SetUpOnMainThread();
+ web_controller_ = WebController::CreateForWebContents(
+ shell()->web_contents(), &user_data_, &log_info_,
+ /* annotate_dom_model_service= */ nullptr);
+ Observe(shell()->web_contents());
+ }
+
+ static ElementConditionProto AllOfConditions(
+ std::vector<ElementConditionProto> conditions) {
+ ElementConditionProto proto;
+ for (auto& condition : conditions) {
+ proto.mutable_any_of()->mutable_conditions()->Add(std::move(condition));
+ }
+ return proto;
+ }
+
+ static ElementConditionProto AnyOfConditions(
+ std::vector<ElementConditionProto> conditions) {
+ ElementConditionProto proto;
+ for (auto& condition : conditions) {
+ proto.mutable_any_of()->mutable_conditions()->Add(std::move(condition));
+ }
+ return proto;
+ }
+
+ static ElementConditionProto NoneOfConditions(
+ std::vector<ElementConditionProto> conditions) {
+ ElementConditionProto proto;
+ for (auto& condition : conditions) {
+ proto.mutable_none_of()->mutable_conditions()->Add(std::move(condition));
+ }
+ return proto;
+ }
+
+ static ElementConditionProto Match(Selector selector, bool strict = false) {
+ ElementConditionProto proto;
+ *proto.mutable_match() = selector.proto;
+ proto.set_require_unique_element(strict);
+ return proto;
+ }
+
+ // Run Observer BatchElementChecker on the provided conditions. The second
+ // value in the pairs (bool) is the match expectation.
+ void RunObserverBatchElementChecker(
+ const std::vector<std::pair<ElementConditionProto, bool>>& conditions) {
+ base::RunLoop run_loop;
+ BatchElementChecker checker;
+ std::vector<bool> actual_results(conditions.size(), false);
+ std::vector<bool> expected_results(conditions.size(), false);
+
+ for (size_t i = 0; i < conditions.size(); ++i) {
+ expected_results[i] = conditions[i].second;
+ checker.AddElementConditionCheck(
+ conditions[i].first,
+ base::BindOnce(&BatchElementCheckerBrowserTest::
+ ObserverBatchElementCheckerElementCallback,
+ &actual_results, i));
+ }
+ checker.AddAllDoneCallback(base::BindOnce(
+ &BatchElementCheckerBrowserTest::
+ ObserverBatchElementCheckerAllDoneCallback,
+ run_loop.QuitClosure(), &expected_results, &actual_results));
+
+ checker.EnableObserver(base::Seconds(30), base::Seconds(1),
+ base::Seconds(15));
+ checker.Run(web_controller_.get());
+ run_loop.Run();
+ EXPECT_EQ(web_controller_->pending_workers_.size(), 0u);
+ }
+
+ static void ObserverBatchElementCheckerElementCallback(
+ std::vector<bool>* res,
+ size_t i,
+ const ClientStatus& status,
+ const std::vector<std::string>& payloads,
+ const std::vector<std::string>& tags,
+ const base::flat_map<std::string, DomObjectFrameStack>& elms) {
+ (*res)[i] = status.ok();
+ }
+
+ static void ObserverBatchElementCheckerAllDoneCallback(
+ base::OnceClosure on_done,
+ const std::vector<bool>* expected,
+ const std::vector<bool>* actual) {
+ for (size_t i = 0; i < expected->size(); ++i) {
+ EXPECT_EQ(actual->at(i), expected->at(i)) << "condition number " << i;
+ }
+ std::move(on_done).Run();
+ }
+
+ protected:
+ std::unique_ptr<WebController> web_controller_;
+ UserData user_data_;
+ UserModel user_model_;
+ ProcessedActionStatusDetailsProto log_info_;
+};
+
+IN_PROC_BROWSER_TEST_F(BatchElementCheckerBrowserTest,
+ ObserverBatchElementCheckerStaticConditions) {
+ RunObserverBatchElementChecker({
+ {Match(Selector({"#button"})), true}, // A visible element.
+ {Match(Selector({"#hidden"})), true}, // A hidden element.
+ {Match(Selector({"#doesnotexist"})), false} // A nonexistent element.
+ });
+
+ RunObserverBatchElementChecker({{
+ AllOfConditions({
+ Match(Selector({"#button"})), // A visible element.
+ Match(Selector({"#hidden"})), // A hidden element.
+ }),
+ true // Expected to match.
+ }});
+
+ RunObserverBatchElementChecker({{
+ AnyOfConditions({
+ Match(Selector({"#button"})), // A visible element.
+ Match(Selector({"#doesnotexist"})) // A nonexistent element.
+ }),
+ true // Expected to match.
+ }});
+
+ RunObserverBatchElementChecker({{
+ NoneOfConditions({// A nonexistent element.
+ Match(Selector({"#doesnotexist"})),
+ // A non-existent element inside an iFrame.
+ Match(Selector({"#iframe", "#doesnotexists"}))}),
+ true // Expected to match.
+ }});
+
+ RunObserverBatchElementChecker({{
+ AllOfConditions(
+ {Match(Selector({"#iframe"})), // An iFrame.
+ Match(Selector({"#iframeExternal"})), // An OOPIF.
+ Match(Selector(
+ {"#iframe", "#button"})), // An element in a same-origin iFrame.
+ Match(Selector(
+ {"#iframeExternal", "#button"})), // An element in an OOPIF.
+ NoneOfConditions(
+ {// A non-existent element in an OOPIF.
+ Match(Selector({"#iframeExternal", "#doesnotexist"})),
+ // A non-existent element in a same-origin iFrame.
+ Match(Selector({"#iframe", "#doesnotexist"}))})}),
+ true // Expected to match.
+ }});
+}
+
+IN_PROC_BROWSER_TEST_F(BatchElementCheckerBrowserTest,
+ ObserverBatchElementCheckerDynamicElements) {
+ RunObserverBatchElementChecker({{
+ // A selector that only matches for ~200ms.
+ Match(Selector({".dynamic.about-2-seconds"})),
+ true // Expected to match.
+ }});
+
+ RunObserverBatchElementChecker({{
+ // A selector that only matches for ~200ms inside of an iFrame.
+ Match(Selector({"#iframe", ".dynamic.about-2-seconds"})),
+ true // Expected to match.
+ }});
+
+ RunObserverBatchElementChecker({{
+ // A selector that only matches for ~200ms inside of an external iFrame.
+ Match(Selector({"#iframeExternal", ".dynamic.about-2-seconds"})),
+ true // Expected to match.
+ }});
+}
+
+IN_PROC_BROWSER_TEST_F(BatchElementCheckerBrowserTest,
+ ObserverBatchElementCheckerDifferentFilters) {
+ Selector non_empty_bounding_box = Selector({"#button"});
+ non_empty_bounding_box.proto.add_filters()
+ ->mutable_bounding_box()
+ ->set_require_nonempty(true);
+
+ // Matches exactly one visible element.
+ auto with_inner_text =
+ Selector({"#with_inner_text span"}).MatchingInnerText("hello, world");
+
+ Selector match_css_selector({"label"});
+ match_css_selector.MatchingInnerText("terms and conditions");
+ match_css_selector.proto.add_filters()->mutable_labelled();
+ match_css_selector.proto.add_filters()->set_match_css_selector(
+ "input[type='checkbox']");
+
+ RunObserverBatchElementChecker({{
+ AllOfConditions(
+ {// A visible element.
+ Match(Selector({"#button"}).MustBeVisible()),
+ // An element in a same-origin iFrame.
+ Match(Selector({"#iframe", "#button"}).MustBeVisible()),
+ Match(non_empty_bounding_box), Match(with_inner_text),
+ Match(with_inner_text.MustBeVisible()), Match(match_css_selector),
+ NoneOfConditions(
+ {// A hidden element.
+ Match(Selector({"#hidden"}).MustBeVisible()),
+ // A non-existent element.
+ Match(Selector({"#doesnotexist"}).MustBeVisible())})}),
+ true // Expected to match.
+ }});
+}
+
+IN_PROC_BROWSER_TEST_F(BatchElementCheckerBrowserTest, SelectorObserver) {
+ base::RunLoop run_loop;
+ // Selector ids can be any number as long as unique.
+ const SelectorObserver::SelectorId button_id(11);
+ const SelectorObserver::SelectorId iframe_button_id(1234);
+ const SelectorObserver::SelectorId dynamic_id(0);
+
+ std::vector<base::flat_set<std::pair<SelectorObserver::SelectorId, bool>>>
+ expected_updates = {
+ {
+ // Initial state.
+ std::make_pair(button_id, /* match = */ true),
+ std::make_pair(iframe_button_id, /* match = */ true),
+ std::make_pair(dynamic_id, /* match = */ false),
+ },
+ {
+ // Dynamic element matches about 2s in.
+ std::make_pair(dynamic_id, /* match = */ true),
+ },
+ {
+ // Then shortly stops matching.
+ std::make_pair(dynamic_id, /* match = */ false),
+ }};
+
+ auto element_callback = base::BindLambdaForTesting(
+ [&](const ClientStatus& status,
+ const base::flat_map<SelectorObserver::SelectorId,
+ DomObjectFrameStack>& elements) {
+ EXPECT_TRUE(status.ok());
+ EXPECT_EQ(elements.size(), 1u);
+ EXPECT_EQ(elements.count(iframe_button_id), 1u);
+ run_loop.Quit();
+ });
+
+ int button_element_id = -1;
+ SelectorObserver::Callback update_callback = base::BindLambdaForTesting(
+ [&](const ClientStatus& status,
+ const std::vector<SelectorObserver::Update>& updates,
+ SelectorObserver* observer) {
+ EXPECT_TRUE(status.ok());
+ EXPECT_FALSE(expected_updates.empty());
+ for (auto& update : updates) {
+ auto removed = expected_updates[0].erase(
+ std::make_pair(update.selector_id, update.match));
+ EXPECT_EQ(removed, 1u);
+ if (update.selector_id == iframe_button_id) {
+ button_element_id = update.element_id;
+ }
+ }
+ if (expected_updates[0].empty()) {
+ expected_updates.erase(expected_updates.begin());
+ }
+ if (expected_updates.empty()) {
+ // Done receiving updates.
+ observer->GetElementsAndStop(
+ {{SelectorObserver::SelectorId(iframe_button_id),
+ /* element_id */ button_element_id}},
+ std::move(element_callback));
+ } else {
+ observer->Continue();
+ }
+ });
+
+ web_controller_->ObserveSelectors(
+ {{/* selector_id = */ button_id,
+ /* proto = */ Selector({"#button"}).proto,
+ /* strict = */ true},
+ {/* selector_id = */ iframe_button_id,
+ /* proto = */ Selector({"#iframe", "#button"}).proto,
+ /* strict = */ true},
+ {/* selector_id = */ dynamic_id,
+ /* proto = */
+ Selector({"#iframeExternal", ".dynamic.about-2-seconds"}).proto,
+ /* strict = */ true}},
+ base::Seconds(30), base::Seconds(1), base::Seconds(15), update_callback);
+
+ run_loop.Run();
+ ASSERT_TRUE(expected_updates.empty());
+}
+
+IN_PROC_BROWSER_TEST_F(BatchElementCheckerBrowserTest,
+ SelectorObserverRedirectIframe) {
+ base::RunLoop run_loop;
+ bool received_no_match_update = false;
+ const SelectorObserver::SelectorId button_id(15);
+
+ auto element_callback = base::BindLambdaForTesting(
+ [&](const ClientStatus& status,
+ const base::flat_map<SelectorObserver::SelectorId,
+ DomObjectFrameStack>& elements) {
+ EXPECT_TRUE(status.ok());
+ run_loop.Quit();
+ });
+
+ SelectorObserver::Callback update_callback = base::BindLambdaForTesting(
+ [&](const ClientStatus& status,
+ const std::vector<SelectorObserver::Update>& updates,
+ SelectorObserver* observer) {
+ EXPECT_TRUE(status.ok());
+ EXPECT_EQ(updates.size(), 1u);
+ EXPECT_EQ(updates[0].selector_id, button_id);
+ if (updates[0].match) {
+ EXPECT_TRUE(received_no_match_update);
+ observer->GetElementsAndStop({}, std::move(element_callback));
+ } else {
+ received_no_match_update = true;
+ observer->Continue();
+ }
+ });
+
+ web_controller_->ObserveSelectors(
+ {{/* selector_id = */ button_id,
+ /* proto = */ Selector({"#iframeRedirecting", "#button"}).proto,
+ /* strict = */ true}},
+ base::Seconds(30), base::Seconds(1), base::Seconds(15), update_callback);
+
+ run_loop.Run();
+}
+
+IN_PROC_BROWSER_TEST_F(BatchElementCheckerBrowserTest,
+ SelectorObserverTimeout) {
+ base::RunLoop run_loop;
+
+ base::MockCallback<base::RepeatingCallback<void(
+ const ClientStatus& status,
+ const std::vector<SelectorObserver::Update>& updates,
+ SelectorObserver* observer)>>
+ mock_callback;
+ EXPECT_CALL(mock_callback, Run)
+ .WillOnce([](const ClientStatus& status,
+ const std::vector<SelectorObserver::Update>& updates,
+ SelectorObserver* observer) {
+ // First call informs of the initial state of the selectors.
+ EXPECT_TRUE(status.ok());
+ EXPECT_EQ(updates.size(), 1u);
+ observer->Continue();
+ })
+ .WillOnce([&](const ClientStatus& status,
+ const std::vector<SelectorObserver::Update>& updates,
+ SelectorObserver* observer) {
+ // Second call when it timeouts.
+ EXPECT_EQ(status.proto_status(), ELEMENT_RESOLUTION_FAILED);
+ EXPECT_EQ(updates.size(), 0u);
+ run_loop.Quit();
+ });
+
+ web_controller_->ObserveSelectors(
+ {{/* selector_id = */ SelectorObserver::SelectorId(1),
+ /* proto = */ Selector({"#does_not_exist"}).proto,
+ /* strict = */ true}},
+ base::Milliseconds(300), base::Seconds(1), base::Seconds(15),
+ mock_callback.Get());
+
+ run_loop.Run();
+}
+
+IN_PROC_BROWSER_TEST_F(BatchElementCheckerBrowserTest,
+ SelectorObserverShortMaxWaitTime) {
+ base::RunLoop run_loop;
+ const SelectorObserver::SelectorId button_id(15);
+ base::MockCallback<base::OnceCallback<void(
+ const ClientStatus& status,
+ const base::flat_map<SelectorObserver::SelectorId, DomObjectFrameStack>&
+ elements)>>
+ element_callback;
+ EXPECT_CALL(element_callback, Run)
+ .WillOnce([&](const ClientStatus& status,
+ const base::flat_map<SelectorObserver::SelectorId,
+ DomObjectFrameStack>& elements) {
+ EXPECT_TRUE(status.ok());
+ run_loop.Quit();
+ });
+
+ base::MockCallback<base::RepeatingCallback<void(
+ const ClientStatus& status,
+ const std::vector<SelectorObserver::Update>& updates,
+ SelectorObserver* observer)>>
+ update_callback;
+ EXPECT_CALL(update_callback, Run)
+ .WillOnce([&](const ClientStatus& status,
+ const std::vector<SelectorObserver::Update>& updates,
+ SelectorObserver* observer) {
+ EXPECT_TRUE(status.ok());
+ EXPECT_EQ(updates.size(), 1u);
+ EXPECT_EQ(updates[0].selector_id, button_id);
+ EXPECT_TRUE(updates[0].match);
+ observer->GetElementsAndStop({}, element_callback.Get());
+ });
+
+ web_controller_->ObserveSelectors(
+ {{/* selector_id = */ button_id,
+ /* proto = */ Selector({"#iframe", "#button"}).proto,
+ /* strict = */ true}},
+ base::Milliseconds(1), base::Seconds(1), base::Seconds(15),
+ update_callback.Get());
+
+ run_loop.Run();
+}
+
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/web/element.cc b/chromium/components/autofill_assistant/browser/web/element.cc
index afff69126aa..8fb951d48b3 100644
--- a/chromium/components/autofill_assistant/browser/web/element.cc
+++ b/chromium/components/autofill_assistant/browser/web/element.cc
@@ -15,6 +15,37 @@ DomObjectFrameStack::~DomObjectFrameStack() = default;
DomObjectFrameStack::DomObjectFrameStack(const DomObjectFrameStack&) = default;
+GlobalBackendNodeId::GlobalBackendNodeId(
+ content::RenderFrameHost* render_frame_host,
+ int backend_node_id)
+ : backend_node_id_(backend_node_id) {
+ if (render_frame_host) {
+ host_id_ = render_frame_host->GetGlobalId();
+ }
+}
+
+GlobalBackendNodeId::GlobalBackendNodeId(
+ content::GlobalRenderFrameHostId host_id,
+ int backend_node_id)
+ : host_id_(host_id), backend_node_id_(backend_node_id) {}
+
+GlobalBackendNodeId::~GlobalBackendNodeId() = default;
+
+GlobalBackendNodeId::GlobalBackendNodeId(const GlobalBackendNodeId&) = default;
+
+bool GlobalBackendNodeId::operator==(const GlobalBackendNodeId& other) const {
+ return host_id_ == other.host_id_ &&
+ backend_node_id_ == other.backend_node_id_;
+}
+
+content::GlobalRenderFrameHostId GlobalBackendNodeId::host_id() const {
+ return host_id_;
+}
+
+int GlobalBackendNodeId::backend_node_id() const {
+ return backend_node_id_;
+}
+
content::RenderFrameHost* FindCorrespondingRenderFrameHost(
const std::string& frame_id,
content::WebContents* web_contents) {
diff --git a/chromium/components/autofill_assistant/browser/web/element.h b/chromium/components/autofill_assistant/browser/web/element.h
index 89e6b729ab4..04aef40d18d 100644
--- a/chromium/components/autofill_assistant/browser/web/element.h
+++ b/chromium/components/autofill_assistant/browser/web/element.h
@@ -8,6 +8,7 @@
#include <string>
#include <vector>
+#include "content/public/browser/global_routing_id.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
@@ -41,6 +42,26 @@ struct DomObjectFrameStack {
std::vector<JsObjectIdentifier> frame_stack;
};
+// GlobalBackendNodeId contains all data required to uniquely identify a node.
+class GlobalBackendNodeId {
+ public:
+ GlobalBackendNodeId(content::RenderFrameHost* render_frame_host,
+ int backend_node_id);
+ GlobalBackendNodeId(content::GlobalRenderFrameHostId host_id,
+ int backend_node_id);
+ ~GlobalBackendNodeId();
+ GlobalBackendNodeId(const GlobalBackendNodeId&);
+
+ bool operator==(const GlobalBackendNodeId& other) const;
+
+ content::GlobalRenderFrameHostId host_id() const;
+ int backend_node_id() const;
+
+ private:
+ content::GlobalRenderFrameHostId host_id_;
+ int backend_node_id_ = -1;
+};
+
// Find the frame host in the set of known frames matching the |frame_id|. This
// returns nullptr if no frame is found.
content::RenderFrameHost* FindCorrespondingRenderFrameHost(
diff --git a/chromium/components/autofill_assistant/browser/web/element_finder.cc b/chromium/components/autofill_assistant/browser/web/element_finder.cc
index 1c16340e504..52042b4e5e2 100644
--- a/chromium/components/autofill_assistant/browser/web/element_finder.cc
+++ b/chromium/components/autofill_assistant/browser/web/element_finder.cc
@@ -4,11 +4,16 @@
#include "components/autofill_assistant/browser/web/element_finder.h"
+#include "base/barrier_callback.h"
#include "components/autofill_assistant/browser/devtools/devtools_client.h"
#include "components/autofill_assistant/browser/service.pb.h"
#include "components/autofill_assistant/browser/user_data_util.h"
#include "components/autofill_assistant/browser/web/element.h"
+#include "components/autofill_assistant/browser/web/js_filter_builder.h"
#include "components/autofill_assistant/browser/web/web_controller_util.h"
+#include "components/autofill_assistant/content/browser/content_autofill_assistant_driver.h"
+#include "components/autofill_assistant/content/common/autofill_assistant_agent.mojom.h"
+#include "content/public/browser/global_routing_id.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
@@ -16,8 +21,7 @@ namespace autofill_assistant {
namespace {
// Javascript code to get document root element.
-const char kGetDocumentElement[] =
- "(function() { return document.documentElement; }())";
+const char kGetDocumentElement[] = "document.documentElement;";
const char kGetArrayElement[] = "function(index) { return this[index]; }";
@@ -75,263 +79,13 @@ bool ConvertPseudoType(const PseudoType pseudo_type,
return false;
}
-ClientStatus MoveAutofillValueRegexpToTextFilter(
- const UserData* user_data,
- SelectorProto::PropertyFilter* value) {
- if (!value->has_autofill_value_regexp()) {
- return OkClientStatus();
- }
- if (user_data == nullptr) {
- return ClientStatus(PRECONDITION_FAILED);
- }
- const AutofillValueRegexp& autofill_value_regexp =
- value->autofill_value_regexp();
- TextFilter text_filter;
- text_filter.set_case_sensitive(
- autofill_value_regexp.value_expression_re2().case_sensitive());
- std::string re2;
- ClientStatus re2_status = user_data::GetFormattedClientValue(
- autofill_value_regexp, *user_data, &re2);
- text_filter.set_re2(re2);
- // Assigning text_filter will clear autofill_value_regexp.
- *value->mutable_text_filter() = text_filter;
- return re2_status;
-}
-
-ClientStatus GetUserDataResolvedSelector(const Selector& selector,
- const UserData* user_data,
- SelectorProto* out_selector) {
- SelectorProto copy = selector.proto;
- for (auto& filter : *copy.mutable_filters()) {
- switch (filter.filter_case()) {
- case SelectorProto::Filter::kProperty: {
- ClientStatus filter_status = MoveAutofillValueRegexpToTextFilter(
- user_data, filter.mutable_property());
- if (!filter_status.ok()) {
- return filter_status;
- }
- break;
- }
- case SelectorProto::Filter::kInnerText:
- case SelectorProto::Filter::kValue:
- case SelectorProto::Filter::kPseudoElementContent:
- case SelectorProto::Filter::kCssStyle:
- case SelectorProto::Filter::kCssSelector:
- case SelectorProto::Filter::kEnterFrame:
- case SelectorProto::Filter::kPseudoType:
- case SelectorProto::Filter::kBoundingBox:
- case SelectorProto::Filter::kNthMatch:
- case SelectorProto::Filter::kLabelled:
- case SelectorProto::Filter::kMatchCssSelector:
- case SelectorProto::Filter::kOnTop:
- case SelectorProto::Filter::FILTER_NOT_SET:
- break;
- // Do not add default here. In case a new filter gets added (that may
- // contain a RegexpFilter) we want this to fail at compilation here.
- }
- }
- *out_selector = copy;
- return OkClientStatus();
+void AddHostToList(std::vector<content::GlobalRenderFrameHostId>& host_ids,
+ content::RenderFrameHost* host) {
+ host_ids.push_back(host->GetGlobalId());
}
} // namespace
-ElementFinder::JsFilterBuilder::JsFilterBuilder() = default;
-ElementFinder::JsFilterBuilder::~JsFilterBuilder() = default;
-
-std::vector<std::unique_ptr<runtime::CallArgument>>
-ElementFinder::JsFilterBuilder::BuildArgumentList() const {
- auto str_array_arg = std::make_unique<base::Value>(base::Value::Type::LIST);
- for (const std::string& str : arguments_) {
- str_array_arg->Append(str);
- }
- std::vector<std::unique_ptr<runtime::CallArgument>> arguments;
- arguments.emplace_back(runtime::CallArgument::Builder()
- .SetValue(std::move(str_array_arg))
- .Build());
- return arguments;
-}
-
-// clang-format off
-std::string ElementFinder::JsFilterBuilder::BuildFunction() const {
- return base::StrCat({
- R"(
- function(args) {
- let elements = [this];
- )",
- snippet_.ToString(),
- R"(
- if (elements.length == 0) return null;
- if (elements.length == 1) { return elements[0] }
- return elements;
- })"
- });
-}
-// clang-format on
-
-bool ElementFinder::JsFilterBuilder::AddFilter(
- const SelectorProto::Filter& filter) {
- switch (filter.filter_case()) {
- case SelectorProto::Filter::kCssSelector:
- // We querySelectorAll the current elements and remove duplicates, which
- // are likely when using inner text before CSS selector filters. We must
- // not return duplicates as they cause incorrect TOO_MANY_ELEMENTS errors.
- DefineQueryAllDeduplicated();
- AddLine({"elements = queryAllDeduplicated(elements, ",
- AddArgument(filter.css_selector()), ");"});
- return true;
-
- case SelectorProto::Filter::kInnerText:
- AddRegexpFilter(filter.inner_text(), "innerText");
- return true;
-
- case SelectorProto::Filter::kValue:
- AddRegexpFilter(filter.value(), "value");
- return true;
-
- case SelectorProto::Filter::kProperty:
- AddRegexpFilter(filter.property().text_filter(),
- filter.property().property());
- return true;
-
- case SelectorProto::Filter::kBoundingBox:
- if (filter.bounding_box().require_nonempty()) {
- AddLine("elements = elements.filter((e) => {");
- AddLine(" const rect = e.getBoundingClientRect();");
- AddLine(" return rect.width != 0 && rect.height != 0;");
- AddLine("});");
- } else {
- AddLine(
- "elements = elements.filter((e) => e.getClientRects().length > "
- "0);");
- }
- return true;
-
- case SelectorProto::Filter::kPseudoElementContent: {
- // When a content is set, window.getComputedStyle().content contains a
- // double-quoted string with the content, unquoted here by JSON.parse().
- std::string re_var =
- AddRegexpInstance(filter.pseudo_element_content().content());
- std::string pseudo_type =
- PseudoTypeName(filter.pseudo_element_content().pseudo_type());
-
- AddLine("elements = elements.filter((e) => {");
- AddLine({" const s = window.getComputedStyle(e, '", pseudo_type, "');"});
- AddLine(" if (!s || !s.content || !s.content.startsWith('\"')) {");
- AddLine(" return false;");
- AddLine(" }");
- AddLine({" return ", re_var, ".test(JSON.parse(s.content));"});
- AddLine("});");
- return true;
- }
-
- case SelectorProto::Filter::kCssStyle: {
- std::string re_var = AddRegexpInstance(filter.css_style().value());
- std::string property = AddArgument(filter.css_style().property());
- std::string element = AddArgument(filter.css_style().pseudo_element());
- AddLine("elements = elements.filter((e) => {");
- AddLine(" const s = window.getComputedStyle(e, ");
- AddLine({" ", element, " === '' ? null : ", element, ");"});
- AddLine({" const match = ", re_var, ".test(s[", property, "]);"});
- if (filter.css_style().should_match()) {
- AddLine(" return match;");
- } else {
- AddLine(" return !match;");
- }
- AddLine("});");
- return true;
- }
-
- case SelectorProto::Filter::kLabelled:
- AddLine("elements = elements.flatMap((e) => {");
- AddLine(
- " return e.tagName === 'LABEL' && e.control ? [e.control] : [];");
- AddLine("});");
- return true;
-
- case SelectorProto::Filter::kMatchCssSelector:
- AddLine({"elements = elements.filter((e) => e.webkitMatchesSelector(",
- AddArgument(filter.match_css_selector()), "));"});
- return true;
-
- case SelectorProto::Filter::kOnTop:
- AddLine("elements = elements.filter((e) => {");
- AddLine("if (e.getClientRects().length == 0) return false;");
- if (filter.on_top().scroll_into_view_if_needed()) {
- AddLine("e.scrollIntoViewIfNeeded(false);");
- }
- AddReturnIfOnTop(
- &snippet_, "e", /* on_top= */ "true", /* not_on_top= */ "false",
- /* not_in_view= */ filter.on_top().accept_element_if_not_in_view()
- ? "true"
- : "false");
- AddLine("});");
- return true;
-
- case SelectorProto::Filter::kEnterFrame:
- case SelectorProto::Filter::kPseudoType:
- case SelectorProto::Filter::kNthMatch:
- case SelectorProto::Filter::FILTER_NOT_SET:
- return false;
- }
-}
-
-std::string ElementFinder::JsFilterBuilder::AddRegexpInstance(
- const TextFilter& filter) {
- std::string re_flags = filter.case_sensitive() ? "" : "i";
- std::string re_var = DeclareVariable();
- AddLine({"const ", re_var, " = RegExp(", AddArgument(filter.re2()), ", '",
- re_flags, "');"});
- return re_var;
-}
-
-void ElementFinder::JsFilterBuilder::AddRegexpFilter(
- const TextFilter& filter,
- const std::string& property) {
- std::string re_var = AddRegexpInstance(filter);
- AddLine({"elements = elements.filter((e) => ", re_var, ".test(e.", property,
- "));"});
-}
-
-std::string ElementFinder::JsFilterBuilder::DeclareVariable() {
- return base::StrCat({"v", base::NumberToString(variable_counter_++)});
-}
-
-std::string ElementFinder::JsFilterBuilder::AddArgument(
- const std::string& value) {
- int index = arguments_.size();
- arguments_.emplace_back(value);
- return base::StrCat({"args[", base::NumberToString(index), "]"});
-}
-
-void ElementFinder::JsFilterBuilder::DefineQueryAllDeduplicated() {
- // Ensure that we don't define the function more than once.
- if (defined_query_all_deduplicated_)
- return;
-
- defined_query_all_deduplicated_ = true;
-
- AddLine(R"(
- const queryAllDeduplicated = function(roots, selector) {
- if (roots.length == 0) {
- return [];
- }
-
- const matchesSet = new Set();
- const matches = [];
- roots.forEach((root) => {
- root.querySelectorAll(selector).forEach((elem) => {
- if (!matchesSet.has(elem)) {
- matchesSet.add(elem);
- matches.push(elem);
- }
- });
- });
- return matches;
- }
- )");
-}
-
ElementFinder::Result::Result() = default;
ElementFinder::Result::~Result() = default;
@@ -342,16 +96,19 @@ ElementFinder::Result ElementFinder::Result::EmptyResult() {
return ElementFinder::Result();
}
-ElementFinder::ElementFinder(content::WebContents* web_contents,
- DevtoolsClient* devtools_client,
- const UserData* user_data,
- ProcessedActionStatusDetailsProto* log_info,
- const Selector& selector,
- ResultType result_type)
+ElementFinder::ElementFinder(
+ content::WebContents* web_contents,
+ DevtoolsClient* devtools_client,
+ const UserData* user_data,
+ ProcessedActionStatusDetailsProto* log_info,
+ AnnotateDomModelService* annotate_dom_model_service,
+ const Selector& selector,
+ ResultType result_type)
: web_contents_(web_contents),
devtools_client_(devtools_client),
user_data_(user_data),
log_info_(log_info),
+ annotate_dom_model_service_(annotate_dom_model_service),
selector_(selector),
result_type_(result_type) {}
@@ -361,17 +118,25 @@ void ElementFinder::Start(const Result& start_element, Callback callback) {
callback_ = std::move(callback);
if (selector_.empty()) {
- SendErrorResult(ClientStatus(INVALID_SELECTOR));
+ SendResult(ClientStatus(INVALID_SELECTOR), Result::EmptyResult());
return;
}
+ selector_proto_ = selector_.proto;
ClientStatus resolve_status =
- GetUserDataResolvedSelector(selector_, user_data_, &selector_proto_);
+ user_data::ResolveSelectorUserData(&selector_proto_, user_data_);
if (!resolve_status.ok()) {
- SendErrorResult(resolve_status);
+ SendResult(resolve_status, Result::EmptyResult());
return;
}
+ if (annotate_dom_model_service_ &&
+ selector_.proto.has_semantic_information()) {
+ RunAnnotateDomModel();
+ } else {
+ semantic_result_done_ = true;
+ }
+
if (start_element.container_frame_host == nullptr) {
current_frame_ = web_contents_->GetMainFrame();
} else {
@@ -388,7 +153,8 @@ void ElementFinder::Start(const Result& start_element, Callback callback) {
}
}
-void ElementFinder::UpdateLogInfo(const ClientStatus& status) {
+void ElementFinder::UpdateLogInfo(const Result& result,
+ const ClientStatus& status) {
if (log_info_ == nullptr) {
return;
}
@@ -404,29 +170,68 @@ void ElementFinder::UpdateLogInfo(const ClientStatus& status) {
if (selector_.proto.has_tracking_id()) {
info->set_tracking_id(selector_.proto.tracking_id());
}
+
+ if (selector_.proto.has_semantic_information()) {
+ auto* inference_result = info->mutable_semantic_inference_result();
+ for (const auto& node_id : semantic_node_results_) {
+ auto* predicted_element = inference_result->add_predicted_elements();
+ predicted_element->set_matches_css_element(
+ GlobalBackendNodeId(result.container_frame_host,
+ result_backend_node_id_.value_or(-1)) == node_id);
+ }
+ }
}
-void ElementFinder::SendErrorResult(const ClientStatus& status) {
- if (!callback_)
+void ElementFinder::SendResult(const ClientStatus& status,
+ const Result& result) {
+ if (!callback_) {
return;
+ }
+ UpdateLogInfo(result, status);
+ std::move(callback_).Run(
+ ClientStatus(status.proto_status(), status.details()),
+ std::make_unique<Result>(result));
+}
+
+void ElementFinder::SendCollectedResultIfAny() {
+ if (!callback_) {
+ return;
+ }
+ if (!css_result_done_ || !semantic_result_done_) {
+ return;
+ }
+ SendResult(result_status_, result_);
+}
+void ElementFinder::GiveUpElementResolutionWithError(
+ const ClientStatus& status) {
DCHECK(!status.ok());
- UpdateLogInfo(status);
+ if (!callback_)
+ return;
- std::move(callback_).Run(status, std::make_unique<Result>());
+ css_result_done_ = true;
+ result_status_ = status;
+ SendCollectedResultIfAny();
}
-void ElementFinder::SendSuccessResult(const std::string& object_id) {
+void ElementFinder::ResultFound(const std::string& object_id) {
if (!callback_)
return;
- UpdateLogInfo(OkClientStatus());
+ result_status_ = OkClientStatus();
- // Fill in result and return
- std::unique_ptr<Result> result =
- std::make_unique<Result>(BuildResult(object_id));
- result->dom_object.frame_stack = frame_stack_;
- std::move(callback_).Run(OkClientStatus(), std::move(result));
+ // Fill in result.
+ result_ = BuildResult(object_id);
+ result_.dom_object.frame_stack = frame_stack_;
+
+ if (annotate_dom_model_service_ &&
+ selector_.proto.has_semantic_information()) {
+ DescribeNodeForAnnotateDom();
+ return;
+ }
+
+ css_result_done_ = true;
+ SendCollectedResultIfAny();
}
ElementFinder::Result ElementFinder::BuildResult(const std::string& object_id) {
@@ -437,6 +242,87 @@ ElementFinder::Result ElementFinder::BuildResult(const std::string& object_id) {
return result;
}
+void ElementFinder::DescribeNodeForAnnotateDom() {
+ devtools_client_->GetDOM()->DescribeNode(
+ dom::DescribeNodeParams::Builder()
+ .SetObjectId(result_.object_id())
+ .Build(),
+ result_.node_frame_id(),
+ base::BindOnce(&ElementFinder::OnDescribeNodeForAnnotateDom,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void ElementFinder::OnDescribeNodeForAnnotateDom(
+ const DevtoolsClient::ReplyStatus& reply_status,
+ std::unique_ptr<dom::DescribeNodeResult> node_result) {
+ if (node_result && node_result->GetNode()) {
+ result_backend_node_id_ = node_result->GetNode()->GetBackendNodeId();
+ }
+ css_result_done_ = true;
+ SendCollectedResultIfAny();
+}
+
+void ElementFinder::RunAnnotateDomModel() {
+ std::vector<content::GlobalRenderFrameHostId> host_ids;
+ web_contents_->GetMainFrame()->ForEachRenderFrameHost(
+ base::BindRepeating(&AddHostToList, std::ref(host_ids)));
+ const auto run_on_frame =
+ base::BarrierCallback<std::vector<GlobalBackendNodeId>>(
+ host_ids.size(), base::BindOnce(&ElementFinder::OnRunAnnotateDomModel,
+ weak_ptr_factory_.GetWeakPtr()));
+ for (const auto& host_id : host_ids) {
+ RunAnnotateDomModelOnFrame(host_id, run_on_frame);
+ }
+}
+
+void ElementFinder::RunAnnotateDomModelOnFrame(
+ const content::GlobalRenderFrameHostId& host_id,
+ base::OnceCallback<void(std::vector<GlobalBackendNodeId>)> callback) {
+ content::RenderFrameHost* render_frame_host =
+ content::RenderFrameHost::FromID(host_id);
+ if (!render_frame_host) {
+ std::move(callback).Run(std::vector<GlobalBackendNodeId>());
+ return;
+ }
+
+ auto* driver = ContentAutofillAssistantDriver::GetOrCreateForRenderFrameHost(
+ render_frame_host, annotate_dom_model_service_);
+ if (!driver) {
+ NOTREACHED();
+ std::move(callback).Run(std::vector<GlobalBackendNodeId>());
+ return;
+ }
+
+ driver->GetAutofillAssistantAgent()->GetSemanticNodes(
+ selector_.proto.semantic_information().semantic_role(),
+ selector_.proto.semantic_information().objective(),
+ base::BindOnce(&ElementFinder::OnRunAnnotateDomModelOnFrame,
+ weak_ptr_factory_.GetWeakPtr(), host_id,
+ std::move(callback)));
+}
+
+void ElementFinder::OnRunAnnotateDomModelOnFrame(
+ const content::GlobalRenderFrameHostId& host_id,
+ base::OnceCallback<void(std::vector<GlobalBackendNodeId>)> callback,
+ bool success,
+ const std::vector<NodeData>& node_data) {
+ std::vector<GlobalBackendNodeId> node_ids;
+ for (const auto& node : node_data) {
+ node_ids.emplace_back(GlobalBackendNodeId(host_id, node.backend_node_id));
+ }
+ std::move(callback).Run(node_ids);
+}
+
+void ElementFinder::OnRunAnnotateDomModel(
+ const std::vector<std::vector<GlobalBackendNodeId>>& all_nodes) {
+ for (const auto& node_ids : all_nodes) {
+ semantic_node_results_.insert(semantic_node_results_.end(),
+ node_ids.begin(), node_ids.end());
+ }
+ semantic_result_done_ = true;
+ SendCollectedResultIfAny();
+}
+
void ElementFinder::ExecuteNextTask() {
const auto& filters = selector_proto_.filters();
@@ -461,7 +347,7 @@ void ElementFinder::ExecuteNextTask() {
}
break;
}
- SendSuccessResult(object_id);
+ ResultFound(object_id);
return;
}
@@ -494,6 +380,8 @@ void ElementFinder::ExecuteNextTask() {
}
case SelectorProto::Filter::kNthMatch: {
+ // TODO(b/205676462): This could be done with javascript like in
+ // |SelectorObserver|.
std::string object_id;
if (!ConsumeMatchAtOrFail(filter.nth_match().index(), object_id))
return;
@@ -532,7 +420,7 @@ void ElementFinder::ExecuteNextTask() {
case SelectorProto::Filter::FILTER_NOT_SET:
VLOG(1) << __func__ << " Unset or unknown filter in " << filter << " in "
<< selector_;
- SendErrorResult(ClientStatus(INVALID_SELECTOR));
+ GiveUpElementResolutionWithError(ClientStatus(INVALID_SELECTOR));
return;
}
}
@@ -541,11 +429,11 @@ bool ElementFinder::ConsumeOneMatchOrFail(std::string& object_id_out) {
if (current_matches_.size() > 1) {
VLOG(1) << __func__ << " Got " << current_matches_.size() << " matches for "
<< selector_ << ", when only 1 was expected.";
- SendErrorResult(ClientStatus(TOO_MANY_ELEMENTS));
+ GiveUpElementResolutionWithError(ClientStatus(TOO_MANY_ELEMENTS));
return false;
}
if (current_matches_.empty()) {
- SendErrorResult(ClientStatus(ELEMENT_RESOLUTION_FAILED));
+ GiveUpElementResolutionWithError(ClientStatus(ELEMENT_RESOLUTION_FAILED));
return false;
}
@@ -562,7 +450,7 @@ bool ElementFinder::ConsumeMatchAtOrFail(size_t index,
return true;
}
- SendErrorResult(ClientStatus(ELEMENT_RESOLUTION_FAILED));
+ GiveUpElementResolutionWithError(ClientStatus(ELEMENT_RESOLUTION_FAILED));
return false;
}
@@ -573,7 +461,7 @@ bool ElementFinder::ConsumeAllMatchesOrFail(
current_matches_.clear();
return true;
}
- SendErrorResult(ClientStatus(ELEMENT_RESOLUTION_FAILED));
+ GiveUpElementResolutionWithError(ClientStatus(ELEMENT_RESOLUTION_FAILED));
return false;
}
@@ -585,7 +473,7 @@ bool ElementFinder::ConsumeMatchArrayOrFail(std::string& array_object_id) {
}
if (current_matches_.empty()) {
- SendErrorResult(ClientStatus(ELEMENT_RESOLUTION_FAILED));
+ GiveUpElementResolutionWithError(ClientStatus(ELEMENT_RESOLUTION_FAILED));
return false;
}
@@ -631,7 +519,7 @@ void ElementFinder::OnMoveMatchesToJSArrayRecursive(
CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__);
if (!status.ok()) {
VLOG(1) << __func__ << ": Failed to push value to JS array.";
- SendErrorResult(status);
+ GiveUpElementResolutionWithError(status);
return;
}
@@ -640,7 +528,7 @@ void ElementFinder::OnMoveMatchesToJSArrayRecursive(
if (index == 0 &&
!SafeGetObjectId(result->GetResult(), &current_matches_js_array_)) {
VLOG(1) << __func__ << " Failed to get array ID.";
- SendErrorResult(ClientStatus(ELEMENT_RESOLUTION_FAILED));
+ GiveUpElementResolutionWithError(ClientStatus(ELEMENT_RESOLUTION_FAILED));
return;
}
@@ -663,14 +551,14 @@ void ElementFinder::OnGetDocumentElement(
if (!status.ok()) {
VLOG(1) << __func__ << " Failed to get document root element.";
get_document_failed_ = true;
- SendErrorResult(status);
+ GiveUpElementResolutionWithError(status);
return;
}
std::string object_id;
if (!SafeGetObjectId(result->GetResult(), &object_id)) {
VLOG(1) << __func__ << " Failed to get document root element.";
get_document_failed_ = true;
- SendErrorResult(ClientStatus(ELEMENT_RESOLUTION_FAILED));
+ GiveUpElementResolutionWithError(ClientStatus(ELEMENT_RESOLUTION_FAILED));
return;
}
@@ -709,7 +597,7 @@ void ElementFinder::OnApplyJsFilters(
// call, it is expected.
VLOG(1) << __func__ << ": Context doesn't exist yet to query frame "
<< frame_stack_.size() << " of " << selector_;
- SendErrorResult(ClientStatus(ELEMENT_RESOLUTION_FAILED));
+ GiveUpElementResolutionWithError(ClientStatus(ELEMENT_RESOLUTION_FAILED));
return;
}
ClientStatus status =
@@ -717,7 +605,7 @@ void ElementFinder::OnApplyJsFilters(
if (!status.ok()) {
VLOG(1) << __func__ << ": Failed to query selector for frame "
<< frame_stack_.size() << " of " << selector_ << ": " << status;
- SendErrorResult(status);
+ GiveUpElementResolutionWithError(status);
return;
}
@@ -746,7 +634,7 @@ void ElementFinder::ResolvePseudoElement(
if (!ConvertPseudoType(proto_pseudo_type, &pseudo_type)) {
VLOG(1) << __func__ << ": Unsupported pseudo-type "
<< PseudoTypeName(proto_pseudo_type);
- SendErrorResult(ClientStatus(INVALID_ACTION));
+ GiveUpElementResolutionWithError(ClientStatus(INVALID_ACTION));
return;
}
@@ -770,7 +658,7 @@ void ElementFinder::OnDescribeNodeForPseudoElement(
std::unique_ptr<dom::DescribeNodeResult> result) {
if (!result || !result->GetNode()) {
VLOG(1) << __func__ << " Failed to describe the node for pseudo element.";
- SendErrorResult(
+ GiveUpElementResolutionWithError(
UnexpectedDevtoolsErrorStatus(reply_status, __FILE__, __LINE__));
return;
}
@@ -821,7 +709,7 @@ void ElementFinder::OnDescribeNodeForFrame(
std::unique_ptr<dom::DescribeNodeResult> result) {
if (!result || !result->GetNode()) {
VLOG(1) << __func__ << " Failed to describe the node.";
- SendErrorResult(
+ GiveUpElementResolutionWithError(
UnexpectedDevtoolsErrorStatus(reply_status, __FILE__, __LINE__));
return;
}
@@ -833,7 +721,7 @@ void ElementFinder::OnDescribeNodeForFrame(
// See: b/206647825
if (!node->HasFrameId()) {
NOTREACHED() << "Frame without ID"; // Ensure all frames have an id.
- SendErrorResult(ClientStatus(FRAME_HOST_NOT_FOUND));
+ GiveUpElementResolutionWithError(ClientStatus(FRAME_HOST_NOT_FOUND));
return;
}
@@ -843,7 +731,7 @@ void ElementFinder::OnDescribeNodeForFrame(
FindCorrespondingRenderFrameHost(node->GetFrameId(), web_contents_);
if (!frame) {
VLOG(1) << __func__ << " Failed to find corresponding owner frame.";
- SendErrorResult(ClientStatus(FRAME_HOST_NOT_FOUND));
+ GiveUpElementResolutionWithError(ClientStatus(FRAME_HOST_NOT_FOUND));
return;
}
current_frame_ = frame;
@@ -890,7 +778,7 @@ void ElementFinder::OnResolveNode(
std::unique_ptr<dom::ResolveNodeResult> result) {
if (!result || !result->GetObject() || !result->GetObject()->HasObjectId()) {
VLOG(1) << __func__ << " Failed to resolve object id from backend id.";
- SendErrorResult(
+ GiveUpElementResolutionWithError(
UnexpectedDevtoolsErrorStatus(reply_status, __FILE__, __LINE__));
return;
}
@@ -958,7 +846,7 @@ void ElementFinder::OnReportMatchingElementsArrayRecursive(
if (!status.ok()) {
VLOG(1) << __func__ << ": Failed to get element from array for "
<< selector_;
- SendErrorResult(status);
+ GiveUpElementResolutionWithError(status);
return;
}
diff --git a/chromium/components/autofill_assistant/browser/web/element_finder.h b/chromium/components/autofill_assistant/browser/web/element_finder.h
index c8994aea808..e8c972c3e4e 100644
--- a/chromium/components/autofill_assistant/browser/web/element_finder.h
+++ b/chromium/components/autofill_assistant/browser/web/element_finder.h
@@ -20,12 +20,16 @@
#include "components/autofill_assistant/browser/selector.h"
#include "components/autofill_assistant/browser/user_data.h"
#include "components/autofill_assistant/browser/web/element.h"
-#include "components/autofill_assistant/browser/web/js_snippets.h"
+#include "components/autofill_assistant/browser/web/js_filter_builder.h"
#include "components/autofill_assistant/browser/web/web_controller_worker.h"
+#include "components/autofill_assistant/content/browser/annotate_dom_model_service.h"
+#include "components/autofill_assistant/content/common/node_data.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
namespace content {
class WebContents;
class RenderFrameHost;
+struct GlobalRenderFrameHostId;
} // namespace content
namespace autofill_assistant {
@@ -88,11 +92,13 @@ class ElementFinder : public WebControllerWorker {
};
// |web_contents|, |devtools_client| and |user_data| must be valid for the
- // lifetime of the instance.
+ // lifetime of the instance. If |annotate_dom_model_service| is not nullptr,
+ // must be valid for the lifetime of the instance.
ElementFinder(content::WebContents* web_contents,
DevtoolsClient* devtools_client,
const UserData* user_data,
ProcessedActionStatusDetailsProto* log_info,
+ AnnotateDomModelService* annotate_dom_model_service,
const Selector& selector,
ResultType result_type);
~ElementFinder() override;
@@ -105,87 +111,24 @@ class ElementFinder : public WebControllerWorker {
void Start(const Result& start_element, Callback callback);
private:
- // Helper for building JavaScript functions.
- //
- // TODO(b/155264465): extract this into a top-level class in its own file, so
- // it can be tested.
- class JsFilterBuilder {
- public:
- JsFilterBuilder();
- ~JsFilterBuilder();
-
- // Builds the argument list for the function.
- std::vector<std::unique_ptr<runtime::CallArgument>> BuildArgumentList()
- const;
-
- // Return the JavaScript function.
- std::string BuildFunction() const;
-
- // Adds a filter, if possible.
- bool AddFilter(const SelectorProto::Filter& filter);
-
- private:
- std::vector<std::string> arguments_;
- JsSnippet snippet_;
- bool defined_query_all_deduplicated_ = false;
-
- // A number that's increased by each call to DeclareVariable() to make sure
- // we generate unique variables.
- int variable_counter_ = 0;
-
- // Adds a regexp filter.
- void AddRegexpFilter(const TextFilter& filter, const std::string& property);
-
- // Declares and initializes a variable containing a RegExp object that
- // correspond to |filter| and returns the variable name.
- std::string AddRegexpInstance(const TextFilter& filter);
-
- // Returns the name of a new unique variable.
- std::string DeclareVariable();
-
- // Adds an argument to the argument list and returns its JavaScript
- // representation.
- //
- // This allows passing strings to the JavaScript code without having to
- // hardcode and escape them - this helps avoid XSS issues.
- std::string AddArgument(const std::string& value);
-
- // Adds a line of JavaScript code to the function, between the header and
- // footer. At that point, the variable "elements" contains the current set
- // of matches, as an array of nodes. It should be updated to contain the new
- // set of matches.
- //
- // IMPORTANT: Only pass strings that originate from hardcoded strings to
- // this method.
- void AddLine(const std::string& line) { snippet_.AddLine(line); }
-
- // Adds a line of JavaScript code to the function that's made up of multiple
- // parts to be concatenated together.
- //
- // IMPORTANT: Only pass strings that originate from hardcoded strings to
- // this method.
- void AddLine(const std::vector<std::string>& line) {
- snippet_.AddLine(line);
- }
+ // Update the log info with details about the current run.
+ void UpdateLogInfo(const Result& result, const ClientStatus& status);
- // Define a |queryAllDeduplicated(roots, selector)| JS function that calls
- // querySelectorAll(selector) on all |roots| (in order) and returns a
- // deduplicated list of the matching elements.
- // Calling this function a second time does not do anything; the function
- // will be defined only once.
- void DefineQueryAllDeduplicated();
- };
+ // Eventually returns the given status and no element. This expects an error
+ // status.
+ void GiveUpElementResolutionWithError(const ClientStatus& status);
- // Update the log info with details about the current run.
- void UpdateLogInfo(const ClientStatus& status);
+ // Builds a result from the current state of the finder and eventually
+ // returns it with an ok status.
+ void ResultFound(const std::string& object_id);
- // Sends a result with the given status and no data. This expects an error
- // status and will add details to |log_info_|.
- void SendErrorResult(const ClientStatus& status);
+ // Call |callback_| with the |status| and |result|.
+ void SendResult(const ClientStatus& status, const Result& result);
- // Builds a result from the current state of the finder and returns it. This
- // will add details to |log_info_|.
- void SendSuccessResult(const std::string& object_id);
+ // Calls |SendResult| with a the |result_status_| and |result_| if all tasks
+ // are complete. This includes waiting for the CSS selector resolution and
+ // the annotate DOM model inference (if applicable).
+ void SendCollectedResultIfAny();
// Report |object_id| as result in |result| and initialize the frame-related
// fields of |result| from the current state. Leaves the frame stack empty.
@@ -323,10 +266,29 @@ class ElementFinder : public WebControllerWorker {
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::CallFunctionOnResult> result);
+ // Helpers for running the annotate DOM model on all frames. The results will
+ // be compared against |result_| and logged to |log_info_|.
+ void DescribeNodeForAnnotateDom();
+ void OnDescribeNodeForAnnotateDom(
+ const DevtoolsClient::ReplyStatus& reply_status,
+ std::unique_ptr<dom::DescribeNodeResult> node_result);
+ void RunAnnotateDomModel();
+ void RunAnnotateDomModelOnFrame(
+ const content::GlobalRenderFrameHostId& host_id,
+ base::OnceCallback<void(std::vector<GlobalBackendNodeId>)> callback);
+ void OnRunAnnotateDomModelOnFrame(
+ const content::GlobalRenderFrameHostId& host_id,
+ base::OnceCallback<void(std::vector<GlobalBackendNodeId>)> callback,
+ bool success,
+ const std::vector<NodeData>& node_data);
+ void OnRunAnnotateDomModel(
+ const std::vector<std::vector<GlobalBackendNodeId>>& all_nodes);
+
const raw_ptr<content::WebContents> web_contents_;
const raw_ptr<DevtoolsClient> devtools_client_;
const raw_ptr<const UserData> user_data_;
const raw_ptr<ProcessedActionStatusDetailsProto> log_info_;
+ const raw_ptr<AnnotateDomModelService> annotate_dom_model_service_;
const Selector selector_;
const ResultType result_type_;
Callback callback_;
@@ -370,6 +332,24 @@ class ElementFinder : public WebControllerWorker {
std::vector<JsObjectIdentifier> frame_stack_;
+ // The status of finding the element.
+ ClientStatus result_status_;
+
+ // The successful result when the element has been found. In the case where
+ // |selector_| contains |SemanticInformation| this is only filled once the
+ // backend node id has been resolved.
+ Result result_ = Result::EmptyResult();
+ // The backend node id (stable id of DevTools) for the |result_|. Only
+ // filled if the |selector_| contains |SemanticInformation|.
+ // TODO(b/217160707): Always fill this.
+ absl::optional<int> result_backend_node_id_;
+ bool css_result_done_ = false;
+
+ // Elements gathered through all frames. Unused if the |selector_| does not
+ // contain |SemanticInformation|.
+ std::vector<GlobalBackendNodeId> semantic_node_results_;
+ bool semantic_result_done_ = false;
+
// Finder for the target of the current proximity filter.
std::unique_ptr<ElementFinder> proximity_target_filter_;
diff --git a/chromium/components/autofill_assistant/browser/web/element_rect_getter.cc b/chromium/components/autofill_assistant/browser/web/element_rect_getter.cc
index dd6337c29c1..b5e05f3acce 100644
--- a/chromium/components/autofill_assistant/browser/web/element_rect_getter.cc
+++ b/chromium/components/autofill_assistant/browser/web/element_rect_getter.cc
@@ -84,7 +84,7 @@ void ElementRectGetter::OnGetClientRectResult(
CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__);
if (!status.ok() || !result->GetResult()->HasValue() ||
!result->GetResult()->GetValue()->is_list() ||
- result->GetResult()->GetValue()->GetList().size() != 4u) {
+ result->GetResult()->GetValue()->GetListDeprecated().size() != 4u) {
VLOG(2) << __func__ << " Failed to get element rect: " << status;
std::move(callback).Run(
JavaScriptErrorStatus(reply_status, __FILE__, __LINE__, nullptr),
@@ -92,7 +92,7 @@ void ElementRectGetter::OnGetClientRectResult(
return;
}
- const auto& list = result->GetResult()->GetValue()->GetList();
+ const auto& list = result->GetResult()->GetValue()->GetListDeprecated();
// Value::GetDouble() is safe to call without checking the value type; it'll
// return 0.0 if the value has the wrong type.
diff --git a/chromium/components/autofill_assistant/browser/web/js_filter_builder.cc b/chromium/components/autofill_assistant/browser/web/js_filter_builder.cc
new file mode 100644
index 00000000000..3be18b997e1
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/web/js_filter_builder.cc
@@ -0,0 +1,223 @@
+// Copyright 2022 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.
+
+#include "components/autofill_assistant/browser/web/js_filter_builder.h"
+
+#include <memory>
+#include <string>
+
+#include "base/strings/strcat.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/values.h"
+#include "components/autofill_assistant/browser/devtools/devtools/domains/types_runtime.h"
+#include "components/autofill_assistant/browser/service.pb.h"
+#include "components/autofill_assistant/browser/user_data_util.h"
+
+namespace autofill_assistant {
+
+JsFilterBuilder::JsFilterBuilder() = default;
+JsFilterBuilder::~JsFilterBuilder() = default;
+
+std::unique_ptr<base::Value> JsFilterBuilder::BuildArgumentArray() const {
+ auto str_array_arg = std::make_unique<base::Value>(base::Value::Type::LIST);
+ for (const std::string& str : arguments_) {
+ str_array_arg->Append(str);
+ }
+ return str_array_arg;
+}
+
+std::vector<std::unique_ptr<runtime::CallArgument>>
+JsFilterBuilder::BuildArgumentList() const {
+ std::vector<std::unique_ptr<runtime::CallArgument>> arguments;
+ arguments.emplace_back(
+ runtime::CallArgument::Builder().SetValue(BuildArgumentArray()).Build());
+ return arguments;
+}
+
+// clang-format off
+std::string JsFilterBuilder::BuildFunction() const {
+ return base::StrCat({
+ R"(
+ function(args) {
+ let elements = [this];
+ )",
+ snippet_.ToString(),
+ R"(
+ if (elements.length == 0) return null;
+ if (elements.length == 1) { return elements[0] }
+ return elements;
+ })"
+ });
+}
+// clang-format on
+
+bool JsFilterBuilder::AddFilter(const SelectorProto::Filter& filter) {
+ switch (filter.filter_case()) {
+ case SelectorProto::Filter::kCssSelector:
+ // We querySelectorAll the current elements and remove duplicates, which
+ // are likely when using inner text before CSS selector filters. We must
+ // not return duplicates as they cause incorrect TOO_MANY_ELEMENTS errors.
+ DefineQueryAllDeduplicated();
+ AddLine({"elements = queryAllDeduplicated(elements, ",
+ AddArgument(filter.css_selector()), ");"});
+ return true;
+
+ case SelectorProto::Filter::kInnerText:
+ AddRegexpFilter(filter.inner_text(), "innerText");
+ return true;
+
+ case SelectorProto::Filter::kValue:
+ AddRegexpFilter(filter.value(), "value");
+ return true;
+
+ case SelectorProto::Filter::kProperty:
+ AddRegexpFilter(filter.property().text_filter(),
+ filter.property().property());
+ return true;
+
+ case SelectorProto::Filter::kBoundingBox:
+ if (filter.bounding_box().require_nonempty()) {
+ AddLine("elements = elements.filter((e) => {");
+ AddLine(" const rect = e.getBoundingClientRect();");
+ AddLine(" return rect.width != 0 && rect.height != 0;");
+ AddLine("});");
+ } else {
+ AddLine(
+ "elements = elements.filter((e) => e.getClientRects().length > "
+ "0);");
+ }
+ return true;
+
+ case SelectorProto::Filter::kPseudoElementContent: {
+ // When a content is set, window.getComputedStyle().content contains a
+ // double-quoted string with the content, unquoted here by JSON.parse().
+ std::string re_var =
+ AddRegexpInstance(filter.pseudo_element_content().content());
+ std::string pseudo_type =
+ PseudoTypeName(filter.pseudo_element_content().pseudo_type());
+
+ AddLine("elements = elements.filter((e) => {");
+ AddLine({" const s = window.getComputedStyle(e, '", pseudo_type, "');"});
+ AddLine(" if (!s || !s.content || !s.content.startsWith('\"')) {");
+ AddLine(" return false;");
+ AddLine(" }");
+ AddLine({" return ", re_var, ".test(JSON.parse(s.content));"});
+ AddLine("});");
+ return true;
+ }
+
+ case SelectorProto::Filter::kCssStyle: {
+ std::string re_var = AddRegexpInstance(filter.css_style().value());
+ std::string property = AddArgument(filter.css_style().property());
+ std::string element = AddArgument(filter.css_style().pseudo_element());
+ AddLine("elements = elements.filter((e) => {");
+ AddLine(" const s = window.getComputedStyle(e, ");
+ AddLine({" ", element, " === '' ? null : ", element, ");"});
+ AddLine({" const match = ", re_var, ".test(s[", property, "]);"});
+ if (filter.css_style().should_match()) {
+ AddLine(" return match;");
+ } else {
+ AddLine(" return !match;");
+ }
+ AddLine("});");
+ return true;
+ }
+
+ case SelectorProto::Filter::kLabelled:
+ AddLine("elements = elements.flatMap((e) => {");
+ AddLine(
+ " return e.tagName === 'LABEL' && e.control ? [e.control] : [];");
+ AddLine("});");
+ return true;
+
+ case SelectorProto::Filter::kMatchCssSelector:
+ AddLine({"elements = elements.filter((e) => e.webkitMatchesSelector(",
+ AddArgument(filter.match_css_selector()), "));"});
+ return true;
+
+ case SelectorProto::Filter::kOnTop:
+ AddLine("elements = elements.filter((e) => {");
+ AddLine("if (e.getClientRects().length == 0) return false;");
+ if (filter.on_top().scroll_into_view_if_needed()) {
+ AddLine("e.scrollIntoViewIfNeeded(false);");
+ }
+ AddReturnIfOnTop(
+ &snippet_, "e", /* on_top= */ "true", /* not_on_top= */ "false",
+ /* not_in_view= */ filter.on_top().accept_element_if_not_in_view()
+ ? "true"
+ : "false");
+ AddLine("});");
+ return true;
+
+ case SelectorProto::Filter::kNthMatch: {
+ std::string index = base::NumberToString(filter.nth_match().index());
+ AddLine({"elements = ", index, " < elements.length ? [elements[", index,
+ "]] : [];"});
+ return true;
+ }
+
+ case SelectorProto::Filter::kEnterFrame:
+ case SelectorProto::Filter::kPseudoType:
+ case SelectorProto::Filter::FILTER_NOT_SET:
+ return false;
+ }
+}
+
+void JsFilterBuilder::ClearResultsIfMoreThanOneResult() {
+ AddLine("if (elements.length > 1) return [];");
+}
+
+std::string JsFilterBuilder::AddRegexpInstance(const TextFilter& filter) {
+ std::string re_flags = filter.case_sensitive() ? "" : "i";
+ std::string re_var = DeclareVariable();
+ AddLine({"const ", re_var, " = RegExp(", AddArgument(filter.re2()), ", '",
+ re_flags, "');"});
+ return re_var;
+}
+
+void JsFilterBuilder::AddRegexpFilter(const TextFilter& filter,
+ const std::string& property) {
+ std::string re_var = AddRegexpInstance(filter);
+ AddLine({"elements = elements.filter((e) => ", re_var, ".test(e.", property,
+ "));"});
+}
+
+std::string JsFilterBuilder::DeclareVariable() {
+ return base::StrCat({"v", base::NumberToString(variable_counter_++)});
+}
+
+std::string JsFilterBuilder::AddArgument(const std::string& value) {
+ int index = arguments_.size();
+ arguments_.emplace_back(value);
+ return base::StrCat({"args[", base::NumberToString(index), "]"});
+}
+
+void JsFilterBuilder::DefineQueryAllDeduplicated() {
+ // Ensure that we don't define the function more than once.
+ if (defined_query_all_deduplicated_)
+ return;
+
+ defined_query_all_deduplicated_ = true;
+
+ AddLine(R"(
+ const queryAllDeduplicated = function(roots, selector) {
+ if (roots.length == 0) {
+ return [];
+ }
+
+ const matchesSet = new Set();
+ const matches = [];
+ roots.forEach((root) => {
+ root.querySelectorAll(selector).forEach((elem) => {
+ if (!matchesSet.has(elem)) {
+ matchesSet.add(elem);
+ matches.push(elem);
+ }
+ });
+ });
+ return matches;
+ }
+ )");
+}
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/web/js_filter_builder.h b/chromium/components/autofill_assistant/browser/web/js_filter_builder.h
new file mode 100644
index 00000000000..67c350c863f
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/web/js_filter_builder.h
@@ -0,0 +1,87 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_JS_FILTER_BUILDER_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_JS_FILTER_BUILDER_H_
+
+#include <memory>
+#include <string>
+
+#include "components/autofill_assistant/browser/action_value.pb.h"
+#include "components/autofill_assistant/browser/devtools/devtools/domains/types_runtime.h"
+#include "components/autofill_assistant/browser/selector.h"
+#include "components/autofill_assistant/browser/service.pb.h"
+#include "components/autofill_assistant/browser/web/js_snippets.h"
+
+namespace autofill_assistant {
+// Helper for building JavaScript functions.
+//
+// TODO(b/213859457): add tests
+class JsFilterBuilder {
+ public:
+ JsFilterBuilder();
+ ~JsFilterBuilder();
+
+ // Builds the argument list for the function.
+ std::vector<std::unique_ptr<runtime::CallArgument>> BuildArgumentList() const;
+ std::unique_ptr<base::Value> BuildArgumentArray() const;
+
+ // Return the JavaScript function.
+ std::string BuildFunction() const;
+ // Adds a filter, if possible.
+ bool AddFilter(const SelectorProto::Filter& filter);
+ void ClearResultsIfMoreThanOneResult();
+
+ private:
+ std::vector<std::string> arguments_;
+ JsSnippet snippet_;
+ bool defined_query_all_deduplicated_ = false;
+
+ // A number that's increased by each call to DeclareVariable() to make sure
+ // we generate unique variables.
+ int variable_counter_ = 0;
+
+ // Adds a regexp filter.
+ void AddRegexpFilter(const TextFilter& filter, const std::string& property);
+
+ // Declares and initializes a variable containing a RegExp object that
+ // correspond to |filter| and returns the variable name.
+ std::string AddRegexpInstance(const TextFilter& filter);
+
+ // Returns the name of a new unique variable.
+ std::string DeclareVariable();
+
+ // Adds an argument to the argument list and returns its JavaScript
+ // representation.
+ //
+ // This allows passing strings to the JavaScript code without having to
+ // hardcode and escape them - this helps avoid XSS issues.
+ std::string AddArgument(const std::string& value);
+
+ // Adds a line of JavaScript code to the function, between the header and
+ // footer. At that point, the variable "elements" contains the current set
+ // of matches, as an array of nodes. It should be updated to contain the new
+ // set of matches.
+ //
+ // IMPORTANT: Only pass strings that originate from hardcoded strings to
+ // this method.
+ void AddLine(const std::string& line) { snippet_.AddLine(line); }
+
+ // Adds a line of JavaScript code to the function that's made up of multiple
+ // parts to be concatenated together.
+ //
+ // IMPORTANT: Only pass strings that originate from hardcoded strings to
+ // this method.
+ void AddLine(const std::vector<std::string>& line) { snippet_.AddLine(line); }
+
+ // Define a |queryAllDeduplicated(roots, selector)| JS function that calls
+ // querySelectorAll(selector) on all |roots| (in order) and returns a
+ // deduplicated list of the matching elements.
+ // Calling this function a second time does not do anything; the function
+ // will be defined only once.
+ void DefineQueryAllDeduplicated();
+};
+
+} // namespace autofill_assistant
+#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_JS_FILTER_BUILDER_H_
diff --git a/chromium/components/autofill_assistant/browser/web/mock_web_controller.cc b/chromium/components/autofill_assistant/browser/web/mock_web_controller.cc
index 6a1055e9bc1..05c205cd147 100644
--- a/chromium/components/autofill_assistant/browser/web/mock_web_controller.cc
+++ b/chromium/components/autofill_assistant/browser/web/mock_web_controller.cc
@@ -10,7 +10,8 @@ MockWebController::MockWebController()
: WebController(/* web_contents= */ nullptr,
/* devtools_client= */ nullptr,
/* user_data= */ nullptr,
- /* log_info= */ nullptr) {}
+ /* log_info= */ nullptr,
+ /* annotate_dom_model_service= */ nullptr) {}
MockWebController::~MockWebController() {}
} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/web/mock_web_controller.h b/chromium/components/autofill_assistant/browser/web/mock_web_controller.h
index 41236dedbe5..f0962ae3ef3 100644
--- a/chromium/components/autofill_assistant/browser/web/mock_web_controller.h
+++ b/chromium/components/autofill_assistant/browser/web/mock_web_controller.h
@@ -155,6 +155,10 @@ class MockWebController : public WebController {
base::TimeDelta)> callback));
MOCK_METHOD1(DispatchJsEvent,
void(base::OnceCallback<void(const ClientStatus&)> callback));
+ MOCK_METHOD3(ExecuteJS,
+ void(const std::string& snippet,
+ const ElementFinder::Result& element,
+ base::OnceCallback<void(const ClientStatus&)> callback));
base::WeakPtr<WebController> GetWeakPtr() const override {
return weak_ptr_factory_.GetWeakPtr();
diff --git a/chromium/components/autofill_assistant/browser/web/selector_observer.cc b/chromium/components/autofill_assistant/browser/web/selector_observer.cc
new file mode 100644
index 00000000000..317a3d4c2c8
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/web/selector_observer.cc
@@ -0,0 +1,903 @@
+// Copyright 2022 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.
+
+#include "components/autofill_assistant/browser/web/selector_observer.h"
+
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/callback_forward.h"
+#include "base/callback_helpers.h"
+#include "base/check.h"
+#include "base/json/json_writer.h"
+#include "base/logging.h"
+#include "base/notreached.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/time/time.h"
+#include "components/autofill_assistant/browser/action_value.pb.h"
+#include "components/autofill_assistant/browser/client_status.h"
+#include "components/autofill_assistant/browser/devtools/devtools/domains/types_dom.h"
+#include "components/autofill_assistant/browser/devtools/devtools/domains/types_runtime.h"
+#include "components/autofill_assistant/browser/devtools/devtools_client.h"
+#include "components/autofill_assistant/browser/user_data_util.h"
+#include "components/autofill_assistant/browser/web/element.h"
+#include "components/autofill_assistant/browser/web/js_filter_builder.h"
+#include "components/autofill_assistant/browser/web/selector_observer_script.h"
+#include "components/autofill_assistant/browser/web/web_controller.h"
+#include "components/autofill_assistant/browser/web/web_controller_util.h"
+#include "content/public/browser/web_contents.h"
+#include "js_snippets.h"
+#include "selector_observer.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace autofill_assistant {
+namespace {
+// Javascript code to get the document.
+const char kGetDocumentElement[] = "document";
+} // namespace
+
+SelectorObserver::ObservableSelector::ObservableSelector(
+ const SelectorId selector_id,
+ const SelectorProto& proto,
+ bool strict)
+ : selector_id(selector_id), proto(proto), strict(strict) {}
+SelectorObserver::ObservableSelector::~ObservableSelector() = default;
+SelectorObserver::ObservableSelector::ObservableSelector(
+ const ObservableSelector&) = default;
+
+SelectorObserver::Update::Update() = default;
+SelectorObserver::Update::~Update() = default;
+SelectorObserver::Update::Update(const Update&) = default;
+
+SelectorObserver::RequestedElement::RequestedElement(
+ const SelectorId& selector_id,
+ int element_id)
+ : selector_id(selector_id), element_id(element_id) {}
+SelectorObserver::RequestedElement::~RequestedElement() = default;
+SelectorObserver::RequestedElement::RequestedElement(const RequestedElement&) =
+ default;
+
+SelectorObserver::SelectorObserver(
+ const std::vector<ObservableSelector>& selectors,
+ base::TimeDelta max_wait_time,
+ base::TimeDelta periodic_check_interval,
+ base::TimeDelta extra_timeout,
+ content::WebContents* web_contents,
+ DevtoolsClient* devtools_client,
+ const UserData* user_data,
+ Callback update_callback)
+ : periodic_check_interval_(periodic_check_interval),
+ extra_timeout_(extra_timeout),
+ devtools_client_(devtools_client),
+ web_contents_(web_contents),
+ user_data_(user_data),
+ update_callback_(update_callback) {
+ const DomRoot root(/* frame_id = */ "", DomRoot::kUseMainDoc);
+ wait_time_remaining_ms_[root] = max_wait_time.InMilliseconds();
+ for (auto& selector : selectors) {
+ selectors_.emplace(std::make_pair(selector.selector_id, selector));
+ // Every selector starts in the root frame
+ dom_roots_.emplace(std::make_pair(selector.selector_id, 0), root);
+ }
+}
+
+SelectorObserver::~SelectorObserver() {
+ Stop();
+}
+
+ClientStatus SelectorObserver::Start(base::OnceClosure finished_callback) {
+ DCHECK(state_ == State::INITIALIZED);
+ finished_callback_ = std::move(finished_callback);
+ for (auto& selector : selectors_) {
+ auto result =
+ user_data::ResolveSelectorUserData(&selector.second.proto, user_data_);
+ if (!result.ok()) {
+ EnterState(State::ERROR);
+ return result;
+ }
+ }
+
+ EnterState(State::RUNNING);
+ const DomRoot root(/* frame_id = */ "", DomRoot::kUseMainDoc);
+ ResolveObjectIdAndInjectFrame(root, 0);
+
+ timeout_timer_ = std::make_unique<base::OneShotTimer>();
+ timeout_timer_->Start(FROM_HERE, MaxTimeRemaining() + extra_timeout_,
+ base::BindOnce(&SelectorObserver::OnHardTimeout,
+ weak_ptr_factory_.GetWeakPtr()));
+
+ return OkClientStatus();
+}
+
+void SelectorObserver::GetElementsAndStop(
+ const std::vector<RequestedElement>& requested_elements,
+ base::OnceCallback<void(
+ const ClientStatus&,
+ const base::flat_map<SelectorId, DomObjectFrameStack>&)> callback) {
+ DCHECK(state_ == State::RUNNING);
+ timeout_timer_.reset();
+ EnterState(State::FETCHING_ELEMENTS);
+ get_elements_callback_ = std::move(callback);
+ base::flat_map<DomRoot, std::vector<RequestedElement>> elements_by_dom_root;
+
+ for (auto& element : requested_elements) {
+ size_t depth = 0;
+ DomRoot leaf_dom_root;
+ auto it = dom_roots_.find(std::make_pair(element.selector_id, depth++));
+ DCHECK(it != dom_roots_.end()) << "Invalid selector_id";
+ while (it != dom_roots_.end()) {
+ leaf_dom_root = it->second;
+ it = dom_roots_.find(std::make_pair(element.selector_id, depth++));
+ }
+ elements_by_dom_root[leaf_dom_root].push_back(element);
+ }
+
+ pending_get_elements_responses_ = elements_by_dom_root.size();
+ for (auto& entry : elements_by_dom_root) {
+ std::vector<int> element_ids_list;
+ for (auto& element : entry.second) {
+ element_ids_list.push_back(element.element_id);
+ }
+ GetElementsByElementId(
+ entry.first, element_ids_list,
+ base::BindOnce(&SelectorObserver::OnGetElementsResponse,
+ weak_ptr_factory_.GetWeakPtr(), entry.first,
+ entry.second));
+ }
+ // In case there were no elements requested.
+ MaybeFinishedGettingElements();
+}
+
+void SelectorObserver::OnGetElementsResponse(
+ const DomRoot& dom_root,
+ const std::vector<RequestedElement>& elements,
+ const base::flat_map<int, std::string>& object_ids) {
+ if (state_ != State::FETCHING_ELEMENTS) {
+ return;
+ }
+ for (auto& element : elements) {
+ auto element_object_id_entry = object_ids.find(element.element_id);
+ if (element_object_id_entry == object_ids.end()) {
+ NOTREACHED();
+ FailWithError(UnexpectedErrorStatus(__FILE__, __LINE__));
+ return;
+ }
+ DomObjectFrameStack element_dom_object;
+ element_dom_object.object_data.object_id = element_object_id_entry->second;
+ element_dom_object.object_data.node_frame_id = dom_root.frame_id();
+
+ size_t depth = 1;
+ std::string prev_frame_id = "";
+ auto it = dom_roots_.find(std::make_pair(element.selector_id, depth++));
+ while (it != dom_roots_.end() && it->second != dom_root) {
+ auto entry = iframe_object_ids_.find(it->second);
+ if (entry != iframe_object_ids_.end()) {
+ JsObjectIdentifier frame;
+ frame.object_id = entry->second;
+ frame.node_frame_id = prev_frame_id;
+ element_dom_object.frame_stack.push_back(frame);
+ }
+ prev_frame_id = it->second.frame_id();
+ it = dom_roots_.find(std::make_pair(element.selector_id, depth++));
+ }
+ get_elements_response_[element.selector_id] = element_dom_object;
+ }
+ pending_get_elements_responses_--;
+ MaybeFinishedGettingElements();
+}
+
+void SelectorObserver::MaybeFinishedGettingElements() {
+ if (pending_get_elements_responses_ == 0) {
+ auto callback = std::move(get_elements_callback_);
+ auto response = get_elements_response_;
+ Stop();
+ // Entering TERMINATED state can destroy this.
+ EnterState(State::TERMINATED);
+ std::move(callback).Run(OkClientStatus(), response);
+ }
+}
+
+void SelectorObserver::Stop() {
+ while (!script_api_object_ids_.empty()) {
+ TerminateDomRoot(script_api_object_ids_.begin()->first);
+ }
+}
+
+void SelectorObserver::FailWithError(const ClientStatus& status) {
+ DCHECK(!status.ok());
+ VLOG(1) << "Selector observer failed: " << status;
+ if (state_ == State::RUNNING) {
+ update_callback_.Run(status, {}, this);
+ } else if (state_ == State::FETCHING_ELEMENTS) {
+ std::move(get_elements_callback_).Run(status, get_elements_response_);
+ }
+ timeout_timer_.reset();
+ EnterState(State::ERROR);
+}
+
+template <typename T>
+bool SelectorObserver::FailIfError(const DevtoolsClient::ReplyStatus& js_status,
+ const T* result,
+ const char* file,
+ int line) {
+ if (!js_status.is_ok()) {
+ FailWithError(UnexpectedErrorStatus(file, line));
+ return false;
+ }
+ auto status = CheckJavaScriptResult(js_status, result, file, line);
+ if (!status.ok()) {
+ FailWithError(status);
+ return false;
+ }
+ return true;
+}
+
+bool SelectorObserver::GetObjectId(const runtime::RemoteObject* result,
+ std::string* out,
+ const char* file,
+ int line) {
+ if (!SafeGetObjectId(result, out)) {
+ VLOG(1) << "Failed to get Object ID.";
+ FailWithError(UnexpectedErrorStatus(file, line));
+ return false;
+ }
+ return true;
+}
+
+void SelectorObserver::EnterState(State new_state) {
+ if (state_ == new_state)
+ return;
+ if (new_state < state_) {
+ NOTREACHED();
+ return;
+ }
+ VLOG(2) << " status " << static_cast<int>(state_) << " -> "
+ << static_cast<int>(new_state);
+ state_ = new_state;
+ if ((state_ == State::TERMINATED || state_ == State::ERROR) &&
+ finished_callback_) {
+ std::move(finished_callback_).Run();
+ }
+}
+
+ClientStatus SelectorObserver::CallSelectorObserverScriptApi(
+ const DomRoot& dom_root,
+ const std::string& function,
+ runtime::CallFunctionOnParams::CallFunctionOnParamsBuilder<0>&&
+ param_builder,
+ base::OnceCallback<void(const MessageDispatcher::ReplyStatus&,
+ std::unique_ptr<runtime::CallFunctionOnResult>)>
+ callback) {
+ auto entry = script_api_object_ids_.find(dom_root);
+ if (entry == script_api_object_ids_.end()) {
+ NOTREACHED();
+ return UnexpectedErrorStatus(__FILE__, __LINE__);
+ }
+ devtools_client_->GetRuntime()->CallFunctionOn(
+ param_builder.SetObjectId(entry->second)
+ .SetFunctionDeclaration(base::StrCat(
+ {"(function(...args) { return this.", function, "(...args); })"}))
+ .Build(),
+ dom_root.frame_id(), std::move(callback));
+ return OkClientStatus();
+}
+
+void SelectorObserver::TerminateDomRoot(const DomRoot& dom_root) {
+ CallSelectorObserverScriptApi(
+ dom_root, "terminate", runtime::CallFunctionOnParams::Builder(),
+ base::BindOnce(&SelectorObserver::OnTerminateDone,
+ weak_ptr_factory_.GetWeakPtr()));
+ script_api_object_ids_.erase(dom_root);
+}
+
+void SelectorObserver::OnTerminateDone(
+ const MessageDispatcher::ReplyStatus& js_status,
+ std::unique_ptr<runtime::CallFunctionOnResult> result) {
+ if (!VLOG_IS_ON(1))
+ return;
+
+ if (!js_status.is_ok()) {
+ VLOG(1) << "Failed to terminate: " << js_status.error_code;
+ }
+ auto status =
+ CheckJavaScriptResult(js_status, result.get(), __FILE__, __LINE__);
+ if (!status.ok()) {
+ VLOG(1) << "Failed to terminate: " << status;
+ }
+}
+
+void SelectorObserver::Continue() {
+ DCHECK(state_ == State::RUNNING);
+ for (auto& entry : script_api_object_ids_) {
+ AwaitChanges(entry.first);
+ }
+}
+
+void SelectorObserver::InjectOrAddSelectorsByParent(
+ const DomRoot& parent,
+ const std::string& object_id,
+ const std::vector<SelectorId>& selector_ids) {
+ devtools_client_->GetDOM()->DescribeNode(
+ dom::DescribeNodeParams::Builder().SetObjectId(object_id).Build(),
+ parent.frame_id(),
+ base::BindOnce(&SelectorObserver::OnDescribeNodeDone,
+ weak_ptr_factory_.GetWeakPtr(), parent, object_id,
+ selector_ids));
+}
+
+void SelectorObserver::OnDescribeNodeDone(
+ const DomRoot& parent,
+ const std::string& parent_object_id,
+ const std::vector<SelectorId>& selector_ids,
+ const MessageDispatcher::ReplyStatus& status,
+ std::unique_ptr<dom::DescribeNodeResult> result) {
+ if (!status.is_ok()) {
+ // TODO(b/205676462): It's possible .
+ FailWithError(UnexpectedErrorStatus(__FILE__, __LINE__));
+ return;
+ }
+ if (state_ != State::RUNNING) {
+ return;
+ }
+
+ int frame_depth = frame_depth_.at(parent) + 1;
+ auto* node = result->GetNode();
+ std::vector<int> backend_ids;
+ if (node->GetNodeName() == "IFRAME") {
+ // See: b/206647825
+ if (!node->HasFrameId()) {
+ NOTREACHED() << "Frame without ID"; // Ensure all frames have an id.
+ FailWithError(UnexpectedErrorStatus(__FILE__, __LINE__));
+ return;
+ }
+
+ DomRoot dom_root;
+ if (node->HasContentDocument()) {
+ // If the frame has a ContentDocument it's considered a local frame.
+ // In this case frame_id doesn't change.
+ dom_root = DomRoot(parent.frame_id(),
+ node->GetContentDocument()->GetBackendNodeId());
+ } else {
+ // OOP frame.
+ dom_root = DomRoot(node->GetFrameId(), DomRoot::kUseMainDoc);
+ }
+ iframe_object_ids_.emplace(dom_root, parent_object_id);
+ InjectOrAddSelectorsToDomRoot(dom_root, frame_depth, selector_ids);
+ } else if (node->HasShadowRoots()) {
+ // We aren't entering a frame but a shadow dom.
+ DomRoot dom_root(parent.frame_id(),
+ node->GetShadowRoots()->front()->GetBackendNodeId());
+ InjectOrAddSelectorsToDomRoot(dom_root, frame_depth, selector_ids);
+ }
+}
+
+void SelectorObserver::InjectOrAddSelectorsToDomRoot(
+ const DomRoot& dom_root,
+ size_t frame_depth,
+ const std::vector<SelectorId>& selector_ids) {
+ std::vector<SelectorId> new_selector_ids;
+ --pending_frame_injects_;
+
+ for (const auto& selector_id : selector_ids) {
+ auto key = std::make_pair(selector_id, frame_depth);
+ auto existing_entry = dom_roots_.find(key);
+ if (existing_entry != dom_roots_.end() &&
+ existing_entry->second == dom_root) {
+ continue;
+ }
+ new_selector_ids.push_back(selector_id);
+ dom_roots_[key] = dom_root;
+ // If we have changed a frame, all following frames in the chain are
+ // invalidated.
+ InvalidateDeeperFrames(selector_id, frame_depth + 1);
+ }
+ if (new_selector_ids.empty())
+ return;
+ TerminateUnneededDomRoots();
+
+ if (script_api_object_ids_.contains(dom_root)) {
+ // Frame known and we are injected into.
+ AddSelectorsToDomRoot(dom_root, new_selector_ids);
+ } else if (!frame_depth_.contains(dom_root)) {
+ // We haven't injected yet
+ wait_time_remaining_ms_[dom_root] =
+ std::max(1, static_cast<int>(MaxTimeRemaining().InMilliseconds()));
+ VLOG(2) << "Injecting into new frame";
+ ResolveObjectIdAndInjectFrame(dom_root, frame_depth);
+ }
+}
+
+void SelectorObserver::ResolveObjectIdAndInjectFrame(const DomRoot& dom_root,
+ size_t frame_depth) {
+ DCHECK(!frame_depth_.contains(dom_root));
+
+ frame_depth_.insert({dom_root, frame_depth});
+ if (dom_root.should_use_main_doc()) {
+ devtools_client_->GetRuntime()->Evaluate(
+ std::string(kGetDocumentElement), dom_root.frame_id(),
+ base::BindOnce(&SelectorObserver::OnGetDocumentElement,
+ weak_ptr_factory_.GetWeakPtr(), dom_root));
+ } else {
+ devtools_client_->GetDOM()->ResolveNode(
+ dom::ResolveNodeParams::Builder()
+ .SetBackendNodeId(dom_root.root_backend_node_id())
+ .Build(),
+ dom_root.frame_id(),
+ base::BindOnce(&SelectorObserver::OnResolveNode,
+ weak_ptr_factory_.GetWeakPtr(), dom_root));
+ }
+}
+
+void SelectorObserver::OnGetDocumentElement(
+ const DomRoot& dom_root,
+ const DevtoolsClient::ReplyStatus& status,
+ std::unique_ptr<runtime::EvaluateResult> result) {
+ if (state_ != State::RUNNING) {
+ return;
+ }
+ // TODO(b/205676462): Investigate if this can fail if we try to get a frame's
+ // document while the page is loading.
+ if (!FailIfError<runtime::EvaluateResult>(status, result.get(), __FILE__,
+ __LINE__)) {
+ return;
+ }
+ std::string object_id;
+ if (!GetObjectId(result->GetResult(), &object_id, __FILE__, __LINE__)) {
+ return;
+ }
+ InjectFrame(dom_root, object_id);
+}
+
+void SelectorObserver::OnResolveNode(
+ const DomRoot& dom_root,
+ const DevtoolsClient::ReplyStatus& status,
+ std::unique_ptr<dom::ResolveNodeResult> result) {
+ if (state_ != State::RUNNING) {
+ return;
+ }
+ if (!status.is_ok()) {
+ FailWithError(UnexpectedErrorStatus(__FILE__, __LINE__));
+ return;
+ }
+ std::string object_id;
+ if (!GetObjectId(result->GetObject(), &object_id, __FILE__, __LINE__)) {
+ return;
+ }
+ InjectFrame(dom_root, object_id);
+}
+
+void SelectorObserver::AddSelectorsToDomRoot(
+ const DomRoot& dom_root,
+ const std::vector<SelectorId>& selector_ids) {
+ auto entry = script_api_object_ids_.find(dom_root);
+ if (entry == script_api_object_ids_.end()) {
+ FailWithError(UnexpectedErrorStatus(__FILE__, __LINE__));
+ return;
+ }
+
+ std::string expr = BuildUpdateExpression(dom_root, selector_ids);
+ devtools_client_->GetRuntime()->CallFunctionOn(
+ runtime::CallFunctionOnParams::Builder()
+ .SetFunctionDeclaration(expr)
+ .SetReturnByValue(false)
+ .SetObjectId(entry->second)
+ .Build(),
+ /* optional_node_frame_id= */ dom_root.frame_id(), base::DoNothing());
+}
+
+void SelectorObserver::InjectFrame(const DomRoot& dom_root,
+ const std::string& object_id) {
+ DCHECK(!script_api_object_ids_.contains(dom_root));
+ DCHECK(frame_depth_.contains(dom_root));
+
+ auto expr = BuildExpression(dom_root);
+ devtools_client_->GetRuntime()->CallFunctionOn(
+ runtime::CallFunctionOnParams::Builder()
+ .SetFunctionDeclaration(expr)
+ .SetReturnByValue(false)
+ .SetObjectId(object_id)
+ .Build(),
+ /* optional_node_frame_id= */ dom_root.frame_id(),
+ base::BindOnce(&SelectorObserver::OnInjectFrame,
+ weak_ptr_factory_.GetWeakPtr(), dom_root));
+}
+
+void SelectorObserver::OnInjectFrame(
+ const DomRoot& dom_root,
+ const MessageDispatcher::ReplyStatus& status,
+ std::unique_ptr<runtime::CallFunctionOnResult> result) {
+ std::string object_id;
+ if (state_ != State::RUNNING) {
+ return;
+ }
+ if (!FailIfError<runtime::CallFunctionOnResult>(status, result.get(),
+ __FILE__, __LINE__)) {
+ return;
+ }
+ if (!GetObjectId(result->GetResult(), &object_id, __FILE__, __LINE__)) {
+ return;
+ }
+ script_api_object_ids_.emplace(dom_root, object_id);
+
+ AwaitChanges(dom_root);
+}
+
+void SelectorObserver::AwaitChanges(const DomRoot& dom_root) {
+ auto status = CallSelectorObserverScriptApi(
+ dom_root, "getChanges",
+ std::move(runtime::CallFunctionOnParams::Builder()
+ .SetAwaitPromise(true)
+ .SetReturnByValue(true)),
+ base::BindOnce(&SelectorObserver::OnHasChanges,
+ weak_ptr_factory_.GetWeakPtr(), dom_root));
+ if (!status.ok()) {
+ FailWithError(status);
+ }
+}
+
+void SelectorObserver::OnHasChanges(
+ const DomRoot& dom_root,
+ const MessageDispatcher::ReplyStatus& status,
+ std::unique_ptr<runtime::CallFunctionOnResult> result) {
+ if (state_ != State::RUNNING) {
+ return;
+ }
+ if (!FailIfError<runtime::CallFunctionOnResult>(status, result.get(),
+ __FILE__, __LINE__)) {
+ return;
+ }
+ DCHECK(result->GetResult()->HasValue());
+
+ const base::Value* value = result->GetResult()->GetValue();
+ VLOG(2) << "OnHasChanges: " << value->DebugString();
+ DCHECK(value->is_dict());
+ std::string response_status = value->FindKey("status")->GetString();
+ if (response_status == "listenerSuperseded") {
+ return;
+ } else if (response_status == "pageUnload") {
+ OnFrameUnloaded(dom_root);
+ return;
+ } else if (response_status == "timeout") {
+ wait_time_remaining_ms_[dom_root] = 0;
+ CheckTimeout();
+ return;
+ }
+ DCHECK_EQ(response_status, "update");
+
+ int wait_time_remaining = value->FindKey("waitTimeRemaining")->GetInt();
+ wait_time_remaining_ms_[dom_root] = wait_time_remaining;
+ const base::Value* updates_val = value->FindKey("updates");
+ DCHECK(updates_val->is_list());
+ auto update_list = updates_val->GetListDeprecated();
+ if (update_list.size() == 0) {
+ AwaitChanges(dom_root);
+ return;
+ }
+
+ bool invalidated_frames = false;
+ std::vector<Update> updates;
+ base::flat_map<int, std::vector<SelectorId>> frames_to_inject;
+ for (const auto& entry : update_list) {
+ SelectorId selector_id(entry.FindKey("selectorId")->GetInt());
+ auto element_id = entry.FindKey("elementId")->GetIfInt();
+ bool match = element_id.has_value();
+ bool is_leaf_frame = entry.FindKey("isLeafFrame")->GetBool();
+ if (is_leaf_frame || !match) {
+ Update& update = updates.emplace_back();
+ update.selector_id = selector_id;
+ update.element_id = element_id.has_value() ? element_id.value() : -1;
+ update.match = match;
+ if (!is_leaf_frame) { // No match in a non-leaf frame
+ InvalidateDeeperFrames(selector_id, dom_root);
+ invalidated_frames = true;
+ }
+ } else { // Match in a non-leaf frame
+ frames_to_inject[element_id.value()].emplace_back(selector_id);
+ }
+ }
+ if (invalidated_frames) {
+ TerminateUnneededDomRoots();
+ }
+ if (frames_to_inject.size()) {
+ std::vector<int> element_ids;
+ for (const auto& entry : frames_to_inject) {
+ element_ids.push_back(entry.first);
+ }
+ pending_frame_injects_ += element_ids.size();
+ GetElementsByElementId(
+ dom_root, element_ids,
+ base::BindOnce(&SelectorObserver::OnGetFramesObjectIds,
+ weak_ptr_factory_.GetWeakPtr(), dom_root,
+ frames_to_inject));
+ }
+ if (updates.size()) {
+ // Callbacks can delete `this`. The callback should call Continue() if
+ // needed.
+ update_callback_.Run(OkClientStatus(), updates, this);
+ } else {
+ AwaitChanges(dom_root);
+ }
+}
+
+void SelectorObserver::OnGetFramesObjectIds(
+ const DomRoot& dom_root,
+ const base::flat_map<int, std::vector<SelectorId>>& frames_to_inject,
+ const base::flat_map<int, std::string>& element_object_ids) {
+ if (state_ != State::RUNNING) {
+ return;
+ }
+ for (auto& entry : frames_to_inject) {
+ auto object_id_it = element_object_ids.find(entry.first);
+ if (object_id_it == element_object_ids.end()) {
+ NOTREACHED();
+ FailWithError(UnexpectedErrorStatus(__FILE__, __LINE__));
+ return;
+ }
+ InjectOrAddSelectorsByParent(/*parent*/ dom_root, object_id_it->second,
+ entry.second);
+ }
+}
+
+void SelectorObserver::GetElementsByElementId(
+ const DomRoot& dom_root,
+ const std::vector<int>& element_ids,
+ base::OnceCallback<void(const base::flat_map<int, std::string>&)>
+ callback) {
+ auto element_ids_list =
+ std::make_unique<base::Value>(base::Value::Type::LIST);
+ for (int id : element_ids) {
+ DCHECK(id >= 0);
+ element_ids_list->Append(id);
+ }
+ std::vector<std::unique_ptr<runtime::CallArgument>> arguments;
+ arguments.emplace_back(runtime::CallArgument::Builder()
+ .SetValue(std::move(element_ids_list))
+ .Build());
+ auto status = CallSelectorObserverScriptApi(
+ dom_root, "getElements",
+ std::move(runtime::CallFunctionOnParams::Builder()
+ .SetArguments(std::move(arguments))
+ .SetReturnByValue(false)),
+ base::BindOnce(&SelectorObserver::OnGetElementsByElementIdResult,
+ weak_ptr_factory_.GetWeakPtr(), dom_root,
+ std::move(callback)));
+ if (!status.ok()) {
+ FailWithError(status);
+ }
+}
+
+void SelectorObserver::OnGetElementsByElementIdResult(
+ const DomRoot& dom_root,
+ base::OnceCallback<void(const base::flat_map<int, std::string>&)> callback,
+ const MessageDispatcher::ReplyStatus& status,
+ std::unique_ptr<runtime::CallFunctionOnResult> result) {
+ if (state_ != State::RUNNING && state_ != State::FETCHING_ELEMENTS) {
+ return;
+ }
+ if (!FailIfError<runtime::CallFunctionOnResult>(status, result.get(),
+ __FILE__, __LINE__)) {
+ return;
+ }
+ std::string object_id;
+ if (!GetObjectId(result->GetResult(), &object_id, __FILE__, __LINE__)) {
+ return;
+ }
+ devtools_client_->GetRuntime()->GetProperties(
+ runtime::GetPropertiesParams::Builder()
+ .SetOwnProperties(true)
+ .SetObjectId(object_id)
+ .Build(),
+ dom_root.frame_id(),
+ base::BindOnce(&SelectorObserver::CallGetElementsByIdCallback,
+ weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+}
+
+void SelectorObserver::CallGetElementsByIdCallback(
+ base::OnceCallback<void(const base::flat_map<int, std::string>&)> callback,
+ const MessageDispatcher::ReplyStatus& status,
+ std::unique_ptr<runtime::GetPropertiesResult> result) {
+ if (state_ != State::RUNNING && state_ != State::FETCHING_ELEMENTS) {
+ return;
+ }
+ if (!FailIfError<runtime::GetPropertiesResult>(status, result.get(), __FILE__,
+ __LINE__)) {
+ return;
+ }
+ std::vector<std::pair<int, std::string>> object_ids_vector;
+ for (auto& prop : *result->GetResult()) {
+ std::string prop_object_id;
+ std::string name = prop->GetName();
+ if (!GetObjectId(prop->GetValue(), &prop_object_id, __FILE__, __LINE__)) {
+ return;
+ }
+ size_t id;
+ if (base::StringToSizeT(name, &id)) {
+ object_ids_vector.emplace_back(id, prop_object_id);
+ } else {
+ NOTREACHED();
+ }
+ }
+ base::flat_map<int, std::string> element_object_ids(object_ids_vector);
+ std::move(callback).Run(element_object_ids);
+}
+
+void SelectorObserver::OnFrameUnloaded(const DomRoot& dom_root) {
+ auto frame_depth_entry = frame_depth_.find(dom_root);
+ if (frame_depth_entry == frame_depth_.end())
+ return;
+ size_t frame_depth = frame_depth_entry->second;
+
+ std::vector<SelectorId> affected_selector_ids;
+ for (auto& entry : selectors_) {
+ const SelectorId& selector_id = entry.first;
+ auto dom_root_entry =
+ dom_roots_.find(std::make_pair(selector_id, frame_depth));
+ if (dom_root_entry == dom_roots_.end() ||
+ dom_root_entry->second != dom_root)
+ continue;
+ // Remove the unloaded frame and it's descendants
+ InvalidateDeeperFrames(selector_id, frame_depth);
+ affected_selector_ids.push_back(selector_id);
+ }
+
+ if (frame_depth >= 1 && affected_selector_ids.size() > 0) {
+ auto parent_it = dom_roots_.find(
+ std::make_pair(affected_selector_ids[0], frame_depth - 1));
+ if (parent_it == dom_roots_.end()) {
+ // This can happen if a frame unloaded had frames of it's own.
+ return;
+ }
+ // Re-add the parent frame selector to the parent frame. This causes us to
+ // receive an update from the frame element.
+ AddSelectorsToDomRoot(parent_it->second, affected_selector_ids);
+ }
+ TerminateUnneededDomRoots();
+}
+
+void SelectorObserver::InvalidateDeeperFrames(const SelectorId& selector_id,
+ const DomRoot& dom_root) {
+ auto frame_depth_entry = frame_depth_.find(dom_root);
+ if (frame_depth_entry == frame_depth_.end())
+ return;
+ size_t frame_depth = frame_depth_entry->second;
+ InvalidateDeeperFrames(selector_id, frame_depth + 1);
+}
+
+void SelectorObserver::InvalidateDeeperFrames(const SelectorId& selector_id,
+ size_t frame_depth) {
+ while (dom_roots_.erase(std::make_pair(selector_id, frame_depth)) == 1) {
+ ++frame_depth;
+ }
+}
+
+void SelectorObserver::TerminateUnneededDomRoots() {
+ std::set<DomRoot> unused_dom_roots;
+ for (const auto& entry : script_api_object_ids_) {
+ unused_dom_roots.insert(entry.first);
+ }
+ for (const auto& entry : dom_roots_) {
+ unused_dom_roots.erase(entry.second);
+ }
+ for (const DomRoot& dom_root : unused_dom_roots) {
+ TerminateDomRoot(dom_root);
+ }
+}
+
+void SelectorObserver::OnHardTimeout() {
+ // This timeout is unexpected, means something went wrong along the way. End
+ // with an error.
+ FailWithError(ClientStatus(TIMED_OUT));
+}
+
+base::TimeDelta SelectorObserver::MaxTimeRemaining() const {
+ int max = 0;
+ for (const auto& entry : wait_time_remaining_ms_) {
+ max = std::max(max, entry.second);
+ }
+ return base::Milliseconds(max);
+}
+
+void SelectorObserver::CheckTimeout() {
+ if (pending_frame_injects_ == 0 && MaxTimeRemaining().is_zero()) {
+ // We didn't didn't match the required condition in the allotted time. It
+ // could be expected from the script perspective.
+ FailWithError(ClientStatus(ELEMENT_RESOLUTION_FAILED));
+ }
+}
+
+std::string SelectorObserver::BuildExpression(const DomRoot& dom_root) const {
+ JsSnippet snippet;
+ snippet.AddLine("(function selectorObserver() {");
+ snippet.AddLine(
+ {"const pollInterval = ",
+ base::NumberToString(periodic_check_interval_.InMilliseconds()), ";"});
+ int max_wait_time = wait_time_remaining_ms_.at(dom_root);
+ snippet.AddLine({"const maxRuntime = ",
+ base::NumberToString(base::saturated_cast<int>(
+ (base::Milliseconds(max_wait_time) + extra_timeout_)
+ .InMilliseconds())),
+ ";"});
+ snippet.AddLine(
+ {"const maxWaitTime = ", base::NumberToString(max_wait_time), ";"});
+ snippet.AddLine("const selectors = [");
+
+ size_t depth = frame_depth_.at(dom_root);
+ for (const auto& entry : selectors_) {
+ auto frame_id_entry = dom_roots_.find(std::make_pair(entry.first, depth));
+ if (frame_id_entry == dom_roots_.end() ||
+ frame_id_entry->second != dom_root) {
+ continue;
+ }
+ SelectorObserver::SerializeSelector(entry.second.proto, entry.first,
+ entry.second.strict, depth, snippet);
+ }
+ snippet.AddLine("];"); // const selectors = [
+ snippet.AddLine(selector_observer_script::kWaitForChangeScript);
+ snippet.AddLine("})"); // (function selectorObserver() {
+
+ return snippet.ToString();
+}
+
+std::string SelectorObserver::BuildUpdateExpression(
+ const DomRoot& dom_root,
+ const std::vector<SelectorId>& selector_ids) const {
+ JsSnippet snippet;
+ snippet.AddLine("(function selectorObserverUpdate() {");
+ snippet.AddLine("const selectors = [");
+
+ size_t depth = frame_depth_.at(dom_root);
+ for (const auto& selector_id : selector_ids) {
+ auto frame_id_entry = dom_roots_.find(std::make_pair(selector_id, depth));
+ if (frame_id_entry == dom_roots_.end() ||
+ frame_id_entry->second != dom_root) {
+ NOTREACHED();
+ continue;
+ }
+ auto entry = selectors_.at(selector_id);
+ SelectorObserver::SerializeSelector(entry.proto, selector_id, entry.strict,
+ depth, snippet);
+ }
+ snippet.AddLine("];"); // const selectors = [
+ snippet.AddLine("this.addSelectors(selectors);");
+ snippet.AddLine("})"); // (function selectorObserverUpdate() {
+
+ return snippet.ToString();
+}
+
+void SelectorObserver::SerializeSelector(const SelectorProto& selector,
+ const SelectorId& selector_id,
+ bool strict,
+ size_t frame_depth,
+ JsSnippet& snippet) {
+ JsFilterBuilder builder;
+ int depth = frame_depth;
+ for (const auto& filter : selector.filters()) {
+ if (filter.filter_case() == SelectorProto::Filter::kEnterFrame) {
+ depth--;
+ } else if (depth == 0) {
+ builder.AddFilter(filter);
+ } else if (depth < 0) {
+ break;
+ }
+ }
+ bool is_leaf_frame = depth == 0;
+ if (strict && is_leaf_frame) {
+ builder.ClearResultsIfMoreThanOneResult();
+ }
+
+ snippet.AddLine("[");
+ snippet.AddLine(builder.BuildFunction());
+
+ base::Value metadata(base::Value::Type::DICTIONARY);
+ metadata.SetIntKey("selectorId", selector_id.value());
+ metadata.SetKey("args", std::move(*builder.BuildArgumentArray()));
+ metadata.SetBoolKey("isLeafFrame", is_leaf_frame);
+ std::string serialized_meta;
+ base::JSONWriter::Write(metadata, &serialized_meta);
+ snippet.AddLine({",", serialized_meta, "],"});
+}
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/web/selector_observer.h b/chromium/components/autofill_assistant/browser/web/selector_observer.h
new file mode 100644
index 00000000000..b3569ff84dd
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/web/selector_observer.h
@@ -0,0 +1,322 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_SELECTOR_OBSERVER_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_SELECTOR_OBSERVER_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/containers/flat_map.h"
+#include "base/strings/strcat.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
+#include "base/types/strong_alias.h"
+#include "components/autofill_assistant/browser/client_status.h"
+#include "components/autofill_assistant/browser/devtools/devtools/domains/types_runtime.h"
+#include "components/autofill_assistant/browser/devtools/devtools_client.h"
+#include "components/autofill_assistant/browser/devtools/message_dispatcher.h"
+#include "components/autofill_assistant/browser/service.pb.h"
+#include "components/autofill_assistant/browser/user_data.h"
+#include "components/autofill_assistant/browser/web/element.h"
+#include "components/autofill_assistant/browser/web/web_controller_worker.h"
+#include "content/public/browser/web_contents.h"
+#include "js_snippets.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace autofill_assistant {
+
+// Class to observe selectors. It received a list of selectors and a callback
+// that gets notified every time the match status of a selector changes. If a
+// selector matches, the callback also receives an identifier that can be
+// used to retrieve the matching DOM nodes the caller is interested in (Using
+// GetElementsAndStop).
+//
+// It works by splitting the Selectors into subsequences of filters separated
+// by EnterFrame filters and injecting a JavaScript script into the frames to
+// observe (using MutationObserver) the status of this subsequences. When the
+// match status or the matching element of the subsequences change, they send an
+// to OnHasChanges(). OnHasChanges() then sends the updates to the callback if
+// necessary.
+//
+// TODO(b/205676462): Implement pseudo elements.
+class SelectorObserver : public WebControllerWorker {
+ public:
+ using SelectorId = base::StrongAlias<class SelectorIdTag, size_t>;
+ // Used to request selectors to be observed.
+ struct ObservableSelector {
+ ObservableSelector(SelectorId selector_id,
+ const SelectorProto& proto,
+ bool strict);
+ ~ObservableSelector();
+ ObservableSelector(const ObservableSelector&);
+
+ // Id to reference this selector in the updates. It's chosen by the callers
+ // and can be any string as long as it's unique.
+ SelectorId selector_id;
+ SelectorProto proto;
+ // If true, match will fail if more that one element matches the selector.
+ bool strict;
+ };
+ // An update to the match status of a selector.
+ struct Update {
+ Update();
+ ~Update();
+ Update(const Update&);
+
+ // Selector identifier, same as the one in |ObservableSelector|.
+ SelectorId selector_id;
+ bool match;
+ // Identifier for the specific DOM node that matched. This can be used to
+ // fetch the element later.
+ int element_id;
+ };
+ struct RequestedElement {
+ RequestedElement(const SelectorId& selector_id, int element_id);
+ ~RequestedElement();
+ RequestedElement(const RequestedElement&);
+
+ // The id of the selector passed to |ObservableSelector|.
+ SelectorId selector_id;
+ // An identifier for a matching DOM node. Callers get it from
+ // an |Update| and copy it here if they want to fetch the element at the
+ // end.
+ int element_id;
+ };
+ using Callback = base::RepeatingCallback<
+ void(const ClientStatus&, const std::vector<Update>&, SelectorObserver*)>;
+
+ // |content::WebContents| and |DevtoolsClient| need to outlive this instance.
+ // |UserData| needs to exist until Start() is called.
+ explicit SelectorObserver(const std::vector<ObservableSelector>& selectors,
+ base::TimeDelta max_wait_time,
+ base::TimeDelta periodic_check_interval,
+ base::TimeDelta extra_timeout,
+ content::WebContents*,
+ DevtoolsClient*,
+ const UserData*,
+ Callback update_callback);
+
+ ~SelectorObserver() override;
+
+ // Calls the callbacks when the conditions (that can be tested using
+ // javascript) match, or after |timeout_ms|. The DevtoolsClient needs to
+ // outlive this instance.
+ ClientStatus Start(base::OnceClosure finished_callback);
+
+ // Continue watching for changes. Callbacks should call either Continue() or
+ // GetElementsAndStop().
+ void Continue();
+
+ // Convert |element_ids| to DomObjectFrameStacks.
+ void GetElementsAndStop(
+ const std::vector<RequestedElement>& element_ids,
+ base::OnceCallback<void(
+ const ClientStatus&,
+ const base::flat_map<SelectorId, DomObjectFrameStack>&)> callback);
+
+ private:
+ // A DomRoot is a root element of a document or a shadow DOM that we should
+ // observe. frame_id is the devtools frame id (empty string to use the main
+ // frame), root_backend_node_id is the backend_node_id of the root element to
+ // observe. In the case of the main frame or a OOP frame, root_backend_node_id
+ // can be set to kDomRootUseMainDoc, indicating to observe the document's root
+ // element.
+ struct DomRoot : public std::pair<std::string, int> {
+ constexpr static int kUseMainDoc = -1;
+
+ using std::pair<std::string, int>::pair;
+ const std::string& frame_id() const { return first; }
+ bool should_use_main_doc() const { return second == kUseMainDoc; }
+ int root_backend_node_id() const {
+ DCHECK(second != kUseMainDoc);
+ return second;
+ }
+ };
+ enum class State {
+ INITIALIZED = 0,
+ RUNNING = 1,
+ FETCHING_ELEMENTS = 2,
+ TERMINATED = 3,
+ ERROR = 4,
+ };
+ State state_ = State::INITIALIZED;
+ const base::TimeDelta periodic_check_interval_;
+ const base::TimeDelta extra_timeout_;
+ base::TimeDelta max_wait_time_;
+ base::TimeTicks started_;
+ std::unique_ptr<base::OneShotTimer> timeout_timer_;
+
+ base::flat_map<SelectorId, ObservableSelector> selectors_;
+ DevtoolsClient* devtools_client_;
+ content::WebContents* web_contents_;
+ const UserData* user_data_;
+ Callback update_callback_;
+ base::OnceClosure finished_callback_;
+
+ base::OnceCallback<void(
+ const ClientStatus&,
+ const base::flat_map<SelectorId, DomObjectFrameStack>&)>
+ get_elements_callback_;
+ int pending_frame_injects_ = 0;
+ int pending_get_elements_responses_;
+ base::flat_map<SelectorId, DomObjectFrameStack> get_elements_response_;
+
+ // Selector observer script api object id for each DomRoot
+ base::flat_map<DomRoot, std::string> script_api_object_ids_;
+
+ // Object id's of containing iframes
+ base::flat_map<DomRoot, std::string> iframe_object_ids_;
+
+ // Dom root for each selector's stretch: {selector_id, frame_depth} -> DomRoot
+ base::flat_map<std::pair<SelectorId, size_t>, DomRoot> dom_roots_;
+
+ // How deep is a frame (root = 0). frame_id -> depth
+ base::flat_map<DomRoot, size_t> frame_depth_;
+
+ base::flat_map<DomRoot, int> wait_time_remaining_ms_;
+
+ // Stop watching and free held resources.
+ void Stop();
+
+ void OnGetElementsResponse(
+ const DomRoot&,
+ const std::vector<RequestedElement>& elements,
+ const base::flat_map<int, std::string>& object_ids);
+ void MaybeFinishedGettingElements();
+
+ void FailWithError(const ClientStatus&);
+ template <typename T>
+ bool FailIfError(const DevtoolsClient::ReplyStatus& status,
+ const T* result,
+ const char* file,
+ int line);
+ bool GetObjectId(const runtime::RemoteObject* result,
+ std::string* out,
+ const char* file,
+ int line);
+ void EnterState(State status);
+
+ ClientStatus CallSelectorObserverScriptApi(
+ const DomRoot&,
+ const std::string& function,
+ runtime::CallFunctionOnParams::CallFunctionOnParamsBuilder<0>&&
+ param_builder,
+ base::OnceCallback<void(const MessageDispatcher::ReplyStatus&,
+ std::unique_ptr<runtime::CallFunctionOnResult>)>
+ callback);
+
+ // Remove observers from this DomRoot
+ void TerminateDomRoot(const DomRoot&);
+ void OnTerminateDone(const MessageDispatcher::ReplyStatus& status,
+ std::unique_ptr<runtime::CallFunctionOnResult> result);
+
+ void InjectFrame(const DomRoot&, const std::string& object_id);
+ void OnInjectFrame(const DomRoot&,
+ const MessageDispatcher::ReplyStatus&,
+ std::unique_ptr<runtime::CallFunctionOnResult>);
+
+ void InjectOrAddSelectorsByParent(
+ const DomRoot& parent,
+ const std::string& node_object_id,
+ const std::vector<SelectorId>& selector_ids);
+ void OnDescribeNodeDone(const DomRoot& parent,
+ const std::string& parent_object_id,
+ const std::vector<SelectorId>& selector_ids,
+ const MessageDispatcher::ReplyStatus&,
+ std::unique_ptr<dom::DescribeNodeResult> result);
+ void InjectOrAddSelectorsToDomRoot(
+ const DomRoot&,
+ size_t frame_depth,
+ const std::vector<SelectorId>& selector_ids);
+ void ResolveObjectIdAndInjectFrame(const DomRoot&, size_t frame_depth);
+ void InjectOrAddSelectorsToBackendId(
+ const DomRoot& parent,
+ int backend_id,
+ const std::vector<SelectorId>& selector_ids);
+
+ void OnGetDocumentElement(const DomRoot&,
+ const DevtoolsClient::ReplyStatus& status,
+ std::unique_ptr<runtime::EvaluateResult> result);
+
+ void OnResolveNode(const DomRoot&,
+ const DevtoolsClient::ReplyStatus& status,
+ std::unique_ptr<dom::ResolveNodeResult> result);
+ void OnResolveBackendId(const DevtoolsClient::ReplyStatus& reply_status,
+ std::unique_ptr<dom::ResolveNodeResult> result);
+ void AddSelectorsToDomRoot(const DomRoot&,
+ const std::vector<SelectorId>& selector_ids);
+
+ void AwaitChanges(const DomRoot&);
+
+ // Receives and processes changes form JavacScript. Updates have the format
+ // [{
+ // selectorId: string,
+ // isLeafFrame: bool,
+ // elementId: int
+ // }]
+ // |elementId| is unique within this DomRoot.
+ // |isLeafFrame| is true if this is the last frame of the selector, i.e., if
+ // true the referenced element is the element the selector is looking for,
+ // otherwise it's a frame we need to inject into in order to find the final
+ // element.
+ void OnHasChanges(const DomRoot&,
+ const MessageDispatcher::ReplyStatus&,
+ std::unique_ptr<runtime::CallFunctionOnResult>);
+
+ void OnGetFramesObjectIds(
+ const DomRoot&,
+ const base::flat_map<int, std::vector<SelectorId>>& frames_to_inject,
+ const base::flat_map<int, std::string>& element_object_ids);
+ void OnGetElements(
+ const DomRoot&,
+ const std::map<int, std::vector<std::string>> frames_to_inject,
+ const MessageDispatcher::ReplyStatus&,
+ std::unique_ptr<runtime::CallFunctionOnResult>);
+
+ void GetElementsByElementId(
+ const DomRoot&,
+ const std::vector<int>& element_ids,
+ base::OnceCallback<void(const base::flat_map<int, std::string>&)>
+ callback);
+ void OnGetElementsByElementIdResult(
+ const DomRoot&,
+ base::OnceCallback<void(const base::flat_map<int, std::string>&)>
+ callback,
+ const MessageDispatcher::ReplyStatus& status,
+ std::unique_ptr<runtime::CallFunctionOnResult> result);
+ void CallGetElementsByIdCallback(
+ base::OnceCallback<void(const base::flat_map<int, std::string>&)>
+ callback,
+ const MessageDispatcher::ReplyStatus& status,
+ std::unique_ptr<runtime::GetPropertiesResult> result);
+
+ void OnFrameUnloaded(const DomRoot&);
+ // Invalidates frames at `frame_depth` and deeper.
+ void InvalidateDeeperFrames(const SelectorId& selector_id,
+ size_t frame_depth);
+ // Invalidates frames after DomRoot, not including DomRoot.
+ void InvalidateDeeperFrames(const SelectorId& selector_id, const DomRoot&);
+
+ void TerminateUnneededDomRoots();
+ void OnHardTimeout();
+ void CheckTimeout();
+ base::TimeDelta MaxTimeRemaining() const;
+
+ std::string BuildExpression(const DomRoot&) const;
+ std::string BuildUpdateExpression(
+ const DomRoot&,
+ const std::vector<SelectorId>& selector_ids) const;
+ static void SerializeSelector(const SelectorProto& selector,
+ const SelectorId&,
+ bool strict,
+ size_t frame_depth,
+ JsSnippet& snippet);
+
+ base::WeakPtrFactory<SelectorObserver> weak_ptr_factory_{this};
+};
+} // namespace autofill_assistant
+
+#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_SELECTOR_OBSERVER_H_
diff --git a/chromium/components/autofill_assistant/browser/web/selector_observer_script.h b/chromium/components/autofill_assistant/browser/web/selector_observer_script.h
new file mode 100644
index 00000000000..f4207e521ba
--- /dev/null
+++ b/chromium/components/autofill_assistant/browser/web/selector_observer_script.h
@@ -0,0 +1,221 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_SELECTOR_OBSERVER_SCRIPT_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_SELECTOR_OBSERVER_SCRIPT_H_
+
+namespace autofill_assistant {
+namespace selector_observer_script {
+
+// Javascript comments are moved here so that they don't use up space.
+//
+// (1) selector_id -> element
+// (2) selector_id -> element
+// (3) element_id -> element
+// (4) uses setTimeout so that initialization isn't blocked checking the
+// selectors.
+// (5) In case c++ doesn't call terminate()
+// (7) A result is serializable by value. Unserializable elements are saved in
+// `pendingElements` and callers must retrieve them by calling
+// `getElements`.
+// (7) Hasn't changed so we don't need to update.
+// (8) Public API
+// (9) Returns a promise that fulfills whenever the status of a selector has
+// changed
+// (10) Listened twice for callbacks, send an empty update to the old one.
+// (11) Since the polling-based WaitForDom checks less often, this tries to
+// approximate the number of checks the polling-based WaitForDom would have
+// done so that the time they take when element is not found is
+// approximately equivalent.
+
+constexpr char kWaitForChangeScript[] = R"eof(
+ const UPDATE = "update";
+ const LISTENER_SUPERSEDED = "listenerSuperseded"
+ const PAGE_UNLOAD = "pageUnload";
+ const TIMEOUT = "timeout";
+
+ let pollingTid = null;
+ let hasChanges = false;
+ let pendingCallback = null;
+ const matchResults = {}; // (1)
+ const previousMatchResults = {}; // (2)
+ const rootElement = this;
+ const ownerWindow = (rootElement.ownerDocument || rootElement).defaultView;
+ const pendingElements = {}; // (3)
+ let nextElementId = 0;
+
+ const now = () => (new Date()).getTime();
+
+ ownerWindow.addEventListener("unload", () => {
+ if (pendingCallback) {
+ pendingCallback(PAGE_UNLOAD);
+ pendingCallback = null;
+ }
+ }, true);
+
+ const runSelector = (selector) => {
+ const [fn, { args }] = selector;
+ const startElement = rootElement.nodeType === Node.DOCUMENT_NODE
+ ? rootElement.documentElement
+ : rootElement;
+ const result = fn.call(startElement, args);
+ return Array.isArray(result) ? result[0] : result;
+ };
+
+ let checkCount = 0;
+ let selectorCheckTime = 0;
+ let startTime = null;
+
+ // (11)
+ const waitTimeApprox = () => {
+ const runTime = (now() - startTime);
+ const count = 1 + Math.floor(Math.min(runTime, maxWaitTime) / pollInterval);
+ const avgCheckTime = selectorCheckTime / checkCount;
+ return runTime - count * avgCheckTime;
+ };
+
+ const onChange = () => {
+ if (startTime == null) {
+ startTime = now();
+ }
+ checkCount += 1;
+ const start = now();
+ if (pollingTid) clearTimeout(pollingTid);
+ pollingTid = setTimeout(onChange, pollInterval);
+
+ for (const selector of selectors) {
+ const node = runSelector(selector);
+ const { selectorId } = selector[1];
+ if (node !== matchResults[selectorId]) {
+ matchResults[selectorId] = node;
+ hasChanges = true;
+ }
+ }
+
+ if (hasChanges && pendingCallback) {
+ pendingCallback(UPDATE);
+ pendingCallback = null;
+ }
+ const end = now();
+ selectorCheckTime += (end - start);
+ if (waitTimeApprox() >= maxWaitTime) {
+ if (pendingCallback) {
+ pendingCallback(TIMEOUT);
+ pendingCallback = null;
+ }
+ terminate();
+ }
+ };
+
+ const config = {
+ attributes: true,
+ childList: true,
+ subtree: true,
+ characterData: true,
+ };
+ const observer = new MutationObserver(onChange);
+ observer.observe(rootElement, config);
+ const terminate = () => {
+ observer.disconnect();
+ if (pollingTid) clearTimeout(pollingTid);
+ clearTimeout(disconnectTid);
+ };
+ // (4)
+ setTimeout(onChange, 0);
+ // (5)
+ const disconnectTid = setTimeout(terminate, maxRuntime);
+
+ const buildResult = () => {
+ // (6)
+ const updates = [];
+ const result = {
+ updates,
+ status: UPDATE,
+ waitTimeRemaining: (maxWaitTime - waitTimeApprox()) | 0,
+ timing: { checkCount, selectorCheckTime },
+ };
+ const indexes = new WeakMap();
+
+ selectors.forEach(([_, { selectorId, isLeafFrame }]) => {
+ const element = matchResults[selectorId];
+ if (selectorId in previousMatchResults &&
+ previousMatchResults[selectorId] == element) {
+ // (7)
+ return;
+ }
+ previousMatchResults[selectorId] = element;
+
+ if (element && !indexes.has(element)) {
+ const nextId = ++nextElementId;
+ indexes.set(element, nextId);
+ pendingElements[nextId] = element;
+ }
+ const elementId = element ? indexes.get(element) : null;
+
+ updates.push({
+ selectorId,
+ isLeafFrame,
+ elementId,
+ });
+ });
+
+ return result;
+ };
+
+ // (8)
+ return {
+ terminate,
+ addSelectors(selectors) {
+ selectors.forEach((selector) => {
+ const newSelectorId = selector[1].selectorId;
+ delete matchResults[newSelectorId];
+ delete previousMatchResults[newSelectorId];
+ if (!selectors.find(
+ ([_, { selectorId }]) => selectorId == newSelectorId)) {
+ selectors.push(selector);
+ }
+ });
+ onChange();
+ },
+ getElements(elementIds) {
+ const result = {};
+ elementIds.forEach((id) => {
+ result[id] = pendingElements[id];
+ });
+ return result;
+ },
+ // (9)
+ getChanges() {
+ if (hasChanges) {
+ hasChanges = false;
+ return Promise.resolve(buildResult());
+ }
+
+ if (pendingCallback) {
+ // (10)
+ pendingCallback(LISTENER_SUPERSEDED);
+ pendingCallback = null;
+ }
+
+ if (startTime && waitTimeApprox() >= maxWaitTime) {
+ return Promise.resolve({ status: TIMEOUT });
+ }
+
+ return (new Promise((fulfill) => {
+ pendingCallback = fulfill;
+ })).then((status) => {
+ if (status != UPDATE) {
+ return { status };
+ } else {
+ hasChanges = false;
+ return buildResult();
+ }
+ });
+ },
+ };
+)eof";
+
+} // namespace selector_observer_script
+} // namespace autofill_assistant
+#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_SELECTOR_OBSERVER_SCRIPT_H_
diff --git a/chromium/components/autofill_assistant/browser/web/web_controller.cc b/chromium/components/autofill_assistant/browser/web/web_controller.cc
index 74ad4dff653..1ea6aa14dff 100644
--- a/chromium/components/autofill_assistant/browser/web/web_controller.cc
+++ b/chromium/components/autofill_assistant/browser/web/web_controller.cc
@@ -7,6 +7,7 @@
#include <math.h>
#include <algorithm>
#include <ctime>
+#include <memory>
#include <utility>
#include "base/bind.h"
@@ -29,6 +30,8 @@
#include "components/autofill_assistant/browser/rectf.h"
#include "components/autofill_assistant/browser/string_conversions_util.h"
#include "components/autofill_assistant/browser/user_data_util.h"
+#include "components/autofill_assistant/browser/web/element.h"
+#include "components/autofill_assistant/browser/web/selector_observer.h"
#include "components/autofill_assistant/browser/web/web_controller_util.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
@@ -414,22 +417,26 @@ void DecorateControllerStatusWithValue(
std::unique_ptr<WebController> WebController::CreateForWebContents(
content::WebContents* web_contents,
const UserData* user_data,
- ProcessedActionStatusDetailsProto* log_info) {
+ ProcessedActionStatusDetailsProto* log_info,
+ AnnotateDomModelService* annotate_dom_model_service) {
return std::make_unique<WebController>(
web_contents,
std::make_unique<DevtoolsClient>(
content::DevToolsAgentHost::GetOrCreateFor(web_contents)),
- user_data, log_info);
+ user_data, log_info, annotate_dom_model_service);
}
-WebController::WebController(content::WebContents* web_contents,
- std::unique_ptr<DevtoolsClient> devtools_client,
- const UserData* user_data,
- ProcessedActionStatusDetailsProto* log_info)
+WebController::WebController(
+ content::WebContents* web_contents,
+ std::unique_ptr<DevtoolsClient> devtools_client,
+ const UserData* user_data,
+ ProcessedActionStatusDetailsProto* log_info,
+ AnnotateDomModelService* annotate_dom_model_service)
: web_contents_(web_contents),
devtools_client_(std::move(devtools_client)),
user_data_(user_data),
- log_info_(log_info) {}
+ log_info_(log_info),
+ annotate_dom_model_service_(annotate_dom_model_service) {}
WebController::~WebController() {}
@@ -515,7 +522,7 @@ void WebController::OnJavaScriptResultForStringArray(
return;
}
- auto values = remote_object->GetValue()->GetList();
+ auto values = remote_object->GetValue()->GetListDeprecated();
std::vector<std::string> v;
for (const base::Value& value : values) {
if (!value.is_string()) {
@@ -534,7 +541,7 @@ void WebController::OnJavaScriptResultForStringArray(
std::move(callback).Run(status, v);
}
-void WebController::ExecuteVoidJsWithoutArguments(
+void WebController::ExecuteJsWithoutArguments(
const ElementFinder::Result& element,
const std::string& js_snippet,
WebControllerErrorInfoProto::WebAction web_action,
@@ -543,14 +550,45 @@ void WebController::ExecuteVoidJsWithoutArguments(
runtime::CallFunctionOnParams::Builder()
.SetObjectId(element.object_id())
.SetFunctionDeclaration(js_snippet)
+ .SetReturnByValue(true)
+ .SetAwaitPromise(true)
.Build(),
element.node_frame_id(),
- base::BindOnce(&WebController::OnJavaScriptResult,
+ base::BindOnce(&WebController::OnExecuteJsWithoutArguments,
weak_ptr_factory_.GetWeakPtr(),
base::BindOnce(&DecorateWebControllerStatus, web_action,
std::move(callback))));
}
+void WebController::OnExecuteJsWithoutArguments(
+ base::OnceCallback<void(const ClientStatus&)> callback,
+ const DevtoolsClient::ReplyStatus& reply_status,
+ std::unique_ptr<runtime::CallFunctionOnResult> result) {
+ ClientStatus status =
+ CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__);
+ if (!status.ok()) {
+ DVLOG(1) << __func__ << " Failed JavaScript with status: " << status;
+ std::move(callback).Run(status);
+ return;
+ }
+
+ if (!result->GetResult() || !result->GetResult()->HasValue()) {
+ // No result means everything went as expected.
+ std::move(callback).Run(OkClientStatus());
+ return;
+ }
+ int value;
+ if (!SafeGetIntValue(result->GetResult(), &value) ||
+ !ProcessedActionStatusProto_IsValid(value)) {
+ // If a result is present, we expect it to be an integer.
+ std::move(callback).Run(ClientStatus(INVALID_ACTION));
+ return;
+ }
+
+ std::move(callback).Run(
+ ClientStatus(static_cast<ProcessedActionStatusProto>(value)));
+}
+
void WebController::ScrollIntoView(
const std::string& animation,
const std::string& vertical_alignment,
@@ -718,9 +756,9 @@ void WebController::OnWaitUntilElementIsStable(
void WebController::JsClickElement(
const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&)> callback) {
- ExecuteVoidJsWithoutArguments(element, std::string(kClickElementScript),
- WebControllerErrorInfoProto::JS_CLICK_ELEMENT,
- std::move(callback));
+ ExecuteJsWithoutArguments(element, std::string(kClickElementScript),
+ WebControllerErrorInfoProto::JS_CLICK_ELEMENT,
+ std::move(callback));
}
void WebController::ClickOrTapElement(
@@ -852,8 +890,8 @@ void WebController::RunElementFinder(const ElementFinder::Result& start_element,
ElementFinder::ResultType result_type,
ElementFinder::Callback callback) {
auto finder = std::make_unique<ElementFinder>(
- web_contents_, devtools_client_.get(), user_data_, log_info_, selector,
- result_type);
+ web_contents_, devtools_client_.get(), user_data_, log_info_,
+ annotate_dom_model_service_, selector, result_type);
auto* ptr = finder.get();
pending_workers_.emplace_back(std::move(finder));
@@ -873,6 +911,27 @@ void WebController::OnFindElementResult(
std::move(callback).Run(status, std::move(result));
}
+ClientStatus WebController::ObserveSelectors(
+ const std::vector<SelectorObserver::ObservableSelector>& selectors,
+ base::TimeDelta timeout_ms,
+ base::TimeDelta periodic_check_interval,
+ base::TimeDelta extra_timeout,
+ SelectorObserver::Callback callback) {
+ auto observer = std::make_unique<SelectorObserver>(
+ selectors, timeout_ms, periodic_check_interval, extra_timeout,
+ web_contents_, devtools_client_.get(), user_data_, std::move(callback));
+ auto* ptr = observer.get();
+ pending_workers_.emplace_back(std::move(observer));
+ return ptr->Start(base::BindOnce(&WebController::OnSelectorObserverFinished,
+ weak_ptr_factory_.GetWeakPtr(), ptr));
+}
+
+void WebController::OnSelectorObserverFinished(SelectorObserver* observer) {
+ base::EraseIf(pending_workers_, [observer](const auto& worker) {
+ return worker.get() == observer;
+ });
+}
+
void WebController::FillAddressForm(
std::unique_ptr<autofill::AutofillProfile> profile,
const ElementFinder::Result& element,
@@ -1252,9 +1311,9 @@ void WebController::GetStringAttribute(
void WebController::SelectFieldValue(
const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&)> callback) {
- ExecuteVoidJsWithoutArguments(element, std::string(kSelectFieldValueScript),
- WebControllerErrorInfoProto::SELECT_FIELD_VALUE,
- std::move(callback));
+ ExecuteJsWithoutArguments(element, std::string(kSelectFieldValueScript),
+ WebControllerErrorInfoProto::SELECT_FIELD_VALUE,
+ std::move(callback));
}
void WebController::SetValueAttribute(
@@ -1376,17 +1435,17 @@ void WebController::OnSendKeyboardInputDone(
void WebController::FocusField(
const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&)> callback) {
- ExecuteVoidJsWithoutArguments(element, std::string(kFocusFieldScript),
- WebControllerErrorInfoProto::FOCUS_FIELD,
- std::move(callback));
+ ExecuteJsWithoutArguments(element, std::string(kFocusFieldScript),
+ WebControllerErrorInfoProto::FOCUS_FIELD,
+ std::move(callback));
}
void WebController::BlurField(
const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&)> callback) {
- ExecuteVoidJsWithoutArguments(element, std::string(kBlurFieldScript),
- WebControllerErrorInfoProto::BLUR_FIELD,
- std::move(callback));
+ ExecuteJsWithoutArguments(element, std::string(kBlurFieldScript),
+ WebControllerErrorInfoProto::BLUR_FIELD,
+ std::move(callback));
}
void WebController::GetVisualViewport(
@@ -1409,14 +1468,14 @@ void WebController::OnGetVisualViewport(
CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__);
if (!status.ok() || !result->GetResult()->HasValue() ||
!result->GetResult()->GetValue()->is_list() ||
- result->GetResult()->GetValue()->GetList().size() != 4u) {
+ result->GetResult()->GetValue()->GetListDeprecated().size() != 4u) {
VLOG(1) << __func__ << " Failed to get visual viewport: " << status;
std::move(callback).Run(
JavaScriptErrorStatus(reply_status, __FILE__, __LINE__, nullptr),
RectF());
return;
}
- const auto& list = result->GetResult()->GetValue()->GetList();
+ const auto& list = result->GetResult()->GetValue()->GetListDeprecated();
// Value::GetDouble() is safe to call without checking the value type; it'll
// return 0.0 if the value has the wrong type.
@@ -1528,9 +1587,9 @@ void WebController::GetElementTag(
void WebController::SendChangeEvent(
const ElementFinder::Result& element,
base::OnceCallback<void(const ClientStatus&)> callback) {
- ExecuteVoidJsWithoutArguments(element, std::string(kSendChangeEventScript),
- WebControllerErrorInfoProto::SEND_CHANGE_EVENT,
- std::move(callback));
+ ExecuteJsWithoutArguments(element, std::string(kSendChangeEventScript),
+ WebControllerErrorInfoProto::SEND_CHANGE_EVENT,
+ std::move(callback));
}
void WebController::DispatchJsEvent(
@@ -1562,6 +1621,18 @@ void WebController::OnDispatchJsEvent(
std::move(callback).Run(status);
}
+void WebController::ExecuteJS(
+ const std::string& js_snippet,
+ const ElementFinder::Result& element,
+ base::OnceCallback<void(const ClientStatus&)> callback) {
+ // We do not add a leading newline to have consistent line numbers from
+ // errors. We cannot omit the trailing newline, in case the snippet ends
+ // with a comment.
+ ExecuteJsWithoutArguments(
+ element, base::StrCat({"function() { ", js_snippet, "\n}"}),
+ WebControllerErrorInfoProto::EXECUTE_JS, std::move(callback));
+}
+
base::WeakPtr<WebController> WebController::GetWeakPtr() const {
return weak_ptr_factory_.GetWeakPtr();
}
diff --git a/chromium/components/autofill_assistant/browser/web/web_controller.h b/chromium/components/autofill_assistant/browser/web/web_controller.h
index 013eb157f4c..62fe51f4e7a 100644
--- a/chromium/components/autofill_assistant/browser/web/web_controller.h
+++ b/chromium/components/autofill_assistant/browser/web/web_controller.h
@@ -14,7 +14,6 @@
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "components/autofill_assistant/browser/action_value.pb.h"
-#include "components/autofill_assistant/browser/batch_element_checker.h"
#include "components/autofill_assistant/browser/client_status.h"
#include "components/autofill_assistant/browser/devtools/devtools/domains/types_dom.h"
#include "components/autofill_assistant/browser/devtools/devtools/domains/types_input.h"
@@ -30,8 +29,10 @@
#include "components/autofill_assistant/browser/web/element_finder.h"
#include "components/autofill_assistant/browser/web/element_position_getter.h"
#include "components/autofill_assistant/browser/web/element_rect_getter.h"
+#include "components/autofill_assistant/browser/web/selector_observer.h"
#include "components/autofill_assistant/browser/web/send_keyboard_input_worker.h"
#include "components/autofill_assistant/browser/web/web_controller_worker.h"
+#include "components/autofill_assistant/content/browser/annotate_dom_model_service.h"
#include "content/public/browser/web_contents_observer.h"
#include "third_party/icu/source/common/unicode/umachine.h"
#include "url/gurl.h"
@@ -63,18 +64,22 @@ namespace autofill_assistant {
// multiple operations, whether in sequence or in parallel.
class WebController {
public:
- // Create web controller for a given |web_contents|. |user_data| must be valid
+ // Create web controller for a given |web_contents|. |user_data|, |log_info|
+ // and |annotate_dom_model_service| (if not nullptr) must be valid
// for the lifetime of the controller.
static std::unique_ptr<WebController> CreateForWebContents(
content::WebContents* web_contents,
const UserData* user_data,
- ProcessedActionStatusDetailsProto* log_info);
+ ProcessedActionStatusDetailsProto* log_info,
+ AnnotateDomModelService* annotate_dom_model_service);
- // |web_contents| and |user_data| must outlive this web controller.
+ // |web_contents|, |user_data|, |log_info| and |annotate_dom_model_service|
+ // (if not nullptr) must outlive this web controller.
WebController(content::WebContents* web_contents,
std::unique_ptr<DevtoolsClient> devtools_client,
const UserData* user_data,
- ProcessedActionStatusDetailsProto* log_info);
+ ProcessedActionStatusDetailsProto* log_info,
+ AnnotateDomModelService* annotate_dom_model_service);
WebController(const WebController&) = delete;
WebController& operator=(const WebController&) = delete;
@@ -106,6 +111,13 @@ class WebController {
virtual void FindAllElements(const Selector& selector,
ElementFinder::Callback callback);
+ virtual ClientStatus ObserveSelectors(
+ const std::vector<SelectorObserver::ObservableSelector>& selectors,
+ base::TimeDelta timeout_ms,
+ base::TimeDelta periodic_check_interval,
+ base::TimeDelta extra_timeout,
+ SelectorObserver::Callback callback);
+
// Scroll the |element| into view. |animation| defines the transition
// animation, |vertical_alignment| defines the vertical alignment,
// |horizontal_alignment| defines the horizontal alignment.
@@ -363,10 +375,18 @@ class WebController {
virtual void DispatchJsEvent(
base::OnceCallback<void(const ClientStatus&)> callback);
+ // Execute an arbitrary JS snippet on the |element|. `this` in the snippet
+ // will refer to the |element|.
+ virtual void ExecuteJS(
+ const std::string& js_snippet,
+ const ElementFinder::Result& element,
+ base::OnceCallback<void(const ClientStatus&)> callback);
+
virtual base::WeakPtr<WebController> GetWeakPtr() const;
private:
friend class WebControllerBrowserTest;
+ friend class BatchElementCheckerBrowserTest;
void OnJavaScriptResult(
base::OnceCallback<void(const ClientStatus&)> callback,
@@ -386,11 +406,15 @@ class WebController {
const std::vector<std::string>&)> callback,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::CallFunctionOnResult> result);
- void ExecuteVoidJsWithoutArguments(
+ void ExecuteJsWithoutArguments(
const ElementFinder::Result& element,
const std::string& js_snippet,
WebControllerErrorInfoProto::WebAction web_action,
base::OnceCallback<void(const ClientStatus&)> callback);
+ void OnExecuteJsWithoutArguments(
+ base::OnceCallback<void(const ClientStatus&)> callback,
+ const DevtoolsClient::ReplyStatus& reply_status,
+ std::unique_ptr<runtime::CallFunctionOnResult> result);
void OnScrollWindow(base::OnceCallback<void(const ClientStatus&)> callback,
const DevtoolsClient::ReplyStatus& reply_status,
std::unique_ptr<runtime::EvaluateResult> result);
@@ -414,6 +438,8 @@ class WebController {
ElementFinder::Callback callback,
const ClientStatus& status,
std::unique_ptr<ElementFinder::Result> result);
+
+ void OnSelectorObserverFinished(SelectorObserver* observer);
void OnFindElementForRetrieveElementFormAndFieldData(
base::OnceCallback<void(const ClientStatus&,
const autofill::FormData& form_data,
@@ -511,6 +537,8 @@ class WebController {
// Must not be |nullptr| and outlive this web controller.
const raw_ptr<const UserData> user_data_;
const raw_ptr<ProcessedActionStatusDetailsProto> log_info_;
+ // Can be |nullptr|, if not must outlive this web controller.
+ const raw_ptr<AnnotateDomModelService> annotate_dom_model_service_;
// Currently running workers.
std::vector<std::unique_ptr<WebControllerWorker>> pending_workers_;
diff --git a/chromium/components/autofill_assistant/browser/web/web_controller_browsertest.cc b/chromium/components/autofill_assistant/browser/web/web_controller_browsertest.cc
index 4307e76c6ad..fe5b7bbad15 100644
--- a/chromium/components/autofill_assistant/browser/web/web_controller_browsertest.cc
+++ b/chromium/components/autofill_assistant/browser/web/web_controller_browsertest.cc
@@ -4,50 +4,121 @@
#include "components/autofill_assistant/browser/web/web_controller.h"
-#include <chrono>
-#include <thread>
+#include <stddef.h>
+#include <iosfwd>
+#include <memory>
+#include <string>
+#include <type_traits>
+#include <vector>
#include "base/bind.h"
+#include "base/callback.h"
+#include "base/callback_forward.h"
#include "base/callback_helpers.h"
-#include "base/memory/ref_counted.h"
-#include "base/strings/strcat.h"
+#include "base/containers/checked_range.h"
+#include "base/location.h"
+#include "base/memory/raw_ptr.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/numerics/clamped_math.h"
+#include "base/run_loop.h"
+#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
+#include "base/task/single_thread_task_runner.h"
#include "base/test/bind.h"
+#include "base/test/gmock_callback_support.h"
+#include "base/test/mock_callback.h"
+#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
+#include "base/unguessable_token.h"
+#include "base/values.h"
+#include "components/autofill/core/browser/data_model/autofill_profile.h"
#include "components/autofill/core/browser/field_types.h"
+#include "components/autofill_assistant/browser/action_strategy.pb.h"
#include "components/autofill_assistant/browser/action_value.pb.h"
#include "components/autofill_assistant/browser/actions/wait_for_dom_action.h"
+#include "components/autofill_assistant/browser/base_browsertest.h"
+#include "components/autofill_assistant/browser/client_status.h"
+#include "components/autofill_assistant/browser/devtools/devtools/domains/runtime.h"
+#include "components/autofill_assistant/browser/devtools/devtools_client.h"
+#include "components/autofill_assistant/browser/dom_action.pb.h"
+#include "components/autofill_assistant/browser/fake_script_executor_ui_delegate.h"
#include "components/autofill_assistant/browser/mock_script_executor_delegate.h"
+#include "components/autofill_assistant/browser/model.pb.h"
+#include "components/autofill_assistant/browser/rectf.h"
#include "components/autofill_assistant/browser/script.h"
#include "components/autofill_assistant/browser/script_executor.h"
+#include "components/autofill_assistant/browser/selector.h"
#include "components/autofill_assistant/browser/service.pb.h"
#include "components/autofill_assistant/browser/string_conversions_util.h"
#include "components/autofill_assistant/browser/top_padding.h"
+#include "components/autofill_assistant/browser/trigger_context.h"
#include "components/autofill_assistant/browser/user_data.h"
#include "components/autofill_assistant/browser/user_model.h"
+#include "components/autofill_assistant/browser/web/element.h"
#include "components/autofill_assistant/browser/web/element_action_util.h"
#include "components/autofill_assistant/browser/web/element_finder.h"
+#include "components/autofill_assistant/browser/web/element_store.h"
+#include "components/autofill_assistant/content/common/autofill_assistant_agent.mojom.h"
+#include "components/autofill_assistant/content/common/node_data.h"
+#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_observer.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
-#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_utils.h"
#include "content/shell/browser/shell.h"
+#include "mojo/public/cpp/bindings/associated_receiver_set.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
#include "third_party/blink/public/common/switches.h"
+#include "url/gurl.h"
+#include "url/url_constants.h"
namespace autofill_assistant {
+namespace {
+using ::base::test::RunOnceCallback;
+using ::testing::_;
using ::testing::AnyOf;
using ::testing::IsEmpty;
using ::testing::Return;
-// Flag to enable site per process to enforce OOPIFs.
-const char* kSitePerProcess = "site-per-process";
-const char* kTargetWebsitePath = "/autofill_assistant_target_website.html";
+class MockAutofillAssistantAgent : public mojom::AutofillAssistantAgent {
+ public:
+ MockAutofillAssistantAgent() = default;
+ ~MockAutofillAssistantAgent() override = default;
+
+ void BindPendingReceiver(mojo::ScopedInterfaceEndpointHandle handle) {
+ receivers_.Add(
+ this, mojo::PendingAssociatedReceiver<mojom::AutofillAssistantAgent>(
+ std::move(handle)));
+ }
+
+ MOCK_METHOD(
+ void,
+ GetSemanticNodes,
+ (int32_t role,
+ int32_t objective,
+ base::OnceCallback<void(bool, const std::vector<NodeData>&)> callback),
+ (override));
+
+ private:
+ mojo::AssociatedReceiverSet<mojom::AutofillAssistantAgent> receivers_;
+};
-class WebControllerBrowserTest : public content::ContentBrowserTest,
+class FakeAnnotateDomModelService : public AnnotateDomModelService {
+ public:
+ FakeAnnotateDomModelService()
+ : AnnotateDomModelService(/* opt_guide= */ nullptr,
+ /* background_task_runner= */ nullptr) {}
+ ~FakeAnnotateDomModelService() override = default;
+};
+
+} // namespace
+
+class WebControllerBrowserTest : public autofill_assistant::BaseBrowserTest,
public content::WebContentsObserver {
public:
WebControllerBrowserTest() {}
@@ -57,33 +128,24 @@ class WebControllerBrowserTest : public content::ContentBrowserTest,
~WebControllerBrowserTest() override {}
- void SetUpCommandLine(base::CommandLine* command_line) override {
- command_line->AppendSwitch(kSitePerProcess);
- // Necessary to avoid flakiness or failure due to input arriving
- // before the first compositor commit.
- command_line->AppendSwitch(blink::switches::kAllowPreCommitInput);
- }
-
void SetUpOnMainThread() override {
- ContentBrowserTest::SetUpOnMainThread();
-
- // Start a mock server for hosting an OOPIF.
- http_server_iframe_ = std::make_unique<net::EmbeddedTestServer>(
- net::EmbeddedTestServer::TYPE_HTTP);
- http_server_iframe_->ServeFilesFromSourceDirectory(
- "components/test/data/autofill_assistant/html_iframe");
- ASSERT_TRUE(http_server_iframe_->Start(8081));
-
- // Start the main server hosting the test page.
- http_server_ = std::make_unique<net::EmbeddedTestServer>(
- net::EmbeddedTestServer::TYPE_HTTP);
- http_server_->ServeFilesFromSourceDirectory(
- "components/test/data/autofill_assistant/html");
- ASSERT_TRUE(http_server_->Start(8080));
- ASSERT_TRUE(
- NavigateToURL(shell(), http_server_->GetURL(kTargetWebsitePath)));
+ BaseBrowserTest::SetUpOnMainThread();
+
+ // Register the same agent on all frames, such that the callback can be
+ // mocked.
+ shell()->web_contents()->GetMainFrame()->ForEachRenderFrameHost(
+ base::BindLambdaForTesting([this](content::RenderFrameHost* host) {
+ host->GetRemoteAssociatedInterfaces()->OverrideBinderForTesting(
+ mojom::AutofillAssistantAgent::Name_,
+ base::BindRepeating(
+ &MockAutofillAssistantAgent::BindPendingReceiver,
+ base::Unretained(&autofill_assistant_agent_)));
+ }));
+
web_controller_ = WebController::CreateForWebContents(
- shell()->web_contents(), &user_data_, &log_info_);
+ shell()->web_contents(), &user_data_, &log_info_,
+ &annotate_dom_model_service_);
+
Observe(shell()->web_contents());
}
@@ -837,11 +899,11 @@ document.getElementById("overlay_in_frame").style.visibility='hidden';
[itemRect.top, itemRect.bottom, window.innerHeight,
containerRect.top, containerRect.bottom])")
.ExtractList();
- double top = eval_result.GetList()[0].GetDouble();
- double bottom = eval_result.GetList()[1].GetDouble();
- double window_height = eval_result.GetList()[2].GetDouble();
- double container_top = eval_result.GetList()[3].GetDouble();
- double container_bottom = eval_result.GetList()[4].GetDouble();
+ double top = eval_result.GetListDeprecated()[0].GetDouble();
+ double bottom = eval_result.GetListDeprecated()[1].GetDouble();
+ double window_height = eval_result.GetListDeprecated()[2].GetDouble();
+ double container_top = eval_result.GetListDeprecated()[3].GetDouble();
+ double container_bottom = eval_result.GetListDeprecated()[4].GetDouble();
// Element is at the desired position. (top is relative to the viewport)
EXPECT_NEAR(top, window_height * 0.25, 1);
@@ -860,15 +922,48 @@ document.getElementById("overlay_in_frame").style.visibility='hidden';
/* node_frame_id= */ std::string());
}
+ ClientStatus RunWaitForDom(
+ const ActionProto& wait_for_dom_action,
+ bool use_observers,
+ base::OnceCallback<void(ScriptExecutor*)> run_expectations) {
+ MockScriptExecutorDelegate mock_script_executor_delegate;
+ ON_CALL(mock_script_executor_delegate, GetWebController)
+ .WillByDefault(Return(web_controller_.get()));
+ TriggerContext trigger_context;
+ if (use_observers) {
+ trigger_context.SetScriptParameters(std::make_unique<ScriptParameters>(
+ base::flat_map<std::string, std::string>{
+ {"ENABLE_OBSERVER_WAIT_FOR_DOM", "true"}}));
+ }
+ ON_CALL(mock_script_executor_delegate, GetTriggerContext())
+ .WillByDefault(Return(&trigger_context));
+ std::vector<std::unique_ptr<Script>> ordered_interrupts;
+ FakeScriptExecutorUiDelegate fake_script_executor_ui_delegate;
+ ScriptExecutor script_executor(
+ /* script_path= */ std::string(), /* additional_context= */ nullptr,
+ /* global_payload= */ std::string(),
+ /* script_payload= */ std::string(),
+ /* listener= */ nullptr, &ordered_interrupts,
+ &mock_script_executor_delegate, &fake_script_executor_ui_delegate);
+
+ WaitForDomAction action(&script_executor, wait_for_dom_action);
+ base::RunLoop run_loop;
+ ClientStatus status;
+ action.ProcessAction(base::BindOnce(
+ &WebControllerBrowserTest::OnProcessedAction, base::Unretained(this),
+ run_loop.QuitClosure(), &status));
+ run_loop.Run();
+ std::move(run_expectations).Run(&script_executor);
+ return status;
+ }
+
protected:
std::unique_ptr<WebController> web_controller_;
UserData user_data_;
UserModel user_model_;
ProcessedActionStatusDetailsProto log_info_;
-
- private:
- std::unique_ptr<net::EmbeddedTestServer> http_server_;
- std::unique_ptr<net::EmbeddedTestServer> http_server_iframe_;
+ MockAutofillAssistantAgent autofill_assistant_agent_;
+ FakeAnnotateDomModelService annotate_dom_model_service_;
};
IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, ElementExistenceCheck) {
@@ -1568,8 +1663,8 @@ IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest,
let containerRect = container.getBoundingClientRect();
[itemRect.top, containerRect.top])")
.ExtractList();
- double element_top = eval_result.GetList()[0].GetDouble();
- double container_top = eval_result.GetList()[1].GetDouble();
+ double element_top = eval_result.GetListDeprecated()[0].GetDouble();
+ double container_top = eval_result.GetListDeprecated()[1].GetDouble();
// Element is at the desired position.
EXPECT_NEAR(element_top, container_top, 1);
@@ -1641,8 +1736,8 @@ IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest,
)")
.ExtractList();
- double top = eval_result.GetList()[0].GetDouble();
- double window_inner_height = eval_result.GetList()[1].GetDouble();
+ double top = eval_result.GetListDeprecated()[0].GetDouble();
+ double window_inner_height = eval_result.GetListDeprecated()[1].GetDouble();
EXPECT_NEAR(top, window_inner_height * 0.7, 1);
}
@@ -2893,16 +2988,6 @@ IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, FocusAndBlur) {
}
IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, WaitForDomForUniqueElement) {
- MockScriptExecutorDelegate mock_script_executor_delegate;
- ON_CALL(mock_script_executor_delegate, GetWebController)
- .WillByDefault(Return(web_controller_.get()));
- std::vector<std::unique_ptr<Script>> ordered_interrupts;
- ScriptExecutor script_executor(
- /* script_path= */ std::string(), /* additional_context= */ nullptr,
- /* global_payload= */ std::string(), /* script_payload= */ std::string(),
- /* listener= */ nullptr, &ordered_interrupts,
- &mock_script_executor_delegate);
-
ActionProto action_proto;
auto* wait_for_dom = action_proto.mutable_wait_for_dom();
auto* condition = wait_for_dom->mutable_wait_condition();
@@ -2911,29 +2996,19 @@ IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, WaitForDomForUniqueElement) {
// This element is unique.
*condition->mutable_match() = ToSelectorProto("#select");
- WaitForDomAction action(&script_executor, action_proto);
- base::RunLoop run_loop;
- ClientStatus status;
- action.ProcessAction(
- base::BindOnce(&WebControllerBrowserTest::OnProcessedAction,
- base::Unretained(this), run_loop.QuitClosure(), &status));
- run_loop.Run();
+ base::MockCallback<base::OnceCallback<void(ScriptExecutor*)>>
+ run_expectations;
+ EXPECT_CALL(run_expectations, Run(_))
+ .WillOnce([](ScriptExecutor* script_executor) {
+ EXPECT_TRUE(script_executor->GetElementStore()->HasElement("e"));
+ });
+ ClientStatus status = RunWaitForDom(action_proto, /* use_observers= */ false,
+ run_expectations.Get());
EXPECT_EQ(status.proto_status(), ACTION_APPLIED);
- EXPECT_TRUE(script_executor.GetElementStore()->HasElement("e"));
}
IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest,
WaitForDomForNonUniqueElement) {
- MockScriptExecutorDelegate mock_script_executor_delegate;
- ON_CALL(mock_script_executor_delegate, GetWebController)
- .WillByDefault(Return(web_controller_.get()));
- std::vector<std::unique_ptr<Script>> ordered_interrupts;
- ScriptExecutor script_executor(
- /* script_path= */ std::string(), /* additional_context= */ nullptr,
- /* global_payload= */ std::string(), /* script_payload= */ std::string(),
- /* listener= */ nullptr, &ordered_interrupts,
- &mock_script_executor_delegate);
-
ActionProto action_proto;
auto* wait_for_dom = action_proto.mutable_wait_for_dom();
auto* condition = wait_for_dom->mutable_wait_condition();
@@ -2942,15 +3017,35 @@ IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest,
// This element is not unique.
*condition->mutable_match() = ToSelectorProto("div");
- WaitForDomAction action(&script_executor, action_proto);
- base::RunLoop run_loop;
- ClientStatus status;
- action.ProcessAction(
- base::BindOnce(&WebControllerBrowserTest::OnProcessedAction,
- base::Unretained(this), run_loop.QuitClosure(), &status));
- run_loop.Run();
+ base::MockCallback<base::OnceCallback<void(ScriptExecutor*)>>
+ run_expectations;
+ EXPECT_CALL(run_expectations, Run(_))
+ .WillOnce([](ScriptExecutor* script_executor) {
+ EXPECT_FALSE(script_executor->GetElementStore()->HasElement("e"));
+ });
+ ClientStatus status = RunWaitForDom(action_proto, /* use_observers= */ false,
+ run_expectations.Get());
EXPECT_EQ(status.proto_status(), ELEMENT_RESOLUTION_FAILED);
- EXPECT_FALSE(script_executor.GetElementStore()->HasElement("e"));
+}
+
+IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest,
+ ObserverWaitForDomForUniqueElement) {
+ ActionProto action_proto;
+ auto* wait_for_dom = action_proto.mutable_wait_for_dom();
+ auto* condition = wait_for_dom->mutable_wait_condition();
+ condition->mutable_client_id()->set_identifier("e");
+ condition->set_require_unique_element(true);
+ // This element is unique.
+ *condition->mutable_match() = ToSelectorProto("#select");
+ base::MockCallback<base::OnceCallback<void(ScriptExecutor*)>>
+ run_expectations;
+ EXPECT_CALL(run_expectations, Run(_))
+ .WillOnce([](ScriptExecutor* script_executor) {
+ EXPECT_TRUE(script_executor->GetElementStore()->HasElement("e"));
+ });
+ ClientStatus status = RunWaitForDom(action_proto, /* use_observers= */ true,
+ run_expectations.Get());
+ EXPECT_EQ(status.proto_status(), ACTION_APPLIED);
}
IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, FindElementError) {
@@ -3044,4 +3139,135 @@ IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, RunElementFinderFromOOPIF) {
WaitForElementRemove(Selector({"#iframeExternal", "#div"}));
}
+IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, ExecuteJSForFocusAndBlur) {
+ ClientStatus element_status;
+ ElementFinder::Result element;
+ FindElement(Selector({"#input1"}), &element_status, &element);
+ EXPECT_EQ(ACTION_APPLIED, element_status.proto_status());
+
+ ClientStatus focus_status;
+ base::RunLoop focus_run_loop;
+ web_controller_->ExecuteJS(
+ "this.focus();", element,
+ base::BindOnce(&WebControllerBrowserTest::OnClientStatus,
+ base::Unretained(this), focus_run_loop.QuitClosure(),
+ &focus_status));
+ focus_run_loop.Run();
+ EXPECT_EQ(ACTION_APPLIED, focus_status.proto_status());
+ EXPECT_TRUE(
+ content::EvalJs(
+ shell(),
+ R"(document.activeElement === document.getElementById('input1'))")
+ .ExtractBool());
+
+ ClientStatus blur_status;
+ base::RunLoop blur_run_loop;
+ web_controller_->ExecuteJS(
+ "this.blur();", element,
+ base::BindOnce(&WebControllerBrowserTest::OnClientStatus,
+ base::Unretained(this), blur_run_loop.QuitClosure(),
+ &blur_status));
+ blur_run_loop.Run();
+ EXPECT_EQ(ACTION_APPLIED, blur_status.proto_status());
+ EXPECT_TRUE(
+ content::EvalJs(shell(), R"(document.activeElement === document.body)")
+ .ExtractBool());
+}
+
+IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, ExecuteJSWithClientStatus) {
+ ClientStatus element_status;
+ ElementFinder::Result element;
+ FindElement(Selector({"#input1"}), &element_status, &element);
+ EXPECT_EQ(ACTION_APPLIED, element_status.proto_status());
+
+ ClientStatus valid_result_status;
+ base::RunLoop valid_run_loop;
+ web_controller_->ExecuteJS(
+ "return 27; // ELEMENT_NOT_ON_TOP", element,
+ base::BindOnce(&WebControllerBrowserTest::OnClientStatus,
+ base::Unretained(this), valid_run_loop.QuitClosure(),
+ &valid_result_status));
+ valid_run_loop.Run();
+ EXPECT_EQ(ELEMENT_NOT_ON_TOP, valid_result_status.proto_status());
+
+ ClientStatus invalid_result_status;
+ base::RunLoop invalid_run_loop;
+ web_controller_->ExecuteJS(
+ "return -1;", element,
+ base::BindOnce(&WebControllerBrowserTest::OnClientStatus,
+ base::Unretained(this), invalid_run_loop.QuitClosure(),
+ &invalid_result_status));
+ invalid_run_loop.Run();
+ EXPECT_EQ(INVALID_ACTION, invalid_result_status.proto_status());
+}
+
+IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, ExecuteJSWithBadReturnValue) {
+ ClientStatus element_status;
+ ElementFinder::Result element;
+ FindElement(Selector({"#input1"}), &element_status, &element);
+ EXPECT_EQ(ACTION_APPLIED, element_status.proto_status());
+
+ ClientStatus result_status;
+ base::RunLoop run_loop;
+ web_controller_->ExecuteJS(
+ "return 'text';", element,
+ base::BindOnce(&WebControllerBrowserTest::OnClientStatus,
+ base::Unretained(this), run_loop.QuitClosure(),
+ &result_status));
+ run_loop.Run();
+ EXPECT_EQ(INVALID_ACTION, result_status.proto_status());
+}
+
+IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, ExecuteJSWithPromise) {
+ ClientStatus element_status;
+ ElementFinder::Result element;
+ FindElement(Selector({"#input1"}), &element_status, &element);
+ EXPECT_EQ(ACTION_APPLIED, element_status.proto_status());
+
+ ClientStatus success_status;
+ base::RunLoop success_run_loop;
+ web_controller_->ExecuteJS(
+ R"(
+ return new Promise((fulfill, reject) => {
+ fulfill();
+ });
+ )",
+ element,
+ base::BindOnce(&WebControllerBrowserTest::OnClientStatus,
+ base::Unretained(this), success_run_loop.QuitClosure(),
+ &success_status));
+ success_run_loop.Run();
+ EXPECT_EQ(ACTION_APPLIED, success_status.proto_status());
+
+ ClientStatus error_status;
+ base::RunLoop error_run_loop;
+ web_controller_->ExecuteJS(
+ R"(
+ return new Promise((fulfill, reject) => {
+ fulfill(27); // ELEMENT_NOT_ON_TOP
+ });
+ )",
+ element,
+ base::BindOnce(&WebControllerBrowserTest::OnClientStatus,
+ base::Unretained(this), error_run_loop.QuitClosure(),
+ &error_status));
+ error_run_loop.Run();
+ EXPECT_EQ(ELEMENT_NOT_ON_TOP, error_status.proto_status());
+
+ ClientStatus reject_status;
+ base::RunLoop reject_run_loop;
+ web_controller_->ExecuteJS(
+ R"(
+ return new Promise((fulfill, reject) => {
+ reject();
+ });
+ )",
+ element,
+ base::BindOnce(&WebControllerBrowserTest::OnClientStatus,
+ base::Unretained(this), reject_run_loop.QuitClosure(),
+ &reject_status));
+ reject_run_loop.Run();
+ EXPECT_EQ(UNEXPECTED_JS_ERROR, reject_status.proto_status());
+}
+
} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/browser/website_login_manager_impl.cc b/chromium/components/autofill_assistant/browser/website_login_manager_impl.cc
index 1193defaed6..be002db0fcf 100644
--- a/chromium/components/autofill_assistant/browser/website_login_manager_impl.cc
+++ b/chromium/components/autofill_assistant/browser/website_login_manager_impl.cc
@@ -500,7 +500,7 @@ void WebsiteLoginManagerImpl::ResetPendingCredentials() {
}
bool WebsiteLoginManagerImpl::ReadyToCommitSubmittedPassword() {
- return client_->GetPasswordManager()->IsFormManagerPendingPasswordUpdate();
+ return client_->GetPasswordManager()->HasSubmittedManager();
}
bool WebsiteLoginManagerImpl::SaveSubmittedPassword() {
diff --git a/chromium/components/autofill_assistant/browser/website_login_manager_impl_unittest.cc b/chromium/components/autofill_assistant/browser/website_login_manager_impl_unittest.cc
index dc72bf01a8c..b0ff929d804 100644
--- a/chromium/components/autofill_assistant/browser/website_login_manager_impl_unittest.cc
+++ b/chromium/components/autofill_assistant/browser/website_login_manager_impl_unittest.cc
@@ -10,6 +10,7 @@
#include "base/test/mock_callback.h"
#include "base/test/task_environment.h"
#include "components/password_manager/core/browser/mock_password_store_interface.h"
+#include "components/password_manager/core/browser/mock_webauthn_credentials_delegate.h"
#include "components/password_manager/core/browser/password_manager.h"
#include "components/password_manager/core/browser/password_store_consumer.h"
#include "components/password_manager/core/browser/password_store_interface.h"
@@ -55,15 +56,23 @@ class MockPasswordManagerClient
MockPasswordManagerClient() = default;
~MockPasswordManagerClient() override = default;
- MOCK_CONST_METHOD0(GetProfilePasswordStore,
- password_manager::PasswordStoreInterface*());
- MOCK_CONST_METHOD0(GetAccountPasswordStore,
- password_manager::PasswordStoreInterface*());
- MOCK_CONST_METHOD0(GetPasswordManager, PasswordManager*());
+ MOCK_METHOD(password_manager::PasswordStoreInterface*,
+ GetProfilePasswordStore,
+ (),
+ (const, override));
+ MOCK_METHOD(password_manager::PasswordStoreInterface*,
+ GetAccountPasswordStore,
+ (),
+ (const, override));
+ MOCK_METHOD(PasswordManager*, GetPasswordManager, (), (const, override));
MOCK_METHOD(bool,
IsSavingAndFillingEnabled,
(const GURL&),
(const, override));
+ MOCK_METHOD(password_manager::MockWebAuthnCredentialsDelegate*,
+ GetWebAuthnCredentialsDelegate,
+ (),
+ (override));
};
FormData MakeFormDataWithPasswordField() {
@@ -83,6 +92,30 @@ FormData MakeFormDataWithPasswordField() {
return form_data;
}
+FormData MakeFormDataWithUsernameAndPasswordField() {
+ FormData form_data;
+ form_data.url = GURL(kFakeUrl);
+ form_data.action = GURL(kFakeUrl);
+ form_data.name = kFormDataName;
+
+ FormFieldData field;
+ field.name = kUsernameElement;
+ field.id_attribute = field.name;
+ field.name_attribute = field.name;
+ field.value = kFakeUsername16;
+ field.form_control_type = "text";
+ form_data.fields.push_back(field);
+
+ field.name = kPasswordElement;
+ field.id_attribute = field.name;
+ field.name_attribute = field.name;
+ field.value = kFakePassword;
+ field.form_control_type = "password";
+ form_data.fields.push_back(field);
+
+ return form_data;
+}
+
PasswordForm MakeSimplePasswordForm() {
PasswordForm form;
form.url = GURL(kFakeUrl);
@@ -113,6 +146,12 @@ PasswordForm MakeSimplePasswordFormWithFormData() {
return form;
}
+PasswordForm MakeSimpleLoginFormWithFormData() {
+ PasswordForm form = MakeSimplePasswordForm();
+ form.form_data = MakeFormDataWithUsernameAndPasswordField();
+ return form;
+}
+
} // namespace
class WebsiteLoginManagerImplTest : public testing::Test {
@@ -151,6 +190,10 @@ class WebsiteLoginManagerImplTest : public testing::Test {
password_manager_ = std::make_unique<PasswordManager>(&client_);
ON_CALL(client_, GetPasswordManager())
.WillByDefault(Return(password_manager_.get()));
+ ON_CALL(client_, GetWebAuthnCredentialsDelegate())
+ .WillByDefault(Return(&webauthn_credentials_delegate_));
+ ON_CALL(webauthn_credentials_delegate_, IsWebAuthnAutofillEnabled)
+ .WillByDefault(Return(false));
}
password_manager::MockPasswordStoreInterface* store() {
@@ -167,6 +210,8 @@ class WebsiteLoginManagerImplTest : public testing::Test {
testing::NiceMock<MockPasswordManagerClient> client_;
std::unique_ptr<WebsiteLoginManagerImpl> manager_;
std::unique_ptr<PasswordManager> password_manager_;
+ testing::NiceMock<password_manager::MockWebAuthnCredentialsDelegate>
+ webauthn_credentials_delegate_;
password_manager::StubPasswordManagerDriver driver_;
scoped_refptr<password_manager::MockPasswordStoreInterface> profile_store_;
scoped_refptr<password_manager::MockPasswordStoreInterface> account_store_;
@@ -181,6 +226,11 @@ MATCHER_P(FormMatches, form, "") {
form.password_value == arg.password_value;
}
+ACTION_P(InvokeEmptyConsumerWithForms, store) {
+ arg0->OnGetPasswordStoreResultsFrom(
+ store, std::vector<std::unique_ptr<PasswordForm>>());
+}
+
TEST_F(WebsiteLoginManagerImplTest, SaveGeneratedPassword) {
password_manager::PasswordFormDigest form_digest(
password_manager::PasswordForm::Scheme::kHtml, kFakeUrl, GURL(kFakeUrl));
@@ -284,25 +334,25 @@ TEST_F(WebsiteLoginManagerImplTest, ResetPendingCredentials) {
PasswordForm form = MakeSimplePasswordFormWithFormData();
password_manager_->OnPasswordFormsParsed(&driver_, {form.form_data});
- EXPECT_FALSE(password_manager_->IsFormManagerPendingPasswordUpdate());
+ EXPECT_FALSE(password_manager_->HasSubmittedManager());
password_manager_->OnInformAboutUserInput(&driver_, form.form_data);
password_manager_->OnPasswordFormSubmitted(&driver_, form.form_data);
- EXPECT_TRUE(password_manager_->IsFormManagerPendingPasswordUpdate());
+ EXPECT_TRUE(password_manager_->HasSubmittedManager());
EXPECT_TRUE(password_manager_->GetSubmittedManagerForTest());
manager_->ResetPendingCredentials();
- EXPECT_FALSE(password_manager_->IsFormManagerPendingPasswordUpdate());
+ EXPECT_FALSE(password_manager_->HasSubmittedManager());
EXPECT_FALSE(password_manager_->GetSubmittedManagerForTest());
}
-TEST_F(WebsiteLoginManagerImplTest, SaveSubmittedPassword) {
+TEST_F(WebsiteLoginManagerImplTest, SaveSubmittedPasswordUpdate) {
EXPECT_CALL(client_, IsSavingAndFillingEnabled).WillRepeatedly(Return(true));
PasswordForm form(MakeSimplePasswordFormWithFormData());
password_manager_->OnPasswordFormsParsed(&driver_, {form.form_data});
- // The user updates the password.
+ // The user updates the password of a stored credential.
FormData updated_data(form.form_data);
updated_data.fields[0].value = u"updated_password";
password_manager_->OnInformAboutUserInput(&driver_, updated_data);
@@ -317,6 +367,46 @@ TEST_F(WebsiteLoginManagerImplTest, SaveSubmittedPassword) {
EXPECT_TRUE(manager_->SaveSubmittedPassword());
}
+TEST_F(WebsiteLoginManagerImplTest, SaveSubmittedPasswordEqualPassword) {
+ EXPECT_CALL(client_, IsSavingAndFillingEnabled).WillRepeatedly(Return(true));
+
+ PasswordForm form(MakeSimplePasswordFormWithFormData());
+ password_manager_->OnPasswordFormsParsed(&driver_, {form.form_data});
+
+ // The user submits an existing credential.
+ FormData non_updated_data(form.form_data);
+ non_updated_data.fields[0].value = kFakePassword;
+ password_manager_->OnInformAboutUserInput(&driver_, non_updated_data);
+ password_manager_->OnPasswordFormSubmitted(&driver_, non_updated_data);
+ EXPECT_TRUE(password_manager_->GetSubmittedManagerForTest());
+ EXPECT_TRUE(manager_->ReadyToCommitSubmittedPassword());
+
+ // The expected form with a the same password.
+ PasswordForm expected_form(form);
+ expected_form.password_value = non_updated_data.fields[0].value;
+ EXPECT_CALL(*store(), UpdateLogin(FormMatches(expected_form)));
+ EXPECT_TRUE(manager_->SaveSubmittedPassword());
+}
+
+TEST_F(WebsiteLoginManagerImplTest, SaveSubmittedPasswordNewLogin) {
+ EXPECT_CALL(client_, IsSavingAndFillingEnabled).WillRepeatedly(Return(true));
+ PasswordForm form(MakeSimpleLoginFormWithFormData());
+
+ EXPECT_CALL(*store(), GetLogins(_, _))
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms(store())));
+
+ // The user submits the an entirely new credential.
+ password_manager_->OnPasswordFormsParsed(&driver_, {form.form_data});
+ password_manager_->OnPasswordFormsRendered(&driver_, {form.form_data}, true);
+ password_manager_->OnPasswordFormSubmitted(&driver_, form.form_data);
+ EXPECT_TRUE(password_manager_->GetSubmittedManagerForTest());
+ EXPECT_TRUE(manager_->ReadyToCommitSubmittedPassword());
+
+ // Expect the password to get saved.
+ EXPECT_CALL(*store(), AddLogin(FormMatches(form)));
+ EXPECT_TRUE(manager_->SaveSubmittedPassword());
+}
+
TEST_F(WebsiteLoginManagerImplTest, SaveSubmittedPasswordFailure) {
EXPECT_CALL(client_, IsSavingAndFillingEnabled).WillRepeatedly(Return(true));
password_manager_->OnPasswordFormsParsed(&driver_,
diff --git a/chromium/components/autofill_assistant/content/browser/annotate_dom_model_service.cc b/chromium/components/autofill_assistant/content/browser/annotate_dom_model_service.cc
index 0bdec428f05..3c88e9a97fd 100644
--- a/chromium/components/autofill_assistant/content/browser/annotate_dom_model_service.cc
+++ b/chromium/components/autofill_assistant/content/browser/annotate_dom_model_service.cc
@@ -43,9 +43,11 @@ AnnotateDomModelService::AnnotateDomModelService(
optimization_guide::OptimizationGuideModelProvider* opt_guide,
const scoped_refptr<base::SequencedTaskRunner>& background_task_runner)
: opt_guide_(opt_guide), background_task_runner_(background_task_runner) {
- opt_guide_->AddObserverForOptimizationTargetModel(
- optimization_guide::proto::OPTIMIZATION_TARGET_AUTOFILL_ASSISTANT,
- /* model_metadata= */ absl::nullopt, this);
+ if (opt_guide_) {
+ opt_guide_->AddObserverForOptimizationTargetModel(
+ optimization_guide::proto::OPTIMIZATION_TARGET_AUTOFILL_ASSISTANT,
+ /* model_metadata= */ absl::nullopt, this);
+ }
}
AnnotateDomModelService::~AnnotateDomModelService() = default;
diff --git a/chromium/components/autofill_assistant/content/browser/content_autofill_assistant_driver.cc b/chromium/components/autofill_assistant/content/browser/content_autofill_assistant_driver.cc
index 5e23f9496da..0ceb2ad6cdb 100644
--- a/chromium/components/autofill_assistant/content/browser/content_autofill_assistant_driver.cc
+++ b/chromium/components/autofill_assistant/content/browser/content_autofill_assistant_driver.cc
@@ -18,6 +18,35 @@ ContentAutofillAssistantDriver::ContentAutofillAssistantDriver(
render_frame_host) {}
ContentAutofillAssistantDriver::~ContentAutofillAssistantDriver() = default;
+// static
+void ContentAutofillAssistantDriver::BindDriver(
+ mojo::PendingAssociatedReceiver<mojom::AutofillAssistantDriver>
+ pending_receiver,
+ content::RenderFrameHost* render_frame_host) {
+ DCHECK(render_frame_host);
+
+ auto* driver = ContentAutofillAssistantDriver::GetOrCreateForCurrentDocument(
+ render_frame_host);
+ if (driver) {
+ driver->BindPendingReceiver(std::move(pending_receiver));
+ }
+}
+
+// static
+ContentAutofillAssistantDriver*
+ContentAutofillAssistantDriver::GetOrCreateForRenderFrameHost(
+ content::RenderFrameHost* render_frame_host,
+ AnnotateDomModelService* annotate_dom_model_service) {
+ ContentAutofillAssistantDriver* driver =
+ ContentAutofillAssistantDriver::GetOrCreateForCurrentDocument(
+ render_frame_host);
+ if (driver) {
+ DCHECK(annotate_dom_model_service);
+ driver->annotate_dom_model_service_ = annotate_dom_model_service;
+ }
+ return driver;
+}
+
void ContentAutofillAssistantDriver::BindPendingReceiver(
mojo::PendingAssociatedReceiver<mojom::AutofillAssistantDriver>
pending_receiver) {
@@ -35,22 +64,17 @@ ContentAutofillAssistantDriver::GetAutofillAssistantAgent() {
return autofill_assistant_agent_;
}
-void ContentAutofillAssistantDriver::SetAnnotateDomModelService(
- AnnotateDomModelService* annotate_dom_model_service) {
- DCHECK(annotate_dom_model_service);
- annotate_dom_model_service_ = annotate_dom_model_service;
-}
-
void ContentAutofillAssistantDriver::GetAnnotateDomModel(
GetAnnotateDomModelCallback callback) {
- DCHECK(annotate_dom_model_service_);
if (!annotate_dom_model_service_) {
+ NOTREACHED() << "No model service";
std::move(callback).Run(base::File());
+ return;
}
absl::optional<base::File> file = annotate_dom_model_service_->GetModelFile();
if (file) {
- std::move(callback).Run(file->Duplicate());
+ std::move(callback).Run(*std::move(file));
return;
}
@@ -67,13 +91,13 @@ void ContentAutofillAssistantDriver::OnModelAvailabilityChanged(
return;
}
- auto file_opt = annotate_dom_model_service_->GetModelFile();
- DCHECK(file_opt);
- if (!file_opt) {
+ absl::optional<base::File> file = annotate_dom_model_service_->GetModelFile();
+ if (!file) {
+ NOTREACHED() << "No model file where expected.";
std::move(callback).Run(base::File());
return;
}
- std::move(callback).Run(file_opt->Duplicate());
+ std::move(callback).Run(*std::move(file));
}
} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/content/browser/content_autofill_assistant_driver.h b/chromium/components/autofill_assistant/content/browser/content_autofill_assistant_driver.h
index a7bcc4e9924..25f0f3ddcbe 100644
--- a/chromium/components/autofill_assistant/content/browser/content_autofill_assistant_driver.h
+++ b/chromium/components/autofill_assistant/content/browser/content_autofill_assistant_driver.h
@@ -31,6 +31,14 @@ class ContentAutofillAssistantDriver
ContentAutofillAssistantDriver& operator=(
const ContentAutofillAssistantDriver&) = delete;
+ static void BindDriver(mojo::PendingAssociatedReceiver<
+ mojom::AutofillAssistantDriver> pending_receiver,
+ content::RenderFrameHost* render_frame_host);
+
+ static ContentAutofillAssistantDriver* GetOrCreateForRenderFrameHost(
+ content::RenderFrameHost* render_frame_host,
+ AnnotateDomModelService* annotate_dom_model_service);
+
void BindPendingReceiver(
mojo::PendingAssociatedReceiver<mojom::AutofillAssistantDriver>
pending_receiver);
@@ -38,9 +46,6 @@ class ContentAutofillAssistantDriver
const mojo::AssociatedRemote<mojom::AutofillAssistantAgent>&
GetAutofillAssistantAgent();
- void SetAnnotateDomModelService(
- AnnotateDomModelService* annotate_dom_model_service);
-
// autofill_assistant::mojom::AutofillAssistantDriver:
void GetAnnotateDomModel(GetAnnotateDomModelCallback callback) override;
diff --git a/chromium/components/autofill_assistant/content/common/autofill_assistant_agent.mojom b/chromium/components/autofill_assistant/content/common/autofill_assistant_agent.mojom
index 3bdd76da442..80b71b69baf 100644
--- a/chromium/components/autofill_assistant/content/common/autofill_assistant_agent.mojom
+++ b/chromium/components/autofill_assistant/content/common/autofill_assistant_agent.mojom
@@ -12,5 +12,5 @@ interface AutofillAssistantAgent {
// Evaluates all input, textarea and select nodes in the frame's document and
// returns all that match the given semantic role and objective.
GetSemanticNodes(int32 role, int32 objective)
- => (array<autofill_assistant.mojom.NodeData> nodes);
+ => (bool success, array<autofill_assistant.mojom.NodeData> nodes);
};
diff --git a/chromium/components/autofill_assistant/content/renderer/BUILD.gn b/chromium/components/autofill_assistant/content/renderer/BUILD.gn
index 595bfa38449..3138bb95fb8 100644
--- a/chromium/components/autofill_assistant/content/renderer/BUILD.gn
+++ b/chromium/components/autofill_assistant/content/renderer/BUILD.gn
@@ -2,6 +2,13 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//components/optimization_guide/features.gni")
+import("//third_party/protobuf/proto_library.gni")
+
+proto_library("model_metadata_proto") {
+ sources = [ "model_metadata.proto" ]
+}
+
static_library("renderer") {
sources = [
"autofill_assistant_agent.cc",
@@ -9,12 +16,65 @@ static_library("renderer") {
]
deps = [
+ ":model_metadata_proto",
+ "//base",
"//components/autofill_assistant/content/common:common",
"//components/autofill_assistant/content/common:mojo_interfaces",
+ "//components/optimization_guide:machine_learning_tflite_buildflags",
"//content/public/common:common",
"//content/public/renderer:renderer",
"//mojo/public/cpp/bindings",
+ "//third_party/abseil-cpp:absl",
"//third_party/blink/public:blink",
"//third_party/blink/public/common",
]
+
+ if (build_with_tflite_lib) {
+ sources += [
+ "autofill_assistant_model_executor.cc",
+ "autofill_assistant_model_executor.h",
+ ]
+ deps += [ "//components/optimization_guide/core:model_executor" ]
+ public_deps = [
+ "//third_party/tflite",
+ "//third_party/tflite:tflite_public_headers",
+ "//third_party/tflite_support",
+ "//third_party/tflite_support:tflite_support_proto",
+ ]
+ }
+}
+
+source_set("unit_tests") {
+ testonly = true
+ sources = []
+
+ if (build_with_tflite_lib) {
+ sources += [ "autofill_assistant_model_executor_unittest.cc" ]
+ }
+
+ deps = [
+ ":renderer",
+ "//base",
+ "//base/test:test_support",
+ "//third_party/blink/public:blink",
+ ]
+}
+
+source_set("browser_tests") {
+ testonly = true
+ sources = []
+
+ if (build_with_tflite_lib) {
+ sources += [ "autofill_assistant_agent_browsertest.cc" ]
+ }
+
+ deps = [
+ ":renderer",
+ "//base",
+ "//base/test:test_support",
+ "//components/autofill_assistant/content/common:mojo_interfaces",
+ "//content/public/browser",
+ "//content/public/renderer",
+ "//content/test:test_support",
+ ]
}
diff --git a/chromium/components/autofill_assistant/content/renderer/DEPS b/chromium/components/autofill_assistant/content/renderer/DEPS
index f0556f58323..a28ced1664c 100644
--- a/chromium/components/autofill_assistant/content/renderer/DEPS
+++ b/chromium/components/autofill_assistant/content/renderer/DEPS
@@ -1,11 +1,15 @@
include_rules = [
+ "+components/optimization_guide",
"+content/public/common",
"+content/public/renderer",
"+content/public/test",
+ "+mojo/public/cpp/bindings",
"+mojo/public/cpp/bindings/binding.h",
"+services/service_manager/public/cpp",
+ "+third_party/abseil-cpp/absl/status/status.h",
"+third_party/blink/public/common",
"+third_party/blink/public/platform",
"+third_party/blink/public/web",
- "+mojo/public/cpp/bindings",
+ "+third_party/tflite",
+ "+third_party/tflite_support",
]
diff --git a/chromium/components/autofill_assistant/content/renderer/autofill_assistant_agent.cc b/chromium/components/autofill_assistant/content/renderer/autofill_assistant_agent.cc
index 01372156ab4..6192852efe6 100644
--- a/chromium/components/autofill_assistant/content/renderer/autofill_assistant_agent.cc
+++ b/chromium/components/autofill_assistant/content/renderer/autofill_assistant_agent.cc
@@ -4,12 +4,18 @@
#include "components/autofill_assistant/content/renderer/autofill_assistant_agent.h"
+#include "base/time/time.h"
+#include "components/optimization_guide/machine_learning_tflite_buildflags.h"
#include "content/public/renderer/render_frame.h"
-#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
+#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
#include "third_party/blink/public/platform/web_vector.h"
#include "third_party/blink/public/web/modules/autofill_assistant/node_signals.h"
#include "third_party/blink/public/web/web_local_frame.h"
+#if BUILDFLAG(BUILD_WITH_TFLITE_LIB)
+#include "components/autofill_assistant/content/renderer/autofill_assistant_model_executor.h"
+#endif // BUILDFLAG(BUILD_WITH_TFLITE_LIB)
+
namespace autofill_assistant {
AutofillAssistantAgent::AutofillAssistantAgent(
@@ -43,53 +49,78 @@ void AutofillAssistantAgent::GetSemanticNodes(
int32_t role,
int32_t objective,
GetSemanticNodesCallback callback) {
- std::vector<NodeData> nodes;
-
blink::WebLocalFrame* frame = render_frame()->GetWebFrame();
if (!frame) {
- std::move(callback).Run(nodes);
+ std::move(callback).Run(false, std::vector<NodeData>());
return;
}
- blink::WebVector<blink::AutofillAssistantNodeSignals> node_signals =
- blink::GetAutofillAssistantNodeSignals(frame->GetDocument());
-
- // TODO(sandromaggi): Run the model on the collected signals and filter
- // accordingly.
-
- for (const auto& node_signal : node_signals) {
- NodeData node_data;
- node_data.backend_node_id = node_signal.backend_node_id;
- nodes.push_back(node_data);
- }
-
- std::move(callback).Run(nodes);
+ GetAnnotateDomModel(base::BindOnce(
+ &AutofillAssistantAgent::OnGetModelFile, weak_ptr_factory_.GetWeakPtr(),
+ base::Time::Now(), frame, role, objective, std::move(callback)));
}
void AutofillAssistantAgent::GetAnnotateDomModel(
base::OnceCallback<void(base::File)> callback) {
- GetDriver()->GetAnnotateDomModel(std::move(callback));
+ GetDriver().GetAnnotateDomModel(std::move(callback));
}
-const mojo::Remote<mojom::AutofillAssistantDriver>&
-AutofillAssistantAgent::GetDriver() {
+mojom::AutofillAssistantDriver& AutofillAssistantAgent::GetDriver() {
if (!driver_) {
- render_frame()->GetBrowserInterfaceBroker()->GetInterface(
- driver_.BindNewPipeAndPassReceiver());
- return driver_;
+ render_frame()->GetRemoteAssociatedInterfaces()->GetInterface(&driver_);
+ }
+ return *driver_;
+}
+
+void AutofillAssistantAgent::OnGetModelFile(base::Time start_time,
+ blink::WebLocalFrame* frame,
+ int32_t role,
+ int32_t objective,
+ GetSemanticNodesCallback callback,
+ base::File model) {
+ base::Time on_get_model_file = base::Time::Now();
+ DVLOG(3) << "AutofillAssistant, loading model file: "
+ << (on_get_model_file - start_time).InMilliseconds() << "ms";
+
+ blink::WebVector<blink::AutofillAssistantNodeSignals> node_signals =
+ blink::GetAutofillAssistantNodeSignals(frame->GetDocument());
+
+ base::Time on_node_signals = base::Time::Now();
+ DVLOG(3) << "AutofillAssistant, signals extraction: "
+ << (on_node_signals - on_get_model_file).InMilliseconds() << "ms";
+
+ std::vector<NodeData> nodes;
+
+#if BUILDFLAG(BUILD_WITH_TFLITE_LIB)
+ AutofillAssistantModelExecutor model_executor;
+ if (!model_executor.InitializeModelFromFile(std::move(model))) {
+ std::move(callback).Run(false, nodes);
+ return;
}
- // The driver_ can become unbound or disconnected in testing so this catches
- // that case and reconnects so `this` can connect to the driver in the
- // browser.
- if (driver_.is_bound() && driver_.is_connected()) {
- return driver_;
+ base::Time on_executor_initialized = base::Time::Now();
+ DVLOG(3) << "AutofillAssistant, executor initialization: "
+ << (on_executor_initialized - on_node_signals).InMilliseconds()
+ << "ms";
+
+ for (const auto& node_signal : node_signals) {
+ auto result = model_executor.ExecuteModelWithInput(node_signal);
+ if (result && result->first == role && result->second == objective) {
+ NodeData node_data;
+ node_data.backend_node_id = node_signal.backend_node_id;
+ nodes.push_back(node_data);
+ }
}
- driver_.reset();
- render_frame()->GetBrowserInterfaceBroker()->GetInterface(
- driver_.BindNewPipeAndPassReceiver());
- return driver_;
+ base::Time on_node_signals_evaluated = base::Time::Now();
+ DVLOG(3)
+ << "AutofillAssistant, node evaluation (for " << node_signals.size()
+ << " nodes): "
+ << (on_node_signals_evaluated - on_executor_initialized).InMilliseconds()
+ << "ms";
+#endif // BUILDFLAG(BUILD_WITH_TFLITE_LIB)
+
+ std::move(callback).Run(true, nodes);
}
} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/content/renderer/autofill_assistant_agent.h b/chromium/components/autofill_assistant/content/renderer/autofill_assistant_agent.h
index 790a8f09dbc..c41c564e8d9 100644
--- a/chromium/components/autofill_assistant/content/renderer/autofill_assistant_agent.h
+++ b/chromium/components/autofill_assistant/content/renderer/autofill_assistant_agent.h
@@ -13,6 +13,7 @@
#include "components/autofill_assistant/content/common/node_data.h"
#include "content/public/renderer/render_frame_observer.h"
#include "mojo/public/cpp/bindings/associated_receiver.h"
+#include "mojo/public/cpp/bindings/associated_remote.h"
#include "mojo/public/cpp/bindings/pending_associated_receiver.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_registry.h"
@@ -46,9 +47,16 @@ class AutofillAssistantAgent : public content::RenderFrameObserver,
// content::RenderFrameObserver:
void OnDestruct() override;
- const mojo::Remote<mojom::AutofillAssistantDriver>& GetDriver();
+ mojom::AutofillAssistantDriver& GetDriver();
- mojo::Remote<mojom::AutofillAssistantDriver> driver_;
+ void OnGetModelFile(base::Time start_time,
+ blink::WebLocalFrame* frame,
+ int32_t role,
+ int32_t objective,
+ GetSemanticNodesCallback callback,
+ base::File model);
+
+ mojo::AssociatedRemote<mojom::AutofillAssistantDriver> driver_;
mojo::AssociatedReceiver<mojom::AutofillAssistantAgent> receiver_{this};
base::WeakPtrFactory<AutofillAssistantAgent> weak_ptr_factory_{this};
diff --git a/chromium/components/autofill_assistant/content/renderer/autofill_assistant_agent_browsertest.cc b/chromium/components/autofill_assistant/content/renderer/autofill_assistant_agent_browsertest.cc
index a44d75d3412..4d1d0a24111 100644
--- a/chromium/components/autofill_assistant/content/renderer/autofill_assistant_agent_browsertest.cc
+++ b/chromium/components/autofill_assistant/content/renderer/autofill_assistant_agent_browsertest.cc
@@ -5,6 +5,8 @@
#include "components/autofill_assistant/content/renderer/autofill_assistant_agent.h"
#include "base/files/file.h"
+#include "base/files/file_path.h"
+#include "base/path_service.h"
#include "base/run_loop.h"
#include "base/test/gmock_callback_support.h"
#include "base/test/mock_callback.h"
@@ -12,26 +14,20 @@
#include "content/public/renderer/render_frame.h"
#include "content/public/test/render_view_test.h"
#include "mojo/public/cpp/bindings/associated_receiver_set.h"
-#include "mojo/public/cpp/bindings/receiver_set.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
-#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
namespace autofill_assistant {
namespace {
using ::base::test::RunOnceCallback;
+using ::testing::_;
class MockAutofillAssistantDriver : public mojom::AutofillAssistantDriver {
public:
- void BindHandle(mojo::ScopedMessagePipeHandle handle) {
- receivers_.Add(this, mojo::PendingReceiver<mojom::AutofillAssistantDriver>(
- std::move(handle)));
- }
-
void BindPendingReceiver(mojo::ScopedInterfaceEndpointHandle handle) {
- associated_receivers_.Add(
+ receivers_.Add(
this, mojo::PendingAssociatedReceiver<mojom::AutofillAssistantDriver>(
std::move(handle)));
}
@@ -42,9 +38,7 @@ class MockAutofillAssistantDriver : public mojom::AutofillAssistantDriver {
(override));
private:
- mojo::ReceiverSet<mojom::AutofillAssistantDriver> receivers_;
- mojo::AssociatedReceiverSet<mojom::AutofillAssistantDriver>
- associated_receivers_;
+ mojo::AssociatedReceiverSet<mojom::AutofillAssistantDriver> receivers_;
};
class AutofillAssistantAgentBrowserTest : public content::RenderViewTest {
@@ -54,18 +48,26 @@ class AutofillAssistantAgentBrowserTest : public content::RenderViewTest {
void SetUp() override {
RenderViewTest::SetUp();
- GetMainRenderFrame()->GetBrowserInterfaceBroker()->SetBinderForTesting(
- mojom::AutofillAssistantDriver::Name_,
- base::BindRepeating(&MockAutofillAssistantDriver::BindHandle,
- base::Unretained(&autofill_assistant_driver_)));
- blink::AssociatedInterfaceProvider* remote_interfaces =
- GetMainRenderFrame()->GetRemoteAssociatedInterfaces();
- remote_interfaces->OverrideBinderForTesting(
- mojom::AutofillAssistantDriver::Name_,
- base::BindRepeating(&MockAutofillAssistantDriver::BindPendingReceiver,
- base::Unretained(&autofill_assistant_driver_)));
+ GetMainRenderFrame()
+ ->GetRemoteAssociatedInterfaces()
+ ->OverrideBinderForTesting(
+ mojom::AutofillAssistantDriver::Name_,
+ base::BindRepeating(
+ &MockAutofillAssistantDriver::BindPendingReceiver,
+ base::Unretained(&autofill_assistant_driver_)));
autofill_assistant_agent_ = std::make_unique<AutofillAssistantAgent>(
GetMainRenderFrame(), &associated_interfaces_);
+
+ base::FilePath source_root_dir;
+ base::PathService::Get(base::DIR_SOURCE_ROOT, &source_root_dir);
+ base::FilePath model_file_path = source_root_dir.AppendASCII("components")
+ .AppendASCII("test")
+ .AppendASCII("data")
+ .AppendASCII("autofill_assistant")
+ .AppendASCII("model")
+ .AppendASCII("model.tflite");
+ model_file_ = base::File(model_file_path,
+ (base::File::FLAG_OPEN | base::File::FLAG_READ));
}
void TearDown() override {
@@ -76,7 +78,7 @@ class AutofillAssistantAgentBrowserTest : public content::RenderViewTest {
protected:
MockAutofillAssistantDriver autofill_assistant_driver_;
std::unique_ptr<AutofillAssistantAgent> autofill_assistant_agent_;
- base::MockCallback<base::OnceCallback<void(base::File)>> callback_;
+ base::File model_file_;
private:
blink::AssociatedInterfaceRegistry associated_interfaces_;
@@ -84,10 +86,34 @@ class AutofillAssistantAgentBrowserTest : public content::RenderViewTest {
TEST_F(AutofillAssistantAgentBrowserTest, GetModelFile) {
EXPECT_CALL(autofill_assistant_driver_, GetAnnotateDomModel)
- .WillOnce(RunOnceCallback<0>(base::File()));
+ .WillOnce(RunOnceCallback<0>(model_file_.Duplicate()));
+
+ base::MockCallback<base::OnceCallback<void(base::File)>> callback;
+ EXPECT_CALL(callback, Run);
+
+ autofill_assistant_agent_->GetAnnotateDomModel(callback.Get());
- EXPECT_CALL(callback_, Run);
- autofill_assistant_agent_->GetAnnotateDomModel(callback_.Get());
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST_F(AutofillAssistantAgentBrowserTest, GetSemanticNodes) {
+ EXPECT_CALL(autofill_assistant_driver_, GetAnnotateDomModel)
+ .WillOnce(RunOnceCallback<0>(model_file_.Duplicate()));
+
+ base::MockCallback<
+ base::OnceCallback<void(bool, const std::vector<NodeData>&)>>
+ callback;
+ EXPECT_CALL(callback, Run(true, _));
+
+ LoadHTML(R"(
+ <div>
+ <h1>Shipping address</h1>
+ <label for="street">Street Address</label><input id="street">
+ </div>)");
+
+ autofill_assistant_agent_->GetSemanticNodes(
+ /* role= */ 47 /* ADDRESS_LINE1 */,
+ /* objective= */ 7 /* FILL_DELIVERY_ADDRESS */, callback.Get());
base::RunLoop().RunUntilIdle();
}
diff --git a/chromium/components/autofill_assistant/content/renderer/autofill_assistant_model_executor.cc b/chromium/components/autofill_assistant/content/renderer/autofill_assistant_model_executor.cc
new file mode 100644
index 00000000000..12fd613850f
--- /dev/null
+++ b/chromium/components/autofill_assistant/content/renderer/autofill_assistant_model_executor.cc
@@ -0,0 +1,281 @@
+// Copyright 2022 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.
+
+#include "components/autofill_assistant/content/renderer/autofill_assistant_model_executor.h"
+
+#include "base/i18n/case_conversion.h"
+#include "base/no_destructor.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/optimization_guide/core/execution_status.h"
+#include "components/optimization_guide/core/tflite_op_resolver.h"
+#include "third_party/abseil-cpp/absl/status/status.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "third_party/tflite/src/tensorflow/lite/kernels/internal/runtime_shape.h"
+#include "third_party/tflite/src/tensorflow/lite/kernels/internal/tensor_ctypes.h"
+#include "third_party/tflite_support/src/tensorflow_lite_support/cc/task/core/task_utils.h"
+#include "third_party/tflite_support/src/tensorflow_lite_support/metadata/cc/metadata_extractor.h"
+
+namespace autofill_assistant {
+
+AutofillAssistantModelExecutor::AutofillAssistantModelExecutor() = default;
+AutofillAssistantModelExecutor::~AutofillAssistantModelExecutor() = default;
+
+bool AutofillAssistantModelExecutor::InitializeModelFromFile(
+ base::File model_file) {
+ if (!model_file.IsValid() || !model_file_.Initialize(std::move(model_file))) {
+ return false;
+ }
+
+ std::unique_ptr<tflite::task::core::TfLiteEngine> tflite_engine =
+ std::make_unique<tflite::task::core::TfLiteEngine>(
+ std::make_unique<optimization_guide::TFLiteOpResolver>());
+ absl::Status model_load_status = tflite_engine->BuildModelFromFlatBuffer(
+ reinterpret_cast<const char*>(model_file_.data()), model_file_.length());
+ if (!model_load_status.ok()) {
+ DLOG(ERROR) << "Failed to load model: " << model_load_status.ToString();
+ return false;
+ }
+ absl::Status interpreter_status = tflite_engine->InitInterpreter(
+ tflite::proto::ComputeSettings(), /* num_threads= */ 1);
+ if (!interpreter_status.ok()) {
+ DLOG(ERROR) << "Failed to initialize model interpreter: "
+ << interpreter_status.ToString();
+ return false;
+ }
+
+ auto metadata_or =
+ tflite_engine->metadata_extractor()->GetAssociatedFile("metadata.pb");
+ if (!metadata_or.ok()) {
+ DLOG(ERROR) << "Could not read metadata: "
+ << metadata_or.status().ToString();
+ return false;
+ }
+ if (!model_metadata_.ParseFromArray(metadata_or->data(),
+ metadata_or->size())) {
+ DLOG(ERROR) << "Could not parse metadata.";
+ return false;
+ }
+
+ InitializeTagsTokenizer("\\s+", model_metadata_.input().tag().vocabulary());
+ InitializeTypesTokenizer("\\s+", model_metadata_.input().type().vocabulary());
+ InitializeTextTokenizer(model_metadata_.input().text().regex(),
+ model_metadata_.input().text().vocabulary());
+
+ BuildExecutionTask(std::move(tflite_engine));
+
+ return true;
+}
+
+void AutofillAssistantModelExecutor::BuildExecutionTask(
+ std::unique_ptr<tflite::task::core::TfLiteEngine> tflite_engine) {
+ execution_task_ =
+ std::make_unique<ExecutionTask>(std::move(tflite_engine), this);
+}
+
+absl::optional<std::pair<int, int>>
+AutofillAssistantModelExecutor::ExecuteModelWithInput(
+ const blink::AutofillAssistantNodeSignals& node_signals) {
+ if (!execution_task_) {
+ NOTREACHED() << "No available task";
+ return absl::nullopt;
+ }
+ optimization_guide::ExecutionStatus out_status;
+ return Execute(execution_task_.get(), &out_status, node_signals);
+}
+
+void AutofillAssistantModelExecutor::InitializeTagsTokenizer(
+ const std::string& pattern,
+ const std::string& vocabulary) {
+ DCHECK(!pattern.empty());
+ DCHECK(!vocabulary.empty());
+ tags_tokenizer_ =
+ std::make_unique<tflite::support::text::tokenizer::RegexTokenizer>(
+ pattern, vocabulary.data(), vocabulary.size());
+}
+
+void AutofillAssistantModelExecutor::InitializeTypesTokenizer(
+ const std::string& pattern,
+ const std::string& vocabulary) {
+ DCHECK(!pattern.empty());
+ DCHECK(!vocabulary.empty());
+ types_tokenizer_ =
+ std::make_unique<tflite::support::text::tokenizer::RegexTokenizer>(
+ pattern, vocabulary.data(), vocabulary.size());
+}
+
+void AutofillAssistantModelExecutor::InitializeTextTokenizer(
+ const std::string& pattern,
+ const std::string& vocabulary) {
+ DCHECK(!pattern.empty());
+ DCHECK(!vocabulary.empty());
+ text_tokenizer_ =
+ std::make_unique<tflite::support::text::tokenizer::RegexTokenizer>(
+ pattern, vocabulary.data(), vocabulary.size());
+}
+
+bool AutofillAssistantModelExecutor::Preprocess(
+ const std::vector<TfLiteTensor*>& input_tensors,
+ const blink::AutofillAssistantNodeSignals& node_signals) {
+ if (input_tensors.size() < 5u) {
+ NOTREACHED() << "Input tensors mismatch.";
+ return false;
+ }
+ std::vector<std::vector<float>> inputs;
+ for (const auto* input_tensor : input_tensors) {
+ tflite::RuntimeShape shape = tflite::GetTensorShape(input_tensor);
+ if (shape.DimensionsCount() < 2) {
+ return false;
+ }
+ inputs.emplace_back(std::vector(shape.Dims(1), 0.0f));
+ }
+
+ DCHECK(tags_tokenizer_);
+ Tokenize(node_signals.node_features.html_tag.Utf16(), tags_tokenizer_.get(),
+ &inputs[0]);
+ DCHECK(types_tokenizer_);
+ Tokenize(node_signals.node_features.type.Utf16(), types_tokenizer_.get(),
+ &inputs[1]);
+ DCHECK(text_tokenizer_);
+ Tokenize(node_signals.node_features.invisible_attributes.Utf16(),
+ text_tokenizer_.get(), &inputs[2]);
+ for (const auto& text : node_signals.node_features.text) {
+ Tokenize(text.Utf16(), text_tokenizer_.get(), &inputs[2]);
+ }
+ for (const auto& text : node_signals.label_features.text) {
+ Tokenize(text.Utf16(), text_tokenizer_.get(), &inputs[3]);
+ }
+ for (const auto& text : node_signals.context_features.header_text) {
+ Tokenize(text.Utf16(), text_tokenizer_.get(), &inputs[4]);
+ }
+
+ for (size_t i = 0; i < inputs.size(); ++i) {
+ absl::Status tensor_status =
+ tflite::task::core::PopulateTensor<float>(inputs[i], input_tensors[i]);
+ if (!tensor_status.ok()) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool AutofillAssistantModelExecutor::GetIndexOfBestRole(
+ const std::vector<float>& output_role,
+ size_t* index_of_best_role) {
+ if (output_role.size() <
+ static_cast<size_t>(
+ model_metadata_.output().semantic_role().classes_size())) {
+ NOTREACHED();
+ return false;
+ }
+ *index_of_best_role = std::distance(
+ output_role.begin(),
+ std::max_element(
+ output_role.begin(),
+ output_role.begin() +
+ model_metadata_.output().semantic_role().classes_size()));
+ return true;
+}
+
+bool AutofillAssistantModelExecutor::GetBlockIndex(
+ const std::vector<float>& output_role,
+ size_t index_of_best_role,
+ int* block_index) {
+ if (index_of_best_role >=
+ static_cast<size_t>(model_metadata_.output()
+ .semantic_role()
+ .objective_block_index_size())) {
+ NOTREACHED();
+ return false;
+ }
+ *block_index = model_metadata_.output().semantic_role().objective_block_index(
+ index_of_best_role);
+ return true;
+}
+
+bool AutofillAssistantModelExecutor::GetObjective(
+ const std::vector<float>& output_objective,
+ int block_index,
+ int* objective) {
+ if (block_index + 1 >= model_metadata_.output().objective().blocks_size()) {
+ NOTREACHED();
+ return false;
+ }
+ auto block_start = output_objective.begin() +
+ model_metadata_.output().objective().blocks(block_index);
+ auto block_end = output_objective.begin() +
+ model_metadata_.output().objective().blocks(block_index + 1);
+ size_t index_of_best_objective =
+ std::distance(block_start, std::max_element(block_start, block_end));
+ if (index_of_best_objective >=
+ static_cast<size_t>(
+ model_metadata_.output().objective().classes_size())) {
+ NOTREACHED();
+ return false;
+ }
+
+ *objective =
+ model_metadata_.output().objective().classes(index_of_best_objective);
+ return true;
+}
+
+absl::optional<std::pair<int, int>> AutofillAssistantModelExecutor::Postprocess(
+ const std::vector<const TfLiteTensor*>& output_tensors) {
+ if (output_tensors.size() < 2u) {
+ NOTREACHED() << "Output Tensors mismatch.";
+ return absl::nullopt;
+ }
+ std::vector<float> output_role;
+ absl::Status role_status = tflite::task::core::PopulateVector<float>(
+ output_tensors[0], &output_role);
+ if (!role_status.ok()) {
+ return absl::nullopt;
+ }
+ std::vector<float> output_objective;
+ absl::Status objective_status = tflite::task::core::PopulateVector<float>(
+ output_tensors[1], &output_objective);
+ if (!objective_status.ok()) {
+ return absl::nullopt;
+ }
+
+ size_t index_of_best_role;
+ if (!GetIndexOfBestRole(output_role, &index_of_best_role)) {
+ return absl::nullopt;
+ }
+ int semantic_role =
+ model_metadata_.output().semantic_role().classes(index_of_best_role);
+ if (semantic_role == 0) {
+ return std::pair<int, int>(semantic_role, 0);
+ }
+
+ int block_index;
+ if (!GetBlockIndex(output_role, index_of_best_role, &block_index)) {
+ return absl::nullopt;
+ }
+ int objective;
+ if (!GetObjective(output_objective, block_index, &objective)) {
+ return absl::nullopt;
+ }
+
+ return std::pair<int, int>(semantic_role, objective);
+}
+
+void AutofillAssistantModelExecutor::Tokenize(
+ const std::u16string& input,
+ tflite::support::text::tokenizer::RegexTokenizer* tokenizer,
+ std::vector<float>* output) {
+ auto result =
+ tokenizer->Tokenize(base::UTF16ToUTF8(base::i18n::ToUpper(input)));
+ for (const auto& token : result.subwords) {
+ int index;
+ if (tokenizer->LookupId(token, &index)) {
+ if (static_cast<size_t>(index) >= output->size()) {
+ NOTREACHED();
+ continue;
+ }
+ ++output->at(index);
+ }
+ }
+}
+
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/content/renderer/autofill_assistant_model_executor.h b/chromium/components/autofill_assistant/content/renderer/autofill_assistant_model_executor.h
new file mode 100644
index 00000000000..f067934a534
--- /dev/null
+++ b/chromium/components/autofill_assistant/content/renderer/autofill_assistant_model_executor.h
@@ -0,0 +1,109 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_AUTOFILL_ASSISTANT_CONTENT_RENDERER_AUTOFILL_ASSISTANT_MODEL_EXECUTOR_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_CONTENT_RENDERER_AUTOFILL_ASSISTANT_MODEL_EXECUTOR_H_
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/files/file.h"
+#include "base/files/memory_mapped_file.h"
+#include "components/autofill_assistant/content/renderer/model_metadata.pb.h"
+#include "components/optimization_guide/core/base_model_executor.h"
+#include "components/optimization_guide/core/base_model_executor_helpers.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "third_party/blink/public/web/modules/autofill_assistant/node_signals.h"
+#include "third_party/tflite/src/tensorflow/lite/c/common.h"
+#include "third_party/tflite_support/src/tensorflow_lite_support/cc/task/core/base_task_api.h"
+#include "third_party/tflite_support/src/tensorflow_lite_support/cc/task/core/tflite_engine.h"
+#include "third_party/tflite_support/src/tensorflow_lite_support/cc/text/tokenizers/regex_tokenizer.h"
+
+namespace autofill_assistant {
+
+// Holds and executes the AnnotateDOM model to predict semantic roles based on
+// node signals.
+class AutofillAssistantModelExecutor
+ : public optimization_guide::BaseModelExecutor<
+ std::pair<int, int>,
+ const blink::AutofillAssistantNodeSignals&> {
+ public:
+ using ExecutionTask = optimization_guide::GenericModelExecutionTask<
+ std::pair<int, int>,
+ const blink::AutofillAssistantNodeSignals&>;
+
+ AutofillAssistantModelExecutor();
+ ~AutofillAssistantModelExecutor() override;
+
+ AutofillAssistantModelExecutor(const AutofillAssistantModelExecutor&) =
+ delete;
+ void operator=(const AutofillAssistantModelExecutor&) = delete;
+
+ // Initialize the model from the |model_file|. Sets |model_initialized_|.
+ bool InitializeModelFromFile(base::File model_file);
+
+ // Execute the model with the given input.
+ absl::optional<std::pair<int, int>> ExecuteModelWithInput(
+ const blink::AutofillAssistantNodeSignals& node_signals);
+
+ protected:
+ // optimization_guide::InferenceDelegate:
+ bool Preprocess(
+ const std::vector<TfLiteTensor*>& input_tensors,
+ const blink::AutofillAssistantNodeSignals& node_signals) override;
+ absl::optional<std::pair<int, int>> Postprocess(
+ const std::vector<const TfLiteTensor*>& output_tensors) override;
+
+ private:
+ // Initialize Tokenizers with |pattern| for splitting and the |vocabulary| in
+ // the form of "<word> <index>" per line.
+ void InitializeTagsTokenizer(const std::string& pattern,
+ const std::string& vocabulary);
+ void InitializeTypesTokenizer(const std::string& pattern,
+ const std::string& vocabulary);
+ void InitializeTextTokenizer(const std::string& pattern,
+ const std::string& vocabulary);
+
+ // Build the execution task from the model file.
+ void BuildExecutionTask(
+ std::unique_ptr<tflite::task::core::TfLiteEngine> tflite_engine);
+
+ // Tokenize the |input| and count words into the |output| vector. The |output|
+ // can be reused for all relevant inputs for a signal.
+ void Tokenize(const std::u16string& input,
+ tflite::support::text::tokenizer::RegexTokenizer* tokenizer,
+ std::vector<float>* output);
+
+ // Helper functions for post processing based on |model_metadata_|.
+ bool GetIndexOfBestRole(const std::vector<float>& output_role,
+ size_t* index_of_best_role);
+ bool GetBlockIndex(const std::vector<float>& output_role,
+ size_t index_of_best_role,
+ int* block_index);
+ bool GetObjective(const std::vector<float>& output_objective,
+ int block_index,
+ int* objective);
+
+ // Tokenizer for HTML tag.
+ std::unique_ptr<tflite::support::text::tokenizer::RegexTokenizer>
+ tags_tokenizer_;
+ // Tokenizer for HTML attribute "type".
+ std::unique_ptr<tflite::support::text::tokenizer::RegexTokenizer>
+ types_tokenizer_;
+ // Tokenizer for arbitrary text.
+ std::unique_ptr<tflite::support::text::tokenizer::RegexTokenizer>
+ text_tokenizer_;
+
+ // The task for this executor.
+ std::unique_ptr<ExecutionTask> execution_task_;
+ // Model file held in memory by this instance.
+ base::MemoryMappedFile model_file_;
+ // Model Metadata for handling input/output.
+ ModelMetadata model_metadata_;
+};
+
+} // namespace autofill_assistant
+
+#endif // COMPONENTS_AUTOFILL_ASSISTANT_CONTENT_RENDERER_AUTOFILL_ASSISTANT_MODEL_EXECUTOR_H_
diff --git a/chromium/components/autofill_assistant/content/renderer/autofill_assistant_model_executor_unittest.cc b/chromium/components/autofill_assistant/content/renderer/autofill_assistant_model_executor_unittest.cc
new file mode 100644
index 00000000000..2f5df620f25
--- /dev/null
+++ b/chromium/components/autofill_assistant/content/renderer/autofill_assistant_model_executor_unittest.cc
@@ -0,0 +1,90 @@
+// Copyright 2022 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.
+
+#include "components/autofill_assistant/content/renderer/autofill_assistant_model_executor.h"
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/files/file.h"
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+#include "base/strings/strcat.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "components/autofill_assistant/content/renderer/autofill_assistant_model_executor.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/platform/web_string.h"
+#include "third_party/blink/public/platform/web_vector.h"
+#include "third_party/blink/public/web/modules/autofill_assistant/node_signals.h"
+
+namespace autofill_assistant {
+namespace {
+
+class AutofillAssistantModelExecutorTest : public testing::Test {
+ public:
+ AutofillAssistantModelExecutorTest() {
+ base::FilePath model_file_path =
+ GetTestDataDir().AppendASCII("model.tflite");
+ model_file_ = base::File(model_file_path,
+ (base::File::FLAG_OPEN | base::File::FLAG_READ));
+ }
+
+ ~AutofillAssistantModelExecutorTest() override = default;
+
+ protected:
+ base::File model_file_;
+ AutofillAssistantModelExecutor model_executor_;
+
+ private:
+ base::FilePath GetTestDataDir() {
+ base::FilePath source_root_dir;
+ base::PathService::Get(base::DIR_SOURCE_ROOT, &source_root_dir);
+ return source_root_dir.AppendASCII("components")
+ .AppendASCII("test")
+ .AppendASCII("data")
+ .AppendASCII("autofill_assistant")
+ .AppendASCII("model");
+ }
+};
+
+TEST_F(AutofillAssistantModelExecutorTest, DoesNotInitializeFromEmptyFile) {
+ EXPECT_FALSE(model_executor_.InitializeModelFromFile(base::File()));
+}
+
+TEST_F(AutofillAssistantModelExecutorTest, OnlyInitializesModelOnce) {
+ EXPECT_TRUE(model_executor_.InitializeModelFromFile(model_file_.Duplicate()));
+ EXPECT_FALSE(
+ model_executor_.InitializeModelFromFile(model_file_.Duplicate()));
+}
+
+TEST_F(AutofillAssistantModelExecutorTest, ExecuteWithLoadedModel) {
+ ASSERT_TRUE(model_executor_.InitializeModelFromFile(model_file_.Duplicate()));
+
+ blink::AutofillAssistantNodeSignals node_signals;
+ node_signals.node_features.html_tag = blink::WebString::FromUTF8("INPUT");
+ node_signals.node_features.type = blink::WebString::FromUTF8("TEXT");
+ node_signals.node_features.text.push_back(
+ blink::WebString::FromUTF8("street"));
+ node_signals.label_features.text.push_back(
+ blink::WebString::FromUTF8("Street Address:"));
+ node_signals.label_features.text.push_back(
+ blink::WebString::FromUTF8("Line 1"));
+ node_signals.context_features.header_text.push_back(
+ blink::WebString::FromUTF8("Street Address"));
+ node_signals.context_features.header_text.push_back(
+ blink::WebString::FromUTF8("Checkout"));
+ node_signals.context_features.header_text.push_back(
+ blink::WebString::FromUTF8("SHIPPING"));
+
+ auto result = model_executor_.ExecuteModelWithInput(node_signals);
+ ASSERT_TRUE(result.has_value());
+ EXPECT_EQ(result->first, 47 /* ADDRESS_LINE1 */);
+ EXPECT_EQ(result->second, 7 /* FILL_DELIVERY_ADDRESS */);
+}
+
+} // namespace
+} // namespace autofill_assistant
diff --git a/chromium/components/autofill_assistant/content/renderer/model_metadata.proto b/chromium/components/autofill_assistant/content/renderer/model_metadata.proto
new file mode 100644
index 00000000000..46199cf4863
--- /dev/null
+++ b/chromium/components/autofill_assistant/content/renderer/model_metadata.proto
@@ -0,0 +1,71 @@
+// Copyright 2022 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.
+
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+
+package autofill_assistant;
+
+// Metadata required to preprocess the model inputs and postprocess the model
+// outputs.
+message ModelMetadata {
+ // Metadata to preprocess the tag features.
+ message TagMetadata {
+ // Vocabulary in the format needed by RegexTokenizer (one token and token
+ // index per line).
+ optional string vocabulary = 1;
+ }
+ // Metadata to preprocess the type features.
+ message TypeMetadata {
+ // Vocabulary in the format needed by RegexTokenizer (one token and token
+ // index per line).
+ optional string vocabulary = 1;
+ }
+ // Metadata to preprocess the text features.
+ message TextMetadata {
+ // Vocabulary in the format needed by RegexTokenizer (one token and token
+ // index per line).
+ optional string vocabulary = 1;
+ // Regex for the RegexTokenizer.
+ optional string regex = 2;
+ }
+ // Metadata needed to preprocess the model inputs.
+ message InputMetadata {
+ optional TagMetadata tag = 1;
+ optional TypeMetadata type = 2;
+ optional TextMetadata text = 3;
+ }
+
+ // Metadata used to evaluate the semantic role.
+ message SemanticRoleMetadata {
+ // List of semantic roles corresponding to each index of the semantic role
+ // output vector.
+ repeated int32 classes = 1 [packed = true];
+ // For each index i of the output vector, objective_block_index[i] gives the
+ // index of the block of objectives to read to decode the objective. See
+ // ObjectiveMetadata.blocks.
+ repeated int32 objective_block_index = 2 [packed = true];
+ }
+ // Metadata used to evaluate the objective.
+ message ObjectiveMetadata {
+ // List of objectives corresponding to each index of the objective output
+ // vector.
+ repeated int32 classes = 1 [packed = true];
+ // A list of integers describing how to split the objective output vector v
+ // into interpretable blocks. The outputs v[blocks[i]:blocks[i+1]]
+ // correspond to the scores of a block of objective predictions. In
+ // particular, blocks[-1] is always equal to the size of the objective
+ // output vector.
+ repeated int32 blocks = 2 [packed = true];
+ }
+ // Metadata needed to interpret the model outputs.
+ message OutputMetadata {
+ optional SemanticRoleMetadata semantic_role = 1;
+ optional ObjectiveMetadata objective = 2;
+ }
+
+ optional InputMetadata input = 1;
+ optional OutputMetadata output = 2;
+}
diff --git a/chromium/components/autofill_payments_strings.grdp b/chromium/components/autofill_payments_strings.grdp
index c0655c6bae7..2f1c7378331 100644
--- a/chromium/components/autofill_payments_strings.grdp
+++ b/chromium/components/autofill_payments_strings.grdp
@@ -154,7 +154,7 @@
<message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_UPLOAD_EXPLANATION" desc="Explanation of the effect of the Autofill save card prompt when the card is to be saved by uploading it to Google Payments and also saved locally. The prompt can be either a bubble or an infobar.">
Pay quickly on sites and apps across devices using cards you have saved with Google.
</message>
- <message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_UPLOAD_EXPLANATION_V3" desc="Explanation of the effect of the Autofill save card prompt when the card is to be saved by uploading it to Google Payments, according to April 2018 UI guidelines. The prompt will be shown in a bubble below the omnibox.">
+ <message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_UPLOAD_EXPLANATION_V3" desc="Explanation of the effect of the Autofill save card prompt when the card is to be saved by uploading it to Google Payments, according to April 2018 UI guidelines. The prompt will be shown in a bubble below the omnibox." formatter_data="android_java">
To pay faster next time, save your card and billing address to your Google Account.
</message>
<message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_UPLOAD_EXPLANATION_V3_WITH_NAME" desc="Explanation of the effect of the Autofill save card prompt when the card is to be saved by uploading it to Google Payments, according to April 2018 UI guidelines. The prompt will be shown in a bubble below the omnibox.">
@@ -476,6 +476,15 @@
<message name="IDS_AUTOFILL_CLOUD_TOKEN_DROPDOWN_OPTION_LABEL" desc="Text shown in the button in the Autofill dropdown menu when a credit card form field is queried, to offer the option to use a virtual card.">
Use a virtual card number...
</message>
+ <message name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_FALLBACK_ICON_TOOLTIP" desc="The tooltip message for the omnibox icon for the virtual card enroll bubble on Desktop. This bubble prompts users if they would like to enroll in a virtual card.">
+ Add virtual card
+ </message>
+ <message name="IDS_AUTOFILL_VIRTUAL_CARD_ENTRY_PREFIX" desc="Notifies users that the type of card they are enrolling in is a virtual card.">
+ Virtual card
+ </message>
+ <message name="IDS_AUTOFILL_VIRTUAL_CARD_ENTRY_PREFIX_TWO" desc="Notifies the user that their virtual card card is linked with another card on their account.">
+ Linked with
+ </message>
<message name="IDS_AUTOFILL_VIRTUAL_CARD_SELECTION_DIALOG_CONTENT_TITLE" desc="The title shown in the Autofill virtual card selection dialog. This dialog offers available virtual credit cards for users to choose to fill the form with. [ICU Syntax]">
{NUM_CARDS, plural,
=1 {Use a virtual number for this card}
@@ -496,7 +505,10 @@
Virtual card for <ph name="CARD_IDENTIFIER">$1<ex>Visa - 1234</ex></ph>
</message>
<message name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_EDUCATIONAL_BODY_LABEL" desc="The label shown in body of the Autofill virtual card manual fallback bubble on Desktop. The label serves as a educational message to explain to users how to use the bubble to fill card information to the form. This bubble shows the complete information for the virtual card selected to fill the form.">
- Virtual card number not filled in? Click card details to copy
+ Virtual card number not filled in? Click card details to copy. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL">$1<ex>Learn about virtual cards</ex></ph>
+ </message>
+ <message name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" desc="Link text to learn more about virtual cards. Added to the end of the explanatory message of the virtual card manual fallback bubble in IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_EDUCATIONAL_BODY_LABEL">
+ Learn about virtual cards
</message>
<message name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_CARD_NUMBER_LABEL" desc="Text shown next to the virtual card number in the virtual card manual fallback bubble on Desktop. This bubble shows the complete information for the virtual card selected to fill the form.">
Virtual number:
@@ -520,6 +532,16 @@
Copied
</message>
</if>
+
+ <message name="IDS_AUTOFILL_VIRTUAL_CARD_SUGGESTION_IPH_BUBBLE_LABEL" desc="Text shown in the IPH bubble for the virtual card option in the suggestion dropdown bubble.">
+ Use your virtual card for added security
+ </message>
+ <message name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_ACCEPT_BUTTON_LABEL" desc="Accept enrolling card as a virtual card." formatter_data="android_java">
+ Yes
+ </message>
+ <message name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_DIALOG_TITLE_LABEL" desc="Title encouraging users to enroll their card to VCN." formatter_data="android_java">
+ Make it more secure with a virtual card?
+ </message>
<message name="IDS_AUTOFILL_CARD_UNMASK_AUTHENTICATION_SELECTION_DIALOG_ISSUER_CONFIRMATION_TEXT" desc="The issuer confirmation text shown in the Autofill card unmask authentication selection dialog on Desktop. This is the header text of the dialog, and it is the text stating that the issuer wants additional authentication. This dialog lets the user choose the method of authentication when unmasking a server card, including a virtual card.">
Your bank wants to confirm it's you.
</message>
@@ -577,6 +599,18 @@
<message name="IDS_AUTOFILL_ERROR_DIALOG_NEGATIVE_BUTTON_LABEL" desc="Label for the negative button for the error dialog.">
Close
</message>
+ <message name="IDS_AUTOFILL_VIRTUAL_CARD_NUMBER_SWITCH_LABEL" desc="The text shown as the label for virtual card enrollment switch in the server card edit page." formatter_data="android_java">
+ Virtual card
+ </message>
+ <message name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_DIALOG_CONTENT_LABEL" desc="Text explaining the benefit of enrolling a credit card as a virtual card. Also contains a link to learn more about virtual cards from IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL.">
+ A virtual card disguises your actual card to help protect you from potential fraud. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL">$1<ex>Learn about virtual cards</ex></ph>
+ </message>
+ <message name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_DECLINE_BUTTON_LABEL" desc="Decline enrolling card as a virtual card.">
+ No Thanks
+ </message>
+ <message name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" desc="Link text to learn more about virtual cards. Added to the end of the explanatory message of the virtual card enrollment dialog in IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_DIALOG_CONTENT_LABEL.">
+ Learn about virtual cards
+ </message>
<if expr="is_android">
<message name="IDS_AUTOFILL_VIRTUAL_CARD_NUMBER_SNACKBAR_MESSAGE_TEXT" desc="Text to be displayed in the snackbar shown after a virtual card number id autofilled.">
Virtual card number not filled in?
diff --git a/chromium/components/autofill_payments_strings_grdp/IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_ACCEPT_BUTTON_LABEL.png.sha1 b/chromium/components/autofill_payments_strings_grdp/IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_ACCEPT_BUTTON_LABEL.png.sha1
new file mode 100644
index 00000000000..471d7a776ab
--- /dev/null
+++ b/chromium/components/autofill_payments_strings_grdp/IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_ACCEPT_BUTTON_LABEL.png.sha1
@@ -0,0 +1 @@
+5af1d715b1f10ec0fb2ca47ad49dba474da266ae \ No newline at end of file
diff --git a/chromium/components/autofill_payments_strings_grdp/IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_DECLINE_BUTTON_LABEL.png.sha1 b/chromium/components/autofill_payments_strings_grdp/IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_DECLINE_BUTTON_LABEL.png.sha1
new file mode 100644
index 00000000000..b554f32b6a3
--- /dev/null
+++ b/chromium/components/autofill_payments_strings_grdp/IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_DECLINE_BUTTON_LABEL.png.sha1
@@ -0,0 +1 @@
+2e68f3f210c4fe868ac40d686c010bd951a61977 \ No newline at end of file
diff --git a/chromium/components/autofill_payments_strings_grdp/IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_DIALOG_CONTENT_LABEL.png.sha1 b/chromium/components/autofill_payments_strings_grdp/IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_DIALOG_CONTENT_LABEL.png.sha1
new file mode 100644
index 00000000000..c82bfa3d1e8
--- /dev/null
+++ b/chromium/components/autofill_payments_strings_grdp/IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_DIALOG_CONTENT_LABEL.png.sha1
@@ -0,0 +1 @@
+6d220d5a0e8b42035028e8e06b251e6bfae75e74 \ No newline at end of file
diff --git a/chromium/components/autofill_payments_strings_grdp/IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_DIALOG_TITLE_LABEL.png.sha1 b/chromium/components/autofill_payments_strings_grdp/IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_DIALOG_TITLE_LABEL.png.sha1
new file mode 100644
index 00000000000..ec93ae1bb1b
--- /dev/null
+++ b/chromium/components/autofill_payments_strings_grdp/IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_DIALOG_TITLE_LABEL.png.sha1
@@ -0,0 +1 @@
+5a8350413a7ae46696e9e09f50d30490e0783981 \ No newline at end of file
diff --git a/chromium/components/autofill_payments_strings_grdp/IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_FALLBACK_ICON_TOOLTIP.png.sha1 b/chromium/components/autofill_payments_strings_grdp/IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_FALLBACK_ICON_TOOLTIP.png.sha1
new file mode 100644
index 00000000000..6fbcc0174dc
--- /dev/null
+++ b/chromium/components/autofill_payments_strings_grdp/IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_FALLBACK_ICON_TOOLTIP.png.sha1
@@ -0,0 +1 @@
+974d251f565540aa7c95a4cefdb8a8d8285842e5 \ No newline at end of file
diff --git a/chromium/components/autofill_payments_strings_grdp/IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL.png.sha1 b/chromium/components/autofill_payments_strings_grdp/IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL.png.sha1
new file mode 100644
index 00000000000..64a3a21cbd1
--- /dev/null
+++ b/chromium/components/autofill_payments_strings_grdp/IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL.png.sha1
@@ -0,0 +1 @@
+8da30476f16d6aceceb97c38d43d7df19bf93013 \ No newline at end of file
diff --git a/chromium/components/autofill_payments_strings_grdp/IDS_AUTOFILL_VIRTUAL_CARD_ENTRY_PREFIX_TWO.png.sha1 b/chromium/components/autofill_payments_strings_grdp/IDS_AUTOFILL_VIRTUAL_CARD_ENTRY_PREFIX_TWO.png.sha1
new file mode 100644
index 00000000000..6d21e8f077f
--- /dev/null
+++ b/chromium/components/autofill_payments_strings_grdp/IDS_AUTOFILL_VIRTUAL_CARD_ENTRY_PREFIX_TWO.png.sha1
@@ -0,0 +1 @@
+a589eaa78741b7ef068fcecbc1c073a18c032fba \ No newline at end of file
diff --git a/chromium/components/autofill_payments_strings_grdp/IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_EDUCATIONAL_BODY_LABEL.png.sha1 b/chromium/components/autofill_payments_strings_grdp/IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_EDUCATIONAL_BODY_LABEL.png.sha1
index 5fc3b3b1ef5..940c22ae902 100644
--- a/chromium/components/autofill_payments_strings_grdp/IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_EDUCATIONAL_BODY_LABEL.png.sha1
+++ b/chromium/components/autofill_payments_strings_grdp/IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_EDUCATIONAL_BODY_LABEL.png.sha1
@@ -1 +1 @@
-d111001d0b92845c60b545527925d779eeeae833 \ No newline at end of file
+1862b92592a9698e54beb20b2462e02e395347a7 \ No newline at end of file
diff --git a/chromium/components/autofill_payments_strings_grdp/IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL.png.sha1 b/chromium/components/autofill_payments_strings_grdp/IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL.png.sha1
new file mode 100644
index 00000000000..7c31eb76920
--- /dev/null
+++ b/chromium/components/autofill_payments_strings_grdp/IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL.png.sha1
@@ -0,0 +1 @@
+425de2267243e5df5bb96a559219d41f0fe5ef01 \ No newline at end of file
diff --git a/chromium/components/autofill_payments_strings_grdp/IDS_AUTOFILL_VIRTUAL_CARD_NUMBER_SWITCH_LABEL.png.sha1 b/chromium/components/autofill_payments_strings_grdp/IDS_AUTOFILL_VIRTUAL_CARD_NUMBER_SWITCH_LABEL.png.sha1
new file mode 100644
index 00000000000..edcddfe0f5e
--- /dev/null
+++ b/chromium/components/autofill_payments_strings_grdp/IDS_AUTOFILL_VIRTUAL_CARD_NUMBER_SWITCH_LABEL.png.sha1
@@ -0,0 +1 @@
+a76a2454a5f84e5b80f7824deb29df9e7995ac07 \ No newline at end of file
diff --git a/chromium/components/autofill_payments_strings_grdp/IDS_AUTOFILL_VIRTUAL_CARD_SUGGESTION_IPH_BUBBLE_LABEL.png.sha1 b/chromium/components/autofill_payments_strings_grdp/IDS_AUTOFILL_VIRTUAL_CARD_SUGGESTION_IPH_BUBBLE_LABEL.png.sha1
new file mode 100644
index 00000000000..0c6d2a8ddf2
--- /dev/null
+++ b/chromium/components/autofill_payments_strings_grdp/IDS_AUTOFILL_VIRTUAL_CARD_SUGGESTION_IPH_BUBBLE_LABEL.png.sha1
@@ -0,0 +1 @@
+c268ae70d46009771482cb9fe595fd5b0e187706 \ No newline at end of file
diff --git a/chromium/components/background_fetch/background_fetch_delegate_base.cc b/chromium/components/background_fetch/background_fetch_delegate_base.cc
index 75741638c74..98d8977f1b1 100644
--- a/chromium/components/background_fetch/background_fetch_delegate_base.cc
+++ b/chromium/components/background_fetch/background_fetch_delegate_base.cc
@@ -47,7 +47,7 @@ void BackgroundFetchDelegateBase::GetIconDisplaySize(
// icon at all, which is returned for all non-Android platforms as the
// icons can't be displayed on the UI yet.
gfx::Size display_size;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
display_size = gfx::Size(192, 192);
#endif
std::move(callback).Run(display_size);
@@ -171,8 +171,11 @@ void BackgroundFetchDelegateBase::CancelDownload(std::string job_id) {
Abort(job_id);
if (auto client = GetClient(job_id)) {
+ // The |download_guid| is not releavnt here as the job has already
+ // been aborted and is assumed to have been removed.
client->OnJobCancelled(
- job_id, blink::mojom::BackgroundFetchFailureReason::CANCELLED_FROM_UI);
+ job_id, "" /* download_guid */,
+ blink::mojom::BackgroundFetchFailureReason::CANCELLED_FROM_UI);
}
}
@@ -242,14 +245,15 @@ void BackgroundFetchDelegateBase::MarkJobComplete(const std::string& job_id) {
job_details->current_fetch_guids.clear();
}
-void BackgroundFetchDelegateBase::FailFetch(const std::string& job_id) {
+void BackgroundFetchDelegateBase::FailFetch(const std::string& job_id,
+ const std::string& download_guid) {
// Save a copy before Abort() deletes the reference.
const std::string unique_id = job_id;
Abort(job_id);
if (auto client = GetClient(unique_id)) {
client->OnJobCancelled(
- unique_id,
+ download_guid, unique_id,
blink::mojom::BackgroundFetchFailureReason::DOWNLOAD_TOTAL_EXCEEDED);
}
}
@@ -301,7 +305,7 @@ void BackgroundFetchDelegateBase::OnDownloadUpdated(
// We only do this if total download size is specified. If not specified,
// this check is skipped. This is to allow for situations when the
// total download size cannot be known when invoking fetch.
- FailFetch(job_id);
+ FailFetch(job_id, download_guid);
return;
}
DoUpdateUi(job_id);
diff --git a/chromium/components/background_fetch/background_fetch_delegate_base.h b/chromium/components/background_fetch/background_fetch_delegate_base.h
index fe20adb475b..b9d509d2fad 100644
--- a/chromium/components/background_fetch/background_fetch_delegate_base.h
+++ b/chromium/components/background_fetch/background_fetch_delegate_base.h
@@ -59,7 +59,7 @@ class BackgroundFetchDelegateBase : public content::BackgroundFetchDelegate {
// Abort all ongoing downloads and fail the fetch. Currently only used when
// the bytes downloaded exceed the total download size, if specified.
- void FailFetch(const std::string& job_id);
+ void FailFetch(const std::string& job_id, const std::string& download_guid);
void OnDownloadStarted(
const std::string& guid,
diff --git a/chromium/components/background_sync/background_sync_controller_impl.cc b/chromium/components/background_sync/background_sync_controller_impl.cc
index 3eaa8aa3f55..2d5041cd8b7 100644
--- a/chromium/components/background_sync/background_sync_controller_impl.cc
+++ b/chromium/components/background_sync/background_sync_controller_impl.cc
@@ -8,6 +8,7 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/time/time.h"
+#include "build/build_config.h"
#include "components/content_settings/core/browser/host_content_settings_map.h"
#include "components/content_settings/core/common/content_settings.h"
#include "components/keep_alive_registry/keep_alive_registry.h"
@@ -25,7 +26,7 @@
// static
const char BackgroundSyncControllerImpl::kFieldTrialName[] = "BackgroundSync";
const char BackgroundSyncControllerImpl::kDisabledParameterName[] = "disabled";
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
const char BackgroundSyncControllerImpl::kRelyOnAndroidNetworkDetection[] =
"rely_on_android_network_detection";
#endif
@@ -104,7 +105,7 @@ void BackgroundSyncControllerImpl::GetParameterOverrides(
content::BackgroundSyncParameters* parameters) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
if (delegate_->ShouldDisableBackgroundSync())
parameters->disable = true;
#endif
@@ -189,7 +190,7 @@ void BackgroundSyncControllerImpl::GetParameterOverrides(
}
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Check if the delegate explicitly disabled this feature.
if (delegate_->ShouldDisableAndroidNetworkDetection()) {
parameters->rely_on_android_network_detection = false;
@@ -254,7 +255,7 @@ void BackgroundSyncControllerImpl::ScheduleBrowserWakeUpWithDelay(
if (delegate_->IsProfileOffTheRecord())
return;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
delegate_->ScheduleBrowserWakeUpWithDelay(sync_type, delay);
#endif
}
@@ -266,7 +267,7 @@ void BackgroundSyncControllerImpl::CancelBrowserWakeup(
if (delegate_->IsProfileOffTheRecord())
return;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
delegate_->CancelBrowserWakeup(sync_type);
#endif
}
@@ -366,7 +367,7 @@ base::TimeDelta BackgroundSyncControllerImpl::GetNextEventDelay(
std::unique_ptr<content::BackgroundSyncController::BackgroundSyncEventKeepAlive>
BackgroundSyncControllerImpl::CreateBackgroundSyncEventKeepAlive() {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Not needed on Android.
return nullptr;
#else
diff --git a/chromium/components/background_sync/background_sync_delegate.h b/chromium/components/background_sync/background_sync_delegate.h
index 944250550f1..7184506f6b5 100644
--- a/chromium/components/background_sync/background_sync_delegate.h
+++ b/chromium/components/background_sync/background_sync_delegate.h
@@ -28,7 +28,7 @@ class BackgroundSyncDelegate {
public:
virtual ~BackgroundSyncDelegate() = default;
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
// Keeps the browser and profile alive to allow a one-shot Background Sync
// registration to finish firing one sync event.
virtual std::unique_ptr<
@@ -63,7 +63,7 @@ class BackgroundSyncDelegate {
// Returns 0 if the engagement level is blink::mojom::EngagementLevel::NONE.
virtual int GetSiteEngagementPenalty(const GURL& url) = 0;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Schedules the browser to be woken up when the device is online to process
// registrations of type |sync| after a minimum delay |delay|.
virtual void ScheduleBrowserWakeUpWithDelay(
diff --git a/chromium/components/background_task_scheduler/background_task.h b/chromium/components/background_task_scheduler/background_task.h
index cd1b1e88bdb..d5ce57ec74e 100644
--- a/chromium/components/background_task_scheduler/background_task.h
+++ b/chromium/components/background_task_scheduler/background_task.h
@@ -15,6 +15,7 @@ class BrowserContext;
namespace background_task {
+// Boolean parameter indicates whether the task needs to be rescheduled.
using TaskFinishedCallback = base::OnceCallback<void(bool)>;
// Entry point for callbacks from BackgroundTaskScheduler. Any classes
@@ -25,7 +26,8 @@ class BackgroundTask {
// The following two methods represent the callback from
// BackgroundTaskScheduler when your task should start processing. It is
// invoked on the main thread, and after your task finishes, you should
- // run the |callback|. While this method is running the system holds a
+ // run the |callback|, with a boolean parameter indicating whether the task
+ // needs to be rescheduled. While this method is running the system holds a
// wakelock and the wakelock is not released until either the |callback| is
// invoked, or the system calls onStopTask. Depending on whether Chrome is
// running in service manager only mode or full browser mode, one or both of
diff --git a/chromium/components/background_task_scheduler/background_task_scheduler_factory.cc b/chromium/components/background_task_scheduler/background_task_scheduler_factory.cc
index a1de62fa760..e215c7e61fb 100644
--- a/chromium/components/background_task_scheduler/background_task_scheduler_factory.cc
+++ b/chromium/components/background_task_scheduler/background_task_scheduler_factory.cc
@@ -11,7 +11,7 @@
#include "components/background_task_scheduler/background_task_scheduler.h"
#include "components/keyed_service/core/simple_dependency_manager.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "components/background_task_scheduler/internal/android/native_task_scheduler.h"
#endif
@@ -38,7 +38,7 @@ BackgroundTaskSchedulerFactory::~BackgroundTaskSchedulerFactory() = default;
std::unique_ptr<KeyedService>
BackgroundTaskSchedulerFactory::BuildServiceInstanceFor(
SimpleFactoryKey* key) const {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
return std::make_unique<NativeTaskScheduler>();
#else
return nullptr;
diff --git a/chromium/components/background_task_scheduler/internal/android/javatests/src/org/chromium/components/background_task_scheduler/internal/BackgroundTaskSchedulerJobServiceTest.java b/chromium/components/background_task_scheduler/internal/android/javatests/src/org/chromium/components/background_task_scheduler/internal/BackgroundTaskSchedulerJobServiceTest.java
index f6036c5c39e..8a4b33e482c 100644
--- a/chromium/components/background_task_scheduler/internal/android/javatests/src/org/chromium/components/background_task_scheduler/internal/BackgroundTaskSchedulerJobServiceTest.java
+++ b/chromium/components/background_task_scheduler/internal/android/javatests/src/org/chromium/components/background_task_scheduler/internal/BackgroundTaskSchedulerJobServiceTest.java
@@ -4,7 +4,6 @@
package org.chromium.components.background_task_scheduler.internal;
-import android.annotation.TargetApi;
import android.app.job.JobInfo;
import android.os.Build;
import android.os.Bundle;
@@ -29,7 +28,6 @@ import java.util.concurrent.TimeUnit;
* Tests for {@link BackgroundTaskSchedulerJobService}.
*/
@RunWith(BaseJUnit4ClassRunner.class)
-@TargetApi(Build.VERSION_CODES.LOLLIPOP_MR1)
@MinAndroidSdkLevel(Build.VERSION_CODES.LOLLIPOP_MR1)
public class BackgroundTaskSchedulerJobServiceTest {
private static final long CLOCK_TIME_MS = 1415926535000L;
diff --git a/chromium/components/background_task_scheduler/internal/android/javatests/src/org/chromium/components/background_task_scheduler/internal/BundleToPersistableBundleConverterTest.java b/chromium/components/background_task_scheduler/internal/android/javatests/src/org/chromium/components/background_task_scheduler/internal/BundleToPersistableBundleConverterTest.java
index 576ec1638a0..2b82b3c0db2 100644
--- a/chromium/components/background_task_scheduler/internal/android/javatests/src/org/chromium/components/background_task_scheduler/internal/BundleToPersistableBundleConverterTest.java
+++ b/chromium/components/background_task_scheduler/internal/android/javatests/src/org/chromium/components/background_task_scheduler/internal/BundleToPersistableBundleConverterTest.java
@@ -4,7 +4,6 @@
package org.chromium.components.background_task_scheduler.internal;
-import android.annotation.TargetApi;
import android.os.Build;
import android.os.Bundle;
import android.os.PersistableBundle;
@@ -26,7 +25,6 @@ import java.util.Set;
* Tests for {@link BundleToPersistableBundleConverter}.
*/
@RunWith(BaseJUnit4ClassRunner.class)
-@TargetApi(Build.VERSION_CODES.LOLLIPOP_MR1)
@MinAndroidSdkLevel(Build.VERSION_CODES.LOLLIPOP_MR1)
public class BundleToPersistableBundleConverterTest {
@Test
diff --git a/chromium/components/background_task_scheduler/internal/android/junit/src/org/chromium/components/background_task_scheduler/internal/BackgroundTaskSchedulerPrefsTest.java b/chromium/components/background_task_scheduler/internal/android/junit/src/org/chromium/components/background_task_scheduler/internal/BackgroundTaskSchedulerPrefsTest.java
index 206f31bb696..61391a78232 100644
--- a/chromium/components/background_task_scheduler/internal/android/junit/src/org/chromium/components/background_task_scheduler/internal/BackgroundTaskSchedulerPrefsTest.java
+++ b/chromium/components/background_task_scheduler/internal/android/junit/src/org/chromium/components/background_task_scheduler/internal/BackgroundTaskSchedulerPrefsTest.java
@@ -16,6 +16,7 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.annotation.Config;
+import org.robolectric.annotation.LooperMode;
import org.robolectric.util.ReflectionHelpers;
import org.chromium.base.ContextUtils;
@@ -34,6 +35,7 @@ import java.util.concurrent.TimeUnit;
/** Unit tests for {@link BackgroundTaskSchedulerPrefs}. */
@RunWith(BaseRobolectricTestRunner.class)
@Config(manifest = Config.NONE)
+@LooperMode(LooperMode.Mode.LEGACY)
public class BackgroundTaskSchedulerPrefsTest {
private TaskInfo mTask1;
private TaskInfo mTask2;
diff --git a/chromium/components/background_task_scheduler/internal/android/junit/src/org/chromium/components/background_task_scheduler/internal/BackgroundTaskSchedulerUmaTest.java b/chromium/components/background_task_scheduler/internal/android/junit/src/org/chromium/components/background_task_scheduler/internal/BackgroundTaskSchedulerUmaTest.java
index 9e2844f7109..0d5fd481b10 100644
--- a/chromium/components/background_task_scheduler/internal/android/junit/src/org/chromium/components/background_task_scheduler/internal/BackgroundTaskSchedulerUmaTest.java
+++ b/chromium/components/background_task_scheduler/internal/android/junit/src/org/chromium/components/background_task_scheduler/internal/BackgroundTaskSchedulerUmaTest.java
@@ -125,9 +125,6 @@ public class BackgroundTaskSchedulerUmaTest {
BackgroundTaskSchedulerUma.toUmaEnumValueFromTaskId(TaskIds.QUERY_TILE_JOB_ID));
assertEquals(BackgroundTaskSchedulerUma.BACKGROUND_TASK_FEEDV2_REFRESH,
BackgroundTaskSchedulerUma.toUmaEnumValueFromTaskId(TaskIds.FEEDV2_REFRESH_JOB_ID));
- assertEquals(BackgroundTaskSchedulerUma.BACKGROUND_TASK_OFFLINE_MEASUREMENTS,
- BackgroundTaskSchedulerUma.toUmaEnumValueFromTaskId(
- TaskIds.OFFLINE_MEASUREMENT_JOB_ID));
assertEquals(BackgroundTaskSchedulerUma.BACKGROUND_TASK_WEBVIEW_COMPONENT_UPDATE,
BackgroundTaskSchedulerUma.toUmaEnumValueFromTaskId(
TaskIds.WEBVIEW_COMPONENT_UPDATE_JOB_ID));
diff --git a/chromium/components/background_task_scheduler/internal/android/junit/src/org/chromium/components/background_task_scheduler/internal/BroadcastReceiverRobolectricTest.java b/chromium/components/background_task_scheduler/internal/android/junit/src/org/chromium/components/background_task_scheduler/internal/BroadcastReceiverRobolectricTest.java
index 717661bebdd..ca8b4e04bdb 100644
--- a/chromium/components/background_task_scheduler/internal/android/junit/src/org/chromium/components/background_task_scheduler/internal/BroadcastReceiverRobolectricTest.java
+++ b/chromium/components/background_task_scheduler/internal/android/junit/src/org/chromium/components/background_task_scheduler/internal/BroadcastReceiverRobolectricTest.java
@@ -18,6 +18,7 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.annotation.Config;
+import org.robolectric.annotation.LooperMode;
import org.robolectric.shadows.ShadowBatteryManager;
import org.robolectric.shadows.ShadowConnectivityManager;
@@ -39,6 +40,7 @@ import java.util.concurrent.TimeUnit;
@RunWith(BaseRobolectricTestRunner.class)
@Config(manifest = Config.NONE,
shadows = {ShadowBatteryManager.class, ShadowConnectivityManager.class})
+@LooperMode(LooperMode.Mode.LEGACY)
public final class BroadcastReceiverRobolectricTest {
private static final long WAIT_TIME_MS = 10;
private CountDownLatch mScheduleLatch;
diff --git a/chromium/components/background_task_scheduler/task_ids.h b/chromium/components/background_task_scheduler/task_ids.h
index 067e1111201..2881c52abd5 100644
--- a/chromium/components/background_task_scheduler/task_ids.h
+++ b/chromium/components/background_task_scheduler/task_ids.h
@@ -48,7 +48,6 @@ enum class TaskIds {
PERIODIC_BACKGROUND_SYNC_CHROME_WAKEUP_TASK_JOB_ID = 105,
QUERY_TILE_JOB_ID = 106,
FEEDV2_REFRESH_JOB_ID = 107,
- OFFLINE_MEASUREMENT_JOB_ID = 108,
WEBFEEDS_REFRESH_JOB_ID = 109,
WEBVIEW_COMPONENT_UPDATE_JOB_ID = 110,
ATTRIBUTION_PROVIDER_FLUSH_JOB_ID = 111,
diff --git a/chromium/components/base32/base32.cc b/chromium/components/base32/base32.cc
index 96950b380eb..03cf5fee052 100644
--- a/chromium/components/base32/base32.cc
+++ b/chromium/components/base32/base32.cc
@@ -15,6 +15,9 @@ namespace base32 {
namespace {
+constexpr char kEncoding[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
+constexpr char kPaddingChar = '=';
+
// Returns a 5 bit number between [0,31] matching the provided base 32 encoded
// character. Returns 0xff on error.
uint8_t ReverseMapping(char input_char) {
diff --git a/chromium/components/base32/base32.h b/chromium/components/base32/base32.h
index 52fc745ac47..7be608d8478 100644
--- a/chromium/components/base32/base32.h
+++ b/chromium/components/base32/base32.h
@@ -11,9 +11,6 @@
namespace base32 {
-constexpr char kEncoding[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
-constexpr char kPaddingChar = '=';
-
enum class Base32EncodePolicy {
// Include the trailing padding in the output, when necessary.
INCLUDE_PADDING,
diff --git a/chromium/components/blocked_content/android/popup_blocked_helper.cc b/chromium/components/blocked_content/android/popup_blocked_helper.cc
index b0219aa49d2..4c87edb206f 100644
--- a/chromium/components/blocked_content/android/popup_blocked_helper.cc
+++ b/chromium/components/blocked_content/android/popup_blocked_helper.cc
@@ -17,7 +17,7 @@ void ShowBlockedPopups(content::WebContents* web_contents) {
bool PopupSettingManagedByPolicy(HostContentSettingsMap* map, const GURL& url) {
content_settings::SettingInfo setting_info;
- std::unique_ptr<base::Value> setting = map->GetWebsiteSetting(
+ const base::Value setting = map->GetWebsiteSetting(
url, url, ContentSettingsType::POPUPS, &setting_info);
return setting_info.source == content_settings::SETTING_SOURCE_POLICY;
}
diff --git a/chromium/components/blocked_content/popup_opener_tab_helper.cc b/chromium/components/blocked_content/popup_opener_tab_helper.cc
index 1412f4230ce..c09d054d577 100644
--- a/chromium/components/blocked_content/popup_opener_tab_helper.cc
+++ b/chromium/components/blocked_content/popup_opener_tab_helper.cc
@@ -86,8 +86,14 @@ void PopupOpenerTabHelper::DidGetUserInteraction(
void PopupOpenerTabHelper::DidStartNavigation(
content::NavigationHandle* navigation_handle) {
// Treat browser-initiated navigations as user interactions.
- if (!navigation_handle->IsRendererInitiated())
+ // Note that |HasUserGesture| does not capture browser-initiated navigations.
+ // The negation of |IsRendererInitiated| tells us whether the navigation is
+ // browser-generated.
+ if (navigation_handle->IsInPrimaryMainFrame() &&
+ (navigation_handle->HasUserGesture() ||
+ !navigation_handle->IsRendererInitiated())) {
has_opened_popup_since_last_user_gesture_ = false;
+ }
}
void PopupOpenerTabHelper::MaybeLogPagePopupContentSettings() {
diff --git a/chromium/components/blocked_content/safe_browsing_triggered_popup_blocker.cc b/chromium/components/blocked_content/safe_browsing_triggered_popup_blocker.cc
index 87f77b7bc25..137ba1b838d 100644
--- a/chromium/components/blocked_content/safe_browsing_triggered_popup_blocker.cc
+++ b/chromium/components/blocked_content/safe_browsing_triggered_popup_blocker.cc
@@ -154,7 +154,7 @@ void SafeBrowsingTriggeredPopupBlocker::DidFinishNavigation(
back_forward_cache::DisabledReasonId::
kSafeBrowsingTriggeredPopupBlocker));
} else if (level == SubresourceFilterLevel::WARN) {
- web_contents()->GetMainFrame()->AddMessageToConsole(
+ navigation_handle->GetRenderFrameHost()->AddMessageToConsole(
blink::mojom::ConsoleMessageLevel::kWarning, kAbusiveWarnMessage);
LogAction(Action::kWarningSite);
}
diff --git a/chromium/components/blocklist/opt_out_blocklist/sql/opt_out_store_sql.cc b/chromium/components/blocklist/opt_out_blocklist/sql/opt_out_store_sql.cc
index 62ed9e87ead..109721d8cbd 100644
--- a/chromium/components/blocklist/opt_out_blocklist/sql/opt_out_store_sql.cc
+++ b/chromium/components/blocklist/opt_out_blocklist/sql/opt_out_store_sql.cc
@@ -6,13 +6,13 @@
#include <map>
#include <string>
+#include <tuple>
#include <utility>
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/command_line.h"
#include "base/files/file_util.h"
-#include "base/ignore_result.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/metrics/histogram_functions.h"
@@ -108,7 +108,7 @@ void DatabaseErrorCallback(sql::Database* db,
// or hardware issues, not coding errors at the client level, so displaying
// the error would probably lead to confusion. The ignored call signals the
// test-expectation framework that the error was handled.
- ignore_result(sql::Database::IsExpectedSqliteError(extended_error));
+ std::ignore = sql::Database::IsExpectedSqliteError(extended_error);
return;
}
}
diff --git a/chromium/components/bookmarks/browser/bookmark_codec.cc b/chromium/components/bookmarks/browser/bookmark_codec.cc
index 16b50c5807b..97be25d3dc2 100644
--- a/chromium/components/bookmarks/browser/bookmark_codec.cc
+++ b/chromium/components/bookmarks/browser/bookmark_codec.cc
@@ -29,7 +29,7 @@ using base::Time;
namespace bookmarks {
const char BookmarkCodec::kRootsKey[] = "roots";
-const char BookmarkCodec::kRootFolderNameKey[] = "bookmark_bar";
+const char BookmarkCodec::kBookmarkBarFolderNameKey[] = "bookmark_bar";
const char BookmarkCodec::kOtherBookmarkFolderNameKey[] = "other";
// The value is left as 'synced' for historical reasons.
const char BookmarkCodec::kMobileBookmarkFolderNameKey[] = "synced";
@@ -51,6 +51,18 @@ const char BookmarkCodec::kSyncMetadata[] = "sync_metadata";
// Current version of the file.
static const int kCurrentVersion = 1;
+namespace {
+
+// Encodes Sync metadata and cleans up the input string to decrease peak memory
+// usage during encoding.
+base::Value EncodeSyncMetadata(std::string sync_metadata_str) {
+ std::string sync_metadata_str_base64;
+ base::Base64Encode(sync_metadata_str, &sync_metadata_str_base64);
+ return base::Value(std::move(sync_metadata_str_base64));
+}
+
+} // namespace
+
BookmarkCodec::BookmarkCodec()
: ids_reassigned_(false),
guids_reassigned_(false),
@@ -60,10 +72,10 @@ BookmarkCodec::BookmarkCodec()
BookmarkCodec::~BookmarkCodec() = default;
base::Value BookmarkCodec::Encode(BookmarkModel* model,
- const std::string& sync_metadata_str) {
+ std::string sync_metadata_str) {
return Encode(model->bookmark_bar_node(), model->other_node(),
model->mobile_node(), model->root_node()->GetMetaInfoMap(),
- sync_metadata_str);
+ std::move(sync_metadata_str));
}
base::Value BookmarkCodec::Encode(
@@ -71,30 +83,35 @@ base::Value BookmarkCodec::Encode(
const BookmarkNode* other_folder_node,
const BookmarkNode* mobile_folder_node,
const BookmarkNode::MetaInfoMap* model_meta_info_map,
- const std::string& sync_metadata_str) {
+ std::string sync_metadata_str) {
ids_reassigned_ = false;
guids_reassigned_ = false;
+
+ base::Value main(base::Value::Type::DICTIONARY);
+ main.SetIntKey(kVersionKey, kCurrentVersion);
+
+ // Encode Sync metadata before encoding other fields to reduce peak memory
+ // usage.
+ if (!sync_metadata_str.empty()) {
+ main.SetKey(kSyncMetadata,
+ EncodeSyncMetadata(std::move(sync_metadata_str)));
+ sync_metadata_str.clear();
+ }
+
InitializeChecksum();
base::Value roots(base::Value::Type::DICTIONARY);
- roots.SetKey(kRootFolderNameKey, EncodeNode(bookmark_bar_node));
+ roots.SetKey(kBookmarkBarFolderNameKey, EncodeNode(bookmark_bar_node));
roots.SetKey(kOtherBookmarkFolderNameKey, EncodeNode(other_folder_node));
roots.SetKey(kMobileBookmarkFolderNameKey, EncodeNode(mobile_folder_node));
if (model_meta_info_map)
roots.SetKey(kMetaInfo, EncodeMetaInfo(*model_meta_info_map));
- base::Value main(base::Value::Type::DICTIONARY);
- main.SetIntKey(kVersionKey, kCurrentVersion);
FinalizeChecksum();
// We are going to store the computed checksum. So set stored checksum to be
// the same as computed checksum.
stored_checksum_ = computed_checksum_;
main.SetStringKey(kChecksumKey, computed_checksum_);
+
main.SetKey(kRootsKey, std::move(roots));
- if (!sync_metadata_str.empty()) {
- std::string sync_metadata_str_base64;
- base::Base64Encode(sync_metadata_str, &sync_metadata_str_base64);
- main.SetKey(kSyncMetadata,
- base::Value(std::move(sync_metadata_str_base64)));
- }
return main;
}
@@ -193,32 +210,18 @@ bool BookmarkCodec::DecodeHelper(BookmarkNode* bb_node,
const base::Value* roots = value.FindDictKey(kRootsKey);
if (!roots)
return false; // No roots, or invalid type for roots.
- const base::Value* root_folder_value = roots->FindDictKey(kRootFolderNameKey);
+ const base::Value* bb_value = roots->FindDictKey(kBookmarkBarFolderNameKey);
const base::Value* other_folder_value =
roots->FindDictKey(kOtherBookmarkFolderNameKey);
- if (!root_folder_value || !other_folder_value) {
- return false; // Invalid type for root folder and/or other
- // folder.
- }
- DecodeNode(*root_folder_value, nullptr, bb_node);
- DecodeNode(*other_folder_value, nullptr, other_folder_node);
-
- // Fail silently if we can't deserialize mobile bookmarks. We can't require
- // them to exist in order to be backwards-compatible with older versions of
- // chrome.
const base::Value* mobile_folder_value =
roots->FindDictKey(kMobileBookmarkFolderNameKey);
- if (mobile_folder_value) {
- DecodeNode(*mobile_folder_value, nullptr, mobile_folder_node);
- } else {
- // If we didn't find the mobile folder, we're almost guaranteed to have a
- // duplicate id when we add the mobile folder. Consequently, if we don't
- // intend to reassign ids in the future (ids_valid_ is still true), then at
- // least reassign the mobile bookmarks to avoid it colliding with anything
- // else.
- if (ids_valid_)
- ReassignIDsHelper(mobile_folder_node);
- }
+
+ if (!bb_value || !other_folder_value || !mobile_folder_value)
+ return false;
+
+ DecodeNode(*bb_value, nullptr, bb_node);
+ DecodeNode(*other_folder_value, nullptr, other_folder_node);
+ DecodeNode(*mobile_folder_value, nullptr, mobile_folder_node);
if (!DecodeMetaInfo(*roots, &model_meta_info_map_))
return false;
@@ -244,7 +247,7 @@ bool BookmarkCodec::DecodeHelper(BookmarkNode* bb_node,
bool BookmarkCodec::DecodeChildren(const base::Value& child_value_list,
BookmarkNode* parent) {
DCHECK(child_value_list.is_list());
- for (const base::Value& child_value : child_value_list.GetList()) {
+ for (const base::Value& child_value : child_value_list.GetListDeprecated()) {
if (!child_value.is_dict())
return false;
DecodeNode(child_value, parent, nullptr);
diff --git a/chromium/components/bookmarks/browser/bookmark_codec.h b/chromium/components/bookmarks/browser/bookmark_codec.h
index 3426e6bd0f4..eb9f5da763e 100644
--- a/chromium/components/bookmarks/browser/bookmark_codec.h
+++ b/chromium/components/bookmarks/browser/bookmark_codec.h
@@ -42,15 +42,14 @@ class BookmarkCodec {
// Encodes the model to a JSON value. This is invoked to encode the contents
// of the bookmark bar model and is currently a convenience to invoking Encode
// that takes the bookmark bar node and other folder node.
- base::Value Encode(BookmarkModel* model,
- const std::string& sync_metadata_str);
+ base::Value Encode(BookmarkModel* model, std::string sync_metadata_str);
// Encodes the bookmark bar and other folders returning the JSON value.
base::Value Encode(const BookmarkNode* bookmark_bar_node,
const BookmarkNode* other_folder_node,
const BookmarkNode* mobile_folder_node,
const BookmarkNode::MetaInfoMap* model_meta_info_map,
- const std::string& sync_metadata_str);
+ std::string sync_metadata_str);
// Decodes the previously encoded value to the specified nodes as well as
// setting |max_node_id| to the greatest node id. Returns true on success,
@@ -89,7 +88,7 @@ class BookmarkCodec {
// Names of the various keys written to the Value.
static const char kRootsKey[];
- static const char kRootFolderNameKey[];
+ static const char kBookmarkBarFolderNameKey[];
static const char kOtherBookmarkFolderNameKey[];
static const char kMobileBookmarkFolderNameKey[];
static const char kVersionKey[];
diff --git a/chromium/components/bookmarks/browser/bookmark_codec_unittest.cc b/chromium/components/bookmarks/browser/bookmark_codec_unittest.cc
index c1a985c7f51..8cce5fa7177 100644
--- a/chromium/components/bookmarks/browser/bookmark_codec_unittest.cc
+++ b/chromium/components/bookmarks/browser/bookmark_codec_unittest.cc
@@ -125,14 +125,15 @@ class BookmarkCodecTest : public testing::Test {
ASSERT_TRUE(roots);
base::Value* bb_value =
- roots->FindDictKey(BookmarkCodec::kRootFolderNameKey);
+ roots->FindDictKey(BookmarkCodec::kBookmarkBarFolderNameKey);
ASSERT_TRUE(bb_value);
base::Value* bb_children_value =
bb_value->FindListKey(BookmarkCodec::kChildrenKey);
ASSERT_TRUE(bb_children_value);
- base::Value::ListView bb_children_l_value = bb_children_value->GetList();
+ base::Value::ListView bb_children_l_value =
+ bb_children_value->GetListDeprecated();
ASSERT_LT(index, bb_children_l_value.size());
base::Value& child_value = bb_children_l_value[index];
@@ -378,7 +379,7 @@ TEST_F(BookmarkCodecTest, PersistIDsTest) {
AssertModelsEqual(decoded_model.get(), decoded_model2.get()));
}
-TEST_F(BookmarkCodecTest, CanDecodeModelWithoutMobileBookmarks) {
+TEST_F(BookmarkCodecTest, CannotDecodeModelWithoutMobileBookmarks) {
base::FilePath test_file =
GetTestDataDir().AppendASCII("bookmarks/model_without_sync.json");
ASSERT_TRUE(base::PathExists(test_file));
@@ -390,35 +391,8 @@ TEST_F(BookmarkCodecTest, CanDecodeModelWithoutMobileBookmarks) {
std::unique_ptr<BookmarkModel> decoded_model(
TestBookmarkClient::CreateModel());
BookmarkCodec decoder;
- ASSERT_TRUE(Decode(&decoder, *root.get(), decoded_model.get(),
- /*sync_metadata_str=*/nullptr));
- ExpectIDsUnique(decoded_model.get());
-
- const BookmarkNode* bbn = decoded_model->bookmark_bar_node();
- ASSERT_EQ(1u, bbn->children().size());
-
- const BookmarkNode* child = bbn->children().front().get();
- EXPECT_EQ(BookmarkNode::FOLDER, child->type());
- EXPECT_EQ(u"Folder A", child->GetTitle());
- ASSERT_EQ(1u, child->children().size());
-
- child = child->children().front().get();
- EXPECT_EQ(BookmarkNode::URL, child->type());
- EXPECT_EQ(u"Bookmark Manager", child->GetTitle());
-
- const BookmarkNode* other = decoded_model->other_node();
- ASSERT_EQ(1u, other->children().size());
-
- child = other->children().front().get();
- EXPECT_EQ(BookmarkNode::FOLDER, child->type());
- EXPECT_EQ(u"Folder B", child->GetTitle());
- ASSERT_EQ(1u, child->children().size());
-
- child = child->children().front().get();
- EXPECT_EQ(BookmarkNode::URL, child->type());
- EXPECT_EQ(u"Get started with Google Chrome", child->GetTitle());
-
- ASSERT_TRUE(decoded_model->mobile_node() != nullptr);
+ EXPECT_FALSE(Decode(&decoder, *root.get(), decoded_model.get(),
+ /*sync_metadata_str=*/nullptr));
}
TEST_F(BookmarkCodecTest, EncodeAndDecodeMetaInfo) {
diff --git a/chromium/components/bookmarks/browser/bookmark_expanded_state_tracker.cc b/chromium/components/bookmarks/browser/bookmark_expanded_state_tracker.cc
index 677552fa8fc..39148bb13eb 100644
--- a/chromium/components/bookmarks/browser/bookmark_expanded_state_tracker.cc
+++ b/chromium/components/bookmarks/browser/bookmark_expanded_state_tracker.cc
@@ -48,7 +48,7 @@ BookmarkExpandedStateTracker::GetExpandedNodes() {
return nodes;
bool changed = false;
- for (const auto& entry : value->GetList()) {
+ for (const auto& entry : value->GetListDeprecated()) {
int64_t node_id;
const BookmarkNode* node;
const std::string* value_str = entry.GetIfString();
diff --git a/chromium/components/bookmarks/browser/bookmark_model.cc b/chromium/components/bookmarks/browser/bookmark_model.cc
index 3f1dd190eb8..5f41cf15f31 100644
--- a/chromium/components/bookmarks/browser/bookmark_model.cc
+++ b/chromium/components/bookmarks/browser/bookmark_model.cc
@@ -660,9 +660,8 @@ void BookmarkModel::SortChildren(const BookmarkNode* parent) {
std::unique_ptr<icu::Collator> collator(icu::Collator::createInstance(error));
if (U_FAILURE(error))
collator.reset(nullptr);
- BookmarkNode* mutable_parent = AsMutable(parent);
- std::sort(mutable_parent->children_.begin(), mutable_parent->children_.end(),
- SortComparator(collator.get()));
+
+ AsMutable(parent)->SortChildren(SortComparator(collator.get()));
if (store_)
store_->ScheduleSave();
@@ -690,14 +689,15 @@ void BookmarkModel::ReorderChildren(
for (size_t i = 0; i < ordered_nodes.size(); ++i)
order[ordered_nodes[i]] = i;
- std::vector<std::unique_ptr<BookmarkNode>> new_children(
- ordered_nodes.size());
- BookmarkNode* mutable_parent = AsMutable(parent);
- for (auto& child : mutable_parent->children_) {
- size_t new_location = order[child.get()];
- new_children[new_location] = std::move(child);
+ std::vector<size_t> new_order(ordered_nodes.size());
+ for (size_t old_index = 0; old_index < parent->children().size();
+ ++old_index) {
+ const BookmarkNode* node = parent->children()[old_index].get();
+ size_t new_index = order[node];
+ new_order[old_index] = new_index;
}
- mutable_parent->children_.swap(new_children);
+
+ AsMutable(parent)->ReorderChildren(new_order);
if (store_)
store_->ScheduleSave();
@@ -811,8 +811,7 @@ void BookmarkModel::DoneLoading(std::unique_ptr<BookmarkLoadDetails> details) {
std::make_unique<TypedCountSorter>(client_.get()));
// Sorting the permanent nodes has to happen on the main thread, so we do it
// here, after loading completes.
- std::stable_sort(root_->children_.begin(), root_->children_.end(),
- VisibilityComparator(client_.get()));
+ root_->SortChildren(VisibilityComparator(client_.get()));
root_->SetMetaInfoMap(details->model_meta_info_map());
diff --git a/chromium/components/bookmarks/browser/bookmark_model_unittest.cc b/chromium/components/bookmarks/browser/bookmark_model_unittest.cc
index 17579be4839..ac8477d96a1 100644
--- a/chromium/components/bookmarks/browser/bookmark_model_unittest.cc
+++ b/chromium/components/bookmarks/browser/bookmark_model_unittest.cc
@@ -1098,14 +1098,14 @@ TEST_F(BookmarkModelTest, Copy) {
// Tests the default node if no bookmarks have been added yet
TEST_F(BookmarkModelTest, ParentForNewNodesWithEmptyModel) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
ASSERT_EQ(model_->mobile_node(), GetParentForNewNodes(model_.get()));
#else
ASSERT_EQ(model_->bookmark_bar_node(), GetParentForNewNodes(model_.get()));
#endif
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Tests that the bookmark_bar_node can still be returned even on Android in
// case the last bookmark was added to it.
TEST_F(BookmarkModelTest, ParentCanBeBookmarkBarOnAndroid) {
diff --git a/chromium/components/bookmarks/browser/bookmark_node_data.cc b/chromium/components/bookmarks/browser/bookmark_node_data.cc
index aeb33e0936a..14648d29a75 100644
--- a/chromium/components/bookmarks/browser/bookmark_node_data.cc
+++ b/chromium/components/bookmarks/browser/bookmark_node_data.cc
@@ -11,12 +11,13 @@
#include "base/numerics/safe_conversions.h"
#include "base/pickle.h"
#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
#include "components/bookmarks/browser/bookmark_utils.h"
#include "ui/base/clipboard/scoped_clipboard_writer.h"
namespace bookmarks {
-#if !defined(OS_APPLE)
+#if !BUILDFLAG(IS_APPLE)
namespace {
constexpr size_t kMaxVectorPreallocateSize = 10000;
} // namespace
@@ -46,7 +47,7 @@ BookmarkNodeData::Element::Element(const Element& other) = default;
BookmarkNodeData::Element::~Element() {
}
-#if !defined(OS_APPLE)
+#if !BUILDFLAG(IS_APPLE)
void BookmarkNodeData::Element::WriteToPickle(base::Pickle* pickle) const {
pickle->WriteBool(is_url);
pickle->WriteString(url.spec());
@@ -135,7 +136,7 @@ BookmarkNodeData::BookmarkNodeData(
BookmarkNodeData::~BookmarkNodeData() {
}
-#if !defined(OS_APPLE)
+#if !BUILDFLAG(IS_APPLE)
// static
bool BookmarkNodeData::ClipboardContainsBookmarks() {
ui::DataTransferEndpoint data_dst = ui::DataTransferEndpoint(
@@ -176,11 +177,11 @@ bool BookmarkNodeData::ReadFromTuple(const GURL& url,
return true;
}
-#if !defined(OS_APPLE)
+#if !BUILDFLAG(IS_APPLE)
void BookmarkNodeData::WriteToClipboard() {
ui::ScopedClipboardWriter scw(ui::ClipboardBuffer::kCopyPaste);
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
const std::u16string kEOL(u"\r\n");
#else
const std::u16string kEOL = u"\n";
@@ -286,7 +287,7 @@ bool BookmarkNodeData::ReadFromPickle(base::Pickle* pickle) {
return true;
}
-#endif // OS_APPLE
+#endif // BUILDFLAG(IS_APPLE)
std::vector<const BookmarkNode*> BookmarkNodeData::GetNodes(
BookmarkModel* model,
diff --git a/chromium/components/bookmarks/browser/bookmark_node_data.h b/chromium/components/bookmarks/browser/bookmark_node_data.h
index 36cf5ee89da..47ab5ef5778 100644
--- a/chromium/components/bookmarks/browser/bookmark_node_data.h
+++ b/chromium/components/bookmarks/browser/bookmark_node_data.h
@@ -89,7 +89,7 @@ struct BookmarkNodeData {
private:
friend struct BookmarkNodeData;
-#if !defined(OS_APPLE)
+#if !BUILDFLAG(IS_APPLE)
// For reading/writing this Element.
void WriteToPickle(base::Pickle* pickle) const;
bool ReadFromPickle(base::PickleIterator* iterator);
@@ -99,7 +99,7 @@ struct BookmarkNodeData {
int64_t id_;
};
-#if !defined(OS_APPLE)
+#if !BUILDFLAG(IS_APPLE)
// The MIME type for the clipboard format for BookmarkNodeData. This type is
// not used on the Mac.
static const char kClipboardFormatString[];
@@ -146,7 +146,7 @@ struct BookmarkNodeData {
bool Read(const ui::OSExchangeData& data);
#endif
-#if !defined(OS_APPLE)
+#if !BUILDFLAG(IS_APPLE)
// Writes the data for a drag to |pickle|.
void WriteToPickle(const base::FilePath& profile_path,
base::Pickle* pickle) const;
diff --git a/chromium/components/bookmarks/browser/bookmark_node_data_unittest.cc b/chromium/components/bookmarks/browser/bookmark_node_data_unittest.cc
index 4f21e5a79c6..1586c27a645 100644
--- a/chromium/components/bookmarks/browser/bookmark_node_data_unittest.cc
+++ b/chromium/components/bookmarks/browser/bookmark_node_data_unittest.cc
@@ -89,7 +89,7 @@ TEST_F(BookmarkNodeDataTest, BogusRead) {
// Writes a URL to the clipboard and make sure BookmarkNodeData can correctly
// read it.
// Test is flaky on Mac: crbug.com/1236362
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
#define MAYBE_JustURL DISABLED_JustURL
#else
#define MAYBE_JustURL JustURL
@@ -114,7 +114,7 @@ TEST_F(BookmarkNodeDataTest, MAYBE_JustURL) {
}
// Test is flaky on Mac: crbug.com/1236362
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
#define MAYBE_URL DISABLED_URL
#else
#define MAYBE_URL URL
@@ -167,7 +167,7 @@ TEST_F(BookmarkNodeDataTest, MAYBE_URL) {
// Tests writing a folder to the clipboard.
// Test is flaky on Mac: crbug.com/1236362
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
#define MAYBE_Folder DISABLED_Folder
#else
#define MAYBE_Folder Folder
@@ -214,7 +214,7 @@ TEST_F(BookmarkNodeDataTest, MAYBE_Folder) {
// Tests reading/writing a folder with children.
// Test is flaky on Mac: crbug.com/1236362
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
#define MAYBE_FolderWithChild DISABLED_FolderWithChild
#else
#define MAYBE_FolderWithChild FolderWithChild
@@ -257,7 +257,7 @@ TEST_F(BookmarkNodeDataTest, MAYBE_FolderWithChild) {
// Tests reading/writing of multiple nodes.
// Test is flaky on Mac: crbug.com/1236362
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
#define MAYBE_MultipleNodes DISABLED_MultipleNodes
#else
#define MAYBE_MultipleNodes MultipleNodes
@@ -326,7 +326,7 @@ TEST_F(BookmarkNodeDataTest, DISABLED_WriteToClipboardURL) {
EXPECT_EQ(base::UTF8ToUTF16(url.spec()), clipboard_result);
}
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
#define MAYBE_WriteToClipboardMultipleURLs DISABLED_WriteToClipboardMultipleURLs
#else
#define MAYBE_WriteToClipboardMultipleURLs WriteToClipboardMultipleURLs
@@ -349,7 +349,7 @@ TEST_F(BookmarkNodeDataTest, MAYBE_WriteToClipboardMultipleURLs) {
// Now read the data back in.
std::u16string combined_text;
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
std::u16string new_line = u"\r\n";
#else
std::u16string new_line = u"\n";
@@ -363,7 +363,7 @@ TEST_F(BookmarkNodeDataTest, MAYBE_WriteToClipboardMultipleURLs) {
}
// Test is flaky on LaCrOS: crbug.com/1010185
-#if defined(OS_APPLE) || BUILDFLAG(IS_CHROMEOS_LACROS)
+#if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_CHROMEOS_LACROS)
#define MAYBE_WriteToClipboardEmptyFolder DISABLED_WriteToClipboardEmptyFolder
#else
#define MAYBE_WriteToClipboardEmptyFolder WriteToClipboardEmptyFolder
@@ -387,7 +387,7 @@ TEST_F(BookmarkNodeDataTest, MAYBE_WriteToClipboardEmptyFolder) {
// Test is flaky on LaCrOS: crbug.com/1010353
// Test is flaky on Mac: crbug.com/1236362
-#if defined(OS_MAC) || BUILDFLAG(IS_CHROMEOS_LACROS)
+#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS_LACROS)
#define MAYBE_WriteToClipboardFolderWithChildren \
DISABLED_WriteToClipboardFolderWithChildren
#else
@@ -432,7 +432,7 @@ TEST_F(BookmarkNodeDataTest, DISABLED_WriteToClipboardFolderAndURL) {
// Now read the data back in.
std::u16string combined_text;
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
std::u16string new_line = u"\r\n";
#else
std::u16string new_line = u"\n";
@@ -447,7 +447,7 @@ TEST_F(BookmarkNodeDataTest, DISABLED_WriteToClipboardFolderAndURL) {
// Tests reading/writing of meta info.
// Test is flaky on Mac: crbug.com/1236362
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
#define MAYBE_MetaInfo DISABLED_MetaInfo
#else
#define MAYBE_MetaInfo MetaInfo
@@ -477,7 +477,7 @@ TEST_F(BookmarkNodeDataTest, MAYBE_MetaInfo) {
EXPECT_EQ("someothervalue", meta_info_map["someotherkey"]);
}
-#if !defined(OS_APPLE)
+#if !BUILDFLAG(IS_APPLE)
TEST_F(BookmarkNodeDataTest, ReadFromPickleTooManyNodes) {
// Test case determined by a fuzzer. See https://crbug.com/956583.
const uint8_t pickled_data[] = {0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
diff --git a/chromium/components/bookmarks/browser/bookmark_utils.cc b/chromium/components/bookmarks/browser/bookmark_utils.cc
index 0acb753d6d5..07e14a994e2 100644
--- a/chromium/components/bookmarks/browser/bookmark_utils.cc
+++ b/chromium/components/bookmarks/browser/bookmark_utils.cc
@@ -145,7 +145,7 @@ std::string TruncateUrl(const std::string& url) {
// returned.
GURL GetUrlFromClipboard(bool notify_if_restricted) {
std::u16string url_text;
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
ui::DataTransferEndpoint data_dst = ui::DataTransferEndpoint(
ui::EndpointType::kDefault, notify_if_restricted);
ui::Clipboard::GetForCurrentThread()->ReadText(
@@ -179,7 +179,7 @@ void GetBookmarksMatchingPropertiesImpl(
}
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Returns whether or not a bookmark model contains any bookmarks aside of the
// permanent nodes.
bool HasUserCreatedBookmarks(BookmarkModel* model) {
@@ -578,7 +578,7 @@ bool HasDescendantsOf(const std::vector<const BookmarkNode*>& list,
}
const BookmarkNode* GetParentForNewNodes(BookmarkModel* model) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
if (!HasUserCreatedBookmarks(model))
return model->mobile_node();
#endif
diff --git a/chromium/components/bookmarks/browser/bookmark_utils_unittest.cc b/chromium/components/bookmarks/browser/bookmark_utils_unittest.cc
index 96f8e878c9d..c1f9d39cedf 100644
--- a/chromium/components/bookmarks/browser/bookmark_utils_unittest.cc
+++ b/chromium/components/bookmarks/browser/bookmark_utils_unittest.cc
@@ -43,11 +43,11 @@ class BookmarkUtilsTest : public testing::Test,
~BookmarkUtilsTest() override {}
// Copy and paste is not yet supported on iOS. http://crbug.com/228147
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
void TearDown() override {
ui::Clipboard::DestroyClipboardForCurrentThread();
}
-#endif // !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_IOS)
// Certain user actions require multiple changes to the bookmark model,
// however these modifications need to be atomic for the undo framework. The
@@ -58,7 +58,7 @@ class BookmarkUtilsTest : public testing::Test,
int expected_ended_count) {
// The undo framework is not used under Android. Thus the group change
// events will not be fired and so should not be tested for Android.
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
EXPECT_EQ(grouped_changes_beginning_count_, expected_beginning_count);
EXPECT_EQ(grouped_changes_ended_count_, expected_ended_count);
#endif
@@ -246,7 +246,7 @@ TEST_F(BookmarkUtilsTest, GetBookmarksMatchingPropertiesConjunction) {
}
// Copy and paste is not yet supported on iOS. http://crbug.com/228147
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
TEST_F(BookmarkUtilsTest, DISABLED_PasteBookmarkFromURL) {
std::unique_ptr<BookmarkModel> model(TestBookmarkClient::CreateModel());
const std::u16string url_text = u"http://www.google.com/";
@@ -278,7 +278,7 @@ TEST_F(BookmarkUtilsTest, DISABLED_PasteBookmarkFromURL) {
}
// TODO(https://crbug.com/1010182): Fix flakes and re-enable this test.
-#if defined(OS_WIN) || defined(OS_MAC)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
#define MAYBE_CopyPaste DISABLED_CopyPaste
#else
#define MAYBE_CopyPaste CopyPaste
@@ -374,7 +374,7 @@ TEST_F(BookmarkUtilsTest, DISABLED_CopyPasteMetaInfo) {
EXPECT_EQ("someothervalue", value);
}
-#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_MAC)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_MAC)
// http://crbug.com/396472
#define MAYBE_CutToClipboard DISABLED_CutToClipboard
#else
@@ -406,7 +406,7 @@ TEST_F(BookmarkUtilsTest, MAYBE_CutToClipboard) {
}
// Test is flaky on Mac and LaCros: crbug.com/1236362
-#if defined(OS_MAC) || BUILDFLAG(IS_CHROMEOS_LACROS)
+#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS_LACROS)
#define MAYBE_PasteNonEditableNodes DISABLED_PasteNonEditableNodes
#else
#define MAYBE_PasteNonEditableNodes PasteNonEditableNodes
@@ -434,7 +434,7 @@ TEST_F(BookmarkUtilsTest, MAYBE_PasteNonEditableNodes) {
EXPECT_FALSE(upcast->CanBeEditedByUser(managed_node));
EXPECT_FALSE(CanPasteFromClipboard(model.get(), managed_node));
}
-#endif // !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_IOS)
TEST_F(BookmarkUtilsTest, GetParentForNewNodes) {
std::unique_ptr<BookmarkModel> model(TestBookmarkClient::CreateModel());
diff --git a/chromium/components/bookmarks/browser/titled_url_index.cc b/chromium/components/bookmarks/browser/titled_url_index.cc
index 40fa198d659..15385198455 100644
--- a/chromium/components/bookmarks/browser/titled_url_index.cc
+++ b/chromium/components/bookmarks/browser/titled_url_index.cc
@@ -6,10 +6,17 @@
#include <stdint.h>
+#include <algorithm>
+#include <unordered_set>
+#include <utility>
+
#include "base/containers/cxx20_erase.h"
#include "base/i18n/case_conversion.h"
#include "base/i18n/unicodestring.h"
#include "base/logging.h"
+#include "base/metrics/histogram_functions.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/ranges/algorithm.h"
#include "base/stl_util.h"
#include "base/strings/utf_offset_string_conversions.h"
#include "build/build_config.h"
@@ -24,6 +31,11 @@ namespace bookmarks {
namespace {
+// The maximum number of nodes to fetch when looking for nodes that match any
+// term (i.e. when invoking `RetrieveNodesMatchingAnyTerms()`). Parameterized
+// for testing.
+constexpr size_t kMatchingAnyTermsMaxNodes = 3000;
+
// Returns a normalized version of the UTF16 string |text|. If it fails to
// normalize the string, returns |text| itself as a best-effort.
std::u16string Normalize(const std::u16string& text) {
@@ -75,17 +87,49 @@ std::vector<TitledUrlMatch> TitledUrlIndex::GetResultsMatching(
size_t max_count,
query_parser::MatchingAlgorithm matching_algorithm,
bool match_ancestor_titles) {
+ SCOPED_UMA_HISTOGRAM_TIMER("Bookmarks.GetResultsMatching.Timing.Total");
const std::u16string query = Normalize(input_query);
std::vector<std::u16string> terms = ExtractQueryWords(query);
+ base::UmaHistogramExactLinear("Bookmarks.GetResultsMatching.Terms.TermsCount",
+ terms.size(), 16);
+ if (terms.empty())
+ return {};
+ for (const std::u16string& term : terms) {
+ base::UmaHistogramExactLinear(
+ "Bookmarks.GetResultsMatching.Terms.TermLength", term.size(), 16);
+ }
// When |match_ancestor_titles| is true, |matches| shouldn't exclude nodes
// that don't match every query term, as the query terms may match in the
// ancestors. |MatchTitledUrlNodeWithQuery()| below will filter out nodes that
// neither match nor ancestor-match every query term.
- TitledUrlNodeSet matches =
- match_ancestor_titles
- ? RetrieveNodesMatchingAnyTerms(terms, matching_algorithm)
- : RetrieveNodesMatchingAllTerms(terms, matching_algorithm);
+ TitledUrlNodeSet matches;
+ {
+ SCOPED_UMA_HISTOGRAM_TIMER(
+ "Bookmarks.GetResultsMatching.Timing.RetrievingNodes");
+ matches = match_ancestor_titles
+ ? RetrieveNodesMatchingAnyTerms(terms, matching_algorithm,
+ kMatchingAnyTermsMaxNodes)
+ : RetrieveNodesMatchingAllTerms(terms, matching_algorithm);
+ }
+ base::UmaHistogramBoolean("Bookmarks.GetResultsMatching.AnyTermApproach.Used",
+ match_ancestor_titles);
+ base::UmaHistogramCounts10000("Bookmarks.GetResultsMatching.Nodes.Count",
+ matches.size());
+ // Slice by 3, the default value of
+ // `kShortBookmarkSuggestionsByTotalInputLengthThreshold`. Shorter inputs will
+ // likely have many fewer nodes than longer queries.
+ if (input_query.size() < 3) {
+ base::UmaHistogramCounts10000(
+ "Bookmarks.GetResultsMatching.Nodes.Count."
+ "InputsShorterThan3CharsLong",
+ matches.size());
+ } else {
+ base::UmaHistogramCounts10000(
+ "Bookmarks.GetResultsMatching.Nodes.Count.InputsAtLeast3CharsLong",
+ matches.size());
+ }
+
if (matches.empty())
return {};
@@ -99,24 +143,20 @@ std::vector<TitledUrlMatch> TitledUrlIndex::GetResultsMatching(
query_parser::QueryParser::ParseQueryNodes(query, matching_algorithm,
&query_nodes);
- // The highest typed counts should be at the beginning of the results vector
- // so that the best matches will always be included in the results. The loop
- // that calculates result relevance in HistoryContentsProvider::ConvertResults
- // will run backwards to assure higher relevance will be attributed to the
- // best matches.
- std::vector<TitledUrlMatch> results;
- for (TitledUrlNodes::const_iterator i = sorted_nodes.begin();
- i != sorted_nodes.end() && results.size() < max_count; ++i) {
- absl::optional<TitledUrlMatch> match =
- MatchTitledUrlNodeWithQuery(*i, query_nodes, match_ancestor_titles);
- if (match)
- results.push_back(match.value());
- }
+ std::vector<TitledUrlMatch> results = MatchTitledUrlNodesWithQuery(
+ sorted_nodes, query_nodes, max_count, match_ancestor_titles);
+
+ // In practice, `max_count`, is always 50 (`kMaxBookmarkMatches`), so
+ // `results.size()` is at most 50.
+ base::UmaHistogramExactLinear(
+ "Bookmarks.GetResultsMatching.Matches.ReturnedCount", results.size(), 51);
return results;
}
void TitledUrlIndex::SortMatches(const TitledUrlNodeSet& matches,
TitledUrlNodes* sorted_nodes) const {
+ SCOPED_UMA_HISTOGRAM_TIMER(
+ "Bookmarks.GetResultsMatching.Timing.SortingNodes");
if (sorter_) {
sorter_->SortMatches(matches, sorted_nodes);
} else {
@@ -124,6 +164,33 @@ void TitledUrlIndex::SortMatches(const TitledUrlNodeSet& matches,
}
}
+std::vector<TitledUrlMatch> TitledUrlIndex::MatchTitledUrlNodesWithQuery(
+ const TitledUrlNodes& nodes,
+ const query_parser::QueryNodeVector& query_nodes,
+ size_t max_count,
+ bool match_ancestor_titles) {
+ SCOPED_UMA_HISTOGRAM_TIMER(
+ "Bookmarks.GetResultsMatching.Timing.CreatingMatches");
+ // The highest typed counts should be at the beginning of the `matches` vector
+ // so that the best matches will always be included in the results. The loop
+ // that calculates match relevance in
+ // `HistoryContentsProvider::ConvertResults()` will run backwards to assure
+ // higher relevance will be attributed to the best matches.
+ std::vector<TitledUrlMatch> matches;
+ int nodes_considered = 0;
+ for (TitledUrlNodes::const_iterator i = nodes.begin();
+ i != nodes.end() && matches.size() < max_count; ++i) {
+ absl::optional<TitledUrlMatch> match =
+ MatchTitledUrlNodeWithQuery(*i, query_nodes, match_ancestor_titles);
+ if (match)
+ matches.emplace_back(std::move(match).value());
+ ++nodes_considered;
+ }
+ base::UmaHistogramCounts10000(
+ "Bookmarks.GetResultsMatching.Matches.ConsideredCount", nodes_considered);
+ return matches;
+}
+
absl::optional<TitledUrlMatch> TitledUrlIndex::MatchTitledUrlNodeWithQuery(
const TitledUrlNode* node,
const query_parser::QueryNodeVector& query_nodes,
@@ -193,9 +260,7 @@ absl::optional<TitledUrlMatch> TitledUrlIndex::MatchTitledUrlNodeWithQuery(
TitledUrlIndex::TitledUrlNodeSet TitledUrlIndex::RetrieveNodesMatchingAllTerms(
const std::vector<std::u16string>& terms,
query_parser::MatchingAlgorithm matching_algorithm) const {
- if (terms.empty())
- return {};
-
+ DCHECK(!terms.empty());
TitledUrlNodeSet matches =
RetrieveNodesMatchingTerm(terms[0], matching_algorithm);
for (size_t i = 1; i < terms.size() && !matches.empty(); ++i) {
@@ -210,20 +275,82 @@ TitledUrlIndex::TitledUrlNodeSet TitledUrlIndex::RetrieveNodesMatchingAllTerms(
TitledUrlIndex::TitledUrlNodeSet TitledUrlIndex::RetrieveNodesMatchingAnyTerms(
const std::vector<std::u16string>& terms,
- query_parser::MatchingAlgorithm matching_algorithm) const {
- if (terms.empty())
- return {};
-
- TitledUrlNodes matches =
- RetrieveNodesMatchingTerm(terms[0], matching_algorithm);
- for (size_t i = 1; i < terms.size(); ++i) {
+ query_parser::MatchingAlgorithm matching_algorithm,
+ size_t max_nodes) const {
+ DCHECK(!terms.empty());
+
+ std::vector<TitledUrlNodes> matches_per_term;
+ bool some_term_had_empty_matches = false;
+ for (const std::u16string& term : terms) {
+ // Use `matching_algorithm`, as opposed to exact matching, to allow inputs
+ // like 'myFolder goog' to match a 'google.com' bookmark in a 'myFolder'
+ // folder.
TitledUrlNodes term_matches =
- RetrieveNodesMatchingTerm(terms[i], matching_algorithm);
- std::copy(term_matches.begin(), term_matches.end(),
- std::back_inserter(matches));
+ RetrieveNodesMatchingTerm(term, matching_algorithm);
+ base::UmaHistogramCounts1000(
+ "Bookmarks.GetResultsMatching.AnyTermApproach.NodeCountPerTerm",
+ term_matches.size());
+ if (term_matches.empty())
+ some_term_had_empty_matches = true;
+ else
+ matches_per_term.push_back(std::move(term_matches));
}
-
- return TitledUrlNodeSet(matches);
+ base::UmaHistogramExactLinear(
+ "Bookmarks.GetResultsMatching.AnyTermApproach.TermsUnionedCount",
+ matches_per_term.size(), 16);
+
+ // Sort `matches_per_term` least frequent first. This prevents terms like
+ // 'https', which match a lot of nodes, from wasting `max_nodes` capacity.
+ base::ranges::sort(
+ matches_per_term,
+ [](size_t first, size_t second) { return first < second; },
+ [](const auto& matches) { return matches.size(); });
+
+ // Use an `unordered_set` to avoid potentially 1000's of linear time
+ // insertions into the ordered `TitledUrlNodeSet` (i.e. `flat_set`).
+ std::unordered_set<const TitledUrlNode*> matches;
+ for (const auto& term_matches : matches_per_term) {
+ for (const TitledUrlNode* node : term_matches) {
+ matches.insert(node);
+ if (matches.size() == max_nodes)
+ break;
+ }
+ if (matches.size() == max_nodes)
+ break;
+ }
+ base::UmaHistogramCounts10000(
+ "Bookmarks.GetResultsMatching.AnyTermApproach.NodeCountAnyTerms",
+ matches.size());
+
+ // Append all nodes that match every input term. This is necessary because
+ // with the `max_nodes` threshold above, it's possible that `matches` is
+ // missing some nodes that match every input term. Since `matches_per_term[i]`
+ // is a superset of the intersection of `matches_per_term`s, if
+ // `matches_per_term[0].size() <= max_nodes`, all of `matches_per_term[0]`,
+ // and therefore the intersection matches`, are already in `matches`.
+ TitledUrlNodeSet all_term_matches;
+ if (!some_term_had_empty_matches && matches_per_term[0].size() > max_nodes) {
+ all_term_matches = matches_per_term[0];
+ for (size_t i = 1; i < matches_per_term.size() && !all_term_matches.empty();
+ ++i) {
+ // Compute intersection between the two sets.
+ base::EraseIf(all_term_matches,
+ base::IsNotIn<TitledUrlNodeSet>(matches_per_term[i]));
+ }
+ // `all_term_matches` is the intersection of each term's node matches; the
+ // same as `RetrieveNodesMatchingAllTerms()`. We don't call the latter as a
+ // performance optimization.
+ DCHECK(all_term_matches ==
+ RetrieveNodesMatchingAllTerms(terms, matching_algorithm));
+ }
+ base::UmaHistogramCounts1000(
+ "Bookmarks.GetResultsMatching.AnyTermApproach.NodeCountAllTerms",
+ all_term_matches.size());
+
+ matches.insert(all_term_matches.begin(), all_term_matches.end());
+ base::UmaHistogramCounts10000(
+ "Bookmarks.GetResultsMatching.AnyTermApproach.NodeCount", matches.size());
+ return TitledUrlNodeSet(matches.begin(), matches.end());
}
TitledUrlIndex::TitledUrlNodes TitledUrlIndex::RetrieveNodesMatchingTerm(
diff --git a/chromium/components/bookmarks/browser/titled_url_index.h b/chromium/components/bookmarks/browser/titled_url_index.h
index 6730f5a97ff..477d883c550 100644
--- a/chromium/components/bookmarks/browser/titled_url_index.h
+++ b/chromium/components/bookmarks/browser/titled_url_index.h
@@ -8,6 +8,7 @@
#include <stddef.h>
#include <map>
+#include <memory>
#include <string>
#include <vector>
@@ -70,8 +71,9 @@ class TitledUrlIndex {
// For testing only.
TitledUrlNodeSet RetrieveNodesMatchingAnyTermsForTesting(
const std::vector<std::u16string>& terms,
- query_parser::MatchingAlgorithm matching_algorithm) const {
- return RetrieveNodesMatchingAnyTerms(terms, matching_algorithm);
+ query_parser::MatchingAlgorithm matching_algorithm,
+ size_t max_nodes) const {
+ return RetrieveNodesMatchingAnyTerms(terms, matching_algorithm, max_nodes);
}
private:
@@ -83,6 +85,14 @@ class TitledUrlIndex {
void SortMatches(const TitledUrlNodeSet& matches,
TitledUrlNodes* sorted_nodes) const;
+ // For each node, calls `MatchTitledUrlNodeWithQuery()` and returns the
+ // aggregated `TitledUrlMatch`s.
+ std::vector<TitledUrlMatch> MatchTitledUrlNodesWithQuery(
+ const TitledUrlNodes& nodes,
+ const query_parser::QueryNodeVector& query_nodes,
+ size_t max_count,
+ bool match_ancestor_titles);
+
// Finds |query_nodes| matches in |node| and returns a TitledUrlMatch
// containing |node| and the matches.
absl::optional<TitledUrlMatch> MatchTitledUrlNodeWithQuery(
@@ -96,9 +106,16 @@ class TitledUrlIndex {
const std::vector<std::u16string>& terms,
query_parser::MatchingAlgorithm matching_algorithm) const;
+ // Return matches for the specified `terms`. This is approximately a union of
+ // each term's match, with some limitations to avoid too many nodes being
+ // returned: terms shorter than `term_min_length` or matching more than
+ // `max_nodes_per_term` nodes won't have their nodes accumulated by union; and
+ // accumulation is capped to `max_nodes`. Guaranteed to include any node
+ // `RetrieveNodesMatchingAllTerms()` includes.
TitledUrlNodeSet RetrieveNodesMatchingAnyTerms(
const std::vector<std::u16string>& terms,
- query_parser::MatchingAlgorithm matching_algorithm) const;
+ query_parser::MatchingAlgorithm matching_algorithm,
+ size_t max_nodes) const;
// Return matches for the specified |term|. May return duplicates.
TitledUrlNodes RetrieveNodesMatchingTerm(
diff --git a/chromium/components/bookmarks/browser/titled_url_index_unittest.cc b/chromium/components/bookmarks/browser/titled_url_index_unittest.cc
index aef32e03fbf..47897652e24 100644
--- a/chromium/components/bookmarks/browser/titled_url_index_unittest.cc
+++ b/chromium/components/bookmarks/browser/titled_url_index_unittest.cc
@@ -13,6 +13,7 @@
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/test/metrics/histogram_tester.h"
#include "components/bookmarks/browser/titled_url_match.h"
#include "components/bookmarks/browser/titled_url_node.h"
#include "components/bookmarks/browser/typed_count_sorter.h"
@@ -25,6 +26,16 @@ using base::UTF8ToUTF16;
namespace bookmarks {
namespace {
+// Helper to create vector of buckets. Each `pairs` are structured
+// `{min sample, count}`.
+std::vector<base::Bucket> CreateBuckets(
+ const std::vector<std::pair<int, int>>& pairs) {
+ std::vector<base::Bucket> buckets;
+ for (const auto& pair : pairs)
+ buckets.emplace_back(pair.first, pair.second);
+ return buckets;
+}
+
// Used for sorting in combination with TypedCountSorter.
class BookmarkClientMock : public TestBookmarkClient {
public:
@@ -236,6 +247,7 @@ TEST_F(TitledUrlIndexTest, GetResultsMatching) {
{"abc def", "abc d", ""},
};
for (const TestData& test_data : data) {
+ SCOPED_TRACE("Query: " + test_data.query);
ResetNodes();
for (const std::string& title :
@@ -563,7 +575,7 @@ TEST_F(TitledUrlIndexTest, GetResultsSortedByTypedCount) {
TEST_F(TitledUrlIndexTest, RetrieveNodesMatchingAllTerms) {
TitledUrlNode* node =
- AddNode("termA termB otherTerm xyz ab", GURL("http://foo.com"));
+ AddNode("term1 term2 other xyz ab", GURL("http://foo.com"));
struct TestData {
const std::string query;
@@ -594,36 +606,152 @@ TEST_F(TitledUrlIndexTest, RetrieveNodesMatchingAllTerms) {
TEST_F(TitledUrlIndexTest, RetrieveNodesMatchingAnyTerms) {
TitledUrlNode* node =
- AddNode("termA termB otherTerm xyz ab", GURL("http://foo.com"));
+ AddNode("term1 term2 other xyz ab", GURL("http://foo.com"));
struct TestData {
const std::string query;
const bool should_be_retrieved;
- } data[] = {// Should return matches if any input terms match, even if not all
- // node terms match.
- {"term not", true},
- // Should not return duplicate matches.
- {"term termA termB", true},
- // Should not early exit when there are no intermediate matches.
- {"not term", true},
- // Should not match midword.
- {"ther", false},
- // Short input terms should only return exact matches.
- {"xy", false},
- {"ab", true}};
+ const int histogram_terms_unioned_count;
+ const std::vector<std::pair<int, int>> histogram_term_node_counts;
+ const int histogram_any_terms_nodes;
+ const int histogram_all_terms_nodes;
+ const int histogram_joint_nodes;
+ } data[] = {
+ // Should return matches if any input terms match, even if not all node
+ // terms match.
+ {"term not", true, 1, {{0, 1}, {2, 1}}, 1, 0, 1},
+ // Should not return duplicate matches.
+ {"term term1 term2", true, 3, {{1, 2}, {2, 1}}, 1, 0, 1},
+ // Should not early exit when there are no intermediate matches.
+ {"not term", true, 1, {{0, 1}, {2, 1}}, 1, 0, 1},
+ // Should not match midword.
+ {"ther", false, 0, {{0, 1}}, 0, 0, 0},
+ // Short input terms should only return exact matches.
+ {"xy", false, 0, {{0, 1}}, 0, 0, 0},
+ {"ab", true, 1, {{1, 1}}, 1, 0, 1}};
for (const TestData& test_data : data) {
SCOPED_TRACE("Query: " + test_data.query);
+ base::HistogramTester histogram_tester;
std::vector<std::u16string> terms =
base::SplitString(base::UTF8ToUTF16(test_data.query), u" ",
base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
auto matches = index()->RetrieveNodesMatchingAnyTermsForTesting(
- terms, query_parser::MatchingAlgorithm::DEFAULT);
+ terms, query_parser::MatchingAlgorithm::DEFAULT, 9);
+
+ // Verify whether the node matched.
if (test_data.should_be_retrieved) {
EXPECT_EQ(matches.size(), 1u);
EXPECT_TRUE(matches.contains(node));
} else
EXPECT_TRUE(matches.empty());
+
+ // Verify histograms.
+ histogram_tester.ExpectUniqueSample(
+ "Bookmarks.GetResultsMatching.AnyTermApproach.TermsUnionedCount",
+ test_data.histogram_terms_unioned_count, 1);
+ EXPECT_EQ(
+ CreateBuckets(test_data.histogram_term_node_counts),
+ histogram_tester.GetAllSamples(
+ "Bookmarks.GetResultsMatching.AnyTermApproach.NodeCountPerTerm"));
+ histogram_tester.ExpectUniqueSample(
+ "Bookmarks.GetResultsMatching.AnyTermApproach.NodeCountAnyTerms",
+ test_data.histogram_any_terms_nodes, 1);
+ histogram_tester.ExpectUniqueSample(
+ "Bookmarks.GetResultsMatching.AnyTermApproach.NodeCountAllTerms",
+ test_data.histogram_all_terms_nodes, 1);
+ histogram_tester.ExpectUniqueSample(
+ "Bookmarks.GetResultsMatching.AnyTermApproach.NodeCount",
+ test_data.histogram_joint_nodes, 1);
+ };
+}
+
+TEST_F(TitledUrlIndexTest, RetrieveNodesMatchingAnyTermsMaxNodes) {
+ std::vector<TitledUrlNode*> nodes = {
+ AddNode("common11", GURL("http://foo.com")),
+ AddNode("common12", GURL("http://foo.com")),
+ AddNode("common13 uncommon", GURL("http://foo.com")),
+ AddNode("common21 uncommon1", GURL("http://foo.com")),
+ AddNode("common22 uncommon1", GURL("http://foo.com")),
+ AddNode("common23 uncommon1", GURL("http://foo.com")),
+ };
+
+ struct TestData {
+ const std::string query;
+ const std::vector<int> retrieved_node_indexes;
+ const bool histogram_any_term_approach_used;
+ const int histogram_terms_unioned_count;
+ const std::vector<std::pair<int, int>> histogram_term_node_counts;
+ const int histogram_any_terms_nodes;
+ const int histogram_all_terms_nodes;
+ const int histogram_joint_nodes;
+ } data[] = {
+ // Should not look for all-term matches if at least 1 term matches at most
+ // `max_nodes`.
+ {"uncommon1", {3, 4, 5}, true, 1, {{3, 1}}, 3, 0, 3},
+ // Like above, but even if some terms match more than `max_nodes`. Should
+ // look for per term matches even after `max_nodes` matches have been
+ // found.
+ {"common uncommon1", {3, 4, 5}, true, 2, {{3, 1}, {6, 1}}, 3, 0, 3},
+ // Should look for all-term matches if all terms match more than
+ // `ma_nodes`.
+ {"uncommon", {2, 3, 4, 5}, true, 1, {{4, 1}}, 3, 4, 4},
+ {"common", {0, 1, 2, 3, 4, 5}, true, 1, {{6, 1}}, 3, 6, 6},
+ {"common uncommon", {2, 3, 4, 5}, true, 2, {{4, 1}, {6, 1}}, 3, 4, 4},
+ {"common x", {0, 1, 2}, true, 1, {{0, 1}, {6, 1}}, 3, 0, 3},
+ // Should not crash if no term has matches.
+ {"x", {}, true, 0, {{0, 1}}, 0, 0, 0},
+ };
+
+ for (const TestData& test_data : data) {
+ SCOPED_TRACE("Query: " + test_data.query);
+ base::HistogramTester histogram_tester;
+ std::vector<std::u16string> terms =
+ base::SplitString(base::UTF8ToUTF16(test_data.query), u" ",
+ base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+ auto matches = index()->RetrieveNodesMatchingAnyTermsForTesting(
+ terms, query_parser::MatchingAlgorithm::DEFAULT, 3);
+
+ // Verify the correct nodes matched.
+ ASSERT_EQ(matches.size(), test_data.retrieved_node_indexes.size());
+ for (int index : test_data.retrieved_node_indexes) {
+ SCOPED_TRACE("node: " +
+ base::UTF16ToUTF8(nodes[index]->GetTitledUrlNodeTitle()));
+ EXPECT_TRUE(matches.contains(nodes[index]));
+ }
+
+ // Verify histograms.
+ if (test_data.histogram_any_term_approach_used) {
+ histogram_tester.ExpectUniqueSample(
+ "Bookmarks.GetResultsMatching.AnyTermApproach.TermsUnionedCount",
+ test_data.histogram_terms_unioned_count, 1);
+ EXPECT_EQ(
+ CreateBuckets(test_data.histogram_term_node_counts),
+ histogram_tester.GetAllSamples(
+ "Bookmarks.GetResultsMatching.AnyTermApproach.NodeCountPerTerm"));
+ histogram_tester.ExpectUniqueSample(
+ "Bookmarks.GetResultsMatching.AnyTermApproach.NodeCountAnyTerms",
+ test_data.histogram_any_terms_nodes, 1);
+ histogram_tester.ExpectUniqueSample(
+ "Bookmarks.GetResultsMatching.AnyTermApproach.NodeCountAllTerms",
+ test_data.histogram_all_terms_nodes, 1);
+ histogram_tester.ExpectUniqueSample(
+ "Bookmarks.GetResultsMatching.AnyTermApproach.NodeCount",
+ test_data.histogram_joint_nodes, 1);
+ } else {
+ // If AnyTermApproach wasn't used, then other histograms shouldn't be
+ // recorded.
+ histogram_tester.ExpectTotalCount(
+ "Bookmarks.GetResultsMatching.AnyTermApproach.TermsUnionedCount", 0);
+ histogram_tester.ExpectTotalCount(
+ "Bookmarks.GetResultsMatching.AnyTermApproach.NodeCountPerTerm", 0);
+ histogram_tester.ExpectTotalCount(
+ "Bookmarks.GetResultsMatching.AnyTermApproach.NodeCountAnyTerms", 0);
+ histogram_tester.ExpectTotalCount(
+ "Bookmarks.GetResultsMatching.AnyTermApproach.NodeCountAllTerms", 0);
+ histogram_tester.ExpectTotalCount(
+ "Bookmarks.GetResultsMatching.AnyTermApproach.NodeCount", 0);
+ }
};
}
@@ -635,31 +763,45 @@ TEST_F(TitledUrlIndexTest, GetResultsMatchingAncestors) {
const bool match_ancestor_titles;
const bool should_be_retrieved;
const bool should_have_ancestor_match;
+ const bool histogram_any_term_approach_used;
+ const int histogram_terms_count;
+ const std::vector<std::pair<int, int>> histogram_term_lengths;
+ const bool histogram_matched_node;
} data[] = {
// Should exclude matches with ancestor matches when
// |match_ancestor_titles| is false.
- {"leaf parent", false, false, false},
+ {"leaf parent", false, false, false, false, 2, {{4, 1}, {6, 1}}, false},
// Should allow ancestor matches when |match_ancestor_titles| is true.
- {"leaf parent", true, true, true},
+ {"leaf parent", true, true, true, true, 2, {{4, 1}, {6, 1}}, true},
// Should not early exit when there are no accumulated
// non-ancestor matches.
- {"parent leaf", true, true, true},
+ {"parent leaf", true, true, true, true, 2, {{4, 1}, {6, 1}}, true},
// Should still require at least 1 non-ancestor match when
// |match_ancestor_titles| is true.
- {"parent", true, false, false},
+ {"parent", true, false, false, true, 1, {{6, 1}}, false},
// Should set |has_ancestor_match| to true even if a term matched
// both an ancestor and title/URL.
- {"pare", true, true, true},
+ {"pare", true, true, true, true, 1, {{4, 1}}, true},
// Short inputs should only match exact title or ancestor terms.
- {"pa", true, false, false},
+ {"pa", true, false, false, true, 1, {{2, 1}}, false},
// Should not return matches if a term matches neither the title
// nor ancestor.
- {"term not parent", true, false, false}};
+ {"leaf not parent",
+ true,
+ false,
+ false,
+ true,
+ 3,
+ {{3, 1}, {4, 1}, {6, 1}},
+ true}};
for (const TestData& test_data : data) {
SCOPED_TRACE("Query: " + test_data.query);
+ base::HistogramTester histogram_tester;
auto matches = GetResultsMatching(test_data.query, 10,
test_data.match_ancestor_titles);
+
+ // Verify whether the match.
if (test_data.should_be_retrieved) {
EXPECT_EQ(matches.size(), 1u);
EXPECT_EQ(matches[0].node, node);
@@ -667,7 +809,97 @@ TEST_F(TitledUrlIndexTest, GetResultsMatchingAncestors) {
test_data.should_have_ancestor_match);
} else
EXPECT_TRUE(matches.empty());
+
+ // Verify histograms.
+ histogram_tester.ExpectUniqueSample(
+ "Bookmarks.GetResultsMatching.Terms.TermsCount",
+ test_data.histogram_terms_count, 1);
+ EXPECT_EQ(CreateBuckets(test_data.histogram_term_lengths),
+ histogram_tester.GetAllSamples(
+ "Bookmarks.GetResultsMatching.Terms.TermLength"));
+ histogram_tester.ExpectUniqueSample(
+ "Bookmarks.GetResultsMatching.AnyTermApproach.Used",
+ test_data.histogram_any_term_approach_used, 1);
+ histogram_tester.ExpectUniqueSample(
+ "Bookmarks.GetResultsMatching.Nodes.Count",
+ test_data.histogram_matched_node, 1);
+ if (test_data.query.size() < 3) {
+ histogram_tester.ExpectUniqueSample(
+ "Bookmarks.GetResultsMatching.Nodes.Count."
+ "InputsShorterThan3CharsLong",
+ test_data.histogram_matched_node, 1);
+ histogram_tester.ExpectTotalCount(
+ "Bookmarks.GetResultsMatching.Nodes.Count.InputsAtLeast3CharsLong",
+ 0);
+ } else {
+ histogram_tester.ExpectUniqueSample(
+ "Bookmarks.GetResultsMatching.Nodes.Count.InputsAtLeast3CharsLong",
+ test_data.histogram_matched_node, 1);
+ histogram_tester.ExpectTotalCount(
+ "Bookmarks.GetResultsMatching.Nodes.Count."
+ "InputsShorterThan3CharsLong",
+ 0);
+ }
+ if (test_data.histogram_matched_node) {
+ histogram_tester.ExpectUniqueSample(
+ "Bookmarks.GetResultsMatching.Matches.ConsideredCount", 1, 1);
+ } else {
+ histogram_tester.ExpectTotalCount(
+ "Bookmarks.GetResultsMatching.Matches.ConsideredCount", 0);
+ }
+ if (test_data.should_be_retrieved) {
+ histogram_tester.ExpectUniqueSample(
+ "Bookmarks.GetResultsMatching.Matches.ReturnedCount", 1, 1);
+ } else if (test_data.histogram_matched_node) {
+ histogram_tester.ExpectUniqueSample(
+ "Bookmarks.GetResultsMatching.Matches.ReturnedCount", 0, 1);
+ } else {
+ histogram_tester.ExpectTotalCount(
+ "Bookmarks.GetResultsMatching.Matches.ReturnedCount", 0);
+ }
+ EXPECT_EQ(histogram_tester
+ .GetAllSamples("Bookmarks.GetResultsMatching.Timing.Total")
+ .size(),
+ 1u);
+ EXPECT_EQ(histogram_tester
+ .GetAllSamples(
+ "Bookmarks.GetResultsMatching.Timing.RetrievingNodes")
+ .size(),
+ 1u);
+ if (test_data.histogram_matched_node) {
+ EXPECT_EQ(
+ histogram_tester
+ .GetAllSamples("Bookmarks.GetResultsMatching.Timing.SortingNodes")
+ .size(),
+ 1u);
+ EXPECT_EQ(histogram_tester
+ .GetAllSamples(
+ "Bookmarks.GetResultsMatching.Timing.CreatingMatches")
+ .size(),
+ 1u);
+ } else {
+ histogram_tester.ExpectTotalCount(
+ "Bookmarks.GetResultsMatching.Timing.SortingNodes", 0);
+ histogram_tester.ExpectTotalCount(
+ "Bookmarks.GetResultsMatching.Timing.CreatingMatches", 0);
+ }
};
+
+ {
+ // With an empty input, most histograms should not be logged.
+ base::HistogramTester histogram_tester;
+ auto matches = GetResultsMatching("", 10, true);
+ EXPECT_EQ(histogram_tester
+ .GetAllSamples("Bookmarks.GetResultsMatching.Timing.Total")
+ .size(),
+ 1u);
+ histogram_tester.ExpectUniqueSample(
+ "Bookmarks.GetResultsMatching.Terms.TermsCount", 0, 1);
+ histogram_tester.ExpectTotalCount(
+ "Bookmarks.GetResultsMatching.Terms.TermLength", 0);
+ histogram_tester.ExpectTotalCount(
+ "Bookmarks.GetResultsMatching.Timing.RetrievingNodes", 0);
+ }
}
} // namespace
diff --git a/chromium/components/bookmarks/managed/managed_bookmarks_policy_handler.cc b/chromium/components/bookmarks/managed/managed_bookmarks_policy_handler.cc
index 589202514cb..106758916ec 100644
--- a/chromium/components/bookmarks/managed/managed_bookmarks_policy_handler.cc
+++ b/chromium/components/bookmarks/managed/managed_bookmarks_policy_handler.cc
@@ -40,7 +40,7 @@ void ManagedBookmarksPolicyHandler::ApplyPolicySettings(
return;
prefs->SetString(prefs::kManagedBookmarksFolderName, GetFolderName(*value));
- base::Value filtered(FilterBookmarks(std::move(*value).TakeList()));
+ base::Value filtered(FilterBookmarks(std::move(*value).TakeListDeprecated()));
prefs->SetValue(prefs::kManagedBookmarks, std::move(filtered));
}
@@ -48,7 +48,7 @@ std::string ManagedBookmarksPolicyHandler::GetFolderName(
const base::Value& list) {
DCHECK(list.is_list());
// Iterate over the list, and try to find the FolderName.
- for (const auto& el : list.GetList()) {
+ for (const auto& el : list.GetListDeprecated()) {
if (!el.is_dict())
continue;
@@ -84,7 +84,8 @@ base::Value::ListStorage ManagedBookmarksPolicyHandler::FilterBookmarks(
if (children) {
// Ignore the URL if this bookmark has child nodes.
item.RemoveKey(ManagedBookmarksTracker::kUrl);
- *children = base::Value(FilterBookmarks(std::move(*children).TakeList()));
+ *children = base::Value(
+ FilterBookmarks(std::move(*children).TakeListDeprecated()));
} else {
// Make sure the URL is valid before passing a bookmark to the pref.
item.RemoveKey(ManagedBookmarksTracker::kChildren);
diff --git a/chromium/components/bookmarks/managed/managed_bookmarks_tracker.cc b/chromium/components/bookmarks/managed/managed_bookmarks_tracker.cc
index fb714d98fef..6f831d9fbef 100644
--- a/chromium/components/bookmarks/managed/managed_bookmarks_tracker.cc
+++ b/chromium/components/bookmarks/managed/managed_bookmarks_tracker.cc
@@ -52,7 +52,7 @@ int64_t ManagedBookmarksTracker::LoadInitial(BookmarkNode* folder,
const base::Value* list,
int64_t next_node_id) {
DCHECK(list->is_list());
- for (size_t i = 0; i < list->GetList().size(); ++i) {
+ for (size_t i = 0; i < list->GetListDeprecated().size(); ++i) {
// Extract the data for the next bookmark from the |list|.
std::u16string title;
GURL url;
@@ -116,7 +116,7 @@ void ManagedBookmarksTracker::UpdateBookmarks(const BookmarkNode* folder,
const base::Value* list) {
DCHECK(list->is_list());
size_t folder_index = 0;
- for (size_t i = 0; i < list->GetList().size(); ++i) {
+ for (size_t i = 0; i < list->GetListDeprecated().size(); ++i) {
// Extract the data for the next bookmark from the |list|.
std::u16string title;
GURL url;
@@ -165,7 +165,7 @@ bool ManagedBookmarksTracker::LoadBookmark(const base::Value* list,
DCHECK(list->is_list());
*url = GURL();
*children = nullptr;
- const base::Value& dict = list->GetList()[index];
+ const base::Value& dict = list->GetListDeprecated()[index];
if (!dict.is_dict()) {
// Should never happen after policy validation.
NOTREACHED();
diff --git a/chromium/components/bookmarks/managed/managed_bookmarks_tracker_unittest.cc b/chromium/components/bookmarks/managed/managed_bookmarks_tracker_unittest.cc
index 203e68c1d0b..3d1d8563a39 100644
--- a/chromium/components/bookmarks/managed/managed_bookmarks_tracker_unittest.cc
+++ b/chromium/components/bookmarks/managed/managed_bookmarks_tracker_unittest.cc
@@ -138,12 +138,14 @@ class ManagedBookmarksTrackerTest : public testing::Test {
if (node->is_folder()) {
const base::Value* children = dict.FindListKey("children");
- if (!children || node->children().size() != children->GetList().size())
+ if (!children ||
+ node->children().size() != children->GetListDeprecated().size())
return false;
size_t i = 0;
return std::all_of(node->children().cbegin(), node->children().cend(),
[children, &i](const auto& child_node) {
- const base::Value& child = children->GetList()[i++];
+ const base::Value& child =
+ children->GetListDeprecated()[i++];
return child.is_dict() &&
NodeMatchesValue(child_node.get(), child);
});
@@ -206,7 +208,7 @@ TEST_F(ManagedBookmarksTrackerTest, SwapNodes) {
// Swap the Google bookmark with the Folder.
base::Value updated(CreateTestTree());
- base::Value::ListView updated_listview = updated.GetList();
+ base::Value::ListView updated_listview = updated.GetListDeprecated();
ASSERT_FALSE(updated_listview.empty());
base::Value removed = std::move(updated_listview[0]);
ASSERT_TRUE(updated.EraseListIter(updated_listview.begin()));
@@ -230,7 +232,7 @@ TEST_F(ManagedBookmarksTrackerTest, RemoveNode) {
// Remove the Folder.
base::Value updated(CreateTestTree());
- ASSERT_TRUE(updated.EraseListIter(updated.GetList().begin() + 1));
+ ASSERT_TRUE(updated.EraseListIter(updated.GetListDeprecated().begin() + 1));
const BookmarkNode* parent = managed_node();
EXPECT_CALL(observer_, BookmarkNodeRemoved(model_.get(), parent, 1, _, _));
diff --git a/chromium/components/breadcrumbs/core/breadcrumb_manager.cc b/chromium/components/breadcrumbs/core/breadcrumb_manager.cc
index 33f4e4f4ef6..daaf1bbe620 100644
--- a/chromium/components/breadcrumbs/core/breadcrumb_manager.cc
+++ b/chromium/components/breadcrumbs/core/breadcrumb_manager.cc
@@ -4,6 +4,7 @@
#include "components/breadcrumbs/core/breadcrumb_manager.h"
+#include "base/containers/adapters.h"
#include "base/format_macros.h"
#include "base/strings/stringprintf.h"
#include "components/breadcrumbs/core/breadcrumb_manager_observer.h"
@@ -39,8 +40,8 @@ size_t BreadcrumbManager::GetEventCount() {
DropOldEvents();
size_t count = 0;
- for (auto it = event_buckets_.rbegin(); it != event_buckets_.rend(); ++it) {
- count += it->events.size();
+ for (const EventBucket& event_bucket : base::Reversed(event_buckets_)) {
+ count += event_bucket.events.size();
}
return count;
}
@@ -50,11 +51,8 @@ const std::list<std::string> BreadcrumbManager::GetEvents(
DropOldEvents();
std::list<std::string> events;
- for (auto it = event_buckets_.rbegin(); it != event_buckets_.rend(); ++it) {
- const std::list<std::string>& bucket_events = it->events;
- for (auto event_it = bucket_events.rbegin();
- event_it != bucket_events.rend(); ++event_it) {
- const std::string& event = *event_it;
+ for (const EventBucket& event_bucket : base::Reversed(event_buckets_)) {
+ for (const std::string& event : base::Reversed(event_bucket.events)) {
events.push_front(event);
if (event_count_limit > 0 && events.size() >= event_count_limit) {
return events;
@@ -142,6 +140,10 @@ void BreadcrumbManager::RemoveObserver(BreadcrumbManagerObserver* observer) {
observers_.RemoveObserver(observer);
}
+bool BreadcrumbManager::HasObserver(BreadcrumbManagerObserver* observer) {
+ return observers_.HasObserver(observer);
+}
+
BreadcrumbManager::EventBucket::EventBucket(int minutes_elapsed)
: minutes_elapsed(minutes_elapsed) {}
BreadcrumbManager::EventBucket::EventBucket(const EventBucket&) = default;
diff --git a/chromium/components/breadcrumbs/core/breadcrumb_manager.h b/chromium/components/breadcrumbs/core/breadcrumb_manager.h
index eb15e0f8023..f705adedc55 100644
--- a/chromium/components/breadcrumbs/core/breadcrumb_manager.h
+++ b/chromium/components/breadcrumbs/core/breadcrumb_manager.h
@@ -52,6 +52,9 @@ class BreadcrumbManager {
void AddObserver(BreadcrumbManagerObserver* observer);
void RemoveObserver(BreadcrumbManagerObserver* observer);
+ // TODO(crbug.com/1287441): remove this once crash is understood.
+ bool HasObserver(BreadcrumbManagerObserver* observer);
+
private:
// Drops events which are considered stale. Note that stale events are not
// guaranteed to be removed. Explicitly, stale events will be retained while
diff --git a/chromium/components/breadcrumbs/core/breadcrumb_manager_keyed_service.cc b/chromium/components/breadcrumbs/core/breadcrumb_manager_keyed_service.cc
index b2954deebfb..7c6c534737a 100644
--- a/chromium/components/breadcrumbs/core/breadcrumb_manager_keyed_service.cc
+++ b/chromium/components/breadcrumbs/core/breadcrumb_manager_keyed_service.cc
@@ -44,6 +44,9 @@ void BreadcrumbManagerKeyedService::StartPersisting(
StopPersisting();
}
+ CHECK(breadcrumb_manager_);
+ CHECK(!breadcrumb_manager_->HasObserver(persistent_storage_manager));
+
persistent_storage_manager_ = persistent_storage_manager;
persistent_storage_manager_->MonitorBreadcrumbManagerService(this);
}
diff --git a/chromium/components/breadcrumbs/core/breadcrumb_persistent_storage_manager.cc b/chromium/components/breadcrumbs/core/breadcrumb_persistent_storage_manager.cc
index 25747cd1b74..c39381503f5 100644
--- a/chromium/components/breadcrumbs/core/breadcrumb_persistent_storage_manager.cc
+++ b/chromium/components/breadcrumbs/core/breadcrumb_persistent_storage_manager.cc
@@ -10,6 +10,7 @@
#include <string>
#include "base/bind.h"
+#include "base/containers/adapters.h"
#include "base/files/file_util.h"
#include "base/files/memory_mapped_file.h"
#include "base/strings/string_split.h"
@@ -183,7 +184,7 @@ BreadcrumbPersistentStorageManager::BreadcrumbPersistentStorageManager(
FROM_HERE,
base::BindOnce(&DoGetStoredEventsLength, breadcrumbs_file_path_),
base::BindOnce(
- &BreadcrumbPersistentStorageManager::SetCurrentMappedFilePosition,
+ &BreadcrumbPersistentStorageManager::InitializeFilePosition,
weak_ptr_factory_.GetWeakPtr()));
}
@@ -221,28 +222,24 @@ void BreadcrumbPersistentStorageManager::CombineEventsAndRewriteAllBreadcrumbs(
const std::vector<std::string> pending_breadcrumbs,
std::vector<std::string> existing_events) {
// Add events which had not yet been written.
- for (const auto& event : pending_breadcrumbs) {
+ for (const std::string& event : pending_breadcrumbs) {
existing_events.push_back(event);
}
std::vector<std::string> breadcrumbs;
- for (auto event_it = existing_events.rbegin();
- event_it != existing_events.rend(); ++event_it) {
+ for (const std::string& event : base::Reversed(existing_events)) {
// Reduce saved events to only fill the amount which would be included on
// a crash log. This allows future events to be appended individually up
// to |kPersistedFilesizeInBytes|, which is more efficient than writing
// out the
const int event_with_seperator_size =
- event_it->size() + strlen(kEventSeparator);
- if (event_with_seperator_size + current_mapped_file_position_.value() >=
- kMaxDataLength) {
+ event.size() + strlen(kEventSeparator);
+ if (event_with_seperator_size + file_position_.value() >= kMaxDataLength)
break;
- }
breadcrumbs.push_back(kEventSeparator);
- breadcrumbs.push_back(*event_it);
- current_mapped_file_position_ =
- current_mapped_file_position_.value() + event_with_seperator_size;
+ breadcrumbs.push_back(event);
+ file_position_ = file_position_.value() + event_with_seperator_size;
}
std::reverse(breadcrumbs.begin(), breadcrumbs.end());
@@ -267,7 +264,7 @@ void BreadcrumbPersistentStorageManager::RewriteAllExistingBreadcrumbs() {
write_timer_.Stop();
last_written_time_ = base::TimeTicks::Now();
- current_mapped_file_position_ = 0;
+ file_position_ = 0;
// Load persisted events directly from file because the correct order can not
// be reconstructed from the multiple BreadcrumbManagers with the partial
@@ -287,14 +284,12 @@ void BreadcrumbPersistentStorageManager::WritePendingBreadcrumbs() {
// DoInsertEventsIntoMemoryMappedFile() callback, since |pending_breadcrumbs_|
// is about to be cleared.
const std::string pending_breadcrumbs = pending_breadcrumbs_;
- task_runner_->PostTask(FROM_HERE,
- base::BindOnce(&DoInsertEventsIntoMemoryMappedFile,
- breadcrumbs_file_path_,
- current_mapped_file_position_.value(),
- pending_breadcrumbs));
-
- current_mapped_file_position_ =
- current_mapped_file_position_.value() + pending_breadcrumbs_.size();
+ task_runner_->PostTask(
+ FROM_HERE, base::BindOnce(&DoInsertEventsIntoMemoryMappedFile,
+ breadcrumbs_file_path_, file_position_.value(),
+ pending_breadcrumbs));
+
+ file_position_ = file_position_.value() + pending_breadcrumbs_.size();
last_written_time_ = base::TimeTicks::Now();
pending_breadcrumbs_.clear();
@@ -311,27 +306,35 @@ void BreadcrumbPersistentStorageManager::WriteEvent(const std::string& event) {
WriteEvents();
}
-void BreadcrumbPersistentStorageManager::SetCurrentMappedFilePosition(
+void BreadcrumbPersistentStorageManager::InitializeFilePosition(
size_t file_size) {
- current_mapped_file_position_ = file_size;
+ file_position_ = file_size;
+ // Write any startup events that have accumulated while waiting for this
+ // function to run.
+ WriteEvents();
}
void BreadcrumbPersistentStorageManager::WriteEvents() {
+ // No events can be written to the file until the size of existing breadcrumbs
+ // is known.
+ if (!file_position_)
+ return;
+
write_timer_.Stop();
const base::TimeDelta time_delta_since_last_write =
base::TimeTicks::Now() - last_written_time_;
- // Delay writing the event to disk if an event was just written or if the size
- // of exisiting breadcrumbs is not yet known.
- if (time_delta_since_last_write < kMinDelayBetweenWrites ||
- !current_mapped_file_position_) {
- write_timer_.Start(FROM_HERE,
- kMinDelayBetweenWrites - time_delta_since_last_write,
- this, &BreadcrumbPersistentStorageManager::WriteEvents);
+ if (time_delta_since_last_write < kMinDelayBetweenWrites) {
+ // If an event was just written, delay writing the event to disk in order to
+ // limit overhead.
+ write_timer_.Start(
+ FROM_HERE, kMinDelayBetweenWrites - time_delta_since_last_write,
+ base::BindOnce(&BreadcrumbPersistentStorageManager::WriteEvents,
+ weak_ptr_factory_.GetWeakPtr()));
} else {
// If the event does not fit within |kPersistedFilesizeInBytes|, rewrite the
// file to trim old events.
- if ((current_mapped_file_position_.value() + pending_breadcrumbs_.size())
+ if ((file_position_.value() + pending_breadcrumbs_.size())
// Use >= here instead of > to allow space for \0 to terminate file.
>= kPersistedFilesizeInBytes) {
RewriteAllExistingBreadcrumbs();
diff --git a/chromium/components/breadcrumbs/core/breadcrumb_persistent_storage_manager.h b/chromium/components/breadcrumbs/core/breadcrumb_persistent_storage_manager.h
index 2d8fd0c8903..29e96a585ca 100644
--- a/chromium/components/breadcrumbs/core/breadcrumb_persistent_storage_manager.h
+++ b/chromium/components/breadcrumbs/core/breadcrumb_persistent_storage_manager.h
@@ -67,8 +67,8 @@ class BreadcrumbPersistentStorageManager : public BreadcrumbManagerObserver {
BreadcrumbManagerKeyedService* service);
private:
- // Sets |current_mapped_file_position_| to |file_size|;
- void SetCurrentMappedFilePosition(size_t file_size);
+ // Initializes |file_position_| to |file_size| and writes any events so far.
+ void InitializeFilePosition(size_t file_size);
// Writes |pending_breadcrumbs_| to |breadcrumbs_file_| if it fits, otherwise
// rewrites the file. NOTE: Writing may be delayed if the file has recently
@@ -117,7 +117,7 @@ class BreadcrumbPersistentStorageManager : public BreadcrumbManagerObserver {
// The current size of breadcrumbs written to |breadcrumbs_file_path_|.
// NOTE: The optional will not have a value until the size of the existing
// file, if any, is retrieved.
- absl::optional<size_t> current_mapped_file_position_;
+ absl::optional<size_t> file_position_;
// The SequencedTaskRunner on which File IO operations are performed.
scoped_refptr<base::SequencedTaskRunner> task_runner_;
diff --git a/chromium/components/breadcrumbs/core/breadcrumb_persistent_storage_util.cc b/chromium/components/breadcrumbs/core/breadcrumb_persistent_storage_util.cc
index 4ff7e049455..fbf4d3b8be0 100644
--- a/chromium/components/breadcrumbs/core/breadcrumb_persistent_storage_util.cc
+++ b/chromium/components/breadcrumbs/core/breadcrumb_persistent_storage_util.cc
@@ -4,7 +4,10 @@
#include "components/breadcrumbs/core/breadcrumb_persistent_storage_util.h"
+#include "base/bind.h"
#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/task/thread_pool.h"
namespace breadcrumbs {
namespace {
@@ -15,6 +18,13 @@ const base::FilePath::CharType kBreadcrumbsFile[] =
const base::FilePath::CharType kBreadcrumbsTempFile[] =
FILE_PATH_LITERAL("Breadcrumbs.temp");
+void DoDeleteBreadcrumbFiles(const base::FilePath& storage_dir) {
+ base::DeleteFile(
+ breadcrumbs::GetBreadcrumbPersistentStorageFilePath(storage_dir));
+ base::DeleteFile(
+ breadcrumbs::GetBreadcrumbPersistentStorageTempFilePath(storage_dir));
+}
+
} // namespace
base::FilePath GetBreadcrumbPersistentStorageFilePath(
@@ -27,4 +37,10 @@ base::FilePath GetBreadcrumbPersistentStorageTempFilePath(
return storage_dir.Append(kBreadcrumbsTempFile);
}
+void DeleteBreadcrumbFiles(const base::FilePath& storage_dir) {
+ base::ThreadPool::PostTask(
+ FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT},
+ base::BindOnce(&DoDeleteBreadcrumbFiles, storage_dir));
+}
+
} // namespace breadcrumbs
diff --git a/chromium/components/breadcrumbs/core/breadcrumb_persistent_storage_util.h b/chromium/components/breadcrumbs/core/breadcrumb_persistent_storage_util.h
index 2914eab8fe0..da2cfb72c4a 100644
--- a/chromium/components/breadcrumbs/core/breadcrumb_persistent_storage_util.h
+++ b/chromium/components/breadcrumbs/core/breadcrumb_persistent_storage_util.h
@@ -25,6 +25,9 @@ base::FilePath GetBreadcrumbPersistentStorageFilePath(
base::FilePath GetBreadcrumbPersistentStorageTempFilePath(
const base::FilePath& storage_dir);
+// Deletes the breadcrumbs file and breadcrumbs temp file in |storage_dir|.
+void DeleteBreadcrumbFiles(const base::FilePath& storage_dir);
+
} // namespace breadcrumbs
#endif // COMPONENTS_BREADCRUMBS_CORE_BREADCRUMB_PERSISTENT_STORAGE_UTIL_H_
diff --git a/chromium/components/breadcrumbs/core/crash_reporter_breadcrumb_observer.cc b/chromium/components/breadcrumbs/core/crash_reporter_breadcrumb_observer.cc
index bbee6f930c5..8235db49451 100644
--- a/chromium/components/breadcrumbs/core/crash_reporter_breadcrumb_observer.cc
+++ b/chromium/components/breadcrumbs/core/crash_reporter_breadcrumb_observer.cc
@@ -7,6 +7,8 @@
#include <numeric>
#include <string>
+#include "base/containers/adapters.h"
+#include "base/no_destructor.h"
#include "components/breadcrumbs/core/crash_reporter_breadcrumb_constants.h"
#include "components/crash/core/common/crash_key.h"
@@ -91,9 +93,8 @@ void CrashReporterBreadcrumbObserver::UpdateBreadcrumbEventsCrashKey() {
// Concatenate breadcrumbs backwards, putting new breadcrumbs at the front, so
// that the most relevant (i.e., newest) breadcrumbs are at the top in Crash.
- for (auto it = breadcrumbs_.rbegin(), end_it = breadcrumbs_.rend();
- it != end_it; ++it) {
- breadcrumbs_string += *it;
+ for (const std::string& breadcrumb : base::Reversed(breadcrumbs_)) {
+ breadcrumbs_string += breadcrumb;
breadcrumbs_string += kEventSeparator;
}
DCHECK(breadcrumbs_string.length() == breadcrumbs_string_length);
diff --git a/chromium/components/browser_sync/BUILD.gn b/chromium/components/browser_sync/BUILD.gn
index c92f09dd478..c9c7d5a7c6a 100644
--- a/chromium/components/browser_sync/BUILD.gn
+++ b/chromium/components/browser_sync/BUILD.gn
@@ -10,12 +10,11 @@ static_library("browser_sync") {
"active_devices_provider_impl.cc",
"active_devices_provider_impl.h",
"browser_sync_client.h",
- "browser_sync_switches.cc",
"browser_sync_switches.h",
- "profile_sync_components_factory_impl.cc",
- "profile_sync_components_factory_impl.h",
"signin_confirmation_helper.cc",
"signin_confirmation_helper.h",
+ "sync_api_component_factory_impl.cc",
+ "sync_api_component_factory_impl.h",
]
public_deps = [ "//components/sync" ]
diff --git a/chromium/components/browser_sync/README.md b/chromium/components/browser_sync/README.md
new file mode 100644
index 00000000000..5cb33a1ca9e
--- /dev/null
+++ b/chromium/components/browser_sync/README.md
@@ -0,0 +1 @@
+See components/sync/README.md.
diff --git a/chromium/components/browser_sync/browser_sync_client.h b/chromium/components/browser_sync/browser_sync_client.h
index b06226b44d3..656c8b713a4 100644
--- a/chromium/components/browser_sync/browser_sync_client.h
+++ b/chromium/components/browser_sync/browser_sync_client.h
@@ -11,12 +11,6 @@
#include "components/sync/driver/sync_client.h"
#include "components/sync/model/model_type_controller_delegate.h"
-class BookmarkUndoService;
-
-namespace bookmarks {
-class BookmarkModel;
-} // namespace bookmarks
-
namespace favicon {
class FaviconService;
} // namespace favicon
@@ -66,14 +60,12 @@ class BrowserSyncClient : public syncer::SyncClient {
// DataType specific service getters.
virtual syncer::DeviceInfoSyncService* GetDeviceInfoSyncService() = 0;
- virtual bookmarks::BookmarkModel* GetBookmarkModel() = 0;
virtual favicon::FaviconService* GetFaviconService() = 0;
virtual history::HistoryService* GetHistoryService() = 0;
virtual sync_preferences::PrefServiceSyncable* GetPrefServiceSyncable() = 0;
virtual sync_sessions::SessionSyncService* GetSessionSyncService() = 0;
virtual send_tab_to_self::SendTabToSelfSyncService*
GetSendTabToSelfSyncService() = 0;
- virtual BookmarkUndoService* GetBookmarkUndoService() = 0;
};
} // namespace browser_sync
diff --git a/chromium/components/browser_sync/browser_sync_switches.cc b/chromium/components/browser_sync/browser_sync_switches.cc
deleted file mode 100644
index 158f5d5c919..00000000000
--- a/chromium/components/browser_sync/browser_sync_switches.cc
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright 2015 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.
-
-#include "components/browser_sync/browser_sync_switches.h"
-
-namespace switches {
-
-// Disables syncing one or more sync data types that are on by default.
-// See sync/base/model_type.h for possible types. Types
-// should be comma separated, and follow the naming convention for string
-// representation of model types, e.g.:
-// --disable-synctypes='Typed URLs, Bookmarks, Autofill Profiles'
-const char kDisableSyncTypes[] = "disable-sync-types";
-
-// Enabled the local sync backend implemented by the LoopbackServer.
-const char kEnableLocalSyncBackend[] = "enable-local-sync-backend";
-
-// Specifies the local sync backend directory. The name is chosen to mimic
-// user-data-dir etc. This flag only matters if the enable-local-sync-backend
-// flag is present.
-const char kLocalSyncBackendDir[] = "local-sync-backend-dir";
-
-#if defined(OS_ANDROID)
-const base::Feature kSyncUseSessionsUnregisterDelay{
- "SyncUseSessionsUnregisterDelay", base::FEATURE_DISABLED_BY_DEFAULT};
-#endif // defined(OS_ANDROID)
-
-// Enables providing the list of FCM registration tokens in the commit request.
-const base::Feature kSyncUseFCMRegistrationTokensList{
- "SyncUseFCMRegistrationTokensList", base::FEATURE_ENABLED_BY_DEFAULT};
-
-// Max size of FCM registration tokens list. If the number of active devices
-// having FCM registration tokens is higher, then the resulting list will be
-// empty meaning unknown FCM registration tokens.
-const base::FeatureParam<int> kSyncFCMRegistrationTokensListMaxSize{
- &kSyncUseFCMRegistrationTokensList, "SyncFCMRegistrationTokensListMaxSize",
- 5};
-
-// Enables filtering out inactive devices which haven't sent DeviceInfo update
-// recently (depending on the device's pulse_interval and an additional margin).
-const base::Feature kSyncFilterOutInactiveDevicesForSingleClient{
- "SyncFilterOutInactiveDevicesForSingleClient",
- base::FEATURE_ENABLED_BY_DEFAULT};
-
-// An additional threshold to consider devices as active. It extends device's
-// pulse interval to mitigate possible latency after DeviceInfo commit.
-const base::FeatureParam<base::TimeDelta> kSyncActiveDeviceMargin{
- &kSyncFilterOutInactiveDevicesForSingleClient, "SyncActiveDeviceMargin",
- base::Minutes(30)};
-
-} // namespace switches
diff --git a/chromium/components/browser_sync/browser_sync_switches.h b/chromium/components/browser_sync/browser_sync_switches.h
index ef0a538795f..86fa0200a7c 100644
--- a/chromium/components/browser_sync/browser_sync_switches.h
+++ b/chromium/components/browser_sync/browser_sync_switches.h
@@ -11,19 +11,40 @@
namespace switches {
-extern const char kDisableSyncTypes[];
-extern const char kEnableLocalSyncBackend[];
-extern const char kLocalSyncBackendDir[];
+// Enabled the local sync backend implemented by the LoopbackServer.
+inline constexpr char kEnableLocalSyncBackend[] = "enable-local-sync-backend";
-#if defined(OS_ANDROID)
-extern const base::Feature kSyncUseSessionsUnregisterDelay;
-#endif
+// Specifies the local sync backend directory. The name is chosen to mimic
+// user-data-dir etc. This flag only matters if the enable-local-sync-backend
+// flag is present.
+inline constexpr char kLocalSyncBackendDir[] = "local-sync-backend-dir";
+
+#if BUILDFLAG(IS_ANDROID)
+inline constexpr base::Feature kSyncUseSessionsUnregisterDelay{
+ "SyncUseSessionsUnregisterDelay", base::FEATURE_DISABLED_BY_DEFAULT};
+#endif // BUILDFLAG(IS_ANDROID)
// Sync invalidation switches.
-extern const base::Feature kSyncUseFCMRegistrationTokensList;
-extern const base::FeatureParam<int> kSyncFCMRegistrationTokensListMaxSize;
-extern const base::Feature kSyncFilterOutInactiveDevicesForSingleClient;
-extern const base::FeatureParam<base::TimeDelta> kSyncActiveDeviceMargin;
+//
+// Enables providing the list of FCM registration tokens in the commit request.
+inline constexpr base::Feature kSyncUseFCMRegistrationTokensList{
+ "SyncUseFCMRegistrationTokensList", base::FEATURE_ENABLED_BY_DEFAULT};
+// Max size of FCM registration tokens list. If the number of active devices
+// having FCM registration tokens is higher, then the resulting list will be
+// empty meaning unknown FCM registration tokens.
+inline constexpr base::FeatureParam<int> kSyncFCMRegistrationTokensListMaxSize{
+ &kSyncUseFCMRegistrationTokensList, "SyncFCMRegistrationTokensListMaxSize",
+ 5};
+// Enables filtering out inactive devices which haven't sent DeviceInfo update
+// recently (depending on the device's pulse_interval and an additional margin).
+inline constexpr base::Feature kSyncFilterOutInactiveDevicesForSingleClient{
+ "SyncFilterOutInactiveDevicesForSingleClient",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+// An additional threshold to consider devices as active. It extends device's
+// pulse interval to mitigate possible latency after DeviceInfo commit.
+inline constexpr base::FeatureParam<base::TimeDelta> kSyncActiveDeviceMargin{
+ &kSyncFilterOutInactiveDevicesForSingleClient, "SyncActiveDeviceMargin",
+ base::Minutes(30)};
} // namespace switches
diff --git a/chromium/components/browser_sync/profile_sync_components_factory_impl.cc b/chromium/components/browser_sync/sync_api_component_factory_impl.cc
index 7656bc8bf43..f14f4101758 100644
--- a/chromium/components/browser_sync/profile_sync_components_factory_impl.cc
+++ b/chromium/components/browser_sync/sync_api_component_factory_impl.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/browser_sync/profile_sync_components_factory_impl.h"
+#include "components/browser_sync/sync_api_component_factory_impl.h"
#include <utility>
@@ -35,13 +35,11 @@
#include "components/send_tab_to_self/send_tab_to_self_sync_service.h"
#include "components/sync/base/legacy_directory_deletion.h"
#include "components/sync/base/report_unrecoverable_error.h"
-#include "components/sync/base/sync_base_switches.h"
#include "components/sync/base/sync_prefs.h"
#include "components/sync/driver/data_type_manager_impl.h"
#include "components/sync/driver/glue/sync_engine_impl.h"
#include "components/sync/driver/glue/sync_transport_data_prefs.h"
#include "components/sync/driver/model_type_controller.h"
-#include "components/sync/driver/sync_driver_switches.h"
#include "components/sync/driver/syncable_service_based_model_type_controller.h"
#include "components/sync/engine/sync_engine.h"
#include "components/sync/invalidations/sync_invalidations_service.h"
@@ -124,7 +122,7 @@ base::WeakPtr<syncer::SyncableService> SyncableServiceForPrefs(
} // namespace
-ProfileSyncComponentsFactoryImpl::ProfileSyncComponentsFactoryImpl(
+SyncApiComponentFactoryImpl::SyncApiComponentFactoryImpl(
browser_sync::BrowserSyncClient* sync_client,
version_info::Channel channel,
const scoped_refptr<base::SequencedTaskRunner>& ui_thread,
@@ -154,10 +152,10 @@ ProfileSyncComponentsFactoryImpl::ProfileSyncComponentsFactoryImpl(
DCHECK(sync_client_);
}
-ProfileSyncComponentsFactoryImpl::~ProfileSyncComponentsFactoryImpl() = default;
+SyncApiComponentFactoryImpl::~SyncApiComponentFactoryImpl() = default;
syncer::DataTypeController::TypeVector
-ProfileSyncComponentsFactoryImpl::CreateCommonDataTypeControllers(
+SyncApiComponentFactoryImpl::CreateCommonDataTypeControllers(
syncer::ModelTypeSet disabled_types,
syncer::SyncService* sync_service) {
syncer::DataTypeController::TypeVector controllers;
@@ -235,8 +233,7 @@ ProfileSyncComponentsFactoryImpl::CreateCommonDataTypeControllers(
// disabled.
// TODO(crbug.com/1112095): Currently the offer data depends on Wallet data
// sync, but revisit after other offer types are implemented.
- if (base::FeatureList::IsEnabled(switches::kSyncAutofillWalletOfferData) &&
- !disabled_types.Has(syncer::AUTOFILL_WALLET_DATA) &&
+ if (!disabled_types.Has(syncer::AUTOFILL_WALLET_DATA) &&
!disabled_types.Has(syncer::AUTOFILL_WALLET_OFFER)) {
controllers.push_back(CreateWalletModelTypeController(
syncer::AUTOFILL_WALLET_OFFER,
@@ -375,11 +372,8 @@ ProfileSyncComponentsFactoryImpl::CreateCommonDataTypeControllers(
std::make_unique<syncer::ForwardingModelTypeControllerDelegate>(
delegate),
/*delegate_for_transport_mode=*/
- base::FeatureList::IsEnabled(
- send_tab_to_self::kSendTabToSelfWhenSignedIn)
- ? std::make_unique<
- syncer::ForwardingModelTypeControllerDelegate>(delegate)
- : nullptr));
+ std::make_unique<syncer::ForwardingModelTypeControllerDelegate>(
+ delegate)));
}
if (!disabled_types.Has(syncer::USER_CONSENTS)) {
@@ -398,7 +392,7 @@ ProfileSyncComponentsFactoryImpl::CreateCommonDataTypeControllers(
}
std::unique_ptr<DataTypeManager>
-ProfileSyncComponentsFactoryImpl::CreateDataTypeManager(
+SyncApiComponentFactoryImpl::CreateDataTypeManager(
const syncer::WeakHandle<syncer::DataTypeDebugInfoListener>&
debug_info_listener,
const DataTypeController::TypeMap* controllers,
@@ -411,7 +405,7 @@ ProfileSyncComponentsFactoryImpl::CreateDataTypeManager(
}
std::unique_ptr<syncer::SyncEngine>
-ProfileSyncComponentsFactoryImpl::CreateSyncEngine(
+SyncApiComponentFactoryImpl::CreateSyncEngine(
const std::string& name,
invalidation::InvalidationService* invalidator,
syncer::SyncInvalidationsService* sync_invalidation_service) {
@@ -428,7 +422,7 @@ ProfileSyncComponentsFactoryImpl::CreateSyncEngine(
base::Unretained(sync_client_)));
}
-void ProfileSyncComponentsFactoryImpl::ClearAllTransportData() {
+void SyncApiComponentFactoryImpl::ClearAllTransportData() {
syncer::SyncTransportDataPrefs sync_transport_data_prefs(
sync_client_->GetPrefService());
@@ -450,20 +444,21 @@ void ProfileSyncComponentsFactoryImpl::ClearAllTransportData() {
}
std::unique_ptr<syncer::ModelTypeControllerDelegate>
-ProfileSyncComponentsFactoryImpl::CreateForwardingControllerDelegate(
+SyncApiComponentFactoryImpl::CreateForwardingControllerDelegate(
syncer::ModelType type) {
return std::make_unique<syncer::ForwardingModelTypeControllerDelegate>(
sync_client_->GetControllerDelegateForModelType(type).get());
}
-std::unique_ptr<ModelTypeController> ProfileSyncComponentsFactoryImpl::
- CreateModelTypeControllerForModelRunningOnUIThread(syncer::ModelType type) {
+std::unique_ptr<ModelTypeController>
+SyncApiComponentFactoryImpl::CreateModelTypeControllerForModelRunningOnUIThread(
+ syncer::ModelType type) {
return std::make_unique<ModelTypeController>(
type, CreateForwardingControllerDelegate(type));
}
std::unique_ptr<ModelTypeController>
-ProfileSyncComponentsFactoryImpl::CreateWalletModelTypeController(
+SyncApiComponentFactoryImpl::CreateWalletModelTypeController(
syncer::ModelType type,
const base::RepeatingCallback<
base::WeakPtr<syncer::ModelTypeControllerDelegate>(
@@ -478,13 +473,13 @@ ProfileSyncComponentsFactoryImpl::CreateWalletModelTypeController(
sync_client_->GetPrefService(), sync_service);
}
-std::unique_ptr<ModelTypeController> ProfileSyncComponentsFactoryImpl::
- CreateWalletModelTypeControllerWithInMemorySupport(
- syncer::ModelType type,
- const base::RepeatingCallback<
- base::WeakPtr<syncer::ModelTypeControllerDelegate>(
- autofill::AutofillWebDataService*)>& delegate_from_web_data,
- syncer::SyncService* sync_service) {
+std::unique_ptr<ModelTypeController>
+SyncApiComponentFactoryImpl::CreateWalletModelTypeControllerWithInMemorySupport(
+ syncer::ModelType type,
+ const base::RepeatingCallback<
+ base::WeakPtr<syncer::ModelTypeControllerDelegate>(
+ autofill::AutofillWebDataService*)>& delegate_from_web_data,
+ syncer::SyncService* sync_service) {
return std::make_unique<AutofillWalletModelTypeController>(
type, /*delegate_for_full_sync_mode=*/
std::make_unique<syncer::ProxyModelTypeControllerDelegate>(
diff --git a/chromium/components/browser_sync/profile_sync_components_factory_impl.h b/chromium/components/browser_sync/sync_api_component_factory_impl.h
index 8c3904ff56b..435c7032191 100644
--- a/chromium/components/browser_sync/profile_sync_components_factory_impl.h
+++ b/chromium/components/browser_sync/sync_api_component_factory_impl.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef COMPONENTS_BROWSER_SYNC_PROFILE_SYNC_COMPONENTS_FACTORY_IMPL_H__
-#define COMPONENTS_BROWSER_SYNC_PROFILE_SYNC_COMPONENTS_FACTORY_IMPL_H__
+#ifndef COMPONENTS_BROWSER_SYNC_SYNC_API_COMPONENT_FACTORY_IMPL_H_
+#define COMPONENTS_BROWSER_SYNC_SYNC_API_COMPONENT_FACTORY_IMPL_H_
#include <memory>
#include <string>
@@ -39,10 +39,9 @@ namespace browser_sync {
class BrowserSyncClient;
-class ProfileSyncComponentsFactoryImpl
- : public syncer::SyncApiComponentFactory {
+class SyncApiComponentFactoryImpl : public syncer::SyncApiComponentFactory {
public:
- ProfileSyncComponentsFactoryImpl(
+ SyncApiComponentFactoryImpl(
BrowserSyncClient* sync_client,
version_info::Channel channel,
const scoped_refptr<base::SequencedTaskRunner>& ui_thread,
@@ -56,15 +55,14 @@ class ProfileSyncComponentsFactoryImpl
const scoped_refptr<password_manager::PasswordStoreInterface>&
account_password_store,
sync_bookmarks::BookmarkSyncService* bookmark_sync_service);
- ProfileSyncComponentsFactoryImpl(const ProfileSyncComponentsFactoryImpl&) =
+ SyncApiComponentFactoryImpl(const SyncApiComponentFactoryImpl&) = delete;
+ SyncApiComponentFactoryImpl& operator=(const SyncApiComponentFactoryImpl&) =
delete;
- ProfileSyncComponentsFactoryImpl& operator=(
- const ProfileSyncComponentsFactoryImpl&) = delete;
- ~ProfileSyncComponentsFactoryImpl() override;
+ ~SyncApiComponentFactoryImpl() override;
// Creates and returns enabled datatypes and their controllers.
// |disabled_types| allows callers to prevent certain types from being
- // created (e.g. to honor command-line flags).
+ // created.
syncer::DataTypeController::TypeVector CreateCommonDataTypeControllers(
syncer::ModelTypeSet disabled_types,
syncer::SyncService* sync_service);
@@ -133,4 +131,4 @@ class ProfileSyncComponentsFactoryImpl
} // namespace browser_sync
-#endif // COMPONENTS_BROWSER_SYNC_PROFILE_SYNC_COMPONENTS_FACTORY_IMPL_H__
+#endif // COMPONENTS_BROWSER_SYNC_SYNC_API_COMPONENT_FACTORY_IMPL_H_
diff --git a/chromium/components/browser_ui/accessibility/DEPS b/chromium/components/browser_ui/accessibility/DEPS
new file mode 100644
index 00000000000..08335e87944
--- /dev/null
+++ b/chromium/components/browser_ui/accessibility/DEPS
@@ -0,0 +1,6 @@
+include_rules = [
+ "+components/prefs",
+ "+components/user_prefs",
+ "+content/public/android/java",
+ "+content/public/browser",
+]
diff --git a/chromium/components/browser_ui/accessibility/DIR_METADATA b/chromium/components/browser_ui/accessibility/DIR_METADATA
new file mode 100644
index 00000000000..5153b281f24
--- /dev/null
+++ b/chromium/components/browser_ui/accessibility/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//chrome/android/java/src/org/chromium/chrome/browser/accessibility/COMMON_METADATA"
diff --git a/chromium/components/browser_ui/accessibility/OWNERS b/chromium/components/browser_ui/accessibility/OWNERS
new file mode 100644
index 00000000000..b1c8771531d
--- /dev/null
+++ b/chromium/components/browser_ui/accessibility/OWNERS
@@ -0,0 +1 @@
+file://chrome/android/java/src/org/chromium/chrome/browser/accessibility/OWNERS
diff --git a/chromium/components/browser_ui/accessibility/android/BUILD.gn b/chromium/components/browser_ui/accessibility/android/BUILD.gn
new file mode 100644
index 00000000000..23b6a6358b0
--- /dev/null
+++ b/chromium/components/browser_ui/accessibility/android/BUILD.gn
@@ -0,0 +1,62 @@
+# Copyright 2022 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.
+
+import("//build/config/android/rules.gni")
+
+generate_jni("accessibility_jni_headers") {
+ sources = [ "java/src/org/chromium/components/browser_ui/accessibility/FontSizePrefs.java" ]
+}
+
+source_set("android") {
+ sources = [
+ "font_size_prefs_android.cc",
+ "font_size_prefs_android.h",
+ ]
+ deps = [
+ ":accessibility_jni_headers",
+ "//base",
+ "//components/prefs",
+ "//components/user_prefs",
+ "//content/public/browser",
+ ]
+}
+
+# Constants only target without dependencies to allow embedders to only include relevant code.
+android_library("constants_java") {
+ sources = [ "java/src/org/chromium/components/browser_ui/accessibility/AccessibilityConstants.java" ]
+}
+
+android_library("java") {
+ sources = [
+ "java/src/org/chromium/components/browser_ui/accessibility/AccessibilitySettings.java",
+ "java/src/org/chromium/components/browser_ui/accessibility/AccessibilitySettingsDelegate.java",
+ "java/src/org/chromium/components/browser_ui/accessibility/FontSizePrefs.java",
+ "java/src/org/chromium/components/browser_ui/accessibility/TextScalePreference.java",
+ ]
+ annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
+ deps = [
+ ":constants_java",
+ ":java_resources",
+ "//base:base_java",
+ "//components/browser_ui/settings/android:java",
+ "//content/public/android:content_full_java",
+ "//third_party/androidx:androidx_annotation_annotation_java",
+ "//third_party/androidx:androidx_preference_preference_java",
+ ]
+ resources_package = "org.chromium.components.browser_ui.accessibility"
+}
+
+android_resources("java_resources") {
+ deps = [
+ "//components/browser_ui/strings/android:browser_ui_strings_grd",
+ "//components/browser_ui/styles/android:java_resources",
+ "//third_party/androidx:androidx_preference_preference_java",
+ ]
+ sources = [
+ "java/res/layout/custom_preference.xml",
+ "java/res/layout/preference_text_scale.xml",
+ "java/res/values/styles.xml",
+ "java/res/xml/accessibility_preferences.xml",
+ ]
+}
diff --git a/chromium/components/browser_ui/accessibility/android/font_size_prefs_android.cc b/chromium/components/browser_ui/accessibility/android/font_size_prefs_android.cc
new file mode 100644
index 00000000000..6707a2b32d3
--- /dev/null
+++ b/chromium/components/browser_ui/accessibility/android/font_size_prefs_android.cc
@@ -0,0 +1,97 @@
+// Copyright 2014 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.
+
+#include "components/browser_ui/accessibility/android/font_size_prefs_android.h"
+
+#include <memory>
+
+#include "base/bind.h"
+#include "base/observer_list.h"
+#include "components/browser_ui/accessibility/android/accessibility_jni_headers/FontSizePrefs_jni.h"
+#include "components/prefs/pref_change_registrar.h"
+#include "components/prefs/pref_service.h"
+#include "components/user_prefs/user_prefs.h"
+#include "content/public/browser/android/browser_context_handle.h"
+#include "content/public/browser/browser_context.h"
+
+namespace browser_ui {
+
+using base::android::JavaParamRef;
+using base::android::JavaRef;
+
+namespace prefs {
+const char kWebKitFontScaleFactor[] = "webkit.webprefs.font_scale_factor";
+const char kWebKitForceEnableZoom[] = "webkit.webprefs.force_enable_zoom";
+} // namespace prefs
+
+FontSizePrefsAndroid::FontSizePrefsAndroid(
+ JNIEnv* env,
+ jobject obj,
+ const JavaParamRef<jobject>& jbrowser_context_handle)
+ : pref_service_(user_prefs::UserPrefs::Get(
+ content::BrowserContextFromJavaHandle(jbrowser_context_handle))) {
+ java_ref_.Reset(env, obj);
+ pref_change_registrar_ = std::make_unique<PrefChangeRegistrar>();
+ pref_change_registrar_->Init(pref_service_);
+ pref_change_registrar_->Add(
+ prefs::kWebKitFontScaleFactor,
+ base::BindRepeating(&FontSizePrefsAndroid::OnFontScaleFactorChanged,
+ base::Unretained(this)));
+ pref_change_registrar_->Add(
+ prefs::kWebKitForceEnableZoom,
+ base::BindRepeating(&FontSizePrefsAndroid::OnForceEnableZoomChanged,
+ base::Unretained(this)));
+}
+
+FontSizePrefsAndroid::~FontSizePrefsAndroid() {}
+
+void FontSizePrefsAndroid::SetFontScaleFactor(JNIEnv* env,
+ const JavaRef<jobject>& obj,
+ jfloat font_size) {
+ pref_service_->SetDouble(prefs::kWebKitFontScaleFactor,
+ static_cast<double>(font_size));
+}
+
+float FontSizePrefsAndroid::GetFontScaleFactor(JNIEnv* env,
+ const JavaRef<jobject>& obj) {
+ return pref_service_->GetDouble(prefs::kWebKitFontScaleFactor);
+}
+
+void FontSizePrefsAndroid::SetForceEnableZoom(JNIEnv* env,
+ const JavaRef<jobject>& obj,
+ jboolean enabled) {
+ pref_service_->SetBoolean(prefs::kWebKitForceEnableZoom, enabled);
+}
+
+bool FontSizePrefsAndroid::GetForceEnableZoom(JNIEnv* env,
+ const JavaRef<jobject>& obj) {
+ return pref_service_->GetBoolean(prefs::kWebKitForceEnableZoom);
+}
+
+void FontSizePrefsAndroid::Destroy(JNIEnv* env) {
+ delete this;
+}
+
+jlong JNI_FontSizePrefs_Init(
+ JNIEnv* env,
+ const JavaParamRef<jobject>& obj,
+ const base::android::JavaParamRef<jobject>& jbrowser_context_handle) {
+ FontSizePrefsAndroid* font_size_prefs_android =
+ new FontSizePrefsAndroid(env, obj, jbrowser_context_handle);
+ return reinterpret_cast<intptr_t>(font_size_prefs_android);
+}
+
+void FontSizePrefsAndroid::OnFontScaleFactorChanged() {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ float factor = GetFontScaleFactor(env, java_ref_);
+ Java_FontSizePrefs_onFontScaleFactorChanged(env, java_ref_, factor);
+}
+
+void FontSizePrefsAndroid::OnForceEnableZoomChanged() {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ bool enabled = GetForceEnableZoom(env, java_ref_);
+ Java_FontSizePrefs_onForceEnableZoomChanged(env, java_ref_, enabled);
+}
+
+} // namespace browser_ui
diff --git a/chromium/components/browser_ui/accessibility/android/font_size_prefs_android.h b/chromium/components/browser_ui/accessibility/android/font_size_prefs_android.h
new file mode 100644
index 00000000000..6db5639f321
--- /dev/null
+++ b/chromium/components/browser_ui/accessibility/android/font_size_prefs_android.h
@@ -0,0 +1,66 @@
+// Copyright 2014 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.
+
+#ifndef COMPONENTS_BROWSER_UI_ACCESSIBILITY_ANDROID_FONT_SIZE_PREFS_ANDROID_H_
+#define COMPONENTS_BROWSER_UI_ACCESSIBILITY_ANDROID_FONT_SIZE_PREFS_ANDROID_H_
+
+#include <memory>
+
+#include "base/android/scoped_java_ref.h"
+#include "base/memory/raw_ptr.h"
+
+class PrefChangeRegistrar;
+class PrefService;
+
+namespace browser_ui {
+namespace prefs {
+
+// Prefs related to this class.
+extern const char kWebKitFontScaleFactor[];
+extern const char kWebKitForceEnableZoom[];
+
+} // namespace prefs
+
+/*
+ * Native implementation of FontSizePrefs. This class is used to get and set
+ * FontScaleFactor and ForceEnableZoom.
+ */
+class FontSizePrefsAndroid {
+ public:
+ FontSizePrefsAndroid(
+ JNIEnv* env,
+ jobject obj,
+ const base::android::JavaParamRef<jobject>& jbrowser_context_handle);
+
+ FontSizePrefsAndroid(const FontSizePrefsAndroid&) = delete;
+ FontSizePrefsAndroid& operator=(const FontSizePrefsAndroid&) = delete;
+
+ ~FontSizePrefsAndroid();
+
+ void SetFontScaleFactor(JNIEnv* env,
+ const base::android::JavaRef<jobject>& obj,
+ jfloat font);
+ float GetFontScaleFactor(JNIEnv* env,
+ const base::android::JavaRef<jobject>& obj);
+ void SetForceEnableZoom(JNIEnv* env,
+ const base::android::JavaRef<jobject>& obj,
+ jboolean enabled);
+ bool GetForceEnableZoom(JNIEnv* env,
+ const base::android::JavaRef<jobject>& obj);
+ void Destroy(JNIEnv* env);
+
+ private:
+ // Callback for FontScaleFactor changes from pref change registrar.
+ void OnFontScaleFactorChanged();
+ // Callback for ForceEnableZoom changes from pref change registrar.
+ void OnForceEnableZoomChanged();
+
+ std::unique_ptr<PrefChangeRegistrar> pref_change_registrar_;
+ const raw_ptr<PrefService> pref_service_;
+ base::android::ScopedJavaGlobalRef<jobject> java_ref_;
+};
+
+} // namespace browser_ui
+
+#endif // COMPONENTS_BROWSER_UI_ACCESSIBILITY_ANDROID_FONT_SIZE_PREFS_ANDROID_H_
diff --git a/chromium/components/browser_ui/bottomsheet/android/internal/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetControllerImpl.java b/chromium/components/browser_ui/bottomsheet/android/internal/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetControllerImpl.java
index e6a264bb0b1..adc69e08d98 100644
--- a/chromium/components/browser_ui/bottomsheet/android/internal/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetControllerImpl.java
+++ b/chromium/components/browser_ui/bottomsheet/android/internal/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetControllerImpl.java
@@ -406,8 +406,10 @@ class BottomSheetControllerImpl implements ManagedBottomSheetController {
if (mBottomSheet == null) mSheetInitializer.run();
- // If already showing the requested content, do nothing.
- if (content == mBottomSheet.getCurrentSheetContent()) return true;
+ // If already showing (or queued to show) the requested content, do nothing.
+ if (content == mBottomSheet.getCurrentSheetContent() || mContentQueue.contains(content)) {
+ return content == mBottomSheet.getCurrentSheetContent();
+ }
boolean shouldSwapForPriorityContent = mBottomSheet.getCurrentSheetContent() != null
&& content.getPriority() < mBottomSheet.getCurrentSheetContent().getPriority()
diff --git a/chromium/components/browser_ui/bottomsheet/android/internal/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetObserverTest.java b/chromium/components/browser_ui/bottomsheet/android/internal/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetObserverTest.java
index 92ebeff25e1..789a93c3717 100644
--- a/chromium/components/browser_ui/bottomsheet/android/internal/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetObserverTest.java
+++ b/chromium/components/browser_ui/bottomsheet/android/internal/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheetObserverTest.java
@@ -29,7 +29,7 @@ import org.chromium.base.test.util.Restriction;
import org.chromium.components.browser_ui.bottomsheet.BottomSheetController.StateChangeReason;
import org.chromium.components.browser_ui.widget.scrim.ScrimCoordinator;
import org.chromium.ui.KeyboardVisibilityDelegate;
-import org.chromium.ui.test.util.DummyUiActivity;
+import org.chromium.ui.test.util.BlankUiTestActivity;
import org.chromium.ui.test.util.UiRestriction;
import java.util.concurrent.TimeoutException;
@@ -98,8 +98,8 @@ public class BottomSheetObserverTest {
}
@ClassRule
- public static BaseActivityTestRule<DummyUiActivity> mTestRule =
- new BaseActivityTestRule<>(DummyUiActivity.class);
+ public static BaseActivityTestRule<BlankUiTestActivity> mTestRule =
+ new BaseActivityTestRule<>(BlankUiTestActivity.class);
private TestSheetObserver mObserver;
private TestBottomSheetContent mSheetContent;
private BottomSheetController mBottomSheetController;
diff --git a/chromium/components/browser_ui/client_certificate/android/BUILD.gn b/chromium/components/browser_ui/client_certificate/android/BUILD.gn
index dad52aab610..7890738b09f 100644
--- a/chromium/components/browser_ui/client_certificate/android/BUILD.gn
+++ b/chromium/components/browser_ui/client_certificate/android/BUILD.gn
@@ -20,6 +20,7 @@ android_library("java") {
deps = [
":java_resources",
"//base:base_java",
+ "//components/browser_ui/widget/android:java_resources",
"//content/public/android:content_java",
"//third_party/androidx:androidx_annotation_annotation_java",
"//third_party/androidx:androidx_appcompat_appcompat_java",
diff --git a/chromium/components/browser_ui/client_certificate/android/ssl_client_certificate_request.cc b/chromium/components/browser_ui/client_certificate/android/ssl_client_certificate_request.cc
index 014cf5d0786..36a27f3c250 100644
--- a/chromium/components/browser_ui/client_certificate/android/ssl_client_certificate_request.cc
+++ b/chromium/components/browser_ui/client_certificate/android/ssl_client_certificate_request.cc
@@ -5,6 +5,8 @@
#include "components/browser_ui/client_certificate/android/ssl_client_certificate_request.h"
#include <stddef.h>
+
+#include <tuple>
#include <utility>
#include "base/android/jni_array.h"
@@ -14,7 +16,6 @@
#include "base/check.h"
#include "base/compiler_specific.h"
#include "base/containers/queue.h"
-#include "base/ignore_result.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "components/browser_ui/client_certificate/android/jni_headers/SSLClientCertificateRequest_jni.h"
@@ -211,7 +212,7 @@ static void StartClientCertificateRequest(
}
// Ownership was transferred to Java.
- ignore_result(request.release());
+ std::ignore = request.release();
}
void SSLClientCertPendingRequests::AddRequest(
diff --git a/chromium/components/browser_ui/notifications/android/BUILD.gn b/chromium/components/browser_ui/notifications/android/BUILD.gn
index 0e14bed984e..8035d5039aa 100644
--- a/chromium/components/browser_ui/notifications/android/BUILD.gn
+++ b/chromium/components/browser_ui/notifications/android/BUILD.gn
@@ -26,6 +26,7 @@ android_library("java") {
"//third_party/android_deps:android_support_v4_java",
"//third_party/androidx:androidx_annotation_annotation_java",
"//third_party/androidx:androidx_core_core_java",
+ "//ui/android:ui_java",
]
}
diff --git a/chromium/components/guest_view/common/DEPS b/chromium/components/browser_ui/notifications/android/DEPS
index b0e64bf2235..da0f8995779 100644
--- a/chromium/components/guest_view/common/DEPS
+++ b/chromium/components/browser_ui/notifications/android/DEPS
@@ -1,3 +1,3 @@
include_rules = [
- "+ipc"
-]
+ "+ui/android",
+] \ No newline at end of file
diff --git a/chromium/components/browser_ui/photo_picker/android/BUILD.gn b/chromium/components/browser_ui/photo_picker/android/BUILD.gn
index 89d86637b26..fe4984130aa 100644
--- a/chromium/components/browser_ui/photo_picker/android/BUILD.gn
+++ b/chromium/components/browser_ui/photo_picker/android/BUILD.gn
@@ -65,8 +65,7 @@ generate_jni("photo_picker_jni_headers") {
}
android_aidl("photo_picker_aidl") {
- import_include =
- [ "java/src/org/chromium/components/browser_ui/photo_picker" ]
+ import_include = [ "java/src/" ]
sources = [
"java/src/org/chromium/components/browser_ui/photo_picker/IDecoderService.aidl",
"java/src/org/chromium/components/browser_ui/photo_picker/IDecoderServiceCallback.aidl",
diff --git a/chromium/components/browser_ui/photo_picker/android/features.cc b/chromium/components/browser_ui/photo_picker/android/features.cc
index b71197e8ec5..7939f9e8ef8 100644
--- a/chromium/components/browser_ui/photo_picker/android/features.cc
+++ b/chromium/components/browser_ui/photo_picker/android/features.cc
@@ -11,7 +11,7 @@ namespace features {
namespace {
-// Array of features exposed through the Java Features brdige class. Entries in
+// Array of features exposed through the Java Features bridge class. Entries in
// this array may either refer to features defined in the header of this file or
// in other locations in the code base (e.g. content_features.h), and must be
// replicated in the same order in PhotoPickerFeatures.java.
@@ -22,7 +22,7 @@ const base::Feature* kFeaturesExposedToJava[] = {
} // namespace
const base::Feature kPhotoPickerVideoSupport{"PhotoPickerVideoSupport",
- base::FEATURE_DISABLED_BY_DEFAULT};
+ base::FEATURE_ENABLED_BY_DEFAULT};
static jlong JNI_PhotoPickerFeatures_GetFeature(JNIEnv* env, jint ordinal) {
return reinterpret_cast<jlong>(kFeaturesExposedToJava[ordinal]);
diff --git a/chromium/components/browser_ui/settings/android/BUILD.gn b/chromium/components/browser_ui/settings/android/BUILD.gn
index f8ac1bcb989..5da51fc2750 100644
--- a/chromium/components/browser_ui/settings/android/BUILD.gn
+++ b/chromium/components/browser_ui/settings/android/BUILD.gn
@@ -19,6 +19,7 @@ android_library("java") {
"widget/java/src/org/chromium/components/browser_ui/settings/ChromeSwitchPreference.java",
"widget/java/src/org/chromium/components/browser_ui/settings/ClickableSpansTextMessagePreference.java",
"widget/java/src/org/chromium/components/browser_ui/settings/ExpandablePreferenceGroup.java",
+ "widget/java/src/org/chromium/components/browser_ui/settings/ImageButtonPreference.java",
"widget/java/src/org/chromium/components/browser_ui/settings/LearnMorePreference.java",
"widget/java/src/org/chromium/components/browser_ui/settings/LongSummaryTextMessagePreference.java",
"widget/java/src/org/chromium/components/browser_ui/settings/SpinnerPreference.java",
@@ -58,6 +59,7 @@ android_resources("java_resources") {
"java/res/layout/button_preference_layout.xml",
"java/res/layout/checkable_image_view_widget.xml",
"java/res/layout/clickable_spans_text_message_preference_layout.xml",
+ "java/res/layout/image_button_widget.xml",
"java/res/layout/preference_chrome_image_view.xml",
"java/res/layout/preference_spinner.xml",
"java/res/layout/preference_spinner_single_line.xml",
diff --git a/chromium/components/browser_ui/settings/android/widget/java/src/org/chromium/components/browser_ui/settings/ButtonPreference.java b/chromium/components/browser_ui/settings/android/widget/java/src/org/chromium/components/browser_ui/settings/ButtonPreference.java
index 4d7bbd40460..bebc308ab1f 100644
--- a/chromium/components/browser_ui/settings/android/widget/java/src/org/chromium/components/browser_ui/settings/ButtonPreference.java
+++ b/chromium/components/browser_ui/settings/android/widget/java/src/org/chromium/components/browser_ui/settings/ButtonPreference.java
@@ -5,6 +5,7 @@
package org.chromium.components.browser_ui.settings;
import android.content.Context;
+import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.widget.Button;
@@ -24,7 +25,11 @@ public class ButtonPreference extends Preference {
public ButtonPreference(Context context, AttributeSet attrs) {
super(context, attrs);
setLayoutResource(R.layout.button_preference_layout);
- setWidgetLayoutResource(R.layout.button_preference_button);
+
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ButtonPreference);
+ setWidgetLayoutResource(a.getResourceId(
+ R.styleable.ButtonPreference_buttonLayout, R.layout.button_preference_button));
+ a.recycle();
// Only the inner button element should be focusable.
setSelectable(false);
diff --git a/chromium/components/browser_ui/settings/android/widget/java/src/org/chromium/components/browser_ui/settings/ChromeBasePreference.java b/chromium/components/browser_ui/settings/android/widget/java/src/org/chromium/components/browser_ui/settings/ChromeBasePreference.java
index 6c5476db8ad..aa9de492de0 100644
--- a/chromium/components/browser_ui/settings/android/widget/java/src/org/chromium/components/browser_ui/settings/ChromeBasePreference.java
+++ b/chromium/components/browser_ui/settings/android/widget/java/src/org/chromium/components/browser_ui/settings/ChromeBasePreference.java
@@ -15,6 +15,8 @@ import androidx.annotation.Nullable;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
+import org.chromium.base.metrics.RecordUserAction;
+
/**
* A preference that supports some Chrome-specific customizations:
*
@@ -37,6 +39,8 @@ public class ChromeBasePreference extends Preference {
private Boolean mDividerAllowedAbove;
@Nullable
private Boolean mDividerAllowedBelow;
+ @Nullable
+ private String mUserAction;
/**
* Constructor for use in Java.
@@ -55,6 +59,7 @@ public class ChromeBasePreference extends Preference {
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ChromeBasePreference);
mIconTint = a.getColorStateList(R.styleable.ChromeBasePreference_iconTint);
+ mUserAction = a.getString(R.styleable.ChromeBasePreference_userAction);
a.recycle();
}
@@ -94,6 +99,9 @@ public class ChromeBasePreference extends Preference {
@Override
protected void onClick() {
if (ManagedPreferencesUtils.onClickPreference(mManagedPrefDelegate, this)) return;
+ if (mUserAction != null) {
+ RecordUserAction.record(mUserAction);
+ }
super.onClick();
}
}
diff --git a/chromium/components/browser_ui/settings/android/widget/java/src/org/chromium/components/browser_ui/settings/ImageButtonPreference.java b/chromium/components/browser_ui/settings/android/widget/java/src/org/chromium/components/browser_ui/settings/ImageButtonPreference.java
new file mode 100644
index 00000000000..f88c42e6ea4
--- /dev/null
+++ b/chromium/components/browser_ui/settings/android/widget/java/src/org/chromium/components/browser_ui/settings/ImageButtonPreference.java
@@ -0,0 +1,66 @@
+// Copyright 2022 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.
+
+package org.chromium.components.browser_ui.settings;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+
+import androidx.annotation.DrawableRes;
+import androidx.annotation.StringRes;
+import androidx.preference.PreferenceViewHolder;
+
+import org.chromium.ui.widget.ChromeImageButton;
+
+/**
+ * A preference with an ImageButton as widget. Clicks on the image button will trigger the
+ * OnPreferenceClickListener. Clicks on the preference itself are ignored.
+ */
+public class ImageButtonPreference extends ChromeBasePreference implements View.OnClickListener {
+ private @DrawableRes int mImage;
+ private @StringRes int mContentDescription;
+
+ public ImageButtonPreference(Context context) {
+ super(context);
+ initialize();
+ }
+
+ public ImageButtonPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ initialize();
+ }
+
+ /**
+ * Set the image and content description for this preference.
+ */
+ public void setImage(@DrawableRes int image, @StringRes int contentDescription) {
+ mImage = image;
+ mContentDescription = contentDescription;
+ }
+
+ private void initialize() {
+ setSelectable(false);
+ setWidgetLayoutResource(R.layout.image_button_widget);
+ }
+
+ @Override
+ public void onBindViewHolder(PreferenceViewHolder holder) {
+ super.onBindViewHolder(holder);
+ ChromeImageButton imageButton = (ChromeImageButton) holder.findViewById(R.id.image_button);
+ imageButton.setImageResource(mImage);
+ if (mContentDescription != 0) {
+ imageButton.setContentDescription(
+ imageButton.getResources().getString(mContentDescription));
+ }
+ imageButton.setOnClickListener(this);
+ }
+
+ @Override
+ public void onClick(View v) {
+ if (getOnPreferenceClickListener() != null) {
+ getOnPreferenceClickListener().onPreferenceClick(this);
+ }
+ }
+}
diff --git a/chromium/components/browser_ui/settings/android/widget/java/src/org/chromium/components/browser_ui/settings/LearnMorePreference.java b/chromium/components/browser_ui/settings/android/widget/java/src/org/chromium/components/browser_ui/settings/LearnMorePreference.java
index 82330fb48a6..415354815d7 100644
--- a/chromium/components/browser_ui/settings/android/widget/java/src/org/chromium/components/browser_ui/settings/LearnMorePreference.java
+++ b/chromium/components/browser_ui/settings/android/widget/java/src/org/chromium/components/browser_ui/settings/LearnMorePreference.java
@@ -32,7 +32,7 @@ public class LearnMorePreference extends Preference {
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
TextView titleView = (TextView) holder.findViewById(android.R.id.title);
- ApiCompatibilityUtils.setTextAppearance(titleView, R.style.TextAppearance_TextLarge_Blue);
+ ApiCompatibilityUtils.setTextAppearance(titleView, R.style.TextAppearance_TextLarge_Link);
titleView.setClickable(true);
titleView.setOnClickListener(v -> getOnPreferenceClickListener().onPreferenceClick(this));
}
diff --git a/chromium/components/browser_ui/share/android/BUILD.gn b/chromium/components/browser_ui/share/android/BUILD.gn
index 9e632933ba3..7ee31479c68 100644
--- a/chromium/components/browser_ui/share/android/BUILD.gn
+++ b/chromium/components/browser_ui/share/android/BUILD.gn
@@ -41,6 +41,7 @@ android_library("java") {
":java_resources",
"//base:base_java",
"//components/browser_ui/util/android:java",
+ "//components/browser_ui/widget/android:java_resources",
"//components/dom_distiller/core/android:dom_distiller_core_java",
"//content/public/android:content_java",
"//third_party/androidx:androidx_annotation_annotation_java",
@@ -73,6 +74,7 @@ android_library("javatests") {
"//base:base_java_test_support",
"//chrome/android:chrome_java",
"//content/public/test/android:content_java_test_support",
+ "//third_party/androidx:androidx_annotation_annotation_java",
"//third_party/androidx:androidx_appcompat_appcompat_java",
"//third_party/androidx:androidx_core_core_java",
"//third_party/androidx:androidx_test_runner_java",
diff --git a/chromium/components/browser_ui/site_settings/android/storage_info_fetcher.cc b/chromium/components/browser_ui/site_settings/android/storage_info_fetcher.cc
index aa68b455f24..f87430ea508 100644
--- a/chromium/components/browser_ui/site_settings/android/storage_info_fetcher.cc
+++ b/chromium/components/browser_ui/site_settings/android/storage_info_fetcher.cc
@@ -51,7 +51,6 @@ void StorageInfoFetcher::ClearStorage(const std::string& host,
FROM_HERE,
base::BindOnce(
&storage::QuotaManager::DeleteHostData, quota_manager_, host, type,
- storage::AllQuotaClientTypes(),
base::BindOnce(&StorageInfoFetcher::OnUsageClearedInternal, this)));
}
diff --git a/chromium/components/browser_ui/site_settings/android/website_preference_bridge.cc b/chromium/components/browser_ui/site_settings/android/website_preference_bridge.cc
index a97af8e07f4..720f516d13d 100644
--- a/chromium/components/browser_ui/site_settings/android/website_preference_bridge.cc
+++ b/chromium/components/browser_ui/site_settings/android/website_preference_bridge.cc
@@ -26,7 +26,6 @@
#include "components/cdm/browser/media_drm_storage_impl.h"
#include "components/content_settings/core/browser/cookie_settings.h"
#include "components/content_settings/core/browser/host_content_settings_map.h"
-#include "components/content_settings/core/browser/uma_util.h"
#include "components/content_settings/core/common/content_settings.h"
#include "components/content_settings/core/common/content_settings_types.h"
#include "components/permissions/object_permission_context_base.h"
@@ -79,24 +78,6 @@ HostContentSettingsMap* GetHostContentSettingsMap(
return GetHostContentSettingsMap(unwrap(jbrowser_context_handle));
}
-// Reset the give permission for the DSE if the permission and origin are
-// controlled by the DSE.
-bool MaybeResetDSEPermission(BrowserContext* browser_context,
- ContentSettingsType type,
- const GURL& origin,
- const GURL& embedder,
- ContentSetting setting) {
- if (!embedder.is_empty() && embedder != origin)
- return false;
-
- if (setting != CONTENT_SETTING_DEFAULT)
- return false;
-
- return permissions::PermissionsClient::Get()
- ->ResetPermissionIfControlledByDse(browser_context, type,
- url::Origin::Create(origin));
-}
-
ScopedJavaLocalRef<jstring> ConvertOriginToJavaString(
JNIEnv* env,
const std::string& origin) {
@@ -242,11 +223,6 @@ void SetPermissionSettingForOrigin(
->RemoveEmbargoAndResetCounts(origin_url, content_type);
}
- if (MaybeResetDSEPermission(browser_context, content_type, origin_url,
- embedder_url, setting)) {
- return;
- }
-
permissions::PermissionUmaUtil::ScopedRevocationReporter
scoped_revocation_reporter(
browser_context, origin_url, embedder_url, content_type,
@@ -254,7 +230,6 @@ void SetPermissionSettingForOrigin(
GetHostContentSettingsMap(browser_context)
->SetContentSettingDefaultScope(origin_url, embedder_url, content_type,
setting);
- content_settings::LogWebSiteSettingsPermissionChange(content_type, setting);
}
permissions::ObjectPermissionContextBase* GetChooserContext(
@@ -362,12 +337,6 @@ static void SetNotificationSettingForOrigin(
->GetPermissionDecisionAutoBlocker(browser_context)
->RemoveEmbargoAndResetCounts(url, ContentSettingsType::NOTIFICATIONS);
- if (MaybeResetDSEPermission(browser_context,
- ContentSettingsType::NOTIFICATIONS, url, GURL(),
- setting)) {
- return;
- }
-
permissions::PermissionUmaUtil::ScopedRevocationReporter
scoped_revocation_reporter(
browser_context, url, GURL(), ContentSettingsType::NOTIFICATIONS,
@@ -376,8 +345,6 @@ static void SetNotificationSettingForOrigin(
GetHostContentSettingsMap(browser_context)
->SetContentSettingDefaultScope(
url, GURL(), ContentSettingsType::NOTIFICATIONS, setting);
- content_settings::LogWebSiteSettingsPermissionChange(
- ContentSettingsType::NOTIFICATIONS, setting);
}
// In Android O+, Android is responsible for revoking notification settings--
@@ -392,9 +359,6 @@ static void JNI_WebsitePreferenceBridge_ReportNotificationRevokedForOrigin(
ContentSetting setting = static_cast<ContentSetting>(new_setting_value);
DCHECK_NE(setting, CONTENT_SETTING_ALLOW);
- content_settings::LogWebSiteSettingsPermissionChange(
- ContentSettingsType::NOTIFICATIONS, setting);
-
permissions::PermissionUmaUtil::PermissionRevoked(
ContentSettingsType::NOTIFICATIONS,
permissions::PermissionSourceUI::ANDROID_SETTINGS,
@@ -692,7 +656,7 @@ static void JNI_WebsitePreferenceBridge_ClearBannerData(
GetHostContentSettingsMap(jbrowser_context_handle)
->SetWebsiteSettingDefaultScope(
GURL(ConvertJavaStringToUTF8(env, jorigin)), GURL(),
- ContentSettingsType::APP_BANNER, nullptr);
+ ContentSettingsType::APP_BANNER, base::Value());
}
static void JNI_WebsitePreferenceBridge_ClearMediaLicenses(
@@ -708,17 +672,6 @@ static void JNI_WebsitePreferenceBridge_ClearMediaLicenses(
base::DoNothing());
}
-static jboolean JNI_WebsitePreferenceBridge_IsPermissionControlledByDSE(
- JNIEnv* env,
- const JavaParamRef<jobject>& jbrowser_context_handle,
- int content_settings_type,
- const JavaParamRef<jstring>& jorigin) {
- return permissions::PermissionsClient::Get()->IsPermissionControlledByDse(
- unwrap(jbrowser_context_handle),
- static_cast<ContentSettingsType>(content_settings_type),
- url::Origin::Create(GURL(ConvertJavaStringToUTF8(env, jorigin))));
-}
-
static jboolean JNI_WebsitePreferenceBridge_IsDSEOrigin(
JNIEnv* env,
const JavaParamRef<jobject>& jbrowser_context_handle,
diff --git a/chromium/components/browser_ui/strings/android/browser_ui_strings.grd b/chromium/components/browser_ui/strings/android/browser_ui_strings.grd
index b08e32e3cba..4e5ecf6afcf 100644
--- a/chromium/components/browser_ui/strings/android/browser_ui_strings.grd
+++ b/chromium/components/browser_ui/strings/android/browser_ui_strings.grd
@@ -171,9 +171,6 @@
<messages fallback_to_english="true">
<part file="site_settings.grdp" />
- <message name="IDS_DELETED" desc='Text that announces to the user that something was deleted.'>
- Deleted
- </message>
<message name="IDS_GOT_IT" desc="Button for the user to accept a disclosure/message">
Got it
</message>
@@ -331,6 +328,9 @@
<message name="IDS_ACCESSIBILITY_LIST_MENU_BUTTON" desc="Content description for the button that shows option menu for a list item.">
<ph name="NAME_OF_LIST_ITEM">%1$s<ex>Movie Title</ex></ph> Options
</message>
+ <message name="IDS_ACCESSIBILITY_LIST_REMOVE_BUTTON" desc="Content description for the button that removes a list item.">
+ <ph name="NAME_OF_LIST_ITEM">%1$s<ex>Movie Title</ex></ph> Remove
+ </message>
<message name="IDS_ACCESSIBILITY_TOOLBAR_SCREEN_POSITION" desc="Accessibility announcement to inform users about a toolbar's location.">
<ph name="ITEM_COUNT">%1$s<ex>3</ex></ph> selected. Options available near top of the screen
</message>
@@ -448,7 +448,7 @@
<!-- Page Info popup -->
<message name="IDS_PAGE_INFO_ABOUT_THIS_SITE_TITLE" desc="The title label of the 'About this site' subpage in Page Info bubble.">
- About this site
+ From the web
</message>
<message name="IDS_PAGE_INFO_ABOUT_THIS_SITE_SUBPAGE_FROM_LABEL" desc="The label containing the source of the description in the 'About this site' subpage in Page Info bubble.">
From <ph name="SOURCE_NAME">%1$s<ex>Wikipedia</ex></ph>
@@ -580,6 +580,15 @@
<message name="IDS_PAGE_INFO_URL_TRUNCATED" desc="Accessibility announcement when the URL in PageInfo switches from full to truncated display">
URL truncated
</message>
+ <message name="IDS_PAGE_INFO_AD_PERSONALIZATION_TITLE" desc="The title of the 'Ad personalization' section in Page Info.">
+ Ad personalization
+ </message>
+ <message name="IDS_PAGE_AD_PERSONALIZATION_DESCRIPTION" desc="Description of a section in PageInfo that shows information on how the current site is using ad personalization APIs from the Privacy Sandbox.">
+ This site gets your interests from Chrome to show you more relevant ads
+ </message>
+ <message name="IDS_PAGE_INFO_AD_MANAGE_INTERESTS" desc="The button label of the 'Manage interests' button in Page Info. The button opens a settings page to manage interests for the site.">
+ Manage interests
+ </message>
<message name="IDS_COOKIES_TITLE" desc="Title for the Cookies settings screen [CHAR_LIMIT=32]">
Cookies
@@ -830,6 +839,43 @@
<message name="IDS_IPH_SNOOZE" desc="Snooze button text within In-Product Help tooltip.">
Remind me
</message>
+
+ <!-- ChipView -->
+ <message name="IDS_CHIP_REMOVE_ICON_CONTENT_DESCRIPTION" desc="Accessibility string for X icon on a chip announcing that clicking on this icon will remove this input chip.">
+ Remove '<ph name="CHIP_LABEL">%1$s<ex>News</ex></ph>'
+ </message>
+
+ <!-- Accessibility preferences -->
+ <message name="IDS_PREFS_ACCESSIBILITY" desc="Title of Accessibility settings, which allows the user to change webpage font sizes. [CHAR_LIMIT=32]">
+ Accessibility
+ </message>
+ <message name="IDS_FONT_SIZE" desc="Title for font size preference.">
+ Text scaling
+ </message>
+ <message name="IDS_FONT_SIZE_PREVIEW_TEXT" desc="Preview text for font-size slider.">
+ Drag the slider until you can read this comfortably. Text should look at least this big after double-tapping on a paragraph.
+ </message>
+ <message name="IDS_FORCE_ENABLE_ZOOM_TITLE" desc="Title of preference that allows the user to zoom in on any webpage, even if the page tries to disable zooming.">
+ Force enable zoom
+ </message>
+ <message name="IDS_FORCE_ENABLE_ZOOM_SUMMARY" desc="Summary of preference that allows the user to zoom in on any webpage, even if the page tries to disable zooming.">
+ Override a website’s request to prevent zooming in
+ </message>
+ <message name="IDS_READER_FOR_ACCESSIBILITY_TITLE" desc="Title of preference that allows the user to use simplified view on any articles, even if the page is mobile-friendly. Simplified view is the new user-facing name for Reader Mode, which extracts the content of an article and removes clutter from a web page and puts the result in a easier-to-read format.">
+ Simplified view for web pages
+ </message>
+ <message name="IDS_READER_FOR_ACCESSIBILITY_SUMMARY" desc="Summary of preference that allows the user to use simplified view on any supported articles, even if the page is mobile-friendly.">
+ Get notified when a site can be shown in simplified view
+ </message>
+ <message name="IDS_ACCESSIBILITY_TAB_SWITCHER_TITLE" desc="Title of preference that allows the user to use a simplified tab switcher that is accessibility friendly. The words 'Open tabs' should match translation in TC ID 3108541343994525384, provided that 'open' is correctly used as an adjective and not a verb.">
+ Simplified view for open tabs
+ </message>
+ <message name="IDS_ACCESSIBILITY_TAB_SWITCHER_SUMMARY" desc="Summary of the preference that allows the user to use a simplified tab switcher. The simplified tab switcher is recommended for use with TalkBack and Switch Access which are accessibility services provided by Android. TalkBack does not need to be translated. 'Switch Access' translation should match TC ID 382005103867249841.">
+ Recommended when TalkBack or Switch Access are on
+ </message>
+ <message name="IDS_ACCESSIBILITY_CAPTIONS_TITLE" desc="Title of the preference that allows the user to update caption settings.">
+ Captions
+ </message>
</messages>
</release>
</grit>
diff --git a/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_ACCESSIBILITY_CAPTIONS_TITLE.png.sha1 b/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_ACCESSIBILITY_CAPTIONS_TITLE.png.sha1
new file mode 100644
index 00000000000..433f68cdb8a
--- /dev/null
+++ b/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_ACCESSIBILITY_CAPTIONS_TITLE.png.sha1
@@ -0,0 +1 @@
+ef7969ff56c980a729507dafa20ba40b7be0a4d3 \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_ACCESSIBILITY_LIST_REMOVE_BUTTON.png.sha1 b/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_ACCESSIBILITY_LIST_REMOVE_BUTTON.png.sha1
new file mode 100644
index 00000000000..34436f5a30a
--- /dev/null
+++ b/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_ACCESSIBILITY_LIST_REMOVE_BUTTON.png.sha1
@@ -0,0 +1 @@
+fb46d0712ac318b9074ae28a55f315f46c6e214a \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_ACCESSIBILITY_TAB_SWITCHER_SUMMARY.png.sha1 b/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_ACCESSIBILITY_TAB_SWITCHER_SUMMARY.png.sha1
new file mode 100644
index 00000000000..5fdbaa0be39
--- /dev/null
+++ b/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_ACCESSIBILITY_TAB_SWITCHER_SUMMARY.png.sha1
@@ -0,0 +1 @@
+6cbcf47beee0c66ac1c4a3d7b28bff16464457a1 \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_ACCESSIBILITY_TAB_SWITCHER_TITLE.png.sha1 b/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_ACCESSIBILITY_TAB_SWITCHER_TITLE.png.sha1
new file mode 100644
index 00000000000..433f68cdb8a
--- /dev/null
+++ b/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_ACCESSIBILITY_TAB_SWITCHER_TITLE.png.sha1
@@ -0,0 +1 @@
+ef7969ff56c980a729507dafa20ba40b7be0a4d3 \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_CHIP_REMOVE_ICON_CONTENT_DESCRIPTION.png.sha1 b/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_CHIP_REMOVE_ICON_CONTENT_DESCRIPTION.png.sha1
new file mode 100644
index 00000000000..b762fa1efbc
--- /dev/null
+++ b/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_CHIP_REMOVE_ICON_CONTENT_DESCRIPTION.png.sha1
@@ -0,0 +1 @@
+86c9383d64ab3b866b2d9be57bba73266ae54543 \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_FONT_SIZE.png.sha1 b/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_FONT_SIZE.png.sha1
new file mode 100644
index 00000000000..433f68cdb8a
--- /dev/null
+++ b/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_FONT_SIZE.png.sha1
@@ -0,0 +1 @@
+ef7969ff56c980a729507dafa20ba40b7be0a4d3 \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_FONT_SIZE_PREVIEW_TEXT.png.sha1 b/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_FONT_SIZE_PREVIEW_TEXT.png.sha1
new file mode 100644
index 00000000000..433f68cdb8a
--- /dev/null
+++ b/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_FONT_SIZE_PREVIEW_TEXT.png.sha1
@@ -0,0 +1 @@
+ef7969ff56c980a729507dafa20ba40b7be0a4d3 \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_FORCE_ENABLE_ZOOM_SUMMARY.png.sha1 b/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_FORCE_ENABLE_ZOOM_SUMMARY.png.sha1
new file mode 100644
index 00000000000..433f68cdb8a
--- /dev/null
+++ b/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_FORCE_ENABLE_ZOOM_SUMMARY.png.sha1
@@ -0,0 +1 @@
+ef7969ff56c980a729507dafa20ba40b7be0a4d3 \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_FORCE_ENABLE_ZOOM_TITLE.png.sha1 b/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_FORCE_ENABLE_ZOOM_TITLE.png.sha1
new file mode 100644
index 00000000000..433f68cdb8a
--- /dev/null
+++ b/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_FORCE_ENABLE_ZOOM_TITLE.png.sha1
@@ -0,0 +1 @@
+ef7969ff56c980a729507dafa20ba40b7be0a4d3 \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_AD_PERSONALIZATION_DESCRIPTION.png.sha1 b/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_AD_PERSONALIZATION_DESCRIPTION.png.sha1
new file mode 100644
index 00000000000..e17e0e12203
--- /dev/null
+++ b/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_AD_PERSONALIZATION_DESCRIPTION.png.sha1
@@ -0,0 +1 @@
+4a3e07901714f9a71692a964b0c914a945493f87 \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_INFO_ABOUT_THIS_SITE_TITLE.png.sha1 b/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_INFO_ABOUT_THIS_SITE_TITLE.png.sha1
index d274e8b859f..cf0d5cdd3bd 100644
--- a/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_INFO_ABOUT_THIS_SITE_TITLE.png.sha1
+++ b/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_INFO_ABOUT_THIS_SITE_TITLE.png.sha1
@@ -1 +1 @@
-93cd354e212b4d406084a108f160f1e6e50f0e32 \ No newline at end of file
+615c239640a2d400f684595cfdfe5716b11e8417 \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_INFO_AD_MANAGE_INTERESTS.png.sha1 b/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_INFO_AD_MANAGE_INTERESTS.png.sha1
new file mode 100644
index 00000000000..3876ce87ac5
--- /dev/null
+++ b/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_INFO_AD_MANAGE_INTERESTS.png.sha1
@@ -0,0 +1 @@
+e56f9dbd2936731b58a10b00fff9a5b7a9e0c791 \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_INFO_AD_PERSONALIZATION_TITLE.png.sha1 b/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_INFO_AD_PERSONALIZATION_TITLE.png.sha1
new file mode 100644
index 00000000000..3876ce87ac5
--- /dev/null
+++ b/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PAGE_INFO_AD_PERSONALIZATION_TITLE.png.sha1
@@ -0,0 +1 @@
+e56f9dbd2936731b58a10b00fff9a5b7a9e0c791 \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PREFS_ACCESSIBILITY.png.sha1 b/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PREFS_ACCESSIBILITY.png.sha1
new file mode 100644
index 00000000000..433f68cdb8a
--- /dev/null
+++ b/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_PREFS_ACCESSIBILITY.png.sha1
@@ -0,0 +1 @@
+ef7969ff56c980a729507dafa20ba40b7be0a4d3 \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_READER_FOR_ACCESSIBILITY_SUMMARY.png.sha1 b/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_READER_FOR_ACCESSIBILITY_SUMMARY.png.sha1
new file mode 100644
index 00000000000..433f68cdb8a
--- /dev/null
+++ b/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_READER_FOR_ACCESSIBILITY_SUMMARY.png.sha1
@@ -0,0 +1 @@
+ef7969ff56c980a729507dafa20ba40b7be0a4d3 \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_READER_FOR_ACCESSIBILITY_TITLE.png.sha1 b/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_READER_FOR_ACCESSIBILITY_TITLE.png.sha1
new file mode 100644
index 00000000000..433f68cdb8a
--- /dev/null
+++ b/chromium/components/browser_ui/strings/android/browser_ui_strings_grd/IDS_READER_FOR_ACCESSIBILITY_TITLE.png.sha1
@@ -0,0 +1 @@
+ef7969ff56c980a729507dafa20ba40b7be0a4d3 \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/site_settings.grdp b/chromium/components/browser_ui/strings/android/site_settings.grdp
index 40c7b8d138a..a7fa1724fed 100644
--- a/chromium/components/browser_ui/strings/android/site_settings.grdp
+++ b/chromium/components/browser_ui/strings/android/site_settings.grdp
@@ -429,10 +429,10 @@
<!-- NFC -->
<message name="IDS_WEBSITE_SETTINGS_CATEGORY_NFC_ASK" desc="Summary text explaining that sites need to ask for permission before using NFC and that it is the recommended setting.">
- Ask before allowing sites to send and receive info when you tap NFC devices (recommended)
+ Ask before allowing sites to see and change information on NFC devices (recommended)
</message>
<message name="IDS_WEBSITE_SETTINGS_CATEGORY_NFC_BLOCKED" desc="Summary text explaining that sites are blocked from using NFC.">
- Block sites from sending and receiving info when you tap NFC devices
+ Block sites from seeing and changing information on NFC devices
</message>
<message name="IDS_ANDROID_NFC_OFF_GLOBALLY" desc="The message to show when NFC has been turned off globally in Android. Contains a link to the settings menu to enable NFC.">
NFC is off for this device. Turn it on in <ph name="BEGIN_LINK">&lt;link&gt;</ph>Android Settings<ph name="END_LINK">&lt;/link&gt;</ph>.
diff --git a/chromium/components/browser_ui/strings/android/site_settings_grdp/IDS_WEBSITE_SETTINGS_CATEGORY_NFC_ASK.png.sha1 b/chromium/components/browser_ui/strings/android/site_settings_grdp/IDS_WEBSITE_SETTINGS_CATEGORY_NFC_ASK.png.sha1
index aa1a3778e9a..df9baf01150 100644
--- a/chromium/components/browser_ui/strings/android/site_settings_grdp/IDS_WEBSITE_SETTINGS_CATEGORY_NFC_ASK.png.sha1
+++ b/chromium/components/browser_ui/strings/android/site_settings_grdp/IDS_WEBSITE_SETTINGS_CATEGORY_NFC_ASK.png.sha1
@@ -1 +1 @@
-dcc70d2f161b724d0f133f61f351960266fced6a \ No newline at end of file
+2ec976dd4379fee74a7c224bfc8e78d752533cf5 \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/site_settings_grdp/IDS_WEBSITE_SETTINGS_CATEGORY_NFC_BLOCKED.png.sha1 b/chromium/components/browser_ui/strings/android/site_settings_grdp/IDS_WEBSITE_SETTINGS_CATEGORY_NFC_BLOCKED.png.sha1
index 0063cff8d5a..63a6cf002bc 100644
--- a/chromium/components/browser_ui/strings/android/site_settings_grdp/IDS_WEBSITE_SETTINGS_CATEGORY_NFC_BLOCKED.png.sha1
+++ b/chromium/components/browser_ui/strings/android/site_settings_grdp/IDS_WEBSITE_SETTINGS_CATEGORY_NFC_BLOCKED.png.sha1
@@ -1 +1 @@
-79a40a1cc62f30a32d18ca40f74761f7064d241d \ No newline at end of file
+c8c6d87c19a6438fddc588e6d51870096a51a108 \ No newline at end of file
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_af.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_af.xtb
index 1cf08e07279..5eb796304c1 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_af.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_af.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">Werf <ph name="SITE_NAME" /> bygevoeg</translation>
<translation id="1383876407941801731">Soek</translation>
<translation id="1384959399684842514">Aflaai is onderbreek</translation>
+<translation id="1409426117486808224">Vereenvoudigde aansig vir oop oortjies</translation>
<translation id="1415402041810619267">URL is afgekap</translation>
<translation id="1446450296470737166">Laat vol MIDI-toestelbeheer toe</translation>
<translation id="1620510694547887537">Kamera</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">Laat webkoekies toe</translation>
<translation id="2228071138934252756">Om <ph name="APP_NAME" /> toegang tot jou kamera te gee, moet jy kamera ook in <ph name="BEGIN_LINK" />Android-instellings<ph name="END_LINK" /> aanskakel.</translation>
<translation id="2241634353105152135">Net een keer</translation>
+<translation id="2253414712144136228"><ph name="NAME_OF_LIST_ITEM" /> Verwyder</translation>
<translation id="2289270750774289114">Vra wanneer 'n werf Bluetooth-toestelle in die omtrek wil ontdek (aanbeveel)</translation>
<translation id="2315043854645842844">Bedryfstelsel steun nie die sertifikaat wat die kliënt gekies het nie.</translation>
+<translation id="2321958826496381788">Trek die glyer totdat jy dit gemaklik kan lees. Teks behoort minstens só groot te lyk nadat jy op 'n paragraaf gedubbeltik het.</translation>
<translation id="2359808026110333948">Gaan voort</translation>
<translation id="2379925928934107488">Pas donkertema op werwe toe wanneer Chrome donkertema gebruik, indien moontlik</translation>
+<translation id="2387895666653383613">Verander teksgrootte</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> en nog <ph name="NUM_MORE" /> word toegelaat}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> en nog <ph name="NUM_MORE" /> word toegelaat}}</translation>
<translation id="2434158240863470628">Aflaai is voltooi <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">Wys inligting</translation>
<translation id="3123473560110926937">Geblokkeer op sommige werwe</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> gestoorde data</translation>
+<translation id="3203366800380907218">Op die web</translation>
<translation id="321187648315454507">Om <ph name="APP_NAME" /> vir jou kennisgewings te laat stuur, moet jy kennisgewings ook in <ph name="BEGIN_LINK" />Android-instellings<ph name="END_LINK" /> aanskakel.</translation>
<translation id="3227137524299004712">Mikrofoon</translation>
<translation id="3277252321222022663">Laat werwe toegang tot sensors toe (aanbeveel)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">Jou toestelgebruik</translation>
<translation id="385051799172605136">Terug</translation>
<translation id="3859306556332390985">Soek vorentoe</translation>
+<translation id="3895926599014793903">Dwing aktivering van zoem</translation>
<translation id="3955193568934677022">Laat werwe toe om beskermde inhoud te speel (aanbeveel)</translation>
<translation id="3967822245660637423">Aflaai is voltooi</translation>
<translation id="3987993985790029246">Kopieer skakel</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> van ?</translation>
<translation id="4002066346123236978">Titel</translation>
<translation id="4008040567710660924">Laat webkoekies vir 'n spesifieke werf toe.</translation>
+<translation id="4040330681741629921">Word in kennis gestel wanneer ’n werf in vereenvoudigde aansig gewys kan word</translation>
<translation id="4046123991198612571">Volgende snit</translation>
+<translation id="4149994727733219643">Vereenvoudigde aansig vir webbladsye</translation>
<translation id="4165986682804962316">Werfinstellings</translation>
+<translation id="4194328954146351878">Vra voor werwe toegelaat word om inligting op NFC-toestelle te sien en te verander (aanbeveel)</translation>
<translation id="4200726100658658164">Maak ligginginstellings oop</translation>
<translation id="4226663524361240545">Kennisgewings kan die toestel laat vibreer</translation>
<translation id="4259722352634471385">Navigasie is geblokkeer: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">Vou uit</translation>
<translation id="4336434711095810371">Vee alle data uit</translation>
<translation id="4402755511846832236">Keer dat werwe weet wanneer jy hierdie toestel aktief gebruik</translation>
+<translation id="4428065317363009941">Advertensiepersonalisering</translation>
<translation id="4434045419905280838">Opspringers en herleidings</translation>
<translation id="445467742685312942">Laat werwe toe om beskermde inhoud te speel</translation>
<translation id="4468959413250150279">Demp klank vir 'n spesifieke werf.</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">Opsie is naby die bokant van die skerm beskikbaar</translation>
<translation id="5197729504361054390">Die kontakte wat jy kies, sal gedeel word met <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />.</translation>
<translation id="5216942107514965959">Laas vandag besoek</translation>
+<translation id="5264323282659631142">Verwyder "<ph name="CHIP_LABEL" />"</translation>
<translation id="528192093759286357">Sleep van bo af en raak die terugknoppie om volskerm te verlaat.</translation>
<translation id="5300589172476337783">Wys</translation>
<translation id="5301954838959518834">OK, het dit</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">Dit sal <ph name="DATASIZE" /> se data en webkoekies uitvee wat deur werwe geberg is.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(+ nog 1)}other{(+ nog #)}}</translation>
<translation id="5403592356182871684">Name</translation>
+<translation id="5412236728747081950">Hierdie werf kry jou belangstellings van Chrome af om vir jou relevanter advertensies te wys</translation>
<translation id="5438097262470833822">Hierdie keuse sal toestemmings vir <ph name="WEBSITE" /> terugstel</translation>
<translation id="5489227211564503167">Tyd verstreke is <ph name="ELAPSED_TIME" /> van <ph name="TOTAL_TIME" />.</translation>
<translation id="5494752089476963479">Blokkeer advertensies op werwe wat indringerige of misleidende advertensies wys</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">Herlaai</translation>
<translation id="5596627076506792578">Meer opsies</translation>
<translation id="5649053991847567735">Outomatiese aflaaie</translation>
+<translation id="5668404140385795438">Ignoreer 'n webwerf se versoek om inzoem te verhoed</translation>
<translation id="5677928146339483299">Geblokkeer</translation>
<translation id="5689516760719285838">Ligging</translation>
<translation id="5690795753582697420">Kamera is afgeskakel in Android-instellings</translation>
-<translation id="5710871682236653961">Vra voordat jy werwe toelaat om inligting te stuur en te ontvang wanneer jy op NFC-toestelle tik (aanbeveel)</translation>
<translation id="5719847187258001597">Dit sal alle data en webkoekies uitvee wat deur <ph name="ORIGIN" /> of deur sy program op jou tuisskerm geberg is.</translation>
<translation id="5771720122942595109"><ph name="PERMISSION_1" /> word geblokkeer</translation>
<translation id="5804241973901381774">Toestemmings</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">Speel</translation>
<translation id="6818926723028410516">Kies items</translation>
<translation id="6864395892908308021">Hierdie toestel kan nie NFC lees nie</translation>
-<translation id="6910211073230771657">Uitgevee</translation>
<translation id="6912998170423641340">Blokkeer werwe om teks en prente van die knipbord af te lees</translation>
<translation id="6945221475159498467">Kies</translation>
<translation id="6965382102122355670">OK</translation>
+<translation id="6981982820502123353">Toeganklikheid</translation>
<translation id="6992289844737586249">Vra eers voordat werwe toegelaat word om jou mikrofoon te gebruik (aanbeveel)</translation>
<translation id="7000754031042624318">Afgeskakel in Android-instellings</translation>
<translation id="7016516562562142042">Toegelaat vir huidige soekenjin</translation>
+<translation id="702463548815491781">Aanbeveel wanneer TalkBack of Skakelaartoegang aan is</translation>
<translation id="7053983685419859001">Blokkeer</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1 gekies}other{# gekies}}</translation>
-<translation id="7070090581017165256">Meer oor hierdie werf</translation>
<translation id="7087918508125750058"><ph name="ITEM_COUNT" /> gekies. Opsies is naby aan die bokant van die skerm beskikbaar</translation>
<translation id="7141896414559753902">Verhinder werwe om opspringers en herleidings te wys (aanbeveel)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> KB</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">'n Werf gebruik tans jou mikrofoon</translation>
<translation id="7561196759112975576">Altyd</translation>
-<translation id="7572498721684305250">Blokkeer werwe om inligting te stuur en te ontvang wanneer jy op NFC-toestelle tik</translation>
<translation id="757524316907819857">Blokkeer werwe om beskermde inhoud te speel</translation>
+<translation id="7577900504646297215">Bestuur belangstellings</translation>
<translation id="7649070708921625228">Hulp</translation>
<translation id="7658239707568436148">Kanselleer</translation>
<translation id="7781829728241885113">Gister</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">Verbinding is veilig</translation>
<translation id="8249310407154411074">Skuif na bo</translation>
<translation id="8261506727792406068">Vee uit</translation>
+<translation id="8284326494547611709">Onderskrifte</translation>
<translation id="8300705686683892304">Bestuur deur program</translation>
<translation id="8324158725704657629">Moenie weer vra nie</translation>
<translation id="8372893542064058268">Laat agtergrondsinkronisering vir 'n spesifieke werf toe.</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">Zoem in</translation>
<translation id="8921772741368021346"><ph name="POSITION" /> / <ph name="DURATION" /></translation>
<translation id="8926666909099850184">NFC is af vir hierdie toestel. Skakel dit aan in <ph name="BEGIN_LINK" />Android-instellings<ph name="END_LINK" />.</translation>
+<translation id="8928445016601307354">Blokkeer werwe om inligting op NFC-toestelle te sien en te verander</translation>
<translation id="8941729603749328384">www.voorbeeld.com</translation>
<translation id="8958424370300090006">Blokkeer webkoekies vir 'n spesifieke werf.</translation>
<translation id="8959122750345127698">Navigasie is onbereikbaar: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_am.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_am.xtb
index 890ac6bb78d..95e8dd9a977 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_am.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_am.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676"><ph name="SITE_NAME" /> ጣቢያ ተክáˆáˆ</translation>
<translation id="1383876407941801731">áለጋ </translation>
<translation id="1384959399684842514">የሚወርደዠላáታ ቆሟáˆ</translation>
+<translation id="1409426117486808224">ለክáት ትሮች የተቃለለ እይታ</translation>
<translation id="1415402041810619267">ዩአርኤሠእንዲያጥር ተደርጓáˆ</translation>
<translation id="1446450296470737166">ሙሉ የMIDI መሣሪያዎች መቆጣጠርን ያስችላáˆ</translation>
<translation id="1620510694547887537">ካሜራ</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">ኩኪዎችን áቀድ</translation>
<translation id="2228071138934252756">የእርስዎን ካሜራ <ph name="APP_NAME" /> እንዲደርስበት ለማድረáŒá£ በ <ph name="BEGIN_LINK" />Android ቅንብሮች<ph name="END_LINK" /> á‹áˆµáŒ¥ ካሜራን በተጨማሪ ያብሩá¢</translation>
<translation id="2241634353105152135">አንድ ጊዜ ብቻ</translation>
+<translation id="2253414712144136228"><ph name="NAME_OF_LIST_ITEM" />ን አስወáŒá‹µ</translation>
<translation id="2289270750774289114">አንድ ጣቢያ በአቅራቢያ ያሉ ብሉቱዠመሣሪያዎችን áˆáˆáŒŽ ለማáŒáŠ˜á‰µ ሲáˆáˆáŒ ጠይቅ (የሚመከር)</translation>
<translation id="2315043854645842844">የደንበኛ ወገን á‹•á‹á‰…ና ማረጋገጫ áˆáˆ­áŒ« በስርዓተ-ክወናዠአይደገááˆá¢</translation>
+<translation id="2321958826496381788">ይህን በሚመች áˆáŠ”ታ ማንበብ እስኪችሉ ድረስ ተንሸራታቹን ይጎትቱትᢠበአንድ አንቀጽ ላይ áˆáˆˆá‰´ መታ ካደረጉ በኋላ ጽሑá ቢያንስ የዚህ ያህሠትáˆá‰€á‰µ ሊኖረዠይገባáˆá¢</translation>
<translation id="2359808026110333948">ቀጥáˆ</translation>
<translation id="2379925928934107488">በሚቻáˆá‰ á‰µ ጊዜ Chrome ጠቆር ያለ ገጽታ ሲጠቀሠጠቆር ያለ ገጽታን ጣቢያዎች ላይ ተáŒá‰¥áˆ­</translation>
+<translation id="2387895666653383613">የጽሑá áˆáŠ¬á‰µ</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> ሜባ</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />ᣠ<ph name="PERMISSION_2" />ᣠእና <ph name="NUM_MORE" /> ተጨማሪ ተáˆá‰…á‹°á‹‹áˆ}one{<ph name="PERMISSION_1" />ᣠ<ph name="PERMISSION_2" /> እና <ph name="NUM_MORE" /> ተጨማሪ ተáˆá‰…á‹°á‹‹áˆ}other{<ph name="PERMISSION_1" />ᣠ<ph name="PERMISSION_2" /> እና <ph name="NUM_MORE" /> ተጨማሪ ተáˆá‰…á‹°á‹‹áˆ}}</translation>
<translation id="2434158240863470628">ማá‹áˆ¨á‹µ ተጠናቅቋሠ<ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">መረጃ አሳይ</translation>
<translation id="3123473560110926937">በአንዳንድ ጣቢያዎች ላይ ታáŒá‹·áˆ</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> የተከማቸ á‹áˆ‚ብ</translation>
+<translation id="3203366800380907218">ከድሩ</translation>
<translation id="321187648315454507"><ph name="APP_NAME" /> ማሳወቂያዎችን እንዲáˆáŠ­áˆá‹Žá‰µ ለማድረáŒá£ በተጨማሪ በ <ph name="BEGIN_LINK" />Android ቅንብሮች<ph name="END_LINK" /> á‹áˆµáŒ¥ ማሳወቂያዎችን ያብሩá¢</translation>
<translation id="3227137524299004712">ማይክሮáŽáŠ•</translation>
<translation id="3277252321222022663">ጣቢያዎች ዳሳሾችን እንዲደርሱ á‹­áቀዱላቸዠ(የሚመከር)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">የእርስዎ መሣሪያ አጠቃቀáˆ</translation>
<translation id="385051799172605136">ተመለስ</translation>
<translation id="3859306556332390985">ወደáŠá‰µ áˆáˆáŒ</translation>
+<translation id="3895926599014793903">ማጉላት አንቃን ያስገድዱ</translation>
<translation id="3955193568934677022">ጥበቃ የሚደረáŒá‰ á‰µáŠ• ይዘት እንዲያጫá‹á‰± ለጣቢያዎች áቀድ (የሚመከር)</translation>
<translation id="3967822245660637423">ማá‹áˆ¨á‹µ ተጠናቅቋáˆ</translation>
<translation id="3987993985790029246">አገናአቅዳ</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> / ?</translation>
<translation id="4002066346123236978">ርዕስ</translation>
<translation id="4008040567710660924">የተወሰአጣቢያ ኩኪዎችን áቀድá¢</translation>
+<translation id="4040330681741629921">አንድ ጣቢያ ቀላሠበሆአእይታ á‹áˆµáŒ¥ መታየት ሲችሠማሳወቂያ á‹«áŒáŠ™</translation>
<translation id="4046123991198612571">ቀጣይ ትራክ</translation>
+<translation id="4149994727733219643">ለድረ-ገጾች የተቃለለ እይታ</translation>
<translation id="4165986682804962316">የጣቢያ ቅንብሮች</translation>
+<translation id="4194328954146351878">ጣቢያዎች በኤንኤáሲ መሣሪያዎች ላይ መረጃ እንዲያዩ እና እንዲቀይሩ ከመáˆá‰€á‹± በáŠá‰µ ይጠይቅ (የሚመከር)</translation>
<translation id="4200726100658658164">የአካባቢ ቅንብሮችን ክáˆá‰µ</translation>
<translation id="4226663524361240545">ማሳወቂያዎች መሣሪያá‹áŠ• እንዲáŠá‹áˆ­ ሊያደርጉት ይችላሉ</translation>
<translation id="4259722352634471385">ዳሰሳ ታáŒá‹·áˆá¦ <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">ዘርጋ</translation>
<translation id="4336434711095810371">áˆáˆ‰áŠ•áˆ á‹áˆ‚ብ አጽዳ</translation>
<translation id="4402755511846832236">እርስዎ ይህን መሣሪያ በንቃት ሲጠቀሙ ጣቢያዎች እንዳያá‹á‰ á‹«áŒá‹±</translation>
+<translation id="4428065317363009941">ማስታወቂያን áŒáˆ‹á‹ŠáŠá‰µ ማላበስ</translation>
<translation id="4434045419905280838">ብቅ-ባዮች እና አቅጣጫ ማዞሮች</translation>
<translation id="445467742685312942">ጣቢያዎች የተጠበቀ ይዘትን እንዲያጫá‹á‰µ á‹­áቀዱ</translation>
<translation id="4468959413250150279">በአንድ የተወሰአጣቢያ ላይ ድáˆáŒ¸-ከሠአድርáŒá¢</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">አማራጮች ከማያ ገጹ አናት አጠገብ ይገኛሉ</translation>
<translation id="5197729504361054390">የመረጧቸዠእá‹á‰‚ያዎች ለ<ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ይጋራሉá¢</translation>
<translation id="5216942107514965959">መጨረሻ የተጎበኘዠዛሬ</translation>
+<translation id="5264323282659631142">«<ph name="CHIP_LABEL" />»ን ያስወáŒá‹±</translation>
<translation id="528192093759286357">ከሙሉ ማያ ገጽ ለመá‹áŒ£á‰µ ከላይ ይጎትቱ እና የተመለስ አá‹áˆ«áˆ©áŠ• ይንኩá¢</translation>
<translation id="5300589172476337783">አሳይ</translation>
<translation id="5301954838959518834">እሺᣠገባáŠ</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">ይህ በጣቢያዎች የተከማቹ <ph name="DATASIZE" /> á‹áˆ‚ብ እና ኩኪዎችን ያጸዳáˆá¢</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(+ 1 ተጨማሪ)}one{(+ # ተጨማሪ)}other{(+ # ተጨማሪ)}}</translation>
<translation id="5403592356182871684">ስሞች</translation>
+<translation id="5412236728747081950">ይህ ጣቢያ ይበáˆáŒ¥ አáŒá‰£á‰¥áŠá‰µ ያላቸá‹áŠ• ማስታወቂያዎች ለእርስዎ ለማሳየት የእርስዎን á‹áŠ•á‰£áˆŒá‹Žá‰½ ከChrome ያገኛáˆ</translation>
<translation id="5438097262470833822">ይህ áˆáˆ­áŒ« áˆá‰ƒá‹¶á‰½áŠ• ለ<ph name="WEBSITE" /> ዳáŒáˆ ያስጀáˆáˆ«áˆ</translation>
<translation id="5489227211564503167">የጠá‹á‹ ጊዜ <ph name="ELAPSED_TIME" /> ከ<ph name="TOTAL_TIME" />á¢</translation>
<translation id="5494752089476963479">ረባሽ ወይሠአሳሳች ማስታወቂያዎችን ከሚያሳዩ ጣቢያዎች የሚመጡ ማስታወቂያዎችን አáŒá‹µ</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">ዳáŒáˆ ጫን</translation>
<translation id="5596627076506792578">ተጨማሪ አማራጮች</translation>
<translation id="5649053991847567735">ራስ-ሰር á‹áˆ­á‹¶á‰½</translation>
+<translation id="5668404140385795438">የአንድ ድር ጣቢያ ማጉላትን መከáˆáŠ¨áˆ ጥያቄ ሻር</translation>
<translation id="5677928146339483299">ታáŒá‹·áˆ</translation>
<translation id="5689516760719285838">አካባቢ</translation>
<translation id="5690795753582697420">ካሜራ በAndroid ቅንብሮች á‹áˆµáŒ¥ ጠáቷáˆ</translation>
-<translation id="5710871682236653961">የNFC መሣሪያዎችን መታ ሲያደርጉ ጣቢያዎች መረጃን እንዲáˆáŠ© እና እንዲቀበሉ ከመáቀድዎ በáŠá‰µ ይጠይበ(የሚመከር)</translation>
<translation id="5719847187258001597">ይህ በ<ph name="ORIGIN" /> ወይሠበመáŠáˆ» ገጽዎ ላይ በመተáŒá‰ áˆªá‹«á‹ የተከማቹ áˆáˆ‰áŠ•áˆ á‹áˆ‚ብ እና ኩኪዎች ያጸዳáˆá¢</translation>
<translation id="5771720122942595109"><ph name="PERMISSION_1" /> ታáŒá‹·áˆ</translation>
<translation id="5804241973901381774">áቃዶች</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">አጫá‹á‰µ</translation>
<translation id="6818926723028410516">ንጥሎችን á‹­áˆáˆ¨áŒ¡</translation>
<translation id="6864395892908308021">ይህ መሣሪያ NFCን ማንበብ አይችáˆáˆ</translation>
-<translation id="6910211073230771657">ተሰርዟáˆ</translation>
<translation id="6912998170423641340">ጣቢያዎች ከቅንጥብ ሰሌዳ ጽሑáን እና áˆáˆµáˆŽá‰½áŠ• እንዳያáŠá‰¥á‰¡ አáŒá‹µ</translation>
<translation id="6945221475159498467">á‹­áˆáˆ¨áŒ¡</translation>
<translation id="6965382102122355670">እሺ</translation>
+<translation id="6981982820502123353">ተደራሽáŠá‰µ</translation>
<translation id="6992289844737586249">ጣቢያዎች ማይክሮáŽáŠ•á‹ŽáŠ• እንዲጠቀሙ ከመáቀድዎ በáŠá‰µ ይጠይቅ (የሚመከር)</translation>
<translation id="7000754031042624318">በAndroid ቅንብሮች á‹áˆµáŒ¥ ጠáቷáˆ</translation>
<translation id="7016516562562142042">ለአáˆáŠ‘ የáለጋ á•áˆ®áŒáˆ«áˆ ተáˆá‰…á‹·áˆ</translation>
+<translation id="702463548815491781">TalkBack ወይሠመዳረሻ ቀይር ሲበሩ የሚመከር</translation>
<translation id="7053983685419859001">አáŒá‹µ</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1 ተመርጧáˆ}one{# ተመርጠዋáˆ}other{# ተመርጠዋáˆ}}</translation>
-<translation id="7070090581017165256">ስለዚህ ጣቢያ</translation>
<translation id="7087918508125750058"><ph name="ITEM_COUNT" /> ተመርጠዋáˆá¢ አማራጮች ከማያ ገጹ አናት አጠገብ ይገኛሉ</translation>
<translation id="7141896414559753902">ጣቢያዎች ብቅ-ባዮችን እንዳያሳዩ á‹«áŒá‹± (የሚመከር)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> ኪባ</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">ጃቫስክሪá•á‰µ</translation>
<translation id="7554752735887601236">አንድ ጣቢያ የእርስዎን ማይክሮáŽáŠ• እየተጠቀመ áŠá‹</translation>
<translation id="7561196759112975576">áˆáˆáŒŠá‹œ</translation>
-<translation id="7572498721684305250">የNFC መሣሪያዎችን መታ ሲያደርጉ ጣቢያዎች መረጃን እንዳይáˆáŠ© እና እንዳይቀበሉ á‹«áŒá‹·á‰¸á‹</translation>
<translation id="757524316907819857">ጣቢያዎች ጥበቃ የሚደረáŒáˆˆá‰µáŠ• ይዘት እንዳያጫá‹á‰± á‹«áŒá‹±</translation>
+<translation id="7577900504646297215">áላጎቶችን አቀናብር</translation>
<translation id="7649070708921625228">እገዛ</translation>
<translation id="7658239707568436148">ይቅር</translation>
<translation id="7781829728241885113">ትናንት</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">áŒáŠ•áŠ™áŠá‰µ ደኅንáŠá‰± የተጠበቀ áŠá‹</translation>
<translation id="8249310407154411074">ወደ ላይ á‹áˆ°á‹µ</translation>
<translation id="8261506727792406068">ሰርá‹</translation>
+<translation id="8284326494547611709">መáŒáˆˆáŒ« ጽሑáŽá‰½</translation>
<translation id="8300705686683892304">በመተáŒá‰ áˆªá‹« የሚተዳደር</translation>
<translation id="8324158725704657629">ዳáŒáˆ አትጠይቅ</translation>
<translation id="8372893542064058268">ለአንድ የተወሰአጣቢያ የጀርባ ስáˆáˆ¨á‰µáŠ• á‹­áቀዱá¢</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">አጉላ</translation>
<translation id="8921772741368021346"><ph name="POSITION" /> / <ph name="DURATION" /></translation>
<translation id="8926666909099850184">NFC ለዚህ መሣሪያ ጠáቷáˆá¢ በ<ph name="BEGIN_LINK" />Android ቅንበሮች<ph name="END_LINK" /> á‹áˆµáŒ¥ ያብሩትá¢</translation>
+<translation id="8928445016601307354">ጣቢያዎች በኤንኤáሲ መሣሪያዎች ላይ መረጃን እንዳያዩ እና እንዳይቀይሩ á‹«áŒá‹±</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">የአንድ የተወሰአጣቢያ ኩኪዎችን á‹«áŒá‹±á¢</translation>
<translation id="8959122750345127698">ዳሰሳ ሊደረስበት አይችáˆáˆá¦ <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ar.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ar.xtb
index 6cee9a33fd6..ca9011febe1 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ar.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ar.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">تمت إضاÙØ© الموقع <ph name="SITE_NAME" /></translation>
<translation id="1383876407941801731">البحث</translation>
<translation id="1384959399684842514">تم إيقا٠التنزيل مؤقتًا</translation>
+<translation id="1409426117486808224">عرض مبسَّط لعلامات التبويب المÙتوحة</translation>
<translation id="1415402041810619267">â€ØªÙ… اقتطاع عنوان URL</translation>
<translation id="1446450296470737166">â€Ø§Ù„سماح بالتحكم الكامل لأجهزة MIDI</translation>
<translation id="1620510694547887537">الكاميرا</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">السماح بملÙات تعري٠الارتباط</translation>
<translation id="2228071138934252756">â€Ù„لسماح لتطبيق <ph name="APP_NAME" /> بالوصول إلى الكاميرا، ÙŠÙرجى أيضًا تÙعيل الكاميرا ÙÙŠ <ph name="BEGIN_LINK" />إعدادات Android<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">مرة واحدة Ùقط</translation>
+<translation id="2253414712144136228">إزالة <ph name="NAME_OF_LIST_ITEM" /></translation>
<translation id="2289270750774289114">طلب الإذن عند محاولة موقع إلكتروني العثور على أجهزة البلوتوث المجاورة (إجراء موصَى به)</translation>
<translation id="2315043854645842844">لا يدعم نظام التشغيل تحديد الشهادة من جانب العميل.</translation>
+<translation id="2321958826496381788">اسحب شريط التمرير إلى أن تتمكّن من قراءة هذا النص بسهولة. يجب أن يظهر النص بهذا الحجم على الأقل بعد النقر مرّتين على أي Ùقرة.</translation>
<translation id="2359808026110333948">متابعة</translation>
<translation id="2379925928934107488">â€ÙŠÙ…كنك تطبيق "المظهر الداكن" على المواقع الإلكترونية عندما يستخدم Chrome "المظهر الداكن"ØŒ إن أمكن ذلك.</translation>
+<translation id="2387895666653383613">تغيير حجم النص</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> ميغابايت</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{تم السماح بالوصول إلى <ph name="PERMISSION_1" /> و<ph name="PERMISSION_2" /> وإذن واحد (<ph name="NUM_MORE" />) آخر.}zero{تم السماح بالوصول إلى <ph name="PERMISSION_1" /> و<ph name="PERMISSION_2" /> و<ph name="NUM_MORE" /> إذن آخر.}two{تم السماح بالوصول إلى <ph name="PERMISSION_1" /> و<ph name="PERMISSION_2" /> وإذنَين (<ph name="NUM_MORE" />) آخرَين.}few{تم السماح بالوصول إلى <ph name="PERMISSION_1" /> و<ph name="PERMISSION_2" /> و<ph name="NUM_MORE" /> أذونات أخرى.}many{تم السماح بالوصول إلى <ph name="PERMISSION_1" /> و<ph name="PERMISSION_2" /> و<ph name="NUM_MORE" /> إذنًا آخر.}other{تم السماح بالوصول إلى <ph name="PERMISSION_1" /> و<ph name="PERMISSION_2" /> و<ph name="NUM_MORE" /> إذن آخر.}}</translation>
<translation id="2434158240863470628">اكتمل التنزيل <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -60,7 +64,7 @@
<translation id="2482878487686419369">الإشعارات</translation>
<translation id="2485422356828889247">إزالة التثبيت</translation>
<translation id="2490684707762498678">تتم إدارتها من خلال <ph name="APP_NAME" /></translation>
-<translation id="2498359688066513246">المساعدة والتعليقات</translation>
+<translation id="2498359688066513246">المساعدة والملاحظات</translation>
<translation id="2501278716633472235">الرجوع</translation>
<translation id="2569468611847789653">{COOKIE_COUNT,plural, =1{تم حظر مل٠تعري٠ارتباط واحد.}zero{تم حظر # مل٠تعري٠ارتباط.}two{تم حظر ملÙَّي تعري٠ارتباط.}few{تم حظر # ملÙات تعري٠ارتباط.}many{تم حظر # مل٠تعري٠ارتباط.}other{تم حظر # مل٠تعري٠ارتباط.}}</translation>
<translation id="2570922361219980984">â€Ø§Ù„وصول إلى الموقع الجغراÙÙŠ متوق٠لهذا الجهاز أيضًا. يمكنك تÙعليه ÙÙŠ <ph name="BEGIN_LINK" />إعدادات Android<ph name="END_LINK" />.</translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">عرض المعلومات</translation>
<translation id="3123473560110926937">حظر الإعلانات ÙÙŠ بعض المواقع</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> من البيانات المخزّنة</translation>
+<translation id="3203366800380907218">من الويب</translation>
<translation id="321187648315454507">â€Ù„لسماح لتطبيق <ph name="APP_NAME" /> بإرسال الإشعارات إليك، ÙŠÙرجى أيضًا تÙعيل الإشعارات ÙÙŠ <ph name="BEGIN_LINK" />إعدادات Android<ph name="END_LINK" />.</translation>
<translation id="3227137524299004712">الميكروÙون</translation>
<translation id="3277252321222022663">يمكنك السماح للمواقع بالوصول إلى أجهزة الاستشعار (Ù…Ùقترَح).</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">استخدامك للجهاز</translation>
<translation id="385051799172605136">رجوع</translation>
<translation id="3859306556332390985">الانتقال للأمام</translation>
+<translation id="3895926599014793903">Ùرض تÙعيل التكبير أو التصغير</translation>
<translation id="3955193568934677022">السماح للمواقع الإلكترونية بتشغيل المحتوى المحمي (Ù…Ùستحسَن)</translation>
<translation id="3967822245660637423">اكتمل التنزيل</translation>
<translation id="3987993985790029246">نسخ الرابط</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> / ?</translation>
<translation id="4002066346123236978">العنوان</translation>
<translation id="4008040567710660924">السماح لموقع إلكتروني معيّن بتشغيل ملÙات تعري٠الارتباط</translation>
+<translation id="4040330681741629921">تلقّي إشعارات ÙÙŠ حال كان خيار العرض المبسَّط متاحًا لموقع إلكتروني</translation>
<translation id="4046123991198612571">المقطع الصوتي التالي</translation>
+<translation id="4149994727733219643">عرض مبسَّط لصÙحات الويب</translation>
<translation id="4165986682804962316">إعدادات المواقع الإلكترونية</translation>
+<translation id="4194328954146351878">â€ÙŠØªÙ… طلب الإذن قبل السماح للمواقع الإلكترونية بالاطّلاع على المعلومات وتعديلها على الأجهزة المزوَّدة بتقنية NFC (إعداد Ù…Ùقترَح).</translation>
<translation id="4200726100658658164">Ùتح إعدادات الموقع الجغراÙÙŠ</translation>
<translation id="4226663524361240545">يمكن أن تؤدي الإشعارات إلى اهتزاز الجهاز</translation>
<translation id="4259722352634471385">التنقل محظور: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">توسيع</translation>
<translation id="4336434711095810371">محو جميع البيانات</translation>
<translation id="4402755511846832236">منع المواقع الإلكترونية من رصد استخدامك النشط لهذا الجهاز</translation>
+<translation id="4428065317363009941">تخصيص الإعلانات</translation>
<translation id="4434045419905280838">النواÙØ° المنبثقة وإعادة التوجيه</translation>
<translation id="445467742685312942">السماح للمواقع الإلكترونية بتشغيل المحتوى المَحمي</translation>
<translation id="4468959413250150279">كتم صوت موقع إلكتروني معين.</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">يمكنك العثور على خيار Ø­Ùظ كلمة المرور بالقرب من أعلى الشاشة.</translation>
<translation id="5197729504361054390">ستتم مشاركة جهات الاتصال التي تختارها مع الموقع الإلكتروني <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />.</translation>
<translation id="5216942107514965959">تمّت زيارة الموقع الإلكتروني آخر مرّة اليوم.</translation>
+<translation id="5264323282659631142">إزالة شريحة "<ph name="CHIP_LABEL" />"</translation>
<translation id="528192093759286357">اسحب من الجزء العلوي والمس زر الرجوع للخروج من وضع ملء الشاشة.</translation>
<translation id="5300589172476337783">عرض</translation>
<translation id="5301954838959518834">حسنًا</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">سيؤدي هذا الإجراء إلى محو <ph name="DATASIZE" /> من البيانات وملÙات تعري٠الارتباط المÙخزّنة من خلال المواقع الإلكترونية.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(+ 1 آخر)}zero{(+ # آخر)}two{(+ اثنين (#) آخرين)}few{(+ # أخرى)}many{(+ # آخر)}other{(+ # آخر)}}</translation>
<translation id="5403592356182871684">الأسماء</translation>
+<translation id="5412236728747081950">â€ÙŠØªØ¹Ø±Ù‘٠هذا الموقع الإلكتروني على اهتماماتك من خلال متصÙّح Chrome ويعرض لك إعلانات تناسبك أكثر.</translation>
<translation id="5438097262470833822">سيؤدي هذا الخيار إلى إعادة ضبط أذونات الموقع الإلكتروني <ph name="WEBSITE" />.</translation>
<translation id="5489227211564503167">الوقت المنقضي <ph name="ELAPSED_TIME" /> من <ph name="TOTAL_TIME" /></translation>
<translation id="5494752089476963479">حظر الإعلانات ÙÙŠ المواقع الإلكترونية التي تعرض إعلانات مضلّÙلة أو غير مرغوب Ùيها</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">إعادة التحميل</translation>
<translation id="5596627076506792578">خيارات إضاÙية</translation>
<translation id="5649053991847567735">عمليات التنزيل التلقائية</translation>
+<translation id="5668404140385795438">تجاوز طلب الموقع الإلكتروني لمنع التكبير</translation>
<translation id="5677928146339483299">الحظر</translation>
<translation id="5689516760719285838">الموقع الجغراÙÙŠ</translation>
<translation id="5690795753582697420">â€ØªÙ… إيقا٠الكاميرا ÙÙŠ إعدادات Android.</translation>
-<translation id="5710871682236653961">â€Ø§Ù„سؤال قبل السماح للمواقع الإلكترونية بإرسال المعلومات وتلقّيها عند النقر على أجهزة NFC (مستحسن)</translation>
<translation id="5719847187258001597">سيؤدي هذا الإجراء إلى محو جميع البيانات وملÙات تعري٠الارتباط المÙخزّنة من خلال <ph name="ORIGIN" /> أو من خلال التطبيق على الشاشة الرئيسية.</translation>
<translation id="5771720122942595109">تم حظر <ph name="PERMISSION_1" />.</translation>
<translation id="5804241973901381774">الأذونات</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">التشغيل</translation>
<translation id="6818926723028410516">اختيار عناصر</translation>
<translation id="6864395892908308021">â€ÙŠØªØ¹Ø°Ù‘ر على هذا الجهاز قراءة NFC.</translation>
-<translation id="6910211073230771657">تم الحذÙ</translation>
<translation id="6912998170423641340">حظر المواقع الإلكترونية من قراءة الصور والنصوص من الحاÙظة</translation>
<translation id="6945221475159498467">تحديد</translation>
<translation id="6965382102122355670">حسنًا</translation>
+<translation id="6981982820502123353">تسهيل الاستخدام</translation>
<translation id="6992289844737586249">السؤال أولاً قبل السماح للمواقع الإلكترونية باستخدام الميكروÙون (موصى به)</translation>
<translation id="7000754031042624318">â€ØªÙ… إيقاÙÙ‡ ÙÙŠ إعدادات Android.</translation>
<translation id="7016516562562142042">تم منح الإذن لمحرّك البحث الحالي</translation>
+<translation id="702463548815491781">â€ÙŠÙوصى به عند تÙعيل TalkBack أو الوصول عبر Ù…Ùتاح التحويل</translation>
<translation id="7053983685419859001">حظر</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{تم اختيار عنصر واحد}zero{تم اختيار # عنصر}two{تم اختيار عنصرين (#)}few{تم اختيار # عناصر}many{تم اختيار # عنصرًا}other{تم اختيار # عنصر}}</translation>
-<translation id="7070090581017165256">لمحة عن هذا الموقع الإلكتروني</translation>
<translation id="7087918508125750058">تم اختيار <ph name="ITEM_COUNT" /> عنصر، ويمكنك الاطّلاع على الخيارات ÙÙŠ الجزء العلوي من الشاشة.</translation>
<translation id="7141896414559753902">منع المواقع الإلكترونية من عرض النواÙØ° المنبثقة وعمليات إعادة التوجيه (Ù…Ùوصى به)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> كيلوبايت</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">هناك موقع إلكتروني يستخدم الميكروÙون.</translation>
<translation id="7561196759112975576">دومًا</translation>
-<translation id="7572498721684305250">â€Ø­Ø¸Ø± المواقع الإلكترونية من إرسال المعلومات وتلقّيها عند النقر على أجهزة NFC.</translation>
<translation id="757524316907819857">منع المواقع الإلكترونية من تشغيل المحتوى المحمي</translation>
+<translation id="7577900504646297215">إدارة الاهتمامات</translation>
<translation id="7649070708921625228">مساعدة</translation>
<translation id="7658239707568436148">إلغاء</translation>
<translation id="7781829728241885113">أمس</translation>
@@ -285,9 +297,11 @@
<translation id="8197286292360124385">تم السماح بالوصول إلى <ph name="PERMISSION_1" />.</translation>
<translation id="8200772114523450471">استئناÙ</translation>
<translation id="8206354486702514201">تم Ùرض هذا الإعداد بواسطة المشرÙ.</translation>
-<translation id="8211406090763984747">الاتصال بموقع الويب هذا آمن</translation>
+<translation id="8211406090763984747">الاتصال بهذا الموقع الإلكتروني آمن
+</translation>
<translation id="8249310407154411074">نقل إلى الأعلى</translation>
<translation id="8261506727792406068">حذÙ</translation>
+<translation id="8284326494547611709">الترجمة والشرح</translation>
<translation id="8300705686683892304">تتم الإدارة من خلال التطبيق</translation>
<translation id="8324158725704657629">عدم السؤال مرة أخرى</translation>
<translation id="8372893542064058268">السماح لموقع إلكتروني معيّن بتشغيل "المزامنة ÙÙŠ الخلÙية"</translation>
@@ -321,6 +335,7 @@
<translation id="8903921497873541725">تكبير</translation>
<translation id="8921772741368021346"><ph name="POSITION" /> / <ph name="DURATION" /></translation>
<translation id="8926666909099850184">â€ØªÙ‚نية NFC غير Ù…Ùعّلة على هذا الجهاز. Ùعّلها ÙÙŠ<ph name="BEGIN_LINK" />إعدادات Android<ph name="END_LINK" />.</translation>
+<translation id="8928445016601307354">â€ÙŠØªÙŠØ­ لك هذا الإعداد منع المواقع الإلكترونية من الاطّلاع على المعلومات وتعديلها على الأجهزة المزوَّدة بتقنية NFC.</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">حظر ملÙات تعري٠الارتباط لموقع إلكتروني Ù…Ùحدَّد.</translation>
<translation id="8959122750345127698">التنقل غير قابل للوصول: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_as.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_as.xtb
index 78730aecb27..cb3457d89ea 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_as.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_as.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">ছাইট <ph name="SITE_NAME" /> যোগ কৰা হ’ল</translation>
<translation id="1383876407941801731">Search</translation>
<translation id="1384959399684842514">ডাইনল’ড পজ কৰা হৈছে</translation>
+<translation id="1409426117486808224">খোলা টেবৰ বাবে সৰলীকৃত ভিউ</translation>
<translation id="1415402041810619267">URL চà§à¦Ÿà¦¿ কৰা হ’ল</translation>
<translation id="1446450296470737166">MIDI ডিভাইচৰ সমà§à¦ªà§‚রà§à¦£ নিয়নà§à¦¤à§à§°à¦£à§° অনà§à¦®à¦¤à¦¿ দিয়া</translation>
<translation id="1620510694547887537">কেমেৰা</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">কà§à¦•à¦¿à¦¸à¦®à§‚হক অনà§à¦®à¦¤à¦¿ দিয়ক</translation>
<translation id="2228071138934252756"><ph name="APP_NAME" />ক আপোনাৰ কেমেৰা à¦à¦•à§à¦¸à§‡à¦› কৰিবলৈ দিবলৈ <ph name="BEGIN_LINK" />Android ছেটিংসমূহ<ph name="END_LINK" />তো কেমেৰা অন কৰক।</translation>
<translation id="2241634353105152135">মাতà§à§° à¦à¦¬à¦¾à§°</translation>
+<translation id="2253414712144136228"><ph name="NAME_OF_LIST_ITEM" /> আà¦à¦¤à§°à¦¾à¦“ক</translation>
<translation id="2289270750774289114">কোনো ছাইটে নিকটৱৰà§à¦¤à§€ ডিভাইচ বà§à¦²à§à¦Ÿà§à¦¥ ডিভাইচসমূহ পাব বিচাৰিলে সোধক (আমি চà§à¦ªà¦¾à§°à¦¿à¦› কৰোà¦)</translation>
<translation id="2315043854645842844">অপাৰেটিং ছিষà§à¦Ÿà§‡à¦®à¦Ÿà§‹à§±à§‡ কà§à¦²à¦¾à¦¯à¦¼à§‡à¦£à§à¦Ÿà§° ফালৰ পà§à§°à¦®à¦¾à¦£à¦ªà¦¤à§à§° বাছনি কৰা সà§à¦¬à¦¿à¦§à¦¾à¦Ÿà§‹ সমৰà§à¦¥à¦¨ নকৰে।</translation>
+<translation id="2321958826496381788">আপà§à¦¨à¦¿ à¦à¦‡à¦–িনি অনায়সে পঢ়িব নোৱাৰালৈকে সà§à¦²à¦¾à¦‡à¦¡à¦¾à§°à¦Ÿà§‹ টানক। কোনো পেৰেগà§à§°à¦¾à¦«à¦¤ দà§à¦¬à¦¾à§° টিপিলে পাঠখিনি অতি কমেও ইমানখিনি ডাঙৰ দেখা হ'ব লাগে।</translation>
<translation id="2359808026110333948">অবà§à¦¯à¦¾à¦¹à¦¤ ৰাখক</translation>
<translation id="2379925928934107488">সমà§à¦­à§± হ’লে, Chromeঠগাৠৰঙৰ থীম বà§à¦¯à§±à¦¹à¦¾à§° কৰাৰ সময়ত ছাইটত গাৠৰঙৰ থীম পà§à§°à¦¯à¦¼à§‹à¦— কৰক</translation>
+<translation id="2387895666653383613">পাঠ মিলোৱা কাৰà§à¦¯</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> à¦à¦®. বি.</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> আৰৠ<ph name="NUM_MORE" /> টাৰ অনà§à¦®à¦¤à¦¿ দিয়া আছে}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> আৰৠ<ph name="NUM_MORE" /> টাৰ অনà§à¦®à¦¤à¦¿ দিয়া আছে}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> আৰৠ<ph name="NUM_MORE" /> টাৰ অনà§à¦®à¦¤à¦¿ দিয়া আছে}}</translation>
<translation id="2434158240863470628">ডাউনল’ড সমà§à¦ªà§‚রà§à¦£ হৈছে <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">তথà§à¦¯ দেখà§à§±à¦¾à¦“ক</translation>
<translation id="3123473560110926937">কিছà§à¦®à¦¾à¦¨ ছাইটত অৱৰোধ কৰা আছে</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> ডেটা ষà§à¦Ÿâ€™à§° কৰা আছে</translation>
+<translation id="3203366800380907218">ৱেবৰ পৰা</translation>
<translation id="321187648315454507"><ph name="APP_NAME" />ক আপোনালৈ জাননী পঠিয়াবলৈ দিবলৈ <ph name="BEGIN_LINK" />Android ছেটিংসমূহ<ph name="END_LINK" />তো জাননী অন কৰক।</translation>
<translation id="3227137524299004712">মাইকà§à§°â€™à¦«â€™à¦¨</translation>
<translation id="3277252321222022663">ছেনà§à¦¸à§°à¦¸à¦®à§‚হলৈ à¦à¦•à§à¦¸à§‡à¦› পাবলৈ ছাইটসমূহক অনà§à¦®à¦¤à¦¿ দিয়ক (চà§à¦ªà¦¾à§°à¦¿à¦› কৰা)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">আপোনাৰ ডিভাইচটোৰ বà§à¦¯à§±à¦¹à¦¾à§°</translation>
<translation id="385051799172605136">উভতি যাওক</translation>
<translation id="3859306556332390985">আগলৈ যাওক</translation>
+<translation id="3895926599014793903">বলেৰে জà§à¦® সকà§à¦·à¦® কৰক</translation>
<translation id="3955193568934677022">ছাইটসমূহক সà§à§°à¦•à§à¦·à¦¿à¦¤ সমল পà§à¦²à§‡â€™ কৰিবলৈ অনà§à¦®à¦¤à¦¿ দিয়ক (চà§à¦ªà¦¾à§°à¦¿à¦› কৰা হয়)</translation>
<translation id="3967822245660637423">ডাউনল’ড সমà§à¦ªà§‚ৰà§à¦£ হ’ল</translation>
<translation id="3987993985790029246">লিংক পà§à§°à¦¤à¦¿à¦²à¦¿à¦ªà¦¿ কৰক</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> / ?</translation>
<translation id="4002066346123236978">শিৰোনাম</translation>
<translation id="4008040567710660924">কোনো নিৰà§à¦¦à¦¿à¦·à§à¦Ÿ ছাইটৰ বাবে কà§à¦•à¦¿à¦¸à¦®à§‚হক অনà§à¦®à¦¤à¦¿ দিয়ক।</translation>
+<translation id="4040330681741629921">à¦à¦Ÿà¦¾ ছাইট সৰলীকৃত ভিউত দেখà§à§±à¦¾à¦¬ পৰা হ'লে জাননী পাওক</translation>
<translation id="4046123991198612571">পৰৱৰà§à¦¤à§€ টà§à§°à§‡à¦•</translation>
+<translation id="4149994727733219643">ৱেবপৃষà§à¦ à¦¾à§° বাবে সৰলকৰণ কৰা ভিউ</translation>
<translation id="4165986682804962316">ছাইটৰ ছেটিংসমূহ</translation>
+<translation id="4194328954146351878">ছাইটসমূহক NFC ডিভাইচত তথà§à¦¯ চোৱা আৰৠসলনি কৰাৰ অনà§à¦®à¦¤à¦¿ দিয়াৰ পূৰà§à¦¬à§‡ সোধক (চà§à¦ªà¦¾à§°à¦¿à¦› কৰা হয়)</translation>
<translation id="4200726100658658164">অৱসà§à¦¥à¦¾à¦¨à§° ছেটিংসমূহ খোলক</translation>
<translation id="4226663524361240545">জাননীয়ে ডিভাইচটো কমà§à¦ªà¦¨ কৰিব পাৰে</translation>
<translation id="4259722352634471385">নেভিগে’শà§à¦¬à¦¨ অৱৰোধ কৰা আছে: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">বিসà§à¦¤à¦¾à§° কৰক</translation>
<translation id="4336434711095810371">সকলো ডেটা মচক</translation>
<translation id="4402755511846832236">আপà§à¦¨à¦¿ à¦à¦‡ ডিভাইচটো সকà§à§°à¦¿à§Ÿà¦­à¦¾à§±à§‡ বà§à¦¯à§±à¦¹à¦¾à§° কৰি থকাৰ বিষয়ে ছাইটসমূহে জনাটো অৱৰোধ কৰক</translation>
+<translation id="4428065317363009941">বিজà§à¦žà¦¾à¦ªà¦¨ বà§à¦¯à¦•à§à¦¤à¦¿à¦—তকৰণ</translation>
<translation id="4434045419905280838">পপ-আপ আৰৠপà§à¦¨à§° নিরà§à¦¦à§‡à¦¶</translation>
<translation id="445467742685312942">ছাইটসমূহক সà§à§°à¦•à§à¦·à¦¿à¦¤ সমল পà§à¦²à§‡' কৰিবলৈ অনà§à¦®à¦¤à¦¿ দিয়ক</translation>
<translation id="4468959413250150279">নিৰà§à¦¦à¦¿à¦·à§à¦Ÿ ছাইটৰ বাবে ধà§à¦¬à¦¨à¦¿ মিউট কৰক।</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">সà§à¦•à§à§°à§€à¦¨à§° ওপৰৰ অংশৰ ওচৰত বিকলà§à¦ªà¦Ÿà§‹ উপলবà§à¦§</translation>
<translation id="5197729504361054390">আপà§à¦¨à¦¿ বাছনি কৰা সমà§à¦ªà§°à§à¦•à¦¬à§‹à§° <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />ৰ সৈতে শà§à¦¬à§‡à¦¯à¦¼à¦¾à§° কৰা হ’ব।</translation>
<translation id="5216942107514965959">শেষবাৰ আজি চাইছে</translation>
+<translation id="5264323282659631142">‘<ph name="CHIP_LABEL" />’ আà¦à¦¤à§°à¦¾à¦“ক</translation>
<translation id="528192093759286357">সমà§à¦ªà§‚ৰà§à¦£ সà§à¦•à§à§°à§€à¦£à§° পৰা পà§à§°à¦¸à§à¦¥à¦¾à¦¨ কৰিবলৈ ওপৰৰ পৰা টানি আনক আৰৠবেক বà§à¦Ÿà¦¾à¦®à¦Ÿà§‹ টিপক।</translation>
<translation id="5300589172476337783">দেখà§à§±à¦¾à¦“ক</translation>
<translation id="5301954838959518834">ঠিক আছে, বà§à¦œà¦¿ পালোà¦</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">à¦à¦‡à¦Ÿà§‹à§±à§‡ ছাইটসমূহে ষà§à¦Ÿâ€™à§° কৰা <ph name="DATASIZE" /> ডেটা আৰৠকà§à¦•à¦¿ মচিব।</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(আৰৠ১টা)}one{(আৰৠ#টা)}other{(আৰৠ#টা)}}</translation>
<translation id="5403592356182871684">নামসমূহ</translation>
+<translation id="5412236728747081950">আপোনাক অধিক পà§à§°à¦¾à¦¸à¦‚গিক বিজà§à¦žà¦¾à¦ªà¦¨ দেখà§à§±à¦¾à¦¬à¦²à§ˆ à¦à¦‡ ছাইটটোৱে Chromeৰ পৰা আপোনাৰ আগà§à§°à¦¹à¦¸à¦®à§‚হ পায়</translation>
<translation id="5438097262470833822">à¦à¦‡ বাছনিটোৱে <ph name="WEBSITE" />ৰ বাবে অনà§à¦®à¦¤à¦¿ ৰিছেট কৰিব</translation>
<translation id="5489227211564503167"><ph name="TOTAL_TIME" />ৰ ভিতৰত <ph name="ELAPSED_TIME" /> সময় পাৰ হৈছে।</translation>
<translation id="5494752089476963479">অননà§à¦®à§‹à¦¦à¦¿à¦¤ বা বিভà§à§°à¦¾à¦¨à§à¦¤à¦¿à¦•à§° বিজà§à¦žà¦¾à¦ªà¦¨ দেখà§à¦“ৱা ছাইটসমূহত বিজà§à¦žà¦¾à¦ªà¦¨ অৱৰোধ কৰক</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">পà§à¦¨à§° ল’ড কৰক</translation>
<translation id="5596627076506792578">অধিক বিকলà§à¦ª</translation>
<translation id="5649053991847567735">সà§à¦¬à§Ÿà¦‚কà§à§°à¦¿à§Ÿà¦­à¦¾à§±à§‡ হোৱা ডাউনল’ড</translation>
+<translation id="5668404140385795438">ৱেবছাইটোৱে জà§à¦® ইনৰ কà§à¦·à§‡à¦¤à§à§°à¦¤ বাধা দিবলৈ কৰা অনà§à§°à§‹à¦§ অ’ভাৰৰাইড কৰে</translation>
<translation id="5677928146339483299">অৱৰোধিত</translation>
<translation id="5689516760719285838">অৱসà§à¦¥à¦¾à¦¨</translation>
<translation id="5690795753582697420">Android ছেটিংসমূহত কেমেৰাটো অফ কৰা হ’ল</translation>
-<translation id="5710871682236653961">আপà§à¦¨à¦¿ NFC ডিভাইচসমূহত টিপিলে ছাইটসমূহক তথà§à¦¯ পঠিওৱা আৰৠলাভ কৰাৰ অনà§à¦®à¦¤à¦¿ দিয়াৰ আগতে সোধক (চà§à¦ªà¦¾à§°à¦¿à¦› কৰা হয়)</translation>
<translation id="5719847187258001597">à¦à¦‡à¦Ÿà§‹à§±à§‡ আপোনাৰ গৃহ সà§à¦•à§à¦°à§€à¦¨à¦¤ <ph name="ORIGIN" />ঠঅথবা ইয়াৰ à¦à¦ªà§â€Œà¦Ÿà§‹à§±à§‡ ষà§à¦Ÿâ€™à§° কৰা সকলো ডেটা আৰৠকà§à¦•à¦¿ মচিব।</translation>
<translation id="5771720122942595109"><ph name="PERMISSION_1" />ক অৱৰোধ কৰা আছে</translation>
<translation id="5804241973901381774">অনà§à¦®à¦¤à¦¿</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">পà§à¦²à§‡â€™ কৰক</translation>
<translation id="6818926723028410516">বসà§à¦¤à§ বাছনি কৰক</translation>
<translation id="6864395892908308021">à¦à¦‡ ডিভাইচটোৱে NFC পà§à¦¿à¦¬ নোৱাৰে</translation>
-<translation id="6910211073230771657">মচা হ’ল</translation>
<translation id="6912998170423641340">ছাইটসমূহৰ কà§à¦²à¦¿à¦ªà¦¬â€™à§°à§à¦¡à§° পাঠ আৰৠছবি পঢ়াৰ সà§à¦¬à¦¿à¦§à¦¾ অৱৰোধ কৰক</translation>
<translation id="6945221475159498467">বাছনি কৰক</translation>
<translation id="6965382102122355670">ঠিক আছে</translation>
+<translation id="6981982820502123353">সাধà§à¦¯ সà§à¦¬à¦¿à¦§à¦¾à¦¸à¦®à§‚হ</translation>
<translation id="6992289844737586249">ছাইটসমূহে আপোনাৰ ডিভাইচৰ মাইকà§à§°à¦«'ন বà§à¦¯à§±à¦¹à¦¾à§° কৰাৰ পূরà§à¦¬à§‡ অনà§à¦®à¦¤à¦¿ ল'বলৈ দিয়ক (à¦à§Ÿà¦¾ চà§à¦ªà¦¾à§°à¦¿à¦› কৰা হয়)</translation>
<translation id="7000754031042624318">Androidৰ ছেটিংসমূহত অফ কৰা আছে</translation>
<translation id="7016516562562142042">বৰà§à¦¤à¦®à¦¾à¦¨à§° সনà§à¦§à¦¾à¦¨ ইঞà§à¦œà¦¿à¦¨à§° বাবে অনà§à¦®à§‹à¦¦à¦¨ জনোৱা হৈছে</translation>
+<translation id="702463548815491781">টকবেক বা ছà§à¦‡à¦šà§° দà§à¦¬à¦¾à§°à¦¾ বà§à¦¯à§±à¦¹à¦¾à§° কৰা অনà§à¦®à¦¤à¦¿ অন থকা অৱসà§à¦¥à¦¾à¦¨ à¦à§Ÿà¦¾ চà§à¦ªà¦¾à§°à¦¿à¦› কৰা হয়</translation>
<translation id="7053983685419859001">অৱৰোধ কৰক</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{১টা বসà§à¦¤à§ বাছনি কৰা হ’ল}one{#টা বসà§à¦¤à§ বাছনি কৰা হ’ল}other{#টা বসà§à¦¤à§ বাছনি কৰা হ’ল}}</translation>
-<translation id="7070090581017165256">à¦à¦‡ ছাইটটোৰ বিষয়ে</translation>
<translation id="7087918508125750058"><ph name="ITEM_COUNT" />টা বাছনি কৰা হ’ল। সà§à¦•à§à§°à§€à¦£à§° ওপৰৰ অংশত কাষত থকা বিকলà§à¦ªà¦¸à¦®à§‚হ</translation>
<translation id="7141896414559753902">ছাইটসমূহে পপà§â€Œ-আপ দেখà§à¦“ৱাটো আৰৠবেলেগ লিংকলৈ লৈ যোৱাটো অৱৰোধ কৰক (আমি চà§à¦ªà¦¾à§°à¦¿à¦› কৰোà¦)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> কে.বি.</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">à¦à¦Ÿà¦¾ ছাইটে আপোনাৰ মাইকà§à§°â€™à¦«â€™à¦¨ বà§à¦¯à§±à¦¹à¦¾à§° কৰি আছে</translation>
<translation id="7561196759112975576">সদায়</translation>
-<translation id="7572498721684305250">আপà§à¦¨à¦¿ NFC ডিভাইচসমূহত টিপিলে ছাইটসমূহে তথà§à¦¯ পঠিয়াব আৰৠলাভ কৰিব নোৱৰাকৈ অৱৰোধ কৰক</translation>
<translation id="757524316907819857">সà§à§°à¦•à§à¦·à¦¿à¦¤ সমল পà§à¦²à§‡â€™ কৰাৰ পৰা ছাইটসমূহক অৱৰোধ কৰক</translation>
+<translation id="7577900504646297215">আগà§à§°à¦¹à¦¸à¦®à§‚হ পৰিচালনা কৰক</translation>
<translation id="7649070708921625228">সহায়</translation>
<translation id="7658239707568436148">বাতিল কৰক</translation>
<translation id="7781829728241885113">কালি</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">সংযোগটো নিৰাপদ</translation>
<translation id="8249310407154411074">শীৰà§à¦·à¦²à§ˆ নিয়ক</translation>
<translation id="8261506727792406068">মচক</translation>
+<translation id="8284326494547611709">কেপশà§à¦¬à¦¨</translation>
<translation id="8300705686683892304">à¦à¦ªà§° দà§à¦¬à¦¾à§°à¦¾ পৰিচালিত</translation>
<translation id="8324158725704657629">পà§à¦¨à§° নà§à¦¸à§à¦§à¦¿à¦¬</translation>
<translation id="8372893542064058268">কোনো নিরà§à¦¦à¦¿à¦·à§à¦Ÿ ছাইটৰ বাবে নেপথà§à¦¯à¦¤ ছিংক কৰাৰ অনà§à¦®à¦¤à¦¿ দিয়ক।</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">জà§à¦® ইন কৰক</translation>
<translation id="8921772741368021346"><ph name="POSITION" /> / <ph name="DURATION" /></translation>
<translation id="8926666909099850184">à¦à¦‡ ডিভাইচটোৰ বাবে NFC অফ কৰা আছে। ইয়াক <ph name="BEGIN_LINK" />Android ছেটিংসমূহ<ph name="END_LINK" />লৈ গৈ অন কৰক।</translation>
+<translation id="8928445016601307354">ছাইটসমূহক NFC ডিভাইচত তথà§à¦¯ চোৱা আৰৠসলনি কৰাৰ পৰা অৱৰোধ কৰক</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">কোনো বিশেষ ছাইটৰ বাবে কà§à¦•à¦¿à¦¸à¦®à§‚হ অৱৰোধ কৰক।</translation>
<translation id="8959122750345127698">ইয়ালৈ নেভিগেশà§à¦¬à¦¨ পাব পৰা অৱসà§à¦¥à¦¾à¦¤ নাই: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_az.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_az.xtb
index 1125974542d..a6ed78aaa06 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_az.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_az.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676"><ph name="SITE_NAME" /> saytı əlavə edildi</translation>
<translation id="1383876407941801731">Axtar</translation>
<translation id="1384959399684842514">EndirmÉ™ durduruldu</translation>
+<translation id="1409426117486808224">Açıq tablar üçün sadələşdirilmiş görünüş</translation>
<translation id="1415402041810619267">URL tam deyil</translation>
<translation id="1446450296470737166">MIDI cihazlar üzərində tam nəzarətə icazə verin</translation>
<translation id="1620510694547887537">Kamera</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">Kukilərə icazə verin</translation>
<translation id="2228071138934252756"><ph name="APP_NAME" /> tətbiqinə kameranıza giriş icazəsi vermək üçün <ph name="BEGIN_LINK" />Android Ayarlarında<ph name="END_LINK" /> kameranı da aktiv edin.</translation>
<translation id="2241634353105152135">Sadəcə bir dəfə</translation>
+<translation id="2253414712144136228"><ph name="NAME_OF_LIST_ITEM" /> Silin</translation>
<translation id="2289270750774289114">Sayt yaxınlıqdakı Bluetooth cihazlarını kəşf etmək istədikdə soruşun (tövsiyə edilir)</translation>
<translation id="2315043854645842844">Müştəri sayt sertifikatı seçimi əməliyyat sistemi tərəfindən dəstəklənmir.</translation>
+<translation id="2321958826496381788">Rahat oxuya biləcəyinizə qədər slayderi dartın. Abzasa iki dəfə tıklayandan sonra mətn bu böyüklükdə olmalıdır.</translation>
<translation id="2359808026110333948">Davam edin</translation>
<translation id="2379925928934107488">Mümkün olduqda, Chrome tünd temadan istifadə edərkən saytlara tünd tema tətbiq edin</translation>
+<translation id="2387895666653383613">Mətn miqyası</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> və daha <ph name="NUM_MORE" /> üçün icazə verilib}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> və daha <ph name="NUM_MORE" /> üçün icazə verilib}}</translation>
<translation id="2434158240863470628">Endirmə tamamlandı <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">Məlumatı göstərin</translation>
<translation id="3123473560110926937">Bəzi saytlarda bloklandı</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> saxlanılan data</translation>
+<translation id="3203366800380907218">Vebdən</translation>
<translation id="321187648315454507"><ph name="APP_NAME" /> tətbiqinə sizə bildiriş göndərmək icazəsi vermək üçün <ph name="BEGIN_LINK" />Android Ayarlarında<ph name="END_LINK" /> bildirişləri də aktiv edin.</translation>
<translation id="3227137524299004712">Mikrofon</translation>
<translation id="3277252321222022663">Saytların sensorlara daxil olmasına icazə verin (tövsiyə edilir)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">Cihazdan istifadəniz</translation>
<translation id="385051799172605136">Geri</translation>
<translation id="3859306556332390985">İrəli axtarın</translation>
+<translation id="3895926599014793903">Zoom'a icazə verməyə məcbur edin</translation>
<translation id="3955193568934677022">Saytlara qorunan datanı oxumağa icazə verin (tövsiyə olunur)</translation>
<translation id="3967822245660637423">Endirmə tamamdır</translation>
<translation id="3987993985790029246">Linki kopyalayın</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> / ?</translation>
<translation id="4002066346123236978">Başlıq</translation>
<translation id="4008040567710660924">Xüsusi sayt üçün kukilərə icazə verin.</translation>
+<translation id="4040330681741629921">Sayt sadələşdirilmiş görünüşdə göstərilə bildikdə bildiriş alın</translation>
<translation id="4046123991198612571">Növbəti trek</translation>
+<translation id="4149994727733219643">İnternet səhifələr üçün sadələşdirilmiş görünüş</translation>
<translation id="4165986682804962316">Sayt ayarları</translation>
+<translation id="4194328954146351878">Saytların NFC cihazlarındakı məlumatları görməsi və dəyişməsinə icazə verməzdən əvvəl soruşun (tövsiyə edilir)</translation>
<translation id="4200726100658658164">Məkan Ayarlarını açın</translation>
<translation id="4226663524361240545">Bildirişlər cihazı titrədə bilər</translation>
<translation id="4259722352634471385">Naviqasiya bloklandı: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">Genişləndirin</translation>
<translation id="4336434711095810371">Bütün datanı silin</translation>
<translation id="4402755511846832236">Saytların bu cihazdan nə zaman aktiv şəkildə istifadə etdiyinizi bilməsini bloklayın</translation>
+<translation id="4428065317363009941">Reklam fərdiləşdirməsi</translation>
<translation id="4434045419905280838">Popap və yönləndirmələr</translation>
<translation id="445467742685312942">Saytlara qorunan kontenti oxutmaÄŸa icazÉ™ verin</translation>
<translation id="4468959413250150279">Xüsusi saytı səsiz rejimə keçirin.</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">Seçim ekranın yuxarısına yaxın yerdə əlçatandır</translation>
<translation id="5197729504361054390">Seçdiyiniz kontaktlar <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ilə paylaşılacaq.</translation>
<translation id="5216942107514965959">Son ziyarət bu gün olub</translation>
+<translation id="5264323282659631142">"<ph name="CHIP_LABEL" />" daxiletməsini silin</translation>
<translation id="528192093759286357">Yuxarıdan sürüşdürün və tam ekrandan çıxmaq üçün geri düyməsinə basın.</translation>
<translation id="5300589172476337783">Göstərin</translation>
<translation id="5301954838959518834">Ok, anladım</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">Bununla saytlar tərəfindən saxlanılan <ph name="DATASIZE" /> data və kuki silinəcək.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(+1)}other{(+ #)}}</translation>
<translation id="5403592356182871684">Adlar</translation>
+<translation id="5412236728747081950">Bu sayt sizə daha uyğun reklamlar göstərmək üçün Chrome'dan maraqlarınızı əldə edir</translation>
<translation id="5438097262470833822">Bu seçim <ph name="WEBSITE" /> üçün icazələri sıfırlayacaq</translation>
<translation id="5489227211564503167">Keçən vaxt: <ph name="ELAPSED_TIME" /> / <ph name="TOTAL_TIME" />.</translation>
<translation id="5494752089476963479">İntruziv və aldadıcı reklamlar göstərən saytlardakı reklamları bloklayın</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">Yenidən yükləyin</translation>
<translation id="5596627076506792578">ÆlavÉ™ seçimlÉ™r</translation>
<translation id="5649053991847567735">Avtomatik endirmələr</translation>
+<translation id="5668404140385795438">Böyüdülmənin qarşısını almaq üçün saytın sorğusunu kənarlaşdırın</translation>
<translation id="5677928146339483299">Bloklananlar</translation>
<translation id="5689516760719285838">Məkan</translation>
<translation id="5690795753582697420">Kamera Android ayarlarında deaktiv edilib</translation>
-<translation id="5710871682236653961">NFC cihazlarına toxunduqda saytların məlumat göndərməsi və almasına icazə verməzdən əvvəl soruşulsun (tövsiyə edilir)</translation>
<translation id="5719847187258001597">Bununla Æsas ekranda <ph name="ORIGIN" /> vÉ™ ya onun tÉ™tbiqi tÉ™rÉ™findÉ™n saxlanılan bütün data vÉ™ kukilÉ™r silinÉ™cÉ™k.</translation>
<translation id="5771720122942595109"><ph name="PERMISSION_1" /> bloklanıb</translation>
<translation id="5804241973901381774">İcazələr</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">Oxudun</translation>
<translation id="6818926723028410516">Element seçin</translation>
<translation id="6864395892908308021">Bu cihazda NFC dəstəklənmir</translation>
-<translation id="6910211073230771657">Silinib</translation>
<translation id="6912998170423641340">Saytların buferdəki mətn və şəkillərə girişini blok edin</translation>
<translation id="6945221475159498467">Seçin</translation>
<translation id="6965382102122355670">OK</translation>
+<translation id="6981982820502123353">Giriş İmkanı</translation>
<translation id="6992289844737586249">Saytlara mikrofonunuzu istifadə etmək icazəsi verməmişdən əvvəl soruşun (tövsiyə olunur)</translation>
<translation id="7000754031042624318">Android ayarlarında söndürülüb</translation>
<translation id="7016516562562142042">Cari axtarış sistemi üçün icazə verildi</translation>
+<translation id="702463548815491781">TalkBack və ya Keçid Düyməsi aktiv olduqda tövsiyə olunur</translation>
<translation id="7053983685419859001">Bloklayın</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1 element seçildi}other{# element seçildi}}</translation>
-<translation id="7070090581017165256">Bu sayt haqqında</translation>
<translation id="7087918508125750058"><ph name="ITEM_COUNT" /> seçildi. Seçimlər ekranın yuxarısında əlçatandır</translation>
<translation id="7141896414559753902">Saytların popapları və yönləndirmələri göstərməyini blok edin (tövsiyə olunur)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> KB</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">Sayt mikrofonunuzdan istifadÉ™ edir</translation>
<translation id="7561196759112975576">Həmişə</translation>
-<translation id="7572498721684305250">NFC cihazlarına toxunduqda saytların məlumat göndərməsi və almasının qarşısını alın</translation>
<translation id="757524316907819857">Saytların qorunan kontenti oxutmasını blok edin</translation>
+<translation id="7577900504646297215">Maraqları idarə edin</translation>
<translation id="7649070708921625228">Yardım</translation>
<translation id="7658239707568436148">Ləğv edin</translation>
<translation id="7781829728241885113">Dünən</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">Bağlantı təhlükəsizdir</translation>
<translation id="8249310407154411074">Æn yuxarı</translation>
<translation id="8261506727792406068">Silin</translation>
+<translation id="8284326494547611709">Başlıqlar</translation>
<translation id="8300705686683892304">Tədbiq tərəfindən idarə edilən</translation>
<translation id="8324158725704657629">Daha soruÅŸma</translation>
<translation id="8372893542064058268">Xüsusi sayt üçün Arxa fon Sinxronizasiyasına icazə verin.</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">Zoom</translation>
<translation id="8921772741368021346"><ph name="POSITION" /> / <ph name="DURATION" /></translation>
<translation id="8926666909099850184">NFC bu cihazda deaktivdir. <ph name="BEGIN_LINK" />Android Ayarlarında<ph name="END_LINK" /> onu aktiv edin.</translation>
+<translation id="8928445016601307354">Saytların NFC cihazlarındakı məlumatları görməsi və dəyişməsini bloklayın</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">Xüsusi sayt üçün kukiləri blok edin.</translation>
<translation id="8959122750345127698">Naviqasiya əlçatmazdır: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_be.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_be.xtb
index dd0b9392037..648ae95b190 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_be.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_be.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">Сайт <ph name="SITE_NAME" /> дададзены</translation>
<translation id="1383876407941801731">Пошук</translation>
<translation id="1384959399684842514">Спампоўка прыпынена</translation>
+<translation id="1409426117486808224">Спрошчаны выглÑд адкрытых укладак</translation>
<translation id="1415402041810619267">URL-Ð°Ð´Ñ€Ð°Ñ Ð°Ð±Ñ€Ñзаны</translation>
<translation id="1446450296470737166">Дазв. поўны кантроль MIDI-прылад</translation>
<translation id="1620510694547887537">Камера</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">Дазволіць файлы cookie</translation>
<translation id="2228071138934252756">Каб праграма "<ph name="APP_NAME" />" атрымала доÑтуп да камеры, уключыце камеру такÑама Ñž <ph name="BEGIN_LINK" />Ðаладах Android<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Толькі адзін раз</translation>
+<translation id="2253414712144136228">Выдаліць: <ph name="NAME_OF_LIST_ITEM" /></translation>
<translation id="2289270750774289114">Пытацца, калі Ñайт Ñпрабуе выÑвіць прылады Bluetooth паблізу (Ñ€Ñкамендуецца)</translation>
<translation id="2315043854645842844">ÐÐ¿ÐµÑ€Ð°Ñ†Ñ‹Ð¹Ð½Ð°Ñ ÑÑ–ÑÑ‚Ñма не падтрымлівае выбар Ñертыфіката кліента.</translation>
+<translation id="2321958826496381788">ПерацÑгвайце паўзунок, пакуль гÑÑ‚Ñ‹ Ñ‚ÑкÑÑ‚ не будзе зручна чытаць. ПаÑÐ»Ñ Ð¿Ð°Ð´Ð²Ð¾Ð¹Ð½Ð°Ð³Ð° націÑÐºÐ°Ð½Ð½Ñ Ð½Ð° абзац Ñ‚ÑкÑÑ‚ павінен быць Ñк мінімум такім вÑлікім.</translation>
<translation id="2359808026110333948">ПрацÑгнуць</translation>
<translation id="2379925928934107488">Калі Chrome выкарыÑтоўвае цёмную Ñ‚Ñму, прымÑнÑць Ñе да Ñайтаў (калі гÑта магчыма)</translation>
+<translation id="2387895666653383613">Маштаб Ñ‚ÑкÑту</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> МБ</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Дазволены <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> Ñ– ÑÑˆÑ‡Ñ <ph name="NUM_MORE" />}one{Дазволены <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> Ñ– ÑÑˆÑ‡Ñ <ph name="NUM_MORE" />}few{Дазволены <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> Ñ– ÑÑˆÑ‡Ñ <ph name="NUM_MORE" />}many{Дазволены <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> Ñ– ÑÑˆÑ‡Ñ <ph name="NUM_MORE" />}other{Дазволены <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> Ñ– ÑÑˆÑ‡Ñ <ph name="NUM_MORE" />}}</translation>
<translation id="2434158240863470628">Спампоўванне завершана <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">Паказаць інфармацыю</translation>
<translation id="3123473560110926937">Заблакіравана на некаторых Ñайтах</translation>
<translation id="3198916472715691905">Ðб'ём захаваных даных: <ph name="STORAGE_AMOUNT" /></translation>
+<translation id="3203366800380907218">З інтÑрнÑту</translation>
<translation id="321187648315454507">Каб праграма "<ph name="APP_NAME" />" магла адпраўлÑць вам апавÑшчÑнні, такÑама ўключыце Ñ–Ñ… у <ph name="BEGIN_LINK" />Ðаладах Android<ph name="END_LINK" />.</translation>
<translation id="3227137524299004712">Мікрафон</translation>
<translation id="3277252321222022663">Дазволіць Ñайтам доÑтуп да датчыкаў (Ñ€Ñкамендуецца)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">ВыкарыÑтанне вамі прылады</translation>
<translation id="385051799172605136">Ðазад</translation>
<translation id="3859306556332390985">ПерайÑці ўперад</translation>
+<translation id="3895926599014793903">ПрымуÑовае ўключÑнне павелічÑннÑ</translation>
<translation id="3955193568934677022">Дазволіць Ñайтам прайграваць абароненае змеÑціва (Ñ€Ñкамендуецца)</translation>
<translation id="3967822245660637423">Спампоўка завершана</translation>
<translation id="3987993985790029246">Скапіраваць ÑпаÑылку</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> / ?</translation>
<translation id="4002066346123236978">Ðазва</translation>
<translation id="4008040567710660924">Дазвол выкарыÑÑ‚Ð°Ð½Ð½Ñ Ñ„Ð°Ð¹Ð»Ð°Ñž cookie ад канкрÑтнага Ñайта.</translation>
+<translation id="4040330681741629921">ÐпавÑшчаць, калі Ñайт можна адкрыць у Ñпрошчаным выглÑдзе</translation>
<translation id="4046123991198612571">ÐаÑтупны Ñ‚Ñ€Ñк</translation>
+<translation id="4149994727733219643">Спрошчаны выглÑд Ð´Ð»Ñ Ð²Ñб-Ñтаронак</translation>
<translation id="4165986682804962316">Ðалады Ñайта</translation>
+<translation id="4194328954146351878">Пытацца, перш чым дазвалÑць Ñайтам праглÑдаць Ñ– змÑнÑць інфармацыю на прыладах NFC (Ñ€Ñкамендуецца)</translation>
<translation id="4200726100658658164">Ðдкрыць налады меÑцазнаходжаннÑ</translation>
<translation id="4226663524361240545">ÐпавÑшчÑнні могуць уключаць вібрацыю прылады</translation>
<translation id="4259722352634471385">Пераход па наÑтупным адраÑе заблакіраваны: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">Разгарнуць</translation>
<translation id="4336434711095810371">Выдаліць уÑе даныÑ</translation>
<translation id="4402755511846832236">Ðе даваць Ñайтам знаць, калі вы карыÑтаецеÑÑ Ð³Ñтай прыладай</translation>
+<translation id="4428065317363009941">ПерÑÐ°Ð½Ð°Ð»Ñ–Ð·Ð°Ñ†Ñ‹Ñ Ñ€Ñкламы</translation>
<translation id="4434045419905280838">УÑплыв. вокны Ñ– перанакіраванні</translation>
<translation id="445467742685312942">Дазволіць Ñайтам прайграваць абароненае змеÑціва</translation>
<translation id="4468959413250150279">Выключыць гук на канкрÑтным Ñайце.</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">ГÑÑ‚Ñ‹ выбар можна зрабіць уверÑе Ñкрана</translation>
<translation id="5197729504361054390">Ð’Ñ‹Ð±Ñ€Ð°Ð½Ñ‹Ñ Ð²Ð°Ð¼Ñ– кантакты будуць абагулены з Ñайтам <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />.</translation>
<translation id="5216942107514965959">ÐпошнÑе наведванне: ÑённÑ</translation>
+<translation id="5264323282659631142">Выдаліць чып "<ph name="CHIP_LABEL" />"</translation>
<translation id="528192093759286357">Каб выйÑці з поўнаÑкраннага Ñ€Ñжыму, правÑдзіце зверху ўніз Ñ– націÑніце кнопку "Ðазад".</translation>
<translation id="5300589172476337783">Паказаць</translation>
<translation id="5301954838959518834">OK</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">Будуць выдалены файлы cookie Ñ– Ð´Ð°Ð½Ñ‹Ñ (<ph name="DATASIZE" />), Ð·Ð°Ñ…Ð°Ð²Ð°Ð½Ñ‹Ñ Ñайтамі.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(Ñ– ÑÑˆÑ‡Ñ 1)}one{(Ñ– ÑÑˆÑ‡Ñ #)}few{(Ñ– ÑÑˆÑ‡Ñ #)}many{(Ñ– ÑÑˆÑ‡Ñ #)}other{(Ñ– ÑÑˆÑ‡Ñ #)}}</translation>
<translation id="5403592356182871684">Імёны</translation>
+<translation id="5412236728747081950">ГÑÑ‚Ñ‹ Ñайт выкарыÑтоўвае інфармацыю пра вашы дзеÑнні Ñž Chrome, каб паказваць вам больш адпаведную вашым інтарÑÑам Ñ€Ñкламу</translation>
<translation id="5438097262470833822">Будуць Ñкінуты дазволы Ð´Ð»Ñ Ð²Ñб-Ñайта <ph name="WEBSITE" /></translation>
<translation id="5489227211564503167">Прайшло чаÑу: <ph name="ELAPSED_TIME" /> з <ph name="TOTAL_TIME" />.</translation>
<translation id="5494752089476963479">Блакіраваць Ñ€Ñкламу на Ñайтах, ÑÐºÑ–Ñ Ð¿Ð°ÐºÐ°Ð·Ð²Ð°ÑŽÑ†ÑŒ назойлівую Ñ€Ñкламу або Ñ€Ñкламу, ÑÐºÐ°Ñ ÑžÐ²Ð¾Ð´Ð·Ñ–Ñ†ÑŒ у зман</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">Перазагрузіць</translation>
<translation id="5596627076506792578">Ð”Ð°Ð´Ð°Ñ‚ÐºÐ¾Ð²Ñ‹Ñ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ñ‹</translation>
<translation id="5649053991847567735">Ðўтаматычнае Ñпампоўванне</translation>
+<translation id="5668404140385795438">Перавызначаць запыт вÑб-Ñайта на прадухіленне павелічÑÐ½Ð½Ñ Ð¼Ð°ÑˆÑ‚Ð°Ð±Ñƒ</translation>
<translation id="5677928146339483299">Заблакіравана</translation>
<translation id="5689516760719285838">МеÑцазнаходжанне</translation>
<translation id="5690795753582697420">Камера выключана ў наладах Android</translation>
-<translation id="5710871682236653961">Пытацца, перш чым дазволіць Ñайтам адпраўлÑць Ñ– атрымліваць інфармацыю, калі вы націÑканнем выбіраеце прылады NFC (Ñ€Ñкамендуецца)</translation>
<translation id="5719847187258001597">Будуць выдалены ÑžÑе файлы cookie Ñ– даныÑ, Ð·Ð°Ñ…Ð°Ð²Ð°Ð½Ñ‹Ñ Ñайтам <ph name="ORIGIN" /> Ñ– Ñго праграмай, размешчанай на галоўным Ñкране.</translation>
<translation id="5771720122942595109">Заблакіравана: <ph name="PERMISSION_1" /></translation>
<translation id="5804241973901381774">Дазволы</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">Прайграць</translation>
<translation id="6818926723028410516">Выберыце Ñлементы</translation>
<translation id="6864395892908308021">ГÑта прылада не падтрымлівае функцыю NFC</translation>
-<translation id="6910211073230771657">Выдалена</translation>
<translation id="6912998170423641340">Заблакіраваць Ñайтам доÑтуп да Ñ‡Ñ‹Ñ‚Ð°Ð½Ð½Ñ Ñ‚ÑкÑту Ñ– відарыÑаў з буфера абмену</translation>
<translation id="6945221475159498467">Выбраць</translation>
<translation id="6965382102122355670">ОК</translation>
+<translation id="6981982820502123353">Спец. магчымаÑці</translation>
<translation id="6992289844737586249">Пытацца, перш чым дазволіць Ñайтам выкарыÑтоўваць мікрафон (Ñ€Ñкамендуецца)</translation>
<translation id="7000754031042624318">Выключана ў наладах Android</translation>
<translation id="7016516562562142042">Дазволена Ð´Ð»Ñ Ð±Ñгучай пошукавай ÑÑ–ÑÑ‚Ñмы</translation>
+<translation id="702463548815491781">РÑкамендуецца, калі ўключаны TalkBack або доÑтуп праз пераключальнікі</translation>
<translation id="7053983685419859001">Заблакіраваць</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{Выбраны 1 Ñлемент}one{Выбраны # Ñлемент}few{Выбрана # Ñлементы}many{Выбрана # Ñлементаў}other{Выбрана # Ñлемента}}</translation>
-<translation id="7070090581017165256">Ð†Ð½Ñ„Ð°Ñ€Ð¼Ð°Ñ†Ñ‹Ñ Ð¿Ñ€Ð° гÑÑ‚Ñ‹ Ñайт</translation>
<translation id="7087918508125750058">Выбрана: <ph name="ITEM_COUNT" />. Параметры знаходзÑцца ўверÑе Ñкрана</translation>
<translation id="7141896414559753902">Заблакіраваць Ñайтам паказ выплыўных вокнаў Ñ– перанакіраванні (Ñ€Ñкамендуецца)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> КБ</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">Сайт выкарыÑтоўвае мікрафон</translation>
<translation id="7561196759112975576">ЗаўÑёды</translation>
-<translation id="7572498721684305250">Блакіраваць Ñайтам адпраўку Ñ– атрыманне інфармацыі, калі вы націÑканнем выбіраеце прылады NFC</translation>
<translation id="757524316907819857">Блакіраваць прайграванне абароненага змеÑціва на Ñайтах</translation>
+<translation id="7577900504646297215">Кіраваць інтарÑÑамі</translation>
<translation id="7649070708921625228">Даведка</translation>
<translation id="7658239707568436148">СкаÑаваць</translation>
<translation id="7781829728241885113">Учора</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">ПадключÑнне бÑÑпечнае</translation>
<translation id="8249310407154411074">ПерамÑÑціць уверх</translation>
<translation id="8261506727792406068">Выдаліць</translation>
+<translation id="8284326494547611709">Субцітры</translation>
<translation id="8300705686683892304">Пад кіраваннем праграмы</translation>
<translation id="8324158725704657629">Больш не пытацца</translation>
<translation id="8372893542064058268">Дазволіць фонавую Ñінхранізацыю Ð´Ð»Ñ ÐºÐ°Ð½ÐºÑ€Ñтнага Ñайта.</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">ПавÑлічыць маштаб</translation>
<translation id="8921772741368021346"><ph name="POSITION" /> / <ph name="DURATION" /></translation>
<translation id="8926666909099850184">Ð¤ÑƒÐ½ÐºÑ†Ñ‹Ñ NFC выключана на гÑтай прыладзе. Уключыце Ñе Ñž <ph name="BEGIN_LINK" />Ðаладах Android<ph name="END_LINK" />.</translation>
+<translation id="8928445016601307354">Забараніць Ñайтам праглÑдаць Ñ– змÑнÑць інфармацыю на прыладах NFC</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">Блакіраваць файлы cookie Ð´Ð»Ñ Ð¿Ñўнага Ñайта.</translation>
<translation id="8959122750345127698">Пераход па наÑтупным адраÑе недаÑтупны: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_bg.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_bg.xtb
index 70798410688..7b78661e69f 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_bg.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_bg.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">Сайтът <ph name="SITE_NAME" /> е добавен</translation>
<translation id="1383876407941801731">ТърÑене</translation>
<translation id="1384959399684842514">ИзтеглÑнето е на пауза</translation>
+<translation id="1409426117486808224">ОпроÑтен изглед на отворените раздели</translation>
<translation id="1415402041810619267">URL адреÑÑŠÑ‚ е Ñъкратен</translation>
<translation id="1446450296470737166">Разр. на Ð¿ÑŠÐ»Ð½Ð¸Ñ ÐºÐ¾Ð½Ñ‚Ñ€Ð¾Ð» над MIDI</translation>
<translation id="1620510694547887537">Камера</translation>
@@ -44,15 +45,18 @@
<translation id="2091887806945687916">Звук</translation>
<translation id="2107397443965016585">Запитване преди разрешаване на Ñайтовете да възпроизвеждат защитено Ñъдържание (препоръчително)</translation>
<translation id="2146738493024040262">ОтварÑне на мигновеното приложение</translation>
-<translation id="2148716181193084225">ДнеÑ</translation>
+<translation id="2148716181193084225">днеÑ</translation>
<translation id="2182457891543959921">Извеждане на запитване, преди да Ñе разреши на Ñайтовете да Ñъздават триизмерна карта на заобикалÑщата ви Ñреда или да ÑледÑÑ‚ позициÑта на камерата (препоръчително)</translation>
<translation id="2212565012507486665">Разрешаване на „биÑквитките“</translation>
<translation id="2228071138934252756">За да разрешите на <ph name="APP_NAME" /> да оÑъщеÑтвÑва доÑтъп до камерата ви, Ñ‚Ñ Ñ‚Ñ€Ñбва да бъде включена и от <ph name="BEGIN_LINK" />наÑтройките на Android<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Само веднъж</translation>
+<translation id="2253414712144136228">Премахване на <ph name="NAME_OF_LIST_ITEM" /></translation>
<translation id="2289270750774289114">Извеждане на запитване, когато Ñайт иÑка да открива уÑтройÑтва Ñ Bluetooth в близоÑÑ‚ (препоръчително)</translation>
<translation id="2315043854645842844">ИзбраниÑÑ‚ Ñертификат от Ñтраната на клиента не Ñе поддържа от операционната ÑиÑтема.</translation>
+<translation id="2321958826496381788">ПремеÑтете плъзгача, докато можете да четете удобно това. ТекÑÑ‚ÑŠÑ‚ Ñ‚Ñ€Ñбва да изглежда поне толкова голÑм Ñлед двукратно докоÑване на абзац.</translation>
<translation id="2359808026110333948">Ðапред</translation>
<translation id="2379925928934107488">Прилагане на тъмната тема към Ñайтовете, Ñтига да е възможно и когато Chrome използва тъмната тема</translation>
+<translation id="2387895666653383613">Мащабиране на текÑта</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> МБ</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{ДоÑтъпът до <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> и още <ph name="NUM_MORE" /> е разрешен}other{ДоÑтъпът до <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> и още <ph name="NUM_MORE" /> е разрешен}}</translation>
<translation id="2434158240863470628">ИзтеглÑнето завърши <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">Показване на информациÑта</translation>
<translation id="3123473560110926937">Блокиране на нÑкои Ñайтове</translation>
<translation id="3198916472715691905">СъхранÑвани данни: <ph name="STORAGE_AMOUNT" /></translation>
+<translation id="3203366800380907218">От мрежата</translation>
<translation id="321187648315454507">За да разрешите на <ph name="APP_NAME" /> да ви изпраща извеÑтиÑ, те Ñ‚Ñ€Ñбва да бъдат включени и от <ph name="BEGIN_LINK" />наÑтройките на Android<ph name="END_LINK" />.</translation>
<translation id="3227137524299004712">Микрофон</translation>
<translation id="3277252321222022663">Разрешаване на доÑтъпа на Ñайтовете до Ñензорите (препоръчително)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">Използването на уÑтройÑтвото ви</translation>
<translation id="385051799172605136">Ðазад</translation>
<translation id="3859306556332390985">Придвижване напред</translation>
+<translation id="3895926599014793903">Принудително активиране на промÑната на мащаба</translation>
<translation id="3955193568934677022">Разрешаване на Ñайтовете да възпроизвеждат защитено Ñъдържание (препоръчително)</translation>
<translation id="3967822245660637423">ИзтеглÑнето завърши</translation>
<translation id="3987993985790029246">Връзка: Коп.</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> от ?</translation>
<translation id="4002066346123236978">Заглавие</translation>
<translation id="4008040567710660924">Разрешаване на „биÑквитките“ за конкретен Ñайт.</translation>
+<translation id="4040330681741629921">Получаване на извеÑтие, когато даден Ñайт може да бъде показан в опроÑтен изглед</translation>
<translation id="4046123991198612571">Следващ запиÑ</translation>
+<translation id="4149994727733219643">ОпроÑтен изглед на уеб Ñтраниците</translation>
<translation id="4165986682804962316">ÐаÑтройки за Ñайта</translation>
+<translation id="4194328954146351878">Извеждане на запитване, преди да Ñе разреши на Ñайтовете да четат и променÑÑ‚ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð½Ð° уÑтройÑтва Ñ NFC (препоръчително)</translation>
<translation id="4200726100658658164">ОтварÑне на наÑтройките за меÑтоположението</translation>
<translation id="4226663524361240545">Възможно е уÑтройÑтвото да вибрира при извеÑтиÑ</translation>
<translation id="4259722352634471385">Ðавигирането е блокирано: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">Разгъване</translation>
<translation id="4336434711095810371">ИзчиÑтване на вÑички данни</translation>
<translation id="4402755511846832236">Блокиране на Ñайтовете, така че да не знаÑÑ‚ дали това уÑтройÑтво Ñе използва активно</translation>
+<translation id="4428065317363009941">ПерÑонализиране на рекламите</translation>
<translation id="4434045419905280838">ИзÑкач. прозорци и пренаÑочваниÑ</translation>
<translation id="445467742685312942">Разрешаване на Ñайтовете да възпроизвеждат защитено Ñъдържание</translation>
<translation id="4468959413250150279">Спиране на звука за конкретен Ñайт.</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">ОпциÑта е в горната чаÑÑ‚ на екрана</translation>
<translation id="5197729504361054390">Избраните от Ð²Ð°Ñ ÐºÐ¾Ð½Ñ‚Ð°ÐºÑ‚Ð¸ ще бъдат Ñподелени ÑÑŠÑ Ñайта <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />.</translation>
<translation id="5216942107514965959">ПоÑледно поÑещение: днеÑ</translation>
+<translation id="5264323282659631142">Премахване на „<ph name="CHIP_LABEL" />“</translation>
<translation id="528192093759286357">Плъзнете пръÑÑ‚ от горната чаÑÑ‚ на екрана и докоÑнете бутона за връщане назад, за да излезете от режима на цÑл екран.</translation>
<translation id="5300589172476337783">Показване</translation>
<translation id="5301954838959518834">Добре, разбрах</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">СъхранÑваните от Ñайтовете данни и „биÑквитки“ в размер на <ph name="DATASIZE" /> ще бъдат изчиÑтени.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(и още 1)}other{(и още #)}}</translation>
<translation id="5403592356182871684">Имена</translation>
+<translation id="5412236728747081950">Този Ñайт получава Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð·Ð° интереÑите ви от Chrome, за да ви показва по-подходÑщи реклами</translation>
<translation id="5438097262470833822">Така ще Ñе нулират разрешениÑта за <ph name="WEBSITE" /></translation>
<translation id="5489227211564503167">Изминало време: <ph name="ELAPSED_TIME" /> от <ph name="TOTAL_TIME" />.</translation>
<translation id="5494752089476963479">Блокиране на рекламите от Ñайтове, на които Ñе показват натрапчиви или подвеждащи реклами</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">Повторно зареждане</translation>
<translation id="5596627076506792578">Още опции</translation>
<translation id="5649053991847567735">Ðвтоматични изтеглÑниÑ</translation>
+<translation id="5668404140385795438">ОтмÑна на иÑкането на уебÑайта да не Ñе допуÑка увеличаване на мащаба</translation>
<translation id="5677928146339483299">Блокирано</translation>
<translation id="5689516760719285838">МеÑтоположение</translation>
<translation id="5690795753582697420">Камерата е изключена от наÑтройките на Android</translation>
-<translation id="5710871682236653961">Извеждане на запитване преди разрешаване на Ñайтовете да изпращат и получават Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¿Ñ€Ð¸ допиране на уÑтройÑтва Ñ NFC (препоръчително)</translation>
<translation id="5719847187258001597">Ð’Ñички ÑъхранÑвани от <ph name="ORIGIN" /> или от Ñъответното приложение на Ð½Ð°Ñ‡Ð°Ð»Ð½Ð¸Ñ ÐµÐºÑ€Ð°Ð½ данни и „биÑквитки“ ще бъдат изчиÑтени.</translation>
<translation id="5771720122942595109">ДоÑтъпът до <ph name="PERMISSION_1" /> е блокиран</translation>
<translation id="5804241973901381774">РазрешениÑ</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">ПуÑкане</translation>
<translation id="6818926723028410516">Избор на елементи</translation>
<translation id="6864395892908308021">Това уÑтройÑтво не може да чете NFC</translation>
-<translation id="6910211073230771657">Изтрито</translation>
<translation id="6912998170423641340">ЗабранÑване на Ñайтовете да четат текÑта и изображениÑта от буферната памет</translation>
<translation id="6945221475159498467">Избиране</translation>
<translation id="6965382102122355670">OK</translation>
+<translation id="6981982820502123353">ДоÑтъпноÑÑ‚</translation>
<translation id="6992289844737586249">Извеждане на запитване, преди да Ñе разреши на Ñайтовете да използват микрофона (препоръчително)</translation>
<translation id="7000754031042624318">Изключено от наÑтройките на Android</translation>
<translation id="7016516562562142042">Разрешено за текущата Ñ‚ÑŠÑ€Ñеща машина</translation>
+<translation id="702463548815491781">Препоръчва Ñе, когато TalkBack или доÑтъпът Ñ Ð¿Ñ€ÐµÐ²ÐºÐ»ÑŽÑ‡Ð²Ð°Ð½Ðµ Ñа задейÑтвани</translation>
<translation id="7053983685419859001">Блокиране</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{Избран е 1}other{Избрани Ñа #}}</translation>
-<translation id="7070090581017165256">Ð’Ñичко за този Ñайт</translation>
<translation id="7087918508125750058">Избрани: <ph name="ITEM_COUNT" />. Ðалице Ñа опции близо до горната чаÑÑ‚ на екрана</translation>
<translation id="7141896414559753902">Блокиране на показването на изÑкачащи прозорци и пренаÑÐ¾Ñ‡Ð²Ð°Ð½Ð¸Ñ Ð¾Ñ‚ Ñайтовете (препоръчително)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> КБ</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">Сайт използва микрофона ви</translation>
<translation id="7561196759112975576">Винаги</translation>
-<translation id="7572498721684305250">Блокиране на Ñайтовете, така че да не изпращат и получават Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¿Ñ€Ð¸ допиране на уÑтройÑтва Ñ NFC</translation>
<translation id="757524316907819857">Блокиране на възможноÑтта на Ñайтовете да възпроизвеждат защитено Ñъдържание</translation>
+<translation id="7577900504646297215">Управление на интереÑите</translation>
<translation id="7649070708921625228">Помощ</translation>
<translation id="7658239707568436148">Отказ</translation>
<translation id="7781829728241885113">Вчера</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">Връзката е защитена</translation>
<translation id="8249310407154411074">ПремеÑтване най-горе</translation>
<translation id="8261506727792406068">Изтриване</translation>
+<translation id="8284326494547611709">ÐадпиÑи</translation>
<translation id="8300705686683892304">УправлÑвани от приложение</translation>
<translation id="8324158725704657629">Без повторно питане</translation>
<translation id="8372893542064058268">Разрешаване на Ñинхронизирането на заден план за конкретен Ñайт.</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">Увеличаване на мащаба</translation>
<translation id="8921772741368021346"><ph name="POSITION" />/<ph name="DURATION" /></translation>
<translation id="8926666909099850184">ФункциÑта за NFC е изключена на това уÑтройÑтво. Включете Ñ Ð¾Ñ‚ <ph name="BEGIN_LINK" />наÑтройките на Android<ph name="END_LINK" />.</translation>
+<translation id="8928445016601307354">Блокиране на Ñайтовете, така че да не могат да четат и променÑÑ‚ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð½Ð° уÑтройÑтва Ñ NFC (препоръчително)</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">Блокиране на „биÑквитките“ за конкретен Ñайт.</translation>
<translation id="8959122750345127698">Ðавигирането не е възможно: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_bn.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_bn.xtb
index b8f586a2cf1..f8467d8f82c 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_bn.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_bn.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676"><ph name="SITE_NAME" /> সাইট যোগ করা হয়েছে</translation>
<translation id="1383876407941801731">Search</translation>
<translation id="1384959399684842514">ডাউনলোড পজ করা আছে</translation>
+<translation id="1409426117486808224">খোলা টà§à¦¯à¦¾à¦¬à§‡à¦° জনà§à¦¯ সরলীকৃত ভিউ</translation>
<translation id="1415402041810619267">ইউআরà¦à¦² ছোট করা হয়েছে</translation>
<translation id="1446450296470737166">MIDI ডিভাইসগà§à¦²à¦¿à¦° পূরà§à¦£ নিয়নà§à¦¤à§à¦°à¦£à§‡à¦° অনà§à¦®à¦¤à¦¿ দিন</translation>
<translation id="1620510694547887537">কà§à¦¯à¦¾à¦®à§‡à¦°à¦¾</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">কà§à¦•à¦¿à¦—à§à¦²à¦¿à¦•à§‡ অনà§à¦®à¦¤à¦¿ দিন</translation>
<translation id="2228071138934252756">তাছাড়া, যাতে <ph name="APP_NAME" /> আপনার কà§à¦¯à¦¾à¦®à§‡à¦°à¦¾ অà§à¦¯à¦¾à¦•à§à¦¸à§‡à¦¸ করতে পারে, তার জনà§à¦¯ <ph name="BEGIN_LINK" />Android সেটিংসে<ph name="END_LINK" /> গিয়েও কà§à¦¯à¦¾à¦®à§‡à¦°à¦¾ চালৠকরে দিন।</translation>
<translation id="2241634353105152135">শà§à¦§à§à¦®à¦¾à¦¤à§à¦° à¦à¦•à¦¬à¦¾à¦°</translation>
+<translation id="2253414712144136228"><ph name="NAME_OF_LIST_ITEM" /> সরিয়ে দিন</translation>
<translation id="2289270750774289114">কাছাকাছি বà§à¦²à§à¦Ÿà§à¦¥ ডিভাইস আছে কিনা তা কোনও সাইট খà§à¦à¦œà¦¤à§‡ চাইলে আমাকে জিজà§à¦žà¦¾à¦¸à¦¾ করà§à¦¨ (সাজেসà§à¦Ÿ করা হচà§à¦›à§‡)</translation>
<translation id="2315043854645842844">কà§à¦²à¦¾à§Ÿà§‡à¦¨à§à¦Ÿ সাইড সারà§à¦Ÿà¦¿à¦«à¦¿à¦•à§‡à¦Ÿ নিরà§à¦¬à¦¾à¦šà¦¨ অপারেটিং সিসটেম দà§à¦¬à¦¾à¦°à¦¾ সমরà§à¦¥à¦¿à¦¤ নয়।</translation>
+<translation id="2321958826496381788">আপনি à¦à¦Ÿà¦¿ সà§à¦¬à¦šà§à¦›à¦¨à§à¦¦à§‡ পড়তে না পারা পরà§à¦¯à¦¨à§à¦¤ সà§à¦²à¦¾à¦‡à¦¡à¦¾à¦°à¦Ÿà¦¿ টেনে আনà§à¦¨à§· কোনো অনà§à¦šà§à¦›à§‡à¦¦à§‡ দà§à¦¬à¦¾à¦°-আলতো চাপার পরে পাঠà§à¦¯à¦Ÿà¦¿à¦•à§‡ দেখতে অনà§à¦¤à¦¤à¦ªà¦•à§à¦·à§‡ à¦à¦‡à¦°à¦•à¦® বড় লাগা উচিত৷</translation>
<translation id="2359808026110333948">চালিয়ে যান</translation>
<translation id="2379925928934107488">যখনই সমà§à¦­à¦¬, Chrome-ঠডারà§à¦• থিম বà§à¦¯à¦¬à¦¹à¦¾à¦° করার সময় সাইটে ডারà§à¦• থিম পà§à¦°à§Ÿà§‹à¦— করà§à¦¨</translation>
+<translation id="2387895666653383613">পাঠà§à¦¯ সà§à¦•à§‡à¦²à¦¿à¦‚</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> à¦à¦®à¦¬à¦¿</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ও আরও <ph name="NUM_MORE" />টি সà§à¦¬à¦¿à¦§à¦¾ বà§à¦¯à¦¬à¦¹à¦¾à¦°à§‡à¦° অনà§à¦®à¦¤à¦¿ দেওয়া হয়েছে}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ও আরও <ph name="NUM_MORE" />টি সà§à¦¬à¦¿à¦§à¦¾ বà§à¦¯à¦¬à¦¹à¦¾à¦°à§‡à¦° অনà§à¦®à¦¤à¦¿ দেওয়া হয়েছে}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ও আরও <ph name="NUM_MORE" />টি সà§à¦¬à¦¿à¦§à¦¾ বà§à¦¯à¦¬à¦¹à¦¾à¦°à§‡à¦° অনà§à¦®à¦¤à¦¿ দেওয়া হয়েছে}}</translation>
<translation id="2434158240863470628"><ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /> ডাউনলোড সমà§à¦ªà§‚রà§à¦£ হয়েছে</translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">তথà§à¦¯ দেখà§à¦¨</translation>
<translation id="3123473560110926937">কিছৠসাইটে বà§à¦²à¦• করা হয়েছে</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> সংরকà§à¦·à¦¿à¦¤ ডেটা</translation>
+<translation id="3203366800380907218">ওয়েব থেকে</translation>
<translation id="321187648315454507">তাছাড়া, যাতে <ph name="APP_NAME" /> আপনাকে বিজà§à¦žà¦ªà§à¦¤à¦¿ পাঠাতে পারে, তার জনà§à¦¯ <ph name="BEGIN_LINK" />Android সেটিংসে<ph name="END_LINK" /> গিয়েও বিজà§à¦žà¦ªà§à¦¤à¦¿ চালৠকরে দিন।</translation>
<translation id="3227137524299004712">মাইকà§à¦°à§‹à¦«à§‹à¦¨</translation>
<translation id="3277252321222022663">সাইটকে সেনà§à¦¸à¦° অà§à¦¯à¦¾à¦•à§à¦¸à§‡à¦¸ করার অনà§à¦®à¦¤à¦¿ দিন (সাজেসà§à¦Ÿ করা হয়)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">আপনার ডিভাইসের বà§à¦¯à¦¬à¦¹à¦¾à¦°</translation>
<translation id="385051799172605136">ফিরà§à¦¨</translation>
<translation id="3859306556332390985">সামনে à¦à¦—োন</translation>
+<translation id="3895926599014793903">ফোরà§à¦¸ জà§à¦® চালৠকরà§à¦¨</translation>
<translation id="3955193568934677022">সà§à¦°à¦•à§à¦·à¦¿à¦¤ কনà§à¦Ÿà§‡à¦¨à§à¦Ÿ পà§à¦²à§‡ করতে সাইটগà§à¦²à¦¿à¦•à§‡ মঞà§à¦œà§à¦°à¦¿ দিন (পà§à¦°à¦¸à§à¦¤à¦¾à¦¬à¦¿à¦¤)</translation>
<translation id="3967822245660637423">ডাউনলোড সমà§à¦ªà§‚রà§à¦£</translation>
<translation id="3987993985790029246">লিঙà§à¦• কপি করà§à¦¨</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> / ?</translation>
<translation id="4002066346123236978">শিরোনাম</translation>
<translation id="4008040567710660924">কোনও নিরà§à¦¦à¦¿à¦·à§à¦Ÿ সাইটের জনà§à¦¯ কà§à¦•à¦¿à¦•à§‡ অনà§à¦®à¦¤à¦¿ দিন।</translation>
+<translation id="4040330681741629921">কোনও সাইটে সিমপà§à¦²à¦¿à¦«à¦¾à§Ÿà§‡à¦¡ ভিউ কাজ করলে সেই বিষয়ে বিজà§à¦žà¦ªà§à¦¤à¦¿ পান</translation>
<translation id="4046123991198612571">পরবরà§à¦¤à§€ টà§à¦°à§à¦¯à¦¾à¦•</translation>
+<translation id="4149994727733219643">ওয়েব পৃষà§à¦ à¦¾à¦° জনà§à¦¯ সরলীকৃত ভিউ</translation>
<translation id="4165986682804962316">সাইটের সেটিংস</translation>
+<translation id="4194328954146351878">সাইটগà§à¦²à¦¿à¦•à§‡ NFC ডিভাইসে তথà§à¦¯ দেখতে à¦à¦¬à¦‚ পরিবরà§à¦¤à¦¨ করার অনà§à¦®à¦¤à¦¿ দেওয়ার আগে জিজà§à¦žà¦¾à¦¸à¦¾ করে নিন (পà§à¦°à¦¸à§à¦¤à¦¾à¦¬à¦¿à¦¤)</translation>
<translation id="4200726100658658164">লোকেশন সেটিংস খà§à¦²à§à¦¨</translation>
<translation id="4226663524361240545">বিজà§à¦žà¦ªà§à¦¤à¦¿ আসলে ডিভাইস ভাইবà§à¦°à§‡à¦Ÿ হতে পারে</translation>
<translation id="4259722352634471385">নেভিগেশন অবরà§à¦¦à§à¦§ করা হয়েছে: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">পà§à¦°à¦¸à¦¾à¦°à¦¿à¦¤ করà§à¦¨</translation>
<translation id="4336434711095810371">সব ডেটা মà§à¦›à§‡ ফেলà§à¦¨</translation>
<translation id="4402755511846832236">আপনি ডিভাইস কখন সকà§à¦°à¦¿à§Ÿà¦­à¦¾à¦¬à§‡ বà§à¦¯à¦¬à¦¹à¦¾à¦° করছেন, সাইট যাতে জানতে না পারে তার জনà§à¦¯ সাইট বà§à¦²à¦• করà§à¦¨</translation>
+<translation id="4428065317363009941">পছনà§à¦¦ অনà§à¦¯à¦¾à§Ÿà§€ বিজà§à¦žà¦¾à¦ªà¦¨ বেছে নেওয়া</translation>
<translation id="4434045419905280838">পপ-আপ à¦à¦¬à¦‚ রিডাইরেকà§à¦Ÿ</translation>
<translation id="445467742685312942">সাইটকে সà§à¦°à¦•à§à¦·à¦¿à¦¤ কনà§à¦Ÿà§‡à¦¨à§à¦Ÿ চালানোর জনà§à¦¯ অনà§à¦®à¦¤à¦¿ দিন</translation>
<translation id="4468959413250150279">নিরà§à¦¦à¦¿à¦·à§à¦Ÿ কোনও সাইটের জনà§à¦¯ সাউনà§à¦¡ মিউট করà§à¦¨à¥¤</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">সà§à¦•à§à¦°à¦¿à¦¨à§‡à¦° উপরের দিকে বিকলà§à¦ªà¦—à§à¦²à¦¿ দেখানো হয়েছে</translation>
<translation id="5197729504361054390">আপনার বেছে নেওয়া পরিচিতি <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />-à¦à¦° সাথে শেয়ার করা হবে।</translation>
<translation id="5216942107514965959">আজ শেষবার দেখা হয়েছে</translation>
+<translation id="5264323282659631142">'<ph name="CHIP_LABEL" />' সরান</translation>
<translation id="528192093759286357">উপর থেকে টেনে আনà§à¦¨ à¦à¦¬à¦‚ পূরà§à¦£ সà§à¦•à§à¦°à¦¿à¦¨ থেকে বেরিয়ে যেতে পিছনে ফেরার বোতাম সà§à¦ªà¦°à§à¦¶ করà§à¦¨à¥¤</translation>
<translation id="5300589172476337783">দেখান</translation>
<translation id="5301954838959518834">ঠিক আছে, বà§à¦à§‡à¦›à¦¿</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">à¦à¦Ÿà¦¿ করলে, সাইটে সেভ থাকা <ph name="DATASIZE" /> ডেটা ও কà§à¦•à¦¿ মà§à¦›à§‡ যাবে।</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(à¦à¦›à¦¾à¦¡à¦¼à¦¾ আরও ১টি)}one{(à¦à¦›à¦¾à¦¡à¦¼à¦¾ আরও #টি)}other{(à¦à¦›à¦¾à¦¡à¦¼à¦¾ আরও #টি)}}</translation>
<translation id="5403592356182871684">নাম</translation>
+<translation id="5412236728747081950">à¦à¦‡ সাইটটি আপনাকে আরও পà§à¦°à¦¾à¦¸à¦™à§à¦—িক বিজà§à¦žà¦¾à¦ªà¦¨ দেখানোর জনà§à¦¯ Chrome থেকে আপনার আগà§à¦°à¦¹à¦—à§à¦²à¦¿ নেয়।</translation>
<translation id="5438097262470833822">à¦à¦‡ পছনà§à¦¦ <ph name="WEBSITE" />-à¦à¦° অনà§à¦®à¦¤à¦¿ আবার সেট করবে</translation>
<translation id="5489227211564503167"><ph name="TOTAL_TIME" />-à¦à¦° মধà§à¦¯à§‡ <ph name="ELAPSED_TIME" /> সময় অতিবাহিত হয়েছে।</translation>
<translation id="5494752089476963479">সাইটে থাকা বà§à¦¯à¦¾à¦˜à¦¾à¦¤ সৃষà§à¦Ÿà¦¿à¦•à¦¾à¦°à§€ বা বিভà§à¦°à¦¾à¦¨à§à¦¤à¦¿à¦•à¦° বিজà§à¦žà¦¾à¦ªà¦¨ বà§à¦²à¦• করà§à¦¨</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">রিলোড করà§à¦¨</translation>
<translation id="5596627076506792578">আরও বিকলà§à¦ªà¦—à§à¦²à¦¿</translation>
<translation id="5649053991847567735">অটোমেটিক ডাউনলোডগà§à¦²à¦¿</translation>
+<translation id="5668404140385795438">কোনো ওয়েবসাইটের জà§à¦® ইন পà§à¦°à¦¤à¦¿à¦°à§‹à¦§ করার অনà§à¦°à§‹à¦§ উপেকà§à¦·à¦¾ করà§à¦¨</translation>
<translation id="5677928146339483299">অবরà§à¦¦à§à¦§</translation>
<translation id="5689516760719285838">লোকেশন</translation>
<translation id="5690795753582697420">Android সেটিংসে কà§à¦¯à¦¾à¦®à§‡à¦°à¦¾ বনà§à¦§ করা আছে</translation>
-<translation id="5710871682236653961">NFC ডিভাইসে টà§à¦¯à¦¾à¦ª করলে (সাজেসà§à¦Ÿ করা হয়েছে) সাইট থেকে তথà§à¦¯ পাঠানো বা পাওয়ার আগে অনà§à¦®à¦¤à¦¿ নিতে হবে</translation>
<translation id="5719847187258001597">à¦à¦Ÿà¦¿ করলে, আপনার হোম সà§à¦•à§à¦°à¦¿à¦¨à§‡ <ph name="ORIGIN" />-à¦à¦° মাধà§à¦¯à¦®à§‡ বা à¦à¦° সাইট ও অà§à¦¯à¦¾à¦ªà§‡à¦° মাধà§à¦¯à¦®à§‡ সেভ হওয়া সব ডেটা à¦à¦¬à¦‚ কà§à¦•à¦¿ মà§à¦›à§‡ যাবে।</translation>
<translation id="5771720122942595109"><ph name="PERMISSION_1" /> বà§à¦²à¦• করা হয়েছে</translation>
<translation id="5804241973901381774">অনà§à¦®à¦¤à¦¿à¦—à§à¦²à¦¿</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">চালৠকরà§à¦¨</translation>
<translation id="6818926723028410516">আইটেম বেছে নিন</translation>
<translation id="6864395892908308021">à¦à¦‡ ডিভাইস NFC পড়তে পারছে না</translation>
-<translation id="6910211073230771657">মোছা হয়েছে</translation>
<translation id="6912998170423641340">কà§à¦²à¦¿à¦ªà¦¬à§‹à¦°à§à¦¡à§‡à¦° টেকà§à¦¸à¦Ÿ à¦à¦¬à¦‚ ছবি পড়ার থেকে সাইটগà§à¦²à¦¿à¦•à§‡ বà§à¦²à¦• করà§à¦¨</translation>
<translation id="6945221475159498467">নিরà§à¦¬à¦¾à¦šà¦¨</translation>
<translation id="6965382102122355670">ঠিক আছে</translation>
+<translation id="6981982820502123353">বà§à¦¯à¦¬à¦¹à¦¾à¦°à¦¯à§‹à¦—à§à¦¯à¦¤à¦¾</translation>
<translation id="6992289844737586249">সাইটগà§à¦²à¦¿à¦•à§‡ আপনার মাইকà§à¦°à§‹à¦«à§‹à¦¨ বà§à¦¯à¦¬à¦¹à¦¾à¦° করতে দিতে মঞà§à¦œà§à¦°à¦¿ দেওয়ার আগে পà§à¦°à¦¥à¦®à§‡ জিজà§à¦žà¦¾à¦¸à¦¾ করà§à¦¨ (পà§à¦°à¦¸à§à¦¤à¦¾à¦¬à¦¿à¦¤)</translation>
<translation id="7000754031042624318">Android সেটিংসে বনà§à¦§ করা আছে</translation>
<translation id="7016516562562142042">বরà§à¦¤à¦®à¦¾à¦¨ সারà§à¦š ইঞà§à¦œà¦¿à¦¨à§‡à¦° জনà§à¦¯ অনà§à¦®à§‹à¦¦à¦¨ দেওয়া হয়েছে</translation>
+<translation id="702463548815491781">'টকবà§à¦¯à¦¾à¦•' অথবা 'অà§à¦¯à¦¾à¦•à§à¦¸à§‡à¦¸ পরিবরà§à¦¤à¦¨ করà§à¦¨' চালৠকরা থাকলে à¦à¦Ÿà¦¿ করার সাজেশন পাবেন</translation>
<translation id="7053983685419859001">বà§à¦²à¦• করà§à¦¨</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{১টি বেছে নেওয়া হয়েছে}one{#টি বেছে নেওয়া হয়েছে}other{#টি বেছে নেওয়া হয়েছে}}</translation>
-<translation id="7070090581017165256">à¦à¦‡ সাইটের বিষয়ে</translation>
<translation id="7087918508125750058"><ph name="ITEM_COUNT" /> বেছে নেওয়া হয়েছে। সà§à¦•à§à¦°à¦¿à¦¨à§‡à¦° উপরে বিকলà§à¦ªà¦—à§à¦²à¦¿ পাওয়া যাবে</translation>
<translation id="7141896414559753902">সাইটগà§à¦²à¦¿à¦•à§‡ পপ-আপ দেখাতে à¦à¦¬à¦‚ রিডাইরেকà§à¦Ÿ করা থেকে বাধা দিন (পà§à¦°à¦¸à§à¦¤à¦¾à¦¬à¦¿à¦¤)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> কেবি</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">জাভাসà§à¦•à§à¦°à¦¿à¦ªà§à¦Ÿ</translation>
<translation id="7554752735887601236">à¦à¦•à¦Ÿà¦¿ সাইট আপনার মাইকà§à¦°à§‹à¦«à§‹à¦¨ বà§à¦¯à¦¬à¦¹à¦¾à¦° করছে</translation>
<translation id="7561196759112975576">সবসময়</translation>
-<translation id="7572498721684305250">আপনি NFC ডিভাইসে টà§à¦¯à¦¾à¦ª করলে সাইট থেকে তথà§à¦¯ পাঠানো ও পাওয়া, কোনওটাই করা যাবে না</translation>
<translation id="757524316907819857">সà§à¦°à¦•à§à¦·à¦¿à¦¤ কনà§à¦Ÿà§‡à¦¨à§à¦Ÿ চালানো থেকে সাইটকে বà§à¦²à¦• করà§à¦¨</translation>
+<translation id="7577900504646297215">আপনার পছনà§à¦¦ মà§à¦¯à¦¾à¦¨à§‡à¦œ করà§à¦¨</translation>
<translation id="7649070708921625228">সহায়তা</translation>
<translation id="7658239707568436148">বাতিল</translation>
<translation id="7781829728241885113">গতকাল</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">কানেকশনটি নিরাপদ</translation>
<translation id="8249310407154411074">শীরà§à¦·à§‡ সরান</translation>
<translation id="8261506727792406068">মà§à¦›à§à¦¨</translation>
+<translation id="8284326494547611709">পরিচয়লিপিগà§à¦²à¦¿</translation>
<translation id="8300705686683892304">অà§à¦¯à¦¾à¦ª মà§à¦¯à¦¾à¦¨à§‡à¦œ করে</translation>
<translation id="8324158725704657629">আর দেখতে চাই না</translation>
<translation id="8372893542064058268">à¦à¦•à¦Ÿà¦¿ নিরà§à¦¦à¦¿à¦·à§à¦Ÿ সাইটের জনà§à¦¯ পটভূমি সিঙà§à¦•à§‡à¦° অনà§à¦®à¦¤à¦¿ দিন।</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">জà§à¦® বাড়ান</translation>
<translation id="8921772741368021346"><ph name="POSITION" /> / <ph name="DURATION" /></translation>
<translation id="8926666909099850184">à¦à¦‡ ডিভাইসে NFC বনà§à¦§ আছে। <ph name="BEGIN_LINK" />Android সেটিংস<ph name="END_LINK" /> থেকে à¦à¦Ÿà¦¿ চালৠকরà§à¦¨à¥¤</translation>
+<translation id="8928445016601307354">NFC ডিভাইসে তথà§à¦¯ দেখা à¦à¦¬à¦‚ পরিবরà§à¦¤à¦¨ করা থেকে সাইটগà§à¦²à¦¿à¦•à§‡ বà§à¦²à¦• করà§à¦¨</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">কোনও নিরà§à¦¦à¦¿à¦·à§à¦Ÿ সাইটের জনà§à¦¯ কà§à¦•à¦¿ বà§à¦²à¦• করà§à¦¨à¥¤</translation>
<translation id="8959122750345127698">নেভিগেশানে পৌছানো যাচà§à¦›à§‡ না: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_bs.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_bs.xtb
index 9cddc332103..726abbb4bc9 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_bs.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_bs.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">Web lokacija <ph name="SITE_NAME" /> je dodana</translation>
<translation id="1383876407941801731">Traži</translation>
<translation id="1384959399684842514">Preuzimanje je pauzirano</translation>
+<translation id="1409426117486808224">Pojednostavljeni prikaz za otvaranje kartica</translation>
<translation id="1415402041810619267">URL je odsjeÄen</translation>
<translation id="1446450296470737166">Puna kontrola MIDI uređaja</translation>
<translation id="1620510694547887537">Kamera</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">Dozvoli kolaÄiće</translation>
<translation id="2228071138934252756">Da omogućite aplikaciji <ph name="APP_NAME" /> pristup kameri, takoÄ‘er ukljuÄite kameru u <ph name="BEGIN_LINK" />Postavkama Androida<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Samo ovaj put</translation>
+<translation id="2253414712144136228">Uklanjanje stavke <ph name="NAME_OF_LIST_ITEM" /></translation>
<translation id="2289270750774289114">Pitaj kada web lokacija želi otkriti Bluetooth ureÄ‘aje u blizini (preporuÄeno)</translation>
<translation id="2315043854645842844">Operativni sistem ne podržava odabir potvrde na strani klijenta.</translation>
+<translation id="2321958826496381788">PovlaÄite klizaÄ dok vam tekst ne bude ugodan za Äitanje. Nakon dvostrukog dodira na pasus, tekst bi trebao izgledati najmanje ove veliÄine.</translation>
<translation id="2359808026110333948">Nastavi</translation>
<translation id="2379925928934107488">Tamna tema će se primjenjivati na web lokacije kada Chrome koristi tamnu temu, kada je to moguće</translation>
+<translation id="2387895666653383613">Promjena veliÄine teksta</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Dozvoljeno: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i još <ph name="NUM_MORE" />}one{Dozvoljeno: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i još <ph name="NUM_MORE" />}few{Dozvoljeno: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i još <ph name="NUM_MORE" />}other{Dozvoljeno: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i još <ph name="NUM_MORE" />}}</translation>
<translation id="2434158240863470628">Preuzimanje je završeno <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">Prikaži informacije</translation>
<translation id="3123473560110926937">Blokirano na nekim web lokacijama</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> pohranjenih podataka</translation>
+<translation id="3203366800380907218">S interneta</translation>
<translation id="321187648315454507">Da dozvolite da vam aplikacija <ph name="APP_NAME" /> Å¡alje obavjeÅ¡tenja, takoÄ‘er ukljuÄite obavjeÅ¡tenja u <ph name="BEGIN_LINK" />Postavkama Androida<ph name="END_LINK" />.</translation>
<translation id="3227137524299004712">Mikrofon</translation>
<translation id="3277252321222022663">Dozvolite web lokacijama pristup senzorima (preporuÄeno)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">Korištenje vašeg uređaja</translation>
<translation id="385051799172605136">Nazad</translation>
<translation id="3859306556332390985">Pomakni naprijed</translation>
+<translation id="3895926599014793903">Prisilno omogući zumiranje</translation>
<translation id="3955193568934677022">Dozvoljava web lokacijama da reproduciraju zaÅ¡tićeni sadržaj (preporuÄeno)</translation>
<translation id="3967822245660637423">Preuzimanje je završeno</translation>
<translation id="3987993985790029246">Kopiraj link</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" />/?</translation>
<translation id="4002066346123236978">Naslov</translation>
<translation id="4008040567710660924">Omogućavanje kolaÄića za odreÄ‘enu web lokaciju.</translation>
+<translation id="4040330681741629921">Primajte obavještenja kada se web lokacija može prikazati u pojednostavljenom prikazu</translation>
<translation id="4046123991198612571">Sljedeća pjesma</translation>
+<translation id="4149994727733219643">Pojednostavljeni prikaz za web lokacije</translation>
<translation id="4165986682804962316">Postavke web-lokacije</translation>
+<translation id="4194328954146351878">Web lokacije moraju tražiti odobrenje za pregled i izmjenu informacija na NFC ureÄ‘ajima (preporuÄeno)</translation>
<translation id="4200726100658658164">Otvaranje postavki lokacije</translation>
<translation id="4226663524361240545">Obavještenja mogu aktivirati vibraciju uređaja</translation>
<translation id="4259722352634471385">Navigacija je blokirana: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">Proširi</translation>
<translation id="4336434711095810371">Obriši sve podatke</translation>
<translation id="4402755511846832236">Blokirajte web lokacijama informacije o vašem aktivnom korištenju ovog uređaja</translation>
+<translation id="4428065317363009941">Personalizacija oglasa</translation>
<translation id="4434045419905280838">SkoÄni proz. i preusmjeravanja</translation>
<translation id="445467742685312942">Dozvoljava web lokacijama da reproduciraju zaštićen sadržaj</translation>
<translation id="4468959413250150279">IskljuÄen zvuk za odreÄ‘enu web lokaciju.</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">Opcije su dostupne pri vrhu ekrana</translation>
<translation id="5197729504361054390">Kontakti koje odaberete će se podijeliti s web lokacijom <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />.</translation>
<translation id="5216942107514965959">Posljednji put je posjećeno danas</translation>
+<translation id="5264323282659631142">Uklanjanje stavke "<ph name="CHIP_LABEL" />"</translation>
<translation id="528192093759286357">Povucite s vrha i dodirnite dugme za nazad da napustite prikaz preko cijelog ekrana.</translation>
<translation id="5300589172476337783">Prikaži</translation>
<translation id="5301954838959518834">Uredu, razumijem</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">Ovim će se obrisati <ph name="DATASIZE" /> podataka i kolaÄića koje su pohranile web lokacije.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(i još 1)}one{(i još #)}few{(i još #)}other{(i još #)}}</translation>
<translation id="5403592356182871684">Imena</translation>
+<translation id="5412236728747081950">Ova web lokacija prikuplja vaša interesovanja iz Chromea da vam prikazuje relevantnije oglase</translation>
<translation id="5438097262470833822">Ovim odabirom će se poništiti odobrenja za web lokaciju <ph name="WEBSITE" /></translation>
<translation id="5489227211564503167">Proteklo vrijeme <ph name="ELAPSED_TIME" /> od <ph name="TOTAL_TIME" />.</translation>
<translation id="5494752089476963479">Blokiraj oglase na web lokacijama koje prikazuju nametljive ili obmanjujuće oglase</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">UÄitaj ponovo</translation>
<translation id="5596627076506792578">Više opcija</translation>
<translation id="5649053991847567735">Automatska preuzimanja</translation>
+<translation id="5668404140385795438">Zaobilaženje zahtjeva web lokacije kako bi se sprijeÄilo zumiranje</translation>
<translation id="5677928146339483299">Blokirano</translation>
<translation id="5689516760719285838">Lokacija</translation>
<translation id="5690795753582697420">Kamera je iskljuÄena u postavkama Androida</translation>
-<translation id="5710871682236653961">Web lokacije moraju tražiti dozvolu za slanje i primanje informacija kada dodirnete NFC ureÄ‘aje (preporuÄeno)</translation>
<translation id="5719847187258001597">Ovim će se obrisati svi podaci i kolaÄići koje je pohranila web lokacija <ph name="ORIGIN" /> ili njena aplikacija na poÄetnom ekranu.</translation>
<translation id="5771720122942595109">Blokirano: <ph name="PERMISSION_1" /></translation>
<translation id="5804241973901381774">Odobrenja</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">Pokreni</translation>
<translation id="6818926723028410516">Odaberite stavke</translation>
<translation id="6864395892908308021">Ovaj ureÄ‘aj ne može oÄitavati NFC</translation>
-<translation id="6910211073230771657">Izbrisano</translation>
<translation id="6912998170423641340">Blokirajte web lokacijama Äitanje teksta i pregled slika u meÄ‘umemoriji</translation>
<translation id="6945221475159498467">Odaberi</translation>
<translation id="6965382102122355670">Uredu</translation>
+<translation id="6981982820502123353">PristupaÄnost</translation>
<translation id="6992289844737586249">Web-lokacije moraju tražiti dopuÅ¡tenje za upotrebu mikrofona (preporuÄeno)</translation>
<translation id="7000754031042624318">IskljuÄeno u postavkama Androida</translation>
<translation id="7016516562562142042">Dozvoljeno za trenutni pretraživaÄ</translation>
+<translation id="702463548815491781">PreporuÄeno kada je ukljuÄena funkcija TalkBack ili prekidaÄ za pristup.</translation>
<translation id="7053983685419859001">Blokiraj</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1 odabrana kartica}one{# odabrana kartica}few{# odabrane kartice}other{# odabranih kartica}}</translation>
-<translation id="7070090581017165256">O ovoj web lokaciji</translation>
<translation id="7087918508125750058">Odabrali ste <ph name="ITEM_COUNT" />. Opcije su dostupne pri vrhu ekrana</translation>
<translation id="7141896414559753902">Blokiranje prikazivanja skoÄnih prozora na web lokacijama i preusmjeravanje (preporuÄeno)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> kB</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">Web lokacija koristi vaš mikrofon</translation>
<translation id="7561196759112975576">Uvijek</translation>
-<translation id="7572498721684305250">Blokirajte stranicama slanje i primanje informacija kada dodirnete NFC uređaje</translation>
<translation id="757524316907819857">Blokirajte reproduciranje zaštićenog sadržaja na web lokacijama</translation>
+<translation id="7577900504646297215">Upravljajte interesovanjima</translation>
<translation id="7649070708921625228">Pomoć</translation>
<translation id="7658239707568436148">Otkaži</translation>
<translation id="7781829728241885113">JuÄer</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">Veza je sigurna</translation>
<translation id="8249310407154411074">Premjesti na vrh</translation>
<translation id="8261506727792406068">Izbriši</translation>
+<translation id="8284326494547611709">Titlovi</translation>
<translation id="8300705686683892304">Upravlja aplikacija</translation>
<translation id="8324158725704657629">Ne pitaj ponovo</translation>
<translation id="8372893542064058268">Dozvolite sinhronizaciju u pozadini za određenu web lokaciju.</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">Uvećaj</translation>
<translation id="8921772741368021346"><ph name="POSITION" /> / <ph name="DURATION" /></translation>
<translation id="8926666909099850184">NFC je iskljuÄen na ovom ureÄ‘aju. UkljuÄite ga u <ph name="BEGIN_LINK" />Postavkama Androida<ph name="END_LINK" />.</translation>
+<translation id="8928445016601307354">Blokirajte web lokacijama pregled i izmjenu informacija na NFC uređajima</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">Blokiranje kolaÄića za odreÄ‘enu web lokaciju.</translation>
<translation id="8959122750345127698">Navigacija je nedostupna: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ca.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ca.xtb
index f9a983facbb..e2756a8bb23 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ca.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ca.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">El lloc <ph name="SITE_NAME" /> s'ha afegit</translation>
<translation id="1383876407941801731">Cerca</translation>
<translation id="1384959399684842514">La baixada s'ha posat en pausa</translation>
+<translation id="1409426117486808224">Visualització simplificada de les pestanyes obertes</translation>
<translation id="1415402041810619267">L'URL s'ha truncat</translation>
<translation id="1446450296470737166">Permet control total disp. MIDI</translation>
<translation id="1620510694547887537">Càmera</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">Permet les galetes</translation>
<translation id="2228071138934252756">Perquè <ph name="APP_NAME" /> pugui accedir a la càmera, també has d'activar-la a la <ph name="BEGIN_LINK" />configuració d'Android<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Només una vegada</translation>
+<translation id="2253414712144136228">Suprimeix <ph name="NAME_OF_LIST_ITEM" /></translation>
<translation id="2289270750774289114">Pregunta'm quan un lloc web vulgui descobrir dispositius Bluetooth propers (opció recomanada)</translation>
<translation id="2315043854645842844">El sistema operatiu no permet seleccionar el certificat del client.</translation>
+<translation id="2321958826496381788">Arrossega el control lliscant fins que puguis llegir aquest text còmodament. El text ha de ser almenys així de gran després de tocar dos cops un paràgraf.</translation>
<translation id="2359808026110333948">Continua</translation>
<translation id="2379925928934107488">Aplica el tema fosc als llocs web quan Chrome l'utilitzi i sigui possible</translation>
+<translation id="2387895666653383613">Ajust del text</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{S'han permès <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i <ph name="NUM_MORE" /> més}other{S'han permès <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i <ph name="NUM_MORE" /> més}}</translation>
<translation id="2434158240863470628">S'ha completat la baixada <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">Mostra la informació</translation>
<translation id="3123473560110926937">Bloquejat en alguns llocs web</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> de dades desades</translation>
+<translation id="3203366800380907218">Del web</translation>
<translation id="321187648315454507">Perquè <ph name="APP_NAME" /> et pugui enviar notificacions, també has d'activar-les a la <ph name="BEGIN_LINK" />configuració d'Android<ph name="END_LINK" />.</translation>
<translation id="3227137524299004712">Micròfon</translation>
<translation id="3277252321222022663">Permet que els llocs web accedeixin als sensors (opció recomanada)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">L'ús que fas del dispositiu</translation>
<translation id="385051799172605136">Enrere</translation>
<translation id="3859306556332390985">Avança</translation>
+<translation id="3895926599014793903">Força l'activació del zoom</translation>
<translation id="3955193568934677022">Permet que els llocs web reprodueixin contingut protegit (opció recomanada)</translation>
<translation id="3967822245660637423">S'ha completat la baixada</translation>
<translation id="3987993985790029246">Copia l'enllaç</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" />/?</translation>
<translation id="4002066346123236978">Títol</translation>
<translation id="4008040567710660924">Permet les galetes d'un lloc web concret.</translation>
+<translation id="4040330681741629921">Rep una notificació quan un lloc web es pugui mostrar en visualització simplificada</translation>
<translation id="4046123991198612571">Pista següent</translation>
+<translation id="4149994727733219643">Visualització simplificada de pàgines web</translation>
<translation id="4165986682804962316">Configuració del lloc web</translation>
+<translation id="4194328954146351878">Pregunta abans de permetre que els llocs web vegin i canviïn la informació que hi ha als dispositius amb NFC (opció recomanada)</translation>
<translation id="4200726100658658164">Obre la configuració d'ubicació</translation>
<translation id="4226663524361240545">És possible que les notificacions facin vibrar el dispositiu</translation>
<translation id="4259722352634471385">S'ha bloquejat la navegació: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">Desplega</translation>
<translation id="4336434711095810371">Esborra totes les dades</translation>
<translation id="4402755511846832236">Bloqueja els llocs web perquè no sàpiguen quan estàs utilitzant aquest dispositiu de manera activa</translation>
+<translation id="4428065317363009941">Personalització d'anuncis</translation>
<translation id="4434045419905280838">Finestres emergents i redireccions</translation>
<translation id="445467742685312942">Permet que els llocs web reprodueixin contingut protegit</translation>
<translation id="4468959413250150279">Silencia el so d'un lloc web concret.</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">L'opció està disponible a prop de la part superior de la pantalla.</translation>
<translation id="5197729504361054390">Els contactes que seleccionis es compartiran amb <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />.</translation>
<translation id="5216942107514965959">Darrera visita: avui</translation>
+<translation id="5264323282659631142">Suprimeix <ph name="CHIP_LABEL" /></translation>
<translation id="528192093759286357">Arrossegueu la pantalla des de la part superior i toqueu el botó Enrere per sortir de la pantalla completa.</translation>
<translation id="5300589172476337783">Mostra</translation>
<translation id="5301954838959518834">D'acord</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">Amb aquesta acció s'esborraran dades i galetes (<ph name="DATASIZE" />) emmagatzemades per llocs web.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(i 1 més)}other{(i # més)}}</translation>
<translation id="5403592356182871684">Noms</translation>
+<translation id="5412236728747081950">Aquest lloc web obté els teus interessos de Chrome per mostrar-te anuncis més rellevants</translation>
<translation id="5438097262470833822">Amb aquesta opció, es restabliran els permisos per a <ph name="WEBSITE" /></translation>
<translation id="5489227211564503167">Temps transcorregut: <ph name="ELAPSED_TIME" /> de <ph name="TOTAL_TIME" />.</translation>
<translation id="5494752089476963479">Bloqueja els anuncis als llocs web que mostren publicitat intrusiva o enganyosa</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">Torna a carregar</translation>
<translation id="5596627076506792578">Més opcions</translation>
<translation id="5649053991847567735">Baixades automàtiques</translation>
+<translation id="5668404140385795438">Ignora la sol·licitud d'un lloc web per evitar que s'apropi la imatge</translation>
<translation id="5677928146339483299">Bloquejat</translation>
<translation id="5689516760719285838">Ubicació</translation>
<translation id="5690795753582697420">La càmera està desactivada a la configuració d'Android</translation>
-<translation id="5710871682236653961">Pregunta abans de permetre que els llocs web enviïn i rebin informació quan toquis dispositius amb NFC (opció recomanada)</translation>
<translation id="5719847187258001597">Amb aquesta acció s'esborraran totes les dades i galetes emmagatzemades per <ph name="ORIGIN" /> o per la seva aplicació de la pantalla d'inici.</translation>
<translation id="5771720122942595109">S'ha bloquejat <ph name="PERMISSION_1" /></translation>
<translation id="5804241973901381774">Permisos</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">Reprodueix</translation>
<translation id="6818926723028410516">Selecciona elements</translation>
<translation id="6864395892908308021">Aquest dispositiu no pot llegir NFC</translation>
-<translation id="6910211073230771657">Suprimit</translation>
<translation id="6912998170423641340">Impedeix que els llocs web llegeixin el text i les imatges del porta-retalls</translation>
<translation id="6945221475159498467">Selecciona</translation>
<translation id="6965382102122355670">D'acord</translation>
+<translation id="6981982820502123353">Accessibilitat</translation>
<translation id="6992289844737586249">Pregunta abans de permetre que els llocs web utilitzin el micròfon (opció recomanada)</translation>
<translation id="7000754031042624318">Desactivat a la configuració d'Android</translation>
<translation id="7016516562562142042">Es permet al motor de cerca actual</translation>
+<translation id="702463548815491781">Es recomana quan TalkBack o l'accés amb interruptors estan activats</translation>
<translation id="7053983685419859001">Bloqueja</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1 seleccionat}other{# seleccionats}}</translation>
-<translation id="7070090581017165256">Sobre aquest lloc web</translation>
<translation id="7087918508125750058"><ph name="ITEM_COUNT" /> elements seleccionats. Hi ha opcions disponibles a prop de la part superior de la pantalla.</translation>
<translation id="7141896414559753902">Bloqueja les finestres emergents i les redireccions als llocs web (opció recomanada)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> kB</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">Un lloc web està utilitzant el micròfon</translation>
<translation id="7561196759112975576">Sempre</translation>
-<translation id="7572498721684305250">Evita que els llocs web enviïn i rebin informació quan toquis dispositius amb NFC</translation>
<translation id="757524316907819857">Impedeix que els llocs web reprodueixin contingut protegit</translation>
+<translation id="7577900504646297215">Gestiona els interessos</translation>
<translation id="7649070708921625228">Ajuda</translation>
<translation id="7658239707568436148">Cancel·la</translation>
<translation id="7781829728241885113">Ahir</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">La connexió és segura</translation>
<translation id="8249310407154411074">Mou a la part superior</translation>
<translation id="8261506727792406068">Suprimeix</translation>
+<translation id="8284326494547611709">Subtítols</translation>
<translation id="8300705686683892304">Gestionats per aplicacions</translation>
<translation id="8324158725704657629">No m'ho tornis a preguntar</translation>
<translation id="8372893542064058268">Permet la sincronització en segon pla en un lloc concret.</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">Amplia</translation>
<translation id="8921772741368021346"><ph name="POSITION" />/<ph name="DURATION" /></translation>
<translation id="8926666909099850184">L'NFC està desactivada en aquest dispositiu. Activa-la a la <ph name="BEGIN_LINK" />configuració d'Android<ph name="END_LINK" />.</translation>
+<translation id="8928445016601307354">Bloqueja els llocs web perquè no vegin ni canviïn la informació que hi ha als dispositius amb NFC</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">Bloqueja les galetes d'un lloc web concret.</translation>
<translation id="8959122750345127698">No es pot accedir a la navegació: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_cs.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_cs.xtb
index a1fd9b82d36..02bf396ca7c 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_cs.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_cs.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">Byl přidán web <ph name="SITE_NAME" /></translation>
<translation id="1383876407941801731">Vyhledávání</translation>
<translation id="1384959399684842514">Stahování pozastaveno</translation>
+<translation id="1409426117486808224">Zjednodušené zobrazení otevřených karet</translation>
<translation id="1415402041810619267">Zkrácená adresa URL</translation>
<translation id="1446450296470737166">Povolit úplné ovládání zařízení MIDI</translation>
<translation id="1620510694547887537">Kamera</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">Povolit cookies</translation>
<translation id="2228071138934252756">Pokud aplikaci <ph name="APP_NAME" /> chcete umožnit přístup k fotoaparátu, zapněte fotoaparát také v <ph name="BEGIN_LINK" />Nastavení Android<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Pouze jednou</translation>
+<translation id="2253414712144136228">Odstranit položku <ph name="NAME_OF_LIST_ITEM" /></translation>
<translation id="2289270750774289114">Zeptat se, když chce web objevit zařízení Bluetooth v okolí (doporuÄeno)</translation>
<translation id="2315043854645842844">Volbu certifikátu na stranÄ› klienta operaÄní systém nepodporuje.</translation>
+<translation id="2321958826496381788">PÅ™etahujte posuvník tak dlouho, dokud nebudete moci pohodlnÄ› pÅ™eÄíst tento text. Po dvojitém klepnutí na odstavec by mÄ›l být text alespoň takto velký.</translation>
<translation id="2359808026110333948">PokraÄovat</translation>
<translation id="2379925928934107488">Když Chrome používá tmavý motiv, použít ho i pro Chrome (pokud je to možné)</translation>
+<translation id="2387895666653383613">Zvětšení/zmenšení textu</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Povolená oprávnění: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> a další (<ph name="NUM_MORE" />)}few{Povolená oprávnění: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> a další (<ph name="NUM_MORE" />)}many{Povolená oprávnění: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> a další (<ph name="NUM_MORE" />)}other{Povolená oprávnění: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> a další (<ph name="NUM_MORE" />)}}</translation>
<translation id="2434158240863470628">Stažení bylo dokonÄeno <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">Zobrazit informace</translation>
<translation id="3123473560110926937">Na některých webech blokováno</translation>
<translation id="3198916472715691905">Uložená data: <ph name="STORAGE_AMOUNT" /></translation>
+<translation id="3203366800380907218">Z webu</translation>
<translation id="321187648315454507">Pokud aplikaci <ph name="APP_NAME" /> chcete povolit, aby vám zasílala oznámení, zapněte oznámení také v <ph name="BEGIN_LINK" />Natavení Android<ph name="END_LINK" />.</translation>
<translation id="3227137524299004712">Mikrofon</translation>
<translation id="3277252321222022663">Povolit webům přístup k senzorům (doporuÄeno)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">Využití vašeho zařízení</translation>
<translation id="385051799172605136">Zpět</translation>
<translation id="3859306556332390985">PÅ™etoÄit dopÅ™edu</translation>
+<translation id="3895926599014793903">Vynutit aktivaci přiblížení</translation>
<translation id="3955193568934677022">Povolit webům pÅ™ehrávat chránÄ›ný obsah (doporuÄeno)</translation>
<translation id="3967822245660637423">Stahování bylo dokonÄeno</translation>
<translation id="3987993985790029246">Kopírovat odkaz</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> / ?</translation>
<translation id="4002066346123236978">Název</translation>
<translation id="4008040567710660924">Povolit soubory cookie pro konkrétní web.</translation>
+<translation id="4040330681741629921">Oznámit, když lze web zobrazit ve zjednodušeném zobrazení</translation>
<translation id="4046123991198612571">Další skladba</translation>
+<translation id="4149994727733219643">Zjednodušené zobrazení webových stránek</translation>
<translation id="4165986682804962316">Nastavení webu</translation>
+<translation id="4194328954146351878">Pokud web bude chtít Äíst a mÄ›nit informace na zařízeních NFC, zobrazit dotaz (doporuÄeno)</translation>
<translation id="4200726100658658164">Otevřít nastavení polohy</translation>
<translation id="4226663524361240545">Oznámení mohou aktivovat vibraci</translation>
<translation id="4259722352634471385">Navigace je blokována: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">Rozbalit</translation>
<translation id="4336434711095810371">Vymazat všechna data</translation>
<translation id="4402755511846832236">Nedovolit webům zjistit, kdy aktivně používáte toto zařízení</translation>
+<translation id="4428065317363009941">Personalizace reklam</translation>
<translation id="4434045419905280838">Vyskakovací okna a přesměrování</translation>
<translation id="445467742685312942">Povolit webům přehrávat chráněný obsah</translation>
<translation id="4468959413250150279">Vypne zvuk na konkrétním webu.</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">Možnost je k dispozici u horního okraje obrazovky</translation>
<translation id="5197729504361054390">Vybrané kontakty budou sdíleny s webem <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />.</translation>
<translation id="5216942107514965959">Naposledy navštíveno dnes</translation>
+<translation id="5264323282659631142">Odstranit položku <ph name="CHIP_LABEL" /></translation>
<translation id="528192093759286357">Režim celé obrazovky ukonÄíte pÅ™etažením z horního okraje obrazovky a klepnutím na tlaÄítko ZpÄ›t.</translation>
<translation id="5300589172476337783">Zobrazit</translation>
<translation id="5301954838959518834">Dobře, rozumím</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">Tímto vymažete <ph name="DATASIZE" /> dat a souborů cookie, které uložily weby.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(+ 1 další)}few{(+ # další)}many{(+ # další)}other{(+ # dalších)}}</translation>
<translation id="5403592356182871684">Názvy</translation>
+<translation id="5412236728747081950">Tento web získává z Chromu vaše zájmy, aby vám mohl zobrazovat relevantnější reklamy</translation>
<translation id="5438097262470833822">Výběrem této možnosti resetujete oprávnění webu <ph name="WEBSITE" /></translation>
<translation id="5489227211564503167">Uplynulá doba: <ph name="ELAPSED_TIME" /> z <ph name="TOTAL_TIME" />.</translation>
<translation id="5494752089476963479">Blokovat reklamy na webech, které zobrazují obtěžující nebo zavádějící reklamy</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">NaÄíst znovu</translation>
<translation id="5596627076506792578">Další možnosti</translation>
<translation id="5649053991847567735">Automatické stahování</translation>
+<translation id="5668404140385795438">Přepsat požadavek webu na zákaz přiblížení</translation>
<translation id="5677928146339483299">Zablokováno</translation>
<translation id="5689516760719285838">Poloha</translation>
<translation id="5690795753582697420">Fotoaparát je vypnutý v nastavení zařízení Android</translation>
-<translation id="5710871682236653961">Když se dotknete zařízení NFC, nejdříve se zeptat a teprve poté webu případnÄ› povolit odesílání a příjem informací (doporuÄeno)</translation>
<translation id="5719847187258001597">Tímto vymažete veškerá data a soubory cookie, které uložil web <ph name="ORIGIN" /> nebo jeho aplikace na ploše.</translation>
<translation id="5771720122942595109">Oprávnění <ph name="PERMISSION_1" /> je zablokováno</translation>
<translation id="5804241973901381774">Oprávnění</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">Přehrát</translation>
<translation id="6818926723028410516">Výběr položek</translation>
<translation id="6864395892908308021">Toto zařízení neumí Äíst NFC</translation>
-<translation id="6910211073230771657">Smazáno</translation>
<translation id="6912998170423641340">Blokovat webům přístup k textu a obrázkům zkopírovaným do schránky</translation>
<translation id="6945221475159498467">Vybrat</translation>
<translation id="6965382102122355670">OK</translation>
+<translation id="6981982820502123353">Usnadnění</translation>
<translation id="6992289844737586249">Pokud web bude chtít použít váš mikrofon, zobrazit dotaz (doporuÄeno)</translation>
<translation id="7000754031042624318">Vypnuto v nastavení systému Android</translation>
<translation id="7016516562562142042">Pro aktuální vyhledávaÄ povoleno</translation>
+<translation id="702463548815491781">DoporuÄeno, když je zapnuta funkce TalkBack nebo přístup pomocí pÅ™epínaÄů</translation>
<translation id="7053983685419859001">Blokovat</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{Vybráno: 1}few{Vybráno: #}many{Vybráno: #}other{Vybráno: #}}</translation>
-<translation id="7070090581017165256">O tomto webu</translation>
<translation id="7087918508125750058">Vybrané položky: <ph name="ITEM_COUNT" />. Možnosti jsou k dispozici u horního okraje obrazovky</translation>
<translation id="7141896414559753902">Bránit webům v zobrazování vyskakovacích oken a v pÅ™esmÄ›rování (doporuÄeno)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> kB</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">Webové stránky používají váš mikrofon</translation>
<translation id="7561196759112975576">Vždy</translation>
-<translation id="7572498721684305250">Blokovat webům odesílání a příjem informací, když se dotknete zařízení NFC</translation>
<translation id="757524316907819857">Bránit webům v přehrávání chráněného obsahu</translation>
+<translation id="7577900504646297215">Spravovat zájmy</translation>
<translation id="7649070708921625228">Nápověda</translation>
<translation id="7658239707568436148">Zrušit</translation>
<translation id="7781829728241885113">VÄera</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">PÅ™ipojení je zabezpeÄené</translation>
<translation id="8249310407154411074">PÅ™esunout na zaÄátek</translation>
<translation id="8261506727792406068">Smazat</translation>
+<translation id="8284326494547611709">Titulky</translation>
<translation id="8300705686683892304">Spravováno aplikací</translation>
<translation id="8324158725704657629">Příště se neptat</translation>
<translation id="8372893542064058268">Povolit synchronizaci na pozadí konkrétnímu webu.</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">Přiblížit</translation>
<translation id="8921772741368021346"><ph name="POSITION" />/<ph name="DURATION" /></translation>
<translation id="8926666909099850184">Funkce NFC je v tomto zařízení vypnutá. Zapnete ji v <ph name="BEGIN_LINK" />Nastavení Android<ph name="END_LINK" />.</translation>
+<translation id="8928445016601307354">Bránit webům v zobrazení a změně informací na zařízeních NFC</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">Blokovat soubory cookie pro konkrétní web.</translation>
<translation id="8959122750345127698">Navigace není dosažitelná: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_da.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_da.xtb
index 157d9557be0..fe0b14b2204 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_da.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_da.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">Websitet <ph name="SITE_NAME" /> blev tilføjet</translation>
<translation id="1383876407941801731">Søg</translation>
<translation id="1384959399684842514">Download er sat på pause</translation>
+<translation id="1409426117486808224">Enkel visning af åbne faner</translation>
<translation id="1415402041810619267">Webadressen er forkortet</translation>
<translation id="1446450296470737166">Tillad fuld kontrol over MIDI-enheder</translation>
<translation id="1620510694547887537">Kamera</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">Tillad cookies</translation>
<translation id="2228071138934252756">Aktivér også dit kamera i <ph name="BEGIN_LINK" />Android-indstillingerne<ph name="END_LINK" /> for at give <ph name="APP_NAME" /> adgang til kameraet.</translation>
<translation id="2241634353105152135">Kun én gang</translation>
+<translation id="2253414712144136228">Fjern <ph name="NAME_OF_LIST_ITEM" /></translation>
<translation id="2289270750774289114">Spørg, når et website vil søge efter Bluetooth-enheder i nærheden (anbefalet)</translation>
<translation id="2315043854645842844">Klientens certifikatvalg understøttes ikke af operativsystemet.</translation>
+<translation id="2321958826496381788">Træk i skyderen, indtil du kan nemt læse dette. Teksten som minimum have denne størrelse, når du har trykket to gange på et afsnit.</translation>
<translation id="2359808026110333948">Fortsæt</translation>
<translation id="2379925928934107488">Anvend Mørkt tema på websites, når Chrome anvender Mørkt tema (når det er muligt)</translation>
+<translation id="2387895666653383613">Tekststørrelse</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> og <ph name="NUM_MORE" /> mere er tilladt}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, and <ph name="NUM_MORE" /> more allowed}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> og <ph name="NUM_MORE" /> mere er tilladt}}</translation>
<translation id="2434158240863470628">Downloaden er fuldført <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">Vis info</translation>
<translation id="3123473560110926937">Blokeret på visse websites</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> gemte data</translation>
+<translation id="3203366800380907218">Fra nettet</translation>
<translation id="321187648315454507">Aktivér også notifikationer i <ph name="BEGIN_LINK" />Android-indstillingerne<ph name="END_LINK" /> for at give <ph name="APP_NAME" /> tilladelse til at sende dig notifikationer.</translation>
<translation id="3227137524299004712">Mikrofon</translation>
<translation id="3277252321222022663">Tillad, at websites kan få adgang til sensorer (anbefales)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">Din enhedsbrug</translation>
<translation id="385051799172605136">Tilbage</translation>
<translation id="3859306556332390985">Spol fremad</translation>
+<translation id="3895926599014793903">Tving aktivering af zoom</translation>
<translation id="3955193568934677022">Tillad, at websites afspiller beskyttet indhold (anbefales)</translation>
<translation id="3967822245660637423">Download fuldført</translation>
<translation id="3987993985790029246">Kopiér linket</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" />/?</translation>
<translation id="4002066346123236978">Titel</translation>
<translation id="4008040567710660924">Tillad cookies for et bestemt website.</translation>
+<translation id="4040330681741629921">Få besked, når et website kan vises i en enkelt visning</translation>
<translation id="4046123991198612571">Næste nummer</translation>
+<translation id="4149994727733219643">Enkel visning af websider</translation>
<translation id="4165986682804962316">Websiteindstillinger</translation>
+<translation id="4194328954146351878">Spørg, om websites må få adgang til og ændre oplysninger på NFC-enheder (anbefales)</translation>
<translation id="4200726100658658164">Ã…bn lokationsindstillinger</translation>
<translation id="4226663524361240545">Notifikationer kan få enheden til at vibrere</translation>
<translation id="4259722352634471385">Navigationen er blokeret: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">Udvid</translation>
<translation id="4336434711095810371">Ryd alle data</translation>
<translation id="4402755511846832236">Bloker websites fra at vide, hvornår du aktivt bruger denne enhed</translation>
+<translation id="4428065317363009941">Annoncetilpasning</translation>
<translation id="4434045419905280838">Pop op-vinduer og omdirigeringer</translation>
<translation id="445467742685312942">Tillad, at websites afspiller beskyttet indhold</translation>
<translation id="4468959413250150279">Slå lyden fra for et bestemt website.</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">Se valgmuligheden øverst på skærmen</translation>
<translation id="5197729504361054390">De kontakter, du vælger, deles med <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />.</translation>
<translation id="5216942107514965959">Senest besøgt i dag</translation>
+<translation id="5264323282659631142">Fjern "<ph name="CHIP_LABEL" />"</translation>
<translation id="528192093759286357">Træk fra toppen, og tryk på tilbageknappen igen for at afslutte fuld skærm.</translation>
<translation id="5300589172476337783">Vis</translation>
<translation id="5301954838959518834">OK, det er forstået</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">Dette rydder <ph name="DATASIZE" /> data og cookies, som er gemt af websites.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(+ 1 anden)}one{(+ # anden)}other{(+ # andre)}}</translation>
<translation id="5403592356182871684">Navne</translation>
+<translation id="5412236728747081950">Dette website henter dine interesser fra Chrome og bruger dem til at vise dig mere relevante annoncer</translation>
<translation id="5438097262470833822">Denne handling nulstiller tilladelserne for <ph name="WEBSITE" /></translation>
<translation id="5489227211564503167">Forløbet tid: <ph name="ELAPSED_TIME" /> af <ph name="TOTAL_TIME" />.</translation>
<translation id="5494752089476963479">Bloker annoncer på websites, der viser påtrængende eller vildledende annoncer</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">Genindlæs</translation>
<translation id="5596627076506792578">Flere valgmuligheder</translation>
<translation id="5649053991847567735">Automatiske downloads</translation>
+<translation id="5668404140385795438">Tilsidesæt en anmodning fra et website om at undgå at zoome ind</translation>
<translation id="5677928146339483299">Blokeret</translation>
<translation id="5689516760719285838">Placering</translation>
<translation id="5690795753582697420">Kameraet er deaktiveret i Android-indstillingerne</translation>
-<translation id="5710871682236653961">Spørg om tilladelse, før websites får mulighed for at sende og modtage oplysninger, når du parrer NFC-enheder (anbefalet)</translation>
<translation id="5719847187258001597">Dette rydder alle data og cookies, som er gemt af <ph name="ORIGIN" /> eller de tilhørende apps på din startskærm.</translation>
<translation id="5771720122942595109"><ph name="PERMISSION_1" /> blev blokeret</translation>
<translation id="5804241973901381774">Tilladelser</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">Afspil</translation>
<translation id="6818926723028410516">Vælg elementer</translation>
<translation id="6864395892908308021">Denne enhed kan ikke læse NFC</translation>
-<translation id="6910211073230771657">Slettet</translation>
<translation id="6912998170423641340">Bloker websites, så de ikke kan læse tekst og billeder fra udklipsholderen</translation>
<translation id="6945221475159498467">Vælg</translation>
<translation id="6965382102122355670">OK</translation>
+<translation id="6981982820502123353">Hjælpefunktioner</translation>
<translation id="6992289844737586249">Spørg, før websites bruger din mikrofon (anbefales)</translation>
<translation id="7000754031042624318">Deaktiveret i indstillingerne for Android</translation>
<translation id="7016516562562142042">Tilladt for den nuværende søgemaskine</translation>
+<translation id="702463548815491781">Anbefales, når TalkBack eller Kontaktadgang er aktiveret</translation>
<translation id="7053983685419859001">Bloker</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1 er valgt}one{# er valgt}other{# er valgt}}</translation>
-<translation id="7070090581017165256">Om dette website</translation>
<translation id="7087918508125750058"><ph name="ITEM_COUNT" /> er markeret. De tilgængelige valgmuligheder er øverst på skærmen</translation>
<translation id="7141896414559753902">Bloker visning af pop up-vinduer på websites og omdirigeringer (anbefales)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> kB</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">Et website anvender din mikrofon</translation>
<translation id="7561196759112975576">Altid</translation>
-<translation id="7572498721684305250">Bloker websites, så de ikke kan sende og modtage oplysninger, når du parrer NFC-enheder</translation>
<translation id="757524316907819857">Bloker afspilning af beskyttet indhold på websites</translation>
+<translation id="7577900504646297215">Administrer interesser</translation>
<translation id="7649070708921625228">Hjælp</translation>
<translation id="7658239707568436148">Annuller</translation>
<translation id="7781829728241885113">I går</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">Forbindelsen er sikker</translation>
<translation id="8249310407154411074">Flyt til toppen</translation>
<translation id="8261506727792406068">Slet</translation>
+<translation id="8284326494547611709">Undertekster</translation>
<translation id="8300705686683892304">Administreres af en app</translation>
<translation id="8324158725704657629">Spørg ikke igen</translation>
<translation id="8372893542064058268">Tillad synkronisering i baggrunden for et bestemt website.</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">Zoom ind</translation>
<translation id="8921772741368021346"><ph name="POSITION" />/<ph name="DURATION" /></translation>
<translation id="8926666909099850184">NFC er deaktiveret for denne enhed. Aktivér funktionen i <ph name="BEGIN_LINK" />Android-indstillingerne<ph name="END_LINK" />.</translation>
+<translation id="8928445016601307354">Bloker websites, så de ikke kan få adgang til og ændre oplysninger på NFC-enheder</translation>
<translation id="8941729603749328384">www.eksempel.dk</translation>
<translation id="8958424370300090006">Bloker cookies for et bestemt website.</translation>
<translation id="8959122750345127698">Navigationen er ikke mulig: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_de.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_de.xtb
index a99ee780e66..b5dca5df880 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_de.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_de.xtb
@@ -16,13 +16,14 @@
<translation id="1369915414381695676">Website "<ph name="SITE_NAME" />" hinzugefügt</translation>
<translation id="1383876407941801731">Durchsuchen</translation>
<translation id="1384959399684842514">Download angehalten</translation>
+<translation id="1409426117486808224">Vereinfachte Ansicht für geöffnete Tabs</translation>
<translation id="1415402041810619267">URL abgeschnitten</translation>
<translation id="1446450296470737166">Volle Kontr. über MIDI-Ger. erl.</translation>
<translation id="1620510694547887537">Kamera</translation>
<translation id="1644574205037202324">Verlauf</translation>
-<translation id="1647582022260550163">Möchten Sie die Berechtigungen dieser Website wirklich zurücksetzen und ihre Cookies und Daten löschen?</translation>
+<translation id="1647582022260550163">Möchtest du die Berechtigungen dieser Website wirklich zurücksetzen und ihre Cookies und Daten löschen?</translation>
<translation id="1660204651932907780">Wiedergabe von Ton auf Websites zulassen (empfohlen)</translation>
-<translation id="1677097821151855053">Durch Cookies und andere Websitedaten erinnert sich die Website an Sie, z. B. bei der Anmeldung oder für personalisierte Werbung. Sie können Cookies für alle Websites <ph name="BEGIN_LINK" />in den Einstellungen verwalten<ph name="END_LINK" />.</translation>
+<translation id="1677097821151855053">Durch Cookies und andere Websitedaten erinnert sich die Website an dich, z. B. bei der Anmeldung oder für personalisierte Werbung. Du kannst Cookies für alle Websites <ph name="BEGIN_LINK" />in den Einstellungen verwalten<ph name="END_LINK" />.</translation>
<translation id="1688867105868176567">Websitedaten löschen?</translation>
<translation id="169515064810179024">Zugriff auf Bewegungssensoren für Websites blockieren</translation>
<translation id="1717218214683051432">Bewegungssensoren</translation>
@@ -30,7 +31,7 @@
<translation id="1779089405699405702">Bild-Decodierer</translation>
<translation id="1818308510395330587">Damit <ph name="APP_NAME" /> AR verwenden kann, muss die Kameraberechtigung auch in den <ph name="BEGIN_LINK" />Android-Einstellungen<ph name="END_LINK" /> aktiviert sein.</translation>
<translation id="1864927262126810325">Quelle: <ph name="SOURCE_NAME" /></translation>
-<translation id="1887786770086287077">Der Standortzugriff ist für dieses Gerät deaktiviert. Sie können ihn in den <ph name="BEGIN_LINK" />Android-Einstellungen<ph name="END_LINK" /> aktivieren.</translation>
+<translation id="1887786770086287077">Der Standortzugriff ist für dieses Gerät deaktiviert. Du kannst ihn in den <ph name="BEGIN_LINK" />Android-Einstellungen<ph name="END_LINK" /> aktivieren.</translation>
<translation id="1919345977826869612">Werbung</translation>
<translation id="1919950603503897840">Kontakte auswählen</translation>
<translation id="1923695749281512248"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> von <ph name="FILE_SIZE_WITH_UNITS" /></translation>
@@ -43,16 +44,19 @@
<translation id="2079545284768500474">Rückgängig machen</translation>
<translation id="2091887806945687916">Ton</translation>
<translation id="2107397443965016585">Fragen, bevor Websites erlaubt wird, geschützten Inhalt wiederzugeben (empfohlen)</translation>
-<translation id="2146738493024040262">Instant-App öffnen</translation>
+<translation id="2146738493024040262">Instant App öffnen</translation>
<translation id="2148716181193084225">Heute</translation>
<translation id="2182457891543959921">Nachfragen, bevor Websites erlaubt wird, eine 3D-Karte meiner Umgebung zu erstellen oder die Kameraposition zu verfolgen (empfohlen)</translation>
<translation id="2212565012507486665">Cookies zulassen</translation>
-<translation id="2228071138934252756">Um <ph name="APP_NAME" /> Zugriff auf Ihre Kamera zu gewähren, muss die Kameraberechtigung auch in den <ph name="BEGIN_LINK" />Android-Einstellungen<ph name="END_LINK" /> aktiviert werden.</translation>
+<translation id="2228071138934252756">Um <ph name="APP_NAME" /> Zugriff auf deine Kamera zu gewähren, muss die Kameraberechtigung auch in den <ph name="BEGIN_LINK" />Android-Einstellungen<ph name="END_LINK" /> aktiviert werden.</translation>
<translation id="2241634353105152135">Nur einmal</translation>
+<translation id="2253414712144136228"><ph name="NAME_OF_LIST_ITEM" /> entfernen</translation>
<translation id="2289270750774289114">Nachfragen, wenn eine Website nach Bluetooth-Geräten in der Nähe suchen möchte (empfohlen)</translation>
<translation id="2315043854645842844">Die clientseitige Zertifikatauswahl wird vom Betriebssystem nicht unterstützt.</translation>
+<translation id="2321958826496381788">Ziehe den Schieberegler, bis du diesen Text problemlos lesen kannst. Nach dem Doppeltippen auf einen Abschnitt sollte der Text mindestens so groß sein.</translation>
<translation id="2359808026110333948">Weiter</translation>
<translation id="2379925928934107488">Sofern möglich, dunkles Design auf Websites anwenden, wenn Chrome das dunkle Design verwendet</translation>
+<translation id="2387895666653383613">Text-Skalierung</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> und <ph name="NUM_MORE" /> weitere zugelassen}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> und <ph name="NUM_MORE" /> weitere zugelassen}}</translation>
<translation id="2434158240863470628">Download abgeschlossen <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -63,7 +67,7 @@
<translation id="2498359688066513246">Hilfe &amp; Feedback</translation>
<translation id="2501278716633472235">Zurück</translation>
<translation id="2569468611847789653">{COOKIE_COUNT,plural, =1{Ein Cookie blockiert}other{# Cookies blockiert}}</translation>
-<translation id="2570922361219980984">Der Standortzugriff ist für dieses Gerät ebenfalls deaktiviert. Sie können ihn in den <ph name="BEGIN_LINK" />Android-Einstellungen<ph name="END_LINK" /> aktivieren.</translation>
+<translation id="2570922361219980984">Der Standortzugriff ist für dieses Gerät ebenfalls deaktiviert. Du kannst ihn in den <ph name="BEGIN_LINK" />Android-Einstellungen<ph name="END_LINK" /> aktivieren.</translation>
<translation id="257931822824936280">Maximiert – zum Minimieren klicken</translation>
<translation id="2586657967955657006">Zwischenablage</translation>
<translation id="2597457036804169544">Dunkles Design nicht auf Websites anwenden</translation>
@@ -74,7 +78,7 @@
<translation id="2704606927547763573">Kopiert</translation>
<translation id="2717722538473713889">E-Mail-Adressen</translation>
<translation id="2785051990912111074">Mit dieser Option werden Cookies für <ph name="WEBSITE" /> gelöscht</translation>
-<translation id="2822354292072154809">Möchten Sie wirklich alle Websiteberechtigungen für <ph name="CHOSEN_OBJECT_NAME" /> zurücksetzen?</translation>
+<translation id="2822354292072154809">Möchtest du wirklich alle Websiteberechtigungen für <ph name="CHOSEN_OBJECT_NAME" /> zurücksetzen?</translation>
<translation id="2870560284913253234">Website</translation>
<translation id="2874939134665556319">Vorheriger Titel</translation>
<translation id="2903493209154104877">Adressen</translation>
@@ -89,7 +93,8 @@
<translation id="3115898365077584848">Informationen anzeigen</translation>
<translation id="3123473560110926937">Auf einigen Websites blockiert</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> gespeicherte Daten</translation>
-<translation id="321187648315454507">Damit <ph name="APP_NAME" /> Ihnen Benachrichtigungen senden kann, müssen Sie die Berechtigung für Benachrichtigungen auch in den <ph name="BEGIN_LINK" />Android-Einstellungen<ph name="END_LINK" /> aktivieren.</translation>
+<translation id="3203366800380907218">Aus dem Web</translation>
+<translation id="321187648315454507">Damit <ph name="APP_NAME" /> dir Benachrichtigungen senden kann, musst du die Berechtigung für Benachrichtigungen auch in den <ph name="BEGIN_LINK" />Android-Einstellungen<ph name="END_LINK" /> aktivieren.</translation>
<translation id="3227137524299004712">Mikrofon</translation>
<translation id="3277252321222022663">Websites den Zugriff auf Sensoren erlauben (empfohlen)</translation>
<translation id="3295602654194328831">Informationen ausblenden</translation>
@@ -104,20 +109,24 @@
<translation id="3596414637720633074">Cookies von Drittanbietern im Inkognitomodus blockieren</translation>
<translation id="3600792891314830896">Websites stummschalten, die Ton wiedergeben</translation>
<translation id="3744111561329211289">Hintergrundsynchronisierung</translation>
-<translation id="3763247130972274048">Tippen Sie links oder rechts im Video doppelt, um 10 s zu überspringen</translation>
+<translation id="3763247130972274048">Tippe links oder rechts im Video doppelt, um 10 s zu überspringen</translation>
<translation id="3797520601150691162">Dunkles Design auf eine bestimmte Website nicht anwenden</translation>
<translation id="381841723434055211">Telefonnummern</translation>
<translation id="3835233591525155343">Meine Gerätenutzung</translation>
<translation id="385051799172605136">Zurück</translation>
<translation id="3859306556332390985">Nach vorne navigieren</translation>
+<translation id="3895926599014793903">Zoom zwingend aktivieren</translation>
<translation id="3955193568934677022">Wiedergabe geschützter Inhalte auf Websites zulassen (empfohlen)</translation>
<translation id="3967822245660637423">Download abgeschlossen</translation>
<translation id="3987993985790029246">Link kopieren</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> von ?</translation>
<translation id="4002066346123236978">Titel</translation>
<translation id="4008040567710660924">Cookies für eine bestimmte Website werden zugelassen.</translation>
+<translation id="4040330681741629921">Benachrichtigen, wenn eine Website in der vereinfachten Ansicht angezeigt werden kann</translation>
<translation id="4046123991198612571">Nächster Titel</translation>
+<translation id="4149994727733219643">Vereinfachte Ansicht für Webseiten</translation>
<translation id="4165986682804962316">Website-Einstellungen</translation>
+<translation id="4194328954146351878">Nachfragen, bevor Websites erlaubt wird, Informationen auf NFC-Geräten abzurufen und zu ändern (empfohlen)</translation>
<translation id="4200726100658658164">Standorteinstellungen öffnen</translation>
<translation id="4226663524361240545">Bei Benachrichtigungen kann das Gerät vibrieren</translation>
<translation id="4259722352634471385">Die Navigation zu <ph name="URL" /> ist blockiert.</translation>
@@ -125,18 +134,19 @@
<translation id="429312253194641664">Eine Website gibt Medien wieder</translation>
<translation id="42981349822642051">Maximieren</translation>
<translation id="4336434711095810371">Alle Daten löschen</translation>
-<translation id="4402755511846832236">Websites daran hindern, Informationen zu Ihrer aktiven Nutzung dieses Geräts abzurufen</translation>
+<translation id="4402755511846832236">Websites daran hindern, Informationen zu deiner aktiven Nutzung dieses Geräts abzurufen</translation>
+<translation id="4428065317363009941">Personalisierte Werbung</translation>
<translation id="4434045419905280838">Pop-ups und Weiterleitungen</translation>
<translation id="445467742685312942">Websites erlauben, geschützte Inhalte wiederzugeben</translation>
<translation id="4468959413250150279">Eine bestimmte Website stummschalten.</translation>
<translation id="4479647676395637221">Nachfragen, bevor Websites Zugriff auf meine Kamera erhalten (empfohlen)</translation>
<translation id="4505788138578415521">URL maximiert</translation>
-<translation id="4534723447064627427">Um <ph name="APP_NAME" /> Zugriff auf Ihr Mikrofon zu gewähren, muss die Mikrofonberechtigung auch in den <ph name="BEGIN_LINK" />Android-Einstellungen<ph name="END_LINK" /> aktiviert werden.</translation>
+<translation id="4534723447064627427">Um <ph name="APP_NAME" /> Zugriff auf dein Mikrofon zu gewähren, muss die Mikrofonberechtigung auch in den <ph name="BEGIN_LINK" />Android-Einstellungen<ph name="END_LINK" /> aktiviert werden.</translation>
<translation id="4570913071927164677">Details</translation>
<translation id="4645575059429386691">Von deinen Eltern verwaltet</translation>
<translation id="4670064810192446073">Virtual Reality</translation>
<translation id="4751476147751820511">Bewegungs- oder Lichtsensoren</translation>
-<translation id="4836046166855586901">Nachfragen, wenn eine Website Informationen zu Ihrer aktiven Nutzung dieses Geräts abrufen möchte</translation>
+<translation id="4836046166855586901">Nachfragen, wenn eine Website Informationen zu deiner aktiven Nutzung dieses Geräts abrufen möchte</translation>
<translation id="4883854917563148705">Verwaltete Einstellungen können nicht zurückgesetzt werden</translation>
<translation id="4887024562049524730">Nachfragen, bevor Websites erlaubt wird, mein Virtual-Reality-Gerät und meine Virtual-Reality-Daten zu verwenden (empfohlen)</translation>
<translation id="4962975101802056554">Alle Berechtigungen für Gerät entziehen</translation>
@@ -154,9 +164,10 @@
<translation id="5123685120097942451">Inkognitotab</translation>
<translation id="5134599672855298214">Mobile Ansicht anzeigen (empfohlen)</translation>
<translation id="5186036860380548585">Option ist oben auf dem Bildschirm verfügbar</translation>
-<translation id="5197729504361054390">Die von Ihnen ausgewählten Kontakte werden mit <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> geteilt.</translation>
+<translation id="5197729504361054390">Die von dir ausgewählten Kontakte werden mit <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> geteilt.</translation>
<translation id="5216942107514965959">Heute zuletzt besucht</translation>
-<translation id="528192093759286357">Ziehen Sie zum Beenden des Vollbildmodus von oben und tippen Sie auf die Zurück-Taste.</translation>
+<translation id="5264323282659631142">"<ph name="CHIP_LABEL" />" entfernen</translation>
+<translation id="528192093759286357">Ziehe zum Beenden des Vollbildmodus von oben und tippe auf die Zurück-Taste.</translation>
<translation id="5300589172476337783">Anzeigen</translation>
<translation id="5301954838959518834">Ok</translation>
<translation id="5313967007315987356">Website hinzufügen</translation>
@@ -166,21 +177,22 @@
<translation id="5354152178998424783">Dadurch werden <ph name="DATASIZE" /> an von Websites gespeicherten Daten und Cookies gelöscht.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(+ 1 weitere)}other{(+ # weitere)}}</translation>
<translation id="5403592356182871684">Namen</translation>
+<translation id="5412236728747081950">Diese Website ruft deine Interessen von Chrome ab, damit sie dir relevantere Werbung anzeigen kann</translation>
<translation id="5438097262470833822">Mit dieser Option werden die Berechtigungen für <ph name="WEBSITE" /> zurückgesetzt</translation>
<translation id="5489227211564503167">Verstrichene Zeit: <ph name="ELAPSED_TIME" /> von <ph name="TOTAL_TIME" />.</translation>
<translation id="5494752089476963479">Werbung auf Websites blockieren, auf denen aufdringliche oder irreführende Werbung angezeigt wird</translation>
<translation id="5502860503640766021"><ph name="PERMISSION_1" /> zugelassen, <ph name="PERMISSION_2" /> blockiert</translation>
-<translation id="5505264765875738116">Websites können nicht fragen, ob Sie Benachrichtigungen erhalten möchten</translation>
+<translation id="5505264765875738116">Websites können nicht fragen, ob du Benachrichtigungen erhalten möchtest</translation>
<translation id="5516455585884385570">Benachrichtigungseinstellungen öffnen</translation>
<translation id="5527111080432883924">Nachfragen, bevor einer Website erlaubt wird, Texte und Bilder aus der Zwischenablage abzurufen (empfohlen)</translation>
<translation id="5553374991681107062">Letzte</translation>
<translation id="5556459405103347317">Neu laden</translation>
<translation id="5596627076506792578">Weitere Optionen</translation>
<translation id="5649053991847567735">Auto-Downloads</translation>
+<translation id="5668404140385795438">Website-Anfrage zum Verhindern des Vergrößerns übergehen</translation>
<translation id="5677928146339483299">Blockiert</translation>
<translation id="5689516760719285838">Standort</translation>
<translation id="5690795753582697420">Die Kamera wurde in den Android-Einstellungen deaktiviert</translation>
-<translation id="5710871682236653961">Fragen, bevor Websites erlaubt wird, Informationen zu senden und zu empfangen, wenn das Smartphone an NFC-Geräte gehalten wird (empfohlen)</translation>
<translation id="5719847187258001597">Dadurch werden alle von <ph name="ORIGIN" /> oder der zugehörigen App auf dem Startbildschirm gespeicherten Daten und Cookies gelöscht.</translation>
<translation id="5771720122942595109"><ph name="PERMISSION_1" /> blockiert</translation>
<translation id="5804241973901381774">Berechtigungen</translation>
@@ -192,7 +204,7 @@
<translation id="5939518447894949180">Zurücksetzen</translation>
<translation id="5975083100439434680">Verkleinern</translation>
<translation id="5976059395673079613"><ph name="PERMISSION" /> – <ph name="WARNING_MESSAGE" /></translation>
-<translation id="6015775454662021376">Zugriff dieser Website auf Ihr Gerät steuern</translation>
+<translation id="6015775454662021376">Zugriff dieser Website auf dein Gerät steuern</translation>
<translation id="6040143037577758943">Schließen</translation>
<translation id="6042308850641462728">Mehr</translation>
<translation id="6064125863973209585">Abgeschlossene Downloads</translation>
@@ -205,7 +217,7 @@
<translation id="6216432067784365534">Optionen für <ph name="NAME_OF_LIST_ITEM" /></translation>
<translation id="6231752747840485235">„<ph name="APP_NAME" />“ deinstallieren?</translation>
<translation id="6262279340360821358"><ph name="PERMISSION_1" /> und <ph name="PERMISSION_2" /> blockiert</translation>
-<translation id="6270391203985052864">Websites können fragen, ob Sie Benachrichtigungen erhalten möchten</translation>
+<translation id="6270391203985052864">Websites können fragen, ob du Benachrichtigungen erhalten möchtest</translation>
<translation id="6295158916970320988">Alle Websites</translation>
<translation id="6320088164292336938">Vibrieren</translation>
<translation id="6388207532828177975">Löschen &amp; zurücksetzen</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">Wiedergabe</translation>
<translation id="6818926723028410516">Einträge auswählen</translation>
<translation id="6864395892908308021">NFC wird von diesem Gerät nicht unterstützt</translation>
-<translation id="6910211073230771657">Gelöscht</translation>
<translation id="6912998170423641340">Websites dürfen keine Texte oder Bilder aus der Zwischenablage abrufen</translation>
<translation id="6945221475159498467">Auswählen</translation>
<translation id="6965382102122355670">Ok</translation>
+<translation id="6981982820502123353">Bedienungshilfen</translation>
<translation id="6992289844737586249">Nachfragen, bevor Websites auf mein Mikrofon zugreifen dürfen (empfohlen)</translation>
<translation id="7000754031042624318">In den Android-Einstellungen deaktiviert</translation>
<translation id="7016516562562142042">Für die aktuelle Suchmaschine zugelassen</translation>
+<translation id="702463548815491781">Empfohlen, wenn TalkBack oder der Schalterzugriff aktiviert ist</translation>
<translation id="7053983685419859001">Blockieren</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1 ausgewählt}other{# ausgewählt}}</translation>
-<translation id="7070090581017165256">Ãœber diese Website</translation>
<translation id="7087918508125750058"><ph name="ITEM_COUNT" /> ausgewählt. Optionen sind oben auf dem Bildschirm verfügbar</translation>
<translation id="7141896414559753902">Anzeige von Pop-ups und Weiterleitungen für Websites blockieren (empfohlen)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> KB</translation>
@@ -247,31 +259,31 @@
<translation id="7243308994586599757">Optionen unten auf dem Bildschirm verfügbar</translation>
<translation id="7250468141469952378"><ph name="ITEM_COUNT" /> ausgewählt</translation>
<translation id="7260727271532453612"><ph name="PERMISSION_1" /> und <ph name="PERMISSION_2" /> zugelassen</translation>
-<translation id="7302486331832100261">Normalerweise blockieren Sie Benachrichtigungen. Sie können auf Details tippen, um sie zuzulassen.</translation>
+<translation id="7302486331832100261">Normalerweise blockierst du Benachrichtigungen. Du kannst auf Details tippen, um sie zuzulassen.</translation>
<translation id="7423098979219808738">Zuerst fragen</translation>
<translation id="7423538860840206698">Es dürfen keine Dateien aus der Zwischenablage abgerufen werden</translation>
<translation id="7425915948813553151">Dunkles Design für Websites</translation>
<translation id="7521387064766892559">JavaScript</translation>
-<translation id="7554752735887601236">Eine Website verwendet Ihr Mikrofon</translation>
+<translation id="7554752735887601236">Eine Website verwendet dein Mikrofon</translation>
<translation id="7561196759112975576">Immer</translation>
-<translation id="7572498721684305250">Websites daran hindern, Informationen zu senden und zu empfangen, wenn das Smartphone an NFC-Geräte gehalten wird</translation>
<translation id="757524316907819857">Wiedergabe von geschützten Inhalten für Websites blockieren</translation>
+<translation id="7577900504646297215">Interessen verwalten</translation>
<translation id="7649070708921625228">Hilfe</translation>
<translation id="7658239707568436148">Abbrechen</translation>
<translation id="7781829728241885113">Gestern</translation>
<translation id="7791543448312431591">Hinzufügen</translation>
<translation id="780301667611848630">Kein Interesse</translation>
-<translation id="7804248752222191302">Eine Website verwendet Ihre Kamera</translation>
-<translation id="7817023149356982970">Sie werden von dieser Website abgemeldet.</translation>
-<translation id="7828557259026017104">Cookies sind Dateien, die von Websites erstellt werden, die Sie besuchen. Sie werden zum Speichern Ihrer Einstellungen verwendet. Drittanbieter-Cookies werden von anderen Websites erstellt. Diesen Websites gehören einige der Inhalte, wie z. B. Werbeanzeigen oder Bilder, die Sie auf der besuchten Webseite sehen.</translation>
+<translation id="7804248752222191302">Eine Website verwendet deine Kamera</translation>
+<translation id="7817023149356982970">Du wirst von dieser Website abgemeldet.</translation>
+<translation id="7828557259026017104">Cookies sind Dateien, die von Websites erstellt werden, die du besuchst. Sie werden zum Speichern deiner Einstellungen verwendet. Drittanbieter-Cookies werden von anderen Websites erstellt. Diesen Websites gehören einige der Inhalte, wie z. B. Werbeanzeigen oder Bilder, die du auf der besuchten Webseite siehst.</translation>
<translation id="7835852323729233924">Medien werden wiedergegeben</translation>
<translation id="783819812427904514">Stummschaltung des Videos aufheben</translation>
<translation id="7846076177841592234">Auswahl aufheben</translation>
-<translation id="7846621471902887024">Sie werden von allen Websites abgemeldet.</translation>
+<translation id="7846621471902887024">Du wirst von allen Websites abgemeldet.</translation>
<translation id="7882806643839505685">Wiedergabe von Ton auf einer bestimmten Website zulassen.</translation>
<translation id="7940722705963108451">Erinnern</translation>
<translation id="7986741934819883144">Kontakt auswählen</translation>
-<translation id="7999064672810608036">Möchten Sie wirklich alle lokalen Daten einschließlich Cookies löschen und alle Berechtigungen für diese Website zurücksetzen?</translation>
+<translation id="7999064672810608036">Möchtest du wirklich alle lokalen Daten einschließlich Cookies löschen und alle Berechtigungen für diese Website zurücksetzen?</translation>
<translation id="8007176423574883786">Für dieses Gerät deaktiviert</translation>
<translation id="802154636333426148">Downloadfehler</translation>
<translation id="8042586301629853791">Sortieren nach:</translation>
@@ -284,20 +296,21 @@
<translation id="8154912474061769055">Viele Websites funktionieren dann möglicherweise nicht mehr richtig</translation>
<translation id="8197286292360124385"><ph name="PERMISSION_1" /> zugelassen</translation>
<translation id="8200772114523450471">Fortsetzen</translation>
-<translation id="8206354486702514201">Diese Einstellung wird von Ihrem Administrator erzwungen.</translation>
+<translation id="8206354486702514201">Diese Einstellung wird von deinem Administrator erzwungen.</translation>
<translation id="8211406090763984747">Verbindung ist sicher</translation>
<translation id="8249310407154411074">Ganz nach oben</translation>
<translation id="8261506727792406068">Löschen</translation>
+<translation id="8284326494547611709">Untertitel</translation>
<translation id="8300705686683892304">Von App verwaltet</translation>
<translation id="8324158725704657629">Nicht mehr fragen</translation>
<translation id="8372893542064058268">Lässt die Hintergrundsynchronisierung für eine bestimmte Website zu.</translation>
<translation id="8376384591331888629">Einschließlich Cookies von Drittanbietern auf dieser Website</translation>
-<translation id="83792324527827022">Eine Website verwendet Ihre Kamera und Ihr Mikrofon</translation>
+<translation id="83792324527827022">Eine Website verwendet deine Kamera und dein Mikrofon</translation>
<translation id="8380167699614421159">Diese Website zeigt aufdringliche oder irreführende Werbung an</translation>
<translation id="8394832520002899662">Tippen, um zur Website zurückzukehren</translation>
<translation id="8425213833346101688">Ändern</translation>
<translation id="8441146129660941386">Zurück navigieren</translation>
-<translation id="8444433999583714703">Um <ph name="APP_NAME" /> Zugriff auf Ihren Standort zu gewähren, müssen Sie die Standortberechtigung auch in den <ph name="BEGIN_LINK" />Android-Einstellungen<ph name="END_LINK" /> aktivieren.</translation>
+<translation id="8444433999583714703">Um <ph name="APP_NAME" /> Zugriff auf deinen Standort zu gewähren, musst du die Standortberechtigung auch in den <ph name="BEGIN_LINK" />Android-Einstellungen<ph name="END_LINK" /> aktivieren.</translation>
<translation id="8447861592752582886">Zugriffsberechtigung auf Gerät widerrufen</translation>
<translation id="8451050538944905715">{NUM_SELECTED,plural, =1{1 verwendeter Cookie}other{# verwendete Cookies}}</translation>
<translation id="8487700953926739672">Offline verfügbar</translation>
@@ -315,12 +328,13 @@
<translation id="8730621377337864115">Fertig</translation>
<translation id="8737217482364735741">Dadurch werden alle von <ph name="ORIGIN" /> gespeicherten Daten und Cookies gelöscht.</translation>
<translation id="8751914237388039244">Bild auswählen</translation>
-<translation id="8801436777607969138">Hier können Sie Websites angeben, für die JavaScript blockiert werden soll.</translation>
+<translation id="8801436777607969138">Hier kannst du Websites angeben, für die JavaScript blockiert werden soll.</translation>
<translation id="8816026460808729765">Zugriff auf Sensoren für Websites blockieren</translation>
<translation id="8847988622838149491">USB</translation>
<translation id="8903921497873541725">Vergrößern</translation>
<translation id="8921772741368021346"><ph name="POSITION" />/<ph name="DURATION" /></translation>
-<translation id="8926666909099850184">NFC ist für dieses Gerät deaktiviert. Sie können die Funktion in den <ph name="BEGIN_LINK" />Android-Einstellungen<ph name="END_LINK" /> aktivieren.</translation>
+<translation id="8926666909099850184">NFC ist für dieses Gerät deaktiviert. Du kannst die Funktion in den <ph name="BEGIN_LINK" />Android-Einstellungen<ph name="END_LINK" /> aktivieren.</translation>
+<translation id="8928445016601307354">Websites daran hindern, Informationen auf NFC-Geräten abzurufen und zu ändern</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">Cookies für eine bestimmte Website werden blockiert.</translation>
<translation id="8959122750345127698">Navigation nicht möglich: <ph name="URL" /> ist nicht erreichbar.</translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_el.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_el.xtb
index d9450c2b905..7eaee1997d8 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_el.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_el.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">ΠÏοστέθηκε ο ιστότοπος <ph name="SITE_NAME" /></translation>
<translation id="1383876407941801731">Αναζήτηση</translation>
<translation id="1384959399684842514">Η λήψη διακόπηκε Ï€ÏοσωÏινά.</translation>
+<translation id="1409426117486808224">Απλοποιημένη Ï€Ïοβολή για ανοικτές καÏτέλες</translation>
<translation id="1415402041810619267">ΠεÏικομμένο URL</translation>
<translation id="1446450296470737166">Îα επιτÏέπεται πλήÏης έλεγχος σε MIDI</translation>
<translation id="1620510694547887537">ΚάμεÏα</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">Αποδοχή cookie</translation>
<translation id="2228071138934252756">Για να επιτÏέψετε στην εφαÏμογή <ph name="APP_NAME" /> να αποκτήσει Ï€Ïόσβαση στην κάμεÏά σας, ενεÏγοποιήστε επίσης την κάμεÏα στις <ph name="BEGIN_LINK" />Ρυθμίσεις Android<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Μόνο μία φοÏά</translation>
+<translation id="2253414712144136228"><ph name="NAME_OF_LIST_ITEM" /> ΚατάÏγηση</translation>
<translation id="2289270750774289114">Îα γίνεται εÏώτηση όταν ένας ιστότοπος επιθυμεί να εντοπίσει κοντινές συσκευες Bluetooth (συνιστάται)</translation>
<translation id="2315043854645842844">Η επιλογή Ï€Î¹ÏƒÏ„Î¿Ï€Î¿Î¹Î·Ï„Î¹ÎºÎ¿Ï Î±Ï€ÏŒ τον πελάτη δεν υποστηÏίζεται από το λειτουÏγικό σÏστημα.</translation>
+<translation id="2321958826496381788">ΣÏÏετε το Ïυθμιστικό έως ότου να διαβάσετε αυτό το μήνυμα άνετα. Το κείμενο θα Ï€Ïέπει να είναι τουλάχιστον τόσο μεγάλο Î±Ï†Î¿Ï Ï€Î±Ï„Î®ÏƒÎµÏ„Îµ δÏο φοÏές σε μια παÏάγÏαφο.</translation>
<translation id="2359808026110333948">Συνέχεια</translation>
<translation id="2379925928934107488">ΕφαÏμογή σκοÏÏου θέματος σε ιστοτόπους όταν το Chrome χÏησιμοποιεί σκοÏÏο θέμα, όταν υπάÏχει αυτή η δυνατότητα</translation>
+<translation id="2387895666653383613">Κλιμάκωση κειμένου</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Οι άδειες <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> και <ph name="NUM_MORE" /> ακόμη επιτÏάπηκαν.}other{Οι άδειες <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> και <ph name="NUM_MORE" /> ακόμη επιτÏάπηκαν.}}</translation>
<translation id="2434158240863470628">Η λήψη ολοκληÏώθηκε <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">ΠληÏοφοÏίες εκπομπής</translation>
<translation id="3123473560110926937">Αποκλεισμός σε οÏισμένους ιστοτόπους</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> αποθηκευμένα δεδομένα</translation>
+<translation id="3203366800380907218">Από τον ιστό</translation>
<translation id="321187648315454507">Για να επιτÏέψετε στην εφαÏμογή <ph name="APP_NAME" /> να σας στέλνει ειδοποιήσεις, ενεÏγοποιήστε επίσης τις ειδοποιήσεις στις <ph name="BEGIN_LINK" />Ρυθμίσεις Android<ph name="END_LINK" />.</translation>
<translation id="3227137524299004712">ΜικÏόφωνο</translation>
<translation id="3277252321222022663">Îα επιτÏέπεται στους ιστοτόπους η Ï€Ïόσβαση στους αισθητήÏες (συνιστάται)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">ΧÏήση της συσκευής σας</translation>
<translation id="385051799172605136">Πίσω</translation>
<translation id="3859306556332390985">Αναζήτηση Ï€Ïος τα εμπÏός</translation>
+<translation id="3895926599014793903">Αναγκαστική ενεÏγοποίηση εστίασης</translation>
<translation id="3955193568934677022">Îα επιτÏέπεται στους ιστοτόπους να αναπαÏάγουν Ï€Ïοστατευμένο πεÏιεχόμενο (συνιστάται)</translation>
<translation id="3967822245660637423">ΟλοκλήÏωση λήψης</translation>
<translation id="3987993985790029246">Αντ. συνδ.</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> / ?</translation>
<translation id="4002066346123236978">Τίτλος</translation>
<translation id="4008040567710660924">ΕπιτÏέπει τα cookie για έναν συγκεκÏιμένο ιστότοπο.</translation>
+<translation id="4040330681741629921">Λάβετε ειδοποίηση όταν ένας ιστότοπος μποÏεί να εμφανιστεί σε απλοποιημένη Ï€Ïοβολή</translation>
<translation id="4046123991198612571">Επόμενο κομμάτι</translation>
+<translation id="4149994727733219643">Απλοποιημένη Ï€Ïοβολή για ιστοσελίδες</translation>
<translation id="4165986682804962316">Ρυθμίσεις ιστότοπου</translation>
+<translation id="4194328954146351878">Îα γίνεται εÏώτηση Ï€Ïιν επιτÏαπεί στους ιστοτόπους να βλέπουν και να αλλάζουν πληÏοφοÏίες σε συσκευές NFC (συνιστάται)</translation>
<translation id="4200726100658658164">Άνοιγμα Ïυθμίσεων τοποθεσίας</translation>
<translation id="4226663524361240545">Κατά τη λήψη ειδοποιήσεων ενδέχεται να δονείται η συσκευή</translation>
<translation id="4259722352634471385">Αποκλείστηκε η μετάβαση στη διεÏθυνση: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">Επέκταση</translation>
<translation id="4336434711095810371">ΔιαγÏαφή όλων των δεδομένων</translation>
<translation id="4402755511846832236">Îα μην επιτÏέπεται σε ιστοτόπους να γνωÏίζουν πότε χÏησιμοποιείτε τη συσκευή ενεÏγά</translation>
+<translation id="4428065317363009941">Εξατομίκευση διαφημίσεων</translation>
<translation id="4434045419905280838">Αναδυόμενα παÏάθυÏα και ανακατευθÏνσεις</translation>
<translation id="445467742685312942">Îα επιτÏέπεται στους ιστοτόπους η αναπαÏαγωγή Ï€Ïοστατευμένου πεÏιεχομένου</translation>
<translation id="4468959413250150279">Σίγαση ήχου για συγκεκÏιμένο ιστότοπο.</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">Η επιλογή είναι διαθέσιμη κοντά στην κοÏυφή της οθόνης</translation>
<translation id="5197729504361054390">Οι επαφές που επιλέγετε θα κοινοποιηθοÏν στον ιστότοπο <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />.</translation>
<translation id="5216942107514965959">Τελευταία επίσκεψη σήμεÏα</translation>
+<translation id="5264323282659631142">ΚατάÏγηση <ph name="CHIP_LABEL" /></translation>
<translation id="528192093759286357">ΣÏÏετε από το επάνω τμήμα και αγγίξτε το κουμπί επιστÏοφής για έξοδο από την πλήÏη οθόνη.</translation>
<translation id="5300589172476337783">Εμφάνιση</translation>
<translation id="5301954838959518834">OK, το κατάλαβα</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">Αυτή η ενέÏγεια θα διαγÏάψει <ph name="DATASIZE" /> δεδομένων και cookie που έχουν αποθηκευτεί από ιστοτόπους.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(+ 1 ακόμη)}other{(+ # ακόμη)}}</translation>
<translation id="5403592356182871684">Ονόματα</translation>
+<translation id="5412236728747081950">Αυτός ο ιστότοπος λαμβάνει πληÏοφοÏίες για τα ενδιαφέÏοντά σας από το Chrome για να εμφανίσει πιο συναφείς διαφημίσεις.</translation>
<translation id="5438097262470833822">Με αυτήν την επιλογή θα γίνει επαναφοÏά των αδειών για τον ιστότοπο <ph name="WEBSITE" /></translation>
<translation id="5489227211564503167">Έχουν πεÏάσει <ph name="ELAPSED_TIME" /> από <ph name="TOTAL_TIME" />.</translation>
<translation id="5494752089476963479">Αποκλεισμός διαφημίσεων σε ιστοτόπους που εμφανίζουν παÏεμβατικές ή παÏαπλανητικές διαφημίσεις</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">ΕπαναφόÏτωση</translation>
<translation id="5596627076506792578">ΠεÏισσότεÏες επιλογές</translation>
<translation id="5649053991847567735">Αυτόματες λήψεις</translation>
+<translation id="5668404140385795438">ΠαÏάκαμψη του αιτήματος ενός ιστότοπου για παÏεμπόδιση εστίασης</translation>
<translation id="5677928146339483299">Αποκλεισμένο</translation>
<translation id="5689516760719285838">Τοποθεσία</translation>
<translation id="5690795753582697420">Η κάμεÏα απενεÏγοποιήθηκε στις Ïυθμίσεις Android.</translation>
-<translation id="5710871682236653961">Îα γίνεται εÏώτηση Ï€ÏÎ¿Ï„Î¿Ï ÎµÏ€Î¹Ï„Ïαπεί σε ιστοτόπους η αποστολή ή η λήψη πληÏοφοÏιών κατά το πάτημα συσκευών NFC (συνιστάται).</translation>
<translation id="5719847187258001597">Αυτή η ενέÏγεια θα διαγÏάψει όλα τα δεδομένα και τα cookie που έχουν αποθηκευτεί από <ph name="ORIGIN" /> ή από αυτήν την εφαÏμογή στην αÏχική οθόνη σας.</translation>
<translation id="5771720122942595109">Η άδεια <ph name="PERMISSION_1" /> αποκλείστηκε.</translation>
<translation id="5804241973901381774">Άδειες</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">ΑναπαÏαγωγή</translation>
<translation id="6818926723028410516">Επιλέξτε στοιχεία</translation>
<translation id="6864395892908308021">Αυτή η συσκευή δεν μποÏεί να διαβάσει NFC</translation>
-<translation id="6910211073230771657">ΔιαγÏάφηκε</translation>
<translation id="6912998170423641340">Αποκλεισμός ιστοτόπων από ανάγνωση κειμένου και εικόνων από το Ï€ÏόχειÏο</translation>
<translation id="6945221475159498467">Επιλογή</translation>
<translation id="6965382102122355670">OK</translation>
+<translation id="6981982820502123353">ΠÏοσβασιμότητα</translation>
<translation id="6992289844737586249">Îα γίνεται εÏώτηση Ï€ÏÎ¿Ï„Î¿Ï ÎµÏ€Î¹Ï„Ïαπεί στους ιστότοπους να χÏησιμοποιήσουν το μικÏόφωνό σας (συνιστάται)</translation>
<translation id="7000754031042624318">Έχει απενεÏγοποιηθεί στις Ρυθμίσεις Android</translation>
<translation id="7016516562562142042">ΕπιτÏάπηκε για την Ï„Ïέχουσα μηχανή αναζήτησης</translation>
+<translation id="702463548815491781">Συνιστάται όταν έχει ενεÏγοποιηθεί το TalkBack ή η Ï€Ïόσβαση με διακόπτη</translation>
<translation id="7053983685419859001">Αποκλεισμός</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1 επιλεγμένο}other{# επιλεγμένα}}</translation>
-<translation id="7070090581017165256">Σχετικά με αυτόν τον ιστότοπο</translation>
<translation id="7087918508125750058">Επιλέχθηκαν <ph name="ITEM_COUNT" />. Οι επιλογές είναι διαθέσιμες κοντά στο επάνω μέÏος της οθόνης</translation>
<translation id="7141896414559753902">Αποκλεισμός εμφάνισης αναδυόμενων παÏαθÏÏων και ανακατευθÏνσεων σε ιστοτόπους (συνιστάται)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> KB</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">Ένας ιστότοπος χÏησιμοποιεί το μικÏόφωνό σας.</translation>
<translation id="7561196759112975576">Πάντα</translation>
-<translation id="7572498721684305250">Αποκλεισμός ιστοτόπων από την αποστολή ή τη λήψη πληÏοφοÏιών κατά το πάτημα συσκευών NFC.</translation>
<translation id="757524316907819857">Αποκλεισμός αναπαÏαγωγής Ï€Ïοστατευόμενου πεÏιεχομένου από ιστοτόπους</translation>
+<translation id="7577900504646297215">ΔιαχείÏιση ενδιαφεÏόντων</translation>
<translation id="7649070708921625228">Βοήθεια</translation>
<translation id="7658239707568436148">ΑκÏÏωση</translation>
<translation id="7781829728241885113">Χθες</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">Η σÏνδεση είναι ασφαλής</translation>
<translation id="8249310407154411074">Μετακίνηση επάνω</translation>
<translation id="8261506727792406068">ΔιαγÏαφή</translation>
+<translation id="8284326494547611709">Υπότιτλοι</translation>
<translation id="8300705686683892304">ΔιαχείÏιση από εφαÏμογή</translation>
<translation id="8324158725704657629">Îα μην εÏωτηθώ ξανά</translation>
<translation id="8372893542064058268">Îα επιτÏέπεται ο ΣυγχÏονισμός παÏασκηνίου για έναν συγκεκÏιμένο ιστότοπο.</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">Μεγέθυνση</translation>
<translation id="8921772741368021346"><ph name="POSITION" />/<ph name="DURATION" /></translation>
<translation id="8926666909099850184">Το NFC είναι ανενεÏγό για αυτήν τη συσκευή. ΕνεÏγοποιήστε το στις <ph name="BEGIN_LINK" />Ρυθμίσεις Android<ph name="END_LINK" />.</translation>
+<translation id="8928445016601307354">Αποκλεισμός ιστοτόπων από την εμφάνιση και την αλλαγή πληÏοφοÏιών σε συσκευές NFC</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">Αποκλεισμός cookie για έναν συγκεκÏιμένο ιστοτόπο.</translation>
<translation id="8959122750345127698">Δεν είναι δυνατή η μετάβαση στη διεÏθυνση: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_en-GB.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_en-GB.xtb
index d002a082072..5d5522c75b9 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_en-GB.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_en-GB.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">Site <ph name="SITE_NAME" /> added</translation>
<translation id="1383876407941801731">Search</translation>
<translation id="1384959399684842514">Download paused</translation>
+<translation id="1409426117486808224">Simplified view for open tabs</translation>
<translation id="1415402041810619267">URL truncated</translation>
<translation id="1446450296470737166">Allow full control of MIDI devices</translation>
<translation id="1620510694547887537">Camera</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">Allow cookies</translation>
<translation id="2228071138934252756">To let <ph name="APP_NAME" /> access your camera, also turn on camera in <ph name="BEGIN_LINK" />Android settings<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Just once</translation>
+<translation id="2253414712144136228"><ph name="NAME_OF_LIST_ITEM" /> Remove</translation>
<translation id="2289270750774289114">Ask when a site wants to discover nearby Bluetooth devices (recommended)</translation>
<translation id="2315043854645842844">Client side certificate selection is not supported by the operating system.</translation>
+<translation id="2321958826496381788">Drag the slider until you can read this comfortably. Text should look at least this big after double-tapping on a paragraph.</translation>
<translation id="2359808026110333948">Continue</translation>
<translation id="2379925928934107488">Apply Dark theme to sites when Chrome uses Dark theme, when possible</translation>
+<translation id="2387895666653383613">Text scaling</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> and <ph name="NUM_MORE" /> more allowed}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> and <ph name="NUM_MORE" /> more allowed}}</translation>
<translation id="2434158240863470628">Download complete <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">Show info</translation>
<translation id="3123473560110926937">Blocked on some sites</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> stored data</translation>
+<translation id="3203366800380907218">From the web</translation>
<translation id="321187648315454507">To let <ph name="APP_NAME" /> send you notifications, also turn on notifications in <ph name="BEGIN_LINK" />Android settings<ph name="END_LINK" />.</translation>
<translation id="3227137524299004712">Microphone</translation>
<translation id="3277252321222022663">Allow sites to access sensors (recommended)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">Your device use</translation>
<translation id="385051799172605136">Back</translation>
<translation id="3859306556332390985">Seek forward</translation>
+<translation id="3895926599014793903">Force enable zoom</translation>
<translation id="3955193568934677022">Allow sites to play protected content (recommended)</translation>
<translation id="3967822245660637423">Download complete</translation>
<translation id="3987993985790029246">Copy link</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" />/?</translation>
<translation id="4002066346123236978">Title</translation>
<translation id="4008040567710660924">Allow cookies for a specific site.</translation>
+<translation id="4040330681741629921">Get notified when a site can be shown in simplified view</translation>
<translation id="4046123991198612571">Next track</translation>
+<translation id="4149994727733219643">Simplified view for web pages</translation>
<translation id="4165986682804962316">Site settings</translation>
+<translation id="4194328954146351878">Ask before allowing sites to see and change information on NFC devices (recommended)</translation>
<translation id="4200726100658658164">Open location settings</translation>
<translation id="4226663524361240545">Notifications may vibrate the device</translation>
<translation id="4259722352634471385">Navigation is blocked: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">Expand</translation>
<translation id="4336434711095810371">Clear all data</translation>
<translation id="4402755511846832236">Block sites from knowing when you're actively using this device</translation>
+<translation id="4428065317363009941">Ad personalisation</translation>
<translation id="4434045419905280838">Pop-ups and redirects</translation>
<translation id="445467742685312942">Allow sites to play protected content</translation>
<translation id="4468959413250150279">Mute sound for a specific site.</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">Option available near top of the screen</translation>
<translation id="5197729504361054390">The contacts that you select will be shared with <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />.</translation>
<translation id="5216942107514965959">Last visited today</translation>
+<translation id="5264323282659631142">Remove '<ph name="CHIP_LABEL" />'</translation>
<translation id="528192093759286357">Drag from top and touch the back button to exit full screen.</translation>
<translation id="5300589172476337783">Show</translation>
<translation id="5301954838959518834">OK, got it</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">This will clear <ph name="DATASIZE" /> of data and cookies stored by sites.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(+ 1 more)}other{(+ # more)}}</translation>
<translation id="5403592356182871684">Names</translation>
+<translation id="5412236728747081950">This site gets your interests from Chrome to show you more relevant ads</translation>
<translation id="5438097262470833822">This choice will reset permissions for <ph name="WEBSITE" /></translation>
<translation id="5489227211564503167">Elapsed time <ph name="ELAPSED_TIME" /> of <ph name="TOTAL_TIME" />.</translation>
<translation id="5494752089476963479">Block ads on sites that show intrusive or misleading ads</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">Reload</translation>
<translation id="5596627076506792578">More options</translation>
<translation id="5649053991847567735">Automatic downloads</translation>
+<translation id="5668404140385795438">Override a website’s request to prevent zooming in</translation>
<translation id="5677928146339483299">Blocked</translation>
<translation id="5689516760719285838">Location</translation>
<translation id="5690795753582697420">Camera is turned off in Android settings</translation>
-<translation id="5710871682236653961">Ask before allowing sites to send and receive info when you tap NFC devices (recommended)</translation>
<translation id="5719847187258001597">This will clear all data and cookies stored by <ph name="ORIGIN" /> or by its app on your home screen.</translation>
<translation id="5771720122942595109"><ph name="PERMISSION_1" /> blocked</translation>
<translation id="5804241973901381774">Permissions</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">Play</translation>
<translation id="6818926723028410516">Select items</translation>
<translation id="6864395892908308021">This device can't read NFC</translation>
-<translation id="6910211073230771657">Deleted</translation>
<translation id="6912998170423641340">Block sites from reading text and images from the clipboard</translation>
<translation id="6945221475159498467">Select</translation>
<translation id="6965382102122355670">OK</translation>
+<translation id="6981982820502123353">Accessibility</translation>
<translation id="6992289844737586249">Ask first before allowing sites to use your microphone (recommended)</translation>
<translation id="7000754031042624318">Turned off in Android settings</translation>
<translation id="7016516562562142042">Allowed for current search engine</translation>
+<translation id="702463548815491781">Recommended when TalkBack or Switch Access are on</translation>
<translation id="7053983685419859001">Block</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1 selected}other{# selected}}</translation>
-<translation id="7070090581017165256">About this site</translation>
<translation id="7087918508125750058"><ph name="ITEM_COUNT" /> selected. Options available near top of the screen</translation>
<translation id="7141896414559753902">Block sites from showing pop-ups and redirects (recommended)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> KB</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">A site is using your microphone</translation>
<translation id="7561196759112975576">Always</translation>
-<translation id="7572498721684305250">Block sites from sending and receiving info when you tap NFC devices</translation>
<translation id="757524316907819857">Block sites from playing protected content</translation>
+<translation id="7577900504646297215">Manage interests</translation>
<translation id="7649070708921625228">Help</translation>
<translation id="7658239707568436148">Cancel</translation>
<translation id="7781829728241885113">Yesterday</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">Connection is secure</translation>
<translation id="8249310407154411074">Move to top</translation>
<translation id="8261506727792406068">Delete</translation>
+<translation id="8284326494547611709">Captions</translation>
<translation id="8300705686683892304">Managed by app</translation>
<translation id="8324158725704657629">Don't ask again</translation>
<translation id="8372893542064058268">Allow Background Sync for a specific site.</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">Zoom in</translation>
<translation id="8921772741368021346"><ph name="POSITION" />/<ph name="DURATION" /></translation>
<translation id="8926666909099850184">NFC is off for this device. Turn it on in <ph name="BEGIN_LINK" />Android settings<ph name="END_LINK" />.</translation>
+<translation id="8928445016601307354">Block sites from seeing and changing information on NFC devices</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">Block cookies for a specific site.</translation>
<translation id="8959122750345127698">Navigation is unreachable: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_es-419.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_es-419.xtb
index 801022ba2a3..3744e3f39e6 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_es-419.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_es-419.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">Se agregó el sitio <ph name="SITE_NAME" />.</translation>
<translation id="1383876407941801731">Buscar</translation>
<translation id="1384959399684842514">Descarga detenida</translation>
+<translation id="1409426117486808224">Vista simplificada para las pestañas abiertas</translation>
<translation id="1415402041810619267">URL acortada</translation>
<translation id="1446450296470737166">Control de dispositivos MIDI</translation>
<translation id="1620510694547887537">Cámara</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">Permitir cookies</translation>
<translation id="2228071138934252756">Para permitir que <ph name="APP_NAME" /> acceda a tu cámara, actívala también en la <ph name="BEGIN_LINK" />Configuración de Android<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Solo esta vez</translation>
+<translation id="2253414712144136228">Quitar <ph name="NAME_OF_LIST_ITEM" /></translation>
<translation id="2289270750774289114">Preguntarme cuando un sitio intente conectarse a dispositivos Bluetooth cercanos (recomendado)</translation>
<translation id="2315043854645842844">El sistema operativo no admite la selección de certificados del lado del cliente.</translation>
+<translation id="2321958826496381788">Arrastra el control deslizante hasta que puedas leer esto cómodamente. El texto debería verse, al menos, de este tamaño al tocar dos veces un párrafo.</translation>
<translation id="2359808026110333948">Continuar</translation>
<translation id="2379925928934107488">Aplicar el Tema oscuro para los sitios (de ser posible) cuando está habilitado en Chrome</translation>
+<translation id="2387895666653383613">Ajuste de texto</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Permitidos: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> y <ph name="NUM_MORE" /> más}other{Permitidos: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> y <ph name="NUM_MORE" /> más}}</translation>
<translation id="2434158240863470628">Se completó la descarga <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">Mostrar información</translation>
<translation id="3123473560110926937">Bloqueados en algunos sitios</translation>
<translation id="3198916472715691905">Datos almacenados: <ph name="STORAGE_AMOUNT" /></translation>
+<translation id="3203366800380907218">Desde la Web</translation>
<translation id="321187648315454507">Para permitir que <ph name="APP_NAME" /> te envíe notificaciones, actívalas también en la <ph name="BEGIN_LINK" />Configuración de Android<ph name="END_LINK" />.</translation>
<translation id="3227137524299004712">Micrófono</translation>
<translation id="3277252321222022663">Permitir que los sitios accedan a los sensores (recomendado)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">Uso de tu dispositivo</translation>
<translation id="385051799172605136">Atrás</translation>
<translation id="3859306556332390985">Buscar más adelante</translation>
+<translation id="3895926599014793903">Forzar habilitación de zoom</translation>
<translation id="3955193568934677022">Permitir que los sitios reproduzcan contenido protegido (recomendado)</translation>
<translation id="3967822245660637423">Descarga completa</translation>
<translation id="3987993985790029246">Copiar vínculo</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" />/?</translation>
<translation id="4002066346123236978">Título</translation>
<translation id="4008040567710660924">Permite las cookies para un sitio específico.</translation>
+<translation id="4040330681741629921">Notificarme cada vez que se pueda mostrar la vista simplificada de un sitio</translation>
<translation id="4046123991198612571">Siguiente pista</translation>
+<translation id="4149994727733219643">Vista simplificada para páginas web</translation>
<translation id="4165986682804962316">Configuración de sitios</translation>
+<translation id="4194328954146351878">Preguntar antes de permitir que los sitios vean y cambien la información de los dispositivos NFC (recomendado)</translation>
<translation id="4200726100658658164">Abrir la configuración de la ubicación</translation>
<translation id="4226663524361240545">Es posible que las notificaciones hagan vibrar el dispositivo</translation>
<translation id="4259722352634471385">Navegación bloqueada: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">Expandir</translation>
<translation id="4336434711095810371">Borrar todos los datos</translation>
<translation id="4402755511846832236">No permitir que los sitios sepan cuando estás usando activamente este dispositivo</translation>
+<translation id="4428065317363009941">Personalización de anuncios</translation>
<translation id="4434045419905280838">Ventanas emergentes y redireccionamientos</translation>
<translation id="445467742685312942">Permitir que los sitios reproduzcan contenido protegido</translation>
<translation id="4468959413250150279">Silenciar un sitio específico.</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">Esta opción está disponible cerca de la parte superior de la pantalla.</translation>
<translation id="5197729504361054390">Los contactos que selecciones se compartirán con <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />.</translation>
<translation id="5216942107514965959">Última visita: hoy</translation>
+<translation id="5264323282659631142">Quitar "<ph name="CHIP_LABEL" />"</translation>
<translation id="528192093759286357">Arrastra el dedo desde la parte superior y toca el botón Atrás para salir de la pantalla completa.</translation>
<translation id="5300589172476337783">Mostrar</translation>
<translation id="5301954838959518834">Entendido</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">Esta acción borrará <ph name="DATASIZE" /> de datos y cookies que almacenaron los sitios.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(1 más)}other{(# más)}}</translation>
<translation id="5403592356182871684">Nombres</translation>
+<translation id="5412236728747081950">Este sitio obtiene tus intereses de Chrome para mostrarte anuncios más relevantes</translation>
<translation id="5438097262470833822">Esta acción restablecerá los permisos de <ph name="WEBSITE" />.</translation>
<translation id="5489227211564503167">Tiempo transcurrido: <ph name="ELAPSED_TIME" /> de <ph name="TOTAL_TIME" />.</translation>
<translation id="5494752089476963479">Bloquear anuncios de sitios que muestran anuncios intrusivos o engañosos</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">Cargar de nuevo</translation>
<translation id="5596627076506792578">Más opciones</translation>
<translation id="5649053991847567735">Descargas automáticas</translation>
+<translation id="5668404140385795438">Anular la solicitud de inhabilitación del zoom de un sitio web</translation>
<translation id="5677928146339483299">Bloqueado</translation>
<translation id="5689516760719285838">Ubicación</translation>
<translation id="5690795753582697420">La cámara está desactivada en la configuración de Android</translation>
-<translation id="5710871682236653961">Preguntar antes de permitir que los sitios envíen y reciban información cuando presionas dispositivos NFC (recomendado)</translation>
<translation id="5719847187258001597">Esta acción borrará todos los datos y cookies almacenados por <ph name="ORIGIN" /> o su app que aparece en la pantalla principal.</translation>
<translation id="5771720122942595109">Bloqueado: <ph name="PERMISSION_1" /></translation>
<translation id="5804241973901381774">Permisos</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">Reproducir</translation>
<translation id="6818926723028410516">Seleccionar elementos</translation>
<translation id="6864395892908308021">Este dispositivo no puede leer NFC</translation>
-<translation id="6910211073230771657">Eliminado</translation>
<translation id="6912998170423641340">Impedir que los sitios lean el texto y las imágenes del portapapeles</translation>
<translation id="6945221475159498467">Seleccionar</translation>
<translation id="6965382102122355670">Aceptar</translation>
+<translation id="6981982820502123353">Accesibilidad</translation>
<translation id="6992289844737586249">Preguntar primero antes de permitir que los sitios usen tu micrófono (recomendado)</translation>
<translation id="7000754031042624318">Desactivado en la configuración de Android</translation>
<translation id="7016516562562142042">Se habilitó para el motor de búsqueda actual</translation>
+<translation id="702463548815491781">Se recomienda cuando TalkBack o Accesibilidad con interruptores están activadas</translation>
<translation id="7053983685419859001">Bloquear</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1 seleccionado}other{# seleccionados}}</translation>
-<translation id="7070090581017165256">Acerca de este sitio</translation>
<translation id="7087918508125750058">Elementos seleccionados: <ph name="ITEM_COUNT" />. Opciones disponibles cerca de la parte superior de la pantalla</translation>
<translation id="7141896414559753902">Bloquea las ventanas emergentes y los redireccionamientos en los sitios (recomendado)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> KB</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">Un sitio está utilizando el micrófono</translation>
<translation id="7561196759112975576">Siempre</translation>
-<translation id="7572498721684305250">Impide que los sitios envíen y reciban información cuando presionas dispositivos NFC</translation>
<translation id="757524316907819857">Impedir que los sitios reproduzcan contenido protegido</translation>
+<translation id="7577900504646297215">Administrar intereses</translation>
<translation id="7649070708921625228">Ayuda</translation>
<translation id="7658239707568436148">Cancelar</translation>
<translation id="7781829728241885113">Ayer</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">La conexión es segura</translation>
<translation id="8249310407154411074">Mover al principio</translation>
<translation id="8261506727792406068">Borrar</translation>
+<translation id="8284326494547611709">Subtítulos</translation>
<translation id="8300705686683892304">Administrados por una app</translation>
<translation id="8324158725704657629">No volver a preguntar</translation>
<translation id="8372893542064058268">Permite la sincronización en segundo plano para un sitio específico.</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">Acercar</translation>
<translation id="8921772741368021346"><ph name="POSITION" /> / <ph name="DURATION" /></translation>
<translation id="8926666909099850184">La tecnología NFC está desactivada en este dispositivo. Actívala en la <ph name="BEGIN_LINK" />Configuración de Android<ph name="END_LINK" />.</translation>
+<translation id="8928445016601307354">No permitir que los sitio vean y cambien la información de los dispositivos NFC</translation>
<translation id="8941729603749328384">www.ejemplo.com</translation>
<translation id="8958424370300090006">Bloquea las cookies en un sitio específico.</translation>
<translation id="8959122750345127698">Navegación inaccesible: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_es.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_es.xtb
index 8fdcc43fd36..0dfdd31950e 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_es.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_es.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">Se ha añadido el sitio <ph name="SITE_NAME" /></translation>
<translation id="1383876407941801731">Buscar</translation>
<translation id="1384959399684842514">Descarga en pausa</translation>
+<translation id="1409426117486808224">Vista simplificada de las pestañas abiertas</translation>
<translation id="1415402041810619267">URL truncada</translation>
<translation id="1446450296470737166">Control total dispositivos MIDI</translation>
<translation id="1620510694547887537">Cámara</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">Permitir cookies</translation>
<translation id="2228071138934252756">Para que <ph name="APP_NAME" /> pueda acceder a tu cámara, activa la cámara también en los <ph name="BEGIN_LINK" />ajustes de Android<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Solo una vez</translation>
+<translation id="2253414712144136228"><ph name="NAME_OF_LIST_ITEM" /> Eliminar</translation>
<translation id="2289270750774289114">Preguntar cuando un sitio web quiera buscar dispositivos Bluetooth cercanos (recomendado)</translation>
<translation id="2315043854645842844">El sistema operativo no admite la selección de certificados de cliente.</translation>
+<translation id="2321958826496381788">Arrastra el control deslizante hasta que puedas leer cómodamente. El texto debe tener al menos este tamaño después de tocar un párrafo dos veces.</translation>
<translation id="2359808026110333948">Continuar</translation>
<translation id="2379925928934107488">El tema oscuro se aplica a los sitios si Chrome lo usa y es posible</translation>
+<translation id="2387895666653383613">Ajuste de texto</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> y <ph name="NUM_MORE" /> más permitidos}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> y <ph name="NUM_MORE" /> más permitidos}}</translation>
<translation id="2434158240863470628">Descarga finalizada <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">Mostrar información</translation>
<translation id="3123473560110926937">Bloqueados en algunos sitios</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> de datos almacenados</translation>
+<translation id="3203366800380907218">Información del sitio web</translation>
<translation id="321187648315454507">Para que <ph name="APP_NAME" /> pueda enviarte notificaciones, actívalas también en los <ph name="BEGIN_LINK" />ajustes de Android<ph name="END_LINK" />.</translation>
<translation id="3227137524299004712">Micrófono</translation>
<translation id="3277252321222022663">Permitir que los sitios accedan a los sensores (recomendado)</translation>
@@ -97,7 +102,7 @@
<translation id="3333961966071413176">Todos los contactos</translation>
<translation id="3386292677130313581">Preguntar antes de permitir que los sitios detecten tu ubicación (recomendado)</translation>
<translation id="3538390592868664640">No permitir que los sitios creen un mapa 3D de tu entorno o hagan un seguimiento de la posición de la cámara</translation>
-<translation id="3551268116566418498">¿Salir del modo de incógnito?</translation>
+<translation id="3551268116566418498">¿Salir del modo Incógnito?</translation>
<translation id="3586500876634962664">Uso de cámara y micrófono</translation>
<translation id="358794129225322306">Permitir que un sitio web descargue varios archivos automáticamente.</translation>
<translation id="3594780231884063836">Silenciar vídeo</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">Uso de tu dispositivo</translation>
<translation id="385051799172605136">Volver</translation>
<translation id="3859306556332390985">Buscar hacia delante</translation>
+<translation id="3895926599014793903">Forzar zoom</translation>
<translation id="3955193568934677022">Permitir que los sitios reproduzcan contenido protegido (recomendado)</translation>
<translation id="3967822245660637423">Descarga completa</translation>
<translation id="3987993985790029246">Copiar enlace</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" />/?</translation>
<translation id="4002066346123236978">Título</translation>
<translation id="4008040567710660924">Permitir cookies en un sitio específico.</translation>
+<translation id="4040330681741629921">Recibir una notificación cuando un sitio pueda mostrarse en vista simplificada</translation>
<translation id="4046123991198612571">Pista siguiente</translation>
-<translation id="4165986682804962316">Configuración de sitios</translation>
+<translation id="4149994727733219643">Vista simplificada de páginas web</translation>
+<translation id="4165986682804962316">Configuración del sitio</translation>
+<translation id="4194328954146351878">Pregunta antes de permitir que los sitios vean y cambien la información de los dispositivos NFC (recomendado)</translation>
<translation id="4200726100658658164">Abrir Ajustes de ubicación</translation>
<translation id="4226663524361240545">Es posible que las notificaciones hagan que el dispositivo vibre</translation>
<translation id="4259722352634471385">Se ha bloqueado la navegación: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">Mostrar</translation>
<translation id="4336434711095810371">Borrar todos los datos</translation>
<translation id="4402755511846832236">Impide que los sitios detecten cuándo usas activamente este dispositivo</translation>
+<translation id="4428065317363009941">Personalización de anuncios</translation>
<translation id="4434045419905280838">Ventanas emergentes y redirecciones</translation>
<translation id="445467742685312942">Permitir que los sitios reproduzcan contenido protegido</translation>
<translation id="4468959413250150279">Silencia el sonido de un sitio específico.</translation>
@@ -147,15 +157,16 @@
<translation id="5014906230196386306">¿Borrar cookies?</translation>
<translation id="5039804452771397117">Permitir</translation>
<translation id="5048398596102334565">Permitir que los sitios accedan a los sensores de movimiento (recomendado)</translation>
-<translation id="5050380848339752099">Este sitio va a compartir información con una aplicación fuera del modo de incógnito.</translation>
+<translation id="5050380848339752099">Este sitio va a compartir información con una aplicación fuera del modo Incógnito.</translation>
<translation id="5063480226653192405">Uso</translation>
<translation id="509133520954049755">Solicita la vista para ordenador</translation>
<translation id="5100237604440890931">Contraído (hacer clic para ampliar)</translation>
-<translation id="5123685120097942451">Pestaña de incógnito</translation>
+<translation id="5123685120097942451">Pestaña de Incógnito</translation>
<translation id="5134599672855298214">Solicita la vista para móvil (recomendada)</translation>
<translation id="5186036860380548585">Opción disponible cerca de la parte superior de la pantalla</translation>
<translation id="5197729504361054390">Los contactos que selecciones se compartirán con <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />.</translation>
<translation id="5216942107514965959">Última visita: hoy</translation>
+<translation id="5264323282659631142">Quitar "<ph name="CHIP_LABEL" />"</translation>
<translation id="528192093759286357">Arrastra el dedo desde la parte superior y toca el botón de retroceso para salir de la pantalla completa.</translation>
<translation id="5300589172476337783">Mostrar</translation>
<translation id="5301954838959518834">Entendido</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">Esta acción borrará <ph name="DATASIZE" /> de datos y cookies almacenados por sitios.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(y 1 más)}other{(y # más)}}</translation>
<translation id="5403592356182871684">Nombres</translation>
+<translation id="5412236728747081950">Este sitio consulta tus intereses en Chrome para mostrarte anuncios más relevantes</translation>
<translation id="5438097262470833822">Se restablecerán los permisos de <ph name="WEBSITE" />.</translation>
<translation id="5489227211564503167">Tiempo transcurrido: <ph name="ELAPSED_TIME" /> de <ph name="TOTAL_TIME" />.</translation>
<translation id="5494752089476963479">Bloquea anuncios invasivos o engañosos en los sitios que los muestran</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">Volver a cargar</translation>
<translation id="5596627076506792578">Más opciones</translation>
<translation id="5649053991847567735">Descargas automáticas</translation>
+<translation id="5668404140385795438">Ignorar la solicitud de un sitio web para no ampliar la imagen</translation>
<translation id="5677928146339483299">Bloqueado</translation>
<translation id="5689516760719285838">Ubicación</translation>
<translation id="5690795753582697420">La cámara está desactivada en los ajustes de Android</translation>
-<translation id="5710871682236653961">Preguntar antes de permitir que los sitios envíen y reciban información cuando toques dispositivos NFC (recomendado)</translation>
<translation id="5719847187258001597">Esta acción borrará todos los datos y cookies almacenados por <ph name="ORIGIN" /> y su aplicación en tu pantalla de inicio.</translation>
<translation id="5771720122942595109"><ph name="PERMISSION_1" /> bloqueado</translation>
<translation id="5804241973901381774">Permisos</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">Reproducir</translation>
<translation id="6818926723028410516">Seleccionar elementos</translation>
<translation id="6864395892908308021">Este dispositivo no puede leer NFC</translation>
-<translation id="6910211073230771657">Eliminado</translation>
<translation id="6912998170423641340">Evitar que los sitios lean texto e imágenes del portapapeles</translation>
<translation id="6945221475159498467">Seleccionar</translation>
<translation id="6965382102122355670">Aceptar</translation>
+<translation id="6981982820502123353">Accesibilidad</translation>
<translation id="6992289844737586249">Preguntar antes de permitir que los sitios utilicen el micrófono (recomendado)</translation>
<translation id="7000754031042624318">Desactivado en los ajustes de Android</translation>
<translation id="7016516562562142042">Permitido en el motor de búsqueda actual</translation>
+<translation id="702463548815491781">Se recomienda cuando TalkBack o la accesibilidad con interruptores están activados</translation>
<translation id="7053983685419859001">Bloquear</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1 seleccionada}other{# seleccionadas}}</translation>
-<translation id="7070090581017165256">Acerca de este sitio</translation>
<translation id="7087918508125750058">Elementos seleccionados: <ph name="ITEM_COUNT" />. Hay opciones disponibles en la parte superior de la pantalla</translation>
<translation id="7141896414559753902">Impide que los sitios muestren ventanas emergentes y redirecciones (recomendado)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> kB</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">Un sitio web está usando tu micrófono</translation>
<translation id="7561196759112975576">Siempre</translation>
-<translation id="7572498721684305250">No permitir que los sitios envíen y reciban información cuando toques dispositivos NFC</translation>
<translation id="757524316907819857">No permitir que los sitios reproduzcan contenido protegido</translation>
+<translation id="7577900504646297215">Gestionar intereses</translation>
<translation id="7649070708921625228">Ayuda</translation>
<translation id="7658239707568436148">Cancelar</translation>
<translation id="7781829728241885113">Ayer</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">La conexión es segura</translation>
<translation id="8249310407154411074">Mover al principio</translation>
<translation id="8261506727792406068">Eliminar</translation>
+<translation id="8284326494547611709">Subtítulos</translation>
<translation id="8300705686683892304">Administrados por una aplicación</translation>
<translation id="8324158725704657629">No volver a preguntar</translation>
<translation id="8372893542064058268">Permite la sincronización en segundo plano de un sitio específico.</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">Acercar</translation>
<translation id="8921772741368021346"><ph name="POSITION" />/<ph name="DURATION" /></translation>
<translation id="8926666909099850184">La tecnología NFC está desactivada en este dispositivo. Actívala en los <ph name="BEGIN_LINK" />ajustes de Android<ph name="END_LINK" />.</translation>
+<translation id="8928445016601307354">Impide que los sitios vean y cambien la información de los dispositivos NFC</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">Bloquear las cookies de un sitio específico.</translation>
<translation id="8959122750345127698">No se puede realizar la navegación: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_et.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_et.xtb
index c9ca1c756e4..584dd0e145f 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_et.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_et.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676"><ph name="SITE_NAME" /> on lisatud</translation>
<translation id="1383876407941801731">Otsi</translation>
<translation id="1384959399684842514">Allalaadimine peatatud</translation>
+<translation id="1409426117486808224">Avatud vahelehtede lihtsustatud vaade</translation>
<translation id="1415402041810619267">Lühendatud URL</translation>
<translation id="1446450296470737166">MIDI-seadm. täieliku juht. lub.</translation>
<translation id="1620510694547887537">Kaamera</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">Luba küpsisefailid</translation>
<translation id="2228071138934252756">Selleks et anda rakendusele <ph name="APP_NAME" /> juurdepääs teie kaamerale, lülitage kaamera sisse ka <ph name="BEGIN_LINK" />Androidi seadetes<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Ainult ühe korra</translation>
+<translation id="2253414712144136228"><ph name="NAME_OF_LIST_ITEM" /> Eemalda</translation>
<translation id="2289270750774289114">Küsi, kui sait soovib läheduses asuvaid Bluetoothi seadmeid tuvastada (soovitatav)</translation>
<translation id="2315043854645842844">Operatsioonisüsteem ei toeta kliendipoolset sertifikaadi valimist.</translation>
+<translation id="2321958826496381788">Lohistage liugurit, kuni saate seda mugavalt lugeda. Lõigu topeltkoputamisel peab tekst olema vähemalt nii suur.</translation>
<translation id="2359808026110333948">Jätka</translation>
<translation id="2379925928934107488">Kui Chrome kasutab tumedat teemat, rakendatakse saitidele võimaluse korral tume teema</translation>
+<translation id="2387895666653383613">Teksti skaleerimine</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ja veel <ph name="NUM_MORE" /> on lubatud}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ja veel <ph name="NUM_MORE" /> on lubatud}}</translation>
<translation id="2434158240863470628">Allalaadimine jõudis lõpule: <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">Kuva teave</translation>
<translation id="3123473560110926937">Blokeeritud teatud saitidel</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> salvestatud andmeid</translation>
+<translation id="3203366800380907218">Veebist</translation>
<translation id="321187648315454507">Selleks et lubada rakendusel <ph name="APP_NAME" /> teile märguandeid saata, lülitage märguanded sisse ka <ph name="BEGIN_LINK" />Androidi seadetes<ph name="END_LINK" />.</translation>
<translation id="3227137524299004712">Mikrofon</translation>
<translation id="3277252321222022663">Luba saitide jaoks juurdepääs anduritele (soovitatav)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">Teie seadmekasutus</translation>
<translation id="385051799172605136">Tagasi</translation>
<translation id="3859306556332390985">Keri edasi</translation>
+<translation id="3895926599014793903">Sundluba suumimine</translation>
<translation id="3955193568934677022">Luba saitidel esitada kaitstud sisu (soovitatav)</translation>
<translation id="3967822245660637423">Allalaadimine on lõpule viidud</translation>
<translation id="3987993985790029246">Kop. link</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> / ?</translation>
<translation id="4002066346123236978">Pealkiri</translation>
<translation id="4008040567710660924">Lubage konkreetse saidi küpsisefailid.</translation>
+<translation id="4040330681741629921">Saate märguande, kui saiti saab kuvada lihtsustatud vaates</translation>
<translation id="4046123991198612571">Järgmine lugu</translation>
+<translation id="4149994727733219643">Veebilehtede lihtsustatud vaade</translation>
<translation id="4165986682804962316">Saidi seaded</translation>
+<translation id="4194328954146351878">Teilt küsitakse luba, kui saidid üritavad NFC-seadmetes teavet vaadata ja muuta (soovitatav)</translation>
<translation id="4200726100658658164">Ava asukohaseaded</translation>
<translation id="4226663524361240545">Seade võib märguannete korral vibreerida</translation>
<translation id="4259722352634471385">Navigeerimine on blokeeritud: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">Laienda</translation>
<translation id="4336434711095810371">Kustuta kõik andmed</translation>
<translation id="4402755511846832236">Keelake saitidel selle tuvastamine, millal seda seadet aktiivselt kasutate</translation>
+<translation id="4428065317363009941">Reklaamide isikupärastamine</translation>
<translation id="4434045419905280838">Hüpikaknad ja ümbersuunamised</translation>
<translation id="445467742685312942">Saitidel on lubatud esitada kaitstud sisu</translation>
<translation id="4468959413250150279">Konkreetse saidi heli vaigistamine.</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">Valik on saadaval ekraanikuva ülaosas</translation>
<translation id="5197729504361054390">Teie valitud kontakte jagatakse saidiga <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />.</translation>
<translation id="5216942107514965959">Viimati külastati täna</translation>
+<translation id="5264323282659631142">Eemalda „<ph name="CHIP_LABEL" />â€</translation>
<translation id="528192093759286357">Täisekraanilt väljumiseks lohistage ülaservast alla ja puudutage tagasinuppu.</translation>
<translation id="5300589172476337783">Kuva</translation>
<translation id="5301954838959518834">Selge, sain aru</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">See kustutab <ph name="DATASIZE" /> andmed ja küpsisefailid, mille saidid on salvestanud.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(ja veel 1)}other{(ja veel #)}}</translation>
<translation id="5403592356182871684">Nimed</translation>
+<translation id="5412236728747081950">See sait hangib Chrome'ist teie huvid, et näidata teile asjakohasemaid reklaame</translation>
<translation id="5438097262470833822">Jätkates lähtestatakse veebisaidi <ph name="WEBSITE" /> load</translation>
<translation id="5489227211564503167">Kulunud aeg: <ph name="ELAPSED_TIME" />/<ph name="TOTAL_TIME" />.</translation>
<translation id="5494752089476963479">Blokeeri reklaamid saitidel, mis kuvavad sekkuvaid või eksitavaid reklaame</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">Laadi uuesti</translation>
<translation id="5596627076506792578">Rohkem valikuid</translation>
<translation id="5649053991847567735">Automaatsed allalaadimised</translation>
+<translation id="5668404140385795438">Sissesuumimise takistamiseks veebisaidi taotluse alistamine</translation>
<translation id="5677928146339483299">Blokeeritud</translation>
<translation id="5689516760719285838">Asukoht</translation>
<translation id="5690795753582697420">Kaamera on Androidi seadetes välja lülitatud</translation>
-<translation id="5710871682236653961">Küsitakse, enne kui lubatakse saitide jaoks teabe saatmine ja saamine, kui puudutate NFC-seadmeid (soovitatav)</translation>
<translation id="5719847187258001597">See kustutab saidi <ph name="ORIGIN" /> või selle rakenduse salvestatud kõik andmed ja küpsisefailid teie avakuvalt.</translation>
<translation id="5771720122942595109"><ph name="PERMISSION_1" /> on keelatud</translation>
<translation id="5804241973901381774">Load</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">Esita</translation>
<translation id="6818926723028410516">Valige üksused</translation>
<translation id="6864395892908308021">See seade ei saa NFC andmeid lugeda</translation>
-<translation id="6910211073230771657">Kustutatud</translation>
<translation id="6912998170423641340">Keela saitidel lugeda lõikelaual olevat teksti ja pilte</translation>
<translation id="6945221475159498467">Vali</translation>
<translation id="6965382102122355670">OK</translation>
+<translation id="6981982820502123353">Juurdepääsetavus</translation>
<translation id="6992289844737586249">Küsi enne saitidele minu mikrofoni kasutamiseks juurdepääsu lubamist (soovitatav)</translation>
<translation id="7000754031042624318">Androidi seadetes välja lülitatud</translation>
<translation id="7016516562562142042">Praeguse otsingumootori puhul lubatud</translation>
+<translation id="702463548815491781">Soovitatav juhul, kui TalkBack või lülitiga juurdepääs on sisse lülitatud</translation>
<translation id="7053983685419859001">Blokeeri</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1 on valitud}other{# on valitud}}</translation>
-<translation id="7070090581017165256">Teave selle saidi kohta</translation>
<translation id="7087918508125750058"><ph name="ITEM_COUNT" /> on valitud. Valikud on saadaval ekraanikuva ülaosas</translation>
<translation id="7141896414559753902">Blokeeri saitidel hüpikakende ja ümbersuunamiste kuvamine (soovitatav)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> kB</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">Sait kasutab teie mikrofoni</translation>
<translation id="7561196759112975576">Alati</translation>
-<translation id="7572498721684305250">Saitide jaoks blokeeritakse teabe saatmine ja saamine, kui puudutate NFC-seadmeid</translation>
<translation id="757524316907819857">Saitidel kaitstud sisu esitamise blokeerimine</translation>
+<translation id="7577900504646297215">Huvide haldamine</translation>
<translation id="7649070708921625228">Abi</translation>
<translation id="7658239707568436148">Tühista</translation>
<translation id="7781829728241885113">Eile</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">Ãœhendus on turvaline</translation>
<translation id="8249310407154411074">Teisalda kõige üles</translation>
<translation id="8261506727792406068">Kustuta</translation>
+<translation id="8284326494547611709">Subtiitrid</translation>
<translation id="8300705686683892304">Neid haldab rakendus</translation>
<translation id="8324158725704657629">Ära enam küsi</translation>
<translation id="8372893542064058268">Konkreetse saidi jaoks taustal sünkroonimise lubamine.</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">Suurendab</translation>
<translation id="8921772741368021346"><ph name="POSITION" />/<ph name="DURATION" /></translation>
<translation id="8926666909099850184">NFC on selle seadme puhul välja lülitatud. Lülitage see <ph name="BEGIN_LINK" />Androidi seadetes<ph name="END_LINK" /> sisse.</translation>
+<translation id="8928445016601307354">Saitidel keelatakse NFC-seadmetes teabe nägemine ja muutmine</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">Blokeerige konkreetse saidi küpsisefailid.</translation>
<translation id="8959122750345127698">Navigeerimine ei ole saadaval: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_eu.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_eu.xtb
index a2c59c0a8bb..49b41e9e9dc 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_eu.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_eu.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676"><ph name="SITE_NAME" /> webgunea gehitu da</translation>
<translation id="1383876407941801731">Bilaketa</translation>
<translation id="1384959399684842514">Pausatu da deskarga</translation>
+<translation id="1409426117486808224">Irekitako fitxen ikuspegi sinplifikatua</translation>
<translation id="1415402041810619267">URLa moztuta dago</translation>
<translation id="1446450296470737166">Onartu MIDI gailuen kontrol osoa</translation>
<translation id="1620510694547887537">Kamera</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">Onartu cookieak</translation>
<translation id="2228071138934252756"><ph name="APP_NAME" /> aplikazioari kamera atzitzeko baimena emateko, kamera atzitzeko baimena aktibatu behar duzu <ph name="BEGIN_LINK" />Android-en ezarpenetan<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Behin soilik</translation>
+<translation id="2253414712144136228">Kendu <ph name="NAME_OF_LIST_ITEM" /></translation>
<translation id="2289270750774289114">Eskatu nire baimena webgune batek inguruko Bluetooth bidezko gailuak bilatu nahi dituenean (gomendatua)</translation>
<translation id="2315043854645842844">Sistema eragileak ez du onartzen bezeroarentzako ziurtagiria hautatzea.</translation>
+<translation id="2321958826496381788">Arrastatu graduatzailea testu hau erraz irakurri ahal izan arte. Testuak gutxienez hau bezain handia izan beharko du paragrafoan klik bikoitza egin ondoren.</translation>
<translation id="2359808026110333948">Egin aurrera</translation>
<translation id="2379925928934107488">Chrome-n gai iluna erabiltzeko aukera ezarrita badago, aplikatu gai iluna webguneetan, ahal denean</translation>
+<translation id="2387895666653383613">Testua doitzea</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Baimena eman zaie hauei: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> eta beste <ph name="NUM_MORE" />}other{Baimena eman zaie hauei: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> eta beste <ph name="NUM_MORE" />}}</translation>
<translation id="2434158240863470628">Deskargatu da <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">Erakutsi informazioa</translation>
<translation id="3123473560110926937">Webgune batzuetan blokeatu dira iragarkiak</translation>
<translation id="3198916472715691905">Gordetako datuak: <ph name="STORAGE_AMOUNT" /></translation>
+<translation id="3203366800380907218">Saretik</translation>
<translation id="321187648315454507"><ph name="APP_NAME" /> aplikazioari jakinarazpenak bidaltzeko baimena emateko, jakinarazpenak bidaltzeko baimena aktibatu behar duzu <ph name="BEGIN_LINK" />Android-en ezarpenetan<ph name="END_LINK" />.</translation>
<translation id="3227137524299004712">Mikrofonoa</translation>
<translation id="3277252321222022663">Eman sentsoreak atzitzeko baimena webguneei (gomendatua)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">Gailuaren erabilera</translation>
<translation id="385051799172605136">Atzera</translation>
<translation id="3859306556332390985">Aurreratu</translation>
+<translation id="3895926599014793903">Behartu zooma gaitzera</translation>
<translation id="3955193568934677022">Baimendu webguneei eduki babestua erreproduzitzea (gomendatua)</translation>
<translation id="3967822245660637423">Deskargatzen amaitu da</translation>
<translation id="3987993985790029246">Kopiatu esteka</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> / ?</translation>
<translation id="4002066346123236978">Izena</translation>
<translation id="4008040567710660924">Onartu webgune zehatz baten cookieak.</translation>
+<translation id="4040330681741629921">Jaso jakinarazpen bat webgune bat ikuspegi sinplifikatuan erakuts daitekeenean</translation>
<translation id="4046123991198612571">Hurrengo pista</translation>
+<translation id="4149994727733219643">Web-orrien ikuspegi sinplifikatua</translation>
<translation id="4165986682804962316">Webgunearen ezarpenak</translation>
+<translation id="4194328954146351878">Webguneei NFC darabilten gailuetako informazioa ikusi eta aldatzeko baimena eman aurretik, eskatu onespena (gomendatua)</translation>
<translation id="4200726100658658164">Ireki kokapen-ezarpenak</translation>
<translation id="4226663524361240545">Gailua dardararaz dezakete jakinarazpenek</translation>
<translation id="4259722352634471385"><ph name="URL" /> orrira joateko aukera blokeatuta dago</translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">Zabaldu</translation>
<translation id="4336434711095810371">Garbitu datu guztiak</translation>
<translation id="4402755511846832236">Ez utzi jakiten webguneei gailua noiz erabiltzen ari zaren</translation>
+<translation id="4428065317363009941">Iragarkien pertsonalizazioa</translation>
<translation id="4434045419905280838">Leiho gainerak. / Birbideratzeak</translation>
<translation id="445467742685312942">Baimendu webguneei eduki babestua erreproduzitzea</translation>
<translation id="4468959413250150279">Desaktibatu webgune jakin baten audioa.</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">Aukera pantailaren goialdean dago</translation>
<translation id="5197729504361054390">Hautatzen dituzun kontaktuak <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> webgunearekin partekatuko dira.</translation>
<translation id="5216942107514965959">Gaur bisitatu duzu azkenengoz</translation>
+<translation id="5264323282659631142">Kendu "<ph name="CHIP_LABEL" />"</translation>
<translation id="528192093759286357">Pantaila osoko ikuspegitik irteteko, arrastatu goitik eta ukitu Atzera botoia.</translation>
<translation id="5300589172476337783">Erakutsi</translation>
<translation id="5301954838959518834">Ados, ulertu dut</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">Webguneek gordetako datu eta cookieen <ph name="DATASIZE" /> garbituko dira.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(eta beste bat)}other{(eta beste #)}}</translation>
<translation id="5403592356182871684">Izenak</translation>
+<translation id="5412236728747081950">Webgune honek Chrome-n oinarritzen da zure interesen berri izateko, iragarki erabilgarriagoak erakuts diezazkizun</translation>
<translation id="5438097262470833822"><ph name="WEBSITE" /> webgunearen baimenak berrezarriko dira</translation>
<translation id="5489227211564503167"><ph name="ELAPSED_TIME" /> igaro dira, eta <ph name="TOTAL_TIME" /> gelditzen</translation>
<translation id="5494752089476963479">Blokeatu iragarki oztopatzaileak edo iruzurrezkoak erakusten dituzten webguneetako iragarkiak</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">Kargatu berriro</translation>
<translation id="5596627076506792578">Aukera gehiago</translation>
<translation id="5649053991847567735">Deskarga automatikoak</translation>
+<translation id="5668404140385795438">Gainidatzi zoom-maila ez handiagotzeko webgune baten eskaera</translation>
<translation id="5677928146339483299">Blokeatuta</translation>
<translation id="5689516760719285838">Kokapena</translation>
<translation id="5690795753582697420">Kamera atzitzeko baimena desaktibatuta dago Android-en ezarpenetan</translation>
-<translation id="5710871682236653961">NFC darabilten gailuak ukitzean, eskatu baimena webguneei informazioa bidali eta jasotzeko (gomendatua)</translation>
<translation id="5719847187258001597"><ph name="ORIGIN" /> webguneak edo hari dagokion hasierako pantailako aplikazioak gorde dituen datu eta cookie guztiak garbituko dira.</translation>
<translation id="5771720122942595109"><ph name="PERMISSION_1" /> blokeatu egin da</translation>
<translation id="5804241973901381774">Baimenak</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">Erreproduzitu</translation>
<translation id="6818926723028410516">Hautatu elementuak</translation>
<translation id="6864395892908308021">Gailu honek ezin du irakurri NFC</translation>
-<translation id="6910211073230771657">Ezabatu egin da</translation>
<translation id="6912998170423641340">Ez utzi webguneei arbeleko testua eta irudiak ikusten</translation>
<translation id="6945221475159498467">Hautatu</translation>
<translation id="6965382102122355670">Ados</translation>
+<translation id="6981982820502123353">Erabilerraztasuna</translation>
<translation id="6992289844737586249">Webguneei mikrofonoa erabiltzeko baimena eman aurretik, eskatu onespena (gomendatua)</translation>
<translation id="7000754031042624318">Desaktibatuta dago Android-en ezarpenetan</translation>
<translation id="7016516562562142042">Baimenduta dago oraingo bilatzailean</translation>
+<translation id="702463548815491781">TalkBack edo Erabilerraztasun-osagarria aktibatuta daudenean gomendatua</translation>
<translation id="7053983685419859001">Blokeatu</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1 hautatuta}other{# hautatuta}}</translation>
-<translation id="7070090581017165256">Webgune honi buruz</translation>
<translation id="7087918508125750058"><ph name="ITEM_COUNT" /> hautatu dira. Pantailaren goialdean daude aukera erabilgarriak.</translation>
<translation id="7141896414559753902">Ez utzi webguneei leiho gainerakorrak eta birbideratzeak erakusten (gomendatua)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> kB</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">Webgune bat mikrofonoa erabiltzen ari da</translation>
<translation id="7561196759112975576">Beti</translation>
-<translation id="7572498721684305250">Blokeatu webguneak, ez dezaten bidali eta jaso informaziorik NFC darabilten gailuak ukitzen dituzunean.</translation>
<translation id="757524316907819857">Ez utzi webguneei eduki babestua erreproduzitzen</translation>
+<translation id="7577900504646297215">Kudeatu interesak</translation>
<translation id="7649070708921625228">Laguntza</translation>
<translation id="7658239707568436148">Utzi</translation>
<translation id="7781829728241885113">Atzo</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">Konexioa segurua da</translation>
<translation id="8249310407154411074">Eraman goraino</translation>
<translation id="8261506727792406068">Ezabatu</translation>
+<translation id="8284326494547611709">Azpitituluak</translation>
<translation id="8300705686683892304">Aplikazio batek kudeatzen du</translation>
<translation id="8324158725704657629">Ez galdetu berriro</translation>
<translation id="8372893542064058268">Baimendu atzeko planoko sinkronizazioa webgune zehatz batean.</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">Handitu</translation>
<translation id="8921772741368021346"><ph name="POSITION" />/<ph name="DURATION" /></translation>
<translation id="8926666909099850184">NFC aukera desaktibatuta dago gailu honetan. Aktiba ezazu <ph name="BEGIN_LINK" />Android-en ezarpenetan<ph name="END_LINK" />.</translation>
+<translation id="8928445016601307354">Ez utzi webguneei NFC darabilten gailuetako informazioa ikusten eta aldatzen</translation>
<translation id="8941729603749328384">www.adibidea.com</translation>
<translation id="8958424370300090006">Blokeatu webgune jakin bateko cookieak.</translation>
<translation id="8959122750345127698">Ezin da joan <ph name="URL" /> orrira</translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_fa.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_fa.xtb
index a0544e4848c..07483f82044 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_fa.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_fa.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">سایت <ph name="SITE_NAME" /> اضاÙÙ‡ شد</translation>
<translation id="1383876407941801731">جستجو</translation>
<translation id="1384959399684842514">بارگیری موقتاً متوق٠شد</translation>
+<translation id="1409426117486808224">نمای ساده‌شده برای برگه‌های باز</translation>
<translation id="1415402041810619267">نشانی وب کوتاه‌شده</translation>
<translation id="1446450296470737166">â€Ø§Ø¬Ø§Ø²Ù‡ کنترل کامل دستگاه‌های MIDI</translation>
<translation id="1620510694547887537">دوربین</translation>
@@ -34,7 +35,7 @@
<translation id="1919345977826869612">آگهی‌ها</translation>
<translation id="1919950603503897840">انتخاب مخاطبین</translation>
<translation id="1923695749281512248">‎<ph name="BYTES_DOWNLOADED_WITH_UNITS" /> / <ph name="FILE_SIZE_WITH_UNITS" />‎</translation>
-<translation id="1984937141057606926">مجاز، به غیر از طر٠ثالث</translation>
+<translation id="1984937141057606926">مجاز، به‌غیراز شخص ثالث</translation>
<translation id="1989112275319619282">مشاهده محتوای موجود در Ùروشگاه ما</translation>
<translation id="1994173015038366702">نشانی وب سایت</translation>
<translation id="2004697686368036666">ممکن است ویژگی‌های برخی‌از سایت‌ها کار نکند</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">مجاز کردن کوکی ها</translation>
<translation id="2228071138934252756">â€Ø¨Ø±Ø§ÛŒ اینکه به <ph name="APP_NAME" /> اجازه دهید به دوربین دسترسی پیدا کند، دوربین را در <ph name="BEGIN_LINK" />تنظیمات Android<ph name="END_LINK" /> نیز روشن کنید.</translation>
<translation id="2241634353105152135">Ùقط یک بار</translation>
+<translation id="2253414712144136228">برداشتن <ph name="NAME_OF_LIST_ITEM" /></translation>
<translation id="2289270750774289114">وقتی سایتی می‌خواهد دستگا‌ه‌های بلوتوث اطرا٠را پیدا کند، سؤال شود (توصیه می‌شود)</translation>
<translation id="2315043854645842844">انتخاب گواهی سمت کلاینت توسط سیستم‌عامل پشتیبانی نمی‌شود.</translation>
+<translation id="2321958826496381788">لغزنده را بکشید تا زمانی Ú©Ù‡ بتوانید این متن را به راحتی بخوانید. بعد از دو ضربه متوالی روی یک پاراگراÙØŒ اندازه نوشتار حداقل باید به این بزرگی باشد.</translation>
<translation id="2359808026110333948">ادامه</translation>
-<translation id="2379925928934107488">â€Ø§Ø³ØªÙاده از طرح زمینه تیره برای سایت‌ها وقتی Chrome از طرح زمینه تیره استÙاده می‌کند (هرگاه ممکن باشد)</translation>
+<translation id="2379925928934107488">â€Ø§Ø³ØªÙاده از زمینه تیره برای سایت‌ها وقتی Chrome از زمینه تیره استÙاده می‌کند (هرگاه ممکن باشد)</translation>
+<translation id="2387895666653383613">مقیاس‌گذاری نوشتار</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> مگابایت</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />، <ph name="PERMISSION_2" />، و <ph name="NUM_MORE" /> اجازه دیگر مجاز هستند}one{<ph name="PERMISSION_1" />، <ph name="PERMISSION_2" />، و <ph name="NUM_MORE" /> اجازه دیگر مجاز هستند}other{<ph name="PERMISSION_1" />، <ph name="PERMISSION_2" />، و <ph name="NUM_MORE" /> اجازه دیگر مجاز هستند}}</translation>
<translation id="2434158240863470628">بارگیری کامل شد <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -66,7 +70,7 @@
<translation id="2570922361219980984">â€Ø¯Ø³ØªØ±Ø³ÛŒ به مکان برای این دستگاه نیز خاموش است. آن را در <ph name="BEGIN_LINK" />تنظیمات Android<ph name="END_LINK" /> روشن کنید.</translation>
<translation id="257931822824936280">بزرگ‌شده - برای کوچک کردن کلیک کنید.</translation>
<translation id="2586657967955657006">بریده‌دان</translation>
-<translation id="2597457036804169544">طرح زمینه تیره برای سایت‌ها استÙاده نشود</translation>
+<translation id="2597457036804169544">زمینه تیره برای سایت‌ها استÙاده نشود</translation>
<translation id="2621115761605608342">جاوااسکریپت را برای سایتی خاص مجاز کنید.</translation>
<translation id="2653659639078652383">ارسال</translation>
<translation id="2677748264148917807">خروج</translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">نمایش دادن اطلاعات</translation>
<translation id="3123473560110926937">در برخی سایت‌ها مسدود می‌شود</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> داده‌های ذخیره شده</translation>
+<translation id="3203366800380907218">برگرÙته از وب</translation>
<translation id="321187648315454507">â€Ø¨Ø±Ø§ÛŒ اینکه به <ph name="APP_NAME" /> اجازه دهید برایتان اعلان ارسال کند، اعلان‌ها را در <ph name="BEGIN_LINK" />تنظیمات Android<ph name="END_LINK" /> نیز روشن کنید.</translation>
<translation id="3227137524299004712">میکروÙÙ†</translation>
<translation id="3277252321222022663">مجاز بودن دسترسی سایت‌ها به حسگرها (توصیه می‌شود)</translation>
@@ -105,19 +110,23 @@
<translation id="3600792891314830896">سایت‌هایی که صدا پخش می‌کنند بی‌صدا شوند</translation>
<translation id="3744111561329211289">همگام‌سازی پس‌زمینه</translation>
<translation id="3763247130972274048">در سمت راست یا چپ ویدیو دو ضربه سریع بزنید تا ۱۰ ثانیه رد شود</translation>
-<translation id="3797520601150691162">طرح زمینه تیره برای سایت خاصی استÙاده نشود</translation>
+<translation id="3797520601150691162">زمینه تیره برای سایت خاصی استÙاده نشود</translation>
<translation id="381841723434055211">شماره‌های تلÙÙ†</translation>
<translation id="3835233591525155343">استÙاده از دستگاه</translation>
<translation id="385051799172605136">بازگشت</translation>
<translation id="3859306556332390985">جستجو به جلو</translation>
+<translation id="3895926599014793903">Ùعال کردن اجباری بزرگ‌نمایی</translation>
<translation id="3955193568934677022">به سایت‌ها اجازه داده شود محتوای محاÙظت‌شده پخش کنند (توصیه می‌شود)</translation>
<translation id="3967822245660637423">بارگیری کامل شد</translation>
<translation id="3987993985790029246">کپی پیوند</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> از ؟</translation>
<translation id="4002066346123236978">عنوان</translation>
<translation id="4008040567710660924">کوکی‌ها را برای سایت خاصی مجاز کنید.</translation>
+<translation id="4040330681741629921">هرزمان Ú©Ù‡ بتوان سایت را در نمای ساده‌شده نشان داد، اعلان دریاÙت می‌کنید</translation>
<translation id="4046123991198612571">آهنگ بعدی</translation>
+<translation id="4149994727733219643">نمای ساده‌شده برای صÙحه‌های وب</translation>
<translation id="4165986682804962316">تنظیمات سایت</translation>
+<translation id="4194328954146351878">â€Ù‚بل‌از اینکه به سایت‌ها اجازه داده شود اطلاعات دستگاه‌های NFC را ببینند Ùˆ تغییر دهند سؤال شود (توصیه می‌شود)</translation>
<translation id="4200726100658658164">باز کردن «تنظیمات مکان»</translation>
<translation id="4226663524361240545">اعلان‌ها ممکن است دستگاه را بلرزانند</translation>
<translation id="4259722352634471385">پیمایش مسدود شده است: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">بزرگ کردن</translation>
<translation id="4336434711095810371">پاک کردن همه داده‌ها</translation>
<translation id="4402755511846832236">از اینکه سایت‌ها بدانند Ú†Ù‡ زمانی به‌صورت Ùعال از این دستگاه استÙاده می‌کنید جلوگیری می‌شود</translation>
+<translation id="4428065317363009941">شخصی‌سازی آگهی</translation>
<translation id="4434045419905280838">پنجره‌های بازشو و هدایت‌ها</translation>
<translation id="445467742685312942">به سایت‌ها اجازه داده شود محتوای محاÙظت‌شده پخش کنند</translation>
<translation id="4468959413250150279">سایتی خاص بی‌صدا شود.</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">گزینه مربوطه در نزدیکی بالای صÙحه دردسترس است</translation>
<translation id="5197729504361054390">مخاطبین انتخابی شما با <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> هم‌رسانی می‌شود.</translation>
<translation id="5216942107514965959">آخرین بازدید: امروز</translation>
+<translation id="5264323282659631142">برداشتن «<ph name="CHIP_LABEL" />»</translation>
<translation id="528192093759286357">برای خروج از حالت تمام صÙحه، از بالا صÙحه را بکشید Ùˆ دکمه برگشت را لمس کنید.</translation>
<translation id="5300589172476337783">نمایش</translation>
<translation id="5301954838959518834">بله، متوجه شدم</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">با این کار <ph name="DATASIZE" /> از داده‌ها و کوکی‌هایی که سایت ذخیره کرده است پاک خواهد شد.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(+ ۱ مورد دیگر)}one{(+ # مورد دیگر)}other{(+ # مورد دیگر)}}</translation>
<translation id="5403592356182871684">نام‌ها</translation>
+<translation id="5412236728747081950">â€Ø§ÛŒÙ† سایت علایقتان را از Chrome می‌گیرد تا آگهی‌های مرتبط‌تری به شما نشان دهد</translation>
<translation id="5438097262470833822">این گزینه همه اجازه‌های <ph name="WEBSITE" /> را بازنشانی خواهد کرد</translation>
<translation id="5489227211564503167">زمان سپری‌شده: <ph name="ELAPSED_TIME" /> از <ph name="TOTAL_TIME" />.</translation>
<translation id="5494752089476963479">آگهی سایت‌هایی که آگهی‌های مزاحم یا گمراه‌کننده نشان می‌دهند، مسدود می‌شود</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">تازه‌سازی</translation>
<translation id="5596627076506792578">گزینه‌های بیشتر</translation>
<translation id="5649053991847567735">بارگیری‌های خودکار</translation>
+<translation id="5668404140385795438">لغو درخواست وب‌سایت برای جلوگیری از بزرگ‌نمایی</translation>
<translation id="5677928146339483299">مسدود است</translation>
<translation id="5689516760719285838">مکان</translation>
<translation id="5690795753582697420">â€Â«Ø¯ÙˆØ±Ø¨ÛŒÙ†Â» در تنظیمات Android خاموش است</translation>
-<translation id="5710871682236653961">â€ÙˆÙ‚تی روی دستگاه‌های NFC ضربه می‌زنید، قبل از ارسال Ùˆ دریاÙت اطلاعات سؤال شود (توصیه می‌شود)</translation>
<translation id="5719847187258001597">با این کار همه داده‌ها Ùˆ کوکی‌هایی Ú©Ù‡ <ph name="ORIGIN" /> Ùˆ برنامه آن در صÙحه اصلی ذخیره کرده‌اند پاک می‌شود.</translation>
<translation id="5771720122942595109"><ph name="PERMISSION_1" /> مسدود شد</translation>
<translation id="5804241973901381774">مجوزها</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">پخش</translation>
<translation id="6818926723028410516">انتخاب موارد</translation>
<translation id="6864395892908308021">â€Ø§ÛŒÙ† دستگاه نمی‌تواند NFC را بخواند</translation>
-<translation id="6910211073230771657">حذ٠شد</translation>
<translation id="6912998170423641340">سایت‌ها از خواندن نوشتار و تصاویر بریده‌دان منع شوند</translation>
<translation id="6945221475159498467">انتخاب</translation>
<translation id="6965382102122355670">قبول</translation>
+<translation id="6981982820502123353">دسترس‌پذیری</translation>
<translation id="6992289844737586249">قبل از اجازه به سایت‌ها برای استÙاده از میکروÙون ابتدا سؤال شود (توصیه می‌شود)</translation>
<translation id="7000754031042624318">â€Ø¯Ø± تنظیمات Android غیرÙعال شده است</translation>
<translation id="7016516562562142042">برای موتور جستجوی Ùعلی مجاز است</translation>
+<translation id="702463548815491781">â€ØªÙˆØµÛŒÙ‡ در زمانی‌که TalkBack یا «دسترسی کلیدی» روشن است</translation>
<translation id="7053983685419859001">مسدود کردن</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{۱ مورد انتخاب شد}one{# مورد انتخاب شد}other{# مورد انتخاب شد}}</translation>
-<translation id="7070090581017165256">درباره این سایت</translation>
<translation id="7087918508125750058"><ph name="ITEM_COUNT" /> مورد انتخاب شد. گزینه‌ها در نزدیکی بالای صÙحه دردسترس است</translation>
<translation id="7141896414559753902">مسدود کردن نمایش پنجره‌های بازشو و هدایت‌ها در سایت‌ها (توصیه می‌شود)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> کیلوبایت</translation>
@@ -250,12 +262,12 @@
<translation id="7302486331832100261">معمولاً اعلان‌ها را مسدود می‌کنید. برای مجاز کردن، روی «جزئیات» ضربه بزنید.</translation>
<translation id="7423098979219808738">ابتدا سؤال شود</translation>
<translation id="7423538860840206698">خواندن محتوای بریده‌دان مسدود شد</translation>
-<translation id="7425915948813553151">طرح زمینه تیره برای سایت‌ها</translation>
+<translation id="7425915948813553151">زمینه تیره برای سایت‌ها</translation>
<translation id="7521387064766892559">جاوا اسکریپت</translation>
<translation id="7554752735887601236">سایتی درحال استÙاده از میکروÙونتان است</translation>
<translation id="7561196759112975576">همیشه</translation>
-<translation id="7572498721684305250">â€ÙˆÙ‚تی روی دستگاه‌های NFC ضربه می‌زنید، ارسال Ùˆ دریاÙت اطلاعات در سایت‌ها مسدود شود</translation>
<translation id="757524316907819857">مسدود کردن سایت‌ها برای پخش محتوای محاÙظت‌شده</translation>
+<translation id="7577900504646297215">مدیریت علایق</translation>
<translation id="7649070708921625228">راهنما</translation>
<translation id="7658239707568436148">لغو</translation>
<translation id="7781829728241885113">دیروز</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">اتصال امن است</translation>
<translation id="8249310407154411074">انتقال به بالا</translation>
<translation id="8261506727792406068">حذÙ</translation>
+<translation id="8284326494547611709">زیرنویس‌ها</translation>
<translation id="8300705686683892304">مدیریت‌شده توسط برنامه</translation>
<translation id="8324158725704657629">دوباره سؤال نشود</translation>
<translation id="8372893542064058268">«همگام‌سازی پس‌زمینه» را برای یک سایت خاص مجاز کنید.</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">بزرگ‌نمایی</translation>
<translation id="8921772741368021346"><ph name="POSITION" /> / <ph name="DURATION" /></translation>
<translation id="8926666909099850184">â€NFC برای این دستگاه خاموش است. در <ph name="BEGIN_LINK" />تنظیمات Android<ph name="END_LINK" /> آن را روشن کنید.</translation>
+<translation id="8928445016601307354">â€Ø³Ø§ÛŒØªâ€ŒÙ‡Ø§ اجازه نداشته باشند اطلاعات دستگاه‌های NFC را ببینند Ùˆ تغییر دهند</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">کوکی‌ها را برای سایت خاصی مسدود کنید.</translation>
<translation id="8959122750345127698">پیمایش غیرقابل دسترسی است: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_fi.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_fi.xtb
index 481043abaaa..d766e3cc119 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_fi.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_fi.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">Sivusto <ph name="SITE_NAME" /> lisättiin.</translation>
<translation id="1383876407941801731">Haku</translation>
<translation id="1384959399684842514">Lataus keskeytettiin.</translation>
+<translation id="1409426117486808224">Yksinkertaisempi avoimien välilehtien näkymä</translation>
<translation id="1415402041810619267">URL näkyy lyhennettynä</translation>
<translation id="1446450296470737166">Salli MIDI-laitteiden täysi käyttöoik.</translation>
<translation id="1620510694547887537">Kamera</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">Salli evästeet</translation>
<translation id="2228071138934252756">Laita kamera päälle myös <ph name="BEGIN_LINK" />Androidin asetuksista<ph name="END_LINK" />, jotta <ph name="APP_NAME" /> saa pääsyn kameraasi.</translation>
<translation id="2241634353105152135">Vain kerran</translation>
+<translation id="2253414712144136228">Poista <ph name="NAME_OF_LIST_ITEM" /></translation>
<translation id="2289270750774289114">Kysy aina, kun sivusto pyytää lupaa löytää lähellä olevat Bluetooth-laitteet (suositus)</translation>
<translation id="2315043854645842844">Käyttöjärjestelmä ei tue palvelimen varmennevalintaa.</translation>
+<translation id="2321958826496381788">Vedä liukusäädintä, kunnes voit lukea tämän mukavasti. Tekstin tulisi olla vähintään näin suurta kaksoisnapautettuasi kappaletta.</translation>
<translation id="2359808026110333948">Jatka</translation>
<translation id="2379925928934107488">Jos mahdollista, käytä tummaa teemaa sivustoilla, kun se on Chromen käytössä</translation>
+<translation id="2387895666653383613">Tekstin skaalaus</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> Mt</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ja <ph name="NUM_MORE" /> muuta sallittu}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ja <ph name="NUM_MORE" /> muuta sallittu}}</translation>
<translation id="2434158240863470628">Lataus valmis <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,12 +93,13 @@
<translation id="3115898365077584848">Näytä tiedot</translation>
<translation id="3123473560110926937">Estetty tietyillä sivustoilla</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> tallennettua tietoa</translation>
+<translation id="3203366800380907218">Verkosta</translation>
<translation id="321187648315454507">Ota ilmoitukset käyttöön myös <ph name="BEGIN_LINK" />Androidin asetuksista<ph name="END_LINK" />, jotta <ph name="APP_NAME" /> voi lähettää sinulle ilmoituksia.</translation>
<translation id="3227137524299004712">Mikrofoni</translation>
<translation id="3277252321222022663">Anna sivustojen käyttää tunnistimia (suositus)</translation>
<translation id="3295602654194328831">Piilota tiedot</translation>
<translation id="3328801116991980348">Tietoja sivustosta</translation>
-<translation id="3333961966071413176">Kaikki yhteystiedot</translation>
+<translation id="3333961966071413176">Kaikki kontaktit</translation>
<translation id="3386292677130313581">Pyydä lupaa, kun sivustot yrittävät käyttää sijaintiasi (suositus).</translation>
<translation id="3538390592868664640">Estä sivustoja luomasta 3D-karttaa ympäristöstäsi tai seuraamasta kameran asentoa</translation>
<translation id="3551268116566418498">Poistutaanko incognito-tilasta?</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">Laitteesi käyttö</translation>
<translation id="385051799172605136">Takaisin</translation>
<translation id="3859306556332390985">Kelaa eteenpäin</translation>
+<translation id="3895926599014793903">Ota zoomaus käyttöön</translation>
<translation id="3955193568934677022">Salli sivustojen toistaa suojattua sisältöä (suositus)</translation>
<translation id="3967822245660637423">Lataus on valmis</translation>
<translation id="3987993985790029246">Kopioi linkki</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> / ?</translation>
<translation id="4002066346123236978">Nimi</translation>
<translation id="4008040567710660924">Salli evästeet tietyllä sivustolla.</translation>
+<translation id="4040330681741629921">Saat ilmoituksen, kun sivustolla voidaan käyttää yksinkertaistettua näkymää</translation>
<translation id="4046123991198612571">Seuraava kappale</translation>
+<translation id="4149994727733219643">Yksinkertaisempi sivunäkymä</translation>
<translation id="4165986682804962316">Sivustoasetukset</translation>
+<translation id="4194328954146351878">Kysy, saavatko sivustot nähdä ja muuttaa NFC-laitteiden tietoja (suositeltu)</translation>
<translation id="4200726100658658164">Avaa sijaintiasetukset</translation>
<translation id="4226663524361240545">Laite voi väristä ilmoitusten yhteydessä.</translation>
<translation id="4259722352634471385">Kohde on estetty: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">Laajenna</translation>
<translation id="4336434711095810371">Poista kaikki data</translation>
<translation id="4402755511846832236">Estä sivustoja tietämästä, kun käytät tätä laitetta aktiivisesti</translation>
+<translation id="4428065317363009941">Mainosten personointi</translation>
<translation id="4434045419905280838">Ponn.ikkunat ja uudelleenohjaus</translation>
<translation id="445467742685312942">Salli sivustojen toistaa suojattua sisältöä</translation>
<translation id="4468959413250150279">Mykistä tietyn sivuston äänet.</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">Toiminto on käytettävissä näytön yläosassa</translation>
<translation id="5197729504361054390"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> saa valitsemasi yhteystiedot.</translation>
<translation id="5216942107514965959">Viimeksi avattu tänään</translation>
+<translation id="5264323282659631142">Poista <ph name="CHIP_LABEL" /></translation>
<translation id="528192093759286357">Poistu koko näytön tilasta vetämällä näytön yläreunasta ja koskettamalla Takaisin-painiketta.</translation>
<translation id="5300589172476337783">Näytä</translation>
<translation id="5301954838959518834">Selvä</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">Tämä tyhjentää <ph name="DATASIZE" /> dataa ja sivustojen tallentamat evästeet.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(+ 1 muu)}other{(+ # muuta)}}</translation>
<translation id="5403592356182871684">Nimet</translation>
+<translation id="5412236728747081950">Tämä sivusto saa kiinnostuksen kohteesi Chromesta, jotta voit nähdä osuvampia mainoksia</translation>
<translation id="5438097262470833822">Valinta nollaa luvat osoitteessa <ph name="WEBSITE" /></translation>
<translation id="5489227211564503167">Kulunut aika: <ph name="ELAPSED_TIME" />/<ph name="TOTAL_TIME" /></translation>
<translation id="5494752089476963479">Estä häiritseviä tai harhaanjohtavia mainoksia näyttävien sivustojen mainokset</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">Lataa uudelleen</translation>
<translation id="5596627076506792578">Lisäasetukset</translation>
<translation id="5649053991847567735">Automaattiset lataukset</translation>
+<translation id="5668404140385795438">Ohita sivuston zoomauksen estämispyyntö</translation>
<translation id="5677928146339483299">Estetty</translation>
<translation id="5689516760719285838">Sijainti</translation>
<translation id="5690795753582697420">Kamera laitettiin pois päältä Androidin asetuksista</translation>
-<translation id="5710871682236653961">Kysy, saavatko sivustot lähettää ja vastaanottaa tietoja, kun kosketat NFC-laitteita (suositus)</translation>
<translation id="5719847187258001597">Tämä tyhjentää kaiken datan ja kaikki evästeet, jotka <ph name="ORIGIN" /> tai sen aloitusnäytölläsi oleva sovellus on tallentanut.</translation>
<translation id="5771720122942595109"><ph name="PERMISSION_1" /> estetty</translation>
<translation id="5804241973901381774">Luvat</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">Toista</translation>
<translation id="6818926723028410516">Valitse kohteet</translation>
<translation id="6864395892908308021">Tämä laite ei lue NFC-dataa</translation>
-<translation id="6910211073230771657">Poistettu</translation>
<translation id="6912998170423641340">Estä sivustoja lukemasta tekstiä ja kuvia leikepöydältä</translation>
<translation id="6945221475159498467">Valitse</translation>
<translation id="6965382102122355670">OK</translation>
+<translation id="6981982820502123353">Esteettömyys</translation>
<translation id="6992289844737586249">Pyydä lupaa, kun sivustot yrittävät käyttää mikrofonia (suositus).</translation>
<translation id="7000754031042624318">Poistettu käytöstä Android-asetuksissa</translation>
<translation id="7016516562562142042">Sallittu nykyisellä hakukoneella</translation>
+<translation id="702463548815491781">Suositellaan käytettäväksi, kun TalkBack tai Kytkimen käyttö on päällä</translation>
<translation id="7053983685419859001">Estä</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1 valittu}other{# valittu}}</translation>
-<translation id="7070090581017165256">Tietoja tästä sivustosta</translation>
<translation id="7087918508125750058"><ph name="ITEM_COUNT" /> valittu. Toimintoja on käytettävissä näytön yläosassa.</translation>
<translation id="7141896414559753902">Estä ponnahdusikkunoiden näyttäminen sivustoilla (suositus)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> kt</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">Sivusto käyttää mikrofoniasi</translation>
<translation id="7561196759112975576">Aina</translation>
-<translation id="7572498721684305250">Estä sivustoja lähettämästä ja vastaanottamasta tietoja, kun kosketat NFC-laitteita</translation>
<translation id="757524316907819857">Estä sivustoja toistamasta suojattua sisältöä</translation>
+<translation id="7577900504646297215">Ylläpidä kiinnostuksen kohteita</translation>
<translation id="7649070708921625228">Ohje</translation>
<translation id="7658239707568436148">Peru</translation>
<translation id="7781829728241885113">Eilen</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">Yhteys on turvallinen</translation>
<translation id="8249310407154411074">Siirrä ylimmäksi</translation>
<translation id="8261506727792406068">Poista</translation>
+<translation id="8284326494547611709">Tekstitykset</translation>
<translation id="8300705686683892304">Sovelluksen ylläpitämät</translation>
<translation id="8324158725704657629">Älä kysy uudestaan</translation>
<translation id="8372893542064058268">Salli taustasynkronointi tietyllä sivustolla.</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">Lähennä</translation>
<translation id="8921772741368021346"><ph name="POSITION" />/<ph name="DURATION" /></translation>
<translation id="8926666909099850184">NFC on pois päältä tällä laitteella. Voit laittaa sen päälle <ph name="BEGIN_LINK" />Androidin asetuksista<ph name="END_LINK" />.</translation>
+<translation id="8928445016601307354">Estä sivustoja näkemästä ja muuttamasta NFC-laitteiden tietoja</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">Estä evästeet tietyltä sivustolta.</translation>
<translation id="8959122750345127698">Kohde ei ole saatavilla: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_fil.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_fil.xtb
index 36b75b85ed1..93b43ce25d4 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_fil.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_fil.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">Nadagdag na ang site ng <ph name="SITE_NAME" /></translation>
<translation id="1383876407941801731">Hanapin</translation>
<translation id="1384959399684842514">Na-pause ang pag-download</translation>
+<translation id="1409426117486808224">Pinasimpleng view para sa mga bukas na tab</translation>
<translation id="1415402041810619267">Naputol ang URL</translation>
<translation id="1446450296470737166">Payagan ganap na kontrol sa MIDI device</translation>
<translation id="1620510694547887537">Camera</translation>
@@ -44,15 +45,18 @@
<translation id="2091887806945687916">Tunog</translation>
<translation id="2107397443965016585">Magtanong bago pahintulutan ang mga site na mag-play ng pinoprotektahang content (inirerekomenda)</translation>
<translation id="2146738493024040262">Buksan ang Instant App</translation>
-<translation id="2148716181193084225">Ngayon</translation>
+<translation id="2148716181193084225">Ngayong Araw</translation>
<translation id="2182457891543959921">Magtanong bago payagan ang mga site na gumawa ng 3D na mapa ng iyong kapaligiran o subaybayan ang posisyon ng camera (inirerekomenda)</translation>
<translation id="2212565012507486665">Payagan ang cookies</translation>
<translation id="2228071138934252756">Para payagan ang <ph name="APP_NAME" /> na i-access ang iyong camera, i-on din ang camera sa <ph name="BEGIN_LINK" />Mga Setting ng Android<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Isang beses lang</translation>
+<translation id="2253414712144136228"><ph name="NAME_OF_LIST_ITEM" /> Alisin</translation>
<translation id="2289270750774289114">Magtanong kapag gusto ng isang site na tumuklas ng mga Bluetooth device na nasa malapit (inirerekomenda)</translation>
<translation id="2315043854645842844">Hindi sinusuportahan ng operating system ang pagpipilian ng certificate sa panig ng kliyente.</translation>
+<translation id="2321958826496381788">I-drag ang slider hanggang sa mabasa mo ito nang kumportable. Dapat ay halos ganito kalaki ang text pagkatapos mag-double tap sa isang talata.</translation>
<translation id="2359808026110333948">Magpatuloy</translation>
<translation id="2379925928934107488">Ilapat ang madilim na tema sa mga site kapag ginagamit ng Chrome ang madilim na tema, kapag posible</translation>
+<translation id="2387895666653383613">Pag-scale ng text</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Pinapayagan ang <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, at <ph name="NUM_MORE" /> pa}one{Pinapayagan ang <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, at <ph name="NUM_MORE" /> pa}other{Pinapayagan ang <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, at <ph name="NUM_MORE" /> pa}}</translation>
<translation id="2434158240863470628">Tapos nang mag-download <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">Ipakita ang Impormasyon</translation>
<translation id="3123473560110926937">Naka-block sa ilang site</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> ang naka-store na data</translation>
+<translation id="3203366800380907218">Mula sa web</translation>
<translation id="321187648315454507">Para payagan ang <ph name="APP_NAME" /> na magpadala sa iyo ng mga notification, i-on din ang mga notification sa <ph name="BEGIN_LINK" />Mga Setting ng Android<ph name="END_LINK" />.</translation>
<translation id="3227137524299004712">Mikropono</translation>
<translation id="3277252321222022663">Payagan ang mga site na i-access ang mga sensor (inirerekomenda)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">Iyong paggamit ng device</translation>
<translation id="385051799172605136">Bumalik</translation>
<translation id="3859306556332390985">Maghanap nang pasulong</translation>
+<translation id="3895926599014793903">Puwersahang i-enable ang zoom</translation>
<translation id="3955193568934677022">Pahintulutan ang mga site na mag-play ng pinoprotektahang content (inirerekomenda)</translation>
<translation id="3967822245660637423">Tapos na ang pag-download</translation>
<translation id="3987993985790029246">Kopyahin ang link</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> / ?</translation>
<translation id="4002066346123236978">Pamagat</translation>
<translation id="4008040567710660924">Payagan ang cookies para sa isang partikular na site.</translation>
+<translation id="4040330681741629921">Maabisuhan kapag puwedeng ipakita ang site sa pinasimpleng view</translation>
<translation id="4046123991198612571">Susunod na track</translation>
+<translation id="4149994727733219643">Pinasimpleng view para sa mga web page</translation>
<translation id="4165986682804962316">Mga setting ng site</translation>
+<translation id="4194328954146351878">Magtanong bago payagan ang mga site na tingnan at baguhin ang impormasyon sa mga NFC device (inirerekomenda)</translation>
<translation id="4200726100658658164">Buksan ang Mga Setting ng Lokasyon</translation>
<translation id="4226663524361240545">Maaaring mag-vibrate ang device dahil sa mga notification</translation>
<translation id="4259722352634471385">Naka-block ang navigation: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">Palawakin</translation>
<translation id="4336434711095810371">I-clear ang lahat ng data</translation>
<translation id="4402755511846832236">Pigilan ang mga site na malaman kung kailan mo aktibong ginagamit ang device na ito</translation>
+<translation id="4428065317363009941">Pag-personalize ng ad</translation>
<translation id="4434045419905280838">Mga pop-up at pag-redirect</translation>
<translation id="445467742685312942">Pahintulutan ang mga site na mag-play ng pinoprotektahang content</translation>
<translation id="4468959413250150279">I-mute ang tunog para sa isang partikular na site.</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">Available ang opsyon malapit sa bandang itaas ng screen</translation>
<translation id="5197729504361054390">Ibabahagi sa <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ang mga contact na pipiliin mo.</translation>
<translation id="5216942107514965959">Huling binisita ngayong araw</translation>
+<translation id="5264323282659631142">Alisin ang '<ph name="CHIP_LABEL" />'</translation>
<translation id="528192093759286357">I-drag mula sa itaas at pindutin ang button na bumalik upang lumabas sa full screen.</translation>
<translation id="5300589172476337783">Ipakita</translation>
<translation id="5301954838959518834">OK, nakuha ko</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">Iki-clear nito ang <ph name="DATASIZE" /> ng data at cookies na na-store ng mga site.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(+ 1 pa)}one{(+ # pa)}other{(+ # pa)}}</translation>
<translation id="5403592356182871684">Mga Pangalan</translation>
+<translation id="5412236728747081950">Kinukuha ng site na ito ang iyong mga interes mula sa Chrome para makapagpakita sa iyo ng higit pang nauugnay na ad</translation>
<translation id="5438097262470833822">Ire-reset ng opsyong ito ang mga pahintulot para sa <ph name="WEBSITE" /></translation>
<translation id="5489227211564503167"><ph name="ELAPSED_TIME" /> ang lumipas mula sa <ph name="TOTAL_TIME" />.</translation>
<translation id="5494752089476963479">I-block ang mga ad sa mga site na nagpapakita ng mga nakakasagabal o nakakapanlinlang na ad</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">I-reload</translation>
<translation id="5596627076506792578">Higit pang opsyon</translation>
<translation id="5649053991847567735">Mga awtomatikong pag-download</translation>
+<translation id="5668404140385795438">I-override ang kahilingan ng isang website upang mapigilan ang pagzu-zoom in</translation>
<translation id="5677928146339483299">Naka-block</translation>
<translation id="5689516760719285838">Lokasyon</translation>
<translation id="5690795753582697420">Naka-off ang camera sa mga setting ng Android</translation>
-<translation id="5710871682236653961">Magtanong bago pahintulutan ang mga site na magpadala at tumanggap ng impormasyon kapag na-tap mo ang mga NFC device (inirerekomenda)</translation>
<translation id="5719847187258001597">Iki-clear nito ang lahat ng data at cookies na na-store ng <ph name="ORIGIN" /> o ng app nito sa iyong Home screen.</translation>
<translation id="5771720122942595109">Naka-block ang <ph name="PERMISSION_1" /></translation>
<translation id="5804241973901381774">Mga Pahintulot</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">I-play</translation>
<translation id="6818926723028410516">Pumili ng mga item</translation>
<translation id="6864395892908308021">Hindi nababasa ng device na ito ang NFC</translation>
-<translation id="6910211073230771657">Na-delete</translation>
<translation id="6912998170423641340">I-block ang mga site sa pag-read ng text at mga larawan mula sa clipboard</translation>
<translation id="6945221475159498467">Pumili</translation>
<translation id="6965382102122355670">OK</translation>
+<translation id="6981982820502123353">Accessibility</translation>
<translation id="6992289844737586249">Magtanong muna bago payagan ang mga site na gamitin ang iyong mikropono (inirerekomenda)</translation>
<translation id="7000754031042624318">Naka-off sa mga setting ng Android</translation>
<translation id="7016516562562142042">Pinapayagan para sa kasalukuyang search engine</translation>
+<translation id="702463548815491781">Inirerekomenda kapag naka-on ang TalkBack o Switch Access</translation>
<translation id="7053983685419859001">I-block</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1 ang napili}one{# ang napili}other{# ang napili}}</translation>
-<translation id="7070090581017165256">Tungkol sa site na ito</translation>
<translation id="7087918508125750058"><ph name="ITEM_COUNT" /> ang napili. Available ang mga opsyon malapit sa itaas ng screen</translation>
<translation id="7141896414559753902">I-block ang pagpapakita ng mga site ng mga pop-up at pag-redirect (inirerekomenda)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> KB</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">Gingamit ng isang site ang iyong mikropono</translation>
<translation id="7561196759112975576">Palagi</translation>
-<translation id="7572498721684305250">I-block ang mga site sa pagpapadala at pagtanggap ng impormasyon kapag na-tap mo ang mga NFC device</translation>
<translation id="757524316907819857">I-block ang mga site sa pag-play ng pinoprotektahang content</translation>
+<translation id="7577900504646297215">Pamahalaan ang mga interes</translation>
<translation id="7649070708921625228">Tulong</translation>
<translation id="7658239707568436148">Kanselahin</translation>
<translation id="7781829728241885113">Kahapon</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">Secure ang koneksyon</translation>
<translation id="8249310407154411074">Ilipat sa itaas</translation>
<translation id="8261506727792406068">I-delete</translation>
+<translation id="8284326494547611709">Mga Caption</translation>
<translation id="8300705686683892304">Pinapamahalaan ng app</translation>
<translation id="8324158725704657629">Huwag nang itanong ulit</translation>
<translation id="8372893542064058268">Payagan ang Pag-sync sa Background para sa isang partikular na site.</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">Mag-zoom in</translation>
<translation id="8921772741368021346"><ph name="POSITION" /> / <ph name="DURATION" /></translation>
<translation id="8926666909099850184">Naka-off ang NFC para sa device na ito. I-on ito sa <ph name="BEGIN_LINK" />Mga Setting ng Android<ph name="END_LINK" />.</translation>
+<translation id="8928445016601307354">I-block ang mga site sa pagtingin at pagbago ng impormasyon sa mga NFC device</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">Mag-block ng cookies para sa isang partikular na site.</translation>
<translation id="8959122750345127698">Hindi gumagana ang navigation: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_fr-CA.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_fr-CA.xtb
index 07b66f9487d..e07cc9a2262 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_fr-CA.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_fr-CA.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">Le site <ph name="SITE_NAME" /> a été ajouté</translation>
<translation id="1383876407941801731">Rechercher</translation>
<translation id="1384959399684842514">Téléchargement interrompu</translation>
+<translation id="1409426117486808224">Affichage simplifié pour les onglets ouverts</translation>
<translation id="1415402041810619267">URL tronquée</translation>
<translation id="1446450296470737166">Autoriser le contrôle des appareils MIDI</translation>
<translation id="1620510694547887537">Caméra</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">Autoriser les témoins</translation>
<translation id="2228071138934252756">Pour autoriser <ph name="APP_NAME" /> à accéder à votre appareil photo, activez aussi celui-ci dans les <ph name="BEGIN_LINK" />paramètres d'Android<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Une fois</translation>
+<translation id="2253414712144136228">Retirer l'élément suivant : <ph name="NAME_OF_LIST_ITEM" /></translation>
<translation id="2289270750774289114">Demander quand un site souhaite rechercher les appareils Bluetooth à proximité (recommandé)</translation>
<translation id="2315043854645842844">La sélection du certificat client SSL n'est pas prise en charge par le système d'exploitation.</translation>
+<translation id="2321958826496381788">Faites glisser le curseur pour lire le texte aisément. Sa taille doit être similaire à celle-ci lorsque vous appuyez deux fois sur un paragraphe.</translation>
<translation id="2359808026110333948">Continuer</translation>
<translation id="2379925928934107488">Si possible, appliquer le thème sombre aux sites lorsque Chrome l'utilise</translation>
+<translation id="2387895666653383613">Mise à l'échelle texte</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> Mo</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Autorisations <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> et <ph name="NUM_MORE" /> autre accordées}one{Autorisations <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> et <ph name="NUM_MORE" /> autre accordées}other{Autorisations <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> et <ph name="NUM_MORE" /> autres accordées}}</translation>
<translation id="2434158240863470628">Téléchargement terminé <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">Afficher les renseignements</translation>
<translation id="3123473560110926937">Annonces bloquées sur certains sites</translation>
<translation id="3198916472715691905">Stockage de données : <ph name="STORAGE_AMOUNT" /></translation>
+<translation id="3203366800380907218">Du Web</translation>
<translation id="321187648315454507">Pour autoriser <ph name="APP_NAME" /> à vous envoyer des notifications, vous devez aussi activer celles-ci dans les <ph name="BEGIN_LINK" />paramètres d'Android<ph name="END_LINK" />.</translation>
<translation id="3227137524299004712">Microphone</translation>
<translation id="3277252321222022663">Autoriser les sites à accéder aux capteurs (recommandé)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">Votre utilisation de l'appareil</translation>
<translation id="385051799172605136">Retour</translation>
<translation id="3859306556332390985">Rechercher vers l'avant</translation>
+<translation id="3895926599014793903">Forcer l'activation du zoom</translation>
<translation id="3955193568934677022">Autoriser les sites à lire le contenu protégé (recommandé)</translation>
<translation id="3967822245660637423">Téléchargement terminé</translation>
<translation id="3987993985790029246">Copier lien</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" />/?</translation>
<translation id="4002066346123236978">Titre</translation>
<translation id="4008040567710660924">Autoriser les témoins pour un site en particulier.</translation>
+<translation id="4040330681741629921">Recevez une notification lorsqu'un site prend en charge l'affichage simplifié</translation>
<translation id="4046123991198612571">Chanson suivante</translation>
+<translation id="4149994727733219643">Affichage simplifié pour les pages Web</translation>
<translation id="4165986682804962316">Paramètres du site</translation>
+<translation id="4194328954146351878">Demander l'autorisation avant de permettre aux sites de consulter et de modifier les données stockées sur les appareils CCP (recommandé)</translation>
<translation id="4200726100658658164">Ouvrir les paramètres de localisation</translation>
<translation id="4226663524361240545">Les notifications peuvent faire vibrer l'appareil</translation>
<translation id="4259722352634471385">Navigation bloquée : <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">Développer</translation>
<translation id="4336434711095810371">Effacer toutes les données</translation>
<translation id="4402755511846832236">Empêcher les sites de savoir quand vous êtes en train d'utiliser cet appareil</translation>
+<translation id="4428065317363009941">Personnalisation des annonces</translation>
<translation id="4434045419905280838">Fenêt. context. et redirections</translation>
<translation id="445467742685312942">Autoriser les sites à lire du contenu protégé</translation>
<translation id="4468959413250150279">Désactivez le son sur un site précis.</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">Option accessible près du haut de l'écran</translation>
<translation id="5197729504361054390">Les contacts que vous sélectionnez seront partagés avec <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />.</translation>
<translation id="5216942107514965959">Dernière visite : aujourd'hui</translation>
+<translation id="5264323282659631142">Retirer « <ph name="CHIP_LABEL" /> »</translation>
<translation id="528192093759286357">Faites glisser du haut vers le bas et appuyez sur le bouton de retour pour quitter le mode plein écran.</translation>
<translation id="5300589172476337783">Afficher</translation>
<translation id="5301954838959518834">J'ai compris.</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">Cette action effacera <ph name="DATASIZE" /> de données et de témoins qu'ont stockés des sites.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(+ 1 autre)}one{(+ # autre)}other{(+ # autres)}}</translation>
<translation id="5403592356182871684">Noms</translation>
+<translation id="5412236728747081950">Ce site récupère vos centres d'intérêt de Chrome pour vous montrer des annonces plus pertinentes</translation>
<translation id="5438097262470833822">Ce choix réinitialisera les autorisations du site <ph name="WEBSITE" /></translation>
<translation id="5489227211564503167">Temps écoulé : <ph name="ELAPSED_TIME" /> sur <ph name="TOTAL_TIME" /></translation>
<translation id="5494752089476963479">Bloquer les annonces sur les sites qui diffusent des annonces intrusives ou trompeuses</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">Actualiser</translation>
<translation id="5596627076506792578">Autres options</translation>
<translation id="5649053991847567735">Téléchargements automatiques</translation>
+<translation id="5668404140385795438">Ignorer la demande d'un site refusant de faire un zoom avant</translation>
<translation id="5677928146339483299">Bloqué</translation>
<translation id="5689516760719285838">Lieu</translation>
<translation id="5690795753582697420">L'appareil photo est désactivé dans les paramètres d'Android</translation>
-<translation id="5710871682236653961">Demander avant d'autoriser les sites à envoyer et à recevoir de l'information lorsque vous touchez des appareils CCP (recommandé)</translation>
<translation id="5719847187258001597">Cette action entraînera la suppression de l'ensemble des données et des témoins stockés par <ph name="ORIGIN" /> ou son application installée sur votre écran d'accueil.</translation>
<translation id="5771720122942595109">Autorisation <ph name="PERMISSION_1" /> bloquée</translation>
<translation id="5804241973901381774">Autorisations</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">Jouer</translation>
<translation id="6818926723028410516">Sélectionner des éléments</translation>
<translation id="6864395892908308021">Cet appareil ne prend pas en charge la technologie CCP</translation>
-<translation id="6910211073230771657">Supprimé</translation>
<translation id="6912998170423641340">Empêcher les sites de lire du texte et des images du presse-papiers</translation>
<translation id="6945221475159498467">Sélectionner</translation>
<translation id="6965382102122355670">OK</translation>
+<translation id="6981982820502123353">Accessibilité</translation>
<translation id="6992289844737586249">Demander avant d'autoriser des sites à utiliser votre microphone (recommandé)</translation>
<translation id="7000754031042624318">Désactivée dans les paramètres Android</translation>
<translation id="7016516562562142042">Autorisée pour le moteur de recherche actuel</translation>
+<translation id="702463548815491781">Recommandé lorsque le service TalkBack ou Switch Access est activé</translation>
<translation id="7053983685419859001">Bloquer</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1 élément sélectionné}one{# élément sélectionné}other{# éléments sélectionnés}}</translation>
-<translation id="7070090581017165256">À propos de ce site</translation>
<translation id="7087918508125750058"><ph name="ITEM_COUNT" /> élément(s) sélectionné(s). Options disponibles vers le haut de l'écran</translation>
<translation id="7141896414559753902">Bloquer l'affichage de fenêtres contextuelles et de redirections à partir des sites (recommandé)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> ko</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">Un site utilise votre microphone</translation>
<translation id="7561196759112975576">Toujours</translation>
-<translation id="7572498721684305250">Empêcher les sites d'envoyer et de recevoir de l'information lorsque vous touchez des appareils CCP</translation>
<translation id="757524316907819857">Empêcher les sites de lire du contenu protégé</translation>
+<translation id="7577900504646297215">Gérer les centres d'intérêt</translation>
<translation id="7649070708921625228">Aide</translation>
<translation id="7658239707568436148">Annuler</translation>
<translation id="7781829728241885113">Hier</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">Connexion sécurisée</translation>
<translation id="8249310407154411074">Placer en première position</translation>
<translation id="8261506727792406068">Supprimer</translation>
+<translation id="8284326494547611709">Sous-titres</translation>
<translation id="8300705686683892304">Gérés par une application</translation>
<translation id="8324158725704657629">Ne plus me demander</translation>
<translation id="8372893542064058268">Autorisez la synchronisation en arrière-plan pour un site en particulier.</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">Zoom avant</translation>
<translation id="8921772741368021346"><ph name="POSITION" /> sur <ph name="DURATION" /></translation>
<translation id="8926666909099850184">La CCP est désactivée pour cet appareil. Activez-la dans le menu <ph name="BEGIN_LINK" />Paramètres Android<ph name="END_LINK" />.</translation>
+<translation id="8928445016601307354">Empêcher les sites de consulter et de modifier les données stockées sur les appareils CCP</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">Bloquer les témoins pour un site en particulier.</translation>
<translation id="8959122750345127698">Navigation inaccessible : <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_fr.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_fr.xtb
index 2271c422e1b..02e2bf61d12 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_fr.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_fr.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">Site "<ph name="SITE_NAME" />" ajouté</translation>
<translation id="1383876407941801731">Rechercher</translation>
<translation id="1384959399684842514">Téléchargement suspendu</translation>
+<translation id="1409426117486808224">Vue simplifiée pour les onglets ouverts</translation>
<translation id="1415402041810619267">URL tronquée</translation>
<translation id="1446450296470737166">Autoriser le contrôle complet des appareils MIDI</translation>
<translation id="1620510694547887537">Caméra</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">Autoriser les cookies</translation>
<translation id="2228071138934252756">Pour autoriser <ph name="APP_NAME" /> à accéder à votre caméra, activez-la également dans les <ph name="BEGIN_LINK" />paramètres Android<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Une seule fois</translation>
+<translation id="2253414712144136228">Supprimer <ph name="NAME_OF_LIST_ITEM" /></translation>
<translation id="2289270750774289114">Me demander lorsqu'un site souhaite accéder aux appareils Bluetooth se trouvant à proximité (recommandé)</translation>
<translation id="2315043854645842844">La sélection de certificat côté client n'est pas compatible avec le système d'exploitation.</translation>
+<translation id="2321958826496381788">Faites glisser le curseur pour lire le texte aisément. Sa taille doit être similaire à celle-ci lorsque vous appuyez deux fois sur un paragraphe.</translation>
<translation id="2359808026110333948">Continuer</translation>
<translation id="2379925928934107488">Si le thème sombre est activé dans Chrome, il sera appliqué aux sites, si possible</translation>
+<translation id="2387895666653383613">Mise à l'échelle du texte</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> Mo</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Autorisations accordées : <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> et <ph name="NUM_MORE" /> de plus}one{Autorisations accordées : <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> et <ph name="NUM_MORE" /> de plus}other{Autorisations accordées : <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> et <ph name="NUM_MORE" /> de plus}}</translation>
<translation id="2434158240863470628">Téléchargement terminé <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">Afficher les informations</translation>
<translation id="3123473560110926937">Bloqué sur certains sites</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> de données stockées</translation>
+<translation id="3203366800380907218">Sur le Web</translation>
<translation id="321187648315454507">Pour autoriser <ph name="APP_NAME" /> à vous envoyer des notifications, activez également celles-ci dans les <ph name="BEGIN_LINK" />paramètres Android<ph name="END_LINK" />.</translation>
<translation id="3227137524299004712">Micro</translation>
<translation id="3277252321222022663">Autoriser les sites à accéder à vos capteurs (recommandé)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">Savoir si vous utilisez l'appareil</translation>
<translation id="385051799172605136">Retour</translation>
<translation id="3859306556332390985">Avance rapide</translation>
+<translation id="3895926599014793903">Forcer l'activation du zoom</translation>
<translation id="3955193568934677022">Autoriser les sites à lire les contenus protégés (recommandé)</translation>
<translation id="3967822245660637423">Téléchargement terminé</translation>
<translation id="3987993985790029246">Copier lien</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" />/ ?</translation>
<translation id="4002066346123236978">Titre</translation>
<translation id="4008040567710660924">Autorisez les cookies pour un site spécifique.</translation>
+<translation id="4040330681741629921">M'avertir lorsqu'un site peut s'afficher en vue simplifiée</translation>
<translation id="4046123991198612571">Piste suivante</translation>
+<translation id="4149994727733219643">Vue simplifiée pour les pages Web</translation>
<translation id="4165986682804962316">Paramètres de site</translation>
+<translation id="4194328954146351878">Vous demander avant d'autoriser les sites à consulter et modifier des informations sur des appareils NFC (recommandé)</translation>
<translation id="4200726100658658164">Accéder aux paramètres de localisation</translation>
<translation id="4226663524361240545">L'appareil vibrera en cas de notifications.</translation>
<translation id="4259722352634471385">La navigation sur <ph name="URL" /> est bloquée.</translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">Développer</translation>
<translation id="4336434711095810371">Effacer toutes les données</translation>
<translation id="4402755511846832236">Empêcher les sites de savoir si vous utilisez activement cet appareil</translation>
+<translation id="4428065317363009941">Personnalisation des annonces</translation>
<translation id="4434045419905280838">Pop-up et redirections</translation>
<translation id="445467742685312942">Autoriser les sites à lire les contenus protégés</translation>
<translation id="4468959413250150279">Coupez le son d'un site spécifique.</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">Cette option est disponible en haut de l'écran</translation>
<translation id="5197729504361054390">Les contacts que vous sélectionnez seront partagés avec <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />.</translation>
<translation id="5216942107514965959">Dernière visite : aujourd'hui</translation>
+<translation id="5264323282659631142">Supprimer "<ph name="CHIP_LABEL" />"</translation>
<translation id="528192093759286357">Pour quitter le mode plein écran, faites glisser un doigt du haut vers le bas, puis appuyez sur le bouton Retour.</translation>
<translation id="5300589172476337783">Afficher</translation>
<translation id="5301954838959518834">OK</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">Cette action entraînera la suppression de <ph name="DATASIZE" /> de données et de cookies stockés par les sites.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(+ 1 autre)}one{(+ # autre)}other{(+ # autres)}}</translation>
<translation id="5403592356182871684">Noms</translation>
+<translation id="5412236728747081950">Ce site obtient vos centres d'intérêt via Chrome pour afficher des annonces plus pertinentes</translation>
<translation id="5438097262470833822">Cette action réinitialisera les autorisations de <ph name="WEBSITE" /></translation>
<translation id="5489227211564503167">Temps écoulé : <ph name="ELAPSED_TIME" /> sur <ph name="TOTAL_TIME" />.</translation>
<translation id="5494752089476963479">Bloquer les annonces sur les sites qui affichent des annonces intrusives ou trompeuses</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">Actualiser</translation>
<translation id="5596627076506792578">Plus d'options</translation>
<translation id="5649053991847567735">Téléchargements automatiques</translation>
+<translation id="5668404140385795438">Ignore la demande d'un site d'empêcher les zooms avant</translation>
<translation id="5677928146339483299">Bloqué</translation>
<translation id="5689516760719285838">Position</translation>
<translation id="5690795753582697420">L'appareil photo est désactivé dans les paramètres Android</translation>
-<translation id="5710871682236653961">Demander avant d'autoriser les sites à envoyer et recevoir des informations lorsque vous utilisez des appareils NFC (recommandé)</translation>
<translation id="5719847187258001597">Cette action entraînera la suppression de l'ensemble des données et cookies stockés par <ph name="ORIGIN" /> ou son application installée sur votre écran d'accueil.</translation>
<translation id="5771720122942595109">Autorisation refusée : <ph name="PERMISSION_1" /></translation>
<translation id="5804241973901381774">Autorisations</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">Lire</translation>
<translation id="6818926723028410516">Sélectionner des éléments</translation>
<translation id="6864395892908308021">Lecture NFC impossible sur cet appareil</translation>
-<translation id="6910211073230771657">Supprimé</translation>
<translation id="6912998170423641340">Interdire aux sites d'accéder en lecture au texte et aux images du presse-papiers</translation>
<translation id="6945221475159498467">Sélectionner</translation>
<translation id="6965382102122355670">OK</translation>
+<translation id="6981982820502123353">Accessibilité</translation>
<translation id="6992289844737586249">Demander avant d'autoriser des sites à utiliser mon micro (recommandé)</translation>
<translation id="7000754031042624318">Désactivée dans les paramètres Android</translation>
<translation id="7016516562562142042">Autorisé pour le moteur de recherche actuel</translation>
+<translation id="702463548815491781">Recommandé quand TalkBack ou Switch Access sont activés</translation>
<translation id="7053983685419859001">Bloquer</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1 élément sélectionné}one{# élément sélectionné}other{# éléments sélectionnés}}</translation>
-<translation id="7070090581017165256">À propos de ce site</translation>
<translation id="7087918508125750058">Nombre d'éléments sélectionnés : <ph name="ITEM_COUNT" />. Options disponibles dans la partie supérieure de l'écran</translation>
<translation id="7141896414559753902">Bloquer l'affichage de fenêtres pop-up et les redirections par les sites (recommandé)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> Ko</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">Un site utilise votre micro</translation>
<translation id="7561196759112975576">Toujours</translation>
-<translation id="7572498721684305250">Empêcher les sites d'envoyer et de recevoir des informations lorsque vous utilisez des appareils NFC</translation>
<translation id="757524316907819857">Empêcher les sites de lire les contenus protégés</translation>
+<translation id="7577900504646297215">Gérer les centres d'intérêt</translation>
<translation id="7649070708921625228">Aide</translation>
<translation id="7658239707568436148">Annuler</translation>
<translation id="7781829728241885113">Hier</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">La connexion est sécurisée</translation>
<translation id="8249310407154411074">Déplacer vers le haut</translation>
<translation id="8261506727792406068">Supprimer</translation>
+<translation id="8284326494547611709">Sous-titres</translation>
<translation id="8300705686683892304">Gérés par l'application</translation>
<translation id="8324158725704657629">Ne plus me demander</translation>
<translation id="8372893542064058268">Autorisez la synchronisation en arrière-plan pour un site spécifique.</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">Zoom avant</translation>
<translation id="8921772741368021346"><ph name="POSITION" />/<ph name="DURATION" /></translation>
<translation id="8926666909099850184">La fonctionnalité NFC est désactivée pour cet appareil. Activez-la dans les <ph name="BEGIN_LINK" />paramètres Android<ph name="END_LINK" />.</translation>
+<translation id="8928445016601307354">Empêcher les sites de consulter et de modifier des informations sur des appareils NFC</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">Bloquez les cookies pour un site spécifique.</translation>
<translation id="8959122750345127698">Impossible d'accéder à <ph name="URL" />.</translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_gl.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_gl.xtb
index 0cf38c687af..d7938697642 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_gl.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_gl.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">Engadiuse o sitio <ph name="SITE_NAME" /></translation>
<translation id="1383876407941801731">Buscar</translation>
<translation id="1384959399684842514">Pausouse a descarga</translation>
+<translation id="1409426117486808224">Vista simplificada de pestanas abertas</translation>
<translation id="1415402041810619267">URL truncado</translation>
<translation id="1446450296470737166">Permitir control disposit. MIDI</translation>
<translation id="1620510694547887537">Cámara</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">Permitir uso de cookies</translation>
<translation id="2228071138934252756">Para permitir que <ph name="APP_NAME" /> acceda á cámara, actívaa tamén en <ph name="BEGIN_LINK" />Configuración de Android<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Só unha vez</translation>
+<translation id="2253414712144136228">Eliminar <ph name="NAME_OF_LIST_ITEM" /></translation>
<translation id="2289270750774289114">Preguntar cando un sitio web queira detectar dispositivos Bluetooth próximos (recomendado)</translation>
<translation id="2315043854645842844">A selección do certificado do cliente non é compatible co sistema operativo.</translation>
+<translation id="2321958826496381788">Arrastra o control desprazable ata que poidas ler con comodidade. O texto debe ter polo menos este tamaño despois de facer dobre clic nun parágrafo.</translation>
<translation id="2359808026110333948">Continuar</translation>
<translation id="2379925928934107488">Aplícaselles o tema escuro aos sitios sempre que é posible cando Chrome está configurado con ese tema</translation>
+<translation id="2387895666653383613">Axuste de texto</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> e <ph name="NUM_MORE" /> máis (permitidos)}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> e <ph name="NUM_MORE" /> máis (permitidos)}}</translation>
<translation id="2434158240863470628">Completouse a descarga <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">Mostrar información</translation>
<translation id="3123473560110926937">Anuncios bloqueados nalgúns sitios</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> de datos almacenados</translation>
+<translation id="3203366800380907218">Da Web</translation>
<translation id="321187648315454507">Para permitir que <ph name="APP_NAME" /> che envíe notificacións, actívaas tamén en <ph name="BEGIN_LINK" />Configuración de Android<ph name="END_LINK" />.</translation>
<translation id="3227137524299004712">Micrófono</translation>
<translation id="3277252321222022663">Permitir que os sitios accedan aos sensores (recomendado)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">Uso do dispositivo</translation>
<translation id="385051799172605136">Atrás</translation>
<translation id="3859306556332390985">Buscar cara adiante</translation>
+<translation id="3895926599014793903">Forzar a activación do zoom</translation>
<translation id="3955193568934677022">Permitir que os sitios reproduzan contido protexido (recomendado)</translation>
<translation id="3967822245660637423">Descarga completa</translation>
<translation id="3987993985790029246">Copiar ligazón</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" />/?</translation>
<translation id="4002066346123236978">Título</translation>
<translation id="4008040567710660924">Permite cookies para un sitio específico.</translation>
+<translation id="4040330681741629921">Recibe notificacións cando se poida mostrar un sitio na vista simplificada</translation>
<translation id="4046123991198612571">Pista seguinte</translation>
+<translation id="4149994727733219643">Vista simplificada de páxinas web</translation>
<translation id="4165986682804962316">Configuración do sitio</translation>
+<translation id="4194328954146351878">Pregunta antes de permitir que os sitios consulten e cambien información en dispositivos con NFC (recomendado)</translation>
<translation id="4200726100658658164">Abrir Configuración de localización</translation>
<translation id="4226663524361240545">O dispositivo pode vibrar ao recibir notificacións</translation>
<translation id="4259722352634471385">A navegación está bloqueada: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">Ampliar</translation>
<translation id="4336434711095810371">Borrar todos os datos</translation>
<translation id="4402755511846832236">Impide que os sitios saiban se estás utilizando este dispositivo de maneira activa</translation>
+<translation id="4428065317363009941">Personalización de anuncios</translation>
<translation id="4434045419905280838">Ventás emerxentes e redireccións</translation>
<translation id="445467742685312942">Permitir que os sitios reproduzan contido protexido</translation>
<translation id="4468959413250150279">Silencia o son dun sitio específico.</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">Opción dispoñible preto da parte superior da pantalla</translation>
<translation id="5197729504361054390">Os contactos que selecciones compartiranse con <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />.</translation>
<translation id="5216942107514965959">Visitouse hoxe por última vez</translation>
+<translation id="5264323282659631142">Quitar <ph name="CHIP_LABEL" /></translation>
<translation id="528192093759286357">Arrastra desde a parte superior e toca o botón Volver para saír da pantalla completa.</translation>
<translation id="5300589172476337783">Mostrar</translation>
<translation id="5301954838959518834">Entendido</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">Ao realizar esta acción, borraranse os datos e as cookies (<ph name="DATASIZE" />) que almacenasen os sitios.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(e 1 máis)}other{(e # máis)}}</translation>
<translation id="5403592356182871684">Nomes</translation>
+<translation id="5412236728747081950">Este sitio obtén os teus intereses de Chrome para mostrarche anuncios máis relevantes</translation>
<translation id="5438097262470833822">Con esta opción restableceranse os permisos de <ph name="WEBSITE" /></translation>
<translation id="5489227211564503167">Tempo transcorrido: <ph name="ELAPSED_TIME" /> de <ph name="TOTAL_TIME" />.</translation>
<translation id="5494752089476963479">Bloquear anuncios en sitios que mostran anuncios enganosos ou intrusivos</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">Volver cargar</translation>
<translation id="5596627076506792578">Máis opcións</translation>
<translation id="5649053991847567735">Descargas automáticas</translation>
+<translation id="5668404140385795438">Anular a solicitude dun sitio web para evitar ampliar a imaxe</translation>
<translation id="5677928146339483299">Bloqueada</translation>
<translation id="5689516760719285838">Localización</translation>
<translation id="5690795753582697420">A cámara está desactivada na sección Configuración de Android</translation>
-<translation id="5710871682236653961">Pregunta antes de permitir que os sitios envíen e reciban información cando toques dispositivos con NFC (recomendado)</translation>
<translation id="5719847187258001597">Ao realizar esta acción, borraranse os datos e as cookies que almacenase <ph name="ORIGIN" /> ou a súa aplicación instalada na pantalla de inicio.</translation>
<translation id="5771720122942595109"><ph name="PERMISSION_1" /> (bloqueado)</translation>
<translation id="5804241973901381774">Permisos</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">Reproducir</translation>
<translation id="6818926723028410516">Selecciona elementos</translation>
<translation id="6864395892908308021">Este dispositivo non pode ler NFC</translation>
-<translation id="6910211073230771657">Eliminado</translation>
<translation id="6912998170423641340">Impedir que os sitios lean texto e imaxes do portapapeis</translation>
<translation id="6945221475159498467">Seleccionar</translation>
<translation id="6965382102122355670">Aceptar</translation>
+<translation id="6981982820502123353">Accesibilidade</translation>
<translation id="6992289844737586249">Pregunta antes de permitir que os sitios utilicen o teu micrófono (recomendado)</translation>
<translation id="7000754031042624318">Desactivouse na configuración de Android</translation>
<translation id="7016516562562142042">Permitido para o motor de busca actual</translation>
+<translation id="702463548815491781">Recoméndase cando están activadas as funcións TalkBack ou Acceso con interruptores</translation>
<translation id="7053983685419859001">Bloquear</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1 elemento seleccionado}other{# elementos seleccionados}}</translation>
-<translation id="7070090581017165256">Acerca deste sitio</translation>
<translation id="7087918508125750058">Elementos seleccionados: <ph name="ITEM_COUNT" />. Hai opcións dispoñibles na parte superior da pantalla</translation>
<translation id="7141896414559753902">Non permite que os sitios mostren ventás emerxentes nin redireccións (recomendado)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> kB</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">Un sitio está utilizando o micrófono</translation>
<translation id="7561196759112975576">Sempre</translation>
-<translation id="7572498721684305250">Bloquea o envío e a recepción de información dos sitios cando toques dispositivos con NFC</translation>
<translation id="757524316907819857">Non permite que os sitios reproduzan o contido protexido</translation>
+<translation id="7577900504646297215">Xestionar intereses</translation>
<translation id="7649070708921625228">Axuda</translation>
<translation id="7658239707568436148">Cancelar</translation>
<translation id="7781829728241885113">Onte</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">A conexión é segura</translation>
<translation id="8249310407154411074">Mover á parte superior</translation>
<translation id="8261506727792406068">Eliminar</translation>
+<translation id="8284326494547611709">Subtítulos</translation>
<translation id="8300705686683892304">Sitios xestionados pola aplicación</translation>
<translation id="8324158725704657629">Non preguntar de novo</translation>
<translation id="8372893542064058268">Permite a sincronización en segundo plano nun sitio específico.</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">Achegar</translation>
<translation id="8921772741368021346"><ph name="POSITION" />/<ph name="DURATION" /></translation>
<translation id="8926666909099850184">A NFC está desactivada para este dispositivo. Actívaa en <ph name="BEGIN_LINK" />Configuración de Android<ph name="END_LINK" />.</translation>
+<translation id="8928445016601307354">Impide que os sitios consulten e cambien información en dispositivos con NFC</translation>
<translation id="8941729603749328384">www.exemplo.com</translation>
<translation id="8958424370300090006">Bloquea cookies para un sitio específico.</translation>
<translation id="8959122750345127698">A navegación é inaccesible: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_gu.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_gu.xtb
index e569ab09854..0f23a5fcdfc 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_gu.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_gu.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">સાઈટ <ph name="SITE_NAME" /> ઉમેરવામાં આવી</translation>
<translation id="1383876407941801731">શોધો</translation>
<translation id="1384959399684842514">ડાઉનલોડ થોભાવà«àª¯à«àª‚</translation>
+<translation id="1409426117486808224">ખà«àª²à«àª²à«€ ટૅબ માટે સરળ દૃશà«àª¯</translation>
<translation id="1415402041810619267">URL ટૂંકી કરી છે</translation>
<translation id="1446450296470737166">MIDI ઉપકરણોના પૂરà«àª£ નિયંતà«àª°àª£àª¨à«€ મંજૂરી આપો</translation>
<translation id="1620510694547887537">કૅમેરા</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">કà«àª•à«€àª¨à«‡ મંજૂરી આપો</translation>
<translation id="2228071138934252756"><ph name="APP_NAME" /> તમારો કૅમેરા àªàª•à«àª¸à«‡àª¸ કરી શકે તે માટે <ph name="BEGIN_LINK" />Android સેટિંગ<ph name="END_LINK" />માં પણ કૅમેરા ચાલૠકરો.</translation>
<translation id="2241634353105152135">માતà«àª° àªàª• વખત</translation>
+<translation id="2253414712144136228"><ph name="NAME_OF_LIST_ITEM" /> કાઢી નાખો</translation>
<translation id="2289270750774289114">જà«àª¯àª¾àª°à«‡ કોઈ સાઇટ નજીકના બà«àª²à«‚ટૂથ ડિવાઇસને શોધવા માગે તà«àª¯àª¾àª°à«‡ પૂછો (સà«àªàª¾àªµ આપેલ)</translation>
<translation id="2315043854645842844">ઓપરેટિંગ સિસà«àªŸàª® દà«àªµàª¾àª°àª¾ કà«àª²àª¾àª‡àª¨à«àªŸ તરફની પà«àª°àª®àª¾àª£àªªàª¤à«àª° પસંદગી સપોરà«àªŸ કરતી નથી.</translation>
+<translation id="2321958826496381788">જà«àª¯àª¾àª‚ સà«àª§à«€ તમે આ અનà«àª•à«‚ળ રીતે વાંચી ન શકો તà«àª¯àª¾àª‚ સà«àª§à«€ સà«àª²àª¾àª‡àª¡àª° ખેંચો. ફકરા પર ડબલ-ટેપિંગ પછી ટેકà«àª¸à«àªŸ ઓછામાં ઓછી આટલી મોટી દેખાવી જોઈàª.</translation>
<translation id="2359808026110333948">આગળ વધો</translation>
<translation id="2379925928934107488">શકà«àª¯ હોય તà«àª¯àª¾àª°à«‡, Chrome જà«àª¯àª¾àª°à«‡ ઘેરી થીમનો ઉપયોગ કરે, તà«àª¯àª¾àª°à«‡ સાઇટ પર ઘેરી થીમ લાગૠકરો</translation>
+<translation id="2387895666653383613">ટેકà«àª¸à«àªŸ માપન</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> અને વધૠ<ph name="NUM_MORE" />ની મંજૂરી આપી}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> અને વધૠ<ph name="NUM_MORE" />ની મંજૂરી આપી}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> અને વધૠ<ph name="NUM_MORE" />ની મંજૂરી આપી}}</translation>
<translation id="2434158240863470628">ડાઉનલોડ પૂરà«àª£ <ph name="SEPARATOR" /><ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">માહિતી બતાવો</translation>
<translation id="3123473560110926937">કેટલીક સાઇટ પર બà«àª²à«‰àª• થયેલà«àª‚ છે</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> સંગà«àª°àª¹àª¿àª¤ ડેટા</translation>
+<translation id="3203366800380907218">વેબ પરથી</translation>
<translation id="321187648315454507"><ph name="APP_NAME" /> તમને નોટિફિકેશન મોકલી શકે તે માટે <ph name="BEGIN_LINK" />Android સેટિંગ<ph name="END_LINK" />માં પણ નોટિફિકેશન ચાલૠકરો.</translation>
<translation id="3227137524299004712">માઇકà«àª°à«‹àª«à«‹àª¨</translation>
<translation id="3277252321222022663">સાઇટને સેનà«àª¸àª°àª¨àª¾ àªàª•à«àª¸à«‡àª¸àª¨à«€ મંજૂરી આપો (સà«àªàª¾àªµ આપેલો છે)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">તમારા ડિવાઇસનો વપરાશ</translation>
<translation id="385051799172605136">પાછળ</translation>
<translation id="3859306556332390985">આગળ કરો</translation>
+<translation id="3895926599014793903">ફરજિયાતપૂરà«àªµàª• àªà«‚મ ચાલૠકરો</translation>
<translation id="3955193568934677022">સાઇટને સંરકà«àª·àª¿àª¤ કનà«àªŸà«‡àª¨à«àªŸ ચલાવવાની મંજૂરી આપો (સà«àªàª¾àªµ આપીઠછીàª)</translation>
<translation id="3967822245660637423">ડાઉનલોડ પૂરà«àª£</translation>
<translation id="3987993985790029246">લિંક કૉપિ કરો</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> / ?</translation>
<translation id="4002066346123236978">શીરà«àª·àª•</translation>
<translation id="4008040567710660924">કોઈ ચોકà«àª•àª¸ સાઇટ માટે કà«àª•à«€àª¨à«‡ મંજૂરી આપો.</translation>
+<translation id="4040330681741629921">જà«àª¯àª¾àª°à«‡ સાઇટને સરળ બનાવેલા વà«àª¯à«‚માં બતાવી શકાતી હોય તà«àª¯àª¾àª°à«‡ નોટિફિકેશન મેળવો</translation>
<translation id="4046123991198612571">આગલો ટà«àª°à«…ક</translation>
+<translation id="4149994727733219643">વેબપેજ માટે સરળ દૃશà«àª¯</translation>
<translation id="4165986682804962316">સાઇટ સેટિંગ</translation>
+<translation id="4194328954146351878">NFC ડિવાઇસ પર સાઇટને માહિતી જોવાની અને બદલવાની મંજૂરી આપતા પહેલાં પૂછો (ભલામણ કરવામાં આવે છે)</translation>
<translation id="4200726100658658164">સà«àª¥àª¾àª¨ સેટિંગ ખોલો</translation>
<translation id="4226663524361240545">સૂચનાઓ ઉપકરણને વાઇબà«àª°à«‡àªŸ કરી શકે છે</translation>
<translation id="4259722352634471385">નેવિગેશન અવરોધિત છે: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">વિસà«àª¤à«ƒàª¤ કરો</translation>
<translation id="4336434711095810371">બધો ડેટા સાફ કરો</translation>
<translation id="4402755511846832236">તમે સકà«àª°àª¿àª¯ રીતે આ ડિવાઇસનો ઉપયોગ કà«àª¯àª¾àª°à«‡ કરો છો, તેની જાણ ન થાય ઠમાટે સાઇટ બà«àª²à«‰àª• કરો</translation>
+<translation id="4428065317363009941">રà«àªšàª¿ મà«àªœàª¬ જાહેરાત</translation>
<translation id="4434045419905280838">પૉપ-અપ અને રીડાયરેકà«àªŸ</translation>
<translation id="445467742685312942">સાઇટને સંરકà«àª·àª¿àª¤ કનà«àªŸà«‡àª¨à«àªŸ ચલાવવાની મંજૂરી આપો</translation>
<translation id="4468959413250150279">કોઈ àªàª• ચોકà«àª•àª¸ સાઇટ માટે અવાજ બંધ કરો.</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">સà«àª•à«àª°à«€àª¨àª¨à«€ ટોચની નજીક વિકલà«àªª ઉપલબà«àª§ છે</translation>
<translation id="5197729504361054390">તમે પસંદ કરશો તે સંપરà«àª•à«‹àª¨à«‡ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> સાથે શેર કરવામાં આવશે.</translation>
<translation id="5216942107514965959">છેલà«àª²à«‡ આજે મà«àª²àª¾àª•àª¾àª¤ લીધી</translation>
+<translation id="5264323282659631142">'<ph name="CHIP_LABEL" />'ને કાઢી નાખો</translation>
<translation id="528192093759286357">પૂરà«àª£àª¸à«àª•à«àª°à«€àª¨àª¥à«€ બહાર નીકળવા માટે ઉપરથી ખેંચો અને પાછળ બટનને ટચ કરો.</translation>
<translation id="5300589172476337783">બતાવો</translation>
<translation id="5301954838959518834">બરાબર, સમજાઇ ગયà«àª‚</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">આમ કરવાથી સાઇટ દà«àªµàª¾àª°àª¾ સà«àªŸà«‹àª° કરવામાં આવેલા <ph name="DATASIZE" /> જેટલો ડેટા અને કà«àª•à«€ સાફ થશે.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(+ વધૠ1)}one{(+ વધૠ#)}other{(+ વધૠ#)}}</translation>
<translation id="5403592356182871684">નામ</translation>
+<translation id="5412236728747081950">તમને વધૠસંબંધિત હોય તેવી જાહેરાતો બતાવી શકાય તે માટે આ સાઇટ Chromeમાંથી તમારી રà«àªšàª¿àª“ મેળવે છે</translation>
<translation id="5438097262470833822">આ પસંદગી <ph name="WEBSITE" /> માટેની પરવાનગીઓને રીસેટ કરશે</translation>
<translation id="5489227211564503167"><ph name="TOTAL_TIME" />માંથી <ph name="ELAPSED_TIME" />નો સમય વીતી ગયો.</translation>
<translation id="5494752089476963479">ઘૃણાસà«àªªàª¦ અથવા ભà«àª°àª¾àª®àª• જાહેરાતો બતાવતી સાઇટ પરથી જાહેરાતો બà«àª²à«‰àª• કરો</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">ફરીથી લોડ કરો</translation>
<translation id="5596627076506792578">વધૠવિકલà«àªªà«‹</translation>
<translation id="5649053991847567735">ઑટોમૅટિક રીતે ડાઉનલોડ</translation>
+<translation id="5668404140385795438">àªà«‚મ વધારવાનà«àª‚ અટકાવવા માટે વેબસાઇટની વિનંતી ઑવરરાઇડ કરો</translation>
<translation id="5677928146339483299">બà«àª²à«‰àª• કરેલ</translation>
<translation id="5689516760719285838">સà«àª¥àª¾àª¨</translation>
<translation id="5690795753582697420">Android સેટિંગમાંથી કૅમેરા બંધ કરવામાં આવà«àª¯à«‹ છે</translation>
-<translation id="5710871682236653961">જà«àª¯àª¾àª°à«‡ તમે NFC ડિવાઇસ પર ટૅપ કરો તà«àª¯àª¾àª°à«‡ સાઇટને માહિતી મોકલવા અને પà«àª°àª¾àªªà«àª¤ કરવાની મંજૂરી આપતા પહેલાં પૂછો (સà«àªàª¾àªµ આપેલો છે)</translation>
<translation id="5719847187258001597">આમ કરવાથી તમારી હોમ સà«àª•à«àª°à«€àª¨ પર <ph name="ORIGIN" /> અથવા તેની àªàªª દà«àªµàª¾àª°àª¾ સà«àªŸà«‹àª° કરવામાં આવેલો બધો ડેટા અને કૂકી સાફ કરવામાં આવશે.</translation>
<translation id="5771720122942595109"><ph name="PERMISSION_1" /> બà«àª²à«‰àª• કરી</translation>
<translation id="5804241973901381774">પરવાનગીઓ</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">ચલાવો</translation>
<translation id="6818926723028410516">આઇટમ પસંદ કરો</translation>
<translation id="6864395892908308021">આ ડિવાઇસ NFC વાંચી શકતà«àª‚ નથી</translation>
-<translation id="6910211073230771657">કાઢી નાખà«àª¯à«àª‚</translation>
<translation id="6912998170423641340">બધી સાઇટને કà«àª²àª¿àªªàª¬à«‹àª°à«àª¡ પરની ટેકà«àª¸à«àªŸ અને છબીઓ વાંચવાથી બà«àª²à«‰àª• કરો</translation>
<translation id="6945221475159498467">પસંદ કરો</translation>
<translation id="6965382102122355670">બરાબર, સમજાઇ ગયà«àª‚</translation>
+<translation id="6981982820502123353">àªàª•à«àª¸à«‡àª¸àª¿àª¬àª¿àª²àª¿àªŸà«€</translation>
<translation id="6992289844737586249">સાઇટને તમારા માઇકà«àª°à«‹àª«à«‹àª¨àª¨à«‹ ઉપયોગ કરવાની મંજૂરી આપતાં પહેલા પૂછો (સà«àªàª¾àªµ આપીઠછીàª)</translation>
<translation id="7000754031042624318">Android સેટિંગમાં પરવાનગી બંધ કરી છે</translation>
<translation id="7016516562562142042">હાલનાં શોધ àªàª¨à«àªœàª¿àª¨ માટે મંજૂર</translation>
+<translation id="702463548815491781">જà«àª¯àª¾àª°à«‡ ટૉકબૅક અથવા સà«àªµàª¿àªš àªàª•à«àª¸à«‡àª¸ ચાલૠહોય તà«àª¯àª¾àª°à«‡ આપેલ સà«àªàª¾àªµ</translation>
<translation id="7053983685419859001">અવરોધિત કરો</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1 પસંદ કરી}one{# પસંદ કરી}other{# પસંદ કરી}}</translation>
-<translation id="7070090581017165256">આ સાઇટ વિશે</translation>
<translation id="7087918508125750058"><ph name="ITEM_COUNT" />ની પસંદગી કરી. સà«àª•à«àª°à«€àª¨àª¨àª¾ ટોચની નજીક વિકલà«àªªà«‹ ઉપલબà«àª§ છે</translation>
<translation id="7141896414559753902">સાઇટને પૉપ-અપ અને રીડાયરેકà«àªŸ બતાવવા દેવાથી બà«àª²à«‰àª• કરો (સà«àªàª¾àªµ આપીઠછીàª)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> KB</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">કોઈ સાઇટ તમારા માઇકà«àª°à«‹àª«à«‹àª¨àª¨à«‹ ઉપયોગ કરી રહી છે</translation>
<translation id="7561196759112975576">હંમેશાં</translation>
-<translation id="7572498721684305250">જà«àª¯àª¾àª°à«‡ તમે NFC ડિવાઇસ પર ટૅપ કરો તà«àª¯àª¾àª°à«‡ સાઇટને માહિતી મોકલવા અને પà«àª°àª¾àªªà«àª¤ કરવાથી બà«àª²à«‰àª• કરો</translation>
<translation id="757524316907819857">સાઇટને સંરકà«àª·àª¿àª¤ કનà«àªŸà«‡àª¨à«àªŸ ચલાવવાથી બà«àª²à«‰àª• કરો</translation>
+<translation id="7577900504646297215">રà«àªšàª¿àª“ મેનેજ કરો</translation>
<translation id="7649070708921625228">સહાય</translation>
<translation id="7658239707568436148">રદ કરો</translation>
<translation id="7781829728241885113">ગઈ કાલે</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">કનેકà«àª¶àª¨ સà«àª°àª•à«àª·àª¿àª¤ છે</translation>
<translation id="8249310407154411074">ટોચે ખસેડો</translation>
<translation id="8261506727792406068">ડિલીટ કરો</translation>
+<translation id="8284326494547611709">કૅપà«àª¶àª¨à«àª¸</translation>
<translation id="8300705686683892304">àªàªª દà«àªµàª¾àª°àª¾ મેનેજ થતી</translation>
<translation id="8324158725704657629">ફરીથી પૂછશો નહીં</translation>
<translation id="8372893542064058268">ચોકà«àª•àª¸ સાઇટ માટે બૅકગà«àª°àª¾àª‰àª¨à«àª¡ સિંકની મંજૂરી આપો.</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">àªà«‚મ વધારો</translation>
<translation id="8921772741368021346"><ph name="POSITION" /> / <ph name="DURATION" /></translation>
<translation id="8926666909099850184">આ ડિવાઇસ માટે NFC સેવા બંધ કરેલી છે. તેને <ph name="BEGIN_LINK" />Android સેટિંગ<ph name="END_LINK" />માં ચાલૠકરો.</translation>
+<translation id="8928445016601307354">NFC ડિવાઇસ પર સાઇટને માહિતી જોવાથી અને બદલવાથી બà«àª²à«‰àª• કરો</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">કોઈ ચોકà«àª•àª¸ સાઇટ માટે કà«àª•à«€àª¨à«‡ બà«àª²à«‰àª• કરો.</translation>
<translation id="8959122750345127698">નેવિગેશન બિનપહોંચ યોગà«àª¯ છે: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_hi.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_hi.xtb
index 63b7994957e..ef8c2386b7f 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_hi.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_hi.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676"><ph name="SITE_NAME" /> साइट जोड़ी गई</translation>
<translation id="1383876407941801731">Search</translation>
<translation id="1384959399684842514">डाउनलोड रोका गया</translation>
+<translation id="1409426117486808224">खà¥à¤²à¥‡ टैब के लिठसरल बनाया गया वà¥à¤¯à¥‚</translation>
<translation id="1415402041810619267">यूआरà¤à¤² छोटा हो गया</translation>
<translation id="1446450296470737166">MIDI डिवाइस के पूरे नियंतà¥à¤°à¤£ की अनà¥à¤®à¤¤à¤¿ दें</translation>
<translation id="1620510694547887537">कैमरा</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">कà¥à¤•à¥€ की अनà¥à¤®à¤¤à¤¿ दें</translation>
<translation id="2228071138934252756"><ph name="APP_NAME" /> को कैमरे का à¤à¤•à¥à¤¸à¥‡à¤¸ देने के लिà¤, <ph name="BEGIN_LINK" />Android की सेटिंग<ph name="END_LINK" /> में जाकर भी कैमरा चालू करें.</translation>
<translation id="2241634353105152135">बस à¤à¤• बार</translation>
+<translation id="2253414712144136228"><ph name="NAME_OF_LIST_ITEM" /> हटाà¤à¤‚</translation>
<translation id="2289270750774289114">जब कोई साइट आस-पास के बà¥à¤²à¥‚टूथ डिवाइस को खोजना चाहे, तो इसके लिठपूछें (सà¥à¤à¤¾à¤¯à¤¾ गया)</translation>
<translation id="2315043854645842844">कà¥à¤²à¤¾à¤‡à¤‚ट-साइड पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° चà¥à¤¨à¤¨à¤¾ ऑपरेटिंग सिसà¥à¤Ÿà¤® से नहीं किया जा सकता है.</translation>
+<translation id="2321958826496381788">इस टेकà¥à¤¸à¥à¤Ÿ को आसानी से पढ़ने लायक बनाने के लिà¤, सà¥â€à¤²à¤¾à¤‡à¤¡à¤° को आगे की ओर खींचें. पैरागà¥à¤°à¤¾à¤«à¤¼ पर डबल-टैप करने के बाद, टेकà¥à¤¸à¥à¤Ÿ को इतना बड़ा दिखाई देना चाहिà¤.</translation>
<translation id="2359808026110333948">जारी रखें</translation>
<translation id="2379925928934107488">जब भी हो सके, तो साइटों पर तब गहरे रंग वाली थीम लागू करें जब Chrome इस थीम पर सेट हो</translation>
+<translation id="2387895666653383613">लेख सà¥â€à¤•à¥‡à¤²à¤¿à¤‚ग</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> à¤à¤®à¤¬à¥€</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, और <ph name="NUM_MORE" /> अनà¥à¤¯ सà¥à¤µà¤¿à¤§à¤¾ को इसà¥à¤¤à¥‡à¤®à¤¾à¤² करने की अनà¥à¤®à¤¤à¤¿ दी गई}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, और <ph name="NUM_MORE" /> अनà¥à¤¯ सà¥à¤µà¤¿à¤§à¤¾ को इसà¥à¤¤à¥‡à¤®à¤¾à¤² करने की अनà¥à¤®à¤¤à¤¿ दी गई}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, और <ph name="NUM_MORE" /> अनà¥à¤¯ सà¥à¤µà¤¿à¤§à¤¾à¤“ं को इसà¥à¤¤à¥‡à¤®à¤¾à¤² करने की अनà¥à¤®à¤¤à¤¿ दी गई}}</translation>
<translation id="2434158240863470628">डाउनलोड हो गया <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">जानकारी दिखाà¤à¤‚</translation>
<translation id="3123473560110926937">कà¥à¤› साइटों पर बà¥à¤²à¥‰à¤• किठगठहैं</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> संगà¥à¤°à¤¹à¤¿à¤¤ डेटा</translation>
+<translation id="3203366800380907218">वेब से</translation>
<translation id="321187648315454507"><ph name="BEGIN_LINK" />Android की सेटिंग<ph name="END_LINK" /> में जाकर भी सूचनाà¤à¤‚ चालू करें, ताकि <ph name="APP_NAME" /> आपको सूचनाà¤à¤‚ भेज सके.</translation>
<translation id="3227137524299004712">माइकà¥à¤°à¥‹à¤«à¤¼à¥‹à¤¨</translation>
<translation id="3277252321222022663">साइटों को सेंसर à¤à¤•à¥à¤¸à¥‡à¤¸ करने दें (सà¥à¤à¤¾à¤¯à¤¾ गया)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">आपके डिवाइस का इसà¥à¤¤à¥‡à¤®à¤¾à¤²</translation>
<translation id="385051799172605136">वापस जाà¤à¤‚</translation>
<translation id="3859306556332390985">आगे जाà¤à¤‚</translation>
+<translation id="3895926599014793903">ज़बरदसà¥à¤¤à¥€ ज़ूम करना चालू करें</translation>
<translation id="3955193568934677022">साइटों को सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ सामगà¥à¤°à¥€ चलाने दें (हम इस सेटिंग को चालू रखने का सà¥à¤à¤¾à¤µ देते हैं)</translation>
<translation id="3967822245660637423">डाउनलोड पूरा हà¥à¤†</translation>
<translation id="3987993985790029246">लिंक की पà¥à¤°à¤¤à¤¿ बनाà¤à¤‚</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> / ?</translation>
<translation id="4002066346123236978">शीरà¥à¤·à¤•</translation>
<translation id="4008040567710660924">किसी खास साइट के लिठकà¥à¤•à¥€ की मंज़ूरी दें.</translation>
+<translation id="4040330681741629921">किसी साइट के लिà¤, सरल बनाठगठवà¥à¤¯à¥‚ की सà¥à¤µà¤¿à¤§à¤¾ उपलबà¥à¤§ होने पर सूचना पाà¤à¤‚</translation>
<translation id="4046123991198612571">अगला टà¥à¤°à¥ˆà¤•</translation>
+<translation id="4149994727733219643">वेब पेजों के लिठसरल बनाया गया वà¥à¤¯à¥‚</translation>
<translation id="4165986682804962316">साइट सेटिंग</translation>
+<translation id="4194328954146351878">साइटों को à¤à¤¨à¤à¤«à¤¼à¤¸à¥€ की सà¥à¤µà¤¿à¤§à¤¾ वाले डिवाइसों पर, जानकारी देखने और उसमें बदलाव करने की अनà¥à¤®à¤¤à¤¿ देने से पहले पूछा जाठ(सà¥à¤à¤¾à¤ˆ गई सेटिंग)</translation>
<translation id="4200726100658658164">जगह की सेटिंग खोलें</translation>
<translation id="4226663524361240545">नोटिफ़िकेशन से डिवाइस में कंपन हो सकता है</translation>
<translation id="4259722352634471385">मारà¥à¤—दरà¥à¤¶à¤• अवरोधित है: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">विसà¥à¤¤à¥ƒà¤¤ करें</translation>
<translation id="4336434711095810371">सारा डेटा मिटाà¤à¤‚</translation>
<translation id="4402755511846832236">साइटों को यह जानने से रोकें कि आप इस डिवाइस का इसà¥à¤¤à¥‡à¤®à¤¾à¤² कब करते हैं</translation>
+<translation id="4428065317363009941">दिलचसà¥à¤ªà¥€ के मà¥à¤¤à¤¾à¤¬à¤¿à¤• विजà¥à¤žà¤¾à¤ªà¤¨</translation>
<translation id="4434045419905280838">पॉप-अप और रीडायरेकà¥à¤Ÿ</translation>
<translation id="445467742685312942">साइटों को सभी सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ सामगà¥à¤°à¥€ चलाने दें</translation>
<translation id="4468959413250150279">किसी खास साइट के लिठआवाज़ बंद करें.</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">यह विकलà¥à¤ª, सà¥à¤•à¥à¤°à¥€à¤¨ के सबसे ऊपरी हिसà¥à¤¸à¥‡ में उपलबà¥à¤§ है</translation>
<translation id="5197729504361054390">आप जो संपरà¥à¤• चà¥à¤¨à¥‡à¤‚गे उनà¥à¤¹à¥‡à¤‚ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> के साथ शेयर किया जाà¤à¤—ा.</translation>
<translation id="5216942107514965959">साइट पर पिछली बार आज गà¤</translation>
+<translation id="5264323282659631142">'<ph name="CHIP_LABEL" />' हटाà¤à¤‚</translation>
<translation id="528192093759286357">फ़à¥à¤² सà¥à¤•à¥à¤°à¥€à¤¨ से बाहर निकलने के लिठऊपर से खींचें और वापस जाà¤à¤‚ सà¥à¤ªà¤°à¥à¤¶ करें.</translation>
<translation id="5300589172476337783">दिखाà¤à¤‚</translation>
<translation id="5301954838959518834">ठीक है, समठलिया</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">इससे वे <ph name="DATASIZE" /> डेटा और कà¥à¤•à¥€ मिट जाà¤à¤‚गे जिनà¥à¤¹à¥‡à¤‚ साइटों ने सेव किया है.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(+ 1 और)}one{(+ # और)}other{(+ # और)}}</translation>
<translation id="5403592356182871684">नाम</translation>
+<translation id="5412236728747081950">यह साइट आपकी दिलचसà¥à¤ªà¥€ के बारे में Chrome से पता करती है, ताकि आपको ज़à¥à¤¯à¤¾à¤¦à¤¾ काम के विजà¥à¤žà¤¾à¤ªà¤¨ दिखा सके</translation>
<translation id="5438097262470833822">यह विकलà¥à¤ª <ph name="WEBSITE" /> के लिठअनà¥à¤®à¤¤à¤¿à¤¯à¤¾à¤‚ रीसेट करेगा</translation>
<translation id="5489227211564503167"><ph name="TOTAL_TIME" /> में से <ph name="ELAPSED_TIME" /> का समय बीत चà¥à¤•à¤¾ है.</translation>
<translation id="5494752089476963479">तंग करने वाले या गà¥à¤®à¤°à¤¾à¤¹ करने वाले विजà¥à¤žà¤¾à¤ªà¤¨ दिखाने वाली साइटों पर विजà¥à¤žà¤¾à¤ªà¤¨ बà¥à¤²à¥‰à¤• करें</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">फिर लोड करें</translation>
<translation id="5596627076506792578">ज़à¥à¤¯à¤¾à¤¦à¤¾ विकलà¥à¤ª</translation>
<translation id="5649053991847567735">अपने आप होने वाले डाउनलोड</translation>
+<translation id="5668404140385795438">किसी वेबसाइट के वेबपेज ज़ूम इन न करने के नियम को बदल देता है</translation>
<translation id="5677928146339483299">बà¥à¤²à¥‰à¤• किया गया है</translation>
<translation id="5689516760719285838">सà¥à¤¥à¤¾à¤¨</translation>
<translation id="5690795753582697420">Android की सेटिंग में कैमरा बंद है</translation>
-<translation id="5710871682236653961">NFC डिवाइस पर टैप करने के बाद, साइटों को जानकारी भेजने और पाने की अनà¥à¤®à¤¤à¤¿ देने से पहले पूछें (सà¥à¤à¤¾à¤¯à¤¾ गया)</translation>
<translation id="5719847187258001597">इससे वे सभी डेटा और कà¥à¤•à¥€ मिट जाà¤à¤‚गे जिनà¥à¤¹à¥‡à¤‚ <ph name="ORIGIN" /> या इसके à¤à¤ªà¥à¤²à¤¿à¤•à¥‡à¤¶à¤¨ ने आपकी होम सà¥à¤•à¥à¤°à¥€à¤¨ पर सेव किया है.</translation>
<translation id="5771720122942595109"><ph name="PERMISSION_1" /> को बà¥à¤²à¥‰à¤• किया गया</translation>
<translation id="5804241973901381774">अनà¥à¤®à¤¤à¤¿à¤¯à¤¾à¤‚</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">चलाà¤à¤‚</translation>
<translation id="6818926723028410516">आइटम चà¥à¤¨à¥‡à¤‚</translation>
<translation id="6864395892908308021">इस डिवाइस के साथ NFC काम नहीं कर सकता</translation>
-<translation id="6910211073230771657">हटाया गया</translation>
<translation id="6912998170423641340">साइटों को कà¥à¤²à¤¿à¤ªà¤¬à¥‹à¤°à¥à¤¡ से टेकà¥à¤¸à¥à¤Ÿ और इमेज पढ़ने से रोकें</translation>
<translation id="6945221475159498467">चà¥à¤¨à¥‡à¤‚</translation>
<translation id="6965382102122355670">ठीक है</translation>
+<translation id="6981982820502123353">सà¥à¤²à¤­à¤¤à¤¾</translation>
<translation id="6992289844737586249">साइटों को अपने माइकà¥à¤°à¥‹à¥žà¥‹à¤¨ का इसà¥à¤¤à¥‡à¤®à¤¾à¤² करने देने से पहले अनà¥à¤®à¤¤à¤¿ लेना ज़रूरी बनाà¤à¤‚ (सà¥à¤à¤¾à¤¯à¤¾ गया)</translation>
<translation id="7000754031042624318">Android सेटिंग में बंद कर दिया गया है</translation>
<translation id="7016516562562142042">मौजूदा सरà¥à¤š इंजन के लिठअनà¥à¤®à¤¤à¤¿ दी गई है</translation>
+<translation id="702463548815491781">उस समय के लिठसà¥à¤à¤¾à¤¯à¤¾ गया जब 'टॉकबैक' या 'à¤à¤•à¥à¤¸à¥‡à¤¸ करने का तरीका बदलें' चालू हों</translation>
<translation id="7053983685419859001">बà¥à¤²à¥‰à¤• करें</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1 चà¥à¤¨à¤¾ गया}one{# चà¥à¤¨à¥‡ गà¤}other{# चà¥à¤¨à¥‡ गà¤}}</translation>
-<translation id="7070090581017165256">इस साइट के बारे में</translation>
<translation id="7087918508125750058"><ph name="ITEM_COUNT" /> चà¥à¤¨à¥‡ गà¤. विकलà¥à¤ª, सà¥à¤•à¥à¤°à¥€à¤¨ के ऊपरी भाग के पास उपलबà¥à¤§ हैं</translation>
<translation id="7141896414559753902">साइटों को पॉप-अप और रीडायरेकà¥à¤Ÿ दिखाने से रोकें (हम इस सेटिंग को चालू रखने का सà¥à¤à¤¾à¤µ देते हैं)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> केबी</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">कोई साइट आपके माइकà¥à¤°à¥‹à¤«à¤¼à¥‹à¤¨ का इसà¥à¤¤à¥‡à¤®à¤¾à¤² कर रही है</translation>
<translation id="7561196759112975576">हमेशा</translation>
-<translation id="7572498721684305250">NFC डिवाइस पर टैप करने के बाद, साइटों को जानकारी भेजने और पाने पर रोक लगाà¤à¤‚</translation>
<translation id="757524316907819857">साइटों को सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ सामगà¥à¤°à¥€ चलाने से रोकें</translation>
+<translation id="7577900504646297215">पसंद पà¥à¤°à¤¬à¤‚धित करें</translation>
<translation id="7649070708921625228">सहायता</translation>
<translation id="7658239707568436148">अभी नहीं</translation>
<translation id="7781829728241885113">बीता कल</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">कनेकà¥à¤¶à¤¨ सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ है</translation>
<translation id="8249310407154411074">सबसे ऊपर ले जाà¤à¤‚</translation>
<translation id="8261506727792406068">मिटाà¤à¤‚</translation>
+<translation id="8284326494547611709">कैपà¥à¤¶à¤¨</translation>
<translation id="8300705686683892304">à¤à¤ªà¥à¤²à¤¿à¤•à¥‡à¤¶à¤¨ मैनेज करता है</translation>
<translation id="8324158725704657629">दोबारा न पूछें</translation>
<translation id="8372893542064058268">किसी विशिषà¥à¤Ÿ साइट के लिठपृषà¥à¤ à¤­à¥‚मि समनà¥à¤µà¤¯à¤¨ की अनà¥à¤®à¤¤à¤¿ दें.</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">ज़ूम इन करें</translation>
<translation id="8921772741368021346"><ph name="POSITION" /> / <ph name="DURATION" /></translation>
<translation id="8926666909099850184">इस डिवाइस पर NFC बंद है. <ph name="BEGIN_LINK" />Android सेटिंग<ph name="END_LINK" /> में इसे चालू करें.</translation>
+<translation id="8928445016601307354">साइटों को à¤à¤¨à¤à¤«à¤¼à¤¸à¥€ की सà¥à¤µà¤¿à¤§à¤¾ वाले डिवाइसों पर जानकारी देखने और उसमें बदलाव करने से रोकें</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">किसी खास साइट के लिठकà¥à¤•à¥€ बà¥à¤²à¥‰à¤• करें.</translation>
<translation id="8959122750345127698">मारà¥à¤—दरà¥à¤¶à¤• तक नहीं पहà¥à¤‚चा जा सकता: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_hr.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_hr.xtb
index d6f48eb1072..0f18a070a05 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_hr.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_hr.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">Dodana je web-lokacija <ph name="SITE_NAME" /></translation>
<translation id="1383876407941801731">Traži</translation>
<translation id="1384959399684842514">Preuzimanje je pauzirano</translation>
+<translation id="1409426117486808224">Pojednostavljeni prikaz za otvorene kartice</translation>
<translation id="1415402041810619267">URL je skraćen</translation>
<translation id="1446450296470737166">Omogući potpuni nadzor za MIDI</translation>
<translation id="1620510694547887537">Fotoaparat</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">Dopusti kolaÄiće</translation>
<translation id="2228071138934252756">Da bi aplikacija <ph name="APP_NAME" /> mogla pristupiti vaÅ¡oj kameri, ukljuÄite kameru i u <ph name="BEGIN_LINK" />Androidovim postavkama<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Samo jednom</translation>
+<translation id="2253414712144136228">Ukloni <ph name="NAME_OF_LIST_ITEM" /></translation>
<translation id="2289270750774289114">Prikaži upit kad web-lokacija želi tražiti Bluetooth ureÄ‘aje u blizini (preporuÄeno)</translation>
<translation id="2315043854645842844">Operativni sustav ne podržava odabir klijentskog certifikata.</translation>
+<translation id="2321958826496381788">PomiÄite klizaÄ dok ne budete mogli Äitati ovaj tekst bez poteÅ¡koća. Tekst bi trebao biti barem ovoliko velik nakon Å¡to dvaput dodirnete odlomak.</translation>
<translation id="2359808026110333948">Nastavi</translation>
<translation id="2379925928934107488">Primijeni tamnu temu na web-lokacije kad Chrome koristi tamnu temu, kad je moguće</translation>
+<translation id="2387895666653383613">Skaliranje teksta</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Odobrena su dopuštenja <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i još <ph name="NUM_MORE" />}one{Odobrena su dopuštenja <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i još <ph name="NUM_MORE" />}few{Odobrena su dopuštenja <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i još <ph name="NUM_MORE" />}other{Odobrena su dopuštenja <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i još <ph name="NUM_MORE" />}}</translation>
<translation id="2434158240863470628">Preuzimanje je dovršeno: <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">Prikaži informacije</translation>
<translation id="3123473560110926937">Blokirano na nekim web-lokacijama</translation>
<translation id="3198916472715691905">Pohranjeni podaci: <ph name="STORAGE_AMOUNT" /></translation>
+<translation id="3203366800380907218">S weba</translation>
<translation id="321187648315454507">Da bi vam aplikacija <ph name="APP_NAME" /> slati obavijesti, ukljuÄite obavijesti i u <ph name="BEGIN_LINK" />Androidovim postavkama<ph name="END_LINK" />.</translation>
<translation id="3227137524299004712">Mikrofon</translation>
<translation id="3277252321222022663">DopuÅ¡tanje pristupa senzorima za web-lokacije (preporuÄeno)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">Vaša upotreba uređaja</translation>
<translation id="385051799172605136">Natrag</translation>
<translation id="3859306556332390985">Traži unaprijed</translation>
+<translation id="3895926599014793903">Prisilno omogućavanje zumiranja</translation>
<translation id="3955193568934677022">Web-lokacije mogu reproducirati zaÅ¡tićeni sadržaj (preporuÄeno)</translation>
<translation id="3967822245660637423">Preuzimanje dovršeno</translation>
<translation id="3987993985790029246">Kopiraj vezu</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" />/?</translation>
<translation id="4002066346123236978">Naslov</translation>
<translation id="4008040567710660924">Dopusti kolaÄiće za odreÄ‘enu web-lokaciju.</translation>
+<translation id="4040330681741629921">Primi obavijest kad se web-lokacija može prikazati u pojednostavljenom prikazu</translation>
<translation id="4046123991198612571">Sljedeća pjesma</translation>
+<translation id="4149994727733219643">Pojednostavljeni prikaz za web-stranice</translation>
<translation id="4165986682804962316">Postavke web-lokacije</translation>
+<translation id="4194328954146351878">Pitaj prije omogućavanja web-lokacijama da vide i mijenjaju podatke na NFC ureÄ‘ajima (preporuÄeno)</translation>
<translation id="4200726100658658164">Otvori postavke lokacije</translation>
<translation id="4226663524361240545">Obavijesti mogu ukljuÄiti vibriranje ureÄ‘aja</translation>
<translation id="4259722352634471385">Otvaranje je blokirano: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">Proširi</translation>
<translation id="4336434711095810371">Izbriši sve podatke</translation>
<translation id="4402755511846832236">Onemogućivanje web-lokacijama da znaju kad aktivno upotrebljavate ovaj uređaj</translation>
+<translation id="4428065317363009941">Prilagodba oglasa</translation>
<translation id="4434045419905280838">SkoÄni prozori i preusmjeravanja</translation>
<translation id="445467742685312942">Web-lokacijama je dopuštena reprodukcija zaštićenog sadržaja</translation>
<translation id="4468959413250150279">IskljuÄivanje zvuka za odreÄ‘enu web-lokaciju.</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">Opcija je dostupna pri vrhu zaslona</translation>
<translation id="5197729504361054390">Kontakti koje odaberete podijelit će se s web-lokacijom <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />.</translation>
<translation id="5216942107514965959">Posljednji posjet bio je danas</translation>
+<translation id="5264323282659631142">Ukloni '<ph name="CHIP_LABEL" />'</translation>
<translation id="528192093759286357">Povucite od vrha zaslona i dodirnite gumb Natrag da biste zatvorili prikaz na cijelom zaslonu.</translation>
<translation id="5300589172476337783">Prikaži</translation>
<translation id="5301954838959518834">U redu, shvaćam</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">Izbrisat će se <ph name="DATASIZE" /> podataka i kolaÄića koje su spremile web-lokacije.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(+ još 1)}one{(+ još #)}few{(+ još #)}other{(+ još #)}}</translation>
<translation id="5403592356182871684">Nazivi</translation>
+<translation id="5412236728747081950">Ova web-lokacija prima podatke o vašim interesima iz Chromea kako bi vam prikazivala relevantnije oglase.</translation>
<translation id="5438097262470833822">Poništit će se dopuštenja za web-lokaciju <ph name="WEBSITE" /></translation>
<translation id="5489227211564503167">Proteklo vrijeme: <ph name="ELAPSED_TIME" /> od <ph name="TOTAL_TIME" /></translation>
<translation id="5494752089476963479">Blokiraj oglase na web-lokacijama koje prikazuju ometajuće ili obmanjujuće oglase</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">Ponovno uÄitaj</translation>
<translation id="5596627076506792578">Više opcija</translation>
<translation id="5649053991847567735">Automatska preuzimanja</translation>
+<translation id="5668404140385795438">NadjaÄa zahtjev web-lokacije za sprjeÄavanje povećavanja</translation>
<translation id="5677928146339483299">Blokirano</translation>
<translation id="5689516760719285838">Lokacija</translation>
<translation id="5690795753582697420">Kamera se iskljuÄuje u Androidovim postavkama</translation>
-<translation id="5710871682236653961">Pitati prije dopuÅ¡tenja slanja i primanja informacija s web-lokacija kad dodirnete NFC ureÄ‘aje (preporuÄeno)</translation>
<translation id="5719847187258001597">Izbrisat će se svi podaci i kolaÄići koje je spremila web-lokacija <ph name="ORIGIN" /> ili njezina aplikacija na vaÅ¡em poÄetnom zaslonu.</translation>
<translation id="5771720122942595109">Blokirano je dopuštenje <ph name="PERMISSION_1" /></translation>
<translation id="5804241973901381774">Dozvoljeno</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">Reproduciraj</translation>
<translation id="6818926723028410516">Odaberite stavke</translation>
<translation id="6864395892908308021">Ovaj ureÄ‘aj ne može Äitati NFC</translation>
-<translation id="6910211073230771657">Izbrisano</translation>
<translation id="6912998170423641340">Blokiraj web-lokacijama Äitanje teksta i slika iz meÄ‘uspremnika</translation>
<translation id="6945221475159498467">Odaberi</translation>
<translation id="6965382102122355670">U redu</translation>
+<translation id="6981982820502123353">PristupaÄnost</translation>
<translation id="6992289844737586249">Web-lokacije moraju tražiti dopuÅ¡tenje za upotrebu mikrofona (preporuÄeno)</translation>
<translation id="7000754031042624318">IskljuÄeno u postavkama Androida</translation>
<translation id="7016516562562142042">DopuÅ¡teno za trenutaÄnu tražilicu</translation>
+<translation id="702463548815491781">PreporuÄuje se kada su ukljuÄeni TalkBack ili prekidaÄ za pristup</translation>
<translation id="7053983685419859001">Blokiraj</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1 odabrana stavka}one{# odabrana stavka}few{# odabrane stavke}other{# odabranih stavki}}</translation>
-<translation id="7070090581017165256">O ovoj web-lokaciji</translation>
<translation id="7087918508125750058">Odabrano: <ph name="ITEM_COUNT" />. Opcije su dostupne pri vrhu zaslona</translation>
<translation id="7141896414559753902">Web-lokacijama nije dopuÅ¡teno prikazivanje skoÄnih prozora i preusmjeravanja (preporuÄeno)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> KB</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">Web-lokacija upotrebljava vaš mikrofon</translation>
<translation id="7561196759112975576">Uvijek</translation>
-<translation id="7572498721684305250">Blokiranje slanja i primanja informacija s web-lokacija kad dodirnete NFC uređaje</translation>
<translation id="757524316907819857">Web-lokacijama nije dopušteno reproduciranje zaštićenog sadržaja</translation>
+<translation id="7577900504646297215">Upravljaj interesima</translation>
<translation id="7649070708921625228">Pomoć</translation>
<translation id="7658239707568436148">Odustani</translation>
<translation id="7781829728241885113">Danas</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">Veza je sigurna</translation>
<translation id="8249310407154411074">Na vrh</translation>
<translation id="8261506727792406068">Izbriši</translation>
+<translation id="8284326494547611709">Titlovi</translation>
<translation id="8300705686683892304">Upravlja aplikacija</translation>
<translation id="8324158725704657629">Više me ne pitaj</translation>
<translation id="8372893542064058268">Omogućuje sinkronizaciju u pozadini za određenu web-lokaciju.</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">Povećaj</translation>
<translation id="8921772741368021346"><ph name="POSITION" />/<ph name="DURATION" /></translation>
<translation id="8926666909099850184">NFC je iskljuÄen za ovaj ureÄ‘aj. UkljuÄite ga u <ph name="BEGIN_LINK" />postavkama Androida<ph name="END_LINK" />.</translation>
+<translation id="8928445016601307354">Onemogući web-lokacijama da vide i mijenjaju podatke na NFC uređajima</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">Blokiraj kolaÄiće za odreÄ‘enu web-lokaciju.</translation>
<translation id="8959122750345127698">Otvaranje je nedostupno: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_hu.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_hu.xtb
index 32d7535e89c..5c589c647ea 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_hu.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_hu.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">A(z) <ph name="SITE_NAME" /> webhely hozzáadva</translation>
<translation id="1383876407941801731">Keresés</translation>
<translation id="1384959399684842514">A letöltés szünetel</translation>
+<translation id="1409426117486808224">A megnyitott lapok egyszerűsített nézete</translation>
<translation id="1415402041810619267">URL csonkolva</translation>
<translation id="1446450296470737166">MIDI-eszközök teljes vezérlése</translation>
<translation id="1620510694547887537">Kamera</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">Cookie-k engedélyezése</translation>
<translation id="2228071138934252756">Ahhoz, hogy a(z) <ph name="APP_NAME" /> hozzáférhessen a kamerához, a kamerát az <ph name="BEGIN_LINK" />Android-beállítások<ph name="END_LINK" /> között is be kell kapcsolni.</translation>
<translation id="2241634353105152135">Csak egyszer</translation>
+<translation id="2253414712144136228"><ph name="NAME_OF_LIST_ITEM" /> eltávolítása</translation>
<translation id="2289270750774289114">Kérdezzen rá, ha valamelyik webhely szeretné felfedezni a közeli Bluetooth-eszközöket (ajánlott)</translation>
<translation id="2315043854645842844">Az ügyféloldali tanúsítványválasztást az operációs rendszer nem támogatja.</translation>
+<translation id="2321958826496381788">Húzza a csúszkát, amíg kényelmesen nem tudja olvasni a szöveget. A szövegnek legalább ekkorának kell lennie, miután duplán koppint egy bekezdésre.</translation>
<translation id="2359808026110333948">Tovább</translation>
<translation id="2379925928934107488">A sötét téma alkalmazása a webhelyekre (amikor lehetséges), ha a Chrome-ban sötét téma van beállítva</translation>
+<translation id="2387895666653383613">Szöveg nagyítása</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> és további <ph name="NUM_MORE" /> engedélyezve}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> és további <ph name="NUM_MORE" /> engedélyezve}}</translation>
<translation id="2434158240863470628">Letöltés befejezve <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">Információk megjelenítése</translation>
<translation id="3123473560110926937">Letiltva egyes webhelyeken</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> tárolt adat</translation>
+<translation id="3203366800380907218">Az internetről</translation>
<translation id="321187648315454507">Ahhoz, hogy a(z) <ph name="APP_NAME" /> értesítéseket küldhessen, az értesítéseket az <ph name="BEGIN_LINK" />Android-beállítások<ph name="END_LINK" /> között is be kell kapcsolni.</translation>
<translation id="3227137524299004712">Mikrofon</translation>
<translation id="3277252321222022663">Az érzékelőkhöz való hozzáférés engedélyezése a webhelyek számára (ajánlott)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">Aktív eszközhasználat</translation>
<translation id="385051799172605136">Vissza</translation>
<translation id="3859306556332390985">Ugrás előre</translation>
+<translation id="3895926599014793903">A nagyítás mindig engedélyezett</translation>
<translation id="3955193568934677022">Engedélyezi a webhelyek számára a védett tartalmak lejátszását (ajánlott)</translation>
<translation id="3967822245660637423">A letöltés sikeres</translation>
<translation id="3987993985790029246">Link másolása</translation>
<translation id="3991845972263764475">? / <ph name="BYTES_DOWNLOADED_WITH_UNITS" /></translation>
<translation id="4002066346123236978">Cím</translation>
<translation id="4008040567710660924">Adott webhely cookie-jainak engedélyezése.</translation>
+<translation id="4040330681741629921">Értesítés megjelenítése, ha az adott webhely megjeleníthető egyszerűsített négyzetben</translation>
<translation id="4046123991198612571">Következő szám</translation>
+<translation id="4149994727733219643">Weboldalak egyszerűsített nézete</translation>
<translation id="4165986682804962316">Webhelybeállítások</translation>
+<translation id="4194328954146351878">Kérdezzen rá, mielőtt engedélyezi a webhelyek számára az NFC-eszközökön található információk megtekintését és az ilyen eszközökkel való információcserét (ajánlott)</translation>
<translation id="4200726100658658164">Helybeállítások megnyitása</translation>
<translation id="4226663524361240545">Az értesítések miatt rezeghet az eszköz</translation>
<translation id="4259722352634471385">Le van tiltva az ide vezető navigáció: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">Kibontás</translation>
<translation id="4336434711095810371">Az összes adat törlése</translation>
<translation id="4402755511846832236">A webhelyek nem kaphatnak információt arról, hogy Ön mikor használja aktívan ezt az eszközt.</translation>
+<translation id="4428065317363009941">Hirdetések személyre szabása</translation>
<translation id="4434045419905280838">Előugró ablakok és átirányítások</translation>
<translation id="445467742685312942">Védett tartalmak lejátszásának engedélyezése a webhelyek számára</translation>
<translation id="4468959413250150279">Egy adott webhely hangjának némítása.</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">A lehetőség a képernyő tetején található</translation>
<translation id="5197729504361054390">A kiválasztott névjegyeket megosztjuk a következő webhellyel: <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />.</translation>
<translation id="5216942107514965959">Utolsó látogatás: ma</translation>
+<translation id="5264323282659631142">„<ph name="CHIP_LABEL" />“ eltávolítása</translation>
<translation id="528192093759286357">A teljes képernyős megjelenítésből való kilépéshez húzza le felülről, majd koppintson a vissza gombra.</translation>
<translation id="5300589172476337783">Megjelenítés</translation>
<translation id="5301954838959518834">Rendben, értem</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">Ezzel <ph name="DATASIZE" />-nyi, webhelyek által tárolt adatot és cookie-t töröl.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(+ 1 további)}other{(+ # további)}}</translation>
<translation id="5403592356182871684">Nevek</translation>
+<translation id="5412236728747081950">Ez a webhely lekéri az érdeklődési köreit a Chrome-tól, hogy relevánsabb hirdetéseket jelenítsen meg Önnek</translation>
<translation id="5438097262470833822">Ezzel visszaállítja a(z) <ph name="WEBSITE" /> webhelyhez tartozó engedélyeket.</translation>
<translation id="5489227211564503167">Eltelt idő: <ph name="ELAPSED_TIME" />, ennyiből: <ph name="TOTAL_TIME" />.</translation>
<translation id="5494752089476963479">Hirdetések letiltása a tolakodó és félrevezető hirdetéseket megjelenítő webhelyeken</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">Újratöltés</translation>
<translation id="5596627076506792578">További lehetőségek</translation>
<translation id="5649053991847567735">Automatikus letöltések</translation>
+<translation id="5668404140385795438">Felülbírálja a webhely kérelmét, mely megakadályozná a nagyítást</translation>
<translation id="5677928146339483299">Letiltva</translation>
<translation id="5689516760719285838">Tartózkodási hely</translation>
<translation id="5690795753582697420">A kamera ki van kapcsolva az Android-beállítások között</translation>
-<translation id="5710871682236653961">Kérdezzen rá, mielőtt engedélyezi a webhelyek számára az adatok küldését és fogadását, amikor NFC-eszközökre koppint (javasolt)</translation>
<translation id="5719847187258001597">Ezzel törli a(z) <ph name="ORIGIN" /> vagy az alkalmazása által tárolt összes adatot és cookie-t a kezdőképernyőn.</translation>
<translation id="5771720122942595109"><ph name="PERMISSION_1" /> letiltva</translation>
<translation id="5804241973901381774">Engedélyek</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">Lejátszás</translation>
<translation id="6818926723028410516">Válasszon elemeket</translation>
<translation id="6864395892908308021">Ez az eszköz nem képes az NFC-alapú kommunikáció olvasására</translation>
-<translation id="6910211073230771657">Törölve</translation>
<translation id="6912998170423641340">A vágólapon található szövegek és képek megtekintésének letiltása a webhelyek számára</translation>
<translation id="6945221475159498467">Kiválasztás</translation>
<translation id="6965382102122355670">OK</translation>
+<translation id="6981982820502123353">Kisegítő lehetőségek</translation>
<translation id="6992289844737586249">Kérdezzen rá, mielőtt engedélyezné a webhelyek számára a mikrofon használatát (ajánlott)</translation>
<translation id="7000754031042624318">Kikapcsolva az Android beállításaiban</translation>
<translation id="7016516562562142042">Engedélyezett a jelenlegi keresőmotor számára</translation>
+<translation id="702463548815491781">Ajánlott, amikor a TalkBack vagy a Kapcsolóalapú hozzáférés be van kapcsolva</translation>
<translation id="7053983685419859001">Letiltás</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1 elem kijelölve}other{# elem kijelölve}}</translation>
-<translation id="7070090581017165256">A webhelyről</translation>
<translation id="7087918508125750058"><ph name="ITEM_COUNT" /> elem kiválasztva. A lehetőségek a képernyő tetején találhatók.</translation>
<translation id="7141896414559753902">Előugró ablakok és átirányítások letiltása a webhelyeken (ajánlott)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> kB</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">Egy webhely használja az Ön mikrofonját</translation>
<translation id="7561196759112975576">Mindig</translation>
-<translation id="7572498721684305250">Adatok küldésének és fogadásának letiltása a webhelyek számára, amikor NFC-eszközökre koppint</translation>
<translation id="757524316907819857">Védett tartalom lejátszásának letiltása a webhelyeken</translation>
+<translation id="7577900504646297215">Érdeklődési körök kezelése</translation>
<translation id="7649070708921625228">Súgó</translation>
<translation id="7658239707568436148">Mégse</translation>
<translation id="7781829728241885113">Tegnap</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">A kapcsolat biztonságos</translation>
<translation id="8249310407154411074">Mozgatás az elejére</translation>
<translation id="8261506727792406068">Törlés</translation>
+<translation id="8284326494547611709">Feliratok</translation>
<translation id="8300705686683892304">Alkalmazás által kezelt</translation>
<translation id="8324158725704657629">Ne jelenjen meg többé</translation>
<translation id="8372893542064058268">Háttérben történő szinkronizálás engedélyezése adott webhely esetében.</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">Nagyítás</translation>
<translation id="8921772741368021346"><ph name="POSITION" />/<ph name="DURATION" /></translation>
<translation id="8926666909099850184">Az NFC ki van kapcsolva ezen az eszközön. Kapcsolja be az <ph name="BEGIN_LINK" />Android Beállítások alkalmazásában<ph name="END_LINK" />.</translation>
+<translation id="8928445016601307354">NFC-eszközökön található információk megtekintésének és az ilyen eszközökkel való információcserének a tiltása a webhelyek számára</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">Adott webhely cookie-jainak letiltása.</translation>
<translation id="8959122750345127698">Nem érhető el az ide vezető navigáció: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_hy.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_hy.xtb
index e91e0aefd94..8fed2b4a483 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_hy.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_hy.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676"><ph name="SITE_NAME" /> Õ¯Õ¡ÕµÖ„Õ¶ Õ¡Õ¾Õ¥Õ¬Õ¡ÖÕ¾Õ¥Õ¬ Õ§</translation>
<translation id="1383876407941801731">ÕˆÖ€Õ¸Õ¶Õ¸Ö‚Õ´</translation>
<translation id="1384959399684842514">Õ†Õ¥Ö€Õ¢Õ¥Õ¼Õ¶Õ¸Ö‚Õ´Õ¨ Õ¤Õ¡Õ¤Õ¡Ö€Õ¥ÖÕ¾Õ¥Õ¬ Õ§</translation>
+<translation id="1409426117486808224">Ô²Õ¡Ö Õ¶Õ¥Ö€Õ¤Õ«Ö€Õ¶Õ¥Ö€Õ« ÕºÕ¡Ö€Õ¦Õ¥ÖÕ¾Õ¡Õ® Õ¤Õ«Õ¿Õ¡Õ¯Õ¥Ö€Õº</translation>
<translation id="1415402041810619267">URL-Õ¨ Õ¯Ö€Õ³Õ¡Õ¿Õ¾Õ¥Õ¬ Õ§</translation>
<translation id="1446450296470737166">ÕÖ€Õ¡Õ´Õ¡Õ¤Ö€Õ¥Õ¬ Õ¡Õ´Õ¢Õ¸Õ²Õ»Õ¡Õ¯Õ¡Õ¶ Õ°Õ½Õ¯Õ¸Õ²Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶ MIDI Õ½Õ¡Ö€Ö„Õ¥Ö€Õ« Õ¶Õ¯Õ¡Õ¿Õ´Õ¡Õ´Õ¢</translation>
<translation id="1620510694547887537">ÕÕ¥Õ½Õ¡Õ­ÖÕ«Õ¯</translation>
@@ -26,7 +27,7 @@
<translation id="1688867105868176567">Õ‹Õ¶Õ»Õ¥ÕžÕ¬ Õ¯Õ¡ÕµÖ„Õ« Õ¿Õ¾ÕµÕ¡Õ¬Õ¶Õ¥Ö€Õ¨</translation>
<translation id="169515064810179024">Ô±Ö€Õ£Õ¥Õ¬Õ¥Õ¬ Õ¯Õ¡ÕµÖ„Õ¥Ö€Õ«Õ¶ Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¥Õ¬ Õ·Õ¡Ö€ÕªÕ´Õ¡Õ¶ Õ¿Õ¾Õ«Õ¹Õ¶Õ¥Ö€Õ¨</translation>
<translation id="1717218214683051432">Õ‡Õ¡Ö€ÕªÕ´Õ¡Õ¶ Õ¿Õ¾Õ«Õ¹Õ¶Õ¥Ö€</translation>
-<translation id="1743802530341753419">Õ€Õ¡Ö€ÖÕ¶Õ¥Õ¬Õ Õ¶Õ¡Õ­Ö„Õ¡Õ¶ Õ¯Õ¡ÕµÖ„Õ¥Ö€Õ«Õ¶ Õ¸Ö€Ö‡Õ§ Õ½Õ¡Ö€Ö„Õ« Õ´Õ«Õ¡Õ¶Õ¡Õ¬ Õ©Õ¸Ö‚ÕµÕ¬Õ¡Õ¿Ö€Õ¥Õ¬Õ¨ (Õ­Õ¸Ö€Õ°Õ¸Ö‚Ö€Õ¤ Õ§ Õ¿Ö€Õ¾Õ¸Ö‚Õ´)</translation>
+<translation id="1743802530341753419">Õ€Õ¡Ö€ÖÕ¶Õ¥Õ¬ Õ¶Õ¡Õ­Ö„Õ¡Õ¶ Õ¯Õ¡ÕµÖ„Õ¥Ö€Õ«Õ¶ Õ¸Ö€Ö‡Õ§ Õ½Õ¡Ö€Ö„Õ« Õ´Õ«Õ¡Õ¶Õ¡Õ¬ Õ©Õ¸Ö‚ÕµÕ¬Õ¡Õ¿Ö€Õ¥Õ¬Õ¨ (Õ­Õ¸Ö€Õ°Õ¸Ö‚Ö€Õ¤ Õ§ Õ¿Ö€Õ¾Õ¸Ö‚Õ´)</translation>
<translation id="1779089405699405702">ÕŠÕ¡Õ¿Õ¯Õ¥Ö€Õ« Õ¡ÕºÕ¡Õ¯Õ¸Õ¤Õ¡Õ¾Õ¸Ö€Õ«Õ¹</translation>
<translation id="1818308510395330587"><ph name="APP_NAME" />-Õ«Õ¶ AR Õ¼Õ¥ÕªÕ«Õ´Õ¶ Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¥Õ¬Õ¸Ö‚ Õ©Õ¸Ö‚ÕµÕ¬Õ¿Õ¾Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶ Õ¿Õ¡Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€ Õ´Õ«Õ¡ÖÖ€Õ¥Ö„ Õ¶Õ¡Ö‡ Õ¿Õ¥Õ½Õ¡Õ­ÖÕ«Õ¯Õ¨ <ph name="BEGIN_LINK" />Android-Õ« Õ¯Õ¡Ö€Õ£Õ¡Õ¾Õ¸Ö€Õ¸Ö‚Õ´Õ¶Õ¥Ö€Õ¸Ö‚Õ´<ph name="END_LINK" />Ö‰</translation>
<translation id="1864927262126810325">Ô±Õ²Õ¢ÕµÕ¸Ö‚Ö€Õ¨Õ <ph name="SOURCE_NAME" /></translation>
@@ -42,17 +43,20 @@
<translation id="2030769033451695672">Õ€ÕºÕ¥Ö„Õ <ph name="URL_OF_THE_CURRENT_TAB" /> Õ¾Õ¥Ö€Õ¡Õ¤Õ¡Õ¼Õ¶Õ¡Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€</translation>
<translation id="2079545284768500474">Õ€Õ¥Õ¿Õ¡Ö€Õ¯Õ¥Õ¬</translation>
<translation id="2091887806945687916">ÕÕ¡ÕµÕ¶</translation>
-<translation id="2107397443965016585">Õ€Õ¡Ö€ÖÕ¶Õ¥Õ¬Õ Õ¶Õ¡Õ­Ö„Õ¡Õ¶ Õ©Õ¸Ö‚ÕµÕ¬Õ¡Õ¿Ö€Õ¥Õ¬Õ¨ Õ¯Õ¡ÕµÖ„Õ¥Ö€Õ«Õ¶ Õ¶Õ¾Õ¡Õ£Õ¡Ö€Õ¯Õ¥Õ¬ ÕºÕ¡Õ·Õ¿ÕºÕ¡Õ¶Õ¾Õ¡Õ® Õ¢Õ¸Õ¾Õ¡Õ¶Õ¤Õ¡Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶ (Õ­Õ¸Ö€Õ°Õ¸Ö‚Ö€Õ¤ Õ§ Õ¿Ö€Õ¾Õ¸Ö‚Õ´)</translation>
+<translation id="2107397443965016585">Õ€Õ¡Ö€ÖÕ¶Õ¥Õ¬ Õ¶Õ¡Õ­Ö„Õ¡Õ¶ Õ©Õ¸Ö‚ÕµÕ¬Õ¡Õ¿Ö€Õ¥Õ¬Õ¨ Õ¯Õ¡ÕµÖ„Õ¥Ö€Õ«Õ¶ Õ¶Õ¾Õ¡Õ£Õ¡Ö€Õ¯Õ¥Õ¬ ÕºÕ¡Õ·Õ¿ÕºÕ¡Õ¶Õ¾Õ¡Õ® Õ¢Õ¸Õ¾Õ¡Õ¶Õ¤Õ¡Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶ (Õ­Õ¸Ö€Õ°Õ¸Ö‚Ö€Õ¤ Õ§ Õ¿Ö€Õ¾Õ¸Ö‚Õ´)</translation>
<translation id="2146738493024040262">Ô²Õ¡ÖÕ¥Õ¬ Õ¡Õ¯Õ¶Õ©Õ¡Ö€Õ©Õ¡ÕµÕ«Õ¶ Õ°Õ¡Õ¾Õ¥Õ¬Õ¾Õ¡Õ®Õ¨</translation>
<translation id="2148716181193084225">Ô±ÕµÕ½Ö…Ö€</translation>
<translation id="2182457891543959921">Ô¿Õ¡ÕµÖ„Õ¥Ö€Õ« Õ°Õ¡Õ´Õ¡Ö€ Õ©Õ¸Ö‚ÕµÕ¬Õ¿Õ¾Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶ Õ­Õ¶Õ¤Ö€Õ¥Õ¬Õ Õ½Õ¿Õ¥Õ²Õ®Õ¥Õ¬Õ¸Ö‚ Õ·Ö€Õ»Õ¡Õ¯Õ¡ÕµÖ„Õ« Õ¥Õ¼Õ¡Õ¹Õ¡Öƒ Ö„Õ¡Ö€Õ¿Õ¥Õ¦Õ¶ Õ¸Ö‚ Õ°Õ¥Õ¿Õ¡Õ£Õ®Õ¥Õ¬Õ¸Ö‚ Õ±Õ¥Ö€ Õ¿Õ¥Õ½Õ¡Õ­ÖÕ«Õ¯Õ« Õ¤Õ«Ö€Ö„Õ¨ (Õ­Õ¸Ö€Õ°Õ¸Ö‚Ö€Õ¤ Õ§ Õ¿Ö€Õ¾Õ¸Ö‚Õ´)</translation>
<translation id="2212565012507486665">Ô¹Õ¸Ö‚ÕµÕ¬Õ¡Õ¿Ö€Õ¥Õ¬ Ö„Õ¸Ö‚Ö„Õ«Õ¶Õ¥Ö€Õ¨</translation>
<translation id="2228071138934252756">ÕˆÖ€ÕºÕ¥Õ½Õ¦Õ« Õ¿Õ¥Õ½Õ¡Õ­ÖÕ«Õ¯Õ¨ Õ°Õ¡Õ½Õ¡Õ¶Õ¥Õ¬Õ« Õ¤Õ¡Õ¼Õ¶Õ¡ <ph name="APP_NAME" />-Õ«Õ¶, Õ´Õ«Õ¡ÖÖ€Õ¥Ö„ Õ¡ÕµÕ¶ <ph name="BEGIN_LINK" />Android-Õ« Õ¯Õ¡Ö€Õ£Õ¡Õ¾Õ¸Ö€Õ¸Ö‚Õ´Õ¶Õ¥Ö€Õ¸Ö‚Õ´<ph name="END_LINK" />Ö‰</translation>
<translation id="2241634353105152135">Õ„Õ«Õ¡ÕµÕ¶ Õ¡ÕµÕ½ Õ¡Õ¶Õ£Õ¡Õ´</translation>
+<translation id="2253414712144136228">Õ€Õ¥Õ¼Õ¡ÖÕ¶Õ¥Õ¬ «<ph name="NAME_OF_LIST_ITEM" />» Õ¯Õ¥Õ¿Õ¨</translation>
<translation id="2289270750774289114">Õ€Õ¡Ö€ÖÕ¶Õ¥Õ¬, Õ¥Ö€Õ¢ Õ¸Ö€Ö‡Õ§ Õ¯Õ¡ÕµÖ„ Õ¸Ö‚Õ¦Õ¸Ö‚Õ´ Õ§ Õ°Õ¡ÕµÕ¿Õ¶Õ¡Õ¢Õ¥Ö€Õ¥Õ¬ Õ´Õ¸Õ¿Õ¡Õ¯Õ¡ Bluetooth Õ½Õ¡Ö€Ö„Õ¥Ö€Õ¨ (Õ­Õ¸Ö€Õ°Õ¸Ö‚Ö€Õ¤ Õ§ Õ¿Ö€Õ¾Õ¸Ö‚Õ´)</translation>
<translation id="2315043854645842844">ÕÕ¾ÕµÕ¡Õ¬ Ö…ÕºÕ¥Ö€Õ¡ÖÕ«Õ¸Õ¶ Õ°Õ¡Õ´Õ¡Õ¯Õ¡Ö€Õ£Õ¨ Õ¹Õ« Õ¡Õ»Õ¡Õ¯ÖÕ¸Ö‚Õ´ Õ½ÕºÕ¡Õ½Õ¡Õ¼Õ¸Ö‚Õ« Õ¯Õ¸Õ²Õ´Õ«Ö Õ¾Õ¯Õ¡ÕµÕ¡Õ£Ö€Õ« Õ¨Õ¶Õ¿Ö€Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¨:</translation>
+<translation id="2321958826496381788">Õ”Õ¡Õ·Õ¥Ö„ Õ½Õ¡Õ°Õ«Õ¹Õ¶ Õ¡ÕµÕ¶ÕºÕ¥Õ½, Õ¸Ö€ Õ°Õ¡Ö€Õ´Õ¡Ö€Õ¡Õ¾Õ¥Õ¿ Õ¬Õ«Õ¶Õ« Õ¯Õ¡Ö€Õ¤Õ¡Õ¬Õ¨: ÕŠÕ¡Ö€Õ¢Õ¥Ö€Õ¸Ö‚Õ©ÕµÕ¡Õ¶ Õ¾Ö€Õ¡ Õ¥Ö€Õ¯Õ¸Ö‚ Õ¡Õ¶Õ£Õ¡Õ´ Õ½Õ¥Õ²Õ´Õ¥Õ¬Õ¸Ö‚Ö Õ°Õ¥Õ¿Õ¸ Õ¿Õ¥Ö„Õ½Õ¿Õ¨ ÕºÕ¥Õ¿Ö„ Õ§ Õ¡ÕµÕ½ÕºÕ«Õ½Õ« Õ¹Õ¡Öƒ Õ¸Ö‚Õ¶Õ¥Õ¶Õ¡:</translation>
<translation id="2359808026110333948">Õ‡Õ¡Ö€Õ¸Ö‚Õ¶Õ¡Õ¯Õ¥Õ¬</translation>
<translation id="2379925928934107488">Ô¿Õ¡ÕµÖ„Õ¥Ö€Õ¸Ö‚Õ´ Õ°Õ¶Õ¡Ö€Õ¡Õ¾Õ¸Ö€Õ«Õ¶Õ½ Õ¯Õ«Ö€Õ¡Õ¼Õ¥Õ¬ Õ´Õ¸Ö‚Õ£ Õ©Õ¥Õ´Õ¡Õ¶, Õ¥Ö€Õ¢ Chrome-Õ¶ Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¸Ö‚Õ´ Õ§ Õ¡ÕµÕ¶</translation>
+<translation id="2387895666653383613">ÕÕ¥Ö„Õ½Õ¿Õ« Õ¹Õ¡ÖƒÕ¡ÖƒÕ¸Õ­Õ¸Ö‚Õ´</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> Õ„Ô²</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Ô¹Õ¸Ö‚ÕµÕ¬Õ¡Õ¿Ö€Õ¾Õ¡Õ® Õ¥Õ¶Õ Â«<ph name="PERMISSION_1" />», «<ph name="PERMISSION_2" />» Õ¸Ö‚ Ö‡Õ½ <ph name="NUM_MORE" /> Õ©Õ¸Ö‚ÕµÕ¬Õ¿Õ¾Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶}one{Ô¹Õ¸Ö‚ÕµÕ¬Õ¡Õ¿Ö€Õ¾Õ¡Õ® Õ¥Õ¶Õ Â«<ph name="PERMISSION_1" />», «<ph name="PERMISSION_2" />» Õ¸Ö‚ Ö‡Õ½ <ph name="NUM_MORE" /> Õ©Õ¸Ö‚ÕµÕ¬Õ¿Õ¾Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶}other{Ô¹Õ¸Ö‚ÕµÕ¬Õ¡Õ¿Ö€Õ¾Õ¡Õ® Õ¥Õ¶Õ Â«<ph name="PERMISSION_1" />», «<ph name="PERMISSION_2" />» Õ¸Ö‚ Ö‡Õ½ <ph name="NUM_MORE" /> Õ©Õ¸Ö‚ÕµÕ¬Õ¿Õ¾Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶}}</translation>
<translation id="2434158240863470628">Õ†Õ¥Ö€Õ¢Õ¥Õ¼Õ¶Õ¸Ö‚Õ´Õ¶ Õ¡Õ¾Õ¡Ö€Õ¿Õ¾Õ¡Õ® Õ§Õ <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,13 +93,14 @@
<translation id="3115898365077584848">Õ‘Õ¸Ö‚ÖÕ¡Õ¤Ö€Õ¥Õ¬ Õ¿Õ¥Õ²Õ¥Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¨</translation>
<translation id="3123473560110926937">Ô±Ö€Õ£Õ¥Õ¬Õ¡ÖƒÕ¡Õ¯Õ¾Õ¡Õ® Õ§ Õ¸Ö€Õ¸Õ· Õ¯Õ¡ÕµÖ„Õ¥Ö€Õ¸Ö‚Õ´</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> ÕºÕ¡Õ°Õ¾Õ¡Õ® Õ¿Õ¾ÕµÕ¡Õ¬Õ¶Õ¥Ö€</translation>
+<translation id="3203366800380907218">Õ€Õ¡Õ´Õ¡ÖÕ¡Õ¶ÖÕ«Ö</translation>
<translation id="321187648315454507">ÕˆÖ€ÕºÕ¥Õ½Õ¦Õ« <ph name="APP_NAME" />-Õ«Õ¶ Õ©Õ¸Ö‚ÕµÕ¬Õ¡Õ¿Ö€Õ¥Ö„ Õ±Õ¥Õ¦ Õ®Õ¡Õ¶Õ¸Ö‚ÖÕ¸Ö‚Õ´Õ¶Õ¥Ö€ Õ¸Ö‚Õ²Õ¡Ö€Õ¯Õ¥Õ¬, Õ´Õ«Õ¡ÖÖ€Õ¥Ö„ Õ¶Õ¡Ö‡ Õ®Õ¡Õ¶Õ¸Ö‚ÖÕ¸Ö‚Õ´Õ¶Õ¥Ö€Õ¨ <ph name="BEGIN_LINK" />Android-Õ« Õ¯Õ¡Ö€Õ£Õ¡Õ¾Õ¸Ö€Õ¸Ö‚Õ´Õ¶Õ¥Ö€Õ¸Ö‚Õ´<ph name="END_LINK" />Ö‰</translation>
<translation id="3227137524299004712">Ô½Õ¸Õ½Õ¡ÖƒÕ¸Õ²</translation>
<translation id="3277252321222022663">Ô¹Õ¸Ö‚ÕµÕ¬ Õ¿Õ¡Õ¬ Õ¯Õ¡ÕµÖ„Õ¥Ö€Õ«Õ¶ Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¥Õ¬ Õ¿Õ¾Õ«Õ¹Õ¶Õ¥Ö€Õ¨ (Õ­Õ¸Ö€Õ°Õ¸Ö‚Ö€Õ¤ Õ§ Õ¿Ö€Õ¾Õ¸Ö‚Õ´)</translation>
<translation id="3295602654194328831">Ô¹Õ¡Ö„ÖÕ¶Õ¥Õ¬ Õ¿Õ¥Õ²Õ¥Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¨</translation>
<translation id="3328801116991980348">ÕÕ¥Õ²Õ¥Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€ Õ¯Õ¡ÕµÖ„Õ« Õ´Õ¡Õ½Õ«Õ¶</translation>
<translation id="3333961966071413176">Ô²Õ¸Õ¬Õ¸Ö€ Õ¯Õ¸Õ¶Õ¿Õ¡Õ¯Õ¿Õ¶Õ¥Ö€Õ¨</translation>
-<translation id="3386292677130313581">Õ€Õ¡Ö€ÖÕ¶Õ¥Õ¬Õ Õ¶Õ¡Õ­Ö„Õ¡Õ¶ Õ±Õ¥Ö€ Õ¿Õ¥Õ²Õ¡Õ¤Ö€Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¨ Õ¯Õ¡ÕµÖ„Õ¥Ö€Õ«Õ¶ Õ°Õ¡Õ½Õ¡Õ¶Õ¥Õ¬Õ« Õ¤Õ¡Ö€Õ±Õ¶Õ¥Õ¬Õ¨ (Õ­Õ¸Ö€Õ°Õ¸Ö‚Ö€Õ¤ Õ§ Õ¿Ö€Õ¾Õ¸Ö‚Õ´)</translation>
+<translation id="3386292677130313581">Õ€Õ¡Ö€ÖÕ¶Õ¥Õ¬ Õ¶Õ¡Õ­Ö„Õ¡Õ¶ Õ±Õ¥Ö€ Õ¿Õ¥Õ²Õ¡Õ¤Ö€Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¨ Õ¯Õ¡ÕµÖ„Õ¥Ö€Õ«Õ¶ Õ°Õ¡Õ½Õ¡Õ¶Õ¥Õ¬Õ« Õ¤Õ¡Ö€Õ±Õ¶Õ¥Õ¬Õ¨ (Õ­Õ¸Ö€Õ°Õ¸Ö‚Ö€Õ¤ Õ§ Õ¿Ö€Õ¾Õ¸Ö‚Õ´)</translation>
<translation id="3538390592868664640">Ô±Ö€Õ£Õ¥Õ¬Õ¥Õ¬ Õ¯Õ¡ÕµÖ„Õ¥Ö€Õ«Õ¶ Õ½Õ¿Õ¥Õ²Õ®Õ¥Õ¬ Õ·Ö€Õ»Õ¡Õ¯Õ¡ÕµÖ„Õ« Õ¥Õ¼Õ¡Õ¹Õ¡Öƒ Ö„Õ¡Ö€Õ¿Õ¥Õ¦Õ¨ Ö‡ Õ°Õ¥Õ¿Õ¡Õ£Õ®Õ¥Õ¬ Õ¿Õ¥Õ½Õ¡Õ­ÖÕ«Õ¯Õ« Õ¤Õ«Ö€Ö„Õ¨</translation>
<translation id="3551268116566418498">Ô´Õ¸Ö‚Ö€Õ½ Õ£Õ¡ÕžÕ¬ Õ«Õ¶Õ¯Õ¸Õ£Õ¶Õ«Õ¿Õ¸ Õ¼Õ¥ÕªÕ«Õ´Õ«Ö</translation>
<translation id="3586500876634962664">ÕÕ¥Õ½Õ¡Õ­ÖÕ«Õ¯Õ« Ö‡ Õ­Õ¸Õ½Õ¡ÖƒÕ¸Õ²Õ« Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¸Ö‚Õ´</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">ÕÕ¡Ö€Ö„Õ« Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¸Ö‚Õ´</translation>
<translation id="385051799172605136">Õ€Õ¥Õ¿</translation>
<translation id="3859306556332390985">ÕˆÖ€Õ¸Õ¶Õ¥Õ¬ Õ¤Õ¥ÕºÕ« Õ¡Õ¼Õ¡Õ»</translation>
+<translation id="3895926599014793903">Õ€Õ¡Ö€Õ¯Õ¡Õ¤Ö€Õ¡Õ¢Õ¡Ö€ Õ´Õ«Õ¡ÖÕ¶Õ¥Õ¬ Õ¹Õ¡ÖƒÕ¡ÖƒÕ¸Õ­Õ¸Ö‚Õ´Õ¨</translation>
<translation id="3955193568934677022">Ô¹Õ¸Ö‚ÕµÕ¬ Õ¿Õ¡Õ¬ Õ¯Õ¡ÕµÖ„Õ¥Ö€Õ«Õ¶ Õ¶Õ¾Õ¡Õ£Õ¡Ö€Õ¯Õ¥Õ¬ ÕºÕ¡Õ·Õ¿ÕºÕ¡Õ¶Õ¾Õ¡Õ® Õ¢Õ¸Õ¾Õ¡Õ¶Õ¤Õ¡Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¨ (Õ­Õ¸Ö€Õ°Õ¸Ö‚Ö€Õ¤ Õ§ Õ¿Ö€Õ¾Õ¸Ö‚Õ´)</translation>
<translation id="3967822245660637423">Õ†Õ¥Ö€Õ¢Õ¥Õ¼Õ¶Õ¸Ö‚Õ´Õ¶ Õ¡Õ¾Õ¡Ö€Õ¿Õ¾Õ¥Ö</translation>
<translation id="3987993985790029246">ÕŠÕ¡Õ¿Õ³Õ¥Õ¶Õ¥Õ¬ Õ°Õ²Õ¸Ö‚Õ´Õ¨</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" />/?</translation>
<translation id="4002066346123236978">ÕŽÕ¥Ö€Õ¶Õ¡Õ£Õ«Ö€</translation>
<translation id="4008040567710660924">Ô¹Õ¸Ö‚ÕµÕ¬Õ¡Õ¿Ö€Õ¥Õ¬ Ö„Õ¸Ö‚Ö„Õ«Õ¶Õ¥Ö€Õ¨ Õ¯Õ¸Õ¶Õ¯Ö€Õ¥Õ¿ Õ¯Õ¡ÕµÖ„Õ« Õ°Õ¡Õ´Õ¡Ö€:</translation>
+<translation id="4040330681741629921">ÕÕ¿Õ¡Õ¶Õ¡Õ¬ Õ®Õ¡Õ¶Õ¸Ö‚ÖÕ¸Ö‚Õ´, Õ¥Ö€Õ¢ Õ¯Õ¡ÕµÖ„Õ¨ Õ°Õ¶Õ¡Ö€Õ¡Õ¾Õ¸Ö€ Õ¬Õ«Õ¶Õ« Õ¤Õ«Õ¿Õ¥Õ¬ ÕºÕ¡Ö€Õ¦Õ¥ÖÕ¾Õ¡Õ® Õ¿Õ¥Õ½Ö„Õ¸Õ¾</translation>
<translation id="4046123991198612571">Õ€Õ¡Õ»Õ¸Ö€Õ¤Õ¨</translation>
+<translation id="4149994727733219643">Ô¿Õ¡ÕµÖ„Õ¥Ö€Õ« ÕºÕ¡Ö€Õ¦Õ¥ÖÕ¾Õ¡Õ® Õ¤Õ«Õ¿Õ¡Õ¯Õ¥Ö€Õº</translation>
<translation id="4165986682804962316">Ô¿Õ¡ÕµÖ„Õ« Õ¯Õ¡Ö€Õ£Õ¡Õ¾Õ¸Ö€Õ¸Ö‚Õ´Õ¶Õ¥Ö€</translation>
+<translation id="4194328954146351878">Ô¿Õ¡ÕµÖ„Õ¥Ö€Õ« Õ°Õ¡Õ´Õ¡Ö€ Õ©Õ¸Ö‚ÕµÕ¬Õ¿Õ¾Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶ Õ­Õ¶Õ¤Ö€Õ¥Õ¬Õ Õ¿Õ¥Õ½Õ¶Õ¥Õ¬Õ¸Ö‚ Ö‡ ÖƒÕ¸ÖƒÕ¸Õ­Õ¥Õ¬Õ¸Ö‚ Õ¿Õ¥Õ²Õ¥Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¨ NFC Õ½Õ¡Ö€Ö„Õ¥Ö€Õ¸Ö‚Õ´ (Õ­Õ¸Ö€Õ°Õ¸Ö‚Ö€Õ¤ Õ§ Õ¿Ö€Õ¾Õ¸Ö‚Õ´)</translation>
<translation id="4200726100658658164">Ô²Õ¡ÖÕ¥Õ¬ Õ¿Õ¥Õ²Õ¡Õ¤Ö€Õ¸Ö‚Õ©ÕµÕ¡Õ¶ Õ¯Õ¡Ö€Õ£Õ¡Õ¾Õ¸Ö€Õ¸Ö‚Õ´Õ¶Õ¥Ö€Õ¨</translation>
<translation id="4226663524361240545">Ô¾Õ¡Õ¶Õ¸Ö‚ÖÕ¸Ö‚Õ´Õ¶Õ¥Ö€Õ« ÕªÕ¡Õ´Õ¡Õ¶Õ¡Õ¯ Õ½Õ¡Ö€Ö„Õ¨ Õ¯Õ©Ö€Õ©Õ¼Õ¡</translation>
<translation id="4259722352634471385">Õ†Õ¡Õ¾Õ«Õ£Õ¡ÖÕ«Õ¡Õ¶ Õ¡Ö€Õ£Õ¥Õ¬Õ¡ÖƒÕ¡Õ¯Õ¾Õ¡Õ® Õ§Õ <ph name="URL" /></translation>
@@ -126,10 +135,11 @@
<translation id="42981349822642051">Ô¸Õ¶Õ¤Õ¡Ö€Õ±Õ¡Õ¯Õ¥Õ¬</translation>
<translation id="4336434711095810371">Õ„Õ¡Ö„Ö€Õ¥Õ¬ Õ¢Õ¸Õ¬Õ¸Ö€ Õ¿Õ¾ÕµÕ¡Õ¬Õ¶Õ¥Ö€Õ¨</translation>
<translation id="4402755511846832236">Ô±Ö€Õ£Õ¥Õ¬Õ¥Õ¬ Õ¯Õ¡ÕµÖ„Õ¥Ö€Õ«Õ¶ Õ¿Õ¥Õ²Õ¥Õ¯Õ¡Õ¶Õ¡Õ¬, Õ¥Ö€Õ¢ Õ¤Õ¸Ö‚Ö„ Õ¡Õ¯Õ¿Õ«Õ¾Õ¸Ö€Õ¥Õ¶ Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¸Ö‚Õ´ Õ¥Ö„ Õ¡ÕµÕ½ Õ½Õ¡Ö€Ö„Õ¨</translation>
+<translation id="4428065317363009941">Ô³Õ¸Õ¾Õ¡Õ¦Õ¤Õ« Õ¡Õ¶Õ°Õ¡Õ¿Õ¡Õ¯Õ¡Õ¶Õ¡ÖÕ¸Ö‚Õ´</translation>
<translation id="4434045419905280838">ÔµÕ¬Õ¶Õ¸Õ² ÕºÕ¡Õ¿Õ¸Ö‚Õ°Õ¡Õ¶Õ¶Õ¥Ö€ Ö‡ Õ¾Õ¥Ö€Õ¡Õ°Õ²Õ¸Ö‚Õ´</translation>
<translation id="445467742685312942">Ô¹Õ¸Ö‚ÕµÕ¬Õ¡Õ¿Ö€Õ¥Õ¬ Õ¯Õ¡ÕµÖ„Õ¥Ö€Õ«Õ¶ Õ¶Õ¾Õ¡Õ£Õ¡Ö€Õ¯Õ¥Õ¬ ÕºÕ¡Õ·Õ¿ÕºÕ¡Õ¶Õ¾Õ¡Õ® Õ¢Õ¸Õ¾Õ¡Õ¶Õ¤Õ¡Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶</translation>
<translation id="4468959413250150279">Ô±Õ¶Õ»Õ¡Õ¿Õ¥Õ¬ Õ±Õ¡ÕµÕ¶Õ¨ Õ¡Õ¼Õ¡Õ¶Õ±Õ«Õ¶ Õ¯Õ¡ÕµÖ„Õ¥Ö€Õ¸Ö‚Õ´</translation>
-<translation id="4479647676395637221">Õ€Õ¡Ö€ÖÕ¶Õ¥Õ¬Õ Õ¶Õ¡Õ­Ö„Õ¡Õ¶ Õ±Õ¥Ö€ Õ¿Õ¥Õ½Õ¡Õ­ÖÕ«Õ¯Õ¨ Õ¯Õ¡ÕµÖ„Õ¥Ö€Õ«Õ¶ Õ°Õ¡Õ½Õ¡Õ¶Õ¥Õ¬Õ« Õ¤Õ¡Ö€Õ±Õ¶Õ¥Õ¬Õ¨ (Õ­Õ¸Ö€Õ°Õ¸Ö‚Ö€Õ¤ Õ§ Õ¿Ö€Õ¾Õ¸Ö‚Õ´)</translation>
+<translation id="4479647676395637221">Õ€Õ¡Ö€ÖÕ¶Õ¥Õ¬ Õ¶Õ¡Õ­Ö„Õ¡Õ¶ Õ±Õ¥Ö€ Õ¿Õ¥Õ½Õ¡Õ­ÖÕ«Õ¯Õ¨ Õ¯Õ¡ÕµÖ„Õ¥Ö€Õ«Õ¶ Õ°Õ¡Õ½Õ¡Õ¶Õ¥Õ¬Õ« Õ¤Õ¡Ö€Õ±Õ¶Õ¥Õ¬Õ¨ (Õ­Õ¸Ö€Õ°Õ¸Ö‚Ö€Õ¤ Õ§ Õ¿Ö€Õ¾Õ¸Ö‚Õ´)</translation>
<translation id="4505788138578415521">URL-Õ¨ Õ®Õ¡Õ¾Õ¡Õ¬Õ¾Õ¥Õ¬ Õ§</translation>
<translation id="4534723447064627427">ÕˆÖ€ÕºÕ¥Õ½Õ¦Õ« Õ­Õ¸Õ½Õ¡ÖƒÕ¸Õ²Õ¨ Õ°Õ¡Õ½Õ¡Õ¶Õ¥Õ¬Õ« Õ¤Õ¡Õ¼Õ¶Õ¡ <ph name="APP_NAME" />-Õ«Õ¶, Õ´Õ«Õ¡ÖÖ€Õ¥Ö„ Õ¡ÕµÕ¶ <ph name="BEGIN_LINK" />Android-Õ« Õ¯Õ¡Ö€Õ£Õ¡Õ¾Õ¸Ö€Õ¸Ö‚Õ´Õ¶Õ¥Ö€Õ¸Ö‚Õ´<ph name="END_LINK" />Ö‰</translation>
<translation id="4570913071927164677">Õ„Õ¡Õ¶Ö€Õ¡Õ´Õ¡Õ½Õ¶Õ¥Ö€</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">Ô³Õ¸Ö€Õ®Õ¸Õ²Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¨ Õ°Õ¡Õ½Õ¡Õ¶Õ¥Õ¬Õ« Õ§ Õ§Õ¯Ö€Õ¡Õ¶Õ« Õ¾Õ¥Ö€Õ«Õ¶ Õ´Õ¡Õ½Õ¸Ö‚Õ´</translation>
<translation id="5197729504361054390">ÕÕ¥Ö€ Õ¨Õ¶Õ¿Ö€Õ¡Õ® Õ¯Õ¸Õ¶Õ¿Õ¡Õ¯Õ¿Õ¶Õ¥Ö€Õ¨ Õ°Õ¡Õ½Õ¡Õ¶Õ¥Õ¬Õ« Õ¯Õ¤Õ¡Õ¼Õ¶Õ¡Õ¶ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> Õ¯Õ¡ÕµÖ„Õ«Õ¶:</translation>
<translation id="5216942107514965959">ÕŽÕ¥Ö€Õ»Õ«Õ¶ Õ¡ÕµÖÕ¥Õ¬Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¨Õ Õ¡ÕµÕ½Ö…Ö€</translation>
+<translation id="5264323282659631142">Õ€Õ¥Õ¼Õ¡ÖÕ¶Õ¥Õ¬ «<ph name="CHIP_LABEL" />» Õ¹Õ«ÕºÕ¨</translation>
<translation id="528192093759286357">Ô¼Õ«Õ¡Õ§Õ¯Ö€Õ¡Õ¶ Õ¼Õ¥ÕªÕ«Õ´Õ«Ö Õ¤Õ¸Ö‚Ö€Õ½ Õ£Õ¡Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€ Ö„Õ¡Õ·Õ¥Ö„ Õ¾Õ¥Ö€Ö‡Õ«Ö Ö‡ Õ°ÕºÕ¥Ö„ «Հետ» Õ¯Õ¸Õ³Õ¡Õ¯Õ«Õ¶:</translation>
<translation id="5300589172476337783">Õ‘Õ¸Ö‚ÕµÖ Õ¿Õ¡Õ¬</translation>
<translation id="5301954838959518834">ÕŠÕ¡Ö€Õ¦ Õ§</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">Ô¿Õ¡ÕµÖ„Õ¥Ö€Õ« ÕºÕ¡Õ°Õ¡Õ® <ph name="DATASIZE" /> Õ®Õ¡Õ¾Õ¡Õ¬Õ¸Õ¾ Õ¿Õ¾ÕµÕ¡Õ¬Õ¶Õ¥Ö€Õ¶ Õ¸Ö‚ Ö„Õ¸Ö‚Ö„Õ«Õ¶Õ¥Ö€Õ¨ Õ¯Õ»Õ¶Õ»Õ¾Õ¥Õ¶Ö‰</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(Õ¸Ö‚ Ö‡Õ½ 1)}one{(Õ¸Ö‚ Ö‡Õ½ #)}other{(Õ¸Ö‚ Ö‡Õ½ #)}}</translation>
<translation id="5403592356182871684">Ô±Õ¶Õ¸Ö‚Õ¶Õ¶Õ¥Ö€</translation>
+<translation id="5412236728747081950">Ô±ÕµÕ½ Õ¯Õ¡ÕµÖ„Õ¨ Chrome-Õ«Ö Õ½Õ¿Õ¡Õ¶Õ¸Ö‚Õ´ Õ§ Õ±Õ¥Õ¦ Õ°Õ¥Õ¿Õ¡Ö„Ö€Ö„Ö€Õ¸Õ² Õ©Õ¥Õ´Õ¡Õ¶Õ¥Ö€Õ« Õ´Õ¡Õ½Õ«Õ¶ Õ¿Õ¾ÕµÕ¡Õ¬Õ¶Õ¥Ö€Õ Õ¡Õ¾Õ¥Õ¬Õ« Õ°Õ¡Õ´Õ¡ÕºÕ¡Õ¿Õ¡Õ½Õ­Õ¡Õ¶ Õ£Õ¸Õ¾Õ¡Õ¦Õ¤ ÖÕ¸Ö‚ÖÕ¡Õ¤Ö€Õ¥Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€</translation>
<translation id="5438097262470833822">Ô±ÕµÕ½ Õ¯Õ¡ÕµÖ„Õ« (<ph name="WEBSITE" />) Õ©Õ¸Ö‚ÕµÕ¬Õ¿Õ¾Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¨ Õ¯Õ¦Ö€Õ¸ÕµÕ¡ÖÕ¾Õ¥Õ¶</translation>
<translation id="5489227211564503167">Ô±Õ¶ÖÕ¡Õ® ÕªÕ¡Õ´Õ¡Õ¶Õ¡Õ¯Õ¨Õ <ph name="ELAPSED_TIME" />/<ph name="TOTAL_TIME" />Ö‰</translation>
<translation id="5494752089476963479">Ô±Ö€Õ£Õ¥Õ¬Õ¡ÖƒÕ¡Õ¯Õ¥Õ¬ Õ£Õ¸Õ¾Õ¡Õ¦Õ¤Õ¨ Õ¯Õ¡ÕµÖ„Õ¥Ö€Õ¸Ö‚Õ´, Õ¸Ö€Õ¸Õ¶Ö„ Õ°Õ¸Õ£Õ¶Õ¥ÖÕ¶Õ¸Õ² Õ¯Õ¡Õ´ Õ´Õ¸Õ¬Õ¸Ö€Õ¥ÖÕ¶Õ¸Õ² Õ£Õ¸Õ¾Õ¡Õ¦Õ¤ Õ¥Õ¶ ÖÕ¸Ö‚ÖÕ¡Õ¤Ö€Õ¸Ö‚Õ´</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">ÕŽÕ¥Ö€Õ¡Õ¢Õ¥Õ¼Õ¶Õ¥Õ¬</translation>
<translation id="5596627076506792578">Ô¼Ö€Õ¡ÖÕ¸Ö‚ÖÕ«Õ¹ Õ¨Õ¶Õ¿Ö€Õ¡Õ¶Ö„Õ¶Õ¥Ö€</translation>
<translation id="5649053991847567735">Ô±Õ¾Õ¿Õ¸Õ´Õ¡Õ¿ Õ¶Õ¥Ö€Õ¢Õ¥Õ¼Õ¶Õ¸Ö‚Õ´Õ¶Õ¥Ö€</translation>
+<translation id="5668404140385795438">Ô±Õ¶Õ¿Õ¥Õ½Õ¥Õ¬ Õ¯Õ¡ÕµÖ„Õ¥Ö€Õ«Õ Õ­Õ¸Õ·Õ¸Ö€Õ¡ÖÕ¸Ö‚Õ´Õ¨ Õ¯Õ¡Õ¶Õ­Õ¥Õ¬Õ¸Ö‚ Õ°Õ¡Ö€ÖÕ¸Ö‚Õ´Õ¶Õ¥Ö€Õ¨</translation>
<translation id="5677928146339483299">Ô±Ö€Õ£Õ¥Õ¬Õ¡ÖƒÕ¡Õ¯Õ¾Õ¡Õ® Õ§</translation>
<translation id="5689516760719285838">ÕÕ¥Õ²Õ¸Ö€Õ¸Õ·Õ¸Ö‚Õ´</translation>
<translation id="5690795753582697420">ÕÕ¥Õ½Õ¡Õ­ÖÕ«Õ¯Õ¶ Õ¡Õ¶Õ»Õ¡Õ¿Õ¾Õ¡Õ® Õ§ Android-Õ« Õ¯Õ¡Ö€Õ£Õ¡Õ¾Õ¸Ö€Õ¸Ö‚Õ´Õ¶Õ¥Ö€Õ¸Ö‚Õ´</translation>
-<translation id="5710871682236653961">Õ€Õ¡Ö€ÖÕ¶Õ¥Õ¬Õ Õ¶Õ¡Õ­Ö„Õ¡Õ¶ Õ©Õ¸Ö‚ÕµÕ¬Õ¡Õ¿Ö€Õ¥Õ¬Õ¨ Õ¯Õ¡ÕµÖ„Õ¥Ö€Õ«Õ¶ Õ¸Ö‚Õ²Õ¡Ö€Õ¯Õ¥Õ¬ Ö‡ Õ½Õ¿Õ¡Õ¶Õ¡Õ¬ Õ¿Õ¥Õ²Õ¥Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€, Õ¥Ö€Õ¢ Õ°ÕºÕ¸Ö‚Õ´ Õ¥Ö„ NFC Õ½Õ¡Ö€Ö„Õ¥Ö€Õ«Õ¶ (Õ­Õ¸Ö€Õ°Õ¸Ö‚Ö€Õ¤ Õ§ Õ¿Ö€Õ¾Õ¸Ö‚Õ´)</translation>
<translation id="5719847187258001597">Ô¿Õ»Õ¶Õ»Õ¾Õ¥Õ¶ Õ¢Õ¸Õ¬Õ¸Ö€ Õ¿Õ¾ÕµÕ¡Õ¬Õ¶Õ¥Ö€Õ¶ Õ¸Ö‚ Ö„Õ¸Ö‚Ö„Õ«Õ¶Õ¥Ö€Õ¨, Õ¸Ö€Õ¸Õ¶Ö„ Õ°Õ«Õ´Õ¶Õ¡Õ¯Õ¡Õ¶ Õ§Õ¯Ö€Õ¡Õ¶Õ«Õ¶ Õ¥Õ¶ ÕºÕ¡Õ°Õ¾Õ¥Õ¬ <ph name="ORIGIN" /> Õ¯Õ¡ÕµÖ„Õ« Ö‡ Õ¤Ö€Õ¡ Õ°Õ¡Õ¾Õ¥Õ¬Õ¾Õ¡Õ®Õ« Õ¯Õ¸Õ²Õ´Õ«ÖÖ‰</translation>
<translation id="5771720122942595109">Ô±Ö€Õ£Õ¥Õ¬Õ¡ÖƒÕ¡Õ¯Õ¾Õ¡Õ® Õ§Õ Â«<ph name="PERMISSION_1" />»</translation>
<translation id="5804241973901381774">Ô¹Õ¸Ö‚ÕµÕ¬Õ¿Õ¾Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">Õ†Õ¾Õ¡Õ£Õ¡Ö€Õ¯Õ¥Õ¬</translation>
<translation id="6818926723028410516">Ô¸Õ¶Õ¿Ö€Õ¥Ö„ Õ¿Õ¡Ö€Ö€Õ¥Ö€</translation>
<translation id="6864395892908308021">Ô±ÕµÕ½ Õ½Õ¡Ö€Ö„Õ¸Ö‚Õ´ NFC-Õ¶ Õ¹Õ« Õ¡Õ»Õ¡Õ¯ÖÕ¾Õ¸Ö‚Õ´</translation>
-<translation id="6910211073230771657">Õ‹Õ¶Õ»Õ¾Õ¡Õ®</translation>
<translation id="6912998170423641340">Ô±Ö€Õ£Õ¥Õ¬Õ¡ÖƒÕ¡Õ¯Õ¥Õ¬ Õ½Õ¥Õ²Õ´Õ¡Õ¿Õ¡Õ­Õ¿Õ¡Õ¯Õ« Õ¿Õ¥Ö„Õ½Õ¿Õ¥Ö€Õ« Õ¸Ö‚ ÕºÕ¡Õ¿Õ¯Õ¥Ö€Õ¶Õ¥Ö€Õ« Õ°Õ¡Õ½Õ¡Õ¶Õ¥Õ¬Õ«Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¨ Õ¯Õ¡ÕµÖ„Õ¥Ö€Õ«Õ¶</translation>
<translation id="6945221475159498467">Ô¸Õ¶Õ¿Ö€Õ¥Õ¬</translation>
<translation id="6965382102122355670">ÔµÕ²Õ¡Õ¾</translation>
-<translation id="6992289844737586249">Õ€Õ¡Ö€ÖÕ¶Õ¥Õ¬Õ Õ¶Õ¡Õ­Ö„Õ¡Õ¶ Õ±Õ¥Ö€ Õ­Õ¸Õ½Õ¡ÖƒÕ¸Õ²Õ¨ Õ¯Õ¡ÕµÖ„Õ¥Ö€Õ«Õ¶ Õ°Õ¡Õ½Õ¡Õ¶Õ¥Õ¬Õ« Õ¤Õ¡Ö€Õ±Õ¶Õ¥Õ¬Õ¨ (Õ­Õ¸Ö€Õ°Õ¸Ö‚Ö€Õ¤ Õ§ Õ¿Ö€Õ¾Õ¸Ö‚Õ´)</translation>
+<translation id="6981982820502123353">Õ„Õ¡Õ¿Õ¹Õ¥Õ¬Õ«Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¨</translation>
+<translation id="6992289844737586249">Õ€Õ¡Ö€ÖÕ¶Õ¥Õ¬ Õ¶Õ¡Õ­Ö„Õ¡Õ¶ Õ±Õ¥Ö€ Õ­Õ¸Õ½Õ¡ÖƒÕ¸Õ²Õ¨ Õ¯Õ¡ÕµÖ„Õ¥Ö€Õ«Õ¶ Õ°Õ¡Õ½Õ¡Õ¶Õ¥Õ¬Õ« Õ¤Õ¡Ö€Õ±Õ¶Õ¥Õ¬Õ¨ (Õ­Õ¸Ö€Õ°Õ¸Ö‚Ö€Õ¤ Õ§ Õ¿Ö€Õ¾Õ¸Ö‚Õ´)</translation>
<translation id="7000754031042624318">Ô±Õ¶Õ»Õ¡Õ¿Õ¾Õ¡Õ® Õ§ Android-Õ« Õ¯Õ¡Ö€Õ£Õ¡Õ¾Õ¸Ö€Õ¸Ö‚Õ´Õ¶Õ¥Ö€Õ¸Ö‚Õ´</translation>
<translation id="7016516562562142042">Ô¹Õ¸Ö‚ÕµÕ¬Õ¡Õ¿Ö€Õ¾Õ¡Õ® Õ§ Õ¨Õ¶Õ©Õ¡ÖÕ«Õ¯ Õ¸Ö€Õ¸Õ¶Õ«Õ¹Õ«Õ¶</translation>
+<translation id="702463548815491781">Ô½Õ¸Ö€Õ°Õ¸Ö‚Ö€Õ¤ Õ§ Õ¿Ö€Õ¾Õ¸Ö‚Õ´, Õ¥Ö€Õ¢ TalkBack-Õ¨ Õ¯Õ¡Õ´ Switch Access-Õ¨ Õ´Õ«Õ¡ÖÕ¾Õ¡Õ® Õ¥Õ¶</translation>
<translation id="7053983685419859001">Ô±Ö€Õ£Õ¥Õ¬Õ¡ÖƒÕ¡Õ¯Õ¥Õ¬</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1 Õ¨Õ¶Õ¿Ö€Õ¾Õ¡Õ® Õ¿Õ¡Ö€Ö€}one{# Õ¨Õ¶Õ¿Ö€Õ¾Õ¡Õ® Õ¿Õ¡Ö€Ö€}other{# Õ¨Õ¶Õ¿Ö€Õ¾Õ¡Õ® Õ¿Õ¡Ö€Ö€}}</translation>
-<translation id="7070090581017165256">Ô±ÕµÕ½ Õ¯Õ¡ÕµÖ„Õ« Õ´Õ¡Õ½Õ«Õ¶</translation>
<translation id="7087918508125750058">Ô¸Õ¶Õ¿Ö€Õ¾Õ¡Õ® Õ§ <ph name="ITEM_COUNT" /> Õ¿Õ¡Ö€Ö€Ö‰ Ô¸Õ¶Õ¿Ö€Õ¡Õ¶Ö„Õ¶Õ¥Ö€Õ¨ Õ°Õ¡Õ½Õ¡Õ¶Õ¥Õ¬Õ« Õ¥Õ¶ Õ§Õ¯Ö€Õ¡Õ¶Õ« Õ¾Õ¥Ö€Õ«Õ¶ Õ°Õ¡Õ¿Õ¾Õ¡Õ®Õ¸Ö‚Õ´</translation>
<translation id="7141896414559753902">Ô±Ö€Õ£Õ¥Õ¬Õ¡ÖƒÕ¡Õ¯Õ¥Õ¬ Õ¥Õ¬Õ¶Õ¸Õ² ÕºÕ¡Õ¿Õ¸Ö‚Õ°Õ¡Õ¶Õ¶Õ¥Ö€Õ¨ Ö‡ Õ¾Õ¥Ö€Õ¡Õ°Õ¡Õ½ÖÕ¥Õ¡Õ¾Õ¸Ö€Õ¸Ö‚Õ´Õ¨ Õ¯Õ¡ÕµÖ„Õ¥Ö€Õ¸Ö‚Õ´ (Õ­Õ¸Ö€Õ°Õ¸Ö‚Ö€Õ¤ Õ§ Õ¿Ö€Õ¾Õ¸Ö‚Õ´)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> Ô¿Ô²</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">Ô¿Õ¡ÕµÖ„Õ¶ Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¸Ö‚Õ´ Õ§ Õ±Õ¥Ö€ Õ­Õ¸Õ½Õ¡ÖƒÕ¸Õ²Õ¨</translation>
<translation id="7561196759112975576">Õ„Õ«Õ·Õ¿</translation>
-<translation id="7572498721684305250">Ô¹Õ¸Ö‚ÕµÕ¬ Õ¹Õ¿Õ¡Õ¬ Õ¯Õ¡ÕµÖ„Õ¥Ö€Õ«Õ¶ Õ¸Ö‚Õ²Õ¡Ö€Õ¯Õ¥Õ¬ Ö‡ Õ½Õ¿Õ¡Õ¶Õ¡Õ¬ Õ¿Õ¥Õ²Õ¥Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€, Õ¥Ö€Õ¢ Õ°ÕºÕ¸Ö‚Õ´ Õ¥Ö„ NFC Õ½Õ¡Ö€Ö„Õ¥Ö€Õ«Õ¶</translation>
<translation id="757524316907819857">Ô±Ö€Õ£Õ¥Õ¬Õ¥Õ¬ Õ¯Õ¡ÕµÖ„Õ¥Ö€Õ«Õ¶ ÕºÕ¡Õ·Õ¿ÕºÕ¡Õ¶Õ¾Õ¡Õ® Õ¢Õ¸Õ¾Õ¡Õ¶Õ¤Õ¡Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶ Õ¶Õ¾Õ¡Õ£Õ¡Ö€Õ¯Õ¥Õ¬</translation>
+<translation id="7577900504646297215">Ô¿Õ¡Õ¼Õ¡Õ¾Õ¡Ö€Õ¥Õ¬ Õ°Õ¥Õ¿Õ¡Ö„Ö€Ö„Ö€Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¨</translation>
<translation id="7649070708921625228">Õ•Õ£Õ¶Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶</translation>
<translation id="7658239707568436148">Õ‰Õ¥Õ²Õ¡Ö€Õ¯Õ¥Õ¬</translation>
<translation id="7781829728241885113">ÔµÖ€Õ¥Õ¯</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">Ô¿Õ¡ÕºÕ¶ Õ¡Õ¶Õ¾Õ¿Õ¡Õ¶Õ£ Õ§</translation>
<translation id="8249310407154411074">ÕÕ¥Õ²Õ¡ÖƒÕ¸Õ­Õ¥Õ¬ ÖÕ¡Õ¶Õ¯Õ« Õ½Õ¯Õ«Õ¦Õ¢</translation>
<translation id="8261506727792406068">Õ‹Õ¶Õ»Õ¥Õ¬</translation>
+<translation id="8284326494547611709">ÔµÕ¶Õ©Õ¡Õ£Ö€Õ¥Ö€</translation>
<translation id="8300705686683892304">Õ€Õ¡Õ¾Õ¥Õ¬Õ¾Õ¡Õ®Õ« Õ¯Õ¸Õ²Õ´Õ«Ö Õ¯Õ¡Õ¼Õ¡Õ¾Õ¡Ö€Õ¾Õ¸Õ²</translation>
<translation id="8324158725704657629">Õ†Õ¸Ö€Õ«Ö Õ¹Õ°Õ¡Ö€ÖÕ¶Õ¥Õ¬</translation>
<translation id="8372893542064058268">Ô¹Õ¸Ö‚ÕµÕ¬Õ¡Õ¿Ö€Õ¥Õ¬ Ö†Õ¸Õ¶Õ¡ÕµÕ«Õ¶ Õ°Õ¡Õ´Õ¡ÕªÕ¡Õ´Õ¡ÖÕ¸Ö‚Õ´Õ¨ Õ¶Õ·Õ¾Õ¡Õ® Õ¯Õ¡ÕµÖ„Õ¸Ö‚Õ´:</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">Ô½Õ¸Õ·Õ¸Ö€Õ¡ÖÕ¶Õ¥Õ¬</translation>
<translation id="8921772741368021346"><ph name="POSITION" />/<ph name="DURATION" /></translation>
<translation id="8926666909099850184">ÕÕ¡Ö€Ö„Õ« NFC-Õ¶ Õ¡Õ¶Õ»Õ¡Õ¿Õ¾Õ¡Õ® Õ§Ö‰ Õ„Õ«Õ¡ÖÖ€Õ¥Ö„ Õ¡ÕµÕ¶ <ph name="BEGIN_LINK" />Android-Õ« Õ¯Õ¡Ö€Õ£Õ¡Õ¾Õ¸Ö€Õ¸Ö‚Õ´Õ¶Õ¥Ö€Õ¸Ö‚Õ´<ph name="END_LINK" />Ö‰</translation>
+<translation id="8928445016601307354">Ô±Ö€Õ£Õ¥Õ¬Õ¥Õ¬ Õ¯Õ¡ÕµÖ„Õ¥Ö€Õ«Õ¶ Õ¿Õ¥Õ½Õ¶Õ¥Õ¬ Ö‡ ÖƒÕ¸ÖƒÕ¸Õ­Õ¥Õ¬ Õ¿Õ¥Õ²Õ¥Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¨ NFC Õ½Õ¡Ö€Ö„Õ¥Ö€Õ¸Ö‚Õ´</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">Ô±Ö€Õ£Õ¥Õ¬Õ¡ÖƒÕ¡Õ¯Õ¥Õ¬ Ö„Õ¸Ö‚Ö„Õ«Õ¶Õ¥Ö€Õ¨ Õ¯Õ¸Õ¶Õ¯Ö€Õ¥Õ¿ Õ¯Õ¡ÕµÖ„Õ« Õ°Õ¡Õ´Õ¡Ö€:</translation>
<translation id="8959122750345127698">Õ†Õ¡Õ¾Õ«Õ£Õ¡ÖÕ«Õ¡Õ¶ Õ¡Õ¶Õ°Õ¡Õ½Õ¡Õ¶Õ¥Õ¬Õ« Õ§Õ <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_id.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_id.xtb
index 872fd1829ec..404c2285987 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_id.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_id.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">Situs <ph name="SITE_NAME" /> ditambahkan</translation>
<translation id="1383876407941801731">Telusuri</translation>
<translation id="1384959399684842514">Download dijeda</translation>
+<translation id="1409426117486808224">Tampilan sederhana untuk tab yang terbuka</translation>
<translation id="1415402041810619267">URL dipotong</translation>
<translation id="1446450296470737166">Izinkan kontrol penuh perangkat MIDI</translation>
<translation id="1620510694547887537">Kamera</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">Izinkan cookie</translation>
<translation id="2228071138934252756">Untuk mengizinkan <ph name="APP_NAME" /> mengakses kamera Anda, aktifkan juga kamera di <ph name="BEGIN_LINK" />Setelan Android<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Sekali ini saja</translation>
+<translation id="2253414712144136228">Hapus <ph name="NAME_OF_LIST_ITEM" /></translation>
<translation id="2289270750774289114">Tanyakan saat situs ingin menemukan perangkat Bluetooth di sekitar (direkomendasikan)</translation>
<translation id="2315043854645842844">Pilihan sertifikat sisi klien tidak didukung oleh sistem operasi.</translation>
+<translation id="2321958826496381788">Geser ukuran teks sampai Anda dapat membacanya dengan nyaman. Teks akan terlihat setidaknya sebesar ini setelah Anda mengetuk sebuah paragraf dua kali.</translation>
<translation id="2359808026110333948">Lanjutkan</translation>
<translation id="2379925928934107488">Terapkan tema gelap ke situs saat Chrome menggunakan tema gelap, jika mungkin</translation>
+<translation id="2387895666653383613">Ukuran teks</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, dan <ph name="NUM_MORE" /> lainnya diizinkan}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, dan <ph name="NUM_MORE" /> lainnya diizinkan}}</translation>
<translation id="2434158240863470628">Download selesai <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">Tampilkan Info</translation>
<translation id="3123473560110926937">Diblokir di beberapa situs</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> data tersimpan</translation>
+<translation id="3203366800380907218">Dari web</translation>
<translation id="321187648315454507">Untuk mengizinkan <ph name="APP_NAME" /> mengirimkan notifikasi, aktifkan juga notifikasi di <ph name="BEGIN_LINK" />Setelan Android<ph name="END_LINK" />.</translation>
<translation id="3227137524299004712">Mikrofon</translation>
<translation id="3277252321222022663">Mengizinkan situs untuk mengakses sensor (disarankan)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">Penggunaan perangkat Anda</translation>
<translation id="385051799172605136">Kembali</translation>
<translation id="3859306556332390985">Cari maju</translation>
+<translation id="3895926599014793903">Aktifkan zoom secara paksa</translation>
<translation id="3955193568934677022">Izinkan situs memutar konten yang dilindungi (direkomendasikan)</translation>
<translation id="3967822245660637423">Download selesai</translation>
<translation id="3987993985790029246">Salin link</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> / ?</translation>
<translation id="4002066346123236978">Judul</translation>
<translation id="4008040567710660924">Izinkan cookie untuk situs tertentu.</translation>
+<translation id="4040330681741629921">Dapatkan notifikasi saat situs bisa ditampilkan dalam tampilan sederhana</translation>
<translation id="4046123991198612571">Lagu berikutnya</translation>
+<translation id="4149994727733219643">Tampilan sederhana untuk halaman web</translation>
<translation id="4165986682804962316">Setelan situs</translation>
+<translation id="4194328954146351878">Tanyakan sebelum mengizinkan situs melihat dan mengubah informasi di perangkat NFC (direkomendasikan)</translation>
<translation id="4200726100658658164">Buka Setelan Lokasi</translation>
<translation id="4226663524361240545">Notifikasi dapat membuat perangkat bergetar</translation>
<translation id="4259722352634471385">Navigasi diblokir: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">Luaskan</translation>
<translation id="4336434711095810371">Hapus semua data</translation>
<translation id="4402755511846832236">Blokir situs agar tidak mengetahui saat Anda aktif menggunakan perangkat ini</translation>
+<translation id="4428065317363009941">Personalisasi iklan</translation>
<translation id="4434045419905280838">Pop-up dan pengalihan</translation>
<translation id="445467742685312942">Izinkan situs memutar konten yang dilindungi</translation>
<translation id="4468959413250150279">Mematikan suara untuk situs tertentu.</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">Opsi tersedia di dekat bagian atas layar</translation>
<translation id="5197729504361054390">Kontak yang Anda pilih akan dibagikan dengan <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />.</translation>
<translation id="5216942107514965959">Terakhir dibuka hari ini</translation>
+<translation id="5264323282659631142">Hapus '<ph name="CHIP_LABEL" />'</translation>
<translation id="528192093759286357">Tarik dari atas dan ketuk tombol kembali untuk keluar dari mode layar penuh.</translation>
<translation id="5300589172476337783">Tampilkan</translation>
<translation id="5301954838959518834">Oke, mengerti</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">Ini akan menghapus <ph name="DATASIZE" /> data dan cookie yang disimpan oleh situs.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(+ 1 lainnya)}other{(+ # lainnya)}}</translation>
<translation id="5403592356182871684">Nama</translation>
+<translation id="5412236728747081950">Situs ini mendapatkan minat Anda dari Chrome untuk menampilkan iklan yang lebih relevan</translation>
<translation id="5438097262470833822">Pilihan ini akan mereset izin untuk <ph name="WEBSITE" /></translation>
<translation id="5489227211564503167">Waktu berlalu <ph name="ELAPSED_TIME" /> dari <ph name="TOTAL_TIME" />.</translation>
<translation id="5494752089476963479">Blokir iklan di situs yang menampilkan iklan yang mengganggu atau menyesatkan</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">Muat ulang</translation>
<translation id="5596627076506792578">Opsi lainnya</translation>
<translation id="5649053991847567735">Download otomatis</translation>
+<translation id="5668404140385795438">Abaikan permintaan situs web untuk mencegah zoom</translation>
<translation id="5677928146339483299">Diblokir</translation>
<translation id="5689516760719285838">Lokasi</translation>
<translation id="5690795753582697420">Kamera dinonaktifkan di setelan Android</translation>
-<translation id="5710871682236653961">Tanyakan sebelum mengizinkan situs untuk mengirim dan menerima info saat Anda mengetuk perangkat NFC (direkomendasikan)</translation>
<translation id="5719847187258001597">Ini akan menghapus semua data dan cookie yang disimpan oleh <ph name="ORIGIN" /> atau aplikasinya di Layar utama Anda.</translation>
<translation id="5771720122942595109"><ph name="PERMISSION_1" /> diblokir</translation>
<translation id="5804241973901381774">Izin</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">Putar</translation>
<translation id="6818926723028410516">Pilih item</translation>
<translation id="6864395892908308021">Perangkat ini tidak dapat membaca NFC</translation>
-<translation id="6910211073230771657">Dihapus</translation>
<translation id="6912998170423641340">Blokir situs agar tidak membaca teks dan gambar dari papan klip</translation>
<translation id="6945221475159498467">Pilih</translation>
<translation id="6965382102122355670">Oke</translation>
+<translation id="6981982820502123353">Aksesibilitas</translation>
<translation id="6992289844737586249">Tanya terlebih dahulu sebelum mengizinkan situs menggunakan mikrofon Anda (disarankan)</translation>
<translation id="7000754031042624318">Dinonaktifkan di setelan Android</translation>
<translation id="7016516562562142042">Diizinkan untuk mesin telusur yang sedang digunakan</translation>
+<translation id="702463548815491781">Disarankan saat TalkBack atau Tombol Akses aktif</translation>
<translation id="7053983685419859001">Blokir</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1 dipilih}other{# dipilih}}</translation>
-<translation id="7070090581017165256">Tentang situs ini</translation>
<translation id="7087918508125750058"><ph name="ITEM_COUNT" /> dipilih. Opsi yang tersedia di dekat bagian atas layar</translation>
<translation id="7141896414559753902">Blokir situs agar tidak menampilkan pop-up dan pengalihan (disarankan)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> KB</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">Situs menggunakan mikrofon Anda</translation>
<translation id="7561196759112975576">Selalu</translation>
-<translation id="7572498721684305250">Blokir situs agar tidak mengirim dan menerima info saat Anda mengetuk perangkat NFC</translation>
<translation id="757524316907819857">Blokir situs agar tidak memutar konten yang dilindungi</translation>
+<translation id="7577900504646297215">Kelola minat</translation>
<translation id="7649070708921625228">Bantuan</translation>
<translation id="7658239707568436148">Batal</translation>
<translation id="7781829728241885113">Kemarin</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">Koneksi aman</translation>
<translation id="8249310407154411074">Pindahkan ke atas</translation>
<translation id="8261506727792406068">Hapus</translation>
+<translation id="8284326494547611709">Teks</translation>
<translation id="8300705686683892304">Dikelola oleh aplikasi</translation>
<translation id="8324158725704657629">Jangan tanya lagi</translation>
<translation id="8372893542064058268">Mengizinkan Sinkronisasi Latar Belakang untuk situs tertentu.</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">Perbesar</translation>
<translation id="8921772741368021346"><ph name="POSITION" />/<ph name="DURATION" /></translation>
<translation id="8926666909099850184">NFC dinonaktifkan di perangkat ini. Aktifkan di <ph name="BEGIN_LINK" />Setelan Android<ph name="END_LINK" />.</translation>
+<translation id="8928445016601307354">Blokir situs agar tidak melihat dan mengubah informasi di perangkat NFC</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">Blokir cookie untuk situs tertentu.</translation>
<translation id="8959122750345127698">Navigasi tidak dapat dijangkau: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_is.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_is.xtb
index 811b4f84847..3493ec91f04 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_is.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_is.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">Vefsvæðinu <ph name="SITE_NAME" /> bætt við</translation>
<translation id="1383876407941801731">Leita</translation>
<translation id="1384959399684842514">Gert var hlé á niðurhali</translation>
+<translation id="1409426117486808224">Einfaldað yfirlit fyrir opna flipa</translation>
<translation id="1415402041810619267">Stytt vefslóð</translation>
<translation id="1446450296470737166">Leyfa ótakmarkaða stjórn á MIDI-tækjum</translation>
<translation id="1620510694547887537">Myndavél</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">Leyfa fótspor</translation>
<translation id="2228071138934252756">Til að veita <ph name="APP_NAME" /> aðgang að myndavélinni þarftu einnig að kveikja á henni í <ph name="BEGIN_LINK" />stillingum Android<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Bara einu sinni</translation>
+<translation id="2253414712144136228"><ph name="NAME_OF_LIST_ITEM" /> Fjarlægja</translation>
<translation id="2289270750774289114">Spyrja þegar vefsvæði vill finna nálæg Bluetooth-tæki (ráðlagt)</translation>
<translation id="2315043854645842844">Stýrikerfið styður ekki vottorðsval hjá biðlara.</translation>
+<translation id="2321958826496381788">Dragðu sleðann þangað til þú getur lesið þetta áreynslulaust. Texti ætti að vera að minnsta kosti svona stór eftir að ýtt hefur verið tvisvar á efnisgrein.</translation>
<translation id="2359808026110333948">Halda áfram</translation>
<translation id="2379925928934107488">Nota dökkt þema fyrir vefsvæði þegar Chrome notar dökkt þema, sé þess kostur</translation>
+<translation id="2387895666653383613">Textastærð</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{„<ph name="PERMISSION_1" />“, „<ph name="PERMISSION_2" />“ og <ph name="NUM_MORE" /> í viðbót leyft}one{„<ph name="PERMISSION_1" />“, „<ph name="PERMISSION_2" />“ og <ph name="NUM_MORE" /> í viðbót leyft}other{„<ph name="PERMISSION_1" />“, „<ph name="PERMISSION_2" />“ og <ph name="NUM_MORE" /> í viðbót leyft}}</translation>
<translation id="2434158240863470628">Niðurhali lokið <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">Sýna upplýsingar</translation>
<translation id="3123473560110926937">Útilokaðar á sumum vefsvæðum</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> af vistuðum gögnum</translation>
+<translation id="3203366800380907218">Af vefnum</translation>
<translation id="321187648315454507">Til að leyfa <ph name="APP_NAME" /> að senda þér tilkynningar þarftu einnig að kveikja á þeim í <ph name="BEGIN_LINK" />stillingum Android<ph name="END_LINK" />.</translation>
<translation id="3227137524299004712">Hljóðnemi</translation>
<translation id="3277252321222022663">Leyfa vefsvæðum að fá aðgang að skynjurum (ráðlagt)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">Tækjanotkun þín</translation>
<translation id="385051799172605136">Til baka</translation>
<translation id="3859306556332390985">Leita áfram</translation>
+<translation id="3895926599014793903">Þvinga fram aðdrátt</translation>
<translation id="3955193568934677022">Leyfa vefsvæðum að spila varið efni (ráðlagt)</translation>
<translation id="3967822245660637423">Niðurhali lokið</translation>
<translation id="3987993985790029246">Afrita tengil</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" />/?</translation>
<translation id="4002066346123236978">Heiti</translation>
<translation id="4008040567710660924">Leyfa fótspor fyrir tiltekið vefsvæði.</translation>
+<translation id="4040330681741629921">Fá tilkynningu þegar hægt er að birta vefsvæði í einfaldaðri útgáfu</translation>
<translation id="4046123991198612571">Næsta lag</translation>
+<translation id="4149994727733219643">Einfaldað yfirlit fyrir vefsíður</translation>
<translation id="4165986682804962316">Vefsvæðastillingar</translation>
+<translation id="4194328954146351878">Spyrja áður en vefsvæði fá að sjá og breyta upplýsingum í NFC-tækjum (ráðlagt)</translation>
<translation id="4200726100658658164">Opna staðsetningarstillingar</translation>
<translation id="4226663524361240545">Tilkynningar gætu látið tækið titra</translation>
<translation id="4259722352634471385">Lokað er fyrir skoðun: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">Stækka</translation>
<translation id="4336434711095810371">Hreinsa öll gögn</translation>
<translation id="4402755511846832236">Lokaðu á að vefsvæði geti séð hvenær þú notar þetta tæki</translation>
+<translation id="4428065317363009941">Sérsniðnar auglýsingar</translation>
<translation id="4434045419905280838">Sprettigluggar og framsendingar</translation>
<translation id="445467742685312942">Leyfa vefsvæðum að spila varið efni</translation>
<translation id="4468959413250150279">Slökkva á hljóði á tilteknu vefsvæði.</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">Valkosturinn er við efri brún skjásins</translation>
<translation id="5197729504361054390">Tengiliðunum sem þú valdir verður deilt með <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />.</translation>
<translation id="5216942107514965959">Síðast opnað í dag</translation>
+<translation id="5264323282659631142">Fjarlægja „<ph name="CHIP_LABEL" />“</translation>
<translation id="528192093759286357">Dragðu ofan frá og snertu bakkhnappinn til að hætta birtingu á öllum skjánum.</translation>
<translation id="5300589172476337783">Sýna</translation>
<translation id="5301954838959518834">Ég skil</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">Þetta hreinsar <ph name="DATASIZE" /> af gögnum og fótsporum sem vefsvæði geyma.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(+ 1 í viðbót)}one{(+ # í viðbót)}other{(+ # í viðbót)}}</translation>
<translation id="5403592356182871684">Heiti</translation>
+<translation id="5412236728747081950">Þetta vefsvæði fær upplýsingar um áhugasvið þín frá Chrome til að birta þér viðeigandi auglýsingar</translation>
<translation id="5438097262470833822">Þetta val endurstillir heimildir fyrir <ph name="WEBSITE" /></translation>
<translation id="5489227211564503167">Liðinn tími: <ph name="ELAPSED_TIME" /> af <ph name="TOTAL_TIME" />.</translation>
<translation id="5494752089476963479">Útiloka auglýsingar á vefsvæðum sem birta ágengar eða villandi auglýsingar</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">Endurhlaða</translation>
<translation id="5596627076506792578">Fleiri valkostir</translation>
<translation id="5649053991847567735">Sjálfvirkt niðurhal</translation>
+<translation id="5668404140385795438">Hunsa beiðni vefsvæðis um að koma í veg fyrir aðdrátt</translation>
<translation id="5677928146339483299">Lokað fyrir aðgang</translation>
<translation id="5689516760719285838">Staðsetning</translation>
<translation id="5690795753582697420">Slökkt er á myndavél í stillingum Android</translation>
-<translation id="5710871682236653961">Spyrja áður en vefsvæði fá leyfi til að senda og taka við upplýsingum þegar þú ýtir á NFC-tæki (ráðlagt)</translation>
<translation id="5719847187258001597">Þetta hreinsar öll gögn og fótspor sem <ph name="ORIGIN" /> eða forrit þess geymir á heimaskjánum</translation>
<translation id="5771720122942595109">Lokað er fyrir <ph name="PERMISSION_1" /></translation>
<translation id="5804241973901381774">Heimildir</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">Spila</translation>
<translation id="6818926723028410516">Veldu atriði</translation>
<translation id="6864395892908308021">Þetta tæki getur ekki lesið NFC</translation>
-<translation id="6910211073230771657">Eytt</translation>
<translation id="6912998170423641340">Koma í veg fyrir að vefsvæði geti lesið texta og myndir af klippiborðinu</translation>
<translation id="6945221475159498467">Velja</translation>
<translation id="6965382102122355670">Ã lagi</translation>
+<translation id="6981982820502123353">Aðgengi</translation>
<translation id="6992289844737586249">Spyrja áður en vefsvæðum er veitt heimild til að nota hljóðnemann þinn (ráðlagt)</translation>
<translation id="7000754031042624318">Slökkt í stillingum Android</translation>
<translation id="7016516562562142042">Leyft á núverandi leitarvél</translation>
+<translation id="702463548815491781">Mælt með þegar kveikt er á TalkBack eða rofaaðgangi</translation>
<translation id="7053983685419859001">Setja á bannlista</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1 valið}one{# valið}other{# valin}}</translation>
-<translation id="7070090581017165256">Um þetta vefsvæði</translation>
<translation id="7087918508125750058"><ph name="ITEM_COUNT" /> valin. Valkostir eru ofarlega á skjánum</translation>
<translation id="7141896414559753902">Banna síðum að birta sprettiglugga og framsendingar (ráðlagt)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> KB</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">Vefsvæði er að nota hljóðnemann</translation>
<translation id="7561196759112975576">Alltaf</translation>
-<translation id="7572498721684305250">Loka fyrir að vefsvæði geti sent og tekið við upplýsingum þegar þú ýtir á NFC-tæki</translation>
<translation id="757524316907819857">Banna síðum að spila varið efni</translation>
+<translation id="7577900504646297215">Stjórna áhugamálum</translation>
<translation id="7649070708921625228">Hjálp</translation>
<translation id="7658239707568436148">Hætta við</translation>
<translation id="7781829728241885113">à gær</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">Tengingin er örugg</translation>
<translation id="8249310407154411074">Færa efst</translation>
<translation id="8261506727792406068">Eyða</translation>
+<translation id="8284326494547611709">Skjátextar</translation>
<translation id="8300705686683892304">Stjórnað af forriti</translation>
<translation id="8324158725704657629">Ekki spyrja aftur</translation>
<translation id="8372893542064058268">Leyfa bakgrunnssamstillingu fyrir ákveðið vefsvæði.</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">Auka aðdrátt</translation>
<translation id="8921772741368021346"><ph name="POSITION" /> / <ph name="DURATION" /></translation>
<translation id="8926666909099850184">Slökkt er á NFC fyrir þetta tæki. Kveiktu á því í <ph name="BEGIN_LINK" />stillingum Android<ph name="END_LINK" />.</translation>
+<translation id="8928445016601307354">Loka á að vefsvæði sjái og breyti upplýsingum í NFC-tækjum</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">Lokaðu á fótspor fyrir tiltekið vefsvæði.</translation>
<translation id="8959122750345127698">Ekki næst samband: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_it.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_it.xtb
index 6f02ea03d33..c4f761e165e 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_it.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_it.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">Sito <ph name="SITE_NAME" /> aggiunto</translation>
<translation id="1383876407941801731">Cerca</translation>
<translation id="1384959399684842514">Download sospeso</translation>
+<translation id="1409426117486808224">Visualizzazione semplificata delle schede aperte</translation>
<translation id="1415402041810619267">URL troncato</translation>
<translation id="1446450296470737166">Controllo completo dispos. MIDI</translation>
<translation id="1620510694547887537">Fotocamera</translation>
@@ -49,12 +50,15 @@
<translation id="2212565012507486665">Consenti cookie</translation>
<translation id="2228071138934252756">Per consentire all'app <ph name="APP_NAME" /> di accedere alla fotocamera, attiva la fotocamera anche nelle <ph name="BEGIN_LINK" />Impostazioni Android<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Solo una volta</translation>
+<translation id="2253414712144136228">Rimuovi <ph name="NAME_OF_LIST_ITEM" /></translation>
<translation id="2289270750774289114">Chiedi conferma quando un sito vuole rilevare i dispositivi Bluetooth nelle vicinanze (opzione consigliata)</translation>
<translation id="2315043854645842844">La selezione del certificato lato client non è supportata dal sistema operativo.</translation>
+<translation id="2321958826496381788">Trascina il cursore finché leggi il testo senza problemi. Il testo dovrebbe avere queste dimensioni minime quando tocchi due volte un paragrafo.</translation>
<translation id="2359808026110333948">Continua</translation>
<translation id="2379925928934107488">Applica il tema scuro ai siti quando viene usato in Chrome, se possibile</translation>
+<translation id="2387895666653383613">Ridimensionamento testo</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
-<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Consentite: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> e <ph name="NUM_MORE" /> altra}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, and <ph name="NUM_MORE" /> more allowed}other{Consentite: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> e altre <ph name="NUM_MORE" />}}</translation>
+<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Consentite: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> e <ph name="NUM_MORE" /> altra}other{Consentite: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> e altre <ph name="NUM_MORE" />}}</translation>
<translation id="2434158240863470628">Download completato: <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
<translation id="2442870161001914531">Richiedi sempre sito desktop</translation>
<translation id="2482878487686419369">Notifiche</translation>
@@ -62,7 +66,7 @@
<translation id="2490684707762498678">Gestite da <ph name="APP_NAME" /></translation>
<translation id="2498359688066513246">Guida e feedback</translation>
<translation id="2501278716633472235">Indietro</translation>
-<translation id="2569468611847789653">{COOKIE_COUNT,plural, =1{1 cookie bloccato}one{# cookie bloccati}other{# cookie bloccati}}</translation>
+<translation id="2569468611847789653">{COOKIE_COUNT,plural, =1{1 cookie bloccato}other{# cookie bloccati}}</translation>
<translation id="2570922361219980984">L'accesso alla posizione è disattivato anche per questo dispositivo. Attivalo nelle <ph name="BEGIN_LINK" />Impostazioni Android<ph name="END_LINK" />.</translation>
<translation id="257931822824936280">Espanso. Fai clic per comprimere.</translation>
<translation id="2586657967955657006">Appunti</translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">Mostra informazioni</translation>
<translation id="3123473560110926937">Bloccati su alcuni siti</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> di dati memorizzati</translation>
+<translation id="3203366800380907218">Dal Web</translation>
<translation id="321187648315454507">Per consentire all'app <ph name="APP_NAME" /> di inviarti notifiche, devi attivare le notifiche anche nelle <ph name="BEGIN_LINK" />Impostazioni Android<ph name="END_LINK" />.</translation>
<translation id="3227137524299004712">Microfono</translation>
<translation id="3277252321222022663">Consenti ai siti di accedere ai sensori (opzione consigliata)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">Utilizzo del tuo dispositivo</translation>
<translation id="385051799172605136">Indietro</translation>
<translation id="3859306556332390985">Posiziona avanti</translation>
+<translation id="3895926599014793903">Attivazione forzata dello zoom</translation>
<translation id="3955193568934677022">Consenti ai siti di riprodurre i contenuti protetti (opzione consigliata)</translation>
<translation id="3967822245660637423">Download completato</translation>
<translation id="3987993985790029246">Copia link</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> di ?</translation>
<translation id="4002066346123236978">Titolo</translation>
<translation id="4008040567710660924">Consenti i cookie per un sito specifico.</translation>
+<translation id="4040330681741629921">Ricevi una notifica quando un sito può essere mostrato nella visualizzazione semplificata</translation>
<translation id="4046123991198612571">Traccia successiva</translation>
+<translation id="4149994727733219643">Visualizzazione semplificata delle pagine web</translation>
<translation id="4165986682804962316">Impostazioni sito</translation>
+<translation id="4194328954146351878">Chiedi conferma prima di consentire ai siti di vedere e modificare informazioni su dispositivi NFC (opzione consigliata)</translation>
<translation id="4200726100658658164">Apri Impostazioni di geolocalizzazione</translation>
<translation id="4226663524361240545">Le notifiche possono far vibrare il dispositivo</translation>
<translation id="4259722352634471385">Navigazione bloccata: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">Espandi</translation>
<translation id="4336434711095810371">Cancella tutti i dati</translation>
<translation id="4402755511846832236">Impedisci ai siti di sapere quando usi attivamente questo dispositivo</translation>
+<translation id="4428065317363009941">Personalizzazione degli annunci</translation>
<translation id="4434045419905280838">Popup e reindirizzamenti</translation>
<translation id="445467742685312942">Consenti ai siti di riprodurre contenuti protetti</translation>
<translation id="4468959413250150279">Disattiva l'audio per un sito specifico.</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">Opzione disponibile nella parte superiore dello schermo</translation>
<translation id="5197729504361054390">I contatti che selezioni verranno condivisi con <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />.</translation>
<translation id="5216942107514965959">Ultima visita: oggi</translation>
+<translation id="5264323282659631142">Rimuovi "<ph name="CHIP_LABEL" />"</translation>
<translation id="528192093759286357">Trascina dall'alto e tocca il pulsante Indietro per uscire dalla modalità a schermo intero.</translation>
<translation id="5300589172476337783">Mostra</translation>
<translation id="5301954838959518834">OK</translation>
@@ -164,8 +175,9 @@
<translation id="5335288049665977812">Consenti l'esecuzione di JavaScript nei siti (opzione consigliata)</translation>
<translation id="534295439873310000">Dispositivi NFC</translation>
<translation id="5354152178998424783">Verranno cancellati <ph name="DATASIZE" /> di dati e cookie memorizzati dai siti.</translation>
-<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(+ 1 altro)}one{(+ altri #)}other{(+ altri #)}}</translation>
+<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(+ 1 altro)}other{(+ altri #)}}</translation>
<translation id="5403592356182871684">Nomi</translation>
+<translation id="5412236728747081950">Questo sito acquisisce i tuoi interessi da Chrome per mostrarti annunci più pertinenti</translation>
<translation id="5438097262470833822">Questa selezione reimposterà le autorizzazioni per <ph name="WEBSITE" /></translation>
<translation id="5489227211564503167">Tempo trascorso: <ph name="ELAPSED_TIME" /> di <ph name="TOTAL_TIME" />.</translation>
<translation id="5494752089476963479">Blocca gli annunci su siti che mostrano annunci invasivi o fuorvianti</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">Ricarica</translation>
<translation id="5596627076506792578">Altre opzioni</translation>
<translation id="5649053991847567735">Download automatici</translation>
+<translation id="5668404140385795438">Ignora la richiesta di un sito per evitare l'aumento dello zoom</translation>
<translation id="5677928146339483299">Blocca</translation>
<translation id="5689516760719285838">Posizione</translation>
<translation id="5690795753582697420">La fotocamera è disattivata nelle impostazioni di Android</translation>
-<translation id="5710871682236653961">Chiedi prima di consentire ai siti di inviare e ricevere informazioni quando tocchi i dispositivi NFC (opzione consigliata)</translation>
<translation id="5719847187258001597">Verranno cancellati tutti i dati e i cookie memorizzati dal sito <ph name="ORIGIN" /> o dalla relativa app nella schermata Home.</translation>
<translation id="5771720122942595109">Autorizzazione <ph name="PERMISSION_1" /> bloccata</translation>
<translation id="5804241973901381774">Autorizzazioni</translation>
@@ -214,7 +226,7 @@
<translation id="6447842834002726250">Cookie</translation>
<translation id="6527303717912515753">Condividi</translation>
<translation id="6545864417968258051">Scansione Bluetooth</translation>
-<translation id="6552800053856095716">{PERMISSIONS_SUMMARY_BLOCKED,plural, =1{Bloccate: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> e <ph name="NUM_MORE" /> altra}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, and <ph name="NUM_MORE" /> more blocked}other{Bloccate: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> e altre <ph name="NUM_MORE" />}}</translation>
+<translation id="6552800053856095716">{PERMISSIONS_SUMMARY_BLOCKED,plural, =1{Bloccate: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> e <ph name="NUM_MORE" /> altra}other{Bloccate: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> e altre <ph name="NUM_MORE" />}}</translation>
<translation id="6554732001434021288">Ultima visita: <ph name="NUM_DAYS" /> giorni fa</translation>
<translation id="6561560012278703671">Usa messaggi più discreti (impedisce alle notifiche di disturbarti)</translation>
<translation id="6593061639179217415">Sito desktop</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">Riproduci</translation>
<translation id="6818926723028410516">Seleziona elementi</translation>
<translation id="6864395892908308021">Questo dispositivo non può leggere la tecnologia NFC</translation>
-<translation id="6910211073230771657">Eliminato</translation>
<translation id="6912998170423641340">Impedisci ai siti di leggere testo e immagini negli appunti</translation>
<translation id="6945221475159498467">Seleziona</translation>
<translation id="6965382102122355670">OK</translation>
+<translation id="6981982820502123353">Accessibilità</translation>
<translation id="6992289844737586249">Chiedi conferma prima di consentire ai siti di utilizzare il microfono (opzione consigliata)</translation>
<translation id="7000754031042624318">Disattivata nelle impostazioni Android</translation>
<translation id="7016516562562142042">Consentita per il motore di ricerca corrente</translation>
+<translation id="702463548815491781">Consigliata quando TalkBack o Switch Access sono attivi</translation>
<translation id="7053983685419859001">Blocca</translation>
-<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1 elemento selezionato}one{# selected}other{# elementi selezionati}}</translation>
-<translation id="7070090581017165256">Informazioni su questo sito</translation>
+<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1 elemento selezionato}other{# elementi selezionati}}</translation>
<translation id="7087918508125750058"><ph name="ITEM_COUNT" /> elementi selezionati. Opzioni disponibili nella parte superiore dello schermo</translation>
<translation id="7141896414559753902">Impedisci ai siti di mostrare popup e reindirizzamenti (opzione consigliata)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> kB</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">Un sito sta utilizzando il microfono</translation>
<translation id="7561196759112975576">Sempre</translation>
-<translation id="7572498721684305250">Impedisci ai siti di inviare e ricevere informazioni quando tocchi i dispositivi NFC</translation>
<translation id="757524316907819857">Impedisci ai siti di riprodurre contenuti protetti</translation>
+<translation id="7577900504646297215">Gestisci interessi</translation>
<translation id="7649070708921625228">Guida</translation>
<translation id="7658239707568436148">Annulla</translation>
<translation id="7781829728241885113">Ieri</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">La connessione è sicura</translation>
<translation id="8249310407154411074">Sposta in alto</translation>
<translation id="8261506727792406068">Elimina</translation>
+<translation id="8284326494547611709">Sottotitoli</translation>
<translation id="8300705686683892304">Gestiti dall'app</translation>
<translation id="8324158725704657629">Non chiedermelo più</translation>
<translation id="8372893542064058268">Consenti la sincronizzazione in background per un sito specifico.</translation>
@@ -299,7 +312,7 @@
<translation id="8441146129660941386">Posiziona indietro</translation>
<translation id="8444433999583714703">Per consentire all'app <ph name="APP_NAME" /> di accedere alla tua posizione, devi attivare la posizione anche nelle <ph name="BEGIN_LINK" />Impostazioni Android<ph name="END_LINK" />.</translation>
<translation id="8447861592752582886">Revoca autorizzazione dispositivo</translation>
-<translation id="8451050538944905715">{NUM_SELECTED,plural, =1{1 cookie in uso}one{# cookie in uso}other{# cookie in uso}}</translation>
+<translation id="8451050538944905715">{NUM_SELECTED,plural, =1{1 cookie in uso}other{# cookie in uso}}</translation>
<translation id="8487700953926739672">Disponibile offline</translation>
<translation id="848952951823693243">Richiedi sempre sito per dispositivi mobili</translation>
<translation id="851751545965956758">Impedisci ai siti di connettersi ai dispositivi</translation>
@@ -321,13 +334,14 @@
<translation id="8903921497873541725">Aumenta lo zoom</translation>
<translation id="8921772741368021346"><ph name="POSITION" />/<ph name="DURATION" /></translation>
<translation id="8926666909099850184">Funzionalità NFC non attiva per questo dispositivo. Attivala nelle <ph name="BEGIN_LINK" />Impostazioni Android<ph name="END_LINK" />.</translation>
+<translation id="8928445016601307354">Impedisci ai siti di vedere e modificare informazioni su dispositivi NFC</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">Blocca i cookie per un sito specifico.</translation>
<translation id="8959122750345127698">Navigazione inaccessibile: <ph name="URL" /></translation>
<translation id="8986362086234534611">Elimina</translation>
<translation id="9019902583201351841">Gestito dai genitori</translation>
<translation id="9074739597929991885">Bluetooth</translation>
-<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> e <ph name="NUM_MORE" /> altra}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, and <ph name="NUM_MORE" /> more}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> e altre <ph name="NUM_MORE" />}}</translation>
+<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> e <ph name="NUM_MORE" /> altra}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> e altre <ph name="NUM_MORE" />}}</translation>
<translation id="913657688200966289">Attiva le autorizzazioni per l'app <ph name="APP_NAME" /> nelle <ph name="BEGIN_LINK" />Impostazioni Android<ph name="END_LINK" />.</translation>
<translation id="9162462602695099906">Questa pagina è pericolosa</translation>
<translation id="930525582205581608">Vuoi eliminare questo sito?</translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_iw.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_iw.xtb
index a498a687512..08eeb5daf7d 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_iw.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_iw.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">×”×תר <ph name="SITE_NAME" /> נוסף</translation>
<translation id="1383876407941801731">חיפוש</translation>
<translation id="1384959399684842514">ההורדה הושהתה</translation>
+<translation id="1409426117486808224">תצוגה פשוטה של כרטיסיות פתוחות</translation>
<translation id="1415402041810619267">â€×›×ª×•×‘ת ×”-URL קוצרה</translation>
<translation id="1446450296470737166">â€×”תרת שליטה מל××” על מכשירי MIDI</translation>
<translation id="1620510694547887537">מצלמה</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">â€×ישור קובצי cookie</translation>
<translation id="2228071138934252756">â€×›×“×™ ל×פשר ל-<ph name="APP_NAME" /> לגשת ×ל המצלמה, צריך להפעיל ×ותה ×’× ×‘<ph name="BEGIN_LINK" />הגדרות Android<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">×¤×¢× ×חת בלבד</translation>
+<translation id="2253414712144136228">הסרה של <ph name="NAME_OF_LIST_ITEM" /></translation>
<translation id="2289270750774289114">â€×”מערכת מבקשת ×ישור כש×תר רוצה ל×תר התקני Bluetooth ×§×¨×•×‘×™× (מומלץ)</translation>
<translation id="2315043854645842844">מערכת ההפעלה ××™× ×” תומכת בבחירת ×ישור בצד הלקוח.</translation>
+<translation id="2321958826496381788">יש לגרור ×ת המחוון עד ש×פשר ×™×”×™×” ×œ×§×¨×•× ×ת הקטע ×”×–×” בצורה נוחה. ל×חר הקשה ×¤×¢×ž×™×™× ×¢×œ פיסקה, הטקסט ×מור להיות מוצג בגודל ×”×–×” לפחות.</translation>
<translation id="2359808026110333948">המשך</translation>
<translation id="2379925928934107488">â€×”עיצוב ×”×›×”×” יוחל על ××ª×¨×™× ×›×©-Chrome ישתמש בעיצוב ×”×›×”×”, כשהפעולה תת×פשר</translation>
+<translation id="2387895666653383613">שינוי גודל טקסט</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{הוענקו ההרש×ות <ph name="PERMISSION_1" />,†<ph name="PERMISSION_2" /> ועוד ×חת (<ph name="NUM_MORE" />)}two{הוענקו ההרש×ות <ph name="PERMISSION_1" />,†<ph name="PERMISSION_2" /> ועוד <ph name="NUM_MORE" />}many{הוענקו ההרש×ות <ph name="PERMISSION_1" />,†<ph name="PERMISSION_2" /> ועוד <ph name="NUM_MORE" />}other{הוענקו ההרש×ות <ph name="PERMISSION_1" />,†<ph name="PERMISSION_2" /> ועוד <ph name="NUM_MORE" />}}</translation>
<translation id="2434158240863470628">ההורדה הושלמה <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">הצגת פרטי×</translation>
<translation id="3123473560110926937">חסומות בחלק מה×תרי×</translation>
<translation id="3198916472715691905">× ×ª×•× ×™× ×ž××•×—×¡× ×™× ×‘× ×¤×— <ph name="STORAGE_AMOUNT" /></translation>
+<translation id="3203366800380907218">מה×ינטרנט</translation>
<translation id="321187648315454507">â€×›×“×™ ל×פשר ל-<ph name="APP_NAME" /> לשלוח לך התר×ות, צריך להפעיל ×ותן ×’× ×‘<ph name="BEGIN_LINK" />הגדרות Android<ph name="END_LINK" />.</translation>
<translation id="3227137524299004712">מיקרופון</translation>
<translation id="3277252321222022663">התרת גישה של ××ª×¨×™× ×ל ×”×—×™×™×©× ×™× (מומלץ)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">השימוש שלך במכשיר</translation>
<translation id="385051799172605136">חזרה</translation>
<translation id="3859306556332390985">הרצה קדימה</translation>
+<translation id="3895926599014793903">שינוי ×”×–×•× ×‘×›×œ מקרה</translation>
<translation id="3955193568934677022">××ª×¨×™× ×™×•×›×œ×• להפעיל תוכן מוגן (מומלץ)</translation>
<translation id="3967822245660637423">ההורדה הושלמה</translation>
<translation id="3987993985790029246">העתקת קישור</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> / ?</translation>
<translation id="4002066346123236978">כותרת</translation>
<translation id="4008040567710660924">â€×ישור קובצי Cookie של ×תר מסוי×.</translation>
+<translation id="4040330681741629921">קבלת התר××” כש×פשר להציג ×תר בתצוגה פשוטה</translation>
<translation id="4046123991198612571">הרצועה הב××”</translation>
+<translation id="4149994727733219643">תצוגה פשוטה של דפי ×ינטרנט</translation>
<translation id="4165986682804962316">הגדרות ל×תרי×</translation>
+<translation id="4194328954146351878">â€×”צגת ש×לה לפני מתן הרש××” ל××ª×¨×™× ×œ×¨×ות ולשנות מידע במכשירי NFC (מומלץ).</translation>
<translation id="4200726100658658164">פתיחת הגדרות המיקו×</translation>
<translation id="4226663524361240545">רטט של המכשיר ×פשרי כשמתקבלת הודעה</translation>
<translation id="4259722352634471385">הניווט חסו×: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">הרחבה</translation>
<translation id="4336434711095810371">ניקוי כל הנתוני×</translation>
<translation id="4402755511846832236">××ª×¨×™× ×œ× ×™×•×›×œ×• לדעת מתי המכשיר ×”×–×” משמש ×ותך ב×ופן פעיל</translation>
+<translation id="4428065317363009941">הת×מה ×ישית של מודעות</translation>
<translation id="4434045419905280838">חלונות ×§×•×¤×¦×™× ×•×”×¤× ×™×•×ª ×וטומטיות</translation>
<translation id="445467742685312942">מתן הרש××” ל××ª×¨×™× ×œ×”×¦×™×’ תוכן מוגן</translation>
<translation id="4468959413250150279">השתקת ×¦×œ×™×œ×™× ×‘×תר ספציפי.</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">×”×פשרות זמינה בחלק העליון של המסך</translation>
<translation id="5197729504361054390">×נשי הקשר שייבחרו ישותפו ×¢× <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />.</translation>
<translation id="5216942107514965959">הכניסה ×”×חרונה בוצעה היו×</translation>
+<translation id="5264323282659631142">הסרת '<ph name="CHIP_LABEL" />'</translation>
<translation id="528192093759286357">כדי לצ×ת ממסך מל×, יש לגרור מלמעלה ולגעת בלחצן 'הקוד×'.</translation>
<translation id="5300589172476337783">הצגה</translation>
<translation id="5301954838959518834">בסדר, הבנתי</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">â€×”פעולה הזו ×ª×’×¨×•× ×œ×ž×—×™×§×ª <ph name="DATASIZE" /> של × ×ª×•× ×™× ×•×§×•×‘×¦×™ cookie שנשמרו על ידי ×תרי×.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(ועוד 1)}two{(ועוד #)}many{(ועוד #)}other{(ועוד #)}}</translation>
<translation id="5403592356182871684">שמות</translation>
+<translation id="5412236728747081950">â€×™×•×¦×’ו לך מודעות רלוונטיות יותר ב×תר על סמך תחומי העניין שלך מ-Chrome</translation>
<translation id="5438097262470833822">הבחירה הזו ×ª×’×¨×•× ×œ×יפוס ההרש×ות של <ph name="WEBSITE" /></translation>
<translation id="5489227211564503167">צפית ב-<ph name="ELAPSED_TIME" /> מתוך <ph name="TOTAL_TIME" />.</translation>
<translation id="5494752089476963479">חסימת מודעות ב××ª×¨×™× ×©×ž×•×¦×’×•×ª ×‘×”× ×ž×•×“×¢×•×ª מפריעות ×ו מטעות</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">טעינה מחדש</translation>
<translation id="5596627076506792578">×פשרויות נוספות</translation>
<translation id="5649053991847567735">הורדות ×וטומטיות</translation>
+<translation id="5668404140385795438">×œ×”×ª×¢×œ× ×ž×‘×§×©×” של ×תר שנועדה למנוע ×ת שינוי המרחק מהתצוגה</translation>
<translation id="5677928146339483299">חסו×</translation>
<translation id="5689516760719285838">מיקו×</translation>
<translation id="5690795753582697420">â€×”מצלמה מושבתת בהגדרות Android</translation>
-<translation id="5710871682236653961">â€×”צגת ש×לה לפני מתן הרש××” ל××ª×¨×™× ×œ×©×œ×•×— ולקבל מידע ×›×©×ž×§×™×©×™× ×¢×œ מכשירי NFC (מומלץ)</translation>
<translation id="5719847187258001597">â€×”פעולה ×”×–×ת תמחק ×ת כל ×”× ×ª×•× ×™× ×•×ת קובצי ×”-cookie שנשמרו במסך הבית על ידי ×”×תר <ph name="ORIGIN" /> ×ו ×”×פליקציה שלו.</translation>
<translation id="5771720122942595109">חסומה: <ph name="PERMISSION_1" /></translation>
<translation id="5804241973901381774">הרש×ות</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">הפעלה</translation>
<translation id="6818926723028410516">בחירת פריטי×</translation>
<translation id="6864395892908308021">â€NFC ×œ× × ×ª×ž×š במכשיר ×”×–×”</translation>
-<translation id="6910211073230771657">נמחק</translation>
<translation id="6912998170423641340">חסימת היכולת של ××ª×¨×™× ×œ×§×¨×•× ×˜×§×¡×˜ ותמונות מלוח העריכה</translation>
<translation id="6945221475159498467">בחירה</translation>
<translation id="6965382102122355670">×ישור</translation>
+<translation id="6981982820502123353">נגישות</translation>
<translation id="6992289844737586249">יש לש×ול לפני שמ××¤×©×¨×™× ×œ××ª×¨×™× ×œ×”×©×ª×ž×© במיקרופון (מומלץ)</translation>
<translation id="7000754031042624318">â€×”הרש××” מושבתת בהגדרות Android</translation>
<translation id="7016516562562142042">מופעל למנוע החיפוש הנוכחי</translation>
+<translation id="702463548815491781">â€×ž×•×ž×œ×¥ ×× ×”×¤×¢×œ×ª TalkBack ×ו גישה ב×מצעות מתג</translation>
<translation id="7053983685419859001">חסימה</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{נבחר ×חד}two{נבחרו #}many{נבחרו #}other{נבחרו #}}</translation>
-<translation id="7070090581017165256">מידע על ×”×תר ×”×–×”</translation>
<translation id="7087918508125750058">נבחרו <ph name="ITEM_COUNT" />. ×”×פשרויות מוצגות בחלק העליון של המסך</translation>
<translation id="7141896414559753902">חסימה של חלונות ×§×•×¤×¦×™× ×•×”×¤× ×™×•×ª ×וטומטיות ב××ª×¨×™× (מומלץ)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> KB</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">×תר כלשהו משתמש במיקרופון שלך</translation>
<translation id="7561196759112975576">תמיד</translation>
-<translation id="7572498721684305250">â€×—סימת ×”×פשרות של ××ª×¨×™× ×œ×©×œ×•×— ולקבל מידע ×›×©×ž×§×™×©×™× ×¢×œ מכשירי NFC</translation>
<translation id="757524316907819857">חסימה של הפעלת תוכן מוגן על-ידי ×תרי×</translation>
+<translation id="7577900504646297215">ניהול תחומי עניין</translation>
<translation id="7649070708921625228">עזרה</translation>
<translation id="7658239707568436148">ביטול</translation>
<translation id="7781829728241885113">×תמול</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">החיבור מ×ובטח</translation>
<translation id="8249310407154411074">העברה לר×ש הרשימה</translation>
<translation id="8261506727792406068">מחיקה</translation>
+<translation id="8284326494547611709">כתוביות</translation>
<translation id="8300705686683892304">×ž× ×•×”×œ×™× ×¢×œ-ידי ×פליקציה</translation>
<translation id="8324158725704657629">×œ× ×œ×©×ול שוב</translation>
<translation id="8372893542064058268">×ישור סנכרון ברקע ל×תר ספציפי.</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">התקרבות לתצוגה</translation>
<translation id="8921772741368021346"><ph name="POSITION" /> / <ph name="DURATION" /></translation>
<translation id="8926666909099850184">â€×§×™×©×•×¨×™×•×ª ×”-NFC מושבתת במכשיר ×”×–×”. ניתן להפעיל ×ותה דרך <ph name="BEGIN_LINK" />הגדרות Android<ph name="END_LINK" />.</translation>
+<translation id="8928445016601307354">â€×œ××ª×¨×™× ×ין הרש××” לר×ות ולשנות מידע במכשירי NFC.</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">â€×—סימת קובצי Cookie של ×תר מסוי×.</translation>
<translation id="8959122750345127698">הניווט ×œ× ×פשרי: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ja.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ja.xtb
index b3b29b009ad..e6733afbfc4 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ja.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ja.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">サイト <ph name="SITE_NAME" /> を追加ã—ã¾ã—ãŸ</translation>
<translation id="1383876407941801731">検索</translation>
<translation id="1384959399684842514">ダウンロードを一時åœæ­¢ã—ã¾ã—ãŸ</translation>
+<translation id="1409426117486808224">é–‹ã„ã¦ã„るタブã®ç°¡æ˜“表示</translation>
<translation id="1415402041810619267">URL ã®çŸ­ç¸®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã§ã™</translation>
<translation id="1446450296470737166">MIDI機器ã®ãƒ•ãƒ«ã‚³ãƒ³ãƒˆãƒ­ãƒ¼ãƒ«ã‚’許å¯</translation>
<translation id="1620510694547887537">カメラ</translation>
@@ -49,14 +50,17 @@
<translation id="2212565012507486665">Cookie を許å¯</translation>
<translation id="2228071138934252756"><ph name="APP_NAME" /> ã«ã‚«ãƒ¡ãƒ©ã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ã‚’許å¯ã™ã‚‹ã«ã¯ã€<ph name="BEGIN_LINK" />Android ã®è¨­å®š<ph name="END_LINK" />ã§ã‚‚カメラをオンã«ã—ã¦ãã ã•ã„。</translation>
<translation id="2241634353105152135">一回é™ã‚Š</translation>
+<translation id="2253414712144136228"><ph name="NAME_OF_LIST_ITEM" /> を削除</translation>
<translation id="2289270750774289114">サイトã‹ã‚‰è¿‘ãã«ã‚ã‚‹ Bluetooth デãƒã‚¤ã‚¹ã®æ¤œå‡ºã‚’求ã‚られãŸã¨ãã«ç¢ºèªã™ã‚‹ï¼ˆæŽ¨å¥¨ï¼‰</translation>
<translation id="2315043854645842844">オペレーティング システムã§ã‚µãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ãªã„ãŸã‚ã€ã‚¯ãƒ©ã‚¤ã‚¢ãƒ³ãƒˆã‚µã‚¤ãƒ‰ã§è¨¼æ˜Žæ›¸ã‚’é¸æŠžã™ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“。</translation>
+<translation id="2321958826496381788">読ã¿ã‚„ã™ããªã‚‹ã¾ã§ã‚¹ãƒ©ã‚¤ãƒ€ã‚’ドラッグã—ã¦ãã ã•ã„。段è½ã‚’ダブルタップã™ã‚‹ã¨ãƒ†ã‚­ã‚¹ãƒˆãŒã“れより大ãããªã‚Šã¾ã™ã€‚</translation>
<translation id="2359808026110333948">続行</translation>
<translation id="2379925928934107488">å¯èƒ½ã§ã‚ã‚Œã°ã€Chrome ãŒãƒ€ãƒ¼ã‚¯ãƒ¢ãƒ¼ãƒ‰ã‚’使用ã—ã¦ã„ã‚‹å ´åˆã«ãƒ€ãƒ¼ã‚¯ãƒ¢ãƒ¼ãƒ‰ã‚’サイトã«é©ç”¨ã—ã¾ã™</translation>
+<translation id="2387895666653383613">テキストã®æ‹¡å¤§ã¨ç¸®å°</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />ã€<ph name="PERMISSION_2" />ã€ä»– <ph name="NUM_MORE" /> 個ã®æ¨©é™ãŒè¨±å¯ã•ã‚Œã¦ã„ã¾ã™}other{<ph name="PERMISSION_1" />ã€<ph name="PERMISSION_2" />ã€ä»– <ph name="NUM_MORE" /> 個ã®æ¨©é™ãŒè¨±å¯ã•ã‚Œã¦ã„ã¾ã™}}</translation>
<translation id="2434158240863470628">ダウンロードãŒå®Œäº†ã—ã¾ã—ãŸ<ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
-<translation id="2442870161001914531">常ã«ãƒ‡ã‚¹ã‚¯ãƒˆãƒƒãƒ—版サイトを表示ã™ã‚‹</translation>
+<translation id="2442870161001914531">常㫠PC 版サイトを表示ã™ã‚‹</translation>
<translation id="2482878487686419369">通知</translation>
<translation id="2485422356828889247">アンインストール</translation>
<translation id="2490684707762498678"><ph name="APP_NAME" /> ã§ç®¡ç†</translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">情報を表示</translation>
<translation id="3123473560110926937">一部ã®ã‚µã‚¤ãƒˆã§ãƒ–ロックã•ã‚Œã¦ã„ã¾ã™</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> ã®ä¿å­˜ãƒ‡ãƒ¼ã‚¿</translation>
+<translation id="3203366800380907218">ウェブã‹ã‚‰</translation>
<translation id="321187648315454507"><ph name="APP_NAME" /> ã«é€šçŸ¥ã®é€ä¿¡ã‚’許å¯ã™ã‚‹ã«ã¯ã€<ph name="BEGIN_LINK" />Android ã®è¨­å®š<ph name="END_LINK" />ã§ã‚‚通知をオンã«ã—ã¦ãã ã•ã„。</translation>
<translation id="3227137524299004712">マイク</translation>
<translation id="3277252321222022663">サイトã«ã‚ˆã‚‹ã‚»ãƒ³ã‚µãƒ¼ã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ã‚’許å¯ã™ã‚‹ï¼ˆæŽ¨å¥¨ï¼‰</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">デãƒã‚¤ã‚¹ã®ã‚¢ã‚¯ãƒ†ã‚£ãƒ–状態</translation>
<translation id="385051799172605136">戻る</translation>
<translation id="3859306556332390985">å‰æ–¹ã«ã‚·ãƒ¼ã‚¯å†ç”Ÿ</translation>
+<translation id="3895926599014793903">強制的ã«ã‚ºãƒ¼ãƒ ã‚’有効ã«ã™ã‚‹</translation>
<translation id="3955193568934677022">ä¿è­·ã•ã‚ŒãŸã‚³ãƒ³ãƒ†ãƒ³ãƒ„ã®å†ç”Ÿã‚’サイトã«è¨±å¯ã™ã‚‹ï¼ˆæŽ¨å¥¨ï¼‰</translation>
<translation id="3967822245660637423">ダウンロード完了</translation>
<translation id="3987993985790029246">リンクã®ã‚³ãƒ”ー</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> / ?</translation>
<translation id="4002066346123236978">タイトル</translation>
<translation id="4008040567710660924">特定ã®ã‚µã‚¤ãƒˆã® Cookie を許å¯ã—ã¾ã™ã€‚</translation>
+<translation id="4040330681741629921">サイトを簡易表示ã§ãã‚‹å ´åˆã«é€šçŸ¥ã™ã‚‹</translation>
<translation id="4046123991198612571">次ã®ãƒˆãƒ©ãƒƒã‚¯</translation>
+<translation id="4149994727733219643">ウェブページã®ç°¡æ˜“表示</translation>
<translation id="4165986682804962316">サイトã®è¨­å®š</translation>
+<translation id="4194328954146351878">サイト㌠NFC デãƒã‚¤ã‚¹ã®æƒ…報をå‚ç…§ãŠã‚ˆã³å¤‰æ›´ã™ã‚‹ã“ã¨ã‚’許å¯ã™ã‚‹å‰ã«ç¢ºèªã™ã‚‹ï¼ˆæŽ¨å¥¨ï¼‰</translation>
<translation id="4200726100658658164">ä½ç½®æƒ…å ±ã®è¨­å®šã‚’é–‹ã</translation>
<translation id="4226663524361240545">通知をå—ã‘å–ã‚‹ã¨ãƒ‡ãƒã‚¤ã‚¹ãŒæŒ¯å‹•ã—ã¾ã™</translation>
<translation id="4259722352634471385"><ph name="URL" /> ã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ãŒãƒ–ロックã•ã‚Œã¾ã—ãŸ</translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">展開</translation>
<translation id="4336434711095810371">データをã™ã¹ã¦æ¶ˆåŽ»</translation>
<translation id="4402755511846832236">サイトã«ã‚ˆã‚‹ã“ã®ãƒ‡ãƒã‚¤ã‚¹ã®ã‚¢ã‚¯ãƒ†ã‚£ãƒ–状態ã®æ¤œå‡ºã‚’ブロックã™ã‚‹</translation>
+<translation id="4428065317363009941">広告ã®ã‚«ã‚¹ã‚¿ãƒžã‚¤ã‚º</translation>
<translation id="4434045419905280838">ãƒãƒƒãƒ—アップã¨ãƒªãƒ€ã‚¤ãƒ¬ã‚¯ãƒˆ</translation>
<translation id="445467742685312942">ä¿è­·ã•ã‚ŒãŸã‚³ãƒ³ãƒ†ãƒ³ãƒ„ã®å†ç”Ÿã‚’サイトã«è¨±å¯ã™ã‚‹</translation>
<translation id="4468959413250150279">特定ã®ã‚µã‚¤ãƒˆã®éŸ³å£°ã‚’ミュートã—ã¾ã™ã€‚</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">設定ã¯ç”»é¢ä¸Šéƒ¨ã«ã‚ã‚Šã¾ã™</translation>
<translation id="5197729504361054390">é¸æŠžã—ãŸé€£çµ¡å…ˆãŒ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ã¨å…±æœ‰ã•ã‚Œã¾ã™ã€‚</translation>
<translation id="5216942107514965959">最終アクセス日: 今日</translation>
+<translation id="5264323282659631142"><ph name="CHIP_LABEL" /> を削除</translation>
<translation id="528192093759286357">全画é¢è¡¨ç¤ºã‚’終了ã™ã‚‹ã«ã¯ã€ä¸Šã‹ã‚‰ãƒ‰ãƒ©ãƒƒã‚°ã—ã¦ã€æˆ»ã‚‹ãƒœã‚¿ãƒ³ã‚’タップã—ã¾ã™ã€‚</translation>
<translation id="5300589172476337783">表示</translation>
<translation id="5301954838959518834">OK</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">サイトã«ã‚ˆã‚Šä¿å­˜ã•ã‚ŒãŸ <ph name="DATASIZE" /> ã®ãƒ‡ãƒ¼ã‚¿ã¨ Cookie ãŒå‰Šé™¤ã•ã‚Œã¾ã™ã€‚</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(他 1 件)}other{(他 # 件)}}</translation>
<translation id="5403592356182871684">åå‰</translation>
+<translation id="5412236728747081950">ã“ã®ã‚µã‚¤ãƒˆã§ã¯ Chrome ã‹ã‚‰ãŠå®¢æ§˜ã®èˆˆå‘³ã‚„関心ã«é–¢ã™ã‚‹æƒ…報をå–å¾—ã—ã¦ã€é–¢é€£æ€§ã®é«˜ã„広告を表示ã—ã¦ã„ã¾ã™</translation>
<translation id="5438097262470833822">ã“れをé¸æŠžã™ã‚‹ã¨ã€<ph name="WEBSITE" /> ã®æ¨©é™ãŒãƒªã‚»ãƒƒãƒˆã•ã‚Œã¾ã™</translation>
<translation id="5489227211564503167"><ph name="TOTAL_TIME" /> ã®ã†ã¡ <ph name="ELAPSED_TIME" /> 経éŽã—ã¾ã—ãŸã€‚</translation>
<translation id="5494752089476963479">ç…©ã‚ã—ã„広告や誤解を招ã広告ãŒè¡¨ç¤ºã•ã‚Œã‚‹ã‚µã‚¤ãƒˆã§åºƒå‘Šã‚’ブロックã™ã‚‹</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">å†èª­ã¿è¾¼ã¿</translation>
<translation id="5596627076506792578">ãã®ä»–ã®ã‚ªãƒ—ション</translation>
<translation id="5649053991847567735">自動ダウンロード</translation>
+<translation id="5668404140385795438">ウェブサイトã®ã‚ºãƒ¼ãƒ é˜²æ­¢ãƒªã‚¯ã‚¨ã‚¹ãƒˆã‚’上書ãã—ã¾ã™</translation>
<translation id="5677928146339483299">ブロック中</translation>
<translation id="5689516760719285838">ä½ç½®æƒ…å ±</translation>
<translation id="5690795753582697420">Android ã®è¨­å®šã§ã‚«ãƒ¡ãƒ©ãŒã‚ªãƒ•ã«ãªã£ã¦ã„ã¾ã™</translation>
-<translation id="5710871682236653961">NFC デãƒã‚¤ã‚¹ã‚’タップã—ãŸã¨ãã€æƒ…å ±ã®é€å—信をサイトã«è¨±å¯ã™ã‚‹ã‹ã©ã†ã‹ã‚’確èªã™ã‚‹ï¼ˆæŽ¨å¥¨ï¼‰</translation>
<translation id="5719847187258001597"><ph name="ORIGIN" /> ã¾ãŸã¯ãƒ›ãƒ¼ãƒ ç”»é¢ã®åŒã‚¢ãƒ—リã«ã‚ˆã‚Šä¿å­˜ã•ã‚ŒãŸã™ã¹ã¦ã®ãƒ‡ãƒ¼ã‚¿ãŠã‚ˆã³ Cookie ãŒå‰Šé™¤ã•ã‚Œã¾ã™ã€‚</translation>
<translation id="5771720122942595109"><ph name="PERMISSION_1" />をブロック</translation>
<translation id="5804241973901381774">権é™</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">å†ç”Ÿ</translation>
<translation id="6818926723028410516">アイテムをé¸æŠž</translation>
<translation id="6864395892908308021">ã“ã®ãƒ‡ãƒã‚¤ã‚¹ã§ã¯ NFC を読ã¿è¾¼ã‚ã¾ã›ã‚“</translation>
-<translation id="6910211073230771657">削除済ã¿</translation>
<translation id="6912998170423641340">サイトã«ã‚ˆã‚‹ã‚¯ãƒªãƒƒãƒ—ボードã®ãƒ†ã‚­ã‚¹ãƒˆã‚„ç”»åƒã®èª­ã¿å–りをブロックã™ã‚‹</translation>
<translation id="6945221475159498467">é¸æŠž</translation>
<translation id="6965382102122355670">OK</translation>
+<translation id="6981982820502123353">ユーザー補助機能</translation>
<translation id="6992289844737586249">サイトã«ãƒžã‚¤ã‚¯ã®ä½¿ç”¨ã‚’許å¯ã™ã‚‹å‰ã«ç¢ºèªã™ã‚‹ï¼ˆæŽ¨å¥¨ï¼‰</translation>
<translation id="7000754031042624318">Android ã®è¨­å®šã§ç„¡åŠ¹</translation>
<translation id="7016516562562142042">ç¾åœ¨ã®æ¤œç´¢ã‚¨ãƒ³ã‚¸ãƒ³ã«å¯¾ã—ã¦è¨±å¯</translation>
+<translation id="702463548815491781">TalkBack ã¾ãŸã¯ã‚¹ã‚¤ãƒƒãƒ アクセスを有効ã«ã—ã¦ã„ã‚‹å ´åˆã«ãŠã™ã™ã‚ã§ã™</translation>
<translation id="7053983685419859001">ブロック</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1 件をé¸æŠžæ¸ˆã¿}other{# 件をé¸æŠžæ¸ˆã¿}}</translation>
-<translation id="7070090581017165256">ã“ã®ã‚µã‚¤ãƒˆã«ã¤ã„ã¦</translation>
<translation id="7087918508125750058"><ph name="ITEM_COUNT" /> 件é¸æŠžã•ã‚Œã¦ã„ã¾ã™ã€‚オプションã¯ç”»é¢ä¸Šéƒ¨ã«ã‚ã‚Šã¾ã™</translation>
<translation id="7141896414559753902">サイトã§ã®ãƒãƒƒãƒ—アップ表示ã¨ãƒªãƒ€ã‚¤ãƒ¬ã‚¯ãƒˆã‚’ブロックã™ã‚‹ï¼ˆæŽ¨å¥¨ï¼‰</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> KB</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">サイトã§ãƒžã‚¤ã‚¯ãŒä½¿ç”¨ã•ã‚Œã¦ã„ã¾ã™</translation>
<translation id="7561196759112975576">常ã«ä½¿ç”¨</translation>
-<translation id="7572498721684305250">NFC デãƒã‚¤ã‚¹ã‚’タップã—ãŸã¨ãã€ã‚µã‚¤ãƒˆã«ã‚ˆã‚‹æƒ…å ±ã®é€å—信をブロックã™ã‚‹</translation>
<translation id="757524316907819857">サイトã§ã®ä¿è­·ã•ã‚ŒãŸã‚³ãƒ³ãƒ†ãƒ³ãƒ„ã®å†ç”Ÿã‚’ブロックã™ã‚‹</translation>
+<translation id="7577900504646297215">興味ã®ã‚るトピックを管ç†</translation>
<translation id="7649070708921625228">ヘルプ</translation>
<translation id="7658239707568436148">キャンセル</translation>
<translation id="7781829728241885113">昨日</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">ã“ã®æŽ¥ç¶šã¯ä¿è­·ã•ã‚Œã¦ã„ã¾ã™</translation>
<translation id="8249310407154411074">一番上ã«ç§»å‹•</translation>
<translation id="8261506727792406068">削除</translation>
+<translation id="8284326494547611709">字幕</translation>
<translation id="8300705686683892304">アプリã«ã‚ˆã‚‹ç®¡ç†</translation>
<translation id="8324158725704657629">次回ã‹ã‚‰è¡¨ç¤ºã—ãªã„</translation>
<translation id="8372893542064058268">特定ã®ã‚µã‚¤ãƒˆã«å¯¾ã—ã¦ãƒãƒƒã‚¯ã‚°ãƒ©ã‚¦ãƒ³ãƒ‰åŒæœŸã‚’許å¯ã—ã¾ã™ã€‚</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">拡大ã™ã‚‹</translation>
<translation id="8921772741368021346"><ph name="POSITION" /> / <ph name="DURATION" /></translation>
<translation id="8926666909099850184">ã“ã®ãƒ‡ãƒã‚¤ã‚¹ã§ã¯ NFC ãŒã‚ªãƒ•ã«ãªã£ã¦ã„ã¾ã™ã€‚<ph name="BEGIN_LINK" />Android ã®è¨­å®š<ph name="END_LINK" />ã§ã‚ªãƒ³ã«ã—ã¦ãã ã•ã„。</translation>
+<translation id="8928445016601307354">サイト㌠NFC デãƒã‚¤ã‚¹ã®æƒ…報をå‚ç…§ãŠã‚ˆã³å¤‰æ›´ã™ã‚‹ã“ã¨ã‚’ブロックã™ã‚‹</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">特定ã®ã‚µã‚¤ãƒˆã® Cookie をブロックã—ã¾ã™ã€‚</translation>
<translation id="8959122750345127698"><ph name="URL" /> ã«ã‚¢ã‚¯ã‚»ã‚¹ã§ãã¾ã›ã‚“</translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ka.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ka.xtb
index 81aed9bfd91..210cadf3c5c 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ka.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ka.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">სáƒáƒ˜áƒ¢áƒ˜: <ph name="SITE_NAME" /> დáƒáƒ›áƒáƒ¢áƒ”ბულიáƒ</translation>
<translation id="1383876407941801731">ძიებáƒ</translation>
<translation id="1384959399684842514">ჩáƒáƒ›áƒáƒ¢áƒ•áƒ˜áƒ áƒ—ვრდáƒáƒžáƒáƒ£áƒ–ებულიáƒ</translation>
+<translation id="1409426117486808224">გáƒáƒ›áƒáƒ áƒ¢áƒ˜áƒ•áƒ”ბული ხედი გáƒáƒ®áƒ¡áƒœáƒ˜áƒšáƒ˜ ჩáƒáƒœáƒáƒ áƒ—ებისთვის</translation>
<translation id="1415402041810619267">URL შემáƒáƒ™áƒšáƒ”ბულიáƒ</translation>
<translation id="1446450296470737166">MIDI მáƒáƒ¬áƒ§. სრული კáƒáƒœáƒ¢. დáƒáƒ¨áƒ•áƒ”ბáƒ</translation>
<translation id="1620510694547887537">კáƒáƒ›áƒ”რáƒ</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">ქუქი-ჩáƒáƒœáƒáƒ¬áƒ”რების დáƒáƒ¨áƒ•áƒ”ბáƒ</translation>
<translation id="2228071138934252756"><ph name="APP_NAME" />-მრკáƒáƒ›áƒ”რით რáƒáƒ› ისáƒáƒ áƒ’ებლáƒáƒ¡, გáƒáƒáƒáƒ¥áƒ¢áƒ˜áƒ£áƒ áƒ”თ კáƒáƒ›áƒ”რáƒáƒ–ე წვდáƒáƒ›áƒ˜áƒ¡ ნებáƒáƒ áƒ—ვáƒáƒª <ph name="BEGIN_LINK" />Android-ის პáƒáƒ áƒáƒ›áƒ”ტრებიდáƒáƒœ<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">მხáƒáƒšáƒáƒ“ ერთხელ</translation>
+<translation id="2253414712144136228"><ph name="NAME_OF_LIST_ITEM" /> — áƒáƒ›áƒáƒ¨áƒšáƒ</translation>
<translation id="2289270750774289114">სáƒáƒ˜áƒ¢áƒ”ბის მიერ áƒáƒ®áƒšáƒáƒ›áƒ“ებáƒáƒ áƒ” Bluetooth მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘ების áƒáƒ¦áƒ›áƒáƒ©áƒ”ნის მáƒáƒ—ხáƒáƒ•áƒœáƒ (რეკáƒáƒ›áƒ”ნდებული)</translation>
<translation id="2315043854645842844">კლიენტის სერტიფიკáƒáƒ¢áƒ”ბის áƒáƒ áƒ©áƒ”ვრáƒáƒ  áƒáƒ áƒ˜áƒ¡ მხáƒáƒ áƒ“áƒáƒ­áƒ”რილი áƒáƒžáƒ”რáƒáƒªáƒ˜áƒ£áƒšáƒ˜ სისტემის მიერ.</translation>
+<translation id="2321958826496381788">გáƒáƒ“áƒáƒáƒ—რიეთ ცáƒáƒªáƒ˜áƒ, რáƒáƒ—რáƒáƒ˜áƒ áƒ©áƒ˜áƒáƒ— კითხვისთვის ყველáƒáƒ–ე მáƒáƒ¡áƒáƒ®áƒ”რხებელი შრიფტის ზáƒáƒ›áƒ. áƒáƒ‘ზáƒáƒªáƒ–ე áƒáƒ áƒ¯áƒ”რ შეხების შედეგáƒáƒ“ ტექსტი უნდრგáƒáƒ“იდდეს áƒáƒ› ზáƒáƒ›áƒáƒ›áƒ“ე.</translation>
<translation id="2359808026110333948">გáƒáƒ’რძელებáƒ</translation>
<translation id="2379925928934107488">სáƒáƒ˜áƒ¢áƒ”ბზე მუქი თემის გáƒáƒ›áƒáƒ§áƒ”ნებáƒ, რáƒáƒªáƒ Chrome მუქ თემáƒáƒ¡ იყენებს (შეძლებისდáƒáƒ’ვáƒáƒ áƒáƒ“)</translation>
+<translation id="2387895666653383613">ტექსტის მáƒáƒ¡áƒ¨áƒ¢áƒáƒ‘ირებáƒ</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> მბáƒáƒ˜áƒ¢áƒ˜</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> დრ<ph name="NUM_MORE" /> სხვრდáƒáƒ¨áƒ•áƒ”ბულიáƒ}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> დრ<ph name="NUM_MORE" /> სხვრდáƒáƒ¨áƒ•áƒ”ბულიáƒ}}</translation>
<translation id="2434158240863470628">ჩáƒáƒ›áƒáƒ¢áƒ•áƒ˜áƒ áƒ—ვრდáƒáƒ¡áƒ áƒ£áƒšáƒ“áƒ: <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ˜áƒ¡ ჩვენებáƒ</translation>
<translation id="3123473560110926937">დáƒáƒ‘ლáƒáƒ™áƒ˜áƒšáƒ˜áƒ ზáƒáƒ’იერთ სáƒáƒ˜áƒ¢áƒ–ე</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> შენáƒáƒ®áƒ£áƒšáƒ˜ მáƒáƒœáƒáƒªáƒ”მები</translation>
+<translation id="3203366800380907218">ვებიდáƒáƒœ</translation>
<translation id="321187648315454507"><ph name="APP_NAME" />-მრშეტყáƒáƒ‘ინებები რáƒáƒ› გáƒáƒ›áƒáƒ’იგზáƒáƒ•áƒœáƒáƒ—, გáƒáƒáƒáƒ¥áƒ¢áƒ˜áƒ£áƒ áƒ”თ შეტყáƒáƒ‘ინებებზე წვდáƒáƒ›áƒ˜áƒ¡ ნებáƒáƒ áƒ—ვáƒáƒª <ph name="BEGIN_LINK" />Android-ის პáƒáƒ áƒáƒ›áƒ”ტრებიდáƒáƒœ<ph name="END_LINK" />.</translation>
<translation id="3227137524299004712">მიკრáƒáƒ¤áƒáƒœáƒ˜</translation>
<translation id="3277252321222022663">სáƒáƒ˜áƒ¢áƒ”ბისთვის სენსáƒáƒ áƒ”ბზე წვდáƒáƒ›áƒ˜áƒ¡ დáƒáƒ¨áƒ•áƒ”ბრ(რეკáƒáƒ›áƒ”ნდებული)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">თქვენი მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘ის გáƒáƒ›áƒáƒ§áƒ”ნებáƒ</translation>
<translation id="385051799172605136">უკáƒáƒœ</translation>
<translation id="3859306556332390985">წინ ძიებáƒ</translation>
+<translation id="3895926599014793903">გáƒáƒ“იდების იძულებით ჩáƒáƒ áƒ—ვáƒ</translation>
<translation id="3955193568934677022">ვებსáƒáƒ˜áƒ¢áƒ”ბისთვის დáƒáƒªáƒ£áƒšáƒ˜ კáƒáƒœáƒ¢áƒ”ნტის დáƒáƒ™áƒ•áƒ áƒ˜áƒ¡ დáƒáƒ¨áƒ•áƒ”ბრ(რეკáƒáƒ›áƒ”ნდებული)</translation>
<translation id="3967822245660637423">ჩáƒáƒ›áƒáƒ¢áƒ•áƒ˜áƒ áƒ—ვრდáƒáƒ¡áƒ áƒ£áƒšáƒ“áƒ</translation>
<translation id="3987993985790029246">ბმულის კáƒáƒžáƒ˜áƒ áƒ”ბáƒ</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> / ?</translation>
<translation id="4002066346123236978">სáƒáƒ—áƒáƒ£áƒ áƒ˜</translation>
<translation id="4008040567710660924">ქუქი-ჩáƒáƒœáƒáƒ¬áƒ”რების დáƒáƒ¨áƒ•áƒ”ბრკáƒáƒœáƒ™áƒ áƒ”ტული სáƒáƒ˜áƒ¢áƒ˜áƒ¡áƒ—ვის.</translation>
+<translation id="4040330681741629921">შეტყáƒáƒ‘ინების მიღებáƒ, რáƒáƒªáƒ სáƒáƒ˜áƒ¢áƒ˜áƒ¡ ჩვენებრშესáƒáƒ«áƒšáƒ”ბელირგáƒáƒ›áƒáƒ áƒ¢áƒ˜áƒ•áƒ”ბული ხედით</translation>
<translation id="4046123991198612571">შემდეგი ჩáƒáƒœáƒáƒ¬áƒ”რი</translation>
+<translation id="4149994727733219643">გáƒáƒ›áƒáƒ áƒ¢áƒ˜áƒ•áƒ”ბული ხედი ვებგვერდებისთვის</translation>
<translation id="4165986682804962316">სáƒáƒ˜áƒ¢áƒ˜áƒ¡ პáƒáƒ áƒáƒ›áƒ”ტრები</translation>
+<translation id="4194328954146351878">შეკითხვრსáƒáƒ˜áƒ¢áƒ”ბისთვის NFC მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘ებზე ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒáƒ–ე წვდáƒáƒ›áƒ˜áƒ¡áƒ დრმისი შეცვლის დáƒáƒ¨áƒ•áƒ”ბáƒáƒ›áƒ“ე (რეკáƒáƒ›áƒ”ნდებული)</translation>
<translation id="4200726100658658164">მდებáƒáƒ áƒ”áƒáƒ‘ის პáƒáƒ áƒáƒ›áƒ”ტრების გáƒáƒ®áƒ¡áƒœáƒ</translation>
<translation id="4226663524361240545">შეტყáƒáƒ‘ინებებმრშეიძლებრმáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘ის ვიბრáƒáƒªáƒ˜áƒ გáƒáƒ›áƒáƒ˜áƒ¬áƒ•áƒ˜áƒáƒ¡</translation>
<translation id="4259722352634471385">ნáƒáƒ•áƒ˜áƒ’áƒáƒªáƒ˜áƒ დáƒáƒ‘ლáƒáƒ™áƒ˜áƒšáƒ˜áƒ: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">გáƒáƒ¨áƒšáƒ</translation>
<translation id="4336434711095810371">ყველრმáƒáƒœáƒáƒªáƒ”მის გáƒáƒ¡áƒ£áƒ¤áƒ—áƒáƒ•áƒ”ბáƒ</translation>
<translation id="4402755511846832236">სáƒáƒ˜áƒ¢áƒ”ბისთვის áƒáƒ› მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘ის áƒáƒ¥áƒ¢áƒ˜áƒ£áƒ áƒáƒ“ გáƒáƒ›áƒáƒ§áƒ”ნების შესáƒáƒ®áƒ”ბ ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ˜áƒ¡ მიღების დáƒáƒ‘ლáƒáƒ™áƒ•áƒ</translation>
+<translation id="4428065317363009941">რეკლáƒáƒ›áƒ˜áƒ¡ პერსáƒáƒœáƒáƒšáƒ˜áƒ–ებáƒ</translation>
<translation id="4434045419905280838">áƒáƒ›áƒáƒ›áƒ®. ფáƒáƒœáƒ¯áƒ áƒ”ბი/გáƒáƒ“áƒáƒ›áƒ˜áƒ¡áƒáƒ›áƒáƒ áƒ—ებáƒ</translation>
<translation id="445467742685312942">სáƒáƒ˜áƒ¢áƒ”ბისთვის დáƒáƒªáƒ£áƒšáƒ˜ კáƒáƒœáƒ¢áƒ”ნტის დáƒáƒ™áƒ•áƒ áƒ˜áƒ¡ დáƒáƒ¨áƒ•áƒ”ბáƒ</translation>
<translation id="4468959413250150279">ხმის დáƒáƒ“უმებრკáƒáƒœáƒ™áƒ áƒ”ტული სáƒáƒ˜áƒ¢áƒ˜áƒ¡áƒ—ვის.</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">ვáƒáƒ áƒ˜áƒáƒœáƒ¢áƒ˜ ხელმისáƒáƒ¬áƒ•áƒ“áƒáƒ›áƒ˜áƒ ეკრáƒáƒœáƒ˜áƒ¡ ზედრნáƒáƒ¬áƒ˜áƒšáƒ—áƒáƒœ</translation>
<translation id="5197729504361054390">თქვენ მიერ áƒáƒ áƒ©áƒ”ული კáƒáƒœáƒ¢áƒáƒ¥áƒ¢áƒ”ბი გáƒáƒ–იáƒáƒ áƒ“ებრ<ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />-თáƒáƒœ.</translation>
<translation id="5216942107514965959">ბáƒáƒšáƒ ვიზიტი იყრდღეს</translation>
+<translation id="5264323282659631142">„<ph name="CHIP_LABEL" />“-ის áƒáƒ›áƒáƒ¨áƒšáƒ</translation>
<translation id="528192093759286357">სრულეკრáƒáƒœáƒ˜áƒáƒœáƒ˜ რეჟიმიდáƒáƒœ გáƒáƒ›áƒáƒ¡áƒáƒ¡áƒ•áƒšáƒ”ლáƒáƒ“, გáƒáƒ£áƒ¡áƒ•áƒ˜áƒ— ეკრáƒáƒœáƒ¡ თითი ზემáƒáƒ“áƒáƒœ ქვემáƒáƒ— დრშეეხეთ ღილáƒáƒ™áƒ¡ „უკáƒáƒœâ€œ.</translation>
<translation id="5300589172476337783">ჩვენებáƒ</translation>
<translation id="5301954838959518834">კáƒáƒ áƒ’ი, გáƒáƒ¡áƒáƒ’ებიáƒ</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">áƒáƒ› მáƒáƒ¥áƒ›áƒ”დებით გáƒáƒ¡áƒ£áƒ¤áƒ—áƒáƒ•áƒ“ებრსáƒáƒ˜áƒ¢áƒ”ბის მიერ შენáƒáƒ®áƒ£áƒšáƒ˜ მáƒáƒœáƒáƒªáƒ”მებისრდრქუქი-ჩáƒáƒœáƒáƒ¬áƒ”რების <ph name="DATASIZE" />.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(+ 1 სხვáƒ)}other{(+ # სხვáƒ)}}</translation>
<translation id="5403592356182871684">სáƒáƒ®áƒ”ლები</translation>
+<translation id="5412236728747081950">ეს სáƒáƒ˜áƒ¢áƒ˜ Chrome-იდáƒáƒœ იღებს ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒáƒ¡ თქვენი ინტერესების შესáƒáƒ®áƒ”ბ, უფრრშესáƒáƒ¤áƒ”რისი რეკლáƒáƒ›áƒ რáƒáƒ› შემáƒáƒ’თáƒáƒ•áƒáƒ–áƒáƒ—</translation>
<translation id="5438097262470833822">ეს áƒáƒ áƒ©áƒ”ვáƒáƒœáƒ˜ გáƒáƒ“áƒáƒáƒ§áƒ”ნებს ნებáƒáƒ áƒ—ვებს <ph name="WEBSITE" />-ისთვის</translation>
<translation id="5489227211564503167">გáƒáƒ•áƒ˜áƒ“რ<ph name="ELAPSED_TIME" /> / <ph name="TOTAL_TIME" />-დáƒáƒœ.</translation>
<translation id="5494752089476963479">რეკლáƒáƒ›áƒ˜áƒ¡ დáƒáƒ‘ლáƒáƒ™áƒ•áƒ იმ სáƒáƒ˜áƒ¢áƒ”ბზე, რáƒáƒ›áƒšáƒ”ბიც áƒáƒ©áƒ•áƒ”ნებს მáƒáƒ›áƒáƒ‘ეზრებელ áƒáƒœ შეცდáƒáƒ›áƒáƒ¨áƒ˜ შემყვáƒáƒœ რეკლáƒáƒ›áƒáƒ¡</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">ხელáƒáƒ®áƒšáƒ ჩáƒáƒ¢áƒ•áƒ˜áƒ áƒ—ვáƒ</translation>
<translation id="5596627076506792578">დáƒáƒ›áƒáƒ¢áƒ”ბითი ვáƒáƒ áƒ˜áƒáƒœáƒ¢áƒ”ბი</translation>
<translation id="5649053991847567735">áƒáƒ•áƒ¢áƒáƒ›áƒáƒ¢áƒ£áƒ áƒ˜ ჩáƒáƒ›áƒáƒ¢áƒ•áƒ˜áƒ áƒ—ვები</translation>
+<translation id="5668404140385795438">ვებსáƒáƒ˜áƒ¢áƒ˜áƒ¡ მიერ მáƒáƒ¡áƒ¨áƒ¢áƒáƒ‘ირების áƒáƒ™áƒ áƒ«áƒáƒšáƒ•áƒ˜áƒ¡ გáƒáƒ£áƒ¥áƒ›áƒ”ბáƒ</translation>
<translation id="5677928146339483299">დáƒáƒ‘ლáƒáƒ™áƒ˜áƒšáƒ˜</translation>
<translation id="5689516760719285838">მდებáƒáƒ áƒ”áƒáƒ‘áƒ</translation>
<translation id="5690795753582697420">კáƒáƒ›áƒ”რრგáƒáƒ›áƒáƒ áƒ—ულირAndroid-ის პáƒáƒ áƒáƒ›áƒ”ტრებში</translation>
-<translation id="5710871682236653961">შეკითხვრNFC მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘áƒáƒ–ე შეხებისáƒáƒ¡ სáƒáƒ˜áƒ¢áƒ”ბისთვის ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ˜áƒ¡ გáƒáƒ’ზáƒáƒ•áƒœáƒ˜áƒ¡áƒ დრმიღების დáƒáƒ¨áƒ•áƒ”ბáƒáƒ›áƒ“ე (რეკáƒáƒ›áƒ”ნდებული)</translation>
<translation id="5719847187258001597">áƒáƒ› მáƒáƒ¥áƒ›áƒ”დებით გáƒáƒ¡áƒ£áƒ¤áƒ—áƒáƒ•áƒ“ებრ<ph name="ORIGIN" />-ის áƒáƒœ მისი áƒáƒžáƒ˜áƒ¡ მიერ თქვენს მთáƒáƒ•áƒáƒ  ეკრáƒáƒœáƒ–ე შენáƒáƒ®áƒ£áƒšáƒ˜ ყველრმáƒáƒœáƒáƒªáƒ”მი.</translation>
<translation id="5771720122942595109"><ph name="PERMISSION_1" /> დáƒáƒ‘ლáƒáƒ™áƒ˜áƒšáƒ˜áƒ</translation>
<translation id="5804241973901381774">ნებáƒáƒ áƒ—ვები</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">დáƒáƒ™áƒ•áƒ áƒ</translation>
<translation id="6818926723028410516">áƒáƒ˜áƒ áƒ©áƒ˜áƒ”თ ერთეულები</translation>
<translation id="6864395892908308021">NFC მხáƒáƒ áƒ“áƒáƒ£áƒ­áƒ”რელირáƒáƒ› მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘ის მიერ</translation>
-<translation id="6910211073230771657">წáƒáƒ¨áƒšáƒ˜áƒšáƒ˜</translation>
<translation id="6912998170423641340">სáƒáƒ˜áƒ¢áƒ”ბისთვის გáƒáƒªáƒ•áƒšáƒ˜áƒ¡ ბუფერში áƒáƒ áƒ¡áƒ”ბულ ტექსტსრდრსურáƒáƒ—ებზე წვდáƒáƒ›áƒ˜áƒ¡ დáƒáƒ‘ლáƒáƒ™áƒ•áƒ</translation>
<translation id="6945221475159498467">áƒáƒ áƒ©áƒ”ვáƒ</translation>
<translation id="6965382102122355670">კáƒáƒ áƒ’ი</translation>
+<translation id="6981982820502123353">სპეციáƒáƒšáƒ£áƒ áƒ˜ შესáƒáƒ«áƒšáƒ”ბლáƒáƒ‘ები</translation>
<translation id="6992289844737586249">შეკითხვრსáƒáƒ˜áƒ¢áƒ”ბისთვის თქვენი მიკრáƒáƒ¤áƒáƒœáƒ˜áƒ¡ გáƒáƒ›áƒáƒ§áƒ”ნების დáƒáƒ¨áƒ•áƒ”ბáƒáƒ›áƒ“ე (რეკáƒáƒ›áƒ”ნდებული)</translation>
<translation id="7000754031042624318">გáƒáƒ›áƒáƒ áƒ—ულირAndroid-ის პáƒáƒ áƒáƒ›áƒ”ტრებიდáƒáƒœ</translation>
<translation id="7016516562562142042">დáƒáƒ¨áƒ•áƒ”ბულირáƒáƒ›áƒŸáƒáƒ›áƒ˜áƒœáƒ“ელი სáƒáƒ«áƒ˜áƒ”ბრსისტემისთვის</translation>
+<translation id="702463548815491781">რეკáƒáƒ›áƒ”ნდებულიáƒ, რáƒáƒªáƒ ჩáƒáƒ áƒ—ულირTalkBack áƒáƒœ გáƒáƒ“áƒáƒ›áƒ áƒ—ველით წვდáƒáƒ›áƒ</translation>
<translation id="7053983685419859001">დáƒáƒ‘ლáƒáƒ™áƒ•áƒ</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{áƒáƒ áƒ©áƒ”ულირ1}other{áƒáƒ áƒ©áƒ”ულირ#}}</translation>
-<translation id="7070090581017165256">áƒáƒ› სáƒáƒ˜áƒ¢áƒ˜áƒ¡ შესáƒáƒ®áƒ”ბ</translation>
<translation id="7087918508125750058">áƒáƒ áƒ©áƒ”ულირ<ph name="ITEM_COUNT" />. ვáƒáƒ áƒ˜áƒáƒœáƒ¢áƒ”ბი ხელმისáƒáƒ¬áƒ•áƒ“áƒáƒ›áƒ˜áƒ ეკრáƒáƒœáƒ˜áƒ¡ ზედრნáƒáƒ¬áƒ˜áƒšáƒ—áƒáƒœ</translation>
<translation id="7141896414559753902">სáƒáƒ˜áƒ¢áƒ”ბისთვის გáƒáƒ“áƒáƒ›áƒ˜áƒ¡áƒáƒ›áƒáƒ áƒ—ებისრდრáƒáƒ›áƒáƒ›áƒ®áƒ¢áƒáƒ áƒ˜ ფáƒáƒœáƒ¯áƒ áƒ”ბის ჩვენების დáƒáƒ‘ლáƒáƒ™áƒ•áƒ (რეკáƒáƒ›áƒ”ნდებული)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> კბáƒáƒ˜áƒ¢áƒ˜</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">ეს სáƒáƒ˜áƒ¢áƒ˜ იყენებს თქვენს მიკრáƒáƒ¤áƒáƒœáƒ¡</translation>
<translation id="7561196759112975576">ყáƒáƒ•áƒ”ლთვის</translation>
-<translation id="7572498721684305250">NFC მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘áƒáƒ–ე შეხებისáƒáƒ¡ ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ˜áƒ¡ გáƒáƒ’ზáƒáƒ•áƒœáƒ˜áƒ¡áƒ დრმიღების დáƒáƒ‘ლáƒáƒ™áƒ•áƒ სáƒáƒ˜áƒ¢áƒ”ბისთვის</translation>
<translation id="757524316907819857">სáƒáƒ˜áƒ¢áƒ”ბისთვის დáƒáƒªáƒ£áƒšáƒ˜ კáƒáƒœáƒ¢áƒ”ნტის დáƒáƒ™áƒ•áƒ áƒ˜áƒ¡ დáƒáƒ‘ლáƒáƒ™áƒ•áƒ</translation>
+<translation id="7577900504646297215">ინტერესების მáƒáƒ áƒ—ვáƒ</translation>
<translation id="7649070708921625228">დáƒáƒ®áƒ›áƒáƒ áƒ”ბáƒ</translation>
<translation id="7658239707568436148">გáƒáƒ£áƒ¥áƒ›áƒ”ბáƒ</translation>
<translation id="7781829728241885113">გუშინ</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">კáƒáƒ•áƒ¨áƒ˜áƒ áƒ˜ დáƒáƒªáƒ£áƒšáƒ˜áƒ</translation>
<translation id="8249310407154411074">თáƒáƒ•áƒ¨áƒ˜ გáƒáƒ“áƒáƒ¢áƒáƒœáƒ</translation>
<translation id="8261506727792406068">წáƒáƒ¨áƒšáƒ</translation>
+<translation id="8284326494547611709">ტიტრები</translation>
<translation id="8300705686683892304">იმáƒáƒ áƒ—ებრáƒáƒžáƒ˜áƒ¡ მიერ</translation>
<translation id="8324158725704657629">áƒáƒ¦áƒáƒ  მკითხáƒ</translation>
<translation id="8372893542064058268">კáƒáƒœáƒ™áƒ áƒ”ტული სáƒáƒ˜áƒ¢áƒ˜áƒ¡áƒ—ვის ფáƒáƒœáƒ£áƒ áƒ˜ სინქრáƒáƒœáƒ˜áƒ–áƒáƒªáƒ˜áƒ˜áƒ¡ დáƒáƒ¨áƒ•áƒ”ბáƒ.</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">მáƒáƒ¡áƒ¨áƒ¢áƒáƒ‘ის გáƒáƒ“იდებáƒ</translation>
<translation id="8921772741368021346"><ph name="POSITION" /> / <ph name="DURATION" /></translation>
<translation id="8926666909099850184">NFC გáƒáƒ›áƒáƒ áƒ—ულირáƒáƒ› მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘ისთვის. მისი ჩáƒáƒ áƒ—ვრშეგიძლიáƒáƒ— <ph name="BEGIN_LINK" />Android-ის პáƒáƒ áƒáƒ›áƒ”ტრებიდáƒáƒœ<ph name="END_LINK" />.</translation>
+<translation id="8928445016601307354">áƒáƒ”კრძáƒáƒšáƒáƒ¡ სáƒáƒ˜áƒ¢áƒ”ბს ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒáƒ–ე წვდáƒáƒ›áƒ დრმისი შეცვლრNFC მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘ებზე</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">ქუქი-ჩáƒáƒœáƒáƒ¬áƒ”რების დáƒáƒ‘ლáƒáƒ™áƒ•áƒ კáƒáƒœáƒ™áƒ áƒ”ტული სáƒáƒ˜áƒ¢áƒ˜áƒ¡áƒ—ვის.</translation>
<translation id="8959122750345127698">ნáƒáƒ•áƒ˜áƒ’áƒáƒªáƒ˜áƒ მიუწვდáƒáƒ›áƒ”ლიáƒ: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_kk.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_kk.xtb
index 8acfa66ed5a..a828b635c4b 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_kk.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_kk.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676"><ph name="SITE_NAME" /> Ñайты қоÑылды</translation>
<translation id="1383876407941801731">Іздеу</translation>
<translation id="1384959399684842514">Жүктеу кідіртілді</translation>
+<translation id="1409426117486808224">Ðшық қойындылардың қарапайым көрініÑÑ–</translation>
<translation id="1415402041810619267">URL қыÑқартылды</translation>
<translation id="1446450296470737166">MIDI толық бақылауға Ñ€Ò±Ò›Ñат беру</translation>
<translation id="1620510694547887537">Камера</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">Cookie файлдарына Ñ€Ò±Ò›Ñат беру</translation>
<translation id="2228071138934252756"><ph name="APP_NAME" /> браузері камераны пайдалануы үшін, <ph name="BEGIN_LINK" />Android параметрлерінде<ph name="END_LINK" /> оны да қоÑыңыз.</translation>
<translation id="2241634353105152135">Бір-ақ рет</translation>
+<translation id="2253414712144136228"><ph name="NAME_OF_LIST_ITEM" /> Ñлементін жою</translation>
<translation id="2289270750774289114">Сайт маңайдағы Bluetooth құрылғыларын анықтағыÑÑ‹ келген кезде, Ñ€Ò±Ò›Ñат ÑұралÑын (Ò±Ñынылады).</translation>
<translation id="2315043854645842844">ОперациÑлық жүйе клиенттік Ñертификатты таңдауға қолдау көрÑетпейді.</translation>
+<translation id="2321958826496381788">Сырғытпаны оқу ыңғайлы болғанға дейін Ñүйреңіз. Ðбзацты екі рет баÑқан кезде, мәтіннің үлкендігі оÑындай болуы керек.</translation>
<translation id="2359808026110333948">ЖалғаÑтыру</translation>
-<translation id="2379925928934107488">Chrome қараңғы тақырып қолданғанда, Ñайттарға да мүмкіндігінше қараңғы тақырып қолданыңыз.</translation>
+<translation id="2379925928934107488">Chrome қараңғы режим қолданғанда, Ñайттарға да мүмкіндігінше қараңғы режим қолданыңыз.</translation>
+<translation id="2387895666653383613">Мәтін маÑштабтау</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> МБ</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> және тағы <ph name="NUM_MORE" /> қызметті пайдалануға Ñ€Ò±Ò›Ñат етілген.}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> және тағы <ph name="NUM_MORE" /> қызметті пайдалануға Ñ€Ò±Ò›Ñат етілген.}}</translation>
<translation id="2434158240863470628"><ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /> жүктеп алынды</translation>
@@ -66,7 +70,7 @@
<translation id="2570922361219980984">Бұл құрылғыда да орынды анықтау қызметі өшірулі. Оны <ph name="BEGIN_LINK" />Android параметрлері<ph name="END_LINK" /> арқылы қоÑыңыз.</translation>
<translation id="257931822824936280">Жайылған – жию үшін баÑыңыз.</translation>
<translation id="2586657967955657006">Буфер</translation>
-<translation id="2597457036804169544">Сайттарға қараңғы тақырып қолданылмайды.</translation>
+<translation id="2597457036804169544">Сайттарға қараңғы режим қолданылмайды.</translation>
<translation id="2621115761605608342">Белгілі бір Ñайт үшін JavaScript бағдарламаÑына Ñ€Ò±Ò›Ñат беру.</translation>
<translation id="2653659639078652383">Жіберу</translation>
<translation id="2677748264148917807">Шығу</translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">Ðқпаратты көрÑету</translation>
<translation id="3123473560110926937">Кейбір Ñайттарда тыйым Ñалынған</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> Ñақталған деректері</translation>
+<translation id="3203366800380907218">Интернеттен</translation>
<translation id="321187648315454507"><ph name="APP_NAME" /> браузерінен хабарландырулар алу үшін <ph name="BEGIN_LINK" />Android параметрлерінде<ph name="END_LINK" /> оларды да қоÑыңыз.</translation>
<translation id="3227137524299004712">Микрофон</translation>
<translation id="3277252321222022663">Сайттардың датчиктерді пайдалануына Ñ€Ò±Ò›Ñат ету (Ò±Ñынылады)</translation>
@@ -105,19 +110,23 @@
<translation id="3600792891314830896">Сайттардың дыбыÑÑ‹ өшірілді</translation>
<translation id="3744111561329211289">Фондық Ñинхрондау</translation>
<translation id="3763247130972274048">10 Ñекунд уақытты өткізіп жіберу үшін бейнені Ñолға немеÑе оңға қарай екі рет түртіңіз.</translation>
-<translation id="3797520601150691162">Белгілі бір Ñайтқа қараңғы тақырып қолданылмайды.</translation>
+<translation id="3797520601150691162">Белгілі бір Ñайтқа қараңғы режим қолданылмайды.</translation>
<translation id="381841723434055211">Телефон нөмірлері</translation>
<translation id="3835233591525155343">Құрылғыны пайдалануыңыз</translation>
<translation id="385051799172605136">Ðртқа</translation>
<translation id="3859306556332390985">Ðлға</translation>
+<translation id="3895926599014793903">МаÑштабтауды мәжбүрлі түрде қоÑу</translation>
<translation id="3955193568934677022">Сайттарға қорғалған мазмұнды ойнатуға Ñ€Ò±Ò›Ñат беру (Ò±Ñынылады)</translation>
<translation id="3967822245660637423">Жүктеп алынды</translation>
<translation id="3987993985790029246">Сілтемені көшіру</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" />/?</translation>
<translation id="4002066346123236978">Тақырып</translation>
<translation id="4008040567710660924">Белгілі бір Ñайт үшін cookie файлдарына Ñ€Ò±Ò›Ñат беріңіз.</translation>
+<translation id="4040330681741629921">Сайт қарапайым көрініÑте болған кезде хабарлау</translation>
<translation id="4046123991198612571">КелеÑÑ– аудиотрек</translation>
+<translation id="4149994727733219643">Веб-беттердің қарапайым көрініÑÑ–</translation>
<translation id="4165986682804962316">Сайт параметрлері</translation>
+<translation id="4194328954146351878">Сайттардың NFC құрылғылары туралы ақпаратты көруіне және өзгертуіне Ñ€Ò±Ò›Ñат Ð±ÐµÑ€Ð¼ÐµÑ Ð±Ò±Ñ€Ñ‹Ð½ Ñізден Ñұрау (Ò±Ñынылады)</translation>
<translation id="4200726100658658164">ОрналаÑу параметрлерін ашу</translation>
<translation id="4226663524361240545">Хабарландыру келіп Ñ‚Ò¯Ñкенде, құрылғы дірілдейді</translation>
<translation id="4259722352634471385">ÐÐ°Ð²Ð¸Ð³Ð°Ñ†Ð¸Ñ Ñ‚Ñ‹Ð¹Ñ‹Ð»Ò“Ð°Ð½: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">Жаю</translation>
<translation id="4336434711095810371">Барлық деректерді өшіру</translation>
<translation id="4402755511846832236">Сайттарды бөгеу арқылы олардың құрылғыны қашан белÑенді пайдаланғаныңыз туралы ақпаратты алуына жол берілмейді.</translation>
+<translation id="4428065317363009941">Жарнаманы жекелендіру</translation>
<translation id="4434045419905280838">Қалқымалы терезе және бағыттау</translation>
<translation id="445467742685312942">Сайттарға қорғалған мазмұнды ойнатуға Ñ€Ò±Ò›Ñат беру</translation>
<translation id="4468959413250150279">Белгілі бір Ñайтта дыбыÑÑ‚Ñ‹ өшіру.</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">ОпциÑлар Ñкранның жоғарғы жағында тұрады</translation>
<translation id="5197729504361054390">Сіз таңдаған контактілер <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> Ñайтымен бөліÑіледі.</translation>
<translation id="5216942107514965959">Соңғы кіру: бүгін</translation>
+<translation id="5264323282659631142">"<ph name="CHIP_LABEL" />" өшіру</translation>
<translation id="528192093759286357">Толық Ñкраннан шығу үшін Ò¯Ñтіңгі жақтан Ñүйреп, "Ðртқа" түймеÑін түртіңіз.</translation>
<translation id="5300589172476337783">КөрÑету</translation>
<translation id="5301954838959518834">Жарайды, Ñ‚Ò¯Ñінікті</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">Сайттарда Ñақталған <ph name="DATASIZE" /> деректер мен cookie файлдары өшіріледі.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(Тағы 1)}other{(Тағы #)}}</translation>
<translation id="5403592356182871684">Ðтаулары</translation>
+<translation id="5412236728747081950">Бұл Ñайт ÑÓ™Ð¹ÐºÐµÑ Ð¶Ð°Ñ€Ð½Ð°Ð¼Ð°Ð»Ð°Ñ€Ð´Ñ‹ көрÑету үшін қызығушылықтарыңыз туралы ақпаратты Chrome браузерінен алады.</translation>
<translation id="5438097262470833822"><ph name="WEBSITE" /> веб-Ñайтына арналған Ñ€Ò±Ò›Ñаттар баÑтапқы күйіне қайтарылады.</translation>
<translation id="5489227211564503167">Өткен уақыт: <ph name="ELAPSED_TIME" />/<ph name="TOTAL_TIME" />.</translation>
<translation id="5494752089476963479">Мазалайтын не жалған ақпаратты жарнамалар берілетін Ñайттарда жарнамаларды бөгеу</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">Қайта жүктеу</translation>
<translation id="5596627076506792578">ҚоÑымша опциÑлар</translation>
<translation id="5649053991847567735">Ðвтоматты жүктеулер</translation>
+<translation id="5668404140385795438">Веб-Ñайттардың үлкейтуге тыйым Ñалу туралы Ñұрауларын елемеу</translation>
<translation id="5677928146339483299">Тыйым Ñалынған</translation>
<translation id="5689516760719285838">ЛокациÑ</translation>
<translation id="5690795753582697420">Камера Android параметрлерінде өшірілген.</translation>
-<translation id="5710871682236653961">NFC функциÑÑÑ‹ бар құрылғыларды түрткенде, Ñайттар үшін ақпарат алмаÑу Ñ€Ò±Ò›Ñатын Ñұрау (Ò±Ñынылады).</translation>
<translation id="5719847187258001597">Ðегізгі Ñкрандағы <ph name="ORIGIN" /> Ñайты мен қолданбада Ñақталған барлық деректер мен cookie файлдары өшіріледі.</translation>
<translation id="5771720122942595109"><ph name="PERMISSION_1" /> үшін тыйым Ñалынған.</translation>
<translation id="5804241973901381774">РұқÑаттар</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">Ойнату</translation>
<translation id="6818926723028410516">Элементтерді таңдаңыз</translation>
<translation id="6864395892908308021">Бұл құрылғы NFC Ñигналын оқи алмайды</translation>
-<translation id="6910211073230771657">Жойылды</translation>
<translation id="6912998170423641340">Сайттардың буфердегі мәтіндер мен кеÑкіндерді оқуына тыйым Ñалу</translation>
<translation id="6945221475159498467">Таңдау</translation>
<translation id="6965382102122355670">Жарайды</translation>
+<translation id="6981982820502123353">Ðрнайы мүмкіндіктер</translation>
<translation id="6992289844737586249">Сайттар микрофонды пайдалану үшін Ñ€Ò±Ò›Ñат Ñұрайды (Ò±Ñынылады)</translation>
<translation id="7000754031042624318">Android параметрлері ішінде өшірілді</translation>
<translation id="7016516562562142042">Ðғымдағы іздеу жүйеÑіне Ñ€Ò±Ò›Ñат берілген</translation>
+<translation id="702463548815491781">TalkBack не ÐуыÑтырғышпен кіру қоÑулы кезде пайдалануға Ò±Ñынылады</translation>
<translation id="7053983685419859001">Бөгеу</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1 таңдалды}other{# таңдалды}}</translation>
-<translation id="7070090581017165256">ОÑÑ‹ Ñайт туралы</translation>
<translation id="7087918508125750058"><ph name="ITEM_COUNT" /> таңдалды. ОпциÑлар Ñкранның жоғарғы жағында тұр</translation>
<translation id="7141896414559753902">Сайттардың қалқымалы терезе көрÑетуіне және бағыттауына тыйым Ñалу (Ò±Ñынылады)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> КБ</translation>
@@ -250,12 +262,12 @@
<translation id="7302486331832100261">Әдетте хабарландыруларға тыйым ÑалаÑыз. РұқÑат беру үшін "Мәліметтер" түймеÑін түртіңіз.</translation>
<translation id="7423098979219808738">Ðлдымен Ñұрау</translation>
<translation id="7423538860840206698">Буфердегі мазмұнды оқуға тыйым Ñалынған</translation>
-<translation id="7425915948813553151">Сайттар үшін қараңғы тақырып</translation>
+<translation id="7425915948813553151">Сайттар үшін қараңғы режим</translation>
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">Сайт микрофонды пайдаланып жатыр.</translation>
<translation id="7561196759112975576">Әрқашан</translation>
-<translation id="7572498721684305250">NFC функциÑÑÑ‹ бар құрылғыларды түрткенде, Ñайттарға ақпарат алмаÑуға тыйым Ñалу</translation>
<translation id="757524316907819857">Сайттардың қорғалған мазмұнды ойнатуына тыйым Ñалу</translation>
+<translation id="7577900504646297215">Қызығушылықтарды баÑқару</translation>
<translation id="7649070708921625228">Ðнықтама</translation>
<translation id="7658239707568436148">Ð‘Ð°Ñ Ñ‚Ð°Ñ€Ñ‚Ñƒ</translation>
<translation id="7781829728241885113">Кеше</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">ҚауіпÑіз байланыÑ</translation>
<translation id="8249310407154411074">БаÑына жылжыту</translation>
<translation id="8261506727792406068">Жою</translation>
+<translation id="8284326494547611709">Титрлер</translation>
<translation id="8300705686683892304">Қолданба баÑқарады</translation>
<translation id="8324158725704657629">Қайта ÑұралмаÑын</translation>
<translation id="8372893542064058268">Белгілі бір Ñайт үшін фондық Ñинхрондауға Ñ€Ò±Ò›Ñат беру.</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">Үлкейту</translation>
<translation id="8921772741368021346"><ph name="POSITION" />/<ph name="DURATION" /></translation>
<translation id="8926666909099850184">Бұл құрылғыда NFC функциÑÑÑ‹ өшірілген. Оны <ph name="BEGIN_LINK" />Android параметрлерінен<ph name="END_LINK" /> қоÑыңыз.</translation>
+<translation id="8928445016601307354">Сайттардың NFC құрылғылары туралы ақпаратты көруіне және өзгертуіне тыйым Ñалу</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">Белгілі бір Ñайт үшін cookie файлдарына тыйым Ñалыңыз.</translation>
<translation id="8959122750345127698"><ph name="URL" /> мекенжайына өту мүмкін емеÑ</translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_km.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_km.xtb
index 41662605be8..87b268d76c1 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_km.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_km.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">áž‚áŸáž áž‘ំពáŸážš <ph name="SITE_NAME" /> ážáŸ’រូវបានបន្ážáŸ‚ម</translation>
<translation id="1383876407941801731">ស្វែងរក</translation>
<translation id="1384959399684842514">បានផ្អាកការទាញយក</translation>
+<translation id="1409426117486808224">ទិដ្ឋភាព​សាមញ្ញ​សម្រាប់​ផ្ទាំង​បើក</translation>
<translation id="1415402041810619267">បានបង្រួម URL</translation>
<translation id="1446450296470737166">អនុញ្ញាážáž²áŸ’យមានការគ្រប់គ្រងពáŸáž‰áž›áŸáž‰áž›áž¾áž§áž”ករណ០MIDI</translation>
<translation id="1620510694547887537">កាមáŸážšáŸ‰áž¶</translation>
@@ -49,16 +50,19 @@
<translation id="2212565012507486665">អនុញ្ញាážâ€‹ážáž¼áž‚ី</translation>
<translation id="2228071138934252756">ដើម្បីអនុញ្ញាážáž±áŸ’áž™ <ph name="APP_NAME" /> ចូលប្រើកាមáŸážšáŸ‰áž¶â€‹ážšáž”ស់អ្នក អ្នកកáŸážáŸ’រូវបើក​កាមáŸážšáŸ‰áž¶â€‹áž“ៅក្នុង​<ph name="BEGIN_LINK" />ការកំណážáŸ‹ Android<ph name="END_LINK" /> ផងដែរ។</translation>
<translation id="2241634353105152135">ម្ážáž„ប៉ុណ្ណោះ</translation>
+<translation id="2253414712144136228">ដក <ph name="NAME_OF_LIST_ITEM" /> áž…áŸáž‰</translation>
<translation id="2289270750774289114">សួរនៅពáŸáž›áž‚áŸáž áž‘ំពáŸážšâ€‹áž…ង់ស្វែងរកឧបករណáŸâ€‹áž”៊្លូធូសដែលនៅជិហ(បានណែនាំ)</translation>
<translation id="2315043854645842844">ការជ្រើសរើសវិញ្ញាបនបážáŸ’រសម្រាប់ម៉ាស៊ីនកូនមិនគាំទ្រដោយប្រពáŸáž“្ធដំណើរការនáŸáŸ‡áž‘áŸáŸ”</translation>
+<translation id="2321958826496381788">ទាញរបារំកិលរហូážáž¢áŸ’នកអាចអានបានយ៉ាងងាយស្រួល។ អážáŸ’ážáž”ទគួរážáŸ‚មើលទៅធំប៉ុននáŸáŸ‡ បន្ទាប់ពីប៉ះពីរដងនៅលើកážáž¶ážážŽáŸ’ឌ។</translation>
<translation id="2359808026110333948">បន្áž</translation>
<translation id="2379925928934107488">ប្រើរចនាបáŸáž‘្មងងឹážáž›áž¾áž‚áŸáž áž‘ំពáŸážš នៅពáŸáž› Chrome ប្រើរចនាបáŸáž‘្មងងឹហនៅពáŸáž›áž¢áž¶áž…ប្រើបាន</translation>
+<translation id="2387895666653383613">ការប្ដូរទំហំអក្សរ</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{បានអនុញ្ញាហ<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> áž“áž·áž„ <ph name="NUM_MORE" /> ទៀáž}other{បានអនុញ្ញាហ<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> áž“áž·áž„ <ph name="NUM_MORE" /> ទៀáž}}</translation>
<translation id="2434158240863470628">ការទាញយក​បានបញ្ចប់ <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
<translation id="2442870161001914531">ស្នើគáŸáž áž‘ំពáŸážšážŸáž˜áŸ’រាប់កុំព្យូទáŸážšáž‡áž¶áž“ិច្ច</translation>
<translation id="2482878487686419369">ការជូនដំណឹង</translation>
-<translation id="2485422356828889247">លុបការážáŸ†áž¡áž¾áž„</translation>
+<translation id="2485422356828889247">លុប</translation>
<translation id="2490684707762498678">ស្ážáž·ážáž€áŸ’រោម​ការគ្រប់គ្រង​របស់ <ph name="APP_NAME" /></translation>
<translation id="2498359688066513246">ជំនួយ &amp; មážáž·</translation>
<translation id="2501278716633472235">ážáŸ’រលប់ក្រោយ</translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">បង្ហាញពáŸážáŸŒáž˜áž¶áž“</translation>
<translation id="3123473560110926937">បាន​ទប់ស្កាážáŸ‹áž“ៅលើគáŸáž áž‘ំពáŸážšâ€‹áž˜áž½áž™áž…ំនួន</translation>
<translation id="3198916472715691905">ទិន្ននáŸáž™ážŠáŸ‚លបានផ្ទុក <ph name="STORAGE_AMOUNT" /></translation>
+<translation id="3203366800380907218">​ពី​បណ្ážáž¶áž‰</translation>
<translation id="321187648315454507">ដើម្បីអនុញ្ញាážáž±áŸ’áž™ <ph name="APP_NAME" /> ផ្ញើការជូនដំណឹង​ទៅអ្នក អ្នកកáŸážáŸ’រូវបើក​ការជូនដំណឹង​នៅក្នុង​<ph name="BEGIN_LINK" />ការកំណážáŸ‹ Android<ph name="END_LINK" /> ផងដែរ។</translation>
<translation id="3227137524299004712">ម៉ៃក្រូហ្វូន</translation>
<translation id="3277252321222022663">អនុញ្ញាážâ€‹áž±áŸ’យ​គáŸáž áž‘ំពáŸážšâ€‹áž…ូលប្រើ​ឧបករណáŸâ€‹áž…ាប់សញ្ញា (បាន​ណែនាំ)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">ការប្រើប្រាស់​ឧបករណáŸážšáž”ស់អ្នក</translation>
<translation id="385051799172605136">ážáž™áž€áŸ’រោយ</translation>
<translation id="3859306556332390985">ស្វែងរក​ទៅ​មុáž</translation>
+<translation id="3895926599014793903">បង្ážáŸ†áž”ើកដំណើរការពង្រីក</translation>
<translation id="3955193568934677022">អនុញ្ញាážâ€‹áž²áŸ’យ​ទំពáŸážšâ€‹áž…ាក់​មាážáž·áž€áž¶â€‹ážŠáŸ‚លមាន​ការ​ការពារ (ážáŸ’រូវបាន​ណែនាំ)</translation>
<translation id="3967822245660637423">ការទាញយកបានបញ្ចប់</translation>
<translation id="3987993985790029246">ចម្លងážáŸ†ážŽ</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> / ?</translation>
<translation id="4002066346123236978">ចំណងជើង</translation>
<translation id="4008040567710660924">អនុញ្ញាážážáž¼áž‚ី​សម្រាប់គáŸáž áž‘ំពáŸážšâ€‹áž‡áž¶áž€áŸ‹áž›áž¶áž€áŸ‹áŸ”</translation>
+<translation id="4040330681741629921">ទទួលបានការជូនដំណឹង នៅពáŸáž›ážŠáŸ‚លអាចបង្ហាញគáŸáž áž‘ំពáŸážšážŽáž¶áž˜áž½áž™áž€áŸ’នុងទិដ្ឋភាពសាមញ្ញ</translation>
<translation id="4046123991198612571">បទ​បន្ទាប់</translation>
+<translation id="4149994727733219643">ទិដ្ឋភាព​សាមញ្ញ​សម្រាប់​ទំពáŸážšáž”ណ្ដាញ</translation>
<translation id="4165986682804962316">ការកំណážáŸ‹áž‚áŸáž áž‘ំពáŸážš</translation>
+<translation id="4194328954146351878">សួរ​មុនពáŸáž›â€‹áž¢áž“ុញ្ញាážáž±áŸ’យ​គáŸáž áž‘ំពáŸážšáž˜áž¾áž›ážƒáž¾áž‰ និងផ្លាស់ប្ដូរពáŸážáŸŒáž˜áž¶áž“នៅលើឧបករណ០NFC (បានណែនាំ)</translation>
<translation id="4200726100658658164">បើកការកំណážáŸ‹áž‘ីážáž¶áŸ†áž„</translation>
<translation id="4226663524361240545">ការជូនដំណឹងអាចនឹងធ្វើឲ្យឧបករណáŸáž‰áŸážš</translation>
<translation id="4259722352634471385">ការរុករកážáŸ’រូវបានរារាំង៖ <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">ពង្រីក</translation>
<translation id="4336434711095810371">សម្អាážâ€‹áž‘ិន្ននáŸáž™â€‹áž‘ាំងអស់</translation>
<translation id="4402755511846832236">ទប់ស្កាážáŸ‹â€‹áž‚áŸáž áž‘ំពáŸážšáž˜áž·áž“ឱ្យដឹង​អំពីពáŸáž›ážœáŸáž›áž¶ážŠáŸ‚លអ្នក​កំពុងប្រើឧបករណáŸáž“áŸáŸ‡â€‹áž™áŸ‰áž¶áž„សកម្ម</translation>
+<translation id="4428065317363009941">ការកំណážáŸ‹áž€áž¶ážšáž•áŸ’សាយពាណិជ្ជកម្មឱ្យស្របážáž¶áž˜áž”ុគ្គល</translation>
<translation id="4434045419905280838">ផ្ទាំងផុស​ និង​ការ​បញ្ជូន​បន្áž</translation>
<translation id="445467742685312942">អនុញ្ញាážáž±áŸ’យ​គáŸáž áž‘ំពáŸážšâ€‹áž…ាក់ážáŸ’លឹមសារដែលមាន​ការការពារ</translation>
<translation id="4468959413250150279">បិទសំឡáŸáž„សម្រាប់ទំពáŸážšáž‡áž¶áž€áŸ‹áž›áž¶áž€áŸ‹áŸ”</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">ជម្រើសមាន​នៅជិážáž•áŸ’នែក​ážáž¶áž„លើ​នៃអáŸáž€áŸ’រង់</translation>
<translation id="5197729504361054390">ទំនាក់ទំនងដែលអ្នកជ្រើសរើស​នឹងចែករំលែកជាមួយ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ។</translation>
<translation id="5216942107514965959">បានចូលមើល​លើកចុងក្រោយ​នៅážáŸ’ងៃនáŸáŸ‡</translation>
+<translation id="5264323282659631142">លុប '<ph name="CHIP_LABEL" />'</translation>
<translation id="528192093759286357">អូសពីលើ ហើយប៉ះប៊ូážáž»áž„ážáž™áž€áŸ’រោយដើម្បីចáŸáž‰áž–ីរបៀបពáŸáž‰áž¢áŸáž€áŸ’រង់។</translation>
<translation id="5300589172476337783">បង្ហាញ</translation>
<translation id="5301954838959518834">យល់ព្រម ážáŸ’ញុំយល់ហើយ</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">សកម្មភាពនáŸáŸ‡â€‹áž“ឹងសម្អាážáž‘ិន្ននáŸáž™ áž“áž·áž„ážáž¼áž‚ីទំហំ <ph name="DATASIZE" /> ដែលគáŸáž áž‘ំពáŸážšáž“ានាបានរក្សាទុក។</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(+ 1 ទៀáž)}other{(+ # ទៀáž)}}</translation>
<translation id="5403592356182871684">ឈ្មោះ</translation>
+<translation id="5412236728747081950">áž‚áŸáž áž‘ំពáŸážšáž“áŸáŸ‡áž”្រមូលពáŸážáŸŒáž˜áž¶áž“អំពីចំណាប់អារម្មណáŸážšáž”ស់អ្នកពី Chrome ដើម្បីបង្ហាញការផ្សាយពាណិជ្ជកម្មកាន់ážáŸ‚ពាក់ពáŸáž“្ធដល់អ្នក</translation>
<translation id="5438097262470833822">ជម្រើសនáŸáŸ‡áž“ឹងកំណážáŸ‹áž€áž¶ážšâ€‹áž¢áž“ុញ្ញាážáž¡áž¾áž„វិញសម្រាប់ <ph name="WEBSITE" /></translation>
<translation id="5489227211564503167">រយៈពáŸáž›â€‹ážŠáŸ‚លកន្លងផុហ<ph name="ELAPSED_TIME" /> នៃ <ph name="TOTAL_TIME" />។</translation>
<translation id="5494752089476963479">ទប់ស្កាážáŸ‹â€‹áž€áž¶ážšáž•áŸ’សាយពាណិជ្ជកម្ម​នៅលើគáŸáž áž‘ំពáŸážšâ€‹ážŠáŸ‚លបង្ហាញ​ការផ្សាយពាណិជ្ជកម្ម​នាំឱ្យយល់ច្រឡំ ឬរំážáž¶áž“</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">ដំណើរការឡើងវិញ</translation>
<translation id="5596627076506792578">ជម្រើសច្រើនទៀáž</translation>
<translation id="5649053991847567735">ទាញយកស្វáŸáž™áž”្រវážáŸ’ážáž·</translation>
+<translation id="5668404140385795438">បដិសáŸáž’សំណើរគáŸáž áž‘ំពáŸážšážŠáž¾áž˜áŸ’បីបង្ការការពង្រីក</translation>
<translation id="5677928146339483299">បានរារាំង</translation>
<translation id="5689516760719285838">ទីážáž¶áŸ†áž„</translation>
<translation id="5690795753582697420">កាមáŸážšáŸ‰áž¶ážáŸ’រូវបានបិទនៅក្នុងការកំណážáŸ‹ Android</translation>
-<translation id="5710871682236653961">សួរ​មុនពáŸáž›â€‹áž¢áž“ុញ្ញាážáž±áŸ’យ​គáŸáž áž‘ំពáŸážšáž•áŸ’ញើ និងទទួល​ពáŸážáŸŒáž˜áž¶áž“ នៅពáŸáž›â€‹áž¢áŸ’នកចុច​ឧបករណ០NFC (បានណែនាំ)</translation>
<translation id="5719847187258001597">សកម្មភាពនáŸáŸ‡áž“ឹង​សម្អាážâ€‹áž‘ិន្ននáŸáž™ áž“áž·áž„ážáž¼áž‚ីទាំងអស់​ដែល <ph name="ORIGIN" /> ឬកម្មវិធីរបស់ážáŸ’លួនបានរក្សាទុក នៅលើ​អáŸáž€áŸ’រង់ដើម​របស់អ្នក។</translation>
<translation id="5771720122942595109">បានទប់​ស្កាážáŸ‹ <ph name="PERMISSION_1" /></translation>
<translation id="5804241973901381774">ការអនុញ្ញាáž</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">áž›áŸáž„</translation>
<translation id="6818926723028410516">ជ្រើសរើសធាážáž»</translation>
<translation id="6864395892908308021">ឧបករណáŸáž“áŸáŸ‡â€‹áž˜áž·áž“អាចអាន NFC បានទáŸ</translation>
-<translation id="6910211073230771657">បានលុប</translation>
<translation id="6912998170423641340">ទប់ស្កាážáŸ‹â€‹áž‘ំពáŸážšâ€‹áž˜áž·áž“​ឱ្យ​អាន​អក្សរ និង​រូបភាព​ពី​អង្គ​ចង​ចាំ</translation>
<translation id="6945221475159498467">ជ្រើសរើស</translation>
<translation id="6965382102122355670">យល់ព្រម</translation>
+<translation id="6981982820502123353">លទ្ធភាពប្រើប្រាស់</translation>
<translation id="6992289844737586249">សួរជាមុនសិន មុនពáŸáž›áž¢áž“ុញ្ញាážáž²áŸ’យគáŸáž áž‘ំពáŸážšáž”្រើមីក្រូហ្វូនរបស់អ្នក (បានណែនាំ)</translation>
<translation id="7000754031042624318">បានបិទនៅក្នុងការកំណážáŸ‹ Android</translation>
<translation id="7016516562562142042">បានអនុញ្ញាážâ€‹ážŸáž˜áŸ’រាប់​ម៉ាស៊ីន​ស្វែងរក​​បច្ចុប្បន្ន</translation>
+<translation id="702463548815491781">បានណែនាំ នៅពáŸáž›â€‹áž”ើកកម្មវិធីážáž”វិញ ឬមុážáž„ារ​ប្រើប៊ូážáž»áž„ចុច​</translation>
<translation id="7053983685419859001">ទប់ស្កាážáŸ‹</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{បានជ្រើសរើស 1}other{បានជ្រើសរើស #}}</translation>
-<translation id="7070090581017165256">អំពីគáŸáž áž‘ំពáŸážšáž“áŸáŸ‡</translation>
<translation id="7087918508125750058">បានជ្រើស​រើស <ph name="ITEM_COUNT" />។ ជម្រើស​មាននៅក្បែរ​ផ្នែកážáž¶áž„លើ​អáŸáž€áŸ’រង់</translation>
<translation id="7141896414559753902">ទប់​ស្កាážáŸ‹â€‹áž‘ំពáŸážšâ€‹áž˜áž·áž“​ឱ្យ​បង្ហាញ​ផ្ទាំង​ផុស និង​ការ​បញ្ជូន​បន្ហ(បាន​ណែនាំ)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> KB</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">áž‚áŸáž áž‘ំពáŸážšáž˜áž½áž™áž€áŸ†áž–ុងប្រើប្រាស់មីក្រូហ្វូនរបស់អ្នក</translation>
<translation id="7561196759112975576">ជានិច្ច</translation>
-<translation id="7572498721684305250">ទប់ស្កាážáŸ‹â€‹áž‚áŸáž áž‘ំពáŸážšâ€‹áž€áž»áŸ†áž±áŸ’យផ្ញើ និង​ទទួលពáŸážáŸŒáž˜áž¶áž“ នៅពáŸáž›â€‹áž¢áŸ’នក​ចុច​ឧបករណ០NFC</translation>
<translation id="757524316907819857">ទប់ស្កាážáŸ‹â€‹áž‚áŸáž áž‘ំពáŸážšâ€‹áž˜áž·áž“ឱ្យ​លáŸáž„ážáŸ’លឹមសារ​ដែលមានការការពារ</translation>
+<translation id="7577900504646297215">គ្រប់គ្រង​ចំណាប់អារម្មណáŸ</translation>
<translation id="7649070708921625228">ជំនួយ</translation>
<translation id="7658239707568436148">បដិសáŸáž’</translation>
<translation id="7781829728241885113">ម្សិលមិញ</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">ការážáž—្ជាប់មានសុវážáŸ’ážáž·áž—ាព</translation>
<translation id="8249310407154411074">ផ្លាស់ទីទៅážáž¶áž„​លើបំផុáž</translation>
<translation id="8261506727792406068">លុប</translation>
+<translation id="8284326494547611709">អážáŸ’ážáž”ទពិពណ៌នា</translation>
<translation id="8300705686683892304">ស្ážáž·ážáž€áŸ’រោមការគ្រប់គ្រង​របស់កម្មវិធី</translation>
<translation id="8324158725704657629">កុំ​សួរ​ម្ដងទៀáž</translation>
<translation id="8372893542064058268">អនុញ្ញាážáž€áž¶ážšáž’្វើសមកាលកម្មផ្ទៃážáž¶áž„ក្រោយសម្រាប់គáŸáž áž‘ំពáŸážšáž‡áž¶áž€áŸ‹áž›áž¶áž€áŸ‹áŸ”</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">ពង្រីក</translation>
<translation id="8921772741368021346"><ph name="POSITION" /> / <ph name="DURATION" /></translation>
<translation id="8926666909099850184">NFC ážáŸ’រូវ​បាន​បិទសម្រាប់​ឧបករណáŸâ€‹áž“áŸáŸ‡áŸ” បើក NFC នៅក្នុង<ph name="BEGIN_LINK" />ការកំណážáŸ‹ Android<ph name="END_LINK" />។</translation>
+<translation id="8928445016601307354">ទប់ស្កាážáŸ‹áž‚áŸáž áž‘ំពáŸážšáž€áž»áŸ†áž±áŸ’យមើលឃើញ និងផ្លាស់ប្ដូរពáŸážáŸŒáž˜áž¶áž“នៅលើឧបករណ០NFC</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">ទប់ស្កាážáŸ‹â€‹ážáž¼áž‚ីសម្រាប់​គáŸáž áž‘ំពáŸážšâ€‹áž‡áž¶áž€áŸ‹áž›áž¶áž€áŸ‹áŸ”</translation>
<translation id="8959122750345127698">ការុករកមិនអាចភ្ជាប់បានទáŸáŸ– <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_kn.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_kn.xtb
index e7d4682a4fb..4d9c6fe249a 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_kn.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_kn.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676"><ph name="SITE_NAME" /> ಸೈಟೠಸೇರಿಸಲಾಗಿದೆ</translation>
<translation id="1383876407941801731">Search</translation>
<translation id="1384959399684842514">ಡೌನà³â€Œà²²à³‹à²¡à³ ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ</translation>
+<translation id="1409426117486808224">ತೆರೆದ ಟà³à²¯à²¾à²¬à³â€Œà²—ಳಿಗಾಗಿ ಸರಳೀಕೃತ ವೀಕà³à²·à²£à³†</translation>
<translation id="1415402041810619267">URL ಕಿರಿದà³à²—ೊಳಿಸಲಾಗಿದೆ</translation>
<translation id="1446450296470737166">MIDI ಸಾಧನಗಳ ಪೂರà³à²£ ನಿಯಂತà³à²°à²£ ಅನà³à²®à²¤à²¿à²¸à²¿</translation>
<translation id="1620510694547887537">ಕà³à²¯à²¾à²®à²°à²¾</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">ಕà³à²•à³€à²—ಳನà³à²¨à³ ಅನà³à²®à²¤à²¿à²¸à²¿</translation>
<translation id="2228071138934252756"><ph name="APP_NAME" /> ನಿಮà³à²® ಕà³à²¯à²¾à²®à²°à²¾à²µà²¨à³à²¨à³ ಪà³à²°à²µà³‡à²¶à²¿à²¸à³à²µà³à²¦à²•à³à²•à³† ಅನà³à²®à²¤à²¿à²¸à²²à³, <ph name="BEGIN_LINK" />Android ಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳಲà³à²²à²¿<ph name="END_LINK" /> ಕà³à²¯à²¾à²®à²°à²¾à²µà²¨à³à²¨à³ ಸಹ ಆನೠಮಾಡಬೇಕಾಗà³à²¤à³à²¤à²¦à³†.</translation>
<translation id="2241634353105152135">ಕೇವಲ ಒಂದೠಬಾರಿ</translation>
+<translation id="2253414712144136228"><ph name="NAME_OF_LIST_ITEM" /> ಅನà³à²¨à³ ತೆಗೆದà³à²¹à²¾à²•à²¿</translation>
<translation id="2289270750774289114">ಸೈಟೠಯಾವಾಗ ಸಮೀಪದ ಬà³à²²à³‚ಟೂತೠಸಾಧನಗಳನà³à²¨à³ ಅನà³à²µà³‡à²·à²¿à²¸à²²à³ ಬಯಸà³à²¤à³à²¤à²¦à³†à²¯à³‹ ಆಗ ಕೇಳಿ (ಶಿಫಾರಸೠಮಾಡಲಾಗಿದೆ)</translation>
<translation id="2315043854645842844">ಕà³à²²à³ˆà²‚ಟà³â€Œà²¨ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²° ಆಯà³à²•à³†à²¯à²¨à³à²¨à³ ಆಪರೇಟಿಂಗೠಸಿಸà³à²Ÿà²‚ನಿಂದ ಬೆಂಬಲಿಸಲಾಗಿಲà³à²².</translation>
+<translation id="2321958826496381788">ನೀವೠಇದನà³à²¨à³ ಆರಾಮವಾಗಿ ಓದಲೠಸಾಧà³à²¯à²µà²¾à²—à³à²µà²µà²°à³†à²—ೆ ಸà³à²²à³ˆà²¡à²°à³ ಎಳೆಯಿರಿ. ಪà³à²¯à²¾à²°à²¾à²—à³à²°à²¾à²«à³â€Œà²¨à²²à³à²²à²¿ ಡಬಲೠಟà³à²¯à²¾à²ªà²¿à²‚ಗೠಮಾಡಿದ ನಂತರ ಪಠà³à²¯à²µà³ ಕನಿಷà³à²  ಇಷà³à²Ÿà³ ದೊಡà³à²¡à²¦à²¾à²—ಿ ಕಾಣಿಸಬೇಕà³.</translation>
<translation id="2359808026110333948">ಮà³à²‚ದà³à²µà²°à³†à²¸à²¿</translation>
<translation id="2379925928934107488">ಡಾರà³à²•à³ ಥೀಮà³â€Œ ಅನà³à²¨à³ Chrome ಬಳಸà³à²µà²¾à²—, ಸಾಧà³à²¯à²µà²¾à²¦à²°à³† ಡಾರà³à²•à³ ಥೀಮà³â€Œ ಅನà³à²¨à³ ಸೈಟà³â€Œà²—ಳಿಗೆ ಅನà³à²µà²¯à²¿à²¸à²¿</translation>
+<translation id="2387895666653383613">ಪಠà³à²¯ ಸà³à²•à³†à³•à²²à²¿à²‚ಗà³</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, ಮತà³à²¤à³ ಇನà³à²¨à³‚ <ph name="NUM_MORE" /> ಸಂಗತಿಗಳನà³à²¨à³ ಅನà³à²®à²¤à²¿à²¸à²²à²¾à²—ಿದೆ}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, ಮತà³à²¤à³ ಇನà³à²¨à³‚ <ph name="NUM_MORE" /> ಸಂಗತಿಗಳನà³à²¨à³ ಅನà³à²®à²¤à²¿à²¸à²²à²¾à²—ಿದೆ}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, ಮತà³à²¤à³ ಇನà³à²¨à³‚ <ph name="NUM_MORE" /> ಸಂಗತಿಗಳನà³à²¨à³ ಅನà³à²®à²¤à²¿à²¸à²²à²¾à²—ಿದೆ}}</translation>
<translation id="2434158240863470628">ಡೌನà³â€Œà²²à³‹à²¡à³â€Œâ€Œ ಪೂರà³à²£à²—ೊಂಡಿದೆ <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">ಮಾಹಿತಿಯನà³à²¨à³ ತೋರಿಸಿ</translation>
<translation id="3123473560110926937">ಕೆಲವೠಸೈಟà³â€Œà²—ಳಲà³à²²à²¿ ನಿರà³à²¬à²‚ಧಿಸಲಾಗಿದೆ</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> ಸಂಗà³à²°à²¹à²¿à²¸à²¿à²¦ ಡೇಟಾ</translation>
+<translation id="3203366800380907218">ವೆಬà³â€Œà²¨à²¿à²‚ದ</translation>
<translation id="321187648315454507"><ph name="APP_NAME" /> ನಿಮಗೆ ಅಧಿಸೂಚನೆಗಳನà³à²¨à³ ಕಳà³à²¹à²¿à²¸à³à²µà³à²¦à²•à³à²•à³† ಅನà³à²®à²¤à²¿à²¸à²²à³, <ph name="BEGIN_LINK" />Android ಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳಲà³à²²à²¿<ph name="END_LINK" /> ಅಧಿಸೂಚನೆಗಳನà³à²¨à³ ಸಹ ಆನೠಮಾಡಬೇಕಾಗà³à²¤à³à²¤à²¦à³†.</translation>
<translation id="3227137524299004712">ಮೈಕà³à²°à³‹à²«à³‹à²¨à³</translation>
<translation id="3277252321222022663">ಸೆನà³à²¸à²°à³â€Œà²—ಳನà³à²¨à³ ಪà³à²°à²µà³‡à²¶à²¿à²¸à²²à³ ಸೈಟà³â€Œà²—ಳಿಗೆ ಅನà³à²®à²¤à²¿ ನೀಡಿ (ಶಿಫಾರಸೠಮಾಡಿರà³à²µà³à²¦à³)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">ನಿಮà³à²® ಸಾಧನದ ಬಳಕೆ</translation>
<translation id="385051799172605136">ಹಿಂದೆ</translation>
<translation id="3859306556332390985">ಮà³à²‚ದಕà³à²•à³† ಸೀಕೠಮಾಡಿ</translation>
+<translation id="3895926599014793903">ಒತà³à²¤à²¾à²¯à²¦ à²à³‚ಮೠಸಕà³à²°à²¿à²¯à²—ೊಳಿಸà³à²µà²¿à²•à³†</translation>
<translation id="3955193568934677022">ಸಂರಕà³à²·à²¿à²¸à²²à²¾à²¦ ವಿಷಯವನà³à²¨à³ ಪà³à²²à³†à³• ಮಾಡಲೠಸೈಟà³â€Œà²—ಳಿಗೆ ಅನà³à²®à²¤à²¿à²¸à²¿ (ಶಿಫಾರಸೠಮಾಡಲಾಗಿದೆ)</translation>
<translation id="3967822245660637423">ಡೌನà³â€Œà²²à³‹à²¡à³â€Œâ€Œ ಪೂರà³à²£à²—ೊಂಡಿದೆ</translation>
<translation id="3987993985790029246">ಲಿಂಕೠನಕಲಿಸಿ</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> / ?</translation>
<translation id="4002066346123236978">ಶೀರà³à²·à²¿à²•à³†</translation>
<translation id="4008040567710660924">ನಿರà³à²¦à²¿à²·à³à²Ÿ ಸೈಟà³â€Œ ಒಂದಕà³à²•à³† ಕà³à²•à³€à²—ಳನà³à²¨à³ ಅನà³à²®à²¤à²¿à²¸à²¿.</translation>
+<translation id="4040330681741629921">ಸೈಟೠಅನà³à²¨à³ ಸರಳೀಕೃತ ವೀಕà³à²·à²£à³†à²¯à²²à³à²²à²¿ ತೋರಿಸಬಹà³à²¦à³ ಎಂದಾದಾಗ ಸೂಚನೆ ಪಡೆಯಿರಿ</translation>
<translation id="4046123991198612571">ಮà³à²‚ದಿನ ಟà³à²°à³à²¯à²¾à²•à³</translation>
+<translation id="4149994727733219643">ವೆಬೠಪà³à²Ÿà²—ಳಿಗಾಗಿ ಸರಳೀಕೃತ ವೀಕà³à²·à²£à³†</translation>
<translation id="4165986682804962316">ಸೈಟೠಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳà³</translation>
+<translation id="4194328954146351878">NFC ಸಾಧನಗಳಲà³à²²à²¿ ಮಾಹಿತಿಯನà³à²¨à³ ನೋಡಲೠಮತà³à²¤à³ ಬದಲಾಯಿಸಲೠಸೈಟà³â€Œà²—ಳಿಗೆ ಅನà³à²®à²¤à²¿à²¸à³à²µ ಮೊದಲೠಕೇಳಿ (ಶಿಫಾರಸೠಮಾಡಲಾಗಿದೆ)</translation>
<translation id="4200726100658658164">ಸà³à²¥à²³ ಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳನà³à²¨à³ ತೆರೆಯಿರಿ</translation>
<translation id="4226663524361240545">ಪà³à²°à²•à²Ÿà²£à³†à²—ಳೠಸಾಧನವನà³à²¨à³ ವೈಬà³à²°à³‡à²Ÿà³ ಮಾಡಬಹà³à²¦à³</translation>
<translation id="4259722352634471385">ನà³à²¯à²¾à²µà²¿à²—ೇಶನà³â€Œ ನಿರà³à²¬à²‚ಧಿಸಲಾಗಿದೆ: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">ವಿಸà³à²¤à²°à²¿à²¸à²¿</translation>
<translation id="4336434711095810371">ಎಲà³à²²à²¾ ಡೇಟಾವನà³à²¨à³ ತೆರವà³à²—ೊಳಿಸಿ</translation>
<translation id="4402755511846832236">ನೀವೠಈ ಸಾಧನವನà³à²¨à³ ಸಕà³à²°à²¿à²¯à²µà²¾à²—ಿ ಬಳಸà³à²¤à³à²¤à²¿à²°à³à²µà²¾à²— ಸೈಟà³â€Œà²—ಳೠನಿಮà³à²® ಉಪಸà³à²¥à²¿à²¤à²¿à²¯ ಕà³à²°à²¿à²¤à³ ತಿಳಿದà³à²•à³Šà²³à³à²³à²¦à²‚ತೆ ನಿರà³à²¬à²‚ಧಿಸಿ</translation>
+<translation id="4428065317363009941">ಜಾಹೀರಾತೠವೈಯಕà³à²¤à³€à²•à²°à²£</translation>
<translation id="4434045419905280838">ಪಾಪà³-ಅಪà³â€Œà²—ಳೠಹಾಗೂ ಮರà³à²¨à²¿à²°à³à²¦à³‡à²¶à²¨à²—ಳà³</translation>
<translation id="445467742685312942">ಸಂರಕà³à²·à²¿à²¤ ವಿಷಯವನà³à²¨à³ ಪà³à²²à³‡ ಮಾಡಲೠಸೈಟà³â€Œà²—ಳಿಗೆ ಅನà³à²®à²¤à²¿ ನೀಡಿ</translation>
<translation id="4468959413250150279">ನಿರà³à²¦à²¿à²·à³à²Ÿ ಸೈಟà³â€Œà²¨ ಧà³à²µà²¨à²¿à²¯à²¨à³à²¨à³ ಮà³à²¯à³‚ಟೠಮಾಡಿ</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">ಸà³à²•à³à²°à³€à²¨à³â€Œà²¨ ಮೇಲà³à²¬à²¾à²—ದ ಹತà³à²¤à²¿à²°à²¦à²²à³à²²à²¿ ಲಭà³à²¯à²µà²¿à²°à³à²µ ಆಯà³à²•à³†à²—ಳà³</translation>
<translation id="5197729504361054390">ನೀವೠಆಯà³à²•à³† ಮಾಡà³à²µ ಸಂಪರà³à²•à²—ಳನà³à²¨à³ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ಜೊತೆಗೆ ಹಂಚಿಕೊಳà³à²³à²²à²¾à²—à³à²¤à³à²¤à²¦à³†.</translation>
<translation id="5216942107514965959">ಇಂದೠಕೊನೆಯಾದಾಗಿ ಭೇಟಿ ನೀಡಲಾಗಿದೆ</translation>
+<translation id="5264323282659631142">'<ph name="CHIP_LABEL" />' ಅನà³à²¨à³ ತೆಗೆದà³à²¹à²¾à²•à²¿</translation>
<translation id="528192093759286357">ಪೂರà³à²£à²ªà²°à²¦à³†à²¯à²¨à³à²¨à³ ನಿರà³à²—ಮಿಸಲೠಮೇಲಿನಿಂದ ಡà³à²°à³à²¯à²¾à²—ೠಮಾಡಿ ಹಾಗೂ ಹಿಂದೆ ಬಟನೠಸà³à²ªà²°à³à²¶à²¿à²¸à²¿.</translation>
<translation id="5300589172476337783">ತೋರಿಸಿ</translation>
<translation id="5301954838959518834">ಸರಿ, ಅರà³à²¥à²µà²¾à²¯à²¿à²¤à³</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">ಇದೠಸೈಟà³â€Œà²—ಳ ಮೂಲಕ ಸಂಗà³à²°à²¹à²£à³† ಮಾಡಲಾದ <ph name="DATASIZE" /> ಯಷà³à²Ÿà³ ಡೇಟಾ ಮತà³à²¤à³ ಕà³à²•à³€à²—ಳನà³à²¨à³ ತೆರವà³à²—ೊಳಿಸà³à²¤à³à²¤à²¦à³†.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(+ 1 ಹೆಚà³à²šà³)}one{(+ # ಹೆಚà³à²šà³)}other{(+ # ಹೆಚà³à²šà³)}}</translation>
<translation id="5403592356182871684">ಹೆಸರà³à²—ಳà³</translation>
+<translation id="5412236728747081950">ನಿಮಗೆ ಹೆಚà³à²šà³ ಸಂಬಂಧಿತ ಜಾಹೀರಾತà³à²—ಳನà³à²¨à³ ತೋರಿಸಲà³, ಈ ಸೈಟೠನಿಮà³à²® ಆಸಕà³à²¤à²¿à²—ಳ ಕà³à²°à²¿à²¤ ಮಾಹಿತಿಯನà³à²¨à³ Chrome ನಿಂದ ಪಡೆಯà³à²¤à³à²¤à²¦à³†</translation>
<translation id="5438097262470833822">ಈ ಆಯà³à²•à³†à²¯à³ <ph name="WEBSITE" /> ನ ಅನà³à²®à²¤à²¿à²—ಳನà³à²¨à³ ರೀಸೆಟೠಮಾಡà³à²¤à³à²¤à²¦à³†</translation>
<translation id="5489227211564503167"><ph name="TOTAL_TIME" /> ನಲà³à²²à²¿ <ph name="ELAPSED_TIME" /> ಸಮಯ ಕಳೆದಿದೆ.</translation>
<translation id="5494752089476963479">ಅನಪೇಕà³à²·à²¿à²¤ ಅಥವಾ ತಪà³à²ªà³à²¦à²¾à²°à²¿à²—ೆಳೆಯà³à²µ ಜಾಹೀರಾತà³à²—ಳನà³à²¨à³ ತೋರಿಸà³à²µ ಸೈಟà³â€Œà²—ಳಲà³à²²à²¿ ಜಾಹೀರಾತà³à²—ಳನà³à²¨à³ ನಿರà³à²¬à²‚ಧಿಸಿ</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">ಮರà³à²²à³‹à²¡à³â€Œ</translation>
<translation id="5596627076506792578">ಇನà³à²¨à²·à³à²Ÿà³ ಆಯà³à²•à³†à²—ಳà³</translation>
<translation id="5649053991847567735">ಸà³à²µà²¯à²‚ಚಾಲಿತ ಡೌನà³â€Œà²²à³‹à²¡à³â€Œà²—ಳà³</translation>
+<translation id="5668404140385795438">à²à³‚ಮà³â€Œ ಇನà³â€Œ ಮಾಡà³à²µà³à²¦à²¨à³à²¨à³ ತಡೆಗಟà³à²Ÿà²²à³ ವೆಬà³â€Œà²¸à³ˆà²Ÿà³â€Œà²¨ ವಿನಂತಿಯನà³à²¨à³ ಅತಿಕà³à²°à²®à²¿à²¸à³</translation>
<translation id="5677928146339483299">ನಿರà³à²¬à²‚ಧಿಸಲಾಗಿದೆ</translation>
<translation id="5689516760719285838">ಸà³à²¥à²³</translation>
<translation id="5690795753582697420">Android ಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳಲà³à²²à²¿ ಕà³à²¯à²¾à²®à²°à²¾à²µà²¨à³à²¨à³ ಆಫೠಮಾಡಲಾಗಿದೆ</translation>
-<translation id="5710871682236653961">ನೀವೠNFC ಸಾಧನಗಳನà³à²¨à³ ಟà³à²¯à²¾à²ªà³ ಮಾಡಿದಾಗ ಮಾಹಿತಿಯನà³à²¨à³ ಕಳà³à²¹à²¿à²¸à²²à³ ಮತà³à²¤à³ ಸà³à²µà³€à²•à²°à²¿à²¸à²²à³ ವೆಬà³â€Œà²¸à³ˆà²Ÿà³â€Œà²—ಳನà³à²¨à³ ಅನà³à²®à²¤à²¿à²¸à³à²µ ಮೊದಲೠಕೇಳಿ (ಶಿಫಾರಸೠಮಾಡಲಾಗಿದೆ)</translation>
<translation id="5719847187258001597"><ph name="ORIGIN" /> ಅಥವಾ ನಿಮà³à²® ಹೋಮೠಸà³à²•à³à²°à³€à²¨à³â€Œà²¨à²²à³à²²à²¿à²°à³à²µ ಅದರ ಆà³à²¯à²ªà³ ಮೂಲಕ ಸಂಗà³à²°à²¹à²£à³† ಮಾಡಲಾಗಿರà³à²µ ಎಲà³à²²à²¾ ಡೇಟಾ ಮತà³à²¤à³ ಕà³à²•à³€à²—ಳನà³à²¨à³ ಇದೠತೆರವà³à²—ೊಳಿಸà³à²¤à³à²¤à²¦à³†.</translation>
<translation id="5771720122942595109"><ph name="PERMISSION_1" /> ಅನà³à²¨à³ ನಿರà³à²¬à²‚ಧಿಸಲಾಗಿದೆ</translation>
<translation id="5804241973901381774">ಅನà³à²®à²¤à²¿à²—ಳà³</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">ಪà³à²²à³‡ ಮಾಡà³</translation>
<translation id="6818926723028410516">à²à²Ÿà²‚ಗಳನà³à²¨à³ ಆಯà³à²•à³†à²®à²¾à²¡à²¿</translation>
<translation id="6864395892908308021">ಈ ಸಾಧನವೠNFC ಯನà³à²¨à³ ಓದಲೠಸಾಧà³à²¯à²µà²¿à²²à³à²²</translation>
-<translation id="6910211073230771657">ಅಳಿಸಲಾಗಿದೆ</translation>
<translation id="6912998170423641340">ಕà³à²²à²¿à²ªà³â€Œà²¬à³‹à²°à³à²¡à³â€Œà²—ೆ ನಕಲಿಸಿರà³à²µ ಪಠà³à²¯ ಮತà³à²¤à³ ಚಿತà³à²°à²—ಳನà³à²¨à³ ಓದದಂತೆ ಸೈಟೠಅನà³à²¨à³ ನಿರà³à²¬à²‚ಧಿಸಿ</translation>
<translation id="6945221475159498467">ಆಯà³à²•à³†à²®à²¾à²¡à²¿</translation>
<translation id="6965382102122355670">ಸರಿ</translation>
+<translation id="6981982820502123353">ಪà³à²°à²µà³‡à²¶</translation>
<translation id="6992289844737586249">ನಿಮà³à²® ಮೈಕà³à²°à³‹à²«à³‹à²¨à³â€ ಬಳಸಲೠಸೈಟà³â€Œà²—ಳಿಗೆ ಅನà³à²®à²¤à²¿à²¸à³à²µ ಮೊದಲೠಕೇಳಿ (ಶಿಫಾರಸೠಮಾಡಲಾಗಿದೆ)</translation>
<translation id="7000754031042624318">Android ಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳಲà³à²²à²¿ ಆಫೠಮಾಡಲಾಗಿದೆ</translation>
<translation id="7016516562562142042">ಪà³à²°à²¸à³à²¤à³à²¤ ಹà³à²¡à³à²•à²¾à²Ÿ ಇಂಜಿನà³â€Œà²—ೆ ಅನà³à²®à²¤à²¿à²¸à²²à²¾à²—ಿದೆ</translation>
+<translation id="702463548815491781">TalkBack ಅಥವಾ ಪà³à²°à²µà³‡à²¶ ಬದಲಾಯಿಸಿ ಆನೠಆಗಿದà³à²¦à²¾à²— ಶಿಫಾರಸೠಮಾಡಲಾಗಿದೆ</translation>
<translation id="7053983685419859001">ನಿರà³à²¬à²‚ಧಿಸà³</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1 ಆಯà³à²•à³† ಮಾಡಲಾಗಿದೆ}one{# ಆಯà³à²•à³† ಮಾಡಲಾಗಿದೆ}other{# ಆಯà³à²•à³† ಮಾಡಲಾಗಿದೆ}}</translation>
-<translation id="7070090581017165256">ಈ ಸೈಟೠಕà³à²°à²¿à²¤à³</translation>
<translation id="7087918508125750058"><ph name="ITEM_COUNT" /> ಅನà³à²¨à³ ಆಯà³à²•à³† ಮಾಡಲಾಗಿದೆ. ಪರದೆಯ ಮೇಲà³à²­à²¾à²—ದಲà³à²²à²¿ ಲಭà³à²¯à²µà²¿à²°à³à²µ ಆಯà³à²•à³†à²—ಳà³</translation>
<translation id="7141896414559753902">ಪಾಪà³-ಅಪà³â€à²—ಳೠಮತà³à²¤à³ ಮರà³à²¨à²¿à²°à³à²¦à³‡à²¶à²¨à²—ಳನà³à²¨à³ ತೋರಿಸದಂತೆ ಸೈಟà³â€Œà²—ಳನà³à²¨à³ ನಿರà³à²¬à²‚ಧಿಸಿ (ಶಿಫಾರಸೠಮಾಡಲಾಗಿದೆ)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> KB</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">ಒಂದೠಸೈಟೠನಿಮà³à²® ಮೈಕà³à²°à³Šà²«à³‹à²¨à³ ಅನà³à²¨à³ ಬಳಸà³à²¤à³à²¤à²¿à²¦à³†</translation>
<translation id="7561196759112975576">ಯಾವಾಗಲೂ</translation>
-<translation id="7572498721684305250">ನೀವೠNFC ಸಾಧನಗಳನà³à²¨à³ ಟà³à²¯à²¾à²ªà³ ಮಾಡಿದಾಗ, ವೆಬà³â€Œà²¸à³ˆà²Ÿà³â€Œà²—ಳೠಮಾಹಿತಿ ಕಳà³à²¹à²¿à²¸à³à²µà³à²¦à²¨à³à²¨à³ ಮತà³à²¤à³ ಸà³à²µà³€à²•à²°à²¿à²¸à³à²µà³à²¦à²¨à³à²¨à³ ನಿರà³à²¬à²‚ಧಿಸಿ</translation>
<translation id="757524316907819857">ಸಂರಕà³à²·à²¿à²¤ ವಿಷಯವನà³à²¨à³ ಪà³à²²à³‡ ಮಾಡದಂತೆ ಸೈಟà³â€Œà²—ಳನà³à²¨à³ ನಿರà³à²¬à²‚ಧಿಸಿ</translation>
+<translation id="7577900504646297215">ಆಸಕà³à²¤à²¿à²—ಳನà³à²¨à³ ನಿರà³à²µà²¹à²¿à²¸à²¿</translation>
<translation id="7649070708921625228">ಸಹಾಯ</translation>
<translation id="7658239707568436148">ರದà³à²¦à³à²®à²¾à²¡à²¿</translation>
<translation id="7781829728241885113">ನಿನà³à²¨à³†</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">ಸಂಪರà³à²• ಸà³à²°à²•à³à²·à²¿à²¤à²µà²¾à²—ಿದೆ</translation>
<translation id="8249310407154411074">ಮೇಲಕà³à²•à³† ಸರಿಸಿ</translation>
<translation id="8261506727792406068">ಅಳಿಸಿ</translation>
+<translation id="8284326494547611709">ಶೀರà³à²·à²¿à²•à³†à²—ಳà³</translation>
<translation id="8300705686683892304">ಆà³à²¯à²ªà³ ಮೂಲಕ ನಿರà³à²µà²¹à²¿à²¸à²²à²¾à²—ಿದೆ</translation>
<translation id="8324158725704657629">ಮತà³à²¤à³† ಕೇಳಬೇಡ</translation>
<translation id="8372893542064058268">ನಿರà³à²¦à²¿à²·à³à²Ÿ ಸೈಟà³â€Œà²—ಾಗಿ ಹಿನà³à²¨à³†à²²à³† ಸಿಂಕà³â€Œ ಅನà³à²®à²¤à²¿à²¸à²¿.</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">à²à³‚ಮೠಇನà³</translation>
<translation id="8921772741368021346"><ph name="POSITION" /> / <ph name="DURATION" /></translation>
<translation id="8926666909099850184">ಈ ಸಾಧನದಲà³à²²à²¿ NFC ಅನà³à²¨à³ ಆಫೠಮಾಡಲಾಗಿದೆ. ಇದನà³à²¨à³ <ph name="BEGIN_LINK" />Android ಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳಲà³à²²à²¿<ph name="END_LINK" /> ತೆರೆಯಿರಿ.</translation>
+<translation id="8928445016601307354">NFC ಸಾಧನಗಳಲà³à²²à²¿ ಮಾಹಿತಿಯನà³à²¨à³ ನೋಡದಂತೆ ಮತà³à²¤à³ ಬದಲಾಯಿಸದಂತೆ ಸೈಟà³â€Œà²—ಳನà³à²¨à³ ನಿರà³à²¬à²‚ಧಿಸಿ</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">ನಿರà³à²¦à²¿à²·à³à²Ÿ ಸೈಟà³â€Œ ಒಂದಕà³à²•à³† ಕà³à²•à³€à²—ಳನà³à²¨à³ ನಿರà³à²¬à²‚ಧಿಸಿ.</translation>
<translation id="8959122750345127698">ನà³à²¯à²¾à²µà²¿à²—ೇಶನà³â€Œ ತಲà³à²ªà²²à²¾à²—à³à²µà³à²¦à²¿à²²à³à²²: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ko.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ko.xtb
index efcc10ac616..5c47aac0c59 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ko.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ko.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676"><ph name="SITE_NAME" /> 사ì´íŠ¸ 추가ë¨</translation>
<translation id="1383876407941801731">검색</translation>
<translation id="1384959399684842514">다운로드 ì¼ì‹œì¤‘지ë¨</translation>
+<translation id="1409426117486808224">열린 탭 간단히 보기</translation>
<translation id="1415402041810619267">URL 잘림</translation>
<translation id="1446450296470737166">MIDI ê¸°ê¸°ì˜ ì „ì²´ 제어 허용</translation>
<translation id="1620510694547887537">ì¹´ë©”ë¼</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">쿠키 허용</translation>
<translation id="2228071138934252756"><ph name="APP_NAME" />ì—ì„œ ì¹´ë©”ë¼ì— 액세스하ë„ë¡ í—ˆìš©í•˜ë ¤ë©´ <ph name="BEGIN_LINK" />Android 설정<ph name="END_LINK" />ì—ì„œë„ ì¹´ë©”ë¼ë¥¼ 사용 설정하세요.</translation>
<translation id="2241634353105152135">한 번만</translation>
+<translation id="2253414712144136228"><ph name="NAME_OF_LIST_ITEM" /> 삭제</translation>
<translation id="2289270750774289114">사ì´íŠ¸ê°€ 주변 블루투스 기기를 조회하려고 í•  ë•Œ 확ì¸(권장)</translation>
<translation id="2315043854645842844">í´ë¼ì´ì–¸íŠ¸ì¸¡ ì¸ì¦ì„œ ì„ íƒì´ ìš´ì˜ì²´ì œì—ì„œ 지ì›ë˜ì§€ 않습니다.</translation>
+<translation id="2321958826496381788">편하게 ì½ì„ 수 ìžˆì„ ë•Œê¹Œì§€ 슬ë¼ì´ë”를 드래그하세요. 단ë½ì„ ë‘ ë²ˆ 탭하면 í…스트가 ì´ ì´ìƒì˜ í¬ê¸°ë¡œ 표시ë©ë‹ˆë‹¤.</translation>
<translation id="2359808026110333948">계ì†</translation>
<translation id="2379925928934107488">가능하면 Chromeì—ì„œ ì–´ë‘ìš´ 테마를 사용할 ë•Œ 사ì´íŠ¸ì—ë„ ì–´ë‘ìš´ 테마를 ì ìš©í•©ë‹ˆë‹¤.</translation>
+<translation id="2387895666653383613">í…스트 í¬ê¸° ì¡°ì •</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" />MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> 외 <ph name="NUM_MORE" />ê°œ 허용ë¨}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> 외 <ph name="NUM_MORE" />ê°œ 허용ë¨}}</translation>
<translation id="2434158240863470628">다운로드 완료: <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">정보 표시</translation>
<translation id="3123473560110926937">ì¼ë¶€ 사ì´íŠ¸ì—ì„œ 차단ë¨</translation>
<translation id="3198916472715691905">저장 ë°ì´í„° <ph name="STORAGE_AMOUNT" /></translation>
+<translation id="3203366800380907218">웹ì—ì„œ ì°¾ì€ ì •ë³´</translation>
<translation id="321187648315454507"><ph name="APP_NAME" />ì—ì„œ ì•Œë¦¼ì„ ì „ì†¡í•˜ë„ë¡ í—ˆìš©í•˜ë ¤ë©´ <ph name="BEGIN_LINK" />Android 설정<ph name="END_LINK" />ì—ì„œë„ ì•Œë¦¼ì„ ì‚¬ìš© 설정하세요.</translation>
<translation id="3227137524299004712">마ì´í¬</translation>
<translation id="3277252321222022663">사ì´íŠ¸ì˜ 센서 액세스 허용(권장)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">기기 사용 여부</translation>
<translation id="385051799172605136">뒤로</translation>
<translation id="3859306556332390985">앞으로 íƒìƒ‰</translation>
+<translation id="3895926599014793903">확대/축소 강제 사용</translation>
<translation id="3955193568934677022">사ì´íŠ¸ì—ì„œ ë³´í˜¸ëœ ì½˜í…츠를 재ìƒí•˜ë„ë¡ í—ˆìš©(권장)</translation>
<translation id="3967822245660637423">다운로드 완료</translation>
<translation id="3987993985790029246">ë§í¬ 복사</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" />/?</translation>
<translation id="4002066346123236978">제목</translation>
<translation id="4008040567710660924">특정 사ì´íŠ¸ì˜ 쿠키를 허용합니다.</translation>
+<translation id="4040330681741629921">사ì´íŠ¸ë¥¼ 간단한 ë·°ë¡œ 표시할 수 ìžˆì„ ë•Œ 알림 받기</translation>
<translation id="4046123991198612571">ë‹¤ìŒ íŠ¸ëž™</translation>
+<translation id="4149994727733219643">웹페ì´ì§€ 간단히 보기</translation>
<translation id="4165986682804962316">사ì´íŠ¸ 설정</translation>
+<translation id="4194328954146351878">사ì´íŠ¸ì—ì„œ NFC ê¸°ê¸°ì˜ ì •ë³´ë¥¼ ë³´ê³  변경하ë„ë¡ í—ˆìš©í•˜ê¸° ì „ì— í™•ì¸(권장)</translation>
<translation id="4200726100658658164">위치 설정 열기</translation>
<translation id="4226663524361240545">ì•Œë¦¼ì´ ìžˆìœ¼ë©´ 진ë™ì´ 울릴 ìˆ˜ë„ ìžˆìŠµë‹ˆë‹¤.</translation>
<translation id="4259722352634471385">íƒìƒ‰ì´ 차단ë¨: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">펼치기</translation>
<translation id="4336434711095810371">모든 ë°ì´í„° ì‚­ì œ</translation>
<translation id="4402755511846832236">사용ìžê°€ 현재 기기를 사용 중ì¸ì§€ 사ì´íŠ¸ì—ì„œ ì•Œ 수 ì—†ë„ë¡ ì°¨ë‹¨í•©ë‹ˆë‹¤.</translation>
+<translation id="4428065317363009941">ê´‘ê³  ê°œì¸ ìµœì í™”</translation>
<translation id="4434045419905280838">íŒì—… ë° ë¦¬ë””ë ‰ì…˜</translation>
<translation id="445467742685312942">사ì´íŠ¸ì—ì„œ ë³´í˜¸ëœ ì½˜í…츠를 재ìƒí•˜ë„ë¡ í—ˆìš©</translation>
<translation id="4468959413250150279">특정 사ì´íŠ¸ë¥¼ ìŒì†Œê±°í•©ë‹ˆë‹¤.</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">화면 ìƒë‹¨ì—ì„œ ì˜µì…˜ì„ ì„ íƒí•  수 있습니다</translation>
<translation id="5197729504361054390">ì„ íƒí•œ ì—°ë½ì²˜ê°€ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />ê³¼(와) 공유ë©ë‹ˆë‹¤.</translation>
<translation id="5216942107514965959">최근 방문: 오늘</translation>
+<translation id="5264323282659631142">‘<ph name="CHIP_LABEL" />’ 삭제</translation>
<translation id="528192093759286357">ì „ì²´í™”ë©´ì„ ì¢…ë£Œí•˜ë ¤ë©´ ìƒë‹¨ì—ì„œ 드래그하여 뒤로 ë²„íŠ¼ì„ í„°ì¹˜í•˜ì„¸ìš”.</translation>
<translation id="5300589172476337783">표시</translation>
<translation id="5301954838959518834">확ì¸</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">사ì´íŠ¸ì—ì„œ 저장한 <ph name="DATASIZE" />ì˜ ë°ì´í„°ì™€ 쿠키가 ì‚­ì œë©ë‹ˆë‹¤.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(외 1개)}other{(외 #개)}}</translation>
<translation id="5403592356182871684">ì´ë¦„</translation>
+<translation id="5412236728747081950">ì´ ì‚¬ì´íŠ¸ëŠ” Chromeì— ì €ìž¥ëœ ë‚´ 관심분야 정보를 토대로 ë”ìš± 관련성 있는 광고를 표시합니다.</translation>
<translation id="5438097262470833822"><ph name="WEBSITE" />ì˜ ê¶Œí•œì´ ìž¬ì„¤ì •ë©ë‹ˆë‹¤.</translation>
<translation id="5489227211564503167"><ph name="TOTAL_TIME" /> 중 <ph name="ELAPSED_TIME" /> 경과</translation>
<translation id="5494752089476963479">ë°©í•´ê°€ ë˜ê±°ë‚˜ 사용ìžë¥¼ 현혹하는 광고를 표시하는 사ì´íŠ¸ì˜ ê´‘ê³  차단</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">새로고침</translation>
<translation id="5596627076506792578">옵션 ë”보기</translation>
<translation id="5649053991847567735">ìžë™ 다운로드</translation>
+<translation id="5668404140385795438">웹사ì´íŠ¸ì˜ 확대 방지 요청 무시</translation>
<translation id="5677928146339483299">차단</translation>
<translation id="5689516760719285838">위치</translation>
<translation id="5690795753582697420">Android 설정ì—ì„œ ì¹´ë©”ë¼ê°€ 사용 중지ë©ë‹ˆë‹¤.</translation>
-<translation id="5710871682236653961">NFC 기기를 탭하면 사ì´íŠ¸ê°€ 정보를 주고받ë„ë¡ í—ˆìš©í• ì§€ 확ì¸(권장)</translation>
<translation id="5719847187258001597">ì´ë ‡ê²Œ 하면 <ph name="ORIGIN" /> ë˜ëŠ” 홈 í™”ë©´ì˜ ì•±ì— ì €ìž¥í•œ ë°ì´í„° ë° ì¿ í‚¤ê°€ ëª¨ë‘ ì‚­ì œë©ë‹ˆë‹¤.</translation>
<translation id="5771720122942595109"><ph name="PERMISSION_1" /> 차단ë¨</translation>
<translation id="5804241973901381774">권한</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">재ìƒ</translation>
<translation id="6818926723028410516">항목 ì„ íƒ</translation>
<translation id="6864395892908308021">기기ì—ì„œ NFC를 ì½ì„ 수 ì—†ìŒ</translation>
-<translation id="6910211073230771657">ì‚­ì œë¨</translation>
<translation id="6912998170423641340">사ì´íŠ¸ì—ì„œ í´ë¦½ë³´ë“œì˜ í…스트 ë° ì´ë¯¸ì§€ì— 액세스하지 못하ë„ë¡ ì°¨ë‹¨</translation>
<translation id="6945221475159498467">ì„ íƒ</translation>
<translation id="6965382102122355670">확ì¸</translation>
+<translation id="6981982820502123353">접근성</translation>
<translation id="6992289844737586249">사ì´íŠ¸ì—ì„œ 마ì´í¬ë¥¼ 사용하기 ì „ì— í™•ì¸(권장)</translation>
<translation id="7000754031042624318">Android 설정ì—ì„œ 사용 중지ë¨</translation>
<translation id="7016516562562142042">현재 ê²€ìƒ‰ì—”ì§„ì— í—ˆìš©ë¨</translation>
+<translation id="702463548815491781">ìŒì„± 안내 ì§€ì› ë˜ëŠ” 스위치 제어를 사용 ì¤‘ì¼ ë•Œ 권장ë©ë‹ˆë‹¤.</translation>
<translation id="7053983685419859001">차단</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1ê°œ ì„ íƒë¨}other{#ê°œ ì„ íƒë¨}}</translation>
-<translation id="7070090581017165256">사ì´íŠ¸ ì •ë³´</translation>
<translation id="7087918508125750058"><ph name="ITEM_COUNT" />ê°œ ì„ íƒë¨. 화면 ìƒë‹¨ì—ì„œ 옵션 ì„ íƒ ê°€ëŠ¥</translation>
<translation id="7141896414559753902">사ì´íŠ¸ì—ì„œ íŒì—… ë° ë¦¬ë””ë ‰ì…˜ì„ í‘œì‹œí•˜ì§€ 못하ë„ë¡ ì°¨ë‹¨(권장)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" />KB</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">ìžë°”스í¬ë¦½íŠ¸</translation>
<translation id="7554752735887601236">사ì´íŠ¸ì—ì„œ 마ì´í¬ë¥¼ 사용 중입니다.</translation>
<translation id="7561196759112975576">í•­ìƒ</translation>
-<translation id="7572498721684305250">NFC 기기를 탭할 ë•Œ 사ì´íŠ¸ê°€ 정보를 주고받지 못하ë„ë¡ ì°¨ë‹¨</translation>
<translation id="757524316907819857">사ì´íŠ¸ì—ì„œ ë³´í˜¸ëœ ì½˜í…츠를 재ìƒí•˜ì§€ 못하ë„ë¡ ì°¨ë‹¨</translation>
+<translation id="7577900504646297215">관심분야 관리</translation>
<translation id="7649070708921625228">ë„움ë§</translation>
<translation id="7658239707568436148">취소</translation>
<translation id="7781829728241885113">어제</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">ì´ ì‚¬ì´íŠ¸ëŠ” 보안 ì—°ê²°(HTTPS)ì´ ì‚¬ìš©ë˜ì—ˆìŠµë‹ˆë‹¤.</translation>
<translation id="8249310407154411074">맨 위로 ì´ë™</translation>
<translation id="8261506727792406068">삭제</translation>
+<translation id="8284326494547611709">ìžë§‰</translation>
<translation id="8300705686683892304">앱ì—ì„œ 관리함</translation>
<translation id="8324158725704657629">다시 묻지 ì•ŠìŒ</translation>
<translation id="8372893542064058268">특정 사ì´íŠ¸ì—ì„œ 백그ë¼ìš´ë“œ ë™ê¸°í™”를 허용합니다.</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">확대</translation>
<translation id="8921772741368021346"><ph name="POSITION" />/<ph name="DURATION" /></translation>
<translation id="8926666909099850184">기기ì—ì„œ NFCê°€ 사용 중지ë˜ì–´ 있습니다. <ph name="BEGIN_LINK" />Android 설정<ph name="END_LINK" />ì—ì„œ NFC를 사용 설정하세요.</translation>
+<translation id="8928445016601307354">사ì´íŠ¸ì—ì„œ NFC ê¸°ê¸°ì˜ ì •ë³´ë¥¼ ë³´ê³  변경할 수 ì—†ë„ë¡ ì°¨ë‹¨</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">특정 사ì´íŠ¸ì˜ 쿠키를 차단합니다.</translation>
<translation id="8959122750345127698">íƒìƒ‰í•  수 ì—†ìŒ: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ky.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ky.xtb
index 99d18ef7c2b..8e69ac1856d 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ky.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ky.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676"><ph name="SITE_NAME" /> Ñайты кошулду</translation>
<translation id="1383876407941801731">Издөө</translation>
<translation id="1384959399684842514">Жүктөп алуу тындырылды</translation>
+<translation id="1409426117486808224">Ðчык өтмөктөр үчүн жөнөкөйлөштүрүлгөн көрүнүш</translation>
<translation id="1415402041810619267">URL кеÑилди</translation>
<translation id="1446450296470737166">MIDI түзмктрд толук көзмлд уркÑÑ‚</translation>
<translation id="1620510694547887537">Камера</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">Cookies файлдарына урукÑат берүү</translation>
<translation id="2228071138934252756"><ph name="APP_NAME" /> колдонмоÑуна камерага кирүүгө урукÑат берүү үчүн, <ph name="BEGIN_LINK" />Android Жөндөөлөрүнөн<ph name="END_LINK" /> камераны күйгүзүңүз.</translation>
<translation id="2241634353105152135">Бир гана жлу</translation>
+<translation id="2253414712144136228"><ph name="NAME_OF_LIST_ITEM" /> өчүрүү</translation>
<translation id="2289270750774289114">Сайт жакын жердеги Bluetooth түзмөктөрүн колдонгону жатканда урукÑат ÑуралÑын (Ñунушталат)</translation>
<translation id="2315043854645842844">Кардар тандаган таÑтыктама операциÑлык тутумда колдоого алынбайт.</translation>
+<translation id="2321958826496381788">Жылмышкычты текÑтти окуганга ыңгайлуу болгонго чейин Ñүйрөңүз. Параграфты Ñки жолу таптаганыңыздан кийин, текÑÑ‚ ушундай өлчөмдө көрүнүп калышы керек.</translation>
<translation id="2359808026110333948">Улантуу</translation>
<translation id="2379925928934107488">Chrome'до караңгы тема колдонулуп жатканда, Ñайттарга караңгы теманы колдонуу (мүмкүн болгондо)</translation>
+<translation id="2387895666653383613">ТекÑтти чен өлчөмдөө</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> Мб</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> жана дагы <ph name="NUM_MORE" /> үчүн урукÑат берилди}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> жана дагы <ph name="NUM_MORE" /> үчүн урукÑат берилди}}</translation>
<translation id="2434158240863470628">Жүктөлүп алынды: <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">Маалыматты көрÑÓ©Ñ‚Ò¯Ò¯</translation>
<translation id="3123473560110926937">Ðйрым Ñайттарда бөгөттөлдү</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> Ñакталган дайындар</translation>
+<translation id="3203366800380907218">Интернеттен алынды</translation>
<translation id="321187648315454507"><ph name="APP_NAME" /> колдонмоÑуна билдирмелерди жөнөтүүгө урукÑат берүү үчүн, <ph name="BEGIN_LINK" />Android Жөндөөлөрүнөн<ph name="END_LINK" /> билдирмелерди күйгүзүңүз.</translation>
<translation id="3227137524299004712">Микрофон</translation>
<translation id="3277252321222022663">Сайттарга ÑенÑорлорду колдонууга урукÑат берүү (Ñунушталат)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">Түзмөгүңүздүн колдонулушу</translation>
<translation id="385051799172605136">Ðртка</translation>
<translation id="3859306556332390985">Ðлдыга түрдүрүү</translation>
+<translation id="3895926599014793903">Мажбурлап чоңойтууну иштетүү</translation>
<translation id="3955193568934677022">Сайттарга корголгон мазмунду ойнотууга урукÑат берүү (Ñунушталат)</translation>
<translation id="3967822245660637423">Жүктөп алуу аÑктады</translation>
<translation id="3987993985790029246">Шилтм көчр</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> / ?</translation>
<translation id="4002066346123236978">Ðталышы</translation>
<translation id="4008040567710660924">Белгилүү бир Ñайттын cookie файлдарына урукÑат берүү.</translation>
+<translation id="4040330681741629921">Сайттын жөнөкөйлөтүлгөн көрүнүшү жеткиликтүү болгондо кабар алуу</translation>
<translation id="4046123991198612571">Кийинки трек</translation>
+<translation id="4149994727733219643">Веб барактар үчүн жөнөкөйлөштүрүлгөн көрүнүш</translation>
<translation id="4165986682804962316">Сайт жөндөөлөрү</translation>
+<translation id="4194328954146351878">Колдонмолор NFC түзмөктөрүндөгү маалыматты көрүп жана өзгөрткөнү жатканда урукÑат ÑуралÑын (Ñунушталат)</translation>
<translation id="4200726100658658164">Жайгашкан жерди аныктоо жөндөөлөрүн ачуу</translation>
<translation id="4226663524361240545">Билдирмелер кегенде түзмөк дирилдейт</translation>
<translation id="4259722352634471385">Чабыттоо бөгөттөлгөн: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">Жайып көрÑÓ©Ñ‚Ò¯Ò¯</translation>
<translation id="4336434711095810371">Бардык маалыматты өчүрүү</translation>
<translation id="4402755511846832236">Түзмөгүңүз активдүү колдонулуп жаткан учур Ñайттардан жашырылÑын</translation>
+<translation id="4428065317363009941">Жарнамаларды жекелештирүү</translation>
<translation id="4434045419905280838">Калкыма терезелер жана багыттоолор</translation>
<translation id="445467742685312942">Сайттарга корголгон мазмунду ойнотууга урукÑат берүү</translation>
<translation id="4468959413250150279">Белгилүү бир Ñайттын үнүн өчүрүү.</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">Параметр Ñкрандын жогору жагында берилген</translation>
<translation id="5197729504361054390">Сиз тандаган байланыштар <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> менен бөлүшүлөт.</translation>
<translation id="5216942107514965959">Бүгүн акыркы жолу кирген</translation>
+<translation id="5264323282659631142">"<ph name="CHIP_LABEL" />" өчүрүү</translation>
<translation id="528192093759286357">Толук Ñкрандан чыгуу үчүн жогорудан ылдый Ñүйрөп келип, "Ðртка" деген баÑкычка тийип коюңуз.</translation>
<translation id="5300589172476337783">КөрÑÓ©Ñ‚Ò¯Ò¯</translation>
<translation id="5301954838959518834">Жарайт, түшүндүм</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">Ушуну менен маалымат жана cookie-файлдары ÑÑлеп турган <ph name="DATASIZE" /> орун бошотулат.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(+ дагы 1)}other{(+ дагы #)}}</translation>
<translation id="5403592356182871684">ЫÑымдар</translation>
+<translation id="5412236728747081950">Бул Ñайт Сhrome'дон кызыккан нерÑелериңиз тууралуу маалымат алып, Ñизге ылайыктуу жарнамаларды көрÑөтүп турат</translation>
<translation id="5438097262470833822">Ушуну менен <ph name="WEBSITE" /> Ñайтынын урукÑаттары баштапкы абалга келтирилет</translation>
<translation id="5489227211564503167"><ph name="TOTAL_TIME" /> ичинен <ph name="ELAPSED_TIME" /> өттү.</translation>
<translation id="5494752089476963479">Тажатма же адаштыруучу жарнамаларды көрÑөткөн Ñайттан келген жарнамалар бөгөттөлÑүн</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">Кайра жүктөө</translation>
<translation id="5596627076506792578">Дагы параметрлер</translation>
<translation id="5649053991847567735">Ðвтоматтык жүктөп алуулар</translation>
+<translation id="5668404140385795438">Чоңойтууга жол берилбеÑин деген вебÑайттын Ñурамын жокко чыгаруу</translation>
<translation id="5677928146339483299">Бөгөттөлгөн</translation>
<translation id="5689516760719285838">Жайгашкан жер</translation>
<translation id="5690795753582697420">Камера Android жөндөөлөрүнөн өчүрүлдү</translation>
-<translation id="5710871682236653961">NFC түзмөктөрүн баÑканда Ñайттар маалыматты жөнөтүүдөн жана алуудан мурда урукÑат ÑуралÑын (Ñунушталат)</translation>
<translation id="5719847187258001597">Ушуну менен <ph name="ORIGIN" /> жана анын колдонмоÑу Башкы Ñкраныңызда Ñактаган маалымат менен cookie файлдар тазаланат.</translation>
<translation id="5771720122942595109"><ph name="PERMISSION_1" /> бөгөттөлдү</translation>
<translation id="5804241973901381774">УрукÑаттар</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">Ойнотуу</translation>
<translation id="6818926723028410516">Элементтерди тандоо</translation>
<translation id="6864395892908308021">Бул түзмөк NFC'ни окуй албайт</translation>
-<translation id="6910211073230771657">Жок кылынды</translation>
<translation id="6912998170423641340">Сайттарда алмашуу буфериндеги текÑттер жана Ñүрөттөрдү окуу бөгөттөлÑүн</translation>
<translation id="6945221475159498467">Тандаңыз</translation>
<translation id="6965382102122355670">OK</translation>
+<translation id="6981982820502123353">Ðтайын мүмкүн-Ñ‚Ó©Ñ€</translation>
<translation id="6992289844737586249">Сайттар микрофонуңузду колдоноордон мурун урукÑат ÑуралÑын (Ñунушталат)</translation>
<translation id="7000754031042624318">Android Жөндөөлөрүнөн өчүрүлгөн</translation>
<translation id="7016516562562142042">Учурдагы издөө каражаты үчүн урукÑат берилген</translation>
+<translation id="702463548815491781">TalkBack же Switch Access функциÑлары күйүк кезде Ñунушталат</translation>
<translation id="7053983685419859001">Бөгөттөө</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1 тандалды}other{# тандалды}}</translation>
-<translation id="7070090581017165256">Ушул Ñайт жөнүндө</translation>
<translation id="7087918508125750058"><ph name="ITEM_COUNT" /> тандалды. Параметрлер Ñкрандын жогору жагында берилген</translation>
<translation id="7141896414559753902">Сайттарда калкыма терезелерди көрÑÓ©Ñ‚Ò¯Ò¯ менен багыттоолор бөгөттөлÑүн (Ñунушталат)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> Кб</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">Сайт микрофонуңузду колдонуп жатат</translation>
<translation id="7561196759112975576">ÐÑ€ дайым</translation>
-<translation id="7572498721684305250">NFC түзмөктөрүн баÑканда Ñайттардын маалыматты жөнөтүү жана алууÑу бөгөттөлÑүн</translation>
<translation id="757524316907819857">Сайттарга корголгон мазмунду ойнотууга тыюу ÑалынÑын</translation>
+<translation id="7577900504646297215">Кызыккан нерÑелерди башкаруу</translation>
<translation id="7649070708921625228">Жардам</translation>
<translation id="7658239707568436148">Жокко чыгаруу</translation>
<translation id="7781829728241885113">КечÑÑ</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">Туташуу коопÑуз</translation>
<translation id="8249310407154411074">Башына жылдыруу</translation>
<translation id="8261506727792406068">Жок кылуу</translation>
+<translation id="8284326494547611709">Коштомо жазуулар</translation>
<translation id="8300705686683892304">Колдонмо тарабынан башкарылууда</translation>
<translation id="8324158725704657629">Экинчи ÑуралбаÑын</translation>
<translation id="8372893542064058268">Белгилүү бир Ñайт фондо шайкештирилишине урукÑат берүү.</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">Чоңойтуу</translation>
<translation id="8921772741368021346"><ph name="POSITION" />/<ph name="DURATION" /></translation>
<translation id="8926666909099850184">NFC бул түзмөктө өчүрүлгөн. <ph name="BEGIN_LINK" />Android жөндөөлөрүнө<ph name="END_LINK" /> өтүп, аны күйгүзүңүз.</translation>
+<translation id="8928445016601307354">Сайттардын NFC түзмөктөрүндөгү маалыматты көрүү жана өзгөртүү мүмкүнчүлүгүн бөгөттөө</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">Белгилүү бир Ñайттын cookie файлдарын бөгөттөө.</translation>
<translation id="8959122750345127698">Чабыттоо жеткиликÑиз: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_lo.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_lo.xtb
index c80f0088f58..ef95e28424c 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_lo.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_lo.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">ເພີ່ມ <ph name="SITE_NAME" /> ເວັບ​ໄຊ​ທ໌​à»àº¥à»‰àº§</translation>
<translation id="1383876407941801731">ຊອàºàº«àº²</translation>
<translation id="1384959399684842514">ຢຸດàºàº²àº™àº”າວໂຫລດໄວ້ຊົ່ວຄາວà»àº¥à»‰àº§</translation>
+<translation id="1409426117486808224">ມຸມມອງງ່າàºàº”າàºàºªàº³àº¥àº±àºšà»àº–ບທີ່ເປີດຢູ່</translation>
<translation id="1415402041810619267">ຕັດ URL ໃຫ້ສັ້ນລົງà»àº¥à»‰àº§</translation>
<translation id="1446450296470737166">ອະ​ນຸ​àºàº²àº”​àºàº²àº™â€‹àº„ວບ​ຄຸມ​ອຸ​ປະ​àºàº­àº™ MIDI ເຕັມ</translation>
<translation id="1620510694547887537">àºà»‰àº­àº‡â€‹àº–່າàºâ€‹àº®àº¹àºš</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">ອະນຸàºàº²àº”ຄຸàºàºàºµà»‰</translation>
<translation id="2228071138934252756">ເພື່ອອະນຸàºàº²àº”ໃຫ້ <ph name="APP_NAME" /> ເຂົ້າເຖິງàºà»‰àº­àº‡àº–່າàºàº®àº¹àºšàº‚ອງທ່ານ, àºàº°àº¥àº¸àº™àº²à»€àº›àºµàº”àºà»‰àº­àº‡àº–່າàºàº®àº¹àºšà»ƒàº™ <ph name="BEGIN_LINK" />àºàº²àº™àº•àº±à»‰àº‡àº„່າ Android<ph name="END_LINK" /> ນຳ.</translation>
<translation id="2241634353105152135">ຄັ້ງ​ດຽວ​ເທົ່າ​ນັ້ນ</translation>
+<translation id="2253414712144136228"><ph name="NAME_OF_LIST_ITEM" /> ລຶບອອàº</translation>
<translation id="2289270750774289114">ຖາມເມື່ອເວັບໄຊຕ້ອງàºàº²àº™àºàº§àº”ຫາອຸປະàºàº­àº™ Bluetooth ທີ່ຢູ່ໃàºà»‰àº„ຽງ (à»àº™àº°àº™àº³)</translation>
<translation id="2315043854645842844">àºàº²àº™â€‹à»€àº¥àº·àº­àºâ€‹à»ƒàºšâ€‹àº¢àº±à»‰àº‡â€‹àº¢àº·àº™à»€àºšàº·à»‰àº­àº‡â€‹àº¥àº¹àºâ€‹àº‚່າàºâ€‹àºšà»à»ˆâ€‹àº–ືàºâ€‹àº®àº­àº‡â€‹àº®àº±àºšâ€‹à»‚ດàºâ€‹àº¥àº°â€‹àºšàº»àºšâ€‹àº›àº°àº•àº´àºšàº±àº”àºàº²àº™.</translation>
+<translation id="2321958826496381788">ລາàºâ€‹àºšà»ˆàº­àº™â€‹à»€àº¥àº·à»ˆàº­àº™â€‹à»„ປ​ຈົນ​àºàº§à»ˆàº²â€‹àº—່ານ​ຈະ​ຮູ້​ສຶàºâ€‹àº§à»ˆàº²â€‹àº­à»ˆàº²àº™â€‹à»„ດ້​ສະບາàºâ€‹àº•àº². ຂà»à»‰àº„ວາມ​ໃນ​ໜ້າເວັບ​​ຈະ​ມີ​ຂະໜາດ​ໃຫàºà»ˆâ€‹à»€àº—ົ່າ​ນີ້​ເປັນ​ຢ່າງ​ໜ້ອàºâ€‹à»€àº¡àº·à»ˆàº­â€‹àº—ຳàºàº²àº™â€‹à»àº•àº°â€‹à»ƒàºªà»ˆâ€‹àº«àºà»à»‰â€‹à»œà»‰àº²â€‹àº‚à»à»‰àº„ວາມ​ໃດ​ນຶ່ງ​ສອງ​ເທື່ອ.</translation>
<translation id="2359808026110333948">ສືບຕà»à»ˆ</translation>
<translation id="2379925928934107488">ນຳໃຊ້ຮູບà»àºšàºšàºªàºµàºªàº±àº™àº¡àº·àº”ໃສ່ເວັບໄຊເມື່ອ Chrome ໃຊ້ຮູບà»àºšàºšàºªàºµàºªàº±àº™àº¡àº·àº”, ເມື່ອເປັນໄປໄດ້.</translation>
+<translation id="2387895666653383613">ຂະໜາດໂຕໜັງສື</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{ອະນຸàºàº²àº” <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> à»àº¥àº° ອີຠ<ph name="NUM_MORE" /> ລາàºàºàº²àº™à»àº¥à»‰àº§}other{ອະນຸàºàº²àº” <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> à»àº¥àº° ອີຠ<ph name="NUM_MORE" /> ລາàºàºàº²àº™à»àº¥à»‰àº§}}</translation>
<translation id="2434158240863470628">àºàº²àº™àº”າວໂຫຼດສຳເລັດà»àº¥à»‰àº§ <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">ສະà»àº”ງຂà»à»‰àº¡àº¹àº™</translation>
<translation id="3123473560110926937">ບລັອàºà»ƒàº™àºšàº²àº‡à»€àº§àº±àºšà»„ຊ</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> ຂà»à»‰â€‹àº¡àº¹àº™â€‹à»€àºàº±àºšâ€‹àº®àº±àºâ€‹àºªàº²â€‹à»„ວ້</translation>
+<translation id="3203366800380907218">​ຈາàºâ€‹à»€àº§àº±àºšâ€‹à»„ຊ</translation>
<translation id="321187648315454507">ເພື່ອອະນຸàºàº²àº”ໃຫ້ <ph name="APP_NAME" /> ສົ່ງàºàº²àº™à»àºˆà»‰àº‡à»€àº•àº·àº­àº™à»ƒàº«à»‰àº—່ານ, àºàº°àº¥àº¸àº™àº²à»€àº›àºµàº”àºàº²àº™à»àºˆà»‰àº‡à»€àº•àº·àº­àº™à»ƒàº™ <ph name="BEGIN_LINK" />àºàº²àº™àº•àº±à»‰àº‡àº„່າ Android<ph name="END_LINK" /> ນຳ.</translation>
<translation id="3227137524299004712">ໄມໂຄຣໂຟນ</translation>
<translation id="3277252321222022663">ອະນຸàºàº²àº”ໃຫ້ເວັບໄຊເຂົ້າເຖິງເຊັນເຊີ (à»àº™àº°àº™àº³)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">àºàº²àº™àº™àº³à»ƒàºŠà»‰àº­àº¸àº›àº°àºàº­àº™àº‚ອງທ່ານ</translation>
<translation id="385051799172605136">àºàº±àºšâ€‹àº„ືນ​</translation>
<translation id="3859306556332390985">ເລື່ອນໄປໜ້າ</translation>
+<translation id="3895926599014793903">ບັງຄັບໃຫ້ເປີດ​ໃຊ້​àºàº²àº™â€‹àºŠàº¹àº¡</translation>
<translation id="3955193568934677022">ອະນຸàºàº²àº”ໃຫ້ເວັບໄຊຕ່າງໆຫຼິ້ນເນື້ອຫາທີ່ໄດ້ຮັບàºàº²àº™àº›àº»àºàº›à»‰àº­àº‡ (à»àº™àº°àº™àº³)</translation>
<translation id="3967822245660637423">ດາວ​ໂຫຼດ​ສຳ​ເລັດ</translation>
<translation id="3987993985790029246">ອັດ​ສຳ​ເນົາລິ້ງເຊື່ອມໂàºàº‡</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> / ?</translation>
<translation id="4002066346123236978">ຫົວຂà»à»‰</translation>
<translation id="4008040567710660924">ອະນຸàºàº²àº”ຄຸàºàºàºµà»‰àºªàº³àº¥àº±àºšà»€àº§àº±àºšà»„ຊສະເພາະ.</translation>
+<translation id="4040330681741629921">ຮັບàºàº²àº™à»àºˆà»‰àº‡à»€àº•àº·àº­àº™à»€àº¡àº·à»ˆàº­àºªàº²àº¡àº²àº”ສະà»àº”ງເວັບໄຊໃດໜຶ່ງໃນມຸມມອງà»àºšàºšàº‡à»ˆàº²àºà»„ດ້</translation>
<translation id="4046123991198612571">ເພງຕà»à»ˆà»„ປ</translation>
+<translation id="4149994727733219643">ມຸມມອງງ່າàºàº”າàºàºªàº³àº¥àº±àºšà»œà»‰àº²à»€àº§àº±àºš</translation>
<translation id="4165986682804962316">àºàº²àº™àº•àº±à»‰àº‡àº„່າເວັບໄຊທ໌</translation>
+<translation id="4194328954146351878">ຖາມàºà»ˆàº­àº™àºàº²àº™àº­àº°àº™àº¸àºàº²àº”ໃຫ້ເວັບໄຊເບິ່ງເຫັນ à»àº¥àº° ປ່ຽນຂà»à»‰àº¡àº¹àº™àº¢àº¹à»ˆàº­àº¸àº›àº°àºàº­àº™ NFC (à»àº™àº°àº™àº³)</translation>
<translation id="4200726100658658164">ເປີດàºàº²àº™àº•àº±à»‰àº‡àº„່າສະຖານທີ່</translation>
<translation id="4226663524361240545">àºàº²àº™à»àºˆà»‰àº‡à»€àº•àº·àº­àº™àº­àº²àº”ຈະເຮັດໃຫ້ອຸປະàºàº­àº™àºªàº±à»ˆàº™</translation>
<translation id="4259722352634471385">àºàº²àº™àº™à»àº²àº—າງຖືàºàºšàº¥àº±àº­àºà»„ວ້: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">ຂະ​ຫàºàº²àº</translation>
<translation id="4336434711095810371">ລຶບລ້າງຂà»à»‰àº¡àº¹àº™àº—ັງà»àº»àº”</translation>
<translation id="4402755511846832236">ບລັອàºàºšà»à»ˆà»ƒàº«à»‰à»€àº§àº±àºšà»„ຊຮູ້ໃນເວລາທີ່ທ່ານàºàº³àº¥àº±àº‡à»ƒàºŠà»‰àº­àº¸àº›àº°àºàº­àº™àº™àºµà»‰àº¢àº¹à»ˆ</translation>
+<translation id="4428065317363009941">àºàº²àº™àº›àº±àºšà»àº•à»ˆàº‡à»‚ຄສະນາເປັນà»àºšàºšàºªà»ˆàº§àº™àº•àº»àº§</translation>
<translation id="4434045419905280838">ປັອບອັບ à»àº¥àº° àºàº²àº™àº›à»ˆàº½àº™à»€àºªàº±à»‰àº™àº—າງ</translation>
<translation id="445467742685312942">ອະນຸàºàº²àº”ໃຫ້ເວັບໄຊຫຼິ້ນເນື້ອຫາທີ່ໄດ້ຮັບàºàº²àº™àº›àº»àºàº›à»‰àº­àº‡</translation>
<translation id="4468959413250150279">ປິດສຽງສຳລັບເວັບໄຊສະເພາະໃດໜຶ່ງ.</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">ຕົວເລືອàºàº¡àºµà»ƒàº«à»‰àº™àº³à»ƒàºŠà»‰àº¢àº¹à»ˆà»ƒàºà»‰àºªà»ˆàº§àº™à»€àº—ິງສຸດຂອງໜ້າຈà»</translation>
<translation id="5197729504361054390">ລາàºàºŠàº·à»ˆàºœàº¹à»‰àº•àº´àº”ຕà»à»ˆàº—ີ່ທ່ານເລືອàºàºˆàº°àº–ືàºà»àºšà»ˆàº‡àº›àº±àº™àºàº±àºš <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />.</translation>
<translation id="5216942107514965959">ເຂົ້າເບິ່ງມື້ນີ້</translation>
+<translation id="5264323282659631142">ລຶບ '<ph name="CHIP_LABEL" />' ອອàº</translation>
<translation id="528192093759286357">ລາàºàºˆàº²àºàº”້ານເທິງ à»àº¥à»‰àº§à»àº•àº°àº›àº¸à»ˆàº¡àºàº±àºšàº„ືນ ເພື່ອອອàºàºˆàº²àºà»€àº•àº±àº¡àºˆà».</translation>
<translation id="5300589172476337783">ສະ​à»àº”ງ​</translation>
<translation id="5301954838959518834">ຕົàºàº¥àº»àº‡, ເຂົ້າໃຈà»àº¥à»‰àº§</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">ນີ້ຈະລຶບລ້າງຂà»à»‰àº¡àº¹àº™ <ph name="DATASIZE" /> à»àº¥àº° ຄຸàºàºàºµà»‰àº—ັງà»àº»àº”ທີ່ເàºàº±àºšà»„ວ້ໂດàºà»€àº§àº±àºšà»„ຊ.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(ອີຠ1 ລາàºàºàº²àº™)}other{(ອີຠ# ລາàºàºàº²àº™)}}</translation>
<translation id="5403592356182871684">ຊື່</translation>
+<translation id="5412236728747081950">ເວັບໄຊນີ້ໄດ້ຮັບຄວາມສົນໃຈຂອງທ່ານຈາຠChrome ເພື່ອສະà»àº”ງໂຄສະນາທີ່àºà»ˆàº½àº§àº‚້ອງຫຼາàºàº‚ຶ້ນໃຫ້ທ່ານເຫັນ</translation>
<translation id="5438097262470833822">ຕົວເລືອàºàº™àºµà»‰àºˆàº°àº£àºµà»€àºŠàº±àº”àºàº²àº™àº­àº°àº™àº¸àºàº²àº”ສຳລັບ <ph name="WEBSITE" /></translation>
<translation id="5489227211564503167">ເວລາຜ່ານໄປ <ph name="ELAPSED_TIME" /> ຈາàºàº—ັງà»àº»àº” <ph name="TOTAL_TIME" />.</translation>
<translation id="5494752089476963479">ບລັອàºà»‚ຄສະນາໃນເວັບໄຊທີ່ສະà»àº”ງໂຄສະນາທີ່ລົບàºàº§àº™ ຫຼື ຫຼອàºàº¥àº§àº‡</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">ໂຫຼດຄືນໃà»à»ˆ</translation>
<translation id="5596627076506792578">ໂຕ​ເລືອàºâ€‹à»€àºžàºµà»ˆàº¡â€‹à»€àº•àºµàº¡</translation>
<translation id="5649053991847567735">ດາວ​ໂຫຼດ​ອັດ​ຕະ​ໂນ​ມັດ</translation>
+<translation id="5668404140385795438">à»àº—ນ​ທີ່​ຄຳ​ຂà»â€‹àº‚ອງ​ເວັບໄຊທ໌​ເພື່ອ​ປ້ອງ​àºàº±àº™â€‹àºàº²àº™â€‹àºŠàº¹àº¡â€‹à»€àº‚ົ້າ</translation>
<translation id="5677928146339483299">ບລັອàºà»àº¥à»‰àº§</translation>
<translation id="5689516760719285838">ສະຖານທີ່</translation>
<translation id="5690795753582697420">àºà»‰àº­àº‡àº›àº´àº”ຢູ່ໃນàºàº²àº™àº•àº±à»‰àº‡àº„່າ Android</translation>
-<translation id="5710871682236653961">ຖາມàºà»ˆàº­àº™àº—ີ່ຈະອະນຸàºàº²àº”ໃຫ້ເວັບໄຊສົ່ງ à»àº¥àº° ຮັບຂà»à»‰àº¡àº¹àº™à»ƒàº™à»€àº§àº¥àº²àº—ີ່ທ່ານà»àº•àº°àº­àº¸àº›àº°àºàº­àº™ NFC (à»àº™àº°àº™àº³)</translation>
<translation id="5719847187258001597">ນີ້ຈະລຶບລ້າງຂà»à»‰àº¡àº¹àº™ à»àº¥àº° ຄຸàºàºàºµà»‰àº—ັງà»àº»àº”ທີ່ເàºàº±àºšà»„ວ້ໂດຠ<ph name="ORIGIN" /> ຫຼື ໂດàºà»àº­àº±àºšàº‚ອງມັນໃນໜ້າຈà»àº«àº¼àº±àºàº‚ອງທ່ານ.</translation>
<translation id="5771720122942595109">ບລັອຠ<ph name="PERMISSION_1" /> ໄວ້à»àº¥à»‰àº§</translation>
<translation id="5804241973901381774">àºàº²àº™â€‹àº­àº°â€‹àº™àº¸â€‹àºàº²àº”</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">​ຫຼິ້ນ</translation>
<translation id="6818926723028410516">ເລືອàºàº¥àº²àºàºàº²àº™</translation>
<translation id="6864395892908308021">ອຸປະàºàº­àº™àº™àºµà»‰àºšà»à»ˆàºªàº²àº¡àº²àº”ອ່ານ NFC ໄດ້</translation>
-<translation id="6910211073230771657">ລຶບà»àº¥à»‰àº§</translation>
<translation id="6912998170423641340">ບລັອàºàºšà»à»ˆà»ƒàº«à»‰à»€àº§àº±àºšà»„ຊອ່ານຂà»à»‰àº„ວາມ à»àº¥àº° ຮູບພາບຈາàºàº„ລິບບອດ</translation>
<translation id="6945221475159498467">ເລືອàº</translation>
<translation id="6965382102122355670">ຕົàºàº¥àº»àº‡</translation>
+<translation id="6981982820502123353">àºàº²àº™à»€àº‚ົ້າ​​ເຖິງ​ໄດ້</translation>
<translation id="6992289844737586249">ຖາມàºà»ˆàº­àº™àº—ີ່ຈະອະນຸàºàº²àº”ໃຫ້ເວັບໄຊໃຊ້ໄມໂຄຣໂຟນຂອງທ່ານ (à»àº™àº°àº™àº³)</translation>
<translation id="7000754031042624318">ປິດໃນàºàº²àº™àº•àº±à»‰àº‡àº„່າ Android</translation>
<translation id="7016516562562142042">ອະນຸàºàº²àº”ສຳລັບໂປຣà»àºàº£àº¡àºŠàº­àºàº«àº²àº›àº±àº”ຈຸບັນà»àº¥à»‰àº§</translation>
+<translation id="702463548815491781">à»àº™àº°àº™àº³à»€àº¡àº·à»ˆàº­ TalkBack ຫຼື àºàº²àº™à»€àº‚ົ້າເຖິງດ້ວàºàº›àº¸à»ˆàº¡à»€àº›àºµàº”ຢູ່</translation>
<translation id="7053983685419859001">ບລັອàº</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{ເລືອຠ1 ລາàºàºàº²àº™à»àº¥à»‰àº§}other{ເລືອຠ# ລາàºàºàº²àº™à»àº¥à»‰àº§}}</translation>
-<translation id="7070090581017165256">àºà»ˆàº½àº§àºàº±àºšà»€àº§àº±àºšà»„ຊນີ້</translation>
<translation id="7087918508125750058">ເລືອຠ<ph name="ITEM_COUNT" /> ລາàºàºàº²àº™à»àº¥à»‰àº§. ມີຕົວເລືອàºà»ƒàº«à»‰àº™àº³à»ƒàºŠà»‰àº¢àº¹à»ˆà»ƒàºà»‰àºªà»ˆàº§àº™à»€àº—ິງຂອງໜ້າຈà»</translation>
<translation id="7141896414559753902">ບລັອàºàºšà»à»ˆà»ƒàº«à»‰à»€àº§àº±àºšà»„ຊສະà»àº”ງປັອບອັບ à»àº¥àº° àºàº²àº™àº›à»ˆàº½àº™à»€àºªàº±à»‰àº™àº—າງ (à»àº™àº°àº™àº³)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> KB</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">ເວັບໄຊàºàº³àº¥àº±àº‡à»ƒàºŠà»‰à»„ມໂຄຣໂຟນຂອງທ່ານ</translation>
<translation id="7561196759112975576">ຢູ່ສະເà»àºµ</translation>
-<translation id="7572498721684305250">ບລັອàºàºšà»à»ˆà»ƒàº«à»‰à»€àº§àº±àºšà»„ຊສົ່ງ à»àº¥àº° ຮັບຂà»à»‰àº¡àº¹àº™à»ƒàº™à»€àº§àº¥àº²àº—ີ່ທ່ານà»àº•àº°àº­àº¸àº›àº°àºàº­àº™ NFC</translation>
<translation id="757524316907819857">ບລັອàºà»€àº§àº±àºšà»„ຊບà»à»ˆà»ƒàº«à»‰àº«àº¼àº´à»‰àº™à»€àº™àº·à»‰àº­àº«àº²àº—ີ່ມີàºàº²àº™àº›à»‰àº­àº‡àºàº±àº™à»„ວ້</translation>
+<translation id="7577900504646297215">ຈັດàºàº²àº™àº„ວາມສົນໃຈ</translation>
<translation id="7649070708921625228">ຊ່ວàºâ€‹à»€àº«àº¼àº·àº­</translation>
<translation id="7658239707568436148">àºàº»àºâ€‹à»€àº¥àºµàºâ€‹</translation>
<translation id="7781829728241885113">ມື້​ວານ​ນີ້</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">àºàº²àº™à»€àºŠàº·à»ˆàº­àº¡àº•à»à»ˆàº›àº­àº”ໄພດີ</translation>
<translation id="8249310407154411074">àºà»‰àº²àºà»„ປເທິງສຸດ</translation>
<translation id="8261506727792406068">ລຶບ</translation>
+<translation id="8284326494547611709">ຄà»àº²àºšàº±àº™àºàº²àºàºžàº²àºš</translation>
<translation id="8300705686683892304">ຈັດàºàº²àº™à»‚ດàºà»àº­àº±àºš</translation>
<translation id="8324158725704657629">ຢ່າຖາມອີàº</translation>
<translation id="8372893542064058268">ອະນຸàºàº²àº”àºàº²àº™àºŠàº´à»‰àº‡àº‚à»à»‰àº¡àº¹àº™à»ƒàº™àºžàº·à»‰àº™àº«àº¼àº±àº‡àºªàº³àº¥àº±àºšà»€àº§àº±àºšà»„ຊສະເພາະໃດໜຶ່ງ.</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">ຊຸມເຂົ້າ</translation>
<translation id="8921772741368021346"><ph name="POSITION" /> / <ph name="DURATION" /></translation>
<translation id="8926666909099850184">NFC ປິດຢູ່ສຳລັບອຸປະàºàº­àº™àº™àºµà»‰. àºàº°àº¥àº¸àº™àº²à»€àº›àºµàº”ມັນໃນ <ph name="BEGIN_LINK" />àºàº²àº™àº•àº±à»‰àº‡àº„່າ Android<ph name="END_LINK" />.</translation>
+<translation id="8928445016601307354">ບລັອàºà»€àº§àº±àºšà»„ຊບà»à»ˆà»ƒàº«à»‰à»€àºšàº´à»ˆàº‡à»€àº«àº±àº™ à»àº¥àº° ບà»à»ˆà»ƒàº«à»‰àº›à»ˆàº½àº™àº‚à»à»‰àº¡àº¹àº™àº¢àº¹à»ˆàº­àº¸àº›àº°àºàº­àº™ NFC</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">ບລັອàºàº„ຸàºàºàºµà»‰àºªàº³àº¥àº±àºšà»€àº§àº±àºšà»„ຊສະເພາະ.</translation>
<translation id="8959122750345127698">àºàº²àº™àº™àº³àº—າງà»àº¡à»ˆàº™àºšà»à»ˆàºªàº²àº¡àº²àº”ເຂົ້າເຖິງໄດ້: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_lt.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_lt.xtb
index a8e96f34f53..52bfa59f7c7 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_lt.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_lt.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">PridÄ—ta svetainÄ— <ph name="SITE_NAME" /></translation>
<translation id="1383876407941801731">Ieškoti</translation>
<translation id="1384959399684842514">Atsisiuntimas pristabdytas</translation>
+<translation id="1409426117486808224">Supaprastinta atidarytų skirtukų peržiūra</translation>
<translation id="1415402041810619267">URL sutrumpintas</translation>
<translation id="1446450296470737166">Leisti visiškai valdyti MIDI įr.</translation>
<translation id="1620510694547887537">Kamera</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">Leisti slapukus</translation>
<translation id="2228071138934252756">Norėdami leisti „<ph name="APP_NAME" />“ pasiekti jūsų kamerą, taip pat įjunkite ją <ph name="BEGIN_LINK" />„Android“ nustatymuose<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Tik vienÄ… kartÄ…</translation>
+<translation id="2253414712144136228">Pašalinti „<ph name="NAME_OF_LIST_ITEM" />“</translation>
<translation id="2289270750774289114">Paklausti, kai svetainÄ— nori atrasti netoliese esanÄius „Bluetooth“ įrenginius (rekomenduojama)</translation>
<translation id="2315043854645842844">Kliento pasirinkto sertifikato nepalaiko operacinÄ— sistema.</translation>
+<translation id="2321958826496381788">Vilkite šliaužiklį, kol bus patogu skaityti šį tekstą. Du kartus palietus pastraipą, tekstas turėtų būti mažiausiai tokio dydžio.</translation>
<translation id="2359808026110333948">Tęskite</translation>
<translation id="2379925928934107488">Kai galima, taikyti tamsiąją temą svetainėse, kai „Chrome“ naudoja tamsiąją temą</translation>
+<translation id="2387895666653383613">Teksto mastelio keitimas</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Leidžiama: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ir dar <ph name="NUM_MORE" />}one{Leidžiama: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ir dar <ph name="NUM_MORE" />}few{Leidžiama: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ir dar <ph name="NUM_MORE" />}many{Leidžiama: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ir dar <ph name="NUM_MORE" />}other{Leidžiama: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ir dar <ph name="NUM_MORE" />}}</translation>
<translation id="2434158240863470628">Atsisiųsta: <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">Rodyti informacijÄ…</translation>
<translation id="3123473560110926937">Užblokuota kai kuriose svetainėse</translation>
<translation id="3198916472715691905">Išsaugota duomenų: <ph name="STORAGE_AMOUNT" /></translation>
+<translation id="3203366800380907218">Iš žiniatinklio</translation>
<translation id="321187648315454507">Norėdami leisti „<ph name="APP_NAME" />“ siųsti pranešimus, taip pat įjunkite juos <ph name="BEGIN_LINK" />„Android“ nustatymuose<ph name="END_LINK" />.</translation>
<translation id="3227137524299004712">Mikrofonas</translation>
<translation id="3277252321222022663">Leidžiama svetainėms pasiekti jutiklius (rekomenduojama)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">Įrenginio naudojimas</translation>
<translation id="385051799172605136">Atgal</translation>
<translation id="3859306556332390985">Eiti pirmyn</translation>
+<translation id="3895926599014793903">Priverstinai įgalinti mastelio keitimą</translation>
<translation id="3955193568934677022">Leisti svetainėms paleisti apsaugotą turinį (rekomenduojama)</translation>
<translation id="3967822245660637423">Atsisiuntimas baigtas</translation>
<translation id="3987993985790029246">Kop. nuor.</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> iš ?</translation>
<translation id="4002066346123236978">Pavadinimas</translation>
<translation id="4008040567710660924">Leisti konkreÄios svetainÄ—s slapukus.</translation>
+<translation id="4040330681741629921">Gaukite pranešimą, kai galima rodyti supaprastinto rodinio svetainę</translation>
<translation id="4046123991198612571">Kitas takelis</translation>
+<translation id="4149994727733219643">Supaprastinta tinklalapių peržiūra</translation>
<translation id="4165986682804962316">SvetainÄ—s nustatymai</translation>
+<translation id="4194328954146351878">Klausti prieš leidžiant svetainėms peržiūrėti ir keisti informaciją NFC įrenginiuose (rekomenduojama)</translation>
<translation id="4200726100658658164">Atidaryti vietovÄ—s nustatymus</translation>
<translation id="4226663524361240545">Gavus pranešimą įrenginys gali vibruoti</translation>
<translation id="4259722352634471385">Naršymas užblokuotas: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">IÅ¡skleisti</translation>
<translation id="4336434711095810371">IÅ¡valyti visus duomenis</translation>
<translation id="4402755511846832236">Neleisti svetainėms žinoti, kada aktyviai naudojate šį įrenginį</translation>
+<translation id="4428065317363009941">Skelbimų suasmeninimas</translation>
<translation id="4434045419905280838">IÅ¡Å¡ok. langai ir peradresavimai</translation>
<translation id="445467742685312942">Leisti svetainėms leisti saugomą turinį</translation>
<translation id="4468959413250150279">KonkreÄios svetainÄ—s garso iÅ¡jungimas.</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">Parinktis pasiekiama netoli ekrano viršaus</translation>
<translation id="5197729504361054390">Pasirinkti kontaktai bus bendrinami su <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />.</translation>
<translation id="5216942107514965959">Paskutinį kartą lankytasi šiandien</translation>
+<translation id="5264323282659631142">Pašalinti „<ph name="CHIP_LABEL" />“</translation>
<translation id="528192093759286357">Vilkite žymeklį nuo viršaus ir palieskite mygtuką „Atgal“, kad išeitumėte iš viso ekrano režimo.</translation>
<translation id="5300589172476337783">Rodyti</translation>
<translation id="5301954838959518834">Gerai, supratau</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">Tai atlikus bus išvalyta <ph name="DATASIZE" /> svetainių saugomų duomenų ir slapukų.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(ir dar 1)}one{(ir dar #)}few{(ir dar #)}many{(ir dar #)}other{(ir dar #)}}</translation>
<translation id="5403592356182871684">Pavadinimai</translation>
+<translation id="5412236728747081950">Ši svetainė gauna informaciją apie jūsų pomėgius iš „Chrome“, kad galėtų rodyti jums aktualesnius skelbimus</translation>
<translation id="5438097262470833822">Bus iš naujo nustatyti svetainės <ph name="WEBSITE" /> leidimai</translation>
<translation id="5489227211564503167">Praėjęs laikas: <ph name="ELAPSED_TIME" /> iš <ph name="TOTAL_TIME" />.</translation>
<translation id="5494752089476963479">Blokuoti skelbimus svetainÄ—se, kuriose rodomi nepageidaujami arba klaidinantys skelbimai</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">Įkelti iš naujo</translation>
<translation id="5596627076506792578">Daugiau parinkÄių</translation>
<translation id="5649053991847567735">Automatiškai atsisiųsti</translation>
+<translation id="5668404140385795438">Nepaisyti svetainės mastelio keitimo vengimo užklausos</translation>
<translation id="5677928146339483299">Užblokuoti</translation>
<translation id="5689516760719285838">Vieta</translation>
<translation id="5690795753582697420">Fotoaparatas išjungtas „Android“ nustatymuose</translation>
-<translation id="5710871682236653961">Klausti prieš leidžiant svetainėms siųsti ir gauti informaciją palietus ALR įrenginius (rekomenduojama)</translation>
<translation id="5719847187258001597">Tai atlikus bus išvalyti visi <ph name="ORIGIN" /> arba jos programos jūsų pagrindiniame ekrane saugomi duomenys ir slapukai.</translation>
<translation id="5771720122942595109">Užblokuota: <ph name="PERMISSION_1" /></translation>
<translation id="5804241973901381774">Leidimai</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">Žaisti</translation>
<translation id="6818926723028410516">Pasirinkite elementus</translation>
<translation id="6864395892908308021">Šis įrenginys negali nuskaityti ALR</translation>
-<translation id="6910211073230771657">IÅ¡trintas</translation>
<translation id="6912998170423641340">Neleisti svetainėms skaityti teksto ir vaizdų iš iškarpinės</translation>
<translation id="6945221475159498467">Pasirinkti</translation>
<translation id="6965382102122355670">Gerai</translation>
+<translation id="6981982820502123353">Pritaikymas neįgaliesiems</translation>
<translation id="6992289844737586249">Pirmiausia klausti prieš leidžiant svetainėms naudoti mikrofoną (rekomenduojama)</translation>
<translation id="7000754031042624318">Išjungta „Android“ nustatymuose</translation>
<translation id="7016516562562142042">Leidžiama dabartiniam paieškos varikliui</translation>
+<translation id="702463548815491781">Rekomenduojama, kai įjungta „TalkBack“ arba prieiga jungikliu</translation>
<translation id="7053983685419859001">Blokuoti</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{Pasirinktas 1 elementas}one{Pasirinktas # elementas}few{Pasirinkti # elementai}many{Pasirinkta # elemento}other{Pasirinkta # elementų}}</translation>
-<translation id="7070090581017165256">Apie Å¡iÄ… svetainÄ™</translation>
<translation id="7087918508125750058">Pasirinkta: <ph name="ITEM_COUNT" />. Parinktys pasiekiamos netoli ekrano viršaus</translation>
<translation id="7141896414559753902">Blokuoti, kad svetainėse nebūtų rodomi iššokantieji langai ir peradresavimai (rekomenduojama)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> KB</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">„JavaScript“</translation>
<translation id="7554752735887601236">Svetainėje naudojamas jūsų mikrofonas</translation>
<translation id="7561196759112975576">Visada</translation>
-<translation id="7572498721684305250">Blokuoti svetainėse informacijos siuntimą ir gavimą palietus ALR įrenginius</translation>
<translation id="757524316907819857">Užblokuoti svetaines, kad neleistų apsaugoto turinio</translation>
+<translation id="7577900504646297215">Tvarkyti pomÄ—gius</translation>
<translation id="7649070708921625228">Pagalba</translation>
<translation id="7658239707568436148">Atšaukti</translation>
<translation id="7781829728241885113">Vakar</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">Ryšys saugus</translation>
<translation id="8249310407154411074">Perkelti į viršų</translation>
<translation id="8261506727792406068">IÅ¡trinti</translation>
+<translation id="8284326494547611709">Subtitrai</translation>
<translation id="8300705686683892304">Valdo programa</translation>
<translation id="8324158725704657629">Daugiau neklausti</translation>
<translation id="8372893542064058268">Leisti fono sinchronizavimÄ… konkreÄioje svetainÄ—je.</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">Artinti</translation>
<translation id="8921772741368021346"><ph name="POSITION" /> / <ph name="DURATION" /></translation>
<translation id="8926666909099850184">ALR išjungtas šiame įrenginyje. Įjunkite ALR <ph name="BEGIN_LINK" />„Android“ nustatymuose<ph name="END_LINK" />.</translation>
+<translation id="8928445016601307354">Blokuoti svetaines neleidžiant peržiūrėti ir keisti informacijos NFC įrenginiuose</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">Blokuoti konkreÄios svetainÄ—s slapukus.</translation>
<translation id="8959122750345127698">Naršymas nepasiekiamas: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_lv.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_lv.xtb
index 60c9666f01c..396c78d87f1 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_lv.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_lv.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">Tika pievienota vietne <ph name="SITE_NAME" /></translation>
<translation id="1383876407941801731">Meklēt</translation>
<translation id="1384959399684842514">LejupielÄde pÄrtraukta</translation>
+<translation id="1409426117486808224">VienkÄrÅ¡ots atvÄ“rtu ciļņu skatÄ«jums</translation>
<translation id="1415402041810619267">URL ir saÄ«sinÄts</translation>
<translation id="1446450296470737166">PilnÄ«ga MIDI ierÄ«Äu pÄrvaldÄ«ba</translation>
<translation id="1620510694547887537">Kamera</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">Atļaut sīkfailus</translation>
<translation id="2228071138934252756">Lai atļautu lietotnei <ph name="APP_NAME" /> piekļūt jūsu kamerai, ieslēdziet kameru arī <ph name="BEGIN_LINK" />Android iestatījumos<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Tikai vienreiz</translation>
+<translation id="2253414712144136228">Noņemt vienumu “<ph name="NAME_OF_LIST_ITEM" />â€</translation>
<translation id="2289270750774289114">VaicÄt, ja vietne vÄ“las redzÄ“t tuvumÄ esoÅ¡Äs Bluetooth ierÄ«ces (ieteicams)</translation>
<translation id="2315043854645842844">OperÄ“tÄjsistÄ“ma neatbalsta klienta puses sertifikÄta atlasi.</translation>
+<translation id="2321958826496381788">Velciet slÄ«dni, kamÄ“r varat Ä“rti lasÄ«t. PÄ“c dubultskÄriena rindkopai tekstam ir jÄbÅ«t vismaz Å¡ÄdÄ lielumÄ.</translation>
<translation id="2359808026110333948">TurpinÄt</translation>
<translation id="2379925928934107488">Lietojiet tumÅ¡o motÄ«vu vietnÄ“s, kad tumÅ¡ais motÄ«vs tiek izmantots pÄrlÅ«kÄ Chrome (ja iespÄ“jams)</translation>
+<translation id="2387895666653383613">Teksta mērogošana</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Atļautas: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> un vēl <ph name="NUM_MORE" />}zero{Atļautas: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> un vēl <ph name="NUM_MORE" />}one{Atļautas: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> un vēl <ph name="NUM_MORE" />}other{Atļautas: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> un vēl <ph name="NUM_MORE" />}}</translation>
<translation id="2434158240863470628">LejupielÄde pabeigta: <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">RÄdÄ«t informÄciju</translation>
<translation id="3123473560110926937">BloÄ·Ä“tas dažÄs vietnÄ“s</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> saglabÄtu datu</translation>
+<translation id="3203366800380907218">No tīmekļa</translation>
<translation id="321187648315454507">Lai atļautu lietotnei <ph name="APP_NAME" /> sūtīt jums paziņojumus, ieslēdziet paziņojumus arī <ph name="BEGIN_LINK" />Android iestatījumos<ph name="END_LINK" />.</translation>
<translation id="3227137524299004712">Mikrofons</translation>
<translation id="3277252321222022663">Atļaut vietnēm piekļūt sensoriem (ieteicams)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">Jūsu ierīces lietojums</translation>
<translation id="385051799172605136">Atpakaļ</translation>
<translation id="3859306556332390985">PÄrtÄ«t uz priekÅ¡u</translation>
+<translation id="3895926599014793903">TÄlummaiņas piespiedu iespÄ“joÅ¡ana</translation>
<translation id="3955193568934677022">Atļaut vietnÄ“m atskaņot aizsargÄtu saturu (ieteicams)</translation>
<translation id="3967822245660637423">LejupielÄde pabeigta</translation>
<translation id="3987993985790029246">Saites kopēšana</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> no ?</translation>
<translation id="4002066346123236978">Nosaukums</translation>
<translation id="4008040567710660924">Atļaut sīkfailus konkrētai vietnei.</translation>
+<translation id="4040330681741629921">Saņemiet paziņojumu, kad vietnei var tikt parÄdÄ«ts vienkÄrÅ¡otais skats.</translation>
<translation id="4046123991198612571">NÄkamais ieraksts</translation>
+<translation id="4149994727733219643">VienkÄrÅ¡ots tÄ«mekļa lapu skatÄ«jums</translation>
<translation id="4165986682804962316">Vietnes iestatījumi</translation>
+<translation id="4194328954146351878">VaicÄt, pirms ļaut vietnÄ“m NFC ierÄ«cÄ“s piekļūt informÄcijai un to mainÄ«t (ieteicams)</translation>
<translation id="4200726100658658164">AtvÄ“rt atraÅ¡anÄs vietu iestatÄ«jumus</translation>
<translation id="4226663524361240545">Saņemot paziņojumu, ierīce var vibrēt.</translation>
<translation id="4259722352634471385">NavigÄcija ir bloÄ·Ä“ta: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">Izvērst</translation>
<translation id="4336434711095810371">Notīrīt visus datus</translation>
<translation id="4402755511846832236">NerÄdÄ«t vietnÄ“m, kad jÅ«s aktÄ«vi lietojat Å¡o ierÄ«ci</translation>
+<translation id="4428065317363009941">ReklÄmu personalizÄ“Å¡ana</translation>
<translation id="4434045419905280838">Uznirstošie elem. un novirzīšana</translation>
<translation id="445467742685312942">Ä»aut vietnÄ“m atskaņot aizsargÄtu saturu</translation>
<translation id="4468959413250150279">Izslēgt skaņu noteiktai vietnei</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">Opcija pieejama ekrÄna augÅ¡daļÄ</translation>
<translation id="5197729504361054390">Atlasīto kontaktpersonu dati tiks kopīgoti ar vietni <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />.</translation>
<translation id="5216942107514965959">Pēdējoreiz apmeklēta šodien</translation>
+<translation id="5264323282659631142">Noņemt žetonu <ph name="CHIP_LABEL" /></translation>
<translation id="528192093759286357">Lai izietu no pilnekrÄna režīma, velciet no augÅ¡as un pieskarieties pogai Atpakaļ.</translation>
<translation id="5300589172476337783">RÄdÄ«t</translation>
<translation id="5301954838959518834">Labi, sapratu</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">Tiks dzÄ“sti dati un vietnÄ“s uzglabÄtie sÄ«kfaili (<ph name="DATASIZE" />).</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(un vēl 1)}zero{(un vēl #)}one{(un vēl #)}other{(un vēl #)}}</translation>
<translation id="5403592356182871684">Nosaukumi</translation>
+<translation id="5412236728747081950">Å Ä« vietne iegÅ«st informÄciju par jÅ«su interesÄ“m no pÄrlÅ«ka Chrome, lai rÄdÄ«tu jums atbilstoÅ¡Äkas reklÄmas.</translation>
<translation id="5438097262470833822">Veicot šo darbību, tiks atiestatītas vietnes <ph name="WEBSITE" /> atļaujas.</translation>
<translation id="5489227211564503167">PagÄjuÅ¡ais laiks: <ph name="ELAPSED_TIME" /> (no <ph name="TOTAL_TIME" />)</translation>
<translation id="5494752089476963479">BloÄ·Ä“t reklÄmas vietnÄ“s, kurÄs tiek rÄdÄ«tas traucÄ“joÅ¡as vai maldinoÅ¡as reklÄmas</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">PÄrlÄdÄ“t</translation>
<translation id="5596627076506792578">Citas opcijas</translation>
<translation id="5649053991847567735">AutomÄtiskÄs lejupielÄdes</translation>
+<translation id="5668404140385795438">IgnorÄ“t vietnes pieprasÄ«jumu, lai novÄ“rstu tuvinÄÅ¡anu</translation>
<translation id="5677928146339483299">BloÄ·Ä“ts</translation>
<translation id="5689516760719285838">AtraÅ¡anÄs vieta</translation>
<translation id="5690795753582697420">Android iestatījumos ir izslēgta kameras atļauja</translation>
-<translation id="5710871682236653961">VaicÄt, pirms atļaut vietnÄ“m sÅ«tÄ«t un saņemt informÄciju, kad ar ierÄ«ci pieskaraties citai NFC ierÄ«cei (ieteicams)</translation>
<translation id="5719847187258001597">Tiks dzÄ“sti visi dati un sÄ«kfaili, ko glabÄ vietne <ph name="ORIGIN" /> vai tÄs lietotne jÅ«su sÄkuma ekrÄnÄ.</translation>
<translation id="5771720122942595109">BloÄ·Ä“ta: <ph name="PERMISSION_1" /></translation>
<translation id="5804241973901381774">Atļaujas</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">Atskaņot</translation>
<translation id="6818926723028410516">Vienumu atlase</translation>
<translation id="6864395892908308021">Šī ierīce nevar lasīt NFC</translation>
-<translation id="6910211073230771657">Dzēsts</translation>
<translation id="6912998170423641340">Bloķēt vietņu piekļuvi teksta un attēlu lasīšanai no starpliktuves</translation>
<translation id="6945221475159498467">Atlasīt</translation>
<translation id="6965382102122355670">Labi</translation>
+<translation id="6981982820502123353">Pieejamība</translation>
<translation id="6992289844737586249">JautÄt, pirms atļaut vietnÄ“m izmantot jÅ«su mikrofonu (ieteicams)</translation>
<translation id="7000754031042624318">Izslēgta Android iestatījumos</translation>
<translation id="7016516562562142042">Atļauta paÅ¡reizÄ“jai meklÄ“tÄjprogrammai</translation>
+<translation id="702463548815491781">Ieteicams, ja ir ieslēgta lietotne TalkBack vai slēdžu piekļuves funkcija.</translation>
<translation id="7053983685419859001">BloÄ·Ä“t</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{Atlasīts 1 vienums}zero{Atlasīti # vienumi}one{Atlasīts # vienums}other{Atlasīti # vienumi}}</translation>
-<translation id="7070090581017165256">Par Å¡o vietni</translation>
<translation id="7087918508125750058">AtlasÄ«ti vienumi: <ph name="ITEM_COUNT" />. Opcijas ir pieejamas ekrÄna augÅ¡daļÄ.</translation>
<translation id="7141896414559753902">Neļaut vietnÄ“m novirzÄ«t un rÄdÄ«t uznirstoÅ¡os elementus (ieteicams)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> KB</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">KÄda vietne izmanto jÅ«su mikrofonu</translation>
<translation id="7561196759112975576">Vienmēr</translation>
-<translation id="7572498721684305250">BloÄ·Ä“t informÄcijas sÅ«tÄ«Å¡anu uz vietnÄ“m un saņemÅ¡anu no vietnÄ“m, kad ar ierÄ«ci pieskaraties citai NFC ierÄ«cei</translation>
<translation id="757524316907819857">Neļaut vietnÄ“m atskaņot aizsargÄtu saturu</translation>
+<translation id="7577900504646297215">PÄrvaldÄ«t intereses</translation>
<translation id="7649070708921625228">Palīdzība</translation>
<translation id="7658239707568436148">Atcelt</translation>
<translation id="7781829728241885113">Vakar</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">Savienojums ir drošs</translation>
<translation id="8249310407154411074">PÄrvietot uz augÅ¡daļu</translation>
<translation id="8261506727792406068">Dzēst</translation>
+<translation id="8284326494547611709">Subtitri</translation>
<translation id="8300705686683892304">PÄrvalda lietotne</translation>
<translation id="8324158725704657629">NejautÄt atkÄrtoti</translation>
<translation id="8372893542064058268">Atļaut sinhronizÄciju fonÄ konkrÄ“tai vietnei</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">TuvinÄt</translation>
<translation id="8921772741368021346"><ph name="POSITION" /> / <ph name="DURATION" /></translation>
<translation id="8926666909099850184">Å ajÄ ierÄ«cÄ“ tehnoloÄ£ija NFC ir izslÄ“gta. IeslÄ“dziet to <ph name="BEGIN_LINK" />Android iestatÄ«jumos<ph name="END_LINK" />.</translation>
+<translation id="8928445016601307354">Liegt vietnÄ“m NFC ierÄ«cÄ“s piekļūt informÄcijai un to mainÄ«t</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">Bloķēt sīkfailus konkrētai vietnei.</translation>
<translation id="8959122750345127698">NavigÄcija nav sasniedzama: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_mk.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_mk.xtb
index bd524a32be1..363bef3a14a 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_mk.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_mk.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">Локацијата <ph name="SITE_NAME" /> е додадена</translation>
<translation id="1383876407941801731">Барај</translation>
<translation id="1384959399684842514">Преземањето е паузирано</translation>
+<translation id="1409426117486808224">ПоедноÑтавен приказ за отворени картички</translation>
<translation id="1415402041810619267">URL-адреÑата е Ñкратена</translation>
<translation id="1446450296470737166">Дозволи контрола над MIDI-уреди</translation>
<translation id="1620510694547887537">Камера</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">Дозволи колачиња</translation>
<translation id="2228071138934252756">За да овозможите <ph name="APP_NAME" /> да приÑтапува до вашата камера, вклучете ја дозволата за камерата и во <ph name="BEGIN_LINK" />ПоÑтавки за Android<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Само еднаш</translation>
+<translation id="2253414712144136228">ОтÑтранете <ph name="NAME_OF_LIST_ITEM" /></translation>
<translation id="2289270750774289114">Прашај кога некој Ñајт Ñака да открива уреди Ñо Bluetooth во близина (Ñе препорачува)</translation>
<translation id="2315043854645842844">Оперативниот ÑиÑтем не поддржува избор на Ñертификат од Ñтрана на клиентот.</translation>
+<translation id="2321958826496381788">Влечете го лизгачот ÑÑ Ð´Ð¾Ð´ÐµÐºÐ° не го читате ова удобно. ТекÑтот треба да изгледа барем олку голем по двојно допирање на паÑуÑот.</translation>
<translation id="2359808026110333948">Продолжи</translation>
<translation id="2379925928934107488">Ðко е можно, примени темна тема на Ñајтовите кога Chrome кориÑти темна тема</translation>
+<translation id="2387895666653383613">Скалирање текÑÑ‚</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> и уште <ph name="NUM_MORE" /> Ñе одобрени}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> и уште <ph name="NUM_MORE" /> Ñе одобрени}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> и уште <ph name="NUM_MORE" /> Ñе одобрени}}</translation>
<translation id="2434158240863470628">Преземањето е завршено <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">Прикажи ги информациите</translation>
<translation id="3123473560110926937">Блокирано на некои Ñајтови</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> Ñкладирани податоци</translation>
+<translation id="3203366800380907218">Од интернет</translation>
<translation id="321187648315454507">За да овозможите <ph name="APP_NAME" /> да ви иÑпраќа извеÑтувања, вклучете ја дозволата за извеÑтувања и во <ph name="BEGIN_LINK" />ПоÑтавки за Android<ph name="END_LINK" />.</translation>
<translation id="3227137524299004712">Микрофон</translation>
<translation id="3277252321222022663">Дозволете Ñајтовите да приÑтапуваат до Ñензорите (препорачано)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">КориÑтење на уредот</translation>
<translation id="385051799172605136">Ðазад</translation>
<translation id="3859306556332390985">Барај понапред</translation>
+<translation id="3895926599014793903">ПриÑилно овозможи зумирање</translation>
<translation id="3955193568934677022">Дозволете Ñајтовите да пуштаат заштитени Ñодржини (Ñе препорачува)</translation>
<translation id="3967822245660637423">Преземањето е завршено</translation>
<translation id="3987993985790029246">Копирај линк</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" />/?</translation>
<translation id="4002066346123236978">ÐаÑлов</translation>
<translation id="4008040567710660924">Дозволете колачиња за конкретен Ñајт.</translation>
+<translation id="4040330681741629921">Добивајте извеÑтувања кога Ñајт може да Ñе прикажува во поедноÑтавен преглед</translation>
<translation id="4046123991198612571">Следна пеÑна</translation>
+<translation id="4149994727733219643">ПоедноÑтавен приказ за веб-Ñтраници</translation>
<translation id="4165986682804962316">ПоÑтавки на локација</translation>
+<translation id="4194328954146351878">Прашај пред да дозволиш Ñајтовите да гледаат и менуваат податоци на NFC-уреди (Ñе препорачува)</translation>
<translation id="4200726100658658164">Отворете ги поÑтавките за локација</translation>
<translation id="4226663524361240545">ИзвеÑтувањата може да предизвикаат вибрации на уредот</translation>
<translation id="4259722352634471385">Ðавигацијата е блокирана: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">Прошири</translation>
<translation id="4336434711095810371">Избриши ги Ñите податоци</translation>
<translation id="4402755511846832236">Ðе дозволувај Ñајтовите да знаат кога активно го кориÑтам уредов</translation>
+<translation id="4428065317363009941">ПерÑонализирање на рекламите</translation>
<translation id="4434045419905280838">Скокачки прозорци/пренаÑочувања</translation>
<translation id="445467742685312942">Дозволи Ñајтовите да пуштаат заштитени Ñодржини</translation>
<translation id="4468959413250150279">ИÑклучете го звукот за одреден Ñајт.</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">Опцијата е доÑтапна речиÑи најгоре на екранот</translation>
<translation id="5197729504361054390">Контактите што ќе ги изберете ќе Ñе Ñподелат Ñо <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />.</translation>
<translation id="5216942107514965959">ПоÑледно поÑетено денеÑ</translation>
+<translation id="5264323282659631142">ОтÑтранете го „<ph name="CHIP_LABEL" />“</translation>
<translation id="528192093759286357">Повлечете од врвот и допрете го копчето Ðазад за да излезете од цел екран.</translation>
<translation id="5300589172476337783">Прикажи</translation>
<translation id="5301954838959518834">Добро, Ñфатив</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">Ова ќе избрише <ph name="DATASIZE" /> податоци и колачиња Ñкладирани од Ñајтовите.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(и уште 1)}one{(и уште #)}other{(и уште #)}}</translation>
<translation id="5403592356182871684">Имиња</translation>
+<translation id="5412236728747081950">Сајтов ги добива вашите интереÑи од Chrome за да ви прикажува порелевантни реклами</translation>
<translation id="5438097262470833822">Изборов ќе ги реÑетира дозволите за <ph name="WEBSITE" /></translation>
<translation id="5489227211564503167">Изминато време: <ph name="ELAPSED_TIME" /> од <ph name="TOTAL_TIME" />.</translation>
<translation id="5494752089476963479">Блокирај ги рекламите на Ñајтови што прикажуваат нападни или лажни реклами</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">Повторно вчитај</translation>
<translation id="5596627076506792578">Повеќе опции</translation>
<translation id="5649053991847567735">ÐвтоматÑки преземања</translation>
+<translation id="5668404140385795438">Отфрли го барањето на веб-локацијата да Ñпречи зумирање</translation>
<translation id="5677928146339483299">Блокирано</translation>
<translation id="5689516760719285838">Локација</translation>
<translation id="5690795753582697420">Камерата е иÑклучена во поÑтавките за Android</translation>
-<translation id="5710871682236653961">Прашај пред да дозволиш Ñајтовите да иÑпраќаат и примаат информации при допир на NFC-уреди (Ñе препорачува)</translation>
<translation id="5719847187258001597">Ова ќе ги избрише Ñите податоци и колачиња Ñкладирани од Ñајтот <ph name="ORIGIN" /> или од неговата апликација на почетниот екран.</translation>
<translation id="5771720122942595109"><ph name="PERMISSION_1" /> е блокирана</translation>
<translation id="5804241973901381774">Дозволи</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">Репродуцирај</translation>
<translation id="6818926723028410516">Изберете Ñтавки</translation>
<translation id="6864395892908308021">Уредов не може да чита NFC</translation>
-<translation id="6910211073230771657">Избришано</translation>
<translation id="6912998170423641340">Блокирај го читањето текÑÑ‚ и Ñлики од привремената меморија за Ñајтовите</translation>
<translation id="6945221475159498467">Избери</translation>
<translation id="6965382102122355670">Во ред</translation>
+<translation id="6981982820502123353">ПриÑтапноÑÑ‚</translation>
<translation id="6992289844737586249">Прво прашај пред да дозволиш Ñајтовите да го кориÑтат микрофонот (Ñе препорачува)</translation>
<translation id="7000754031042624318">ИÑклучена во поÑтавките за Android</translation>
<translation id="7016516562562142042">Дозволено за тековниот пребарувач</translation>
+<translation id="702463548815491781">Препорачано при вклучен TalkBack или „ПриÑтап Ñо прекинувачи“</translation>
<translation id="7053983685419859001">Блокирај</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{Избрана е 1}one{Избрана е #}other{Избрани Ñе #}}</translation>
-<translation id="7070090581017165256">За Ñајтов</translation>
<translation id="7087918508125750058">Избрани Ñтавки: <ph name="ITEM_COUNT" />. ДоÑтапни Ñе опции во горниот дел од екранот</translation>
<translation id="7141896414559753902">Блокирај го прикажувањето Ñкокачки прозорци и пренаÑочувања на Ñајтовите (Ñе препорачува)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> KB</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">Сајтот го кориÑти микрофонот</translation>
<translation id="7561196759112975576">Секогаш</translation>
-<translation id="7572498721684305250">Блокирај ги иÑпраќањето и примањето информации при допир на NFC-уреди</translation>
<translation id="757524316907819857">Блокирај го пуштањето заштитени Ñодржини од Ñтрана на Ñајтовите</translation>
+<translation id="7577900504646297215">Управувајте Ñо она што ве интереÑира</translation>
<translation id="7649070708921625228">Помош</translation>
<translation id="7658239707568436148">Откажи</translation>
<translation id="7781829728241885113">Вчера</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">Ð’Ñ€Ñката е безбедна</translation>
<translation id="8249310407154411074">ПремеÑти најгоре</translation>
<translation id="8261506727792406068">Избриши</translation>
+<translation id="8284326494547611709">Титлови</translation>
<translation id="8300705686683892304">Управувани од апликација</translation>
<translation id="8324158725704657629">Ðе прашувај повторно</translation>
<translation id="8372893542064058268">Дозволи Синхронизација во заднина за одреден Ñајт.</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">Зумирај</translation>
<translation id="8921772741368021346"><ph name="POSITION" />/<ph name="DURATION" /></translation>
<translation id="8926666909099850184">NFC е иÑклучена за уредов. Вклучете ја во <ph name="BEGIN_LINK" />„ПоÑтавки за Android“<ph name="END_LINK" />.</translation>
+<translation id="8928445016601307354">Блокирај Ñајтовите да не ги гледаат и менуваат податоците на NFC-уреди</translation>
<translation id="8941729603749328384">www.primer.com</translation>
<translation id="8958424370300090006">Блокирајте колачиња за одреден Ñајт.</translation>
<translation id="8959122750345127698">Ðавигацијата е недоÑтапна: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ml.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ml.xtb
index e2ac7884ed4..72fc9994c4c 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ml.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ml.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676"><ph name="SITE_NAME" /> à´Žà´¨àµà´¨ സൈറàµà´±àµ ചേർതàµà´¤àµ‚</translation>
<translation id="1383876407941801731">Search</translation>
<translation id="1384959399684842514">ഡൗൺലോഡൠതാൽകàµà´•à´¾à´²à´¿à´•à´®à´¾à´¯à´¿ നിർതàµà´¤à´¿</translation>
+<translation id="1409426117486808224">à´¤àµà´±à´¨àµà´¨ ടാബàµà´•àµ¾à´•àµà´•à´¾à´¯à´¿ ലളിതവൽകàµà´•à´°à´¿à´šàµà´š കാഴàµà´š</translation>
<translation id="1415402041810619267">URL à´šàµà´°àµà´•àµà´•à´¿</translation>
<translation id="1446450296470737166">MIDI ഉപകരണങàµà´™à´³àµà´Ÿàµ† പൂർണàµà´£ നിയനàµà´¤àµà´°à´£à´‚ à´…à´¨àµà´µà´¦à´¿à´•àµà´•àµà´•</translation>
<translation id="1620510694547887537">à´•àµà´¯à´¾à´®à´±</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">à´•àµà´•àµà´•à´¿à´•àµ¾ à´…à´¨àµà´µà´¦à´¿à´•àµà´•àµà´•</translation>
<translation id="2228071138934252756"><ph name="APP_NAME" /> ആപàµà´ªà´¿à´¨àµ† നിങàµà´™à´³àµà´Ÿàµ† à´•àµà´¯à´¾à´®à´± ആകàµâ€Œà´¸à´¸àµ ചെയàµà´¯à´¾àµ» à´…à´¨àµà´µà´¦à´¿à´•àµà´•àµà´¨àµà´¨à´¤à´¿à´¨àµ, <ph name="BEGIN_LINK" />Android à´•àµà´°à´®àµ€à´•à´°à´£à´¤àµà´¤à´¿à´²àµà´‚<ph name="END_LINK" /> à´•àµà´¯à´¾à´®à´± ഓണാകàµà´•àµà´•.</translation>
<translation id="2241634353105152135">à´’à´°à´¿à´•àµà´•àµ½ മാതàµà´°à´‚</translation>
+<translation id="2253414712144136228"><ph name="NAME_OF_LIST_ITEM" /> നീകàµà´•à´‚ ചെയàµà´¯àµà´•</translation>
<translation id="2289270750774289114">സമീപതàµà´¤àµà´³àµà´³ Bluetooth ഉപകരണങàµà´™àµ¾ à´•à´£àµà´Ÿàµ†à´¤àµà´¤à´¾àµ» ഒരൠസൈറàµà´±àµ താൽപàµà´ªà´°àµà´¯à´ªàµà´ªàµ†à´Ÿàµà´®àµà´ªàµ‹àµ¾ ചോദികàµà´•àµà´• (à´¶àµà´ªà´¾àµ¼à´¶à´šàµ†à´¯àµâ€Œà´¤à´¤àµ)</translation>
<translation id="2315043854645842844">à´“à´ªàµà´ªà´±àµ‡à´±àµà´±à´¿à´‚ഗൠസിസàµà´±àµà´±à´‚ à´•àµà´²à´¯à´¨àµà´±à´¿à´¨àµà´±àµ† സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ തിരഞàµà´žàµ†à´Ÿàµà´•àµà´•à´²à´¿à´¨àµ† പിനàµà´¤àµà´£à´¯àµâ€Œà´•àµà´•àµà´¨àµà´¨à´¿à´²àµà´².</translation>
+<translation id="2321958826496381788">നിങàµà´™àµ¾à´•àµà´•àµ ഇതൠസൗകരàµà´¯à´ªàµà´°à´¦à´®à´¾à´¯à´¿ വായികàµà´•à´¾àµ» à´•à´´à´¿à´¯àµà´¨àµà´¨à´¤àµà´µà´°àµ† à´¸àµà´²àµˆà´¡àµ¼ വലികàµà´•àµà´•. ഒരൠഖണàµà´¡à´¿à´•à´¯à´¿àµ½ ഇരടàµà´Ÿ-ടാപàµà´ªàµ ചെയàµâ€Œà´¤à´¤à´¿à´¨àµà´¶àµ‡à´·à´‚ ടെകàµâ€Œà´¸àµà´±àµà´±à´¿à´¨àµ à´ˆ വലàµà´ªàµà´ªà´®àµ†à´™àµà´•à´¿à´²àµà´‚ ഉണàµà´Ÿà´¾à´¯à´¿à´°à´¿à´•àµà´•à´£à´‚.</translation>
<translation id="2359808026110333948">à´¤àµà´Ÿà´°àµà´•</translation>
<translation id="2379925928934107488">സാധàµà´¯à´®à´¾à´•àµà´®àµà´ªàµ‹à´´àµ†à´²àµà´²à´¾à´‚, Chrome ഡാർകàµà´•àµ തീം ഉപയോഗികàµà´•àµà´®àµà´ªàµ‹àµ¾ സൈറàµà´±àµà´•àµ¾à´•àµà´•àµà´‚ ഡാർകàµà´•àµ തീം ബാധകമാകàµà´•àµà´•</translation>
+<translation id="2387895666653383613">ടെകàµâ€Œà´¸àµà´±àµà´±àµ à´¸àµâ€Œà´•àµ†à´¯à´¿à´²à´¿à´‚à´—àµ</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> à´Žà´¨àµà´¨à´¿à´µà´¯àµà´‚ മറàµà´±àµ <ph name="NUM_MORE" /> à´Žà´£àµà´£à´µàµà´‚ à´…à´¨àµà´µà´¦à´¿à´šàµà´šàµ}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> à´Žà´¨àµà´¨à´¿à´µà´¯àµà´‚ മറàµà´±àµ <ph name="NUM_MORE" /> à´Žà´£àµà´£à´µàµà´‚ à´…à´¨àµà´µà´¦à´¿à´šàµà´šàµ}}</translation>
<translation id="2434158240863470628">ഡൗൺലോഡൠപൂർതàµà´¤à´¿à´¯à´¾à´¯à´¿ <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">വിവരങàµà´™àµ¾ കാണികàµà´•àµà´•</translation>
<translation id="3123473560110926937">à´šà´¿à´² സൈറàµà´±àµà´•à´³à´¿àµ½ à´¬àµà´²àµ‹à´•àµà´•àµ ചെയàµâ€Œà´¤à´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨àµ</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> സംഭരിചàµà´š വിവരം</translation>
+<translation id="3203366800380907218">വെബിൽ നിനàµà´¨àµ</translation>
<translation id="321187648315454507">അറിയിപàµà´ªàµà´•àµ¾ അയയàµà´•àµà´•à´¾àµ» <ph name="APP_NAME" /> ആപàµà´ªà´¿à´¨àµ† à´…à´¨àµà´µà´¦à´¿à´•àµà´•àµà´¨àµà´¨à´¤à´¿à´¨àµ, <ph name="BEGIN_LINK" />Android à´•àµà´°à´®àµ€à´•à´°à´£à´¤àµà´¤à´¿à´²àµà´‚<ph name="END_LINK" /> അറിയിപàµà´ªàµà´•àµ¾ ഓണാകàµà´•àµà´•.</translation>
<translation id="3227137524299004712">മൈകàµà´°àµ‹à´«àµ‹àµº</translation>
<translation id="3277252321222022663">സെൻസറàµà´•àµ¾ ആകàµâ€Œà´¸à´¸àµ ചെയàµà´¯à´¾àµ» സൈറàµà´±àµà´•à´³àµ† à´…à´¨àµà´µà´¦à´¿à´•àµà´•àµà´• (à´¶àµà´ªà´¾àµ¼à´¶ ചെയàµà´¯àµà´¨àµà´¨à´¤àµ)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">നിങàµà´™à´³àµà´Ÿàµ† ഉപകരണതàµà´¤à´¿à´¨àµà´±àµ† ഉപയോഗം</translation>
<translation id="385051799172605136">പിനàµà´¨àµ‹à´Ÿàµà´Ÿàµ</translation>
<translation id="3859306556332390985">à´®àµà´¨àµà´¨àµ‹à´Ÿàµà´Ÿàµ നീകàµà´•àµà´•</translation>
+<translation id="3895926599014793903">നിർബനàµà´§à´¿à´¤ സൂം à´ªàµà´°à´µàµ¼à´¤àµà´¤à´¨à´•àµà´·à´®à´®à´¾à´•àµà´•àµà´•</translation>
<translation id="3955193568934677022">പരിരകàµà´·à´¿à´¤ ഉളàµà´³à´Ÿà´•àµà´•à´‚ à´ªàµà´²àµ‡ ചെയàµà´¯à´¾àµ» സൈറàµà´±àµà´•à´³àµ† à´…à´¨àµà´µà´¦à´¿à´•àµà´•àµà´• (à´¶àµà´ªà´¾àµ¼à´¶ ചെയàµâ€Œà´¤à´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨àµ)</translation>
<translation id="3967822245660637423">ഡൗൺലോഡൠപൂർതàµà´¤à´¿à´¯à´¾à´¯à´¿</translation>
<translation id="3987993985790029246">ലിങàµà´•àµ പകർതàµà´¤àµà´•</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> / ?</translation>
<translation id="4002066346123236978">ശീർഷകം</translation>
<translation id="4008040567710660924">ഒരൠപàµà´°à´¤àµà´¯àµ‡à´• സൈറàµà´±à´¿à´¨à´¾à´¯à´¿ à´•àµà´•àµà´•à´¿à´•àµ¾ à´…à´¨àµà´µà´¦à´¿à´•àµà´•àµà´•.</translation>
+<translation id="4040330681741629921">ലളിതമാകàµà´•à´¿à´¯ കാഴàµà´šà´¯à´¿àµ½ ഒരൠസൈറàµà´±àµ കാണികàµà´•à´¾àµ» à´•à´´à´¿à´¯àµà´®àµà´ªàµ‹àµ¾ അറിയിപàµà´ªàµ നേടàµà´•</translation>
<translation id="4046123991198612571">à´…à´Ÿàµà´¤àµà´¤ à´Ÿàµà´°à´¾à´•àµà´•àµ</translation>
+<translation id="4149994727733219643">വെബൠപേജàµà´•àµ¾à´•àµà´•à´¾à´¯à´¿ ലളിതവൽകàµà´•à´°à´¿à´šàµà´š കാഴàµà´š</translation>
<translation id="4165986682804962316">സൈറàµà´±àµ à´•àµà´°à´®àµ€à´•à´°à´£à´™àµà´™àµ¾</translation>
+<translation id="4194328954146351878">NFC ഉപകരണങàµà´™à´³à´¿à´²àµ† വിവരങàµà´™àµ¾ കാണാനàµà´‚ അവയിൽ മാറàµà´±à´‚ വരàµà´¤àµà´¤à´¾à´¨àµà´‚ സൈറàµà´±àµà´•à´³àµ† à´…à´¨àµà´µà´¦à´¿à´•àµà´•àµà´¨àµà´¨à´¤à´¿à´¨àµ à´®àµà´®àµà´ªàµ ചോദികàµà´•àµà´• (നിർദàµà´¦àµ‡à´¶à´¿à´•àµà´•àµà´¨àµà´¨à´¤àµ)</translation>
<translation id="4200726100658658164">ലൊകàµà´•àµ‡à´·àµ» à´•àµà´°à´®àµ€à´•à´°à´£à´‚ à´¤àµà´±à´•àµà´•àµà´•</translation>
<translation id="4226663524361240545">അറിയിപàµà´ªàµà´•àµ¾ ലഭികàµà´•àµà´®àµà´ªàµ‹àµ¾ ഉപകരണം വൈബàµà´°àµ‡à´±àµà´±àµ ചെയàµâ€Œà´¤àµ‡à´•àµà´•à´¾à´‚</translation>
<translation id="4259722352634471385">നാവിഗേഷൻ തടഞàµà´žà´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨àµ: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">വികസിപàµà´ªà´¿à´•àµà´•àµà´•</translation>
<translation id="4336434711095810371">à´Žà´²àµà´²à´¾ ഡാറàµà´±à´¯àµà´‚ മായàµà´•àµà´•àµà´•</translation>
<translation id="4402755511846832236">നിങàµà´™àµ¾ à´ˆ ഉപകരണം സജീവമായി ഉപയോഗികàµà´•àµà´¨àµà´¨à´¤àµ അറിയàµà´¨àµà´¨à´¤à´¿àµ½ നിനàµà´¨àµ സൈറàµà´±àµà´•à´³àµ† à´¬àµà´²àµ‹à´•àµà´•àµ ചെയàµà´¯àµà´¨àµà´¨àµ</translation>
+<translation id="4428065317363009941">പരസàµà´¯à´‚ à´µàµà´¯à´•àµà´¤à´¿à´ªà´°à´®à´¾à´•àµà´•àµ½</translation>
<translation id="4434045419905280838">പോപàµ-à´…à´ªàµà´ªàµà´•à´³àµà´‚ റീഡയറകàµâ€Œà´±àµà´±àµà´•à´³àµà´‚</translation>
<translation id="445467742685312942">പരിരകàµà´·à´¿à´¤ ഉളàµà´³à´Ÿà´•àµà´•à´‚ à´ªàµà´²àµ‡ ചെയàµà´¯à´¾àµ» സൈറàµà´±àµà´•à´³àµ† à´…à´¨àµà´µà´¦à´¿à´•àµà´•àµà´•</translation>
<translation id="4468959413250150279">ഒരൠപàµà´°à´¤àµà´¯àµ‡à´• സൈറàµà´±à´¿à´¨à´¾à´¯à´¿ ശബàµâ€Œà´¦à´‚ à´®àµà´¯àµ‚à´Ÿàµà´Ÿàµ ചെയàµà´¯àµà´•.</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">à´¸àµâ€Œà´•àµà´°àµ€à´¨à´¿à´¨àµà´±àµ† à´®àµà´•à´³à´¿àµ½ à´“à´ªàµâ€Œà´·àµ» ലഭàµà´¯à´®à´¾à´£àµ</translation>
<translation id="5197729504361054390">നിങàµà´™àµ¾ തിരഞàµà´žàµ†à´Ÿàµà´•àµà´•àµà´¨àµà´¨ കോൺടാകàµâ€Œà´±àµà´±àµà´•àµ¾ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> à´Žà´¨àµà´¨ സൈറàµà´±àµà´®à´¾à´¯à´¿ പങàµà´•à´¿à´Ÿàµà´‚.</translation>
<translation id="5216942107514965959">അവസാനം സനàµà´¦àµ¼à´¶à´¿à´šàµà´šà´¤àµ ഇനàµà´¨à´¾à´£àµ</translation>
+<translation id="5264323282659631142">'<ph name="CHIP_LABEL" />' നീകàµà´•à´‚ചെയàµà´¯àµà´•</translation>
<translation id="528192093759286357">പൂർണàµà´£ à´¸àµâ€Œà´•àµà´°àµ€à´¨à´¿àµ½ നിനàµà´¨àµ à´ªàµà´±à´¤àµà´¤àµà´•à´Ÿà´•àµà´•à´¾àµ», à´®àµà´•à´³à´¿àµ½ നിനàµà´¨àµ വലിചàµà´šà´¿à´Ÿàµà´Ÿàµ ബാകàµà´•àµ ബടàµà´Ÿà´£à´¿àµ½ à´¸àµâ€Œà´ªàµ¼à´¶à´¿à´•àµà´•àµà´•.</translation>
<translation id="5300589172476337783">കാണികàµà´•àµà´•</translation>
<translation id="5301954838959518834">മനസàµà´¸à´¿à´²à´¾à´¯à´¿</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">സൈറàµà´±àµà´•àµ¾ സംഭരിചàµà´š <ph name="DATASIZE" /> ഡാറàµà´±à´¯àµà´‚ à´•àµà´•àµà´•à´¿à´•à´³àµà´‚ ഇതൠമായàµâ€Œà´•àµà´•àµà´‚.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(+ ഒരെണàµà´£à´‚ കൂടി)}other{(+ # à´Žà´£àµà´£à´‚ കൂടി)}}</translation>
<translation id="5403592356182871684">പേരàµà´•àµ¾</translation>
+<translation id="5412236728747081950">കൂടàµà´¤àµ½ à´ªàµà´°à´¸à´•àµà´¤à´®à´¾à´¯ പരസàµà´¯à´™àµà´™àµ¾ കാണികàµà´•à´¾àµ» à´ˆ സൈറàµà´±à´¿à´¨àµ Chrome-ൽ നിനàµà´¨àµ നിങàµà´™à´³àµà´Ÿàµ† താൽപàµà´ªà´°àµà´¯à´™àµà´™àµ¾ ലഭികàµà´•àµà´¨àµà´¨àµ</translation>
<translation id="5438097262470833822">ഇതൠതിരഞàµà´žàµ†à´Ÿàµà´•àµà´•àµà´¨àµà´¨à´¤à´¿à´²àµ‚ടെ <ph name="WEBSITE" /> à´Žà´¨àµà´¨à´¤à´¿à´¨àµà´³àµà´³ à´…à´¨àµà´®à´¤à´¿à´•àµ¾ റീസെറàµà´±àµ ചെയàµà´¯àµà´‚</translation>
<translation id="5489227211564503167">ആകെ <ph name="TOTAL_TIME" />-ൽ <ph name="ELAPSED_TIME" /> à´•à´´à´¿à´žàµà´žàµ.</translation>
<translation id="5494752089476963479">അനാവശàµà´¯à´®àµ‹ തെറàµà´±à´¿à´¦àµà´§à´°à´¿à´ªàµà´ªà´¿à´•àµà´•àµà´¨àµà´¨à´¤àµ‹ ആയ പരസàµà´¯à´™àµà´™à´³àµâ€ കാണികàµà´•àµà´¨àµà´¨ സൈറàµà´±àµà´•à´³à´¿à´²àµ† പരസàµà´¯à´™àµà´™àµ¾ à´¬àµà´²àµ‹à´•àµà´•àµ ചെയàµà´¯àµà´•</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">വീണàµà´Ÿàµà´‚ ലോഡൠചെയàµà´¯àµà´•</translation>
<translation id="5596627076506792578">കൂടàµà´¤àµ½â€ à´“à´ªàµâ€Œà´·à´¨àµà´•àµ¾</translation>
<translation id="5649053991847567735">യാനàµà´¤àµà´°à´¿à´• ഡൗൺലോഡàµà´•àµ¾</translation>
+<translation id="5668404140385795438">സൂം ഇൻ ചെയàµà´¯àµà´¨àµà´¨à´¤àµ തടയàµà´¨àµà´¨à´¤à´¿à´¨àµà´³àµà´³ ഒരൠവെബàµà´¸àµˆà´±àµà´±à´¿à´¨àµà´±àµ† à´…à´­àµà´¯àµ¼à´¤àµà´¥à´¨ അസാധàµà´µà´¾à´•àµà´•àµà´•</translation>
<translation id="5677928146339483299">തടഞàµà´žàµ</translation>
<translation id="5689516760719285838">ലൊകàµà´•àµ‡à´·àµ»</translation>
<translation id="5690795753582697420">Android à´•àµà´°à´®àµ€à´•à´°à´£à´¤àµà´¤à´¿àµ½ à´•àµà´¯à´¾à´®à´± ഓഫാകàµà´•à´¿à´¯à´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨àµ</translation>
-<translation id="5710871682236653961">നിങàµà´™àµ¾ NFC ഉപകരണങàµà´™à´³à´¿àµ½ ടാപàµà´ªàµ ചെയàµà´¯àµà´®àµà´ªàµ‹àµ¾ വിവരങàµà´™àµ¾ അയയàµâ€Œà´•àµà´•à´¾à´¨àµà´‚ à´¸àµà´µàµ€à´•à´°à´¿à´•àµà´•à´¾à´¨àµà´‚ സൈറàµà´±àµà´•à´³àµ† à´…à´¨àµà´µà´¦à´¿à´•àµà´•àµà´¨àµà´¨à´¤à´¿à´¨àµ à´®àµà´®àµà´ªàµ ചോദികàµà´•àµà´• (à´¶àµà´ªà´¾àµ¼à´¶ ചെയàµà´¯àµà´¨àµà´¨à´¤àµ)</translation>
<translation id="5719847187258001597">ഇതൠ<ph name="ORIGIN" /> à´…à´²àµà´²àµ†à´™àµà´•à´¿àµ½ അതിനàµà´±àµ† ആപàµà´ªàµ നിങàµà´™à´³àµà´Ÿàµ† ഹോം à´¸àµà´•àµà´°àµ€à´¨à´¿àµ½ സംഭരിചàµà´š à´Žà´²àµà´²à´¾ ഡാറàµà´±à´¯àµà´‚ à´•àµà´•àµà´•à´¿à´•à´³àµà´‚ മായàµà´•àµà´•àµà´‚.</translation>
<translation id="5771720122942595109"><ph name="PERMISSION_1" /> à´¬àµà´²àµ‹à´•àµà´•àµ ചെയàµâ€Œà´¤àµ</translation>
<translation id="5804241973901381774">à´…à´¨àµà´®à´¤à´¿à´•àµ¾</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">à´ªàµà´²àµ‡à´šàµ†à´¯àµà´¯àµà´•</translation>
<translation id="6818926723028410516">ഇനങàµà´™àµ¾ തിരഞàµà´žàµ†à´Ÿàµà´•àµà´•àµà´•</translation>
<translation id="6864395892908308021">à´ˆ ഉപകരണതàµà´¤à´¿à´¨àµ NFC റീഡൠചെയàµà´¯à´¾à´¨à´¾à´µà´¿à´²àµà´²</translation>
-<translation id="6910211073230771657">ഇലàµà´²à´¾à´¤à´¾à´•àµà´•à´¿</translation>
<translation id="6912998170423641340">à´•àµà´²à´¿à´ªàµà´ªàµà´¬àµ‹àµ¼à´¡à´¿àµ½ നിനàµà´¨àµ à´šà´¿à´¤àµà´°à´™àµà´™à´³àµà´‚ ടെകàµâ€Œà´¸àµâ€Œà´±àµà´±àµà´‚ റീഡൠചെയàµà´¯àµà´¨àµà´¨à´¤à´¿àµ½ നിനàµà´¨àµ സൈറàµà´±àµà´•à´³àµ† à´¬àµà´²àµ‹à´•àµà´•àµ ചെയàµà´¯àµà´•</translation>
<translation id="6945221475159498467">തിരഞàµà´žàµ†à´Ÿàµà´•àµà´•àµà´•</translation>
<translation id="6965382102122355670">ശരി</translation>
+<translation id="6981982820502123353">ഉപയോഗസഹായി</translation>
<translation id="6992289844737586249">നിങàµà´™à´³àµà´Ÿàµ† മൈകàµà´°àµ‹à´«àµ‹àµº ഉപയോഗികàµà´•à´¾àµ» സൈറàµà´±àµà´•à´³àµ† à´…à´¨àµà´µà´¦à´¿à´•àµà´•àµà´¨àµà´¨à´¤à´¿à´¨àµ à´®àµà´®àµà´ªàµ ആദàµà´¯à´‚ ചോദികàµà´•àµà´• (à´¶àµà´ªà´¾àµ¼à´¶à´šàµ†à´¯àµâ€Œà´¤à´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨àµ)</translation>
<translation id="7000754031042624318">Android à´•àµà´°à´®àµ€à´•à´°à´£à´¤àµà´¤à´¿àµ½ ഓഫാകàµà´•à´¿à´¯à´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨àµ</translation>
<translation id="7016516562562142042">നിലവിലെ തിരയൽ യനàµà´¤àµà´°à´¤àµà´¤à´¿àµ½ à´…à´¨àµà´µà´¦à´¿à´šàµà´šà´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨àµ</translation>
+<translation id="702463548815491781">TalkBack à´…à´²àµà´²àµ†à´™àµà´•à´¿àµ½ à´¸àµà´µà´¿à´šàµà´šàµ ആകàµâ€Œà´¸à´¸àµ ഓണായിരികàµà´•àµà´®àµà´ªàµ‹àµ¾ à´¶àµà´ªà´¾àµ¼à´¶ ചെയàµà´¯àµà´¨àµà´¨àµ</translation>
<translation id="7053983685419859001">തടയàµà´•</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1 തിരഞàµà´žàµ†à´Ÿàµà´¤àµà´¤àµ}other{# തിരഞàµà´žàµ†à´Ÿàµà´¤àµà´¤àµ}}</translation>
-<translation id="7070090581017165256">à´ˆ സൈറàµà´±à´¿à´¨àµ† à´•àµà´±à´¿à´šàµà´šàµ</translation>
<translation id="7087918508125750058"><ph name="ITEM_COUNT" /> à´Žà´£àµà´£à´‚ തിരഞàµà´žàµ†à´Ÿàµà´¤àµà´¤àµ. à´¸àµâ€Œà´•àµà´°àµ€à´¨à´¿à´¨àµà´±àµ† à´®àµà´•à´³à´¿à´²àµà´³àµà´³ ഭാഗതàµà´¤à´¿à´¨àµ സമീപം à´“à´ªàµâ€Œà´·à´¨àµà´•àµ¾ ലഭàµà´¯à´®à´¾à´£àµ</translation>
<translation id="7141896414559753902">പോപàµà´ªàµ à´…à´ªàµà´ªàµà´•à´³àµà´‚ റീഡയറകàµâ€Œà´±àµà´±àµà´•à´³àµà´‚ കാണികàµà´•àµà´¨àµà´¨à´¤à´¿àµ½ നിനàµà´¨àµ സൈറàµà´±àµà´•à´³àµ† à´¬àµà´²àµ‹à´•àµà´•àµ ചെയàµà´¯àµà´• (à´¶àµà´ªà´¾àµ¼à´¶ ചെയàµâ€Œà´¤à´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨àµ)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> KB</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">ഒരൠസൈറàµà´±àµ നിങàµà´™à´³àµà´Ÿàµ† മൈകàµà´°àµ‹à´«àµ‹àµº ഉപയോഗികàµà´•àµà´¨àµà´¨àµ</translation>
<translation id="7561196759112975576">à´Žà´²àµà´²à´¾à´¯àµà´ªàµà´ªàµ‹à´´àµà´‚</translation>
-<translation id="7572498721684305250">നിങàµà´™àµ¾ NFC ഉപകരണങàµà´™à´³à´¿àµ½ ടാപàµà´ªàµ ചെയàµà´¯àµà´®àµà´ªàµ‹àµ¾ വിവരങàµà´™àµ¾ അയയàµâ€Œà´•àµà´•àµà´¨àµà´¨à´¤à´¿àµ½ നിനàµà´¨àµà´‚ à´¸àµà´µàµ€à´•à´°à´¿à´•àµà´•àµà´¨àµà´¨à´¤à´¿àµ½ നിനàµà´¨àµà´‚ സൈറàµà´±àµà´•à´³àµ† à´¬àµà´²àµ‹à´•àµà´•àµ ചെയàµà´¯àµà´•</translation>
<translation id="757524316907819857">പരിരകàµà´·à´¿à´¤ ഉളàµà´³à´Ÿà´•àµà´•à´‚ à´ªàµà´²àµ‡ ചെയàµà´¯àµà´¨àµà´¨à´¤à´¿àµ½ നിനàµà´¨àµ സൈറàµà´±àµà´•à´³àµ† à´¬àµà´²àµ‹à´•àµà´•àµ ചെയàµà´¯àµà´•</translation>
+<translation id="7577900504646297215">താൽപàµà´ªà´°àµà´¯à´™àµà´™àµ¾ മാനേജൠചെയàµà´¯àµà´•</translation>
<translation id="7649070708921625228">സഹായം</translation>
<translation id="7658239707568436148">റദàµà´¦à´¾à´•àµà´•àµ‚</translation>
<translation id="7781829728241885113">ഇനàµà´¨à´²àµ†</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">കണകàµà´·àµ» à´¸àµà´°à´•àµà´·à´¿à´¤à´®à´¾à´£àµ</translation>
<translation id="8249310407154411074">à´®àµà´•à´³à´¿à´²àµ‡à´•àµà´•àµ നീകàµà´•àµà´•</translation>
<translation id="8261506727792406068">ഇലàµà´²à´¾à´¤à´¾à´•àµà´•àµà´•</translation>
+<translation id="8284326494547611709">à´…à´Ÿà´¿à´•àµà´•àµà´±à´¿à´ªàµà´ªàµà´•àµ¾</translation>
<translation id="8300705686683892304">ആപàµà´ªàµ മാനേജൠചെയàµà´¯àµà´¨àµà´¨à´¤àµ</translation>
<translation id="8324158725704657629">വീണàµà´Ÿàµà´‚ ആവശàµà´¯à´ªàµà´ªàµ†à´Ÿà´°àµà´¤àµ</translation>
<translation id="8372893542064058268">ഒരൠപàµà´°à´¤àµà´¯àµ‡à´• സൈറàµà´±à´¿à´¨àµ വേണàµà´Ÿà´¿ പശàµà´šà´¾à´¤àµà´¤à´²à´‚ സമനàµà´µà´¯à´¿à´ªàµà´ªà´¿à´•àµà´•àµ½ à´…à´¨àµà´µà´¦à´¿à´•àµà´•àµà´•.</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">സൂം ഇനàµâ€ ചെയàµà´¯àµà´•</translation>
<translation id="8921772741368021346"><ph name="POSITION" /> / <ph name="DURATION" /></translation>
<translation id="8926666909099850184">à´ˆ ഉപകരണതàµà´¤à´¿à´¨àµà´³àµà´³ NFC ഓഫാണàµ. ഇതൠ<ph name="BEGIN_LINK" />Android à´•àµà´°à´®àµ€à´•à´°à´£à´¤àµà´¤à´¿àµ½<ph name="END_LINK" /> ഓണാകàµà´•àµà´•.</translation>
+<translation id="8928445016601307354">NFC ഉപകരണങàµà´™à´³à´¿à´²àµ† വിവരങàµà´™àµ¾ കാണàµà´¨àµà´¨à´¤à´¿à´²àµà´‚ അവയിൽ മാറàµà´±à´‚ വരàµà´¤àµà´¤àµà´¨àµà´¨à´¤à´¿à´²àµà´‚ നിനàµà´¨àµ സൈറàµà´±àµà´•à´³àµ† à´¬àµà´²àµ‹à´•àµà´•àµ ചെയàµà´¯àµà´•</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">ഒരൠപàµà´°à´¤àµà´¯àµ‡à´• സൈറàµà´±à´¿à´¨à´¾à´¯à´¿ à´•àµà´•àµà´•à´¿à´•àµ¾ à´¬àµà´²àµ‹à´•àµà´•àµ ചെയàµà´¯àµà´•.</translation>
<translation id="8959122750345127698">നാവിഗേഷൻ ലഭàµà´¯à´®à´²àµà´²: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_mn.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_mn.xtb
index 12835488aea..2f02d5cbd78 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_mn.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_mn.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">Сайт <ph name="SITE_NAME" /> нÑмÑÑн</translation>
<translation id="1383876407941801731">Хайлт</translation>
<translation id="1384959399684842514">Таталтыг түр зогÑооÑон</translation>
+<translation id="1409426117486808224">ÐÑÑлттÑй табын Ñ…ÑлбаршуулÑан харагдац</translation>
<translation id="1415402041810619267">URL-г танаÑан</translation>
<translation id="1446450296470737166">MIDI төхөөрөмжийг бүрÑн Ñ…Ñнахыг зөвшөөрөх</translation>
<translation id="1620510694547887537">Камер</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">Күүкиг зөвшөөрөх</translation>
<translation id="2228071138934252756"><ph name="APP_NAME" />-д камертаа хандахыг зөвшөөрөхийн тулд камерыг мөн <ph name="BEGIN_LINK" />Ðндройдын тохиргоо<ph name="END_LINK" />-нд аÑаана уу.</translation>
<translation id="2241634353105152135">Ганц удаа</translation>
+<translation id="2253414712144136228"><ph name="NAME_OF_LIST_ITEM" />-г хаÑах</translation>
<translation id="2289270750774289114">Сайт ойролцоох Bluetooth төхөөрөмжийг илрүүлÑÑ… Ñ…Ò¯ÑÑлтÑй үед аÑуух (Ñанал болгоÑон)</translation>
<translation id="2315043854645842844">ҮйлчлүүлÑгч талын Ñертификатын Ñонголтыг үйлдлийн ÑиÑтемÑÑÑ Ð´ÑмжÑÑгүй.</translation>
+<translation id="2321958826496381788">Уншихад тохиромжтой болох хүртÑл хүрÑÑг томруулж татна уу. БичвÑÑ€ дÑÑÑ€ хоёр удаа товшÑоны дараагаар текÑтийн Ñ…ÑмжÑÑ Ñ‚Ð¾Ð¼Ð¾Ñ€Ñ‡ харагдана.</translation>
<translation id="2359808026110333948">Цааш</translation>
<translation id="2379925928934107488">Боломжтой бол Chrome бараан загвар ашиглаÑан тохиолдолд Ñайтуудад бараан загвар ашиглана уу</translation>
+<translation id="2387895666653383613">ТекÑтийн Ñ…ÑмжÑÑÑ</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> МБ</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> болон буÑад <ph name="NUM_MORE" />-г зөвшөөрÑөн}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> болон буÑад <ph name="NUM_MORE" />-г зөвшөөрÑөн}}</translation>
<translation id="2434158240863470628">Татаж дууÑÑан <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">ÐœÑдÑÑллийг харуулах</translation>
<translation id="3123473560110926937">Зарим Ñайт дÑÑÑ€ блоклоÑон</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> хадгалÑан өгөгдөл</translation>
+<translation id="3203366800380907218">ВебÑÑÑ</translation>
<translation id="321187648315454507"><ph name="APP_NAME" />-д танд мÑдÑгдÑл илгÑÑхийг зөвшөөрөхийн тулд мÑдÑгдлийг мөн <ph name="BEGIN_LINK" />Ðндройдын тохиргоо<ph name="END_LINK" />-нд аÑаана уу.</translation>
<translation id="3227137524299004712">Микрофон</translation>
<translation id="3277252321222022663">Сайтуудад мÑдрÑгчид хандахыг зөвшөөрөх (Ñанал болгоÑон)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">Таны төхөөрөмжийн ашиглалт</translation>
<translation id="385051799172605136">Буцах</translation>
<translation id="3859306556332390985">Урагш хайх</translation>
+<translation id="3895926599014793903">Ямар ч тохиолдолд томруулан харуулах</translation>
<translation id="3955193568934677022">Сайтад хамгаалÑан агуулгыг тоглохыг зөвшөөрөх (Ñанал болгоÑон)</translation>
<translation id="3967822245660637423">Татаж авч дууÑлаа</translation>
<translation id="3987993985790029246">ХолбооÑыг хуулах</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> / ?</translation>
<translation id="4002066346123236978">Гарчиг</translation>
<translation id="4008040567710660924">Күүкиг тодорхой Ñайтад зөвшөөрнө Ò¯Ò¯.</translation>
+<translation id="4040330681741629921">Сайтыг Ñ…ÑлбаршуулÑан харагдах байдлаар харуулах боломжтой болох үед мÑдÑгдÑл авна уу</translation>
<translation id="4046123991198612571">Дараагийн бичлÑг</translation>
+<translation id="4149994727733219643">Веб хуудаÑны Ñ…ÑлбаршуулÑан харагдац</translation>
<translation id="4165986682804962316">Сайтын тохиргоо</translation>
+<translation id="4194328954146351878">Сайтуудыг NFC төхөөрөмжүүд дÑÑрх мÑдÑÑллийг харах болон өөрчлөхийг Ð·Ó©Ð²ÑˆÓ©Ó©Ñ€Ó©Ñ…Ó©Ó©Ñ Ó©Ð¼Ð½Ó© аÑуух (зөвлөÑөн)</translation>
<translation id="4200726100658658164">Байршлын тохиргоог нÑÑÑ…</translation>
<translation id="4226663524361240545">ÐœÑдÑгдÑл ирÑÑ…Ñд төхөөрөмж чичрÑнÑ</translation>
<translation id="4259722352634471385">Ðавигацыг хориглоÑон байна: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">Өргөтгөх</translation>
<translation id="4336434711095810371">Бүх өгөгдлийг уÑтгах</translation>
<translation id="4402755511846832236">Сайтуудыг таныг ÑÐ½Ñ Ñ‚Ó©Ñ…Ó©Ó©Ñ€Ó©Ð¼Ð¶Ð¸Ð¹Ð³ Ñ…ÑзÑÑ Ð¸Ð´ÑвхтÑй ашиглаж буйг мÑдÑхийг нь блоклоно</translation>
+<translation id="4428065317363009941">СонирхÑон зарын тохируулга</translation>
<translation id="4434045419905280838">Попап болон дахин чиглүүлÑлт</translation>
<translation id="445467742685312942">Сайтуудад хамгаалагдÑан контент тоглуулахыг зөвшөөрөх</translation>
<translation id="4468959413250150279">Тодорхой Ñайтын дууг хаана уу.</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">Сонголт дÑлгÑцийн дÑÑд Ñ…ÑÑÑгт байна</translation>
<translation id="5197729504361054390">Таны Ñонгох харилцагчдыг <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />-тай хуваалцана.</translation>
<translation id="5216942107514965959">Хамгийн Ñүүлд өнөөдөр зочилÑон</translation>
+<translation id="5264323282659631142">'<ph name="CHIP_LABEL" />'-г хаÑах</translation>
<translation id="528192093759286357">БүтÑн дÑлгÑцийн Ð³Ð¾Ñ€Ð¸Ð¼Ð¾Ð¾Ñ Ð³Ð°Ñ€Ð°Ñ…Ñ‹Ð½ тулд дÑÑÑ€ÑÑÑ Ð·Ó©Ó©Ð³Ó©Ó©Ð´, буцах товчлуурыг дарна уу.</translation>
<translation id="5300589172476337783">Харуулах</translation>
<translation id="5301954838959518834">OK, ойлголоо</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">Ð­Ð½Ñ Ð½ÑŒ ÑÐ°Ð¹Ñ‚Ð°Ð°Ñ Ñ…Ð°Ð´Ð³Ð°Ð»Ñан <ph name="DATASIZE" /> өгөгдөл болон күүкиг арилгана.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(буÑад + 1)}other{(буÑад + #)}}</translation>
<translation id="5403592356182871684">ÐÑÑ€</translation>
+<translation id="5412236728747081950">Ð­Ð½Ñ Ñайт танд илүү хамааралтай зар харуулахын тулд таны Ñонирхлуудыг Chrome-Ñ Ð°Ð²Ð´Ð°Ð³</translation>
<translation id="5438097262470833822">Ð­Ð½Ñ Ñонголт <ph name="WEBSITE" />-н зөвшөөрлийг шинÑчилнÑ</translation>
<translation id="5489227211564503167">ӨнгөрÑөн цаг: <ph name="TOTAL_TIME" />-н <ph name="ELAPSED_TIME" />.</translation>
<translation id="5494752089476963479">ТөвөгтÑй ÑÑвÑл хуурамч зар харуулдаг Ñайтуудын зарыг блоклох</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">Дахин ачаал</translation>
<translation id="5596627076506792578">БуÑад Ñонголт</translation>
<translation id="5649053991847567735">Ðвтоматаар татаж авах файл</translation>
+<translation id="5668404140385795438">Томруулах үйлдлÑÑÑ ÑƒÑ€ÑŒÐ´Ñ‡Ð¸Ð»Ð°Ð½ ÑÑргийлÑхийн тулд вÑбÑайтны Ñ…Ò¯ÑÑлтийг хүчингүй болгох</translation>
<translation id="5677928146339483299">ХаагдÑан</translation>
<translation id="5689516760719285838">Байршил</translation>
<translation id="5690795753582697420">Камерыг Android тохиргоо Ñ…ÑÑÑгт унтрааÑан байна</translation>
-<translation id="5710871682236653961">Таныг NFC төхөөрөмж дÑÑÑ€ товших үед мÑдÑÑлÑл илгÑÑÑ… болон хүлÑÑн авахыг Ñайтуудад зөвшөөрөхийн өмнө аÑуух (зөвлөÑөн)</translation>
<translation id="5719847187258001597">Ð­Ð½Ñ Ð½ÑŒ <ph name="ORIGIN" /> ÑÑвÑл таны ҮндÑÑн нүүрÑн дÑÑрх үүний Ð°Ð¿Ð¿Ð°Ð°Ñ Ñ…Ð°Ð´Ð³Ð°Ð»Ñан бүх өгөгдөл болон күүкиг арилгана.</translation>
<translation id="5771720122942595109"><ph name="PERMISSION_1" />-г блоклоÑон</translation>
<translation id="5804241973901381774">Зөвшөөрлүүд</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">Тоглуулах</translation>
<translation id="6818926723028410516">Зүйл Ñонгох</translation>
<translation id="6864395892908308021">Ð­Ð½Ñ Ñ‚Ó©Ñ…Ó©Ó©Ñ€Ó©Ð¼Ð¶ NFC-г унших боломжгүй байна</translation>
-<translation id="6910211073230771657">УÑтгаÑан</translation>
<translation id="6912998170423641340">Сайтыг түр Ñанах ойн текÑÑ‚ болон зургийг уншихыг хориглох</translation>
<translation id="6945221475159498467">Сонгох</translation>
<translation id="6965382102122355670">OK</translation>
+<translation id="6981982820502123353">Хандалт</translation>
<translation id="6992289844737586249">Сайтууд микрофон ашиглах зөвшөөрөл авах (Ñанал болгоÑон)</translation>
<translation id="7000754031042624318">Ðндройдын тохиргоонд унтрааÑан</translation>
<translation id="7016516562562142042">Одоогийн хайлтын Ñ…ÑÑ€ÑгÑÑлд зөвшөөрÑөн</translation>
+<translation id="702463548815491781">TalkBack ÑÑвÑл Хандалтыг ÑÑлгÑÑ… аÑаалттай үед тохиромжтой</translation>
<translation id="7053983685419859001">Блоклох</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1 ÑонгоÑон}other{# ÑонгоÑон}}</translation>
-<translation id="7070090581017165256">Ð­Ð½Ñ Ñайтын талаар</translation>
<translation id="7087918508125750058"><ph name="ITEM_COUNT" />-г ÑонгоÑон. Сонголт дÑлгÑцийн дÑÑд Ñ…ÑÑÑгт боломжтой</translation>
<translation id="7141896414559753902">Сайтыг попап болон дахин чиглүүлÑлтийг Ñ…Ð°Ñ€ÑƒÑƒÐ»Ð°Ñ…Ð°Ð°Ñ Ð±Ð»Ð¾ÐºÐ»Ð¾Ñ… (Ñанал болгоÑон)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> килобайт</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">Сайт таны микрофоныг ашиглаж байна</translation>
<translation id="7561196759112975576">ҮргÑлж</translation>
-<translation id="7572498721684305250">Таныг NFC төхөөрөмж дÑÑÑ€ товших үед мÑдÑÑлÑл илгÑÑÑ… болон хүлÑÑн авахыг Ñайтуудад хориглох</translation>
<translation id="757524316907819857">Хамгаалалттай контентыг тоглуулж буй Ñайтуудыг блок хийх</translation>
+<translation id="7577900504646297215">Сонирхлыг удирдах</translation>
<translation id="7649070708921625228">ТуÑламж</translation>
<translation id="7658239707568436148">Болих</translation>
<translation id="7781829728241885113">Өчигдөр</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">Холболт аюулгүй байна</translation>
<translation id="8249310407154411074">ДÑÑд Ñ…ÑÑÑг Ñ€Ò¯Ò¯ зөөх</translation>
<translation id="8261506727792406068">УÑтгах</translation>
+<translation id="8284326494547611709">Тайлбар</translation>
<translation id="8300705686683892304">Ðппаар удирддаг</translation>
<translation id="8324158725704657629">Дахиж бүү аÑуу</translation>
<translation id="8372893542064058268">Тодорхой Ñайтад дÑвÑгÑрт Ñинк хийхийг зөвшөөрнө.</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">Томруулж харах</translation>
<translation id="8921772741368021346"><ph name="POSITION" /> / <ph name="DURATION" /></translation>
<translation id="8926666909099850184">Ð­Ð½Ñ Ñ‚Ó©Ñ…Ó©Ó©Ñ€Ó©Ð¼Ð¶ дÑÑÑ€ NFC унтраалттай байна. Үүнийг <ph name="BEGIN_LINK" />Android-н тохиргоо<ph name="END_LINK" /> Ñ…ÑÑÑгт аÑаана уу.</translation>
+<translation id="8928445016601307354">Сайтуудыг NFC төхөөрөмжүүд дÑÑрх мÑдÑÑллийг харах болон өөрчлөхийг блоклох</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">Күүкиг тодорхой Ñайтад хориглоно уу.</translation>
<translation id="8959122750345127698">Ðавигацтай холбогдох боломжгүй байна: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_mr.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_mr.xtb
index b3fd0253cf4..afa25a478e0 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_mr.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_mr.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676"><ph name="SITE_NAME" /> साइट जोडली</translation>
<translation id="1383876407941801731">शोधा</translation>
<translation id="1384959399684842514">डाउनलोडला विराम दिला</translation>
+<translation id="1409426117486808224">उघडà¥à¤¯à¤¾ टॅबसाठी सोपा केलेला वà¥à¤¹à¥à¤¯à¥‚</translation>
<translation id="1415402041810619267">URL कापली गेली</translation>
<translation id="1446450296470737166">MIDI डिवà¥à¤¹à¤¾à¤‡à¤¸à¥‡à¤¸à¤šà¥à¤¯à¤¾ पूरà¥à¤£ नियंतà¥à¤°à¤£à¤¾à¤¸ अनà¥à¤®à¤¤à¥€ दà¥à¤¯à¤¾</translation>
<translation id="1620510694547887537">कॅमेरा</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">कà¥à¤•à¥€à¤‚ना अनà¥à¤®à¤¤à¥€ दà¥à¤¯à¤¾</translation>
<translation id="2228071138934252756"><ph name="APP_NAME" /> ला तà¥à¤®à¤šà¤¾ कॅमेरा ॲकà¥à¤¸à¥‡à¤¸ करू देणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€, <ph name="BEGIN_LINK" />Android सेटिंगà¥à¤œ<ph name="END_LINK" /> मधà¥à¤¯à¥‡à¤¦à¥‡à¤–ील कॅमेरा सà¥à¤°à¥‚ करा.</translation>
<translation id="2241634353105152135">फकà¥à¤¤ à¤à¤•à¤¦à¤¾à¤š</translation>
+<translation id="2253414712144136228"><ph name="NAME_OF_LIST_ITEM" /> काढून टाका</translation>
<translation id="2289270750774289114">साइटला केवà¥à¤¹à¤¾ जवळपासचे बà¥à¤²à¥‚टूथ डिवà¥à¤¹à¤¾à¤‡à¤¸ शोधायचे आहे हे विचारा (शिफारस केलेले)</translation>
<translation id="2315043854645842844">कà¥à¤²à¤¾à¤¯à¤‚ट साइड पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° निवडीला ऑपरेटिंग सिसà¥à¤Ÿà¤®à¤šà¤¾ सपोरà¥à¤Ÿ नाही.</translation>
+<translation id="2321958826496381788">तà¥à¤®à¥à¤¹à¥€ हे वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¿à¤¤ वाचू शकणà¥à¤¯à¤¾à¤ªà¤¾à¤°à¥à¤¯à¤‚त सà¥à¤²à¤¾à¤¯à¤¡à¤° डà¥à¤°à¥…ग करा. परिचà¥à¤›à¥‡à¤¦à¤¾à¤µà¤° डबल-टॅपिंग केलà¥à¤¯à¤¾à¤¨à¤‚तर मजकूर कमीत कमी यापेकà¥à¤·à¤¾ मोठा दिसावा.</translation>
<translation id="2359808026110333948">सà¥à¤°à¥‚ ठेवा</translation>
<translation id="2379925928934107488">शकà¥à¤¯ असेल तेवà¥à¤¹à¤¾, Chrome गडद थीम वापरते तेवà¥à¤¹à¤¾ साइटवर गडद थीम लागू करा</translation>
+<translation id="2387895666653383613">मजकूर सà¥à¤•à¥‡à¤²à¤¿à¤—</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> आणि आणखी <ph name="NUM_MORE" /> ला अनà¥à¤®à¤¤à¥€ दिली}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> आणि आणखी <ph name="NUM_MORE" /> ना अनà¥à¤®à¤¤à¥€ दिली}}</translation>
<translation id="2434158240863470628">डाउनलोड पूरà¥à¤£ à¤à¤¾à¤²à¥‡ <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">माहिती दाखवा</translation>
<translation id="3123473560110926937">काही साइटवर बà¥à¤²à¥‰à¤• केले आहे</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> संचयित केलेला डेटा</translation>
+<translation id="3203366800380907218">वेबवरील</translation>
<translation id="321187648315454507"><ph name="APP_NAME" /> ने तà¥à¤®à¥à¤¹à¤¾à¤²à¤¾ सूचना पाठवणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€, <ph name="BEGIN_LINK" />Android सेटिंगà¥à¤œ<ph name="END_LINK" /> मधà¥à¤¯à¥‡à¤¦à¥‡à¤–ील सूचना सà¥à¤°à¥‚ करा.</translation>
<translation id="3227137524299004712">मायकà¥à¤°à¥‹à¤«à¥‹à¤¨</translation>
<translation id="3277252321222022663">साइटना सेनà¥à¤¸à¤° ॲकà¥à¤¸à¥‡à¤¸ करणà¥à¤¯à¤¾à¤šà¥€ अनà¥à¤®à¤¤à¥€ दà¥à¤¯à¤¾ (शिफारस केलेले)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">तà¥à¤®à¤šà¥à¤¯à¤¾ डिवà¥à¤¹à¤¾à¤‡à¤¸à¤šà¤¾ वापर</translation>
<translation id="385051799172605136">मागील</translation>
<translation id="3859306556332390985">पà¥à¤¢à¥‡ शोधा</translation>
+<translation id="3895926599014793903">à¤à¥‚म सà¥à¤°à¥‚ करणà¥à¤¯à¤¾à¤šà¥€ सकà¥à¤¤à¥€</translation>
<translation id="3955193568934677022">संरकà¥à¤·à¤¿à¤¤ आशय पà¥à¤²à¥‡ करणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ साइटना अनà¥à¤®à¤¤à¥€ दà¥à¤¯à¤¾ (शिफारस केलेले)</translation>
<translation id="3967822245660637423">पूरà¥à¤£ डाउनलोड करा</translation>
<translation id="3987993985790029246">लिंक कॉपी करा</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> / ?</translation>
<translation id="4002066346123236978">शीरà¥à¤·à¤•</translation>
<translation id="4008040567710660924">विशिषà¥à¤ŸÂ à¤¸à¤¾à¤‡à¤Ÿà¤¸à¤¾à¤ à¥€Â à¤•à¥à¤•à¥€à¤¨à¤¾Â à¤…नà¥à¤®à¤¤à¥€Â à¤¦à¥à¤¯à¤¾.</translation>
+<translation id="4040330681741629921">à¤à¤–ादी साइट सà¥à¤²à¤­ दृशà¥à¤¯à¤¾à¤¤ दाखवली जाऊ शकत असलà¥à¤¯à¤¾à¤¸ सूचना मिळवा</translation>
<translation id="4046123991198612571">पà¥à¤¢à¥€à¤² टà¥à¤°à¥…क</translation>
+<translation id="4149994727733219643">वेब पेजसाठी सोपा केलेला वà¥à¤¹à¥à¤¯à¥‚</translation>
<translation id="4165986682804962316">साइट सेटिंगà¥à¤œ</translation>
+<translation id="4194328954146351878">साइटना NFC डिवà¥à¤¹à¤¾à¤‡à¤¸à¤µà¤°à¥€à¤² माहिती पाहू देणà¥à¤¯à¤¾à¤šà¥€ किंवा बदलणà¥à¤¯à¤¾à¤šà¥€ अनà¥à¤®à¤¤à¥€ देणà¥à¤¯à¤¾à¤ªà¥‚रà¥à¤µà¥€ विचारा (शिफारस केलेले)</translation>
<translation id="4200726100658658164">सà¥à¤¥à¤¾à¤¨ सेटिंगà¥à¤œ उघडा</translation>
<translation id="4226663524361240545">सूचनांमà¥à¤³à¥‡ डिवà¥à¤¹à¤¾à¤‡à¤¸à¤šà¥‡ कंपन होऊ शकते</translation>
<translation id="4259722352634471385">नेवà¥à¤¹à¤¿à¤—ेशन अवरोधित केले आहे: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">विसà¥à¤¤à¥ƒà¤¤ करा</translation>
<translation id="4336434711095810371">सरà¥à¤µ डेटा साफ करा</translation>
<translation id="4402755511846832236">तà¥à¤®à¥à¤¹à¥€ हे डिवà¥à¤¹à¤¾à¤‡à¤¸ ॲकà¥à¤Ÿà¤¿à¤µà¥à¤¹à¤ªà¤£à¥‡ कधी वापरता हे साइटना जाणून घेणà¥à¤¯à¤¾à¤ªà¤¾à¤¸à¥‚न बà¥à¤²à¥‰à¤• करा</translation>
+<translation id="4428065317363009941">जाहिरात परà¥à¤¸à¤¨à¤²à¤¾à¤¯à¤à¥‡à¤¶à¤¨</translation>
<translation id="4434045419905280838">पॉप-अप आणि रीडिरेकà¥à¤Ÿ</translation>
<translation id="445467742685312942">साइटना संरकà¥à¤·à¤¿à¤¤Â à¤†à¤¶à¤¯Â à¤ªà¥à¤²à¥‡Â à¤•à¤°à¥‚ दà¥à¤¯à¤¾</translation>
<translation id="4468959413250150279">विशिषà¥à¤Ÿ साइटसाठी धà¥à¤µà¤¨à¥€ मà¥à¤¯à¥‚ट करा.</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">सà¥à¤•à¥à¤°à¥€à¤¨à¤šà¥à¤¯à¤¾ सरà¥à¤µà¤¾à¤¤ वरती परà¥à¤¯à¤¾à¤¯ उपलबà¥à¤§ आहे</translation>
<translation id="5197729504361054390">तà¥à¤®à¥à¤¹à¥€ निवडलेले संपरà¥à¤• <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />सोबत शेअर केले जातील.</translation>
<translation id="5216942107514965959">आज शेवटची भेट दिली</translation>
+<translation id="5264323282659631142">'<ph name="CHIP_LABEL" />' काढून टाका</translation>
<translation id="528192093759286357">शीरà¥à¤· पासून डà¥à¤°à¥…ग करा आणि फà¥à¤²à¤¸à¥à¤•à¥à¤°à¥€à¤¨ मधून बाहेर पडणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ परत बटणास सà¥à¤ªà¤°à¥à¤¶ करा.</translation>
<translation id="5300589172476337783">दरà¥à¤¶à¤µà¤¾</translation>
<translation id="5301954838959518834">ठीक आहे, समजले</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">हे साइटने सà¥à¤Ÿà¥‹à¤…र केलेला <ph name="DATASIZE" /> डेटा आणि कà¥à¤•à¥€ साफ करेल.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(+ आणखी à¤à¤•)}other{(+ आणखी #)}}</translation>
<translation id="5403592356182871684">नावे</translation>
+<translation id="5412236728747081950">तà¥à¤®à¥à¤¹à¤¾à¤²à¤¾ आणखी उपयà¥à¤•à¥à¤¤ जाहिराती दाखवणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ ही साइट Chrome मधून तà¥à¤®à¤šà¥€ सà¥à¤µà¤¾à¤°à¤¸à¥à¤¯à¥‡ मिळवते</translation>
<translation id="5438097262470833822">या निवडीमà¥à¤³à¥‡ <ph name="WEBSITE" /> चà¥à¤¯à¤¾ परवानगà¥à¤¯à¤¾ रीसेट होतील</translation>
<translation id="5489227211564503167"><ph name="TOTAL_TIME" /> पैकी <ph name="ELAPSED_TIME" /> गेलेला वेळ.</translation>
<translation id="5494752089476963479">अनाहूत किंवा दिशाभूल करणाऱà¥à¤¯à¤¾ जाहिराती दाखवणाऱà¥à¤¯à¤¾ साइटवरील जाहिराती बà¥à¤²à¥‰à¤• करा</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">रीलोड करा</translation>
<translation id="5596627076506792578">अधिक परà¥à¤¯à¤¾à¤¯</translation>
<translation id="5649053991847567735">सà¥à¤µà¤¯à¤‚चलित डाउनलोड</translation>
+<translation id="5668404140385795438">à¤à¥‚म वाढविणे निरà¥à¤¬à¤‚धित करणà¥à¤¯à¤¾à¤šà¥€ वेबसाइटची विनंती ओवà¥à¤¹à¤°à¤°à¤¾à¤‡à¤¡ करा</translation>
<translation id="5677928146339483299">अवरोधित</translation>
<translation id="5689516760719285838">सà¥à¤¥à¤¾à¤¨</translation>
<translation id="5690795753582697420">Android सेटिंगà¥à¤œà¤®à¤§à¥à¤¯à¥‡ कॅमेरा बंद केला आहे</translation>
-<translation id="5710871682236653961">तà¥à¤®à¥à¤¹à¥€ NFC डिवà¥à¤¹à¤¾à¤‡à¤¸à¤µà¤° टॅप करता तेवà¥à¤¹à¤¾ साइटना माहिती पाठवणà¥à¤¯à¤¾à¤šà¥€ आणि मिळवणà¥à¤¯à¤¾à¤šà¥€ अनà¥à¤®à¤¤à¥€ देणà¥à¤¯à¤¾à¤ªà¥‚रà¥à¤µà¥€ परवानगीची विनंती करा (शिफारस केलेले)</translation>
<translation id="5719847187258001597">हे <ph name="ORIGIN" /> किंवा तà¥à¤¯à¤¾à¤šà¥à¤¯à¤¾ अâ€à¥…पà¥à¤¸à¤¨à¥€ तà¥à¤®à¤šà¥à¤¯à¤¾ होम सà¥à¤•à¥à¤°à¥€à¤¨à¤µà¤° सà¥à¤Ÿà¥‹à¤…र केलेला सरà¥à¤µ डेटा आणि कà¥à¤•à¥€ साफ करेल.</translation>
<translation id="5771720122942595109"><ph name="PERMISSION_1" /> ला बà¥à¤²à¥‰à¤• केले</translation>
<translation id="5804241973901381774">परवानगà¥à¤¯à¤¾</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">पà¥à¤²à¥‡ करा</translation>
<translation id="6818926723028410516">आयटम निवडा</translation>
<translation id="6864395892908308021">हे डिवà¥à¤¹à¤¾à¤‡à¤¸ NFC रीड करू शकत नाही</translation>
-<translation id="6910211073230771657">हटवला</translation>
<translation id="6912998170423641340">साइटचे कà¥à¤²à¤¿à¤ªà¤¬à¥‹à¤°à¥à¤¡à¤µà¤°à¥€à¤² मजकूर आणि इमेज रीड करणे बà¥à¤²à¥‰à¤• करा</translation>
<translation id="6945221475159498467">निवडा</translation>
<translation id="6965382102122355670">ठीक आहे</translation>
+<translation id="6981982820502123353">ॲकà¥à¤¸à¥‡à¤¸à¤¿à¤¬à¤¿à¤²à¤¿à¤Ÿà¥€</translation>
<translation id="6992289844737586249">साइटना तà¥à¤®à¤šà¤¾ मायकà¥à¤°à¥‹à¤«à¥‹à¤¨ वापरणà¥à¤¯à¤¾à¤šà¥€ अनà¥à¤®à¤¤à¥€ देणà¥à¤¯à¤¾à¤ªà¥‚रà¥à¤µà¥€ पà¥à¤°à¤¥à¤® विचारा (शिफारस केलेले)</translation>
<translation id="7000754031042624318">Android सेटिंगà¥à¤œà¤®à¤§à¥â€à¤¯à¥‡ बंद केले</translation>
<translation id="7016516562562142042">वरà¥à¤¤à¤®à¤¾à¤¨ शोध इंजिनसाठी अनà¥à¤®à¤¤à¥€ दिली</translation>
+<translation id="702463548815491781">TalkBack किंवा सà¥à¤µà¤¿à¤š ॲकà¥à¤¸à¥‡à¤¸ सà¥à¤°à¥‚ असताना शिफारस केलेले</translation>
<translation id="7053983685419859001">अवरोधित करा</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1 निवडला}other{# निवडले}}</translation>
-<translation id="7070090581017165256">या साइटविषयी</translation>
<translation id="7087918508125750058"><ph name="ITEM_COUNT" /> निवडले. सà¥à¤•à¥à¤°à¥€à¤¨à¤šà¥à¤¯à¤¾ वरचà¥à¤¯à¤¾ बाजूला परà¥à¤¯à¤¾à¤¯ उपलबà¥à¤§ आहेत</translation>
<translation id="7141896414559753902">साइट पॉप-अप आणि रीडिरेकà¥à¤Ÿ दाखवणà¥à¤¯à¤¾à¤ªà¤¾à¤¸à¥‚न बà¥à¤²à¥‰à¤• करा (शिफारस केलेले)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> KB</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">साइट तà¥à¤®à¤šà¤¾ मायकà¥à¤°à¥‹à¤«à¥‹à¤¨ वापरत आहे</translation>
<translation id="7561196759112975576">नेहमी</translation>
-<translation id="7572498721684305250">तà¥à¤®à¥à¤¹à¥€ NFC डिवà¥à¤¹à¤¾à¤‡à¤¸à¤µà¤° टॅप करता तेवà¥à¤¹à¤¾ साइटना माहिती पाठवणà¥à¤¯à¤¾à¤ªà¤¾à¤¸à¥‚न किंवा मिळवणà¥à¤¯à¤¾à¤ªà¤¾à¤¸à¥‚न बà¥à¤²à¥‰à¤• करा</translation>
<translation id="757524316907819857">संरकà¥à¤·à¤¿à¤¤ आशय पà¥à¤²à¥‡ करणà¥à¤¯à¤¾à¤ªà¤¾à¤¸à¥‚न साइटवर बà¥à¤²à¥‰à¤• करा</translation>
+<translation id="7577900504646297215">सà¥à¤µà¤¾à¤°à¤¸à¥à¤¯à¥‡ वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¿à¤¤ करा</translation>
<translation id="7649070708921625228">मदत</translation>
<translation id="7658239707568436148">रदà¥à¤¦ करा</translation>
<translation id="7781829728241885113">काल</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">कनेकà¥à¤¶à¤¨ सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ आहे</translation>
<translation id="8249310407154411074">वर नà¥à¤¯à¤¾</translation>
<translation id="8261506727792406068">हटवा</translation>
+<translation id="8284326494547611709">मथळे</translation>
<translation id="8300705686683892304">ॲपदà¥à¤µà¤¾à¤°à¥‡ वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¿à¤¤</translation>
<translation id="8324158725704657629">पà¥à¤¨à¥à¤¹à¤¾ विचारू नका</translation>
<translation id="8372893542064058268">विशिषà¥à¤Ÿ साइटसाठी पारà¥à¤¶à¥à¤µà¤­à¥‚मी संकालनासाठी अनà¥à¤®à¤¤à¥€ दà¥à¤¯à¤¾.</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">à¤à¥‚म इन करा</translation>
<translation id="8921772741368021346"><ph name="POSITION" /> / <ph name="DURATION" /></translation>
<translation id="8926666909099850184">या डिवà¥à¤¹à¤¾à¤‡à¤¸à¤¸à¤¾à¤ à¥€ NFC बंद केले आहे. ते <ph name="BEGIN_LINK" />Android सेटिंगà¥à¤œà¤®à¤§à¥à¤¯à¥‡<ph name="END_LINK" /> सà¥à¤°à¥‚ करा.</translation>
+<translation id="8928445016601307354">NFC डिवà¥à¤¹à¤¾à¤‡à¤¸à¤µà¤° माहिती पाहणà¥à¤¯à¤¾à¤ªà¤¾à¤¸à¥‚न आणि बदलणà¥à¤¯à¤¾à¤ªà¤¾à¤¸à¥‚न साइटना बà¥à¤²à¥‰à¤• करा</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">विशिषà¥à¤Ÿ साइटसाठी कà¥à¤•à¥€Â à¤¬à¥à¤²à¥‰à¤•Â à¤•à¤°à¤¾.</translation>
<translation id="8959122750345127698">नेवà¥à¤¹à¤¿à¤—ेशन आवाकà¥à¤¯à¤¾à¤¬à¤¾à¤¹à¥‡à¤° आहे: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ms.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ms.xtb
index 968c5e7a265..616890f1c37 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ms.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ms.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">Tapak <ph name="SITE_NAME" /> telah ditambahkan</translation>
<translation id="1383876407941801731">Carian</translation>
<translation id="1384959399684842514">Muat turun dijeda</translation>
+<translation id="1409426117486808224">Paparan ringkas bagi tab terbuka</translation>
<translation id="1415402041810619267">URL terpangkas</translation>
<translation id="1446450296470737166">Benarkan kawalan penuh peranti MIDI</translation>
<translation id="1620510694547887537">Kamera</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">Benarkan kuki</translation>
<translation id="2228071138934252756">Untuk membolehkan <ph name="APP_NAME" /> mengakses kamera anda, hidupkan juga kamera dalam <ph name="BEGIN_LINK" />Tetapan Android<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Hanya sekali</translation>
+<translation id="2253414712144136228">Alih keluar <ph name="NAME_OF_LIST_ITEM" /></translation>
<translation id="2289270750774289114">Tanya apabila tapak mahu mencari peranti Bluetooth berdekatan (disyorkan)</translation>
<translation id="2315043854645842844">Pemilihan sijil pihak pelanggan tidak disokong oleh sistem pengendalian ini.</translation>
+<translation id="2321958826496381788">Seret gelangsar sehingga anda selesa membaca teks ini. Teks harus kelihatan sekurang-kurangnya sebesar ini selepas mengetik dua kali pada perenggan.</translation>
<translation id="2359808026110333948">Teruskan</translation>
<translation id="2379925928934107488">Gunakan tema gelap pada laman apabila Chrome menggunakan tema gelap, jika boleh</translation>
+<translation id="2387895666653383613">Penskalaan teks</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> dan <ph name="NUM_MORE" /> lagi dibenarkan}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> dan <ph name="NUM_MORE" /> lagi dibenarkan}}</translation>
<translation id="2434158240863470628">Muat turun selesai: <ph name="SEPARATOR" /><ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">Tunjukkan Maklumat</translation>
<translation id="3123473560110926937">Disekat di sesetengah tapak</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> data disimpan</translation>
+<translation id="3203366800380907218">Daripada web</translation>
<translation id="321187648315454507">Untuk membolehkan <ph name="APP_NAME" /> menghantar pemberitahuan kepada anda, hidupkan juga pemberitahuan dalam <ph name="BEGIN_LINK" />Tetapan Android<ph name="END_LINK" />.</translation>
<translation id="3227137524299004712">Mikrofon</translation>
<translation id="3277252321222022663">Benarkan tapak mengakses penderia (disyorkan)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">Penggunaan peranti anda</translation>
<translation id="385051799172605136">Kembali</translation>
<translation id="3859306556332390985">Cari ke hadapan</translation>
+<translation id="3895926599014793903">Zum didaya paksa</translation>
<translation id="3955193568934677022">Benarkan tapak untuk memainkan kandungan yang dilindungi (disyorkan)</translation>
<translation id="3967822245660637423">Muat turun selesai</translation>
<translation id="3987993985790029246">Salin pautan</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> / ?</translation>
<translation id="4002066346123236978">Tajuk</translation>
<translation id="4008040567710660924">Benarkan kuki untuk tapak tertentu.</translation>
+<translation id="4040330681741629921">Dapatkan pemberitahuan apabila laman boleh ditunjukkan dalam paparan ringkas</translation>
<translation id="4046123991198612571">Lagu seterusnya</translation>
+<translation id="4149994727733219643">Paparan ringkas bagi halaman web</translation>
<translation id="4165986682804962316">Tetapan tapak</translation>
+<translation id="4194328954146351878">Tanya sebelum membenarkan laman melihat dan menukar maklumat pada peranti NFC (disyorkan)</translation>
<translation id="4200726100658658164">Buka Tetapan Lokasi</translation>
<translation id="4226663524361240545">Pemberitahuan boleh menggetarkan peranti</translation>
<translation id="4259722352634471385">Navigasi disekat: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">Kembangkan</translation>
<translation id="4336434711095810371">Kosongkan semua data</translation>
<translation id="4402755511846832236">Sekat tapak daripada mengetahui waktu anda menggunakan peranti ini dengan aktif</translation>
+<translation id="4428065317363009941">Pemperibadian iklan</translation>
<translation id="4434045419905280838">Tetingkap timbul dan ubah hala</translation>
<translation id="445467742685312942">Benarkan tapak memainkan kandungan yang dilindungi</translation>
<translation id="4468959413250150279">Redam bunyi untuk tapak tertentu.</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">Pilihan tersedia berhampiran bahagian atas skrin</translation>
<translation id="5197729504361054390">Kenalan yang anda pilih akan dikongsi dengan <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />.</translation>
<translation id="5216942107514965959">Terakhir dilawati hari ini</translation>
+<translation id="5264323282659631142">Alih keluar '<ph name="CHIP_LABEL" />'</translation>
<translation id="528192093759286357">Seret dari atas dan sentuh butang kembali untuk keluar daripada skrin penuh.</translation>
<translation id="5300589172476337783">Paparkan</translation>
<translation id="5301954838959518834">OK, faham</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">Tindakan ini akan mengosongkan <ph name="DATASIZE" /> data dan kuki yang disimpan oleh tapak.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(+ 1 lagi)}other{(+ # lagi)}}</translation>
<translation id="5403592356182871684">Nama</translation>
+<translation id="5412236728747081950">Laman ini mendapat minat anda daripada Chrome untuk memaparkan iklan yang lebih berkaitan kepada anda</translation>
<translation id="5438097262470833822">Pilihan ini akan menetapkan semula kebenaran untuk <ph name="WEBSITE" /></translation>
<translation id="5489227211564503167"><ph name="ELAPSED_TIME" /> masa berlalu daripada <ph name="TOTAL_TIME" /></translation>
<translation id="5494752089476963479">Sekat iklan di tapak yang menyiarkan iklan yang mengganggu atau mengelirukan</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">Muat Semula</translation>
<translation id="5596627076506792578">Lagi pilihan</translation>
<translation id="5649053991847567735">Muat turun automatik</translation>
+<translation id="5668404140385795438">Mengatasi permintaan laman web untuk menghalang zum masuk</translation>
<translation id="5677928146339483299">Disekat</translation>
<translation id="5689516760719285838">Lokasi</translation>
<translation id="5690795753582697420">Kamera dimatikan dalam tetapan Android</translation>
-<translation id="5710871682236653961">Tanya sebelum membenarkan tapak menghantar dan menerima maklumat semasa anda mengetik peranti NFC (disyorkan)</translation>
<translation id="5719847187258001597">Tindakan ini akan mengosongkan semua data dan kuki yang disimpan oleh <ph name="ORIGIN" /> atau oleh aplnya pada Skrin utama anda.</translation>
<translation id="5771720122942595109"><ph name="PERMISSION_1" /> disekat</translation>
<translation id="5804241973901381774">Kebenaran</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">Mainkan</translation>
<translation id="6818926723028410516">Pilih item</translation>
<translation id="6864395892908308021">Peranti ini tidak dapat membaca NFC</translation>
-<translation id="6910211073230771657">Dipadamkan</translation>
<translation id="6912998170423641340">Sekat tapak daripada membaca teks dan imej daripada papan keratan</translation>
<translation id="6945221475159498467">Pilih</translation>
<translation id="6965382102122355670">OK</translation>
+<translation id="6981982820502123353">Kebolehcapaian</translation>
<translation id="6992289844737586249">Tanya dahulu sebelum membenarkan tapak menggunakan mikrofon anda (disyorkan)</translation>
<translation id="7000754031042624318">Dimatikan dalam tetapan Android</translation>
<translation id="7016516562562142042">Dibenarkan untuk enjin carian semasa</translation>
+<translation id="702463548815491781">Disyorkan apabila TalkBack atau Akses Suis dihidupkan</translation>
<translation id="7053983685419859001">Sekat</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1 dipilih}other{# dipilih}}</translation>
-<translation id="7070090581017165256">Perihal laman ini</translation>
<translation id="7087918508125750058"><ph name="ITEM_COUNT" /> dipilih. Pilihan tersedia berhampiran bahagian atas skrin</translation>
<translation id="7141896414559753902">Sekat tapak daripada memaparkan tetingkap timbul dan ubah hala (disyorkan)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> KB</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">Suatu tapak sedang menggunakan mikrofon anda</translation>
<translation id="7561196759112975576">Sentiasa</translation>
-<translation id="7572498721684305250">Sekat tapak daripada menghantar dan menerima maklumat semasa anda mengetik peranti NFC</translation>
<translation id="757524316907819857">Sekat tapak daripada memainkan kandungan yang dilindungi</translation>
+<translation id="7577900504646297215">Urus minat</translation>
<translation id="7649070708921625228">Bantuan</translation>
<translation id="7658239707568436148">Batal</translation>
<translation id="7781829728241885113">Semalam</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">Sambungan selamat</translation>
<translation id="8249310407154411074">Alihkan ke atas</translation>
<translation id="8261506727792406068">Padam</translation>
+<translation id="8284326494547611709">Kapsyen</translation>
<translation id="8300705686683892304">Diurus oleh apl</translation>
<translation id="8324158725704657629">Jangan tanya lagi</translation>
<translation id="8372893542064058268">Benarkan Penyegerakan Latar Belakang untuk tapak tertentu</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">Zum masuk</translation>
<translation id="8921772741368021346"><ph name="POSITION" /> / <ph name="DURATION" /></translation>
<translation id="8926666909099850184">NFC dimatikan untuk peranti ini. Hidupkan dalam <ph name="BEGIN_LINK" />Tetapan Android<ph name="END_LINK" />.</translation>
+<translation id="8928445016601307354">Sekat laman daripada melihat dan menukar maklumat pada peranti NFC</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">Sekat kuki untuk tapak tertentu.</translation>
<translation id="8959122750345127698">Tidak dapat mencapai navigasi: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_my.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_my.xtb
index 750078d7f30..50a6eb75eb6 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_my.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_my.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">ဆိုက် <ph name="SITE_NAME" /> အား ထည့်á€á€²á€·á</translation>
<translation id="1383876407941801731">ရှာဖွေမှု</translation>
<translation id="1384959399684842514">ဒေါင်းလုဒ်လုပ်မှု ဆိုင်းငံ့ထားသည်</translation>
+<translation id="1409426117486808224">á€á€˜á€ºá€–ွင့်á€á€¼á€„်းများအá€á€½á€€á€º ရိုးရှင်းသည့် မြင်ကွင်း</translation>
<translation id="1415402041810619267">URL ကို ဖြá€á€ºá€œá€­á€¯á€€á€ºá€žá€Šá€º</translation>
<translation id="1446450296470737166">MIDI ကိရိယာများအား အပြည့်အဠထိန်းá€á€»á€¯á€•á€ºá€á€½á€„့် ပြုရန်</translation>
<translation id="1620510694547887537">ကင်မရာ</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">ကွá€á€ºá€€á€®á€¸á€™á€»á€¬á€¸ á€á€½á€„့်ပြုရန်</translation>
<translation id="2228071138934252756"><ph name="APP_NAME" /> က သင့်ကင်မရာကို သုံးနိုင်ရန် <ph name="BEGIN_LINK" />Android ဆက်á€á€„်များ<ph name="END_LINK" /> á€á€½á€„်လည်း ကင်မရာကို ဖွင့်ပါá‹</translation>
<translation id="2241634353105152135">á€á€…်ကြိမ်သာ</translation>
+<translation id="2253414712144136228"><ph name="NAME_OF_LIST_ITEM" /> ဖယ်ရှားရန်</translation>
<translation id="2289270750774289114">á€á€˜á€ºá€†á€­á€¯á€€á€ºá€€ အနီးအနားရှိ ဘလူးá€á€¯á€žá€ºá€€á€­á€›á€­á€šá€¬á€™á€»á€¬á€¸ ရှာဖွေလိုသည့်အá€á€« á€á€½á€„့်á€á€±á€¬á€„်းရန် (အကြံပြုထားသည်)</translation>
<translation id="2315043854645842844">ကလိုင်းယင့် ဘက်မှ လက်မှá€á€ºá€›á€½á€±á€¸á€™á€¾á€¯á€€á€­á€¯ လည်ပá€á€ºá€žá€Šá€ºá€·á€…နစ်မှ မပံ့ပိုးပါá‹</translation>
+<translation id="2321958826496381788">သင်က ယင်းကို ဖá€á€ºá€›á€¡á€†á€„်ပြေသည့် အထိ ဆွဲá€á€”်းကို ဆွဲယူပါዠစာသားá€á€½á€„် စာပိုဒ် á€á€…်á€á€¯á€€á€­á€¯ နှစ်ကြိမ် ပုá€á€ºá€œá€­á€¯á€€á€ºá€žá€Šá€ºá€· နောက်မှာ ဤမျှလောက် ကြီးလျက် မြင်ရသင့်သည်á‹</translation>
<translation id="2359808026110333948">ဆက်လုပ်ရန်</translation>
<translation id="2379925928934107488">Chrome က á€á€˜á€ºá€†á€­á€¯á€€á€ºá€™á€»á€¬á€¸á€€á€­á€¯ မှောင်သည့် အပြင်အဆင်သုံးလျှင် ဖြစ်နိုင်ပါက áŽá€„်းအပြင်အဆင်ကို ပြောင်းပေးသည်</translation>
+<translation id="2387895666653383613">စာသား စကေး</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> မီဂါဘိုက်</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />አ<ph name="PERMISSION_2" /> နှင့် နောက်ထပ် <ph name="NUM_MORE" /> á€á€¯ á€á€½á€„့်ပြုထားသည်}other{<ph name="PERMISSION_1" />አ<ph name="PERMISSION_2" /> နှင့် နောက်ထပ် <ph name="NUM_MORE" /> á€á€¯ á€á€½á€„့်ပြုထားသည်}}</translation>
<translation id="2434158240863470628">ဒေါင်းလုဒ်လုပ်ပြီးပါပြီ <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">အá€á€»á€€á€ºá€¡á€œá€€á€ºá€™á€»á€¬á€¸á€€á€­á€¯ ပြသရန်</translation>
<translation id="3123473560110926937">အá€á€»á€­á€¯á€·á€á€˜á€ºá€†á€­á€¯á€€á€ºá€™á€»á€¬á€¸á€á€½á€„် ပိá€á€ºá€‘ားသည်</translation>
<translation id="3198916472715691905">သိမ်းထားသော ဒေá€á€¬ <ph name="STORAGE_AMOUNT" /></translation>
+<translation id="3203366800380907218">á€á€˜á€ºá€•á€±á€«á€ºá€™á€¾</translation>
<translation id="321187648315454507"><ph name="APP_NAME" /> က အကြောင်းကြားá€á€»á€€á€ºá€™á€»á€¬á€¸ ပေးပို့နိုင်ရန် <ph name="BEGIN_LINK" />Android ဆက်á€á€„်များ<ph name="END_LINK" /> á€á€½á€„်လည်း အကြောင်းကြားá€á€»á€€á€ºá€™á€»á€¬á€¸ ဖွင့်ပါá‹</translation>
<translation id="3227137524299004712">မိုက်á€á€›á€­á€¯á€–ုန်း</translation>
<translation id="3277252321222022663">အာရုံá€á€¶á€…နစ်များ အသုံးပြုရန် ဤá€á€˜á€ºá€†á€­á€¯á€€á€ºá€™á€»á€¬á€¸á€€á€­á€¯ á€á€½á€„့်ပြုသည် (အကြံပြုထားသည်)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">သင်á ကိရိယာအသုံးပြုမှု</translation>
<translation id="385051799172605136">နောက်သို့</translation>
<translation id="3859306556332390985">အရှေ့သို့ ရစ်ရန်</translation>
+<translation id="3895926599014793903">ဇူးမ် အá€á€„်း ဖွင့်ရန်</translation>
<translation id="3955193568934677022">ကာကွယ်ထားသည့် အကြောင်းအရာများကို ဆိုက်များအား ဖွင့်á€á€½á€„့်ပြုပါ (အကြံပြုထားသည်)</translation>
<translation id="3967822245660637423">ဒေါင်းလုဒ်လုပ်á€á€¼á€„်း ပြည့်စုံပါပြီ</translation>
<translation id="3987993985790029246">လင့်á€á€ºá€€á€°á€¸á€šá€°á€™á€Šá€º</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> / ?</translation>
<translation id="4002066346123236978">á€á€±á€«á€„်းစဉ်</translation>
<translation id="4008040567710660924">အá€á€»á€­á€¯á€·á€á€˜á€ºá€†á€­á€¯á€€á€ºá€™á€»á€¬á€¸á€¡á€á€½á€€á€º ကွá€á€ºá€€á€®á€¸á€™á€»á€¬á€¸ á€á€½á€„့်ပြုသည်á‹</translation>
+<translation id="4040330681741629921">á€á€˜á€ºá€†á€­á€¯á€€á€ºá€€á€­á€¯ ရိုးရှင်းသည့်မြင်ကွင်းဖြင့် ပြနိုင်သောအá€á€« အကြောင်းကြားá€á€»á€€á€ºá€›á€šá€°á€”ိုင်သည်</translation>
<translation id="4046123991198612571">နောက်á€á€…်ပုဒ်</translation>
+<translation id="4149994727733219643">á€á€˜á€ºá€…ာမျက်နှာများအá€á€½á€€á€º ရိုးရှင်းသည့်မြင်ကွင်း</translation>
<translation id="4165986682804962316">á€á€€á€ºá€†á€­á€¯á€€á€º ဆက်á€á€„်များ</translation>
+<translation id="4194328954146351878">NFC စက်ပစ္စည်းများရှိ အá€á€»á€€á€ºá€¡á€œá€€á€ºá€™á€»á€¬á€¸á€€á€­á€¯ á€á€˜á€ºá€†á€­á€¯á€€á€ºá€™á€»á€¬á€¸á€¡á€¬á€¸ ကြည့်á€á€½á€„့်နှင့် ပြောင်းလဲá€á€½á€„့်မပေးမီ ဦးစွာမေးမြန်းပါ (အကြံပြုထားသည်)</translation>
<translation id="4200726100658658164">'á€á€Šá€ºá€”ေရာပြဆက်á€á€„်များ' ကို ဖွင့်ပါ</translation>
<translation id="4226663524361240545">အကြောင်းကြားá€á€»á€€á€ºá€žá€Šá€º စက်ပစ္စည်းကို á€á€¯á€”်á€á€«á€…ေပါမည်</translation>
<translation id="4259722352634471385">သွားလာမှုပြလမ်းညွှန်အား ပိá€á€ºá€‘ားá- <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">á€á€­á€¯á€¸á€á€»á€²á€·</translation>
<translation id="4336434711095810371">ဒေá€á€¬á€¡á€¬á€¸á€œá€¯á€¶á€¸ ရှင်းထုá€á€ºá€›á€”်</translation>
<translation id="4402755511846832236">ဤကိရိယာသုံးနေá€á€»á€­á€”်ကို á€á€˜á€ºá€†á€­á€¯á€€á€ºá€™á€»á€¬á€¸á€€á€žá€­á€á€¼á€„်းအား ပိá€á€ºá€‘ားရန်</translation>
+<translation id="4428065317363009941">ကြော်ငြာ စိá€á€ºá€€á€¼á€­á€¯á€€á€ºá€žá€á€ºá€™á€¾á€á€ºá€á€¼á€„်း</translation>
<translation id="4434045419905280838">ပေါ့ပ်အပ်နှင့် á€á€…်ဆင့်ညွှန်á€á€»á€€á€º</translation>
<translation id="445467742685312942">ကာကွယ်ထားသော အကြောင်းအရာများ ဖွင့်ရန် á€á€˜á€ºá€†á€­á€¯á€€á€ºá€™á€»á€¬á€¸á€€á€­á€¯ï¿½ á€á€½á€„့်ပြုသည်</translation>
<translation id="4468959413250150279">á€á€˜á€ºá€†á€­á€¯á€€á€ºá€á€…်á€á€¯á€¡á€á€½á€€á€º အသံá€á€­á€á€ºá€‘ားသည်á‹</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">ဖန်သားပြင်áထိပ်နားá€á€½á€„် ရွေးá€á€»á€šá€ºá€”ိုင်သည်</translation>
<translation id="5197729504361054390">သင်ရွေးá€á€»á€šá€ºá€žá€±á€¬ အဆက်အသွယ်များကို <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> နှင့် မျှá€á€±á€•á€«á€™á€Šá€ºá‹</translation>
<translation id="5216942107514965959">ယနေ့ နောက်ဆုံး á€á€„်ကြည့်ထားသည်</translation>
+<translation id="5264323282659631142">'<ph name="CHIP_LABEL" />' ဖယ်ရှားရန်</translation>
<translation id="528192093759286357">မျက်နှာပြင်အပြည့်ဖွင့်á€á€¼á€„်းမှ ထွက်ရန် ထိပ်ဆုံးမှဆွဲá€á€»á€€á€¬ နောက်ဆုá€á€ºá€›á€”်á€á€œá€¯á€á€ºá€€á€­á€¯ နှိပ်ပါá‹</translation>
<translation id="5300589172476337783">ပြရန်</translation>
<translation id="5301954838959518834">OK</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">áŽá€„်းက ဒေá€á€¬ <ph name="DATASIZE" /> နှင့် á€á€˜á€ºá€†á€­á€¯á€€á€ºá€™á€»á€¬á€¸á€€ သိမ်းထားသည့် ကွá€á€ºá€€á€®á€¸á€™á€»á€¬á€¸á€€á€­á€¯ ရှင်းထုá€á€ºá€œá€­á€¯á€€á€ºá€•á€«á€™á€Šá€ºá‹</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(+ နောက်ထပ် á á€á€¯)}other{(+ နောက်ထပ် # á€á€¯)}}</translation>
<translation id="5403592356182871684">အမည်များ</translation>
+<translation id="5412236728747081950">နောက်ထပ်သက်ဆိုင်ရာ ကြော်ငြာများ ပြရန် Chrome မှ သင့်စိá€á€ºá€á€„်စားမှုများကို ဤá€á€˜á€ºá€†á€­á€¯á€€á€ºá€€ ရယူပါသည်</translation>
<translation id="5438097262470833822">ဤရွေးá€á€»á€šá€ºá€™á€¾á€¯á€€ <ph name="WEBSITE" /> အá€á€½á€€á€º á€á€½á€„့်ပြုá€á€»á€€á€ºá€™á€»á€¬á€¸á€€á€­á€¯ ပြင်ဆင်သá€á€ºá€™á€¾á€á€ºá€•á€«á€œá€­á€™á€·á€ºá€™á€Šá€º</translation>
<translation id="5489227211564503167">ကုန်လွန်သွားá€á€»á€­á€”် <ph name="TOTAL_TIME" /> အနက် <ph name="ELAPSED_TIME" />á‹</translation>
<translation id="5494752089476963479">စိá€á€ºá€¡á€”ှောင့်အယှက်ဖြစ်စေသော သို့မဟုá€á€º အထင်အမြင်မှားစေနိုင်သော ကြော်ငြာများပြသသည့် á€á€˜á€ºá€†á€­á€¯á€€á€ºá€™á€»á€¬á€¸á€á€½á€„် ကြော်ငြာများကို ပိá€á€ºá€žá€Šá€º</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">ပြန်á€á€„်ရန်</translation>
<translation id="5596627076506792578">ပိုမို ရွေးá€á€»á€šá€ºá€…ရာများ</translation>
<translation id="5649053991847567735">အလိုအလျောက် ဒေါင်းလုပ်ရယူá€á€¼á€„်း</translation>
+<translation id="5668404140385795438">á€á€»á€²á€·á€”ေမှုကို ဟန့်á€á€¬á€¸á€›á€”် á€á€˜á€ºá€†á€­á€¯á€€á€º á€á€…်á€á€¯á á€á€±á€¬á€„်းဆိုá€á€»á€€á€ºá€€á€­á€¯ အုပ်ရေးပါ</translation>
<translation id="5677928146339483299">ပိá€á€ºá€†á€­á€¯á€·á€‘ား</translation>
<translation id="5689516760719285838">á€á€Šá€ºá€”ေရာ</translation>
<translation id="5690795753582697420">Android ဆက်á€á€„်များá€á€½á€„် 'ကင်မရာ' ပိá€á€ºá€‘ားသည်</translation>
-<translation id="5710871682236653961">NFC စက်များကို á€á€­á€¯á€·á€œá€­á€¯á€€á€ºá€žá€Šá€·á€ºá€¡á€á€« အá€á€»á€€á€ºá€¡á€œá€€á€ºá€™á€»á€¬á€¸ ပို့ရန်አလက်á€á€¶á€›á€”် á€á€˜á€ºá€†á€­á€¯á€€á€ºá€™á€»á€¬á€¸á€€á€­á€¯ á€á€½á€„့်မပြုမီ á€á€½á€„့်á€á€±á€¬á€„်းပါ (အကြံပြုထားသည်)</translation>
<translation id="5719847187258001597">áŽá€„်းက သင့် 'ပင်မစာမျက်နှာ' ပေါ်ရှိ <ph name="ORIGIN" /> သို့မဟုá€á€º áŽá€„်းáအက်ပ်က သိမ်းထားသော ဒေá€á€¬á€”ှင့် ကွá€á€ºá€€á€®á€¸á€¡á€¬á€¸á€œá€¯á€¶á€¸á€€á€­á€¯ ရှင်းထုá€á€ºá€œá€­á€¯á€€á€ºá€•á€«á€™á€Šá€ºá‹</translation>
<translation id="5771720122942595109"><ph name="PERMISSION_1" /> ပိá€á€ºá€‘ားသည်</translation>
<translation id="5804241973901381774">á€á€½á€„့်ပြုá€á€»á€€á€ºá€™á€»á€¬á€¸</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">ဖွင့်ရန်</translation>
<translation id="6818926723028410516">စာရင်းမှ ရွေးရန်</translation>
<translation id="6864395892908308021">ဤစက်က NFC ဖá€á€ºáမရပါ</translation>
-<translation id="6910211073230771657">ဖျက်ပြီး</translation>
<translation id="6912998170423641340">ကလစ်ဘုá€á€ºá€›á€¾á€­ စာနှင့် ပုံများအား မကြည့်နိုင်ရန် á€á€˜á€ºá€†á€­á€¯á€€á€ºá€™á€»á€¬á€¸á€€á€­á€¯ ပိá€á€ºá€•á€«</translation>
<translation id="6945221475159498467">ရွေးရန်</translation>
<translation id="6965382102122355670">OK</translation>
+<translation id="6981982820502123353">ရယူအသုံးá€á€»á€”ိုင်မှု</translation>
<translation id="6992289844737586249">ဆိုက်များကို သင့်မိုá€á€›á€­á€¯á€–ုန်းအား အသုံးပြုá€á€½á€„့်မပေးမီ ဦးစွာမေးမြန်းပါ (အကြံပြုထားသည်)</translation>
<translation id="7000754031042624318">Android ဆက်á€á€„်များá€á€½á€„် ပိá€á€ºá€‘ားသည်</translation>
<translation id="7016516562562142042">လက်ရှိရှာ​ဖွေမှု အင်ဂျင်အá€á€½á€€á€º á€á€½á€„့်ပြုထားသည်</translation>
+<translation id="702463548815491781">TalkBack သို့မဟုá€á€º 'á€á€œá€¯á€á€ºá€¡á€žá€¯á€¶á€¸á€•á€¼á€¯á€á€½á€„့်' ဖွင့်ထားသည့်အá€á€« အကြံပြုသည်</translation>
<translation id="7053983685419859001">ပိá€á€ºá€†á€­á€¯á€·á€›á€”်</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1 á€á€¯ ရွေးထားသည်}other{# á€á€¯ ရွေးထားသည်}}</translation>
-<translation id="7070090581017165256">ဤá€á€˜á€ºá€†á€­á€¯á€€á€ºá€¡á€€á€¼á€±á€¬á€„်း</translation>
<translation id="7087918508125750058"><ph name="ITEM_COUNT" /> á€á€¯ ရွေးထားသည်ዠမျက်နှာပြင်á ထိပ်နားá€á€½á€„် ရွေးá€á€»á€šá€ºá€…ရာများ ရှိသည်</translation>
<translation id="7141896414559753902">ပေါ့ပ်အပ်နှင့် á€á€…်ဆင့်ပြန်ညွှန်á€á€»á€€á€ºá€™á€»á€¬á€¸á€€á€­á€¯ မဖော်ပြနိုင်စေရန် á€á€˜á€ºá€†á€­á€¯á€€á€ºá€™á€»á€¬á€¸á€¡á€¬á€¸ ပိá€á€ºá€•á€« (အကြံပြုထားသည်)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> ကီလိုဘိုက်</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">á€á€˜á€ºá€†á€­á€¯á€€á€ºá€á€…်á€á€¯á€€ သင့်မိုက်ကရိုဖုန်းကို အသုံးပြုနေသည်</translation>
<translation id="7561196759112975576">အမြဲá€á€™á€ºá€¸</translation>
-<translation id="7572498721684305250">NFC စက်များကို á€á€­á€¯á€·á€œá€­á€¯á€€á€ºá€žá€Šá€·á€ºá€¡á€á€« အá€á€»á€€á€ºá€¡á€œá€€á€ºá€™á€»á€¬á€¸ ပို့á€á€¼á€„်းአလက်á€á€¶á€á€¼á€„်းá€á€­á€¯á€·á€™á€¾ á€á€˜á€ºá€†á€­á€¯á€€á€ºá€™á€»á€¬á€¸á€€á€­á€¯ ပိá€á€ºá€‘ားသည်</translation>
<translation id="757524316907819857">ကာကွယ်ထားသည့် အကြောင်းအရာများကို မပြသရန် á€á€˜á€ºá€†á€­á€¯á€€á€ºá€™á€»á€¬á€¸á€€á€­á€¯ ပိá€á€ºá€•á€«</translation>
+<translation id="7577900504646297215">စိá€á€ºá€á€„်စားမှုများ စီမံရန်</translation>
<translation id="7649070708921625228">အကူအညီ</translation>
<translation id="7658239707568436148">မလုပ်á€á€±á€¬á€·</translation>
<translation id="7781829728241885113">မနေ့က</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">á€á€»á€­á€á€ºá€†á€€á€ºá€™á€¾á€¯á€žá€Šá€º လုံá€á€¼á€¯á€¶á€•á€«á€žá€Šá€º</translation>
<translation id="8249310407154411074">အပေါ်ဆုံးသို့ ရွှေ့ပါ</translation>
<translation id="8261506727792406068">ဖျက်ရန်</translation>
+<translation id="8284326494547611709">စာá€á€”်းများ</translation>
<translation id="8300705686683892304">အက်ပ်က စီမံá€á€”့်á€á€½á€²á€‘ားသည်</translation>
<translation id="8324158725704657629">ထပ်မမေးပါနှင့်</translation>
<translation id="8372893542064058268">á€á€­á€€á€»á€žá€Šá€·á€ºá€†á€­á€¯á€€á€ºá€¡á€á€½á€€á€º နောက်á€á€¶á€á€½á€„်စင့်á€á€ºá€œá€¯á€•á€ºá€á€¼á€„်းကို á€á€½á€„့်ပြုပါ</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">á€á€»á€²á€·á€€á€¼á€Šá€·á€ºá€•á€«</translation>
<translation id="8921772741368021346"><ph name="POSITION" /> / <ph name="DURATION" /></translation>
<translation id="8926666909099850184">ဤစက်အá€á€½á€€á€º NFC ကို ပိá€á€ºá€‘ားသည်ዠ<ph name="BEGIN_LINK" />Android ဆက်á€á€„်များ<ph name="END_LINK" /> ထဲá€á€½á€„် áŽá€„်းကို ဖွင့်ပါá‹</translation>
+<translation id="8928445016601307354">á€á€˜á€ºá€†á€­á€¯á€€á€ºá€™á€»á€¬á€¸á€¡á€¬á€¸ NFC စက်ပစ္စည်းများရှိ အá€á€»á€€á€ºá€¡á€œá€€á€ºá€™á€»á€¬á€¸á€€á€­á€¯ ကြည့်á€á€½á€„့်နှင့် ပြောင်းလဲá€á€½á€„့် ပိá€á€ºá€›á€”်</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">အá€á€»á€­á€¯á€·á€á€˜á€ºá€†á€­á€¯á€€á€ºá€™á€»á€¬á€¸á€¡á€á€½á€€á€º ကွá€á€ºá€€á€®á€¸á€™á€»á€¬á€¸á€€á€­á€¯ ပိá€á€ºá€†á€­á€¯á€·á€žá€Šá€ºá‹</translation>
<translation id="8959122750345127698">သွားလာမှုပြလမ်းညွှန်ဆီသို့ မရောက်နိုင်ပါ- <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ne.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ne.xtb
index d28a78b03c5..0c2b0505c9b 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ne.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ne.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">साइट <ph name="SITE_NAME" /> थपियो</translation>
<translation id="1383876407941801731">खोजà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="1384959399684842514">डाउनलोड रोकिà¤à¤•à¥‹ छ</translation>
+<translation id="1409426117486808224">खà¥à¤²à¤¾ टà¥à¤¯à¤¾à¤¬à¤¹à¤°à¥‚का लागि सरलीकृत दृशà¥à¤¯</translation>
<translation id="1415402041810619267">URL छोटो बनाइयो</translation>
<translation id="1446450296470737166">MIDI डिभाइसहरूको पूरà¥à¤£ नियनà¥à¤¤à¥à¤°à¤£à¤²à¤¾à¤ˆ अनà¥à¤®à¤¤à¤¿ दिनà¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="1620510694547887537">कà¥à¤¯à¤¾à¤®à¥‡à¤°à¤¾</translation>
@@ -30,7 +31,7 @@
<translation id="1779089405699405702">छविको डिकोडर</translation>
<translation id="1818308510395330587"><ph name="APP_NAME" /> लाई AR पà¥à¤°à¤¯à¥‹à¤— गरà¥à¤¨ दिन <ph name="BEGIN_LINK" />Android का सेटिङ<ph name="END_LINK" />मा गई कà¥à¤¯à¤¾à¤®à¥‡à¤°à¤¾ पनि अन गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥à¥¤</translation>
<translation id="1864927262126810325"><ph name="SOURCE_NAME" /> बाट पà¥à¤°à¤¾à¤ªà¥à¤¤ जानकारी</translation>
-<translation id="1887786770086287077">यो डिभाइसको सà¥à¤¥à¤¾à¤¨à¤®à¤¾à¤¥à¤¿à¤•à¥‹ पहà¥à¤à¤š निषà¥à¤•à¥à¤°à¤¿à¤¯ छ। <ph name="BEGIN_LINK" />Android का सेटिङहरू<ph name="END_LINK" /> मा गई यसलाई सकà¥à¤°à¤¿à¤¯ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥à¥¤</translation>
+<translation id="1887786770086287077">यो डिभाइसको सà¥à¤¥à¤¾à¤¨à¤®à¤¾à¤¥à¤¿à¤•à¥‹ पहà¥à¤à¤š निषà¥à¤•à¥à¤°à¤¿à¤¯ छ। <ph name="BEGIN_LINK" />Android का सेटिङहरू<ph name="END_LINK" /> मा गई यसलाई अन गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥à¥¤</translation>
<translation id="1919345977826869612">विजà¥à¤žà¤¾à¤ªà¤¨à¤¹à¤°à¥‚</translation>
<translation id="1919950603503897840">समà¥à¤ªà¤°à¥à¤•à¤¹à¤°à¥‚ चयन गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="1923695749281512248"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> / <ph name="FILE_SIZE_WITH_UNITS" /></translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">कà¥à¤•à¥€à¤¹à¤°à¥‚लाई अनà¥à¤®à¤¤à¤¿ दिनà¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="2228071138934252756"><ph name="APP_NAME" /> लाई आफà¥à¤¨à¥‹ कà¥à¤¯à¤¾à¤®à¥‡à¤°à¤¾ पà¥à¤°à¤¯à¥‹à¤— गरà¥à¤¨ दिन <ph name="BEGIN_LINK" />Android का सेटिङ<ph name="END_LINK" />मा गई कà¥à¤¯à¤¾à¤®à¥‡à¤°à¤¾ पनि अन गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥à¥¤</translation>
<translation id="2241634353105152135">à¤à¤•à¤ªà¤Ÿà¤• मातà¥à¤°</translation>
+<translation id="2253414712144136228"><ph name="NAME_OF_LIST_ITEM" /> हटाउनà¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="2289270750774289114">कà¥à¤¨à¥ˆ साइटले छेउछाउका बà¥à¤²à¥à¤Ÿà¥à¤¥ यनà¥à¤¤à¥à¤°à¤¹à¤°à¥‚ पतà¥à¤¤à¤¾ लगाउन खोजà¥à¤¦à¤¾ सोधà¥à¤¨à¥à¤¹à¥‹à¤¸à¥ (सिफारिस गरिà¤à¤•à¥‹)</translation>
<translation id="2315043854645842844">अपरेटिङ सिसà¥à¤Ÿà¤®à¤²à¥‡ कà¥à¤²à¤¾à¤‡à¤¨à¥à¤Ÿ साइड पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤°à¤•à¥‹ चयनलाई समरà¥à¤¥à¤¨ गरà¥à¤¦à¥ˆà¤¨à¥¤</translation>
+<translation id="2321958826496381788">तपाईंले आरामसà¤à¤— पढà¥à¤¨ सकà¥à¤¦à¤¾à¤¸à¤®à¥à¤® सà¥à¤²à¤¾à¤‡à¤¡à¤°à¤²à¤¾à¤ˆ तानà¥à¤¨à¥à¤¹à¥‹à¤¸à¥à¥¤ अनà¥à¤šà¥à¤›à¥‡à¤¦à¤®à¤¾ दोहोरो टà¥à¤¯à¤¾à¤ª गरेपछि पाठ कमà¥à¤¤à¥€à¤®à¤¾ पनि यतिको ठà¥à¤²à¥‹ देखिनà¥à¤ªà¤°à¥à¤›à¥¤</translation>
<translation id="2359808026110333948">जारी राखà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="2379925928934107488">Chrome मा अà¤à¤§à¥à¤¯à¤¾à¤°à¥‹ थिम पà¥à¤°à¤¯à¥‹à¤— गरिà¤à¤•à¤¾ बेला साइटहरूमा सकेसमà¥à¤® अà¤à¤§à¥à¤¯à¤¾à¤°à¥‹ थिम लागू गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
+<translation id="2387895666653383613">पाठ सà¥à¤•à¥‡à¤²à¤¿à¤™</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> à¤à¤®.बि.</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> र थप <ph name="NUM_MORE" /> सà¥à¤µà¤¿à¤§à¤¾à¤¸à¤®à¥à¤¬à¤¨à¥à¤§à¥€ अनà¥à¤®à¤¤à¤¿ दिइà¤à¤•à¥‹ छ}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> र थप <ph name="NUM_MORE" /> सà¥à¤µà¤¿à¤§à¤¾à¤¸à¤®à¥à¤¬à¤¨à¥à¤§à¥€ अनà¥à¤®à¤¤à¤¿ दिइà¤à¤•à¥‹ छ}}</translation>
<translation id="2434158240863470628">डाउनलोड समà¥à¤ªà¤¨à¥à¤¨ भयो <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -63,7 +67,7 @@
<translation id="2498359688066513246">मदà¥à¤¦à¤¤ र पà¥à¤°à¤¤à¤¿à¤•à¥à¤°à¤¿à¤¯à¤¾</translation>
<translation id="2501278716633472235">पछाडि जानà¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="2569468611847789653">{COOKIE_COUNT,plural, =1{१ कà¥à¤•à¥€à¤®à¤¾à¤¥à¤¿ रोक लगाइयो}other{# कà¥à¤•à¥€à¤¹à¤°à¥‚माथि रोक लगाइयो}}</translation>
-<translation id="2570922361219980984">यो डिभाइसको सà¥à¤¥à¤¾à¤¨à¤®à¤¾à¤¥à¤¿à¤•à¥‹ पहà¥à¤à¤š पनि निषà¥à¤•à¥à¤°à¤¿à¤¯ छ। <ph name="BEGIN_LINK" />Android का सेटिङहरू<ph name="END_LINK" /> मा गई यसलाई सकà¥à¤°à¤¿à¤¯ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥à¥¤</translation>
+<translation id="2570922361219980984">यो डिभाइसको सà¥à¤¥à¤¾à¤¨à¤®à¤¾à¤¥à¤¿à¤•à¥‹ पहà¥à¤à¤š पनि निषà¥à¤•à¥à¤°à¤¿à¤¯ छ। <ph name="BEGIN_LINK" />Android का सेटिङहरू<ph name="END_LINK" /> मा गई यसलाई अन गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥à¥¤</translation>
<translation id="257931822824936280">विसà¥à¤¤à¥ƒà¤¤ गरिà¤à¤•à¥‹ - संकà¥à¤·à¤¿à¤ªà¥à¤¤ पारà¥à¤¨ कà¥à¤²à¤¿à¤• गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="2586657967955657006">कà¥à¤²à¤¿à¤ªà¤¬à¥‹à¤°à¥à¤¡</translation>
<translation id="2597457036804169544">साइटहरूमा अà¤à¤§à¥à¤¯à¤¾à¤°à¥‹ थिम लागू नगरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">जानकारी देखाउनà¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="3123473560110926937">केही साइटका हकमा रोक लगाइà¤à¤•à¥‹ छ</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> भणà¥à¤¡à¤¾à¤°à¤£ डेटा</translation>
+<translation id="3203366800380907218">वेबबाट पà¥à¤°à¤¾à¤ªà¥à¤¤</translation>
<translation id="321187648315454507"><ph name="APP_NAME" /> लाई तपाईंलाई सूचनाहरू पठाउन दिन <ph name="BEGIN_LINK" />Android का सेटिङ<ph name="END_LINK" />मा गई सूचनाहरू पनि अन गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥à¥¤</translation>
<translation id="3227137524299004712">माइकà¥à¤°à¥‹à¤«à¥‹à¤¨</translation>
<translation id="3277252321222022663">साइटहरूलाई सेनà¥à¤¸à¤°à¤¹à¤°à¥‚माथि पहà¥à¤à¤š राखà¥à¤¨à¥‡ अनà¥à¤®à¤¤à¤¿ दिनà¥à¤¹à¥‹à¤¸à¥ (सिफारिस गरिà¤à¤•à¥‹)</translation>
@@ -110,15 +115,19 @@
<translation id="3835233591525155343">तपाईंको डिभाइसको पà¥à¤°à¤¯à¥‹à¤—</translation>
<translation id="385051799172605136">पछाडि जानà¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="3859306556332390985">अगाडि खोजà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
+<translation id="3895926599014793903">जूम सकà¥à¤·à¤® गरà¥à¤¨ दबाब दिनà¥</translation>
<translation id="3955193568934677022">साइटहरूलाई सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ सामगà¥à¤°à¥€ पà¥à¤²à¥‡ गरà¥à¤¨à¥‡ अनà¥à¤®à¤¤à¤¿ दिनà¥à¤¹à¥‹à¤¸à¥ (सिफारिस गरिà¤à¤•à¥‹)</translation>
<translation id="3967822245660637423">डाउनलोड पूरà¥à¤£ भयो</translation>
<translation id="3987993985790029246">लिंक पà¥à¤°à¤¤à¤¿à¤²à¤¿à¤ªà¤¿ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> / ?</translation>
<translation id="4002066346123236978">शीरà¥à¤·à¤•</translation>
<translation id="4008040567710660924">कà¥à¤¨à¥ˆ खास साइटमा कà¥à¤•à¥€à¤¹à¤°à¥‚लाई अनà¥à¤®à¤¤à¤¿ दिनà¥à¤¹à¥‹à¤¸à¥à¥¤</translation>
+<translation id="4040330681741629921">साइट सरलीकृत भà¥à¤¯à¥‚मा देखाउन मिलà¥à¤¨à¥‡ भà¤à¤®à¤¾ उकà¥à¤¤ कà¥à¤°à¤¾à¤•à¤¾ बारेमा सूचना पठाइयोसà¥</translation>
<translation id="4046123991198612571">अरà¥à¤•à¥‹ टà¥à¤°à¥à¤¯à¤¾à¤•</translation>
+<translation id="4149994727733219643">वेब पृषà¥à¤ à¤¹à¤°à¥‚का लागि सरलीकृत दृशà¥à¤¯</translation>
<translation id="4165986682804962316">साइट सेटिङहरू</translation>
-<translation id="4200726100658658164">सà¥à¤¥à¤¾à¤¨à¤¸à¤®à¥à¤¬à¤¨à¥à¤§à¥€ सेटिङ खोलà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
+<translation id="4194328954146351878">साइटहरूलाई NFC डिभाइसमा भà¤à¤•à¤¾ जानकारी हेरà¥à¤¨à¥‡ र ती जानकारी परिवरà¥à¤¤à¤¨ गरà¥à¤¨à¥‡ अनà¥à¤®à¤¤à¤¿ दिनà¥à¤…घि मलाई सोधियोसॠ(सिफारिस गरिà¤à¤•à¥‹)</translation>
+<translation id="4200726100658658164">लोकेसन सेटिङ खोलà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="4226663524361240545">सूचनाहरूले गरà¥à¤¦à¤¾ यनà¥à¤¤à¥à¤° कमà¥à¤ªà¤¨ गरà¥à¤¨ सकà¥à¤›</translation>
<translation id="4259722352634471385">नेभिगेशन रोकियो: <ph name="URL" /></translation>
<translation id="4278390842282768270">अनà¥à¤®à¤¤à¤¿ पà¥à¤°à¤¾à¤ªà¥à¤¤</translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">विसà¥à¤¤à¥ƒà¤¤ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="4336434711095810371">सबै डेटा मेटाउनà¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="4402755511846832236">तपाईं यो डिभाइस चलाउà¤à¤¦à¥ˆ हà¥à¤¨à¥à¤¹à¥à¤¨à¥à¤› कि हà¥à¤¨à¥à¤¹à¥à¤¨à¥à¤¨ भनà¥à¤¨à¥‡ कà¥à¤°à¤¾ साइटहरूलाई थाहा पाउन नदिनà¥à¤¹à¥‹à¤¸à¥</translation>
+<translation id="4428065317363009941">विजà¥à¤žà¤¾à¤ªà¤¨à¤•à¥‹ परà¥à¤¸à¤¨à¤²à¤¾à¤‡à¤œà¥‡à¤¸à¤¨</translation>
<translation id="4434045419905280838">पपअप तथा रिडिरेकà¥à¤Ÿà¤¹à¤°à¥‚</translation>
<translation id="445467742685312942">साइटहरूलाई संरकà¥à¤·à¤¿à¤¤ सामगà¥à¤°à¥€ पà¥à¤²à¥‡ गरà¥à¤¨à¥‡ अनà¥à¤®à¤¤à¤¿ दिनà¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="4468959413250150279">निशà¥à¤šà¤¿à¤¤ साइटको धà¥à¤µà¤¨à¤¿ मà¥à¤¯à¥à¤Ÿ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥à¥¤</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">यो विकलà¥à¤ª सà¥à¤•à¥à¤°à¤¿à¤¨à¤•à¥‹ सिरान छेउमा उपलबà¥à¤§ छ</translation>
<translation id="5197729504361054390">तपाईंले चयन गरà¥à¤¨à¥‡ समà¥à¤ªà¤°à¥à¤•à¤¹à¤°à¥‚ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> सà¤à¤— आदान पà¥à¤°à¤¦à¤¾à¤¨ गरिने छनà¥à¥¤</translation>
<translation id="5216942107514965959">पछिलà¥à¤²à¥‹ पटक आज खोलिà¤à¤•à¥‹</translation>
+<translation id="5264323282659631142">'<ph name="CHIP_LABEL" />' हटाउनà¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="528192093759286357">पूरà¥à¤£ सà¥à¤•à¥à¤°à¤¿à¤¨à¤¬à¤¾à¤Ÿ बाहिर निसà¥à¤•à¤¨à¤•à¤¾ लागि शीरà¥à¤·à¤¬à¤¾à¤Ÿ तानेर पछाडि बटनलाई छà¥à¤¨à¥à¤¹à¥‹à¤¸à¥à¥¤</translation>
<translation id="5300589172476337783">देखाउनà¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="5301954838959518834">ठिक छ, बà¥à¤à¥‡à¤</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">यस कारà¥à¤¯à¤²à¥‡ साइटहरूले भणà¥à¤¡à¤¾à¤°à¤£ गरेका <ph name="DATASIZE" /> डेटा तथा कà¥à¤•à¥€à¤¹à¤°à¥‚ मेटाउने छ।</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(+ १ थप)}other{(+ # थप)}}</translation>
<translation id="5403592356182871684">नामहरू</translation>
+<translation id="5412236728747081950">यो साइटले तपाईंलाई थप सानà¥à¤¦à¤°à¥à¤­à¤¿à¤• विजà¥à¤žà¤¾à¤ªà¤¨à¤¹à¤°à¥‚ देखाउने पà¥à¤°à¤¯à¥‹à¤œà¤¨à¤•à¤¾ लागि तपाईंले Chrome मा तोकेका रà¥à¤šà¤¿à¤¹à¤°à¥‚ पà¥à¤°à¤¾à¤ªà¥à¤¤ गरà¥à¤›</translation>
<translation id="5438097262470833822">तपाईंले यो विकलà¥à¤ª रोजà¥à¤¨à¥à¤­à¤¯à¥‹ भने <ph name="WEBSITE" /> लाई दिइà¤à¤•à¤¾ अनà¥à¤®à¤¤à¤¿à¤¹à¤°à¥‚ रिसेट गरिने छनà¥</translation>
<translation id="5489227211564503167"><ph name="TOTAL_TIME" /> मधà¥à¤¯à¥‡ <ph name="ELAPSED_TIME" /> समय बितà¥à¤¯à¥‹à¥¤</translation>
<translation id="5494752089476963479">हसà¥à¤¤à¤•à¥à¤·à¥‡à¤ªà¤•à¤¾à¤°à¥€ वा भà¥à¤°à¤¾à¤®à¤• विजà¥à¤žà¤¾à¤ªà¤¨ देखाउने साइटका विजà¥à¤žà¤¾à¤ªà¤¨à¤¹à¤°à¥‚लाई रोक लगाउनà¥à¤¹à¥‹à¤¸à¥</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">पà¥à¤¨: लोड गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="5596627076506792578">अनà¥à¤¯ विकलà¥à¤ªà¤¹à¤°à¥‚</translation>
<translation id="5649053991847567735">सà¥à¤µà¤šà¤¾à¤²à¤¿à¤¤ डाउनलोडहरू</translation>
+<translation id="5668404140385795438">जूमिङ इनलाई रोकà¥à¤¨ वेबसाइटको अनà¥à¤°à¥‹à¤§à¤²à¤¾à¤ˆ ओभरराइड गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="5677928146339483299">बà¥à¤²à¤• गरिà¤à¤•à¥‹ छ</translation>
<translation id="5689516760719285838">सà¥à¤¥à¤¾à¤¨</translation>
<translation id="5690795753582697420">Android का सेटिङमा कà¥à¤¯à¤¾à¤®à¥‡à¤°à¤¾ बनà¥à¤¦ गरिà¤à¤•à¥‹ छ</translation>
-<translation id="5710871682236653961">तपाईंले NFC यनà¥à¤¤à¥à¤°à¤¹à¤°à¥‚मा टà¥à¤¯à¤¾à¤ª गरà¥à¤¦à¤¾ साइटहरूलाई जानकारी पठाउने र पà¥à¤°à¤¾à¤ªà¥à¤¤ गरà¥à¤¨à¥‡ अनà¥à¤®à¤¤à¤¿ दिनà¥à¤…घि सोधà¥à¤¨à¥à¤¹à¥‹à¤¸à¥ (सिफारिस गरिà¤à¤•à¥‹)</translation>
<translation id="5719847187258001597">यस कारà¥à¤¯à¤²à¥‡ <ph name="ORIGIN" /> ले वा यसको à¤à¤ªà¤²à¥‡ तपाईंको होम सà¥à¤•à¥à¤°à¤¿à¤¨à¤®à¤¾ भणà¥à¤¡à¤¾à¤°à¤£ गरेका सबै डेटा र कà¥à¤•à¥€à¤¹à¤°à¥‚ मेटाउने छ।</translation>
<translation id="5771720122942595109"><ph name="PERMISSION_1" /> बà¥à¤²à¤• गरिà¤à¤•à¥‹ छ</translation>
<translation id="5804241973901381774">अनà¥à¤®à¤¤à¤¿à¤¹à¤°à¥‚</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">पà¥à¤²à¥‡ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="6818926723028410516">वसà¥à¤¤à¥à¤¹à¤°à¥‚ छनाैट गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="6864395892908308021">यस यनà¥à¤¤à¥à¤°à¤²à¥‡ NFC पढà¥à¤¨ सकà¥à¤¦à¥ˆà¤¨</translation>
-<translation id="6910211073230771657">मेटाइà¤à¤•à¥‹</translation>
<translation id="6912998170423641340">साइटहरूलाई कà¥à¤²à¤¿à¤ªà¤¬à¥‹à¤°à¥à¤¡à¤•à¤¾ पाठ तथा फोटो पढà¥à¤¨à¤¬à¤¾à¤Ÿ रोक लगाउनà¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="6945221475159498467">चयन गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="6965382102122355670">ठिक छ</translation>
+<translation id="6981982820502123353">पहà¥à¤à¤š</translation>
<translation id="6992289844737586249">साइटहरूलाई तपाईà¤à¤•à¥‹ माइकà¥à¤°à¥‹à¤«à¥‹à¤¨ पà¥à¤°à¤¯à¥‹à¤— गरà¥à¤¨ अनà¥à¤®à¤¤à¤¿ दिनà¥à¤­à¤¨à¥à¤¦à¤¾ पहिले तपाईà¤à¤²à¤¾à¤ˆ सोधà¥à¤¨à¥‡ (सिफारिस गरिà¤à¤•à¥‹)</translation>
<translation id="7000754031042624318">Android का सेटिङहरूमा अनà¥à¤®à¤¤à¤¿ निषà¥à¤•à¥à¤°à¤¿à¤¯ पारिà¤à¤•à¥‹ छ</translation>
<translation id="7016516562562142042">हालको खोज इनà¥à¤œà¤¿à¤¨à¤•à¤¾ लागि अनà¥à¤®à¤¤à¤¿ दिइà¤à¤•à¥‹</translation>
+<translation id="702463548815491781">TalkBack वा पहà¥à¤à¤š सà¥à¤µà¤¿à¤š गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥ नामक सà¥à¤µà¤¿à¤§à¤¾ सकà¥à¤°à¤¿à¤¯ हà¥à¤à¤¦à¤¾ मातà¥à¤° सिफारिस गरिनà¥à¤›</translation>
<translation id="7053983685419859001">रोकà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{१ चयन गरियो}other{# चयन गरिà¤}}</translation>
-<translation id="7070090581017165256">यो साइटका बारेमा जानकारी</translation>
<translation id="7087918508125750058"><ph name="ITEM_COUNT" /> चयन गरिà¤à¥¤ विकलà¥à¤ªà¤¹à¤°à¥‚ सà¥à¤•à¥à¤°à¤¿à¤¨à¤•à¥‹ शीरà¥à¤·à¤­à¤¾à¤—को नजिकै उपलबà¥à¤§ छनà¥</translation>
<translation id="7141896414559753902">साइटहरूलाई पपअपहरू देखाउन र रिडिरेकà¥à¤Ÿ गरà¥à¤¨à¤¬à¤¾à¤Ÿ रोकà¥à¤¨à¥à¤¹à¥‹à¤¸à¥ (सिफारिस गरिà¤à¤•à¥‹)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> के.बि.</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">कà¥à¤¨à¥ˆ साइटले तपाईंको माइकà¥à¤°à¥‹à¤«à¥‹à¤¨ पà¥à¤°à¤¯à¥‹à¤— गरà¥à¤¦à¥ˆ छ</translation>
<translation id="7561196759112975576">सधैं</translation>
-<translation id="7572498721684305250">तपाईंले NFC यनà¥à¤¤à¥à¤°à¤¹à¤°à¥‚मा टà¥à¤¯à¤¾à¤ª गरà¥à¤¦à¤¾ साइटहरूलाई जानकारी पठाउन र पà¥à¤°à¤¾à¤ªà¥à¤¤ गरà¥à¤¨ रोक लगाउनà¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="757524316907819857">साइटहरूलाई संरकà¥à¤·à¤¿à¤¤ सामगà¥à¤°à¥€ पà¥à¤²à¥‡ गरà¥à¤¨ रोक लगाउनà¥à¤¹à¥‹à¤¸à¥</translation>
+<translation id="7577900504646297215">रà¥à¤šà¤¿à¤¹à¤°à¥‚ वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¨ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="7649070708921625228">मदà¥à¤¦à¤¤</translation>
<translation id="7658239707568436148">रदà¥à¤¦ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="7781829728241885113">हिजो</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">जडान सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ छ</translation>
<translation id="8249310407154411074">शीरà¥à¤·à¤­à¤¾à¤—मा सारà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="8261506727792406068">मेटà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
+<translation id="8284326494547611709">कà¥à¤¯à¤¾à¤ªà¥à¤¸à¤¨</translation>
<translation id="8300705686683892304">अनà¥à¤ªà¥à¤°à¤¯à¥‹à¤—ले वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¨ गरेको</translation>
<translation id="8324158725704657629">फेरि नसोधियोसà¥</translation>
<translation id="8372893542064058268">कà¥à¤¨à¥ˆ विशेष साइटलाई पृषà¥à¤ à¤­à¥‚मिमा सिंक गरà¥à¤¨à¥‡ सà¥à¤µà¤¿à¤§à¤¾à¤•à¥‹ पà¥à¤°à¤¯à¥‹à¤— गरà¥à¤¨à¥‡ अनà¥à¤®à¤¤à¤¿ दिनà¥à¤¹à¥‹à¤¸à¥à¥¤</translation>
@@ -320,7 +333,8 @@
<translation id="8847988622838149491">USB</translation>
<translation id="8903921497873541725">जà¥à¤® इन</translation>
<translation id="8921772741368021346"><ph name="POSITION" />/<ph name="DURATION" /></translation>
-<translation id="8926666909099850184">यो डिभाइसमा NFC निषà¥à¤•à¥à¤°à¤¿à¤¯ पारिà¤à¤•à¥‹ छ। <ph name="BEGIN_LINK" />Android का सेटिङ<ph name="END_LINK" /> मा गई यसलाई सकà¥à¤°à¤¿à¤¯ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥à¥¤</translation>
+<translation id="8926666909099850184">यो डिभाइसमा NFC निषà¥à¤•à¥à¤°à¤¿à¤¯ पारिà¤à¤•à¥‹ छ। <ph name="BEGIN_LINK" />Android का सेटिङ<ph name="END_LINK" /> मा गई यसलाई अन गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥à¥¤</translation>
+<translation id="8928445016601307354">साइटहरूलाई NFC डिभाइसमा भà¤à¤•à¤¾ जानकारी हेरà¥à¤¨ र ती जानकारी परिवरà¥à¤¤à¤¨ गरà¥à¤¨à¤¬à¤¾à¤Ÿ बà¥à¤²à¤• गरियोसà¥</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">कà¥à¤¨à¥ˆ खास साइटमा कà¥à¤•à¥€à¤¹à¤°à¥‚लाई रोक लगाउनà¥à¤¹à¥‹à¤¸à¥à¥¤</translation>
<translation id="8959122750345127698">नेभिगेशन पहà¥à¤à¤šà¤¯à¥‹à¤—à¥à¤¯ छैन: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_nl.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_nl.xtb
index 44d60ed2e10..82010b53245 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_nl.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_nl.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">Site <ph name="SITE_NAME" /> toegevoegd</translation>
<translation id="1383876407941801731">Zoeken</translation>
<translation id="1384959399684842514">Download onderbroken</translation>
+<translation id="1409426117486808224">Vereenvoudigde weergave voor geopende tabbladen</translation>
<translation id="1415402041810619267">URL afgekapt</translation>
<translation id="1446450296470737166">Volledig beheer van MIDI-apparaten toestaan</translation>
<translation id="1620510694547887537">Camera</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">Cookies toestaan</translation>
<translation id="2228071138934252756">Als je <ph name="APP_NAME" /> toegang wilt geven tot je camera, moet je de camera ook aanzetten via de <ph name="BEGIN_LINK" />Android-instellingen<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Slechts één keer</translation>
+<translation id="2253414712144136228"><ph name="NAME_OF_LIST_ITEM" /> verwijderen</translation>
<translation id="2289270750774289114">Vragen wanneer een site Bluetooth-apparaten in de buurt wilt detecteren (aanbevolen)</translation>
<translation id="2315043854645842844">Certificaatselectie aan clientzijde wordt niet ondersteund door het besturingssysteem.</translation>
+<translation id="2321958826496381788">Sleep de schuifknop tot je deze tekst prettig kunt lezen. De tekst moet minimaal deze grootte hebben nadat je op een alinea hebt gedubbeltikt.</translation>
<translation id="2359808026110333948">Doorgaan</translation>
<translation id="2379925928934107488">Donker thema zo mogelijk toepassen op sites als Chrome het donkere thema gebruikt</translation>
+<translation id="2387895666653383613">Tekstgrootte</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> en nog <ph name="NUM_MORE" /> toegestaan}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> en nog <ph name="NUM_MORE" /> toegestaan}}</translation>
<translation id="2434158240863470628">Download voltooid <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">Informatie bekijken</translation>
<translation id="3123473560110926937">Geblokkeerd op bepaalde sites</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> opgeslagen gegevens</translation>
+<translation id="3203366800380907218">Van internet</translation>
<translation id="321187648315454507">Als je wilt dat <ph name="APP_NAME" /> je meldingen stuurt, moet je meldingen ook aanzetten via de <ph name="BEGIN_LINK" />Android-instellingen<ph name="END_LINK" />.</translation>
<translation id="3227137524299004712">Microfoon</translation>
<translation id="3277252321222022663">Sites toegang geven tot sensoren (aanbevolen)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">Je apparaatgebruik</translation>
<translation id="385051799172605136">Terug</translation>
<translation id="3859306556332390985">Vooruit zoeken</translation>
+<translation id="3895926599014793903">Zoom verplicht aan</translation>
<translation id="3955193568934677022">Toestaan dat sites beschermde content afspelen (aanbevolen)</translation>
<translation id="3967822245660637423">Downloaden voltooid</translation>
<translation id="3987993985790029246">Link kop.</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> van ?</translation>
<translation id="4002066346123236978">Titel</translation>
<translation id="4008040567710660924">Cookies voor een specifieke site toestaan.</translation>
+<translation id="4040330681741629921">Melding krijgen als een site kan worden getoond in de vereenvoudigde weergave</translation>
<translation id="4046123991198612571">Volgend nummer</translation>
+<translation id="4149994727733219643">Vereenvoudigde weergave voor webpagina's</translation>
<translation id="4165986682804962316">Site-instellingen</translation>
+<translation id="4194328954146351878">Vragen voordat sites informatie op NFC-apparaten mogen zien en wijzigen (aanbevolen)</translation>
<translation id="4200726100658658164">Locatie-instellingen openen</translation>
<translation id="4226663524361240545">Het apparaat kan trillen bij meldingen</translation>
<translation id="4259722352634471385">Navigatie is geblokkeerd: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">Uitvouwen</translation>
<translation id="4336434711095810371">Alle gegevens wissen</translation>
<translation id="4402755511846832236">Voorkomen dat sites weten wanneer je dit apparaat actief gebruikt</translation>
+<translation id="4428065317363009941">Advertentiepersonalisatie</translation>
<translation id="4434045419905280838">Pop-ups en omleidingen</translation>
<translation id="445467742685312942">Sites toestaan om beschermde content af te spelen</translation>
<translation id="4468959413250150279">Geluid uitzetten voor een specifieke site.</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">Optie beschikbaar boven aan het scherm</translation>
<translation id="5197729504361054390">De contacten die je selecteert, worden gedeeld met <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />.</translation>
<translation id="5216942107514965959">Laatst bezocht: vandaag</translation>
+<translation id="5264323282659631142">'<ph name="CHIP_LABEL" />' verwijderen</translation>
<translation id="528192093759286357">Sleep vanaf de bovenkant en tik op de knop Terug om het volledige scherm te sluiten.</translation>
<translation id="5300589172476337783">Tonen</translation>
<translation id="5301954838959518834">OK, begrepen</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">Hiermee wis je <ph name="DATASIZE" /> aan gegevens en cookies die zijn opgeslagen door sites.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(en nog 1)}other{(en nog #)}}</translation>
<translation id="5403592356182871684">Namen</translation>
+<translation id="5412236728747081950">Deze site krijgt je interesses van Chrome zodat de site je relevantere advertenties kan laten zien</translation>
<translation id="5438097262470833822">Met deze keuze reset je de rechten voor <ph name="WEBSITE" /></translation>
<translation id="5489227211564503167">De verstreken tijd is <ph name="ELAPSED_TIME" /> van <ph name="TOTAL_TIME" />.</translation>
<translation id="5494752089476963479">Advertenties blokkeren op sites die opdringerige of misleidende advertenties bekijken</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">Opnieuw laden</translation>
<translation id="5596627076506792578">Meer opties</translation>
<translation id="5649053991847567735">Automatische downloads</translation>
+<translation id="5668404140385795438">Negeer verzoek van website om inzoomen te voorkomen</translation>
<translation id="5677928146339483299">Geblokkeerd</translation>
<translation id="5689516760719285838">Locatie</translation>
<translation id="5690795753582697420">Camera staat uit in de Android-instellingen</translation>
-<translation id="5710871682236653961">Vragen voordat sites informatie mogen sturen en ontvangen als je NFC-apparaten tegen elkaar houdt (aanbevolen)</translation>
<translation id="5719847187258001597">Hiermee wis je alle gegevens en cookies die zijn opgeslagen door <ph name="ORIGIN" /> of de bijbehorende app op je startscherm.</translation>
<translation id="5771720122942595109"><ph name="PERMISSION_1" /> geblokkeerd</translation>
<translation id="5804241973901381774">Rechten</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">Spelen</translation>
<translation id="6818926723028410516">Items selecteren</translation>
<translation id="6864395892908308021">Dit apparaat kan NFC niet lezen</translation>
-<translation id="6910211073230771657">Verwijderd</translation>
<translation id="6912998170423641340">Voorkomen dat sites tekst en afbeeldingen vanaf het klembord kunnen lezen</translation>
<translation id="6945221475159498467">Selecteren</translation>
<translation id="6965382102122355670">OK</translation>
+<translation id="6981982820502123353">Toegankelijkheid</translation>
<translation id="6992289844737586249">Eerst vragen voordat sites je microfoon mogen gebruiken (aanbevolen)</translation>
<translation id="7000754031042624318">Uitgezet in Android-instellingen</translation>
<translation id="7016516562562142042">Toegestaan voor huidige zoekmachine</translation>
+<translation id="702463548815491781">Aanbevolen als TalkBack of Toegang via schakelaar aanstaan</translation>
<translation id="7053983685419859001">Blokkeren</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1 geselecteerd}other{# geselecteerd}}</translation>
-<translation id="7070090581017165256">Over deze site</translation>
<translation id="7087918508125750058"><ph name="ITEM_COUNT" /> geselecteerd. Opties beschikbaar bovenaan het scherm.</translation>
<translation id="7141896414559753902">Sites niet toestaan pop-ups te bekijken en omleidingen uit te voeren (aanbevolen)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> KB</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">Een site gebruikt de microfoon</translation>
<translation id="7561196759112975576">Altijd</translation>
-<translation id="7572498721684305250">Voorkomen dat sites informatie sturen en ontvangen als je NFC-apparaten tegen elkaar houdt</translation>
<translation id="757524316907819857">Blokkeren dat sites beschermde content kunnen afspelen</translation>
+<translation id="7577900504646297215">Interesses beheren</translation>
<translation id="7649070708921625228">Hulp</translation>
<translation id="7658239707568436148">Annuleren</translation>
<translation id="7781829728241885113">Gisteren</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">Verbinding is beveiligd</translation>
<translation id="8249310407154411074">Bovenaan zetten</translation>
<translation id="8261506727792406068">Verwijderen</translation>
+<translation id="8284326494547611709">Ondertiteling</translation>
<translation id="8300705686683892304">Beheerd door app</translation>
<translation id="8324158725704657629">Niet meer vragen</translation>
<translation id="8372893542064058268">Synchronisatie op de achtergrond toestaan voor een specifieke site.</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">Inzoomen</translation>
<translation id="8921772741368021346"><ph name="POSITION" />/<ph name="DURATION" /></translation>
<translation id="8926666909099850184">NFC staat uit voor dit apparaat. Zet deze functie aan via de <ph name="BEGIN_LINK" />Android-instellingen<ph name="END_LINK" />.</translation>
+<translation id="8928445016601307354">Voorkomen dat sites informatie op NFC-apparaten kunnen zien en wijzigen</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">Cookies voor een specifieke site blokkeren.</translation>
<translation id="8959122750345127698">Navigatie is onbereikbaar: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_no.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_no.xtb
index d2b956f2993..f712731eae0 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_no.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_no.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">Nettstedet <ph name="SITE_NAME" /> er lagt til</translation>
<translation id="1383876407941801731">Søk</translation>
<translation id="1384959399684842514">Nedlastingen er satt på pause</translation>
+<translation id="1409426117486808224">Forenklet visning for åpne faner</translation>
<translation id="1415402041810619267">Nettadressen er avkortet</translation>
<translation id="1446450296470737166">Full kontroll over MIDI-enheter</translation>
<translation id="1620510694547887537">Kamera</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">Tillat informasjonskapsler</translation>
<translation id="2228071138934252756">For å gi <ph name="APP_NAME" /> tilgang til kameraet må du også slå på kameraet i <ph name="BEGIN_LINK" />Android-innstillingene<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Bare én gang</translation>
+<translation id="2253414712144136228">Fjern <ph name="NAME_OF_LIST_ITEM" /></translation>
<translation id="2289270750774289114">Spør når nettsteder vil oppdage Bluetooth-enheter i nærheten (anbefales)</translation>
<translation id="2315043854645842844">Operativsystemet har ikke støtte for sertifikatvalg på klientsiden.</translation>
+<translation id="2321958826496381788">Dra glidebryteren til du kan lese dette uten problemer. Når du har dobbelttrykket på et avsnitt, bør teksten være minst like stor som dette.</translation>
<translation id="2359808026110333948">Fortsett</translation>
<translation id="2379925928934107488">Bruk mørkt tema på nettsteder når Chrome bruker mørkt tema, når det er mulig</translation>
+<translation id="2387895666653383613">Tekstskalering</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> og <ph name="NUM_MORE" /> til er tillatt}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> og <ph name="NUM_MORE" /> til er tillatt}}</translation>
<translation id="2434158240863470628">Nedlasting fullført <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">Vis informasjon</translation>
<translation id="3123473560110926937">Blokkert på enkelte nettsteder</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> lagrede data</translation>
+<translation id="3203366800380907218">Fra nettet</translation>
<translation id="321187648315454507">For at <ph name="APP_NAME" /> skal kunne sende deg varsler, må du også slå på varsler i <ph name="BEGIN_LINK" />Android-innstillingene<ph name="END_LINK" />.</translation>
<translation id="3227137524299004712">Mikrofon</translation>
<translation id="3277252321222022663">Gi nettsteder tilgang til sensorer (anbefalt)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">Enhetsbruken din</translation>
<translation id="385051799172605136">Tilbake</translation>
<translation id="3859306556332390985">Spol fremover</translation>
+<translation id="3895926599014793903">Tving zoom på</translation>
<translation id="3955193568934677022">Gi nettsteder tillatelse til å spille av beskyttet innhold (anbefales)</translation>
<translation id="3967822245660637423">Nedlasting fullført</translation>
<translation id="3987993985790029246">Kopiér link</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> / ?</translation>
<translation id="4002066346123236978">Tittel</translation>
<translation id="4008040567710660924">Tillat informasjonskapsler for et spesifikt nettsted.</translation>
+<translation id="4040330681741629921">Bli varslet når nettsteder kan vises i forenklet visning</translation>
<translation id="4046123991198612571">Neste spor</translation>
+<translation id="4149994727733219643">Forenklet visning av nettsider</translation>
<translation id="4165986682804962316">Nettstedsinnstillinger</translation>
+<translation id="4194328954146351878">Spør før nettsteder får lov til å se og endre informasjon på NFC-enheter (anbefales)</translation>
<translation id="4200726100658658164">Ã…pne posisjonsinnstillingene</translation>
<translation id="4226663524361240545">Varsler kan gjøre at enheten vibrerer</translation>
<translation id="4259722352634471385">Nettadressen er blokkert: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">Vis</translation>
<translation id="4336434711095810371">Slett alle data</translation>
<translation id="4402755511846832236">Blokkér nettsteder fra å vite når du bruker denne enheten aktivt</translation>
+<translation id="4428065317363009941">Personlig tilpasning av annonser</translation>
<translation id="4434045419905280838">Forgrunnsvinduer/viderekoblinger</translation>
<translation id="445467742685312942">Tillat at nettsteder kan spille beskyttet innhold</translation>
<translation id="4468959413250150279">Kutt lyden for et bestemt nettsted.</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">Alternativet finner du nesten øverst på skjermen</translation>
<translation id="5197729504361054390">Kontaktene du velger, deles med <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />.</translation>
<translation id="5216942107514965959">Sist besøkt i dag</translation>
+<translation id="5264323282659631142">Fjern «<ph name="CHIP_LABEL" />»</translation>
<translation id="528192093759286357">Dra ned fra toppen og trykk på tilbakeknappen for å avslutte fullskjerm.</translation>
<translation id="5300589172476337783">Vis</translation>
<translation id="5301954838959518834">Greit</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">Dette sletter <ph name="DATASIZE" /> med data og informasjonskapsler som er lagret av nettsteder.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(+ 1 til)}other{(+ # til)}}</translation>
<translation id="5403592356182871684">Navn</translation>
+<translation id="5412236728747081950">Dette nettstedet mottar interessene dine fra Chrome for å kunne vise deg mer relevante annonser</translation>
<translation id="5438097262470833822">Dette valget tilbakestiller tillatelser for <ph name="WEBSITE" /></translation>
<translation id="5489227211564503167">Medgått tid: <ph name="ELAPSED_TIME" /> av <ph name="TOTAL_TIME" />.</translation>
<translation id="5494752089476963479">Blokkér annonser på nettsteder som ofte viser forstyrrende eller villedende annonser</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">Last inn på nytt</translation>
<translation id="5596627076506792578">Flere alternativer</translation>
<translation id="5649053991847567735">Automatiske nedlastinger</translation>
+<translation id="5668404140385795438">Overstyr nettstedets forespørsel om å forhindre zooming</translation>
<translation id="5677928146339483299">Blokkert</translation>
<translation id="5689516760719285838">Sted</translation>
<translation id="5690795753582697420">Kameraet er slått av i Android-innstillingene</translation>
-<translation id="5710871682236653961">Spør før nettsteder får tillatelse til å sende og motta info når du berører NFC-enheter (anbefales)</translation>
<translation id="5719847187258001597">Dette sletter alle data og informasjonskapsler som er lagret av <ph name="ORIGIN" /> eller den tilhørende appen på startskjermen.</translation>
<translation id="5771720122942595109"><ph name="PERMISSION_1" /> er blokkert</translation>
<translation id="5804241973901381774">Tillatelser</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">Spill av</translation>
<translation id="6818926723028410516">Velg elementer</translation>
<translation id="6864395892908308021">Denne enheten kan ikke lese NFC</translation>
-<translation id="6910211073230771657">Slettet</translation>
<translation id="6912998170423641340">Blokkér nettsteder fra å få tilgang til tekst og bilder fra utklippstavlen</translation>
<translation id="6945221475159498467">Velg</translation>
<translation id="6965382102122355670">OK</translation>
+<translation id="6981982820502123353">Tilgjengelighet</translation>
<translation id="6992289844737586249">Spør før nettsteder får bruke mikrofonen (anbefales)</translation>
<translation id="7000754031042624318">Slått av i Android-innstillingene</translation>
<translation id="7016516562562142042">tillatt for den aktive søkemotoren</translation>
+<translation id="702463548815491781">Anbefalt når TalkBack eller brytertilgang er på</translation>
<translation id="7053983685419859001">Blokkér</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1 er valgt}other{# er valgt}}</translation>
-<translation id="7070090581017165256">Om dette nettstedet</translation>
<translation id="7087918508125750058"><ph name="ITEM_COUNT" /> er valgt. Du finner alternativer oppe på skjermen</translation>
<translation id="7141896414559753902">Blokkér nettsteder fra å vise forgrunnsvinduer og viderekoblinger (anbefales)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> kB</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">Et nettsted bruker mikrofonen din</translation>
<translation id="7561196759112975576">Alltid</translation>
-<translation id="7572498721684305250">Blokkér nettsteder fra å sende og motta info når du berører NFC-enheter</translation>
<translation id="757524316907819857">Blokkér nettsteder fra å spille av beskyttet innhold</translation>
+<translation id="7577900504646297215">Administrer interesser</translation>
<translation id="7649070708921625228">Hjelp</translation>
<translation id="7658239707568436148">Avbryt</translation>
<translation id="7781829728241885113">I går</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">Tilkoblingen er sikker</translation>
<translation id="8249310407154411074">Flytt til toppen</translation>
<translation id="8261506727792406068">Slett</translation>
+<translation id="8284326494547611709">Teksting</translation>
<translation id="8300705686683892304">Administreres av app</translation>
<translation id="8324158725704657629">Ikke spør igjen</translation>
<translation id="8372893542064058268">Tillat bakgrunnssynkronisering for et bestemt nettsted.</translation>
@@ -311,7 +324,7 @@
<translation id="8702612070107455751">Eventuelle frakoblede data blir slettet.</translation>
<translation id="8712637175834984815">Skjønner</translation>
<translation id="8719283222052720129">Slå på tillatelsen for <ph name="APP_NAME" /> i <ph name="BEGIN_LINK" />Android-innstillingene<ph name="END_LINK" />.</translation>
-<translation id="8725066075913043281">Prøv igjen</translation>
+<translation id="8725066075913043281">Prøv på nytt</translation>
<translation id="8730621377337864115">Ferdig</translation>
<translation id="8737217482364735741">Dette sletter alle data og informasjonskapsler som er lagret av <ph name="ORIGIN" />.</translation>
<translation id="8751914237388039244">Velg et bilde</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">Zoom inn</translation>
<translation id="8921772741368021346"><ph name="POSITION" />/<ph name="DURATION" /></translation>
<translation id="8926666909099850184">NFC er av for denne enheten. Slå det på i <ph name="BEGIN_LINK" />Android-innstillingene<ph name="END_LINK" />.</translation>
+<translation id="8928445016601307354">Blokker nettsteder fra å se og endre informasjon på NFC-enheter</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">Blokkér informasjonskapsler for et spesifikt nettsted.</translation>
<translation id="8959122750345127698">Nettadressen er utilgjengelig: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_or.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_or.xtb
index 4c1a06c2061..90b82ef0889 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_or.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_or.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676"><ph name="SITE_NAME" /> ସାଇଟୠଯୋଗ କରାଗଲା</translation>
<translation id="1383876407941801731">Search</translation>
<translation id="1384959399684842514">ଡାଉନà­â€Œà¬²à­‹à¬¡à­ ବିରତ ହୋଇଛି</translation>
+<translation id="1409426117486808224">ଖୋଲାଥିବା ଟାବà­â€à¬—à­à­œà¬¿à¬• ପାଇଠସରଳୀକୃତ ଦୃଶà­à­Ÿ</translation>
<translation id="1415402041810619267">URLକୠଛୋଟ କରାଯାଇଛି</translation>
<translation id="1446450296470737166">MIDI ଡିଭାଇସà­â€Œà¬—à­à¬¡à¬¼à¬¿à¬•à¬° ପୂରà­à¬£à­à¬£ ନିୟନà­à¬¤à­à¬°à¬£à¬° ଅନà­à¬®à¬¤à¬¿ ଦିଅନà­à¬¤à­</translation>
<translation id="1620510694547887537">କà­à­Ÿà¬¾à¬®à­‡à¬°à¬¾</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">କà­à¬•à­€à¬—à­à¬¡à¬¼à¬¿à¬•à­ ଅନà­à¬®à¬¤à¬¿ ଦିଅନà­à¬¤à­</translation>
<translation id="2228071138934252756"><ph name="APP_NAME" />କୠଆପଣଙà­à¬• କà­à­Ÿà¬¾à¬®à­‡à¬°à¬¾ ଆକà­à¬¸à­‡à¬¸à­ ଦେବା ପାଇà¬, <ph name="BEGIN_LINK" />Android ସେଟିଂସ<ph name="END_LINK" />ରେ କà­à­Ÿà¬¾à¬®à­‡à¬°à¬¾ ମଧà­à­Ÿ ଚାଲୠକରନà­à¬¤à­à¥¤</translation>
<translation id="2241634353105152135">ଥରେ ମାତà­à¬°</translation>
+<translation id="2253414712144136228"><ph name="NAME_OF_LIST_ITEM" />କୠକାà­à¬¿ ଦିଅନà­à¬¤à­</translation>
<translation id="2289270750774289114">ଯେତେବେଳେ à¬à¬• ସାଇଟୠଆଖପାଖର ବà­à¬²à­à¬Ÿà­‚ଥୠଡିଭାଇସà­â€à¬—à­à­œà¬¿à¬•à­ ଖୋଜିବାକୠଚାହà­à¬à¬›à¬¿, ସେତେବେଳେ ପଚାରନà­à¬¤à­ (ସà­à¬ªà¬¾à¬°à¬¿à¬¶ କରାଯାଇଛି)</translation>
<translation id="2315043854645842844">କà­à¬²à¬¾à¬à¬£à­à¬Ÿ ସାଇଡୠସାରà­à¬Ÿà¬¿à¬«à¬¿à¬•à­‡à¬Ÿà­ ଚୟନ ଅପରେଟିଂ ସିଷà­à¬Ÿà¬®à­â€ ଦà­à¬¬à¬¾à¬°à¬¾ ସପୋରà­à¬Ÿ କରà­à¬¨à¬¾à¬¹à¬¿à¬à¥¤</translation>
+<translation id="2321958826496381788">ସà­à¬²à¬¾à¬‡à¬¡à¬°à­â€à¬•à­ ସେପରà­à¬¯à­à­Ÿà¬¨à­à¬¤ ଟାଣନà­à¬¤à­, ଯେପରà­à¬¯à­à­Ÿà¬¨à­à¬¤ ଆପଣ à¬à¬¹à¬¾à¬•à­ ଭଲ ଭାବରେ ପà­à¬¿à¬¨à¬¾à¬¹à¬¾à¬¨à­à¬¤à¬¿à¥¤ ପାରାଗà­à¬°à¬¾à¬«à­â€â€à¬°à­‡ ଦà­à¬‡à¬¥à¬° ଟାପୠକରିବା ପରେ ଟେକà­à¬¸à¬Ÿà­ ଅତି କମà­â€â€à¬°à­‡ à¬à¬¤à­‡ ବଡ଼ ଦେଖାଯିବା ଆବଶà­à­Ÿà¬•à¥¤</translation>
<translation id="2359808026110333948">ଜାରି ରଖନà­à¬¤à­</translation>
<translation id="2379925928934107488">ଯେତେବେଳେ ସମà­à¬­à¬¬, Chrome ଗାà­à¬¾ ଥିମ ବà­à­Ÿà¬¬à¬¹à¬¾à¬° କରିବା ସମୟରେ ସାଇଟଗà­à­œà¬¿à¬•à¬°à­‡ ଗାà­à¬¾ ଥିମ ଲାଗୠକରନà­à¬¤à­</translation>
+<translation id="2387895666653383613">ଟେକà­à¬¸à¬Ÿà­â€Œ ସà­à¬•à­‡à¬²à¬¿à¬‚</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, à¬à¬¬à¬‚ ଅଧିକ <ph name="NUM_MORE" />ଟିକୠଅନà­à¬®à¬¤à¬¿ ଦିଆଯାଇଛି}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, à¬à¬¬à¬‚ ଅଧିକ <ph name="NUM_MORE" />ଟିକୠଅନà­à¬®à¬¤à¬¿ ଦିଆଯାଇଛି}}</translation>
<translation id="2434158240863470628">ଡାଉନà­â€Œà¬²à­‹à¬¡à­ ଶେଷ ହେଲା <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">ସୂଚନା ଦେଖାନà­à¬¤à­</translation>
<translation id="3123473560110926937">କିଛି ସାଇଟà­â€à¬—à­à­œà¬¿à¬•à¬°à­‡ ଅବରୋଧ କରାଯାଇଛି</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> ଷà­à¬Ÿà­‹à¬°à­ ହୋâ€à¬‡à¬¥à¬¿à¬¬à¬¾ ଡାଟା</translation>
+<translation id="3203366800380907218">ୱେବରà­</translation>
<translation id="321187648315454507"><ph name="APP_NAME" />କୠଆପଣଙà­à¬•à­ ବିଜà­à¬žà¬ªà­à¬¤à¬¿à¬—à­à­œà¬¿à¬• ପଠାଇବାକୠଅନà­à¬®à¬¤à¬¿ ଦେବା ପାଇà¬, <ph name="BEGIN_LINK" />Android ସେଟିଂସ<ph name="END_LINK" />ରେ ମଧà­à­Ÿ ବିଜà­à¬žà¬ªà­à¬¤à¬¿à¬—à­à­œà¬¿à¬• ଚାଲୠକରନà­à¬¤à­à¥¤</translation>
<translation id="3227137524299004712">ମାଇକà­à¬°à­‹à¬«à­‹à¬¨à­</translation>
<translation id="3277252321222022663">ସେନà­à¬¸à¬°à­ ଆକà­à¬¸à­‡à¬¸à­ କରିବାକୠସାଇଟà­â€Œà¬—à­à¬¡à¬¼à¬¿à¬•à­ ଅନà­à¬®à¬¤à¬¿ ଦିଅନà­à¬¤à­ (ସà­à¬ªà¬¾à¬°à¬¿à¬¶ କରାଯାଇଛି)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">ଆପଣଙà­à¬• ଡିଭାଇସର ବà­à­Ÿà¬¬à¬¹à¬¾à¬°</translation>
<translation id="385051799172605136">ପଛକà­</translation>
<translation id="3859306556332390985">ଆଗକୠବଢ଼ାନà­à¬¤à­</translation>
+<translation id="3895926599014793903">ଜà­à¬®à­ ସକà­à¬·à¬® କରିବା ପାଇଠବାଧà­à­Ÿ କରନà­à¬¤à­</translation>
<translation id="3955193568934677022">ସà­à¬°à¬•à­à¬·à¬¿à¬¤ ବିଷୟବସà­à¬¤à­à¬•à­ ଚଲାଇବା ପାଇଠସାଇଟà­â€à¬—à­à­œà¬¿à¬•à­ ଅନà­à¬®à¬¤à¬¿ ଦିଆଯାଇଛି।(ସà­à¬ªà¬¾à¬°à¬¿à¬¶à­ କରାଯାଇଛି)</translation>
<translation id="3967822245660637423">ଡାଉନà­â€â€â€à¬²à­‹à¬¡à­ ଶେଷ ହୋଇଛି</translation>
<translation id="3987993985790029246">ଲିଙà­à¬•à­ କପି କରନà­à¬¤à­</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> / ?</translation>
<translation id="4002066346123236978">ଆଖà­à­Ÿà¬¾</translation>
<translation id="4008040567710660924">à¬à¬• ନିରà­à¬¦à­à¬¦à¬¿à¬·à­à¬Ÿ ସାଇଟୠପାଇଠକà­à¬•à­€à¬—à­à­œà¬¿à¬•à­ ଅନà­à¬®à¬¤à¬¿ ଦିà¬à¥¤</translation>
+<translation id="4040330681741629921">ଯେତେବେଳେ à¬à¬• ସାଇଟ ସରଳୀକୃତ ଭà­à­Ÿà­à¬°à­‡ ଦେଖାଯାଇପାରିବ, ସେତେବେଳେ ସେ ବିଷୟରେ ସୂଚନା ପାଆନà­à¬¤à­</translation>
<translation id="4046123991198612571">ପରବରà­à¬¤à­à¬¤à­€ ଟà­à¬°à¬¾à¬•à­</translation>
+<translation id="4149994727733219643">ୱେବୠପୃଷà­à¬ à¬¾à¬—à­à­œà¬¿à¬• ପାଇଠସରଳୀକୃତ ଭà­à­Ÿà­</translation>
<translation id="4165986682804962316">ସାଇଟà­â€ ସେଟିଂସà­â€Œ</translation>
+<translation id="4194328954146351878">NFC ଡିଭାଇସଗà­à¬¡à¬¼à¬¿à¬•à¬°à­‡ ସୂଚନା ଦେଖିବା à¬à¬¬à¬‚ ପରିବରà­à¬¤à­à¬¤à¬¨ କରିବା ପାଇଠସାଇଟଗà­à¬¡à¬¼à¬¿à¬•à­ ଅନà­à¬®à¬¤à¬¿ ଦେବା ପୂରà­à¬¬à¬°à­ ପଚାରନà­à¬¤à­ (ସà­à¬ªà¬¾à¬°à¬¿à¬¶ କରାଯାଇଛି)</translation>
<translation id="4200726100658658164">ଲୋକେସନୠସେଟିଂସୠଖୋଲନà­à¬¤à­</translation>
<translation id="4226663524361240545">ବିଜà­à¬žà¬ªà­à¬¤à¬¿ ଡିଭାଇସà­â€à¬•à­ ଭାଇବà­à¬°à­‡à¬Ÿà­ କରିପାରେ</translation>
<translation id="4259722352634471385">ନାଭିଗେସନୠଅବରୋଧ କରାଯାଇଛି: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">ପà­à¬°à¬¸à¬¾à¬°à¬£ କରନà­à¬¤à­</translation>
<translation id="4336434711095810371">ସମସà­à¬¤ ଡାଟା ଖାଲି କରନà­à¬¤à­</translation>
<translation id="4402755511846832236">ଆପଣ କେତେବେଳେ ସକà­à¬°à¬¿à­Ÿ ଭାବେ à¬à¬¹à¬¿ ଡିଭାଇସକୠବà­à­Ÿà¬¬à¬¹à¬¾à¬° କରà­à¬›à¬¨à­à¬¤à¬¿ ତାହା ଜାଣିବାରୠସାଇଟଗà­à¬¡à¬¼à¬¿à¬•à­ ବà­à¬²à¬•à­ କରନà­à¬¤à­</translation>
+<translation id="4428065317363009941">ବିଜà­à¬žà¬¾à¬ªà¬¨ ପରà­à¬¸à¬¨à¬¾à¬²à¬¾à¬‡à¬œà­‡à¬¸à¬¨</translation>
<translation id="4434045419905280838">ପପà­-ଅପୠà¬à¬¬à¬‚ ରିଡାଇରେକà­â€Œà¬Ÿ</translation>
<translation id="445467742685312942">ସାଇଟà­â€à¬—à­à­œà¬¿à¬•à­ ସà­à¬°à¬•à­à¬·à¬¿à¬¤ ବିଷୟବସà­à¬¤à­ ଚଳାଇବାକୠଅନà­à¬®à¬¤à¬¿ ଦିଅନà­à¬¤à­</translation>
<translation id="4468959413250150279">ଗୋଟିଠନିରà­à¬¦à­à¬¦à¬¿à¬·à­à¬Ÿ ସାଇଟୠପାଇଠସାଉଣà­à¬¡à¬•à­ ମà­à­Ÿà­à¬Ÿà­ କରନà­à¬¤à­à¥¤</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">ସà­à¬•à­à¬°à¬¿à¬¨à¬° ଶୀରà­à¬·à¬­à¬¾à¬—ର ନିକଟରେ ବିକଳà­à¬ª ଉପଲବà­à¬§ ଅଛି</translation>
<translation id="5197729504361054390">ଆପଣ ଚୟନ କରିଥିବା ଯୋଗାଯୋଗଗà­à­œà¬¿à¬• <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ସହିତ ସେୟାରୠକରାଯିବ।</translation>
<translation id="5216942107514965959">ଆଜି ଶେଷ ଥର ଭିଜିଟୠକରାଯାଇଛି</translation>
+<translation id="5264323282659631142">'<ph name="CHIP_LABEL" />'କୠକାà­à¬¿ ଦିଅନà­à¬¤à­</translation>
<translation id="528192093759286357">ପୂରà­à¬£à­à¬£ ସà­à¬•à­à¬°à¬¿à¬¨à­â€Œà¬°à­ ପà­à¬°à¬¸à­à¬¥à¬¾à¬¨ କରିବାକୠଶୀରà­à¬·à¬°à­ ଟାଣନà­à¬¤à­ à¬à¬¬à¬‚ ପଛପଟ ବଟନà­â€Œà¬•à­ ସà­à¬ªà¬°à­à¬¶ କରନà­à¬¤à­</translation>
<translation id="5300589172476337783">ପà­à¬°à¬¦à¬°à­à¬¶à¬¨ କରନà­à¬¤à­</translation>
<translation id="5301954838959518834">ଠିକୠଅଛି, ବà­à¬à¬¿à¬—ଲି</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">à¬à¬¹à¬¾ ସାଇଟଗà­à¬¡à¬¼à¬¿à¬• ଦà­à­±à¬¾à¬°à¬¾ ଷà­à¬Ÿà­‹à¬°à­ କରାଯାଇଥିବା <ph name="DATASIZE" /> ଡାଟା à¬à¬¬à¬‚ କà­à¬•à­€à¬—à­à¬¡à¬¼à¬¿à¬•à­ ଖାଲି କରିଦେବ।</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(+ 1ଟି ଅଧିକ)}other{(+ #ଟି ଅଧିକ)}}</translation>
<translation id="5403592356182871684">ନାମଗà­à­œà¬¿à¬•</translation>
+<translation id="5412236728747081950">ଆପଣଙà­à¬•à­ ଅଧିକ ପà­à¬°à¬¾à¬¸à¬™à­à¬—ିକ ବିଜà­à¬žà¬¾à¬ªà¬¨ ଦେଖାଇବା ପାଇଠà¬à¬¹à¬¿ ସାଇଟ Chromeରୠଆପଣଙà­à¬•à¬° ରà­à¬šà¬¿à¬—à­à¬¡à¬¼à¬¿à¬• ପାଇଥାà¬</translation>
<translation id="5438097262470833822">à¬à¬¹à¬¿ ବିକଳà­à¬ªà¬•à­ ପସନà­à¬¦ କଲେ à¬à¬¹à¬¾ <ph name="WEBSITE" /> ପାଇଠଅନà­à¬®à¬¤à¬¿à¬—à­à­œà¬¿à¬•à­ ରିସେଟୠକରିଦେବ</translation>
<translation id="5489227211564503167"><ph name="TOTAL_TIME" />ର <ph name="ELAPSED_TIME" /> ବିତିଯାଇଥିବା ସମୟ।</translation>
<translation id="5494752089476963479">ଅନଧିକାର ପà­à¬°à¬¬à­‡à¬¶ କରିଥିବା କିମà­à¬¬à¬¾ ବିଭà­à¬°à¬¾à¬¨à­à¬¤à¬¿à¬•à¬° ବିଜà­à¬žà¬¾à¬ªà¬¨ ଦେଖାଉଥିବା ସାଇଟୠବà­à¬²à¬•à­ କରନà­à¬¤à­</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">ପà­à¬¨à¬ƒ ଲୋଡୠକରନà­à¬¤à­</translation>
<translation id="5596627076506792578">ଅଧିକ ବିକଳà­à¬ª</translation>
<translation id="5649053991847567735">ସà­à­±à¬šà¬¾à¬³à¬¿à¬¤ ଡାଉନà­â€Œà¬²à­‹à¬¡à­â€Œà¬—à­à­œà¬¿à¬•</translation>
+<translation id="5668404140385795438">ଜà­à¬®à­ ଇନୠପà­à¬°à¬•à­à¬°à¬¿à­Ÿà¬¾à¬•à­ ପà­à¬°à¬¤à¬¿à¬°à­‹à¬§ କରିବା ପାଇଠà¬à¬• ୱେବà­â€Œà¬¸à¬¾à¬‡à¬Ÿà­â€Œà¬° ଅନà­à¬°à­‹à¬§à¬•à­ ଓଭରà­â€Œà¬°à¬¾à¬‡à¬¡à­ କରନà­à¬¤à­</translation>
<translation id="5677928146339483299">ବà­à¬²à¬•à­ କରାଯାଇଛି</translation>
<translation id="5689516760719285838">ଲୋକେସନà­</translation>
<translation id="5690795753582697420">Android ସେଟିଂସରେ କà­à­Ÿà¬¾à¬®à­‡à¬°à¬¾ ବନà­à¬¦ କରାଯାଇଛି</translation>
-<translation id="5710871682236653961">ଆପଣ NFC ଡିଭାଇସà­â€à¬—à­à­œà¬¿à¬•à¬°à­‡ ଟାପୠକଲେ ସାଇଟà­â€à¬—à­à­œà¬¿à¬•à­ ସୂଚନା ପଠାଇବା à¬à¬¬à¬‚ ପà­à¬°à¬¾à¬ªà­à¬¤ କରିବାକୠଅନà­à¬®à¬¤à¬¿ ଦେବା ପୂରà­à¬¬à¬°à­ ପଚାରନà­à¬¤à­ (ସà­à¬ªà¬¾à¬°à¬¿à¬¶ କରାଯାଇଛି)</translation>
<translation id="5719847187258001597">ଆପଣଙà­à¬• ମୂଳ ସà­à¬•à­à¬°à¬¿à¬¨à¬°à­‡ <ph name="ORIGIN" /> କିମà­à¬¬à¬¾ à¬à¬¹à¬¾à¬° ଆପଗà­à¬¡à¬¼à¬¿à¬• ଦà­à­±à¬¾à¬°à¬¾ ଷà­à¬Ÿà­‹à¬°à­ କରାଯାଇଥିବା ଡାଟା à¬à¬¬à¬‚ କà­à¬•à­€à¬—à­à¬¡à¬¼à¬¿à¬•à­ à¬à¬¹à¬¾ ଖାଲି କରିଦେବ।</translation>
<translation id="5771720122942595109"><ph name="PERMISSION_1" /> ବà­à¬²à¬•à­ କରାଯାଇଛି</translation>
<translation id="5804241973901381774">ଅନà­à¬®à¬¤à¬¿à¬—à­à¬¡à¬¼à¬¿à¬•</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">ଚଲାନà­à¬¤à­</translation>
<translation id="6818926723028410516">ଆଇଟମୠଚୟନ କରନà­à¬¤à­</translation>
<translation id="6864395892908308021">à¬à¬¹à¬¿ ଡିଭାଇସୠNFC ପଢ଼ିପାରିବ ନାହିà¬</translation>
-<translation id="6910211073230771657">ଡିଲିଟୠକରାଗଲା</translation>
<translation id="6912998170423641340">ସାଇଟà­â€ à¬à¬¬à¬‚ କà­à¬²à¬¿à¬ªà­â€Œà¬¬à­‹à¬°à­à¬¡à¬°à­ ଲେଖା ପà­à¬¿à¬¬à¬¾ à¬à¬¬à¬‚ ଛବି ଅବରୋଧ କରନà­à¬¤à­</translation>
<translation id="6945221475159498467">ଚୟନ କରନà­à¬¤à­</translation>
<translation id="6965382102122355670">ଓକେ ବଟନà­</translation>
+<translation id="6981982820502123353">ଆକà­à¬¸à­‡à¬¸à¬¿à¬¬à¬¿à¬²à¬¿à¬Ÿà­€</translation>
<translation id="6992289844737586249">ଆପଣଙà­à¬•à¬° ମାଇକà­à¬°à­‹à¬«à­‹à¬¨à­â€ ବà­à­Ÿà¬¬à¬¹à¬¾à¬° କରିବାକୠସାଇଟà­â€Œà¬—à­à­œà¬¿à¬•à­ ଅନà­à¬®à¬¤à¬¿ ଦେବା ପୂରà­à¬¬à¬°à­, ପà­à¬°à¬¥à¬®à­‡ ପଚାରନà­à¬¤à­(ସà­à¬ªà¬¾à¬°à¬¿à¬¶à­â€Œ କରାଯାଇଛି)</translation>
<translation id="7000754031042624318">Android ସେଟିଂସରେ ବନà­à¬¦ କରାଯାଇଛି</translation>
<translation id="7016516562562142042">ସାମà­à¬ªà­à¬°à¬¤à¬¿à¬• 'ସନà­à¬§à¬¾à¬¨ ଇଞà­à¬œà¬¿à¬¨à­' ପାଇଠଅନà­à¬®à¬¤à¬¿ ଦିଆଯାଇଛି</translation>
+<translation id="702463548815491781">TalkBack କିମà­à¬¬à¬¾ ଆକà­à¬¸à­‡à¬¸à­ ପରିବରà­à¬¤à­à¬¤à¬¨ ଚାଲୠଥିଲେ à¬à¬¹à¬¾ କରିବାକୠସà­à¬ªà¬¾à¬°à¬¿à¬¶à­ କରାଯାଇଛି</translation>
<translation id="7053983685419859001">ଅବରୋଧ କରନà­à¬¤à­</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1ଟି ଚୟନ କରାଯାଇଛି}other{#ଟି ଚୟନ କରାଯାଇଛି}}</translation>
-<translation id="7070090581017165256">à¬à¬¹à¬¿ ସାଇଟ ବିଷୟରେ</translation>
<translation id="7087918508125750058"><ph name="ITEM_COUNT" />ଟି ଚୟନ କରାଯାଇଛି। ସà­à¬•à­à¬°à¬¿à¬¨à­â€Œà¬° ଶୀରà­à¬·à¬­à¬¾à¬—ରେ ବିକଳà­à¬ªà¬—à­à¬¡à¬¼à¬¿à¬• ଉପଲବà­à¬§ ଅଛି</translation>
<translation id="7141896414559753902">ସାଇଟà­â€Œà¬—à­à­œà¬¿à¬•à¬° ପପà­â€Œ-ଅପà­â€Œ à¬à¬¬à¬‚ ରିଡାଇରେକà­à¬Ÿ ଦେଖାଇବାକୠଅବରୋଧ କରନà­à¬¤à­ (ସà­à¬ªà¬¾à¬°à¬¿à¬¶à­ କରାଯାଇଛି)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> KB</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">କୌଣସି ସାଇଟୠଆପଣଙà­à¬• ମାଇକà­à¬°à­‹à¬«à­‹à¬¨à¬•à­ ବà­à­Ÿà¬¬à¬¹à¬¾à¬° କରà­à¬›à¬¿</translation>
<translation id="7561196759112975576">ସରà­à¬¬à¬¦à¬¾</translation>
-<translation id="7572498721684305250">ଆପଣ NFC ଡିଭାଇସà­â€à¬—à­à­œà¬¿à¬•à¬°à­‡ ଟାପୠକଲେ ସାଇଟà­â€à¬—à­à­œà¬¿à¬•à­ ସୂଚନା ପଠାଇବା à¬à¬¬à¬‚ ପà­à¬°à¬¾à¬ªà­à¬¤ କରିବାରୠବà­à¬²à¬•à­ କରନà­à¬¤à­</translation>
<translation id="757524316907819857">ସà­à¬°à¬•à­à¬·à¬¿à¬¤ ଥିବା ବିଷୟବସà­à¬¤à­ ଚଲାଇବାରୠସାଇଟà­â€Œà¬—à­à¬¡à¬¼à¬¿à¬•à­ ବà­à¬²à¬•à­ କରନà­à¬¤à­</translation>
+<translation id="7577900504646297215">ରà­à¬šà¬¿à¬—à­à¬¡à¬¼à¬¿à¬•à­ ପରିଚାଳନା କରନà­à¬¤à­</translation>
<translation id="7649070708921625228">ସହାୟତା</translation>
<translation id="7658239707568436148">ବାତିଲà­</translation>
<translation id="7781829728241885113">ଗତକଲି</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">ସଂଯୋଗ ସà­à¬°à¬•à­à¬·à¬¿à¬¤ ଅଛି</translation>
<translation id="8249310407154411074">ଉପରକୠଘà­à¬žà­à¬šà¬¾à¬¨à­à¬¤à­</translation>
<translation id="8261506727792406068">ବିଲୋପ</translation>
+<translation id="8284326494547611709">କà­à­Ÿà¬¾à¬ªà¬¸à¬¨à­</translation>
<translation id="8300705686683892304">ଆପୠଦà­à­±à¬¾à¬°à¬¾ ପରିଚାଳିତ</translation>
<translation id="8324158725704657629">ପà­à¬£à¬¿ ପଚାର ନାହିà¬</translation>
<translation id="8372893542064058268">à¬à¬• ନିରà­à¬¦à­à¬¦à¬¿à¬·à­à¬Ÿ ସାଇଟୠପାଇଠପୃଷà­à¬Ÿà¬ªà¬Ÿ ସିଙà­à¬•à­â€Œà¬•à­ ଅନà­à¬®à¬¤à¬¿ ଦିଅନà­à¬¤à­à¥¤</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">ଜà­à¬®à­ ବà­à¬¾à¬¨à­à¬¤à­</translation>
<translation id="8921772741368021346"><ph name="POSITION" /> / <ph name="DURATION" /></translation>
<translation id="8926666909099850184">à¬à¬¹à¬¿ ଡିଭାଇସୠପାଇଠNFC ବନà­à¬¦ ଅଛି। à¬à¬¹à¬¾à¬•à­ <ph name="BEGIN_LINK" />Android ସେଟିଂସà­â€Œ<ph name="END_LINK" />ରେ ଚାଲୠକରନà­à¬¤à­à¥¤</translation>
+<translation id="8928445016601307354">NFC ଡିଭାଇସଗà­à¬¡à¬¼à¬¿à¬•à¬°à­‡ ସୂଚନା ଦେଖିବାରୠà¬à¬¬à¬‚ ପରିବରà­à¬¤à­à¬¤à¬¨ କରିବାରୠସାଇଟଗà­à¬¡à¬¼à¬¿à¬•à­ ବà­à¬²à¬• କରନà­à¬¤à­</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">à¬à¬• ନିରà­à¬¦à­à¬¦à¬¿à¬·à­à¬Ÿ ସାଇଟୠପାଇଠକà­à¬•à­€à¬—à­à­œà¬¿à¬•à­ ଅବରୋଧ କରନà­à¬¤à­à¥¤</translation>
<translation id="8959122750345127698">ନାଭିଗେସନà­â€Œà¬°à­‡ ପହଞà­à¬šà¬¿ ହେଉନାହିà¬: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_pa.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_pa.xtb
index 9a9787e98a5..11564529f0f 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_pa.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_pa.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">ਸਾਈਟ <ph name="SITE_NAME" /> ਜੋੜੀ ਗਈ</translation>
<translation id="1383876407941801731">ਖੋਜੋ</translation>
<translation id="1384959399684842514">ਡਾਊਨਲੋਡ ਰੋਕਿਆ ਗਿਆ</translation>
+<translation id="1409426117486808224">ਖà©à©±à¨²à©à¨¹à©€à¨†à¨‚ ਟੈਬਾਂ ਲਈ ਸਰਲੀਕਿਰਤ ਦà©à¨°à¨¿à¨¶</translation>
<translation id="1415402041810619267">URL ਛੋਟਾ ਕੀਤਾ ਗਿਆ</translation>
<translation id="1446450296470737166">MIDI ਡਿਵਾਈਸਾਂ ਦੇ ਪੂਰੇ ਨਿਯੰਤਰਣ ਦੀ ਆਗਿਆ ਦਿਓ</translation>
<translation id="1620510694547887537">ਕੈਮਰਾ</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">ਕà©à¨•à©€à©› ਨੂੰ ਆਗਿਆ ਦਿਓ</translation>
<translation id="2228071138934252756"><ph name="APP_NAME" /> ਨੂੰ ਆਪਣੇ ਕੈਮਰੇ ਤੱਕ ਪਹà©à©°à¨š ਕਰਨ ਦੇਣ ਲਈ, <ph name="BEGIN_LINK" />Android ਸੈਟਿੰਗਾਂ<ph name="END_LINK" /> ਵਿੱਚ ਕੈਮਰਾ ਵੀ ਚਾਲੂ ਕਰੋ।</translation>
<translation id="2241634353105152135">ਸਿਰਫ ਇੱਕ ਵਾਰ</translation>
+<translation id="2253414712144136228"><ph name="NAME_OF_LIST_ITEM" /> ਹਟਾਓ</translation>
<translation id="2289270750774289114">ਕਿਸੇ ਸਾਈਟ ਵੱਲੋਂ ਨਜ਼ਦੀਕੀ ਬਲੂਟà©à©±à¨¥ ਡੀਵਾਈਸਾਂ ਦਾ ਪਤਾ ਲਗਾਉਣ ਵੇਲੇ ਪà©à©±à¨›à©‹ (ਸਿਫ਼ਾਰਸ਼ੀ)</translation>
<translation id="2315043854645842844">ਕਲਾਈਂਟ ਵੱਲੋਂ ਕੀਤੀ ਗਈ ਪà©à¨°à¨®à¨¾à¨£-ਪੱਤਰ ਦੀ ਚੋਣ ਓਪਰੇਟਿੰਗ ਸਿਸਟਮ ਵੱਲੋਂ ਸਮਰਥਿਤ ਨਹੀਂ ਹੈ।</translation>
+<translation id="2321958826496381788">ਸਲਾਈਡਰ ਨੂੰ ਡà©à¨°à©ˆà¨— ਕਰੋ ਜਦੋਂ ਤੱਕ ਤà©à¨¸à©€à¨‚ ਇਸਨੂੰ ਆਸਾਨੀ ਨਾਲ ਪੜà©à¨¹ ਨਾ ਲਓ। ਲਿਖਤ ਇੱਕ ਪੈਰਾਗà©à¨°à¨¾à¨« 'ਤੇ ਡਬਲ-ਟੈਪ ਕਰਨ ਤੋਂ ਬਾਅਦ ਘੱਟੋ-ਘੱਟ ਇੰਨਾ ਵੱਡਾ ਦਿਖਾਈ ਦੇਣਾ ਚਾਹੀਦਾ ਹੈ।</translation>
<translation id="2359808026110333948">ਜਾਰੀ ਰੱਖੋ</translation>
<translation id="2379925928934107488">ਜਦੋਂ ਵੀ ਸੰਭਵ ਹੋਵੇ, Chrome ਵੱਲੋਂ ਗੂੜà©à¨¹à¨¾ ਥੀਮ ਵਰਤੇ ਜਾਣ 'ਤੇ ਸਾਈਟਾਂ ਲਈ ਗੂੜà©à¨¹à¨¾ ਥੀਮ ਲਾਗੂ ਕਰੋ</translation>
+<translation id="2387895666653383613">ਟੈਕਸਟ ਸਕੇਲਿੰਗ</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ਅਤੇ <ph name="NUM_MORE" /> ਹੋਰ ਦੀ ਇਜਾਜ਼ਤ ਦਿੱਤੀ ਗਈ}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ਅਤੇ <ph name="NUM_MORE" /> ਹੋਰ ਦੀ ਇਜਾਜ਼ਤ ਦਿੱਤੀ ਗਈ}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ਅਤੇ <ph name="NUM_MORE" /> ਹੋਰ ਦੀ ਇਜਾਜ਼ਤ ਦਿੱਤੀ ਗਈ}}</translation>
<translation id="2434158240863470628">ਡਾਊਨਲੋਡ ਮà©à¨•à©°à¨®à¨² ਹੋਇਆ <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">ਜਾਣਕਾਰੀ ਦਿਖਾਓ</translation>
<translation id="3123473560110926937">ਕà©à¨ ਸਾਈਟਾਂ 'ਤੇ ਬਲਾਕ ਕੀਤੇ ਗà¨</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> ਸਟੋਰ ਕੀਤਾ ਡਾਟਾ</translation>
+<translation id="3203366800380907218">ਵੈੱਬ ਤੋਂ</translation>
<translation id="321187648315454507"><ph name="APP_NAME" /> ਨੂੰ ਤà©à¨¹à¨¾à¨¨à©‚à©° ਸੂਚਨਾਵਾਂ ਭੇਜਣ ਦੇਣ ਲਈ, <ph name="BEGIN_LINK" />Android ਸੈਟਿੰਗਾਂ<ph name="END_LINK" /> ਵਿੱਚ ਸੂਚਨਾਵਾਂ ਵੀ ਚਾਲੂ ਕਰੋ।</translation>
<translation id="3227137524299004712">ਮਾਈਕà©à¨°à©‹à¨«à©‹à¨¨</translation>
<translation id="3277252321222022663">ਸਾਈਟਾਂ ਨੂੰ ਸੈਂਸਰਾਂ ਤੱਕ ਪਹà©à©°à¨š ਕਰਨ ਦਿਓ (ਸਿਫ਼ਾਰਸ਼ੀ)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">ਤà©à¨¹à¨¾à¨¡à©‡ ਡੀਵਾਈਸ ਦੀ ਵਰਤੋਂ</translation>
<translation id="385051799172605136">ਪਿੱਛੇ</translation>
<translation id="3859306556332390985">ਅੱਗੇ ਵੱਲ ਨੂੰ ਲੈ ਜਾਓ</translation>
+<translation id="3895926599014793903">ਜ਼ੂਮ ਨੂੰ ਚਾਲੂ ਕਰਨ 'ਤੇ ਜ਼ੋਰ ਦਿਓ</translation>
<translation id="3955193568934677022">ਸਾਈਟਾਂ ਨੂੰ ਸà©à¨°à©±à¨–ਿਅਤ ਸਮੱਗਰੀ ਚਲਾਉਣ ਦਿਓ (ਸਿਫ਼ਾਰਸ਼ੀ)</translation>
<translation id="3967822245660637423">ਡਾਊਨਲੋਡ ਪੂਰਾ ਹੋਇਆ</translation>
<translation id="3987993985790029246">ਲਿੰਕ ਕਾਪੀ ਕਰੋ</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> / ?</translation>
<translation id="4002066346123236978">ਸਿਰਲੇਖ</translation>
<translation id="4008040567710660924">ਕਿਸੇ ਖਾਸ ਸਾਈਟ ਨੂੰ ਕà©à¨•à©€à©› ਨੂੰ ਵਰਤਣ ਦਿਓ।</translation>
+<translation id="4040330681741629921">ਕਿਸੇ ਸਾਈਟ ਲਈ ਸਰਲੀਕਿਰਤ ਦà©à¨°à¨¿à¨¸à¨¼ ਦੀ ਸà©à¨µà¨¿à¨§à¨¾ ਉਪਲਬਧ ਹੋਣ 'ਤੇ ਸੂਚਨਾ ਪà©à¨°à¨¾à¨ªà¨¤ ਕਰੋ</translation>
<translation id="4046123991198612571">ਅਗਲਾ ਟਰੈਕ</translation>
+<translation id="4149994727733219643">ਵੈੱਬ ਪੰਨਿਆਂ ਲਈ ਸਰਲੀਕਿਰਤ ਦà©à¨°à¨¿à¨¶</translation>
<translation id="4165986682804962316">ਸਾਈਟ ਸੈਟਿੰਗਾਂ</translation>
+<translation id="4194328954146351878">ਸਾਈਟਾਂ ਨੂੰ NFC ਡੀਵਾਈਸਾਂ 'ਤੇ ਜਾਣਕਾਰੀ ਦੇਖਣ ਅਤੇ ਬਦਲਣ ਦੀ ਆਗਿਆ ਦੇਣ ਤੋਂ ਪਹਿਲਾਂ ਪà©à©±à¨›à©‹ (ਸਿਫ਼ਾਰਸ਼ੀ)</translation>
<translation id="4200726100658658164">ਟਿਕਾਣਾ ਸੈਟਿੰਗਾਂ ਖੋਲà©à¨¹à©‹</translation>
<translation id="4226663524361240545">ਸੂਚਨਾਵਾਂ ਡੀਵਾਈਸ ਨੂੰ ਥਰਥਰਾਹਟ ਕਰ ਸਕਦੀਆਂ ਹਨ</translation>
<translation id="4259722352634471385">ਨੈਵੀਗੇਸ਼ਨ ਬਲੌਕ ਕੀਤੀ ਹੈ: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">ਵਿਸਤਾਰ ਕਰੋ</translation>
<translation id="4336434711095810371">ਸਾਰਾ ਡਾਟਾ ਕਲੀਅਰ ਕਰੋ</translation>
<translation id="4402755511846832236">ਸਾਈਟਾਂ ਨੂੰ ਇਹ ਜਾਣਨ ਤੋਂ ਰੋਕਣ ਲਈ ਬਲਾਕ ਕਰੋ ਕਿ ਤà©à¨¸à©€à¨‚ ਕਿਰਿਆਸ਼ੀਲ ਤੌਰ 'ਤੇ ਇਸ ਡੀਵਾਈਸ ਦੀ ਵਰਤੋਂ ਕਦੋਂ ਕਰਦੇ ਹੋ</translation>
+<translation id="4428065317363009941">ਵਿਗਿਆਪਨ ਵਿਅਕਤੀਗਤਕਰਨ</translation>
<translation id="4434045419905280838">ਪੌਪ-ਅੱਪ ਅਤੇ ਰੀਡਾਇਰੈਕਟ</translation>
<translation id="445467742685312942">ਸਾਈਟਾਂ ਨੂੰ ਸà©à¨°à©±à¨–ਿਅਤ ਕੀਤੀ ਸਮੱਗਰੀ ਚਲਾਉਣ ਦਿਓ</translation>
<translation id="4468959413250150279">ਕਿਸੇ ਖਾਸ ਸਾਈਟ ਦੀ ਧà©à¨¨à©€ ਨੂੰ ਮਿਊਟ ਕਰੋ।</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">ਸਕà©à¨°à©€à¨¨ ਦੇ ਸਿਖਰ ਨੇੜੇ ਵਿਕਲਪ ਉਪਲਬਧ ਹਨ</translation>
<translation id="5197729504361054390">ਤà©à¨¹à¨¾à¨¡à©‡ ਵੱਲੋਂ ਚà©à¨£à©‡ ਸੰਪਰਕ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ਨਾਲ ਸਾਂà¨à©‡ ਕੀਤੇ ਜਾਣਗੇ।</translation>
<translation id="5216942107514965959">ਪਿਛਲੀ ਵਾਰ ਅੱਜ ਦੇਖੀ ਗਈ</translation>
+<translation id="5264323282659631142">'<ph name="CHIP_LABEL" />' ਨੂੰ ਹਟਾਓ</translation>
<translation id="528192093759286357">ਉੱਪਰ ਤੋਂ ਘਸੀਟੋ ਅਤੇ ਪੂਰੀ ਸਕà©à¨°à©€à¨¨ ਤੋਂ ਬਾਹਰ ਜਾਣ ਲਈ ਪਿੱਛੇ ਜਾਓ ਬਟਨ ਨੂੰ ਸਪਰਸ਼ ਕਰੋ।</translation>
<translation id="5300589172476337783">ਦਿਖਾਓ</translation>
<translation id="5301954838959518834">ਠੀਕ, ਸਮਠਲਿਆ</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">ਇੰਠਕਰਨ ਨਾਲ ਸਾਈਟਾਂ ਵੱਲੋਂ ਸਟੋਰ ਕੀਤੇ <ph name="DATASIZE" /> ਡਾਟੇ ਅਤੇ ਕà©à¨•à©€à¨œà¨¼ ਨੂੰ ਕਲੀਅਰ ਕਰ ਦਿੱਤਾ ਜਾਵੇਗਾ।</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(+ 1 ਹੋਰ)}one{(+ # ਹੋਰ)}other{(+ # ਹੋਰ)}}</translation>
<translation id="5403592356182871684">ਨਾਮ</translation>
+<translation id="5412236728747081950">ਤà©à¨¹à¨¾à¨¨à©‚à©° ਜ਼ਿਆਦਾ ਢà©à¨•à¨µà©‡à¨‚ ਵਿਗਿਆਪਨ ਦਿਖਾਉਣ ਲਈ, ਇਹ ਸਾਈਟ Chrome ਤੋਂ ਤà©à¨¹à¨¾à¨¡à©€à¨†à¨‚ ਦਿਲਚਸਪੀਆਂ ਬਾਰੇ ਜਾਣਕਾਰੀ ਲੈਂਦੀ ਹੈ</translation>
<translation id="5438097262470833822">ਇਹ ਚੋਣ <ph name="WEBSITE" /> ਦੀਆਂ ਇਜਾਜ਼ਤਾਂ ਨੂੰ ਰੀਸੈੱਟ ਕਰ ਦੇਵੇਗੀ</translation>
<translation id="5489227211564503167"><ph name="TOTAL_TIME" /> ਵਿੱਚੋਂ ਬੀਤਿਆ ਸਮਾਂ <ph name="ELAPSED_TIME" />।</translation>
<translation id="5494752089476963479">ਉਹਨਾਂ ਸਾਈਟਾਂ 'ਤੇ ਵਿਗਿਆਪਨਾਂ ਨੂੰ ਬਲਾਕ ਕਰੋ, ਜੋ ਦਖਲਅੰਦਾਜ਼ੀ ਅਤੇ ਗà©à¨®à¨°à¨¾à¨¹ ਕਰਨ ਵਾਲੇ ਵਿਗਿਆਪਨ ਦਿਖਾਉਂਦੀਆਂ ਹਨ</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">ਰੀਲੋਡ ਕਰੋ</translation>
<translation id="5596627076506792578">ਹੋਰ ਚੋਣਾਂ</translation>
<translation id="5649053991847567735">ਆਟੋਮੈਟਿਕ ਡਾਊਨਲੋਡਸ</translation>
+<translation id="5668404140385795438">ਜ਼ੂਮ ਇਨ ਕਰਨ ਤੋਂ ਰੋਕਣ ਲਈ ਵੈੱਬਸਾਈਟ ਦੀ ਬੇਨਤੀ ਨੂੰ ਓਵਰਰਾਈਡ ਕਰੋ</translation>
<translation id="5677928146339483299">ਬਲੌਕ ਕੀਤਾ</translation>
<translation id="5689516760719285838">ਟਿਕਾਣਾ</translation>
<translation id="5690795753582697420">Android ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਕੈਮਰਾ ਬੰਦ ਕੀਤਾ ਹੋਇਆ ਹੈ</translation>
-<translation id="5710871682236653961">ਤà©à¨¹à¨¾à¨¡à©‡ ਵੱਲੋਂ NFC ਡੀਵਾਈਸਾਂ 'ਤੇ ਟੈਪ ਕਰਨ ਵੇਲੇ ਸਾਈਟਾਂ 'ਤੇ ਜਾਣਕਾਰੀ ਭੇਜਣ ਅਤੇ ਪà©à¨°à¨¾à¨ªà¨¤ ਕਰਨ ਤੋਂ ਪਹਿਲਾਂ ਪà©à©±à¨›à©‹ (ਸਿਫ਼ਾਰਸ਼ੀ)</translation>
<translation id="5719847187258001597">ਇੰਠਕਰਨ ਨਾਲ ਤà©à¨¹à¨¾à¨¡à©€ ਹੋਮ ਸਕà©à¨°à©€à¨¨ 'ਤੇ <ph name="ORIGIN" /> ਜਾਂ ਉਸਦੀ à¨à¨ª ਵੱਲੋਂ ਸਟੋਰ ਕੀਤੇ ਸਾਰੇ ਡਾਟੇ ਅਤੇ ਕà©à¨•à©€à¨œà¨¼ ਨੂੰ ਕਲੀਅਰ ਕਰ ਦਿੱਤਾ ਜਾਵੇਗਾ।</translation>
<translation id="5771720122942595109"><ph name="PERMISSION_1" /> ਨੂੰ ਬਲਾਕ ਕੀਤਾ ਗਿਆ</translation>
<translation id="5804241973901381774">ਅਨà©à¨®à¨¤à©€à¨†à¨‚</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">ਪਲੇ ਕਰੋ</translation>
<translation id="6818926723028410516">ਆਈਟਮਾਂ ਚà©à¨£à©‹</translation>
<translation id="6864395892908308021">ਇਹ ਡੀਵਾਈਸ NFC ਨੂੰ ਨਹੀਂ ਪੜà©à¨¹ ਸਕਦਾ</translation>
-<translation id="6910211073230771657">ਮਿਟਾਇਆ ਗਿਆ</translation>
<translation id="6912998170423641340">ਸਾਈਟਾਂ ਨੂੰ ਕਲਿੱਪਬੋਰਡ ਤੋਂ ਲਿਖਤ ਪੜà©à¨¹à¨¨ ਅਤੇ ਚਿੱਤਰ ਦੇਖਣ ਤੋਂ ਬਲਾਕ ਕਰੋ</translation>
<translation id="6945221475159498467">ਚà©à¨£à©‹</translation>
<translation id="6965382102122355670">ਠੀਕ</translation>
+<translation id="6981982820502123353">ਪਹà©à©°à¨šà¨¯à©‹à¨—ਤਾ</translation>
<translation id="6992289844737586249">ਸਾਈਟਾਂ ਨੂੰ ਤà©à¨¹à¨¾à¨¡à©‡ ਮਾਈਕà©à¨°à©‹à¨«à©‹à¨¨ ਦੀ ਵਰਤੋਂ ਕਰਨ ਤੋਂ ਪਹਿਲਾਂ ਤà©à¨¹à¨¾à¨¡à©€ ਇਜਾਜ਼ਤ ਲੈਣ ਨੂੰ ਜ਼ਰੂਰੀ ਬਣਾਓ (ਸਿਫ਼ਾਰਸ਼ੀ)</translation>
<translation id="7000754031042624318">Android ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਬੰਦ ਕੀਤੀ ਗਈ</translation>
<translation id="7016516562562142042">ਮੌਜੂਦਾ ਖੋਜ ਇੰਜਣ ਲਈ ਇਜਾਜ਼ਤ ਹੈ</translation>
+<translation id="702463548815491781">TalkBack ਜਾਂ 'ਸਵਿੱਚ ਪਹà©à©°à¨š' ਦੇ ਚਾਲੂ ਹੋਣ 'ਤੇ ਸਿਫ਼ਾਰਸ਼ ਕੀਤੀ ਜਾਂਦੀ ਹੈ</translation>
<translation id="7053983685419859001">ਬਲੌਕ ਕਰੋ</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1 ਚà©à¨£à©€ ਗਈ}one{# ਚà©à¨£à©€ ਗਈ}other{# ਚà©à¨£à©€à¨†à¨‚ ਗਈਆਂ}}</translation>
-<translation id="7070090581017165256">ਇਸ ਸਾਈਟ ਬਾਰੇ</translation>
<translation id="7087918508125750058"><ph name="ITEM_COUNT" /> ਨੂੰ ਚà©à¨£à¨¿à¨† ਗਿਆ। ਸਕà©à¨°à©€à¨¨ ਦੇ ਸਿਖਰ ਨੇੜੇ ਵਿਕਲਪ ਉਪਲਬਧ ਹਨ</translation>
<translation id="7141896414559753902">ਸਾਈਟਾਂ ਨੂੰ ਪੌਪ-ਅੱਪ ਅਤੇ ਰੀਡਾਇਰੈਕਟ ਦਿਖਾਉਣ ਤੋਂ ਬਲਾਕ ਕਰੋ (ਸਿਫ਼ਾਰਸ਼ੀ)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> KB</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">ਕੋਈ ਸਾਈਟ ਤà©à¨¹à¨¾à¨¡à¨¾ ਮਾਈਕà©à¨°à©‹à¨«à¨¼à©‹à¨¨ ਵਰਤ ਰਹੀ ਹੈ</translation>
<translation id="7561196759112975576">ਹਮੇਸ਼ਾਂ</translation>
-<translation id="7572498721684305250">ਤà©à¨¹à¨¾à¨¡à©‡ ਵੱਲੋਂ NFC ਡੀਵਾਈਸਾਂ 'ਤੇ ਟੈਪ ਕਰਨ ਵੇਲੇ ਜਾਣਕਾਰੀ ਭੇਜਣ ਜਾਂ ਪà©à¨°à¨¾à¨ªà¨¤ ਕਰਨ ਤੋਂ ਸਾਈਟਾਂ ਨੂੰ ਬਲਾਕ ਕਰੋ</translation>
<translation id="757524316907819857">ਸਾਈਟਾਂ ਨੂੰ ਸà©à¨°à©±à¨–ਿਅਤ ਸਮੱਗਰੀ ਚਲਾਉਣ ਤੋਂ ਬਲਾਕ ਕਰੋ</translation>
+<translation id="7577900504646297215">ਦਿਲਚਸਪੀਆਂ ਦਾ ਪà©à¨°à¨¬à©°à¨§à¨¨ ਕਰੋ</translation>
<translation id="7649070708921625228">ਸਹਾਇਤਾ</translation>
<translation id="7658239707568436148">ਰੱਦ ਕਰੋ</translation>
<translation id="7781829728241885113">ਕੱਲà©à¨¹</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">ਕਨੈਕਸ਼ਨ ਸà©à¨°à©±à¨–ਿਅਤ ਹੈ</translation>
<translation id="8249310407154411074">ਸਿਖਰ 'ਤੇ ਲੈ ਜਾਓ</translation>
<translation id="8261506727792406068">ਮਿਟਾਓ</translation>
+<translation id="8284326494547611709">ਸà©à¨°à¨–ੀਆਂ</translation>
<translation id="8300705686683892304">à¨à¨ª ਵੱਲੋਂ ਪà©à¨°à¨¬à©°à¨§à¨¿à¨¤</translation>
<translation id="8324158725704657629">ਦà©à¨¬à¨¾à¨°à¨¾ ਨਾ ਪà©à©±à¨›à©‹</translation>
<translation id="8372893542064058268">ਇੱਕ ਖ਼ਾਸ ਸਾਈਟ ਲਈ ਬੈਕਗà©à¨°à¨¾à¨Šà¨‚ਡ ਸਿੰਕ ਦੀ ਆਗਿਆ ਦਿਓ।</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">ਜ਼ੂਮ ਵਧਾਓ</translation>
<translation id="8921772741368021346"><ph name="POSITION" /> / <ph name="DURATION" /></translation>
<translation id="8926666909099850184">ਇਸ ਡੀਵਾਈਸ ਲਈ NFC ਬੰਦ ਹੈ। ਇਸਨੂੰ <ph name="BEGIN_LINK" />Android ਸੈਟਿੰਗਾਂ<ph name="END_LINK" /> ਵਿੱਚ ਚਾਲੂ ਕਰੋ।</translation>
+<translation id="8928445016601307354">ਸਾਈਟਾਂ ਨੂੰ NFC ਡੀਵਾਈਸਾਂ 'ਤੇ ਜਾਣਕਾਰੀ ਦੇਖਣ ਅਤੇ ਬਦਲਣ ਤੋਂ ਬਲਾਕ ਕਰੋ</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">ਕਿਸੇ ਖਾਸ ਸਾਈਟ ਲਈ ਕà©à¨•à©€à©› ਬਲਾਕ ਕਰੋ।</translation>
<translation id="8959122750345127698">ਨੈਵੀਗੇਸ਼ਨ ਨਾਪਹà©à©°à¨šà¨¯à©‹à¨— ਹੈ: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_pl.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_pl.xtb
index 42f80ffa97d..5566f1f2e1f 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_pl.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_pl.xtb
@@ -16,9 +16,10 @@
<translation id="1369915414381695676">Strona <ph name="SITE_NAME" /> została dodana</translation>
<translation id="1383876407941801731">Szukaj</translation>
<translation id="1384959399684842514">Pobieranie wstrzymane</translation>
+<translation id="1409426117486808224">Uproszczony widok otwartych kart</translation>
<translation id="1415402041810619267">URL obcięty</translation>
<translation id="1446450296470737166">Pełne sterowanie urządzeniami MIDI</translation>
-<translation id="1620510694547887537">Aparat</translation>
+<translation id="1620510694547887537">Kamera</translation>
<translation id="1644574205037202324">Historia</translation>
<translation id="1647582022260550163">Czy na pewno chcesz zresetować uprawnienia oraz wyczyścić pliki cookie i dane witryn?</translation>
<translation id="1660204651932907780">Zezwalaj na odtwarzanie dźwięku na stronach internetowych (zalecane)</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">Zezwalaj na pliki cookie</translation>
<translation id="2228071138934252756">Aby zezwolić aplikacji <ph name="APP_NAME" /> na dostęp do aparatu, musisz go też włączyć w <ph name="BEGIN_LINK" />Ustawieniach Androida<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Tylko raz</translation>
+<translation id="2253414712144136228">Usuń <ph name="NAME_OF_LIST_ITEM" /></translation>
<translation id="2289270750774289114">Pytaj, gdy strona chce wykryć urządzenia Bluetooth w pobliżu (zalecane)</translation>
<translation id="2315043854645842844">Wybieranie certyfikatu klienta nie jest obsługiwane przez ten system operacyjny.</translation>
+<translation id="2321958826496381788">Przeciągaj suwak, by umożliwić wygodne czytanie. Gdy dwukrotnie klikniesz akapit, tekst powiększy się co najmniej do tej wielkości.</translation>
<translation id="2359808026110333948">Dalej</translation>
<translation id="2379925928934107488">Stosuj ciemny motyw witryn w przypadkach, w których stosuje go Chrome, tam, gdzie to możliwe</translation>
+<translation id="2387895666653383613">Skalowanie tekstu</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Dozwolone: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i jeszcze <ph name="NUM_MORE" />}few{Dozwolone: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i jeszcze <ph name="NUM_MORE" />}many{Dozwolone: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i jeszcze <ph name="NUM_MORE" />}other{Dozwolone: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i jeszcze <ph name="NUM_MORE" />}}</translation>
<translation id="2434158240863470628">Ukończono pobieranie <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">Pokaż informacje</translation>
<translation id="3123473560110926937">Blokowane na niektórych stronach</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> zapisanych danych</translation>
+<translation id="3203366800380907218">Z sieci</translation>
<translation id="321187648315454507">Aby zezwolić aplikacji <ph name="APP_NAME" /> na wysyłanie do Ciebie powiadomień, musisz je też włączyć w <ph name="BEGIN_LINK" />ustawieniach Androida<ph name="END_LINK" />.</translation>
<translation id="3227137524299004712">Mikrofon</translation>
<translation id="3277252321222022663">Zezwalaj stronom na dostęp do czujników (zalecane)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">Korzystanie z urządzenia</translation>
<translation id="385051799172605136">Wstecz</translation>
<translation id="3859306556332390985">Przewiń do przodu</translation>
+<translation id="3895926599014793903">Wymuś powiększenie</translation>
<translation id="3955193568934677022">Zezwalaj stronom na odtwarzanie treści chronionej (zalecane)</translation>
<translation id="3967822245660637423">Pobieranie zakończone</translation>
<translation id="3987993985790029246">Skopiuj link</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> / ?</translation>
<translation id="4002066346123236978">Tytuł</translation>
<translation id="4008040567710660924">Zezwalaj na pliki cookie z określonej strony internetowej.</translation>
+<translation id="4040330681741629921">Otrzymuj powiadomienia, gdy witrynę można wyświetlić w widoku uproszczonym</translation>
<translation id="4046123991198612571">Następny utwór</translation>
+<translation id="4149994727733219643">Uproszczony widok stron internetowych</translation>
<translation id="4165986682804962316">Ustawienia witryn</translation>
+<translation id="4194328954146351878">Pytaj, zanim zezwolisz stronom na odczytywanie i zmienianie informacji na urządzeniach z funkcją NFC (zalecane)</translation>
<translation id="4200726100658658164">Otwórz ustawienia lokalizacji</translation>
<translation id="4226663524361240545">Powiadomienia będą sygnalizowane wibracjami</translation>
<translation id="4259722352634471385">Adres zablokowany: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">Rozwiń</translation>
<translation id="4336434711095810371">Wyczyść wszystkie dane</translation>
<translation id="4402755511846832236">Nie pozwalaj stronom sprawdzać, czy aktualnie używasz urządzenia</translation>
+<translation id="4428065317363009941">Personalizacja reklam</translation>
<translation id="4434045419905280838">Pop-upy i przekierowania</translation>
<translation id="445467742685312942">Zezwalaj stronom na odtwarzanie treści chronionych</translation>
<translation id="4468959413250150279">Wycisz dźwięk na konkretnej stronie.</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">Opcja dostępna u góry ekranu</translation>
<translation id="5197729504361054390">Wybrane kontakty zostaną udostępnione witrynie <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />.</translation>
<translation id="5216942107514965959">Ostatnio używana dzisiaj</translation>
+<translation id="5264323282659631142">UsuÅ„: „<ph name="CHIP_LABEL" />â€</translation>
<translation id="528192093759286357">Przeciągnij od góry i kliknij przycisk Wstecz, by wyjść z trybu pełnoekranowego.</translation>
<translation id="5300589172476337783">Pokaż</translation>
<translation id="5301954838959518834">Rozumiem</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">Spowoduje to usunięcie <ph name="DATASIZE" /> danych i plików cookie zapisanych przez strony.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(i jeszcze 1)}few{(i jeszcze #)}many{(i jeszcze #)}other{(i jeszcze #)}}</translation>
<translation id="5403592356182871684">Nazwy</translation>
+<translation id="5412236728747081950">Witryna korzysta z gromadzonych przez Chrome informacji o Twoich zainteresowaniach, aby wyświetlać trafniejsze reklamy</translation>
<translation id="5438097262470833822">Spowoduje to zresetowanie uprawnień witryny <ph name="WEBSITE" /></translation>
<translation id="5489227211564503167">Upłynęło: <ph name="ELAPSED_TIME" /> z <ph name="TOTAL_TIME" /></translation>
<translation id="5494752089476963479">Blokuj reklamy na stronach, które wyświetlają reklamy uciążliwe lub wprowadzające w błąd</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">Odśwież</translation>
<translation id="5596627076506792578">Więcej opcji</translation>
<translation id="5649053991847567735">Pobieranie automatyczne</translation>
+<translation id="5668404140385795438">Zignoruj żądanie strony, gdy chce zapobiec powiększeniu widoku</translation>
<translation id="5677928146339483299">Zablokowane</translation>
<translation id="5689516760719285838">Lokalizacja</translation>
<translation id="5690795753582697420">Kamera jest wyłączona w ustawieniach Androida</translation>
-<translation id="5710871682236653961">Pytaj, zanim zezwolisz stronom na wysyłanie i odbieranie informacji po dotknięciu urządzeń z funkcją NFC (zalecane)</translation>
<translation id="5719847187258001597">Spowoduje to usunięcie wszystkich danych i plików cookie zapisanych przez stronę <ph name="ORIGIN" /> lub jej aplikację na ekranie głównym.</translation>
<translation id="5771720122942595109">Zablokowane: <ph name="PERMISSION_1" /></translation>
<translation id="5804241973901381774">Uprawnienia</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">Odtwórz</translation>
<translation id="6818926723028410516">Wybierz elementy</translation>
<translation id="6864395892908308021">To urządzenie nie obsługuje NFC</translation>
-<translation id="6910211073230771657">Usunięto</translation>
<translation id="6912998170423641340">Zablokuj stronom możliwość odczytywania tekstu i obrazów ze schowka</translation>
<translation id="6945221475159498467">Wybierz</translation>
<translation id="6965382102122355670">OK</translation>
+<translation id="6981982820502123353">Ułatwienia dostępu</translation>
<translation id="6992289844737586249">Pytaj, zanim zezwolisz stronom na korzystanie z mikrofonu (zalecane)</translation>
<translation id="7000754031042624318">Wyłączone w ustawieniach Androida</translation>
<translation id="7016516562562142042">Zezwolono na dostęp obecnej wyszukiwarce</translation>
+<translation id="702463548815491781">Zalecane, gdy włączono TalkBack lub Switch Access</translation>
<translation id="7053983685419859001">Blokuj</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{Wybrano 1}few{Wybrano #}many{Wybrano #}other{Wybrano #}}</translation>
-<translation id="7070090581017165256">O tej witrynie</translation>
<translation id="7087918508125750058">Wybrano <ph name="ITEM_COUNT" />. Opcje dostępne na górze ekranu</translation>
<translation id="7141896414559753902">Blokuj wyskakujące okienka i przekierowania na stronach (zalecane)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> KB</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">Strona używa mikrofonu</translation>
<translation id="7561196759112975576">Zawsze</translation>
-<translation id="7572498721684305250">Nie zezwalaj stronom na wysyłanie i odbieranie informacji po dotknięciu urządzeń z funkcją NFC</translation>
<translation id="757524316907819857">Blokuj odtwarzanie treści chronionej na stronach</translation>
+<translation id="7577900504646297215">ZarzÄ…dzaj zainteresowaniami</translation>
<translation id="7649070708921625228">Pomoc</translation>
<translation id="7658239707568436148">Anuluj</translation>
<translation id="7781829728241885113">Wczoraj</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">Połączenie jest bezpieczne</translation>
<translation id="8249310407154411074">PrzenieÅ› na poczÄ…tek</translation>
<translation id="8261506727792406068">Usuń</translation>
+<translation id="8284326494547611709">Napisy</translation>
<translation id="8300705686683892304">ZarzÄ…dzane przez aplikacjÄ™</translation>
<translation id="8324158725704657629">Nie pytaj ponownie</translation>
<translation id="8372893542064058268">Zezwalaj na synchronizowanie w tle z określoną stroną.</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">Powiększ</translation>
<translation id="8921772741368021346"><ph name="POSITION" />/<ph name="DURATION" /></translation>
<translation id="8926666909099850184">Funkcja NFC na tym urządzeniu jest wyłączona. Włącz ją w <ph name="BEGIN_LINK" />Ustawieniach Androida<ph name="END_LINK" />.</translation>
+<translation id="8928445016601307354">Nie zezwalaj stronom na odczytywanie i zmienianie informacji na urządzeniach z funkcją NFC</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">Blokuj pliki cookie z określonej strony internetowej.</translation>
<translation id="8959122750345127698">Adres nieosiÄ…galny: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_pt-BR.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_pt-BR.xtb
index 5e11c9f4158..92eaf97d8db 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_pt-BR.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_pt-BR.xtb
@@ -3,7 +3,7 @@
<translationbundle lang="pt-BR">
<translation id="1006017844123154345">Abrir on-line</translation>
<translation id="1044891598689252897">Os sites funcionarão normalmente</translation>
-<translation id="1124090076051167250">Essa ação apagará <ph name="DATASIZE" /> de dados e cookies armazenados por sites ou apps na sua tela inicial.</translation>
+<translation id="1124090076051167250">Essa ação vai apagar <ph name="DATASIZE" /> de dados e cookies armazenados por sites ou apps na sua tela inicial.</translation>
<translation id="1178581264944972037">Pausar</translation>
<translation id="1181037720776840403">Remover</translation>
<translation id="1201402288615127009">Próxima</translation>
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">Site <ph name="SITE_NAME" /> adicionado</translation>
<translation id="1383876407941801731">Pesquisar</translation>
<translation id="1384959399684842514">Download pausado</translation>
+<translation id="1409426117486808224">Versão simplificada das guias abertas</translation>
<translation id="1415402041810619267">URL truncado</translation>
<translation id="1446450296470737166">Permitir controle total de dispositivos MIDI</translation>
<translation id="1620510694547887537">Câmera</translation>
@@ -23,7 +24,7 @@
<translation id="1647582022260550163">Tem certeza de que quer redefinir as permissões e apagar os cookies e dados do site?</translation>
<translation id="1660204651932907780">Permitir o áudio dos sites (recomendado)</translation>
<translation id="1677097821151855053">Os cookies e outros dados do site são usados para lembrar de você, por exemplo, para conectar sua conta ou personalizar anúncios. Para gerenciar os cookies de todos os sites, acesse <ph name="BEGIN_LINK" />Configurações<ph name="END_LINK" />.</translation>
-<translation id="1688867105868176567">Limpar dados do site?</translation>
+<translation id="1688867105868176567">Remover dados do site?</translation>
<translation id="169515064810179024">Impedir que sites acessem os sensores de movimento</translation>
<translation id="1717218214683051432">Sensores de movimento</translation>
<translation id="1743802530341753419">Perguntar antes de permitir que sites se conectem ao dispositivo (recomendado)</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">Permitir cookies</translation>
<translation id="2228071138934252756">Para permitir que o app <ph name="APP_NAME" /> acesse sua câmera, ative-a também nas <ph name="BEGIN_LINK" />configurações do Android<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Apenas uma vez</translation>
+<translation id="2253414712144136228">Remover <ph name="NAME_OF_LIST_ITEM" /></translation>
<translation id="2289270750774289114">Perguntar quando um site quer descobrir dispositivos Bluetooth nas proximidades (recomendado)</translation>
<translation id="2315043854645842844">A seleção de certificado do cliente não é compatível com o sistema operacional.</translation>
+<translation id="2321958826496381788">Arraste o controle deslizante até a leitura ficar confortável. Com o toque duplo em um parágrafo, o texto ficará pelo menos deste tamanho.</translation>
<translation id="2359808026110333948">Continuar</translation>
<translation id="2379925928934107488">Aplicar o tema escuro para sites, quando possível, ao usar o tema escuro no Chrome</translation>
+<translation id="2387895666653383613">Escala do texto</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Permitidas: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> e mais <ph name="NUM_MORE" />}one{Permitidas: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> e mais <ph name="NUM_MORE" />}other{Permitidas: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> e mais <ph name="NUM_MORE" />}}</translation>
<translation id="2434158240863470628">Download concluído <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -73,7 +77,7 @@
<translation id="2687403674020088961">Bloquear todos os cookies (não recomendado)</translation>
<translation id="2704606927547763573">Copiado</translation>
<translation id="2717722538473713889">Endereços de e-mail</translation>
-<translation id="2785051990912111074">Essa ação apagará os cookies de <ph name="WEBSITE" /></translation>
+<translation id="2785051990912111074">Essa ação vai apagar os cookies de <ph name="WEBSITE" /></translation>
<translation id="2822354292072154809">Tem certeza de que quer redefinir todas as permissões de site para <ph name="CHOSEN_OBJECT_NAME" />?</translation>
<translation id="2870560284913253234">Site</translation>
<translation id="2874939134665556319">Faixa anterior</translation>
@@ -82,13 +86,14 @@
<translation id="2913331724188855103">Permitir que os sites salvem e leiam os dados de arquivos "cookies" - que armazenam temporariamente o que você visitou na rede. (Recomendado)</translation>
<translation id="2932883381142163287">Denunciar abuso</translation>
<translation id="2968755619301702150">Leitor de certificados</translation>
-<translation id="300526633675317032">Essa ação apagará tudo, <ph name="SIZE_IN_KB" /> de dados de armazenamento de sites.</translation>
+<translation id="300526633675317032">Essa ação vai apagar tudo, <ph name="SIZE_IN_KB" /> de dados de armazenamento de sites.</translation>
<translation id="3008272652534848354">Redefinir permissões</translation>
<translation id="301521992641321250">Bloqueada automaticamente</translation>
<translation id="3114012059975132928">Player de vídeo</translation>
<translation id="3115898365077584848">Mostrar informações</translation>
<translation id="3123473560110926937">Bloqueados em alguns sites</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> de dados armazenados</translation>
+<translation id="3203366800380907218">Da Web</translation>
<translation id="321187648315454507">Para permitir que o app <ph name="APP_NAME" /> envie notificações, também é necessário ativá-las nas <ph name="BEGIN_LINK" />configurações do Android<ph name="END_LINK" />.</translation>
<translation id="3227137524299004712">Microfone</translation>
<translation id="3277252321222022663">Permitir que sites acessem os sensores (recomendado)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">Uso do seu dispositivo</translation>
<translation id="385051799172605136">Voltar</translation>
<translation id="3859306556332390985">Avançar</translation>
+<translation id="3895926599014793903">Forçar zoom</translation>
<translation id="3955193568934677022">Permitir que os sites mostrem conteúdo protegido (recomendado)</translation>
<translation id="3967822245660637423">Download concluído</translation>
<translation id="3987993985790029246">Copiar link</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> / ?</translation>
<translation id="4002066346123236978">Título</translation>
<translation id="4008040567710660924">Permita cookies de um site específico.</translation>
+<translation id="4040330681741629921">Receber uma notificação quando um site puder ser mostrado na visualização simplificada</translation>
<translation id="4046123991198612571">Próxima faixa</translation>
+<translation id="4149994727733219643">Versão simplificada das páginas da Web</translation>
<translation id="4165986682804962316">Configurações do site</translation>
+<translation id="4194328954146351878">Perguntar antes de permitir que sites vejam e mudem informações em dispositivos NFC (recomendado)</translation>
<translation id="4200726100658658164">Abrir as configurações de localização</translation>
<translation id="4226663524361240545">É possível que as notificações façam o dispositivo vibrar</translation>
<translation id="4259722352634471385">A Navegação GPS está bloqueada: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">Expandir</translation>
<translation id="4336434711095810371">Limpar todos os dados</translation>
<translation id="4402755511846832236">Impedir que sites saibam quando você está usando este dispositivo</translation>
+<translation id="4428065317363009941">Personalização de anúncios</translation>
<translation id="4434045419905280838">Pop-ups e redirecionamentos</translation>
<translation id="445467742685312942">Permitir que sites mostrem conteúdo protegido</translation>
<translation id="4468959413250150279">Desativar o som de um site específico.</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">Opção disponível perto da parte superior da tela</translation>
<translation id="5197729504361054390">Os contatos selecionados serão compartilhados com <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />.</translation>
<translation id="5216942107514965959">Última visita: hoje</translation>
+<translation id="5264323282659631142">Remover "<ph name="CHIP_LABEL" />"</translation>
<translation id="528192093759286357">Arraste a partir da parte superior e toque no botão "Voltar" para sair da tela cheia.</translation>
<translation id="5300589172476337783">Mostrar</translation>
<translation id="5301954838959518834">Ok, entendi</translation>
@@ -163,9 +174,10 @@
<translation id="5317780077021120954">Salvar</translation>
<translation id="5335288049665977812">Permitir que sites executem o JavaScript (recomendado)</translation>
<translation id="534295439873310000">Dispositivos NFC</translation>
-<translation id="5354152178998424783">Essa ação apagará <ph name="DATASIZE" /> de dados e cookies armazenados por sites.</translation>
+<translation id="5354152178998424783">Essa ação vai apagar <ph name="DATASIZE" /> de dados e cookies armazenados por sites.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(mais 1)}one{(mais #)}other{(mais #)}}</translation>
<translation id="5403592356182871684">Nomes</translation>
+<translation id="5412236728747081950">Este site acessa seus interesses no Chrome para mostrar anúncios mais relevantes</translation>
<translation id="5438097262470833822">Essa ação redefinirá as permissões de <ph name="WEBSITE" /></translation>
<translation id="5489227211564503167">Tempo decorrido: <ph name="ELAPSED_TIME" /> de <ph name="TOTAL_TIME" />.</translation>
<translation id="5494752089476963479">Bloquear anúncios em sites com publicidade invasiva ou enganosa</translation>
@@ -177,11 +189,11 @@
<translation id="5556459405103347317">Recarregar</translation>
<translation id="5596627076506792578">Mais opções</translation>
<translation id="5649053991847567735">Downloads automáticos</translation>
+<translation id="5668404140385795438">Aplicar zoom mesmo que o site tente impedir.</translation>
<translation id="5677928146339483299">Bloqueado</translation>
<translation id="5689516760719285838">Local</translation>
<translation id="5690795753582697420">A câmera está desativada nas configurações do Android</translation>
-<translation id="5710871682236653961">Perguntar antes de permitir que sites enviem e recebam informações quando você tocar em dispositivos NFC (recomendado)</translation>
-<translation id="5719847187258001597">Essa ação apagará todos os dados e cookies armazenados por <ph name="ORIGIN" /> ou pelo app dele na sua tela inicial.</translation>
+<translation id="5719847187258001597">Essa ação vai apagar todos os dados e cookies armazenados por <ph name="ORIGIN" /> ou pelo app dele na sua tela inicial.</translation>
<translation id="5771720122942595109">Bloqueada: <ph name="PERMISSION_1" /></translation>
<translation id="5804241973901381774">Permissões</translation>
<translation id="5860033963881614850">Desativado</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">Reproduzir</translation>
<translation id="6818926723028410516">Selecionar itens</translation>
<translation id="6864395892908308021">O dispositivo não consegue ler a NFC</translation>
-<translation id="6910211073230771657">Excluído</translation>
<translation id="6912998170423641340">Impedir que sites leiam textos e imagens da área de transferência</translation>
<translation id="6945221475159498467">Selecionar</translation>
<translation id="6965382102122355670">OK</translation>
+<translation id="6981982820502123353">Acessibilidade</translation>
<translation id="6992289844737586249">Perguntar antes de permitir que sites usem o microfone (recomendado)</translation>
<translation id="7000754031042624318">Desativada nas configurações do Android</translation>
<translation id="7016516562562142042">Permitido para o mecanismo de pesquisa atual</translation>
+<translation id="702463548815491781">Recomendado quando o TalkBack ou o acesso com interruptor estão ativados</translation>
<translation id="7053983685419859001">Bloquear</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1 selecionado}one{# selecionado}other{# selecionados}}</translation>
-<translation id="7070090581017165256">Sobre este site</translation>
<translation id="7087918508125750058"><ph name="ITEM_COUNT" /> itens selecionados. Opções disponíveis perto da parte superior da tela</translation>
<translation id="7141896414559753902">Impedir pop-ups e redirecionamento dos sites (recomendado)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> KB</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">Um site está usando seu microfone</translation>
<translation id="7561196759112975576">Sempre</translation>
-<translation id="7572498721684305250">Impedir que sites enviem e recebam informações quando você tocar em dispositivos NFC</translation>
<translation id="757524316907819857">Impedir que sites mostrem conteúdo protegido</translation>
+<translation id="7577900504646297215">Gerenciar interesses</translation>
<translation id="7649070708921625228">Ajuda</translation>
<translation id="7658239707568436148">Cancelar</translation>
<translation id="7781829728241885113">Ontem</translation>
@@ -279,7 +291,7 @@
<translation id="8068648041423924542">Não foi possível selecionar certificado.</translation>
<translation id="8087000398470557479">Este conteúdo é de <ph name="DOMAIN_NAME" />, veiculado pelo Google.</translation>
<translation id="8116925261070264013">Com som desativado</translation>
-<translation id="813082847718468539">Visualizar informações do site</translation>
+<translation id="813082847718468539">Ver informações do site</translation>
<translation id="8131740175452115882">Confirmar</translation>
<translation id="8154912474061769055">Os recursos de vários sites podem não funcionar</translation>
<translation id="8197286292360124385">Permitida: <ph name="PERMISSION_1" /></translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">A conexão é segura</translation>
<translation id="8249310407154411074">Mover para o início</translation>
<translation id="8261506727792406068">Excluir</translation>
+<translation id="8284326494547611709">Legendas</translation>
<translation id="8300705686683892304">Gerenciados por app</translation>
<translation id="8324158725704657629">Não perguntar novamente</translation>
<translation id="8372893542064058268">Permitir a sincronização em segundo plano para um site específico.</translation>
@@ -313,7 +326,7 @@
<translation id="8719283222052720129">Ative a permissão para o app <ph name="APP_NAME" /> nas <ph name="BEGIN_LINK" />configurações do Android<ph name="END_LINK" />.</translation>
<translation id="8725066075913043281">Tentar novamente</translation>
<translation id="8730621377337864115">Concluído</translation>
-<translation id="8737217482364735741">Essa ação apagará todos os dados e cookies armazenados por <ph name="ORIGIN" />.</translation>
+<translation id="8737217482364735741">Essa ação vai apagar todos os dados e cookies armazenados por <ph name="ORIGIN" />.</translation>
<translation id="8751914237388039244">Selecione uma imagem</translation>
<translation id="8801436777607969138">Bloquear JavaScript para um site específico.</translation>
<translation id="8816026460808729765">Impedir que sites acessem os sensores</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">Aumentar zoom</translation>
<translation id="8921772741368021346"><ph name="POSITION" /> / <ph name="DURATION" /></translation>
<translation id="8926666909099850184">A NFC está desativada neste dispositivo. Ative-a nas <ph name="BEGIN_LINK" />configurações do Android<ph name="END_LINK" />.</translation>
+<translation id="8928445016601307354">Impedir que sites vejam e mudem informações em dispositivos NFC</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">Bloqueie cookies de um site específico.</translation>
<translation id="8959122750345127698">A Navegação GPS está inacessível: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_pt-PT.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_pt-PT.xtb
index 89277fb364c..b191cd32743 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_pt-PT.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_pt-PT.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">Site <ph name="SITE_NAME" /> adicionado</translation>
<translation id="1383876407941801731">Pesquisar</translation>
<translation id="1384959399684842514">Transferência interrompida</translation>
+<translation id="1409426117486808224">Vista simplificada dos separadores abertos</translation>
<translation id="1415402041810619267">URL truncado</translation>
<translation id="1446450296470737166">Perm. controlo total dispo. MIDI</translation>
<translation id="1620510694547887537">Câmara</translation>
@@ -49,12 +50,15 @@
<translation id="2212565012507486665">Permitir cookies</translation>
<translation id="2228071138934252756">Para permitir que a app <ph name="APP_NAME" /> aceda à câmara, ative também a câmara nas <ph name="BEGIN_LINK" />Definições do Android<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Apenas uma vez</translation>
+<translation id="2253414712144136228"><ph name="NAME_OF_LIST_ITEM" /> Remover</translation>
<translation id="2289270750774289114">Perguntar quando um site pretende detetar dispositivos Bluetooth próximos (recomendado)</translation>
<translation id="2315043854645842844">O sistema operativo não suporta a seleção do certificado do lado do cliente.</translation>
+<translation id="2321958826496381788">Arraste o controlo de deslize até conseguir ler confortavelmente. O texto deve ter, pelo menos, este tamanho depois de tocar duas vezes num parágrafo.</translation>
<translation id="2359808026110333948">Continuar</translation>
<translation id="2379925928934107488">Aplique o tema escuro aos sites quando o Chrome utiliza o tema escuro, quando possível</translation>
+<translation id="2387895666653383613">Escala do texto</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
-<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> e mais <ph name="NUM_MORE" /> permitidas.}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, and <ph name="NUM_MORE" /> more allowed}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> e mais <ph name="NUM_MORE" /> permitidas.}}</translation>
+<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> e mais <ph name="NUM_MORE" /> permitidas.}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> e mais <ph name="NUM_MORE" /> permitidas.}}</translation>
<translation id="2434158240863470628">Transferência concluída: <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
<translation id="2442870161001914531">Peça sempre o site para computador</translation>
<translation id="2482878487686419369">Notificações</translation>
@@ -62,7 +66,7 @@
<translation id="2490684707762498678">Gerido por <ph name="APP_NAME" /></translation>
<translation id="2498359688066513246">Ajuda e comentários</translation>
<translation id="2501278716633472235">Voltar</translation>
-<translation id="2569468611847789653">{COOKIE_COUNT,plural, =1{1 cookie bloqueado}one{# cookie(s) bloqueado(s)}other{# cookies bloqueados}}</translation>
+<translation id="2569468611847789653">{COOKIE_COUNT,plural, =1{1 cookie bloqueado}other{# cookies bloqueados}}</translation>
<translation id="2570922361219980984">O acesso à localização também está desativado para este dispositivo. Ative-o nas <ph name="BEGIN_LINK" />Definições do Android<ph name="END_LINK" />.</translation>
<translation id="257931822824936280">Expandido. Clique para reduzir.</translation>
<translation id="2586657967955657006">Ãrea de transferência</translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">Mostrar informações</translation>
<translation id="3123473560110926937">Bloqueado em alguns sites.</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> de dados armazenados</translation>
+<translation id="3203366800380907218">Da Web</translation>
<translation id="321187648315454507">Para permitir que a app <ph name="APP_NAME" /> lhe envie notificações, ative também as notificações nas <ph name="BEGIN_LINK" />Definições do Android<ph name="END_LINK" />.</translation>
<translation id="3227137524299004712">Microfone</translation>
<translation id="3277252321222022663">Permitir que os sites acedam aos sensores (recomendado)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">A utilização do dispositivo</translation>
<translation id="385051799172605136">Anterior</translation>
<translation id="3859306556332390985">Procurar para a frente</translation>
+<translation id="3895926599014793903">Forçar ativação do zoom</translation>
<translation id="3955193568934677022">Permitir que os sites reproduzam conteúdo protegido (recomendado)</translation>
<translation id="3967822245660637423">Transferência concluída</translation>
<translation id="3987993985790029246">Cop. link</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" />/?</translation>
<translation id="4002066346123236978">Título</translation>
<translation id="4008040567710660924">Permita cookies para um site específico.</translation>
+<translation id="4040330681741629921">Receber uma notificação quando um site pode ser apresentado na vista simplificada</translation>
<translation id="4046123991198612571">Faixa seguinte</translation>
+<translation id="4149994727733219643">Vista simplificada de páginas Web</translation>
<translation id="4165986682804962316">Definições de sites</translation>
+<translation id="4194328954146351878">Perguntar antes de permitir que os sites vejam e alterem informações em dispositivos NFC (recomendado)</translation>
<translation id="4200726100658658164">Abrir definições de localização</translation>
<translation id="4226663524361240545">As notificações podem fazer com que o dispositivo vibre</translation>
<translation id="4259722352634471385">A navegação está bloqueada: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">Expandir</translation>
<translation id="4336434711095810371">Limpar todos os dados</translation>
<translation id="4402755511846832236">Impeça os sites de saberem quando está ativamente a utilizar este dispositivo.</translation>
+<translation id="4428065317363009941">Personalização de anúncios</translation>
<translation id="4434045419905280838">Pop-ups e redirecionamentos</translation>
<translation id="445467742685312942">Permitir que os sites reproduzam conteúdos protegidos</translation>
<translation id="4468959413250150279">Desative o som de um site específico.</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">Opção disponível junto à parte superior do ecrã</translation>
<translation id="5197729504361054390">Os contactos que selecionar serão partilhados com <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />.</translation>
<translation id="5216942107514965959">Última visita hoje</translation>
+<translation id="5264323282659631142">Remover "<ph name="CHIP_LABEL" />"</translation>
<translation id="528192093759286357">Arraste a partir da parte superior e toque no botão de retrocesso para sair do ecrã inteiro.</translation>
<translation id="5300589172476337783">Mostrar</translation>
<translation id="5301954838959518834">OK</translation>
@@ -164,8 +175,9 @@
<translation id="5335288049665977812">Permitir que os sites executem JavaScript (recomendado)</translation>
<translation id="534295439873310000">Dispositivos NFC</translation>
<translation id="5354152178998424783">Esta ação eliminará <ph name="DATASIZE" /> de dados e cookies armazenados pelos sites.</translation>
-<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(mais 1)}one{(mais #)}other{(mais #)}}</translation>
+<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(mais 1)}other{(mais #)}}</translation>
<translation id="5403592356182871684">Nomes</translation>
+<translation id="5412236728747081950">Este site obtém os seus interesses do Chrome para lhe mostrar anúncios mais relevantes</translation>
<translation id="5438097262470833822">Esta opção repõe as autorizações de <ph name="WEBSITE" /></translation>
<translation id="5489227211564503167">Tempo decorrido: <ph name="ELAPSED_TIME" /> de <ph name="TOTAL_TIME" />.</translation>
<translation id="5494752089476963479">Bloquear anúncios em sites que apresentam anúncios intrusivos ou enganadores</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">Recarregar</translation>
<translation id="5596627076506792578">Mais opções</translation>
<translation id="5649053991847567735">Transferências automáticas</translation>
+<translation id="5668404140385795438">Substituir pedido de um Website para evitar aumentar o zoom</translation>
<translation id="5677928146339483299">Bloqueado</translation>
<translation id="5689516760719285838">Local</translation>
<translation id="5690795753582697420">A câmara está desativada nas Definições do Android</translation>
-<translation id="5710871682236653961">Perguntar antes de permitir que os sites enviem e recebam informações quando toca em dispositivos NFC (recomendado)</translation>
<translation id="5719847187258001597">Esta ação limpa todos os dados e cookies armazenados por <ph name="ORIGIN" /> ou pela respetiva app no seu ecrã principal.</translation>
<translation id="5771720122942595109">Bloqueio de <ph name="PERMISSION_1" />.</translation>
<translation id="5804241973901381774">Permissões</translation>
@@ -214,7 +226,7 @@
<translation id="6447842834002726250">Cookies</translation>
<translation id="6527303717912515753">Partilhar</translation>
<translation id="6545864417968258051">Procura de Bluetooth</translation>
-<translation id="6552800053856095716">{PERMISSIONS_SUMMARY_BLOCKED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> e mais <ph name="NUM_MORE" /> bloqueadas.}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, and <ph name="NUM_MORE" /> more blocked}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> e mais <ph name="NUM_MORE" /> bloqueadas.}}</translation>
+<translation id="6552800053856095716">{PERMISSIONS_SUMMARY_BLOCKED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> e mais <ph name="NUM_MORE" /> bloqueadas.}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> e mais <ph name="NUM_MORE" /> bloqueadas.}}</translation>
<translation id="6554732001434021288">Última visita há <ph name="NUM_DAYS" /> dias</translation>
<translation id="6561560012278703671">Utilizar mensagens mais discretas (impede interrupções de pedidos de notificação)</translation>
<translation id="6593061639179217415">Site para computador</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">Reproduzir</translation>
<translation id="6818926723028410516">Selecionar itens</translation>
<translation id="6864395892908308021">Este dispositivo não suporta a tecnologia NFC.</translation>
-<translation id="6910211073230771657">Eliminado</translation>
<translation id="6912998170423641340">Impedir sites de lerem texto e imagens da área de transferência</translation>
<translation id="6945221475159498467">Selecionar</translation>
<translation id="6965382102122355670">OK</translation>
+<translation id="6981982820502123353">Acessibilidade</translation>
<translation id="6992289844737586249">Perguntar antes de permitir que os sites utilizem o microfone (recomendado)</translation>
<translation id="7000754031042624318">Desativada nas Definições do Android</translation>
<translation id="7016516562562142042">Permitido para o motor de pesquisa atual</translation>
+<translation id="702463548815491781">Recomendado quando o TalkBack ou o Acesso por comutador estão ativados.</translation>
<translation id="7053983685419859001">Bloquear</translation>
-<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1 selecionado}one{# selecionados}other{# selecionados}}</translation>
-<translation id="7070090581017165256">Acerca deste site</translation>
+<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1 selecionado}other{# selecionados}}</translation>
<translation id="7087918508125750058"><ph name="ITEM_COUNT" /> selecionado(s). Opções disponíveis junto à parte superior do ecrã.</translation>
<translation id="7141896414559753902">Impedir que os sites apresentem pop-ups e redirecionamentos (recomendado).</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> KB</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">Um site está a utilizar o seu microfone.</translation>
<translation id="7561196759112975576">Sempre</translation>
-<translation id="7572498721684305250">Impedir que os sites enviem e recebam informações quando toca em dispositivos NFC</translation>
<translation id="757524316907819857">Impedir que os sites reproduzam conteúdos protegidos</translation>
+<translation id="7577900504646297215">Gerir interesses</translation>
<translation id="7649070708921625228">Ajuda</translation>
<translation id="7658239707568436148">Cancelar</translation>
<translation id="7781829728241885113">Ontem</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">A ligação é segura</translation>
<translation id="8249310407154411074">Mover para o início</translation>
<translation id="8261506727792406068">Eliminar</translation>
+<translation id="8284326494547611709">Legendas</translation>
<translation id="8300705686683892304">Geridos por aplicação</translation>
<translation id="8324158725704657629">Não perguntar novamente</translation>
<translation id="8372893542064058268">Permitir Sincronização em segundo plano num site específico.</translation>
@@ -299,7 +312,7 @@
<translation id="8441146129660941386">Procurar para trás</translation>
<translation id="8444433999583714703">Para permitir que a app <ph name="APP_NAME" /> aceda à sua localização, ative também a localização nas <ph name="BEGIN_LINK" />Definições do Android<ph name="END_LINK" />.</translation>
<translation id="8447861592752582886">Revogar autorização do dispositivo</translation>
-<translation id="8451050538944905715">{NUM_SELECTED,plural, =1{1 cookie em utilização}one{# cookie(s) em utilização}other{# cookies em utilização}}</translation>
+<translation id="8451050538944905715">{NUM_SELECTED,plural, =1{1 cookie em utilização}other{# cookies em utilização}}</translation>
<translation id="8487700953926739672">Disponível offline</translation>
<translation id="848952951823693243">Peça sempre o site para dispositivos móveis</translation>
<translation id="851751545965956758">Impedir a ligação de sites a dispositivos</translation>
@@ -321,13 +334,14 @@
<translation id="8903921497873541725">Ampliar</translation>
<translation id="8921772741368021346"><ph name="POSITION" />/<ph name="DURATION" /></translation>
<translation id="8926666909099850184">O NFC está desativado para este dispositivo. Ative-o nas <ph name="BEGIN_LINK" />Definições do Android<ph name="END_LINK" />.</translation>
+<translation id="8928445016601307354">Impedir os sites de verem e alterarem informações em dispositivos NFC</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">Bloqueie cookies para um site específico.</translation>
<translation id="8959122750345127698">A navegação está inacessível: <ph name="URL" /></translation>
<translation id="8986362086234534611">Esquecer</translation>
<translation id="9019902583201351841">Gerido pelos teus pais</translation>
<translation id="9074739597929991885">Bluetooth</translation>
-<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> e mais <ph name="NUM_MORE" />.}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, and <ph name="NUM_MORE" /> more}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> e mais <ph name="NUM_MORE" />.}}</translation>
+<translation id="9109747640384633967">{PERMISSIONS_SUMMARY_MIXED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> e mais <ph name="NUM_MORE" />.}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> e mais <ph name="NUM_MORE" />.}}</translation>
<translation id="913657688200966289">Ative as autorizações para a app <ph name="APP_NAME" /> nas <ph name="BEGIN_LINK" />Definições do Android<ph name="END_LINK" />.</translation>
<translation id="9162462602695099906">Esta página é perigosa</translation>
<translation id="930525582205581608">Pretende esquecer este site?</translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ro.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ro.xtb
index 61a81fa804a..58fcedcc93b 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ro.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ro.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">Site-ul <ph name="SITE_NAME" /> a fost adăugat</translation>
<translation id="1383876407941801731">Caută</translation>
<translation id="1384959399684842514">Descărcare întreruptă</translation>
+<translation id="1409426117486808224">Afișare simplificată pentru filele deschise</translation>
<translation id="1415402041810619267">Adresă URL trunchiată</translation>
<translation id="1446450296470737166">Control complet dispozitive MIDI</translation>
<translation id="1620510694547887537">Cameră</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">Permite cookie-urile</translation>
<translation id="2228071138934252756">Pentru a permite aplicației <ph name="APP_NAME" /> să acceseze camera, activează camera și în <ph name="BEGIN_LINK" />Setările Android<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Numai o singură dată</translation>
+<translation id="2253414712144136228">Elimină <ph name="NAME_OF_LIST_ITEM" /></translation>
<translation id="2289270750774289114">Întreabă-mă când un site dorește să descopere dispozitive Bluetooth din apropiere (recomandat)</translation>
<translation id="2315043854645842844">Selectarea certificatelor pe partea de client nu este acceptată de sistemul de operare.</translation>
+<translation id="2321958826496381788">Trage cursorul până poți citi textul cu ușurință. Textul trebuie să fie cel puțin la fel de mare ca acesta după o atingere dublă pe un paragraf.</translation>
<translation id="2359808026110333948">Continuă</translation>
<translation id="2379925928934107488">Aplică tema întunecată pe site-uri când Chrome folosește tema întunecată, dacă este posibil</translation>
+<translation id="2387895666653383613">Scalarea textului</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> și încă <ph name="NUM_MORE" /> sunt permise}few{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> și încă <ph name="NUM_MORE" /> sunt permise}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> și încă <ph name="NUM_MORE" /> sunt permise}}</translation>
<translation id="2434158240863470628">Descărcare finalizată <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">Afișează informațiile</translation>
<translation id="3123473560110926937">Blocate pe anumite site-uri</translation>
<translation id="3198916472715691905">Date stocate: <ph name="STORAGE_AMOUNT" /></translation>
+<translation id="3203366800380907218">De pe web</translation>
<translation id="321187648315454507">Pentru a permite aplicației <ph name="APP_NAME" /> să îți trimită notificări, activează notificările și în <ph name="BEGIN_LINK" />Setările Android<ph name="END_LINK" />.</translation>
<translation id="3227137524299004712">Microfon</translation>
<translation id="3277252321222022663">Permite accesul site-urilor la senzori (recomandat)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">Folosirea dispozitivului</translation>
<translation id="385051799172605136">ÃŽnapoi</translation>
<translation id="3859306556332390985">Derulează înainte</translation>
+<translation id="3895926599014793903">Forțează activarea zoomului</translation>
<translation id="3955193568934677022">Permite site-urilor să redea conținutul protejat (recomandat)</translation>
<translation id="3967822245660637423">Descărcare finalizată</translation>
<translation id="3987993985790029246">Copiază linkul</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> / ?</translation>
<translation id="4002066346123236978">Titlu</translation>
<translation id="4008040567710660924">Permite cookie-uri pentru un anumit site.</translation>
+<translation id="4040330681741629921">Primește o notificare atunci când site-ul poate fi afișat într-o vizualizare simplificată</translation>
<translation id="4046123991198612571">Melodia următoare</translation>
+<translation id="4149994727733219643">Afișare simplificată pentru paginile web</translation>
<translation id="4165986682804962316">Setări pentru site-uri</translation>
+<translation id="4194328954146351878">Întreabă înainte de a permite site-urilor să vadă și să modifice informații de pe dispozitive NFC (recomandat)</translation>
<translation id="4200726100658658164">Deschide setările privind locația</translation>
<translation id="4226663524361240545">Notificările pot face dispozitivul să vibreze</translation>
<translation id="4259722352634471385">Navigarea este blocată: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">Extinde</translation>
<translation id="4336434711095810371">Șterge toate datele</translation>
<translation id="4402755511846832236">Împiedică site-urile să detecteze când folosești activ dispozitivul</translation>
+<translation id="4428065317363009941">Personalizarea anunțurilor</translation>
<translation id="4434045419905280838">Ferestre pop-up și redirecționări</translation>
<translation id="445467742685312942">Permite site-urilor să redea conținut protejat</translation>
<translation id="4468959413250150279">Dezactivează sunetul pentru un anumit site.</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">Opțiunea este disponibilă în partea de sus a ecranului</translation>
<translation id="5197729504361054390">Persoanele de contact pe care le selectezi vor fi trimise site-ului <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />.</translation>
<translation id="5216942107514965959">Accesat ultima dată azi</translation>
+<translation id="5264323282659631142">Elimină „<ph name="CHIP_LABEL" />â€</translation>
<translation id="528192093759286357">Trage din partea de sus și atinge butonul Înapoi pentru a ieși din ecranul complet.</translation>
<translation id="5300589172476337783">Afișează</translation>
<translation id="5301954838959518834">OK, am înțeles</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">Astfel, se vor șterge <ph name="DATASIZE" /> din datele și cookie-urile stocate de site-uri.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(+ încă 1)}few{(+ încă #)}other{(+ încă #)}}</translation>
<translation id="5403592356182871684">Nume</translation>
+<translation id="5412236728747081950">Acest site obține interesele tale din Chrome ca să-ți afișeze anunțuri mai relevante</translation>
<translation id="5438097262470833822">Astfel, se vor reseta permisiunile pentru <ph name="WEBSITE" /></translation>
<translation id="5489227211564503167">Timp scurs: <ph name="ELAPSED_TIME" /> din <ph name="TOTAL_TIME" />.</translation>
<translation id="5494752089476963479">Blochează anunțurile pe site-urile care afișează anunțuri deranjante sau înșelătoare</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">Reîncarcă</translation>
<translation id="5596627076506792578">Mai multe opțiuni</translation>
<translation id="5649053991847567735">Descărcări automate</translation>
+<translation id="5668404140385795438">Ignoră solicitarea unui site de a împiedica mărirea</translation>
<translation id="5677928146339483299">Blocat</translation>
<translation id="5689516760719285838">Locație</translation>
<translation id="5690795753582697420">Camera foto este dezactivată în setările Android</translation>
-<translation id="5710871682236653961">Întreabă înainte de a permite site-urilor să trimită și să primească informații când se ating dispozitive NFC (recomandat)</translation>
<translation id="5719847187258001597">Astfel, se vor șterge toate datele și cookie-urile stocate de <ph name="ORIGIN" /> sau de aplicația asociată de pe ecranul de pornire.</translation>
<translation id="5771720122942595109">S-a blocat <ph name="PERMISSION_1" /></translation>
<translation id="5804241973901381774">Permisiuni</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">Redă</translation>
<translation id="6818926723028410516">Selectează elementele</translation>
<translation id="6864395892908308021">Dispozitivul nu poate citi comunicările NFC</translation>
-<translation id="6910211073230771657">Șters</translation>
<translation id="6912998170423641340">Blochează accesul de citire a textului și imaginilor din clipboard pentru site-uri</translation>
<translation id="6945221475159498467">Selectează</translation>
<translation id="6965382102122355670">OK</translation>
+<translation id="6981982820502123353">Accesibilitate</translation>
<translation id="6992289844737586249">Întreabă înainte de a permite site-urilor să folosească microfonul (recomandat)</translation>
<translation id="7000754031042624318">Dezactivată din setările Android</translation>
<translation id="7016516562562142042">Se permite pentru motorul de căutare actual</translation>
+<translation id="702463548815491781">Recomandat atunci când este activată opțiunea TalkBack sau Acces prin comutare</translation>
<translation id="7053983685419859001">Blochează</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1 selectat}few{# selectate}other{# selectate}}</translation>
-<translation id="7070090581017165256">Despre acest site</translation>
<translation id="7087918508125750058"><ph name="ITEM_COUNT" /> selectate. Opțiunile sunt disponibile în partea de sus a ecranului</translation>
<translation id="7141896414559753902">Împiedică site-urile să afișeze ferestre pop-up și redirecționări (recomandat)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> KB</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">Un site folosește microfonul</translation>
<translation id="7561196759112975576">ÃŽntotdeauna</translation>
-<translation id="7572498721684305250">Blochează trimiterea și primirea informațiilor de la site-uri când se ating dispozitive NFC</translation>
<translation id="757524316907819857">Împiedică site-urile să redea conținutul protejat</translation>
+<translation id="7577900504646297215">Gestionează interesele</translation>
<translation id="7649070708921625228">Ajutor</translation>
<translation id="7658239707568436148">Anulează</translation>
<translation id="7781829728241885113">Ieri</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">Conexiunea este securizată</translation>
<translation id="8249310407154411074">Mută la început</translation>
<translation id="8261506727792406068">Șterge</translation>
+<translation id="8284326494547611709">Subtitrări</translation>
<translation id="8300705686683892304">Gestionate de aplicație</translation>
<translation id="8324158725704657629">Nu mai întreba</translation>
<translation id="8372893542064058268">Permite sincronizarea în fundal pentru un anumit site.</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">Mărește</translation>
<translation id="8921772741368021346"><ph name="POSITION" />/<ph name="DURATION" /></translation>
<translation id="8926666909099850184">NFC este dezactivat pentru acest dispozitiv. Activează-l în <ph name="BEGIN_LINK" />Setări Android<ph name="END_LINK" />.</translation>
+<translation id="8928445016601307354">Împiedică site-urile să vadă și să modifice informații de pe dispozitive NFC</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">Blochează cookie-urile pentru un anumit site.</translation>
<translation id="8959122750345127698">Navigarea nu este accesibilă: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ru.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ru.xtb
index 1b352b4eee3..03068d906b9 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ru.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ru.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">Добавлен Ñайт <ph name="SITE_NAME" /></translation>
<translation id="1383876407941801731">ПоиÑк</translation>
<translation id="1384959399684842514">Скачивание приоÑтановлено.</translation>
+<translation id="1409426117486808224">Упрощенный проÑмотр открытых вкладок</translation>
<translation id="1415402041810619267">URL укорочен</translation>
<translation id="1446450296470737166">Полный доÑтуп к управлению MIDI-уÑтройÑтвами</translation>
<translation id="1620510694547887537">Камера</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">Разрешить файлы cookie</translation>
<translation id="2228071138934252756">Чтобы у Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ "<ph name="APP_NAME" />" был доÑтуп к камере, включите ее в <ph name="BEGIN_LINK" />наÑтройках Android<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Однократно</translation>
+<translation id="2253414712144136228">Удалить пункт "<ph name="NAME_OF_LIST_ITEM" />"</translation>
<translation id="2289270750774289114">Запрашивать Ð´Ð»Ñ Ñайтов разрешение на поиÑк Bluetooth-уÑтройÑтв поблизоÑти (рекомендуетÑÑ)</translation>
<translation id="2315043854645842844">Сертификат, выбранный клиентом, не поддерживаетÑÑ Ð¾Ð¿ÐµÑ€Ð°Ñ†Ð¸Ð¾Ð½Ð½Ð¾Ð¹ ÑиÑтемой.</translation>
+<translation id="2321958826496381788">Перемещайте ползунок, пока текÑÑ‚ не Ñтанет удобным Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ. ПоÑле двойного Ð½Ð°Ð¶Ð°Ñ‚Ð¸Ñ Ð½Ð° абзац текÑÑ‚ должен быть такого размера.</translation>
<translation id="2359808026110333948">Продолжить</translation>
<translation id="2379925928934107488">ЕÑли Ñ‚Ñ‘Ð¼Ð½Ð°Ñ Ñ‚ÐµÐ¼Ð° активирована в Chrome, она будет иÑпользоватьÑÑ Ð´Ð»Ñ Ñайтов, когда Ñто возможно.</translation>
+<translation id="2387895666653383613">МаÑштабирование текÑта</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> МБ</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Разрешено: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> и ещё <ph name="NUM_MORE" />}one{Разрешено: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> и ещё <ph name="NUM_MORE" />}few{Разрешено: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> и ещё <ph name="NUM_MORE" />}many{Разрешено: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> и ещё <ph name="NUM_MORE" />}other{Разрешено: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> и ещё <ph name="NUM_MORE" />}}</translation>
<translation id="2434158240863470628">Скачивание завершено <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">Показать информацию</translation>
<translation id="3123473560110926937">Заблокировано на некоторых Ñайтах</translation>
<translation id="3198916472715691905">Ð’ памÑти занÑто: <ph name="STORAGE_AMOUNT" /></translation>
+<translation id="3203366800380907218">Из интернета</translation>
<translation id="321187648315454507">Чтобы получать ÑƒÐ²ÐµÐ´Ð¾Ð¼Ð»ÐµÐ½Ð¸Ñ Ð¸Ð· Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ "<ph name="APP_NAME" />", включите их в <ph name="BEGIN_LINK" />наÑтройках Android<ph name="END_LINK" />.</translation>
<translation id="3227137524299004712">Микрофон</translation>
<translation id="3277252321222022663">ПредоÑтавить Ñайтам доÑтуп к датчикам (рекомендуетÑÑ)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">ИÑпользование уÑтройÑтва</translation>
<translation id="385051799172605136">Ðазад</translation>
<translation id="3859306556332390985">Перемотать вперед</translation>
+<translation id="3895926599014793903">Принудительно изменÑÑ‚ÑŒ маÑштаб</translation>
<translation id="3955193568934677022">Разрешить Ñайтам воÑпроизводить защищенный контент (рекомендуетÑÑ)</translation>
<translation id="3967822245660637423">Скачивание завершено.</translation>
<translation id="3987993985790029246">Копировать ÑÑылку</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> из ?</translation>
<translation id="4002066346123236978">Ðазвание</translation>
<translation id="4008040567710660924">Разрешить определенному Ñайту ÑохранÑÑ‚ÑŒ файлы cookie</translation>
+<translation id="4040330681741629921">Показывать уведомление, еÑли Ð´Ð»Ñ Ñайта доÑтупен упрощенный проÑмотр</translation>
<translation id="4046123991198612571">Следующий трек</translation>
+<translation id="4149994727733219643">Упрощенный проÑмотр веб-Ñтраниц</translation>
<translation id="4165986682804962316">ÐаÑтройки Ñайтов</translation>
+<translation id="4194328954146351878">Запрашивать Ð´Ð»Ñ Ñайтов разрешение на доÑтуп к информации и ее изменение через NFC (рекомендуетÑÑ)</translation>
<translation id="4200726100658658164">Открыть наÑтройки геолокации</translation>
<translation id="4226663524361240545">Ð’Ð¸Ð±Ñ€Ð°Ñ†Ð¸Ñ Ð¿Ñ€Ð¸ получении уведомлений</translation>
<translation id="4259722352634471385">ÐÐ°Ð²Ð¸Ð³Ð°Ñ†Ð¸Ñ Ð·Ð°Ð±Ð»Ð¾ÐºÐ¸Ñ€Ð¾Ð²Ð°Ð½Ð°: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">Развернуть</translation>
<translation id="4336434711095810371">Удалить вÑе данные</translation>
<translation id="4402755511846832236">Блокировать передачу на Ñайты информации об иÑпользовании уÑтройÑтва</translation>
+<translation id="4428065317363009941">ПерÑÐ¾Ð½Ð°Ð»Ð¸Ð·Ð°Ñ†Ð¸Ñ Ñ€ÐµÐºÐ»Ð°Ð¼Ñ‹</translation>
<translation id="4434045419905280838">Ð’Ñплывающие окна и переадреÑациÑ</translation>
<translation id="445467742685312942">Разрешить Ñайтам воÑпроизводить защищенный контент</translation>
<translation id="4468959413250150279">Отключить звуки на определенном Ñайте</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">ДейÑтвие доÑтупно вверху Ñкрана</translation>
<translation id="5197729504361054390">Сайт <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> получит доÑтуп к выбранным контактам.</translation>
<translation id="5216942107514965959">ПоÑледнее поÑещение: ÑегоднÑ</translation>
+<translation id="5264323282659631142">Удалить Ñлемент "<ph name="CHIP_LABEL" />"</translation>
<translation id="528192093759286357">Чтобы выйти из полноÑкранного режима, проведите по Ñкрану Ñверху вниз и нажмите кнопку "Ðазад".</translation>
<translation id="5300589172476337783">Показать</translation>
<translation id="5301954838959518834">ОК</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">Будут удалены данные и файлы cookie (вÑего <ph name="DATASIZE" />), Ñохраненные Ñайтами.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(и ещё 1)}one{(и ещё #)}few{(и ещё #)}many{(и ещё #)}other{(и ещё #)}}</translation>
<translation id="5403592356182871684">Имена</translation>
+<translation id="5412236728747081950">Этот Ñайт иÑпользует информацию из Chrome о ваших интереÑах, чтобы показывать более подходÑщие рекламные объÑвлениÑ.</translation>
<translation id="5438097262470833822">Будут отозваны Ñ€Ð°Ð·Ñ€ÐµÑˆÐµÐ½Ð¸Ñ Ð´Ð»Ñ <ph name="WEBSITE" />.</translation>
<translation id="5489227211564503167">ПроÑмотрено <ph name="ELAPSED_TIME" /> из <ph name="TOTAL_TIME" />.</translation>
<translation id="5494752089476963479">Блокировать объÑÐ²Ð»ÐµÐ½Ð¸Ñ Ð½Ð° Ñайтах, которые показывают навÑзчивую или вводÑщую в заблуждение рекламу</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">Перезагрузить</translation>
<translation id="5596627076506792578">Ещё</translation>
<translation id="5649053991847567735">ÐвтоматичеÑкое Ñкачивание</translation>
+<translation id="5668404140385795438">Игнорировать запроÑÑ‹ Ñайтов на запрет маÑштабированиÑ</translation>
<translation id="5677928146339483299">Заблокировано</translation>
<translation id="5689516760719285838">Геоданные</translation>
<translation id="5690795753582697420">Камера выключена в наÑтройках Android.</translation>
-<translation id="5710871682236653961">Запрашивать Ð´Ð»Ñ Ñайтов разрешение на обмен информацией через NFC (рекомендуетÑÑ)</translation>
<translation id="5719847187258001597">Будут удалены вÑе данные и файлы cookie, которые Ñохранены Ñайтом <ph name="ORIGIN" /> или его приложением, добавленным на главный Ñкран.</translation>
<translation id="5771720122942595109">Заблокировано: <ph name="PERMISSION_1" /></translation>
<translation id="5804241973901381774">РазрешениÑ</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">ВоÑпроизвеÑти</translation>
<translation id="6818926723028410516">Выберите объекты</translation>
<translation id="6864395892908308021">Это уÑтройÑтво не поддерживает NFC.</translation>
-<translation id="6910211073230771657">Удалено</translation>
<translation id="6912998170423641340">Блокировать Ñайтам доÑтуп к текÑту и изображениÑм, Ñкопированным в буфер обмена</translation>
<translation id="6945221475159498467">Выбрать</translation>
<translation id="6965382102122355670">ОК</translation>
+<translation id="6981982820502123353">Спец. возможноÑти</translation>
<translation id="6992289844737586249">Запрашивать разрешение на доÑтуп к микрофону (рекомендуетÑÑ)</translation>
<translation id="7000754031042624318">Отключено в наÑтройках Android</translation>
<translation id="7016516562562142042">Открыт доÑтуп Ð´Ð»Ñ Ñ‚ÐµÐºÑƒÑ‰ÐµÐ¹ поиÑковой ÑиÑтемы</translation>
+<translation id="702463548815491781">Рекомендовано при включенных функциÑÑ… TalkBack и Switch Access</translation>
<translation id="7053983685419859001">Блокировать</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{Выбран 1 объект}one{Выбран # объект}few{Выбрано # объекта}many{Выбрано # объектов}other{Выбрано # объекта}}</translation>
-<translation id="7070090581017165256">О Ñайте</translation>
<translation id="7087918508125750058">Выбрано: <ph name="ITEM_COUNT" />. Меню находитÑÑ Ð² верхней чаÑти Ñкрана.</translation>
<translation id="7141896414559753902">Блокировать вÑплывающие окна и переадреÑацию на Ñайтах (рекомендуетÑÑ)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> КБ</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">Сайт иÑпользует ваш микрофон</translation>
<translation id="7561196759112975576">Ð’Ñегда</translation>
-<translation id="7572498721684305250">Запретить Ñайтам обмен информацией через NFC.</translation>
<translation id="757524316907819857">Запретить Ñайтам воÑпроизводить защищенный контент</translation>
+<translation id="7577900504646297215">Управление интереÑами</translation>
<translation id="7649070708921625228">Справка</translation>
<translation id="7658239707568436148">Отмена</translation>
<translation id="7781829728241885113">Вчера</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">БезопаÑное подключение</translation>
<translation id="8249310407154411074">ПеремеÑтить в начало</translation>
<translation id="8261506727792406068">Удалить</translation>
+<translation id="8284326494547611709">Субтитры</translation>
<translation id="8300705686683892304">Под управлением приложениÑ</translation>
<translation id="8324158725704657629">Больше не Ñпрашивать</translation>
<translation id="8372893542064058268">Разрешить фоновую Ñинхронизацию Ð´Ð»Ñ ÐºÐ¾Ð½ÐºÑ€ÐµÑ‚Ð½Ð¾Ð³Ð¾ Ñайта</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">Увеличить</translation>
<translation id="8921772741368021346"><ph name="POSITION" />/<ph name="DURATION" /></translation>
<translation id="8926666909099850184">Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ NFC на Ñтом уÑтройÑтве отключена. Включите ее в <ph name="BEGIN_LINK" />наÑтройках Android<ph name="END_LINK" />.</translation>
+<translation id="8928445016601307354">Запретить Ñайтам получать доÑтуп к информации и изменÑÑ‚ÑŒ ее через NFC</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">Блокировать файлы cookie Ð´Ð»Ñ Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð½Ð¾Ð³Ð¾ Ñайта.</translation>
<translation id="8959122750345127698">Страница не найдена: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_si.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_si.xtb
index 8be7a0dbee2..dc5f678b0f2 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_si.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_si.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">අඩවි <ph name="SITE_NAME" /> එක් කරන ලදී</translation>
<translation id="1383876407941801731">සොයන්න</translation>
<translation id="1384959399684842514">බà·à¶œà·à¶±à·“ම විරà·à¶¸à¶ºà·’</translation>
+<translation id="1409426117486808224">විවෘත ටà·à¶¶à·Š සඳහ෠සරල දසුනක්</translation>
<translation id="1415402041810619267">URL කපන ලදි</translation>
<translation id="1446450296470737166">MIDI උපà·à¶‚ගවල සම්පූර්ණ පà·à¶½à¶±à¶ºà¶§ ඉඩ දෙන්න</translation>
<translation id="1620510694547887537">කà·à¶¸à¶»à·à·€</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">කුකීවලට ඉඩ දෙන්න</translation>
<translation id="2228071138934252756"><ph name="APP_NAME" /> හට ඔබේ කà·à¶¸à¶»à·à·€à¶§ ප්â€à¶»à·€à·šà· වීමට ඉඩ දීමට, <ph name="BEGIN_LINK" />Android à·ƒà·à¶šà·ƒà·“ම්<ph name="END_LINK" /> තුළද කà·à¶¸à¶»à·à·€ ක්â€à¶»à·’යà·à¶­à·Šà¶¸à¶š කරන්න.</translation>
<translation id="2241634353105152135">හුදෙක් එක් වරක්</translation>
+<translation id="2253414712144136228"><ph name="NAME_OF_LIST_ITEM" /> ඉවත් කරන්න</translation>
<translation id="2289270750774289114">වෙබ් අඩවියකට අවට බ්ලූටූත් උපà·à¶‚ග සොය෠ගà·à¶±à·“මට අවà·à·Šâ€à¶º වූ විට අසන්න (නිර්දේà·à·’තයි)</translation>
<translation id="2315043854645842844">මෙහෙයුම් පද්ධතිය සේවà·à¶½à·à¶·à·“ පà·à¶­à·Šà¶­à·š සහතික තේරීමට සහà·à¶º නොදක්වයි.</translation>
+<translation id="2321958826496381788">මෙය පහසුවෙන් කියවිය à·„à·à¶šà·’ වන තෙක් ස්ලයිඩරය අදින්න. ඡේදය මත දෙවරක් තට්ටු කිරීමෙන් පසුව අකුරු අඩු à·€à·à¶ºà·™à¶±à·Š මෙතරම් වත් විà·à·à¶½ විය යුතුය.</translation>
<translation id="2359808026110333948">කරගෙන යන්න</translation>
<translation id="2379925928934107488">à·„à·à¶šà·’ විට, Chrome අඳුරු තේමà·à·€ භà·à·€à·’ත කරන විට අඩවිවලට අඳුරු තේමà·à·€ යොදන්න</translation>
+<translation id="2387895666653383613">පෙළ පරිමà·à¶«à¶º</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> සහ තව <ph name="NUM_MORE" />ක් ඉඩ දෙන ලදි}one{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> සහ තව <ph name="NUM_MORE" />ක් ඉඩ දෙන ලදි}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> සහ තව <ph name="NUM_MORE" />ක් ඉඩ දෙන ලදි}}</translation>
<translation id="2434158240863470628">බà·à¶œà·à¶±à·“ම සම්පූර්ණයි <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">තතු පෙන්වන්න</translation>
<translation id="3123473560110926937">සමහර වෙබ් අඩවිවල අවහිර කෙරේ</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> ගබඩ෠කළ දත්ත</translation>
+<translation id="3203366800380907218">වෙබය වෙතින්</translation>
<translation id="321187648315454507"><ph name="APP_NAME" /> හට ඔබට දà·à¶±à·”ම්දීම් එවීමට ඉඩ දීමට <ph name="BEGIN_LINK" />Android à·ƒà·à¶šà·ƒà·“ම්<ph name="END_LINK" /> තුළ දà·à¶±à·”ම්දීම්ද ක්â€à¶»à·’යà·à¶­à·Šà¶¸à¶š කරන්න.</translation>
<translation id="3227137524299004712">මයික්â€à¶»à·†à·à¶±à¶º:</translation>
<translation id="3277252321222022663">වෙබ් අඩවිවලට සංවේදක වෙත ප්â€à¶»à·€à·šà· වීමට ඉඩ දෙන්න (නිර්දේà·à·’තයි)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">ඔබගේ උපà·à¶‚ග භà·à·€à·’තය</translation>
<translation id="385051799172605136">ආපසු</translation>
<translation id="3859306556332390985">ඉදිරියට සොයන්න</translation>
+<translation id="3895926599014793903">විà·à·à¶½à¶±à¶º සක්â€à¶»à·’ය කිරීම බල කරන්න</translation>
<translation id="3955193568934677022">අඩවිවලට ආරක්ෂිත අන්තර්ගතය à·€à·à¶¯à¶±à¶º කිරීමට ඉඩ දෙන්න (නිර්දේà·à·’තයි)</translation>
<translation id="3967822245660637423">බà·à¶œà·à¶±à·“ම සම්පූර්ණයි</translation>
<translation id="3987993985790029246">සබà·à¶³à·’ය පිටපත් කරන්න</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> / ?</translation>
<translation id="4002066346123236978">සිරස්තලය</translation>
<translation id="4008040567710660924">නිà·à·Šà¶ à·’ත අඩවියක් සඳහ෠කුකීවලට ඉඩ දෙන්න.</translation>
+<translation id="4040330681741629921">අඩවියක් සරල කළ දසුනින් පෙන්විය à·„à·à¶šà·’ විට දà·à¶±à·”ම් දීම් ලබ෠ගන්න</translation>
<translation id="4046123991198612571">ඊළඟ ඛණ්ඩය</translation>
+<translation id="4149994727733219643">වෙබ් පිටු සඳහ෠සරල දසුනක්</translation>
<translation id="4165986682804962316">අඩවි à·ƒà·à¶šà·ƒà·”ම්</translation>
+<translation id="4194328954146351878">NFC උපà·à¶‚ගවල තොරතුරු බà·à¶½à·“මට සහ වෙනස් කිරීමට අඩවිවලට ඉඩ දීමට පෙර අසන්න (නිර්දේà·à·’තයි)</translation>
<translation id="4200726100658658164">ස්ථà·à¶± à·ƒà·à¶šà·ƒà·“ම් විවෘත කරන්න</translation>
<translation id="4226663524361240545">දà·à¶±à·”ම්දීම් උපà·à¶‚ගය කම්පනය කළ à·„à·à¶š</translation>
<translation id="4259722352634471385">සංචà·à¶½à¶±à¶º අවහිර කර ඇත: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">දිගහරින්න</translation>
<translation id="4336434711095810371">සියලු දත්ත හිස් කරන්න</translation>
<translation id="4402755511846832236">ඔබ මෙම උපà·à¶‚ගය සක්â€à¶»à·’යව භà·à·€à·’ත කරන විට දà·à¶± ගà·à¶±à·“මෙන් අඩවි අවහිර කරන්න</translation>
+<translation id="4428065317363009941">වෙළඳ දà·à¶±à·Šà·€à·“ම් පුද්ගලිකකරණය</translation>
<translation id="4434045419905280838">උත්පතන සහ හරව෠යà·à·€à·“ම්</translation>
<translation id="445467742685312942">මෙම වෙබ් අඩවියට ආරක්â€à·‚ිත අන්තර්ගතය ධà·à·€à¶± කිරීමට ඉඩ දෙන්න.</translation>
<translation id="4468959413250150279">නිà·à·Šà¶ à·’ත අඩවියක් සඳහ෠à·à¶¶à·Šà¶¯à¶º නිහඬ කරන්න.</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">තිරයේ ඉහළට ආසන්නව විකල්පය තිබේ</translation>
<translation id="5197729504361054390">ඔබ තේරූ සම්බන්ධත෠<ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> සමඟ බෙද෠ගනු ලà·à¶¶à·š.</translation>
<translation id="5216942107514965959">අද අවසන් වරට පිවිසි</translation>
+<translation id="5264323282659631142">'<ph name="CHIP_LABEL" />' ඉවත් කරන්න</translation>
<translation id="528192093759286357">ඉහළින් ඇද, පූර්ණ තිරයෙන් ඉවත් වීමට පිටුපස බොත්තම ස්පර්෠කරන්න.</translation>
<translation id="5300589172476337783">පෙන්වන්න</translation>
<translation id="5301954838959518834">හරි, එය තේරුණà·</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">මෙය වෙබ් අඩවිවලින් ගමන෠කරනු ලà·à¶¶à·– දත්ත සහ කුකී <ph name="DATASIZE" /> ක් ඉවත් කරයි.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(තවත් + 1ක්)}one{(තවත් + #ක්)}other{(තවත් + #ක්)}}</translation>
<translation id="5403592356182871684">නම්</translation>
+<translation id="5412236728747081950">මෙම අඩවිය ඔබට වඩà·à¶­à·Š අදà·à·… වෙළඳ දà·à¶±à·Šà·€à·“ම් පෙන්වීමට Chrome වෙතින් ඔබගේ ලà·à¶¯à·’කම් ලබ෠ගනී</translation>
<translation id="5438097262470833822">මෙම තේරීම <ph name="WEBSITE" /> සඳහ෠අවසර යළි සකසනු ඇත</translation>
<translation id="5489227211564503167">ගත වූ කà·à¶½à¶º <ph name="TOTAL_TIME" /> න් <ph name="ELAPSED_TIME" />.</translation>
<translation id="5494752089476963479">ආක්â€à¶»à¶¸à¶«à·à·“ලී හ෠නොමඟ යවන දà·à¶±à·Šà·€à·“ම් පෙන්වන වෙබ් අඩවි මත දà·à¶±à·Šà·€à·“ම් අවහිර කරන්න</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">නà·à·€à¶­</translation>
<translation id="5596627076506792578">තවත් විකල්ප</translation>
<translation id="5649053991847567735">ස්වයංක්â€à¶»à·“ය බà·à¶œà·à¶±à·“ම්</translation>
+<translation id="5668404140385795438">විà·à·à¶½à¶±à¶º à·€à·à¶©à·’ කිරීම සඳහ෠වෙබ් අඩවියෙහි ඉල්ලීමක් අතික්â€à¶»à¶¸à¶«à¶º කරන්න</translation>
<translation id="5677928146339483299">බà·à¶°à·à¶šà·…</translation>
<translation id="5689516760719285838">ස්ථà·à¶±à¶º</translation>
<translation id="5690795753582697420">Android à·ƒà·à¶šà·ƒà·“ම් තුළ කà·à¶¸à¶»à·à·€ අක්â€à¶»à·’ය කර ඇත</translation>
-<translation id="5710871682236653961">ඔබ NFC උපà·à¶‚ග තට්ටු කරන විට වෙබ් අඩවිවලට තොරතුරු යà·à·€à·“මට සහ ලà·à¶¶à·“මට ඉඩ දීමට පෙර අසන්න (නිර්දේà·à·’තයි)</translation>
<translation id="5719847187258001597">මෙය <ph name="ORIGIN" /> හ෠එහි යෙදුම විසින් ඔබේ මුල් තිරය මත ගබ෠කරනු ලà·à¶¶à·– සියලුම දත්ත සහ කුකී ඉවත් කරයි.</translation>
<translation id="5771720122942595109"><ph name="PERMISSION_1" /> අවහිර කරන ලදී</translation>
<translation id="5804241973901381774">අවසර</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">à·€à·à¶¯à¶±à¶º කරන්න</translation>
<translation id="6818926723028410516">අයිතම තà·à¶»à¶±à·Šà¶±</translation>
<translation id="6864395892908308021">මෙම උපà·à¶‚ගය NFC කියවිය නොහà·à¶š</translation>
-<translation id="6910211073230771657">මකà·à¶¯à·à¶¸à·–</translation>
<translation id="6912998170423641340">පසුරු පුවරුවෙන් පෙළ සහ රූප කියවීමෙන් අඩවි අවහිර කරන්න</translation>
<translation id="6945221475159498467">තà·à¶»à¶±à·Šà¶±</translation>
<translation id="6965382102122355670">හරි</translation>
+<translation id="6981982820502123353">ප්â€à¶»à·€à·šà·à·Šâ€à¶ºà¶­à·à·€</translation>
<translation id="6992289844737586249">අඩවි වලට ඔබගේ මයික්â€à¶»à·†à·à¶±à¶º භà·à·€à·’ත෠කිරීමට ඉඩ දීමට පෙර පළමුව විමසන්න (නිර්දේà·à·’තයි)</translation>
<translation id="7000754031042624318">Android à·ƒà·à¶šà·ƒà·“ම් තුළ අක්â€à¶»à·’ය කළà·</translation>
<translation id="7016516562562142042">වත්මන් සෙවුම් යන්ත්â€à¶»à¶º සඳහ෠ඉඩ දෙයි</translation>
+<translation id="702463548815491781">TalkBack හ෠ප්â€à¶»à·€à·šà·à¶º ස්විචය ක්â€à¶»à·’යà·à¶­à·Šà¶¸à¶š විට නිර්දේ෠කරනු ලà·à¶¶à·š</translation>
<translation id="7053983685419859001">අවහිර කරන්න</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1ක් තà·à¶»à¶± ලදී}one{#ක් තà·à¶»à¶± ලදී}other{#ක් තà·à¶»à¶± ලදී}}</translation>
-<translation id="7070090581017165256">මෙම අඩවිය ගà·à¶±</translation>
<translation id="7087918508125750058"><ph name="ITEM_COUNT" /> ක් තà·à¶»à¶± ලදි. තිරයේ ඉහළට ආසන්නව විකල්ප තිබේ</translation>
<translation id="7141896414559753902">උත්පතන සහ හරව෠යà·à·€à·“ම් පෙන්වීමෙන් අඩවි අවහිර කරන්න (නිර්දේà·à·’තයි)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> KB</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">වෙබ් අඩවියක් ඔබේ මයික්â€à¶»à·œà·†à·à¶±à¶º භà·à·€à·’ත කරයි</translation>
<translation id="7561196759112975576">à·ƒà·à¶¸à·€à·’ටම</translation>
-<translation id="7572498721684305250">ඔබ NFC උපà·à¶‚ග තට්ටු කරන විට වෙබ් අඩවිවලින් තොරතුරු යà·à·€à·“ම හ෠ලà·à¶¶à·“ම අවහිර කරන්න</translation>
<translation id="757524316907819857">ආරක්ෂිත අන්තර්ගත à·€à·à¶¯à¶±à¶º කරමින් තිබෙන අඩවි තහනම් කිරීම</translation>
+<translation id="7577900504646297215">ලà·à¶¯à·’කම් කළමන෠කරන්න</translation>
<translation id="7649070708921625228">උදවු</translation>
<translation id="7658239707568436148">අවලංගු කරන්න</translation>
<translation id="7781829728241885113">ඊයේ</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">සම්බන්ධතà·à·€à¶º ආරක්ෂිත වේ</translation>
<translation id="8249310407154411074">ඉහළට ගෙන යන්න</translation>
<translation id="8261506727792406068">මකන්න</translation>
+<translation id="8284326494547611709">සිරස්තල</translation>
<translation id="8300705686683892304">යෙදුමෙන් කළමන෠කෙරෙන</translation>
<translation id="8324158725704657629">නà·à·€à¶­ නොඅසන්න</translation>
<translation id="8372893542064058268">නිà·à·Šà¶ à·’ත අඩවියක් සඳහ෠පසුබිම සමමුහුර්ත කිරීමට ඉඩ දෙන්න.</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">විà·à·à¶½à¶±à¶º කරන්න</translation>
<translation id="8921772741368021346"><ph name="POSITION" /> / <ph name="DURATION" /></translation>
<translation id="8926666909099850184">මෙම උපà·à¶‚ගය සඳහ෠NFC අක්â€à¶»à·’යයි. <ph name="BEGIN_LINK" />Android à·ƒà·à¶šà·ƒà·“ම්<ph name="END_LINK" /> තුළින් එය සක්â€à¶»à·“ය කරන්න.</translation>
+<translation id="8928445016601307354">NFC උපà·à¶‚ගවල තොරතුරු බà·à¶½à·“මෙන් සහ වෙනස් කිරීමෙන් අඩවි අවහිර කරන්න</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">නිà·à·Šà¶ à·’ත අඩවියක් සඳහ෠කුකී අවහිර කරන්න.</translation>
<translation id="8959122750345127698">සංචà·à¶½à¶±à¶º වෙත ළඟ෠විය නොහà·à¶šà·’ය: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sk.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sk.xtb
index 8f5d53d11e3..dfc71ac4b82 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sk.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sk.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">Boli pridané stránky <ph name="SITE_NAME" /></translation>
<translation id="1383876407941801731">Vyhľadávanie</translation>
<translation id="1384959399684842514">Sťahovanie bolo pozastavené</translation>
+<translation id="1409426117486808224">Jednoduché zobrazenie otvorených kariet</translation>
<translation id="1415402041810619267">Skrátená webová adresa</translation>
<translation id="1446450296470737166">Povoliť úplné ovlád. zar. MIDI</translation>
<translation id="1620510694547887537">Kamera</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">Povoliť súbory cookie</translation>
<translation id="2228071138934252756">Ak chcete povoliť aplikácii <ph name="APP_NAME" /> používať váš fotoaparát, zapnite ho aj v <ph name="BEGIN_LINK" />nastaveniach Androidu<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Iba raz</translation>
+<translation id="2253414712144136228">Odobrať osobu alebo odstrániť položku <ph name="NAME_OF_LIST_ITEM" /></translation>
<translation id="2289270750774289114">OpýtaÅ¥ sa, keÄ chce web objavovaÅ¥ zariadenia Bluetooth v okolí (odporúÄané)</translation>
<translation id="2315043854645842844">OperaÄný systém nepodporuje výber certifikátu na strane klienta.</translation>
+<translation id="2321958826496381788">Presúvajte posúvaÄ, dokým nebude Äítanie tohto textu pohodlné. Po dvojitom klepnutí na odsek by mal byÅ¥ text aspoň takto veľký.</translation>
<translation id="2359808026110333948">PokraÄovaÅ¥</translation>
<translation id="2379925928934107488">Ak je to možné, používajte tmavý režim na weboch, keÄ ho používa Chrome</translation>
+<translation id="2387895666653383613">Mierka textu</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Sú udelené povolenia <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> a <ph name="NUM_MORE" /> ÄalÅ¡ie}few{Sú udelené povolenia <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> a <ph name="NUM_MORE" /> ÄalÅ¡ie}many{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, and <ph name="NUM_MORE" /> more allowed}other{Sú udelené povolenia <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> a <ph name="NUM_MORE" /> Äalších}}</translation>
<translation id="2434158240863470628">SÅ¥ahovanie bolo dokonÄené <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">Zobraziť informácie</translation>
<translation id="3123473560110926937">Blokované na niektorých weboch</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> uložených dát</translation>
+<translation id="3203366800380907218">Z webu</translation>
<translation id="321187648315454507">Ak chcete povoliť aplikácii <ph name="APP_NAME" /> odosielať vám upozornenia, zapnite ich aj v <ph name="BEGIN_LINK" />nastaveniach Androidu<ph name="END_LINK" />.</translation>
<translation id="3227137524299004712">Mikrofón</translation>
<translation id="3277252321222022663">PovoliÅ¥ webom prístup k senzorom (odporúÄané)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">Používanie vášho zariadenia</translation>
<translation id="385051799172605136">Späť</translation>
<translation id="3859306556332390985">PretoÄiÅ¥ dopredu</translation>
+<translation id="3895926599014793903">Vynútiť povolenie priblíženia</translation>
<translation id="3955193568934677022">PovoliÅ¥ webom prehrávaÅ¥ chránený obsah (odporúÄané)</translation>
<translation id="3967822245660637423">SÅ¥ahovanie dokonÄené</translation>
<translation id="3987993985790029246">Kopírovať odkaz</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> / ?</translation>
<translation id="4002066346123236978">Názov</translation>
<translation id="4008040567710660924">Povoliť súbory cookie na konkrétnom webe.</translation>
+<translation id="4040330681741629921">Dostávajte upozornenia, keÄ bude web dostupný v zjednoduÅ¡enom zobrazení</translation>
<translation id="4046123991198612571">Ďalšia skladba</translation>
+<translation id="4149994727733219643">Jednoduché zobrazenie webových stránok</translation>
<translation id="4165986682804962316">Nastavenia webu</translation>
+<translation id="4194328954146351878">PýtaÅ¥ sa, Äi chcete povoliÅ¥ webom zobrazovaÅ¥ a meniÅ¥ informácie v zariadeniach s rozhraním NFC (odprúÄané)</translation>
<translation id="4200726100658658164">Otvoriť nastavenia polohy</translation>
<translation id="4226663524361240545">Upozornenia môžu pri prijatí na zariadení spustiť vibrovanie</translation>
<translation id="4259722352634471385">Navigácia je zablokovaná: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">Rozbaliť</translation>
<translation id="4336434711095810371">Vymazať všetky dáta</translation>
<translation id="4402755511846832236">NeumožniÅ¥ webom zistiÅ¥, Äi aktívne používate toto zariadenie</translation>
+<translation id="4428065317363009941">Prispôsobenie reklám</translation>
<translation id="4434045419905280838">Vyskakovacie okná a presmerovania</translation>
<translation id="445467742685312942">Povoliť webom prehrávať chránený obsah</translation>
<translation id="4468959413250150279">Vypnúť zvuk na konkrétnom webe.</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">MožnosÅ¥ je k dispozícii v hornej Äasti obrazovky</translation>
<translation id="5197729504361054390">Vybrané kontakty budú zdieľané s webom <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />.</translation>
<translation id="5216942107514965959">Naposledy navštívený dnes</translation>
+<translation id="5264323282659631142">Odstrániť <ph name="CHIP_LABEL" /></translation>
<translation id="528192093759286357">Režim celej obrazovky ukonÄíte potiahnutím z hornej Äasti a klepnutím na tlaÄidlo Späť.</translation>
<translation id="5300589172476337783">Zobraziť</translation>
<translation id="5301954838959518834">Dobre</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">Týmto vymažete <ph name="DATASIZE" /> dát a súborov cookie uložených webmi.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(+ 1 ÄalÅ¡ie)}few{(+ # ÄalÅ¡ie)}many{(+ # more)}other{(+ # Äalších)}}</translation>
<translation id="5403592356182871684">Názvy</translation>
+<translation id="5412236728747081950">Chrome upozorní tento web na to, že sa oň zaujímate, a budú sa vám zobrazovať relevantné reklamy</translation>
<translation id="5438097262470833822">Týmto výberom resetujete povolenia pre web <ph name="WEBSITE" /></translation>
<translation id="5489227211564503167">Uplynutý Äas: <ph name="ELAPSED_TIME" /> z <ph name="TOTAL_TIME" />.</translation>
<translation id="5494752089476963479">Blokovať reklamy na weboch, ktoré zobrazujú obťažujúce alebo zavádzajúce reklamy</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">Znova naÄítaÅ¥</translation>
<translation id="5596627076506792578">Ďalšie možnosti</translation>
<translation id="5649053991847567735">Automatické sťahovanie</translation>
+<translation id="5668404140385795438">Ignorovať požiadavku webových stránok na zákaz priblíženia</translation>
<translation id="5677928146339483299">Blokované</translation>
<translation id="5689516760719285838">Poloha</translation>
<translation id="5690795753582697420">Fotoaparát je vypnutý v nastaveniach Androidu</translation>
-<translation id="5710871682236653961">PýtaÅ¥ sa, Äi chcete povoliÅ¥ webu posielaÅ¥ a prijímaÅ¥ informácie cez NFC (odporúÄané)</translation>
<translation id="5719847187258001597">Týmto vymažete všetky dáta a súbory cookie uložené webom <ph name="ORIGIN" /> alebo jeho aplikáciou na ploche.</translation>
<translation id="5771720122942595109">Blokované: <ph name="PERMISSION_1" /></translation>
<translation id="5804241973901381774">Povolenia</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">Prehrať</translation>
<translation id="6818926723028410516">Vyberte položky</translation>
<translation id="6864395892908308021">Toto zariadenie nedokáže ÄítaÅ¥ NFC</translation>
-<translation id="6910211073230771657">Odstránené</translation>
<translation id="6912998170423641340">Brániť webom v prístupe k textom a obrázkom v schránke</translation>
<translation id="6945221475159498467">Vybrať</translation>
<translation id="6965382102122355670">OK</translation>
+<translation id="6981982820502123353">Dostupnosť</translation>
<translation id="6992289844737586249">PýtaÅ¥ sa, Äi chcete povoliÅ¥ webu používaÅ¥ mikrofón (odporúÄané)</translation>
<translation id="7000754031042624318">Vypnuté v nastaveniach Androidu</translation>
<translation id="7016516562562142042">Povolené v aktuálnom vyhľadávaÄi</translation>
+<translation id="702463548815491781">OdporúÄané, keÄ je zapnutá aplikácia TalkBack alebo prístup s prepínaÄmi</translation>
<translation id="7053983685419859001">Blokovať</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1 vybratá položka}few{# vybraté položky}many{Niekoľko (#) vybratých položiek}other{# vybratých položiek}}</translation>
-<translation id="7070090581017165256">Tento web</translation>
<translation id="7087918508125750058">Vybrané: <ph name="ITEM_COUNT" />. Možnosti sú k dispozícii v hornej Äasti obrazovky.</translation>
<translation id="7141896414559753902">BrániÅ¥ webom otváraÅ¥ vyskakovacie okná a používaÅ¥ presmerovania (odporúÄané)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> kB</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">Váš mikrofón používa nejaký web</translation>
<translation id="7561196759112975576">Vždy</translation>
-<translation id="7572498721684305250">BrániÅ¥ webom posielaÅ¥ a prijímaÅ¥ údaje, keÄ sa dotknete zariadenia NFC</translation>
<translation id="757524316907819857">Brániť webom prehrávať chránený obsah</translation>
+<translation id="7577900504646297215">Spravovať záujmy</translation>
<translation id="7649070708921625228">Pomocník</translation>
<translation id="7658239707568436148">Zrušiť</translation>
<translation id="7781829728241885113">VÄera</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">Spojenie je zabezpeÄené</translation>
<translation id="8249310407154411074">Presunúť na zaÄiatok</translation>
<translation id="8261506727792406068">Odstrániť</translation>
+<translation id="8284326494547611709">Titulky</translation>
<translation id="8300705686683892304">Spravované aplikáciou</translation>
<translation id="8324158725704657629">Nabudúce sa nepýtať</translation>
<translation id="8372893542064058268">Povoliť synchronizáciu na pozadí na konkrétnom webe.</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">Priblížiť</translation>
<translation id="8921772741368021346"><ph name="POSITION" />/<ph name="DURATION" /></translation>
<translation id="8926666909099850184">Technológia NFC je v tomto zariadení vypnutá. Zapnite ju v <ph name="BEGIN_LINK" />Nastaveniach Androidu<ph name="END_LINK" />.</translation>
+<translation id="8928445016601307354">Zakázať webom zobrazovať a meniť informácie v zariadeniach s rozhraním NFC</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">Blokovať súbory cookie na konkrétnom webe.</translation>
<translation id="8959122750345127698">Navigácia je nedostupná: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sl.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sl.xtb
index a14da815186..e5d5b1ec369 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sl.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sl.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">Spletno mesto <ph name="SITE_NAME" /> je bilo dodano</translation>
<translation id="1383876407941801731">IÅ¡Äi</translation>
<translation id="1384959399684842514">Prenos je zaustavljen</translation>
+<translation id="1409426117486808224">Poenostavljen pogled za odprte zavihke</translation>
<translation id="1415402041810619267">URL je skrajšan</translation>
<translation id="1446450296470737166">Dovolitev popolnega nadzora nad napravami MIDI</translation>
<translation id="1620510694547887537">Kamera</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">Dovoli piškotke</translation>
<translation id="2228071138934252756">ÄŒe želite aplikaciji <ph name="APP_NAME" /> omogoÄiti dostop do fotoaparata, fotoaparat vklopite tudi v <ph name="BEGIN_LINK" />nastavitvah za Android<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Samo enkrat</translation>
+<translation id="2253414712144136228"><ph name="NAME_OF_LIST_ITEM" /> Odstrani</translation>
<translation id="2289270750774289114">VpraÅ¡aj, ko želi spletno mesto odkrivati naprave Bluetooth v bližini (priporoÄljivo)</translation>
<translation id="2315043854645842844">Operacijski sistem ne podpira izbire potrdila pri odjemalcu.</translation>
+<translation id="2321958826496381788">Drsnik povlecite tako daleÄ, da boste lahko to besedilo brez težave prebrali. Besedilo bo po dvakratnem dotiku odstavka vsaj tako veliko.</translation>
<translation id="2359808026110333948">Naprej</translation>
<translation id="2379925928934107488">Uporaba temne teme (ko je to mogoÄe) na spletnih mestih, Äe Chrome uporablja temno temo.</translation>
+<translation id="2387895666653383613">Prilagajanje velikosti besedila</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Dovoljeno: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> in Å¡e <ph name="NUM_MORE" />}one{Dovoljeno: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> in Å¡e <ph name="NUM_MORE" />}two{Dovoljeno: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> in Å¡e <ph name="NUM_MORE" />}few{Dovoljeno: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> in Å¡e <ph name="NUM_MORE" />}other{Dovoljeno: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> in Å¡e <ph name="NUM_MORE" />}}</translation>
<translation id="2434158240863470628">Prenos je konÄan <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">Pokaži informacije</translation>
<translation id="3123473560110926937">Blokirano na nekaterih spletnih mestih</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> shranjenih podatkov</translation>
+<translation id="3203366800380907218">Iz spleta</translation>
<translation id="321187648315454507">Če želite, da vam aplikacija <ph name="APP_NAME" /> pošilja obvestila, obvestila vklopite tudi v <ph name="BEGIN_LINK" />nastavitvah za Android<ph name="END_LINK" />.</translation>
<translation id="3227137524299004712">Mikrofon</translation>
<translation id="3277252321222022663">Spletnim mestom dovoli dostop do tipal (priporoÄeno)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">Uporaba naprave</translation>
<translation id="385051799172605136">Nazaj</translation>
<translation id="3859306556332390985">IÅ¡Äi naprej</translation>
+<translation id="3895926599014793903">Vsili poveÄavo</translation>
<translation id="3955193568934677022">Dovoli spletnim mestom predvajanje zaÅ¡Äitene vsebine (priporoÄeno)</translation>
<translation id="3967822245660637423">Prenos konÄan</translation>
<translation id="3987993985790029246">Kopiranje povezave</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" />/?</translation>
<translation id="4002066346123236978">Naslov</translation>
<translation id="4008040567710660924">OmogoÄanje piÅ¡kotkov za doloÄeno spletno mesto.</translation>
+<translation id="4040330681741629921">Prejmite obvestilo, ko je spletno mesto lahko prikazano v poenostavljenem pogledu.</translation>
<translation id="4046123991198612571">Naslednja skladba</translation>
+<translation id="4149994727733219643">Poenostavljen pogled za spletne strani</translation>
<translation id="4165986682804962316">Nastavitve spletnega mesta</translation>
+<translation id="4194328954146351878">VpraÅ¡aj, preden se spletnim mestom dovoli ogled in spreminjanje podatkov v napravah NFC (priporoÄeno)</translation>
<translation id="4200726100658658164">Odpri nastavitve lokacije</translation>
<translation id="4226663524361240545">Ob prejemanju obvestil naprava morda vibrira</translation>
<translation id="4259722352634471385">Krmarjenje je blokirano: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">Razširi</translation>
<translation id="4336434711095810371">Izbriši vse podatke</translation>
<translation id="4402755511846832236">PrepreÄevanje, da bi spletna mesta vedela, kdaj aktivno uporabljate to napravo.</translation>
+<translation id="4428065317363009941">Osebno prilagajanje oglasov</translation>
<translation id="4434045419905280838">Pojavna okna in preusmeritve</translation>
<translation id="445467742685312942">Spletnim mestom dovoli predvajanje zaÅ¡Äitene vsebine</translation>
<translation id="4468959413250150279">Izklop zvoka za doloÄeno spletno mesto.</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">Možnosti so na voljo blizu vrha zaslona</translation>
<translation id="5197729504361054390">Izbrani stiki bodo v skupni rabi s spletnim mestom <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />.</translation>
<translation id="5216942107514965959">Nazadnje obiskano danes</translation>
+<translation id="5264323282659631142">Odstranitev vnosa »<ph name="CHIP_LABEL" />«</translation>
<translation id="528192093759286357">Povlecite z vrha in se dotaknite gumba za nazaj, Äe želite zapreti celozaslonski naÄin.</translation>
<translation id="5300589172476337783">Pokaži</translation>
<translation id="5301954838959518834">V redu, razumem</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">S tem boste izbrisali <ph name="DATASIZE" /> podatkov in piškotkov, ki so jih shranila spletna mesta.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(in Å¡e 1)}one{(in Å¡e #)}two{(in Å¡e #)}few{(in Å¡e #)}other{(in Å¡e #)}}</translation>
<translation id="5403592356182871684">Imena</translation>
+<translation id="5412236728747081950">To spletno mesto pridobi vaša zanimanja iz Chroma, da vam pokaže ustreznejše oglase.</translation>
<translation id="5438097262470833822">S to izbiro bodo ponastavljena dovoljenja za spletno mesto <ph name="WEBSITE" />.</translation>
<translation id="5489227211564503167">PreteÄeni Äas: <ph name="ELAPSED_TIME" /> od <ph name="TOTAL_TIME" />.</translation>
<translation id="5494752089476963479">Blokiranje oglasov na spletnih mestih, ki prikazujejo vsiljive ali zavajajoÄe oglase</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">Znova naloži</translation>
<translation id="5596627076506792578">VeÄ možnosti</translation>
<translation id="5649053991847567735">Samodejni prenosi</translation>
+<translation id="5668404140385795438">Preglasi zahtevo spletnega mesta za prepreÄevanje poveÄave</translation>
<translation id="5677928146339483299">Blokirano</translation>
<translation id="5689516760719285838">Lokacija</translation>
<translation id="5690795753582697420">Fotoaparat je izklopljen v nastavitvah za Android</translation>
-<translation id="5710871682236653961">Poziv, preden se spletnim mestom dovoli poÅ¡iljanje in prejemanje podatkov, ko se dotaknete naprav s tehnologijo NFC (priporoÄeno)</translation>
<translation id="5719847187258001597">S tem boste izbrisali vse podatke in piÅ¡kotke, ki jih je shranilo spletno mesto <ph name="ORIGIN" /> ali njegova aplikacija na vaÅ¡em zaÄetnem zaslonu.</translation>
<translation id="5771720122942595109">Blokirano: <ph name="PERMISSION_1" /></translation>
<translation id="5804241973901381774">Dovoljenja</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">Predvajanje</translation>
<translation id="6818926723028410516">Izberite elemente</translation>
<translation id="6864395892908308021">Ta naprava ne podpira NFC-ja</translation>
-<translation id="6910211073230771657">Izbrisano</translation>
<translation id="6912998170423641340">Spletnim mestom prepreÄi branje besedila in slik v odložiÅ¡Äu</translation>
<translation id="6945221475159498467">Izberi</translation>
<translation id="6965382102122355670">V redu</translation>
+<translation id="6981982820502123353">Dostopnost</translation>
<translation id="6992289844737586249">Prikaži poziv, preden se spletnim mestom dovoli uporaba mikrofona (priporoÄeno)</translation>
<translation id="7000754031042624318">Izklopljeno v nastavitvah za Android</translation>
<translation id="7016516562562142042">Dovoljeno za trenutni iskalnik</translation>
+<translation id="702463548815491781">PriporoÄljivo, ko je vklopljena aplikacija TalkBack ali funkcija dostopa s stikalom</translation>
<translation id="7053983685419859001">Blokiraj</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1 izbran}one{# izbran}two{# izbrana}few{# izbrani}other{# izbranih}}</translation>
-<translation id="7070090581017165256">O tem spletnem mestu</translation>
<translation id="7087918508125750058">Št. izbranih: <ph name="ITEM_COUNT" />. Možnosti so na voljo na zgornjem delu zaslona.</translation>
<translation id="7141896414559753902">PrepreÄevanje, da spletna mesta prikazujejo pojavna okna in preusmeritve (priporoÄeno)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> KB</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">Spletno mesto uporablja mikrofon</translation>
<translation id="7561196759112975576">Vedno</translation>
-<translation id="7572498721684305250">Blokiranje, da spletna mesta pošiljajo in prejemajo podatke, ko se dotaknete naprav s tehnologijo NFC</translation>
<translation id="757524316907819857">PrepreÄi spletnim mestom predvajanje zaÅ¡Äitene vsebine</translation>
+<translation id="7577900504646297215">Upravljanje zanimanj</translation>
<translation id="7649070708921625228">PomoÄ</translation>
<translation id="7658239707568436148">PrekliÄi</translation>
<translation id="7781829728241885113">VÄeraj</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">Povezava je varna</translation>
<translation id="8249310407154411074">Na vrh</translation>
<translation id="8261506727792406068">Izbriši</translation>
+<translation id="8284326494547611709">Napisi</translation>
<translation id="8300705686683892304">Upravlja aplikacija</translation>
<translation id="8324158725704657629">Ne vpraÅ¡aj me veÄ</translation>
<translation id="8372893542064058268">Dovoli sinhroniziranje v ozadju za doloÄeno spletno mesto.</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">PoveÄaj</translation>
<translation id="8921772741368021346"><ph name="POSITION" />/<ph name="DURATION" /></translation>
<translation id="8926666909099850184">Tehnologija NFC je izklopljena za to napravo. Vklopite jo v <ph name="BEGIN_LINK" />nastavitvah za Android<ph name="END_LINK" />.</translation>
+<translation id="8928445016601307354">PrepreÄevanje ogleda in spreminjanja podatkov v napravah NFC spletnim mestom</translation>
<translation id="8941729603749328384">www.primer.si</translation>
<translation id="8958424370300090006">Blokiranje piÅ¡kotkov za doloÄeno spletno mesto.</translation>
<translation id="8959122750345127698">Krmarjenje ni dosegljivo: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sq.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sq.xtb
index 4ed7fc5ba10..d4b8a9b14ba 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sq.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sq.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">Sajti <ph name="SITE_NAME" /> u shtua</translation>
<translation id="1383876407941801731">Kërko</translation>
<translation id="1384959399684842514">Shkarkimi u ndërpre</translation>
+<translation id="1409426117486808224">Pamje e thjeshtuar për skedat e hapura</translation>
<translation id="1415402041810619267">URL e prerë</translation>
<translation id="1446450296470737166">Lejo kontrollin e plotë të pajisjeve MIDI</translation>
<translation id="1620510694547887537">Kamera</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">Lejo kukit</translation>
<translation id="2228071138934252756">Për të lejuar që <ph name="APP_NAME" /> të ketë qasje te kamera jote, aktivizo gjithashtu kamerën në <ph name="BEGIN_LINK" />Cilësimet e Android<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Vetëm një herë</translation>
+<translation id="2253414712144136228"><ph name="NAME_OF_LIST_ITEM" /> - Hiq</translation>
<translation id="2289270750774289114">Pyet kur një sajt dëshiron të zbulojë pajisjet Bluetooth në afërsi (rekomandohet)</translation>
<translation id="2315043854645842844">Përzgjedhja e certifikatës nga ana e klientit nuk mbështetet nga sistemi operativ.</translation>
+<translation id="2321958826496381788">Zvarrit rrëshqitësin derisa të arrish ta lexosh këtë pa u munduar. Teksti duhet të duket të paktën kaq i madh pas trokitjes dy herë mbi një paragraf.</translation>
<translation id="2359808026110333948">Vazhdo</translation>
<translation id="2379925928934107488">Kur është e mundur, zbato temën e errët për sajtet kur Chrome përdor temën e errët</translation>
+<translation id="2387895666653383613">Shkallëzimi i tekstit</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> dhe <ph name="NUM_MORE" /> tjetër e lejuar}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> dhe <ph name="NUM_MORE" /> të tjera të lejuara}}</translation>
<translation id="2434158240863470628">Shkarkimi përfundoi <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">Shfaq informacionin</translation>
<translation id="3123473560110926937">Bllokuar në disa sajte</translation>
<translation id="3198916472715691905">Të dhënat e ruajtura <ph name="STORAGE_AMOUNT" /></translation>
+<translation id="3203366800380907218">Nga uebi</translation>
<translation id="321187648315454507">Për të lejuar që <ph name="APP_NAME" /> të të dërgojë njoftime, aktivizo gjithashtu njoftimet në <ph name="BEGIN_LINK" />Cilësimet e Android<ph name="END_LINK" />.</translation>
<translation id="3227137524299004712">Mikrofoni</translation>
<translation id="3277252321222022663">Lejoju faqeve të të hapin sensorët (rekomandohet)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">Përdorimi i pajisjes sate</translation>
<translation id="385051799172605136">Prapa</translation>
<translation id="3859306556332390985">Kërko përpara</translation>
+<translation id="3895926599014793903">Aktivizo me detyrim zmadhimin</translation>
<translation id="3955193568934677022">Lejo që sajtet të luajnë përmbajtje të mbrojtur (rekomandohet)</translation>
<translation id="3967822245660637423">Shkarkimi përfundoi</translation>
<translation id="3987993985790029246">Kopjo lidhjen</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> / ?</translation>
<translation id="4002066346123236978">Titulli</translation>
<translation id="4008040567710660924">Lejo kukit për një sajt specifik.</translation>
+<translation id="4040330681741629921">Merr njoftime kur një sajt mund të shfaqet në pamje të thjeshtuar</translation>
<translation id="4046123991198612571">Kënga tjetër</translation>
+<translation id="4149994727733219643">Pamje e thjeshtuar për faqet e uebit</translation>
<translation id="4165986682804962316">Cilësimet e sajtit</translation>
+<translation id="4194328954146351878">Pyet përpara se të lejosh sajtet të shikojnë dhe ndryshojnë informacionin në pajisjet NFC (rekomandohet)</translation>
<translation id="4200726100658658164">Hap "Cilësimet e vendndodhjes"</translation>
<translation id="4226663524361240545">Njoftimet mund të bëjnë që pajisja të dridhet</translation>
<translation id="4259722352634471385">Lundrimi është bllokuar: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">Zgjero</translation>
<translation id="4336434711095810371">Pastro të gjitha të dhënat</translation>
<translation id="4402755511846832236">Blloko sajtet që të mos e dinë kur ti e përdor këtë pajisje në mënyrë aktive</translation>
+<translation id="4428065317363009941">Personalizimi i reklamave</translation>
<translation id="4434045419905280838">Dritaret kërcyese dhe ridrejtimet</translation>
<translation id="445467742685312942">Lejo sajtet të luajnë përmbajtje të mbrojtura</translation>
<translation id="4468959413250150279">Hiq zërin për një sajt specifik.</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">Opsionet ofrohen pranë kreut të ekranit</translation>
<translation id="5197729504361054390">Kontaktet që zgjedh do të ndahen me <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />.</translation>
<translation id="5216942107514965959">Vizituar për herë të fundit sot</translation>
+<translation id="5264323282659631142">Hiqe "<ph name="CHIP_LABEL" />"</translation>
<translation id="528192093759286357">Zvarrit nga lart dhe prek butonin e kthimit për të dalë nga ekrani i plotë.</translation>
<translation id="5300589172476337783">Shfaq</translation>
<translation id="5301954838959518834">Në rregull, kuptova.</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">Kjo do të pastrojë <ph name="DATASIZE" /> të dhëna dhe kuki të ruajtura nga sajtet.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(+ 1 tjetër)}other{(+ # të tjerë)}}</translation>
<translation id="5403592356182871684">Emrat</translation>
+<translation id="5412236728747081950">Ky sajt merr interesat e tua nga Chrome për të të shfaqur reklama më të përshtatshme</translation>
<translation id="5438097262470833822">Kjo zgjedhje do të rivendosë autorizimet për <ph name="WEBSITE" /></translation>
<translation id="5489227211564503167">Koha e kaluar: <ph name="ELAPSED_TIME" /> nga <ph name="TOTAL_TIME" />.</translation>
<translation id="5494752089476963479">Blloko reklamat në sajtet që shfaqin reklama ndërhyrëse ose mashtruese</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">Ringarko</translation>
<translation id="5596627076506792578">Më shumë opsione</translation>
<translation id="5649053991847567735">Shkarkimet automatike</translation>
+<translation id="5668404140385795438">Zëvendësoje kërkesën e një sajti uebi për të parandaluar zmadhimin</translation>
<translation id="5677928146339483299">Të bllokuara</translation>
<translation id="5689516760719285838">Vendndodhja</translation>
<translation id="5690795753582697420">Kamera është çaktivizuar në cilësimet e Android</translation>
-<translation id="5710871682236653961">Pyet përpara se sajtet të lejohen të dërgojnë dhe të marrin informacione kur troket pajisjet me NFC (rekomandohet)</translation>
<translation id="5719847187258001597">Kjo do të pastrojë të gjitha të dhënat dhe kukit e ruajtura nga <ph name="ORIGIN" /> ose nga aplikacioni i tij në ekranin bazë.</translation>
<translation id="5771720122942595109"><ph name="PERMISSION_1" /> është bllokuar</translation>
<translation id="5804241973901381774">Lejet</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">Luaj</translation>
<translation id="6818926723028410516">Zgjidh artikujt</translation>
<translation id="6864395892908308021">Kjo pajisje nuk mund të lexojë NFC-në</translation>
-<translation id="6910211073230771657">Fshirë</translation>
<translation id="6912998170423641340">Blloko sajtet që të mos lexojnë tekstin dhe imazhet nga kujtesa e fragmenteve</translation>
<translation id="6945221475159498467">Përzgjidhe</translation>
<translation id="6965382102122355670">Në rregull</translation>
+<translation id="6981982820502123353">Qasja</translation>
<translation id="6992289844737586249">Pyet përpara se sajtet të lejohen të përdorin mikrofonin (rekomandohet)</translation>
<translation id="7000754031042624318">E çaktivizuar te cilësimet e Android</translation>
<translation id="7016516562562142042">Lejuar për motorin aktual të kërkimit</translation>
+<translation id="702463548815491781">Rekomandohet kur është aktiv TalkBack ose "Qasja me çelës"</translation>
<translation id="7053983685419859001">Bllokoje</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1 i zgjedhur}other{# të zgjedhur}}</translation>
-<translation id="7070090581017165256">Rreth këtij sajti</translation>
<translation id="7087918508125750058"><ph name="ITEM_COUNT" /> të zgjedhura. Opsionet ofrohen pranë kreut të ekranit</translation>
<translation id="7141896414559753902">Blloko që sajtet të shfaqin dritare kërcyese dhe ridrejtime (rekomandohet)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> KB</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">Një sajt po përdor mikrofonin tënd</translation>
<translation id="7561196759112975576">Gjithmonë</translation>
-<translation id="7572498721684305250">Blloko sajtet që të mos dërgojnë dhe marrin informacione kur troket pajisjet me NFC</translation>
<translation id="757524316907819857">Blloko sajtet që të mos luajnë përmbajtje të mbrojtura</translation>
+<translation id="7577900504646297215">Menaxho interesat</translation>
<translation id="7649070708921625228">Ndihma</translation>
<translation id="7658239707568436148">Anulo</translation>
<translation id="7781829728241885113">Dje</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">Lidhja është e sigurt</translation>
<translation id="8249310407154411074">Lëvize në krye</translation>
<translation id="8261506727792406068">Fshi</translation>
+<translation id="8284326494547611709">Titrat</translation>
<translation id="8300705686683892304">Menaxhuar nga aplikacioni</translation>
<translation id="8324158725704657629">Mos pyet më</translation>
<translation id="8372893542064058268">Lejo "Sinkronizimin në sfond" për një sajt specifik.</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">Zmadho</translation>
<translation id="8921772741368021346"><ph name="POSITION" /> / <ph name="DURATION" /></translation>
<translation id="8926666909099850184">Veçoria NFC është joaktive për këtë pajisje. Aktivizoje te <ph name="BEGIN_LINK" />Cilësimet e Android<ph name="END_LINK" />.</translation>
+<translation id="8928445016601307354">Blloko sajtet që të mos shikojnë dhe ndryshojnë informacionin në pajisjet NFC</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">Blloko kukit për një sajt specifik.</translation>
<translation id="8959122750345127698">Lundrimi është i paarritshëm: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sr-Latn.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sr-Latn.xtb
index f62c1c087d9..84f5c7043f0 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sr-Latn.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sr-Latn.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">Sajt <ph name="SITE_NAME" /> je dodat</translation>
<translation id="1383876407941801731">Pretraži</translation>
<translation id="1384959399684842514">Preuzimanje je pauzirano</translation>
+<translation id="1409426117486808224">Pojednostavljen prikaz otvorenih kartica</translation>
<translation id="1415402041810619267">URL je skracÌen</translation>
<translation id="1446450296470737166">Puna kontrola nad MIDI uređajima</translation>
<translation id="1620510694547887537">Kamera</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">Dozvoli kolaÄicÌe</translation>
<translation id="2228071138934252756">Da biste dozvolili da <ph name="APP_NAME" /> pristupa kameri, ukljuÄite kameru i u <ph name="BEGIN_LINK" />Android podeÅ¡avanjima<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Samo jednom</translation>
+<translation id="2253414712144136228"><ph name="NAME_OF_LIST_ITEM" /> Uklonite</translation>
<translation id="2289270750774289114">Pitaj kada sajt želi da otkrije Bluetooth ureÄ‘aje u blizini (preporuÄeno)</translation>
<translation id="2315043854645842844">Operativni sistem ne podržava izbor sertifikata za klijenta.</translation>
+<translation id="2321958826496381788">PrevlaÄite klizaÄ dok ovo ne budete mogli lako da proÄitate. Kada dvaput dodirnete pasus, tekst treba da bude bar ovoliki.</translation>
<translation id="2359808026110333948">Nastavite</translation>
<translation id="2379925928934107488">Kada je to mogucÌe, tamna tema se primenjuje za sajtove kada je Chrome koristi</translation>
+<translation id="2387895666653383613">Promena veliÄine teksta</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Odobrene su dozvole <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i još <ph name="NUM_MORE" />}one{Odobrene su dozvole <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i još <ph name="NUM_MORE" />}few{Odobrene su dozvole <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i još <ph name="NUM_MORE" />}other{Odobrene su dozvole <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> i još <ph name="NUM_MORE" />}}</translation>
<translation id="2434158240863470628">Preuzimanje je završeno <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">Prikaži informacije</translation>
<translation id="3123473560110926937">Blokirano na nekim sajtovima</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> saÄuvanih podataka</translation>
+<translation id="3203366800380907218">Sa veba</translation>
<translation id="321187648315454507">Da biste dozvolili da vam <ph name="APP_NAME" /> Å¡alje obaveÅ¡tenja, ukljuÄite obaveÅ¡tenja i u <ph name="BEGIN_LINK" />Android podeÅ¡avanjima<ph name="END_LINK" />.</translation>
<translation id="3227137524299004712">Mikrofon</translation>
<translation id="3277252321222022663">Dozvoli sajtovima da pristupaju senzorima (preporuÄeno)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">KoriÅ¡cÌenje ureÄ‘aja</translation>
<translation id="385051799172605136">Nazad</translation>
<translation id="3859306556332390985">Premotaj unapred</translation>
+<translation id="3895926599014793903">Prinudno omogucÌi zumiranje</translation>
<translation id="3955193568934677022">Dozvoli sajtovima da puÅ¡taju zaÅ¡ticÌeni sadržaj (preporuÄeno)</translation>
<translation id="3967822245660637423">Preuzimanje je dovršeno</translation>
<translation id="3987993985790029246">Kopiraj link</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" />/?</translation>
<translation id="4002066346123236978">Naslov</translation>
<translation id="4008040567710660924">OmogucÌava kolaÄicÌe za odreÄ‘eni sajt.</translation>
+<translation id="4040330681741629921">Dobijte obaveštenje kada je pojednostavljeni prikaz dostupan za sajt</translation>
<translation id="4046123991198612571">SledecÌa pesma</translation>
+<translation id="4149994727733219643">Pojednostavljen prikaz veb-stranica</translation>
<translation id="4165986682804962316">Podešavanja sajta</translation>
+<translation id="4194328954146351878">Pre nego Å¡to dozvolite sajtovima da vide i menjaju informacije na NFC ureÄ‘ajima prikazuje se upit (preporuÄeno)</translation>
<translation id="4200726100658658164">Otvorite podešavanja lokacije</translation>
<translation id="4226663524361240545">UreÄ‘aj cÌe vibrirati kada primate obaveÅ¡tenja</translation>
<translation id="4259722352634471385">Navigacija je blokirana: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">Proširite</translation>
<translation id="4336434711095810371">Obriši sve podatke</translation>
<translation id="4402755511846832236">Ne dozvolite sajtovima da znaju kada aktivno koristite ovaj uređaj</translation>
+<translation id="4428065317363009941">Personalizacija oglasa</translation>
<translation id="4434045419905280838">IskaÄucÌi prozori i preusmeravanja</translation>
<translation id="445467742685312942">Dozvolite sajtovima da puÅ¡taju zaÅ¡ticÌeni sadržaj</translation>
<translation id="4468959413250150279">IskljuÄi zvuk za odreÄ‘eni sajt</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">Opcija je dostupna u vrhu ekrana</translation>
<translation id="5197729504361054390">Kontakti koje izaberete cÌe se deliti sa <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />.</translation>
<translation id="5216942107514965959">Poslednji posecÌen danas</translation>
+<translation id="5264323282659631142">Uklonite „<ph name="CHIP_LABEL" />“</translation>
<translation id="528192093759286357">Prevucite od vrha ekrana i dodirnite dugme Nazad da biste izašli iz režima celog ekrana.</translation>
<translation id="5300589172476337783">Prikaži</translation>
<translation id="5301954838959518834">Važi</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">Ovim briÅ¡ete <ph name="DATASIZE" /> podataka i kolaÄicÌa koje Äuvaju sajtovi.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(i još 1)}one{(i još #)}few{(i još #)}other{(i još #)}}</translation>
<translation id="5403592356182871684">Imena</translation>
+<translation id="5412236728747081950">Ovaj sajt prima podatke o vašim interesovanjima iz Chrome-a da bi vam prikazivao relevantnije oglase</translation>
<translation id="5438097262470833822">Ovaj izbor cÌe resetovati dozvole za <ph name="WEBSITE" /></translation>
<translation id="5489227211564503167">Proteklo vreme: <ph name="ELAPSED_TIME" /> od <ph name="TOTAL_TIME" />.</translation>
<translation id="5494752089476963479">Blokiraj oglase na sajtovima koji prikazuju oglase koji ometaju aktivnosti ili obmanjujucÌe oglase</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">UÄitaj ponovo</translation>
<translation id="5596627076506792578">Još opcija</translation>
<translation id="5649053991847567735">Automatska preuzimanja</translation>
+<translation id="5668404140385795438">Odbijanje zahteva veb-sajta da se spreÄi uvecÌavanje</translation>
<translation id="5677928146339483299">Blokirano</translation>
<translation id="5689516760719285838">Lokacija</translation>
<translation id="5690795753582697420">Kamera je iskljuÄena u Android podeÅ¡avanjima</translation>
-<translation id="5710871682236653961">Pre nego Å¡to dozvolite sajtovima da Å¡alju i dobijaju informacije kada dodirnete NFC ureÄ‘aje prikazuje se upit (preporuÄeno)</translation>
<translation id="5719847187258001597">Ovim briÅ¡ete sve podatke i kolaÄicÌe koje Äuva sajt <ph name="ORIGIN" /> ili njegova aplikacija na poÄetnom ekranu.</translation>
<translation id="5771720122942595109">Dozvola <ph name="PERMISSION_1" /> je blokirana</translation>
<translation id="5804241973901381774">Dozvole</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">Pusti</translation>
<translation id="6818926723028410516">Izaberite stavke</translation>
<translation id="6864395892908308021">Ovaj ureÄ‘aj ne može da Äita NFC</translation>
-<translation id="6910211073230771657">Izbrisano</translation>
<translation id="6912998170423641340">Blokiraj sajtove tako da ne Äitaju tekst i slike iz privremene memorije</translation>
<translation id="6945221475159498467">Izaberi</translation>
<translation id="6965382102122355670">Potvrdi</translation>
+<translation id="6981982820502123353">PristupaÄnost</translation>
<translation id="6992289844737586249">Pitaj pre nego Å¡to dozvoliÅ¡ sajtovima da koriste mikrofon (preporuÄeno)</translation>
<translation id="7000754031042624318">IskljuÄeno je u Android podeÅ¡avanjima</translation>
<translation id="7016516562562142042">Dozvoljeno je za aktuelni pretraživaÄ</translation>
+<translation id="702463548815491781">PreporuÄujemo vam kada ukljuÄite TalkBack ili pristup pomocÌu prekidaÄa</translation>
<translation id="7053983685419859001">Blokiraj</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{Izabrano: 1}one{Izabrano: #}few{Izabrano: #}other{Izabrano: #}}</translation>
-<translation id="7070090581017165256">O ovom sajtu</translation>
<translation id="7087918508125750058">Izabrali ste <ph name="ITEM_COUNT" />. Opcije su dostupne pri vrhu ekrana</translation>
<translation id="7141896414559753902">Blokiraj prikazivanje iskaÄucÌih prozora i preusmeravanja na sajtovima (preporuÄeno)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> kB</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">Sajt koristi mikrofon</translation>
<translation id="7561196759112975576">Uvek</translation>
-<translation id="7572498721684305250">Ne dozvoljava sajtovima da šalju i primaju informacije kada dodirnete NFC uređaje</translation>
<translation id="757524316907819857">Blokiraj da sajtovi puÅ¡taju zaÅ¡ticÌeni sadržaj</translation>
+<translation id="7577900504646297215">Upravljajte interesovanjima</translation>
<translation id="7649070708921625228">PomocÌ</translation>
<translation id="7658239707568436148">Otkaži</translation>
<translation id="7781829728241885113">JuÄe</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">Veza je bezbedna</translation>
<translation id="8249310407154411074">Premesti na vrh</translation>
<translation id="8261506727792406068">Izbriši</translation>
+<translation id="8284326494547611709">Titl</translation>
<translation id="8300705686683892304">Upravlja aplikacija</translation>
<translation id="8324158725704657629">Ne pitaj ponovo</translation>
<translation id="8372893542064058268">Dozvolite Sinhronizaciju u pozadini za određeni sajt.</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">UvecÌavanje</translation>
<translation id="8921772741368021346"><ph name="POSITION" />/<ph name="DURATION" /></translation>
<translation id="8926666909099850184">NFC je iskljuÄen za ovaj ureÄ‘aj. UkljuÄite ga u <ph name="BEGIN_LINK" />Android podeÅ¡avanjima<ph name="END_LINK" />.</translation>
+<translation id="8928445016601307354">SpreÄite sajtove da vide i menjaju informacije na NFC ureÄ‘ajima</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">Blokirajte kolaÄicÌe za odreÄ‘eni sajt.</translation>
<translation id="8959122750345127698">Navigacija je nedostupna: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sr.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sr.xtb
index 8f608eee7df..08404decd94 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sr.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sr.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">Сајт <ph name="SITE_NAME" /> је додат</translation>
<translation id="1383876407941801731">Претражи</translation>
<translation id="1384959399684842514">Преузимање је паузирано</translation>
+<translation id="1409426117486808224">ПоједноÑтављен приказ отворених картица</translation>
<translation id="1415402041810619267">URL је Ñкраћен</translation>
<translation id="1446450296470737166">Пуна контрола над MIDI уређајима</translation>
<translation id="1620510694547887537">Камера</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">Дозволи колачиће</translation>
<translation id="2228071138934252756">Да биÑте дозволили да <ph name="APP_NAME" /> приÑтупа камери, укључите камеру и у <ph name="BEGIN_LINK" />Android подешавањима<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Само једном</translation>
+<translation id="2253414712144136228"><ph name="NAME_OF_LIST_ITEM" /> Уклоните</translation>
<translation id="2289270750774289114">Питај када Ñајт жели да открије Bluetooth уређаје у близини (препоручено)</translation>
<translation id="2315043854645842844">Оперативни ÑиÑтем не подржава избор Ñертификата за клијента.</translation>
+<translation id="2321958826496381788">Превлачите клизач док ово не будете могли лако да прочитате. Када двапут додирнете паÑуÑ, текÑÑ‚ треба да буде бар оволики.</translation>
<translation id="2359808026110333948">ÐаÑтавите</translation>
<translation id="2379925928934107488">Када је то могуће, тамна тема Ñе примењује за Ñајтове када је Chrome кориÑти</translation>
+<translation id="2387895666653383613">Промена величине текÑта</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Одобрене Ñу дозволе <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> и још <ph name="NUM_MORE" />}one{Одобрене Ñу дозволе <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> и још <ph name="NUM_MORE" />}few{Одобрене Ñу дозволе <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> и још <ph name="NUM_MORE" />}other{Одобрене Ñу дозволе <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> и још <ph name="NUM_MORE" />}}</translation>
<translation id="2434158240863470628">Преузимање је завршено <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">Прикажи информације</translation>
<translation id="3123473560110926937">Блокирано на неким Ñајтовима</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> Ñачуваних података</translation>
+<translation id="3203366800380907218">Са веба</translation>
<translation id="321187648315454507">Да биÑте дозволили да вам <ph name="APP_NAME" /> шаље обавештења, укључите обавештења и у <ph name="BEGIN_LINK" />Android подешавањима<ph name="END_LINK" />.</translation>
<translation id="3227137524299004712">Микрофон</translation>
<translation id="3277252321222022663">Дозволи Ñајтовима да приÑтупају Ñензорима (препоручено)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">Коришћење уређаја</translation>
<translation id="385051799172605136">Ðазад</translation>
<translation id="3859306556332390985">Премотај унапред</translation>
+<translation id="3895926599014793903">Принудно омогући зумирање</translation>
<translation id="3955193568934677022">Дозволи Ñајтовима да пуштају заштићени Ñадржај (препоручено)</translation>
<translation id="3967822245660637423">Преузимање је довршено</translation>
<translation id="3987993985790029246">Копирај линк</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" />/?</translation>
<translation id="4002066346123236978">ÐаÑлов</translation>
<translation id="4008040567710660924">Омогућава колачиће за одређени Ñајт.</translation>
+<translation id="4040330681741629921">Добијте обавештење када је поједноÑтављени приказ доÑтупан за Ñајт</translation>
<translation id="4046123991198612571">Следећа пеÑма</translation>
+<translation id="4149994727733219643">ПоједноÑтављен приказ веб-Ñтраница</translation>
<translation id="4165986682804962316">Подешавања Ñајта</translation>
+<translation id="4194328954146351878">Пре него што дозволите Ñајтовима да виде и мењају информације на NFC уређајима приказује Ñе упит (препоручено)</translation>
<translation id="4200726100658658164">Отворите подешавања локације</translation>
<translation id="4226663524361240545">Уређај ће вибрирати када примате обавештења</translation>
<translation id="4259722352634471385">Ðавигација је блокирана: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">Проширите</translation>
<translation id="4336434711095810371">Обриши Ñве податке</translation>
<translation id="4402755511846832236">Ðе дозволите Ñајтовима да знају када активно кориÑтите овај уређај</translation>
+<translation id="4428065317363009941">ПерÑонализација оглаÑа</translation>
<translation id="4434045419905280838">ИÑкачући прозори и преуÑмеравања</translation>
<translation id="445467742685312942">Дозволите Ñајтовима да пуштају заштићени Ñадржај</translation>
<translation id="4468959413250150279">ИÑкључи звук за одређени Ñајт</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">Опција је доÑтупна у врху екрана</translation>
<translation id="5197729504361054390">Контакти које изаберете ће Ñе делити Ñа <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />.</translation>
<translation id="5216942107514965959">ПоÑледњи поÑећен данаÑ</translation>
+<translation id="5264323282659631142">Уклоните „<ph name="CHIP_LABEL" />“</translation>
<translation id="528192093759286357">Превуците од врха екрана и додирните дугме Ðазад да биÑте изашли из режима целог екрана.</translation>
<translation id="5300589172476337783">Прикажи</translation>
<translation id="5301954838959518834">Важи</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">Овим бришете <ph name="DATASIZE" /> података и колачића које чувају Ñајтови.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(и још 1)}one{(и још #)}few{(и још #)}other{(и још #)}}</translation>
<translation id="5403592356182871684">Имена</translation>
+<translation id="5412236728747081950">Овај Ñајт прима податке о вашим интереÑовањима из Chrome-а да би вам приказивао релевантније оглаÑе</translation>
<translation id="5438097262470833822">Овај избор ће реÑетовати дозволе за <ph name="WEBSITE" /></translation>
<translation id="5489227211564503167">Протекло време: <ph name="ELAPSED_TIME" /> од <ph name="TOTAL_TIME" />.</translation>
<translation id="5494752089476963479">Блокирај оглаÑе на Ñајтовима који приказују оглаÑе који ометају активноÑти или обмањујуће оглаÑе</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">Учитај поново</translation>
<translation id="5596627076506792578">Још опција</translation>
<translation id="5649053991847567735">ÐутоматÑка преузимања</translation>
+<translation id="5668404140385795438">Одбијање захтева веб-Ñајта да Ñе Ñпречи увећавање</translation>
<translation id="5677928146339483299">Блокирано</translation>
<translation id="5689516760719285838">Локација</translation>
<translation id="5690795753582697420">Камера је иÑкључена у Android подешавањима</translation>
-<translation id="5710871682236653961">Пре него што дозволите Ñајтовима да шаљу и добијају информације када додирнете NFC уређаје приказује Ñе упит (препоручено)</translation>
<translation id="5719847187258001597">Овим бришете Ñве податке и колачиће које чува Ñајт <ph name="ORIGIN" /> или његова апликација на почетном екрану.</translation>
<translation id="5771720122942595109">Дозвола <ph name="PERMISSION_1" /> је блокирана</translation>
<translation id="5804241973901381774">Дозволе</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">ПуÑти</translation>
<translation id="6818926723028410516">Изаберите Ñтавке</translation>
<translation id="6864395892908308021">Овај уређај не може да чита NFC</translation>
-<translation id="6910211073230771657">ИзбриÑано</translation>
<translation id="6912998170423641340">Блокирај Ñајтове тако да не читају текÑÑ‚ и Ñлике из привремене меморије</translation>
<translation id="6945221475159498467">Изабери</translation>
<translation id="6965382102122355670">Потврди</translation>
+<translation id="6981982820502123353">ПриÑтупачноÑÑ‚</translation>
<translation id="6992289844737586249">Питај пре него што дозволиш Ñајтовима да кориÑте микрофон (препоручено)</translation>
<translation id="7000754031042624318">ИÑкључено је у Android подешавањима</translation>
<translation id="7016516562562142042">Дозвољено је за актуелни претраживач</translation>
+<translation id="702463548815491781">Препоручујемо вам када укључите TalkBack или приÑтуп помоћу прекидача</translation>
<translation id="7053983685419859001">Блокирај</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{Изабрано: 1}one{Изабрано: #}few{Изабрано: #}other{Изабрано: #}}</translation>
-<translation id="7070090581017165256">О овом Ñајту</translation>
<translation id="7087918508125750058">Изабрали Ñте <ph name="ITEM_COUNT" />. Опције Ñу доÑтупне при врху екрана</translation>
<translation id="7141896414559753902">Блокирај приказивање иÑкачућих прозора и преуÑмеравања на Ñајтовима (препоручено)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> kB</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">Сајт кориÑти микрофон</translation>
<translation id="7561196759112975576">Увек</translation>
-<translation id="7572498721684305250">Ðе дозвољава Ñајтовима да шаљу и примају информације када додирнете NFC уређаје</translation>
<translation id="757524316907819857">Блокирај да Ñајтови пуштају заштићени Ñадржај</translation>
+<translation id="7577900504646297215">Управљајте интереÑовањима</translation>
<translation id="7649070708921625228">Помоћ</translation>
<translation id="7658239707568436148">Откажи</translation>
<translation id="7781829728241885113">Јуче</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">Веза је безбедна</translation>
<translation id="8249310407154411074">ПремеÑти на врх</translation>
<translation id="8261506727792406068">Избриши</translation>
+<translation id="8284326494547611709">Титл</translation>
<translation id="8300705686683892304">Управља апликација</translation>
<translation id="8324158725704657629">Ðе питај поново</translation>
<translation id="8372893542064058268">Дозволите Синхронизацију у позадини за одређени Ñајт.</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">Увећавање</translation>
<translation id="8921772741368021346"><ph name="POSITION" />/<ph name="DURATION" /></translation>
<translation id="8926666909099850184">NFC је иÑкључен за овај уређај. Укључите га у <ph name="BEGIN_LINK" />Android подешавањима<ph name="END_LINK" />.</translation>
+<translation id="8928445016601307354">Спречите Ñајтове да виде и мењају информације на NFC уређајима</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">Блокирајте колачиће за одређени Ñајт.</translation>
<translation id="8959122750345127698">Ðавигација је недоÑтупна: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sv.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sv.xtb
index 226b6580231..b75271fb7a5 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sv.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sv.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">Webbplatsen <ph name="SITE_NAME" /> har lagts till</translation>
<translation id="1383876407941801731">Sök</translation>
<translation id="1384959399684842514">Nedladdningen har pausats</translation>
+<translation id="1409426117486808224">Förenklad vy för öppna flikar</translation>
<translation id="1415402041810619267">Webbadressen har trunkerats</translation>
<translation id="1446450296470737166">Tillåt fullst. kontroll av MIDI</translation>
<translation id="1620510694547887537">Kamera</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">Tillåt cookies</translation>
<translation id="2228071138934252756">Om du vill ge <ph name="APP_NAME" /> åtkomst till kameran måste du även aktivera kameran i <ph name="BEGIN_LINK" />Android-inställningarna<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Bara en gång</translation>
+<translation id="2253414712144136228"><ph name="NAME_OF_LIST_ITEM" /> Ta bort</translation>
<translation id="2289270750774289114">Fråga när en webbplats försöker söka efter Bluetooth-enheter i närheten (rekommenderas)</translation>
<translation id="2315043854645842844">Val av certifikat på klienten stöds inte av operativsystemet.</translation>
+<translation id="2321958826496381788">Flytta reglaget tills du kan läsa texten ordentligt. Texten bör bli åtminstone så här stor när du trycker två gånger på ett stycke.</translation>
<translation id="2359808026110333948">Fortsätt</translation>
<translation id="2379925928934107488">Använd mörkt tema på webbplatser om Chrome använder mörkt tema, när det är möjligt</translation>
+<translation id="2387895666653383613">Textskalning</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> och <ph name="NUM_MORE" /> till tillåts}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> och <ph name="NUM_MORE" /> till tillåts}}</translation>
<translation id="2434158240863470628">Nedladdningen är klar<ph name="SEPARATOR" /><ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">Visa info</translation>
<translation id="3123473560110926937">Blockeras på vissa webbplatser</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> sparad data</translation>
+<translation id="3203366800380907218">Från webben</translation>
<translation id="321187648315454507">Om du vill få aviseringar från <ph name="APP_NAME" /> måste du även aktivera aviseringar i <ph name="BEGIN_LINK" />Android-inställningarna<ph name="END_LINK" />.</translation>
<translation id="3227137524299004712">Mikrofon</translation>
<translation id="3277252321222022663">Tillåt att webbplatser får åtkomst till enhetens sensorer (rekommenderas)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">Enhetsanvändning</translation>
<translation id="385051799172605136">Föregående</translation>
<translation id="3859306556332390985">Sök framåt</translation>
+<translation id="3895926599014793903">Tvinga aktivering av zoom</translation>
<translation id="3955193568934677022">Tillåt att skyddat innehåll spelas upp på webbplatser (rekommenderas)</translation>
<translation id="3967822245660637423">Nedladdning slutförd</translation>
<translation id="3987993985790029246">Kopiera länk</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" />/?</translation>
<translation id="4002066346123236978">Titel</translation>
<translation id="4008040567710660924">Tillåt cookies för en enskild webbplats.</translation>
+<translation id="4040330681741629921">Bli meddelad om det finns en förenklad vy av en webbplats.</translation>
<translation id="4046123991198612571">Nästa spår</translation>
+<translation id="4149994727733219643">Förenklad vy för webbsidor</translation>
<translation id="4165986682804962316">Webbplatsinställningar</translation>
+<translation id="4194328954146351878">Fråga innan webbplatser tillåts att visa och ändra information på NFC-enheter (rekommenderas)</translation>
<translation id="4200726100658658164">Öppna platsinställningarna</translation>
<translation id="4226663524361240545">Aviseringar kan göra att enheten vibrerar</translation>
<translation id="4259722352634471385">Webbadressen har blockerats: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">Expandera</translation>
<translation id="4336434711095810371">Rensa all data</translation>
<translation id="4402755511846832236">Blockera webbplatser från att veta när du använder enheten aktivt</translation>
+<translation id="4428065317363009941">Personliga annonspreferenser</translation>
<translation id="4434045419905280838">Popup-fönster och omdirigeringar</translation>
<translation id="445467742685312942">Tillåt att webbplatser spelar upp skyddat innehåll</translation>
<translation id="4468959413250150279">Stäng av ljudet för en webbplats.</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">Alternativet visas högt upp på skärmen</translation>
<translation id="5197729504361054390">Kontakterna du väljer delas med <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />.</translation>
<translation id="5216942107514965959">Besöktes senast i dag</translation>
+<translation id="5264323282659631142">Ta bort <ph name="CHIP_LABEL" /></translation>
<translation id="528192093759286357">Dra uppifrån och tryck på bakåtknappen för att lämna helskärmsläget.</translation>
<translation id="5300589172476337783">Visa</translation>
<translation id="5301954838959518834">Ok, jag förstår</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783"><ph name="DATASIZE" /> data och cookies som har sparats av webbplatser rensas.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(+ 1 till)}other{(+ # till)}}</translation>
<translation id="5403592356182871684">Namn</translation>
+<translation id="5412236728747081950">Den här webbplatsen hämtar dina intressen från Chrome för att visa mer relevanta annonser för dig</translation>
<translation id="5438097262470833822">Detta återställer behörigheter för <ph name="WEBSITE" /></translation>
<translation id="5489227211564503167">Förfluten tid: <ph name="ELAPSED_TIME" /> av <ph name="TOTAL_TIME" />.</translation>
<translation id="5494752089476963479">Blockera annonser på webbplatser där påträngande eller vilseledande annonser visas</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">Hämta igen</translation>
<translation id="5596627076506792578">Fler alternativ</translation>
<translation id="5649053991847567735">Automatiska nedladdningar</translation>
+<translation id="5668404140385795438">Åsidosätt en webbplats begäran att hindra inzoomning</translation>
<translation id="5677928146339483299">Blockerat</translation>
<translation id="5689516760719285838">Plats</translation>
<translation id="5690795753582697420">Kameran har inaktiverats i inställningarna för Android</translation>
-<translation id="5710871682236653961">Fråga innan webbplatser tillåts att skicka och ta emot uppgifter när du snuddar vid NFC-enheter (rekommenderas)</translation>
<translation id="5719847187258001597">All data och alla cookies som har sparats av <ph name="ORIGIN" /> eller motsvarande app på startskärmen rensas.</translation>
<translation id="5771720122942595109"><ph name="PERMISSION_1" /> blockeras</translation>
<translation id="5804241973901381774">Behörigheter</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">Spela</translation>
<translation id="6818926723028410516">Välj objekt</translation>
<translation id="6864395892908308021">Enheten kan inte läsa NFC</translation>
-<translation id="6910211073230771657">Borttagen</translation>
<translation id="6912998170423641340">Webbplatser ges inte tillgång till text och bilder i Urklipp</translation>
<translation id="6945221475159498467">Välj</translation>
<translation id="6965382102122355670">OK</translation>
+<translation id="6981982820502123353">Tillgänglighet</translation>
<translation id="6992289844737586249">Fråga innan webbplatser tillåts att använda mikrofonen (rekommenderas)</translation>
<translation id="7000754031042624318">Inaktiverad i Android-inställningarna</translation>
<translation id="7016516562562142042">Tillåt för den nuvarande sökmotorn</translation>
+<translation id="702463548815491781">Rekommenderas när TalkBack eller brytarstyrning är aktiverat</translation>
<translation id="7053983685419859001">Blockera</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1 har valts}other{# har valts}}</translation>
-<translation id="7070090581017165256">Om den här webbplatsen</translation>
<translation id="7087918508125750058"><ph name="ITEM_COUNT" /> har valts. Alternativ finns högt upp på skärmen</translation>
<translation id="7141896414559753902">Blockera webbplatser från att visa popup-fönster (rekommenderas)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> kB</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">En webbplats använder mikrofonen</translation>
<translation id="7561196759112975576">Alltid</translation>
-<translation id="7572498721684305250">Blockera webbplatser från att skicka och ta emot uppgifter när du snuddar vid NFC-enheter.</translation>
<translation id="757524316907819857">Blockera webbplatser från att spela upp skyddat innehåll</translation>
+<translation id="7577900504646297215">Hantera intressen</translation>
<translation id="7649070708921625228">Hjälp</translation>
<translation id="7658239707568436148">Avbryt</translation>
<translation id="7781829728241885113">Igår</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">Anslutningen är säker</translation>
<translation id="8249310407154411074">Flytta högst upp</translation>
<translation id="8261506727792406068">Radera</translation>
+<translation id="8284326494547611709">Textning</translation>
<translation id="8300705686683892304">Hanteras av app</translation>
<translation id="8324158725704657629">Fråga inte igen</translation>
<translation id="8372893542064058268">Tillåt bakgrundssynkronisering för en specifik webbplats.</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">Zooma in</translation>
<translation id="8921772741368021346"><ph name="POSITION" />/<ph name="DURATION" /></translation>
<translation id="8926666909099850184">NFC är inte aktiverat på enheten. Aktivera det i <ph name="BEGIN_LINK" />Android-inställningarna<ph name="END_LINK" />.</translation>
+<translation id="8928445016601307354">Förhindra att webbplatser visar och ändrar information på NFC-enheter</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">Blockera cookies för en enskild webbplats.</translation>
<translation id="8959122750345127698">Det går inte att nå webbadressen: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sw.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sw.xtb
index d9d0d8ea2f9..0acab6cba81 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sw.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_sw.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">Tovuti <ph name="SITE_NAME" /> imeongezwa</translation>
<translation id="1383876407941801731">Tafuta</translation>
<translation id="1384959399684842514">Upakuaji umesitishwa</translation>
+<translation id="1409426117486808224">Mwonekano uliorahisishwa kwa ajili ya vichupo vilivyofunguliwa</translation>
<translation id="1415402041810619267">URL imepunguzwa</translation>
<translation id="1446450296470737166">Ruhusu udhibiti kamili wa vifaa vya MIDI</translation>
<translation id="1620510694547887537">Kamera</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">Ruhusu vidakuzi</translation>
<translation id="2228071138934252756">Ili uruhusu <ph name="APP_NAME" /> ifikie kamera yako, washa pia kamera katika <ph name="BEGIN_LINK" />Mipangilio ya Android<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Mara moja tu</translation>
+<translation id="2253414712144136228">Ondoa <ph name="NAME_OF_LIST_ITEM" /></translation>
<translation id="2289270750774289114">Niulize wakati tovuti inataka kugundua vifaa vya Bluetooth vilivyo karibu (inapendekezwa)</translation>
<translation id="2315043854645842844">Uchaguzi wa cheti cha sehemu ya seva teja hautumiwi na mfumo wa uendeshaji.</translation>
+<translation id="2321958826496381788">Buruta kitelezi hadi uweze kusoma haya kwa starehe. Maandishi yanapaswa kuonekana angalau kwa ukubwa huu baada ya kugonga mara mbili kwenye aya.</translation>
<translation id="2359808026110333948">Endelea</translation>
<translation id="2379925928934107488">Tumia mandhari meusi kwenye tovuti wakati Chrome inatumia mandhari meusi, panapowezekana</translation>
+<translation id="2387895666653383613">Upimaji wa maandishi</translation>
<translation id="2402980924095424747">MB <ph name="MEGABYTES" /></translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Umeruhusu <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> na nyingine<ph name="NUM_MORE" />}other{Umeruhusu <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> na nyingine<ph name="NUM_MORE" />}}</translation>
<translation id="2434158240863470628">Upakuaji umekamilika <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">Onyesha Maelezo</translation>
<translation id="3123473560110926937">Yamezuiwa kwenye baadhi ya tovuti</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> za data iliyohifadhiwa</translation>
+<translation id="3203366800380907218">Kutoka kwenye wavuti</translation>
<translation id="321187648315454507">Ili uruhusu <ph name="APP_NAME" /> ikutumie arifa, washa pia arifa katika <ph name="BEGIN_LINK" />Mipangilio ya Android<ph name="END_LINK" />.</translation>
<translation id="3227137524299004712">Maikrofoni</translation>
<translation id="3277252321222022663">Ruhusu tovuti zifikie vitambuzi (inapendekezwa)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">Matumizi ya kifaa chako</translation>
<translation id="385051799172605136">Rudi nyuma</translation>
<translation id="3859306556332390985">Peleka mbele</translation>
+<translation id="3895926599014793903">Lazimisha kuwasha ukuzaji</translation>
<translation id="3955193568934677022">Ruhusu tovuti zicheze maudhui yanayolindwa (inapendekezwa)</translation>
<translation id="3967822245660637423">Faili imekamilika kupakuliwa</translation>
<translation id="3987993985790029246">Nakili kiungo</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> / ?</translation>
<translation id="4002066346123236978">Kichwa</translation>
<translation id="4008040567710660924">Ruhusu vidakuzi katika tovuti maalum.</translation>
+<translation id="4040330681741629921">Pata arifa wakati tovuti inapoweza kuonyeshwa katika mwonekano uliorahisishwa</translation>
<translation id="4046123991198612571">Wimbo unaofuata</translation>
+<translation id="4149994727733219643">Mwonekano uliorahisishwa kwa ajili ya kurasa za wavuti</translation>
<translation id="4165986682804962316">Mipangilio ya tovuti</translation>
+<translation id="4194328954146351878">Uliza kabla ya kuruhusu tovuti zione na zibadilishe maelezo kwenye vifaa vya NFC (inapendekezwa)</translation>
<translation id="4200726100658658164">Fungua Mipangilio ya Mahali</translation>
<translation id="4226663524361240545">Arifa huenda zitatetemesha kifaa</translation>
<translation id="4259722352634471385">Kudurusu kumezuiwa: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">Panua</translation>
<translation id="4336434711095810371">Futa data yote</translation>
<translation id="4402755511846832236">Zuia tovuti zisijue wakati unatumia kifaa hiki</translation>
+<translation id="4428065317363009941">Kuweka mapendeleo ya matangazo</translation>
<translation id="4434045419905280838">Madirisha ibukizi/kuelekeza kwingine</translation>
<translation id="445467742685312942">Ruhusu tovuti icheze maudhui yanayolindwa</translation>
<translation id="4468959413250150279">Zima sauti katika tovuti mahususi.</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">Chaguo linapatikana karibu na sehemu ya juu ya skrini</translation>
<translation id="5197729504361054390">Anwani unazochagua zitashirikiwa na <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />.</translation>
<translation id="5216942107514965959">Ilitembelewa mara ya mwisho leo</translation>
+<translation id="5264323282659631142">Ondoa '<ph name="CHIP_LABEL" />'</translation>
<translation id="528192093759286357">Buruta kutoka juu na uguse kitufe cha kurudi nyuma ili uondoke kwenye skrini nzima.</translation>
<translation id="5300589172476337783">Onyesha</translation>
<translation id="5301954838959518834">Sawa, nimeelewa</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">Hatua hii itafuta data na vidakuzi vya ukubwa wa <ph name="DATASIZE" /> vilivyohifadhiwa na tovuti.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(+ 1 zaidi)}other{(+ # zaidi)}}</translation>
<translation id="5403592356182871684">Majina</translation>
+<translation id="5412236728747081950">Tovuti hii hupata mambo yanayokuvutia kutoka kwenye Chrome ili kukuonyesha matangazo yanayokufaa zaidi</translation>
<translation id="5438097262470833822">Chaguo hili litabadilisha ruhusa za <ph name="WEBSITE" /></translation>
<translation id="5489227211564503167">Muda uliopita ni <ph name="ELAPSED_TIME" /> kati ya <ph name="TOTAL_TIME" />.</translation>
<translation id="5494752089476963479">Zuia matangazo kwenye tovuti zinazoonyesha matangazo yanayopotosha au yanayokatiza huduma</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">Pakia upya</translation>
<translation id="5596627076506792578">Chaguo zaidi</translation>
<translation id="5649053991847567735">Vipakuliwa vya kiotomatiki</translation>
+<translation id="5668404140385795438">Batilisha ombi la tovuti ili kuzuia kuvuta karibu</translation>
<translation id="5677928146339483299">Kumezuiwa</translation>
<translation id="5689516760719285838">Mahali</translation>
<translation id="5690795753582697420">Kamera imezimwa katika mipangilio ya Android</translation>
-<translation id="5710871682236653961">Uliza kabla ya kuruhusu tovuti kutuma na kupokea maelezo unapogusa vifaa vya NFC (inapendekezwa)</translation>
<translation id="5719847187258001597">Hatua hii itafuta data na vidakuzi vyote vilivyohifadhiwa na <ph name="ORIGIN" /> au na programu yake kwenye Skrini yako ya kwanza.</translation>
<translation id="5771720122942595109">Umezuia <ph name="PERMISSION_1" /></translation>
<translation id="5804241973901381774">Idhini</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">Cheza</translation>
<translation id="6818926723028410516">Chagua vipengee</translation>
<translation id="6864395892908308021">Kifaa hiki kimeshindwa kusoma NFC</translation>
-<translation id="6910211073230771657">Imeondolewa</translation>
<translation id="6912998170423641340">Zuia tovuti zisisome maandishi na picha kutoka ubao wa kunakili</translation>
<translation id="6945221475159498467">Chagua</translation>
<translation id="6965382102122355670">Sawa</translation>
+<translation id="6981982820502123353">Ufikivu</translation>
<translation id="6992289844737586249">Uliza kwanza kabla ya kuruhusu tovuti zitumie maikrofoni yako (inapendekezwa)</translation>
<translation id="7000754031042624318">Imezimwa katika mipangilio ya Android</translation>
<translation id="7016516562562142042">Imeruhusiwa kwa mtambo wa sasa wa kutafuta</translation>
+<translation id="702463548815491781">Inapendekezwa wakati umewasha TalkBack au kipengele cha Kufikia Kupitia Swichi</translation>
<translation id="7053983685419859001">Zuia</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{Umechagua 1}other{Umechagua #}}</translation>
-<translation id="7070090581017165256">Kuhusu tovuti hii</translation>
<translation id="7087918508125750058">Imechagua <ph name="ITEM_COUNT" />. Chaguo zinapatikana karibu na sehemu ya juu ya skrini</translation>
<translation id="7141896414559753902">Zuia tovuti zisionyeshe madirisha ibukizi na kuelekeza kwingine (inapendekezwa)</translation>
<translation id="7176368934862295254">KB <ph name="KILOBYTES" /></translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">Tovuti inatumia maikrofoni yako</translation>
<translation id="7561196759112975576">Kila wakati</translation>
-<translation id="7572498721684305250">Zuia tovuti zisitume na kupokea maelezo wakati unagusa vifaa vya NFC</translation>
<translation id="757524316907819857">Zuia tovuti zisicheze maudhui yanayolindwa</translation>
+<translation id="7577900504646297215">Dhibiti yanayokuvutia</translation>
<translation id="7649070708921625228">Usaidizi</translation>
<translation id="7658239707568436148">Ghairi</translation>
<translation id="7781829728241885113">Jana</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">Muunganisho ni salama</translation>
<translation id="8249310407154411074">Sogeza juu</translation>
<translation id="8261506727792406068">Futa</translation>
+<translation id="8284326494547611709">Manukuu</translation>
<translation id="8300705686683892304">Zinazodhibitiwa na programu</translation>
<translation id="8324158725704657629">Usiniulize tena</translation>
<translation id="8372893542064058268">Ruhusu Usawazishaji wa Chini Chini wa tovuti mahususi.</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">Kuza karibu</translation>
<translation id="8921772741368021346"><ph name="POSITION" /> / <ph name="DURATION" /></translation>
<translation id="8926666909099850184">Kipengele cha NFC kimezimwa kwenye kifaa hiki. Kiwashe katika <ph name="BEGIN_LINK" />Mipangilio ya Android<ph name="END_LINK" />.</translation>
+<translation id="8928445016601307354">Zuia tovuti zisione wala kubadilisha maelezo kwenye vifaa vya NFC</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">Zuia vidakuzi katika tovuti maalum.</translation>
<translation id="8959122750345127698">Kudurusu hakufikiki: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ta.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ta.xtb
index b3e4f3b1c7f..248d9230f48 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ta.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ta.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676"><ph name="SITE_NAME" /> தளம௠சேரà¯à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯</translation>
<translation id="1383876407941801731">Search</translation>
<translation id="1384959399684842514">பதிவிறகà¯à®•à®®à¯ இடைநிறà¯à®¤à¯à®¤à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯</translation>
+<translation id="1409426117486808224">திறகà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³ தாவலà¯à®•à®³à¯à®•à¯à®•à®¾à®© எளிதாகà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿ காடà¯à®šà®¿</translation>
<translation id="1415402041810619267">URL தà¯à®£à¯à®Ÿà®¿à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯</translation>
<translation id="1446450296470737166">MIDI சாதனஙà¯à®•à®³à¯à®•à¯à®•à¯ à®®à¯à®´à¯à®•à¯ கடà¯à®Ÿà¯à®ªà¯à®ªà®¾à®Ÿà¯à®Ÿà¯ˆ அனà¯à®®à®¤à®¿</translation>
<translation id="1620510694547887537">கேமரா</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">கà¯à®•à¯à®•à¯€à®•à®³à¯ˆ அனà¯à®®à®¤à®¿</translation>
<translation id="2228071138934252756">உஙà¯à®•à®³à¯ கேமராவை அணà¯à®• <ph name="APP_NAME" /> ஆபà¯à®¸à¯ˆ அனà¯à®®à®¤à®¿à®ªà¯à®ªà®¤à®±à¯à®•à¯ <ph name="BEGIN_LINK" />Android அமைபà¯à®ªà¯à®•à®³à®¿à®²à¯à®®à¯<ph name="END_LINK" /> கேமராவிறà¯à®•à®¾à®© அனà¯à®®à®¤à®¿à®¯à¯ˆ இயகà¯à®•à®µà¯à®®à¯.</translation>
<translation id="2241634353105152135">à®’à®°à¯à®®à¯à®±à¯ˆ மடà¯à®Ÿà¯à®®à¯‡</translation>
+<translation id="2253414712144136228"><ph name="NAME_OF_LIST_ITEM" /> ஠அகறà¯à®±à¯à®®à¯</translation>
<translation id="2289270750774289114">à®…à®°à¯à®•à®¿à®²à¯à®³à¯à®³ பà¯à®³à¯‚டூத௠சாதனஙà¯à®•à®³à¯ˆ வலைதளம௠கணà¯à®Ÿà®±à®¿à®¯ à®®à¯à®¯à®²à¯à®®à¯à®ªà¯‹à®¤à¯ கேள௠(பரிநà¯à®¤à¯à®°à¯ˆà®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®•à®¿à®±à®¤à¯)</translation>
<translation id="2315043854645842844">கிளையனà¯à®Ÿà¯ சாரà¯à®ªà®¾à®• சானà¯à®±à®¿à®¤à®´à¯ தேரà¯à®¨à¯à®¤à¯†à®Ÿà¯à®ªà¯à®ªà¯ˆ ஆபà¯à®°à¯‡à®Ÿà¯à®Ÿà®¿à®™à¯ சிஸà¯à®Ÿà®®à¯ ஆதரிகà¯à®•à®µà®¿à®²à¯à®²à¯ˆ.</translation>
+<translation id="2321958826496381788">இதை வசதியாக படிபà¯à®ªà®¤à®±à¯à®•à¯, ஸà¯à®²à¯ˆà®Ÿà®°à¯ˆ இழà¯à®•à¯à®•à®µà¯à®®à¯. பதà¯à®¤à®¿à®¯à®¿à®²à¯ இர௠மà¯à®±à¯ˆ தடà¯à®Ÿà®¿à®¯ பிறகà¯, உரையானத௠கà¯à®±à¯ˆà®¨à¯à®¤à®¤à¯ இநà¯à®¤ அளவ௠பெரியதாக தோனà¯à®± வேணà¯à®Ÿà¯à®®à¯.</translation>
<translation id="2359808026110333948">தொடரà¯à®•</translation>
<translation id="2379925928934107488">Chromeமில௠டாரà¯à®•à¯ தீமினைப௠பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à¯à®®à¯à®ªà¯‹à®¤à¯ சாதà¯à®¤à®¿à®¯à®®à®¾à®© சூழலà¯à®•à®³à®¿à®²à¯ தளஙà¯à®•à®³à¯à®•à¯à®•à¯à®®à¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®ªà¯à®ªà®Ÿà¯à®®à¯</translation>
+<translation id="2387895666653383613">எழà¯à®¤à¯à®¤à¯ அளவà¯</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> மெ.பை.</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> &amp; மேலà¯à®®à¯ <ph name="NUM_MORE" /> அனà¯à®®à®¤à®¿à®•à®³à¯ வழஙà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®©}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> &amp; மேலà¯à®®à¯ <ph name="NUM_MORE" /> அனà¯à®®à®¤à®¿à®•à®³à¯ வழஙà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®©}}</translation>
<translation id="2434158240863470628">பதிவிறகà¯à®•à®®à¯ à®®à¯à®Ÿà®¿à®¨à¯à®¤à®¤à¯ <ph name="SEPARATOR" /><ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">தகவலைக௠காடà¯à®Ÿà¯</translation>
<translation id="3123473560110926937">சில தளஙà¯à®•à®³à®¿à®²à¯ தடà¯à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®©</translation>
<translation id="3198916472715691905">சேமிகà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿ தரவà¯: <ph name="STORAGE_AMOUNT" /></translation>
+<translation id="3203366800380907218">இணையதà¯à®¤à®¿à®²à¯ இரà¯à®¨à¯à®¤à¯</translation>
<translation id="321187648315454507"><ph name="APP_NAME" /> ஆபà¯à®¸à¯ உஙà¯à®•à®³à¯à®•à¯à®•à¯ அறிவிபà¯à®ªà¯à®•à®³à¯ˆ அனà¯à®ªà¯à®ª அனà¯à®®à®¤à®¿à®ªà¯à®ªà®¤à®±à¯à®•à¯ <ph name="BEGIN_LINK" />Android அமைபà¯à®ªà¯à®•à®³à®¿à®²à¯à®®à¯<ph name="END_LINK" /> அறிவிபà¯à®ªà¯à®•à®³à¯à®•à¯à®•à®¾à®© அனà¯à®®à®¤à®¿à®¯à¯ˆ இயகà¯à®•à®µà¯à®®à¯.</translation>
<translation id="3227137524299004712">மைகà¯à®°à¯‡à®¾à®ƒà®ªà¯‡à®¾à®©à¯</translation>
<translation id="3277252321222022663">தளஙà¯à®•à®³à¯ செனà¯à®šà®¾à®°à¯à®•à®³à¯ˆ அணà¯à®• அனà¯à®®à®¤à®¿à®•à¯à®•à¯à®®à¯ (பரிநà¯à®¤à¯à®°à¯ˆà®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®•à®¿à®±à®¤à¯)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">உஙà¯à®•à®³à¯ சாதன உபயோகமà¯</translation>
<translation id="385051799172605136">திரà¯à®®à¯à®ªà¯</translation>
<translation id="3859306556332390985">à®®à¯à®©à¯à®šà¯†à®²à¯</translation>
+<translation id="3895926599014793903">பெரிதாகà¯à®•à¯à®µà®¤à¯ˆà®šà¯ செயலà¯à®ªà®Ÿà¯à®¤à¯à®¤ வலியà¯à®±à¯à®¤à¯à®¤à¯</translation>
<translation id="3955193568934677022">பாதà¯à®•à®¾à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿ உளà¯à®³à®Ÿà®•à¯à®•à®¤à¯à®¤à¯ˆ இயகà¯à®•, தளஙà¯à®•à®³à¯ˆ அனà¯à®®à®¤à®¿ (பரிநà¯à®¤à¯à®°à¯ˆà®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®•à®¿à®±à®¤à¯)</translation>
<translation id="3967822245660637423">பதிவிறகà¯à®•à®®à¯ à®®à¯à®Ÿà®¿à®¨à¯à®¤à®¤à¯</translation>
<translation id="3987993985790029246">இணைபà¯à®ªà¯ˆ நகலெடà¯</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> / ?</translation>
<translation id="4002066346123236978">தலைபà¯à®ªà¯</translation>
<translation id="4008040567710660924">கà¯à®±à®¿à®ªà¯à®ªà®¿à®Ÿà¯à®Ÿ தளதà¯à®¤à®¿à®±à¯à®•à¯, கà¯à®•à¯à®•à¯€à®•à®³à¯ˆ அனà¯à®®à®¤à®¿à®•à¯à®•à¯à®®à¯.</translation>
+<translation id="4040330681741629921">எளிதாகà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿ காடà¯à®šà®¿à®¯à®¿à®²à¯ தளம௠காடà¯à®Ÿà®ªà¯à®ªà®Ÿà¯à®®à¯à®ªà¯‹à®¤à¯ அறிவிபà¯à®ªà¯ˆà®ªà¯ பெறலாமà¯</translation>
<translation id="4046123991198612571">அடà¯à®¤à¯à®¤ டிராகà¯</translation>
+<translation id="4149994727733219643">இணையப௠பகà¯à®•à®™à¯à®•à®³à¯à®•à¯à®•à®¾à®© எளிதாகà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿ காடà¯à®šà®¿</translation>
<translation id="4165986682804962316">தள அமைபà¯à®ªà¯à®•à®³à¯</translation>
+<translation id="4194328954146351878">NFC சாதனஙà¯à®•à®³à®¿à®©à¯ தகவலà¯à®•à®³à¯ˆà®¤à¯ தளஙà¯à®•à®³à¯ பாரà¯à®ªà¯à®ªà®¤à®±à¯à®•à¯à®®à¯ மாறà¯à®±à¯à®µà®¤à®±à¯à®•à¯à®®à¯ à®®à¯à®©à¯à®ªà¯ அனà¯à®®à®¤à®¿ கேடà¯à®•à®ªà¯à®ªà®Ÿà¯à®®à¯ (பரிநà¯à®¤à¯à®°à¯ˆà®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®•à®¿à®±à®¤à¯)</translation>
<translation id="4200726100658658164">இரà¯à®ªà¯à®ªà®¿à®Ÿ அமைபà¯à®ªà¯à®•à®³à¯ˆà®¤à¯ திறகà¯à®•à¯à®®à¯</translation>
<translation id="4226663524361240545">அறிவிபà¯à®ªà¯à®•à®³à¯ வரà¯à®®à¯ போத௠சாதனம௠அதிரà¯à®µà¯à®±à®•à¯à®•à¯‚டà¯à®®à¯</translation>
<translation id="4259722352634471385">செலà¯à®µà®¤à¯ தடà¯à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">விரி</translation>
<translation id="4336434711095810371">அனைதà¯à®¤à¯à®¤à¯ தரவையà¯à®®à¯ அழி</translation>
<translation id="4402755511846832236">இநà¯à®¤à®šà¯ சாதனதà¯à®¤à®¿à®²à¯ நீஙà¯à®•à®³à¯ செயலில௠இரà¯à®ªà¯à®ªà®¤à¯ கà¯à®±à®¿à®¤à¯à®¤à¯à®¤à¯ தளஙà¯à®•à®³à¯ அறிநà¯à®¤à¯à®•à¯Šà®³à¯à®µà®¤à¯ˆà®¤à¯ தடà¯à®•à¯à®•à¯à®®à¯</translation>
+<translation id="4428065317363009941">விளமà¯à®ªà®°à®ªà¯ பிரதà¯à®¤à®¿à®¯à¯‡à®•à®®à®¾à®•à¯à®•à®²à¯</translation>
<translation id="4434045419905280838">பாபà¯-அபà¯à®•à®³à¯ &amp; திசைதிரà¯à®ªà¯à®ªà¯à®¤à®²à¯à®•à®³à¯</translation>
<translation id="445467742685312942">பாதà¯à®•à®¾à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿ உளà¯à®³à®Ÿà®•à¯à®•à®¤à¯à®¤à¯ˆ இயகà¯à®•à¯à®µà®¤à®±à¯à®•à¯à®¤à¯ தளஙà¯à®•à®³à¯ˆ அனà¯à®®à®¤à®¿à®•à¯à®•à¯à®®à¯</translation>
<translation id="4468959413250150279">கà¯à®±à®¿à®ªà¯à®ªà®¿à®Ÿà¯à®Ÿ தளதà¯à®¤à®¿à®±à¯à®•à¯ ஒலியடகà¯à®•à¯</translation>
@@ -156,7 +166,8 @@
<translation id="5186036860380548585">அதறà¯à®•à®¾à®© விரà¯à®ªà¯à®ªà®®à¯ திரையின௠மேறà¯à®ªà®•à¯à®¤à®¿à®¯à®¿à®²à¯ உளà¯à®³à®¤à¯</translation>
<translation id="5197729504361054390">நீஙà¯à®•à®³à¯ தேரà¯à®¨à¯à®¤à¯†à®Ÿà¯à®•à¯à®•à¯à®®à¯ தொடரà¯à®ªà¯à®•à®³à¯ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> உடன௠பகிரபà¯à®ªà®Ÿà¯à®®à¯.</translation>
<translation id="5216942107514965959">கடைசியாகப௠பாரà¯à®¤à¯à®¤à®¤à¯: இனà¯à®±à¯</translation>
-<translation id="528192093759286357">à®®à¯à®´à¯à®¤à¯à®¤à®¿à®°à¯ˆà®¯à®¿à®²à®¿à®°à¯à®¨à¯à®¤à¯ வெளியேற, மேலிரà¯à®¨à¯à®¤à¯ இழà¯à®¤à¯à®¤à¯ "à®®à¯à®¨à¯à®¤à¯ˆà®¯à®¤à¯" பொதà¯à®¤à®¾à®©à¯ˆà®¤à¯ தொடவà¯à®®à¯.</translation>
+<translation id="5264323282659631142">'<ph name="CHIP_LABEL" />' ஠அகறà¯à®±à¯à®®à¯</translation>
+<translation id="528192093759286357">à®®à¯à®´à¯à®¤à¯à®¤à®¿à®°à¯ˆà®¯à®¿à®²à®¿à®°à¯à®¨à¯à®¤à¯ வெளியேற, மேலிரà¯à®¨à¯à®¤à¯ இழà¯à®¤à¯à®¤à¯ "à®®à¯à®¨à¯à®¤à¯ˆà®¯à®¤à¯" படà¯à®Ÿà®©à¯ˆà®¤à¯ தொடவà¯à®®à¯.</translation>
<translation id="5300589172476337783">காணà¯à®ªà®¿</translation>
<translation id="5301954838959518834">சரி, பà¯à®°à®¿à®¨à¯à®¤à®¤à¯</translation>
<translation id="5313967007315987356">தளதà¯à®¤à¯ˆà®šà¯ சேரà¯</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">இதைச௠செயà¯à®¤à®¾à®²à¯ தளஙà¯à®•à®³à¯ சேமிதà¯à®¤à¯à®³à¯à®³ <ph name="DATASIZE" /> தரவà¯à®®à¯ கà¯à®•à¯à®•à¯€à®•à®³à¯à®®à¯ அழிகà¯à®•à®ªà¯à®ªà®Ÿà¯à®®à¯.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(மேலà¯à®®à¯ 1)}other{(மேலà¯à®®à¯ #)}}</translation>
<translation id="5403592356182871684">பெயரà¯à®•à®³à¯</translation>
+<translation id="5412236728747081950">மிகவà¯à®®à¯ தொடரà¯à®ªà¯à®Ÿà¯ˆà®¯ விளமà¯à®ªà®°à®™à¯à®•à®³à¯ˆà®•à¯ காடà¯à®Ÿà¯à®µà®¤à®±à¯à®•à®¾à®• Chromeமில௠இரà¯à®¨à¯à®¤à¯ உஙà¯à®•à®³à¯ ஆரà¯à®µà®™à¯à®•à®³à¯ˆ இநà¯à®¤à®¤à¯ தளம௠பெறà¯à®•à®¿à®±à®¤à¯</translation>
<translation id="5438097262470833822">இதைச௠செயà¯à®¤à®¾à®²à¯ <ph name="WEBSITE" /> தளதà¯à®¤à®¿à®±à¯à®•à®¾à®© அனà¯à®®à®¤à®¿à®•à®³à¯ ரீசெட௠செயà¯à®¯à®ªà¯à®ªà®Ÿà¯à®®à¯</translation>
<translation id="5489227211564503167">à®®à¯à®Ÿà®¿à®¨à¯à®¤ நேரமà¯: <ph name="ELAPSED_TIME" />/<ph name="TOTAL_TIME" />.</translation>
<translation id="5494752089476963479">கà¯à®±à¯à®•à¯à®•à®¿à®Ÿà¯à®®à¯ அலà¯à®²à®¤à¯ தவறாக வழிநடதà¯à®¤à¯à®®à¯ விளமà¯à®ªà®°à®™à¯à®•à®³à¯ˆà®•à¯ காடà¯à®Ÿà¯à®®à¯ தளஙà¯à®•à®³à®¿à®²à¯ விளமà¯à®ªà®°à®™à¯à®•à®³à¯ˆà®¤à¯ தடà¯</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">மீணà¯à®Ÿà¯à®®à¯ à®à®±à¯à®±à¯</translation>
<translation id="5596627076506792578">கூடà¯à®¤à®²à¯ விரà¯à®ªà¯à®ªà®™à¯à®•à®³à¯</translation>
<translation id="5649053991847567735">தனà¯à®©à®¿à®¯à®•à¯à®•à®ªà¯ பதிவிறகà¯à®•à®™à¯à®•à®³à¯</translation>
+<translation id="5668404140385795438">பெரிதாகà¯à®•à®ªà¯à®ªà®Ÿà¯à®µà®¤à¯ˆà®¤à¯ தடà¯à®•à¯à®• இணையதளம௠விடà¯à®¤à¯à®¤ கோரிகà¯à®•à¯ˆà®¯à¯ˆà®ªà¯ பà¯à®±à®•à¯à®•à®£à®¿à®•à¯à®•à®µà¯à®®à¯</translation>
<translation id="5677928146339483299">தடà¯à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯</translation>
<translation id="5689516760719285838">இரà¯à®ªà¯à®ªà®¿à®Ÿà®®à¯</translation>
<translation id="5690795753582697420">Android அமைபà¯à®ªà¯à®•à®³à®¿à®²à¯ கேமரா à®®à¯à®Ÿà®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯</translation>
-<translation id="5710871682236653961">நீஙà¯à®•à®³à¯ NFC சாதனஙà¯à®•à®³à¯ˆà®¤à¯ தடà¯à®Ÿà¯à®®à¯à®ªà¯‹à®¤à¯ தகவலà¯à®•à®³à¯ˆ அனà¯à®ªà¯à®ªà¯à®µà®¤à®±à¯à®•à¯à®®à¯ பெறà¯à®µà®¤à®±à¯à®•à¯à®®à¯ தளஙà¯à®•à®³à¯ˆ அனà¯à®®à®¤à®¿à®ªà¯à®ªà®¤à®±à¯à®•à¯ à®®à¯à®©à¯à®ªà¯ அனà¯à®®à®¤à®¿ கோரà¯à®®à¯ (பரிநà¯à®¤à¯à®°à¯ˆà®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®•à®¿à®±à®¤à¯)</translation>
<translation id="5719847187258001597">இதைச௠செயà¯à®¤à®¾à®²à¯ <ph name="ORIGIN" /> தளமோ உஙà¯à®•à®³à¯ à®®à¯à®•à®ªà¯à®ªà¯à®¤à¯ திரையில௠உளà¯à®³ அதன௠ஆபà¯à®¸à¯‹ சேமிதà¯à®¤à¯à®³à¯à®³ தரவà¯, கà¯à®•à¯à®•à¯€à®•à®³à¯ ஆகிய அனைதà¯à®¤à¯à®®à¯ அழிகà¯à®•à®ªà¯à®ªà®Ÿà¯à®®à¯.</translation>
<translation id="5771720122942595109"><ph name="PERMISSION_1" />கà¯à®•à®¾à®© அனà¯à®®à®¤à®¿ தடà¯à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯</translation>
<translation id="5804241973901381774">அனà¯à®®à®¤à®¿à®•à®³à¯</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">இயகà¯à®•à¯</translation>
<translation id="6818926723028410516">படà¯à®Ÿà®¿à®¯à®²à®¿à®²à®¿à®°à¯à®¨à¯à®¤à¯ தேரà¯à®¨à¯à®¤à¯†à®Ÿà¯à®•à¯à®•à®µà¯à®®à¯</translation>
<translation id="6864395892908308021">இநà¯à®¤à®šà¯ சாதனதà¯à®¤à®¿à®²à¯ NFC ஆதரிகà¯à®•à®ªà¯à®ªà®Ÿà®µà®¿à®²à¯à®²à¯ˆ</translation>
-<translation id="6910211073230771657">நீகà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯</translation>
<translation id="6912998170423641340">தளஙà¯à®•à®³à¯, கிளிபà¯à®ªà¯‹à®°à¯à®Ÿà®¿à®²à®¿à®°à¯à®¨à¯à®¤à¯ உரையையà¯à®®à¯ படஙà¯à®•à®³à¯ˆà®¯à¯à®®à¯ படிபà¯à®ªà®¤à¯ தடà¯à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯</translation>
<translation id="6945221475159498467">தேரà¯à®¨à¯à®¤à¯†à®Ÿà¯</translation>
<translation id="6965382102122355670">சரி</translation>
+<translation id="6981982820502123353">அணà¯à®•à®²à¯ தனà¯à®®à¯ˆ</translation>
<translation id="6992289844737586249">எனத௠மைகà¯à®°à¯‹à®ƒà®ªà¯‹à®©à¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®¤à¯ தளஙà¯à®•à®³à¯ˆ அனà¯à®®à®¤à®¿à®•à¯à®•à¯à®®à¯ à®®à¯à®©à¯ கேள௠(பரிநà¯à®¤à¯à®°à¯ˆà®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®•à®¿à®±à®¤à¯)</translation>
<translation id="7000754031042624318">Android அமைபà¯à®ªà¯à®•à®³à®¿à®²à¯ à®®à¯à®Ÿà®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯</translation>
<translation id="7016516562562142042">நடபà¯à®ªà¯à®¤à¯ தேடல௠இனà¯à®œà®¿à®©à¯à®•à¯à®•à¯ அனà¯à®®à®¤à®¿à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯</translation>
+<translation id="702463548815491781">TalkBack அலà¯à®²à®¤à¯ ‘ஸà¯à®µà®¿à®Ÿà¯à®šà¯ அணà¯à®•à®²à¯â€™ இயகà¯à®•à®¤à¯à®¤à®¿à®²à¯ இரà¯à®•à¯à®•à¯à®®à¯à®ªà¯‹à®¤à¯ பரிநà¯à®¤à¯à®°à¯ˆà®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®•à®¿à®±à®¤à¯</translation>
<translation id="7053983685419859001">தடà¯</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1 தேரà¯à®¨à¯à®¤à¯†à®Ÿà¯à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯}other{# தேரà¯à®¨à¯à®¤à¯†à®Ÿà¯à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®©}}</translation>
-<translation id="7070090581017165256">இநà¯à®¤à®¤à¯ தளதà¯à®¤à¯ˆà®ªà¯ பறà¯à®±à®¿</translation>
<translation id="7087918508125750058"><ph name="ITEM_COUNT" /> தேரà¯à®¨à¯à®¤à¯†à®Ÿà¯à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®©. திரையின௠மேறà¯à®ªà®•à¯à®¤à®¿à®•à¯à®•à¯ à®…à®°à¯à®•à®¿à®²à¯, விரà¯à®ªà¯à®ªà®™à¯à®•à®³à¯ உளà¯à®³à®©</translation>
<translation id="7141896414559753902">தளஙà¯à®•à®³à¯ பாபà¯-அபà¯à®•à®³à¯ˆà®¯à¯à®®à¯ திசைதிரà¯à®ªà¯à®ªà¯à®¤à®²à¯à®•à®³à¯ˆà®¯à¯à®®à¯ காடà¯à®Ÿà®¾à®®à®²à¯ தட௠(பரிநà¯à®¤à¯à®°à¯ˆà®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®•à®¿à®±à®¤à¯)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> கி.பை.</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">ஒர௠தளம௠உஙà¯à®•à®³à¯ மைகà¯à®°à¯‹à®ƒà®ªà¯‹à®©à¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à¯à®•à®¿à®±à®¤à¯</translation>
<translation id="7561196759112975576">எபà¯à®ªà¯‹à®¤à¯à®®à¯</translation>
-<translation id="7572498721684305250">நீஙà¯à®•à®³à¯ NFC சாதனஙà¯à®•à®³à¯ˆà®¤à¯ தடà¯à®Ÿà¯à®®à¯à®ªà¯‹à®¤à¯ தகவலà¯à®•à®³à¯ˆ அனà¯à®ªà¯à®ªà¯à®µà®¤à®¿à®²à®¿à®°à¯à®¨à¯à®¤à¯à®®à¯ பெறà¯à®µà®¤à®¿à®²à®¿à®°à¯à®¨à¯à®¤à¯à®®à¯ தளஙà¯à®•à®³à¯ˆà®¤à¯ தடà¯à®•à¯à®•à¯à®®à¯</translation>
<translation id="757524316907819857">பாதà¯à®•à®¾à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿ உளà¯à®³à®Ÿà®•à¯à®•à®¤à¯à®¤à¯ˆà®¤à¯ தளஙà¯à®•à®³à¯ இயகà¯à®•à¯à®µà®¤à¯ˆà®¤à¯ தடà¯à®•à¯à®•à¯à®®à¯</translation>
+<translation id="7577900504646297215">ஆரà¯à®µà®™à¯à®•à®³à¯ˆ நிரà¯à®µà®•à®¿à®•à¯à®•à¯à®®à¯</translation>
<translation id="7649070708921625228">உதவி</translation>
<translation id="7658239707568436148">ரதà¯à®¤à¯ செயà¯</translation>
<translation id="7781829728241885113">நேறà¯à®±à¯</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">இணைபà¯à®ªà¯ பாதà¯à®•à®¾à®ªà¯à®ªà®¾à®©à®¤à¯</translation>
<translation id="8249310407154411074">à®®à¯à®¤à®²à®¾à®µà®¤à®¾à®• நகரà¯à®¤à¯à®¤à¯</translation>
<translation id="8261506727792406068">நீகà¯à®•à¯</translation>
+<translation id="8284326494547611709">வசனஙà¯à®•à®³à¯</translation>
<translation id="8300705686683892304">ஆபà¯à®¸à¯ நிரà¯à®µà®•à®¿à®ªà¯à®ªà®µà¯ˆ</translation>
<translation id="8324158725704657629">மீணà¯à®Ÿà¯à®®à¯ கேடà¯à®•à®¾à®¤à¯‡</translation>
<translation id="8372893542064058268">கà¯à®±à®¿à®ªà¯à®ªà®¿à®Ÿà¯à®Ÿ தளதà¯à®¤à®¿à®±à¯à®•à¯, பினà¯à®©à®£à®¿ ஒதà¯à®¤à®¿à®šà¯ˆà®µà¯ˆ அனà¯à®®à®¤à®¿.</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">பெரிதாகà¯à®•à¯</translation>
<translation id="8921772741368021346"><ph name="POSITION" /> / <ph name="DURATION" /></translation>
<translation id="8926666909099850184">இநà¯à®¤à®šà¯ சாதனதà¯à®¤à®¿à®²à¯ NFC ஆஃப௠செயà¯à®¯à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯. அதை <ph name="BEGIN_LINK" />Android அமைபà¯à®ªà¯à®•à®³à®¿à®²à¯<ph name="END_LINK" /> ஆன௠செயà¯à®¯à®µà¯à®®à¯.</translation>
+<translation id="8928445016601307354">NFC சாதனஙà¯à®•à®³à®¿à®©à¯ தகவலà¯à®•à®³à¯ˆà®¤à¯ தளஙà¯à®•à®³à¯ பாரà¯à®ªà¯à®ªà®¤à¯à®®à¯ மாறà¯à®±à¯à®µà®¤à¯à®®à¯ தடà¯à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®®à¯</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">கà¯à®±à®¿à®ªà¯à®ªà®¿à®Ÿà¯à®Ÿ தளதà¯à®¤à®¿à®±à¯à®•à®¾à®© கà¯à®•à¯à®•à¯€à®•à®³à¯ˆà®¤à¯ தடà¯à®•à¯à®•à¯à®®à¯.</translation>
<translation id="8959122750345127698">செலà¯à®² à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_te.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_te.xtb
index f6e76ff913c..a1d6de5982e 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_te.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_te.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676"><ph name="SITE_NAME" /> సైటౠజోడించబడింది</translation>
<translation id="1383876407941801731">సెరà±à°šà±</translation>
<translation id="1384959399684842514">డౌనà±â€Œà°²à±‹à°¡à± పాజౠచేయబడింది</translation>
+<translation id="1409426117486808224">తెరిచిన à°Ÿà±à°¯à°¾à°¬à±â€Œà°² కోసం సరళమైన వీకà±à°·à°£</translation>
<translation id="1415402041810619267">URL à°•à±à°¦à°¿à°‚చబడింది</translation>
<translation id="1446450296470737166">MIDI పరికరాల పూరà±à°¤à°¿ నియం. à°…à°¨à±à°®.</translation>
<translation id="1620510694547887537">కెమెరా</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">à°•à±à°•à±à°•à±€à°²à°¨à± à°…à°¨à±à°®à°¤à°¿à°‚à°šà±</translation>
<translation id="2228071138934252756">మీ కెమెరానౠయాకà±à°¸à±†à°¸à± చేయడానికి <ph name="APP_NAME" />ని à°…à°¨à±à°®à°¤à°¿à°‚చడానికి, <ph name="BEGIN_LINK" />Android సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²<ph name="END_LINK" />లో కూడా కెమెరానౠఆనౠచేయండి.</translation>
<translation id="2241634353105152135">ఒకసారి మాతà±à°°à°®à±‡</translation>
+<translation id="2253414712144136228"><ph name="NAME_OF_LIST_ITEM" />‌నౠతీసివేయండి</translation>
<translation id="2289270750774289114">à°à°¦à±ˆà°¨à°¾ à°’à°• సైటౠసమీపంలోని à°¬à±à°²à±‚టూతౠపరికరాలనౠకనà±à°—ొనాలనà±à°•à±à°¨à±à°¨à°ªà±à°ªà±à°¡à± à°…à°¨à±à°®à°¤à°¿ à°…à°¡à±à°—à±à°¤à±à°‚ది (సిఫారà±à°¸à± చేయడమైనది)</translation>
<translation id="2315043854645842844">à°•à±à°²à°¯à°¿à°‚టౠతరపౠస‌రà±à°Ÿà°¿à°«à°¿à°•à±†à°Ÿà±â€Œ ఎంపికకౠఆపరేటింగౠసిసà±à°Ÿà°®à± మదà±à°¦à°¤à± లేదà±.</translation>
+<translation id="2321958826496381788">మీరౠదీనిని సౌకరà±à°¯à°µà°‚తంగా చదవగలిగే వరకౠసà±à°²à±ˆà°¡à°°à±â€Œà°¨à± లాగండి. పేరాపై రెండà±à°¸à°¾à°°à±à°²à± నొకà±à°•à°¿à°¨ తరà±à°µà°¾à°¤ వచనం కనీసం ఇంత పెదà±à°¦à°¦à°¿à°—à°¾ కనిపించాలి.</translation>
<translation id="2359808026110333948">కొనసాగించà±</translation>
<translation id="2379925928934107488">Chrome à°®à±à°¦à±à°°à± రంగౠరూపానà±à°¨à°¿ ఉపయోగించినపà±à°ªà±à°¡à±, వీలైతే, సైటà±â€Œà°²à°•à± à°®à±à°¦à±à°°à± రంగౠరూపానà±à°¨à°¿ వరà±à°¤à°¿à°‚పజేయండి</translation>
+<translation id="2387895666653383613">వచన à°ªà±à°°à°®à°¾à°£à°‚</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, ఇంకా మరో <ph name="NUM_MORE" /> à°…à°¨à±à°®à°¤à°¿à°‚చబడà±à°¡à°¾à°¯à°¿}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, ఇంకా మరో <ph name="NUM_MORE" /> à°…à°¨à±à°®à°¤à°¿à°‚చబడà±à°¡à°¾à°¯à°¿}}</translation>
<translation id="2434158240863470628">డౌనà±â€Œà°²à±‹à°¡à± పూరà±à°¤à°¯à°¿à°‚ది <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">సమాచారానà±à°¨à°¿ చూపà±</translation>
<translation id="3123473560110926937">కొనà±à°¨à°¿ సైటà±â€Œà°²à°²à±‹ à°¬à±à°²à°¾à°•à± చేయబడింది</translation>
<translation id="3198916472715691905">నిలà±à°µ చేసిన డేటా <ph name="STORAGE_AMOUNT" /></translation>
+<translation id="3203366800380907218">వెబౠనà±à°‚à°¡à°¿</translation>
<translation id="321187648315454507">మీకౠనోటిఫికేషనà±â€Œà°²à°¨à± పంపడానికి <ph name="APP_NAME" />ని à°…à°¨à±à°®à°¤à°¿à°‚చేందà±à°•à±, <ph name="BEGIN_LINK" />Android సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²<ph name="END_LINK" />లో కూడా నోటిఫికేషనà±â€Œà°²à°¨à± ఆనౠచేయండి.</translation>
<translation id="3227137524299004712">మైకà±à°°à±‹à°«à±‹à°¨à±</translation>
<translation id="3277252321222022663">సెనà±à°¸à°¾à°°à±â€Œà°²à°¨à± యాకà±à°¸à±†à°¸à± చేయడానికి సైటà±â€Œà°²à°¨à± à°…à°¨à±à°®à°¤à°¿à°¸à±à°¤à±à°‚ది (సిఫారà±à°¸à± చేసà±à°¤à±à°¨à±à°¨à°¾à°®à±)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">మీ పరికర వినియోగం</translation>
<translation id="385051799172605136">వెనà±à°•à°•à±</translation>
<translation id="3859306556332390985">à°®à±à°‚à°¦à±à°•à± జరà±à°ªà±</translation>
+<translation id="3895926599014793903">జూమౠచేయడానà±à°¨à°¿ నిరà±à°¬à°‚ధంగా à°ªà±à°°à°¾à°°à°‚à°­à°¿à°‚à°šà±</translation>
<translation id="3955193568934677022">à°°à°•à±à°·à°¿à°¤ కంటెంటà±â€Œà°¨à± à°ªà±à°²à±‡ చేయడానికి సైటà±â€Œà°²à°¨à± à°…à°¨à±à°®à°¤à°¿à°¸à±à°¤à±à°‚ది (సిఫారà±à°¸à± చేయబడింది)</translation>
<translation id="3967822245660637423">డౌనà±â€Œà°²à±‹à°¡à± పూరà±à°¤à°¯à°¿à°‚ది</translation>
<translation id="3987993985790029246">లింకà±â€Œà°¨à± కాపీ చేయి</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> / ?</translation>
<translation id="4002066346123236978">శీరà±à°·à°¿à°•</translation>
<translation id="4008040567710660924">నిరà±à°¦à°¿à°·à±à°Ÿ సైటౠకోసం à°•à±à°•à±à°•à±€à°²à°¨à± à°…à°¨à±à°®à°¤à°¿à°‚à°šà°‚à°¡à°¿.</translation>
+<translation id="4040330681741629921">సరళీకరించిన వీకà±à°·à°£à°²à±‹ సైటà±â€Œà°¨à± చూపగలిగినపà±à°ªà±à°¡à± నోటిఫికేషనౠపొందండి</translation>
<translation id="4046123991198612571">తరà±à°µà°¾à°¤ à°Ÿà±à°°à°¾à°•à±</translation>
+<translation id="4149994727733219643">వెబౠపేజీల కోసం సరళమైన వీకà±à°·à°£</translation>
<translation id="4165986682804962316">సైటౠసెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²à±</translation>
+<translation id="4194328954146351878">NFC పరికరాలలో సమాచారానà±à°¨à°¿ చూడటానికి, మారà±à°šà°¡à°¾à°¨à°¿à°•à°¿ సైటà±â€Œà°²à°¨à± à°…à°¨à±à°®à°¤à°¿à°‚చే à°®à±à°‚దౠఅడగాలి (సిఫారà±à°¸à± చేయడమైనది)</translation>
<translation id="4200726100658658164">లొకేషనౠసెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²à°¨à± తెరవండి</translation>
<translation id="4226663524361240545">నోటిఫికేషనà±â€Œà°²à± పరికరానà±à°¨à°¿ వైబà±à°°à±‡à°Ÿà± చేయవచà±à°šà±</translation>
<translation id="4259722352634471385">నావిగేషనౠబà±à°²à°¾à°•à± చేయబడింది: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">విసà±à°¤à°°à°¿à°‚à°šà±</translation>
<translation id="4336434711095810371">మొతà±à°¤à°‚ డేటానౠకà±à°²à°¿à°¯à°°à± చేయి</translation>
<translation id="4402755511846832236">మీరౠఈ పరికరానà±à°¨à°¿ యాకà±à°Ÿà°¿à°µà±â€Œà°—à°¾ ఉపయోగిసà±à°¤à±à°¨à±à°¨à°ªà±à°ªà±à°¡à± à°† విషయానà±à°¨à°¿ ఇతర సైటà±â€Œà°²à± తెలà±à°¸à±à°•à±‹à°•à±à°‚à°¡à°¾ à°¬à±à°²à°¾à°•à± చేయండి</translation>
+<translation id="4428065317363009941">యాడౠవà±à°¯à°•à±à°¤à°¿à°—తీకరణ</translation>
<translation id="4434045419905280838">పాపà±-à°…à°ªà±â€Œà°²à± మరియౠమళà±à°²à°¿à°‚à°ªà±à°²à±</translation>
<translation id="445467742685312942">à°°à°•à±à°·à°¿à°¤ కంటెంటà±â€Œà°¨à± à°ªà±à°²à±‡ చేయడానికి సైటà±â€Œà°²à°¨à± à°…à°¨à±à°®à°¤à°¿à°¸à±à°¤à±à°‚ది</translation>
<translation id="4468959413250150279">నిరà±à°¦à°¿à°·à±à°Ÿ సైటౠకోసం à°§à±à°µà°¨à°¿à°¨à°¿ à°®à±à°¯à±‚టౠచేయండి.</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">ఆపà±à°·à°¨à± à°¸à±à°•à±à°°à±€à°¨à± పైభాగానికి సమీపంలో à°…à°‚à°¦à±à°¬à°¾à°Ÿà±à°²à±‹ ఉంటà±à°‚ది</translation>
<translation id="5197729504361054390">మీరౠఎంచà±à°•à±à°¨à±à°¨ కాంటాకà±à°Ÿà±â€Œà°²à± <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />తో షేరౠచేయబడతాయి.</translation>
<translation id="5216942107514965959">చివరిగా ఈరోజౠసందరà±à°¶à°¿à°‚చారà±</translation>
+<translation id="5264323282659631142">'<ph name="CHIP_LABEL" />'నౠతీసివేయండి</translation>
<translation id="528192093759286357">à°«à±à°²à±-à°¸à±à°•à±à°°à±€à°¨à±â€Œ à°¨à±à°‚à°¡à°¿ నిషà±à°•à±à°°à°®à°¿à°‚చడానికి పైనà±à°‚à°¡à°¿ లాగి, వెనà±à°•à°•à± బటనà±â€Œà°¨à± తాకండి.</translation>
<translation id="5300589172476337783">చూపించà±</translation>
<translation id="5301954838959518834">సరే, à°…à°°à±à°¥à°®à±ˆà°‚ది</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">ఇది సైటà±â€Œà°² à°¦à±à°µà°¾à°°à°¾ à°¸à±à°Ÿà±‹à°°à± చేయబడిన <ph name="DATASIZE" /> డేటానà±, à°•à±à°•à±à°•à±€à°²à°¨à± à°•à±à°²à°¿à°¯à°°à± చేసà±à°¤à±à°‚ది.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(+ మరో 1)}other{(+ మరో #)}}</translation>
<translation id="5403592356182871684">పేరà±à°²à±</translation>
+<translation id="5412236728747081950">మీకౠమరింత సందరà±à°­à±‹à°šà°¿à°¤à°®à±ˆà°¨ యాడà±â€Œà°²à°¨à± చూపడానికి à°ˆ సైటౠమీ ఆసకà±à°¤à±à°²à°¨à± Chrome à°¨à±à°‚à°¡à°¿ పొందà±à°¤à±à°‚ది</translation>
<translation id="5438097262470833822">దీనిని à°Žà°‚à°šà±à°•à±‹à°µà°¡à°‚ à°¦à±à°µà°¾à°°à°¾ <ph name="WEBSITE" />కౠసంబంధించిన à°…à°¨à±à°®à°¤à±à°²à± రీసెటౠచేయబడతాయి</translation>
<translation id="5489227211564503167"><ph name="TOTAL_TIME" />లో <ph name="ELAPSED_TIME" /> సమయం గడిచిపోయింది.</translation>
<translation id="5494752089476963479">à°…à°¨à±à°šà°¿à°¤à°®à±ˆà°¨ లేదా తపà±à°ªà±à°¦à°¾à°°à°¿ పటà±à°Ÿà°¿à°‚చే à°ªà±à°°à°•à°Ÿà°¨à°²à°¨à± చూపించే సైటà±â€Œà°²à°²à±‹ à°ªà±à°°à°•à°Ÿà°¨à°²à°¨à± à°¬à±à°²à°¾à°•à± చేసà±à°¤à±à°‚ది</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">మళà±à°²à±€ లోడౠచేయి</translation>
<translation id="5596627076506792578">మరినà±à°¨à°¿ ఎంపికలà±</translation>
<translation id="5649053991847567735">ఆటోమేటికౠడౌనà±â€Œà°²à±‹à°¡à±â€Œà°²à±</translation>
+<translation id="5668404140385795438">దగà±à°—రకౠజూమౠచేయడానà±à°¨à°¿ నిరోధించడానికి à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚చే వెబà±â€Œà°¸à±ˆà°Ÿà± à°°à°¿à°•à±à°µà±†à°¸à±à°Ÿà±â€Œà°¨à± పటà±à°Ÿà°¿à°‚à°šà±à°•à±‹à°¦à±</translation>
<translation id="5677928146339483299">à°¬à±à°²à°¾à°•à± చేయబడింది</translation>
<translation id="5689516760719285838">లొకేషనà±</translation>
<translation id="5690795753582697420">Android సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²à°²à±‹ కెమెరా ఆఫౠచేయబడింది</translation>
-<translation id="5710871682236653961">మీరౠNFC పరికరాలనౠనొకà±à°•à°¿à°¨à°ªà±à°ªà±à°¡à±, సైటà±â€Œà°²à± సమాచారానà±à°¨à°¿ పంపడానికి, అలాగే à°¸à±à°µà±€à°•à°°à°¿à°‚చడానికి à°®à±à°‚దౠఅనà±à°®à°¤à°¿ కోసం à°…à°¡à±à°—à±à°¤à°¾à°¯à°¿ (సిఫారà±à°¸à± చేయబడింది)</translation>
<translation id="5719847187258001597">ఇది మీ హోమౠసà±à°•à±à°°à±€à°¨à±â€Œà°²à±‹ <ph name="ORIGIN" /> లేదా దాని యాపౠదà±à°µà°¾à°°à°¾ à°¸à±à°Ÿà±‹à°°à± చేయబడిన మొతà±à°¤à°‚ డేటా, à°•à±à°•à±à°•à±€à°²à°¨à± à°•à±à°²à°¿à°¯à°°à± చేసà±à°¤à±à°‚ది.</translation>
<translation id="5771720122942595109">'<ph name="PERMISSION_1" />'నౠబà±à°²à°¾à°•à± చేశారà±</translation>
<translation id="5804241973901381774">à°…à°¨à±à°®à°¤à±à°²à±</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">à°ªà±à°²à±‡ చేయి</translation>
<translation id="6818926723028410516">అంశాలనౠఎంచà±à°•à±‹à°‚à°¡à°¿</translation>
<translation id="6864395892908308021">à°ˆ పరికరం NFCని రీడౠచేయదà±</translation>
-<translation id="6910211073230771657">తొలగించబడింది</translation>
<translation id="6912998170423641340">à°•à±à°²à°¿à°ªà±â€Œà°¬à±‹à°°à±à°¡à± à°¨à±à°‚à°¡à°¿ వచనం మరియౠచితà±à°°à°¾à°²à°¨à± చదవకà±à°‚à°¡à°¾ సైటà±â€Œà°²à± à°¬à±à°²à°¾à°•à± చేయబడతాయి</translation>
<translation id="6945221475159498467">à°Žà°‚à°šà±à°•à±‹à°‚à°¡à°¿</translation>
<translation id="6965382102122355670">సరే</translation>
+<translation id="6981982820502123353">యాకà±à°¸à±†à°¸à°¿à°¬à°¿à°²à°¿à°Ÿà±€</translation>
<translation id="6992289844737586249">మీ మైకà±à°°à±‹à°«à±‹à°¨à±â€Œà°¨à± à°à°µà±ˆà°¨à°¾ సైటà±â€Œà°²à± ఉపయోగించగలిగేలా వాటిని à°…à°¨à±à°®à°¤à°¿à°‚చే à°®à±à°‚à°¦à±, మిమà±à°®à°²à±à°¨à°¿ à°…à°¡à±à°—à±à°¤à±à°‚ది (సిఫారà±à°¸à± చేయబడింది)</translation>
<translation id="7000754031042624318">Android సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²à°²à±‹ ఆఫౠచేయబడింది</translation>
<translation id="7016516562562142042">à°ªà±à°°à°¸à±à°¤à±à°¤ శోధన ఇంజినà±â€Œà°•à± à°…à°¨à±à°®à°¤à°¿à°‚చబడింది</translation>
+<translation id="702463548815491781">TalkBack లేదా à°¸à±à°µà°¿à°šà± యాకà±à°¸à±†à°¸à± ఆనà±â€Œà°²à±‹ ఉనà±à°¨à°ªà±à°ªà±à°¡à± సిఫారà±à°¸à± చేయబడింది</translation>
<translation id="7053983685419859001">నిరోధించà±</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1 à°Žà°‚à°šà±à°•à±‹à°¬à°¡à°¿à°‚ది}other{# à°Žà°‚à°šà±à°•à±‹à°¬à°¡à±à°¡à°¾à°¯à°¿}}</translation>
-<translation id="7070090581017165256">à°ˆ సైటౠగà±à°°à°¿à°‚à°šà°¿</translation>
<translation id="7087918508125750058"><ph name="ITEM_COUNT" /> à°Žà°‚à°šà±à°•à±‹à°¬à°¡à±à°¡à°¾à°¯à°¿. ఎంపికలౠసà±à°•à±à°°à±€à°¨à± పైభాగానికి సమీపంలో à°…à°‚à°¦à±à°¬à°¾à°Ÿà±à°²à±‹ ఉనà±à°¨à°¾à°¯à°¿</translation>
<translation id="7141896414559753902">మళà±à°²à°¿à°‚à°ªà±à°²à±, పాపà±-à°…à°ªà±â€Œà°²à°¨à± చూపనివà±à°µà°•à±à°‚à°¡à°¾ సైటà±â€Œà°²à°¨à± à°¬à±à°²à°¾à°•à± చేసà±à°¤à±à°‚ది (సిఫారà±à°¸à± చేయడమైనది)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> KB</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">à°’à°• సైటౠమీ మైకà±à°°à±‹à°«à±‹à°¨à±â€Œà°¨à± ఉపయోగిసà±à°¤à±‹à°‚ది</translation>
<translation id="7561196759112975576">à°Žà°²à±à°²à°ªà±à°ªà±à°¡à±‚</translation>
-<translation id="7572498721684305250">మీరౠNFC పరికరాలనౠనొకà±à°•à°¿à°¨à°ªà±à°ªà±à°¡à±, సైటà±â€Œà°²à± సమాచారానà±à°¨à°¿ పంపడానà±à°¨à°¿, అలాగే à°¸à±à°µà±€à°•à°°à°¿à°‚చడానà±à°¨à°¿ à°¬à±à°²à°¾à°•à± చేసà±à°¤à±à°‚ది (సిఫారà±à°¸à± చేయబడింది)</translation>
<translation id="757524316907819857">à°°à°•à±à°·à°¿à°¤ కంటెంటà±â€Œà°¨à± à°ªà±à°²à±‡ చేయకà±à°‚à°¡à°¾ సైటà±â€Œà°²à°¨à± à°¬à±à°²à°¾à°•à± చేసà±à°¤à±à°‚ది</translation>
+<translation id="7577900504646297215">ఆసకà±à°¤à±à°²à°¨à± మేనేజౠచేయండి</translation>
<translation id="7649070708921625228">సహాయం</translation>
<translation id="7658239707568436148">à°°à°¦à±à°¦à± చేయండి</translation>
<translation id="7781829728241885113">నినà±à°¨</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">కనెకà±à°·à°¨à± à°¸à±à°°à°•à±à°·à°¿à°¤à°‚à°—à°¾ ఉంది</translation>
<translation id="8249310407154411074">à°Žà°—à±à°µà°•à± తరలించà±</translation>
<translation id="8261506727792406068">తొలగించà±</translation>
+<translation id="8284326494547611709">à°•à±à°¯à°¾à°ªà±à°·à°¨à±â€Œà°²à±</translation>
<translation id="8300705686683892304">యాపౠదà±à°µà°¾à°°à°¾ నిరà±à°µà°¹à°¿à°‚చబడà±à°¤à±à°¨à±à°¨à°µà°¿</translation>
<translation id="8324158725704657629">మళà±à°²à±€ అడగవదà±à°¦à±</translation>
<translation id="8372893542064058268">నిరà±à°¦à°¿à°·à±à°Ÿ సైటౠకోసం నేపథà±à°¯ సింకà±â€Œà°¨à± à°…à°¨à±à°®à°¤à°¿à°¸à±à°¤à±à°‚ది.</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">దగà±à°—à°°à°¿à°•à°¿ జూమౠచేయి</translation>
<translation id="8921772741368021346"><ph name="POSITION" /> / <ph name="DURATION" /></translation>
<translation id="8926666909099850184">à°ˆ పరికరంలో NFC ఆఫౠచేయబడింది. <ph name="BEGIN_LINK" />Android సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²<ph name="END_LINK" />లో దానà±à°¨à°¿ ఆనౠచేయండి.</translation>
+<translation id="8928445016601307354">NFC పరికరాలలో సమాచారానà±à°¨à°¿ చూడకà±à°‚à°¡à°¾, మారà±à°šà°•à±à°‚à°¡à°¾ ఉండేలా సైటà±â€Œà°²à°¨à± à°¬à±à°²à°¾à°•à± చేయండి</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">à°à°¦à±ˆà°¨à°¾ à°’à°• నిరà±à°¦à°¿à°·à±à°Ÿ సైటà±â€Œà°²à±‹ à°•à±à°•à±à°•à±€à°²à°¨à± à°¬à±à°²à°¾à°•à± చేయండి.</translation>
<translation id="8959122750345127698">దీనికి నావిగేటౠచేయడం సాధà±à°¯à°ªà°¡à°¦à±: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_th.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_th.xtb
index ae70d20241e..1555b16a4a4 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_th.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_th.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">เพิ่มเว็บไซต์ <ph name="SITE_NAME" /> à¹à¸¥à¹‰à¸§</translation>
<translation id="1383876407941801731">ค้นหา</translation>
<translation id="1384959399684842514">หยุดดาวน์โหลดไว้ชั่วคราว</translation>
+<translation id="1409426117486808224">มุมมองอย่างง่ายสำหรับà¹à¸—็บที่เปิดไว้</translation>
<translation id="1415402041810619267">ตัด URL ให้สั้นลงà¹à¸¥à¹‰à¸§</translation>
<translation id="1446450296470737166">ควบคุมอุปà¸à¸£à¸“์ MIDI ได้สมบูรณ์</translation>
<translation id="1620510694547887537">à¸à¸¥à¹‰à¸­à¸‡à¸–่ายรูป</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">อนุà¸à¸²à¸•à¸„ุà¸à¸à¸µà¹‰</translation>
<translation id="2228071138934252756">หาà¸à¸•à¹‰à¸­à¸‡à¸à¸²à¸£à¸­à¸™à¸¸à¸à¸²à¸•à¹ƒà¸«à¹‰ <ph name="APP_NAME" /> เข้าถึงà¸à¸¥à¹‰à¸­à¸‡à¸–่ายรูป ให้เปิดใช้à¸à¸¥à¹‰à¸­à¸‡à¹ƒà¸™<ph name="BEGIN_LINK" />à¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่า Android<ph name="END_LINK" /> ด้วย</translation>
<translation id="2241634353105152135">เพียงครั้งเดียว</translation>
+<translation id="2253414712144136228">นำ<ph name="NAME_OF_LIST_ITEM" />ออà¸</translation>
<translation id="2289270750774289114">ถามเมื่อเว็บไซต์ต้องà¸à¸²à¸£à¸„้นหาอุปà¸à¸£à¸“์บลูทูธใà¸à¸¥à¹‰à¹€à¸„ียง (à¹à¸™à¸°à¸™à¸³)</translation>
<translation id="2315043854645842844">ระบบปà¸à¸´à¸šà¸±à¸•à¸´à¸à¸²à¸£à¹„ม่สนับสนุนà¸à¸²à¸£à¹€à¸¥à¸·à¸­à¸à¹ƒà¸šà¸£à¸±à¸šà¸£à¸­à¸‡à¸à¸±à¹ˆà¸‡à¸¥à¸¹à¸à¸„้า</translation>
+<translation id="2321958826496381788">ลาà¸à¹à¸–บเลื่อนจนà¸à¸§à¹ˆà¸²à¸„ุณจะสามารถอ่านได้อย่างสะดวภข้อความควรมีขนาดเท่านี้เป็นอย่างน้อยหลังจาà¸à¹à¸•à¸° 2 ครั้งบนย่อหน้า</translation>
<translation id="2359808026110333948">ต่อไป</translation>
<translation id="2379925928934107488">เมื่อทำได้ ให้ใช้ธีมมืดà¸à¸±à¸šà¹€à¸§à¹‡à¸šà¹„ซต์เมื่อ Chrome ใช้ธีมมืด</translation>
+<translation id="2387895666653383613">อัตราส่วนข้อความ</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{อนุà¸à¸²à¸•à¹ƒà¸«à¹‰à¹€à¸‚้าถึง<ph name="PERMISSION_1" /> <ph name="PERMISSION_2" /> à¹à¸¥à¸°à¸­à¸µà¸ <ph name="NUM_MORE" /> รายà¸à¸²à¸£}other{อนุà¸à¸²à¸•à¹ƒà¸«à¹‰à¹€à¸‚้าถึง<ph name="PERMISSION_1" /> <ph name="PERMISSION_2" /> à¹à¸¥à¸°à¸­à¸µà¸ <ph name="NUM_MORE" /> รายà¸à¸²à¸£}}</translation>
<translation id="2434158240863470628">ดาวน์โหลดเสร็จสมบูรณ์ <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">à¹à¸ªà¸”งข้อมูล</translation>
<translation id="3123473560110926937">บล็อà¸à¹ƒà¸™à¸šà¸²à¸‡à¹€à¸§à¹‡à¸šà¹„ซต์</translation>
<translation id="3198916472715691905">ข้อมูลที่จัดเà¸à¹‡à¸šà¸¡à¸µ <ph name="STORAGE_AMOUNT" /></translation>
+<translation id="3203366800380907218">จาà¸à¹€à¸§à¹‡à¸š</translation>
<translation id="321187648315454507">หาà¸à¸•à¹‰à¸­à¸‡à¸à¸²à¸£à¸­à¸™à¸¸à¸à¸²à¸•à¹ƒà¸«à¹‰ <ph name="APP_NAME" /> ส่งà¸à¸²à¸£à¹à¸ˆà¹‰à¸‡à¹€à¸•à¸·à¸­à¸™à¹ƒà¸«à¹‰à¸„ุณ ให้เปิดใช้à¸à¸²à¸£à¹à¸ˆà¹‰à¸‡à¹€à¸•à¸·à¸­à¸™à¹ƒà¸™<ph name="BEGIN_LINK" />à¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่า Android<ph name="END_LINK" /> ด้วย</translation>
<translation id="3227137524299004712">ไมโครโฟน</translation>
<translation id="3277252321222022663">อนุà¸à¸²à¸•à¹ƒà¸«à¹‰à¹€à¸§à¹‡à¸šà¹„ซต์เข้าถึงเซ็นเซอร์ (à¹à¸™à¸°à¸™à¸³)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">à¸à¸²à¸£à¹ƒà¸Šà¹‰à¸‡à¸²à¸™à¸­à¸¸à¸›à¸à¸£à¸“์ของคุณ</translation>
<translation id="385051799172605136">à¸à¸¥à¸±à¸š</translation>
<translation id="3859306556332390985">ไปข้างหน้า</translation>
+<translation id="3895926599014793903">บังคับให้เปิดใช้à¸à¸²à¸£à¸‹à¸¹à¸¡</translation>
<translation id="3955193568934677022">อนุà¸à¸²à¸•à¹ƒà¸«à¹‰à¹€à¸§à¹‡à¸šà¹„ซต์เล่นเนื้อหาที่ได้รับความคุ้มครอง (à¹à¸™à¸°à¸™à¸³)</translation>
<translation id="3967822245660637423">ดาวน์โหลดเสร็จสมบูรณ์</translation>
<translation id="3987993985790029246">คัดลอà¸à¸¥à¸´à¸‡à¸à¹Œ</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" />/?</translation>
<translation id="4002066346123236978">ชื่อ</translation>
<translation id="4008040567710660924">อนุà¸à¸²à¸•à¸„ุà¸à¸à¸µà¹‰à¸‚องเว็บไซต์ที่เจาะจง</translation>
+<translation id="4040330681741629921">รับà¸à¸²à¸£à¹à¸ˆà¹‰à¸‡à¹€à¸•à¸·à¸­à¸™à¹€à¸¡à¸·à¹ˆà¸­à¹à¸ªà¸”งเว็บไซต์ในมุมมองอย่างง่ายได้</translation>
<translation id="4046123991198612571">à¹à¸—ร็à¸à¸–ัดไป</translation>
+<translation id="4149994727733219643">มุมมองอย่างง่ายสำหรับหน้าเว็บ</translation>
<translation id="4165986682804962316">à¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่าเว็บไซต์</translation>
+<translation id="4194328954146351878">ถามà¸à¹ˆà¸­à¸™à¸—ี่จะอนุà¸à¸²à¸•à¹ƒà¸«à¹‰à¹€à¸§à¹‡à¸šà¹„ซต์ดูà¹à¸¥à¸°à¹€à¸›à¸¥à¸µà¹ˆà¸¢à¸™à¹à¸›à¸¥à¸‡à¸‚้อมูลในอุปà¸à¸£à¸“์ NFC (à¹à¸™à¸°à¸™à¸³)</translation>
<translation id="4200726100658658164">เปิดà¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่าตำà¹à¸«à¸™à¹ˆà¸‡</translation>
<translation id="4226663524361240545">à¸à¸²à¸£à¹à¸ˆà¹‰à¸‡à¹€à¸•à¸·à¸­à¸™à¸­à¸²à¸ˆà¸—ำให้อุปà¸à¸£à¸“์สั่น</translation>
<translation id="4259722352634471385">มีà¸à¸²à¸£à¸šà¸¥à¹‡à¸­à¸à¸à¸²à¸£à¸™à¸³à¸—าง: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">ขยาย</translation>
<translation id="4336434711095810371">ล้างข้อมูลทั้งหมด</translation>
<translation id="4402755511846832236">บล็อà¸à¹€à¸§à¹‡à¸šà¹„ซต์ไม่ให้ทราบเวลาที่คุณใช้งานอุปà¸à¸£à¸“์นี้อยู่</translation>
+<translation id="4428065317363009941">à¸à¸²à¸£à¸›à¸£à¸±à¸šà¹‚ฆษณาตามโปรไฟล์ของผู้ใช้</translation>
<translation id="4434045419905280838">ป๊อปอัปà¹à¸¥à¸°à¸à¸²à¸£à¹€à¸›à¸¥à¸µà¹ˆà¸¢à¸™à¹€à¸ªà¹‰à¸™à¸—าง</translation>
<translation id="445467742685312942">อนุà¸à¸²à¸•à¹ƒà¸«à¹‰à¹€à¸§à¹‡à¸šà¹„ซต์เล่นเนื้อหาที่ได้รับความคุ้มครอง</translation>
<translation id="4468959413250150279">ปิดเสียงไซต์ที่ต้องà¸à¸²à¸£</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">ตัวเลือà¸à¸­à¸¢à¸¹à¹ˆà¸•à¸£à¸‡à¸šà¸£à¸´à¹€à¸§à¸“ด้านบนของหน้าจอ</translation>
<translation id="5197729504361054390">ระบบจะà¹à¸Šà¸£à¹Œà¸£à¸²à¸¢à¸Šà¸·à¹ˆà¸­à¸•à¸´à¸”ต่อที่คุณเลือà¸à¸à¸±à¸š <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /></translation>
<translation id="5216942107514965959">เข้าชมล่าสุดวันนี้</translation>
+<translation id="5264323282659631142">นำ "<ph name="CHIP_LABEL" />" ออà¸</translation>
<translation id="528192093759286357">ลาà¸à¸ˆà¸²à¸à¸”้านบน à¹à¸¥à¹‰à¸§à¹à¸•à¸°à¸›à¸¸à¹ˆà¸¡à¸à¸¥à¸±à¸šà¹€à¸žà¸·à¹ˆà¸­à¸­à¸­à¸à¸ˆà¸²à¸à¹‚หมดเต็มหน้าจอ</translation>
<translation id="5300589172476337783">à¹à¸ªà¸”ง</translation>
<translation id="5301954838959518834">ตà¸à¸¥à¸‡ เข้าใจà¹à¸¥à¹‰à¸§</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">à¸à¸²à¸£à¸”ำเนินà¸à¸²à¸£à¸™à¸µà¹‰à¸ˆà¸°à¸¥à¹‰à¸²à¸‡à¸‚้อมูลà¹à¸¥à¸°à¸„ุà¸à¸à¸µà¹‰à¸—ี่เว็บไซต์ต่างๆ จัดเà¸à¹‡à¸šà¹„ว้รวมทั้งสิ้น <ph name="DATASIZE" /></translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(อีภ1 รายà¸à¸²à¸£)}other{(อีภ# รายà¸à¸²à¸£)}}</translation>
<translation id="5403592356182871684">ชื่อ</translation>
+<translation id="5412236728747081950">เว็บไซต์นี้รับข้อมูลความสนใจของคุณจาภChrome เพื่อà¹à¸ªà¸”งโฆษณาที่เà¸à¸µà¹ˆà¸¢à¸§à¸‚้องมาà¸à¸‚ึ้น</translation>
<translation id="5438097262470833822">ตัวเลือà¸à¸™à¸µà¹‰à¸ˆà¸°à¸£à¸µà¹€à¸‹à¹‡à¸•à¸ªà¸´à¸—ธิ์ของ <ph name="WEBSITE" /></translation>
<translation id="5489227211564503167">เวลาผ่านไป <ph name="ELAPSED_TIME" /> จาภ<ph name="TOTAL_TIME" /></translation>
<translation id="5494752089476963479">บล็อà¸à¹‚ฆษณาในเว็บไซต์ที่à¹à¸ªà¸”งโฆษณาที่à¹à¸—รà¸à¸«à¸£à¸·à¸­à¸—ำให้เข้าใจผิด</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">โหลดใหม่</translation>
<translation id="5596627076506792578">ตัวเลือà¸à¹€à¸žà¸´à¹ˆà¸¡à¹€à¸•à¸´à¸¡</translation>
<translation id="5649053991847567735">à¸à¸²à¸£à¸”าวน์โหลดโดยอัตโนมัติ</translation>
+<translation id="5668404140385795438">ลบล้างคำขอของเว็บไซต์เพื่อป้องà¸à¸±à¸™à¸à¸²à¸£à¸‹à¸¹à¸¡à¹€à¸‚้า</translation>
<translation id="5677928146339483299">ถูà¸à¸šà¸¥à¹‡à¸­à¸</translation>
<translation id="5689516760719285838">ตำà¹à¸«à¸™à¹ˆà¸‡</translation>
<translation id="5690795753582697420">à¸à¸¥à¹‰à¸­à¸‡à¸›à¸´à¸”อยู่ในà¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่า Android</translation>
-<translation id="5710871682236653961">ถามà¸à¹ˆà¸­à¸™à¸—ี่จะอนุà¸à¸²à¸•à¹ƒà¸«à¹‰à¹€à¸§à¹‡à¸šà¹„ซต์ส่งà¹à¸¥à¸°à¸£à¸±à¸šà¸‚้อมูลเมื่อคุณà¹à¸•à¸°à¸­à¸¸à¸›à¸à¸£à¸“์ NFC (à¹à¸™à¸°à¸™à¸³)</translation>
<translation id="5719847187258001597">à¸à¸²à¸£à¸”ำเนินà¸à¸²à¸£à¸™à¸µà¹‰à¸ˆà¸°à¸¥à¹‰à¸²à¸‡à¸‚้อมูลà¹à¸¥à¸°à¸„ุà¸à¸à¸µà¹‰à¸—ั้งหมดที่ <ph name="ORIGIN" /> หรือà¹à¸­à¸›à¸—ี่อยู่ในหน้าจอหลัà¸à¸ˆà¸±à¸”เà¸à¹‡à¸šà¹„ว้</translation>
<translation id="5771720122942595109">บล็อà¸<ph name="PERMISSION_1" /></translation>
<translation id="5804241973901381774">à¸à¸²à¸£à¸­à¸™à¸¸à¸à¸²à¸•</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">เล่น</translation>
<translation id="6818926723028410516">เลือà¸à¸£à¸²à¸¢à¸à¸²à¸£</translation>
<translation id="6864395892908308021">อุปà¸à¸£à¸“์นี้อ่าน NFC ไม่ได้</translation>
-<translation id="6910211073230771657">ลบà¹à¸¥à¹‰à¸§</translation>
<translation id="6912998170423641340">บล็อà¸à¹€à¸§à¹‡à¸šà¹„ซต์ไม่ให้อ่านข้อความà¹à¸¥à¸°à¸”ูรูปภาพจาà¸à¸„ลิปบอร์ด</translation>
<translation id="6945221475159498467">เลือà¸</translation>
<translation id="6965382102122355670">ตà¸à¸¥à¸‡</translation>
+<translation id="6981982820502123353">à¸à¸²à¸£à¸Šà¹ˆà¸§à¸¢à¹€à¸«à¸¥à¸·à¸­à¸žà¸´à¹€à¸¨à¸©</translation>
<translation id="6992289844737586249">ถามà¸à¹ˆà¸­à¸™ à¸à¹ˆà¸­à¸™à¸—ี่จะอนุà¸à¸²à¸•à¹ƒà¸«à¹‰à¹€à¸§à¹‡à¸šà¹„ซต์ใช้ไมโครโฟน (à¹à¸™à¸°à¸™à¸³)</translation>
<translation id="7000754031042624318">ปิดในà¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่า Android</translation>
<translation id="7016516562562142042">อนุà¸à¸²à¸•à¸ªà¸³à¸«à¸£à¸±à¸šà¹€à¸„รื่องมือค้นหาปัจจุบัน</translation>
+<translation id="702463548815491781">à¹à¸™à¸°à¸™à¸³à¹ƒà¸«à¹‰à¹ƒà¸Šà¹‰à¹€à¸¡à¸·à¹ˆà¸­ TalkBack หรือà¸à¸²à¸£à¹€à¸‚้าถึงด้วยสวิตช์เปิดอยู่</translation>
<translation id="7053983685419859001">บล็อà¸</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{เลือภ1 รายà¸à¸²à¸£}other{เลือภ# รายà¸à¸²à¸£}}</translation>
-<translation id="7070090581017165256">เà¸à¸µà¹ˆà¸¢à¸§à¸à¸±à¸šà¹€à¸§à¹‡à¸šà¹„ซต์นี้</translation>
<translation id="7087918508125750058">เลือà¸à¹„ว้ <ph name="ITEM_COUNT" /> รายà¸à¸²à¸£ ตัวเลือà¸à¸­à¸¢à¸¹à¹ˆà¸•à¸£à¸‡à¸šà¸£à¸´à¹€à¸§à¸“ด้านบนของหน้าจอ</translation>
<translation id="7141896414559753902">บล็อà¸à¹€à¸§à¹‡à¸šà¹„ซต์ไม่ให้à¹à¸ªà¸”งป๊อปอัปà¹à¸¥à¸°à¸à¸²à¸£à¹€à¸›à¸¥à¸µà¹ˆà¸¢à¸™à¹€à¸ªà¹‰à¸™à¸—าง (à¹à¸™à¸°à¸™à¸³)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> KB</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">มีเว็บไซต์à¸à¸³à¸¥à¸±à¸‡à¹ƒà¸Šà¹‰à¹„มโครโฟน</translation>
<translation id="7561196759112975576">ทุà¸à¸„รั้ง</translation>
-<translation id="7572498721684305250">บล็อà¸à¹€à¸§à¹‡à¸šà¹„ซต์ไม่ให้ส่งหรือรับข้อมูลเมื่อคุณà¹à¸•à¸°à¸­à¸¸à¸›à¸à¸£à¸“์ NFC</translation>
<translation id="757524316907819857">บล็อà¸à¹„ม่ให้เว็บไซต์เล่นเนื้อหาที่ได้รับความคุ้มครอง</translation>
+<translation id="7577900504646297215">จัดà¸à¸²à¸£à¸„วามสนใจ</translation>
<translation id="7649070708921625228">ความช่วยเหลือ</translation>
<translation id="7658239707568436148">ยà¸à¹€à¸¥à¸´à¸</translation>
<translation id="7781829728241885113">เมื่อวานนี้</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">à¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸›à¸¥à¸­à¸”ภัย</translation>
<translation id="8249310407154411074">เลื่อนไปบนสุด</translation>
<translation id="8261506727792406068">ลบ</translation>
+<translation id="8284326494547611709">คำบรรยาย</translation>
<translation id="8300705686683892304">จัดà¸à¸²à¸£à¹‚ดยà¹à¸­à¸›</translation>
<translation id="8324158725704657629">ไม่ต้องถามอีà¸</translation>
<translation id="8372893542064058268">อนุà¸à¸²à¸•à¹ƒà¸«à¹‰à¹ƒà¸Šà¹‰à¸à¸²à¸£à¸‹à¸´à¸‡à¸„์ในà¹à¸šà¹‡à¸à¸à¸£à¸²à¸§à¸”์สำหรับเว็บไซต์ที่เจาะจง</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">ขยาย</translation>
<translation id="8921772741368021346"><ph name="POSITION" /> / <ph name="DURATION" /></translation>
<translation id="8926666909099850184">NFC ในอุปà¸à¸£à¸“์นี้ปิดอยู่ เปิดได้ใน<ph name="BEGIN_LINK" />à¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่า Android<ph name="END_LINK" /></translation>
+<translation id="8928445016601307354">บล็อà¸à¹€à¸§à¹‡à¸šà¹„ซต์ไม่ให้ดูà¹à¸¥à¸°à¹€à¸›à¸¥à¸µà¹ˆà¸¢à¸™à¹à¸›à¸¥à¸‡à¸‚้อมูลในอุปà¸à¸£à¸“์ NFC</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">บล็อà¸à¸„ุà¸à¸à¸µà¹‰à¸‚องเว็บไซต์ที่เจาะจง</translation>
<translation id="8959122750345127698">ไม่สามารถเข้าถึงà¸à¸²à¸£à¸™à¸³à¸—างได้: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_tr.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_tr.xtb
index 13856a0b799..f16f12dfcf3 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_tr.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_tr.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676"><ph name="SITE_NAME" /> sitesi eklendi</translation>
<translation id="1383876407941801731">Ara</translation>
<translation id="1384959399684842514">İndirme işlemi duraklatıldı</translation>
+<translation id="1409426117486808224">Açık sekmeler için basitleştirilmiş görünüm</translation>
<translation id="1415402041810619267">URL kısaltıldı</translation>
<translation id="1446450296470737166">MIDI cihazlarının tam denetimine izin verme</translation>
<translation id="1620510694547887537">Kamera</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">Çerezlere izin ver</translation>
<translation id="2228071138934252756"><ph name="APP_NAME" /> uygulamasının kameranıza erişebilmesi için <ph name="BEGIN_LINK" />Android Ayarları<ph name="END_LINK" />'nda da kamerayı açın.</translation>
<translation id="2241634353105152135">Sadece bir defa</translation>
+<translation id="2253414712144136228"><ph name="NAME_OF_LIST_ITEM" /> öğesini kaldır</translation>
<translation id="2289270750774289114">Bir site yakındaki Bluetooth cihazları bulmak istediğinde sor (önerilir)</translation>
<translation id="2315043854645842844">İstemci tarafı sertifika seçimi, işletim sistemi tarafından desteklenmiyor.</translation>
+<translation id="2321958826496381788">Bu yazıyı rahatça okuyana kadar kaydırma çubuğunu sürükleyin. Bir paragrafa iki kez hafifçe dokunduğunuzda metin en az bunun kadar büyük görünmelidir.</translation>
<translation id="2359808026110333948">Devam et</translation>
<translation id="2379925928934107488">Mümkünse Chrome koyu tema kullandığında sitelere de koyu tema uygulayın</translation>
+<translation id="2387895666653383613">Metin ölçekleme</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ve <ph name="NUM_MORE" /> tanesi için daha izin verildi}other{<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> ve <ph name="NUM_MORE" /> tanesi için daha izin verildi}}</translation>
<translation id="2434158240863470628">İndirme işlemi tamamlandı <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">Bilgileri Göster</translation>
<translation id="3123473560110926937">Bazı sitelerde engellendi</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> depolanmış veri</translation>
+<translation id="3203366800380907218">Web'den</translation>
<translation id="321187648315454507"><ph name="APP_NAME" /> uygulamasının size bildirim gönderebilmesi için <ph name="BEGIN_LINK" />Android Ayarları<ph name="END_LINK" />'nda da bildirimleri açın.</translation>
<translation id="3227137524299004712">Mikrofon</translation>
<translation id="3277252321222022663">Sitelerin sensörlere erişmesine izin ver (önerilen)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">Cihaz kullanımınız</translation>
<translation id="385051799172605136">Geri</translation>
<translation id="3859306556332390985">Ä°leriye doÄŸru git</translation>
+<translation id="3895926599014793903">Yakınlaştırmayı etkinleştirmeye zorla</translation>
<translation id="3955193568934677022">Sitelerin korumalı içeriği oynatmasına izin ver (önerilir)</translation>
<translation id="3967822245660637423">İndirme tamamlandı</translation>
<translation id="3987993985790029246">Bağlantıyı kopyala</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> / ?</translation>
<translation id="4002066346123236978">Başlık</translation>
<translation id="4008040567710660924">Belirli bir site için çerezlere izin verin.</translation>
+<translation id="4040330681741629921">Siteler basitleştirilmiş görünümde gösterilebiliyorsa bilgilendirilirsiniz</translation>
<translation id="4046123991198612571">Sonraki parça</translation>
+<translation id="4149994727733219643">Web sayfalarının basitleştirilmiş görünümü</translation>
<translation id="4165986682804962316">Site ayarları</translation>
+<translation id="4194328954146351878">NFC cihazlarda sitelere bilgileri görme ve değiştirme izni vermeden önce sor (önerilir)</translation>
<translation id="4200726100658658164">Konum Ayarlarını açın</translation>
<translation id="4226663524361240545">Bildirimler cihazı titretebilir</translation>
<translation id="4259722352634471385">Gezinme engellendi: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">GeniÅŸlet</translation>
<translation id="4336434711095810371">Tüm verileri temizle</translation>
<translation id="4402755511846832236">Bu cihazı etkin olarak kullandığınızda sitelerin bunu bilmesi engellenir</translation>
+<translation id="4428065317363009941">Reklam kiÅŸiselleÅŸtirme</translation>
<translation id="4434045419905280838">Pop-up'lar ve yönlendirmeler</translation>
<translation id="445467742685312942">Sitelerin korumalı içeriği oynatmasına izin ver</translation>
<translation id="4468959413250150279">Belirli bir site için sesi kapatın.</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">Seçenek, ekranın üst kısmına yakın bir yerdedir</translation>
<translation id="5197729504361054390">Seçtiğiniz kişiler <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ile paylaşılacak.</translation>
<translation id="5216942107514965959">En son bugün ziyaret edildi</translation>
+<translation id="5264323282659631142">"<ph name="CHIP_LABEL" />" çipini kaldır</translation>
<translation id="528192093759286357">Tam ekrandan çıkmak için yukarıdan sürükleyin ve geri düğmesine dokunun.</translation>
<translation id="5300589172476337783">Göster</translation>
<translation id="5301954838959518834">Tamam, anladım</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">Bu işlem, siteler tarafından depolanan <ph name="DATASIZE" /> boyutunda veriyi ve çerezi temizler.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(+ 1 tane daha)}other{(+ # tane daha)}}</translation>
<translation id="5403592356182871684">Adlar</translation>
+<translation id="5412236728747081950">Bu site size daha alakalı reklamlar göstermek için Chrome'dan ilgi alanlarınızı öğrenir</translation>
<translation id="5438097262470833822">Bu tercih, <ph name="WEBSITE" /> izinlerini sıfırlar</translation>
<translation id="5489227211564503167">Geçen süre: <ph name="ELAPSED_TIME" />/<ph name="TOTAL_TIME" /></translation>
<translation id="5494752089476963479">Araya giren veya yanıltıcı reklamlar gösteren sitelerde reklamları engelle</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">Yeniden Yükle</translation>
<translation id="5596627076506792578">Diğer seçenekler</translation>
<translation id="5649053991847567735">Otomatik indirmeler</translation>
+<translation id="5668404140385795438">Web sitesinin yakınlaştırmayı önleme isteğini geçersiz kıl</translation>
<translation id="5677928146339483299">Engelleniyor</translation>
<translation id="5689516760719285838">Konum</translation>
<translation id="5690795753582697420">Kamera, Android ayarlarında kapatıldı</translation>
-<translation id="5710871682236653961">NFC cihazlarına dokunduğunuzda sitelerin bilgi göndermesine ve almasına izin verilmeden önce size sorulur (önerilen)</translation>
<translation id="5719847187258001597">Bu işlem, Ana ekranınızdaki <ph name="ORIGIN" /> sitesi ve sitenin uygulaması tarafından depolanan tüm verileri ve çerezleri temizleyecek.</translation>
<translation id="5771720122942595109"><ph name="PERMISSION_1" /> engellendi</translation>
<translation id="5804241973901381774">Ä°zinler</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">Oynat</translation>
<translation id="6818926723028410516">Öğe seçin</translation>
<translation id="6864395892908308021">Bu cihaz NFC'yi okuyamıyor</translation>
-<translation id="6910211073230771657">Silindi</translation>
<translation id="6912998170423641340">Sitelerin panodaki metni ve resimleri okumasını engelle</translation>
<translation id="6945221475159498467">Seç</translation>
<translation id="6965382102122355670">Tamam</translation>
+<translation id="6981982820502123353">EriÅŸilebilirlik</translation>
<translation id="6992289844737586249">Sitelerin, mikrofonunuzu kullanmasına izin verilmeden önce size sorulsun (önerilen)</translation>
<translation id="7000754031042624318">Android ayarlarından kapatıldı</translation>
<translation id="7016516562562142042">Geçerli arama motoru için izin verildi</translation>
+<translation id="702463548815491781">TalkBack veya Anahtar Erişimi açık olduğunda önerilir</translation>
<translation id="7053983685419859001">Engelle</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1 öğe seçildi}other{# öğe seçildi}}</translation>
-<translation id="7070090581017165256">Bu site hakkında</translation>
<translation id="7087918508125750058"><ph name="ITEM_COUNT" /> öğe seçildi. Seçenekler, ekranın üst kısmına yakın bir yerde bulunur</translation>
<translation id="7141896414559753902">Sitelerin pop-up göstermesini ve yönlendirme yapmasını engelle (önerilir)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> KB</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">Bir site mikrofonunuzu kullanıyor</translation>
<translation id="7561196759112975576">Her zaman</translation>
-<translation id="7572498721684305250">NFC cihazlarına dokunduğunuzda sitelerin bilgi göndermesini ve almasını engelle</translation>
<translation id="757524316907819857">Sitelerin korumalı içeriği oynatmasını engellenir</translation>
+<translation id="7577900504646297215">İlgi alanlarını yönet</translation>
<translation id="7649070708921625228">Yardım</translation>
<translation id="7658239707568436148">Ä°ptal</translation>
<translation id="7781829728241885113">Dün</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">Bağlantı güvenli</translation>
<translation id="8249310407154411074">En üste taşı</translation>
<translation id="8261506727792406068">Sil</translation>
+<translation id="8284326494547611709">Altyazılar</translation>
<translation id="8300705686683892304">Uygulama tarafından yönetiliyor</translation>
<translation id="8324158725704657629">Tekrar sorma</translation>
<translation id="8372893542064058268">Belirli bir site için Arka Plan Senkronizasyonuna izin verin.</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">Yakınlaştır</translation>
<translation id="8921772741368021346"><ph name="POSITION" />/<ph name="DURATION" /></translation>
<translation id="8926666909099850184">NFC bu cihazda kapalı. Bu özelliği <ph name="BEGIN_LINK" />Android Ayarları<ph name="END_LINK" />'nda açın.</translation>
+<translation id="8928445016601307354">NFC cihazlarda sitelerin bilgileri görmesini ve değiştirmesini engelle</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">Belirli bir site için çerezleri engelleyin.</translation>
<translation id="8959122750345127698">Gezinme işlevine ulaşılamıyor: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_uk.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_uk.xtb
index 0f52178eacf..7511e732c18 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_uk.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_uk.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">Сайт <ph name="SITE_NAME" /> додано</translation>
<translation id="1383876407941801731">Пошук</translation>
<translation id="1384959399684842514">Ð—Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¸Ð·ÑƒÐ¿Ð¸Ð½ÐµÐ½Ð¾</translation>
+<translation id="1409426117486808224">Спрощений переглÑд відкритих вкладок</translation>
<translation id="1415402041810619267">URL-адреÑу Ñкорочено</translation>
<translation id="1446450296470737166">Повний контроль приÑтроїв MIDI</translation>
<translation id="1620510694547887537">Камера</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">Дозволити файли cookie</translation>
<translation id="2228071138934252756">Щоб надати додатку <ph name="APP_NAME" /> доÑтуп до камери, також увімкніть Ñ—Ñ— в <ph name="BEGIN_LINK" />налаштуваннÑÑ… Android<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Лише цього разу</translation>
+<translation id="2253414712144136228">Видалити <ph name="NAME_OF_LIST_ITEM" /></translation>
<translation id="2289270750774289114">Запитувати, коли Ñайт хоче шукати приÑтрої Bluetooth поблизу (рекомендовано)</translation>
<translation id="2315043854645842844">Операційна ÑиÑтема не підтримує Ñертифікат, вибраний на Ñтороні клієнта.</translation>
+<translation id="2321958826496381788">ПеретÑгуйте повзунок, доки розмір текÑту не Ñтане зручним Ð´Ð»Ñ Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ. Якщо двічі торкнутиÑÑŒ абзацу, розмір текÑту має Ñтати принаймні таким, Ñк цей.</translation>
<translation id="2359808026110333948">Продовжити</translation>
<translation id="2379925928934107488">Якщо у веб-перекладачі Chrome активовано темну тему, вона викориÑтовуватиметьÑÑ Ð´Ð»Ñ Ñайтів, коли це можливо.</translation>
+<translation id="2387895666653383613">МаÑштаб текÑту</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> МБ</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Дозволено: "<ph name="PERMISSION_1" />", "<ph name="PERMISSION_2" />" і ще <ph name="NUM_MORE" />}one{Дозволено: "<ph name="PERMISSION_1" />", "<ph name="PERMISSION_2" />" і ще <ph name="NUM_MORE" />}few{Дозволено: "<ph name="PERMISSION_1" />", "<ph name="PERMISSION_2" />" і ще <ph name="NUM_MORE" />}many{Дозволено: "<ph name="PERMISSION_1" />", "<ph name="PERMISSION_2" />" і ще <ph name="NUM_MORE" />}other{Дозволено: "<ph name="PERMISSION_1" />", "<ph name="PERMISSION_2" />" і ще <ph name="NUM_MORE" />}}</translation>
<translation id="2434158240863470628">Завантажено <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">Показати інформацію</translation>
<translation id="3123473560110926937">Заблоковано на деÑких Ñайтах</translation>
<translation id="3198916472715691905">У пам'ÑÑ‚Ñ– зайнÑто <ph name="STORAGE_AMOUNT" /></translation>
+<translation id="3203366800380907218">З Інтернету</translation>
<translation id="321187648315454507">Щоб дозволити додатку <ph name="APP_NAME" /> надÑилати вам ÑповіщеннÑ, також увімкніть Ñ—Ñ… у <ph name="BEGIN_LINK" />налаштуваннÑÑ… Android<ph name="END_LINK" />.</translation>
<translation id="3227137524299004712">Мікрофон</translation>
<translation id="3277252321222022663">Ðадати Ñайтам доÑтуп до датчиків (рекомендовано)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">Дані про активний Ñтан приÑтрою</translation>
<translation id="385051799172605136">Ðазад</translation>
<translation id="3859306556332390985">Далі</translation>
+<translation id="3895926599014793903">ПримуÑово ввімкнути маÑштабуваннÑ</translation>
<translation id="3955193568934677022">Дозволити Ñайтам відтворювати захищений вміÑÑ‚ (рекомендуєтьÑÑ)</translation>
<translation id="3967822245660637423">Завантажено</translation>
<translation id="3987993985790029246">Копіювати</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" />/?</translation>
<translation id="4002066346123236978">Ðазва</translation>
<translation id="4008040567710660924">Дозволити файли cookie Ð´Ð»Ñ ÐºÐ¾Ð½ÐºÑ€ÐµÑ‚Ð½Ð¾Ð³Ð¾ Ñайту.</translation>
+<translation id="4040330681741629921">Отримуйте ÑповіщеннÑ, коли Ñайт можна показати в режимі Ñпрощеного переглÑду</translation>
<translation id="4046123991198612571">ÐаÑтупна композиціÑ</translation>
+<translation id="4149994727733219643">Спрощений переглÑд веб-Ñторінок</translation>
<translation id="4165986682804962316">ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ñайту</translation>
+<translation id="4194328954146351878">Запитувати, перш ніж дозволÑти Ñайтам переглÑдати й змінювати інформацію на приÑтроÑÑ… NFC (рекомендовано)</translation>
<translation id="4200726100658658164">Відкрити Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð¾Ñтупу до моїх геоданих</translation>
<translation id="4226663524361240545">Коли надходитимуть ÑповіщеннÑ, приÑтрій може вібрувати</translation>
<translation id="4259722352634471385">Веб-Ñторінку <ph name="URL" /> заблоковано</translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">Розгорнути</translation>
<translation id="4336434711095810371">Видалити вÑÑ– дані</translation>
<translation id="4402755511846832236">Блокувати Ñайтам інформацію про те, чи ви активно викориÑтовуєте цей приÑтрій</translation>
+<translation id="4428065317363009941">ПерÑÐ¾Ð½Ð°Ð»Ñ–Ð·Ð°Ñ†Ñ–Ñ Ñ€ÐµÐºÐ»Ð°Ð¼Ð¸</translation>
<translation id="4434045419905280838">Спливаючі вікна/переÑпрÑмуваннÑ</translation>
<translation id="445467742685312942">Дозволити Ñайтам відтворювати захищений вміÑÑ‚</translation>
<translation id="4468959413250150279">Вимкнути звук Ð´Ð»Ñ Ð¿ÐµÐ²Ð½Ð¾Ð³Ð¾ Ñайту.</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">Ð”Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ натиÑніть відповідну кнопку вгорі екрана</translation>
<translation id="5197729504361054390">Веб-Ñайт <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> отримає доÑтуп до вибраних контактів.</translation>
<translation id="5216942107514965959">ОÑтаннє відвідуваннÑ: Ñьогодні</translation>
+<translation id="5264323282659631142">Видалити запит "<ph name="CHIP_LABEL" />"</translation>
<translation id="528192093759286357">Щоб вийти з повноекранного режиму, проведіть пальцем по екрану згори вниз Ñ– торкнітьÑÑ ÐºÐ½Ð¾Ð¿ÐºÐ¸ "Ðазад".</translation>
<translation id="5300589172476337783">Показати</translation>
<translation id="5301954838959518834">OK</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">Буде видалено <ph name="DATASIZE" /> даних Ñ– файлів cookie Ñайтів.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(+ ще 1)}one{(+ ще #)}few{(+ ще #)}many{(+ ще #)}other{(+ ще #)}}</translation>
<translation id="5403592356182871684">Імена</translation>
+<translation id="5412236728747081950">Цей Ñайт викориÑтовує дані про ваші інтереÑи з Chrome, щоб показувати вам доречнішу рекламу</translation>
<translation id="5438097262470833822">Буде Ñкинуто дозволи Ð´Ð»Ñ Ð²ÐµÐ±-Ñайту <ph name="WEBSITE" /></translation>
<translation id="5489227211564503167">Минуло чаÑу: <ph name="ELAPSED_TIME" /> з <ph name="TOTAL_TIME" /></translation>
<translation id="5494752089476963479">Блокувати рекламу на Ñайтах, Ñкі показують нав’Ñзливі чи оманливі оголошеннÑ</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">Перезавантажити</translation>
<translation id="5596627076506792578">Інші опції</translation>
<translation id="5649053991847567735">Ðвтоматичні завантаженнÑ</translation>
+<translation id="5668404140385795438">ВідхилÑти запит веб-Ñайту, щоб заборонÑти маÑштабуваннÑ</translation>
<translation id="5677928146339483299">Заблоковано</translation>
<translation id="5689516760719285838">МіÑцезнаходженнÑ</translation>
<translation id="5690795753582697420">Камеру вимкнено в налаштуваннÑÑ… Android</translation>
-<translation id="5710871682236653961">Запитувати, перш ніж дозволÑти Ñайтам обмінюватиÑÑ Ð´Ð°Ð½Ð¸Ð¼Ð¸ з іншими приÑтроÑми через NFC (рекомендовано)</translation>
<translation id="5719847187258001597">Буде видалено вÑÑ– дані й файли cookie Ñайту <ph name="ORIGIN" /> або його додатка на головному екрані.</translation>
<translation id="5771720122942595109">Заблоковано: "<ph name="PERMISSION_1" />"</translation>
<translation id="5804241973901381774">Дозволи</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">Відтворити</translation>
<translation id="6818926723028410516">Виберіть елементи</translation>
<translation id="6864395892908308021">Цей приÑтрій не підтримує NFC</translation>
-<translation id="6910211073230771657">Видалено</translation>
<translation id="6912998170423641340">Ðе дозволÑти Ñайтам переглÑдати текÑти й Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ Ð² буфері обміну</translation>
<translation id="6945221475159498467">Вибрати</translation>
<translation id="6965382102122355670">OK</translation>
+<translation id="6981982820502123353">Спеціальні можливоÑÑ‚Ñ–</translation>
<translation id="6992289844737586249">Запитувати, перш ніж дозволити Ñайтам викориÑтовувати мікрофон (рекомендуєтьÑÑ)</translation>
<translation id="7000754031042624318">Вимкнено в налаштуваннÑÑ… Android</translation>
<translation id="7016516562562142042">Дозволено Ð´Ð»Ñ Ð¿Ð¾Ñ‚Ð¾Ñ‡Ð½Ð¾Ñ— пошукової ÑиÑтеми</translation>
+<translation id="702463548815491781">РекомендуєтьÑÑ, коли ввімкнено TalkBack або кнопковий доÑтуп</translation>
<translation id="7053983685419859001">Блокувати</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{Вибрано 1}one{Вибрано #}few{Вибрано #}many{Вибрано #}other{Вибрано #}}</translation>
-<translation id="7070090581017165256">Про цей Ñайт</translation>
<translation id="7087918508125750058">Вибрано <ph name="ITEM_COUNT" />. Панель інÑтрументів розташовано вгорі екрана</translation>
<translation id="7141896414559753902">Блокувати Ñпливаючі вікна та переадреÑацію на Ñайтах (рекомендовано)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> КБ</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">Сайт викориÑтовує мікрофон</translation>
<translation id="7561196759112975576">Завжди</translation>
-<translation id="7572498721684305250">Заборонити Ñайтам обмінюватиÑÑ Ð´Ð°Ð½Ð¸Ð¼Ð¸ з іншими приÑтроÑми через NFC</translation>
<translation id="757524316907819857">Заборонити Ñайтам відтворювати захищений вміÑÑ‚</translation>
+<translation id="7577900504646297215">Керувати інтереÑами</translation>
<translation id="7649070708921625228">Довідка</translation>
<translation id="7658239707568436148">СкаÑувати</translation>
<translation id="7781829728241885113">Учора</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">Ð—â€™Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð±ÐµÐ·Ð¿ÐµÑ‡Ð½Ðµ</translation>
<translation id="8249310407154411074">Ðа початок</translation>
<translation id="8261506727792406068">Видалити</translation>
+<translation id="8284326494547611709">Субтитри</translation>
<translation id="8300705686683892304">КеруютьÑÑ Ð´Ð¾Ð´Ð°Ñ‚ÐºÐ¾Ð¼</translation>
<translation id="8324158725704657629">Ðе запитувати знову</translation>
<translation id="8372893542064058268">Ñайті.</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">Збільшити маÑштаб</translation>
<translation id="8921772741368021346"><ph name="POSITION" />/<ph name="DURATION" /></translation>
<translation id="8926666909099850184">NFC вимкнено на цьому приÑтрої. Увімкніть цю функцію в <ph name="BEGIN_LINK" />налаштуваннÑÑ… Android<ph name="END_LINK" />.</translation>
+<translation id="8928445016601307354">Заборонити Ñайтам переглÑдати й змінювати інформацію на приÑтроÑÑ… NFC</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">Блокувати файли cookie з конкретного Ñайту.</translation>
<translation id="8959122750345127698">Веб-Ñторінка <ph name="URL" /> недоÑтупна</translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ur.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ur.xtb
index e9113dbe9cf..acdc30c0c9b 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ur.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_ur.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">سائٹ <ph name="SITE_NAME" /> شامل کی گئی</translation>
<translation id="1383876407941801731">تلاش کریں</translation>
<translation id="1384959399684842514">ڈاؤن لوڈ موقو٠Ûوگیا</translation>
+<translation id="1409426117486808224">Ú©Ú¾Ù„Û’ ٹیبز کیلئے Ø³Ø§Ø¯Û Ù…Ù†Ø¸Ø±</translation>
<translation id="1415402041810619267">â€URL Ú©Ùˆ چھوٹا کیا گیا</translation>
<translation id="1446450296470737166">â€MIDI آلات Ú©Û’ مکمل کنٹرول Ú©ÛŒ اجازت دیں</translation>
<translation id="1620510694547887537">کیمرا</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">کوکیز کی اجازت دیں</translation>
<translation id="2228071138934252756">â€<ph name="APP_NAME" /> Ú©Ùˆ اپنے کیمرے تک رسائی دینے Ú©Û’ لیے، <ph name="BEGIN_LINK" />Android Ú©ÛŒ ترتیبات<ph name="END_LINK" /> میں بھی کیمرا آن کریں۔</translation>
<translation id="2241634353105152135">بس ایک بار</translation>
+<translation id="2253414712144136228"><ph name="NAME_OF_LIST_ITEM" /> Ûٹائیں</translation>
<translation id="2289270750774289114">اس وقت پوچھیں جب کسی سائٹ میں قریبی بلوٹوتھ آلات Ú©Ùˆ دریاÙت کرنا مقصود ÛÙˆ (تجویز کردÛ)</translation>
<translation id="2315043854645842844">کلائنٹ سائڈ سرٹیÙکیٹ کا انتخاب آپریٹنگ سسٹم Ú©Û’ Ø°Ø±ÛŒØ¹Û ØªØ¹Ø§ÙˆÙ† یاÙØªÛ Ù†Ûیں ÛÛ’Û”</translation>
+<translation id="2321958826496381788">سلائیڈر Ú©Ùˆ اس وقت تک گھسیٹیں جب اسے آرام سے Ù¾Ú‘Ú¾ سکتے ÛÙˆÚºÛ” کسی پیراگرا٠پر دوبار تھپتھپانے Ú©Û’ بعد متن Ú©Ù… از Ú©Ù… اتنا بڑا دکھائی دینا چاÛیے۔</translation>
<translation id="2359808026110333948">جاری رکھیں</translation>
<translation id="2379925928934107488">â€Ù…Ù…Ú©Ù† ÛÙˆ تو سائٹس پر Ú¯Ûری تھیم لاگو Ûوتی ÛÛ’ جب Chrome Ú©Ùˆ Ú¯Ûری تھیم استعمال کرنے کیلئے سیٹ کیا جاتا ÛÛ’</translation>
+<translation id="2387895666653383613">متن کی پیمائش کرنا</translation>
<translation id="2402980924095424747">‎<ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{<ph name="PERMISSION_1" />، <ph name="PERMISSION_2" /> اور <ph name="NUM_MORE" /> مزید کی اجازت دی گئی}other{<ph name="PERMISSION_1" />، <ph name="PERMISSION_2" /> اور <ph name="NUM_MORE" /> مزید کی اجازت دی گئی}}</translation>
<translation id="2434158240863470628">ڈاؤن لوڈ مکمل ÛÙˆ گیا <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">معلومات دکھائیں</translation>
<translation id="3123473560110926937">بعض سائٹس پر مسدود ÛÛ’</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> اسٹور Ú©Ø±Ø¯Û ÚˆÛŒÙ¹Ø§</translation>
+<translation id="3203366800380907218">ویب سے</translation>
<translation id="321187648315454507">â€<ph name="APP_NAME" /> Ú©Ùˆ آپ Ú©Ùˆ اطلاعات بھیجنے Ú©ÛŒ سÛولت دینے Ú©Û’ لیے، <ph name="BEGIN_LINK" />Android Ú©ÛŒ ترتیبات<ph name="END_LINK" /> میں بھی اطلاعات آن کریں۔</translation>
<translation id="3227137524299004712">مائیکروÙون</translation>
<translation id="3277252321222022663">سائٹس Ú©Ùˆ سینسرز تک رسائی حاصل کرنے Ú©ÛŒ اجازت دیں (تجویز کردÛ)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">آپ کے آلے کا استعمال</translation>
<translation id="385051799172605136">پیچھے</translation>
<translation id="3859306556332390985">آگے لے جائیں</translation>
+<translation id="3895926599014793903">زوم Ú©Ùˆ زبردستی Ùعال کریں</translation>
<translation id="3955193568934677022">سائٹس Ú©Ùˆ محÙوظ Ú©Ø±Ø¯Û Ù…ÙˆØ§Ø¯ چلانے Ú©ÛŒ اجازت دیں (تجویز کردÛ)</translation>
<translation id="3967822245660637423">ڈاؤن لوڈ مکمل Ûوگیا ÛÛ’</translation>
<translation id="3987993985790029246">لنک کاپی کریں</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> / ?</translation>
<translation id="4002066346123236978">عنوان</translation>
<translation id="4008040567710660924">مخصوص سائٹ کے لیے کوکیز کی اجازت دیں۔</translation>
+<translation id="4040330681741629921">کسی سائٹ Ú©Ùˆ Ø³Ø§Ø¯Û Ù…Ù†Ø¸Ø± میں دکھائے جانے پر اطلاع حاصل کریں</translation>
<translation id="4046123991198612571">اگلا ٹریک</translation>
+<translation id="4149994727733219643">ویب صÙحات کیلئے Ø³Ø§Ø¯Û Ù…Ù†Ø¸Ø±</translation>
<translation id="4165986682804962316">سائٹ کی ترتیبات</translation>
+<translation id="4194328954146351878">â€Ø³Ø§Ø¦Ù¹Ø³ Ú©Ùˆ NFC آلات پر معلومات دیکھنے اور تبدیل کرنے Ú©ÛŒ اجازت دینے سے Ù¾ÛÙ„Û’ پوچھیں (تجویز کردÛ)</translation>
<translation id="4200726100658658164">مقام کی ترتیبات کھولیں</translation>
<translation id="4226663524361240545">اطلاعات Ø¢Ù„Û Ú©Ùˆ وائبریٹ کر سکتی Ûیں</translation>
<translation id="4259722352634471385">نیویگیشن مسدود ÛÛ’: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">پھیلائیں</translation>
<translation id="4336434711095810371">سبھی ڈیٹا صا٠کریں</translation>
<translation id="4402755511846832236">کب آپ Ùعال طور پر اس Ø¢Ù„Û Ú©Ø§ استعمال کر رÛÛ’ Ûیں اس کا Ù¾ØªÛ Ù„Ú¯Ø§Ù†Û’ سے سائٹس Ú©Ùˆ مسدود کریں</translation>
+<translation id="4428065317363009941">اشتÛارات Ú©Ùˆ ذاتی نوعیت کا بنانا</translation>
<translation id="4434045419905280838">پوپ اپس اور ری ڈائریکٹس</translation>
<translation id="445467742685312942">سائٹس Ú©Ùˆ محÙوظ مواد چلانے Ú©ÛŒ اجازت دیں</translation>
<translation id="4468959413250150279">کسی مخصوص سائٹ کیلئے آواز بند کریں۔</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">اسکرین Ú©Û’ اوپری Ø­ØµÛ Ú©Û’ قریب اختیار دستیاب ÛÛ’</translation>
<translation id="5197729504361054390">آپ Ú©Û’ منتخب Ú©Ø±Ø¯Û Ø±Ø§Ø¨Ø·ÙˆÚº کا <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> Ú©Û’ ساتھ اشتراک کیا جائے گا۔</translation>
<translation id="5216942107514965959">آخری بار آج Ù…Ù„Ø§Ø­Ø¸Û Ú©ÛŒØ§ گیا</translation>
+<translation id="5264323282659631142">’<ph name="CHIP_LABEL" />‘ Ûٹائیں</translation>
<translation id="528192093759286357">پوری اسکرین سے باÛر نکلنے کیلئے اوپر سے گھسیٹیں اور پیچھے جائیں بٹن Ú©Ùˆ Ù¹Ú† کریں۔</translation>
<translation id="5300589172476337783">دکھائیں</translation>
<translation id="5301954838959518834">ٹھیک ÛÛ’ØŒ سمجھ Ø¢ گئی</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">اس سے سائٹس Ú©Û’ ذریعے اسٹور Ú©Ø±Ø¯Û <ph name="DATASIZE" /> ڈیٹا اور کوکیز صا٠ÛÙˆ جائیں گی۔</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{â€(‎+1 مزید)}other{(# + مزید)}}</translation>
<translation id="5403592356182871684">نام</translation>
+<translation id="5412236728747081950">â€ÛŒÛ سائٹ آپ Ú©Ùˆ مزید Ù…ØªØ¹Ù„Ù‚Û Ø§Ø´ØªÛارات دکھانے Ú©Û’ لیے Chrome سے آپ Ú©ÛŒ دلچسپیاں موصول کرتی ÛÛ’</translation>
<translation id="5438097262470833822">ÛŒÛ Ø§Ù†ØªØ®Ø§Ø¨ <ph name="WEBSITE" /> Ú©Û’ لیے اجازتوں Ú©Ùˆ ری سیٹ کرے گا</translation>
<translation id="5489227211564503167"><ph name="TOTAL_TIME" /> میں سے <ph name="ELAPSED_TIME" /> وقت گزر گیا۔</translation>
<translation id="5494752089476963479">دخل انداز یا Ú¯Ù…Ø±Ø§Û Ú©Ù† اشتÛارات دکھانے والی سائٹس پر اشتÛارات Ú©Ùˆ مسدود کریں</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">Ø¯ÙˆØ¨Ø§Ø±Û Ù„ÙˆÚˆ کریں</translation>
<translation id="5596627076506792578">مزید اختیارات</translation>
<translation id="5649053991847567735">خود کار ڈاؤن لوڈز</translation>
+<translation id="5668404140385795438">زوم ان کرنے سے بچنے کیلئے کسی ویب سائٹ کی درخواست کو اوور رائیڈ کریں</translation>
<translation id="5677928146339483299">مسدود کردÛ</translation>
<translation id="5689516760719285838">مقام</translation>
<translation id="5690795753582697420">â€Android Ú©ÛŒ ترتیبات میں کیمرا آ٠ÛÛ’</translation>
-<translation id="5710871682236653961">â€NFC آلات پر تھپتھپاتے وقت سائٹس Ú©Ùˆ معلومات بھیجنے اور وصول کرنے Ú©ÛŒ اجازت دینے سے Ù¾ÛÙ„Û’ پوچھیں (تجویز کردÛ)</translation>
<translation id="5719847187258001597">اس سے <ph name="ORIGIN" /> یا اس ایپ Ú©Û’ ذریعے آپ Ú©ÛŒ Ûوم اسکرین پر اسٹور Ú©Ø±Ø¯Û Ø³Ø¨Ú¾ÛŒ ڈیٹا اور کوکیز صا٠ÛÙˆ جائیں گی۔</translation>
<translation id="5771720122942595109"><ph name="PERMISSION_1" /> مسدود ÛÙˆ گیا</translation>
<translation id="5804241973901381774">اجازتیں</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">چلائیں</translation>
<translation id="6818926723028410516">آئٹمز منتخب کریں</translation>
<translation id="6864395892908308021">â€ÛŒÛ Ø¢Ù„Û NFC Ú©Ùˆ Ù†Ûیں Ù¾Ú‘Ú¾ سکتا</translation>
-<translation id="6910211073230771657">حذ٠کردÛ</translation>
<translation id="6912998170423641340">سائٹس کو کلپ بورڈ سے ٹیکسٹ اور تصاویر پڑھنے سے مسدود کریں</translation>
<translation id="6945221475159498467">منتخب کریں</translation>
<translation id="6965382102122355670">ٹھیک ÛÛ’</translation>
+<translation id="6981982820502123353">ایکسیسبیلٹی</translation>
<translation id="6992289844737586249">سائٹس Ú©Ùˆ آپ کا مائیکروÙون استعمال کرنے Ú©ÛŒ اجازت دینے سے Ù¾ÛÙ„Û’ پوچھیں (تجویز کردÛ)</translation>
<translation id="7000754031042624318">â€Android ترتیبات میں آ٠کر دیا گیا</translation>
<translation id="7016516562562142042">Ù…ÙˆØ¬ÙˆØ¯Û Ø³Ø±Ú† انجن کیلئے اجازت یاÙتÛ</translation>
+<translation id="702463548815491781">â€TalkBack یا سوئچ رسائی آن Ûونے پر تجویز کردÛ</translation>
<translation id="7053983685419859001">مسدود کریں</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1 منتخب ÛÛ’}other{# منتخب کردÛ}}</translation>
-<translation id="7070090581017165256">اس سائٹ کے بارے میں</translation>
<translation id="7087918508125750058"><ph name="ITEM_COUNT" /> منتخب ÛÙˆ گئے۔ اختیارات اسکرین Ú©Û’ اوپری Ø­ØµÛ Ú©Û’ قریب دستیاب Ûیں</translation>
<translation id="7141896414559753902">سائٹس Ú©Ùˆ پاپ اپس اور ری ڈائریکٹس دکھانے سے مسدود کریں (تجویز کردÛ)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> KB</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">سائٹ آپ کا مائیکروÙون استعمال کر رÛÛŒ ÛÛ’</translation>
<translation id="7561196759112975576">ÛمیشÛ</translation>
-<translation id="7572498721684305250">â€NFC آلات پر تھپتھپاتے وقت سائٹس Ú©Ùˆ معلومات بھیجنے اور وصول کرنے سے مسدود کریں</translation>
<translation id="757524316907819857">محÙوظ مواد چلانے سے سائٹس Ú©Ùˆ مسدود کریں</translation>
+<translation id="7577900504646297215">دلچسپیوں کا نظم کریں</translation>
<translation id="7649070708921625228">مدد</translation>
<translation id="7658239707568436148">منسوخ کریں</translation>
<translation id="7781829728241885113">Ú¯Ø²Ø´ØªÛ Ú©Ù„</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">کنکشن محÙوظ ÛÛ’</translation>
<translation id="8249310407154411074">اوپر منتقل کریں</translation>
<translation id="8261506727792406068">حذ٠کریں</translation>
+<translation id="8284326494547611709">کیپشنز</translation>
<translation id="8300705686683892304">ایپ Ú©Û’ زیر انتظام Ûیں</translation>
<translation id="8324158725704657629">Ø¯ÙˆØ¨Ø§Ø±Û Ù…Øª پوچھیں</translation>
<translation id="8372893542064058268">کسی مخصوص سائٹ کیلئے پس منظر کی مطابقت پذیری کی اجازت دیں۔</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">زوم ان کریں</translation>
<translation id="8921772741368021346"><ph name="POSITION" /> / <ph name="DURATION" /></translation>
<translation id="8926666909099850184">â€Ø§Ø³ Ø§Ù“Ù„Û Ú©Û’ لیے NFC آ٠ÛÛ’Û” اسے <ph name="BEGIN_LINK" />Android ترتیبات<ph name="END_LINK" /> میں آن کریں۔</translation>
+<translation id="8928445016601307354">â€Ø³Ø§Ø¦Ù¹Ø³ Ú©Ùˆ NFC آلات پر معلومات دیکھنے اور تبدیل کرنے سے مسدود کریں</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">کسی مخصوص سائٹ کے لیے کوکیز مسدود کریں۔</translation>
<translation id="8959122750345127698">نیویگیشن ناقابل رسائی ÛÛ’: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_uz.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_uz.xtb
index a288c43bb6d..1b4db5619ee 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_uz.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_uz.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676"><ph name="SITE_NAME" /> sayti qo‘shildi</translation>
<translation id="1383876407941801731">Qidiruv</translation>
<translation id="1384959399684842514">Yuklab olish pauza qilindi.</translation>
+<translation id="1409426117486808224">Ochiq varaqlarni ko‘rish uchun oddiy rejim</translation>
<translation id="1415402041810619267">URL manzil qisqartirildi</translation>
<translation id="1446450296470737166">MIDI qurilmalarini boshqarishga to‘liq ruxsat berish</translation>
<translation id="1620510694547887537">Kamera</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">Cookie fayllariga ruxsat berish</translation>
<translation id="2228071138934252756"><ph name="APP_NAME" /> kameradan foydalanishiga ruxsat berish uchun <ph name="BEGIN_LINK" />Android sozlamalari<ph name="END_LINK" /> orqali kamerani yoqing.</translation>
<translation id="2241634353105152135">Bir marta</translation>
+<translation id="2253414712144136228">Olib tashlash: <ph name="NAME_OF_LIST_ITEM" /></translation>
<translation id="2289270750774289114">Sayt atrofdagi Bluetooth qurilmalarni tekshirmoqchi boʻlsa, xabar berilsin (tavsiya etiladi)</translation>
<translation id="2315043854645842844">Tanlangan mijoz sertifikati eskirgan va operatsion tizim tomonidan qo‘llab-quvvatlanmaydi.</translation>
+<translation id="2321958826496381788">Sudragichni matn o‘qish uchun qulay bo‘lguncha suring. Satr boshiga ikki marta bosilganda matn hajmi shunday bo‘lishi kerak.</translation>
<translation id="2359808026110333948">Davom etish</translation>
<translation id="2379925928934107488">Chrome tungi mavzudan foydalansa, saytlarga ham u tatbiq etiladi</translation>
+<translation id="2387895666653383613">Matn hajmi</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Ruxsat berildi: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> va yana <ph name="NUM_MORE" /> ta}other{Ruxsat berildi: <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> va yana <ph name="NUM_MORE" /> ta}}</translation>
<translation id="2434158240863470628">Yuklab olindi: <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">Ma’lumotlarni ko‘rsatish</translation>
<translation id="3123473560110926937">Ayrim saytlarda bloklangan</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> xotira band</translation>
+<translation id="3203366800380907218">Internetdan</translation>
<translation id="321187648315454507"><ph name="APP_NAME" /> sizga bildirishnomalar yuborishi uchun <ph name="BEGIN_LINK" />Android sozlamalari<ph name="END_LINK" /> orqali bildirishnomalarni yoqing.</translation>
<translation id="3227137524299004712">Mikrofon</translation>
<translation id="3277252321222022663">Saytlarga sensorlardan foydalanish uchun ruxsat berish (tavsiya etiladi)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">Qurilmadan foydalanish</translation>
<translation id="385051799172605136">Orqaga</translation>
<translation id="3859306556332390985">Oldinga surish</translation>
+<translation id="3895926599014793903">Hajmni majburiy o‘zgartirish funksiyasini yoqish</translation>
<translation id="3955193568934677022">Saytlarga himoyalangan kontentni ijro qilish uchun ruxsat berish (tavsiya etiladi)</translation>
<translation id="3967822245660637423">Yuklab olindi</translation>
<translation id="3987993985790029246">Nusxalash</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> / ?</translation>
<translation id="4002066346123236978">Nomi</translation>
<translation id="4008040567710660924">Muayyan saytlar uchun cookie-fayllarga ruxsat berish</translation>
+<translation id="4040330681741629921">Saytni soddalashgan shaklda koʻrish mumkin boʻlganda xabar berilsin</translation>
<translation id="4046123991198612571">Keyingi musiqa</translation>
+<translation id="4149994727733219643">Veb sahifalarni ko‘rish uchun oddiy rejim</translation>
<translation id="4165986682804962316">Sayt sozlamalari</translation>
+<translation id="4194328954146351878">Saytlar NFC qurilmalarni koʻrishi va ulardagi axborotni oʻzgartirishidan oldin ruxsat olsin (tavsiya etiladi)</translation>
<translation id="4200726100658658164">Joylashuv sozlamalarini ochish</translation>
<translation id="4226663524361240545">Bildirishnoma kelganida qurilma tebranishi mumkin</translation>
<translation id="4259722352634471385">Sahifa bloklandi: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">Kengaytirish</translation>
<translation id="4336434711095810371">Barcha maʼlumotlarni tozalash</translation>
<translation id="4402755511846832236">Bu qurilmadan foydalanish axborotlarini saytlar bilishini taqiqlash</translation>
+<translation id="4428065317363009941">Reklamalarni moslashtirish</translation>
<translation id="4434045419905280838">Qalquvchi oyna va yo‘naltirishlar</translation>
<translation id="445467742685312942">Saytlarga himoyalangan kontentni ijro qilish uchun ruxsat berish</translation>
<translation id="4468959413250150279">Muayyan saytdagi ovozni o‘chirish.</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">Parametr ekranning yuqoriroq qismida joylashgan</translation>
<translation id="5197729504361054390">Tanlangan kontaktlar <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> saytiga ulashiladi.</translation>
<translation id="5216942107514965959">Oxirgi tashrif: bugun</translation>
+<translation id="5264323282659631142">Olib tashlash: <ph name="CHIP_LABEL" /></translation>
<translation id="528192093759286357">To‘liq ekran rejimidan chiqish uchun ekranni tepadan pastga torting va “Orqaga†tugmasini bosing.</translation>
<translation id="5300589172476337783">Ko‘rsatish</translation>
<translation id="5301954838959518834">OK</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">Saytlar joylagan <ph name="DATASIZE" /> maʼlumot va cookie fayllar tozalab tashlanadi.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(yana 1 ta)}other{(yana # ta)}}</translation>
<translation id="5403592356182871684">Ismlar</translation>
+<translation id="5412236728747081950">Bu sayt mos reklamalarni chiqarish uchun qiziqishlaringiz haqidagi Chrome maʼlumotlaridan foydalanadi.</translation>
<translation id="5438097262470833822">Bunda <ph name="WEBSITE" /> ruxsatlari tiklanadi</translation>
<translation id="5489227211564503167">Ijro etilgan vaqt: <ph name="ELAPSED_TIME" />/<ph name="TOTAL_TIME" />.</translation>
<translation id="5494752089476963479">Saytlarda chiquvchi yoqimsiz yoki befoyda reklamalar bloklansin</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">Qayta yuklash</translation>
<translation id="5596627076506792578">Boshqa sozlamalar</translation>
<translation id="5649053991847567735">Avtomatik yuklamalar</translation>
+<translation id="5668404140385795438">Saytlarda masshtab taqiqlarini chetlab matn hajmini o‘zgartirish</translation>
<translation id="5677928146339483299">Bloklangan</translation>
<translation id="5689516760719285838">Joylashuv</translation>
<translation id="5690795753582697420">Kamera Android sozlamalarida yoqilmagan</translation>
-<translation id="5710871682236653961">NFC qurilmalar ustiga bosilganda saytlarda axborot almashinuviga ruxsat soʻralsin (tavsiya etiladi)</translation>
<translation id="5719847187258001597">Bunda <ph name="ORIGIN" /> saytidan saqlangan barcha maʼlumotlar va cookie fayllar yoki Bosh ekrandagi ilovalar tozalab tashlanadi.</translation>
<translation id="5771720122942595109">Bloklandi: <ph name="PERMISSION_1" /></translation>
<translation id="5804241973901381774">Ruxsatlar</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">Ijro etish</translation>
<translation id="6818926723028410516">Fayllarni tanlang</translation>
<translation id="6864395892908308021">Bu qurilma NFC teglarni oʻqiy olmaydi</translation>
-<translation id="6910211073230771657">O‘chirib tashlandi</translation>
<translation id="6912998170423641340">Saytlarga klipboarddagi matn va rasmlarni ko‘rishni taqiqlash</translation>
<translation id="6945221475159498467">Tanlash</translation>
<translation id="6965382102122355670">OK</translation>
+<translation id="6981982820502123353">Qulayliklar</translation>
<translation id="6992289844737586249">Mikrofondan foydalanishga ruxsat so‘ralsin (tavsiya etiladi)</translation>
<translation id="7000754031042624318">Android sozlamalari orqali faolsizlantirilgan</translation>
<translation id="7016516562562142042">Joriy qidiruv tizimiga ruxsat berilgan</translation>
+<translation id="702463548815491781">TalkBack yoki Switch Access yoniq holatda tavsiya etiladi</translation>
<translation id="7053983685419859001">Taqiqlash</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{ 1 ta belgilandi}other{# ta belgilandi}}</translation>
-<translation id="7070090581017165256">Bu sayt haqida</translation>
<translation id="7087918508125750058"><ph name="ITEM_COUNT" /> ta element tanlandi. Parametrlar ekranning yuqoriroq qismida joylashgan</translation>
<translation id="7141896414559753902">Saytlarga qalqib chiquvchi oynalarni ochishni taqiqlash (tavsiya etiladi)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> KB</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">Sayt mikrofondan foydalanmoqda</translation>
<translation id="7561196759112975576">Har doim</translation>
-<translation id="7572498721684305250">NFC qurilmalar ustiga bosilganda saytlarda axborot almashinuvi taqiqlansin</translation>
<translation id="757524316907819857">Saytlarga himoyalangan kontent ijrosini taqiqlash</translation>
+<translation id="7577900504646297215">Qiziqishlarni sozlash</translation>
<translation id="7649070708921625228">Yordam</translation>
<translation id="7658239707568436148">Bekor qilish</translation>
<translation id="7781829728241885113">Kecha</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">Bu ulanish xavfsiz</translation>
<translation id="8249310407154411074">Tepaga siljitish</translation>
<translation id="8261506727792406068">O‘chirish</translation>
+<translation id="8284326494547611709">Taglavhalar</translation>
<translation id="8300705686683892304">Ilova boshqaruvida</translation>
<translation id="8324158725704657629">Boshqa soʻralmasin</translation>
<translation id="8372893542064058268">Ko‘rsatilgan sayt uchun fonda sinxronlashga ruxsat berish.</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">Kattalashtirish</translation>
<translation id="8921772741368021346"><ph name="POSITION" /> / <ph name="DURATION" /></translation>
<translation id="8926666909099850184">Telefonda NFC yoqilmagan. Uni <ph name="BEGIN_LINK" />Android sozlamalari<ph name="END_LINK" /> orqali yoqing.</translation>
+<translation id="8928445016601307354">Saytlarga NFC qurilmalarni koʻrish va ulardagi axborotni oʻzgartirishni taqiqlash</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">Muayyan saytlar uchun cookie-fayllarni bloklang.</translation>
<translation id="8959122750345127698">Sahifa topilmadi: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_vi.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_vi.xtb
index 15503a1df31..59eb30d79f3 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_vi.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_vi.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">Äã thêm trang web <ph name="SITE_NAME" /></translation>
<translation id="1383876407941801731">Tìm kiếm</translation>
<translation id="1384959399684842514">Äã tạm dừng quá trình tải xuống</translation>
+<translation id="1409426117486808224">Chế độ xem đơn giản cho thẻ đang mở</translation>
<translation id="1415402041810619267">URL đã được cắt bớt</translation>
<translation id="1446450296470737166">Cho pheÌp kiểm soaÌt hoaÌ€n toaÌ€n thiêÌt biÌ£ MIDI</translation>
<translation id="1620510694547887537">Máy ảnh</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">Cho phép cookie</translation>
<translation id="2228071138934252756">Äể cho phép <ph name="APP_NAME" /> truy cập vào máy ảnh của bạn, hãy bật cả máy ảnh trong phần <ph name="BEGIN_LINK" />Cài đặt Android<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Chỉ một lần</translation>
+<translation id="2253414712144136228"><ph name="NAME_OF_LIST_ITEM" /> Xoá</translation>
<translation id="2289270750774289114">Há»i khi má»™t trang web muốn tìm các thiết bị Bluetooth ở gần (khuyên dùng)</translation>
<translation id="2315043854645842844">Lá»±a chá»n chứng chỉ phía ứng dụng khách không được hệ Ä‘iá»u hành há»— trợ.</translation>
+<translation id="2321958826496381788">Kéo thanh trượt cho đến khi bạn có thể Ä‘á»c ná»™i dung này thoải mái. Chữ tối thiểu phải to nhÆ° này sau khi bấm đúp vào má»™t Ä‘oạn.</translation>
<translation id="2359808026110333948">Tiếp tục</translation>
<translation id="2379925928934107488">Ãp dụng giao diện tối cho các trang web khi Chrome sá»­ dụng giao diện tối, nếu có thể</translation>
+<translation id="2387895666653383613">Chia tỷ lệ văn bản</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{Äã cho phép <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> và <ph name="NUM_MORE" /> quyá»n khác}other{Äã cho phép <ph name="PERMISSION_1" />, <ph name="PERMISSION_2" /> và <ph name="NUM_MORE" /> quyá»n khác}}</translation>
<translation id="2434158240863470628">Quá trình tải xuống hoàn tất <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">Hiển thị thông tin</translation>
<translation id="3123473560110926937">Äã chặn trên má»™t số trang web</translation>
<translation id="3198916472715691905">Dữ liệu đã lưu trữ: <ph name="STORAGE_AMOUNT" /></translation>
+<translation id="3203366800380907218">Trên web</translation>
<translation id="321187648315454507">Äể cho phép <ph name="APP_NAME" /> gá»­i thông báo cho bạn, hãy bật cả thông báo trong phần <ph name="BEGIN_LINK" />Cài đặt Android<ph name="END_LINK" />.</translation>
<translation id="3227137524299004712">Micrô</translation>
<translation id="3277252321222022663">Cho phép các trang web sử dụng cảm biến của thiết bị (nên dùng)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">Hoạt động dùng thiết bị của bạn</translation>
<translation id="385051799172605136">Quay lại</translation>
<translation id="3859306556332390985">Tìm kiếm tiến</translation>
+<translation id="3895926599014793903">Buộc bật thu phóng</translation>
<translation id="3955193568934677022">Cho phép trang web phát nội dung được bảo vệ (được đỠxuất)</translation>
<translation id="3967822245660637423">Äã tải xuống xong</translation>
<translation id="3987993985790029246">Sao chép Ä‘Æ°á»ng liên kết</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" />/?</translation>
<translation id="4002066346123236978">Tiêu Ä‘á»</translation>
<translation id="4008040567710660924">Cho phép cookie của một trang web cụ thể.</translation>
+<translation id="4040330681741629921">Nhận thông báo khi má»™t trang web có thể xuâÌt hiện trong chế Ä‘á»™ xem Ä‘Æ¡n giản</translation>
<translation id="4046123991198612571">Bản nhạc tiếp theo</translation>
+<translation id="4149994727733219643">Chế độ xem đơn giản cho trang web</translation>
<translation id="4165986682804962316">Cài đặt trang web</translation>
+<translation id="4194328954146351878">Há»i trÆ°á»›c khi cho phép các trang web xem và thay đổi thông tin trên thiết bị NFC (nên chá»n)</translation>
<translation id="4200726100658658164">Mở phần Cài đặt vị trí</translation>
<translation id="4226663524361240545">Thông báo có thể làm rung thiết bị</translation>
<translation id="4259722352634471385">Äiá»u hÆ°á»›ng bị chặn: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">Mở rộng</translation>
<translation id="4336434711095810371">Xóa tất cả dữ liệu</translation>
<translation id="4402755511846832236">Không cho các trang web biết khi bạn đang dùng thiết bị này</translation>
+<translation id="4428065317363009941">Cá nhân hoá quảng cáo</translation>
<translation id="4434045419905280838">Cửa sổ bật lên và liên kết chuyển hướng</translation>
<translation id="445467742685312942">Cho phép trang web phát nội dung được bảo vệ</translation>
<translation id="4468959413250150279">Tắt âm thanh trên một trang web cụ thể.</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">Tùy chá»n này ở gần đầu màn hình</translation>
<translation id="5197729504361054390">Những ngÆ°á»i liên hệ bạn chá»n sẽ được chia sẻ vá»›i <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />.</translation>
<translation id="5216942107514965959">Lần truy cập gần đây nhất: hôm nay</translation>
+<translation id="5264323282659631142">Xóa "<ph name="CHIP_LABEL" />"</translation>
<translation id="528192093759286357">Kéo từ trên xuống và chạm vào nút quay lại để thoát khá»i chế Ä‘á»™ toàn màn hình.</translation>
<translation id="5300589172476337783">Hiển thị</translation>
<translation id="5301954838959518834">Ok</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">Thao tác này sẽ xóa <ph name="DATASIZE" /> dữ liệu và cookie do các trang web lưu trữ.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(+ 1 lá»±a chá»n khác)}other{(+ # lá»±a chá»n khác)}}</translation>
<translation id="5403592356182871684">Tên</translation>
+<translation id="5412236728747081950">Trang web này lấy thông tin vỠmối quan tâm của bạn trên Chrome để cho bạn thấy những quảng cáo phù hợp hơn</translation>
<translation id="5438097262470833822">Lá»±a chá»n này sẽ đặt lại các quyá»n của <ph name="WEBSITE" /></translation>
<translation id="5489227211564503167">Thá»i gian đã trôi qua: <ph name="ELAPSED_TIME" />/<ph name="TOTAL_TIME" />.</translation>
<translation id="5494752089476963479">Chặn quảng cáo trên các trang web hiển thị quảng cáo xâm nhập hoặc quảng cáo gây hiểu nhầm</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">Tải lại</translation>
<translation id="5596627076506792578">Tùy chá»n khác</translation>
<translation id="5649053991847567735">Tự động tải xuống</translation>
+<translation id="5668404140385795438">Ghi đè yêu cầu của trang web để chặn phoÌng to</translation>
<translation id="5677928146339483299">Bị chặn</translation>
<translation id="5689516760719285838">Vị trí</translation>
<translation id="5690795753582697420">Bạn đã tắt máy ảnh trong phần cài đặt của Android</translation>
-<translation id="5710871682236653961">Há»i ý bạn trÆ°á»›c khi cho phép các trang web gá»­i và nhận thông tin khi bạn nhấn vào tùy chá»n thiết bị dùng công nghệ giao tiếp tầm gần (NFC) (khuyên dùng)</translation>
<translation id="5719847187258001597">Thao tác này sẽ xóa toàn bộ dữ liệu và cookie lưu trữ trong <ph name="ORIGIN" /> hoặc ứng dụng liên quan trên Màn hình chính.</translation>
<translation id="5771720122942595109">Äã chặn <ph name="PERMISSION_1" /></translation>
<translation id="5804241973901381774">Quyá»n</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">Phát</translation>
<translation id="6818926723028410516">Chá»n mục</translation>
<translation id="6864395892908308021">Thiết bị này không hỗ trợ công nghệ Giao tiếp phạm vi gần (NFC)</translation>
-<translation id="6910211073230771657">Äã xóa</translation>
<translation id="6912998170423641340">Chặn trang web Ä‘á»c văn bản và hình ảnh từ bảng nhá»› tạm</translation>
<translation id="6945221475159498467">Chá»n</translation>
<translation id="6965382102122355670">OK</translation>
+<translation id="6981982820502123353">Hỗ trợ tiếp cận</translation>
<translation id="6992289844737586249">Há»i trÆ°á»›c trÆ°á»›c khi cho phép các trang web sá»­ dụng micrô của bạn (được Ä‘á» xuất)</translation>
<translation id="7000754031042624318">Äã tắt trong phần Cài đặt Android</translation>
<translation id="7016516562562142042">Äược cho phép đối vá»›i công cụ tìm kiếm hiện tại</translation>
+<translation id="702463548815491781">Khuyên dùng khi dịch vụ TalkBack hoặc Tiếp cận bằng công tắc đang bật</translation>
<translation id="7053983685419859001">Chặn</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{Äã chá»n 1 mục}other{Äã chá»n # mục}}</translation>
-<translation id="7070090581017165256">Thông tin vỠtrang web này</translation>
<translation id="7087918508125750058">Äã chá»n <ph name="ITEM_COUNT" /> mục. Bạn có thể sá»­ dụng các tùy chá»n ở gần đầu màn hình</translation>
<translation id="7141896414559753902">Chặn trang web hiển thị cửa sổ bật lên và liên kết chuyển hướng (khuyên dùng)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> KB</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">Một trang web đang sử dụng micrô của bạn</translation>
<translation id="7561196759112975576">Luôn luôn</translation>
-<translation id="7572498721684305250">Chặn không cho các trang web gá»­i và nhận thông tin khi bạn nhấn vào tùy chá»n thiết bị dùng công nghệ giao tiếp tầm gần (NFC)</translation>
<translation id="757524316907819857">Chặn không cho trang web phát nội dung được bảo vệ</translation>
+<translation id="7577900504646297215">Quản lý mối quan tâm</translation>
<translation id="7649070708921625228">Trợ giúp</translation>
<translation id="7658239707568436148">Hủy</translation>
<translation id="7781829728241885113">Hôm qua</translation>
@@ -287,7 +299,8 @@
<translation id="8206354486702514201">Cài đặt này được quản trị viên của bạn thực thi.</translation>
<translation id="8211406090763984747">Kết nối an toàn</translation>
<translation id="8249310407154411074">Chuyển lên trên cùng</translation>
-<translation id="8261506727792406068">Xóa</translation>
+<translation id="8261506727792406068">Xoá</translation>
+<translation id="8284326494547611709">Phụ Ä‘á»</translation>
<translation id="8300705686683892304">Do ứng dụng quản lý</translation>
<translation id="8324158725704657629">Không há»i lại</translation>
<translation id="8372893542064058268">Cho phép Äồng bá»™ hóa dÆ°á»›i ná»n cho trang web cụ thể.</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">Phóng to</translation>
<translation id="8921772741368021346"><ph name="POSITION" />/<ph name="DURATION" /></translation>
<translation id="8926666909099850184">NFC đã tắt đối với thiết bị này. Hãy bật trong phần <ph name="BEGIN_LINK" />Cài đặt Android<ph name="END_LINK" />.</translation>
+<translation id="8928445016601307354">Chặn không cho các trang web xem và thay đổi thông tin trên thiết bị NFC</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">Chặn cookie của một trang web cụ thể.</translation>
<translation id="8959122750345127698">Không thể tiếp cận Ä‘iá»u hÆ°á»›ng: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_zh-CN.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_zh-CN.xtb
index 0e9f25d976a..8854e09328f 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_zh-CN.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_zh-CN.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">网站 <ph name="SITE_NAME" /> 已添加</translation>
<translation id="1383876407941801731">æœç´¢</translation>
<translation id="1384959399684842514">已暂åœä¸‹è½½</translation>
+<translation id="1409426117486808224">使用简化版视图查看打开的标签页</translation>
<translation id="1415402041810619267">网å€è¢«æˆªæ–­äº†</translation>
<translation id="1446450296470737166">å…许全é¢æŽ§åˆ¶ MIDI 设备</translation>
<translation id="1620510694547887537">æ‘„åƒå¤´</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">å…许使用 Cookie</translation>
<translation id="2228071138934252756">è‹¥è¦å…许 <ph name="APP_NAME" /> 使用您的摄åƒå¤´ï¼Œæ‚¨è¿˜éœ€åœ¨ <ph name="BEGIN_LINK" />Android 设置<ph name="END_LINK" />中开å¯æ‘„åƒå¤´ã€‚</translation>
<translation id="2241634353105152135">仅一次</translation>
+<translation id="2253414712144136228">移除“<ph name="NAME_OF_LIST_ITEM" />â€</translation>
<translation id="2289270750774289114">在网站想å‘现附近的è“牙设备时询问您(推è)</translation>
<translation id="2315043854645842844">æ“作系统ä¸æ”¯æŒé€‰æ‹©å®¢æˆ·ç«¯è¯ä¹¦ã€‚</translation>
+<translation id="2321958826496381788">拖动该滑å—,将文字调整到适åˆæ‚¨é˜…读的大å°ã€‚点按两次æŸæ®µè½åŽï¼Œæ˜¾ç¤ºçš„文字至少应是这么大。</translation>
<translation id="2359808026110333948">继续</translation>
<translation id="2379925928934107488">当 Chrome 使用深色主题时,尽å¯èƒ½å¯¹ç½‘站应用深色主题</translation>
+<translation id="2387895666653383613">文字大å°</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{已授予“<ph name="PERMISSION_1" />â€æƒé™ã€â€œ<ph name="PERMISSION_2" />â€æƒé™å’Œå¦å¤– <ph name="NUM_MORE" /> 项æƒé™}other{已授予“<ph name="PERMISSION_1" />â€æƒé™ã€â€œ<ph name="PERMISSION_2" />â€æƒé™å’Œå¦å¤– <ph name="NUM_MORE" /> 项æƒé™}}</translation>
<translation id="2434158240863470628">ä¸‹è½½å®Œæˆ <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">显示信æ¯</translation>
<translation id="3123473560110926937">å·²ç¦æ­¢éƒ¨åˆ†ç½‘站显示广告</translation>
<translation id="3198916472715691905">已存储 <ph name="STORAGE_AMOUNT" /> æ•°æ®</translation>
+<translation id="3203366800380907218">æ¥è‡ªç½‘络</translation>
<translation id="321187648315454507">è‹¥è¦å…许 <ph name="APP_NAME" /> å‘您å‘é€é€šçŸ¥ï¼Œæ‚¨è¿˜éœ€åœ¨ <ph name="BEGIN_LINK" />Android 设置<ph name="END_LINK" />中开å¯é€šçŸ¥ã€‚</translation>
<translation id="3227137524299004712">麦克风</translation>
<translation id="3277252321222022663">å…许网站使用传感器(推è)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">您的设备使用情况</translation>
<translation id="385051799172605136">返回</translation>
<translation id="3859306556332390985">å‰è¿›</translation>
+<translation id="3895926599014793903">强制å¯ç”¨ç¼©æ”¾åŠŸèƒ½</translation>
<translation id="3955193568934677022">å…许网站播放å—ä¿æŠ¤çš„内容(推è)</translation>
<translation id="3967822245660637423">下载完毕</translation>
<translation id="3987993985790029246">å¤åˆ¶é“¾æŽ¥</translation>
<translation id="3991845972263764475">已下载 <ph name="BYTES_DOWNLOADED_WITH_UNITS" />,总大å°ä¸æ˜Ž</translation>
<translation id="4002066346123236978">标题</translation>
<translation id="4008040567710660924">å…许特定网站使用 Cookie。</translation>
+<translation id="4040330681741629921">当网站能以简化版视图显示时通知我</translation>
<translation id="4046123991198612571">下一曲</translation>
+<translation id="4149994727733219643">使用简化版视图查看网页</translation>
<translation id="4165986682804962316">网站设置</translation>
+<translation id="4194328954146351878">需先询问,得到许å¯åŽæ‰å…许网站查看和更改 NFC 设备上的信æ¯ï¼ˆæŽ¨è)</translation>
<translation id="4200726100658658164">打开ä½ç½®ä¿¡æ¯è®¾ç½®</translation>
<translation id="4226663524361240545">收到通知时设备会振动</translation>
<translation id="4259722352634471385">å·²å±è”½ <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">展开</translation>
<translation id="4336434711095810371">清除所有数æ®</translation>
<translation id="4402755511846832236">ç¦æ­¢ç½‘站了解您何时在主动使用此设备</translation>
+<translation id="4428065317363009941">广告个性化</translation>
<translation id="4434045419905280838">弹出å¼çª—å£å’Œé‡å®šå‘</translation>
<translation id="445467742685312942">å…许网站播放å—ä¿æŠ¤å†…容。</translation>
<translation id="4468959413250150279">å°†æŸä¸ªç‰¹å®šç½‘ç«™é™éŸ³ã€‚</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">选项ä½äºŽå±å¹•é¡¶éƒ¨é™„è¿‘</translation>
<translation id="5197729504361054390">系统会将您所选è”系人的详细信æ¯åˆ†äº«ç»™ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />。</translation>
<translation id="5216942107514965959">上次访问时间:今天</translation>
+<translation id="5264323282659631142">移除“<ph name="CHIP_LABEL" />â€</translation>
<translation id="528192093759286357">从顶部å‘下拖动并触摸“返回â€æŒ‰é’®ï¼Œå³å¯é€€å‡ºå…¨å±æ¨¡å¼ã€‚</translation>
<translation id="5300589172476337783">显示</translation>
<translation id="5301954838959518834">知é“了</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">æ­¤æ“作会清除网站存储的 <ph name="DATASIZE" /> æ•°æ®å’Œ Cookie。</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(以åŠå¦å¤– 1 个)}other{(以åŠå¦å¤– # 个)}}</translation>
<translation id="5403592356182871684">å称</translation>
+<translation id="5412236728747081950">此网站会从 Chrome 中了解您的兴趣,从而å‘您展示与您的需求更相符的广告</translation>
<translation id="5438097262470833822">此选项会é‡ç½® <ph name="WEBSITE" /> çš„æƒé™</translation>
<translation id="5489227211564503167">已播时长为 <ph name="ELAPSED_TIME" />,总时长为 <ph name="TOTAL_TIME" />。</translation>
<translation id="5494752089476963479">ç¦æ­¢ä¼šå±•ç¤ºä¾µæ‰°æ€§æˆ–误导性广告的网站显示广告</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">é‡æ–°åŠ è½½</translation>
<translation id="5596627076506792578">更多选项</translation>
<translation id="5649053991847567735">自动下载项</translation>
+<translation id="5668404140385795438">覆盖网站的请求,以防止放大</translation>
<translation id="5677928146339483299">å·²ç¦æ­¢</translation>
<translation id="5689516760719285838">ä½ç½®ä¿¡æ¯</translation>
<translation id="5690795753582697420">已在 Android 设置中关闭摄åƒå¤´</translation>
-<translation id="5710871682236653961">需先询问,得到许å¯åŽæ‰å…许网站在您触碰 NFC 设备时å‘é€å’ŒæŽ¥æ”¶ä¿¡æ¯ï¼ˆæŽ¨è)</translation>
<translation id="5719847187258001597">æ­¤æ“作会清除 <ph name="ORIGIN" /> 或其在主å±å¹•ä¸­å®‰è£…的应用所存储的全部数æ®å’Œ Cookie。</translation>
<translation id="5771720122942595109">å·²ç¦ç”¨â€œ<ph name="PERMISSION_1" />â€æƒé™</translation>
<translation id="5804241973901381774">æƒé™</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">播放</translation>
<translation id="6818926723028410516">选择内容</translation>
<translation id="6864395892908308021">æ­¤è®¾å¤‡æ— æ³•è¯»å– NFC æ•°æ®</translation>
-<translation id="6910211073230771657">已删除</translation>
<translation id="6912998170423641340">ç¦æ­¢ç½‘站读å–剪贴æ¿ä¸­çš„文字和图片</translation>
<translation id="6945221475159498467">选择</translation>
<translation id="6965382102122355670">确定</translation>
+<translation id="6981982820502123353">æ— éšœç¢</translation>
<translation id="6992289844737586249">在å…许网站使用您的麦克风å‰å…ˆè¯¢é—®ï¼ˆæŽ¨è)</translation>
<translation id="7000754031042624318">已在 Android 设置中关闭</translation>
<translation id="7016516562562142042">å…许当å‰æœç´¢å¼•æ“Žä½¿ç”¨</translation>
+<translation id="702463548815491781">å»ºè®®åœ¨å¼€å¯ TalkBack 或“开关控制â€æ—¶ä½¿ç”¨</translation>
<translation id="7053983685419859001">ç¦æ­¢</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{已选择 1 项}other{已选择 # 项}}</translation>
-<translation id="7070090581017165256">关于此网站</translation>
<translation id="7087918508125750058">已选择 <ph name="ITEM_COUNT" /> 项。选项ä½äºŽå±å¹•é¡¶éƒ¨é™„è¿‘</translation>
<translation id="7141896414559753902">ç¦æ­¢ç½‘站显示弹出å¼çª—å£å’Œé‡å®šå‘(推è)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> KB</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">有一个网站正在使用您的麦克风</translation>
<translation id="7561196759112975576">永远</translation>
-<translation id="7572498721684305250">ç¦æ­¢ç½‘站在您触碰 NFC 设备时å‘é€å’ŒæŽ¥æ”¶ä¿¡æ¯</translation>
<translation id="757524316907819857">ç¦æ­¢ç½‘站播放å—ä¿æŠ¤çš„内容</translation>
+<translation id="7577900504646297215">管ç†æˆ‘的兴趣</translation>
<translation id="7649070708921625228">帮助</translation>
<translation id="7658239707568436148">å–消</translation>
<translation id="7781829728241885113">昨天</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">连接是安全的</translation>
<translation id="8249310407154411074">移至顶部</translation>
<translation id="8261506727792406068">删除</translation>
+<translation id="8284326494547611709">字幕</translation>
<translation id="8300705686683892304">由应用管ç†</translation>
<translation id="8324158725704657629">别å†è¯¢é—®</translation>
<translation id="8372893542064058268">å…许特定网站进行åŽå°åŒæ­¥ã€‚</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">放大</translation>
<translation id="8921772741368021346"><ph name="POSITION" /> / <ph name="DURATION" /></translation>
<translation id="8926666909099850184">此设备的 NFC 功能处于关闭状æ€ã€‚请在 <ph name="BEGIN_LINK" />Android 设置<ph name="END_LINK" />中开å¯æ­¤åŠŸèƒ½ã€‚</translation>
+<translation id="8928445016601307354">ç¦æ­¢ç½‘站查看和更改 NFC 设备上的信æ¯</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">阻止特定网站使用 Cookie。</translation>
<translation id="8959122750345127698">无法访问 <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_zh-HK.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_zh-HK.xtb
index aaf984100fa..139ace828f1 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_zh-HK.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_zh-HK.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">已新增網站 <ph name="SITE_NAME" /></translation>
<translation id="1383876407941801731">æœå°‹</translation>
<translation id="1384959399684842514">已暫åœä¸‹è¼‰</translation>
+<translation id="1409426117486808224">使用簡化檢視模å¼æŸ¥çœ‹é–‹å•Ÿçš„分é </translation>
<translation id="1415402041810619267">縮短咗網å€</translation>
<translation id="1446450296470737166">å…許全權控制 MIDI è£ç½®ã€‚</translation>
<translation id="1620510694547887537">相機</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">å…許 Cookie</translation>
<translation id="2228071138934252756">如è¦è®“ <ph name="APP_NAME" /> å­˜å–您的相機,請一併在 <ph name="BEGIN_LINK" />Android 設定<ph name="END_LINK" />中開啟相機。</translation>
<translation id="2241634353105152135">åªæœ‰é€™ä¸€æ¬¡</translation>
+<translation id="2253414712144136228">移除<ph name="NAME_OF_LIST_ITEM" /></translation>
<translation id="2289270750774289114">在網站è¦æŽ¢ç´¢é™„è¿‘çš„è—牙è£ç½®æ™‚è©¢å•æ‚¨ (建議)</translation>
<translation id="2315043854645842844">作業系統ä¸æ”¯æ´ç”±å®¢æˆ¶ç«¯é¸å–憑證。</translation>
+<translation id="2321958826496381788">拖曳滑桿,將文字調整到您閱讀時感到舒é©çš„大å°ã€‚當您輕按兩下文字段è½ï¼Œæ–‡å­—至少應有這樣大。</translation>
<translation id="2359808026110333948">繼續</translation>
<translation id="2379925928934107488">當 Chrome 採用深色主題背景時,盡å¯èƒ½å°ç¶²ç«™å¥—用深色主題背景</translation>
+<translation id="2387895666653383613">文字大å°</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{å·²å…許「<ph name="PERMISSION_1" />ã€ã€ã€Œ<ph name="PERMISSION_2" />ã€å’Œå¦å¤– <ph name="NUM_MORE" /> 項權é™}other{å·²å…許「<ph name="PERMISSION_1" />ã€ã€ã€Œ<ph name="PERMISSION_2" />ã€å’Œå¦å¤– <ph name="NUM_MORE" /> 項權é™}}</translation>
<translation id="2434158240863470628">ä¸‹è¼‰å®Œæˆ <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">顯示資料</translation>
<translation id="3123473560110926937">在部分網站上設定å°éŽ–</translation>
<translation id="3198916472715691905">已使用 <ph name="STORAGE_AMOUNT" /> 儲存空間</translation>
+<translation id="3203366800380907218">來自網絡</translation>
<translation id="321187648315454507">如è¦è®“ <ph name="APP_NAME" /> 傳é€é€šçŸ¥ï¼Œè«‹ä¸€ä½µåœ¨ <ph name="BEGIN_LINK" />Android 設定<ph name="END_LINK" />中開啟通知功能。</translation>
<translation id="3227137524299004712">麥克風</translation>
<translation id="3277252321222022663">å…許網站存å–感應器 (建議)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">您的è£ç½®ä½¿ç”¨ç‹€æ…‹</translation>
<translation id="385051799172605136">返回</translation>
<translation id="3859306556332390985">å‘å‰å¿«è½‰</translation>
+<translation id="3895926599014793903">強制啟用縮放功能</translation>
<translation id="3955193568934677022">å…許網站播放å—ä¿è­·çš„內容 (建議)</translation>
<translation id="3967822245660637423">下載完æˆ</translation>
<translation id="3987993985790029246">複製連çµ</translation>
<translation id="3991845972263764475">已下載:<ph name="BYTES_DOWNLOADED_WITH_UNITS" />,總大å°ï¼šä¸æ˜Ž</translation>
<translation id="4002066346123236978">標題</translation>
<translation id="4008040567710660924">å…è¨±ç‰¹å®šç¶²ç«™å­˜å– Cookie。</translation>
+<translation id="4040330681741629921">在網站能以簡化檢視模å¼é¡¯ç¤ºæ™‚接收通知</translation>
<translation id="4046123991198612571">下一首曲目</translation>
+<translation id="4149994727733219643">使用簡化檢視模å¼æŸ¥çœ‹ç¶²é </translation>
<translation id="4165986682804962316">網站設定</translation>
+<translation id="4194328954146351878">在å…許網站查看和變更 NFC è£ç½®ä¸Šçš„資料å‰å…ˆè©¢å•æ‚¨ (建議)</translation>
<translation id="4200726100658658164">é–‹å•Ÿä½ç½®è¨­å®š</translation>
<translation id="4226663524361240545">è£ç½®æœƒåœ¨æ”¶åˆ°é€šçŸ¥æ™‚震動</translation>
<translation id="4259722352634471385">ç€è¦½ç¶²å€è¢«å°éŽ–:<ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">展開</translation>
<translation id="4336434711095810371">清除所有資料</translation>
<translation id="4402755511846832236">ç¦æ­¢ç¶²ç«™å–å¾—æ­¤è£ç½®çš„使用狀態</translation>
+<translation id="4428065317363009941">廣告個人化</translation>
<translation id="4434045419905280838">彈出å¼è¦–窗和é‡æ–°å°Žå‘</translation>
<translation id="445467742685312942">å…許網站播放å—ä¿è­·çš„內容</translation>
<translation id="4468959413250150279">將特定網站設為éœéŸ³ã€‚</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">é¸é …喺螢幕頂部附近</translation>
<translation id="5197729504361054390">系統會將您é¸å–çš„è¯çµ¡äººå‘ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> æ供。</translation>
<translation id="5216942107514965959">上次ç€è¦½æ™‚間:今天</translation>
+<translation id="5264323282659631142">移除「<ph name="CHIP_LABEL" />ã€</translation>
<translation id="528192093759286357">由上而下拖曳,然後輕觸返回按鈕å³å¯é€€å‡ºå…¨èž¢å¹•ã€‚</translation>
<translation id="5300589172476337783">顯示</translation>
<translation id="5301954838959518834">好,我知é“了</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">æ­¤æ“作會清除網站儲存的資料和 Cookie (å…± <ph name="DATASIZE" />)。</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(還有 1 個)}other{(還有 # 個)}}</translation>
<translation id="5403592356182871684">å稱</translation>
+<translation id="5412236728747081950">此網站會從 Chrome å–得您的喜好,為您顯示更相關的廣告</translation>
<translation id="5438097262470833822">æ­¤é¸é …將會清除 <ph name="WEBSITE" /> 的權é™</translation>
<translation id="5489227211564503167">播咗嘅時間係 <ph name="ELAPSED_TIME" />,影片總長度係 <ph name="TOTAL_TIME" />。</translation>
<translation id="5494752089476963479">在顯示滋擾或誤導廣告的網站上å°éŽ–廣告</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">é‡æ–°è¼‰å…¥</translation>
<translation id="5596627076506792578">更多é¸é …</translation>
<translation id="5649053991847567735">自動下載</translation>
+<translation id="5668404140385795438">覆寫網站ç¦æ­¢æ”¾å¤§çš„è¦æ±‚</translation>
<translation id="5677928146339483299">å·²å°éŽ–</translation>
<translation id="5689516760719285838">ä½ç½®</translation>
<translation id="5690795753582697420">相機已在 Android 設定中關閉</translation>
-<translation id="5710871682236653961">系統需è¦å…ˆè©¢å•æ‚¨ï¼Œæ‰èƒ½å…許網站在您輕按 NFC è£ç½®æ™‚傳é€åŠæŽ¥æ”¶è³‡è¨Š (建議)</translation>
<translation id="5719847187258001597">æ­¤æ“作會清除主畫é¢ä¸Š <ph name="ORIGIN" /> 或其應用程å¼å„²å­˜çš„所有資料和 Cookie。</translation>
<translation id="5771720122942595109">å·²å°éŽ–「<ph name="PERMISSION_1" />ã€</translation>
<translation id="5804241973901381774">權é™</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">播放</translation>
<translation id="6818926723028410516">é¸å–é …ç›®</translation>
<translation id="6864395892908308021">æ­¤è£ç½®ç„¡æ³•è®€å– NFC</translation>
-<translation id="6910211073230771657">已刪除</translation>
<translation id="6912998170423641340">ç¦æ­¢ç¶²ç«™è®€å–剪貼簿的文字和圖片</translation>
<translation id="6945221475159498467">é¸å–</translation>
<translation id="6965382102122355670">確定</translation>
+<translation id="6981982820502123353">å”助工具</translation>
<translation id="6992289844737586249">å…許網站使用麥克風å‰å…ˆè©¢å•æ‚¨ (建議)</translation>
<translation id="7000754031042624318">已在「Android 設定ã€ä¸­é—œé–‰</translation>
<translation id="7016516562562142042">å…許目å‰çš„æœå°‹å¼•æ“Žä½¿ç”¨</translation>
+<translation id="702463548815491781">建議在 TalkBack 或「按鈕控制ã€é–‹å•Ÿæ™‚使用</translation>
<translation id="7053983685419859001">å°éŽ–</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{å·²é¸å– 1 個項目}other{å·²é¸å– # 個項目}}</translation>
-<translation id="7070090581017165256">關於此網站</translation>
<translation id="7087918508125750058">æ€å’— <ph name="ITEM_COUNT" /> 個。é¸é …喺螢幕頂部</translation>
<translation id="7141896414559753902">ç¦æ­¢ç¶²ç«™é¡¯ç¤ºå½ˆå‡ºå¼è¦–窗和é‡æ–°å°Žå‘ (建議)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> KB</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">有網站正在使用您的麥克風</translation>
<translation id="7561196759112975576">æ°¸é ä½¿ç”¨</translation>
-<translation id="7572498721684305250">ç¦æ­¢ç¶²ç«™åœ¨æ‚¨è¼•æŒ‰ NFC è£ç½®æ™‚傳é€åŠæŽ¥æ”¶è³‡æ–™</translation>
<translation id="757524316907819857">ç¦æ­¢ç¶²ç«™æ’­æ”¾å—ä¿è­·å…§å®¹</translation>
+<translation id="7577900504646297215">管ç†èˆˆè¶£</translation>
<translation id="7649070708921625228">說明</translation>
<translation id="7658239707568436148">å–消</translation>
<translation id="7781829728241885113">昨天</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">己建立安全連線</translation>
<translation id="8249310407154411074">移至頂部</translation>
<translation id="8261506727792406068">刪除</translation>
+<translation id="8284326494547611709">字幕</translation>
<translation id="8300705686683892304">由應用程å¼ç®¡ç†</translation>
<translation id="8324158725704657629">ä¸è¦å†è©¢å•</translation>
<translation id="8372893542064058268">å…許特定網站執行背景åŒæ­¥åŠŸèƒ½ã€‚</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">放大</translation>
<translation id="8921772741368021346"><ph name="POSITION" />/<ph name="DURATION" /></translation>
<translation id="8926666909099850184">æ­¤è£ç½®çš„ NFC 已關閉,請在「<ph name="BEGIN_LINK" />Android 設定<ph name="END_LINK" />ã€ä¸­é–‹å•Ÿã€‚</translation>
+<translation id="8928445016601307354">ç¦æ­¢ç¶²ç«™åœ¨ NFC è£ç½®ä¸ŠæŸ¥çœ‹å’Œè®Šæ›´è³‡æ–™</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">ç¦æ­¢ç‰¹å®šç¶²ç«™å­˜å– Cookie。</translation>
<translation id="8959122750345127698">無法存å–ç€è¦½ç¶²å€ï¼š<ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_zh-TW.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_zh-TW.xtb
index 3afe37c10a1..a5207d3a809 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_zh-TW.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_zh-TW.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">已新增 <ph name="SITE_NAME" /> 網站</translation>
<translation id="1383876407941801731">æœå°‹</translation>
<translation id="1384959399684842514">已暫åœä¸‹è¼‰</translation>
+<translation id="1409426117486808224">使用簡易檢視模å¼æŸ¥çœ‹é–‹å•Ÿçš„分é </translation>
<translation id="1415402041810619267">已截斷網å€</translation>
<translation id="1446450296470737166">å…許完整控制 MIDI è£ç½®</translation>
<translation id="1620510694547887537">æ”影機</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">å…許 Cookie</translation>
<translation id="2228071138934252756">如è¦å…許 <ph name="APP_NAME" /> å­˜å–è£ç½®çš„相機,請一併在 <ph name="BEGIN_LINK" />Android 設定<ph name="END_LINK" />中開啟相機。</translation>
<translation id="2241634353105152135">åªæœ‰é€™ä¸€æ¬¡</translation>
+<translation id="2253414712144136228">移除<ph name="NAME_OF_LIST_ITEM" /></translation>
<translation id="2289270750774289114">當網站è¦æœå°‹é™„è¿‘çš„è—牙è£ç½®æ™‚,必須先詢å•ä½  (建議)</translation>
<translation id="2315043854645842844">作業系統ä¸å…許您在用戶端é¸å–憑證。</translation>
+<translation id="2321958826496381788">拖曳滑桿,將文字調整到é©ç•¶çš„字體大å°ã€‚當你輕觸兩下文字段è½æ™‚,ç€è¦½å™¨è‡³å°‘應呈ç¾é€™æ¨£çš„字體大å°ã€‚</translation>
<translation id="2359808026110333948">繼續</translation>
<translation id="2379925928934107488">當 Chrome 採用深色主題時,盡å¯èƒ½å°ç¶²ç«™å¥—用深色主題</translation>
+<translation id="2387895666653383613">文字大å°</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{å·²å…許「<ph name="PERMISSION_1" />ã€ã€ã€Œ<ph name="PERMISSION_2" />ã€å’Œå¦å¤– <ph name="NUM_MORE" /> 項權é™}other{å·²å…許「<ph name="PERMISSION_1" />ã€ã€ã€Œ<ph name="PERMISSION_2" />ã€å’Œå¦å¤– <ph name="NUM_MORE" /> 項權é™}}</translation>
<translation id="2434158240863470628">ä¸‹è¼‰å®Œæˆ <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">顯示資訊</translation>
<translation id="3123473560110926937">在æŸäº›ç¶²ç«™ä¸Šè¨­å®šå°éŽ–</translation>
<translation id="3198916472715691905">儲存了 <ph name="STORAGE_AMOUNT" /> 的資料</translation>
+<translation id="3203366800380907218">來自網路</translation>
<translation id="321187648315454507">如è¦å…許 <ph name="APP_NAME" /> 傳é€é€šçŸ¥ï¼Œè«‹ä¸€ä½µåœ¨ <ph name="BEGIN_LINK" />Android 設定<ph name="END_LINK" />中開啟通知功能。</translation>
<translation id="3227137524299004712">麥克風</translation>
<translation id="3277252321222022663">å…許網站存å–感應器 (建議)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">ä½ çš„è£ç½®ä½¿ç”¨ç‹€æ…‹</translation>
<translation id="385051799172605136">返回</translation>
<translation id="3859306556332390985">快轉到特定的播放時間點</translation>
+<translation id="3895926599014793903">強制啟用縮放功能</translation>
<translation id="3955193568934677022">å…許網站播放å—ä¿è­·çš„內容 (建議)</translation>
<translation id="3967822245660637423">下載完æˆ</translation>
<translation id="3987993985790029246">複製連çµ</translation>
<translation id="3991845972263764475">已下載:<ph name="BYTES_DOWNLOADED_WITH_UNITS" />,總大å°ï¼šä¸æ˜Ž</translation>
<translation id="4002066346123236978">標題</translation>
<translation id="4008040567710660924">å…許特定網站的 Cookie。</translation>
+<translation id="4040330681741629921">在網站能以簡易檢視模å¼é¡¯ç¤ºæ™‚通知我</translation>
<translation id="4046123991198612571">下一首曲目</translation>
+<translation id="4149994727733219643">使用簡易檢視模å¼æŸ¥çœ‹ç¶²é </translation>
<translation id="4165986682804962316">網站設定</translation>
+<translation id="4194328954146351878">系統必須先詢å•ä½ ï¼Œæ‰èƒ½å…許網站在 NFC è£ç½®ä¸ŠæŸ¥çœ‹å’Œè®Šæ›´è³‡è¨Š (建議設定)</translation>
<translation id="4200726100658658164">é–‹å•Ÿä½ç½®è³‡è¨Šè¨­å®š</translation>
<translation id="4226663524361240545">收到通知時è£ç½®æœƒéœ‡å‹•</translation>
<translation id="4259722352634471385">ç€è¦½çš„網å€å·²å°éŽ–:<ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">展開</translation>
<translation id="4336434711095810371">清除所有資料</translation>
<translation id="4402755511846832236">ç¦æ­¢ç¶²ç«™å–得這部è£ç½®çš„使用狀態</translation>
+<translation id="4428065317363009941">廣告個人化</translation>
<translation id="4434045419905280838">彈出å¼è¦–窗與é‡æ–°å°Žå‘</translation>
<translation id="445467742685312942">å…許網站播放å—ä¿è­·çš„內容</translation>
<translation id="4468959413250150279">將特定網站設為éœéŸ³ã€‚</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">é¸é …ä½æ–¼ç•«é¢é ‚端</translation>
<translation id="5197729504361054390">系統會將你é¸å–çš„è¯çµ¡äººè³‡è¨Šæ供給 <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />。</translation>
<translation id="5216942107514965959">上次造訪日期:今天</translation>
+<translation id="5264323282659631142">移除「<ph name="CHIP_LABEL" />ã€</translation>
<translation id="528192093759286357">從頂端拖曳並輕觸返回按鈕å³å¯çµæŸå…¨èž¢å¹•æ¨¡å¼ã€‚</translation>
<translation id="5300589172476337783">顯示</translation>
<translation id="5301954838959518834">好,我知é“了</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">這會清除網站儲存的資料和 Cookie (共 <ph name="DATASIZE" />)。</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(還有 1 個)}other{(還有 # 個)}}</translation>
<translation id="5403592356182871684">å稱</translation>
+<translation id="5412236728747081950">這個網站會å–得你在 Chrome 設定的興趣喜好,為你顯示更貼近需求的廣告</translation>
<translation id="5438097262470833822">這會é‡è¨­ <ph name="WEBSITE" /> 的權é™</translation>
<translation id="5489227211564503167">經éŽæ™‚間:<ph name="ELAPSED_TIME" />,影片總長:<ph name="TOTAL_TIME" />。</translation>
<translation id="5494752089476963479">å°éŽ–干擾性或誤導性的網站廣告</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">é‡æ–°è¼‰å…¥</translation>
<translation id="5596627076506792578">更多é¸é …</translation>
<translation id="5649053991847567735">自動下載</translation>
+<translation id="5668404140385795438">覆寫網站ç¦æ­¢æ”¾å¤§çš„è¦æ±‚</translation>
<translation id="5677928146339483299">å·²å°éŽ–</translation>
<translation id="5689516760719285838">ä½ç½®</translation>
<translation id="5690795753582697420">已關閉 Android 設定中的æ”影機</translation>
-<translation id="5710871682236653961">系統必須先詢å•ä½ ï¼Œæ‰èƒ½å…許網站在你輕觸 NFC è£ç½®æ™‚傳é€åŠæŽ¥æ”¶è³‡è¨Š (建議設定)</translation>
<translation id="5719847187258001597">這會清除 <ph name="ORIGIN" /> 或該網站在主畫é¢ä¸Šçš„應用程å¼æ‰€å„²å­˜çš„所有資料和 Cookie。</translation>
<translation id="5771720122942595109">å·²å°éŽ–「<ph name="PERMISSION_1" />ã€</translation>
<translation id="5804241973901381774">權é™</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">播放</translation>
<translation id="6818926723028410516">é¸å–é …ç›®</translation>
<translation id="6864395892908308021">這部è£ç½®ç„¡æ³•è®€å– NFC</translation>
-<translation id="6910211073230771657">已刪除</translation>
<translation id="6912998170423641340">ç¦æ­¢ç¶²ç«™è®€å–剪貼簿中的文字和圖片</translation>
<translation id="6945221475159498467">é¸å–</translation>
<translation id="6965382102122355670">確定</translation>
+<translation id="6981982820502123353">無障礙設定</translation>
<translation id="6992289844737586249">å…許網站使用你的麥克風å‰ï¼Œå¿…須先詢å•ä½  (建議)</translation>
<translation id="7000754031042624318">已在 Android 設定中關閉</translation>
<translation id="7016516562562142042">å…許目å‰çš„æœå°‹å¼•æ“Žå­˜å–ä½ç½®è³‡è¨Š</translation>
+<translation id="702463548815491781">建議在 TalkBack 或切æ›æŽ§åˆ¶åŠŸèƒ½é–‹å•Ÿæ™‚使用</translation>
<translation id="7053983685419859001">å°éŽ–</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{å·²é¸å– 1 個項目}other{å·²é¸å– # 個項目}}</translation>
-<translation id="7070090581017165256">關於這個網站</translation>
<translation id="7087918508125750058">å·²é¸å– <ph name="ITEM_COUNT" /> 個項目。é¸é …ä½æ–¼ç•«é¢é ‚端</translation>
<translation id="7141896414559753902">ç¦æ­¢ç¶²ç«™é¡¯ç¤ºå½ˆå‡ºå¼è¦–窗åŠé‡æ–°å°Žå‘ (建議)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> KB</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7554752735887601236">有網站正在使用你的麥克風</translation>
<translation id="7561196759112975576">一律使用</translation>
-<translation id="7572498721684305250">ç¦æ­¢ç¶²ç«™åœ¨ä½ è¼•è§¸ NFC è£ç½®æ™‚傳é€åŠæŽ¥æ”¶è³‡è¨Š</translation>
<translation id="757524316907819857">ç¦æ­¢ç¶²ç«™æ’­æ”¾å—ä¿è­·çš„內容</translation>
+<translation id="7577900504646297215">管ç†èˆˆè¶£å–œå¥½</translation>
<translation id="7649070708921625228">說明</translation>
<translation id="7658239707568436148">å–消</translation>
<translation id="7781829728241885113">昨天</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">已建立安全連線</translation>
<translation id="8249310407154411074">移至頂端</translation>
<translation id="8261506727792406068">刪除</translation>
+<translation id="8284326494547611709">字幕</translation>
<translation id="8300705686683892304">由應用程å¼ç®¡ç†</translation>
<translation id="8324158725704657629">ä¸è¦å†è©¢å•</translation>
<translation id="8372893542064058268">å…許特定網站執行背景åŒæ­¥è™•ç†ä½œæ¥­ã€‚</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">放大</translation>
<translation id="8921772741368021346"><ph name="POSITION" />/<ph name="DURATION" /></translation>
<translation id="8926666909099850184">這部è£ç½®çš„ NFC 功能已關閉。請å‰å¾€ <ph name="BEGIN_LINK" />Android 設定<ph name="END_LINK" />開啟這項功能。</translation>
+<translation id="8928445016601307354">ç¦æ­¢ç¶²ç«™åœ¨ NFC è£ç½®ä¸ŠæŸ¥çœ‹å’Œè®Šæ›´è³‡è¨Š</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">å°éŽ–特定網站的 Cookie。</translation>
<translation id="8959122750345127698">ç€è¦½çš„網å€ç„¡æ³•å­˜å–:<ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_zu.xtb b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_zu.xtb
index a05f47a89ba..ccf854029c6 100644
--- a/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_zu.xtb
+++ b/chromium/components/browser_ui/strings/android/translations/browser_ui_strings_zu.xtb
@@ -16,6 +16,7 @@
<translation id="1369915414381695676">Isayithi le-<ph name="SITE_NAME" /> lingeziwe</translation>
<translation id="1383876407941801731">Sesha</translation>
<translation id="1384959399684842514">Ukulayisha kumiswe isikhashana</translation>
+<translation id="1409426117486808224">Ukubuka okwenziwe lula kumathebhu avuliwe</translation>
<translation id="1415402041810619267">I-URL inciphisiwe</translation>
<translation id="1446450296470737166">Vumela ulawulo olugcwele lwamadivayisi we-MIDI</translation>
<translation id="1620510694547887537">Ikhamela</translation>
@@ -49,10 +50,13 @@
<translation id="2212565012507486665">Vumela amakhukhi</translation>
<translation id="2228071138934252756">Ukuze uvumele i-<ph name="APP_NAME" /> ifinyelele ikhamera yakho, vula nekhamera <ph name="BEGIN_LINK" />Kumasethingi e-Android<ph name="END_LINK" />.</translation>
<translation id="2241634353105152135">Kanye nje</translation>
+<translation id="2253414712144136228">Susa i-<ph name="NAME_OF_LIST_ITEM" /></translation>
<translation id="2289270750774289114">Buza uma isayithi lifuna ukuthola amadivayisi aseduze e-Bluetooth (kunconyiwe)</translation>
<translation id="2315043854645842844">Ukukhethwa kwesitifiketi sohlangothi lweklayenti akusekelwe yisistimu yokusebenza.</translation>
+<translation id="2321958826496381788">Hudula isilayida uze ufunde lokhu unelisekile. Umbhalo kumele ubukeke okungenani umkhulu ngale ndlela ngemuva kokuthepha kabili kupharagrafu.</translation>
<translation id="2359808026110333948">Qhubeka</translation>
<translation id="2379925928934107488">Sebenzisa itimu emnyama kumasayithi lapho i-Chrome isebenzisa itimu emnyama, uma kunokwenzeka</translation>
+<translation id="2387895666653383613">Ukulinganisa kombhalo</translation>
<translation id="2402980924095424747"><ph name="MEGABYTES" /> MB</translation>
<translation id="2404630663942400771">{PERMISSIONS_SUMMARY_ALLOWED,plural, =1{I-<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, nezinye ezingu-<ph name="NUM_MORE" /> zivunyelwe}one{I-<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, nezinye ezingu-<ph name="NUM_MORE" /> zivunyelwe}other{I-<ph name="PERMISSION_1" />, <ph name="PERMISSION_2" />, nezinye ezingu-<ph name="NUM_MORE" /> zivunyelwe}}</translation>
<translation id="2434158240863470628">Ukulanda kuqedile <ph name="SEPARATOR" /> <ph name="BYTES_DOWNLOADED" /></translation>
@@ -89,6 +93,7 @@
<translation id="3115898365077584848">Khombisa ulwazi</translation>
<translation id="3123473560110926937">Kuvinjelwe kwamanye amasayithi</translation>
<translation id="3198916472715691905"><ph name="STORAGE_AMOUNT" /> idatha egciniwe</translation>
+<translation id="3203366800380907218">Kusuka kuwebhu</translation>
<translation id="321187648315454507">Ukuze uvumele i-<ph name="APP_NAME" /> ukuthi ikuthumele izaziso, vula nezaziso <ph name="BEGIN_LINK" />Kumasethingi e-Android<ph name="END_LINK" />.</translation>
<translation id="3227137524299004712">Imakrofoni</translation>
<translation id="3277252321222022663">Vumela amasayithi ukuthi afinyelele kuzinzwa (kunconyiwe)</translation>
@@ -110,14 +115,18 @@
<translation id="3835233591525155343">Umsebenzi wedivayisi yakho</translation>
<translation id="385051799172605136">Emuva</translation>
<translation id="3859306556332390985">Funela phambili</translation>
+<translation id="3895926599014793903">Phoqa ukunika amandla ukusondeza</translation>
<translation id="3955193568934677022">Vumela amasayithi ukudlala okuqukethwe okuvikelwe (kunconyiwe)</translation>
<translation id="3967822245660637423">Ukulanda kuqedile</translation>
<translation id="3987993985790029246">Kopisha isixhumanisi</translation>
<translation id="3991845972263764475"><ph name="BYTES_DOWNLOADED_WITH_UNITS" /> / ?</translation>
<translation id="4002066346123236978">Isihloko</translation>
<translation id="4008040567710660924">Vumela amakhukhi esayithi elithile.</translation>
+<translation id="4040330681741629921">Thola ukwaziswa uma isayithi lingaboniswa ekubukeni okwenziwe lula</translation>
<translation id="4046123991198612571">Ithrekhi elandelayo</translation>
+<translation id="4149994727733219643">Ukubuka okwenziwe lula kwamakhasi ewebhu</translation>
<translation id="4165986682804962316">Izilungiselelo zesayithi</translation>
+<translation id="4194328954146351878">Buza ngaphambi kokuvumela amasayithi ukuthi abone futhi aguqule ulwazi kumadivayisi e-NFC (kuyanconywa)</translation>
<translation id="4200726100658658164">Vula Izilungiselelo zendawo</translation>
<translation id="4226663524361240545">Izaziso zingadlidliza idivayisi</translation>
<translation id="4259722352634471385">Ukuzulazula kuvinjiwe: <ph name="URL" /></translation>
@@ -126,6 +135,7 @@
<translation id="42981349822642051">Nweba</translation>
<translation id="4336434711095810371">Sula yonke idatha</translation>
<translation id="4402755511846832236">Vimbela amasayithi ukuthi azi lapho usebenzisa le divayisi</translation>
+<translation id="4428065317363009941">Ukwenza ngezifiso izikhangiso</translation>
<translation id="4434045419905280838">Okwesikhashana nokuqondiswa kabusha</translation>
<translation id="445467742685312942">Vumela amasayithi ukudlala okuqukethwe okuvikelekile</translation>
<translation id="4468959413250150279">Thulisa umsindo kusayithi elithile.</translation>
@@ -156,6 +166,7 @@
<translation id="5186036860380548585">Inketho iyatholakala eduze kwaphezulu kwesikrini</translation>
<translation id="5197729504361054390">Oxhumana nabo obakhethayo bazokwabiwa no-<ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />.</translation>
<translation id="5216942107514965959">Kugcine ukuvakashelwa namuhla</translation>
+<translation id="5264323282659631142">Susa i-'<ph name="CHIP_LABEL" />'</translation>
<translation id="528192093759286357">Hudula kusukela phezulu uphinde uthinte inkinobho yokubuyela emuva ukuze uphume kusikrini esigcwele.</translation>
<translation id="5300589172476337783">Bonisa</translation>
<translation id="5301954838959518834">OK, ngiyezwa</translation>
@@ -166,6 +177,7 @@
<translation id="5354152178998424783">Lokhu kuzosula idatha engu-<ph name="DATASIZE" /> namakhukhu alondolozwe amasayithi.</translation>
<translation id="5394307150471348411">{DETAIL_COUNT,plural, =1{(+ 1 okuningi)}one{(+ # okuningi)}other{(+ # okuningi)}}</translation>
<translation id="5403592356182871684">Amagama</translation>
+<translation id="5412236728747081950">Leli sayithi lithola ongaba nentshisekelo kukho ku-Chrome ukuze likubonise izikhangiso ezihambisana kakhulu</translation>
<translation id="5438097262470833822">Le nketho izosetha kabusha izimvume ze-<ph name="WEBSITE" /></translation>
<translation id="5489227211564503167">Isikhathi esidlulile singu-<ph name="ELAPSED_TIME" /> kwesingu-<ph name="TOTAL_TIME" />.</translation>
<translation id="5494752089476963479">Vimbela izikhangiso kumasayithi abonisa izikhangiso ezisongelayo noma ezilahlekisayo</translation>
@@ -177,10 +189,10 @@
<translation id="5556459405103347317">Phinda ulayishe</translation>
<translation id="5596627076506792578">Izinketho eziningi</translation>
<translation id="5649053991847567735">Ukulandwa okuzenzakalelayo</translation>
+<translation id="5668404140385795438">Bhala ngaphezulu izicelo zamawebhusayithi ukuvikela ukusondeza</translation>
<translation id="5677928146339483299">Kuvinjelwe</translation>
<translation id="5689516760719285838">Indawo</translation>
<translation id="5690795753582697420">Ikhamera ivaliwe kuzilungiselelo ze-Android</translation>
-<translation id="5710871682236653961">Buza ngaphambi kokuvumela amasayithi ukuthi athumele aphinde amukele ulwazi uma uthepha amadivayisi e-NFC (kunconyiwe)</translation>
<translation id="5719847187258001597">Lokhu kuzosula yonke idatha namakhukhi agcinwe yi-<ph name="ORIGIN" /> noma uhlelo lwayo lokusebenza Kusikrini sakho sasekhaya.</translation>
<translation id="5771720122942595109">I-<ph name="PERMISSION_1" /> ivinjiwe</translation>
<translation id="5804241973901381774">Izimvume</translation>
@@ -230,16 +242,16 @@
<translation id="6790428901817661496">Dlala</translation>
<translation id="6818926723028410516">Khetha izinto</translation>
<translation id="6864395892908308021">Le divayisi ayikwazi ukufunda i-NFC</translation>
-<translation id="6910211073230771657">Kususiwe</translation>
<translation id="6912998170423641340">Vimbela amasayithi kusukela ekufundeni umbhalo nezithombe kusukela kubhodi lokunamathisela</translation>
<translation id="6945221475159498467">Khetha</translation>
<translation id="6965382102122355670">OK</translation>
+<translation id="6981982820502123353">Ukufinyeleleka</translation>
<translation id="6992289844737586249">Buza kuqala ngaphambi kokuvumela amasayithi ukuthi asebenzise imakrofoni yakho (kunconyiwe)</translation>
<translation id="7000754031042624318">Kuvaliwe kuzilungiselelo ze-Android</translation>
<translation id="7016516562562142042">Kuvunyelwe injini yokusesha yamanje</translation>
+<translation id="702463548815491781">Kunconyiwe uma i-TalkBack noma okuthi Shintsha ukufinyelela kuvuliwe</translation>
<translation id="7053983685419859001">Vimba</translation>
<translation id="7066151586745993502">{NUM_SELECTED,plural, =1{1 ekhethiwe}one{# ekhethiwe}other{# ekhethiwe}}</translation>
-<translation id="7070090581017165256">Mayelana naleli sayithi</translation>
<translation id="7087918508125750058"><ph name="ITEM_COUNT" /> kukhethiwe. Izinketho zitholakala eceleni naphezu kwesikrini</translation>
<translation id="7141896414559753902">Vimbela amasayithi kusukela ekuboniseni okwesikhashana nokuqondiswa kabusha (kunconyiwe)</translation>
<translation id="7176368934862295254"><ph name="KILOBYTES" /> KB</translation>
@@ -254,8 +266,8 @@
<translation id="7521387064766892559">I-JavaScript</translation>
<translation id="7554752735887601236">Isayithi isebenzisa imakrofoni yakho</translation>
<translation id="7561196759112975576">Njalo</translation>
-<translation id="7572498721684305250">Vimbela amasayithi kusukela ekuthumeleni nasekutholeni ulwazi uma uthepha amadivayisi e-NFC</translation>
<translation id="757524316907819857">Vimbela amasayithi ekudlaleni okuqukethwe okuvikelwe</translation>
+<translation id="7577900504646297215">Lawula izintshisekelo</translation>
<translation id="7649070708921625228">Usizo</translation>
<translation id="7658239707568436148">Khansela</translation>
<translation id="7781829728241885113">Izolo</translation>
@@ -288,6 +300,7 @@
<translation id="8211406090763984747">Ukuxhumeka kuvikelekile</translation>
<translation id="8249310407154411074">Thumela phezulu</translation>
<translation id="8261506727792406068">Susa</translation>
+<translation id="8284326494547611709">Amazwibela</translation>
<translation id="8300705686683892304">Kuphethwe uhlelo lokusebenza</translation>
<translation id="8324158725704657629">Ungabuzi futhi</translation>
<translation id="8372893542064058268">Vumela ukuvumelanisa kwangemuva kwesayithi elithile.</translation>
@@ -321,6 +334,7 @@
<translation id="8903921497873541725">Sondeza</translation>
<translation id="8921772741368021346"><ph name="POSITION" /> / <ph name="DURATION" /></translation>
<translation id="8926666909099850184">I-NFC ivaliwe kule divayisi. Ivule kokuthi <ph name="BEGIN_LINK" />Izilungiselelo ze-Android<ph name="END_LINK" />.</translation>
+<translation id="8928445016601307354">Vimba amasayithi ekuboneni nasekuguquleni ulwazi kumadivayisi e-NFC</translation>
<translation id="8941729603749328384">www.example.com</translation>
<translation id="8958424370300090006">Vimbela amakhukhi kusayithi elithile.</translation>
<translation id="8959122750345127698">Ukuzulazula akufinyeleleki: <ph name="URL" /></translation>
diff --git a/chromium/components/browser_ui/styles/android/BUILD.gn b/chromium/components/browser_ui/styles/android/BUILD.gn
index d204d8c4ec8..a3939c9b475 100644
--- a/chromium/components/browser_ui/styles/android/BUILD.gn
+++ b/chromium/components/browser_ui/styles/android/BUILD.gn
@@ -23,19 +23,35 @@ android_library("java") {
android_resources("java_resources") {
sources = [
+ "java/res/color-night/new_tab_button_pressed_tint.xml",
+ "java/res/color-night/new_tab_button_tint.xml",
+ "java/res/color-night/switch_thumb_tint.xml",
+ "java/res/color-night/switch_track_tint.xml",
+ "java/res/color/chip_text_color_secondary.xml",
"java/res/color/default_icon_color_accent1_tint_list.xml",
+ "java/res/color/default_icon_color_dark_tint_list.xml",
+ "java/res/color/default_icon_color_disabled.xml",
"java/res/color/default_icon_color_light_tint_list.xml",
"java/res/color/default_icon_color_secondary_light_tint_list.xml",
"java/res/color/default_icon_color_secondary_tint_list.xml",
"java/res/color/default_icon_color_tint_list.xml",
+ "java/res/color/default_icon_color_white_tint_list.xml",
+ "java/res/color/default_text_color_accent1_tint_list.xml",
"java/res/color/default_text_color_disabled_list.xml",
"java/res/color/default_text_color_hint_list.xml",
+ "java/res/color/default_text_color_link_tint_list.xml",
"java/res/color/default_text_color_list.xml",
+ "java/res/color/default_text_color_on_accent1_list.xml",
"java/res/color/default_text_color_secondary_list.xml",
+ "java/res/color/icon_animated_faded_color.xml",
+ "java/res/color/new_tab_button_pressed_tint.xml",
+ "java/res/color/new_tab_button_tint.xml",
"java/res/color/progress_bar_bg_color.xml",
"java/res/color/selection_control_button_tint.xml",
"java/res/color/switch_thumb_tint.xml",
+ "java/res/color/switch_thumb_tint_incognito.xml",
"java/res/color/switch_track_tint.xml",
+ "java/res/color/switch_track_tint_incognito.xml",
"java/res/color/text_highlight_color.xml",
"java/res/drawable-hdpi/btn_star_filled.png",
"java/res/drawable-hdpi/ic_chrome.png",
@@ -148,9 +164,11 @@ android_resources("java_resources") {
"java/res/drawable-xxxhdpi/top_round_shadow.9.png",
"java/res/drawable/checkmark_blue.xml",
"java/res/drawable/circle_white.xml",
+ "java/res/drawable/gm_ads_click_24.xml",
+ "java/res/drawable/gm_insert_chart_24.xml",
+ "java/res/drawable/ic_account_circle_24dp.xml",
"java/res/drawable/ic_add.xml",
"java/res/drawable/ic_bar_chart_24dp.xml",
- "java/res/drawable/ic_brightness_medium_20dp.xml",
"java/res/drawable/ic_brightness_medium_24dp.xml",
"java/res/drawable/ic_business.xml",
"java/res/drawable/ic_collections_grey.xml",
@@ -165,7 +183,7 @@ android_resources("java_resources") {
"java/res/drawable/ic_file_download_36dp.xml",
"java/res/drawable/ic_flash_on_24dp.xml",
"java/res/drawable/ic_folder_blue_24dp.xml",
- "java/res/drawable/ic_globe_24dp.xml",
+ "java/res/drawable/ic_google_24dp.xml",
"java/res/drawable/ic_help_and_feedback.xml",
"java/res/drawable/ic_info_outline_grey_16dp.xml",
"java/res/drawable/ic_info_outline_grey_24dp.xml",
@@ -181,6 +199,7 @@ android_resources("java_resources") {
"java/res/drawable/ic_remove.xml",
"java/res/drawable/ic_security_grey.xml",
"java/res/drawable/ic_settings_black.xml",
+ "java/res/drawable/ic_spam_reduction_24dp.xml",
"java/res/drawable/ic_tune_24dp.xml",
"java/res/drawable/ic_update_grey.xml",
"java/res/drawable/ic_videocam_24dp.xml",
@@ -191,10 +210,12 @@ android_resources("java_resources") {
"java/res/drawable/ic_vpn_key_grey.xml",
"java/res/drawable/ic_warning_red_16dp.xml",
"java/res/drawable/ic_warning_red_24dp.xml",
+ "java/res/drawable/ic_web_asset_24dp.xml",
"java/res/drawable/ic_zoom_in.xml",
"java/res/drawable/smartphone_black_24dp.xml",
"java/res/drawable/toolbar_hairline.xml",
"java/res/values-night/colors.xml",
+ "java/res/values-night/dimens.xml",
"java/res/values-night/drawables.xml",
"java/res/values-night/styles.xml",
"java/res/values-night/themes.xml",
diff --git a/chromium/components/browser_ui/util/android/url_constants.cc b/chromium/components/browser_ui/util/android/url_constants.cc
index 01a3dceeedb..cc4c62cdab5 100644
--- a/chromium/components/browser_ui/util/android/url_constants.cc
+++ b/chromium/components/browser_ui/util/android/url_constants.cc
@@ -4,8 +4,10 @@
#include "components/browser_ui/util/android/url_constants.h"
+#include "build/build_config.h"
+
namespace browser_ui {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
const char kChromeUINativeScheme[] = "chrome-native";
#endif
diff --git a/chromium/components/browser_ui/util/android/url_constants.h b/chromium/components/browser_ui/util/android/url_constants.h
index bd418c80bac..2d1b485db74 100644
--- a/chromium/components/browser_ui/util/android/url_constants.h
+++ b/chromium/components/browser_ui/util/android/url_constants.h
@@ -8,9 +8,9 @@
#include "build/build_config.h"
namespace browser_ui {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
extern const char kChromeUINativeScheme[];
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
} // namespace browser_ui
diff --git a/chromium/components/browser_ui/webshare/android/BUILD.gn b/chromium/components/browser_ui/webshare/android/BUILD.gn
index 86a332570a3..24424f041e6 100644
--- a/chromium/components/browser_ui/webshare/android/BUILD.gn
+++ b/chromium/components/browser_ui/webshare/android/BUILD.gn
@@ -16,6 +16,7 @@ android_library("java") {
"//content/public/android:content_java",
"//mojo/public/java:system_java",
"//mojo/public/java/system:system_impl_java",
+ "//mojo/public/mojom/base:base_java",
"//third_party/androidx:androidx_annotation_annotation_java",
"//third_party/blink/public/mojom:android_mojo_bindings_java",
"//ui/android:ui_java",
diff --git a/chromium/components/browser_ui/widget/android/BUILD.gn b/chromium/components/browser_ui/widget/android/BUILD.gn
index 4169af2435f..6912044f631 100644
--- a/chromium/components/browser_ui/widget/android/BUILD.gn
+++ b/chromium/components/browser_ui/widget/android/BUILD.gn
@@ -18,6 +18,7 @@ android_library("java") {
"java/src/org/chromium/components/browser_ui/widget/FadingShadow.java",
"java/src/org/chromium/components/browser_ui/widget/FadingShadowView.java",
"java/src/org/chromium/components/browser_ui/widget/InsetObserverView.java",
+ "java/src/org/chromium/components/browser_ui/widget/InsetObserverViewSupplier.java",
"java/src/org/chromium/components/browser_ui/widget/MaterialCardViewNoShadow.java",
"java/src/org/chromium/components/browser_ui/widget/MaterialProgressBar.java",
"java/src/org/chromium/components/browser_ui/widget/MenuOrKeyboardActionController.java",
@@ -47,6 +48,7 @@ android_library("java") {
"java/src/org/chromium/components/browser_ui/widget/async_image/ForegroundDrawableCompat.java",
"java/src/org/chromium/components/browser_ui/widget/async_image/ForegroundRoundedCornerImageView.java",
"java/src/org/chromium/components/browser_ui/widget/chips/ChipProperties.java",
+ "java/src/org/chromium/components/browser_ui/widget/chips/ChipView.java",
"java/src/org/chromium/components/browser_ui/widget/chips/ChipViewBinder.java",
"java/src/org/chromium/components/browser_ui/widget/chips/ChipsCoordinator.java",
"java/src/org/chromium/components/browser_ui/widget/displaystyle/DisplayStyleObserver.java",
@@ -97,6 +99,7 @@ android_library("java") {
"java/src/org/chromium/components/browser_ui/widget/selectable_list/SelectableItemViewHolder.java",
"java/src/org/chromium/components/browser_ui/widget/selectable_list/SelectableListLayout.java",
"java/src/org/chromium/components/browser_ui/widget/selectable_list/SelectableListToolbar.java",
+ "java/src/org/chromium/components/browser_ui/widget/selectable_list/SelectableListUtils.java",
"java/src/org/chromium/components/browser_ui/widget/selectable_list/SelectionDelegate.java",
"java/src/org/chromium/components/browser_ui/widget/text/AccessibleTextView.java",
"java/src/org/chromium/components/browser_ui/widget/text/AlertDialogEditText.java",
@@ -140,10 +143,20 @@ android_resources("java_resources") {
"java/res/anim/image_tile_enter.xml",
"java/res/anim/menu_enter.xml",
"java/res/anim/menu_enter_from_bottom.xml",
+ "java/res/anim/menu_enter_from_bottom_left.xml",
+ "java/res/anim/menu_enter_from_top_left.xml",
"java/res/anim/menu_exit.xml",
"java/res/anim/menu_exit_from_bottom.xml",
+ "java/res/anim/menu_exit_from_bottom_left.xml",
+ "java/res/anim/menu_exit_from_top_left.xml",
"java/res/anim/textbubble_in.xml",
"java/res/anim/textbubble_out.xml",
+ "java/res/color/chip_background_color.xml",
+ "java/res/color/chip_ripple_color.xml",
+ "java/res/color/chip_state_layer_color.xml",
+ "java/res/color/chip_stroke_color.xml",
+ "java/res/color/chip_text_color.xml",
+ "java/res/color/menu_chip_background.xml",
"java/res/drawable-hdpi/btn_delete_24dp.png",
"java/res/drawable-hdpi/btn_info.png",
"java/res/drawable-hdpi/ic_arrow_back_white_24dp.png",
@@ -158,7 +171,23 @@ android_resources("java_resources") {
"java/res/drawable-mdpi/ic_drag_handle_grey600_24dp.png",
"java/res/drawable-mdpi/ic_more_vert_24dp_on_dark_bg.png",
"java/res/drawable-mdpi/ic_more_vert_24dp_on_light_bg.png",
- "java/res/drawable-v24/tile_view_icon_background_modern.xml",
+ "java/res/drawable-v23/app_menu_bg.xml",
+ "java/res/drawable-v23/default_list_item_bg_rect.xml",
+ "java/res/drawable-v23/dialog_bg_no_shadow.xml",
+ "java/res/drawable-v23/modern_toolbar_text_box_background.xml",
+ "java/res/drawable-v23/oval_surface_1.xml",
+ "java/res/drawable-v23/rectangle_surface_1.xml",
+ "java/res/drawable-v23/rounded_rectangle_surface_1.xml",
+ "java/res/drawable-v23/sheet_background.xml",
+ "java/res/drawable-v31/app_menu_bg.xml",
+ "java/res/drawable-v31/default_list_item_bg_rect.xml",
+ "java/res/drawable-v31/dialog_bg_no_shadow.xml",
+ "java/res/drawable-v31/menu_bg_tinted.xml",
+ "java/res/drawable-v31/modern_toolbar_text_box_background.xml",
+ "java/res/drawable-v31/oval_surface_1.xml",
+ "java/res/drawable-v31/rectangle_surface_1.xml",
+ "java/res/drawable-v31/rounded_rectangle_surface_1.xml",
+ "java/res/drawable-v31/sheet_background.xml",
"java/res/drawable-xhdpi/btn_delete_24dp.png",
"java/res/drawable-xhdpi/btn_info.png",
"java/res/drawable-xhdpi/ic_arrow_back_white_24dp.png",
@@ -180,12 +209,10 @@ android_resources("java_resources") {
"java/res/drawable-xxxhdpi/ic_drag_handle_grey600_24dp.png",
"java/res/drawable-xxxhdpi/ic_more_vert_24dp_on_dark_bg.png",
"java/res/drawable-xxxhdpi/ic_more_vert_24dp_on_light_bg.png",
- "java/res/drawable/app_menu_bg.xml",
"java/res/drawable/async_image_view_unavailable.xml",
"java/res/drawable/async_image_view_waiting.xml",
"java/res/drawable/bottom_sheet_background.xml",
"java/res/drawable/card_with_corners_background.xml",
- "java/res/drawable/hairline_border_card_background.xml",
"java/res/drawable/ic_arrow_back_24dp.xml",
"java/res/drawable/ic_check_googblue_24dp_animated.xml",
"java/res/drawable/ic_offline_pin_blue_white.xml",
@@ -193,13 +220,11 @@ android_resources("java_resources") {
"java/res/drawable/incognito_card_bg.xml",
"java/res/drawable/list_item_icon_modern_bg.xml",
"java/res/drawable/list_item_icon_modern_bg_rect.xml",
- "java/res/drawable/modern_toolbar_text_box_background.xml",
"java/res/drawable/query_tile_overlay.xml",
"java/res/drawable/search_toolbar_modern_bg.xml",
"java/res/drawable/tile_view_highlight.xml",
"java/res/drawable/tile_view_highlight_mask.xml",
"java/res/drawable/tile_view_highlight_plain.xml",
- "java/res/drawable/tile_view_icon_background_modern.xml",
"java/res/layout/app_menu_divider.xml",
"java/res/layout/app_menu_layout.xml",
"java/res/layout/date_divided_adapter_header_view_holder.xml",
@@ -230,6 +255,8 @@ android_resources("java_resources") {
"java/res/layout/tile_view_modern.xml",
"java/res/layout/tile_view_modern_condensed.xml",
"java/res/values-ldrtl/values.xml",
+ "java/res/values-night/colors.xml",
+ "java/res/values-night/dimens.xml",
"java/res/values-night/drawables.xml",
"java/res/values-sw600dp/dimens.xml",
"java/res/values/attrs.xml",
@@ -238,6 +265,7 @@ android_resources("java_resources") {
"java/res/values/drawables.xml",
"java/res/values/ids.xml",
"java/res/values/styles.xml",
+ "java/res/values/themes.xml",
"java/res/values/values.xml",
]
deps = [
@@ -359,6 +387,7 @@ java_library("junit") {
"//base:base_junit_test_support",
"//base/test:test_support_java",
"//third_party/android_deps:robolectric_all_java",
+ "//third_party/androidx:androidx_annotation_annotation_java",
"//third_party/androidx:androidx_test_runner_java",
"//third_party/junit",
"//third_party/mockito:mockito_java",
diff --git a/chromium/components/browser_watcher/activity_report_extractor_unittest.cc b/chromium/components/browser_watcher/activity_report_extractor_unittest.cc
index b7998f62684..73bc7cc144c 100644
--- a/chromium/components/browser_watcher/activity_report_extractor_unittest.cc
+++ b/chromium/components/browser_watcher/activity_report_extractor_unittest.cc
@@ -15,6 +15,7 @@
#include "base/files/memory_mapped_file.h"
#include "base/files/scoped_temp_dir.h"
#include "base/metrics/persistent_memory_allocator.h"
+#include "base/threading/platform_thread.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -130,9 +131,9 @@ class StabilityReportExtractorThreadTrackerTest : public testing::Test {
ASSERT_EQ(1, process_state.threads_size());
const ThreadState& thread_state = process_state.threads(0);
EXPECT_EQ(base::PlatformThread::GetName(), thread_state.thread_name());
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
EXPECT_EQ(base::PlatformThread::CurrentId(), thread_state.thread_id());
-#elif defined(OS_POSIX)
+#elif BUILDFLAG(IS_POSIX)
EXPECT_EQ(base::PlatformThread::CurrentHandle().platform_handle(),
thread_state.thread_id());
#endif
diff --git a/chromium/components/browser_watcher/extended_crash_reporting.cc b/chromium/components/browser_watcher/extended_crash_reporting.cc
index b79ba4f231b..444eb5b1793 100644
--- a/chromium/components/browser_watcher/extended_crash_reporting.cc
+++ b/chromium/components/browser_watcher/extended_crash_reporting.cc
@@ -12,6 +12,7 @@
#include "base/memory/ptr_util.h"
#include "base/metrics/persistent_memory_allocator.h"
#include "base/strings/string_piece.h"
+#include "base/time/time.h"
#include "base/win/pe_image.h"
#include "build/build_config.h"
#include "components/browser_watcher/activity_data_names.h"
@@ -21,7 +22,7 @@
#include "components/browser_watcher/extended_crash_reporting_metrics.h"
#include "components/browser_watcher/features.h"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// https://devblogs.microsoft.com/oldnewthing/20041025-00/?p=37483.
extern "C" IMAGE_DOS_HEADER __ImageBase;
#endif
diff --git a/chromium/components/browser_watcher/extended_crash_reporting_win_unittest.cc b/chromium/components/browser_watcher/extended_crash_reporting_win_unittest.cc
index 5185376bbda..dbef03483b0 100644
--- a/chromium/components/browser_watcher/extended_crash_reporting_win_unittest.cc
+++ b/chromium/components/browser_watcher/extended_crash_reporting_win_unittest.cc
@@ -120,7 +120,7 @@ TEST_F(ExtendedCrashReportingTest, RecordsAnnotation) {
EXPECT_TRUE(IsNonEmpty(GetActivtyTrackerAnnotation()));
}
-#if defined(ADDRESS_SANITIZER) && defined(OS_WIN)
+#if defined(ADDRESS_SANITIZER) && BUILDFLAG(IS_WIN)
// The test does not pass under WinASan. See crbug.com/809524.
#define MAYBE_CrashingTest DISABLED_CrashingTest
#else
diff --git a/chromium/components/browsing_data/content/browsing_data_helper.cc b/chromium/components/browsing_data/content/browsing_data_helper.cc
index 02a0c71b1d4..94441a09e65 100644
--- a/chromium/components/browsing_data/content/browsing_data_helper.cc
+++ b/chromium/components/browsing_data/content/browsing_data_helper.cc
@@ -159,7 +159,7 @@ void RemoveSiteSettingsData(const base::Time& delete_begin,
ContentSettingsType::FEDERATED_IDENTITY_SHARING, delete_begin, delete_end,
HostContentSettingsMap::PatternSourcePredicate());
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
host_content_settings_map->ClearSettingsForOneTypeWithPredicate(
ContentSettingsType::SERIAL_CHOOSER_DATA, delete_begin, delete_end,
HostContentSettingsMap::PatternSourcePredicate());
diff --git a/chromium/components/browsing_data/content/canonical_cookie_hash.cc b/chromium/components/browsing_data/content/canonical_cookie_hash.cc
index fcaa43a6d27..c7c4c350db2 100644
--- a/chromium/components/browsing_data/content/canonical_cookie_hash.cc
+++ b/chromium/components/browsing_data/content/canonical_cookie_hash.cc
@@ -12,7 +12,11 @@ namespace canonical_cookie {
size_t FastHash(const net::CanonicalCookie& cookie) {
return base::PersistentHash(cookie.Name()) +
3 * base::PersistentHash(cookie.Domain()) +
- 7 * base::PersistentHash(cookie.Path());
+ 7 * base::PersistentHash(cookie.Path()) +
+ (cookie.IsPartitioned()
+ ? 13 * base::PersistentHash(
+ cookie.PartitionKey()->site().GetURL().host())
+ : 0);
}
bool CanonicalCookieComparer::operator()(
@@ -20,7 +24,8 @@ bool CanonicalCookieComparer::operator()(
const net::CanonicalCookie& cookie2) const {
return cookie1.Name() == cookie2.Name() &&
cookie1.Domain() == cookie2.Domain() &&
- cookie1.Path() == cookie2.Path();
+ cookie1.Path() == cookie2.Path() &&
+ cookie1.PartitionKey() == cookie2.PartitionKey();
}
} // namespace canonical_cookie
diff --git a/chromium/components/browsing_data/content/cookie_helper.cc b/chromium/components/browsing_data/content/cookie_helper.cc
index 3d3b9d8c4ff..7b0a528c22c 100644
--- a/chromium/components/browsing_data/content/cookie_helper.cc
+++ b/chromium/components/browsing_data/content/cookie_helper.cc
@@ -11,7 +11,6 @@
#include "base/callback_helpers.h"
#include "base/check_op.h"
#include "base/location.h"
-#include "base/no_destructor.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/cookie_access_details.h"
#include "content/public/browser/storage_partition.h"
diff --git a/chromium/components/browsing_data/content/cookie_helper_unittest.cc b/chromium/components/browsing_data/content/cookie_helper_unittest.cc
index 58d8a7328bc..25a8cb5f852 100644
--- a/chromium/components/browsing_data/content/cookie_helper_unittest.cc
+++ b/chromium/components/browsing_data/content/cookie_helper_unittest.cc
@@ -10,6 +10,7 @@
#include "base/run_loop.h"
#include "base/test/bind.h"
#include "base/time/time.h"
+#include "build/build_config.h"
#include "content/public/browser/cookie_access_details.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/test/browser_task_environment.h"
@@ -591,7 +592,13 @@ TEST_F(CookieHelperTest, CannedDifferentFrames) {
base::Unretained(this)));
}
-TEST_F(CookieHelperTest, CannedGetCookieCount) {
+#if BUILDFLAG(IS_LINUX) && defined(THREAD_SANITIZER)
+#define MAYBE_CannedGetCookieCount DISABLED_CannedGetCookieCount
+#else
+#define MAYBE_CannedGetCookieCount CannedGetCookieCount
+#endif
+// Flaky on Linux TSan: https://crbug.com/1285414.
+TEST_F(CookieHelperTest, MAYBE_CannedGetCookieCount) {
// The URL in the omnibox is a frame URL. This is not necessarily the request
// URL, since websites usually include other resources.
GURL frame1_url("http://www.google.com");
diff --git a/chromium/components/browsing_data/content/database_helper_browsertest.cc b/chromium/components/browsing_data/content/database_helper_browsertest.cc
index 6603bcf959e..4e3572f2b04 100644
--- a/chromium/components/browsing_data/content/database_helper_browsertest.cc
+++ b/chromium/components/browsing_data/content/database_helper_browsertest.cc
@@ -77,7 +77,8 @@ class DatabaseHelperTest : public content::ContentBrowserTest {
}
};
-IN_PROC_BROWSER_TEST_F(DatabaseHelperTest, FetchData) {
+// Flaky, see https://crbug.com/1293136
+IN_PROC_BROWSER_TEST_F(DatabaseHelperTest, DISABLED_FetchData) {
CreateDatabases();
auto database_helper = base::MakeRefCounted<DatabaseHelper>(
shell()->web_contents()->GetBrowserContext());
diff --git a/chromium/components/browsing_data/content/mock_cookie_helper.cc b/chromium/components/browsing_data/content/mock_cookie_helper.cc
index 59657cc2d6c..cbf97899f4f 100644
--- a/chromium/components/browsing_data/content/mock_cookie_helper.cc
+++ b/chromium/components/browsing_data/content/mock_cookie_helper.cc
@@ -29,26 +29,23 @@ void MockCookieHelper::StartFetching(FetchCallback callback) {
}
void MockCookieHelper::DeleteCookie(const net::CanonicalCookie& cookie) {
- std::string key = cookie.Name() + "=" + cookie.Value();
- ASSERT_TRUE(base::Contains(cookies_, key));
- cookies_[key] = false;
+ ASSERT_TRUE(base::Contains(cookies_, cookie));
+ cookies_[cookie] = false;
}
-void MockCookieHelper::AddCookieSamples(const GURL& url,
- const std::string& cookie_line) {
+void MockCookieHelper::AddCookieSamples(
+ const GURL& url,
+ const std::string& cookie_line,
+ absl::optional<net::CookiePartitionKey> cookie_partition_key) {
std::unique_ptr<net::CanonicalCookie> cc(net::CanonicalCookie::Create(
url, cookie_line, base::Time::Now(), absl::nullopt /* server_time */,
- absl::nullopt /* cookie_partition_key */));
+ cookie_partition_key));
if (cc.get()) {
- for (const auto& cookie : cookie_list_) {
- if (cookie.Name() == cc->Name() && cookie.Domain() == cc->Domain() &&
- cookie.Path() == cc->Path()) {
- return;
- }
- }
+ if (cookies_.count(*cc))
+ return;
cookie_list_.push_back(*cc);
- cookies_[cookie_line] = true;
+ cookies_[*cc] = true;
}
}
diff --git a/chromium/components/browsing_data/content/mock_cookie_helper.h b/chromium/components/browsing_data/content/mock_cookie_helper.h
index 6fcc9201c21..d334cfac507 100644
--- a/chromium/components/browsing_data/content/mock_cookie_helper.h
+++ b/chromium/components/browsing_data/content/mock_cookie_helper.h
@@ -5,9 +5,10 @@
#ifndef COMPONENTS_BROWSING_DATA_CONTENT_MOCK_COOKIE_HELPER_H_
#define COMPONENTS_BROWSING_DATA_CONTENT_MOCK_COOKIE_HELPER_H_
-#include <map>
#include <string>
+#include <unordered_map>
+#include "components/browsing_data/content/canonical_cookie_hash.h"
#include "components/browsing_data/content/cookie_helper.h"
#include "net/cookies/canonical_cookie.h"
@@ -30,7 +31,10 @@ class MockCookieHelper : public CookieHelper {
void DeleteCookie(const net::CanonicalCookie& cookie) override;
// Adds some cookie samples.
- void AddCookieSamples(const GURL& url, const std::string& cookie_line);
+ void AddCookieSamples(const GURL& url,
+ const std::string& cookie_line,
+ absl::optional<net::CookiePartitionKey>
+ cookie_partition_key = absl::nullopt);
// Notifies the callback.
void Notify();
@@ -50,7 +54,11 @@ class MockCookieHelper : public CookieHelper {
net::CookieList cookie_list_;
// Stores which cookies exist.
- std::map<const std::string, bool> cookies_;
+ std::unordered_map<net::CanonicalCookie,
+ bool,
+ canonical_cookie::CanonicalCookieHasher,
+ canonical_cookie::CanonicalCookieComparer>
+ cookies_;
};
} // namespace browsing_data
diff --git a/chromium/components/browsing_data/content/service_worker_helper_unittest.cc b/chromium/components/browsing_data/content/service_worker_helper_unittest.cc
index c325b5baa0f..e056b829d18 100644
--- a/chromium/components/browsing_data/content/service_worker_helper_unittest.cc
+++ b/chromium/components/browsing_data/content/service_worker_helper_unittest.cc
@@ -9,6 +9,7 @@
#include "base/memory/scoped_refptr.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "build/build_config.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/test/browser_task_environment.h"
@@ -30,7 +31,13 @@ class CannedServiceWorkerHelperTest : public testing::Test {
content::TestBrowserContext browser_context_;
};
-TEST_F(CannedServiceWorkerHelperTest, Empty) {
+#if BUILDFLAG(IS_LINUX) && defined(THREAD_SANITIZER)
+#define MAYBE_Empty DISABLED_Empty
+#else
+#define MAYBE_Empty Empty
+#endif
+// Flaky on Linux TSan: https://crbug.com/1285414
+TEST_F(CannedServiceWorkerHelperTest, MAYBE_Empty) {
const GURL origin("https://host1:1/");
std::vector<GURL> scopes;
scopes.push_back(GURL("https://host1:1/*"));
diff --git a/chromium/components/browsing_data/core/counters/history_counter.cc b/chromium/components/browsing_data/core/counters/history_counter.cc
index e482967e49c..9fd579dd667 100644
--- a/chromium/components/browsing_data/core/counters/history_counter.cc
+++ b/chromium/components/browsing_data/core/counters/history_counter.cc
@@ -154,7 +154,7 @@ void HistoryCounter::OnGetWebHistoryCount(
if (!result)
has_synced_visits_ = true;
else if (const base::Value* events = result->FindListKey("event"))
- has_synced_visits_ = !events->GetList().empty();
+ has_synced_visits_ = !events->GetListDeprecated().empty();
else
has_synced_visits_ = false;
web_counting_finished_ = true;
diff --git a/chromium/components/browsing_data/core/counters/passwords_counter.cc b/chromium/components/browsing_data/core/counters/passwords_counter.cc
index ea907ac0123..96764b89165 100644
--- a/chromium/components/browsing_data/core/counters/passwords_counter.cc
+++ b/chromium/components/browsing_data/core/counters/passwords_counter.cc
@@ -236,6 +236,10 @@ void PasswordsCounter::Count() {
base::BindOnce(&PasswordsCounter::OnFetchDone, base::Unretained(this)));
}
+void PasswordsCounter::OnPasswordsFetchDone() {
+ ReportResult(MakeResult());
+}
+
std::unique_ptr<PasswordsCounter::PasswordsResult>
PasswordsCounter::MakeResult() {
DCHECK(!(is_sync_active() && num_account_passwords() > 0));
@@ -246,7 +250,7 @@ PasswordsCounter::MakeResult() {
void PasswordsCounter::OnFetchDone() {
if (--remaining_tasks_ == 0)
- ReportResult(MakeResult());
+ OnPasswordsFetchDone();
}
} // namespace browsing_data
diff --git a/chromium/components/browsing_data/core/counters/passwords_counter.h b/chromium/components/browsing_data/core/counters/passwords_counter.h
index 254ac060301..88214e97fd7 100644
--- a/chromium/components/browsing_data/core/counters/passwords_counter.h
+++ b/chromium/components/browsing_data/core/counters/passwords_counter.h
@@ -63,8 +63,11 @@ class PasswordsCounter : public browsing_data::BrowsingDataCounter {
~PasswordsCounter() override;
const char* GetPrefName() const override;
+
protected:
+ virtual void OnPasswordsFetchDone();
virtual std::unique_ptr<PasswordsResult> MakeResult();
+ void Count() override;
bool is_sync_active() { return sync_tracker_.IsSyncActive(); }
int num_passwords();
@@ -76,8 +79,6 @@ class PasswordsCounter : public browsing_data::BrowsingDataCounter {
void OnInitialized() override;
void OnFetchDone();
- void Count() override;
-
base::CancelableTaskTracker cancelable_task_tracker_;
std::unique_ptr<PasswordStoreFetcher> profile_store_fetcher_;
std::unique_ptr<PasswordStoreFetcher> account_store_fetcher_;
diff --git a/chromium/components/browsing_data/core/features.cc b/chromium/components/browsing_data/core/features.cc
index 9440116d179..92e8b946aae 100644
--- a/chromium/components/browsing_data/core/features.cc
+++ b/chromium/components/browsing_data/core/features.cc
@@ -12,7 +12,7 @@ namespace features {
const base::Feature kEnableRemovingAllThirdPartyCookies{
"EnableRemovingAllThirdPartyCookies", base::FEATURE_DISABLED_BY_DEFAULT};
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
const base::Feature kEnableBrowsingDataLifetimeManager{
"BrowsingDataLifetimeManager", base::FEATURE_DISABLED_BY_DEFAULT};
#else
diff --git a/chromium/components/browsing_data/core/pref_names.cc b/chromium/components/browsing_data/core/pref_names.cc
index 5fc2a7b3d07..9ea1bb4d735 100644
--- a/chromium/components/browsing_data/core/pref_names.cc
+++ b/chromium/components/browsing_data/core/pref_names.cc
@@ -89,7 +89,7 @@ void RegisterBrowserUserPrefs(user_prefs::PrefRegistrySyncable* registry) {
registry->RegisterIntegerPref(
kClearBrowsingDataHistoryNoticeShownTimes, 0);
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
registry->RegisterBooleanPref(
kDeleteDownloadHistory, true,
user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
@@ -101,7 +101,7 @@ void RegisterBrowserUserPrefs(user_prefs::PrefRegistrySyncable* registry) {
user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
#else
registry->RegisterInt64Pref(prefs::kLastClearBrowsingDataTime, 0);
-#endif // !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_IOS)
registry->RegisterIntegerPref(kLastClearBrowsingDataTab, 0);
registry->RegisterBooleanPref(
diff --git a/chromium/components/captive_portal/content/captive_portal_service.cc b/chromium/components/captive_portal/content/captive_portal_service.cc
index ea9da895d19..52cb794bdf3 100644
--- a/chromium/components/captive_portal/content/captive_portal_service.cc
+++ b/chromium/components/captive_portal/content/captive_portal_service.cc
@@ -21,7 +21,7 @@
#include "content/public/browser/storage_partition.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include "base/win/windows_version.h"
#endif
diff --git a/chromium/components/cast/message_port/message_port_unittest.cc b/chromium/components/cast/message_port/message_port_unittest.cc
index 81efc2abc9d..1208f1cf983 100644
--- a/chromium/components/cast/message_port/message_port_unittest.cc
+++ b/chromium/components/cast/message_port/message_port_unittest.cc
@@ -17,9 +17,9 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/messaging/web_message_port.h"
-#if defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_FUCHSIA)
#include "components/cast/message_port/fuchsia/message_port_fuchsia.h"
-#endif // defined(OS_FUCHSIA)
+#endif // BUILDFLAG(IS_FUCHSIA)
#ifdef PostMessage
#undef PostMessage
@@ -122,7 +122,7 @@ TEST_F(MessagePortTest, WrapPlatformPort) {
// Initialize ports from the platform type instead of agnostic CreatePair
#if BUILDFLAG(USE_MESSAGE_PORT_CORE)
cast_api_bindings::CreateMessagePortCorePair(&client_, &server_);
-#elif defined(OS_FUCHSIA)
+#elif BUILDFLAG(IS_FUCHSIA)
fidl::InterfaceHandle<fuchsia::web::MessagePort> port0;
fidl::InterfaceRequest<fuchsia::web::MessagePort> port1 = port0.NewRequest();
client_ = MessagePortFuchsia::Create(std::move(port0));
@@ -131,7 +131,7 @@ TEST_F(MessagePortTest, WrapPlatformPort) {
auto pair = blink::WebMessagePort::CreatePair();
client_ = MessagePortCast::Create(std::move(pair.first));
server_ = MessagePortCast::Create(std::move(pair.second));
-#endif // defined(OS_FUCHSIA)
+#endif // BUILDFLAG(IS_FUCHSIA)
TestPostMessage();
}
@@ -146,7 +146,7 @@ TEST_F(MessagePortTest, UnwrapPlatformPort) {
cast_api_bindings::MessagePortCore::FromMessagePort(client_.release()));
server_.reset(
cast_api_bindings::MessagePortCore::FromMessagePort(server_.release()));
-#elif defined(OS_FUCHSIA)
+#elif BUILDFLAG(IS_FUCHSIA)
client_ = MessagePortFuchsia::Create(
MessagePortFuchsia::FromMessagePort(client_.get())->TakeClientHandle());
server_ = MessagePortFuchsia::Create(
@@ -156,7 +156,7 @@ TEST_F(MessagePortTest, UnwrapPlatformPort) {
MessagePortCast::FromMessagePort(client_.get())->TakePort());
server_ = MessagePortCast::Create(
MessagePortCast::FromMessagePort(server_.get())->TakePort());
-#endif // defined(OS_FUCHSIA)
+#endif // BUILDFLAG(IS_FUCHSIA)
TestPostMessage();
}
@@ -179,9 +179,9 @@ const MessagePortTestParam MessagePortTestParams[] = {
{MessagePortTestType::PLATFORM, &CreatePlatformMessagePortPair},
{MessagePortTestType::PLATFORM_TO_BLINK, &CreatePlatformToBlinkPair},
{MessagePortTestType::BLINK_TO_PLATFORM, &CreateBlinkToPlatformPair},
-#if defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_FUCHSIA)
{MessagePortTestType::FUCHSIA, &MessagePortFuchsia::CreatePair},
-#endif // defined(OS_FUCHSIA)
+#endif // BUILDFLAG(IS_FUCHSIA)
{MessagePortTestType::CORE, &CreateMessagePortCorePair},
{MessagePortTestType::CAST, &MessagePortCast::CreatePair}};
@@ -218,7 +218,7 @@ TEST_P(ParameterizedMessagePortTest, OnError) {
SetDefaultReceivers();
client_->PostMessage("");
-#if defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_FUCHSIA)
// blink::WebMessagePort reports failure when PostMessage returns false, but
// fuchsia::web::MessagePort will not report the error until the port closes
server_receiver_.RunUntilMessageCountEqual(1);
diff --git a/chromium/components/cast/message_port/platform_message_port.cc b/chromium/components/cast/message_port/platform_message_port.cc
index f48b4049b37..64fe0a1c664 100644
--- a/chromium/components/cast/message_port/platform_message_port.cc
+++ b/chromium/components/cast/message_port/platform_message_port.cc
@@ -9,7 +9,7 @@
#if BUILDFLAG(USE_MESSAGE_PORT_CORE)
#include "components/cast/message_port/cast_core/create_message_port_core.h" // nogncheck
-#elif defined(OS_FUCHSIA)
+#elif BUILDFLAG(IS_FUCHSIA)
#include "components/cast/message_port/fuchsia/message_port_fuchsia.h" // nogncheck
#else
#include "components/cast/message_port/cast/message_port_cast.h" // nogncheck
@@ -22,7 +22,7 @@ void CreatePlatformMessagePortPair(std::unique_ptr<MessagePort>* client,
std::unique_ptr<MessagePort>* server) {
#if BUILDFLAG(USE_MESSAGE_PORT_CORE)
return CreateMessagePortCorePair(client, server);
-#elif defined(OS_FUCHSIA)
+#elif BUILDFLAG(IS_FUCHSIA)
return MessagePortFuchsia::CreatePair(client, server);
#else
return MessagePortCast::CreatePair(client, server);
diff --git a/chromium/components/cast_certificate/cast_cert_reader.cc b/chromium/components/cast_certificate/cast_cert_reader.cc
index 5c94f52cb4a..7e879b84f24 100644
--- a/chromium/components/cast_certificate/cast_cert_reader.cc
+++ b/chromium/components/cast_certificate/cast_cert_reader.cc
@@ -5,7 +5,6 @@
#include "components/cast_certificate/cast_cert_reader.h"
#include "base/files/file_util.h"
#include "base/logging.h"
-#include "base/no_destructor.h"
#include "base/path_service.h"
#include "net/cert/internal/common_cert_errors.h"
#include "net/cert/pem.h"
diff --git a/chromium/components/cast_certificate/cast_cert_validator.cc b/chromium/components/cast_certificate/cast_cert_validator.cc
index a181ba6a0b6..467e4e2ca58 100644
--- a/chromium/components/cast_certificate/cast_cert_validator.cc
+++ b/chromium/components/cast_certificate/cast_cert_validator.cc
@@ -206,7 +206,7 @@ bool GetCommonNameFromSubject(const net::der::Input& subject_tlv,
for (const net::RelativeDistinguishedName& rdn : rdn_sequence) {
for (const auto& atv : rdn) {
- if (atv.type == net::TypeCommonNameOid()) {
+ if (atv.type == net::der::Input(net::kTypeCommonNameOid)) {
return atv.ValueAsString(common_name);
}
}
@@ -252,7 +252,7 @@ void DetermineDeviceCertificatePolicy(
// Checks properties on the target certificate.
//
// * The Key Usage must include Digital Signature
-WARN_UNUSED_RESULT bool CheckTargetCertificate(
+[[nodiscard]] bool CheckTargetCertificate(
const net::ParsedCertificate* cert,
std::unique_ptr<CertVerificationContext>* context) {
// Get the Key Usage extension.
@@ -370,7 +370,8 @@ CastCertError VerifyDeviceCertUsingCustomTrustStore(
net::CertPathBuilder path_builder(
target_cert.get(), trust_store, &path_builder_delegate, verification_time,
net::KeyPurpose::CLIENT_AUTH, net::InitialExplicitPolicy::kFalse,
- {net::AnyPolicy()}, net::InitialPolicyMappingInhibit::kFalse,
+ {net::der::Input(net::kAnyPolicyOid)},
+ net::InitialPolicyMappingInhibit::kFalse,
net::InitialAnyPolicyInhibit::kFalse);
path_builder.AddCertIssuerSource(&intermediate_cert_issuer_source);
net::CertPathBuilder::Result result = path_builder.Run();
diff --git a/chromium/components/cast_certificate/cast_cert_validator.h b/chromium/components/cast_certificate/cast_cert_validator.h
index eafc5264f71..161e7bae5ce 100644
--- a/chromium/components/cast_certificate/cast_cert_validator.h
+++ b/chromium/components/cast_certificate/cast_cert_validator.h
@@ -9,7 +9,6 @@
#include <string>
#include <vector>
-#include "base/compiler_specific.h"
#include "base/strings/string_piece.h"
#include "base/time/time.h"
@@ -117,27 +116,27 @@ class CertVerificationContext {
// properties from the device certificate (Common Name).
// * |policy| is filled with an indication of the device certificate's policy
// (i.e. is it for audio-only devices or is it unrestricted?)
-CastCertError VerifyDeviceCert(
+[[nodiscard]] CastCertError VerifyDeviceCert(
const std::vector<std::string>& certs,
const base::Time& time,
std::unique_ptr<CertVerificationContext>* context,
CastDeviceCertPolicy* policy,
const CastCRL* crl,
- CRLPolicy crl_policy) WARN_UNUSED_RESULT;
+ CRLPolicy crl_policy);
// This is an overloaded version of VerifyDeviceCert that allows
// the input of a custom TrustStore.
//
// For production use pass |trust_store| as nullptr to use the production trust
// store.
-CastCertError VerifyDeviceCertUsingCustomTrustStore(
+[[nodiscard]] CastCertError VerifyDeviceCertUsingCustomTrustStore(
const std::vector<std::string>& certs,
const base::Time& time,
std::unique_ptr<CertVerificationContext>* context,
CastDeviceCertPolicy* policy,
const CastCRL* crl,
CRLPolicy crl_policy,
- net::TrustStore* trust_store) WARN_UNUSED_RESULT;
+ net::TrustStore* trust_store);
// Exposed only for unit-tests, not for use in production code.
// Production code would get a context from VerifyDeviceCert().
diff --git a/chromium/components/cast_certificate/cast_crl.cc b/chromium/components/cast_certificate/cast_crl.cc
index 2afd48e0a47..a6a20714569 100644
--- a/chromium/components/cast_certificate/cast_crl.cc
+++ b/chromium/components/cast_certificate/cast_crl.cc
@@ -164,7 +164,8 @@ bool VerifyCRL(const Crl& crl,
net::CertPathBuilder path_builder(
parsed_cert.get(), trust_store, &path_builder_delegate, verification_time,
net::KeyPurpose::ANY_EKU, net::InitialExplicitPolicy::kFalse,
- {net::AnyPolicy()}, net::InitialPolicyMappingInhibit::kFalse,
+ {net::der::Input(net::kAnyPolicyOid)},
+ net::InitialPolicyMappingInhibit::kFalse,
net::InitialAnyPolicyInhibit::kFalse);
net::CertPathBuilder::Result result = path_builder.Run();
if (!result.HasValidPath()) {
diff --git a/chromium/components/cast_channel/BUILD.gn b/chromium/components/cast_channel/BUILD.gn
index 982de974d56..f792016abd6 100644
--- a/chromium/components/cast_channel/BUILD.gn
+++ b/chromium/components/cast_channel/BUILD.gn
@@ -192,7 +192,7 @@ fuzzer_test("cast_auth_util_fuzzer") {
seed_corpus_deps = [ ":cast_auth_util_fuzzer_convert_corpus" ]
}
-# TODO(jrw): Rename target to cast_framer_ingest_fuzzer. The name
+# TODO(crbug.com/1291729): Rename target to cast_framer_ingest_fuzzer. The name
# is left unchanged for now to avoid the need to get reviews for
# various files that include it.
fuzzer_test("cast_message_fuzzer") {
diff --git a/chromium/components/cast_channel/cast_channel_enum.cc b/chromium/components/cast_channel/cast_channel_enum.cc
index e499d0e9878..f9a5c7d69de 100644
--- a/chromium/components/cast_channel/cast_channel_enum.cc
+++ b/chromium/components/cast_channel/cast_channel_enum.cc
@@ -14,7 +14,7 @@ namespace cast_channel {
case enum: \
return #enum
-// TODO(jrw): Replace with EnumTable.
+// TODO(crbug.com/1291730): Replace with EnumTable.
std::string ReadyStateToString(ReadyState ready_state) {
switch (ready_state) {
CAST_CHANNEL_TYPE_TO_STRING(ReadyState::NONE);
@@ -27,7 +27,7 @@ std::string ReadyStateToString(ReadyState ready_state) {
return "Unknown ready_state";
}
-// TODO(jrw): Replace with EnumTable.
+// TODO(crbug.com/1291730): Replace with EnumTable.
std::string ChannelErrorToString(ChannelError channel_error) {
switch (channel_error) {
CAST_CHANNEL_TYPE_TO_STRING(ChannelError::NONE);
diff --git a/chromium/components/cast_channel/cast_message_handler.cc b/chromium/components/cast_channel/cast_message_handler.cc
index 16e8262fee0..c3366fdecc9 100644
--- a/chromium/components/cast_channel/cast_message_handler.cc
+++ b/chromium/components/cast_channel/cast_message_handler.cc
@@ -352,10 +352,10 @@ void CastMessageHandler::OnError(const CastSocket& socket,
void CastMessageHandler::OnMessage(const CastSocket& socket,
const CastMessage& message) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- // TODO(jrw): Splitting internal messages into a separate code path with a
- // separate data type is pretty questionable, because it causes duplicated
- // code paths in the downstream logic (manifested as separate OnAppMessage and
- // OnInternalMessage methods).
+ // TODO(crbug.com/1291736): Splitting internal messages into a separate code
+ // path with a separate data type is pretty questionable, because it causes
+ // duplicated code paths in the downstream logic (manifested as separate
+ // OnAppMessage and OnInternalMessage methods).
if (IsCastReservedNamespace(message.namespace_())) {
if (message.payload_type() ==
cast::channel::CastMessage_PayloadType_STRING) {
diff --git a/chromium/components/cast_channel/cast_message_handler.h b/chromium/components/cast_channel/cast_message_handler.h
index c468a7d0ce0..435f61db8f8 100644
--- a/chromium/components/cast_channel/cast_message_handler.h
+++ b/chromium/components/cast_channel/cast_message_handler.h
@@ -104,7 +104,7 @@ struct InternalMessage {
~InternalMessage();
CastMessageType type;
- // TODO(jrw): This field is only needed to communicate the namespace
+ // This field is only needed to communicate the namespace
// information from CastMessageHandler::OnMessage to
// MirroringActivityRecord::OnInternalMessage. Maybe there's a better way?
// One possibility is to derive namespace when it's needed based on the
@@ -204,7 +204,8 @@ class CastMessageHandler : public CastSocket::Observer {
// Sends |message| to the device given by |channel_id|. The caller may use
// this method to forward app messages from the SDK client to the device.
//
- // TODO(jrw): Could this be merged with SendAppMessage()? Note from mfoltz:
+ // TODO(crbug.com/1291734): Could this be merged with SendAppMessage()? Note
+ // from mfoltz:
//
// The two differences between an app message and a protocol message:
// - app message has a sender ID that comes from the clientId of the SDK
diff --git a/chromium/components/cast_channel/cast_message_handler_unittest.cc b/chromium/components/cast_channel/cast_message_handler_unittest.cc
index 982825f488d..9e440db45f5 100644
--- a/chromium/components/cast_channel/cast_message_handler_unittest.cc
+++ b/chromium/components/cast_channel/cast_message_handler_unittest.cc
@@ -105,7 +105,7 @@ class CastMessageHandlerTest : public testing::Test {
kTestUserAgentString,
"66.0.3331.0",
"en-US") {
- ON_CALL(cast_socket_service_, GetSocket(_))
+ ON_CALL(cast_socket_service_, GetSocket(testing::Matcher<int>(_)))
.WillByDefault(testing::Return(&cast_socket_));
}
diff --git a/chromium/components/cast_channel/cast_message_util.cc b/chromium/components/cast_channel/cast_message_util.cc
index 8959ba07d56..77c708b74ee 100644
--- a/chromium/components/cast_channel/cast_message_util.cc
+++ b/chromium/components/cast_channel/cast_message_util.cc
@@ -162,13 +162,13 @@ CastMessage CreateKeepAliveMessage(base::StringPiece keep_alive_type) {
// request. The value is platform-dependent and is taken from the Platform enum
// defined in third_party/metrics_proto/cast_logs.proto.
int GetVirtualConnectPlatformValue() {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
return 3;
-#elif defined(OS_APPLE)
+#elif BUILDFLAG(IS_APPLE)
return 4;
#elif BUILDFLAG(IS_CHROMEOS_ASH)
return 5;
-#elif defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
+#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
return 6;
#else
return 0;
@@ -272,29 +272,28 @@ CastMessageType ParseMessageTypeFromPayload(const base::Value& payload) {
: CastMessageType::kOther;
}
-// TODO(jrw): Eliminate this function.
+// TODO(crbug.com/1291730): Eliminate this function.
const char* ToString(CastMessageType message_type) {
return EnumToString(message_type).value_or("").data();
}
-// TODO(jrw): Eliminate this function.
+// TODO(crbug.com/1291730): Eliminate this function.
const char* ToString(V2MessageType message_type) {
return EnumToString(message_type).value_or("").data();
}
-// TODO(jrw): Eliminate this function.
+// TODO(crbug.com/1291730): Eliminate this function.
CastMessageType CastMessageTypeFromString(const std::string& type) {
auto result = StringToEnum<CastMessageType>(type);
DVLOG_IF(1, !result) << "Unknown message type: " << type;
return result.value_or(CastMessageType::kOther);
}
-// TODO(jrw): Eliminate this function.
+// TODO(crbug.com/1291730): Eliminate this function.
V2MessageType V2MessageTypeFromString(const std::string& type) {
return StringToEnum<V2MessageType>(type).value_or(V2MessageType::kOther);
}
-// TODO(jrw): Convert to operator<<
std::string AuthMessageToString(const DeviceAuthMessage& message) {
std::string out("{");
if (message.has_challenge()) {
@@ -580,7 +579,7 @@ bool IsMediaRequestMessageType(V2MessageType type) {
}
}
-// TODO(jrw): Eliminate this function.
+// TODO(crbug.com/1291730): Eliminate this function.
const char* ToString(GetAppAvailabilityResult result) {
return EnumToString(result).value_or("").data();
}
diff --git a/chromium/components/cast_channel/cast_message_util.h b/chromium/components/cast_channel/cast_message_util.h
index f9b9d814b69..79a5a2239e9 100644
--- a/chromium/components/cast_channel/cast_message_util.h
+++ b/chromium/components/cast_channel/cast_message_util.h
@@ -181,7 +181,8 @@ CastMessageType CastMessageTypeFromString(const std::string& type);
// correspond to a known type.
V2MessageType V2MessageTypeFromString(const std::string& type);
-// Returns a human readable string for |message|.
+// Returns a human readable string for |message|. Should probably be converted
+// to operator<<.
std::string AuthMessageToString(const DeviceAuthMessage& message);
// Fills |message_proto| appropriately for an auth challenge request message.
diff --git a/chromium/components/cast_channel/cast_socket_service.cc b/chromium/components/cast_channel/cast_socket_service.cc
index d9322ff3845..0ac8f4f9073 100644
--- a/chromium/components/cast_channel/cast_socket_service.cc
+++ b/chromium/components/cast_channel/cast_socket_service.cc
@@ -71,6 +71,15 @@ std::unique_ptr<CastSocket> CastSocketServiceImpl::RemoveSocket(
return socket;
}
+void CastSocketService::CloseSocket(int channel_id) {
+ DCHECK(task_runner_->BelongsToCurrentThread());
+ auto* socket = GetSocket(channel_id);
+ if (socket) {
+ socket->Close(base::BindOnce([](int x) {}));
+ RemoveSocket(socket->id());
+ }
+}
+
CastSocket* CastSocketServiceImpl::GetSocket(int channel_id) const {
DCHECK(task_runner_->BelongsToCurrentThread());
DCHECK(channel_id > 0);
diff --git a/chromium/components/cast_channel/cast_socket_service.h b/chromium/components/cast_channel/cast_socket_service.h
index 9243e517922..1627c4d7599 100644
--- a/chromium/components/cast_channel/cast_socket_service.h
+++ b/chromium/components/cast_channel/cast_socket_service.h
@@ -30,6 +30,10 @@ class CastSocketService {
// CastSocketRegistry. Returns nullptr if no such CastSocket exists.
virtual std::unique_ptr<CastSocket> RemoveSocket(int channel_id) = 0;
+ // Attempts to close an open CastSocket connection corresponding to the given
+ // |ip_endpoint|. Does nothing if the socket_id doesn't exist.
+ virtual void CloseSocket(int channel_id);
+
// Returns the socket corresponding to |channel_id| if one exists, or nullptr
// otherwise.
virtual CastSocket* GetSocket(int channel_id) const = 0;
diff --git a/chromium/components/cast_channel/cast_socket_unittest.cc b/chromium/components/cast_channel/cast_socket_unittest.cc
index 7f521265d2d..05068a8e8d2 100644
--- a/chromium/components/cast_channel/cast_socket_unittest.cc
+++ b/chromium/components/cast_channel/cast_socket_unittest.cc
@@ -49,6 +49,8 @@
#include "net/test/cert_test_util.h"
#include "net/test/test_data_directory.h"
#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
+#include "net/url_request/url_request_context.h"
+#include "net/url_request/url_request_context_builder.h"
#include "net/url_request/url_request_test_util.h"
#include "services/network/network_context.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -349,20 +351,6 @@ class TestSocketFactory : public net::ClientSocketFactory {
std::move(nested_socket), net::HostPortPair(), net::SSLConfig(),
ssl_socket_data_provider_.get());
}
- std::unique_ptr<net::ProxyClientSocket> CreateProxyClientSocket(
- std::unique_ptr<net::StreamSocket> stream_socket,
- const std::string& user_agent,
- const net::HostPortPair& endpoint,
- const net::ProxyServer& proxy_server,
- net::HttpAuthController* http_auth_controller,
- bool tunnel,
- bool using_spdy,
- net::NextProto negotiated_protocol,
- net::ProxyDelegate* proxy_delegate,
- const net::NetworkTrafficAnnotationTag& traffic_annotation) override {
- NOTIMPLEMENTED();
- return nullptr;
- }
net::IPEndPoint ip_;
// Simulated connect data
@@ -384,7 +372,6 @@ class CastSocketTestBase : public testing::Test {
protected:
CastSocketTestBase()
: task_environment_(content::BrowserTaskEnvironment::IO_MAINLOOP),
- url_request_context_(true),
logger_(new Logger()),
observer_(new MockCastSocketObserver()),
socket_open_params_(CreateIPEndPointForTest(),
@@ -399,11 +386,13 @@ class CastSocketTestBase : public testing::Test {
void SetUp() override {
EXPECT_CALL(*observer_, OnMessage(_, _)).Times(0);
- url_request_context_.set_client_socket_factory(&client_socket_factory_);
- url_request_context_.Init();
+ auto context_builder = net::CreateTestURLRequestContextBuilder();
+ context_builder->set_client_socket_factory_for_testing(
+ &client_socket_factory_);
+ url_request_context_ = context_builder->Build();
network_context_ = std::make_unique<network::NetworkContext>(
nullptr, network_context_remote_.BindNewPipeAndPassReceiver(),
- &url_request_context_,
+ url_request_context_.get(),
/*cors_exempt_header_list=*/std::vector<std::string>());
}
@@ -416,7 +405,7 @@ class CastSocketTestBase : public testing::Test {
TestSocketFactory* client_socket_factory() { return &client_socket_factory_; }
content::BrowserTaskEnvironment task_environment_;
- net::TestURLRequestContext url_request_context_;
+ std::unique_ptr<net::URLRequestContext> url_request_context_;
std::unique_ptr<network::NetworkContext> network_context_;
mojo::Remote<network::mojom::NetworkContext> network_context_remote_;
raw_ptr<Logger> logger_;
@@ -1066,7 +1055,7 @@ TEST_F(MockCastSocketTest, TestOpenChannelClosedSocket) {
}
// https://crbug.com/874491, flaky on Win and Mac
-#if defined(OS_WIN) || defined(OS_APPLE)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE)
#define MAYBE_TestConnectEndToEndWithRealSSL \
DISABLED_TestConnectEndToEndWithRealSSL
#else
diff --git a/chromium/components/cast_channel/cast_test_util.h b/chromium/components/cast_channel/cast_test_util.h
index bcf75d26d40..95fa59e45f6 100644
--- a/chromium/components/cast_channel/cast_test_util.h
+++ b/chromium/components/cast_channel/cast_test_util.h
@@ -99,6 +99,12 @@ class MockCastSocketService : public CastSocketServiceImpl {
void(const net::IPEndPoint& ip_endpoint,
CastSocket::OnOpenCallback& open_cb));
MOCK_CONST_METHOD1(GetSocket, CastSocket*(int channel_id));
+ MOCK_METHOD(CastSocket*,
+ GetSocket,
+ (const net::IPEndPoint& ip_endpoint),
+ (override, const));
+ MOCK_METHOD(std::unique_ptr<CastSocket>, RemoveSocket, (int channel_id), ());
+ MOCK_METHOD(void, CloseSocket, (int channel_id), (override));
};
class MockCastSocket : public CastSocket {
diff --git a/chromium/components/cast_channel/enum_table.h b/chromium/components/cast_channel/enum_table.h
index 842553a317e..e87ffb19580 100644
--- a/chromium/components/cast_channel/enum_table.h
+++ b/chromium/components/cast_channel/enum_table.h
@@ -15,7 +15,7 @@
#include "build/build_config.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
-// TODO(jrw): Move this file to a more appropriate directory.
+// TODO(crbug.com/1291730): Move this file to a more appropriate directory.
//
//
// A bidirectional mapping between enum values and strings.
@@ -413,8 +413,8 @@ inline absl::optional<base::StringPiece> EnumToString(E value) {
// Converts a literal enum value to a string at compile time using the default
// table (EnumTable<E>::GetInstance()) for the given enum type.
//
-// TODO(jrw): Once C++17 features are allowed, change this function to have only
-// one template parameter:
+// TODO(crbug.com/1291730): Once C++17 features are allowed, change this
+// function to have only one template parameter:
//
// template <auto Value>
// inline base::StringPiece EnumToString() {
diff --git a/chromium/components/cast_streaming/browser/cast_message_port_impl_unittest.cc b/chromium/components/cast_streaming/browser/cast_message_port_impl_unittest.cc
index b71d4159508..2d5d7d24a4c 100644
--- a/chromium/components/cast_streaming/browser/cast_message_port_impl_unittest.cc
+++ b/chromium/components/cast_streaming/browser/cast_message_port_impl_unittest.cc
@@ -247,7 +247,7 @@ TEST_F(CastMessagePortImplTest, MediaStatus) {
const base::Value* status_value = return_value->FindListKey(kKeyStatus);
ASSERT_TRUE(status_value);
- EXPECT_EQ(status_value->GetList().size(), 1u);
+ EXPECT_EQ(status_value->GetListDeprecated().size(), 1u);
}
// Checks sending invalid media messages results in no response.
diff --git a/chromium/components/cast_streaming/browser/public/receiver_session.h b/chromium/components/cast_streaming/browser/public/receiver_session.h
index 80a8b3cc9c7..bda57c97ebd 100644
--- a/chromium/components/cast_streaming/browser/public/receiver_session.h
+++ b/chromium/components/cast_streaming/browser/public/receiver_session.h
@@ -16,6 +16,11 @@ namespace cast_api_bindings {
class MessagePort;
}
+namespace media {
+class AudioDecoderConfig;
+class VideoDecoderConfig;
+} // namespace media
+
namespace cast_streaming {
// This interface handles a single Cast Streaming Receiver Session over a given
@@ -26,6 +31,18 @@ namespace cast_streaming {
// requiring the import above.
class ReceiverSession {
public:
+ class Client {
+ public:
+ virtual ~Client() = default;
+
+ // Called when the associated config is set or updated by the remote sender
+ // device.
+ virtual void OnAudioConfigUpdated(
+ const media::AudioDecoderConfig& audio_config) = 0;
+ virtual void OnVideoConfigUpdated(
+ const media::VideoDecoderConfig& video_config) = 0;
+ };
+
using MessagePortProvider =
base::OnceCallback<std::unique_ptr<cast_api_bindings::MessagePort>()>;
using AVConstraints = openscreen::cast::ReceiverSession::Preferences;
@@ -41,7 +58,8 @@ class ReceiverSession {
// ReceiverSession::Preferences object from //media types.
static std::unique_ptr<ReceiverSession> Create(
std::unique_ptr<AVConstraints> av_constraints,
- MessagePortProvider message_port_provider);
+ MessagePortProvider message_port_provider,
+ Client* client = nullptr);
// Sets up the CastStreamingReceiver mojo remote. This will immediately call
// CastStreamingReceiver::EnableReceiver(). Upon receiving the callback for
diff --git a/chromium/components/cast_streaming/browser/receiver_session_impl.cc b/chromium/components/cast_streaming/browser/receiver_session_impl.cc
index 9210936c62e..bc7f61ade5e 100644
--- a/chromium/components/cast_streaming/browser/receiver_session_impl.cc
+++ b/chromium/components/cast_streaming/browser/receiver_session_impl.cc
@@ -15,16 +15,19 @@ namespace cast_streaming {
// static
std::unique_ptr<ReceiverSession> ReceiverSession::Create(
std::unique_ptr<ReceiverSession::AVConstraints> av_constraints,
- ReceiverSession::MessagePortProvider message_port_provider) {
+ ReceiverSession::MessagePortProvider message_port_provider,
+ ReceiverSession::Client* client) {
return std::make_unique<ReceiverSessionImpl>(
- std::move(av_constraints), std::move(message_port_provider));
+ std::move(av_constraints), std::move(message_port_provider), client);
}
ReceiverSessionImpl::ReceiverSessionImpl(
std::unique_ptr<ReceiverSession::AVConstraints> av_constraints,
- ReceiverSession::MessagePortProvider message_port_provider)
+ ReceiverSession::MessagePortProvider message_port_provider,
+ ReceiverSession::Client* client)
: message_port_provider_(std::move(message_port_provider)),
- av_constraints_(std::move(av_constraints)) {
+ av_constraints_(std::move(av_constraints)),
+ client_(client) {
// TODO(crbug.com/1218495): Validate the provided codecs against build flags.
DCHECK(av_constraints_);
DCHECK(message_port_provider_);
@@ -83,6 +86,15 @@ void ReceiverSessionImpl::OnSessionInitialization(
cast_streaming_receiver_->OnStreamsInitialized(
std::move(mojo_audio_stream_info), std::move(mojo_video_stream_info));
+
+ if (client_) {
+ if (audio_stream_info) {
+ client_->OnAudioConfigUpdated(audio_stream_info->decoder_config);
+ }
+ if (video_stream_info) {
+ client_->OnVideoConfigUpdated(video_stream_info->decoder_config);
+ }
+ }
}
void ReceiverSessionImpl::OnAudioBufferReceived(
@@ -116,6 +128,15 @@ void ReceiverSessionImpl::OnSessionReinitialization(
video_remote_->OnNewVideoConfig(video_stream_info->decoder_config,
std::move(video_stream_info->data_pipe));
}
+
+ if (client_) {
+ if (audio_stream_info) {
+ client_->OnAudioConfigUpdated(audio_stream_info->decoder_config);
+ }
+ if (video_stream_info) {
+ client_->OnVideoConfigUpdated(video_stream_info->decoder_config);
+ }
+ }
}
void ReceiverSessionImpl::OnSessionEnded() {
diff --git a/chromium/components/cast_streaming/browser/receiver_session_impl.h b/chromium/components/cast_streaming/browser/receiver_session_impl.h
index 9233f149764..76b5682287f 100644
--- a/chromium/components/cast_streaming/browser/receiver_session_impl.h
+++ b/chromium/components/cast_streaming/browser/receiver_session_impl.h
@@ -24,7 +24,8 @@ class ReceiverSessionImpl final
// surrounding this support.
ReceiverSessionImpl(
std::unique_ptr<ReceiverSession::AVConstraints> av_constraints,
- MessagePortProvider message_port_provider);
+ MessagePortProvider message_port_provider,
+ ReceiverSession::Client* client);
~ReceiverSessionImpl() override;
ReceiverSessionImpl(const ReceiverSessionImpl&) = delete;
@@ -67,6 +68,8 @@ class ReceiverSessionImpl final
mojo::Remote<mojom::CastStreamingBufferReceiver> audio_remote_;
mojo::Remote<mojom::CastStreamingBufferReceiver> video_remote_;
+
+ ReceiverSession::Client* const client_;
};
} // namespace cast_streaming
diff --git a/chromium/components/cast_streaming/browser/rpc_call_translator.cc b/chromium/components/cast_streaming/browser/rpc_call_translator.cc
index 7a2338a5fd3..d6ef3f9c0e1 100644
--- a/chromium/components/cast_streaming/browser/rpc_call_translator.cc
+++ b/chromium/components/cast_streaming/browser/rpc_call_translator.cc
@@ -60,7 +60,7 @@ void RpcCallTranslator::OnBufferingStateChange(
message_processor_.Run(CreateMessageForBufferingStateChange(state));
}
-void RpcCallTranslator::OnError(const media::Status& status) {
+void RpcCallTranslator::OnError(const media::PipelineStatus& status) {
message_processor_.Run(CreateMessageForError());
}
diff --git a/chromium/components/cast_streaming/browser/rpc_call_translator.h b/chromium/components/cast_streaming/browser/rpc_call_translator.h
index d019ef786e3..04bd33d5f70 100644
--- a/chromium/components/cast_streaming/browser/rpc_call_translator.h
+++ b/chromium/components/cast_streaming/browser/rpc_call_translator.h
@@ -53,7 +53,7 @@ class RpcCallTranslator : public media::mojom::RendererClient,
media::BufferingState state,
media::BufferingStateChangeReason reason) override;
void OnEnded() override;
- void OnError(const media::Status& status) override;
+ void OnError(const media::PipelineStatus& status) override;
void OnAudioConfigChange(const media::AudioDecoderConfig& config) override;
void OnVideoConfigChange(const media::VideoDecoderConfig& config) override;
void OnVideoNaturalSizeChange(const gfx::Size& size) override;
diff --git a/chromium/components/cast_streaming/renderer/cast_streaming_demuxer.cc b/chromium/components/cast_streaming/renderer/cast_streaming_demuxer.cc
index 7815e9ace4b..a549c310299 100644
--- a/chromium/components/cast_streaming/renderer/cast_streaming_demuxer.cc
+++ b/chromium/components/cast_streaming/renderer/cast_streaming_demuxer.cc
@@ -297,8 +297,7 @@ void CastStreamingDemuxer::OnStreamsInitializedOnMediaThread(
DCHECK(initialized_cb_);
if (!audio_stream_info && !video_stream_info) {
- std::move(initialized_cb_)
- .Run(media::PipelineStatus::DEMUXER_ERROR_COULD_NOT_OPEN);
+ std::move(initialized_cb_).Run(media::DEMUXER_ERROR_COULD_NOT_OPEN);
return;
}
@@ -312,7 +311,7 @@ void CastStreamingDemuxer::OnStreamsInitializedOnMediaThread(
}
was_initialization_successful_ = true;
- std::move(initialized_cb_).Run(media::PipelineStatus::PIPELINE_OK);
+ std::move(initialized_cb_).Run(media::PIPELINE_OK);
}
std::vector<media::DemuxerStream*> CastStreamingDemuxer::GetAllStreams() {
@@ -366,7 +365,7 @@ void CastStreamingDemuxer::CancelPendingSeek(base::TimeDelta seek_time) {}
// Not supported.
void CastStreamingDemuxer::Seek(base::TimeDelta time,
media::PipelineStatusCallback status_cb) {
- std::move(status_cb).Run(media::PipelineStatus::PIPELINE_OK);
+ std::move(status_cb).Run(media::PIPELINE_OK);
}
void CastStreamingDemuxer::Stop() {
diff --git a/chromium/components/cast_streaming/renderer/playback_command_forwarding_renderer.cc b/chromium/components/cast_streaming/renderer/playback_command_forwarding_renderer.cc
index b03dc533b6a..dc2fa0fad51 100644
--- a/chromium/components/cast_streaming/renderer/playback_command_forwarding_renderer.cc
+++ b/chromium/components/cast_streaming/renderer/playback_command_forwarding_renderer.cc
@@ -7,6 +7,70 @@
#include "base/notreached.h"
namespace cast_streaming {
+namespace {
+
+constexpr base::TimeDelta kTimeUpdateInterval = base::Milliseconds(250);
+
+} // namespace
+
+// Class responsible for receiving Renderer commands from a remote source and
+// forwarding them to |owning_renderer| unchanged. This class exists only to
+// avoid intersection of media::Renderer and media::mojom::Renderer methods in
+// PlaybackCommandForwardingRenderer.
+//
+// NOTE: This class CANNOT be declared in an unnamed namespace or the friend
+// declaration in PlaybackCommandForwardingRenderer will no longer function.
+class RendererCommandForwarder : public media::mojom::Renderer {
+ public:
+ // |owning_renderer| is expected to outlive this class.
+ RendererCommandForwarder(
+ PlaybackCommandForwardingRenderer* owning_renderer,
+ mojo::PendingReceiver<media::mojom::Renderer> playback_controller)
+ : owning_renderer_(owning_renderer),
+ playback_controller_(this, std::move(playback_controller)) {
+ DCHECK(owning_renderer_);
+ }
+
+ ~RendererCommandForwarder() override = default;
+
+ // media::mojom::Renderer overrides.
+ void Initialize(
+ ::mojo::PendingAssociatedRemote<media::mojom::RendererClient> client,
+ absl::optional<
+ std::vector<::mojo::PendingRemote<::media::mojom::DemuxerStream>>>
+ streams,
+ media::mojom::MediaUrlParamsPtr media_url_params,
+ InitializeCallback callback) override {
+ owning_renderer_->MojoRendererInitialize(
+ std::move(client), std::move(streams), std::move(media_url_params),
+ std::move(callback));
+ }
+
+ void StartPlayingFrom(::base::TimeDelta time) override {
+ owning_renderer_->MojoRendererStartPlayingFrom(std::move(time));
+ }
+
+ void SetPlaybackRate(double playback_rate) override {
+ owning_renderer_->MojoRendererSetPlaybackRate(playback_rate);
+ }
+
+ void Flush(FlushCallback callback) override {
+ owning_renderer_->MojoRendererFlush(std::move(callback));
+ }
+
+ void SetVolume(float volume) override {
+ owning_renderer_->MojoRendererSetVolume(volume);
+ }
+
+ void SetCdm(const absl::optional<::base::UnguessableToken>& cdm_id,
+ SetCdmCallback callback) override {
+ owning_renderer_->MojoRendererSetCdm(cdm_id, std::move(callback));
+ }
+
+ private:
+ PlaybackCommandForwardingRenderer* const owning_renderer_;
+ mojo::Receiver<media::mojom::Renderer> playback_controller_;
+};
PlaybackCommandForwardingRenderer::PlaybackCommandForwardingRenderer(
std::unique_ptr<media::Renderer> renderer,
@@ -18,6 +82,12 @@ PlaybackCommandForwardingRenderer::PlaybackCommandForwardingRenderer(
weak_factory_(this) {
DCHECK(real_renderer_);
DCHECK(pending_renderer_controls_);
+
+ send_timestamp_update_caller_.Start(
+ FROM_HERE, kTimeUpdateInterval,
+ base::BindRepeating(
+ &PlaybackCommandForwardingRenderer::SendTimestampUpdate,
+ weak_factory_.GetWeakPtr()));
}
PlaybackCommandForwardingRenderer::~PlaybackCommandForwardingRenderer() =
@@ -29,9 +99,10 @@ void PlaybackCommandForwardingRenderer::Initialize(
media::PipelineStatusCallback init_cb) {
DCHECK(!init_cb_);
+ upstream_renderer_client_ = client;
init_cb_ = std::move(init_cb);
real_renderer_->Initialize(
- media_resource, client,
+ media_resource, this,
base::BindOnce(&PlaybackCommandForwardingRenderer::
OnRealRendererInitializationComplete,
weak_factory_.GetWeakPtr()));
@@ -69,9 +140,8 @@ void PlaybackCommandForwardingRenderer::OnRealRendererInitializationComplete(
DCHECK(init_cb_);
DCHECK(!playback_controller_);
- playback_controller_ = std::make_unique<PlaybackController>(
- std::move(pending_renderer_controls_), task_runner_,
- real_renderer_.get());
+ playback_controller_ = std::make_unique<RendererCommandForwarder>(
+ this, std::move(pending_renderer_controls_));
std::move(init_cb_).Run(status);
}
@@ -81,74 +151,205 @@ void PlaybackCommandForwardingRenderer::OnRealRendererInitializationComplete(
// implementation. Calls must instead be bounced to the correct task runner in
// each receiver method.
// TODO(b/205307190): Bind the mojo pipe to the task runner directly.
-PlaybackCommandForwardingRenderer::PlaybackController::PlaybackController(
- mojo::PendingReceiver<media::mojom::Renderer> pending_renderer_controls,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner,
- media::Renderer* real_renderer)
- : real_renderer_(real_renderer),
- task_runner_(std::move(task_runner)),
- playback_controller_(this, std::move(pending_renderer_controls)),
- weak_factory_(this) {
- DCHECK(real_renderer_);
- DCHECK(task_runner_);
-}
-
-PlaybackCommandForwardingRenderer::PlaybackController::~PlaybackController() =
- default;
-
-void PlaybackCommandForwardingRenderer::PlaybackController::Initialize(
+void PlaybackCommandForwardingRenderer::MojoRendererInitialize(
::mojo::PendingAssociatedRemote<media::mojom::RendererClient> client,
absl::optional<
std::vector<::mojo::PendingRemote<::media::mojom::DemuxerStream>>>
streams,
media::mojom::MediaUrlParamsPtr media_url_params,
- InitializeCallback callback) {
- NOTIMPLEMENTED();
- std::move(callback).Run(false);
+ media::mojom::Renderer::InitializeCallback callback) {
+ DCHECK(!media_url_params);
+ DCHECK(client);
+
+ // NOTE: To maintain existing functionality, and ensure mirroring continues
+ // working as currently written with or without this Renderer, the mirroring
+ // data stream is provided through the standard Initialize() call, not passed
+ // over the mojo pipe here
+ DCHECK(!streams || streams.value().empty());
+
+ if (!task_runner_->BelongsToCurrentThread()) {
+ task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(
+ &PlaybackCommandForwardingRenderer::MojoRendererInitialize,
+ weak_factory_.GetWeakPtr(), std::move(client), std::move(streams),
+ std::move(media_url_params), std::move(callback)));
+ return;
+ }
+
+ remote_renderer_client_.Bind(std::move(client));
+
+ // |playback_controller_| which forwards the call here is only set following
+ // the completion of real_renderer_->Initialize().
+ std::move(callback).Run(true);
}
-void PlaybackCommandForwardingRenderer::PlaybackController::Flush(
- FlushCallback callback) {
- NOTIMPLEMENTED();
- std::move(callback).Run();
+void PlaybackCommandForwardingRenderer::MojoRendererFlush(
+ media::mojom::Renderer::FlushCallback callback) {
+ if (!task_runner_->BelongsToCurrentThread()) {
+ task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(&PlaybackCommandForwardingRenderer::MojoRendererFlush,
+ weak_factory_.GetWeakPtr(), std::move(callback)));
+ return;
+ }
+
+ real_renderer_->Flush(std::move(callback));
}
-void PlaybackCommandForwardingRenderer::PlaybackController::StartPlayingFrom(
+void PlaybackCommandForwardingRenderer::MojoRendererStartPlayingFrom(
::base::TimeDelta time) {
if (!task_runner_->BelongsToCurrentThread()) {
task_runner_->PostTask(
- FROM_HERE, base::BindOnce(&PlaybackCommandForwardingRenderer::
- PlaybackController::StartPlayingFrom,
- weak_factory_.GetWeakPtr(), time));
+ FROM_HERE,
+ base::BindOnce(
+ &PlaybackCommandForwardingRenderer::MojoRendererStartPlayingFrom,
+ weak_factory_.GetWeakPtr(), time));
return;
}
real_renderer_->StartPlayingFrom(time);
}
-void PlaybackCommandForwardingRenderer::PlaybackController::SetPlaybackRate(
+void PlaybackCommandForwardingRenderer::MojoRendererSetPlaybackRate(
double playback_rate) {
if (!task_runner_->BelongsToCurrentThread()) {
task_runner_->PostTask(
- FROM_HERE, base::BindOnce(&PlaybackCommandForwardingRenderer::
- PlaybackController::SetPlaybackRate,
- weak_factory_.GetWeakPtr(), playback_rate));
+ FROM_HERE,
+ base::BindOnce(
+ &PlaybackCommandForwardingRenderer::MojoRendererSetPlaybackRate,
+ weak_factory_.GetWeakPtr(), playback_rate));
return;
}
real_renderer_->SetPlaybackRate(playback_rate);
}
-void PlaybackCommandForwardingRenderer::PlaybackController::SetVolume(
- float volume) {
- NOTIMPLEMENTED();
+void PlaybackCommandForwardingRenderer::MojoRendererSetVolume(float volume) {
+ if (!task_runner_->BelongsToCurrentThread()) {
+ task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(
+ &PlaybackCommandForwardingRenderer::MojoRendererSetVolume,
+ weak_factory_.GetWeakPtr(), volume));
+ return;
+ }
+
+ real_renderer_->SetVolume(volume);
}
-void PlaybackCommandForwardingRenderer::PlaybackController::SetCdm(
+void PlaybackCommandForwardingRenderer::MojoRendererSetCdm(
const absl::optional<::base::UnguessableToken>& cdm_id,
- SetCdmCallback callback) {
- NOTIMPLEMENTED();
- std::move(callback).Run(false);
+ media::mojom::Renderer::SetCdmCallback callback) {
+ NOTREACHED() << "Use of a CDM is not supported by the remoting protocol.";
+}
+
+void PlaybackCommandForwardingRenderer::OnError(media::PipelineStatus status) {
+ if (remote_renderer_client_)
+ remote_renderer_client_->OnError(status);
+ if (upstream_renderer_client_)
+ upstream_renderer_client_->OnError(status);
+}
+
+void PlaybackCommandForwardingRenderer::OnEnded() {
+ DCHECK(task_runner_->BelongsToCurrentThread());
+
+ if (remote_renderer_client_)
+ remote_renderer_client_->OnEnded();
+ if (upstream_renderer_client_)
+ upstream_renderer_client_->OnEnded();
+}
+
+void PlaybackCommandForwardingRenderer::OnStatisticsUpdate(
+ const media::PipelineStatistics& stats) {
+ DCHECK(task_runner_->BelongsToCurrentThread());
+
+ if (remote_renderer_client_)
+ remote_renderer_client_->OnStatisticsUpdate(stats);
+ if (upstream_renderer_client_)
+ upstream_renderer_client_->OnStatisticsUpdate(stats);
+}
+
+void PlaybackCommandForwardingRenderer::OnBufferingStateChange(
+ media::BufferingState state,
+ media::BufferingStateChangeReason reason) {
+ DCHECK(task_runner_->BelongsToCurrentThread());
+
+ if (remote_renderer_client_)
+ remote_renderer_client_->OnBufferingStateChange(state, reason);
+ if (upstream_renderer_client_)
+ upstream_renderer_client_->OnBufferingStateChange(state, reason);
+}
+
+void PlaybackCommandForwardingRenderer::OnWaiting(media::WaitingReason reason) {
+ DCHECK(task_runner_->BelongsToCurrentThread());
+
+ if (remote_renderer_client_)
+ remote_renderer_client_->OnWaiting(reason);
+ if (upstream_renderer_client_)
+ upstream_renderer_client_->OnWaiting(reason);
+}
+
+void PlaybackCommandForwardingRenderer::OnAudioConfigChange(
+ const media::AudioDecoderConfig& config) {
+ DCHECK(task_runner_->BelongsToCurrentThread());
+
+ if (remote_renderer_client_)
+ remote_renderer_client_->OnAudioConfigChange(config);
+ if (upstream_renderer_client_)
+ upstream_renderer_client_->OnAudioConfigChange(config);
+}
+
+void PlaybackCommandForwardingRenderer::OnVideoConfigChange(
+ const media::VideoDecoderConfig& config) {
+ DCHECK(task_runner_->BelongsToCurrentThread());
+
+ if (remote_renderer_client_)
+ remote_renderer_client_->OnVideoConfigChange(config);
+ if (upstream_renderer_client_)
+ upstream_renderer_client_->OnVideoConfigChange(config);
+}
+
+void PlaybackCommandForwardingRenderer::OnVideoNaturalSizeChange(
+ const gfx::Size& size) {
+ DCHECK(task_runner_->BelongsToCurrentThread());
+
+ if (remote_renderer_client_)
+ remote_renderer_client_->OnVideoNaturalSizeChange(size);
+ if (upstream_renderer_client_)
+ upstream_renderer_client_->OnVideoNaturalSizeChange(size);
+}
+
+void PlaybackCommandForwardingRenderer::OnVideoOpacityChange(bool opaque) {
+ DCHECK(task_runner_->BelongsToCurrentThread());
+
+ if (remote_renderer_client_)
+ remote_renderer_client_->OnVideoOpacityChange(opaque);
+ if (upstream_renderer_client_)
+ upstream_renderer_client_->OnVideoOpacityChange(opaque);
+}
+
+void PlaybackCommandForwardingRenderer::OnVideoFrameRateChange(
+ absl::optional<int> fps) {
+ DCHECK(task_runner_->BelongsToCurrentThread());
+
+ // media::mojom::RendererClient does not support this call.
+ if (upstream_renderer_client_)
+ upstream_renderer_client_->OnVideoFrameRateChange(std::move(fps));
+}
+
+void PlaybackCommandForwardingRenderer::SendTimestampUpdate() {
+ DCHECK(task_runner_->BelongsToCurrentThread());
+
+ if (!remote_renderer_client_) {
+ return;
+ }
+
+ // Because |remote_renderer_client_| isn't set until |real_renderer_| is
+ // initialized, this call is well defined.
+ base::TimeDelta media_time = real_renderer_->GetMediaTime();
+ remote_renderer_client_->OnTimeUpdate(media_time, media_time,
+ base::TimeTicks::Now());
}
} // namespace cast_streaming
diff --git a/chromium/components/cast_streaming/renderer/playback_command_forwarding_renderer.h b/chromium/components/cast_streaming/renderer/playback_command_forwarding_renderer.h
index fcc891baa0b..96ef1b347ec 100644
--- a/chromium/components/cast_streaming/renderer/playback_command_forwarding_renderer.h
+++ b/chromium/components/cast_streaming/renderer/playback_command_forwarding_renderer.h
@@ -9,7 +9,9 @@
#include "base/memory/weak_ptr.h"
#include "media/base/renderer.h"
+#include "media/base/renderer_client.h"
#include "media/mojo/mojom/renderer.mojom.h"
+#include "mojo/public/cpp/bindings/associated_remote.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/receiver.h"
@@ -17,7 +19,8 @@ namespace cast_streaming {
// For high-level details, see documentation in
// PlaybackCommandForwardingRendererFactory.h.
-class PlaybackCommandForwardingRenderer : public media::Renderer {
+class PlaybackCommandForwardingRenderer : public media::Renderer,
+ public media::RendererClient {
public:
// |renderer| is the Renderer to which the Initialize() call should be
// delegated.
@@ -59,46 +62,51 @@ class PlaybackCommandForwardingRenderer : public media::Renderer {
base::TimeDelta GetMediaTime() override;
private:
- // Class responsible for receiving Renderer commands from a remote source and
- // acting on |real_renderer_| appropriately. This logic has been separated
- // from the parent class to avoid the complexity associated with having
- // both media::Renderer and media::mojo::Renderer implemented side-by-side.
- class PlaybackController : public media::mojom::Renderer {
- public:
- PlaybackController(
- mojo::PendingReceiver<media::mojom::Renderer> pending_rederer_controls,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner,
- media::Renderer* real_renderer);
- ~PlaybackController() override;
-
- // media::mojom::Renderer overrides.
- void StartPlayingFrom(::base::TimeDelta time) override;
- void SetPlaybackRate(double playback_rate) override;
-
- // The following overrides are not currently implemented.
- //
- // TODO(b/182429524): Implement these methods.
- void Initialize(
- ::mojo::PendingAssociatedRemote<media::mojom::RendererClient> client,
- absl::optional<
- std::vector<::mojo::PendingRemote<::media::mojom::DemuxerStream>>>
- streams,
- media::mojom::MediaUrlParamsPtr media_url_params,
- InitializeCallback callback) override;
- void Flush(FlushCallback callback) override;
- void SetVolume(float volume) override;
- void SetCdm(const absl::optional<::base::UnguessableToken>& cdm_id,
- SetCdmCallback callback) override;
-
- private:
- media::Renderer* const real_renderer_;
- scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
- mojo::Receiver<media::mojom::Renderer> playback_controller_;
- base::WeakPtrFactory<PlaybackController> weak_factory_;
- };
+ // Private namespace function not defined here because its details are not
+ // important.
+ friend class RendererCommandForwarder;
+
+ // media::mojom::Renderer implementation, with methods renamed to avoid
+ // intersection with media::Renderer types.
+ //
+ // Calls are all forwarded to |real_renderer_|;
+ void MojoRendererInitialize(
+ ::mojo::PendingAssociatedRemote<media::mojom::RendererClient> client,
+ absl::optional<
+ std::vector<::mojo::PendingRemote<::media::mojom::DemuxerStream>>>
+ streams,
+ media::mojom::MediaUrlParamsPtr media_url_params,
+ media::mojom::Renderer::InitializeCallback callback);
+ void MojoRendererStartPlayingFrom(::base::TimeDelta time);
+ void MojoRendererSetPlaybackRate(double playback_rate);
+ void MojoRendererFlush(media::mojom::Renderer::FlushCallback callback);
+ void MojoRendererSetVolume(float volume);
+ void MojoRendererSetCdm(
+ const absl::optional<::base::UnguessableToken>& cdm_id,
+ media::mojom::Renderer::SetCdmCallback callback);
+
+ // media::RendererClient overrides.
+ //
+ // Each of these simply forwards the call to both |remote_renderer_client_|
+ // and |upstream_renderer_client_|.
+ void OnError(media::PipelineStatus status) override;
+ void OnEnded() override;
+ void OnStatisticsUpdate(const media::PipelineStatistics& stats) override;
+ void OnBufferingStateChange(
+ media::BufferingState state,
+ media::BufferingStateChangeReason reason) override;
+ void OnWaiting(media::WaitingReason reason) override;
+ void OnAudioConfigChange(const media::AudioDecoderConfig& config) override;
+ void OnVideoConfigChange(const media::VideoDecoderConfig& config) override;
+ void OnVideoNaturalSizeChange(const gfx::Size& size) override;
+ void OnVideoOpacityChange(bool opaque) override;
+ void OnVideoFrameRateChange(absl::optional<int> fps) override;
void OnRealRendererInitializationComplete(media::PipelineStatus status);
+ // Sends an OnTimeUpdate() call to |remote_renderer_client_|.
+ void SendTimestampUpdate();
+
// Renderer to which playback calls should be forwarded.
std::unique_ptr<media::Renderer> real_renderer_;
@@ -114,7 +122,15 @@ class PlaybackCommandForwardingRenderer : public media::Renderer {
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
// Created as part of OnRealRendererInitializationComplete().
- std::unique_ptr<PlaybackController> playback_controller_;
+ std::unique_ptr<media::mojom::Renderer> playback_controller_;
+
+ // Channel to provide data back to the remote caller, set during
+ // MojoRendererInitialize().
+ mojo::AssociatedRemote<media::mojom::RendererClient> remote_renderer_client_;
+
+ RendererClient* upstream_renderer_client_;
+
+ base::RepeatingTimer send_timestamp_update_caller_;
base::WeakPtrFactory<PlaybackCommandForwardingRenderer> weak_factory_;
};
diff --git a/chromium/components/cast_streaming/renderer/playback_command_forwarding_renderer_unittest.cc b/chromium/components/cast_streaming/renderer/playback_command_forwarding_renderer_unittest.cc
index 4ad69e13364..fe10c6724ce 100644
--- a/chromium/components/cast_streaming/renderer/playback_command_forwarding_renderer_unittest.cc
+++ b/chromium/components/cast_streaming/renderer/playback_command_forwarding_renderer_unittest.cc
@@ -7,12 +7,60 @@
#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "components/cast_streaming/public/mojom/renderer_controller.mojom.h"
+#include "media/base/media_util.h"
#include "media/base/mock_filters.h"
+#include "media/base/test_helpers.h"
+#include "media/mojo/mojom/renderer.mojom.h"
+#include "mojo/public/cpp/bindings/associated_receiver.h"
+#include "mojo/public/cpp/bindings/associated_remote.h"
+#include "mojo/public/cpp/bindings/pending_associated_receiver.h"
+#include "mojo/public/cpp/bindings/pending_associated_remote.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace cast_streaming {
+namespace {
+
+class MockMojoRendererClient : public media::mojom::RendererClient {
+ public:
+ explicit MockMojoRendererClient(
+ mojo::PendingAssociatedReceiver<media::mojom::RendererClient> receiver)
+ : receiver_(this, std::move(receiver)) {}
+
+ MockMojoRendererClient(const MockMojoRendererClient&) = delete;
+ MockMojoRendererClient& operator=(const MockMojoRendererClient&) = delete;
+
+ ~MockMojoRendererClient() override = default;
+
+ MOCK_METHOD0(FlushCallback, void());
+ MOCK_METHOD1(InitializeCallback, void(bool));
+
+ // mojom::RendererClient implementation.
+ MOCK_METHOD3(OnTimeUpdate,
+ void(base::TimeDelta time,
+ base::TimeDelta max_time,
+ base::TimeTicks capture_time));
+ MOCK_METHOD2(OnBufferingStateChange,
+ void(media::BufferingState state,
+ media::BufferingStateChangeReason reason));
+ MOCK_METHOD0(OnEnded, void());
+ MOCK_METHOD1(OnError, void(const media::PipelineStatus& status));
+ MOCK_METHOD1(OnVideoOpacityChange, void(bool opaque));
+ MOCK_METHOD1(OnAudioConfigChange, void(const media::AudioDecoderConfig&));
+ MOCK_METHOD1(OnVideoConfigChange, void(const media::VideoDecoderConfig&));
+ MOCK_METHOD1(OnVideoNaturalSizeChange, void(const gfx::Size& size));
+ MOCK_METHOD1(OnStatisticsUpdate,
+ void(const media::PipelineStatistics& stats));
+ MOCK_METHOD1(OnWaiting, void(media::WaitingReason));
+ MOCK_METHOD1(OnDurationChange, void(base::TimeDelta duration));
+ MOCK_METHOD1(OnRemotePlayStateChange, void(media::MediaStatus::State state));
+
+ private:
+ mojo::AssociatedReceiver<media::mojom::RendererClient> receiver_;
+};
+
+} // namespace
class PlaybackCommandForwardingRendererTest : public testing::Test {
public:
@@ -23,54 +71,194 @@ class PlaybackCommandForwardingRendererTest : public testing::Test {
renderer_ = std::make_unique<PlaybackCommandForwardingRenderer>(
std::move(mock_renderer), task_environment_.GetMainThreadTaskRunner(),
remote_.BindNewPipeAndPassReceiver());
+
+ mojo_renderer_client_ =
+ std::make_unique<testing::StrictMock<MockMojoRendererClient>>(
+ remote_client_.InitWithNewEndpointAndPassReceiver());
}
~PlaybackCommandForwardingRendererTest() override = default;
+ protected:
+ void CallInitialize() {
+ auto init_cb = base::BindOnce(
+ &PlaybackCommandForwardingRendererTest::OnInitializationComplete,
+ base::Unretained(this));
+
+ EXPECT_CALL(*mock_renderer_, OnInitialize(&mock_media_resource_,
+ renderer_.get(), testing::_))
+ .WillOnce([this](media::MediaResource* media_resource,
+ media::RendererClient* client,
+ media::PipelineStatusCallback& init_cb) {
+ task_environment_.GetMainThreadTaskRunner()->PostTask(
+ FROM_HERE,
+ base::BindOnce(std::move(init_cb), media::PIPELINE_OK));
+ });
+
+ renderer_->Initialize(&mock_media_resource_, &mock_renderer_client_,
+ std::move(init_cb));
+ }
+
+ media::RendererClient* renderer_client() { return renderer_.get(); }
+
MOCK_METHOD1(OnInitializationComplete, void(media::PipelineStatus));
- protected:
base::test::SingleThreadTaskEnvironment task_environment_{
base::test::TaskEnvironment::TimeSource::MOCK_TIME};
mojo::Remote<media::mojom::Renderer> remote_;
+ mojo::PendingAssociatedRemote<media::mojom::RendererClient> remote_client_;
media::MockRenderer* mock_renderer_;
+ testing::StrictMock<media::MockMediaResource> mock_media_resource_;
+ testing::StrictMock<media::MockRendererClient> mock_renderer_client_;
std::unique_ptr<PlaybackCommandForwardingRenderer> renderer_;
+ std::unique_ptr<testing::StrictMock<MockMojoRendererClient>>
+ mojo_renderer_client_;
};
-TEST_F(PlaybackCommandForwardingRendererTest,
- RendererInitializeInitializesMojoPipe) {
- testing::StrictMock<media::MockMediaResource> mock_media_resource;
- testing::StrictMock<media::MockRendererClient> mock_renderer_client;
-
- auto init_cb = base::BindOnce(
- &PlaybackCommandForwardingRendererTest::OnInitializationComplete,
- base::Unretained(this));
-
- EXPECT_CALL(*mock_renderer_, OnInitialize(&mock_media_resource,
- &mock_renderer_client, testing::_))
- .WillOnce([this](media::MediaResource* media_resource,
- media::RendererClient* client,
- media::PipelineStatusCallback& init_cb) {
- auto result = base::BindOnce(std::move(init_cb),
- media::PipelineStatus::PIPELINE_OK);
- task_environment_.GetMainThreadTaskRunner()->PostTask(
- FROM_HERE, std::move(result));
- });
-
+TEST_F(PlaybackCommandForwardingRendererTest, StartPlaybackAsMirroring) {
remote_->SetPlaybackRate(1.0);
remote_->StartPlayingFrom(base::TimeDelta{});
task_environment_.RunUntilIdle();
- renderer_->Initialize(&mock_media_resource, &mock_renderer_client,
- std::move(init_cb));
+ CallInitialize();
- EXPECT_CALL(*this,
- OnInitializationComplete(media::PipelineStatus::PIPELINE_OK));
+ EXPECT_CALL(*this, OnInitializationComplete(
+ media::HasStatusCode(media::PIPELINE_OK)));
EXPECT_CALL(*mock_renderer_, SetPlaybackRate(1.0));
EXPECT_CALL(*mock_renderer_, StartPlayingFrom(testing::_));
task_environment_.RunUntilIdle();
}
+TEST_F(PlaybackCommandForwardingRendererTest, MojoCallsCorrectlyForwarded) {
+ CallInitialize();
+ EXPECT_CALL(*this, OnInitializationComplete(
+ media::HasStatusCode(media::PIPELINE_OK)));
+ task_environment_.RunUntilIdle();
+
+ EXPECT_CALL(*mock_renderer_, StartPlayingFrom(base::Seconds(42)));
+ remote_->StartPlayingFrom(base::Seconds(42));
+ task_environment_.RunUntilIdle();
+ testing::Mock::VerifyAndClearExpectations(mock_renderer_);
+
+ EXPECT_CALL(*mock_renderer_, SetPlaybackRate(12.34));
+ remote_->SetPlaybackRate(12.34);
+ task_environment_.RunUntilIdle();
+ testing::Mock::VerifyAndClearExpectations(mock_renderer_);
+
+ EXPECT_CALL(*mock_renderer_, OnFlush(testing::_))
+ .WillOnce([](base::OnceClosure& callback) { std::move(callback).Run(); });
+ EXPECT_CALL(*mojo_renderer_client_, FlushCallback());
+ remote_->Flush(base::BindOnce(&MockMojoRendererClient::FlushCallback,
+ base::Unretained(mojo_renderer_client_.get())));
+ task_environment_.RunUntilIdle();
+ testing::Mock::VerifyAndClearExpectations(mock_renderer_);
+
+ EXPECT_CALL(*mock_renderer_, SetVolume(43.21));
+ remote_->SetVolume(43.21);
+ task_environment_.RunUntilIdle();
+}
+
+TEST_F(PlaybackCommandForwardingRendererTest, RendererClientCallbacksCalled) {
+ CallInitialize();
+ EXPECT_CALL(*this, OnInitializationComplete(
+ media::HasStatusCode(media::PIPELINE_OK)));
+ task_environment_.RunUntilIdle();
+
+ EXPECT_CALL(*mojo_renderer_client_, InitializeCallback(true));
+ remote_->Initialize(
+ std::move(remote_client_), absl::nullopt, nullptr,
+ base::BindOnce(&MockMojoRendererClient::InitializeCallback,
+ base::Unretained(mojo_renderer_client_.get())));
+ task_environment_.RunUntilIdle();
+
+ const auto status = media::PIPELINE_ERROR_NETWORK;
+ EXPECT_CALL(*mojo_renderer_client_, OnError(testing::_));
+ EXPECT_CALL(mock_renderer_client_, OnError(media::HasStatusCode(status)));
+ renderer_client()->OnError(status);
+ task_environment_.RunUntilIdle();
+ testing::Mock::VerifyAndClearExpectations(mojo_renderer_client_.get());
+ testing::Mock::VerifyAndClearExpectations(&mock_renderer_client_);
+
+ EXPECT_CALL(*mojo_renderer_client_, OnEnded());
+ EXPECT_CALL(mock_renderer_client_, OnEnded());
+ renderer_client()->OnEnded();
+ task_environment_.RunUntilIdle();
+ testing::Mock::VerifyAndClearExpectations(mojo_renderer_client_.get());
+ testing::Mock::VerifyAndClearExpectations(&mock_renderer_client_);
+
+ media::PipelineStatistics stats;
+ stats.audio_bytes_decoded = 7;
+ stats.video_memory_usage = 42;
+ EXPECT_CALL(*mojo_renderer_client_, OnStatisticsUpdate(stats));
+ EXPECT_CALL(mock_renderer_client_, OnStatisticsUpdate(stats));
+ renderer_client()->OnStatisticsUpdate(stats);
+ task_environment_.RunUntilIdle();
+ testing::Mock::VerifyAndClearExpectations(mojo_renderer_client_.get());
+ testing::Mock::VerifyAndClearExpectations(&mock_renderer_client_);
+
+ const media::BufferingState state = media::BUFFERING_HAVE_ENOUGH;
+ const media::BufferingStateChangeReason reason = media::DEMUXER_UNDERFLOW;
+ EXPECT_CALL(*mojo_renderer_client_, OnBufferingStateChange(state, reason));
+ EXPECT_CALL(mock_renderer_client_, OnBufferingStateChange(state, reason));
+ renderer_client()->OnBufferingStateChange(state, reason);
+ task_environment_.RunUntilIdle();
+ testing::Mock::VerifyAndClearExpectations(mojo_renderer_client_.get());
+ testing::Mock::VerifyAndClearExpectations(&mock_renderer_client_);
+
+ const auto wait_reason = media::WaitingReason::kDecoderStateLost;
+ EXPECT_CALL(*mojo_renderer_client_, OnWaiting(wait_reason));
+ EXPECT_CALL(mock_renderer_client_, OnWaiting(wait_reason));
+ renderer_client()->OnWaiting(wait_reason);
+ task_environment_.RunUntilIdle();
+ testing::Mock::VerifyAndClearExpectations(mojo_renderer_client_.get());
+ testing::Mock::VerifyAndClearExpectations(&mock_renderer_client_);
+
+ const media::AudioDecoderConfig audio_config(
+ media::AudioCodec::kAAC, media::SampleFormat::kSampleFormatU8,
+ media::CHANNEL_LAYOUT_STEREO, 3, {},
+ media::EncryptionScheme::kUnencrypted);
+ EXPECT_CALL(*mojo_renderer_client_, OnAudioConfigChange(testing::_));
+ EXPECT_CALL(mock_renderer_client_, OnAudioConfigChange(testing::_));
+ renderer_client()->OnAudioConfigChange(audio_config);
+ task_environment_.RunUntilIdle();
+ testing::Mock::VerifyAndClearExpectations(mojo_renderer_client_.get());
+ testing::Mock::VerifyAndClearExpectations(&mock_renderer_client_);
+
+ const media::VideoDecoderConfig video_config(
+ media::VideoCodec::kH264, media::H264PROFILE_MAIN,
+ media::VideoDecoderConfig::AlphaMode::kIsOpaque, media::VideoColorSpace(),
+ media::VideoTransformation(), gfx::Size{1920, 1080},
+ gfx::Rect{1920, 1080}, gfx::Size{1920, 1080}, media::EmptyExtraData(),
+ media::EncryptionScheme::kUnencrypted);
+ EXPECT_CALL(*mojo_renderer_client_, OnVideoConfigChange(testing::_));
+ EXPECT_CALL(mock_renderer_client_, OnVideoConfigChange(testing::_));
+ renderer_client()->OnVideoConfigChange(video_config);
+ task_environment_.RunUntilIdle();
+ testing::Mock::VerifyAndClearExpectations(mojo_renderer_client_.get());
+ testing::Mock::VerifyAndClearExpectations(&mock_renderer_client_);
+
+ const gfx::Size size{123, 456};
+ EXPECT_CALL(*mojo_renderer_client_, OnVideoNaturalSizeChange(size));
+ EXPECT_CALL(mock_renderer_client_, OnVideoNaturalSizeChange(size));
+ renderer_client()->OnVideoNaturalSizeChange(size);
+ task_environment_.RunUntilIdle();
+ testing::Mock::VerifyAndClearExpectations(mojo_renderer_client_.get());
+ testing::Mock::VerifyAndClearExpectations(&mock_renderer_client_);
+
+ const bool opacity = true;
+ EXPECT_CALL(*mojo_renderer_client_, OnVideoOpacityChange(opacity));
+ EXPECT_CALL(mock_renderer_client_, OnVideoOpacityChange(opacity));
+ renderer_client()->OnVideoOpacityChange(opacity);
+ task_environment_.RunUntilIdle();
+ testing::Mock::VerifyAndClearExpectations(mojo_renderer_client_.get());
+ testing::Mock::VerifyAndClearExpectations(&mock_renderer_client_);
+
+ const absl::optional<int> frame_rate = 123;
+ EXPECT_CALL(mock_renderer_client_, OnVideoFrameRateChange(frame_rate));
+ renderer_client()->OnVideoFrameRateChange(frame_rate);
+ task_environment_.RunUntilIdle();
+}
+
} // namespace cast_streaming
diff --git a/chromium/components/cdm/browser/cdm_message_filter_android.cc b/chromium/components/cdm/browser/cdm_message_filter_android.cc
index 893aa2b5ab3..c61eacfd8dd 100644
--- a/chromium/components/cdm/browser/cdm_message_filter_android.cc
+++ b/chromium/components/cdm/browser/cdm_message_filter_android.cc
@@ -74,6 +74,10 @@ const CodecInfo<media::AudioCodec> kMP4AudioCodecsToQuery[] = {
{media::EME_CODEC_AC3, media::AudioCodec::kAC3},
{media::EME_CODEC_EAC3, media::AudioCodec::kEAC3},
#endif
+#if BUILDFLAG(ENABLE_PLATFORM_DTS_AUDIO)
+ {media::EME_CODEC_DTS, media::AudioCodec::kDTS},
+ {media::EME_CODEC_DTSXP2, media::AudioCodec::kDTSXP2},
+#endif
#endif // BUILDFLAG(USE_PROPRIETARY_CODECS)
};
diff --git a/chromium/components/cdm/browser/media_drm_storage_impl.cc b/chromium/components/cdm/browser/media_drm_storage_impl.cc
index e0974c4a7d4..34a51d845e6 100644
--- a/chromium/components/cdm/browser/media_drm_storage_impl.cc
+++ b/chromium/components/cdm/browser/media_drm_storage_impl.cc
@@ -29,7 +29,7 @@
#include "url/origin.h"
#include "url/url_constants.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "base/threading/scoped_blocking_call.h"
@@ -307,7 +307,7 @@ base::Value* CreateOriginDictAndReturnSessionsDict(
->SetKey(kSessions, base::Value(base::Value::Type::DICTIONARY));
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Clear sessions whose creation time falls in [start, end] from
// |sessions_dict|. This function also cleans corruption data and should never
// fail.
@@ -354,7 +354,7 @@ void ClearSessionDataForTimePeriod(base::Value* sessions_dict,
// 2. Removes the origin data if all of the sessions are removed.
// 3. Returns a list of origin IDs to unprovision.
std::vector<base::UnguessableToken> ClearMatchingLicenseData(
- base::DictionaryValue* storage_dict,
+ base::Value* storage_dict,
base::Time start,
base::Time end,
const base::RepeatingCallback<bool(const GURL&)>& filter) {
@@ -432,7 +432,7 @@ void ClearMediaDrmLicensesBlocking(
media_drm_bridge->Unprovision();
}
}
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
// Returns true if any session in |sessions_dict| has been modified more
// recently than |start| and before |end|, and otherwise
@@ -461,9 +461,8 @@ bool SessionsModifiedBetween(const base::Value* sessions_dict,
// Returns the origin ID for |origin|, if it exists. Will return an empty value
// if the origin ID can not be found in |storage_dict|.
-base::UnguessableToken GetOriginIdForOrigin(
- const base::DictionaryValue* storage_dict,
- const url::Origin& origin) {
+base::UnguessableToken GetOriginIdForOrigin(const base::Value* storage_dict,
+ const url::Origin& origin) {
DCHECK(storage_dict);
const base::Value* origin_dict = storage_dict->FindKeyOfType(
@@ -526,7 +525,7 @@ class InitializationSerializer {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
// Check if the preference has an existing origin ID.
- const base::DictionaryValue* storage_dict =
+ const base::Value* storage_dict =
pref_service->GetDictionary(prefs::kMediaDrmStorage);
base::UnguessableToken origin_id =
GetOriginIdForOrigin(storage_dict, origin);
@@ -612,7 +611,7 @@ std::set<GURL> MediaDrmStorageImpl::GetAllOrigins(
const PrefService* pref_service) {
DCHECK(pref_service);
- const base::DictionaryValue* storage_dict =
+ const base::Value* storage_dict =
pref_service->GetDictionary(prefs::kMediaDrmStorage);
if (!storage_dict)
return std::set<GURL>();
@@ -634,7 +633,7 @@ std::vector<GURL> MediaDrmStorageImpl::GetOriginsModifiedBetween(
base::Time end) {
DCHECK(pref_service);
- const base::DictionaryValue* storage_dict =
+ const base::Value* storage_dict =
pref_service->GetDictionary(prefs::kMediaDrmStorage);
if (!storage_dict)
return {};
@@ -683,7 +682,7 @@ std::vector<GURL> MediaDrmStorageImpl::GetOriginsModifiedBetween(
return matching_origins;
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// static
void MediaDrmStorageImpl::ClearMatchingLicenses(
PrefService* pref_service,
@@ -816,7 +815,7 @@ void MediaDrmStorageImpl::OnProvisioned(OnProvisionedCallback callback) {
}
DictionaryPrefUpdate update(pref_service_, prefs::kMediaDrmStorage);
- base::DictionaryValue* storage_dict = update.Get();
+ base::Value* storage_dict = update.Get();
DCHECK(storage_dict);
// Update origin dict once origin provisioning completes. There may be
@@ -848,7 +847,7 @@ void MediaDrmStorageImpl::SavePersistentSession(
}
DictionaryPrefUpdate update(pref_service_, prefs::kMediaDrmStorage);
- base::DictionaryValue* storage_dict = update.Get();
+ base::Value* storage_dict = update.Get();
DCHECK(storage_dict);
base::Value* sessions_dict = GetSessionsDictFromStorageDict<base::Value>(
diff --git a/chromium/components/cdm/browser/media_drm_storage_impl.h b/chromium/components/cdm/browser/media_drm_storage_impl.h
index 1387209365b..721a07eb63e 100644
--- a/chromium/components/cdm/browser/media_drm_storage_impl.h
+++ b/chromium/components/cdm/browser/media_drm_storage_impl.h
@@ -72,7 +72,7 @@ class MediaDrmStorageImpl final
base::Time start,
base::Time end);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Clear media licenses and related data if:
// 1. Creation time falls in [delete_begin, delete_end], and
// 2. |filter| returns true for the origin. |filter| is passed in to allow
diff --git a/chromium/components/cdm/browser/media_drm_storage_impl_unittest.cc b/chromium/components/cdm/browser/media_drm_storage_impl_unittest.cc
index df61f8f9fe3..fb61cad1fbd 100644
--- a/chromium/components/cdm/browser/media_drm_storage_impl_unittest.cc
+++ b/chromium/components/cdm/browser/media_drm_storage_impl_unittest.cc
@@ -122,7 +122,7 @@ class MediaDrmStorageImplTest : public content::RenderViewHostTestHarness {
base::RunLoop().RunUntilIdle();
// Verify the origin dictionary is created.
- const base::DictionaryValue* storage_dict =
+ const base::Value* storage_dict =
pref_service_->GetDictionary(prefs::kMediaDrmStorage);
EXPECT_TRUE(storage_dict->FindKey(kTestOrigin));
@@ -290,7 +290,7 @@ TEST_F(MediaDrmStorageImplTest, OnProvisioned) {
base::RunLoop().RunUntilIdle();
// Verify the origin dictionary is created.
- const base::DictionaryValue* storage_dict =
+ const base::Value* storage_dict =
pref_service_->GetDictionary(prefs::kMediaDrmStorage);
EXPECT_TRUE(storage_dict->FindKey(kTestOrigin));
}
diff --git a/chromium/components/cdm/common/cdm_manifest.cc b/chromium/components/cdm/common/cdm_manifest.cc
index 2378886c6eb..614942de67c 100644
--- a/chromium/components/cdm/common/cdm_manifest.cc
+++ b/chromium/components/cdm/common/cdm_manifest.cc
@@ -148,7 +148,7 @@ bool GetEncryptionSchemes(
}
base::flat_set<media::EncryptionScheme> result;
- for (const auto& item : value->GetList()) {
+ for (const auto& item : value->GetListDeprecated()) {
if (!item.is_string()) {
DLOG(ERROR) << "Unrecognized item type in CDM manifest entry "
<< kCdmSupportedEncryptionSchemesName;
diff --git a/chromium/components/cdm/common/cdm_message_generator.h b/chromium/components/cdm/common/cdm_message_generator.h
index 08309514782..bf591832590 100644
--- a/chromium/components/cdm/common/cdm_message_generator.h
+++ b/chromium/components/cdm/common/cdm_message_generator.h
@@ -6,6 +6,6 @@
#include "build/build_config.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "components/cdm/common/cdm_messages_android.h"
#endif
diff --git a/chromium/components/cdm/renderer/widevine_key_system_properties.cc b/chromium/components/cdm/renderer/widevine_key_system_properties.cc
index 3cf1ecee5a5..4c522b0092e 100644
--- a/chromium/components/cdm/renderer/widevine_key_system_properties.cc
+++ b/chromium/components/cdm/renderer/widevine_key_system_properties.cc
@@ -5,7 +5,6 @@
#include "components/cdm/renderer/widevine_key_system_properties.h"
#include "base/command_line.h"
-#include "base/compiler_specific.h"
#include "base/feature_list.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
@@ -45,7 +44,7 @@ Robustness ConvertRobustness(const std::string& robustness) {
return Robustness::INVALID;
}
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
bool IsHardwareSecurityEnabledForKeySystem(const std::string& key_system) {
return (key_system == kWidevineKeySystem &&
base::FeatureList::IsEnabled(media::kHardwareSecureDecryption)) ||
@@ -53,7 +52,7 @@ bool IsHardwareSecurityEnabledForKeySystem(const std::string& key_system) {
base::FeatureList::IsEnabled(
media::kHardwareSecureDecryptionExperiment));
}
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
} // namespace
@@ -85,13 +84,13 @@ std::string WidevineKeySystemProperties::GetBaseKeySystemName() const {
bool WidevineKeySystemProperties::IsSupportedKeySystem(
const std::string& key_system) const {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
if (key_system == kWidevineExperimentKeySystem &&
base::FeatureList::IsEnabled(
media::kHardwareSecureDecryptionExperiment)) {
return true;
}
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
return key_system == kWidevineKeySystem;
}
@@ -169,10 +168,10 @@ EmeConfigRule WidevineKeySystemProperties::GetRobustnessConfigRule(
return EmeConfigRule::NOT_SUPPORTED;
}
- bool hw_secure_codecs_required =
+ [[maybe_unused]] bool hw_secure_codecs_required =
hw_secure_requirement && *hw_secure_requirement;
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS)
// Hardware security requires HWDRM or remote attestation, both of these
// require an identifier.
if (robustness >= Robustness::HW_SECURE_CRYPTO || hw_secure_codecs_required) {
@@ -198,11 +197,11 @@ EmeConfigRule WidevineKeySystemProperties::GetRobustnessConfigRule(
max_robustness == Robustness::HW_SECURE_ALL) {
return EmeConfigRule::IDENTIFIER_RECOMMENDED;
}
-#elif defined(OS_ANDROID)
+#elif BUILDFLAG(IS_ANDROID)
// On Android, require hardware secure codecs for SW_SECURE_DECODE and above.
if (robustness >= Robustness::SW_SECURE_DECODE || hw_secure_codecs_required)
return EmeConfigRule::HW_SECURE_CODECS_REQUIRED;
-#elif defined(OS_WIN)
+#elif BUILDFLAG(IS_WIN)
// On Windows, hardware security uses MediaFoundation-based CDM which requires
// identifier and persistent state.
if (robustness >= Robustness::HW_SECURE_CRYPTO || hw_secure_codecs_required) {
@@ -216,9 +215,7 @@ EmeConfigRule WidevineKeySystemProperties::GetRobustnessConfigRule(
// above.
if (robustness >= Robustness::HW_SECURE_CRYPTO)
return EmeConfigRule::HW_SECURE_CODECS_REQUIRED;
-
- ALLOW_UNUSED_LOCAL(hw_secure_codecs_required);
-#endif // defined(OS_CHROMEOS)
+#endif // BUILDFLAG(IS_CHROMEOS)
return EmeConfigRule::SUPPORTED;
}
diff --git a/chromium/components/certificate_transparency/BUILD.gn b/chromium/components/certificate_transparency/BUILD.gn
index e560bd9659a..49c7a7e6917 100644
--- a/chromium/components/certificate_transparency/BUILD.gn
+++ b/chromium/components/certificate_transparency/BUILD.gn
@@ -12,7 +12,7 @@ proto_library("proto") {
]
}
-static_library("certificate_transparency") {
+component("certificate_transparency") {
sources = [
"chrome_ct_policy_enforcer.cc",
"chrome_ct_policy_enforcer.h",
@@ -26,7 +26,10 @@ static_library("certificate_transparency") {
"pref_names.h",
]
+ defines = [ "IS_CERTIFICATE_TRANSPARENCY_IMPL" ]
+
deps = [
+ ":proto",
"//base",
"//components/base32",
"//components/certificate_transparency/data:ct_log_list",
@@ -36,8 +39,6 @@ static_library("certificate_transparency") {
"//net",
"//url",
]
-
- public_deps = [ ":proto" ]
}
source_set("unit_tests") {
diff --git a/chromium/components/certificate_transparency/OWNERS b/chromium/components/certificate_transparency/OWNERS
index d254893d150..4d052948d20 100644
--- a/chromium/components/certificate_transparency/OWNERS
+++ b/chromium/components/certificate_transparency/OWNERS
@@ -1,5 +1,8 @@
# Primary
-rsleevi@chromium.org
+carlosil@chromium.org
+cthomp@chromium.org
+estark@chromium.org
+jdeblasio@chromium.org
# Secondary
file://net/OWNERS
diff --git a/chromium/components/certificate_transparency/certificate_transparency_config.proto b/chromium/components/certificate_transparency/certificate_transparency_config.proto
index e2f2db2ba47..ac7906b600c 100644
--- a/chromium/components/certificate_transparency/certificate_transparency_config.proto
+++ b/chromium/components/certificate_transparency/certificate_transparency_config.proto
@@ -16,4 +16,7 @@ message CTConfig {
bool disable_ct_enforcement = 1;
// Logs Chrome should recognize.
CTLogList log_list = 2;
-} \ No newline at end of file
+ // A list of the leaf hashes for the most popular SCTs encountered in Chrome
+ // recently. Sorted lexicographically.
+ repeated bytes popular_scts = 3;
+}
diff --git a/chromium/components/certificate_transparency/chrome_ct_policy_enforcer.cc b/chromium/components/certificate_transparency/chrome_ct_policy_enforcer.cc
index 031116768ea..25417ff3de9 100644
--- a/chromium/components/certificate_transparency/chrome_ct_policy_enforcer.cc
+++ b/chromium/components/certificate_transparency/chrome_ct_policy_enforcer.cc
@@ -93,16 +93,16 @@ base::Value NetLogCertComplianceCheckResultParams(
net::X509Certificate* cert,
bool build_timely,
CTPolicyCompliance compliance) {
- base::DictionaryValue dict;
+ base::Value dict(base::Value::Type::DICTIONARY);
// TODO(mattm): This double-wrapping of the certificate list is weird. Remove
// this (probably requires updates to netlog-viewer).
base::Value certificate_dict(base::Value::Type::DICTIONARY);
certificate_dict.SetKey("certificates", net::NetLogX509CertificateList(cert));
dict.SetKey("certificate", std::move(certificate_dict));
- dict.SetBoolean("build_timely", build_timely);
- dict.SetString("ct_compliance_status",
- CTPolicyComplianceToString(compliance));
- return std::move(dict);
+ dict.SetBoolKey("build_timely", build_timely);
+ dict.SetStringKey("ct_compliance_status",
+ CTPolicyComplianceToString(compliance));
+ return dict;
}
} // namespace
@@ -114,7 +114,7 @@ OperatorHistoryEntry::OperatorHistoryEntry(const OperatorHistoryEntry& other) =
ChromeCTPolicyEnforcer::ChromeCTPolicyEnforcer(
base::Time log_list_date,
- std::vector<std::pair<std::string, base::TimeDelta>> disqualified_logs,
+ std::vector<std::pair<std::string, base::Time>> disqualified_logs,
std::vector<std::string> operated_by_google_logs,
std::map<std::string, OperatorHistoryEntry> log_operator_history)
: disqualified_logs_(std::move(disqualified_logs)),
@@ -152,7 +152,7 @@ CTPolicyCompliance ChromeCTPolicyEnforcer::CheckCompliance(
void ChromeCTPolicyEnforcer::UpdateCTLogList(
base::Time update_time,
- std::vector<std::pair<std::string, base::TimeDelta>> disqualified_logs,
+ std::vector<std::pair<std::string, base::Time>> disqualified_logs,
std::vector<std::string> operated_by_google_logs,
std::map<std::string, OperatorHistoryEntry> log_operator_history) {
log_list_date_ = update_time;
@@ -172,7 +172,10 @@ bool ChromeCTPolicyEnforcer::IsLogDisqualified(
if (p == std::end(disqualified_logs_) || p->first != log_id) {
return false;
}
- *disqualification_date = base::Time::UnixEpoch() + p->second;
+ *disqualification_date = p->second;
+ if (base::Time::Now() < *disqualification_date) {
+ return false;
+ }
return true;
}
@@ -217,7 +220,7 @@ CTPolicyCompliance ChromeCTPolicyEnforcer::CheckCTPolicyCompliance(
issuance_date = std::min(sct->timestamp, issuance_date);
}
- // Certificates issued after this date (February 1, 2022, OO:OO:OO GMT)
+ // Certificates issued after this date (April 15, 2022, OO:OO:OO GMT)
// will be subject to the new CT policy, which:
// -Removes the One Google log requirement.
// -Introduces a log operator diversity (at least 2 SCTs that come from
@@ -227,7 +230,7 @@ CTPolicyCompliance ChromeCTPolicyEnforcer::CheckCTPolicyCompliance(
// Increases the SCT requirements for certificates with a lifetime between
// 180 days and 15 months, from 2 to 3.
const base::Time kPolicyUpdateDate =
- base::Time::UnixEpoch() + base::Seconds(1643673600);
+ base::Time::UnixEpoch() + base::Seconds(1649980800);
bool use_2022_policy =
base::FeatureList::IsEnabled(
features::kCertificateTransparency2022PolicyAllCerts) ||
@@ -343,7 +346,7 @@ CTPolicyCompliance ChromeCTPolicyEnforcer::CheckCTPolicyCompliance(
// ... AND the certificate embeds SCTs from AT LEAST the number of logs
// once or currently qualified shown in Table 1 of the CT Policy.
base::TimeDelta lifetime = cert.valid_expiry() - cert.valid_start();
- if (lifetime >= base::Days(180)) {
+ if (lifetime > base::Days(180)) {
num_required_embedded_scts = 3;
} else {
num_required_embedded_scts = 2;
@@ -418,7 +421,7 @@ std::string ChromeCTPolicyEnforcer::GetOperatorForLog(
DCHECK(log_operator_history_.find(log_id) != log_operator_history_.end());
OperatorHistoryEntry log_history = log_operator_history_.at(log_id);
for (auto operator_entry : log_history.previous_operators_) {
- if (timestamp - base::Time::UnixEpoch() < operator_entry.second)
+ if (timestamp < operator_entry.second)
return operator_entry.first;
}
// Either the log has only ever had one operator, or the timestamp is after
diff --git a/chromium/components/certificate_transparency/chrome_ct_policy_enforcer.h b/chromium/components/certificate_transparency/chrome_ct_policy_enforcer.h
index 807578c8c61..df7544daa3f 100644
--- a/chromium/components/certificate_transparency/chrome_ct_policy_enforcer.h
+++ b/chromium/components/certificate_transparency/chrome_ct_policy_enforcer.h
@@ -10,6 +10,8 @@
#include <utility>
#include <vector>
+#include "base/component_export.h"
+#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/time/clock.h"
#include "base/time/time.h"
@@ -17,12 +19,12 @@
namespace certificate_transparency {
-struct OperatorHistoryEntry {
+struct COMPONENT_EXPORT(CERTIFICATE_TRANSPARENCY) OperatorHistoryEntry {
// Name of the current operator for the log.
std::string current_operator_;
// Vector of previous operators (if any) for the log, represented as pairs of
// operator name and time when they stopped operating the log.
- std::vector<std::pair<std::string, base::TimeDelta>> previous_operators_;
+ std::vector<std::pair<std::string, base::Time>> previous_operators_;
OperatorHistoryEntry();
~OperatorHistoryEntry();
@@ -37,7 +39,8 @@ struct OperatorHistoryEntry {
// for the set of known, qualified logs - either through a reliable binary
// updating mechanism or through out-of-band delivery. See
// //net/docs/certificate-transparency.md for more details.
-class ChromeCTPolicyEnforcer : public net::CTPolicyEnforcer {
+class COMPONENT_EXPORT(CERTIFICATE_TRANSPARENCY) ChromeCTPolicyEnforcer
+ : public net::CTPolicyEnforcer {
public:
// |logs| is a list of Certificate Transparency logs. Data about each log is
// needed to apply Chrome's policies. |disqualified_logs| is a map of log ID
@@ -47,7 +50,7 @@ class ChromeCTPolicyEnforcer : public net::CTPolicyEnforcer {
// arguments were generated. Both lists of logs must be sorted by log ID.
ChromeCTPolicyEnforcer(
base::Time log_list_date,
- std::vector<std::pair<std::string, base::TimeDelta>> disqualified_logs,
+ std::vector<std::pair<std::string, base::Time>> disqualified_logs,
std::vector<std::string> operated_by_google_logs,
std::map<std::string, OperatorHistoryEntry> log_operator_history);
@@ -63,7 +66,7 @@ class ChromeCTPolicyEnforcer : public net::CTPolicyEnforcer {
// list of log IDs operated by Google
void UpdateCTLogList(
base::Time update_time,
- std::vector<std::pair<std::string, base::TimeDelta>> disqualified_logs,
+ std::vector<std::pair<std::string, base::Time>> disqualified_logs,
std::vector<std::string> operated_by_google_logs,
std::map<std::string, OperatorHistoryEntry> log_operator_history);
@@ -77,7 +80,7 @@ class ChromeCTPolicyEnforcer : public net::CTPolicyEnforcer {
const std::vector<std::string>& operated_by_google_logs_for_testing() {
return operated_by_google_logs_;
}
- const std::vector<std::pair<std::string, base::TimeDelta>>&
+ const std::vector<std::pair<std::string, base::Time>>&
disqualified_logs_for_testing() {
return disqualified_logs_;
}
@@ -93,6 +96,10 @@ class ChromeCTPolicyEnforcer : public net::CTPolicyEnforcer {
}
private:
+ FRIEND_TEST_ALL_PREFIXES(ChromeCTPolicyEnforcerTestBothPolicies,
+ IsLogDisqualifiedTimestamp);
+ FRIEND_TEST_ALL_PREFIXES(ChromeCTPolicyEnforcerTestBothPolicies,
+ IsLogDisqualifiedReturnsFalseOnUnknownLog);
// Returns true if the log identified by |log_id| (the SHA-256 hash of the
// log's DER-encoded SPKI) has been disqualified, and sets
// |*disqualification_date| to the date of disqualification. Any SCTs that
@@ -115,7 +122,7 @@ class ChromeCTPolicyEnforcer : public net::CTPolicyEnforcer {
std::string GetOperatorForLog(std::string log_id, base::Time timestamp) const;
// Map of SHA-256(SPKI) to log disqualification date.
- std::vector<std::pair<std::string, base::TimeDelta>> disqualified_logs_;
+ std::vector<std::pair<std::string, base::Time>> disqualified_logs_;
// List of SHA-256(SPKI) for logs operated by Google.
std::vector<std::string> operated_by_google_logs_;
diff --git a/chromium/components/certificate_transparency/chrome_ct_policy_enforcer_unittest.cc b/chromium/components/certificate_transparency/chrome_ct_policy_enforcer_unittest.cc
index 94bd7060633..e9525db87b9 100644
--- a/chromium/components/certificate_transparency/chrome_ct_policy_enforcer_unittest.cc
+++ b/chromium/components/certificate_transparency/chrome_ct_policy_enforcer_unittest.cc
@@ -45,6 +45,8 @@ const char kGoogleAviatorLogID[] =
static_assert(base::size(kGoogleAviatorLogID) - 1 == crypto::kSHA256Length,
"Incorrect log ID length.");
+} // namespace
+
class ChromeCTPolicyEnforcerTest : public ::testing::Test {
public:
void SetUp() override {
@@ -132,15 +134,41 @@ class ChromeCTPolicyEnforcerTest : public ::testing::Test {
return result;
}
+ void FillOperatorHistoryWithDiverseOperators(
+ SCTList scts,
+ std::map<std::string, OperatorHistoryEntry>* operator_history) {
+ for (size_t i = 0; i < scts.size(); i++) {
+ OperatorHistoryEntry entry;
+ entry.current_operator_ = "Operator " + base::NumberToString(i);
+ (*operator_history)[scts[i]->log_id] = entry;
+ }
+ }
+
protected:
base::SimpleTestClock clock_;
- std::unique_ptr<net::CTPolicyEnforcer> policy_enforcer_;
+ std::unique_ptr<ChromeCTPolicyEnforcer> policy_enforcer_;
scoped_refptr<X509Certificate> chain_;
std::string google_log_id_;
std::string non_google_log_id_;
+ base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+// Subclass of ChromeCTPolicyEnforcerTest that tests using only the pre-2022
+// policy.
+class ChromeCTPolicyEnforcerTestPre2022Policy
+ : public ChromeCTPolicyEnforcerTest {
+ public:
+ void SetUp() override {
+ scoped_feature_list_.InitWithFeatures(
+ /*enabled_features*/ {},
+ /*disabled_features*/ {
+ features::kCertificateTransparency2022Policy,
+ features::kCertificateTransparency2022PolicyAllCerts});
+ ChromeCTPolicyEnforcerTest::SetUp();
+ }
};
-TEST_F(ChromeCTPolicyEnforcerTest,
+TEST_F(ChromeCTPolicyEnforcerTestPre2022Policy,
DoesNotConformToCTPolicyNotEnoughDiverseSCTsAllGoogle) {
SCTList scts;
std::vector<std::string> desired_log_ids(2, google_log_id_);
@@ -154,7 +182,7 @@ TEST_F(ChromeCTPolicyEnforcerTest,
NetLogWithSource()));
}
-TEST_F(ChromeCTPolicyEnforcerTest,
+TEST_F(ChromeCTPolicyEnforcerTestPre2022Policy,
DoesNotConformToCTPolicyNotEnoughDiverseSCTsAllNonGoogle) {
SCTList scts;
std::vector<std::string> desired_log_ids(2, non_google_log_id_);
@@ -168,7 +196,7 @@ TEST_F(ChromeCTPolicyEnforcerTest,
NetLogWithSource()));
}
-TEST_F(ChromeCTPolicyEnforcerTest,
+TEST_F(ChromeCTPolicyEnforcerTestPre2022Policy,
ConformsToCTPolicyIfSCTBeforeEnforcementDate) {
SCTList scts;
// |chain_| is valid for 10 years - over 121 months - so requires 5 SCTs.
@@ -181,96 +209,129 @@ TEST_F(ChromeCTPolicyEnforcerTest,
NetLogWithSource()));
}
-TEST_F(ChromeCTPolicyEnforcerTest, ConformsToCTPolicyWithNonEmbeddedSCTs) {
- SCTList scts;
- FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_FROM_TLS_EXTENSION,
- 2, &scts);
+TEST_F(ChromeCTPolicyEnforcerTestPre2022Policy,
+ ConformsToPolicyExactNumberOfSCTsForValidityPeriod) {
+ std::unique_ptr<crypto::RSAPrivateKey> private_key(
+ crypto::RSAPrivateKey::Create(1024));
+ ASSERT_TRUE(private_key);
- EXPECT_EQ(CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS,
- policy_enforcer_->CheckCompliance(chain_.get(), scts,
- NetLogWithSource()));
-}
+ // Test multiple validity periods
+ base::Time time_2015_3_0_25_11_25_0_0 =
+ CreateTime({2015, 3, 0, 25, 11, 25, 0, 0});
-TEST_F(ChromeCTPolicyEnforcerTest, EnforcementDisabledByBinaryAge) {
- SCTList scts;
- FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_FROM_TLS_EXTENSION,
- 2, &scts);
+ base::Time time_2016_6_0_6_11_25_0_0 =
+ CreateTime({2016, 6, 0, 6, 11, 25, 0, 0});
- EXPECT_EQ(CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS,
- policy_enforcer_->CheckCompliance(chain_.get(), scts,
- NetLogWithSource()));
+ base::Time time_2016_6_0_25_11_25_0_0 =
+ CreateTime({2016, 6, 0, 25, 11, 25, 0, 0});
- clock_.Advance(base::Days(71));
+ base::Time time_2016_6_0_27_11_25_0_0 =
+ CreateTime({2016, 6, 0, 27, 11, 25, 0, 0});
- EXPECT_EQ(CTPolicyCompliance::CT_POLICY_BUILD_NOT_TIMELY,
- policy_enforcer_->CheckCompliance(chain_.get(), scts,
- NetLogWithSource()));
-}
+ base::Time time_2017_6_0_25_11_25_0_0 =
+ CreateTime({2017, 6, 0, 25, 11, 25, 0, 0});
-TEST_F(ChromeCTPolicyEnforcerTest, ConformsToCTPolicyWithEmbeddedSCTs) {
- // |chain_| is valid for 10 years - over 121 months - so requires 5 SCTs.
- SCTList scts;
- FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_EMBEDDED, 5, &scts);
+ base::Time time_2017_6_0_28_11_25_0_0 =
+ CreateTime({2017, 6, 0, 28, 11, 25, 0, 0});
- EXPECT_EQ(CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS,
- policy_enforcer_->CheckCompliance(chain_.get(), scts,
- NetLogWithSource()));
-}
+ base::Time time_2018_6_0_25_11_25_0_0 =
+ CreateTime({2018, 6, 0, 25, 11, 25, 0, 0});
-TEST_F(ChromeCTPolicyEnforcerTest,
- ConformsToCTPolicyWithPooledNonEmbeddedSCTs) {
- SCTList scts;
- std::vector<std::string> desired_logs;
+ base::Time time_2018_6_0_27_11_25_0_0 =
+ CreateTime({2018, 6, 0, 27, 11, 25, 0, 0});
- // One Google log, delivered via OCSP.
- desired_logs.clear();
- desired_logs.push_back(google_log_id_);
- FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_FROM_OCSP_RESPONSE,
- desired_logs.size(), desired_logs, true, &scts);
+ const struct TestData {
+ base::Time validity_start;
+ base::Time validity_end;
+ size_t scts_required;
+ } kTestData[] = {{// Cert valid for -14 months (nonsensical), needs 2 SCTs.
+ time_2016_6_0_6_11_25_0_0, time_2015_3_0_25_11_25_0_0, 2},
+ {// Cert valid for 14 months, needs 2 SCTs.
+ time_2015_3_0_25_11_25_0_0, time_2016_6_0_6_11_25_0_0, 2},
+ {// Cert valid for exactly 15 months, needs 3 SCTs.
+ time_2015_3_0_25_11_25_0_0, time_2016_6_0_25_11_25_0_0, 3},
+ {// Cert valid for over 15 months, needs 3 SCTs.
+ time_2015_3_0_25_11_25_0_0, time_2016_6_0_27_11_25_0_0, 3},
+ {// Cert valid for exactly 27 months, needs 3 SCTs.
+ time_2015_3_0_25_11_25_0_0, time_2017_6_0_25_11_25_0_0, 3},
+ {// Cert valid for over 27 months, needs 4 SCTs.
+ time_2015_3_0_25_11_25_0_0, time_2017_6_0_28_11_25_0_0, 4},
+ {// Cert valid for exactly 39 months, needs 4 SCTs.
+ time_2015_3_0_25_11_25_0_0, time_2018_6_0_25_11_25_0_0, 4},
+ {// Cert valid for over 39 months, needs 5 SCTs.
+ time_2015_3_0_25_11_25_0_0, time_2018_6_0_27_11_25_0_0, 5}};
- // One non-Google log, delivered via TLS.
- desired_logs.clear();
- desired_logs.push_back(non_google_log_id_);
- FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_FROM_TLS_EXTENSION,
- desired_logs.size(), desired_logs, true, &scts);
+ for (size_t i = 0; i < base::size(kTestData); ++i) {
+ SCOPED_TRACE(i);
+ const base::Time& start = kTestData[i].validity_start;
+ const base::Time& end = kTestData[i].validity_end;
+ size_t required_scts = kTestData[i].scts_required;
- EXPECT_EQ(CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS,
- policy_enforcer_->CheckCompliance(chain_.get(), scts,
- NetLogWithSource()));
+ // Create a self-signed certificate with exactly the validity period.
+ std::string cert_data;
+ ASSERT_TRUE(net::x509_util::CreateSelfSignedCert(
+ private_key->key(), net::x509_util::DIGEST_SHA256, "CN=test",
+ i * 10 + required_scts, start, end, {}, &cert_data));
+ scoped_refptr<X509Certificate> cert(X509Certificate::CreateFromBytes(
+ base::as_bytes(base::make_span(cert_data))));
+ ASSERT_TRUE(cert);
+
+ for (size_t j = 0; j < required_scts - 1; ++j) {
+ SCTList scts;
+ FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_EMBEDDED, j,
+ std::vector<std::string>(), false, &scts);
+ EXPECT_EQ(CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS,
+ policy_enforcer_->CheckCompliance(cert.get(), scts,
+ NetLogWithSource()))
+ << " for: " << (end - start).InDays() << " and " << required_scts
+ << " scts=" << scts.size() << " j=" << j;
+ }
+ SCTList scts;
+ FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_EMBEDDED,
+ required_scts, std::vector<std::string>(), false,
+ &scts);
+ EXPECT_EQ(
+ CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS,
+ policy_enforcer_->CheckCompliance(cert.get(), scts, NetLogWithSource()))
+ << " for: " << (end - start).InDays() << " and " << required_scts
+ << " scts=" << scts.size();
+ }
}
-TEST_F(ChromeCTPolicyEnforcerTest, ConformsToCTPolicyWithPooledEmbeddedSCTs) {
+TEST_F(ChromeCTPolicyEnforcerTestPre2022Policy,
+ DoesNotConformToCTPolicyNotEnoughUniqueEmbeddedLogs) {
SCTList scts;
std::vector<std::string> desired_logs;
- // One Google log, delivered embedded.
+ // One Google Log.
desired_logs.clear();
desired_logs.push_back(google_log_id_);
FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_EMBEDDED,
desired_logs.size(), desired_logs, true, &scts);
- // One non-Google log, delivered via OCSP.
+ // Two distinct non-Google logs.
desired_logs.clear();
- desired_logs.push_back(non_google_log_id_);
- FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_FROM_OCSP_RESPONSE,
+ desired_logs.emplace_back(crypto::kSHA256Length, 'A');
+ desired_logs.emplace_back(crypto::kSHA256Length, 'B');
+ FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_EMBEDDED,
desired_logs.size(), desired_logs, true, &scts);
- EXPECT_EQ(CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS,
- policy_enforcer_->CheckCompliance(chain_.get(), scts,
- NetLogWithSource()));
-}
+ // Two unique SCTs from the same non-Google log.
+ desired_logs.clear();
+ desired_logs.emplace_back(crypto::kSHA256Length, 'C');
+ desired_logs.emplace_back(crypto::kSHA256Length, 'C');
+ FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_EMBEDDED,
+ desired_logs.size(), desired_logs, true, &scts);
-TEST_F(ChromeCTPolicyEnforcerTest, DoesNotConformToCTPolicyNotEnoughSCTs) {
// |chain_| is valid for 10 years - over 121 months - so requires 5 SCTs.
- SCTList scts;
- FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_EMBEDDED, 2, &scts);
-
+ // However, there are only 4 SCTs are from distinct logs.
EXPECT_EQ(CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS,
policy_enforcer_->CheckCompliance(chain_.get(), scts,
NetLogWithSource()));
}
-TEST_F(ChromeCTPolicyEnforcerTest, DoesNotConformToCTPolicyNotEnoughFreshSCTs) {
+TEST_F(ChromeCTPolicyEnforcerTestPre2022Policy,
+ DoesNotConformToCTPolicyNotEnoughFreshSCTs) {
SCTList scts;
// The results should be the same before and after disqualification,
@@ -315,231 +376,403 @@ TEST_F(ChromeCTPolicyEnforcerTest, DoesNotConformToCTPolicyNotEnoughFreshSCTs) {
NetLogWithSource()));
}
-TEST_F(ChromeCTPolicyEnforcerTest,
- ConformsWithDisqualifiedLogBeforeDisqualificationDate) {
+// Subclass of ChromeCTPolicyEnforcerTest that tests both with the pre-2022
+// policy and the 2022 policy.
+class ChromeCTPolicyEnforcerTestBothPolicies
+ : public ChromeCTPolicyEnforcerTest,
+ public ::testing::WithParamInterface<bool> {
+ public:
+ void SetUp() override {
+ if (GetParam()) {
+ scoped_feature_list_.InitAndEnableFeature(
+ features::kCertificateTransparency2022PolicyAllCerts);
+ } else {
+ scoped_feature_list_.InitWithFeatures(
+ /*enabled_features*/ {},
+ /*disabled_features*/ {
+ features::kCertificateTransparency2022Policy,
+ features::kCertificateTransparency2022PolicyAllCerts});
+ }
+ ChromeCTPolicyEnforcerTest::SetUp();
+ }
+};
+
+TEST_P(ChromeCTPolicyEnforcerTestBothPolicies,
+ ConformsToCTPolicyWithNonEmbeddedSCTs) {
SCTList scts;
- FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_EMBEDDED, 4, &scts);
- AddDisqualifiedLogSCT(SignedCertificateTimestamp::SCT_EMBEDDED, false, &scts);
+ FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_FROM_TLS_EXTENSION,
+ 2, &scts);
+ if (GetParam()) {
+ std::map<std::string, OperatorHistoryEntry> operator_history;
+ FillOperatorHistoryWithDiverseOperators(scts, &operator_history);
+ policy_enforcer_->SetOperatorHistoryForTesting(operator_history);
+ }
- // |chain_| is valid for 10 years - over 121 months - so requires 5 SCTs.
EXPECT_EQ(CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS,
policy_enforcer_->CheckCompliance(chain_.get(), scts,
NetLogWithSource()));
}
-TEST_F(ChromeCTPolicyEnforcerTest,
- DoesNotConformWithDisqualifiedLogAfterDisqualificationDate) {
+TEST_P(ChromeCTPolicyEnforcerTestBothPolicies, EnforcementDisabledByBinaryAge) {
SCTList scts;
- FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_EMBEDDED, 4, &scts);
- AddDisqualifiedLogSCT(SignedCertificateTimestamp::SCT_EMBEDDED, true, &scts);
+ FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_FROM_TLS_EXTENSION,
+ 2, &scts);
+ if (GetParam()) {
+ std::map<std::string, OperatorHistoryEntry> operator_history;
+ FillOperatorHistoryWithDiverseOperators(scts, &operator_history);
+ policy_enforcer_->SetOperatorHistoryForTesting(operator_history);
+ }
- // |chain_| is valid for 10 years - over 121 months - so requires 5 SCTs.
- EXPECT_EQ(CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS,
+ EXPECT_EQ(CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS,
+ policy_enforcer_->CheckCompliance(chain_.get(), scts,
+ NetLogWithSource()));
+
+ clock_.Advance(base::Days(71));
+
+ EXPECT_EQ(CTPolicyCompliance::CT_POLICY_BUILD_NOT_TIMELY,
policy_enforcer_->CheckCompliance(chain_.get(), scts,
NetLogWithSource()));
}
-TEST_F(ChromeCTPolicyEnforcerTest,
- DoesNotConformWithIssuanceDateAfterDisqualificationDate) {
+TEST_P(ChromeCTPolicyEnforcerTestBothPolicies,
+ ConformsToCTPolicyWithEmbeddedSCTs) {
+ // |chain_| is valid for 10 years - over 121 months - so requires 5 SCTs.
SCTList scts;
- AddDisqualifiedLogSCT(SignedCertificateTimestamp::SCT_EMBEDDED, true, &scts);
- FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_EMBEDDED, 4, &scts);
- // Make sure all SCTs are after the disqualification date.
- for (size_t i = 1; i < scts.size(); ++i)
- scts[i]->timestamp = scts[0]->timestamp;
+ FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_EMBEDDED, 5, &scts);
+ if (GetParam()) {
+ std::map<std::string, OperatorHistoryEntry> operator_history;
+ FillOperatorHistoryWithDiverseOperators(scts, &operator_history);
+ policy_enforcer_->SetOperatorHistoryForTesting(operator_history);
+ }
- // |chain_| is valid for 10 years - over 121 months - so requires 5 SCTs.
- EXPECT_EQ(CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS,
+ EXPECT_EQ(CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS,
policy_enforcer_->CheckCompliance(chain_.get(), scts,
NetLogWithSource()));
}
-TEST_F(ChromeCTPolicyEnforcerTest,
- DoesNotConformToCTPolicyNotEnoughUniqueEmbeddedLogs) {
+TEST_P(ChromeCTPolicyEnforcerTestBothPolicies,
+ ConformsToCTPolicyWithPooledNonEmbeddedSCTs) {
SCTList scts;
std::vector<std::string> desired_logs;
- // One Google Log.
+ // One Google log, delivered via OCSP.
desired_logs.clear();
desired_logs.push_back(google_log_id_);
- FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_EMBEDDED,
- desired_logs.size(), desired_logs, true, &scts);
-
- // Two distinct non-Google logs.
- desired_logs.clear();
- desired_logs.push_back(std::string(crypto::kSHA256Length, 'A'));
- desired_logs.push_back(std::string(crypto::kSHA256Length, 'B'));
- FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_EMBEDDED,
+ FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_FROM_OCSP_RESPONSE,
desired_logs.size(), desired_logs, true, &scts);
- // Two unique SCTs from the same non-Google log.
+ // One non-Google log, delivered via TLS.
desired_logs.clear();
- desired_logs.push_back(std::string(crypto::kSHA256Length, 'C'));
- desired_logs.push_back(std::string(crypto::kSHA256Length, 'C'));
- FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_EMBEDDED,
+ desired_logs.push_back(non_google_log_id_);
+ FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_FROM_TLS_EXTENSION,
desired_logs.size(), desired_logs, true, &scts);
+ if (GetParam()) {
+ std::map<std::string, OperatorHistoryEntry> operator_history;
+ FillOperatorHistoryWithDiverseOperators(scts, &operator_history);
+ policy_enforcer_->SetOperatorHistoryForTesting(operator_history);
+ }
- // |chain_| is valid for 10 years - over 121 months - so requires 5 SCTs.
- // However, there are only 4 SCTs are from distinct logs.
- EXPECT_EQ(CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS,
+ EXPECT_EQ(CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS,
policy_enforcer_->CheckCompliance(chain_.get(), scts,
NetLogWithSource()));
}
-TEST_F(ChromeCTPolicyEnforcerTest,
- ConformsToPolicyExactNumberOfSCTsForValidityPeriod) {
- std::unique_ptr<crypto::RSAPrivateKey> private_key(
- crypto::RSAPrivateKey::Create(1024));
- ASSERT_TRUE(private_key);
+TEST_P(ChromeCTPolicyEnforcerTestBothPolicies,
+ ConformsToCTPolicyWithPooledEmbeddedSCTs) {
+ SCTList scts;
+ std::vector<std::string> desired_logs;
- // Test multiple validity periods
- base::Time time_2015_3_0_25_11_25_0_0 =
- CreateTime({2015, 3, 0, 25, 11, 25, 0, 0});
+ // One Google log, delivered embedded.
+ desired_logs.clear();
+ desired_logs.push_back(google_log_id_);
+ FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_EMBEDDED,
+ desired_logs.size(), desired_logs, true, &scts);
- base::Time time_2016_6_0_6_11_25_0_0 =
- CreateTime({2016, 6, 0, 6, 11, 25, 0, 0});
+ // One non-Google log, delivered via OCSP.
+ desired_logs.clear();
+ desired_logs.push_back(non_google_log_id_);
+ FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_FROM_OCSP_RESPONSE,
+ desired_logs.size(), desired_logs, true, &scts);
- base::Time time_2016_6_0_25_11_25_0_0 =
- CreateTime({2016, 6, 0, 25, 11, 25, 0, 0});
+ if (GetParam()) {
+ std::map<std::string, OperatorHistoryEntry> operator_history;
+ FillOperatorHistoryWithDiverseOperators(scts, &operator_history);
+ policy_enforcer_->SetOperatorHistoryForTesting(operator_history);
+ }
- base::Time time_2016_6_0_27_11_25_0_0 =
- CreateTime({2016, 6, 0, 27, 11, 25, 0, 0});
+ EXPECT_EQ(CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS,
+ policy_enforcer_->CheckCompliance(chain_.get(), scts,
+ NetLogWithSource()));
+}
- base::Time time_2017_6_0_25_11_25_0_0 =
- CreateTime({2017, 6, 0, 25, 11, 25, 0, 0});
+TEST_P(ChromeCTPolicyEnforcerTestBothPolicies,
+ DoesNotConformToCTPolicyNotEnoughSCTs) {
+ // |chain_| is valid for 10 years - over 121 months - so requires 5 SCTs.
+ SCTList scts;
+ FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_EMBEDDED, 2, &scts);
+ if (GetParam()) {
+ std::map<std::string, OperatorHistoryEntry> operator_history;
+ FillOperatorHistoryWithDiverseOperators(scts, &operator_history);
+ policy_enforcer_->SetOperatorHistoryForTesting(operator_history);
+ }
- base::Time time_2017_6_0_28_11_25_0_0 =
- CreateTime({2017, 6, 0, 28, 11, 25, 0, 0});
+ EXPECT_EQ(CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS,
+ policy_enforcer_->CheckCompliance(chain_.get(), scts,
+ NetLogWithSource()));
+}
- base::Time time_2018_6_0_25_11_25_0_0 =
- CreateTime({2018, 6, 0, 25, 11, 25, 0, 0});
+TEST_P(ChromeCTPolicyEnforcerTestBothPolicies,
+ ConformsWithDisqualifiedLogBeforeDisqualificationDate) {
+ SCTList scts;
+ FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_EMBEDDED, 4, &scts);
+ AddDisqualifiedLogSCT(SignedCertificateTimestamp::SCT_EMBEDDED, false, &scts);
+ if (GetParam()) {
+ std::map<std::string, OperatorHistoryEntry> operator_history;
+ FillOperatorHistoryWithDiverseOperators(scts, &operator_history);
+ policy_enforcer_->SetOperatorHistoryForTesting(operator_history);
+ }
- base::Time time_2018_6_0_27_11_25_0_0 =
- CreateTime({2018, 6, 0, 27, 11, 25, 0, 0});
+ // |chain_| is valid for 10 years - over 121 months - so requires 5 SCTs.
+ EXPECT_EQ(CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS,
+ policy_enforcer_->CheckCompliance(chain_.get(), scts,
+ NetLogWithSource()));
+}
- const struct TestData {
- base::Time validity_start;
- base::Time validity_end;
- size_t scts_required;
- } kTestData[] = {{// Cert valid for -14 months (nonsensical), needs 2 SCTs.
- time_2016_6_0_6_11_25_0_0, time_2015_3_0_25_11_25_0_0, 2},
- {// Cert valid for 14 months, needs 2 SCTs.
- time_2015_3_0_25_11_25_0_0, time_2016_6_0_6_11_25_0_0, 2},
- {// Cert valid for exactly 15 months, needs 3 SCTs.
- time_2015_3_0_25_11_25_0_0, time_2016_6_0_25_11_25_0_0, 3},
- {// Cert valid for over 15 months, needs 3 SCTs.
- time_2015_3_0_25_11_25_0_0, time_2016_6_0_27_11_25_0_0, 3},
- {// Cert valid for exactly 27 months, needs 3 SCTs.
- time_2015_3_0_25_11_25_0_0, time_2017_6_0_25_11_25_0_0, 3},
- {// Cert valid for over 27 months, needs 4 SCTs.
- time_2015_3_0_25_11_25_0_0, time_2017_6_0_28_11_25_0_0, 4},
- {// Cert valid for exactly 39 months, needs 4 SCTs.
- time_2015_3_0_25_11_25_0_0, time_2018_6_0_25_11_25_0_0, 4},
- {// Cert valid for over 39 months, needs 5 SCTs.
- time_2015_3_0_25_11_25_0_0, time_2018_6_0_27_11_25_0_0, 5}};
+TEST_P(ChromeCTPolicyEnforcerTestBothPolicies,
+ DoesNotConformWithDisqualifiedLogAfterDisqualificationDate) {
+ SCTList scts;
+ // Add required - 1 valid SCTs (with the old policy 5 are required, with the
+ // new policy 3).
+ FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_EMBEDDED,
+ GetParam() ? 2 : 4, &scts);
+ AddDisqualifiedLogSCT(SignedCertificateTimestamp::SCT_EMBEDDED, true, &scts);
+ if (GetParam()) {
+ std::map<std::string, OperatorHistoryEntry> operator_history;
+ FillOperatorHistoryWithDiverseOperators(scts, &operator_history);
+ policy_enforcer_->SetOperatorHistoryForTesting(operator_history);
+ }
- for (size_t i = 0; i < base::size(kTestData); ++i) {
- SCOPED_TRACE(i);
- const base::Time& start = kTestData[i].validity_start;
- const base::Time& end = kTestData[i].validity_end;
- size_t required_scts = kTestData[i].scts_required;
+ // |chain_| is valid for 10 years - over 121 months - so requires 5 SCTs.
+ EXPECT_EQ(CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS,
+ policy_enforcer_->CheckCompliance(chain_.get(), scts,
+ NetLogWithSource()));
+}
- // Create a self-signed certificate with exactly the validity period.
- std::string cert_data;
- ASSERT_TRUE(net::x509_util::CreateSelfSignedCert(
- private_key->key(), net::x509_util::DIGEST_SHA256, "CN=test",
- i * 10 + required_scts, start, end, {}, &cert_data));
- scoped_refptr<X509Certificate> cert(X509Certificate::CreateFromBytes(
- base::as_bytes(base::make_span(cert_data))));
- ASSERT_TRUE(cert);
+TEST_P(ChromeCTPolicyEnforcerTestBothPolicies,
+ DoesNotConformWithIssuanceDateAfterDisqualificationDate) {
+ SCTList scts;
+ AddDisqualifiedLogSCT(SignedCertificateTimestamp::SCT_EMBEDDED, true, &scts);
+ // Add required - 1 valid SCTs (with the old policy 5 are required, with the
+ // new policy 3).
+ FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_EMBEDDED,
+ GetParam() ? 2 : 4, &scts);
+ // Make sure all SCTs are after the disqualification date.
+ for (size_t i = 1; i < scts.size(); ++i)
+ scts[i]->timestamp = scts[0]->timestamp;
- for (size_t j = 0; j < required_scts - 1; ++j) {
- SCTList scts;
- FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_EMBEDDED, j,
- std::vector<std::string>(), false, &scts);
- EXPECT_EQ(CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS,
- policy_enforcer_->CheckCompliance(cert.get(), scts,
- NetLogWithSource()))
- << " for: " << (end - start).InDays() << " and " << required_scts
- << " scts=" << scts.size() << " j=" << j;
- }
- SCTList scts;
- FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_EMBEDDED,
- required_scts, std::vector<std::string>(), false,
- &scts);
- EXPECT_EQ(
- CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS,
- policy_enforcer_->CheckCompliance(cert.get(), scts, NetLogWithSource()))
- << " for: " << (end - start).InDays() << " and " << required_scts
- << " scts=" << scts.size();
+ if (GetParam()) {
+ std::map<std::string, OperatorHistoryEntry> operator_history;
+ FillOperatorHistoryWithDiverseOperators(scts, &operator_history);
+ policy_enforcer_->SetOperatorHistoryForTesting(operator_history);
}
+
+ // |chain_| is valid for 10 years - over 121 months - so requires 5 SCTs.
+ EXPECT_EQ(CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS,
+ policy_enforcer_->CheckCompliance(chain_.get(), scts,
+ NetLogWithSource()));
}
-TEST_F(ChromeCTPolicyEnforcerTest, UpdateCTLogList) {
- ChromeCTPolicyEnforcer* chrome_policy_enforcer =
- static_cast<ChromeCTPolicyEnforcer*>(policy_enforcer_.get());
+TEST_P(ChromeCTPolicyEnforcerTestBothPolicies, UpdateCTLogList) {
SCTList scts;
FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_FROM_TLS_EXTENSION,
2, &scts);
- std::vector<std::pair<std::string, base::TimeDelta>> disqualified_logs;
+ std::vector<std::pair<std::string, base::Time>> disqualified_logs;
std::vector<std::string> operated_by_google_logs;
- chrome_policy_enforcer->UpdateCTLogList(base::Time::Now(), disqualified_logs,
- operated_by_google_logs,
- /*log_operator_history=*/{});
+ std::map<std::string, OperatorHistoryEntry> operator_history;
+ for (auto sct : scts) {
+ OperatorHistoryEntry entry;
+ entry.current_operator_ = "Operator";
+ operator_history[sct->log_id] = entry;
+ }
- // The check should fail since the Google Aviator log is no longer in the
- // list after the update with an empty list.
+ policy_enforcer_->UpdateCTLogList(base::Time::Now(), disqualified_logs,
+ operated_by_google_logs, operator_history);
+
+ // The check should fail with the old policy since the Google Aviator log is
+ // no longer in the list after the update with an empty list, and with the new
+ // policy since all logs have the same operator.
EXPECT_EQ(CTPolicyCompliance::CT_POLICY_NOT_DIVERSE_SCTS,
- chrome_policy_enforcer->CheckCompliance(chain_.get(), scts,
- NetLogWithSource()));
+ policy_enforcer_->CheckCompliance(chain_.get(), scts,
+ NetLogWithSource()));
// Update the list again, this time including all the known operated by Google
- // logs.
+ // logs, and setting operators to different values.
operated_by_google_logs = certificate_transparency::GetLogsOperatedByGoogle();
- chrome_policy_enforcer->UpdateCTLogList(base::Time::Now(), disqualified_logs,
- operated_by_google_logs,
- /*log_operator_history=*/{});
+ FillOperatorHistoryWithDiverseOperators(scts, &operator_history);
+ policy_enforcer_->UpdateCTLogList(base::Time::Now(), disqualified_logs,
+ operated_by_google_logs, operator_history);
// The check should now succeed.
EXPECT_EQ(CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS,
- chrome_policy_enforcer->CheckCompliance(chain_.get(), scts,
- NetLogWithSource()));
+ policy_enforcer_->CheckCompliance(chain_.get(), scts,
+ NetLogWithSource()));
}
-TEST_F(ChromeCTPolicyEnforcerTest, TimestampUpdates) {
- ChromeCTPolicyEnforcer* chrome_policy_enforcer =
- static_cast<ChromeCTPolicyEnforcer*>(policy_enforcer_.get());
+TEST_P(ChromeCTPolicyEnforcerTestBothPolicies, TimestampUpdates) {
SCTList scts;
FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_FROM_TLS_EXTENSION,
- 2, &scts);
+ 1, &scts);
// Clear the log list and set the last updated time to more than 10 weeks ago.
- std::vector<std::pair<std::string, base::TimeDelta>> disqualified_logs;
+ std::vector<std::pair<std::string, base::Time>> disqualified_logs;
std::vector<std::string> operated_by_google_logs;
std::map<std::string, OperatorHistoryEntry> log_operator_history;
- chrome_policy_enforcer->UpdateCTLogList(
- base::Time::Now() - base::Days(71), disqualified_logs,
- operated_by_google_logs, log_operator_history);
+ FillOperatorHistoryWithDiverseOperators(scts, &log_operator_history);
- // The check should return build not timely even though the Google Aviator log
- // is no longer in the list, since the last update time is greater than 10
- // weeks.
+ policy_enforcer_->UpdateCTLogList(base::Time::Now() - base::Days(71),
+ disqualified_logs, operated_by_google_logs,
+ log_operator_history);
+
+ // The check should return build not timely even though there are not enough
+ // SCTs.
EXPECT_EQ(CTPolicyCompliance::CT_POLICY_BUILD_NOT_TIMELY,
- chrome_policy_enforcer->CheckCompliance(chain_.get(), scts,
- NetLogWithSource()));
+ policy_enforcer_->CheckCompliance(chain_.get(), scts,
+ NetLogWithSource()));
// Update the last update time value again, this time with a recent time.
- chrome_policy_enforcer->UpdateCTLogList(base::Time::Now(), disqualified_logs,
- operated_by_google_logs,
- log_operator_history);
+ policy_enforcer_->UpdateCTLogList(base::Time::Now(), disqualified_logs,
+ operated_by_google_logs,
+ log_operator_history);
// The check should now fail
EXPECT_EQ(CTPolicyCompliance::CT_POLICY_NOT_DIVERSE_SCTS,
- chrome_policy_enforcer->CheckCompliance(chain_.get(), scts,
- NetLogWithSource()));
+ policy_enforcer_->CheckCompliance(chain_.get(), scts,
+ NetLogWithSource()));
+}
+
+TEST_P(ChromeCTPolicyEnforcerTestBothPolicies, IsLogDisqualifiedTimestamp) {
+ // Clear the log list and add 2 disqualified logs, one with a disqualification
+ // date in the past and one in the future.
+ // The actual logs are irrelevant for this test, so we use Aviator for the one
+ // disqualified in the past, and a modified version of it for disqualified in
+ // the future.
+ const char kModifiedGoogleAviatorLogID[] =
+ "\x68\xf6\x98\xf8\x1f\x64\x82\xbe\x3a\x8c\xee\xb9\x28\x1d\x4c\xfc\x71\x51"
+ "\x5d\x67\x93\xd4\x44\xd1\x0a\x67\xac\xbb\x4f\x4f\x4f\xf4";
+ std::vector<std::pair<std::string, base::Time>> disqualified_logs;
+ std::vector<std::string> operated_by_google_logs;
+ std::map<std::string, OperatorHistoryEntry> log_operator_history;
+ base::Time past_disqualification = base::Time::Now() - base::Hours(1);
+ base::Time future_disqualification = base::Time::Now() + base::Hours(1);
+ disqualified_logs.emplace_back(kModifiedGoogleAviatorLogID,
+ future_disqualification);
+ disqualified_logs.emplace_back(kGoogleAviatorLogID, past_disqualification);
+ policy_enforcer_->UpdateCTLogList(base::Time::Now(), disqualified_logs,
+ operated_by_google_logs,
+ log_operator_history);
+
+ base::Time disqualification_time;
+ EXPECT_TRUE(policy_enforcer_->IsLogDisqualified(kGoogleAviatorLogID,
+ &disqualification_time));
+ EXPECT_EQ(disqualification_time, past_disqualification);
+ EXPECT_FALSE(policy_enforcer_->IsLogDisqualified(kModifiedGoogleAviatorLogID,
+ &disqualification_time));
+ EXPECT_EQ(disqualification_time, future_disqualification);
}
+TEST_P(ChromeCTPolicyEnforcerTestBothPolicies,
+ IsLogDisqualifiedReturnsFalseOnUnknownLog) {
+ // Clear the log list and add a single disqualified log, with a
+ // disqualification date in the past;
+ const char kModifiedGoogleAviatorLogID[] =
+ "\x68\xf6\x98\xf8\x1f\x64\x82\xbe\x3a\x8c\xee\xb9\x28\x1d\x4c\xfc\x71\x51"
+ "\x5d\x67\x93\xd4\x44\xd1\x0a\x67\xac\xbb\x4f\x4f\x4f\xf4";
+ std::vector<std::pair<std::string, base::Time>> disqualified_logs;
+ std::vector<std::string> operated_by_google_logs;
+ std::map<std::string, OperatorHistoryEntry> log_operator_history;
+ disqualified_logs.emplace_back(kModifiedGoogleAviatorLogID,
+ base::Time::Now() - base::Days(1));
+ policy_enforcer_->UpdateCTLogList(base::Time::Now(), disqualified_logs,
+ operated_by_google_logs,
+ log_operator_history);
+
+ base::Time unused;
+ // IsLogDisqualified should return false for a log that is not in the
+ // disqualified list.
+ EXPECT_FALSE(
+ policy_enforcer_->IsLogDisqualified(kGoogleAviatorLogID, &unused));
+}
+
+TEST_P(ChromeCTPolicyEnforcerTestBothPolicies,
+ ConformsWithCTPolicyFutureRetirementDateLogs) {
+ SCTList scts;
+ FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_EMBEDDED, 5, &scts);
+
+ std::vector<std::pair<std::string, base::Time>> disqualified_logs;
+ std::vector<std::string> operated_by_google_logs = {google_log_id_};
+ std::map<std::string, OperatorHistoryEntry> log_operator_history;
+ FillOperatorHistoryWithDiverseOperators(scts, &log_operator_history);
+
+ // Set all the log operators for these SCTs as disqualified, with a timestamp
+ // one hour from now.
+ base::Time retirement_time = base::Time::Now() + base::Hours(1);
+ // This mirrors how FillListWithSCTsOfOrigin generates log ids.
+ disqualified_logs.emplace_back(google_log_id_, retirement_time);
+ for (size_t i = 1; i < 5; ++i) {
+ disqualified_logs.emplace_back(
+ std::string(crypto::kSHA256Length, static_cast<char>(i)),
+ retirement_time);
+ }
+ std::sort(std::begin(disqualified_logs), std::end(disqualified_logs));
+
+ policy_enforcer_->UpdateCTLogList(base::Time::Now(), disqualified_logs,
+ operated_by_google_logs,
+ log_operator_history);
+
+ // SCTs should comply since retirement date is in the future.
+ EXPECT_EQ(CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS,
+ policy_enforcer_->CheckCompliance(chain_.get(), scts,
+ NetLogWithSource()));
+}
+
+TEST_P(ChromeCTPolicyEnforcerTestBothPolicies,
+ DoesNotConformWithCTPolicyPastRetirementDateLogs) {
+ SCTList scts;
+ FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_EMBEDDED, 5, &scts);
+
+ std::vector<std::pair<std::string, base::Time>> disqualified_logs;
+ std::vector<std::string> operated_by_google_logs = {google_log_id_};
+ std::map<std::string, OperatorHistoryEntry> log_operator_history;
+
+ // Set all the log operators for these SCTs as disqualiied, with a timestamp
+ // one hour ago.
+ base::Time retirement_time = base::Time::Now() - base::Hours(1);
+ // This mirrors how FillListWithSCTsOfOrigin generates log ids.
+ disqualified_logs.emplace_back(google_log_id_, retirement_time);
+ for (size_t i = 1; i < 5; ++i) {
+ disqualified_logs.emplace_back(
+ std::string(crypto::kSHA256Length, static_cast<char>(i)),
+ retirement_time);
+ }
+ std::sort(std::begin(disqualified_logs), std::end(disqualified_logs));
+
+ FillOperatorHistoryWithDiverseOperators(scts, &log_operator_history);
+
+ policy_enforcer_->UpdateCTLogList(base::Time::Now(), disqualified_logs,
+ operated_by_google_logs,
+ log_operator_history);
+
+ // SCTs should not comply since retirement date is in the past.
+ EXPECT_EQ(CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS,
+ policy_enforcer_->CheckCompliance(chain_.get(), scts,
+ NetLogWithSource()));
+}
+
+INSTANTIATE_TEST_SUITE_P(All,
+ ChromeCTPolicyEnforcerTestBothPolicies,
+ testing::Bool());
+
class ChromeCTPolicyEnforcerTest2022Policy : public ChromeCTPolicyEnforcerTest {
public:
void SetUp() override {
@@ -547,29 +780,22 @@ class ChromeCTPolicyEnforcerTest2022Policy : public ChromeCTPolicyEnforcerTest {
features::kCertificateTransparency2022Policy);
ChromeCTPolicyEnforcerTest::SetUp();
}
-
- private:
- base::test::ScopedFeatureList scoped_feature_list_;
};
TEST_F(ChromeCTPolicyEnforcerTest2022Policy,
2022PolicyNotInEffectBeforeTargetDate) {
// Old policy should enforce one Google log requirement.
- ChromeCTPolicyEnforcer* chrome_policy_enforcer =
- static_cast<ChromeCTPolicyEnforcer*>(policy_enforcer_.get());
SCTList scts;
FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_FROM_TLS_EXTENSION,
2, std::vector<std::string>(), true, &scts);
std::map<std::string, OperatorHistoryEntry> operator_history;
- for (size_t i = 0; i < scts.size(); i++) {
- OperatorHistoryEntry entry;
- entry.current_operator_ = "Operator " + base::NumberToString(i);
- operator_history[scts[i]->log_id] = entry;
+ FillOperatorHistoryWithDiverseOperators(scts, &operator_history);
+ for (auto sct : scts) {
// Set timestamp to 1 day before new policy comes in effect.
- EXPECT_TRUE(base::Time::FromUTCExploded({2022, 1, 0, 31, 0, 0, 0, 0},
- &scts[i]->timestamp));
+ EXPECT_TRUE(base::Time::FromUTCExploded({2022, 4, 0, 14, 0, 0, 0, 0},
+ &sct->timestamp));
}
- chrome_policy_enforcer->SetOperatorHistoryForTesting(operator_history);
+ policy_enforcer_->SetOperatorHistoryForTesting(operator_history);
EXPECT_EQ(CTPolicyCompliance::CT_POLICY_NOT_DIVERSE_SCTS,
policy_enforcer_->CheckCompliance(chain_.get(), scts,
@@ -580,21 +806,17 @@ TEST_F(ChromeCTPolicyEnforcerTest2022Policy,
2022PolicyInEffectAfterTargetDate) {
// New policy should allow SCTs from all non-Google operators to comply as
// long as diversity requirement is fulfilled.
- ChromeCTPolicyEnforcer* chrome_policy_enforcer =
- static_cast<ChromeCTPolicyEnforcer*>(policy_enforcer_.get());
SCTList scts;
FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_FROM_TLS_EXTENSION,
2, std::vector<std::string>(), true, &scts);
std::map<std::string, OperatorHistoryEntry> operator_history;
- for (size_t i = 0; i < scts.size(); i++) {
- OperatorHistoryEntry entry;
- entry.current_operator_ = "Operator " + base::NumberToString(i);
- operator_history[scts[i]->log_id] = entry;
+ FillOperatorHistoryWithDiverseOperators(scts, &operator_history);
+ for (auto sct : scts) {
// Set timestamp to the day new policy comes in effect.
- EXPECT_TRUE(base::Time::FromUTCExploded({2022, 2, 0, 1, 0, 0, 0, 0},
- &scts[i]->timestamp));
+ EXPECT_TRUE(base::Time::FromUTCExploded({2022, 4, 0, 15, 0, 0, 0, 0},
+ &sct->timestamp));
}
- chrome_policy_enforcer->SetOperatorHistoryForTesting(operator_history);
+ policy_enforcer_->SetOperatorHistoryForTesting(operator_history);
EXPECT_EQ(CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS,
policy_enforcer_->CheckCompliance(chain_.get(), scts,
@@ -609,15 +831,9 @@ class ChromeCTPolicyEnforcerTest2022PolicyAllCerts
features::kCertificateTransparency2022PolicyAllCerts);
ChromeCTPolicyEnforcerTest::SetUp();
}
-
- private:
- base::test::ScopedFeatureList scoped_feature_list_;
};
TEST_F(ChromeCTPolicyEnforcerTest2022PolicyAllCerts, UpdatedSCTRequirements) {
- ChromeCTPolicyEnforcer* chrome_policy_enforcer =
- static_cast<ChromeCTPolicyEnforcer*>(policy_enforcer_.get());
-
std::unique_ptr<crypto::RSAPrivateKey> private_key(
crypto::RSAPrivateKey::Create(1024));
ASSERT_TRUE(private_key);
@@ -632,6 +848,9 @@ TEST_F(ChromeCTPolicyEnforcerTest2022PolicyAllCerts, UpdatedSCTRequirements) {
base::Time time_2015_9_0_21_11_25_0_0 =
CreateTime({2015, 9, 0, 21, 11, 25, 0, 0});
+ base::Time time_2015_9_0_21_11_25_1_0 =
+ CreateTime({2015, 9, 0, 21, 11, 25, 1, 0});
+
base::Time time_2016_3_0_25_11_25_0_0 =
CreateTime({2016, 3, 0, 25, 11, 25, 0, 0});
@@ -643,8 +862,10 @@ TEST_F(ChromeCTPolicyEnforcerTest2022PolicyAllCerts, UpdatedSCTRequirements) {
time_2016_3_0_25_11_25_0_0, time_2015_3_0_25_11_25_0_0, 2},
{// Cert valid for 179 days, needs 2 SCTs.
time_2015_3_0_25_11_25_0_0, time_2015_9_0_20_11_25_0_0, 2},
- {// Cert valid for exactly 180 days, needs 3 SCTs.
- time_2015_3_0_25_11_25_0_0, time_2015_9_0_21_11_25_0_0, 3},
+ {// Cert valid for exactly 180 days, needs only 2 SCTs.
+ time_2015_3_0_25_11_25_0_0, time_2015_9_0_21_11_25_0_0, 2},
+ {// Cert valid for barely over 180 days, needs 3 SCTs.
+ time_2015_3_0_25_11_25_0_0, time_2015_9_0_21_11_25_1_0, 3},
{// Cert valid for over 180 days, needs 3 SCTs.
time_2015_3_0_25_11_25_0_0, time_2016_3_0_25_11_25_0_0, 3}};
@@ -664,18 +885,14 @@ TEST_F(ChromeCTPolicyEnforcerTest2022PolicyAllCerts, UpdatedSCTRequirements) {
ASSERT_TRUE(cert);
std::map<std::string, OperatorHistoryEntry> operator_history;
- for (size_t j = 0; j <= scts_required - 1; ++j) {
+ for (size_t j = 0; j <= scts_required; ++j) {
SCTList scts;
FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_EMBEDDED, j,
std::vector<std::string>(), false, &scts);
// Add different operators to the logs so the SCTs comply with operator
// diversity.
- for (size_t k = 0; k < scts.size(); k++) {
- OperatorHistoryEntry entry;
- entry.current_operator_ = "Operator " + base::NumberToString(k);
- operator_history[scts[k]->log_id] = entry;
- }
- chrome_policy_enforcer->SetOperatorHistoryForTesting(operator_history);
+ FillOperatorHistoryWithDiverseOperators(scts, &operator_history);
+ policy_enforcer_->SetOperatorHistoryForTesting(operator_history);
CTPolicyCompliance expected;
if (j == scts_required) {
// If the scts provided are as many as are required, the cert should be
@@ -698,18 +915,16 @@ TEST_F(ChromeCTPolicyEnforcerTest2022PolicyAllCerts, UpdatedSCTRequirements) {
TEST_F(ChromeCTPolicyEnforcerTest2022PolicyAllCerts,
DoesNotConformToCTPolicyAllLogsSameOperator) {
- ChromeCTPolicyEnforcer* chrome_policy_enforcer =
- static_cast<ChromeCTPolicyEnforcer*>(policy_enforcer_.get());
SCTList scts;
FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_FROM_TLS_EXTENSION,
2, std::vector<std::string>(), true, &scts);
std::map<std::string, OperatorHistoryEntry> operator_history;
- for (size_t i = 0; i < scts.size(); i++) {
+ for (auto sct : scts) {
OperatorHistoryEntry entry;
entry.current_operator_ = "Operator";
- operator_history[scts[i]->log_id] = entry;
+ operator_history[sct->log_id] = entry;
}
- chrome_policy_enforcer->SetOperatorHistoryForTesting(operator_history);
+ policy_enforcer_->SetOperatorHistoryForTesting(operator_history);
EXPECT_EQ(CTPolicyCompliance::CT_POLICY_NOT_DIVERSE_SCTS,
policy_enforcer_->CheckCompliance(chain_.get(), scts,
@@ -718,18 +933,12 @@ TEST_F(ChromeCTPolicyEnforcerTest2022PolicyAllCerts,
TEST_F(ChromeCTPolicyEnforcerTest2022PolicyAllCerts,
ConformsToCTPolicyDifferentOperators) {
- ChromeCTPolicyEnforcer* chrome_policy_enforcer =
- static_cast<ChromeCTPolicyEnforcer*>(policy_enforcer_.get());
SCTList scts;
FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_FROM_TLS_EXTENSION,
2, std::vector<std::string>(), true, &scts);
std::map<std::string, OperatorHistoryEntry> operator_history;
- for (size_t i = 0; i < scts.size(); i++) {
- OperatorHistoryEntry entry;
- entry.current_operator_ = "Operator " + base::NumberToString(i);
- operator_history[scts[i]->log_id] = entry;
- }
- chrome_policy_enforcer->SetOperatorHistoryForTesting(operator_history);
+ FillOperatorHistoryWithDiverseOperators(scts, &operator_history);
+ policy_enforcer_->SetOperatorHistoryForTesting(operator_history);
EXPECT_EQ(CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS,
policy_enforcer_->CheckCompliance(chain_.get(), scts,
@@ -738,8 +947,6 @@ TEST_F(ChromeCTPolicyEnforcerTest2022PolicyAllCerts,
TEST_F(ChromeCTPolicyEnforcerTest2022PolicyAllCerts,
ConformsToPolicyDueToOperatorSwitch) {
- ChromeCTPolicyEnforcer* chrome_policy_enforcer =
- static_cast<ChromeCTPolicyEnforcer*>(policy_enforcer_.get());
SCTList scts;
FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_FROM_TLS_EXTENSION,
2, std::vector<std::string>(), true, &scts);
@@ -753,9 +960,8 @@ TEST_F(ChromeCTPolicyEnforcerTest2022PolicyAllCerts,
// Set the previous operator of one of the logs to a different one, with an
// end time after the SCT timestamp.
operator_history[scts[1]->log_id].previous_operators_.emplace_back(
- "Different Operator",
- scts[1]->timestamp + base::Seconds(1) - base::Time::UnixEpoch());
- chrome_policy_enforcer->SetOperatorHistoryForTesting(operator_history);
+ "Different Operator", scts[1]->timestamp + base::Seconds(1));
+ policy_enforcer_->SetOperatorHistoryForTesting(operator_history);
EXPECT_EQ(CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS,
policy_enforcer_->CheckCompliance(chain_.get(), scts,
@@ -764,24 +970,18 @@ TEST_F(ChromeCTPolicyEnforcerTest2022PolicyAllCerts,
TEST_F(ChromeCTPolicyEnforcerTest2022PolicyAllCerts,
DoesNotConformToPolicyDueToOperatorSwitch) {
- ChromeCTPolicyEnforcer* chrome_policy_enforcer =
- static_cast<ChromeCTPolicyEnforcer*>(policy_enforcer_.get());
SCTList scts;
FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_FROM_TLS_EXTENSION,
2, std::vector<std::string>(), true, &scts);
std::map<std::string, OperatorHistoryEntry> operator_history;
// Set logs to different operators
- for (size_t i = 0; i < scts.size(); i++) {
- OperatorHistoryEntry entry;
- entry.current_operator_ = "Operator " + base::NumberToString(i);
- operator_history[scts[i]->log_id] = entry;
- }
+ FillOperatorHistoryWithDiverseOperators(scts, &operator_history);
+
// Set the previous operator of one of the logs to the same as the other log,
// with an end time after the SCT timestamp.
operator_history[scts[1]->log_id].previous_operators_.emplace_back(
- "Operator 0",
- scts[1]->timestamp + base::Seconds(1) - base::Time::UnixEpoch());
- chrome_policy_enforcer->SetOperatorHistoryForTesting(operator_history);
+ "Operator 0", scts[1]->timestamp + base::Seconds(1));
+ policy_enforcer_->SetOperatorHistoryForTesting(operator_history);
EXPECT_EQ(CTPolicyCompliance::CT_POLICY_NOT_DIVERSE_SCTS,
policy_enforcer_->CheckCompliance(chain_.get(), scts,
@@ -789,27 +989,19 @@ TEST_F(ChromeCTPolicyEnforcerTest2022PolicyAllCerts,
}
TEST_F(ChromeCTPolicyEnforcerTest2022PolicyAllCerts, MultipleOperatorSwitches) {
- ChromeCTPolicyEnforcer* chrome_policy_enforcer =
- static_cast<ChromeCTPolicyEnforcer*>(policy_enforcer_.get());
SCTList scts;
FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_FROM_TLS_EXTENSION,
2, std::vector<std::string>(), true, &scts);
std::map<std::string, OperatorHistoryEntry> operator_history;
// Set logs to different operators
- for (size_t i = 0; i < scts.size(); i++) {
- OperatorHistoryEntry entry;
- entry.current_operator_ = "Operator " + base::NumberToString(i);
- operator_history[scts[i]->log_id] = entry;
- }
+ FillOperatorHistoryWithDiverseOperators(scts, &operator_history);
// Set multiple previous operators, the first should be ignored since it
// stopped operating before the SCT timestamp.
operator_history[scts[1]->log_id].previous_operators_.emplace_back(
- "Different Operator",
- scts[1]->timestamp - base::Seconds(1) - base::Time::UnixEpoch());
+ "Different Operator", scts[1]->timestamp - base::Seconds(1));
operator_history[scts[1]->log_id].previous_operators_.emplace_back(
- "Operator 0",
- scts[1]->timestamp + base::Seconds(1) - base::Time::UnixEpoch());
- chrome_policy_enforcer->SetOperatorHistoryForTesting(operator_history);
+ "Operator 0", scts[1]->timestamp + base::Seconds(1));
+ policy_enforcer_->SetOperatorHistoryForTesting(operator_history);
EXPECT_EQ(CTPolicyCompliance::CT_POLICY_NOT_DIVERSE_SCTS,
policy_enforcer_->CheckCompliance(chain_.get(), scts,
@@ -818,8 +1010,6 @@ TEST_F(ChromeCTPolicyEnforcerTest2022PolicyAllCerts, MultipleOperatorSwitches) {
TEST_F(ChromeCTPolicyEnforcerTest2022PolicyAllCerts,
MultipleOperatorSwitchesBeforeSCTTimestamp) {
- ChromeCTPolicyEnforcer* chrome_policy_enforcer =
- static_cast<ChromeCTPolicyEnforcer*>(policy_enforcer_.get());
SCTList scts;
FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_FROM_TLS_EXTENSION,
2, std::vector<std::string>(), true, &scts);
@@ -833,18 +1023,14 @@ TEST_F(ChromeCTPolicyEnforcerTest2022PolicyAllCerts,
// Set multiple previous operators, all of them should be ignored since they
// all stopped operating before the SCT timestamp.
operator_history[scts[1]->log_id].previous_operators_.emplace_back(
- "Different Operator",
- scts[1]->timestamp - base::Seconds(2) - base::Time::UnixEpoch());
+ "Different Operator", scts[1]->timestamp - base::Seconds(2));
operator_history[scts[1]->log_id].previous_operators_.emplace_back(
- "Yet Another Different Operator",
- scts[1]->timestamp - base::Seconds(1) - base::Time::UnixEpoch());
- chrome_policy_enforcer->SetOperatorHistoryForTesting(operator_history);
+ "Yet Another Different Operator", scts[1]->timestamp - base::Seconds(1));
+ policy_enforcer_->SetOperatorHistoryForTesting(operator_history);
EXPECT_EQ(CTPolicyCompliance::CT_POLICY_NOT_DIVERSE_SCTS,
policy_enforcer_->CheckCompliance(chain_.get(), scts,
NetLogWithSource()));
}
-} // namespace
-
} // namespace certificate_transparency
diff --git a/chromium/components/certificate_transparency/chrome_require_ct_delegate.cc b/chromium/components/certificate_transparency/chrome_require_ct_delegate.cc
index 3fd0a548609..28b2ef4aba7 100644
--- a/chromium/components/certificate_transparency/chrome_require_ct_delegate.cc
+++ b/chromium/components/certificate_transparency/chrome_require_ct_delegate.cc
@@ -75,7 +75,7 @@ class OrgAttributeFilter {
void AdvanceIfNecessary() {
while (sequence_head_ != sequence_end_) {
while (rdn_it_ != sequence_head_->end()) {
- if (rdn_it_->type == net::TypeOrganizationNameOid())
+ if (rdn_it_->type == net::der::Input(net::kTypeOrganizationNameOid))
return;
++rdn_it_;
}
@@ -100,8 +100,10 @@ bool ParseOrganizationBoundName(net::der::Input dn_without_sequence,
return false;
for (const auto& rdn : *out) {
for (const auto& attribute_type_and_value : rdn) {
- if (attribute_type_and_value.type == net::TypeOrganizationNameOid())
+ if (attribute_type_and_value.type ==
+ net::der::Input(net::kTypeOrganizationNameOid)) {
return true;
+ }
}
}
return false;
diff --git a/chromium/components/certificate_transparency/chrome_require_ct_delegate.h b/chromium/components/certificate_transparency/chrome_require_ct_delegate.h
index 90b6b830cee..8b3fed9bdd6 100644
--- a/chromium/components/certificate_transparency/chrome_require_ct_delegate.h
+++ b/chromium/components/certificate_transparency/chrome_require_ct_delegate.h
@@ -9,6 +9,7 @@
#include <string>
#include <vector>
+#include "base/component_export.h"
#include "base/memory/ref_counted.h"
#include "components/url_matcher/url_matcher.h"
#include "net/base/hash_value.h"
@@ -32,7 +33,7 @@ namespace certificate_transparency {
// To support Enterprise configuration, additional requirements or exceptions
// can be provided via |UpdateCTPolicies()|, which uses the configuration
// syntax documented in pref_names.h for each of the options.
-class ChromeRequireCTDelegate
+class COMPONENT_EXPORT(CERTIFICATE_TRANSPARENCY) ChromeRequireCTDelegate
: public net::TransportSecurityState::RequireCTDelegate {
public:
explicit ChromeRequireCTDelegate();
diff --git a/chromium/components/certificate_transparency/ct_features.cc b/chromium/components/certificate_transparency/ct_features.cc
index ccdb588888d..dc5cbcc3d4d 100644
--- a/chromium/components/certificate_transparency/ct_features.cc
+++ b/chromium/components/certificate_transparency/ct_features.cc
@@ -9,7 +9,7 @@
namespace certificate_transparency {
namespace features {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
const base::Feature kCertificateTransparencyComponentUpdater{
"CertificateTransparencyComponentUpdater",
base::FEATURE_DISABLED_BY_DEFAULT};
@@ -20,7 +20,7 @@ const base::Feature kCertificateTransparencyComponentUpdater{
#endif
const base::Feature kCertificateTransparency2022Policy{
- "CertificateTransparency2022Policy", base::FEATURE_DISABLED_BY_DEFAULT};
+ "CertificateTransparency2022Policy", base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kCertificateTransparency2022PolicyAllCerts{
"CertificateTransparency2022PolicyAllCerts",
diff --git a/chromium/components/certificate_transparency/ct_features.h b/chromium/components/certificate_transparency/ct_features.h
index 79774e1e653..1738fcd2e1e 100644
--- a/chromium/components/certificate_transparency/ct_features.h
+++ b/chromium/components/certificate_transparency/ct_features.h
@@ -5,11 +5,13 @@
#ifndef COMPONENTS_CERTIFICATE_TRANSPARENCY_CT_FEATURES_H_
#define COMPONENTS_CERTIFICATE_TRANSPARENCY_CT_FEATURES_H_
+#include "base/component_export.h"
#include "base/feature_list.h"
namespace certificate_transparency {
namespace features {
+COMPONENT_EXPORT(CERTIFICATE_TRANSPARENCY)
extern const base::Feature kCertificateTransparencyComponentUpdater;
// If enabled, the 2022 CT policy which removes the one Google log
@@ -17,12 +19,14 @@ extern const base::Feature kCertificateTransparencyComponentUpdater;
// the number of embedded SCTs required for certificates with a lifetime over
// 180 days (from 2 to 3) will be used for any certificate issued after February
// 1, 2022.
+COMPONENT_EXPORT(CERTIFICATE_TRANSPARENCY)
extern const base::Feature kCertificateTransparency2022Policy;
// If enabled, the 2022 CT policy which removes the one Google log
// requirement, introduces log operator diversity requirements, and increases
// the number of embedded SCTs required for certificates with a lifetime over
// 180 days (from 2 to 3) will be used for all certificates.
+COMPONENT_EXPORT(CERTIFICATE_TRANSPARENCY)
extern const base::Feature kCertificateTransparency2022PolicyAllCerts;
} // namespace features
diff --git a/chromium/components/certificate_transparency/ct_known_logs.cc b/chromium/components/certificate_transparency/ct_known_logs.cc
index b2698f61be2..fd9e6f1db27 100644
--- a/chromium/components/certificate_transparency/ct_known_logs.cc
+++ b/chromium/components/certificate_transparency/ct_known_logs.cc
@@ -20,7 +20,7 @@ namespace {
} // namespace
base::Time GetLogListTimestamp() {
- return base::Time::UnixEpoch() + kLogListTimestamp;
+ return kLogListTimestamp;
}
std::vector<CTLogInfo> GetKnownLogs() {
@@ -44,8 +44,8 @@ std::vector<std::string> GetLogsOperatedByGoogle() {
return result;
}
-std::vector<std::pair<std::string, base::TimeDelta>> GetDisqualifiedLogs() {
- std::vector<std::pair<std::string, base::TimeDelta>> result;
+std::vector<std::pair<std::string, base::Time>> GetDisqualifiedLogs() {
+ std::vector<std::pair<std::string, base::Time>> result;
for (const auto& log : kDisqualifiedCTLogList) {
result.push_back(
std::make_pair(std::string(log.log_id, crypto::kSHA256Length),
diff --git a/chromium/components/certificate_transparency/ct_known_logs.h b/chromium/components/certificate_transparency/ct_known_logs.h
index 3ba1d101792..8623c11cc40 100644
--- a/chromium/components/certificate_transparency/ct_known_logs.h
+++ b/chromium/components/certificate_transparency/ct_known_logs.h
@@ -7,6 +7,7 @@
#include <vector>
+#include "base/component_export.h"
#include "base/memory/ref_counted.h"
#include "base/strings/string_piece.h"
#include "base/time/time.h"
@@ -19,7 +20,7 @@ struct PreviousOperatorEntry {
const char* const name;
// Time when the operator stopped operating this log, expressed as a TimeDelta
// from the Unix Epoch.
- const base::TimeDelta end_time;
+ const base::Time end_time;
};
struct CTLogInfo {
@@ -39,16 +40,18 @@ struct CTLogInfo {
};
// Returns the time at which the log list was last updated.
-base::Time GetLogListTimestamp();
+COMPONENT_EXPORT(CERTIFICATE_TRANSPARENCY) base::Time GetLogListTimestamp();
// Returns information about all known logs, which includes those that are
// presently qualified for inclusion and logs which were previously qualified,
// but have since been disqualified. To determine the status of a given log
// (via its log ID), use |GetDisqualifiedLogs()|.
+COMPONENT_EXPORT(CERTIFICATE_TRANSPARENCY)
std::vector<CTLogInfo> GetKnownLogs();
// Returns the log IDs of all logs that are operated by Google, sorted. The log
// ID is the SHA-256 hash of the log's |log_key|.
+COMPONENT_EXPORT(CERTIFICATE_TRANSPARENCY)
std::vector<std::string> GetLogsOperatedByGoogle();
// Returns pairs of (log ID, disqualification date) for all disqualified logs,
@@ -59,7 +62,8 @@ std::vector<std::string> GetLogsOperatedByGoogle();
// Any SCTs that are embedded in certificates issued after the disqualification
// date should not be trusted, nor contribute to any uniqueness or freshness
// requirements.
-std::vector<std::pair<std::string, base::TimeDelta>> GetDisqualifiedLogs();
+COMPONENT_EXPORT(CERTIFICATE_TRANSPARENCY)
+std::vector<std::pair<std::string, base::Time>> GetDisqualifiedLogs();
} // namespace certificate_transparency
diff --git a/chromium/components/certificate_transparency/ct_known_logs_unittest.cc b/chromium/components/certificate_transparency/ct_known_logs_unittest.cc
index aedc58d927e..7c1439d54ec 100644
--- a/chromium/components/certificate_transparency/ct_known_logs_unittest.cc
+++ b/chromium/components/certificate_transparency/ct_known_logs_unittest.cc
@@ -26,7 +26,7 @@ TEST(CTKnownLogsTest, GoogleIDsAreSorted) {
}
TEST(CTKnownLogsTest, DisallowedLogsAreSortedByLogID) {
- std::vector<std::pair<std::string, base::TimeDelta>> disqualified_logs =
+ std::vector<std::pair<std::string, base::Time>> disqualified_logs =
GetDisqualifiedLogs();
ASSERT_TRUE(std::is_sorted(
std::begin(disqualified_logs), std::end(disqualified_logs),
diff --git a/chromium/components/certificate_transparency/data/log_list.json b/chromium/components/certificate_transparency/data/log_list.json
index 2c442c57342..e7448754206 100644
--- a/chromium/components/certificate_transparency/data/log_list.json
+++ b/chromium/components/certificate_transparency/data/log_list.json
@@ -1,6 +1,6 @@
{
- "version": "5.8",
- "log_list_timestamp": "2022-02-01T01:37:38Z",
+ "version": "7.51",
+ "log_list_timestamp": "2022-04-29T12:56:40Z",
"operators": [
{
"name": "Google",
@@ -9,22 +9,6 @@
],
"logs": [
{
- "description": "Google 'Argon2021' log",
- "log_id": "9lyUL9F3MCIUVBgIMJRWjuNNExkzv98MLyALzE7xZOM=",
- "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAETeBmZOrzZKo4xYktx9gI2chEce3cw/tbr5xkoQlmhB18aKfsxD+MnILgGNl0FOm0eYGilFVi85wLRIOhK8lxKw==",
- "url": "https://ct.googleapis.com/logs/argon2021/",
- "mmd": 86400,
- "state": {
- "usable": {
- "timestamp": "2018-06-15T02:30:13Z"
- }
- },
- "temporal_interval": {
- "start_inclusive": "2021-01-01T00:00:00Z",
- "end_exclusive": "2022-01-01T00:00:00Z"
- }
- },
- {
"description": "Google 'Argon2022' log",
"log_id": "KXm+8J45OSHwVnOfY6V35b5XfZxgCvj5TV0mXCVdx4Q=",
"key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeIPc6fGmuBg6AJkv/z7NFckmHvf/OqmjchZJ6wm2qN200keRDg352dWpi7CHnSV51BpQYAj1CQY5JuRAwrrDwg==",
@@ -57,22 +41,6 @@
}
},
{
- "description": "Google 'Xenon2021' log",
- "log_id": "fT7y+I//iFVoJMLAyp5SiXkrxQ54CX8uapdomX4i8Nc=",
- "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAER+1MInu8Q39BwDZ5Rp9TwXhwm3ktvgJzpk/r7dDgGk7ZacMm3ljfcoIvP1E72T8jvyLT1bvdapylajZcTH6W5g==",
- "url": "https://ct.googleapis.com/logs/xenon2021/",
- "mmd": 86400,
- "state": {
- "usable": {
- "timestamp": "2019-06-17T21:23:01Z"
- }
- },
- "temporal_interval": {
- "start_inclusive": "2021-01-01T00:00:00Z",
- "end_exclusive": "2022-01-01T00:00:00Z"
- }
- },
- {
"description": "Google 'Xenon2022' log",
"log_id": "RqVV63X6kSAwtaKJafTzfREsQXS+/Um4havy/HD+bUc=",
"key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE+WS9FSxAYlCVEzg8xyGwOrmPonoV14nWjjETAIdZvLvukPzIWBMKv6tDNlQjpIHNrUcUt1igRPpqoKDXw2MeKw==",
@@ -182,22 +150,6 @@
],
"logs": [
{
- "description": "Cloudflare 'Nimbus2021' Log",
- "log_id": "RJRlLrDuzq/EQAfYqP4owNrmgr7YyzG1P9MzlrW2gag=",
- "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAExpon7ipsqehIeU1bmpog9TFo4Pk8+9oN8OYHl1Q2JGVXnkVFnuuvPgSo2Ep+6vLffNLcmEbxOucz03sFiematg==",
- "url": "https://ct.cloudflare.com/logs/nimbus2021/",
- "mmd": 86400,
- "state": {
- "usable": {
- "timestamp": "2018-06-15T02:30:13Z"
- }
- },
- "temporal_interval": {
- "start_inclusive": "2021-01-01T00:00:00Z",
- "end_exclusive": "2022-01-01T00:00:00Z"
- }
- },
- {
"description": "Cloudflare 'Nimbus2022' Log",
"log_id": "QcjKsd8iRkoQxqE6CUKHXk4xixsD6+tLx2jwkGKWBvY=",
"key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAESLJHTlAycmJKDQxIv60pZG8g33lSYxYpCi5gteI6HLevWbFVCdtZx+m9b+0LrwWWl/87mkNN6xE0M4rnrIPA/w==",
@@ -262,22 +214,6 @@
}
},
{
- "description": "DigiCert Yeti2021 Log",
- "log_id": "XNxDkv7mq0VEsV6a1FbmEDf71fpH3KFzlLJe5vbHDso=",
- "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE6J4EbcpIAl1+AkSRsbhoY5oRTj3VoFfaf1DlQkfi7Rbe/HcjfVtrwN8jaC+tQDGjF+dqvKhWJAQ6Q6ev6q9Mew==",
- "url": "https://yeti2021.ct.digicert.com/log/",
- "mmd": 86400,
- "state": {
- "usable": {
- "timestamp": "2018-08-24T00:53:07Z"
- }
- },
- "temporal_interval": {
- "start_inclusive": "2021-01-01T00:00:00Z",
- "end_exclusive": "2022-01-01T00:00:00Z"
- }
- },
- {
"description": "DigiCert Yeti2022 Log",
"log_id": "IkVFB1lVJFaWP6Ev8fdthuAjJmOtwEt/XcaDXG7iDwI=",
"key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEn/jYHd77W1G1+131td5mEbCdX/1v/KiYW5hPLcOROvv+xA8Nw2BDjB7y+RGyutD2vKXStp/5XIeiffzUfdYTJg==",
@@ -310,22 +246,6 @@
}
},
{
- "description": "DigiCert Nessie2021 Log",
- "log_id": "7sCV7o1yZA+S48O5G8cSo2lqCXtLahoUOOZHssvtxfk=",
- "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE9o7AiwrbGBIX6Lnc47I6OfLMdZnRzKoP5u072nBi6vpIOEooktTi1gNwlRPzGC2ySGfuc1xLDeaA/wSFGgpYFg==",
- "url": "https://nessie2021.ct.digicert.com/log/",
- "mmd": 86400,
- "state": {
- "usable": {
- "timestamp": "2019-05-09T22:11:02Z"
- }
- },
- "temporal_interval": {
- "start_inclusive": "2021-01-01T00:00:00Z",
- "end_exclusive": "2022-01-01T00:00:00Z"
- }
- },
- {
"description": "DigiCert Nessie2022 Log",
"log_id": "UaOw9f0BeZxWbbg3eI8MpHrMGyfL956IQpoN/tSLBeU=",
"key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEJyTdaAMoy/5jvg4RR019F2ihEV1McclBKMe2okuX7MCv/C87v+nxsfz1Af+p+0lADGMkmNd5LqZVqxbGvlHYcQ==",
@@ -392,6 +312,22 @@
"timestamp": "2019-02-16T00:00:00Z"
}
}
+ },
+ {
+ "description": "DigiCert Yeti2022-2 Log",
+ "log_id": "BZwB0yDgB4QTlYBJjRF8kDJmr69yULWvO0akPhGEDUo=",
+ "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEHWlePwrycXfNnV3DNEkA7mB34XJ2dKh8XH0J8jIdBX4u/lsx1Tr9czRuSRROUFiWWsTH9L4FZKT31+WxbTMMww==",
+ "url": "https://yeti2022-2.ct.digicert.com/log/",
+ "mmd": 86400,
+ "state": {
+ "qualified": {
+ "timestamp": "2022-03-11T00:00:00Z"
+ }
+ },
+ "temporal_interval": {
+ "start_inclusive": "2022-01-01T00:00:00Z",
+ "end_exclusive": "2023-01-01T00:00:00Z"
+ }
}
]
},
@@ -554,22 +490,6 @@
],
"logs": [
{
- "description": "Let's Encrypt 'Oak2021' log",
- "log_id": "lCC8Ho7VjWyIcx+CiyIsDdHaTV5sT5Q9YdtOL1hNosI=",
- "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAELsYzGMNwo8rBIlaklBIdmD2Ofn6HkfrjK0Ukz1uOIUC6Lm0jTITCXhoIdjs7JkyXnwuwYiJYiH7sE1YeKu8k9w==",
- "url": "https://oak.ct.letsencrypt.org/2021/",
- "mmd": 86400,
- "state": {
- "usable": {
- "timestamp": "2020-01-27T18:18:26Z"
- }
- },
- "temporal_interval": {
- "start_inclusive": "2021-01-01T00:00:00Z",
- "end_exclusive": "2022-01-07T00:00:00Z"
- }
- },
- {
"description": "Let's Encrypt 'Oak2022' log",
"log_id": "36Veq2iCTx9sre64X04+WurNohKkal6OOxLAIERcKnM=",
"key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEhjyxDVIjWt5u9sB/o2S8rcGJ2pdZTGA8+IpXhI/tvKBjElGE5r3de4yAfeOPhqTqqc+o7vPgXnDgu/a9/B+RLg==",
@@ -610,38 +530,6 @@
],
"logs": [
{
- "description": "Trust Asia CT2021",
- "log_id": "qNxS9j1rJCXlMeN89ORKcU8UKiCAOw0E0uLuBmR5SiM=",
- "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAESdAfC+h1SZNsSARs188n/dCiNYjGSgkT7avLYe1mmXJzzHhsmxmAorHtOzhDkFgaCSCrUPrXdunK946eyIeSmA==",
- "url": "https://ct2021.trustasia.com/log2021/",
- "mmd": 86400,
- "state": {
- "usable": {
- "timestamp": "2021-10-16T01:46:32Z"
- }
- },
- "temporal_interval": {
- "start_inclusive": "2021-01-01T00:00:00Z",
- "end_exclusive": "2022-01-01T00:00:00Z"
- }
- },
- {
- "description": "Trust Asia Log2021",
- "log_id": "Z422Wz50Q7bzo3DV4TqxtDvgoNNR98p0IlDHxvpRqIo=",
- "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEjwlzYzssDEG4DpPoOS73Ewsdohc0MzaohzRmUz9dih7Z8SHyyviKmnQL1KKfY6VGFnt0ulbVupzGXSaYUAoupA==",
- "url": "https://ct.trustasia.com/log2021/",
- "mmd": 86400,
- "state": {
- "retired": {
- "timestamp": "2020-12-01T00:00:00Z"
- }
- },
- "temporal_interval": {
- "start_inclusive": "2021-01-01T00:00:00Z",
- "end_exclusive": "2022-01-01T00:00:00Z"
- }
- },
- {
"description": "Trust Asia Log2022",
"log_id": "w2X5s2VPMoPHnamOk9dBj1ure+MlLJjh0vBLuetCfSM=",
"key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEu1LyFs+SC8555lRtwjdTpPX5OqmzBewdvRbsMKwu+HliNRWOGtgWLuRIa/bGE/GWLlwQ/hkeqBi4Dy3DpIZRlw==",
diff --git a/chromium/components/certificate_transparency/pref_names.h b/chromium/components/certificate_transparency/pref_names.h
index b7153c5fb10..46ccc670903 100644
--- a/chromium/components/certificate_transparency/pref_names.h
+++ b/chromium/components/certificate_transparency/pref_names.h
@@ -5,6 +5,8 @@
#ifndef COMPONENTS_CERTIFICATE_TRANSPARENCY_PREF_NAMES_H_
#define COMPONENTS_CERTIFICATE_TRANSPARENCY_PREF_NAMES_H_
+#include "base/component_export.h"
+
class PrefRegistrySimple;
namespace certificate_transparency {
@@ -12,16 +14,17 @@ namespace prefs {
// Registers the preferences related to Certificate Transparency policy
// in the given pref registry.
+COMPONENT_EXPORT(CERTIFICATE_TRANSPARENCY)
void RegisterPrefs(PrefRegistrySimple* registry);
-// The set of hosts (as URLBlacklist-syntax filters) for which Certificate
+// The set of hosts (as URLBlocklist-syntax filters) for which Certificate
// Transparency is required to be present.
-extern const char kCTRequiredHosts[];
+COMPONENT_EXPORT(CERTIFICATE_TRANSPARENCY) extern const char kCTRequiredHosts[];
-// The set of hosts (as URLBlacklist-syntax filters) for which Certificate
+// The set of hosts (as URLBlocklist-syntax filters) for which Certificate
// Transparency information is allowed to be absent, even if it would
// otherwise be required (e.g. as part of security policy).
-extern const char kCTExcludedHosts[];
+COMPONENT_EXPORT(CERTIFICATE_TRANSPARENCY) extern const char kCTExcludedHosts[];
// The set of subjectPublicKeyInfo hashes in the form of
// <hash-name>"/"<base64-hash-value>. If a certificate matches this SPKI, then
@@ -35,7 +38,7 @@ extern const char kCTExcludedHosts[];
// 2) The matching certificate contains one or more organizationName
// attributes in the Subject, and those attributes are identical in
// ordering, number of values, and byte-for-byte equality of values.
-extern const char kCTExcludedSPKIs[];
+COMPONENT_EXPORT(CERTIFICATE_TRANSPARENCY) extern const char kCTExcludedSPKIs[];
// The set of subjectPublicKeyInfo hashes in the form of
// <hash-name>"/"<base64-hash-value>. If a certificate matches this SPKI, then
@@ -45,6 +48,7 @@ extern const char kCTExcludedSPKIs[];
// 2) The SPKI listed is not actively trusted in the current version of the
// ChromiumOS or Android root stores.
// (see '"legacy": true' in root_stores.json)
+COMPONENT_EXPORT(CERTIFICATE_TRANSPARENCY)
extern const char kCTExcludedLegacySPKIs[];
} // namespace prefs
diff --git a/chromium/components/certificate_transparency/tools/make_ct_known_logs_list.py b/chromium/components/certificate_transparency/tools/make_ct_known_logs_list.py
index 9aec4aa741a..a7c2fc56d33 100755
--- a/chromium/components/certificate_transparency/tools/make_ct_known_logs_list.py
+++ b/chromium/components/certificate_transparency/tools/make_ct_known_logs_list.py
@@ -30,7 +30,7 @@ def _write_disqualified_log_info_struct_definition(f):
" // SCTs embedded in pre-certificates after this date should not"
" count\n"
" // towards any uniqueness/freshness requirements.\n"
- " const base::TimeDelta disqualification_date;\n"
+ " const base::Time disqualification_date;\n"
"};\n\n")
@@ -141,7 +141,7 @@ def _to_disqualified_loginfo_struct(log, index):
s += ",\n"
s += _to_loginfo_struct(log, index)
s += ",\n"
- s += ' base::Seconds(%d)' % (
+ s += ' base::Time::FromTimeT(%d)' % (
_timestamp_to_timedelta_since_unixepoch(
log["state"]["retired"]["timestamp"]))
s += '}'
@@ -167,8 +167,9 @@ def _to_previous_operators_struct(log, index):
_timestamp_to_timedelta_since_unixepoch(
x["end_time"])):
s += '\n {"%s", ' % (_escape_c_string(operator_switch["name"]))
- s += 'base::Seconds(%d)},' % _timestamp_to_timedelta_since_unixepoch(
- operator_switch["end_time"])
+ s += (
+ 'base::Time::FromTimeT(%d)},' %
+ _timestamp_to_timedelta_since_unixepoch(operator_switch["end_time"]))
s += '};\n'
return s
@@ -210,8 +211,8 @@ def _is_log_once_or_currently_qualified(log):
def _generate_log_list_timestamp(timestamp):
s = ""
s += "// The time at which this log list was last updated.\n";
- s += "const base::TimeDelta kLogListTimestamp = "
- s += 'base::Seconds(%d);\n\n' % (
+ s += "const base::Time kLogListTimestamp = "
+ s += 'base::Time::FromTimeT(%d);\n\n' % (
_timestamp_to_timedelta_since_unixepoch(timestamp))
return s
diff --git a/chromium/components/certificate_transparency/tools/make_ct_known_logs_list_unittest.py b/chromium/components/certificate_transparency/tools/make_ct_known_logs_list_unittest.py
index 7b3e1ba4837..6166f17a5b2 100755
--- a/chromium/components/certificate_transparency/tools/make_ct_known_logs_list_unittest.py
+++ b/chromium/components/certificate_transparency/tools/make_ct_known_logs_list_unittest.py
@@ -207,7 +207,7 @@ class DisqualifiedLogsHandlingTest(unittest.TestCase):
'\\x7a\\x9c\\xb4\\x10\\xff\\x61\\xf2\\x00\\x15\\xad",\n {"\\x61'
'\\x62\\x63",\n 3,\n "Test Description"'
',\n "",\n nullptr, 0},\n '
- "base::Seconds(1551083574)}")
+ "base::Time::FromTimeT(1551083574)}")
self.assertEqual(
make_ct_known_logs_list._to_disqualified_loginfo_struct(log, 1),
@@ -266,8 +266,8 @@ class LogListTimestampGenerationTest(unittest.TestCase):
iso_timestamp = "2021-08-09T00:00:00Z"
expected_generated_timestamp = (
'// The time at which this log list was last updated.\n'
- 'const base::TimeDelta kLogListTimestamp = '
- 'base::Seconds(1628467200);\n\n')
+ 'const base::Time kLogListTimestamp = '
+ 'base::Time::FromTimeT(1628467200);\n\n')
self.assertEqual(
make_ct_known_logs_list._generate_log_list_timestamp(iso_timestamp),
@@ -291,9 +291,9 @@ class LogListPreviousOperatorsTest(unittest.TestCase):
]
}
expected_previous_operator_info = (
- 'const PreviousOperatorEntry kPreviousOperators1[] = {\n {'
- '"test123456", base::Seconds(1514764800)},\n {"test123", '
- 'base::Seconds(1609459200)},};\n')
+ 'const PreviousOperatorEntry kPreviousOperators1[] = {\n'
+ ' {"test123456", base::Time::FromTimeT(1514764800)},\n'
+ ' {"test123", base::Time::FromTimeT(1609459200)},};\n')
self.assertEqual(
make_ct_known_logs_list._to_previous_operators_struct(log, 1),
expected_previous_operator_info)
diff --git a/chromium/components/client_hints/OWNERS b/chromium/components/client_hints/OWNERS
index 7c9f8f73129..6c2aca6d9ae 100644
--- a/chromium/components/client_hints/OWNERS
+++ b/chromium/components/client_hints/OWNERS
@@ -2,5 +2,4 @@ aarontag@chromium.org
abeyad@chromium.org
arichiv@chromium.org
ryansturm@chromium.org
-tbansal@chromium.org
yoavweiss@chromium.org
diff --git a/chromium/components/client_hints/browser/BUILD.gn b/chromium/components/client_hints/browser/BUILD.gn
index 168697b0a57..06d1e0982d9 100644
--- a/chromium/components/client_hints/browser/BUILD.gn
+++ b/chromium/components/client_hints/browser/BUILD.gn
@@ -18,3 +18,17 @@ source_set("browser") {
"//third_party/blink/public/common:headers",
]
}
+
+source_set("in_memory") {
+ sources = [
+ "in_memory_client_hints_controller_delegate.cc",
+ "in_memory_client_hints_controller_delegate.h",
+ ]
+ deps = [
+ "//base",
+ "//content/public/browser",
+ "//services/network/public/cpp",
+ "//third_party/blink/public/common:headers",
+ "//url",
+ ]
+}
diff --git a/chromium/components/client_hints/browser/DEPS b/chromium/components/client_hints/browser/DEPS
index 9a103f6d8b0..66033c37ce9 100644
--- a/chromium/components/client_hints/browser/DEPS
+++ b/chromium/components/client_hints/browser/DEPS
@@ -3,6 +3,8 @@ include_rules = [
"+components/embedder_support",
"+components/keyed_service",
"+content/public/browser",
+ "+third_party/blink/public/common/client_hints/enabled_client_hints.h",
+ "+third_party/blink/public/common/features.h",
"+third_party/blink/public/common/user_agent",
"+services/network/public/cpp/is_potentially_trustworthy.h",
"+services/network/public/cpp/client_hints.h"
diff --git a/chromium/components/client_hints/browser/client_hints.cc b/chromium/components/client_hints/browser/client_hints.cc
index 689115fa2b3..d2d4aa8eb80 100644
--- a/chromium/components/client_hints/browser/client_hints.cc
+++ b/chromium/components/client_hints/browser/client_hints.cc
@@ -6,15 +6,16 @@
#include <functional>
#include <string>
-#include "components/client_hints/browser/client_hints.h"
-
#include "base/command_line.h"
+#include "base/feature_list.h"
#include "base/json/json_reader.h"
-#include "base/metrics/histogram_macros.h"
+#include "base/metrics/histogram_functions.h"
#include "base/time/time.h"
+#include "components/client_hints/browser/client_hints.h"
#include "components/client_hints/common/client_hints.h"
#include "components/client_hints/common/switches.h"
#include "components/content_settings/core/browser/host_content_settings_map.h"
+#include "components/content_settings/core/common/content_settings_constraints.h"
#include "components/content_settings/core/common/content_settings_types.h"
#include "components/content_settings/core/common/content_settings_utils.h"
#include "components/embedder_support/user_agent_utils.h"
@@ -22,6 +23,8 @@
#include "content/public/browser/render_process_host.h"
#include "services/network/public/cpp/client_hints.h"
#include "services/network/public/cpp/is_potentially_trustworthy.h"
+#include "third_party/blink/public/common/client_hints/enabled_client_hints.h"
+#include "third_party/blink/public/common/features.h"
namespace client_hints {
@@ -170,25 +173,35 @@ void ClientHints::PersistClientHints(
return;
}
+ const base::TimeTicks start_time = base::TimeTicks::Now();
base::Value::ListStorage client_hints_list;
client_hints_list.reserve(client_hints.size());
- for (const auto& entry : client_hints)
+ for (const auto& entry : client_hints) {
client_hints_list.push_back(base::Value(static_cast<int>(entry)));
+ }
auto client_hints_dictionary = std::make_unique<base::DictionaryValue>();
client_hints_dictionary->SetKey(kClientHintsSettingKey,
base::Value(std::move(client_hints_list)));
+ const auto session_model =
+ base::FeatureList::IsEnabled(blink::features::kDurableClientHintsCache)
+ ? content_settings::SessionModel::Durable
+ : content_settings::SessionModel::UserSession;
+
// TODO(tbansal): crbug.com/735518. Disable updates to client hints settings
// when cookies are disabled for |primary_origin|.
settings_map_->SetWebsiteSettingDefaultScope(
primary_url, GURL(), ContentSettingsType::CLIENT_HINTS,
- std::move(client_hints_dictionary),
- {base::Time(), content_settings::SessionModel::UserSession});
-
- UMA_HISTOGRAM_EXACT_LINEAR("ClientHints.UpdateEventCount", 1, 2);
- UMA_HISTOGRAM_COUNTS_100("ClientHints.UpdateSize", client_hints.size());
+ base::Value::FromUniquePtrValue(std::move(client_hints_dictionary)),
+ {base::Time(), session_model});
+
+ // Record the time spent getting the client hints.
+ base::TimeDelta duration = base::TimeTicks::Now() - start_time;
+ base::UmaHistogramTimes("ClientHints.StoreLatency", duration);
+ base::UmaHistogramExactLinear("ClientHints.UpdateEventCount", 1, 2);
+ base::UmaHistogramCounts100("ClientHints.UpdateSize", client_hints.size());
}
void ClientHints::SetAdditionalClientHints(
diff --git a/chromium/components/client_hints/browser/client_hints.h b/chromium/components/client_hints/browser/client_hints.h
index 9593653d705..59189c5b64b 100644
--- a/chromium/components/client_hints/browser/client_hints.h
+++ b/chromium/components/client_hints/browser/client_hints.h
@@ -8,17 +8,20 @@
#include <memory>
#include "base/memory/raw_ptr.h"
-#include "base/memory/ref_counted.h"
#include "base/memory/scoped_refptr.h"
#include "components/content_settings/core/browser/cookie_settings.h"
#include "components/keyed_service/core/keyed_service.h"
#include "content/public/browser/client_hints_controller_delegate.h"
-#include "third_party/blink/public/common/user_agent/user_agent_metadata.h"
class GURL;
class HostContentSettingsMap;
class PrefService;
+namespace blink {
+struct UserAgentMetadata;
+class EnabledClientHints;
+} // namespace blink
+
namespace client_hints {
class ClientHints : public KeyedService,
diff --git a/chromium/components/client_hints/browser/in_memory_client_hints_controller_delegate.cc b/chromium/components/client_hints/browser/in_memory_client_hints_controller_delegate.cc
new file mode 100644
index 00000000000..e253e888c8b
--- /dev/null
+++ b/chromium/components/client_hints/browser/in_memory_client_hints_controller_delegate.cc
@@ -0,0 +1,102 @@
+// Copyright 2022 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.
+
+#include "components/client_hints/browser/in_memory_client_hints_controller_delegate.h"
+
+#include <vector>
+
+#include "base/bind.h"
+#include "services/network/public/cpp/is_potentially_trustworthy.h"
+#include "third_party/blink/public/common/client_hints/enabled_client_hints.h"
+#include "url/origin.h"
+
+namespace client_hints {
+
+InMemoryClientHintsControllerDelegate::InMemoryClientHintsControllerDelegate(
+ network::NetworkQualityTracker* network_quality_tracker,
+ base::RepeatingCallback<bool(const GURL&)> is_javascript_allowed_callback,
+ base::RepeatingCallback<bool(const GURL&)>
+ are_third_party_cookies_blocked_callback,
+ blink::UserAgentMetadata user_agent_metadata)
+ : network_quality_tracker_(network_quality_tracker),
+ is_javascript_allowed_callback_(is_javascript_allowed_callback),
+ are_third_party_cookies_blocked_callback_(
+ are_third_party_cookies_blocked_callback),
+ user_agent_metadata_(user_agent_metadata) {}
+
+InMemoryClientHintsControllerDelegate::
+ ~InMemoryClientHintsControllerDelegate() = default;
+
+// Enabled Client Hints are only cached and not persisted in this
+// implementation.
+void InMemoryClientHintsControllerDelegate::PersistClientHints(
+ const url::Origin& primary_origin,
+ const std::vector<network::mojom::WebClientHintsType>& client_hints) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ const GURL primary_url = primary_origin.GetURL();
+ DCHECK(primary_url.is_valid());
+ DCHECK(network::IsUrlPotentiallyTrustworthy(primary_url));
+
+ // Client hints should only be enabled when JavaScript is enabled.
+ if (!IsJavaScriptAllowed(primary_url))
+ return;
+
+ blink::EnabledClientHints enabled_hints;
+ for (auto hint : client_hints) {
+ enabled_hints.SetIsEnabled(hint, true);
+ }
+ accept_ch_cache_[primary_origin] = enabled_hints;
+}
+
+// Looks up enabled Client Hints for the URL origin, and adds additional Client
+// Hints if set.
+void InMemoryClientHintsControllerDelegate::GetAllowedClientHintsFromSource(
+ const GURL& url,
+ blink::EnabledClientHints* client_hints) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(client_hints);
+ DCHECK(network::IsUrlPotentiallyTrustworthy(url));
+
+ const url::Origin origin = url::Origin::Create(url);
+ const auto& it = accept_ch_cache_.find(origin);
+ if (it != accept_ch_cache_.end()) {
+ *client_hints = it->second;
+ }
+
+ for (auto hint : additional_hints_)
+ client_hints->SetIsEnabled(hint, true);
+}
+
+void InMemoryClientHintsControllerDelegate::SetAdditionalClientHints(
+ const std::vector<network::mojom::WebClientHintsType>& hints) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ additional_hints_ = hints;
+}
+
+void InMemoryClientHintsControllerDelegate::ClearAdditionalClientHints() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ additional_hints_.clear();
+}
+
+network::NetworkQualityTracker*
+InMemoryClientHintsControllerDelegate::GetNetworkQualityTracker() {
+ return network_quality_tracker_;
+}
+
+bool InMemoryClientHintsControllerDelegate::IsJavaScriptAllowed(
+ const GURL& url) {
+ return is_javascript_allowed_callback_.Run(url);
+}
+
+bool InMemoryClientHintsControllerDelegate::AreThirdPartyCookiesBlocked(
+ const GURL& url) {
+ return are_third_party_cookies_blocked_callback_.Run(url);
+}
+
+blink::UserAgentMetadata
+InMemoryClientHintsControllerDelegate::GetUserAgentMetadata() {
+ return user_agent_metadata_;
+}
+
+} // namespace client_hints
diff --git a/chromium/components/client_hints/browser/in_memory_client_hints_controller_delegate.h b/chromium/components/client_hints/browser/in_memory_client_hints_controller_delegate.h
new file mode 100644
index 00000000000..6ffb7689611
--- /dev/null
+++ b/chromium/components/client_hints/browser/in_memory_client_hints_controller_delegate.h
@@ -0,0 +1,95 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_CLIENT_HINTS_BROWSER_IN_MEMORY_CLIENT_HINTS_CONTROLLER_DELEGATE_H_
+#define COMPONENTS_CLIENT_HINTS_BROWSER_IN_MEMORY_CLIENT_HINTS_CONTROLLER_DELEGATE_H_
+
+#include <map>
+#include <vector>
+
+#include "base/memory/raw_ptr.h"
+#include "base/sequence_checker.h"
+#include "content/public/browser/client_hints_controller_delegate.h"
+#include "third_party/blink/public/common/user_agent/user_agent_metadata.h"
+
+namespace blink {
+class EnabledClientHints;
+}
+
+namespace network {
+class NetworkQualityTracker;
+}
+
+namespace url {
+class Origin;
+}
+
+namespace client_hints {
+
+// In-memory manager of Accept-CH Cache used in Client Hints infrastructure.
+// See https://wicg.github.io/client-hints-infrastructure/.
+//
+// This cache is not persisted and has the same lifetime as the delegate.
+// Differs from client_hints::ClientHints by not relying on ContentSettings to
+// store Accept-CH Cache.
+class InMemoryClientHintsControllerDelegate final
+ : public content::ClientHintsControllerDelegate {
+ public:
+ InMemoryClientHintsControllerDelegate(
+ network::NetworkQualityTracker* network_quality_tracker,
+ base::RepeatingCallback<bool(const GURL&)> is_javascript_allowed_callback,
+ base::RepeatingCallback<bool(const GURL&)>
+ are_third_party_cookies_blocked_callback,
+ blink::UserAgentMetadata user_agent_metadata);
+ ~InMemoryClientHintsControllerDelegate() override;
+
+ InMemoryClientHintsControllerDelegate(
+ InMemoryClientHintsControllerDelegate&) = delete;
+ InMemoryClientHintsControllerDelegate& operator=(
+ InMemoryClientHintsControllerDelegate&) = delete;
+
+ // content::ClientHintsControllerDelegate implementation:
+ void PersistClientHints(const url::Origin& primary_origin,
+ const std::vector<network::mojom::WebClientHintsType>&
+ client_hints) override;
+ void GetAllowedClientHintsFromSource(
+ const GURL& url,
+ blink::EnabledClientHints* client_hints) override;
+ void SetAdditionalClientHints(
+ const std::vector<network::mojom::WebClientHintsType>&) override;
+ void ClearAdditionalClientHints() override;
+ network::NetworkQualityTracker* GetNetworkQualityTracker() override;
+ bool IsJavaScriptAllowed(const GURL& url) override;
+ bool AreThirdPartyCookiesBlocked(const GURL& url) override;
+ blink::UserAgentMetadata GetUserAgentMetadata() override;
+
+ private:
+ SEQUENCE_CHECKER(sequence_checker_);
+
+ // Stores enabled Client Hint types for an origin.
+ std::map<url::Origin, blink::EnabledClientHints> accept_ch_cache_
+ GUARDED_BY_CONTEXT(sequence_checker_);
+
+ // Additional Client Hint types for Client Hints Reliability. If additional
+ // hints are set, they would be included by subsequent calls to
+ // GetAllowedClientHintsFromSource.
+ std::vector<network::mojom::WebClientHintsType> additional_hints_
+ GUARDED_BY_CONTEXT(sequence_checker_);
+
+ // Tracker for networking-related hints. Must outlive this object.
+ raw_ptr<network::NetworkQualityTracker> network_quality_tracker_;
+
+ // Callback to determine whether JavaScript is enabled for an URL.
+ base::RepeatingCallback<bool(const GURL&)> is_javascript_allowed_callback_;
+
+ // Callback to determine whether third-party cookies are blocked for an URL.
+ base::RepeatingCallback<bool(const GURL&)>
+ are_third_party_cookies_blocked_callback_;
+
+ const blink::UserAgentMetadata user_agent_metadata_;
+};
+
+} // namespace client_hints
+
+#endif // COMPONENTS_CLIENT_HINTS_BROWSER_IN_MEMORY_CLIENT_HINTS_CONTROLLER_DELEGATE_H_
diff --git a/chromium/components/client_hints/common/client_hints.cc b/chromium/components/client_hints/common/client_hints.cc
index 5327eb696d0..75239d95d12 100644
--- a/chromium/components/client_hints/common/client_hints.cc
+++ b/chromium/components/client_hints/common/client_hints.cc
@@ -39,7 +39,7 @@ void GetAllowedClientHintsFromSource(
if (list_value == nullptr)
continue;
DCHECK(list_value->is_list());
- for (const auto& client_hint : list_value->GetList()) {
+ for (const auto& client_hint : list_value->GetListDeprecated()) {
DCHECK(client_hint.is_int());
network::mojom::WebClientHintsType client_hint_mojo =
static_cast<network::mojom::WebClientHintsType>(client_hint.GetInt());
diff --git a/chromium/components/cloud_devices/common/description_items_inl.h b/chromium/components/cloud_devices/common/description_items_inl.h
index f8d7b6ceb2e..ba0ce562f6b 100644
--- a/chromium/components/cloud_devices/common/description_items_inl.h
+++ b/chromium/components/cloud_devices/common/description_items_inl.h
@@ -51,7 +51,7 @@ bool ListCapability<Option, Traits>::LoadFrom(
description.GetItem(Traits::GetCapabilityPath(), base::Value::Type::LIST);
if (!options_value)
return false;
- for (const base::Value& option_value : options_value->GetList()) {
+ for (const base::Value& option_value : options_value->GetListDeprecated()) {
Option option;
if (!option_value.is_dict() || !Traits::Load(option_value, &option))
return false;
@@ -135,7 +135,7 @@ bool SelectionCapability<Option, Traits>::LoadFrom(const base::Value& dict) {
dict.FindKeyOfType(json::kKeyOption, base::Value::Type::LIST);
if (!options_value)
return false;
- for (const base::Value& option_value : options_value->GetList()) {
+ for (const base::Value& option_value : options_value->GetListDeprecated()) {
Option option;
if (!option_value.is_dict() || !Traits::Load(option_value, &option))
return false;
diff --git a/chromium/components/cloud_devices/common/printer_description.cc b/chromium/components/cloud_devices/common/printer_description.cc
index 9292612b528..9ec1d88cec8 100644
--- a/chromium/components/cloud_devices/common/printer_description.cc
+++ b/chromium/components/cloud_devices/common/printer_description.cc
@@ -21,6 +21,7 @@
#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
#include "base/values.h"
+#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "components/cloud_devices/common/cloud_device_description_consts.h"
#include "components/cloud_devices/common/description_items_inl.h"
@@ -64,9 +65,9 @@ extern constexpr char kOptionRangeCapability[] = "range_cap";
extern constexpr char kOptionSelectCapability[] = "select_cap";
extern constexpr char kOptionTypedValueCapability[] = "typed_value_cap";
extern constexpr char kOptionVendorCapability[] = "vendor_capability";
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS)
extern constexpr char kOptionPin[] = "pin";
-#endif // defined(OS_CHROMEOS)
+#endif // BUILDFLAG(IS_CHROMEOS)
constexpr char kMarginBottom[] = "bottom_microns";
constexpr char kMarginLeft[] = "left_microns";
@@ -93,9 +94,9 @@ constexpr char kMinValue[] = "min";
constexpr char kMaxValue[] = "max";
constexpr char kDefaultValue[] = "default";
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS)
constexpr char kPinSupported[] = "supported";
-#endif // defined(OS_CHROMEOS)
+#endif // BUILDFLAG(IS_CHROMEOS)
constexpr char kTypeRangeVendorCapabilityFloat[] = "FLOAT";
constexpr char kTypeRangeVendorCapabilityInteger[] = "INTEGER";
@@ -1057,7 +1058,8 @@ class PwgRasterConfigTraits : public NoValueValidation,
if (document_types_supported) {
if (!document_types_supported->is_list())
return false;
- for (const auto& type_value : document_types_supported->GetList()) {
+ for (const auto& type_value :
+ document_types_supported->GetListDeprecated()) {
if (!type_value.is_string())
return false;
@@ -1332,7 +1334,7 @@ class PageRangeTraits : public ItemsTraits<kOptionPageRange> {
dict.FindKeyOfType(kPageRangeInterval, base::Value::Type::LIST);
if (!list_value)
return false;
- for (const base::Value& interval : list_value->GetList()) {
+ for (const base::Value& interval : list_value->GetListDeprecated()) {
int page_range_start = interval.FindIntKey(kPageRangeStart).value_or(1);
int page_range_end =
interval.FindIntKey(kPageRangeEnd).value_or(kMaxPageNumber);
@@ -1441,7 +1443,7 @@ class ReverseTraits : public NoValueValidation,
}
};
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS)
class PinTraits : public NoValueValidation, public ItemsTraits<kOptionPin> {
public:
static bool Load(const base::Value& dict, bool* option) {
@@ -1456,7 +1458,7 @@ class PinTraits : public NoValueValidation, public ItemsTraits<kOptionPin> {
dict->SetKey(kPinSupported, base::Value(option));
}
};
-#endif // defined(OS_CHROMEOS)
+#endif // BUILDFLAG(IS_CHROMEOS)
} // namespace printer
@@ -1481,9 +1483,9 @@ template class ValueCapability<printer::Copies,
template class EmptyCapability<printer::PageRangeTraits>;
template class BooleanCapability<printer::CollateTraits>;
template class BooleanCapability<printer::ReverseTraits>;
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS)
template class ValueCapability<bool, printer::PinTraits>;
-#endif // defined(OS_CHROMEOS)
+#endif // BUILDFLAG(IS_CHROMEOS)
template class TicketItem<printer::PwgRasterConfig,
printer::PwgRasterConfigTraits>;
diff --git a/chromium/components/cloud_devices/common/printer_description.h b/chromium/components/cloud_devices/common/printer_description.h
index 9b8c73c2ac2..afe849d16bd 100644
--- a/chromium/components/cloud_devices/common/printer_description.h
+++ b/chromium/components/cloud_devices/common/printer_description.h
@@ -533,11 +533,11 @@ typedef ValueCapability<Copies, class CopiesCapabilityTraits> CopiesCapability;
typedef EmptyCapability<class PageRangeTraits> PageRangeCapability;
typedef BooleanCapability<class CollateTraits> CollateCapability;
typedef BooleanCapability<class ReverseTraits> ReverseCapability;
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS)
// This capability is not a part of standard CDD description. It's used for
// providing PIN printing opportunity in Chrome OS native printing.
typedef ValueCapability<bool, class PinTraits> PinCapability;
-#endif // defined(OS_CHROMEOS)
+#endif // BUILDFLAG(IS_CHROMEOS)
typedef TicketItem<PwgRasterConfig, PwgRasterConfigTraits>
PwgRasterConfigTicketItem;
diff --git a/chromium/components/cloud_devices/common/printer_description_unittest.cc b/chromium/components/cloud_devices/common/printer_description_unittest.cc
index 217f8cdbd2e..ccc6b30b10a 100644
--- a/chromium/components/cloud_devices/common/printer_description_unittest.cc
+++ b/chromium/components/cloud_devices/common/printer_description_unittest.cc
@@ -11,6 +11,7 @@
#include "base/json/json_writer.h"
#include "base/strings/string_util.h"
#include "base/values.h"
+#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -507,7 +508,7 @@ const char kSeveralInnerCapabilitiesVendorCapabilityCdd[] = R"(
}
})";
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS)
const char kPinOnlyCdd[] = R"(
{
"version": "1.0",
@@ -517,7 +518,7 @@ const char kPinOnlyCdd[] = R"(
}
}
})";
-#endif // defined(OS_CHROMEOS)
+#endif // BUILDFLAG(IS_CHROMEOS)
const char kCjt[] = R"(
{
@@ -1103,7 +1104,7 @@ TEST(PrinterDescriptionTest, CddSetVendorCapability) {
NormalizeJson(description.ToString()));
}
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS)
TEST(PrinterDescriptionTest, CddGetPin) {
{
CloudDeviceDescription description;
@@ -1129,7 +1130,7 @@ TEST(PrinterDescriptionTest, CddSetPin) {
pin_capability.SaveTo(&description);
EXPECT_EQ(NormalizeJson(kPinOnlyCdd), NormalizeJson(description.ToString()));
}
-#endif // defined(OS_CHROMEOS)
+#endif // BUILDFLAG(IS_CHROMEOS)
TEST(PrinterDescriptionTest, CddGetAll) {
CloudDeviceDescription description;
diff --git a/chromium/components/commerce/OWNERS b/chromium/components/commerce/OWNERS
index a991d869aab..3104d54dc56 100644
--- a/chromium/components/commerce/OWNERS
+++ b/chromium/components/commerce/OWNERS
@@ -1,3 +1,4 @@
ayman@chromium.org
davidjm@chromium.org
+mdjones@chromium.org
wychen@chromium.org
diff --git a/chromium/components/commerce/content/BUILD.gn b/chromium/components/commerce/content/BUILD.gn
new file mode 100644
index 00000000000..9e7e3f33ead
--- /dev/null
+++ b/chromium/components/commerce/content/BUILD.gn
@@ -0,0 +1,19 @@
+# Copyright 2022 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.
+
+static_library("metrics") {
+ sources = [
+ "metrics/commerce_metrics_tab_helper.cc",
+ "metrics/commerce_metrics_tab_helper.h",
+ ]
+
+ deps = [
+ "//base",
+ "//components/commerce/core:metrics",
+ "//components/optimization_guide/content/browser",
+ "//components/optimization_guide/proto:optimization_guide_proto",
+ "//components/prefs",
+ "//content/public/browser",
+ ]
+}
diff --git a/chromium/components/commerce/content/DEPS b/chromium/components/commerce/content/DEPS
new file mode 100644
index 00000000000..4697636e8ff
--- /dev/null
+++ b/chromium/components/commerce/content/DEPS
@@ -0,0 +1,6 @@
+include_rules = [
+ "+components/optimization_guide",
+ "+components/prefs",
+ "+content/public",
+]
+
diff --git a/chromium/components/commerce/content/metrics/commerce_metrics_tab_helper.cc b/chromium/components/commerce/content/metrics/commerce_metrics_tab_helper.cc
new file mode 100644
index 00000000000..9a9807cbaff
--- /dev/null
+++ b/chromium/components/commerce/content/metrics/commerce_metrics_tab_helper.cc
@@ -0,0 +1,62 @@
+// Copyright 2022 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.
+
+#include "components/commerce/content/metrics/commerce_metrics_tab_helper.h"
+
+#include "base/bind.h"
+#include "components/commerce/core/metrics/metrics_utils.h"
+#include "components/optimization_guide/content/browser/optimization_guide_decider.h"
+#include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/web_contents.h"
+
+namespace commerce::metrics {
+
+CommerceMetricsTabHelper::CommerceMetricsTabHelper(
+ content::WebContents* content,
+ optimization_guide::OptimizationGuideDecider* optimization_guide,
+ PrefService* pref_service,
+ bool is_off_the_record)
+ : content::WebContentsObserver(content),
+ content::WebContentsUserData<CommerceMetricsTabHelper>(*content),
+ optimization_guide_(optimization_guide),
+ pref_service_(pref_service),
+ is_off_the_record_(is_off_the_record),
+ weak_ptr_factory_(this) {
+ // In tests |optimization_guide_| can be null.
+ if (optimization_guide_) {
+ std::vector<optimization_guide::proto::OptimizationType> types;
+ types.push_back(
+ optimization_guide::proto::OptimizationType::PRICE_TRACKING);
+ optimization_guide_->RegisterOptimizationTypes(types);
+ }
+}
+
+CommerceMetricsTabHelper::~CommerceMetricsTabHelper() = default;
+
+void CommerceMetricsTabHelper::DidFinishNavigation(
+ content::NavigationHandle* navigation_handle) {
+ if (!navigation_handle->HasCommitted() ||
+ navigation_handle->IsSameDocument() ||
+ !navigation_handle->IsInPrimaryMainFrame() || !optimization_guide_) {
+ return;
+ }
+
+ optimization_guide_->CanApplyOptimizationAsync(
+ navigation_handle,
+ optimization_guide::proto::OptimizationType::PRICE_TRACKING,
+ base::BindOnce(&CommerceMetricsTabHelper::OnOptimizationGuideResult,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void CommerceMetricsTabHelper::OnOptimizationGuideResult(
+ optimization_guide::OptimizationGuideDecision decision,
+ const optimization_guide::OptimizationMetadata& metadata) {
+ RecordPDPStateForNavigation(decision, metadata, pref_service_,
+ is_off_the_record_);
+}
+
+WEB_CONTENTS_USER_DATA_KEY_IMPL(CommerceMetricsTabHelper);
+
+} // namespace commerce::metrics
diff --git a/chromium/components/commerce/content/metrics/commerce_metrics_tab_helper.h b/chromium/components/commerce/content/metrics/commerce_metrics_tab_helper.h
new file mode 100644
index 00000000000..1b41eaf7190
--- /dev/null
+++ b/chromium/components/commerce/content/metrics/commerce_metrics_tab_helper.h
@@ -0,0 +1,65 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_COMMERCE_CONTENT_METRICS_COMMERCE_METRICS_TAB_HELPER_H_
+#define COMPONENTS_COMMERCE_CONTENT_METRICS_COMMERCE_METRICS_TAB_HELPER_H_
+
+#include "base/memory/raw_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "components/optimization_guide/core/optimization_guide_decision.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "content/public/browser/web_contents_user_data.h"
+
+class PrefService;
+
+namespace content {
+class NavigationHandle;
+class WebContents;
+} // namespace content
+
+namespace optimization_guide {
+class OptimizationGuideDecider;
+} // namespace optimization_guide
+
+namespace commerce::metrics {
+
+class CommerceMetricsTabHelper
+ : public content::WebContentsObserver,
+ public content::WebContentsUserData<CommerceMetricsTabHelper> {
+ public:
+ ~CommerceMetricsTabHelper() override;
+ CommerceMetricsTabHelper(const CommerceMetricsTabHelper& other) = delete;
+ CommerceMetricsTabHelper& operator=(const CommerceMetricsTabHelper& other) =
+ delete;
+
+ void DidFinishNavigation(
+ content::NavigationHandle* navigation_handle) override;
+
+ private:
+ friend class content::WebContentsUserData<CommerceMetricsTabHelper>;
+
+ CommerceMetricsTabHelper(
+ content::WebContents* contents,
+ optimization_guide::OptimizationGuideDecider* optimization_guide,
+ PrefService* pref_service,
+ bool is_off_the_record);
+
+ void OnOptimizationGuideResult(
+ optimization_guide::OptimizationGuideDecision decision,
+ const optimization_guide::OptimizationMetadata& metadata);
+
+ raw_ptr<optimization_guide::OptimizationGuideDecider> optimization_guide_;
+
+ raw_ptr<PrefService> pref_service_;
+
+ bool is_off_the_record_;
+
+ base::WeakPtrFactory<CommerceMetricsTabHelper> weak_ptr_factory_;
+
+ WEB_CONTENTS_USER_DATA_KEY_DECL();
+};
+
+} // namespace commerce::metrics
+
+#endif // COMPONENTS_COMMERCE_CONTENT_METRICS_COMMERCE_METRICS_TAB_HELPER_H_
diff --git a/chromium/components/commerce/core/BUILD.gn b/chromium/components/commerce/core/BUILD.gn
index 1d75fae67ed..ffee7942337 100644
--- a/chromium/components/commerce/core/BUILD.gn
+++ b/chromium/components/commerce/core/BUILD.gn
@@ -8,6 +8,37 @@ if (is_android) {
import("//build/config/android/rules.gni")
}
+source_set("feature_list") {
+ sources = [
+ "commerce_feature_list.cc",
+ "commerce_feature_list.h",
+ "flag_descriptions.cc",
+ "flag_descriptions.h",
+ ]
+
+ deps = [
+ "//base",
+ "//components/flags_ui",
+ "//third_party/re2:re2",
+ "//url:url",
+ ]
+}
+
+static_library("metrics") {
+ sources = [
+ "metrics/metrics_utils.cc",
+ "metrics/metrics_utils.h",
+ ]
+
+ deps = [
+ ":proto",
+ "//base",
+ "//components/optimization_guide/core",
+ "//components/optimization_guide/proto:optimization_guide_proto",
+ "//components/prefs",
+ ]
+}
+
proto_library("proto") {
proto_in_dir = "//"
sources = [ "proto/price_tracking.proto" ]
diff --git a/chromium/components/commerce/core/DEPS b/chromium/components/commerce/core/DEPS
new file mode 100644
index 00000000000..d2e100a2367
--- /dev/null
+++ b/chromium/components/commerce/core/DEPS
@@ -0,0 +1,6 @@
+include_rules = [
+ "+components/flags_ui",
+ "+components/optimization_guide",
+ "+components/prefs",
+ "+third_party/re2",
+]
diff --git a/chromium/components/commerce/core/commerce_feature_list.cc b/chromium/components/commerce/core/commerce_feature_list.cc
new file mode 100644
index 00000000000..182e5dc3f3a
--- /dev/null
+++ b/chromium/components/commerce/core/commerce_feature_list.cc
@@ -0,0 +1,70 @@
+// Copyright 2021 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.
+
+#include "components/commerce/core/commerce_feature_list.h"
+
+#include "base/feature_list.h"
+#include "base/metrics/field_trial_params.h"
+#include "base/no_destructor.h"
+#include "third_party/re2/src/re2/re2.h"
+
+namespace commerce {
+
+namespace {
+
+constexpr base::FeatureParam<std::string> kPartnerMerchantPattern{
+ &commerce::kRetailCoupons, "coupon-partner-merchant-pattern",
+ // This regex does not match anything.
+ "\\b\\B"};
+
+const re2::RE2& GetPartnerMerchantPattern() {
+ re2::RE2::Options options;
+ options.set_case_sensitive(false);
+ static base::NoDestructor<re2::RE2> instance(kPartnerMerchantPattern.Get(),
+ options);
+ return *instance;
+}
+
+} // namespace
+
+const base::Feature kCommerceMerchantViewer{"CommerceMerchantViewer",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+const base::Feature kCommercePriceTracking{"CommercePriceTracking",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+const base::FeatureParam<bool> kDeleteAllMerchantsOnClearBrowsingHistory{
+ &kCommerceMerchantViewer, "delete_all_merchants_on_clear_history", false};
+
+const base::Feature kShoppingList{"ShoppingList",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+const base::Feature kShoppingPDPMetrics{"ShoppingPDPMetrics",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+
+const base::Feature kRetailCoupons{"RetailCoupons",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+const base::Feature kCommerceDeveloper{"CommerceDeveloper",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+const char kRetailCouponsWithCodeParam[] = "RetailCouponsWithCodeParam";
+
+// Params use for Discount Consent v2.
+const base::Feature kDiscountConsentV2{"DiscountConsentV2",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+bool IsCouponDiscountPartnerMerchant(const GURL& url) {
+ const std::string& url_string = url.spec();
+ return RE2::PartialMatch(
+ re2::StringPiece(url_string.data(), url_string.size()),
+ GetPartnerMerchantPattern());
+}
+
+bool IsCouponWithCodeEnabled() {
+ return base::GetFieldTrialParamByFeatureAsBool(
+ kRetailCoupons, kRetailCouponsWithCodeParam, false);
+}
+
+} // namespace commerce
diff --git a/chromium/components/commerce/core/commerce_feature_list.h b/chromium/components/commerce/core/commerce_feature_list.h
new file mode 100644
index 00000000000..acd6de9b8d0
--- /dev/null
+++ b/chromium/components/commerce/core/commerce_feature_list.h
@@ -0,0 +1,89 @@
+// Copyright 2021 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.
+
+#ifndef COMPONENTS_COMMERCE_CORE_COMMERCE_FEATURE_LIST_H_
+#define COMPONENTS_COMMERCE_CORE_COMMERCE_FEATURE_LIST_H_
+
+#include "base/cxx17_backports.h"
+#include "base/feature_list.h"
+#include "base/metrics/field_trial_params.h"
+#include "components/flags_ui/feature_entry.h"
+#include "url/gurl.h"
+
+namespace commerce {
+extern const base::Feature kCommercePriceTracking;
+
+// Price tracking variations for Android.
+constexpr flags_ui::FeatureEntry::FeatureParam
+ kCommercePriceTracking_PriceAlerts[] = {
+ {"enable_price_tracking", "true"},
+ {"price_tracking_with_optimization_guide", "false"}};
+
+constexpr flags_ui::FeatureEntry::FeatureParam
+ kCommercePriceTracking_PriceAlerts_WithOptimizationGuide[] = {
+ {"enable_price_tracking", "true"},
+ {"price_tracking_with_optimization_guide", "true"}};
+
+constexpr flags_ui::FeatureEntry::FeatureParam
+ kCommercePriceTracking_PriceNotifications[] = {
+ {"enable_price_tracking", "true"},
+ {"price_tracking_with_optimization_guide", "true"},
+ {"enable_price_notification", "true"}};
+
+constexpr flags_ui::FeatureEntry::FeatureVariation
+ kCommercePriceTrackingAndroidVariations[] = {
+ {"Price alerts", kCommercePriceTracking_PriceAlerts,
+ base::size(kCommercePriceTracking_PriceAlerts), nullptr},
+ {"Price alerts with OptimizationGuide",
+ kCommercePriceTracking_PriceAlerts_WithOptimizationGuide,
+ base::size(kCommercePriceTracking_PriceAlerts_WithOptimizationGuide),
+ nullptr},
+ {"Price notifications", kCommercePriceTracking_PriceNotifications,
+ base::size(kCommercePriceTracking_PriceNotifications), nullptr},
+};
+
+// Price tracking variations for iOS.
+constexpr flags_ui::FeatureEntry::FeatureParam
+ kCommercePriceTrackingWithOptimizationGuide[] = {
+ {"price_tracking_with_optimization_guide", "true"},
+ {"price_tracking_opt_out", "false"}};
+
+constexpr flags_ui::FeatureEntry::FeatureParam
+ kCommercePriceTrackingWithOptimizationGuideAndOptOut[] = {
+ {"price_tracking_with_optimization_guide", "true"},
+ {"price_tracking_opt_out", "true"}};
+
+constexpr flags_ui::FeatureEntry::FeatureVariation
+ kCommercePriceTrackingVariations[] = {
+ {"Price Tracking with Optimization Guide",
+ kCommercePriceTrackingWithOptimizationGuide,
+ base::size(kCommercePriceTrackingWithOptimizationGuide), nullptr},
+ {"Price Tracking with Optimization Guide and Opt Out",
+ kCommercePriceTrackingWithOptimizationGuideAndOptOut,
+ base::size(kCommercePriceTrackingWithOptimizationGuideAndOptOut),
+ nullptr}};
+
+extern const base::Feature kCommerceMerchantViewer;
+extern const base::FeatureParam<bool> kDeleteAllMerchantsOnClearBrowsingHistory;
+extern const base::Feature kShoppingList;
+extern const base::Feature kShoppingPDPMetrics;
+extern const base::Feature kRetailCoupons;
+extern const base::Feature kCommerceDeveloper;
+// Parameter for enabling feature variation of coupons with code.
+extern const char kRetailCouponsWithCodeParam[];
+
+// Feature flag for Discount user consent v2.
+extern const base::Feature kDiscountConsentV2;
+
+// Interval that controls the frequency of showing coupons in infobar bubbles.
+constexpr base::FeatureParam<base::TimeDelta> kCouponDisplayInterval{
+ &commerce::kRetailCoupons, "coupon_display_interval", base::Hours(18)};
+
+// Check if a URL belongs to a partner merchant of coupon discount.
+bool IsCouponDiscountPartnerMerchant(const GURL& url);
+// Check if the feature variation of coupons with code is enabled.
+bool IsCouponWithCodeEnabled();
+} // namespace commerce
+
+#endif // COMPONENTS_COMMERCE_CORE_COMMERCE_FEATURE_LIST_H_
diff --git a/chromium/components/commerce/core/flag_descriptions.cc b/chromium/components/commerce/core/flag_descriptions.cc
new file mode 100644
index 00000000000..2104e0d4c6e
--- /dev/null
+++ b/chromium/components/commerce/core/flag_descriptions.cc
@@ -0,0 +1,13 @@
+// Copyright 2022 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.
+
+#include "components/commerce/core/flag_descriptions.h"
+
+namespace commerce::flag_descriptions {
+
+const char kCommercePriceTrackingName[] = "Price Tracking";
+const char kCommercePriceTrackingDescription[] =
+ "Allows users to track product prices through Chrome.";
+
+} // namespace commerce::flag_descriptions
diff --git a/chromium/components/commerce/core/flag_descriptions.h b/chromium/components/commerce/core/flag_descriptions.h
new file mode 100644
index 00000000000..7fe751305bb
--- /dev/null
+++ b/chromium/components/commerce/core/flag_descriptions.h
@@ -0,0 +1,18 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_COMMERCE_CORE_FLAG_DESCRIPTIONS_H_
+#define COMPONENTS_COMMERCE_CORE_FLAG_DESCRIPTIONS_H_
+
+namespace commerce::flag_descriptions {
+
+// Enables the user to track prices of the Shopping URLs they are visiting.
+// The first variation is to display price drops in the Tab Switching UI when
+// they are identified.
+extern const char kCommercePriceTrackingName[];
+extern const char kCommercePriceTrackingDescription[];
+
+} // namespace commerce::flag_descriptions
+
+#endif // COMPONENTS_COMMERCE_CORE_FLAG_DESCRIPTIONS_H_
diff --git a/chromium/components/commerce/core/metrics/metrics_utils.cc b/chromium/components/commerce/core/metrics/metrics_utils.cc
new file mode 100644
index 00000000000..a2ccf06b83a
--- /dev/null
+++ b/chromium/components/commerce/core/metrics/metrics_utils.cc
@@ -0,0 +1,59 @@
+// Copyright 2022 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.
+
+#include "components/commerce/core/metrics/metrics_utils.h"
+
+#include "base/metrics/histogram_functions.h"
+#include "components/commerce/core/proto/price_tracking.pb.h"
+#include "components/optimization_guide/core/optimization_guide_decision.h"
+#include "components/optimization_guide/core/optimization_guide_permissions_util.h"
+
+namespace commerce::metrics {
+
+void RecordPDPStateToUma(ShoppingPDPState state) {
+ base::UmaHistogramEnumeration("Commerce.PDPStateOnNavigation", state);
+}
+
+ShoppingPDPState ComputeStateForOptGuideResult(
+ optimization_guide::OptimizationGuideDecision decision,
+ const optimization_guide::OptimizationMetadata& metadata) {
+ if (decision != optimization_guide::OptimizationGuideDecision::kTrue ||
+ !metadata.any_metadata().has_value()) {
+ return ShoppingPDPState::kNotPDP;
+ }
+
+ absl::optional<PriceTrackingData> parsed_any =
+ optimization_guide::ParsedAnyMetadata<PriceTrackingData>(
+ metadata.any_metadata().value());
+
+ if (!parsed_any.has_value() || !parsed_any.value().IsInitialized())
+ return ShoppingPDPState::kNotPDP;
+
+ const PriceTrackingData& price_data = parsed_any.value();
+
+ if (price_data.has_buyable_product() &&
+ price_data.buyable_product().has_product_cluster_id()) {
+ return ShoppingPDPState::kIsPDPWithClusterId;
+ }
+
+ return ShoppingPDPState::kIsPDPWithoutClusterId;
+}
+
+void RecordPDPStateForNavigation(
+ optimization_guide::OptimizationGuideDecision decision,
+ const optimization_guide::OptimizationMetadata& metadata,
+ PrefService* pref_service,
+ bool is_off_the_record) {
+ // If optimization guide isn't allowed to run, don't attempt to query and
+ // record the metrics.
+ if (!pref_service ||
+ !optimization_guide::IsUserPermittedToFetchFromRemoteOptimizationGuide(
+ is_off_the_record, pref_service)) {
+ return;
+ }
+
+ RecordPDPStateToUma(ComputeStateForOptGuideResult(decision, metadata));
+}
+
+} // namespace commerce::metrics
diff --git a/chromium/components/commerce/core/metrics/metrics_utils.h b/chromium/components/commerce/core/metrics/metrics_utils.h
new file mode 100644
index 00000000000..15e0817d0b3
--- /dev/null
+++ b/chromium/components/commerce/core/metrics/metrics_utils.h
@@ -0,0 +1,39 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_COMMERCE_CORE_METRICS_METRICS_UTILS_H_
+#define COMPONENTS_COMMERCE_CORE_METRICS_METRICS_UTILS_H_
+
+#include "components/optimization_guide/core/optimization_guide_util.h"
+#include "components/optimization_guide/core/optimization_metadata.h"
+#include "components/optimization_guide/proto/hints.pb.h"
+#include "components/prefs/pref_service.h"
+
+namespace commerce::metrics {
+
+// Possible options for the stat of a product details page (PDP). These must be
+// kept in sync with the values in enums.xml.
+enum class ShoppingPDPState {
+ kNotPDP = 0,
+
+ // The cluster ID is used to identify a product that is not specific to a
+ // particular merchant (i.e. many merchants sell this). This is the
+ // counterpart to offer ID which identifies a product for a specific merchant.
+ kIsPDPWithoutClusterId = 1,
+ kIsPDPWithClusterId = 2,
+
+ // This enum must be last and is only used for histograms.
+ kMaxValue = kIsPDPWithClusterId
+};
+
+// Record the state of a PDP for a navigation.
+void RecordPDPStateForNavigation(
+ optimization_guide::OptimizationGuideDecision decision,
+ const optimization_guide::OptimizationMetadata& metadata,
+ PrefService* pref_service,
+ bool is_off_the_record);
+
+} // namespace commerce::metrics
+
+#endif // COMPONENTS_COMMERCE_CORE_METRICS_METRICS_UTILS_H_
diff --git a/chromium/components/component_updater/android/component_loader_policy.cc b/chromium/components/component_updater/android/component_loader_policy.cc
index cdffa4e6b2a..4a145130e4a 100644
--- a/chromium/components/component_updater/android/component_loader_policy.cc
+++ b/chromium/components/component_updater/android/component_loader_policy.cc
@@ -30,6 +30,7 @@
#include "base/metrics/histogram_functions.h"
#include "base/sequence_checker.h"
#include "base/strings/strcat.h"
+#include "base/strings/string_util.h"
#include "base/task/post_task.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
@@ -163,7 +164,10 @@ void AndroidComponentLoaderPolicy::NotifyNewVersion(
return;
}
std::string version_ascii;
- manifest->GetStringASCII("version", &version_ascii);
+ if (const std::string* ptr = manifest->FindStringKey("version")) {
+ if (base::IsStringASCII(*ptr))
+ version_ascii = *ptr;
+ }
base::Version version(version_ascii);
if (!version.IsValid()) {
ComponentLoadFailedInternal(ComponentLoadResult::kInvalidVersion);
diff --git a/chromium/components/component_updater/component_installer.cc b/chromium/components/component_updater/component_installer.cc
index 4c08b85452f..e9ceaeca9e2 100644
--- a/chromium/components/component_updater/component_installer.cc
+++ b/chromium/components/component_updater/component_installer.cc
@@ -6,6 +6,7 @@
#include <cstdint>
#include <string>
+#include <tuple>
#include <utility>
#include <vector>
@@ -15,7 +16,6 @@
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
-#include "base/ignore_result.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/path_service.h"
@@ -40,6 +40,10 @@
#include "components/update_client/utils.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
+#if BUILDFLAG(IS_APPLE)
+#include "base/mac/backup_util.h"
+#endif
+
namespace component_updater {
namespace {
@@ -71,21 +75,22 @@ ComponentInstaller::ComponentInstaller(
ComponentInstaller::~ComponentInstaller() = default;
void ComponentInstaller::Register(ComponentUpdateService* cus,
- base::OnceClosure callback) {
+ base::OnceClosure callback,
+ base::TaskPriority task_priority) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(cus);
Register(base::BindOnce(&ComponentUpdateService::RegisterComponent,
base::Unretained(cus)),
- std::move(callback));
+ std::move(callback), task_priority);
}
void ComponentInstaller::Register(RegisterCallback register_callback,
- base::OnceClosure callback) {
+ base::OnceClosure callback,
+ base::TaskPriority task_priority) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- // Some components may affect user visible features, hence USER_VISIBLE.
task_runner_ = base::ThreadPool::CreateSequencedTaskRunner(
- {base::MayBlock(), base::TaskPriority::USER_VISIBLE,
+ {base::MayBlock(), task_priority,
base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN});
if (!installer_policy_) {
@@ -151,7 +156,7 @@ Result ComponentInstaller::InstallHelper(const base::FilePath& unpack_path,
// Acquire the ownership of the |local_install_path|.
base::ScopedTempDir install_path_owner;
- ignore_result(install_path_owner.Set(local_install_path));
+ std::ignore = install_path_owner.Set(local_install_path);
#if BUILDFLAG(IS_CHROMEOS_ASH)
if (!base::SetPosixFilePermissions(local_install_path, 0755)) {
@@ -164,6 +169,12 @@ Result ComponentInstaller::InstallHelper(const base::FilePath& unpack_path,
DCHECK(!base::PathExists(unpack_path));
DCHECK(base::PathExists(local_install_path));
+#if BUILDFLAG(IS_APPLE)
+ // Since components can be large and can be re-downloaded when needed, they
+ // are excluded from backups.
+ base::mac::SetBackupExclusion(local_install_path);
+#endif
+
const Result result =
installer_policy_->OnCustomInstall(local_manifest, local_install_path);
if (result.error)
@@ -309,9 +320,8 @@ void ComponentInstaller::StartRegistration(
#if BUILDFLAG(IS_CHROMEOS_ASH)
base::FilePath base_dir_ = base_component_dir;
- std::vector<base::FilePath::StringType> components;
- installer_policy_->GetRelativeInstallDir().GetComponents(&components);
- for (const base::FilePath::StringType& component : components) {
+ for (const base::FilePath::StringType& component :
+ installer_policy_->GetRelativeInstallDir().GetComponents()) {
base_dir_ = base_dir_.Append(component);
if (!base::SetPosixFilePermissions(base_dir_, 0755)) {
PLOG(ERROR) << "SetPosixFilePermissions failed: " << base_dir.value();
diff --git a/chromium/components/component_updater/component_installer.h b/chromium/components/component_updater/component_installer.h
index 7dd911ade86..5e2561eb7af 100644
--- a/chromium/components/component_updater/component_installer.h
+++ b/chromium/components/component_updater/component_installer.h
@@ -14,6 +14,7 @@
#include "base/callback_forward.h"
#include "base/files/file_path.h"
#include "base/memory/ref_counted.h"
+#include "base/task/task_traits.h"
#include "base/threading/thread_checker.h"
#include "base/values.h"
#include "base/version.h"
@@ -123,12 +124,24 @@ class ComponentInstaller final : public update_client::CrxInstaller {
// |cus| provides the registration logic.
// The passed |callback| will be called once the initial check for installed
// versions is done and the component has been registered.
- void Register(ComponentUpdateService* cus, base::OnceClosure callback);
+ // Registration tasks will be done with a priority of |task_priority|. Some
+ // components may affect user-visible features, hence a default of
+ // USER_VISIBLE.
+ void Register(
+ ComponentUpdateService* cus,
+ base::OnceClosure callback,
+ base::TaskPriority task_priority = base::TaskPriority::USER_VISIBLE);
// Registers the component for update checks and installs.
// |register_callback| is called to do the registration.
// |callback| is called when registration finishes.
- void Register(RegisterCallback register_callback, base::OnceClosure callback);
+ // Registration tasks will be done with a priority of |task_priority|. Some
+ // components may affect user-visible features, hence a default of
+ // USER_VISIBLE.
+ void Register(
+ RegisterCallback register_callback,
+ base::OnceClosure callback,
+ base::TaskPriority task_priority = base::TaskPriority::USER_VISIBLE);
// Overrides from update_client::CrxInstaller.
void OnUpdateError(int error) override;
diff --git a/chromium/components/component_updater/component_installer_unittest.cc b/chromium/components/component_updater/component_installer_unittest.cc
index 48d3de2f522..51c206c1507 100644
--- a/chromium/components/component_updater/component_installer_unittest.cc
+++ b/chromium/components/component_updater/component_installer_unittest.cc
@@ -17,7 +17,9 @@
#include "base/memory/ref_counted.h"
#include "base/path_service.h"
#include "base/run_loop.h"
+#include "base/sequence_checker.h"
#include "base/task/post_task.h"
+#include "base/test/bind.h"
#include "base/test/scoped_path_override.h"
#include "base/test/task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
@@ -126,7 +128,13 @@ class MockUpdateClient : public UpdateClient {
class MockInstallerPolicy : public ComponentInstallerPolicy {
public:
- MockInstallerPolicy() = default;
+ using ComponentReadyCallback =
+ base::OnceCallback<void(const base::Version& version,
+ const base::FilePath& install_dir,
+ base::Value manifest)>;
+ explicit MockInstallerPolicy(
+ ComponentReadyCallback component_ready_cb = ComponentReadyCallback())
+ : component_ready_cb_(std::move(component_ready_cb)) {}
~MockInstallerPolicy() override = default;
bool VerifyInstallation(const base::Value& manifest,
@@ -150,7 +158,12 @@ class MockInstallerPolicy : public ComponentInstallerPolicy {
void ComponentReady(const base::Version& version,
const base::FilePath& install_dir,
- base::Value manifest) override {}
+ base::Value manifest) override {
+ if (component_ready_cb_) {
+ std::move(component_ready_cb_)
+ .Run(version, install_dir, std::move(manifest));
+ }
+ }
base::FilePath GetRelativeInstallDir() const override {
return base::FilePath(relative_install_dir);
@@ -171,6 +184,8 @@ class MockInstallerPolicy : public ComponentInstallerPolicy {
static void GetPkHash(std::vector<uint8_t>* hash) {
hash->assign(std::begin(kSha256Hash), std::end(kSha256Hash));
}
+
+ ComponentReadyCallback component_ready_cb_;
};
class MockUpdateScheduler : public UpdateScheduler {
@@ -337,6 +352,96 @@ TEST_F(ComponentInstallerTest, RegisterComponent) {
EXPECT_TRUE(component.requires_network_encryption);
}
+// Tests that `ComponentInstallerPolicy::ComponentReady` and the completion
+// callback of `ComponentInstaller::Register` are called in sequence.
+TEST_F(ComponentInstallerTest, InstallerRegister_CheckSequence) {
+ class RegisterHandler {
+ public:
+ virtual ~RegisterHandler() = default;
+
+ virtual void ComponentReady() = 0;
+ virtual void RegisterComplete() = 0;
+ };
+
+ // Allows defining call expectations on its functions when the functions
+ // are invoked by callbacks posted from `ComponentInstaller::Register`.
+ class MockRegisterHandler : public RegisterHandler {
+ public:
+ MockRegisterHandler() {
+ ON_CALL(*this, ComponentReady)
+ .WillByDefault(Invoke(this, &MockRegisterHandler::CheckSequence));
+ ON_CALL(*this, RegisterComplete)
+ .WillByDefault(Invoke(this, &MockRegisterHandler::CheckSequence));
+ }
+
+ MOCK_METHOD(void, ComponentReady, (), (override));
+ MOCK_METHOD(void, RegisterComplete, (), (override));
+
+ private:
+ void CheckSequence() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker); }
+ SEQUENCE_CHECKER(sequence_checker);
+ };
+
+ base::ScopedPathOverride scoped_path_override(DIR_COMPONENT_USER);
+
+ // Install a CRX component so that `ComponentInstallerPolicy::ComponentReady`
+ // can be invoked later on.
+ {
+ base::RunLoop run_loop;
+ auto installer = base::MakeRefCounted<ComponentInstaller>(
+ std::make_unique<MockInstallerPolicy>());
+ Unpack(test_file("jebgalgnebhfojomionfpkfelancnnkf.crx"));
+ ASSERT_EQ(result().error, update_client::UnpackerError::kNone);
+ base::FilePath base_dir;
+ ASSERT_TRUE(base::PathService::Get(DIR_COMPONENT_USER, &base_dir));
+ base_dir = base_dir.Append(relative_install_dir);
+ ASSERT_TRUE(base::CreateDirectory(base_dir));
+ installer->Install(
+ result().unpack_path, update_client::jebg_public_key, nullptr,
+ base::DoNothing(),
+ base::BindLambdaForTesting(
+ [&run_loop](const update_client::CrxInstaller::Result& result) {
+ ASSERT_EQ(result.error, 0);
+ run_loop.QuitClosure().Run();
+ }));
+ run_loop.Run();
+ }
+
+ base::RunLoop run_loop;
+ EXPECT_CALL(update_client(), DoUpdate(_, _)).WillOnce(Invoke([&run_loop]() {
+ run_loop.QuitClosure().Run();
+ }));
+
+ // Set up expectations for uninteresting calls on the mocks due to component
+ // updater waking up after the component is registered.
+ EXPECT_CALL(scheduler(), Schedule(_, _, _, _)).Times(1);
+ EXPECT_CALL(scheduler(), Stop()).Times(1);
+ EXPECT_CALL(update_client(), Stop()).Times(1);
+
+ MockRegisterHandler mock_register_handler;
+ {
+ ::testing::InSequence seq;
+ EXPECT_CALL(mock_register_handler, ComponentReady()).Times(1);
+ EXPECT_CALL(mock_register_handler, RegisterComplete()).Times(1);
+ }
+
+ auto installer_policy =
+ std::make_unique<MockInstallerPolicy>(base::BindLambdaForTesting(
+ [&mock_register_handler](const base::Version& version,
+ const base::FilePath& install_dir,
+ base::Value manifest) {
+ EXPECT_EQ(version.GetString(), "1.0");
+ mock_register_handler.ComponentReady();
+ }));
+ auto installer =
+ base::MakeRefCounted<ComponentInstaller>(std::move(installer_policy));
+ installer->Register(component_updater(),
+ base::BindLambdaForTesting([&mock_register_handler]() {
+ mock_register_handler.RegisterComplete();
+ }));
+ run_loop.Run();
+}
+
// Tests that the unpack path is removed when the install succeeded.
TEST_F(ComponentInstallerTest, UnpackPathInstallSuccess) {
auto installer = base::MakeRefCounted<ComponentInstaller>(
diff --git a/chromium/components/component_updater/component_updater_command_line_config_policy.cc b/chromium/components/component_updater/component_updater_command_line_config_policy.cc
index 708dbb7b4f3..ed0fe4b8a7a 100644
--- a/chromium/components/component_updater/component_updater_command_line_config_policy.cc
+++ b/chromium/components/component_updater/component_updater_command_line_config_policy.cc
@@ -39,10 +39,10 @@ const char kSwitchDisableDeltaUpdates[] = "disable-delta-updates";
// value is in seconds.
const char kInitialDelay[] = "initial-delay";
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// Disables background downloads.
const char kSwitchDisableBackgroundDownloads[] = "disable-background-downloads";
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
// If there is an element of |vec| of the form |test|=.*, returns the right-
// hand side of that assignment. Otherwise, returns an empty string.
@@ -76,7 +76,7 @@ ComponentUpdaterCommandLineConfigPolicy::
cmdline->GetSwitchValueASCII(switches::kComponentUpdater), ",",
base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
background_downloads_enabled_ =
!base::Contains(switch_values, kSwitchDisableBackgroundDownloads);
#else
diff --git a/chromium/components/component_updater/configurator_impl.cc b/chromium/components/component_updater/configurator_impl.cc
index 53dda33d8d0..c6d75f0ecb1 100644
--- a/chromium/components/component_updater/configurator_impl.cc
+++ b/chromium/components/component_updater/configurator_impl.cc
@@ -4,11 +4,13 @@
#include "components/component_updater/configurator_impl.h"
-#include <stddef.h>
-
#include <algorithm>
+#include <string>
+#include <vector>
#include "base/callback.h"
+#include "base/containers/flat_map.h"
+#include "base/enterprise_util.h"
#include "base/feature_list.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
@@ -20,10 +22,12 @@
#include "components/update_client/protocol_handler.h"
#include "components/update_client/utils.h"
#include "components/version_info/version_info.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "url/gurl.h"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include "base/win/win_util.h"
-#endif // OS_WIN
+#endif
namespace component_updater {
@@ -132,4 +136,23 @@ ConfiguratorImpl::GetProtocolHandlerFactory() const {
return std::make_unique<update_client::ProtocolHandlerFactoryJSON>();
}
+// Returns a "do nothing" callback which returns an empty updater state.
+// This is the correct default for all the embedders except the component
+// updater for Chrome on macOS and Windows, which includes a recovery
+// component.
+update_client::UpdaterStateProvider ConfiguratorImpl::GetUpdaterStateProvider()
+ const {
+ return base::BindRepeating([](bool /*is_machine*/) {
+ return base::flat_map<std::string, std::string>();
+ });
+}
+
+absl::optional<bool> ConfiguratorImpl::IsMachineExternallyManaged() const {
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
+ return base::IsMachineExternallyManaged();
+#else
+ return absl::nullopt;
+#endif
+}
+
} // namespace component_updater
diff --git a/chromium/components/component_updater/configurator_impl.h b/chromium/components/component_updater/configurator_impl.h
index e599aadf635..f73f690c855 100644
--- a/chromium/components/component_updater/configurator_impl.h
+++ b/chromium/components/component_updater/configurator_impl.h
@@ -11,6 +11,7 @@
#include "base/containers/flat_map.h"
#include "components/update_client/configurator.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
#include "url/gurl.h"
namespace base {
@@ -94,6 +95,10 @@ class ConfiguratorImpl {
std::unique_ptr<update_client::ProtocolHandlerFactory>
GetProtocolHandlerFactory() const;
+ absl::optional<bool> IsMachineExternallyManaged() const;
+
+ update_client::UpdaterStateProvider GetUpdaterStateProvider() const;
+
private:
base::flat_map<std::string, std::string> extra_info_;
const bool background_downloads_enabled_;
diff --git a/chromium/components/component_updater/installer_policies/client_side_phishing_component_installer_policy.cc b/chromium/components/component_updater/installer_policies/client_side_phishing_component_installer_policy.cc
index 17ebcd2a573..6556544cca9 100644
--- a/chromium/components/component_updater/installer_policies/client_side_phishing_component_installer_policy.cc
+++ b/chromium/components/component_updater/installer_policies/client_side_phishing_component_installer_policy.cc
@@ -18,12 +18,10 @@
#include "components/component_updater/component_installer.h"
namespace component_updater {
-const base::FilePath::CharType kClientModelBinaryPbFileName[] =
- FILE_PATH_LITERAL("client_model.pb");
-const base::FilePath::CharType kVisualTfLiteModelFileName[] =
- FILE_PATH_LITERAL("visual_model.tflite");
namespace {
+const char kClientSidePhishingManifestName[] = "Client Side Phishing Detection";
+
// The SHA256 of the SubjectPublicKeyInfo used to sign the extension.
// The extension id is: imefjhfbkmcmebodilednhmaccmincoa
const uint8_t kClientSidePhishingPublicKeySHA256[32] = {
@@ -31,10 +29,13 @@ const uint8_t kClientSidePhishingPublicKeySHA256[32] = {
0xc0, 0x22, 0xc8, 0xd2, 0xe0, 0xe3, 0xe2, 0x33, 0x88, 0x1f, 0x09,
0x6d, 0xde, 0x65, 0x6a, 0x83, 0x32, 0x71, 0x52, 0x6e, 0x77};
-const char kClientSidePhishingManifestName[] = "Client Side Phishing Detection";
-
} // namespace
+const base::FilePath::CharType kClientModelBinaryPbFileName[] =
+ FILE_PATH_LITERAL("client_model.pb");
+const base::FilePath::CharType kVisualTfLiteModelFileName[] =
+ FILE_PATH_LITERAL("visual_model.tflite");
+
ClientSidePhishingComponentInstallerPolicy::
ClientSidePhishingComponentInstallerPolicy(
const ReadFilesCallback& read_files_callback,
@@ -46,6 +47,14 @@ ClientSidePhishingComponentInstallerPolicy::
ClientSidePhishingComponentInstallerPolicy::
~ClientSidePhishingComponentInstallerPolicy() = default;
+// static
+void ClientSidePhishingComponentInstallerPolicy::GetPublicHash(
+ std::vector<uint8_t>* hash) {
+ hash->assign(kClientSidePhishingPublicKeySHA256,
+ kClientSidePhishingPublicKeySHA256 +
+ base::size(kClientSidePhishingPublicKeySHA256));
+}
+
bool ClientSidePhishingComponentInstallerPolicy::
SupportsGroupPolicyEnabledComponentUpdates() const {
return true;
@@ -89,9 +98,7 @@ ClientSidePhishingComponentInstallerPolicy::GetRelativeInstallDir() const {
void ClientSidePhishingComponentInstallerPolicy::GetHash(
std::vector<uint8_t>* hash) const {
- hash->assign(kClientSidePhishingPublicKeySHA256,
- kClientSidePhishingPublicKeySHA256 +
- base::size(kClientSidePhishingPublicKeySHA256));
+ GetPublicHash(hash);
}
std::string ClientSidePhishingComponentInstallerPolicy::GetName() const {
diff --git a/chromium/components/component_updater/installer_policies/client_side_phishing_component_installer_policy.h b/chromium/components/component_updater/installer_policies/client_side_phishing_component_installer_policy.h
index bf95047a094..825c8ea1a1e 100644
--- a/chromium/components/component_updater/installer_policies/client_side_phishing_component_installer_policy.h
+++ b/chromium/components/component_updater/installer_policies/client_side_phishing_component_installer_policy.h
@@ -45,6 +45,8 @@ class ClientSidePhishingComponentInstallerPolicy
const ClientSidePhishingComponentInstallerPolicy&) = delete;
~ClientSidePhishingComponentInstallerPolicy() override;
+ static void GetPublicHash(std::vector<uint8_t>* hash);
+
private:
// The following methods override ComponentInstallerPolicy.
bool SupportsGroupPolicyEnabledComponentUpdates() const override;
diff --git a/chromium/components/component_updater/pref_names.cc b/chromium/components/component_updater/pref_names.cc
index e8162d00ad7..712c63f2108 100644
--- a/chromium/components/component_updater/pref_names.cc
+++ b/chromium/components/component_updater/pref_names.cc
@@ -18,7 +18,7 @@ const char kRecoveryComponentVersion[] = "recovery_component.version";
// Full path where last recovery component CRX was unpacked to.
const char kRecoveryComponentUnpackPath[] = "recovery_component.unpack_path";
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// The last exit code integer value returned by the SwReporter. Saved in local
// state.
const char kSwReporterLastExitCode[] = "software_reporter.last_exit_code";
diff --git a/chromium/components/component_updater/pref_names.h b/chromium/components/component_updater/pref_names.h
index 1d645a3fdcf..f486a556256 100644
--- a/chromium/components/component_updater/pref_names.h
+++ b/chromium/components/component_updater/pref_names.h
@@ -14,7 +14,7 @@ extern const char kComponentUpdatesEnabled[];
extern const char kRecoveryComponentVersion[];
extern const char kRecoveryComponentUnpackPath[];
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// Local state prefs.
extern const char kSwReporterLastExitCode[];
extern const char kSwReporterLastTimeTriggered[];
diff --git a/chromium/components/components_chromium_strings.grd b/chromium/components/components_chromium_strings.grd
index f627c9c2d09..8ebae851153 100644
--- a/chromium/components/components_chromium_strings.grd
+++ b/chromium/components/components_chromium_strings.grd
@@ -36,8 +36,10 @@
<output filename="components_chromium_strings_zh-HK.pak" type="data_package" lang="zh-HK" />
<output filename="components_chromium_strings_zu.pak" type="data_package" lang="zu" />
</if>
- <if expr="chromeos or lacros">
+ <if expr="chromeos_ash or chromeos_lacros">
+ <output filename="components_chromium_strings_af.pak" type="data_package" lang="af" />
<output filename="components_chromium_strings_is.pak" type="data_package" lang="is" />
+ <output filename="components_chromium_strings_zu.pak" type="data_package" lang="zu" />
</if>
<output filename="components_chromium_strings_am.pak" type="data_package" lang="am" />
<output filename="components_chromium_strings_ar.pak" type="data_package" lang="ar" />
diff --git a/chromium/components/components_google_chrome_strings.grd b/chromium/components/components_google_chrome_strings.grd
index 652475a9b69..15c59870091 100644
--- a/chromium/components/components_google_chrome_strings.grd
+++ b/chromium/components/components_google_chrome_strings.grd
@@ -36,8 +36,10 @@
<output filename="components_google_chrome_strings_zh-HK.pak" type="data_package" lang="zh-HK" />
<output filename="components_google_chrome_strings_zu.pak" type="data_package" lang="zu" />
</if>
- <if expr="chromeos or lacros">
+ <if expr="chromeos_ash or chromeos_lacros">
+ <output filename="components_google_chrome_strings_af.pak" type="data_package" lang="af" />
<output filename="components_google_chrome_strings_is.pak" type="data_package" lang="is" />
+ <output filename="components_google_chrome_strings_zu.pak" type="data_package" lang="zu" />
</if>
<output filename="components_google_chrome_strings_am.pak" type="data_package" lang="am" />
<output filename="components_google_chrome_strings_ar.pak" type="data_package" lang="ar" />
@@ -216,9 +218,16 @@
<message name="IDS_ERRORPAGES_SUMMARY_BLOCKED_BY_CLIENT" desc="Summary in the error page when a request is blocked by the browser.">
This page has been blocked by Chrome
</message>
- <message name="IDS_ERRORPAGES_SUMMARY_BLOCKED_ENROLLMENT_CHECK_PENDING" desc="Summary in the error page when the user tries to browse before the forced enrollment check has finished.">
- Chrome OS hasn’t completed its initial setup.
- </message>
+ <if expr="reven">
+ <message name="IDS_ERRORPAGES_SUMMARY_BLOCKED_ENROLLMENT_CHECK_PENDING" desc="Summary in the error page when the user tries to browse before the forced enrollment check has finished.">
+ CloudReady 2.0 hasn’t completed its initial setup.
+ </message>
+ </if>
+ <if expr="not reven">
+ <message name="IDS_ERRORPAGES_SUMMARY_BLOCKED_ENROLLMENT_CHECK_PENDING" desc="Summary in the error page when the user tries to browse before the forced enrollment check has finished.">
+ Chrome OS hasn’t completed its initial setup.
+ </message>
+ </if>
<if expr="is_macosx">
<message name="IDS_ERRORPAGES_SUGGESTION_PROXY_DISABLE_PLATFORM" desc="Mac OSX instructions for disabling use of a proxy server.">
Go to
diff --git a/chromium/components/components_locale_settings.grd b/chromium/components/components_locale_settings.grd
index 5f19a473ff5..7b483b09ae2 100644
--- a/chromium/components/components_locale_settings.grd
+++ b/chromium/components/components_locale_settings.grd
@@ -34,8 +34,10 @@
<output filename="components_locale_settings_zh-HK.pak" type="data_package" lang="zh-HK" />
<output filename="components_locale_settings_zu.pak" type="data_package" lang="zu" />
</if>
- <if expr="chromeos or lacros">
+ <if expr="chromeos_ash or chromeos_lacros">
+ <output filename="components_locale_settings_af.pak" type="data_package" lang="af" />
<output filename="components_locale_settings_is.pak" type="data_package" lang="is" />
+ <output filename="components_locale_settings_zu.pak" type="data_package" lang="zu" />
</if>
<output filename="components_locale_settings_am.pak" type="data_package" lang="am" />
<output filename="components_locale_settings_ar.pak" type="data_package" lang="ar" />
diff --git a/chromium/components/components_strings.grd b/chromium/components/components_strings.grd
index 5f3971e0596..43df0688afe 100644
--- a/chromium/components/components_strings.grd
+++ b/chromium/components/components_strings.grd
@@ -36,8 +36,10 @@
<output filename="components_strings_zh-HK.pak" type="data_package" lang="zh-HK" />
<output filename="components_strings_zu.pak" type="data_package" lang="zu" />
</if>
- <if expr="chromeos or lacros">
+ <if expr="chromeos_ash or chromeos_lacros">
+ <output filename="components_strings_af.pak" type="data_package" lang="af" />
<output filename="components_strings_is.pak" type="data_package" lang="is" />
+ <output filename="components_strings_zu.pak" type="data_package" lang="zu" />
</if>
<output filename="components_strings_am.pak" type="data_package" lang="am" />
<output filename="components_strings_ar.pak" type="data_package" lang="ar" />
@@ -321,6 +323,7 @@
<part file="print_media_strings.grdp" />
<part file="printing_component_strings.grdp" />
<part file="privacy_sandbox_strings.grdp" />
+ <part file="protocol_handler_strings.grdp" />
<part file="reset_password_strings.grdp" />
<part file="security_interstitials_strings.grdp" />
<part file="send_tab_to_self_strings.grdp" />
@@ -336,7 +339,7 @@
<part file="version_ui_strings.grdp" />
<part file="webapps_strings.grdp" />
- <if expr="not is_android and not is_ios">
+ <if expr="not is_ios">
<part file="management_strings.grdp" />
</if>
<if expr="not is_android and not is_ios">
diff --git a/chromium/components/consent_auditor/consent_auditor_impl.cc b/chromium/components/consent_auditor/consent_auditor_impl.cc
index 3148dac4a7a..c8d50d90016 100644
--- a/chromium/components/consent_auditor/consent_auditor_impl.cc
+++ b/chromium/components/consent_auditor/consent_auditor_impl.cc
@@ -147,14 +147,14 @@ void ConsentAuditorImpl::RecordLocalConsent(
const std::string& confirmation_text) {
DictionaryPrefUpdate consents_update(pref_service_,
prefs::kLocalConsentsDictionary);
- base::DictionaryValue* consents = consents_update.Get();
+ base::Value* consents = consents_update.Get();
DCHECK(consents);
- base::DictionaryValue record;
- record.SetKey(kLocalConsentDescriptionKey, base::Value(description_text));
- record.SetKey(kLocalConsentConfirmationKey, base::Value(confirmation_text));
- record.SetKey(kLocalConsentVersionKey, base::Value(app_version_));
- record.SetKey(kLocalConsentLocaleKey, base::Value(app_locale_));
+ base::Value record(base::Value::Type::DICTIONARY);
+ record.SetStringKey(kLocalConsentDescriptionKey, description_text);
+ record.SetStringKey(kLocalConsentConfirmationKey, confirmation_text);
+ record.SetStringKey(kLocalConsentVersionKey, app_version_);
+ record.SetStringKey(kLocalConsentLocaleKey, app_locale_);
consents->SetKey(feature, std::move(record));
}
diff --git a/chromium/components/consent_auditor/consent_auditor_impl_unittest.cc b/chromium/components/consent_auditor/consent_auditor_impl_unittest.cc
index 668a71e9877..0a482007469 100644
--- a/chromium/components/consent_auditor/consent_auditor_impl_unittest.cc
+++ b/chromium/components/consent_auditor/consent_auditor_impl_unittest.cc
@@ -172,7 +172,7 @@ TEST_F(ConsentAuditorImplTest, LocalConsentPrefRepresentation) {
consent_auditor()->RecordLocalConsent("feature1", kFeature1Description,
kFeature1Confirmation);
ASSERT_TRUE(pref_service()->HasPrefPath(prefs::kLocalConsentsDictionary));
- const base::DictionaryValue* consents =
+ const base::Value* consents =
pref_service()->GetDictionary(prefs::kLocalConsentsDictionary);
ASSERT_TRUE(consents);
std::string description;
diff --git a/chromium/components/constrained_window/constrained_window_views.cc b/chromium/components/constrained_window/constrained_window_views.cc
index 62b2d18fc4c..d662221bcc6 100644
--- a/chromium/components/constrained_window/constrained_window_views.cc
+++ b/chromium/components/constrained_window/constrained_window_views.cc
@@ -21,6 +21,7 @@
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_observer.h"
#include "ui/views/window/dialog_delegate.h"
+#include "url/gurl.h"
#if defined(USE_OZONE)
#include "ui/ozone/public/ozone_platform.h"
@@ -194,11 +195,16 @@ views::Widget* CreateWebModalDialogViews(views::WidgetDelegate* dialog,
DCHECK_EQ(ui::MODAL_TYPE_CHILD, dialog->GetModalType());
web_modal::WebContentsModalDialogManager* manager =
web_modal::WebContentsModalDialogManager::FromWebContents(web_contents);
- LOG_IF(FATAL, !manager) << "CreateWebModalDialogViews without a manager"
- << ", scheme="
- << web_contents->GetLastCommittedURL().scheme_piece()
- << ", host="
- << web_contents->GetLastCommittedURL().host_piece();
+
+ // TODO(http://crbug/1273287): Drop "if" and DEBUG_ALIAS_FOR_GURL after fix.
+ if (!manager) {
+ const GURL& url = web_contents->GetLastCommittedURL();
+ DEBUG_ALIAS_FOR_GURL(url_alias, url);
+ LOG_IF(FATAL, !manager)
+ << "CreateWebModalDialogViews without a manager"
+ << ", scheme=" << url.scheme_piece() << ", host=" << url.host_piece();
+ }
+
return views::DialogDelegate::CreateDialogWidget(
dialog, nullptr,
manager->delegate()->GetWebContentsModalDialogHost()->GetHostView());
@@ -223,7 +229,7 @@ views::Widget* CreateBrowserModalDialogViews(views::DialogDelegate* dialog,
bool requires_positioning = dialog->use_custom_frame();
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
// On Mac, window modal dialogs are displayed as sheets, so their position is
// managed by the parent window.
requires_positioning = false;
diff --git a/chromium/components/constrained_window/constrained_window_views_unittest.cc b/chromium/components/constrained_window/constrained_window_views_unittest.cc
index 48992147bc8..47721c7d0a5 100644
--- a/chromium/components/constrained_window/constrained_window_views_unittest.cc
+++ b/chromium/components/constrained_window/constrained_window_views_unittest.cc
@@ -202,7 +202,7 @@ TEST_F(ConstrainedWindowViewsTest, MaximumWebContentsDialogSize) {
// Ensure CreateBrowserModalDialogViews() works correctly with a null parent.
// Flaky on Win10. https://crbug.com/1009182
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#define MAYBE_NullModalParent DISABLED_NullModalParent
#else
#define MAYBE_NullModalParent NullModalParent
diff --git a/chromium/components/content_capture/android/junit/BUILD.gn b/chromium/components/content_capture/android/junit/BUILD.gn
index c32ed45ca4e..3c567a74edc 100644
--- a/chromium/components/content_capture/android/junit/BUILD.gn
+++ b/chromium/components/content_capture/android/junit/BUILD.gn
@@ -21,6 +21,7 @@ java_library("components_content_capture_junit_tests") {
"//components/content_capture/android:java",
"//content/public/android:content_java",
"//third_party/android_deps:robolectric_all_java",
+ "//third_party/androidx:androidx_annotation_annotation_java",
"//third_party/junit",
"//third_party/mockito:mockito_java",
]
diff --git a/chromium/components/content_capture/android/junit/src/org/chromium/components/content_capture/PlatformContentCaptureControllerTest.java b/chromium/components/content_capture/android/junit/src/org/chromium/components/content_capture/PlatformContentCaptureControllerTest.java
index f45aa7b3998..a22c10b6152 100644
--- a/chromium/components/content_capture/android/junit/src/org/chromium/components/content_capture/PlatformContentCaptureControllerTest.java
+++ b/chromium/components/content_capture/android/junit/src/org/chromium/components/content_capture/PlatformContentCaptureControllerTest.java
@@ -8,7 +8,6 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.doReturn;
-import android.annotation.TargetApi;
import android.content.ComponentName;
import android.content.Context;
import android.content.LocusId;
@@ -16,6 +15,8 @@ import android.os.Build;
import android.view.contentcapture.ContentCaptureCondition;
import android.view.contentcapture.ContentCaptureManager;
+import androidx.annotation.RequiresApi;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -32,7 +33,7 @@ import java.util.HashSet;
*/
@RunWith(BaseRobolectricTestRunner.class)
@Config(manifest = Config.NONE)
-@TargetApi(Build.VERSION_CODES.Q)
+@RequiresApi(Build.VERSION_CODES.Q)
public class PlatformContentCaptureControllerTest {
private ContentCaptureManager mContentCaptureManager;
private Context mContext;
diff --git a/chromium/components/content_capture/android/test_support/content_capture_test_support_android.cc b/chromium/components/content_capture/android/test_support/content_capture_test_support_android.cc
index 3fbd2291205..ab7601e5cd7 100644
--- a/chromium/components/content_capture/android/test_support/content_capture_test_support_android.cc
+++ b/chromium/components/content_capture/android/test_support/content_capture_test_support_android.cc
@@ -51,11 +51,11 @@ static void JNI_ContentCaptureTestSupport_SimulateDidUpdateFaviconURL(
CHECK(root);
CHECK(root->is_list());
std::vector<blink::mojom::FaviconURLPtr> favicon_urls;
- for (const base::Value& icon : root->GetList()) {
+ for (const base::Value& icon : root->GetListDeprecated()) {
std::vector<gfx::Size> sizes;
// The sizes is optional.
if (auto* icon_sizes = icon.FindKey("sizes")) {
- for (const base::Value& size : icon_sizes->GetList()) {
+ for (const base::Value& size : icon_sizes->GetListDeprecated()) {
CHECK(size.FindKey("width"));
CHECK(size.FindKey("height"));
sizes.emplace_back(size.FindKey("width")->GetInt(),
diff --git a/chromium/components/content_capture/browser/BUILD.gn b/chromium/components/content_capture/browser/BUILD.gn
index f41a3ef1026..c7a5e3dd623 100644
--- a/chromium/components/content_capture/browser/BUILD.gn
+++ b/chromium/components/content_capture/browser/BUILD.gn
@@ -24,16 +24,42 @@ source_set("browser") {
deps = []
}
+source_set("test_support") {
+ testonly = true
+ sources = [
+ "content_capture_test_helper.cc",
+ "content_capture_test_helper.h",
+ ]
+
+ public_deps = [
+ ":browser",
+ "//testing/gtest",
+ ]
+}
+
source_set("unit_tests") {
testonly = true
sources = [ "content_capture_receiver_test.cc" ]
deps = [
- ":browser",
- "//base",
+ ":test_support",
"//base/test:test_support",
"//content/test:test_support",
- "//mojo/public/cpp/bindings",
- "//testing/gtest",
+ ]
+}
+
+source_set("browser_tests") {
+ testonly = true
+ sources = [ "content_capture_receiver_browsertest.cc" ]
+
+ defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ]
+
+ public_deps = [
+ ":test_support",
+ "//base/test:test_support",
+ "//content/public/browser",
+ "//content/shell:content_shell_lib",
+ "//content/test:browsertest_support",
+ "//content/test:test_support",
]
}
diff --git a/chromium/components/content_capture/browser/DEPS b/chromium/components/content_capture/browser/DEPS
index 5818eb72f8a..593f683671c 100644
--- a/chromium/components/content_capture/browser/DEPS
+++ b/chromium/components/content_capture/browser/DEPS
@@ -1,12 +1,17 @@
include_rules = [
"+content/public/browser",
- "+content/public/test",
"+third_party/blink/public/common/associated_interfaces",
"+third_party/blink/public/mojom/favicon",
]
specific_include_rules = {
- ".*_test.cc": [
+ ".*test.cc": [
+ "+content/public/test",
+ ],
+ "content_capture_receiver_test.cc": [
"+content/public/common",
],
+ "content_capture_receiver_browsertest.cc": [
+ "+content/shell/browser",
+ ],
}
diff --git a/chromium/components/content_capture/browser/content_capture_receiver_browsertest.cc b/chromium/components/content_capture/browser/content_capture_receiver_browsertest.cc
new file mode 100644
index 00000000000..c640738dc0d
--- /dev/null
+++ b/chromium/components/content_capture/browser/content_capture_receiver_browsertest.cc
@@ -0,0 +1,112 @@
+// Copyright 2021 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.
+
+#include "components/content_capture/browser/content_capture_test_helper.h"
+#include "content/public/test/browser_test.h"
+#include "content/public/test/content_browser_test.h"
+#include "content/public/test/fenced_frame_test_util.h"
+#include "content/shell/browser/shell.h"
+
+namespace content_capture {
+
+static constexpr char kMainFrameUrl[] = "/title1.html";
+static constexpr char kFencedFrameUrl[] = "/fenced_frames/title1.html";
+
+class ContentCaptureBrowserTest : public content::ContentBrowserTest {
+ public:
+ void SetUpOnMainThread() override {
+ content::ContentBrowserTest::SetUpOnMainThread();
+ ASSERT_TRUE(embedded_test_server()->Start());
+
+ // Navigate to the initial page.
+ const GURL main_frame_url = embedded_test_server()->GetURL(kMainFrameUrl);
+ ASSERT_TRUE(NavigateToURL(web_contents(), main_frame_url));
+ main_frame_ = web_contents()->GetMainFrame();
+ EXPECT_NE(nullptr, main_frame_);
+
+ // Create a provider and add a consumer.
+ helper_.CreateProviderAndConsumer(web_contents());
+
+ // Bind sender with receiver for main frame.
+ main_frame_sender_.Bind(main_frame_);
+
+ // Create a fenced frame.
+ const GURL fenced_frame_url =
+ embedded_test_server()->GetURL(kFencedFrameUrl);
+ fenced_frame_ =
+ fenced_frame_helper_.CreateFencedFrame(main_frame_, fenced_frame_url);
+ EXPECT_NE(nullptr, fenced_frame_);
+
+ // Bind sender with receiver for fenced frame.
+ fenced_frame_sender_.Bind(fenced_frame_);
+
+ helper_.InitTestData(base::UTF8ToUTF16(main_frame_url.spec()),
+ base::UTF8ToUTF16(fenced_frame_url.spec()));
+ }
+
+ int64_t GetFrameId(bool main_frame) {
+ return ContentCaptureReceiver::GetIdFrom(main_frame ? main_frame_.get()
+ : fenced_frame_.get());
+ }
+
+ content::WebContents* web_contents() { return shell()->web_contents(); }
+
+ OnscreenContentProvider* provider() const {
+ return helper_.onscreen_content_provider();
+ }
+
+ ContentCaptureConsumerHelper* consumer() const {
+ return helper_.content_capture_consumer();
+ }
+
+ FakeContentCaptureSender* main_frame_sender() { return &main_frame_sender_; }
+ FakeContentCaptureSender* fenced_frame_sender() {
+ return &fenced_frame_sender_;
+ }
+
+ ContentCaptureTestHelper* helper() { return &helper_; }
+
+ protected:
+ ContentCaptureTestHelper helper_;
+
+ raw_ptr<content::RenderFrameHost> main_frame_ = nullptr;
+ raw_ptr<content::RenderFrameHost> fenced_frame_ = nullptr;
+
+ FakeContentCaptureSender main_frame_sender_;
+ FakeContentCaptureSender fenced_frame_sender_;
+
+ content::test::FencedFrameTestHelper fenced_frame_helper_;
+};
+
+IN_PROC_BROWSER_TEST_F(ContentCaptureBrowserTest,
+ FencedFrameDidCaptureContent) {
+ // 2 frames - main & fenced
+ EXPECT_EQ(2u, provider()->GetFrameMapSizeForTesting());
+
+ // Simulate to capture the content from main frame.
+ main_frame_sender()->DidCaptureContent(helper()->test_data(),
+ true /* first_data */);
+ // Verifies to get test_data() with correct frame content id.
+ EXPECT_TRUE(consumer()->parent_session().empty());
+ EXPECT_TRUE(consumer()->removed_sessions().empty());
+ EXPECT_EQ(GetExpectedTestData(helper()->test_data(),
+ GetFrameId(true /* main_frame */)),
+ consumer()->captured_data());
+
+ // Simulate to capture the content from fenced frame.
+ fenced_frame_sender()->DidCaptureContent(helper()->test_data2(),
+ true /* first_data */);
+ // Verifies that the parent_session was set correctly.
+ EXPECT_FALSE(consumer()->parent_session().empty());
+ std::vector<ContentCaptureFrame> expected{GetExpectedTestData(
+ helper()->test_data(), GetFrameId(true /* main_frame */))};
+ VerifySession(expected, consumer()->parent_session());
+ EXPECT_TRUE(consumer()->removed_sessions().empty());
+ // Verifies that we receive the correct content from fenced frame.
+ EXPECT_EQ(GetExpectedTestData(helper()->test_data2(),
+ GetFrameId(false /* main_frame */)),
+ consumer()->captured_data());
+}
+
+} // namespace content_capture
diff --git a/chromium/components/content_capture/browser/content_capture_receiver_test.cc b/chromium/components/content_capture/browser/content_capture_receiver_test.cc
index 6af081dcba9..9f934df6dde 100644
--- a/chromium/components/content_capture/browser/content_capture_receiver_test.cc
+++ b/chromium/components/content_capture/browser/content_capture_receiver_test.cc
@@ -4,24 +4,14 @@
#include "components/content_capture/browser/content_capture_receiver.h"
-#include <memory>
-#include <utility>
-
#include "base/json/json_reader.h"
-#include "base/memory/raw_ptr.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/task/post_task.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/test_mock_time_task_runner.h"
#include "build/build_config.h"
-#include "components/content_capture/browser/content_capture_consumer.h"
-#include "components/content_capture/browser/onscreen_content_provider.h"
-#include "content/public/browser/content_browser_client.h"
-#include "content/public/browser/web_contents.h"
+#include "components/content_capture/browser/content_capture_test_helper.h"
#include "content/public/common/content_features.h"
#include "content/public/test/test_renderer_host.h"
#include "content/public/test/test_utils.h"
-#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/mojom/favicon/favicon_url.mojom.h"
#include "ui/gfx/geometry/size.h"
@@ -34,125 +24,6 @@ static constexpr char16_t kChildFrameUrl[] = u"http://foo.org/child.html";
static constexpr char16_t kMainFrameSameDocument[] =
u"http://foo.com/main.html#1";
-// Fake ContentCaptureSender to call ContentCaptureReceiver mojom interface.
-class FakeContentCaptureSender {
- public:
- FakeContentCaptureSender() {}
-
- void DidCaptureContent(const ContentCaptureData& captured_content,
- bool first_data) {
- content_capture_receiver_->DidCaptureContent(captured_content, first_data);
- }
-
- void DidUpdateContent(const ContentCaptureData& captured_content) {
- content_capture_receiver_->DidUpdateContent(captured_content);
- }
-
- void DidRemoveContent(const std::vector<int64_t>& data) {
- content_capture_receiver_->DidRemoveContent(data);
- }
-
- mojo::PendingAssociatedReceiver<mojom::ContentCaptureReceiver>
- GetPendingAssociatedReceiver() {
- return content_capture_receiver_.BindNewEndpointAndPassDedicatedReceiver();
- }
-
- private:
- mojo::AssociatedRemote<mojom::ContentCaptureReceiver>
- content_capture_receiver_;
-};
-
-class SessionRemovedTestHelper {
- public:
- void DidRemoveSession(const ContentCaptureSession& data) {
- removed_sessions_.push_back(data);
- }
-
- const std::vector<ContentCaptureSession>& removed_sessions() const {
- return removed_sessions_;
- }
-
- void Reset() { removed_sessions_.clear(); }
-
- private:
- std::vector<ContentCaptureSession> removed_sessions_;
-};
-
-// The helper class implements ContentCaptureConsumer and keeps the
-// result for verification.
-class ContentCaptureConsumerHelper : public ContentCaptureConsumer {
- public:
- explicit ContentCaptureConsumerHelper(
- SessionRemovedTestHelper* session_removed_test_helper)
- : session_removed_test_helper_(session_removed_test_helper) {}
-
- void DidCaptureContent(const ContentCaptureSession& parent_session,
- const ContentCaptureFrame& data) override {
- parent_session_ = parent_session;
- captured_data_ = data;
- }
-
- void DidUpdateContent(const ContentCaptureSession& parent_session,
- const ContentCaptureFrame& data) override {
- updated_parent_session_ = parent_session;
- updated_data_ = data;
- }
-
- void DidRemoveContent(const ContentCaptureSession& session,
- const std::vector<int64_t>& ids) override {
- session_ = session;
- removed_ids_ = ids;
- }
-
- void DidRemoveSession(const ContentCaptureSession& data) override {
- if (session_removed_test_helper_)
- session_removed_test_helper_->DidRemoveSession(data);
- removed_sessions_.push_back(data);
- }
-
- void DidUpdateTitle(const ContentCaptureFrame& main_frame) override {
- updated_title_ = main_frame.title;
- }
-
- void DidUpdateFavicon(const ContentCaptureFrame& main_frame) override {}
-
- bool ShouldCapture(const GURL& url) override { return false; }
-
- const ContentCaptureSession& parent_session() const {
- return parent_session_;
- }
-
- const ContentCaptureSession& updated_parent_session() const {
- return updated_parent_session_;
- }
-
- const ContentCaptureSession& session() const { return session_; }
-
- const ContentCaptureFrame& captured_data() const { return captured_data_; }
-
- const ContentCaptureFrame& updated_data() const { return updated_data_; }
-
- const std::vector<ContentCaptureSession>& removed_sessions() const {
- return removed_sessions_;
- }
-
- const std::vector<int64_t>& removed_ids() const { return removed_ids_; }
- const std::u16string& updated_title() const { return updated_title_; }
-
- void Reset() { removed_sessions_.clear(); }
-
- private:
- ContentCaptureSession parent_session_;
- ContentCaptureSession updated_parent_session_;
- ContentCaptureSession session_;
- ContentCaptureFrame captured_data_;
- ContentCaptureFrame updated_data_;
- std::vector<int64_t> removed_ids_;
- std::vector<ContentCaptureSession> removed_sessions_;
- raw_ptr<SessionRemovedTestHelper> session_removed_test_helper_;
- std::u16string updated_title_;
-};
-
} // namespace
class ContentCaptureReceiverTest : public content::RenderViewHostTestHarness,
@@ -168,208 +39,93 @@ class ContentCaptureReceiverTest : public content::RenderViewHostTestHarness,
{features::kBackForwardCacheMemoryControls});
}
content::RenderViewHostTestHarness::SetUp();
- onscreen_content_provider_ =
- OnscreenContentProvider::Create(web_contents());
-
- content_capture_consumer_helper_ =
- std::make_unique<ContentCaptureConsumerHelper>(
- &session_removed_test_helper_);
- onscreen_content_provider_->AddConsumer(
- *(content_capture_consumer_helper_.get()));
+ helper_.CreateProviderAndConsumer(web_contents(),
+ &session_removed_test_helper_);
// This needed to keep the WebContentsObserverConsistencyChecker checks
// happy for when AppendChild is called.
NavigateAndCommit(GURL(kMainFrameUrl));
- content_capture_sender_ = std::make_unique<FakeContentCaptureSender>();
main_frame_ = web_contents()->GetMainFrame();
- // Binds sender with receiver.
- OnscreenContentProvider::BindContentCaptureReceiver(
- content_capture_sender_->GetPendingAssociatedReceiver(), main_frame_);
-
- ContentCaptureData child;
- // Have the unique id for text content.
- child.id = 2;
- child.value = u"Hello";
- child.bounds = gfx::Rect(5, 5, 5, 5);
- // No need to set id in sender.
- test_data_.value = kMainFrameUrl;
- test_data_.bounds = gfx::Rect(10, 10);
- test_data_.children.push_back(child);
- test_data2_.value = kChildFrameUrl;
- test_data2_.bounds = gfx::Rect(10, 10);
- test_data2_.children.push_back(child);
-
- ContentCaptureData child_change;
- // Same ID with child.
- child_change.id = 2;
- child_change.value = u"Hello World";
- child_change.bounds = gfx::Rect(5, 5, 5, 5);
- test_data_change_.value = kMainFrameUrl;
- test_data_change_.bounds = gfx::Rect(10, 10);
- test_data_change_.children.push_back(child_change);
-
- // Update to test_data_.
- ContentCaptureData child2;
- // Have the unique id for text content.
- child2.id = 3;
- child2.value = u"World";
- child2.bounds = gfx::Rect(5, 10, 5, 5);
- test_data_update_.value = kMainFrameUrl;
- test_data_update_.bounds = gfx::Rect(10, 10);
- test_data_update_.children.push_back(child2);
+ EXPECT_TRUE(main_frame_);
+
+ main_frame_sender_ = std::make_unique<FakeContentCaptureSender>();
+ main_frame_sender_->Bind(main_frame_);
+
+ helper_.InitTestData(kMainFrameUrl, kChildFrameUrl);
}
void NavigateMainFrame(const GURL& url) {
- content_capture_consumer_helper()->Reset();
+ consumer()->Reset();
NavigateAndCommit(url);
main_frame_ = web_contents()->GetMainFrame();
}
void NavigateMainFrameSameDocument() {
- content_capture_consumer_helper()->Reset();
+ consumer()->Reset();
NavigateAndCommit(GURL(kMainFrameSameDocument));
}
void SetupChildFrame() {
- child_content_capture_sender_ =
- std::make_unique<FakeContentCaptureSender>();
- child_frame_ =
- content::RenderFrameHostTester::For(main_frame_)->AppendChild("child");
- // Binds sender with receiver for child frame.
- OnscreenContentProvider::BindContentCaptureReceiver(
- child_content_capture_sender_->GetPendingAssociatedReceiver(),
- child_frame_);
- }
+ child_frame_ = content::RenderFrameHostTester::For(main_frame_.get())
+ ->AppendChild("child");
+ EXPECT_TRUE(child_frame_);
- FakeContentCaptureSender* content_capture_sender() {
- return content_capture_sender_.get();
+ child_frame_sender_ = std::make_unique<FakeContentCaptureSender>();
+ child_frame_sender_->Bind(child_frame_);
}
- FakeContentCaptureSender* child_content_capture_sender() {
- return child_content_capture_sender_.get();
+ void BuildChildSession(const ContentCaptureSession& parent,
+ const ContentCaptureFrame& data,
+ ContentCaptureSession* child) {
+ ContentCaptureFrame child_frame = data;
+ child_frame.children.clear();
+ child->clear();
+ child->push_back(child_frame);
+ DCHECK(parent.size() == 1);
+ child->push_back(parent.front());
}
- const ContentCaptureData& test_data() const { return test_data_; }
- const ContentCaptureData& test_data_change() const {
- return test_data_change_;
- }
- const ContentCaptureData& test_data2() const { return test_data2_; }
- const ContentCaptureData& test_data_update() const {
- return test_data_update_;
+ int64_t GetFrameId(bool main_frame) {
+ return ContentCaptureReceiver::GetIdFrom(main_frame ? main_frame_.get()
+ : child_frame_.get());
}
+
const std::vector<int64_t>& expected_removed_ids() const {
return expected_removed_ids_;
}
- ContentCaptureFrame GetExpectedTestData(bool main_frame) const {
- ContentCaptureFrame expected(test_data_);
- // Replaces the id with expected id.
- expected.id = ContentCaptureReceiver::GetIdFrom(
- main_frame ? main_frame_.get() : child_frame_.get());
- return expected;
- }
-
- ContentCaptureFrame GetExpectedTestDataChange(int64_t expected_id) const {
- ContentCaptureFrame expected(test_data_change_);
- // Replaces the id with expected id.
- expected.id = expected_id;
- return expected;
- }
-
- ContentCaptureFrame GetExpectedTestData2(bool main_frame) const {
- ContentCaptureFrame expected(test_data2_);
- // Replaces the id with expected id.
- expected.id = ContentCaptureReceiver::GetIdFrom(
- main_frame ? main_frame_.get() : child_frame_.get());
- return expected;
- }
-
- ContentCaptureFrame GetExpectedTestDataUpdate(bool main_frame) const {
- ContentCaptureFrame expected(test_data_update_);
- // Replaces the id with expected id.
- expected.id = ContentCaptureReceiver::GetIdFrom(
- main_frame ? main_frame_.get() : child_frame_.get());
- return expected;
- }
-
- ContentCaptureConsumerHelper* content_capture_consumer_helper() const {
- return content_capture_consumer_helper_.get();
- }
-
- OnscreenContentProvider* onscreen_content_provider() const {
- return onscreen_content_provider_;
- }
-
SessionRemovedTestHelper* session_removed_test_helper() {
return &session_removed_test_helper_;
}
- void VerifySession(const ContentCaptureSession& expected,
- const ContentCaptureSession& result) const {
- EXPECT_EQ(expected.size(), result.size());
- for (size_t i = 0; i < expected.size(); i++) {
- EXPECT_EQ(expected[i].id, result[i].id);
- EXPECT_EQ(expected[i].url, result[i].url);
- EXPECT_EQ(expected[i].bounds, result[i].bounds);
- EXPECT_TRUE(result[i].children.empty());
- }
- }
-
- void DidCaptureContent(const ContentCaptureData& captured_content,
- bool first_data) {
- base::RunLoop run_loop;
- content_capture_sender()->DidCaptureContent(captured_content, first_data);
- run_loop.RunUntilIdle();
- }
-
- void DidCaptureContentForChildFrame(
- const ContentCaptureData& captured_content,
- bool first_data) {
- base::RunLoop run_loop;
- child_content_capture_sender()->DidCaptureContent(captured_content,
- first_data);
- run_loop.RunUntilIdle();
+ OnscreenContentProvider* provider() const {
+ return helper_.onscreen_content_provider();
}
- void DidUpdateContent(const ContentCaptureData& updated_content) {
- base::RunLoop run_loop;
- content_capture_sender()->DidUpdateContent(updated_content);
- run_loop.RunUntilIdle();
+ ContentCaptureConsumerHelper* consumer() const {
+ return helper_.content_capture_consumer();
}
- void DidRemoveContent(const std::vector<int64_t>& data) {
- base::RunLoop run_loop;
- content_capture_sender()->DidRemoveContent(data);
- run_loop.RunUntilIdle();
+ FakeContentCaptureSender* main_frame_sender() const {
+ return main_frame_sender_.get();
}
-
- void BuildChildSession(const ContentCaptureSession& parent,
- const ContentCaptureFrame& data,
- ContentCaptureSession* child) {
- ContentCaptureFrame child_frame = data;
- child_frame.children.clear();
- child->clear();
- child->push_back(child_frame);
- DCHECK(parent.size() == 1);
- child->push_back(parent.front());
+ FakeContentCaptureSender* child_frame_sender() const {
+ return child_frame_sender_.get();
}
- protected:
- std::unique_ptr<ContentCaptureConsumerHelper>
- content_capture_consumer_helper_;
- raw_ptr<OnscreenContentProvider> onscreen_content_provider_ = nullptr;
+ const ContentCaptureTestHelper* helper() const { return &helper_; }
private:
+ ContentCaptureTestHelper helper_;
+
// The sender for main frame.
- std::unique_ptr<FakeContentCaptureSender> content_capture_sender_;
+ std::unique_ptr<FakeContentCaptureSender> main_frame_sender_;
// The sender for child frame.
- std::unique_ptr<FakeContentCaptureSender> child_content_capture_sender_;
+ std::unique_ptr<FakeContentCaptureSender> child_frame_sender_;
+
raw_ptr<content::RenderFrameHost> main_frame_ = nullptr;
raw_ptr<content::RenderFrameHost> child_frame_ = nullptr;
- ContentCaptureData test_data_;
- ContentCaptureData test_data_change_;
- ContentCaptureData test_data2_;
- ContentCaptureData test_data_update_;
+
// Expected removed Ids.
std::vector<int64_t> expected_removed_ids_{2};
SessionRemovedTestHelper session_removed_test_helper_;
@@ -381,171 +137,186 @@ INSTANTIATE_TEST_SUITE_P(,
testing::Values(true, false));
TEST_P(ContentCaptureReceiverTest, DidCaptureContent) {
- DidCaptureContent(test_data(), true /* first_data */);
- EXPECT_TRUE(content_capture_consumer_helper()->parent_session().empty());
- EXPECT_TRUE(content_capture_consumer_helper()->removed_sessions().empty());
- EXPECT_EQ(GetExpectedTestData(true /* main_frame */),
- content_capture_consumer_helper()->captured_data());
+ main_frame_sender()->DidCaptureContent(helper()->test_data(),
+ true /* first_data */);
+ EXPECT_TRUE(consumer()->parent_session().empty());
+ EXPECT_TRUE(consumer()->removed_sessions().empty());
+ EXPECT_EQ(GetExpectedTestData(helper()->test_data(),
+ GetFrameId(true /* main_frame */)),
+ consumer()->captured_data());
}
TEST_P(ContentCaptureReceiverTest, MultipleConsumers) {
std::unique_ptr<ContentCaptureConsumerHelper> consumer2 =
std::make_unique<ContentCaptureConsumerHelper>(nullptr);
- onscreen_content_provider()->AddConsumer(*(consumer2.get()));
- DidCaptureContent(test_data(), true /* first_data */);
- EXPECT_TRUE(content_capture_consumer_helper()->parent_session().empty());
- EXPECT_TRUE(content_capture_consumer_helper()->removed_sessions().empty());
- EXPECT_EQ(GetExpectedTestData(true /* main_frame */),
- content_capture_consumer_helper()->captured_data());
+ provider()->AddConsumer(*(consumer2.get()));
+ main_frame_sender()->DidCaptureContent(helper()->test_data(),
+ true /* first_data */);
+ EXPECT_TRUE(consumer()->parent_session().empty());
+ EXPECT_TRUE(consumer()->removed_sessions().empty());
+ EXPECT_EQ(GetExpectedTestData(helper()->test_data(),
+ GetFrameId(true /* main_frame */)),
+ consumer()->captured_data());
EXPECT_TRUE(consumer2->parent_session().empty());
EXPECT_TRUE(consumer2->removed_sessions().empty());
- EXPECT_EQ(GetExpectedTestData(true /* main_frame */),
+ EXPECT_EQ(GetExpectedTestData(helper()->test_data(),
+ GetFrameId(true /* main_frame */)),
consumer2->captured_data());
// Verifies to get the remove session callback in RemoveConsumer.
- onscreen_content_provider()->RemoveConsumer(*(consumer2.get()));
- EXPECT_TRUE(content_capture_consumer_helper()->removed_sessions().empty());
+ provider()->RemoveConsumer(*(consumer2.get()));
+ EXPECT_TRUE(consumer()->removed_sessions().empty());
EXPECT_EQ(1u, consumer2->removed_sessions().size());
- std::vector<ContentCaptureFrame> expected{
- GetExpectedTestData(true /* main_frame */)};
+ std::vector<ContentCaptureFrame> expected{GetExpectedTestData(
+ helper()->test_data(), GetFrameId(true /* main_frame */))};
VerifySession(expected, consumer2->removed_sessions().front());
- EXPECT_EQ(1u, onscreen_content_provider()->GetConsumersForTesting().size());
- EXPECT_EQ(content_capture_consumer_helper(),
- onscreen_content_provider()->GetConsumersForTesting()[0]);
+ EXPECT_EQ(1u, provider()->GetConsumersForTesting().size());
+ EXPECT_EQ(consumer(), provider()->GetConsumersForTesting()[0]);
}
// TODO(https://crbug.com/1010179): Fix flakes on win10_chromium_x64_rel_ng and
// re-enable this test.
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#define MAYBE_DidCaptureContentWithUpdate DISABLED_DidCaptureContentWithUpdate
#else
#define MAYBE_DidCaptureContentWithUpdate DidCaptureContentWithUpdate
#endif
TEST_P(ContentCaptureReceiverTest, MAYBE_DidCaptureContentWithUpdate) {
- DidCaptureContent(test_data(), true /* first_data */);
+ main_frame_sender()->DidCaptureContent(helper()->test_data(),
+ true /* first_data */);
// Verifies to get test_data() with correct frame content id.
- EXPECT_TRUE(content_capture_consumer_helper()->parent_session().empty());
- EXPECT_TRUE(content_capture_consumer_helper()->removed_sessions().empty());
- EXPECT_EQ(GetExpectedTestData(true /* main_frame */),
- content_capture_consumer_helper()->captured_data());
+ EXPECT_TRUE(consumer()->parent_session().empty());
+ EXPECT_TRUE(consumer()->removed_sessions().empty());
+ EXPECT_EQ(GetExpectedTestData(helper()->test_data(),
+ GetFrameId(true /* main_frame */)),
+ consumer()->captured_data());
// Simulates to update the content within the same document.
- DidCaptureContent(test_data_update(), false /* first_data */);
+ main_frame_sender()->DidCaptureContent(helper()->test_data_update(),
+ false /* first_data */);
// Verifies to get test_data2() with correct frame content id.
- EXPECT_TRUE(content_capture_consumer_helper()->parent_session().empty());
+ EXPECT_TRUE(consumer()->parent_session().empty());
// Verifies that the session isn't removed.
- EXPECT_TRUE(content_capture_consumer_helper()->removed_sessions().empty());
- EXPECT_EQ(GetExpectedTestDataUpdate(true /* main_frame */),
- content_capture_consumer_helper()->captured_data());
+ EXPECT_TRUE(consumer()->removed_sessions().empty());
+ EXPECT_EQ(GetExpectedTestData(helper()->test_data_update(),
+ GetFrameId(true /* main_frame */)),
+ consumer()->captured_data());
}
// TODO(https://crbug.com/1011204): Fix flakes on win10_chromium_x64_rel_ng and
// re-enable this test.
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#define MAYBE_DidUpdateContent DISABLED_DidUpdateContent
#else
#define MAYBE_DidUpdateContent DidUpdateContent
#endif
TEST_P(ContentCaptureReceiverTest, MAYBE_DidUpdateContent) {
- DidCaptureContent(test_data(), true /* first_data */);
- EXPECT_TRUE(content_capture_consumer_helper()->parent_session().empty());
- EXPECT_TRUE(content_capture_consumer_helper()->removed_sessions().empty());
- ContentCaptureFrame expected_data =
- GetExpectedTestData(true /* main_frame */);
- EXPECT_EQ(expected_data, content_capture_consumer_helper()->captured_data());
+ main_frame_sender()->DidCaptureContent(helper()->test_data(),
+ true /* first_data */);
+ EXPECT_TRUE(consumer()->parent_session().empty());
+ EXPECT_TRUE(consumer()->removed_sessions().empty());
+ ContentCaptureFrame expected_data = GetExpectedTestData(
+ helper()->test_data(), GetFrameId(true /* main_frame */));
+ EXPECT_EQ(expected_data, consumer()->captured_data());
// Simulate content change.
- DidUpdateContent(test_data_change());
- EXPECT_TRUE(
- content_capture_consumer_helper()->updated_parent_session().empty());
- EXPECT_TRUE(content_capture_consumer_helper()->removed_sessions().empty());
- EXPECT_EQ(GetExpectedTestDataChange(expected_data.id),
- content_capture_consumer_helper()->updated_data());
+ main_frame_sender()->DidUpdateContent(helper()->test_data_change());
+ EXPECT_TRUE(consumer()->updated_parent_session().empty());
+ EXPECT_TRUE(consumer()->removed_sessions().empty());
+ EXPECT_EQ(GetExpectedTestData(helper()->test_data_change(), expected_data.id),
+ consumer()->updated_data());
}
TEST_P(ContentCaptureReceiverTest, DidRemoveSession) {
- DidCaptureContent(test_data(), true /* first_data */);
+ main_frame_sender()->DidCaptureContent(helper()->test_data(),
+ true /* first_data */);
// Verifies to get test_data() with correct frame content id.
- EXPECT_TRUE(content_capture_consumer_helper()->parent_session().empty());
- EXPECT_TRUE(content_capture_consumer_helper()->removed_sessions().empty());
- EXPECT_EQ(GetExpectedTestData(true /* main_frame */),
- content_capture_consumer_helper()->captured_data());
+ EXPECT_TRUE(consumer()->parent_session().empty());
+ EXPECT_TRUE(consumer()->removed_sessions().empty());
+ EXPECT_EQ(GetExpectedTestData(helper()->test_data(),
+ GetFrameId(true /* main_frame */)),
+ consumer()->captured_data());
// Simulates to navigate other document.
- DidCaptureContent(test_data2(), true /* first_data */);
- EXPECT_TRUE(content_capture_consumer_helper()->parent_session().empty());
+ main_frame_sender()->DidCaptureContent(helper()->test_data2(),
+ true /* first_data */);
+ EXPECT_TRUE(consumer()->parent_session().empty());
// Verifies that the previous session was removed.
- EXPECT_EQ(1u, content_capture_consumer_helper()->removed_sessions().size());
- std::vector<ContentCaptureFrame> expected{
- GetExpectedTestData(true /* main_frame */)};
- VerifySession(expected,
- content_capture_consumer_helper()->removed_sessions().front());
+ EXPECT_EQ(1u, consumer()->removed_sessions().size());
+ std::vector<ContentCaptureFrame> expected{GetExpectedTestData(
+ helper()->test_data(), GetFrameId(true /* main_frame */))};
+ VerifySession(expected, consumer()->removed_sessions().front());
// Verifies that we get the test_data2() from the new document.
- EXPECT_EQ(GetExpectedTestData2(true /* main_frame */),
- content_capture_consumer_helper()->captured_data());
+ EXPECT_EQ(GetExpectedTestData(helper()->test_data2(),
+ GetFrameId(true /* main_frame */)),
+ consumer()->captured_data());
}
TEST_P(ContentCaptureReceiverTest, DidRemoveContent) {
- DidCaptureContent(test_data(), true /* first_data */);
+ main_frame_sender()->DidCaptureContent(helper()->test_data(),
+ true /* first_data */);
// Verifies to get test_data() with correct frame content id.
- EXPECT_TRUE(content_capture_consumer_helper()->parent_session().empty());
- EXPECT_TRUE(content_capture_consumer_helper()->removed_sessions().empty());
- EXPECT_EQ(GetExpectedTestData(true /* main_frame */),
- content_capture_consumer_helper()->captured_data());
+ EXPECT_TRUE(consumer()->parent_session().empty());
+ EXPECT_TRUE(consumer()->removed_sessions().empty());
+ EXPECT_EQ(GetExpectedTestData(helper()->test_data(),
+ GetFrameId(true /* main_frame */)),
+ consumer()->captured_data());
// Simulates to remove the content.
- DidRemoveContent(expected_removed_ids());
- EXPECT_TRUE(content_capture_consumer_helper()->parent_session().empty());
- EXPECT_TRUE(content_capture_consumer_helper()->removed_sessions().empty());
+ main_frame_sender()->DidRemoveContent(expected_removed_ids());
+ EXPECT_TRUE(consumer()->parent_session().empty());
+ EXPECT_TRUE(consumer()->removed_sessions().empty());
// Verifies that the removed_ids() was removed from the correct session.
- EXPECT_EQ(expected_removed_ids(),
- content_capture_consumer_helper()->removed_ids());
- std::vector<ContentCaptureFrame> expected{
- GetExpectedTestData(true /* main_frame */)};
- VerifySession(expected, content_capture_consumer_helper()->session());
+ EXPECT_EQ(expected_removed_ids(), consumer()->removed_ids());
+ std::vector<ContentCaptureFrame> expected{GetExpectedTestData(
+ helper()->test_data(), GetFrameId(true /* main_frame */))};
+ VerifySession(expected, consumer()->session());
}
TEST_P(ContentCaptureReceiverTest, ChildFrameDidCaptureContent) {
// Simulate add child frame.
SetupChildFrame();
// Simulate to capture the content from main frame.
- DidCaptureContent(test_data(), true /* first_data */);
+ main_frame_sender()->DidCaptureContent(helper()->test_data(),
+ true /* first_data */);
// Verifies to get test_data() with correct frame content id.
- EXPECT_TRUE(content_capture_consumer_helper()->parent_session().empty());
- EXPECT_TRUE(content_capture_consumer_helper()->removed_sessions().empty());
- EXPECT_EQ(GetExpectedTestData(true /* main_frame */),
- content_capture_consumer_helper()->captured_data());
+ EXPECT_TRUE(consumer()->parent_session().empty());
+ EXPECT_TRUE(consumer()->removed_sessions().empty());
+ EXPECT_EQ(GetExpectedTestData(helper()->test_data(),
+ GetFrameId(true /* main_frame */)),
+ consumer()->captured_data());
// Simulate to capture the content from child frame.
- DidCaptureContentForChildFrame(test_data2(), true /* first_data */);
+ child_frame_sender()->DidCaptureContent(helper()->test_data2(),
+ true /* first_data */);
// Verifies that the parent_session was set correctly.
- EXPECT_FALSE(content_capture_consumer_helper()->parent_session().empty());
- std::vector<ContentCaptureFrame> expected{
- GetExpectedTestData(true /* main_frame */)};
- VerifySession(expected, content_capture_consumer_helper()->parent_session());
- EXPECT_TRUE(content_capture_consumer_helper()->removed_sessions().empty());
+ EXPECT_FALSE(consumer()->parent_session().empty());
+ std::vector<ContentCaptureFrame> expected{GetExpectedTestData(
+ helper()->test_data(), GetFrameId(true /* main_frame */))};
+ VerifySession(expected, consumer()->parent_session());
+ EXPECT_TRUE(consumer()->removed_sessions().empty());
// Verifies that we receive the correct content from child frame.
- EXPECT_EQ(GetExpectedTestData2(false /* main_frame */),
- content_capture_consumer_helper()->captured_data());
+ EXPECT_EQ(GetExpectedTestData(helper()->test_data2(),
+ GetFrameId(false /* main_frame */)),
+ consumer()->captured_data());
}
// This test is for issue crbug.com/995121 .
TEST_P(ContentCaptureReceiverTest, RenderFrameHostGone) {
- auto* receiver =
- onscreen_content_provider()->ContentCaptureReceiverForFrameForTesting(
- web_contents()->GetMainFrame());
+ auto* receiver = provider()->ContentCaptureReceiverForFrameForTesting(
+ web_contents()->GetMainFrame());
// No good way to simulate crbug.com/995121, just set rfh_ to nullptr in
// ContentCaptureReceiver, so content::WebContents::FromRenderFrameHost()
// won't return WebContents.
receiver->rfh_ = nullptr;
// Ensure no crash.
- DidCaptureContent(test_data(), true /* first_data */);
- DidUpdateContent(test_data());
- DidRemoveContent(expected_removed_ids());
+ main_frame_sender()->DidCaptureContent(helper()->test_data(),
+ true /* first_data */);
+ main_frame_sender()->DidUpdateContent(helper()->test_data());
+ main_frame_sender()->DidRemoveContent(expected_removed_ids());
}
TEST_P(ContentCaptureReceiverTest, TitleUpdateTaskDelay) {
- auto* receiver =
- onscreen_content_provider()->ContentCaptureReceiverForFrameForTesting(
- web_contents()->GetMainFrame());
+ auto* receiver = provider()->ContentCaptureReceiverForFrameForTesting(
+ web_contents()->GetMainFrame());
auto task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>();
// Uses TestMockTimeTaskRunner to check the task state.
receiver->title_update_task_runner_ = task_runner;
@@ -556,7 +327,8 @@ TEST_P(ContentCaptureReceiverTest, TitleUpdateTaskDelay) {
EXPECT_FALSE(task_runner->HasPendingTask());
// Capture content, then update the title.
- DidCaptureContent(test_data(), /*first_data=*/true);
+ main_frame_sender()->DidCaptureContent(helper()->test_data(),
+ /*first_data=*/true);
std::u16string title2 = u"title 2";
receiver->SetTitle(title2);
// A task should be scheduled.
@@ -567,7 +339,7 @@ TEST_P(ContentCaptureReceiverTest, TitleUpdateTaskDelay) {
task_runner->FastForwardBy(base::Seconds(receiver->exponential_delay_ / 2));
task_runner->RunUntilIdle();
// Verify the title is updated and the task is reset.
- EXPECT_EQ(title2, content_capture_consumer_helper()->updated_title());
+ EXPECT_EQ(title2, consumer()->updated_title());
EXPECT_FALSE(receiver->notify_title_update_callback_);
EXPECT_FALSE(task_runner->HasPendingTask());
@@ -589,12 +361,12 @@ TEST_P(ContentCaptureReceiverTest, TitleUpdateTaskDelay) {
// The delay time is reset after session is removed.
EXPECT_EQ(1u, receiver->exponential_delay_);
// Verify the latest task isn't run.
- EXPECT_EQ(title2, content_capture_consumer_helper()->updated_title());
+ EXPECT_EQ(title2, consumer()->updated_title());
}
// TODO(https://crbug.com/1010416): Fix flakes on win10_chromium_x64_rel_ng and
// re-enable this test.
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#define MAYBE_ChildFrameCaptureContentFirst \
DISABLED_ChildFrameCaptureContentFirst
#else
@@ -604,53 +376,55 @@ TEST_P(ContentCaptureReceiverTest, MAYBE_ChildFrameCaptureContentFirst) {
// Simulate add child frame.
SetupChildFrame();
// Simulate to capture the content from child frame.
- DidCaptureContentForChildFrame(test_data2(), true /* first_data */);
+ child_frame_sender()->DidCaptureContent(helper()->test_data2(),
+ true /* first_data */);
// Verifies that the parent_session was set correctly.
- EXPECT_FALSE(content_capture_consumer_helper()->parent_session().empty());
+ EXPECT_FALSE(consumer()->parent_session().empty());
- ContentCaptureFrame data = GetExpectedTestData(true /* main_frame */);
+ ContentCaptureFrame data = GetExpectedTestData(
+ helper()->test_data(), GetFrameId(true /* main_frame */));
// Currently, there is no way to fake frame size, set it to 0.
data.bounds = gfx::Rect();
ContentCaptureSession expected{data};
- VerifySession(expected, content_capture_consumer_helper()->parent_session());
- EXPECT_TRUE(content_capture_consumer_helper()->removed_sessions().empty());
+ VerifySession(expected, consumer()->parent_session());
+ EXPECT_TRUE(consumer()->removed_sessions().empty());
// Verifies that we receive the correct content from child frame.
- EXPECT_EQ(GetExpectedTestData2(false /* main_frame */),
- content_capture_consumer_helper()->captured_data());
+ EXPECT_EQ(GetExpectedTestData(helper()->test_data2(),
+ GetFrameId(false /* main_frame */)),
+ consumer()->captured_data());
// Get the child session, so we can verify that it has been removed in next
// navigation
- ContentCaptureFrame child_frame = GetExpectedTestData2(false);
+ ContentCaptureFrame child_frame = GetExpectedTestData(
+ helper()->test_data2(), GetFrameId(false /* main_frame */));
// child_frame.children.clear();
ContentCaptureSession removed_child_session;
- BuildChildSession(expected,
- content_capture_consumer_helper()->captured_data(),
+ BuildChildSession(expected, consumer()->captured_data(),
&removed_child_session);
ContentCaptureSession removed_main_session = expected;
// When main frame navigates to same url, the parent session will not change.
NavigateMainFrame(GURL(kMainFrameUrl));
SetupChildFrame();
- DidCaptureContentForChildFrame(test_data2(), true /* first_data */);
- VerifySession(expected, content_capture_consumer_helper()->parent_session());
+ child_frame_sender()->DidCaptureContent(helper()->test_data2(),
+ true /* first_data */);
+ VerifySession(expected, consumer()->parent_session());
- EXPECT_EQ(2u, content_capture_consumer_helper()->removed_sessions().size());
- VerifySession(removed_child_session,
- content_capture_consumer_helper()->removed_sessions().back());
- VerifySession(removed_main_session,
- content_capture_consumer_helper()->removed_sessions().front());
+ EXPECT_EQ(2u, consumer()->removed_sessions().size());
+ VerifySession(removed_child_session, consumer()->removed_sessions().back());
+ VerifySession(removed_main_session, consumer()->removed_sessions().front());
// Get main and child session to verify that they are removed in next
// navigateion.
removed_main_session = expected;
- BuildChildSession(expected,
- content_capture_consumer_helper()->captured_data(),
+ BuildChildSession(expected, consumer()->captured_data(),
&removed_child_session);
// When main frame navigates to same domain, the parent session will change.
NavigateMainFrame(GURL(kMainFrameUrl2));
SetupChildFrame();
- DidCaptureContentForChildFrame(test_data2(), true /* first_data */);
+ child_frame_sender()->DidCaptureContent(helper()->test_data2(),
+ true /* first_data */);
// Intentionally reuse the data.id from previous result, so we know navigating
// to same domain didn't create new ContentCaptureReceiver when call
@@ -659,52 +433,49 @@ TEST_P(ContentCaptureReceiverTest, MAYBE_ChildFrameCaptureContentFirst) {
// or RenderDocument is enabled on same-site main frame navigation, where we
// will get new RenderFrameHosts after the navigation to |kMainFrameUrl2|.
if (content::CanSameSiteMainFrameNavigationsChangeRenderFrameHosts())
- data = GetExpectedTestData(/* main_frame =*/true);
+ data = GetExpectedTestData(helper()->test_data(),
+ GetFrameId(true /* main_frame */));
data.url = kMainFrameUrl2;
// Currently, there is no way to fake frame size, set it to 0.
data.bounds = gfx::Rect();
expected.clear();
expected.push_back(data);
- VerifySession(expected, content_capture_consumer_helper()->parent_session());
+ VerifySession(expected, consumer()->parent_session());
// There are two sessions removed, one the main frame because we navigate to
// different URL (though the domain is same), another one is child frame
// because of the main frame change.
- EXPECT_EQ(2u, content_capture_consumer_helper()->removed_sessions().size());
+ EXPECT_EQ(2u, consumer()->removed_sessions().size());
- VerifySession(removed_child_session,
- content_capture_consumer_helper()->removed_sessions().back());
- VerifySession(removed_main_session,
- content_capture_consumer_helper()->removed_sessions().front());
+ VerifySession(removed_child_session, consumer()->removed_sessions().back());
+ VerifySession(removed_main_session, consumer()->removed_sessions().front());
// Keep current sessions to verify removed sessions later.
removed_main_session = expected;
- BuildChildSession(expected,
- content_capture_consumer_helper()->captured_data(),
+ BuildChildSession(expected, consumer()->captured_data(),
&removed_child_session);
// When main frame navigates to different domain, the parent session will
// change.
NavigateMainFrame(GURL(kChildFrameUrl));
SetupChildFrame();
- DidCaptureContentForChildFrame(test_data2(), true /* first_data */);
+ child_frame_sender()->DidCaptureContent(helper()->test_data2(),
+ true /* first_data */);
- data = GetExpectedTestData2(true /* main_frame */);
+ data = GetExpectedTestData(helper()->test_data2(),
+ GetFrameId(true /* main_frame */));
// Currently, there is no way to fake frame size, set it to 0.
data.bounds = gfx::Rect();
expected.clear();
expected.push_back(data);
- VerifySession(expected, content_capture_consumer_helper()->parent_session());
- EXPECT_EQ(2u, content_capture_consumer_helper()->removed_sessions().size());
- VerifySession(removed_child_session,
- content_capture_consumer_helper()->removed_sessions().back());
- VerifySession(removed_main_session,
- content_capture_consumer_helper()->removed_sessions().front());
+ VerifySession(expected, consumer()->parent_session());
+ EXPECT_EQ(2u, consumer()->removed_sessions().size());
+ VerifySession(removed_child_session, consumer()->removed_sessions().back());
+ VerifySession(removed_main_session, consumer()->removed_sessions().front());
// Keep current sessions to verify removed sessions later.
removed_main_session = expected;
- BuildChildSession(expected,
- content_capture_consumer_helper()->captured_data(),
+ BuildChildSession(expected, consumer()->captured_data(),
&removed_child_session);
session_removed_test_helper()->Reset();
@@ -717,15 +488,17 @@ TEST_P(ContentCaptureReceiverTest, MAYBE_ChildFrameCaptureContentFirst) {
}
TEST_P(ContentCaptureReceiverTest, SameDocumentSameSession) {
- DidCaptureContent(test_data(), true /* first_data */);
+ main_frame_sender()->DidCaptureContent(helper()->test_data(),
+ true /* first_data */);
// Verifies to get test_data() with correct frame content id.
- EXPECT_TRUE(content_capture_consumer_helper()->parent_session().empty());
- EXPECT_TRUE(content_capture_consumer_helper()->removed_sessions().empty());
- EXPECT_EQ(GetExpectedTestData(true /* main_frame */),
- content_capture_consumer_helper()->captured_data());
+ EXPECT_TRUE(consumer()->parent_session().empty());
+ EXPECT_TRUE(consumer()->removed_sessions().empty());
+ EXPECT_EQ(GetExpectedTestData(helper()->test_data(),
+ GetFrameId(true /* main_frame */)),
+ consumer()->captured_data());
NavigateMainFrameSameDocument();
// Verifies the session wasn't removed for the same document navigation.
- EXPECT_TRUE(content_capture_consumer_helper()->removed_sessions().empty());
+ EXPECT_TRUE(consumer()->removed_sessions().empty());
}
TEST_P(ContentCaptureReceiverTest, ConvertFaviconURLToJSON) {
@@ -769,7 +542,7 @@ TEST_P(ContentCaptureReceiverTest, ConvertFaviconURLToJSON) {
}
class ContentCaptureReceiverMultipleFrameTest
- : public ContentCaptureReceiverTest {
+ : public content::RenderViewHostTestHarness {
public:
void SetUp() override {
// Setup multiple frames before creates OnscreenContentProvider.
@@ -779,21 +552,21 @@ class ContentCaptureReceiverMultipleFrameTest
NavigateAndCommit(GURL("about:blank"));
content::RenderFrameHostTester::For(web_contents()->GetMainFrame())
->AppendChild("child");
- onscreen_content_provider_ =
- OnscreenContentProvider::Create(web_contents());
- content_capture_consumer_helper_ =
- std::make_unique<ContentCaptureConsumerHelper>(nullptr);
- onscreen_content_provider_->AddConsumer(
- *(content_capture_consumer_helper_.get()));
+ helper_.CreateProviderAndConsumer(web_contents());
}
- void TearDown() override { content::RenderViewHostTestHarness::TearDown(); }
+ OnscreenContentProvider* provider() const {
+ return helper_.onscreen_content_provider();
+ }
+
+ private:
+ ContentCaptureTestHelper helper_;
};
// TODO(https://crbug.com/1010417): Fix flakes on win10_chromium_x64_rel_ng and
// re-enable this test.
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#define MAYBE_ReceiverCreatedForExistingFrame \
DISABLED_ReceiverCreatedForExistingFrame
#else
@@ -801,7 +574,7 @@ class ContentCaptureReceiverMultipleFrameTest
#endif
TEST_F(ContentCaptureReceiverMultipleFrameTest,
MAYBE_ReceiverCreatedForExistingFrame) {
- EXPECT_EQ(2u, onscreen_content_provider()->GetFrameMapSizeForTesting());
+ EXPECT_EQ(2u, provider()->GetFrameMapSizeForTesting());
}
} // namespace content_capture
diff --git a/chromium/components/content_capture/browser/content_capture_test_helper.cc b/chromium/components/content_capture/browser/content_capture_test_helper.cc
new file mode 100644
index 00000000000..b9ac9665adc
--- /dev/null
+++ b/chromium/components/content_capture/browser/content_capture_test_helper.cc
@@ -0,0 +1,177 @@
+// Copyright 2021 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.
+
+#include "components/content_capture/browser/content_capture_test_helper.h"
+
+#include "base/run_loop.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content_capture {
+
+FakeContentCaptureSender::FakeContentCaptureSender() = default;
+
+FakeContentCaptureSender::~FakeContentCaptureSender() = default;
+
+void FakeContentCaptureSender::Bind(content::RenderFrameHost* frame) {
+ DCHECK(frame);
+ content_capture_receiver_.reset();
+ OnscreenContentProvider::BindContentCaptureReceiver(
+ content_capture_receiver_.BindNewEndpointAndPassDedicatedReceiver(),
+ frame);
+}
+
+void FakeContentCaptureSender::DidCaptureContent(
+ const ContentCaptureData& captured_content,
+ bool first_data) {
+ base::RunLoop run_loop;
+ content_capture_receiver_->DidCaptureContent(captured_content, first_data);
+ run_loop.RunUntilIdle();
+}
+
+void FakeContentCaptureSender::DidUpdateContent(
+ const ContentCaptureData& captured_content) {
+ base::RunLoop run_loop;
+ content_capture_receiver_->DidUpdateContent(captured_content);
+ run_loop.RunUntilIdle();
+}
+
+void FakeContentCaptureSender::DidRemoveContent(
+ const std::vector<int64_t>& data) {
+ base::RunLoop run_loop;
+ content_capture_receiver_->DidRemoveContent(data);
+ run_loop.RunUntilIdle();
+}
+
+SessionRemovedTestHelper::SessionRemovedTestHelper() = default;
+
+SessionRemovedTestHelper::~SessionRemovedTestHelper() = default;
+
+void SessionRemovedTestHelper::DidRemoveSession(
+ const ContentCaptureSession& data) {
+ removed_sessions_.push_back(data);
+}
+
+void SessionRemovedTestHelper::Reset() {
+ removed_sessions_.clear();
+}
+
+ContentCaptureConsumerHelper::ContentCaptureConsumerHelper(
+ SessionRemovedTestHelper* session_removed_test_helper)
+ : session_removed_test_helper_(session_removed_test_helper) {}
+
+ContentCaptureConsumerHelper::~ContentCaptureConsumerHelper() = default;
+
+void ContentCaptureConsumerHelper::DidCaptureContent(
+ const ContentCaptureSession& parent_session,
+ const ContentCaptureFrame& data) {
+ parent_session_ = parent_session;
+ captured_data_ = data;
+}
+
+void ContentCaptureConsumerHelper::DidUpdateContent(
+ const ContentCaptureSession& parent_session,
+ const ContentCaptureFrame& data) {
+ updated_parent_session_ = parent_session;
+ updated_data_ = data;
+}
+
+void ContentCaptureConsumerHelper::DidRemoveContent(
+ const ContentCaptureSession& session,
+ const std::vector<int64_t>& ids) {
+ session_ = session;
+ removed_ids_ = ids;
+}
+
+void ContentCaptureConsumerHelper::DidRemoveSession(
+ const ContentCaptureSession& data) {
+ if (session_removed_test_helper_)
+ session_removed_test_helper_->DidRemoveSession(data);
+ removed_sessions_.push_back(data);
+}
+
+void ContentCaptureConsumerHelper::DidUpdateTitle(
+ const ContentCaptureFrame& main_frame) {
+ updated_title_ = main_frame.title;
+}
+
+void ContentCaptureConsumerHelper::DidUpdateFavicon(
+ const ContentCaptureFrame& main_frame) {}
+
+bool ContentCaptureConsumerHelper::ShouldCapture(const GURL& url) {
+ return false;
+}
+
+void ContentCaptureConsumerHelper::Reset() {
+ removed_sessions_.clear();
+}
+
+ContentCaptureTestHelper::ContentCaptureTestHelper() = default;
+
+ContentCaptureTestHelper::~ContentCaptureTestHelper() = default;
+
+void ContentCaptureTestHelper::CreateProviderAndConsumer(
+ content::WebContents* web_contents,
+ SessionRemovedTestHelper* session_removed_helper) {
+ onscreen_content_provider_ = OnscreenContentProvider::Create(web_contents);
+
+ content_capture_consumer_ =
+ std::make_unique<ContentCaptureConsumerHelper>(session_removed_helper);
+ onscreen_content_provider_->AddConsumer(*(content_capture_consumer_.get()));
+}
+
+void ContentCaptureTestHelper::InitTestData(const std::u16string& data1,
+ const std::u16string& data2) {
+ ContentCaptureData child;
+ // Have the unique id for text content.
+ child.id = 2;
+ child.value = u"Hello";
+ child.bounds = gfx::Rect(5, 5, 5, 5);
+ // No need to set id in sender.
+ test_data_.value = data1;
+ test_data_.bounds = gfx::Rect(10, 10);
+ test_data_.children.push_back(child);
+ test_data2_.value = data2;
+ test_data2_.bounds = gfx::Rect(10, 10);
+ test_data2_.children.push_back(child);
+
+ ContentCaptureData child_change;
+ // Same ID with child.
+ child_change.id = 2;
+ child_change.value = u"Hello World";
+ child_change.bounds = gfx::Rect(5, 5, 5, 5);
+ test_data_change_.value = data1;
+ test_data_change_.bounds = gfx::Rect(10, 10);
+ test_data_change_.children.push_back(child_change);
+
+ // Update to test_data_.
+ ContentCaptureData child2;
+ // Have the unique id for text content.
+ child2.id = 3;
+ child2.value = u"World";
+ child2.bounds = gfx::Rect(5, 10, 5, 5);
+ test_data_update_.value = data1;
+ test_data_update_.bounds = gfx::Rect(10, 10);
+ test_data_update_.children.push_back(child2);
+}
+
+void VerifySession(const ContentCaptureSession& expected,
+ const ContentCaptureSession& result) {
+ EXPECT_EQ(expected.size(), result.size());
+ for (size_t i = 0; i < expected.size(); i++) {
+ EXPECT_EQ(expected[i].id, result[i].id);
+ EXPECT_EQ(expected[i].url, result[i].url);
+ EXPECT_EQ(expected[i].bounds, result[i].bounds);
+ EXPECT_TRUE(result[i].children.empty());
+ }
+}
+
+ContentCaptureFrame GetExpectedTestData(const ContentCaptureData& data,
+ int64_t expected_id) {
+ ContentCaptureFrame expected(data);
+ // Replaces the id with expected id.
+ expected.id = expected_id;
+ return expected;
+}
+
+} // namespace content_capture
diff --git a/chromium/components/content_capture/browser/content_capture_test_helper.h b/chromium/components/content_capture/browser/content_capture_test_helper.h
new file mode 100644
index 00000000000..f4be3738a1a
--- /dev/null
+++ b/chromium/components/content_capture/browser/content_capture_test_helper.h
@@ -0,0 +1,161 @@
+// Copyright 2021 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.
+
+#ifndef COMPONENTS_CONTENT_CAPTURE_BROWSER_CONTENT_CAPTURE_TEST_HELPER_H_
+#define COMPONENTS_CONTENT_CAPTURE_BROWSER_CONTENT_CAPTURE_TEST_HELPER_H_
+
+#include "components/content_capture/browser/content_capture_consumer.h"
+#include "components/content_capture/browser/content_capture_receiver.h"
+#include "components/content_capture/browser/onscreen_content_provider.h"
+
+namespace content_capture {
+
+// Fake ContentCaptureSender to call ContentCaptureReceiver mojom interface.
+class FakeContentCaptureSender {
+ public:
+ FakeContentCaptureSender();
+ virtual ~FakeContentCaptureSender();
+
+ void Bind(content::RenderFrameHost* frame);
+
+ void DidCaptureContent(const ContentCaptureData& captured_content,
+ bool first_data);
+
+ void DidUpdateContent(const ContentCaptureData& captured_content);
+
+ void DidRemoveContent(const std::vector<int64_t>& data);
+
+ private:
+ mojo::AssociatedRemote<mojom::ContentCaptureReceiver>
+ content_capture_receiver_;
+};
+
+class SessionRemovedTestHelper {
+ public:
+ SessionRemovedTestHelper();
+ virtual ~SessionRemovedTestHelper();
+
+ void DidRemoveSession(const ContentCaptureSession& data);
+
+ const std::vector<ContentCaptureSession>& removed_sessions() const {
+ return removed_sessions_;
+ }
+
+ void Reset();
+
+ private:
+ std::vector<ContentCaptureSession> removed_sessions_;
+};
+
+// The helper class implements ContentCaptureConsumer and keeps the
+// result for verification.
+class ContentCaptureConsumerHelper : public ContentCaptureConsumer {
+ public:
+ explicit ContentCaptureConsumerHelper(
+ SessionRemovedTestHelper* session_removed_test_helper);
+
+ ~ContentCaptureConsumerHelper() override;
+
+ // ContentCaptureConsumer
+ void DidCaptureContent(const ContentCaptureSession& parent_session,
+ const ContentCaptureFrame& data) override;
+
+ void DidUpdateContent(const ContentCaptureSession& parent_session,
+ const ContentCaptureFrame& data) override;
+
+ void DidRemoveContent(const ContentCaptureSession& session,
+ const std::vector<int64_t>& ids) override;
+
+ void DidRemoveSession(const ContentCaptureSession& data) override;
+
+ void DidUpdateTitle(const ContentCaptureFrame& main_frame) override;
+
+ void DidUpdateFavicon(const ContentCaptureFrame& main_frame) override;
+
+ bool ShouldCapture(const GURL& url) override;
+
+ const ContentCaptureSession& parent_session() const {
+ return parent_session_;
+ }
+
+ const ContentCaptureSession& updated_parent_session() const {
+ return updated_parent_session_;
+ }
+
+ const ContentCaptureSession& session() const { return session_; }
+
+ const ContentCaptureFrame& captured_data() const { return captured_data_; }
+
+ const ContentCaptureFrame& updated_data() const { return updated_data_; }
+
+ const std::vector<ContentCaptureSession>& removed_sessions() const {
+ return removed_sessions_;
+ }
+
+ const std::vector<int64_t>& removed_ids() const { return removed_ids_; }
+ const std::u16string& updated_title() const { return updated_title_; }
+
+ void Reset();
+
+ private:
+ ContentCaptureSession parent_session_;
+ ContentCaptureSession updated_parent_session_;
+ ContentCaptureSession session_;
+ ContentCaptureFrame captured_data_;
+ ContentCaptureFrame updated_data_;
+ std::vector<int64_t> removed_ids_;
+ std::vector<ContentCaptureSession> removed_sessions_;
+ raw_ptr<SessionRemovedTestHelper> session_removed_test_helper_;
+ std::u16string updated_title_;
+};
+
+class ContentCaptureTestHelper {
+ public:
+ ContentCaptureTestHelper();
+ ContentCaptureTestHelper(const ContentCaptureTestHelper&) = delete;
+ ContentCaptureTestHelper& operator=(const ContentCaptureTestHelper&) = delete;
+ virtual ~ContentCaptureTestHelper();
+
+ void CreateProviderAndConsumer(
+ content::WebContents* web_contents,
+ SessionRemovedTestHelper* session_removed_helper = nullptr);
+
+ void InitTestData(const std::u16string& data1, const std::u16string& data2);
+
+ OnscreenContentProvider* onscreen_content_provider() const {
+ return onscreen_content_provider_;
+ }
+
+ ContentCaptureConsumerHelper* content_capture_consumer() const {
+ return content_capture_consumer_.get();
+ }
+
+ const ContentCaptureData& test_data() const { return test_data_; }
+ const ContentCaptureData& test_data2() const { return test_data2_; }
+ const ContentCaptureData& test_data_change() const {
+ return test_data_change_;
+ }
+ const ContentCaptureData& test_data_update() const {
+ return test_data_update_;
+ }
+
+ private:
+ raw_ptr<OnscreenContentProvider> onscreen_content_provider_ = nullptr;
+ std::unique_ptr<ContentCaptureConsumerHelper> content_capture_consumer_;
+
+ ContentCaptureData test_data_;
+ ContentCaptureData test_data2_;
+ ContentCaptureData test_data_change_;
+ ContentCaptureData test_data_update_;
+};
+
+void VerifySession(const ContentCaptureSession& expected,
+ const ContentCaptureSession& result);
+
+ContentCaptureFrame GetExpectedTestData(const ContentCaptureData& data,
+ int64_t expected_id);
+
+} // namespace content_capture
+
+#endif // COMPONENTS_CONTENT_CAPTURE_BROWSER_CONTENT_CAPTURE_TEST_HELPER_H_
diff --git a/chromium/components/content_capture/browser/onscreen_content_provider.cc b/chromium/components/content_capture/browser/onscreen_content_provider.cc
index 9f85d5a4fca..188bb941bf0 100644
--- a/chromium/components/content_capture/browser/onscreen_content_provider.cc
+++ b/chromium/components/content_capture/browser/onscreen_content_provider.cc
@@ -256,7 +256,8 @@ void OnscreenContentProvider::BuildContentCaptureSession(
if (!ancestor_only)
session->push_back(content_capture_receiver->GetContentCaptureFrame());
- content::RenderFrameHost* rfh = content_capture_receiver->rfh()->GetParent();
+ content::RenderFrameHost* rfh =
+ content_capture_receiver->rfh()->GetParentOrOuterDocument();
while (rfh) {
ContentCaptureReceiver* receiver = ContentCaptureReceiverForFrame(rfh);
// TODO(michaelbai): Only creates ContentCaptureReceiver here, clean up the
@@ -267,7 +268,7 @@ void OnscreenContentProvider::BuildContentCaptureSession(
DCHECK(receiver);
}
session->push_back(receiver->GetContentCaptureFrame());
- rfh = receiver->rfh()->GetParent();
+ rfh = receiver->rfh()->GetParentOrOuterDocument();
}
}
@@ -276,13 +277,14 @@ bool OnscreenContentProvider::BuildContentCaptureSessionLastSeen(
ContentCaptureSession* session) {
session->push_back(
content_capture_receiver->GetContentCaptureFrameLastSeen());
- content::RenderFrameHost* rfh = content_capture_receiver->rfh()->GetParent();
+ content::RenderFrameHost* rfh =
+ content_capture_receiver->rfh()->GetParentOrOuterDocument();
while (rfh) {
ContentCaptureReceiver* receiver = ContentCaptureReceiverForFrame(rfh);
if (!receiver)
return false;
session->push_back(receiver->GetContentCaptureFrameLastSeen());
- rfh = receiver->rfh()->GetParent();
+ rfh = receiver->rfh()->GetParentOrOuterDocument();
}
return true;
}
diff --git a/chromium/components/content_capture/common/content_capture_features.cc b/chromium/components/content_capture/common/content_capture_features.cc
index 9a722d523dc..5f5d4de72f1 100644
--- a/chromium/components/content_capture/common/content_capture_features.cc
+++ b/chromium/components/content_capture/common/content_capture_features.cc
@@ -11,7 +11,7 @@
namespace content_capture {
namespace features {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
const base::Feature kContentCapture{"ContentCapture",
base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/chromium/components/content_creation/notes/core/note_features.h b/chromium/components/content_creation/notes/core/note_features.h
index 6d8412a599a..ad4df1a4b46 100644
--- a/chromium/components/content_creation/notes/core/note_features.h
+++ b/chromium/components/content_creation/notes/core/note_features.h
@@ -6,6 +6,7 @@
#define COMPONENTS_CONTENT_CREATION_NOTES_CORE_NOTE_FEATURES_H_
#include "base/feature_list.h"
+#include "base/metrics/field_trial_params.h"
namespace content_creation {
diff --git a/chromium/components/content_creation/notes/core/note_prefs.cc b/chromium/components/content_creation/notes/core/note_prefs.cc
index a9e851c8071..bec4138f04b 100644
--- a/chromium/components/content_creation/notes/core/note_prefs.cc
+++ b/chromium/components/content_creation/notes/core/note_prefs.cc
@@ -47,7 +47,7 @@ absl::optional<std::vector<NoteTemplateIds>> TryGetRandomOrder(
}
std::vector<NoteTemplateIds> template_ids;
- for (const base::Value& current_value : stored_value->GetList()) {
+ for (const base::Value& current_value : stored_value->GetListDeprecated()) {
absl::optional<int> maybe_int = current_value.GetIfInt();
if (!maybe_int) {
continue;
diff --git a/chromium/components/content_settings/browser/page_specific_content_settings.cc b/chromium/components/content_settings/browser/page_specific_content_settings.cc
index c2551967709..7edb148d0e7 100644
--- a/chromium/components/content_settings/browser/page_specific_content_settings.cc
+++ b/chromium/components/content_settings/browser/page_specific_content_settings.cc
@@ -117,11 +117,10 @@ PageSpecificContentSettings::WebContentsHandler::WebContentsHandler(
content::WebContentsUserData<WebContentsHandler>(*web_contents),
delegate_(std::move(delegate)),
map_(delegate_->GetSettingsMap()) {
- DCHECK(!PageSpecificContentSettings::GetForCurrentDocument(
- web_contents->GetMainFrame()));
- content::DocumentUserData<PageSpecificContentSettings>::
- CreateForCurrentDocument(web_contents->GetMainFrame(), *this,
- delegate_.get());
+ DCHECK(
+ !PageSpecificContentSettings::GetForPage(web_contents->GetPrimaryPage()));
+ content::PageUserData<PageSpecificContentSettings>::CreateForPage(
+ web_contents->GetPrimaryPage(), *this, delegate_.get());
}
PageSpecificContentSettings::WebContentsHandler::~WebContentsHandler() {
@@ -163,8 +162,7 @@ void PageSpecificContentSettings::WebContentsHandler::OnCookiesAccessed(
void PageSpecificContentSettings::WebContentsHandler::OnCookiesAccessed(
content::RenderFrameHost* rfh,
const content::CookieAccessDetails& details) {
- auto* pscs =
- PageSpecificContentSettings::GetForCurrentDocument(rfh->GetMainFrame());
+ auto* pscs = PageSpecificContentSettings::GetForPage(rfh->GetPage());
if (pscs)
pscs->OnCookiesAccessed(details);
}
@@ -195,8 +193,7 @@ void PageSpecificContentSettings::WebContentsHandler::OnServiceWorkerAccessed(
content::RenderFrameHost* frame,
const GURL& scope,
content::AllowServiceWorkerResult allowed) {
- auto* pscs =
- PageSpecificContentSettings::GetForCurrentDocument(frame->GetMainFrame());
+ auto* pscs = PageSpecificContentSettings::GetForPage(frame->GetPage());
if (pscs)
pscs->OnServiceWorkerAccessed(scope, allowed);
}
@@ -222,9 +219,9 @@ void PageSpecificContentSettings::WebContentsHandler::DidFinishNavigation(
if (WillNavigationCreateNewPageSpecificContentSettingsOnCommit(
navigation_handle)) {
- content::DocumentUserData<PageSpecificContentSettings>::
- CreateForCurrentDocument(navigation_handle->GetRenderFrameHost(), *this,
- delegate_.get());
+ content::PageUserData<PageSpecificContentSettings>::CreateForPage(
+ navigation_handle->GetRenderFrameHost()->GetPage(), *this,
+ delegate_.get());
InflightNavigationContentSettings* inflight_settings =
content::NavigationHandleUserData<InflightNavigationContentSettings>::
GetForNavigationHandle(*navigation_handle);
@@ -279,10 +276,10 @@ PageSpecificContentSettings::PendingUpdates::PendingUpdates() = default;
PageSpecificContentSettings::PendingUpdates::~PendingUpdates() = default;
PageSpecificContentSettings::PageSpecificContentSettings(
- content::RenderFrameHost* main_frame,
+ content::Page& page,
PageSpecificContentSettings::WebContentsHandler& handler,
Delegate* delegate)
- : content::DocumentUserData<PageSpecificContentSettings>(main_frame),
+ : content::PageUserData<PageSpecificContentSettings>(page),
handler_(handler),
delegate_(delegate),
map_(delegate_->GetSettingsMap()),
@@ -297,9 +294,8 @@ PageSpecificContentSettings::PageSpecificContentSettings(
delegate_->GetAdditionalFileSystemTypes(),
delegate_->GetIsDeletionDisabledCallback()),
microphone_camera_state_(MICROPHONE_CAMERA_NOT_ACCESSED) {
- DCHECK(!render_frame_host().GetParent());
observation_.Observe(map_.get());
- if (render_frame_host().GetLifecycleState() ==
+ if (page.GetMainDocument().GetLifecycleState() ==
content::RenderFrameHost::LifecycleState::kPrerendering) {
updates_queued_during_prerender_ = std::make_unique<PendingUpdates>();
}
@@ -318,10 +314,7 @@ void PageSpecificContentSettings::CreateForWebContents(
// static
void PageSpecificContentSettings::DeleteForWebContentsForTest(
content::WebContents* web_contents) {
- if (web_contents->GetMainFrame()) {
- PageSpecificContentSettings::DeleteForCurrentDocument(
- web_contents->GetMainFrame());
- }
+ PageSpecificContentSettings::DeleteForPage(web_contents->GetPrimaryPage());
web_contents->RemoveUserData(
PageSpecificContentSettings::WebContentsHandler::UserDataKey());
@@ -340,8 +333,7 @@ PageSpecificContentSettings* PageSpecificContentSettings::GetForFrame(
PageSpecificContentSettings* PageSpecificContentSettings::GetForFrame(
content::RenderFrameHost* rfh) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- return rfh ? PageSpecificContentSettings::GetForCurrentDocument(
- rfh->GetMainFrame())
+ return rfh ? PageSpecificContentSettings::GetForPage(rfh->GetPage())
: nullptr;
}
@@ -420,6 +412,17 @@ void PageSpecificContentSettings::SharedWorkerAccessed(
}
// static
+void PageSpecificContentSettings::InterestGroupJoined(
+ content::RenderFrameHost* rfh,
+ const url::Origin api_origin,
+ bool blocked_by_policy) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ PageSpecificContentSettings* settings = GetForFrame(rfh);
+ if (settings)
+ settings->OnInterestGroupJoined(api_origin, blocked_by_policy);
+}
+
+// static
content::WebContentsObserver*
PageSpecificContentSettings::GetWebContentsObserverForTest(
content::WebContents* web_contents) {
@@ -515,7 +518,7 @@ void PageSpecificContentSettings::OnContentAllowed(ContentSettingsType type) {
if (type == ContentSettingsType::SENSORS)
must_reset_blocked_status = true;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// content_settings_status_[type].allowed is always set to true in
// OnContentBlocked, so we have to use
// content_settings_status_[type].blocked to detect whether the protected
@@ -660,6 +663,19 @@ void PageSpecificContentSettings::OnSharedWorkerAccessed(
}
}
+void PageSpecificContentSettings::OnInterestGroupJoined(
+ const url::Origin api_origin,
+ bool blocked_by_policy) {
+ if (blocked_by_policy) {
+ blocked_interest_group_api_.push_back(api_origin);
+ OnContentBlocked(ContentSettingsType::COOKIES);
+ } else {
+ allowed_interest_group_api_.push_back(api_origin);
+ OnContentAllowed(ContentSettingsType::COOKIES);
+ }
+ NotifySiteDataObservers();
+}
+
void PageSpecificContentSettings::OnWebDatabaseAccessed(
const GURL& url,
bool blocked_by_policy) {
@@ -694,7 +710,7 @@ void PageSpecificContentSettings::OnFileSystemAccessed(const GURL& url,
NotifySiteDataObservers();
}
-#if defined(OS_ANDROID) || defined(OS_CHROMEOS) || defined(OS_WIN)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN)
void PageSpecificContentSettings::OnProtectedMediaIdentifierPermissionSet(
const GURL& requesting_origin,
bool allowed) {
@@ -795,7 +811,7 @@ void PageSpecificContentSettings::OnContentSettingChanged(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type) {
- const GURL current_url = render_frame_host().GetLastCommittedURL();
+ const GURL current_url = page().GetMainDocument().GetLastCommittedURL();
if (!primary_pattern.Matches(current_url)) {
return;
}
@@ -827,7 +843,7 @@ void PageSpecificContentSettings::OnContentSettingChanged(
map_->GetContentSetting(current_url, current_url, content_type);
if (geolocation_setting == CONTENT_SETTING_ALLOW)
geolocation_was_just_granted_on_site_level_ = true;
- FALLTHROUGH;
+ [[fallthrough]];
}
case ContentSettingsType::IMAGES:
case ContentSettingsType::JAVASCRIPT:
@@ -862,7 +878,8 @@ void PageSpecificContentSettings::OnContentSettingChanged(
if (!ShouldSendUpdatedContentSettingsRulesToRenderer(content_type))
return;
- MaybeSendRendererContentSettingsRules(&render_frame_host(), map_, delegate_);
+ MaybeSendRendererContentSettingsRules(&page().GetMainDocument(), map_,
+ delegate_);
}
void PageSpecificContentSettings::ClearContentSettingsChangedViaPageInfo() {
@@ -888,7 +905,7 @@ void PageSpecificContentSettings::BlockAllContentForTesting() {
PageSpecificContentSettings::MICROPHONE_BLOCKED |
PageSpecificContentSettings::CAMERA_ACCESSED |
PageSpecificContentSettings::CAMERA_BLOCKED);
- OnMediaStreamPermissionSet(render_frame_host().GetLastCommittedURL(),
+ OnMediaStreamPermissionSet(page().GetMainDocument().GetLastCommittedURL(),
media_blocked, std::string(), std::string(),
std::string(), std::string());
}
@@ -904,6 +921,10 @@ bool PageSpecificContentSettings::HasContentSettingChangedViaPageInfo(
content_settings_changed_via_page_info_.end();
}
+bool PageSpecificContentSettings::HasJoinedUserToInterestGroup() const {
+ return !allowed_interest_group_api_.empty();
+}
+
bool PageSpecificContentSettings::IsPagePrerendering() const {
// We consider the Page to be prerendering iff
// |updates_queued_during_prerender_| is non null. Note, the page already may
@@ -942,6 +963,6 @@ void PageSpecificContentSettings::MaybeUpdateLocationBar() {
delegate_->UpdateLocationBar();
}
-DOCUMENT_USER_DATA_KEY_IMPL(PageSpecificContentSettings);
+PAGE_USER_DATA_KEY_IMPL(PageSpecificContentSettings);
} // namespace content_settings
diff --git a/chromium/components/content_settings/browser/page_specific_content_settings.h b/chromium/components/content_settings/browser/page_specific_content_settings.h
index 69f7e7e404a..d032ddd3d27 100644
--- a/chromium/components/content_settings/browser/page_specific_content_settings.h
+++ b/chromium/components/content_settings/browser/page_specific_content_settings.h
@@ -26,8 +26,8 @@
#include "components/content_settings/core/common/content_settings.h"
#include "components/content_settings/core/common/content_settings_types.h"
#include "content/public/browser/allow_service_worker_result.h"
-#include "content/public/browser/document_user_data.h"
#include "content/public/browser/navigation_handle_user_data.h"
+#include "content/public/browser/page_user_data.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_contents_user_data.h"
@@ -71,7 +71,7 @@ namespace content_settings {
// loaded page once the navigation commits or discarded if it does not.
class PageSpecificContentSettings
: public content_settings::Observer,
- public content::DocumentUserData<PageSpecificContentSettings> {
+ public content::PageUserData<PageSpecificContentSettings> {
public:
// Fields describing the current mic/camera state. If a page has attempted to
// access a device, the XXX_ACCESSED bit will be set. If access was blocked,
@@ -262,6 +262,12 @@ class PageSpecificContentSettings
const blink::StorageKey& storage_key,
bool blocked_by_policy);
+ // Called when |api_origin| attempts to join an interest group via the
+ // Interest Group API.
+ static void InterestGroupJoined(content::RenderFrameHost* rfh,
+ const url::Origin api_origin,
+ bool blocked_by_policy);
+
static content::WebContentsObserver* GetWebContentsObserverForTest(
content::WebContents* web_contents);
@@ -364,8 +370,10 @@ class PageSpecificContentSettings
const std::string& name,
const blink::StorageKey& storage_key,
bool blocked_by_policy);
+ void OnInterestGroupJoined(const url::Origin api_origin,
+ bool blocked_by_policy);
void OnWebDatabaseAccessed(const GURL& url, bool blocked_by_policy);
-#if defined(OS_ANDROID) || defined(OS_CHROMEOS) || defined(OS_WIN)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN)
void OnProtectedMediaIdentifierPermissionSet(const GURL& requesting_frame,
bool allowed);
#endif
@@ -394,8 +402,12 @@ class PageSpecificContentSettings
// since the last navigation.
bool HasContentSettingChangedViaPageInfo(ContentSettingsType type) const;
+ // Returns true if the user was joined to an interest group and if the page
+ // is the joining origin.
+ bool HasJoinedUserToInterestGroup() const;
+
private:
- friend class content::DocumentUserData<PageSpecificContentSettings>;
+ friend class content::PageUserData<PageSpecificContentSettings>;
// Keeps track of cookie and service worker access during a navigation.
// These types of access can happen for the current page or for a new
@@ -498,7 +510,7 @@ class PageSpecificContentSettings
};
explicit PageSpecificContentSettings(
- content::RenderFrameHost* rfh,
+ content::Page& page,
PageSpecificContentSettings::WebContentsHandler& handler,
Delegate* delegate);
@@ -568,6 +580,11 @@ class PageSpecificContentSettings
std::string media_stream_requested_audio_device_;
std::string media_stream_requested_video_device_;
+ // Contains URLs which attempted to join interest groups. Note: The UI will
+ // only currently show the top frame as having attempted to join.
+ std::vector<url::Origin> allowed_interest_group_api_;
+ std::vector<url::Origin> blocked_interest_group_api_;
+
// The Geolocation, camera, and/or microphone permission was granted to this
// origin from a permission prompt that was triggered by the currently active
// document.
@@ -587,7 +604,7 @@ class PageSpecificContentSettings
// the page is prerendering. These calls are run when the page is activated.
std::unique_ptr<PendingUpdates> updates_queued_during_prerender_;
- DOCUMENT_USER_DATA_KEY_DECL();
+ PAGE_USER_DATA_KEY_DECL();
base::WeakPtrFactory<PageSpecificContentSettings> weak_factory_{this};
};
diff --git a/chromium/components/content_settings/browser/page_specific_content_settings_unittest.cc b/chromium/components/content_settings/browser/page_specific_content_settings_unittest.cc
index b4033561da8..cfa4ed58912 100644
--- a/chromium/components/content_settings/browser/page_specific_content_settings_unittest.cc
+++ b/chromium/components/content_settings/browser/page_specific_content_settings_unittest.cc
@@ -105,7 +105,7 @@ TEST_F(PageSpecificContentSettingsTest, BlockedContent) {
PageSpecificContentSettings::GetForFrame(web_contents()->GetMainFrame());
// Check that after initializing, nothing is blocked.
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
EXPECT_FALSE(content_settings->IsContentBlocked(ContentSettingsType::IMAGES));
#endif
EXPECT_FALSE(
@@ -134,7 +134,7 @@ TEST_F(PageSpecificContentSettingsTest, BlockedContent) {
false});
content_settings =
PageSpecificContentSettings::GetForFrame(web_contents()->GetMainFrame());
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
content_settings->OnContentBlocked(ContentSettingsType::IMAGES);
#endif
content_settings->OnContentBlocked(ContentSettingsType::POPUPS);
@@ -149,7 +149,7 @@ TEST_F(PageSpecificContentSettingsTest, BlockedContent) {
std::string(), std::string(), std::string());
// Check that only the respective content types are affected.
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
EXPECT_TRUE(content_settings->IsContentBlocked(ContentSettingsType::IMAGES));
#endif
EXPECT_FALSE(
@@ -211,7 +211,7 @@ TEST_F(PageSpecificContentSettingsTest, BlockedContent) {
NavigateAndCommit(GURL("http://google.com"));
content_settings =
PageSpecificContentSettings::GetForFrame(web_contents()->GetMainFrame());
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
EXPECT_FALSE(content_settings->IsContentBlocked(ContentSettingsType::IMAGES));
#endif
EXPECT_FALSE(
@@ -466,10 +466,9 @@ TEST_F(PageSpecificContentSettingsTest,
ContentSettingsPattern pattern =
ContentSettingsPattern::FromURL(web_contents()->GetVisibleURL());
- map->SetWebsiteSettingCustomScope(
- pattern, ContentSettingsPattern::Wildcard(),
- ContentSettingsType::CLIPBOARD_READ_WRITE,
- std::make_unique<base::Value>(CONTENT_SETTING_ALLOW));
+ map->SetWebsiteSettingCustomScope(pattern, ContentSettingsPattern::Wildcard(),
+ ContentSettingsType::CLIPBOARD_READ_WRITE,
+ base::Value(CONTENT_SETTING_ALLOW));
// Now the indicator is set to allowed.
EXPECT_TRUE(content_settings->IsContentAllowed(
@@ -478,10 +477,9 @@ TEST_F(PageSpecificContentSettingsTest,
ContentSettingsType::CLIPBOARD_READ_WRITE));
// Simulate the user modifying the setting back to blocked.
- map->SetWebsiteSettingCustomScope(
- pattern, ContentSettingsPattern::Wildcard(),
- ContentSettingsType::CLIPBOARD_READ_WRITE,
- std::make_unique<base::Value>(CONTENT_SETTING_BLOCK));
+ map->SetWebsiteSettingCustomScope(pattern, ContentSettingsPattern::Wildcard(),
+ ContentSettingsType::CLIPBOARD_READ_WRITE,
+ base::Value(CONTENT_SETTING_BLOCK));
// Now the indicator is set to allowed.
EXPECT_TRUE(content_settings->IsContentBlocked(
diff --git a/chromium/components/content_settings/browser/ui/cookie_controls_controller.cc b/chromium/components/content_settings/browser/ui/cookie_controls_controller.cc
index fdbc3aa2fc5..87e31d5f68b 100644
--- a/chromium/components/content_settings/browser/ui/cookie_controls_controller.cc
+++ b/chromium/components/content_settings/browser/ui/cookie_controls_controller.cc
@@ -117,9 +117,8 @@ bool CookieControlsController::FirstPartyCookiesBlocked() {
}
int CookieControlsController::GetAllowedCookieCount() {
- auto* pscs =
- content_settings::PageSpecificContentSettings::GetForCurrentDocument(
- tab_observer_->web_contents()->GetMainFrame());
+ auto* pscs = content_settings::PageSpecificContentSettings::GetForPage(
+ tab_observer_->web_contents()->GetPrimaryPage());
if (pscs) {
return pscs->allowed_local_shared_objects().GetObjectCount();
} else {
@@ -127,9 +126,8 @@ int CookieControlsController::GetAllowedCookieCount() {
}
}
int CookieControlsController::GetBlockedCookieCount() {
- auto* pscs =
- content_settings::PageSpecificContentSettings::GetForCurrentDocument(
- tab_observer_->web_contents()->GetMainFrame());
+ auto* pscs = content_settings::PageSpecificContentSettings::GetForPage(
+ tab_observer_->web_contents()->GetPrimaryPage());
if (pscs) {
return pscs->blocked_local_shared_objects().GetObjectCount();
} else {
diff --git a/chromium/components/content_settings/core/browser/BUILD.gn b/chromium/components/content_settings/core/browser/BUILD.gn
index dbb8fbafd1e..592cb548ecd 100644
--- a/chromium/components/content_settings/core/browser/BUILD.gn
+++ b/chromium/components/content_settings/core/browser/BUILD.gn
@@ -38,8 +38,6 @@ static_library("browser") {
"host_content_settings_map.h",
"private_network_settings.cc",
"private_network_settings.h",
- "uma_util.cc",
- "uma_util.h",
"user_modifiable_provider.h",
"website_settings_info.cc",
"website_settings_info.h",
@@ -110,7 +108,6 @@ source_set("unit_tests") {
"//components/pref_registry:pref_registry",
"//components/prefs",
"//components/prefs:test_support",
- "//components/privacy_sandbox:privacy_sandbox_prefs",
"//components/sync_preferences:test_support",
"//extensions/buildflags",
"//net",
@@ -126,6 +123,7 @@ source_set("unit_tests") {
deps += [
"//components/policy:generated",
"//components/policy/core/browser:test_support",
+ "//components/privacy_sandbox:privacy_sandbox_prefs",
"//third_party/blink/public/common:headers",
]
}
diff --git a/chromium/components/content_settings/core/browser/content_settings_default_provider.cc b/chromium/components/content_settings/core/browser/content_settings_default_provider.cc
index 8169e361cd7..3935fe80b14 100644
--- a/chromium/components/content_settings/core/browser/content_settings_default_provider.cc
+++ b/chromium/components/content_settings/core/browser/content_settings_default_provider.cc
@@ -34,10 +34,14 @@ namespace content_settings {
namespace {
// These settings are no longer used, and should be deleted on profile startup.
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
const char kObsoleteFullscreenDefaultPref[] =
"profile.default_content_setting_values.fullscreen";
-#if !defined(OS_ANDROID)
+// The "nfc" preference was superseded by "nfc-devices" once Web NFC gained the
+// ability to make NFC tags permanently read-only. See crbug.com/1275576
+const char kObsoleteNfcDefaultPref[] =
+ "profile.default_content_setting_values.nfc";
+#if !BUILDFLAG(IS_ANDROID)
const char kObsoleteMouseLockDefaultPref[] =
"profile.default_content_setting_values.mouselock";
const char kObsoletePluginsDefaultPref[] =
@@ -46,19 +50,19 @@ const char kObsoletePluginsDataDefaultPref[] =
"profile.default_content_setting_values.flash_data";
const char kObsoleteFileHandlingDefaultPref[] =
"profile.default_content_setting_values.file_handling";
-#endif // !defined(OS_ANDROID)
-#endif // !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_ANDROID)
+#endif // !BUILDFLAG(IS_IOS)
-#if BUILDFLAG(IS_CHROMEOS_ASH) || defined(OS_WIN)
+#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_WIN)
// This setting was moved and should be migrated on profile startup.
const char kDeprecatedEnableDRM[] = "settings.privacy.drm_enabled";
-#endif // BUILDFLAG(IS_CHROMEOS_ASH) || defined(OS_WIN)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_WIN)
ContentSetting GetDefaultValue(const WebsiteSettingsInfo* info) {
- const base::Value* initial_default = info->initial_default_value();
- if (!initial_default)
+ const base::Value& initial_default = info->initial_default_value();
+ if (initial_default.is_none())
return CONTENT_SETTING_DEFAULT;
- return static_cast<ContentSetting>(initial_default->GetInt());
+ return static_cast<ContentSetting>(initial_default.GetInt());
}
ContentSetting GetDefaultValue(ContentSettingsType type) {
@@ -73,9 +77,9 @@ const std::string& GetPrefName(ContentSettingsType type) {
class DefaultRuleIterator : public RuleIterator {
public:
- explicit DefaultRuleIterator(const base::Value* value) {
- if (value)
- value_ = value->Clone();
+ explicit DefaultRuleIterator(base::Value value) {
+ if (!value.is_none())
+ value_ = std::move(value);
else
is_done_ = true;
}
@@ -116,23 +120,24 @@ void DefaultProvider::RegisterProfilePrefs(
// These prefs have been deprecated, but need to be registered so they can
// be deleted on startup (see DiscardOrMigrateObsoletePreferences).
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
registry->RegisterIntegerPref(
kObsoleteFullscreenDefaultPref, 0,
user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
-#if !defined(OS_ANDROID)
+ registry->RegisterIntegerPref(kObsoleteNfcDefaultPref, 0);
+#if !BUILDFLAG(IS_ANDROID)
registry->RegisterIntegerPref(
kObsoleteMouseLockDefaultPref, 0,
user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
registry->RegisterIntegerPref(kObsoletePluginsDataDefaultPref, 0);
registry->RegisterIntegerPref(kObsoletePluginsDefaultPref, 0);
registry->RegisterIntegerPref(kObsoleteFileHandlingDefaultPref, 0);
-#endif // !defined(OS_ANDROID)
-#endif // !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_ANDROID)
+#endif // !BUILDFLAG(IS_IOS)
-#if BUILDFLAG(IS_CHROMEOS_ASH) || defined(OS_WIN)
+#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_WIN)
registry->RegisterBooleanPref(kDeprecatedEnableDRM, true);
-#endif // BUILDFLAG(IS_CHROMEOS_ASH) || defined(OS_WIN)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_WIN)
}
DefaultProvider::DefaultProvider(PrefService* prefs, bool off_the_record)
@@ -155,14 +160,14 @@ DefaultProvider::DefaultProvider(PrefService* prefs, bool off_the_record)
IntToContentSetting(prefs_->GetInteger(
GetPrefName(ContentSettingsType::POPUPS))),
CONTENT_SETTING_NUM_SETTINGS);
-#if !defined(OS_IOS) && !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_IOS) && !BUILDFLAG(IS_ANDROID)
UMA_HISTOGRAM_ENUMERATION("ContentSettings.DefaultImagesSetting",
IntToContentSetting(prefs_->GetInteger(
GetPrefName(ContentSettingsType::IMAGES))),
CONTENT_SETTING_NUM_SETTINGS);
#endif
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
UMA_HISTOGRAM_ENUMERATION("ContentSettings.DefaultJavaScriptSetting",
IntToContentSetting(prefs_->GetInteger(
GetPrefName(ContentSettingsType::JAVASCRIPT))),
@@ -215,16 +220,21 @@ DefaultProvider::DefaultProvider(PrefService* prefs, bool off_the_record)
CONTENT_SETTING_NUM_SETTINGS);
#endif
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
UMA_HISTOGRAM_ENUMERATION("ContentSettings.DefaultAutoDarkWebContentSetting",
IntToContentSetting(prefs_->GetInteger(GetPrefName(
ContentSettingsType::AUTO_DARK_WEB_CONTENT))),
CONTENT_SETTING_NUM_SETTINGS);
+#endif
+
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
+
UMA_HISTOGRAM_ENUMERATION("ContentSettings.DefaultRequestDesktopSiteSetting",
IntToContentSetting(prefs_->GetInteger(GetPrefName(
ContentSettingsType::REQUEST_DESKTOP_SITE))),
CONTENT_SETTING_NUM_SETTINGS);
+
#endif
pref_change_registrar_.Init(prefs_);
@@ -236,14 +246,13 @@ DefaultProvider::DefaultProvider(PrefService* prefs, bool off_the_record)
pref_change_registrar_.Add(info->default_value_pref_name(), callback);
}
-DefaultProvider::~DefaultProvider() {
-}
+DefaultProvider::~DefaultProvider() = default;
bool DefaultProvider::SetWebsiteSetting(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type,
- std::unique_ptr<base::Value>&& in_value,
+ base::Value&& in_value,
const ContentSettingConstraints& constraints) {
DCHECK(CalledOnValidThread());
DCHECK(prefs_);
@@ -254,9 +263,9 @@ bool DefaultProvider::SetWebsiteSetting(
return false;
}
- // Put |in_value| in a scoped pointer to ensure that it gets cleaned up
- // properly if we don't pass on the ownership.
- std::unique_ptr<base::Value> value(std::move(in_value));
+ // Move |in_value| to ensure that it gets cleaned up properly even if we don't
+ // pass on the ownership.
+ base::Value value(std::move(in_value));
// The default settings may not be directly modified for OTR sessions.
// Instead, they are synced to the main profile's setting.
@@ -271,9 +280,9 @@ bool DefaultProvider::SetWebsiteSetting(
// whose callbacks may try to reacquire the lock on the same thread.
{
base::AutoLock lock(lock_);
- ChangeSetting(content_type, value.get());
+ ChangeSetting(content_type, value.Clone());
}
- WriteToPref(content_type, value.get());
+ WriteToPref(content_type, value);
}
NotifyObservers(ContentSettingsPattern::Wildcard(),
@@ -290,12 +299,12 @@ std::unique_ptr<RuleIterator> DefaultProvider::GetRuleIterator(
return nullptr;
base::AutoLock lock(lock_);
- auto it = default_settings_.find(content_type);
+ const auto it = default_settings_.find(content_type);
if (it == default_settings_.end()) {
NOTREACHED();
return nullptr;
}
- return std::make_unique<DefaultRuleIterator>(it->second.get());
+ return std::make_unique<DefaultRuleIterator>(it->second.Clone());
}
void DefaultProvider::ClearAllContentSettingsRules(
@@ -319,34 +328,34 @@ void DefaultProvider::ReadDefaultSettings() {
WebsiteSettingsRegistry* website_settings =
WebsiteSettingsRegistry::GetInstance();
for (const WebsiteSettingsInfo* info : *website_settings)
- ChangeSetting(info->type(), ReadFromPref(info->type()).get());
+ ChangeSetting(info->type(), ReadFromPref(info->type()));
}
bool DefaultProvider::IsValueEmptyOrDefault(ContentSettingsType content_type,
- base::Value* value) {
- return !value ||
+ const base::Value& value) {
+ return value.is_none() ||
ValueToContentSetting(value) == GetDefaultValue(content_type);
}
void DefaultProvider::ChangeSetting(ContentSettingsType content_type,
- base::Value* value) {
+ base::Value value) {
const ContentSettingsInfo* info =
ContentSettingsRegistry::GetInstance()->Get(content_type);
- DCHECK(!info || !value ||
+ DCHECK(!info || value.is_none() ||
info->IsDefaultSettingValid(ValueToContentSetting(value)));
default_settings_[content_type] =
- value ? base::Value::ToUniquePtrValue(value->Clone())
- : ContentSettingToValue(GetDefaultValue(content_type));
+ value.is_none() ? ContentSettingToValue(GetDefaultValue(content_type))
+ : std::move(value);
}
void DefaultProvider::WriteToPref(ContentSettingsType content_type,
- base::Value* value) {
+ const base::Value& value) {
if (IsValueEmptyOrDefault(content_type, value)) {
prefs_->ClearPref(GetPrefName(content_type));
return;
}
- prefs_->SetInteger(GetPrefName(content_type), value->GetInt());
+ prefs_->SetInteger(GetPrefName(content_type), value.GetInt());
}
void DefaultProvider::OnPreferenceChanged(const std::string& name) {
@@ -381,7 +390,7 @@ void DefaultProvider::OnPreferenceChanged(const std::string& name) {
// whose callbacks may try to reacquire the lock on the same thread.
{
base::AutoLock lock(lock_);
- ChangeSetting(content_type, ReadFromPref(content_type).get());
+ ChangeSetting(content_type, ReadFromPref(content_type));
}
}
@@ -389,8 +398,7 @@ void DefaultProvider::OnPreferenceChanged(const std::string& name) {
ContentSettingsPattern::Wildcard(), content_type);
}
-std::unique_ptr<base::Value> DefaultProvider::ReadFromPref(
- ContentSettingsType content_type) {
+base::Value DefaultProvider::ReadFromPref(ContentSettingsType content_type) {
int int_value = prefs_->GetInteger(GetPrefName(content_type));
return ContentSettingToValue(IntToContentSetting(int_value));
}
@@ -400,17 +408,18 @@ void DefaultProvider::DiscardOrMigrateObsoletePreferences() {
return;
// These prefs were never stored on iOS/Android so they don't need to be
// deleted.
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
prefs_->ClearPref(kObsoleteFullscreenDefaultPref);
-#if !defined(OS_ANDROID)
+ prefs_->ClearPref(kObsoleteNfcDefaultPref);
+#if !BUILDFLAG(IS_ANDROID)
prefs_->ClearPref(kObsoleteMouseLockDefaultPref);
prefs_->ClearPref(kObsoletePluginsDefaultPref);
prefs_->ClearPref(kObsoletePluginsDataDefaultPref);
prefs_->ClearPref(kObsoleteFileHandlingDefaultPref);
-#endif // !defined(OS_ANDROID)
-#endif // !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_ANDROID)
+#endif // !BUILDFLAG(IS_IOS)
-#if BUILDFLAG(IS_CHROMEOS_ASH) || defined(OS_WIN)
+#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_WIN)
// TODO(crbug.com/1191642): Remove this migration logic in M100.
WebsiteSettingsRegistry* website_settings =
WebsiteSettingsRegistry::GetInstance();
@@ -424,7 +433,7 @@ void DefaultProvider::DiscardOrMigrateObsoletePreferences() {
: CONTENT_SETTING_BLOCK);
}
prefs_->ClearPref(kDeprecatedEnableDRM);
-#endif // BUILDFLAG(IS_CHROMEOS_ASH) || defined(OS_WIN)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_WIN)
}
} // namespace content_settings
diff --git a/chromium/components/content_settings/core/browser/content_settings_default_provider.h b/chromium/components/content_settings/core/browser/content_settings_default_provider.h
index bbc06b9ec84..b2a6b6cbbb2 100644
--- a/chromium/components/content_settings/core/browser/content_settings_default_provider.h
+++ b/chromium/components/content_settings/core/browser/content_settings_default_provider.h
@@ -45,7 +45,7 @@ class DefaultProvider : public ObservableProvider {
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type,
- std::unique_ptr<base::Value>&& value,
+ base::Value&& value,
const ContentSettingConstraints& constraint = {}) override;
void ClearAllContentSettingsRules(ContentSettingsType content_type) override;
@@ -56,20 +56,19 @@ class DefaultProvider : public ObservableProvider {
// Reads all settings from the pref service.
void ReadDefaultSettings();
- // Change the remembered setting in the memory.
- void ChangeSetting(ContentSettingsType content_type, base::Value* value);
+ // Change the remembered setting in the memory. Pass NONE value to reset.
+ void ChangeSetting(ContentSettingsType content_type, base::Value value);
- // True if |value| is NULL or it is the default value for |content_type|.
+ // True if |value| is NONE-type or it is the default value for |content_type|.
bool IsValueEmptyOrDefault(ContentSettingsType content_type,
- base::Value* value);
+ const base::Value& value);
// Reads the preference corresponding to |content_type|.
- std::unique_ptr<base::Value> ReadFromPref(ContentSettingsType content_type);
+ base::Value ReadFromPref(ContentSettingsType content_type);
// Writes the value |value| to the preference corresponding to |content_type|.
// It's the responsibility of caller to obtain a lock and notify observers.
- void WriteToPref(ContentSettingsType content_type,
- base::Value* value);
+ void WriteToPref(ContentSettingsType content_type, const base::Value& value);
// Called on prefs change.
void OnPreferenceChanged(const std::string& pref_name);
@@ -78,7 +77,7 @@ class DefaultProvider : public ObservableProvider {
void DiscardOrMigrateObsoletePreferences();
// Copies of the pref data, so that we can read it on the IO thread.
- std::map<ContentSettingsType, std::unique_ptr<base::Value>> default_settings_;
+ std::map<ContentSettingsType, base::Value> default_settings_;
raw_ptr<PrefService> prefs_;
diff --git a/chromium/components/content_settings/core/browser/content_settings_info.cc b/chromium/components/content_settings/core/browser/content_settings_info.cc
index 836ae72a5ae..88f44afbe8f 100644
--- a/chromium/components/content_settings/core/browser/content_settings_info.cc
+++ b/chromium/components/content_settings/core/browser/content_settings_info.cc
@@ -28,9 +28,9 @@ ContentSettingsInfo::ContentSettingsInfo(
ContentSettingsInfo::~ContentSettingsInfo() {}
ContentSetting ContentSettingsInfo::GetInitialDefaultSetting() const {
- const base::Value* initial_default =
+ const base::Value& initial_default =
website_settings_info()->initial_default_value();
- DCHECK(initial_default);
+ DCHECK(initial_default.is_int());
return ValueToContentSetting(initial_default);
}
diff --git a/chromium/components/content_settings/core/browser/content_settings_policy_provider.cc b/chromium/components/content_settings/core/browser/content_settings_policy_provider.cc
index afd989278fd..7819eb802ce 100644
--- a/chromium/components/content_settings/core/browser/content_settings_policy_provider.cc
+++ b/chromium/components/content_settings/core/browser/content_settings_policy_provider.cc
@@ -88,6 +88,14 @@ constexpr PrefsForManagedContentSettingsMapEntry
ContentSettingsType::JAVASCRIPT_JIT, CONTENT_SETTING_ALLOW},
{prefs::kManagedJavaScriptJitBlockedForSites,
ContentSettingsType::JAVASCRIPT_JIT, CONTENT_SETTING_BLOCK},
+ {prefs::kManagedWebHidAskForUrls, ContentSettingsType::HID_GUARD,
+ CONTENT_SETTING_ASK},
+ {prefs::kManagedWebHidBlockedForUrls, ContentSettingsType::HID_GUARD,
+ CONTENT_SETTING_BLOCK},
+ {prefs::kManagedWindowPlacementAllowedForUrls,
+ ContentSettingsType::WINDOW_PLACEMENT, CONTENT_SETTING_ALLOW},
+ {prefs::kManagedWindowPlacementBlockedForUrls,
+ ContentSettingsType::WINDOW_PLACEMENT, CONTENT_SETTING_BLOCK},
};
constexpr const char* kManagedPrefs[] = {
@@ -122,6 +130,10 @@ constexpr const char* kManagedPrefs[] = {
prefs::kManagedWebUsbBlockedForUrls,
prefs::kManagedJavaScriptJitAllowedForSites,
prefs::kManagedJavaScriptJitBlockedForSites,
+ prefs::kManagedWebHidAskForUrls,
+ prefs::kManagedWebHidBlockedForUrls,
+ prefs::kManagedWindowPlacementAllowedForUrls,
+ prefs::kManagedWindowPlacementBlockedForUrls,
};
// The following preferences are only used to indicate if a default content
@@ -149,6 +161,8 @@ constexpr const char* kManagedDefaultPrefs[] = {
prefs::kManagedDefaultWebBluetoothGuardSetting,
prefs::kManagedDefaultWebUsbGuardSetting,
prefs::kManagedDefaultJavaScriptJitSetting,
+ prefs::kManagedDefaultWebHidGuardSetting,
+ prefs::kManagedDefaultWindowPlacementSetting,
};
} // namespace
@@ -196,6 +210,10 @@ const PolicyProvider::PrefsForManagedDefaultMapEntry
prefs::kManagedDefaultInsecurePrivateNetworkSetting},
{ContentSettingsType::JAVASCRIPT_JIT,
prefs::kManagedDefaultJavaScriptJitSetting},
+ {ContentSettingsType::HID_GUARD,
+ prefs::kManagedDefaultWebHidGuardSetting},
+ {ContentSettingsType::WINDOW_PLACEMENT,
+ prefs::kManagedDefaultWindowPlacementSetting},
};
// static
@@ -254,7 +272,8 @@ void PolicyProvider::GetContentSettingsFromPreferences(
return;
}
- base::Value::ConstListView pattern_str_list = pref->GetValue()->GetList();
+ base::Value::ConstListView pattern_str_list =
+ pref->GetValue()->GetListDeprecated();
for (size_t i = 0; i < pattern_str_list.size(); ++i) {
if (!pattern_str_list[i].is_string()) {
NOTREACHED() << "Could not read content settings pattern #" << i
@@ -337,7 +356,7 @@ void PolicyProvider::GetAutoSelectCertificateSettingsFromPreferences(
// }
// }
std::unordered_map<std::string, base::DictionaryValue> filters_map;
- for (const auto& pattern_filter_str : pref->GetValue()->GetList()) {
+ for (const auto& pattern_filter_str : pref->GetValue()->GetListDeprecated()) {
if (!pattern_filter_str.is_string()) {
NOTREACHED();
continue;
@@ -361,7 +380,8 @@ void PolicyProvider::GetAutoSelectCertificateSettingsFromPreferences(
const std::string& pattern_str = pattern->GetString();
if (filters_map.find(pattern_str) == filters_map.end())
- filters_map[pattern_str].SetKey("filters", base::ListValue());
+ filters_map[pattern_str].SetKey("filters",
+ base::Value(base::Value::Type::LIST));
// Don't pass removed values from `pattern_filter`, because base::Values
// read with JSONReader use a shared string buffer. Instead, Clone() here.
@@ -370,7 +390,7 @@ void PolicyProvider::GetAutoSelectCertificateSettingsFromPreferences(
for (const auto& it : filters_map) {
const std::string& pattern_str = it.first;
- const base::DictionaryValue& setting = it.second;
+ const base::Value& setting = it.second;
ContentSettingsPattern pattern =
ContentSettingsPattern::FromString(pattern_str);
@@ -438,7 +458,7 @@ bool PolicyProvider::SetWebsiteSetting(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type,
- std::unique_ptr<base::Value>&& value,
+ base::Value&& value,
const ContentSettingConstraints& constraints) {
return false;
}
diff --git a/chromium/components/content_settings/core/browser/content_settings_policy_provider.h b/chromium/components/content_settings/core/browser/content_settings_policy_provider.h
index c2a5dbb253f..efcd90c3220 100644
--- a/chromium/components/content_settings/core/browser/content_settings_policy_provider.h
+++ b/chromium/components/content_settings/core/browser/content_settings_policy_provider.h
@@ -41,7 +41,7 @@ class PolicyProvider : public ObservableProvider {
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type,
- std::unique_ptr<base::Value>&& value,
+ base::Value&& value,
const ContentSettingConstraints& constraint = {}) override;
void ClearAllContentSettingsRules(ContentSettingsType content_type) override;
diff --git a/chromium/components/content_settings/core/browser/content_settings_pref.cc b/chromium/components/content_settings/core/browser/content_settings_pref.cc
index 8a31604c0e1..1175f143557 100644
--- a/chromium/components/content_settings/core/browser/content_settings_pref.cc
+++ b/chromium/components/content_settings/core/browser/content_settings_pref.cc
@@ -32,25 +32,25 @@
namespace {
-const char kExpirationPath[] = "expiration";
-const char kSessionModelPath[] = "model";
-const char kSettingPath[] = "setting";
-const char kLastModifiedPath[] = "last_modified";
+const char kExpirationKey[] = "expiration";
+const char kSessionModelKey[] = "model";
+const char kSettingKey[] = "setting";
+const char kLastModifiedKey[] = "last_modified";
-bool IsValueAllowedForType(const base::Value* value, ContentSettingsType type) {
+bool IsValueAllowedForType(const base::Value& value, ContentSettingsType type) {
const content_settings::ContentSettingsInfo* info =
content_settings::ContentSettingsRegistry::GetInstance()->Get(type);
if (info) {
- if (!value->is_int())
+ if (!value.is_int())
return false;
- if (value->GetInt() == CONTENT_SETTING_DEFAULT)
+ if (value.GetInt() == CONTENT_SETTING_DEFAULT)
return false;
- return info->IsSettingValid(IntToContentSetting(value->GetInt()));
+ return info->IsSettingValid(IntToContentSetting(value.GetInt()));
}
// TODO(raymes): We should permit different types of base::Value for
// website settings.
- return value->type() == base::Value::Type::DICTIONARY;
+ return value.is_dict();
}
std::string GetString(const base::Value& dict, const char* key) {
@@ -59,10 +59,10 @@ std::string GetString(const base::Value& dict, const char* key) {
return value ? *value : std::string();
}
-// Extract a timestamp from |dictionary[kLastModifiedPath]|.
+// Extract a timestamp from |dictionary[kLastModifiedKey]|.
// Will return base::Time() if no timestamp exists.
-base::Time GetTimeStamp(const base::DictionaryValue* dictionary) {
- std::string timestamp_str = GetString(*dictionary, kLastModifiedPath);
+base::Time GetTimeStamp(const base::Value& dictionary) {
+ std::string timestamp_str = GetString(dictionary, kLastModifiedKey);
int64_t timestamp = 0;
base::StringToInt64(timestamp_str, &timestamp);
base::Time last_modified =
@@ -70,11 +70,10 @@ base::Time GetTimeStamp(const base::DictionaryValue* dictionary) {
return last_modified;
}
-// Extract a timestamp from |dictionary[kExpirationPath]|. Will return
+// Extract a timestamp from |dictionary[kExpirationKey]|. Will return
// base::Time() if no timestamp exists.
-base::Time GetExpiration(const base::DictionaryValue* dictionary) {
- std::string expiration_timestamp_str =
- GetString(*dictionary, kExpirationPath);
+base::Time GetExpiration(const base::Value& dictionary) {
+ std::string expiration_timestamp_str = GetString(dictionary, kExpirationKey);
int64_t expiration_timestamp = 0;
base::StringToInt64(expiration_timestamp_str, &expiration_timestamp);
base::Time expiration = base::Time::FromDeltaSinceWindowsEpoch(
@@ -82,11 +81,10 @@ base::Time GetExpiration(const base::DictionaryValue* dictionary) {
return expiration;
}
-// Extract a SessionModel from |dictionary[kSessionModelPath]|. Will return
+// Extract a SessionModel from |dictionary[kSessionModelKey]|. Will return
// SessionModel::Durable if no model exists.
-content_settings::SessionModel GetSessionModel(
- const base::DictionaryValue* dictionary) {
- int model_int = dictionary->FindIntKey(kSessionModelPath).value_or(0);
+content_settings::SessionModel GetSessionModel(const base::Value& dictionary) {
+ int model_int = dictionary.FindIntKey(kSessionModelKey).value_or(0);
if ((model_int >
static_cast<int>(content_settings::SessionModel::kMaxValue)) ||
(model_int < 0)) {
@@ -145,7 +143,7 @@ ContentSettingsPref::ContentSettingsPref(
base::Unretained(this)));
}
-ContentSettingsPref::~ContentSettingsPref() {}
+ContentSettingsPref::~ContentSettingsPref() = default;
std::unique_ptr<RuleIterator> ContentSettingsPref::GetRuleIterator(
bool off_the_record) const {
@@ -154,21 +152,18 @@ std::unique_ptr<RuleIterator> ContentSettingsPref::GetRuleIterator(
return value_map_.GetRuleIterator(content_type_, &lock_);
}
-bool ContentSettingsPref::SetWebsiteSetting(
+void ContentSettingsPref::SetWebsiteSetting(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
base::Time modified_time,
- std::unique_ptr<base::Value>&& in_value,
+ base::Value value,
const ContentSettingConstraints& constraints) {
- DCHECK(!in_value || IsValueAllowedForType(in_value.get(), content_type_));
+ DCHECK(value.is_none() || IsValueAllowedForType(value, content_type_));
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(prefs_);
DCHECK(primary_pattern != ContentSettingsPattern::Wildcard() ||
secondary_pattern != ContentSettingsPattern::Wildcard());
- // At this point take the ownership of the |in_value|.
- std::unique_ptr<base::Value> value(std::move(in_value));
-
// Update in memory value map.
OriginIdentifierValueMap* map_to_modify = &off_the_record_value_map_;
if (!off_the_record_)
@@ -176,9 +171,9 @@ bool ContentSettingsPref::SetWebsiteSetting(
{
base::AutoLock auto_lock(lock_);
- if (value) {
+ if (!value.is_none()) {
map_to_modify->SetValue(primary_pattern, secondary_pattern, content_type_,
- modified_time, value->Clone(), constraints);
+ modified_time, value.Clone(), constraints);
} else {
map_to_modify->DeleteValue(primary_pattern, secondary_pattern,
content_type_);
@@ -186,13 +181,11 @@ bool ContentSettingsPref::SetWebsiteSetting(
}
// Update the content settings preference.
if (!off_the_record_) {
- UpdatePref(primary_pattern, secondary_pattern, modified_time, value.get(),
- constraints);
+ UpdatePref(primary_pattern, secondary_pattern, modified_time,
+ std::move(value), constraints);
}
notify_callback_.Run(primary_pattern, secondary_pattern, content_type_);
-
- return true;
}
base::Time ContentSettingsPref::GetWebsiteSettingLastModified(
@@ -262,7 +255,7 @@ void ContentSettingsPref::ReadContentSettingsFromPref() {
value_map_.clear();
// The returned value could be nullptr if the pref has never been set.
- const base::DictionaryValue* all_settings_dictionary =
+ const base::Value* all_settings_dictionary =
prefs_->GetDictionary(pref_name_);
if (!all_settings_dictionary)
return;
@@ -281,9 +274,8 @@ void ContentSettingsPref::ReadContentSettingsFromPref() {
// patterns is to be re-keyed under the canonical pattern.
base::StringPairs non_canonical_patterns_to_canonical_pattern;
- for (base::DictionaryValue::Iterator i(*all_settings_dictionary);
- !i.IsAtEnd(); i.Advance()) {
- const std::string& pattern_str(i.key());
+ for (const auto i : all_settings_dictionary->DictItems()) {
+ const std::string& pattern_str(i.first);
PatternPair pattern_pair = ParsePatternString(pattern_str);
if (!pattern_pair.first.IsValid() || !pattern_pair.second.IsValid()) {
// TODO: Change this to DFATAL when crbug.com/132659 is fixed.
@@ -295,7 +287,7 @@ void ContentSettingsPref::ReadContentSettingsFromPref() {
CreatePatternString(pattern_pair.first, pattern_pair.second);
DCHECK(!canonicalized_pattern_str.empty());
if (canonicalized_pattern_str != pattern_str) {
- if (all_settings_dictionary->HasKey(canonicalized_pattern_str)) {
+ if (all_settings_dictionary->FindKey(canonicalized_pattern_str)) {
non_canonical_patterns_to_remove.push_back(pattern_str);
continue;
} else {
@@ -310,9 +302,8 @@ void ContentSettingsPref::ReadContentSettingsFromPref() {
// Get settings dictionary for the current pattern string, and read
// settings from the dictionary.
- const base::DictionaryValue* settings_dictionary = nullptr;
- bool is_dictionary = i.value().GetAsDictionary(&settings_dictionary);
- DCHECK(is_dictionary);
+ DCHECK(i.second.is_dict());
+ const base::Value& settings_dictionary = i.second;
// Check to see if the setting is expired or not. This may be due to a past
// expiration date or a SessionModel of UserSession.
@@ -324,10 +315,10 @@ void ContentSettingsPref::ReadContentSettingsFromPref() {
continue;
}
- const base::Value* value = settings_dictionary->FindKey(kSettingPath);
+ const base::Value* value = settings_dictionary.FindKey(kSettingKey);
if (value) {
base::Time last_modified = GetTimeStamp(settings_dictionary);
- DCHECK(IsValueAllowedForType(value, content_type_));
+ DCHECK(IsValueAllowedForType(*value, content_type_));
value_map_.SetValue(std::move(pattern_pair.first),
std::move(pattern_pair.second), content_type_,
last_modified, value->Clone(),
@@ -378,7 +369,7 @@ void ContentSettingsPref::UpdatePref(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
const base::Time last_modified,
- const base::Value* value,
+ base::Value value,
const ContentSettingConstraints& constraints) {
// Ensure that |lock_| is not held by this thread, since this function will
// send out notifications (by |~ScopedDictionaryPrefUpdate|).
@@ -397,7 +388,7 @@ void ContentSettingsPref::UpdatePref(
bool found = pattern_pairs_settings->GetDictionaryWithoutPathExpansion(
pattern_str, &settings_dictionary);
- if (!found && value) {
+ if (!found && !value.is_none()) {
settings_dictionary =
pattern_pairs_settings->SetDictionaryWithoutPathExpansion(
pattern_str, std::make_unique<base::DictionaryValue>());
@@ -405,28 +396,27 @@ void ContentSettingsPref::UpdatePref(
if (settings_dictionary) {
// Update settings dictionary.
- if (value == nullptr) {
- settings_dictionary->RemoveWithoutPathExpansion(kSettingPath, nullptr);
- settings_dictionary->RemoveWithoutPathExpansion(kLastModifiedPath,
+ if (value.is_none()) {
+ settings_dictionary->RemoveWithoutPathExpansion(kSettingKey, nullptr);
+ settings_dictionary->RemoveWithoutPathExpansion(kLastModifiedKey,
nullptr);
- settings_dictionary->RemoveWithoutPathExpansion(kExpirationPath,
+ settings_dictionary->RemoveWithoutPathExpansion(kExpirationKey,
nullptr);
- settings_dictionary->RemoveWithoutPathExpansion(kSessionModelPath,
+ settings_dictionary->RemoveWithoutPathExpansion(kSessionModelKey,
nullptr);
} else {
- settings_dictionary->SetWithoutPathExpansion(
- kSettingPath, base::Value::ToUniquePtrValue(value->Clone()));
+ settings_dictionary->SetKey(kSettingKey, std::move(value));
settings_dictionary->SetKey(
- kLastModifiedPath,
+ kLastModifiedKey,
base::Value(base::NumberToString(
last_modified.ToDeltaSinceWindowsEpoch().InMicroseconds())));
settings_dictionary->SetKey(
- kExpirationPath,
+ kExpirationKey,
base::Value(base::NumberToString(
constraints.expiration.ToDeltaSinceWindowsEpoch()
.InMicroseconds())));
settings_dictionary->SetKey(
- kSessionModelPath,
+ kSessionModelKey,
base::Value(static_cast<int>(constraints.session_model)));
}
diff --git a/chromium/components/content_settings/core/browser/content_settings_pref.h b/chromium/components/content_settings/core/browser/content_settings_pref.h
index 3bfa234ae00..6e8b426289e 100644
--- a/chromium/components/content_settings/core/browser/content_settings_pref.h
+++ b/chromium/components/content_settings/core/browser/content_settings_pref.h
@@ -52,10 +52,10 @@ class ContentSettingsPref {
std::unique_ptr<RuleIterator> GetRuleIterator(
bool off_the_record) const;
- bool SetWebsiteSetting(const ContentSettingsPattern& primary_pattern,
+ void SetWebsiteSetting(const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
base::Time modified_time,
- std::unique_ptr<base::Value>&& value,
+ base::Value value,
const ContentSettingConstraints& constraints);
// Returns the |last_modified| date of a setting.
@@ -87,7 +87,7 @@ class ContentSettingsPref {
void UpdatePref(const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
const base::Time last_modified,
- const base::Value* value,
+ base::Value value,
const ContentSettingConstraints& constraints);
// In the debug mode, asserts that |lock_| is not held by this thread. It's
diff --git a/chromium/components/content_settings/core/browser/content_settings_pref_provider.cc b/chromium/components/content_settings/core/browser/content_settings_pref_provider.cc
index 94ccd833781..c183de34075 100644
--- a/chromium/components/content_settings/core/browser/content_settings_pref_provider.cc
+++ b/chromium/components/content_settings/core/browser/content_settings_pref_provider.cc
@@ -45,10 +45,14 @@ namespace {
const char kObsoleteDomainToOriginMigrationStatus[] =
"profile.content_settings.domain_to_origin_migration_status";
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
const char kObsoleteFullscreenExceptionsPref[] =
"profile.content_settings.exceptions.fullscreen";
-#if !defined(OS_ANDROID)
+// The "nfc" preference was superseded by "nfc-devices" once Web NFC gained the
+// ability to make NFC tags permanently read-only. See crbug.com/1275576
+const char kObsoleteNfcExceptionsPref[] =
+ "profile.content_settings.exceptions.nfc";
+#if !BUILDFLAG(IS_ANDROID)
const char kObsoleteMouseLockExceptionsPref[] =
"profile.content_settings.exceptions.mouselock";
const char kObsoletePluginsExceptionsPref[] =
@@ -57,8 +61,8 @@ const char kObsoletePluginsDataExceptionsPref[] =
"profile.content_settings.exceptions.flash_data";
const char kObsoleteFileHandlingExceptionsPref[] =
"profile.content_settings.exceptions.file_handling";
-#endif // !defined(OS_ANDROID)
-#endif // !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_ANDROID)
+#endif // !BUILDFLAG(IS_IOS)
} // namespace
@@ -85,19 +89,20 @@ void PrefProvider::RegisterProfilePrefs(
// These prefs have been removed, but need to be registered so they can
// be deleted on startup.
registry->RegisterIntegerPref(kObsoleteDomainToOriginMigrationStatus, 0);
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
registry->RegisterDictionaryPref(
kObsoleteFullscreenExceptionsPref,
user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
-#if !defined(OS_ANDROID)
+ registry->RegisterDictionaryPref(kObsoleteNfcExceptionsPref);
+#if !BUILDFLAG(IS_ANDROID)
registry->RegisterDictionaryPref(
kObsoleteMouseLockExceptionsPref,
user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
registry->RegisterDictionaryPref(kObsoletePluginsDataExceptionsPref);
registry->RegisterDictionaryPref(kObsoletePluginsExceptionsPref);
registry->RegisterDictionaryPref(kObsoleteFileHandlingExceptionsPref);
-#endif // !defined(OS_ANDROID)
-#endif // !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_ANDROID)
+#endif // !BUILDFLAG(IS_IOS)
}
PrefProvider::PrefProvider(PrefService* prefs,
@@ -179,7 +184,7 @@ bool PrefProvider::SetWebsiteSetting(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type,
- std::unique_ptr<base::Value>&& in_value,
+ base::Value&& in_value,
const ContentSettingConstraints& constraints) {
DCHECK(CalledOnValidThread());
DCHECK(prefs_);
@@ -205,12 +210,13 @@ bool PrefProvider::SetWebsiteSetting(
// existing Allow Always setting.
if (constraints.session_model == SessionModel::OneTime) {
DCHECK_EQ(content_type, ContentSettingsType::GEOLOCATION);
- in_value = nullptr;
+ in_value = base::Value();
}
- return GetPref(content_type)
+ GetPref(content_type)
->SetWebsiteSetting(primary_pattern, secondary_pattern, modified_time,
std::move(in_value), constraints);
+ return true;
}
base::Time PrefProvider::GetWebsiteSettingLastModified(
@@ -273,15 +279,16 @@ void PrefProvider::DiscardOrMigrateObsoletePreferences() {
// These prefs were never stored on iOS/Android so they don't need to be
// deleted.
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
prefs_->ClearPref(kObsoleteFullscreenExceptionsPref);
-#if !defined(OS_ANDROID)
+ prefs_->ClearPref(kObsoleteNfcExceptionsPref);
+#if !BUILDFLAG(IS_ANDROID)
prefs_->ClearPref(kObsoleteMouseLockExceptionsPref);
prefs_->ClearPref(kObsoletePluginsExceptionsPref);
prefs_->ClearPref(kObsoletePluginsDataExceptionsPref);
prefs_->ClearPref(kObsoleteFileHandlingExceptionsPref);
-#endif // !defined(OS_ANDROID)
-#endif // !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_ANDROID)
+#endif // !BUILDFLAG(IS_IOS)
}
void PrefProvider::SetClockForTesting(base::Clock* clock) {
diff --git a/chromium/components/content_settings/core/browser/content_settings_pref_provider.h b/chromium/components/content_settings/core/browser/content_settings_pref_provider.h
index f60c454b4e8..997c3eba7b0 100644
--- a/chromium/components/content_settings/core/browser/content_settings_pref_provider.h
+++ b/chromium/components/content_settings/core/browser/content_settings_pref_provider.h
@@ -52,7 +52,7 @@ class PrefProvider : public UserModifiableProvider {
bool SetWebsiteSetting(const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type,
- std::unique_ptr<base::Value>&& value,
+ base::Value&& value,
const ContentSettingConstraints& constraints) override;
void ClearAllContentSettingsRules(ContentSettingsType content_type) override;
void ShutdownOnUIThread() override;
diff --git a/chromium/components/content_settings/core/browser/content_settings_pref_unittest.cc b/chromium/components/content_settings/core/browser/content_settings_pref_unittest.cc
index f367417a97b..adff32c6812 100644
--- a/chromium/components/content_settings/core/browser/content_settings_pref_unittest.cc
+++ b/chromium/components/content_settings/core/browser/content_settings_pref_unittest.cc
@@ -114,16 +114,17 @@ TEST(ContentSettingsPref, CanonicalizationWhileReadingFromPrefs) {
{kTestPatternCanonicalBeta, kTestPatternCanonicalBeta},
};
- auto original_pref_value = std::make_unique<base::DictionaryValue>();
+ base::Value original_pref_value(base::Value::Type::DICTIONARY);
for (const auto* pattern : kTestOriginalPatterns) {
- original_pref_value->SetKey(
+ original_pref_value.SetKey(
pattern, CreateDummyContentSettingValue(pattern, /*expired=*/false));
}
TestingPrefServiceSimple prefs;
prefs.registry()->RegisterDictionaryPref(kTestContentSettingPrefName);
- prefs.SetUserPref(kTestContentSettingPrefName,
- std::move(original_pref_value));
+ prefs.SetUserPref(
+ kTestContentSettingPrefName,
+ base::Value::ToUniquePtrValue(std::move(original_pref_value)));
PrefChangeRegistrar registrar;
registrar.Init(&prefs);
@@ -177,20 +178,21 @@ TEST(ContentSettingsPref, ExpirationWhileReadingFromPrefs) {
// Create two pre-existing entries, one that is expired and one that never
// expires.
- auto original_pref_value = std::make_unique<base::DictionaryValue>();
- original_pref_value->SetKey(
+ base::Value original_pref_value(base::Value::Type::DICTIONARY);
+ original_pref_value.SetKey(
kTestPatternCanonicalAlpha,
CreateDummyContentSettingValue(kTestPatternCanonicalAlpha,
/*expired=*/true));
- original_pref_value->SetKey(
+ original_pref_value.SetKey(
kTestPatternCanonicalBeta,
CreateDummyContentSettingValue(kTestPatternCanonicalBeta,
/*expired=*/false));
TestingPrefServiceSimple prefs;
prefs.registry()->RegisterDictionaryPref(kTestContentSettingPrefName);
- prefs.SetUserPref(kTestContentSettingPrefName,
- std::move(original_pref_value));
+ prefs.SetUserPref(
+ kTestContentSettingPrefName,
+ base::Value::ToUniquePtrValue(std::move(original_pref_value)));
PrefChangeRegistrar registrar;
registrar.Init(&prefs);
@@ -232,7 +234,7 @@ TEST(ContentSettingsPref, ExpirationWhileReadingFromPrefs) {
TEST(ContentSettingsPref, LegacyLastModifiedLoad) {
constexpr char kPatternPair[] = "http://example.com,*";
- auto original_pref_value = std::make_unique<base::DictionaryValue>();
+ base::Value original_pref_value(base::Value::Type::DICTIONARY);
const base::Time last_modified =
base::Time::FromInternalValue(13189876543210000);
@@ -244,12 +246,13 @@ TEST(ContentSettingsPref, LegacyLastModifiedLoad) {
pref_value.SetKey(kSettingKey, base::Value(CONTENT_SETTING_BLOCK));
pref_value.SetKey(kExpirationKey, base::Value("0"));
- original_pref_value->SetKey(kPatternPair, std::move(pref_value));
+ original_pref_value.SetKey(kPatternPair, std::move(pref_value));
TestingPrefServiceSimple prefs;
prefs.registry()->RegisterDictionaryPref(kTestContentSettingPrefName);
- prefs.SetUserPref(kTestContentSettingPrefName,
- std::move(original_pref_value));
+ prefs.SetUserPref(
+ kTestContentSettingPrefName,
+ base::Value::ToUniquePtrValue(std::move(original_pref_value)));
PrefChangeRegistrar registrar;
registrar.Init(&prefs);
diff --git a/chromium/components/content_settings/core/browser/content_settings_provider.h b/chromium/components/content_settings/core/browser/content_settings_provider.h
index 77b775f2370..fad467a1071 100644
--- a/chromium/components/content_settings/core/browser/content_settings_provider.h
+++ b/chromium/components/content_settings/core/browser/content_settings_provider.h
@@ -51,7 +51,7 @@ class ProviderInterface {
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type,
- std::unique_ptr<base::Value>&& value,
+ base::Value&& value,
const ContentSettingConstraints& constraints) = 0;
// Resets all content settings for the given |content_type| and empty resource
diff --git a/chromium/components/content_settings/core/browser/content_settings_provider_unittest.cc b/chromium/components/content_settings/core/browser/content_settings_provider_unittest.cc
index 87ec9511472..bb0b0303524 100644
--- a/chromium/components/content_settings/core/browser/content_settings_provider_unittest.cc
+++ b/chromium/components/content_settings/core/browser/content_settings_provider_unittest.cc
@@ -4,6 +4,7 @@
#include <memory>
+#include "base/values.h"
#include "components/content_settings/core/common/content_settings_pattern.h"
#include "components/content_settings/core/test/content_settings_mock_provider.h"
#include "components/content_settings/core/test/content_settings_test_utils.h"
@@ -18,30 +19,30 @@ TEST(ContentSettingsProviderTest, Mock) {
GURL url("http://www.youtube.com");
MockProvider mock_provider(false);
- mock_provider.SetWebsiteSetting(
- pattern, pattern, ContentSettingsType::NOTIFICATIONS,
- std::make_unique<base::Value>(CONTENT_SETTING_BLOCK));
+ mock_provider.SetWebsiteSetting(pattern, pattern,
+ ContentSettingsType::NOTIFICATIONS,
+ base::Value(CONTENT_SETTING_BLOCK));
EXPECT_EQ(
CONTENT_SETTING_BLOCK,
TestUtils::GetContentSetting(&mock_provider, url, url,
ContentSettingsType::NOTIFICATIONS, false));
- std::unique_ptr<base::Value> value_ptr(TestUtils::GetContentSettingValue(
- &mock_provider, url, url, ContentSettingsType::NOTIFICATIONS, false));
+ base::Value value = TestUtils::GetContentSettingValue(
+ &mock_provider, url, url, ContentSettingsType::NOTIFICATIONS, false);
EXPECT_EQ(CONTENT_SETTING_BLOCK,
- IntToContentSetting(value_ptr->GetIfInt().value_or(-1)));
+ IntToContentSetting(value.GetIfInt().value_or(-1)));
EXPECT_EQ(
CONTENT_SETTING_DEFAULT,
TestUtils::GetContentSetting(&mock_provider, url, url,
ContentSettingsType::GEOLOCATION, false));
- EXPECT_EQ(nullptr, TestUtils::GetContentSettingValue(
- &mock_provider, url, url,
- ContentSettingsType::GEOLOCATION, false));
+ EXPECT_EQ(base::Value(), TestUtils::GetContentSettingValue(
+ &mock_provider, url, url,
+ ContentSettingsType::GEOLOCATION, false));
bool owned = mock_provider.SetWebsiteSetting(
pattern, pattern, ContentSettingsType::NOTIFICATIONS,
- std::make_unique<base::Value>(CONTENT_SETTING_ALLOW));
+ base::Value(CONTENT_SETTING_ALLOW));
EXPECT_TRUE(owned);
EXPECT_EQ(
CONTENT_SETTING_ALLOW,
@@ -49,9 +50,9 @@ TEST(ContentSettingsProviderTest, Mock) {
ContentSettingsType::NOTIFICATIONS, false));
mock_provider.set_read_only(true);
- std::unique_ptr<base::Value> value(new base::Value(CONTENT_SETTING_BLOCK));
- owned = mock_provider.SetWebsiteSetting(
- pattern, pattern, ContentSettingsType::NOTIFICATIONS, std::move(value));
+ owned = mock_provider.SetWebsiteSetting(pattern, pattern,
+ ContentSettingsType::NOTIFICATIONS,
+ base::Value(CONTENT_SETTING_BLOCK));
EXPECT_FALSE(owned);
EXPECT_EQ(
CONTENT_SETTING_ALLOW,
@@ -61,9 +62,9 @@ TEST(ContentSettingsProviderTest, Mock) {
EXPECT_TRUE(mock_provider.read_only());
mock_provider.set_read_only(false);
- owned = mock_provider.SetWebsiteSetting(
- pattern, pattern, ContentSettingsType::NOTIFICATIONS,
- std::make_unique<base::Value>(CONTENT_SETTING_BLOCK));
+ owned = mock_provider.SetWebsiteSetting(pattern, pattern,
+ ContentSettingsType::NOTIFICATIONS,
+ base::Value(CONTENT_SETTING_BLOCK));
EXPECT_TRUE(owned);
EXPECT_EQ(
CONTENT_SETTING_BLOCK,
diff --git a/chromium/components/content_settings/core/browser/content_settings_registry.cc b/chromium/components/content_settings/core/browser/content_settings_registry.cc
index b8968af15b6..f6ae469fca7 100644
--- a/chromium/components/content_settings/core/browser/content_settings_registry.cc
+++ b/chromium/components/content_settings/core/browser/content_settings_registry.cc
@@ -16,7 +16,7 @@
#include "components/content_settings/core/common/content_settings.h"
#include "components/content_settings/core/common/features.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "media/base/android/media_drm_bridge.h"
#endif
@@ -268,21 +268,21 @@ void ContentSettingsRegistry::Init() {
// https://crbug.com/904883).
// On ChromeOS and Windows the default value is always ALLOW.
const auto protected_media_identifier_setting =
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
media::MediaDrmBridge::IsPerOriginProvisioningSupported()
? CONTENT_SETTING_ALLOW
: CONTENT_SETTING_ASK;
#else
CONTENT_SETTING_ALLOW;
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
Register(ContentSettingsType::PROTECTED_MEDIA_IDENTIFIER,
"protected-media-identifier", protected_media_identifier_setting,
WebsiteSettingsInfo::UNSYNCABLE, AllowlistedSchemes(),
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK,
CONTENT_SETTING_ASK),
-#else // defined(OS_ANDROID)
+#else // BUILDFLAG(IS_ANDROID)
ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK),
#endif // else
WebsiteSettingsInfo::SINGLE_ORIGIN_ONLY_SCOPE,
@@ -503,7 +503,9 @@ void ContentSettingsRegistry::Init() {
ContentSettingsInfo::PERSISTENT,
ContentSettingsInfo::EXCEPTIONS_ON_SECURE_ORIGINS_ONLY);
- Register(ContentSettingsType::NFC, "nfc", CONTENT_SETTING_ASK,
+ // The "nfc" name should not be used in the future to avoid name collisions.
+ // See crbug.com/1275576
+ Register(ContentSettingsType::NFC, "nfc-devices", CONTENT_SETTING_ASK,
WebsiteSettingsInfo::UNSYNCABLE, AllowlistedSchemes(),
ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_ASK,
CONTENT_SETTING_BLOCK),
@@ -614,13 +616,13 @@ void ContentSettingsRegistry::Init() {
ContentSettingsInfo::EXCEPTIONS_ON_SECURE_AND_INSECURE_ORIGINS);
const auto auto_dark_web_content_setting =
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
content_settings::kDarkenWebsitesCheckboxOptOut.Get()
? CONTENT_SETTING_ALLOW
: CONTENT_SETTING_BLOCK;
#else
CONTENT_SETTING_ALLOW;
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
Register(ContentSettingsType::AUTO_DARK_WEB_CONTENT, "auto-dark-web-content",
auto_dark_web_content_setting, WebsiteSettingsInfo::UNSYNCABLE,
@@ -637,7 +639,8 @@ void ContentSettingsRegistry::Init() {
AllowlistedSchemes(),
ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK),
WebsiteSettingsInfo::SINGLE_ORIGIN_ONLY_SCOPE,
- WebsiteSettingsRegistry::PLATFORM_ANDROID,
+ WebsiteSettingsRegistry::PLATFORM_ANDROID |
+ WebsiteSettingsRegistry::PLATFORM_IOS,
ContentSettingsInfo::INHERIT_IN_INCOGNITO,
ContentSettingsInfo::PERSISTENT,
ContentSettingsInfo::EXCEPTIONS_ON_SECURE_AND_INSECURE_ORIGINS);
@@ -658,8 +661,7 @@ void ContentSettingsRegistry::Register(
// Ensure that nothing has been registered yet for the given type.
DCHECK(!website_settings_registry_->Get(type));
- std::unique_ptr<base::Value> default_value(
- new base::Value(static_cast<int>(initial_default_value)));
+ base::Value default_value(static_cast<int>(initial_default_value));
const WebsiteSettingsInfo* website_settings_info =
website_settings_registry_->Register(
type, name, std::move(default_value), sync_status,
diff --git a/chromium/components/content_settings/core/browser/content_settings_registry_unittest.cc b/chromium/components/content_settings/core/browser/content_settings_registry_unittest.cc
index bdb81f19d43..23302535d11 100644
--- a/chromium/components/content_settings/core/browser/content_settings_registry_unittest.cc
+++ b/chromium/components/content_settings/core/browser/content_settings_registry_unittest.cc
@@ -40,18 +40,18 @@ class ContentSettingsRegistryTest : public testing::Test {
};
TEST_F(ContentSettingsRegistryTest, GetPlatformDependent) {
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
// Javascript shouldn't be registered on iOS.
EXPECT_FALSE(registry()->Get(ContentSettingsType::JAVASCRIPT));
#endif
-#if defined(OS_IOS) || defined(OS_ANDROID)
+#if BUILDFLAG(IS_IOS) || BUILDFLAG(IS_ANDROID)
// Images shouldn't be registered on mobile.
EXPECT_FALSE(registry()->Get(ContentSettingsType::IMAGES));
#endif
// Protected media identifier only registered on Android, Chrome OS and Windows.
-#if defined(ANDROID) || defined(OS_CHROMEOS) || defined(OS_WIN)
+#if defined(ANDROID) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN)
EXPECT_TRUE(registry()->Get(ContentSettingsType::PROTECTED_MEDIA_IDENTIFIER));
#else
EXPECT_FALSE(
@@ -84,10 +84,10 @@ TEST_F(ContentSettingsRegistryTest, Properties) {
website_settings_info->pref_name());
EXPECT_EQ("profile.default_content_setting_values.cookies",
website_settings_info->default_value_pref_name());
- ASSERT_TRUE(website_settings_info->initial_default_value()->is_int());
+ ASSERT_TRUE(website_settings_info->initial_default_value().is_int());
EXPECT_EQ(CONTENT_SETTING_ALLOW,
- website_settings_info->initial_default_value()->GetInt());
-#if defined(OS_ANDROID) || defined(OS_IOS)
+ website_settings_info->initial_default_value().GetInt());
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
EXPECT_EQ(PrefRegistry::NO_REGISTRATION_FLAGS,
website_settings_info->GetPrefRegistrationFlags());
#else
@@ -158,7 +158,7 @@ TEST_F(ContentSettingsRegistryTest, IsDefaultSettingValid) {
registry()->Get(ContentSettingsType::COOKIES);
EXPECT_TRUE(info->IsDefaultSettingValid(CONTENT_SETTING_ALLOW));
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
info = registry()->Get(ContentSettingsType::MEDIASTREAM_MIC);
EXPECT_FALSE(info->IsDefaultSettingValid(CONTENT_SETTING_ALLOW));
@@ -171,7 +171,7 @@ TEST_F(ContentSettingsRegistryTest, IsDefaultSettingValid) {
EXPECT_TRUE(info->IsDefaultSettingValid(CONTENT_SETTING_ALLOW));
#endif
-#if !defined(OS_IOS) && !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_IOS) && !BUILDFLAG(IS_ANDROID)
info = registry()->Get(ContentSettingsType::FILE_SYSTEM_WRITE_GUARD);
EXPECT_FALSE(info->IsDefaultSettingValid(CONTENT_SETTING_ALLOW));
#endif
@@ -182,7 +182,7 @@ TEST_F(ContentSettingsRegistryTest, IsDefaultSettingValid) {
// would require this test to be updated.
TEST_F(ContentSettingsRegistryTest, GetInitialDefaultSetting) {
// There is no default-ask content setting on iOS, so skip testing it there.
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
const ContentSettingsInfo* notifications =
registry()->Get(ContentSettingsType::NOTIFICATIONS);
EXPECT_EQ(CONTENT_SETTING_ASK, notifications->GetInitialDefaultSetting());
diff --git a/chromium/components/content_settings/core/browser/content_settings_utils.cc b/chromium/components/content_settings/core/browser/content_settings_utils.cc
index 75473709e0e..6a37f727642 100644
--- a/chromium/components/content_settings/core/browser/content_settings_utils.cc
+++ b/chromium/components/content_settings/core/browser/content_settings_utils.cc
@@ -70,9 +70,9 @@ std::string ContentSettingToString(ContentSetting setting) {
bool ContentSettingFromString(const std::string& name,
ContentSetting* setting) {
- for (size_t i = 0; i < base::size(kContentSettingsStringMapping); ++i) {
- if (name == kContentSettingsStringMapping[i].content_setting_str) {
- *setting = kContentSettingsStringMapping[i].content_setting;
+ for (const auto& string_mapping : kContentSettingsStringMapping) {
+ if (name == string_mapping.content_setting_str) {
+ *setting = string_mapping.content_setting;
return true;
}
}
@@ -120,7 +120,7 @@ PatternPair ParsePatternString(const std::string& pattern_str) {
void GetRendererContentSettingRules(const HostContentSettingsMap* map,
RendererContentSettingRules* rules) {
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
map->GetSettingsForOneType(ContentSettingsType::IMAGES,
&(rules->image_rules));
map->GetSettingsForOneType(ContentSettingsType::MIXEDSCRIPT,
@@ -129,24 +129,21 @@ void GetRendererContentSettingRules(const HostContentSettingsMap* map,
// is added for all origins.
rules->auto_dark_content_rules.push_back(ContentSettingPatternSource(
ContentSettingsPattern::Wildcard(), ContentSettingsPattern::Wildcard(),
- base::Value::FromUniquePtrValue(
- ContentSettingToValue(CONTENT_SETTING_ALLOW)),
- std::string(), map->IsOffTheRecord()));
+ ContentSettingToValue(CONTENT_SETTING_ALLOW), std::string(),
+ map->IsOffTheRecord()));
#else
// Android doesn't use image content settings, so ALLOW rule is added for
// all origins.
rules->image_rules.push_back(ContentSettingPatternSource(
ContentSettingsPattern::Wildcard(), ContentSettingsPattern::Wildcard(),
- base::Value::FromUniquePtrValue(
- ContentSettingToValue(CONTENT_SETTING_ALLOW)),
- std::string(), map->IsOffTheRecord()));
+ ContentSettingToValue(CONTENT_SETTING_ALLOW), std::string(),
+ map->IsOffTheRecord()));
// In Android active mixed content is hard blocked, with no option to allow
// it.
rules->mixed_content_rules.push_back(ContentSettingPatternSource(
ContentSettingsPattern::Wildcard(), ContentSettingsPattern::Wildcard(),
- base::Value::FromUniquePtrValue(
- ContentSettingToValue(CONTENT_SETTING_BLOCK)),
- std::string(), map->IsOffTheRecord()));
+ ContentSettingToValue(CONTENT_SETTING_BLOCK), std::string(),
+ map->IsOffTheRecord()));
map->GetSettingsForOneType(ContentSettingsType::AUTO_DARK_WEB_CONTENT,
&(rules->auto_dark_content_rules));
#endif
diff --git a/chromium/components/content_settings/core/browser/cookie_settings.cc b/chromium/components/content_settings/core/browser/cookie_settings.cc
index 0a687439982..101b01f9531 100644
--- a/chromium/components/content_settings/core/browser/cookie_settings.cc
+++ b/chromium/components/content_settings/core/browser/cookie_settings.cc
@@ -21,7 +21,7 @@
#include "net/cookies/site_for_cookies.h"
#include "url/gurl.h"
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
#include "components/content_settings/core/common/features.h"
#else
#include "third_party/blink/public/common/features.h"
@@ -175,9 +175,8 @@ ContentSetting CookieSettings::GetCookieSettingInternal(
// First get any host-specific settings.
SettingInfo info;
- std::unique_ptr<base::Value> value =
- host_content_settings_map_->GetWebsiteSetting(
- url, first_party_url, ContentSettingsType::COOKIES, &info);
+ const base::Value value = host_content_settings_map_->GetWebsiteSetting(
+ url, first_party_url, ContentSettingsType::COOKIES, &info);
if (source)
*source = info.source;
@@ -189,8 +188,8 @@ ContentSetting CookieSettings::GetCookieSettingInternal(
!first_party_url.SchemeIs(extension_scheme_);
// We should always have a value, at least from the default provider.
- DCHECK(value);
- ContentSetting setting = ValueToContentSetting(value.get());
+ DCHECK(value.is_int());
+ ContentSetting setting = ValueToContentSetting(value);
bool block = block_third && is_third_party_request;
if (!block) {
@@ -198,7 +197,7 @@ ContentSetting CookieSettings::GetCookieSettingInternal(
net::cookie_util::StorageAccessResult::ACCESS_ALLOWED);
}
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
// IOS doesn't use blink and as such cannot check our feature flag. Disabling
// by default there should be no-op as the lack of Blink also means no grants
// would be generated. Everywhere else we'll use |kStorageAccessAPI| to gate
@@ -231,7 +230,7 @@ CookieSettings::~CookieSettings() = default;
bool CookieSettings::ShouldBlockThirdPartyCookiesInternal() {
DCHECK(thread_checker_.CalledOnValidThread());
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
if (!base::FeatureList::IsEnabled(kImprovedCookieControls))
return false;
#endif
diff --git a/chromium/components/content_settings/core/browser/cookie_settings_policy_handler.cc b/chromium/components/content_settings/core/browser/cookie_settings_policy_handler.cc
index 294028e9d04..f3c3b5a1ee3 100644
--- a/chromium/components/content_settings/core/browser/cookie_settings_policy_handler.cc
+++ b/chromium/components/content_settings/core/browser/cookie_settings_policy_handler.cc
@@ -35,6 +35,7 @@ void CookieSettingsPolicyHandler::ApplyPolicySettings(
// sandbox while privacy sandbox is an experiment.
if (third_party_cookie_blocking->GetBool()) {
prefs->SetBoolean(prefs::kPrivacySandboxApisEnabled, false);
+ prefs->SetBoolean(prefs::kPrivacySandboxApisEnabledV2, false);
}
}
// Also check against the default cookie content settings policy and disable
@@ -45,6 +46,7 @@ void CookieSettingsPolicyHandler::ApplyPolicySettings(
static_cast<ContentSetting>(default_cookie_setting->GetInt()) ==
CONTENT_SETTING_BLOCK) {
prefs->SetBoolean(prefs::kPrivacySandboxApisEnabled, false);
+ prefs->SetBoolean(prefs::kPrivacySandboxApisEnabledV2, false);
}
}
diff --git a/chromium/components/content_settings/core/browser/cookie_settings_policy_handler_unittest.cc b/chromium/components/content_settings/core/browser/cookie_settings_policy_handler_unittest.cc
index 86e2941f99f..340c8b18e3f 100644
--- a/chromium/components/content_settings/core/browser/cookie_settings_policy_handler_unittest.cc
+++ b/chromium/components/content_settings/core/browser/cookie_settings_policy_handler_unittest.cc
@@ -74,6 +74,7 @@ TEST_F(CookieSettingsPolicyHandlerTest,
UpdateProviderPolicy(policy);
const base::Value* value;
EXPECT_FALSE(store_->GetValue(prefs::kPrivacySandboxApisEnabled, &value));
+ EXPECT_FALSE(store_->GetValue(prefs::kPrivacySandboxApisEnabledV2, &value));
}
TEST_F(CookieSettingsPolicyHandlerTest,
@@ -82,6 +83,8 @@ TEST_F(CookieSettingsPolicyHandlerTest,
const base::Value* value;
EXPECT_TRUE(store_->GetValue(prefs::kPrivacySandboxApisEnabled, &value));
EXPECT_EQ(value->GetBool(), false);
+ EXPECT_TRUE(store_->GetValue(prefs::kPrivacySandboxApisEnabledV2, &value));
+ EXPECT_EQ(value->GetBool(), false);
}
TEST_F(CookieSettingsPolicyHandlerTest,
@@ -89,6 +92,7 @@ TEST_F(CookieSettingsPolicyHandlerTest,
SetThirdPartyCookiePolicy(false);
const base::Value* value;
EXPECT_FALSE(store_->GetValue(prefs::kPrivacySandboxApisEnabled, &value));
+ EXPECT_FALSE(store_->GetValue(prefs::kPrivacySandboxApisEnabledV2, &value));
}
TEST_F(CookieSettingsPolicyHandlerTest,
@@ -97,6 +101,8 @@ TEST_F(CookieSettingsPolicyHandlerTest,
const base::Value* value;
EXPECT_TRUE(store_->GetValue(prefs::kPrivacySandboxApisEnabled, &value));
EXPECT_EQ(value->GetBool(), false);
+ EXPECT_TRUE(store_->GetValue(prefs::kPrivacySandboxApisEnabledV2, &value));
+ EXPECT_EQ(value->GetBool(), false);
}
TEST_F(CookieSettingsPolicyHandlerTest,
@@ -104,6 +110,7 @@ TEST_F(CookieSettingsPolicyHandlerTest,
SetDefaultCookiePolicy(CONTENT_SETTING_ALLOW);
const base::Value* value;
EXPECT_FALSE(store_->GetValue(prefs::kPrivacySandboxApisEnabled, &value));
+ EXPECT_FALSE(store_->GetValue(prefs::kPrivacySandboxApisEnabledV2, &value));
}
} // namespace content_settings
diff --git a/chromium/components/content_settings/core/browser/cookie_settings_unittest.cc b/chromium/components/content_settings/core/browser/cookie_settings_unittest.cc
index 8686807066c..80ec5be9176 100644
--- a/chromium/components/content_settings/core/browser/cookie_settings_unittest.cc
+++ b/chromium/components/content_settings/core/browser/cookie_settings_unittest.cc
@@ -27,7 +27,7 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
#include "components/content_settings/core/common/features.h"
#else
#include "third_party/blink/public/common/features.h"
@@ -86,7 +86,7 @@ class CookieSettingsTest : public testing::Test {
kHttpsSubdomainSite("https://www.example.com"),
kHttpsSite8080("https://example.com:8080"),
kAllHttpsSitesPattern(ContentSettingsPattern::FromString("https://*")) {
-#ifdef OS_IOS
+#if BUILDFLAG(IS_IOS)
feature_list_.InitAndEnableFeature(kImprovedCookieControls);
#else
feature_list_.Init();
@@ -215,7 +215,7 @@ TEST_F(CookieSettingsTest, CookiesControlsEnabledForIncognito) {
kBlockedSite, kFirstPartySite));
}
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
// Test fixture with ImprovedCookieControls disabled.
class ImprovedCookieControlsDisabledCookieSettingsTest
: public CookieSettingsTest {
@@ -447,7 +447,7 @@ TEST_F(CookieSettingsTest, CookiesBlockEverythingExceptAllowed) {
EXPECT_FALSE(cookie_settings_->IsCookieSessionOnly(kAllowedSite));
}
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
TEST_F(CookieSettingsTest, GetCookieSettingAllowedTelemetry) {
const GURL top_level_url = GURL(kFirstPartySite);
const GURL url = GURL(kAllowedSite);
diff --git a/chromium/components/content_settings/core/browser/host_content_settings_map.cc b/chromium/components/content_settings/core/browser/host_content_settings_map.cc
index 3d9c1d68e8a..ffe15b025e0 100644
--- a/chromium/components/content_settings/core/browser/host_content_settings_map.cc
+++ b/chromium/components/content_settings/core/browser/host_content_settings_map.cc
@@ -110,9 +110,9 @@ bool SchemeCanBeAllowlisted(const std::string& scheme) {
// Handles inheritance of settings from the regular profile into the incognito
// profile.
-std::unique_ptr<base::Value> ProcessIncognitoInheritanceBehavior(
+base::Value ProcessIncognitoInheritanceBehavior(
ContentSettingsType content_type,
- std::unique_ptr<base::Value> value) {
+ base::Value value) {
// Website setting inheritance can be completely disallowed.
const WebsiteSettingsInfo* website_settings_info =
content_settings::WebsiteSettingsRegistry::GetInstance()->Get(
@@ -120,7 +120,7 @@ std::unique_ptr<base::Value> ProcessIncognitoInheritanceBehavior(
if (website_settings_info &&
website_settings_info->incognito_behavior() ==
WebsiteSettingsInfo::DONT_INHERIT_IN_INCOGNITO) {
- return nullptr;
+ return base::Value();
}
// Content setting inheritance can be for settings, that are more permissive
@@ -135,10 +135,10 @@ std::unique_ptr<base::Value> ProcessIncognitoInheritanceBehavior(
case ContentSettingsInfo::INHERIT_IN_INCOGNITO:
return value;
case ContentSettingsInfo::INHERIT_IF_LESS_PERMISSIVE:
- ContentSetting setting =
- content_settings::ValueToContentSetting(value.get());
- const base::Value* initial_value = content_settings_info
- ->website_settings_info()->initial_default_value();
+ ContentSetting setting = content_settings::ValueToContentSetting(value);
+ const base::Value& initial_value =
+ content_settings_info->website_settings_info()
+ ->initial_default_value();
ContentSetting initial_setting =
content_settings::ValueToContentSetting(initial_value);
if (content_settings::IsMorePermissive(setting, initial_setting))
@@ -322,7 +322,7 @@ ContentSetting HostContentSettingsMap::GetDefaultContentSettingFromProvider(
content_settings::Rule rule = rule_iterator->Next();
if (rule.primary_pattern == wildcard &&
rule.secondary_pattern == wildcard) {
- return content_settings::ValueToContentSetting(&rule.value);
+ return content_settings::ValueToContentSetting(rule.value);
}
}
}
@@ -346,8 +346,7 @@ ContentSetting HostContentSettingsMap::GetDefaultContentSettingInternal(
default_setting = content_settings::ValueToContentSetting(
ProcessIncognitoInheritanceBehavior(
content_type,
- content_settings::ContentSettingToValue(default_setting))
- .get());
+ content_settings::ContentSettingToValue(default_setting)));
}
if (default_setting != CONTENT_SETTING_DEFAULT) {
*provider_type = provider_pair.first;
@@ -375,9 +374,9 @@ ContentSetting HostContentSettingsMap::GetContentSetting(
ContentSettingsType content_type) const {
DCHECK(content_settings::ContentSettingsRegistry::GetInstance()->Get(
content_type));
- std::unique_ptr<base::Value> value =
+ const base::Value value =
GetWebsiteSetting(primary_url, secondary_url, content_type, nullptr);
- return content_settings::ValueToContentSetting(value.get());
+ return content_settings::ValueToContentSetting(value);
}
ContentSetting HostContentSettingsMap::GetUserModifiableContentSetting(
@@ -386,10 +385,10 @@ ContentSetting HostContentSettingsMap::GetUserModifiableContentSetting(
ContentSettingsType content_type) const {
DCHECK(content_settings::ContentSettingsRegistry::GetInstance()->Get(
content_type));
- std::unique_ptr<base::Value> value =
+ const base::Value value =
GetWebsiteSettingInternal(primary_url, secondary_url, content_type,
kFirstUserModifiableProvider, nullptr);
- return content_settings::ValueToContentSetting(value.get());
+ return content_settings::ValueToContentSetting(value);
}
void HostContentSettingsMap::GetSettingsForOneType(
@@ -415,13 +414,13 @@ void HostContentSettingsMap::GetSettingsForOneType(
void HostContentSettingsMap::SetDefaultContentSetting(
ContentSettingsType content_type,
ContentSetting setting) {
- std::unique_ptr<base::Value> value;
+ base::Value value;
// A value of CONTENT_SETTING_DEFAULT implies deleting the content setting.
if (setting != CONTENT_SETTING_DEFAULT) {
DCHECK(content_settings::ContentSettingsRegistry::GetInstance()
->Get(content_type)
->IsDefaultSettingValid(setting));
- value = std::make_unique<base::Value>(setting);
+ value = base::Value(setting);
}
SetWebsiteSettingCustomScope(ContentSettingsPattern::Wildcard(),
ContentSettingsPattern::Wildcard(), content_type,
@@ -432,7 +431,7 @@ void HostContentSettingsMap::SetWebsiteSettingDefaultScope(
const GURL& primary_url,
const GURL& secondary_url,
ContentSettingsType content_type,
- std::unique_ptr<base::Value> value,
+ base::Value value,
const content_settings::ContentSettingConstraints& constraints) {
content_settings::PatternPair patterns = GetPatternsForContentSettingsType(
primary_url, secondary_url, content_type);
@@ -449,21 +448,30 @@ void HostContentSettingsMap::SetWebsiteSettingCustomScope(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type,
- std::unique_ptr<base::Value> value,
+ base::Value value,
const content_settings::ContentSettingConstraints& constraints) {
DCHECK(IsSecondaryPatternAllowed(primary_pattern, secondary_pattern,
- content_type, value.get()));
+ content_type, value));
// TODO(crbug.com/731126): Verify that assumptions for notification content
// settings are met.
UsedContentSettingsProviders();
+#if DCHECK_IS_ON()
+ base::Value clone = value.Clone();
+#endif
for (const auto& provider_pair : content_settings_providers_) {
+ // The std::move(value) here just turns the value into an r-value reference.
+ // It doesn't actually move the value yet. The provider can decide to accept
+ // the value. If successful then ownership is passed to the provider.
if (provider_pair.second->SetWebsiteSetting(
primary_pattern, secondary_pattern, content_type, std::move(value),
constraints)) {
- // If successful then ownership is passed to the provider.
return;
}
+ // Ensure that the value is unmodified until accepted by a provider.
+#if DCHECK_IS_ON()
+ DCHECK_EQ(value, clone);
+#endif
}
NOTREACHED();
}
@@ -514,8 +522,8 @@ content_settings::PatternPair HostContentSettingsMap::GetNarrowestPatterns (
// the existing rule is more specific, than change the existing rule instead
// of creating a new rule that would be hidden behind the existing rule.
content_settings::SettingInfo info;
- std::unique_ptr<base::Value> v = GetWebsiteSettingInternal(
- primary_url, secondary_url, type, kFirstProvider, &info);
+ GetWebsiteSettingInternal(primary_url, secondary_url, type, kFirstProvider,
+ &info);
if (info.source != content_settings::SETTING_SOURCE_USER) {
// Return an invalid pattern if the current setting is not a user setting
// and thus can't be changed.
@@ -550,13 +558,13 @@ void HostContentSettingsMap::SetContentSettingCustomScope(
DCHECK(content_settings::ContentSettingsRegistry::GetInstance()->Get(
content_type));
- std::unique_ptr<base::Value> value;
+ base::Value value;
// A value of CONTENT_SETTING_DEFAULT implies deleting the content setting.
if (setting != CONTENT_SETTING_DEFAULT) {
DCHECK(content_settings::ContentSettingsRegistry::GetInstance()
->Get(content_type)
->IsSettingValid(setting));
- value = std::make_unique<base::Value>(setting);
+ value = base::Value(setting);
}
SetWebsiteSettingCustomScope(primary_pattern, secondary_pattern, content_type,
std::move(value), constraints);
@@ -734,7 +742,7 @@ void HostContentSettingsMap::ClearSettingsForOneTypeWithPredicate(
(last_modified < end_time || end_time.is_null())) {
provider->SetWebsiteSetting(setting.primary_pattern,
setting.secondary_pattern, content_type,
- nullptr, {});
+ base::Value(), {});
}
}
}
@@ -795,11 +803,10 @@ void HostContentSettingsMap::AddSettingsForOneType(
// Normal rules applied to incognito profiles are subject to inheritance
// settings.
if (!incognito && is_off_the_record_) {
- std::unique_ptr<base::Value> inherit_value =
- ProcessIncognitoInheritanceBehavior(
- content_type, base::Value::ToUniquePtrValue(std::move(value)));
- if (inherit_value)
- value = std::move(*inherit_value);
+ base::Value inherit_value =
+ ProcessIncognitoInheritanceBehavior(content_type, std::move(value));
+ if (!inherit_value.is_none())
+ value = std::move(inherit_value);
else
continue;
}
@@ -820,12 +827,11 @@ void HostContentSettingsMap::UsedContentSettingsProviders() const {
#endif
}
-std::unique_ptr<base::Value> HostContentSettingsMap::GetWebsiteSetting(
+base::Value HostContentSettingsMap::GetWebsiteSetting(
const GURL& primary_url,
const GURL& secondary_url,
ContentSettingsType content_type,
content_settings::SettingInfo* info) const {
-
// Check if the requested setting is allowlisted.
// TODO(raymes): Move this into GetContentSetting. This has nothing to do with
// website settings
@@ -843,7 +849,7 @@ std::unique_ptr<base::Value> HostContentSettingsMap::GetWebsiteSetting(
info->primary_pattern = ContentSettingsPattern::Wildcard();
info->secondary_pattern = ContentSettingsPattern::Wildcard();
}
- return std::make_unique<base::Value>(CONTENT_SETTING_ALLOW);
+ return base::Value(CONTENT_SETTING_ALLOW);
}
}
}
@@ -876,7 +882,7 @@ HostContentSettingsMap::GetSettingSourceFromProviderName(
return content_settings::SETTING_SOURCE_NONE;
}
-std::unique_ptr<base::Value> HostContentSettingsMap::GetWebsiteSettingInternal(
+base::Value HostContentSettingsMap::GetWebsiteSettingInternal(
const GURL& primary_url,
const GURL& secondary_url,
ContentSettingsType content_type,
@@ -896,10 +902,10 @@ std::unique_ptr<base::Value> HostContentSettingsMap::GetWebsiteSettingInternal(
// precedence.
auto it = content_settings_providers_.lower_bound(first_provider_to_search);
for (; it != content_settings_providers_.end(); ++it) {
- std::unique_ptr<base::Value> value = GetContentSettingValueAndPatterns(
+ base::Value value = GetContentSettingValueAndPatterns(
it->second.get(), primary_url, secondary_url, content_type,
is_off_the_record_, primary_pattern, secondary_pattern, session_model);
- if (value) {
+ if (!value.is_none()) {
if (info)
info->source = kProviderNamesSourceMap[it->first].provider_source;
return value;
@@ -911,12 +917,11 @@ std::unique_ptr<base::Value> HostContentSettingsMap::GetWebsiteSettingInternal(
info->primary_pattern = ContentSettingsPattern();
info->secondary_pattern = ContentSettingsPattern();
}
- return nullptr;
+ return base::Value();
}
// static
-std::unique_ptr<base::Value>
-HostContentSettingsMap::GetContentSettingValueAndPatterns(
+base::Value HostContentSettingsMap::GetContentSettingValueAndPatterns(
const content_settings::ProviderInterface* provider,
const GURL& primary_url,
const GURL& secondary_url,
@@ -931,26 +936,26 @@ HostContentSettingsMap::GetContentSettingValueAndPatterns(
// normal mode.
std::unique_ptr<content_settings::RuleIterator> incognito_rule_iterator(
provider->GetRuleIterator(content_type, true /* incognito */));
- std::unique_ptr<base::Value> value = GetContentSettingValueAndPatterns(
+ base::Value value = GetContentSettingValueAndPatterns(
incognito_rule_iterator.get(), primary_url, secondary_url,
primary_pattern, secondary_pattern, session_model);
- if (value)
+ if (!value.is_none())
return value;
}
// No settings from the incognito; use the normal mode.
std::unique_ptr<content_settings::RuleIterator> rule_iterator(
provider->GetRuleIterator(content_type, false /* incognito */));
- std::unique_ptr<base::Value> value = GetContentSettingValueAndPatterns(
+ base::Value value = GetContentSettingValueAndPatterns(
rule_iterator.get(), primary_url, secondary_url, primary_pattern,
secondary_pattern, session_model);
- if (value && include_incognito)
+ if (!value.is_none() && include_incognito) {
value = ProcessIncognitoInheritanceBehavior(content_type, std::move(value));
+ }
return value;
}
// static
-std::unique_ptr<base::Value>
-HostContentSettingsMap::GetContentSettingValueAndPatterns(
+base::Value HostContentSettingsMap::GetContentSettingValueAndPatterns(
content_settings::RuleIterator* rule_iterator,
const GURL& primary_url,
const GURL& secondary_url,
@@ -970,11 +975,11 @@ HostContentSettingsMap::GetContentSettingValueAndPatterns(
*secondary_pattern = rule.secondary_pattern;
if (session_model)
*session_model = rule.session_model;
- return base::Value::ToUniquePtrValue(rule.value.Clone());
+ return rule.value.Clone();
}
}
}
- return nullptr;
+ return base::Value();
}
void HostContentSettingsMap::
@@ -1050,7 +1055,7 @@ bool HostContentSettingsMap::IsSecondaryPatternAllowed(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type,
- base::Value* value) {
+ const base::Value& value) {
// A secondary pattern is normally only allowed if the content type supports
// secondary patterns. One exception is made when deleting content settings
// (aka setting them to CONTENT_SETTING_DEFAULT).
diff --git a/chromium/components/content_settings/core/browser/host_content_settings_map.h b/chromium/components/content_settings/core/browser/host_content_settings_map.h
index c49da645303..b0fabd75aad 100644
--- a/chromium/components/content_settings/core/browser/host_content_settings_map.h
+++ b/chromium/components/content_settings/core/browser/host_content_settings_map.h
@@ -137,15 +137,14 @@ class HostContentSettingsMap : public content_settings::Observer,
// allowlisted. For allowlisted schemes the |source| field of |info| is set
// the |SETTING_SOURCE_ALLOWLIST| and the |primary_pattern| and
// |secondary_pattern| are set to a wildcard pattern. If there is no content
- // setting, NULL is returned and the |source| field of |info| is set to
- // |SETTING_SOURCE_NONE|. The pattern fields of |info| are set to empty
+ // setting, a NONE-type value is returned and the |source| field of |info| is
+ // set to |SETTING_SOURCE_NONE|. The pattern fields of |info| are set to empty
// patterns.
// May be called on any thread.
- std::unique_ptr<base::Value> GetWebsiteSetting(
- const GURL& primary_url,
- const GURL& secondary_url,
- ContentSettingsType content_type,
- content_settings::SettingInfo* info) const;
+ base::Value GetWebsiteSetting(const GURL& primary_url,
+ const GURL& secondary_url,
+ ContentSettingsType content_type,
+ content_settings::SettingInfo* info) const;
// For a given content type, returns all patterns with a non-default setting,
// mapped to their actual settings, in the precedence order of the rules.
@@ -212,7 +211,8 @@ class HostContentSettingsMap : public content_settings::Observer,
// Sets the |value| for the default scope of the url that is appropriate for
// the given |content_type| applying any provided |constraints|. Setting the
- // value to null removes the default pattern pair for this content type.
+ // value to NONE (base::Value()) removes the default pattern pair for this
+ // content type.
//
// Internally this will call SetWebsiteSettingCustomScope() with the default
// scope patterns for the given |content_type|. Developers will generally want
@@ -222,18 +222,18 @@ class HostContentSettingsMap : public content_settings::Observer,
const GURL& requesting_url,
const GURL& top_level_url,
ContentSettingsType content_type,
- std::unique_ptr<base::Value> value,
+ base::Value value,
const content_settings::ContentSettingConstraints& constraints = {});
// Sets a rule to apply the |value| for all sites matching |pattern|,
// |content_type| applying any provided |constraints|. Setting the value to
- // null removes the given pattern pair. Unless adding a custom-scoped setting,
+ // NONE removes the given pattern pair. Unless adding a custom-scoped setting,
// most developers will want to use SetWebsiteSettingDefaultScope() instead.
void SetWebsiteSettingCustomScope(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type,
- std::unique_ptr<base::Value> value,
+ base::Value value,
const content_settings::ContentSettingConstraints& constraints = {});
// Check if a call to SetNarrowestContentSetting would succeed or if it would
@@ -378,7 +378,7 @@ class HostContentSettingsMap : public content_settings::Observer,
// Returns the single content setting |value| with a toggle for if it
// takes the global on/off switch into account.
- std::unique_ptr<base::Value> GetWebsiteSettingInternal(
+ base::Value GetWebsiteSettingInternal(
const GURL& primary_url,
const GURL& secondary_url,
ContentSettingsType content_type,
@@ -390,7 +390,7 @@ class HostContentSettingsMap : public content_settings::Observer,
const GURL& secondary_url,
ContentSettingsType type) const;
- static std::unique_ptr<base::Value> GetContentSettingValueAndPatterns(
+ static base::Value GetContentSettingValueAndPatterns(
const content_settings::ProviderInterface* provider,
const GURL& primary_url,
const GURL& secondary_url,
@@ -400,7 +400,7 @@ class HostContentSettingsMap : public content_settings::Observer,
ContentSettingsPattern* secondary_pattern,
content_settings::SessionModel* session_model);
- static std::unique_ptr<base::Value> GetContentSettingValueAndPatterns(
+ static base::Value GetContentSettingValueAndPatterns(
content_settings::RuleIterator* rule_iterator,
const GURL& primary_url,
const GURL& secondary_url,
@@ -425,7 +425,7 @@ class HostContentSettingsMap : public content_settings::Observer,
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type,
- base::Value* value);
+ const base::Value& value);
#ifndef NDEBUG
// This starts as the thread ID of the thread that constructs this
diff --git a/chromium/components/content_settings/core/browser/uma_util.cc b/chromium/components/content_settings/core/browser/uma_util.cc
deleted file mode 100644
index 66d13f7cff8..00000000000
--- a/chromium/components/content_settings/core/browser/uma_util.cc
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright 2015 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.
-
-#include "components/content_settings/core/browser/uma_util.h"
-
-#include <stddef.h>
-
-#include "base/check_op.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/notreached.h"
-
-namespace content_settings {
-
-void LogWebSiteSettingsPermissionChange(ContentSettingsType type,
- ContentSetting setting) {
- size_t num_values;
- int histogram_value = ContentSettingTypeToHistogramValue(type, &num_values);
- UMA_HISTOGRAM_EXACT_LINEAR("WebsiteSettings.Menu.PermissionChanged",
- histogram_value, num_values);
-
- if (setting == ContentSetting::CONTENT_SETTING_ALLOW) {
- UMA_HISTOGRAM_EXACT_LINEAR("WebsiteSettings.Menu.PermissionChanged.Allowed",
- histogram_value, num_values);
- } else if (setting == ContentSetting::CONTENT_SETTING_BLOCK) {
- UMA_HISTOGRAM_EXACT_LINEAR("WebsiteSettings.Menu.PermissionChanged.Blocked",
- histogram_value, num_values);
- } else if (setting == ContentSetting::CONTENT_SETTING_ASK) {
- UMA_HISTOGRAM_EXACT_LINEAR("WebsiteSettings.Menu.PermissionChanged.Ask",
- histogram_value, num_values);
- } else if (setting == ContentSetting::CONTENT_SETTING_DEFAULT) {
- UMA_HISTOGRAM_EXACT_LINEAR("WebsiteSettings.Menu.PermissionChanged.Reset",
- histogram_value, num_values);
- } else if (setting == ContentSetting::CONTENT_SETTING_SESSION_ONLY) {
- DCHECK_EQ(ContentSettingsType::COOKIES, type);
- UMA_HISTOGRAM_EXACT_LINEAR(
- "WebsiteSettings.Menu.PermissionChanged.SessionOnly", histogram_value,
- num_values);
- } else {
- NOTREACHED() << "Requested to log permission change "
- << static_cast<int32_t>(type) << " to " << setting;
- }
-}
-
-} // namespace content_settings
diff --git a/chromium/components/content_settings/core/browser/uma_util.h b/chromium/components/content_settings/core/browser/uma_util.h
deleted file mode 100644
index 0803c0616a4..00000000000
--- a/chromium/components/content_settings/core/browser/uma_util.h
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2015 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.
-
-#ifndef COMPONENTS_CONTENT_SETTINGS_CORE_BROWSER_UMA_UTIL_H_
-#define COMPONENTS_CONTENT_SETTINGS_CORE_BROWSER_UMA_UTIL_H_
-
-#include "components/content_settings/core/common/content_settings.h"
-
-namespace content_settings {
-
-void LogWebSiteSettingsPermissionChange(ContentSettingsType type,
- ContentSetting setting);
-} // namespace content_settings
-
-#endif // COMPONENTS_CONTENT_SETTINGS_CORE_BROWSER_UMA_UTIL_H_
diff --git a/chromium/components/content_settings/core/browser/website_settings_info.cc b/chromium/components/content_settings/core/browser/website_settings_info.cc
index 1a0ae7123eb..f5cba1dc30b 100644
--- a/chromium/components/content_settings/core/browser/website_settings_info.cc
+++ b/chromium/components/content_settings/core/browser/website_settings_info.cc
@@ -27,14 +27,13 @@ std::string GetPreferenceName(const std::string& name, const char* prefix) {
namespace content_settings {
-WebsiteSettingsInfo::WebsiteSettingsInfo(
- ContentSettingsType type,
- const std::string& name,
- std::unique_ptr<base::Value> initial_default_value,
- SyncStatus sync_status,
- LossyStatus lossy_status,
- ScopingType scoping_type,
- IncognitoBehavior incognito_behavior)
+WebsiteSettingsInfo::WebsiteSettingsInfo(ContentSettingsType type,
+ const std::string& name,
+ base::Value initial_default_value,
+ SyncStatus sync_status,
+ LossyStatus lossy_status,
+ ScopingType scoping_type,
+ IncognitoBehavior incognito_behavior)
: type_(type),
name_(name),
pref_name_(GetPreferenceName(name, kPrefPrefix)),
@@ -44,13 +43,14 @@ WebsiteSettingsInfo::WebsiteSettingsInfo(
lossy_status_(lossy_status),
scoping_type_(scoping_type),
incognito_behavior_(incognito_behavior) {
- // For legacy reasons the default value is currently restricted to be an int.
+ // For legacy reasons the default value is currently restricted to be an int
+ // or none.
// TODO(raymes): We should migrate the underlying pref to be a dictionary
// rather than an int.
- DCHECK(!initial_default_value_ || initial_default_value_->is_int());
+ DCHECK(initial_default_value_.is_none() || initial_default_value_.is_int());
}
-WebsiteSettingsInfo::~WebsiteSettingsInfo() {}
+WebsiteSettingsInfo::~WebsiteSettingsInfo() = default;
uint32_t WebsiteSettingsInfo::GetPrefRegistrationFlags() const {
uint32_t flags = PrefRegistry::NO_REGISTRATION_FLAGS;
diff --git a/chromium/components/content_settings/core/browser/website_settings_info.h b/chromium/components/content_settings/core/browser/website_settings_info.h
index 52e58be1f6f..858cdb7e537 100644
--- a/chromium/components/content_settings/core/browser/website_settings_info.h
+++ b/chromium/components/content_settings/core/browser/website_settings_info.h
@@ -10,12 +10,9 @@
#include <memory>
#include <string>
+#include "base/values.h"
#include "components/content_settings/core/common/content_settings_types.h"
-namespace base {
-class Value;
-} // namespace base
-
namespace content_settings {
// This class stores the properties related to a website setting.
@@ -68,7 +65,7 @@ class WebsiteSettingsInfo {
WebsiteSettingsInfo(ContentSettingsType type,
const std::string& name,
- std::unique_ptr<base::Value> initial_default_value,
+ base::Value initial_default_value,
SyncStatus sync_status,
LossyStatus lossy_status,
ScopingType scoping_type,
@@ -86,8 +83,8 @@ class WebsiteSettingsInfo {
const std::string& default_value_pref_name() const {
return default_value_pref_name_;
}
- const base::Value* initial_default_value() const {
- return initial_default_value_.get();
+ const base::Value& initial_default_value() const {
+ return initial_default_value_;
}
uint32_t GetPrefRegistrationFlags() const;
@@ -103,7 +100,7 @@ class WebsiteSettingsInfo {
const std::string pref_name_;
const std::string default_value_pref_name_;
- const std::unique_ptr<base::Value> initial_default_value_;
+ const base::Value initial_default_value_;
const SyncStatus sync_status_;
const LossyStatus lossy_status_;
const ScopingType scoping_type_;
diff --git a/chromium/components/content_settings/core/browser/website_settings_registry.cc b/chromium/components/content_settings/core/browser/website_settings_registry.cc
index 99e460ee709..08daef2024a 100644
--- a/chromium/components/content_settings/core/browser/website_settings_registry.cc
+++ b/chromium/components/content_settings/core/browser/website_settings_registry.cc
@@ -30,7 +30,7 @@ WebsiteSettingsRegistry::WebsiteSettingsRegistry() {
Init();
}
-WebsiteSettingsRegistry::~WebsiteSettingsRegistry() {}
+WebsiteSettingsRegistry::~WebsiteSettingsRegistry() = default;
void WebsiteSettingsRegistry::ResetForTest() {
website_settings_info_.clear();
@@ -57,40 +57,39 @@ const WebsiteSettingsInfo* WebsiteSettingsRegistry::GetByName(
const WebsiteSettingsInfo* WebsiteSettingsRegistry::Register(
ContentSettingsType type,
const std::string& name,
- std::unique_ptr<base::Value> initial_default_value,
+ base::Value initial_default_value,
WebsiteSettingsInfo::SyncStatus sync_status,
WebsiteSettingsInfo::LossyStatus lossy_status,
WebsiteSettingsInfo::ScopingType scoping_type,
Platforms platform,
WebsiteSettingsInfo::IncognitoBehavior incognito_behavior) {
-
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
if (!(platform & PLATFORM_WINDOWS))
return nullptr;
-#elif defined(OS_LINUX)
+#elif BUILDFLAG(IS_LINUX)
if (!(platform & PLATFORM_LINUX))
return nullptr;
-#elif defined(OS_MAC)
+#elif BUILDFLAG(IS_MAC)
if (!(platform & PLATFORM_MAC))
return nullptr;
-#elif defined(OS_CHROMEOS)
+#elif BUILDFLAG(IS_CHROMEOS)
if (!(platform & PLATFORM_CHROMEOS))
return nullptr;
-#elif defined(OS_ANDROID)
+#elif BUILDFLAG(IS_ANDROID)
if (!(platform & PLATFORM_ANDROID))
return nullptr;
// Don't sync settings to mobile platforms. The UI is different to desktop and
// doesn't allow the settings to be managed in the same way. See
// crbug.com/642184.
sync_status = WebsiteSettingsInfo::UNSYNCABLE;
-#elif defined(OS_IOS)
+#elif BUILDFLAG(IS_IOS)
if (!(platform & PLATFORM_IOS))
return nullptr;
// Don't sync settings to mobile platforms. The UI is different to desktop and
// doesn't allow the settings to be managed in the same way. See
// crbug.com/642184.
sync_status = WebsiteSettingsInfo::UNSYNCABLE;
-#elif defined(OS_FUCHSIA)
+#elif BUILDFLAG(IS_FUCHSIA)
if (!(platform & PLATFORM_FUCHSIA))
return nullptr;
#else
@@ -122,60 +121,62 @@ void WebsiteSettingsRegistry::Init() {
// Website settings.
Register(ContentSettingsType::AUTO_SELECT_CERTIFICATE,
- "auto-select-certificate", nullptr, WebsiteSettingsInfo::UNSYNCABLE,
- WebsiteSettingsInfo::NOT_LOSSY,
+ "auto-select-certificate", base::Value(),
+ WebsiteSettingsInfo::UNSYNCABLE, WebsiteSettingsInfo::NOT_LOSSY,
WebsiteSettingsInfo::SINGLE_ORIGIN_WITH_EMBEDDED_EXCEPTIONS_SCOPE,
ALL_PLATFORMS, WebsiteSettingsInfo::INHERIT_IN_INCOGNITO);
- Register(
- ContentSettingsType::SSL_CERT_DECISIONS, "ssl-cert-decisions", nullptr,
- WebsiteSettingsInfo::UNSYNCABLE, WebsiteSettingsInfo::NOT_LOSSY,
- WebsiteSettingsInfo::SINGLE_ORIGIN_WITH_EMBEDDED_EXCEPTIONS_SCOPE,
- DESKTOP | PLATFORM_ANDROID, WebsiteSettingsInfo::INHERIT_IN_INCOGNITO);
- Register(ContentSettingsType::APP_BANNER, "app-banner", nullptr,
- WebsiteSettingsInfo::UNSYNCABLE, WebsiteSettingsInfo::LOSSY,
+ Register(ContentSettingsType::SSL_CERT_DECISIONS, "ssl-cert-decisions",
+ base::Value(), WebsiteSettingsInfo::UNSYNCABLE,
+ WebsiteSettingsInfo::NOT_LOSSY,
WebsiteSettingsInfo::SINGLE_ORIGIN_WITH_EMBEDDED_EXCEPTIONS_SCOPE,
DESKTOP | PLATFORM_ANDROID,
WebsiteSettingsInfo::INHERIT_IN_INCOGNITO);
- Register(ContentSettingsType::SITE_ENGAGEMENT, "site-engagement", nullptr,
+ Register(ContentSettingsType::APP_BANNER, "app-banner", base::Value(),
WebsiteSettingsInfo::UNSYNCABLE, WebsiteSettingsInfo::LOSSY,
WebsiteSettingsInfo::SINGLE_ORIGIN_WITH_EMBEDDED_EXCEPTIONS_SCOPE,
DESKTOP | PLATFORM_ANDROID,
WebsiteSettingsInfo::INHERIT_IN_INCOGNITO);
- Register(ContentSettingsType::USB_CHOOSER_DATA, "usb-chooser-data", nullptr,
- WebsiteSettingsInfo::UNSYNCABLE, WebsiteSettingsInfo::NOT_LOSSY,
- WebsiteSettingsInfo::SINGLE_ORIGIN_ONLY_SCOPE,
- DESKTOP | PLATFORM_ANDROID,
- WebsiteSettingsInfo::DONT_INHERIT_IN_INCOGNITO);
+ Register(
+ ContentSettingsType::SITE_ENGAGEMENT, "site-engagement", base::Value(),
+ WebsiteSettingsInfo::UNSYNCABLE, WebsiteSettingsInfo::LOSSY,
+ WebsiteSettingsInfo::SINGLE_ORIGIN_WITH_EMBEDDED_EXCEPTIONS_SCOPE,
+ DESKTOP | PLATFORM_ANDROID, WebsiteSettingsInfo::INHERIT_IN_INCOGNITO);
+ Register(
+ ContentSettingsType::USB_CHOOSER_DATA, "usb-chooser-data", base::Value(),
+ WebsiteSettingsInfo::UNSYNCABLE, WebsiteSettingsInfo::NOT_LOSSY,
+ WebsiteSettingsInfo::SINGLE_ORIGIN_ONLY_SCOPE, DESKTOP | PLATFORM_ANDROID,
+ WebsiteSettingsInfo::DONT_INHERIT_IN_INCOGNITO);
Register(ContentSettingsType::IMPORTANT_SITE_INFO, "important-site-info",
- nullptr, WebsiteSettingsInfo::UNSYNCABLE, WebsiteSettingsInfo::LOSSY,
+ base::Value(), WebsiteSettingsInfo::UNSYNCABLE,
+ WebsiteSettingsInfo::LOSSY,
WebsiteSettingsInfo::SINGLE_ORIGIN_WITH_EMBEDDED_EXCEPTIONS_SCOPE,
DESKTOP | PLATFORM_ANDROID,
WebsiteSettingsInfo::INHERIT_IN_INCOGNITO);
Register(ContentSettingsType::PERMISSION_AUTOBLOCKER_DATA,
- "permission-autoblocking-data", nullptr,
+ "permission-autoblocking-data", base::Value(),
WebsiteSettingsInfo::UNSYNCABLE, WebsiteSettingsInfo::NOT_LOSSY,
WebsiteSettingsInfo::SINGLE_ORIGIN_WITH_EMBEDDED_EXCEPTIONS_SCOPE,
DESKTOP | PLATFORM_ANDROID,
WebsiteSettingsInfo::INHERIT_IN_INCOGNITO);
Register(ContentSettingsType::PASSWORD_PROTECTION, "password-protection",
- nullptr, WebsiteSettingsInfo::UNSYNCABLE,
+ base::Value(), WebsiteSettingsInfo::UNSYNCABLE,
WebsiteSettingsInfo::NOT_LOSSY,
WebsiteSettingsInfo::SINGLE_ORIGIN_WITH_EMBEDDED_EXCEPTIONS_SCOPE,
ALL_PLATFORMS, WebsiteSettingsInfo::INHERIT_IN_INCOGNITO);
// Set when an origin is activated for subresource filtering and the
// associated UI is shown to the user. Cleared when a site is de-activated or
// the first URL matching the origin is removed from history.
- Register(ContentSettingsType::ADS_DATA, "subresource-filter-data", nullptr,
- WebsiteSettingsInfo::UNSYNCABLE, WebsiteSettingsInfo::NOT_LOSSY,
- WebsiteSettingsInfo::SINGLE_ORIGIN_WITH_EMBEDDED_EXCEPTIONS_SCOPE,
- DESKTOP | PLATFORM_ANDROID,
- WebsiteSettingsInfo::INHERIT_IN_INCOGNITO);
- Register(ContentSettingsType::MEDIA_ENGAGEMENT, "media-engagement", nullptr,
- WebsiteSettingsInfo::UNSYNCABLE, WebsiteSettingsInfo::LOSSY,
- WebsiteSettingsInfo::SINGLE_ORIGIN_WITH_EMBEDDED_EXCEPTIONS_SCOPE,
- DESKTOP | PLATFORM_ANDROID,
- WebsiteSettingsInfo::INHERIT_IN_INCOGNITO);
- Register(ContentSettingsType::CLIENT_HINTS, "client-hints", nullptr,
+ Register(
+ ContentSettingsType::ADS_DATA, "subresource-filter-data", base::Value(),
+ WebsiteSettingsInfo::UNSYNCABLE, WebsiteSettingsInfo::NOT_LOSSY,
+ WebsiteSettingsInfo::SINGLE_ORIGIN_WITH_EMBEDDED_EXCEPTIONS_SCOPE,
+ DESKTOP | PLATFORM_ANDROID, WebsiteSettingsInfo::INHERIT_IN_INCOGNITO);
+ Register(
+ ContentSettingsType::MEDIA_ENGAGEMENT, "media-engagement", base::Value(),
+ WebsiteSettingsInfo::UNSYNCABLE, WebsiteSettingsInfo::LOSSY,
+ WebsiteSettingsInfo::SINGLE_ORIGIN_WITH_EMBEDDED_EXCEPTIONS_SCOPE,
+ DESKTOP | PLATFORM_ANDROID, WebsiteSettingsInfo::INHERIT_IN_INCOGNITO);
+ Register(ContentSettingsType::CLIENT_HINTS, "client-hints", base::Value(),
WebsiteSettingsInfo::UNSYNCABLE, WebsiteSettingsInfo::LOSSY,
WebsiteSettingsInfo::SINGLE_ORIGIN_WITH_EMBEDDED_EXCEPTIONS_SCOPE,
DESKTOP | PLATFORM_ANDROID,
@@ -183,73 +184,75 @@ void WebsiteSettingsRegistry::Init() {
// Set to keep track of dismissals without user's interaction for intent
// picker UI.
Register(ContentSettingsType::INTENT_PICKER_DISPLAY,
- "intent-picker-auto-display", nullptr,
+ "intent-picker-auto-display", base::Value(),
WebsiteSettingsInfo::UNSYNCABLE, WebsiteSettingsInfo::NOT_LOSSY,
WebsiteSettingsInfo::SINGLE_ORIGIN_WITH_EMBEDDED_EXCEPTIONS_SCOPE,
DESKTOP, WebsiteSettingsInfo::DONT_INHERIT_IN_INCOGNITO);
Register(ContentSettingsType::SERIAL_CHOOSER_DATA, "serial-chooser-data",
- nullptr, WebsiteSettingsInfo::UNSYNCABLE,
+ base::Value(), WebsiteSettingsInfo::UNSYNCABLE,
WebsiteSettingsInfo::NOT_LOSSY,
WebsiteSettingsInfo::SINGLE_ORIGIN_ONLY_SCOPE, DESKTOP,
WebsiteSettingsInfo::DONT_INHERIT_IN_INCOGNITO);
- Register(ContentSettingsType::HID_CHOOSER_DATA, "hid-chooser-data", nullptr,
- WebsiteSettingsInfo::UNSYNCABLE, WebsiteSettingsInfo::NOT_LOSSY,
+ Register(ContentSettingsType::HID_CHOOSER_DATA, "hid-chooser-data",
+ base::Value(), WebsiteSettingsInfo::UNSYNCABLE,
+ WebsiteSettingsInfo::NOT_LOSSY,
WebsiteSettingsInfo::SINGLE_ORIGIN_ONLY_SCOPE, DESKTOP,
WebsiteSettingsInfo::DONT_INHERIT_IN_INCOGNITO);
Register(ContentSettingsType::INSTALLED_WEB_APP_METADATA,
- "installed-web-app-metadata", nullptr,
+ "installed-web-app-metadata", base::Value(),
WebsiteSettingsInfo::UNSYNCABLE, WebsiteSettingsInfo::LOSSY,
WebsiteSettingsInfo::SINGLE_ORIGIN_ONLY_SCOPE, DESKTOP,
WebsiteSettingsInfo::DONT_INHERIT_IN_INCOGNITO);
Register(
ContentSettingsType::BLUETOOTH_CHOOSER_DATA, "bluetooth-chooser-data",
- /*initial_default_value=*/nullptr, WebsiteSettingsInfo::UNSYNCABLE,
+ /*initial_default_value=*/base::Value(), WebsiteSettingsInfo::UNSYNCABLE,
WebsiteSettingsInfo::NOT_LOSSY,
WebsiteSettingsInfo::SINGLE_ORIGIN_ONLY_SCOPE, DESKTOP | PLATFORM_ANDROID,
WebsiteSettingsInfo::DONT_INHERIT_IN_INCOGNITO);
Register(ContentSettingsType::SAFE_BROWSING_URL_CHECK_DATA,
- "safe-browsing-url-check-data", nullptr,
+ "safe-browsing-url-check-data", base::Value(),
WebsiteSettingsInfo::UNSYNCABLE, WebsiteSettingsInfo::LOSSY,
WebsiteSettingsInfo::SINGLE_ORIGIN_ONLY_SCOPE, ALL_PLATFORMS,
WebsiteSettingsInfo::DONT_INHERIT_IN_INCOGNITO);
Register(ContentSettingsType::PERMISSION_AUTOREVOCATION_DATA,
- "permission-autorevocation-data", nullptr,
+ "permission-autorevocation-data", base::Value(),
WebsiteSettingsInfo::UNSYNCABLE, WebsiteSettingsInfo::NOT_LOSSY,
WebsiteSettingsInfo::SINGLE_ORIGIN_ONLY_SCOPE,
DESKTOP | PLATFORM_ANDROID,
WebsiteSettingsInfo::DONT_INHERIT_IN_INCOGNITO);
Register(ContentSettingsType::FILE_SYSTEM_ACCESS_CHOOSER_DATA,
- "file-system-access-chooser-data", nullptr,
+ "file-system-access-chooser-data", base::Value(),
WebsiteSettingsInfo::UNSYNCABLE, WebsiteSettingsInfo::NOT_LOSSY,
WebsiteSettingsInfo::SINGLE_ORIGIN_ONLY_SCOPE, DESKTOP,
WebsiteSettingsInfo::DONT_INHERIT_IN_INCOGNITO);
Register(ContentSettingsType::FILE_SYSTEM_LAST_PICKED_DIRECTORY,
- "file-system-last-picked-directory", nullptr,
+ "file-system-last-picked-directory", base::Value(),
WebsiteSettingsInfo::UNSYNCABLE, WebsiteSettingsInfo::NOT_LOSSY,
WebsiteSettingsInfo::SINGLE_ORIGIN_ONLY_SCOPE, DESKTOP,
WebsiteSettingsInfo::DONT_INHERIT_IN_INCOGNITO);
Register(ContentSettingsType::FEDERATED_IDENTITY_SHARING, "webid-share",
- nullptr, WebsiteSettingsInfo::UNSYNCABLE,
+ base::Value(), WebsiteSettingsInfo::UNSYNCABLE,
WebsiteSettingsInfo::NOT_LOSSY,
WebsiteSettingsInfo::SINGLE_ORIGIN_ONLY_SCOPE, ALL_PLATFORMS,
WebsiteSettingsInfo::DONT_INHERIT_IN_INCOGNITO);
Register(ContentSettingsType::FEDERATED_IDENTITY_REQUEST, "webid-request",
- nullptr, WebsiteSettingsInfo::UNSYNCABLE,
+ base::Value(), WebsiteSettingsInfo::UNSYNCABLE,
WebsiteSettingsInfo::NOT_LOSSY,
WebsiteSettingsInfo::SINGLE_ORIGIN_ONLY_SCOPE, ALL_PLATFORMS,
WebsiteSettingsInfo::DONT_INHERIT_IN_INCOGNITO);
- Register(ContentSettingsType::HTTP_ALLOWED, "http-allowed", nullptr,
+ Register(ContentSettingsType::HTTP_ALLOWED, "http-allowed", base::Value(),
WebsiteSettingsInfo::UNSYNCABLE, WebsiteSettingsInfo::NOT_LOSSY,
WebsiteSettingsInfo::SINGLE_ORIGIN_WITH_EMBEDDED_EXCEPTIONS_SCOPE,
DESKTOP | PLATFORM_ANDROID,
WebsiteSettingsInfo::INHERIT_IN_INCOGNITO);
- Register(ContentSettingsType::FORMFILL_METADATA, "formfill-metadata", nullptr,
- WebsiteSettingsInfo::UNSYNCABLE, WebsiteSettingsInfo::LOSSY,
+ Register(ContentSettingsType::FORMFILL_METADATA, "formfill-metadata",
+ base::Value(), WebsiteSettingsInfo::UNSYNCABLE,
+ WebsiteSettingsInfo::LOSSY,
WebsiteSettingsInfo::SINGLE_ORIGIN_ONLY_SCOPE, ALL_PLATFORMS,
WebsiteSettingsInfo::INHERIT_IN_INCOGNITO);
Register(ContentSettingsType::FEDERATED_IDENTITY_ACTIVE_SESSION,
- "webid-active-session", nullptr, WebsiteSettingsInfo::UNSYNCABLE,
- WebsiteSettingsInfo::NOT_LOSSY,
+ "webid-active-session", base::Value(),
+ WebsiteSettingsInfo::UNSYNCABLE, WebsiteSettingsInfo::NOT_LOSSY,
WebsiteSettingsInfo::SINGLE_ORIGIN_ONLY_SCOPE, ALL_PLATFORMS,
WebsiteSettingsInfo::DONT_INHERIT_IN_INCOGNITO);
}
diff --git a/chromium/components/content_settings/core/browser/website_settings_registry.h b/chromium/components/content_settings/core/browser/website_settings_registry.h
index 6805e291c19..cac992b45b1 100644
--- a/chromium/components/content_settings/core/browser/website_settings_registry.h
+++ b/chromium/components/content_settings/core/browser/website_settings_registry.h
@@ -71,7 +71,7 @@ class WebsiteSettingsRegistry {
const WebsiteSettingsInfo* Register(
ContentSettingsType type,
const std::string& name,
- std::unique_ptr<base::Value> initial_default_value,
+ base::Value initial_default_value,
WebsiteSettingsInfo::SyncStatus sync_status,
WebsiteSettingsInfo::LossyStatus lossy_status,
WebsiteSettingsInfo::ScopingType scoping_type,
diff --git a/chromium/components/content_settings/core/browser/website_settings_registry_unittest.cc b/chromium/components/content_settings/core/browser/website_settings_registry_unittest.cc
index 89200b97761..f0fa549ebf9 100644
--- a/chromium/components/content_settings/core/browser/website_settings_registry_unittest.cc
+++ b/chromium/components/content_settings/core/browser/website_settings_registry_unittest.cc
@@ -48,8 +48,8 @@ TEST_F(WebsiteSettingsRegistryTest, GetByName) {
info);
// Register a new setting.
- registry()->Register(static_cast<ContentSettingsType>(10), "test", nullptr,
- WebsiteSettingsInfo::UNSYNCABLE,
+ registry()->Register(static_cast<ContentSettingsType>(10), "test",
+ base::Value(), WebsiteSettingsInfo::UNSYNCABLE,
WebsiteSettingsInfo::LOSSY,
WebsiteSettingsInfo::SINGLE_ORIGIN_ONLY_SCOPE,
WebsiteSettingsRegistry::ALL_PLATFORMS,
@@ -62,7 +62,7 @@ TEST_F(WebsiteSettingsRegistryTest, GetByName) {
}
TEST_F(WebsiteSettingsRegistryTest, GetPlatformDependent) {
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
// App banner shouldn't be registered on iOS.
EXPECT_FALSE(registry()->Get(ContentSettingsType::APP_BANNER));
#else
@@ -83,25 +83,25 @@ TEST_F(WebsiteSettingsRegistryTest, Properties) {
info->pref_name());
EXPECT_EQ("profile.default_content_setting_values.auto_select_certificate",
info->default_value_pref_name());
- ASSERT_FALSE(info->initial_default_value());
+ ASSERT_TRUE(info->initial_default_value().is_none());
EXPECT_EQ(PrefRegistry::NO_REGISTRATION_FLAGS,
info->GetPrefRegistrationFlags());
// Register a new setting.
- registry()->Register(
- static_cast<ContentSettingsType>(10), "test",
- std::make_unique<base::Value>(999), WebsiteSettingsInfo::SYNCABLE,
- WebsiteSettingsInfo::LOSSY, WebsiteSettingsInfo::SINGLE_ORIGIN_ONLY_SCOPE,
- WebsiteSettingsRegistry::ALL_PLATFORMS,
- WebsiteSettingsInfo::INHERIT_IN_INCOGNITO);
+ registry()->Register(static_cast<ContentSettingsType>(10), "test",
+ base::Value(999), WebsiteSettingsInfo::SYNCABLE,
+ WebsiteSettingsInfo::LOSSY,
+ WebsiteSettingsInfo::SINGLE_ORIGIN_ONLY_SCOPE,
+ WebsiteSettingsRegistry::ALL_PLATFORMS,
+ WebsiteSettingsInfo::INHERIT_IN_INCOGNITO);
info = registry()->Get(static_cast<ContentSettingsType>(10));
ASSERT_TRUE(info);
EXPECT_EQ("profile.content_settings.exceptions.test", info->pref_name());
EXPECT_EQ("profile.default_content_setting_values.test",
info->default_value_pref_name());
- ASSERT_TRUE(info->initial_default_value()->is_int());
- EXPECT_EQ(999, info->initial_default_value()->GetInt());
-#if defined(OS_ANDROID) || defined(OS_IOS)
+ ASSERT_TRUE(info->initial_default_value().is_int());
+ EXPECT_EQ(999, info->initial_default_value().GetInt());
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
EXPECT_EQ(PrefRegistry::LOSSY_PREF, info->GetPrefRegistrationFlags());
#else
EXPECT_EQ(PrefRegistry::LOSSY_PREF |
@@ -115,12 +115,12 @@ TEST_F(WebsiteSettingsRegistryTest, Properties) {
}
TEST_F(WebsiteSettingsRegistryTest, Iteration) {
- registry()->Register(
- static_cast<ContentSettingsType>(10), "test",
- std::make_unique<base::Value>(999), WebsiteSettingsInfo::SYNCABLE,
- WebsiteSettingsInfo::LOSSY, WebsiteSettingsInfo::SINGLE_ORIGIN_ONLY_SCOPE,
- WebsiteSettingsRegistry::ALL_PLATFORMS,
- WebsiteSettingsInfo::INHERIT_IN_INCOGNITO);
+ registry()->Register(static_cast<ContentSettingsType>(10), "test",
+ base::Value(999), WebsiteSettingsInfo::SYNCABLE,
+ WebsiteSettingsInfo::LOSSY,
+ WebsiteSettingsInfo::SINGLE_ORIGIN_ONLY_SCOPE,
+ WebsiteSettingsRegistry::ALL_PLATFORMS,
+ WebsiteSettingsInfo::INHERIT_IN_INCOGNITO);
bool found = false;
for (const WebsiteSettingsInfo* info : *registry()) {
diff --git a/chromium/components/content_settings/core/common/content_settings.cc b/chromium/components/content_settings/core/common/content_settings.cc
index 9a9015cdf6b..2c152515fc9 100644
--- a/chromium/components/content_settings/core/common/content_settings.cc
+++ b/chromium/components/content_settings/core/common/content_settings.cc
@@ -175,7 +175,7 @@ ContentSettingPatternSource& ContentSettingPatternSource::operator=(
ContentSettingPatternSource::~ContentSettingPatternSource() {}
ContentSetting ContentSettingPatternSource::GetContentSetting() const {
- return content_settings::ValueToContentSetting(&setting_value);
+ return content_settings::ValueToContentSetting(setting_value);
}
bool ContentSettingPatternSource::IsExpired() const {
diff --git a/chromium/components/content_settings/core/common/content_settings_pattern.cc b/chromium/components/content_settings/core/common/content_settings_pattern.cc
index 96b39eeebf8..5f2730f5aef 100644
--- a/chromium/components/content_settings/core/common/content_settings_pattern.cc
+++ b/chromium/components/content_settings/core/common/content_settings_pattern.cc
@@ -367,8 +367,6 @@ operator=(PatternParts&& other) = default;
// - a.b.c.d (matches an exact IPv4 ip)
// - [a:b:c:d:e:f:g:h] (matches an exact IPv6 ip)
// - file:///tmp/test.html (a complete URL without a host)
-// Version 2 adds a resource identifier for plugins.
-// TODO(jochen): update once this feature is no longer behind a flag.
const int ContentSettingsPattern::kContentSettingsPatternVersion = 1;
// static
diff --git a/chromium/components/content_settings/core/common/content_settings_utils.cc b/chromium/components/content_settings/core/common/content_settings_utils.cc
index 45a3ee0d957..08b331267e1 100644
--- a/chromium/components/content_settings/core/common/content_settings_utils.cc
+++ b/chromium/components/content_settings/core/common/content_settings_utils.cc
@@ -15,33 +15,45 @@ namespace {
// Converts a |Value| to a |ContentSetting|. Returns true if |value| encodes
// a valid content setting, false otherwise. Note that |CONTENT_SETTING_DEFAULT|
// is encoded as a NULL value, so it is not allowed as an integer value.
-bool ParseContentSettingValue(const base::Value* value,
+bool ParseContentSettingValue(const base::Value& value,
ContentSetting* setting) {
- if (!value) {
+ if (value.is_none()) {
*setting = CONTENT_SETTING_DEFAULT;
return true;
}
- if (!value->is_int())
+ if (!value.is_int())
return false;
- *setting = IntToContentSetting(value->GetInt());
+ *setting = IntToContentSetting(value.GetInt());
return *setting != CONTENT_SETTING_DEFAULT;
}
} // namespace
-ContentSetting ValueToContentSetting(const base::Value* value) {
+ContentSetting ValueToContentSetting(const base::Value& value) {
ContentSetting setting = CONTENT_SETTING_DEFAULT;
bool valid = ParseContentSettingValue(value, &setting);
DCHECK(valid);
return setting;
}
-std::unique_ptr<base::Value> ContentSettingToValue(ContentSetting setting) {
+base::Value ContentSettingToValue(ContentSetting setting) {
if (setting <= CONTENT_SETTING_DEFAULT ||
setting >= CONTENT_SETTING_NUM_SETTINGS) {
- return nullptr;
+ return base::Value();
}
- return std::make_unique<base::Value>(setting);
+ return base::Value(setting);
+}
+
+std::unique_ptr<base::Value> ToNullableUniquePtrValue(base::Value value) {
+ if (value.is_none())
+ return nullptr;
+ return base::Value::ToUniquePtrValue(std::move(value));
+}
+
+base::Value FromNullableUniquePtrValue(std::unique_ptr<base::Value> value) {
+ if (!value)
+ return base::Value();
+ return base::Value::FromUniquePtrValue(std::move(value));
}
} // namespace content_settings
diff --git a/chromium/components/content_settings/core/common/content_settings_utils.h b/chromium/components/content_settings/core/common/content_settings_utils.h
index 640483d9338..af3f051a997 100644
--- a/chromium/components/content_settings/core/common/content_settings_utils.h
+++ b/chromium/components/content_settings/core/common/content_settings_utils.h
@@ -16,11 +16,18 @@ class Value;
namespace content_settings {
// Converts |value| to |ContentSetting|.
-ContentSetting ValueToContentSetting(const base::Value* value);
+ContentSetting ValueToContentSetting(const base::Value& value);
// Returns a base::Value representation of |setting| if |setting| is
-// a valid content setting. Otherwise, returns a nullptr.
-std::unique_ptr<base::Value> ContentSettingToValue(ContentSetting setting);
+// a valid content setting. Otherwise, returns an empty value.
+base::Value ContentSettingToValue(ContentSetting setting);
+
+// Adaptor for converting from the new way of base::Value to the old one.
+// Like base::Value::ToUniquePtrValue but converts NONE-type values to nullptr.
+std::unique_ptr<base::Value> ToNullableUniquePtrValue(base::Value value);
+// Adaptor for converting from the old way of base::Value to the new one.
+// Like base::Value::FromUniquePtrValue but converts nullptr to NONE-type value.
+base::Value FromNullableUniquePtrValue(std::unique_ptr<base::Value> value);
} // namespace content_settings
diff --git a/chromium/components/content_settings/core/common/cookie_settings_base.cc b/chromium/components/content_settings/core/common/cookie_settings_base.cc
index dba38072881..9c8c2433ca4 100644
--- a/chromium/components/content_settings/core/common/cookie_settings_base.cc
+++ b/chromium/components/content_settings/core/common/cookie_settings_base.cc
@@ -84,7 +84,7 @@ ContentSetting CookieSettingsBase::GetCookieSetting(
bool CookieSettingsBase::IsFullCookieAccessAllowed(
const GURL& url,
const GURL& first_party_url) const {
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
// IOS uses this method with an empty |first_party_url| but we don't have
// content settings on IOS, so it does not matter.
DCHECK(!first_party_url.is_empty() || url.is_empty()) << url;
diff --git a/chromium/components/content_settings/core/common/features.cc b/chromium/components/content_settings/core/common/features.cc
index 620fcd76102..3ff4e9def8f 100644
--- a/chromium/components/content_settings/core/common/features.cc
+++ b/chromium/components/content_settings/core/common/features.cc
@@ -10,17 +10,17 @@
namespace content_settings {
// Enables an improved UI for third-party cookie blocking in incognito mode.
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
const base::Feature kImprovedCookieControls{"ImprovedCookieControls",
base::FEATURE_DISABLED_BY_DEFAULT};
-#endif // defined(OS_IOS)
+#endif // BUILDFLAG(IS_IOS)
// Enables auto dark feature in theme settings.
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
const base::Feature kDarkenWebsitesCheckboxInThemesSetting{
"DarkenWebsitesCheckboxInThemesSetting", base::FEATURE_DISABLED_BY_DEFAULT};
constexpr base::FeatureParam<bool> kDarkenWebsitesCheckboxOptOut{
&kDarkenWebsitesCheckboxInThemesSetting, "opt_out", true};
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
} // namespace content_settings
diff --git a/chromium/components/content_settings/core/common/features.h b/chromium/components/content_settings/core/common/features.h
index 1d2d27bf28c..25cc6613d88 100644
--- a/chromium/components/content_settings/core/common/features.h
+++ b/chromium/components/content_settings/core/common/features.h
@@ -7,17 +7,18 @@
#include "base/component_export.h"
#include "base/feature_list.h"
+#include "base/metrics/field_trial_params.h"
#include "build/build_config.h"
namespace content_settings {
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
// Feature to enable a better cookie controls ui.
COMPONENT_EXPORT(CONTENT_SETTINGS_FEATURES)
extern const base::Feature kImprovedCookieControls;
#endif
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Enables auto dark feature in theme settings.
COMPONENT_EXPORT(CONTENT_SETTINGS_FEATURES)
extern const base::Feature kDarkenWebsitesCheckboxInThemesSetting;
diff --git a/chromium/components/content_settings/core/common/pref_names.cc b/chromium/components/content_settings/core/common/pref_names.cc
index 07498435b25..a4360ea9f37 100644
--- a/chromium/components/content_settings/core/common/pref_names.cc
+++ b/chromium/components/content_settings/core/common/pref_names.cc
@@ -4,6 +4,8 @@
#include "components/content_settings/core/common/pref_names.h"
+#include "build/build_config.h"
+
namespace prefs {
// CookieControlsMode enum value that decides when the cookie controls UI is
@@ -57,6 +59,10 @@ const char kManagedDefaultInsecurePrivateNetworkSetting[] =
"profile.managed_default_content_settings.insecure_private_network";
const char kManagedDefaultJavaScriptJitSetting[] =
"profile.managed_default_content_settings.javascript_jit";
+const char kManagedDefaultWebHidGuardSetting[] =
+ "profile.managed_default_content_settings.web_hid_guard";
+const char kManagedDefaultWindowPlacementSetting[] =
+ "profile.managed_default_content_settings.window_placement";
// Preferences that are exclusively used to store managed
// content settings patterns.
@@ -120,6 +126,13 @@ const char kManagedJavaScriptJitAllowedForSites[] =
"profile.managed_javascript_jit_allowed_for_sites";
const char kManagedJavaScriptJitBlockedForSites[] =
"profile.managed_javascript_jit_blocked_for_sites";
+const char kManagedWebHidAskForUrls[] = "profile.managed_web_hid_ask_for_urls";
+const char kManagedWebHidBlockedForUrls[] =
+ "profile.managed_web_hid_blocked_for_urls";
+const char kManagedWindowPlacementAllowedForUrls[] =
+ "profile.managed_window_placement_allowed_for_urls";
+const char kManagedWindowPlacementBlockedForUrls[] =
+ "profile.managed_window_placement_blocked_for_urls";
// Boolean indicating whether the quiet UI is enabled for notification
// permission requests.
@@ -139,7 +152,7 @@ const char kQuietNotificationPermissionUiEnablingMethod[] =
const char kQuietNotificationPermissionUiDisabledTime[] =
"profile.content_settings.disable_quiet_permission_ui_time.notifications";
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Enable vibration for web notifications.
const char kNotificationsVibrateEnabled[] = "notifications.vibrate_enabled";
#endif
diff --git a/chromium/components/content_settings/core/common/pref_names.h b/chromium/components/content_settings/core/common/pref_names.h
index d54cbc89744..a34f557b789 100644
--- a/chromium/components/content_settings/core/common/pref_names.h
+++ b/chromium/components/content_settings/core/common/pref_names.h
@@ -36,6 +36,8 @@ extern const char kManagedDefaultFileSystemWriteGuardSetting[];
extern const char kManagedDefaultSerialGuardSetting[];
extern const char kManagedDefaultInsecurePrivateNetworkSetting[];
extern const char kManagedDefaultJavaScriptJitSetting[];
+extern const char kManagedDefaultWebHidGuardSetting[];
+extern const char kManagedDefaultWindowPlacementSetting[];
extern const char kManagedCookiesAllowedForUrls[];
extern const char kManagedCookiesBlockedForUrls[];
@@ -68,12 +70,16 @@ extern const char kManagedSerialBlockedForUrls[];
extern const char kManagedInsecurePrivateNetworkAllowedForUrls[];
extern const char kManagedJavaScriptJitAllowedForSites[];
extern const char kManagedJavaScriptJitBlockedForSites[];
+extern const char kManagedWebHidAskForUrls[];
+extern const char kManagedWebHidBlockedForUrls[];
+extern const char kManagedWindowPlacementAllowedForUrls[];
+extern const char kManagedWindowPlacementBlockedForUrls[];
extern const char kEnableQuietNotificationPermissionUi[];
extern const char kQuietNotificationPermissionUiEnablingMethod[];
extern const char kQuietNotificationPermissionUiDisabledTime[];
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
extern const char kNotificationsVibrateEnabled[];
#endif
diff --git a/chromium/components/content_settings/renderer/content_settings_agent_impl.cc b/chromium/components/content_settings/renderer/content_settings_agent_impl.cc
index f0720efc9e9..e11724a73a2 100644
--- a/chromium/components/content_settings/renderer/content_settings_agent_impl.cc
+++ b/chromium/components/content_settings/renderer/content_settings_agent_impl.cc
@@ -23,7 +23,6 @@
#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_registry.h"
#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
-#include "third_party/blink/public/common/loader/previews_state.h"
#include "third_party/blink/public/platform/url_conversion.h"
#include "third_party/blink/public/platform/web_security_origin.h"
#include "third_party/blink/public/platform/web_url.h"
diff --git a/chromium/components/content_settings/renderer/content_settings_agent_impl_browsertest.cc b/chromium/components/content_settings/renderer/content_settings_agent_impl_browsertest.cc
index 4954260a75c..5dc1922cb45 100644
--- a/chromium/components/content_settings/renderer/content_settings_agent_impl_browsertest.cc
+++ b/chromium/components/content_settings/renderer/content_settings_agent_impl_browsertest.cc
@@ -93,13 +93,13 @@ class MockContentSettingsAgentDelegate
class MockContentSettingsAgentImpl : public ContentSettingsAgentImpl {
public:
- MockContentSettingsAgentImpl(content::RenderFrame* render_frame);
+ explicit MockContentSettingsAgentImpl(content::RenderFrame* render_frame);
MockContentSettingsAgentImpl(const MockContentSettingsAgentImpl&) = delete;
MockContentSettingsAgentImpl& operator=(const MockContentSettingsAgentImpl&) =
delete;
- ~MockContentSettingsAgentImpl() override {}
+ ~MockContentSettingsAgentImpl() override = default;
const GURL& image_url() const { return image_url_; }
const std::string& image_origin() const { return image_origin_; }
@@ -288,8 +288,7 @@ TEST_F(ContentSettingsAgentImplBrowserTest, JSBlockSentAfterPageLoad) {
content_setting_rules.script_rules;
script_setting_rules.push_back(ContentSettingPatternSource(
ContentSettingsPattern::Wildcard(), ContentSettingsPattern::Wildcard(),
- base::Value::FromUniquePtrValue(
- content_settings::ContentSettingToValue(CONTENT_SETTING_BLOCK)),
+ content_settings::ContentSettingToValue(CONTENT_SETTING_BLOCK),
std::string(), false));
ContentSettingsAgentImpl* agent =
ContentSettingsAgentImpl::Get(GetMainRenderFrame());
@@ -333,8 +332,7 @@ TEST_F(ContentSettingsAgentImplBrowserTest, ImagesBlockedByDefault) {
content_setting_rules.image_rules;
image_setting_rules.push_back(ContentSettingPatternSource(
ContentSettingsPattern::Wildcard(), ContentSettingsPattern::Wildcard(),
- base::Value::FromUniquePtrValue(
- content_settings::ContentSettingToValue(CONTENT_SETTING_BLOCK)),
+ content_settings::ContentSettingToValue(CONTENT_SETTING_BLOCK),
std::string(), false));
ContentSettingsAgentImpl* agent =
@@ -351,8 +349,7 @@ TEST_F(ContentSettingsAgentImplBrowserTest, ImagesBlockedByDefault) {
ContentSettingPatternSource(
ContentSettingsPattern::Wildcard(),
ContentSettingsPattern::FromString(mock_agent.image_origin()),
- base::Value::FromUniquePtrValue(
- content_settings::ContentSettingToValue(CONTENT_SETTING_ALLOW)),
+ content_settings::ContentSettingToValue(CONTENT_SETTING_ALLOW),
std::string(), false));
EXPECT_TRUE(agent->AllowImage(true, mock_agent.image_url()));
@@ -372,8 +369,7 @@ TEST_F(ContentSettingsAgentImplBrowserTest, ImagesAllowedByDefault) {
content_setting_rules.image_rules;
image_setting_rules.push_back(ContentSettingPatternSource(
ContentSettingsPattern::Wildcard(), ContentSettingsPattern::Wildcard(),
- base::Value::FromUniquePtrValue(
- content_settings::ContentSettingToValue(CONTENT_SETTING_ALLOW)),
+ content_settings::ContentSettingToValue(CONTENT_SETTING_ALLOW),
std::string(), false));
ContentSettingsAgentImpl* agent =
@@ -389,8 +385,7 @@ TEST_F(ContentSettingsAgentImplBrowserTest, ImagesAllowedByDefault) {
ContentSettingPatternSource(
ContentSettingsPattern::Wildcard(),
ContentSettingsPattern::FromString(mock_agent.image_origin()),
- base::Value::FromUniquePtrValue(
- content_settings::ContentSettingToValue(CONTENT_SETTING_BLOCK)),
+ content_settings::ContentSettingToValue(CONTENT_SETTING_BLOCK),
std::string(), false));
EXPECT_FALSE(agent->AllowImage(true, mock_agent.image_url()));
base::RunLoop().RunUntilIdle();
@@ -406,8 +401,7 @@ TEST_F(ContentSettingsAgentImplBrowserTest, ContentSettingsBlockScripts) {
content_setting_rules.script_rules;
script_setting_rules.push_back(ContentSettingPatternSource(
ContentSettingsPattern::Wildcard(), ContentSettingsPattern::Wildcard(),
- base::Value::FromUniquePtrValue(
- content_settings::ContentSettingToValue(CONTENT_SETTING_BLOCK)),
+ content_settings::ContentSettingToValue(CONTENT_SETTING_BLOCK),
std::string(), false));
ContentSettingsAgentImpl* agent =
@@ -429,8 +423,7 @@ TEST_F(ContentSettingsAgentImplBrowserTest, ContentSettingsAllowScripts) {
content_setting_rules.script_rules;
script_setting_rules.push_back(ContentSettingPatternSource(
ContentSettingsPattern::Wildcard(), ContentSettingsPattern::Wildcard(),
- base::Value::FromUniquePtrValue(
- content_settings::ContentSettingToValue(CONTENT_SETTING_ALLOW)),
+ content_settings::ContentSettingToValue(CONTENT_SETTING_ALLOW),
std::string(), false));
ContentSettingsAgentImpl* agent =
@@ -453,8 +446,7 @@ TEST_F(ContentSettingsAgentImplBrowserTest,
content_setting_rules.script_rules;
script_setting_rules.push_back(ContentSettingPatternSource(
ContentSettingsPattern::Wildcard(), ContentSettingsPattern::Wildcard(),
- base::Value::FromUniquePtrValue(
- content_settings::ContentSettingToValue(CONTENT_SETTING_ALLOW)),
+ content_settings::ContentSettingToValue(CONTENT_SETTING_ALLOW),
std::string(), false));
ContentSettingsAgentImpl* agent =
@@ -480,8 +472,7 @@ TEST_F(ContentSettingsAgentImplBrowserTest, ContentSettingsNoscriptTag) {
content_setting_rules.script_rules;
script_setting_rules.push_back(ContentSettingPatternSource(
ContentSettingsPattern::Wildcard(), ContentSettingsPattern::Wildcard(),
- base::Value::FromUniquePtrValue(
- content_settings::ContentSettingToValue(CONTENT_SETTING_BLOCK)),
+ content_settings::ContentSettingToValue(CONTENT_SETTING_BLOCK),
std::string(), false));
ContentSettingsAgentImpl* agent =
@@ -513,8 +504,7 @@ TEST_F(ContentSettingsAgentImplBrowserTest, ContentSettingsNoscriptTag) {
script_setting_rules.clear();
script_setting_rules.push_back(ContentSettingPatternSource(
ContentSettingsPattern::Wildcard(), ContentSettingsPattern::Wildcard(),
- base::Value::FromUniquePtrValue(
- content_settings::ContentSettingToValue(CONTENT_SETTING_ALLOW)),
+ content_settings::ContentSettingToValue(CONTENT_SETTING_ALLOW),
std::string(), false));
agent->SetContentSettingRules(&content_setting_rules);
@@ -554,8 +544,7 @@ TEST_F(ContentSettingsAgentImplBrowserTest,
content_setting_rules.script_rules;
script_setting_rules.push_back(ContentSettingPatternSource(
ContentSettingsPattern::Wildcard(), ContentSettingsPattern::Wildcard(),
- base::Value::FromUniquePtrValue(
- content_settings::ContentSettingToValue(CONTENT_SETTING_BLOCK)),
+ content_settings::ContentSettingToValue(CONTENT_SETTING_BLOCK),
std::string(), false));
ContentSettingsAgentImpl* agent =
@@ -579,8 +568,7 @@ TEST_F(ContentSettingsAgentImplBrowserTest, MixedAutoupgradesDisabledByRules) {
content_setting_rules.mixed_content_rules;
mixed_content_setting_rules.push_back(ContentSettingPatternSource(
ContentSettingsPattern::Wildcard(), ContentSettingsPattern::Wildcard(),
- base::Value::FromUniquePtrValue(
- content_settings::ContentSettingToValue(CONTENT_SETTING_BLOCK)),
+ content_settings::ContentSettingToValue(CONTENT_SETTING_BLOCK),
std::string(), false));
ContentSettingsAgentImpl* agent =
@@ -594,8 +582,7 @@ TEST_F(ContentSettingsAgentImplBrowserTest, MixedAutoupgradesDisabledByRules) {
ContentSettingPatternSource(
ContentSettingsPattern::FromString("https://example.com/"),
ContentSettingsPattern::Wildcard(),
- base::Value::FromUniquePtrValue(
- content_settings::ContentSettingToValue(CONTENT_SETTING_ALLOW)),
+ content_settings::ContentSettingToValue(CONTENT_SETTING_ALLOW),
std::string(), false));
EXPECT_FALSE(agent->ShouldAutoupgradeMixedContent());
@@ -613,8 +600,7 @@ TEST_F(ContentSettingsAgentImplBrowserTest, ContentSettingsAllowedAutoDark) {
content_setting_rules.auto_dark_content_rules;
auto_dark_content_rules.push_back(ContentSettingPatternSource(
ContentSettingsPattern::Wildcard(), ContentSettingsPattern::Wildcard(),
- base::Value::FromUniquePtrValue(
- content_settings::ContentSettingToValue(CONTENT_SETTING_ALLOW)),
+ content_settings::ContentSettingToValue(CONTENT_SETTING_ALLOW),
std::string(), false));
ContentSettingsAgentImpl* agent =
@@ -628,8 +614,7 @@ TEST_F(ContentSettingsAgentImplBrowserTest, ContentSettingsAllowedAutoDark) {
ContentSettingPatternSource(
ContentSettingsPattern::FromString("https://example.com/"),
ContentSettingsPattern::Wildcard(),
- base::Value::FromUniquePtrValue(
- content_settings::ContentSettingToValue(CONTENT_SETTING_BLOCK)),
+ content_settings::ContentSettingToValue(CONTENT_SETTING_BLOCK),
std::string(), false));
EXPECT_FALSE(agent->AllowAutoDarkWebContent(true));
@@ -647,8 +632,7 @@ TEST_F(ContentSettingsAgentImplBrowserTest, ContentSettingsDisabledAutoDark) {
content_setting_rules.auto_dark_content_rules;
auto_dark_content_rules.push_back(ContentSettingPatternSource(
ContentSettingsPattern::Wildcard(), ContentSettingsPattern::Wildcard(),
- base::Value::FromUniquePtrValue(
- content_settings::ContentSettingToValue(CONTENT_SETTING_BLOCK)),
+ content_settings::ContentSettingToValue(CONTENT_SETTING_BLOCK),
std::string(), false));
ContentSettingsAgentImpl* agent =
diff --git a/chromium/components/cookie_config/cookie_store_util.cc b/chromium/components/cookie_config/cookie_store_util.cc
index d9bbbe27e90..cf65443b372 100644
--- a/chromium/components/cookie_config/cookie_store_util.cc
+++ b/chromium/components/cookie_config/cookie_store_util.cc
@@ -11,8 +11,8 @@
namespace cookie_config {
-#if defined(OS_WIN) || defined(OS_APPLE) || defined(OS_LINUX) || \
- defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) || \
+ BUILDFLAG(IS_CHROMEOS)
namespace {
// Use the operating system's mechanisms to encrypt cookies before writing
@@ -28,7 +28,7 @@ class CookieOSCryptoDelegate : public net::CookieCryptoDelegate {
};
bool CookieOSCryptoDelegate::ShouldEncrypt() {
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
// Cookie encryption is not necessary on iOS, due to OS-protected storage.
// However, due to https://codereview.chromium.org/135183021/, cookies were
// accidentally encrypted. In order to allow these cookies to still be used,a
@@ -64,12 +64,12 @@ base::LazyInstance<CookieOSCryptoDelegate>::DestructorAtExit
net::CookieCryptoDelegate* GetCookieCryptoDelegate() {
return g_cookie_crypto_delegate.Pointer();
}
-#else // defined(OS_WIN) || defined(OS_APPLE) || defined(OS_LINUX) ||
- // defined(OS_CHROMEOS)
+#else // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) ||
+ // BUILDFLAG(IS_CHROMEOS)
net::CookieCryptoDelegate* GetCookieCryptoDelegate() {
return NULL;
}
-#endif // defined(OS_WIN) || defined(OS_APPLE) || defined(OS_LINUX) ||
- // defined(OS_CHROMEOS)
+#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) ||
+ // BUILDFLAG(IS_CHROMEOS)
} // namespace cookie_config
diff --git a/chromium/components/country_codes/country_codes.cc b/chromium/components/country_codes/country_codes.cc
index 4c3a9a4e5ea..584fe177b7d 100644
--- a/chromium/components/country_codes/country_codes.cc
+++ b/chromium/components/country_codes/country_codes.cc
@@ -4,7 +4,9 @@
#include "components/country_codes/country_codes.h"
-#if defined(OS_POSIX) && !defined(OS_APPLE)
+#include "build/build_config.h"
+
+#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_APPLE)
#include <locale.h>
#endif
@@ -13,14 +15,14 @@
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/pref_service.h"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include <windows.h>
#undef IN // On Windows, windef.h defines this, which screws up "India" cases.
-#elif defined(OS_APPLE)
+#elif BUILDFLAG(IS_APPLE)
#include "base/mac/scoped_cftyperef.h"
#endif
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "base/android/locale_utils.h"
#endif
@@ -49,7 +51,7 @@ int CountryCharsToCountryIDWithUpdate(char c1, char c2) {
return CountryCharsToCountryID(c1, c2);
}
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// For reference, a list of GeoIDs can be found at
// http://msdn.microsoft.com/en-us/library/dd374073.aspx .
@@ -106,7 +108,7 @@ int GeoIDToCountryID(GEOID geo_id) {
}
}
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
} // namespace
@@ -138,13 +140,13 @@ void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
kCountryIDUnknown);
}
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
int GetCurrentCountryID() {
return GeoIDToCountryID(GetUserGeoID(GEOCLASS_NATION));
}
-#elif defined(OS_APPLE)
+#elif BUILDFLAG(IS_APPLE)
int GetCurrentCountryID() {
base::ScopedCFTypeRef<CFLocaleRef> locale(CFLocaleCopyCurrent());
@@ -161,13 +163,13 @@ int GetCurrentCountryID() {
static_cast<char>(isobuf[1]));
}
-#elif defined(OS_ANDROID)
+#elif BUILDFLAG(IS_ANDROID)
int GetCurrentCountryID() {
return CountryStringToCountryID(base::android::GetDefaultCountryCode());
}
-#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
int GetCurrentCountryID() {
const char* locale = setlocale(LC_MESSAGES, nullptr);
diff --git a/chromium/components/crash/android/BUILD.gn b/chromium/components/crash/android/BUILD.gn
index ed3eda57fdc..3a3788beca5 100644
--- a/chromium/components/crash/android/BUILD.gn
+++ b/chromium/components/crash/android/BUILD.gn
@@ -6,6 +6,7 @@ import("//build/config/android/rules.gni")
_jni_sources = [
"java/src/org/chromium/components/crash/CrashKeys.java",
+ "java/src/org/chromium/components/crash/PureJavaExceptionHandler.java",
"java/src/org/chromium/components/crash/browser/ChildProcessCrashObserver.java",
"java/src/org/chromium/components/crash/browser/PackagePaths.java",
"java/src/org/chromium/components/crash/browser/ProcessExitReasonFromSystem.java",
@@ -22,17 +23,59 @@ java_cpp_enum("java_enums_srcjar") {
android_library("java") {
deps = [
"//base:base_java",
+ "//components/minidump_uploader:minidump_uploader_java",
+ "//components/version_info/android:version_constants_java",
"//third_party/androidx:androidx_annotation_annotation_java",
]
annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
srcjar_deps = [ ":java_enums_srcjar" ]
- sources = _jni_sources
+ sources = [
+ "java/src/org/chromium/components/crash/LogcatCrashExtractor.java",
+ "java/src/org/chromium/components/crash/MinidumpLogcatPrepender.java",
+ "java/src/org/chromium/components/crash/PureJavaExceptionReporter.java",
+ ]
+ sources += _jni_sources
+}
+
+android_library("javatests") {
+ testonly = true
+ sources = [ "javatests/src/org/chromium/components/crash/PureJavaExceptionReporterTest.java" ]
+ deps = [
+ ":java",
+ "//base:base_java_test_support",
+ "//components/minidump_uploader:minidump_uploader_java_test_support",
+ "//content/public/test/android:content_java_test_support",
+ "//third_party/androidx:androidx_test_runner_java",
+ "//third_party/junit",
+ ]
+}
+
+java_library("junit") {
+ # Skip platform checks since Robolectric depends on requires_android targets.
+ bypass_platform_checks = true
+ testonly = true
+ sources = [
+ "junit/src/org/chromium/components/crash/LogcatCrashExtractorTest.java",
+ "junit/src/org/chromium/components/crash/anr/AnrCollectorTest.java",
+ ]
+ deps = [
+ ":anr_collector_java",
+ ":anr_data_proto_java",
+ ":java",
+ "//base:base_java",
+ "//base:base_java_test_support",
+ "//base:base_junit_test_support",
+ "//third_party/android_deps:robolectric_all_java",
+ "//third_party/junit",
+ ]
}
source_set("crash_android") {
sources = [
"crash_keys_android.cc",
"crash_keys_android.h",
+ "pure_java_exception_handler.cc",
+ "pure_java_exception_handler.h",
]
deps = [
":jni_headers",
@@ -74,3 +117,25 @@ static_library("crashpad_main") {
"//third_party/crashpad/crashpad/handler",
]
}
+
+source_set("anr_skipped_reason") {
+ sources = [ "anr_skipped_reason.h" ]
+}
+java_cpp_enum("anr_skipped_reason_enum") {
+ sources = [ "anr_skipped_reason.h" ]
+}
+
+proto_java_library("anr_data_proto_java") {
+ proto_path = "."
+ sources = [ "anr_data.proto" ]
+}
+
+android_library("anr_collector_java") {
+ deps = [
+ ":anr_data_proto_java",
+ "//base:base_java",
+ "//third_party/androidx:androidx_annotation_annotation_java",
+ ]
+ srcjar_deps = [ ":anr_skipped_reason_enum" ]
+ sources = [ "java/src/org/chromium/components/crash/anr/AnrCollector.java" ]
+}
diff --git a/chromium/components/crash/android/DEPS b/chromium/components/crash/android/DEPS
index 56e7e235177..1023fa8ce8f 100644
--- a/chromium/components/crash/android/DEPS
+++ b/chromium/components/crash/android/DEPS
@@ -1,4 +1,6 @@
include_rules = [
"+components/crash/android/jni_headers",
+ "+components/minidump_uploader/android",
+ "+components/version_info/android",
"+third_party/crashpad",
]
diff --git a/chromium/components/crash/android/anr_data.proto b/chromium/components/crash/android/anr_data.proto
new file mode 100644
index 00000000000..fe148878100
--- /dev/null
+++ b/chromium/components/crash/android/anr_data.proto
@@ -0,0 +1,73 @@
+// Copyright 2021 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.
+
+syntax = "proto2";
+option optimize_for = LITE_RUNTIME;
+
+package crash.anr.proto;
+
+option java_package = "org.chromium.components.crash.anr";
+
+// This is a proto copied from the source code of the crash server to ensure we
+// have the correct format to upload.
+message AnrData {
+ // Name of the activity which is not responding.
+ // Chrome does not use this right now.
+ // optional string activity = 1;
+
+ // Description of the operation that timed out.
+ // Chrome does not put a useful value in here, but must include it to be
+ // processed.
+ optional string cause = 2; // required
+
+ // Type of ANR, parsed from the cause.
+ // Chrome does not use this right now.
+ // optional string cause_type = 10;
+
+ // This is the android app component (declared in the manifest) that is
+ // experiencing the ANR. It could be extracted form the "ANR cause" or it
+ // could be the activity (for input dispatching timeout cases - in which
+ // case it's not parsed from the cause).
+ //
+ // For instance, for the following ANR cause:
+ // "Broadcast of Intent { act=com.nativedroid.sa.sdk.tick flg=0x10
+ // cmp=com.android.appkeyguard/cnuunh.myimpj.yhYjQqAheTNUaYGL
+ // (has extras) }"
+ //
+ // The android app component is:
+ // "com.android.appkeyguard/cnuunh.myimpj.yhYjQqAheTNUaYGL".
+ // Chrome does not use this right now.
+ // optional string component = 9;
+
+ // A message created for the developer by ActivityManagerService during an
+ // ANR. It contains additional info such as the CPU stats.
+ // Chrome does not use this right now.
+ // optional string extra = 3;
+
+ // Stack traces for all the threads that were running on the device. If
+ // deobfuscation is enabled, these stack_traces will be deobfuscated during
+ // the preprocessing phase.
+ optional string stack_traces = 4;
+
+ // The parsed stack traces for easier processing.
+ // This parsing is performed upstream and this field is already parsed when
+ // passing to crash.
+ // Chrome does not use this right now.
+ // repeated string parsed_stack_traces = 5;
+
+ // The stack trace of the main thread (starting from the status line)
+ // of the process that is not responsive according to
+ // MobileData.package_data.process_name.
+ optional string main_thread_stack_trace = 6;
+
+ // The state of the main thread of the process that is not responsive,
+ // parsed from the stacktrace (e.g. "NATIVE", "SUSPENDED", "WAIT").
+ // This field is populated during server side processing from
+ // main_thread_stack_trace.
+ // Chrome does not use this right now.
+ // optional string main_thread_state = 7;
+
+ // Preamble of anr report.
+ optional string preamble = 8;
+}
diff --git a/chromium/components/crash/android/anr_skipped_reason.h b/chromium/components/crash/android/anr_skipped_reason.h
new file mode 100644
index 00000000000..816cf5234a8
--- /dev/null
+++ b/chromium/components/crash/android/anr_skipped_reason.h
@@ -0,0 +1,21 @@
+// Copyright 2021 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.
+
+#ifndef COMPONENTS_CRASH_ANDROID_ANR_SKIPPED_REASON_H_
+#define COMPONENTS_CRASH_ANDROID_ANR_SKIPPED_REASON_H_
+
+// Enum to record how many and why ANRs were not uploaded to UMA.
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
+//
+// A Java counterpart will be generated for this enum.
+// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.components.crash.anr
+enum class AnrSkippedReason {
+ kFilesystemReadFailure = 0,
+ kFilesystemWriteFailure = 1,
+ kMissingVersion = 2,
+ kMaxValue = kMissingVersion,
+};
+
+#endif // COMPONENTS_CRASH_ANDROID_ANR_SKIPPED_REASON_H_
diff --git a/chromium/components/crash/android/javatests/src/org/chromium/components/crash/DEPS b/chromium/components/crash/android/javatests/src/org/chromium/components/crash/DEPS
new file mode 100644
index 00000000000..877e2a4da34
--- /dev/null
+++ b/chromium/components/crash/android/javatests/src/org/chromium/components/crash/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+content/public/test/android",
+] \ No newline at end of file
diff --git a/chromium/components/crash/android/javatests/src/org/chromium/components/crash/PureJavaExceptionReporterTest.java b/chromium/components/crash/android/javatests/src/org/chromium/components/crash/PureJavaExceptionReporterTest.java
new file mode 100644
index 00000000000..5bff2770b06
--- /dev/null
+++ b/chromium/components/crash/android/javatests/src/org/chromium/components/crash/PureJavaExceptionReporterTest.java
@@ -0,0 +1,132 @@
+// Copyright 2015 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.
+
+package org.chromium.components.crash;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.BaseJUnit4ClassRunner;
+import org.chromium.components.minidump_uploader.CrashTestRule;
+import org.chromium.content_public.browser.test.util.TestThreadUtils;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+
+/**
+ * Unittests for {@link PureJavaExceptionReporter}.
+ */
+@RunWith(BaseJUnit4ClassRunner.class)
+public class PureJavaExceptionReporterTest {
+ @Rule
+ public CrashTestRule mTestRule = new CrashTestRule();
+
+ private class TestPureJavaExceptionReporter extends PureJavaExceptionReporter {
+ private boolean mReportUploaded;
+ private File mMinidump;
+
+ public TestPureJavaExceptionReporter() {
+ super(mTestRule.getCacheDir());
+ }
+
+ @Override
+ protected String getProductName() {
+ return "Test";
+ }
+
+ @Override
+ protected void uploadMinidump(File minidump) {
+ mMinidump = minidump;
+ mReportUploaded = (minidump != null);
+ }
+
+ @Override
+ protected String getMinidumpPrefix() {
+ return "test-minidump-";
+ }
+
+ public boolean reportUploaded() {
+ return mReportUploaded;
+ }
+
+ public File getMinidumpFile() {
+ return mMinidump;
+ }
+ }
+
+ private static final String EXCEPTION_NAME = "EXCEPTION_NAME";
+
+ private static final String[] REPORT_FIELDS = {PureJavaExceptionReporter.CHANNEL,
+ PureJavaExceptionReporter.VERSION, PureJavaExceptionReporter.PRODUCT,
+ PureJavaExceptionReporter.ANDROID_BUILD_ID, PureJavaExceptionReporter.ANDROID_BUILD_FP,
+ PureJavaExceptionReporter.SDK, PureJavaExceptionReporter.DEVICE,
+ PureJavaExceptionReporter.GMS_CORE_VERSION,
+ PureJavaExceptionReporter.INSTALLER_PACKAGE_NAME, PureJavaExceptionReporter.ABI_NAME,
+ PureJavaExceptionReporter.PACKAGE, PureJavaExceptionReporter.MODEL,
+ PureJavaExceptionReporter.BRAND, PureJavaExceptionReporter.BOARD,
+ PureJavaExceptionReporter.EXCEPTION_INFO, PureJavaExceptionReporter.PROCESS_TYPE,
+ PureJavaExceptionReporter.EARLY_JAVA_EXCEPTION};
+
+ private String readFileToString(File file) {
+ StringBuilder sb = new StringBuilder();
+ try (BufferedReader br = new BufferedReader(new FileReader(file))) {
+ String line;
+ while ((line = br.readLine()) != null) {
+ sb.append(line);
+ }
+ } catch (IOException e) {
+ }
+ return sb.toString();
+ }
+
+ private void verifyField(String minidumpString, String field) {
+ Assert.assertTrue("Report field \"" + field
+ + "\" is not included in the report. Minidump string is \"" + minidumpString
+ + "\"",
+ minidumpString.contains(field));
+ }
+
+ @Test
+ @SmallTest
+ public void verifyMinidumpContentAndUpload() {
+ Throwable exception = new RuntimeException(EXCEPTION_NAME);
+ TestPureJavaExceptionReporter reporter = new TestPureJavaExceptionReporter();
+ reporter.createAndUploadReport(exception);
+ String minidumpString = readFileToString(reporter.getMinidumpFile());
+
+ for (String field : REPORT_FIELDS) {
+ verifyField(minidumpString, field);
+ }
+
+ // Exception string should be included in the stack trace.
+ Assert.assertTrue(minidumpString.contains(EXCEPTION_NAME));
+
+ // Current function name should be included in the stack trace.
+ Assert.assertTrue(minidumpString.contains("verifyMinidumpContentAndUpload"));
+
+ Assert.assertTrue(reporter.reportUploaded());
+ }
+
+ @Test
+ @SmallTest
+ public void verifyCrashKeys() {
+ TestThreadUtils.runOnUiThreadBlocking(
+ () -> { CrashKeys.getInstance().set(CrashKeyIndex.LOADED_DYNAMIC_MODULE, "foo"); });
+
+ TestPureJavaExceptionReporter reporter = new TestPureJavaExceptionReporter();
+ reporter.createAndUploadReport(new RuntimeException());
+ String minidumpString = readFileToString(reporter.getMinidumpFile());
+
+ Assert.assertTrue(
+ minidumpString.contains(CrashKeys.getKey(CrashKeyIndex.LOADED_DYNAMIC_MODULE)));
+ Assert.assertFalse(
+ minidumpString.contains(CrashKeys.getKey(CrashKeyIndex.ACTIVE_DYNAMIC_MODULE)));
+ }
+}
diff --git a/chromium/components/crash/android/junit/src/org/chromium/components/crash/LogcatCrashExtractorTest.java b/chromium/components/crash/android/junit/src/org/chromium/components/crash/LogcatCrashExtractorTest.java
new file mode 100644
index 00000000000..f69d18c1ed1
--- /dev/null
+++ b/chromium/components/crash/android/junit/src/org/chromium/components/crash/LogcatCrashExtractorTest.java
@@ -0,0 +1,132 @@
+// Copyright 2015 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.
+
+package org.chromium.components.crash;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+
+import static org.chromium.components.crash.LogcatCrashExtractor.BEGIN_MICRODUMP;
+import static org.chromium.components.crash.LogcatCrashExtractor.END_MICRODUMP;
+import static org.chromium.components.crash.LogcatCrashExtractor.SNIPPED_MICRODUMP;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.annotation.Config;
+
+import org.chromium.base.test.BaseRobolectricTestRunner;
+
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * junit tests for {@link LogcatCrashExtractor}.
+ */
+@RunWith(BaseRobolectricTestRunner.class)
+@Config(manifest = Config.NONE)
+public class LogcatCrashExtractorTest {
+ private static final int MAX_LINES = 5;
+
+ @Test
+ public void testLogTagNotElided() {
+ List<String> original = Arrays.asList(new String[] {"I/cr_FooBar(123): Some message"});
+ assertEquals(original, LogcatCrashExtractor.elideLogcat(original));
+ }
+
+ @Test
+ public void testLogcatEmpty() {
+ final List<String> original = new LinkedList<>();
+ assertLogcatLists(original, original);
+ }
+
+ @Test
+ public void testLogcatWithoutBeginOrEnd_smallLogcat() {
+ final List<String> original =
+ Arrays.asList("Line 1", "Line 2", "Line 3", "Line 4", "Line 5");
+ assertLogcatLists(original, original);
+ }
+
+ @Test
+ public void testLogcatWithoutBeginOrEnd_largeLogcat() {
+ final List<String> original = Arrays.asList("Trimmed Line 1", "Trimmed Line 2", "Line 3",
+ "Line 4", "Line 5", "Line 6", "Line 7");
+ final List<String> expected =
+ Arrays.asList("Line 3", "Line 4", "Line 5", "Line 6", "Line 7");
+ assertLogcatLists(expected, original);
+ }
+
+ @Test
+ public void testLogcatBeginsWithBegin() {
+ final List<String> original = Arrays.asList(BEGIN_MICRODUMP, "a", "b", "c", "d", "e");
+ final List<String> expected = Arrays.asList(SNIPPED_MICRODUMP);
+ assertLogcatLists(expected, original);
+ }
+
+ @Test
+ public void testLogcatWithBegin() {
+ final List<String> original =
+ Arrays.asList("Line 1", "Line 2", BEGIN_MICRODUMP, "a", "b", "c", "d", "e");
+ final List<String> expected = Arrays.asList("Line 1", "Line 2", SNIPPED_MICRODUMP);
+ assertLogcatLists(expected, original);
+ }
+
+ @Test
+ public void testLogcatWithEnd() {
+ final List<String> original = Arrays.asList("Line 1", "Line 2", END_MICRODUMP);
+ assertLogcatLists(original, original);
+ }
+
+ @Test
+ public void testLogcatWithBeginAndEnd_smallLogcat() {
+ final List<String> original = Arrays.asList(
+ "Line 1", "Line 2", BEGIN_MICRODUMP, "a", "b", "c", "d", "e", END_MICRODUMP);
+ final List<String> expected = Arrays.asList("Line 1", "Line 2", SNIPPED_MICRODUMP);
+ assertLogcatLists(expected, original);
+ }
+
+ @Test
+ public void testLogcatWithBeginAndEnd_splitLogcat() {
+ final List<String> original = Arrays.asList("Line 1", "Line 2", BEGIN_MICRODUMP, "a", "b",
+ "c", "d", "e", END_MICRODUMP, "Trimmed Line 3", "Trimmed Line 4");
+ final List<String> expected = Arrays.asList("Line 1", "Line 2", SNIPPED_MICRODUMP);
+ assertLogcatLists(expected, original);
+ }
+
+ @Test
+ public void testLogcatWithBeginAndEnd_largeLogcat() {
+ final List<String> original = Arrays.asList("Trimmed Line 1", "Trimmed Line 2", "Line 3",
+ "Line 4", "Line 5", "Line 6", BEGIN_MICRODUMP, "a", "b", "c", "d", "e",
+ END_MICRODUMP, "Trimmed Line 7", "Trimmed Line 8");
+ final List<String> expected =
+ Arrays.asList("Line 3", "Line 4", "Line 5", "Line 6", SNIPPED_MICRODUMP);
+ assertLogcatLists(expected, original);
+ }
+
+ @Test
+ public void testLogcatWithEndAndBegin_smallLogcat() {
+ final List<String> original = Arrays.asList(
+ END_MICRODUMP, "Line 1", "Line 2", BEGIN_MICRODUMP, "a", "b", "c", "d", "e");
+ final List<String> expected =
+ Arrays.asList(END_MICRODUMP, "Line 1", "Line 2", SNIPPED_MICRODUMP);
+ assertLogcatLists(expected, original);
+ }
+
+ @Test
+ public void testLogcatWithEndAndBegin_largeLogcat() {
+ final List<String> original =
+ Arrays.asList(END_MICRODUMP, "Line 1", "Line 2", BEGIN_MICRODUMP, "a", "b", "c",
+ "d", "e", END_MICRODUMP, "Trimmed Line 3", "Trimmed Line 4");
+ final List<String> expected =
+ Arrays.asList(END_MICRODUMP, "Line 1", "Line 2", SNIPPED_MICRODUMP);
+ assertLogcatLists(expected, original);
+ }
+
+ private void assertLogcatLists(List<String> expected, List<String> original) {
+ // trimLogcat() expects a modifiable list as input.
+ LinkedList<String> rawLogcat = new LinkedList<String>(original);
+ List<String> actualLogcat = LogcatCrashExtractor.trimLogcat(rawLogcat, MAX_LINES);
+ assertArrayEquals(expected.toArray(), actualLogcat.toArray());
+ }
+}
diff --git a/chromium/components/crash/android/junit/src/org/chromium/components/crash/anr/AnrCollectorTest.java b/chromium/components/crash/android/junit/src/org/chromium/components/crash/anr/AnrCollectorTest.java
new file mode 100644
index 00000000000..1e1dfd152ed
--- /dev/null
+++ b/chromium/components/crash/android/junit/src/org/chromium/components/crash/anr/AnrCollectorTest.java
@@ -0,0 +1,1085 @@
+// Copyright 2021 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.
+
+package org.chromium.components.crash.anr;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.components.crash.anr.AnrDataOuterClass.AnrData;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.StringReader;
+
+/** Unit tests for AnrCollector. */
+@RunWith(BaseRobolectricTestRunner.class)
+public final class AnrCollectorTest {
+ // There are a number of lines well over 100 characters, with tab characters present as well.
+ // This is a line-for-line copy of exactly what we get from the API. So, to maintain
+ // readability, we avoid line wrapping and preserve tab characters.
+ static final String TEXT_FROM_GET_TRACE_INPUT_STREAM =
+ "----- pid 10849 at 2021-09-28 15:41:53 -----\n"
+ + "Cmd line: com.google.android.apps.chrome\n"
+ + "Build fingerprint: 'google/sdk_gphone_x86/generic_x86_arm:11/RSR1.201013.001/6903271:user/release-keys'\n"
+ + "ABI: 'x86'\n"
+ + "Build type: optimized\n"
+ + "Zygote loaded classes=15746 post zygote classes=1796\n"
+ + "Dumping registered class loaders\n"
+ + "#0 dalvik.system.PathClassLoader: [], parent #1\n"
+ + "#1 java.lang.BootClassLoader: [], no parent\n"
+ + "#2 dalvik.system.PathClassLoader: [/data/app/~~vsJt6r0FRID_SGtfoYZfsw==/com.google.android.apps.chrome-elBS_VoQghHLRXEgGrwmbQ==/base.apk], parent #1\n"
+ + "#3 dalvik.system.PathClassLoader: [/data/app/~~VozU4lWeE_mDx8UNcfmuYg==/com.google.android.trichromelibrary.debug_463700031-WKdKLOoLSzICU5jkoCrpsA==/base.apk], parent #1\n"
+ + "#4 dalvik.system.PathClassLoader: [/data/app/~~vsJt6r0FRID_SGtfoYZfsw==/com.google.android.apps.chrome-elBS_VoQghHLRXEgGrwmbQ==/split_chrome.apk], parent #2\n"
+ + "#5 dalvik.system.DelegateLastClassLoader: [/data/user_de/0/com.google.android.gms/app_chimera/m/0000001a/DynamiteLoader.apk], parent #0\n"
+ + "#6 dalvik.system.DelegateLastClassLoader: [/data/user_de/0/com.google.android.gms/app_chimera/m/0000001d/GoogleCertificates.apk], parent #4\n"
+ + "Done dumping class loaders\n"
+ + "Classes initialized: 1391 in 79.445ms\n"
+ + "Intern table: 31916 strong; 520 weak\n"
+ + "JNI: CheckJNI is on; globals=798 (plus 43 weak)\n"
+ + "Libraries: /data/app/~~VozU4lWeE_mDx8UNcfmuYg==/com.google.android.trichromelibrary.debug_463700031-WKdKLOoLSzICU5jkoCrpsA==/base.apk!/lib/x86/libmonochrome.so /data/app/~~vsJt6r0FRID_SGtfoYZfsw==/com.google.android.apps.chrome-elBS_VoQghHLRXEgGrwmbQ==/base.apk!/lib/x86/libchromium_android_linker.so libandroid.so libaudioeffect_jni.so libcompiler_rt.so libicu_jni.so libjavacore.so libjavacrypto.so libjnigraphics.so libmedia_jni.so libopenjdk.so librs_jni.so libsfplugin_ccodec.so libsoundpool.so libstats_jni.so libwebviewchromium_loader.so (16)\n"
+ + "Heap: 87% free, 3559KB/26MB; 81403 objects\n"
+ + "Dumping cumulative Gc timings\n"
+ + "Average major GC reclaim bytes ratio inf over 0 GC cycles\n"
+ + "Average major GC copied live bytes ratio 0.723527 over 4 major GCs\n"
+ + "Cumulative bytes moved 11416448\n"
+ + "Cumulative objects moved 215864\n"
+ + "Peak regions allocated 35 (8960KB) / 768 (192MB)\n"
+ + "Start Dumping histograms for 1 iterations for young concurrent copying\n"
+ + "ProcessMarkStack: Sum: 9.613ms 99% C.I. 9.613ms-9.613ms Avg: 9.613ms Max: 9.613ms\n"
+ + "ScanImmuneSpaces: Sum: 4.390ms 99% C.I. 4.390ms-4.390ms Avg: 4.390ms Max: 4.390ms\n"
+ + "VisitConcurrentRoots: Sum: 2.118ms 99% C.I. 2.118ms-2.118ms Avg: 2.118ms Max: 2.118ms\n"
+ + "SweepSystemWeaks: Sum: 1.486ms 99% C.I. 1.486ms-1.486ms Avg: 1.486ms Max: 1.486ms\n"
+ + "ClearFromSpace: Sum: 1.095ms 99% C.I. 1.095ms-1.095ms Avg: 1.095ms Max: 1.095ms\n"
+ + "GrayAllDirtyImmuneObjects: Sum: 866us 99% C.I. 866us-866us Avg: 866us Max: 866us\n"
+ + "InitializePhase: Sum: 861us 99% C.I. 861us-861us Avg: 861us Max: 861us\n"
+ + "FlipOtherThreads: Sum: 414us 99% C.I. 414us-414us Avg: 414us Max: 414us\n"
+ + "ScanCardsForSpace: Sum: 249us 99% C.I. 249us-249us Avg: 249us Max: 249us\n"
+ + "VisitNonThreadRoots: Sum: 221us 99% C.I. 221us-221us Avg: 221us Max: 221us\n"
+ + "EnqueueFinalizerReferences: Sum: 207us 99% C.I. 207us-207us Avg: 207us Max: 207us\n"
+ + "SweepArray: Sum: 204us 99% C.I. 204us-204us Avg: 204us Max: 204us\n"
+ + "ProcessReferences: Sum: 117us 99% C.I. 1us-116us Avg: 58.500us Max: 116us\n"
+ + "RecordFree: Sum: 51us 99% C.I. 5us-46us Avg: 25.500us Max: 46us\n"
+ + "CopyingPhase: Sum: 48us 99% C.I. 48us-48us Avg: 48us Max: 48us\n"
+ + "FreeList: Sum: 45us 99% C.I. 45us-45us Avg: 45us Max: 45us\n"
+ + "(Paused)ClearCards: Sum: 39us 99% C.I. 0.250us-16us Avg: 3us Max: 16us\n"
+ + "MarkZygoteLargeObjects: Sum: 36us 99% C.I. 36us-36us Avg: 36us Max: 36us\n"
+ + "ThreadListFlip: Sum: 28us 99% C.I. 28us-28us Avg: 28us Max: 28us\n"
+ + "(Paused)GrayAllNewlyDirtyImmuneObjects: Sum: 26us 99% C.I. 26us-26us Avg: 26us Max: 26us\n"
+ + "ResetStack: Sum: 21us 99% C.I. 21us-21us Avg: 21us Max: 21us\n"
+ + "ReclaimPhase: Sum: 10us 99% C.I. 10us-10us Avg: 10us Max: 10us\n"
+ + "(Paused)SetFromSpace: Sum: 8us 99% C.I. 8us-8us Avg: 8us Max: 8us\n"
+ + "(Paused)FlipCallback: Sum: 6us 99% C.I. 6us-6us Avg: 6us Max: 6us\n"
+ + "UnBindBitmaps: Sum: 2us 99% C.I. 2us-2us Avg: 2us Max: 2us\n"
+ + "FlipThreadRoots: Sum: 1us 99% C.I. 1us-1us Avg: 1us Max: 1us\n"
+ + "Done Dumping histograms\n"
+ + "young concurrent copying paused: Sum: 105us 99% C.I. 105us-105us Avg: 105us Max: 105us\n"
+ + "young concurrent copying freed-bytes: Avg: 3768KB Max: 3768KB Min: 3768KB\n"
+ + "Freed-bytes histogram: 3520:1\n"
+ + "young concurrent copying total time: 22.235ms mean time: 22.235ms\n"
+ + "young concurrent copying freed: 52955 objects with total size 3768KB\n"
+ + "young concurrent copying throughput: 2.40705e+06/s / 167MB/s per cpu-time: 175419636/s / 167MB/s\n"
+ + "Average minor GC reclaim bytes ratio 0.905098 over 1 GC cycles\n"
+ + "Average minor GC copied live bytes ratio 0.218373 over 2 minor GCs\n"
+ + "Cumulative bytes moved 1933528\n"
+ + "Cumulative objects moved 34234\n"
+ + "Peak regions allocated 35 (8960KB) / 768 (192MB)\n"
+ + "Total time spent in GC: 22.235ms\n"
+ + "Mean GC size throughput: 165MB/s per cpu-time: 163MB/s\n"
+ + "Mean GC object throughput: 2.38161e+06 objects/s\n"
+ + "Total number of allocations 134358\n"
+ + "Total bytes allocated 7328KB\n"
+ + "Total bytes freed 3768KB\n"
+ + "Free memory 23MB\n"
+ + "Free memory until GC 23MB\n"
+ + "Free memory until OOME 188MB\n"
+ + "Total memory 26MB\n"
+ + "Max memory 192MB\n"
+ + "Zygote space size 3016KB\n"
+ + "Total mutator paused time: 105us\n"
+ + "Total time waiting for GC to complete: 2.938us\n"
+ + "Total GC count: 1\n"
+ + "Total GC time: 22.235ms\n"
+ + "Total blocking GC count: 0\n"
+ + "Total blocking GC time: 0\n"
+ + "Native bytes total: 18233624 registered: 279864\n"
+ + "Total native bytes at last GC: 18144188\n"
+ + "/system/framework/oat/x86/android.test.base.odex: quicken\n"
+ + "/data/app/~~vsJt6r0FRID_SGtfoYZfsw==/com.google.android.apps.chrome-elBS_VoQghHLRXEgGrwmbQ==/oat/x86/split_chrome.odex: speed-profile\n"
+ + "/system/framework/oat/x86/android.hidl.manager-V1.0-java.odex: quicken\n"
+ + "/system/framework/oat/x86/android.hidl.base-V1.0-java.odex: quicken\n"
+ + "/data/app/~~VozU4lWeE_mDx8UNcfmuYg==/com.google.android.trichromelibrary.debug_463700031-WKdKLOoLSzICU5jkoCrpsA==/oat/x86/base.odex: speed-profile\n"
+ + "/data/app/~~vsJt6r0FRID_SGtfoYZfsw==/com.google.android.apps.chrome-elBS_VoQghHLRXEgGrwmbQ==/oat/x86/split_extra_icu.odex: speed-profile\n"
+ + "/data/app/~~vsJt6r0FRID_SGtfoYZfsw==/com.google.android.apps.chrome-elBS_VoQghHLRXEgGrwmbQ==/oat/x86/base.odex: speed-profile\n"
+ + "Current JIT code cache size (used / resident): 82KB / 88KB\n"
+ + "Current JIT data cache size (used / resident): 51KB / 64KB\n"
+ + "Zygote JIT code cache size (at point of fork): 40KB / 44KB\n"
+ + "Zygote JIT data cache size (at point of fork): 30KB / 32KB\n"
+ + "Current JIT mini-debug-info size: 29KB\n"
+ + "Current JIT capacity: 256KB\n"
+ + "Current number of JIT JNI stub entries: 0\n"
+ + "Current number of JIT code cache entries: 90\n"
+ + "Total number of JIT compilations: 55\n"
+ + "Total number of JIT compilations for on stack replacement: 0\n"
+ + "Total number of JIT code cache collections: 2\n"
+ + "Memory used for stack maps: Avg: 356B Max: 2396B Min: 20B\n"
+ + "Memory used for compiled code: Avg: 1551B Max: 10KB Min: 82B\n"
+ + "Memory used for profiling info: Avg: 296B Max: 3116B Min: 20B\n"
+ + "Start Dumping histograms for 95 iterations for JIT timings\n"
+ + "Compiling: Sum: 585.229ms 99% C.I. 0.197ms-231.487ms Avg: 6.292ms Max: 411.532ms\n"
+ + "TrimMaps: Sum: 7.909ms 99% C.I. 19us-810.499us Avg: 85.043us Max: 908us\n"
+ + "Code cache collection: Sum: 5.340ms 99% C.I. 0.572ms-4.758ms Avg: 2.670ms Max: 4.768ms\n"
+ + "Done Dumping histograms\n"
+ + "Memory used for compilation: Avg: 112KB Max: 1087KB Min: 9680B\n"
+ + "ProfileSaver total_bytes_written=0\n"
+ + "ProfileSaver total_number_of_writes=0\n"
+ + "ProfileSaver total_number_of_code_cache_queries=0\n"
+ + "ProfileSaver total_number_of_skipped_writes=0\n"
+ + "ProfileSaver total_number_of_failed_writes=0\n"
+ + "ProfileSaver total_ms_of_sleep=5000\n"
+ + "ProfileSaver total_ms_of_work=0\n"
+ + "ProfileSaver total_number_of_hot_spikes=0\n"
+ + "ProfileSaver total_number_of_wake_ups=0\n"
+ + "Number of JIT inline cache deoptimizations: 3\n"
+ + "\n"
+ + "suspend all histogram: Sum: 90us 99% C.I. 1us-46us Avg: 10us Max: 46us\n"
+ + "DALVIK THREADS (25):\n"
+ + "\"Signal Catcher\" daemon prio=10 tid=6 Runnable\n"
+ + " | group=\"system\" sCount=0 dsCount=0 flags=0 obj=0x134c01b0 self=0xe2d44610\n"
+ + " | sysTid=10865 nice=-20 cgrp=top-app sched=0/0 handle=0xd7f9d1e0\n"
+ + " | state=R schedstat=( 13249338 1928149 5 ) utm=0 stm=0 core=2 HZ=100\n"
+ + " | stack=0xd7ea2000-0xd7ea4000 stackSize=1008KB\n"
+ + " | held mutexes= \"mutator lock\"(shared held)\n"
+ + " native: #00 pc 00542d9e /apex/com.android.art/lib/libart.so (art::DumpNativeStack(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, int, BacktraceMap*, char const*, art::ArtMethod*, void*, bool)+110)\n"
+ + " native: #01 pc 006a0897 /apex/com.android.art/lib/libart.so (art::Thread::DumpStack(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, bool, BacktraceMap*, bool) const+1015)\n"
+ + " native: #02 pc 0069a171 /apex/com.android.art/lib/libart.so (art::Thread::Dump(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, bool, BacktraceMap*, bool) const+65)\n"
+ + " native: #03 pc 006c61b4 /apex/com.android.art/lib/libart.so (art::DumpCheckpoint::Run(art::Thread*)+1172)\n"
+ + " native: #04 pc 006bf266 /apex/com.android.art/lib/libart.so (art::ThreadList::RunCheckpoint(art::Closure*, art::Closure*)+630)\n"
+ + " native: #05 pc 006be1ce /apex/com.android.art/lib/libart.so (art::ThreadList::Dump(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, bool)+2446)\n"
+ + " native: #06 pc 006bd70c /apex/com.android.art/lib/libart.so (art::ThreadList::DumpForSigQuit(std::__1::basic_ostream<char, std::__1::char_traits<char> >&)+1644)\n"
+ + " native: #07 pc 0064d654 /apex/com.android.art/lib/libart.so (art::Runtime::DumpForSigQuit(std::__1::basic_ostream<char, std::__1::char_traits<char> >&)+212)\n"
+ + " native: #08 pc 00665b6a /apex/com.android.art/lib/libart.so (art::SignalCatcher::HandleSigQuit()+1818)\n"
+ + " native: #09 pc 0066496b /apex/com.android.art/lib/libart.so (art::SignalCatcher::Run(void*)+587)\n"
+ + " native: #10 pc 000e6974 /apex/com.android.runtime/lib/bionic/libc.so (__pthread_start(void*)+100)\n"
+ + " native: #11 pc 00078567 /apex/com.android.runtime/lib/bionic/libc.so (__start_thread+71)\n"
+ + " (no managed stack frames)\n"
+ + "\n"
+ + "\"main\" prio=5 tid=1 Sleeping\n"
+ + " | group=\"main\" sCount=1 dsCount=0 flags=1 obj=0x712b6c28 self=0xe2d41c10\n"
+ + " | sysTid=10849 nice=-10 cgrp=top-app sched=0/0 handle=0xf114a478\n"
+ + " | state=S schedstat=( 478587788 174448370 929 ) utm=34 stm=13 core=0 HZ=100\n"
+ + " | stack=0xff4d8000-0xff4da000 stackSize=8192KB\n"
+ + " | held mutexes=\n"
+ + " at java.lang.Thread.sleep(Native method)\n"
+ + " - sleeping on <0x0add3331> (a java.lang.Object)\n"
+ + " at java.lang.Thread.sleep(Thread.java:442)\n"
+ + " - locked <0x0add3331> (a java.lang.Object)\n"
+ + " at java.lang.Thread.sleep(Thread.java:358)\n"
+ + " at android.os.SystemClock.sleep(SystemClock.java:131)\n"
+ + " at org.chromium.chrome.browser.settings.SettingsActivity.onOptionsItemSelected(chromium-TrichromeChromeGoogle.aab-default-463700031:-1)\n"
+ + " at android.app.Activity.onMenuItemSelected(Activity.java:4269)\n"
+ + " at C11.onMenuItemSelected(chromium-TrichromeChromeGoogle.aab-default-463700031:-1)\n"
+ + " at Vd.onMenuItemSelected(chromium-TrichromeChromeGoogle.aab-default-463700031:-1)\n"
+ + " at oe.onMenuItemSelected(chromium-TrichromeChromeGoogle.aab-default-463700031:-1)\n"
+ + " at hV3.onClick(chromium-TrichromeChromeGoogle.aab-default-463700031:-1)\n"
+ + " at android.view.View.performClick(View.java:7448)\n"
+ + " at android.view.View.performClickInternal(View.java:7425)\n"
+ + " at android.view.View.access$3600(View.java:810)\n"
+ + " at android.view.View$PerformClick.run(View.java:28305)\n"
+ + " at android.os.Handler.handleCallback(Handler.java:938)\n"
+ + " at android.os.Handler.dispatchMessage(Handler.java:99)\n"
+ + " at android.os.Looper.loop(Looper.java:223)\n"
+ + " at android.app.ActivityThread.main(ActivityThread.java:7656)\n"
+ + " at java.lang.reflect.Method.invoke(Native method)\n"
+ + " at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)\n"
+ + " at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)\n"
+ + "\n"
+ + "\"ReferenceQueueDaemon\" daemon prio=5 tid=7 Waiting\n"
+ + " | group=\"system\" sCount=1 dsCount=0 flags=1 obj=0x134c0228 self=0xe2d47e10\n"
+ + " | sysTid=10872 nice=4 cgrp=top-app sched=0/0 handle=0xc2f251e0\n"
+ + " | state=S schedstat=( 1373918 4806489 4 ) utm=0 stm=0 core=1 HZ=100\n"
+ + " | stack=0xc2e22000-0xc2e24000 stackSize=1040KB\n"
+ + " | held mutexes=\n"
+ + " at java.lang.Object.wait(Native method)\n"
+ + " - waiting on <0x0eadea16> (a java.lang.Class<java.lang.ref.ReferenceQueue>)\n"
+ + " at java.lang.Object.wait(Object.java:442)\n"
+ + " at java.lang.Object.wait(Object.java:568)\n"
+ + " at java.lang.Daemons$ReferenceQueueDaemon.runInternal(Daemons.java:217)\n"
+ + " - locked <0x0eadea16> (a java.lang.Class<java.lang.ref.ReferenceQueue>)\n"
+ + " at java.lang.Daemons$Daemon.run(Daemons.java:139)\n"
+ + " at java.lang.Thread.run(Thread.java:923)\n"
+ + "\n"
+ + "\"FinalizerWatchdogDaemon\" daemon prio=5 tid=8 Waiting\n"
+ + " | group=\"system\" sCount=1 dsCount=0 flags=1 obj=0x134c02a0 self=0xe2d4a810\n"
+ + " | sysTid=10874 nice=4 cgrp=top-app sched=0/0 handle=0xc2d131e0\n"
+ + " | state=S schedstat=( 311400 4725185 4 ) utm=0 stm=0 core=1 HZ=100\n"
+ + " | stack=0xc2c10000-0xc2c12000 stackSize=1040KB\n"
+ + " | held mutexes=\n"
+ + " at java.lang.Object.wait(Native method)\n"
+ + " - waiting on <0x00638f97> (a java.lang.Daemons$FinalizerWatchdogDaemon)\n"
+ + " at java.lang.Object.wait(Object.java:442)\n"
+ + " at java.lang.Object.wait(Object.java:568)\n"
+ + " at java.lang.Daemons$FinalizerWatchdogDaemon.sleepUntilNeeded(Daemons.java:341)\n"
+ + " - locked <0x00638f97> (a java.lang.Daemons$FinalizerWatchdogDaemon)\n"
+ + " at java.lang.Daemons$FinalizerWatchdogDaemon.runInternal(Daemons.java:321)\n"
+ + " at java.lang.Daemons$Daemon.run(Daemons.java:139)\n"
+ + " at java.lang.Thread.run(Thread.java:923)\n"
+ + "\n"
+ + "\"Jit thread pool worker thread 0\" daemon prio=5 tid=9 Native\n"
+ + " | group=\"system\" sCount=1 dsCount=0 flags=1 obj=0x134c0318 self=0xe2d42a10\n"
+ + " | sysTid=10870 nice=0 cgrp=top-app sched=0/0 handle=0xd7e9fd60\n"
+ + " | state=S schedstat=( 544856613 44836261 101 ) utm=38 stm=15 core=1 HZ=100\n"
+ + " | stack=0xd7da1000-0xd7da3000 stackSize=1023KB\n"
+ + " | held mutexes=\n"
+ + " native: #00 pc 00000b97 [vdso] (__kernel_vsyscall+7)\n"
+ + " native: #01 pc 0005ad68 /apex/com.android.runtime/lib/bionic/libc.so (syscall+40)\n"
+ + " native: #02 pc 001d82ec /apex/com.android.art/lib/libart.so (art::ConditionVariable::WaitHoldingLocks(art::Thread*)+108)\n"
+ + " native: #03 pc 001d8273 /apex/com.android.art/lib/libart.so (art::ConditionVariable::Wait(art::Thread*)+35)\n"
+ + " native: #04 pc 006c838f /apex/com.android.art/lib/libart.so (art::ThreadPool::GetTask(art::Thread*)+143)\n"
+ + " native: #05 pc 006c73e5 /apex/com.android.art/lib/libart.so (art::ThreadPoolWorker::Run()+133)\n"
+ + " native: #06 pc 006c6e9d /apex/com.android.art/lib/libart.so (art::ThreadPoolWorker::Callback(void*)+269)\n"
+ + " native: #07 pc 000e6974 /apex/com.android.runtime/lib/bionic/libc.so (__pthread_start(void*)+100)\n"
+ + " native: #08 pc 00078567 /apex/com.android.runtime/lib/bionic/libc.so (__start_thread+71)\n"
+ + " (no managed stack frames)\n"
+ + "\n"
+ + "\"HeapTaskDaemon\" daemon prio=5 tid=10 WaitingForTaskProcessor\n"
+ + " | group=\"system\" sCount=1 dsCount=0 flags=1 obj=0x134c1470 self=0xe2d45410\n"
+ + " | sysTid=10871 nice=4 cgrp=top-app sched=0/0 handle=0xd7d9b1e0\n"
+ + " | state=S schedstat=( 24497375 5430499 8 ) utm=2 stm=0 core=1 HZ=100\n"
+ + " | stack=0xd7c98000-0xd7c9a000 stackSize=1040KB\n"
+ + " | held mutexes=\n"
+ + " native: #00 pc 00000b97 [vdso] (__kernel_vsyscall+7)\n"
+ + " native: #01 pc 0005ad68 /apex/com.android.runtime/lib/bionic/libc.so (syscall+40)\n"
+ + " native: #02 pc 001d82ec /apex/com.android.art/lib/libart.so (art::ConditionVariable::WaitHoldingLocks(art::Thread*)+108)\n"
+ + " native: #03 pc 001d8273 /apex/com.android.art/lib/libart.so (art::ConditionVariable::Wait(art::Thread*)+35)\n"
+ + " native: #04 pc 0034a036 /apex/com.android.art/lib/libart.so (art::gc::TaskProcessor::GetTask(art::Thread*)+630)\n"
+ + " native: #05 pc 0034aa64 /apex/com.android.art/lib/libart.so (art::gc::TaskProcessor::RunAllTasks(art::Thread*)+84)\n"
+ + " native: #06 pc 005591f5 /apex/com.android.art/lib/libart.so (art::VMRuntime_runHeapTasks(_JNIEnv*, _jobject*)+53)\n"
+ + " at dalvik.system.VMRuntime.runHeapTasks(Native method)\n"
+ + " at java.lang.Daemons$HeapTaskDaemon.runInternal(Daemons.java:531)\n"
+ + " at java.lang.Daemons$Daemon.run(Daemons.java:139)\n"
+ + " at java.lang.Thread.run(Thread.java:923)\n"
+ + "\n"
+ + "\"FinalizerDaemon\" daemon prio=5 tid=11 Waiting\n"
+ + " | group=\"system\" sCount=1 dsCount=0 flags=1 obj=0x134c0390 self=0xe2d40e10\n"
+ + " | sysTid=10873 nice=4 cgrp=top-app sched=0/0 handle=0xc2e1c1e0\n"
+ + " | state=S schedstat=( 1051441 5125750 4 ) utm=0 stm=0 core=3 HZ=100\n"
+ + " | stack=0xc2d19000-0xc2d1b000 stackSize=1040KB\n"
+ + " | held mutexes=\n"
+ + " at java.lang.Object.wait(Native method)\n"
+ + " - waiting on <0x05ee5584> (a java.lang.Object)\n"
+ + " at java.lang.Object.wait(Object.java:442)\n"
+ + " at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:190)\n"
+ + " - locked <0x05ee5584> (a java.lang.Object)\n"
+ + " at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:211)\n"
+ + " at java.lang.Daemons$FinalizerDaemon.runInternal(Daemons.java:273)\n"
+ + " at java.lang.Daemons$Daemon.run(Daemons.java:139)\n"
+ + " at java.lang.Thread.run(Thread.java:923)\n"
+ + "\n"
+ + "\"Binder:10849_1\" prio=5 tid=12 Native\n"
+ + " | group=\"main\" sCount=1 dsCount=0 flags=1 obj=0x134c0408 self=0xe2d4c410\n"
+ + " | sysTid=10875 nice=0 cgrp=top-app sched=0/0 handle=0xc2b0c1e0\n"
+ + " | state=S schedstat=( 607170 4411639 7 ) utm=0 stm=0 core=3 HZ=100\n"
+ + " | stack=0xc2a11000-0xc2a13000 stackSize=1008KB\n"
+ + " | held mutexes=\n"
+ + " native: #00 pc 00000b97 [vdso] (__kernel_vsyscall+7)\n"
+ + " native: #01 pc 000cd46c /apex/com.android.runtime/lib/bionic/libc.so (__ioctl+28)\n"
+ + " native: #02 pc 00080e6a /apex/com.android.runtime/lib/bionic/libc.so (ioctl+58)\n"
+ + " native: #03 pc 00050edb /system/lib/libbinder.so (android::IPCThreadState::talkWithDriver(bool)+331)\n"
+ + " native: #04 pc 0005117a /system/lib/libbinder.so (android::IPCThreadState::getAndExecuteCommand()+42)\n"
+ + " native: #05 pc 00051cb8 /system/lib/libbinder.so (android::IPCThreadState::joinThreadPool(bool)+72)\n"
+ + " native: #06 pc 0007e309 /system/lib/libbinder.so (android::PoolThread::threadLoop()+41)\n"
+ + " native: #07 pc 00015116 /system/lib/libutils.so (android::Thread::_threadLoop(void*)+374)\n"
+ + " native: #08 pc 00098fee /system/lib/libandroid_runtime.so (android::AndroidRuntime::javaThreadShell(void*)+174)\n"
+ + " native: #09 pc 000147d9 /system/lib/libutils.so (thread_data_t::trampoline(thread_data_t const*)+457)\n"
+ + " native: #10 pc 000e6974 /apex/com.android.runtime/lib/bionic/libc.so (__pthread_start(void*)+100)\n"
+ + " native: #11 pc 00078567 /apex/com.android.runtime/lib/bionic/libc.so (__start_thread+71)\n"
+ + " (no managed stack frames)\n"
+ + "\n"
+ + "\"Binder:10849_2\" prio=5 tid=13 Native\n"
+ + " | group=\"main\" sCount=1 dsCount=0 flags=1 obj=0x134c0480 self=0xe2d48c10\n"
+ + " | sysTid=10876 nice=0 cgrp=top-app sched=0/0 handle=0xc2a0b1e0\n"
+ + " | state=S schedstat=( 5272069 33206603 14 ) utm=0 stm=0 core=2 HZ=100\n"
+ + " | stack=0xc2910000-0xc2912000 stackSize=1008KB\n"
+ + " | held mutexes=\n"
+ + " native: #00 pc 00000b97 [vdso] (__kernel_vsyscall+7)\n"
+ + " native: #01 pc 000cd46c /apex/com.android.runtime/lib/bionic/libc.so (__ioctl+28)\n"
+ + " native: #02 pc 00080e6a /apex/com.android.runtime/lib/bionic/libc.so (ioctl+58)\n"
+ + " native: #03 pc 00050edb /system/lib/libbinder.so (android::IPCThreadState::talkWithDriver(bool)+331)\n"
+ + " native: #04 pc 0005117a /system/lib/libbinder.so (android::IPCThreadState::getAndExecuteCommand()+42)\n"
+ + " native: #05 pc 00051cb8 /system/lib/libbinder.so (android::IPCThreadState::joinThreadPool(bool)+72)\n"
+ + " native: #06 pc 0007e309 /system/lib/libbinder.so (android::PoolThread::threadLoop()+41)\n"
+ + " native: #07 pc 00015116 /system/lib/libutils.so (android::Thread::_threadLoop(void*)+374)\n"
+ + " native: #08 pc 00098fee /system/lib/libandroid_runtime.so (android::AndroidRuntime::javaThreadShell(void*)+174)\n"
+ + " native: #09 pc 000147d9 /system/lib/libutils.so (thread_data_t::trampoline(thread_data_t const*)+457)\n"
+ + " native: #10 pc 000e6974 /apex/com.android.runtime/lib/bionic/libc.so (__pthread_start(void*)+100)\n"
+ + " native: #11 pc 00078567 /apex/com.android.runtime/lib/bionic/libc.so (__start_thread+71)\n"
+ + " (no managed stack frames)\n"
+ + "\n"
+ + "\"Profile Saver\" daemon prio=5 tid=14 Native\n"
+ + " | group=\"system\" sCount=1 dsCount=0 flags=1 obj=0x134c04f8 self=0xe2d50a10\n"
+ + " | sysTid=10886 nice=9 cgrp=top-app sched=0/0 handle=0xc25931e0\n"
+ + " | state=S schedstat=( 7065834 1783772 21 ) utm=0 stm=0 core=3 HZ=100\n"
+ + " | stack=0xc2498000-0xc249a000 stackSize=1008KB\n"
+ + " | held mutexes=\n"
+ + " native: #00 pc 00000b97 [vdso] (__kernel_vsyscall+7)\n"
+ + " native: #01 pc 0005ad68 /apex/com.android.runtime/lib/bionic/libc.so (syscall+40)\n"
+ + " native: #02 pc 001d82ec /apex/com.android.art/lib/libart.so (art::ConditionVariable::WaitHoldingLocks(art::Thread*)+108)\n"
+ + " native: #03 pc 001d8273 /apex/com.android.art/lib/libart.so (art::ConditionVariable::Wait(art::Thread*)+35)\n"
+ + " native: #04 pc 003cc829 /apex/com.android.art/lib/libart.so (art::ProfileSaver::Run()+633)\n"
+ + " native: #05 pc 003d2e8f /apex/com.android.art/lib/libart.so (art::ProfileSaver::RunProfileSaverThread(void*)+175)\n"
+ + " native: #06 pc 000e6974 /apex/com.android.runtime/lib/bionic/libc.so (__pthread_start(void*)+100)\n"
+ + " native: #07 pc 00078567 /apex/com.android.runtime/lib/bionic/libc.so (__start_thread+71)\n"
+ + " (no managed stack frames)\n"
+ + "\n"
+ + "\"CrAsyncTask #1\" prio=5 tid=15 TimedWaiting\n"
+ + " | group=\"main\" sCount=1 dsCount=0 flags=1 obj=0x134c0570 self=0xe2d51810\n"
+ + " | sysTid=10889 nice=-1 cgrp=top-app sched=0/0 handle=0xc239b1e0\n"
+ + " | state=S schedstat=( 5906313 2046809 11 ) utm=0 stm=0 core=2 HZ=100\n"
+ + " | stack=0xc2298000-0xc229a000 stackSize=1040KB\n"
+ + " | held mutexes=\n"
+ + " at sun.misc.Unsafe.park(Native method)\n"
+ + " - waiting on an unknown object\n"
+ + " at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:230)\n"
+ + " at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2109)\n"
+ + " at java.util.concurrent.ArrayBlockingQueue.poll(ArrayBlockingQueue.java:402)\n"
+ + " at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1091)\n"
+ + " at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1152)\n"
+ + " at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)\n"
+ + " at p00.run(chromium-TrichromeChromeGoogle.aab-default-463700031:-1)\n"
+ + " at java.lang.Thread.run(Thread.java:923)\n"
+ + "\n"
+ + "\"CrAsyncTask #2\" prio=5 tid=16 TimedWaiting\n"
+ + " | group=\"main\" sCount=1 dsCount=0 flags=1 obj=0x134c0790 self=0xe2d4ee10\n"
+ + " | sysTid=10894 nice=10 cgrp=top-app sched=0/0 handle=0xc1b511e0\n"
+ + " | state=S schedstat=( 1434137 8412443 14 ) utm=0 stm=0 core=2 HZ=100\n"
+ + " | stack=0xc1a4e000-0xc1a50000 stackSize=1040KB\n"
+ + " | held mutexes=\n"
+ + " at sun.misc.Unsafe.park(Native method)\n"
+ + " - waiting on an unknown object\n"
+ + " at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:230)\n"
+ + " at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2109)\n"
+ + " at java.util.concurrent.ArrayBlockingQueue.poll(ArrayBlockingQueue.java:402)\n"
+ + " at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1091)\n"
+ + " at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1152)\n"
+ + " at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)\n"
+ + " at p00.run(chromium-TrichromeChromeGoogle.aab-default-463700031:-1)\n"
+ + " at java.lang.Thread.run(Thread.java:923)\n"
+ + "\n"
+ + "\"RenderThread\" daemon prio=7 tid=19 Native\n"
+ + " | group=\"main\" sCount=1 dsCount=0 flags=1 obj=0x134c0c70 self=0xe2d4fc10\n"
+ + " | sysTid=10898 nice=-10 cgrp=top-app sched=0/0 handle=0xc193f1e0\n"
+ + " | state=S schedstat=( 2602000672 50772536 773 ) utm=30 stm=229 core=3 HZ=100\n"
+ + " | stack=0xc1844000-0xc1846000 stackSize=1008KB\n"
+ + " | held mutexes=\n"
+ + " native: #00 pc 00000b99 [vdso] (__kernel_vsyscall+9)\n"
+ + " native: #01 pc 000cf2cb /apex/com.android.runtime/lib/bionic/libc.so (__epoll_pwait+43)\n"
+ + " native: #02 pc 00088f9d /apex/com.android.runtime/lib/bionic/libc.so (epoll_wait+45)\n"
+ + " native: #03 pc 0001a003 /system/lib/libutils.so (android::Looper::pollInner(int)+259)\n"
+ + " native: #04 pc 00019e96 /system/lib/libutils.so (android::Looper::pollOnce(int, int*, int*, void**)+118)\n"
+ + " native: #05 pc 002452c5 /system/lib/libhwui.so (android::uirenderer::ThreadBase::waitForWork()+149)\n"
+ + " native: #06 pc 0026cab7 /system/lib/libhwui.so (android::uirenderer::renderthread::RenderThread::threadLoop()+119)\n"
+ + " native: #07 pc 00015116 /system/lib/libutils.so (android::Thread::_threadLoop(void*)+374)\n"
+ + " native: #08 pc 000147d9 /system/lib/libutils.so (thread_data_t::trampoline(thread_data_t const*)+457)\n"
+ + " native: #09 pc 000e6974 /apex/com.android.runtime/lib/bionic/libc.so (__pthread_start(void*)+100)\n"
+ + " native: #10 pc 00078567 /apex/com.android.runtime/lib/bionic/libc.so (__start_thread+71)\n"
+ + " (no managed stack frames)\n"
+ + "\n"
+ + "\"CrAsyncTask #3\" prio=5 tid=20 TimedWaiting\n"
+ + " | group=\"main\" sCount=1 dsCount=0 flags=1 obj=0x134c0ce8 self=0xe2d52610\n"
+ + " | sysTid=10901 nice=10 cgrp=top-app sched=0/0 handle=0xc16471e0\n"
+ + " | state=S schedstat=( 43937569 28546608 85 ) utm=4 stm=0 core=0 HZ=100\n"
+ + " | stack=0xc1544000-0xc1546000 stackSize=1040KB\n"
+ + " | held mutexes=\n"
+ + " at sun.misc.Unsafe.park(Native method)\n"
+ + " - waiting on an unknown object\n"
+ + " at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:230)\n"
+ + " at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2109)\n"
+ + " at java.util.concurrent.ArrayBlockingQueue.poll(ArrayBlockingQueue.java:402)\n"
+ + " at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1091)\n"
+ + " at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1152)\n"
+ + " at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)\n"
+ + " at p00.run(chromium-TrichromeChromeGoogle.aab-default-463700031:-1)\n"
+ + " at java.lang.Thread.run(Thread.java:923)\n"
+ + "\n"
+ + "\"GmsDynamite\" prio=5 tid=21 Waiting\n"
+ + " | group=\"dynamiteLoader\" sCount=1 dsCount=0 flags=1 obj=0x134c0dc0 self=0xe2d57a10\n"
+ + " | sysTid=10904 nice=19 cgrp=top-app sched=0/0 handle=0xb50281e0\n"
+ + " | state=S schedstat=( 293737 4529784 3 ) utm=0 stm=0 core=3 HZ=100\n"
+ + " | stack=0xb4f25000-0xb4f27000 stackSize=1040KB\n"
+ + " | held mutexes=\n"
+ + " at java.lang.Object.wait(Native method)\n"
+ + " - waiting on <0x0ca0d16d> (a vE0)\n"
+ + " at java.lang.Object.wait(Object.java:442)\n"
+ + " at java.lang.Object.wait(Object.java:568)\n"
+ + " at vE0.run(chromium-TrichromeChromeGoogle.aab-default-463700031:-1)\n"
+ + " - locked <0x0ca0d16d> (a vE0)\n"
+ + "\n"
+ + "\"queued-work-looper\" prio=5 tid=22 Native\n"
+ + " | group=\"main\" sCount=1 dsCount=0 flags=1 obj=0x134c0f68 self=0xe2d58810\n"
+ + " | sysTid=10911 nice=-2 cgrp=top-app sched=0/0 handle=0xc14d61e0\n"
+ + " | state=S schedstat=( 10225849 983976 22 ) utm=0 stm=0 core=1 HZ=100\n"
+ + " | stack=0xc13d3000-0xc13d5000 stackSize=1040KB\n"
+ + " | held mutexes=\n"
+ + " native: #08 pc 02364017 /data/app/~~VozU4lWeE_mDx8UNcfmuYg==/com.google.android.trichromelibrary.debug_463700031-WKdKLOoLSzICU5jkoCrpsA==/base.apk!libmonochrome.so (offset 65c000) (???)\n"
+ + " (no managed stack frames)\n"
+ + "\n"
+ + "\"ThreadPoolForeg\" prio=5 tid=25 Native\n"
+ + " | group=\"main\" sCount=1 dsCount=0 flags=1 obj=0x134c1138 self=0xe2d56c10\n"
+ + " | sysTid=10917 nice=0 cgrp=top-app sched=0/0 handle=0xbff171e0\n"
+ + " | state=S schedstat=( 34339976 115169857 451 ) utm=2 stm=1 core=2 HZ=100\n"
+ + " | stack=0xbfe1c000-0xbfe1e000 stackSize=1008KB\n"
+ + " | held mutexes=\n"
+ + " native: #00 pc 00000b99 [vdso] (__kernel_vsyscall+9)\n"
+ + " native: #05 pc 023713dc /data/app/~~VozU4lWeE_mDx8UNcfmuYg==/com.google.android.trichromelibrary.debug_463700031-WKdKLOoLSzICU5jkoCrpsA==/base.apk!libmonochrome.so (offset 65c000) (???)\n"
+ + " native: #06 pc 0236dee1 /data/app/~~VozU4lWeE_mDx8UNcfmuYg==/com.google.android.trichromelibrary.debug_463700031-WKdKLOoLSzICU5jkoCrpsA==/base.apk!libmonochrome.so (offset 65c000) (???)\n"
+ + " native: #07 pc 0231f2c5 /data/app/~~VozU4lWeE_mDx8UNcfmuYg==/com.google.android.trichromelibrary.debug_463700031-WKdKLOoLSzICU5jkoCrpsA==/base.apk!libmonochrome.so (offset 65c000) (???)\n"
+ + " native: #08 pc 02364017 /data/app/~~VozU4lWeE_mDx8UNcfmuYg==/com.google.android.trichromelibrary.debug_463700031-WKdKLOoLSzICU5jkoCrpsA==/base.apk!libmonochrome.so (offset 65c000) (???)\n"
+ + " native: #09 pc 022fdf7f /data/app/~~VozU4lWeE_mDx8UNcfmuYg==/com.google.android.trichromelibrary.debug_463700031-WKdKLOoLSzICU5jkoCrpsA==/base.apk!libmonochrome.so (offset 65c000) (???)\n"
+ + " native: #10 pc 000e6974 /apex/com.android.runtime/lib/bionic/libc.so (__pthread_start(void*)+100)\n"
+ + " native: #11 pc 00078567 /apex/com.android.runtime/lib/bionic/libc.so (__start_thread+71)\n"
+ + " (no managed stack frames)\n"
+ + "\n"
+ + "\"GoogleApiHandler\" prio=5 tid=26 Native\n"
+ + " | group=\"main\" sCount=1 dsCount=0 flags=1 obj=0x134c11b0 self=0xe2d54210\n"
+ + " | sysTid=10930 nice=9 cgrp=top-app sched=0/0 handle=0xbf30b1e0\n"
+ + " | state=S schedstat=( 9053686 20157363 34 ) utm=0 stm=0 core=2 HZ=100\n"
+ + " | stack=0xbf208000-0xbf20a000 stackSize=1040KB\n"
+ + " | held mutexes=\n"
+ + " native: #00 pc 00000b99 [vdso] (__kernel_vsyscall+9)\n"
+ + " native: #01 pc 000cf2cb /apex/com.android.runtime/lib/bionic/libc.so (__epoll_pwait+43)\n"
+ + " native: #02 pc 00088f9d /apex/com.android.runtime/lib/bionic/libc.so (epoll_wait+45)\n"
+ + " native: #03 pc 0001a003 /system/lib/libutils.so (android::Looper::pollInner(int)+259)\n"
+ + " native: #04 pc 00019e96 /system/lib/libutils.so (android::Looper::pollOnce(int, int*, int*, void**)+118)\n"
+ + " native: #05 pc 0010ef8b /system/lib/libandroid_runtime.so (android::android_os_MessageQueue_nativePollOnce(_JNIEnv*, _jobject*, long long, int)+59)\n"
+ + " at android.os.MessageQueue.nativePollOnce(Native method)\n"
+ + " at android.os.MessageQueue.next(MessageQueue.java:335)\n"
+ + " at android.os.Looper.loop(Looper.java:183)\n"
+ + " at android.os.HandlerThread.run(HandlerThread.java:67)\n"
+ + "\n"
+ + "\"ThreadPoolForeg\" prio=5 tid=27 Native\n"
+ + " | group=\"main\" sCount=1 dsCount=0 flags=1 obj=0x134c1290 self=0xe2d5a410\n"
+ + " | sysTid=10923 nice=0 cgrp=top-app sched=0/0 handle=0xbf9111e0\n"
+ + " | state=S schedstat=( 7861103 15723367 24 ) utm=0 stm=0 core=3 HZ=100\n"
+ + " | stack=0xbf816000-0xbf818000 stackSize=1008KB\n"
+ + " | held mutexes=\n"
+ + " native: #00 pc 00000b99 [vdso] (__kernel_vsyscall+9)\n"
+ + " native: #01 pc 0005ad68 /apex/com.android.runtime/lib/bionic/libc.so (syscall+40)\n"
+ + " native: #02 pc 0007725e /apex/com.android.runtime/lib/bionic/libc.so (__futex_wait_ex(void volatile*, bool, int, bool, timespec const*)+142)\n"
+ + " native: #03 pc 000e5bce /apex/com.android.runtime/lib/bionic/libc.so (pthread_cond_timedwait+110)\n"
+ + " native: #04 pc 0237955a /data/app/~~VozU4lWeE_mDx8UNcfmuYg==/com.google.android.trichromelibrary.debug_463700031-WKdKLOoLSzICU5jkoCrpsA==/base.apk!libmonochrome.so (offset 65c000) (???)\n"
+ + " native: #05 pc 023713dc /data/app/~~VozU4lWeE_mDx8UNcfmuYg==/com.google.android.trichromelibrary.debug_463700031-WKdKLOoLSzICU5jkoCrpsA==/base.apk!libmonochrome.so (offset 65c000) (???)\n"
+ + " native: #06 pc 0236dee1 /data/app/~~VozU4lWeE_mDx8UNcfmuYg==/com.google.android.trichromelibrary.debug_463700031-WKdKLOoLSzICU5jkoCrpsA==/base.apk!libmonochrome.so (offset 65c000) (???)\n"
+ + " native: #07 pc 0231f2c5 /data/app/~~VozU4lWeE_mDx8UNcfmuYg==/com.google.android.trichromelibrary.debug_463700031-WKdKLOoLSzICU5jkoCrpsA==/base.apk!libmonochrome.so (offset 65c000) (???)\n"
+ + " native: #08 pc 02364017 /data/app/~~VozU4lWeE_mDx8UNcfmuYg==/com.google.android.trichromelibrary.debug_463700031-WKdKLOoLSzICU5jkoCrpsA==/base.apk!libmonochrome.so (offset 65c000) (???)\n"
+ + " native: #09 pc 022fdf7f /data/app/~~VozU4lWeE_mDx8UNcfmuYg==/com.google.android.trichromelibrary.debug_463700031-WKdKLOoLSzICU5jkoCrpsA==/base.apk!libmonochrome.so (offset 65c000) (???)\n"
+ + " native: #10 pc 000e6974 /apex/com.android.runtime/lib/bionic/libc.so (__pthread_start(void*)+100)\n"
+ + " native: #11 pc 00078567 /apex/com.android.runtime/lib/bionic/libc.so (__start_thread+71)\n"
+ + " (no managed stack frames)\n"
+ + "\n"
+ + "\"ThreadPoolForeg\" prio=5 tid=28 Native\n"
+ + " | group=\"main\" sCount=1 dsCount=0 flags=1 obj=0x134c1308 self=0xe2d59610\n"
+ + " | sysTid=10921 nice=0 cgrp=top-app sched=0/0 handle=0xbfb131e0\n"
+ + " | state=S schedstat=( 5466001 16594180 28 ) utm=0 stm=0 core=1 HZ=100\n"
+ + " | stack=0xbfa18000-0xbfa1a000 stackSize=1008KB\n"
+ + " | held mutexes=\n"
+ + " native: #00 pc 00000b99 [vdso] (__kernel_vsyscall+9)\n"
+ + " native: #01 pc 0005ad68 /apex/com.android.runtime/lib/bionic/libc.so (syscall+40)\n"
+ + " native: #02 pc 0007725e /apex/com.android.runtime/lib/bionic/libc.so (__futex_wait_ex(void volatile*, bool, int, bool, timespec const*)+142)\n"
+ + " native: #03 pc 000e5bce /apex/com.android.runtime/lib/bionic/libc.so (pthread_cond_timedwait+110)\n"
+ + " native: #04 pc 0237955a /data/app/~~VozU4lWeE_mDx8UNcfmuYg==/com.google.android.trichromelibrary.debug_463700031-WKdKLOoLSzICU5jkoCrpsA==/base.apk!libmonochrome.so (offset 65c000) (???)\n"
+ + " native: #05 pc 023713dc /data/app/~~VozU4lWeE_mDx8UNcfmuYg==/com.google.android.trichromelibrary.debug_463700031-WKdKLOoLSzICU5jkoCrpsA==/base.apk!libmonochrome.so (offset 65c000) (???)\n"
+ + " native: #06 pc 0236dee1 /data/app/~~VozU4lWeE_mDx8UNcfmuYg==/com.google.android.trichromelibrary.debug_463700031-WKdKLOoLSzICU5jkoCrpsA==/base.apk!libmonochrome.so (offset 65c000) (???)\n"
+ + " native: #07 pc 0231f2c5 /data/app/~~VozU4lWeE_mDx8UNcfmuYg==/com.google.android.trichromelibrary.debug_463700031-WKdKLOoLSzICU5jkoCrpsA==/base.apk!libmonochrome.so (offset 65c000) (???)\n"
+ + " native: #08 pc 02364017 /data/app/~~VozU4lWeE_mDx8UNcfmuYg==/com.google.android.trichromelibrary.debug_463700031-WKdKLOoLSzICU5jkoCrpsA==/base.apk!libmonochrome.so (offset 65c000) (???)\n"
+ + " native: #09 pc 022fdf7f /data/app/~~VozU4lWeE_mDx8UNcfmuYg==/com.google.android.trichromelibrary.debug_463700031-WKdKLOoLSzICU5jkoCrpsA==/base.apk!libmonochrome.so (offset 65c000) (???)\n"
+ + " native: #10 pc 000e6974 /apex/com.android.runtime/lib/bionic/libc.so (__pthread_start(void*)+100)\n"
+ + " native: #11 pc 00078567 /apex/com.android.runtime/lib/bionic/libc.so (__start_thread+71)\n"
+ + " (no managed stack frames)\n"
+ + "\n"
+ + "\"Binder:10849_3\" prio=5 tid=29 Native\n"
+ + " | stack=0xbf107000-0xbf109000 stackSize=1008KB\n"
+ + " | held mutexes=\n"
+ + " native: #00 pc 00000b97 [vdso] (__kernel_vsyscall+7)\n"
+ + " native: #01 pc 000cd46c /apex/com.android.runtime/lib/bionic/libc.so (__ioctl+28)\n"
+ + " native: #02 pc 00080e6a /apex/com.android.runtime/lib/bionic/libc.so (ioctl+58)\n"
+ + " native: #03 pc 00050edb /system/lib/libbinder.so (android::IPCThreadState::talkWithDriver(bool)+331)\n"
+ + " native: #04 pc 0005117a /system/lib/libbinder.so (android::IPCThreadState::getAndExecuteCommand()+42)\n"
+ + " native: #05 pc 00051cb8 /system/lib/libbinder.so (android::IPCThreadState::joinThreadPool(bool)+72)\n"
+ + " native: #06 pc 0007e309 /system/lib/libbinder.so (android::PoolThread::threadLoop()+41)\n"
+ + " native: #07 pc 00015116 /system/lib/libutils.so (android::Thread::_threadLoop(void*)+374)\n"
+ + " native: #08 pc 00098fee /system/lib/libandroid_runtime.so (android::AndroidRuntime::javaThreadShell(void*)+174)\n"
+ + " native: #09 pc 000147d9 /system/lib/libutils.so (thread_data_t::trampoline(thread_data_t const*)+457)\n"
+ + " native: #10 pc 000e6974 /apex/com.android.runtime/lib/bionic/libc.so (__pthread_start(void*)+100)\n"
+ + " native: #11 pc 00078567 /apex/com.android.runtime/lib/bionic/libc.so (__start_thread+71)\n"
+ + " (no managed stack frames)\n"
+ + "\n"
+ + "\"ThreadPoolForeg\" prio=5 tid=30 Native\n"
+ + " | group=\"main\" sCount=1 dsCount=0 flags=1 obj=0x134c13f8 self=0xe2d5f810\n"
+ + " | sysTid=10924 nice=0 cgrp=top-app sched=0/0 handle=0xbf8101e0\n"
+ + " | state=S schedstat=( 13183111 66742760 36 ) utm=0 stm=0 core=2 HZ=100\n"
+ + " | stack=0xbf715000-0xbf717000 stackSize=1008KB\n"
+ + " | held mutexes=\n"
+ + " native: #00 pc 00000b99 [vdso] (__kernel_vsyscall+9)\n"
+ + " native: #01 pc 0005ad68 /apex/com.android.runtime/lib/bionic/libc.so (syscall+40)\n"
+ + " native: #02 pc 0007725e /apex/com.android.runtime/lib/bionic/libc.so (__futex_wait_ex(void volatile*, bool, int, bool, timespec const*)+142)\n"
+ + " native: #03 pc 000e5bce /apex/com.android.runtime/lib/bionic/libc.so (pthread_cond_timedwait+110)\n"
+ + " native: #04 pc 0237955a /data/app/~~VozU4lWeE_mDx8UNcfmuYg==/com.google.android.trichromelibrary.debug_463700031-WKdKLOoLSzICU5jkoCrpsA==/base.apk!libmonochrome.so (offset 65c000) (???)\n"
+ + " native: #05 pc 023713dc /data/app/~~VozU4lWeE_mDx8UNcfmuYg==/com.google.android.trichromelibrary.debug_463700031-WKdKLOoLSzICU5jkoCrpsA==/base.apk!libmonochrome.so (offset 65c000) (???)\n"
+ + " native: #06 pc 0236dee1 /data/app/~~VozU4lWeE_mDx8UNcfmuYg==/com.google.android.trichromelibrary.debug_463700031-WKdKLOoLSzICU5jkoCrpsA==/base.apk!libmonochrome.so (offset 65c000) (???)\n"
+ + " native: #07 pc 0231f2c5 /data/app/~~VozU4lWeE_mDx8UNcfmuYg==/com.google.android.trichromelibrary.debug_463700031-WKdKLOoLSzICU5jkoCrpsA==/base.apk!libmonochrome.so (offset 65c000) (???)\n"
+ + " native: #08 pc 02364017 /data/app/~~VozU4lWeE_mDx8UNcfmuYg==/com.google.android.trichromelibrary.debug_463700031-WKdKLOoLSzICU5jkoCrpsA==/base.apk!libmonochrome.so (offset 65c000) (???)\n"
+ + " native: #09 pc 022fdf7f /data/app/~~VozU4lWeE_mDx8UNcfmuYg==/com.google.android.trichromelibrary.debug_463700031-WKdKLOoLSzICU5jkoCrpsA==/base.apk!libmonochrome.so (offset 65c000) (???)\n"
+ + " native: #10 pc 000e6974 /apex/com.android.runtime/lib/bionic/libc.so (__pthread_start(void*)+100)\n"
+ + " native: #11 pc 00078567 /apex/com.android.runtime/lib/bionic/libc.so (__start_thread+71)\n"
+ + " (no managed stack frames)\n"
+ + "\n"
+ + " \"NetworkStatusListener\" prio=5 tid=31 Native\n"
+ + " | group=\"main\" sCount=1 dsCount=0 flags=1 obj=0x12c41780 self=0xe2d5ea10\n"
+ + " | sysTid=10940 nice=0 cgrp=top-app sched=0/0 handle=0xbedb41e0\n"
+ + " | state=S schedstat=( 6504387 4427985 21 ) utm=0 stm=0 core=0 HZ=100\n"
+ + " static final String PREAMBLE;\n"
+ + " static final String MAIN_THREAD_STACK_TRACES;\n"
+ + " static final String OTHER_STACK_TRACES;\n"
+ + "\n";
+
+ static final String PREAMBLE = "----- pid 10849 at 2021-09-28 15:41:53 -----\n"
+ + "Cmd line: com.google.android.apps.chrome\n"
+ + "Build fingerprint: 'google/sdk_gphone_x86/generic_x86_arm:11/RSR1.201013.001/6903271:user/release-keys'\n"
+ + "ABI: 'x86'\n"
+ + "Build type: optimized\n"
+ + "Zygote loaded classes=15746 post zygote classes=1796\n"
+ + "Dumping registered class loaders\n"
+ + "#0 dalvik.system.PathClassLoader: [], parent #1\n"
+ + "#1 java.lang.BootClassLoader: [], no parent\n"
+ + "#2 dalvik.system.PathClassLoader: [/data/app/~~vsJt6r0FRID_SGtfoYZfsw==/com.google.android.apps.chrome-elBS_VoQghHLRXEgGrwmbQ==/base.apk], parent #1\n"
+ + "#3 dalvik.system.PathClassLoader: [/data/app/~~VozU4lWeE_mDx8UNcfmuYg==/com.google.android.trichromelibrary.debug_463700031-WKdKLOoLSzICU5jkoCrpsA==/base.apk], parent #1\n"
+ + "#4 dalvik.system.PathClassLoader: [/data/app/~~vsJt6r0FRID_SGtfoYZfsw==/com.google.android.apps.chrome-elBS_VoQghHLRXEgGrwmbQ==/split_chrome.apk], parent #2\n"
+ + "#5 dalvik.system.DelegateLastClassLoader: [/data/user_de/0/com.google.android.gms/app_chimera/m/0000001a/DynamiteLoader.apk], parent #0\n"
+ + "#6 dalvik.system.DelegateLastClassLoader: [/data/user_de/0/com.google.android.gms/app_chimera/m/0000001d/GoogleCertificates.apk], parent #4\n"
+ + "Done dumping class loaders\n"
+ + "Classes initialized: 1391 in 79.445ms\n"
+ + "Intern table: 31916 strong; 520 weak\n"
+ + "JNI: CheckJNI is on; globals=798 (plus 43 weak)\n"
+ + "Libraries: /data/app/~~VozU4lWeE_mDx8UNcfmuYg==/com.google.android.trichromelibrary.debug_463700031-WKdKLOoLSzICU5jkoCrpsA==/base.apk!/lib/x86/libmonochrome.so /data/app/~~vsJt6r0FRID_SGtfoYZfsw==/com.google.android.apps.chrome-elBS_VoQghHLRXEgGrwmbQ==/base.apk!/lib/x86/libchromium_android_linker.so libandroid.so libaudioeffect_jni.so libcompiler_rt.so libicu_jni.so libjavacore.so libjavacrypto.so libjnigraphics.so libmedia_jni.so libopenjdk.so librs_jni.so libsfplugin_ccodec.so libsoundpool.so libstats_jni.so libwebviewchromium_loader.so (16)\n"
+ + "Heap: 87% free, 3559KB/26MB; 81403 objects\n"
+ + "Dumping cumulative Gc timings\n"
+ + "Average major GC reclaim bytes ratio inf over 0 GC cycles\n"
+ + "Average major GC copied live bytes ratio 0.723527 over 4 major GCs\n"
+ + "Cumulative bytes moved 11416448\n"
+ + "Cumulative objects moved 215864\n"
+ + "Peak regions allocated 35 (8960KB) / 768 (192MB)\n"
+ + "Start Dumping histograms for 1 iterations for young concurrent copying\n"
+ + "ProcessMarkStack: Sum: 9.613ms 99% C.I. 9.613ms-9.613ms Avg: 9.613ms Max: 9.613ms\n"
+ + "ScanImmuneSpaces: Sum: 4.390ms 99% C.I. 4.390ms-4.390ms Avg: 4.390ms Max: 4.390ms\n"
+ + "VisitConcurrentRoots: Sum: 2.118ms 99% C.I. 2.118ms-2.118ms Avg: 2.118ms Max: 2.118ms\n"
+ + "SweepSystemWeaks: Sum: 1.486ms 99% C.I. 1.486ms-1.486ms Avg: 1.486ms Max: 1.486ms\n"
+ + "ClearFromSpace: Sum: 1.095ms 99% C.I. 1.095ms-1.095ms Avg: 1.095ms Max: 1.095ms\n"
+ + "GrayAllDirtyImmuneObjects: Sum: 866us 99% C.I. 866us-866us Avg: 866us Max: 866us\n"
+ + "InitializePhase: Sum: 861us 99% C.I. 861us-861us Avg: 861us Max: 861us\n"
+ + "FlipOtherThreads: Sum: 414us 99% C.I. 414us-414us Avg: 414us Max: 414us\n"
+ + "ScanCardsForSpace: Sum: 249us 99% C.I. 249us-249us Avg: 249us Max: 249us\n"
+ + "VisitNonThreadRoots: Sum: 221us 99% C.I. 221us-221us Avg: 221us Max: 221us\n"
+ + "EnqueueFinalizerReferences: Sum: 207us 99% C.I. 207us-207us Avg: 207us Max: 207us\n"
+ + "SweepArray: Sum: 204us 99% C.I. 204us-204us Avg: 204us Max: 204us\n"
+ + "ProcessReferences: Sum: 117us 99% C.I. 1us-116us Avg: 58.500us Max: 116us\n"
+ + "RecordFree: Sum: 51us 99% C.I. 5us-46us Avg: 25.500us Max: 46us\n"
+ + "CopyingPhase: Sum: 48us 99% C.I. 48us-48us Avg: 48us Max: 48us\n"
+ + "FreeList: Sum: 45us 99% C.I. 45us-45us Avg: 45us Max: 45us\n"
+ + "(Paused)ClearCards: Sum: 39us 99% C.I. 0.250us-16us Avg: 3us Max: 16us\n"
+ + "MarkZygoteLargeObjects: Sum: 36us 99% C.I. 36us-36us Avg: 36us Max: 36us\n"
+ + "ThreadListFlip: Sum: 28us 99% C.I. 28us-28us Avg: 28us Max: 28us\n"
+ + "(Paused)GrayAllNewlyDirtyImmuneObjects: Sum: 26us 99% C.I. 26us-26us Avg: 26us Max: 26us\n"
+ + "ResetStack: Sum: 21us 99% C.I. 21us-21us Avg: 21us Max: 21us\n"
+ + "ReclaimPhase: Sum: 10us 99% C.I. 10us-10us Avg: 10us Max: 10us\n"
+ + "(Paused)SetFromSpace: Sum: 8us 99% C.I. 8us-8us Avg: 8us Max: 8us\n"
+ + "(Paused)FlipCallback: Sum: 6us 99% C.I. 6us-6us Avg: 6us Max: 6us\n"
+ + "UnBindBitmaps: Sum: 2us 99% C.I. 2us-2us Avg: 2us Max: 2us\n"
+ + "FlipThreadRoots: Sum: 1us 99% C.I. 1us-1us Avg: 1us Max: 1us\n"
+ + "Done Dumping histograms\n"
+ + "young concurrent copying paused: Sum: 105us 99% C.I. 105us-105us Avg: 105us Max: 105us\n"
+ + "young concurrent copying freed-bytes: Avg: 3768KB Max: 3768KB Min: 3768KB\n"
+ + "Freed-bytes histogram: 3520:1\n"
+ + "young concurrent copying total time: 22.235ms mean time: 22.235ms\n"
+ + "young concurrent copying freed: 52955 objects with total size 3768KB\n"
+ + "young concurrent copying throughput: 2.40705e+06/s / 167MB/s per cpu-time: 175419636/s / 167MB/s\n"
+ + "Average minor GC reclaim bytes ratio 0.905098 over 1 GC cycles\n"
+ + "Average minor GC copied live bytes ratio 0.218373 over 2 minor GCs\n"
+ + "Cumulative bytes moved 1933528\n"
+ + "Cumulative objects moved 34234\n"
+ + "Peak regions allocated 35 (8960KB) / 768 (192MB)\n"
+ + "Total time spent in GC: 22.235ms\n"
+ + "Mean GC size throughput: 165MB/s per cpu-time: 163MB/s\n"
+ + "Mean GC object throughput: 2.38161e+06 objects/s\n"
+ + "Total number of allocations 134358\n"
+ + "Total bytes allocated 7328KB\n"
+ + "Total bytes freed 3768KB\n"
+ + "Free memory 23MB\n"
+ + "Free memory until GC 23MB\n"
+ + "Free memory until OOME 188MB\n"
+ + "Total memory 26MB\n"
+ + "Max memory 192MB\n"
+ + "Zygote space size 3016KB\n"
+ + "Total mutator paused time: 105us\n"
+ + "Total time waiting for GC to complete: 2.938us\n"
+ + "Total GC count: 1\n"
+ + "Total GC time: 22.235ms\n"
+ + "Total blocking GC count: 0\n"
+ + "Total blocking GC time: 0\n"
+ + "Native bytes total: 18233624 registered: 279864\n"
+ + "Total native bytes at last GC: 18144188\n"
+ + "/system/framework/oat/x86/android.test.base.odex: quicken\n"
+ + "/data/app/~~vsJt6r0FRID_SGtfoYZfsw==/com.google.android.apps.chrome-elBS_VoQghHLRXEgGrwmbQ==/oat/x86/split_chrome.odex: speed-profile\n"
+ + "/system/framework/oat/x86/android.hidl.manager-V1.0-java.odex: quicken\n"
+ + "/system/framework/oat/x86/android.hidl.base-V1.0-java.odex: quicken\n"
+ + "/data/app/~~VozU4lWeE_mDx8UNcfmuYg==/com.google.android.trichromelibrary.debug_463700031-WKdKLOoLSzICU5jkoCrpsA==/oat/x86/base.odex: speed-profile\n"
+ + "/data/app/~~vsJt6r0FRID_SGtfoYZfsw==/com.google.android.apps.chrome-elBS_VoQghHLRXEgGrwmbQ==/oat/x86/split_extra_icu.odex: speed-profile\n"
+ + "/data/app/~~vsJt6r0FRID_SGtfoYZfsw==/com.google.android.apps.chrome-elBS_VoQghHLRXEgGrwmbQ==/oat/x86/base.odex: speed-profile\n"
+ + "Current JIT code cache size (used / resident): 82KB / 88KB\n"
+ + "Current JIT data cache size (used / resident): 51KB / 64KB\n"
+ + "Zygote JIT code cache size (at point of fork): 40KB / 44KB\n"
+ + "Zygote JIT data cache size (at point of fork): 30KB / 32KB\n"
+ + "Current JIT mini-debug-info size: 29KB\n"
+ + "Current JIT capacity: 256KB\n"
+ + "Current number of JIT JNI stub entries: 0\n"
+ + "Current number of JIT code cache entries: 90\n"
+ + "Total number of JIT compilations: 55\n"
+ + "Total number of JIT compilations for on stack replacement: 0\n"
+ + "Total number of JIT code cache collections: 2\n"
+ + "Memory used for stack maps: Avg: 356B Max: 2396B Min: 20B\n"
+ + "Memory used for compiled code: Avg: 1551B Max: 10KB Min: 82B\n"
+ + "Memory used for profiling info: Avg: 296B Max: 3116B Min: 20B\n"
+ + "Start Dumping histograms for 95 iterations for JIT timings\n"
+ + "Compiling: Sum: 585.229ms 99% C.I. 0.197ms-231.487ms Avg: 6.292ms Max: 411.532ms\n"
+ + "TrimMaps: Sum: 7.909ms 99% C.I. 19us-810.499us Avg: 85.043us Max: 908us\n"
+ + "Code cache collection: Sum: 5.340ms 99% C.I. 0.572ms-4.758ms Avg: 2.670ms Max: 4.768ms\n"
+ + "Done Dumping histograms\n"
+ + "Memory used for compilation: Avg: 112KB Max: 1087KB Min: 9680B\n"
+ + "ProfileSaver total_bytes_written=0\n"
+ + "ProfileSaver total_number_of_writes=0\n"
+ + "ProfileSaver total_number_of_code_cache_queries=0\n"
+ + "ProfileSaver total_number_of_skipped_writes=0\n"
+ + "ProfileSaver total_number_of_failed_writes=0\n"
+ + "ProfileSaver total_ms_of_sleep=5000\n"
+ + "ProfileSaver total_ms_of_work=0\n"
+ + "ProfileSaver total_number_of_hot_spikes=0\n"
+ + "ProfileSaver total_number_of_wake_ups=0\n"
+ + "Number of JIT inline cache deoptimizations: 3\n"
+ + "\n"
+ + "suspend all histogram: Sum: 90us 99% C.I. 1us-46us Avg: 10us Max: 46us\n"
+ + "DALVIK THREADS (25):\n";
+
+ static final String MAIN_THREAD_STACK_TRACE = "\"main\" prio=5 tid=1 Sleeping\n"
+ + " | group=\"main\" sCount=1 dsCount=0 flags=1 obj=0x712b6c28 self=0xe2d41c10\n"
+ + " | sysTid=10849 nice=-10 cgrp=top-app sched=0/0 handle=0xf114a478\n"
+ + " | state=S schedstat=( 478587788 174448370 929 ) utm=34 stm=13 core=0 HZ=100\n"
+ + " | stack=0xff4d8000-0xff4da000 stackSize=8192KB\n"
+ + " | held mutexes=\n"
+ + " at java.lang.Thread.sleep(Native method)\n"
+ + " - sleeping on <0x0add3331> (a java.lang.Object)\n"
+ + " at java.lang.Thread.sleep(Thread.java:442)\n"
+ + " - locked <0x0add3331> (a java.lang.Object)\n"
+ + " at java.lang.Thread.sleep(Thread.java:358)\n"
+ + " at android.os.SystemClock.sleep(SystemClock.java:131)\n"
+ + " at org.chromium.chrome.browser.settings.SettingsActivity.onOptionsItemSelected(chromium-TrichromeChromeGoogle.aab-default-463700031:-1)\n"
+ + " at android.app.Activity.onMenuItemSelected(Activity.java:4269)\n"
+ + " at C11.onMenuItemSelected(chromium-TrichromeChromeGoogle.aab-default-463700031:-1)\n"
+ + " at Vd.onMenuItemSelected(chromium-TrichromeChromeGoogle.aab-default-463700031:-1)\n"
+ + " at oe.onMenuItemSelected(chromium-TrichromeChromeGoogle.aab-default-463700031:-1)\n"
+ + " at hV3.onClick(chromium-TrichromeChromeGoogle.aab-default-463700031:-1)\n"
+ + " at android.view.View.performClick(View.java:7448)\n"
+ + " at android.view.View.performClickInternal(View.java:7425)\n"
+ + " at android.view.View.access$3600(View.java:810)\n"
+ + " at android.view.View$PerformClick.run(View.java:28305)\n"
+ + " at android.os.Handler.handleCallback(Handler.java:938)\n"
+ + " at android.os.Handler.dispatchMessage(Handler.java:99)\n"
+ + " at android.os.Looper.loop(Looper.java:223)\n"
+ + " at android.app.ActivityThread.main(ActivityThread.java:7656)\n"
+ + " at java.lang.reflect.Method.invoke(Native method)\n"
+ + " at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)\n"
+ + " at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)\n"
+ + "\n";
+
+ static final String OTHER_STACK_TRACES = "\"Signal Catcher\" daemon prio=10 tid=6 Runnable\n"
+ + " | group=\"system\" sCount=0 dsCount=0 flags=0 obj=0x134c01b0 self=0xe2d44610\n"
+ + " | sysTid=10865 nice=-20 cgrp=top-app sched=0/0 handle=0xd7f9d1e0\n"
+ + " | state=R schedstat=( 13249338 1928149 5 ) utm=0 stm=0 core=2 HZ=100\n"
+ + " | stack=0xd7ea2000-0xd7ea4000 stackSize=1008KB\n"
+ + " | held mutexes= \"mutator lock\"(shared held)\n"
+ + " native: #00 pc 00542d9e /apex/com.android.art/lib/libart.so (art::DumpNativeStack(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, int, BacktraceMap*, char const*, art::ArtMethod*, void*, bool)+110)\n"
+ + " native: #01 pc 006a0897 /apex/com.android.art/lib/libart.so (art::Thread::DumpStack(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, bool, BacktraceMap*, bool) const+1015)\n"
+ + " native: #02 pc 0069a171 /apex/com.android.art/lib/libart.so (art::Thread::Dump(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, bool, BacktraceMap*, bool) const+65)\n"
+ + " native: #03 pc 006c61b4 /apex/com.android.art/lib/libart.so (art::DumpCheckpoint::Run(art::Thread*)+1172)\n"
+ + " native: #04 pc 006bf266 /apex/com.android.art/lib/libart.so (art::ThreadList::RunCheckpoint(art::Closure*, art::Closure*)+630)\n"
+ + " native: #05 pc 006be1ce /apex/com.android.art/lib/libart.so (art::ThreadList::Dump(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, bool)+2446)\n"
+ + " native: #06 pc 006bd70c /apex/com.android.art/lib/libart.so (art::ThreadList::DumpForSigQuit(std::__1::basic_ostream<char, std::__1::char_traits<char> >&)+1644)\n"
+ + " native: #07 pc 0064d654 /apex/com.android.art/lib/libart.so (art::Runtime::DumpForSigQuit(std::__1::basic_ostream<char, std::__1::char_traits<char> >&)+212)\n"
+ + " native: #08 pc 00665b6a /apex/com.android.art/lib/libart.so (art::SignalCatcher::HandleSigQuit()+1818)\n"
+ + " native: #09 pc 0066496b /apex/com.android.art/lib/libart.so (art::SignalCatcher::Run(void*)+587)\n"
+ + " native: #10 pc 000e6974 /apex/com.android.runtime/lib/bionic/libc.so (__pthread_start(void*)+100)\n"
+ + " native: #11 pc 00078567 /apex/com.android.runtime/lib/bionic/libc.so (__start_thread+71)\n"
+ + " (no managed stack frames)\n"
+ + "\n"
+ + "\"ReferenceQueueDaemon\" daemon prio=5 tid=7 Waiting\n"
+ + " | group=\"system\" sCount=1 dsCount=0 flags=1 obj=0x134c0228 self=0xe2d47e10\n"
+ + " | sysTid=10872 nice=4 cgrp=top-app sched=0/0 handle=0xc2f251e0\n"
+ + " | state=S schedstat=( 1373918 4806489 4 ) utm=0 stm=0 core=1 HZ=100\n"
+ + " | stack=0xc2e22000-0xc2e24000 stackSize=1040KB\n"
+ + " | held mutexes=\n"
+ + " at java.lang.Object.wait(Native method)\n"
+ + " - waiting on <0x0eadea16> (a java.lang.Class<java.lang.ref.ReferenceQueue>)\n"
+ + " at java.lang.Object.wait(Object.java:442)\n"
+ + " at java.lang.Object.wait(Object.java:568)\n"
+ + " at java.lang.Daemons$ReferenceQueueDaemon.runInternal(Daemons.java:217)\n"
+ + " - locked <0x0eadea16> (a java.lang.Class<java.lang.ref.ReferenceQueue>)\n"
+ + " at java.lang.Daemons$Daemon.run(Daemons.java:139)\n"
+ + " at java.lang.Thread.run(Thread.java:923)\n"
+ + "\n"
+ + "\"FinalizerWatchdogDaemon\" daemon prio=5 tid=8 Waiting\n"
+ + " | group=\"system\" sCount=1 dsCount=0 flags=1 obj=0x134c02a0 self=0xe2d4a810\n"
+ + " | sysTid=10874 nice=4 cgrp=top-app sched=0/0 handle=0xc2d131e0\n"
+ + " | state=S schedstat=( 311400 4725185 4 ) utm=0 stm=0 core=1 HZ=100\n"
+ + " | stack=0xc2c10000-0xc2c12000 stackSize=1040KB\n"
+ + " | held mutexes=\n"
+ + " at java.lang.Object.wait(Native method)\n"
+ + " - waiting on <0x00638f97> (a java.lang.Daemons$FinalizerWatchdogDaemon)\n"
+ + " at java.lang.Object.wait(Object.java:442)\n"
+ + " at java.lang.Object.wait(Object.java:568)\n"
+ + " at java.lang.Daemons$FinalizerWatchdogDaemon.sleepUntilNeeded(Daemons.java:341)\n"
+ + " - locked <0x00638f97> (a java.lang.Daemons$FinalizerWatchdogDaemon)\n"
+ + " at java.lang.Daemons$FinalizerWatchdogDaemon.runInternal(Daemons.java:321)\n"
+ + " at java.lang.Daemons$Daemon.run(Daemons.java:139)\n"
+ + " at java.lang.Thread.run(Thread.java:923)\n"
+ + "\n"
+ + "\"Jit thread pool worker thread 0\" daemon prio=5 tid=9 Native\n"
+ + " | group=\"system\" sCount=1 dsCount=0 flags=1 obj=0x134c0318 self=0xe2d42a10\n"
+ + " | sysTid=10870 nice=0 cgrp=top-app sched=0/0 handle=0xd7e9fd60\n"
+ + " | state=S schedstat=( 544856613 44836261 101 ) utm=38 stm=15 core=1 HZ=100\n"
+ + " | stack=0xd7da1000-0xd7da3000 stackSize=1023KB\n"
+ + " | held mutexes=\n"
+ + " native: #00 pc 00000b97 [vdso] (__kernel_vsyscall+7)\n"
+ + " native: #01 pc 0005ad68 /apex/com.android.runtime/lib/bionic/libc.so (syscall+40)\n"
+ + " native: #02 pc 001d82ec /apex/com.android.art/lib/libart.so (art::ConditionVariable::WaitHoldingLocks(art::Thread*)+108)\n"
+ + " native: #03 pc 001d8273 /apex/com.android.art/lib/libart.so (art::ConditionVariable::Wait(art::Thread*)+35)\n"
+ + " native: #04 pc 006c838f /apex/com.android.art/lib/libart.so (art::ThreadPool::GetTask(art::Thread*)+143)\n"
+ + " native: #05 pc 006c73e5 /apex/com.android.art/lib/libart.so (art::ThreadPoolWorker::Run()+133)\n"
+ + " native: #06 pc 006c6e9d /apex/com.android.art/lib/libart.so (art::ThreadPoolWorker::Callback(void*)+269)\n"
+ + " native: #07 pc 000e6974 /apex/com.android.runtime/lib/bionic/libc.so (__pthread_start(void*)+100)\n"
+ + " native: #08 pc 00078567 /apex/com.android.runtime/lib/bionic/libc.so (__start_thread+71)\n"
+ + " (no managed stack frames)\n"
+ + "\n"
+ + "\"HeapTaskDaemon\" daemon prio=5 tid=10 WaitingForTaskProcessor\n"
+ + " | group=\"system\" sCount=1 dsCount=0 flags=1 obj=0x134c1470 self=0xe2d45410\n"
+ + " | sysTid=10871 nice=4 cgrp=top-app sched=0/0 handle=0xd7d9b1e0\n"
+ + " | state=S schedstat=( 24497375 5430499 8 ) utm=2 stm=0 core=1 HZ=100\n"
+ + " | stack=0xd7c98000-0xd7c9a000 stackSize=1040KB\n"
+ + " | held mutexes=\n"
+ + " native: #00 pc 00000b97 [vdso] (__kernel_vsyscall+7)\n"
+ + " native: #01 pc 0005ad68 /apex/com.android.runtime/lib/bionic/libc.so (syscall+40)\n"
+ + " native: #02 pc 001d82ec /apex/com.android.art/lib/libart.so (art::ConditionVariable::WaitHoldingLocks(art::Thread*)+108)\n"
+ + " native: #03 pc 001d8273 /apex/com.android.art/lib/libart.so (art::ConditionVariable::Wait(art::Thread*)+35)\n"
+ + " native: #04 pc 0034a036 /apex/com.android.art/lib/libart.so (art::gc::TaskProcessor::GetTask(art::Thread*)+630)\n"
+ + " native: #05 pc 0034aa64 /apex/com.android.art/lib/libart.so (art::gc::TaskProcessor::RunAllTasks(art::Thread*)+84)\n"
+ + " native: #06 pc 005591f5 /apex/com.android.art/lib/libart.so (art::VMRuntime_runHeapTasks(_JNIEnv*, _jobject*)+53)\n"
+ + " at dalvik.system.VMRuntime.runHeapTasks(Native method)\n"
+ + " at java.lang.Daemons$HeapTaskDaemon.runInternal(Daemons.java:531)\n"
+ + " at java.lang.Daemons$Daemon.run(Daemons.java:139)\n"
+ + " at java.lang.Thread.run(Thread.java:923)\n"
+ + "\n"
+ + "\"FinalizerDaemon\" daemon prio=5 tid=11 Waiting\n"
+ + " | group=\"system\" sCount=1 dsCount=0 flags=1 obj=0x134c0390 self=0xe2d40e10\n"
+ + " | sysTid=10873 nice=4 cgrp=top-app sched=0/0 handle=0xc2e1c1e0\n"
+ + " | state=S schedstat=( 1051441 5125750 4 ) utm=0 stm=0 core=3 HZ=100\n"
+ + " | stack=0xc2d19000-0xc2d1b000 stackSize=1040KB\n"
+ + " | held mutexes=\n"
+ + " at java.lang.Object.wait(Native method)\n"
+ + " - waiting on <0x05ee5584> (a java.lang.Object)\n"
+ + " at java.lang.Object.wait(Object.java:442)\n"
+ + " at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:190)\n"
+ + " - locked <0x05ee5584> (a java.lang.Object)\n"
+ + " at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:211)\n"
+ + " at java.lang.Daemons$FinalizerDaemon.runInternal(Daemons.java:273)\n"
+ + " at java.lang.Daemons$Daemon.run(Daemons.java:139)\n"
+ + " at java.lang.Thread.run(Thread.java:923)\n"
+ + "\n"
+ + "\"Binder:10849_1\" prio=5 tid=12 Native\n"
+ + " | group=\"main\" sCount=1 dsCount=0 flags=1 obj=0x134c0408 self=0xe2d4c410\n"
+ + " | sysTid=10875 nice=0 cgrp=top-app sched=0/0 handle=0xc2b0c1e0\n"
+ + " | state=S schedstat=( 607170 4411639 7 ) utm=0 stm=0 core=3 HZ=100\n"
+ + " | stack=0xc2a11000-0xc2a13000 stackSize=1008KB\n"
+ + " | held mutexes=\n"
+ + " native: #00 pc 00000b97 [vdso] (__kernel_vsyscall+7)\n"
+ + " native: #01 pc 000cd46c /apex/com.android.runtime/lib/bionic/libc.so (__ioctl+28)\n"
+ + " native: #02 pc 00080e6a /apex/com.android.runtime/lib/bionic/libc.so (ioctl+58)\n"
+ + " native: #03 pc 00050edb /system/lib/libbinder.so (android::IPCThreadState::talkWithDriver(bool)+331)\n"
+ + " native: #04 pc 0005117a /system/lib/libbinder.so (android::IPCThreadState::getAndExecuteCommand()+42)\n"
+ + " native: #05 pc 00051cb8 /system/lib/libbinder.so (android::IPCThreadState::joinThreadPool(bool)+72)\n"
+ + " native: #06 pc 0007e309 /system/lib/libbinder.so (android::PoolThread::threadLoop()+41)\n"
+ + " native: #07 pc 00015116 /system/lib/libutils.so (android::Thread::_threadLoop(void*)+374)\n"
+ + " native: #08 pc 00098fee /system/lib/libandroid_runtime.so (android::AndroidRuntime::javaThreadShell(void*)+174)\n"
+ + " native: #09 pc 000147d9 /system/lib/libutils.so (thread_data_t::trampoline(thread_data_t const*)+457)\n"
+ + " native: #10 pc 000e6974 /apex/com.android.runtime/lib/bionic/libc.so (__pthread_start(void*)+100)\n"
+ + " native: #11 pc 00078567 /apex/com.android.runtime/lib/bionic/libc.so (__start_thread+71)\n"
+ + " (no managed stack frames)\n"
+ + "\n"
+ + "\"Binder:10849_2\" prio=5 tid=13 Native\n"
+ + " | group=\"main\" sCount=1 dsCount=0 flags=1 obj=0x134c0480 self=0xe2d48c10\n"
+ + " | sysTid=10876 nice=0 cgrp=top-app sched=0/0 handle=0xc2a0b1e0\n"
+ + " | state=S schedstat=( 5272069 33206603 14 ) utm=0 stm=0 core=2 HZ=100\n"
+ + " | stack=0xc2910000-0xc2912000 stackSize=1008KB\n"
+ + " | held mutexes=\n"
+ + " native: #00 pc 00000b97 [vdso] (__kernel_vsyscall+7)\n"
+ + " native: #01 pc 000cd46c /apex/com.android.runtime/lib/bionic/libc.so (__ioctl+28)\n"
+ + " native: #02 pc 00080e6a /apex/com.android.runtime/lib/bionic/libc.so (ioctl+58)\n"
+ + " native: #03 pc 00050edb /system/lib/libbinder.so (android::IPCThreadState::talkWithDriver(bool)+331)\n"
+ + " native: #04 pc 0005117a /system/lib/libbinder.so (android::IPCThreadState::getAndExecuteCommand()+42)\n"
+ + " native: #05 pc 00051cb8 /system/lib/libbinder.so (android::IPCThreadState::joinThreadPool(bool)+72)\n"
+ + " native: #06 pc 0007e309 /system/lib/libbinder.so (android::PoolThread::threadLoop()+41)\n"
+ + " native: #07 pc 00015116 /system/lib/libutils.so (android::Thread::_threadLoop(void*)+374)\n"
+ + " native: #08 pc 00098fee /system/lib/libandroid_runtime.so (android::AndroidRuntime::javaThreadShell(void*)+174)\n"
+ + " native: #09 pc 000147d9 /system/lib/libutils.so (thread_data_t::trampoline(thread_data_t const*)+457)\n"
+ + " native: #10 pc 000e6974 /apex/com.android.runtime/lib/bionic/libc.so (__pthread_start(void*)+100)\n"
+ + " native: #11 pc 00078567 /apex/com.android.runtime/lib/bionic/libc.so (__start_thread+71)\n"
+ + " (no managed stack frames)\n"
+ + "\n"
+ + "\"Profile Saver\" daemon prio=5 tid=14 Native\n"
+ + " | group=\"system\" sCount=1 dsCount=0 flags=1 obj=0x134c04f8 self=0xe2d50a10\n"
+ + " | sysTid=10886 nice=9 cgrp=top-app sched=0/0 handle=0xc25931e0\n"
+ + " | state=S schedstat=( 7065834 1783772 21 ) utm=0 stm=0 core=3 HZ=100\n"
+ + " | stack=0xc2498000-0xc249a000 stackSize=1008KB\n"
+ + " | held mutexes=\n"
+ + " native: #00 pc 00000b97 [vdso] (__kernel_vsyscall+7)\n"
+ + " native: #01 pc 0005ad68 /apex/com.android.runtime/lib/bionic/libc.so (syscall+40)\n"
+ + " native: #02 pc 001d82ec /apex/com.android.art/lib/libart.so (art::ConditionVariable::WaitHoldingLocks(art::Thread*)+108)\n"
+ + " native: #03 pc 001d8273 /apex/com.android.art/lib/libart.so (art::ConditionVariable::Wait(art::Thread*)+35)\n"
+ + " native: #04 pc 003cc829 /apex/com.android.art/lib/libart.so (art::ProfileSaver::Run()+633)\n"
+ + " native: #05 pc 003d2e8f /apex/com.android.art/lib/libart.so (art::ProfileSaver::RunProfileSaverThread(void*)+175)\n"
+ + " native: #06 pc 000e6974 /apex/com.android.runtime/lib/bionic/libc.so (__pthread_start(void*)+100)\n"
+ + " native: #07 pc 00078567 /apex/com.android.runtime/lib/bionic/libc.so (__start_thread+71)\n"
+ + " (no managed stack frames)\n"
+ + "\n"
+ + "\"CrAsyncTask #1\" prio=5 tid=15 TimedWaiting\n"
+ + " | group=\"main\" sCount=1 dsCount=0 flags=1 obj=0x134c0570 self=0xe2d51810\n"
+ + " | sysTid=10889 nice=-1 cgrp=top-app sched=0/0 handle=0xc239b1e0\n"
+ + " | state=S schedstat=( 5906313 2046809 11 ) utm=0 stm=0 core=2 HZ=100\n"
+ + " | stack=0xc2298000-0xc229a000 stackSize=1040KB\n"
+ + " | held mutexes=\n"
+ + " at sun.misc.Unsafe.park(Native method)\n"
+ + " - waiting on an unknown object\n"
+ + " at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:230)\n"
+ + " at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2109)\n"
+ + " at java.util.concurrent.ArrayBlockingQueue.poll(ArrayBlockingQueue.java:402)\n"
+ + " at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1091)\n"
+ + " at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1152)\n"
+ + " at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)\n"
+ + " at p00.run(chromium-TrichromeChromeGoogle.aab-default-463700031:-1)\n"
+ + " at java.lang.Thread.run(Thread.java:923)\n"
+ + "\n"
+ + "\"CrAsyncTask #2\" prio=5 tid=16 TimedWaiting\n"
+ + " | group=\"main\" sCount=1 dsCount=0 flags=1 obj=0x134c0790 self=0xe2d4ee10\n"
+ + " | sysTid=10894 nice=10 cgrp=top-app sched=0/0 handle=0xc1b511e0\n"
+ + " | state=S schedstat=( 1434137 8412443 14 ) utm=0 stm=0 core=2 HZ=100\n"
+ + " | stack=0xc1a4e000-0xc1a50000 stackSize=1040KB\n"
+ + " | held mutexes=\n"
+ + " at sun.misc.Unsafe.park(Native method)\n"
+ + " - waiting on an unknown object\n"
+ + " at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:230)\n"
+ + " at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2109)\n"
+ + " at java.util.concurrent.ArrayBlockingQueue.poll(ArrayBlockingQueue.java:402)\n"
+ + " at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1091)\n"
+ + " at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1152)\n"
+ + " at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)\n"
+ + " at p00.run(chromium-TrichromeChromeGoogle.aab-default-463700031:-1)\n"
+ + " at java.lang.Thread.run(Thread.java:923)\n"
+ + "\n"
+ + "\"RenderThread\" daemon prio=7 tid=19 Native\n"
+ + " | group=\"main\" sCount=1 dsCount=0 flags=1 obj=0x134c0c70 self=0xe2d4fc10\n"
+ + " | sysTid=10898 nice=-10 cgrp=top-app sched=0/0 handle=0xc193f1e0\n"
+ + " | state=S schedstat=( 2602000672 50772536 773 ) utm=30 stm=229 core=3 HZ=100\n"
+ + " | stack=0xc1844000-0xc1846000 stackSize=1008KB\n"
+ + " | held mutexes=\n"
+ + " native: #00 pc 00000b99 [vdso] (__kernel_vsyscall+9)\n"
+ + " native: #01 pc 000cf2cb /apex/com.android.runtime/lib/bionic/libc.so (__epoll_pwait+43)\n"
+ + " native: #02 pc 00088f9d /apex/com.android.runtime/lib/bionic/libc.so (epoll_wait+45)\n"
+ + " native: #03 pc 0001a003 /system/lib/libutils.so (android::Looper::pollInner(int)+259)\n"
+ + " native: #04 pc 00019e96 /system/lib/libutils.so (android::Looper::pollOnce(int, int*, int*, void**)+118)\n"
+ + " native: #05 pc 002452c5 /system/lib/libhwui.so (android::uirenderer::ThreadBase::waitForWork()+149)\n"
+ + " native: #06 pc 0026cab7 /system/lib/libhwui.so (android::uirenderer::renderthread::RenderThread::threadLoop()+119)\n"
+ + " native: #07 pc 00015116 /system/lib/libutils.so (android::Thread::_threadLoop(void*)+374)\n"
+ + " native: #08 pc 000147d9 /system/lib/libutils.so (thread_data_t::trampoline(thread_data_t const*)+457)\n"
+ + " native: #09 pc 000e6974 /apex/com.android.runtime/lib/bionic/libc.so (__pthread_start(void*)+100)\n"
+ + " native: #10 pc 00078567 /apex/com.android.runtime/lib/bionic/libc.so (__start_thread+71)\n"
+ + " (no managed stack frames)\n"
+ + "\n"
+ + "\"CrAsyncTask #3\" prio=5 tid=20 TimedWaiting\n"
+ + " | group=\"main\" sCount=1 dsCount=0 flags=1 obj=0x134c0ce8 self=0xe2d52610\n"
+ + " | sysTid=10901 nice=10 cgrp=top-app sched=0/0 handle=0xc16471e0\n"
+ + " | state=S schedstat=( 43937569 28546608 85 ) utm=4 stm=0 core=0 HZ=100\n"
+ + " | stack=0xc1544000-0xc1546000 stackSize=1040KB\n"
+ + " | held mutexes=\n"
+ + " at sun.misc.Unsafe.park(Native method)\n"
+ + " - waiting on an unknown object\n"
+ + " at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:230)\n"
+ + " at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2109)\n"
+ + " at java.util.concurrent.ArrayBlockingQueue.poll(ArrayBlockingQueue.java:402)\n"
+ + " at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1091)\n"
+ + " at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1152)\n"
+ + " at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)\n"
+ + " at p00.run(chromium-TrichromeChromeGoogle.aab-default-463700031:-1)\n"
+ + " at java.lang.Thread.run(Thread.java:923)\n"
+ + "\n"
+ + "\"GmsDynamite\" prio=5 tid=21 Waiting\n"
+ + " | group=\"dynamiteLoader\" sCount=1 dsCount=0 flags=1 obj=0x134c0dc0 self=0xe2d57a10\n"
+ + " | sysTid=10904 nice=19 cgrp=top-app sched=0/0 handle=0xb50281e0\n"
+ + " | state=S schedstat=( 293737 4529784 3 ) utm=0 stm=0 core=3 HZ=100\n"
+ + " | stack=0xb4f25000-0xb4f27000 stackSize=1040KB\n"
+ + " | held mutexes=\n"
+ + " at java.lang.Object.wait(Native method)\n"
+ + " - waiting on <0x0ca0d16d> (a vE0)\n"
+ + " at java.lang.Object.wait(Object.java:442)\n"
+ + " at java.lang.Object.wait(Object.java:568)\n"
+ + " at vE0.run(chromium-TrichromeChromeGoogle.aab-default-463700031:-1)\n"
+ + " - locked <0x0ca0d16d> (a vE0)\n"
+ + "\n"
+ + "\"queued-work-looper\" prio=5 tid=22 Native\n"
+ + " | group=\"main\" sCount=1 dsCount=0 flags=1 obj=0x134c0f68 self=0xe2d58810\n"
+ + " | sysTid=10911 nice=-2 cgrp=top-app sched=0/0 handle=0xc14d61e0\n"
+ + " | state=S schedstat=( 10225849 983976 22 ) utm=0 stm=0 core=1 HZ=100\n"
+ + " | stack=0xc13d3000-0xc13d5000 stackSize=1040KB\n"
+ + " | held mutexes=\n"
+ + " native: #08 pc 02364017 /data/app/~~VozU4lWeE_mDx8UNcfmuYg==/com.google.android.trichromelibrary.debug_463700031-WKdKLOoLSzICU5jkoCrpsA==/base.apk!libmonochrome.so (offset 65c000) (???)\n"
+ + " (no managed stack frames)\n"
+ + "\n"
+ + "\"ThreadPoolForeg\" prio=5 tid=25 Native\n"
+ + " | group=\"main\" sCount=1 dsCount=0 flags=1 obj=0x134c1138 self=0xe2d56c10\n"
+ + " | sysTid=10917 nice=0 cgrp=top-app sched=0/0 handle=0xbff171e0\n"
+ + " | state=S schedstat=( 34339976 115169857 451 ) utm=2 stm=1 core=2 HZ=100\n"
+ + " | stack=0xbfe1c000-0xbfe1e000 stackSize=1008KB\n"
+ + " | held mutexes=\n"
+ + " native: #00 pc 00000b99 [vdso] (__kernel_vsyscall+9)\n"
+ + " native: #05 pc 023713dc /data/app/~~VozU4lWeE_mDx8UNcfmuYg==/com.google.android.trichromelibrary.debug_463700031-WKdKLOoLSzICU5jkoCrpsA==/base.apk!libmonochrome.so (offset 65c000) (???)\n"
+ + " native: #06 pc 0236dee1 /data/app/~~VozU4lWeE_mDx8UNcfmuYg==/com.google.android.trichromelibrary.debug_463700031-WKdKLOoLSzICU5jkoCrpsA==/base.apk!libmonochrome.so (offset 65c000) (???)\n"
+ + " native: #07 pc 0231f2c5 /data/app/~~VozU4lWeE_mDx8UNcfmuYg==/com.google.android.trichromelibrary.debug_463700031-WKdKLOoLSzICU5jkoCrpsA==/base.apk!libmonochrome.so (offset 65c000) (???)\n"
+ + " native: #08 pc 02364017 /data/app/~~VozU4lWeE_mDx8UNcfmuYg==/com.google.android.trichromelibrary.debug_463700031-WKdKLOoLSzICU5jkoCrpsA==/base.apk!libmonochrome.so (offset 65c000) (???)\n"
+ + " native: #09 pc 022fdf7f /data/app/~~VozU4lWeE_mDx8UNcfmuYg==/com.google.android.trichromelibrary.debug_463700031-WKdKLOoLSzICU5jkoCrpsA==/base.apk!libmonochrome.so (offset 65c000) (???)\n"
+ + " native: #10 pc 000e6974 /apex/com.android.runtime/lib/bionic/libc.so (__pthread_start(void*)+100)\n"
+ + " native: #11 pc 00078567 /apex/com.android.runtime/lib/bionic/libc.so (__start_thread+71)\n"
+ + " (no managed stack frames)\n"
+ + "\n"
+ + "\"GoogleApiHandler\" prio=5 tid=26 Native\n"
+ + " | group=\"main\" sCount=1 dsCount=0 flags=1 obj=0x134c11b0 self=0xe2d54210\n"
+ + " | sysTid=10930 nice=9 cgrp=top-app sched=0/0 handle=0xbf30b1e0\n"
+ + " | state=S schedstat=( 9053686 20157363 34 ) utm=0 stm=0 core=2 HZ=100\n"
+ + " | stack=0xbf208000-0xbf20a000 stackSize=1040KB\n"
+ + " | held mutexes=\n"
+ + " native: #00 pc 00000b99 [vdso] (__kernel_vsyscall+9)\n"
+ + " native: #01 pc 000cf2cb /apex/com.android.runtime/lib/bionic/libc.so (__epoll_pwait+43)\n"
+ + " native: #02 pc 00088f9d /apex/com.android.runtime/lib/bionic/libc.so (epoll_wait+45)\n"
+ + " native: #03 pc 0001a003 /system/lib/libutils.so (android::Looper::pollInner(int)+259)\n"
+ + " native: #04 pc 00019e96 /system/lib/libutils.so (android::Looper::pollOnce(int, int*, int*, void**)+118)\n"
+ + " native: #05 pc 0010ef8b /system/lib/libandroid_runtime.so (android::android_os_MessageQueue_nativePollOnce(_JNIEnv*, _jobject*, long long, int)+59)\n"
+ + " at android.os.MessageQueue.nativePollOnce(Native method)\n"
+ + " at android.os.MessageQueue.next(MessageQueue.java:335)\n"
+ + " at android.os.Looper.loop(Looper.java:183)\n"
+ + " at android.os.HandlerThread.run(HandlerThread.java:67)\n"
+ + "\n"
+ + "\"ThreadPoolForeg\" prio=5 tid=27 Native\n"
+ + " | group=\"main\" sCount=1 dsCount=0 flags=1 obj=0x134c1290 self=0xe2d5a410\n"
+ + " | sysTid=10923 nice=0 cgrp=top-app sched=0/0 handle=0xbf9111e0\n"
+ + " | state=S schedstat=( 7861103 15723367 24 ) utm=0 stm=0 core=3 HZ=100\n"
+ + " | stack=0xbf816000-0xbf818000 stackSize=1008KB\n"
+ + " | held mutexes=\n"
+ + " native: #00 pc 00000b99 [vdso] (__kernel_vsyscall+9)\n"
+ + " native: #01 pc 0005ad68 /apex/com.android.runtime/lib/bionic/libc.so (syscall+40)\n"
+ + " native: #02 pc 0007725e /apex/com.android.runtime/lib/bionic/libc.so (__futex_wait_ex(void volatile*, bool, int, bool, timespec const*)+142)\n"
+ + " native: #03 pc 000e5bce /apex/com.android.runtime/lib/bionic/libc.so (pthread_cond_timedwait+110)\n"
+ + " native: #04 pc 0237955a /data/app/~~VozU4lWeE_mDx8UNcfmuYg==/com.google.android.trichromelibrary.debug_463700031-WKdKLOoLSzICU5jkoCrpsA==/base.apk!libmonochrome.so (offset 65c000) (???)\n"
+ + " native: #05 pc 023713dc /data/app/~~VozU4lWeE_mDx8UNcfmuYg==/com.google.android.trichromelibrary.debug_463700031-WKdKLOoLSzICU5jkoCrpsA==/base.apk!libmonochrome.so (offset 65c000) (???)\n"
+ + " native: #06 pc 0236dee1 /data/app/~~VozU4lWeE_mDx8UNcfmuYg==/com.google.android.trichromelibrary.debug_463700031-WKdKLOoLSzICU5jkoCrpsA==/base.apk!libmonochrome.so (offset 65c000) (???)\n"
+ + " native: #07 pc 0231f2c5 /data/app/~~VozU4lWeE_mDx8UNcfmuYg==/com.google.android.trichromelibrary.debug_463700031-WKdKLOoLSzICU5jkoCrpsA==/base.apk!libmonochrome.so (offset 65c000) (???)\n"
+ + " native: #08 pc 02364017 /data/app/~~VozU4lWeE_mDx8UNcfmuYg==/com.google.android.trichromelibrary.debug_463700031-WKdKLOoLSzICU5jkoCrpsA==/base.apk!libmonochrome.so (offset 65c000) (???)\n"
+ + " native: #09 pc 022fdf7f /data/app/~~VozU4lWeE_mDx8UNcfmuYg==/com.google.android.trichromelibrary.debug_463700031-WKdKLOoLSzICU5jkoCrpsA==/base.apk!libmonochrome.so (offset 65c000) (???)\n"
+ + " native: #10 pc 000e6974 /apex/com.android.runtime/lib/bionic/libc.so (__pthread_start(void*)+100)\n"
+ + " native: #11 pc 00078567 /apex/com.android.runtime/lib/bionic/libc.so (__start_thread+71)\n"
+ + " (no managed stack frames)\n"
+ + "\n"
+ + "\"ThreadPoolForeg\" prio=5 tid=28 Native\n"
+ + " | group=\"main\" sCount=1 dsCount=0 flags=1 obj=0x134c1308 self=0xe2d59610\n"
+ + " | sysTid=10921 nice=0 cgrp=top-app sched=0/0 handle=0xbfb131e0\n"
+ + " | state=S schedstat=( 5466001 16594180 28 ) utm=0 stm=0 core=1 HZ=100\n"
+ + " | stack=0xbfa18000-0xbfa1a000 stackSize=1008KB\n"
+ + " | held mutexes=\n"
+ + " native: #00 pc 00000b99 [vdso] (__kernel_vsyscall+9)\n"
+ + " native: #01 pc 0005ad68 /apex/com.android.runtime/lib/bionic/libc.so (syscall+40)\n"
+ + " native: #02 pc 0007725e /apex/com.android.runtime/lib/bionic/libc.so (__futex_wait_ex(void volatile*, bool, int, bool, timespec const*)+142)\n"
+ + " native: #03 pc 000e5bce /apex/com.android.runtime/lib/bionic/libc.so (pthread_cond_timedwait+110)\n"
+ + " native: #04 pc 0237955a /data/app/~~VozU4lWeE_mDx8UNcfmuYg==/com.google.android.trichromelibrary.debug_463700031-WKdKLOoLSzICU5jkoCrpsA==/base.apk!libmonochrome.so (offset 65c000) (???)\n"
+ + " native: #05 pc 023713dc /data/app/~~VozU4lWeE_mDx8UNcfmuYg==/com.google.android.trichromelibrary.debug_463700031-WKdKLOoLSzICU5jkoCrpsA==/base.apk!libmonochrome.so (offset 65c000) (???)\n"
+ + " native: #06 pc 0236dee1 /data/app/~~VozU4lWeE_mDx8UNcfmuYg==/com.google.android.trichromelibrary.debug_463700031-WKdKLOoLSzICU5jkoCrpsA==/base.apk!libmonochrome.so (offset 65c000) (???)\n"
+ + " native: #07 pc 0231f2c5 /data/app/~~VozU4lWeE_mDx8UNcfmuYg==/com.google.android.trichromelibrary.debug_463700031-WKdKLOoLSzICU5jkoCrpsA==/base.apk!libmonochrome.so (offset 65c000) (???)\n"
+ + " native: #08 pc 02364017 /data/app/~~VozU4lWeE_mDx8UNcfmuYg==/com.google.android.trichromelibrary.debug_463700031-WKdKLOoLSzICU5jkoCrpsA==/base.apk!libmonochrome.so (offset 65c000) (???)\n"
+ + " native: #09 pc 022fdf7f /data/app/~~VozU4lWeE_mDx8UNcfmuYg==/com.google.android.trichromelibrary.debug_463700031-WKdKLOoLSzICU5jkoCrpsA==/base.apk!libmonochrome.so (offset 65c000) (???)\n"
+ + " native: #10 pc 000e6974 /apex/com.android.runtime/lib/bionic/libc.so (__pthread_start(void*)+100)\n"
+ + " native: #11 pc 00078567 /apex/com.android.runtime/lib/bionic/libc.so (__start_thread+71)\n"
+ + " (no managed stack frames)\n"
+ + "\n"
+ + "\"Binder:10849_3\" prio=5 tid=29 Native\n"
+ + " | stack=0xbf107000-0xbf109000 stackSize=1008KB\n"
+ + " | held mutexes=\n"
+ + " native: #00 pc 00000b97 [vdso] (__kernel_vsyscall+7)\n"
+ + " native: #01 pc 000cd46c /apex/com.android.runtime/lib/bionic/libc.so (__ioctl+28)\n"
+ + " native: #02 pc 00080e6a /apex/com.android.runtime/lib/bionic/libc.so (ioctl+58)\n"
+ + " native: #03 pc 00050edb /system/lib/libbinder.so (android::IPCThreadState::talkWithDriver(bool)+331)\n"
+ + " native: #04 pc 0005117a /system/lib/libbinder.so (android::IPCThreadState::getAndExecuteCommand()+42)\n"
+ + " native: #05 pc 00051cb8 /system/lib/libbinder.so (android::IPCThreadState::joinThreadPool(bool)+72)\n"
+ + " native: #06 pc 0007e309 /system/lib/libbinder.so (android::PoolThread::threadLoop()+41)\n"
+ + " native: #07 pc 00015116 /system/lib/libutils.so (android::Thread::_threadLoop(void*)+374)\n"
+ + " native: #08 pc 00098fee /system/lib/libandroid_runtime.so (android::AndroidRuntime::javaThreadShell(void*)+174)\n"
+ + " native: #09 pc 000147d9 /system/lib/libutils.so (thread_data_t::trampoline(thread_data_t const*)+457)\n"
+ + " native: #10 pc 000e6974 /apex/com.android.runtime/lib/bionic/libc.so (__pthread_start(void*)+100)\n"
+ + " native: #11 pc 00078567 /apex/com.android.runtime/lib/bionic/libc.so (__start_thread+71)\n"
+ + " (no managed stack frames)\n"
+ + "\n"
+ + "\"ThreadPoolForeg\" prio=5 tid=30 Native\n"
+ + " | group=\"main\" sCount=1 dsCount=0 flags=1 obj=0x134c13f8 self=0xe2d5f810\n"
+ + " | sysTid=10924 nice=0 cgrp=top-app sched=0/0 handle=0xbf8101e0\n"
+ + " | state=S schedstat=( 13183111 66742760 36 ) utm=0 stm=0 core=2 HZ=100\n"
+ + " | stack=0xbf715000-0xbf717000 stackSize=1008KB\n"
+ + " | held mutexes=\n"
+ + " native: #00 pc 00000b99 [vdso] (__kernel_vsyscall+9)\n"
+ + " native: #01 pc 0005ad68 /apex/com.android.runtime/lib/bionic/libc.so (syscall+40)\n"
+ + " native: #02 pc 0007725e /apex/com.android.runtime/lib/bionic/libc.so (__futex_wait_ex(void volatile*, bool, int, bool, timespec const*)+142)\n"
+ + " native: #03 pc 000e5bce /apex/com.android.runtime/lib/bionic/libc.so (pthread_cond_timedwait+110)\n"
+ + " native: #04 pc 0237955a /data/app/~~VozU4lWeE_mDx8UNcfmuYg==/com.google.android.trichromelibrary.debug_463700031-WKdKLOoLSzICU5jkoCrpsA==/base.apk!libmonochrome.so (offset 65c000) (???)\n"
+ + " native: #05 pc 023713dc /data/app/~~VozU4lWeE_mDx8UNcfmuYg==/com.google.android.trichromelibrary.debug_463700031-WKdKLOoLSzICU5jkoCrpsA==/base.apk!libmonochrome.so (offset 65c000) (???)\n"
+ + " native: #06 pc 0236dee1 /data/app/~~VozU4lWeE_mDx8UNcfmuYg==/com.google.android.trichromelibrary.debug_463700031-WKdKLOoLSzICU5jkoCrpsA==/base.apk!libmonochrome.so (offset 65c000) (???)\n"
+ + " native: #07 pc 0231f2c5 /data/app/~~VozU4lWeE_mDx8UNcfmuYg==/com.google.android.trichromelibrary.debug_463700031-WKdKLOoLSzICU5jkoCrpsA==/base.apk!libmonochrome.so (offset 65c000) (???)\n"
+ + " native: #08 pc 02364017 /data/app/~~VozU4lWeE_mDx8UNcfmuYg==/com.google.android.trichromelibrary.debug_463700031-WKdKLOoLSzICU5jkoCrpsA==/base.apk!libmonochrome.so (offset 65c000) (???)\n"
+ + " native: #09 pc 022fdf7f /data/app/~~VozU4lWeE_mDx8UNcfmuYg==/com.google.android.trichromelibrary.debug_463700031-WKdKLOoLSzICU5jkoCrpsA==/base.apk!libmonochrome.so (offset 65c000) (???)\n"
+ + " native: #10 pc 000e6974 /apex/com.android.runtime/lib/bionic/libc.so (__pthread_start(void*)+100)\n"
+ + " native: #11 pc 00078567 /apex/com.android.runtime/lib/bionic/libc.so (__start_thread+71)\n"
+ + " (no managed stack frames)\n"
+ + "\n"
+ + " \"NetworkStatusListener\" prio=5 tid=31 Native\n"
+ + " | group=\"main\" sCount=1 dsCount=0 flags=1 obj=0x12c41780 self=0xe2d5ea10\n"
+ + " | sysTid=10940 nice=0 cgrp=top-app sched=0/0 handle=0xbedb41e0\n"
+ + " | state=S schedstat=( 6504387 4427985 21 ) utm=0 stm=0 core=0 HZ=100\n"
+ + " static final String PREAMBLE;\n"
+ + " static final String MAIN_THREAD_STACK_TRACES;\n"
+ + " static final String OTHER_STACK_TRACES;\n"
+ + "\n";
+
+ @Test
+ public void testParseAnrFromReport() throws IOException {
+ BufferedReader reader =
+ new BufferedReader(new StringReader(TEXT_FROM_GET_TRACE_INPUT_STREAM));
+ AnrData anrData = AnrCollector.parseAnrFromReport(reader);
+ assertEquals(PREAMBLE, anrData.getPreamble());
+ assertEquals(MAIN_THREAD_STACK_TRACE, anrData.getMainThreadStackTrace());
+ assertEquals(OTHER_STACK_TRACES, anrData.getStackTraces());
+ }
+}
diff --git a/chromium/components/crash/android/pure_java_exception_handler.cc b/chromium/components/crash/android/pure_java_exception_handler.cc
new file mode 100644
index 00000000000..9a5005bae47
--- /dev/null
+++ b/chromium/components/crash/android/pure_java_exception_handler.cc
@@ -0,0 +1,12 @@
+// Copyright 2017 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.
+
+#include "components/crash/android/pure_java_exception_handler.h"
+
+#include "components/crash/android/jni_headers/PureJavaExceptionHandler_jni.h"
+
+void UninstallPureJavaExceptionHandler() {
+ Java_PureJavaExceptionHandler_uninstallHandler(
+ base::android::AttachCurrentThread());
+}
diff --git a/chromium/components/crash/android/pure_java_exception_handler.h b/chromium/components/crash/android/pure_java_exception_handler.h
new file mode 100644
index 00000000000..c66fa7d2a36
--- /dev/null
+++ b/chromium/components/crash/android/pure_java_exception_handler.h
@@ -0,0 +1,10 @@
+// Copyright 2017 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.
+
+#ifndef COMPONENTS_CRASH_ANDROID_PURE_JAVA_EXCEPTION_HANDLER_H_
+#define COMPONENTS_CRASH_ANDROID_PURE_JAVA_EXCEPTION_HANDLER_H_
+
+void UninstallPureJavaExceptionHandler();
+
+#endif // COMPONENTS_CRASH_ANDROID_PURE_JAVA_EXCEPTION_HANDLER_H_
diff --git a/chromium/components/crash/content/browser/crash_handler_host_linux.cc b/chromium/components/crash/content/browser/crash_handler_host_linux.cc
index 873b4cc0640..d460d18686d 100644
--- a/chromium/components/crash/content/browser/crash_handler_host_linux.cc
+++ b/chromium/components/crash/content/browser/crash_handler_host_linux.cc
@@ -39,19 +39,19 @@
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
#include "third_party/breakpad/breakpad/src/client/linux/handler/exception_handler.h" // nogncheck
#include "third_party/breakpad/breakpad/src/client/linux/minidump_writer/linux_dumper.h" // nogncheck
#include "third_party/breakpad/breakpad/src/client/linux/minidump_writer/minidump_writer.h" // nogncheck
-#endif // ! defined(OS_ANDROID)
+#endif // ! BUILDFLAG(IS_ANDROID)
-#if defined(OS_ANDROID) && !defined(__LP64__)
+#if BUILDFLAG(IS_ANDROID) && !defined(__LP64__)
#include <sys/syscall.h>
#define SYS_read __NR_read
#endif
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "components/crash/core/app/crashpad.h"
#include "third_party/crashpad/crashpad/client/crashpad_client.h" // nogncheck
#include "third_party/crashpad/crashpad/util/posix/signals.h" // nogncheck
@@ -59,7 +59,7 @@
using content::BrowserThread;
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
using google_breakpad::ExceptionHandler;
@@ -114,7 +114,7 @@ CrashHandlerHostLinux::CrashHandlerHostLinux(const std::string& process_type,
bool upload)
: process_type_(process_type),
dumps_path_(dumps_path),
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
upload_(upload),
#endif
fd_watch_controller_(FROM_HERE),
@@ -391,7 +391,7 @@ void CrashHandlerHostLinux::FindCrashingThreadAndDump(
info->process_start_time = uptime;
info->oom_size = oom_size;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Nothing gets uploaded in android.
info->upload = false;
#else
@@ -502,7 +502,7 @@ bool CrashHandlerHostLinux::IsShuttingDown() const {
} // namespace breakpad
-#else // !OS_ANDROID
+#else // !BUILDFLAG(IS_ANDROID)
namespace crashpad {
@@ -659,4 +659,4 @@ void CrashHandlerHost::WillDestroyCurrentMessageLoop() {
} // namespace crashpad
-#endif // !OS_ANDROID
+#endif // !BUILDFLAG(IS_ANDROID)
diff --git a/chromium/components/crash/content/browser/crash_handler_host_linux.h b/chromium/components/crash/content/browser/crash_handler_host_linux.h
index f329ce5fbfc..7490a47e696 100644
--- a/chromium/components/crash/content/browser/crash_handler_host_linux.h
+++ b/chromium/components/crash/content/browser/crash_handler_host_linux.h
@@ -21,7 +21,7 @@
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
#include "components/crash/core/app/breakpad_linux_impl.h"
#endif
@@ -30,7 +30,7 @@ class SequencedTaskRunner;
class Thread;
}
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
namespace breakpad {
@@ -103,7 +103,7 @@ class CrashHandlerHostLinux : public base::MessagePumpForIO::FdWatcher,
const std::string process_type_;
const base::FilePath dumps_path_;
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
const bool upload_;
#endif
@@ -119,7 +119,7 @@ class CrashHandlerHostLinux : public base::MessagePumpForIO::FdWatcher,
} // namespace breakpad
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
#if !BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chromium/components/crash/content/browser/error_reporting/mock_crash_endpoint.cc b/chromium/components/crash/content/browser/error_reporting/mock_crash_endpoint.cc
index e67954aae82..d7d9c55a9ed 100644
--- a/chromium/components/crash/content/browser/error_reporting/mock_crash_endpoint.cc
+++ b/chromium/components/crash/content/browser/error_reporting/mock_crash_endpoint.cc
@@ -31,7 +31,7 @@ class MockCrashEndpoint::Client : public crash_reporter::CrashReporterClient {
FROM_HERE, base::BlockingType::MAY_BLOCK);
return owner_->consented_;
}
-#if defined(OS_POSIX) && !defined(OS_MAC)
+#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC)
void GetProductNameAndVersion(std::string* product_name,
std::string* version,
std::string* channel) override {
diff --git a/chromium/components/crash/content/tools/generate_breakpad_symbols.py b/chromium/components/crash/content/tools/generate_breakpad_symbols.py
index e68039d78f1..99395610be5 100755
--- a/chromium/components/crash/content/tools/generate_breakpad_symbols.py
+++ b/chromium/components/crash/content/tools/generate_breakpad_symbols.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# Copyright 2013 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.
@@ -9,22 +9,20 @@ Currently, the tool only supports Linux, Android, and Mac. Support for other
platforms is planned.
"""
-from __future__ import print_function
import collections
import errno
import glob
import multiprocessing
import optparse
import os
+import queue
import re
import shutil
-import six.moves.queue
import subprocess
import sys
import threading
import traceback
-
CONCURRENT_TASKS=multiprocessing.cpu_count()
if sys.platform == 'win32':
# TODO(crbug.com/1190269) - we can't use more than 56
@@ -221,7 +219,7 @@ def GetSharedLibraryDependenciesChromeOS(binary):
def GetSharedLibraryDependencies(options, binary, exe_path):
"""Return absolute paths to all shared library dependencies of the binary."""
deps = []
- if options.platform.startswith('linux'):
+ if options.platform == 'linux':
deps = GetSharedLibraryDependenciesLinux(binary)
elif options.platform == 'android':
deps = GetSharedLibraryDependenciesAndroid(binary)
@@ -247,7 +245,7 @@ def GetTransitiveDependencies(options):
dependencies of the binary, along with the binary itself."""
binary = os.path.abspath(options.binary)
exe_path = os.path.dirname(binary)
- if options.platform.startswith('linux'):
+ if options.platform == 'linux':
# 'ldd' returns all transitive dependencies for us.
deps = set(GetSharedLibraryDependencies(options, binary, exe_path))
deps.add(binary)
@@ -255,12 +253,12 @@ def GetTransitiveDependencies(options):
elif (options.platform == 'darwin' or options.platform == 'android' or
options.platform == 'chromeos'):
binaries = set([binary])
- queue = [binary]
- while queue:
- deps = GetSharedLibraryDependencies(options, queue.pop(0), exe_path)
+ q = [binary]
+ while q:
+ deps = GetSharedLibraryDependencies(options, q.pop(0), exe_path)
new_deps = set(deps) - binaries
binaries |= new_deps
- queue.extend(list(new_deps))
+ q.extend(list(new_deps))
return binaries
print("Platform not supported.")
sys.exit(1)
@@ -289,7 +287,7 @@ def CreateSymbolDir(options, output_dir, relative_hash_dir):
"""Create the directory to store breakpad symbols in. On Android/Linux, we
also create a symlink in case the hash in the binary is missing."""
mkdir_p(output_dir)
- if options.platform == 'android' or options.platform.startswith('linux'):
+ if options.platform == 'android' or options.platform == 'linux':
try:
os.symlink(relative_hash_dir, os.path.join(os.path.dirname(output_dir),
'000000000000000000000000000000000'))
@@ -300,7 +298,7 @@ def CreateSymbolDir(options, output_dir, relative_hash_dir):
def GenerateSymbols(options, binaries):
"""Dumps the symbols of binary and places them in the given directory."""
- queue = six.moves.queue.Queue()
+ q = queue.Queue()
exceptions = []
print_lock = threading.Lock()
exceptions_lock = threading.Lock()
@@ -311,7 +309,7 @@ def GenerateSymbols(options, binaries):
try:
should_dump_syms = True
reason = "no reason"
- binary = queue.get()
+ binary = q.get()
run_once = True
while run_once:
@@ -369,17 +367,17 @@ def GenerateSymbols(options, binaries):
with exceptions_lock:
exceptions.append(traceback.format_exc())
finally:
- queue.task_done()
+ q.task_done()
for binary in binaries:
- queue.put(binary)
+ q.put(binary)
for _ in range(options.jobs):
t = threading.Thread(target=_Worker)
t.daemon = True
t.start()
- queue.join()
+ q.join()
if exceptions:
exception_str = ('One or more exceptions occurred while generating '
'symbols:\n')
diff --git a/chromium/components/crash/core/app/BUILD.gn b/chromium/components/crash/core/app/BUILD.gn
index a3faf231a83..7a5e5244cfd 100644
--- a/chromium/components/crash/core/app/BUILD.gn
+++ b/chromium/components/crash/core/app/BUILD.gn
@@ -127,6 +127,7 @@ static_library("app") {
if (is_ios) {
sources += [ "crashpad_ios.mm" ]
+ deps += [ "//third_party/crashpad/crashpad/minidump" ]
}
}
@@ -292,4 +293,15 @@ source_set("unit_tests") {
"//third_party/crashpad/crashpad/util",
]
}
+ if (is_ios) {
+ configs += [ "//build/config/compiler:enable_arc" ]
+
+ sources += [ "crashpad_ios_unittest.mm" ]
+ deps += [
+ ":app",
+ "//components/crash/core/common:reporter_running_ios",
+ "//third_party/crashpad/crashpad/client:common",
+ "//third_party/crashpad/crashpad/test",
+ ]
+ }
}
diff --git a/chromium/components/crash/core/app/breakpad_linux.cc b/chromium/components/crash/core/app/breakpad_linux.cc
index ec5b5b9b4da..823e49a234e 100644
--- a/chromium/components/crash/core/app/breakpad_linux.cc
+++ b/chromium/components/crash/core/app/breakpad_linux.cc
@@ -24,12 +24,12 @@
#include <algorithm>
#include <string>
+#include <tuple>
#include "base/base_switches.h"
#include "base/command_line.h"
#include "base/debug/dump_without_crashing.h"
#include "base/files/file_path.h"
-#include "base/ignore_result.h"
#include "base/lazy_instance.h"
#include "base/linux_util.h"
#include "base/logging.h"
@@ -53,7 +53,7 @@
#include "third_party/breakpad/breakpad/src/common/linux/linux_libc_support.h"
#include "third_party/breakpad/breakpad/src/common/memory_allocator.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include <android/log.h>
#include <sys/stat.h>
@@ -73,7 +73,7 @@
#include <ucontext.h> // for getcontext().
#endif
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#define STAT_STRUCT struct stat
#define FSTAT_FUNC fstat
#else
@@ -85,7 +85,7 @@
// where we either a) know the call cannot fail, or b) there is nothing we
// can do when a call fails, we mark the return code as ignored. This avoids
// spurious compiler warnings.
-#define IGNORE_RET(x) ignore_result(x)
+#define IGNORE_RET(x) std::ignore = x
using crash_reporter::GetCrashReporterClient;
using google_breakpad::ExceptionHandler;
@@ -122,7 +122,7 @@ ExceptionHandler* g_breakpad = nullptr;
const char* g_asan_report_str = nullptr;
#endif
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#define G_DUMPS_SUPPRESSED_MAGIC 0x5AFECEDE
uint32_t g_dumps_suppressed = 0;
char* g_process_type = nullptr;
@@ -274,7 +274,7 @@ bool GetEnableCrashReporterSwitchParts(const base::CommandLine& command_line,
return true;
}
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
void SetChannelFromCommandLine(const base::CommandLine& command_line) {
std::vector<std::string> switch_parts;
if (!GetEnableCrashReporterSwitchParts(command_line, &switch_parts))
@@ -589,7 +589,7 @@ void CrashReporterWriter::AddFileContents(const char* filename_msg,
}
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Writes the "package" field, which is in the format:
// $FIREBASE_APP_ID v$VERSION_CODE ($VERSION_NAME)
void WriteAndroidPackage(MimeWriter& writer,
@@ -609,14 +609,14 @@ void WriteAndroidPackage(MimeWriter& writer,
writer.AddPairString("package", buf);
}
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
const char kGoogleBreakpad[] = "google-breakpad";
#endif
size_t WriteLog(const char* buf, size_t nbytes) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
return __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad, buf);
#else
return sys_write(2, buf, nbytes);
@@ -627,7 +627,7 @@ size_t WriteNewline() {
return WriteLog("\n", 1);
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
bool ShouldGenerateDump(void *context) {
return g_dumps_suppressed != G_DUMPS_SUPPRESSED_MAGIC;
}
@@ -689,7 +689,7 @@ bool MicrodumpCrashDone(const MinidumpDescriptor& minidump,
const bool is_browser_process = (context != nullptr);
return FinalizeCrashDoneAndroid(is_browser_process);
}
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
bool CrashDone(const MinidumpDescriptor& minidump,
const bool upload,
@@ -727,7 +727,7 @@ bool CrashDone(const MinidumpDescriptor& minidump,
info.pid = g_pid;
info.crash_keys = crash_reporter::internal::GetCrashKeyStorage();
HandleCrashDump(info);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
return !should_finalize ||
FinalizeCrashDoneAndroid(true /* is_browser_process */);
#else
@@ -735,7 +735,7 @@ bool CrashDone(const MinidumpDescriptor& minidump,
#endif
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Wrapper function, do not add more code here.
bool MinidumpGenerated(const MinidumpDescriptor& minidump,
void* context,
@@ -751,7 +751,7 @@ bool CrashDoneNoUpload(const MinidumpDescriptor& minidump,
return CrashDone(minidump, false, true, succeeded);
}
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
// Wrapper function, do not add more code here.
bool CrashDoneUpload(const MinidumpDescriptor& minidump,
void* context,
@@ -761,7 +761,7 @@ bool CrashDoneUpload(const MinidumpDescriptor& minidump,
#endif
void DumpProcess() {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Don't use g_breakpad and g_microdump directly here, because their
// output might currently be suppressed.
@@ -802,12 +802,12 @@ void AsanLinuxBreakpadCallback(const char* report) {
}
#endif
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
void EnableCrashDumping(bool unattended,
const SanitizationInfo& sanitization_info) {
#else
void EnableCrashDumping(bool unattended) {
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
g_is_crash_reporter_enabled = true;
base::FilePath tmp_path("/tmp");
@@ -830,26 +830,25 @@ void EnableCrashDumping(bool unattended) {
} else {
minidump_descriptor.set_size_limit(kMaxMinidumpFileSize);
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
unattended = true; // Android never uploads directly.
SetMinidumpSanitizationFields(&minidump_descriptor, sanitization_info);
#endif
if (unattended) {
- g_breakpad = new ExceptionHandler(
- minidump_descriptor,
-#if defined(OS_ANDROID)
- ShouldGenerateDump,
+ g_breakpad =
+ new ExceptionHandler(minidump_descriptor,
+#if BUILDFLAG(IS_ANDROID)
+ ShouldGenerateDump,
#else
nullptr,
#endif
- CrashDoneNoUpload,
- nullptr,
- true, // Install handlers.
- -1); // Server file descriptor. -1 for in-process.
+ CrashDoneNoUpload, nullptr,
+ true, // Install handlers.
+ -1); // Server file descriptor. -1 for in-process.
return;
}
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
// Attended mode
g_breakpad = new ExceptionHandler(
minidump_descriptor,
@@ -861,7 +860,7 @@ void EnableCrashDumping(bool unattended) {
#endif
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
bool WriteSignalCodeToPipe(const void* crash_context,
size_t crash_context_size,
void* context) {
@@ -1135,7 +1134,7 @@ void EnableNonBrowserCrashDumping() {
-1);
g_breakpad->set_crash_generation_client(new NonBrowserCrashHandler());
}
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
// GetCrashReporterClient() cannot call any Set methods until after
// InitCrashKeys().
@@ -1749,8 +1748,8 @@ void HandleCrashDump(const BreakpadInfo& info) {
pid_value_buf, pid_value_len);
writer.AddBoundary();
}
-#if defined(OS_ANDROID)
- // Addtional MIME blocks are added for logging on Android devices.
+#if BUILDFLAG(IS_ANDROID)
+ // Additional MIME blocks are added for logging on Android devices.
// When make changes to the name, please sync it with
// PureJavaExceptionReporter.java if needed.
static const char android_build_id[] = "android_build_id";
@@ -1883,7 +1882,7 @@ void HandleCrashDump(const BreakpadInfo& info) {
IGNORE_RET(sys_close(temp_file_fd));
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
if (info.filename) {
size_t filename_length = my_strlen(info.filename);
@@ -1984,7 +1983,7 @@ void HandleCrashDump(const BreakpadInfo& info) {
(void) HANDLE_EINTR(sys_waitpid(child, nullptr, 0));
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// In Android WebView, microdumps are generated conditionally (depending on the
// cause of the crash) and can be sanitized to prevent exposing unnecessary data
// from the embedding application.
@@ -2001,8 +2000,8 @@ void InitCrashReporter(const std::string& process_type,
const SanitizationInfo& sanitization_info) {
#else
void InitCrashReporter(const std::string& process_type) {
-#endif // defined(OS_ANDROID)
-#if defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
base::android::SetJavaExceptionCallback(SetJavaExceptionInfo);
// This will guarantee that the BuildInfo has been initialized and subsequent
@@ -2021,7 +2020,7 @@ void InitCrashReporter(const std::string& process_type) {
return;
bool is_browser_process =
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
process_type == kWebViewSingleProcessType ||
process_type == kBrowserProcessType ||
#endif
@@ -2046,14 +2045,14 @@ void InitCrashReporter(const std::string& process_type) {
}
InitCrashKeys();
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
EnableCrashDumping(GetCrashReporterClient()->IsRunningUnattended(),
sanitization_info);
#else
EnableCrashDumping(GetCrashReporterClient()->IsRunningUnattended());
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
} else if (GetCrashReporterClient()->EnableBreakpadForProcess(process_type)) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
NOTREACHED() << "Breakpad initialized with InitCrashReporter() instead of "
"InitNonBrowserCrashReporter in " << process_type << " process.";
return;
@@ -2071,7 +2070,7 @@ void InitCrashReporter(const std::string& process_type) {
SetClientIdFromCommandLine(parsed_command_line);
EnableNonBrowserCrashDumping();
VLOG(1) << "Non Browser crash dumping enabled for: " << process_type;
-#endif // #if defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
}
PostEnableBreakpadInitialization(process_type, parsed_command_line);
@@ -2091,7 +2090,7 @@ void SetChannelCrashKey(const std::string& channel) {
#endif
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
void InitNonBrowserCrashReporterForAndroid(const std::string& process_type) {
SanitizationInfo sanitization_info;
sanitization_info.should_sanitize_dumps = false;
@@ -2175,7 +2174,7 @@ void GenerateMinidumpOnDemandForAndroid(int dump_fd) {
void SuppressDumpGeneration() {
g_dumps_suppressed = G_DUMPS_SUPPRESSED_MAGIC;
}
-#endif // OS_ANDROID
+#endif // BUILDFLAG(IS_ANDROID)
bool IsCrashReporterEnabled() {
return g_is_crash_reporter_enabled;
diff --git a/chromium/components/crash/core/app/breakpad_linux.h b/chromium/components/crash/core/app/breakpad_linux.h
index 9ea80370a84..2f0d4c55550 100644
--- a/chromium/components/crash/core/app/breakpad_linux.h
+++ b/chromium/components/crash/core/app/breakpad_linux.h
@@ -20,7 +20,7 @@ extern void InitCrashReporter(const std::string& process_type);
// Sets the product/distribution channel crash key.
void SetChannelCrashKey(const std::string& channel);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
extern void InitCrashKeysForTesting();
struct SanitizationInfo {
@@ -56,7 +56,7 @@ extern void AddGpuFingerprintToMicrodumpCrashHandler(
// generate dumps. Calling base::debug::DumpWithoutCrashing will still
// generate a dump.
extern void SuppressDumpGeneration();
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
// Checks if crash reporting is enabled. Note that this is not the same as
// being opted into metrics reporting (and crash reporting), which controls
diff --git a/chromium/components/crash/core/app/client_upload_info.cc b/chromium/components/crash/core/app/client_upload_info.cc
index 29ad127428f..257fcdaa26e 100644
--- a/chromium/components/crash/core/app/client_upload_info.cc
+++ b/chromium/components/crash/core/app/client_upload_info.cc
@@ -3,6 +3,8 @@
// found in the LICENSE file.
#include "components/crash/core/app/client_upload_info.h"
+
+#include "build/build_config.h"
#include "components/crash/core/app/crash_reporter_client.h"
namespace crash_reporter {
@@ -11,7 +13,7 @@ bool GetClientCollectStatsConsent() {
return GetCrashReporterClient()->GetCollectStatsConsent();
}
-#if defined(OS_POSIX) && !defined(OS_APPLE)
+#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_APPLE)
void GetClientProductNameAndVersion(std::string* product,
std::string* version,
std::string* channel) {
diff --git a/chromium/components/crash/core/app/client_upload_info.h b/chromium/components/crash/core/app/client_upload_info.h
index 0d69cd33e86..4cd5ba889fc 100644
--- a/chromium/components/crash/core/app/client_upload_info.h
+++ b/chromium/components/crash/core/app/client_upload_info.h
@@ -14,7 +14,7 @@ namespace crash_reporter {
// Returns whether the user has consented to collecting stats.
bool GetClientCollectStatsConsent();
-#if defined(OS_POSIX) && !defined(OS_APPLE)
+#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_APPLE)
// Returns a textual description of the product type, version and channel
// to include in crash reports.
// TODO(https://crbug.com/986178): Implement this for other platforms.
diff --git a/chromium/components/crash/core/app/crash_reporter_client.cc b/chromium/components/crash/core/app/crash_reporter_client.cc
index 89b4bfccd5d..82b7f241e26 100644
--- a/chromium/components/crash/core/app/crash_reporter_client.cc
+++ b/chromium/components/crash/core/app/crash_reporter_client.cc
@@ -9,7 +9,7 @@
// On Windows don't use FilePath and logging.h.
// http://crbug.com/604923
-#if !defined(OS_WIN)
+#if !BUILDFLAG(IS_WIN)
#include "base/check.h"
#include "base/files/file_path.h"
#else
@@ -41,12 +41,12 @@ CrashReporterClient* GetCrashReporterClient() {
CrashReporterClient::CrashReporterClient() {}
CrashReporterClient::~CrashReporterClient() {}
-#if !defined(OS_APPLE) && !defined(OS_WIN) && !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_APPLE) && !BUILDFLAG(IS_WIN) && !BUILDFLAG(IS_ANDROID)
void CrashReporterClient::SetCrashReporterClientIdFromGUID(
const std::string& client_guid) {}
#endif
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
bool CrashReporterClient::ShouldCreatePipeName(
const std::wstring& process_type) {
return process_type == L"browser";
@@ -78,16 +78,18 @@ bool CrashReporterClient::GetIsPerUserInstall() {
return true;
}
-bool CrashReporterClient::GetShouldDumpLargerDumps() {
- return false;
-}
-
int CrashReporterClient::GetResultCodeRespawnFailed() {
return 0;
}
#endif
-#if defined(OS_POSIX) && !defined(OS_MAC)
+#if BUILDFLAG(IS_WIN) || (BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC))
+bool CrashReporterClient::GetShouldDumpLargerDumps() {
+ return false;
+}
+#endif
+
+#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC)
void CrashReporterClient::GetProductNameAndVersion(const char** product_name,
const char** version) {
}
@@ -106,7 +108,7 @@ bool CrashReporterClient::HandleCrashDump(const char* crashdump_filename,
}
#endif
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
bool CrashReporterClient::GetCrashDumpLocation(std::wstring* crash_dir) {
#else
bool CrashReporterClient::GetCrashDumpLocation(base::FilePath* crash_dir) {
@@ -114,7 +116,7 @@ bool CrashReporterClient::GetCrashDumpLocation(base::FilePath* crash_dir) {
return false;
}
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
bool CrashReporterClient::GetCrashMetricsLocation(std::wstring* crash_dir) {
#else
bool CrashReporterClient::GetCrashMetricsLocation(base::FilePath* crash_dir) {
@@ -139,7 +141,7 @@ bool CrashReporterClient::ReportingIsEnforcedByPolicy(bool* breakpad_enabled) {
return false;
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
unsigned int CrashReporterClient::GetCrashDumpPercentage() {
return 100;
}
@@ -176,7 +178,7 @@ bool CrashReporterClient::ShouldWriteMinidumpToLog() {
#endif
-#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
void CrashReporterClient::GetSanitizationInformation(
const char* const** allowed_annotations,
void** target_module,
diff --git a/chromium/components/crash/core/app/crash_reporter_client.h b/chromium/components/crash/core/app/crash_reporter_client.h
index 39557cce474..24e53fa62c2 100644
--- a/chromium/components/crash/core/app/crash_reporter_client.h
+++ b/chromium/components/crash/core/app/crash_reporter_client.h
@@ -9,7 +9,7 @@
#include "build/build_config.h"
-#if !defined(OS_WIN)
+#if !BUILDFLAG(IS_WIN)
namespace base {
class FilePath;
}
@@ -35,7 +35,7 @@ class CrashReporterClient {
CrashReporterClient();
virtual ~CrashReporterClient();
-#if !defined(OS_APPLE) && !defined(OS_WIN) && !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_APPLE) && !BUILDFLAG(IS_WIN) && !BUILDFLAG(IS_ANDROID)
// Sets the crash reporting client ID, a unique identifier for the client
// that is sending crash reports. After it is set, it should not be changed.
// |client_guid| may either be a full GUID or a GUID that was already stripped
@@ -46,7 +46,7 @@ class CrashReporterClient {
virtual void SetCrashReporterClientIdFromGUID(const std::string& client_guid);
#endif
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// Returns true if the pipe name to connect to breakpad should be computed and
// stored in the process's environment block. By default, returns true for the
// "browser" process.
@@ -79,15 +79,17 @@ class CrashReporterClient {
// Returns true if the running binary is a per-user installation.
virtual bool GetIsPerUserInstall();
- // Returns true if larger crash dumps should be dumped.
- virtual bool GetShouldDumpLargerDumps();
-
// Returns the result code to return when breakpad failed to respawn a
// crashed process.
virtual int GetResultCodeRespawnFailed();
#endif
-#if defined(OS_POSIX) && !defined(OS_MAC)
+#if BUILDFLAG(IS_WIN) || (BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC))
+ // Returns true if larger crash dumps should be dumped.
+ virtual bool GetShouldDumpLargerDumps();
+#endif
+
+#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC)
// Returns a textual description of the product type and version to include
// in the crash report. Neither out parameter should be set to NULL.
// TODO(jperaza): Remove the 2-parameter overload of this method once all
@@ -113,7 +115,7 @@ class CrashReporterClient {
// |crash_dir| was set. Windows has to use std::wstring because this code
// needs to work in chrome_elf, where only kernel32.dll is allowed, and
// base::FilePath and its dependencies pull in other DLLs.
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
virtual bool GetCrashDumpLocation(std::wstring* crash_dir);
#else
virtual bool GetCrashDumpLocation(base::FilePath* crash_dir);
@@ -123,7 +125,7 @@ class CrashReporterClient {
// |metrics_dir| was set. Windows has to use std::wstring because this code
// needs to work in chrome_elf, where only kernel32.dll is allowed, and
// base::FilePath and its dependencies pull in other DLLs.
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
virtual bool GetCrashMetricsLocation(std::wstring* metrics_dir);
#else
virtual bool GetCrashMetricsLocation(base::FilePath* metrics_dir);
@@ -144,7 +146,7 @@ class CrashReporterClient {
// that case, |breakpad_enabled| is set to the value enforced by policies.
virtual bool ReportingIsEnforcedByPolicy(bool* breakpad_enabled);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Used by WebView to sample crashes without generating the unwanted dumps. If
// the returned value is less than 100, crash dumping will be sampled to that
// percentage.
@@ -169,7 +171,7 @@ class CrashReporterClient {
virtual bool ShouldWriteMinidumpToLog();
#endif
-#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
// Configures sanitization of crash dumps.
// |allowed_annotations| is a nullptr terminated array of NUL-terminated
// strings of allowed annotation names or nullptr if all annotations are
diff --git a/chromium/components/crash/core/app/crash_switches.cc b/chromium/components/crash/core/app/crash_switches.cc
index dfcb6bd37cb..4c28c192969 100644
--- a/chromium/components/crash/core/app/crash_switches.cc
+++ b/chromium/components/crash/core/app/crash_switches.cc
@@ -4,6 +4,7 @@
#include "components/crash/core/app/crash_switches.h"
+#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
namespace crash_reporter {
@@ -17,7 +18,7 @@ namespace switches {
// is a standalone executable.
const char kCrashpadHandler[] = "crashpad-handler";
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
// The process ID of the Crashpad handler.
const char kCrashpadHandlerPid[] = "crashpad-handler-pid";
#endif
diff --git a/chromium/components/crash/core/app/crash_switches.h b/chromium/components/crash/core/app/crash_switches.h
index 1855b80d184..2f18cfe8344 100644
--- a/chromium/components/crash/core/app/crash_switches.h
+++ b/chromium/components/crash/core/app/crash_switches.h
@@ -13,9 +13,9 @@ namespace switches {
extern const char kCrashpadHandler[];
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
extern const char kCrashpadHandlerPid[];
-#endif // defined(OS_LINUX) || defined(OS_CHROMEOS)
+#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
#if BUILDFLAG(IS_CHROMEOS_ASH)
extern const char kCrashLoopBefore[];
diff --git a/chromium/components/crash/core/app/crashpad.cc b/chromium/components/crash/core/app/crashpad.cc
index ea9ec2be099..6da6be46cee 100644
--- a/chromium/components/crash/core/app/crashpad.cc
+++ b/chromium/components/crash/core/app/crashpad.cc
@@ -36,11 +36,11 @@
#include "third_party/crashpad/crashpad/client/settings.h"
#include "third_party/crashpad/crashpad/client/simulate_crash.h"
-#if defined(OS_POSIX)
+#if BUILDFLAG(IS_POSIX)
#include <unistd.h>
-#endif // OS_POSIX
+#endif
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include "components/crash/core/app/crash_export_thunks.h"
#endif
@@ -111,23 +111,23 @@ bool InitializeCrashpadImpl(bool initial_client,
const bool browser_process = process_type.empty();
if (initial_client) {
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
// "relauncher" is hard-coded because it's a Chrome --type, but this
// component can't see Chrome's switches. This is only used for argument
// sanitization.
DCHECK(browser_process || process_type == "relauncher" ||
process_type == "app_shim");
-#elif defined(OS_WIN)
+#elif BUILDFLAG(IS_WIN)
// "Chrome Installer" is the name historically used for installer binaries
// as processed by the backend.
DCHECK(browser_process || process_type == "Chrome Installer" ||
process_type == "notification-helper" ||
process_type == "GCPW Installer" || process_type == "GCPW DLL");
-#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
+#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID)
DCHECK(browser_process);
#else
#error Port.
-#endif // OS_APPLE
+#endif // BUILDFLAG(IS_APPLE)
} else {
DCHECK(!browser_process);
}
@@ -140,7 +140,7 @@ bool InitializeCrashpadImpl(bool initial_client,
return false;
}
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
#if defined(NDEBUG)
const bool is_debug_build = false;
#else
@@ -158,19 +158,19 @@ bool InitializeCrashpadImpl(bool initial_client,
crashpad::CrashpadInfo::GetCrashpadInfo()
->set_system_crash_reporter_forwarding(crashpad::TriState::kDisabled);
}
-#endif // OS_APPLE
+#endif // BUILDFLAG(IS_APPLE)
crashpad::AnnotationList::Register();
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
static crashpad::StringAnnotation<24> ptype_key("ptype");
ptype_key.Set(browser_process ? base::StringPiece("browser")
: base::StringPiece(process_type));
static crashpad::StringAnnotation<12> pid_key("pid");
-#if defined(OS_POSIX)
+#if BUILDFLAG(IS_POSIX)
pid_key.Set(base::NumberToString(getpid()));
-#elif defined(OS_WIN)
+#elif BUILDFLAG(IS_WIN)
pid_key.Set(base::NumberToString(::GetCurrentProcessId()));
#endif
@@ -180,7 +180,7 @@ bool InitializeCrashpadImpl(bool initial_client,
// "platform" is used to determine device_model on the crash server.
static crashpad::StringAnnotation<24> platform("platform");
platform.Set(base::SysInfo::HardwareModelName());
-#endif // OS_IOS
+#endif // !BUILDFLAG(IS_IOS)
logging::SetLogMessageHandler(LogMessageHandler);
@@ -191,16 +191,16 @@ bool InitializeCrashpadImpl(bool initial_client,
// the same file and line.
base::debug::SetDumpWithoutCrashingFunction(DumpWithoutCrashing);
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
// On Mac, we only want the browser to initialize the database, but not the
// relauncher.
const bool should_initialize_database_and_set_upload_policy = browser_process;
-#elif defined(OS_WIN)
+#elif BUILDFLAG(IS_WIN)
// On Windows, we want both the browser process and the installer and any
// other "main, first process" to initialize things. There is no "relauncher"
// on Windows, so this is synonymous with initial_client.
const bool should_initialize_database_and_set_upload_policy = initial_client;
-#elif defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
+#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID)
const bool should_initialize_database_and_set_upload_policy = browser_process;
#endif
if (should_initialize_database_and_set_upload_policy) {
@@ -225,7 +225,7 @@ bool InitializeCrashpad(bool initial_client, const std::string& process_type) {
false);
}
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
void InitializeCrashpadWithEmbeddedHandler(bool initial_client,
const std::string& process_type,
const std::string& user_data_dir,
@@ -243,7 +243,7 @@ void InitializeCrashpadWithDllEmbeddedHandler(
InitializeCrashpadImpl(initial_client, process_type, user_data_dir, exe_path,
initial_arguments, true);
}
-#endif // OS_WIN
+#endif // BUILDFLAG(IS_WIN)
crashpad::CrashpadClient& GetCrashpadClient() {
static crashpad::CrashpadClient* const client =
@@ -274,12 +274,12 @@ void SetUploadConsent(bool consent) {
#endif // !BUILDFLAG(IS_CHROMEOS_ASH)
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
void DumpWithoutCrashing() {
CRASHPAD_SIMULATE_CRASH();
}
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
void DumpWithoutCrashAndDeferProcessing() {
CRASHPAD_SIMULATE_CRASH_AND_DEFER_PROCESSING();
}
@@ -292,14 +292,15 @@ void DumpWithoutCrashAndDeferProcessingAtPath(const base::FilePath& path) {
#endif
-#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID)
void CrashWithoutDumping(const std::string& message) {
crashpad::CrashpadClient::CrashWithoutDump(message);
}
-#endif // defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) ||
+ // BUILDFLAG(IS_ANDROID)
void GetReports(std::vector<Report>* reports) {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// On Windows, the crash client may be linked into another module, which
// does the client registration. That means the global that holds the crash
// report database lives across a module boundary, where the other module
@@ -329,7 +330,7 @@ void GetReports(std::vector<Report>* reports) {
}
void RequestSingleCrashUpload(const std::string& local_id) {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// On Windows, crash reporting may be implemented in another module, which is
// why this can't call crash_reporter::RequestSingleCrashUpload directly.
RequestSingleCrashUpload_ExportThunk(local_id.c_str());
@@ -339,7 +340,7 @@ void RequestSingleCrashUpload(const std::string& local_id) {
}
base::FilePath GetCrashpadDatabasePath() {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
return base::FilePath(GetCrashpadDatabasePath_ExportThunk());
#else
return base::FilePath(GetCrashpadDatabasePathImpl());
@@ -347,7 +348,7 @@ base::FilePath GetCrashpadDatabasePath() {
}
void ClearReportsBetween(const base::Time& begin, const base::Time& end) {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
ClearReportsBetween_ExportThunk(begin.ToTimeT(), end.ToTimeT());
#else
ClearReportsBetweenImpl(begin.ToTimeT(), end.ToTimeT());
@@ -450,6 +451,13 @@ crashpad::CrashReportDatabase* GetCrashReportDatabase() {
return g_database;
}
+void SetCrashReportDatabaseForTesting( // IN-TEST
+ crashpad::CrashReportDatabase* database,
+ base::FilePath* database_path) {
+ g_database = database;
+ g_database_path = database_path;
+}
+
} // namespace internal
} // namespace crash_reporter
diff --git a/chromium/components/crash/core/app/crashpad.h b/chromium/components/crash/core/app/crashpad.h
index e6c55451607..55322a1d41b 100644
--- a/chromium/components/crash/core/app/crashpad.h
+++ b/chromium/components/crash/core/app/crashpad.h
@@ -15,18 +15,22 @@
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
#include "base/mac/scoped_mach_port.h"
#endif
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include <windows.h>
#endif
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
#include <signal.h>
#endif
+#if BUILDFLAG(IS_IOS)
+#include "base/containers/span.h"
+#endif
+
namespace base {
class Time;
}
@@ -38,7 +42,7 @@ class CrashReportDatabase;
namespace crash_reporter {
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
bool IsCrashpadEnabled();
#endif
@@ -75,7 +79,7 @@ bool IsCrashpadEnabled();
// On iOS, this will return false if Crashpad initialization fails.
bool InitializeCrashpad(bool initial_client, const std::string& process_type);
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// This is the same as InitializeCrashpad(), but rather than launching a
// crashpad_handler executable, relaunches the executable at |exe_path| or the
// current executable if |exe_path| is empty with a command line argument of
@@ -99,7 +103,7 @@ void InitializeCrashpadWithDllEmbeddedHandler(
const std::string& user_data_dir,
const base::FilePath& exe_path,
const std::vector<std::string>& initial_arguments);
-#endif // OS_WIN
+#endif // BUILDFLAG(IS_WIN)
// Returns the CrashpadClient for this process. This will lazily create it if
// it does not already exist. This is called as part of InitializeCrashpad.
@@ -148,16 +152,28 @@ void RequestSingleCrashUpload(const std::string& local_id);
void DumpWithoutCrashing();
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
void DumpWithoutCrashAndDeferProcessing();
void DumpWithoutCrashAndDeferProcessingAtPath(const base::FilePath& path);
+
+// Processes an externally generated dump.
+// An empty minidump is generated and an attachment is created with |dump_data|.
+// |source_name| is used as attachment name and is appended to the product name.
+// |override_annotations| overrides the standard simple annotations sent with
+// the report.
+// Returns whether the external dump was processed successfully.
+bool ProcessExternalDump(
+ const std::string& source_name,
+ base::span<const uint8_t> dump_data,
+ const std::map<std::string, std::string>& override_annotations = {});
#endif
-#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID)
// Logs message and immediately crashes the current process without triggering a
// crash dump.
void CrashWithoutDumping(const std::string& message);
-#endif // defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) ||
+ // BUILDFLAG(IS_ANDROID)
// Returns the Crashpad database path, only valid in the browser.
base::FilePath GetCrashpadDatabasePath();
@@ -177,13 +193,13 @@ base::FilePath::StringType::const_pointer GetCrashpadDatabasePathImpl();
// The implementation function for ClearReportsBetween.
void ClearReportsBetweenImpl(time_t begin, time_t end);
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
// Captures a minidump for the process named by its |task_port| and stores it
// in the current crash report database.
void DumpProcessWithoutCrashing(task_t task_port);
#endif
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
// Convert intermediate dumps into minidumps and trigger an upload if
// StartProcessingPendingReports() has been called. Optional |annotations| will
// merge with any process annotations. These are useful for adding annotations
@@ -204,19 +220,13 @@ void ProcessIntermediateDump(
void StartProcessingPendingReports();
#endif
-#if defined(OS_ANDROID)
-// This is used by WebView to generate a dump on behalf of the embedding app.
-// This function can only be called from the browser process. Returns `true` on
-// success.
-class CrashReporterClient;
-bool DumpWithoutCrashingForClient(CrashReporterClient* client);
-
+#if BUILDFLAG(IS_ANDROID)
// If a CrashReporterClient has enabled sanitization, this function specifies
// regions of memory which are allowed to be collected by Crashpad.
void AllowMemoryRange(void* begin, size_t size);
-#endif // OS_ANDROID
+#endif // BUILDFLAG(IS_ANDROID)
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
// Install a handler that gets a chance to handle faults before Crashpad. This
// is used by V8 for trap-based bounds checks.
void SetFirstChanceExceptionHandler(bool (*handler)(int, siginfo_t*, void*));
@@ -224,11 +234,11 @@ void SetFirstChanceExceptionHandler(bool (*handler)(int, siginfo_t*, void*));
// Gets the socket and process ID of the Crashpad handler connected to this
// process, valid if this function returns `true`.
bool GetHandlerSocket(int* sock, pid_t* pid);
-#endif // defined(OS_LINUX) || defined(OS_CHROMEOS)
+#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
namespace internal {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// Returns platform specific annotations. This is broken out on Windows only so
// that it may be reused by GetCrashKeysForKasko.
void GetPlatformCrashpadAnnotations(
@@ -238,15 +248,15 @@ void GetPlatformCrashpadAnnotations(
// target process.
DWORD WINAPI DumpProcessForHungInputThread(void* param);
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Starts the handler process with an initial client connected on fd,
// the handler will write minidump to database if write_minidump_to_database is
// true.
// Returns `true` on success.
bool StartHandlerForClient(int fd, bool write_minidump_to_database);
-#endif // OS_ANDROID
+#endif // BUILDFLAG(IS_ANDROID)
// The platform-specific portion of InitializeCrashpad(). On Windows, if
// |user_data_dir| is non-empty, the user data directory will be passed to the
@@ -267,6 +277,11 @@ bool PlatformCrashpadInitialization(
// been initialized yet.
crashpad::CrashReportDatabase* GetCrashReportDatabase();
+// Sets the global database and database path for testing. Must be called when
+// crashpad is not running.
+void SetCrashReportDatabaseForTesting(crashpad::CrashReportDatabase* database,
+ base::FilePath* database_path);
+
} // namespace internal
} // namespace crash_reporter
diff --git a/chromium/components/crash/core/app/crashpad_android.cc b/chromium/components/crash/core/app/crashpad_android.cc
index 77379417d9c..d977ff57451 100644
--- a/chromium/components/crash/core/app/crashpad_android.cc
+++ b/chromium/components/crash/core/app/crashpad_android.cc
@@ -631,25 +631,6 @@ class HandlerStarter {
bool use_java_handler_ = false;
};
-bool ConnectToHandler(CrashReporterClient* client, base::ScopedFD* connection) {
- int fds[2];
- if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) != 0) {
- PLOG(ERROR) << "socketpair";
- return false;
- }
- base::ScopedFD local_connection(fds[0]);
- base::ScopedFD handlers_socket(fds[1]);
-
- if (!HandlerStarter::Get()->StartHandlerForClient(
- client, handlers_socket.get(),
- true /* write_minidump_to_database */)) {
- return false;
- }
-
- *connection = std::move(local_connection);
- return true;
-}
-
bool g_is_browser = false;
} // namespace
@@ -674,35 +655,6 @@ void DumpWithoutCrashing() {
}
}
-bool DumpWithoutCrashingForClient(CrashReporterClient* client) {
- base::ScopedFD connection;
- if (!ConnectToHandler(client, &connection)) {
- return false;
- }
-
- siginfo_t siginfo;
- siginfo.si_signo = crashpad::Signals::kSimulatedSigno;
- siginfo.si_errno = 0;
- siginfo.si_code = 0;
-
- ucontext_t context;
- crashpad::CaptureContext(&context);
-
- crashpad::SanitizationInformation sanitization;
- crashpad::SetSanitizationInfo(client, &sanitization);
-
- crashpad::ExceptionInformation exception;
- crashpad::SetExceptionInformation(&siginfo, &context, &exception);
-
- crashpad::ExceptionHandlerProtocol::ClientInformation info;
- crashpad::SetClientInformation(&exception, &sanitization, &info);
-
- crashpad::ScopedPrSetDumpable set_dumpable(/* may_log= */ false);
-
- crashpad::ExceptionHandlerClient handler_client(connection.get(), false);
- return handler_client.RequestCrashDump(info) == 0;
-}
-
void AllowMemoryRange(void* begin, size_t length) {
crashpad::AllowedMemoryRanges::Singleton()->AddEntry(
crashpad::FromPointerCast<crashpad::VMAddress>(begin),
diff --git a/chromium/components/crash/core/app/crashpad_ios.mm b/chromium/components/crash/core/app/crashpad_ios.mm
index 29ebe7ac47c..d3db34c8fb3 100644
--- a/chromium/components/crash/core/app/crashpad_ios.mm
+++ b/chromium/components/crash/core/app/crashpad_ios.mm
@@ -11,7 +11,13 @@
#include "base/strings/sys_string_conversions.h"
#include "build/branding_buildflags.h"
#include "components/crash/core/app/crash_reporter_client.h"
+#include "third_party/crashpad/crashpad/client/crash_report_database.h"
#include "third_party/crashpad/crashpad/client/crashpad_client.h"
+#include "third_party/crashpad/crashpad/client/settings.h"
+#include "third_party/crashpad/crashpad/minidump/minidump_crashpad_info_writer.h"
+#include "third_party/crashpad/crashpad/minidump/minidump_file_writer.h"
+#include "third_party/crashpad/crashpad/minidump/minidump_simple_string_dictionary_writer.h"
+#include "third_party/crashpad/crashpad/util/misc/metrics.h"
namespace crash_reporter {
@@ -69,6 +75,75 @@ void ProcessIntermediateDump(
GetCrashpadClient().ProcessIntermediateDump(file, annotations);
}
+bool ProcessExternalDump(
+ const std::string& source,
+ base::span<const uint8_t> data,
+ const std::map<std::string, std::string>& override_annotations) {
+ auto crashpad_info_stream =
+ std::make_unique<crashpad::MinidumpCrashpadInfoWriter>();
+
+ auto simple_string_dictionary_writer =
+ std::make_unique<crashpad::MinidumpSimpleStringDictionaryWriter>();
+
+ std::map<std::string, std::string> annotations =
+ GetProcessSimpleAnnotations();
+ annotations["prod"] = annotations["prod"] + "_" + source;
+
+ for (auto& entry : override_annotations) {
+ annotations[entry.first] = entry.second;
+ }
+
+ for (auto& entry : annotations) {
+ auto writer =
+ std::make_unique<crashpad::MinidumpSimpleStringDictionaryEntryWriter>();
+ writer->SetKeyValue(entry.first, entry.second);
+ simple_string_dictionary_writer->AddEntry(std::move(writer));
+ }
+
+ crashpad_info_stream->SetSimpleAnnotations(
+ std::move(simple_string_dictionary_writer));
+
+ crashpad::CrashReportDatabase* database = internal::GetCrashReportDatabase();
+ if (!database) {
+ return false;
+ }
+ std::unique_ptr<crashpad::CrashReportDatabase::NewReport> new_report;
+ crashpad::CrashReportDatabase::OperationStatus database_status =
+ database->PrepareNewCrashReport(&new_report);
+ if (database_status != crashpad::CrashReportDatabase::kNoError) {
+ return false;
+ }
+
+ crashpad::MinidumpFileWriter minidump;
+
+ crashpad_info_stream->SetReportID(new_report->ReportID());
+ crashpad::Settings* const settings = database->GetSettings();
+ crashpad::UUID client_id;
+ if (settings && settings->GetClientID(&client_id)) {
+ crashpad_info_stream->SetClientID(client_id);
+ }
+
+ bool add_stream_result = minidump.AddStream(std::move(crashpad_info_stream));
+ DCHECK(add_stream_result);
+
+ if (data.size() > 0) {
+ crashpad::FileWriter* attachment_writer = new_report->AddAttachment(source);
+ attachment_writer->Write(data.data(), data.size());
+ }
+
+ if (!minidump.WriteEverything(new_report->Writer())) {
+ return false;
+ }
+
+ crashpad::UUID uuid;
+ database_status =
+ database->FinishedWritingCrashReport(std::move(new_report), &uuid);
+ if (database_status != crashpad::CrashReportDatabase::kNoError) {
+ return false;
+ }
+ return true;
+}
+
void StartProcessingPendingReports() {
GetCrashpadClient().StartProcessingPendingReports();
}
diff --git a/chromium/components/crash/core/app/crashpad_ios_unittest.mm b/chromium/components/crash/core/app/crashpad_ios_unittest.mm
new file mode 100644
index 00000000000..b5916832375
--- /dev/null
+++ b/chromium/components/crash/core/app/crashpad_ios_unittest.mm
@@ -0,0 +1,94 @@
+// Copyright 2021 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.
+
+#include "components/crash/core/app/crashpad.h"
+
+#import <Foundation/Foundation.h>
+
+#include "base/files/scoped_temp_dir.h"
+#include "base/strings/sys_string_conversions.h"
+#include "components/crash/core/app/crash_reporter_client.h"
+#import "components/crash/core/common/reporter_running_ios.h"
+#include "testing/platform_test.h"
+#include "third_party/crashpad/crashpad/client/crash_report_database.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace {
+
+// A class to temporarily set a crash reporter client.
+// Setting the global value when crashpad is in use can have unexpected
+// consequences, so this class asserts that the values are null before setting
+// them and restores null values on destruction.
+class ScopedTestCrashDatabaseDir {
+ public:
+ ScopedTestCrashDatabaseDir() {}
+
+ void Init() {
+ ASSERT_FALSE(crash_reporter::internal::GetCrashReportDatabase());
+ ASSERT_TRUE(database_dir_.CreateUniqueTempDir());
+ database_dir_path_ = database_dir_.GetPath();
+ database_ = crashpad::CrashReportDatabase::Initialize(database_dir_path_);
+ crash_reporter::internal::SetCrashReportDatabaseForTesting(
+ database_.get(), &database_dir_path_);
+ }
+
+ ~ScopedTestCrashDatabaseDir() {
+ crash_reporter::internal::SetCrashReportDatabaseForTesting(nullptr,
+ nullptr);
+ }
+
+ // The temporary path to the database.
+ base::FilePath DatabasePath() { return database_dir_path_; }
+
+ // The temporary database.
+ crashpad::CrashReportDatabase* Database() { return database_.get(); }
+
+ private:
+ base::ScopedTempDir database_dir_;
+ base::FilePath database_dir_path_;
+ std::unique_ptr<crashpad::CrashReportDatabase> database_;
+};
+
+} // namespace
+using CrashpadIOS = PlatformTest;
+
+TEST_F(CrashpadIOS, ProcessExternalDump) {
+ ScopedTestCrashDatabaseDir scoped_test_crash_database_dir;
+ scoped_test_crash_database_dir.Init();
+ base::FilePath database_path = scoped_test_crash_database_dir.DatabasePath();
+ crashpad::CrashReportDatabase* database =
+ scoped_test_crash_database_dir.Database();
+
+ std::vector<crashpad::CrashReportDatabase::Report> reports;
+ EXPECT_EQ(database->GetPendingReports(&reports),
+ crashpad::CrashReportDatabase::kNoError);
+ ASSERT_EQ(reports.size(), 0u);
+ std::string attachment_name = "external-source";
+ const char attachment_data[] = "external-dump-data";
+ base::span<const uint8_t> data(
+ reinterpret_cast<const uint8_t*>(attachment_data),
+ sizeof(attachment_data));
+ crash_reporter::ProcessExternalDump(attachment_name, data, {});
+
+ reports.clear();
+ EXPECT_EQ(database->GetPendingReports(&reports),
+ crashpad::CrashReportDatabase::kNoError);
+ ASSERT_EQ(reports.size(), 1u);
+
+ std::unique_ptr<const crashpad::CrashReportDatabase::UploadReport>
+ upload_report;
+ EXPECT_EQ(database->GetReportForUploading(reports[0].uuid, &upload_report),
+ crashpad::CrashReportDatabase::kNoError);
+
+ std::map<std::string, crashpad::FileReader*> attachments =
+ upload_report->GetAttachments();
+ EXPECT_EQ(attachments.size(), 1u);
+ ASSERT_NE(attachments.find(attachment_name), attachments.end());
+ char result_buffer[sizeof(attachment_data)];
+ attachments[attachment_name]->Read(result_buffer, sizeof(result_buffer));
+ EXPECT_EQ(memcmp(attachment_data, result_buffer, sizeof(attachment_data)), 0);
+}
diff --git a/chromium/components/crash/core/app/crashpad_linux.cc b/chromium/components/crash/core/app/crashpad_linux.cc
index 212bc8359f4..dc2b18b3223 100644
--- a/chromium/components/crash/core/app/crashpad_linux.cc
+++ b/chromium/components/crash/core/app/crashpad_linux.cc
@@ -25,6 +25,7 @@
#include "content/public/common/content_descriptors.h"
#include "sandbox/linux/services/namespace_sandbox.h"
#include "third_party/crashpad/crashpad/client/crashpad_client.h"
+#include "third_party/crashpad/crashpad/client/crashpad_info.h"
#if BUILDFLAG(IS_CHROMEOS_LACROS)
#include "base/build_time.h"
@@ -110,8 +111,8 @@ bool PlatformCrashpadInitialization(
}
#endif
+ CrashReporterClient* crash_reporter_client = GetCrashReporterClient();
if (initial_client) {
- CrashReporterClient* crash_reporter_client = GetCrashReporterClient();
base::FilePath metrics_path;
crash_reporter_client->GetCrashDumpLocation(database_path);
crash_reporter_client->GetCrashMetricsLocation(&metrics_path);
@@ -205,28 +206,35 @@ bool PlatformCrashpadInitialization(
annotations, arguments, false, false);
DCHECK(result);
- pthread_atfork(nullptr, nullptr, SetPtracerAtFork);
- return true;
- }
+ } else {
+ int fd = base::GlobalDescriptors::GetInstance()->Get(kCrashDumpSignal);
- int fd = base::GlobalDescriptors::GetInstance()->Get(kCrashDumpSignal);
+ pid_t pid = 0;
+ if (!sandbox::NamespaceSandbox::InNewUserNamespace()) {
+ std::string pid_string =
+ base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ switches::kCrashpadHandlerPid);
+ bool parsed = base::StringToInt(pid_string, &pid);
+ DCHECK(parsed);
+ }
- pid_t pid = 0;
- if (!sandbox::NamespaceSandbox::InNewUserNamespace()) {
- std::string pid_string =
- base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
- switches::kCrashpadHandlerPid);
- bool parsed = base::StringToInt(pid_string, &pid);
- DCHECK(parsed);
- }
+ // SIGSYS handling is reserved for the sandbox.
+ client.SetUnhandledSignals({SIGSYS});
- // SIGSYS handling is reserved for the sandbox.
- client.SetUnhandledSignals({SIGSYS});
+ client.SetHandlerSocket(crashpad::ScopedFileHandle(fd), pid);
- client.SetHandlerSocket(crashpad::ScopedFileHandle(fd), pid);
+ *database_path = base::FilePath();
+ }
pthread_atfork(nullptr, nullptr, SetPtracerAtFork);
- *database_path = base::FilePath();
+
+ if (crash_reporter_client->GetShouldDumpLargerDumps()) {
+ const uint32_t kIndirectMemoryLimit = 4 * 1024 * 1024;
+ crashpad::CrashpadInfo::GetCrashpadInfo()
+ ->set_gather_indirectly_referenced_memory(crashpad::TriState::kEnabled,
+ kIndirectMemoryLimit);
+ }
+
return true;
}
diff --git a/chromium/components/crash/core/browser/crashes_ui_util.cc b/chromium/components/crash/core/browser/crashes_ui_util.cc
index e78e470a02a..cb3c2d6e22e 100644
--- a/chromium/components/crash/core/browser/crashes_ui_util.cc
+++ b/chromium/components/crash/core/browser/crashes_ui_util.cc
@@ -11,6 +11,7 @@
#include "base/cxx17_backports.h"
#include "base/i18n/time_formatting.h"
#include "base/notreached.h"
+#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "components/strings/grit/components_chromium_strings.h"
#include "components/strings/grit/components_strings.h"
@@ -75,18 +76,20 @@ void UploadListToValue(UploadList* upload_list, base::ListValue* out_value) {
for (const auto& info : crashes) {
std::unique_ptr<base::DictionaryValue> crash(new base::DictionaryValue());
- crash->SetString("id", info.upload_id);
+ crash->SetStringKey("id", info.upload_id);
if (info.state == UploadList::UploadInfo::State::Uploaded) {
- crash->SetString("upload_time",
- base::TimeFormatFriendlyDateAndTime(info.upload_time));
+ crash->SetStringKey("upload_time",
+ base::UTF16ToUTF8(base::TimeFormatFriendlyDateAndTime(
+ info.upload_time)));
}
if (!info.capture_time.is_null()) {
- crash->SetString("capture_time",
- base::TimeFormatFriendlyDateAndTime(info.capture_time));
+ crash->SetStringKey("capture_time",
+ base::UTF16ToUTF8(base::TimeFormatFriendlyDateAndTime(
+ info.capture_time)));
}
- crash->SetString("local_id", info.local_id);
- crash->SetString("state", UploadInfoStateAsString(info.state));
- crash->SetString("file_size", info.file_size);
+ crash->SetStringKey("local_id", info.local_id);
+ crash->SetStringKey("state", UploadInfoStateAsString(info.state));
+ crash->SetStringKey("file_size", base::UTF16ToUTF8(info.file_size));
out_value->Append(std::move(crash));
}
}
diff --git a/chromium/components/crash/core/common/BUILD.gn b/chromium/components/crash/core/common/BUILD.gn
index 3c374e37d9b..81460a6cd79 100644
--- a/chromium/components/crash/core/common/BUILD.gn
+++ b/chromium/components/crash/core/common/BUILD.gn
@@ -195,7 +195,11 @@ source_set("unit_tests") {
sources += [ "crash_key_breakpad_unittest.cc" ]
}
+ # TODO(crbug.com/1186718): Enable when crash keys are supported on Fuchsia.
if (is_fuchsia) {
- sources -= [ "crash_key_unittest.cc" ]
+ sources -= [
+ "crash_key_unittest.cc",
+ "crash_keys_unittest.cc",
+ ]
}
}
diff --git a/chromium/components/crash/core/common/crash_key_breakpad.cc b/chromium/components/crash/core/common/crash_key_breakpad.cc
index bb37248d363..bd8d246f7ad 100644
--- a/chromium/components/crash/core/common/crash_key_breakpad.cc
+++ b/chromium/components/crash/core/common/crash_key_breakpad.cc
@@ -15,7 +15,7 @@
#include "components/crash/core/common/crash_key_base_support.h"
#include "components/crash/core/common/crash_key_internal.h"
-#if defined(OS_APPLE) || defined(OS_WIN)
+#if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_WIN)
#error "This file should not be used when Crashpad is available, nor on iOS."
#endif
diff --git a/chromium/components/crash/core/common/crash_keys.cc b/chromium/components/crash/core/common/crash_keys.cc
index 08455f5e144..50112e223d3 100644
--- a/chromium/components/crash/core/common/crash_keys.cc
+++ b/chromium/components/crash/core/common/crash_keys.cc
@@ -77,7 +77,7 @@ void SetSwitchesFromCommandLine(const base::CommandLine& command_line,
// Go through the argv, skipping the exec path. Stop if there are too many
// switches to hold in crash keys.
for (size_t i = 1; i < argv.size(); ++i) {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
std::string switch_str = base::WideToUTF8(argv[i]);
#else
std::string switch_str = argv[i];
diff --git a/chromium/components/crash/core/common/objc_zombie.h b/chromium/components/crash/core/common/objc_zombie.h
index 8d7ddb9d6bb..9581e3ce2e4 100644
--- a/chromium/components/crash/core/common/objc_zombie.h
+++ b/chromium/components/crash/core/common/objc_zombie.h
@@ -34,7 +34,7 @@ void CRASH_EXPORT ZombieDisable();
} // namespace ObjcEvilDoers
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
#if defined(__OBJC__)
#import <Foundation/Foundation.h>
@@ -44,6 +44,6 @@ void CRASH_EXPORT ZombieDisable();
@end
#endif // __OBJC__
-#endif // OS_APPLE
+#endif // BUILDFLAG(IS_APPLE)
#endif // COMPONENTS_CRASH_CORE_COMMON_OBJC_ZOMBIE_H_
diff --git a/chromium/components/crash/core/common/objc_zombie.mm b/chromium/components/crash/core/common/objc_zombie.mm
index 0469fb5e402..d60d4588487 100644
--- a/chromium/components/crash/core/common/objc_zombie.mm
+++ b/chromium/components/crash/core/common/objc_zombie.mm
@@ -11,9 +11,9 @@
#import <objc/runtime.h>
#include <algorithm>
+#include <tuple>
#include "base/debug/stack_trace.h"
-#include "base/ignore_result.h"
#include "base/logging.h"
#include "base/notreached.h"
#include "base/posix/eintr_wrapper.h"
@@ -196,7 +196,7 @@ BOOL GetZombieRecord(id object, ZombieRecord* record) {
BOOL DumpDeallocTrace(const void* const* array, int size) {
// Async-signal safe version of fputs, consistent with StackTrace::Print().
const char message[] = "Backtrace from -dealloc:\n";
- ignore_result(HANDLE_EINTR(write(STDERR_FILENO, message, strlen(message))));
+ std::ignore = HANDLE_EINTR(write(STDERR_FILENO, message, strlen(message)));
base::debug::StackTrace(array, size).Print();
return YES;
diff --git a/chromium/components/cronet/BUILD.gn b/chromium/components/cronet/BUILD.gn
index 602f6c211cc..2db3d1fd4ab 100644
--- a/chromium/components/cronet/BUILD.gn
+++ b/chromium/components/cronet/BUILD.gn
@@ -160,6 +160,7 @@ if (is_android) {
}
if (is_fuchsia) {
+ use_cfv2 = false
additional_manifest_fragments =
[ "//build/config/fuchsia/test/network_capabilities.test-cmx" ]
}
diff --git a/chromium/components/cronet/android/BUILD.gn b/chromium/components/cronet/android/BUILD.gn
index fdf44706c38..a60928d5d2a 100644
--- a/chromium/components/cronet/android/BUILD.gn
+++ b/chromium/components/cronet/android/BUILD.gn
@@ -1027,8 +1027,8 @@ if (!is_component_build) {
lint_suppressions_file = "lint-suppressions.xml"
lint_baseline_file = "lint-baseline.xml"
- # Still needs to support Jelly Bean. See crbug.com/922656.
- lint_min_sdk_version = 16
+ # Still needs to support KitKat. See crbug.com/1042122.
+ lint_min_sdk_version = 19
apk_name = "CronetTestInstrumentation"
android_manifest = "test/javatests/AndroidManifest.xml"
diff --git a/chromium/components/crx_file/id_util.cc b/chromium/components/crx_file/id_util.cc
index a6250c1f60e..00477f4e2db 100644
--- a/chromium/components/crx_file/id_util.cc
+++ b/chromium/components/crx_file/id_util.cc
@@ -72,7 +72,7 @@ std::string HashedIdInHex(const std::string& id) {
}
base::FilePath MaybeNormalizePath(const base::FilePath& path) {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// Normalize any drive letter to upper-case. We do this for consistency with
// net_utils::FilePathToFileURL(), which does the same thing, to make string
// comparisons simpler.
diff --git a/chromium/components/custom_handlers/BUILD.gn b/chromium/components/custom_handlers/BUILD.gn
index c0def34922f..d66b5ac8b23 100644
--- a/chromium/components/custom_handlers/BUILD.gn
+++ b/chromium/components/custom_handlers/BUILD.gn
@@ -8,7 +8,10 @@ static_library("custom_handlers") {
"pref_names.h",
"protocol_handler_registry.cc",
"protocol_handler_registry.h",
+ "protocol_handler_throttle.cc",
+ "protocol_handler_throttle.h",
]
+
deps = [
"//build:chromeos_buildflags",
"//components/keyed_service/core",
@@ -17,5 +20,54 @@ static_library("custom_handlers") {
"//components/user_prefs",
"//content/public/browser",
"//content/public/common",
+ "//services/network/public/cpp:cpp_base",
+ "//third_party/blink/public/common:headers",
+ ]
+
+ if (!is_android) {
+ sources += [
+ "register_protocol_handler_permission_request.cc",
+ "register_protocol_handler_permission_request.h",
+ ]
+
+ deps += [
+ "//components/permissions",
+ "//components/strings",
+ "//ui/base",
+ ]
+ }
+}
+
+source_set("test_support") {
+ testonly = true
+ sources = [
+ "test_protocol_handler_registry_delegate.cc",
+ "test_protocol_handler_registry_delegate.h",
+ ]
+ deps = [
+ ":custom_handlers",
+ "//base",
+ ]
+}
+
+source_set("unit_tests") {
+ testonly = true
+
+ sources = [ "protocol_handler_registry_unittest.cc" ]
+
+ deps = [
+ ":custom_handlers",
+ ":test_support",
+ "//base/test:test_support",
+ "//components/pref_registry",
+ "//components/sync_preferences",
+ "//components/sync_preferences:test_support",
+ "//components/user_prefs",
+ "//content/public/browser",
+ "//content/public/common",
+ "//content/test:test_support",
+ "//testing/gmock",
+ "//testing/gtest",
+ "//third_party/blink/public/common:headers",
]
}
diff --git a/chromium/components/custom_handlers/DEPS b/chromium/components/custom_handlers/DEPS
index abbffeb3951..32f80b99277 100644
--- a/chromium/components/custom_handlers/DEPS
+++ b/chromium/components/custom_handlers/DEPS
@@ -1,8 +1,16 @@
include_rules = [
"+components/keyed_service",
+ "+components/permissions",
"+components/pref_registry",
"+components/prefs",
+ "+components/strings",
+ "+components/sync_preferences",
"+components/user_prefs",
- "+content/public/common",
"+content/public/browser",
+ "+content/public/common",
+ "+content/public/test",
+ "+third_party/blink/public/common/loader",
+ "+third_party/blink/public/common/security",
+ "+services/network/public/cpp",
+ "+ui/base/l10n",
]
diff --git a/chromium/components/custom_handlers/protocol_handler_registry.cc b/chromium/components/custom_handlers/protocol_handler_registry.cc
index 81d71114375..407528e8163 100644
--- a/chromium/components/custom_handlers/protocol_handler_registry.cc
+++ b/chromium/components/custom_handlers/protocol_handler_registry.cc
@@ -34,7 +34,7 @@ namespace {
const ProtocolHandler& LookupHandler(
const ProtocolHandlerRegistry::ProtocolHandlerMap& handler_map,
- const std::string& scheme) {
+ base::StringPiece scheme) {
auto p = handler_map.find(scheme);
if (p != handler_map.end())
@@ -46,7 +46,8 @@ const ProtocolHandler& LookupHandler(
GURL TranslateUrl(
const ProtocolHandlerRegistry::ProtocolHandlerMap& handler_map,
const GURL& url) {
- const ProtocolHandler& handler = LookupHandler(handler_map, url.scheme());
+ const ProtocolHandler& handler =
+ LookupHandler(handler_map, url.scheme_piece());
if (handler.IsEmpty())
return GURL();
@@ -147,6 +148,9 @@ ProtocolHandlerRegistry::GetReplacedHandlers(
void ProtocolHandlerRegistry::ClearDefault(const std::string& scheme) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ // TODO(jfernandez): If we want to use StringPiece as map's key for erasing,
+ // we would need to adapt the ProtocolHandlerMap, or just use the iterator
+ // got from find(scheme).
default_handlers_.erase(scheme);
Save();
NotifyChanged();
@@ -206,7 +210,7 @@ void ProtocolHandlerRegistry::InitProtocolSettings() {
}
}
-int ProtocolHandlerRegistry::GetHandlerIndex(const std::string& scheme) const {
+int ProtocolHandlerRegistry::GetHandlerIndex(base::StringPiece scheme) const {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
const ProtocolHandler& handler = GetHandlerFor(scheme);
if (handler.IsEmpty())
@@ -225,7 +229,7 @@ int ProtocolHandlerRegistry::GetHandlerIndex(const std::string& scheme) const {
}
ProtocolHandlerRegistry::ProtocolHandlerList
-ProtocolHandlerRegistry::GetHandlersFor(const std::string& scheme) const {
+ProtocolHandlerRegistry::GetHandlersFor(base::StringPiece scheme) const {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
auto p = protocol_handlers_.find(scheme);
if (p == protocol_handlers_.end()) {
@@ -285,14 +289,15 @@ void ProtocolHandlerRegistry::GetRegisteredProtocols(
}
bool ProtocolHandlerRegistry::CanSchemeBeOverridden(
- const std::string& scheme) const {
+ base::StringPiece scheme) const {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
const ProtocolHandlerList* handlers = GetHandlerList(scheme);
// If we already have a handler for this scheme, we can add more.
if (handlers != NULL && !handlers->empty())
return true;
// Don't override a scheme if it already has an external handler.
- return !delegate_->IsExternalHandlerRegistered(scheme);
+ return !delegate_->IsExternalHandlerRegistered(
+ static_cast<std::string>(scheme));
}
bool ProtocolHandlerRegistry::IsRegistered(
@@ -311,7 +316,7 @@ bool ProtocolHandlerRegistry::IsRegisteredByUser(
}
bool ProtocolHandlerRegistry::HasPolicyRegisteredHandler(
- const std::string& scheme) {
+ base::StringPiece scheme) {
return (policy_protocol_handlers_.find(scheme) !=
policy_protocol_handlers_.end());
}
@@ -375,7 +380,7 @@ void ProtocolHandlerRegistry::RemoveIgnoredHandler(
}
bool ProtocolHandlerRegistry::IsHandledProtocol(
- const std::string& scheme) const {
+ base::StringPiece scheme) const {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
return enabled_ && !GetHandlerFor(scheme).IsEmpty();
}
@@ -415,7 +420,7 @@ void ProtocolHandlerRegistry::RemoveHandler(const ProtocolHandler& handler) {
NotifyChanged();
}
-void ProtocolHandlerRegistry::RemoveDefaultHandler(const std::string& scheme) {
+void ProtocolHandlerRegistry::RemoveDefaultHandler(base::StringPiece scheme) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
ProtocolHandler current_default = GetHandlerFor(scheme);
if (!current_default.IsEmpty())
@@ -423,7 +428,7 @@ void ProtocolHandlerRegistry::RemoveDefaultHandler(const std::string& scheme) {
}
const ProtocolHandler& ProtocolHandlerRegistry::GetHandlerFor(
- const std::string& scheme) const {
+ base::StringPiece scheme) const {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
return LookupHandler(default_handlers_, scheme);
}
@@ -517,7 +522,7 @@ void ProtocolHandlerRegistry::Save() {
}
const ProtocolHandlerRegistry::ProtocolHandlerList*
-ProtocolHandlerRegistry::GetHandlerList(const std::string& scheme) const {
+ProtocolHandlerRegistry::GetHandlerList(base::StringPiece scheme) const {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
auto p = protocol_handlers_.find(scheme);
if (p == protocol_handlers_.end()) {
@@ -621,9 +626,9 @@ ProtocolHandlerRegistry::GetHandlersFromPref(const char* pref_name) const {
return result;
}
- const base::ListValue* handlers = prefs->GetList(pref_name);
+ const base::Value* handlers = prefs->GetList(pref_name);
if (handlers) {
- for (const auto& dict : handlers->GetList()) {
+ for (const auto& dict : handlers->GetListDeprecated()) {
if (!dict.is_dict())
continue;
const base::DictionaryValue* dict_value =
diff --git a/chromium/components/custom_handlers/protocol_handler_registry.h b/chromium/components/custom_handlers/protocol_handler_registry.h
index 7d5c77de67f..fa0a2f00ddb 100644
--- a/chromium/components/custom_handlers/protocol_handler_registry.h
+++ b/chromium/components/custom_handlers/protocol_handler_registry.h
@@ -24,10 +24,6 @@ namespace user_prefs {
class PrefRegistrySyncable;
}
-namespace {
-class ProtocolHandlerRegistryTest;
-} // namespace
-
using content::ProtocolHandler;
using DefaultClientCallback = base::OnceCallback<void(bool)>;
@@ -45,9 +41,11 @@ class ProtocolHandlerRegistry : public KeyedService {
POLICY, // The handler was installed by policy
};
- typedef std::map<std::string, ProtocolHandler> ProtocolHandlerMap;
+ typedef std::map<std::string, ProtocolHandler, std::less<>>
+ ProtocolHandlerMap;
typedef std::vector<ProtocolHandler> ProtocolHandlerList;
- typedef std::map<std::string, ProtocolHandlerList> ProtocolHandlerMultiMap;
+ typedef std::map<std::string, ProtocolHandlerList, std::less<>>
+ ProtocolHandlerMultiMap;
// |Delegate| provides an interface for interacting asynchronously
// with the underlying OS for the purposes of registering Chrome
@@ -124,10 +122,10 @@ class ProtocolHandlerRegistry : public KeyedService {
// Returns the offset in the list of handlers for a protocol of the default
// handler for that protocol.
- int GetHandlerIndex(const std::string& scheme) const;
+ int GetHandlerIndex(base::StringPiece scheme) const;
// Get the list of protocol handlers for the given scheme.
- ProtocolHandlerList GetHandlersFor(const std::string& scheme) const;
+ ProtocolHandlerList GetHandlersFor(base::StringPiece scheme) const;
// Get a list of protocol handlers registered in [begin, end).
// Does not include predefined or policy installed handlers.
@@ -147,7 +145,7 @@ class ProtocolHandlerRegistry : public KeyedService {
// Returns true if we allow websites to register handlers for the given
// scheme.
- bool CanSchemeBeOverridden(const std::string& scheme) const;
+ bool CanSchemeBeOverridden(base::StringPiece scheme) const;
// Returns true if an identical protocol handler has already been registered.
bool IsRegistered(const ProtocolHandler& handler) const;
@@ -158,7 +156,7 @@ class ProtocolHandlerRegistry : public KeyedService {
// Returns true if the scheme has at least one handler that is registered by
// policy.
- bool HasPolicyRegisteredHandler(const std::string& scheme);
+ bool HasPolicyRegisteredHandler(base::StringPiece scheme);
// Returns true if an identical protocol handler is being ignored.
bool IsIgnored(const ProtocolHandler& handler) const;
@@ -173,17 +171,17 @@ class ProtocolHandlerRegistry : public KeyedService {
void RemoveIgnoredHandler(const ProtocolHandler& handler);
// Returns true if the protocol has a default protocol handler.
- bool IsHandledProtocol(const std::string& scheme) const;
+ bool IsHandledProtocol(base::StringPiece scheme) const;
// Removes the given protocol handler from the registry.
void RemoveHandler(const ProtocolHandler& handler);
// Remove the default handler for the given protocol.
- void RemoveDefaultHandler(const std::string& scheme);
+ void RemoveDefaultHandler(base::StringPiece scheme);
// Returns the default handler for this protocol, or an empty handler if none
// exists.
- const ProtocolHandler& GetHandlerFor(const std::string& scheme) const;
+ const ProtocolHandler& GetHandlerFor(base::StringPiece scheme) const;
// Returns a translated URL if |url| is handled by a protocol handler,
// otherwise it returns an empty URL.
@@ -227,7 +225,7 @@ class ProtocolHandlerRegistry : public KeyedService {
friend struct content::BrowserThread::DeleteOnThread<
content::BrowserThread::IO>;
- friend class ::ProtocolHandlerRegistryTest;
+ friend class ProtocolHandlerRegistryTest;
// Puts the given handler at the top of the list of handlers for its
// protocol.
@@ -238,7 +236,7 @@ class ProtocolHandlerRegistry : public KeyedService {
// Returns a pointer to the list of handlers registered for the given scheme,
// or NULL if there are none.
- const ProtocolHandlerList* GetHandlerList(const std::string& scheme) const;
+ const ProtocolHandlerList* GetHandlerList(base::StringPiece scheme) const;
// Makes this ProtocolHandler the default handler for its protocol.
void SetDefault(const ProtocolHandler& handler);
diff --git a/chromium/components/custom_handlers/protocol_handler_registry_unittest.cc b/chromium/components/custom_handlers/protocol_handler_registry_unittest.cc
new file mode 100644
index 00000000000..dc49e122e51
--- /dev/null
+++ b/chromium/components/custom_handlers/protocol_handler_registry_unittest.cc
@@ -0,0 +1,1189 @@
+// Copyright (c) 2012 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.
+
+#include "components/custom_handlers/protocol_handler_registry.h"
+
+#include <stddef.h>
+
+#include <memory>
+#include <set>
+#include <utility>
+
+#include "base/memory/raw_ptr.h"
+#include "base/run_loop.h"
+#include "base/scoped_observation.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/task/post_task.h"
+#include "build/build_config.h"
+#include "components/custom_handlers/pref_names.h"
+#include "components/custom_handlers/protocol_handler_registry.h"
+#include "components/custom_handlers/test_protocol_handler_registry_delegate.h"
+#include "components/pref_registry/pref_registry_syncable.h"
+#include "components/sync_preferences/pref_service_syncable.h"
+#include "components/sync_preferences/testing_pref_service_syncable.h"
+#include "components/user_prefs/user_prefs.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/common/custom_handlers/protocol_handler.h"
+#include "content/public/test/browser_task_environment.h"
+#include "content/public/test/test_browser_context.h"
+#include "content/public/test/test_renderer_host.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/security/protocol_handler_security_level.h"
+
+using content::BrowserThread;
+using content::ProtocolHandler;
+
+namespace custom_handlers {
+
+std::unique_ptr<base::DictionaryValue> GetProtocolHandlerValue(
+ const std::string& protocol,
+ const std::string& url) {
+ auto value = std::make_unique<base::DictionaryValue>();
+ value->SetString("protocol", protocol);
+ value->SetString("url", url);
+ return value;
+}
+
+std::unique_ptr<base::DictionaryValue> GetProtocolHandlerValueWithDefault(
+ const std::string& protocol,
+ const std::string& url,
+ bool is_default) {
+ std::unique_ptr<base::DictionaryValue> value =
+ GetProtocolHandlerValue(protocol, url);
+ value->SetBoolean("default", is_default);
+ return value;
+}
+
+class ProtocolHandlerChangeListener : public ProtocolHandlerRegistry::Observer {
+ public:
+ explicit ProtocolHandlerChangeListener(ProtocolHandlerRegistry* registry) {
+ registry_observation_.Observe(registry);
+ }
+
+ ProtocolHandlerChangeListener(const ProtocolHandlerChangeListener&) = delete;
+ ProtocolHandlerChangeListener& operator=(
+ const ProtocolHandlerChangeListener&) = delete;
+
+ ~ProtocolHandlerChangeListener() override = default;
+
+ int events() { return events_; }
+ bool notified() { return events_ > 0; }
+ void Clear() { events_ = 0; }
+
+ // ProtocolHandlerRegistry::Observer:
+ void OnProtocolHandlerRegistryChanged() override { ++events_; }
+
+ private:
+ int events_ = 0;
+
+ base::ScopedObservation<ProtocolHandlerRegistry,
+ ProtocolHandlerRegistry::Observer>
+ registry_observation_{this};
+};
+
+class QueryProtocolHandlerOnChange : public ProtocolHandlerRegistry::Observer {
+ public:
+ explicit QueryProtocolHandlerOnChange(ProtocolHandlerRegistry* registry)
+ : local_registry_(registry) {
+ registry_observation_.Observe(registry);
+ }
+
+ QueryProtocolHandlerOnChange(const QueryProtocolHandlerOnChange&) = delete;
+ QueryProtocolHandlerOnChange& operator=(const QueryProtocolHandlerOnChange&) =
+ delete;
+
+ // ProtocolHandlerRegistry::Observer:
+ void OnProtocolHandlerRegistryChanged() override {
+ std::vector<std::string> output;
+ local_registry_->GetRegisteredProtocols(&output);
+ called_ = true;
+ }
+
+ bool called() const { return called_; }
+
+ private:
+ raw_ptr<ProtocolHandlerRegistry> local_registry_;
+ bool called_ = false;
+
+ base::ScopedObservation<ProtocolHandlerRegistry,
+ ProtocolHandlerRegistry::Observer>
+ registry_observation_{this};
+};
+
+class ProtocolHandlerRegistryTest : public testing::Test {
+ protected:
+ ProtocolHandlerRegistryTest()
+ : test_protocol_handler_(CreateProtocolHandler("news", "news")) {}
+
+ TestProtocolHandlerRegistryDelegate* delegate() const { return delegate_; }
+ ProtocolHandlerRegistry* registry() { return registry_.get(); }
+ const ProtocolHandler& test_protocol_handler() const {
+ return test_protocol_handler_;
+ }
+
+ PrefService* GetPrefs() {
+ DCHECK(browser_context_);
+ return user_prefs::UserPrefs::Get(browser_context_.get());
+ }
+
+ ProtocolHandler CreateProtocolHandler(
+ const std::string& protocol,
+ const GURL& url,
+ blink::ProtocolHandlerSecurityLevel security_level =
+ blink::ProtocolHandlerSecurityLevel::kStrict) {
+ return ProtocolHandler::CreateProtocolHandler(protocol, url,
+ security_level);
+ }
+
+ ProtocolHandler CreateProtocolHandler(const std::string& protocol,
+ const std::string& name) {
+ return CreateProtocolHandler(protocol, GURL("https://" + name + "/%s"));
+ }
+
+ ProtocolHandler CreateWebAppProtocolHandler(const std::string& protocol,
+ const GURL& url,
+ const std::string& app_id) {
+ return ProtocolHandler::CreateWebAppProtocolHandler(protocol, url, app_id);
+ }
+
+ bool ProtocolHandlerCanRegisterProtocol(
+ const std::string& protocol,
+ const GURL& handler_url,
+ blink::ProtocolHandlerSecurityLevel security_level) {
+ registry()->OnAcceptRegisterProtocolHandler(
+ CreateProtocolHandler(protocol, handler_url, security_level));
+ return registry()->IsHandledProtocol(protocol);
+ }
+
+ void RecreateRegistry(bool initialize) {
+ TeadDownRegistry();
+ SetUpRegistry(initialize);
+ }
+
+ int InPrefHandlerCount() {
+ const base::Value* in_pref_handlers = GetPrefs()->GetList(
+ custom_handlers::prefs::kRegisteredProtocolHandlers);
+ return static_cast<int>(in_pref_handlers->GetListDeprecated().size());
+ }
+
+ int InMemoryHandlerCount() {
+ int in_memory_handler_count = 0;
+ auto it = registry()->protocol_handlers_.begin();
+ for (; it != registry()->protocol_handlers_.end(); ++it)
+ in_memory_handler_count += it->second.size();
+ return in_memory_handler_count;
+ }
+
+ int InPrefIgnoredHandlerCount() {
+ const base::Value* in_pref_ignored_handlers =
+ GetPrefs()->GetList(custom_handlers::prefs::kIgnoredProtocolHandlers);
+ return static_cast<int>(
+ in_pref_ignored_handlers->GetListDeprecated().size());
+ }
+
+ int InMemoryIgnoredHandlerCount() {
+ int in_memory_ignored_handler_count = 0;
+ auto it = registry()->ignored_protocol_handlers_.begin();
+ for (; it != registry()->ignored_protocol_handlers_.end(); ++it)
+ in_memory_ignored_handler_count++;
+ return in_memory_ignored_handler_count;
+ }
+
+ // It creates a new instance of the ProtocolHandlerRegistry class,
+ // initializing it if |initialize| is true, for the registry_ member variable.
+ void SetUpRegistry(bool initialize) {
+ DCHECK(browser_context_);
+ auto delegate = std::make_unique<TestProtocolHandlerRegistryDelegate>();
+ delegate_ = delegate.get();
+ registry_ = std::make_unique<ProtocolHandlerRegistry>(
+ browser_context_.get(), std::move(delegate));
+ if (initialize)
+ registry_->InitProtocolSettings();
+ }
+
+ void TeadDownRegistry() {
+ registry_->Shutdown();
+ registry_.reset();
+ }
+
+ void SetUp() override {
+ browser_context_ = std::make_unique<content::TestBrowserContext>();
+ user_prefs::UserPrefs::Set(browser_context_.get(), &pref_service_);
+ ProtocolHandlerRegistry::RegisterProfilePrefs(pref_service_.registry());
+ CHECK(GetPrefs());
+ SetUpRegistry(true);
+ test_protocol_handler_ =
+ CreateProtocolHandler("news", GURL("https://test.com/%s"));
+ }
+
+ void TearDown() override { TeadDownRegistry(); }
+
+ private:
+ content::BrowserTaskEnvironment task_environment_;
+
+ std::unique_ptr<content::TestBrowserContext> browser_context_;
+ sync_preferences::TestingPrefServiceSyncable pref_service_;
+ raw_ptr<TestProtocolHandlerRegistryDelegate>
+ delegate_; // Registry assumes ownership of delegate_.
+ std::unique_ptr<ProtocolHandlerRegistry> registry_;
+ ProtocolHandler test_protocol_handler_;
+};
+
+TEST_F(ProtocolHandlerRegistryTest, AcceptProtocolHandlerHandlesProtocol) {
+ ASSERT_FALSE(registry()->IsHandledProtocol("news"));
+ registry()->OnAcceptRegisterProtocolHandler(test_protocol_handler());
+ ASSERT_TRUE(registry()->IsHandledProtocol("news"));
+}
+
+TEST_F(ProtocolHandlerRegistryTest, DeniedProtocolIsntHandledUntilAccepted) {
+ registry()->OnDenyRegisterProtocolHandler(test_protocol_handler());
+ ASSERT_FALSE(registry()->IsHandledProtocol("news"));
+ registry()->OnAcceptRegisterProtocolHandler(test_protocol_handler());
+ ASSERT_TRUE(registry()->IsHandledProtocol("news"));
+}
+
+TEST_F(ProtocolHandlerRegistryTest, ClearDefaultMakesProtocolNotHandled) {
+ registry()->OnAcceptRegisterProtocolHandler(test_protocol_handler());
+ registry()->ClearDefault("news");
+ ASSERT_FALSE(registry()->IsHandledProtocol("news"));
+ ASSERT_TRUE(registry()->GetHandlerFor("news").IsEmpty());
+}
+
+TEST_F(ProtocolHandlerRegistryTest, DisableDeregistersProtocolHandlers) {
+ ASSERT_FALSE(delegate()->IsExternalHandlerRegistered("news"));
+ registry()->OnAcceptRegisterProtocolHandler(test_protocol_handler());
+ ASSERT_TRUE(delegate()->IsExternalHandlerRegistered("news"));
+
+ registry()->Disable();
+ ASSERT_FALSE(delegate()->IsExternalHandlerRegistered("news"));
+ registry()->Enable();
+ ASSERT_TRUE(delegate()->IsExternalHandlerRegistered("news"));
+}
+
+TEST_F(ProtocolHandlerRegistryTest, IgnoreProtocolHandler) {
+ registry()->OnIgnoreRegisterProtocolHandler(test_protocol_handler());
+ ASSERT_TRUE(registry()->IsIgnored(test_protocol_handler()));
+
+ registry()->RemoveIgnoredHandler(test_protocol_handler());
+ ASSERT_FALSE(registry()->IsIgnored(test_protocol_handler()));
+}
+
+TEST_F(ProtocolHandlerRegistryTest, IgnoreEquivalentProtocolHandler) {
+ ProtocolHandler ph1 = CreateProtocolHandler("news", GURL("https://test/%s"));
+ ProtocolHandler ph2 = CreateProtocolHandler("news", GURL("https://test/%s"));
+
+ registry()->OnIgnoreRegisterProtocolHandler(ph1);
+ ASSERT_TRUE(registry()->IsIgnored(ph1));
+ ASSERT_TRUE(registry()->HasIgnoredEquivalent(ph2));
+
+ registry()->RemoveIgnoredHandler(ph1);
+ ASSERT_FALSE(registry()->IsIgnored(ph1));
+ ASSERT_FALSE(registry()->HasIgnoredEquivalent(ph2));
+}
+
+TEST_F(ProtocolHandlerRegistryTest, SaveAndLoad) {
+ ProtocolHandler stuff_protocol_handler(
+ CreateProtocolHandler("stuff", "stuff"));
+ registry()->OnAcceptRegisterProtocolHandler(test_protocol_handler());
+ registry()->OnIgnoreRegisterProtocolHandler(stuff_protocol_handler);
+
+ ASSERT_TRUE(registry()->IsHandledProtocol("news"));
+ ASSERT_TRUE(registry()->IsIgnored(stuff_protocol_handler));
+ delegate()->Reset();
+ RecreateRegistry(true);
+ ASSERT_TRUE(registry()->IsHandledProtocol("news"));
+ ASSERT_TRUE(registry()->IsIgnored(stuff_protocol_handler));
+}
+
+TEST_F(ProtocolHandlerRegistryTest, Encode) {
+ base::Time now = base::Time::Now();
+ ProtocolHandler handler("news", GURL("https://example.com"), "app_id", now,
+ blink::ProtocolHandlerSecurityLevel::kStrict);
+ auto value = handler.Encode();
+ ProtocolHandler recreated =
+ ProtocolHandler::CreateProtocolHandler(value.get());
+ EXPECT_EQ("news", recreated.protocol());
+ EXPECT_EQ(GURL("https://example.com"), recreated.url());
+ EXPECT_EQ(now, recreated.last_modified());
+}
+
+TEST_F(ProtocolHandlerRegistryTest, GetHandlersBetween) {
+ base::Time now = base::Time::Now();
+ base::Time one_hour_ago = now - base::Hours(1);
+ base::Time two_hours_ago = now - base::Hours(2);
+ ProtocolHandler handler1("bitcoin", GURL("https://example.com"),
+ two_hours_ago,
+ blink::ProtocolHandlerSecurityLevel::kStrict);
+ ProtocolHandler handler2("geo", GURL("https://example.com"), one_hour_ago,
+ blink::ProtocolHandlerSecurityLevel::kStrict);
+ ProtocolHandler handler3("im", GURL("https://example.com"), now,
+ blink::ProtocolHandlerSecurityLevel::kStrict);
+ registry()->OnAcceptRegisterProtocolHandler(handler1);
+ registry()->OnAcceptRegisterProtocolHandler(handler2);
+ registry()->OnAcceptRegisterProtocolHandler(handler3);
+
+ EXPECT_EQ(
+ std::vector<ProtocolHandler>({handler1, handler2, handler3}),
+ registry()->GetUserDefinedHandlers(base::Time(), base::Time::Max()));
+ EXPECT_EQ(
+ std::vector<ProtocolHandler>({handler2, handler3}),
+ registry()->GetUserDefinedHandlers(one_hour_ago, base::Time::Max()));
+ EXPECT_EQ(std::vector<ProtocolHandler>({handler1, handler2}),
+ registry()->GetUserDefinedHandlers(base::Time(), now));
+}
+
+TEST_F(ProtocolHandlerRegistryTest, ClearHandlersBetween) {
+ base::Time now = base::Time::Now();
+ base::Time one_hour_ago = now - base::Hours(1);
+ base::Time two_hours_ago = now - base::Hours(2);
+ GURL url("https://example.com");
+ ProtocolHandler handler1("bitcoin", url, two_hours_ago,
+ blink::ProtocolHandlerSecurityLevel::kStrict);
+ ProtocolHandler handler2("geo", url, one_hour_ago,
+ blink::ProtocolHandlerSecurityLevel::kStrict);
+ ProtocolHandler handler3("im", url, now,
+ blink::ProtocolHandlerSecurityLevel::kStrict);
+ ProtocolHandler ignored1("irc", url, two_hours_ago,
+ blink::ProtocolHandlerSecurityLevel::kStrict);
+ ProtocolHandler ignored2("ircs", url, one_hour_ago,
+ blink::ProtocolHandlerSecurityLevel::kStrict);
+ ProtocolHandler ignored3("magnet", url, now,
+ blink::ProtocolHandlerSecurityLevel::kStrict);
+ registry()->OnAcceptRegisterProtocolHandler(handler1);
+ registry()->OnAcceptRegisterProtocolHandler(handler2);
+ registry()->OnAcceptRegisterProtocolHandler(handler3);
+ registry()->OnIgnoreRegisterProtocolHandler(ignored1);
+ registry()->OnIgnoreRegisterProtocolHandler(ignored2);
+ registry()->OnIgnoreRegisterProtocolHandler(ignored3);
+
+ EXPECT_TRUE(registry()->IsHandledProtocol("bitcoin"));
+ EXPECT_TRUE(registry()->IsHandledProtocol("geo"));
+ EXPECT_TRUE(registry()->IsHandledProtocol("im"));
+ EXPECT_TRUE(registry()->IsIgnored(ignored1));
+ EXPECT_TRUE(registry()->IsIgnored(ignored2));
+ EXPECT_TRUE(registry()->IsIgnored(ignored3));
+
+ // Delete handler2 and ignored2.
+ registry()->ClearUserDefinedHandlers(one_hour_ago, now);
+ EXPECT_TRUE(registry()->IsHandledProtocol("bitcoin"));
+ EXPECT_FALSE(registry()->IsHandledProtocol("geo"));
+ EXPECT_TRUE(registry()->IsHandledProtocol("im"));
+ EXPECT_TRUE(registry()->IsIgnored(ignored1));
+ EXPECT_FALSE(registry()->IsIgnored(ignored2));
+ EXPECT_TRUE(registry()->IsIgnored(ignored3));
+
+ // Delete all.
+ registry()->ClearUserDefinedHandlers(base::Time(), base::Time::Max());
+ EXPECT_FALSE(registry()->IsHandledProtocol("bitcoin"));
+ EXPECT_FALSE(registry()->IsHandledProtocol("geo"));
+ EXPECT_FALSE(registry()->IsHandledProtocol("im"));
+ EXPECT_FALSE(registry()->IsIgnored(ignored1));
+ EXPECT_FALSE(registry()->IsIgnored(ignored2));
+ EXPECT_FALSE(registry()->IsIgnored(ignored3));
+}
+
+TEST_F(ProtocolHandlerRegistryTest, TestEnabledDisabled) {
+ registry()->Disable();
+ ASSERT_FALSE(registry()->enabled());
+ registry()->Enable();
+ ASSERT_TRUE(registry()->enabled());
+}
+
+TEST_F(ProtocolHandlerRegistryTest,
+ DisallowRegisteringExternallyHandledProtocols) {
+ ASSERT_TRUE(!delegate()->IsExternalHandlerRegistered("news"));
+ delegate()->RegisterExternalHandler("news");
+ ASSERT_FALSE(registry()->CanSchemeBeOverridden("news"));
+}
+
+TEST_F(ProtocolHandlerRegistryTest, RemovingHandlerMeansItCanBeAddedAgain) {
+ registry()->OnAcceptRegisterProtocolHandler(test_protocol_handler());
+ ASSERT_TRUE(registry()->CanSchemeBeOverridden("news"));
+ registry()->RemoveHandler(test_protocol_handler());
+ ASSERT_TRUE(registry()->CanSchemeBeOverridden("news"));
+}
+
+TEST_F(ProtocolHandlerRegistryTest, TestStartsAsDefault) {
+ registry()->OnAcceptRegisterProtocolHandler(test_protocol_handler());
+ ASSERT_TRUE(registry()->IsDefault(test_protocol_handler()));
+}
+
+TEST_F(ProtocolHandlerRegistryTest, TestClearDefault) {
+ ProtocolHandler ph1 = CreateProtocolHandler("news", "test1");
+ ProtocolHandler ph2 = CreateProtocolHandler("news", "test2");
+ registry()->OnAcceptRegisterProtocolHandler(ph1);
+ registry()->OnAcceptRegisterProtocolHandler(ph2);
+
+ registry()->OnAcceptRegisterProtocolHandler(ph1);
+ registry()->ClearDefault("news");
+ ASSERT_FALSE(registry()->IsDefault(ph1));
+ ASSERT_FALSE(registry()->IsDefault(ph2));
+}
+
+TEST_F(ProtocolHandlerRegistryTest, TestGetHandlerFor) {
+ ProtocolHandler ph1 = CreateProtocolHandler("news", "test1");
+ ProtocolHandler ph2 = CreateProtocolHandler("news", "test2");
+ registry()->OnAcceptRegisterProtocolHandler(ph1);
+ registry()->OnAcceptRegisterProtocolHandler(ph2);
+
+ registry()->OnAcceptRegisterProtocolHandler(ph2);
+ ASSERT_EQ(ph2, registry()->GetHandlerFor("news"));
+ ASSERT_TRUE(registry()->IsHandledProtocol("news"));
+}
+
+TEST_F(ProtocolHandlerRegistryTest, TestMostRecentHandlerIsDefault) {
+ ProtocolHandler ph1 = CreateProtocolHandler("news", "test1");
+ ProtocolHandler ph2 = CreateProtocolHandler("news", "test2");
+ registry()->OnAcceptRegisterProtocolHandler(ph1);
+ registry()->OnAcceptRegisterProtocolHandler(ph2);
+ ASSERT_FALSE(registry()->IsDefault(ph1));
+ ASSERT_TRUE(registry()->IsDefault(ph2));
+}
+
+TEST_F(ProtocolHandlerRegistryTest, TestOnAcceptRegisterProtocolHandler) {
+ ProtocolHandler ph1 = CreateProtocolHandler("news", "test1");
+ ProtocolHandler ph2 = CreateProtocolHandler("news", "test2");
+ registry()->OnAcceptRegisterProtocolHandler(ph1);
+ registry()->OnAcceptRegisterProtocolHandler(ph2);
+
+ registry()->OnAcceptRegisterProtocolHandler(ph1);
+ ASSERT_TRUE(registry()->IsDefault(ph1));
+ ASSERT_FALSE(registry()->IsDefault(ph2));
+
+ registry()->OnAcceptRegisterProtocolHandler(ph2);
+ ASSERT_FALSE(registry()->IsDefault(ph1));
+ ASSERT_TRUE(registry()->IsDefault(ph2));
+}
+
+TEST_F(ProtocolHandlerRegistryTest, TestDefaultSaveLoad) {
+ ProtocolHandler ph1 = CreateProtocolHandler("news", "test1");
+ ProtocolHandler ph2 = CreateProtocolHandler("news", "test2");
+ registry()->OnDenyRegisterProtocolHandler(ph1);
+ registry()->OnDenyRegisterProtocolHandler(ph2);
+
+ registry()->OnAcceptRegisterProtocolHandler(ph2);
+ registry()->Disable();
+
+ RecreateRegistry(true);
+
+ ASSERT_FALSE(registry()->enabled());
+ registry()->Enable();
+ ASSERT_FALSE(registry()->IsDefault(ph1));
+ ASSERT_TRUE(registry()->IsDefault(ph2));
+
+ RecreateRegistry(true);
+ ASSERT_TRUE(registry()->enabled());
+}
+
+TEST_F(ProtocolHandlerRegistryTest, TestRemoveHandler) {
+ ProtocolHandler ph1 = CreateProtocolHandler("news", "test1");
+ registry()->OnAcceptRegisterProtocolHandler(ph1);
+ registry()->OnAcceptRegisterProtocolHandler(ph1);
+
+ registry()->RemoveHandler(ph1);
+ ASSERT_FALSE(registry()->IsRegistered(ph1));
+ ASSERT_FALSE(registry()->IsHandledProtocol("news"));
+
+ registry()->OnIgnoreRegisterProtocolHandler(ph1);
+ ASSERT_FALSE(registry()->IsRegistered(ph1));
+ ASSERT_TRUE(registry()->IsIgnored(ph1));
+
+ registry()->RemoveHandler(ph1);
+ ASSERT_FALSE(registry()->IsRegistered(ph1));
+ ASSERT_FALSE(registry()->IsIgnored(ph1));
+}
+
+TEST_F(ProtocolHandlerRegistryTest, TestIsRegistered) {
+ ProtocolHandler ph1 = CreateProtocolHandler("news", "test1");
+ ProtocolHandler ph2 = CreateProtocolHandler("news", "test2");
+ registry()->OnAcceptRegisterProtocolHandler(ph1);
+ registry()->OnAcceptRegisterProtocolHandler(ph2);
+
+ ASSERT_TRUE(registry()->IsRegistered(ph1));
+}
+
+TEST_F(ProtocolHandlerRegistryTest, TestIsEquivalentRegistered) {
+ ProtocolHandler ph1 = CreateProtocolHandler("news", GURL("https://test/%s"));
+ ProtocolHandler ph2 = CreateProtocolHandler("news", GURL("https://test/%s"));
+ registry()->OnAcceptRegisterProtocolHandler(ph1);
+
+ ASSERT_TRUE(registry()->IsRegistered(ph1));
+ ASSERT_TRUE(registry()->HasRegisteredEquivalent(ph2));
+}
+
+TEST_F(ProtocolHandlerRegistryTest, TestSilentlyRegisterHandler) {
+ ProtocolHandler ph1 =
+ CreateProtocolHandler("news", GURL("https://test/1/%s"));
+ ProtocolHandler ph2 =
+ CreateProtocolHandler("news", GURL("https://test/2/%s"));
+ ProtocolHandler ph3 =
+ CreateProtocolHandler("ignore", GURL("https://test/%s"));
+ ProtocolHandler ph4 =
+ CreateProtocolHandler("ignore", GURL("https://test/%s"));
+
+ ASSERT_FALSE(registry()->SilentlyHandleRegisterHandlerRequest(ph1));
+ ASSERT_FALSE(registry()->IsRegistered(ph1));
+
+ registry()->OnAcceptRegisterProtocolHandler(ph1);
+ ASSERT_TRUE(registry()->IsRegistered(ph1));
+
+ ASSERT_TRUE(registry()->SilentlyHandleRegisterHandlerRequest(ph2));
+ ASSERT_FALSE(registry()->IsRegistered(ph1));
+ ASSERT_TRUE(registry()->IsRegistered(ph2));
+
+ ASSERT_FALSE(registry()->SilentlyHandleRegisterHandlerRequest(ph3));
+ ASSERT_FALSE(registry()->IsRegistered(ph3));
+
+ registry()->OnIgnoreRegisterProtocolHandler(ph3);
+ ASSERT_FALSE(registry()->IsRegistered(ph3));
+ ASSERT_TRUE(registry()->IsIgnored(ph3));
+
+ ASSERT_TRUE(registry()->SilentlyHandleRegisterHandlerRequest(ph4));
+ ASSERT_FALSE(registry()->IsRegistered(ph4));
+ ASSERT_TRUE(registry()->HasIgnoredEquivalent(ph4));
+}
+
+TEST_F(ProtocolHandlerRegistryTest, TestRemoveHandlerRemovesDefault) {
+ ProtocolHandler ph1 = CreateProtocolHandler("news", "test1");
+ ProtocolHandler ph2 = CreateProtocolHandler("news", "test2");
+ ProtocolHandler ph3 = CreateProtocolHandler("news", "test3");
+
+ registry()->OnAcceptRegisterProtocolHandler(ph1);
+ registry()->OnAcceptRegisterProtocolHandler(ph2);
+ registry()->OnAcceptRegisterProtocolHandler(ph3);
+
+ registry()->OnAcceptRegisterProtocolHandler(ph1);
+ registry()->RemoveHandler(ph1);
+ ASSERT_FALSE(registry()->IsDefault(ph1));
+}
+
+TEST_F(ProtocolHandlerRegistryTest, TestGetHandlersFor) {
+ ProtocolHandler ph1 = CreateProtocolHandler("news", "test1");
+ ProtocolHandler ph2 = CreateProtocolHandler("news", "test2");
+ ProtocolHandler ph3 = CreateProtocolHandler("news", "test3");
+ registry()->OnAcceptRegisterProtocolHandler(ph1);
+ registry()->OnAcceptRegisterProtocolHandler(ph2);
+ registry()->OnAcceptRegisterProtocolHandler(ph3);
+
+ ProtocolHandlerRegistry::ProtocolHandlerList handlers =
+ registry()->GetHandlersFor("news");
+ ASSERT_EQ(static_cast<size_t>(3), handlers.size());
+
+ ASSERT_EQ(ph3, handlers[0]);
+ ASSERT_EQ(ph2, handlers[1]);
+ ASSERT_EQ(ph1, handlers[2]);
+}
+
+TEST_F(ProtocolHandlerRegistryTest, TestGetRegisteredProtocols) {
+ std::vector<std::string> protocols;
+ registry()->GetRegisteredProtocols(&protocols);
+ ASSERT_EQ(static_cast<size_t>(0), protocols.size());
+
+ registry()->GetHandlersFor("news");
+
+ protocols.clear();
+ registry()->GetRegisteredProtocols(&protocols);
+ ASSERT_EQ(static_cast<size_t>(0), protocols.size());
+}
+
+TEST_F(ProtocolHandlerRegistryTest, TestIsHandledProtocol) {
+ registry()->GetHandlersFor("news");
+ ASSERT_FALSE(registry()->IsHandledProtocol("news"));
+}
+
+TEST_F(ProtocolHandlerRegistryTest, TestObserver) {
+ ProtocolHandler ph1 = CreateProtocolHandler("news", "test1");
+ ProtocolHandlerChangeListener counter(registry());
+
+ registry()->OnAcceptRegisterProtocolHandler(ph1);
+ ASSERT_TRUE(counter.notified());
+ counter.Clear();
+
+ registry()->Disable();
+ ASSERT_TRUE(counter.notified());
+ counter.Clear();
+
+ registry()->Enable();
+ ASSERT_TRUE(counter.notified());
+ counter.Clear();
+
+ registry()->RemoveHandler(ph1);
+ ASSERT_TRUE(counter.notified());
+ counter.Clear();
+}
+
+TEST_F(ProtocolHandlerRegistryTest, TestReentrantObserver) {
+ QueryProtocolHandlerOnChange queryer(registry());
+ ProtocolHandler ph1 = CreateProtocolHandler("news", "test1");
+ registry()->OnAcceptRegisterProtocolHandler(ph1);
+ ASSERT_TRUE(queryer.called());
+}
+
+TEST_F(ProtocolHandlerRegistryTest, TestProtocolsWithNoDefaultAreHandled) {
+ ProtocolHandler ph1 = CreateProtocolHandler("news", "test1");
+ registry()->OnAcceptRegisterProtocolHandler(ph1);
+ registry()->ClearDefault("news");
+ std::vector<std::string> handled_protocols;
+ registry()->GetRegisteredProtocols(&handled_protocols);
+ ASSERT_EQ(static_cast<size_t>(1), handled_protocols.size());
+ ASSERT_EQ("news", handled_protocols[0]);
+}
+
+TEST_F(ProtocolHandlerRegistryTest, TestDisablePreventsHandling) {
+ ProtocolHandler ph1 = CreateProtocolHandler("news", "test1");
+ registry()->OnAcceptRegisterProtocolHandler(ph1);
+ ASSERT_TRUE(registry()->IsHandledProtocol("news"));
+ registry()->Disable();
+ ASSERT_FALSE(registry()->IsHandledProtocol("news"));
+}
+
+TEST_F(ProtocolHandlerRegistryTest, TestOSRegistration) {
+ ProtocolHandler ph_do1 = CreateProtocolHandler("news", "test1");
+ ProtocolHandler ph_do2 = CreateProtocolHandler("news", "test2");
+ ProtocolHandler ph_dont = CreateProtocolHandler("im", "test3");
+
+ ASSERT_FALSE(delegate()->IsFakeRegisteredWithOS("news"));
+ ASSERT_FALSE(delegate()->IsFakeRegisteredWithOS("im"));
+
+ registry()->OnAcceptRegisterProtocolHandler(ph_do1);
+ registry()->OnDenyRegisterProtocolHandler(ph_dont);
+ base::RunLoop().RunUntilIdle();
+
+ ASSERT_TRUE(delegate()->IsFakeRegisteredWithOS("news"));
+ ASSERT_FALSE(delegate()->IsFakeRegisteredWithOS("im"));
+
+ // This should not register with the OS, if it does the delegate
+ // will assert for us. We don't need to wait for the message loop
+ // as it should not go through to the shell worker.
+ registry()->OnAcceptRegisterProtocolHandler(ph_do2);
+}
+
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+// TODO(benwells): When Linux support is more reliable and
+// http://crbug.com/88255 is fixed this test will pass.
+#define MAYBE_TestOSRegistrationFailure DISABLED_TestOSRegistrationFailure
+#else
+#define MAYBE_TestOSRegistrationFailure TestOSRegistrationFailure
+#endif
+
+TEST_F(ProtocolHandlerRegistryTest, MAYBE_TestOSRegistrationFailure) {
+ ProtocolHandler ph_do = CreateProtocolHandler("news", "test1");
+ ProtocolHandler ph_dont = CreateProtocolHandler("im", "test2");
+
+ ASSERT_FALSE(registry()->IsHandledProtocol("news"));
+ ASSERT_FALSE(registry()->IsHandledProtocol("im"));
+
+ registry()->OnAcceptRegisterProtocolHandler(ph_do);
+ base::RunLoop().RunUntilIdle();
+
+ delegate()->set_force_os_failure(true);
+ registry()->OnAcceptRegisterProtocolHandler(ph_dont);
+ base::RunLoop().RunUntilIdle();
+
+ ASSERT_TRUE(registry()->IsHandledProtocol("news"));
+ ASSERT_EQ(static_cast<size_t>(1), registry()->GetHandlersFor("news").size());
+ ASSERT_FALSE(registry()->IsHandledProtocol("im"));
+ ASSERT_EQ(static_cast<size_t>(1), registry()->GetHandlersFor("im").size());
+}
+
+TEST_F(ProtocolHandlerRegistryTest, TestRemovingDefaultFallsBackToOldDefault) {
+ ProtocolHandler ph1 = CreateProtocolHandler("mailto", "test1");
+ ProtocolHandler ph2 = CreateProtocolHandler("mailto", "test2");
+ ProtocolHandler ph3 = CreateProtocolHandler("mailto", "test3");
+ registry()->OnAcceptRegisterProtocolHandler(ph1);
+ registry()->OnAcceptRegisterProtocolHandler(ph2);
+ registry()->OnAcceptRegisterProtocolHandler(ph3);
+
+ ASSERT_TRUE(registry()->IsDefault(ph3));
+ registry()->RemoveHandler(ph3);
+ ASSERT_TRUE(registry()->IsDefault(ph2));
+ registry()->OnAcceptRegisterProtocolHandler(ph3);
+ ASSERT_TRUE(registry()->IsDefault(ph3));
+ registry()->RemoveHandler(ph2);
+ ASSERT_TRUE(registry()->IsDefault(ph3));
+ registry()->RemoveHandler(ph3);
+ ASSERT_TRUE(registry()->IsDefault(ph1));
+}
+
+TEST_F(ProtocolHandlerRegistryTest, TestRemovingDefaultDoesntChangeHandlers) {
+ ProtocolHandler ph1 = CreateProtocolHandler("mailto", "test1");
+ ProtocolHandler ph2 = CreateProtocolHandler("mailto", "test2");
+ ProtocolHandler ph3 = CreateProtocolHandler("mailto", "test3");
+ registry()->OnAcceptRegisterProtocolHandler(ph1);
+ registry()->OnAcceptRegisterProtocolHandler(ph2);
+ registry()->OnAcceptRegisterProtocolHandler(ph3);
+ registry()->RemoveHandler(ph3);
+
+ ProtocolHandlerRegistry::ProtocolHandlerList handlers =
+ registry()->GetHandlersFor("mailto");
+ ASSERT_EQ(static_cast<size_t>(2), handlers.size());
+
+ ASSERT_EQ(ph2, handlers[0]);
+ ASSERT_EQ(ph1, handlers[1]);
+}
+
+TEST_F(ProtocolHandlerRegistryTest, TestReplaceHandler) {
+ ProtocolHandler ph1 =
+ CreateProtocolHandler("mailto", GURL("https://test.com/%s"));
+ ProtocolHandler ph2 =
+ CreateProtocolHandler("mailto", GURL("https://test.com/updated-url/%s"));
+ registry()->OnAcceptRegisterProtocolHandler(ph1);
+ ASSERT_TRUE(registry()->AttemptReplace(ph2));
+ const ProtocolHandler& handler(registry()->GetHandlerFor("mailto"));
+ ASSERT_EQ(handler.url(), ph2.url());
+}
+
+TEST_F(ProtocolHandlerRegistryTest, TestReplaceNonDefaultHandler) {
+ ProtocolHandler ph1 =
+ CreateProtocolHandler("mailto", GURL("https://test.com/%s"));
+ ProtocolHandler ph2 =
+ CreateProtocolHandler("mailto", GURL("https://test.com/updated-url/%s"));
+ ProtocolHandler ph3 =
+ CreateProtocolHandler("mailto", GURL("https://else.com/%s"));
+ registry()->OnAcceptRegisterProtocolHandler(ph1);
+ registry()->OnAcceptRegisterProtocolHandler(ph3);
+ ASSERT_TRUE(registry()->AttemptReplace(ph2));
+ const ProtocolHandler& handler(registry()->GetHandlerFor("mailto"));
+ ASSERT_EQ(handler.url(), ph3.url());
+}
+
+TEST_F(ProtocolHandlerRegistryTest, TestReplaceRemovesStaleHandlers) {
+ ProtocolHandler ph1 =
+ CreateProtocolHandler("mailto", GURL("https://test.com/%s"));
+ ProtocolHandler ph2 =
+ CreateProtocolHandler("mailto", GURL("https://test.com/updated-url/%s"));
+ ProtocolHandler ph3 =
+ CreateProtocolHandler("mailto", GURL("https://test.com/third/%s"));
+ registry()->OnAcceptRegisterProtocolHandler(ph1);
+ registry()->OnAcceptRegisterProtocolHandler(ph2);
+
+ // This should replace the previous two handlers.
+ ASSERT_TRUE(registry()->AttemptReplace(ph3));
+ const ProtocolHandler& handler(registry()->GetHandlerFor("mailto"));
+ ASSERT_EQ(handler.url(), ph3.url());
+ registry()->RemoveHandler(ph3);
+ ASSERT_TRUE(registry()->GetHandlerFor("mailto").IsEmpty());
+}
+
+TEST_F(ProtocolHandlerRegistryTest, TestIsSameOrigin) {
+ ProtocolHandler ph1 =
+ CreateProtocolHandler("mailto", GURL("https://test.com/%s"));
+ ProtocolHandler ph2 =
+ CreateProtocolHandler("mailto", GURL("https://test.com/updated-url/%s"));
+ ProtocolHandler ph3 =
+ CreateProtocolHandler("mailto", GURL("https://other.com/%s"));
+ ASSERT_EQ(ph1.url().DeprecatedGetOriginAsURL() ==
+ ph2.url().DeprecatedGetOriginAsURL(),
+ ph1.IsSameOrigin(ph2));
+ ASSERT_EQ(ph1.url().DeprecatedGetOriginAsURL() ==
+ ph2.url().DeprecatedGetOriginAsURL(),
+ ph2.IsSameOrigin(ph1));
+ ASSERT_EQ(ph2.url().DeprecatedGetOriginAsURL() ==
+ ph3.url().DeprecatedGetOriginAsURL(),
+ ph2.IsSameOrigin(ph3));
+ ASSERT_EQ(ph3.url().DeprecatedGetOriginAsURL() ==
+ ph2.url().DeprecatedGetOriginAsURL(),
+ ph3.IsSameOrigin(ph2));
+}
+
+TEST_F(ProtocolHandlerRegistryTest, TestInstallDefaultHandler) {
+ RecreateRegistry(false);
+ registry()->AddPredefinedHandler(
+ CreateProtocolHandler("news", GURL("https://test.com/%s")));
+ registry()->InitProtocolSettings();
+ std::vector<std::string> protocols;
+ registry()->GetRegisteredProtocols(&protocols);
+ ASSERT_EQ(static_cast<size_t>(1), protocols.size());
+ EXPECT_TRUE(registry()->IsHandledProtocol("news"));
+ auto handlers =
+ registry()->GetUserDefinedHandlers(base::Time(), base::Time::Max());
+ EXPECT_TRUE(handlers.empty());
+ registry()->ClearUserDefinedHandlers(base::Time(), base::Time::Max());
+ EXPECT_TRUE(registry()->IsHandledProtocol("news"));
+}
+
+#define URL_p1u1 "https://p1u1.com/%s"
+#define URL_p1u2 "https://p1u2.com/%s"
+#define URL_p1u3 "https://p1u3.com/%s"
+#define URL_p2u1 "https://p2u1.com/%s"
+#define URL_p2u2 "https://p2u2.com/%s"
+#define URL_p3u1 "https://p3u1.com/%s"
+
+TEST_F(ProtocolHandlerRegistryTest, TestPrefPolicyOverlapRegister) {
+ base::ListValue handlers_registered_by_pref;
+ base::ListValue handlers_registered_by_policy;
+
+ handlers_registered_by_pref.Append(
+ GetProtocolHandlerValueWithDefault("news", URL_p1u2, true));
+ handlers_registered_by_pref.Append(
+ GetProtocolHandlerValueWithDefault("news", URL_p1u1, true));
+ handlers_registered_by_pref.Append(
+ GetProtocolHandlerValueWithDefault("news", URL_p1u2, false));
+
+ handlers_registered_by_policy.Append(
+ GetProtocolHandlerValueWithDefault("news", URL_p1u1, false));
+ handlers_registered_by_policy.Append(
+ GetProtocolHandlerValueWithDefault("mailto", URL_p3u1, true));
+
+ GetPrefs()->Set(custom_handlers::prefs::kRegisteredProtocolHandlers,
+ handlers_registered_by_pref);
+ GetPrefs()->Set(custom_handlers::prefs::kPolicyRegisteredProtocolHandlers,
+ handlers_registered_by_policy);
+ registry()->InitProtocolSettings();
+
+ // Duplicate p1u2 eliminated in memory but not yet saved in pref
+ ProtocolHandler p1u1 = CreateProtocolHandler("news", GURL(URL_p1u1));
+ ProtocolHandler p1u2 = CreateProtocolHandler("news", GURL(URL_p1u2));
+ ASSERT_EQ(InPrefHandlerCount(), 3);
+ ASSERT_EQ(InMemoryHandlerCount(), 3);
+ ASSERT_TRUE(registry()->IsDefault(p1u1));
+ ASSERT_FALSE(registry()->IsDefault(p1u2));
+
+ ProtocolHandler p2u1 = CreateProtocolHandler("im", GURL(URL_p2u1));
+ registry()->OnDenyRegisterProtocolHandler(p2u1);
+
+ // Duplicate p1u2 saved in pref and a new handler added to pref and memory
+ ASSERT_EQ(InPrefHandlerCount(), 3);
+ ASSERT_EQ(InMemoryHandlerCount(), 4);
+ ASSERT_FALSE(registry()->IsDefault(p2u1));
+
+ registry()->RemoveHandler(p1u1);
+
+ // p1u1 removed from user pref but not from memory due to policy.
+ ASSERT_EQ(InPrefHandlerCount(), 2);
+ ASSERT_EQ(InMemoryHandlerCount(), 4);
+ ASSERT_TRUE(registry()->IsDefault(p1u1));
+
+ ProtocolHandler p3u1 = CreateProtocolHandler("mailto", GURL(URL_p3u1));
+ registry()->RemoveHandler(p3u1);
+
+ // p3u1 not removed from memory due to policy and it was never in pref.
+ ASSERT_EQ(InPrefHandlerCount(), 2);
+ ASSERT_EQ(InMemoryHandlerCount(), 4);
+ ASSERT_TRUE(registry()->IsDefault(p3u1));
+
+ registry()->RemoveHandler(p1u2);
+
+ // p1u2 removed from user pref and memory.
+ ASSERT_EQ(InPrefHandlerCount(), 1);
+ ASSERT_EQ(InMemoryHandlerCount(), 3);
+ ASSERT_TRUE(registry()->IsDefault(p1u1));
+
+ ProtocolHandler p1u3 = CreateProtocolHandler("news", GURL(URL_p1u3));
+ registry()->OnAcceptRegisterProtocolHandler(p1u3);
+
+ // p1u3 added to pref and memory.
+ ASSERT_EQ(InPrefHandlerCount(), 2);
+ ASSERT_EQ(InMemoryHandlerCount(), 4);
+ ASSERT_FALSE(registry()->IsDefault(p1u1));
+ ASSERT_TRUE(registry()->IsDefault(p1u3));
+
+ registry()->RemoveHandler(p1u3);
+
+ // p1u3 the default handler for p1 removed from user pref and memory.
+ ASSERT_EQ(InPrefHandlerCount(), 1);
+ ASSERT_EQ(InMemoryHandlerCount(), 3);
+ ASSERT_FALSE(registry()->IsDefault(p1u3));
+ ASSERT_TRUE(registry()->IsDefault(p1u1));
+ ASSERT_TRUE(registry()->IsDefault(p3u1));
+ ASSERT_FALSE(registry()->IsDefault(p2u1));
+}
+
+TEST_F(ProtocolHandlerRegistryTest, TestPrefPolicyOverlapIgnore) {
+ base::ListValue handlers_ignored_by_pref;
+ base::ListValue handlers_ignored_by_policy;
+
+ handlers_ignored_by_pref.Append(GetProtocolHandlerValue("news", URL_p1u1));
+ handlers_ignored_by_pref.Append(GetProtocolHandlerValue("news", URL_p1u2));
+ handlers_ignored_by_pref.Append(GetProtocolHandlerValue("news", URL_p1u2));
+ handlers_ignored_by_pref.Append(GetProtocolHandlerValue("mailto", URL_p3u1));
+
+ handlers_ignored_by_policy.Append(GetProtocolHandlerValue("news", URL_p1u2));
+ handlers_ignored_by_policy.Append(GetProtocolHandlerValue("news", URL_p1u3));
+ handlers_ignored_by_policy.Append(GetProtocolHandlerValue("im", URL_p2u1));
+
+ GetPrefs()->Set(custom_handlers::prefs::kIgnoredProtocolHandlers,
+ handlers_ignored_by_pref);
+ GetPrefs()->Set(custom_handlers::prefs::kPolicyIgnoredProtocolHandlers,
+ handlers_ignored_by_policy);
+ registry()->InitProtocolSettings();
+
+ // Duplicate p1u2 eliminated in memory but not yet saved in pref
+ ASSERT_EQ(InPrefIgnoredHandlerCount(), 4);
+ ASSERT_EQ(InMemoryIgnoredHandlerCount(), 5);
+
+ ProtocolHandler p2u2 = CreateProtocolHandler("im", GURL(URL_p2u2));
+ registry()->OnIgnoreRegisterProtocolHandler(p2u2);
+
+ // Duplicate p1u2 eliminated in pref, p2u2 added to pref and memory.
+ ASSERT_EQ(InPrefIgnoredHandlerCount(), 4);
+ ASSERT_EQ(InMemoryIgnoredHandlerCount(), 6);
+
+ ProtocolHandler p2u1 = CreateProtocolHandler("im", GURL(URL_p2u1));
+ registry()->RemoveIgnoredHandler(p2u1);
+
+ // p2u1 installed by policy so cant be removed.
+ ASSERT_EQ(InPrefIgnoredHandlerCount(), 4);
+ ASSERT_EQ(InMemoryIgnoredHandlerCount(), 6);
+
+ ProtocolHandler p1u2 = CreateProtocolHandler("news", GURL(URL_p1u2));
+ registry()->RemoveIgnoredHandler(p1u2);
+
+ // p1u2 installed by policy and pref so it is removed from pref and not from
+ // memory.
+ ASSERT_EQ(InPrefIgnoredHandlerCount(), 3);
+ ASSERT_EQ(InMemoryIgnoredHandlerCount(), 6);
+
+ ProtocolHandler p1u1 = CreateProtocolHandler("news", GURL(URL_p1u1));
+ registry()->RemoveIgnoredHandler(p1u1);
+
+ // p1u1 installed by pref so it is removed from pref and memory.
+ ASSERT_EQ(InPrefIgnoredHandlerCount(), 2);
+ ASSERT_EQ(InMemoryIgnoredHandlerCount(), 5);
+
+ registry()->RemoveIgnoredHandler(p2u2);
+
+ // p2u2 installed by user so it is removed from pref and memory.
+ ASSERT_EQ(InPrefIgnoredHandlerCount(), 1);
+ ASSERT_EQ(InMemoryIgnoredHandlerCount(), 4);
+
+ registry()->OnIgnoreRegisterProtocolHandler(p2u1);
+
+ // p2u1 installed by user but it is already installed by policy, so it is
+ // added to pref.
+ ASSERT_EQ(InPrefIgnoredHandlerCount(), 2);
+ ASSERT_EQ(InMemoryIgnoredHandlerCount(), 4);
+
+ registry()->RemoveIgnoredHandler(p2u1);
+
+ // p2u1 installed by user and policy, so it is removed from pref alone.
+ ASSERT_EQ(InPrefIgnoredHandlerCount(), 1);
+ ASSERT_EQ(InMemoryIgnoredHandlerCount(), 4);
+}
+
+TEST_F(ProtocolHandlerRegistryTest, TestURIPercentEncoding) {
+ ProtocolHandler ph =
+ CreateProtocolHandler("web+custom", GURL("https://test.com/url=%s"));
+ registry()->OnAcceptRegisterProtocolHandler(ph);
+
+ // Normal case.
+ GURL translated_url = ph.TranslateUrl(GURL("web+custom://custom/handler"));
+ ASSERT_EQ(translated_url,
+ GURL("https://test.com/url=web%2Bcustom%3A%2F%2Fcustom%2Fhandler"));
+
+ // Percent-encoding.
+ translated_url = ph.TranslateUrl(GURL("web+custom://custom/%20handler"));
+ ASSERT_EQ(
+ translated_url,
+ GURL("https://test.com/url=web%2Bcustom%3A%2F%2Fcustom%2F%2520handler"));
+
+ // Space character.
+ translated_url = ph.TranslateUrl(GURL("web+custom://custom handler"));
+ ASSERT_EQ(translated_url,
+ GURL("https://test.com/url=web%2Bcustom%3A%2F%2Fcustom%20handler"));
+
+ // Query parameters.
+ translated_url = ph.TranslateUrl(GURL("web+custom://custom?foo=bar&bar=baz"));
+ ASSERT_EQ(translated_url,
+ GURL("https://test.com/"
+ "url=web%2Bcustom%3A%2F%2Fcustom%3Ffoo%3Dbar%26bar%3Dbaz"));
+
+ // Non-ASCII characters.
+ translated_url = ph.TranslateUrl(GURL("web+custom://custom/<>`{}#?\"'😂"));
+ ASSERT_EQ(translated_url, GURL("https://test.com/"
+ "url=web%2Bcustom%3A%2F%2Fcustom%2F%3C%3E%60%"
+ "7B%7D%23%3F%2522'%25F0%259F%2598%2582"));
+
+ // ASCII characters from the C0 controls percent-encode set.
+ // GURL constructor encodes U+001F and U+007F as "%1F" and "%7F" first,
+ // Then the protocol handler translator encodes them to "%25%1F" and "%25%7F"
+ // again. That's why the expected result has double-encoded URL.
+ translated_url = ph.TranslateUrl(GURL("web+custom://custom/\x1fhandler"));
+ ASSERT_EQ(
+ translated_url,
+ GURL("https://test.com/url=web%2Bcustom%3A%2F%2Fcustom%2F%251Fhandler"));
+ translated_url = ph.TranslateUrl(GURL("web+custom://custom/\x7Fhandler"));
+ ASSERT_EQ(
+ translated_url,
+ GURL("https://test.com/url=web%2Bcustom%3A%2F%2Fcustom%2F%257Fhandler"));
+
+ // Path percent-encode set.
+ translated_url =
+ ph.TranslateUrl(GURL("web+custom://custom/handler=#download"));
+ ASSERT_EQ(translated_url,
+ GURL("https://test.com/"
+ "url=web%2Bcustom%3A%2F%2Fcustom%2Fhandler%3D%23download"));
+
+ // Userinfo percent-encode set.
+ translated_url = ph.TranslateUrl(GURL("web+custom://custom/handler:@id="));
+ ASSERT_EQ(translated_url,
+ GURL("https://test.com/"
+ "url=web%2Bcustom%3A%2F%2Fcustom%2Fhandler%3A%40id%3D"));
+}
+
+TEST_F(ProtocolHandlerRegistryTest, TestMultiplePlaceholders) {
+ ProtocolHandler ph =
+ CreateProtocolHandler("news", GURL("https://example.com/%s/url=%s"));
+ registry()->OnAcceptRegisterProtocolHandler(ph);
+
+ GURL translated_url = ph.TranslateUrl(GURL("test:duplicated_placeholders"));
+
+ // When URL contains multiple placeholders, only the first placeholder should
+ // be changed to the given URL.
+ ASSERT_EQ(translated_url,
+ GURL("https://example.com/test%3Aduplicated_placeholders/url=%s"));
+}
+
+TEST_F(ProtocolHandlerRegistryTest, InvalidHandlers) {
+ // Invalid protocol.
+ registry()->OnAcceptRegisterProtocolHandler(
+ CreateProtocolHandler("foo", GURL("https://www.google.com/handler%s")));
+ ASSERT_FALSE(registry()->IsHandledProtocol("foo"));
+ registry()->OnAcceptRegisterProtocolHandler(
+ CreateProtocolHandler("web", GURL("https://www.google.com/handler%s")));
+ ASSERT_FALSE(registry()->IsHandledProtocol("web"));
+ registry()->OnAcceptRegisterProtocolHandler(
+ CreateProtocolHandler("web+", GURL("https://www.google.com/handler%s")));
+ ASSERT_FALSE(registry()->IsHandledProtocol("web+"));
+ registry()->OnAcceptRegisterProtocolHandler(
+ CreateProtocolHandler("https", GURL("https://www.google.com/handler%s")));
+ ASSERT_FALSE(registry()->IsHandledProtocol("https"));
+
+ EXPECT_FALSE(ProtocolHandlerCanRegisterProtocol(
+ "ext+", GURL("https://www.google.com/handler%s"),
+ blink::ProtocolHandlerSecurityLevel::kStrict));
+ EXPECT_FALSE(ProtocolHandlerCanRegisterProtocol(
+ "ext+foo", GURL("https://www.google.com/handler%s"),
+ blink::ProtocolHandlerSecurityLevel::kStrict));
+
+ // Invalid handler URL.
+ // data: URL.
+ registry()->OnAcceptRegisterProtocolHandler(CreateProtocolHandler(
+ "news",
+ GURL("data:text/html,<html><body><b>hello world</b></body></html>%s")));
+ ASSERT_FALSE(registry()->IsHandledProtocol("news"));
+ // ftp:// URL.
+ registry()->OnAcceptRegisterProtocolHandler(
+ CreateProtocolHandler("news", GURL("ftp://www.google.com/handler%s")));
+ ASSERT_FALSE(registry()->IsHandledProtocol("news"));
+ // blob:// URL
+ registry()->OnAcceptRegisterProtocolHandler(CreateProtocolHandler(
+ "news", GURL("blob:https://www.google.com/"
+ "f2d8c47d-17d0-4bf5-8f0a-76e42cbed3bf/%s")));
+ ASSERT_FALSE(registry()->IsHandledProtocol("news"));
+ // http:// URL
+ registry()->OnAcceptRegisterProtocolHandler(
+ CreateProtocolHandler("news", GURL("http://www.google.com/handler%s")));
+ ASSERT_FALSE(registry()->IsHandledProtocol("news"));
+ // filesystem:// URL
+ registry()->OnAcceptRegisterProtocolHandler(CreateProtocolHandler(
+ "news", GURL("filesystem:https://www.google.com/"
+ "f2d8c47d-17d0-4bf5-8f0a-76e42cbed3bf/%s")));
+ ASSERT_FALSE(registry()->IsHandledProtocol("news"));
+}
+
+// See
+// https://html.spec.whatwg.org/multipage/system-state.html#normalize-protocol-handler-parameters
+TEST_F(ProtocolHandlerRegistryTest, WebPlusPrefix) {
+ // Not ASCII alphas.
+ registry()->OnAcceptRegisterProtocolHandler(CreateProtocolHandler(
+ "web+***", GURL("https://www.google.com/handler%s")));
+ ASSERT_FALSE(registry()->IsHandledProtocol("web+***"));
+ registry()->OnAcceptRegisterProtocolHandler(CreateProtocolHandler(
+ "web+123", GURL("https://www.google.com/handler%s")));
+ ASSERT_FALSE(registry()->IsHandledProtocol("web+123"));
+ registry()->OnAcceptRegisterProtocolHandler(CreateProtocolHandler(
+ "web+ ", GURL("https://www.google.com/handler%s")));
+ ASSERT_FALSE(registry()->IsHandledProtocol("web+ "));
+ registry()->OnAcceptRegisterProtocolHandler(CreateProtocolHandler(
+ "web+name123", GURL("https://www.google.com/handler%s")));
+ ASSERT_FALSE(registry()->IsHandledProtocol("web+name123"));
+
+ // ASCII lower alphas.
+ registry()->OnAcceptRegisterProtocolHandler(
+ CreateProtocolHandler("web+abcdefghijklmnopqrstuvwxyz",
+ GURL("https://www.google.com/handler%s")));
+ ASSERT_TRUE(registry()->IsHandledProtocol("web+abcdefghijklmnopqrstuvwxyz"));
+
+ // ASCII upper alphas are lowercased.
+ registry()->OnAcceptRegisterProtocolHandler(
+ CreateProtocolHandler("web+ZYXWVUTSRQPONMLKJIHGFEDCBA",
+ GURL("https://www.google.com/handler%s")));
+ ASSERT_TRUE(registry()->IsHandledProtocol("web+zyxwvutsrqponmlkjihgfedcba"));
+}
+
+// See
+// https://html.spec.whatwg.org/multipage/system-state.html#safelisted-scheme
+TEST_F(ProtocolHandlerRegistryTest, SafelistedSchemes) {
+ std::string schemes[] = {
+ "bitcoin", "cabal", "dat", "did", "doi", "dweb",
+ "ethereum", "geo", "hyper", "im", "ipfs", "ipns",
+ "irc", "ircs", "magnet", "mailto", "mms", "news",
+ "nntp", "openpgp4fpr", "sip", "sms", "smsto", "ssb",
+ "ssh", "tel", "urn", "webcal", "wtai", "xmpp"};
+ for (auto& scheme : schemes) {
+ registry()->OnAcceptRegisterProtocolHandler(
+ CreateProtocolHandler(scheme, GURL("https://example.com/url=%s")));
+ ASSERT_TRUE(registry()->IsHandledProtocol(scheme));
+ }
+}
+
+TEST_F(ProtocolHandlerRegistryTest, ProtocolHandlerSecurityLevels) {
+ GURL https_handler_url("https://www.google.com/handler%s");
+
+ // Invalid protocol.
+ EXPECT_FALSE(ProtocolHandlerCanRegisterProtocol(
+ "foo", https_handler_url,
+ blink::ProtocolHandlerSecurityLevel::kExtensionFeatures));
+ EXPECT_FALSE(ProtocolHandlerCanRegisterProtocol(
+ "web", https_handler_url,
+ blink::ProtocolHandlerSecurityLevel::kExtensionFeatures));
+ EXPECT_FALSE(ProtocolHandlerCanRegisterProtocol(
+ "web+", https_handler_url,
+ blink::ProtocolHandlerSecurityLevel::kExtensionFeatures));
+ EXPECT_FALSE(ProtocolHandlerCanRegisterProtocol(
+ "https", https_handler_url,
+ blink::ProtocolHandlerSecurityLevel::kExtensionFeatures));
+ EXPECT_FALSE(ProtocolHandlerCanRegisterProtocol(
+ "ext+", https_handler_url,
+ blink::ProtocolHandlerSecurityLevel::kExtensionFeatures));
+ EXPECT_FALSE(ProtocolHandlerCanRegisterProtocol(
+ "ext+foo", https_handler_url,
+ blink::ProtocolHandlerSecurityLevel::kUntrustedOrigins));
+
+ // Invalid handler URL.
+ // data: URL.
+ EXPECT_FALSE(ProtocolHandlerCanRegisterProtocol(
+ "news",
+ GURL("data:text/html,<html><body><b>hello "
+ "world</b></body></html>%s"),
+ blink::ProtocolHandlerSecurityLevel::kExtensionFeatures));
+ // ftp:// URL.
+ EXPECT_FALSE(ProtocolHandlerCanRegisterProtocol(
+ "news", GURL("ftp://www.google.com/handler%s"),
+ blink::ProtocolHandlerSecurityLevel::kExtensionFeatures));
+ // blob:// URL
+ EXPECT_FALSE(ProtocolHandlerCanRegisterProtocol(
+ "news",
+ GURL("blob:https://www.google.com/"
+ "f2d8c47d-17d0-4bf5-8f0a-76e42cbed3bf/%s"),
+ blink::ProtocolHandlerSecurityLevel::kExtensionFeatures));
+ // http:// URL
+ EXPECT_FALSE(ProtocolHandlerCanRegisterProtocol(
+ "news", GURL("http://www.google.com/handler%s"),
+ blink::ProtocolHandlerSecurityLevel::kExtensionFeatures));
+ // filesystem:// URL
+ EXPECT_FALSE(ProtocolHandlerCanRegisterProtocol(
+ "news",
+ GURL("filesystem:https://www.google.com/"
+ "f2d8c47d-17d0-4bf5-8f0a-76e42cbed3bf/%s"),
+ blink::ProtocolHandlerSecurityLevel::kExtensionFeatures));
+
+ // ext+foo scheme.
+ EXPECT_TRUE(ProtocolHandlerCanRegisterProtocol(
+ "ext+foo", https_handler_url,
+ blink::ProtocolHandlerSecurityLevel::kExtensionFeatures));
+}
+
+} // namespace custom_handlers
diff --git a/chromium/components/custom_handlers/protocol_handler_throttle.cc b/chromium/components/custom_handlers/protocol_handler_throttle.cc
new file mode 100644
index 00000000000..690cfa8ae39
--- /dev/null
+++ b/chromium/components/custom_handlers/protocol_handler_throttle.cc
@@ -0,0 +1,50 @@
+// Copyright 2022 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.
+
+#include "components/custom_handlers/protocol_handler_throttle.h"
+
+#include "components/custom_handlers/protocol_handler_registry.h"
+#include "services/network/public/cpp/resource_request.h"
+
+namespace custom_handlers {
+
+ProtocolHandlerThrottle::ProtocolHandlerThrottle(
+ const custom_handlers::ProtocolHandlerRegistry& protocol_handler_registry)
+ : protocol_handler_registry_(&protocol_handler_registry) {}
+
+void ProtocolHandlerThrottle::WillStartRequest(
+ network::ResourceRequest* request,
+ bool* defer) {
+ // Don't translate the urn: scheme URL while loading the resource from the
+ // specified web bundle.
+ // TODO(https://crbug.com/1257045): Remove this when we drop urn: scheme
+ // support in WebBundles.
+ if (request->web_bundle_token_params &&
+ request->url.SchemeIs(url::kUrnScheme)) {
+ return;
+ }
+ TranslateUrl(request->url);
+}
+
+void ProtocolHandlerThrottle::WillRedirectRequest(
+ net::RedirectInfo* redirect_info,
+ const network::mojom::URLResponseHead& response_head,
+ bool* defer,
+ std::vector<std::string>* to_be_removed_headers,
+ net::HttpRequestHeaders* modified_headers,
+ net::HttpRequestHeaders* modified_cors_exempt_headers) {
+ TranslateUrl(redirect_info->new_url);
+}
+
+void ProtocolHandlerThrottle::TranslateUrl(GURL& url) {
+ // TODO(jfernandez): We should use scheme_piece instead, which would imply
+ // adadpting the ProtocolHandlerRegistry code to use StringPiece.
+ if (!protocol_handler_registry_->IsHandledProtocol(url.scheme()))
+ return;
+ GURL translated_url = protocol_handler_registry_->Translate(url);
+ if (!translated_url.is_empty())
+ url = translated_url;
+}
+
+} // namespace custom_handlers
diff --git a/chromium/components/custom_handlers/protocol_handler_throttle.h b/chromium/components/custom_handlers/protocol_handler_throttle.h
new file mode 100644
index 00000000000..2a79d2980f8
--- /dev/null
+++ b/chromium/components/custom_handlers/protocol_handler_throttle.h
@@ -0,0 +1,44 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_CUSTOM_HANDLERS_PROTOCOL_HANDLER_THROTTLE_H_
+#define COMPONENTS_CUSTOM_HANDLERS_PROTOCOL_HANDLER_THROTTLE_H_
+
+#include "base/memory/raw_ptr.h"
+#include "url/gurl.h"
+
+#include "third_party/blink/public/common/loader/url_loader_throttle.h"
+
+namespace custom_handlers {
+
+class ProtocolHandlerRegistry;
+
+class ProtocolHandlerThrottle : public blink::URLLoaderThrottle {
+ public:
+ explicit ProtocolHandlerThrottle(const ProtocolHandlerRegistry&);
+ ~ProtocolHandlerThrottle() override = default;
+
+ void WillStartRequest(network::ResourceRequest* request,
+ bool* defer) override;
+
+ void WillRedirectRequest(
+ net::RedirectInfo* redirect_info,
+ const network::mojom::URLResponseHead& response_head,
+ bool* defer,
+ std::vector<std::string>* to_be_removed_headers,
+ net::HttpRequestHeaders* modified_headers,
+ net::HttpRequestHeaders* modified_cors_exempt_headers) override;
+
+ private:
+ // If the @url has a custom protocol handler, the argument will return the
+ // translated url.
+ void TranslateUrl(GURL& url);
+ // The ProtocolHandlerRegistry instance is a KeyedService which ownership is
+ // managed by the BrowseContext.
+ raw_ptr<const ProtocolHandlerRegistry> protocol_handler_registry_;
+};
+
+} // namespace custom_handlers
+
+#endif // COMPONENTS_CUSTOM_HANDLERS_PROTOCOL_HANDLER_THROTTLE_H_
diff --git a/chromium/components/custom_handlers/register_protocol_handler_permission_request.cc b/chromium/components/custom_handlers/register_protocol_handler_permission_request.cc
new file mode 100644
index 00000000000..69549deafc1
--- /dev/null
+++ b/chromium/components/custom_handlers/register_protocol_handler_permission_request.cc
@@ -0,0 +1,86 @@
+// Copyright 2014 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.
+
+#include "components/custom_handlers/register_protocol_handler_permission_request.h"
+
+#include "base/bind.h"
+#include "base/metrics/user_metrics.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/custom_handlers/protocol_handler_registry.h"
+#include "components/permissions/request_type.h"
+#include "components/strings/grit/components_strings.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "url/gurl.h"
+
+namespace custom_handlers {
+
+RegisterProtocolHandlerPermissionRequest::
+ RegisterProtocolHandlerPermissionRequest(
+ custom_handlers::ProtocolHandlerRegistry* registry,
+ const ProtocolHandler& handler,
+ GURL url,
+ base::ScopedClosureRunner fullscreen_block)
+ : PermissionRequest(
+ url.DeprecatedGetOriginAsURL(),
+ permissions::RequestType::kRegisterProtocolHandler,
+ /*has_gesture=*/false,
+ base::BindOnce(
+ &RegisterProtocolHandlerPermissionRequest::PermissionDecided,
+ base::Unretained(this)),
+ base::BindOnce(
+ &RegisterProtocolHandlerPermissionRequest::DeleteRequest,
+ base::Unretained(this))),
+ registry_(registry),
+ handler_(handler),
+ fullscreen_block_(std::move(fullscreen_block)) {}
+
+RegisterProtocolHandlerPermissionRequest::
+ ~RegisterProtocolHandlerPermissionRequest() = default;
+
+bool RegisterProtocolHandlerPermissionRequest::IsDuplicateOf(
+ permissions::PermissionRequest* other_request) const {
+ // The downcast here is safe because PermissionRequest::IsDuplicateOf ensures
+ // that both requests are of type kRegisterProtocolHandler.
+ return permissions::PermissionRequest::IsDuplicateOf(other_request) &&
+ handler_.protocol() ==
+ static_cast<RegisterProtocolHandlerPermissionRequest*>(
+ other_request)
+ ->handler_.protocol();
+}
+
+std::u16string
+RegisterProtocolHandlerPermissionRequest::GetMessageTextFragment() const {
+ ProtocolHandler old_handler = registry_->GetHandlerFor(handler_.protocol());
+ return old_handler.IsEmpty()
+ ? l10n_util::GetStringFUTF16(
+ IDS_REGISTER_PROTOCOL_HANDLER_CONFIRM_FRAGMENT,
+ handler_.GetProtocolDisplayName())
+ : l10n_util::GetStringFUTF16(
+ IDS_REGISTER_PROTOCOL_HANDLER_CONFIRM_REPLACE_FRAGMENT,
+ handler_.GetProtocolDisplayName(),
+ base::UTF8ToUTF16(old_handler.url().host_piece()));
+}
+
+void RegisterProtocolHandlerPermissionRequest::PermissionDecided(
+ ContentSetting result,
+ bool is_one_time) {
+ DCHECK(!is_one_time);
+ if (result == ContentSetting::CONTENT_SETTING_ALLOW) {
+ base::RecordAction(
+ base::UserMetricsAction("RegisterProtocolHandler.Infobar_Accept"));
+ registry_->OnAcceptRegisterProtocolHandler(handler_);
+ } else {
+ DCHECK(result == CONTENT_SETTING_BLOCK ||
+ result == CONTENT_SETTING_DEFAULT);
+ base::RecordAction(
+ base::UserMetricsAction("RegisterProtocolHandler.InfoBar_Deny"));
+ registry_->OnIgnoreRegisterProtocolHandler(handler_);
+ }
+}
+
+void RegisterProtocolHandlerPermissionRequest::DeleteRequest() {
+ delete this;
+}
+
+} // namespace custom_handlers
diff --git a/chromium/components/custom_handlers/register_protocol_handler_permission_request.h b/chromium/components/custom_handlers/register_protocol_handler_permission_request.h
new file mode 100644
index 00000000000..fa1cb430931
--- /dev/null
+++ b/chromium/components/custom_handlers/register_protocol_handler_permission_request.h
@@ -0,0 +1,60 @@
+// Copyright 2014 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.
+
+#ifndef COMPONENTS_CUSTOM_HANDLERS_REGISTER_PROTOCOL_HANDLER_PERMISSION_REQUEST_H_
+#define COMPONENTS_CUSTOM_HANDLERS_REGISTER_PROTOCOL_HANDLER_PERMISSION_REQUEST_H_
+
+#include "base/callback_helpers.h"
+#include "base/memory/raw_ptr.h"
+#include "components/permissions/permission_request.h"
+#include "content/public/common/custom_handlers/protocol_handler.h"
+
+namespace permissions {
+enum class RequestType;
+} // namespace permissions
+
+using content::ProtocolHandler;
+
+class GURL;
+namespace custom_handlers {
+class ProtocolHandlerRegistry;
+
+// This class provides display data for a permission request, shown when a page
+// wants to register a protocol handler and was triggered by a user action.
+class RegisterProtocolHandlerPermissionRequest
+ : public permissions::PermissionRequest {
+ public:
+ RegisterProtocolHandlerPermissionRequest(
+ custom_handlers::ProtocolHandlerRegistry* registry,
+ const ProtocolHandler& handler,
+ GURL url,
+ base::ScopedClosureRunner fullscreen_block);
+
+ RegisterProtocolHandlerPermissionRequest(
+ const RegisterProtocolHandlerPermissionRequest&) = delete;
+ RegisterProtocolHandlerPermissionRequest& operator=(
+ const RegisterProtocolHandlerPermissionRequest&) = delete;
+
+ ~RegisterProtocolHandlerPermissionRequest() override;
+
+ private:
+ // permissions::PermissionRequest:
+ bool IsDuplicateOf(
+ permissions::PermissionRequest* other_request) const override;
+ std::u16string GetMessageTextFragment() const override;
+
+ void PermissionDecided(ContentSetting result, bool is_one_time);
+ void DeleteRequest();
+
+ raw_ptr<custom_handlers::ProtocolHandlerRegistry> registry_;
+ ProtocolHandler handler_;
+ // Fullscreen will be blocked for the duration of the lifetime of this block.
+ // TODO(avi): Move to either permissions::PermissionRequest or the
+ // PermissionRequestManager?
+ base::ScopedClosureRunner fullscreen_block_;
+};
+
+} // namespace custom_handlers
+
+#endif // COMONENTS_CUSTOM_HANDLERS_REGISTER_PROTOCOL_HANDLER_PERMISSION_REQUEST_H_
diff --git a/chromium/components/custom_handlers/test_protocol_handler_registry_delegate.cc b/chromium/components/custom_handlers/test_protocol_handler_registry_delegate.cc
new file mode 100644
index 00000000000..bed4941b1e8
--- /dev/null
+++ b/chromium/components/custom_handlers/test_protocol_handler_registry_delegate.cc
@@ -0,0 +1,75 @@
+// Copyright 2019 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.
+
+#include "components/custom_handlers/test_protocol_handler_registry_delegate.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/check_op.h"
+#include "base/threading/thread_task_runner_handle.h"
+
+namespace custom_handlers {
+
+TestProtocolHandlerRegistryDelegate::TestProtocolHandlerRegistryDelegate() =
+ default;
+
+TestProtocolHandlerRegistryDelegate::~TestProtocolHandlerRegistryDelegate() =
+ default;
+
+// ProtocolHandlerRegistry::Delegate:
+void TestProtocolHandlerRegistryDelegate::RegisterExternalHandler(
+ const std::string& protocol) {
+ bool inserted = registered_protocols_.insert(protocol).second;
+ DCHECK(inserted);
+}
+
+void TestProtocolHandlerRegistryDelegate::DeregisterExternalHandler(
+ const std::string& protocol) {
+ size_t removed = registered_protocols_.erase(protocol);
+ DCHECK_EQ(removed, 1u);
+}
+
+bool TestProtocolHandlerRegistryDelegate::IsExternalHandlerRegistered(
+ const std::string& protocol) {
+ return registered_protocols_.find(protocol) != registered_protocols_.end();
+}
+
+void TestProtocolHandlerRegistryDelegate::RegisterWithOSAsDefaultClient(
+ const std::string& protocol,
+ DefaultClientCallback callback) {
+ // Do as-if the registration has to run on another sequence and post back
+ // the result with a task to the current thread.
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(std::move(callback), !force_os_failure_));
+
+ if (!force_os_failure_)
+ os_registered_protocols_.insert(protocol);
+}
+
+void TestProtocolHandlerRegistryDelegate::CheckDefaultClientWithOS(
+ const std::string& protocol,
+ DefaultClientCallback callback) {
+ // Respond asynchronously to mimic the real behavior.
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(std::move(callback), true));
+}
+
+bool TestProtocolHandlerRegistryDelegate::ShouldRemoveHandlersNotInOS() {
+ return true;
+}
+
+bool TestProtocolHandlerRegistryDelegate::IsFakeRegisteredWithOS(
+ const std::string& protocol) {
+ return os_registered_protocols_.find(protocol) !=
+ os_registered_protocols_.end();
+}
+
+void TestProtocolHandlerRegistryDelegate::Reset() {
+ registered_protocols_.clear();
+ os_registered_protocols_.clear();
+ force_os_failure_ = false;
+}
+
+} // namespace custom_handlers
diff --git a/chromium/components/custom_handlers/test_protocol_handler_registry_delegate.h b/chromium/components/custom_handlers/test_protocol_handler_registry_delegate.h
new file mode 100644
index 00000000000..f37f984fa03
--- /dev/null
+++ b/chromium/components/custom_handlers/test_protocol_handler_registry_delegate.h
@@ -0,0 +1,55 @@
+// Copyright 2019 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.
+
+#ifndef COMPONENTS_CUSTOM_HANDLERS_TEST_PROTOCOL_HANDLER_REGISTRY_DELEGATE_H_
+#define COMPONENTS_CUSTOM_HANDLERS_TEST_PROTOCOL_HANDLER_REGISTRY_DELEGATE_H_
+
+#include <set>
+#include <string>
+
+#include "components/custom_handlers/protocol_handler_registry.h"
+
+namespace custom_handlers {
+
+// A test ProtocolHandlerRegistry::Delegate implementation that keeps track of
+// registered protocols and doesn't change any OS settings.
+class TestProtocolHandlerRegistryDelegate
+ : public custom_handlers::ProtocolHandlerRegistry::Delegate {
+ public:
+ TestProtocolHandlerRegistryDelegate();
+ ~TestProtocolHandlerRegistryDelegate() override;
+
+ TestProtocolHandlerRegistryDelegate(
+ const TestProtocolHandlerRegistryDelegate& other) = delete;
+ TestProtocolHandlerRegistryDelegate& operator=(
+ const TestProtocolHandlerRegistryDelegate& other) = delete;
+
+ // ProtocolHandlerRegistry::Delegate:
+ void RegisterExternalHandler(const std::string& protocol) override;
+ void DeregisterExternalHandler(const std::string& protocol) override;
+ bool IsExternalHandlerRegistered(const std::string& protocol) override;
+ void RegisterWithOSAsDefaultClient(const std::string& protocol,
+ DefaultClientCallback callback) override;
+ void CheckDefaultClientWithOS(const std::string& protocol,
+ DefaultClientCallback callback) override;
+ bool ShouldRemoveHandlersNotInOS() override;
+
+ bool IsFakeRegistered(const std::string& protocol);
+ bool IsFakeRegisteredWithOS(const std::string& protocol);
+
+ void set_force_os_failure(bool force) { force_os_failure_ = force; }
+ bool force_os_failure() { return force_os_failure_; }
+
+ void Reset();
+
+ private:
+ // Holds registered protocols.
+ std::set<std::string> registered_protocols_;
+ std::set<std::string> os_registered_protocols_;
+ bool force_os_failure_{false};
+};
+
+} // namespace custom_handlers
+
+#endif // COMPONENTS_CUSTOM_HANDLERS_TEST_PROTOCOL_HANDLER_REGISTRY_DELEGATE_H_
diff --git a/chromium/components/data_reduction_proxy/DEPS b/chromium/components/data_reduction_proxy/DEPS
index 8d8a32f3190..e09f4739a34 100644
--- a/chromium/components/data_reduction_proxy/DEPS
+++ b/chromium/components/data_reduction_proxy/DEPS
@@ -1,5 +1,4 @@
include_rules = [
- "+components/data_use_measurement/core",
"+components/pref_registry",
"+components/prefs",
"+components/previews/core",
diff --git a/chromium/components/data_reduction_proxy/core/browser/BUILD.gn b/chromium/components/data_reduction_proxy/core/browser/BUILD.gn
index 86120f4b4f6..8b2208f6440 100644
--- a/chromium/components/data_reduction_proxy/core/browser/BUILD.gn
+++ b/chromium/components/data_reduction_proxy/core/browser/BUILD.gn
@@ -7,21 +7,9 @@ if (is_android) {
}
browser_sources = [
- "data_reduction_proxy_compression_stats.cc",
- "data_reduction_proxy_compression_stats.h",
"data_reduction_proxy_metrics.h",
- "data_reduction_proxy_prefs.cc",
- "data_reduction_proxy_prefs.h",
- "data_reduction_proxy_service.cc",
- "data_reduction_proxy_service.h",
"data_reduction_proxy_settings.cc",
"data_reduction_proxy_settings.h",
- "data_store.cc",
- "data_store.h",
- "data_usage_store.cc",
- "data_usage_store.h",
- "db_data_owner.cc",
- "db_data_owner.h",
]
if (is_android) {
@@ -31,9 +19,6 @@ if (is_android) {
deps = [
"//base",
"//components/data_reduction_proxy/core/common",
- "//components/data_reduction_proxy/proto:data_reduction_proxy_proto",
- "//components/data_use_measurement/core",
- "//components/data_use_measurement/core:ascriber",
"//components/pref_registry",
"//components/prefs",
"//crypto",
@@ -42,27 +27,14 @@ if (is_android) {
"//url:url",
]
}
-
- java_cpp_enum("data_reduction_proxy_savings_cleared_enum_java") {
- sources = [ "data_reduction_proxy_compression_stats.h" ]
- }
}
static_library("browser") {
sources = browser_sources
- sources += [
- "data_store_impl.cc",
- "data_store_impl.h",
- ]
- public_deps = [
- "//components/data_reduction_proxy/core/common",
- "//components/data_reduction_proxy/proto:data_reduction_proxy_proto",
- ]
+ public_deps = [ "//components/data_reduction_proxy/core/common" ]
deps = [
"//base",
- "//components/data_use_measurement/core",
- "//components/data_use_measurement/core:ascriber",
"//components/pref_registry",
"//components/prefs",
"//crypto",
@@ -78,71 +50,3 @@ static_library("browser") {
defines += [ "USE_GOOGLE_API_KEYS_FOR_AUTH_KEY" ]
}
}
-
-static_library("test_support") {
- testonly = true
- sources = [
- "data_reduction_proxy_settings_test_utils.cc",
- "data_reduction_proxy_settings_test_utils.h",
- "data_reduction_proxy_test_utils.cc",
- "data_reduction_proxy_test_utils.h",
- ]
-
- public_deps = [ ":browser" ]
- deps = [
- "//base",
- "//components/data_reduction_proxy/core/common",
- "//components/data_use_measurement/core",
- "//components/data_use_measurement/core:ascriber",
- "//components/prefs:test_support",
- "//net",
- "//net:test_support",
- "//services/network:test_support",
- "//testing/gmock",
- "//testing/gtest",
- ]
-}
-
-bundle_data("unit_tests_bundle_data") {
- visibility = [ ":unit_tests" ]
- testonly = true
- sources = [
- "//components/test/data/data_reduction_proxy/direct/block10.html",
- "//components/test/data/data_reduction_proxy/direct/block10.html.mock-http-headers",
- "//components/test/data/data_reduction_proxy/direct/noblock.html",
- "//components/test/data/data_reduction_proxy/direct/noblock.html.mock-http-headers",
- "//components/test/data/data_reduction_proxy/proxy/block10.html",
- "//components/test/data/data_reduction_proxy/proxy/block10.html.mock-http-headers",
- "//components/test/data/data_reduction_proxy/proxy/noblock.html",
- "//components/test/data/data_reduction_proxy/proxy/noblock.html.mock-http-headers",
- ]
- outputs = [ "{{bundle_resources_dir}}/" +
- "{{source_root_relative_dir}}/{{source_file_part}}" ]
-}
-
-source_set("unit_tests") {
- testonly = true
- sources = [
- "data_reduction_proxy_compression_stats_unittest.cc",
- "data_reduction_proxy_prefs_unittest.cc",
- "data_reduction_proxy_settings_unittest.cc",
- "data_usage_store_unittest.cc",
- ]
-
- deps = [
- ":browser",
- ":test_support",
- ":unit_tests_bundle_data",
- "//base",
- "//base/test:test_support",
- "//build:chromeos_buildflags",
- "//components/data_reduction_proxy/proto:data_reduction_proxy_proto",
- "//components/data_use_measurement/core:ascriber",
- "//components/prefs:test_support",
- "//components/variations:test_support",
- "//net:test_support",
- "//services/network:test_support",
- "//testing/gmock",
- "//testing/gtest",
- ]
-}
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.cc
deleted file mode 100644
index 9d8538be04e..00000000000
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.cc
+++ /dev/null
@@ -1,890 +0,0 @@
-// Copyright 2014 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.
-
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.h"
-
-#include <algorithm>
-#include <cmath>
-#include <utility>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/check_op.h"
-#include "base/command_line.h"
-#include "base/feature_list.h"
-#include "base/location.h"
-#include "base/memory/raw_ptr.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/metrics/sparse_histogram.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/trace_event/trace_event.h"
-#include "base/values.h"
-#include "build/build_config.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h"
-#include "components/data_reduction_proxy/core/browser/data_usage_store.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_features.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h"
-#include "components/data_reduction_proxy/proto/data_store.pb.h"
-#include "components/prefs/pref_service.h"
-#include "components/prefs/scoped_user_pref_update.h"
-#include "net/base/mime_util.h"
-
-namespace data_reduction_proxy {
-
-namespace {
-
-#define CONCAT(a, b) a##b
-// CONCAT1 provides extra level of indirection so that __LINE__ macro expands.
-#define CONCAT1(a, b) CONCAT(a, b)
-#define UNIQUE_VARNAME CONCAT1(var_, __LINE__)
-// We need to use a macro instead of a method because UMA_HISTOGRAM_COUNTS_1M
-// requires its first argument to be an inline string and not a variable.
-#define RECORD_INT64PREF_TO_HISTOGRAM(pref, uma) \
- int64_t UNIQUE_VARNAME = GetInt64(pref); \
- if (UNIQUE_VARNAME > 0) { \
- UMA_HISTOGRAM_COUNTS_1M(uma, UNIQUE_VARNAME >> 10); \
- }
-
-// Returns the value at |index| of |list_value| as an int64_t.
-int64_t GetInt64PrefValue(const base::ListValue& list_value, size_t index) {
- int64_t val = 0;
- base::Value::ConstListView list_value_view = list_value.GetList();
- if (index < list_value_view.size() && list_value_view[index].is_string()) {
- std::string pref_value = list_value_view[index].GetString();
- bool rv = base::StringToInt64(pref_value, &val);
- DCHECK(rv);
- }
- return val;
-}
-
-// Ensure list has exactly |length| elements, either by truncating at the
-// front, or appending "0"'s to the back.
-void MaintainContentLengthPrefsWindow(base::ListValue* list, size_t length) {
- // Remove data for old days from the front.
- base::Value::ListView list_view = list->GetList();
- while (list_view.size() > length)
- list->EraseListIter(list_view.begin());
- // Newly added lists are empty. Add entries to back to fill the window,
- // each initialized to zero.
- while (list_view.size() < length)
- list->Append(base::NumberToString(0));
- DCHECK_EQ(length, list_view.size());
-}
-
-// Increments an int64_t, stored as a string, in a ListPref at the specified
-// index. The value must already exist and be a string representation of a
-// number.
-void AddInt64ToListPref(size_t index,
- int64_t length,
- base::ListValue* list_update) {
- int64_t value = GetInt64PrefValue(*list_update, index) + length;
- list_update->Set(index,
- std::make_unique<base::Value>(base::NumberToString(value)));
-}
-
-void RecordSavingsClearedMetric(DataReductionProxySavingsClearedReason reason) {
- DCHECK_GT(DataReductionProxySavingsClearedReason::REASON_COUNT, reason);
- UMA_HISTOGRAM_ENUMERATION(
- "DataReductionProxy.SavingsCleared.Reason", reason,
- DataReductionProxySavingsClearedReason::REASON_COUNT);
-}
-
-// TODO(rajendrant): Enable aggregate metrics recording in x86 Android.
-// http://crbug.com/865373
-#if !defined(OS_ANDROID) || !defined(ARCH_CPU_X86)
-const double kSecondsPerWeek =
- base::Time::kMicrosecondsPerWeek / base::Time::kMicrosecondsPerSecond;
-
-// Returns the week number for the current time. The epoch time is treated as
-// week=0.
-int32_t GetCurrentWeekNumber(const base::Time& now) {
- double now_in_seconds = now.ToDoubleT();
- return now_in_seconds / kSecondsPerWeek;
-}
-
-// Adds |value| to the item at |key| in the preference dictionary found at
-// |pref|. If |key| is not found it will be inserted.
-void AddToDictionaryPref(PrefService* pref_service,
- const std::string& pref,
- int key,
- int value) {
- DictionaryPrefUpdate pref_update(pref_service, pref);
- base::DictionaryValue* pref_dict = pref_update.Get();
- const std::string key_str = base::NumberToString(key);
- base::Value* dict_value = pref_dict->FindKey(key_str);
- if (dict_value)
- value += dict_value->GetInt();
- pref_dict->SetKey(key_str, base::Value(value));
-}
-
-// Moves the dictionary stored in preference |pref_src| to |pref_dst|, and
-// clears the preference |pref_src|.
-void MoveAndClearDictionaryPrefs(PrefService* pref_service,
- const std::string& pref_dst,
- const std::string& pref_src) {
- DictionaryPrefUpdate pref_update_dst(pref_service, pref_dst);
- base::DictionaryValue* pref_dict_dst = pref_update_dst.Get();
- DictionaryPrefUpdate pref_update_src(pref_service, pref_src);
- base::DictionaryValue* pref_dict_src = pref_update_src.Get();
- pref_dict_dst->DictClear();
- pref_dict_dst->Swap(pref_dict_src);
- DCHECK(pref_dict_src->DictEmpty());
-}
-
-void MaybeInitWeeklyAggregateDataUsePrefs(const base::Time& now,
- PrefService* pref_service) {
- int saved_week = pref_service->GetInteger(prefs::kThisWeekNumber);
- int current_week = GetCurrentWeekNumber(now);
-
- if (saved_week == current_week)
- return;
-
- pref_service->SetInteger(prefs::kThisWeekNumber, current_week);
- if (current_week == saved_week + 1) {
- // The next week has just started. Move the data use aggregate prefs for
- // this week to last week, and clear the prefs for this week.
- MoveAndClearDictionaryPrefs(pref_service,
- prefs::kLastWeekServicesDownstreamBackgroundKB,
- prefs::kThisWeekServicesDownstreamBackgroundKB);
- MoveAndClearDictionaryPrefs(pref_service,
- prefs::kLastWeekServicesDownstreamForegroundKB,
- prefs::kThisWeekServicesDownstreamForegroundKB);
- MoveAndClearDictionaryPrefs(
- pref_service, prefs::kLastWeekUserTrafficContentTypeDownstreamKB,
- prefs::kThisWeekUserTrafficContentTypeDownstreamKB);
- } else {
- // Current week is too different than the last time data use aggregate prefs
- // were updated. This may happen if Chrome was opened after a long time, or
- // due to system clock being changed backward or forward. Clear all prefs in
- // this case.
- pref_service->ClearPref(prefs::kLastWeekServicesDownstreamBackgroundKB);
- pref_service->ClearPref(prefs::kLastWeekServicesDownstreamForegroundKB);
- pref_service->ClearPref(prefs::kLastWeekUserTrafficContentTypeDownstreamKB);
- pref_service->ClearPref(prefs::kThisWeekServicesDownstreamBackgroundKB);
- pref_service->ClearPref(prefs::kThisWeekServicesDownstreamForegroundKB);
- pref_service->ClearPref(prefs::kThisWeekUserTrafficContentTypeDownstreamKB);
- }
-}
-
-// Records the key-value pairs in the dictionary in a sparse histogram.
-void RecordDictionaryToHistogram(const std::string& histogram_name,
- const base::DictionaryValue* dictionary) {
- base::HistogramBase* histogram = base::SparseHistogram::FactoryGet(
- histogram_name, base::HistogramBase::kUmaTargetedHistogramFlag);
- for (auto entry : dictionary->DictItems()) {
- int key;
- int value = entry.second.GetInt();
- if (value > 0 && base::StringToInt(entry.first, &key)) {
- histogram->AddCount(key, value);
- }
- }
-}
-#endif
-
-} // namespace
-
-class DataReductionProxyCompressionStats::DailyContentLengthUpdate {
- public:
- DailyContentLengthUpdate(
- DataReductionProxyCompressionStats* compression_stats,
- const char* pref_path)
- : update_(nullptr),
- compression_stats_(compression_stats),
- pref_path_(pref_path) {}
-
- DailyContentLengthUpdate(const DailyContentLengthUpdate&) = delete;
- DailyContentLengthUpdate& operator=(const DailyContentLengthUpdate&) = delete;
-
- void UpdateForDateChange(int days_since_last_update) {
- if (days_since_last_update) {
- MaybeInitialize();
- MaintainContentLengthPrefForDateChange(days_since_last_update);
- }
- }
-
- // Update the lengths for the current day.
- void Add(int64_t content_length) {
- if (content_length != 0) {
- MaybeInitialize();
- AddInt64ToListPref(kNumDaysInHistory - 1, content_length, update_);
- }
- }
-
- int64_t GetListPrefValue(size_t index) {
- MaybeInitialize();
- return std::max(GetInt64PrefValue(*update_, index),
- static_cast<int64_t>(0));
- }
-
- private:
- void MaybeInitialize() {
- if (update_)
- return;
-
- update_ = compression_stats_->GetList(pref_path_);
- // New empty lists may have been created. Maintain the invariant that
- // there should be exactly |kNumDaysInHistory| days in the histories.
- MaintainContentLengthPrefsWindow(update_, kNumDaysInHistory);
- }
-
- // Update the list for date change and ensure the list has exactly |length|
- // elements. The last entry in the list will be for the current day after
- // the update.
- void MaintainContentLengthPrefForDateChange(int days_since_last_update) {
- if (days_since_last_update == -1) {
- // The system may go backwards in time by up to a day for legitimate
- // reasons, such as with changes to the time zone. In such cases, we
- // keep adding to the current day.
- // Note: we accept the fact that some reported data is shifted to
- // the adjacent day if users travel back and forth across time zones.
- days_since_last_update = 0;
- } else if (days_since_last_update < -1) {
- // Erase all entries if the system went backwards in time by more than
- // a day.
- update_->ClearList();
-
- days_since_last_update = kNumDaysInHistory;
- }
- DCHECK_GE(days_since_last_update, 0);
-
- // Add entries for days since last update event. This will make the
- // lists longer than kNumDaysInHistory. The additional items will be cut off
- // from the head of the lists by |MaintainContentLengthPrefsWindow|, below.
- for (int i = 0;
- i < days_since_last_update && i < static_cast<int>(kNumDaysInHistory);
- ++i) {
- update_->Append(base::NumberToString(0));
- }
-
- // Entries for new days may have been appended. Maintain the invariant that
- // there should be exactly |kNumDaysInHistory| days in the histories.
- MaintainContentLengthPrefsWindow(update_, kNumDaysInHistory);
- }
-
- // Non-owned. Lazily initialized, set to nullptr until initialized.
- raw_ptr<base::ListValue> update_;
- // Non-owned pointer.
- raw_ptr<DataReductionProxyCompressionStats> compression_stats_;
- // The path of the content length pref for |this|.
- const char* pref_path_;
-};
-
-// DailyDataSavingUpdate maintains a pair of data saving prefs, original_update_
-// and received_update_. pref_original is a list of |kNumDaysInHistory| elements
-// of daily total original content lengths for the past |kNumDaysInHistory|
-// days. pref_received is the corresponding list of the daily total received
-// content lengths.
-class DataReductionProxyCompressionStats::DailyDataSavingUpdate {
- public:
- DailyDataSavingUpdate(DataReductionProxyCompressionStats* compression_stats,
- const char* original_pref_path,
- const char* received_pref_path)
- : original_(compression_stats, original_pref_path),
- received_(compression_stats, received_pref_path) {}
-
- DailyDataSavingUpdate(const DailyDataSavingUpdate&) = delete;
- DailyDataSavingUpdate& operator=(const DailyDataSavingUpdate&) = delete;
-
- void UpdateForDateChange(int days_since_last_update) {
- original_.UpdateForDateChange(days_since_last_update);
- received_.UpdateForDateChange(days_since_last_update);
- }
-
- // Update the lengths for the current day.
- void Add(int64_t original_content_length, int64_t received_content_length) {
- original_.Add(original_content_length);
- received_.Add(received_content_length);
- }
-
- int64_t GetOriginalListPrefValue(size_t index) {
- return original_.GetListPrefValue(index);
- }
- int64_t GetReceivedListPrefValue(size_t index) {
- return received_.GetListPrefValue(index);
- }
-
- private:
- DailyContentLengthUpdate original_;
- DailyContentLengthUpdate received_;
-};
-
-DataReductionProxyCompressionStats::DataReductionProxyCompressionStats(
- DataReductionProxyService* service,
- PrefService* prefs,
- const base::TimeDelta& delay)
- : service_(service),
- pref_service_(prefs),
- delay_(delay),
- data_usage_map_is_dirty_(false),
- current_data_usage_load_status_(NOT_LOADED) {
- DCHECK(service);
- DCHECK(prefs);
- DCHECK_GE(delay.InMilliseconds(), 0);
- Init();
-}
-
-DataReductionProxyCompressionStats::~DataReductionProxyCompressionStats() {
- DCHECK(thread_checker_.CalledOnValidThread());
-
- if (current_data_usage_load_status_ == LOADED)
- PersistDataUsage();
-
- WritePrefs();
-}
-
-void DataReductionProxyCompressionStats::Init() {
- DCHECK(thread_checker_.CalledOnValidThread());
-
- data_usage_reporting_enabled_.Init(
- prefs::kDataUsageReportingEnabled, pref_service_,
- base::BindRepeating(
- &DataReductionProxyCompressionStats::OnDataUsageReportingPrefChanged,
- weak_factory_.GetWeakPtr()));
-
- if (data_usage_reporting_enabled_.GetValue()) {
- current_data_usage_load_status_ = LOADING;
- service_->LoadCurrentDataUsageBucket(base::BindRepeating(
- &DataReductionProxyCompressionStats::OnCurrentDataUsageLoaded,
- weak_factory_.GetWeakPtr()));
- }
-
- InitializeWeeklyAggregateDataUse(base::Time::Now());
-
- if (delay_.is_zero())
- return;
-
- // Init all int64_t prefs.
- InitInt64Pref(prefs::kDailyHttpContentLengthLastUpdateDate);
- InitInt64Pref(prefs::kHttpReceivedContentLength);
- InitInt64Pref(prefs::kHttpOriginalContentLength);
-
- // Init all list prefs.
- InitListPref(prefs::kDailyHttpOriginalContentLength);
- InitListPref(prefs::kDailyHttpReceivedContentLength);
-}
-
-void DataReductionProxyCompressionStats::RecordDataUseWithMimeType(
- int64_t data_used,
- int64_t original_size,
- bool data_saver_enabled,
- const std::string& mime_type,
- bool is_user_traffic,
- data_use_measurement::DataUseUserData::DataUseContentType content_type,
- int32_t service_hash_code) {
- DCHECK(thread_checker_.CalledOnValidThread());
- TRACE_EVENT0("loading",
- "DataReductionProxyCompressionStats::RecordDataUseWithMimeType");
-
- IncreaseInt64Pref(data_reduction_proxy::prefs::kHttpReceivedContentLength,
- data_used);
- IncreaseInt64Pref(data_reduction_proxy::prefs::kHttpOriginalContentLength,
- original_size);
-
- RecordRequestSizePrefs(data_used, original_size, data_saver_enabled,
- mime_type, base::Time::Now());
- RecordWeeklyAggregateDataUse(
- base::Time::Now(), std::round(static_cast<double>(data_used) / 1024),
- is_user_traffic, content_type, service_hash_code);
-}
-
-void DataReductionProxyCompressionStats::InitInt64Pref(const char* pref) {
- int64_t pref_value = pref_service_->GetInt64(pref);
- pref_map_[pref] = pref_value;
-}
-
-void DataReductionProxyCompressionStats::InitListPref(const char* pref) {
- std::unique_ptr<base::ListValue> pref_value =
- pref_service_->GetList(pref)->CreateDeepCopy();
- list_pref_map_[pref] = std::move(pref_value);
-}
-
-int64_t DataReductionProxyCompressionStats::GetInt64(const char* pref_path) {
- if (delay_.is_zero())
- return pref_service_->GetInt64(pref_path);
-
- auto iter = pref_map_.find(pref_path);
- return iter->second;
-}
-
-void DataReductionProxyCompressionStats::SetInt64(const char* pref_path,
- int64_t pref_value) {
- if (delay_.is_zero()) {
- pref_service_->SetInt64(pref_path, pref_value);
- return;
- }
-
- DelayedWritePrefs();
- pref_map_[pref_path] = pref_value;
-}
-
-void DataReductionProxyCompressionStats::IncreaseInt64Pref(
- const char* pref_path,
- int64_t delta) {
- SetInt64(pref_path, GetInt64(pref_path) + delta);
-}
-
-base::ListValue* DataReductionProxyCompressionStats::GetList(
- const char* pref_path) {
- if (delay_.is_zero())
- return ListPrefUpdate(pref_service_, pref_path).Get();
-
- DelayedWritePrefs();
- auto it = list_pref_map_.find(pref_path);
- if (it == list_pref_map_.end())
- return nullptr;
- return it->second.get();
-}
-
-void DataReductionProxyCompressionStats::WritePrefs() {
- DCHECK(thread_checker_.CalledOnValidThread());
- if (delay_.is_zero())
- return;
-
- for (auto iter = pref_map_.begin(); iter != pref_map_.end(); ++iter) {
- pref_service_->SetInt64(iter->first, iter->second);
- }
-
- for (auto iter = list_pref_map_.begin(); iter != list_pref_map_.end();
- ++iter) {
- TransferList(*(iter->second.get()),
- ListPrefUpdate(pref_service_, iter->first).Get());
- }
-}
-
-int64_t DataReductionProxyCompressionStats::GetLastUpdateTime() {
- int64_t last_update_internal =
- GetInt64(prefs::kDailyHttpContentLengthLastUpdateDate);
- base::Time last_update = base::Time::FromInternalValue(last_update_internal);
- return static_cast<int64_t>(last_update.ToJsTime());
-}
-
-void DataReductionProxyCompressionStats::ResetStatistics() {
- base::ListValue* original_update =
- GetList(prefs::kDailyHttpOriginalContentLength);
- base::ListValue* received_update =
- GetList(prefs::kDailyHttpReceivedContentLength);
- original_update->ClearList();
- received_update->ClearList();
- for (size_t i = 0; i < kNumDaysInHistory; ++i) {
- original_update->Append(base::NumberToString(0));
- received_update->Append(base::NumberToString(0));
- }
-}
-
-int64_t DataReductionProxyCompressionStats::GetHttpReceivedContentLength() {
- return GetInt64(prefs::kHttpReceivedContentLength);
-}
-
-int64_t DataReductionProxyCompressionStats::GetHttpOriginalContentLength() {
- return GetInt64(prefs::kHttpOriginalContentLength);
-}
-
-ContentLengthList DataReductionProxyCompressionStats::GetDailyContentLengths(
- const char* pref_name) {
- ContentLengthList content_lengths;
- const base::ListValue* list_value = GetList(pref_name);
- if (list_value->GetList().size() == kNumDaysInHistory) {
- for (size_t i = 0; i < kNumDaysInHistory; ++i)
- content_lengths.push_back(GetInt64PrefValue(*list_value, i));
- }
- return content_lengths;
-}
-
-void DataReductionProxyCompressionStats::GetContentLengths(
- unsigned int days,
- int64_t* original_content_length,
- int64_t* received_content_length,
- int64_t* last_update_time) {
- DCHECK_LE(days, kNumDaysInHistory);
-
- const base::ListValue* original_list =
- GetList(prefs::kDailyHttpOriginalContentLength);
- const base::ListValue* received_list =
- GetList(prefs::kDailyHttpReceivedContentLength);
-
- if (original_list->GetList().size() != kNumDaysInHistory ||
- received_list->GetList().size() != kNumDaysInHistory) {
- *original_content_length = 0L;
- *received_content_length = 0L;
- *last_update_time = 0L;
- return;
- }
-
- int64_t orig = 0L;
- int64_t recv = 0L;
- // Include days from the end of the list going backwards.
- for (size_t i = kNumDaysInHistory - days;
- i < kNumDaysInHistory; ++i) {
- orig += GetInt64PrefValue(*original_list, i);
- recv += GetInt64PrefValue(*received_list, i);
- }
- *original_content_length = orig;
- *received_content_length = recv;
- *last_update_time = GetInt64(prefs::kDailyHttpContentLengthLastUpdateDate);
-}
-
-void DataReductionProxyCompressionStats::GetHistoricalDataUsage(
- HistoricalDataUsageCallback get_data_usage_callback) {
- GetHistoricalDataUsageImpl(std::move(get_data_usage_callback),
- base::Time::Now());
-}
-
-void DataReductionProxyCompressionStats::DeleteBrowsingHistory(
- const base::Time& start,
- const base::Time& end) {
- DCHECK_NE(LOADING, current_data_usage_load_status_);
-
- if (!data_usage_map_last_updated_.is_null() &&
- DataUsageStore::BucketOverlapsInterval(data_usage_map_last_updated_,
- start, end)) {
- data_usage_map_.clear();
- data_usage_map_last_updated_ = base::Time();
- data_usage_map_is_dirty_ = false;
- }
-
- service_->DeleteBrowsingHistory(start, end);
-
- RecordSavingsClearedMetric(DataReductionProxySavingsClearedReason::
- USER_ACTION_DELETE_BROWSING_HISTORY);
-}
-
-void DataReductionProxyCompressionStats::OnCurrentDataUsageLoaded(
- std::unique_ptr<DataUsageBucket> data_usage) {
- // Exit early if the pref was turned off before loading from storage
- // completed.
- if (!data_usage_reporting_enabled_.GetValue()) {
- DCHECK_EQ(NOT_LOADED, current_data_usage_load_status_);
- DCHECK(data_usage_map_.empty());
- current_data_usage_load_status_ = NOT_LOADED;
- return;
- } else {
- DCHECK_EQ(LOADING, current_data_usage_load_status_);
- }
-
- DCHECK(data_usage_map_last_updated_.is_null());
- DCHECK(data_usage_map_.empty());
-
- // We currently do not break down by connection type. However, we use a schema
- // that makes it easy to transition to a connection based breakdown without
- // requiring a data migration.
- DCHECK(data_usage->connection_usage_size() == 0 ||
- data_usage->connection_usage_size() == 1);
- for (const auto& connection_usage : data_usage->connection_usage()) {
- for (const auto& site_usage : connection_usage.site_usage()) {
- data_usage_map_[site_usage.hostname()] =
- std::make_unique<PerSiteDataUsage>(site_usage);
- }
- }
-
- data_usage_map_last_updated_ =
- base::Time::FromInternalValue(data_usage->last_updated_timestamp());
- // Record if there was a read error.
- if (data_usage->had_read_error()) {
- RecordSavingsClearedMetric(
- DataReductionProxySavingsClearedReason::PREFS_PARSE_ERROR);
- }
-
- current_data_usage_load_status_ = LOADED;
-}
-
-void DataReductionProxyCompressionStats::SetDataUsageReportingEnabled(
- bool enabled) {
- DCHECK(thread_checker_.CalledOnValidThread());
- if (data_usage_reporting_enabled_.GetValue() != enabled) {
- data_usage_reporting_enabled_.SetValue(enabled);
- OnDataUsageReportingPrefChanged();
- }
-}
-
-void DataReductionProxyCompressionStats::ClearDataSavingStatistics(
- DataReductionProxySavingsClearedReason reason) {
- DeleteHistoricalDataUsage();
-
- pref_service_->ClearPref(prefs::kDailyHttpContentLengthLastUpdateDate);
- pref_service_->ClearPref(prefs::kHttpReceivedContentLength);
- pref_service_->ClearPref(prefs::kHttpOriginalContentLength);
-
- pref_service_->ClearPref(prefs::kDailyHttpOriginalContentLength);
- pref_service_->ClearPref(prefs::kDailyHttpReceivedContentLength);
-
- for (auto iter = list_pref_map_.begin(); iter != list_pref_map_.end();
- ++iter) {
- iter->second->ClearList();
- }
-
- RecordSavingsClearedMetric(reason);
-}
-
-void DataReductionProxyCompressionStats::DelayedWritePrefs() {
- if (pref_writer_timer_.IsRunning())
- return;
-
- pref_writer_timer_.Start(FROM_HERE, delay_, this,
- &DataReductionProxyCompressionStats::WritePrefs);
-}
-
-void DataReductionProxyCompressionStats::TransferList(
- const base::Value& from_list,
- base::Value* to_list) {
- *to_list = from_list.Clone();
-}
-
-void DataReductionProxyCompressionStats::RecordRequestSizePrefs(
- int64_t data_used,
- int64_t original_size,
- bool with_data_saver_enabled,
- const std::string& mime_type,
- const base::Time& now) {
- // TODO(bengr): Remove this check once the underlying cause of
- // http://crbug.com/287821 is fixed. For now, only continue if the current
- // year is reported as being between 1972 and 2970.
- base::TimeDelta time_since_unix_epoch = now - base::Time::UnixEpoch();
- const int kMinDaysSinceUnixEpoch = 365 * 2; // 2 years.
- const int kMaxDaysSinceUnixEpoch = 365 * 1000; // 1000 years.
- if (time_since_unix_epoch.InDays() < kMinDaysSinceUnixEpoch ||
- time_since_unix_epoch.InDays() > kMaxDaysSinceUnixEpoch) {
- return;
- }
-
- // Determine how many days it has been since the last update.
- int64_t then_internal = GetInt64(
- data_reduction_proxy::prefs::kDailyHttpContentLengthLastUpdateDate);
-
- // Local midnight could have been shifted due to time zone change.
- // If time is null then don't care if midnight will be wrong shifted due to
- // time zone change because it's still too much time ago.
- base::Time then_midnight = base::Time::FromInternalValue(then_internal);
- if (!then_midnight.is_null()) {
- then_midnight = then_midnight.LocalMidnight();
- }
- base::Time midnight = now.LocalMidnight();
-
- DailyDataSavingUpdate total(
- this, data_reduction_proxy::prefs::kDailyHttpOriginalContentLength,
- data_reduction_proxy::prefs::kDailyHttpReceivedContentLength);
-
- int days_since_last_update = (midnight - then_midnight).InDays();
- if (days_since_last_update) {
- // Record the last update time in microseconds in UTC.
- SetInt64(data_reduction_proxy::prefs::kDailyHttpContentLengthLastUpdateDate,
- midnight.ToInternalValue());
-
- // The system may go backwards in time by up to a day for legitimate
- // reasons, such as with changes to the time zone. In such cases, we
- // keep adding to the current day.
- // (Actually resetting the numbers when we're more than a day off
- // happens elsewhere.)
- if (days_since_last_update < -1) {
- RecordSavingsClearedMetric(
- DataReductionProxySavingsClearedReason::SYSTEM_CLOCK_MOVED_BACK);
- }
- }
-
- total.UpdateForDateChange(days_since_last_update);
- total.Add(original_size, data_used);
-}
-
-void DataReductionProxyCompressionStats::RecordDataUseByHost(
- const std::string& data_usage_host,
- int64_t data_used,
- int64_t original_size,
- const base::Time time) {
- DCHECK(thread_checker_.CalledOnValidThread());
- if (current_data_usage_load_status_ != LOADED)
- return;
-
- DCHECK(data_usage_reporting_enabled_.GetValue());
-
- if (!DataUsageStore::AreInSameInterval(data_usage_map_last_updated_, time)) {
- PersistDataUsage();
- data_usage_map_.clear();
- data_usage_map_last_updated_ = base::Time();
- }
-
- std::string normalized_host = NormalizeHostname(data_usage_host);
- auto j = data_usage_map_.insert(
- std::make_pair(normalized_host, std::make_unique<PerSiteDataUsage>()));
- PerSiteDataUsage* per_site_usage = j.first->second.get();
- per_site_usage->set_hostname(normalized_host);
- per_site_usage->set_original_size(per_site_usage->original_size() +
- original_size);
- per_site_usage->set_data_used(per_site_usage->data_used() + data_used);
-
- data_usage_map_last_updated_ = time;
- data_usage_map_is_dirty_ = true;
-}
-
-void DataReductionProxyCompressionStats::PersistDataUsage() {
- DCHECK(current_data_usage_load_status_ == LOADED);
-
- if (data_usage_map_is_dirty_) {
- std::unique_ptr<DataUsageBucket> data_usage_bucket(new DataUsageBucket());
- data_usage_bucket->set_last_updated_timestamp(
- data_usage_map_last_updated_.ToInternalValue());
- PerConnectionDataUsage* connection_usage =
- data_usage_bucket->add_connection_usage();
- for (auto i = data_usage_map_.begin(); i != data_usage_map_.end(); ++i) {
- PerSiteDataUsage* per_site_usage = connection_usage->add_site_usage();
- per_site_usage->CopyFrom(*(i->second.get()));
- }
- service_->StoreCurrentDataUsageBucket(std::move(data_usage_bucket));
- }
-
- data_usage_map_is_dirty_ = false;
-}
-
-void DataReductionProxyCompressionStats::DeleteHistoricalDataUsage() {
- // This method does not support being called in |LOADING| status since this
- // means that the in-memory data usage will get populated when data usage
- // loads, which will undo the clear below. This method is called when users
- // click on the "Clear Data" button, or when user deletes the extension. In
- // both cases, enough time has passed since startup to load current data
- // usage. Technically, this could occur, and will have the effect of not
- // clearing data from the current bucket.
- // TODO(kundaji): Use cancellable tasks and remove this DCHECK.
- DCHECK(current_data_usage_load_status_ != LOADING);
-
- data_usage_map_.clear();
- data_usage_map_last_updated_ = base::Time();
- data_usage_map_is_dirty_ = false;
-
- service_->DeleteHistoricalDataUsage();
-}
-
-void DataReductionProxyCompressionStats::GetHistoricalDataUsageImpl(
- HistoricalDataUsageCallback get_data_usage_callback,
- const base::Time& now) {
-#if !defined(OS_ANDROID)
- if (current_data_usage_load_status_ != LOADED) {
- // If current data usage has not yet loaded, we return an empty array. The
- // extension can retry after a slight delay.
- // This use case is unlikely to occur in practice since current data usage
- // should have sufficient time to load before user tries to view data usage.
- std::move(get_data_usage_callback)
- .Run(std::make_unique<std::vector<DataUsageBucket>>());
- return;
- }
-#endif
-
- if (current_data_usage_load_status_ == LOADED)
- PersistDataUsage();
-
- if (!data_usage_map_last_updated_.is_null() &&
- !DataUsageStore::AreInSameInterval(data_usage_map_last_updated_, now)) {
- data_usage_map_.clear();
- data_usage_map_last_updated_ = base::Time();
-
- // Force the last bucket to be for the current interval.
- std::unique_ptr<DataUsageBucket> data_usage_bucket(new DataUsageBucket());
- data_usage_bucket->set_last_updated_timestamp(now.ToInternalValue());
- service_->StoreCurrentDataUsageBucket(std::move(data_usage_bucket));
- }
-
- service_->LoadHistoricalDataUsage(std::move(get_data_usage_callback));
-}
-
-void DataReductionProxyCompressionStats::OnDataUsageReportingPrefChanged() {
- if (data_usage_reporting_enabled_.GetValue()) {
- if (current_data_usage_load_status_ == NOT_LOADED) {
- current_data_usage_load_status_ = LOADING;
- service_->LoadCurrentDataUsageBucket(base::BindOnce(
- &DataReductionProxyCompressionStats::OnCurrentDataUsageLoaded,
- weak_factory_.GetWeakPtr()));
- }
- } else {
-// Don't delete the historical data on Android, but clear the map.
-#if defined(OS_ANDROID)
- if (current_data_usage_load_status_ == LOADED)
- PersistDataUsage();
-
- data_usage_map_.clear();
- data_usage_map_last_updated_ = base::Time();
- data_usage_map_is_dirty_ = false;
-#else
- DeleteHistoricalDataUsage();
-#endif
- current_data_usage_load_status_ = NOT_LOADED;
- }
-}
-
-void DataReductionProxyCompressionStats::InitializeWeeklyAggregateDataUse(
- const base::Time& now) {
- // TODO(rajendrant): Enable aggregate metrics recording in x86 Android.
- // http://crbug.com/865373
-#if !defined(OS_ANDROID) || !defined(ARCH_CPU_X86)
- MaybeInitWeeklyAggregateDataUsePrefs(now, pref_service_);
- // Record the histograms that will show up in the user feedback.
- RecordDictionaryToHistogram(
- "DataReductionProxy.ThisWeekAggregateKB.Services.Downstream.Background",
- pref_service_->GetDictionary(
- prefs::kThisWeekServicesDownstreamBackgroundKB));
- RecordDictionaryToHistogram(
- "DataReductionProxy.ThisWeekAggregateKB.Services.Downstream.Foreground",
- pref_service_->GetDictionary(
- prefs::kThisWeekServicesDownstreamForegroundKB));
- RecordDictionaryToHistogram(
- "DataReductionProxy.ThisWeekAggregateKB.UserTraffic.Downstream."
- "ContentType",
- pref_service_->GetDictionary(
- prefs::kThisWeekUserTrafficContentTypeDownstreamKB));
- RecordDictionaryToHistogram(
- "DataReductionProxy.LastWeekAggregateKB.Services.Downstream.Background",
- pref_service_->GetDictionary(
- prefs::kLastWeekServicesDownstreamBackgroundKB));
- RecordDictionaryToHistogram(
- "DataReductionProxy.LastWeekAggregateKB.Services.Downstream.Foreground",
- pref_service_->GetDictionary(
- prefs::kLastWeekServicesDownstreamForegroundKB));
- RecordDictionaryToHistogram(
- "DataReductionProxy.LastWeekAggregateKB.UserTraffic.Downstream."
- "ContentType",
- pref_service_->GetDictionary(
- prefs::kLastWeekUserTrafficContentTypeDownstreamKB));
-#endif
-}
-
-void DataReductionProxyCompressionStats::RecordWeeklyAggregateDataUse(
- const base::Time& now,
- int32_t data_used_kb,
- bool is_user_request,
- data_use_measurement::DataUseUserData::DataUseContentType content_type,
- int32_t service_hash_code) {
- // TODO(rajendrant): Enable aggregate metrics recording in x86 Android.
- // http://crbug.com/865373
-#if !defined(OS_ANDROID) || !defined(ARCH_CPU_X86)
- // Update the prefs if this is a new week. This can happen when chrome is open
- // for weeks without being closed.
- MaybeInitWeeklyAggregateDataUsePrefs(now, pref_service_);
- if (is_user_request) {
- AddToDictionaryPref(pref_service_,
- prefs::kThisWeekUserTrafficContentTypeDownstreamKB,
- content_type, data_used_kb);
- } else {
- bool is_app_foreground = true;
- if (is_app_foreground) {
- AddToDictionaryPref(pref_service_,
- prefs::kThisWeekServicesDownstreamForegroundKB,
- service_hash_code, data_used_kb);
- } else {
- AddToDictionaryPref(pref_service_,
- prefs::kThisWeekServicesDownstreamBackgroundKB,
- service_hash_code, data_used_kb);
- }
- }
-#endif
-}
-
-// static
-std::string DataReductionProxyCompressionStats::NormalizeHostname(
- const std::string& host) {
- size_t pos = host.find("://");
- if (pos != std::string::npos)
- return host.substr(pos + 3);
-
- return host;
-}
-
-} // namespace data_reduction_proxy
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.h b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.h
deleted file mode 100644
index cc86976e7fb..00000000000
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.h
+++ /dev/null
@@ -1,306 +0,0 @@
-// Copyright 2014 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.
-
-#ifndef COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_COMPRESSION_STATS_H_
-#define COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_COMPRESSION_STATS_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <map>
-#include <memory>
-#include <string>
-#include <unordered_map>
-
-#include "base/memory/raw_ptr.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "base/threading/thread_checker.h"
-#include "base/time/time.h"
-#include "base/timer/timer.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics.h"
-#include "components/data_reduction_proxy/core/browser/db_data_owner.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
-#include "components/data_use_measurement/core/data_use_user_data.h"
-#include "components/prefs/pref_member.h"
-
-class PrefService;
-
-namespace base {
-class ListValue;
-class Value;
-}
-
-namespace data_reduction_proxy {
-class DataReductionProxyService;
-class DataUsageBucket;
-class PerSiteDataUsage;
-
-// These values are persisted to logs. Entries should not be renumbered and
-// numeric values should never be reused.
-//
-// A Java counterpart will be generated for this enum.
-// GENERATED_JAVA_ENUM_PACKAGE: (
-// org.chromium.chrome.browser.settings.datareduction)
-enum class DataReductionProxySavingsClearedReason {
- SYSTEM_CLOCK_MOVED_BACK,
- PREFS_PARSE_ERROR,
- USER_ACTION_EXTENSION,
- USER_ACTION_SETTINGS_MENU,
- USER_ACTION_DELETE_BROWSING_HISTORY,
- // NOTE: always keep this entry at the end. Add new result types only
- // immediately above this line. Make sure to update the corresponding
- // histogram enum accordingly.
- REASON_COUNT,
-};
-
-// Data reduction proxy delayed pref service reduces the number calls to pref
-// service by storing prefs in memory and writing to the given PrefService after
-// |delay| amount of time. If |delay| is zero, the delayed pref service writes
-// directly to the PrefService and does not store the prefs in memory. All
-// prefs must be stored and read on the UI thread.
-class DataReductionProxyCompressionStats {
- public:
- typedef std::unordered_map<std::string, std::unique_ptr<PerSiteDataUsage>>
- SiteUsageMap;
-
- // Collects and store data usage and compression statistics. Basic data usage
- // stats are stored in browser preferences. More detailed stats broken down
- // by site and internet type are stored in |DataReductionProxyStore|.
- //
- // To store basic stats, it constructs a data reduction proxy delayed pref
- // service object using |pref_service|. Writes prefs to |pref_service| after
- // |delay| and stores them in |pref_map_| and |list_pref_map| between writes.
- // If |delay| is zero, writes directly to the PrefService and does not store
- // in the maps.
- DataReductionProxyCompressionStats(DataReductionProxyService* service,
- PrefService* pref_service,
- const base::TimeDelta& delay);
-
- DataReductionProxyCompressionStats(
- const DataReductionProxyCompressionStats&) = delete;
- DataReductionProxyCompressionStats& operator=(
- const DataReductionProxyCompressionStats&) = delete;
-
- ~DataReductionProxyCompressionStats();
-
- // Records detailed data usage broken down by |mime_type|. Also records daily
- // data savings statistics to prefs and reports data savings UMA. |data_used|
- // and |original_size| are measured in bytes.
- void RecordDataUseWithMimeType(
- int64_t compressed_size,
- int64_t original_size,
- bool data_reduction_proxy_enabled,
- const std::string& mime_type,
- bool is_user_traffic,
- data_use_measurement::DataUseUserData::DataUseContentType content_type,
- int32_t service_hash_code);
-
- // Record data usage and original size of request broken down by host.
- // |original_request_size| and |data_used| are in bytes. |time| is the time at
- // which the data usage occurred. This method should be called in real time,
- // so |time| is expected to be |Time::Now()|.
- void RecordDataUseByHost(const std::string& data_usage_host,
- int64_t original_request_size,
- int64_t data_used,
- const base::Time time);
-
- // Returns the time in milliseconds since epoch that the last update was made
- // to the daily original and received content lengths.
- int64_t GetLastUpdateTime();
-
- // Resets daily content length statistics.
- void ResetStatistics();
-
- // Clears all data saving statistics for the given |reason|.
- void ClearDataSavingStatistics(DataReductionProxySavingsClearedReason reason);
-
- // Returns the total size of all HTTP content received from the network.
- int64_t GetHttpReceivedContentLength();
-
- // Returns the value the total original size of all HTTP content received from
- // the network.
- int64_t GetHttpOriginalContentLength();
-
- // Returns a list of all the daily content lengths.
- ContentLengthList GetDailyContentLengths(const char* pref_name);
-
- // Returns aggregate received and original content lengths over the specified
- // number of days, as well as the time these stats were last updated.
- void GetContentLengths(unsigned int days,
- int64_t* original_content_length,
- int64_t* received_content_length,
- int64_t* last_update_time);
-
- // Calls |get_data_usage_callback| with full data usage history. In-memory
- // data usage stats are flushed to storage before querying for full history.
- // An empty vector will be returned if "data_usage_reporting.enabled" pref is
- // not enabled or if called immediately after enabling the pref before
- // in-memory stats could be initialized from storage. Data usage is sorted
- // chronologically with the last entry corresponding to |base::Time::Now()|.
- void GetHistoricalDataUsage(
- HistoricalDataUsageCallback get_data_usage_callback);
-
- // Deletes browsing history from storage and memory for the given time
- // range. Currently, this method deletes all data usage for the given range.
- void DeleteBrowsingHistory(const base::Time& start, const base::Time& end);
-
- // Callback from loading detailed data usage. Initializes in memory data
- // structures used to collect data usage. |data_usage| contains the data usage
- // for the last stored interval.
- void OnCurrentDataUsageLoaded(std::unique_ptr<DataUsageBucket> data_usage);
-
- // Sets the value of |prefs::kDataUsageReportingEnabled| to |enabled|.
- // Initializes data usage statistics in memory when pref is enabled and
- // persists data usage to memory when pref is disabled.
- void SetDataUsageReportingEnabled(bool enabled);
-
- // Returns |data_usage_map_|.
- const DataReductionProxyCompressionStats::SiteUsageMap&
- DataUsageMapForTesting() const {
- return data_usage_map_;
- }
-
- private:
- // Enum to track the state of loading data usage from storage.
- enum CurrentDataUsageLoadStatus { NOT_LOADED = 0, LOADING = 1, LOADED = 2 };
-
- friend class DataReductionProxyCompressionStatsTest;
-
- typedef std::map<const char*, int64_t> DataReductionProxyPrefMap;
- typedef std::unordered_map<const char*, std::unique_ptr<base::ListValue>>
- DataReductionProxyListPrefMap;
-
- class DailyContentLengthUpdate;
- class DailyDataSavingUpdate;
-
- // Loads all data_reduction_proxy::prefs into the |pref_map_| and
- // |list_pref_map_|.
- void Init();
-
- // Gets the value of |pref| from the pref service and adds it to the
- // |pref_map|.
- void InitInt64Pref(const char* pref);
-
- // Gets the value of |pref| from the pref service and adds it to the
- // |list_pref_map|.
- void InitListPref(const char* pref);
-
- void OnUpdateContentLengths();
-
- // Gets the int64_t pref at |pref_path| from the |DataReductionProxyPrefMap|.
- int64_t GetInt64(const char* pref_path);
-
- // Updates the pref value in the |DataReductionProxyPrefMap| map.
- // The pref is later written to |pref service_|.
- void SetInt64(const char* pref_path, int64_t pref_value);
-
- // Increases the pref value in the |DataReductionProxyPrefMap| map.
- // The pref is later written to |pref service_|.
- void IncreaseInt64Pref(const char* pref_path, int64_t delta);
-
- // Gets the pref list at |pref_path| from the |DataReductionProxyPrefMap|.
- base::ListValue* GetList(const char* pref_path);
-
- // Writes the prefs stored in |DataReductionProxyPrefMap| and
- // |DataReductionProxyListPrefMap| to |pref_service|.
- void WritePrefs();
-
- // Starts a timer (if necessary) to write prefs in |kMinutesBetweenWrites| to
- // the |pref_service|.
- void DelayedWritePrefs();
-
- // Copies the values at each index of |from_list| to the same index in
- // |to_list|.
- void TransferList(const base::Value& from_list, base::Value* to_list);
-
- // Records content length updates to prefs.
- void RecordRequestSizePrefs(int64_t compressed_size,
- int64_t original_size,
- bool with_data_reduction_proxy_enabled,
- const std::string& mime_type,
- const base::Time& now);
-
- void IncrementDailyUmaPrefs(int64_t original_size,
- int64_t received_size,
- const char* original_size_pref,
- const char* received_size_pref,
- bool data_reduction_proxy_enabled,
- const char* original_size_with_proxy_enabled_pref,
- const char* recevied_size_with_proxy_enabled_pref,
- bool via_data_reduction_proxy,
- const char* original_size_via_proxy_pref,
- const char* received_size_via_proxy_pref);
-
- // Persists the in memory data usage information to storage and clears all
- // in-memory data usage. Do not call this method unless |data_usage_loaded_|
- // is |LOADED|.
- void PersistDataUsage();
-
- // Deletes all historical data usage from storage and memory. This method
- // should not be called when |current_data_usage_load_status_| is |LOADING|.
- void DeleteHistoricalDataUsage();
-
- // Actual implementation of |GetHistoricalDataUsage|. This helper method
- // explicitly passes |base::Time::Now()| to make testing easier.
- void GetHistoricalDataUsageImpl(
- HistoricalDataUsageCallback get_data_usage_callback,
- const base::Time& now);
-
- // Called when |prefs::kDataUsageReportingEnabled| pref values changes.
- // Initializes data usage statistics in memory when pref is enabled and
- // persists data usage to memory when pref is disabled.
- void OnDataUsageReportingPrefChanged();
-
- // Initialize the weekly data use prefs for the current week, and records the
- // weekly aggregate data use histograms.
- void InitializeWeeklyAggregateDataUse(const base::Time& now);
-
- // Records |data_used_kb| to the current week data use pref. |is_user_request|
- // indicates if this is user-initiated traffic or chrome services traffic, and
- // |service_hash_code| uniquely identifies the corresponding chrome service.
- void RecordWeeklyAggregateDataUse(
- const base::Time& now,
- int32_t data_used_kb,
- bool is_user_request,
- data_use_measurement::DataUseUserData::DataUseContentType content_type,
- int32_t service_hash_code);
-
- // Normalizes the hostname for data usage attribution. Returns a substring
- // without the protocol.
- // Example: "http://www.finance.google.com" -> "www.finance.google.com"
- static std::string NormalizeHostname(const std::string& host);
-
- raw_ptr<DataReductionProxyService> service_;
- raw_ptr<PrefService> pref_service_;
- const base::TimeDelta delay_;
- DataReductionProxyPrefMap pref_map_;
- DataReductionProxyListPrefMap list_pref_map_;
- BooleanPrefMember data_usage_reporting_enabled_;
-
- // Maintains detailed data usage for current interval.
- SiteUsageMap data_usage_map_;
-
- // Time when |data_usage_map_| was last updated. Contains NULL time if
- // |data_usage_map_| does not have any data. This could happen either because
- // current data usage has not yet been loaded from storage, or because
- // no data usage has ever been recorded.
- base::Time data_usage_map_last_updated_;
-
- // Tracks whether |data_usage_map_| has changes that have not yet been
- // persisted to storage.
- bool data_usage_map_is_dirty_;
-
- // Tracks state of loading data usage from storage.
- CurrentDataUsageLoadStatus current_data_usage_load_status_;
-
- base::OneShotTimer pref_writer_timer_;
- base::ThreadChecker thread_checker_;
-
- base::WeakPtrFactory<DataReductionProxyCompressionStats> weak_factory_{this};
-};
-
-} // namespace data_reduction_proxy
-
-#endif // COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_COMPRESSION_STATS_H_
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats_unittest.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats_unittest.cc
deleted file mode 100644
index 254e98c97f0..00000000000
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats_unittest.cc
+++ /dev/null
@@ -1,1080 +0,0 @@
-// Copyright 2014 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.
-
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <memory>
-#include <string>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/memory/ref_counted.h"
-#include "base/run_loop.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/test/metrics/histogram_tester.h"
-#include "base/test/task_environment.h"
-#include "base/time/time.h"
-#include "base/values.h"
-#include "build/build_config.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h"
-#include "components/data_reduction_proxy/proto/data_store.pb.h"
-#include "components/prefs/pref_registry_simple.h"
-#include "components/prefs/pref_service.h"
-#include "components/prefs/testing_pref_service.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace {
-
-const int kWriteDelayMinutes = 60;
-
-// Each bucket holds data usage for a 15 minute interval. History is maintained
-// for 60 days.
-const int kNumExpectedBuckets = 60 * 24 * 60 / 15;
-
-int64_t GetListPrefInt64Value(const base::ListValue& list_update,
- size_t index) {
- std::string string_value;
- base::Value::ConstListView list_view = list_update.GetList();
- if (index < list_view.size() && list_view[index].is_string()) {
- string_value = list_view[index].GetString();
- } else {
- ADD_FAILURE() << "invalid index or [index] not a string";
- }
-
- int64_t value = 0;
- EXPECT_TRUE(base::StringToInt64(string_value, &value));
- return value;
-}
-
-class DataUsageLoadVerifier {
- public:
- DataUsageLoadVerifier(
- std::unique_ptr<std::vector<data_reduction_proxy::DataUsageBucket>>
- expected) {
- expected_ = std::move(expected);
- }
-
- void OnLoadDataUsage(
- std::unique_ptr<std::vector<data_reduction_proxy::DataUsageBucket>>
- actual) {
- EXPECT_EQ(expected_->size(), actual->size());
-
- // We are iterating through 2 vectors, |actual| and |expected|, so using an
- // index rather than an iterator.
- for (size_t i = 0; i < expected_->size(); ++i) {
- data_reduction_proxy::DataUsageBucket* actual_bucket = &(actual->at(i));
- data_reduction_proxy::DataUsageBucket* expected_bucket =
- &(expected_->at(i));
- EXPECT_EQ(expected_bucket->connection_usage_size(),
- actual_bucket->connection_usage_size());
-
- for (int j = 0; j < expected_bucket->connection_usage_size(); ++j) {
- data_reduction_proxy::PerConnectionDataUsage actual_connection_usage =
- actual_bucket->connection_usage(j);
- data_reduction_proxy::PerConnectionDataUsage expected_connection_usage =
- expected_bucket->connection_usage(j);
-
- EXPECT_EQ(expected_connection_usage.site_usage_size(),
- actual_connection_usage.site_usage_size());
-
- for (auto expected_site_usage :
- expected_connection_usage.site_usage()) {
- data_reduction_proxy::PerSiteDataUsage actual_site_usage;
- for (auto it = actual_connection_usage.site_usage().begin();
- it != actual_connection_usage.site_usage().end(); ++it) {
- if (it->hostname() == expected_site_usage.hostname()) {
- actual_site_usage = *it;
- }
- }
-
- EXPECT_EQ(expected_site_usage.data_used(),
- actual_site_usage.data_used());
- EXPECT_EQ(expected_site_usage.original_size(),
- actual_site_usage.original_size());
- }
- }
- }
- }
-
- private:
- std::unique_ptr<std::vector<data_reduction_proxy::DataUsageBucket>> expected_;
-};
-
-} // namespace
-
-namespace data_reduction_proxy {
-
-// The initial last update time used in test. There is no leap second a few
-// days around this time used in the test.
-// Note: No time zone is specified. Local time will be assumed by
-// base::Time::FromString below.
-const char kLastUpdateTime[] = "Wed, 18 Sep 2013 03:45:26";
-
-class DataReductionProxyCompressionStatsTest : public testing::Test {
- protected:
- DataReductionProxyCompressionStatsTest()
- : task_environment_(
- base::test::SingleThreadTaskEnvironment::MainThreadType::UI) {
- EXPECT_TRUE(base::Time::FromString(kLastUpdateTime, &now_));
- }
-
- void SetUp() override {
- drp_test_context_ = DataReductionProxyTestContext::Builder().Build();
-
- compression_stats_ = std::make_unique<DataReductionProxyCompressionStats>(
- data_reduction_proxy_service(), pref_service(), base::TimeDelta());
- }
-
- void ResetCompressionStatsWithDelay(const base::TimeDelta& delay) {
- compression_stats_ = std::make_unique<DataReductionProxyCompressionStats>(
- data_reduction_proxy_service(), pref_service(), delay);
- }
-
- base::Time FakeNow() const {
- return now_ + now_delta_;
- }
-
- void SetFakeTimeDeltaInHours(int hours) { now_delta_ = base::Hours(hours); }
-
- void AddFakeTimeDeltaInHours(int hours) { now_delta_ += base::Hours(hours); }
-
- void SetUpPrefs() {
- CreatePrefList(prefs::kDailyHttpOriginalContentLength);
- CreatePrefList(prefs::kDailyHttpReceivedContentLength);
-
- const int64_t kOriginalLength = 150;
- const int64_t kReceivedLength = 100;
-
- compression_stats_->SetInt64(
- prefs::kHttpOriginalContentLength, kOriginalLength);
- compression_stats_->SetInt64(
- prefs::kHttpReceivedContentLength, kReceivedLength);
-
- base::ListValue* original_daily_content_length_list =
- compression_stats_->GetList(prefs::kDailyHttpOriginalContentLength);
- base::ListValue* received_daily_content_length_list =
- compression_stats_->GetList(prefs::kDailyHttpReceivedContentLength);
-
- for (size_t i = 0; i < kNumDaysInHistory; ++i) {
- original_daily_content_length_list->Set(
- i, std::make_unique<base::Value>(base::NumberToString(i)));
- }
-
- received_daily_content_length_list->ClearList();
- for (size_t i = 0; i < kNumDaysInHistory / 2; ++i) {
- received_daily_content_length_list->Append(base::NumberToString(i));
- }
- }
-
- // Create daily pref list of |kNumDaysInHistory| zero values.
- void CreatePrefList(const char* pref) {
- base::Value* update = compression_stats_->GetList(pref);
- update->ClearList();
- for (size_t i = 0; i < kNumDaysInHistory; ++i) {
- update->Append(base::Value(base::NumberToString(0)));
- }
- }
-
- // Verify the pref list values in |pref_service_| are equal to those in
- // |simple_pref_service| for |pref|.
- void VerifyPrefListWasWritten(const char* pref) {
- const base::ListValue* delayed_list = compression_stats_->GetList(pref);
- const base::ListValue* written_list = pref_service()->GetList(pref);
- ASSERT_EQ(delayed_list->GetList().size(), written_list->GetList().size());
- size_t count = delayed_list->GetList().size();
-
- for (size_t i = 0; i < count; ++i) {
- EXPECT_EQ(GetListPrefInt64Value(*delayed_list, i),
- GetListPrefInt64Value(*written_list, i));
- }
- }
-
- // Verify the pref value in |pref_service_| are equal to that in
- // |simple_pref_service|.
- void VerifyPrefWasWritten(const char* pref) {
- int64_t delayed_pref = compression_stats_->GetInt64(pref);
- int64_t written_pref = pref_service()->GetInt64(pref);
- EXPECT_EQ(delayed_pref, written_pref);
- }
-
- // Verify the pref values in |dict| are equal to that in |compression_stats_|.
- void VerifyPrefs(base::DictionaryValue* dict) {
- std::u16string dict_pref_string;
- int64_t dict_pref;
- int64_t service_pref;
-
- dict->GetString("historic_original_content_length", &dict_pref_string);
- base::StringToInt64(dict_pref_string, &dict_pref);
- service_pref =
- compression_stats_->GetInt64(prefs::kHttpOriginalContentLength);
- EXPECT_EQ(service_pref, dict_pref);
-
- dict->GetString("historic_received_content_length", &dict_pref_string);
- base::StringToInt64(dict_pref_string, &dict_pref);
- service_pref =
- compression_stats_->GetInt64(prefs::kHttpReceivedContentLength);
- EXPECT_EQ(service_pref, dict_pref);
- }
-
- // Verify the pref list values are equal to the given values.
- // If the count of values is less than kNumDaysInHistory, zeros are assumed
- // at the beginning.
- void VerifyPrefList(const char* pref,
- const int64_t* values,
- size_t count,
- size_t num_days_in_history) {
- ASSERT_GE(num_days_in_history, count);
- base::ListValue* update = compression_stats_->GetList(pref);
- ASSERT_EQ(num_days_in_history, update->GetList().size())
- << "Pref: " << pref;
-
- for (size_t i = 0; i < count; ++i) {
- EXPECT_EQ(values[i],
- GetListPrefInt64Value(*update, num_days_in_history - count + i))
- << pref << "; index=" << (num_days_in_history - count + i);
- }
- for (size_t i = 0; i < num_days_in_history - count; ++i) {
- EXPECT_EQ(0, GetListPrefInt64Value(*update, i)) << "index=" << i;
- }
- }
-
- // Verify that the pref value is equal to given value.
- void VerifyPrefInt64(const char* pref, const int64_t value) {
- EXPECT_EQ(value, compression_stats_->GetInt64(pref));
- }
-
- // Verify all daily data saving pref list values.
- void VerifyDailyDataSavingContentLengthPrefLists(
- const int64_t* original_values,
- size_t original_count,
- const int64_t* received_values,
- size_t received_count,
- size_t num_days_in_history) {
- VerifyPrefList(data_reduction_proxy::prefs::kDailyHttpOriginalContentLength,
- original_values, original_count, num_days_in_history);
- VerifyPrefList(data_reduction_proxy::prefs::kDailyHttpReceivedContentLength,
- received_values, received_count, num_days_in_history);
- }
-
- int64_t GetInt64(const char* pref_path) {
- return compression_stats_->GetInt64(pref_path);
- }
-
- void SetInt64(const char* pref_path, int64_t pref_value) {
- compression_stats_->SetInt64(pref_path, pref_value);
- }
-
- std::string NormalizeHostname(const std::string& hostname) {
- return DataReductionProxyCompressionStats::NormalizeHostname(hostname);
- }
-
- void RecordContentLengthPrefs(int64_t received_content_length,
- int64_t original_content_length,
- bool with_data_reduction_proxy_enabled,
- const std::string& mime_type,
- base::Time now) {
- compression_stats_->RecordRequestSizePrefs(
- received_content_length, original_content_length,
- with_data_reduction_proxy_enabled, mime_type, now);
- }
-
- void RecordContentLengthPrefs(int64_t received_content_length,
- int64_t original_content_length,
- bool with_data_reduction_proxy_enabled,
- base::Time now) {
- RecordContentLengthPrefs(received_content_length, original_content_length,
- with_data_reduction_proxy_enabled,
- "application/octet-stream", now);
- }
-
- void RecordDataUsage(const std::string& data_usage_host,
- int64_t data_used,
- int64_t original_size,
- const base::Time& time) {
- compression_stats_->RecordDataUseByHost(data_usage_host, data_used,
- original_size, time);
- }
-
- void GetHistoricalDataUsage(HistoricalDataUsageCallback on_load_data_usage,
- const base::Time& now) {
- compression_stats_->GetHistoricalDataUsageImpl(
- std::move(on_load_data_usage), now);
- }
-
- void LoadHistoricalDataUsage(HistoricalDataUsageCallback on_load_data_usage) {
- compression_stats_->service_->LoadHistoricalDataUsage(
- std::move(on_load_data_usage));
- }
-
- void DeleteHistoricalDataUsage() {
- compression_stats_->DeleteHistoricalDataUsage();
- }
-
- void ClearDataSavingStatistics() {
- compression_stats_->ClearDataSavingStatistics(
- DataReductionProxySavingsClearedReason::
- USER_ACTION_DELETE_BROWSING_HISTORY);
- }
-
- void DeleteBrowsingHistory(const base::Time& start, const base::Time& end) {
- compression_stats_->DeleteBrowsingHistory(start, end);
- }
-
- void EnableDataUsageReporting() {
- pref_service()->SetBoolean(prefs::kDataUsageReportingEnabled, true);
- }
-
- void DisableDataUsageReporting() {
- pref_service()->SetBoolean(prefs::kDataUsageReportingEnabled, false);
- }
-
- DataReductionProxyCompressionStats* compression_stats() {
- return compression_stats_.get();
- }
-
- void ForceWritePrefs() { compression_stats_->WritePrefs(); }
-
- bool IsDelayedWriteTimerRunning() const {
- return compression_stats_->pref_writer_timer_.IsRunning();
- }
-
- TestingPrefServiceSimple* pref_service() {
- return drp_test_context_->pref_service();
- }
-
- DataReductionProxyService* data_reduction_proxy_service() {
- return drp_test_context_->data_reduction_proxy_service();
- }
-
- bool IsDataReductionProxyEnabled() {
- return drp_test_context_->IsDataReductionProxyEnabled();
- }
-
- void InitializeWeeklyAggregateDataUse(const base::Time& now) {
- compression_stats_->InitializeWeeklyAggregateDataUse(now);
- }
-
- void RecordWeeklyAggregateDataUse(
- const base::Time& now,
- int32_t received_kb,
- bool is_user_request,
- data_use_measurement::DataUseUserData::DataUseContentType content_type,
- int32_t service_hash_code) {
- compression_stats_->RecordWeeklyAggregateDataUse(
- now, received_kb, is_user_request, content_type, service_hash_code);
- }
-
- void VerifyDictionaryPref(const std::string& pref,
- int key,
- int expected_value) const {
- const base::DictionaryValue* dict =
- compression_stats_->pref_service_->GetDictionary(pref);
- EXPECT_EQ(expected_value != 0, dict->HasKey(base::NumberToString(key)));
- if (expected_value) {
- EXPECT_EQ(expected_value,
- dict->FindKey(base::NumberToString(key))->GetInt());
- }
- }
-
- private:
- base::test::SingleThreadTaskEnvironment task_environment_;
- std::unique_ptr<DataReductionProxyTestContext> drp_test_context_;
- std::unique_ptr<DataReductionProxyCompressionStats> compression_stats_;
- base::Time now_;
- base::TimeDelta now_delta_;
-};
-
-TEST_F(DataReductionProxyCompressionStatsTest, WritePrefsDirect) {
- SetUpPrefs();
-
- VerifyPrefWasWritten(prefs::kHttpOriginalContentLength);
- VerifyPrefWasWritten(prefs::kHttpReceivedContentLength);
- VerifyPrefListWasWritten(prefs::kDailyHttpOriginalContentLength);
- VerifyPrefListWasWritten(prefs::kDailyHttpReceivedContentLength);
-}
-
-TEST_F(DataReductionProxyCompressionStatsTest, WritePrefsDelayed) {
- ResetCompressionStatsWithDelay(base::Minutes(kWriteDelayMinutes));
-
- EXPECT_EQ(0, pref_service()->GetInt64(prefs::kHttpOriginalContentLength));
- EXPECT_EQ(0, pref_service()->GetInt64(prefs::kHttpReceivedContentLength));
- EXPECT_FALSE(IsDelayedWriteTimerRunning());
-
- SetUpPrefs();
- EXPECT_TRUE(IsDelayedWriteTimerRunning());
- ForceWritePrefs();
-
- VerifyPrefWasWritten(prefs::kHttpOriginalContentLength);
- VerifyPrefWasWritten(prefs::kHttpReceivedContentLength);
- VerifyPrefListWasWritten(prefs::kDailyHttpOriginalContentLength);
- VerifyPrefListWasWritten(prefs::kDailyHttpReceivedContentLength);
-}
-
-TEST_F(DataReductionProxyCompressionStatsTest, StatsRestoredOnOnRestart) {
- base::Value list_value(base::Value::Type::LIST);
- list_value.Append(base::Value(base::NumberToString(1234)));
- pref_service()->Set(prefs::kDailyHttpOriginalContentLength, list_value);
-
- ResetCompressionStatsWithDelay(base::Minutes(kWriteDelayMinutes));
-
- const base::Value* value =
- pref_service()->GetList(prefs::kDailyHttpOriginalContentLength);
- const std::string* string_value = value->GetList()[0].GetIfString();
- EXPECT_EQ("1234", *string_value);
-}
-
-TEST_F(DataReductionProxyCompressionStatsTest, TotalLengths) {
- const int64_t kOriginalLength = 200;
- const int64_t kReceivedLength = 100;
-
- compression_stats()->RecordDataUseWithMimeType(
- kReceivedLength, kOriginalLength, IsDataReductionProxyEnabled(),
- std::string(), true, data_use_measurement::DataUseUserData::OTHER, 0);
-
- EXPECT_EQ(kReceivedLength,
- GetInt64(data_reduction_proxy::prefs::kHttpReceivedContentLength));
- EXPECT_FALSE(IsDataReductionProxyEnabled());
- EXPECT_EQ(kOriginalLength,
- GetInt64(data_reduction_proxy::prefs::kHttpOriginalContentLength));
-
- // Record the same numbers again, and total lengths should be doubled.
- compression_stats()->RecordDataUseWithMimeType(
- kReceivedLength, kOriginalLength, IsDataReductionProxyEnabled(),
- std::string(), true, data_use_measurement::DataUseUserData::OTHER, 0);
-
- EXPECT_EQ(kReceivedLength * 2,
- GetInt64(data_reduction_proxy::prefs::kHttpReceivedContentLength));
- EXPECT_FALSE(IsDataReductionProxyEnabled());
- EXPECT_EQ(kOriginalLength * 2,
- GetInt64(data_reduction_proxy::prefs::kHttpOriginalContentLength));
-}
-
-TEST_F(DataReductionProxyCompressionStatsTest, OneResponse) {
- const int64_t kOriginalLength = 200;
- const int64_t kReceivedLength = 100;
- int64_t original[] = {kOriginalLength};
- int64_t received[] = {kReceivedLength};
-
- RecordContentLengthPrefs(kReceivedLength, kOriginalLength, true, FakeNow());
-
- VerifyDailyDataSavingContentLengthPrefLists(original, 1, received, 1,
- kNumDaysInHistory);
-}
-
-TEST_F(DataReductionProxyCompressionStatsTest, MultipleResponses) {
- const int64_t kOriginalLength = 150;
- const int64_t kReceivedLength = 100;
- int64_t original[] = {kOriginalLength};
- int64_t received[] = {kReceivedLength};
- RecordContentLengthPrefs(kReceivedLength, kOriginalLength, false, FakeNow());
- VerifyDailyDataSavingContentLengthPrefLists(original, 1, received, 1,
- kNumDaysInHistory);
-
- RecordContentLengthPrefs(kReceivedLength, kOriginalLength, true, FakeNow());
- original[0] += kOriginalLength;
- received[0] += kReceivedLength;
- VerifyDailyDataSavingContentLengthPrefLists(original, 1, received, 1,
- kNumDaysInHistory);
-
- RecordContentLengthPrefs(kReceivedLength, kOriginalLength, true, FakeNow());
- original[0] += kOriginalLength;
- received[0] += kReceivedLength;
- VerifyDailyDataSavingContentLengthPrefLists(original, 1, received, 1,
- kNumDaysInHistory);
-
- RecordContentLengthPrefs(kReceivedLength, kOriginalLength, true, FakeNow());
- original[0] += kOriginalLength;
- received[0] += kReceivedLength;
- VerifyDailyDataSavingContentLengthPrefLists(original, 1, received, 1,
- kNumDaysInHistory);
-
- RecordContentLengthPrefs(kReceivedLength, kOriginalLength, false, FakeNow());
- original[0] += kOriginalLength;
- received[0] += kReceivedLength;
- VerifyDailyDataSavingContentLengthPrefLists(original, 1, received, 1,
- kNumDaysInHistory);
-}
-
-TEST_F(DataReductionProxyCompressionStatsTest, ForwardOneDay) {
- const int64_t kOriginalLength = 200;
- const int64_t kReceivedLength = 100;
-
- RecordContentLengthPrefs(kReceivedLength, kOriginalLength, true, FakeNow());
-
- // Forward one day.
- SetFakeTimeDeltaInHours(24);
-
- // Proxy not enabled. Not via proxy.
- RecordContentLengthPrefs(kReceivedLength, kOriginalLength, false, FakeNow());
-
- int64_t original[] = {kOriginalLength, kOriginalLength};
- int64_t received[] = {kReceivedLength, kReceivedLength};
- VerifyDailyDataSavingContentLengthPrefLists(original, 2, received, 2,
- kNumDaysInHistory);
-
- // Proxy enabled. Not via proxy.
- RecordContentLengthPrefs(kReceivedLength, kOriginalLength, true, FakeNow());
- original[1] += kOriginalLength;
- received[1] += kReceivedLength;
- VerifyDailyDataSavingContentLengthPrefLists(original, 2, received, 2,
- kNumDaysInHistory);
-
- // Proxy enabled and via proxy.
- RecordContentLengthPrefs(kReceivedLength, kOriginalLength, true, FakeNow());
- original[1] += kOriginalLength;
- received[1] += kReceivedLength;
- VerifyDailyDataSavingContentLengthPrefLists(original, 2, received, 2,
- kNumDaysInHistory);
-
- // Proxy enabled and via proxy, with content length greater than max int32_t.
- const int64_t kBigOriginalLength = 0x300000000LL; // 12G.
- const int64_t kBigReceivedLength = 0x200000000LL; // 8G.
- RecordContentLengthPrefs(kBigReceivedLength, kBigOriginalLength, true,
- FakeNow());
- original[1] += kBigOriginalLength;
- received[1] += kBigReceivedLength;
- VerifyDailyDataSavingContentLengthPrefLists(original, 2, received, 2,
- kNumDaysInHistory);
-}
-
-TEST_F(DataReductionProxyCompressionStatsTest, PartialDayTimeChange) {
- const int64_t kOriginalLength = 200;
- const int64_t kReceivedLength = 100;
- int64_t original[] = {0, kOriginalLength};
- int64_t received[] = {0, kReceivedLength};
-
- RecordContentLengthPrefs(kReceivedLength, kOriginalLength, true, FakeNow());
- VerifyDailyDataSavingContentLengthPrefLists(original, 2, received, 2,
- kNumDaysInHistory);
-
- // Forward 10 hours, stay in the same day.
- // See kLastUpdateTime: "Now" in test is 03:45am.
- SetFakeTimeDeltaInHours(10);
- RecordContentLengthPrefs(kReceivedLength, kOriginalLength, true, FakeNow());
- original[1] += kOriginalLength;
- received[1] += kReceivedLength;
- VerifyDailyDataSavingContentLengthPrefLists(original, 2, received, 2,
- kNumDaysInHistory);
-
- // Forward 11 more hours, comes to tomorrow.
- AddFakeTimeDeltaInHours(11);
- RecordContentLengthPrefs(kReceivedLength, kOriginalLength, true, FakeNow());
- int64_t original2[] = {kOriginalLength * 2, kOriginalLength};
- int64_t received2[] = {kReceivedLength * 2, kReceivedLength};
- VerifyDailyDataSavingContentLengthPrefLists(original2, 2, received2, 2,
- kNumDaysInHistory);
-}
-
-TEST_F(DataReductionProxyCompressionStatsTest, BackwardAndForwardOneDay) {
- base::HistogramTester histogram_tester;
- const int64_t kOriginalLength = 200;
- const int64_t kReceivedLength = 100;
- int64_t original[] = {kOriginalLength};
- int64_t received[] = {kReceivedLength};
-
- RecordContentLengthPrefs(kReceivedLength, kOriginalLength, true, FakeNow());
-
- // Backward one day, expect no count.
- SetFakeTimeDeltaInHours(-24);
- RecordContentLengthPrefs(kReceivedLength, kOriginalLength, true, FakeNow());
- original[0] += kOriginalLength;
- received[0] += kReceivedLength;
- VerifyDailyDataSavingContentLengthPrefLists(original, 1, received, 1,
- kNumDaysInHistory);
- histogram_tester.ExpectTotalCount("DataReductionProxy.SavingsCleared.Reason",
- 0);
-
- // Then forward one day, expect no count.
- AddFakeTimeDeltaInHours(24);
- RecordContentLengthPrefs(kReceivedLength, kOriginalLength, true, FakeNow());
- int64_t original2[] = {kOriginalLength * 2, kOriginalLength};
- int64_t received2[] = {kReceivedLength * 2, kReceivedLength};
- VerifyDailyDataSavingContentLengthPrefLists(original2, 2, received2, 2,
- kNumDaysInHistory);
- histogram_tester.ExpectTotalCount("DataReductionProxy.SavingsCleared.Reason",
- 0);
-}
-
-TEST_F(DataReductionProxyCompressionStatsTest, BackwardTwoDays) {
- base::HistogramTester histogram_tester;
- const int64_t kOriginalLength = 200;
- const int64_t kReceivedLength = 100;
- int64_t original[] = {kOriginalLength};
- int64_t received[] = {kReceivedLength};
-
- RecordContentLengthPrefs(kReceivedLength, kOriginalLength, true, FakeNow());
-
- // Backward two days, expect SYSTEM_CLOCK_MOVED_BACK.
- SetFakeTimeDeltaInHours(-2 * 24);
- RecordContentLengthPrefs(kReceivedLength, kOriginalLength, true, FakeNow());
- VerifyDailyDataSavingContentLengthPrefLists(original, 1, received, 1,
- kNumDaysInHistory);
- histogram_tester.ExpectUniqueSample(
- "DataReductionProxy.SavingsCleared.Reason",
- DataReductionProxySavingsClearedReason::SYSTEM_CLOCK_MOVED_BACK, 1);
-
- // Backward another two days, expect SYSTEM_CLOCK_MOVED_BACK.
- SetFakeTimeDeltaInHours(-4 * 24);
- RecordContentLengthPrefs(kReceivedLength, kOriginalLength, true, FakeNow());
- histogram_tester.ExpectUniqueSample(
- "DataReductionProxy.SavingsCleared.Reason",
- DataReductionProxySavingsClearedReason::SYSTEM_CLOCK_MOVED_BACK, 2);
-
- // Forward 2 days, expect no change.
- AddFakeTimeDeltaInHours(2 * 24);
- RecordContentLengthPrefs(kReceivedLength, kOriginalLength, true, FakeNow());
- histogram_tester.ExpectUniqueSample(
- "DataReductionProxy.SavingsCleared.Reason",
- DataReductionProxySavingsClearedReason::SYSTEM_CLOCK_MOVED_BACK, 2);
-}
-
-TEST_F(DataReductionProxyCompressionStatsTest, NormalizeHostname) {
- EXPECT_EQ("www.foo.com", NormalizeHostname("http://www.foo.com"));
- EXPECT_EQ("foo.com", NormalizeHostname("https://foo.com"));
- EXPECT_EQ("bar.co.uk", NormalizeHostname("http://bar.co.uk"));
- EXPECT_EQ("http.www.co.in", NormalizeHostname("http://http.www.co.in"));
-}
-
-TEST_F(DataReductionProxyCompressionStatsTest, RecordDataUsageSingleSite) {
- EnableDataUsageReporting();
- base::RunLoop().RunUntilIdle();
-
- base::Time now = base::Time::Now();
- RecordDataUsage("https://www.foo.com", 1000, 1250, now);
-
- auto expected_data_usage =
- std::make_unique<std::vector<data_reduction_proxy::DataUsageBucket>>(
- kNumExpectedBuckets);
- data_reduction_proxy::PerConnectionDataUsage* connection_usage =
- expected_data_usage->at(kNumExpectedBuckets - 1).add_connection_usage();
- data_reduction_proxy::PerSiteDataUsage* site_usage =
- connection_usage->add_site_usage();
- site_usage->set_hostname("www.foo.com");
- site_usage->set_data_used(1000);
- site_usage->set_original_size(1250);
-
- DataUsageLoadVerifier verifier(std::move(expected_data_usage));
-
- GetHistoricalDataUsage(base::BindOnce(&DataUsageLoadVerifier::OnLoadDataUsage,
- base::Unretained(&verifier)),
- now);
- base::RunLoop().RunUntilIdle();
-}
-
-TEST_F(DataReductionProxyCompressionStatsTest, DisableDataUsageRecording) {
- EnableDataUsageReporting();
- base::RunLoop().RunUntilIdle();
-
- base::Time now = base::Time::Now();
- RecordDataUsage("https://www.foo.com", 1000, 1250, now);
-
- DisableDataUsageReporting();
- base::RunLoop().RunUntilIdle();
-
-#if !defined(OS_ANDROID)
- // Data usage on disk must be deleted.
- auto expected_data_usage1 =
- std::make_unique<std::vector<data_reduction_proxy::DataUsageBucket>>(
- kNumExpectedBuckets);
- DataUsageLoadVerifier verifier1(std::move(expected_data_usage1));
- LoadHistoricalDataUsage(base::BindOnce(
- &DataUsageLoadVerifier::OnLoadDataUsage, base::Unretained(&verifier1)));
-
- // Public API must return an empty array.
- auto expected_data_usage2 =
- std::make_unique<std::vector<data_reduction_proxy::DataUsageBucket>>();
- DataUsageLoadVerifier verifier2(std::move(expected_data_usage2));
- GetHistoricalDataUsage(base::BindOnce(&DataUsageLoadVerifier::OnLoadDataUsage,
- base::Unretained(&verifier2)),
- now);
-#else
- // For Android don't delete data usage.
- auto expected_data_usage =
- std::make_unique<std::vector<data_reduction_proxy::DataUsageBucket>>(
- kNumExpectedBuckets);
- data_reduction_proxy::PerConnectionDataUsage* connection_usage =
- expected_data_usage->at(kNumExpectedBuckets - 1).add_connection_usage();
- data_reduction_proxy::PerSiteDataUsage* site_usage =
- connection_usage->add_site_usage();
- site_usage->set_hostname("www.foo.com");
- site_usage->set_data_used(1000);
- site_usage->set_original_size(1250);
-
- DataUsageLoadVerifier verifier(std::move(expected_data_usage));
-
- GetHistoricalDataUsage(base::BindOnce(&DataUsageLoadVerifier::OnLoadDataUsage,
- base::Unretained(&verifier)),
- now);
-#endif
-
- base::RunLoop().RunUntilIdle();
-}
-
-TEST_F(DataReductionProxyCompressionStatsTest, RecordDataUsageMultipleSites) {
- EnableDataUsageReporting();
- base::RunLoop().RunUntilIdle();
-
- base::Time now = base::Time::Now();
- RecordDataUsage("https://www.foo.com", 1000, 1250, now);
- RecordDataUsage("https://bar.com", 1001, 1251, now);
- RecordDataUsage("http://foobar.com", 1002, 1252, now);
-
- auto expected_data_usage =
- std::make_unique<std::vector<data_reduction_proxy::DataUsageBucket>>(
- kNumExpectedBuckets);
- data_reduction_proxy::PerConnectionDataUsage* connection_usage =
- expected_data_usage->at(kNumExpectedBuckets - 1).add_connection_usage();
- data_reduction_proxy::PerSiteDataUsage* site_usage =
- connection_usage->add_site_usage();
- site_usage->set_hostname("www.foo.com");
- site_usage->set_data_used(1000);
- site_usage->set_original_size(1250);
-
- site_usage = connection_usage->add_site_usage();
- site_usage->set_hostname("bar.com");
- site_usage->set_data_used(1001);
- site_usage->set_original_size(1251);
-
- site_usage = connection_usage->add_site_usage();
- site_usage->set_hostname("foobar.com");
- site_usage->set_data_used(1002);
- site_usage->set_original_size(1252);
-
- DataUsageLoadVerifier verifier(std::move(expected_data_usage));
-
- GetHistoricalDataUsage(base::BindOnce(&DataUsageLoadVerifier::OnLoadDataUsage,
- base::Unretained(&verifier)),
- now);
- base::RunLoop().RunUntilIdle();
-}
-
-TEST_F(DataReductionProxyCompressionStatsTest,
- RecordDataUsageConsecutiveBuckets) {
- EnableDataUsageReporting();
- base::RunLoop().RunUntilIdle();
-
- base::Time now = base::Time::Now();
- base::Time fifteen_mins_ago = now - base::Minutes(15);
-
- RecordDataUsage("https://www.foo.com", 1000, 1250, fifteen_mins_ago);
-
- RecordDataUsage("https://bar.com", 1001, 1251, now);
-
- auto expected_data_usage =
- std::make_unique<std::vector<data_reduction_proxy::DataUsageBucket>>(
- kNumExpectedBuckets);
- data_reduction_proxy::PerConnectionDataUsage* connection_usage =
- expected_data_usage->at(kNumExpectedBuckets - 2).add_connection_usage();
- data_reduction_proxy::PerSiteDataUsage* site_usage =
- connection_usage->add_site_usage();
- site_usage->set_hostname("www.foo.com");
- site_usage->set_data_used(1000);
- site_usage->set_original_size(1250);
-
- connection_usage =
- expected_data_usage->at(kNumExpectedBuckets - 1).add_connection_usage();
- site_usage = connection_usage->add_site_usage();
- site_usage->set_hostname("bar.com");
- site_usage->set_data_used(1001);
- site_usage->set_original_size(1251);
-
- DataUsageLoadVerifier verifier(std::move(expected_data_usage));
-
- GetHistoricalDataUsage(base::BindOnce(&DataUsageLoadVerifier::OnLoadDataUsage,
- base::Unretained(&verifier)),
- now);
- base::RunLoop().RunUntilIdle();
-}
-
-// Test that the last entry in data usage bucket vector is for the current
-// interval even when current interval does not have any data usage.
-TEST_F(DataReductionProxyCompressionStatsTest,
- RecordDataUsageEmptyCurrentInterval) {
- EnableDataUsageReporting();
- base::RunLoop().RunUntilIdle();
-
- base::Time now = base::Time::Now();
- base::Time fifteen_mins_ago = now - base::Minutes(15);
-
- RecordDataUsage("https://www.foo.com", 1000, 1250, fifteen_mins_ago);
-
- auto expected_data_usage =
- std::make_unique<std::vector<data_reduction_proxy::DataUsageBucket>>(
- kNumExpectedBuckets);
- data_reduction_proxy::PerConnectionDataUsage* connection_usage =
- expected_data_usage->at(kNumExpectedBuckets - 2).add_connection_usage();
- data_reduction_proxy::PerSiteDataUsage* site_usage =
- connection_usage->add_site_usage();
- site_usage->set_hostname("www.foo.com");
- site_usage->set_data_used(1000);
- site_usage->set_original_size(1250);
-
- DataUsageLoadVerifier verifier(std::move(expected_data_usage));
-
- GetHistoricalDataUsage(base::BindOnce(&DataUsageLoadVerifier::OnLoadDataUsage,
- base::Unretained(&verifier)),
- now);
- base::RunLoop().RunUntilIdle();
-}
-
-TEST_F(DataReductionProxyCompressionStatsTest, DeleteHistoricalDataUsage) {
- EnableDataUsageReporting();
- base::RunLoop().RunUntilIdle();
-
- base::Time now = base::Time::Now();
- base::Time fifteen_mins_ago = now - base::Minutes(15);
- // Fake record to be from 15 minutes ago so that it is flushed to storage.
- RecordDataUsage("https://www.bar.com", 900, 1100, fifteen_mins_ago);
-
- RecordDataUsage("https://www.foo.com", 1000, 1250, now);
-
- DeleteHistoricalDataUsage();
- base::RunLoop().RunUntilIdle();
-
- auto expected_data_usage =
- std::make_unique<std::vector<data_reduction_proxy::DataUsageBucket>>(
- kNumExpectedBuckets);
- DataUsageLoadVerifier verifier(std::move(expected_data_usage));
-
- GetHistoricalDataUsage(base::BindOnce(&DataUsageLoadVerifier::OnLoadDataUsage,
- base::Unretained(&verifier)),
- now);
- base::RunLoop().RunUntilIdle();
-}
-
-TEST_F(DataReductionProxyCompressionStatsTest, DeleteBrowsingHistory) {
- EnableDataUsageReporting();
- base::RunLoop().RunUntilIdle();
-
- base::Time now = base::Time::Now();
- base::Time fifteen_mins_ago = now - base::Minutes(15);
-
- // Fake record to be from 15 minutes ago so that it is flushed to storage.
- RecordDataUsage("https://www.bar.com", 900, 1100, fifteen_mins_ago);
-
- // This data usage will be in kept in memory.
- RecordDataUsage("https://www.foo.com", 1000, 1250, now);
-
- // This should only delete in-memory usage.
- DeleteBrowsingHistory(now, now);
- base::RunLoop().RunUntilIdle();
-
- ASSERT_TRUE(compression_stats()->DataUsageMapForTesting().empty());
-
- auto expected_data_usage =
- std::make_unique<std::vector<data_reduction_proxy::DataUsageBucket>>(
- kNumExpectedBuckets);
- data_reduction_proxy::PerConnectionDataUsage* connection_usage =
- expected_data_usage->at(kNumExpectedBuckets - 1).add_connection_usage();
- data_reduction_proxy::PerSiteDataUsage* site_usage =
- connection_usage->add_site_usage();
- site_usage->set_hostname("www.bar.com");
- site_usage->set_data_used(900);
- site_usage->set_original_size(1100);
- DataUsageLoadVerifier verifier1(std::move(expected_data_usage));
-
- LoadHistoricalDataUsage(base::BindOnce(
- &DataUsageLoadVerifier::OnLoadDataUsage, base::Unretained(&verifier1)));
- base::RunLoop().RunUntilIdle();
-
- // This should delete in-storage usage as well.
- DeleteBrowsingHistory(fifteen_mins_ago, now);
- base::RunLoop().RunUntilIdle();
-
- expected_data_usage =
- std::make_unique<std::vector<data_reduction_proxy::DataUsageBucket>>(
- kNumExpectedBuckets);
- DataUsageLoadVerifier verifier2(std::move(expected_data_usage));
- LoadHistoricalDataUsage(base::BindOnce(
- &DataUsageLoadVerifier::OnLoadDataUsage, base::Unretained(&verifier2)));
- base::RunLoop().RunUntilIdle();
-}
-
-TEST_F(DataReductionProxyCompressionStatsTest, ClearDataSavingStatistics) {
- EnableDataUsageReporting();
- base::RunLoop().RunUntilIdle();
-
- base::Time now = base::Time::Now();
- base::Time fifteen_mins_ago = now - base::Minutes(15);
- // Fake record to be from 15 minutes ago so that it is flushed to storage.
- RecordDataUsage("https://www.bar.com", 900, 1100, fifteen_mins_ago);
-
- RecordDataUsage("https://www.foo.com", 1000, 1250, now);
-
- const int64_t kOriginalLength = 200;
- const int64_t kReceivedLength = 100;
- int64_t original[] = {kOriginalLength};
- int64_t received[] = {kReceivedLength};
-
- RecordContentLengthPrefs(kReceivedLength, kOriginalLength, true, FakeNow());
-
- VerifyDailyDataSavingContentLengthPrefLists(original, 1, received, 1,
- kNumDaysInHistory);
-
- ClearDataSavingStatistics();
- base::RunLoop().RunUntilIdle();
-
- auto expected_data_usage =
- std::make_unique<std::vector<data_reduction_proxy::DataUsageBucket>>(
- kNumExpectedBuckets);
- DataUsageLoadVerifier verifier(std::move(expected_data_usage));
-
- GetHistoricalDataUsage(base::BindOnce(&DataUsageLoadVerifier::OnLoadDataUsage,
- base::Unretained(&verifier)),
- now);
- base::RunLoop().RunUntilIdle();
-
- VerifyDailyDataSavingContentLengthPrefLists(nullptr, 0, nullptr, 0, 0);
-}
-
-// Aggregate metrics recording was disabled on Android x86 in crbug.com/865373.
-#if defined(OS_ANDROID) && defined(ARCH_CPU_X86)
-#define MAYBE_WeeklyAggregateDataUse DISABLED_WeeklyAggregateDataUse
-#else
-#define MAYBE_WeeklyAggregateDataUse WeeklyAggregateDataUse
-#endif
-TEST_F(DataReductionProxyCompressionStatsTest, MAYBE_WeeklyAggregateDataUse) {
- const int32_t kDataUseKB = 100;
- base::HistogramTester histogram_tester;
-
- InitializeWeeklyAggregateDataUse(base::Time::Now());
- histogram_tester.ExpectTotalCount(
- "DataReductionProxy.ThisWeekAggregateKB.Services.Downstream.Background",
- 0);
- histogram_tester.ExpectTotalCount(
- "DataReductionProxy.ThisWeekAggregateKB.Services.Downstream.Foreground",
- 0);
- histogram_tester.ExpectTotalCount(
- "DataReductionProxy.LastWeekAggregateKB.Services.Downstream.Background",
- 0);
- histogram_tester.ExpectTotalCount(
- "DataReductionProxy.LastWeekAggregateKB.Services.Downstream.Foreground",
- 0);
- histogram_tester.ExpectTotalCount(
- "DataReductionProxy.ThisWeekAggregateKB.UserTraffic.Downstream."
- "ContentType",
- 0);
- histogram_tester.ExpectTotalCount(
- "DataReductionProxy.LastWeekAggregateKB.UserTraffic.Downstream."
- "ContentType",
- 0);
-
- RecordWeeklyAggregateDataUse(
- base::Time::Now(), kDataUseKB, true,
- data_use_measurement::DataUseUserData::MAIN_FRAME_HTML, 0);
- VerifyDictionaryPref(prefs::kThisWeekUserTrafficContentTypeDownstreamKB,
- data_use_measurement::DataUseUserData::MAIN_FRAME_HTML,
- kDataUseKB);
-
- histogram_tester.ExpectTotalCount(
- "DataReductionProxy.ThisWeekAggregateKB.UserTraffic.Downstream."
- "ContentType",
- 0);
-
- InitializeWeeklyAggregateDataUse(base::Time::Now());
- histogram_tester.ExpectBucketCount(
- "DataReductionProxy.ThisWeekAggregateKB.UserTraffic.Downstream."
- "ContentType",
- data_use_measurement::DataUseUserData::MAIN_FRAME_HTML, kDataUseKB);
- histogram_tester.ExpectBucketCount(
- "DataReductionProxy.LastWeekAggregateKB.UserTraffic.Downstream."
- "ContentType",
- data_use_measurement::DataUseUserData::MAIN_FRAME_HTML, 0);
-}
-
-// Aggregate metrics recording was disabled on Android x86 in crbug.com/865373.
-#if defined(OS_ANDROID) && defined(ARCH_CPU_X86)
-#define MAYBE_AggregateDataUseForwardWeeks DISABLED_AggregateDataUseForwardWeeks
-#else
-#define MAYBE_AggregateDataUseForwardWeeks AggregateDataUseForwardWeeks
-#endif
-TEST_F(DataReductionProxyCompressionStatsTest,
- MAYBE_AggregateDataUseForwardWeeks) {
- const int32_t kMainFrameKB = 100;
- const int32_t kNonMainFrameKB = 101;
- base::HistogramTester histogram_tester;
-
- base::Time fake_time_now = base::Time::Now();
-
- InitializeWeeklyAggregateDataUse(fake_time_now);
- histogram_tester.ExpectTotalCount(
- "DataReductionProxy.ThisWeekAggregateKB.UserTraffic.Downstream."
- "ContentType",
- 0);
- histogram_tester.ExpectTotalCount(
- "DataReductionProxy.LastWeekAggregateKB.UserTraffic.Downstream."
- "ContentType",
- 0);
-
- RecordWeeklyAggregateDataUse(
- fake_time_now, kMainFrameKB, true,
- data_use_measurement::DataUseUserData::MAIN_FRAME_HTML, 0);
- VerifyDictionaryPref(prefs::kThisWeekUserTrafficContentTypeDownstreamKB,
- data_use_measurement::DataUseUserData::MAIN_FRAME_HTML,
- kMainFrameKB);
- RecordWeeklyAggregateDataUse(
- fake_time_now, kNonMainFrameKB, true,
- data_use_measurement::DataUseUserData::NON_MAIN_FRAME_HTML, 0);
- VerifyDictionaryPref(
- prefs::kThisWeekUserTrafficContentTypeDownstreamKB,
- data_use_measurement::DataUseUserData::NON_MAIN_FRAME_HTML,
- kNonMainFrameKB);
-
- // Fast forward 7 days, and verify that the last week histograms are recorded.
- fake_time_now += base::Days(7);
- InitializeWeeklyAggregateDataUse(fake_time_now);
- VerifyDictionaryPref(prefs::kLastWeekUserTrafficContentTypeDownstreamKB,
- data_use_measurement::DataUseUserData::MAIN_FRAME_HTML,
- kMainFrameKB);
- VerifyDictionaryPref(
- prefs::kLastWeekUserTrafficContentTypeDownstreamKB,
- data_use_measurement::DataUseUserData::NON_MAIN_FRAME_HTML,
- kNonMainFrameKB);
-
- histogram_tester.ExpectBucketCount(
- "DataReductionProxy.LastWeekAggregateKB.UserTraffic.Downstream."
- "ContentType",
- data_use_measurement::DataUseUserData::MAIN_FRAME_HTML, kMainFrameKB);
- histogram_tester.ExpectBucketCount(
- "DataReductionProxy.LastWeekAggregateKB.UserTraffic.Downstream."
- "ContentType",
- data_use_measurement::DataUseUserData::NON_MAIN_FRAME_HTML,
- kNonMainFrameKB);
- histogram_tester.ExpectTotalCount(
- "DataReductionProxy.ThisWeekAggregateKB.UserTraffic.Downstream."
- "ContentType",
- 0);
-
- // Subsequent data use should be recorded to the current week prefs.
- RecordWeeklyAggregateDataUse(
- fake_time_now, kMainFrameKB, true,
- data_use_measurement::DataUseUserData::MAIN_FRAME_HTML, 0);
- VerifyDictionaryPref(prefs::kThisWeekUserTrafficContentTypeDownstreamKB,
- data_use_measurement::DataUseUserData::MAIN_FRAME_HTML,
- kMainFrameKB);
-
- // Fast forward by more than two weeks, and the prefs will be cleared.
- fake_time_now += base::Days(15);
- InitializeWeeklyAggregateDataUse(fake_time_now);
- VerifyDictionaryPref(prefs::kLastWeekUserTrafficContentTypeDownstreamKB,
- data_use_measurement::DataUseUserData::MAIN_FRAME_HTML,
- 0);
- VerifyDictionaryPref(
- prefs::kLastWeekUserTrafficContentTypeDownstreamKB,
- data_use_measurement::DataUseUserData::NON_MAIN_FRAME_HTML, 0);
- VerifyDictionaryPref(prefs::kThisWeekUserTrafficContentTypeDownstreamKB,
- data_use_measurement::DataUseUserData::MAIN_FRAME_HTML,
- 0);
- VerifyDictionaryPref(
- prefs::kThisWeekUserTrafficContentTypeDownstreamKB,
- data_use_measurement::DataUseUserData::NON_MAIN_FRAME_HTML, 0);
-}
-
-} // namespace data_reduction_proxy
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs.cc
deleted file mode 100644
index 8c495b703e0..00000000000
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs.cc
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright 2014 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.
-
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs.h"
-
-#include <memory>
-
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
-#include "components/pref_registry/pref_registry_syncable.h"
-#include "components/prefs/pref_registry_simple.h"
-#include "components/prefs/pref_service.h"
-#include "components/prefs/scoped_user_pref_update.h"
-
-namespace data_reduction_proxy {
-
-// Make sure any changes here that have the potential to impact android_webview
-// are reflected in RegisterSimpleProfilePrefs.
-void RegisterSyncableProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
- registry->RegisterBooleanPref(prefs::kDataSaverEnabled, false);
- registry->RegisterBooleanPref(prefs::kDataReductionProxyWasEnabledBefore,
- false);
-
- registry->RegisterInt64Pref(prefs::kDataReductionProxyLastEnabledTime, 0L);
-
- registry->RegisterBooleanPref(prefs::kDataUsageReportingEnabled, false);
-
- registry->RegisterInt64Pref(prefs::kHttpReceivedContentLength, 0);
- registry->RegisterInt64Pref(prefs::kHttpOriginalContentLength, 0);
-
- registry->RegisterListPref(prefs::kDailyHttpOriginalContentLength);
-
- registry->RegisterListPref(prefs::kDailyHttpReceivedContentLength);
-
- registry->RegisterInt64Pref(prefs::kDailyHttpContentLengthLastUpdateDate, 0L);
-
- registry->RegisterIntegerPref(prefs::kThisWeekNumber, 0);
- registry->RegisterDictionaryPref(
- prefs::kThisWeekServicesDownstreamBackgroundKB, PrefRegistry::LOSSY_PREF);
- registry->RegisterDictionaryPref(
- prefs::kThisWeekServicesDownstreamForegroundKB, PrefRegistry::LOSSY_PREF);
- registry->RegisterDictionaryPref(
- prefs::kLastWeekServicesDownstreamBackgroundKB, PrefRegistry::LOSSY_PREF);
- registry->RegisterDictionaryPref(
- prefs::kLastWeekServicesDownstreamForegroundKB, PrefRegistry::LOSSY_PREF);
- registry->RegisterDictionaryPref(
- prefs::kThisWeekUserTrafficContentTypeDownstreamKB,
- PrefRegistry::LOSSY_PREF);
- registry->RegisterDictionaryPref(
- prefs::kLastWeekUserTrafficContentTypeDownstreamKB,
- PrefRegistry::LOSSY_PREF);
-}
-
-void RegisterSimpleProfilePrefs(PrefRegistrySimple* registry) {
- registry->RegisterBooleanPref(
- prefs::kDataReductionProxyWasEnabledBefore, false);
-
- registry->RegisterBooleanPref(prefs::kDataUsageReportingEnabled, false);
- RegisterPrefs(registry);
-}
-
-// Add any new data reduction proxy prefs to the |pref_map_| or the
-// |list_pref_map_| in Init() of DataReductionProxyCompressionStats.
-void RegisterPrefs(PrefRegistrySimple* registry) {
- registry->RegisterInt64Pref(prefs::kDataReductionProxyLastEnabledTime, 0L);
- registry->RegisterInt64Pref(prefs::kHttpReceivedContentLength, 0);
- registry->RegisterInt64Pref(
- prefs::kHttpOriginalContentLength, 0);
- registry->RegisterListPref(
- prefs::kDailyHttpOriginalContentLength);
- registry->RegisterListPref(prefs::kDailyHttpReceivedContentLength);
- registry->RegisterInt64Pref(
- prefs::kDailyHttpContentLengthLastUpdateDate, 0L);
-
- registry->RegisterIntegerPref(prefs::kThisWeekNumber, 0);
- registry->RegisterDictionaryPref(
- prefs::kThisWeekServicesDownstreamBackgroundKB, PrefRegistry::LOSSY_PREF);
- registry->RegisterDictionaryPref(
- prefs::kThisWeekServicesDownstreamForegroundKB, PrefRegistry::LOSSY_PREF);
- registry->RegisterDictionaryPref(
- prefs::kLastWeekServicesDownstreamBackgroundKB, PrefRegistry::LOSSY_PREF);
- registry->RegisterDictionaryPref(
- prefs::kLastWeekServicesDownstreamForegroundKB, PrefRegistry::LOSSY_PREF);
- registry->RegisterDictionaryPref(
- prefs::kThisWeekUserTrafficContentTypeDownstreamKB,
- PrefRegistry::LOSSY_PREF);
- registry->RegisterDictionaryPref(
- prefs::kLastWeekUserTrafficContentTypeDownstreamKB,
- PrefRegistry::LOSSY_PREF);
-}
-
-} // namespace data_reduction_proxy
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs.h b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs.h
deleted file mode 100644
index 0801cb37431..00000000000
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2014 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.
-
-#ifndef COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_PREFS_H_
-#define COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_PREFS_H_
-
-namespace user_prefs {
-class PrefRegistrySyncable;
-}
-
-class PrefRegistrySimple;
-
-namespace data_reduction_proxy {
-
-// Registers the data reduction proxy's profile prefs on platforms that use
-// syncable prefs.
-void RegisterSyncableProfilePrefs(
- user_prefs::PrefRegistrySyncable* registry);
-
-// Registers the data reduction proxy's profile prefs on platforms that do not
-// use syncable prefs.
-void RegisterSimpleProfilePrefs(PrefRegistrySimple* registry);
-
-// Registers local state, i.e., profile-agnostic prefs for the data
-// reduction proxy.
-void RegisterPrefs(PrefRegistrySimple* registry);
-
-} // namespace data_reduction_proxy
-
-#endif // COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_PREFS_H_
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs_unittest.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs_unittest.cc
deleted file mode 100644
index 455de14b1d8..00000000000
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs_unittest.cc
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright 2014 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.
-
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs.h"
-
-#include <stdint.h>
-
-#include "base/strings/string_number_conversions.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
-#include "components/prefs/pref_registry_simple.h"
-#include "components/prefs/pref_service.h"
-#include "components/prefs/scoped_user_pref_update.h"
-#include "components/prefs/testing_pref_service.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace data_reduction_proxy {
-
-class DataReductionProxyPrefsTest : public testing::Test {
- public:
- void SetUp() override {
- RegisterPrefs(local_state_prefs_.registry());
- PrefRegistrySimple* profile_registry = profile_prefs_.registry();
- RegisterPrefs(profile_registry);
- }
-
- PrefService* local_state_prefs() {
- return &local_state_prefs_;
- }
-
- PrefService* profile_prefs() {
- return &profile_prefs_;
- }
-
- // Initializes a list with ten string representations of successive int64_t
- // values, starting with |starting_value|.
- void InitializeList(const char* pref_name,
- int64_t starting_value,
- PrefService* pref_service) {
- ListPrefUpdate list(local_state_prefs(), pref_name);
- for (int64_t i = 0; i < 10L; ++i) {
- list->Append(base::NumberToString(i + starting_value));
- }
- }
-
- // Verifies that ten string repreentations of successive int64_t values
- // starting with |starting_value| are found in the |ListValue| with the
- // associated |pref_name|.
- void VerifyList(const char* pref_name,
- int64_t starting_value,
- PrefService* pref_service) {
- const base::ListValue* list_value = pref_service->GetList(pref_name);
- base::Value::ConstListView list_view = list_value->GetList();
- for (int64_t i = 0; i < 10L; ++i) {
- std::string string_value;
- int64_t value;
- if (static_cast<size_t>(i) < list_view.size() &&
- list_view[i].is_string()) {
- string_value = list_view[i].GetString();
- }
- base::StringToInt64(string_value, &value);
- EXPECT_EQ(i + starting_value, value);
- }
- }
-
- private:
- void RegisterPrefs(PrefRegistrySimple* registry) {
- registry->RegisterInt64Pref(prefs::kHttpReceivedContentLength, 0);
- registry->RegisterInt64Pref(prefs::kHttpOriginalContentLength, 0);
-
- registry->RegisterListPref(prefs::kDailyHttpOriginalContentLength);
- registry->RegisterListPref(prefs::kDailyHttpReceivedContentLength);
- registry->RegisterInt64Pref(
- prefs::kDailyHttpContentLengthLastUpdateDate, 0L);
- }
-
- TestingPrefServiceSimple local_state_prefs_;
- TestingPrefServiceSimple profile_prefs_;
-};
-
-} // namespace data_reduction_proxy
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.cc
deleted file mode 100644
index 81f23c62fa0..00000000000
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.cc
+++ /dev/null
@@ -1,236 +0,0 @@
-// Copyright 2015 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.
-
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h"
-
-#include <memory>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/files/file_path.h"
-#include "base/json/json_reader.h"
-#include "base/location.h"
-#include "base/metrics/field_trial_params.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/task/sequenced_task_runner.h"
-#include "base/task/single_thread_task_runner.h"
-#include "base/task/task_runner_util.h"
-#include "base/time/default_clock.h"
-#include "base/time/time.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h"
-#include "components/data_reduction_proxy/core/browser/data_store.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_features.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
-#include "components/data_reduction_proxy/proto/data_store.pb.h"
-#include "components/data_use_measurement/core/data_use_measurement.h"
-#include "components/prefs/pref_service.h"
-
-namespace data_reduction_proxy {
-
-namespace {
-
-absl::optional<base::Value> GetSaveDataSavingsPercentEstimateFromFieldTrial() {
- if (!base::FeatureList::IsEnabled(features::kReportSaveDataSavings))
- return absl::nullopt;
- const auto origin_savings_estimate_json =
- base::GetFieldTrialParamValueByFeature(features::kReportSaveDataSavings,
- "origin_savings_estimate");
- if (origin_savings_estimate_json.empty())
- return absl::nullopt;
-
- auto origin_savings_estimates =
- base::JSONReader::Read(origin_savings_estimate_json);
-
- UMA_HISTOGRAM_BOOLEAN(
- "DataReductionProxy.ReportSaveDataSavings.ParseResult",
- origin_savings_estimates && origin_savings_estimates->is_dict());
-
- return origin_savings_estimates;
-}
-
-// Hostname used for the other bucket which consists of chrome-services traffic.
-// This should be in sync with the same in DataReductionSiteBreakdownView.java
-const char kOtherHostName[] = "Other";
-
-} // namespace
-
-DataReductionProxyService::DataReductionProxyService(
- DataReductionProxySettings* settings,
- PrefService* prefs,
- std::unique_ptr<DataStore> store,
- data_use_measurement::DataUseMeasurement* data_use_measurement,
- const scoped_refptr<base::SequencedTaskRunner>& db_task_runner,
- const base::TimeDelta& commit_delay)
- : settings_(settings),
- prefs_(prefs),
- db_data_owner_(new DBDataOwner(std::move(store))),
- db_task_runner_(db_task_runner),
- data_use_measurement_(data_use_measurement),
- save_data_savings_estimate_dict_(
- GetSaveDataSavingsPercentEstimateFromFieldTrial()) {
- DCHECK(data_use_measurement_);
- DCHECK(settings);
-
- db_task_runner_->PostTask(FROM_HERE,
- base::BindOnce(&DBDataOwner::InitializeOnDBThread,
- db_data_owner_->GetWeakPtr()));
- if (prefs_) {
- compression_stats_ = std::make_unique<DataReductionProxyCompressionStats>(
- this, prefs_, commit_delay);
- }
- if (data_use_measurement_) { // null in unit tests.
- data_use_measurement_->AddServicesDataUseObserver(this);
- }
-}
-
-DataReductionProxyService::~DataReductionProxyService() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- compression_stats_.reset();
- db_task_runner_->DeleteSoon(FROM_HERE, db_data_owner_.release());
- if (data_use_measurement_) { // null in unit tests.
- data_use_measurement_->RemoveServicesDataUseObserver(this);
- }
-}
-
-
-void DataReductionProxyService::Shutdown() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- weak_factory_.InvalidateWeakPtrs();
-}
-
-void DataReductionProxyService::UpdateDataUseForHost(int64_t network_bytes,
- int64_t original_bytes,
- const std::string& host) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- if (compression_stats_) {
- compression_stats_->RecordDataUseByHost(host, network_bytes, original_bytes,
- base::Time::Now());
- }
-}
-
-void DataReductionProxyService::UpdateContentLengths(
- int64_t data_used,
- int64_t original_size,
- bool data_reduction_proxy_enabled,
- const std::string& mime_type,
- bool is_user_traffic,
- data_use_measurement::DataUseUserData::DataUseContentType content_type,
- int32_t service_hash_code) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- if (compression_stats_) {
- compression_stats_->RecordDataUseWithMimeType(
- data_used, original_size, data_reduction_proxy_enabled, mime_type,
- is_user_traffic, content_type, service_hash_code);
- }
-}
-
-void DataReductionProxyService::SetUnreachable(bool unreachable) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- settings_->SetUnreachable(unreachable);
-}
-
-void DataReductionProxyService::SetInt64Pref(const std::string& pref_path,
- int64_t value) {
- if (prefs_)
- prefs_->SetInt64(pref_path, value);
-}
-
-void DataReductionProxyService::SetStringPref(const std::string& pref_path,
- const std::string& value) {
- if (prefs_)
- prefs_->SetString(pref_path, value);
-}
-
-
-
-void DataReductionProxyService::LoadHistoricalDataUsage(
- HistoricalDataUsageCallback load_data_usage_callback) {
- std::unique_ptr<std::vector<DataUsageBucket>> data_usage(
- new std::vector<DataUsageBucket>());
- std::vector<DataUsageBucket>* data_usage_ptr = data_usage.get();
- db_task_runner_->PostTaskAndReply(
- FROM_HERE,
- base::BindOnce(&DBDataOwner::LoadHistoricalDataUsage,
- db_data_owner_->GetWeakPtr(),
- base::Unretained(data_usage_ptr)),
- base::BindOnce(std::move(load_data_usage_callback),
- std::move(data_usage)));
-}
-
-void DataReductionProxyService::LoadCurrentDataUsageBucket(
- LoadCurrentDataUsageCallback load_current_data_usage_callback) {
- std::unique_ptr<DataUsageBucket> bucket(new DataUsageBucket());
- DataUsageBucket* bucket_ptr = bucket.get();
- db_task_runner_->PostTaskAndReply(
- FROM_HERE,
- base::BindOnce(&DBDataOwner::LoadCurrentDataUsageBucket,
- db_data_owner_->GetWeakPtr(),
- base::Unretained(bucket_ptr)),
- base::BindOnce(std::move(load_current_data_usage_callback),
- std::move(bucket)));
-}
-
-void DataReductionProxyService::StoreCurrentDataUsageBucket(
- std::unique_ptr<DataUsageBucket> current) {
- db_task_runner_->PostTask(
- FROM_HERE,
- base::BindOnce(&DBDataOwner::StoreCurrentDataUsageBucket,
- db_data_owner_->GetWeakPtr(), std::move(current)));
-}
-
-void DataReductionProxyService::DeleteHistoricalDataUsage() {
- db_task_runner_->PostTask(
- FROM_HERE, base::BindOnce(&DBDataOwner::DeleteHistoricalDataUsage,
- db_data_owner_->GetWeakPtr()));
-}
-
-void DataReductionProxyService::DeleteBrowsingHistory(const base::Time& start,
- const base::Time& end) {
- DCHECK_LE(start, end);
- db_task_runner_->PostTask(
- FROM_HERE, base::BindOnce(&DBDataOwner::DeleteBrowsingHistory,
- db_data_owner_->GetWeakPtr(), start, end));
-}
-
-base::WeakPtr<DataReductionProxyService>
-DataReductionProxyService::GetWeakPtr() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- return weak_factory_.GetWeakPtr();
-}
-
-void DataReductionProxyService::OnServicesDataUse(int32_t service_hash_code,
- int64_t recv_bytes,
- int64_t sent_bytes) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- if (compression_stats_) {
- // Record non-content initiated traffic to the Other bucket for data saver
- // site-breakdown.
- compression_stats_->RecordDataUseByHost(kOtherHostName, sent_bytes,
- sent_bytes, base::Time::Now());
- compression_stats_->RecordDataUseByHost(kOtherHostName, recv_bytes,
- recv_bytes, base::Time::Now());
- compression_stats_->RecordDataUseWithMimeType(
- recv_bytes, recv_bytes, settings_->IsDataReductionProxyEnabled(),
- std::string(), false, data_use_measurement::DataUseUserData::OTHER,
- service_hash_code);
- }
-}
-
-double DataReductionProxyService::GetSaveDataSavingsPercentEstimate(
- const std::string& origin) const {
- if (origin.empty() || !save_data_savings_estimate_dict_ ||
- !save_data_savings_estimate_dict_->is_dict()) {
- return 0;
- }
- const auto savings_percent =
- save_data_savings_estimate_dict_->FindDoubleKey(origin);
- if (!savings_percent)
- return 0;
- return *savings_percent;
-}
-
-} // namespace data_reduction_proxy
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h
deleted file mode 100644
index 503728b6967..00000000000
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h
+++ /dev/null
@@ -1,154 +0,0 @@
-// Copyright 2015 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.
-
-#ifndef COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_SERVICE_H_
-#define COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_SERVICE_H_
-
-#include <stdint.h>
-
-#include <memory>
-#include <string>
-
-#include "base/callback.h"
-#include "base/gtest_prod_util.h"
-#include "base/memory/raw_ptr.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "base/sequence_checker.h"
-#include "base/values.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics.h"
-#include "components/data_reduction_proxy/core/browser/db_data_owner.h"
-#include "components/data_use_measurement/core/data_use_measurement.h"
-#include "net/nqe/effective_connection_type.h"
-
-class PrefService;
-
-namespace base {
-class SequencedTaskRunner;
-class TimeDelta;
-} // namespace base
-
-namespace data_reduction_proxy {
-
-class DataReductionProxyCompressionStats;
-class DataReductionProxySettings;
-
-// Contains and initializes all Data Reduction Proxy objects that have a
-// lifetime based on the UI thread.
-class DataReductionProxyService
- : public data_use_measurement::DataUseMeasurement::ServicesDataUseObserver {
- public:
- // The caller must ensure that |settings|, |prefs|, |request_context|, and
- // |io_task_runner| remain alive for the lifetime of the
- // |DataReductionProxyService| instance. |prefs| may be null. This instance
- // will take ownership of |compression_stats|.
- // TODO(jeremyim): DataReductionProxyService should own
- // DataReductionProxySettings and not vice versa.
- DataReductionProxyService(
- DataReductionProxySettings* settings,
- PrefService* prefs,
- std::unique_ptr<DataStore> store,
- data_use_measurement::DataUseMeasurement* data_use_measurement,
- const scoped_refptr<base::SequencedTaskRunner>& db_task_runner,
- const base::TimeDelta& commit_delay);
-
- DataReductionProxyService(const DataReductionProxyService&) = delete;
- DataReductionProxyService& operator=(const DataReductionProxyService&) =
- delete;
-
- virtual ~DataReductionProxyService();
-
- void Shutdown();
-
- // Records data usage per host.
- // Virtual for testing.
- virtual void UpdateDataUseForHost(int64_t network_bytes,
- int64_t original_bytes,
- const std::string& host);
-
- // Records daily data savings statistics in |compression_stats_|.
- // Virtual for testing.
- virtual void UpdateContentLengths(
- int64_t data_used,
- int64_t original_size,
- bool data_reduction_proxy_enabled,
- const std::string& mime_type,
- bool is_user_traffic,
- data_use_measurement::DataUseUserData::DataUseContentType content_type,
- int32_t service_hash_code);
-
- // Records whether the Data Reduction Proxy is unreachable or not.
- void SetUnreachable(bool unreachable);
-
- // Stores an int64_t value in |prefs_|.
- void SetInt64Pref(const std::string& pref_path, int64_t value);
-
- // Stores a string value in |prefs_|.
- void SetStringPref(const std::string& pref_path, const std::string& value);
-
- void LoadHistoricalDataUsage(
- HistoricalDataUsageCallback load_data_usage_callback);
- void LoadCurrentDataUsageBucket(
- LoadCurrentDataUsageCallback load_current_data_usage_callback);
- void StoreCurrentDataUsageBucket(std::unique_ptr<DataUsageBucket> current);
- void DeleteHistoricalDataUsage();
- void DeleteBrowsingHistory(const base::Time& start, const base::Time& end);
-
- void SetSettingsForTesting(DataReductionProxySettings* settings) {
- settings_ = settings;
- }
-
- // Returns the percentage of data savings estimate provided by save-data for
- // an origin.
- double GetSaveDataSavingsPercentEstimate(const std::string& origin) const;
-
- // Accessor methods.
- DataReductionProxyCompressionStats* compression_stats() const {
- return compression_stats_.get();
- }
-
- base::WeakPtr<DataReductionProxyService> GetWeakPtr();
-
- base::SequencedTaskRunner* GetDBTaskRunnerForTesting() const {
- return db_task_runner_.get();
- }
-
- private:
- FRIEND_TEST_ALL_PREFIXES(DataReductionProxyConfigServiceClientTest,
- MultipleAuthFailures);
- FRIEND_TEST_ALL_PREFIXES(DataReductionProxyConfigServiceClientTest,
- ValidatePersistedClientConfig);
-
- void OnServicesDataUse(int32_t service_hash_code,
- int64_t recv_bytes,
- int64_t sent_bytes) override;
-
- // Tracks compression statistics to be displayed to the user.
- std::unique_ptr<DataReductionProxyCompressionStats> compression_stats_;
-
- raw_ptr<DataReductionProxySettings> settings_;
-
- // A prefs service for storing data.
- raw_ptr<PrefService> prefs_;
-
- std::unique_ptr<DBDataOwner> db_data_owner_;
-
- // Used to post tasks to |db_data_owner_|.
- scoped_refptr<base::SequencedTaskRunner> db_task_runner_;
-
- // Must be accessed on UI thread. Guaranteed to be non-null during the
- // lifetime of |this|.
- raw_ptr<data_use_measurement::DataUseMeasurement> data_use_measurement_;
-
- // Dictionary of save-data savings estimates by origin.
- const absl::optional<base::Value> save_data_savings_estimate_dict_;
-
- SEQUENCE_CHECKER(sequence_checker_);
-
- base::WeakPtrFactory<DataReductionProxyService> weak_factory_{this};
-};
-
-} // namespace data_reduction_proxy
-
-#endif // COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_SERVICE_H_
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.cc
index ee8861ad00d..099bd766b29 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.cc
@@ -13,15 +13,7 @@
#include "base/time/clock.h"
#include "base/time/default_clock.h"
#include "build/build_config.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_features.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h"
-#include "components/prefs/pref_member.h"
-#include "components/prefs/pref_service.h"
-#include "net/base/network_change_notifier.h"
-#include "net/http/http_request_headers.h"
namespace {
@@ -32,244 +24,28 @@ bool ShouldForceEnableDataReductionProxy() {
data_reduction_proxy::switches::kEnableDataReductionProxy);
}
-// Key of the UMA DataReductionProxy.StartupState histogram.
-const char kUMAProxyStartupStateHistogram[] = "DataReductionProxy.StartupState";
-
-void RecordSettingsEnabledState(
- data_reduction_proxy::DataReductionSettingsEnabledAction action) {
- UMA_HISTOGRAM_ENUMERATION(
- "DataReductionProxy.EnabledState", action,
- data_reduction_proxy::DATA_REDUCTION_SETTINGS_ACTION_BOUNDARY);
-}
-
-// Record the number of days since data reduction proxy was enabled by the
-// user.
-void RecordDaysSinceEnabledMetric(int days_since_enabled) {
- UMA_HISTOGRAM_CUSTOM_COUNTS("DataReductionProxy.DaysSinceEnabled",
- days_since_enabled, 0, 365 * 10, 100);
-}
-
} // namespace
namespace data_reduction_proxy {
DataReductionProxySettings::DataReductionProxySettings(
bool is_off_the_record_profile)
- : unreachable_(false),
- prefs_(nullptr),
- clock_(base::DefaultClock::GetInstance()),
- is_off_the_record_profile_(is_off_the_record_profile) {
+ : is_off_the_record_profile_(is_off_the_record_profile) {
DCHECK(!is_off_the_record_profile_);
}
DataReductionProxySettings::~DataReductionProxySettings() = default;
-void DataReductionProxySettings::InitDataReductionProxySettings(
- PrefService* prefs,
- std::unique_ptr<DataReductionProxyService> data_reduction_proxy_service) {
- DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(prefs);
- DCHECK(data_reduction_proxy_service);
- prefs_ = prefs;
- data_reduction_proxy_service_ = std::move(data_reduction_proxy_service);
- RecordDataReductionInit();
-
- registrar_.Init(prefs_);
- registrar_.Add(
- prefs::kDataSaverEnabled,
- base::BindRepeating(&DataReductionProxySettings::OnProxyEnabledPrefChange,
- base::Unretained(this)));
-
-#if defined(OS_ANDROID)
- if (IsDataSaverEnabledByUser(is_off_the_record_profile_, prefs_)) {
- data_reduction_proxy_service_->compression_stats()
- ->SetDataUsageReportingEnabled(true);
- }
-#endif // defined(OS_ANDROID)
-}
-
-void DataReductionProxySettings::SetCallbackToRegisterSyntheticFieldTrial(
- const SyntheticFieldTrialRegistrationCallback&
- on_data_reduction_proxy_enabled) {
- register_synthetic_field_trial_ = on_data_reduction_proxy_enabled;
- RegisterDataReductionProxyFieldTrial();
-}
+void DataReductionProxySettings::InitDataReductionProxySettings() {}
// static
bool DataReductionProxySettings::IsDataSaverEnabledByUser(
- bool is_off_the_record_profile,
- PrefService* prefs) {
+ bool is_off_the_record_profile) {
if (is_off_the_record_profile)
return false;
if (ShouldForceEnableDataReductionProxy())
return true;
-
-#if defined(OS_ANDROID)
- return prefs && prefs->GetBoolean(prefs::kDataSaverEnabled);
-#else
return false;
-#endif
-}
-
-// static
-void DataReductionProxySettings::SetDataSaverEnabledForTesting(
- PrefService* prefs,
- bool enabled) {
- // Set the command line so that |IsDataSaverEnabledByUser| returns as expected
- // on all platforms.
- base::CommandLine* cmd = base::CommandLine::ForCurrentProcess();
- if (enabled) {
- cmd->AppendSwitch(switches::kEnableDataReductionProxy);
- } else {
- cmd->RemoveSwitch(switches::kEnableDataReductionProxy);
- }
-
- // Set the pref so that all the pref change callbacks run.
- prefs->SetBoolean(prefs::kDataSaverEnabled, enabled);
-}
-
-bool DataReductionProxySettings::IsDataReductionProxyEnabled() const {
- return IsDataSaverEnabledByUser(is_off_the_record_profile_,
- GetOriginalProfilePrefs());
-}
-
-bool DataReductionProxySettings::CanUseDataReductionProxy(
- const GURL& url) const {
- return url.is_valid() && url.scheme() == url::kHttpScheme &&
- IsDataReductionProxyEnabled();
-}
-
-bool DataReductionProxySettings::IsDataReductionProxyManaged() {
- const PrefService::Preference* pref =
- GetOriginalProfilePrefs()->FindPreference(prefs::kDataSaverEnabled);
- return pref && pref->IsManaged();
-}
-
-void DataReductionProxySettings::SetDataReductionProxyEnabled(bool enabled) {
- DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(data_reduction_proxy_service_->compression_stats());
- if (GetOriginalProfilePrefs()->GetBoolean(prefs::kDataSaverEnabled) !=
- enabled) {
- GetOriginalProfilePrefs()->SetBoolean(prefs::kDataSaverEnabled, enabled);
- OnProxyEnabledPrefChange();
-#if defined(OS_ANDROID)
- data_reduction_proxy_service_->compression_stats()
- ->SetDataUsageReportingEnabled(enabled);
-#endif // defined(OS_ANDROID)
- }
-}
-
-int64_t DataReductionProxySettings::GetDataReductionLastUpdateTime() {
- DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(data_reduction_proxy_service_->compression_stats());
- return data_reduction_proxy_service_->compression_stats()
- ->GetLastUpdateTime();
-}
-
-void DataReductionProxySettings::ClearDataSavingStatistics(
- DataReductionProxySavingsClearedReason reason) {
- DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(data_reduction_proxy_service_->compression_stats());
- data_reduction_proxy_service_->compression_stats()->ClearDataSavingStatistics(
- reason);
-}
-
-int64_t DataReductionProxySettings::GetTotalHttpContentLengthSaved() {
- DCHECK(thread_checker_.CalledOnValidThread());
- return data_reduction_proxy_service_->compression_stats()
- ->GetHttpOriginalContentLength() -
- data_reduction_proxy_service_->compression_stats()
- ->GetHttpReceivedContentLength();
-}
-
-void DataReductionProxySettings::SetUnreachable(bool unreachable) {
- unreachable_ = unreachable;
-}
-
-bool DataReductionProxySettings::IsDataReductionProxyUnreachable() {
- DCHECK(thread_checker_.CalledOnValidThread());
- return unreachable_;
-}
-
-PrefService* DataReductionProxySettings::GetOriginalProfilePrefs() const {
- DCHECK(thread_checker_.CalledOnValidThread());
- return prefs_;
-}
-
-base::Time DataReductionProxySettings::GetLastEnabledTime() const {
- PrefService* prefs = GetOriginalProfilePrefs();
- int64_t last_enabled_time =
- prefs->GetInt64(prefs::kDataReductionProxyLastEnabledTime);
- if (last_enabled_time <= 0)
- return base::Time();
- return base::Time::FromInternalValue(last_enabled_time);
-}
-
-void DataReductionProxySettings::RegisterDataReductionProxyFieldTrial() {
- register_synthetic_field_trial_.Run(
- "SyntheticDataReductionProxySetting",
- IsDataReductionProxyEnabled() ? "Enabled" : "Disabled");
-}
-
-void DataReductionProxySettings::OnProxyEnabledPrefChange() {
- DCHECK(thread_checker_.CalledOnValidThread());
- if (!register_synthetic_field_trial_.is_null()) {
- RegisterDataReductionProxyFieldTrial();
- }
- MaybeActivateDataReductionProxy(false);
-
- bool enabled = IsDataReductionProxyEnabled();
- for (auto& observer : observers_)
- observer.OnDataSaverEnabledChanged(enabled);
-}
-
-void DataReductionProxySettings::ResetDataReductionStatistics() {
- DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(data_reduction_proxy_service_->compression_stats());
- data_reduction_proxy_service_->compression_stats()->ResetStatistics();
-}
-
-void DataReductionProxySettings::MaybeActivateDataReductionProxy(
- bool at_startup) {
- DCHECK(thread_checker_.CalledOnValidThread());
- PrefService* prefs = GetOriginalProfilePrefs();
- // Do nothing if prefs have not been initialized. This allows unit testing
- // of profile related code without having to initialize data reduction proxy
- // related prefs.
- if (!prefs)
- return;
-
- bool enabled = IsDataSaverEnabledByUser(is_off_the_record_profile_, prefs);
-
- if (enabled && at_startup) {
- const auto last_enabled_time = GetLastEnabledTime();
- if (!last_enabled_time.is_null()) {
- // Record the metric only if the time when data reduction proxy was
- // enabled is available.
- RecordDaysSinceEnabledMetric(
- (clock_->Now() - last_enabled_time).InDays());
- }
- }
-
- if (enabled &&
- !prefs->GetBoolean(prefs::kDataReductionProxyWasEnabledBefore)) {
- prefs->SetBoolean(prefs::kDataReductionProxyWasEnabledBefore, true);
- ResetDataReductionStatistics();
- }
- if (!at_startup) {
- if (IsDataReductionProxyEnabled()) {
- RecordSettingsEnabledState(DATA_REDUCTION_SETTINGS_ACTION_OFF_TO_ON);
-
- // Data reduction proxy has been enabled by the user. Record the number of
- // days since the data reduction proxy has been enabled as zero, and
- // store the current time in the pref.
- prefs->SetInt64(prefs::kDataReductionProxyLastEnabledTime,
- clock_->Now().ToInternalValue());
- RecordDaysSinceEnabledMetric(0);
- } else {
- RecordSettingsEnabledState(DATA_REDUCTION_SETTINGS_ACTION_ON_TO_OFF);
- }
- }
}
void DataReductionProxySettings::AddDataReductionProxySettingsObserver(
@@ -284,70 +60,4 @@ void DataReductionProxySettings::RemoveDataReductionProxySettingsObserver(
observers_.RemoveObserver(observer);
}
-// Metrics methods
-void DataReductionProxySettings::RecordDataReductionInit() const {
- DCHECK(thread_checker_.CalledOnValidThread());
- RecordStartupState(IsDataReductionProxyEnabled() ? PROXY_ENABLED
- : PROXY_DISABLED);
- RecordStartupSavings();
-}
-
-void DataReductionProxySettings::RecordStartupState(
- ProxyStartupState state) const {
- UMA_HISTOGRAM_ENUMERATION(kUMAProxyStartupStateHistogram, state,
- PROXY_STARTUP_STATE_COUNT);
-}
-
-void DataReductionProxySettings::RecordStartupSavings() const {
- // Minimum bytes the user should have browsed, for the data savings percent
- // UMA to be recorded at startup.
- const unsigned int kMinOriginalContentLengthBytes =
- 10 * 1024 * 1024; // 10 MB.
-
- if (!IsDataReductionProxyEnabled())
- return;
-
- DCHECK(data_reduction_proxy_service_->compression_stats());
- int64_t original_content_length =
- data_reduction_proxy_service_->compression_stats()
- ->GetHttpOriginalContentLength();
- int64_t received_content_length =
- data_reduction_proxy_service_->compression_stats()
- ->GetHttpReceivedContentLength();
- if (original_content_length < kMinOriginalContentLengthBytes)
- return;
- int savings_percent =
- static_cast<int>(((original_content_length - received_content_length) /
- (float)original_content_length) *
- 100.0);
- if (savings_percent >= 0) {
- UMA_HISTOGRAM_PERCENTAGE("DataReductionProxy.StartupSavingsPercent",
- savings_percent > 0 ? savings_percent : 0);
- }
- if (savings_percent < 0) {
- UMA_HISTOGRAM_PERCENTAGE("DataReductionProxy.StartupNegativeSavingsPercent",
- -savings_percent);
- }
-}
-
-ContentLengthList DataReductionProxySettings::GetDailyContentLengths(
- const char* pref_name) {
- DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(data_reduction_proxy_service_->compression_stats());
- return data_reduction_proxy_service_->compression_stats()
- ->GetDailyContentLengths(pref_name);
-}
-
-void DataReductionProxySettings::GetContentLengths(
- unsigned int days,
- int64_t* original_content_length,
- int64_t* received_content_length,
- int64_t* last_update_time) {
- DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(data_reduction_proxy_service_->compression_stats());
-
- data_reduction_proxy_service_->compression_stats()->GetContentLengths(
- days, original_content_length, received_content_length, last_update_time);
-}
-
} // namespace data_reduction_proxy
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h
index 982e668ad00..c1729d5fd6f 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h
@@ -5,53 +5,17 @@
#ifndef COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_SETTINGS_H_
#define COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_SETTINGS_H_
-#include <stdint.h>
-
-#include <memory>
-
#include "base/callback.h"
#include "base/compiler_specific.h"
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/observer_list.h"
#include "base/threading/thread_checker.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics.h"
-#include "components/prefs/pref_change_registrar.h"
-#include "components/prefs/pref_member.h"
-#include "net/http/http_request_headers.h"
#include "url/gurl.h"
-class PrefService;
-
-namespace base {
-class Clock;
-}
-
namespace data_reduction_proxy {
-class DataReductionProxyService;
-class DataReductionProxyCompressionStats;
-
-// Values of the UMA DataReductionProxy.StartupState histogram.
-// This enum must remain synchronized with DataReductionProxyStartupState
-// in metrics/histograms/histograms.xml.
-enum ProxyStartupState {
- PROXY_NOT_AVAILABLE = 0,
- PROXY_DISABLED,
- PROXY_ENABLED,
- PROXY_STARTUP_STATE_COUNT,
-};
-
-// Values of the UMA DataReductionProxy.EnabledState histogram.
-// This enum must remain synchronized with DataReductionProxyEnabledState
-// in metrics/histograms/histograms.xml.
-enum DataReductionSettingsEnabledAction {
- DATA_REDUCTION_SETTINGS_ACTION_OFF_TO_ON = 0,
- DATA_REDUCTION_SETTINGS_ACTION_ON_TO_OFF,
- DATA_REDUCTION_SETTINGS_ACTION_BOUNDARY,
-};
-
// Classes may derive from |DataReductionProxySettingsObserver| and register as
// an observer of |DataReductionProxySettings| to get notified when the proxy
// request headers change or when the DRPSettings class is initialized.
@@ -66,9 +30,6 @@ class DataReductionProxySettingsObserver {
// be called from there.
class DataReductionProxySettings {
public:
- using SyntheticFieldTrialRegistrationCallback =
- base::RepeatingCallback<bool(base::StringPiece, base::StringPiece)>;
-
explicit DataReductionProxySettings(bool is_off_the_record_profile);
DataReductionProxySettings(const DataReductionProxySettings&) = delete;
@@ -80,82 +41,16 @@ class DataReductionProxySettings {
// Initializes the Data Reduction Proxy with the profile prefs. The caller
// must ensure that all parameters remain alive for the lifetime of the
// |DataReductionProxySettings| instance.
- void InitDataReductionProxySettings(
- PrefService* prefs,
- std::unique_ptr<DataReductionProxyService> data_reduction_proxy_service);
-
- // Sets the |register_synthetic_field_trial_| callback and runs to register
- // the DataReductionProxyEnabled synthetic field trial.
- void SetCallbackToRegisterSyntheticFieldTrial(
- const SyntheticFieldTrialRegistrationCallback&
- on_data_reduction_proxy_enabled);
+ void InitDataReductionProxySettings();
// Returns true if the Data Saver feature is enabled by the user on Android.
// This checks only the Data Saver prefs on Android or forcing flag on any
// platform. Does not check any holdback experiments. Note that this may be
// different from the value of |IsDataReductionProxyEnabled|.
- static bool IsDataSaverEnabledByUser(bool is_off_the_record_profile,
- PrefService* prefs);
+ static bool IsDataSaverEnabledByUser(bool is_off_the_record_profile);
// Enables or disables Data Saver, regardless of platform.
- static void SetDataSaverEnabledForTesting(PrefService* prefs, bool enabled);
-
- // Returns true if the Data Reduction HTTP Proxy is enabled. Note that this
- // may be different from the value of |IsDataSaverEnabledByUser|.
- bool IsDataReductionProxyEnabled() const;
-
- // Returns true if the proxy can be used for the given url. This method does
- // not take into account the proxy config or proxy retry list, so it can
- // return true even when the proxy will not be used. Specifically, if
- // another proxy configuration overrides use of data reduction proxy, or
- // if data reduction proxy is in proxy retry list, then data reduction proxy
- // will not be used, but this method will still return true. If this method
- // returns false, then we are guaranteed that data reduction proxy will not be
- // used.
- bool CanUseDataReductionProxy(const GURL& url) const;
-
- // Returns true if the proxy is managed by an adminstrator's policy.
- bool IsDataReductionProxyManaged();
-
- // Enables or disables the data reduction proxy.
- void SetDataReductionProxyEnabled(bool enabled);
-
- // Returns the time in microseconds that the last update was made to the
- // daily original and received content lengths.
- int64_t GetDataReductionLastUpdateTime();
-
- // Clears all data saving statistics for the given |reason|.
- void ClearDataSavingStatistics(DataReductionProxySavingsClearedReason reason);
-
- // Returns the difference between the total original size of all HTTP content
- // received from the network and the actual size of the HTTP content received.
- int64_t GetTotalHttpContentLengthSaved();
-
- // Returns aggregate received and original content lengths over the specified
- // number of days, as well as the time these stats were last updated.
- void GetContentLengths(unsigned int days,
- int64_t* original_content_length,
- int64_t* received_content_length,
- int64_t* last_update_time);
-
- // Records that the data reduction proxy is unreachable or not.
- void SetUnreachable(bool unreachable);
-
- // Returns whether the data reduction proxy is unreachable. Returns true
- // if no request has successfully completed through proxy, even though atleast
- // some of them should have.
- bool IsDataReductionProxyUnreachable();
-
- ContentLengthList GetDailyContentLengths(const char* pref_name);
-
- // Configures data reduction proxy. |at_startup| is true when this method is
- // called in response to creating or loading a new profile.
- void MaybeActivateDataReductionProxy(bool at_startup);
-
- // Returns the time LiteMode was last enabled. This is reset whenever LiteMode
- // is disabled and re-enabled from settings. Null time is returned when
- // LiteMode has never been enabled.
- base::Time GetLastEnabledTime() const;
+ static void SetDataSaverEnabledForTesting(bool enabled);
// Adds an observer that is notified every time the proxy request headers
// change.
@@ -167,94 +62,7 @@ class DataReductionProxySettings {
void RemoveDataReductionProxySettingsObserver(
DataReductionProxySettingsObserver* observer);
- DataReductionProxyService* data_reduction_proxy_service() {
- return data_reduction_proxy_service_.get();
- }
-
- protected:
- void InitPrefMembers();
-
- // Virtualized for unit test support.
- virtual PrefService* GetOriginalProfilePrefs() const;
-
- // Metrics method. Subclasses should override if they wish to provide
- // alternatives.
- virtual void RecordDataReductionInit() const;
-
- // Virtualized for mocking. Records UMA specifying whether the proxy was
- // enabled or disabled at startup.
- virtual void RecordStartupState(
- data_reduction_proxy::ProxyStartupState state) const;
-
private:
- friend class DataReductionProxySettingsTestBase;
- friend class DataReductionProxySettingsTest;
- friend class DataReductionProxyTestContext;
- FRIEND_TEST_ALL_PREFIXES(DataReductionProxySettingsTest,
- TestResetDataReductionStatistics);
- FRIEND_TEST_ALL_PREFIXES(DataReductionProxySettingsTest,
- TestIsProxyEnabledOrManaged);
- FRIEND_TEST_ALL_PREFIXES(DataReductionProxySettingsTest,
- TestCanUseDataReductionProxy);
- FRIEND_TEST_ALL_PREFIXES(DataReductionProxySettingsTest, TestContentLengths);
- FRIEND_TEST_ALL_PREFIXES(DataReductionProxySettingsTest,
- TestGetDailyContentLengths);
- FRIEND_TEST_ALL_PREFIXES(DataReductionProxySettingsTest,
- TestMaybeActivateDataReductionProxy);
- FRIEND_TEST_ALL_PREFIXES(DataReductionProxySettingsTest,
- TestOnProxyEnabledPrefChange);
- FRIEND_TEST_ALL_PREFIXES(DataReductionProxySettingsTest,
- TestInitDataReductionProxyOn);
- FRIEND_TEST_ALL_PREFIXES(DataReductionProxySettingsTest,
- TestInitDataReductionProxyOff);
- FRIEND_TEST_ALL_PREFIXES(DataReductionProxySettingsTest,
- CheckInitMetricsWhenNotAllowed);
- FRIEND_TEST_ALL_PREFIXES(DataReductionProxySettingsTest,
- TestSettingsEnabledStateHistograms);
- FRIEND_TEST_ALL_PREFIXES(DataReductionProxySettingsTest,
- TestDaysSinceEnabled);
- FRIEND_TEST_ALL_PREFIXES(DataReductionProxySettingsTest,
- TestDaysSinceEnabledWithTestClock);
- FRIEND_TEST_ALL_PREFIXES(DataReductionProxySettingsTest,
- TestDaysSinceEnabledExistingUser);
- FRIEND_TEST_ALL_PREFIXES(DataReductionProxySettingsTest,
- TestDaysSinceSavingsCleared);
-
- // Registers the trial "SyntheticDataReductionProxySetting" with the group
- // "Enabled" or "Disabled". Indicates whether the proxy is turned on or not.
- void RegisterDataReductionProxyFieldTrial();
-
- void OnProxyEnabledPrefChange();
-
- // Records data savings percentage histogram at chrome startup, for users who
- // have browsed a reasonable amount. Positive and negative savings are
- // recorded in a separate histogram.
- void RecordStartupSavings() const;
-
- void ResetDataReductionStatistics();
-
- bool unreachable_;
-
- // The number of requests to reload the page with images from the Lo-Fi
- // UI until Lo-Fi is disabled for the remainder of the session.
- int lo_fi_user_requests_for_images_per_session_;
-
- // The number of consecutive sessions where Lo-Fi was disabled for
- // Lo-Fi to be disabled until the next implicit opt out epoch, which may be in
- // a later session, or never.
- int lo_fi_consecutive_session_disables_;
-
- std::unique_ptr<DataReductionProxyService> data_reduction_proxy_service_;
-
- raw_ptr<PrefService> prefs_;
-
- PrefChangeRegistrar registrar_;
-
- SyntheticFieldTrialRegistrationCallback register_synthetic_field_trial_;
-
- // Should not be null.
- raw_ptr<base::Clock> clock_;
-
// Observers to notify when the proxy request headers change or |this| is
// initialized.
base::ObserverList<DataReductionProxySettingsObserver>::Unchecked observers_;
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_test_utils.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_test_utils.cc
deleted file mode 100644
index 4180ef9c1f8..00000000000
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_test_utils.cc
+++ /dev/null
@@ -1,136 +0,0 @@
-// Copyright 2014 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.
-
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_test_utils.h"
-
-#include <stdint.h>
-
-#include "base/bind.h"
-#include "base/command_line.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_piece.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h"
-#include "components/prefs/pref_registry_simple.h"
-#include "components/prefs/scoped_user_pref_update.h"
-#include "components/prefs/testing_pref_service.h"
-
-using testing::_;
-using testing::AnyNumber;
-using testing::Return;
-
-namespace {
-
-const char kProxy[] = "proxy";
-
-} // namespace
-
-namespace data_reduction_proxy {
-
-DataReductionProxySettingsTestBase::DataReductionProxySettingsTestBase() {}
-
-DataReductionProxySettingsTestBase::~DataReductionProxySettingsTestBase() {}
-
-// testing::Test implementation:
-void DataReductionProxySettingsTestBase::SetUp() {
- test_context_ =
- DataReductionProxyTestContext::Builder()
- .WithMockConfig()
- .WithMockDataReductionProxyService()
- .SkipSettingsInitialization()
- .Build();
-
- test_context_->SetDataReductionProxyEnabled(false);
- TestingPrefServiceSimple* pref_service = test_context_->pref_service();
- pref_service->SetInt64(prefs::kDailyHttpContentLengthLastUpdateDate, 0L);
- pref_service->registry()->RegisterDictionaryPref(kProxy);
- pref_service->SetBoolean(prefs::kDataReductionProxyWasEnabledBefore, false);
-
- ResetSettings(nullptr);
-
- ListPrefUpdate original_update(test_context_->pref_service(),
- prefs::kDailyHttpOriginalContentLength);
- ListPrefUpdate received_update(test_context_->pref_service(),
- prefs::kDailyHttpReceivedContentLength);
- for (int64_t i = 0; i < kNumDaysInHistory; i++) {
- original_update->Insert(original_update->GetList().begin(),
- base::Value(base::NumberToString(2 * i)));
- received_update->Insert(received_update->GetList().begin(),
- base::Value(base::NumberToString(i)));
- }
- last_update_time_ = base::Time::Now().LocalMidnight();
- pref_service->SetInt64(prefs::kDailyHttpContentLengthLastUpdateDate,
- last_update_time_.ToInternalValue());
-}
-
-template <class C>
-void DataReductionProxySettingsTestBase::ResetSettings(base::Clock* clock) {
- MockDataReductionProxySettings<C>* settings =
- new MockDataReductionProxySettings<C>();
- if (settings_) {
- settings->data_reduction_proxy_service_ =
- std::move(settings_->data_reduction_proxy_service_);
- } else {
- settings->data_reduction_proxy_service_ = test_context_->TakeService();
- }
- settings->data_reduction_proxy_service_->SetSettingsForTesting(settings);
- settings->prefs_ = test_context_->pref_service();
- if (clock)
- settings->clock_ = clock;
- EXPECT_CALL(*settings, GetOriginalProfilePrefs())
- .Times(AnyNumber())
- .WillRepeatedly(Return(test_context_->pref_service()));
- EXPECT_CALL(*settings, GetLocalStatePrefs())
- .Times(AnyNumber())
- .WillRepeatedly(Return(test_context_->pref_service()));
- settings_.reset(settings);
-}
-
-// Explicitly generate required instantiations.
-template void DataReductionProxySettingsTestBase::ResetSettings<
- DataReductionProxySettings>(base::Clock* clock);
-
-void DataReductionProxySettingsTestBase::CheckOnPrefChange(
- bool enabled,
- bool expected_enabled,
- bool managed) {
- if (managed) {
- test_context_->pref_service()->SetManagedPref(
- prefs::kDataSaverEnabled, std::make_unique<base::Value>(enabled));
- } else {
- test_context_->SetDataReductionProxyEnabled(enabled);
- }
- test_context_->RunUntilIdle();
- // Never expect the proxy to be restricted for pref change tests.
-}
-
-void DataReductionProxySettingsTestBase::InitDataReductionProxy(
- bool enabled_at_startup) {
- settings_->InitDataReductionProxySettings(
- test_context_->pref_service(),
- std::move(settings_->data_reduction_proxy_service_));
- settings_->SetCallbackToRegisterSyntheticFieldTrial(base::BindRepeating(
- &DataReductionProxySettingsTestBase::OnSyntheticFieldTrialRegistration,
- base::Unretained(this)));
-
- test_context_->RunUntilIdle();
-}
-
-void DataReductionProxySettingsTestBase::CheckDataReductionProxySyntheticTrial(
- bool enabled) {
- EXPECT_EQ(enabled ? "Enabled" : "Disabled",
- synthetic_field_trials_["SyntheticDataReductionProxySetting"]);
-}
-
-bool DataReductionProxySettingsTestBase::OnSyntheticFieldTrialRegistration(
- base::StringPiece trial_name,
- base::StringPiece group_name) {
- synthetic_field_trials_[std::string(trial_name)] = std::string(group_name);
- return true;
-}
-
-} // namespace data_reduction_proxy
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_test_utils.h b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_test_utils.h
deleted file mode 100644
index 913e8209b9d..00000000000
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_test_utils.h
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright 2014 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.
-
-#ifndef COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_SETTINGS_TEST_UTILS_H_
-#define COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_SETTINGS_TEST_UTILS_H_
-
-#include <map>
-#include <memory>
-#include <string>
-#include <utility>
-
-#include "base/message_loop/message_pump_type.h"
-#include "base/strings/string_piece.h"
-#include "base/task/single_thread_task_executor.h"
-#include "base/time/clock.h"
-#include "base/time/time.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h"
-#include "components/prefs/testing_pref_service.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-class PrefService;
-
-namespace data_reduction_proxy {
-
-class DataReductionProxyTestContext;
-
-template <class C>
-class MockDataReductionProxySettings : public C {
- public:
- MockDataReductionProxySettings<C>() : C(false) {}
- MOCK_CONST_METHOD0(GetOriginalProfilePrefs, PrefService*());
- MOCK_METHOD0(GetLocalStatePrefs, PrefService*());
- MOCK_CONST_METHOD1(RecordStartupState, void(ProxyStartupState state));
-};
-
-class DataReductionProxySettingsTestBase : public testing::Test {
- public:
- static void AddTestProxyToCommandLine();
-
- DataReductionProxySettingsTestBase();
- ~DataReductionProxySettingsTestBase() override;
-
- void AddProxyToCommandLine();
-
- void SetUp() override;
-
- template <class C>
- void ResetSettings(base::Clock* clock);
- virtual void ResetSettings(base::Clock* clock) = 0;
-
- void CheckMaybeActivateDataReductionProxy(bool initially_enabled,
- bool request_succeeded,
- bool expected_enabled,
- bool expected_restricted,
- bool expected_fallback_restricted);
- void CheckOnPrefChange(bool enabled, bool expected_enabled, bool managed);
- void InitWithStatisticsPrefs();
- void InitDataReductionProxy(bool enabled_at_startup);
- void CheckDataReductionProxySyntheticTrial(bool enabled);
- bool OnSyntheticFieldTrialRegistration(base::StringPiece trial_name,
- base::StringPiece group_name);
-
- protected:
- base::SingleThreadTaskExecutor io_task_executor_{base::MessagePumpType::IO};
- std::unique_ptr<DataReductionProxyTestContext> test_context_;
- std::unique_ptr<DataReductionProxySettings> settings_;
- base::Time last_update_time_;
- std::map<std::string, std::string> synthetic_field_trials_;
-};
-
-// Test implementations should be subclasses of an instantiation of this
-// class parameterized for whatever DataReductionProxySettings class
-// is being tested.
-template <class C>
-class ConcreteDataReductionProxySettingsTest
- : public DataReductionProxySettingsTestBase {
- public:
- typedef MockDataReductionProxySettings<C> MockSettings;
- void ResetSettings(base::Clock* clock) override {
- return DataReductionProxySettingsTestBase::ResetSettings<C>(clock);
- }
-};
-
-} // namespace data_reduction_proxy
-
-#endif // COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_SETTINGS_TEST_UTILS_H_
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_unittest.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_unittest.cc
deleted file mode 100644
index cf0d51796ac..00000000000
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_unittest.cc
+++ /dev/null
@@ -1,347 +0,0 @@
-// Copyright 2014 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.
-
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include "base/command_line.h"
-#include "base/metrics/field_trial.h"
-#include "base/metrics/histogram_samples.h"
-#include "base/test/metrics/histogram_tester.h"
-#include "base/test/mock_entropy_provider.h"
-#include "base/test/simple_test_clock.h"
-#include "base/test/task_environment.h"
-#include "base/time/clock.h"
-#include "base/time/default_clock.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_test_utils.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h"
-#include "components/prefs/pref_registry_simple.h"
-#include "net/base/proxy_server.h"
-#include "net/http/http_util.h"
-#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
-#include "services/network/test/test_url_loader_factory.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace data_reduction_proxy {
-
-class DataReductionProxySettingsTest
- : public ConcreteDataReductionProxySettingsTest<
- DataReductionProxySettings> {
- public:
- void CheckMaybeActivateDataReductionProxy(bool initially_enabled,
- bool request_succeeded,
- bool expected_enabled,
- bool expected_restricted,
- bool expected_fallback_restricted) {
- test_context_->SetDataReductionProxyEnabled(initially_enabled);
- settings_->MaybeActivateDataReductionProxy(false);
- test_context_->RunUntilIdle();
- }
-};
-
-TEST_F(DataReductionProxySettingsTest, TestResetDataReductionStatistics) {
- int64_t original_content_length;
- int64_t received_content_length;
- int64_t last_update_time;
- settings_->ResetDataReductionStatistics();
- settings_->GetContentLengths(kNumDaysInHistory,
- &original_content_length,
- &received_content_length,
- &last_update_time);
- EXPECT_EQ(0L, original_content_length);
- EXPECT_EQ(0L, received_content_length);
- EXPECT_EQ(last_update_time_.ToInternalValue(), last_update_time);
-}
-
-TEST_F(DataReductionProxySettingsTest, TestContentLengths) {
- int64_t original_content_length;
- int64_t received_content_length;
- int64_t last_update_time;
-
- // Request |kNumDaysInHistory| days.
- settings_->GetContentLengths(kNumDaysInHistory,
- &original_content_length,
- &received_content_length,
- &last_update_time);
- const unsigned int days = kNumDaysInHistory;
- // Received content length history values are 0 to |kNumDaysInHistory - 1|.
- int64_t expected_total_received_content_length = (days - 1L) * days / 2;
- // Original content length history values are 0 to
- // |2 * (kNumDaysInHistory - 1)|.
- long expected_total_original_content_length = (days - 1L) * days;
- EXPECT_EQ(expected_total_original_content_length, original_content_length);
- EXPECT_EQ(expected_total_received_content_length, received_content_length);
- EXPECT_EQ(last_update_time_.ToInternalValue(), last_update_time);
-
- // Request |kNumDaysInHistory - 1| days.
- settings_->GetContentLengths(kNumDaysInHistory - 1,
- &original_content_length,
- &received_content_length,
- &last_update_time);
- expected_total_received_content_length -= (days - 1);
- expected_total_original_content_length -= 2 * (days - 1);
- EXPECT_EQ(expected_total_original_content_length, original_content_length);
- EXPECT_EQ(expected_total_received_content_length, received_content_length);
-
- // Request 0 days.
- settings_->GetContentLengths(0,
- &original_content_length,
- &received_content_length,
- &last_update_time);
- expected_total_received_content_length = 0;
- expected_total_original_content_length = 0;
- EXPECT_EQ(expected_total_original_content_length, original_content_length);
- EXPECT_EQ(expected_total_received_content_length, received_content_length);
-
- // Request 1 day. First day had 0 bytes so should be same as 0 days.
- settings_->GetContentLengths(1,
- &original_content_length,
- &received_content_length,
- &last_update_time);
- EXPECT_EQ(expected_total_original_content_length, original_content_length);
- EXPECT_EQ(expected_total_received_content_length, received_content_length);
-}
-
-
-TEST(DataReductionProxySettingsStandaloneTest, TestIsProxyEnabledOrManaged) {
- base::test::SingleThreadTaskEnvironment task_environment{
- base::test::SingleThreadTaskEnvironment::MainThreadType::IO};
- std::unique_ptr<DataReductionProxyTestContext> drp_test_context =
- DataReductionProxyTestContext::Builder()
- .WithMockConfig()
- .WithMockDataReductionProxyService()
- .SkipSettingsInitialization()
- .Build();
-
- drp_test_context->InitSettings();
-
- DataReductionProxySettings* settings = drp_test_context->settings();
-
- drp_test_context->SetDataReductionProxyEnabled(true);
- EXPECT_TRUE(settings->IsDataReductionProxyEnabled());
- EXPECT_FALSE(settings->IsDataReductionProxyManaged());
-
- drp_test_context->SetDataReductionProxyEnabled(false);
- EXPECT_FALSE(settings->IsDataReductionProxyEnabled());
- EXPECT_FALSE(settings->IsDataReductionProxyManaged());
-
- drp_test_context->SetDataReductionProxyEnabled(false);
- drp_test_context->pref_service()->SetManagedPref(
- prefs::kDataSaverEnabled, std::make_unique<base::Value>(false));
- EXPECT_FALSE(settings->IsDataReductionProxyEnabled());
- EXPECT_TRUE(settings->IsDataReductionProxyManaged());
-
- drp_test_context->SetDataReductionProxyEnabled(true);
- drp_test_context->pref_service()->SetManagedPref(
- prefs::kDataSaverEnabled, std::make_unique<base::Value>(true));
- EXPECT_TRUE(settings->IsDataReductionProxyEnabled());
- EXPECT_TRUE(settings->IsDataReductionProxyManaged());
-
- drp_test_context->RunUntilIdle();
-}
-
-
-TEST_F(DataReductionProxySettingsTest, TestMaybeActivateDataReductionProxy) {
- // Initialize the pref member in |settings_| without the usual callback
- // so it won't trigger MaybeActivateDataReductionProxy when the pref value
- // is set.
-
- // TODO(bengr): Test enabling/disabling while a secure proxy check is
- // outstanding.
- // The proxy is enabled and unrestricted initially.
- // Request succeeded but with bad response, expect proxy to be restricted.
- CheckMaybeActivateDataReductionProxy(true, true, true, true, false);
- // Request succeeded with valid response, expect proxy to be unrestricted.
- CheckMaybeActivateDataReductionProxy(true, true, true, false, false);
- // Request failed, expect proxy to be enabled but restricted.
- CheckMaybeActivateDataReductionProxy(true, false, true, true, false);
- // The proxy is disabled initially. No secure proxy checks should take place,
- // and so the state should not change.
- CheckMaybeActivateDataReductionProxy(false, true, false, false, false);
-}
-
-TEST_F(DataReductionProxySettingsTest, TestInitDataReductionProxyOn) {
- MockSettings* settings = static_cast<MockSettings*>(settings_.get());
- EXPECT_CALL(*settings, RecordStartupState(PROXY_ENABLED));
-
- test_context_->SetDataReductionProxyEnabled(true);
- InitDataReductionProxy(true);
- CheckDataReductionProxySyntheticTrial(true);
-}
-
-TEST_F(DataReductionProxySettingsTest, TestInitDataReductionProxyOff) {
- // InitDataReductionProxySettings with the preference off will directly call
- // LogProxyState.
- MockSettings* settings = static_cast<MockSettings*>(settings_.get());
- EXPECT_CALL(*settings, RecordStartupState(PROXY_DISABLED));
-
- test_context_->SetDataReductionProxyEnabled(false);
- InitDataReductionProxy(false);
- CheckDataReductionProxySyntheticTrial(false);
-}
-
-TEST_F(DataReductionProxySettingsTest, TestEnableProxyFromCommandLine) {
- MockSettings* settings = static_cast<MockSettings*>(settings_.get());
- EXPECT_CALL(*settings, RecordStartupState(PROXY_ENABLED));
-
- base::CommandLine::ForCurrentProcess()->AppendSwitch(
- switches::kEnableDataReductionProxy);
- InitDataReductionProxy(true);
- CheckDataReductionProxySyntheticTrial(true);
-}
-
-TEST_F(DataReductionProxySettingsTest, TestSetDataReductionProxyEnabled) {
- MockSettings* settings = static_cast<MockSettings*>(settings_.get());
- EXPECT_CALL(*settings, RecordStartupState(PROXY_ENABLED));
- test_context_->SetDataReductionProxyEnabled(true);
- InitDataReductionProxy(true);
-
- test_context_->SetDataReductionProxyEnabled(false);
- test_context_->RunUntilIdle();
- CheckDataReductionProxySyntheticTrial(false);
-
- test_context_->SetDataReductionProxyEnabled(true);
- test_context_->RunUntilIdle();
- CheckDataReductionProxySyntheticTrial(true);
-}
-
-TEST_F(DataReductionProxySettingsTest, TestSettingsEnabledStateHistograms) {
- const char kUMAEnabledState[] = "DataReductionProxy.EnabledState";
- base::HistogramTester histogram_tester;
-
- // No settings state histograms should be recorded during startup.
- test_context_->RunUntilIdle();
- histogram_tester.ExpectTotalCount(kUMAEnabledState, 0);
-
- test_context_->SetDataReductionProxyEnabled(true);
- settings_->MaybeActivateDataReductionProxy(false);
- test_context_->RunUntilIdle();
- histogram_tester.ExpectBucketCount(
- kUMAEnabledState, DATA_REDUCTION_SETTINGS_ACTION_OFF_TO_ON, 1);
- histogram_tester.ExpectBucketCount(
- kUMAEnabledState, DATA_REDUCTION_SETTINGS_ACTION_ON_TO_OFF, 0);
-
- test_context_->SetDataReductionProxyEnabled(false);
- settings_->MaybeActivateDataReductionProxy(false);
- test_context_->RunUntilIdle();
- histogram_tester.ExpectBucketCount(
- kUMAEnabledState, DATA_REDUCTION_SETTINGS_ACTION_OFF_TO_ON, 1);
- histogram_tester.ExpectBucketCount(
- kUMAEnabledState, DATA_REDUCTION_SETTINGS_ACTION_ON_TO_OFF, 1);
-}
-
-// Verify that the UMA metric and the pref is recorded correctly when the user
-// enables the data reduction proxy.
-TEST_F(DataReductionProxySettingsTest, TestDaysSinceEnabledWithTestClock) {
- const char kUMAEnabledState[] = "DataReductionProxy.DaysSinceEnabled";
- base::SimpleTestClock clock;
- clock.Advance(base::Days(1));
- ResetSettings(&clock);
-
- base::Time last_enabled_time = clock.Now();
-
- {
- base::HistogramTester histogram_tester;
-
- test_context_->RunUntilIdle();
- histogram_tester.ExpectTotalCount(kUMAEnabledState, 0);
-
- // Enable data reduction proxy. The metric should be recorded.
- test_context_->SetDataReductionProxyEnabled(true);
- settings_->MaybeActivateDataReductionProxy(false);
- test_context_->RunUntilIdle();
-
- last_enabled_time = clock.Now();
-
- EXPECT_EQ(
- last_enabled_time,
- base::Time::FromInternalValue(test_context_->pref_service()->GetInt64(
- prefs::kDataReductionProxyLastEnabledTime)));
- histogram_tester.ExpectUniqueSample(kUMAEnabledState, 0, 1);
- }
-
- {
- // Simulate turning off and on of data reduction proxy while Chromium is
- // running.
- test_context_->SetDataReductionProxyEnabled(false);
- settings_->MaybeActivateDataReductionProxy(false);
- clock.Advance(base::Days(1));
- last_enabled_time = clock.Now();
-
- test_context_->SetDataReductionProxyEnabled(true);
- base::HistogramTester histogram_tester;
- settings_->MaybeActivateDataReductionProxy(false /* at_startup */);
- test_context_->RunUntilIdle();
- histogram_tester.ExpectUniqueSample(kUMAEnabledState, 0, 1);
- EXPECT_EQ(
- last_enabled_time,
- base::Time::FromInternalValue(test_context_->pref_service()->GetInt64(
- prefs::kDataReductionProxyLastEnabledTime)));
- }
-
- {
- // Advance clock by a random number of days.
- int advance_clock_days = 42;
- clock.Advance(base::Days(advance_clock_days));
- base::HistogramTester histogram_tester;
- // Simulate Chromium start up. Data reduction proxy was enabled
- // |advance_clock_days| ago.
- settings_->MaybeActivateDataReductionProxy(true /* at_startup */);
- test_context_->RunUntilIdle();
- histogram_tester.ExpectUniqueSample(kUMAEnabledState, advance_clock_days,
- 1);
- EXPECT_EQ(
- last_enabled_time,
- base::Time::FromInternalValue(test_context_->pref_service()->GetInt64(
- prefs::kDataReductionProxyLastEnabledTime)));
- }
-}
-
-// Verify that the pref and the UMA metric are not recorded for existing users
-// that already have data reduction proxy on.
-TEST(DataReductionProxySettingsStandaloneTest,
- TestDaysSinceEnabledExistingUser) {
- base::test::SingleThreadTaskEnvironment task_environment{
- base::test::SingleThreadTaskEnvironment::MainThreadType::IO};
- std::unique_ptr<DataReductionProxyTestContext> drp_test_context =
- DataReductionProxyTestContext::Builder()
- .WithMockConfig()
- .WithMockDataReductionProxyService()
- .SkipSettingsInitialization()
- .Build();
-
- drp_test_context->InitSettings();
-
- base::HistogramTester histogram_tester;
-
- // Simulate Chromium startup with data reduction proxy already enabled.
- drp_test_context->settings()->MaybeActivateDataReductionProxy(
- true /* at_startup */);
- drp_test_context->RunUntilIdle();
- histogram_tester.ExpectTotalCount("DataReductionProxy.DaysSinceEnabled", 0);
- EXPECT_EQ(0, drp_test_context->pref_service()->GetInt64(
- prefs::kDataReductionProxyLastEnabledTime));
-}
-
-TEST_F(DataReductionProxySettingsTest, TestGetDailyContentLengths) {
- ContentLengthList result =
- settings_->GetDailyContentLengths(prefs::kDailyHttpOriginalContentLength);
-
- ASSERT_FALSE(result.empty());
- ASSERT_EQ(kNumDaysInHistory, result.size());
-
- for (size_t i = 0; i < kNumDaysInHistory; ++i) {
- long expected_length =
- static_cast<long>((kNumDaysInHistory - 1 - i) * 2);
- ASSERT_EQ(expected_length, result[i]);
- }
-}
-
-} // namespace data_reduction_proxy
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc
deleted file mode 100644
index 078e0fe8990..00000000000
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc
+++ /dev/null
@@ -1,311 +0,0 @@
-// Copyright 2015 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.
-
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h"
-
-#include <map>
-#include <memory>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/command_line.h"
-#include "base/memory/ptr_util.h"
-#include "base/run_loop.h"
-#include "base/strings/string_piece.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_prefs.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h"
-#include "components/data_reduction_proxy/core/browser/data_store.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h"
-#include "components/prefs/pref_registry_simple.h"
-#include "components/prefs/testing_pref_service.h"
-#include "net/base/network_delegate_impl.h"
-#include "net/proxy_resolution/proxy_config.h"
-#include "net/proxy_resolution/proxy_info.h"
-#include "net/proxy_resolution/proxy_list.h"
-#include "services/network/test/test_network_connection_tracker.h"
-#include "services/network/test/test_network_quality_tracker.h"
-#include "url/gurl.h"
-
-namespace {
-
-enum TestContextOptions {
- // Permits mocking of the underlying |DataReductionProxyConfig|.
- USE_MOCK_CONFIG = 0x1,
- // Construct, but do not initialize the |DataReductionProxySettings| object.
- // Primarily used for testing of the |DataReductionProxySettings| object
- // itself.
- SKIP_SETTINGS_INITIALIZATION = 0x2,
- // Permits mocking of the underlying |DataReductionProxyService|.
- USE_MOCK_SERVICE = 0x4,
-};
-
-} // namespace
-
-namespace data_reduction_proxy {
-
-MockDataReductionProxyService::MockDataReductionProxyService(
- data_use_measurement::DataUseMeasurement* data_use_measurement,
- DataReductionProxySettings* settings,
- PrefService* prefs,
- const scoped_refptr<base::SingleThreadTaskRunner>& task_runner)
- : DataReductionProxyService(settings,
- prefs,
- std::make_unique<TestDataStore>(),
- data_use_measurement,
- task_runner,
- base::TimeDelta()) {}
-
-MockDataReductionProxyService::~MockDataReductionProxyService() {}
-
-TestDataReductionProxyService::TestDataReductionProxyService(
- data_use_measurement::DataUseMeasurement* data_use_measurement,
- DataReductionProxySettings* settings,
- PrefService* prefs,
- const scoped_refptr<base::SequencedTaskRunner>& db_task_runner)
- : DataReductionProxyService(settings,
- prefs,
- std::make_unique<TestDataStore>(),
- data_use_measurement,
- db_task_runner,
- base::TimeDelta()) {}
-
-TestDataReductionProxyService::~TestDataReductionProxyService() {}
-
-TestDataStore::TestDataStore() {}
-
-TestDataStore::~TestDataStore() {}
-
-DataStore::Status TestDataStore::Get(base::StringPiece key,
- std::string* value) {
- auto value_iter = map_.find(std::string(key));
- if (value_iter == map_.end())
- return NOT_FOUND;
-
- value->assign(value_iter->second);
- return OK;
-}
-
-DataStore::Status TestDataStore::Put(
- const std::map<std::string, std::string>& map) {
- for (auto iter = map.begin(); iter != map.end(); ++iter)
- map_[iter->first] = iter->second;
-
- return OK;
-}
-
-DataStore::Status TestDataStore::Delete(base::StringPiece key) {
- map_.erase(std::string(key));
-
- return OK;
-}
-
-DataStore::Status TestDataStore::RecreateDB() {
- map_.clear();
-
- return OK;
-}
-
-DataReductionProxyTestContext::Builder::Builder()
- : use_mock_config_(false),
- use_mock_service_(false),
- skip_settings_initialization_(false),
- data_use_measurement_(
- std::make_unique<data_use_measurement::DataUseMeasurement>(
- nullptr,
- network::TestNetworkConnectionTracker::GetInstance())) {}
-
-DataReductionProxyTestContext::Builder::~Builder() {}
-
-DataReductionProxyTestContext::Builder&
-DataReductionProxyTestContext::Builder::WithMockConfig() {
- use_mock_config_ = true;
- return *this;
-}
-
-DataReductionProxyTestContext::Builder&
-DataReductionProxyTestContext::Builder::WithMockDataReductionProxyService() {
- use_mock_service_ = true;
- return *this;
-}
-
-DataReductionProxyTestContext::Builder&
-DataReductionProxyTestContext::Builder::SkipSettingsInitialization() {
- skip_settings_initialization_ = true;
- return *this;
-}
-
-DataReductionProxyTestContext::Builder&
-DataReductionProxyTestContext::Builder::WithSettings(
- std::unique_ptr<DataReductionProxySettings> settings) {
- settings_ = std::move(settings);
- return *this;
-}
-
-std::unique_ptr<DataReductionProxyTestContext>
-DataReductionProxyTestContext::Builder::Build() {
- unsigned int test_context_flags = 0;
- scoped_refptr<base::SingleThreadTaskRunner> task_runner =
- base::ThreadTaskRunnerHandle::Get();
- std::unique_ptr<TestingPrefServiceSimple> pref_service(
- new TestingPrefServiceSimple());
-
- if (use_mock_config_) {
- test_context_flags |= USE_MOCK_CONFIG;
- } else {
- test_context_flags ^= USE_MOCK_CONFIG;
- }
-
-
- if (!settings_)
- settings_ = std::make_unique<DataReductionProxySettings>(false);
- if (skip_settings_initialization_) {
- test_context_flags |= SKIP_SETTINGS_INITIALIZATION;
- }
-
- pref_service->registry()->RegisterBooleanPref(prefs::kDataSaverEnabled,
- false);
- RegisterSimpleProfilePrefs(pref_service->registry());
-
- std::unique_ptr<DataReductionProxyService> service;
- if (use_mock_service_) {
- test_context_flags |= USE_MOCK_SERVICE;
- service = std::make_unique<MockDataReductionProxyService>(
- data_use_measurement_.get(), settings_.get(), pref_service.get(),
- task_runner);
- } else {
- service = std::make_unique<TestDataReductionProxyService>(
- data_use_measurement_.get(), settings_.get(), pref_service.get(),
- task_runner);
- }
-
- std::unique_ptr<DataReductionProxyTestContext> test_context(
- new DataReductionProxyTestContext(
- std::move(data_use_measurement_), task_runner,
- std::move(pref_service), std::move(settings_), std::move(service),
- test_context_flags));
-
- if (!skip_settings_initialization_)
- test_context->InitSettingsWithoutCheck();
-
- return test_context;
-}
-
-DataReductionProxyTestContext::DataReductionProxyTestContext(
- std::unique_ptr<data_use_measurement::DataUseMeasurement>
- data_use_measurement,
- const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
- std::unique_ptr<TestingPrefServiceSimple> simple_pref_service,
- std::unique_ptr<DataReductionProxySettings> settings,
- std::unique_ptr<DataReductionProxyService> service,
- unsigned int test_context_flags)
- : data_use_measurement_(std::move(data_use_measurement)),
- test_context_flags_(test_context_flags),
- task_runner_(task_runner),
- simple_pref_service_(std::move(simple_pref_service)),
- settings_(std::move(settings)),
- service_(std::move(service)) {
- DCHECK(data_use_measurement_);
-
- if (service_)
- data_reduction_proxy_service_ = service_.get();
- else
- data_reduction_proxy_service_ = settings_->data_reduction_proxy_service();
-}
-
-DataReductionProxyTestContext::~DataReductionProxyTestContext() {
- DestroySettings();
-}
-
-void DataReductionProxyTestContext::RegisterDataReductionProxyEnabledPref() {
- simple_pref_service_->registry()->RegisterBooleanPref(
- prefs::kDataSaverEnabled, false);
-}
-
-void DataReductionProxyTestContext::SetDataReductionProxyEnabled(bool enabled) {
- // Set the command line so that |IsDataSaverEnabledByUser| returns as expected
- // on all platforms.
- base::CommandLine* cmd = base::CommandLine::ForCurrentProcess();
- if (enabled) {
- cmd->AppendSwitch(switches::kEnableDataReductionProxy);
- } else {
- cmd->RemoveSwitch(switches::kEnableDataReductionProxy);
- }
-
- simple_pref_service_->SetBoolean(prefs::kDataSaverEnabled, enabled);
-}
-
-bool DataReductionProxyTestContext::IsDataReductionProxyEnabled() const {
- return simple_pref_service_->GetBoolean(prefs::kDataSaverEnabled);
-}
-
-void DataReductionProxyTestContext::RunUntilIdle() {
- base::RunLoop().RunUntilIdle();
-}
-
-void DataReductionProxyTestContext::InitSettings() {
- DCHECK(test_context_flags_ & SKIP_SETTINGS_INITIALIZATION);
- InitSettingsWithoutCheck();
-}
-
-void DataReductionProxyTestContext::DestroySettings() {
- // Force destruction of |DBDataOwner|, which lives on DB task runner and is
- // indirectly owned by |settings_|.
- if (settings_) {
- settings_.reset();
- RunUntilIdle();
- }
-}
-
-void DataReductionProxyTestContext::InitSettingsWithoutCheck() {
- DCHECK(service_);
- settings_->InitDataReductionProxySettings(simple_pref_service_.get(),
- std::move(service_));
-}
-
-std::unique_ptr<DataReductionProxyService>
-DataReductionProxyTestContext::TakeService() {
- DCHECK(service_);
- DCHECK(test_context_flags_ & SKIP_SETTINGS_INITIALIZATION);
- return std::move(service_);
-}
-
-void DataReductionProxyTestContext::
- EnableDataReductionProxyWithSecureProxyCheckSuccess() {
- // |settings_| needs to have been initialized, since a
- // |DataReductionProxyService| is needed in order to issue the secure proxy
- // check.
- DCHECK(data_reduction_proxy_service());
-
- // Set the pref to cause the secure proxy check to be issued.
- SetDataReductionProxyEnabled(true);
- RunUntilIdle();
-}
-
-
-
-DataReductionProxyService*
-DataReductionProxyTestContext::data_reduction_proxy_service() const {
- return data_reduction_proxy_service_;
-}
-
-TestDataReductionProxyService*
-DataReductionProxyTestContext::test_data_reduction_proxy_service() const {
- DCHECK(!(test_context_flags_ & USE_MOCK_SERVICE));
- return static_cast<TestDataReductionProxyService*>(
- data_reduction_proxy_service());
-}
-
-MockDataReductionProxyService*
-DataReductionProxyTestContext::mock_data_reduction_proxy_service() const {
- DCHECK(!(test_context_flags_ & SKIP_SETTINGS_INITIALIZATION));
- DCHECK(test_context_flags_ & USE_MOCK_SERVICE);
- return static_cast<MockDataReductionProxyService*>(
- data_reduction_proxy_service());
-}
-
-} // namespace data_reduction_proxy
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h
deleted file mode 100644
index ac87bacc3e7..00000000000
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h
+++ /dev/null
@@ -1,228 +0,0 @@
-// Copyright 2015 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.
-
-#ifndef COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_TEST_UTILS_H_
-#define COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_TEST_UTILS_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <memory>
-#include <string>
-
-#include "base/memory/raw_ptr.h"
-#include "base/memory/ref_counted.h"
-#include "base/strings/string_piece.h"
-#include "base/task/single_thread_task_runner.h"
-#include "base/time/clock.h"
-#include "base/time/tick_clock.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_test_utils.h"
-#include "components/data_reduction_proxy/core/browser/data_store.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
-#include "components/data_use_measurement/core/data_use_measurement.h"
-#include "components/prefs/pref_registry_simple.h"
-#include "components/prefs/testing_pref_service.h"
-#include "net/base/backoff_entry.h"
-#include "net/base/proxy_server.h"
-#include "testing/gmock/include/gmock/gmock.h"
-
-class TestingPrefServiceSimple;
-
-namespace data_reduction_proxy {
-
-class DataReductionProxySettings;
-
-
-// Test version of |DataReductionProxyService|, which permits mocking of various
-// methods.
-class MockDataReductionProxyService : public DataReductionProxyService {
- public:
- MockDataReductionProxyService(
- data_use_measurement::DataUseMeasurement* data_use_measurement,
- DataReductionProxySettings* settings,
- PrefService* prefs,
- const scoped_refptr<base::SingleThreadTaskRunner>& task_runner);
- ~MockDataReductionProxyService() override;
-
- MOCK_METHOD2(SetProxyPrefs, void(bool enabled, bool at_startup));
- MOCK_METHOD7(UpdateContentLengths,
- void(int64_t data_used,
- int64_t original_size,
- bool data_reduction_proxy_enabled,
- const std::string& mime_type,
- bool is_user_traffic,
- data_use_measurement::DataUseUserData::DataUseContentType
- content_type,
- int32_t service_hash_code));
- MOCK_METHOD3(UpdateDataUseForHost,
- void(int64_t network_bytes,
- int64_t original_bytes,
- const std::string& host));
-};
-
-// Test version of |DataReductionProxyService|, which bypasses initialization in
-// the constructor in favor of explicitly passing in its owned classes. This
-// permits the use of test/mock versions of those classes.
-class TestDataReductionProxyService : public DataReductionProxyService {
- public:
- TestDataReductionProxyService(
- data_use_measurement::DataUseMeasurement* data_use_measurement,
- DataReductionProxySettings* settings,
- PrefService* prefs,
- const scoped_refptr<base::SequencedTaskRunner>& db_task_runner);
- ~TestDataReductionProxyService() override;
-
- bool ignore_blocklist() const { return ignore_blocklist_; }
-
- private:
- // Whether the long term blocklist rules should be ignored.
- bool ignore_blocklist_ = false;
-};
-
-// Test version of |DataStore|. Uses an in memory hash map to store data.
-class TestDataStore : public data_reduction_proxy::DataStore {
- public:
- TestDataStore();
-
- ~TestDataStore() override;
-
- void InitializeOnDBThread() override {}
-
- DataStore::Status Get(base::StringPiece key, std::string* value) override;
-
- DataStore::Status Put(const std::map<std::string, std::string>& map) override;
-
- DataStore::Status Delete(base::StringPiece key) override;
-
- DataStore::Status RecreateDB() override;
-
- std::map<std::string, std::string>* map() { return &map_; }
-
- private:
- std::map<std::string, std::string> map_;
-};
-
-// Builds a test version of the Data Reduction Proxy stack for use in tests.
-// Takes in various |TestContextOptions| which controls the behavior of the
-// underlying objects.
-class DataReductionProxyTestContext {
- public:
- // Allows for a fluent builder interface to configure what kind of objects
- // (test vs mock vs real) are used by the |DataReductionProxyTestContext|.
- class Builder {
- public:
- Builder();
-
- ~Builder();
-
- // Specifies the use of |MockDataReductionProxyConfig| instead of
- // |TestDataReductionProxyConfig|.
- Builder& WithMockConfig();
-
- // Specifies the use of |MockDataReductionProxyService| instead of
- // |DataReductionProxyService|.
- Builder& WithMockDataReductionProxyService();
-
- // Construct, but do not initialize the |DataReductionProxySettings| object.
- Builder& SkipSettingsInitialization();
-
- // Specifies a settings object to use.
- Builder& WithSettings(std::unique_ptr<DataReductionProxySettings> settings);
-
- // Creates a |DataReductionProxyTestContext|. Owned by the caller.
- std::unique_ptr<DataReductionProxyTestContext> Build();
-
- private:
- bool use_mock_config_;
- bool use_mock_service_;
- bool skip_settings_initialization_;
- std::unique_ptr<DataReductionProxySettings> settings_;
- std::unique_ptr<data_use_measurement::DataUseMeasurement>
- data_use_measurement_;
- };
-
- DataReductionProxyTestContext(const DataReductionProxyTestContext&) = delete;
- DataReductionProxyTestContext& operator=(
- const DataReductionProxyTestContext&) = delete;
-
- virtual ~DataReductionProxyTestContext();
-
- // Registers, sets, and gets the preference used to enable the Data Reduction
- // Proxy, respectively.
- void RegisterDataReductionProxyEnabledPref();
- void SetDataReductionProxyEnabled(bool enabled);
- bool IsDataReductionProxyEnabled() const;
-
- // Waits while executing all tasks on the current SingleThreadTaskRunner.
- void RunUntilIdle();
-
- // Initializes the |DataReductionProxySettings| object. Can only be called if
- // built with SkipSettingsInitialization.
- void InitSettings();
-
- // Destroys the |DataReductionProxySettings| object and waits until objects on
- // the DB task runner are destroyed.
- void DestroySettings();
-
- // Takes ownership of the |DataReductionProxyService| object. Can only be
- // called if built with SkipSettingsInitialization.
- std::unique_ptr<DataReductionProxyService> TakeService();
-
- // Enable the Data Reduction Proxy, simulating a successful secure proxy
- // check. This can only be called if not built with WithTestConfigurator,
- // |settings_| has been initialized, and |this| was built with a
- // |net::MockClientSocketFactory| specified.
- void EnableDataReductionProxyWithSecureProxyCheckSuccess();
-
-
- DataReductionProxyService* data_reduction_proxy_service() const;
-
- // Returns the underlying |TestDataReductionProxyService|. This can only be
- // called if not built with WithMockDataReductionProxyService.
- TestDataReductionProxyService* test_data_reduction_proxy_service() const;
-
- // Returns the underlying |MockDataReductionProxyService|. This can only
- // be called if built with WithMockDataReductionProxyService.
- MockDataReductionProxyService* mock_data_reduction_proxy_service() const;
-
- scoped_refptr<base::SingleThreadTaskRunner> task_runner() const {
- return task_runner_;
- }
-
- TestingPrefServiceSimple* pref_service() {
- return simple_pref_service_.get();
- }
-
- DataReductionProxySettings* settings() const { return settings_.get(); }
-
- void InitSettingsWithoutCheck();
-
-
- private:
- DataReductionProxyTestContext(
- std::unique_ptr<data_use_measurement::DataUseMeasurement>
- data_use_measurement,
- const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
- std::unique_ptr<TestingPrefServiceSimple> simple_pref_service,
- std::unique_ptr<DataReductionProxySettings> settings,
- std::unique_ptr<DataReductionProxyService> service,
- unsigned int test_context_flags);
-
- std::unique_ptr<data_use_measurement::DataUseMeasurement>
- data_use_measurement_;
-
- unsigned int test_context_flags_;
-
- scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
- std::unique_ptr<TestingPrefServiceSimple> simple_pref_service_;
-
- std::unique_ptr<DataReductionProxySettings> settings_;
- raw_ptr<DataReductionProxyService> data_reduction_proxy_service_;
- std::unique_ptr<DataReductionProxyService> service_;
-};
-
-} // namespace data_reduction_proxy
-
-#endif // COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_TEST_UTILS_H_
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_store.cc b/chromium/components/data_reduction_proxy/core/browser/data_store.cc
deleted file mode 100644
index 782a1944b47..00000000000
--- a/chromium/components/data_reduction_proxy/core/browser/data_store.cc
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2015 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.
-
-#include "components/data_reduction_proxy/core/browser/data_store.h"
-
-namespace data_reduction_proxy {
-
-DataStore::DataStore() {
-}
-
-DataStore::~DataStore() {
-}
-
-void DataStore::InitializeOnDBThread() {
-}
-
-DataStore::Status DataStore::Get(base::StringPiece key, std::string* value) {
- return DataStore::Status::NOT_FOUND;
-}
-
-DataStore::Status DataStore::Put(
- const std::map<std::string, std::string>& map) {
- return DataStore::Status::OK;
-}
-
-DataStore::Status DataStore::Delete(base::StringPiece key) {
- return DataStore::Status::OK;
-}
-
-DataStore::Status DataStore::RecreateDB() {
- return DataStore::Status::OK;
-}
-
-} // namespace data_reduction_proxy
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_store.h b/chromium/components/data_reduction_proxy/core/browser/data_store.h
deleted file mode 100644
index 7b90f1bc7af..00000000000
--- a/chromium/components/data_reduction_proxy/core/browser/data_store.h
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2015 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.
-
-#ifndef COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_STORE_H_
-#define COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_STORE_H_
-
-#include <map>
-#include <string>
-
-#include "base/strings/string_piece.h"
-
-namespace data_reduction_proxy {
-
-// Interface for a permanent key/value store used by the Data Reduction Proxy
-// component. This class has no-op methods for clients that do not want to
-// support a permanent store.
-class DataStore {
- public:
- // Values are used in UMA. Do not change existing values; only append to the
- // end. STATUS_MAX should always be last element.
- enum Status { OK, NOT_FOUND, CORRUPTED, IO_ERROR, MISC_ERROR, STATUS_MAX };
-
- DataStore();
-
- DataStore(const DataStore&) = delete;
- DataStore& operator=(const DataStore&) = delete;
-
- virtual ~DataStore();
-
- // Initializes the store on DB sequenced task runner.
- virtual void InitializeOnDBThread();
-
- // Gets the value from the store for the provided key.
- virtual Status Get(base::StringPiece key, std::string* value);
-
- // Persists the provided keys and values into the store.
- virtual Status Put(const std::map<std::string, std::string>& map);
-
- virtual Status Delete(base::StringPiece key);
-
- // Deletes the LevelDB and recreates it.
- virtual Status RecreateDB();
-};
-
-} // namespace data_reduction_proxy
-
-#endif // COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_STORE_H_
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_store_impl.cc b/chromium/components/data_reduction_proxy/core/browser/data_store_impl.cc
deleted file mode 100644
index 043ed02b896..00000000000
--- a/chromium/components/data_reduction_proxy/core/browser/data_store_impl.cc
+++ /dev/null
@@ -1,159 +0,0 @@
-// Copyright 2015 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.
-
-#include "components/data_reduction_proxy/core/browser/data_store_impl.h"
-
-#include <stdint.h>
-
-#include "base/files/file_util.h"
-#include "base/logging.h"
-#include "base/memory/ref_counted.h"
-#include "base/metrics/histogram_macros.h"
-#include "components/data_reduction_proxy/proto/data_store.pb.h"
-#include "third_party/leveldatabase/env_chromium.h"
-#include "third_party/leveldatabase/leveldb_chrome.h"
-#include "third_party/leveldatabase/src/include/leveldb/db.h"
-#include "third_party/leveldatabase/src/include/leveldb/options.h"
-#include "third_party/leveldatabase/src/include/leveldb/status.h"
-#include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
-
-namespace {
-
-const base::FilePath::CharType kDBName[] =
- FILE_PATH_LITERAL("data_reduction_proxy_leveldb");
-
-data_reduction_proxy::DataStore::Status LevelDbToDRPStoreStatus(
- leveldb::Status leveldb_status) {
- if (leveldb_status.ok())
- return data_reduction_proxy::DataStore::Status::OK;
- if (leveldb_status.IsNotFound())
- return data_reduction_proxy::DataStore::Status::NOT_FOUND;
- if (leveldb_status.IsCorruption())
- return data_reduction_proxy::DataStore::Status::CORRUPTED;
- if (leveldb_status.IsIOError())
- return data_reduction_proxy::DataStore::Status::IO_ERROR;
-
- return data_reduction_proxy::DataStore::Status::MISC_ERROR;
-}
-
-} // namespace
-
-namespace data_reduction_proxy {
-
-DataStoreImpl::DataStoreImpl(const base::FilePath& profile_path)
- : profile_path_(profile_path) {
- sequence_checker_.DetachFromSequence();
-}
-
-DataStoreImpl::~DataStoreImpl() {
- DCHECK(sequence_checker_.CalledOnValidSequence());
-}
-
-void DataStoreImpl::InitializeOnDBThread() {
- DCHECK(sequence_checker_.CalledOnValidSequence());
- DCHECK(!db_);
-
- DataStore::Status status = OpenDB();
- if (status == CORRUPTED)
- RecreateDB();
-}
-
-DataStore::Status DataStoreImpl::Get(base::StringPiece key,
- std::string* value) {
- DCHECK(sequence_checker_.CalledOnValidSequence());
-
- if (!db_)
- return MISC_ERROR;
-
- leveldb::ReadOptions read_options;
- read_options.verify_checksums = true;
- leveldb::Slice slice(key.data(), key.size());
- leveldb::Status status = db_->Get(read_options, slice, value);
- if (status.IsCorruption())
- RecreateDB();
-
- return LevelDbToDRPStoreStatus(status);
-}
-
-DataStore::Status DataStoreImpl::Put(
- const std::map<std::string, std::string>& map) {
- DCHECK(sequence_checker_.CalledOnValidSequence());
-
- if (!db_)
- return MISC_ERROR;
-
- leveldb::WriteBatch batch;
- for (const auto& iter : map) {
- batch.Put(iter.first, iter.second);
- }
-
- leveldb::WriteOptions write_options;
- leveldb::Status status = db_->Write(write_options, &batch);
- if (status.IsCorruption())
- RecreateDB();
-
- return LevelDbToDRPStoreStatus(status);
-}
-
-DataStore::Status DataStoreImpl::Delete(base::StringPiece key) {
- DCHECK(sequence_checker_.CalledOnValidSequence());
-
- if (!db_)
- return MISC_ERROR;
-
- leveldb::Slice slice(key.data(), key.size());
- leveldb::WriteOptions write_options;
- leveldb::Status status = db_->Delete(write_options, slice);
- if (status.IsCorruption())
- RecreateDB();
-
- return LevelDbToDRPStoreStatus(status);
-}
-
-DataStore::Status DataStoreImpl::OpenDB() {
- DCHECK(sequence_checker_.CalledOnValidSequence());
-
- leveldb_env::Options options;
- options.create_if_missing = true;
- options.paranoid_checks = true;
- // Deletes to buckets not found are stored in the log. Use a new log so that
- // these log entries are deleted.
- options.reuse_logs = false;
- std::string db_name = profile_path_.Append(kDBName).AsUTF8Unsafe();
- db_.reset();
- Status status =
- LevelDbToDRPStoreStatus(leveldb_env::OpenDB(options, db_name, &db_));
- UMA_HISTOGRAM_ENUMERATION("DataReductionProxy.LevelDBOpenStatus", status,
- STATUS_MAX);
-
- if (status != OK)
- LOG(ERROR) << "Failed to open Data Reduction Proxy DB: " << status;
-
- if (db_) {
- leveldb::Range range;
- uint64_t size;
- // We try to capture the size of the entire DB by using the highest and
- // lowest keys.
- range.start = "";
- range.limit = "z"; // Keys starting with 'z' will not be included.
- db_->GetApproximateSizes(&range, 1, &size);
- UMA_HISTOGRAM_MEMORY_KB("DataReductionProxy.LevelDBSize", size / 1024);
- }
-
- return status;
-}
-
-DataStore::Status DataStoreImpl::RecreateDB() {
- DCHECK(sequence_checker_.CalledOnValidSequence());
-
- db_.reset();
- const base::FilePath db_path = profile_path_.Append(kDBName);
- leveldb::Status s = leveldb_chrome::DeleteDB(db_path, leveldb::Options());
- if (!s.ok())
- return LevelDbToDRPStoreStatus(s);
-
- return OpenDB();
-}
-
-} // namespace data_reduction_proxy
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_store_impl.h b/chromium/components/data_reduction_proxy/core/browser/data_store_impl.h
deleted file mode 100644
index fc5f253c311..00000000000
--- a/chromium/components/data_reduction_proxy/core/browser/data_store_impl.h
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2015 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.
-
-#ifndef COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_STORE_IMPL_H_
-#define COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_STORE_IMPL_H_
-
-#include <map>
-#include <memory>
-#include <string>
-
-#include "base/files/file_path.h"
-#include "base/sequence_checker.h"
-#include "base/strings/string_piece.h"
-#include "components/data_reduction_proxy/core/browser/data_store.h"
-
-namespace leveldb {
-class DB;
-}
-
-namespace data_reduction_proxy {
-
-// Implementation of |DataStore| using LevelDB.
-class DataStoreImpl : public DataStore {
- public:
- explicit DataStoreImpl(const base::FilePath& profile_path);
-
- DataStoreImpl(const DataStoreImpl&) = delete;
- DataStoreImpl& operator=(const DataStoreImpl&) = delete;
-
- ~DataStoreImpl() override;
-
- // Overrides of DataStore.
- void InitializeOnDBThread() override;
-
- Status Get(base::StringPiece key, std::string* value) override;
-
- Status Put(const std::map<std::string, std::string>& map) override;
-
- Status Delete(base::StringPiece key) override;
-
- // Deletes the LevelDB and recreates it. This method is called if any DB call
- // returns a |CORRUPTED| status or the database is cleared.
- Status RecreateDB() override;
-
- private:
- // Opens the underlying LevelDB for read and write.
- Status OpenDB();
-
- // The underlying LevelDB used by this implementation.
- std::unique_ptr<leveldb::DB> db_;
-
- // Path to the profile using this store.
- const base::FilePath profile_path_;
-
- base::SequenceChecker sequence_checker_;
-};
-
-} // namespace data_reduction_proxy
-
-#endif // COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_STORE_IMPL_H_
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_usage_store.cc b/chromium/components/data_reduction_proxy/core/browser/data_usage_store.cc
deleted file mode 100644
index e0a2844e01f..00000000000
--- a/chromium/components/data_reduction_proxy/core/browser/data_usage_store.cc
+++ /dev/null
@@ -1,302 +0,0 @@
-// Copyright 2015 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.
-
-// Each |DataUsageBucket| corresponds to data usage for an interval of
-// |kDataUsageBucketLengthMins| minutes. We store data usage for the past
-// |kNumDataUsageBuckets| buckets. Buckets are maintained as a circular array
-// with indexes from 0 to (kNumDataUsageBuckets - 1). To store the circular
-// array in a key-value store, we convert each index to a unique key. The latest
-// bucket persisted to DB overwrites the oldest.
-
-#include "components/data_reduction_proxy/core/browser/data_usage_store.h"
-
-#include <algorithm>
-#include <string>
-#include <utility>
-
-#include "base/logging.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/stringprintf.h"
-#include "base/time/time.h"
-#include "components/data_reduction_proxy/proto/data_store.pb.h"
-
-namespace data_reduction_proxy {
-
-namespace {
-
-const char kCurrentBucketIndexKey[] = "current_bucket_index";
-const char kBucketKeyPrefix[] = "data_usage_bucket:";
-
-const int kMinutesInHour = 60;
-const int kMinutesInDay = 24 * kMinutesInHour;
-
-static_assert(data_reduction_proxy::kDataUsageBucketLengthInMinutes > 0,
- "Length of time should be positive");
-static_assert(kMinutesInHour %
- data_reduction_proxy::kDataUsageBucketLengthInMinutes ==
- 0,
- "kDataUsageBucketLengthMins must be a factor of kMinsInHour");
-
-// Total number of buckets persisted to DB.
-const int kNumDataUsageBuckets =
- kDataUsageHistoryNumDays * kMinutesInDay / kDataUsageBucketLengthInMinutes;
-
-std::string DbKeyForBucketIndex(int index) {
- DCHECK_GE(index, 0);
- DCHECK_LT(index, kNumDataUsageBuckets);
-
- return base::StringPrintf("%s%d", kBucketKeyPrefix, index);
-}
-
-base::Time BucketLowerBoundary(base::Time time) {
- base::Time::Exploded exploded;
- time.UTCExplode(&exploded);
- exploded.minute -= exploded.minute % kDataUsageBucketLengthInMinutes;
- exploded.second = 0;
- exploded.millisecond = 0;
-
- base::Time out_time;
- bool conversion_success = base::Time::FromUTCExploded(exploded, &out_time);
- DCHECK(conversion_success);
- return out_time;
-}
-
-} // namespace
-
-DataUsageStore::DataUsageStore(DataStore* db)
- : db_(db), current_bucket_index_(-1) {
- sequence_checker_.DetachFromSequence();
-}
-
-DataUsageStore::~DataUsageStore() {
- DCHECK(sequence_checker_.CalledOnValidSequence());
-}
-
-void DataUsageStore::LoadDataUsage(std::vector<DataUsageBucket>* data_usage) {
- SCOPED_UMA_HISTOGRAM_TIMER("DataReductionProxy.HistoricalDataUsageLoadTime");
-
- DCHECK(data_usage);
-
- DataUsageBucket empty_bucket;
- data_usage->clear();
- data_usage->resize(kNumDataUsageBuckets, empty_bucket);
-
- for (int i = 0; i < kNumDataUsageBuckets; ++i) {
- int circular_array_index =
- (i + current_bucket_index_ + 1) % kNumDataUsageBuckets;
- LoadBucketAtIndex(circular_array_index, &data_usage->at(i));
- }
-}
-
-void DataUsageStore::LoadCurrentDataUsageBucket(DataUsageBucket* current) {
- DCHECK(sequence_checker_.CalledOnValidSequence());
- DCHECK(current);
-
- std::string current_index_string;
- DataStore::Status index_read_status =
- db_->Get(kCurrentBucketIndexKey, &current_index_string);
-
- if (index_read_status != DataStore::Status::OK ||
- !base::StringToInt(current_index_string, &current_bucket_index_)) {
- current_bucket_index_ = 0;
- }
-
- DCHECK_GE(current_bucket_index_, 0);
- DCHECK_LT(current_bucket_index_, kNumDataUsageBuckets);
-
- DataStore::Status status = LoadBucketAtIndex(current_bucket_index_, current);
- bool bucket_read_ok = status == DataStore::Status::OK;
- current->set_had_read_error(!bucket_read_ok);
- if (bucket_read_ok) {
- current_bucket_last_updated_ =
- base::Time::FromInternalValue(current->last_updated_timestamp());
- }
-}
-
-void DataUsageStore::StoreCurrentDataUsageBucket(
- const DataUsageBucket& current) {
- DCHECK(sequence_checker_.CalledOnValidSequence());
- DCHECK(current_bucket_index_ >= 0 &&
- current_bucket_index_ < kNumDataUsageBuckets);
-
- // If current bucket does not have any information, we skip writing to DB.
- if (!current.has_last_updated_timestamp() ||
- (current.has_had_read_error() && current.had_read_error()))
- return;
-
- int prev_current_bucket_index = current_bucket_index_;
- base::Time prev_current_bucket_last_updated_ = current_bucket_last_updated_;
- // We might have skipped saving buckets because Chrome was not being used.
- // Write empty buckets to those slots to overwrite outdated information.
- base::Time last_updated =
- base::Time::FromInternalValue(current.last_updated_timestamp());
- std::map<std::string, std::string> buckets_to_save;
- int num_buckets_since_last_saved = BucketOffsetFromLastSaved(last_updated);
- for (int i = 0; i < num_buckets_since_last_saved - 1; ++i)
- GenerateKeyAndAddToMap(DataUsageBucket(), &buckets_to_save, true);
-
- GenerateKeyAndAddToMap(current, &buckets_to_save,
- num_buckets_since_last_saved > 0);
-
- current_bucket_last_updated_ =
- base::Time::FromInternalValue(current.last_updated_timestamp());
-
- buckets_to_save.insert(std::pair<std::string, std::string>(
- kCurrentBucketIndexKey, base::NumberToString(current_bucket_index_)));
-
- DataStore::Status status = db_->Put(buckets_to_save);
- if (status != DataStore::Status::OK) {
- current_bucket_index_ = prev_current_bucket_index;
- current_bucket_last_updated_ = prev_current_bucket_last_updated_;
- LOG(WARNING) << "Failed to write data usage buckets to LevelDB" << status;
- }
-}
-
-void DataUsageStore::DeleteHistoricalDataUsage() {
- std::string current_index_string;
- DataStore::Status index_read_status =
- db_->Get(kCurrentBucketIndexKey, &current_index_string);
-
- // If the index doesn't exist, then no buckets have been written and the
- // data usage doesn't need to be deleted.
- if (index_read_status != DataStore::Status::OK)
- return;
-
- db_->RecreateDB();
-}
-
-void DataUsageStore::DeleteBrowsingHistory(const base::Time& start,
- const base::Time& end) {
- DCHECK_LE(start, end);
- if (current_bucket_last_updated_.is_null())
- return;
-
- base::Time begin_current_interval =
- BucketLowerBoundary(current_bucket_last_updated_);
- // Data usage is stored for the past |kDataUsageHistoryNumDays| days. Compute
- // the begin time for data usage.
- base::Time begin_history = begin_current_interval -
- base::Days(kDataUsageHistoryNumDays) +
- base::Minutes(kDataUsageBucketLengthInMinutes);
-
- // Nothing to do if there is no overlap between given interval and the
- // interval for which data usage history is maintained.
- if (begin_history > end || start > current_bucket_last_updated_)
- return;
-
- base::Time start_delete = start > begin_history ? start : begin_history;
- base::Time end_delete =
- end < current_bucket_last_updated_ ? end : current_bucket_last_updated_;
-
- int first_index_to_delete = ComputeBucketIndex(start_delete);
- int num_buckets_to_delete =
- 1 +
- (BucketLowerBoundary(end_delete) - BucketLowerBoundary(start_delete))
- .InMinutes() /
- kDataUsageBucketLengthInMinutes;
- for (int i = 0; i < num_buckets_to_delete; ++i) {
- int index_to_delete = (first_index_to_delete + i) % kNumDataUsageBuckets;
- db_->Delete(DbKeyForBucketIndex(index_to_delete));
- }
- UMA_HISTOGRAM_COUNTS_10000(
- "DataReductionProxy.DeleteBrowsingHistory.NumBuckets",
- num_buckets_to_delete);
-}
-
-int DataUsageStore::ComputeBucketIndex(const base::Time& time) const {
- int offset = BucketOffsetFromLastSaved(time);
-
- int index = current_bucket_index_ + offset;
- if (index < 0) {
- index += kNumDataUsageBuckets;
- } else if (index >= kNumDataUsageBuckets) {
- index -= kNumDataUsageBuckets;
- }
- DCHECK_GE(index, 0);
- DCHECK_LT(index, kNumDataUsageBuckets);
- return index;
-}
-
-// static
-bool DataUsageStore::AreInSameInterval(const base::Time& time1,
- const base::Time& time2) {
- if (time1.is_null() || time2.is_null())
- return true;
-
- return BucketLowerBoundary(time1) == BucketLowerBoundary(time2);
-}
-
-// static
-bool DataUsageStore::BucketOverlapsInterval(
- const base::Time& bucket_last_updated,
- const base::Time& start_interval,
- const base::Time& end_interval) {
- DCHECK(!bucket_last_updated.is_null());
- DCHECK(!end_interval.is_null());
- DCHECK_LE(start_interval, end_interval);
-
- base::Time bucket_start = BucketLowerBoundary(bucket_last_updated);
- base::Time bucket_end =
- bucket_start + base::Minutes(kDataUsageBucketLengthInMinutes);
- DCHECK_LE(bucket_start, bucket_end);
- return bucket_end >= start_interval && end_interval >= bucket_start;
-}
-
-void DataUsageStore::GenerateKeyAndAddToMap(
- const DataUsageBucket& bucket,
- std::map<std::string, std::string>* map,
- bool increment_current_index) {
- if (increment_current_index) {
- current_bucket_index_++;
- DCHECK(current_bucket_index_ <= kNumDataUsageBuckets);
- if (current_bucket_index_ == kNumDataUsageBuckets)
- current_bucket_index_ = 0;
- }
-
- std::string bucket_key = DbKeyForBucketIndex(current_bucket_index_);
-
- std::string bucket_value;
- bool success = bucket.SerializeToString(&bucket_value);
- DCHECK(success);
-
- map->insert(std::pair<std::string, std::string>(std::move(bucket_key),
- std::move(bucket_value)));
-}
-
-int DataUsageStore::BucketOffsetFromLastSaved(
- const base::Time& new_last_updated_timestamp) const {
- if (current_bucket_last_updated_.is_null())
- return 0;
-
- base::TimeDelta time_delta =
- BucketLowerBoundary(new_last_updated_timestamp) -
- BucketLowerBoundary(current_bucket_last_updated_);
- int offset_from_last_saved =
- (time_delta.InMinutes() / kDataUsageBucketLengthInMinutes);
- return offset_from_last_saved > 0
- ? std::min(offset_from_last_saved, kNumDataUsageBuckets)
- : std::max(offset_from_last_saved, -kNumDataUsageBuckets);
-}
-
-DataStore::Status DataUsageStore::LoadBucketAtIndex(int index,
- DataUsageBucket* bucket) {
- DCHECK(index >= 0 && index < kNumDataUsageBuckets);
-
- std::string bucket_as_string;
- DataStore::Status bucket_read_status =
- db_->Get(DbKeyForBucketIndex(index), &bucket_as_string);
- if ((bucket_read_status != DataStore::Status::OK &&
- bucket_read_status != DataStore::NOT_FOUND)) {
- LOG(WARNING) << "Failed to read data usage bucket from LevelDB: "
- << bucket_read_status;
- }
- if (bucket_read_status == DataStore::Status::OK) {
- bool parse_successful = bucket->ParseFromString(bucket_as_string);
- DCHECK(parse_successful);
- }
- return bucket_read_status;
-}
-
-} // namespace data_reduction_proxy
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_usage_store.h b/chromium/components/data_reduction_proxy/core/browser/data_usage_store.h
deleted file mode 100644
index 19da8b94298..00000000000
--- a/chromium/components/data_reduction_proxy/core/browser/data_usage_store.h
+++ /dev/null
@@ -1,117 +0,0 @@
-// Copyright 2015 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.
-
-#ifndef COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_USAGE_STORE_H_
-#define COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_USAGE_STORE_H_
-
-#include <map>
-#include <string>
-#include <vector>
-
-#include "base/memory/raw_ptr.h"
-#include "base/sequence_checker.h"
-#include "base/time/time.h"
-#include "components/data_reduction_proxy/core/browser/data_store.h"
-
-namespace data_reduction_proxy {
-class DataStore;
-class DataUsageBucket;
-
-// Time interval for each DataUsageBucket.
-constexpr int kDataUsageBucketLengthInMinutes = 15;
-
-// Number of days for which to maintain data usage history.
-constexpr int kDataUsageHistoryNumDays = 60;
-
-// Store for detailed data usage stats. Data usage from every
-// |kDataUsageBucketLengthMins| interval is stored in a DataUsageBucket.
-class DataUsageStore {
- public:
- explicit DataUsageStore(DataStore* db);
-
- DataUsageStore(const DataUsageStore&) = delete;
- DataUsageStore& operator=(const DataUsageStore&) = delete;
-
- ~DataUsageStore();
-
- // Loads the historic data usage into |data_usage|.
- void LoadDataUsage(std::vector<DataUsageBucket>* data_usage);
-
- // Loads the data usage bucket for the current interval into |current_bucket|.
- // This method must be called at least once before any calls to
- // |StoreCurrentDataUsageBucket|.
- void LoadCurrentDataUsageBucket(DataUsageBucket* bucket);
-
- // Stores the data usage bucket for the current interval. This will overwrite
- // the current data usage bucket in the |db_| if they are for the same
- // interval. It will also backfill any missed intervals with empty data.
- // Intervals might be missed because Chrome was not running, or there was no
- // network activity during an interval.
- void StoreCurrentDataUsageBucket(const DataUsageBucket& current_bucket);
-
- // Deletes all historical data usage from storage.
- void DeleteHistoricalDataUsage();
-
- // Deletes historical data usage from storage.
- void DeleteBrowsingHistory(const base::Time& start, const base::Time& end);
-
- // Returns whether |time1| and |time2| are in the same interval. Each hour is
- // divided into |kDataUsageBucketLengthMins| minute long intervals. Returns
- // true if either |time1| or |time2| has NULL time since an uninitialized
- // bucket can be assigned to any interval.
- static bool AreInSameInterval(const base::Time& time1,
- const base::Time& time2);
-
- // Returns whether the bucket that was last updated at |bucket_last_updated|
- // overlaps in time with the interval [|start_interval|, |end_interval|].
- static bool BucketOverlapsInterval(const base::Time& bucket_last_updated,
- const base::Time& start_interval,
- const base::Time& end_interval);
-
- private:
- friend class DataUsageStoreTest;
-
- // Converts the given |bucket| into a string format for persistance to
- // |DataReductionProxyStore| and adds it to the map. The key is generated
- // based on |current_bucket_index_|.
- // |current_bucket_index_| will be incremented before generating the key if
- // |increment_current_index| is true.
- void GenerateKeyAndAddToMap(const DataUsageBucket& bucket,
- std::map<std::string, std::string>* map,
- bool increment_current_index);
-
- // Returns the offset between the bucket for |current| time and the last
- // bucket that was persisted to the store. Eg: Returns 0 if |current| is in
- // the last persisted bucket. Returns 1 if |current| belongs to the bucket
- // immediately after the last persisted bucket.
- int BucketOffsetFromLastSaved(const base::Time& current) const;
-
- // Computes the index of the bucket for the given |time| relative to
- // |current_bucket_index_| and |current_bucket_last_updated_|.
- // |current_bucket_last_updated_| belongs at |current_bucket_index_| and
- // bucket index is computed by going backwards or forwards from current index
- // by one position for every |kDataUsageBucketLengthInMinutes| minutes.
- int ComputeBucketIndex(const base::Time& time) const;
-
- // Loads the data usage bucket at the given index.
- DataStore::Status LoadBucketAtIndex(int index, DataUsageBucket* current);
-
- // The store to persist data usage information.
- raw_ptr<DataStore> db_;
-
- // The index of the last bucket persisted in the |db_|. |DataUsageBucket| is
- // stored in the |db_| as a circular array. This index points to the array
- // position corresponding to the current bucket.
- int current_bucket_index_;
-
- // The time when the current bucket was last written to |db_|. This field is
- // used to determine if a DataUsageBucket to be saved belongs to the same
- // interval, or a more recent interval.
- base::Time current_bucket_last_updated_;
-
- base::SequenceChecker sequence_checker_;
-};
-
-} // namespace data_reduction_proxy
-#endif // COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_USAGE_STORE_H_
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_usage_store_unittest.cc b/chromium/components/data_reduction_proxy/core/browser/data_usage_store_unittest.cc
deleted file mode 100644
index 508a57ae214..00000000000
--- a/chromium/components/data_reduction_proxy/core/browser/data_usage_store_unittest.cc
+++ /dev/null
@@ -1,518 +0,0 @@
-// Copyright 2014 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.
-
-#include "components/data_reduction_proxy/core/browser/data_usage_store.h"
-
-#include <stdint.h>
-
-#include <map>
-#include <memory>
-#include <string>
-
-#include "base/strings/stringprintf.h"
-#include "base/test/metrics/histogram_tester.h"
-#include "base/time/time.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h"
-#include "components/data_reduction_proxy/core/browser/data_store.h"
-#include "components/data_reduction_proxy/proto/data_store.pb.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace {
-// Each bucket holds data usage for a 15 minute interval. History is maintained
-// for 60 days.
-const unsigned kNumExpectedBuckets = 60 * 24 * 60 / 15;
-const int kBucketsInHour = 60 / 15;
-const int kTestCurrentBucketIndex = 2880;
-
-base::Time::Exploded TestExplodedTime() {
- base::Time::Exploded exploded;
- exploded.year = 2001;
- exploded.month = 12;
- exploded.day_of_month = 31;
- exploded.day_of_week = 1;
- exploded.hour = 12;
- exploded.minute = 1;
- exploded.second = 0;
- exploded.millisecond = 0;
-
- return exploded;
-}
-}
-
-namespace data_reduction_proxy {
-
-class DataUsageStoreTest : public testing::Test {
- protected:
- void SetUp() override {
- store_ = std::make_unique<TestDataStore>();
- data_usage_store_ = std::make_unique<DataUsageStore>(store_.get());
- }
-
- int current_bucket_index() const {
- return data_usage_store_->current_bucket_index_;
- }
-
- int64_t current_bucket_last_updated() const {
- return data_usage_store_->current_bucket_last_updated_.ToInternalValue();
- }
-
- int ComputeBucketIndex(const base::Time& time) const {
- return data_usage_store_->ComputeBucketIndex(time);
- }
-
- TestDataStore* store() const { return store_.get(); }
-
- DataUsageStore* data_usage_store() const { return data_usage_store_.get(); }
-
- void PopulateStore() {
- base::Time::Exploded exploded = TestExplodedTime();
- base::Time current_time;
- EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &current_time));
-
- std::map<std::string, std::string> map;
- map.insert(
- std::pair<std::string, std::string>("current_bucket_index", "2880"));
- for (int i = 0; i < static_cast<int>(kNumExpectedBuckets); ++i) {
- base::Time time = current_time - base::Minutes(i * 5);
- DataUsageBucket bucket;
- bucket.set_last_updated_timestamp(time.ToInternalValue());
- bucket.set_had_read_error(false);
- int index = kTestCurrentBucketIndex - i;
- if (index < 0)
- index += kNumExpectedBuckets;
-
- std::string bucket_value;
- ASSERT_TRUE(bucket.SerializeToString(&bucket_value));
- map.insert(std::pair<std::string, std::string>(
- base::StringPrintf("data_usage_bucket:%d", index), bucket_value));
- }
- store()->Put(map);
- }
-
- private:
- std::unique_ptr<TestDataStore> store_;
- std::unique_ptr<DataUsageStore> data_usage_store_;
-};
-
-TEST_F(DataUsageStoreTest, LoadEmpty) {
- ASSERT_NE(0, current_bucket_index());
-
- DataUsageBucket bucket;
- data_usage_store()->LoadCurrentDataUsageBucket(&bucket);
-
- ASSERT_EQ(0, current_bucket_index());
- ASSERT_EQ(0, current_bucket_last_updated());
- ASSERT_FALSE(bucket.has_last_updated_timestamp());
-
- std::vector<DataUsageBucket> data_usage;
- data_usage_store()->LoadDataUsage(&data_usage);
-
- ASSERT_EQ(kNumExpectedBuckets, data_usage.size());
- ASSERT_FALSE(data_usage[0].has_last_updated_timestamp());
-}
-
-TEST_F(DataUsageStoreTest, LoadAndStoreToSameBucket) {
- DataUsageBucket bucket;
- data_usage_store()->LoadCurrentDataUsageBucket(&bucket);
-
- base::Time now = base::Time::Now();
- bucket.set_last_updated_timestamp(now.ToInternalValue());
- bucket.set_had_read_error(false);
-
- data_usage_store()->StoreCurrentDataUsageBucket(bucket);
- ASSERT_EQ(2u, store()->map()->size());
-
- DataUsageBucket stored_bucket;
- data_usage_store()->LoadCurrentDataUsageBucket(&stored_bucket);
- ASSERT_EQ(now.ToInternalValue(), stored_bucket.last_updated_timestamp());
- ASSERT_FALSE(stored_bucket.had_read_error());
-
- std::vector<DataUsageBucket> data_usage;
- data_usage_store()->LoadDataUsage(&data_usage);
-
- ASSERT_EQ(kNumExpectedBuckets, data_usage.size());
- ASSERT_FALSE(data_usage[0].has_last_updated_timestamp());
- ASSERT_FALSE(
- data_usage[kNumExpectedBuckets - 2].has_last_updated_timestamp());
- ASSERT_EQ(now.ToInternalValue(),
- data_usage[kNumExpectedBuckets - 1].last_updated_timestamp());
- ASSERT_FALSE(data_usage[kNumExpectedBuckets - 1].had_read_error());
-}
-
-TEST_F(DataUsageStoreTest, StoreSameBucket) {
- base::Time::Exploded exploded = TestExplodedTime();
-
- exploded.minute = 0;
- exploded.second = 0;
- exploded.millisecond = 0;
- base::Time time1;
- EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &time1));
-
- exploded.minute = 14;
- exploded.second = 59;
- exploded.millisecond = 999;
- base::Time time2;
- EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &time2));
-
- DataUsageBucket bucket;
- data_usage_store()->LoadCurrentDataUsageBucket(&bucket);
-
- bucket.set_last_updated_timestamp(time1.ToInternalValue());
- bucket.set_had_read_error(false);
-
- data_usage_store()->StoreCurrentDataUsageBucket(bucket);
- ASSERT_EQ(2u, store()->map()->size());
-
- bucket.set_last_updated_timestamp(time2.ToInternalValue());
- data_usage_store()->StoreCurrentDataUsageBucket(bucket);
- ASSERT_EQ(2u, store()->map()->size());
-
- std::vector<DataUsageBucket> data_usage;
- data_usage_store()->LoadDataUsage(&data_usage);
-
- ASSERT_EQ(kNumExpectedBuckets, data_usage.size());
- ASSERT_FALSE(data_usage[0].has_last_updated_timestamp());
- ASSERT_FALSE(
- data_usage[kNumExpectedBuckets - 2].has_last_updated_timestamp());
- ASSERT_EQ(time2.ToInternalValue(),
- data_usage[kNumExpectedBuckets - 1].last_updated_timestamp());
- ASSERT_FALSE(data_usage[kNumExpectedBuckets - 1].had_read_error());
-}
-
-TEST_F(DataUsageStoreTest, StoreConsecutiveBuckets) {
- base::Time::Exploded exploded = TestExplodedTime();
-
- exploded.minute = 0;
- exploded.second = 59;
- exploded.millisecond = 999;
- base::Time time1;
- EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &time1));
-
- exploded.minute = 15;
- exploded.second = 0;
- exploded.millisecond = 0;
- base::Time time2;
- EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &time2));
-
- DataUsageBucket bucket;
- data_usage_store()->LoadCurrentDataUsageBucket(&bucket);
-
- bucket.set_last_updated_timestamp(time1.ToInternalValue());
- bucket.set_had_read_error(false);
-
- data_usage_store()->StoreCurrentDataUsageBucket(bucket);
- ASSERT_EQ(2u, store()->map()->size());
-
- bucket.set_last_updated_timestamp(time2.ToInternalValue());
- data_usage_store()->StoreCurrentDataUsageBucket(bucket);
- ASSERT_EQ(3u, store()->map()->size());
-
- std::vector<DataUsageBucket> data_usage;
- data_usage_store()->LoadDataUsage(&data_usage);
-
- ASSERT_EQ(kNumExpectedBuckets, data_usage.size());
- ASSERT_FALSE(data_usage[0].has_last_updated_timestamp());
- ASSERT_FALSE(
- data_usage[kNumExpectedBuckets - 3].has_last_updated_timestamp());
- ASSERT_EQ(time1.ToInternalValue(),
- data_usage[kNumExpectedBuckets - 2].last_updated_timestamp());
- ASSERT_FALSE(data_usage[kNumExpectedBuckets - 2].had_read_error());
- ASSERT_EQ(time2.ToInternalValue(),
- data_usage[kNumExpectedBuckets - 1].last_updated_timestamp());
- ASSERT_FALSE(data_usage[kNumExpectedBuckets - 1].had_read_error());
-}
-
-TEST_F(DataUsageStoreTest, StoreMultipleBuckets) {
- DataUsageBucket bucket;
- data_usage_store()->LoadCurrentDataUsageBucket(&bucket);
-
- // Comments indicate time expressed as day.hour.min.sec.millis relative to
- // each other beginning at 0.0.0.0.0.
- // The first bucket range is 0.0.0.0.0 - 0.0.14.59.999 and
- // the second bucket range is 0.0.5.0.0 - 0.0.29.59.999, etc.
- base::Time first_bucket_time = base::Time::Now(); // 0.0.0.0.0.
- base::Time last_bucket_time = first_bucket_time // 59.23.55.0.0
- + base::Days(60) - base::Minutes(15);
- base::Time before_history_time = // 0.0.-5.0.0
- first_bucket_time - base::Minutes(15);
- base::Time tenth_bucket_time = // 0.2.15.0.0
- first_bucket_time + base::Hours(2) + base::Minutes(15);
- base::Time second_last_bucket_time = // 59.23.45.0.0
- last_bucket_time - base::Minutes(15);
-
- // This bucket will be discarded when the |last_bucket| is stored.
- DataUsageBucket bucket_before_history;
- bucket_before_history.set_last_updated_timestamp(
- before_history_time.ToInternalValue());
- bucket_before_history.set_had_read_error(false);
- data_usage_store()->StoreCurrentDataUsageBucket(bucket_before_history);
- // Only one bucket has been stored, so store should have 2 entries, one for
- // current index and one for the bucket itself.
- ASSERT_EQ(2u, store()->map()->size());
-
- // Calling |StoreCurrentDataUsageBucket| with the same last updated timestamp
- // should not cause number of stored buckets to increase and current bucket
- // should be overwritten.
- data_usage_store()->StoreCurrentDataUsageBucket(bucket_before_history);
- // Only one bucket has been stored, so store should have 2 entries, one for
- // current index and one for the bucket itself.
- ASSERT_EQ(2u, store()->map()->size());
-
- // This will be the very first bucket once |last_bucket| is stored.
- DataUsageBucket first_bucket;
- first_bucket.set_last_updated_timestamp(first_bucket_time.ToInternalValue());
- first_bucket.set_had_read_error(false);
- data_usage_store()->StoreCurrentDataUsageBucket(first_bucket);
- // A new bucket has been stored, so entires in map should increase by one.
- ASSERT_EQ(3u, store()->map()->size());
-
- // This will be the 10th bucket when |last_bucket| is stored. We skipped
- // calling |StoreCurrentDataUsageBucket| on 10 buckets.
- DataUsageBucket tenth_bucket;
- tenth_bucket.set_last_updated_timestamp(tenth_bucket_time.ToInternalValue());
- tenth_bucket.set_had_read_error(false);
- data_usage_store()->StoreCurrentDataUsageBucket(tenth_bucket);
- // 9 more (empty) buckets should have been added to the store.
- ASSERT_EQ(12u, store()->map()->size());
-
- // This will be the last but one bucket when |last_bucket| is stored.
- DataUsageBucket second_last_bucket;
- second_last_bucket.set_last_updated_timestamp(
- second_last_bucket_time.ToInternalValue());
- second_last_bucket.set_had_read_error(false);
- data_usage_store()->StoreCurrentDataUsageBucket(second_last_bucket);
- // Max number of buckets we store to DB plus one for the current index.
- ASSERT_EQ(kNumExpectedBuckets + 1, store()->map()->size());
-
- // This bucket should simply overwrite oldest bucket, so number of entries in
- // store should be unchanged.
- DataUsageBucket last_bucket;
- last_bucket.set_last_updated_timestamp(last_bucket_time.ToInternalValue());
- last_bucket.set_had_read_error(false);
- data_usage_store()->StoreCurrentDataUsageBucket(last_bucket);
- ASSERT_EQ(kNumExpectedBuckets + 1, store()->map()->size());
-
- std::vector<DataUsageBucket> data_usage;
- data_usage_store()->LoadDataUsage(&data_usage);
-
- ASSERT_EQ(kNumExpectedBuckets, data_usage.size());
- ASSERT_EQ(first_bucket_time.ToInternalValue(),
- data_usage[0].last_updated_timestamp());
- ASSERT_EQ(tenth_bucket_time.ToInternalValue(),
- data_usage[9].last_updated_timestamp());
- ASSERT_EQ(second_last_bucket_time.ToInternalValue(),
- data_usage[kNumExpectedBuckets - 2].last_updated_timestamp());
- ASSERT_EQ(last_bucket_time.ToInternalValue(),
- data_usage[kNumExpectedBuckets - 1].last_updated_timestamp());
-
- ASSERT_FALSE(data_usage[0].had_read_error());
- ASSERT_FALSE(data_usage[9].had_read_error());
- ASSERT_FALSE(data_usage[kNumExpectedBuckets - 2].had_read_error());
- ASSERT_FALSE(data_usage[kNumExpectedBuckets - 1].had_read_error());
-}
-
-TEST_F(DataUsageStoreTest, DeleteHistoricalDataUsage) {
- DataUsageBucket bucket;
- data_usage_store()->LoadCurrentDataUsageBucket(&bucket);
-
- bucket.set_last_updated_timestamp(base::Time::Now().ToInternalValue());
- bucket.set_had_read_error(false);
-
- data_usage_store()->StoreCurrentDataUsageBucket(bucket);
- ASSERT_EQ(2u, store()->map()->size());
-
- data_usage_store()->DeleteHistoricalDataUsage();
- ASSERT_EQ(0u, store()->map()->size());
-}
-
-TEST_F(DataUsageStoreTest, BucketOverlapsInterval) {
- base::Time::Exploded exploded = TestExplodedTime();
- base::Time time1;
- EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &time1));
-
- exploded.minute = 16;
- base::Time time16;
- EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &time16));
-
- exploded.minute = 17;
- base::Time time17;
- EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &time17));
-
- exploded.minute = 18;
- base::Time time18;
- EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &time18));
-
- exploded.minute = 33;
- base::Time time33;
- EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &time33));
-
- exploded.minute = 34;
- base::Time time34;
- EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &time34));
-
- exploded.minute = 46;
- base::Time time46;
- EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &time46));
-
- ASSERT_FALSE(DataUsageStore::BucketOverlapsInterval(time1, time17, time33));
- ASSERT_TRUE(DataUsageStore::BucketOverlapsInterval(time16, time17, time33));
- ASSERT_TRUE(DataUsageStore::BucketOverlapsInterval(time18, time17, time33));
- ASSERT_TRUE(DataUsageStore::BucketOverlapsInterval(time34, time17, time33));
- ASSERT_FALSE(DataUsageStore::BucketOverlapsInterval(time46, time17, time33));
-}
-
-TEST_F(DataUsageStoreTest, ComputeBucketIndex) {
- PopulateStore();
-
- base::Time::Exploded exploded = TestExplodedTime();
-
- DataUsageBucket current_bucket;
- data_usage_store()->LoadCurrentDataUsageBucket(&current_bucket);
-
- base::Time out_time;
-
- exploded.minute = 0;
- EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &out_time));
- ASSERT_EQ(kTestCurrentBucketIndex, ComputeBucketIndex(out_time));
-
- exploded.minute = 14;
- EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &out_time));
- ASSERT_EQ(kTestCurrentBucketIndex, ComputeBucketIndex(out_time));
-
- exploded.minute = 15;
- EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &out_time));
- ASSERT_EQ(kTestCurrentBucketIndex + 1, ComputeBucketIndex(out_time));
-
- exploded.hour = 11;
- exploded.minute = 59;
- EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &out_time));
- ASSERT_EQ(kTestCurrentBucketIndex - 1, ComputeBucketIndex(out_time));
-
- exploded.minute = 0;
- EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &out_time));
- ASSERT_EQ(kTestCurrentBucketIndex - kBucketsInHour,
- ComputeBucketIndex(out_time));
-
- exploded.hour = 1;
- EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &out_time));
- ASSERT_EQ(kTestCurrentBucketIndex - kBucketsInHour * 11,
- ComputeBucketIndex(out_time));
-
- exploded.day_of_month = 1;
- exploded.hour = 12;
- EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &out_time));
- ASSERT_EQ(kTestCurrentBucketIndex - kBucketsInHour * 30 * 24,
- ComputeBucketIndex(out_time));
-
- exploded.hour = 11;
- exploded.minute = 45;
- EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &out_time));
- ASSERT_EQ(kTestCurrentBucketIndex - kBucketsInHour * 30 * 24 - 1 +
- static_cast<int>(kNumExpectedBuckets),
- ComputeBucketIndex(out_time));
-
- exploded.minute = 30;
- EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &out_time));
- ASSERT_EQ(kTestCurrentBucketIndex - kBucketsInHour * 30 * 24 - 2 +
- static_cast<int>(kNumExpectedBuckets),
- ComputeBucketIndex(out_time));
-}
-
-TEST_F(DataUsageStoreTest, DeleteBrowsingHistory) {
- PopulateStore();
- DataUsageBucket current_bucket;
- data_usage_store()->LoadCurrentDataUsageBucket(&current_bucket);
- base::HistogramTester histogram_tester;
-
- ASSERT_EQ(kNumExpectedBuckets + 1, store()->map()->size());
-
- base::Time::Exploded exploded = TestExplodedTime();
- exploded.minute = 0;
- base::Time now;
- EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &now));
- base::Time fifteen_mins_from_now = now + base::Minutes(15);
-
- // Deleting browsing from the future should be a no-op.
- data_usage_store()->DeleteBrowsingHistory(fifteen_mins_from_now,
- fifteen_mins_from_now);
- ASSERT_EQ(kNumExpectedBuckets + 1, store()->map()->size());
-
- ASSERT_TRUE(store()->map()->find(base::StringPrintf(
- "data_usage_bucket:%d", kTestCurrentBucketIndex)) !=
- store()->map()->end());
-
- // Delete the current bucket.
- data_usage_store()->DeleteBrowsingHistory(now, now);
- ASSERT_EQ(kNumExpectedBuckets, store()->map()->size());
- ASSERT_TRUE(store()->map()->find(base::StringPrintf(
- "data_usage_bucket:%d", kTestCurrentBucketIndex)) ==
- store()->map()->end());
- histogram_tester.ExpectUniqueSample(
- "DataReductionProxy.DeleteBrowsingHistory.NumBuckets", 1, 1);
-
- // Delete the current bucket + the last 5 minutes, so two buckets.
- data_usage_store()->DeleteBrowsingHistory(now - base::Minutes(5), now);
- ASSERT_EQ(kNumExpectedBuckets - 1, store()->map()->size());
- ASSERT_TRUE(store()->map()->find(base::StringPrintf(
- "data_usage_bucket:%d", kTestCurrentBucketIndex - 1)) ==
- store()->map()->end());
- histogram_tester.ExpectBucketCount(
- "DataReductionProxy.DeleteBrowsingHistory.NumBuckets", 2, 1);
-
- // Delete 30 days of browsing history.
- data_usage_store()->DeleteBrowsingHistory(now - base::Days(30), now);
- ASSERT_EQ(kNumExpectedBuckets - kBucketsInHour * 30 * 24,
- store()->map()->size());
- ASSERT_TRUE(store()->map()->find("data_usage_bucket:0") ==
- store()->map()->end());
- ASSERT_TRUE(store()->map()->find(base::StringPrintf(
- "data_usage_bucket:%d", kNumExpectedBuckets - 1)) !=
- store()->map()->end());
- histogram_tester.ExpectBucketCount(
- "DataReductionProxy.DeleteBrowsingHistory.NumBuckets",
- kBucketsInHour * 30 * 24, 1);
-
- // Delete wraps around and removes the last element which is at position
- // (|kNumExpectedBuckets| - 1).
- data_usage_store()->DeleteBrowsingHistory(
- now - base::Days(30) - base::Minutes(5), now);
- ASSERT_EQ(kNumExpectedBuckets - kBucketsInHour * 30 * 24 - 1,
- store()->map()->size());
- ASSERT_TRUE(store()->map()->find(base::StringPrintf(
- "data_usage_bucket:%d", kNumExpectedBuckets - 1)) ==
- store()->map()->end());
- ASSERT_TRUE(store()->map()->find(base::StringPrintf(
- "data_usage_bucket:%d", kNumExpectedBuckets - 2)) !=
- store()->map()->end());
-
- data_usage_store()->DeleteBrowsingHistory(now - base::Days(60), now);
- ASSERT_EQ(1u, store()->map()->size());
- histogram_tester.ExpectBucketCount(
- "DataReductionProxy.DeleteBrowsingHistory.NumBuckets",
- kBucketsInHour * 30 * 24 - 1, 2);
-}
-
-TEST_F(DataUsageStoreTest, DontStoreReadError) {
- DataUsageBucket bucket;
- data_usage_store()->LoadCurrentDataUsageBucket(&bucket);
-
- base::Time now = base::Time::Now();
- bucket.set_last_updated_timestamp(now.ToInternalValue());
- bucket.set_had_read_error(true);
-
- data_usage_store()->StoreCurrentDataUsageBucket(bucket);
- ASSERT_EQ(0u, store()->map()->size());
-}
-
-TEST_F(DataUsageStoreTest, DontStoreNoTimestamp) {
- DataUsageBucket bucket;
- data_usage_store()->LoadCurrentDataUsageBucket(&bucket);
-
- bucket.set_had_read_error(false);
-
- data_usage_store()->StoreCurrentDataUsageBucket(bucket);
- ASSERT_EQ(0u, store()->map()->size());
-}
-
-} // namespace data_reduction_proxy
diff --git a/chromium/components/data_reduction_proxy/core/browser/db_data_owner.cc b/chromium/components/data_reduction_proxy/core/browser/db_data_owner.cc
deleted file mode 100644
index 49e42fb1253..00000000000
--- a/chromium/components/data_reduction_proxy/core/browser/db_data_owner.cc
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright 2015 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.
-
-#include "components/data_reduction_proxy/core/browser/db_data_owner.h"
-
-#include <utility>
-
-#include "base/check.h"
-#include "components/data_reduction_proxy/core/browser/data_store.h"
-#include "components/data_reduction_proxy/core/browser/data_usage_store.h"
-#include "components/data_reduction_proxy/proto/data_store.pb.h"
-
-namespace data_reduction_proxy {
-
-DBDataOwner::DBDataOwner(std::unique_ptr<DataStore> store)
- : store_(std::move(store)), data_usage_(new DataUsageStore(store_.get())) {
- sequence_checker_.DetachFromSequence();
-}
-
-DBDataOwner::~DBDataOwner() {
- DCHECK(sequence_checker_.CalledOnValidSequence());
-}
-
-void DBDataOwner::InitializeOnDBThread() {
- DCHECK(sequence_checker_.CalledOnValidSequence());
-
- store_->InitializeOnDBThread();
-}
-
-void DBDataOwner::LoadHistoricalDataUsage(
- std::vector<DataUsageBucket>* data_usage) {
- DCHECK(sequence_checker_.CalledOnValidSequence());
-
- data_usage_->LoadDataUsage(data_usage);
-}
-
-void DBDataOwner::LoadCurrentDataUsageBucket(DataUsageBucket* bucket) {
- DCHECK(sequence_checker_.CalledOnValidSequence());
-
- data_usage_->LoadCurrentDataUsageBucket(bucket);
-}
-
-void DBDataOwner::StoreCurrentDataUsageBucket(
- std::unique_ptr<DataUsageBucket> current) {
- DCHECK(sequence_checker_.CalledOnValidSequence());
-
- data_usage_->StoreCurrentDataUsageBucket(*current);
-}
-
-void DBDataOwner::DeleteHistoricalDataUsage() {
- DCHECK(sequence_checker_.CalledOnValidSequence());
-
- data_usage_->DeleteHistoricalDataUsage();
-}
-
-void DBDataOwner::DeleteBrowsingHistory(const base::Time& start,
- const base::Time& end) {
- DCHECK(sequence_checker_.CalledOnValidSequence());
-
- data_usage_->DeleteBrowsingHistory(start, end);
-}
-
-base::WeakPtr<DBDataOwner> DBDataOwner::GetWeakPtr() {
- return weak_factory_.GetWeakPtr();
-}
-
-} // namespace data_reduction_proxy
diff --git a/chromium/components/data_reduction_proxy/core/browser/db_data_owner.h b/chromium/components/data_reduction_proxy/core/browser/db_data_owner.h
deleted file mode 100644
index a21a3feebc5..00000000000
--- a/chromium/components/data_reduction_proxy/core/browser/db_data_owner.h
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright 2015 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.
-
-#ifndef COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DB_DATA_OWNER_H_
-#define COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DB_DATA_OWNER_H_
-
-#include <memory>
-#include <vector>
-
-#include "base/callback_forward.h"
-#include "base/memory/weak_ptr.h"
-#include "base/sequence_checker.h"
-
-namespace base {
-class Time;
-}
-
-namespace data_reduction_proxy {
-class DataStore;
-class DataUsageBucket;
-class DataUsageStore;
-
-// Callback for loading the historical data usage.
-using HistoricalDataUsageCallback =
- base::OnceCallback<void(std::unique_ptr<std::vector<DataUsageBucket>>)>;
-
-// Callback for loading data usage for the current bucket.
-using LoadCurrentDataUsageCallback =
- base::OnceCallback<void(std::unique_ptr<DataUsageBucket>)>;
-
-// Contains and initializes all Data Reduction Proxy objects that have a
-// lifetime based on the DB task runner.
-class DBDataOwner {
- public:
- explicit DBDataOwner(std::unique_ptr<DataStore> store);
-
- DBDataOwner(const DBDataOwner&) = delete;
- DBDataOwner& operator=(const DBDataOwner&) = delete;
-
- virtual ~DBDataOwner();
-
- // Initializes all the DB objects. Must be called on the DB task runner.
- void InitializeOnDBThread();
-
- // Loads data usage history stored in |DataStore|.
- void LoadHistoricalDataUsage(std::vector<DataUsageBucket>* data_usage);
-
- // Loads the last stored data usage bucket from |DataStore| into |bucket|.
- void LoadCurrentDataUsageBucket(DataUsageBucket* bucket);
-
- // Stores |current| to |DataStore|.
- void StoreCurrentDataUsageBucket(std::unique_ptr<DataUsageBucket> current);
-
- // Deletes all historical data usage from storage.
- void DeleteHistoricalDataUsage();
-
- // Deletes browsing history for the given data range from storage.
- void DeleteBrowsingHistory(const base::Time& start, const base::Time& end);
-
- // Returns a weak pointer to self for use on UI thread.
- base::WeakPtr<DBDataOwner> GetWeakPtr();
-
- private:
- std::unique_ptr<DataStore> store_;
- std::unique_ptr<DataUsageStore> data_usage_;
- base::SequenceChecker sequence_checker_;
- base::WeakPtrFactory<DBDataOwner> weak_factory_{this};
-};
-
-} // namespace data_reduction_proxy
-#endif // COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DB_DATA_OWNER_H_
diff --git a/chromium/components/data_reduction_proxy/core/common/BUILD.gn b/chromium/components/data_reduction_proxy/core/common/BUILD.gn
index 4b87a710065..45d0a6906d8 100644
--- a/chromium/components/data_reduction_proxy/core/common/BUILD.gn
+++ b/chromium/components/data_reduction_proxy/core/common/BUILD.gn
@@ -2,29 +2,17 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-import("//build/util/process_version.gni")
-
# Variables:
# deps: Extra dependencies.
template("common_tmpl") {
static_library(target_name) {
sources = [
- "data_reduction_proxy_features.cc",
- "data_reduction_proxy_features.h",
- "data_reduction_proxy_headers.cc",
- "data_reduction_proxy_headers.h",
- "data_reduction_proxy_params.cc",
- "data_reduction_proxy_params.h",
- "data_reduction_proxy_pref_names.cc",
- "data_reduction_proxy_pref_names.h",
"data_reduction_proxy_switches.cc",
"data_reduction_proxy_switches.h",
]
- public_deps = [ ":version_header" ]
deps = [
"//base",
- "//components/data_reduction_proxy/proto:data_reduction_proxy_proto",
"//google_apis",
"//services/network/public/cpp",
]
@@ -43,32 +31,3 @@ common_tmpl("common") {
"//url",
]
}
-
-source_set("unit_tests") {
- testonly = true
- sources = [ "data_reduction_proxy_params_unittest.cc" ]
-
- deps = [
- ":common",
- "//base",
- "//base/test:test_support",
- "//components/prefs",
- "//components/prefs:test_support",
-
- # TODO this dependency seems wrong, but
- "//components/data_reduction_proxy/core/browser",
- "//components/data_reduction_proxy/proto:data_reduction_proxy_proto",
- "//net:test_support",
- "//testing/gtest",
- ]
-}
-
-process_version("version_header") {
- template_file = "version.h.in"
- sources = [ "//chrome/VERSION" ]
- output = "$target_gen_dir/version.h"
- extra_args = [
- "-e",
- "VERSION_FULL=\"%s.%s.%s.%s\" % (MAJOR,MINOR,BUILD,PATCH)",
- ]
-}
diff --git a/chromium/components/data_reduction_proxy/core/common/chrome_proxy_header.txt b/chromium/components/data_reduction_proxy/core/common/chrome_proxy_header.txt
deleted file mode 100644
index 5a6a81caa32..00000000000
--- a/chromium/components/data_reduction_proxy/core/common/chrome_proxy_header.txt
+++ /dev/null
@@ -1,114 +0,0 @@
-The Chrome-Proxy header is used to convey client credentials and capabilities
-to the Data Reduction Proxy and to receive instructions from it.
-
-Background
-----------
-
-The Data Reduction Proxy is operated by Google for Chrome. Chrome is
-configured to connect to it via TLS at proxy.googlezip.net:443 and via HTTP
-at compress.googlezip.net:80. The Data Reduction Proxy only proxies HTTP
-traffic from non-incognito tabs.
-
-Chrome-Proxy Response Header
-----------------------------
-
-The Data Reduction Proxy uses the Chrome-Proxy response header to instruct
-Chrome to bypass the proxy for a period of time and retry the request directly.
-It may do so to shed load, when the requested URL is on a blacklist of
-malicious or illegal resources, or when the request is for video, which the
-proxy does not currently serve. Bypasses may be issued for other reasons as
-well.
-
-In order to bypass a proxy and make decisions about when requests should be
-proxied and which proxy they should use, some proxies serve PAC scripts
-themselves with a low HTTP cache timeout, and dynamically update the scripts
-to direct users. This is the current state of the art, but the approach has many
-drawbacks. Some clients ignore the HTTP caching headers for the PAC script. The
-client's performance suffers because new PAC scripts must be interpreted after
-every invalidation. Clients must also store (large) blacklists. Server design is
-complicated by needing to decouple a request from the mechanism that would
-bypass it (a PAC). Bypass fidelity is coarse meaning that bypass decisions can't
-be made on a per-request basis. And bypass decisions must be made before the
-request is sent, which isn't always possible, e.g., for domains the proxy hasn't
-served before.
-
-Instead, the Data Reduction Proxy sends one of a set of bypass directives in the
-"Chrome-Proxy" header if it wants the client not to use it. Upon reception of
-this header, the client may decide to retry the request with the proxy disabled
-or cancel the request. Chrome cancels instead of retrying non-idempotent
-requests.
-
-The "Chrome-Proxy" response header has the following format:
-
-chrome-proxy = "Chrome-Proxy" ":" 1#chrome-proxy-directive
-chrome-proxy-directive = token [ "=" ( token / quoted-string ) ]
-
-The header uses the definition of 'token' and 'quoted-string' from
-https://datatracker.ietf.org/doc/rfc7230/
-
-The directives have the following meanings:
-
-bypass: Argument syntax: delta-seconds
- delta-seconds = 1*DIGIT (see: 1.2.1 of rfc7234)
- Bypass the currently configured proxy for specified number of
- seconds. If zero is specified, Chrome should use its default
- proxy bypass timeout, which is a random duration between 1 and 5
- minutes. If the TLS proxy is bypassed, Chrome will downgrade to
- using HTTP to connect to the Data Reduction Proxy. If the HTTP
- proxy is bypassed, Chrome will downgrade to using a DIRECT
- connection.
-block: Argument syntax: delta-seconds
- Bypass all Data Reduction Proxies for the specified number of
- seconds. If zero is specified, Chrome will use the default block
- timeout, which is a random time between 1 and 5 minutes.
-block-once: Bypass all Data Reductions Proxies for this request only.
-
-Currently, the directives are mutually exclusive, but the header format does
-not require this. With "block-once", no token is expected.
-
-If more than one directive is contained the header, then Chrome reacts to only
-the highest priority directive. Priorities from highest to lowest are:
-block > bypass > block-once.
-
-
-Examples that respectively bypass the current proxy for seven seconds, bypass
-both the TLS and HTTP proxies for Chrome's default proxy bypass duration, and
-bypass the TLS and HTTP proxies only for the current request:
-
-Chrome-Proxy: bypass=7
-Chrome-Proxy: block=0
-Chrome-Proxy: block-once
-
-
-The Chrome-Proxy header is NOT hop-by-hop, and thus transparent proxies and
-other intermediaries should not modify it. Further, only the Data Reduction
-Proxy should add this header to responses.
-
-Chrome-Proxy Request Header
----------------------------
-
-The Chrome-Proxy request header is used to specify client capabilities and
-credentials. It has the same form as the response header. The directives have
-the following names and meanings:
-
-ps: Argument syntax: token
- A User-Agent-selected pseudorandom session ID.
-sid: Argument syntax: token
- A credential string.
-b: Argument syntax: 1*DIGIT
- The Chrome build number of the client
-p: Argument syntax: 1*DIGIT
- The Chrome patch number of the client
-c: Argument syntax: "android" / "ios" / "mac" / "win" / "linux" /
- "chromeos" / "webview"
- The type of client.
-
-The values of the 'b', 'p', and 'c' directives can often be gleaned from the
-user agent string, but not always, so they are sent explicitly. Each request
-sent from Chrome to a Data Reduction Proxy contains a Chrome-Proxy header with
-values for all five of these directives.
-
-For example, for Chrome 38 on Android with a version 38.0.2125.114 (note the
-'ps' and 'sid' values are representative):
-
-Chrome-Proxy: ps=484343-123-4-9484, sid=he9wj3gjd03, b=2125, p=114, c=android
diff --git a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_features.cc b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_features.cc
deleted file mode 100644
index 39ebc409ae0..00000000000
--- a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_features.cc
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2017 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.
-
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_features.h"
-
-#include "build/build_config.h"
-
-namespace data_reduction_proxy {
-namespace features {
-
-// Enables the data saver promo for low memory Android devices.
-const base::Feature kDataReductionProxyLowMemoryDevicePromo{
- "DataReductionProxyLowMemoryDevicePromo",
- base::FEATURE_DISABLED_BY_DEFAULT};
-
-// Reports estimated data savings due to save-data request header and JS API, as
-// savings provided by DataSaver.
-const base::Feature kReportSaveDataSavings{"ReportSaveDataSavings",
- base::FEATURE_DISABLED_BY_DEFAULT};
-
-} // namespace features
-} // namespace data_reduction_proxy
diff --git a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_features.h b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_features.h
deleted file mode 100644
index aa28cfbad53..00000000000
--- a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_features.h
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2017 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.
-
-#ifndef COMPONENTS_DATA_REDUCTION_PROXY_CORE_COMMON_DATA_REDUCTION_PROXY_FEATURES_H_
-#define COMPONENTS_DATA_REDUCTION_PROXY_CORE_COMMON_DATA_REDUCTION_PROXY_FEATURES_H_
-
-#include "base/feature_list.h"
-
-namespace data_reduction_proxy {
-namespace features {
-
-extern const base::Feature kDataReductionProxyLowMemoryDevicePromo;
-extern const base::Feature kReportSaveDataSavings;
-
-} // namespace features
-} // namespace data_reduction_proxy
-#endif // COMPONENTS_DATA_REDUCTION_PROXY_CORE_COMMON_DATA_REDUCTION_PROXY_FEATURES_H_
diff --git a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc
deleted file mode 100644
index 7b67569a117..00000000000
--- a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc
+++ /dev/null
@@ -1,96 +0,0 @@
-// Copyright 2014 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.
-
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <string>
-#include <utility>
-
-#include "base/metrics/field_trial_params.h"
-#include "base/rand_util.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_split.h"
-#include "base/strings/string_util.h"
-#include "base/time/time.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_features.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
-#include "net/http/http_response_headers.h"
-#include "net/http/http_status_code.h"
-#include "net/http/http_util.h"
-#include "services/network/public/mojom/url_response_head.mojom.h"
-
-namespace {
-
-const char kChromeProxyHeader[] = "chrome-proxy";
-
-const char kActionValueDelimiter = '=';
-
-bool StartsWithActionPrefix(base::StringPiece header_value,
- base::StringPiece action_prefix) {
- DCHECK(!action_prefix.empty());
- // A valid action does not include a trailing '='.
- DCHECK(action_prefix.back() != kActionValueDelimiter);
-
- return header_value.size() > action_prefix.size() + 1 &&
- header_value[action_prefix.size()] == kActionValueDelimiter &&
- base::StartsWith(header_value, action_prefix,
- base::CompareCase::INSENSITIVE_ASCII);
-}
-
-bool GetDataReductionProxyActionValue(const net::HttpResponseHeaders* headers,
- base::StringPiece action_prefix,
- std::string* action_value) {
- DCHECK(headers);
- size_t iter = 0;
- std::string value;
-
- while (headers->EnumerateHeader(&iter, kChromeProxyHeader, &value)) {
- if (StartsWithActionPrefix(value, action_prefix)) {
- if (action_value)
- *action_value = value.substr(action_prefix.size() + 1);
- return true;
- }
- }
- return false;
-}
-
-} // namespace
-
-namespace data_reduction_proxy {
-
-const char* chrome_proxy_header() {
- return kChromeProxyHeader;
-}
-
-int64_t GetDataReductionProxyOFCL(const net::HttpResponseHeaders* headers) {
- std::string ofcl_str;
- int64_t ofcl;
- if (GetDataReductionProxyActionValue(headers, "ofcl", &ofcl_str) &&
- base::StringToInt64(ofcl_str, &ofcl) && ofcl >= 0) {
- return ofcl;
- }
- return -1;
-}
-
-double EstimateCompressionRatioFromHeaders(
- const network::mojom::URLResponseHead* response_head) {
- if (!response_head->network_accessed || !response_head->headers ||
- response_head->headers->GetContentLength() <= 0 ||
- response_head->proxy_server.is_direct()) {
- return 1.0; // No compression
- }
-
- int64_t original_content_length =
- GetDataReductionProxyOFCL(response_head->headers.get());
- if (original_content_length > 0) {
- return static_cast<double>(original_content_length) /
- static_cast<double>(response_head->headers->GetContentLength());
- }
- return 1.0; // No compression
-}
-
-} // namespace data_reduction_proxy
diff --git a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h
deleted file mode 100644
index cf3f26ef8ae..00000000000
--- a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2014 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.
-
-#ifndef COMPONENTS_DATA_REDUCTION_PROXY_CORE_COMMON_DATA_REDUCTION_PROXY_HEADERS_H_
-#define COMPONENTS_DATA_REDUCTION_PROXY_CORE_COMMON_DATA_REDUCTION_PROXY_HEADERS_H_
-
-#include "base/strings/string_piece.h"
-#include "net/http/http_request_headers.h"
-#include "net/http/http_response_headers.h"
-#include "net/proxy_resolution/proxy_resolution_service.h"
-#include "services/network/public/mojom/url_response_head.mojom-forward.h"
-#include "url/gurl.h"
-
-namespace net {
-class HttpResponseHeaders;
-} // namespace net
-
-namespace data_reduction_proxy {
-
-// Gets the header used for data reduction proxy requests and responses.
-const char* chrome_proxy_header();
-
-// Returns the Original-Full-Content-Length(OFCL) value in the Chrome-Proxy
-// header. Returns -1 in case of of error or if OFCL does not exist. |headers|
-// must be non-null.
-int64_t GetDataReductionProxyOFCL(const net::HttpResponseHeaders* headers);
-
-// Returns an estimate of the compression ratio from the Content-Length and
-// Chrome-Proxy Original-Full-Content-Length(OFCL) response headers. These may
-// not be populated for responses which are streamed from the origin which will
-// be treated as a no compression case. Notably, only the response body size is
-// used to compute the ratio, and headers are excluded, since this is only an
-// estimate for response that is beginning to arrive.
-double EstimateCompressionRatioFromHeaders(
- const network::mojom::URLResponseHead* response_head);
-
-} // namespace data_reduction_proxy
-#endif // COMPONENTS_DATA_REDUCTION_PROXY_CORE_COMMON_DATA_REDUCTION_PROXY_HEADERS_H_
diff --git a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc
deleted file mode 100644
index 99d0f5edc85..00000000000
--- a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright 2014 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.
-
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
-
-#include <algorithm>
-#include <map>
-#include <string>
-
-#include "base/command_line.h"
-#include "base/metrics/field_trial.h"
-#include "base/metrics/field_trial_params.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_split.h"
-#include "base/strings/string_util.h"
-#include "build/build_config.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_features.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h"
-#include "net/base/host_port_pair.h"
-#include "net/base/proxy_server.h"
-#include "net/http/http_status_code.h"
-#include "url/url_constants.h"
-
-#if defined(OS_ANDROID)
-#include "base/system/sys_info.h"
-#endif
-
-namespace {
-
-const char kEnabled[] = "Enabled";
-
-bool IsIncludedInFieldTrial(const std::string& name) {
- return base::StartsWith(base::FieldTrialList::FindFullName(name), kEnabled,
- base::CompareCase::SENSITIVE);
-}
-
-bool CanShowAndroidLowMemoryDevicePromo() {
-#if defined(OS_ANDROID)
- return base::SysInfo::IsLowEndDevice() &&
- base::FeatureList::IsEnabled(
- data_reduction_proxy::features::
- kDataReductionProxyLowMemoryDevicePromo);
-#else
- return false;
-#endif
-}
-
-} // namespace
-
-namespace data_reduction_proxy {
-namespace params {
-
-bool IsIncludedInPromoFieldTrial() {
- if (IsIncludedInFieldTrial("DataCompressionProxyPromoVisibility"))
- return true;
-
- return CanShowAndroidLowMemoryDevicePromo();
-}
-
-bool IsIncludedInFREPromoFieldTrial() {
- if (IsIncludedInFieldTrial("DataReductionProxyFREPromo"))
- return true;
-
- return CanShowAndroidLowMemoryDevicePromo();
-}
-
-} // namespace params
-
-} // namespace data_reduction_proxy
diff --git a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params.h b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params.h
deleted file mode 100644
index 89395fcb343..00000000000
--- a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2014 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.
-
-#ifndef COMPONENTS_DATA_REDUCTION_PROXY_CORE_COMMON_DATA_REDUCTION_PROXY_PARAMS_H_
-#define COMPONENTS_DATA_REDUCTION_PROXY_CORE_COMMON_DATA_REDUCTION_PROXY_PARAMS_H_
-
-#include "url/gurl.h"
-
-namespace data_reduction_proxy {
-
-// The data_reduction_proxy::params namespace is a collection of methods to
-// determine the operating parameters of the Data Reduction Proxy as specified
-// by field trials and command line switches.
-namespace params {
-
-// Returns true if this client is part of a field trial that should display
-// a promotion for the data reduction proxy.
-bool IsIncludedInPromoFieldTrial();
-
-// Returns true if this client is part of a field trial that should display
-// a FRE promotion for the data reduction proxy.
-bool IsIncludedInFREPromoFieldTrial();
-
-} // namespace params
-
-} // namespace data_reduction_proxy
-
-#endif // COMPONENTS_DATA_REDUCTION_PROXY_CORE_COMMON_DATA_REDUCTION_PROXY_PARAMS_H_
diff --git a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params_unittest.cc b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params_unittest.cc
deleted file mode 100644
index 22776d3fabc..00000000000
--- a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params_unittest.cc
+++ /dev/null
@@ -1,108 +0,0 @@
-// Copyright 2014 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.
-
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
-
-#include <stddef.h>
-
-#include <map>
-#include <string>
-
-#include "base/command_line.h"
-#include "base/metrics/field_trial.h"
-#include "base/metrics/field_trial_param_associator.h"
-#include "base/metrics/field_trial_params.h"
-#include "base/test/scoped_feature_list.h"
-#include "build/build_config.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_features.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h"
-#include "net/base/proxy_server.h"
-#include "net/http/http_status_code.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/abseil-cpp/absl/types/optional.h"
-
-#if defined(OS_ANDROID)
-#include "base/system/sys_info.h"
-#endif
-
-namespace data_reduction_proxy {
-
-class DataReductionProxyParamsTest : public testing::Test {};
-
-
-TEST_F(DataReductionProxyParamsTest, PromoFieldTrial) {
- const struct {
- std::string trial_group_name;
- bool expected_enabled;
- } tests[] = {
- {"Enabled", true},
- {"Enabled_Control", true},
- {"Disabled", false},
- {"enabled", false},
- };
-
- for (const auto& test : tests) {
- base::test::ScopedFeatureList scoped_feature_list;
- scoped_feature_list.Init();
-
- ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
- "DataCompressionProxyPromoVisibility", test.trial_group_name));
- EXPECT_EQ(test.expected_enabled, params::IsIncludedInPromoFieldTrial())
- << test.trial_group_name;
- }
-}
-
-TEST_F(DataReductionProxyParamsTest, FREPromoFieldTrial) {
- const struct {
- std::string trial_group_name;
- bool expected_enabled;
- } tests[] = {
- {"Enabled", true},
- {"Enabled_Control", true},
- {"Disabled", false},
- {"enabled", false},
- };
-
- for (const auto& test : tests) {
- base::test::ScopedFeatureList scoped_feature_list;
- scoped_feature_list.Init();
-
- ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
- "DataReductionProxyFREPromo", test.trial_group_name));
- EXPECT_EQ(test.expected_enabled, params::IsIncludedInFREPromoFieldTrial())
- << test.trial_group_name;
- }
-}
-
-TEST_F(DataReductionProxyParamsTest, LowMemoryPromoFeature) {
- const struct {
- bool expected_in_field_trial;
- } tests[] = {
- {false}, {true},
- };
-
- for (const auto& test : tests) {
- base::test::ScopedFeatureList scoped_feature_list;
- if (test.expected_in_field_trial) {
- scoped_feature_list.InitAndDisableFeature(
- features::kDataReductionProxyLowMemoryDevicePromo);
- } else {
- scoped_feature_list.InitAndEnableFeature(
- features::kDataReductionProxyLowMemoryDevicePromo);
- }
-
-#if defined(OS_ANDROID)
- EXPECT_EQ(test.expected_in_field_trial && base::SysInfo::IsLowEndDevice(),
- params::IsIncludedInPromoFieldTrial());
- EXPECT_EQ(test.expected_in_field_trial && base::SysInfo::IsLowEndDevice(),
- params::IsIncludedInFREPromoFieldTrial());
-#else
- EXPECT_FALSE(params::IsIncludedInPromoFieldTrial());
- EXPECT_FALSE(params::IsIncludedInFREPromoFieldTrial());
-#endif
- }
-}
-
-} // namespace data_reduction_proxy
diff --git a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.cc b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.cc
deleted file mode 100644
index bc0d21eb123..00000000000
--- a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.cc
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright 2014 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.
-
-#include <stdint.h>
-
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
-
-namespace data_reduction_proxy {
-namespace prefs {
-
-// An int64_t pref that contains an internal representation of midnight on the
-// date of the last update to |kDailyHttp{Original,Received}ContentLength|.
-const char kDailyHttpContentLengthLastUpdateDate[] =
- "data_reduction.last_update_date";
-
-// A List pref that contains daily totals of the original size of all HTTP/HTTPS
-// content received from the network.
-const char kDailyHttpOriginalContentLength[] =
- "data_reduction.daily_original_length";
-
-// A List pref that contains daily totals of the size of all HTTP/HTTPS content
-// received from the network.
-const char kDailyHttpReceivedContentLength[] =
- "data_reduction.daily_received_length";
-
-// A boolean specifying whether the DataSaver feature is enabled for this
-// client. Note that this preference key name is a legacy string for the sdpy
-// proxy.
-//
-// WARNING: This pref is not the source of truth for determining if Data Saver
-// is enabled. Use |DataReductionSettings::IsDataSaverEnabledByUser| instead or
-// consult the OWNERS.
-const char kDataSaverEnabled[] = "spdy_proxy.enabled";
-
-// A boolean specifying whether data usage should be collected for reporting.
-const char kDataUsageReportingEnabled[] = "data_usage_reporting.enabled";
-
-// A boolean specifying whether the data reduction proxy was ever enabled
-// before.
-const char kDataReductionProxyWasEnabledBefore[] =
- "spdy_proxy.was_enabled_before";
-
-// An integer pref that contains the time when the data reduction proxy was last
-// enabled. Recorded only if the data reduction proxy was last enabled since
-// this pref was added.
-const char kDataReductionProxyLastEnabledTime[] =
- "data_reduction.last_enabled_time";
-
-// An int64_t pref that contains the total size of all HTTP content received
-// from the network.
-const char kHttpReceivedContentLength[] = "http_received_content_length";
-
-// An int64_t pref that contains the total original size of all HTTP content
-// received over the network.
-const char kHttpOriginalContentLength[] = "http_original_content_length";
-
-// An integer pref that stores the number of the week when the weekly data use
-// prefs were updated.
-const char kThisWeekNumber[] = "data_reduction.this_week_number";
-
-// Dictionary pref that stores the data use of services. The key will be the
-// service hash code, and the value will be the KB that service used.
-const char kThisWeekServicesDownstreamBackgroundKB[] =
- "data_reduction.this_week_services_downstream_background_kb";
-const char kThisWeekServicesDownstreamForegroundKB[] =
- "data_reduction.this_week_services_downstream_foreground_kb";
-const char kLastWeekServicesDownstreamBackgroundKB[] =
- "data_reduction.last_week_services_downstream_background_kb";
-const char kLastWeekServicesDownstreamForegroundKB[] =
- "data_reduction.last_week_services_downstream_foreground_kb";
-
-// Dictionary pref that stores the content-type of user-initiated traffic. The
-// key will be the content-type, and the value will be the data usage in KB.
-const char kThisWeekUserTrafficContentTypeDownstreamKB[] =
- "data_reduction.this_week_user_traffic_contenttype_downstream_kb";
-const char kLastWeekUserTrafficContentTypeDownstreamKB[] =
- "data_reduction.last_week_user_traffic_contenttype_downstream_kb";
-
-} // namespace prefs
-} // namespace data_reduction_proxy
diff --git a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h
deleted file mode 100644
index 7b546030c92..00000000000
--- a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2014 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.
-
-#ifndef COMPONENTS_DATA_REDUCTION_PROXY_CORE_COMMON_DATA_REDUCTION_PROXY_PREF_NAMES_H_
-#define COMPONENTS_DATA_REDUCTION_PROXY_CORE_COMMON_DATA_REDUCTION_PROXY_PREF_NAMES_H_
-
-namespace data_reduction_proxy {
-namespace prefs {
-
-// Alphabetical list of preference names specific to the data_reduction_proxy
-// component. Keep alphabetized, and document each in the .cc file.
-
-extern const char kDailyHttpContentLengthLastUpdateDate[];
-extern const char kDailyHttpOriginalContentLength[];
-extern const char kDailyHttpReceivedContentLength[];
-
-extern const char kDataSaverEnabled[];
-extern const char kDataUsageReportingEnabled[];
-extern const char kDataReductionProxyWasEnabledBefore[];
-extern const char kDataReductionProxyLastEnabledTime[];
-extern const char kHttpOriginalContentLength[];
-extern const char kHttpReceivedContentLength[];
-
-extern const char kThisWeekNumber[];
-extern const char kThisWeekServicesDownstreamBackgroundKB[];
-extern const char kThisWeekServicesDownstreamForegroundKB[];
-extern const char kLastWeekServicesDownstreamBackgroundKB[];
-extern const char kLastWeekServicesDownstreamForegroundKB[];
-extern const char kThisWeekUserTrafficContentTypeDownstreamKB[];
-extern const char kLastWeekUserTrafficContentTypeDownstreamKB[];
-
-} // namespace prefs
-} // namespace data_reduction_proxy
-
-#endif // COMPONENTS_DATA_REDUCTION_PROXY_CORE_COMMON_DATA_REDUCTION_PROXY_PREF_NAMES_H_
diff --git a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_switches.cc b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_switches.cc
index 49d7f6d8081..e8532097059 100644
--- a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_switches.cc
+++ b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_switches.cc
@@ -10,14 +10,5 @@ namespace switches {
// Enable the data reduction proxy.
const char kEnableDataReductionProxy[] = "enable-spdy-proxy-auth";
-// Enables a 1 MB savings promo for the data reduction proxy.
-const char kEnableDataReductionProxySavingsPromo[] =
- "enable-data-reduction-proxy-savings-promo";
-
-// Override the one-time InfoBar to not needed to be shown before triggering
-// https image compression for the page load.
-const char kOverrideHttpsImageCompressionInfobar[] =
- "override-https-image-compression-infobar";
-
} // namespace switches
} // namespace data_reduction_proxy
diff --git a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h
index ea977b39ff8..51e1ce9b08a 100644
--- a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h
+++ b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h
@@ -12,8 +12,6 @@ namespace switches {
// alongside the definition of their values in the .cc file.
extern const char kEnableDataReductionProxy[];
-extern const char kEnableDataReductionProxySavingsPromo[];
-extern const char kOverrideHttpsImageCompressionInfobar[];
} // namespace switches
} // namespace data_reduction_proxy
diff --git a/chromium/components/data_reduction_proxy/core/common/version.h.in b/chromium/components/data_reduction_proxy/core/common/version.h.in
deleted file mode 100644
index 24772b4bdcd..00000000000
--- a/chromium/components/data_reduction_proxy/core/common/version.h.in
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright 2014 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.
-
-// version.h is generated from version.h.in. Edit the source!
-
-#ifndef DATA_REDUCTION_PROXY_CORE_COMMON_VERSION_INFO_H_
-#define DATA_REDUCTION_PROXY_CORE_COMMON_VERSION_INFO_H_
-
-#define PRODUCT_VERSION "@VERSION_FULL@"
-
-#endif // DATA_REDUCTION_PROXY_CORE_COMMON_VERSION_INFO_H_
diff --git a/chromium/components/data_reduction_proxy/proto/BUILD.gn b/chromium/components/data_reduction_proxy/proto/BUILD.gn
deleted file mode 100644
index 2d5b4e2193a..00000000000
--- a/chromium/components/data_reduction_proxy/proto/BUILD.gn
+++ /dev/null
@@ -1,9 +0,0 @@
-# Copyright 2015 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.
-
-import("//third_party/protobuf/proto_library.gni")
-
-proto_library("data_reduction_proxy_proto") {
- sources = [ "data_store.proto" ]
-}
diff --git a/chromium/components/data_reduction_proxy/proto/data_store.proto b/chromium/components/data_reduction_proxy/proto/data_store.proto
deleted file mode 100644
index 0c67b97e480..00000000000
--- a/chromium/components/data_reduction_proxy/proto/data_store.proto
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2015 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.
-//
-// Protocol buffer definitions for Data Reduction Proxy data stored in LevelDB.
-
-syntax = "proto2";
-
-option optimize_for = LITE_RUNTIME;
-
-package data_reduction_proxy;
-
-// Contains data usage for an interval of time.
-message DataUsageBucket {
- repeated PerConnectionDataUsage connection_usage = 1;
-
- // Timestamp of the last update that was included in this bucket.
- optional int64 last_updated_timestamp = 2;
-
- // True if there was an error while parsing this from disk.
- optional bool had_read_error = 3;
-}
-
-message PerConnectionDataUsage {
- repeated PerSiteDataUsage site_usage = 1;
-}
-
-// Data usage for a specific site.
-message PerSiteDataUsage {
- // Full hostname of the site without scheme, port, and trailing slashes.
- // Eg: For page "http://www.finance.google.com/index.html?a=b", hostname will
- // be "www.finance.google.com".
- required string hostname = 1;
-
- // Total data used in bytes when browsing this site.
- required int64 data_used = 2;
-
- // Amount of data that would have been used to browse this site without
- // employing any data saving techniques.
- required int64 original_size = 3;
-}
diff --git a/chromium/components/data_use_measurement/DIR_METADATA b/chromium/components/data_use_measurement/DIR_METADATA
deleted file mode 100644
index 3d3ad0779f9..00000000000
--- a/chromium/components/data_use_measurement/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
- component: "Internals>Network>DataUse"
-}
diff --git a/chromium/components/data_use_measurement/OWNERS b/chromium/components/data_use_measurement/OWNERS
deleted file mode 100644
index 2783dea1c6e..00000000000
--- a/chromium/components/data_use_measurement/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-file://components/data_reduction_proxy/OWNERS
diff --git a/chromium/components/data_use_measurement/core/BUILD.gn b/chromium/components/data_use_measurement/core/BUILD.gn
deleted file mode 100644
index 775b77a2752..00000000000
--- a/chromium/components/data_use_measurement/core/BUILD.gn
+++ /dev/null
@@ -1,52 +0,0 @@
-# Copyright 2015 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.
-
-static_library("core") {
- sources = [
- "data_use_user_data.cc",
- "data_use_user_data.h",
- ]
- deps = [
- "//base",
- "//net",
- ]
-}
-
-static_library("ascriber") {
- sources = [
- "data_use.cc",
- "data_use.h",
- "data_use_measurement.cc",
- "data_use_measurement.h",
- "data_use_pref_names.h",
- "data_use_tracker_prefs.cc",
- "data_use_tracker_prefs.h",
- ]
- deps = [
- ":core",
- "//base",
- "//components/metrics",
- "//components/prefs",
- "//net",
- "//services/network/public/cpp:cpp",
- ]
-}
-
-source_set("unit_tests") {
- sources = [
- "data_use_measurement_unittest.cc",
- "data_use_tracker_prefs_unittest.cc",
- ]
- testonly = true
- deps = [
- ":ascriber",
- ":core",
- "//base/test:test_support",
- "//components/metrics:metrics",
- "//components/prefs:test_support",
- "//net:test_support",
- "//services/network:test_support",
- "//testing/gtest",
- ]
-}
diff --git a/chromium/components/data_use_measurement/core/DEPS b/chromium/components/data_use_measurement/core/DEPS
deleted file mode 100644
index c620476d474..00000000000
--- a/chromium/components/data_use_measurement/core/DEPS
+++ /dev/null
@@ -1,7 +0,0 @@
-include_rules = [
- "+net",
- "+components/metrics",
- "+components/prefs",
- "+services/network/public/cpp",
- "+services/network/test",
-]
diff --git a/chromium/components/data_use_measurement/core/data_use.cc b/chromium/components/data_use_measurement/core/data_use.cc
deleted file mode 100644
index 8750f45e2bf..00000000000
--- a/chromium/components/data_use_measurement/core/data_use.cc
+++ /dev/null
@@ -1,23 +0,0 @@
-// 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.
-
-#include "components/data_use_measurement/core/data_use.h"
-
-namespace data_use_measurement {
-
-DataUse::DataUse(TrafficType traffic_type)
- : traffic_type_(traffic_type),
- total_bytes_sent_(0),
- total_bytes_received_(0) {}
-
-DataUse::~DataUse() {}
-
-void DataUse::IncrementTotalBytes(int64_t bytes_received, int64_t bytes_sent) {
- total_bytes_received_ += bytes_received;
- total_bytes_sent_ += bytes_sent;
- DCHECK_LE(0, total_bytes_received_);
- DCHECK_LE(0, total_bytes_sent_);
-}
-
-} // namespace data_use_measurement
diff --git a/chromium/components/data_use_measurement/core/data_use.h b/chromium/components/data_use_measurement/core/data_use.h
deleted file mode 100644
index ef6c1934b2f..00000000000
--- a/chromium/components/data_use_measurement/core/data_use.h
+++ /dev/null
@@ -1,77 +0,0 @@
-// 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.
-
-#ifndef COMPONENTS_DATA_USE_MEASUREMENT_CORE_DATA_USE_H_
-#define COMPONENTS_DATA_USE_MEASUREMENT_CORE_DATA_USE_H_
-
-#include <stdint.h>
-
-#include <string>
-
-#include "base/supports_user_data.h"
-#include "url/gurl.h"
-
-namespace data_use_measurement {
-
-// Class to store total network data used by some entity.
-class DataUse : public base::SupportsUserData {
- public:
- enum class TrafficType {
- // Unknown type. URLRequests for arbitrary scheme such as blob, file,
- // extensions, chrome URLs fall under this bucket - url/url_constants.cc
- // TODO(rajendrant): Record metrics on the distribution of these type. It is
- // also possible to remove this UNKNOWN type altogether by skipping the URL
- // schemes that do not make use of network.
- UNKNOWN,
-
- // User initiated traffic.
- USER_TRAFFIC,
-
- // Chrome services.
- SERVICES,
-
- // Fetch from ServiceWorker.
- SERVICE_WORKER,
- };
-
- explicit DataUse(TrafficType traffic_type);
-
- DataUse(const DataUse&) = delete;
- DataUse& operator=(const DataUse&) = delete;
-
- ~DataUse() override;
-
- // Returns the page URL.
- const GURL& url() const { return url_; }
-
- void set_url(const GURL& url) { url_ = url; }
-
- const std::string& description() const { return description_; }
-
- void set_description(const std::string& description) {
- description_ = description;
- }
-
- // Increments the total received and sent byte counts. Can be used to
- // decrement the byte counts as well.
- void IncrementTotalBytes(int64_t bytes_received, int64_t bytes_sent);
-
- int64_t total_bytes_received() const { return total_bytes_received_; }
-
- int64_t total_bytes_sent() const { return total_bytes_sent_; }
-
- TrafficType traffic_type() const { return traffic_type_; }
-
- private:
- GURL url_;
- std::string description_;
- const TrafficType traffic_type_;
-
- int64_t total_bytes_sent_;
- int64_t total_bytes_received_;
-};
-
-} // namespace data_use_measurement
-
-#endif // COMPONENTS_DATA_USE_MEASUREMENT_CORE_DATA_USE_H_
diff --git a/chromium/components/data_use_measurement/core/data_use_measurement.cc b/chromium/components/data_use_measurement/core/data_use_measurement.cc
deleted file mode 100644
index ed8fcde9915..00000000000
--- a/chromium/components/data_use_measurement/core/data_use_measurement.cc
+++ /dev/null
@@ -1,380 +0,0 @@
-// Copyright 2015 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.
-
-#include "components/data_use_measurement/core/data_use_measurement.h"
-
-#include <set>
-
-#include "base/bind.h"
-#include "base/feature_list.h"
-#include "base/memory/ptr_util.h"
-#include "base/metrics/histogram_functions.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/metrics/sparse_histogram.h"
-#include "base/strings/stringprintf.h"
-#include "base/time/clock.h"
-#include "base/time/default_clock.h"
-#include "build/build_config.h"
-#include "components/data_use_measurement/core/data_use_user_data.h"
-#include "net/traffic_annotation/network_traffic_annotation.h"
-#include "services/network/public/cpp/features.h"
-
-#if defined(OS_ANDROID)
-#include "net/android/traffic_stats.h"
-#endif
-
-namespace data_use_measurement {
-
-namespace {
-
-#if defined(OS_ANDROID)
-bool IsInForeground(base::android::ApplicationState state) {
- switch (state) {
- case base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES:
- return true;
- case base::android::APPLICATION_STATE_UNKNOWN:
- case base::android::APPLICATION_STATE_HAS_PAUSED_ACTIVITIES:
- case base::android::APPLICATION_STATE_HAS_STOPPED_ACTIVITIES:
- case base::android::APPLICATION_STATE_HAS_DESTROYED_ACTIVITIES:
- return false;
- }
-}
-#endif
-
-// Records the occurrence of |sample| in |name| histogram. Conventional UMA
-// histograms are not used because the |name| is not static.
-void RecordUMAHistogramCount(const std::string& name, int64_t sample) {
- base::HistogramBase* histogram_pointer = base::Histogram::FactoryGet(
- name,
- 1, // Minimum sample size in bytes.
- 1000000, // Maximum sample size in bytes. Should cover most of the
- // requests by services.
- 50, // Bucket count.
- base::HistogramBase::kUmaTargetedHistogramFlag);
- histogram_pointer->Add(sample);
-}
-
-} // namespace
-
-DataUseMeasurement::DataUseMeasurement(
- PrefService* pref_service,
- network::NetworkConnectionTracker* network_connection_tracker)
- : network_connection_tracker_(network_connection_tracker),
- data_use_tracker_prefs_(base::DefaultClock::GetInstance(), pref_service) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK(network_connection_tracker_);
-
-#if defined(OS_ANDROID)
- int64_t bytes = 0;
- // Query Android traffic stats.
- if (net::android::traffic_stats::GetCurrentUidRxBytes(&bytes))
- rx_bytes_os_ = bytes;
-
- if (net::android::traffic_stats::GetCurrentUidTxBytes(&bytes))
- tx_bytes_os_ = bytes;
-#endif
-
- network_connection_tracker_->AddLeakyNetworkConnectionObserver(this);
-
- network_connection_tracker_->GetConnectionType(
- &connection_type_,
- base::BindOnce(&DataUseMeasurement::OnConnectionChanged,
- weak_ptr_factory_.GetWeakPtr()));
-
-#if defined(OS_ANDROID)
- app_state_ = base::android::ApplicationStatusListener::GetState();
-
- app_listener_ = base::android::ApplicationStatusListener::New(
- base::BindRepeating(&DataUseMeasurement::OnApplicationStateChange,
- base::Unretained(this)));
-#endif
-}
-
-DataUseMeasurement::~DataUseMeasurement() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-#if defined(OS_ANDROID)
- if (app_listener_)
- app_listener_.reset();
-#endif
- network_connection_tracker_->RemoveNetworkConnectionObserver(this);
- DCHECK(services_data_use_observer_list_.empty());
-}
-
-void DataUseMeasurement::RecordDownstreamUserTrafficSizeMetric(
- bool is_tab_visible,
- int64_t bytes) {
- RecordUMAHistogramCount(
- GetHistogramName("DataUse.TrafficSize.User", DOWNSTREAM,
- CurrentAppState(), IsCurrentNetworkCellular()),
- bytes);
- RecordTabStateHistogram(DOWNSTREAM, CurrentAppState(), is_tab_visible, bytes);
- bytes_transferred_since_last_traffic_stats_query_ += bytes;
- MaybeRecordNetworkBytesOS(/*force_record_metrics=*/false);
-
- data_use_tracker_prefs_.ReportNetworkServiceDataUse(
- IsCurrentNetworkCellular(),
- CurrentAppState() == DataUseUserData::FOREGROUND,
- /*is_user_traffic=*/true, bytes);
-}
-
-#if defined(OS_ANDROID)
-void DataUseMeasurement::OnApplicationStateChangeForTesting(
- base::android::ApplicationState application_state) {
- OnApplicationStateChange(application_state);
-}
-#endif
-
-DataUseUserData::AppState DataUseMeasurement::CurrentAppState() const {
-#if defined(OS_ANDROID)
- return IsInForeground(app_state_) ? DataUseUserData::FOREGROUND
- : DataUseUserData::BACKGROUND;
-#else
- // If the OS is not Android, all the requests are considered Foreground.
- return DataUseUserData::FOREGROUND;
-#endif
-}
-
-// static
-std::string DataUseMeasurement::GetHistogramNameWithConnectionType(
- const char* prefix,
- TrafficDirection dir,
- DataUseUserData::AppState app_state) {
- return base::StringPrintf(
- "%s.%s.%s", prefix, dir == UPSTREAM ? "Upstream" : "Downstream",
- app_state == DataUseUserData::UNKNOWN
- ? "Unknown"
- : (app_state == DataUseUserData::FOREGROUND ? "Foreground"
- : "Background"));
-}
-
-// static
-std::string DataUseMeasurement::GetHistogramName(
- const char* prefix,
- TrafficDirection dir,
- DataUseUserData::AppState app_state,
- bool is_connection_cellular) {
- return base::StringPrintf(
- "%s.%s.%s.%s", prefix, dir == UPSTREAM ? "Upstream" : "Downstream",
- app_state == DataUseUserData::UNKNOWN
- ? "Unknown"
- : (app_state == DataUseUserData::FOREGROUND ? "Foreground"
- : "Background"),
- is_connection_cellular ? "Cellular" : "NotCellular");
-}
-
-#if defined(OS_ANDROID)
-void DataUseMeasurement::OnApplicationStateChange(
- base::android::ApplicationState application_state) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
- if (app_state_ == application_state)
- return;
- MaybeRecordNetworkBytesOS(/*force_record_metrics=*/true);
- app_state_ = application_state;
-}
-#endif
-
-void DataUseMeasurement::MaybeRecordNetworkBytesOS(bool force_record_metrics) {
-#if defined(OS_ANDROID)
- // Minimum number of bytes that should be reported by the network delegate
- // before Android's TrafficStats API is queried (if Chrome is not in
- // background). This reduces the overhead of repeatedly calling the API.
- static const int64_t kMinDelegateBytes = 25000;
-
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- if (!force_record_metrics &&
- bytes_transferred_since_last_traffic_stats_query_ < kMinDelegateBytes &&
- CurrentAppState() == DataUseUserData::FOREGROUND) {
- return;
- }
- bytes_transferred_since_last_traffic_stats_query_ = 0;
- int64_t bytes = 0;
- // Query Android traffic stats directly instead of registering with the
- // DataUseAggregator since the latter does not provide notifications for
- // the incognito traffic.
- if (net::android::traffic_stats::GetCurrentUidRxBytes(&bytes)) {
- if (rx_bytes_os_ != 0) {
- DCHECK_GE(bytes, rx_bytes_os_);
- if (bytes > rx_bytes_os_) {
- int64_t incremental_bytes = bytes - rx_bytes_os_;
- // Do not record samples with value 0.
- base::UmaHistogramCustomCounts("DataUse.BytesReceived2.OS",
- incremental_bytes, 50, 10 * 1000 * 1000,
- 50);
- if (IsInForeground(app_state_)) {
- base::UmaHistogramCustomCounts("DataUse.BytesReceived2.OS.Foreground",
- incremental_bytes, 50,
- 10 * 1000 * 1000, 50);
- } else {
- base::UmaHistogramCustomCounts("DataUse.BytesReceived2.OS.Background",
- incremental_bytes, 50,
- 10 * 1000 * 1000, 50);
- }
- }
- }
- rx_bytes_os_ = bytes;
- }
-
- if (net::android::traffic_stats::GetCurrentUidTxBytes(&bytes)) {
- if (tx_bytes_os_ != 0) {
- DCHECK_GE(bytes, tx_bytes_os_);
- if (bytes > tx_bytes_os_) {
- int64_t incremental_bytes = bytes - tx_bytes_os_;
- // Do not record samples with value 0.
- UMA_HISTOGRAM_COUNTS_1M("DataUse.BytesSent.OS", incremental_bytes);
- if (IsInForeground(app_state_)) {
- UMA_HISTOGRAM_COUNTS_1M("DataUse.BytesSent.OS.Foreground",
- incremental_bytes);
- } else {
- UMA_HISTOGRAM_COUNTS_1M("DataUse.BytesSent.OS.Background",
- incremental_bytes);
- }
- }
- }
- tx_bytes_os_ = bytes;
- }
-#endif
-}
-
-void DataUseMeasurement::ReportDataUsageServices(
- int32_t traffic_annotation_hash,
- TrafficDirection dir,
- DataUseUserData::AppState app_state,
- int64_t message_size_bytes) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
- if (message_size_bytes <= 0)
- return;
-
- // Conventional UMA histograms are not used because name is not static.
- base::HistogramBase* histogram = base::SparseHistogram::FactoryGet(
- GetHistogramNameWithConnectionType("DataUse.AllServicesKB", dir,
- app_state),
- base::HistogramBase::kUmaTargetedHistogramFlag);
- // AddKiB method takes value in bytes.
- histogram->AddKiB(traffic_annotation_hash,
- base::saturated_cast<int>(message_size_bytes));
-
- bytes_transferred_since_last_traffic_stats_query_ += message_size_bytes;
- MaybeRecordNetworkBytesOS(/*force_record_metrics=*/false);
-
- data_use_tracker_prefs_.ReportNetworkServiceDataUse(
- IsCurrentNetworkCellular(),
- CurrentAppState() == DataUseUserData::FOREGROUND,
- /*is_user_traffic=*/false, message_size_bytes);
-}
-
-void DataUseMeasurement::RecordTabStateHistogram(
- TrafficDirection dir,
- DataUseUserData::AppState app_state,
- bool is_tab_visible,
- int64_t bytes) const {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
- if (app_state == DataUseUserData::UNKNOWN)
- return;
-
- std::string histogram_name = "DataUse.AppTabState.";
- histogram_name.append(dir == UPSTREAM ? "Upstream." : "Downstream.");
- if (app_state == DataUseUserData::BACKGROUND) {
- histogram_name.append("AppBackground");
- } else if (is_tab_visible) {
- histogram_name.append("AppForeground.TabForeground");
- } else {
- histogram_name.append("AppForeground.TabBackground");
- }
- RecordUMAHistogramCount(histogram_name, bytes);
-}
-
-// static
-bool DataUseMeasurement::IsUserRequest(
- int32_t network_traffic_annotation_hash_id) {
- static const std::set<int32_t> kUserInitiatedTrafficAnnotations = {
- COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH(
- "blink_extension_resource_loader"),
- COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH("blink_resource_loader"),
- COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH("parallel_download_job"),
- COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH("renderer_initiated_download"),
- COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH("drag_download_file"),
- COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH(
- "download_web_contents_frame"), /*save page action*/
- COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH(
- "render_view_context_menu"), /* save link as*/
- COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH("webstore_installer"),
- COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH("pdf_plugin_placeholder"),
- COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH(
- "downloads_api_run_async"), /* Can be user request or
- autonomous request from extensions*/
- COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH("resource_dispatcher_host"),
- COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH("navigation_url_loader"),
- };
- return kUserInitiatedTrafficAnnotations.find(
- network_traffic_annotation_hash_id) !=
- kUserInitiatedTrafficAnnotations.end();
-}
-
-// static
-bool DataUseMeasurement::IsUserDownloadsRequest(
- int32_t network_traffic_annotation_hash_id) {
- static const std::set<int32_t> kUserDownloadsTrafficAnnotations = {
- COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH("parallel_download_job"),
- COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH("renderer_initiated_download"),
- COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH("drag_download_file"),
- COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH("download_web_contents_frame"),
- COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH("downloads_api_run_async"),
- COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH("resumed_downloads"),
- COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH("download_via_context_menu"),
- COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH("offline_pages_download_file"),
- };
- return kUserDownloadsTrafficAnnotations.find(
- network_traffic_annotation_hash_id) !=
- kUserDownloadsTrafficAnnotations.end();
-}
-
-// static
-bool DataUseMeasurement::IsMetricsServiceRequest(
- int32_t network_traffic_annotation_hash_id) {
- static const std::set<int32_t> kMetricsServiceTrafficAnnotations = {
- COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH("metrics_report_uma"),
- COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH("metrics_report_ukm"),
- };
- return kMetricsServiceTrafficAnnotations.find(
- network_traffic_annotation_hash_id) !=
- kMetricsServiceTrafficAnnotations.end();
-}
-
-bool DataUseMeasurement::IsCurrentNetworkCellular() const {
- return network::NetworkConnectionTracker::IsConnectionCellular(
- connection_type_);
-}
-
-void DataUseMeasurement::OnConnectionChanged(
- network::mojom::ConnectionType type) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
- if (connection_type_ != network::mojom::ConnectionType::CONNECTION_UNKNOWN)
- MaybeRecordNetworkBytesOS(/*force_record_metrics=*/true);
-
- connection_type_ = type;
-}
-
-void DataUseMeasurement::AddServicesDataUseObserver(
- ServicesDataUseObserver* observer) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- services_data_use_observer_list_.AddObserver(observer);
-}
-
-void DataUseMeasurement::RemoveServicesDataUseObserver(
- ServicesDataUseObserver* observer) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- services_data_use_observer_list_.RemoveObserver(observer);
-}
-
-// static
-void DataUseMeasurement::RegisterDataUseComponentLocalStatePrefs(
- PrefRegistrySimple* registry) {
- DataUseTrackerPrefs::RegisterDataUseTrackerLocalStatePrefs(registry);
-}
-
-} // namespace data_use_measurement
diff --git a/chromium/components/data_use_measurement/core/data_use_measurement.h b/chromium/components/data_use_measurement/core/data_use_measurement.h
deleted file mode 100644
index 77f47538065..00000000000
--- a/chromium/components/data_use_measurement/core/data_use_measurement.h
+++ /dev/null
@@ -1,202 +0,0 @@
-// Copyright 2015 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.
-
-#ifndef COMPONENTS_DATA_USE_MEASUREMENT_CORE_DATA_USE_MEASUREMENT_H_
-#define COMPONENTS_DATA_USE_MEASUREMENT_CORE_DATA_USE_MEASUREMENT_H_
-
-#include <stdint.h>
-
-#include <memory>
-#include <string>
-
-#include "base/callback.h"
-#include "base/memory/raw_ptr.h"
-#include "base/memory/weak_ptr.h"
-#include "base/observer_list.h"
-#include "base/sequence_checker.h"
-#include "build/build_config.h"
-#include "components/data_use_measurement/core/data_use_tracker_prefs.h"
-#include "components/data_use_measurement/core/data_use_user_data.h"
-#include "services/network/public/cpp/network_connection_tracker.h"
-
-#if defined(OS_ANDROID)
-#include "base/android/application_status_listener.h"
-#endif
-
-class PrefService;
-
-namespace data_use_measurement {
-
-// Records the data use of user traffic and various services in UMA histograms.
-// The UMA is broken down by network technology used (Wi-Fi vs cellular). On
-// Android, the UMA is further broken down by whether the application was in the
-// background or foreground during the request.
-// TODO(amohammadkhan): Complete the layered architecture.
-// http://crbug.com/527460
-class DataUseMeasurement
- : public network::NetworkConnectionTracker::NetworkConnectionObserver {
- public:
- class ServicesDataUseObserver {
- public:
- // Called when services data use is reported.
- virtual void OnServicesDataUse(int32_t service_hash_code,
- int64_t recv_bytes,
- int64_t sent_bytes) = 0;
- };
-
- // Returns true if the NTA hash is initiated by user traffic.
- static bool IsUserRequest(int32_t network_traffic_annotation_hash_id);
-
- // Returns true if the NTA hash is one used by Chrome downloads.
- static bool IsUserDownloadsRequest(
- int32_t network_traffic_annotation_hash_id);
-
- // Returns true if the NTA hash is one used by metrics (UMA, UKM) component.
- static bool IsMetricsServiceRequest(
- int32_t network_traffic_annotation_hash_id);
-
- // |pref_service| can be used for accessing local state prefs. Can be null.
- // |network_connection_tracker| is guaranteed to be non-null.
- DataUseMeasurement(
- PrefService* pref_service,
- network::NetworkConnectionTracker* network_connection_tracker);
-
- DataUseMeasurement(const DataUseMeasurement&) = delete;
- DataUseMeasurement& operator=(const DataUseMeasurement&) = delete;
-
- ~DataUseMeasurement() override;
-
-#if defined(OS_ANDROID)
- // This function should just be used for testing purposes. A change in
- // application state can be simulated by calling this function.
- void OnApplicationStateChangeForTesting(
- base::android::ApplicationState application_state);
-#endif
-
- void AddServicesDataUseObserver(ServicesDataUseObserver* observer);
- void RemoveServicesDataUseObserver(ServicesDataUseObserver* observer);
-
- // Should be called to record downstream data used by user-initiated trafffic
- // requests. |is_tab_visible| is set to true if the traffic was initiated from
- // a tab that was visible in foreground when the data use was observed.
- void RecordDownstreamUserTrafficSizeMetric(bool is_tab_visible,
- int64_t bytes);
-
- protected:
- // Specifies that data is received or sent, respectively.
- enum TrafficDirection { DOWNSTREAM, UPSTREAM };
-
- // Returns the current application state (Foreground or Background). It always
- // returns Foreground if Chrome is not running on Android.
- DataUseUserData::AppState CurrentAppState() const;
-
- // Records data use histograms of services. It gets the size of exchanged
- // message, its direction (which is upstream or downstream) and reports to the
- // histogram DataUse.Services.{Dimensions} with, services as the buckets.
- // |app_state| indicates the app state which can be foreground, or background.
- void ReportDataUsageServices(int32_t traffic_annotation_hash,
- TrafficDirection dir,
- DataUseUserData::AppState app_state,
- int64_t message_size_bytes);
-
- // Returns if the current network connection type is cellular.
- bool IsCurrentNetworkCellular() const;
-
- static void RegisterDataUseComponentLocalStatePrefs(
- PrefRegistrySimple* registry);
-
- base::ObserverList<ServicesDataUseObserver>::Unchecked
- services_data_use_observer_list_;
-
- private:
- friend class DataUseMeasurementTest;
-
- // Records the count of bytes received and sent by Chrome on the network as
- // reported by the operating system. If |force_record_metrics| is true, the
- // data use metrics are always recorded. If |force_record_metrics| is false,
- // data use may be recorded only if it's expected to be high.
- void MaybeRecordNetworkBytesOS(bool force_record_metrics);
-
- // Makes the full name of the histogram. It is made from |prefix| and suffix
- // which is made based on network and application status. suffix is a string
- // representing whether the data use was on the send ("Upstream") or receive
- // ("Downstream") path, and whether the app was in the "Foreground" or
- // "Background".
- static std::string GetHistogramNameWithConnectionType(
- const char* prefix,
- TrafficDirection dir,
- DataUseUserData::AppState app_state);
-
- // Makes the full name of the histogram. It is made from |prefix| and suffix
- // which is made based on network and application status. suffix is a string
- // representing whether the data use was on the send ("Upstream") or receive
- // ("Downstream") path, whether the app was in the "Foreground" or
- // "Background", and whether a "Cellular" or "WiFi" network was use. For
- // example, "Prefix.Upstream.Foreground.Cellular" is a possible output.
- // |app_state| indicates the app state which can be foreground, background, or
- // unknown.
- static std::string GetHistogramName(const char* prefix,
- TrafficDirection dir,
- DataUseUserData::AppState app_state,
- bool is_connection_cellular);
-
-#if defined(OS_ANDROID)
- // Called whenever the application transitions from foreground to background
- // and vice versa.
- void OnApplicationStateChange(
- base::android::ApplicationState application_state);
-#endif
-
- // Records data use histograms split on TrafficDirection, AppState and
- // TabState.
- void RecordTabStateHistogram(TrafficDirection dir,
- DataUseUserData::AppState app_state,
- bool is_tab_visible,
- int64_t bytes) const;
-
- // NetworkConnectionObserver overrides
- void OnConnectionChanged(
- network::mojom::ConnectionType connection_type) override;
-
-#if defined(OS_ANDROID)
- // Application listener store the last known state of the application in this
- // field.
- base::android::ApplicationState app_state_ =
- base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES;
-
- // ApplicationStatusListener used to monitor whether the application is in the
- // foreground or in the background. It is owned by DataUseMeasurement.
- std::unique_ptr<base::android::ApplicationStatusListener> app_listener_;
-#endif
-
- // Number of bytes received and sent by Chromium as reported by the operating
- // system when it was last queried for traffic statistics. Set to 0 if the
- // operating system was never queried.
- int64_t rx_bytes_os_ = 0;
- int64_t tx_bytes_os_ = 0;
-
- // Watches for network connection changes. Global singleton object and
- // outlives |this|
- raw_ptr<network::NetworkConnectionTracker> network_connection_tracker_;
-
- // The current connection type.
- network::mojom::ConnectionType connection_type_ =
- network::mojom::ConnectionType::CONNECTION_UNKNOWN;
-
- // Number of bytes received and sent by Chromium as reported by the network
- // delegate since the operating system was last queried for traffic
- // statistics.
- int64_t bytes_transferred_since_last_traffic_stats_query_ = 0;
-
- SEQUENCE_CHECKER(sequence_checker_);
-
- // Records the data usage in prefs.
- DataUseTrackerPrefs data_use_tracker_prefs_;
-
- base::WeakPtrFactory<DataUseMeasurement> weak_ptr_factory_{this};
-};
-
-} // namespace data_use_measurement
-
-#endif // COMPONENTS_DATA_USE_MEASUREMENT_CORE_DATA_USE_MEASUREMENT_H_
diff --git a/chromium/components/data_use_measurement/core/data_use_measurement_unittest.cc b/chromium/components/data_use_measurement/core/data_use_measurement_unittest.cc
deleted file mode 100644
index 51f4242db79..00000000000
--- a/chromium/components/data_use_measurement/core/data_use_measurement_unittest.cc
+++ /dev/null
@@ -1,113 +0,0 @@
-// Copyright 2015 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.
-
-#include "components/data_use_measurement/core/data_use_measurement.h"
-
-#include <memory>
-#include <string>
-
-#include "base/run_loop.h"
-#include "base/test/metrics/histogram_tester.h"
-#include "base/test/task_environment.h"
-#include "build/build_config.h"
-#include "components/data_use_measurement/core/data_use_pref_names.h"
-#include "components/prefs/pref_registry_simple.h"
-#include "components/prefs/testing_pref_service.h"
-#include "net/base/network_change_notifier.h"
-#include "services/network/test/test_network_connection_tracker.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-#if defined(OS_ANDROID)
-#include "base/android/application_status_listener.h"
-#endif
-
-namespace data_use_measurement {
-
-class DataUseMeasurementTest {
- public:
- explicit DataUseMeasurementTest(TestingPrefServiceSimple* test_prefs_)
- : data_use_measurement_(
- test_prefs_,
- network::TestNetworkConnectionTracker::GetInstance()) {
- // During the test it is expected to not have cellular connection.
- DCHECK(!net::NetworkChangeNotifier::IsConnectionCellular(
- net::NetworkChangeNotifier::GetConnectionType()));
- }
-
- DataUseMeasurementTest(const DataUseMeasurementTest&) = delete;
- DataUseMeasurementTest& operator=(const DataUseMeasurementTest&) = delete;
-
- // This function makes a user request and confirms that its effect is
- // reflected in proper histograms.
- void TestForAUserRequest(const std::string& target_dimension) {
- base::HistogramTester histogram_tester;
- data_use_measurement_.RecordDownstreamUserTrafficSizeMetric(
- true /* is_tab_visible */, 5 /* bytest */);
- data_use_measurement_.RecordDownstreamUserTrafficSizeMetric(
- true /* is_tab_visible */, 5 /* bytest */);
- histogram_tester.ExpectTotalCount("DataUse.TrafficSize.User.Downstream." +
- target_dimension + kConnectionType,
- 2);
- }
-
-
- DataUseMeasurement* data_use_measurement() { return &data_use_measurement_; }
-
- protected:
- // Required to register a NetworkConnectionObserver from the constructor of
- // DataUseMeasurement.
- base::test::TaskEnvironment task_environment_;
-
- DataUseMeasurement data_use_measurement_;
- const std::string kConnectionType = "NotCellular";
-};
-
-// This test function tests recording of data use information in UMA histogram
-// when packet is originated from user or services when the app is in the
-// foreground or the OS is not Android.
-// TODO(amohammadkhan): Add tests for Cellular/non-cellular connection types
-// when support for testing is provided in its class.
-TEST(DataUseMeasurementTest, UserNotUserTest) {
- TestingPrefServiceSimple test_prefs;
-
- test_prefs.registry()->RegisterDictionaryPref(prefs::kDataUsedUserForeground);
- test_prefs.registry()->RegisterDictionaryPref(prefs::kDataUsedUserBackground);
- test_prefs.registry()->RegisterDictionaryPref(
- prefs::kDataUsedServicesForeground);
- test_prefs.registry()->RegisterDictionaryPref(
- prefs::kDataUsedServicesBackground);
-
- DataUseMeasurementTest data_use_measurement_test(&test_prefs);
-#if defined(OS_ANDROID)
- data_use_measurement_test.data_use_measurement()
- ->OnApplicationStateChangeForTesting(
- base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES);
-#endif
- data_use_measurement_test.TestForAUserRequest("Foreground.");
-}
-
-#if defined(OS_ANDROID)
-// This test function tests recording of data use information in UMA histogram
-// when packet is originated from user or services when the app is in the
-// background and OS is Android.
-TEST(DataUseMeasurementTest, ApplicationStateTest) {
- TestingPrefServiceSimple test_prefs;
-
- test_prefs.registry()->RegisterDictionaryPref(prefs::kDataUsedUserForeground);
- test_prefs.registry()->RegisterDictionaryPref(prefs::kDataUsedUserBackground);
- test_prefs.registry()->RegisterDictionaryPref(
- prefs::kDataUsedServicesForeground);
- test_prefs.registry()->RegisterDictionaryPref(
- prefs::kDataUsedServicesBackground);
-
- DataUseMeasurementTest data_use_measurement_test(&test_prefs);
-
- data_use_measurement_test.data_use_measurement()
- ->OnApplicationStateChangeForTesting(
- base::android::APPLICATION_STATE_HAS_STOPPED_ACTIVITIES);
- data_use_measurement_test.TestForAUserRequest("Background.");
-}
-#endif
-
-} // namespace data_use_measurement
diff --git a/chromium/components/data_use_measurement/core/data_use_pref_names.h b/chromium/components/data_use_measurement/core/data_use_pref_names.h
deleted file mode 100644
index ef74cb3a0c6..00000000000
--- a/chromium/components/data_use_measurement/core/data_use_pref_names.h
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2020 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.
-
-#ifndef COMPONENTS_DATA_USE_MEASUREMENT_CORE_DATA_USE_PREF_NAMES_H_
-#define COMPONENTS_DATA_USE_MEASUREMENT_CORE_DATA_USE_PREF_NAMES_H_
-
-namespace data_use_measurement {
-
-namespace prefs {
-// Dictionary prefs for measuring cellular data used. |key| is
-// the date of data usage (stored as string using exploded format). |value|
-// stores the data used for that date as a double in kilobytes.
-const char kDataUsedUserForeground[] =
- "data_use_measurement.data_used.user.foreground";
-const char kDataUsedUserBackground[] =
- "data_use_measurement.data_used.user.background";
-const char kDataUsedServicesForeground[] =
- "data_use_measurement.data_used.services.foreground";
-const char kDataUsedServicesBackground[] =
- "data_use_measurement.data_used.services.background";
-} // namespace prefs
-
-} // namespace data_use_measurement
-
-#endif // COMPONENTS_DATA_USE_MEASUREMENT_CORE_DATA_USE_PREF_NAMES_H_
diff --git a/chromium/components/data_use_measurement/core/data_use_tracker_prefs.cc b/chromium/components/data_use_measurement/core/data_use_tracker_prefs.cc
deleted file mode 100644
index 1a1a498291d..00000000000
--- a/chromium/components/data_use_measurement/core/data_use_tracker_prefs.cc
+++ /dev/null
@@ -1,131 +0,0 @@
-// Copyright 2020 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.
-
-#include "components/data_use_measurement/core/data_use_tracker_prefs.h"
-
-#include <string>
-
-#include "base/bind.h"
-#include "base/callback_helpers.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/numerics/safe_conversions.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_util.h"
-#include "base/strings/stringprintf.h"
-#include "base/task/post_task.h"
-#include "base/task/task_traits.h"
-#include "base/time/clock.h"
-#include "base/time/time.h"
-#include "base/values.h"
-#include "build/build_config.h"
-#include "components/data_use_measurement/core/data_use_pref_names.h"
-#include "components/prefs/pref_registry_simple.h"
-#include "components/prefs/scoped_user_pref_update.h"
-
-namespace data_use_measurement {
-
-DataUseTrackerPrefs::DataUseTrackerPrefs(const base::Clock* time_clock,
- PrefService* pref_service)
- : time_clock_(time_clock), pref_service_(pref_service) {
- DCHECK(time_clock_);
-
- RemoveExpiredEntriesForPref(prefs::kDataUsedUserForeground);
- RemoveExpiredEntriesForPref(prefs::kDataUsedUserBackground);
- RemoveExpiredEntriesForPref(prefs::kDataUsedServicesForeground);
- RemoveExpiredEntriesForPref(prefs::kDataUsedServicesBackground);
-}
-
-void DataUseTrackerPrefs::ReportNetworkServiceDataUse(
- bool is_metered_connection,
- bool is_app_foreground,
- bool is_user_traffic,
- int64_t sent_or_recv_bytes) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
- if (!is_metered_connection)
- return;
-
- if (sent_or_recv_bytes <= 0)
- return;
-
- if (is_user_traffic && is_app_foreground) {
- UpdateUsagePref(prefs::kDataUsedUserForeground, sent_or_recv_bytes);
- } else if (is_user_traffic && !is_app_foreground) {
- UpdateUsagePref(prefs::kDataUsedUserBackground, sent_or_recv_bytes);
- } else if (!is_user_traffic && is_app_foreground) {
- UpdateUsagePref(prefs::kDataUsedServicesForeground, sent_or_recv_bytes);
- } else {
- UpdateUsagePref(prefs::kDataUsedServicesBackground, sent_or_recv_bytes);
- }
-}
-
-base::Time DataUseTrackerPrefs::GetCurrentMeasurementDate() const {
- return time_clock_->Now().LocalMidnight();
-}
-
-void DataUseTrackerPrefs::RemoveExpiredEntriesForPref(
- const std::string& pref_name) {
- if (!pref_service_)
- return;
-
- const base::DictionaryValue* user_pref_dict =
- pref_service_->GetDictionary(pref_name);
- const base::Time current_date = GetCurrentMeasurementDate();
- const base::Time last_date = current_date - base::Days(60);
-
- base::DictionaryValue user_pref_new_dict;
- for (auto it : user_pref_dict->DictItems()) {
- base::Time key_date;
- if (base::Time::FromUTCString(it.first.c_str(), &key_date) &&
- key_date > last_date) {
- user_pref_new_dict.Set(it.first,
- base::Value::ToUniquePtrValue(it.second.Clone()));
- }
- }
- pref_service_->Set(pref_name, user_pref_new_dict);
-}
-
-std::string DataUseTrackerPrefs::GetCurrentMeasurementDateAsString() const {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
- base::Time::Exploded today_exploded;
- GetCurrentMeasurementDate().LocalExplode(&today_exploded);
- std::string date =
- base::StringPrintf("%04d-%02d-%02d", today_exploded.year,
- today_exploded.month, today_exploded.day_of_month);
- return date;
-}
-
-void DataUseTrackerPrefs::UpdateUsagePref(const std::string& pref_name,
- int64_t message_size_bytes) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
- if (!pref_service_)
- return;
-
- DictionaryPrefUpdate pref_updater(pref_service_, pref_name);
- std::string todays_key = GetCurrentMeasurementDateAsString();
-
- const base::DictionaryValue* user_pref_dict =
- pref_service_->GetDictionary(pref_name);
- double todays_traffic = user_pref_dict->FindDoubleKey(todays_key).value_or(0);
- pref_updater->SetDouble(
- todays_key,
- todays_traffic + (static_cast<double>(message_size_bytes) / 1024.0));
-}
-
-// static
-void DataUseTrackerPrefs::RegisterDataUseTrackerLocalStatePrefs(
- PrefRegistrySimple* registry) {
- registry->RegisterDictionaryPref(prefs::kDataUsedUserForeground,
- PrefRegistry::LOSSY_PREF);
- registry->RegisterDictionaryPref(prefs::kDataUsedUserBackground,
- PrefRegistry::LOSSY_PREF);
- registry->RegisterDictionaryPref(prefs::kDataUsedServicesForeground,
- PrefRegistry::LOSSY_PREF);
- registry->RegisterDictionaryPref(prefs::kDataUsedServicesBackground,
- PrefRegistry::LOSSY_PREF);
-}
-
-} // namespace data_use_measurement
diff --git a/chromium/components/data_use_measurement/core/data_use_tracker_prefs.h b/chromium/components/data_use_measurement/core/data_use_tracker_prefs.h
deleted file mode 100644
index f0bd3a94599..00000000000
--- a/chromium/components/data_use_measurement/core/data_use_tracker_prefs.h
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright 2020 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.
-
-#ifndef COMPONENTS_DATA_USE_MEASUREMENT_CORE_DATA_USE_TRACKER_PREFS_H_
-#define COMPONENTS_DATA_USE_MEASUREMENT_CORE_DATA_USE_TRACKER_PREFS_H_
-
-#include <memory>
-
-#include "base/memory/raw_ptr.h"
-#include "base/sequence_checker.h"
-#include "base/time/clock.h"
-#include "base/time/time.h"
-
-class PrefRegistrySimple;
-class PrefService;
-
-namespace data_use_measurement {
-
-// DataUseTrackerPrefs keeps track of the data used over last 60 days. The data
-// used is recorded separately based on whether the data use was initiated by a
-// Chrome service or a user-initiated request.
-class DataUseTrackerPrefs {
- public:
- // |pref_service| may be null in tests.
- DataUseTrackerPrefs(const base::Clock* time_clock, PrefService* pref_service);
-
- // Move-only class.
- DataUseTrackerPrefs(const DataUseTrackerPrefs&) = delete;
- DataUseTrackerPrefs& operator=(const DataUseTrackerPrefs&) = delete;
-
- // Report data used by a service or a user-initiated request.
- // |is_metered_connection| should be true if data consumption happened on a
- // metered connection. |is_app_foreground| should be true if data was used
- // when Chrome app was in foregorund. |is_user_traffic| should be true if data
- // was used by a user-initiated request. |sent_or_recv_bytes| should be set to
- // the data consumed (in bytes).
- void ReportNetworkServiceDataUse(bool is_metered_connection,
- bool is_app_foreground,
- bool is_user_traffic,
- int64_t sent_or_recv_bytes);
-
- // Register local state prefs.
- static void RegisterDataUseTrackerLocalStatePrefs(
- PrefRegistrySimple* registry);
-
- private:
- // Returns the current date for measurement.
- base::Time GetCurrentMeasurementDate() const;
-
- // Removes entries from the given |pref_name| if they are too old.
- void RemoveExpiredEntriesForPref(const std::string& pref_name);
-
- // Returns the current date as a string with a proper formatting.
- std::string GetCurrentMeasurementDateAsString() const;
-
- // Updates provided |pref_name| for a current date with the given message
- // size.
- void UpdateUsagePref(const std::string& pref_name,
- int64_t message_size_bytes);
-
- raw_ptr<const base::Clock> time_clock_;
- raw_ptr<PrefService> pref_service_ = nullptr;
-
- SEQUENCE_CHECKER(sequence_checker_);
-};
-
-} // namespace data_use_measurement
-
-#endif // COMPONENTS_DATA_USE_MEASUREMENT_CORE_DATA_USE_TRACKER_PREFS_H_
diff --git a/chromium/components/data_use_measurement/core/data_use_tracker_prefs_unittest.cc b/chromium/components/data_use_measurement/core/data_use_tracker_prefs_unittest.cc
deleted file mode 100644
index 6dfee5b33e9..00000000000
--- a/chromium/components/data_use_measurement/core/data_use_tracker_prefs_unittest.cc
+++ /dev/null
@@ -1,172 +0,0 @@
-// Copyright 2020 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.
-
-#include "components/data_use_measurement/core/data_use_tracker_prefs.h"
-
-#include <string>
-
-#include "base/run_loop.h"
-#include "base/test/simple_test_clock.h"
-#include "components/data_use_measurement/core/data_use_pref_names.h"
-#include "components/prefs/pref_registry_simple.h"
-#include "components/prefs/testing_pref_service.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace data_use_measurement {
-
-void RegisterPrefs(TestingPrefServiceSimple* test_prefs) {
- test_prefs->registry()->RegisterDictionaryPref(
- prefs::kDataUsedUserForeground);
- test_prefs->registry()->RegisterDictionaryPref(
- prefs::kDataUsedUserBackground);
- test_prefs->registry()->RegisterDictionaryPref(
- prefs::kDataUsedServicesForeground);
- test_prefs->registry()->RegisterDictionaryPref(
- prefs::kDataUsedServicesBackground);
-}
-
-class DataUseTrackerPrefsTest {
- public:
- DataUseTrackerPrefsTest(base::SimpleTestClock* clock,
- TestingPrefServiceSimple* test_prefs)
- : data_use_tracker_prefs_(clock, test_prefs) {
- // Register the prefs before accessing them.
- }
-
- DataUseTrackerPrefsTest(const DataUseTrackerPrefsTest&) = delete;
- DataUseTrackerPrefsTest& operator=(const DataUseTrackerPrefsTest&) = delete;
-
- DataUseTrackerPrefs* data_use_tracker_prefs() {
- return &data_use_tracker_prefs_;
- }
-
- private:
- DataUseTrackerPrefs data_use_tracker_prefs_;
-};
-
-// Verifies that the prefs are stored correctly: The date is used as the key
-// in the pref and the expired keys are removed.
-TEST(DataUseTrackerPrefsTest, PrefsOnMeteredConnection) {
- base::SimpleTestClock clock;
- clock.SetNow(base::Time::Now());
- TestingPrefServiceSimple test_prefs;
- RegisterPrefs(&test_prefs);
-
- // Report 2 data uses for the same day.
- DataUseTrackerPrefsTest tracker_prefs_test_1(&clock, &test_prefs);
- tracker_prefs_test_1.data_use_tracker_prefs()->ReportNetworkServiceDataUse(
- true, true, true, 10);
- EXPECT_EQ(
- 1u, test_prefs.GetDictionary(prefs::kDataUsedUserForeground)->DictSize());
- tracker_prefs_test_1.data_use_tracker_prefs()->ReportNetworkServiceDataUse(
- true, true, true, 10);
- EXPECT_EQ(
- 1u, test_prefs.GetDictionary(prefs::kDataUsedUserForeground)->DictSize());
-
- // Verify other prefs are not set.
- EXPECT_TRUE(
- test_prefs.GetDictionary(prefs::kDataUsedUserBackground)->DictEmpty());
- EXPECT_TRUE(
- test_prefs.GetDictionary(prefs::kDataUsedServicesForeground)->DictEmpty());
- EXPECT_TRUE(
- test_prefs.GetDictionary(prefs::kDataUsedServicesBackground)->DictEmpty());
-
- // Move clock forward 10 days. New data use reported must go in a separate
- // entry in the dictionary pref.
- clock.Advance(base::Days(10));
- DataUseTrackerPrefsTest tracker_prefs_test_2(&clock, &test_prefs);
- EXPECT_EQ(
- 1u, test_prefs.GetDictionary(prefs::kDataUsedUserForeground)->DictSize());
- tracker_prefs_test_2.data_use_tracker_prefs()->ReportNetworkServiceDataUse(
- true, true, true, 10);
- EXPECT_EQ(
- 2u, test_prefs.GetDictionary(prefs::kDataUsedUserForeground)->DictSize());
-
- // Move clock forward 55 days. This should clean up the first entry since they
- // are now 65 days older (i.e., more than 60 days old). New data use reported
- // must go in a separate entry in the dictionary pref.
- clock.Advance(base::Days(55));
- DataUseTrackerPrefsTest tracker_prefs_test_3(&clock, &test_prefs);
- EXPECT_EQ(
- 1u, test_prefs.GetDictionary(prefs::kDataUsedUserForeground)->DictSize());
- tracker_prefs_test_2.data_use_tracker_prefs()->ReportNetworkServiceDataUse(
- true, true, true, 10);
- EXPECT_EQ(
- 2u, test_prefs.GetDictionary(prefs::kDataUsedUserForeground)->DictSize());
-}
-
-// Verifies that the prefs are not updated on unmetered connections.
-TEST(DataUseTrackerPrefsTest, PrefsOnUnmeteredConnection) {
- base::SimpleTestClock clock;
- clock.SetNow(base::Time::Now());
- TestingPrefServiceSimple test_prefs;
- RegisterPrefs(&test_prefs);
-
- // Report 2 data uses for the same day.
- DataUseTrackerPrefsTest tracker_prefs_test_1(&clock, &test_prefs);
- tracker_prefs_test_1.data_use_tracker_prefs()->ReportNetworkServiceDataUse(
- /*is_metered_connection=*/false, true, true, 10);
- tracker_prefs_test_1.data_use_tracker_prefs()->ReportNetworkServiceDataUse(
- /*is_metered_connection=*/false, true, true, 10);
-
- // Verify prefs are not set.
- EXPECT_TRUE(
- test_prefs.GetDictionary(prefs::kDataUsedUserForeground)->DictEmpty());
- EXPECT_TRUE(
- test_prefs.GetDictionary(prefs::kDataUsedUserBackground)->DictEmpty());
- EXPECT_TRUE(
- test_prefs.GetDictionary(prefs::kDataUsedServicesForeground)->DictEmpty());
- EXPECT_TRUE(
- test_prefs.GetDictionary(prefs::kDataUsedServicesBackground)->DictEmpty());
-}
-
-TEST(DataUseTrackerPrefsTest, TestBasicUserForeground) {
- base::SimpleTestClock clock;
- clock.SetNow(base::Time::Now());
- TestingPrefServiceSimple test_prefs;
- RegisterPrefs(&test_prefs);
-
- // Report 2 data uses for the same day.
- DataUseTrackerPrefsTest tracker_prefs_test(&clock, &test_prefs);
-
- const struct {
- bool foreground;
- bool user_initiated;
- std::string pref_expected_as_non_empty;
- } tests[] = {
- {false, false, prefs::kDataUsedServicesBackground},
- {false, true, prefs::kDataUsedUserBackground},
- {true, false, prefs::kDataUsedServicesForeground},
- {true, true, prefs::kDataUsedUserForeground},
- };
-
- for (const auto& test : tests) {
- test_prefs.ClearPref(prefs::kDataUsedServicesBackground);
- test_prefs.ClearPref(prefs::kDataUsedUserBackground);
- test_prefs.ClearPref(prefs::kDataUsedServicesForeground);
- test_prefs.ClearPref(prefs::kDataUsedServicesForeground);
-
- tracker_prefs_test.data_use_tracker_prefs()->ReportNetworkServiceDataUse(
- true, test.foreground, test.user_initiated, 10);
- // Verify that the expected pref has an entry.
- EXPECT_FALSE(
- test_prefs.GetDictionary(test.pref_expected_as_non_empty)->DictEmpty());
-
- // Verify other prefs are not set.
- EXPECT_TRUE(
- test.pref_expected_as_non_empty == prefs::kDataUsedUserForeground ||
- test_prefs.GetDictionary(prefs::kDataUsedUserForeground)->DictEmpty());
- EXPECT_TRUE(
- test.pref_expected_as_non_empty == prefs::kDataUsedUserBackground ||
- test_prefs.GetDictionary(prefs::kDataUsedUserBackground)->DictEmpty());
- EXPECT_TRUE(
- test.pref_expected_as_non_empty == prefs::kDataUsedServicesForeground ||
- test_prefs.GetDictionary(prefs::kDataUsedServicesForeground)->DictEmpty());
- EXPECT_TRUE(
- test.pref_expected_as_non_empty == prefs::kDataUsedServicesBackground ||
- test_prefs.GetDictionary(prefs::kDataUsedServicesBackground)->DictEmpty());
- }
-}
-
-} // namespace data_use_measurement
diff --git a/chromium/components/data_use_measurement/core/data_use_user_data.cc b/chromium/components/data_use_measurement/core/data_use_user_data.cc
deleted file mode 100644
index 8e4d54a1908..00000000000
--- a/chromium/components/data_use_measurement/core/data_use_user_data.cc
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2015 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.
-
-#include "components/data_use_measurement/core/data_use_user_data.h"
-
-#include <memory>
-
-#include "build/build_config.h"
-#include "net/url_request/url_fetcher.h"
-
-#if defined(OS_ANDROID)
-#include "base/android/application_status_listener.h"
-#endif
-
-namespace data_use_measurement {
-
-DataUseUserData::DataUseUserData(AppState app_state)
- : app_state_(app_state), content_type_(DataUseContentType::OTHER) {}
-
-DataUseUserData::~DataUseUserData() {}
-
-// static
-const void* const DataUseUserData::kUserDataKey =
- &DataUseUserData::kUserDataKey;
-
-} // namespace data_use_measurement
diff --git a/chromium/components/data_use_measurement/core/data_use_user_data.h b/chromium/components/data_use_measurement/core/data_use_user_data.h
deleted file mode 100644
index 7d092652acf..00000000000
--- a/chromium/components/data_use_measurement/core/data_use_user_data.h
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright 2015 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.
-
-#ifndef COMPONENTS_DATA_USE_MEASUREMENT_CORE_DATA_USE_USER_DATA_H_
-#define COMPONENTS_DATA_USE_MEASUREMENT_CORE_DATA_USE_USER_DATA_H_
-
-#include "base/supports_user_data.h"
-
-namespace data_use_measurement {
-
-// Used to annotate URLRequests with the service name if the URLRequest is used
-// by a service.
-class DataUseUserData : public base::SupportsUserData::Data {
- public:
- // Data use broken by content type. This enum must remain synchronized
- // with the enum of the same name in metrics/histograms/histograms.xml.
- // These values are written to logs. New enum values can be added, but
- // existing enums must never be renumbered or deleted and reused.
- enum DataUseContentType {
- OTHER = 0,
- MAIN_FRAME_HTML = 1,
- NON_MAIN_FRAME_HTML = 2,
- CSS = 3,
- IMAGE = 4,
- JAVASCRIPT = 5,
- FONT = 6,
- AUDIO_APPBACKGROUND = 7,
- AUDIO_TABBACKGROUND = 8,
- AUDIO = 9,
- VIDEO_APPBACKGROUND = 10,
- VIDEO_TABBACKGROUND = 11,
- VIDEO = 12,
- kMaxValue = 13,
- };
-
- // The state of the application. Only available on Android and on other
- // platforms it is always FOREGROUND.
- enum AppState { UNKNOWN, BACKGROUND, FOREGROUND };
-
- explicit DataUseUserData(AppState app_state);
-
- DataUseUserData(const DataUseUserData&) = delete;
- DataUseUserData& operator=(const DataUseUserData&) = delete;
-
- ~DataUseUserData() override;
-
- AppState app_state() const { return app_state_; }
-
- void set_app_state(AppState app_state) { app_state_ = app_state; }
-
- DataUseContentType content_type() { return content_type_; }
-
- void set_content_type(DataUseContentType content_type) {
- content_type_ = content_type;
- }
-
- // The key for retrieving back this type of user data.
- static const void* const kUserDataKey;
-
- private:
- // App state when network access was performed for the request previously.
- AppState app_state_;
-
- DataUseContentType content_type_;
-};
-
-} // namespace data_use_measurement
-
-#endif // COMPONENTS_DATA_USE_MEASUREMENT_CORE_DATA_USE_USER_DATA_H_
diff --git a/chromium/components/database_utils/OWNERS b/chromium/components/database_utils/OWNERS
new file mode 100644
index 00000000000..7923121ed84
--- /dev/null
+++ b/chromium/components/database_utils/OWNERS
@@ -0,0 +1 @@
+file://components/history/OWNERS
diff --git a/chromium/components/dbus/menu/menu_property_list_unittest.cc b/chromium/components/dbus/menu/menu_property_list_unittest.cc
index d406b34e420..1f5ddfff665 100644
--- a/chromium/components/dbus/menu/menu_property_list_unittest.cc
+++ b/chromium/components/dbus/menu/menu_property_list_unittest.cc
@@ -22,7 +22,7 @@
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/image/image_skia_rep_default.h"
-#if defined(OS_LINUX)
+#if BUILDFLAG(IS_LINUX)
#include "ui/ozone/public/ozone_platform.h"
#endif
@@ -325,7 +325,7 @@ TEST(MenuPropertyListTest, ComputePropertiesIcon) {
EXPECT_EQ(menu->ComputeProperties(), props);
}
-#if defined(OS_LINUX)
+#if BUILDFLAG(IS_LINUX)
TEST(MenuPropertyListTest, ComputePropertiesAccelerator) {
// The Wayland implementation requires the keyboard layout to be set.
// The ScopedKeyboardLayout does not unset the already existing layout engine,
diff --git a/chromium/components/desks_storage/BUILD.gn b/chromium/components/desks_storage/BUILD.gn
index 5702d517acc..7e4f64c9d4e 100644
--- a/chromium/components/desks_storage/BUILD.gn
+++ b/chromium/components/desks_storage/BUILD.gn
@@ -15,12 +15,16 @@ static_library("desks_storage") {
"core/desk_sync_service.h",
"core/desk_template_conversion.cc",
"core/desk_template_conversion.h",
+ "core/desk_template_util.cc",
+ "core/desk_template_util.h",
"core/local_desk_data_manager.cc",
"core/local_desk_data_manager.h",
]
deps = [
"//ash/public/cpp",
"//base",
+ "//components/account_id",
+ "//components/app_constants",
"//components/app_restore",
"//components/sync",
"//components/sync/model",
@@ -40,6 +44,7 @@ source_set("unit_tests") {
sources = [
"core/desk_sync_bridge_unittest.cc",
"core/desk_template_conversion_unittests.cc",
+ "core/desk_template_util_unittests.cc",
"core/local_desks_data_manager_unittests.cc",
]
deps = [
@@ -47,6 +52,7 @@ source_set("unit_tests") {
"//ash/public/cpp",
"//base",
"//base/test:test_support",
+ "//components/app_constants",
"//components/sync:test_support",
"//testing/gtest",
]
diff --git a/chromium/components/desks_storage/DEPS b/chromium/components/desks_storage/DEPS
index a35abc38802..c804595792a 100644
--- a/chromium/components/desks_storage/DEPS
+++ b/chromium/components/desks_storage/DEPS
@@ -2,12 +2,12 @@ include_rules = [
"+ash/public",
"+chromeos/ui/base/window_state_type.h",
"+components/account_id/account_id.h",
+ "+components/app_constants/constants.h",
"+components/app_restore",
"+components/keyed_service/core",
"+components/services/app_service/public/cpp",
"+components/sync",
"+components/version_info",
- "+extensions/common/constants.h",
"+third_party/re2",
"+ui/base/ui_base_types.h",
"+ui/gfx/geometry"
diff --git a/chromium/components/desks_storage/core/desk_model.cc b/chromium/components/desks_storage/core/desk_model.cc
index 23f34894f71..3855c99b930 100644
--- a/chromium/components/desks_storage/core/desk_model.cc
+++ b/chromium/components/desks_storage/core/desk_model.cc
@@ -5,8 +5,10 @@
#include "components/desks_storage/core/desk_model.h"
#include "ash/public/cpp/desk_template.h"
+#include "base/guid.h"
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
+#include "base/logging.h"
#include "components/desks_storage/core/desk_model_observer.h"
#include "components/desks_storage/core/desk_template_conversion.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
@@ -46,30 +48,56 @@ void DeskModel::RemoveObserver(DeskModelObserver* observer) {
observers_.RemoveObserver(observer);
}
-void DeskModel::SetPolicyDeskTemplates(const std::string& policyJson) {
+void DeskModel::GetTemplateJson(const std::string& uuid,
+ apps::AppRegistryCache* app_cache,
+ GetTemplateJsonCallback callback) {
+ GetEntryByUUID(
+ uuid,
+ base::BindOnce(&DeskModel::HandleTemplateConversionToPolicyJson,
+ base::Unretained(this), std::move(callback), app_cache));
+}
+
+void DeskModel::SetPolicyDeskTemplates(const std::string& policy_json) {
policy_entries_.clear();
- base::StringPiece raw_json = base::StringPiece(policyJson);
+ base::StringPiece raw_json = base::StringPiece(policy_json);
base::JSONReader::ValueWithError parsed_list =
base::JSONReader::ReadAndReturnValueWithError(raw_json);
- if (!parsed_list.value || !parsed_list.value->is_list())
+ if (!parsed_list.value)
+ return;
+
+ if (!parsed_list.value->is_list()) {
+ LOG(WARNING) << "Expected JSON list in admin templates policy.";
return;
+ }
- for (auto& desk_template : parsed_list.value->GetList()) {
+ for (auto& desk_template : parsed_list.value->GetListDeprecated()) {
std::unique_ptr<ash::DeskTemplate> dt =
desk_template_conversion::ParseDeskTemplateFromPolicy(desk_template);
- if (dt)
+ if (dt) {
policy_entries_.push_back(std::move(dt));
+ } else {
+ LOG(WARNING) << "Failed to parse admin template from JSON: "
+ << desk_template;
+ }
}
}
-void DeskModel::GetTemplateJson(const std::string& uuid,
- apps::AppRegistryCache* app_cache,
- GetTemplateJsonCallback callback) {
- GetEntryByUUID(
- uuid,
- base::BindOnce(&DeskModel::HandleTemplateConversionToPolicyJson,
- base::Unretained(this), std::move(callback), app_cache));
+void DeskModel::RemovePolicyDeskTemplates() {
+ policy_entries_.clear();
+}
+
+std::unique_ptr<ash::DeskTemplate> DeskModel::GetAdminDeskTemplateByUUID(
+ const std::string& uuid_str) const {
+ const base::GUID uuid = base::GUID::ParseCaseInsensitive(uuid_str);
+
+ for (const std::unique_ptr<ash::DeskTemplate>& policy_entry :
+ policy_entries_) {
+ if (policy_entry->uuid() == uuid)
+ return policy_entry->Clone();
+ }
+
+ return nullptr;
}
void DeskModel::HandleTemplateConversionToPolicyJson(
@@ -84,10 +112,12 @@ void DeskModel::HandleTemplateConversionToPolicyJson(
}
std::string raw_json;
- bool conversion_success = base::JSONWriter::Write(
- desk_template_conversion::SerializeDeskTemplateAsPolicy(entry.get(),
- app_cache),
- &raw_json);
+ base::Value template_list(base::Value::Type::LIST);
+ template_list.Append(desk_template_conversion::SerializeDeskTemplateAsPolicy(
+ entry.get(), app_cache));
+
+ const bool conversion_success =
+ base::JSONWriter::Write(template_list, &raw_json);
if (conversion_success)
std::move(callback).Run(GetTemplateJsonStatus::kOk, raw_json);
diff --git a/chromium/components/desks_storage/core/desk_model.h b/chromium/components/desks_storage/core/desk_model.h
index 2fdef802b45..8221dc130d1 100644
--- a/chromium/components/desks_storage/core/desk_model.h
+++ b/chromium/components/desks_storage/core/desk_model.h
@@ -49,11 +49,15 @@ class DeskModel {
};
// Status codes for adding or updating a desk template.
+ // These values are persisted to logs. Entries should not be renumbered and
+ // numeric values should never be reused.
enum class AddOrUpdateEntryStatus {
- kOk,
- kFailure,
- kInvalidArgument,
- kHitMaximumLimit,
+ kOk = 0,
+ kFailure = 1,
+ kInvalidArgument = 2,
+ kHitMaximumLimit = 3,
+ kEntryTooLarge = 4,
+ kMaxValue = kEntryTooLarge,
};
// Status codes for deleting desk templates.
@@ -84,15 +88,15 @@ class DeskModel {
using GetEntryByUuidCallback =
base::OnceCallback<void(GetEntryByUuidStatus status,
std::unique_ptr<ash::DeskTemplate> entry)>;
- // Get a specific desk template by |uuid|. Actual storage backend does not
+ // Get a specific desk template by `uuid`. Actual storage backend does not
// need to keep desk templates in memory. The storage backend could load the
- // specified desk template into memory and then call the |callback| with a
+ // specified desk template into memory and then call the `callback` with a
// unique_ptr to the loaded desk template.
- // If the specified desk template does not exist, |callback| will be called
- // with |kNotFound| and an empty unique_ptr. If the specified desk template
- // exists, but could not be loaded/parsed, |callback| will be called with
- // |kFailure| and an empty unique_ptr. An asynchronous |callback| is used here
- // to accommodate storage backend that need to perform asynchronous I/O.
+ // If the specified desk template does not exist, `callback` will be called
+ // with `kNotFound` and a `nullptr`. If the specified desk template exists,
+ // but could not be loaded/parsed, `callback` will be called with `kFailure`
+ // and a nullptr. An asynchronous `callback` is used here to accommodate
+ // storage backend that need to perform asynchronous I/O.
virtual void GetEntryByUUID(const std::string& uuid,
GetEntryByUuidCallback callback) = 0;
@@ -153,10 +157,18 @@ class DeskModel {
void AddObserver(DeskModelObserver* observer);
void RemoveObserver(DeskModelObserver* observer);
- // Operations to update the preconfigured desk templates from policy
- void SetPolicyDeskTemplates(const std::string& policyJson);
+ // Updates the preconfigured desk templates from policy.
+ void SetPolicyDeskTemplates(const std::string& policy_json);
+
+ // Removes the preconfigured desk templates from policy.
+ void RemovePolicyDeskTemplates();
protected:
+ // Finds the admin desk template with the given `uuid`. Returns `nullptr` if
+ // none is found.
+ std::unique_ptr<ash::DeskTemplate> GetAdminDeskTemplateByUUID(
+ const std::string& uuid) const;
+
// The observers.
base::ObserverList<DeskModelObserver>::Unchecked observers_;
diff --git a/chromium/components/desks_storage/core/desk_sync_bridge.cc b/chromium/components/desks_storage/core/desk_sync_bridge.cc
index a1794fda37b..5f07a1d6ed6 100644
--- a/chromium/components/desks_storage/core/desk_sync_bridge.cc
+++ b/chromium/components/desks_storage/core/desk_sync_bridge.cc
@@ -19,10 +19,12 @@
#include "base/time/time.h"
#include "chromeos/ui/base/window_state_type.h"
#include "components/account_id/account_id.h"
+#include "components/app_constants/constants.h"
#include "components/app_restore/app_launch_info.h"
#include "components/app_restore/window_info.h"
#include "components/desks_storage/core/desk_model_observer.h"
#include "components/desks_storage/core/desk_template_conversion.h"
+#include "components/desks_storage/core/desk_template_util.h"
#include "components/services/app_service/public/cpp/app_registry_cache.h"
#include "components/services/app_service/public/cpp/app_registry_cache_wrapper.h"
#include "components/sync/model/entity_change.h"
@@ -32,7 +34,6 @@
#include "components/sync/model/mutable_data_batch.h"
#include "components/sync/protocol/model_type_state.pb.h"
#include "components/sync/protocol/workspace_desk_specifics.pb.h"
-#include "extensions/common/constants.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "ui/base/ui_base_types.h"
@@ -41,6 +42,8 @@ namespace desks_storage {
using BrowserAppTab =
sync_pb::WorkspaceDeskSpecifics_BrowserAppWindow_BrowserAppTab;
using BrowserAppWindow = sync_pb::WorkspaceDeskSpecifics_BrowserAppWindow;
+using ArcApp = sync_pb::WorkspaceDeskSpecifics_ArcApp;
+using ArcAppWindowSize = sync_pb::WorkspaceDeskSpecifics_ArcApp_WindowSize;
using ash::DeskTemplate;
using ash::DeskTemplateSource;
using WindowState = sync_pb::WorkspaceDeskSpecifics_WindowState;
@@ -56,6 +59,13 @@ using syncer::ModelTypeStore;
// The maximum number of templates the local storage can hold.
constexpr std::size_t kMaxTemplateCount = 6u;
+// The maximum number of bytes a template can be.
+// Sync server silently ignores large items. The client-side
+// needs to check item size to avoid sending large items.
+// This limit follows precedent set by the chrome extension API:
+// chrome.storage.sync.QUOTA_BYTES_PER_ITEM.
+constexpr std::size_t kMaxTemplateSize = 8192u;
+
// Allocate a EntityData and copies |specifics| into it.
std::unique_ptr<syncer::EntityData> CopyToEntityData(
const sync_pb::WorkspaceDeskSpecifics& specifics) {
@@ -120,11 +130,13 @@ std::string GetAppId(const sync_pb::WorkspaceDeskSpecifics_App& app) {
return std::string();
case sync_pb::WorkspaceDeskSpecifics_AppOneOf::AppCase::kBrowserAppWindow:
// Browser app has a known app ID.
- return std::string(extension_misc::kChromeAppId);
+ return std::string(app_constants::kChromeAppId);
case sync_pb::WorkspaceDeskSpecifics_AppOneOf::AppCase::kChromeApp:
return app.app().chrome_app().app_id();
case sync_pb::WorkspaceDeskSpecifics_AppOneOf::AppCase::kProgressWebApp:
return app.app().progress_web_app().app_id();
+ case sync_pb::WorkspaceDeskSpecifics_AppOneOf::AppCase::kArcApp:
+ return app.app().arc_app().app_id();
// Leave out the default case to let compiler to ensure we have
// exhaustively handled all cases.
}
@@ -168,6 +180,9 @@ std::unique_ptr<app_restore::AppLaunchInfo> ConvertToAppLaunchInfo(
case sync_pb::WorkspaceDeskSpecifics_AppOneOf::AppCase::kProgressWebApp:
// |app_id| is enough to identify a Progressive Web app.
break;
+ case sync_pb::WorkspaceDeskSpecifics_AppOneOf::AppCase::kArcApp:
+ // |app_id| is enough to identify an Arc app.
+ break;
// Leave out the default case to let compiler to ensure we have
// exhaustively handled all cases.
}
@@ -294,6 +309,9 @@ void FillBrowserAppWindow(BrowserAppWindow* out_browser_app_window,
}
// Fill |out_window_bound| with information from |bound|.
+//
+// TOOD(crbug/1295051): here and elsewhere move out_* args to end of parameter
+// lists.
void FillWindowBound(WindowBound* out_window_bound, const gfx::Rect& bound) {
out_window_bound->set_left(bound.x());
out_window_bound->set_top(bound.y());
@@ -333,6 +351,36 @@ void FillAppWithDisplayId(WorkspaceDeskSpecifics_App* out_app,
out_app->set_display_id(app_restore_data->display_id.value());
}
+void FillArcAppSize(ArcAppWindowSize* out_window_size, const gfx::Size& size) {
+ out_window_size->set_width(size.width());
+ out_window_size->set_height(size.height());
+}
+
+void FillArcBoundsInRoot(WindowBound* out_rect, const gfx::Rect& data_rect) {
+ out_rect->set_left(data_rect.x());
+ out_rect->set_top(data_rect.y());
+ out_rect->set_width(data_rect.width());
+ out_rect->set_height(data_rect.height());
+}
+
+void FillArcApp(ArcApp* out_app,
+ const app_restore::AppRestoreData* app_restore_data) {
+ if (app_restore_data->minimum_size.has_value()) {
+ FillArcAppSize(out_app->mutable_minimum_size(),
+ app_restore_data->minimum_size.value());
+ }
+ if (app_restore_data->maximum_size.has_value()) {
+ FillArcAppSize(out_app->mutable_maximum_size(),
+ app_restore_data->maximum_size.value());
+ }
+ if (app_restore_data->title.has_value())
+ out_app->set_title(base::UTF16ToUTF8(app_restore_data->title.value()));
+ if (app_restore_data->bounds_in_root.has_value()) {
+ FillArcBoundsInRoot(out_app->mutable_bounds_in_root(),
+ app_restore_data->bounds_in_root.value());
+ }
+}
+
// Fill |out_app| with |app_restore_data|.
void FillApp(WorkspaceDeskSpecifics_App* out_app,
const std::string& app_id,
@@ -347,7 +395,7 @@ void FillApp(WorkspaceDeskSpecifics_App* out_app,
// See definition components/services/app_service/public/mojom/types.mojom
switch (app_type) {
case apps::mojom::AppType::kWeb: {
- if (extension_misc::kChromeAppId == app_id) {
+ if (app_constants::kChromeAppId == app_id) {
// Chrome Browser Window.
BrowserAppWindow* browser_app_window =
out_app->mutable_app()->mutable_browser_app_window();
@@ -381,6 +429,12 @@ void FillApp(WorkspaceDeskSpecifics_App* out_app,
}
break;
}
+ case apps::mojom::AppType::kArc: {
+ ArcApp* arc_app = out_app->mutable_app()->mutable_arc_app();
+ arc_app->set_app_id(app_id);
+ FillArcApp(arc_app, app_restore_data);
+ break;
+ }
default: {
// Unhandled app type.
break;
@@ -388,6 +442,28 @@ void FillApp(WorkspaceDeskSpecifics_App* out_app,
}
}
+void FillArcExtraInfoFromProto(app_restore::WindowInfo* out_window_info,
+ const ArcApp& app) {
+ out_window_info->arc_extra_info.emplace();
+ app_restore::WindowInfo::ArcExtraInfo& arc_info =
+ out_window_info->arc_extra_info.value();
+ if (app.has_minimum_size()) {
+ arc_info.minimum_size.emplace(app.minimum_size().width(),
+ app.minimum_size().height());
+ }
+ if (app.has_maximum_size()) {
+ arc_info.maximum_size.emplace(app.maximum_size().width(),
+ app.maximum_size().height());
+ }
+ if (app.has_title())
+ arc_info.title.emplace(base::UTF8ToUTF16(app.title()));
+ if (app.has_bounds_in_root()) {
+ arc_info.bounds_in_root.emplace(
+ app.bounds_in_root().left(), app.bounds_in_root().top(),
+ app.bounds_in_root().width(), app.bounds_in_root().height());
+ }
+}
+
// Fill |out_window_info| with information from Sync proto |app|.
void FillWindowInfoFromProto(app_restore::WindowInfo* out_window_info,
sync_pb::WorkspaceDeskSpecifics_App& app) {
@@ -414,6 +490,11 @@ void FillWindowInfoFromProto(app_restore::WindowInfo* out_window_info,
out_window_info->pre_minimized_show_state_type.emplace(
ToUiWindowState(app.pre_minimized_window_state()));
}
+
+ if (app.app().app_case() ==
+ sync_pb::WorkspaceDeskSpecifics_AppOneOf::AppCase::kArcApp) {
+ FillArcExtraInfoFromProto(out_window_info, app.app().arc_app());
+ }
}
// Convert a desk template to |app_restore::RestoreData|.
@@ -462,7 +543,7 @@ void FillWorkspaceDeskSpecifics(
// The apps cache returns kChromeApp for browser windows, therefore we
// short circuit the cache retrieval if we get the browser ID.
const apps::mojom::AppType app_type =
- app_id == extension_misc::kChromeAppId
+ app_id == app_constants::kChromeAppId
? apps::mojom::AppType::kWeb
: apps_cache->GetAppType(app_id);
@@ -580,7 +661,7 @@ absl::optional<syncer::ModelError> DeskSyncBridge::ApplySyncChanges(
// Add/update the remote_entry to the model.
entries_[uuid] = std::move(remote_entry);
- added_or_updated.push_back(GetEntryByUUID(uuid));
+ added_or_updated.push_back(GetUserEntryByUUID(uuid));
// Write to the store.
batch->WriteData(uuid.AsLowercaseString(), serialized_remote_entry);
@@ -604,7 +685,7 @@ void DeskSyncBridge::GetData(StorageKeyList storage_keys,
for (const std::string& uuid : storage_keys) {
const DeskTemplate* entry =
- GetEntryByUUID(base::GUID::ParseCaseInsensitive(uuid));
+ GetUserEntryByUUID(base::GUID::ParseCaseInsensitive(uuid));
if (!entry) {
continue;
}
@@ -655,22 +736,27 @@ void DeskSyncBridge::GetAllEntries(GetAllEntriesCallback callback) {
void DeskSyncBridge::GetEntryByUUID(const std::string& uuid_str,
GetEntryByUuidCallback callback) {
if (!IsReady()) {
- std::move(callback).Run(GetEntryByUuidStatus::kFailure,
- std::unique_ptr<DeskTemplate>());
+ std::move(callback).Run(GetEntryByUuidStatus::kFailure, nullptr);
return;
}
const base::GUID uuid = base::GUID::ParseCaseInsensitive(uuid_str);
if (!uuid.is_valid()) {
- std::move(callback).Run(GetEntryByUuidStatus::kInvalidUuid,
- std::unique_ptr<DeskTemplate>());
+ std::move(callback).Run(GetEntryByUuidStatus::kInvalidUuid, nullptr);
return;
}
auto it = entries_.find(uuid);
if (it == entries_.end()) {
- std::move(callback).Run(GetEntryByUuidStatus::kNotFound,
- std::unique_ptr<DeskTemplate>());
+ std::unique_ptr<DeskTemplate> policy_entry =
+ GetAdminDeskTemplateByUUID(uuid_str);
+
+ if (policy_entry) {
+ std::move(callback).Run(GetEntryByUuidStatus::kOk,
+ std::move(policy_entry));
+ } else {
+ std::move(callback).Run(GetEntryByUuidStatus::kNotFound, nullptr);
+ }
} else {
std::move(callback).Run(GetEntryByUuidStatus::kOk,
it->second.get()->Clone());
@@ -700,16 +786,32 @@ void DeskSyncBridge::AddOrUpdateEntry(std::unique_ptr<DeskTemplate> new_entry,
entry->set_template_name(
base::CollapseWhitespace(new_entry->template_name(), true));
+ // While we still find duplicate names iterate the duplicate number. i.e.
+ // if there are 4 duplicates of some template name then this iterates until
+ // the current template will be named 5.
+ while (HasUserTemplateWithName(entry->template_name())) {
+ entry->set_template_name(
+ desk_template_util::AppendDuplicateNumberToDuplicateName(
+ entry->template_name()));
+ }
+
std::unique_ptr<ModelTypeStore::WriteBatch> batch =
store_->CreateWriteBatch();
- // Add/update this entry to the store and model.
- auto entity_data = CopyToEntityData(ToSyncProto(entry.get()));
+ // Check the new entry size and ensure it is below the size limit.
+ auto sync_proto = ToSyncProto(entry.get());
+ if (sync_proto.ByteSizeLong() > kMaxTemplateSize) {
+ std::move(callback).Run(AddOrUpdateEntryStatus::kEntryTooLarge);
+ return;
+ }
+
+ // Add/update this entry to the store and model.
+ auto entity_data = CopyToEntityData(sync_proto);
change_processor()->Put(uuid.AsLowercaseString(), std::move(entity_data),
batch->GetMetadataChangeList());
entries_[uuid] = std::move(entry);
- const DeskTemplate* result = GetEntryByUUID(uuid);
+ const DeskTemplate* result = GetUserEntryByUUID(uuid);
batch->WriteData(uuid.AsLowercaseString(),
ToSyncProto(result).SerializeAsString());
@@ -730,7 +832,7 @@ void DeskSyncBridge::DeleteEntry(const std::string& uuid_str,
const base::GUID uuid = base::GUID::ParseCaseInsensitive(uuid_str);
- if (GetEntryByUUID(uuid) == nullptr) {
+ if (GetUserEntryByUUID(uuid) == nullptr) {
// Consider the deletion successful if the entry does not exist.
std::move(callback).Run(DeleteEntryStatus::kOk);
return;
@@ -775,11 +877,11 @@ void DeskSyncBridge::DeleteAllEntries(DeleteEntryCallback callback) {
}
std::size_t DeskSyncBridge::GetEntryCount() const {
- return entries_.size();
+ return entries_.size() + policy_entries_.size();
}
std::size_t DeskSyncBridge::GetMaxEntryCount() const {
- return kMaxTemplateCount;
+ return kMaxTemplateCount + policy_entries_.size();
}
std::vector<base::GUID> DeskSyncBridge::GetAllEntryUuids() const {
@@ -831,7 +933,7 @@ sync_pb::WorkspaceDeskSpecifics DeskSyncBridge::ToSyncProto(
return pb_entry;
}
-const DeskTemplate* DeskSyncBridge::GetEntryByUUID(
+const DeskTemplate* DeskSyncBridge::GetUserEntryByUUID(
const base::GUID& uuid) const {
auto it = entries_.find(uuid);
if (it == entries_.end())
@@ -952,4 +1054,13 @@ void DeskSyncBridge::UploadLocalOnlyData(
}
}
+bool DeskSyncBridge::HasUserTemplateWithName(const std::u16string& name) {
+ return std::find_if(
+ entries_.begin(), entries_.end(),
+ [&name](std::pair<const base::GUID,
+ std::unique_ptr<ash::DeskTemplate>>& entry) {
+ return entry.second->template_name() == name;
+ }) != entries_.end();
+}
+
} // namespace desks_storage
diff --git a/chromium/components/desks_storage/core/desk_sync_bridge.h b/chromium/components/desks_storage/core/desk_sync_bridge.h
index a736617b8b1..00ae0b39c80 100644
--- a/chromium/components/desks_storage/core/desk_sync_bridge.h
+++ b/chromium/components/desks_storage/core/desk_sync_bridge.h
@@ -86,7 +86,7 @@ class DeskSyncBridge : public syncer::ModelTypeSyncBridge, public DeskModel {
sync_pb::WorkspaceDeskSpecifics ToSyncProto(
const ash::DeskTemplate* desk_template);
- const ash::DeskTemplate* GetEntryByUUID(const base::GUID& uuid) const;
+ const ash::DeskTemplate* GetUserEntryByUUID(const base::GUID& uuid) const;
private:
using DeskEntries = std::map<base::GUID, std::unique_ptr<ash::DeskTemplate>>;
@@ -119,6 +119,9 @@ class DeskSyncBridge : public syncer::ModelTypeSyncBridge, public DeskModel {
void UploadLocalOnlyData(syncer::MetadataChangeList* metadata_change_list,
const syncer::EntityChangeList& entity_data);
+ // Returns true if `templates_` contains a desk template with `name`.
+ bool HasUserTemplateWithName(const std::u16string& name);
+
// |entries_| is keyed by UUIDs.
DeskEntries entries_;
diff --git a/chromium/components/desks_storage/core/desk_sync_bridge_unittest.cc b/chromium/components/desks_storage/core/desk_sync_bridge_unittest.cc
index 838e8252668..c0efadc4bd1 100644
--- a/chromium/components/desks_storage/core/desk_sync_bridge_unittest.cc
+++ b/chromium/components/desks_storage/core/desk_sync_bridge_unittest.cc
@@ -10,6 +10,8 @@
#include "ash/public/cpp/desk_template.h"
#include "base/guid.h"
+#include "base/json/json_reader.h"
+#include "base/json/json_writer.h"
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
@@ -17,19 +19,20 @@
#include "base/test/simple_test_clock.h"
#include "base/test/task_environment.h"
#include "components/account_id/account_id.h"
+#include "components/app_constants/constants.h"
#include "components/app_restore/app_launch_info.h"
#include "components/desks_storage/core/desk_model_observer.h"
+#include "components/desks_storage/core/desk_template_conversion.h"
#include "components/services/app_service/public/cpp/app_registry_cache.h"
#include "components/services/app_service/public/cpp/app_registry_cache_wrapper.h"
-#include "components/sync/engine/entity_data.h"
#include "components/sync/model/entity_change.h"
#include "components/sync/model/in_memory_metadata_change_list.h"
#include "components/sync/model/metadata_batch.h"
+#include "components/sync/protocol/entity_data.h"
#include "components/sync/protocol/model_type_state.pb.h"
#include "components/sync/test/model/mock_model_type_change_processor.h"
#include "components/sync/test/model/model_type_store_test_util.h"
#include "components/sync/test/model/test_matchers.h"
-#include "extensions/common/constants.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -37,6 +40,8 @@ namespace desks_storage {
using BrowserAppTab =
sync_pb::WorkspaceDeskSpecifics_BrowserAppWindow_BrowserAppTab;
+using ArcApp = sync_pb::WorkspaceDeskSpecifics_ArcApp;
+using ArcSize = sync_pb::WorkspaceDeskSpecifics_ArcApp_WindowSize;
using BrowserAppWindow = sync_pb::WorkspaceDeskSpecifics_BrowserAppWindow;
using ChromeApp = sync_pb::WorkspaceDeskSpecifics_ChromeApp;
using Desk = sync_pb::WorkspaceDeskSpecifics_Desk;
@@ -69,7 +74,10 @@ using testing::StrEq;
constexpr char kTestPwaAppId[] = "test_pwa_app_id";
constexpr char kTestChromeAppId[] = "test_chrome_app_id";
+constexpr char kTestArcAppId[] = "test_arc_app_id";
constexpr char kUuidFormat[] = "9e186d5a-502e-49ce-9ee1-00000000000%d";
+constexpr char kAdminTemplateUuidFormat[] =
+ "59dbe2b8-671f-4fd0-92ec-11111111100%d";
constexpr char kNameFormat[] = "template %d";
constexpr char kTestUrlFormat[] = "https://www.testdomain%d.com/";
constexpr int kDefaultTemplateIndex = 1;
@@ -82,6 +90,8 @@ const base::GUID kTestUuid8 =
base::GUID::ParseCaseInsensitive(base::StringPrintf(kUuidFormat, 8));
const base::GUID kTestUuid9 =
base::GUID::ParseCaseInsensitive(base::StringPrintf(kUuidFormat, 9));
+const base::GUID kTestAdminTemplateUuid1 = base::GUID::ParseCaseInsensitive(
+ base::StringPrintf(kAdminTemplateUuidFormat, 1));
const std::string kPolicyWithTwoTemplates =
"[{\"version\":1,\"uuid\":\"" + base::StringPrintf(kUuidFormat, 8) +
@@ -109,16 +119,17 @@ const std::string kPolicyWithTwoTemplates =
"2\",\"title\":\"Example2\"}],\"active_tab_index\":1,\"window_id\":0,"
"\"display_id\":\"100\",\"pre_minimized_window_state\":\"NORMAL\"}]}}]";
-void FillExampleBrowserAppWindow(WorkspaceDeskSpecifics_App* app) {
+void FillExampleBrowserAppWindow(WorkspaceDeskSpecifics_App* app,
+ int number_of_tabs = 2) {
BrowserAppWindow* app_window =
app->mutable_app()->mutable_browser_app_window();
- BrowserAppTab* tab1 = app_window->add_tabs();
- tab1->set_url(base::StringPrintf(kTestUrlFormat, 1));
- BrowserAppTab* tab2 = app_window->add_tabs();
- tab2->set_url(base::StringPrintf(kTestUrlFormat, 2));
+ for (int i = 0; i < number_of_tabs; ++i) {
+ BrowserAppTab* tab = app_window->add_tabs();
+ tab->set_url(base::StringPrintf(kTestUrlFormat, i));
+ }
- app_window->set_active_tab_index(1);
+ app_window->set_active_tab_index(number_of_tabs - 1);
WindowBound* window_bound = app->mutable_window_bound();
window_bound->set_left(110);
@@ -166,10 +177,41 @@ void FillExampleChromeAppWindow(WorkspaceDeskSpecifics_App* app) {
app->set_window_id(2555);
}
+void FillExampleArcAppWindow(WorkspaceDeskSpecifics_App* app) {
+ ArcApp* app_window = app->mutable_app()->mutable_arc_app();
+ app_window->set_app_id(kTestArcAppId);
+
+ ArcSize* minimum_size = app_window->mutable_minimum_size();
+ minimum_size->set_width(1);
+ minimum_size->set_height(1);
+
+ ArcSize* maximum_size = app_window->mutable_maximum_size();
+ maximum_size->set_width(256);
+ maximum_size->set_height(256);
+
+ WindowBound* bounds_in_root = app_window->mutable_bounds_in_root();
+ bounds_in_root->set_width(1024);
+ bounds_in_root->set_height(1024);
+ bounds_in_root->set_left(0);
+ bounds_in_root->set_top(0);
+
+ WindowBound* window_bound = app->mutable_window_bound();
+ window_bound->set_left(210);
+ window_bound->set_top(220);
+ window_bound->set_width(2330);
+ window_bound->set_height(2440);
+ app->set_window_state(
+ WindowState::WorkspaceDeskSpecifics_WindowState_MAXIMIZED);
+ app->set_display_id(99887766l);
+ app->set_z_index(233);
+ app->set_window_id(2555);
+}
+
WorkspaceDeskSpecifics ExampleWorkspaceDeskSpecifics(
const std::string uuid,
const std::string template_name,
- base::Time created_time = base::Time::Now()) {
+ base::Time created_time = base::Time::Now(),
+ int number_of_tabs = 2) {
WorkspaceDeskSpecifics specifics;
specifics.set_uuid(uuid);
specifics.set_name(template_name);
@@ -180,7 +222,8 @@ WorkspaceDeskSpecifics ExampleWorkspaceDeskSpecifics(
.ToDeltaSinceWindowsEpoch()
.InMicroseconds());
Desk* desk = specifics.mutable_desk();
- FillExampleBrowserAppWindow(desk->add_apps());
+ FillExampleBrowserAppWindow(desk->add_apps(), number_of_tabs);
+ FillExampleArcAppWindow(desk->add_apps());
FillExampleChromeAppWindow(desk->add_apps());
FillExampleProgressiveWebAppWindow(desk->add_apps());
return specifics;
@@ -206,7 +249,7 @@ std::unique_ptr<ash::DeskTemplate> CreateTemplateWithBrowserFromScratch(
auto restore_data = std::make_unique<app_restore::RestoreData>();
auto browser_info = std::make_unique<app_restore::AppLaunchInfo>(
- extension_misc::kChromeAppId, kBrowserWindowId);
+ app_constants::kChromeAppId, kBrowserWindowId);
browser_info->urls = {GURL(base::StringPrintf(kTestUrlFormat, 1)),
GURL(base::StringPrintf(kTestUrlFormat, 2))};
@@ -329,10 +372,12 @@ class DeskSyncBridgeTest : public testing::Test {
deltas.push_back(
MakeApp(kTestPwaAppId, "Test PWA App", apps::mojom::AppType::kWeb));
// chromeAppId returns kExtension in the real Apps cache.
- deltas.push_back(MakeApp(extension_misc::kChromeAppId, "Chrome Browser",
+ deltas.push_back(MakeApp(app_constants::kChromeAppId, "Chrome Browser",
apps::mojom::AppType::kChromeApp));
deltas.push_back(MakeApp(kTestChromeAppId, "Test Chrome App",
apps::mojom::AppType::kChromeApp));
+ deltas.push_back(
+ MakeApp(kTestArcAppId, "Arc app", apps::mojom::AppType::kArc));
cache_->OnApps(std::move(deltas), apps::mojom::AppType::kUnknown,
false /* should_notify_initialized */);
@@ -431,6 +476,55 @@ class DeskSyncBridgeTest : public testing::Test {
loop2.Run();
}
+ void AddTwoTemplatesWithDuplicatedNames() {
+ // These two templates will have new UUIDs but with names that collides with
+ // "template 1"
+ auto desk_template1 =
+ DeskSyncBridge::FromSyncProto(ExampleWorkspaceDeskSpecifics(
+ kTestUuid8.AsLowercaseString(), "template 1", AdvanceAndGetTime()));
+ auto desk_template2 =
+ DeskSyncBridge::FromSyncProto(ExampleWorkspaceDeskSpecifics(
+ kTestUuid9.AsLowercaseString(), "template 1", AdvanceAndGetTime()));
+
+ base::RunLoop loop1;
+ bridge()->AddOrUpdateEntry(
+ std::move(desk_template1),
+ base::BindLambdaForTesting(
+ [&](DeskModel::AddOrUpdateEntryStatus status) {
+ EXPECT_EQ(DeskModel::AddOrUpdateEntryStatus::kOk, status);
+ loop1.Quit();
+ }));
+ loop1.Run();
+
+ base::RunLoop loop2;
+ bridge()->AddOrUpdateEntry(
+ std::move(desk_template2),
+ base::BindLambdaForTesting(
+ [&](DeskModel::AddOrUpdateEntryStatus status) {
+ EXPECT_EQ(DeskModel::AddOrUpdateEntryStatus::kOk, status);
+ loop2.Quit();
+ }));
+ loop2.Run();
+ }
+
+ void SetOneAdminTemplate() {
+ auto admin_template1 =
+ DeskSyncBridge::FromSyncProto(ExampleWorkspaceDeskSpecifics(
+ kTestAdminTemplateUuid1.AsLowercaseString(), "admin template 1",
+ AdvanceAndGetTime()));
+
+ std::string policy_json;
+ base::Value template_list(base::Value::Type::LIST);
+ template_list.Append(
+ desk_template_conversion::SerializeDeskTemplateAsPolicy(
+ admin_template1.get(), cache_.get()));
+ bool conversion_success =
+ base::JSONWriter::Write(template_list, &policy_json);
+ EXPECT_TRUE(conversion_success);
+
+ bridge()->SetPolicyDeskTemplates(policy_json);
+ }
+
MockModelTypeChangeProcessor* processor() { return &mock_processor_; }
DeskSyncBridge* bridge() { return bridge_.get(); }
@@ -439,6 +533,8 @@ class DeskSyncBridgeTest : public testing::Test {
base::SimpleTestClock* clock() { return &clock_; }
+ apps::AppRegistryCache* app_cache() { return cache_.get(); }
+
private:
base::SimpleTestClock clock_;
@@ -522,17 +618,17 @@ TEST_F(DeskSyncBridgeTest, InitializationWithLocalDataAndMetadata) {
EXPECT_EQ(2ul, bridge()->GetAllEntryUuids().size());
// Verify both local specifics are loaded correctly.
- EXPECT_EQ(bridge()
- ->ToSyncProto(bridge()->GetEntryByUUID(
+ EXPECT_EQ(template1.SerializeAsString(),
+ bridge()
+ ->ToSyncProto(bridge()->GetUserEntryByUUID(
base::GUID::ParseCaseInsensitive(template1.uuid())))
- .SerializeAsString(),
- template1.SerializeAsString());
+ .SerializeAsString());
- EXPECT_EQ(bridge()
- ->ToSyncProto(bridge()->GetEntryByUUID(
+ EXPECT_EQ(template2.SerializeAsString(),
+ bridge()
+ ->ToSyncProto(bridge()->GetUserEntryByUUID(
base::GUID::ParseCaseInsensitive(template2.uuid())))
- .SerializeAsString(),
- template2.SerializeAsString());
+ .SerializeAsString());
}
TEST_F(DeskSyncBridgeTest, GetAllEntriesIncludesPolicyEntries) {
@@ -608,15 +704,40 @@ TEST_F(DeskSyncBridgeTest, AddEntriesLocally) {
EXPECT_EQ(2ul, bridge()->GetAllEntryUuids().size());
// Verify the added desk template content.
- EXPECT_EQ(bridge()
- ->ToSyncProto(bridge()->GetEntryByUUID(kTestUuid1))
- .SerializeAsString(),
- specifics1.SerializeAsString());
+ EXPECT_EQ(specifics1.SerializeAsString(),
+ bridge()
+ ->ToSyncProto(bridge()->GetUserEntryByUUID(kTestUuid1))
+ .SerializeAsString());
+
+ EXPECT_EQ(specifics2.SerializeAsString(),
+ bridge()
+ ->ToSyncProto(bridge()->GetUserEntryByUUID(kTestUuid2))
+ .SerializeAsString());
+}
- EXPECT_EQ(bridge()
- ->ToSyncProto(bridge()->GetEntryByUUID(kTestUuid2))
- .SerializeAsString(),
- specifics2.SerializeAsString());
+TEST_F(DeskSyncBridgeTest, AddEntryShouldFailWhenEntryIsTooLarge) {
+ InitializeBridge();
+
+ EXPECT_CALL(*mock_observer(), EntriesAddedOrUpdatedRemotely(_)).Times(0);
+ EXPECT_CALL(*mock_observer(), EntriesRemovedRemotely(_)).Times(0);
+
+ EXPECT_EQ(0ul, bridge()->GetAllEntryUuids().size());
+
+ // Create a large entry with 500 tabs. This entry should be too large for
+ // Sync.
+ constexpr int number_of_tabs = 500;
+ auto specifics = ExampleWorkspaceDeskSpecifics(
+ kTestUuid1.AsLowercaseString(), "template 1", AdvanceAndGetTime(),
+ number_of_tabs);
+
+ base::RunLoop loop;
+ bridge()->AddOrUpdateEntry(
+ DeskSyncBridge::FromSyncProto(specifics),
+ base::BindLambdaForTesting([&](DeskModel::AddOrUpdateEntryStatus status) {
+ EXPECT_EQ(status, DeskModel::AddOrUpdateEntryStatus::kEntryTooLarge);
+ loop.Quit();
+ }));
+ loop.Run();
}
TEST_F(DeskSyncBridgeTest, AddEntryShouldSucceedWheSyncIsDisabled) {
@@ -663,6 +784,29 @@ TEST_F(DeskSyncBridgeTest, AddEntryShouldFailWhenBridgeIsNotReady) {
loop.Run();
}
+TEST_F(DeskSyncBridgeTest, AppendsDuplicateMarkingsCorrectly) {
+ InitializeBridge();
+
+ AddTwoTemplates();
+
+ EXPECT_EQ(2ul, bridge()->GetAllEntryUuids().size());
+
+ AddTwoTemplatesWithDuplicatedNames();
+
+ // The two duplicated templates should be added.
+ EXPECT_EQ(4ul, bridge()->GetAllEntryUuids().size());
+
+ // Template 8 should be renamed to avoid name collision.
+ EXPECT_EQ("template 1 (1)",
+ base::UTF16ToUTF8(
+ bridge()->GetUserEntryByUUID(kTestUuid8)->template_name()));
+
+ // Template 9 should be renamed twice to avoid name collision.
+ EXPECT_EQ("template 1 (2)",
+ base::UTF16ToUTF8(
+ bridge()->GetUserEntryByUUID(kTestUuid9)->template_name()));
+}
+
TEST_F(DeskSyncBridgeTest, GetEntryByUUIDShouldSucceed) {
InitializeBridge();
@@ -682,6 +826,28 @@ TEST_F(DeskSyncBridgeTest, GetEntryByUUIDShouldSucceed) {
loop.Run();
}
+TEST_F(DeskSyncBridgeTest, GetEntryByUUIDShouldReturnAdminTemplate) {
+ InitializeBridge();
+
+ AddTwoTemplates();
+
+ SetOneAdminTemplate();
+
+ // There should be 3 templates: 2 user templates + 1 admin template.
+ EXPECT_EQ(3ul, bridge()->GetAllEntryUuids().size());
+
+ base::RunLoop loop;
+ bridge()->GetEntryByUUID(
+ kTestAdminTemplateUuid1.AsLowercaseString(),
+ base::BindLambdaForTesting([&](DeskModel::GetEntryByUuidStatus status,
+ std::unique_ptr<ash::DeskTemplate> entry) {
+ EXPECT_EQ(DeskModel::GetEntryByUuidStatus::kOk, status);
+ EXPECT_TRUE(entry);
+ loop.Quit();
+ }));
+ loop.Run();
+}
+
TEST_F(DeskSyncBridgeTest, GetEntryByUUIDShouldFailWhenUuidIsNotFound) {
InitializeBridge();
@@ -749,14 +915,14 @@ TEST_F(DeskSyncBridgeTest, UpdateEntryLocally) {
// We should still have both templates.
EXPECT_EQ(2ul, bridge()->GetAllEntryUuids().size());
// Template 1 should be updated.
- EXPECT_EQ(
- base::UTF16ToUTF8(bridge()->GetEntryByUUID(kTestUuid1)->template_name()),
- "updated template 1");
+ EXPECT_EQ("updated template 1",
+ base::UTF16ToUTF8(
+ bridge()->GetUserEntryByUUID(kTestUuid1)->template_name()));
// Template 2 should be unchanged.
- EXPECT_EQ(
- base::UTF16ToUTF8(bridge()->GetEntryByUUID(kTestUuid2)->template_name()),
- "template 2");
+ EXPECT_EQ("template 2",
+ base::UTF16ToUTF8(
+ bridge()->GetUserEntryByUUID(kTestUuid2)->template_name()));
}
TEST_F(DeskSyncBridgeTest, DeleteEntryLocally) {
@@ -786,9 +952,9 @@ TEST_F(DeskSyncBridgeTest, DeleteEntryLocally) {
// We should have only 1 template.
EXPECT_EQ(1ul, bridge()->GetAllEntryUuids().size());
// Template 2 should be unchanged.
- EXPECT_EQ(
- base::UTF16ToUTF8(bridge()->GetEntryByUUID(kTestUuid2)->template_name()),
- "template 2");
+ EXPECT_EQ("template 2",
+ base::UTF16ToUTF8(
+ bridge()->GetUserEntryByUUID(kTestUuid2)->template_name()));
}
TEST_F(DeskSyncBridgeTest, DeleteAllEntriesLocally) {
@@ -871,16 +1037,16 @@ TEST_F(DeskSyncBridgeTest, ApplySyncChangesWithOneUpdate) {
// We should still have both templates.
EXPECT_EQ(2ul, bridge()->GetAllEntryUuids().size());
// Template 1 should be updated to new content.
- EXPECT_EQ(bridge()
- ->ToSyncProto(bridge()->GetEntryByUUID(
+ EXPECT_EQ(updated_template1.SerializeAsString(),
+ bridge()
+ ->ToSyncProto(bridge()->GetUserEntryByUUID(
base::GUID::ParseCaseInsensitive(template1.uuid())))
- .SerializeAsString(),
- updated_template1.SerializeAsString());
- EXPECT_EQ(bridge()
- ->ToSyncProto(bridge()->GetEntryByUUID(
+ .SerializeAsString());
+ EXPECT_EQ(template2.SerializeAsString(),
+ bridge()
+ ->ToSyncProto(bridge()->GetUserEntryByUUID(
base::GUID::ParseCaseInsensitive(template2.uuid())))
- .SerializeAsString(),
- template2.SerializeAsString());
+ .SerializeAsString());
}
// Tests that remote desk template can be correctly removed.
@@ -907,11 +1073,11 @@ TEST_F(DeskSyncBridgeTest, ApplySyncChangesWithOneDeletion) {
// Verify that we only have template 2.
EXPECT_EQ(1ul, bridge()->GetAllEntryUuids().size());
- EXPECT_EQ(bridge()
- ->ToSyncProto(bridge()->GetEntryByUUID(
+ EXPECT_EQ(template2.SerializeAsString(),
+ bridge()
+ ->ToSyncProto(bridge()->GetUserEntryByUUID(
base::GUID::ParseCaseInsensitive(template2.uuid())))
- .SerializeAsString(),
- template2.SerializeAsString());
+ .SerializeAsString());
}
TEST_F(DeskSyncBridgeTest, ApplySyncChangesDeleteNonexistent) {
@@ -971,6 +1137,65 @@ TEST_F(DeskSyncBridgeTest, MergeSyncDataUploadsLocalOnlyEntries) {
EXPECT_EQ(3ul, bridge()->GetAllEntryUuids().size());
}
+TEST_F(DeskSyncBridgeTest,
+ GetEntryCountShouldIncludeBothUserAndAdminTemplates) {
+ InitializeBridge();
+
+ AddTwoTemplates();
+
+ SetOneAdminTemplate();
+
+ // There should be 3 templates: 2 user templates + 1 admin template.
+ EXPECT_EQ(3ul, bridge()->GetEntryCount());
+}
+
+TEST_F(DeskSyncBridgeTest, GetMaxEntryCountShouldIncreaseWithAdminTemplates) {
+ InitializeBridge();
+
+ AddTwoTemplates();
+
+ std::size_t max_entry_count = bridge()->GetMaxEntryCount();
+
+ SetOneAdminTemplate();
+
+ // The max entry count should increase by 1 since we have set an admin
+ // template.
+ EXPECT_EQ(max_entry_count + 1ul, bridge()->GetMaxEntryCount());
+}
+
+TEST_F(DeskSyncBridgeTest, GetTemplateJsonShouldReturnList) {
+ InitializeBridge();
+
+ // Seed two templates.
+ // Seeded templates will be "template 1" and "template 2".
+ AddTwoTemplates();
+
+ // We should have seeded two templates.
+ EXPECT_EQ(2ul, bridge()->GetAllEntryUuids().size());
+
+ base::RunLoop loop;
+ bridge()->GetTemplateJson(
+ kTestUuid1.AsLowercaseString(), app_cache(),
+ base::BindLambdaForTesting([&](DeskModel::GetTemplateJsonStatus status,
+ const std::string& templates_json) {
+ EXPECT_EQ(DeskModel::GetTemplateJsonStatus::kOk, status);
+
+ EXPECT_TRUE(!templates_json.empty());
+
+ base::JSONReader::ValueWithError parsed_json =
+ base::JSONReader::ReadAndReturnValueWithError(
+ base::StringPiece(templates_json));
+
+ EXPECT_TRUE(parsed_json.value.has_value());
+ EXPECT_TRUE(parsed_json.value->is_list());
+
+ // Content of the conversion is tested in:
+ // components/desks_storage/core/desk_template_conversion_unittests.cc
+ loop.Quit();
+ }));
+ loop.Run();
+}
+
} // namespace
} // namespace desks_storage
diff --git a/chromium/components/desks_storage/core/desk_template_conversion.cc b/chromium/components/desks_storage/core/desk_template_conversion.cc
index 8ee7bc3de62..d308c6f6945 100644
--- a/chromium/components/desks_storage/core/desk_template_conversion.cc
+++ b/chromium/components/desks_storage/core/desk_template_conversion.cc
@@ -10,11 +10,11 @@
#include "base/json/values_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/time/time.h"
+#include "components/app_constants/constants.h"
#include "components/app_restore/app_launch_info.h"
#include "components/app_restore/restore_data.h"
#include "components/app_restore/window_info.h"
#include "components/services/app_service/public/cpp/app_registry_cache.h"
-#include "extensions/common/constants.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "ui/gfx/geometry/rect.h"
@@ -95,7 +95,7 @@ std::string GetJsonAppId(const base::Value& app) {
if (app_type == kAppTypeBrowser) {
// Browser app has a known app ID.
- return std::string(extension_misc::kChromeAppId);
+ return std::string(app_constants::kChromeAppId);
} else if (app_type == kAppTypeChrome || app_type == kAppTypeProgressiveWeb) {
// Read the provided app ID
std::string app_id;
@@ -151,7 +151,7 @@ std::unique_ptr<app_restore::AppLaunchInfo> ConvertJsonToAppLaunchInfo(
app_launch_info->urls.emplace();
const base::Value* tabs = app.FindKeyOfType(kTabs, base::Value::Type::LIST);
if (tabs) {
- for (auto& tab : tabs->GetList()) {
+ for (auto& tab : tabs->GetListDeprecated()) {
std::string url;
if (GetString(tab, kTabUrl, &url)) {
app_launch_info->urls.value().emplace_back(url);
@@ -266,7 +266,7 @@ std::unique_ptr<app_restore::RestoreData> ConvertJsonToRestoreData(
const base::Value* apps = desk->FindListKey(kApps);
if (apps) {
- for (const auto& app : apps->GetList()) {
+ for (const auto& app : apps->GetListDeprecated()) {
std::unique_ptr<app_restore::AppLaunchInfo> app_launch_info =
ConvertJsonToAppLaunchInfo(app);
if (!app_launch_info)
@@ -361,14 +361,14 @@ base::Value ConvertURLsToBrowserAppTabValues(const std::vector<GURL>& urls) {
std::string GetAppTypeForJson(apps::AppRegistryCache* apps_cache,
const std::string& app_id) {
- const apps::mojom::AppType app_type = app_id == extension_misc::kChromeAppId
+ const apps::mojom::AppType app_type = app_id == app_constants::kChromeAppId
? apps::mojom::AppType::kWeb
: apps_cache->GetAppType(app_id);
switch (app_type) {
case apps::mojom::AppType::kWeb:
- return app_id == extension_misc::kChromeAppId ? kAppTypeBrowser
- : kAppTypeProgressiveWeb;
+ return app_id == app_constants::kChromeAppId ? kAppTypeBrowser
+ : kAppTypeProgressiveWeb;
case apps::mojom::AppType::kChromeApp:
return kAppTypeChrome;
default:
@@ -521,4 +521,4 @@ base::Value SerializeDeskTemplateAsPolicy(const ash::DeskTemplate* desk,
} // namespace desk_template_conversion
-} // namespace desks_storage \ No newline at end of file
+} // namespace desks_storage
diff --git a/chromium/components/desks_storage/core/desk_template_conversion_unittests.cc b/chromium/components/desks_storage/core/desk_template_conversion_unittests.cc
index 14954241d9a..f9acd8e22a8 100644
--- a/chromium/components/desks_storage/core/desk_template_conversion_unittests.cc
+++ b/chromium/components/desks_storage/core/desk_template_conversion_unittests.cc
@@ -14,12 +14,12 @@
#include "base/test/task_environment.h"
#include "build/build_config.h"
#include "components/account_id/account_id.h"
+#include "components/app_constants/constants.h"
#include "components/app_restore/app_launch_info.h"
#include "components/app_restore/app_restore_data.h"
#include "components/app_restore/window_info.h"
#include "components/services/app_service/public/cpp/app_registry_cache.h"
#include "components/services/app_service/public/cpp/app_registry_cache_wrapper.h"
-#include "extensions/common/constants.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace desks_storage {
@@ -92,7 +92,7 @@ class DeskTemplateConversionTest : public testing::Test {
deltas.push_back(MakeApp(kProgressiveAppid.c_str(), "Test PWA App",
apps::mojom::AppType::kWeb));
// chromeAppId returns kExtension in the real Apps cache.
- deltas.push_back(MakeApp(extension_misc::kChromeAppId, "Chrome Browser",
+ deltas.push_back(MakeApp(app_constants::kChromeAppId, "Chrome Browser",
apps::mojom::AppType::kChromeApp));
deltas.push_back(MakeApp(kChromeAppId.c_str(), "Test Chrome App",
apps::mojom::AppType::kChromeApp));
@@ -136,16 +136,16 @@ TEST_F(DeskTemplateConversionTest, ParseBrowserTemplate) {
EXPECT_TRUE(rd != nullptr);
EXPECT_EQ(rd->app_id_to_launch_list().size(), 1UL);
- EXPECT_NE(rd->app_id_to_launch_list().find(extension_misc::kChromeAppId),
+ EXPECT_NE(rd->app_id_to_launch_list().find(app_constants::kChromeAppId),
rd->app_id_to_launch_list().end());
const app_restore::AppRestoreData* ard =
- rd->GetAppRestoreData(extension_misc::kChromeAppId, 0);
+ rd->GetAppRestoreData(app_constants::kChromeAppId, 0);
EXPECT_TRUE(ard != nullptr);
EXPECT_TRUE(ard->display_id.has_value());
EXPECT_EQ(ard->display_id.value(), 100L);
std::unique_ptr<app_restore::AppLaunchInfo> ali =
- ard->GetAppLaunchInfo(extension_misc::kChromeAppId, 0);
+ ard->GetAppLaunchInfo(app_constants::kChromeAppId, 0);
std::unique_ptr<app_restore::WindowInfo> wi = ard->GetWindowInfo();
EXPECT_TRUE(ali != nullptr);
EXPECT_TRUE(wi != nullptr);
@@ -318,4 +318,4 @@ TEST_F(DeskTemplateConversionTest, DeskTemplateFromJsonAppTest) {
EXPECT_EQ(parsed_json.value, desk_template_value);
}
-} // namespace desks_storage \ No newline at end of file
+} // namespace desks_storage
diff --git a/chromium/components/desks_storage/core/desk_template_util.cc b/chromium/components/desks_storage/core/desk_template_util.cc
new file mode 100644
index 00000000000..ec2a1052642
--- /dev/null
+++ b/chromium/components/desks_storage/core/desk_template_util.cc
@@ -0,0 +1,45 @@
+// Copyright 2022 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.
+
+#include "components/desks_storage/core/desk_template_util.h"
+
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "third_party/re2/src/re2/re2.h"
+
+namespace {
+
+// Duplicate value format.
+constexpr char kDuplicateNumberFormat[] = "(%d)";
+// Initial duplicate number value.
+constexpr char kInitialDuplicateNumberValue[] = " (1)";
+// Regex used in determining if duplicate name should be incremented.
+constexpr char kDuplicateNumberRegex[] = "\\(([0-9]+)\\)$";
+
+} // namespace
+
+namespace desks_storage {
+
+namespace desk_template_util {
+
+std::u16string AppendDuplicateNumberToDuplicateName(
+ const std::u16string& duplicate_name_u16) {
+ std::string duplicate_name = base::UTF16ToUTF8(duplicate_name_u16);
+ int found_duplicate_number;
+
+ if (RE2::PartialMatch(duplicate_name, kDuplicateNumberRegex,
+ &found_duplicate_number)) {
+ RE2::Replace(
+ &duplicate_name, kDuplicateNumberRegex,
+ base::StringPrintf(kDuplicateNumberFormat, found_duplicate_number + 1));
+ } else {
+ duplicate_name.append(kInitialDuplicateNumberValue);
+ }
+
+ return base::UTF8ToUTF16(duplicate_name);
+}
+
+} // namespace desk_template_util
+
+} // namespace desks_storage
diff --git a/chromium/components/desks_storage/core/desk_template_util.h b/chromium/components/desks_storage/core/desk_template_util.h
new file mode 100644
index 00000000000..77caedb2dee
--- /dev/null
+++ b/chromium/components/desks_storage/core/desk_template_util.h
@@ -0,0 +1,25 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_DESKS_STORAGE_CORE_DESK_TEMPLATE_UTIL_H_
+#define COMPONENTS_DESKS_STORAGE_CORE_DESK_TEMPLATE_UTIL_H_
+
+#include <string>
+
+namespace desks_storage {
+
+namespace desk_template_util {
+
+// Returns a copy of a duplicated name to be stored. This function works by
+// taking the name to be duplicated and adding a "(1)" to it. If the name
+// already has "(1)" then the number inside of the parenthesis will be
+// incremented.
+std::u16string AppendDuplicateNumberToDuplicateName(
+ const std::u16string& duplicate_name_u16);
+
+} // namespace desk_template_util
+
+} // namespace desks_storage
+
+#endif // COMPONENTS_DESKS_STORAGE_CORE_DESK_TEMPLATE_UTIL_H_
diff --git a/chromium/components/desks_storage/core/desk_template_util_unittests.cc b/chromium/components/desks_storage/core/desk_template_util_unittests.cc
new file mode 100644
index 00000000000..0cedf515423
--- /dev/null
+++ b/chromium/components/desks_storage/core/desk_template_util_unittests.cc
@@ -0,0 +1,44 @@
+// Copyright 2022 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.
+
+#include "components/desks_storage/core/desk_template_util.h"
+
+#include <string>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace desks_storage {
+
+using DeskTemplateUtilTest = testing::Test;
+
+TEST_F(DeskTemplateUtilTest, AddSequenceNumberForFirstDuplicate) {
+ EXPECT_EQ(u"test (1)",
+ desk_template_util::AppendDuplicateNumberToDuplicateName(u"test"));
+}
+
+TEST_F(DeskTemplateUtilTest, IncrementSequenceNumberOnSubsequentDuplicate) {
+ EXPECT_EQ(
+ u"test (2)",
+ desk_template_util::AppendDuplicateNumberToDuplicateName(u"test (1)"));
+ EXPECT_EQ(
+ u"test (10)",
+ desk_template_util::AppendDuplicateNumberToDuplicateName(u"test (9)"));
+ EXPECT_EQ(
+ u"test (11)",
+ desk_template_util::AppendDuplicateNumberToDuplicateName(u"test (10)"));
+ EXPECT_EQ(
+ u"test (101)",
+ desk_template_util::AppendDuplicateNumberToDuplicateName(u"test (100)"));
+}
+
+TEST_F(DeskTemplateUtilTest, OnlyIncrementTheLastSequenceNumber) {
+ EXPECT_EQ(u"test (1) (2)",
+ desk_template_util::AppendDuplicateNumberToDuplicateName(
+ u"test (1) (1)"));
+ EXPECT_EQ(u"test (1) (10)",
+ desk_template_util::AppendDuplicateNumberToDuplicateName(
+ u"test (1) (9)"));
+}
+
+} // namespace desks_storage
diff --git a/chromium/components/desks_storage/core/local_desk_data_manager.cc b/chromium/components/desks_storage/core/local_desk_data_manager.cc
index 474afd9b6bd..3a8c83ffc9b 100644
--- a/chromium/components/desks_storage/core/local_desk_data_manager.cc
+++ b/chromium/components/desks_storage/core/local_desk_data_manager.cc
@@ -7,6 +7,7 @@
#include "ash/public/cpp/desk_template.h"
#include "base/files/dir_reader_posix.h"
#include "base/files/file_util.h"
+#include "base/guid.h"
#include "base/json/json_string_value_serializer.h"
#include "base/json/values_util.h"
#include "base/logging.h"
@@ -18,9 +19,9 @@
#include "components/app_restore/restore_data.h"
#include "components/desks_storage/core/desk_model.h"
#include "components/desks_storage/core/desk_template_conversion.h"
+#include "components/desks_storage/core/desk_template_util.h"
#include "components/sync/protocol/workspace_desk_specifics.pb.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
-#include "third_party/re2/src/re2/re2.h"
#include "third_party/re2/src/re2/stringpiece.h"
#include "url/gurl.h"
@@ -28,6 +29,10 @@ namespace desks_storage {
namespace {
+// Setting this to true allows us to add more than the maximum number of
+// templates. Used only for testing.
+bool g_disable_max_template_limit = false;
+
// File extension for templates.
constexpr char kFileExtension[] = ".template";
// Key used in base::Value generation for the template name field.
@@ -38,14 +43,7 @@ constexpr char kDeskTemplateUuidKey[] = "uuid";
constexpr char kDeskTemplateTimeCreatedKey[] = "time_created";
// Key used in base::Value generation for the restore data field.
constexpr char kDeskTemplateRestoreDataKey[] = "restore_data";
-// Duplicate value format
-constexpr char kDuplicateNumberFormat[] = "(%d)";
-// Initial duplicate number value
-constexpr char kInitialDuplicateNumberValue[] = " (1)";
-// The maximum number of templates the local storage can hold.
constexpr std::size_t kMaxTemplateCount = 6u;
-// Regex used in determining if duplicate name should be incremented.
-constexpr char kDuplicateNumberRegex[] = "\\(([0-9])+\\)$";
// Converts ash::DeskTemplates to base::Value for serialization.
base::Value ConvertDeskTemplateToValue(ash::DeskTemplate* desk_template) {
@@ -167,27 +165,6 @@ base::FilePath GetFullyQualifiedPath(base::FilePath file_path,
return base::FilePath(file_path.Append(base::FilePath(filename)));
}
-// Returns a copy of a duplicated name to be stored. This function works by
-// taking the name to be duplicated and adding a "(1)" to it. If the name
-// already has "(1)" then the number inside of the parenthesis will be
-// incremented.
-std::u16string AppendDuplicateNumberToDuplicateName(
- const std::u16string& duplicate_name_u16) {
- std::string duplicate_name = base::UTF16ToUTF8(duplicate_name_u16);
- int found_duplicate_number;
-
- if (RE2::PartialMatch(duplicate_name, kDuplicateNumberRegex,
- &found_duplicate_number)) {
- RE2::Replace(
- &duplicate_name, kDuplicateNumberRegex,
- base::StringPrintf(kDuplicateNumberFormat, found_duplicate_number + 1));
- } else {
- duplicate_name.append(kInitialDuplicateNumberValue);
- }
-
- return base::UTF8ToUTF16(duplicate_name);
-}
-
} // namespace
LocalDeskDataManager::LocalDeskDataManager(const base::FilePath& path)
@@ -227,7 +204,7 @@ void LocalDeskDataManager::GetEntryByUUID(
base::Unretained(this), uuid, status.get(),
entry_ptr.get()),
base::BindOnce(&LocalDeskDataManager::OnGetEntryByUuid,
- weak_ptr_factory_.GetWeakPtr(), std::move(status),
+ weak_ptr_factory_.GetWeakPtr(), uuid, std::move(status),
std::move(entry_ptr), std::move(callback)));
}
@@ -278,11 +255,11 @@ void LocalDeskDataManager::DeleteAllEntries(
}
std::size_t LocalDeskDataManager::GetEntryCount() const {
- return templates_.size();
+ return templates_.size() + policy_entries_.size();
}
std::size_t LocalDeskDataManager::GetMaxEntryCount() const {
- return kMaxTemplateCount;
+ return kMaxTemplateCount + policy_entries_.size();
}
std::vector<base::GUID> LocalDeskDataManager::GetAllEntryUuids() const {
@@ -303,6 +280,11 @@ bool LocalDeskDataManager::IsSyncing() const {
return false;
}
+// static
+void LocalDeskDataManager::SetDisableMaxTemplateLimitForTesting(bool disabled) {
+ g_disable_max_template_limit = disabled;
+}
+
void LocalDeskDataManager::EnsureCacheIsLoaded() {
if (cache_status_ == CacheStatus::kOk) {
// Cache is already loaded.
@@ -394,11 +376,20 @@ void LocalDeskDataManager::GetEntryByUuidTask(
}
void LocalDeskDataManager::OnGetEntryByUuid(
+ const std::string& uuid_str,
std::unique_ptr<DeskModel::GetEntryByUuidStatus> status_ptr,
std::unique_ptr<ash::DeskTemplate*> entry_ptr_ptr,
DeskModel::GetEntryByUuidCallback callback) {
if (*entry_ptr_ptr == nullptr) {
- std::move(callback).Run(*status_ptr, std::unique_ptr<ash::DeskTemplate>());
+ std::unique_ptr<ash::DeskTemplate> policy_entry =
+ GetAdminDeskTemplateByUUID(uuid_str);
+
+ if (policy_entry) {
+ std::move(callback).Run(DeskModel::GetEntryByUuidStatus::kOk,
+ std::move(policy_entry));
+ } else {
+ std::move(callback).Run(*status_ptr, nullptr);
+ }
} else {
std::move(callback).Run(*status_ptr, (*entry_ptr_ptr)->Clone());
}
@@ -413,7 +404,7 @@ void LocalDeskDataManager::AddOrUpdateEntryTask(
return;
}
- if (templates_.size() >= kMaxTemplateCount) {
+ if (!g_disable_max_template_limit && templates_.size() >= kMaxTemplateCount) {
*status_ptr = DeskModel::AddOrUpdateEntryStatus::kHitMaximumLimit;
return;
}
@@ -430,7 +421,8 @@ void LocalDeskDataManager::AddOrUpdateEntryTask(
// the current template will be named 5.
while (HasTemplateWithName(new_entry->template_name())) {
new_entry->set_template_name(
- AppendDuplicateNumberToDuplicateName(new_entry->template_name()));
+ desk_template_util::AppendDuplicateNumberToDuplicateName(
+ new_entry->template_name()));
}
templates_[uuid] = std::move(new_entry);
diff --git a/chromium/components/desks_storage/core/local_desk_data_manager.h b/chromium/components/desks_storage/core/local_desk_data_manager.h
index d7ac601614c..041957dbcf5 100644
--- a/chromium/components/desks_storage/core/local_desk_data_manager.h
+++ b/chromium/components/desks_storage/core/local_desk_data_manager.h
@@ -65,6 +65,8 @@ class LocalDeskDataManager : public DeskModel {
bool IsReady() const override;
bool IsSyncing() const override;
+ static void SetDisableMaxTemplateLimitForTesting(bool disabled);
+
private:
friend class ash::OverviewTestBase;
@@ -89,6 +91,7 @@ class LocalDeskDataManager : public DeskModel {
// Wrapper method to call GetEntryByUuidCallback.
void OnGetEntryByUuid(
+ const std::string& uuid_str,
std::unique_ptr<DeskModel::GetEntryByUuidStatus> status_ptr,
std::unique_ptr<ash::DeskTemplate*> entry_ptr_ptr,
DeskModel::GetEntryByUuidCallback callback);
diff --git a/chromium/components/desks_storage/core/local_desks_data_manager_unittests.cc b/chromium/components/desks_storage/core/local_desks_data_manager_unittests.cc
index ba11cf1f43b..616390c8c86 100644
--- a/chromium/components/desks_storage/core/local_desks_data_manager_unittests.cc
+++ b/chromium/components/desks_storage/core/local_desks_data_manager_unittests.cc
@@ -53,7 +53,7 @@ const std::string kTestFileName1 =
const std::string kPolicyWithOneTemplate =
"[{\"version\":1,\"uuid\":\"" + kTestUuid9 +
"\",\"name\":\""
- "Example Template"
+ "Admin Template 1"
"\",\"created_time_usec\":\"1633535632\",\"updated_time_usec\": "
"\"1633535632\",\"desk\":{\"apps\":[{\"window_"
"bound\":{\"left\":0,\"top\":1,\"height\":121,\"width\":120},\"window_"
@@ -209,6 +209,28 @@ class LocalDeskDataManagerTest : public testing::Test {
testing::Test::SetUp();
}
+ void AddTwoTemplates() {
+ base::RunLoop loop1;
+ data_manager_->AddOrUpdateEntry(
+ std::move(sample_desk_template_one_),
+ base::BindLambdaForTesting(
+ [&](DeskModel::AddOrUpdateEntryStatus status) {
+ EXPECT_EQ(DeskModel::AddOrUpdateEntryStatus::kOk, status);
+ loop1.Quit();
+ }));
+ loop1.Run();
+
+ base::RunLoop loop2;
+ data_manager_->AddOrUpdateEntry(
+ std::move(sample_desk_template_two_),
+ base::BindLambdaForTesting(
+ [&](DeskModel::AddOrUpdateEntryStatus status) {
+ EXPECT_EQ(DeskModel::AddOrUpdateEntryStatus::kOk, status);
+ loop2.Quit();
+ }));
+ loop2.Run();
+ }
+
base::ScopedTempDir temp_dir_;
std::unique_ptr<ash::DeskTemplate> sample_desk_template_one_;
std::unique_ptr<ash::DeskTemplate> sample_desk_template_one_duplicate_;
@@ -409,6 +431,27 @@ TEST_F(LocalDeskDataManagerTest, CanGetEntryByUuid) {
task_environment_.RunUntilIdle();
}
+TEST_F(LocalDeskDataManagerTest, GetEntryByUuidShouldReturnAdminTemplate) {
+ data_manager_->AddOrUpdateEntry(std::move(sample_desk_template_one_),
+ base::BindOnce(&VerifyEntryAddedCorrectly));
+
+ // Set admin template with UUID: kTestUuid9.
+ data_manager_->SetPolicyDeskTemplates(kPolicyWithOneTemplate);
+
+ data_manager_->GetEntryByUUID(
+ kTestUuid9,
+ base::BindLambdaForTesting([&](DeskModel::GetEntryByUuidStatus status,
+ std::unique_ptr<ash::DeskTemplate> entry) {
+ EXPECT_EQ(DeskModel::GetEntryByUuidStatus::kOk, status);
+ EXPECT_EQ(base::GUID::ParseCaseInsensitive(kTestUuid9), entry->uuid());
+ EXPECT_EQ(ash::DeskTemplateSource::kPolicy, entry->source());
+ EXPECT_EQ(base::UTF8ToUTF16(std::string("Admin Template 1")),
+ entry->template_name());
+ }));
+
+ task_environment_.RunUntilIdle();
+}
+
TEST_F(LocalDeskDataManagerTest,
GetEntryByUuidReturnsNotFoundIfEntryDoesNotExist) {
base::RunLoop loop;
@@ -526,4 +569,31 @@ TEST_F(LocalDeskDataManagerTest, CanDeleteAllEntries) {
loop.Run();
}
+TEST_F(LocalDeskDataManagerTest,
+ GetEntryCountShouldIncludeBothUserAndAdminTemplates) {
+ // Add two user templates.
+ AddTwoTemplates();
+
+ // Set one admin template.
+ data_manager_->SetPolicyDeskTemplates(kPolicyWithOneTemplate);
+
+ // There should be 3 templates: 2 user templates + 1 admin template.
+ EXPECT_EQ(3ul, data_manager_->GetEntryCount());
+}
+
+TEST_F(LocalDeskDataManagerTest,
+ GetMaxEntryCountShouldIncreaseWithAdminTemplates) {
+ // Add two user templates.
+ AddTwoTemplates();
+
+ std::size_t max_entry_count = data_manager_->GetMaxEntryCount();
+
+ // Set one admin template.
+ data_manager_->SetPolicyDeskTemplates(kPolicyWithOneTemplate);
+
+ // The max entry count should increase by 1 since we have set an admin
+ // template.
+ EXPECT_EQ(max_entry_count + 1ul, data_manager_->GetMaxEntryCount());
+}
+
} // namespace desks_storage
diff --git a/chromium/components/device_event_log/device_event_log.h b/chromium/components/device_event_log/device_event_log.h
index 67aa2c2cc2f..fd48f78db69 100644
--- a/chromium/components/device_event_log/device_event_log.h
+++ b/chromium/components/device_event_log/device_event_log.h
@@ -74,7 +74,7 @@
DEVICE_LOG(::device_event_log::LOG_TYPE_CAMERA, \
::device_event_log::LOG_LEVEL_##level)
-#if defined(OS_ANDROID) && defined(OFFICIAL_BUILD)
+#if BUILDFLAG(IS_ANDROID) && defined(OFFICIAL_BUILD)
// FIDO_LOG is discarded for release Android builds in order to reduce binary
// size.
#define FIDO_LOG(level) EAT_CHECK_STREAM_PARAMS()
diff --git a/chromium/components/device_event_log/device_event_log_impl.cc b/chromium/components/device_event_log/device_event_log_impl.cc
index f2ad3af561c..6e276060c17 100644
--- a/chromium/components/device_event_log/device_event_log_impl.cc
+++ b/chromium/components/device_event_log/device_event_log_impl.cc
@@ -116,7 +116,7 @@ std::string TimeWithMillieconds(const base::Time& time) {
exploded.millisecond);
}
-#if defined(OS_POSIX)
+#if BUILDFLAG(IS_POSIX)
std::string UnixTime(const base::Time& time) {
base::Time::Exploded utc_exploded, exploded;
time.UTCExplode(&utc_exploded);
@@ -151,7 +151,7 @@ std::string LogEntryToString(const DeviceEventLogImpl::LogEntry& log_entry,
std::string line;
if (show_time == ShowTime::kTimeWithMs)
line += "[" + TimeWithMillieconds(log_entry.time) + "] ";
-#if defined(OS_POSIX)
+#if BUILDFLAG(IS_POSIX)
if (show_time == ShowTime::kUnix)
line += UnixTime(log_entry.time) + " ";
#endif
@@ -160,7 +160,7 @@ std::string LogEntryToString(const DeviceEventLogImpl::LogEntry& log_entry,
if (show_level) {
const char* kLevelDesc[] = {"ERROR", "USER", "EVENT", "DEBUG"};
line += std::string(kLevelDesc[log_entry.log_level]);
-#if defined(OS_POSIX)
+#if BUILDFLAG(IS_POSIX)
if (show_time == ShowTime::kUnix) {
// Format the level consistently with /var/log/messages.
line += base::StringPrintf(" chrome[%d]", base::GetCurrentProcId());
@@ -252,7 +252,7 @@ void GetFormat(const std::string& format_string,
if (tok == "time") {
*show_time = ShowTime::kTimeWithMs;
} else if (tok == "unixtime") {
-#if defined(OS_POSIX)
+#if BUILDFLAG(IS_POSIX)
*show_time = ShowTime::kUnix;
#else
*show_time = ShowTime::kTimeWithMs;
diff --git a/chromium/components/device_event_log/device_event_log_impl_unittest.cc b/chromium/components/device_event_log/device_event_log_impl_unittest.cc
index 529f217270b..cbc700eb811 100644
--- a/chromium/components/device_event_log/device_event_log_impl_unittest.cc
+++ b/chromium/components/device_event_log/device_event_log_impl_unittest.cc
@@ -223,7 +223,7 @@ TEST_F(DeviceEventLogTest, TestTimeFormat) {
EXPECT_EQ(base::StringPrintf("[%s] event0\n", extected_time_str.c_str()),
GetLogString(OLDEST_FIRST, "time", kDefaultLevel, 1));
-#if defined(OS_POSIX)
+#if BUILDFLAG(IS_POSIX)
char sign = hour_delta > 0 ? '+' : '-';
std::string expected_time =
base::StringPrintf("2020-01-01T%02d:34:56.000000%c%02d:00",
diff --git a/chromium/components/digital_asset_links/digital_asset_links_handler.cc b/chromium/components/digital_asset_links/digital_asset_links_handler.cc
index c15f4c9e92f..e18ada8b60f 100644
--- a/chromium/components/digital_asset_links/digital_asset_links_handler.cc
+++ b/chromium/components/digital_asset_links/digital_asset_links_handler.cc
@@ -66,7 +66,7 @@ bool StatementHasMatchingRelationship(const base::Value& statement,
if (!relations)
return false;
- for (const auto& relation : relations->GetList()) {
+ for (const auto& relation : relations->GetListDeprecated()) {
if (relation.is_string() && relation.GetString() == target_relation)
return true;
}
@@ -93,7 +93,7 @@ bool StatementHasMatchingFingerprint(const base::Value& statement,
if (!fingerprints)
return false;
- for (const auto& fingerprint : fingerprints->GetList()) {
+ for (const auto& fingerprint : fingerprints->GetListDeprecated()) {
if (fingerprint.is_string() &&
fingerprint.GetString() == target_fingerprint) {
return true;
@@ -194,7 +194,7 @@ void DigitalAssetLinksHandler::OnJSONParseResult(
// We only output individual statement failures if none match.
std::vector<std::string> failures;
- for (const auto& statement : statement_list.GetList()) {
+ for (const auto& statement : statement_list.GetListDeprecated()) {
if (!statement.is_dict()) {
failures.push_back("Statement is not a dictionary.");
continue;
diff --git a/chromium/components/discardable_memory/client/client_discardable_shared_memory_manager.cc b/chromium/components/discardable_memory/client/client_discardable_shared_memory_manager.cc
index 46717897c8f..cb840906ec0 100644
--- a/chromium/components/discardable_memory/client/client_discardable_shared_memory_manager.cc
+++ b/chromium/components/discardable_memory/client/client_discardable_shared_memory_manager.cc
@@ -38,23 +38,23 @@ size_t GetDefaultAllocationSize() {
// memory usage overhead. 4MB is measured as the ideal size according to the
// usage statistics. For low-end devices, we care about lowering the memory
// usage and 1MB is good for the most basic cases.
- const size_t kDefaultAllocationSize = 4 * kOneMegabyteInBytes;
- const size_t kDefaultLowEndDeviceAllocationSize = kOneMegabyteInBytes;
+ [[maybe_unused]] const size_t kDefaultAllocationSize =
+ 4 * kOneMegabyteInBytes;
+ [[maybe_unused]] const size_t kDefaultLowEndDeviceAllocationSize =
+ kOneMegabyteInBytes;
-#if defined(OS_WIN) && defined(ARCH_CPU_32_BITS)
+#if BUILDFLAG(IS_WIN) && defined(ARCH_CPU_32_BITS)
// On Windows 32 bit, use a smaller chunk, as address space fragmentation may
// make a 4MiB allocation impossible to fulfill in the browser process.
// See crbug.com/983348 for details.
- ALLOW_UNUSED_LOCAL(kDefaultAllocationSize);
return kDefaultLowEndDeviceAllocationSize;
-#elif defined(OS_FUCHSIA)
+#elif BUILDFLAG(IS_FUCHSIA)
// Low end Fuchsia devices may be very constrained, so use smaller allocations
// to save memory. See https://fxbug.dev/55760.
return base::SysInfo::IsLowEndDevice() ? kDefaultLowEndDeviceAllocationSize
: kDefaultAllocationSize;
#else
- ALLOW_UNUSED_LOCAL(kDefaultLowEndDeviceAllocationSize);
return kDefaultAllocationSize;
#endif
}
diff --git a/chromium/components/discardable_memory/service/discardable_shared_memory_manager.cc b/chromium/components/discardable_memory/service/discardable_shared_memory_manager.cc
index 0fbadeb3824..bf06b8c1757 100644
--- a/chromium/components/discardable_memory/service/discardable_shared_memory_manager.cc
+++ b/chromium/components/discardable_memory/service/discardable_shared_memory_manager.cc
@@ -32,7 +32,7 @@
#include "components/discardable_memory/common/discardable_shared_memory_heap.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/metrics/histogram_macros.h"
@@ -167,7 +167,7 @@ int64_t GetDefaultMemoryLimit() {
// not all Chromecast devices.
int64_t max_default_memory_limit = 64 * kMegabyte;
#else
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Limits the number of FDs used to 32, assuming a 4MB allocation size.
int64_t max_default_memory_limit = 128 * kMegabyte;
#else
@@ -179,7 +179,7 @@ int64_t GetDefaultMemoryLimit() {
max_default_memory_limit /= 8;
#endif
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
base::FilePath shmem_dir;
if (base::GetShmemTempDir(false, &shmem_dir)) {
int64_t shmem_dir_amount_of_free_space =
diff --git a/chromium/components/dom_distiller/content/browser/distillability_driver.cc b/chromium/components/dom_distiller/content/browser/distillability_driver.cc
index 824e39e0779..c8d11c4bab0 100644
--- a/chromium/components/dom_distiller/content/browser/distillability_driver.cc
+++ b/chromium/components/dom_distiller/content/browser/distillability_driver.cc
@@ -65,7 +65,7 @@ void DistillabilityDriver::SetIsSecureCallback(
void DistillabilityDriver::OnDistillability(
const DistillabilityResult& result) {
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
if (result.is_distillable) {
if (!is_secure_check_ || !is_secure_check_.Run(&GetWebContents())) {
DistillabilityResult not_distillable;
@@ -78,7 +78,7 @@ void DistillabilityDriver::OnDistillability(
return;
}
}
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
latest_result_ = result;
for (auto& observer : observers_)
observer.OnResult(result);
diff --git a/chromium/components/dom_distiller/content/browser/distillable_page_utils_browsertest.cc b/chromium/components/dom_distiller/content/browser/distillable_page_utils_browsertest.cc
index 98738393cea..f685f2a9535 100644
--- a/chromium/components/dom_distiller/content/browser/distillable_page_utils_browsertest.cc
+++ b/chromium/components/dom_distiller/content/browser/distillable_page_utils_browsertest.cc
@@ -58,14 +58,14 @@ class DomDistillerDistillablePageUtilsTest : public content::ContentBrowserTest,
void AddComponentsResources() {
base::FilePath pak_file;
base::FilePath pak_dir;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
CHECK(base::PathService::Get(base::DIR_ANDROID_APP_DATA, &pak_dir));
pak_dir = pak_dir.Append(FILE_PATH_LITERAL("paks"));
-#elif defined(OS_MAC)
+#elif BUILDFLAG(IS_MAC)
base::PathService::Get(base::DIR_MODULE, &pak_dir);
#else
base::PathService::Get(base::DIR_ASSETS, &pak_dir);
-#endif // OS_ANDROID
+#endif // BUILDFLAG(IS_ANDROID)
pak_file =
pak_dir.Append(FILE_PATH_LITERAL("components_tests_resources.pak"));
ui::ResourceBundle::GetSharedInstance().AddDataPackFromPath(
diff --git a/chromium/components/dom_distiller/content/browser/distiller_page_web_contents_browsertest.cc b/chromium/components/dom_distiller/content/browser/distiller_page_web_contents_browsertest.cc
index 71e440350ad..55cefa188ce 100644
--- a/chromium/components/dom_distiller/content/browser/distiller_page_web_contents_browsertest.cc
+++ b/chromium/components/dom_distiller/content/browser/distiller_page_web_contents_browsertest.cc
@@ -153,7 +153,7 @@ class TestDistillerPageWebContents : public DistillerPageWebContents {
bool new_web_contents_created_;
};
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#define MAYBE_BasicDistillationWorks DISABLED_BasicDistillationWorks
#else
#define MAYBE_BasicDistillationWorks BasicDistillationWorks
@@ -179,7 +179,7 @@ IN_PROC_BROWSER_TEST_F(DistillerPageWebContentsTest,
EXPECT_EQ("", distiller_result_->pagination_info().prev_page());
}
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#define MAYBE_HandlesRelativeLinks DISABLED_HandlesRelativeLinks
#else
#define MAYBE_HandlesRelativeLinks HandlesRelativeLinks
@@ -203,7 +203,7 @@ IN_PROC_BROWSER_TEST_F(DistillerPageWebContentsTest,
HasSubstr("href=\"http://www.google.com/absolutelink.html\""));
}
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#define MAYBE_HandlesRelativeImages DISABLED_HandlesRelativeImages
#else
#define MAYBE_HandlesRelativeImages HandlesRelativeImages
@@ -227,7 +227,7 @@ IN_PROC_BROWSER_TEST_F(DistillerPageWebContentsTest,
HasSubstr("src=\"http://www.google.com/absoluteimage.png\""));
}
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#define MAYBE_HandlesRelativeVideos DISABLED_HandlesRelativeVideos
#else
#define MAYBE_HandlesRelativeVideos HandlesRelativeVideos
@@ -256,7 +256,7 @@ IN_PROC_BROWSER_TEST_F(DistillerPageWebContentsTest,
HasSubstr("src=\"http://www.google.com/absolute_track_fr.vtt\""));
}
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#define MAYBE_VisibilityDetection DISABLED_VisibilityDetection
#else
#define MAYBE_VisibilityDetection VisibilityDetection
@@ -289,7 +289,7 @@ IN_PROC_BROWSER_TEST_F(DistillerPageWebContentsTest,
}
}
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#define MAYBE_UsingCurrentWebContentsWrongUrl \
DISABLED_UsingCurrentWebContentsWrongUrl
#else
@@ -304,7 +304,7 @@ IN_PROC_BROWSER_TEST_F(DistillerPageWebContentsTest,
wait_for_document_loaded);
}
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#define MAYBE_UsingCurrentWebContentsNotFinishedLoadingYet \
DISABLED_UsingCurrentWebContentsNotFinishedLoadingYet
#else
@@ -320,7 +320,7 @@ IN_PROC_BROWSER_TEST_F(DistillerPageWebContentsTest,
wait_for_document_loaded);
}
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#define MAYBE_UsingCurrentWebContentsReadyForDistillation \
DISABLED_UsingCurrentWebContentsReadyForDistillation
#else
@@ -368,7 +368,7 @@ void DistillerPageWebContentsTest::RunUseCurrentWebContentsTest(
EXPECT_EQ("Test Page Title", distiller_result_->title());
}
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#define MAYBE_PageDestroyedBeforeFinishDistillation \
DISABLED_PageDestroyedBeforeFinishDistillation
#else
@@ -409,7 +409,7 @@ IN_PROC_BROWSER_TEST_F(DistillerPageWebContentsTest,
run_loop.Run();
}
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#define MAYBE_MarkupInfo DISABLED_MarkupInfo
#else
#define MAYBE_MarkupInfo MarkupInfo
diff --git a/chromium/components/dom_distiller/content/browser/dom_distiller_viewer_source.cc b/chromium/components/dom_distiller/content/browser/dom_distiller_viewer_source.cc
index a0eef087081..adb03f9078f 100644
--- a/chromium/components/dom_distiller/content/browser/dom_distiller_viewer_source.cc
+++ b/chromium/components/dom_distiller/content/browser/dom_distiller_viewer_source.cc
@@ -212,13 +212,13 @@ void DomDistillerViewerSource::StartDataRequest(
content::WebContents* web_contents = wc_getter.Run();
if (!web_contents)
return;
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
// Don't allow loading of mixed content on Reader Mode pages.
blink::web_pref::WebPreferences prefs =
web_contents->GetOrCreateWebPreferences();
prefs.strict_mixed_content_checking = true;
web_contents->SetWebPreferences(prefs);
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
if (kViewerCssPath == path) {
std::string css = viewer::GetCss();
std::move(callback).Run(base::RefCountedString::TakeString(&css));
diff --git a/chromium/components/dom_distiller/core/distiller.cc b/chromium/components/dom_distiller/core/distiller.cc
index b1b4d04d4fe..2070115cf78 100644
--- a/chromium/components/dom_distiller/core/distiller.cc
+++ b/chromium/components/dom_distiller/core/distiller.cc
@@ -67,7 +67,7 @@ DistillerImpl::~DistillerImpl() {
bool DistillerImpl::DoesFetchImages() {
// Only iOS makes use of the fetched image data.
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
return true;
#else
return false;
diff --git a/chromium/components/dom_distiller/core/dom_distiller_service.cc b/chromium/components/dom_distiller/core/dom_distiller_service.cc
index dba0f171a03..6b49b23a1ee 100644
--- a/chromium/components/dom_distiller/core/dom_distiller_service.cc
+++ b/chromium/components/dom_distiller/core/dom_distiller_service.cc
@@ -137,4 +137,8 @@ base::WeakPtr<DomDistillerService> DomDistillerService::GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
+bool DomDistillerService::HasTaskTrackerForTesting(const GURL& url) const {
+ return GetTaskTrackerForUrl(url);
+}
+
} // namespace dom_distiller
diff --git a/chromium/components/dom_distiller/core/dom_distiller_service.h b/chromium/components/dom_distiller/core/dom_distiller_service.h
index e0efe9e464e..cdb5c8ecc28 100644
--- a/chromium/components/dom_distiller/core/dom_distiller_service.h
+++ b/chromium/components/dom_distiller/core/dom_distiller_service.h
@@ -87,6 +87,8 @@ class DomDistillerService : public DomDistillerServiceInterface {
DistillerUIHandle* GetDistillerUIHandle() override;
base::WeakPtr<DomDistillerService> GetWeakPtr();
+ bool HasTaskTrackerForTesting(const GURL& url) const;
+
private:
void CancelTask(TaskTracker* task);
diff --git a/chromium/components/dom_distiller/core/experiments.cc b/chromium/components/dom_distiller/core/experiments.cc
index 98cbc86b814..657332b0db7 100644
--- a/chromium/components/dom_distiller/core/experiments.cc
+++ b/chromium/components/dom_distiller/core/experiments.cc
@@ -6,6 +6,7 @@
#include "base/command_line.h"
#include "base/metrics/field_trial.h"
+#include "base/notreached.h"
#include "base/strings/string_util.h"
#include "components/dom_distiller/core/dom_distiller_switches.h"
diff --git a/chromium/components/dom_distiller/core/page_features_unittest.cc b/chromium/components/dom_distiller/core/page_features_unittest.cc
index cfd5718f055..a4378fe70de 100644
--- a/chromium/components/dom_distiller/core/page_features_unittest.cc
+++ b/chromium/components/dom_distiller/core/page_features_unittest.cc
@@ -42,13 +42,14 @@ absl::optional<SiteDerivedFeatures> ParseSiteDerivedFeatures(
// For every feature name at index 2*N, their value is at 2*N+1. In particular
// the size must be an even number.
- size_t size = derived_features_json->GetList().size();
+ size_t size = derived_features_json->GetListDeprecated().size();
if (size % 2 != 0)
return absl::nullopt;
std::vector<double> derived_features;
for (size_t i = 1; i < size; i += 2) {
- const base::Value& feature_value = derived_features_json->GetList()[i];
+ const base::Value& feature_value =
+ derived_features_json->GetListDeprecated()[i];
// If the value is a bool, convert it to 1.0 or 0.0.
double numerical_feature_value;
if (feature_value.is_double() || feature_value.is_int())
@@ -85,7 +86,7 @@ std::vector<base::Value> ReadJsonListToValues(const std::string& file_name) {
if (!parsed_content->is_list())
return {};
- return std::move(*parsed_content).TakeList();
+ return std::move(*parsed_content).TakeListDeprecated();
}
// This test uses input data of core features and the output of the training
diff --git a/chromium/components/dom_distiller/core/viewer.cc b/chromium/components/dom_distiller/core/viewer.cc
index c6ccd76af19..dda3f4ba8ad 100644
--- a/chromium/components/dom_distiller/core/viewer.cc
+++ b/chromium/components/dom_distiller/core/viewer.cc
@@ -56,7 +56,7 @@ const char kSansSerifCssClass[] = "sans-serif";
const char kMonospaceCssClass[] = "monospace";
std::string GetPlatformSpecificCss() {
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
return "";
#else // Desktop
return ui::ResourceBundle::GetSharedInstance().LoadDataResourceString(
@@ -160,7 +160,7 @@ std::string ReplaceHtmlTemplateValues(const mojom::Theme theme,
std::ostringstream csp;
std::ostringstream css;
std::ostringstream svg;
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
// On iOS the content is inlined as there is no API to detect those requests
// and return the local data once a page is loaded.
css << "<style>" << viewer::GetCss() << "</style>";
@@ -185,7 +185,7 @@ std::string ReplaceHtmlTemplateValues(const mojom::Theme theme,
#else
css << "<link rel=\"stylesheet\" href=\"/" << kViewerCssPath << "\">";
svg << "<img src=\"/" << kViewerLoadingImagePath << "\">";
-#endif // defined(OS_IOS)
+#endif // BUILDFLAG(IS_IOS)
substitutions.push_back(csp.str()); // $1
substitutions.push_back(css.str()); // $2
@@ -230,7 +230,7 @@ const std::string GetErrorPageJs() {
}
const std::string GetSetTitleJs(std::string title) {
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
base::Value suffixValue("");
#else // Desktop
std::string suffix(
diff --git a/chromium/components/dom_distiller/ios/distiller_page_ios.mm b/chromium/components/dom_distiller/ios/distiller_page_ios.mm
index e2ecf270b70..cb6701b9da7 100644
--- a/chromium/components/dom_distiller/ios/distiller_page_ios.mm
+++ b/chromium/components/dom_distiller/ios/distiller_page_ios.mm
@@ -86,7 +86,7 @@ base::Value ConvertedResultFromScriptResult(const base::Value* value,
} else if (value->is_list()) {
std::vector<base::Value> list;
- for (const base::Value& list_item : value->GetList()) {
+ for (const base::Value& list_item : value->GetListDeprecated()) {
base::Value converted_item =
ConvertedResultFromScriptResult(&list_item, max_depth - 1);
if (converted_item.type() == base::Value::Type::NONE) {
diff --git a/chromium/components/domain_reliability/context_unittest.cc b/chromium/components/domain_reliability/context_unittest.cc
index b63597c1c65..49f4028b640 100644
--- a/chromium/components/domain_reliability/context_unittest.cc
+++ b/chromium/components/domain_reliability/context_unittest.cc
@@ -109,9 +109,9 @@ bool GetEntryFromReport(const Value* report,
if (!report || !report->is_dict())
return false;
const Value* entries = report->FindListKey("entries");
- if (!entries || index >= entries->GetList().size())
+ if (!entries || index >= entries->GetListDeprecated().size())
return false;
- const Value& entry = entries->GetList()[index];
+ const Value& entry = entries->GetListDeprecated()[index];
if (!entry.is_dict())
return false;
*entry_out = &entry;
diff --git a/chromium/components/domain_reliability/monitor_unittest.cc b/chromium/components/domain_reliability/monitor_unittest.cc
index 7a27feea05f..6e82a7efc33 100644
--- a/chromium/components/domain_reliability/monitor_unittest.cc
+++ b/chromium/components/domain_reliability/monitor_unittest.cc
@@ -38,6 +38,8 @@
#include "net/test/gtest_util.h"
#include "net/third_party/quiche/src/quic/core/quic_error_codes.h"
#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
+#include "net/url_request/url_request_context.h"
+#include "net/url_request/url_request_context_builder.h"
#include "net/url_request/url_request_test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -68,8 +70,10 @@ class DomainReliabilityMonitorTest : public testing::Test {
typedef DomainReliabilityMonitor::RequestInfo RequestInfo;
DomainReliabilityMonitorTest()
- : time_(new MockTime()),
- monitor_(&url_request_context_,
+ : url_request_context_(
+ net::CreateTestURLRequestContextBuilder()->Build()),
+ time_(new MockTime()),
+ monitor_(url_request_context_.get(),
"test-reporter",
DomainReliabilityContext::UploadAllowedCallback(),
std::unique_ptr<MockableTime>(time_)) {
@@ -121,7 +125,7 @@ class DomainReliabilityMonitorTest : public testing::Test {
base::test::SingleThreadTaskEnvironment task_environment_{
base::test::TaskEnvironment::MainThreadType::IO};
- net::TestURLRequestContext url_request_context_;
+ std::unique_ptr<net::URLRequestContext> url_request_context_;
raw_ptr<MockTime> time_;
DomainReliabilityMonitor monitor_;
DomainReliabilityMonitor::RequestInfo request_;
@@ -594,9 +598,9 @@ TEST_F(DomainReliabilityMonitorTest, RealRequest) {
net::TestDelegate test_delegate;
std::unique_ptr<net::URLRequest> url_request =
- url_request_context_.CreateRequest(test_server.GetURL("/close-socket"),
- net::DEFAULT_PRIORITY, &test_delegate,
- TRAFFIC_ANNOTATION_FOR_TESTS);
+ url_request_context_->CreateRequest(test_server.GetURL("/close-socket"),
+ net::DEFAULT_PRIORITY, &test_delegate,
+ TRAFFIC_ANNOTATION_FOR_TESTS);
url_request->set_isolation_info(kIsolationInfo);
url_request->Start();
diff --git a/chromium/components/domain_reliability/quic_error_mapping.cc b/chromium/components/domain_reliability/quic_error_mapping.cc
index b17b3ebe89a..87aa93bf948 100644
--- a/chromium/components/domain_reliability/quic_error_mapping.cc
+++ b/chromium/components/domain_reliability/quic_error_mapping.cc
@@ -463,6 +463,8 @@ const struct QuicErrorMapping {
"quic::quic_tls_keying_material_exports_mismatch"},
{quic::QUIC_TLS_KEYING_MATERIAL_EXPORT_NOT_AVAILABLE,
"quic::quic_tls_keying_material_export_not_available"},
+ {quic::QUIC_UNEXPECTED_DATA_BEFORE_ENCRYPTION_ESTABLISHED,
+ "quic::quic_unexpected_data_before_encryption_established"},
// No error. Used as bound while iterating.
{quic::QUIC_LAST_ERROR, "quic.last_error"}};
diff --git a/chromium/components/domain_reliability/uploader.cc b/chromium/components/domain_reliability/uploader.cc
index 43673bb5996..b42b5be5b1a 100644
--- a/chromium/components/domain_reliability/uploader.cc
+++ b/chromium/components/domain_reliability/uploader.cc
@@ -133,9 +133,7 @@ class DomainReliabilityUploaderImpl : public DomainReliabilityUploader,
UploadDepthData::kUserDataKey,
std::make_unique<UploadDepthData>(max_upload_depth + 1));
- UploadMap::iterator it;
- bool inserted;
- std::tie(it, inserted) = uploads_.insert(
+ auto [it, inserted] = uploads_.insert(
std::make_pair(std::move(request), std::move(callback)));
DCHECK(inserted);
it->first->Start();
diff --git a/chromium/components/domain_reliability/uploader_unittest.cc b/chromium/components/domain_reliability/uploader_unittest.cc
index f4c0875a3fb..f49011a8416 100644
--- a/chromium/components/domain_reliability/uploader_unittest.cc
+++ b/chromium/components/domain_reliability/uploader_unittest.cc
@@ -22,8 +22,11 @@
#include "net/base/network_isolation_key.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_response_info.h"
+#include "net/http/http_util.h"
#include "net/log/net_log_with_source.h"
#include "net/url_request/url_request.h"
+#include "net/url_request/url_request_context.h"
+#include "net/url_request/url_request_context_builder.h"
#include "net/url_request/url_request_filter.h"
#include "net/url_request/url_request_interceptor.h"
#include "net/url_request/url_request_job.h"
@@ -181,8 +184,11 @@ class TestUploadCallback {
class DomainReliabilityUploaderTest : public testing::Test {
protected:
DomainReliabilityUploaderTest()
- : uploader_(
- DomainReliabilityUploader::Create(&time_, &url_request_context_)) {
+ : url_request_context_(
+ net::CreateTestURLRequestContextBuilder()->Build()),
+ uploader_(
+ DomainReliabilityUploader::Create(&time_,
+ url_request_context_.get())) {
auto interceptor =
std::make_unique<UploadInterceptor>(expected_isolation_info_);
interceptor_ = interceptor.get();
@@ -197,8 +203,8 @@ class DomainReliabilityUploaderTest : public testing::Test {
DomainReliabilityUploader* uploader() const { return uploader_.get(); }
UploadInterceptor* interceptor() const { return interceptor_; }
- net::TestURLRequestContext* url_request_context() {
- return &url_request_context_;
+ net::URLRequestContext* url_request_context() {
+ return url_request_context_.get();
}
const net::NetworkIsolationKey& network_isolation_key() const {
@@ -212,7 +218,7 @@ class DomainReliabilityUploaderTest : public testing::Test {
const net::IsolationInfo expected_isolation_info_ =
net::IsolationInfo::CreateTransient();
- net::TestURLRequestContext url_request_context_;
+ std::unique_ptr<net::URLRequestContext> url_request_context_;
raw_ptr<UploadInterceptor> interceptor_;
MockTime time_;
std::unique_ptr<DomainReliabilityUploader> uploader_;
diff --git a/chromium/components/domain_reliability/util.cc b/chromium/components/domain_reliability/util.cc
index 2748c453eac..71e05ef7bf5 100644
--- a/chromium/components/domain_reliability/util.cc
+++ b/chromium/components/domain_reliability/util.cc
@@ -101,7 +101,7 @@ bool GetDomainReliabilityBeaconStatus(
return false;
}
-// TODO(juliatuttle): Consider using NPN/ALPN instead, if there's a good way to
+// TODO(juliatuttle): Consider using ALPN instead, if there's a good way to
// differentiate HTTP and HTTPS.
std::string GetDomainReliabilityProtocol(
net::HttpResponseInfo::ConnectionInfo connection_info,
diff --git a/chromium/components/download/content/factory/download_service_factory_helper.cc b/chromium/components/download/content/factory/download_service_factory_helper.cc
index c7edd2d14eb..aa777e06b01 100644
--- a/chromium/components/download/content/factory/download_service_factory_helper.cc
+++ b/chromium/components/download/content/factory/download_service_factory_helper.cc
@@ -28,10 +28,10 @@
#include "components/leveldb_proto/public/proto_database_provider.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "components/download/internal/background_service/android/battery_status_listener_android.h"
#include "components/download/network/android/network_status_listener_android.h"
-#elif defined(OS_APPLE)
+#elif BUILDFLAG(IS_APPLE)
#include "components/download/internal/background_service/scheduler/battery_status_listener_mac.h"
#include "components/download/network/network_status_listener_impl.h"
#else
@@ -62,11 +62,11 @@ std::unique_ptr<BackgroundDownloadService> CreateDownloadServiceInternal(
auto model = std::make_unique<ModelImpl>(std::move(store));
// Build platform network/battery status listener.
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
auto battery_listener = std::make_unique<BatteryStatusListenerAndroid>(
config->battery_query_interval);
auto network_listener = std::make_unique<NetworkStatusListenerAndroid>();
-#elif defined(OS_APPLE)
+#elif BUILDFLAG(IS_APPLE)
auto battery_listener = std::make_unique<BatteryStatusListenerMac>();
auto network_listener =
std::make_unique<NetworkStatusListenerImpl>(network_connection_tracker);
diff --git a/chromium/components/download/database/download_db_conversions.cc b/chromium/components/download/database/download_db_conversions.cc
index 2f81a7566b6..0cebdf37669 100644
--- a/chromium/components/download/database/download_db_conversions.cc
+++ b/chromium/components/download/database/download_db_conversions.cc
@@ -166,7 +166,8 @@ download_pb::InProgressInfo DownloadDBConversions::InProgressInfoToProto(
for (size_t i = 0; i < in_progress_info.url_chain.size(); ++i)
proto.add_url_chain(in_progress_info.url_chain[i].spec());
proto.set_referrer_url(in_progress_info.referrer_url.spec());
- proto.set_site_url(in_progress_info.site_url.spec());
+ proto.set_serialized_embedder_download_data(
+ in_progress_info.serialized_embedder_download_data);
proto.set_tab_url(in_progress_info.tab_url.spec());
proto.set_tab_referrer_url(in_progress_info.tab_referrer_url.spec());
proto.set_fetch_error_body(in_progress_info.fetch_error_body);
@@ -238,7 +239,8 @@ InProgressInfo DownloadDBConversions::InProgressInfoFromProto(
for (const auto& url : proto.url_chain())
info.url_chain.emplace_back(url);
info.referrer_url = GURL(proto.referrer_url());
- info.site_url = GURL(proto.site_url());
+ info.serialized_embedder_download_data =
+ proto.serialized_embedder_download_data();
info.tab_url = GURL(proto.tab_url());
info.tab_referrer_url = GURL(proto.tab_referrer_url());
info.fetch_error_body = proto.fetch_error_body();
diff --git a/chromium/components/download/database/download_db_conversions_unittest.cc b/chromium/components/download/database/download_db_conversions_unittest.cc
index 8bc2e74be3d..3257f19617d 100644
--- a/chromium/components/download/database/download_db_conversions_unittest.cc
+++ b/chromium/components/download/database/download_db_conversions_unittest.cc
@@ -24,7 +24,7 @@ InProgressInfo CreateInProgressInfo() {
info.url_chain.emplace_back("http://foo");
info.url_chain.emplace_back("http://foo2");
info.referrer_url = GURL("http://foo1.com");
- info.site_url = GURL("http://foo.com");
+ info.serialized_embedder_download_data = std::string();
info.tab_url = GURL("http://foo.com");
info.tab_referrer_url = GURL("http://abc.com");
info.start_time = base::Time::NowFromSystemTime().LocalMidnight();
diff --git a/chromium/components/download/database/in_progress/in_progress_info.cc b/chromium/components/download/database/in_progress/in_progress_info.cc
index 2114b3c095b..5523103fdfa 100644
--- a/chromium/components/download/database/in_progress/in_progress_info.cc
+++ b/chromium/components/download/database/in_progress/in_progress_info.cc
@@ -13,7 +13,9 @@ InProgressInfo::InProgressInfo(const InProgressInfo& other) = default;
InProgressInfo::~InProgressInfo() = default;
bool InProgressInfo::operator==(const InProgressInfo& other) const {
- return url_chain == other.url_chain && site_url == other.site_url &&
+ return url_chain == other.url_chain &&
+ serialized_embedder_download_data ==
+ other.serialized_embedder_download_data &&
referrer_url == other.referrer_url && tab_url == other.tab_url &&
tab_referrer_url == other.tab_referrer_url &&
fetch_error_body == other.fetch_error_body &&
diff --git a/chromium/components/download/database/in_progress/in_progress_info.h b/chromium/components/download/database/in_progress/in_progress_info.h
index 36c55246a74..bcdb21016cb 100644
--- a/chromium/components/download/database/in_progress/in_progress_info.h
+++ b/chromium/components/download/database/in_progress/in_progress_info.h
@@ -37,8 +37,8 @@ struct InProgressInfo {
// Referrer url.
GURL referrer_url;
- // Site url.
- GURL site_url;
+ // The serialized embedder download data.
+ std::string serialized_embedder_download_data;
// Tab url.
GURL tab_url;
diff --git a/chromium/components/download/database/proto/download_entry.proto b/chromium/components/download/database/proto/download_entry.proto
index 3897f0483c8..088f23aba8f 100644
--- a/chromium/components/download/database/proto/download_entry.proto
+++ b/chromium/components/download/database/proto/download_entry.proto
@@ -56,7 +56,7 @@ message DownloadSchedule {
message InProgressInfo {
repeated string url_chain = 1;
optional string referrer_url = 2;
- optional string site_url = 3;
+ optional string site_url = 3; // deprecated
optional string tab_url = 4;
optional string tab_referrer_url = 5;
optional bool fetch_error_body = 6;
@@ -86,6 +86,7 @@ message InProgressInfo {
optional int32 credentials_mode = 30; // network::mojom::CredentialsMode
optional int64 range_request_from = 31;
optional int64 range_request_to = 32;
+ optional string serialized_embedder_download_data = 33;
}
// Stores various metadata related to a download.
diff --git a/chromium/components/download/internal/background_service/driver_entry.h b/chromium/components/download/internal/background_service/driver_entry.h
index 97ceadc92a1..2f569c72804 100644
--- a/chromium/components/download/internal/background_service/driver_entry.h
+++ b/chromium/components/download/internal/background_service/driver_entry.h
@@ -15,9 +15,9 @@
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "url/gurl.h"
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
#include "storage/browser/blob/blob_data_handle.h"
-#endif // OS_IOS
+#endif
namespace net {
class HttpResponseHeaders;
@@ -73,11 +73,11 @@ struct DriverEntry {
// Will be empty file path in incognito mode.
base::FilePath current_file_path;
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
// The blob data handle that contains download data.
// Will be available after the download is completed in incognito mode.
absl::optional<storage::BlobDataHandle> blob_handle;
-#endif // OS_IOS
+#endif
// Time the download was marked as complete, base::Time() if the download is
// not yet complete.
diff --git a/chromium/components/download/internal/background_service/scheduler/device_status_listener.cc b/chromium/components/download/internal/background_service/scheduler/device_status_listener.cc
index e0b4119ed25..55554c10600 100644
--- a/chromium/components/download/internal/background_service/scheduler/device_status_listener.cc
+++ b/chromium/components/download/internal/background_service/scheduler/device_status_listener.cc
@@ -33,7 +33,7 @@ NetworkStatus ToNetworkStatus(network::mojom::ConnectionType type) {
case network::mojom::ConnectionType::CONNECTION_BLUETOOTH:
return NetworkStatus::DISCONNECTED;
case network::mojom::ConnectionType::CONNECTION_UNKNOWN:
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
return NetworkStatus::DISCONNECTED;
#else
return NetworkStatus::UNMETERED;
diff --git a/chromium/components/download/internal/background_service/scheduler/device_status_listener_unittest.cc b/chromium/components/download/internal/background_service/scheduler/device_status_listener_unittest.cc
index 44cddf1a406..799798eb535 100644
--- a/chromium/components/download/internal/background_service/scheduler/device_status_listener_unittest.cc
+++ b/chromium/components/download/internal/background_service/scheduler/device_status_listener_unittest.cc
@@ -287,7 +287,7 @@ TEST_F(DeviceStatusListenerTest, ConnectionUnknownTreatedCorrectly) {
base::RunLoop().RunUntilIdle();
// Initial states check.
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
EXPECT_EQ(NetworkStatus::DISCONNECTED,
listener_->CurrentDeviceStatus().network_status);
#else
diff --git a/chromium/components/download/internal/common/BUILD.gn b/chromium/components/download/internal/common/BUILD.gn
index 2069d2b89d2..1ddc494ecc7 100644
--- a/chromium/components/download/internal/common/BUILD.gn
+++ b/chromium/components/download/internal/common/BUILD.gn
@@ -90,10 +90,6 @@ source_set("internal") {
deps += [ "//components/safe_browsing/content/common:file_type_policies" ]
}
- if (is_win) {
- deps += [ "//components/services/quarantine/public/cpp:features" ]
- }
-
if (is_android) {
sources += [
"android/download_collection_bridge.cc",
diff --git a/chromium/components/download/internal/common/DEPS b/chromium/components/download/internal/common/DEPS
index 248ecbec0a3..eaa084960d9 100644
--- a/chromium/components/download/internal/common/DEPS
+++ b/chromium/components/download/internal/common/DEPS
@@ -8,7 +8,6 @@ include_rules = [
"+components/leveldb_proto",
"+components/safe_browsing/buildflags.h",
"+components/safe_browsing/content/common",
- "+components/services/quarantine/public/cpp/quarantine_features_win.h",
"+components/services/quarantine/quarantine.h",
"+components/ukm/test_ukm_recorder.h",
"+crypto",
diff --git a/chromium/components/download/internal/common/base_file.cc b/chromium/components/download/internal/common/base_file.cc
index a7404e7b293..e5899145012 100644
--- a/chromium/components/download/internal/common/base_file.cc
+++ b/chromium/components/download/internal/common/base_file.cc
@@ -25,14 +25,10 @@
#include "components/services/quarantine/quarantine.h"
#include "crypto/secure_hash.h"
-#if defined(OS_WIN)
-#include "components/services/quarantine/public/cpp/quarantine_features_win.h"
-#endif // defined(OS_WIN)
-
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "base/android/content_uri_utils.h"
#include "components/download/internal/common/android/download_collection_bridge.h"
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
#define CONDITIONAL_TRACE(trace) \
do { \
@@ -75,12 +71,12 @@ class FileErrorData : public base::trace_event::ConvertableToTraceFormat {
};
void InitializeFile(base::File* file, const base::FilePath& file_path) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
if (file_path.IsContentUri()) {
*file = DownloadCollectionBridge::OpenIntermediateUri(file_path);
return;
}
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
// Use exclusive write to prevent another process from writing the file.
file->Initialize(file_path,
@@ -92,12 +88,12 @@ void InitializeFile(base::File* file, const base::FilePath& file_path) {
}
void DeleteFileWrapper(const base::FilePath& file_path) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
if (file_path.IsContentUri()) {
DownloadCollectionBridge::DeleteIntermediateUri(file_path);
return;
}
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
base::DeleteFile(file_path);
}
@@ -257,7 +253,7 @@ DownloadInterruptReason BaseFile::Rename(const base::FilePath& new_path) {
full_path_.AsUTF8Unsafe(), "new_filename",
new_path.AsUTF8Unsafe()));
bool need_to_move_file = true;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
if (new_path.IsContentUri()) {
rename_result = DownloadCollectionBridge::MoveFileToIntermediateUri(
full_path_, new_path);
@@ -516,7 +512,7 @@ DownloadInterruptReason BaseFile::LogInterruptReason(
return reason;
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
DownloadInterruptReason BaseFile::PublishDownload() {
Close();
base::FilePath new_path =
@@ -527,7 +523,7 @@ DownloadInterruptReason BaseFile::PublishDownload() {
}
return DOWNLOAD_INTERRUPT_REASON_FILE_FAILED;
}
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
namespace {
@@ -617,16 +613,13 @@ void BaseFile::OnFileQuarantined(
void BaseFile::OnQuarantineServiceError(const GURL& source_url,
const GURL& referrer_url) {
-#if defined(OS_WIN)
- if (base::FeatureList::IsEnabled(quarantine::kOutOfProcessQuarantine)) {
- OnFileQuarantined(/*connection_error=*/true,
- quarantine::SetInternetZoneIdentifierDirectly(
- full_path_, source_url, referrer_url));
- return;
- }
-#endif // defined(OS_WIN)
-
+#if BUILDFLAG(IS_WIN)
+ OnFileQuarantined(/*connection_error=*/true,
+ quarantine::SetInternetZoneIdentifierDirectly(
+ full_path_, source_url, referrer_url));
+#else // !BUILDFLAG(IS_WIN)
CHECK(false) << "In-process quarantine service should not have failed.";
+#endif // !BUILDFLAG(IS_WIN)
}
void BaseFile::AnnotateWithSourceInformation(
@@ -637,7 +630,7 @@ void BaseFile::AnnotateWithSourceInformation(
OnAnnotationDoneCallback on_annotation_done_callback) {
GURL authority_url = GetEffectiveAuthorityURL(source_url, referrer_url);
if (!remote_quarantine) {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
quarantine::mojom::QuarantineFileResult result =
quarantine::SetInternetZoneIdentifierDirectly(full_path_, authority_url,
referrer_url);
diff --git a/chromium/components/download/internal/common/base_file_unittest.cc b/chromium/components/download/internal/common/base_file_unittest.cc
index dbfa9c5a762..702554a6894 100644
--- a/chromium/components/download/internal/common/base_file_unittest.cc
+++ b/chromium/components/download/internal/common/base_file_unittest.cc
@@ -23,7 +23,7 @@
#include "crypto/sha2.h"
#include "testing/gtest/include/gtest/gtest.h"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include "base/win/scoped_com_initializer.h"
#endif
@@ -65,7 +65,7 @@ class BaseFileTest : public testing::Test {
expected_error_(DOWNLOAD_INTERRUPT_REASON_NONE) {}
void SetUp() override {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
ASSERT_TRUE(com_initializer_.Succeeded());
#endif
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
@@ -151,13 +151,13 @@ class BaseFileTest : public testing::Test {
DownloadInterruptReason reason = duplicate_file.Initialize(
file_name, temp_dir_.GetPath(), base::File(), 0, std::string(),
std::unique_ptr<crypto::SecureHash>(), false, &kTestDataBytesWasted);
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
EXPECT_EQ(reason, DOWNLOAD_INTERRUPT_REASON_FILE_FAILED);
#else
EXPECT_EQ(reason, DOWNLOAD_INTERRUPT_REASON_NONE);
// Write something into it.
duplicate_file.AppendDataToFile(kTestData4, kTestDataLength4);
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
// Detach the file so it isn't deleted on destruction of |duplicate_file|.
duplicate_file.Detach();
@@ -193,7 +193,7 @@ class BaseFileTest : public testing::Test {
}
private:
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// This must occur early in the member list to ensure COM is initialized first
// and uninitialized last.
base::win::ScopedCOMInitializer com_initializer_;
@@ -436,9 +436,9 @@ TEST_F(BaseFileTest, WriteWithError) {
std::string(),
std::unique_ptr<crypto::SecureHash>(), false,
&kTestDataBytesWasted));
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
set_expected_error(DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED);
-#elif defined(OS_POSIX)
+#elif BUILDFLAG(IS_POSIX)
set_expected_error(DOWNLOAD_INTERRUPT_REASON_FILE_FAILED);
#endif
ASSERT_FALSE(AppendDataToFile(kTestData1));
diff --git a/chromium/components/download/internal/common/download_create_info.cc b/chromium/components/download/internal/common/download_create_info.cc
index 880cc326b52..eaf28c7c59a 100644
--- a/chromium/components/download/internal/common/download_create_info.cc
+++ b/chromium/components/download/internal/common/download_create_info.cc
@@ -23,6 +23,7 @@ DownloadCreateInfo::DownloadCreateInfo(
offset(0),
has_user_gesture(false),
transient(false),
+ require_safety_checks(true),
result(DOWNLOAD_INTERRUPT_REASON_NONE),
save_info(std::move(save_info)),
render_process_id(-1),
diff --git a/chromium/components/download/internal/common/download_file_impl.cc b/chromium/components/download/internal/common/download_file_impl.cc
index a856532f9e4..6dd78c248bf 100644
--- a/chromium/components/download/internal/common/download_file_impl.cc
+++ b/chromium/components/download/internal/common/download_file_impl.cc
@@ -30,10 +30,10 @@
#include "mojo/public/c/system/types.h"
#include "net/base/io_buffer.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "base/android/content_uri_utils.h"
#include "components/download/internal/common/android/download_collection_bridge.h"
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
namespace download {
@@ -358,7 +358,7 @@ void DownloadFileImpl::RenameAndAnnotate(
RenameWithRetryInternal(std::move(parameters));
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
void DownloadFileImpl::RenameToIntermediateUri(
const GURL& original_url,
const GURL& referrer_url,
@@ -392,7 +392,7 @@ void DownloadFileImpl::PublishDownload(RenameCompletionCallback callback) {
base::FilePath DownloadFileImpl::GetDisplayName() {
return display_name_;
}
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
base::TimeDelta DownloadFileImpl::GetRetryDelayForFailedRename(
int attempt_number) {
diff --git a/chromium/components/download/internal/common/download_file_unittest.cc b/chromium/components/download/internal/common/download_file_unittest.cc
index a87d67c3327..1683cb98a52 100644
--- a/chromium/components/download/internal/common/download_file_unittest.cc
+++ b/chromium/components/download/internal/common/download_file_unittest.cc
@@ -30,7 +30,7 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include "base/win/scoped_com_initializer.h"
#endif
@@ -122,7 +122,7 @@ class TestDownloadFileImpl : public DownloadFileImpl {
return base::Milliseconds(0);
}
-#if !defined(OS_WIN)
+#if !BUILDFLAG(IS_WIN)
// On Posix, we don't encounter transient errors during renames, except
// possibly EAGAIN, which is difficult to replicate reliably. So we resort to
// simulating a transient error using ACCESS_DENIED instead.
@@ -174,7 +174,7 @@ class DownloadFileTest : public testing::Test {
}
void SetUp() override {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
ASSERT_TRUE(com_initializer_.Succeeded());
#endif
EXPECT_CALL(*(observer_.get()), DestinationUpdate(_, _, _))
@@ -483,7 +483,7 @@ class DownloadFileTest : public testing::Test {
}
private:
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// This must occur early in the member list to ensure COM is initialized first
// and uninitialized last.
base::win::ScopedCOMInitializer com_initializer_;
@@ -800,7 +800,7 @@ TEST_P(DownloadFileTestWithRename, RenameWithErrorRetry) {
base::RunLoop succeeding_run;
{
// (Scope for the base::File or base::FilePermissionRestorer below.)
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// On Windows we test with an actual transient error, a sharing violation.
// The rename will fail because we are holding the file open for READ. On
// Posix this doesn't cause a failure.
diff --git a/chromium/components/download/internal/common/download_item_impl.cc b/chromium/components/download/internal/common/download_item_impl.cc
index 9761fe99a6b..3e1abc9e643 100644
--- a/chromium/components/download/internal/common/download_item_impl.cc
+++ b/chromium/components/download/internal/common/download_item_impl.cc
@@ -63,9 +63,9 @@
#include "net/url_request/referrer_policy.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "components/download/internal/common/android/download_collection_bridge.h"
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
namespace download {
@@ -231,7 +231,7 @@ const int DownloadItemImpl::kMaxAutoResumeAttempts = 5;
DownloadItemImpl::RequestInfo::RequestInfo(
const std::vector<GURL>& url_chain,
const GURL& referrer_url,
- const GURL& site_url,
+ const std::string& serialized_embedder_download_data,
const GURL& tab_url,
const GURL& tab_referrer_url,
const absl::optional<url::Origin>& request_initiator,
@@ -247,7 +247,7 @@ DownloadItemImpl::RequestInfo::RequestInfo(
int64_t range_request_to)
: url_chain(url_chain),
referrer_url(referrer_url),
- site_url(site_url),
+ serialized_embedder_download_data(serialized_embedder_download_data),
tab_url(tab_url),
tab_referrer_url(tab_referrer_url),
request_initiator(request_initiator),
@@ -306,7 +306,7 @@ DownloadItemImpl::DownloadItemImpl(
const base::FilePath& target_path,
const std::vector<GURL>& url_chain,
const GURL& referrer_url,
- const GURL& site_url,
+ const std::string& serialized_embedder_download_data,
const GURL& tab_url,
const GURL& tab_refererr_url,
const absl::optional<url::Origin>& request_initiator,
@@ -336,7 +336,7 @@ DownloadItemImpl::DownloadItemImpl(
std::unique_ptr<DownloadEntry> download_entry)
: request_info_(url_chain,
referrer_url,
- site_url,
+ serialized_embedder_download_data,
tab_url,
tab_refererr_url,
request_initiator,
@@ -401,7 +401,7 @@ DownloadItemImpl::DownloadItemImpl(DownloadItemImplDelegate* delegate,
const DownloadCreateInfo& info)
: request_info_(info.url_chain,
info.referrer_url,
- info.site_url,
+ info.serialized_embedder_download_data,
info.tab_url,
info.tab_referrer_url,
info.request_initiator,
@@ -429,6 +429,7 @@ DownloadItemImpl::DownloadItemImpl(DownloadItemImplDelegate* delegate,
delegate_(delegate),
is_temporary_(!info.transient && !info.save_info->file_path.empty()),
transient_(info.transient),
+ require_safety_checks_(info.require_safety_checks),
destination_info_(info.save_info->prompt_for_save_location
? TARGET_DISPOSITION_PROMPT
: TARGET_DISPOSITION_OVERWRITE),
@@ -686,7 +687,9 @@ void DownloadItemImpl::UpdateResumptionInfo(bool user_resume) {
bytes_wasted_ = 0;
}
- auto_resume_count_ = user_resume ? 0 : ++auto_resume_count_;
+ ++auto_resume_count_;
+ if (user_resume)
+ auto_resume_count_ = 0;
download_schedule_ = absl::nullopt;
RecordDownloadLaterEvent(DownloadLaterEvent::kScheduleRemoved);
}
@@ -736,7 +739,7 @@ void DownloadItemImpl::OpenDownload() {
for (auto& observer : observers_)
observer.OnDownloadOpened(this);
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// On Windows, don't actually open the file if it has no extension, to prevent
// Windows from interpreting it as the command for an executable of the same
// name.
@@ -765,9 +768,9 @@ void DownloadItemImpl::RenameDownloadedFileDone(
DownloadRenameResult result) {
if (result == DownloadRenameResult::SUCCESS) {
bool is_content_uri = false;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
is_content_uri = GetFullPath().IsContentUri();
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
if (is_content_uri) {
SetDisplayName(display_name);
} else {
@@ -893,8 +896,8 @@ const GURL& DownloadItemImpl::GetReferrerUrl() const {
return request_info_.referrer_url;
}
-const GURL& DownloadItemImpl::GetSiteUrl() const {
- return request_info_.site_url;
+const std::string& DownloadItemImpl::GetSerializedEmbedderDownloadData() const {
+ return request_info_.serialized_embedder_download_data;
}
const GURL& DownloadItemImpl::GetTabUrl() const {
@@ -1169,6 +1172,10 @@ bool DownloadItemImpl::IsTransient() const {
return transient_;
}
+bool DownloadItemImpl::RequireSafetyChecks() const {
+ return require_safety_checks_;
+}
+
bool DownloadItemImpl::IsParallelDownload() const {
bool is_parallelizable = job_ ? job_->IsParallelizable() : false;
return is_parallelizable && download::IsParallelDownloadEnabled();
@@ -1308,7 +1315,7 @@ std::string DownloadItemImpl::DebugString(bool verbose) const {
" rereoute_info = '%s'"
"\""
" referrer = \"%s\""
- " site_url = \"%s\"",
+ " serialized_embedder_download_data = \"%s\"",
GetTotalBytes(), GetReceivedBytes(),
DownloadInterruptReasonToString(last_reason_).c_str(),
IsPaused() ? 'T' : 'F', DebugResumeModeString(GetResumeMode()),
@@ -1317,7 +1324,7 @@ std::string DownloadItemImpl::DebugString(bool verbose) const {
download_file_ ? "true" : "false", url_list.c_str(),
GetFullPath().value().c_str(), GetTargetFilePath().value().c_str(),
reroute_info_.DebugString().c_str(), GetReferrerUrl().spec().c_str(),
- GetSiteUrl().spec().c_str());
+ GetSerializedEmbedderDownloadData().c_str());
} else {
description += base::StringPrintf(" url = \"%s\"", url_list.c_str());
}
@@ -1671,13 +1678,8 @@ void DownloadItemImpl::Start(
}
RecordDownloadMimeType(mime_type_);
DownloadContent file_type = DownloadContentFromMimeType(mime_type_, false);
- bool is_same_host_download = base::EndsWith(
- new_create_info.url().host(), new_create_info.site_url.host());
DownloadConnectionSecurity state = CheckDownloadConnectionSecurity(
new_create_info.url(), new_create_info.url_chain);
- DownloadUkmHelper::RecordDownloadStarted(
- ukm_download_id_, new_create_info.ukm_source_id, file_type,
- download_source_, state, is_same_host_download);
RecordDownloadValidationMetrics(DownloadMetricsCallsite::kDownloadItem,
state, file_type);
@@ -1692,8 +1694,11 @@ void DownloadItemImpl::Start(
DCHECK(download_file_);
DCHECK(job_);
- if (state_ == RESUMING_INTERNAL)
+ if (state_ == RESUMING_INTERNAL) {
+ if (total_bytes_ == 0 && new_create_info.total_bytes > 0)
+ total_bytes_ = new_create_info.total_bytes;
UpdateValidatorsOnResumption(new_create_info);
+ }
// If the download is not parallel, clear the |received_slices_|.
if (!received_slices_.empty() && !job_->IsParallelizable()) {
@@ -1833,7 +1838,7 @@ void DownloadItemImpl::OnDownloadTargetDetermined(
DownloadFile::RenameCompletionCallback callback =
base::BindOnce(&DownloadItemImpl::OnDownloadRenamedToIntermediateName,
weak_ptr_factory_.GetWeakPtr());
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
if ((download_type_ == TYPE_ACTIVE_DOWNLOAD && !transient_ &&
DownloadCollectionBridge::ShouldPublishDownload(GetTargetFilePath())) ||
GetTargetFilePath().IsContentUri()) {
@@ -1847,7 +1852,7 @@ void DownloadItemImpl::OnDownloadTargetDetermined(
std::move(callback)));
return;
}
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
GetDownloadTaskRunner()->PostTask(
FROM_HERE,
@@ -1868,14 +1873,14 @@ void DownloadItemImpl::OnDownloadRenamedToIntermediateName(
if (DOWNLOAD_INTERRUPT_REASON_NONE == reason) {
SetFullPath(full_path);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// For content URIs, target file path is the same as the current path.
if (full_path.IsContentUri()) {
destination_info_.target_path = full_path;
if (display_name_.empty())
SetDisplayName(download_file_->GetDisplayName());
}
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
} else {
// TODO(asanka): Even though the rename failed, it may still be possible to
// recover the partial state from the 'before' name.
@@ -2020,7 +2025,7 @@ void DownloadItemImpl::OnDownloadCompleting() {
weak_ptr_factory_.GetWeakPtr());
// If an alternate rename handler is specified, use it instead.
- if (GetRenameHandler()) {
+ if (GetRenameHandler() && !is_temporary_) {
auto update_callback =
base::BindRepeating(&DownloadItemImpl::OnRenameHandlerUpdate,
weak_ptr_factory_.GetWeakPtr());
@@ -2028,7 +2033,7 @@ void DownloadItemImpl::OnDownloadCompleting() {
return;
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
if (GetTargetFilePath().IsContentUri()) {
GetDownloadTaskRunner()->PostTask(
FROM_HERE,
@@ -2038,7 +2043,7 @@ void DownloadItemImpl::OnDownloadCompleting() {
std::move(rename_callback)));
return;
}
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
mojo::PendingRemote<quarantine::mojom::Quarantine> quarantine;
auto quarantine_callback = delegate_->GetQuarantineConnectionCallback();
@@ -2243,7 +2248,7 @@ void DownloadItemImpl::InterruptWithPartialState(
}
// else - Fallthrough for cancellation handling which is equivalent to the
// IN_PROGRESS state.
- FALLTHROUGH;
+ [[fallthrough]];
case IN_PROGRESS_INTERNAL:
case TARGET_RESOLVED_INTERNAL: {
@@ -2734,8 +2739,9 @@ void DownloadItemImpl::ResumeInterruptedDownload(
DownloadUkmHelper::RecordDownloadResumed(ukm_download_id_, GetResumeMode(),
time_since_start);
- delegate_->ResumeInterruptedDownload(std::move(download_params),
- request_info_.site_url);
+ delegate_->ResumeInterruptedDownload(
+ std::move(download_params),
+ request_info_.serialized_embedder_download_data);
if (job_)
job_->Resume(false);
@@ -2924,7 +2930,8 @@ size_t DownloadItemImpl::GetApproximateMemoryUsage() const {
for (const GURL& url : GetUrlChain())
size += url.EstimateMemoryUsage();
size += GetReferrerUrl().EstimateMemoryUsage();
- size += GetSiteUrl().EstimateMemoryUsage();
+ size += base::trace_event::EstimateMemoryUsage(
+ GetSerializedEmbedderDownloadData());
size += GetTabUrl().EstimateMemoryUsage();
size += GetTabReferrerUrl().EstimateMemoryUsage();
size += base::trace_event::EstimateMemoryUsage(GetSuggestedFilename());
diff --git a/chromium/components/download/internal/common/download_item_impl_delegate.cc b/chromium/components/download/internal/common/download_item_impl_delegate.cc
index 92c931b6448..1c36aeedb51 100644
--- a/chromium/components/download/internal/common/download_item_impl_delegate.cc
+++ b/chromium/components/download/internal/common/download_item_impl_delegate.cc
@@ -77,7 +77,7 @@ std::string DownloadItemImplDelegate::GetApplicationClientIdForFileScanning()
void DownloadItemImplDelegate::ResumeInterruptedDownload(
std::unique_ptr<DownloadUrlParameters> params,
- const GURL& site_url) {}
+ const std::string& serialized_embedder_download_data) {}
void DownloadItemImplDelegate::UpdatePersistence(DownloadItemImpl* download) {}
diff --git a/chromium/components/download/internal/common/download_item_impl_unittest.cc b/chromium/components/download/internal/common/download_item_impl_unittest.cc
index d0c1ab47e28..0eae1df76f8 100644
--- a/chromium/components/download/internal/common/download_item_impl_unittest.cc
+++ b/chromium/components/download/internal/common/download_item_impl_unittest.cc
@@ -40,9 +40,9 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "components/download/internal/common/android/download_collection_bridge.h"
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
using ::testing::_;
using ::testing::ByMove;
@@ -118,8 +118,9 @@ class MockDelegate : public DownloadItemImplDelegate {
MOCK_METHOD1(ShouldOpenFileBasedOnExtension, bool(const base::FilePath&));
MOCK_METHOD1(CheckForFileRemoval, void(DownloadItemImpl*));
- void ResumeInterruptedDownload(std::unique_ptr<DownloadUrlParameters> params,
- const GURL& site_url) override {
+ void ResumeInterruptedDownload(
+ std::unique_ptr<DownloadUrlParameters> params,
+ const std::string& serialized_embedder_download_data) override {
MockResumeInterruptedDownload(params.get());
}
MOCK_METHOD1(MockResumeInterruptedDownload,
@@ -289,9 +290,8 @@ class DownloadItemTest : public testing::Test {
const download::DownloadItemRerouteInfo& reroute_info) {
auto item = std::make_unique<download::DownloadItemImpl>(
mock_delegate(), kGuid, 10, base::FilePath(), base::FilePath(),
- std::vector<GURL>(), GURL("http://example.com/a"),
+ std::vector<GURL>(), GURL("http://example.com/a"), std::string(),
GURL("http://example.com/a"), GURL("http://example.com/a"),
- GURL("http://example.com/a"),
url::Origin::Create(GURL("http://example.com")),
"application/octet-stream", "application/octet-stream",
base::Time::Now(), base::Time::Now(), std::string(), std::string(), 10,
@@ -386,7 +386,7 @@ class DownloadItemTest : public testing::Test {
const base::FilePath& new_file_path,
DownloadInterruptReason reason) {
bool use_download_collection = false;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
if (DownloadCollectionBridge::ShouldPublishDownload(new_file_path)) {
use_download_collection = true;
EXPECT_CALL(*download_file, RenameToIntermediateUri(_, _, _, _, _, _))
@@ -2422,7 +2422,7 @@ DownloadFile::RenameCompletionCallback GetRenameCompletionCallback(
MockDownloadFile* download_file) {
DownloadFile::RenameCompletionCallback intermediate_rename_callback;
bool use_download_collection = false;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
if (DownloadCollectionBridge::ShouldPublishDownload(
base::FilePath(kDummyIntermediatePath))) {
use_download_collection = true;
diff --git a/chromium/components/download/internal/common/download_path_reservation_tracker.cc b/chromium/components/download/internal/common/download_path_reservation_tracker.cc
index 38e304c431f..2457a91f52e 100644
--- a/chromium/components/download/internal/common/download_path_reservation_tracker.cc
+++ b/chromium/components/download/internal/common/download_path_reservation_tracker.cc
@@ -32,7 +32,7 @@
#include "net/base/filename_util.h"
#include "url/gurl.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "components/download/internal/common/android/download_collection_bridge.h"
#endif
@@ -49,11 +49,11 @@ typedef std::map<ReservationKey, base::FilePath> ReservationMap;
// possible filename.
const size_t kIntermediateNameSuffixLength = sizeof(".crdownload") - 1;
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// On windows, zone identifier is appended to the downloaded file name during
// annotation. That increases the length of the final target path.
const size_t kZoneIdentifierLength = sizeof(":Zone.Identifier") - 1;
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
// Map of download path reservations. Each reserved path is associated with a
// ReservationKey=DownloadItem*. This object is destroyed in |Revoke()| when
@@ -112,13 +112,13 @@ bool IsPathReservedInternal(const base::FilePath& path, DownloadItem* item) {
// and has a different key than |item|. Called on the task
// runner returned by DownloadPathReservationTracker::GetTaskRunner().
bool IsAdditionalPathReserved(const base::FilePath& path, DownloadItem* item) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// If download collection is used, only file name needs to be
// unique.
if (DownloadCollectionBridge::ShouldPublishDownload(path)) {
return IsPathReservedInternal(path.BaseName(), item);
}
-#endif // defined(OS_ANDROID) // No reservation map => no reservations.
+#endif // BUILDFLAG(IS_ANDROID) // No reservation map => no reservations.
return IsPathReservedInternal(path, item);
}
@@ -139,7 +139,7 @@ bool IsPathInUse(const base::FilePath& path) {
if (base::PathExists(path))
return true;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// If download collection is used, only file name needs to be
// unique.
if (DownloadCollectionBridge::ShouldPublishDownload(path))
@@ -178,7 +178,7 @@ bool CreateUniqueFilename(int max_path_component_length,
// If the name length limit is available (max_length != -1), and the
// the current name exceeds the limit, truncate.
if (max_path_component_length != -1) {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
int limit =
max_path_component_length -
std::max(kIntermediateNameSuffixLength, kZoneIdentifierLength) -
@@ -186,7 +186,7 @@ bool CreateUniqueFilename(int max_path_component_length,
#else
int limit = max_path_component_length - kIntermediateNameSuffixLength -
suffix.size();
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
// If truncation failed, give up uniquification.
if (limit <= 0 ||
!filename_generation::TruncateFilename(&path_to_check, limit))
@@ -278,12 +278,12 @@ PathValidationResult ValidatePathAndResolveConflicts(
// Check the limit of file name length if it could be obtained. When the
// suggested name exceeds the limit, truncate or prompt the user.
if (max_path_component_length != -1) {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
int limit = max_path_component_length -
std::max(kIntermediateNameSuffixLength, kZoneIdentifierLength);
#else
int limit = max_path_component_length - kIntermediateNameSuffixLength;
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
if (limit <= 0 ||
!filename_generation::TruncateFilename(target_path, limit))
return PathValidationResult::NAME_TOO_LONG;
@@ -333,7 +333,7 @@ PathValidationResult CreateReservation(const CreateReservationInfo& info,
base::FilePath target_dir = target_path.DirName();
base::FilePath filename = target_path.BaseName();
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
if (DownloadCollectionBridge::ShouldPublishDownload(target_path)) {
PathValidationResult result = PathValidationResult::SUCCESS;
// Disallow downloading a file onto itself. Assume that downloading a file
@@ -378,12 +378,12 @@ void UpdateReservation(ReservationKey key, const base::FilePath& new_path) {
auto iter = g_reservation_map->find(key);
if (iter != g_reservation_map->end()) {
bool use_download_collection = false;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
if (DownloadCollectionBridge::ShouldPublishDownload(new_path)) {
use_download_collection = true;
iter->second = new_path.BaseName();
}
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
if (!use_download_collection) {
iter->second = new_path;
}
@@ -418,7 +418,7 @@ void RunGetReservedPathCallback(
// Gets the path reserved in the global |g_reservation_map|. For content Uri,
// file name instead of file path is used.
base::FilePath GetReservationPath(DownloadItem* download_item) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
if (download_item->GetTargetFilePath().IsContentUri())
return download_item->GetFileNameToReportUser();
#endif
diff --git a/chromium/components/download/internal/common/download_path_reservation_tracker_unittest.cc b/chromium/components/download/internal/common/download_path_reservation_tracker_unittest.cc
index 3edc3eab454..678a3d56e00 100644
--- a/chromium/components/download/internal/common/download_path_reservation_tracker_unittest.cc
+++ b/chromium/components/download/internal/common/download_path_reservation_tracker_unittest.cc
@@ -26,9 +26,9 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "components/download/internal/common/android/download_collection_bridge.h"
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
using testing::AnyNumber;
using testing::Return;
@@ -99,7 +99,7 @@ DownloadPathReservationTrackerTest::DownloadPathReservationTrackerTest() =
void DownloadPathReservationTrackerTest::SetUp() {
ASSERT_TRUE(test_download_dir_.CreateUniqueTempDir());
set_default_download_path(test_download_dir_.GetPath());
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Initialize the global file name map for testing.
if (DownloadCollectionBridge::ShouldPublishDownload(
GetPathInDownloadsDirectory(FILE_PATH_LITERAL("foo.txt")))) {
@@ -280,12 +280,12 @@ TEST_F(DownloadPathReservationTrackerTest, ConflictingFiles) {
base::FilePath path1(
GetPathInDownloadsDirectory(FILE_PATH_LITERAL("foo (1).txt")));
bool use_download_collection = false;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
if (DownloadCollectionBridge::ShouldPublishDownload(path)) {
use_download_collection = true;
DownloadCollectionBridge::AddExistingFileNameForTesting(path.BaseName());
}
-#endif // OS_ANDROID
+#endif // BUILDFLAG(IS_ANDROID)
if (!use_download_collection) {
// Create a file at |path|, and a .crdownload file at |path1|.
ASSERT_EQ(0, base::WriteFile(path, "", 0));
@@ -314,12 +314,12 @@ TEST_F(DownloadPathReservationTrackerTest, ConflictingFiles_Overwrite) {
base::FilePath path(
GetPathInDownloadsDirectory(FILE_PATH_LITERAL("foo.txt")));
bool use_download_collection = false;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
if (DownloadCollectionBridge::ShouldPublishDownload(path)) {
use_download_collection = true;
DownloadCollectionBridge::AddExistingFileNameForTesting(path.BaseName());
}
-#endif // OS_ANDROID
+#endif // BUILDFLAG(IS_ANDROID)
if (!use_download_collection) {
// Create a file at |path|.
ASSERT_EQ(0, base::WriteFile(path, "", 0));
@@ -341,12 +341,12 @@ TEST_F(DownloadPathReservationTrackerTest, ConflictWithSource) {
base::FilePath path(
GetPathInDownloadsDirectory(FILE_PATH_LITERAL("foo.txt")));
bool use_download_collection = false;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
if (DownloadCollectionBridge::ShouldPublishDownload(path)) {
use_download_collection = true;
DownloadCollectionBridge::AddExistingFileNameForTesting(path.BaseName());
}
-#endif // OS_ANDROID
+#endif // BUILDFLAG(IS_ANDROID)
if (!use_download_collection) {
ASSERT_EQ(0, base::WriteFile(path, "", 0));
}
@@ -511,11 +511,11 @@ TEST_F(DownloadPathReservationTrackerTest, UnwriteableDirectory) {
std::unique_ptr<MockDownloadItem> item = CreateDownloadItem(1);
base::FilePath path(
GetPathInDownloadsDirectory(FILE_PATH_LITERAL("foo.txt")));
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// This test is only valid works if download collection is not used.
if (DownloadCollectionBridge::ShouldPublishDownload(path))
return;
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
base::FilePath dir(path.DirName());
ASSERT_FALSE(IsPathInUse(path));
@@ -549,11 +549,11 @@ TEST_F(DownloadPathReservationTrackerTest, UnwriteableDirectory) {
TEST_F(DownloadPathReservationTrackerTest, CreateDefaultDownloadPath) {
base::FilePath path(
GetPathInDownloadsDirectory(FILE_PATH_LITERAL("foo/foo.txt")));
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// This test is only valid works if download collection is not used.
if (DownloadCollectionBridge::ShouldPublishDownload(path))
return;
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
base::FilePath dir(path.DirName());
ASSERT_FALSE(base::DirectoryExists(dir));
@@ -615,20 +615,20 @@ TEST_F(DownloadPathReservationTrackerTest, UpdatesToTargetPath) {
// Tests for long name truncation. On other platforms automatic truncation
// is not performed (yet).
-#if defined(OS_WIN) || defined(OS_APPLE) || BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_CHROMEOS_ASH)
TEST_F(DownloadPathReservationTrackerTest, BasicTruncation) {
int real_max_length =
base::GetMaximumPathComponentLength(default_download_path());
ASSERT_NE(-1, real_max_length);
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
const size_t max_length = real_max_length - strlen(":Zone.Identifier");
#else
// TODO(kinaba): the current implementation leaves spaces for appending
// ".crdownload". So take it into account. Should be removed in the future.
const size_t max_length = real_max_length - 11;
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
std::unique_ptr<MockDownloadItem> item = CreateDownloadItem(1);
base::FilePath path(GetLongNamePathInDownloadsDirectory(
@@ -655,11 +655,11 @@ TEST_F(DownloadPathReservationTrackerTest, TruncationConflict) {
int real_max_length =
base::GetMaximumPathComponentLength(default_download_path());
ASSERT_NE(-1, real_max_length);
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
const size_t max_length = real_max_length - strlen(":Zone.Identifier");
#else
const size_t max_length = real_max_length - 11;
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
std::unique_ptr<MockDownloadItem> item = CreateDownloadItem(1);
base::FilePath path(GetLongNamePathInDownloadsDirectory(
@@ -694,11 +694,11 @@ TEST_F(DownloadPathReservationTrackerTest, TruncationFail) {
int real_max_length =
base::GetMaximumPathComponentLength(default_download_path());
ASSERT_NE(-1, real_max_length);
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
const size_t max_length = real_max_length - strlen(":Zone.Identifier");
#else
const size_t max_length = real_max_length - 11;
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
std::unique_ptr<MockDownloadItem> item = CreateDownloadItem(1);
base::FilePath path(GetPathInDownloadsDirectory(
diff --git a/chromium/components/download/internal/common/download_response_handler.cc b/chromium/components/download/internal/common/download_response_handler.cc
index d42b4ea8e97..ed1e7f021fb 100644
--- a/chromium/components/download/internal/common/download_response_handler.cc
+++ b/chromium/components/download/internal/common/download_response_handler.cc
@@ -60,6 +60,7 @@ DownloadResponseHandler::DownloadResponseHandler(
const DownloadUrlParameters::RequestHeadersType& request_headers,
const std::string& request_origin,
DownloadSource download_source,
+ bool require_safety_checks,
std::vector<GURL> url_chain,
bool is_background_mode)
: delegate_(delegate),
@@ -80,6 +81,7 @@ DownloadResponseHandler::DownloadResponseHandler(
credentials_mode_(resource_request->credentials_mode),
is_partial_request_(save_info_->offset > 0),
completed_(false),
+ require_safety_checks_(require_safety_checks),
abort_reason_(DOWNLOAD_INTERRUPT_REASON_NONE),
is_background_mode_(is_background_mode) {
if (!is_parallel_request) {
@@ -98,7 +100,8 @@ void DownloadResponseHandler::OnReceiveEarlyHints(
network::mojom::EarlyHintsPtr early_hints) {}
void DownloadResponseHandler::OnReceiveResponse(
- network::mojom::URLResponseHeadPtr head) {
+ network::mojom::URLResponseHeadPtr head,
+ mojo::ScopedDataPipeConsumerHandle body) {
create_info_ = CreateDownloadCreateInfo(*head);
cert_status_ = head->cert_status;
@@ -124,6 +127,9 @@ void DownloadResponseHandler::OnReceiveResponse(
if (create_info_->result != DOWNLOAD_INTERRUPT_REASON_NONE)
OnResponseStarted(mojom::DownloadStreamHandlePtr());
+
+ if (body)
+ OnStartLoadingResponseBody(std::move(body));
}
std::unique_ptr<DownloadCreateInfo>
@@ -158,6 +164,7 @@ DownloadResponseHandler::CreateDownloadCreateInfo(
create_info->request_initiator = request_initiator_;
create_info->credentials_mode = credentials_mode_;
create_info->isolation_info = isolation_info_;
+ create_info->require_safety_checks = require_safety_checks_;
HandleResponseHeaders(head.headers.get(), create_info.get());
return create_info;
@@ -173,8 +180,7 @@ void DownloadResponseHandler::OnReceiveRedirect(
return;
}
- if (!first_origin_.IsSameOriginWith(
- url::Origin::Create(redirect_info.new_url))) {
+ if (!first_origin_.IsSameOriginWith(redirect_info.new_url)) {
// Cross-origin redirect.
switch (cross_origin_redirects_) {
case network::mojom::RedirectMode::kFollow:
diff --git a/chromium/components/download/internal/common/download_stats.cc b/chromium/components/download/internal/common/download_stats.cc
index 5fe4f3c92b3..4e124a75a80 100644
--- a/chromium/components/download/internal/common/download_stats.cc
+++ b/chromium/components/download/internal/common/download_stats.cc
@@ -22,7 +22,7 @@
// an empty FileTypePolicies to platforms without Safe Browsing to remove the
// BUILDFLAGs and nogncheck here.
#if (BUILDFLAG(FULL_SAFE_BROWSING) || BUILDFLAG(SAFE_BROWSING_DB_REMOTE)) && \
- !defined(OS_FUCHSIA)
+ !BUILDFLAG(IS_FUCHSIA)
#include "components/safe_browsing/content/common/file_type_policies.h" // nogncheck
#endif
@@ -251,7 +251,7 @@ void RecordDangerousDownloadAccept(DownloadDangerType danger_type,
UMA_HISTOGRAM_ENUMERATION("Download.UserValidatedDangerousDownload",
danger_type, DOWNLOAD_DANGER_TYPE_MAX);
#if (BUILDFLAG(FULL_SAFE_BROWSING) || BUILDFLAG(SAFE_BROWSING_DB_REMOTE)) && \
- !defined(OS_FUCHSIA)
+ !BUILDFLAG(IS_FUCHSIA)
// This can only be recorded for certain platforms, since the enum used for
// file types is provided by safe_browsing::FileTypePolicies.
if (danger_type == DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE) {
@@ -684,17 +684,17 @@ void RecordDownloadLaterEvent(DownloadLaterEvent event) {
base::UmaHistogramEnumeration("Download.Later.Events", event);
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
void RecordBackgroundTargetDeterminationResult(
BackgroudTargetDeterminationResultTypes type) {
base::UmaHistogramEnumeration(
"MobileDownload.Background.TargetDeterminationResult", type);
}
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
void RecordWinFileMoveError(int os_error) {
base::UmaHistogramSparse("Download.WinFileMoveError", os_error);
}
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
} // namespace download
diff --git a/chromium/components/download/internal/common/download_task_runner.cc b/chromium/components/download/internal/common/download_task_runner.cc
index 9488c03df05..4239d76efa3 100644
--- a/chromium/components/download/internal/common/download_task_runner.cc
+++ b/chromium/components/download/internal/common/download_task_runner.cc
@@ -15,7 +15,7 @@ namespace download {
namespace {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// On Windows, the download code dips into COM and the shell here and there,
// necessitating the use of a COM single-threaded apartment sequence.
base::LazyThreadPoolCOMSTATaskRunner g_download_task_runner =
diff --git a/chromium/components/download/internal/common/download_utils.cc b/chromium/components/download/internal/common/download_utils.cc
index b2d7bc26e98..e5eb9aa0206 100644
--- a/chromium/components/download/internal/common/download_utils.cc
+++ b/chromium/components/download/internal/common/download_utils.cc
@@ -30,10 +30,10 @@
#include "net/http/http_status_code.h"
#include "services/network/public/cpp/resource_request.h"
#include "url/origin.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "base/android/content_uri_utils.h"
#include "components/download/internal/common/android/download_collection_bridge.h"
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
namespace download {
@@ -57,7 +57,7 @@ const int kDefaultOverwrittenDownloadExpiredTimeInDays = 90;
// Default buffer size in bytes to write to the download file.
const int kDefaultDownloadFileBufferSize = 524288;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Default maximum length of a downloaded file name on Android.
const int kDefaultMaxFileNameLengthOnAndroid = 127;
@@ -76,7 +76,7 @@ DownloadItem::DownloadRenameResult RenameDownloadedFileForContentUri(
? DownloadItem::DownloadRenameResult::SUCCESS
: DownloadItem::DownloadRenameResult::FAILURE_NAME_INVALID;
}
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
void AppendExtraHeaders(net::HttpRequestHeaders* headers,
DownloadUrlParameters* params) {
@@ -481,7 +481,8 @@ DownloadDBEntry CreateDownloadDBEntryFromItem(const DownloadItemImpl& item) {
InProgressInfo in_progress_info;
in_progress_info.url_chain = item.GetUrlChain();
in_progress_info.referrer_url = item.GetReferrerUrl();
- in_progress_info.site_url = item.GetSiteUrl();
+ in_progress_info.serialized_embedder_download_data =
+ item.GetSerializedEmbedderDownloadData();
in_progress_info.tab_url = item.GetTabUrl();
in_progress_info.tab_referrer_url = item.GetTabReferrerUrl();
in_progress_info.fetch_error_body = item.fetch_error_body();
@@ -557,7 +558,7 @@ ResumeMode GetDownloadResumeMode(const GURL& url,
switch (reason) {
case DOWNLOAD_INTERRUPT_REASON_NETWORK_TIMEOUT:
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// If resume mode is USER_CONTINUE, android can still resume
// the download automatically if we didn't reach the auto resumption
// limit and the interruption was due to network related reasons.
@@ -647,7 +648,7 @@ bool IsDownloadDone(const GURL& url,
case DownloadItem::IN_PROGRESS:
return false;
case DownloadItem::COMPLETE:
- FALLTHROUGH;
+ [[fallthrough]];
case DownloadItem::CANCELLED:
return true;
case DownloadItem::INTERRUPTED:
@@ -661,7 +662,7 @@ bool IsDownloadDone(const GURL& url,
bool DeleteDownloadedFile(const base::FilePath& path) {
DCHECK(GetDownloadTaskRunner()->RunsTasksInCurrentSequence());
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
if (path.IsContentUri()) {
base::DeleteContentUri(path);
return true;
@@ -676,10 +677,10 @@ bool DeleteDownloadedFile(const base::FilePath& path) {
DownloadItem::DownloadRenameResult RenameDownloadedFile(
const base::FilePath& from_path,
const base::FilePath& display_name) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
if (from_path.IsContentUri())
return RenameDownloadedFileForContentUri(from_path, display_name);
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
auto to_path = base::FilePath(from_path.DirName()).Append(display_name);
if (!base::PathExists(from_path) ||
!base::DirectoryExists(from_path.DirName()))
diff --git a/chromium/components/download/internal/common/in_progress_download_manager.cc b/chromium/components/download/internal/common/in_progress_download_manager.cc
index 7127c63a924..58daaba8157 100644
--- a/chromium/components/download/internal/common/in_progress_download_manager.cc
+++ b/chromium/components/download/internal/common/in_progress_download_manager.cc
@@ -30,7 +30,7 @@
#include "services/network/public/mojom/url_response_head.mojom.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "base/android/build_info.h"
#include "components/download/internal/common/android/download_collection_bridge.h"
#include "components/download/public/common/download_path_reservation_tracker.h"
@@ -60,16 +60,16 @@ std::unique_ptr<DownloadItemImpl> CreateDownloadItemImpl(
delegate, entry.download_info->guid, entry.download_info->id,
in_progress_info->current_path, in_progress_info->target_path,
in_progress_info->url_chain, in_progress_info->referrer_url,
- in_progress_info->site_url, in_progress_info->tab_url,
- in_progress_info->tab_referrer_url, absl::nullopt,
- in_progress_info->mime_type, in_progress_info->original_mime_type,
- in_progress_info->start_time, in_progress_info->end_time,
- in_progress_info->etag, in_progress_info->last_modified,
- in_progress_info->received_bytes, in_progress_info->total_bytes,
- in_progress_info->auto_resume_count, in_progress_info->hash,
- in_progress_info->state, in_progress_info->danger_type,
- in_progress_info->interrupt_reason, in_progress_info->paused,
- in_progress_info->metered, false, base::Time(),
+ in_progress_info->serialized_embedder_download_data,
+ in_progress_info->tab_url, in_progress_info->tab_referrer_url,
+ absl::nullopt, in_progress_info->mime_type,
+ in_progress_info->original_mime_type, in_progress_info->start_time,
+ in_progress_info->end_time, in_progress_info->etag,
+ in_progress_info->last_modified, in_progress_info->received_bytes,
+ in_progress_info->total_bytes, in_progress_info->auto_resume_count,
+ in_progress_info->hash, in_progress_info->state,
+ in_progress_info->danger_type, in_progress_info->interrupt_reason,
+ in_progress_info->paused, in_progress_info->metered, false, base::Time(),
in_progress_info->transient, in_progress_info->received_slices,
in_progress_info->reroute_info, in_progress_info->download_schedule,
in_progress_info->range_request_from, in_progress_info->range_request_to,
@@ -94,7 +94,7 @@ void BeginResourceDownload(
const URLSecurityPolicy& url_security_policy,
bool is_new_download,
base::WeakPtr<InProgressDownloadManager> download_manager,
- const GURL& site_url,
+ const std::string& serialized_embedder_download_data,
const GURL& tab_url,
const GURL& tab_referrer_url,
mojo::PendingRemote<device::mojom::WakeLockProvider> wake_lock_provider,
@@ -106,9 +106,9 @@ void BeginResourceDownload(
download_manager, std::move(params), std::move(request),
network::SharedURLLoaderFactory::Create(
std::move(pending_url_loader_factory)),
- url_security_policy, site_url, tab_url, tab_referrer_url,
- is_new_download, false, std::move(wake_lock_provider),
- is_background_mode, main_task_runner)
+ url_security_policy, serialized_embedder_download_data, tab_url,
+ tab_referrer_url, is_new_download, false,
+ std::move(wake_lock_provider), is_background_mode, main_task_runner)
.release(),
base::OnTaskRunnerDeleter(base::ThreadTaskRunnerHandle::Get()));
@@ -121,7 +121,7 @@ void CreateDownloadHandlerForNavigation(
std::unique_ptr<network::ResourceRequest> resource_request,
int render_process_id,
int render_frame_id,
- const GURL& site_url,
+ const std::string& serialized_embedder_download_data,
const GURL& tab_url,
const GURL& tab_referrer_url,
std::vector<GURL> url_chain,
@@ -138,15 +138,16 @@ void CreateDownloadHandlerForNavigation(
ResourceDownloader::InterceptNavigationResponse(
download_manager, std::move(resource_request), render_process_id,
- render_frame_id, site_url, tab_url, tab_referrer_url,
- std::move(url_chain), std::move(cert_status), std::move(response_head),
- std::move(response_body), std::move(url_loader_client_endpoints),
+ render_frame_id, serialized_embedder_download_data, tab_url,
+ tab_referrer_url, std::move(url_chain), std::move(cert_status),
+ std::move(response_head), std::move(response_body),
+ std::move(url_loader_client_endpoints),
network::SharedURLLoaderFactory::Create(
std::move(pending_url_loader_factory)),
url_security_policy, std::move(wake_lock_provider), main_task_runner);
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
void OnDownloadDisplayNamesReturned(
DownloadCollectionBridge::GetDisplayNamesCallback callback,
const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner,
@@ -270,7 +271,8 @@ void InProgressDownloadManager::DownloadUrl(
// Start the new download, the download should be saved to the file path
// specifcied in the |params|.
BeginDownload(std::move(params), url_loader_factory_->Clone(),
- true /* is_new_download */, GURL() /* site_url */,
+ true /* is_new_download */,
+ std::string() /* serialized_embedder_download_data */,
GURL() /* tab_url */, GURL() /* tab_referral_url */);
}
@@ -310,7 +312,7 @@ void InProgressDownloadManager::BeginDownload(
std::unique_ptr<network::PendingSharedURLLoaderFactory>
pending_url_loader_factory,
bool is_new_download,
- const GURL& site_url,
+ const std::string& serialized_embedder_download_data,
const GURL& tab_url,
const GURL& tab_referrer_url) {
std::unique_ptr<network::ResourceRequest> request =
@@ -322,20 +324,20 @@ void InProgressDownloadManager::BeginDownload(
}
GetIOTaskRunner()->PostTask(
FROM_HERE,
- base::BindOnce(&BeginResourceDownload, std::move(params),
- std::move(request), std::move(pending_url_loader_factory),
- url_security_policy_, is_new_download,
- weak_factory_.GetWeakPtr(), site_url, tab_url,
- tab_referrer_url, std::move(wake_lock_provider),
- !delegate_ /* is_background_mode */,
- base::ThreadTaskRunnerHandle::Get()));
+ base::BindOnce(
+ &BeginResourceDownload, std::move(params), std::move(request),
+ std::move(pending_url_loader_factory), url_security_policy_,
+ is_new_download, weak_factory_.GetWeakPtr(),
+ serialized_embedder_download_data, tab_url, tab_referrer_url,
+ std::move(wake_lock_provider), !delegate_ /* is_background_mode */,
+ base::ThreadTaskRunnerHandle::Get()));
}
void InProgressDownloadManager::InterceptDownloadFromNavigation(
std::unique_ptr<network::ResourceRequest> resource_request,
int render_process_id,
int render_frame_id,
- const GURL& site_url,
+ const std::string& serialized_embedder_download_data,
const GURL& tab_url,
const GURL& tab_referrer_url,
std::vector<GURL> url_chain,
@@ -356,9 +358,10 @@ void InProgressDownloadManager::InterceptDownloadFromNavigation(
base::BindOnce(
&CreateDownloadHandlerForNavigation, weak_factory_.GetWeakPtr(),
std::move(resource_request), render_process_id, render_frame_id,
- site_url, tab_url, tab_referrer_url, std::move(url_chain),
- std::move(cert_status), std::move(response_head),
- std::move(response_body), std::move(url_loader_client_endpoints),
+ serialized_embedder_download_data, tab_url, tab_referrer_url,
+ std::move(url_chain), std::move(cert_status),
+ std::move(response_head), std::move(response_body),
+ std::move(url_loader_client_endpoints),
std::move(pending_url_loader_factory), url_security_policy_,
std::move(wake_lock_provider), base::ThreadTaskRunnerHandle::Get()));
}
@@ -396,7 +399,7 @@ void InProgressDownloadManager::DetermineDownloadTarget(
base::FilePath target_path = download->GetForcedFilePath().empty()
? download->GetTargetFilePath()
: download->GetForcedFilePath();
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
if (target_path.empty()) {
std::move(callback).Run(
target_path, DownloadItem::TARGET_DISPOSITION_OVERWRITE,
@@ -440,17 +443,17 @@ void InProgressDownloadManager::DetermineDownloadTarget(
download->GetDangerType(), download->GetMixedContentStatus(),
intermediate_path, download->GetDownloadSchedule(),
DOWNLOAD_INTERRUPT_REASON_NONE);
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
}
void InProgressDownloadManager::ResumeInterruptedDownload(
std::unique_ptr<DownloadUrlParameters> params,
- const GURL& site_url) {
+ const std::string& serialized_embedder_download_data) {
if (!url_loader_factory_)
return;
BeginDownload(std::move(params), url_loader_factory_->Clone(), false,
- site_url, GURL(), GURL());
+ serialized_embedder_download_data, GURL(), GURL());
}
bool InProgressDownloadManager::ShouldOpenDownload(
@@ -582,7 +585,7 @@ void InProgressDownloadManager::StartDownloadWithItem(
void InProgressDownloadManager::OnDBInitialized(
bool success,
std::unique_ptr<std::vector<DownloadDBEntry>> entries) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Retrieve display names for all downloads from media store if needed.
if (base::android::BuildInfo::GetInstance()->sdk_int() >=
base::android::SDK_VERSION_Q) {
@@ -620,7 +623,7 @@ void InProgressDownloadManager::OnDownloadNamesRetrieved(
num_duplicates++;
continue;
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
const base::FilePath& path = item->GetTargetFilePath();
if (path.IsContentUri()) {
base::FilePath display_name = GetDownloadDisplayName(path);
@@ -651,7 +654,7 @@ InProgressDownloadManager::TakeInProgressDownloads() {
base::FilePath InProgressDownloadManager::GetDownloadDisplayName(
const base::FilePath& path) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
if (!display_names_)
return base::FilePath();
auto iter = display_names_->find(path.value());
diff --git a/chromium/components/download/internal/common/resource_downloader.cc b/chromium/components/download/internal/common/resource_downloader.cc
index 1ce01c100c0..af7f2110ce4 100644
--- a/chromium/components/download/internal/common/resource_downloader.cc
+++ b/chromium/components/download/internal/common/resource_downloader.cc
@@ -30,7 +30,8 @@ class URLLoaderStatusMonitor : public network::mojom::URLLoaderClient {
~URLLoaderStatusMonitor() override = default;
// network::mojom::URLLoaderClient
- void OnReceiveResponse(network::mojom::URLResponseHeadPtr head) override {}
+ void OnReceiveResponse(network::mojom::URLResponseHeadPtr head,
+ mojo::ScopedDataPipeConsumerHandle body) override {}
void OnReceiveRedirect(const net::RedirectInfo& redirect_info,
network::mojom::URLResponseHeadPtr head) override {}
void OnUploadProgress(int64_t current_position,
@@ -62,7 +63,7 @@ std::unique_ptr<ResourceDownloader> ResourceDownloader::BeginDownload(
std::unique_ptr<network::ResourceRequest> request,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
const URLSecurityPolicy& url_security_policy,
- const GURL& site_url,
+ const std::string& serialized_embedder_download_data,
const GURL& tab_url,
const GURL& tab_referrer_url,
bool is_new_download,
@@ -72,8 +73,8 @@ std::unique_ptr<ResourceDownloader> ResourceDownloader::BeginDownload(
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) {
auto downloader = std::make_unique<ResourceDownloader>(
delegate, std::move(request), params->render_process_host_id(),
- params->render_frame_host_routing_id(), site_url, tab_url,
- tab_referrer_url, is_new_download, task_runner,
+ params->render_frame_host_routing_id(), serialized_embedder_download_data,
+ tab_url, tab_referrer_url, is_new_download, task_runner,
std::move(url_loader_factory), url_security_policy,
std::move(wake_lock_provider));
@@ -87,7 +88,7 @@ void ResourceDownloader::InterceptNavigationResponse(
std::unique_ptr<network::ResourceRequest> resource_request,
int render_process_id,
int render_frame_id,
- const GURL& site_url,
+ const std::string& serialized_embedder_download_data,
const GURL& tab_url,
const GURL& tab_referrer_url,
std::vector<GURL> url_chain,
@@ -101,8 +102,8 @@ void ResourceDownloader::InterceptNavigationResponse(
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) {
auto downloader = std::make_unique<ResourceDownloader>(
delegate, std::move(resource_request), render_process_id, render_frame_id,
- site_url, tab_url, tab_referrer_url, true, task_runner,
- std::move(url_loader_factory), url_security_policy,
+ serialized_embedder_download_data, tab_url, tab_referrer_url, true,
+ task_runner, std::move(url_loader_factory), url_security_policy,
std::move(wake_lock_provider));
ResourceDownloader* raw_downloader = downloader.get();
task_runner->PostTask(
@@ -122,7 +123,7 @@ ResourceDownloader::ResourceDownloader(
std::unique_ptr<network::ResourceRequest> resource_request,
int render_process_id,
int render_frame_id,
- const GURL& site_url,
+ const std::string& serialized_embedder_download_data,
const GURL& tab_url,
const GURL& tab_referrer_url,
bool is_new_download,
@@ -135,7 +136,7 @@ ResourceDownloader::ResourceDownloader(
is_new_download_(is_new_download),
render_process_id_(render_process_id),
render_frame_id_(render_frame_id),
- site_url_(site_url),
+ serialized_embedder_download_data_(serialized_embedder_download_data),
tab_url_(tab_url),
tab_referrer_url_(tab_referrer_url),
delegate_task_runner_(task_runner),
@@ -171,6 +172,7 @@ void ResourceDownloader::Start(
download_url_parameters->request_headers(),
download_url_parameters->request_origin(),
download_url_parameters->download_source(),
+ download_url_parameters->require_safety_checks(),
std::vector<GURL>(1, resource_request_->url), is_background_mode);
mojo::PendingRemote<network::mojom::URLLoaderClient> url_loader_client_remote;
@@ -209,13 +211,14 @@ void ResourceDownloader::InterceptResponse(
false, /* fetch_error_body */
network::mojom::RedirectMode::kFollow,
download::DownloadUrlParameters::RequestHeadersType(),
- std::string(), /* request_origin */
- download::DownloadSource::NAVIGATION, std::move(url_chain),
- false /* is_background_mode */);
+ std::string(), /* request_origin */
+ download::DownloadSource::NAVIGATION, true, /* require_safety_checks */
+ std::move(url_chain), false /* is_background_mode */);
// Simulate on the new URLLoaderClient calls that happened on the old client.
response_head->cert_status = cert_status;
- url_loader_client_->OnReceiveResponse(std::move(response_head));
+ url_loader_client_->OnReceiveResponse(std::move(response_head),
+ mojo::ScopedDataPipeConsumerHandle());
url_loader_client_->OnStartLoadingResponseBody(std::move(response_body));
// Bind the new client.
@@ -229,7 +232,8 @@ void ResourceDownloader::OnResponseStarted(
mojom::DownloadStreamHandlePtr stream_handle) {
download_create_info->is_new_download = is_new_download_;
download_create_info->guid = guid_;
- download_create_info->site_url = site_url_;
+ download_create_info->serialized_embedder_download_data =
+ serialized_embedder_download_data_;
download_create_info->tab_url = tab_url_;
download_create_info->tab_referrer_url = tab_referrer_url_;
download_create_info->render_process_id = render_process_id_;
diff --git a/chromium/components/download/internal/common/resource_downloader.h b/chromium/components/download/internal/common/resource_downloader.h
index 394c343f4f6..6747e74505a 100644
--- a/chromium/components/download/internal/common/resource_downloader.h
+++ b/chromium/components/download/internal/common/resource_downloader.h
@@ -32,7 +32,7 @@ class COMPONENTS_DOWNLOAD_EXPORT ResourceDownloader
std::unique_ptr<network::ResourceRequest> request,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
const URLSecurityPolicy& url_security_policy,
- const GURL& site_url,
+ const std::string& serialized_embedder_download_data,
const GURL& tab_url,
const GURL& tab_referrer_url,
bool is_new_download,
@@ -49,7 +49,7 @@ class COMPONENTS_DOWNLOAD_EXPORT ResourceDownloader
std::unique_ptr<network::ResourceRequest> resource_request,
int render_process_id,
int render_frame_id,
- const GURL& site_url,
+ const std::string& serialized_embedder_download_data,
const GURL& tab_url,
const GURL& tab_referrer_url,
std::vector<GURL> url_chain,
@@ -67,7 +67,7 @@ class COMPONENTS_DOWNLOAD_EXPORT ResourceDownloader
std::unique_ptr<network::ResourceRequest> resource_request,
int render_process_id,
int render_frame_id,
- const GURL& site_url,
+ const std::string& serialized_embedder_download_data,
const GURL& tab_url,
const GURL& tab_referrer_url,
bool is_new_download,
@@ -143,8 +143,9 @@ class COMPONENTS_DOWNLOAD_EXPORT ResourceDownloader
int render_process_id_;
int render_frame_id_;
- // Site URL for the site instance that initiated the download.
- GURL site_url_;
+ // Serialized embedder data download for the site instance that initiated the
+ // download.
+ std::string serialized_embedder_download_data_;
// The URL of the tab that started us.
GURL tab_url_;
diff --git a/chromium/components/download/internal/common/url_download_handler_factory.cc b/chromium/components/download/internal/common/url_download_handler_factory.cc
index 424253e6c5c..955df7130dc 100644
--- a/chromium/components/download/internal/common/url_download_handler_factory.cc
+++ b/chromium/components/download/internal/common/url_download_handler_factory.cc
@@ -4,7 +4,6 @@
#include "components/download/public/common/url_download_handler_factory.h"
-#include "base/no_destructor.h"
#include "base/synchronization/lock.h"
#include "components/download/internal/common/resource_downloader.h"
#include "components/download/public/common/download_item.h"
@@ -29,8 +28,8 @@ UrlDownloadHandlerFactory::Create(
return UrlDownloadHandler::UniqueUrlDownloadHandlerPtr(
download::ResourceDownloader::BeginDownload(
delegate, std::move(params), std::move(request),
- std::move(url_loader_factory), url_security_policy, GURL(), GURL(),
- GURL(), true, true, std::move(wake_lock_provider),
+ std::move(url_loader_factory), url_security_policy, std::string(),
+ GURL(), GURL(), true, true, std::move(wake_lock_provider),
false /* is_background_mode */, task_runner)
.release(),
base::OnTaskRunnerDeleter(base::ThreadTaskRunnerHandle::Get()));
diff --git a/chromium/components/download/public/background_service/download_metadata.h b/chromium/components/download/public/background_service/download_metadata.h
index 1f313cc4fc9..b2db90238c8 100644
--- a/chromium/components/download/public/background_service/download_metadata.h
+++ b/chromium/components/download/public/background_service/download_metadata.h
@@ -14,7 +14,7 @@
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "url/gurl.h"
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
#include "storage/browser/blob/blob_data_handle.h"
#endif
@@ -26,7 +26,7 @@ struct CompletionInfo {
// to retrieve data.
base::FilePath path;
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
// The blob data handle that contains download data.
// Will be available after the download is completed in incognito mode.
absl::optional<storage::BlobDataHandle> blob_handle;
diff --git a/chromium/components/download/public/common/BUILD.gn b/chromium/components/download/public/common/BUILD.gn
index f79fbdc8e8d..b1881d51cc3 100644
--- a/chromium/components/download/public/common/BUILD.gn
+++ b/chromium/components/download/public/common/BUILD.gn
@@ -64,8 +64,6 @@ component("public") {
"resume_mode.h",
"simple_download_manager.h",
"simple_download_manager_coordinator.h",
- "storage_partition_config.cc",
- "storage_partition_config.h",
"stream_handle_input_stream.h",
"url_download_handler_factory.h",
"url_download_request_handle.h",
@@ -180,7 +178,6 @@ source_set("unit_tests") {
sources = [
"auto_resumption_handler_unittest.cc",
"download_schedule_unittest.cc",
- "storage_partition_config_unittest.cc",
]
deps = [
diff --git a/chromium/components/download/public/common/base_file.h b/chromium/components/download/public/common/base_file.h
index c577ee8d2ae..3d747c981bf 100644
--- a/chromium/components/download/public/common/base_file.h
+++ b/chromium/components/download/public/common/base_file.h
@@ -172,7 +172,7 @@ class COMPONENTS_DOWNLOAD_EXPORT BaseFile {
mojo::PendingRemote<quarantine::mojom::Quarantine> remote_quarantine,
OnAnnotationDoneCallback on_annotation_done_callback);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Publishes the intermediate download to public download collection.
DownloadInterruptReason PublishDownload();
#endif
diff --git a/chromium/components/download/public/common/download_create_info.h b/chromium/components/download/public/common/download_create_info.h
index 36c85afc292..ab845bf75d6 100644
--- a/chromium/components/download/public/common/download_create_info.h
+++ b/chromium/components/download/public/common/download_create_info.h
@@ -70,8 +70,9 @@ struct COMPONENTS_DOWNLOAD_EXPORT DownloadCreateInfo {
GURL referrer_url;
net::ReferrerPolicy referrer_policy;
- // Site URL for the site instance that initiated the download.
- GURL site_url;
+ // The serialized embedder download data for the site instance that initiated
+ // the download.
+ std::string serialized_embedder_download_data;
// The URL of the tab that started us.
GURL tab_url;
@@ -101,6 +102,9 @@ struct COMPONENTS_DOWNLOAD_EXPORT DownloadCreateInfo {
// short-lived and is not shown in the UI.
bool transient;
+ // Whether this download requires safety checks.
+ bool require_safety_checks;
+
absl::optional<ui::PageTransition> transition_type;
// The HTTP response headers. This contains a nullptr when the response has
diff --git a/chromium/components/download/public/common/download_features.cc b/chromium/components/download/public/common/download_features.cc
index 5a8eda50fa6..9610df2af6c 100644
--- a/chromium/components/download/public/common/download_features.cc
+++ b/chromium/components/download/public/common/download_features.cc
@@ -14,7 +14,7 @@ const base::Feature kUseDownloadOfflineContentProvider{
const base::Feature kDownloadAutoResumptionNative {
"DownloadsAutoResumptionNative",
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
base::FEATURE_ENABLED_BY_DEFAULT
#else
base::FEATURE_DISABLED_BY_DEFAULT
@@ -23,7 +23,7 @@ const base::Feature kDownloadAutoResumptionNative {
const base::Feature kParallelDownloading {
"ParallelDownloading",
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
base::FEATURE_ENABLED_BY_DEFAULT
#else
base::FEATURE_DISABLED_BY_DEFAULT
@@ -33,7 +33,7 @@ const base::Feature kParallelDownloading {
const base::Feature kDownloadLater{"DownloadLater",
base::FEATURE_DISABLED_BY_DEFAULT};
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
const base::Feature kSmartSuggestionForLargeDownloads{
"SmartSuggestionForLargeDownloads", base::FEATURE_DISABLED_BY_DEFAULT};
@@ -47,7 +47,7 @@ const base::Feature kUseInProgressDownloadManagerForDownloadService{
const base::Feature kAllowDownloadResumptionWithoutStrongValidators{
"AllowDownloadResumptionWithoutStrongValidators",
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
base::FEATURE_ENABLED_BY_DEFAULT
#else
base::FEATURE_DISABLED_BY_DEFAULT
@@ -76,7 +76,7 @@ const base::Feature kIncognitoDownloadsWarning{
"IncognitoDownloadsWarning", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kDownloadRange{"DownloadRange",
- base::FEATURE_DISABLED_BY_DEFAULT};
+ base::FEATURE_ENABLED_BY_DEFAULT};
} // namespace features
diff --git a/chromium/components/download/public/common/download_features.h b/chromium/components/download/public/common/download_features.h
index 0a98283b87a..72388eedc0f 100644
--- a/chromium/components/download/public/common/download_features.h
+++ b/chromium/components/download/public/common/download_features.h
@@ -34,7 +34,7 @@ COMPONENTS_DOWNLOAD_EXPORT extern const base::Feature kParallelDownloading;
// Whether to enable download later feature.
COMPONENTS_DOWNLOAD_EXPORT extern const base::Feature kDownloadLater;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Whether download expiration date will be refreshed on resumption.
COMPONENTS_DOWNLOAD_EXPORT extern const base::Feature kRefreshExpirationDate;
diff --git a/chromium/components/download/public/common/download_file.h b/chromium/components/download/public/common/download_file.h
index a10a77ff667..e6cb459ee19 100644
--- a/chromium/components/download/public/common/download_file.h
+++ b/chromium/components/download/public/common/download_file.h
@@ -114,7 +114,7 @@ class COMPONENTS_DOWNLOAD_EXPORT DownloadFile {
virtual void Pause() = 0;
virtual void Resume() = 0;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Renames the download file to an intermediate URI. If current_path is a
// content URI, it will be used for the renaming. Otherwise, A new
// intermediate URI will be created to write the download file. Once
@@ -132,7 +132,7 @@ class COMPONENTS_DOWNLOAD_EXPORT DownloadFile {
// Returns the suggested file path from the system.
virtual base::FilePath GetDisplayName() = 0;
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
};
} // namespace download
diff --git a/chromium/components/download/public/common/download_file_impl.h b/chromium/components/download/public/common/download_file_impl.h
index c0b63332324..d7932701275 100644
--- a/chromium/components/download/public/common/download_file_impl.h
+++ b/chromium/components/download/public/common/download_file_impl.h
@@ -79,7 +79,7 @@ class COMPONENTS_DOWNLOAD_EXPORT DownloadFileImpl : public DownloadFile {
void Pause() override;
void Resume() override;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
void RenameToIntermediateUri(const GURL& original_url,
const GURL& referrer_url,
const base::FilePath& file_name,
@@ -88,7 +88,7 @@ class COMPONENTS_DOWNLOAD_EXPORT DownloadFileImpl : public DownloadFile {
RenameCompletionCallback callback) override;
void PublishDownload(RenameCompletionCallback callback) override;
base::FilePath GetDisplayName() override;
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
// Wrapper of a ByteStreamReader or ScopedDataPipeConsumerHandle, and the meta
// data needed to write to a slice of the target file.
@@ -387,9 +387,9 @@ class COMPONENTS_DOWNLOAD_EXPORT DownloadFileImpl : public DownloadFile {
// TaskRunner this object lives on after initialization.
scoped_refptr<base::SequencedTaskRunner> task_runner_;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
base::FilePath display_name_;
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
SEQUENCE_CHECKER(sequence_checker_);
diff --git a/chromium/components/download/public/common/download_item.h b/chromium/components/download/public/common/download_item.h
index b59a486d4c5..f7b65b6f442 100644
--- a/chromium/components/download/public/common/download_item.h
+++ b/chromium/components/download/public/common/download_item.h
@@ -299,10 +299,10 @@ class COMPONENTS_DOWNLOAD_EXPORT DownloadItem : public base::SupportsUserData {
// URL of document that is considered the referrer for the original URL.
virtual const GURL& GetReferrerUrl() const = 0;
- // Site instance URL. Used to locate the correct storage partition during
- // subsequent browser sessions. This may be different from all of
- // GetOriginalUrl(), GetURL() and GetReferrerUrl().
- virtual const GURL& GetSiteUrl() const = 0;
+ // The serialized EmbedderDownloadData string. This is used by the embedder
+ // for placing extra download data, such as the appropriate storage partition
+ // for this download.
+ virtual const std::string& GetSerializedEmbedderDownloadData() const = 0;
// URL of the top level frame at the time the download was initiated.
virtual const GURL& GetTabUrl() const = 0;
@@ -531,6 +531,10 @@ class COMPONENTS_DOWNLOAD_EXPORT DownloadItem : public base::SupportsUserData {
// for target file path determination.
virtual bool IsTransient() const = 0;
+ // Returns whether the download requires safety checks. Only downloads
+ // triggered by Chrome itself are excluded from safety checks.
+ virtual bool RequireSafetyChecks() const = 0;
+
// Returns whether the download item corresponds to a parallel download. This
// usually means parallel download has been enabled and the download job is
// parallelizable.
diff --git a/chromium/components/download/public/common/download_item_factory.h b/chromium/components/download/public/common/download_item_factory.h
index d50e2b3f792..7de423c77fe 100644
--- a/chromium/components/download/public/common/download_item_factory.h
+++ b/chromium/components/download/public/common/download_item_factory.h
@@ -45,7 +45,7 @@ class COMPONENTS_DOWNLOAD_EXPORT DownloadItemFactory {
const base::FilePath& target_path,
const std::vector<GURL>& url_chain,
const GURL& referrer_url,
- const GURL& site_url,
+ const std::string& serialized_embedder_data,
const GURL& tab_url,
const GURL& tab_refererr_url,
const absl::optional<url::Origin>& initiator_origin,
diff --git a/chromium/components/download/public/common/download_item_impl.h b/chromium/components/download/public/common/download_item_impl.h
index 8b9118a9ca2..88a52cb2bbf 100644
--- a/chromium/components/download/public/common/download_item_impl.h
+++ b/chromium/components/download/public/common/download_item_impl.h
@@ -53,7 +53,7 @@ class COMPONENTS_DOWNLOAD_EXPORT DownloadItemImpl
struct COMPONENTS_DOWNLOAD_EXPORT RequestInfo {
RequestInfo(const std::vector<GURL>& url_chain,
const GURL& referrer_url,
- const GURL& site_url,
+ const std::string& serialized_embedder_download_data,
const GURL& tab_url,
const GURL& tab_referrer_url,
const absl::optional<url::Origin>& request_initiator,
@@ -78,8 +78,11 @@ class COMPONENTS_DOWNLOAD_EXPORT DownloadItemImpl
// The URL of the page that initiated the download.
GURL referrer_url;
- // Site URL for the site instance that initiated this download.
- GURL site_url;
+ // The serialized embedder download data for the site instance that
+ // initiated this download. The embedder can use this field to add
+ // additional information about the download, such as the
+ // StoragePartitionConfig that pertains to it.
+ std::string serialized_embedder_download_data;
// The URL of the tab that initiated the download.
GURL tab_url;
@@ -191,7 +194,7 @@ class COMPONENTS_DOWNLOAD_EXPORT DownloadItemImpl
const base::FilePath& target_path,
const std::vector<GURL>& url_chain,
const GURL& referrer_url,
- const GURL& site_url,
+ const std::string& serialized_embedder_download_data,
const GURL& tab_url,
const GURL& tab_referrer_url,
const absl::optional<url::Origin>& request_initiator,
@@ -272,7 +275,7 @@ class COMPONENTS_DOWNLOAD_EXPORT DownloadItemImpl
const std::vector<GURL>& GetUrlChain() const override;
const GURL& GetOriginalUrl() const override;
const GURL& GetReferrerUrl() const override;
- const GURL& GetSiteUrl() const override;
+ const std::string& GetSerializedEmbedderDownloadData() const override;
const GURL& GetTabUrl() const override;
const GURL& GetTabReferrerUrl() const override;
const absl::optional<url::Origin>& GetRequestInitiator() const override;
@@ -325,6 +328,7 @@ class COMPONENTS_DOWNLOAD_EXPORT DownloadItemImpl
bool GetOpened() const override;
base::Time GetLastAccessTime() const override;
bool IsTransient() const override;
+ bool RequireSafetyChecks() const override;
bool IsParallelDownload() const override;
DownloadCreationType GetDownloadCreationType() const override;
const absl::optional<DownloadSchedule>& GetDownloadSchedule() const override;
@@ -832,6 +836,9 @@ class COMPONENTS_DOWNLOAD_EXPORT DownloadItemImpl
// Whether the download item should be transient and not shown in the UI.
bool transient_ = false;
+ // Whether the download requires safe browsing check.
+ bool require_safety_checks_ = true;
+
// Did the delegate delay calling Complete on this download?
bool delegate_delayed_complete_ = false;
diff --git a/chromium/components/download/public/common/download_item_impl_delegate.h b/chromium/components/download/public/common/download_item_impl_delegate.h
index 3f7124e36c9..87da60ee9fb 100644
--- a/chromium/components/download/public/common/download_item_impl_delegate.h
+++ b/chromium/components/download/public/common/download_item_impl_delegate.h
@@ -96,7 +96,7 @@ class COMPONENTS_DOWNLOAD_EXPORT DownloadItemImplDelegate {
// Called when an interrupted download is resumed.
virtual void ResumeInterruptedDownload(
std::unique_ptr<DownloadUrlParameters> params,
- const GURL& site_url);
+ const std::string& serialized_embedder_data);
// Update the persistent store with our information.
virtual void UpdatePersistence(DownloadItemImpl* download);
diff --git a/chromium/components/download/public/common/download_response_handler.h b/chromium/components/download/public/common/download_response_handler.h
index 76bc7af8f04..d56dad69b1a 100644
--- a/chromium/components/download/public/common/download_response_handler.h
+++ b/chromium/components/download/public/common/download_response_handler.h
@@ -55,6 +55,7 @@ class COMPONENTS_DOWNLOAD_EXPORT DownloadResponseHandler
const DownloadUrlParameters::RequestHeadersType& request_headers,
const std::string& request_origin,
DownloadSource download_source,
+ bool require_safety_checks,
std::vector<GURL> url_chain,
bool is_background_mode);
@@ -65,7 +66,8 @@ class COMPONENTS_DOWNLOAD_EXPORT DownloadResponseHandler
// network::mojom::URLLoaderClient
void OnReceiveEarlyHints(network::mojom::EarlyHintsPtr early_hints) override;
- void OnReceiveResponse(network::mojom::URLResponseHeadPtr head) override;
+ void OnReceiveResponse(network::mojom::URLResponseHeadPtr head,
+ mojo::ScopedDataPipeConsumerHandle body) override;
void OnReceiveRedirect(const net::RedirectInfo& redirect_info,
network::mojom::URLResponseHeadPtr head) override;
void OnUploadProgress(int64_t current_position,
@@ -110,6 +112,7 @@ class COMPONENTS_DOWNLOAD_EXPORT DownloadResponseHandler
absl::optional<net::IsolationInfo> isolation_info_;
bool is_partial_request_;
bool completed_;
+ bool require_safety_checks_;
// The abort reason if this class decides to block the download.
DownloadInterruptReason abort_reason_;
diff --git a/chromium/components/download/public/common/download_stats.h b/chromium/components/download/public/common/download_stats.h
index abd47345c25..80d432369db 100644
--- a/chromium/components/download/public/common/download_stats.h
+++ b/chromium/components/download/public/common/download_stats.h
@@ -370,7 +370,7 @@ COMPONENTS_DOWNLOAD_EXPORT void RecordParallelRequestCreationFailure(
COMPONENTS_DOWNLOAD_EXPORT void RecordDownloadLaterEvent(
DownloadLaterEvent event);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
enum class BackgroudTargetDeterminationResultTypes {
// Target determination succeeded.
kSuccess = 0,
@@ -388,12 +388,12 @@ enum class BackgroudTargetDeterminationResultTypes {
// reduced mode.
COMPONENTS_DOWNLOAD_EXPORT void RecordBackgroundTargetDeterminationResult(
BackgroudTargetDeterminationResultTypes type);
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// Records the OS error code when moving a file on Windows.
COMPONENTS_DOWNLOAD_EXPORT void RecordWinFileMoveError(int os_error);
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
} // namespace download
#endif // COMPONENTS_DOWNLOAD_PUBLIC_COMMON_DOWNLOAD_STATS_H_
diff --git a/chromium/components/download/public/common/in_progress_download_manager.h b/chromium/components/download/public/common/in_progress_download_manager.h
index 1e5b4fe70c8..eab50360526 100644
--- a/chromium/components/download/public/common/in_progress_download_manager.h
+++ b/chromium/components/download/public/common/in_progress_download_manager.h
@@ -111,7 +111,7 @@ class COMPONENTS_DOWNLOAD_EXPORT InProgressDownloadManager
std::unique_ptr<network::PendingSharedURLLoaderFactory>
pending_url_loader_factory,
bool is_new_download,
- const GURL& site_url,
+ const std::string& serialized_embedder_download_data,
const GURL& tab_url,
const GURL& tab_referrer_url);
@@ -120,7 +120,7 @@ class COMPONENTS_DOWNLOAD_EXPORT InProgressDownloadManager
std::unique_ptr<network::ResourceRequest> resource_request,
int render_process_id,
int render_frame_id,
- const GURL& site_url,
+ const std::string& serialized_embedder_download_data,
const GURL& tab_url,
const GURL& tab_referrer_url,
std::vector<GURL> url_chain,
@@ -144,8 +144,9 @@ class COMPONENTS_DOWNLOAD_EXPORT InProgressDownloadManager
// DownloadItemImplDelegate implementations.
void DetermineDownloadTarget(DownloadItemImpl* download,
DownloadTargetCallback callback) override;
- void ResumeInterruptedDownload(std::unique_ptr<DownloadUrlParameters> params,
- const GURL& site_url) override;
+ void ResumeInterruptedDownload(
+ std::unique_ptr<DownloadUrlParameters> params,
+ const std::string& serialized_embedder_download_data) override;
bool ShouldOpenDownload(DownloadItemImpl* item,
ShouldOpenDownloadCallback callback) override;
void ReportBytesWasted(DownloadItemImpl* download) override;
@@ -157,7 +158,7 @@ class COMPONENTS_DOWNLOAD_EXPORT InProgressDownloadManager
download_start_observer_ = observer;
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Callback to generate an intermediate file path from the given target file
// path;
using IntermediatePathCallback =
@@ -275,7 +276,7 @@ class COMPONENTS_DOWNLOAD_EXPORT InProgressDownloadManager
// callback to check if an origin is secure.
IsOriginSecureCallback is_origin_secure_cb_;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Callback to generate the intermediate file path.
IntermediatePathCallback intermediate_path_cb_;
diff --git a/chromium/components/download/public/common/mock_download_file.h b/chromium/components/download/public/common/mock_download_file.h
index 17c9711e89e..81ca131356d 100644
--- a/chromium/components/download/public/common/mock_download_file.h
+++ b/chromium/components/download/public/common/mock_download_file.h
@@ -69,7 +69,7 @@ class MockDownloadFile : public DownloadFile {
MOCK_CONST_METHOD0(DebugString, std::string());
MOCK_METHOD0(Pause, void());
MOCK_METHOD0(Resume, void());
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
MOCK_METHOD6(RenameToIntermediateUri,
void(const GURL& original_url,
const GURL& referrer_url,
@@ -79,7 +79,7 @@ class MockDownloadFile : public DownloadFile {
RenameCompletionCallback callback));
MOCK_METHOD1(PublishDownload, void(RenameCompletionCallback callback));
MOCK_METHOD0(GetDisplayName, base::FilePath());
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
};
} // namespace download
diff --git a/chromium/components/download/public/common/mock_download_item.h b/chromium/components/download/public/common/mock_download_item.h
index c0b0357eeca..4e45bf86ab8 100644
--- a/chromium/components/download/public/common/mock_download_item.h
+++ b/chromium/components/download/public/common/mock_download_item.h
@@ -69,7 +69,7 @@ class MockDownloadItem : public DownloadItem {
MOCK_CONST_METHOD0(GetUrlChain, const std::vector<GURL>&());
MOCK_CONST_METHOD0(GetOriginalUrl, const GURL&());
MOCK_CONST_METHOD0(GetReferrerUrl, const GURL&());
- MOCK_CONST_METHOD0(GetSiteUrl, const GURL&());
+ MOCK_CONST_METHOD0(GetSerializedEmbedderDownloadData, const std::string&());
MOCK_CONST_METHOD0(GetTabUrl, const GURL&());
MOCK_CONST_METHOD0(GetTabReferrerUrl, const GURL&());
MOCK_CONST_METHOD0(GetRequestInitiator, const absl::optional<url::Origin>&());
@@ -130,6 +130,7 @@ class MockDownloadItem : public DownloadItem {
MOCK_CONST_METHOD0(GetOpened, bool());
MOCK_CONST_METHOD0(GetLastAccessTime, base::Time());
MOCK_CONST_METHOD0(IsTransient, bool());
+ MOCK_CONST_METHOD0(RequireSafetyChecks, bool());
MOCK_CONST_METHOD0(IsParallelDownload, bool());
MOCK_CONST_METHOD0(GetDownloadCreationType, DownloadCreationType());
MOCK_CONST_METHOD0(GetDownloadSchedule,
diff --git a/chromium/components/download/public/common/mock_download_item_impl.cc b/chromium/components/download/public/common/mock_download_item_impl.cc
index 08aaf11e86b..f929a37fc05 100644
--- a/chromium/components/download/public/common/mock_download_item_impl.cc
+++ b/chromium/components/download/public/common/mock_download_item_impl.cc
@@ -14,7 +14,7 @@ MockDownloadItemImpl::MockDownloadItemImpl(DownloadItemImplDelegate* delegate)
base::FilePath(),
std::vector<GURL>(),
GURL(),
- GURL(),
+ std::string(),
GURL(),
GURL(),
url::Origin(),
diff --git a/chromium/components/download/public/common/storage_partition_config.cc b/chromium/components/download/public/common/storage_partition_config.cc
deleted file mode 100644
index 293e6f1aa92..00000000000
--- a/chromium/components/download/public/common/storage_partition_config.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright 2021 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.
-
-#include "components/download/public/common/storage_partition_config.h"
-
-#include "base/strings/string_split.h"
-
-namespace download {
-
-namespace {
-static const char* kDelimiter = "|";
-static const char* kInMemorySetValue = "in_memory";
-} // namespace
-
-StoragePartitionConfig::StoragePartitionConfig(
- const std::string& partition_domain,
- const std::string& partition_name,
- bool in_memory)
- : partition_domain_(partition_domain),
- partition_name_(partition_name),
- in_memory_(in_memory) {
- DCHECK(partition_domain_.find(kDelimiter) == std::string::npos);
- DCHECK(partition_name.find(kDelimiter) == std::string::npos);
-}
-
-bool StoragePartitionConfig::operator==(
- const StoragePartitionConfig& rhs) const {
- return partition_domain_ == rhs.partition_domain_ &&
- partition_name_ == rhs.partition_name_ && in_memory_ == rhs.in_memory_;
-}
-
-bool StoragePartitionConfig::operator!=(
- const StoragePartitionConfig& rhs) const {
- return !(*this == rhs);
-}
-
-std::string StoragePartitionConfig::SerializeToString() {
- return partition_domain_ + kDelimiter + partition_name_ + kDelimiter +
- (in_memory_ ? kInMemorySetValue : "");
-}
-
-// static
-StoragePartitionConfig StoragePartitionConfig::DeserializeFromString(
- const std::string& str) {
- std::vector<std::string> fields = base::SplitString(
- str, kDelimiter, base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
-
- if (fields.size() != 3)
- return StoragePartitionConfig();
-
- std::string partition_domain = fields[0];
- std::string partition_name = fields[1];
- bool in_memory = fields[2] == kInMemorySetValue;
-
- return StoragePartitionConfig(partition_domain, partition_name, in_memory);
-}
-
-} // namespace download
diff --git a/chromium/components/download/public/common/storage_partition_config.h b/chromium/components/download/public/common/storage_partition_config.h
deleted file mode 100644
index b944a282b89..00000000000
--- a/chromium/components/download/public/common/storage_partition_config.h
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright 2021 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.
-
-#ifndef COMPONENTS_DOWNLOAD_PUBLIC_COMMON_STORAGE_PARTITION_CONFIG_H_
-#define COMPONENTS_DOWNLOAD_PUBLIC_COMMON_STORAGE_PARTITION_CONFIG_H_
-
-#include <string>
-
-#include "components/download/public/common/download_export.h"
-
-namespace download {
-
-// This class represents a content::StoragePartitionConfig that can be within
-// components/download. It contains methods for serializing the
-// StoragePartitionConfig for storage in the downloads table and to deserialize
-// from storage back into this class. It also enables the configs to be compared
-// to each other.
-class COMPONENTS_DOWNLOAD_EXPORT StoragePartitionConfig {
- public:
- StoragePartitionConfig() = default;
- StoragePartitionConfig(const std::string& partition_domain,
- const std::string& partition_name,
- bool in_memory);
-
- StoragePartitionConfig(const StoragePartitionConfig& rhs) = default;
- StoragePartitionConfig& operator=(const StoragePartitionConfig& rhs) =
- default;
-
- bool operator==(const StoragePartitionConfig& rhs) const;
- bool operator!=(const StoragePartitionConfig& rhs) const;
-
- // Serialize and Deserialize methods to store the StoragePartitionConfig in
- // the DownloadDatabase.
- std::string SerializeToString();
- static StoragePartitionConfig DeserializeFromString(const std::string& str);
-
- std::string partition_domain() const { return partition_domain_; }
- std::string partition_name() const { return partition_name_; }
- bool in_memory() const { return in_memory_; }
-
- private:
- std::string partition_domain_;
- std::string partition_name_;
- bool in_memory_;
-};
-
-} // namespace download
-
-#endif // COMPONENTS_DOWNLOAD_PUBLIC_COMMON_STORAGE_PARTITION_CONFIG_H_
diff --git a/chromium/components/download/public/common/storage_partition_config_unittest.cc b/chromium/components/download/public/common/storage_partition_config_unittest.cc
deleted file mode 100644
index 07262685773..00000000000
--- a/chromium/components/download/public/common/storage_partition_config_unittest.cc
+++ /dev/null
@@ -1,99 +0,0 @@
-// Copyright 2021 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.
-
-#include "components/download/public/common/storage_partition_config.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace download {
-
-TEST(StoragePartitionConfigTest, EqualityOperators) {
- StoragePartitionConfig c1(std::string(), std::string(), false);
- StoragePartitionConfig c2(std::string(), std::string(), true);
- StoragePartitionConfig c3("a", std::string(), true);
- StoragePartitionConfig c4("b", std::string(), true);
- StoragePartitionConfig c5(std::string(), "abc", false);
- StoragePartitionConfig c6(std::string(), "abc", true);
- StoragePartitionConfig c7("a", "abc", true);
- StoragePartitionConfig c8("a", "abc", true);
-
- EXPECT_FALSE(c1 == c2);
- EXPECT_FALSE(c1 == c8);
- EXPECT_FALSE(c2 == c8);
- EXPECT_FALSE(c3 == c4);
- EXPECT_FALSE(c3 == c8);
- EXPECT_FALSE(c4 == c8);
- EXPECT_FALSE(c5 == c6);
- EXPECT_FALSE(c5 == c8);
- EXPECT_FALSE(c6 == c8);
- EXPECT_TRUE(c7 == c8);
- EXPECT_TRUE(c8 == c8);
-}
-
-TEST(StoragePartitionConfigTest, SerializeToString) {
- // Check that all of the config's values are serialized properly.
- StoragePartitionConfig c1("a", "abc", true);
- auto c1_str = c1.SerializeToString();
- EXPECT_EQ(c1_str, std::string("a|abc|in_memory"));
-
- // Check that "in_memory" is not set if the value is false.
- StoragePartitionConfig c2("b", "xyz", false);
- auto c2_str = c2.SerializeToString();
- EXPECT_EQ(c2_str, std::string("b|xyz|"));
-
- // Check that the partition domain is not set if the value is empty.
- StoragePartitionConfig c3("", "def", true);
- auto c3_str = c3.SerializeToString();
- EXPECT_EQ(c3_str, std::string("|def|in_memory"));
-
- // Check that the partition name is not set if the value is empty.
- StoragePartitionConfig c4("uvw", "", false);
- auto c4_str = c4.SerializeToString();
- EXPECT_EQ(c4_str, std::string("uvw||"));
-
- // Check that no values are set if the values are empty or false.
- StoragePartitionConfig c5("", "", false);
- auto c5_str = c5.SerializeToString();
- EXPECT_EQ(c5_str, std::string("||"));
-}
-
-TEST(StoragePartitionConfigTest, DeserializeFromString) {
- // Check that all of the values are deserialized properly into the config.
- std::string c1_str = "a|abc|in_memory";
- StoragePartitionConfig expected_c1("a", "abc", true);
- EXPECT_EQ(StoragePartitionConfig::DeserializeFromString(c1_str), expected_c1);
-
- // Check that deserialization is correct if in memory is missing.
- std::string c2_str = "b|xyz|";
- StoragePartitionConfig expected_c2("b", "xyz", false);
- EXPECT_EQ(StoragePartitionConfig::DeserializeFromString(c2_str), expected_c2);
-
- // Check that deserialization is correct if partition domain is missing.
- std::string c3_str = "|def|in_memory";
- StoragePartitionConfig expected_c3("", "def", true);
- EXPECT_EQ(StoragePartitionConfig::DeserializeFromString(c3_str), expected_c3);
-
- // Check that deserialization is correct if partition name is missing.
- std::string c4_str = "uvw||";
- StoragePartitionConfig expected_c4("uvw", "", false);
- EXPECT_EQ(StoragePartitionConfig::DeserializeFromString(c4_str), expected_c4);
-
- std::string empty_str = "";
- StoragePartitionConfig expected_c5("", "", false);
- EXPECT_EQ(StoragePartitionConfig::DeserializeFromString(empty_str),
- expected_c5);
-
- std::string invalid_value_str = "a|abc|invalid";
- StoragePartitionConfig expected_c6("a", "abc", false);
- EXPECT_EQ(StoragePartitionConfig::DeserializeFromString(invalid_value_str),
- expected_c6);
-
- std::string too_many_delimiters_str = "a|abc|in_memory|extra|delimiters";
- StoragePartitionConfig expected_c7("", "", false);
- EXPECT_EQ(
- StoragePartitionConfig::DeserializeFromString(too_many_delimiters_str),
- expected_c7);
-}
-
-} // namespace download
diff --git a/chromium/components/embedder_support/android/delegate/web_contents_delegate_android.cc b/chromium/components/embedder_support/android/delegate/web_contents_delegate_android.cc
index 1aec422b4c8..1911b0558fa 100644
--- a/chromium/components/embedder_support/android/delegate/web_contents_delegate_android.cc
+++ b/chromium/components/embedder_support/android/delegate/web_contents_delegate_android.cc
@@ -272,7 +272,7 @@ void WebContentsDelegateAndroid::UpdateTargetURL(WebContents* source,
if (obj.is_null())
return;
Java_WebContentsDelegateAndroid_onUpdateUrl(
- env, obj, url::GURLAndroid::FromNativeGURL(env, source->GetURL()));
+ env, obj, url::GURLAndroid::FromNativeGURL(env, source->GetVisibleURL()));
}
bool WebContentsDelegateAndroid::HandleKeyboardEvent(
diff --git a/chromium/components/embedder_support/android/javatests/src/org/chromium/components/embedder_support/delegate/ColorPickerDialogRenderTest.java b/chromium/components/embedder_support/android/javatests/src/org/chromium/components/embedder_support/delegate/ColorPickerDialogRenderTest.java
index 30a3a8ede04..06c293be36e 100644
--- a/chromium/components/embedder_support/android/javatests/src/org/chromium/components/embedder_support/delegate/ColorPickerDialogRenderTest.java
+++ b/chromium/components/embedder_support/android/javatests/src/org/chromium/components/embedder_support/delegate/ColorPickerDialogRenderTest.java
@@ -25,7 +25,7 @@ import org.chromium.base.test.params.ParameterizedRunner;
import org.chromium.base.test.util.Feature;
import org.chromium.content_public.browser.test.util.TestThreadUtils;
import org.chromium.ui.R;
-import org.chromium.ui.test.util.DummyUiActivityTestCase;
+import org.chromium.ui.test.util.BlankUiTestActivityTestCase;
import org.chromium.ui.test.util.NightModeTestUtils;
import org.chromium.ui.test.util.RenderTestRule;
@@ -37,7 +37,7 @@ import java.util.List;
*/
@RunWith(ParameterizedRunner.class)
@UseRunnerDelegate(BaseJUnit4RunnerDelegate.class)
-public class ColorPickerDialogRenderTest extends DummyUiActivityTestCase {
+public class ColorPickerDialogRenderTest extends BlankUiTestActivityTestCase {
@ParameterAnnotations.ClassParameter
private static List<ParameterSet> sClassParams =
new NightModeTestUtils.NightModeParams().getParameters();
@@ -48,7 +48,7 @@ public class ColorPickerDialogRenderTest extends DummyUiActivityTestCase {
private View mView;
public ColorPickerDialogRenderTest(boolean nightModeEnabled) {
- NightModeTestUtils.setUpNightModeForDummyUiActivity(nightModeEnabled);
+ NightModeTestUtils.setUpNightModeForBlankUiTestActivity(nightModeEnabled);
mRenderTestRule.setNightModeEnabled(nightModeEnabled);
}
diff --git a/chromium/components/embedder_support/android/metrics/BUILD.gn b/chromium/components/embedder_support/android/metrics/BUILD.gn
index a8e6ab26377..adff06edac1 100644
--- a/chromium/components/embedder_support/android/metrics/BUILD.gn
+++ b/chromium/components/embedder_support/android/metrics/BUILD.gn
@@ -70,6 +70,7 @@ source_set("unit_tests") {
"//base/test:test_support",
"//components/metrics",
"//components/prefs:test_support",
+ "//components/variations/service:constants",
"//content/test:test_support",
"//testing/gtest",
]
diff --git a/chromium/components/embedder_support/android/metrics/DEPS b/chromium/components/embedder_support/android/metrics/DEPS
index aef2f1820f1..0ddc4e3e082 100644
--- a/chromium/components/embedder_support/android/metrics/DEPS
+++ b/chromium/components/embedder_support/android/metrics/DEPS
@@ -2,6 +2,7 @@ include_rules = [
"+components/metrics",
"+components/prefs",
"+components/ukm",
+ "+components/variations/service/variations_safe_mode_constants.h",
"+components/version_info",
"+content/public/browser",
"+content/public/test",
diff --git a/chromium/components/embedder_support/android/metrics/android_metrics_service_client.cc b/chromium/components/embedder_support/android/metrics/android_metrics_service_client.cc
index 0926baa088a..cf77d615e77 100644
--- a/chromium/components/embedder_support/android/metrics/android_metrics_service_client.cc
+++ b/chromium/components/embedder_support/android/metrics/android_metrics_service_client.cc
@@ -11,6 +11,7 @@
#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
#include "base/base_paths_android.h"
+#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/i18n/rtl.h"
#include "base/metrics/field_trial_params.h"
@@ -233,9 +234,7 @@ void AndroidMetricsServiceClient::RegisterPrefs(PrefRegistrySimple* registry) {
ukm::UkmService::RegisterPrefs(registry);
}
-void AndroidMetricsServiceClient::Initialize(
- const base::FilePath& user_data_dir,
- PrefService* pref_service) {
+void AndroidMetricsServiceClient::Initialize(PrefService* pref_service) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(!init_finished_);
@@ -244,8 +243,11 @@ void AndroidMetricsServiceClient::Initialize(
// TODO(crbug/1245347): If and when the Extended Variations Safe Mode
// experiment is enabled on Android WebLayer, pass the channel to the
// MetricsStateManager.
+ //
+ // Pass an empty file path since the path is for the Extended Variations Safe
+ // Mode experiment and Android embedders are excluded from this experiment.
metrics_state_manager_ = MetricsStateManager::Create(
- pref_service_, this, std::wstring(), user_data_dir);
+ pref_service_, this, std::wstring(), base::FilePath());
// Creates the FieldTrialList using the low entropy provider. The low entropy
// provider is used instead of the default provider because the default
diff --git a/chromium/components/embedder_support/android/metrics/android_metrics_service_client.h b/chromium/components/embedder_support/android/metrics/android_metrics_service_client.h
index d829b386390..d21a3867fc6 100644
--- a/chromium/components/embedder_support/android/metrics/android_metrics_service_client.h
+++ b/chromium/components/embedder_support/android/metrics/android_metrics_service_client.h
@@ -9,7 +9,6 @@
#include <string>
#include "base/callback_forward.h"
-#include "base/files/file_path.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/metrics/field_trial.h"
@@ -107,11 +106,7 @@ class AndroidMetricsServiceClient : public MetricsServiceClient,
// Initializes, but does not necessarily start, the MetricsService. See the
// documentation at the top of the file for more details.
- //
- // |user_data_dir| is the path to the client's user data directory. If empty,
- // a separate file will not be used for Variations Safe Mode prefs.
- void Initialize(const base::FilePath& user_data_dir,
- PrefService* pref_service);
+ void Initialize(PrefService* pref_service);
void SetHaveMetricsConsent(bool user_consent, bool app_consent);
void SetFastStartupForTesting(bool fast_startup_for_testing);
void SetUploadIntervalForTesting(const base::TimeDelta& upload_interval);
diff --git a/chromium/components/embedder_support/android/metrics/android_metrics_service_client_unittest.cc b/chromium/components/embedder_support/android/metrics/android_metrics_service_client_unittest.cc
index bacd04f50e9..ce83e1986c4 100644
--- a/chromium/components/embedder_support/android/metrics/android_metrics_service_client_unittest.cc
+++ b/chromium/components/embedder_support/android/metrics/android_metrics_service_client_unittest.cc
@@ -9,6 +9,7 @@
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/memory/scoped_refptr.h"
+#include "base/metrics/field_trial.h"
#include "base/metrics/persistent_histogram_allocator.h"
#include "base/path_service.h"
#include "base/run_loop.h"
@@ -20,6 +21,7 @@
#include "components/metrics/metrics_switches.h"
#include "components/metrics/persistent_histograms.h"
#include "components/prefs/testing_pref_service.h"
+#include "components/variations/service/variations_safe_mode_constants.h"
#include "content/public/test/browser_task_environment.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -43,10 +45,6 @@ class TestClient : public AndroidMetricsServiceClient {
~TestClient() override = default;
- void Initialize(PrefService* pref_service) {
- AndroidMetricsServiceClient::Initialize(base::FilePath(), pref_service);
- }
-
bool IsRecordingActive() {
auto* service = GetMetricsService();
if (service)
@@ -155,6 +153,17 @@ class AndroidMetricsServiceClientTest : public testing::Test {
scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
};
+// Verify that the Extended Variations Safe Mode experiment is disabled on
+// Android embedders.
+TEST_F(AndroidMetricsServiceClientTest,
+ ExtendedVariationsSafeModeExperimentDisabled) {
+ auto prefs = CreateTestPrefs();
+ auto client = std::make_unique<TestClient>();
+ client->Initialize(prefs.get());
+ EXPECT_FALSE(
+ base::FieldTrialList::IsTrialActive(variations::kExtendedSafeModeTrial));
+}
+
TEST_F(AndroidMetricsServiceClientTest, TestSetConsentTrueBeforeInit) {
auto prefs = CreateTestPrefs();
auto client = std::make_unique<TestClient>();
diff --git a/chromium/components/embedder_support/android/metrics/memory_metrics_logger.cc b/chromium/components/embedder_support/android/metrics/memory_metrics_logger.cc
index e5bd196d3cb..a131d813132 100644
--- a/chromium/components/embedder_support/android/metrics/memory_metrics_logger.cc
+++ b/chromium/components/embedder_support/android/metrics/memory_metrics_logger.cc
@@ -65,11 +65,11 @@ void RecordMemoryMetricsImpl(
// renderer process, as it originated from WebView, where there are no
// other processes.
case memory_instrumentation::mojom::ProcessType::ARC:
- FALLTHROUGH;
+ [[fallthrough]];
case memory_instrumentation::mojom::ProcessType::UTILITY:
- FALLTHROUGH;
+ [[fallthrough]];
case memory_instrumentation::mojom::ProcessType::PLUGIN:
- FALLTHROUGH;
+ [[fallthrough]];
case memory_instrumentation::mojom::ProcessType::OTHER:
break;
}
diff --git a/chromium/components/embedder_support/android/util/android_stream_reader_url_loader.cc b/chromium/components/embedder_support/android/util/android_stream_reader_url_loader.cc
index d8d0dd8bffd..df4747d51d5 100644
--- a/chromium/components/embedder_support/android/util/android_stream_reader_url_loader.cc
+++ b/chromium/components/embedder_support/android/util/android_stream_reader_url_loader.cc
@@ -130,7 +130,7 @@ AndroidStreamReaderURLLoader::AndroidStreamReaderURLLoader(
security_options->disable_web_security ||
(security_options->allow_cors_to_same_scheme &&
resource_request.request_initiator->IsSameOriginWith(
- url::Origin::Create(resource_request_.url)));
+ resource_request_.url));
reject_cors_request_ = true;
}
response_head_->response_type = network::cors::CalculateResponseType(
@@ -315,7 +315,8 @@ void AndroidStreamReaderURLLoader::SendResponseToClient() {
DCHECK(client_.is_bound());
cache_response_ =
response_delegate_->ShouldCacheResponse(response_head_.get());
- client_->OnReceiveResponse(std::move(response_head_));
+ client_->OnReceiveResponse(std::move(response_head_),
+ mojo::ScopedDataPipeConsumerHandle());
client_->OnStartLoadingResponseBody(std::move(consumer_handle_));
}
diff --git a/chromium/components/embedder_support/content_settings_utils.cc b/chromium/components/embedder_support/content_settings_utils.cc
index a7c905f969e..64f5df1c60e 100644
--- a/chromium/components/embedder_support/content_settings_utils.cc
+++ b/chromium/components/embedder_support/content_settings_utils.cc
@@ -23,9 +23,9 @@ content::AllowServiceWorkerResult AllowServiceWorker(
GURL first_party_url = top_frame_origin ? top_frame_origin->GetURL() : GURL();
// Check if JavaScript is allowed.
content_settings::SettingInfo info;
- std::unique_ptr<base::Value> value = settings_map->GetWebsiteSetting(
+ const base::Value value = settings_map->GetWebsiteSetting(
first_party_url, first_party_url, ContentSettingsType::JAVASCRIPT, &info);
- ContentSetting setting = content_settings::ValueToContentSetting(value.get());
+ ContentSetting setting = content_settings::ValueToContentSetting(value);
bool allow_javascript = setting == CONTENT_SETTING_ALLOW;
// Check if cookies are allowed.
diff --git a/chromium/components/embedder_support/origin_trials/component_updater_utils.cc b/chromium/components/embedder_support/origin_trials/component_updater_utils.cc
index 941af27a384..954b7331e85 100644
--- a/chromium/components/embedder_support/origin_trials/component_updater_utils.cc
+++ b/chromium/components/embedder_support/origin_trials/component_updater_utils.cc
@@ -36,32 +36,22 @@ void ReadOriginTrialsConfigAndPopulateLocalState(PrefService* local_state,
local_state->ClearPref(prefs::kOriginTrialPublicKey);
}
- // TODO(crbug.com/1187062): Modernize use of base::ListValue once
- // ListPrefUpdate is converted.
- base::ListValue* override_disabled_feature_list = nullptr;
- if (base::Value* raw_override_disabled_feature_list =
- manifest.FindListPath(kManifestDisabledFeaturesPath)) {
- raw_override_disabled_feature_list->GetAsList(
- &override_disabled_feature_list);
- }
+ base::Value* override_disabled_feature_list =
+ manifest.FindListPath(kManifestDisabledFeaturesPath);
if (override_disabled_feature_list &&
- !override_disabled_feature_list->GetList().empty()) {
+ !override_disabled_feature_list->GetListDeprecated().empty()) {
ListPrefUpdate update(local_state, prefs::kOriginTrialDisabledFeatures);
- update->Swap(override_disabled_feature_list);
+ *update = std::move(*override_disabled_feature_list);
} else {
local_state->ClearPref(prefs::kOriginTrialDisabledFeatures);
}
- // TODO(crbug.com/1187062): Modernize use of base::ListValue once
- // ListPrefUpdate is converted.
- base::ListValue* disabled_tokens_list = nullptr;
- if (base::Value* raw_disabled_tokens_list =
- manifest.FindListPath(kManifestDisabledTokenSignaturesPath)) {
- raw_disabled_tokens_list->GetAsList(&disabled_tokens_list);
- }
- if (disabled_tokens_list && !disabled_tokens_list->GetList().empty()) {
+ base::Value* disabled_tokens_list =
+ manifest.FindListPath(kManifestDisabledTokenSignaturesPath);
+ if (disabled_tokens_list &&
+ !disabled_tokens_list->GetListDeprecated().empty()) {
ListPrefUpdate update(local_state, prefs::kOriginTrialDisabledTokens);
- update->Swap(disabled_tokens_list);
+ *update = std::move(*disabled_tokens_list);
} else {
local_state->ClearPref(prefs::kOriginTrialDisabledTokens);
}
diff --git a/chromium/components/embedder_support/origin_trials/component_updater_utils_unittest.cc b/chromium/components/embedder_support/origin_trials/component_updater_utils_unittest.cc
index 6216df3a0e0..34b14c37572 100644
--- a/chromium/components/embedder_support/origin_trials/component_updater_utils_unittest.cc
+++ b/chromium/components/embedder_support/origin_trials/component_updater_utils_unittest.cc
@@ -81,13 +81,13 @@ class OriginTrialsComponentInstallerTest : public PlatformTest {
}
void AddDisabledFeaturesToPrefs(const std::vector<std::string>& features) {
- base::ListValue disabled_feature_list;
+ base::Value disabled_feature_list(base::Value::Type::LIST);
for (const std::string& feature : features) {
disabled_feature_list.Append(feature);
}
ListPrefUpdate update(
local_state(), embedder_support::prefs::kOriginTrialDisabledFeatures);
- update->Swap(&disabled_feature_list);
+ *update = std::move(disabled_feature_list);
}
void CheckDisabledFeaturesPrefs(const std::vector<std::string>& features) {
@@ -96,15 +96,16 @@ class OriginTrialsComponentInstallerTest : public PlatformTest {
ASSERT_TRUE(local_state()->HasPrefPath(
embedder_support::prefs::kOriginTrialDisabledFeatures));
- const base::ListValue* disabled_feature_list = local_state()->GetList(
+ const base::Value* disabled_feature_list = local_state()->GetList(
embedder_support::prefs::kOriginTrialDisabledFeatures);
ASSERT_TRUE(disabled_feature_list);
- ASSERT_EQ(features.size(), disabled_feature_list->GetList().size());
+ ASSERT_EQ(features.size(),
+ disabled_feature_list->GetListDeprecated().size());
for (size_t i = 0; i < features.size(); ++i) {
const std::string* disabled_feature =
- disabled_feature_list->GetList()[i].GetIfString();
+ disabled_feature_list->GetListDeprecated()[i].GetIfString();
if (!disabled_feature) {
ADD_FAILURE() << "Entry not found or not a string at index " << i;
continue;
@@ -115,13 +116,13 @@ class OriginTrialsComponentInstallerTest : public PlatformTest {
}
void AddDisabledTokensToPrefs(const std::vector<std::string>& tokens) {
- base::ListValue disabled_token_list;
+ base::Value disabled_token_list(base::Value::Type::LIST);
for (const std::string& token : tokens) {
disabled_token_list.Append(token);
}
ListPrefUpdate update(local_state(),
embedder_support::prefs::kOriginTrialDisabledTokens);
- update->Swap(&disabled_token_list);
+ *update = std::move(disabled_token_list);
}
void CheckDisabledTokensPrefs(const std::vector<std::string>& tokens) {
@@ -130,15 +131,15 @@ class OriginTrialsComponentInstallerTest : public PlatformTest {
ASSERT_TRUE(local_state()->HasPrefPath(
embedder_support::prefs::kOriginTrialDisabledTokens));
- const base::ListValue* disabled_token_list = local_state()->GetList(
+ const base::Value* disabled_token_list = local_state()->GetList(
embedder_support::prefs::kOriginTrialDisabledTokens);
ASSERT_TRUE(disabled_token_list);
- ASSERT_EQ(tokens.size(), disabled_token_list->GetList().size());
+ ASSERT_EQ(tokens.size(), disabled_token_list->GetListDeprecated().size());
for (size_t i = 0; i < tokens.size(); ++i) {
const std::string* disabled_token =
- disabled_token_list->GetList()[i].GetIfString();
+ disabled_token_list->GetListDeprecated()[i].GetIfString();
if (!disabled_token) {
ADD_FAILURE() << "Entry not found or not a string at index " << i;
diff --git a/chromium/components/embedder_support/permission_context_utils.cc b/chromium/components/embedder_support/permission_context_utils.cc
index ffb476e6295..75b22de5422 100644
--- a/chromium/components/embedder_support/permission_context_utils.cc
+++ b/chromium/components/embedder_support/permission_context_utils.cc
@@ -19,14 +19,14 @@
#include "components/permissions/contexts/wake_lock_permission_context.h"
#include "components/permissions/contexts/webxr_permission_context.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "components/permissions/contexts/geolocation_permission_context_android.h"
#include "components/permissions/contexts/nfc_permission_context_android.h"
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
#include "components/permissions/contexts/geolocation_permission_context_mac.h"
-#endif // defined(OS_MAC)
+#endif // BUILDFLAG(IS_MAC)
namespace embedder_support {
@@ -47,9 +47,9 @@ CreateDefaultPermissionContexts(content::BrowserContext* browser_context,
DCHECK(delegates.camera_pan_tilt_zoom_permission_context_delegate);
DCHECK(delegates.geolocation_permission_context_delegate);
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
DCHECK(delegates.geolocation_manager);
-#endif // defined(OS_MAC)
+#endif // BUILDFLAG(IS_MAC)
DCHECK(delegates.media_stream_device_enumerator);
DCHECK(delegates.nfc_permission_context_delegate);
@@ -72,12 +72,12 @@ CreateDefaultPermissionContexts(content::BrowserContext* browser_context,
permission_contexts[ContentSettingsType::CLIPBOARD_SANITIZED_WRITE] =
std::make_unique<permissions::ClipboardSanitizedWritePermissionContext>(
browser_context);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
permission_contexts[ContentSettingsType::GEOLOCATION] =
std::make_unique<permissions::GeolocationPermissionContextAndroid>(
browser_context,
std::move(delegates.geolocation_permission_context_delegate));
-#elif defined(OS_MAC)
+#elif BUILDFLAG(IS_MAC)
permission_contexts[ContentSettingsType::GEOLOCATION] =
std::make_unique<permissions::GeolocationPermissionContextMac>(
browser_context,
@@ -94,7 +94,7 @@ CreateDefaultPermissionContexts(content::BrowserContext* browser_context,
permission_contexts[ContentSettingsType::MIDI_SYSEX] =
std::make_unique<permissions::MidiSysexPermissionContext>(
browser_context);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
permission_contexts[ContentSettingsType::NFC] =
std::make_unique<permissions::NfcPermissionContextAndroid>(
browser_context,
@@ -104,7 +104,7 @@ CreateDefaultPermissionContexts(content::BrowserContext* browser_context,
std::make_unique<permissions::NfcPermissionContext>(
browser_context,
std::move(delegates.nfc_permission_context_delegate));
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
permission_contexts[ContentSettingsType::PAYMENT_HANDLER] =
std::make_unique<payments::PaymentHandlerPermissionContext>(
browser_context);
diff --git a/chromium/components/embedder_support/permission_context_utils.h b/chromium/components/embedder_support/permission_context_utils.h
index ffe040914af..8bb53496411 100644
--- a/chromium/components/embedder_support/permission_context_utils.h
+++ b/chromium/components/embedder_support/permission_context_utils.h
@@ -16,11 +16,11 @@ namespace content {
class BrowserContext;
} // namespace content
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
namespace device {
class GeolocationManager;
} // namespace device
-#endif // defined(OS_MAC)
+#endif // BUILDFLAG(IS_MAC)
namespace webrtc {
class MediaStreamDeviceEnumerator;
@@ -40,9 +40,9 @@ struct PermissionContextDelegates {
camera_pan_tilt_zoom_permission_context_delegate;
std::unique_ptr<permissions::GeolocationPermissionContext::Delegate>
geolocation_permission_context_delegate;
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
device::GeolocationManager* geolocation_manager;
-#endif // defined(OS_MAC)
+#endif // BUILDFLAG(IS_MAC)
raw_ptr<webrtc::MediaStreamDeviceEnumerator> media_stream_device_enumerator;
std::unique_ptr<permissions::NfcPermissionContext::Delegate>
nfc_permission_context_delegate;
diff --git a/chromium/components/embedder_support/pref_names.cc b/chromium/components/embedder_support/pref_names.cc
index 133f1a827e0..e0b70f2e73b 100644
--- a/chromium/components/embedder_support/pref_names.cc
+++ b/chromium/components/embedder_support/pref_names.cc
@@ -9,4 +9,10 @@ namespace embedder_support {
// A boolean pref set to true if we're using Link Doctor error pages.
const char kAlternateErrorPagesEnabled[] = "alternate_error_pages.enabled";
+// Enum indicating if the user agent string should freeze the major version
+// at 99 and report the browser's major version in the minor position.
+// TODO(crbug.com/1290820): Remove this policy.
+const char kForceMajorVersionToMinorPosition[] =
+ "force_major_version_to_minor_position_in_user_agent";
+
} // namespace embedder_support
diff --git a/chromium/components/embedder_support/pref_names.h b/chromium/components/embedder_support/pref_names.h
index c7c24464c5c..1cfd57dc42a 100644
--- a/chromium/components/embedder_support/pref_names.h
+++ b/chromium/components/embedder_support/pref_names.h
@@ -11,6 +11,7 @@
namespace embedder_support {
extern const char kAlternateErrorPagesEnabled[];
+extern const char kForceMajorVersionToMinorPosition[];
} // namespace embedder_support
diff --git a/chromium/components/embedder_support/user_agent_utils.cc b/chromium/components/embedder_support/user_agent_utils.cc
index 2c451bda79a..958a61892a1 100644
--- a/chromium/components/embedder_support/user_agent_utils.cc
+++ b/chromium/components/embedder_support/user_agent_utils.cc
@@ -15,6 +15,7 @@
#include "base/version.h"
#include "build/branding_buildflags.h"
#include "build/build_config.h"
+#include "components/embedder_support/pref_names.h"
#include "components/embedder_support/switches.h"
#include "components/policy/core/common/policy_pref_names.h"
#include "components/prefs/pref_service.h"
@@ -27,20 +28,20 @@
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/common/user_agent/user_agent_metadata.h"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include <windows.h>
#include "base/win/registry.h"
#include "base/win/windows_version.h"
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
namespace embedder_support {
namespace {
-constexpr char kVersion100[] = "100";
+constexpr char kVersion99[] = "99";
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// The registry key where the UniversalApiContract version value can be read
// from.
@@ -79,6 +80,36 @@ int GetPreRS5UniversalApiContractVersion() {
NOTREACHED();
return 0;
}
+
+// Return the legacy windows platform version to match the spec description
+// https://wicg.github.io/ua-client-hints/#get-the-legacy-windows-version-number,
+// which is available for Windows versions between range WIN7 and WIN8_1.
+// Otherwise, returns 0.
+const std::string& GetLegacyWindowsPlatformVersion() {
+ static const base::NoDestructor<std::string> legacy_windows_platform_version(
+ [] {
+ int major_version = 0;
+ int minor_version = 0;
+ switch (base::win::GetVersion()) {
+ case base::win::Version::WIN7:
+ minor_version = 1;
+ break;
+ case base::win::Version::WIN8:
+ minor_version = 2;
+ break;
+ case base::win::Version::WIN8_1:
+ minor_version = 3;
+ break;
+ default:
+ minor_version = 0;
+ break;
+ }
+ return base::StrCat({base::NumberToString(major_version), ".",
+ base::NumberToString(minor_version), ".0"});
+ }());
+ return *legacy_windows_platform_version;
+}
+
// Returns the UniversalApiContract version number, which is available for
// Windows versions greater than RS5. Otherwise, returns 0.
const std::string& GetUniversalApiContractVersion() {
@@ -121,43 +152,58 @@ const std::string& GetUniversalApiContractVersion() {
return *universal_api_contract_version;
}
-#endif // defined(OS_WIN)
-
-const std::string& GetM100VersionNumber() {
- static const base::NoDestructor<std::string> m100_version_number([] {
- base::Version version(version_info::GetVersionNumber());
- std::string version_str(kVersion100);
- const std::vector<uint32_t>& components = version.components();
- // Rest of the version string remains the same.
- for (size_t i = 1; i < components.size(); ++i) {
- version_str.append(".");
- version_str.append(base::NumberToString(components[i]));
- }
- return version_str;
- }());
- return *m100_version_number;
+const std::string& GetWindowsPlatformVersion() {
+ if (base::win::GetVersion() < base::win::Version::WIN10) {
+ return GetLegacyWindowsPlatformVersion();
+ }
+ return GetUniversalApiContractVersion();
+}
+#endif // BUILDFLAG(IS_WIN)
+
+// Returns true if the user agent string should force the major version into
+// the minor position.
+// TODO(crbug.com/1290820): Remove this method along with policy.
+bool ShouldForceMajorVersionToMinorPosition(
+ ForceMajorVersionToMinorPosition force_major_to_minor = kDefault) {
+ return (
+ (force_major_to_minor != kForceDisabled &&
+ base::FeatureList::IsEnabled(
+ blink::features::kForceMajorVersionInMinorPositionInUserAgent)) ||
+ force_major_to_minor == kForceEnabled);
}
-const std::string& GetM100InMinorVersionNumber() {
- static const base::NoDestructor<std::string> m100_version_number([] {
+const std::string& GetMajorInMinorVersionNumber() {
+ static const base::NoDestructor<std::string> version_number([] {
base::Version version(version_info::GetVersionNumber());
std::string version_str;
const std::vector<uint32_t>& components = version.components();
- // Rest of the version string remains the same.
for (size_t i = 0; i < components.size(); ++i) {
if (i > 0) {
version_str.append(".");
}
- if (i == 1) {
- // Populate "100" for the minor version.
- version_str.append(kVersion100);
+ if (i == 0) {
+ // Hardcode major version to 99
+ version_str.append(kVersion99);
+ } else if (i == 1) {
+ // Force major into minor version
+ version_str.append(base::NumberToString(components[0]));
} else {
+ // build and patch stay the same
version_str.append(base::NumberToString(components[i]));
}
}
return version_str;
}());
- return *m100_version_number;
+ return *version_number;
+}
+
+std::string GetVersionNumber(const UserAgentOptions& options) {
+ // Force major version to 99.
+ if (ShouldForceMajorVersionToMinorPosition(options.force_major_to_minor))
+ return GetMajorInMinorVersionNumber();
+
+ const std::string& version_str = version_info::GetVersionNumber();
+ return version_str;
}
const blink::UserAgentBrandList GetUserAgentBrandList(
@@ -201,13 +247,16 @@ const blink::UserAgentBrandList GetUserAgentBrandMajorVersionList(
blink::UserAgentBrandVersionType::kMajorVersion);
}
-blink::UserAgentBrandList GetForcedM100UserAgentBrandMajorVersionList(
+// TODO(crbug.com/1290820): Remove this method along with policy.
+blink::UserAgentBrandList GetMajorInMinorUserAgentBrandMajorVersionList(
bool enable_updated_grease_by_policy) {
- return GetUserAgentBrandList(kVersion100, enable_updated_grease_by_policy,
- GetM100VersionNumber(),
+ return GetUserAgentBrandList(kVersion99, enable_updated_grease_by_policy,
+ GetMajorInMinorVersionNumber(),
blink::UserAgentBrandVersionType::kMajorVersion);
}
+// TODO(crbug.com/1291612): Consolidate *FullVersionList() methods by using
+// GetVersionNumber()
blink::UserAgentBrandList GetUserAgentBrandFullVersionList(
bool enable_updated_grease_by_policy) {
return GetUserAgentBrandList(version_info::GetMajorVersionNumber(),
@@ -216,20 +265,24 @@ blink::UserAgentBrandList GetUserAgentBrandFullVersionList(
blink::UserAgentBrandVersionType::kFullVersion);
}
-blink::UserAgentBrandList GetForcedM100UserAgentBrandFullVersionList(
+// TODO(crbug.com/1290820): Remove this method along with policy.
+blink::UserAgentBrandList GetMajorInMinorUserAgentBrandFullVersionList(
bool enable_updated_grease_by_policy) {
- return GetUserAgentBrandList(kVersion100, enable_updated_grease_by_policy,
- GetM100VersionNumber(),
+ return GetUserAgentBrandList(kVersion99, enable_updated_grease_by_policy,
+ GetMajorInMinorVersionNumber(),
blink::UserAgentBrandVersionType::kFullVersion);
}
// Return UserAgentBrandList with the major version populated in the brand
// `version` value.
+// TODO(crbug.com/1291612): Consolidate *MajorVersionList() methods by using
+// GetVersionNumber()
blink::UserAgentBrandList GetBrandMajorVersionList(
- bool enable_updated_grease_by_policy) {
- if (base::FeatureList::IsEnabled(
- blink::features::kForceMajorVersion100InUserAgent))
- return GetForcedM100UserAgentBrandMajorVersionList(
+ bool enable_updated_grease_by_policy,
+ ForceMajorVersionToMinorPosition force_major_to_minor) {
+ // Force major version to 99.
+ if (ShouldForceMajorVersionToMinorPosition(force_major_to_minor))
+ return GetMajorInMinorUserAgentBrandMajorVersionList(
enable_updated_grease_by_policy);
return GetUserAgentBrandMajorVersionList(enable_updated_grease_by_policy);
@@ -237,36 +290,44 @@ blink::UserAgentBrandList GetBrandMajorVersionList(
// Return UserAgentBrandList with the full version populated in the brand
// `version` value.
+// TODO(crbug.com/1291612): Consolidate *FullVersionList() methods by using
+// GetVersionNumber()
blink::UserAgentBrandList GetBrandFullVersionList(
- bool enable_updated_grease_by_policy) {
- if (base::FeatureList::IsEnabled(
- blink::features::kForceMajorVersion100InUserAgent))
- return GetForcedM100UserAgentBrandFullVersionList(
+ bool enable_updated_grease_by_policy,
+ ForceMajorVersionToMinorPosition force_major_to_minor) {
+ // Force major version to 99.
+ if (ShouldForceMajorVersionToMinorPosition(force_major_to_minor))
+ return GetMajorInMinorUserAgentBrandFullVersionList(
enable_updated_grease_by_policy);
return GetUserAgentBrandFullVersionList(enable_updated_grease_by_policy);
}
-std::string GetProduct(const bool allow_version_override) {
- if (allow_version_override &&
- base::FeatureList::IsEnabled(
- blink::features::kForceMajorVersion100InUserAgent))
- return "Chrome/" + GetM100VersionNumber();
- if (allow_version_override &&
- base::FeatureList::IsEnabled(
- blink::features::kForceMinorVersion100InUserAgent))
- return "Chrome/" + GetM100InMinorVersionNumber();
+// Returns a string representing the major version number of the user agent
+// string for Chrome, potentially overridden by policy.
+std::string GetMajorVersionForUserAgentString(
+ ForceMajorVersionToMinorPosition force_major_to_minor) {
+ // Force major version to 99.
+ if (ShouldForceMajorVersionToMinorPosition(force_major_to_minor))
+ return kVersion99;
- return version_info::GetProductNameAndVersionForUserAgent();
+ return version_info::GetMajorVersionNumber();
}
} // namespace
-std::string GetProduct() {
- return GetProduct(/*allow_version_override=*/false);
+std::string GetProduct(const bool allow_version_override,
+ ForceMajorVersionToMinorPosition force_major_to_minor) {
+ // Force major version to 99 and minor version to major position.
+ if (allow_version_override &&
+ ShouldForceMajorVersionToMinorPosition(force_major_to_minor))
+ return "Chrome/" + GetMajorInMinorVersionNumber();
+
+ return version_info::GetProductNameAndVersionForUserAgent();
}
-std::string GetUserAgent() {
+std::string GetUserAgent(
+ ForceMajorVersionToMinorPosition force_major_to_minor) {
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(kUserAgent)) {
std::string ua = command_line->GetSwitchValueASCII(kUserAgent);
@@ -275,25 +336,28 @@ std::string GetUserAgent() {
LOG(WARNING) << "Ignored invalid value for flag --" << kUserAgent;
}
+ if (base::FeatureList::IsEnabled(blink::features::kFullUserAgent))
+ return GetFullUserAgent();
+
if (base::FeatureList::IsEnabled(blink::features::kReduceUserAgent))
- return GetReducedUserAgent();
+ return GetReducedUserAgent(force_major_to_minor);
- return GetFullUserAgent();
+ return GetFullUserAgent(force_major_to_minor);
}
-std::string GetReducedUserAgent() {
+std::string GetReducedUserAgent(
+ ForceMajorVersionToMinorPosition force_major_to_minor) {
return content::GetReducedUserAgent(
base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kUseMobileUserAgent),
- base::FeatureList::IsEnabled(
- blink::features::kForceMajorVersion100InUserAgent)
- ? kVersion100
- : version_info::GetMajorVersionNumber());
+ GetMajorVersionForUserAgentString(force_major_to_minor));
}
-std::string GetFullUserAgent() {
- std::string product = GetProduct(/*allow_version_override=*/true);
-#if defined(OS_ANDROID)
+std::string GetFullUserAgent(
+ ForceMajorVersionToMinorPosition force_major_to_minor) {
+ std::string product =
+ GetProduct(/*allow_override=*/true, force_major_to_minor);
+#if BUILDFLAG(IS_ANDROID)
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kUseMobileUserAgent))
product += " Mobile";
@@ -407,22 +471,27 @@ blink::UserAgentBrandVersion GetGreasedUserAgentBrandVersion(
greasey_chars[(seed + 1) % greasey_chars.size()], "A",
greasey_chars[(seed + 2) % greasey_chars.size()], "Brand"});
greasey_version = greased_versions[seed % greased_versions.size()];
+
+ return GetProcessedGreasedBrandVersion(
+ maybe_greasey_brand.value_or(greasey_brand),
+ maybe_greasey_version.value_or(greasey_version), output_version_type);
} else {
const std::vector<std::string> greasey_chars = {" ", " ", ";"};
greasey_brand = base::StrCat({greasey_chars[permuted_order[0]], "Not",
greasey_chars[permuted_order[1]], "A",
greasey_chars[permuted_order[2]], "Brand"});
greasey_version = "99";
- }
- return GetProcessedGreasedBrandVersion(
- maybe_greasey_brand.value_or(greasey_brand),
- maybe_greasey_version.value_or(greasey_version), output_version_type);
+ // The old algorithm is held constant; it does not respond to experiment
+ // overrides.
+ return GetProcessedGreasedBrandVersion(greasey_brand, greasey_version,
+ output_version_type);
+ }
}
// TODO(crbug.com/1103047): This can be removed/re-refactored once we use
// "macOS" by default
std::string GetPlatformForUAMetadata() {
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
return "macOS";
#else
return version_info::GetOSType();
@@ -436,31 +505,30 @@ blink::UserAgentMetadata GetUserAgentMetadata() {
blink::UserAgentMetadata GetUserAgentMetadata(PrefService* pref_service) {
blink::UserAgentMetadata metadata;
bool enable_updated_grease_by_policy = true;
- if (pref_service &&
- pref_service->HasPrefPath(
- policy::policy_prefs::kUserAgentClientHintsGREASEUpdateEnabled)) {
- enable_updated_grease_by_policy = pref_service->GetBoolean(
- policy::policy_prefs::kUserAgentClientHintsGREASEUpdateEnabled);
+ UserAgentOptions ua_options;
+ if (pref_service) {
+ if (pref_service->HasPrefPath(
+ policy::policy_prefs::kUserAgentClientHintsGREASEUpdateEnabled))
+ enable_updated_grease_by_policy = pref_service->GetBoolean(
+ policy::policy_prefs::kUserAgentClientHintsGREASEUpdateEnabled);
+ ua_options.force_major_to_minor = GetMajorToMinorFromPrefs(pref_service);
}
- metadata.brand_version_list =
- GetBrandMajorVersionList(enable_updated_grease_by_policy);
- metadata.brand_full_version_list =
- GetBrandFullVersionList(enable_updated_grease_by_policy);
- metadata.full_version = base::FeatureList::IsEnabled(
- blink::features::kForceMajorVersion100InUserAgent)
- ? GetM100VersionNumber()
- : version_info::GetVersionNumber();
+ metadata.brand_version_list = GetBrandMajorVersionList(
+ enable_updated_grease_by_policy, ua_options.force_major_to_minor);
+ metadata.brand_full_version_list = GetBrandFullVersionList(
+ enable_updated_grease_by_policy, ua_options.force_major_to_minor);
+ metadata.full_version = GetVersionNumber(ua_options);
metadata.platform = GetPlatformForUAMetadata();
metadata.architecture = content::GetLowEntropyCpuArchitecture();
metadata.model = content::BuildModelInfo();
metadata.mobile = false;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
metadata.mobile = base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kUseMobileUserAgent);
#endif
-#if defined(OS_WIN)
- metadata.platform_version = GetUniversalApiContractVersion();
+#if BUILDFLAG(IS_WIN)
+ metadata.platform_version = GetWindowsPlatformVersion();
#else
int32_t major, minor, bugfix = 0;
base::SysInfo::OperatingSystemVersionNumbers(&major, &minor, &bugfix);
@@ -473,11 +541,12 @@ blink::UserAgentMetadata GetUserAgentMetadata(PrefService* pref_service) {
// set number. For more information, see the respective headers.
metadata.architecture = content::GetLowEntropyCpuArchitecture();
metadata.bitness = content::GetLowEntropyCpuBitness();
+ metadata.wow64 = content::IsWoW64();
return metadata;
-} // namespace embedder_support
+}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
void SetDesktopUserAgentOverride(content::WebContents* web_contents,
const blink::UserAgentMetadata& metadata,
bool override_in_new_tabs) {
@@ -485,7 +554,7 @@ void SetDesktopUserAgentOverride(content::WebContents* web_contents,
blink::UserAgentOverride spoofed_ua;
spoofed_ua.ua_string_override = content::BuildUserAgentFromOSAndProduct(
- kLinuxInfoStr, GetProduct(/*allow_version_override=*/true));
+ kLinuxInfoStr, GetProduct(/*allow_override=*/true));
spoofed_ua.ua_metadata_override = metadata;
spoofed_ua.ua_metadata_override->platform = "Linux";
spoofed_ua.ua_metadata_override->platform_version =
@@ -496,15 +565,32 @@ void SetDesktopUserAgentOverride(content::WebContents* web_contents,
// CPU architecture and bitness.`
spoofed_ua.ua_metadata_override->architecture = "x86";
spoofed_ua.ua_metadata_override->bitness = "64";
+ spoofed_ua.ua_metadata_override->wow64 = false;
web_contents->SetUserAgentOverride(spoofed_ua, override_in_new_tabs);
}
-#endif // OS_ANDROID
+#endif // BUILDFLAG(IS_ANDROID)
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
int GetHighestKnownUniversalApiContractVersionForTesting() {
return kHighestKnownUniversalApiContractVersion;
}
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
+
+// TODO(crbug.com/1290820): Remove this function with policy.
+embedder_support::ForceMajorVersionToMinorPosition GetMajorToMinorFromPrefs(
+ PrefService* pref_service) {
+ if (!pref_service->HasPrefPath(kForceMajorVersionToMinorPosition))
+ return kDefault;
+ switch (pref_service->GetInteger(kForceMajorVersionToMinorPosition)) {
+ case 1:
+ return kForceDisabled;
+ case 2:
+ return kForceEnabled;
+ case 0:
+ default:
+ return kDefault;
+ }
+}
} // namespace embedder_support
diff --git a/chromium/components/embedder_support/user_agent_utils.h b/chromium/components/embedder_support/user_agent_utils.h
index 4627f8b8a74..a3d756cd1a8 100644
--- a/chromium/components/embedder_support/user_agent_utils.h
+++ b/chromium/components/embedder_support/user_agent_utils.h
@@ -22,20 +22,44 @@ class WebContents;
namespace embedder_support {
-// Returns the product string, e.g. "Chrome/98.0.4521.0". It's possible to have
-// a mismatch between the product's version number and the version number in the
-// User-Agent string, if there are flag-enabled overrides.
-std::string GetProduct();
+// TODO(crbug.com/1291612): Move this enum definition to
+// chrome/browser/chrome_content_browser_client.h
+// TODO(crbug.com/1290820): Remove this enum along with policy.
+enum ForceMajorVersionToMinorPosition {
+ kDefault = 0,
+ kForceDisabled = 1,
+ kForceEnabled = 2,
+};
+
+struct UserAgentOptions {
+ bool force_major_version_100 = false;
+ ForceMajorVersionToMinorPosition force_major_to_minor = kDefault;
+};
+
+// Returns the product string, e.g. "Chrome/98.0.4521.0". If `allow_override`
+// is set to true, it's possible to have a mismatch between the product's
+// version number and the version number in the User-Agent string if there are
+// flag-enabled overrides.
+// TODO(crbug.com/1291612): modify to accept an optional PrefService*.
+std::string GetProduct(
+ bool allow_override = false,
+ ForceMajorVersionToMinorPosition force_major_to_minor = kDefault);
// Returns the user agent string for Chrome.
-std::string GetFullUserAgent();
+// TODO(crbug.com/1291612): modify to accept an optional PrefService*.
+std::string GetFullUserAgent(
+ ForceMajorVersionToMinorPosition force_major_to_minor = kDefault);
// Returns the reduced user agent string for Chrome.
-std::string GetReducedUserAgent();
+// TODO(crbug.com/1291612): modify to accept an optional PrefService*.
+std::string GetReducedUserAgent(
+ ForceMajorVersionToMinorPosition force_major_to_minor = kDefault);
// Returns the full or "reduced" user agent string, depending on the
// UserAgentReduction enterprise policy and blink::features::kReduceUserAgent
-std::string GetUserAgent();
+// TODO(crbug.com/1291612): modify to accept an optional PrefService*.
+std::string GetUserAgent(
+ ForceMajorVersionToMinorPosition force_major_to_minor = kDefault);
// Returns UserAgentMetadata per the default policy.
// This override is currently used in fuchsia, where the enterprise policy
@@ -68,7 +92,7 @@ blink::UserAgentBrandVersion GetGreasedUserAgentBrandVersion(
bool enable_updated_grease_by_policy,
blink::UserAgentBrandVersionType output_version_type);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// This sets a user agent string to simulate a desktop user agent on mobile.
// If |override_in_new_tabs| is true, and the first navigation in the tab is
// renderer initiated, then is-overriding-user-agent is set to true for the
@@ -78,9 +102,15 @@ void SetDesktopUserAgentOverride(content::WebContents* web_contents,
bool override_in_new_tabs);
#endif
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
int GetHighestKnownUniversalApiContractVersionForTesting();
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
+
+// Returns the ForcemajorVersionToMinorPosition enum value corresponding to
+// the provided integer policy value for ForceMajorVersionToMinorPosition.
+// TODO(crbug.com/1290820): Remove this function with policy.
+embedder_support::ForceMajorVersionToMinorPosition GetMajorToMinorFromPrefs(
+ PrefService* pref_service);
} // namespace embedder_support
diff --git a/chromium/components/embedder_support/user_agent_utils_unittest.cc b/chromium/components/embedder_support/user_agent_utils_unittest.cc
index 5129237f856..9bfbd4de7a8 100644
--- a/chromium/components/embedder_support/user_agent_utils_unittest.cc
+++ b/chromium/components/embedder_support/user_agent_utils_unittest.cc
@@ -16,6 +16,9 @@
#include "base/test/scoped_feature_list.h"
#include "base/version.h"
#include "build/build_config.h"
+#include "components/embedder_support/pref_names.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/testing_pref_service.h"
#include "components/version_info/version_info.h"
#include "content/public/common/content_features.h"
#include "content/public/common/content_switches.h"
@@ -26,11 +29,11 @@
#include "third_party/blink/public/common/user_agent/user_agent_metadata.h"
#include "third_party/re2/src/re2/re2.h"
-#if defined(USE_OZONE)
+#if BUILDFLAG(IS_POSIX)
#include <sys/utsname.h>
#endif
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include <windows.foundation.metadata.h>
#include <wrl.h>
@@ -39,7 +42,7 @@
#include "base/win/scoped_hstring.h"
#include "base/win/scoped_winrt_initializer.h"
#include "base/win/windows_version.h"
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
namespace embedder_support {
@@ -49,7 +52,20 @@ namespace {
// the User-Agent string, where the first capture is the {major_version} and the
// second capture is the {minor_version}.
static constexpr char kChromeProductVersionRegex[] =
- "Chrome/([0-9]+)\\.([0-9]+\\.[0-9]+\\.[0-9]+)";
+ "Chrome/([0-9]+).([0-9]+).([0-9]+).([0-9]+)";
+
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+std::string GetMachine() {
+ struct utsname unixinfo;
+ uname(&unixinfo);
+ std::string machine = unixinfo.machine;
+ if (strcmp(unixinfo.machine, "x86_64") == 0 &&
+ sizeof(void*) == sizeof(int32_t)) {
+ machine = "i686 (x86_64)";
+ }
+ return machine;
+}
+#endif
void CheckUserAgentStringOrdering(bool mobile_device) {
std::vector<std::string> pieces;
@@ -86,7 +102,7 @@ void CheckUserAgentStringOrdering(bool mobile_device) {
pieces = base::SplitStringUsingSubstr(os_str, "; ", base::KEEP_WHITESPACE,
base::SPLIT_WANT_ALL);
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// Windows NT 10.0; Win64; x64
// Windows NT 10.0; WOW64
// Windows NT 10.0
@@ -105,7 +121,7 @@ void CheckUserAgentStringOrdering(bool mobile_device) {
ASSERT_TRUE(base::StringToDouble(pieces[2], &version));
ASSERT_LE(4.0, version);
ASSERT_GT(11.0, version);
-#elif defined(OS_MAC)
+#elif BUILDFLAG(IS_MAC)
// Macintosh; Intel Mac OS X 10_15_4
ASSERT_EQ(2u, pieces.size());
ASSERT_EQ("Macintosh", pieces[0]);
@@ -131,42 +147,33 @@ void CheckUserAgentStringOrdering(bool mobile_device) {
ASSERT_LE(0, value);
ASSERT_TRUE(base::StringToInt(pieces[2], &value));
ASSERT_LE(0, value);
-#elif defined(USE_OZONE)
- // X11; Linux x86_64
+#elif BUILDFLAG(IS_CHROMEOS)
// X11; CrOS armv7l 4537.56.0
- struct utsname unixinfo;
- uname(&unixinfo);
- std::string machine = unixinfo.machine;
- if (strcmp(unixinfo.machine, "x86_64") == 0 &&
- sizeof(void*) == sizeof(int32_t)) {
- machine = "i686 (x86_64)";
- }
ASSERT_EQ(2u, pieces.size());
ASSERT_EQ("X11", pieces[0]);
pieces = base::SplitStringUsingSubstr(pieces[1], " ", base::KEEP_WHITESPACE,
base::SPLIT_WANT_ALL);
-#if defined(OS_CHROMEOS)
- // X11; CrOS armv7l 4537.56.0
- // ^^
ASSERT_EQ(3u, pieces.size());
ASSERT_EQ("CrOS", pieces[0]);
- ASSERT_EQ(machine, pieces[1]);
+ ASSERT_EQ(GetMachine(), pieces[1]);
pieces = base::SplitStringUsingSubstr(pieces[2], ".", base::KEEP_WHITESPACE,
base::SPLIT_WANT_ALL);
for (unsigned int i = 1; i < pieces.size(); ++i) {
int value;
ASSERT_TRUE(base::StringToInt(pieces[i], &value));
}
-#else
+#elif BUILDFLAG(IS_LINUX)
// X11; Linux x86_64
- // ^^
+ ASSERT_EQ(2u, pieces.size());
+ ASSERT_EQ("X11", pieces[0]);
+ pieces = base::SplitStringUsingSubstr(pieces[1], " ", base::KEEP_WHITESPACE,
+ base::SPLIT_WANT_ALL);
ASSERT_EQ(2u, pieces.size());
// This may not be Linux in all cases in the wild, but it is on the bots.
ASSERT_EQ("Linux", pieces[0]);
- ASSERT_EQ(machine, pieces[1]);
-#endif
-#elif defined(OS_ANDROID)
- // Linux; Android 7.1.1; Samsung Chromebook 3
+ ASSERT_EQ(GetMachine(), pieces[1]);
+#elif BUILDFLAG(IS_ANDROID)
+ // Linux; Android 7.1.1; Pixel 2
ASSERT_GE(3u, pieces.size());
ASSERT_EQ("Linux", pieces[0]);
std::string model;
@@ -190,11 +197,13 @@ void CheckUserAgentStringOrdering(bool mobile_device) {
else
ASSERT_EQ("", model);
}
-#elif defined(OS_FUCHSIA)
+#elif BUILDFLAG(IS_FUCHSIA)
// X11; Fuchsia
ASSERT_EQ(2u, pieces.size());
ASSERT_EQ("X11", pieces[0]);
ASSERT_EQ("Fuchsia", pieces[1]);
+#else
+#error Unsupported platform
#endif
// Check that the version numbers match.
@@ -211,7 +220,7 @@ void CheckUserAgentStringOrdering(bool mobile_device) {
}
}
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
bool ResolveCoreWinRT() {
return base::win::ResolveCoreWinRTDelayload() &&
base::win::ScopedHString::ResolveCoreWinRTStringDelayload() &&
@@ -283,42 +292,62 @@ void VerifyWinPlatformVersion(std::string version) {
EXPECT_FALSE(is_supported) << " expected major version " << major_version + 1
<< " to not be supported.";
}
-#endif // defined(OS_WIN)
+
+void VerifyLegacyWinPlatformVersion(const std::string& version) {
+ switch (base::win::GetVersion()) {
+ case base::win::Version::WIN7:
+ EXPECT_EQ("0.1.0", version);
+ break;
+ case base::win::Version::WIN8:
+ EXPECT_EQ("0.2.0", version);
+ break;
+ case base::win::Version::WIN8_1:
+ EXPECT_EQ("0.3.0", version);
+ break;
+ default:
+ EXPECT_EQ("0.0.0", version);
+ break;
+ }
+}
+#endif // BUILDFLAG(IS_WIN)
+
+bool ContainsBrandVersion(const blink::UserAgentBrandList& brand_list,
+ const blink::UserAgentBrandVersion brand_version) {
+ for (const auto& brand_list_entry : brand_list) {
+ if (brand_list_entry == brand_version)
+ return true;
+ }
+ return false;
+}
} // namespace
class UserAgentUtilsTest : public testing::Test,
public testing::WithParamInterface<bool> {
public:
- void SetUp() override {
- if (ForceMajorVersionTo100())
- scoped_feature_list_.InitAndEnableFeature(
- blink::features::kForceMajorVersion100InUserAgent);
- }
-
- bool ForceMajorVersionTo100() { return GetParam(); }
-
- std::string M100VersionNumber() {
+ std::string MajorToMinorVersionNumber() {
const base::Version version = version_info::GetVersion();
- std::string m100_version("100");
- // The rest of the version after the major version string is the same.
- for (size_t i = 1; i < version.components().size(); ++i) {
- m100_version.append(".");
- m100_version.append(base::NumberToString(version.components()[i]));
+ std::string version_str;
+ const auto& components = version.components();
+ for (size_t i = 0; i < version.components().size(); ++i) {
+ if (i > 0)
+ version_str.append(".");
+ if (i == 0)
+ version_str.append("99");
+ else if (i == 1)
+ version_str.append(base::NumberToString(components[0]));
+ else
+ version_str.append(base::NumberToString(components[i]));
}
- return m100_version;
+ return version_str;
}
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
-INSTANTIATE_TEST_CASE_P(All,
- UserAgentUtilsTest,
- /*force_major_version_to_M100*/ testing::Bool());
-
-TEST_P(UserAgentUtilsTest, UserAgentStringOrdering) {
-#if defined(OS_ANDROID)
+TEST_F(UserAgentUtilsTest, UserAgentStringOrdering) {
+#if BUILDFLAG(IS_ANDROID)
const char* const kArguments[] = {"chrome"};
base::test::ScopedCommandLine scoped_command_line;
base::CommandLine* command_line = scoped_command_line.GetProcessCommandLine();
@@ -337,11 +366,11 @@ TEST_P(UserAgentUtilsTest, UserAgentStringOrdering) {
#endif
}
-TEST_P(UserAgentUtilsTest, UserAgentStringReduced) {
+TEST_F(UserAgentUtilsTest, UserAgentStringReduced) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeature(blink::features::kReduceUserAgent);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Verify the correct user agent is returned when the UseMobileUserAgent
// command line flag is present.
const char* const kArguments[] = {"chrome"};
@@ -350,8 +379,7 @@ TEST_P(UserAgentUtilsTest, UserAgentStringReduced) {
command_line->InitFromArgv(1, kArguments);
const std::string major_version_number =
version_info::GetMajorVersionNumber();
- const char* const major_version =
- ForceMajorVersionTo100() ? "100" : major_version_number.c_str();
+ const char* const major_version = major_version_number.c_str();
// Verify the mobile user agent string is not returned when not using a mobile
// user agent.
@@ -377,30 +405,106 @@ TEST_P(UserAgentUtilsTest, UserAgentStringReduced) {
content::GetUnifiedPlatform().c_str(),
major_version, device_compat.c_str()));
}
+
+ // Verify that the reduced user agent string respects
+ // --force-major-version-to-minor
+ scoped_feature_list.Reset();
+ scoped_feature_list.InitWithFeatures(
+ {blink::features::kReduceUserAgent,
+ blink::features::kForceMajorVersionInMinorPositionInUserAgent}, {});
+ {
+ std::string buffer = GetReducedUserAgent();
+ std::string device_compat = "Mobile ";
+ EXPECT_EQ(buffer,
+ base::StringPrintf(content::frozen_user_agent_strings::kAndroid,
+ content::GetUnifiedPlatform().c_str(), "99",
+ device_compat.c_str()));
+ }
+
+ // Ensure that the ForceMajorVersionToMinorPosition policy is applied even
+ // when it contradicts Blink feature status values.
+ scoped_feature_list.Reset();
+ scoped_feature_list.InitWithFeatures(
+ {blink::features::kReduceUserAgent,
+ blink::features::kForceMajorVersionInMinorPositionInUserAgent},
+ {});
+ {
+ std::string buffer = GetReducedUserAgent(kForceDisabled);
+ std::string device_compat = "Mobile ";
+ EXPECT_EQ(buffer,
+ base::StringPrintf(content::frozen_user_agent_strings::kAndroid,
+ content::GetUnifiedPlatform().c_str(),
+ major_version, device_compat.c_str()));
+ }
#else
{
std::string buffer = GetUserAgent();
EXPECT_EQ(buffer, base::StringPrintf(
content::frozen_user_agent_strings::kDesktop,
content::GetUnifiedPlatform().c_str(),
- ForceMajorVersionTo100()
- ? "100"
- : version_info::GetMajorVersionNumber().c_str()));
+ version_info::GetMajorVersionNumber().c_str()));
+ }
+
+ // Verify that the reduced user agent string respects
+ // --force-major-version-to-minor
+ scoped_feature_list.Reset();
+ scoped_feature_list.InitWithFeatures(
+ {blink::features::kReduceUserAgent,
+ blink::features::kForceMajorVersionInMinorPositionInUserAgent}, {});
+ {
+ std::string buffer = GetReducedUserAgent();
+ EXPECT_EQ(buffer,
+ base::StringPrintf(content::frozen_user_agent_strings::kDesktop,
+ content::GetUnifiedPlatform().c_str(), "99"));
+ }
+
+ // Ensure that the ForceMajorVersionToMinorPosition policy is applied even
+ // when it contradicts Blink feature status values.
+ scoped_feature_list.Reset();
+ scoped_feature_list.InitWithFeatures(
+ {blink::features::kReduceUserAgent,
+ blink::features::kForceMajorVersionInMinorPositionInUserAgent},
+ {});
+ {
+ std::string buffer = GetReducedUserAgent(kForceDisabled);
+ EXPECT_EQ(buffer,
+ base::StringPrintf(content::frozen_user_agent_strings::kDesktop,
+ content::GetUnifiedPlatform().c_str(), "100"));
}
#endif
EXPECT_EQ(GetUserAgent(), GetReducedUserAgent());
}
-TEST_P(UserAgentUtilsTest, UserAgentMetadata) {
- auto metadata = GetUserAgentMetadata();
+TEST_F(UserAgentUtilsTest, UserAgentStringFull) {
+ base::test::ScopedFeatureList scoped_feature_list;
+
+ // Verify that the full user agent string respects
+ // --force-major-version-to-minor
+ scoped_feature_list.Reset();
+ scoped_feature_list.InitWithFeatures(
+ {blink::features::kFullUserAgent,
+ blink::features::kForceMajorVersionInMinorPositionInUserAgent},
+ {});
+ { EXPECT_EQ(GetUserAgent(), GetFullUserAgent()); }
+
+ // Verify that the full user agent string when both reduced and full UA
+ // feature enabled respects
+ // --force-major-version-to-minor
+ scoped_feature_list.Reset();
+ scoped_feature_list.InitWithFeatures(
+ {blink::features::kFullUserAgent, blink::features::kReduceUserAgent,
+ blink::features::kForceMajorVersionInMinorPositionInUserAgent},
+ {});
+ { EXPECT_EQ(GetUserAgent(), GetFullUserAgent()); }
+}
- const std::string major_version =
- ForceMajorVersionTo100() ? "100" : version_info::GetMajorVersionNumber();
+TEST_F(UserAgentUtilsTest, UserAgentMetadata) {
+ auto metadata = GetUserAgentMetadata();
- const std::string full_version = ForceMajorVersionTo100()
- ? M100VersionNumber()
- : version_info::GetVersionNumber();
+ const std::string major_version = version_info::GetMajorVersionNumber();
+ const std::string full_version = version_info::GetVersionNumber();
+ const std::string major_to_minor_full_version = MajorToMinorVersionNumber();
// According to spec, Sec-CH-UA should contain what project the browser is
// based on (i.e. Chromium in this case) as well as the actual product.
@@ -409,48 +513,85 @@ TEST_P(UserAgentUtilsTest, UserAgentMetadata) {
const blink::UserAgentBrandVersion chromium_brand_version = {"Chromium",
major_version};
+ const blink::UserAgentBrandVersion major_to_minor_chromium_brand_version = {
+ "Chromium", "99"};
const blink::UserAgentBrandVersion product_brand_version = {
version_info::GetProductName(), major_version};
- bool contains_chromium_brand_version = false;
- bool contains_product_brand_version = false;
-
- for (const auto& brand_version : metadata.brand_version_list) {
- if (brand_version == chromium_brand_version) {
- contains_chromium_brand_version = true;
- }
- if (brand_version == product_brand_version) {
- contains_product_brand_version = true;
- }
- }
+ const blink::UserAgentBrandVersion major_to_minor_product_brand_version = {
+ version_info::GetProductName(), "99"};
- EXPECT_TRUE(contains_chromium_brand_version);
- EXPECT_TRUE(contains_product_brand_version);
+ EXPECT_TRUE(ContainsBrandVersion(metadata.brand_version_list,
+ chromium_brand_version));
+ EXPECT_TRUE(
+ ContainsBrandVersion(metadata.brand_version_list, product_brand_version));
// verify full version list
const blink::UserAgentBrandVersion chromium_brand_full_version = {
"Chromium", full_version};
+ const blink::UserAgentBrandVersion
+ major_to_minor_chromium_brand_full_version = {
+ "Chromium", major_to_minor_full_version};
const blink::UserAgentBrandVersion product_brand_full_version = {
version_info::GetProductName(), full_version};
- bool contains_chromium_brand_full_version = false;
- bool contains_product_brand_full_version = false;
+ const blink::UserAgentBrandVersion major_to_minor_product_brand_full_version =
+ {version_info::GetProductName(), major_to_minor_full_version};
- for (const auto& brand_version : metadata.brand_full_version_list) {
- if (brand_version == chromium_brand_full_version) {
- contains_chromium_brand_full_version = true;
- }
- if (brand_version == product_brand_full_version) {
- contains_product_brand_full_version = true;
- }
- }
+ EXPECT_TRUE(ContainsBrandVersion(metadata.brand_full_version_list,
+ chromium_brand_full_version));
+ EXPECT_TRUE(ContainsBrandVersion(metadata.brand_full_version_list,
+ product_brand_full_version));
+ EXPECT_EQ(metadata.full_version, full_version);
- EXPECT_TRUE(contains_chromium_brand_full_version);
- EXPECT_TRUE(contains_product_brand_full_version);
+ // Ensure ForceMajorVersionToMinorPosition is respected,
+ TestingPrefServiceSimple pref_service;
+ // ForceMajorVersionToMinorPosition: kForceDisabled
+ pref_service.registry()->RegisterIntegerPref(
+ kForceMajorVersionToMinorPosition, kForceDisabled);
+ metadata = GetUserAgentMetadata(&pref_service);
EXPECT_EQ(metadata.full_version, full_version);
-
-#if defined(OS_WIN)
+ EXPECT_TRUE(ContainsBrandVersion(metadata.brand_version_list,
+ chromium_brand_version));
+ EXPECT_TRUE(
+ ContainsBrandVersion(metadata.brand_version_list, product_brand_version));
+ EXPECT_TRUE(ContainsBrandVersion(metadata.brand_full_version_list,
+ chromium_brand_full_version));
+ EXPECT_TRUE(ContainsBrandVersion(metadata.brand_full_version_list,
+ product_brand_full_version));
+ EXPECT_FALSE(ContainsBrandVersion(metadata.brand_version_list,
+ major_to_minor_chromium_brand_version));
+ EXPECT_FALSE(ContainsBrandVersion(metadata.brand_version_list,
+ major_to_minor_product_brand_version));
+ EXPECT_FALSE(
+ ContainsBrandVersion(metadata.brand_full_version_list,
+ major_to_minor_chromium_brand_full_version));
+ EXPECT_FALSE(ContainsBrandVersion(metadata.brand_full_version_list,
+ major_to_minor_product_brand_full_version));
+
+ // ForceMajorVersionToMinorPosition: kForceEnabled
+ pref_service.SetInteger(kForceMajorVersionToMinorPosition, kForceEnabled);
+ metadata = GetUserAgentMetadata(&pref_service);
+ EXPECT_EQ(metadata.full_version, major_to_minor_full_version);
+ EXPECT_TRUE(ContainsBrandVersion(metadata.brand_version_list,
+ major_to_minor_chromium_brand_version));
+ EXPECT_TRUE(ContainsBrandVersion(metadata.brand_version_list,
+ major_to_minor_product_brand_version));
+ EXPECT_TRUE(ContainsBrandVersion(metadata.brand_full_version_list,
+ major_to_minor_chromium_brand_full_version));
+ EXPECT_TRUE(ContainsBrandVersion(metadata.brand_full_version_list,
+ major_to_minor_product_brand_full_version));
+ EXPECT_FALSE(ContainsBrandVersion(metadata.brand_version_list,
+ chromium_brand_version));
+ EXPECT_FALSE(
+ ContainsBrandVersion(metadata.brand_version_list, product_brand_version));
+ EXPECT_FALSE(ContainsBrandVersion(metadata.brand_full_version_list,
+ chromium_brand_full_version));
+ EXPECT_FALSE(ContainsBrandVersion(metadata.brand_full_version_list,
+ product_brand_full_version));
+
+#if BUILDFLAG(IS_WIN)
if (base::win::GetVersion() < base::win::Version::WIN10) {
- EXPECT_EQ(metadata.platform_version, "0.0.0");
+ VerifyLegacyWinPlatformVersion(metadata.platform_version);
} else {
VerifyWinPlatformVersion(metadata.platform_version);
}
@@ -464,7 +605,7 @@ TEST_P(UserAgentUtilsTest, UserAgentMetadata) {
EXPECT_EQ(metadata.platform_version.find(";"), std::string::npos);
// TODO(crbug.com/1103047): This can be removed/re-refactored once we use
// "macOS" by default
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
EXPECT_EQ(metadata.platform, "macOS");
#else
EXPECT_EQ(metadata.platform, version_info::GetOSType());
@@ -472,9 +613,10 @@ TEST_P(UserAgentUtilsTest, UserAgentMetadata) {
EXPECT_EQ(metadata.architecture, content::GetLowEntropyCpuArchitecture());
EXPECT_EQ(metadata.model, content::BuildModelInfo());
EXPECT_EQ(metadata.bitness, content::GetLowEntropyCpuBitness());
+ EXPECT_EQ(metadata.wow64, content::IsWoW64());
}
-TEST_P(UserAgentUtilsTest, GenerateBrandVersionList) {
+TEST_F(UserAgentUtilsTest, GenerateBrandVersionList) {
blink::UserAgentMetadata metadata;
metadata.brand_version_list = GenerateBrandVersionList(
@@ -525,6 +667,9 @@ TEST_P(UserAgentUtilsTest, GenerateBrandVersionList) {
"\"Chromium\";v=\"84.0.0.0\", ",
"\"Totally A Brand\";v=\"84.0.0.0\""}),
brand_list_w_brand_fv);
+
+ // The old GREASE generation algorithm should not respond to experiment
+ // overrides.
metadata.brand_version_list = GenerateBrandVersionList(
84, absl::nullopt, "84", "Clean GREASE", absl::nullopt, true,
blink::UserAgentBrandVersionType::kMajorVersion);
@@ -534,15 +679,13 @@ TEST_P(UserAgentUtilsTest, GenerateBrandVersionList) {
// 1. verify major version
std::string brand_list_grease_override =
metadata.SerializeBrandMajorVersionList();
- EXPECT_EQ(R"("Clean GREASE";v="99", "Chromium";v="84")",
+ EXPECT_EQ(R"(" Not A;Brand";v="99", "Chromium";v="84")",
brand_list_grease_override);
- EXPECT_NE(brand_list, brand_list_grease_override);
// 2. verify full version
std::string brand_list_grease_override_fv =
metadata.SerializeBrandFullVersionList();
- EXPECT_EQ(R"("Clean GREASE";v="99.0.0.0", "Chromium";v="84.0.0.0")",
+ EXPECT_EQ(R"(" Not A;Brand";v="99.0.0.0", "Chromium";v="84.0.0.0")",
brand_list_grease_override_fv);
- EXPECT_NE(brand_list_w_fv, brand_list_grease_override_fv);
metadata.brand_version_list = GenerateBrandVersionList(
84, absl::nullopt, "84", "Clean GREASE", "1024", true,
@@ -553,15 +696,13 @@ TEST_P(UserAgentUtilsTest, GenerateBrandVersionList) {
// 1. verify major version
std::string brand_list_and_version_grease_override =
metadata.SerializeBrandMajorVersionList();
- EXPECT_EQ(R"("Clean GREASE";v="1024", "Chromium";v="84")",
+ EXPECT_EQ(R"(" Not A;Brand";v="99", "Chromium";v="84")",
brand_list_and_version_grease_override);
- EXPECT_NE(brand_list, brand_list_and_version_grease_override);
// 2. verify full version
std::string brand_list_and_version_grease_override_fv =
metadata.SerializeBrandFullVersionList();
- EXPECT_EQ(R"("Clean GREASE";v="1024.0.0.0", "Chromium";v="84.0.0.0")",
+ EXPECT_EQ(R"(" Not A;Brand";v="99.0.0.0", "Chromium";v="84.0.0.0")",
brand_list_and_version_grease_override_fv);
- EXPECT_NE(brand_list_w_fv, brand_list_and_version_grease_override_fv);
metadata.brand_version_list = GenerateBrandVersionList(
84, absl::nullopt, "84", absl::nullopt, "1024", true,
@@ -572,15 +713,13 @@ TEST_P(UserAgentUtilsTest, GenerateBrandVersionList) {
// 1. verify major version
std::string brand_version_grease_override =
metadata.SerializeBrandMajorVersionList();
- EXPECT_EQ(R"(" Not A;Brand";v="1024", "Chromium";v="84")",
+ EXPECT_EQ(R"(" Not A;Brand";v="99", "Chromium";v="84")",
brand_version_grease_override);
- EXPECT_NE(brand_list, brand_version_grease_override);
// 2. verify full version
std::string brand_version_grease_override_fv =
metadata.SerializeBrandFullVersionList();
- EXPECT_EQ(R"(" Not A;Brand";v="1024.0.0.0", "Chromium";v="84.0.0.0")",
+ EXPECT_EQ(R"(" Not A;Brand";v="99.0.0.0", "Chromium";v="84.0.0.0")",
brand_version_grease_override_fv);
- EXPECT_NE(brand_list_w_fv, brand_version_grease_override_fv);
// Should DCHECK on negative numbers
EXPECT_DCHECK_DEATH(GenerateBrandVersionList(
@@ -591,7 +730,7 @@ TEST_P(UserAgentUtilsTest, GenerateBrandVersionList) {
blink::UserAgentBrandVersionType::kFullVersion));
}
-TEST_P(UserAgentUtilsTest, GetGreasedUserAgentBrandVersion) {
+TEST_F(UserAgentUtilsTest, GetGreasedUserAgentBrandVersion) {
base::test::ScopedFeatureList scoped_feature_list;
// Test to ensure the old algorithm is respected when the flag is not set.
scoped_feature_list.InitAndEnableFeatureWithParameters(
@@ -610,41 +749,43 @@ TEST_P(UserAgentUtilsTest, GetGreasedUserAgentBrandVersion) {
EXPECT_EQ(greased_bv.brand, " Not A;Brand");
EXPECT_EQ(greased_bv.version, "99.0.0.0");
+ // With the new algorithm disabled, we want to avoid experiment params
+ // ("WhatIsGrease", 1024) from taking an effect.
greased_bv = GetGreasedUserAgentBrandVersion(
permuted_order, 84, "WhatIsGrease", absl::nullopt, true,
blink::UserAgentBrandVersionType::kMajorVersion);
- EXPECT_EQ(greased_bv.brand, "WhatIsGrease");
+ EXPECT_EQ(greased_bv.brand, " Not A;Brand");
EXPECT_EQ(greased_bv.version, "99");
greased_bv = GetGreasedUserAgentBrandVersion(
permuted_order, 84, "WhatIsGrease", absl::nullopt, true,
blink::UserAgentBrandVersionType::kFullVersion);
- EXPECT_EQ(greased_bv.brand, "WhatIsGrease");
+ EXPECT_EQ(greased_bv.brand, " Not A;Brand");
EXPECT_EQ(greased_bv.version, "99.0.0.0");
greased_bv = GetGreasedUserAgentBrandVersion(
permuted_order, 84, absl::nullopt, "1024", true,
blink::UserAgentBrandVersionType::kMajorVersion);
EXPECT_EQ(greased_bv.brand, " Not A;Brand");
- EXPECT_EQ(greased_bv.version, "1024");
+ EXPECT_EQ(greased_bv.version, "99");
greased_bv = GetGreasedUserAgentBrandVersion(
permuted_order, 84, absl::nullopt, "1024", true,
blink::UserAgentBrandVersionType::kFullVersion);
EXPECT_EQ(greased_bv.brand, " Not A;Brand");
- EXPECT_EQ(greased_bv.version, "1024.0.0.0");
+ EXPECT_EQ(greased_bv.version, "99.0.0.0");
greased_bv = GetGreasedUserAgentBrandVersion(
permuted_order, 84, "WhatIsGrease", "1024", true,
blink::UserAgentBrandVersionType::kMajorVersion);
- EXPECT_EQ(greased_bv.brand, "WhatIsGrease");
- EXPECT_EQ(greased_bv.version, "1024");
+ EXPECT_EQ(greased_bv.brand, " Not A;Brand");
+ EXPECT_EQ(greased_bv.version, "99");
greased_bv = GetGreasedUserAgentBrandVersion(
permuted_order, 84, "WhatIsGrease", "1024", true,
blink::UserAgentBrandVersionType::kFullVersion);
- EXPECT_EQ(greased_bv.brand, "WhatIsGrease");
- EXPECT_EQ(greased_bv.version, "1024.0.0.0");
+ EXPECT_EQ(greased_bv.brand, " Not A;Brand");
+ EXPECT_EQ(greased_bv.version, "99.0.0.0");
// Test to ensure the new algorithm works and is still overridable.
scoped_feature_list.Reset();
@@ -756,27 +897,52 @@ TEST_P(UserAgentUtilsTest, GetGreasedUserAgentBrandVersion) {
}
}
-TEST_P(UserAgentUtilsTest, GetProduct) {
- const std::string product = GetProduct();
+TEST_F(UserAgentUtilsTest, GetProduct) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndDisableFeature(
+ blink::features::kForceMajorVersionInMinorPositionInUserAgent);
+
+ std::string product = GetProduct(/*allow_override=*/false);
std::string major_version;
EXPECT_TRUE(
re2::RE2::FullMatch(product, kChromeProductVersionRegex, &major_version));
- // Whether the force M100 experiment is on or not, the product value should
- // contain the actual major version number.
+ EXPECT_EQ(major_version, version_info::GetMajorVersionNumber());
+
+ // Ensure the policy is ignored if allow_override is false
+ product = GetProduct(/*allow_override=*/false,
+ /*force_major_to_minor=*/kForceEnabled);
+ EXPECT_TRUE(
+ re2::RE2::FullMatch(product, kChromeProductVersionRegex, &major_version));
+ EXPECT_EQ(major_version, version_info::GetMajorVersionNumber());
+
+ // Ensure policy is respected if ForceMajorToMinor is force enabled
+ product = GetProduct(/*allow_override=*/true,
+ /*force_major_to_minor=*/kForceEnabled);
+ EXPECT_TRUE(
+ re2::RE2::FullMatch(product, kChromeProductVersionRegex, &major_version));
+ EXPECT_EQ(major_version, "99");
+
+ // Ensure policy is respected if ForcemajorToMinor is force disabled, even if
+ // the respective Blink feature is enabled.
+ scoped_feature_list.Reset();
+ scoped_feature_list.InitAndEnableFeature(
+ blink::features::kForceMajorVersionInMinorPositionInUserAgent);
+ product = GetProduct(/*allow_override=*/true,
+ /*force_major_to_minor=*/kForceDisabled);
+ EXPECT_TRUE(
+ re2::RE2::FullMatch(product, kChromeProductVersionRegex, &major_version));
EXPECT_EQ(major_version, version_info::GetMajorVersionNumber());
}
-TEST_P(UserAgentUtilsTest, GetUserAgent) {
+TEST_F(UserAgentUtilsTest, GetUserAgent) {
const std::string ua = GetUserAgent();
std::string major_version;
std::string minor_version;
EXPECT_TRUE(re2::RE2::PartialMatch(ua, kChromeProductVersionRegex,
&major_version, &minor_version));
- if (ForceMajorVersionTo100())
- EXPECT_EQ(major_version, "100");
- else
- EXPECT_EQ(major_version, version_info::GetMajorVersionNumber());
- EXPECT_NE(minor_version, "0.0.0");
+ EXPECT_EQ(major_version, version_info::GetMajorVersionNumber());
+ // Minor version should contain the actual minor version number.
+ EXPECT_EQ(minor_version, "0");
}
class UserAgentUtilsMinorVersionTest
@@ -784,33 +950,15 @@ class UserAgentUtilsMinorVersionTest
public testing::WithParamInterface<bool> {
public:
void SetUp() override {
- if (ForceMinorVersionTo100())
+ if (ForceMajorInMinorVersion())
scoped_feature_list_.InitAndEnableFeature(
- blink::features::kForceMinorVersion100InUserAgent);
+ blink::features::kForceMajorVersionInMinorPositionInUserAgent);
}
- bool ForceMinorVersionTo100() { return GetParam(); }
+ bool ForceMajorInMinorVersion() { return GetParam(); }
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
-INSTANTIATE_TEST_CASE_P(All,
- UserAgentUtilsMinorVersionTest,
- /*force_minor_version_to_M100*/ testing::Bool());
-
-TEST_P(UserAgentUtilsMinorVersionTest, GetUserAgent) {
- const std::string ua = GetUserAgent();
- std::string major_version;
- std::string minor_version;
- EXPECT_TRUE(re2::RE2::PartialMatch(ua, kChromeProductVersionRegex,
- &major_version, &minor_version));
- EXPECT_EQ(major_version, version_info::GetMajorVersionNumber());
- if (ForceMinorVersionTo100()) {
- EXPECT_NE(minor_version, "100.0.0");
- } else {
- EXPECT_NE(minor_version, "0.0.0");
- }
-}
-
} // namespace embedder_support
diff --git a/chromium/components/enterprise/BUILD.gn b/chromium/components/enterprise/BUILD.gn
index 50faae4df52..7ccdab80861 100644
--- a/chromium/components/enterprise/BUILD.gn
+++ b/chromium/components/enterprise/BUILD.gn
@@ -8,10 +8,18 @@ static_library("enterprise") {
sources = [
"browser/reporting/browser_report_generator.cc",
"browser/reporting/browser_report_generator.h",
+ "browser/reporting/chrome_profile_request_generator.cc",
+ "browser/reporting/chrome_profile_request_generator.h",
+ "browser/reporting/cloud_profile_reporting_policy_handler.cc",
+ "browser/reporting/cloud_profile_reporting_policy_handler.h",
+ "browser/reporting/cloud_reporting_frequency_policy_handler.cc",
+ "browser/reporting/cloud_reporting_frequency_policy_handler.h",
"browser/reporting/cloud_reporting_policy_handler.cc",
"browser/reporting/cloud_reporting_policy_handler.h",
"browser/reporting/common_pref_names.cc",
"browser/reporting/common_pref_names.h",
+ "browser/reporting/os_report_generator.cc",
+ "browser/reporting/os_report_generator.h",
"browser/reporting/policy_info.cc",
"browser/reporting/policy_info.h",
"browser/reporting/profile_report_generator.cc",
@@ -22,7 +30,8 @@ static_library("enterprise") {
"browser/reporting/real_time_uploader.h",
"browser/reporting/report_generator.cc",
"browser/reporting/report_generator.h",
- "browser/reporting/report_request_definition.h",
+ "browser/reporting/report_request.cc",
+ "browser/reporting/report_request.h",
"browser/reporting/report_request_queue_generator.cc",
"browser/reporting/report_request_queue_generator.h",
"browser/reporting/report_scheduler.cc",
@@ -90,33 +99,41 @@ static_library("test_support") {
source_set("unit_tests") {
testonly = true
- sources = []
- deps = []
+ sources = [
+ "browser/reporting/chrome_profile_request_generator_unittest.cc",
+ "browser/reporting/report_uploader_unittest.cc",
+ ]
+
+ deps = [
+ ":enterprise",
+ "//base/test:test_support",
+ "//build:chromeos_buildflags",
+ "//components/policy/core/common:test_support",
+ "//components/version_info",
+ "//testing/gmock",
+ "//testing/gtest",
+ ]
if (!is_chromeos_ash) {
sources += [
"browser/controller/browser_dm_token_storage_unittest.cc",
"browser/reporting/cloud_reporting_policy_handler_unittest.cc",
- "browser/reporting/report_uploader_unittest.cc",
]
deps += [
- ":enterprise",
":test_support",
"//base",
- "//base/test:test_support",
- "//build:chromeos_buildflags",
- "//components/enterprise/common/proto:extensions_workflow_events_proto",
"//components/policy/core/browser:test_support",
- "//components/policy/core/common:test_support",
"//components/prefs:test_support",
- "//components/reporting/client:test_support",
- "//testing/gmock",
- "//testing/gtest",
]
}
- if (!is_android && !is_chromeos_ash) {
+ if (!is_android) {
sources += [ "browser/reporting/real_time_uploader_unittest.cc" ]
+ deps += [
+ "//base",
+ "//components/enterprise/common/proto:extensions_workflow_events_proto",
+ "//components/reporting/client:test_support",
+ ]
}
}
diff --git a/chromium/components/enterprise/OWNERS b/chromium/components/enterprise/OWNERS
index c389b616a58..62fb4122ae7 100644
--- a/chromium/components/enterprise/OWNERS
+++ b/chromium/components/enterprise/OWNERS
@@ -1,8 +1,8 @@
domfc@chromium.org
emaxx@chromium.org
+ftirelo@chromium.org
nicolaso@chromium.org
pastarmovj@chromium.org
pmarko@chromium.org
rogerta@chromium.org
zmin@chromium.org
-
diff --git a/chromium/components/enterprise/browser/controller/chrome_browser_cloud_management_controller.cc b/chromium/components/enterprise/browser/controller/chrome_browser_cloud_management_controller.cc
index fcd3aad3f6f..ccd3256c93f 100644
--- a/chromium/components/enterprise/browser/controller/chrome_browser_cloud_management_controller.cc
+++ b/chromium/components/enterprise/browser/controller/chrome_browser_cloud_management_controller.cc
@@ -30,10 +30,10 @@
#include "components/policy/core/common/configuration_policy_provider.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
#include "components/enterprise/browser/reporting/report_generator.h"
#include "components/enterprise/browser/reporting/report_scheduler.h"
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
namespace policy {
@@ -364,7 +364,7 @@ void ChromeBrowserCloudManagementController::NotifyBrowserUnenrolled(
void ChromeBrowserCloudManagementController::NotifyCloudReportingLaunched() {
for (auto& observer : observers_) {
- observer.OnCloudReportingLaunched();
+ observer.OnCloudReportingLaunched(report_scheduler_.get());
}
}
@@ -444,14 +444,17 @@ void ChromeBrowserCloudManagementController::CreateReportScheduler() {
cloud_policy_client_->AddObserver(this);
auto reporting_delegate_factory = delegate_->GetReportingDelegateFactory();
- auto generator = std::make_unique<enterprise_reporting::ReportGenerator>(
- reporting_delegate_factory.get());
- auto real_time_generator =
+ enterprise_reporting::ReportScheduler::CreateParams params;
+ params.client = cloud_policy_client_.get();
+ params.delegate = reporting_delegate_factory->GetReportSchedulerDelegate();
+ params.report_generator =
+ std::make_unique<enterprise_reporting::ReportGenerator>(
+ reporting_delegate_factory.get());
+ params.real_time_report_generator =
std::make_unique<enterprise_reporting::RealTimeReportGenerator>(
reporting_delegate_factory.get());
report_scheduler_ = std::make_unique<enterprise_reporting::ReportScheduler>(
- cloud_policy_client_.get(), std::move(generator),
- std::move(real_time_generator), reporting_delegate_factory.get());
+ std::move(params));
NotifyCloudReportingLaunched();
}
diff --git a/chromium/components/enterprise/browser/controller/chrome_browser_cloud_management_controller.h b/chromium/components/enterprise/browser/controller/chrome_browser_cloud_management_controller.h
index ec8e5b00d42..46475346e5a 100644
--- a/chromium/components/enterprise/browser/controller/chrome_browser_cloud_management_controller.h
+++ b/chromium/components/enterprise/browser/controller/chrome_browser_cloud_management_controller.h
@@ -175,7 +175,8 @@ class ChromeBrowserCloudManagementController
virtual void OnBrowserUnenrolled(bool succeeded) {}
// Called when the cloud reporting is launched.
- virtual void OnCloudReportingLaunched() {}
+ virtual void OnCloudReportingLaunched(
+ enterprise_reporting::ReportScheduler* report_scheduler) {}
// Called when enrollment result is recorded.
virtual void OnEnrollmentResultRecorded() {}
diff --git a/chromium/components/enterprise/browser/device_trust/device_trust_key_manager.h b/chromium/components/enterprise/browser/device_trust/device_trust_key_manager.h
index c7c6cc1607f..f77c532eb75 100644
--- a/chromium/components/enterprise/browser/device_trust/device_trust_key_manager.h
+++ b/chromium/components/enterprise/browser/device_trust/device_trust_key_manager.h
@@ -27,6 +27,12 @@ class DeviceTrustKeyManager {
crypto::SignatureVerifier::SignatureAlgorithm algorithm;
};
+ enum class KeyRotationResult {
+ SUCCESS = 0,
+ FAILURE = 1,
+ CANCELLATION = 2,
+ };
+
// Starts the initialization of the manager which includes trying to load the
// signing key, or kicking off its creation. This function is idempotent, so
// only the initial call matters (subsequent calls will be ignored).
@@ -34,7 +40,11 @@ class DeviceTrustKeyManager {
// Starts a key rotation sequence which will update the serialized key,
// upload it to the server using the `nonce`, and then update the cached key.
- virtual void StartKeyRotation(const std::string& nonce) = 0;
+ // Invokes `callback` upon completing the rotation with an enum parameter
+ // indicating the outcome for the request.
+ virtual void RotateKey(
+ const std::string& nonce,
+ base::OnceCallback<void(KeyRotationResult)> callback) = 0;
// Asynchronously exports the signing key pair's public key into a string.
// Invokes `callback` with that string when it is available.
diff --git a/chromium/components/enterprise/browser/reporting/OWNERS b/chromium/components/enterprise/browser/reporting/OWNERS
new file mode 100644
index 00000000000..3cb2517171b
--- /dev/null
+++ b/chromium/components/enterprise/browser/reporting/OWNERS
@@ -0,0 +1,3 @@
+ftirelo@chromium.org
+pastarmovj@chromium.org
+zmin@chromium.org
diff --git a/chromium/components/enterprise/browser/reporting/browser_report_generator.cc b/chromium/components/enterprise/browser/reporting/browser_report_generator.cc
index 324eb326ff7..6c46aab7811 100644
--- a/chromium/components/enterprise/browser/reporting/browser_report_generator.cc
+++ b/chromium/components/enterprise/browser/reporting/browser_report_generator.cc
@@ -28,13 +28,16 @@ BrowserReportGenerator::~BrowserReportGenerator() = default;
void BrowserReportGenerator::Generate(ReportType report_type,
ReportCallback callback) {
auto report = std::make_unique<em::BrowserReport>();
- if (report_type != ReportType::kProfileReport)
- GenerateProfileInfo(report.get());
GenerateBasicInfo(report.get(), report_type);
- // std::move is required here because the function completes the report
- // asynchronously.
- delegate_->GeneratePluginsIfNeeded(std::move(callback), std::move(report));
+ if (report_type != ReportType::kProfileReport) {
+ GenerateProfileInfo(report.get());
+ // std::move is required here because the function completes the report
+ // asynchronously.
+ delegate_->GeneratePluginsIfNeeded(std::move(callback), std::move(report));
+ } else {
+ std::move(callback).Run(std::move(report));
+ }
}
void BrowserReportGenerator::GenerateProfileInfo(em::BrowserReport* report) {
@@ -49,13 +52,21 @@ void BrowserReportGenerator::GenerateProfileInfo(em::BrowserReport* report) {
void BrowserReportGenerator::GenerateBasicInfo(em::BrowserReport* report,
ReportType report_type) {
-#if !BUILDFLAG(IS_CHROMEOS_ASH)
- report->set_browser_version(version_info::GetVersionNumber());
- report->set_channel(policy::ConvertToProtoChannel(delegate_->GetChannel()));
- if (delegate_->IsExtendedStableChannel())
- report->set_is_extended_stable_channel(true);
- delegate_->GenerateBuildStateInfo(report);
-#endif
+ // Chrome OS user session report doesn't include version and channel
+ // information.
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+ bool contains_version_and_channel = report_type == ReportType::kProfileReport;
+#else
+ bool contains_version_and_channel = true;
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
+
+ if (contains_version_and_channel) {
+ report->set_browser_version(version_info::GetVersionNumber());
+ report->set_channel(policy::ConvertToProtoChannel(delegate_->GetChannel()));
+ if (delegate_->IsExtendedStableChannel())
+ report->set_is_extended_stable_channel(true);
+ delegate_->GenerateBuildStateInfo(report);
+ }
switch (report_type) {
case ReportType::kFull:
diff --git a/chromium/components/enterprise/browser/reporting/chrome_profile_request_generator.cc b/chromium/components/enterprise/browser/reporting/chrome_profile_request_generator.cc
new file mode 100644
index 00000000000..6658f9828a0
--- /dev/null
+++ b/chromium/components/enterprise/browser/reporting/chrome_profile_request_generator.cc
@@ -0,0 +1,56 @@
+// Copyright 2022 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.
+
+#include "components/enterprise/browser/reporting/chrome_profile_request_generator.h"
+
+#include <utility>
+
+#include "base/callback.h"
+#include "components/enterprise/browser/reporting/os_report_generator.h"
+#include "components/enterprise/browser/reporting/report_type.h"
+#include "components/enterprise/browser/reporting/reporting_delegate_factory.h"
+
+namespace enterprise_reporting {
+
+namespace em = enterprise_management;
+
+ChromeProfileRequestGenerator::ChromeProfileRequestGenerator(
+ const base::FilePath& profile_path,
+ const std::string& profile_name,
+ ReportingDelegateFactory* delegate_factory)
+ : profile_path_(profile_path),
+ profile_name_(profile_name),
+ browser_report_generator_(delegate_factory),
+ profile_report_generator_(delegate_factory) {}
+
+ChromeProfileRequestGenerator::~ChromeProfileRequestGenerator() = default;
+
+void ChromeProfileRequestGenerator::Generate(ReportCallback callback) {
+ auto request = std::make_unique<ReportRequest>(ReportType::kProfileReport);
+ request->GetChromeProfileReportRequest().set_allocated_os_report(
+ GetOSReport().release());
+ browser_report_generator_.Generate(
+ ReportType::kProfileReport,
+ base::BindOnce(&ChromeProfileRequestGenerator::OnBrowserReportReady,
+ weak_ptr_factory_.GetWeakPtr(), std::move(request),
+ std::move(callback)));
+}
+
+void ChromeProfileRequestGenerator::OnBrowserReportReady(
+ std::unique_ptr<ReportRequest> request,
+ ReportCallback callback,
+ std::unique_ptr<em::BrowserReport> browser_report) {
+ auto profile_report = profile_report_generator_.MaybeGenerate(
+ profile_path_, profile_name_, ReportType::kProfileReport);
+
+ browser_report->add_chrome_user_profile_infos()->Swap(profile_report.get());
+
+ request->GetChromeProfileReportRequest().set_allocated_browser_report(
+ browser_report.release());
+ ReportRequestQueue requests;
+ requests.push(std::move(request));
+ std::move(callback).Run(std::move(requests));
+}
+
+} // namespace enterprise_reporting
diff --git a/chromium/components/enterprise/browser/reporting/chrome_profile_request_generator.h b/chromium/components/enterprise/browser/reporting/chrome_profile_request_generator.h
new file mode 100644
index 00000000000..12161e1fd5d
--- /dev/null
+++ b/chromium/components/enterprise/browser/reporting/chrome_profile_request_generator.h
@@ -0,0 +1,54 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_ENTERPRISE_BROWSER_REPORTING_CHROME_PROFILE_REQUEST_GENERATOR_H_
+#define COMPONENTS_ENTERPRISE_BROWSER_REPORTING_CHROME_PROFILE_REQUEST_GENERATOR_H_
+
+#include <memory>
+#include <string>
+
+#include "base/callback_forward.h"
+#include "base/files/file_path.h"
+#include "base/memory/weak_ptr.h"
+#include "components/enterprise/browser/reporting/browser_report_generator.h"
+#include "components/enterprise/browser/reporting/profile_report_generator.h"
+#include "components/enterprise/browser/reporting/report_request.h"
+
+namespace enterprise_reporting {
+
+class ReportingDelegateFactory;
+
+// The top level generator that creates ChromeProfileRequest proto.
+class ChromeProfileRequestGenerator {
+ public:
+ using ReportCallback = base::OnceCallback<void(ReportRequestQueue)>;
+
+ ChromeProfileRequestGenerator(const base::FilePath& profile_path,
+ const std::string& profile_name,
+ ReportingDelegateFactory* delegate_factory);
+ ChromeProfileRequestGenerator(const ChromeProfileRequestGenerator&) = delete;
+ ChromeProfileRequestGenerator& operator=(
+ const ChromeProfileRequestGenerator&) = delete;
+
+ virtual ~ChromeProfileRequestGenerator();
+
+ virtual void Generate(ReportCallback callback);
+
+ private:
+ void OnBrowserReportReady(
+ std::unique_ptr<ReportRequest> request,
+ ReportCallback callback,
+ std::unique_ptr<enterprise_management::BrowserReport> browser_report);
+
+ const base::FilePath profile_path_;
+ const std::string profile_name_;
+
+ BrowserReportGenerator browser_report_generator_;
+ ProfileReportGenerator profile_report_generator_;
+ base::WeakPtrFactory<ChromeProfileRequestGenerator> weak_ptr_factory_{this};
+};
+
+} // namespace enterprise_reporting
+
+#endif // COMPONENTS_ENTERPRISE_BROWSER_REPORTING_CHROME_PROFILE_REQUEST_GENERATOR_H_
diff --git a/chromium/components/enterprise/browser/reporting/chrome_profile_request_generator_unittest.cc b/chromium/components/enterprise/browser/reporting/chrome_profile_request_generator_unittest.cc
new file mode 100644
index 00000000000..04ab69ff30d
--- /dev/null
+++ b/chromium/components/enterprise/browser/reporting/chrome_profile_request_generator_unittest.cc
@@ -0,0 +1,152 @@
+// Copyright 2022 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.
+
+#include "components/enterprise/browser/reporting/chrome_profile_request_generator.h"
+
+#include <vector>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "components/enterprise/browser/reporting/report_util.h"
+#include "components/enterprise/browser/reporting/reporting_delegate_factory.h"
+#include "components/policy/core/common/cloud/cloud_policy_util.h"
+#include "components/policy/proto/device_management_backend.pb.h"
+#include "components/version_info/channel.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace enterprise_reporting {
+
+namespace em = enterprise_reporting;
+
+namespace {
+
+const base::FilePath::CharType kProfilePath[] =
+ FILE_PATH_LITERAL("profile-path");
+constexpr char kProfileName[] = "profile-name";
+constexpr char kBrowserExePath[] = "browser-path";
+
+class FakeBrowserReportGeneratorDelegate
+ : public BrowserReportGenerator::Delegate {
+ public:
+ ~FakeBrowserReportGeneratorDelegate() override = default;
+
+ std::string GetExecutablePath() override { return kBrowserExePath; }
+ version_info::Channel GetChannel() override {
+ return version_info::Channel::STABLE;
+ }
+ std::vector<BrowserReportGenerator::ReportedProfileData> GetReportedProfiles()
+ override {
+ return std::vector<BrowserReportGenerator::ReportedProfileData>();
+ }
+ bool IsExtendedStableChannel() override { return true; }
+ void GenerateBuildStateInfo(
+ enterprise_management::BrowserReport* report) override {
+ return;
+ }
+ void GeneratePluginsIfNeeded(
+ BrowserReportGenerator::ReportCallback callback,
+ std::unique_ptr<enterprise_management::BrowserReport> report) override {
+ std::move(callback).Run(std::move(report));
+ }
+};
+
+class FakeProfileReportGeneratorDelegate
+ : public ProfileReportGenerator::Delegate {
+ public:
+ ~FakeProfileReportGeneratorDelegate() override = default;
+
+ bool Init(const base::FilePath& path) override { return true; }
+ void GetSigninUserInfo(
+ enterprise_management::ChromeUserProfileInfo* report) override {}
+ void GetExtensionInfo(
+ enterprise_management::ChromeUserProfileInfo* report) override {}
+ void GetExtensionRequest(
+ enterprise_management::ChromeUserProfileInfo* report) override {}
+
+ std::unique_ptr<policy::PolicyConversionsClient> MakePolicyConversionsClient()
+ override {
+ return nullptr;
+ }
+ policy::MachineLevelUserCloudPolicyManager* GetCloudPolicyManager() override {
+ return nullptr;
+ }
+};
+
+class FakeReportingDelegateFactory : public ReportingDelegateFactory {
+ public:
+ ~FakeReportingDelegateFactory() override = default;
+
+ std::unique_ptr<BrowserReportGenerator::Delegate>
+ GetBrowserReportGeneratorDelegate() override {
+ return std::make_unique<FakeBrowserReportGeneratorDelegate>();
+ }
+
+ std::unique_ptr<ProfileReportGenerator::Delegate>
+ GetProfileReportGeneratorDelegate() override {
+ return std::make_unique<FakeProfileReportGeneratorDelegate>();
+ }
+
+ std::unique_ptr<ReportGenerator::Delegate> GetReportGeneratorDelegate()
+ override {
+ return nullptr;
+ }
+
+ std::unique_ptr<ReportScheduler::Delegate> GetReportSchedulerDelegate()
+ override {
+ return nullptr;
+ }
+
+ std::unique_ptr<RealTimeReportGenerator::Delegate>
+ GetRealTimeReportGeneratorDelegate() override {
+ return nullptr;
+ }
+};
+
+} // namespace
+
+class ChromeProfileRequestGeneratorTest : public ::testing::Test {
+ public:
+ ChromeProfileRequestGeneratorTest()
+ : generator_(base::FilePath(kProfilePath),
+ kProfileName,
+ &delegate_factory_) {}
+ void Verify(ReportRequestQueue requests) {
+ ASSERT_EQ(1u, requests.size());
+ ReportRequest* request = requests.front().get();
+ ASSERT_TRUE(request);
+ ASSERT_TRUE(request->GetChromeProfileReportRequest().has_os_report());
+ auto os_report = request->GetChromeProfileReportRequest().os_report();
+ EXPECT_EQ(policy::GetOSPlatform(), os_report.name());
+ EXPECT_EQ(policy::GetOSArchitecture(), os_report.arch());
+ EXPECT_EQ(policy::GetOSVersion(), os_report.version());
+
+ ASSERT_TRUE(request->GetChromeProfileReportRequest().has_browser_report());
+ auto browser_report =
+ request->GetChromeProfileReportRequest().browser_report();
+ EXPECT_EQ(ObfuscateFilePath(kBrowserExePath),
+ browser_report.executable_path());
+ EXPECT_TRUE(browser_report.is_extended_stable_channel());
+
+ ASSERT_EQ(1, browser_report.chrome_user_profile_infos_size());
+ auto profile_report = browser_report.chrome_user_profile_infos(0);
+ EXPECT_EQ(ObfuscateFilePath(base::FilePath(kProfilePath).AsUTF8Unsafe()),
+ profile_report.id());
+ EXPECT_EQ(kProfileName, profile_report.name());
+ EXPECT_TRUE(profile_report.is_detail_available());
+ }
+ void GenerateAndVerify() {
+ generator_.Generate(base::BindOnce(
+ &ChromeProfileRequestGeneratorTest::Verify, base::Unretained(this)));
+ }
+
+ private:
+ FakeReportingDelegateFactory delegate_factory_;
+ ChromeProfileRequestGenerator generator_;
+};
+
+TEST_F(ChromeProfileRequestGeneratorTest, Generate) {
+ GenerateAndVerify();
+}
+
+} // namespace enterprise_reporting
diff --git a/chromium/components/enterprise/browser/reporting/cloud_profile_reporting_policy_handler.cc b/chromium/components/enterprise/browser/reporting/cloud_profile_reporting_policy_handler.cc
new file mode 100644
index 00000000000..82b5213cbcb
--- /dev/null
+++ b/chromium/components/enterprise/browser/reporting/cloud_profile_reporting_policy_handler.cc
@@ -0,0 +1,57 @@
+// Copyright 2022 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.
+
+#include "components/enterprise/browser/reporting/cloud_profile_reporting_policy_handler.h"
+
+#include "base/values.h"
+#include "components/enterprise/browser/reporting/common_pref_names.h"
+#include "components/policy/core/browser/policy_error_map.h"
+#include "components/policy/core/common/policy_map.h"
+#include "components/policy/core/common/policy_types.h"
+#include "components/policy/policy_constants.h"
+#include "components/prefs/pref_value_map.h"
+#include "components/strings/grit/components_strings.h"
+
+namespace enterprise_reporting {
+
+CloudProfileReportingPolicyHandler::CloudProfileReportingPolicyHandler()
+ : policy::TypeCheckingPolicyHandler(
+ policy::key::kCloudProfileReportingEnabled,
+ base::Value::Type::BOOLEAN) {}
+
+CloudProfileReportingPolicyHandler::~CloudProfileReportingPolicyHandler() =
+ default;
+
+bool CloudProfileReportingPolicyHandler::CheckPolicySettings(
+ const policy::PolicyMap& policies,
+ policy::PolicyErrorMap* errors) {
+ const policy::PolicyMap::Entry* policy = policies.Get(policy_name());
+ if (!policy)
+ return true;
+
+ if (!TypeCheckingPolicyHandler::CheckPolicySettings(policies, errors))
+ return false;
+
+ if (policy->source != policy::POLICY_SOURCE_CLOUD ||
+ policy->scope != policy::POLICY_SCOPE_USER) {
+ errors->AddError(policy_name(), IDS_POLICY_CLOUD_USER_ONLY_ERROR);
+ return false;
+ }
+
+ return true;
+}
+
+void CloudProfileReportingPolicyHandler::ApplyPolicySettings(
+ const policy::PolicyMap& policies,
+ PrefValueMap* prefs) {
+ const base::Value* cloud_profile_reporting_policy_value =
+ policies.GetValue(policy_name());
+
+ if (cloud_profile_reporting_policy_value) {
+ prefs->SetBoolean(kCloudProfileReportingEnabled,
+ cloud_profile_reporting_policy_value->GetBool());
+ }
+}
+
+} // namespace enterprise_reporting
diff --git a/chromium/components/enterprise/browser/reporting/cloud_profile_reporting_policy_handler.h b/chromium/components/enterprise/browser/reporting/cloud_profile_reporting_policy_handler.h
new file mode 100644
index 00000000000..6ed7196c513
--- /dev/null
+++ b/chromium/components/enterprise/browser/reporting/cloud_profile_reporting_policy_handler.h
@@ -0,0 +1,32 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_ENTERPRISE_BROWSER_REPORTING_CLOUD_PROFILE_REPORTING_POLICY_HANDLER_H_
+#define COMPONENTS_ENTERPRISE_BROWSER_REPORTING_CLOUD_PROFILE_REPORTING_POLICY_HANDLER_H_
+
+#include "components/policy/core/browser/configuration_policy_handler.h"
+
+namespace enterprise_reporting {
+
+// Sets prefs for policy CloudReportingEnabled policy.
+class CloudProfileReportingPolicyHandler
+ : public policy::TypeCheckingPolicyHandler {
+ public:
+ CloudProfileReportingPolicyHandler();
+ CloudProfileReportingPolicyHandler(
+ const CloudProfileReportingPolicyHandler&) = delete;
+ CloudProfileReportingPolicyHandler& operator=(
+ const CloudProfileReportingPolicyHandler&) = delete;
+ ~CloudProfileReportingPolicyHandler() override;
+
+ // policy::TypeCheckingPolicyHandler
+ bool CheckPolicySettings(const policy::PolicyMap& policies,
+ policy::PolicyErrorMap* errors) override;
+ void ApplyPolicySettings(const policy::PolicyMap& policies,
+ PrefValueMap* prefs) override;
+};
+
+} // namespace enterprise_reporting
+
+#endif // COMPONENTS_ENTERPRISE_BROWSER_REPORTING_CLOUD_PROFILE_REPORTING_POLICY_HANDLER_H_
diff --git a/chromium/components/enterprise/browser/reporting/cloud_reporting_frequency_policy_handler.cc b/chromium/components/enterprise/browser/reporting/cloud_reporting_frequency_policy_handler.cc
new file mode 100644
index 00000000000..d52c4261616
--- /dev/null
+++ b/chromium/components/enterprise/browser/reporting/cloud_reporting_frequency_policy_handler.cc
@@ -0,0 +1,60 @@
+// Copyright 2022 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.
+
+#include "components/enterprise/browser/reporting/cloud_reporting_frequency_policy_handler.h"
+
+#include "base/json/values_util.h"
+#include "base/time/time.h"
+#include "components/enterprise/browser/reporting/common_pref_names.h"
+#include "components/policy/core/browser/policy_error_map.h"
+#include "components/policy/core/common/schema.h"
+#include "components/policy/policy_constants.h"
+#include "components/prefs/pref_value_map.h"
+#include "components/strings/grit/components_strings.h"
+
+namespace enterprise_reporting {
+namespace {
+constexpr int kMinimumReportFrequencyInHour = 3;
+constexpr int kMaximumReportFrequencyInour = 24 * 7;
+
+} // namespace
+
+CloudReportingFrequencyPolicyHandler::CloudReportingFrequencyPolicyHandler()
+ : policy::IntRangePolicyHandlerBase(
+ policy::key::kCloudReportingUploadFrequency,
+ kMinimumReportFrequencyInHour,
+ kMaximumReportFrequencyInour,
+ /*clamp=*/true) {}
+CloudReportingFrequencyPolicyHandler::~CloudReportingFrequencyPolicyHandler() =
+ default;
+
+bool CloudReportingFrequencyPolicyHandler::CheckPolicySettings(
+ const policy::PolicyMap& policies,
+ policy::PolicyErrorMap* errors) {
+ const policy::PolicyMap::Entry* policy = policies.Get(policy_name());
+
+ if (!policy)
+ return true;
+
+ if (policy->source != policy::POLICY_SOURCE_CLOUD &&
+ policy->source != policy::POLICY_SOURCE_CLOUD_FROM_ASH) {
+ errors->AddError(policy_name(), IDS_POLICY_CLOUD_SOURCE_ONLY_ERROR);
+ return false;
+ }
+
+ return policy::IntRangePolicyHandlerBase::CheckPolicySettings(policies,
+ errors);
+}
+
+void CloudReportingFrequencyPolicyHandler::ApplyPolicySettings(
+ const policy::PolicyMap& policies,
+ PrefValueMap* prefs) {
+ const base::Value* value = policies.GetValue(policy_name());
+ int value_in_range;
+ if (value && EnsureInRange(value, &value_in_range, nullptr))
+ prefs->SetValue(kCloudReportingUploadFrequency,
+ base::TimeDeltaToValue(base::Hours(value_in_range)));
+}
+
+} // namespace enterprise_reporting
diff --git a/chromium/components/enterprise/browser/reporting/cloud_reporting_frequency_policy_handler.h b/chromium/components/enterprise/browser/reporting/cloud_reporting_frequency_policy_handler.h
new file mode 100644
index 00000000000..cdcb228ef77
--- /dev/null
+++ b/chromium/components/enterprise/browser/reporting/cloud_reporting_frequency_policy_handler.h
@@ -0,0 +1,32 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_ENTERPRISE_BROWSER_REPORTING_CLOUD_REPORTING_FREQUENCY_POLICY_HANDLER_H_
+#define COMPONENTS_ENTERPRISE_BROWSER_REPORTING_CLOUD_REPORTING_FREQUENCY_POLICY_HANDLER_H_
+
+#include "components/policy/core/browser/configuration_policy_handler.h"
+
+namespace enterprise_reporting {
+
+class CloudReportingFrequencyPolicyHandler
+ : public policy::IntRangePolicyHandlerBase {
+ public:
+ CloudReportingFrequencyPolicyHandler();
+ CloudReportingFrequencyPolicyHandler(
+ const CloudReportingFrequencyPolicyHandler&) = delete;
+ CloudReportingFrequencyPolicyHandler& operator=(
+ const CloudReportingFrequencyPolicyHandler&) = delete;
+ ~CloudReportingFrequencyPolicyHandler() override;
+
+ private:
+ // policy::IntRangePolicyHandlerBase
+ bool CheckPolicySettings(const policy::PolicyMap& policies,
+ policy::PolicyErrorMap* errors) override;
+ void ApplyPolicySettings(const policy::PolicyMap& policies,
+ PrefValueMap* prefs) override;
+};
+
+} // namespace enterprise_reporting
+
+#endif // COMPONENTS_ENTERPRISE_BROWSER_REPORTING_CLOUD_REPORTING_FREQUENCY_POLICY_HANDLER_H_
diff --git a/chromium/components/enterprise/browser/reporting/cloud_reporting_policy_handler.cc b/chromium/components/enterprise/browser/reporting/cloud_reporting_policy_handler.cc
index ae0b27c20eb..7f12b5b1f8d 100644
--- a/chromium/components/enterprise/browser/reporting/cloud_reporting_policy_handler.cc
+++ b/chromium/components/enterprise/browser/reporting/cloud_reporting_policy_handler.cc
@@ -5,6 +5,7 @@
#include "components/enterprise/browser/reporting/cloud_reporting_policy_handler.h"
#include "base/values.h"
+#include "build/build_config.h"
#include "components/enterprise/browser/reporting/common_pref_names.h"
#include "components/policy/core/browser/policy_error_map.h"
#include "components/policy/core/common/cloud/dm_token.h"
@@ -13,9 +14,9 @@
#include "components/prefs/pref_value_map.h"
#include "components/strings/grit/components_strings.h"
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS)
#include "components/enterprise/browser/controller/browser_dm_token_storage.h"
-#endif //! defined(OS_CHROMEOS)
+#endif // !BUILDFLAG(IS_CHROMEOS)
namespace enterprise_reporting {
@@ -32,13 +33,13 @@ bool CloudReportingPolicyHandler::CheckPolicySettings(
return true;
if (!TypeCheckingPolicyHandler::CheckPolicySettings(policies, errors))
return false;
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS)
// We don't return false here because machine enrollment status change may
// not trigger this PolicyHandler later.
if (!policy::BrowserDMTokenStorage::Get()->RetrieveDMToken().is_valid())
errors->AddError(policy_name(),
IDS_POLICY_CLOUD_MANAGEMENT_ENROLLMENT_ONLY_ERROR);
-#endif //! defined(OS_CHROMEOS)
+#endif // !BUILDFLAG(IS_CHROMEOS)
return true;
}
diff --git a/chromium/components/enterprise/browser/reporting/cloud_reporting_policy_handler_unittest.cc b/chromium/components/enterprise/browser/reporting/cloud_reporting_policy_handler_unittest.cc
index 3ef5db9340f..a3f97aefdd1 100644
--- a/chromium/components/enterprise/browser/reporting/cloud_reporting_policy_handler_unittest.cc
+++ b/chromium/components/enterprise/browser/reporting/cloud_reporting_policy_handler_unittest.cc
@@ -4,6 +4,7 @@
#include "components/enterprise/browser/reporting/cloud_reporting_policy_handler.h"
+#include "build/build_config.h"
#include "components/enterprise/browser/controller/fake_browser_dm_token_storage.h"
#include "components/enterprise/browser/reporting/common_pref_names.h"
#include "components/policy/core/browser/policy_error_map.h"
@@ -52,10 +53,10 @@ INSTANTIATE_TEST_SUITE_P(MachineEnrolledOrNot,
testing::Bool());
TEST_P(CloudReportingPolicyHandlerTest, MachineEnrollment) {
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS)
// CBCM device enrollment is not for chromeos.
bool enrolled = EnrollWithChromeBrowserCloudManagement();
-#endif // !defined(OS_CHROMEOS)
+#endif // !BUILDFLAG(IS_CHROMEOS)
policy::PolicyMap policy_map;
policy_map.Set(policy::key::kCloudReportingEnabled,
@@ -65,11 +66,11 @@ TEST_P(CloudReportingPolicyHandlerTest, MachineEnrollment) {
CloudReportingPolicyHandler handler;
policy::PolicyErrorMap errors;
ASSERT_TRUE(handler.CheckPolicySettings(policy_map, &errors));
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS)
EXPECT_TRUE(errors.empty());
#else
EXPECT_EQ(errors.empty(), enrolled);
-#endif // defined(OS_CHROMEOS)
+#endif // BUILDFLAG(IS_CHROMEOS)
PrefValueMap prefs;
handler.ApplyPolicySettings(policy_map, &prefs);
bool enabled = false;
diff --git a/chromium/components/enterprise/browser/reporting/common_pref_names.cc b/chromium/components/enterprise/browser/reporting/common_pref_names.cc
index c7b4544ca9c..1b915ed9f10 100644
--- a/chromium/components/enterprise/browser/reporting/common_pref_names.cc
+++ b/chromium/components/enterprise/browser/reporting/common_pref_names.cc
@@ -11,6 +11,11 @@ namespace enterprise_reporting {
const char kCloudReportingEnabled[] =
"enterprise_reporting.chrome_cloud_reporting";
+// Boolean that indicates whether Chrome enterprise profile cloud reporting is
+// enabled or not.
+const char kCloudProfileReportingEnabled[] =
+ "enterprise_reporting.chrome_profile_cloud_reporting";
+
// The timestamp of the last enterprise report upload.
const char kLastUploadTimestamp[] =
"enterprise_reporting.last_upload_timestamp";
@@ -19,4 +24,8 @@ const char kLastUploadTimestamp[] =
const char kLastUploadSucceededTimestamp[] =
"enterprise_reporting.last_upload_succeeded_timestamp";
+// The report frequency
+const char kCloudReportingUploadFrequency[] =
+ "enterprise_reporting.upload_frequency";
+
} // namespace enterprise_reporting
diff --git a/chromium/components/enterprise/browser/reporting/common_pref_names.h b/chromium/components/enterprise/browser/reporting/common_pref_names.h
index d3cfffcb1d4..28ae9153085 100644
--- a/chromium/components/enterprise/browser/reporting/common_pref_names.h
+++ b/chromium/components/enterprise/browser/reporting/common_pref_names.h
@@ -11,10 +11,14 @@ namespace enterprise_reporting {
extern const char kCloudReportingEnabled[];
+extern const char kCloudProfileReportingEnabled[];
+
extern const char kLastUploadTimestamp[];
extern const char kLastUploadSucceededTimestamp[];
+extern const char kCloudReportingUploadFrequency[];
+
} // namespace enterprise_reporting
#endif // COMPONENTS_ENTERPRISE_BROWSER_REPORTING_COMMON_PREF_NAMES_H_
diff --git a/chromium/components/enterprise/browser/reporting/os_report_generator.cc b/chromium/components/enterprise/browser/reporting/os_report_generator.cc
new file mode 100644
index 00000000000..8ab981196d8
--- /dev/null
+++ b/chromium/components/enterprise/browser/reporting/os_report_generator.cc
@@ -0,0 +1,21 @@
+// Copyright 2022 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.
+
+#include "components/enterprise/browser/reporting/os_report_generator.h"
+
+#include "components/policy/core/common/cloud/cloud_policy_util.h"
+
+namespace enterprise_reporting {
+
+namespace em = enterprise_management;
+
+std::unique_ptr<em::OSReport> GetOSReport() {
+ auto report = std::make_unique<em::OSReport>();
+ report->set_name(policy::GetOSPlatform());
+ report->set_arch(policy::GetOSArchitecture());
+ report->set_version(policy::GetOSVersion());
+ return report;
+}
+
+} // namespace enterprise_reporting
diff --git a/chromium/components/enterprise/browser/reporting/os_report_generator.h b/chromium/components/enterprise/browser/reporting/os_report_generator.h
new file mode 100644
index 00000000000..25ea2804308
--- /dev/null
+++ b/chromium/components/enterprise/browser/reporting/os_report_generator.h
@@ -0,0 +1,20 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_ENTERPRISE_BROWSER_REPORTING_OS_REPORT_GENERATOR_H_
+#define COMPONENTS_ENTERPRISE_BROWSER_REPORTING_OS_REPORT_GENERATOR_H_
+
+#include <memory>
+
+#include "components/policy/proto/device_management_backend.pb.h"
+
+namespace enterprise_reporting {
+
+// Returns an OS report contains basic OS information includes OS name, OS
+// architecture and OS version.
+std::unique_ptr<enterprise_management::OSReport> GetOSReport();
+
+} // namespace enterprise_reporting
+
+#endif // COMPONENTS_ENTERPRISE_BROWSER_REPORTING_OS_REPORT_GENERATOR_H_
diff --git a/chromium/components/enterprise/browser/reporting/profile_report_generator.cc b/chromium/components/enterprise/browser/reporting/profile_report_generator.cc
index 84c76dafd26..3a88bc352ec 100644
--- a/chromium/components/enterprise/browser/reporting/profile_report_generator.cc
+++ b/chromium/components/enterprise/browser/reporting/profile_report_generator.cc
@@ -67,13 +67,16 @@ ProfileReportGenerator::MaybeGenerate(const base::FilePath& path,
if (policies_enabled_) {
// TODO(crbug.com/983151): Upload policy error as their IDs.
auto client = delegate_->MakePolicyConversionsClient();
- policies_ = policy::DictionaryPolicyConversions(std::move(client))
- .EnableConvertTypes(false)
- .EnablePrettyPrint(false)
- .ToValue();
- GetChromePolicyInfo();
- GetExtensionPolicyInfo();
- GetPolicyFetchTimestampInfo();
+ // `client` may not be provided in unit test.
+ if (client) {
+ policies_ = policy::DictionaryPolicyConversions(std::move(client))
+ .EnableConvertTypes(false)
+ .EnablePrettyPrint(false)
+ .ToValue();
+ GetChromePolicyInfo();
+ GetExtensionPolicyInfo();
+ GetPolicyFetchTimestampInfo();
+ }
}
return std::move(report_);
diff --git a/chromium/components/enterprise/browser/reporting/real_time_uploader.cc b/chromium/components/enterprise/browser/reporting/real_time_uploader.cc
index 81abf778d2d..faf959e49b7 100644
--- a/chromium/components/enterprise/browser/reporting/real_time_uploader.cc
+++ b/chromium/components/enterprise/browser/reporting/real_time_uploader.cc
@@ -11,7 +11,6 @@
#include "base/task/bind_post_task.h"
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
-#include "components/enterprise/browser/controller/browser_dm_token_storage.h"
#include "components/prefs/pref_service.h"
namespace enterprise_reporting {
@@ -83,12 +82,12 @@ void RealTimeUploader::CreateReportQueueRequest(
reporting::StatusOr<std::unique_ptr<reporting::ReportQueueConfiguration>>
config,
reporting::ReportQueueProvider::CreateReportQueueCallback callback) {
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
reporting::ReportQueueProvider::CreateQueue(std::move(config.ValueOrDie()),
std::move(callback));
#else
NOTREACHED();
-#endif // !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_IOS)
}
void RealTimeUploader::OnReportQueueCreated(
diff --git a/chromium/components/enterprise/browser/reporting/report_generator.cc b/chromium/components/enterprise/browser/reporting/report_generator.cc
index cc79d7245b7..947f073e68d 100644
--- a/chromium/components/enterprise/browser/reporting/report_generator.cc
+++ b/chromium/components/enterprise/browser/reporting/report_generator.cc
@@ -11,11 +11,12 @@
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "components/enterprise/browser/reporting/browser_report_generator.h"
+#include "components/enterprise/browser/reporting/os_report_generator.h"
#include "components/enterprise/browser/reporting/report_type.h"
#include "components/enterprise/browser/reporting/reporting_delegate_factory.h"
#include "components/policy/core/common/cloud/cloud_policy_util.h"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include "base/win/wmi.h"
#endif
@@ -32,14 +33,10 @@ ReportGenerator::~ReportGenerator() = default;
void ReportGenerator::Generate(ReportType report_type,
ReportCallback callback) {
- CreateBasicRequest(std::make_unique<ReportRequest>(), report_type,
+ CreateBasicRequest(std::make_unique<ReportRequest>(report_type), report_type,
std::move(callback));
}
-void ReportGenerator::SetMaximumReportSizeForTesting(size_t size) {
- report_request_queue_generator_.SetMaximumReportSizeForTesting(size);
-}
-
void ReportGenerator::CreateBasicRequest(
std::unique_ptr<ReportRequest> basic_request,
ReportType report_type,
@@ -47,15 +44,18 @@ void ReportGenerator::CreateBasicRequest(
#if BUILDFLAG(IS_CHROMEOS_ASH)
delegate_->SetAndroidAppInfos(basic_request.get());
#else
- basic_request->set_computer_name(this->GetMachineName());
- basic_request->set_os_user_name(GetOSUserName());
- basic_request->set_serial_number(GetSerialNumber());
- basic_request->set_allocated_os_report(GetOSReport().release());
- basic_request->set_allocated_browser_device_identifier(
- policy::GetBrowserDeviceIdentifier().release());
+ basic_request->GetDeviceReportRequest().set_computer_name(
+ this->GetMachineName());
+ basic_request->GetDeviceReportRequest().set_os_user_name(GetOSUserName());
+ basic_request->GetDeviceReportRequest().set_serial_number(GetSerialNumber());
+ basic_request->GetDeviceReportRequest().set_allocated_os_report(
+ GetOSReport().release());
+ basic_request->GetDeviceReportRequest()
+ .set_allocated_browser_device_identifier(
+ policy::GetBrowserDeviceIdentifier().release());
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
// 1. Async function base::SysInfo::SetHardwareInfo is called.
// 2. ReportGenerator::SetHardwareInfo fills basic_report
// 3. ReportGenerator::GenerateReport is called
@@ -68,15 +68,7 @@ void ReportGenerator::CreateBasicRequest(
std::move(callback))));
#else
GenerateReport(report_type, std::move(callback), std::move(basic_request));
-#endif // defined(OS_ANDROID) || defined(OS_IOS)
-}
-
-std::unique_ptr<em::OSReport> ReportGenerator::GetOSReport() {
- auto report = std::make_unique<em::OSReport>();
- report->set_name(policy::GetOSPlatform());
- report->set_arch(policy::GetOSArchitecture());
- report->set_version(policy::GetOSVersion());
- return report;
+#endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
}
std::string ReportGenerator::GetMachineName() {
@@ -88,7 +80,7 @@ std::string ReportGenerator::GetOSUserName() {
}
std::string ReportGenerator::GetSerialNumber() {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
return base::WideToUTF8(
base::win::WmiComputerSystemInfo::Get().serial_number());
#else
@@ -112,7 +104,8 @@ void ReportGenerator::OnBrowserReportReady(
ReportType report_type,
ReportCallback callback,
std::unique_ptr<em::BrowserReport> browser_report) {
- basic_request->set_allocated_browser_report(browser_report.release());
+ basic_request->GetDeviceReportRequest().set_allocated_browser_report(
+ browser_report.release());
if (report_type != ReportType::kBrowserVersion) {
// Generate a queue of requests containing detailed profile information.
@@ -123,7 +116,7 @@ void ReportGenerator::OnBrowserReportReady(
// Return a queue containing only the basic request and browser report without
// detailed profile information.
- ReportRequests requests;
+ ReportRequestQueue requests;
requests.push(std::move(basic_request));
std::move(callback).Run(std::move(requests));
}
@@ -132,10 +125,11 @@ void ReportGenerator::SetHardwareInfo(
std::unique_ptr<ReportRequest> basic_request,
base::OnceCallback<void(std::unique_ptr<ReportRequest>)> callback,
base::SysInfo::HardwareInfo hardware_info) {
-#if defined(OS_ANDROID) || defined(OS_IOS)
- basic_request->set_brand_name(hardware_info.manufacturer);
- basic_request->set_device_model(hardware_info.model);
-#endif // defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
+ basic_request->GetDeviceReportRequest().set_brand_name(
+ hardware_info.manufacturer);
+ basic_request->GetDeviceReportRequest().set_device_model(hardware_info.model);
+#endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
std::move(callback).Run(std::move(basic_request));
}
diff --git a/chromium/components/enterprise/browser/reporting/report_generator.h b/chromium/components/enterprise/browser/reporting/report_generator.h
index d95a005e19a..407775d2f50 100644
--- a/chromium/components/enterprise/browser/reporting/report_generator.h
+++ b/chromium/components/enterprise/browser/reporting/report_generator.h
@@ -6,14 +6,13 @@
#define COMPONENTS_ENTERPRISE_BROWSER_REPORTING_REPORT_GENERATOR_H_
#include <memory>
-#include <queue>
#include <string>
#include "base/callback.h"
#include "base/memory/weak_ptr.h"
#include "base/system/sys_info.h"
#include "components/enterprise/browser/reporting/browser_report_generator.h"
-#include "components/enterprise/browser/reporting/report_request_definition.h"
+#include "components/enterprise/browser/reporting/report_request.h"
#include "components/enterprise/browser/reporting/report_request_queue_generator.h"
#include "components/enterprise/browser/reporting/report_type.h"
#include "components/policy/proto/device_management_backend.pb.h"
@@ -24,9 +23,7 @@ class ReportingDelegateFactory;
class ReportGenerator {
public:
- using ReportRequest = definition::ReportRequest;
- using ReportRequests = std::queue<std::unique_ptr<ReportRequest>>;
- using ReportCallback = base::OnceCallback<void(ReportRequests)>;
+ using ReportCallback = base::OnceCallback<void(ReportRequestQueue)>;
class Delegate {
public:
@@ -54,18 +51,12 @@ class ReportGenerator {
// information that are needed by that particular type.
virtual void Generate(ReportType report_type, ReportCallback callback);
- void SetMaximumReportSizeForTesting(size_t size);
-
protected:
// Creates a basic request that will be used by all Profiles.
void CreateBasicRequest(std::unique_ptr<ReportRequest> basic_request,
ReportType report_type,
ReportCallback callback);
- // Returns an OS report contains basic OS information includes OS name, OS
- // architecture and OS version.
- virtual std::unique_ptr<enterprise_management::OSReport> GetOSReport();
-
// Returns the name of computer.
virtual std::string GetMachineName();
diff --git a/chromium/components/enterprise/browser/reporting/report_request.cc b/chromium/components/enterprise/browser/reporting/report_request.cc
new file mode 100644
index 00000000000..28400974289
--- /dev/null
+++ b/chromium/components/enterprise/browser/reporting/report_request.cc
@@ -0,0 +1,61 @@
+// Copyright 2021 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.
+
+#include "components/enterprise/browser/reporting/report_request.h"
+
+#include "components/enterprise/browser/reporting/report_type.h"
+
+namespace enterprise_reporting {
+
+namespace em = enterprise_management;
+
+ReportRequest::ReportRequest(ReportType type) {
+ switch (type) {
+ case ReportType::kFull:
+ case ReportType::kBrowserVersion:
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+ proto_.emplace<em::ChromeOsUserReportRequest>();
+#else
+ proto_.emplace<em::ChromeDesktopReportRequest>();
+#endif
+ return;
+ case ReportType::kProfileReport:
+ proto_.emplace<em::ChromeProfileReportRequest>();
+ return;
+ }
+}
+
+ReportRequest::ReportRequest(const em::ChromeDesktopReportRequest& proto)
+ : proto_(proto) {}
+ReportRequest::ReportRequest(const em::ChromeOsUserReportRequest& proto)
+ : proto_(proto) {}
+ReportRequest::ReportRequest(const em::ChromeProfileReportRequest& proto)
+ : proto_(proto) {}
+
+ReportRequest::~ReportRequest() = default;
+
+const ReportRequest::DeviceReportRequestProto&
+ReportRequest::GetDeviceReportRequest() const {
+ return absl::get<ReportRequest::DeviceReportRequestProto>(proto_);
+}
+ReportRequest::DeviceReportRequestProto&
+ReportRequest::GetDeviceReportRequest() {
+ return absl::get<ReportRequest::DeviceReportRequestProto>(proto_);
+}
+
+const em::ChromeProfileReportRequest&
+ReportRequest::GetChromeProfileReportRequest() const {
+ return absl::get<em::ChromeProfileReportRequest>(proto_);
+}
+em::ChromeProfileReportRequest& ReportRequest::GetChromeProfileReportRequest() {
+ return absl::get<em::ChromeProfileReportRequest>(proto_);
+}
+
+std::unique_ptr<ReportRequest> ReportRequest::Clone() const {
+ return absl::visit(
+ [](const auto& proto) { return std::make_unique<ReportRequest>(proto); },
+ proto_);
+}
+
+} // namespace enterprise_reporting
diff --git a/chromium/components/enterprise/browser/reporting/report_request.h b/chromium/components/enterprise/browser/reporting/report_request.h
new file mode 100644
index 00000000000..92b0486332a
--- /dev/null
+++ b/chromium/components/enterprise/browser/reporting/report_request.h
@@ -0,0 +1,69 @@
+// Copyright 2021 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.
+
+#ifndef COMPONENTS_ENTERPRISE_BROWSER_REPORTING_REPORT_REQUEST_H_
+#define COMPONENTS_ENTERPRISE_BROWSER_REPORTING_REPORT_REQUEST_H_
+
+#include <memory>
+#include <queue>
+
+#include "build/chromeos_buildflags.h"
+#include "device_management_backend.pb.h"
+#include "third_party/abseil-cpp/absl/types/variant.h"
+
+namespace enterprise_reporting {
+
+enum class ReportType;
+
+// A class is used to allow reports of multiple types to be stored in a single
+// queue for the uploader.
+class ReportRequest {
+ public:
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+ using DeviceReportRequestProto =
+ enterprise_management::ChromeOsUserReportRequest;
+#else
+ using DeviceReportRequestProto =
+ enterprise_management::ChromeDesktopReportRequest;
+#endif
+
+ explicit ReportRequest(ReportType type);
+ explicit ReportRequest(
+ const enterprise_management::ChromeDesktopReportRequest& proto);
+ explicit ReportRequest(
+ const enterprise_management::ChromeOsUserReportRequest& proto);
+ explicit ReportRequest(
+ const enterprise_management::ChromeProfileReportRequest& proto);
+
+ ReportRequest(const ReportRequest&) = delete;
+ ReportRequest& operator=(const ReportRequest&) = delete;
+ ~ReportRequest();
+
+ const DeviceReportRequestProto& GetDeviceReportRequest() const;
+ DeviceReportRequestProto& GetDeviceReportRequest();
+
+ const enterprise_management::ChromeProfileReportRequest&
+ GetChromeProfileReportRequest() const;
+ enterprise_management::ChromeProfileReportRequest&
+ GetChromeProfileReportRequest();
+
+ // Clone the request proto.
+ // This is required when a report is splitted into multiple requests.
+ // As all requests need to contain shared information like browser version or
+ // machine name. Long term, we can improves the splitting algorithm so Clone
+ // is no longer necessary.
+ std::unique_ptr<ReportRequest> Clone() const;
+
+ private:
+ absl::variant<enterprise_management::ChromeDesktopReportRequest,
+ enterprise_management::ChromeOsUserReportRequest,
+ enterprise_management::ChromeProfileReportRequest>
+ proto_;
+};
+
+using ReportRequestQueue = std::queue<std::unique_ptr<ReportRequest>>;
+
+} // namespace enterprise_reporting
+
+#endif // COMPONENTS_ENTERPRISE_BROWSER_REPORTING_REPORT_REQUEST_H_
diff --git a/chromium/components/enterprise/browser/reporting/report_request_definition.h b/chromium/components/enterprise/browser/reporting/report_request_definition.h
deleted file mode 100644
index 077510421b7..00000000000
--- a/chromium/components/enterprise/browser/reporting/report_request_definition.h
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2019 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.
-
-#ifndef COMPONENTS_ENTERPRISE_BROWSER_REPORTING_REPORT_REQUEST_DEFINITION_H_
-#define COMPONENTS_ENTERPRISE_BROWSER_REPORTING_REPORT_REQUEST_DEFINITION_H_
-
-#include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
-#include "components/policy/proto/device_management_backend.pb.h"
-
-namespace enterprise_reporting {
-
-namespace definition {
-
-// Both ChromeOsUserReportRequest and ChromeDesktopReportRequest are used to
-// upload usage data to DM Server. By the reference to this macro, most classes
-// in enterprise_reporting namespace can share the same logic for various
-// operation systems.
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-using ReportRequest = enterprise_management::ChromeOsUserReportRequest;
-#else
-using ReportRequest = enterprise_management::ChromeDesktopReportRequest;
-#endif
-
-} // namespace definition
-
-} // namespace enterprise_reporting
-
-#endif // COMPONENTS_ENTERPRISE_BROWSER_REPORTING_REPORT_REQUEST_DEFINITION_H_
diff --git a/chromium/components/enterprise/browser/reporting/report_request_queue_generator.cc b/chromium/components/enterprise/browser/reporting/report_request_queue_generator.cc
index 55572505390..9caa827f047 100644
--- a/chromium/components/enterprise/browser/reporting/report_request_queue_generator.cc
+++ b/chromium/components/enterprise/browser/reporting/report_request_queue_generator.cc
@@ -54,23 +54,26 @@ void ReportRequestQueueGenerator::SetMaximumReportSizeForTesting(
maximum_report_size_ = maximum_report_size;
}
-ReportRequestQueueGenerator::ReportRequests
-ReportRequestQueueGenerator::Generate(const ReportRequest& basic_request) {
- ReportRequests requests;
- size_t basic_request_size = basic_request.ByteSizeLong();
+ReportRequestQueue ReportRequestQueueGenerator::Generate(
+ const ReportRequest& basic_request) {
+ ReportRequestQueue requests;
+ size_t basic_request_size =
+ basic_request.GetDeviceReportRequest().ByteSizeLong();
base::UmaHistogramMemoryKB(kBasicRequestSizeMetricsName,
basic_request_size / 1024);
if (basic_request_size <= maximum_report_size_) {
- requests.push(std::make_unique<ReportRequest>(basic_request));
- int profile_infos_size =
- basic_request.browser_report().chrome_user_profile_infos_size();
+ requests.push(basic_request.Clone());
+ int profile_infos_size = basic_request.GetDeviceReportRequest()
+ .browser_report()
+ .chrome_user_profile_infos_size();
for (int index = 0; index < profile_infos_size; index++) {
GenerateProfileReportWithIndex(index, basic_request, &requests);
}
- base::UmaHistogramMemoryKB(kRequestSizeMetricsName,
- requests.back()->ByteSizeLong() / 1024);
+ base::UmaHistogramMemoryKB(
+ kRequestSizeMetricsName,
+ requests.back()->GetDeviceReportRequest().ByteSizeLong() / 1024);
}
base::UmaHistogramExactLinear(kRequestCountMetricsName, requests.size(),
@@ -81,13 +84,16 @@ ReportRequestQueueGenerator::Generate(const ReportRequest& basic_request) {
void ReportRequestQueueGenerator::GenerateProfileReportWithIndex(
int profile_index,
const ReportRequest& basic_request,
- ReportRequests* requests) {
- DCHECK_LT(profile_index,
- basic_request.browser_report().chrome_user_profile_infos_size());
-
- size_t basic_request_size = basic_request.ByteSizeLong();
- auto basic_profile =
- basic_request.browser_report().chrome_user_profile_infos(profile_index);
+ ReportRequestQueue* requests) {
+ DCHECK_LT(profile_index, basic_request.GetDeviceReportRequest()
+ .browser_report()
+ .chrome_user_profile_infos_size());
+
+ size_t basic_request_size =
+ basic_request.GetDeviceReportRequest().ByteSizeLong();
+ auto basic_profile = basic_request.GetDeviceReportRequest()
+ .browser_report()
+ .chrome_user_profile_infos(profile_index);
auto profile_report = profile_report_generator_.MaybeGenerate(
base::FilePath::FromUTF8Unsafe(basic_profile.id()), basic_profile.name(),
ReportType::kFull);
@@ -100,13 +106,15 @@ void ReportRequestQueueGenerator::GenerateProfileReportWithIndex(
// is added. There are still few bytes difference but close enough.
size_t profile_report_incremental_size =
profile_report->ByteSizeLong() - basic_profile.ByteSizeLong();
- size_t current_request_size = requests->back()->ByteSizeLong();
+ size_t current_request_size =
+ requests->back()->GetDeviceReportRequest().ByteSizeLong();
if (current_request_size + profile_report_incremental_size <=
maximum_report_size_) {
// The new full Profile report can be appended into the current request.
requests->back()
- ->mutable_browser_report()
+ ->GetDeviceReportRequest()
+ .mutable_browser_report()
->mutable_chrome_user_profile_infos(profile_index)
->Swap(profile_report.get());
} else if (basic_request_size + profile_report_incremental_size <=
@@ -114,11 +122,13 @@ void ReportRequestQueueGenerator::GenerateProfileReportWithIndex(
// The new full Profile report is too big to be appended into the current
// request, move it to the next request if possible. Record metrics for the
// current request's size.
- base::UmaHistogramMemoryKB(kRequestSizeMetricsName,
- requests->back()->ByteSizeLong() / 1024);
- requests->push(std::make_unique<ReportRequest>(basic_request));
+ base::UmaHistogramMemoryKB(
+ kRequestSizeMetricsName,
+ requests->back()->GetDeviceReportRequest().ByteSizeLong() / 1024);
+ requests->push(basic_request.Clone());
requests->back()
- ->mutable_browser_report()
+ ->GetDeviceReportRequest()
+ .mutable_browser_report()
->mutable_chrome_user_profile_infos(profile_index)
->Swap(profile_report.get());
} else {
diff --git a/chromium/components/enterprise/browser/reporting/report_request_queue_generator.h b/chromium/components/enterprise/browser/reporting/report_request_queue_generator.h
index 47a172d6ce1..2092234e663 100644
--- a/chromium/components/enterprise/browser/reporting/report_request_queue_generator.h
+++ b/chromium/components/enterprise/browser/reporting/report_request_queue_generator.h
@@ -5,12 +5,9 @@
#ifndef COMPONENTS_ENTERPRISE_BROWSER_REPORTING_REPORT_REQUEST_QUEUE_GENERATOR_H_
#define COMPONENTS_ENTERPRISE_BROWSER_REPORTING_REPORT_REQUEST_QUEUE_GENERATOR_H_
-#include <memory>
-#include <queue>
-
#include "build/build_config.h"
#include "components/enterprise/browser/reporting/profile_report_generator.h"
-#include "components/enterprise/browser/reporting/report_request_definition.h"
+#include "components/enterprise/browser/reporting/report_request.h"
#include "components/policy/proto/device_management_backend.pb.h"
namespace enterprise_reporting {
@@ -22,9 +19,6 @@ class ReportingDelegateFactory;
// TODO(crbug.com/1103732): Unit tests for this class are still in
// chrome/browser/enterprise/reporting.
class ReportRequestQueueGenerator {
- using ReportRequest = definition::ReportRequest;
- using ReportRequests = std::queue<std::unique_ptr<ReportRequest>>;
-
public:
explicit ReportRequestQueueGenerator(
ReportingDelegateFactory* delegate_factory);
@@ -42,14 +36,14 @@ class ReportRequestQueueGenerator {
// Generate a queue of requests including full profile info based on given
// basic request.
- ReportRequests Generate(const ReportRequest& basic_request);
+ ReportRequestQueue Generate(const ReportRequest& basic_request);
private:
// Generate request with full profile info at |profile_index| according to
// |basic_request|, then store it into |requests|.
void GenerateProfileReportWithIndex(int profile_index,
const ReportRequest& basic_request,
- ReportRequests* requests);
+ ReportRequestQueue* requests);
private:
size_t maximum_report_size_;
diff --git a/chromium/components/enterprise/browser/reporting/report_scheduler.cc b/chromium/components/enterprise/browser/reporting/report_scheduler.cc
index 6a8096c84a3..984028889cc 100644
--- a/chromium/components/enterprise/browser/reporting/report_scheduler.cc
+++ b/chromium/components/enterprise/browser/reporting/report_scheduler.cc
@@ -29,8 +29,6 @@ namespace enterprise_reporting {
namespace {
-constexpr base::TimeDelta kDefaultUploadInterval =
- base::Hours(24); // Default upload interval is 24 hours.
const int kMaximumRetry = 10; // Retry 10 times takes about 15 to 19 hours.
bool IsBrowserVersionUploaded(ReportScheduler::ReportTrigger trigger) {
@@ -61,7 +59,8 @@ void OnExtensionRequestEnqueued(bool success) {
// So far, there is nothing handle the enqueue failure as the CBCM status
// report will cover all failed requests. However, we may need a retry logic
// here if Extension workflow is decoupled from the status report.
- LOG(ERROR) << "Extension request failed to be added to the pipeline.";
+ if (!success)
+ LOG(ERROR) << "Extension request failed to be added to the pipeline.";
}
} // namespace
@@ -69,6 +68,13 @@ void OnExtensionRequestEnqueued(bool success) {
ReportScheduler::Delegate::Delegate() = default;
ReportScheduler::Delegate::~Delegate() = default;
+ReportScheduler::CreateParams::CreateParams() = default;
+ReportScheduler::CreateParams::CreateParams(
+ ReportScheduler::CreateParams&& other) = default;
+ReportScheduler::CreateParams& ReportScheduler::CreateParams::operator=(
+ ReportScheduler::CreateParams&& other) = default;
+ReportScheduler::CreateParams::~CreateParams() = default;
+
void ReportScheduler::Delegate::SetReportTriggerCallback(
ReportScheduler::ReportTriggerCallback callback) {
DCHECK(trigger_report_callback_.is_null());
@@ -81,44 +87,49 @@ void ReportScheduler::Delegate::SetRealtimeReportTriggerCallback(
trigger_realtime_report_callback_ = std::move(callback);
}
-ReportScheduler::ReportScheduler(
- policy::CloudPolicyClient* client,
- std::unique_ptr<ReportGenerator> report_generator,
- std::unique_ptr<RealTimeReportGenerator> real_time_report_generator,
- ReportingDelegateFactory* delegate_factory)
- : ReportScheduler(std::move(client),
- std::move(report_generator),
- std::move(real_time_report_generator),
- delegate_factory->GetReportSchedulerDelegate()) {}
-
-ReportScheduler::ReportScheduler(
- policy::CloudPolicyClient* client,
- std::unique_ptr<ReportGenerator> report_generator,
- std::unique_ptr<RealTimeReportGenerator> real_time_report_generator,
- std::unique_ptr<ReportScheduler::Delegate> delegate)
- : delegate_(std::move(delegate)),
- cloud_policy_client_(std::move(client)),
- report_generator_(std::move(report_generator)),
- real_time_report_generator_(std::move(real_time_report_generator)) {
+ReportScheduler::ReportScheduler(CreateParams params)
+ : delegate_(std::move(params.delegate)),
+ cloud_policy_client_(params.client),
+ report_generator_(std::move(params.report_generator)),
+ profile_request_generator_(std::move(params.profile_request_generator)),
+ real_time_report_generator_(
+ std::move(params.real_time_report_generator)) {
+ DCHECK(cloud_policy_client_);
+ DCHECK(delegate_);
+
+ if (report_generator_) {
+ reporting_pref_name_ = std::string(kCloudReportingEnabled);
+ full_report_type_ = ReportType::kFull;
+ } else {
+ reporting_pref_name_ = std::string(kCloudProfileReportingEnabled);
+ full_report_type_ = ReportType::kProfileReport;
+ }
+
delegate_->SetReportTriggerCallback(
base::BindRepeating(&ReportScheduler::GenerateAndUploadReport,
weak_ptr_factory_.GetWeakPtr()));
delegate_->SetRealtimeReportTriggerCallback(
base::BindRepeating(&ReportScheduler::GenerateAndUploadRealtimeReport,
weak_ptr_factory_.GetWeakPtr()));
+
RegisterPrefObserver();
}
ReportScheduler::~ReportScheduler() = default;
bool ReportScheduler::IsReportingEnabled() const {
- return delegate_->GetLocalState()->GetBoolean(kCloudReportingEnabled);
+ return delegate_->GetPrefService()->GetBoolean(reporting_pref_name_);
}
bool ReportScheduler::IsNextReportScheduledForTesting() const {
return request_timer_.IsRunning();
}
+ReportScheduler::ReportTrigger ReportScheduler::GetActiveTriggerForTesting()
+ const {
+ return active_trigger_;
+}
+
void ReportScheduler::SetReportUploaderForTesting(
std::unique_ptr<ReportUploader> uploader) {
report_uploader_ = std::move(uploader);
@@ -138,11 +149,15 @@ void ReportScheduler::OnDMTokenUpdated() {
}
void ReportScheduler::RegisterPrefObserver() {
- pref_change_registrar_.Init(delegate_->GetLocalState());
+ pref_change_registrar_.Init(delegate_->GetPrefService());
pref_change_registrar_.Add(
- kCloudReportingEnabled,
+ reporting_pref_name_,
base::BindRepeating(&ReportScheduler::OnReportEnabledPrefChanged,
base::Unretained(this)));
+ pref_change_registrar_.Add(
+ kCloudReportingUploadFrequency,
+ base::BindRepeating(&ReportScheduler::RestartReportTimer,
+ base::Unretained(this)));
// Trigger first pref check during launch process.
OnReportEnabledPrefChanged();
}
@@ -164,22 +179,36 @@ void ReportScheduler::OnReportEnabledPrefChanged() {
#endif
// Start the periodic report timer.
- const base::Time last_upload_timestamp =
- delegate_->GetLocalState()->GetTime(kLastUploadTimestamp);
- Start(last_upload_timestamp);
+ RestartReportTimer();
+
+ // Only device report generator support real time partial version report with
+ // DM Server. With longer term, this should use `real_time_report_generator_`
+ // instead.
+ if (report_generator_) {
+ delegate_->StartWatchingUpdatesIfNeeded(
+ delegate_->GetPrefService()->GetTime(kLastUploadTimestamp),
+ delegate_->GetPrefService()->GetTimeDelta(
+ kCloudReportingUploadFrequency));
+ }
- delegate_->StartWatchingUpdatesIfNeeded(last_upload_timestamp,
- kDefaultUploadInterval);
- delegate_->StartWatchingExtensionRequestIfNeeded();
+ // Enable real time report if the generator is provided.
+ if (real_time_report_generator_)
+ delegate_->StartWatchingExtensionRequestIfNeeded();
}
void ReportScheduler::Stop() {
request_timer_.Stop();
- delegate_->StopWatchingUpdates();
+ if (report_generator_)
+ delegate_->StopWatchingUpdates();
delegate_->StopWatchingExtensionRequest();
extension_request_uploader_.reset();
}
+void ReportScheduler::RestartReportTimer() {
+ request_timer_.Stop();
+ Start(delegate_->GetPrefService()->GetTime(kLastUploadTimestamp));
+}
+
bool ReportScheduler::SetupBrowserPolicyClientRegistration() {
if (cloud_policy_client_->is_registered())
return true;
@@ -207,7 +236,9 @@ bool ReportScheduler::SetupBrowserPolicyClientRegistration() {
void ReportScheduler::Start(base::Time last_upload_time) {
// The next report is triggered 24h after the previous was uploaded.
- const base::Time next_upload_time = last_upload_time + kDefaultUploadInterval;
+ const base::Time next_upload_time =
+ last_upload_time +
+ delegate_->GetPrefService()->GetTimeDelta(kCloudReportingUploadFrequency);
if (VLOG_IS_ON(1)) {
base::TimeDelta first_request_delay = next_upload_time - base::Time::Now();
VLOG(1) << "Schedule the first report in about "
@@ -228,28 +259,17 @@ void ReportScheduler::GenerateAndUploadReport(ReportTrigger trigger) {
}
active_trigger_ = trigger;
- ReportType report_type = ReportType::kFull;
- switch (trigger) {
- case kTriggerNone:
- case kTriggerExtensionRequestRealTime:
- NOTREACHED();
- FALLTHROUGH;
- case kTriggerTimer:
- VLOG(1) << "Generating enterprise report.";
- break;
- case kTriggerUpdate:
- VLOG(1) << "Generating basic enterprise report upon update.";
- report_type = ReportType::kBrowserVersion;
- break;
- case kTriggerNewVersion:
- VLOG(1) << "Generating basic enterprise report upon new version.";
- report_type = ReportType::kBrowserVersion;
- break;
+ ReportType report_type = TriggerToReportType(trigger);
+ if (report_type == ReportType::kProfileReport) {
+ DCHECK(profile_request_generator_);
+ profile_request_generator_->Generate(base::BindOnce(
+ &ReportScheduler::OnReportGenerated, base::Unretained(this)));
+ } else {
+ DCHECK(report_generator_);
+ report_generator_->Generate(
+ report_type, base::BindOnce(&ReportScheduler::OnReportGenerated,
+ base::Unretained(this)));
}
-
- report_generator_->Generate(
- report_type, base::BindOnce(&ReportScheduler::OnReportGenerated,
- base::Unretained(this)));
}
void ReportScheduler::GenerateAndUploadRealtimeReport(
@@ -261,8 +281,7 @@ void ReportScheduler::GenerateAndUploadRealtimeReport(
}
}
-void ReportScheduler::OnReportGenerated(
- ReportGenerator::ReportRequests requests) {
+void ReportScheduler::OnReportGenerated(ReportRequestQueue requests) {
DCHECK_NE(active_trigger_, kTriggerNone);
if (requests.empty()) {
SYSLOG(ERROR)
@@ -280,8 +299,9 @@ void ReportScheduler::OnReportGenerated(
}
RecordUploadTrigger(active_trigger_);
report_uploader_->SetRequestAndUpload(
- std::move(requests), base::BindOnce(&ReportScheduler::OnReportUploaded,
- base::Unretained(this)));
+ TriggerToReportType(active_trigger_), std::move(requests),
+ base::BindOnce(&ReportScheduler::OnReportUploaded,
+ base::Unretained(this)));
}
void ReportScheduler::OnReportUploaded(ReportUploader::ReportStatus status) {
@@ -298,15 +318,15 @@ void ReportScheduler::OnReportUploaded(ReportUploader::ReportStatus status) {
if (IsExtensionRequestUploaded(active_trigger_))
delegate_->OnExtensionRequestUploaded();
- delegate_->GetLocalState()->SetTime(kLastUploadSucceededTimestamp,
- base::Time::Now());
- FALLTHROUGH;
+ delegate_->GetPrefService()->SetTime(kLastUploadSucceededTimestamp,
+ base::Time::Now());
+ [[fallthrough]];
case ReportUploader::kTransientError:
// Stop retrying and schedule the next report to avoid stale report.
// Failure count is not reset so retry delay remains.
if (active_trigger_ == kTriggerTimer) {
const base::Time now = base::Time::Now();
- delegate_->GetLocalState()->SetTime(kLastUploadTimestamp, now);
+ delegate_->GetPrefService()->SetTime(kLastUploadTimestamp, now);
if (IsReportingEnabled())
Start(now);
}
@@ -398,4 +418,20 @@ void ReportScheduler::RecordUploadTrigger(ReportTrigger trigger) {
sample);
}
+ReportType ReportScheduler::TriggerToReportType(
+ ReportScheduler::ReportTrigger trigger) {
+ switch (trigger) {
+ case ReportScheduler::kTriggerNone:
+ case ReportScheduler::kTriggerExtensionRequestRealTime:
+ NOTREACHED();
+ [[fallthrough]];
+ case ReportScheduler::kTriggerTimer:
+ return full_report_type_;
+ case ReportScheduler::kTriggerUpdate:
+ return ReportType::kBrowserVersion;
+ case ReportScheduler::kTriggerNewVersion:
+ return ReportType::kBrowserVersion;
+ }
+}
+
} // namespace enterprise_reporting
diff --git a/chromium/components/enterprise/browser/reporting/report_scheduler.h b/chromium/components/enterprise/browser/reporting/report_scheduler.h
index aadb7e381e2..85b142844c7 100644
--- a/chromium/components/enterprise/browser/reporting/report_scheduler.h
+++ b/chromium/components/enterprise/browser/reporting/report_scheduler.h
@@ -14,6 +14,7 @@
#include "base/observer_list_types.h"
#include "base/time/time.h"
#include "base/timer/wall_clock_timer.h"
+#include "components/enterprise/browser/reporting/chrome_profile_request_generator.h"
#include "components/enterprise/browser/reporting/real_time_report_generator.h"
#include "components/enterprise/browser/reporting/report_generator.h"
#include "components/enterprise/browser/reporting/report_uploader.h"
@@ -25,7 +26,6 @@ class CloudPolicyClient;
namespace enterprise_reporting {
-class ReportingDelegateFactory;
class RealTimeUploader;
// Schedules report generation and upload every 24 hours (and upon browser
@@ -63,7 +63,7 @@ class ReportScheduler {
void SetRealtimeReportTriggerCallback(
RealtimeReportTriggerCallback callback);
- virtual PrefService* GetLocalState() = 0;
+ virtual PrefService* GetPrefService() = 0;
// Browser version
virtual void StartWatchingUpdatesIfNeeded(
@@ -82,17 +82,22 @@ class ReportScheduler {
RealtimeReportTriggerCallback trigger_realtime_report_callback_;
};
- ReportScheduler(
- policy::CloudPolicyClient* client,
- std::unique_ptr<ReportGenerator> report_generator,
- std::unique_ptr<RealTimeReportGenerator> real_time_report_generator,
- ReportingDelegateFactory* delegate_factory);
+ struct CreateParams {
+ CreateParams();
+ CreateParams(const CreateParams&) = delete;
+ CreateParams& operator=(const CreateParams&) = delete;
+ CreateParams(CreateParams&& other);
+ CreateParams& operator=(CreateParams&& other);
+ ~CreateParams();
+
+ raw_ptr<policy::CloudPolicyClient> client;
+ std::unique_ptr<ReportGenerator> report_generator;
+ std::unique_ptr<RealTimeReportGenerator> real_time_report_generator;
+ std::unique_ptr<ChromeProfileRequestGenerator> profile_request_generator;
+ std::unique_ptr<ReportScheduler::Delegate> delegate;
+ };
- ReportScheduler(
- policy::CloudPolicyClient* client,
- std::unique_ptr<ReportGenerator> report_generator,
- std::unique_ptr<RealTimeReportGenerator> real_time_report_generator,
- std::unique_ptr<ReportScheduler::Delegate> delegate);
+ explicit ReportScheduler(CreateParams params);
ReportScheduler(const ReportScheduler&) = delete;
ReportScheduler& operator=(const ReportScheduler&) = delete;
@@ -107,6 +112,8 @@ class ReportScheduler {
// reporting policy is still enabled.
bool IsNextReportScheduledForTesting() const;
+ ReportTrigger GetActiveTriggerForTesting() const;
+
void SetReportUploaderForTesting(std::unique_ptr<ReportUploader> uploader);
void SetExtensionRequestUploaderForTesting(
std::unique_ptr<RealTimeUploader> uploader);
@@ -125,6 +132,10 @@ class ReportScheduler {
// Stops the periodic timer and the update observer.
void Stop();
+ // Stop the timer if there is any and reschedule the next report based on
+ // latest report frequency.
+ void RestartReportTimer();
+
// Register |cloud_policy_client_| with dm token and client id for desktop
// browser only. (Chrome OS doesn't need this step here.)
bool SetupBrowserPolicyClientRegistration();
@@ -140,7 +151,7 @@ class ReportScheduler {
// Continues processing a report (contained in the |requests| collection) by
// sending it to the uploader.
- void OnReportGenerated(ReportGenerator::ReportRequests requests);
+ void OnReportGenerated(ReportRequestQueue requests);
// Finishes processing following report upload. |status| indicates the result
// of the attempted upload.
@@ -156,6 +167,8 @@ class ReportScheduler {
// Records that |trigger| was responsible for an upload attempt.
static void RecordUploadTrigger(ReportTrigger trigger);
+ ReportType TriggerToReportType(ReportTrigger trigger);
+
std::unique_ptr<Delegate> delegate_;
// Policy value watcher
@@ -166,13 +179,12 @@ class ReportScheduler {
base::WallClockTimer request_timer_;
std::unique_ptr<ReportUploader> report_uploader_;
+ std::unique_ptr<RealTimeUploader> extension_request_uploader_;
std::unique_ptr<ReportGenerator> report_generator_;
-
+ std::unique_ptr<ChromeProfileRequestGenerator> profile_request_generator_;
std::unique_ptr<RealTimeReportGenerator> real_time_report_generator_;
- std::unique_ptr<RealTimeUploader> extension_request_uploader_;
-
// The trigger responsible for initiating active report generation.
ReportTrigger active_trigger_ = kTriggerNone;
@@ -181,6 +193,9 @@ class ReportScheduler {
// in-process report.
uint32_t pending_triggers_ = 0;
+ std::string reporting_pref_name_;
+ ReportType full_report_type_;
+
base::WeakPtrFactory<ReportScheduler> weak_ptr_factory_{this};
};
diff --git a/chromium/components/enterprise/browser/reporting/report_uploader.cc b/chromium/components/enterprise/browser/reporting/report_uploader.cc
index 1f0e0fb3165..b9488df0bcd 100644
--- a/chromium/components/enterprise/browser/reporting/report_uploader.cc
+++ b/chromium/components/enterprise/browser/reporting/report_uploader.cc
@@ -9,7 +9,9 @@
#include "base/metrics/histogram_functions.h"
#include "base/time/time.h"
#include "build/chromeos_buildflags.h"
+#include "components/enterprise/browser/reporting/report_type.h"
#include "components/policy/core/common/cloud/cloud_policy_client.h"
+#include "device_management_backend.pb.h"
namespace em = enterprise_management;
@@ -40,24 +42,42 @@ ReportUploader::ReportUploader(policy::CloudPolicyClient* client,
maximum_number_of_retries_(maximum_number_of_retries) {}
ReportUploader::~ReportUploader() = default;
-void ReportUploader::SetRequestAndUpload(ReportRequests requests,
+void ReportUploader::SetRequestAndUpload(ReportType report_type,
+ ReportRequestQueue requests,
ReportCallback callback) {
+ report_type_ = report_type;
requests_ = std::move(requests);
callback_ = std::move(callback);
Upload();
}
void ReportUploader::Upload() {
- auto request = std::make_unique<ReportRequest>(*requests_.front());
auto callback = base::BindRepeating(&ReportUploader::OnRequestFinished,
weak_ptr_factory_.GetWeakPtr());
+ switch (report_type_) {
+ case ReportType::kFull:
+ case ReportType::kBrowserVersion: {
+ auto request = std::make_unique<ReportRequest::DeviceReportRequestProto>(
+ requests_.front()->GetDeviceReportRequest());
#if BUILDFLAG(IS_CHROMEOS_ASH)
- client_->UploadChromeOsUserReport(std::move(request), std::move(callback));
+ client_->UploadChromeOsUserReport(std::move(request),
+ std::move(callback));
#else
- client_->UploadChromeDesktopReport(std::move(request), std::move(callback));
+ client_->UploadChromeDesktopReport(std::move(request),
+ std::move(callback));
#endif
-}
+ break;
+ }
+ case ReportType::kProfileReport: {
+ client_->UploadChromeProfileReport(
+ std::make_unique<em::ChromeProfileReportRequest>(
+ requests_.front()->GetChromeProfileReportRequest()),
+ std::move(callback));
+ break;
+ }
+ }
+} // BUILDFLAG(IS_CHROMEOS_ASH)
void ReportUploader::OnRequestFinished(bool status) {
if (status) {
diff --git a/chromium/components/enterprise/browser/reporting/report_uploader.h b/chromium/components/enterprise/browser/reporting/report_uploader.h
index 4882ac9a6cf..98d85289cb6 100644
--- a/chromium/components/enterprise/browser/reporting/report_uploader.h
+++ b/chromium/components/enterprise/browser/reporting/report_uploader.h
@@ -5,13 +5,10 @@
#ifndef COMPONENTS_ENTERPRISE_BROWSER_REPORTING_REPORT_UPLOADER_H_
#define COMPONENTS_ENTERPRISE_BROWSER_REPORTING_REPORT_UPLOADER_H_
-#include <memory>
-#include <queue>
-
#include "base/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/timer/timer.h"
-#include "components/enterprise/browser/reporting/report_request_definition.h"
+#include "components/enterprise/browser/reporting/report_request.h"
#include "net/base/backoff_entry.h"
namespace base {
@@ -43,8 +40,6 @@ class ReportUploader {
// invalid dm token.
};
- using ReportRequest = definition::ReportRequest;
- using ReportRequests = std::queue<std::unique_ptr<ReportRequest>>;
// A callback to notify the upload result.
using ReportCallback = base::OnceCallback<void(ReportStatus status)>;
@@ -58,7 +53,8 @@ class ReportUploader {
// Sets a list of requests and upload it. Request will be uploaded one after
// another.
- virtual void SetRequestAndUpload(ReportRequests requests,
+ virtual void SetRequestAndUpload(ReportType report_type,
+ ReportRequestQueue requests,
ReportCallback callback);
private:
@@ -81,7 +77,8 @@ class ReportUploader {
raw_ptr<policy::CloudPolicyClient> client_;
ReportCallback callback_;
- ReportRequests requests_;
+ ReportRequestQueue requests_;
+ ReportType report_type_;
net::BackoffEntry backoff_entry_;
base::OneShotTimer backoff_request_timer_;
diff --git a/chromium/components/enterprise/browser/reporting/report_uploader_unittest.cc b/chromium/components/enterprise/browser/reporting/report_uploader_unittest.cc
index 1d68e4b2905..f526eff546d 100644
--- a/chromium/components/enterprise/browser/reporting/report_uploader_unittest.cc
+++ b/chromium/components/enterprise/browser/reporting/report_uploader_unittest.cc
@@ -10,7 +10,10 @@
#include "base/test/task_environment.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
+#include "components/enterprise/browser/reporting/report_request.h"
+#include "components/enterprise/browser/reporting/report_type.h"
#include "components/policy/core/common/cloud/mock_cloud_policy_client.h"
+#include "device_management_backend.pb.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -55,20 +58,33 @@ class ReportUploaderTest : public ::testing::Test {
ReportUploader::ReportStatus expected_status) {
DCHECK_LE(number_of_request, 2)
<< "Please update kBrowserVersionNames above.";
- ReportUploader::ReportRequests requests;
+ ReportRequestQueue requests;
for (int i = 0; i < number_of_request; i++) {
- auto request = std::make_unique<ReportUploader::ReportRequest>();
- request->mutable_browser_report()->set_browser_version(
- kBrowserVersionNames[i]);
+ auto request = std::make_unique<ReportRequest>(GetReportType());
+ em::BrowserReport* browser_report;
+ switch (GetReportType()) {
+ case ReportType::kFull:
+ case ReportType::kBrowserVersion:
+ browser_report =
+ request->GetDeviceReportRequest().mutable_browser_report();
+ break;
+ case ReportType::kProfileReport:
+ browser_report =
+ request->GetChromeProfileReportRequest().mutable_browser_report();
+ break;
+ }
+ browser_report->set_browser_version(kBrowserVersionNames[i]);
requests.push(std::move(request));
}
has_responded_ = false;
uploader_->SetRequestAndUpload(
- std::move(requests),
+ GetReportType(), std::move(requests),
base::BindOnce(&ReportUploaderTest::OnReportUploaded,
base::Unretained(this), expected_status));
}
+ virtual ReportType GetReportType() { return ReportType::kFull; }
+
void OnReportUploaded(ReportUploader::ReportStatus expected_status,
ReportUploader::ReportStatus actuall_status) {
EXPECT_EQ(expected_status, actuall_status);
@@ -101,7 +117,7 @@ class ReportUploaderTest : public ::testing::Test {
base::test::TaskEnvironment task_environment_;
std::unique_ptr<ReportUploader> uploader_;
- policy::MockCloudPolicyClient client_;
+ ::testing::StrictMock<policy::MockCloudPolicyClient> client_;
bool has_responded_ = false;
base::HistogramTester histogram_tester_;
};
@@ -110,17 +126,12 @@ class ReportUploaderTestWithTransientError
: public ReportUploaderTest,
public ::testing::WithParamInterface<policy::DeviceManagementStatus> {};
-TEST_F(ReportUploaderTest, Success) {
- EXPECT_CALL(client_, UploadReportProxy(_, _))
- .WillOnce(WithArgs<1>(policy::ScheduleStatusCallback(true)));
- UploadReportAndSetExpectation(/*number_of_request=*/1,
- ReportUploader::kSuccess);
- RunNextTask();
- EXPECT_TRUE(has_responded_);
- histogram_tester_.ExpectUniqueSample(
- kResponseMetricsName, ReportResponseMetricsStatus::kSuccess, 1);
- ::testing::Mock::VerifyAndClearExpectations(&client_);
-}
+class ReportUploaderTestWithReportType
+ : public ReportUploaderTest,
+ public ::testing::WithParamInterface<ReportType> {
+ public:
+ ReportType GetReportType() override { return GetParam(); }
+};
TEST_F(ReportUploaderTest, PersistentError) {
CreateUploader(/* retry_count = */ 1);
@@ -231,23 +242,25 @@ TEST_F(ReportUploaderTest, MultipleReports) {
{
InSequence s;
// First report
- EXPECT_CALL(client_,
- UploadReportProxy(
- Property(&ReportUploader::ReportRequest::browser_report,
- Property(&em::BrowserReport::browser_version,
- Eq(kBrowserVersionNames[0]))),
- _))
+ EXPECT_CALL(
+ client_,
+ UploadReportProxy(
+ Property(&ReportRequest::DeviceReportRequestProto::browser_report,
+ Property(&em::BrowserReport::browser_version,
+ Eq(kBrowserVersionNames[0]))),
+ _))
.Times(3)
.WillOnce(WithArgs<1>(policy::ScheduleStatusCallback(false)))
.WillOnce(WithArgs<1>(policy::ScheduleStatusCallback(false)))
.WillOnce(WithArgs<1>(policy::ScheduleStatusCallback(true)));
// Second report
- EXPECT_CALL(client_,
- UploadReportProxy(
- Property(&ReportUploader::ReportRequest::browser_report,
- Property(&em::BrowserReport::browser_version,
- Eq(kBrowserVersionNames[1]))),
- _))
+ EXPECT_CALL(
+ client_,
+ UploadReportProxy(
+ Property(&ReportRequest::DeviceReportRequestProto::browser_report,
+ Property(&em::BrowserReport::browser_version,
+ Eq(kBrowserVersionNames[1]))),
+ _))
.Times(2)
.WillOnce(WithArgs<1>(policy::ScheduleStatusCallback(false)))
.WillOnce(WithArgs<1>(policy::ScheduleStatusCallback(false)));
@@ -299,4 +312,32 @@ INSTANTIATE_TEST_SUITE_P(
policy::DM_STATUS_TEMPORARY_UNAVAILABLE,
policy::DM_STATUS_SERVICE_TOO_MANY_REQUESTS));
+TEST_P(ReportUploaderTestWithReportType, Success) {
+ switch (GetReportType()) {
+ case ReportType::kFull:
+ case ReportType::kBrowserVersion:
+ EXPECT_CALL(client_, UploadReportProxy(_, _))
+ .WillOnce(WithArgs<1>(policy::ScheduleStatusCallback(true)));
+ break;
+ case ReportType::kProfileReport:
+ EXPECT_CALL(client_, UploadChromeProfileReportProxy(_, _))
+ .WillOnce(WithArgs<1>(policy::ScheduleStatusCallback(true)));
+ break;
+ }
+
+ UploadReportAndSetExpectation(/*number_of_request=*/1,
+ ReportUploader::kSuccess);
+ RunNextTask();
+ EXPECT_TRUE(has_responded_);
+ histogram_tester_.ExpectUniqueSample(
+ kResponseMetricsName, ReportResponseMetricsStatus::kSuccess, 1);
+ ::testing::Mock::VerifyAndClearExpectations(&client_);
+}
+
+INSTANTIATE_TEST_SUITE_P(All,
+ ReportUploaderTestWithReportType,
+ ::testing::Values(ReportType::kFull,
+ ReportType::kBrowserVersion,
+ ReportType::kProfileReport));
+
} // namespace enterprise_reporting
diff --git a/chromium/components/enterprise/content/clipboard_restriction_service.cc b/chromium/components/enterprise/content/clipboard_restriction_service.cc
index c30c99aebd8..cd87f4e56d7 100644
--- a/chromium/components/enterprise/content/clipboard_restriction_service.cc
+++ b/chromium/components/enterprise/content/clipboard_restriction_service.cc
@@ -9,6 +9,7 @@
#include "components/policy/core/common/policy_pref_names.h"
#include "components/prefs/pref_service.h"
#include "components/strings/grit/components_strings.h"
+#include "components/url_matcher/url_util.h"
#include "components/user_prefs/user_prefs.h"
#include "content/public/browser/browser_context.h"
#include "ui/base/l10n/l10n_util.h"
@@ -69,7 +70,7 @@ void ClipboardRestrictionService::UpdateSettings() {
return;
}
- const base::DictionaryValue* settings = pref_service_->GetDictionary(
+ const base::Value* settings = pref_service_->GetDictionary(
enterprise::content::kCopyPreventionSettings);
const base::Value* enable = settings->FindListKey(
enterprise::content::kCopyPreventionSettingsEnableFieldName);
@@ -96,10 +97,10 @@ void ClipboardRestrictionService::UpdateSettings() {
// and the copy will be blocked. While confusing, this is mostly to map to the
// same policy format as the content analysis connector, which also has
// "enable" and "disable" lists used in this way.
- policy::url_util::AddFilters(enable_url_matcher_.get(), true, &next_id_,
- enable_list);
- policy::url_util::AddFilters(disable_url_matcher_.get(), false, &next_id_,
- disable_list);
+ url_matcher::util::AddFilters(enable_url_matcher_.get(), true, &next_id_,
+ enable_list);
+ url_matcher::util::AddFilters(disable_url_matcher_.get(), false, &next_id_,
+ disable_list);
absl::optional<int> min_data_size = settings->FindIntKey(
enterprise::content::kCopyPreventionSettingsMinDataSizeFieldName);
diff --git a/chromium/components/enterprise/content/clipboard_restriction_service.h b/chromium/components/enterprise/content/clipboard_restriction_service.h
index fc42fc93295..113cda93260 100644
--- a/chromium/components/enterprise/content/clipboard_restriction_service.h
+++ b/chromium/components/enterprise/content/clipboard_restriction_service.h
@@ -11,7 +11,6 @@
#include "base/memory/singleton.h"
#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
#include "components/keyed_service/core/keyed_service.h"
-#include "components/policy/core/browser/url_util.h"
#include "components/prefs/pref_change_registrar.h"
#include "components/url_matcher/url_matcher.h"
diff --git a/chromium/components/enterprise/content/copy_prevention_settings_policy_handler.cc b/chromium/components/enterprise/content/copy_prevention_settings_policy_handler.cc
index ad7066b4621..f9776ac8a0a 100644
--- a/chromium/components/enterprise/content/copy_prevention_settings_policy_handler.cc
+++ b/chromium/components/enterprise/content/copy_prevention_settings_policy_handler.cc
@@ -55,7 +55,7 @@ bool CopyPreventionSettingsPolicyHandler::CheckPolicySettings(
return false;
}
- for (auto& pattern : disable->GetList()) {
+ for (auto& pattern : disable->GetListDeprecated()) {
if (pattern.GetString() == "*") {
errors->AddError(
policy_name(),
diff --git a/chromium/components/error_page/common/localized_error.cc b/chromium/components/error_page/common/localized_error.cc
index 7e4b2bc06f2..de34d6ef8f2 100644
--- a/chromium/components/error_page/common/localized_error.cc
+++ b/chromium/components/error_page/common/localized_error.cc
@@ -37,7 +37,7 @@
#include "ui/base/webui/web_ui_util.h"
#include "url/origin.h"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include "base/win/windows_version.h"
#endif
@@ -525,19 +525,12 @@ base::DictionaryValue GetStandardMenuItemsText() {
return standard_menu_items_text;
}
-// Returns true if the error is due to a disconnected network.
-bool IsOfflineError(const std::string& error_domain, int error_code) {
- return ((error_code == net::ERR_INTERNET_DISCONNECTED &&
- error_domain == Error::kNetErrorDomain) ||
- (error_code == error_page::DNS_PROBE_FINISHED_NO_INTERNET &&
- error_domain == Error::kDnsProbeErrorDomain));
-}
-
// Gets the icon class for a given |error_domain| and |error_code|.
const char* GetIconClassForError(const std::string& error_domain,
int error_code) {
- return IsOfflineError(error_domain, error_code) ? "icon-offline"
- : "icon-generic";
+ return LocalizedError::IsOfflineError(error_domain, error_code)
+ ? "icon-offline"
+ : "icon-generic";
}
base::DictionaryValue SingleEntryDictionary(base::StringPiece path,
@@ -693,7 +686,7 @@ void GetSuggestionsSummaryList(
"summary", IDS_ERRORPAGES_SUGGESTION_CHECK_CONNECTION_SUMMARY));
}
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
if (IsSuggested(suggestions, SUGGEST_DNS_CONFIG) &&
IsSuggested(suggestions, SUGGEST_FIREWALL_CONFIG) &&
IsSuggested(suggestions, SUGGEST_PROXY_CONFIG)) {
@@ -722,7 +715,7 @@ void GetSuggestionsSummaryList(
DCHECK(!(suggestions & SUGGEST_DNS_CONFIG));
DCHECK(!(suggestions & SUGGEST_SECURE_DNS_CONFIG));
}
-#elif defined(OS_ANDROID)
+#elif BUILDFLAG(IS_ANDROID)
if (IsSuggested(suggestions, SUGGEST_SECURE_DNS_CONFIG)) {
suggestions_summary_list.push_back(SingleEntryDictionary(
"summary", IDS_ERRORPAGES_SUGGESTION_CHECK_SECURE_DNS_SUMMARY));
@@ -730,7 +723,7 @@ void GetSuggestionsSummaryList(
#endif
if (IsSuggested(suggestions, SUGGEST_OFFLINE_CHECKS)) {
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
suggestions_summary_list.push_back(SingleEntryDictionary(
"summary", IDS_ERRORPAGES_SUGGESTION_TURN_OFF_AIRPLANE_SUMMARY));
suggestions_summary_list.push_back(SingleEntryDictionary(
@@ -747,7 +740,7 @@ void GetSuggestionsSummaryList(
// If the current platform has a directly accesible network diagnostics tool and
// the URL is valid add a suggestion.
-#if BUILDFLAG(IS_CHROMEOS_ASH) || defined(OS_WIN) || defined(OS_MAC)
+#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
if (IsOnlySuggestion(suggestions, SUGGEST_DIAGNOSE_TOOL)) {
int diagose_message_id =
error_code == error_page::DNS_PROBE_FINISHED_NXDOMAIN
@@ -764,7 +757,7 @@ void GetSuggestionsSummaryList(
}
#else
DCHECK(!IsSuggested(suggestions, SUGGEST_DIAGNOSE_TOOL));
-#endif // BUILDFLAG(IS_CHROMEOS_ASH) || defined(OS_WIN) || defined(OS_MAC)
+#endif // BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
// Add list prefix header.
error_strings->SetStringPath(
@@ -804,7 +797,7 @@ void AddSuggestionsDetails(int error_code,
IDS_ERRORPAGES_SUGGESTION_CHECK_CONNECTION_BODY, false);
}
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
if (suggestions & SUGGEST_SECURE_DNS_CONFIG) {
AddSuggestionDetailDictionaryToList(
suggestions_details, IDS_ERRORPAGES_SUGGESTION_SECURE_DNS_CONFIG_HEADER,
@@ -812,7 +805,7 @@ void AddSuggestionsDetails(int error_code,
}
#endif
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
if (suggestions & SUGGEST_DNS_CONFIG) {
AddSuggestionDetailDictionaryToList(suggestions_details,
IDS_ERRORPAGES_SUGGESTION_DNS_CONFIG_HEADER,
@@ -834,7 +827,7 @@ void AddSuggestionsDetails(int error_code,
}
// TODO(https://crbug.com/1254714): Provide meaningful strings for Fuchsia.
-#if !defined(OS_FUCHSIA)
+#if !BUILDFLAG(IS_FUCHSIA)
if (suggestions & SUGGEST_PROXY_CONFIG) {
AddSuggestionDetailDictionaryToList(
suggestions_details, IDS_ERRORPAGES_SUGGESTION_PROXY_CONFIG_HEADER, 0,
@@ -850,7 +843,7 @@ void AddSuggestionsDetails(int error_code,
"proxyTitle",
l10n_util::GetStringUTF16(IDS_OPTIONS_PROXIES_CONFIGURE_BUTTON));
}
-#endif // !defined(OS_FUCHSIA)
+#endif // !BUILDFLAG(IS_FUCHSIA)
#endif
if (suggestions & SUGGEST_CONTACT_ADMINISTRATOR &&
@@ -894,7 +887,7 @@ LocalizedError::PageState LocalizedError::GetPageState(
const std::string& locale,
bool is_blocked_by_extension) {
LocalizedError::PageState result;
- if (IsOfflineError(error_domain, error_code)) {
+ if (LocalizedError::IsOfflineError(error_domain, error_code)) {
result.is_offline_error = true;
// These strings are to be read by a screen reader during the dino game.
@@ -982,11 +975,18 @@ LocalizedError::PageState LocalizedError::GetPageState(
base::i18n::WrapStringWithLTRFormatting(&failed_url_string);
std::u16string host_name(url_formatter::IDNToUnicode(failed_url.host()));
- if (failed_url.SchemeIsHTTPOrHTTPS())
+ if (failed_url.SchemeIsHTTPOrHTTPS()) {
result.strings.SetStringPath("title", host_name);
- else
+ } else {
result.strings.SetStringPath("title", failed_url_string);
+ // If we do not have a meaningful hostname to display, show the scheme.
+ if (host_name.empty() && !failed_url.IsStandard()) {
+ options.heading_resource_id = IDS_ERRORPAGES_HEADING_BLOCKED_SCHEME;
+ host_name = base::UTF8ToUTF16(failed_url.scheme());
+ }
+ }
+
result.strings.SetStringPath("iconClass",
GetIconClassForError(error_domain, error_code));
@@ -1082,10 +1082,10 @@ LocalizedError::PageState LocalizedError::GetPageState(
AddSuggestionsDetails(error_code, &result.strings, options.suggestions,
suggestions_details);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
if (!is_post && !result.reload_button_shown && !is_incognito &&
failed_url.is_valid() && failed_url.SchemeIsHTTPOrHTTPS() &&
- IsOfflineError(error_domain, error_code)) {
+ LocalizedError::IsOfflineError(error_domain, error_code)) {
if (!auto_fetch_feature_enabled) {
result.download_button_shown = true;
result.strings.SetPath({"downloadButton", "msg"},
@@ -1110,7 +1110,8 @@ LocalizedError::PageState LocalizedError::GetPageState(
"closeDescriptionPopup",
l10n_util::GetStringUTF16(IDS_ERRORPAGES_SUGGESTION_CLOSE_POPUP_BUTTON));
- if (IsOfflineError(error_domain, error_code) && !is_incognito) {
+ if (LocalizedError::IsOfflineError(error_domain, error_code) &&
+ !is_incognito) {
result.offline_content_feature_enabled = offline_content_feature_enabled;
if (offline_content_feature_enabled) {
result.strings.SetStringPath("suggestedOfflineContentPresentation", "on");
@@ -1129,7 +1130,7 @@ LocalizedError::PageState LocalizedError::GetPageState(
base::Value(l10n_util::GetStringUTF16(IDS_HIDE_CONTENT)));
}
}
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
result.strings.SetPath("suggestionsSummaryList",
base::Value(std::move(suggestions_summary_list)));
@@ -1138,6 +1139,33 @@ LocalizedError::PageState LocalizedError::GetPageState(
return result;
}
+LocalizedError::PageState LocalizedError::GetPageStateForOverriddenErrorPage(
+ base::Value string_dict,
+ int error_code,
+ const std::string& error_domain,
+ const GURL& failed_url,
+ const std::string& locale) {
+ LocalizedError::PageState result;
+
+ result.strings.MergeDictionary(&string_dict);
+ webui::SetLoadTimeDataDefaults(locale, &result.strings);
+
+ if (failed_url.SchemeIsHTTPOrHTTPS()) {
+ result.strings.SetStringPath(
+ "title", url_formatter::IDNToUnicode(failed_url.host()));
+ } else {
+ std::u16string failed_url_string(url_formatter::FormatUrl(
+ failed_url, url_formatter::kFormatUrlOmitNothing,
+ net::UnescapeRule::NORMAL, nullptr, nullptr, nullptr));
+ // URLs are always LTR.
+ if (base::i18n::IsRTL())
+ base::i18n::WrapStringWithLTRFormatting(&failed_url_string);
+ result.strings.SetStringPath("title", failed_url_string);
+ }
+
+ return result;
+}
+
std::u16string LocalizedError::GetErrorDetails(const std::string& error_domain,
int error_code,
bool is_secure_dns_network_error,
@@ -1161,4 +1189,13 @@ bool LocalizedError::HasStrings(const std::string& error_domain,
/*is_post=*/false) != nullptr;
}
+// Returns true if the error is due to a disconnected network.
+bool LocalizedError::IsOfflineError(const std::string& error_domain,
+ int error_code) {
+ return ((error_code == net::ERR_INTERNET_DISCONNECTED &&
+ error_domain == Error::kNetErrorDomain) ||
+ (error_code == error_page::DNS_PROBE_FINISHED_NO_INTERNET &&
+ error_domain == Error::kDnsProbeErrorDomain));
+}
+
} // namespace error_page
diff --git a/chromium/components/error_page/common/localized_error.h b/chromium/components/error_page/common/localized_error.h
index 0a296b01a0d..f33f7001f5c 100644
--- a/chromium/components/error_page/common/localized_error.h
+++ b/chromium/components/error_page/common/localized_error.h
@@ -59,6 +59,15 @@ class LocalizedError {
const std::string& locale,
bool is_blocked_by_extension);
+ // Returns a |PageState| that describes the elements that should be shown on
+ // when default offline page is shown.
+ static PageState GetPageStateForOverriddenErrorPage(
+ base::Value string_dict,
+ int error_code,
+ const std::string& error_domain,
+ const GURL& failed_url,
+ const std::string& locale);
+
// Returns a description of the encountered error.
static std::u16string GetErrorDetails(const std::string& error_domain,
int error_code,
@@ -67,6 +76,8 @@ class LocalizedError {
// Returns true if an error page exists for the specified parameters.
static bool HasStrings(const std::string& error_domain, int error_code);
+
+ static bool IsOfflineError(const std::string& error_domain, int error_code);
};
} // namespace error_page
diff --git a/chromium/components/error_page/content/browser/net_error_auto_reloader_browsertest.cc b/chromium/components/error_page/content/browser/net_error_auto_reloader_browsertest.cc
index bea2fbab931..5951a9cc920 100644
--- a/chromium/components/error_page/content/browser/net_error_auto_reloader_browsertest.cc
+++ b/chromium/components/error_page/content/browser/net_error_auto_reloader_browsertest.cc
@@ -220,7 +220,7 @@ class NetErrorAutoReloaderBrowserTest : public content::ContentBrowserTest {
// immediate side effects, such as the scheduling of an auto-reload timer.
//
// Return true if the navigation was successful, or false if it failed.
- bool NavigateMainFrame(const GURL& url) WARN_UNUSED_RESULT {
+ [[nodiscard]] bool NavigateMainFrame(const GURL& url) {
content::TestNavigationManager navigation(shell()->web_contents(), url);
shell()->web_contents()->GetController().LoadURL(
url, content::Referrer(), ui::PAGE_TRANSITION_TYPED,
diff --git a/chromium/components/error_page_strings.grdp b/chromium/components/error_page_strings.grdp
index 4969fc3caae..1c7313ca8ed 100644
--- a/chromium/components/error_page_strings.grdp
+++ b/chromium/components/error_page_strings.grdp
@@ -133,6 +133,9 @@
<message name="IDS_ERRORPAGES_HEADING_BLOCKED" desc="Heading of the error page when a request is blocked by the administrator policy, extension or the browser itself.">
<ph name="HOST_NAME">&lt;span jscontent="hostName"&gt;&lt;/span&gt;<ex>www.example.com</ex></ph> is blocked
</message>
+ <message name="IDS_ERRORPAGES_HEADING_BLOCKED_SCHEME" desc="Heading of the error page when a URL Scheme is blocked by the administrator policy, extension or the browser itself.">
+ “<ph name="HOST_NAME">&lt;span jscontent="hostName"&gt;&lt;/span&gt;<ex>mailto</ex></ph>†links are blocked
+ </message>
<message name="IDS_ERRORPAGES_SUMMARY_NOT_AVAILABLE" desc="Summary in the error page when we can't connect to a site.">
The webpage at <ph name="URL">&lt;strong jscontent="failedUrl"&gt;&lt;/strong&gt;</ph> might be temporarily down or it may have moved permanently to a new web address.
</message>
diff --git a/chromium/components/error_page_strings_grdp/IDS_ERRORPAGES_HEADING_BLOCKED_SCHEME.png.sha1 b/chromium/components/error_page_strings_grdp/IDS_ERRORPAGES_HEADING_BLOCKED_SCHEME.png.sha1
new file mode 100644
index 00000000000..ba79bb5c4b8
--- /dev/null
+++ b/chromium/components/error_page_strings_grdp/IDS_ERRORPAGES_HEADING_BLOCKED_SCHEME.png.sha1
@@ -0,0 +1 @@
+e5178c8c5759488afd728fca170c1c448d329459 \ No newline at end of file
diff --git a/chromium/components/exo/BUILD.gn b/chromium/components/exo/BUILD.gn
index 44a7095d0b2..f3e3dd5d72e 100644
--- a/chromium/components/exo/BUILD.gn
+++ b/chromium/components/exo/BUILD.gn
@@ -13,10 +13,7 @@ import("//ui/base/ui_features.gni")
buildflag_header("buildflags") {
header = "buildflags.h"
- flags = [
- "ENABLE_COLOR_MANAGER=$enable_color_manager",
- "ENABLE_WESTON_TEST=$enable_weston_test",
- ]
+ flags = [ "ENABLE_COLOR_MANAGER=$enable_color_manager" ]
}
if (use_xkbcommon) {
@@ -64,6 +61,7 @@ static_library("exo") {
"pointer.h",
"pointer_constraint_delegate.h",
"pointer_delegate.h",
+ "protected_native_pixmap_query_delegate.h",
"seat.cc",
"seat.h",
"seat_observer.h",
@@ -146,6 +144,7 @@ static_library("exo") {
"//ash/constants",
"//ash/keyboard/ui",
"//ash/public/cpp",
+ "//ash/resources/vector_icons",
"//chromeos/crosapi/cpp",
"//chromeos/ui/base",
"//chromeos/ui/frame",
@@ -261,6 +260,7 @@ source_set("test_support") {
"//ash:test_support",
"//ash/public/cpp",
"//chromeos/ui/base",
+ "//components/exo/wayland:weston_test_stub",
]
}
}
@@ -325,6 +325,8 @@ source_set("unit_tests") {
"shell_surface_unittest.cc",
"shell_surface_util_unittest.cc",
"sub_surface_unittest.cc",
+ "surface_test_util.cc",
+ "surface_test_util.h",
"surface_unittest.cc",
"text_input_unittest.cc",
"toast_surface_unittest.cc",
diff --git a/chromium/components/exo/DEPS b/chromium/components/exo/DEPS
index bc329d7a454..a52a362fcc8 100644
--- a/chromium/components/exo/DEPS
+++ b/chromium/components/exo/DEPS
@@ -11,6 +11,7 @@ include_rules = [
"+components/viz/host",
"+device/gamepad",
"+gpu",
+ "+media/media_buildflags.h",
"+mojo/core/embedder/embedder.h",
"+mojo/public/cpp",
"+net/base",
diff --git a/chromium/components/exo/OWNERS b/chromium/components/exo/OWNERS
index 5aecd661b28..59e093891d4 100644
--- a/chromium/components/exo/OWNERS
+++ b/chromium/components/exo/OWNERS
@@ -1,5 +1,9 @@
oshima@chromium.org
+# For Graphics
+fangzhoug@chromium.org
+jshargo@chromium.org
+
# For Input (keyboard, mouse, touch, data_device)
yhanada@chromium.org
diff --git a/chromium/components/exo/buffer.cc b/chromium/components/exo/buffer.cc
index 9d3dcb6d767..cc99addf55d 100644
--- a/chromium/components/exo/buffer.cc
+++ b/chromium/components/exo/buffer.cc
@@ -37,6 +37,11 @@
#include "ui/gfx/gpu_fence_handle.h"
#include "ui/gfx/gpu_memory_buffer.h"
+#if BUILDFLAG(USE_ARC_PROTECTED_MEDIA)
+#include "base/files/scoped_file.h"
+#include "base/posix/eintr_wrapper.h"
+#endif // BUILDFLAG(USE_ARC_PROTECTED_MEDIA)
+
namespace exo {
namespace {
@@ -409,6 +414,7 @@ bool Buffer::ProduceTransferableResource(
std::unique_ptr<gfx::GpuFence> acquire_fence,
bool secure_output_only,
viz::TransferableResource* resource,
+ ProtectedNativePixmapQueryDelegate* protected_native_pixmap_query,
PerCommitExplicitReleaseCallback per_commit_explicit_release_callback) {
TRACE_EVENT1("exo", "Buffer::ProduceTransferableResource", "buffer_id",
static_cast<const void*>(gfx_buffer()));
@@ -465,6 +471,27 @@ bool Buffer::ProduceTransferableResource(
release_contents_callback_.Reset(
base::BindOnce(&Buffer::ReleaseContents, base::Unretained(this)));
+#if BUILDFLAG(USE_ARC_PROTECTED_MEDIA)
+ // Check if this buffer needs HW protection. This can only happen if we
+ // require a secure output.
+ if (secure_output_only &&
+ protected_buffer_state_ == ProtectedBufferState::UNKNOWN &&
+ gpu_memory_buffer_ && protected_native_pixmap_query) {
+ gfx::GpuMemoryBufferHandle gmb_handle = gpu_memory_buffer_->CloneHandle();
+ if (!gmb_handle.native_pixmap_handle.planes.empty()) {
+ base::ScopedFD pixmap_handle(HANDLE_EINTR(
+ dup(gmb_handle.native_pixmap_handle.planes[0].fd.get())));
+ if (pixmap_handle.is_valid()) {
+ protected_buffer_state_ = ProtectedBufferState::QUERYING;
+ protected_native_pixmap_query->IsProtectedNativePixmapHandle(
+ std::move(pixmap_handle),
+ base::BindOnce(&Buffer::OnIsProtectedNativePixmapHandle,
+ AsWeakPtr()));
+ }
+ }
+ }
+#endif // BUILDFLAG(USE_ARC_PROTECTED_MEDIA)
+
// Zero-copy means using the contents texture directly.
if (use_zero_copy_) {
// This binds the latest contents of this buffer to |contents_texture|.
@@ -550,6 +577,15 @@ SkColor4f Buffer::GetColor() const {
return SkColors::kBlack;
}
+#if BUILDFLAG(USE_ARC_PROTECTED_MEDIA)
+bool Buffer::NeedsHardwareProtection() {
+ // We don't indicate protection is needed in the UNKNOWN state because we have
+ // not seen a pixmap yet that could be protected.
+ return protected_buffer_state_ == ProtectedBufferState::PROTECTED ||
+ protected_buffer_state_ == ProtectedBufferState::QUERYING;
+}
+#endif // BUILDFLAG(USE_ARC_PROTECTED_MEDIA)
+
////////////////////////////////////////////////////////////////////////////////
// Buffer, private:
@@ -608,7 +644,7 @@ void Buffer::MaybeRunPerCommitRelease(
if (release_fence.is_null()) {
std::move(buffer_release_callback).Run();
} else {
-#if defined(OS_POSIX)
+#if BUILDFLAG(IS_POSIX)
auto controller = base::FileDescriptorWatcher::WatchReadable(
release_fence.owned_fd.get(),
base::BindRepeating(&Buffer::FenceSignalled, AsWeakPtr(), commit_id));
@@ -629,6 +665,13 @@ void Buffer::FenceSignalled(uint64_t commit_id) {
buffer_releases_.erase(iter);
}
+#if BUILDFLAG(USE_ARC_PROTECTED_MEDIA)
+void Buffer::OnIsProtectedNativePixmapHandle(bool is_protected) {
+ protected_buffer_state_ = is_protected ? ProtectedBufferState::PROTECTED
+ : ProtectedBufferState::UNPROTECTED;
+}
+#endif // BUILDFLAG(USE_ARC_PROTECTED_MEDIA)
+
SolidColorBuffer::SolidColorBuffer(const SkColor4f& color,
const gfx::Size& size)
: Buffer(nullptr), color_(color), size_(size) {}
@@ -640,9 +683,11 @@ bool SolidColorBuffer::ProduceTransferableResource(
std::unique_ptr<gfx::GpuFence> acquire_fence,
bool secure_output_only,
viz::TransferableResource* resource,
+ ProtectedNativePixmapQueryDelegate* protected_native_pixmap_query,
PerCommitExplicitReleaseCallback per_commit_explicit_release_callback) {
- std::move(per_commit_explicit_release_callback)
- .Run(/*release_fence=*/gfx::GpuFenceHandle());
+ if (per_commit_explicit_release_callback)
+ std::move(per_commit_explicit_release_callback)
+ .Run(/*release_fence=*/gfx::GpuFenceHandle());
return false;
}
diff --git a/chromium/components/exo/buffer.h b/chromium/components/exo/buffer.h
index b68a75bb6e0..43efbfa4aa3 100644
--- a/chromium/components/exo/buffer.h
+++ b/chromium/components/exo/buffer.h
@@ -12,7 +12,9 @@
#include "base/containers/flat_map.h"
#include "base/files/file_descriptor_watcher_posix.h"
#include "base/memory/weak_ptr.h"
+#include "components/exo/protected_native_pixmap_query_delegate.h"
#include "components/viz/common/resources/transferable_resource.h"
+#include "media/media_buildflags.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/gpu_fence.h"
@@ -62,6 +64,7 @@ class Buffer : public base::SupportsWeakPtr<Buffer> {
std::unique_ptr<gfx::GpuFence> acquire_fence,
bool secure_output_only,
viz::TransferableResource* resource,
+ ProtectedNativePixmapQueryDelegate* protected_native_pixmap_query,
PerCommitExplicitReleaseCallback per_commit_explicit_release_callback);
// This should be called when the buffer is attached to a Surface.
@@ -79,6 +82,13 @@ class Buffer : public base::SupportsWeakPtr<Buffer> {
// The default color to be used should transferable resource production fail.
virtual SkColor4f GetColor() const;
+#if BUILDFLAG(USE_ARC_PROTECTED_MEDIA)
+ // Returns true if the underlying buffer is hardware protected. This should
+ // only be checked if the corresponding surface requires secure output,
+ // otherwise it will yield false positives.
+ bool NeedsHardwareProtection();
+#endif // BUILDFLAG(USE_ARC_PROTECTED_MEDIA)
+
// Set the amount of time to wait for buffer release.
void set_wait_for_release_delay_for_testing(
base::TimeDelta wait_for_release_delay) {
@@ -108,6 +118,13 @@ class Buffer : public base::SupportsWeakPtr<Buffer> {
base::OnceClosure buffer_release_callback;
};
+#if BUILDFLAG(USE_ARC_PROTECTED_MEDIA)
+ // For ARC protected content support this tracks the state of the
+ // asynchronous query to determine if the GMB is using a protected buffer or
+ // not.
+ enum class ProtectedBufferState { UNKNOWN, QUERYING, PROTECTED, UNPROTECTED };
+#endif // BUILDFLAG(USE_ARC_PROTECTED_MEDIA)
+
// This should be called when buffer is released and will notify the
// client that buffer has been released.
void Release();
@@ -135,6 +152,10 @@ class Buffer : public base::SupportsWeakPtr<Buffer> {
void FenceSignalled(uint64_t commit_id);
+#if BUILDFLAG(USE_ARC_PROTECTED_MEDIA)
+ void OnIsProtectedNativePixmapHandle(bool is_protected);
+#endif // BUILDFLAG(USE_ARC_PROTECTED_MEDIA)
+
// The GPU memory buffer that contains the contents of this buffer.
std::unique_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer_;
@@ -187,6 +208,10 @@ class Buffer : public base::SupportsWeakPtr<Buffer> {
// Even if we send explicit synchronization release information, Wayland
// protocol requires us to send regular buffer release events.
base::flat_map<uint64_t, BufferRelease> buffer_releases_;
+
+#if BUILDFLAG(USE_ARC_PROTECTED_MEDIA)
+ ProtectedBufferState protected_buffer_state_ = ProtectedBufferState::UNKNOWN;
+#endif // BUILDFLAG(USE_ARC_PROTECTED_MEDIA)
};
class SolidColorBuffer : public Buffer {
@@ -203,6 +228,7 @@ class SolidColorBuffer : public Buffer {
std::unique_ptr<gfx::GpuFence> acquire_fence,
bool secure_output_only,
viz::TransferableResource* resource,
+ ProtectedNativePixmapQueryDelegate* protected_native_pixmap_query,
PerCommitExplicitReleaseCallback per_commit_explicit_release_callback)
override;
diff --git a/chromium/components/exo/buffer_unittest.cc b/chromium/components/exo/buffer_unittest.cc
index f90379a6bff..144300509b7 100644
--- a/chromium/components/exo/buffer_unittest.cc
+++ b/chromium/components/exo/buffer_unittest.cc
@@ -70,7 +70,7 @@ TEST_F(BufferTest, ReleaseCallback) {
// Produce a transferable resource for the contents of the buffer.
int release_resource_count = 0;
bool rv = buffer->ProduceTransferableResource(
- frame_sink_holder->resource_manager(), nullptr, false, &resource,
+ frame_sink_holder->resource_manager(), nullptr, false, &resource, nullptr,
base::BindOnce(&ExplicitRelease,
base::Unretained(&release_resource_count)));
ASSERT_TRUE(rv);
@@ -94,6 +94,50 @@ TEST_F(BufferTest, ReleaseCallback) {
ASSERT_EQ(release_call_count, 1);
}
+TEST_F(BufferTest, SolidColorReleaseCallback) {
+ gfx::Size buffer_size(256, 256);
+ auto buffer = std::make_unique<SolidColorBuffer>(SkColors::kRed, buffer_size);
+ auto surface_tree_host = std::make_unique<SurfaceTreeHost>("BufferTest");
+ LayerTreeFrameSinkHolder* frame_sink_holder =
+ surface_tree_host->layer_tree_frame_sink_holder();
+
+ // This is needed to ensure that base::RunLoop().RunUntilIdle() call below
+ // is always sufficient for buffer to be released.
+ buffer->set_wait_for_release_delay_for_testing(base::TimeDelta());
+
+ // Set the release callback.
+ int release_call_count = 0;
+ buffer->set_release_callback(
+ base::BindRepeating(&Release, base::Unretained(&release_call_count)));
+
+ buffer->OnAttach();
+ viz::TransferableResource resource;
+ // Produce a transferable resource for the contents of the buffer.
+ int release_resource_count = 0;
+ bool rv = buffer->ProduceTransferableResource(
+ frame_sink_holder->resource_manager(), nullptr, false, &resource, nullptr,
+ base::BindOnce(&ExplicitRelease,
+ base::Unretained(&release_resource_count)));
+ // Solid color buffer is immediately released after commit.
+ EXPECT_EQ(release_resource_count, 1);
+ EXPECT_FALSE(rv);
+
+ // Release buffer.
+ std::vector<viz::ReturnedResource> resources;
+ resources.emplace_back(resource.id, resource.mailbox_holder.sync_token,
+ /*release_fence=*/gfx::GpuFenceHandle(),
+ /*count=*/0, /*lost=*/false);
+ frame_sink_holder->ReclaimResources(std::move(resources));
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(release_call_count, 0);
+
+ buffer->OnDetach();
+
+ // Release() should have been called exactly once.
+ EXPECT_EQ(release_call_count, 1);
+}
+
TEST_F(BufferTest, IsLost) {
gfx::Size buffer_size(256, 256);
auto buffer = std::make_unique<Buffer>(
@@ -106,7 +150,7 @@ TEST_F(BufferTest, IsLost) {
// Acquire a texture transferable resource for the contents of the buffer.
viz::TransferableResource resource;
bool rv = buffer->ProduceTransferableResource(
- frame_sink_holder->resource_manager(), nullptr, false, &resource,
+ frame_sink_holder->resource_manager(), nullptr, false, &resource, nullptr,
base::DoNothing());
ASSERT_TRUE(rv);
@@ -133,7 +177,7 @@ TEST_F(BufferTest, IsLost) {
viz::TransferableResource new_resource;
rv = buffer->ProduceTransferableResource(
frame_sink_holder->resource_manager(), nullptr, false, &new_resource,
- base::DoNothing());
+ nullptr, base::DoNothing());
ASSERT_TRUE(rv);
buffer->OnDetach();
@@ -160,7 +204,7 @@ TEST_F(BufferTest, OnLostResources) {
// Acquire a texture transferable resource for the contents of the buffer.
viz::TransferableResource resource;
bool rv = buffer->ProduceTransferableResource(
- frame_sink_holder->resource_manager(), nullptr, false, &resource,
+ frame_sink_holder->resource_manager(), nullptr, false, &resource, nullptr,
base::DoNothing());
ASSERT_TRUE(rv);
@@ -195,7 +239,7 @@ TEST_F(BufferTest, SurfaceTreeHostDestruction) {
// Produce a transferable resource for the contents of the buffer.
int release_resource_count = 0;
bool rv = buffer->ProduceTransferableResource(
- frame_sink_holder->resource_manager(), nullptr, false, &resource,
+ frame_sink_holder->resource_manager(), nullptr, false, &resource, nullptr,
base::BindOnce(&ExplicitRelease,
base::Unretained(&release_resource_count)));
ASSERT_TRUE(rv);
@@ -252,7 +296,7 @@ TEST_F(BufferTest, SurfaceTreeHostLastFrame) {
// Produce a transferable resource for the contents of the buffer.
int release_resource_count = 0;
bool rv = buffer->ProduceTransferableResource(
- frame_sink_holder->resource_manager(), nullptr, false, &resource,
+ frame_sink_holder->resource_manager(), nullptr, false, &resource, nullptr,
base::BindOnce(&ExplicitRelease,
base::Unretained(&release_resource_count)));
ASSERT_TRUE(rv);
diff --git a/chromium/components/exo/buildflags.gni b/chromium/components/exo/buildflags.gni
index ed8e7ed2369..fff3c98a579 100644
--- a/chromium/components/exo/buildflags.gni
+++ b/chromium/components/exo/buildflags.gni
@@ -9,9 +9,4 @@ declare_args() {
# If true, enables zcr_color_manager_v1. This is a temporary flag meant to
# guard an in-progress implementation, to be replaced by a feature flag.
enable_color_manager = false
-
- # If true, enables weston-test. This is a test-only wayland extension that
- # enables things like event injection.
- enable_weston_test =
- is_chromeos_ash && !is_chromeos_device && !is_official_build
}
diff --git a/chromium/components/exo/capabilities.h b/chromium/components/exo/capabilities.h
index 543a8361ef8..f9bf2118d45 100644
--- a/chromium/components/exo/capabilities.h
+++ b/chromium/components/exo/capabilities.h
@@ -6,6 +6,7 @@
#define COMPONENTS_EXO_CAPABILITIES_H_
#include <memory>
+#include <string>
namespace exo {
diff --git a/chromium/components/exo/client_controlled_shell_surface_unittest.cc b/chromium/components/exo/client_controlled_shell_surface_unittest.cc
index 2d599dbb7e0..9ea2f5f42ab 100644
--- a/chromium/components/exo/client_controlled_shell_surface_unittest.cc
+++ b/chromium/components/exo/client_controlled_shell_surface_unittest.cc
@@ -40,7 +40,6 @@
#include "chromeos/ui/base/window_properties.h"
#include "chromeos/ui/frame/caption_buttons/caption_button_model.h"
#include "chromeos/ui/frame/caption_buttons/frame_caption_button_container_view.h"
-#include "components/app_restore/features.h"
#include "components/app_restore/full_restore_utils.h"
#include "components/app_restore/window_properties.h"
#include "components/exo/buffer.h"
@@ -643,12 +642,16 @@ class TestEventHandler : public ui::EventHandler {
~TestEventHandler() override = default;
// ui::EventHandler:
- void OnMouseEvent(ui::MouseEvent* event) override { received_event_ = true; }
+ void OnMouseEvent(ui::MouseEvent* event) override {
+ mouse_events_.push_back(*event);
+ }
- bool received_event() const { return received_event_; }
+ const std::vector<ui::MouseEvent>& mouse_events() const {
+ return mouse_events_;
+ }
private:
- bool received_event_ = false;
+ std::vector<ui::MouseEvent> mouse_events_;
};
} // namespace
@@ -657,9 +660,9 @@ TEST_F(ClientControlledShellSurfaceTest, NoSynthesizedEventOnFrameChange) {
UpdateDisplay("800x600");
gfx::Size buffer_size(256, 256);
- std::unique_ptr<Buffer> buffer(
- new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
- std::unique_ptr<Surface> surface(new Surface);
+ std::unique_ptr<Buffer> buffer = std::make_unique<Buffer>(
+ exo_test_helper()->CreateGpuMemoryBuffer(buffer_size));
+ std::unique_ptr<Surface> surface = std::make_unique<Surface>();
gfx::Rect fullscreen_bounds(0, 0, 800, 600);
@@ -685,10 +688,54 @@ TEST_F(ClientControlledShellSurfaceTest, NoSynthesizedEventOnFrameChange) {
shell_surface->SetGeometry(cropped_fullscreen_bounds);
surface->Commit();
base::RunLoop().RunUntilIdle();
- EXPECT_FALSE(handler.received_event());
+ EXPECT_TRUE(handler.mouse_events().empty());
env->RemovePreTargetHandler(&handler);
}
+// Shell surfaces should not emit extra events on commit even if using pixel
+// coordinates and a cursor is hovering over the window.
+// https://crbug.com/1296315.
+TEST_F(ClientControlledShellSurfaceTest,
+ NoSynthesizedEventsForPixelCoordinates) {
+ TestEventHandler event_handler;
+
+ gfx::Size buffer_size(400, 400);
+ std::unique_ptr<Buffer> buffer(
+ new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
+ auto surface = std::make_unique<Surface>();
+ surface->Attach(buffer.get());
+ auto shell_surface =
+ exo_test_helper()->CreateClientControlledShellSurface(surface.get());
+ // Pixel coordinates add a transform to the underlying layer.
+ shell_surface->set_client_submits_surfaces_in_pixel_coordinates(true);
+
+ display::Display primary_display =
+ display::Screen::GetScreen()->GetPrimaryDisplay();
+ gfx::Rect initial_bounds(150, 10, 200, 200);
+ shell_surface->SetBounds(primary_display.id(), initial_bounds);
+
+ // Tested condition only happens when cursor is over the window.
+ ui::test::EventGenerator generator(ash::Shell::GetPrimaryRootWindow());
+ generator.MoveMouseTo(200, 110);
+
+ shell_surface->host_window()->AddPreTargetHandler(&event_handler);
+ shell_surface->Activate();
+ // Commit an arbitrary number of frames. We expect that this will not generate
+ // synthetic events.
+ for (int i = 0; i < 5; i++) {
+ surface->Commit();
+ task_environment()->RunUntilIdle();
+ }
+
+ // There should be 2 events. One for mouse enter and the other for move.
+ const auto& events = event_handler.mouse_events();
+ ASSERT_EQ(events.size(), 2UL);
+ EXPECT_EQ(events[0].type(), ui::ET_MOUSE_ENTERED);
+ EXPECT_EQ(events[1].type(), ui::ET_MOUSE_MOVED);
+
+ shell_surface->host_window()->RemovePreTargetHandler(&event_handler);
+}
+
TEST_F(ClientControlledShellSurfaceTest, CompositorLockInRotation) {
UpdateDisplay("800x600");
const gfx::Size buffer_size(800, 600);
@@ -2776,31 +2823,9 @@ TEST_F(ClientControlledShellSurfaceTest, OverlayShadowBounds) {
}
}
-class ClientControlledShellSurfaceFullRestoreTest
- : public ClientControlledShellSurfaceTest {
- public:
- ClientControlledShellSurfaceFullRestoreTest() = default;
- ClientControlledShellSurfaceFullRestoreTest(
- const ClientControlledShellSurfaceFullRestoreTest&) = delete;
- ClientControlledShellSurfaceFullRestoreTest& operator=(
- const ClientControlledShellSurfaceFullRestoreTest&) = delete;
- ~ClientControlledShellSurfaceFullRestoreTest() override = default;
-
- // ClientControlledShellSurfaceTest:
- void SetUp() override {
- scoped_feature_list_.InitAndEnableFeature(
- ::full_restore::features::kFullRestore);
- ClientControlledShellSurfaceTest::SetUp();
- }
-
- private:
- base::test::ScopedFeatureList scoped_feature_list_;
-};
-
// WideFrameView follows its respective surface when it is eventually parented.
// See crbug.com/1223135.
-TEST_F(ClientControlledShellSurfaceFullRestoreTest,
- WideframeForUnparentedTasks) {
+TEST_F(ClientControlledShellSurfaceTest, WideframeForUnparentedTasks) {
auto surface = std::make_unique<Surface>();
auto shell_surface =
exo_test_helper()->CreateClientControlledShellSurface(surface.get());
@@ -2837,8 +2862,7 @@ TEST_F(ClientControlledShellSurfaceFullRestoreTest,
// Call the WindowRestoreController, simulating the ARC task becoming ready.
// The surface should be reparented and the WideFrameView should follow it.
- ash::WindowRestoreController::Get()->OnARCTaskReadyForUnparentedWindow(
- window);
+ ash::WindowRestoreController::Get()->OnParentWindowToValidContainer(window);
EXPECT_NE(hidden_container_parent, window->parent());
wide_frame = shell_surface->wide_frame_for_test();
EXPECT_TRUE(wide_frame);
diff --git a/chromium/components/exo/data_device.cc b/chromium/components/exo/data_device.cc
index 63844f98382..b219c48527d 100644
--- a/chromium/components/exo/data_device.cc
+++ b/chromium/components/exo/data_device.cc
@@ -163,7 +163,7 @@ void DataDevice::OnDragExited() {
data_offer_.reset();
}
-DragOperation DataDevice::OnPerformDrop(const ui::DropTargetEvent& event) {
+DragOperation DataDevice::OnPerformDrop() {
if (!data_offer_)
return DragOperation::kNone;
@@ -271,9 +271,8 @@ void DataDevice::SetSelectionToCurrentClipboardData() {
void DataDevice::PerformDropOrExitDrag(
base::ScopedClosureRunner exit_drag,
- const ui::DropTargetEvent& event,
ui::mojom::DragOperation& output_drag_op) {
- output_drag_op = OnPerformDrop(event);
+ output_drag_op = OnPerformDrop();
exit_drag.ReplaceClosure(base::DoNothing());
}
diff --git a/chromium/components/exo/data_device.h b/chromium/components/exo/data_device.h
index f19326963be..fd421dffbd0 100644
--- a/chromium/components/exo/data_device.h
+++ b/chromium/components/exo/data_device.h
@@ -64,8 +64,7 @@ class DataDevice : public WMHelper::DragDropObserver,
aura::client::DragUpdateInfo OnDragUpdated(
const ui::DropTargetEvent& event) override;
void OnDragExited() override;
- ui::mojom::DragOperation OnPerformDrop(
- const ui::DropTargetEvent& event) override;
+ ui::mojom::DragOperation OnPerformDrop() override;
WMHelper::DragDropObserver::DropCallback GetDropCallback(
const ui::DropTargetEvent& event) override;
@@ -90,7 +89,6 @@ class DataDevice : public WMHelper::DragDropObserver,
void SetSelectionToCurrentClipboardData();
void PerformDropOrExitDrag(base::ScopedClosureRunner exit_drag,
- const ui::DropTargetEvent& event,
ui::mojom::DragOperation& output_drag_op);
DataDeviceDelegate* const delegate_;
diff --git a/chromium/components/exo/data_device_unittest.cc b/chromium/components/exo/data_device_unittest.cc
index 57bf20685f8..9aa239f3d7c 100644
--- a/chromium/components/exo/data_device_unittest.cc
+++ b/chromium/components/exo/data_device_unittest.cc
@@ -191,7 +191,7 @@ TEST_F(DataDeviceTest, DataEventsDrop) {
FROM_HERE, base::BindOnce(&TestDataDeviceDelegate::DeleteDataOffer,
base::Unretained(&delegate_), true));
- DragOperation result = device_->OnPerformDrop(event);
+ DragOperation result = device_->OnPerformDrop();
EXPECT_EQ(DragOperation::kLink, result);
ASSERT_EQ(1u, delegate_.PopEvents(&events));
EXPECT_EQ(DataEvent::kDrop, events[0]);
@@ -284,7 +284,7 @@ TEST_F(DataDeviceTest, DataEventsPreventMotion) {
FROM_HERE, base::BindOnce(&TestDataDeviceDelegate::DeleteDataOffer,
base::Unretained(&delegate_), true));
- DragOperation result = device_->OnPerformDrop(event);
+ DragOperation result = device_->OnPerformDrop();
EXPECT_EQ(DragOperation::kLink, result);
ASSERT_EQ(1u, delegate_.PopEvents(&events));
EXPECT_EQ(DataEvent::kDrop, events[0]);
@@ -319,7 +319,7 @@ TEST_F(DataDeviceTest, DeleteDataDeviceDuringDrop) {
device_->OnDragEntered(event);
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindLambdaForTesting([&]() { device_.reset(); }));
- DragOperation result = device_->OnPerformDrop(event);
+ DragOperation result = device_->OnPerformDrop();
EXPECT_EQ(DragOperation::kNone, result);
}
@@ -340,7 +340,7 @@ TEST_F(DataDeviceTest, DeleteDataOfferDuringDrag) {
device_->OnDragUpdated(event).drag_operation);
EXPECT_EQ(0u, delegate_.PopEvents(&events));
- device_->OnPerformDrop(event);
+ device_->OnPerformDrop();
EXPECT_EQ(0u, delegate_.PopEvents(&events));
}
@@ -364,7 +364,7 @@ TEST_F(DataDeviceTest, DataOfferNotFinished) {
FROM_HERE, base::BindOnce(&TestDataDeviceDelegate::DeleteDataOffer,
base::Unretained(&delegate_), false));
- DragOperation result = device_->OnPerformDrop(event);
+ DragOperation result = device_->OnPerformDrop();
EXPECT_EQ(DragOperation::kNone, result);
ASSERT_EQ(1u, delegate_.PopEvents(&events));
EXPECT_EQ(DataEvent::kDrop, events[0]);
@@ -385,7 +385,7 @@ TEST_F(DataDeviceTest, NotAcceptDataEventsForSurface) {
device_->OnDragUpdated(event).drag_operation);
EXPECT_EQ(0u, delegate_.PopEvents(&events));
- device_->OnPerformDrop(event);
+ device_->OnPerformDrop();
EXPECT_EQ(0u, delegate_.PopEvents(&events));
}
@@ -412,7 +412,7 @@ TEST_F(DataDeviceTest, DropCallback_Run) {
base::Unretained(&delegate_), true));
DragOperation output_drag_op = DragOperation::kNone;
- std::move(drop_cb).Run(event, output_drag_op);
+ std::move(drop_cb).Run(output_drag_op);
EXPECT_EQ(DragOperation::kLink, output_drag_op);
ASSERT_EQ(1u, delegate_.PopEvents(&events));
@@ -440,7 +440,7 @@ TEST_F(DataDeviceTest, DropCallback_Invalidated) {
delegate_.DeleteDataOffer(false);
DragOperation output_drag_op = DragOperation::kNone;
- std::move(drop_cb).Run(event, output_drag_op);
+ std::move(drop_cb).Run(output_drag_op);
EXPECT_EQ(DragOperation::kNone, output_drag_op);
EXPECT_EQ(0u, delegate_.PopEvents(&events));
diff --git a/chromium/components/exo/data_offer.cc b/chromium/components/exo/data_offer.cc
index 3827ddcf24d..e98959787a2 100644
--- a/chromium/components/exo/data_offer.cc
+++ b/chromium/components/exo/data_offer.cc
@@ -20,6 +20,7 @@
#include "base/strings/utf_string_conversions.h"
#include "base/task/post_task.h"
#include "base/task/thread_pool.h"
+#include "build/chromeos_buildflags.h"
#include "components/exo/data_device.h"
#include "components/exo/data_exchange_delegate.h"
#include "components/exo/data_offer_delegate.h"
@@ -33,6 +34,7 @@
#include "ui/base/clipboard/clipboard_constants.h"
#include "ui/base/clipboard/file_info.h"
#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
+#include "ui/base/data_transfer_policy/data_transfer_endpoint_serializer.h"
#include "ui/base/dragdrop/os_exchange_data.h"
#include "url/gurl.h"
@@ -91,6 +93,22 @@ DataOffer::AsyncSendDataCallback AsyncEncodeAsRefCountedString(
text, charset);
}
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+void ReadDataTransferEndpointFromClipboard(
+ const std::string& charset,
+ const ui::DataTransferEndpoint data_dst,
+ DataOffer::SendDataCallback callback) {
+ const ui::DataTransferEndpoint* data_src =
+ ui::Clipboard::GetForCurrentThread()->GetSource(
+ ui::ClipboardBuffer::kCopyPaste);
+
+ DCHECK(data_src);
+ std::u16string encoded_endpoint =
+ base::UTF8ToUTF16(ui::ConvertDataTransferEndpointToJson(*data_src));
+ std::move(callback).Run(EncodeAsRefCountedString(encoded_endpoint, charset));
+}
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
+
void ReadTextFromClipboard(const std::string& charset,
const ui::DataTransferEndpoint data_dst,
DataOffer::SendDataCallback callback) {
@@ -217,6 +235,20 @@ void DataOffer::SetDropData(DataExchangeDelegate* data_exchange_delegate,
ui::EndpointType endpoint_type =
data_exchange_delegate->GetDataTransferEndpointType(target);
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+ // Drag & Drop source metadata (if any) is synced between Ash and Lacros by
+ // encoding the metadata into a custom MIME type.
+ if (endpoint_type == ui::EndpointType::kLacros && data.GetSource()) {
+ std::u16string encoded_endpoint = base::UTF8ToUTF16(
+ ui::ConvertDataTransferEndpointToJson(*data.GetSource()));
+ data_callbacks_.emplace(
+ ui::kMimeTypeDataTransferEndpoint,
+ AsyncEncodeAsRefCountedString(encoded_endpoint, kUTF8));
+ delegate_->OnOffer(ui::kMimeTypeDataTransferEndpoint);
+ }
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
+
const std::string uri_list_mime_type =
data_exchange_delegate->GetMimeTypeForUriList(endpoint_type);
// We accept the filenames pickle from FilesApp, or
@@ -313,6 +345,20 @@ void DataOffer::SetClipboardData(DataExchangeDelegate* data_exchange_delegate,
ui::EndpointType endpoint_type) {
DCHECK_EQ(0u, data_callbacks_.size());
const ui::DataTransferEndpoint data_dst(endpoint_type);
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+ // Clipboard source metadata (if any) is synced between Ash and Lacros by
+ // encoding the metadata into a custom MIME type.
+ if (endpoint_type == ui::EndpointType::kLacros &&
+ data.GetSource(ui::ClipboardBuffer::kCopyPaste)) {
+ delegate_->OnOffer(std::string(ui::kMimeTypeDataTransferEndpoint));
+ data_callbacks_.emplace(
+ std::string(ui::kMimeTypeDataTransferEndpoint),
+ base::BindOnce(&ReadDataTransferEndpointFromClipboard,
+ std::string(kUTF8), data_dst));
+ }
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
+
if (data.IsFormatAvailable(ui::ClipboardFormatType::PlainTextType(),
ui::ClipboardBuffer::kCopyPaste, &data_dst)) {
auto utf8_callback = base::BindRepeating(&ReadTextFromClipboard,
diff --git a/chromium/components/exo/data_offer_unittest.cc b/chromium/components/exo/data_offer_unittest.cc
index 8676dbdc89c..2b29b6cb7ee 100644
--- a/chromium/components/exo/data_offer_unittest.cc
+++ b/chromium/components/exo/data_offer_unittest.cc
@@ -14,8 +14,10 @@
#include "base/callback_forward.h"
#include "base/containers/flat_set.h"
#include "base/files/file_util.h"
+#include "base/pickle.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
+#include "build/chromeos_buildflags.h"
#include "cc/test/pixel_comparator.h"
#include "cc/test/pixel_test_utils.h"
#include "components/exo/data_device.h"
@@ -24,6 +26,7 @@
#include "components/exo/test/exo_test_base.h"
#include "components/exo/test/exo_test_data_exchange_delegate.h"
#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/base/clipboard/clipboard.h"
#include "ui/base/clipboard/clipboard_format_type.h"
#include "ui/base/clipboard/scoped_clipboard_writer.h"
#include "ui/base/data_transfer_policy/data_transfer_policy_controller.h"
@@ -34,7 +37,13 @@
namespace exo {
namespace {
-using DataOfferTest = test::ExoTestBase;
+class DataOfferTest : public test::ExoTestBase {
+ public:
+ void TearDown() override {
+ ui::Clipboard::DestroyClipboardForCurrentThread();
+ test::ExoTestBase::TearDown();
+ }
+};
class TestDataOfferDelegate : public DataOfferDelegate {
public:
@@ -481,6 +490,204 @@ TEST_F(DataOfferTest, SetClipboardDataPlainText) {
EXPECT_EQ("Test data", base::UTF16ToUTF8(result16));
}
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+TEST_F(DataOfferTest, SetClipboardDataOfferDteToLacros) {
+ TestDataOfferDelegate delegate;
+ DataOffer data_offer(&delegate);
+
+ TestDataExchangeDelegate data_exchange_delegate;
+ data_exchange_delegate.set_endpoint_type(ui::EndpointType::kLacros);
+ {
+ ui::ScopedClipboardWriter writer(ui::ClipboardBuffer::kCopyPaste);
+ writer.SetDataSource(std::make_unique<ui::DataTransferEndpoint>(
+ url::Origin::Create(GURL("https://www.google.com"))));
+ writer.WriteText(u"Test data");
+ }
+
+ auto* window = CreateTestWindowInShellWithBounds(gfx::Rect());
+ data_offer.SetClipboardData(
+ &data_exchange_delegate, *ui::Clipboard::GetForCurrentThread(),
+ data_exchange_delegate.GetDataTransferEndpointType(window));
+
+ EXPECT_EQ(4u, delegate.mime_types().size());
+ EXPECT_EQ(1u, delegate.mime_types().count("text/plain;charset=utf-8"));
+ EXPECT_EQ(1u, delegate.mime_types().count("text/plain;charset=utf-16"));
+ EXPECT_EQ(1u, delegate.mime_types().count("UTF8_STRING"));
+ EXPECT_EQ(1u,
+ delegate.mime_types().count("chromium/x-data-transfer-endpoint"));
+
+ base::ScopedFD read_pipe;
+ base::ScopedFD write_pipe;
+
+ // Read as utf-8.
+ ASSERT_TRUE(base::CreatePipe(&read_pipe, &write_pipe));
+ data_offer.Receive("text/plain;charset=utf-8", std::move(write_pipe));
+ std::string text_result;
+ ASSERT_TRUE(ReadString(std::move(read_pipe), &text_result));
+ EXPECT_EQ("Test data", text_result);
+
+ // Retrieve encoded clipboard source data transfer endpoint.
+ ASSERT_TRUE(base::CreatePipe(&read_pipe, &write_pipe));
+ data_offer.Receive("chromium/x-data-transfer-endpoint",
+ std::move(write_pipe));
+ std::string dte_json_result;
+ ASSERT_TRUE(ReadString(std::move(read_pipe), &dte_json_result));
+ EXPECT_EQ(R"({"endpoint_type":"url","url_origin":"https://www.google.com"})",
+ dte_json_result);
+}
+
+TEST_F(DataOfferTest, SetClipboardDataDoNotOfferDteToNonLacros) {
+ TestDataOfferDelegate delegate;
+ DataOffer data_offer(&delegate);
+
+ TestDataExchangeDelegate data_exchange_delegate;
+ data_exchange_delegate.set_endpoint_type(ui::EndpointType::kArc);
+ {
+ ui::ScopedClipboardWriter writer(ui::ClipboardBuffer::kCopyPaste);
+ writer.SetDataSource(std::make_unique<ui::DataTransferEndpoint>(
+ url::Origin::Create(GURL("https://www.google.com"))));
+ writer.WriteText(u"Test data");
+ }
+
+ auto* window = CreateTestWindowInShellWithBounds(gfx::Rect());
+ data_offer.SetClipboardData(
+ &data_exchange_delegate, *ui::Clipboard::GetForCurrentThread(),
+ data_exchange_delegate.GetDataTransferEndpointType(window));
+
+ EXPECT_EQ(3u, delegate.mime_types().size());
+ EXPECT_EQ(1u, delegate.mime_types().count("text/plain;charset=utf-8"));
+ EXPECT_EQ(1u, delegate.mime_types().count("text/plain;charset=utf-16"));
+ EXPECT_EQ(1u, delegate.mime_types().count("UTF8_STRING"));
+ EXPECT_EQ(0u,
+ delegate.mime_types().count("chromium/x-data-transfer-endpoint"));
+
+ base::ScopedFD read_pipe;
+ base::ScopedFD write_pipe;
+
+ // Read as utf-8.
+ ASSERT_TRUE(base::CreatePipe(&read_pipe, &write_pipe));
+ data_offer.Receive("text/plain;charset=utf-8", std::move(write_pipe));
+ std::string text_result;
+ ASSERT_TRUE(ReadString(std::move(read_pipe), &text_result));
+ EXPECT_EQ("Test data", text_result);
+
+ // Attempt to retrieve encoded clipboard source data transfer endpoint.
+ // Nothing should be returned.
+ ASSERT_TRUE(base::CreatePipe(&read_pipe, &write_pipe));
+ data_offer.Receive("chromium/x-data-transfer-endpoint",
+ std::move(write_pipe));
+ std::string dte_json_result;
+ ASSERT_TRUE(ReadString(std::move(read_pipe), &dte_json_result));
+ EXPECT_EQ("", dte_json_result);
+}
+
+TEST_F(DataOfferTest, SetDropDataOfferDteToLacros) {
+ base::flat_set<DndAction> source_actions;
+ source_actions.insert(DndAction::kCopy);
+ source_actions.insert(DndAction::kMove);
+
+ ui::OSExchangeData data;
+ data.SetString(std::u16string(u"Test data"));
+ data.SetSource(std::make_unique<ui::DataTransferEndpoint>(
+ url::Origin::Create(GURL("https://www.google.com"))));
+
+ TestDataOfferDelegate delegate;
+ DataOffer data_offer(&delegate);
+
+ EXPECT_EQ(0u, delegate.mime_types().size());
+ EXPECT_EQ(0u, delegate.source_actions().size());
+ EXPECT_EQ(DndAction::kNone, delegate.dnd_action());
+
+ TestDataExchangeDelegate data_exchange_delegate;
+ data_exchange_delegate.set_endpoint_type(ui::EndpointType::kLacros);
+
+ data_offer.SetDropData(&data_exchange_delegate, nullptr, data);
+ data_offer.SetSourceActions(source_actions);
+ data_offer.SetActions(base::flat_set<DndAction>(), DndAction::kMove);
+
+ EXPECT_EQ(1u, delegate.mime_types().count("text/plain;charset=utf-8"));
+ EXPECT_EQ(1u, delegate.mime_types().count("text/plain;charset=utf-16"));
+ EXPECT_EQ(1u,
+ delegate.mime_types().count("chromium/x-data-transfer-endpoint"));
+ EXPECT_EQ(2u, delegate.source_actions().size());
+ EXPECT_EQ(1u, delegate.source_actions().count(DndAction::kCopy));
+ EXPECT_EQ(1u, delegate.source_actions().count(DndAction::kMove));
+ EXPECT_EQ(DndAction::kMove, delegate.dnd_action());
+
+ base::ScopedFD read_pipe;
+ base::ScopedFD write_pipe;
+
+ // Read as utf-8.
+ ASSERT_TRUE(base::CreatePipe(&read_pipe, &write_pipe));
+ data_offer.Receive("text/plain;charset=utf-8", std::move(write_pipe));
+ std::string text_result;
+ ASSERT_TRUE(ReadString(std::move(read_pipe), &text_result));
+ EXPECT_EQ("Test data", text_result);
+
+ // Retrieve encoded drag source data transfer endpoint.
+ ASSERT_TRUE(base::CreatePipe(&read_pipe, &write_pipe));
+ data_offer.Receive("chromium/x-data-transfer-endpoint",
+ std::move(write_pipe));
+ std::string dte_json_result;
+ ASSERT_TRUE(ReadString(std::move(read_pipe), &dte_json_result));
+ EXPECT_EQ(R"({"endpoint_type":"url","url_origin":"https://www.google.com"})",
+ dte_json_result);
+}
+
+TEST_F(DataOfferTest, SetDropDataDoNotOfferDteToNonLacros) {
+ base::flat_set<DndAction> source_actions;
+ source_actions.insert(DndAction::kCopy);
+ source_actions.insert(DndAction::kMove);
+
+ ui::OSExchangeData data;
+ data.SetString(std::u16string(u"Test data"));
+ data.SetSource(std::make_unique<ui::DataTransferEndpoint>(
+ url::Origin::Create(GURL("https://www.google.com"))));
+
+ TestDataOfferDelegate delegate;
+ DataOffer data_offer(&delegate);
+
+ EXPECT_EQ(0u, delegate.mime_types().size());
+ EXPECT_EQ(0u, delegate.source_actions().size());
+ EXPECT_EQ(DndAction::kNone, delegate.dnd_action());
+
+ TestDataExchangeDelegate data_exchange_delegate;
+ data_exchange_delegate.set_endpoint_type(ui::EndpointType::kCrostini);
+
+ data_offer.SetDropData(&data_exchange_delegate, nullptr, data);
+ data_offer.SetSourceActions(source_actions);
+ data_offer.SetActions(base::flat_set<DndAction>(), DndAction::kMove);
+
+ EXPECT_EQ(1u, delegate.mime_types().count("text/plain;charset=utf-8"));
+ EXPECT_EQ(1u, delegate.mime_types().count("text/plain;charset=utf-16"));
+ EXPECT_EQ(0u,
+ delegate.mime_types().count("chromium/x-data-transfer-endpoint"));
+ EXPECT_EQ(2u, delegate.source_actions().size());
+ EXPECT_EQ(1u, delegate.source_actions().count(DndAction::kCopy));
+ EXPECT_EQ(1u, delegate.source_actions().count(DndAction::kMove));
+ EXPECT_EQ(DndAction::kMove, delegate.dnd_action());
+
+ base::ScopedFD read_pipe;
+ base::ScopedFD write_pipe;
+
+ // Read as utf-8.
+ ASSERT_TRUE(base::CreatePipe(&read_pipe, &write_pipe));
+ data_offer.Receive("text/plain;charset=utf-8", std::move(write_pipe));
+ std::string text_result;
+ ASSERT_TRUE(ReadString(std::move(read_pipe), &text_result));
+ EXPECT_EQ("Test data", text_result);
+
+ // Attempt to retrieve encoded drag source data transfer endpoint.
+ // Nothing should be returned.
+ ASSERT_TRUE(base::CreatePipe(&read_pipe, &write_pipe));
+ data_offer.Receive("chromium/x-data-transfer-endpoint",
+ std::move(write_pipe));
+ std::string dte_json_result;
+ ASSERT_TRUE(ReadString(std::move(read_pipe), &dte_json_result));
+ EXPECT_EQ("", dte_json_result);
+}
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
+
TEST_F(DataOfferTest, SetClipboardDataHTML) {
TestDataOfferDelegate delegate;
DataOffer data_offer(&delegate);
diff --git a/chromium/components/exo/data_source.cc b/chromium/components/exo/data_source.cc
index 4359ebf2699..d30848dddca 100644
--- a/chromium/components/exo/data_source.cc
+++ b/chromium/components/exo/data_source.cc
@@ -35,6 +35,7 @@ constexpr char kTextHTML[] = "text/html";
constexpr char kTextUriList[] = "text/uri-list";
constexpr char kApplicationOctetStream[] = "application/octet-stream";
constexpr char kWebCustomData[] = "chromium/x-web-custom-data";
+constexpr char kDataTransferEndpoint[] = "chromium/x-data-transfer-endpoint";
constexpr char kUtfPrefix[] = "UTF";
constexpr char kEncoding16[] = "16";
@@ -95,12 +96,13 @@ int GetCharsetRank(const std::string& charset_input) {
// considered to have any greater meaning. In particular, these are not expected
// to remain stable over time.
int GetImageTypeRank(const std::string& mime_type) {
- // Prefer bitmaps most of all to avoid needing to decode the image, followed
- // by other lossless formats, followed by any other format we support.
- if (net::MatchesMimeType(std::string(kImageBitmap), mime_type))
- return 0;
+ // Prefer PNG most of all because this format preserves the alpha channel and
+ // is lossless, followed by BMP for being lossless and fast to decode (but
+ // doesn't preserve alpha), followed by everything else.
if (net::MatchesMimeType(std::string(kImagePNG), mime_type) ||
net::MatchesMimeType(std::string(kImageAPNG), mime_type))
+ return 0;
+ if (net::MatchesMimeType(std::string(kImageBitmap), mime_type))
return 1;
return 2;
}
@@ -253,6 +255,16 @@ void DataSource::OnDataRead(ReadDataCallback callback,
std::move(callback).Run(mime_type, *data);
}
+void DataSource::ReadDataTransferEndpoint(
+ ReadTextDataCallback dte_reader,
+ base::RepeatingClosure failure_callback) {
+ ReadData(kDataTransferEndpoint,
+ base::BindOnce(&DataSource::OnTextRead,
+ read_data_weak_ptr_factory_.GetWeakPtr(),
+ std::move(dte_reader)),
+ failure_callback);
+}
+
void DataSource::GetDataForPreferredMimeTypes(
ReadTextDataCallback text_reader,
ReadDataCallback rtf_reader,
diff --git a/chromium/components/exo/data_source.h b/chromium/components/exo/data_source.h
index 1f9310fd5ad..1e5974590c0 100644
--- a/chromium/components/exo/data_source.h
+++ b/chromium/components/exo/data_source.h
@@ -86,6 +86,8 @@ class DataSource {
const std::vector<uint8_t>&)>;
using ReadWebCustomDataCallback =
base::OnceCallback<void(const std::string&, const std::vector<uint8_t>&)>;
+ void ReadDataTransferEndpoint(ReadTextDataCallback dte_reader,
+ base::RepeatingClosure failure_callback);
void GetDataForPreferredMimeTypes(
ReadTextDataCallback text_reader,
ReadDataCallback rtf_reader,
diff --git a/chromium/components/exo/data_source_unittest.cc b/chromium/components/exo/data_source_unittest.cc
index 69a383ac448..423579bf0b0 100644
--- a/chromium/components/exo/data_source_unittest.cc
+++ b/chromium/components/exo/data_source_unittest.cc
@@ -209,6 +209,25 @@ TEST_F(DataSourceTest, ReadData_Cancelled) {
task_environment_.RunUntilIdle();
}
+TEST_F(DataSourceTest, CheckDteMimeTypeReceived) {
+ TestDataSourceDelegate delegate;
+ DataSource data_source(&delegate);
+ const std::string kDteMimeType("chromium/x-data-transfer-endpoint");
+ data_source.Offer(kDteMimeType);
+
+ base::RunLoop run_loop;
+ base::RepeatingClosure counter =
+ base::BarrierClosure(1, run_loop.QuitClosure());
+ std::atomic_int failure_count{0};
+
+ data_source.ReadDataTransferEndpoint(
+ base::BindOnce(&CheckTextMimeType, kDteMimeType, counter),
+ base::BindRepeating(&IncrementFailureCounter, &failure_count, counter));
+
+ run_loop.Run();
+ EXPECT_EQ(0, failure_count.load());
+}
+
TEST_F(DataSourceTest, PreferredMimeTypeUTF16) {
TestDataSourceDelegate delegate;
DataSource data_source(&delegate);
@@ -298,13 +317,13 @@ TEST_F(DataSourceTest, PreferredMimeTypeRTF) {
CheckMimeTypesReceived(&data_source, "", "text/rtf", "", "", "", {});
}
-TEST_F(DataSourceTest, PreferredMimeTypeBitmapToPNG) {
+TEST_F(DataSourceTest, PreferredMimeTypePNGtoBitmap) {
TestDataSourceDelegate delegate;
DataSource data_source(&delegate);
data_source.Offer("image/bmp");
data_source.Offer("image/png");
- CheckMimeTypesReceived(&data_source, "", "", "", "image/bmp", "", {});
+ CheckMimeTypesReceived(&data_source, "", "", "", "image/png", "", {});
}
TEST_F(DataSourceTest, PreferredMimeTypePNGToJPEG) {
@@ -317,6 +336,16 @@ TEST_F(DataSourceTest, PreferredMimeTypePNGToJPEG) {
CheckMimeTypesReceived(&data_source, "", "", "", "image/png", "", {});
}
+TEST_F(DataSourceTest, PreferredMimeTypeBitmaptoJPEG) {
+ TestDataSourceDelegate delegate;
+ DataSource data_source(&delegate);
+ data_source.Offer("image/bmp");
+ data_source.Offer("image/jpeg");
+ data_source.Offer("image/jpg");
+
+ CheckMimeTypesReceived(&data_source, "", "", "", "image/bmp", "", {});
+}
+
TEST_F(DataSourceTest, PreferredMimeTypeTextUriList) {
TestDataSourceDelegate delegate;
DataSource data_source(&delegate);
diff --git a/chromium/components/exo/display_unittest.cc b/chromium/components/exo/display_unittest.cc
index 28e1a948bec..3469fdc8089 100644
--- a/chromium/components/exo/display_unittest.cc
+++ b/chromium/components/exo/display_unittest.cc
@@ -84,15 +84,15 @@ class DisplayTest : public test::ExoTestBase {
};
TEST_F(DisplayTest, CreateSurface) {
- std::unique_ptr<Display> display(new Display);
+ Display display;
// Creating a surface should succeed.
- std::unique_ptr<Surface> surface = display->CreateSurface();
+ std::unique_ptr<Surface> surface = display.CreateSurface();
EXPECT_TRUE(surface);
}
TEST_F(DisplayTest, CreateSharedMemory) {
- std::unique_ptr<Display> display(new Display);
+ Display display;
int shm_size = 8192;
base::UnsafeSharedMemoryRegion shared_memory =
@@ -101,12 +101,12 @@ TEST_F(DisplayTest, CreateSharedMemory) {
// Creating a shared memory instance from a valid region should succeed.
std::unique_ptr<SharedMemory> shm1 =
- display->CreateSharedMemory(std::move(shared_memory));
+ display.CreateSharedMemory(std::move(shared_memory));
EXPECT_TRUE(shm1);
// Creating a shared memory instance from a invalid region should fail.
std::unique_ptr<SharedMemory> shm2 =
- display->CreateSharedMemory(base::UnsafeSharedMemoryRegion());
+ display.CreateSharedMemory(base::UnsafeSharedMemoryRegion());
EXPECT_FALSE(shm2);
}
@@ -115,7 +115,7 @@ TEST_F(DisplayTest, CreateSharedMemory) {
TEST_F(DisplayTest, DISABLED_CreateLinuxDMABufBuffer) {
const gfx::Size buffer_size(256, 256);
- std::unique_ptr<Display> display(new Display);
+ Display display;
// Creating a prime buffer from a native pixmap handle should succeed.
scoped_refptr<gfx::NativePixmap> pixmap =
ui::OzonePlatform::GetInstance()
@@ -124,9 +124,9 @@ TEST_F(DisplayTest, DISABLED_CreateLinuxDMABufBuffer) {
buffer_size, gfx::BufferFormat::RGBA_8888,
gfx::BufferUsage::GPU_READ);
gfx::NativePixmapHandle native_pixmap_handle = pixmap->ExportHandle();
- std::unique_ptr<Buffer> buffer1 = display->CreateLinuxDMABufBuffer(
- buffer_size, gfx::BufferFormat::RGBA_8888,
- std::move(native_pixmap_handle), false);
+ std::unique_ptr<Buffer> buffer1 =
+ display.CreateLinuxDMABufBuffer(buffer_size, gfx::BufferFormat::RGBA_8888,
+ std::move(native_pixmap_handle), false);
EXPECT_TRUE(buffer1);
// Create a handle without a file descriptor.
@@ -134,9 +134,9 @@ TEST_F(DisplayTest, DISABLED_CreateLinuxDMABufBuffer) {
native_pixmap_handle.planes[0].fd.reset();
// Creating a prime buffer using an invalid fd should fail.
- std::unique_ptr<Buffer> buffer2 = display->CreateLinuxDMABufBuffer(
- buffer_size, gfx::BufferFormat::RGBA_8888,
- std::move(native_pixmap_handle), false);
+ std::unique_ptr<Buffer> buffer2 =
+ display.CreateLinuxDMABufBuffer(buffer_size, gfx::BufferFormat::RGBA_8888,
+ std::move(native_pixmap_handle), false);
EXPECT_FALSE(buffer2);
}
@@ -146,37 +146,37 @@ TEST_F(DisplayTest, DISABLED_CreateLinuxDMABufBuffer) {
#endif
TEST_F(DisplayTest, CreateShellSurface) {
- std::unique_ptr<Display> display(new Display);
+ Display display;
// Create two surfaces.
- std::unique_ptr<Surface> surface1 = display->CreateSurface();
+ std::unique_ptr<Surface> surface1 = display.CreateSurface();
ASSERT_TRUE(surface1);
- std::unique_ptr<Surface> surface2 = display->CreateSurface();
+ std::unique_ptr<Surface> surface2 = display.CreateSurface();
ASSERT_TRUE(surface2);
// Create a shell surface for surface1.
std::unique_ptr<ShellSurface> shell_surface1 =
- display->CreateShellSurface(surface1.get());
+ display.CreateShellSurface(surface1.get());
EXPECT_TRUE(shell_surface1);
// Create a shell surface for surface2.
std::unique_ptr<ShellSurface> shell_surface2 =
- display->CreateShellSurface(surface2.get());
+ display.CreateShellSurface(surface2.get());
EXPECT_TRUE(shell_surface2);
}
TEST_F(DisplayTest, CreateClientControlledShellSurface) {
- std::unique_ptr<Display> display(new Display);
+ Display display;
// Create two surfaces.
- std::unique_ptr<Surface> surface1 = display->CreateSurface();
+ std::unique_ptr<Surface> surface1 = display.CreateSurface();
ASSERT_TRUE(surface1);
- std::unique_ptr<Surface> surface2 = display->CreateSurface();
+ std::unique_ptr<Surface> surface2 = display.CreateSurface();
ASSERT_TRUE(surface2);
// Create a remote shell surface for surface1.
std::unique_ptr<ClientControlledShellSurface> shell_surface1 =
- display->CreateOrGetClientControlledShellSurface(
+ display.CreateOrGetClientControlledShellSurface(
surface1.get(), ash::kShellWindowId_SystemModalContainer,
/*default_scale_factor=*/2.0,
/*default_scale_cancellation=*/true);
@@ -185,7 +185,7 @@ TEST_F(DisplayTest, CreateClientControlledShellSurface) {
// Create a remote shell surface for surface2.
std::unique_ptr<ShellSurfaceBase> shell_surface2 =
- display->CreateOrGetClientControlledShellSurface(
+ display.CreateOrGetClientControlledShellSurface(
surface2.get(), ash::desks_util::GetActiveDeskContainerId(),
/*default_scale_factor=*/1.0,
/*default_scale_cancellation=*/true);
@@ -193,25 +193,26 @@ TEST_F(DisplayTest, CreateClientControlledShellSurface) {
}
TEST_F(DisplayTest, GetClientControlledShellSurface) {
- std::unique_ptr<Display> display(new Display);
+ Display display;
// Create a external surface, bind with a window id.
+ std::unique_ptr<Surface> surface = display.CreateSurface();
ClientControlledShellSurface* external_shell_surface =
new ClientControlledShellSurface(
- new Surface,
+ surface.get(),
/*can_minimize=*/true, ash::desks_util::GetActiveDeskContainerId(),
/*default_scale_cancellation=*/true);
property_resolver()->PutClientControlledShellSurface(
/*window_session_id=*/10001, base::WrapUnique(external_shell_surface));
// Create surface with specific window id.
- std::unique_ptr<Surface> surface_with_id = display->CreateSurface();
+ std::unique_ptr<Surface> surface_with_id = display.CreateSurface();
ASSERT_TRUE(surface_with_id);
surface_with_id->SetWindowSessionId(10001);
// Get a remote shell surface by external source.
std::unique_ptr<ClientControlledShellSurface> shell_surface =
- display->CreateOrGetClientControlledShellSurface(
+ display.CreateOrGetClientControlledShellSurface(
surface_with_id.get(), ash::desks_util::GetActiveDeskContainerId(),
/*default_scale_factor=*/2.0,
/*default_scale_cancellation=*/true);
@@ -220,68 +221,68 @@ TEST_F(DisplayTest, GetClientControlledShellSurface) {
}
TEST_F(DisplayTest, CreateSubSurface) {
- std::unique_ptr<Display> display(new Display);
+ Display display;
// Create child, parent and toplevel surfaces.
- std::unique_ptr<Surface> child = display->CreateSurface();
+ std::unique_ptr<Surface> child = display.CreateSurface();
ASSERT_TRUE(child);
- std::unique_ptr<Surface> parent = display->CreateSurface();
+ std::unique_ptr<Surface> parent = display.CreateSurface();
ASSERT_TRUE(parent);
- std::unique_ptr<Surface> toplevel = display->CreateSurface();
+ std::unique_ptr<Surface> toplevel = display.CreateSurface();
ASSERT_TRUE(toplevel);
// Attempting to create a sub surface for child with child as its parent
// should fail.
- EXPECT_FALSE(display->CreateSubSurface(child.get(), child.get()));
+ EXPECT_FALSE(display.CreateSubSurface(child.get(), child.get()));
// Create a sub surface for child.
std::unique_ptr<SubSurface> child_sub_surface =
- display->CreateSubSurface(child.get(), toplevel.get());
+ display.CreateSubSurface(child.get(), toplevel.get());
EXPECT_TRUE(child_sub_surface);
// Attempting to create another sub surface when already assigned the role of
// sub surface should fail.
- EXPECT_FALSE(display->CreateSubSurface(child.get(), parent.get()));
+ EXPECT_FALSE(display.CreateSubSurface(child.get(), parent.get()));
// Deleting the sub surface should allow a new sub surface to be created.
child_sub_surface.reset();
- child_sub_surface = display->CreateSubSurface(child.get(), parent.get());
+ child_sub_surface = display.CreateSubSurface(child.get(), parent.get());
EXPECT_TRUE(child_sub_surface);
- std::unique_ptr<Surface> sibling = display->CreateSurface();
+ std::unique_ptr<Surface> sibling = display.CreateSurface();
ASSERT_TRUE(sibling);
// Create a sub surface for sibiling.
std::unique_ptr<SubSurface> sibling_sub_surface =
- display->CreateSubSurface(sibling.get(), parent.get());
+ display.CreateSubSurface(sibling.get(), parent.get());
EXPECT_TRUE(sibling_sub_surface);
// Create a shell surface for toplevel surface.
std::unique_ptr<ShellSurface> shell_surface =
- display->CreateShellSurface(toplevel.get());
+ display.CreateShellSurface(toplevel.get());
EXPECT_TRUE(shell_surface);
// Attempting to create a sub surface when already assigned the role of
// shell surface should fail.
- EXPECT_FALSE(display->CreateSubSurface(toplevel.get(), parent.get()));
+ EXPECT_FALSE(display.CreateSubSurface(toplevel.get(), parent.get()));
- std::unique_ptr<Surface> grandchild = display->CreateSurface();
+ std::unique_ptr<Surface> grandchild = display.CreateSurface();
ASSERT_TRUE(grandchild);
// Create a sub surface for grandchild.
std::unique_ptr<SubSurface> grandchild_sub_surface =
- display->CreateSubSurface(grandchild.get(), child.get());
+ display.CreateSubSurface(grandchild.get(), child.get());
EXPECT_TRUE(grandchild_sub_surface);
// Attempting to create a sub surface for parent with child as its parent
// should fail.
- EXPECT_FALSE(display->CreateSubSurface(parent.get(), child.get()));
+ EXPECT_FALSE(display.CreateSubSurface(parent.get(), child.get()));
// Attempting to create a sub surface for parent with grandchild as its parent
// should fail.
- EXPECT_FALSE(display->CreateSubSurface(parent.get(), grandchild.get()));
+ EXPECT_FALSE(display.CreateSubSurface(parent.get(), grandchild.get()));
// Create a sub surface for parent.
- EXPECT_TRUE(display->CreateSubSurface(parent.get(), toplevel.get()));
+ EXPECT_TRUE(display.CreateSubSurface(parent.get(), toplevel.get()));
}
class TestDataDeviceDelegate : public DataDeviceDelegate {
diff --git a/chromium/components/exo/drag_drop_operation.cc b/chromium/components/exo/drag_drop_operation.cc
index 08f7958b050..b17872ec27b 100644
--- a/chromium/components/exo/drag_drop_operation.cc
+++ b/chromium/components/exo/drag_drop_operation.cc
@@ -36,7 +36,9 @@
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "ash/drag_drop/drag_drop_controller.h"
+#include "chromeos/ui/base/window_properties.h"
#include "components/exo/extended_drag_source.h"
+#include "ui/base/data_transfer_policy/data_transfer_endpoint_serializer.h"
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
namespace exo {
@@ -49,7 +51,7 @@ uint32_t DndActionsToDragOperations(const base::flat_set<DndAction>& actions) {
for (const DndAction action : actions) {
switch (action) {
case DndAction::kNone:
- FALLTHROUGH;
+ [[fallthrough]];
// We don't support the ask action
case DndAction::kAsk:
break;
@@ -190,9 +192,11 @@ DragDropOperation::DragDropOperation(
drag_drop_controller_->AddObserver(this);
- os_exchange_data_->SetSource(std::make_unique<ui::DataTransferEndpoint>(
+ ui::EndpointType endpoint_type =
data_exchange_delegate->GetDataTransferEndpointType(
- origin_->get()->window())));
+ origin_->get()->window());
+ os_exchange_data_->SetSource(
+ std::make_unique<ui::DataTransferEndpoint>(endpoint_type));
#if BUILDFLAG(IS_CHROMEOS_ASH)
extended_drag_source_ = ExtendedDragSource::Get();
@@ -203,17 +207,42 @@ DragDropOperation::DragDropOperation(
}
#endif
- if (icon)
+ int num_additional_callbacks = 0;
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+ // TODO(crbug.com/1298033): Move DTE retrieval into
+ // DataSource::GetDataForPreferredMimeTypes()
+ // Lacros sends additional metadata, in a custom MIME type, to sync drag
+ // source metadata. Hence, the number of callbacks is incremented by one.
+ if (endpoint_type == ui::EndpointType::kLacros)
+ ++num_additional_callbacks;
+#endif
+
+ // When the icon is present, we increment the number of callbacks so we can
+ // wait for the icon to be captured as well.
+ if (icon) {
icon_ = std::make_unique<IconSurface>(icon, this);
+ ++num_additional_callbacks;
+ }
auto start_op_callback =
base::BindOnce(&DragDropOperation::ScheduleStartDragDropOperation,
weak_ptr_factory_.GetWeakPtr());
- // When the icon is present, make the count kMaxDataTypes + 1 so we can wait
- // for the icon to be captured as well.
- counter_ = base::BarrierClosure(DataSource::kMaxDataTypes + (icon ? 1 : 0),
- std::move(start_op_callback));
+ counter_ =
+ base::BarrierClosure(DataSource::kMaxDataTypes + num_additional_callbacks,
+ std::move(start_op_callback));
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+ // TODO(crbug.com/1298033): Move DTE retrieval into
+ // DataSource::GetDataForPreferredMimeTypes()
+ if (endpoint_type == ui::EndpointType::kLacros) {
+ source->ReadDataTransferEndpoint(
+ base::BindOnce(&DragDropOperation::OnDataTransferEndpointRead,
+ weak_ptr_factory_.GetWeakPtr()),
+ counter_);
+ }
+#endif
source->GetDataForPreferredMimeTypes(
base::BindOnce(&DragDropOperation::OnTextRead,
@@ -252,6 +281,20 @@ void DragDropOperation::AbortIfPending() {
delete this;
}
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+void DragDropOperation::OnDataTransferEndpointRead(const std::string& mime_type,
+ std::u16string data) {
+ DCHECK(os_exchange_data_);
+
+ std::string utf8_json = base::UTF16ToUTF8(data);
+ auto drag_source_dte = ui::ConvertJsonToDataTransferEndpoint(utf8_json);
+
+ os_exchange_data_->SetSource(std::move(drag_source_dte));
+
+ counter_.Run();
+}
+#endif
+
void DragDropOperation::OnTextRead(const std::string& mime_type,
std::u16string data) {
DCHECK(os_exchange_data_);
@@ -296,8 +339,7 @@ void DragDropOperation::OnFileContentsRead(const std::string& mime_type,
void DragDropOperation::OnWebCustomDataRead(const std::string& mime_type,
const std::vector<uint8_t>& data) {
DCHECK(os_exchange_data_);
- base::Pickle pickle;
- pickle.WriteBytes(data.data(), data.size());
+ base::Pickle pickle(reinterpret_cast<const char*>(data.data()), data.size());
os_exchange_data_->SetPickledData(
ui::ClipboardFormatType::WebCustomDataType(), pickle);
mime_type_ = mime_type;
@@ -364,17 +406,33 @@ void DragDropOperation::StartDragDropOperation() {
return;
if (op != DragOperation::kNone) {
- // Success
-
- // TODO(crbug.com/994065) This is currently not the actual mime type used by
- // the recipient, just an arbitrary one we pick out of the offered types so
- // we can report back whether or not the drop can succeed. This may need to
- // change in the future.
- source_->get()->Target(mime_type_);
-
- source_->get()->Action(DragOperationToDndAction(op));
- source_->get()->DndDropPerformed();
- source_->get()->DndFinished();
+ // It is possible that Ash flags the dragged tab to snap its origin, and
+ // it uses the `chromeos::kIsDeferredTabDraggingTargetWindowKey` property to
+ // control that. The snap back behavior works as if the drag was cancelled.
+ bool force_tab_swallow = false;
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+ aura::Window* source_window = origin_->get()->window()->GetToplevelWindow();
+ force_tab_swallow =
+ (source_window && source_window->GetProperty(
+ chromeos::kIsDeferredTabDraggingTargetWindowKey));
+ source_window->ClearProperty(
+ chromeos::kIsDeferredTabDraggingTargetWindowKey);
+#endif
+ if (force_tab_swallow) {
+ source_->get()->Cancelled();
+ } else {
+ // Success
+
+ // TODO(crbug.com/994065) This is currently not the actual mime type
+ // used by the recipient, just an arbitrary one we pick out of the
+ // offered types so we can report back whether or not the drop can
+ // succeed. This may need to change in the future.
+ source_->get()->Target(mime_type_);
+
+ source_->get()->Action(DragOperationToDndAction(op));
+ source_->get()->DndDropPerformed();
+ source_->get()->DndFinished();
+ }
// Reset |source_| so it the destructor doesn't try to cancel it.
source_.reset();
@@ -389,8 +447,6 @@ void DragDropOperation::OnDragStarted() {
delete this;
}
-void DragDropOperation::OnDragEnded() {}
-
#if BUILDFLAG(IS_CHROMEOS_ASH)
void DragDropOperation::OnDragActionsChanged(int actions) {
if (!started_by_this_object_)
@@ -414,6 +470,10 @@ void DragDropOperation::OnExtendedDragSourceDestroying(
ResetExtendedDragSource();
}
+ui::OSExchangeData* DragDropOperation::GetOSExchangeDataForTesting() const {
+ return os_exchange_data_.get();
+}
+
void DragDropOperation::ResetExtendedDragSource() {
DCHECK(extended_drag_source_);
extended_drag_source_->RemoveObserver(this);
diff --git a/chromium/components/exo/drag_drop_operation.h b/chromium/components/exo/drag_drop_operation.h
index 87f8e7fc5f9..228e6ba573d 100644
--- a/chromium/components/exo/drag_drop_operation.h
+++ b/chromium/components/exo/drag_drop_operation.h
@@ -79,12 +79,14 @@ class DragDropOperation : public DataSourceObserver,
// aura::client::DragDropClientObserver:
void OnDragStarted() override;
- void OnDragEnded() override;
#if BUILDFLAG(IS_CHROMEOS_ASH)
void OnDragActionsChanged(int actions) override;
// ExtendedDragSource::Observer:
void OnExtendedDragSourceDestroying(ExtendedDragSource* source) override;
+
+ // Used by DragDropOperationTest to verify exchange data.
+ ui::OSExchangeData* GetOSExchangeDataForTesting() const;
#endif
private:
@@ -102,6 +104,15 @@ class DragDropOperation : public DataSourceObserver,
void OnDragIconCaptured(const SkBitmap& icon_bitmap);
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+ // Called when the focused window is a Lacros window and a source
+ // DataTransferEndpoint is found in the available MIME types. This
+ // is currently used to synchronize drag source metadata from
+ // Lacros to Ash.
+ void OnDataTransferEndpointRead(const std::string& mime_type,
+ std::u16string data);
+#endif
+
void OnTextRead(const std::string& mime_type, std::u16string data);
void OnHTMLRead(const std::string& mime_type, std::u16string data);
void OnFilenamesRead(DataExchangeDelegate* data_exchange_delegate,
diff --git a/chromium/components/exo/drag_drop_operation_unittest.cc b/chromium/components/exo/drag_drop_operation_unittest.cc
index d2e02781f5c..ac8cdd36b5a 100644
--- a/chromium/components/exo/drag_drop_operation_unittest.cc
+++ b/chromium/components/exo/drag_drop_operation_unittest.cc
@@ -8,6 +8,7 @@
#include "ash/shell.h"
#include "base/bind.h"
+#include "base/containers/flat_map.h"
#include "base/files/file_util.h"
#include "base/run_loop.h"
#include "base/test/bind.h"
@@ -21,7 +22,10 @@
#include "components/exo/test/exo_test_base.h"
#include "components/exo/test/exo_test_data_exchange_delegate.h"
#include "components/exo/test/shell_surface_builder.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "ui/aura/client/drag_drop_client.h"
+#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
+#include "ui/base/data_transfer_policy/data_transfer_policy_controller.h"
#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-shared.h"
#include "ui/events/test/event_generator.h"
#include "ui/gfx/geometry/point_f.h"
@@ -33,6 +37,9 @@
namespace exo {
namespace {
+using ::testing::_;
+using ::testing::Property;
+
constexpr char kText[] = "test";
constexpr char kTextMimeType[] = "text/plain";
@@ -46,7 +53,11 @@ class TestDataSourceDelegate : public DataSourceDelegate {
void OnTarget(const absl::optional<std::string>& mime_type) override {}
void OnSend(const std::string& mime_type, base::ScopedFD fd) override {
- base::WriteFileDescriptor(fd.get(), kText);
+ if (data_map_.empty()) {
+ base::WriteFileDescriptor(fd.get(), kText);
+ } else {
+ base::WriteFileDescriptor(fd.get(), data_map_[mime_type]);
+ }
}
void OnCancelled() override {}
@@ -60,6 +71,13 @@ class TestDataSourceDelegate : public DataSourceDelegate {
bool CanAcceptDataEventsForSurface(Surface* surface) const override {
return true;
}
+
+ void SetData(const std::string& mime_type, std::vector<uint8_t> data) {
+ data_map_[mime_type] = std::move(data);
+ }
+
+ private:
+ base::flat_map<std::string, std::vector<uint8_t>> data_map_;
};
class DragDropOperationTest : public test::ExoTestBase,
@@ -89,7 +107,10 @@ class DragDropOperationTest : public test::ExoTestBase,
FROM_HERE, std::move(drag_blocked_callback_));
}
- void OnDragEnded() override { drag_end_count_++; }
+ void OnDragCompleted(const ui::DropTargetEvent& event) override {
+ drag_end_count_++;
+ }
+ void OnDragCancelled() override { drag_end_count_++; }
protected:
void set_drag_blocked_callback(base::OnceClosure callback) {
@@ -285,6 +306,165 @@ TEST_F(DragDropOperationTest, DragDropFromNestedPopup) {
EXPECT_EQ(0, GetDragStartCountAndReset());
EXPECT_EQ(1, GetDragEndCountAndReset());
}
+
+namespace {
+
+class MockDataTransferPolicyController
+ : public ui::DataTransferPolicyController {
+ public:
+ MOCK_METHOD3(IsClipboardReadAllowed,
+ bool(const ui::DataTransferEndpoint* const data_src,
+ const ui::DataTransferEndpoint* const data_dst,
+ const absl::optional<size_t> size));
+ MOCK_METHOD5(PasteIfAllowed,
+ void(const ui::DataTransferEndpoint* const data_src,
+ const ui::DataTransferEndpoint* const data_dst,
+ const absl::optional<size_t> size,
+ content::RenderFrameHost* rfh,
+ base::OnceCallback<void(bool)> callback));
+ MOCK_METHOD3(DropIfAllowed,
+ void(const ui::DataTransferEndpoint* data_src,
+ const ui::DataTransferEndpoint* data_dst,
+ base::OnceClosure drop_cb));
+};
+
+} // namespace
+
+// Lacros sends additional metadata about the drag and drop source (e.g. origin
+// URL). This synchronizes the source metadata between Lacros to Ash. This is
+// used in Data Leak Prevention restrictions where admins can restrict data from
+// being copied from restricted locations.
+TEST_F(DragDropOperationTest, DragDropCheckSourceFromLacros) {
+ static_cast<ash::DragDropController*>(
+ aura::client::GetDragDropClient(ash::Shell::GetPrimaryRootWindow()))
+ ->set_should_block_during_drag_drop(false);
+ TestDataExchangeDelegate data_exchange_delegate;
+ data_exchange_delegate.set_endpoint_type(ui::EndpointType::kLacros);
+
+ auto delegate = std::make_unique<TestDataSourceDelegate>();
+ auto data_source = std::make_unique<DataSource>(delegate.get());
+
+ auto dlp_controller = std::make_unique<MockDataTransferPolicyController>();
+
+ // Encoded source DataTransferEndpoint.
+ const std::string kEncodedTestDte =
+ R"({"endpoint_type":"url","url_origin":"https://www.google.com"})";
+ const std::string kDteMimeType = "chromium/x-data-transfer-endpoint";
+
+ data_source->Offer(kDteMimeType);
+ delegate->SetData(kDteMimeType, std::vector<uint8_t>(kEncodedTestDte.begin(),
+ kEncodedTestDte.end()));
+
+ auto origin_surface = std::make_unique<Surface>();
+ ash::Shell::GetPrimaryRootWindow()->AddChild(origin_surface->window());
+
+ gfx::Size buffer_size(100, 100);
+ std::unique_ptr<Buffer> buffer(
+ new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
+ auto icon_surface = std::make_unique<Surface>();
+ icon_surface->Attach(buffer.get());
+
+ // Expect the encoded endpoint from Lacros to be correctly decoded.
+ EXPECT_CALL(
+ *dlp_controller,
+ DropIfAllowed(
+ Pointee(AllOf(Property(&ui::DataTransferEndpoint::IsUrlType, true),
+ Property(&ui::DataTransferEndpoint::GetOrigin,
+ Pointee(Property(&url::Origin::Serialize,
+ "https://www.google.com"))))),
+ _, _))
+ .WillOnce([&](const ui::DataTransferEndpoint* data_src,
+ const ui::DataTransferEndpoint* data_dst,
+ base::OnceClosure drop_cb) { std::move(drop_cb).Run(); });
+
+ base::RunLoop run_loop;
+ set_drag_blocked_callback(run_loop.QuitClosure());
+
+ ui::test::EventGenerator generator(origin_surface->window()->GetRootWindow(),
+ origin_surface->window());
+ generator.PressLeftButton();
+ gfx::Point location =
+ generator.current_screen_location() -
+ origin_surface->window()->GetBoundsInScreen().OffsetFromOrigin();
+ auto operation = DragDropOperation::Create(
+ &data_exchange_delegate, data_source.get(), origin_surface.get(),
+ icon_surface.get(), gfx::PointF(location),
+ ui::mojom::DragEventSource::kMouse);
+ icon_surface->Commit();
+
+ run_loop.Run();
+
+ generator.MoveMouseBy(150, 150);
+ generator.ReleaseLeftButton();
+
+ ::testing::Mock::VerifyAndClearExpectations(dlp_controller.get());
+}
+
+// Additional source metadata should be ignored from non-Lacros instances.
+TEST_F(DragDropOperationTest, DragDropCheckSourceFromNonLacros) {
+ static_cast<ash::DragDropController*>(
+ aura::client::GetDragDropClient(ash::Shell::GetPrimaryRootWindow()))
+ ->set_should_block_during_drag_drop(false);
+ TestDataExchangeDelegate data_exchange_delegate;
+ data_exchange_delegate.set_endpoint_type(ui::EndpointType::kCrostini);
+
+ auto delegate = std::make_unique<TestDataSourceDelegate>();
+ auto data_source = std::make_unique<DataSource>(delegate.get());
+
+ auto dlp_controller = std::make_unique<MockDataTransferPolicyController>();
+
+ // Encoded source DataTransferEndpoint.
+ const std::string kEncodedTestDte =
+ R"({"endpoint_type":"url","url_origin":"https://www.google.com"})";
+ const std::string kDteMimeType = "chromium/x-data-transfer-endpoint";
+
+ data_source->Offer(kDteMimeType);
+ delegate->SetData(kDteMimeType, std::vector<uint8_t>(kEncodedTestDte.begin(),
+ kEncodedTestDte.end()));
+
+ auto origin_surface = std::make_unique<Surface>();
+ ash::Shell::GetPrimaryRootWindow()->AddChild(origin_surface->window());
+
+ gfx::Size buffer_size(100, 100);
+ std::unique_ptr<Buffer> buffer(
+ new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
+ auto icon_surface = std::make_unique<Surface>();
+ icon_surface->Attach(buffer.get());
+
+ // Expect the encoded endpoint from non-Lacros to be ignored.
+ EXPECT_CALL(
+ *dlp_controller,
+ DropIfAllowed(
+ Pointee(AllOf(Property(&ui::DataTransferEndpoint::IsUrlType, false),
+ Property(&ui::DataTransferEndpoint::type,
+ ui::EndpointType::kCrostini))),
+ _, _))
+ .WillOnce([&](const ui::DataTransferEndpoint* data_src,
+ const ui::DataTransferEndpoint* data_dst,
+ base::OnceClosure drop_cb) { std::move(drop_cb).Run(); });
+
+ base::RunLoop run_loop;
+ set_drag_blocked_callback(run_loop.QuitClosure());
+
+ ui::test::EventGenerator generator(origin_surface->window()->GetRootWindow(),
+ origin_surface->window());
+ generator.PressLeftButton();
+ gfx::Point location =
+ generator.current_screen_location() -
+ origin_surface->window()->GetBoundsInScreen().OffsetFromOrigin();
+ auto operation = DragDropOperation::Create(
+ &data_exchange_delegate, data_source.get(), origin_surface.get(),
+ icon_surface.get(), gfx::PointF(location),
+ ui::mojom::DragEventSource::kMouse);
+ icon_surface->Commit();
+
+ run_loop.Run();
+
+ generator.MoveMouseBy(150, 150);
+ generator.ReleaseLeftButton();
+
+ ::testing::Mock::VerifyAndClearExpectations(dlp_controller.get());
+}
#endif
} // namespace exo
diff --git a/chromium/components/exo/extended_drag_source.cc b/chromium/components/exo/extended_drag_source.cc
index 3ea0e81e26f..9e4f801bca9 100644
--- a/chromium/components/exo/extended_drag_source.cc
+++ b/chromium/components/exo/extended_drag_source.cc
@@ -16,6 +16,7 @@
#include "base/notreached.h"
#include "components/exo/data_source.h"
#include "components/exo/surface.h"
+#include "components/exo/wm_helper.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/window.h"
@@ -86,6 +87,12 @@ class ExtendedDragSource::DraggedWindowHolder : public aura::WindowObserver {
surface_->window()->RemoveObserver(this);
}
+ void OnWindowVisibilityChanging(aura::Window* window, bool visible) override {
+ DCHECK(window);
+ if (window == toplevel_window_)
+ source_->OnDraggedWindowVisibilityChanging(visible);
+ }
+
void OnWindowVisibilityChanged(aura::Window* window, bool visible) override {
DCHECK(window);
if (window == toplevel_window_)
@@ -98,6 +105,9 @@ class ExtendedDragSource::DraggedWindowHolder : public aura::WindowObserver {
toplevel_window_ = surface_->window()->GetToplevelWindow();
toplevel_window_->AddObserver(this);
+
+ // Disable visibility change animations on the dragged window.
+ toplevel_window_->SetProperty(aura::client::kAnimationsDisabledKey, true);
return true;
}
@@ -196,7 +206,9 @@ DragOperation ExtendedDragSource::OnToplevelWindowDragDropped() {
void ExtendedDragSource::OnToplevelWindowDragCancelled() {
DVLOG(1) << "OnDragCancelled()";
- // TODO(crbug.com/1099418): Handle cancellation/revert.
+ auto* handler = ash::Shell::Get()->toplevel_window_event_handler();
+ handler->RevertDrag();
+
Cleanup();
}
@@ -247,9 +259,6 @@ void ExtendedDragSource::StartDrag(aura::Window* toplevel,
event_blocker_ =
std::make_unique<aura::ScopedWindowEventTargetingBlocker>(toplevel);
- // Disable visibility change animations on the dragged window.
- toplevel->SetProperty(aura::client::kAnimationsDisabledKey, true);
-
DVLOG(1) << "Starting drag. pointer_loc=" << pointer_location.ToString();
auto* toplevel_handler = ash::Shell::Get()->toplevel_window_event_handler();
auto move_source = drag_event_source_ == ui::mojom::DragEventSource::kTouch
@@ -271,15 +280,17 @@ void ExtendedDragSource::StartDrag(aura::Window* toplevel,
// TODO(crbug.com/1167581): Experiment setting |update_gesture_target| back
// to true when capture is removed from drag and drop.
- toplevel_handler->AttemptToStartDrag(toplevel, pointer_location, HTCAPTION,
- move_source, std::move(end_closure),
- /*update_gesture_target=*/false,
- /*grab_capture=*/false);
+ toplevel_handler->AttemptToStartDrag(
+ toplevel, pointer_location, HTCAPTION, move_source,
+ std::move(end_closure),
+ /*update_gesture_target=*/false,
+ /*grab_capture =*/
+ drag_event_source_ != ui::mojom::DragEventSource::kTouch);
}
-void ExtendedDragSource::OnDraggedWindowVisibilityChanged(bool visible) {
+void ExtendedDragSource::OnDraggedWindowVisibilityChanging(bool visible) {
DCHECK(dragged_window_holder_);
- DVLOG(1) << "Dragged window visibility changed. visible=" << visible;
+ DVLOG(1) << "Dragged window visibility changing. visible=" << visible;
if (!visible) {
dragged_window_holder_.reset();
@@ -295,12 +306,37 @@ void ExtendedDragSource::OnDraggedWindowVisibilityChanged(bool visible) {
toplevel->SetProperty(ash::kTabDraggingSourceWindowKey,
drag_source_window_);
}
+}
+
+void ExtendedDragSource::OnDraggedWindowVisibilityChanged(bool visible) {
+ DCHECK(dragged_window_holder_);
+ DVLOG(1) << "Dragged window visibility changed. visible=" << visible;
+
+ if (!visible) {
+ dragged_window_holder_.reset();
+ return;
+ }
+
+ aura::Window* toplevel = dragged_window_holder_->toplevel_window();
+ DCHECK(toplevel);
+ DCHECK(drag_source_window_);
// The |toplevel| window for the dragged surface has just been created and
// it's about to be mapped. Calculate and set its position based on
// |drag_offset_| and |pointer_location_| before starting the actual drag.
auto screen_location = CalculateOrigin(toplevel);
- toplevel->SetBounds({screen_location, toplevel->bounds().size()});
+
+ auto toplevel_bounds =
+ gfx::Rect({screen_location, toplevel->bounds().size()});
+ toplevel->SetBounds(toplevel_bounds);
+
+ if (WMHelper::GetInstance()->InTabletMode()) {
+ // The bounds that is stored in ash::kRestoreBoundsOverrideKey will be used
+ // by DragDetails to calculate the detached window bounds during dragging
+ // when detaching in tablet mode to ensure the detached window is correctly
+ // placed under the pointer/finger.
+ toplevel->SetProperty(ash::kRestoreBoundsOverrideKey, toplevel_bounds);
+ }
DVLOG(1) << "Dragged window mapped. toplevel=" << toplevel
<< " origin=" << screen_location.ToString();
diff --git a/chromium/components/exo/extended_drag_source.h b/chromium/components/exo/extended_drag_source.h
index 86cef843551..e3a19002047 100644
--- a/chromium/components/exo/extended_drag_source.h
+++ b/chromium/components/exo/extended_drag_source.h
@@ -94,6 +94,7 @@ class ExtendedDragSource : public DataSourceObserver,
void UnlockCursor();
void StartDrag(aura::Window* toplevel,
const gfx::PointF& pointer_location_in_screen);
+ void OnDraggedWindowVisibilityChanging(bool visible);
void OnDraggedWindowVisibilityChanged(bool visible);
gfx::Point CalculateOrigin(aura::Window* target) const;
void Cleanup();
diff --git a/chromium/components/exo/extended_drag_source_unittest.cc b/chromium/components/exo/extended_drag_source_unittest.cc
index 07202a18b5d..61707ebb63e 100644
--- a/chromium/components/exo/extended_drag_source_unittest.cc
+++ b/chromium/components/exo/extended_drag_source_unittest.cc
@@ -7,12 +7,17 @@
#include <memory>
#include <string>
+#include "ash/constants/app_types.h"
#include "ash/drag_drop/drag_drop_controller.h"
#include "ash/drag_drop/toplevel_window_drag_delegate.h"
+#include "ash/public/cpp/tablet_mode.h"
+#include "ash/public/cpp/window_properties.h"
#include "ash/shell.h"
#include "ash/wm/toplevel_window_event_handler.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/test/bind.h"
#include "base/test/gmock_callback_support.h"
+#include "chromeos/ui/base/window_properties.h"
#include "components/exo/buffer.h"
#include "components/exo/data_source.h"
#include "components/exo/data_source_delegate.h"
@@ -22,8 +27,10 @@
#include "components/exo/test/exo_test_base.h"
#include "components/exo/test/exo_test_data_exchange_delegate.h"
#include "components/exo/test/exo_test_helper.h"
+#include "components/exo/test/shell_surface_builder.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/aura/client/aura_constants.h"
#include "ui/aura/client/drag_drop_client.h"
#include "ui/aura/client/drag_drop_delegate.h"
#include "ui/aura/window_tree_host.h"
@@ -38,7 +45,10 @@
#include "ui/gfx/geometry/vector2d.h"
using ::testing::_;
+using ::testing::AnyNumber;
+using ::testing::DoAll;
using ::testing::InvokeWithoutArgs;
+using ::testing::SaveArg;
namespace exo {
namespace {
@@ -136,7 +146,8 @@ class ExtendedDragSourceTest : public test::ExoTestBase {
seat_ =
std::make_unique<Seat>(std::make_unique<TestDataExchangeDelegate>());
- data_source_ = std::make_unique<DataSource>(new TestDataSourceDelegate);
+ data_source_delegate_ = new TestDataSourceDelegate;
+ data_source_ = std::make_unique<DataSource>(data_source_delegate_);
extended_drag_source_ = std::make_unique<ExtendedDragSource>(
data_source_.get(), new TestExtendedDragSourceDelegate(
/*allow_drop_no_target=*/true,
@@ -173,8 +184,20 @@ class ExtendedDragSourceTest : public test::ExoTestBase {
std::unique_ptr<Seat> seat_;
std::unique_ptr<DataSource> data_source_;
std::unique_ptr<ExtendedDragSource> extended_drag_source_;
+
+ // DataSource deletes it upon destruction.
+ TestDataSourceDelegate* data_source_delegate_ = nullptr;
};
+// Enables or disables tablet mode and waits for the transition to finish.
+void SetTabletModeEnabled(bool enabled) {
+ // This does not use ShellTestApi or TabletModeControllerTestApi because those
+ // are implemented in test-only files.
+ ash::TabletMode::Waiter waiter(enabled);
+ ash::Shell::Get()->tablet_mode_controller()->SetEnabledForTest(enabled);
+ waiter.Wait();
+}
+
} // namespace
TEST_F(ExtendedDragSourceTest, DestroySource) {
@@ -238,7 +261,7 @@ TEST_F(ExtendedDragSourceTest, DragSurfaceAlreadyMapped) {
// when it is guarantee the its state is properly set.
class WindowObserverHookChecker : public aura::WindowObserver {
public:
- WindowObserverHookChecker(aura::Window* surface_window)
+ explicit WindowObserverHookChecker(aura::Window* surface_window)
: surface_window_(surface_window) {
DCHECK(!surface_window_->GetRootWindow());
surface_window_->AddObserver(this);
@@ -252,6 +275,9 @@ class WindowObserverHookChecker : public aura::WindowObserver {
dragged_window_ = surface_window_->GetToplevelWindow();
dragged_window_->AddObserver(this);
surface_window_->RemoveObserver(this);
+
+ dragged_window_->SetProperty(aura::client::kAppType,
+ static_cast<int>(ash::AppType::LACROS));
}
MOCK_METHOD(void,
OnWindowVisibilityChanging,
@@ -267,6 +293,24 @@ class WindowObserverHookChecker : public aura::WindowObserver {
aura::Window* dragged_window_ = nullptr;
};
+// Differently than the window observer class above, this one observers
+// the window instance being directly provided to its ctor.
+class WindowObserverHookChecker2 : public aura::WindowObserver {
+ public:
+ explicit WindowObserverHookChecker2(aura::Window* surface_window)
+ : surface_window_(surface_window) {
+ surface_window_->AddObserver(this);
+ }
+ ~WindowObserverHookChecker2() { surface_window_->RemoveObserver(this); }
+ MOCK_METHOD(void,
+ OnWindowPropertyChanged,
+ (aura::Window*, const void*, intptr_t),
+ (override));
+
+ private:
+ aura::Window* surface_window_ = nullptr;
+};
+
TEST_F(ExtendedDragSourceTest, DragSurfaceNotMappedYet) {
// Create and Map the drag origin surface
auto surface = std::make_unique<Surface>();
@@ -302,14 +346,18 @@ TEST_F(ExtendedDragSourceTest, DragSurfaceNotMappedYet) {
// Ensure drag 'n drop starts after
// ExtendedDragSource::OnDraggedWindowVisibilityChanged()
+ aura::Window* toplevel_window;
WindowObserverHookChecker checker(detached_surface->window());
EXPECT_CALL(checker, OnWindowVisibilityChanging(_, _))
.Times(1)
- .WillOnce(InvokeWithoutArgs([]() {
- auto* toplevel_handler =
- ash::Shell::Get()->toplevel_window_event_handler();
- EXPECT_FALSE(toplevel_handler->is_drag_in_progress());
- }));
+ .WillOnce(DoAll(
+ SaveArg<0>(&toplevel_window), InvokeWithoutArgs([&]() {
+ auto* toplevel_handler =
+ ash::Shell::Get()->toplevel_window_event_handler();
+ EXPECT_FALSE(toplevel_handler->is_drag_in_progress());
+ EXPECT_TRUE(toplevel_window->GetProperty(ash::kIsDraggingTabsKey));
+ })));
+
EXPECT_CALL(checker, OnWindowVisibilityChanged(_, _))
.Times(1)
.WillOnce(InvokeWithoutArgs([]() {
@@ -337,7 +385,100 @@ TEST_F(ExtendedDragSourceTest, DragSurfaceNotMappedYet) {
EXPECT_EQ(gfx::Point(140, 140), window->GetBoundsInScreen().origin());
}
-TEST_F(ExtendedDragSourceTest, DragSurfaceNotMappedYetWithTouch) {
+TEST_F(ExtendedDragSourceTest, DragSurfaceNotMappedYet_TabletMode) {
+ SetTabletModeEnabled(true);
+
+ // Create and Map the drag origin surface
+ auto surface = std::make_unique<Surface>();
+ auto shell_surface = std::make_unique<ShellSurface>(surface.get());
+ auto buffer = CreateBuffer({32, 32});
+ surface->Attach(buffer.get());
+ surface->Commit();
+
+ // Creates a mouse-pressed event before starting the drag session.
+ ui::test::EventGenerator generator(GetContext(), gfx::Point(10, 10));
+ generator.PressLeftButton();
+
+ // Start the DND + extended-drag session.
+ StartExtendedDragSession(shell_surface->GetWidget()->GetNativeWindow(),
+ gfx::Point(0, 0), ui::DragDropTypes::DRAG_MOVE,
+ ui::mojom::DragEventSource::kMouse);
+
+ // Create a new surface to emulate a "detachment" process.
+ auto detached_surface = std::make_unique<Surface>();
+ auto detached_shell_surface =
+ std::make_unique<ShellSurface>(detached_surface.get());
+
+ // Set |surface| as the dragged surface while it's still unmapped/invisible.
+ // This can be used to implement tab detaching in Chrome's tab drag use case,
+ // for example. Extended drag source will monitor surface mapping and it's
+ // expected to position it correctly using the provided drag offset here
+ // relative to the current pointer location.
+ extended_drag_source_->Drag(detached_surface.get(), gfx::Vector2d(10, 10));
+ EXPECT_FALSE(extended_drag_source_->GetDraggedWindowForTesting());
+ EXPECT_TRUE(extended_drag_source_->GetDragOffsetForTesting().has_value());
+ EXPECT_EQ(gfx::Vector2d(10, 10),
+ *extended_drag_source_->GetDragOffsetForTesting());
+
+ // Ensure drag 'n drop starts after
+ // ExtendedDragSource::OnDraggedWindowVisibilityChanged()
+ aura::Window* toplevel_window = nullptr;
+ WindowObserverHookChecker checker(detached_surface->window());
+ EXPECT_CALL(checker, OnWindowVisibilityChanging(_, _))
+ .Times(1)
+ .WillOnce(DoAll(
+ SaveArg<0>(&toplevel_window), InvokeWithoutArgs([&]() {
+ auto* toplevel_handler =
+ ash::Shell::Get()->toplevel_window_event_handler();
+ EXPECT_FALSE(toplevel_handler->is_drag_in_progress());
+ EXPECT_TRUE(toplevel_window->GetProperty(ash::kIsDraggingTabsKey));
+ })));
+ EXPECT_CALL(checker, OnWindowVisibilityChanged(_, _))
+ .Times(1)
+ .WillOnce(DoAll(
+ SaveArg<0>(&toplevel_window), InvokeWithoutArgs([&]() {
+ auto* toplevel_handler =
+ ash::Shell::Get()->toplevel_window_event_handler();
+ EXPECT_TRUE(toplevel_handler->is_drag_in_progress());
+ gfx::Rect* override_bounds =
+ toplevel_window->GetProperty(ash::kRestoreBoundsOverrideKey);
+ EXPECT_TRUE(override_bounds && !override_bounds->IsEmpty());
+ EXPECT_EQ(*override_bounds, toplevel_window->bounds());
+ })));
+
+ // Map the |detached_surface|.
+ auto detached_buffer = CreateBuffer({50, 50});
+ detached_surface->Attach(detached_buffer.get());
+ detached_surface->Commit();
+
+ // Ensure the toplevel window for the dragged surface set above, is correctly
+ // detected, after it's mapped.
+ aura::Window* window = detached_shell_surface->GetWidget()->GetNativeWindow();
+ EXPECT_TRUE(extended_drag_source_->GetDraggedWindowForTesting());
+ EXPECT_EQ(window, extended_drag_source_->GetDraggedWindowForTesting());
+
+ WindowObserverHookChecker2 checker2(
+ shell_surface->GetWidget()->GetNativeWindow());
+ aura::Window* source_window = nullptr;
+ const void* property_key;
+ EXPECT_CALL(checker2, OnWindowPropertyChanged(_, _, _))
+ .Times(AnyNumber())
+ .WillRepeatedly(
+ DoAll(SaveArg<0>(&source_window), SaveArg<1>(&property_key),
+ InvokeWithoutArgs([&]() {
+ if (property_key ==
+ chromeos::kIsDeferredTabDraggingTargetWindowKey) {
+ bool new_value = source_window->GetProperty(
+ chromeos::kIsDeferredTabDraggingTargetWindowKey);
+ EXPECT_TRUE(new_value);
+ }
+ })));
+
+ generator.ReleaseLeftButton();
+ SetTabletModeEnabled(false);
+}
+
+TEST_F(ExtendedDragSourceTest, DragSurfaceNotMappedYet_Touch) {
// Create and Map the drag origin surface
auto surface = std::make_unique<Surface>();
auto shell_surface = std::make_unique<ShellSurface>(surface.get());
@@ -417,4 +558,37 @@ TEST_F(ExtendedDragSourceTest, DestroyDraggedSurfaceWhileDragging) {
EXPECT_TRUE(surface->window()->GetBoundsInScreen().origin().IsOrigin());
}
+TEST_F(ExtendedDragSourceTest, CancelDraggingOperation) {
+ // Create and map a toplevel shell surface.
+ auto shell_surface =
+ exo::test::ShellSurfaceBuilder({32, 32}).BuildShellSurface();
+ auto* surface = shell_surface->root_surface();
+
+ extended_drag_source_->Drag(surface, gfx::Vector2d());
+
+ // Start the DND + extended-drag session.
+ // Creates a mouse-pressed event before starting the drag session.
+ ui::test::EventGenerator generator(GetContext(), gfx::Point(10, 10));
+ generator.PressLeftButton();
+
+ // Start a DragDropOperation.
+ drag_drop_controller_->set_should_block_during_drag_drop(true);
+ seat_->StartDrag(data_source_.get(), surface, /*icon=*/nullptr,
+ ui::mojom::DragEventSource::kMouse);
+
+ auto task_1 = base::BindLambdaForTesting([&]() {
+ generator.MoveMouseBy(190, 190);
+
+ auto* toplevel_handler = ash::Shell::Get()->toplevel_window_event_handler();
+ EXPECT_TRUE(toplevel_handler->is_drag_in_progress());
+ drag_drop_controller_->DragCancel();
+ EXPECT_FALSE(toplevel_handler->is_drag_in_progress());
+ });
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(std::move(task_1)));
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(data_source_delegate_->cancelled());
+}
+
} // namespace exo
diff --git a/chromium/components/exo/keyboard.cc b/chromium/components/exo/keyboard.cc
index 701e07a0f51..bb41f4794fd 100644
--- a/chromium/components/exo/keyboard.cc
+++ b/chromium/components/exo/keyboard.cc
@@ -31,6 +31,7 @@
#include "ui/events/base_event_utils.h"
#include "ui/events/event.h"
#include "ui/views/widget/widget.h"
+#include "ui/wm/core/window_util.h"
namespace exo {
namespace {
@@ -90,7 +91,7 @@ bool ProcessAcceleratorIfReserved(Surface* surface, ui::KeyEvent* event) {
// to fix https://crbug.com/847500 without breaking ARC apps/Lacros browser.
bool IsImeSupportedSurface(Surface* surface) {
aura::Window* window = surface->window();
- for (; window; window = window->parent()) {
+ while (window) {
const auto app_type =
static_cast<ash::AppType>(window->GetProperty(aura::client::kAppType));
switch (app_type) {
@@ -109,6 +110,12 @@ bool IsImeSupportedSurface(Surface* surface) {
// TODO(tetsui): find a way to remove this.
if (window->GetProperty(aura::client::kSkipImeProcessing))
return true;
+
+ if (aura::Window* transient_parent = wm::GetTransientParent(window)) {
+ window = transient_parent;
+ } else {
+ window = window->parent();
+ }
}
return false;
}
diff --git a/chromium/components/exo/keyboard_unittest.cc b/chromium/components/exo/keyboard_unittest.cc
index 28471e38b0e..435ff19131e 100644
--- a/chromium/components/exo/keyboard_unittest.cc
+++ b/chromium/components/exo/keyboard_unittest.cc
@@ -594,6 +594,7 @@ TEST_F(KeyboardTest, FocusWithArcOverlay) {
widget1->GetFocusManager()->GetFocusedView()->GetClassName());
EXPECT_EQ(keyboard.focused_surface_for_testing(), surface.get());
+ hold.RunAndReset();
widget1->CloseNow();
}
diff --git a/chromium/components/exo/layer_tree_frame_sink_holder.cc b/chromium/components/exo/layer_tree_frame_sink_holder.cc
index 4aef196254d..11f20135520 100644
--- a/chromium/components/exo/layer_tree_frame_sink_holder.cc
+++ b/chromium/components/exo/layer_tree_frame_sink_holder.cc
@@ -62,8 +62,7 @@ void LayerTreeFrameSinkHolder::DeleteWhenLastResourceHasBeenReclaimed(
frame.render_pass_list.push_back(std::move(pass));
holder->last_frame_resources_.clear();
holder->frame_sink_->SubmitCompositorFrame(std::move(frame),
- /*hit_test_data_changed=*/true,
- /*show_hit_test_borders=*/false);
+ /*hit_test_data_changed=*/true);
// Delete sink holder immediately if not waiting for resources to be
// reclaimed.
@@ -92,8 +91,7 @@ void LayerTreeFrameSinkHolder::SubmitCompositorFrame(
for (auto& resource : frame.resource_list)
last_frame_resources_.push_back(resource.id);
frame_sink_->SubmitCompositorFrame(std::move(frame),
- /*hit_test_data_changed=*/true,
- /*show_hit_test_borders=*/false);
+ /*hit_test_data_changed=*/true);
}
void LayerTreeFrameSinkHolder::DidNotProduceFrame(
diff --git a/chromium/components/exo/notification_surface.cc b/chromium/components/exo/notification_surface.cc
index 978aa864736..6d3224c13d9 100644
--- a/chromium/components/exo/notification_surface.cc
+++ b/chromium/components/exo/notification_surface.cc
@@ -89,6 +89,9 @@ void NotificationSurface::OnWindowPropertyChanged(aura::Window* window,
}
void NotificationSurface::OnWindowAddedToRootWindow(aura::Window* window) {
+ // Force recreating resources to submit the compositor frame w/o
+ // commit request.
+ root_surface()->SurfaceHierarchyResourcesLost();
SubmitCompositorFrame();
is_embedded_ = true;
}
diff --git a/chromium/components/exo/pointer.cc b/chromium/components/exo/pointer.cc
index 47113d3d5ee..83099a845cb 100644
--- a/chromium/components/exo/pointer.cc
+++ b/chromium/components/exo/pointer.cc
@@ -11,6 +11,7 @@
#include "base/threading/sequenced_task_runner_handle.h"
#include "base/trace_event/trace_event.h"
#include "build/chromeos_buildflags.h"
+#include "chromeos/ui/base/window_properties.h"
#include "components/exo/input_trace.h"
#include "components/exo/pointer_constraint_delegate.h"
#include "components/exo/pointer_delegate.h"
@@ -26,6 +27,7 @@
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "ui/aura/client/capture_client.h"
#include "ui/aura/client/cursor_client.h"
+#include "ui/aura/client/drag_drop_client.h"
#include "ui/aura/cursor/cursor_util.h"
#include "ui/aura/env.h"
#include "ui/aura/window.h"
@@ -46,8 +48,10 @@
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "ash/constants/ash_features.h"
+#include "ash/drag_drop/drag_drop_controller.h"
#include "ash/public/cpp/app_types_util.h"
#include "ash/public/cpp/shell_window_ids.h"
+#include "ash/wm/window_util.h"
#endif
namespace exo {
@@ -126,6 +130,10 @@ Pointer::Pointer(PointerDelegate* delegate, Seat* seat)
if (cursor_client)
cursor_client->AddObserver(this);
helper->AddFocusObserver(this);
+
+ auto* drag_drop_client = helper->GetDragDropClient();
+ if (drag_drop_client)
+ drag_drop_client->AddObserver(this);
}
Pointer::~Pointer() {
@@ -144,6 +152,10 @@ Pointer::~Pointer() {
VLOG(1) << "Pointer constraint broken by pointer destruction";
pointer_constraint_delegate_->OnConstraintBroken();
}
+ for (auto it : constraints_) {
+ it.first->RemoveSurfaceObserver(this);
+ it.second->OnDefunct();
+ }
if (stylus_delegate_)
stylus_delegate_->OnPointerDestroying(this);
// TODO(sky): CursorClient does not exist in mash
@@ -154,6 +166,10 @@ Pointer::~Pointer() {
if (root_surface())
root_surface()->RemoveSurfaceObserver(this);
helper->RemoveFocusObserver(this);
+
+ auto* drag_drop_client = helper->GetDragDropClient();
+ if (drag_drop_client)
+ drag_drop_client->RemoveObserver(this);
}
void Pointer::SetCursor(Surface* surface, const gfx::Point& hotspot) {
@@ -243,18 +259,41 @@ bool Pointer::ConstrainPointer(PointerConstraintDelegate* delegate) {
// lock support unless we are on chromeos.
#if BUILDFLAG(IS_CHROMEOS_ASH)
Surface* constrained_surface = delegate->GetConstrainedSurface();
- if (!constrained_surface)
+ if (!constrained_surface) {
+ delegate->OnDefunct();
+ return false;
+ }
+
+ // Pointer lock is permitted for ARC windows, and for windows configured to
+ // notify the user on lock activation. In the latter case, the
+ // kExoPointerLock feature must be enabled.
+ aura::Window* toplevel = constrained_surface->window()->GetToplevelWindow();
+ bool permitted =
+ ash::IsArcWindow(toplevel) ||
+ (base::FeatureList::IsEnabled(chromeos::features::kExoPointerLock) &&
+ toplevel->GetProperty(chromeos::kUseOverviewToExitPointerLock));
+ if (!permitted) {
+ delegate->OnDefunct();
return false;
- // Pointer lock should be enabled for ARC by default. The kExoPointerLock
- // should only apply to Crostini windows.
- bool is_arc_window =
- ash::IsArcWindow(constrained_surface->window()->GetToplevelWindow());
- if (!is_arc_window &&
- !base::FeatureList::IsEnabled(chromeos::features::kExoPointerLock))
+ }
+
+ // Can only have one active constraint request per surface
+ auto result = constraints_.try_emplace(constrained_surface, delegate);
+ if (result.first->second != delegate) {
+ VLOG(1) << "Pointer constraint not granted; one already exists.";
+ delegate->OnAlreadyConstrained();
+ delegate->OnDefunct();
return false;
+ }
+
+ if (!constrained_surface->HasSurfaceObserver(this))
+ constrained_surface->AddSurfaceObserver(this);
+
bool success = EnablePointerCapture(constrained_surface);
- if (success)
+ if (success) {
pointer_constraint_delegate_ = delegate;
+ delegate->OnConstraintActivated();
+ }
return success;
#else
NOTIMPLEMENTED();
@@ -262,14 +301,68 @@ bool Pointer::ConstrainPointer(PointerConstraintDelegate* delegate) {
#endif
}
+bool Pointer::UnconstrainPointerByUserAction() {
+ // Prevent pointer capture until the next user action that permits it,
+ // even if a constraint is currently not active (to prevent an app from
+ // rapidly toggling pointer capture to evade such prevention).
+ capture_permitted_ = false;
+ UpdateCursor(); // forces the cursor to be visible in case the app hid it
+
+ if (pointer_constraint_delegate_ && capture_window_) {
+ VLOG(1) << "Pointer constraint broken by user action";
+ UnconstrainPointer();
+ return true;
+ } else {
+ VLOG(1) << "Pointer constraint forbidden by user (though none active now)";
+ return false;
+ }
+}
+
+void Pointer::RemoveConstraintDelegate(PointerConstraintDelegate* delegate) {
+ delegate->OnDefunct();
+
+ Surface* surface = delegate->GetConstrainedSurface();
+ auto it = constraints_.find(surface);
+ if (it != constraints_.end() && it->second == delegate) {
+ constraints_.erase(it);
+ MaybeRemoveSurfaceObserver(surface);
+ }
+}
+
void Pointer::UnconstrainPointer() {
if (pointer_constraint_delegate_) {
+ pointer_constraint_delegate_->OnConstraintBroken();
+ if (!pointer_constraint_delegate_->IsPersistent()) {
+ RemoveConstraintDelegate(pointer_constraint_delegate_);
+ }
+ pointer_constraint_delegate_ = nullptr;
+ DisablePointerCapture();
+ }
+}
+
+void Pointer::MaybeReactivatePointerConstraint(Surface* surface) {
+ if (!pointer_constraint_delegate_ && surface) {
+ auto it = constraints_.find(surface);
+ if (it != constraints_.end())
+ ConstrainPointer(it->second);
+ }
+}
+
+void Pointer::OnPointerConstraintDelegateDestroying(
+ PointerConstraintDelegate* delegate) {
+ if (pointer_constraint_delegate_ == delegate) {
DisablePointerCapture();
pointer_constraint_delegate_ = nullptr;
}
+ RemoveConstraintDelegate(delegate);
}
bool Pointer::EnablePointerCapture(Surface* capture_surface) {
+ if (!capture_permitted_) {
+ VLOG(1) << "Unable to re-capture the pointer due to previous user action.";
+ return false;
+ }
+
if (!base::FeatureList::IsEnabled(kPointerCapture)) {
LOG(WARNING) << "Unable to capture the pointer, feature is disabled.";
return false;
@@ -278,13 +371,10 @@ bool Pointer::EnablePointerCapture(Surface* capture_surface) {
aura::Window* window = capture_surface->window();
aura::Window* active_window = WMHelper::GetInstance()->GetActiveWindow();
if (!active_window || !active_window->Contains(window)) {
- LOG(ERROR) << "Cannot enable pointer capture on an inactive window.";
+ VLOG(1) << "Cannot enable pointer capture on an inactive window.";
return false;
}
- if (!capture_surface->HasSurfaceObserver(this))
- capture_surface->AddSurfaceObserver(this);
-
capture_window_ = window;
// Add a pre-target handler that can consume all mouse events before it gets
@@ -297,6 +387,8 @@ bool Pointer::EnablePointerCapture(Surface* capture_surface) {
if (ShouldMoveToCenter())
MoveCursorToCenterOfActiveDisplay();
+ seat_->NotifyPointerCaptureEnabled(this, window);
+
return true;
}
@@ -314,9 +406,12 @@ void Pointer::DisablePointerCapture() {
: root->bounds().CenterPoint();
root->MoveCursorTo(p);
+ aura::Window* window = capture_window_;
capture_window_ = nullptr;
location_when_pointer_capture_enabled_.reset();
UpdateCursor();
+
+ seat_->NotifyPointerCaptureDisabled(this, window);
}
void Pointer::SetStylusDelegate(PointerStylusDelegate* delegate) {
@@ -347,24 +442,36 @@ void Pointer::OnSurfaceCommit() {
// SurfaceObserver overrides:
void Pointer::OnSurfaceDestroying(Surface* surface) {
+ bool was_correctly_subscribed = false;
if (surface && pointer_constraint_delegate_ &&
surface == pointer_constraint_delegate_->GetConstrainedSurface()) {
surface->RemoveSurfaceObserver(this);
VLOG(1) << "Pointer constraint broken by surface destruction";
- pointer_constraint_delegate_->OnConstraintBroken();
UnconstrainPointer();
+ was_correctly_subscribed = true;
}
- if (surface && surface->window() == capture_window_)
+ if (surface && surface->window() == capture_window_) {
DisablePointerCapture();
+ was_correctly_subscribed = true;
+ }
+
+ auto it = constraints_.find(surface);
+ if (it != constraints_.end()) {
+ it->second->OnDefunct();
+ constraints_.erase(it);
+ surface->RemoveSurfaceObserver(this);
+ was_correctly_subscribed = true;
+ }
+
if (surface == focus_surface_) {
SetFocus(nullptr, gfx::PointF(), 0);
- return;
- }
- if (surface == root_surface()) {
+ was_correctly_subscribed = true;
+ } else if (surface == root_surface()) {
UpdatePointerSurface(nullptr);
- return;
+ was_correctly_subscribed = true;
}
- NOTREACHED();
+ DCHECK(was_correctly_subscribed);
+ DCHECK(!surface->HasSurfaceObserver(this));
}
////////////////////////////////////////////////////////////////////////////////
@@ -451,8 +558,17 @@ void Pointer::OnMouseEvent(ui::MouseEvent* event) {
switch (event->type()) {
case ui::ET_MOUSE_RELEASED:
seat_->AbortPendingDragOperation();
- FALLTHROUGH;
+ [[fallthrough]];
case ui::ET_MOUSE_PRESSED: {
+ if (!capture_permitted_) {
+ // Clicking any surface with a constraint delegate permits capture
+ auto it = constraints_.find(focus_surface_);
+ if (it != constraints_.end()) {
+ capture_permitted_ = true;
+ UpdateCursor();
+ ConstrainPointer(it->second);
+ }
+ }
delegate_->OnPointerButton(event->time_stamp(),
event->changed_button_flags(),
event->type() == ui::ET_MOUSE_PRESSED);
@@ -590,6 +706,41 @@ void Pointer::OnGestureEvent(ui::GestureEvent* event) {
}
////////////////////////////////////////////////////////////////////////////////
+// aura::client::DragDropClientObserver overrides:
+void Pointer::OnDragStarted() {
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+ // Drag 'n drop operations driven by sources different than pointer/mouse
+ // should have not effect here.
+ WMHelper* helper = WMHelper::GetInstance();
+ if (auto* drag_drop_client = helper->GetDragDropClient()) {
+ if (static_cast<ash::DragDropController*>(drag_drop_client)
+ ->event_source() != ui::mojom::DragEventSource::kMouse)
+ return;
+ }
+
+ SetFocus(nullptr, gfx::PointF(), 0);
+#endif
+}
+
+void Pointer::OnDragCompleted(const ui::DropTargetEvent& event) {
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+ // Drag 'n drop operations driven by sources different than pointer/mouse
+ // should have not effect here.
+ WMHelper* helper = WMHelper::GetInstance();
+ if (auto* drag_drop_client = helper->GetDragDropClient()) {
+ if (static_cast<ash::DragDropController*>(drag_drop_client)
+ ->event_source() != ui::mojom::DragEventSource::kMouse)
+ return;
+ }
+
+ auto* target_window = ash::window_util::GetEventHandlerForEvent(event);
+ auto* surface = Surface::AsSurface(target_window);
+ if (surface)
+ SetFocus(surface, event.location_f(), /*button_flags=*/0);
+#endif
+}
+
+////////////////////////////////////////////////////////////////////////////////
// aura::client::CursorClientObserver overrides:
void Pointer::OnCursorSizeChanged(ui::CursorSize cursor_size) {
@@ -627,12 +778,13 @@ void Pointer::OnWindowFocused(aura::Window* gained_focus,
if (capture_window_ && capture_window_ != gained_focus) {
if (pointer_constraint_delegate_) {
VLOG(1) << "Pointer constraint broken by focus change";
- pointer_constraint_delegate_->OnConstraintBroken();
UnconstrainPointer();
} else {
DisablePointerCapture();
}
}
+ if (gained_focus)
+ MaybeReactivatePointerConstraint(Surface::AsSurface(gained_focus));
}
////////////////////////////////////////////////////////////////////////////////
@@ -657,10 +809,11 @@ void Pointer::SetFocus(Surface* surface,
// First generate a leave event if we currently have a target in focus.
if (focus_surface_) {
delegate_->OnPointerLeave(focus_surface_);
- focus_surface_->RemoveSurfaceObserver(this);
// Require SetCursor() to be called and cursor to be re-defined in
// response to each OnPointerEnter() call.
+ Surface* old_surface = focus_surface_;
focus_surface_ = nullptr;
+ MaybeRemoveSurfaceObserver(old_surface);
cursor_capture_weak_ptr_factory_.InvalidateWeakPtrs();
}
// Second generate an enter event if focus moved to a new surface.
@@ -680,12 +833,14 @@ void Pointer::UpdatePointerSurface(Surface* surface) {
host_window()->SetTransform(gfx::Transform());
if (host_window()->parent())
host_window()->parent()->RemoveChild(host_window());
- root_surface()->RemoveSurfaceObserver(this);
+ Surface* old_surface = root_surface();
SetRootSurface(nullptr);
+ MaybeRemoveSurfaceObserver(old_surface);
}
if (surface) {
- surface->AddSurfaceObserver(this);
+ if (!surface->HasSurfaceObserver(this))
+ surface->AddSurfaceObserver(this);
// Note: Surface window needs to be added to the tree so we can take a
// snapshot. Where in the tree is not important but we might as well use
// the cursor container.
@@ -783,6 +938,12 @@ void Pointer::UpdateCursor() {
cursor_.set_custom_hotspot(hotspot);
}
+ // When pointer capture is broken, use the standard system cursor instead of
+ // the application-requested one. But we keep the app-requested cursor around
+ // for when capture becomes permitted again.
+ const ui::Cursor& cursor =
+ capture_permitted_ ? cursor_ : ui::mojom::CursorType::kPointer;
+
// If there is a focused surface, update its widget as the views framework
// expect that Widget knows the current cursor. Otherwise update the
// cursor directly on CursorClient.
@@ -791,13 +952,13 @@ void Pointer::UpdateCursor() {
do {
views::Widget* widget = views::Widget::GetWidgetForNativeView(window);
if (widget) {
- widget->SetCursor(cursor_);
+ widget->SetCursor(cursor);
return;
}
window = window->parent();
} while (window);
} else {
- cursor_client->SetCursor(cursor_);
+ cursor_client->SetCursor(cursor);
}
}
@@ -856,4 +1017,21 @@ bool Pointer::HandleRelativePointerMotion(
return true;
}
+bool Pointer::ShouldObserveSurface(Surface* surface) {
+ if (!surface)
+ return false;
+
+ if (surface == root_surface() || surface == focus_surface_ ||
+ constraints_.find(surface) != constraints_.end()) {
+ return true;
+ }
+ return false;
+}
+
+void Pointer::MaybeRemoveSurfaceObserver(Surface* surface) {
+ if (!ShouldObserveSurface(surface)) {
+ surface->RemoveSurfaceObserver(this);
+ }
+}
+
} // namespace exo
diff --git a/chromium/components/exo/pointer.h b/chromium/components/exo/pointer.h
index 3523f264f4f..55ea1c13647 100644
--- a/chromium/components/exo/pointer.h
+++ b/chromium/components/exo/pointer.h
@@ -15,6 +15,7 @@
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/aura/client/cursor_client_observer.h"
+#include "ui/aura/client/drag_drop_client_observer.h"
#include "ui/aura/client/focus_change_observer.h"
#include "ui/base/cursor/cursor.h"
#include "ui/base/cursor/mojom/cursor_type.mojom-forward.h"
@@ -48,6 +49,7 @@ class SurfaceTreeHost;
class Pointer : public SurfaceTreeHost,
public SurfaceObserver,
public ui::EventHandler,
+ public aura::client::DragDropClientObserver,
public aura::client::CursorClientObserver,
public aura::client::FocusChangeObserver {
public:
@@ -85,6 +87,10 @@ class Pointer : public SurfaceTreeHost,
void OnScrollEvent(ui::ScrollEvent* event) override;
void OnGestureEvent(ui::GestureEvent* event) override;
+ // aura::client::DragDropClientObserver:
+ void OnDragStarted() override;
+ void OnDragCompleted(const ui::DropTargetEvent& event) override;
+
// Overridden from aura::client::CursorClientObserver:
void OnCursorSizeChanged(ui::CursorSize cursor_size) override;
void OnCursorDisplayChanged(const display::Display& display) override;
@@ -100,21 +106,43 @@ class Pointer : public SurfaceTreeHost,
// Enable the pointer constraint on the given surface. Returns true if the
// lock was granted, false otherwise.
//
+ // The delegate must call OnPointerConstraintDelegateDestroying() upon/before
+ // being destroyed, regardless of the return value of ConstrainPointer(),
+ // unless PointerConstraintDelegate::OnDefunct() is called first.
+ //
// TODO(crbug.com/957455): For legacy reasons, locking the pointer will also
// hide the cursor.
bool ConstrainPointer(PointerConstraintDelegate* delegate);
- // Disable the pointer constraint. This is designed to be called by the
- // delegate, so it does not call OnConstraintBroken(), which should be done
- // separately if the constraint was broken by something other than the
- // delegate.
- void UnconstrainPointer();
+ // Notifies that |delegate| is being destroyed.
+ void OnPointerConstraintDelegateDestroying(
+ PointerConstraintDelegate* delegate);
+
+ // Disable the pointer constraint, notify the delegate, and do not permit
+ // the constraint to be re-established until the user acts on the surface
+ // (by clicking on it).
+ //
+ // Designed to be called by client code, on behalf of a user action to break
+ // the constraint.
+ //
+ // Returns true if an active pointer constraint was disabled.
+ bool UnconstrainPointerByUserAction();
// Set the stylus delegate for handling stylus events.
void SetStylusDelegate(PointerStylusDelegate* delegate);
bool HasStylusDelegate() const;
private:
+ // Remove |delegate| from |constraints_|.
+ void RemoveConstraintDelegate(PointerConstraintDelegate* delegate);
+
+ // Disable the pointer constraint and notify the delegate.
+ void UnconstrainPointer();
+
+ // Try to reactivate a pointer constraint previously requested for the given
+ // surface, if any.
+ void MaybeReactivatePointerConstraint(Surface* surface);
+
// Capture the pointer for the given surface. Returns true iff the capture
// succeeded.
bool EnablePointerCapture(Surface* capture_surface);
@@ -165,6 +193,12 @@ class Pointer : public SurfaceTreeHost,
gfx::PointF location_in_target,
const absl::optional<gfx::Vector2dF>& ordinal_motion);
+ // Whether this Pointer should observe the given |surface|.
+ bool ShouldObserveSurface(Surface* surface);
+
+ // Stop observing |surface| if it's no longer relevant.
+ void MaybeRemoveSurfaceObserver(Surface* surface);
+
// The delegate instance that all events are dispatched to.
PointerDelegate* const delegate_;
@@ -176,9 +210,13 @@ class Pointer : public SurfaceTreeHost,
// The delegate instance that relative movement events are dispatched to.
RelativePointerDelegate* relative_pointer_delegate_ = nullptr;
- // The delegate instance that controls when to lock/unlock this pointer.
+ // Delegate that owns the currently granted pointer lock, if any.
PointerConstraintDelegate* pointer_constraint_delegate_ = nullptr;
+ // All delegates currently requesting a pointer locks, whether granted or
+ // not. Only one such request may exist per surface; others will be denied.
+ base::flat_map<Surface*, PointerConstraintDelegate*> constraints_;
+
// The delegate instance that stylus/pen events are dispatched to.
PointerStylusDelegate* stylus_delegate_ = nullptr;
@@ -199,6 +237,12 @@ class Pointer : public SurfaceTreeHost,
// this is not null.
aura::Window* capture_window_ = nullptr;
+ // True if this pointer is permitted to be captured.
+ //
+ // Set false when a user action (except focus loss) breaks pointer capture.
+ // Set true when the user clicks in any Exo window.
+ bool capture_permitted_ = true;
+
// The position of the pointer surface relative to the pointer location.
gfx::Point hotspot_;
diff --git a/chromium/components/exo/pointer_constraint_delegate.h b/chromium/components/exo/pointer_constraint_delegate.h
index 9af81802900..93dfa0246bc 100644
--- a/chromium/components/exo/pointer_constraint_delegate.h
+++ b/chromium/components/exo/pointer_constraint_delegate.h
@@ -7,24 +7,42 @@
namespace exo {
+class Pointer;
class Surface;
class PointerConstraintDelegate {
public:
virtual ~PointerConstraintDelegate() = default;
+ // Called when the lock is activated by the compositor.
+ //
+ // For non-persistent ("one-shot") locks, this may be called 0 or 1 times.
+ // For persistent locks, this may be called again after OnConstraintBroken().
+ virtual void OnConstraintActivated() = 0;
+
+ // Called when the lock is not activated by the compositor because a
+ // pointer constraint was already requested on this surface.
+ virtual void OnAlreadyConstrained() = 0;
+
// Called when this lock is broken for any reason. Possibly:
// - A user action broke the lock.
// - The lock was granted to a different client.
// - The pointer was destroyed while the lock was active.
- //
- // No matter the case, this delegate no longer holds the lock and therefore
- // should not call UnconstrainPointer().
virtual void OnConstraintBroken() = 0;
- // Callback to access the surface which this delegate wants to lock the
- // curstor for.
+ // Whether the lock is "persistent", meaning it can be reactivated by the
+ // compositor after being broken.
+ virtual bool IsPersistent() = 0;
+
+ // Returns the surface which this delegate wants to lock the cursor for.
+ // The delegate does not guarantee that this pointer is valid, except
+ // when calling Pointer::ConstrainPointer(); the caller is responsible for
+ // tracking the Surface's lifetime.
virtual Surface* GetConstrainedSurface() = 0;
+
+ // Notifies the delegate that it's defunct and must not call
+ // Pointer::OnPointerConstraintDelegateDestroying().
+ virtual void OnDefunct() = 0;
};
} // namespace exo
diff --git a/chromium/components/exo/pointer_unittest.cc b/chromium/components/exo/pointer_unittest.cc
index dae28a199d2..f63f488da5b 100644
--- a/chromium/components/exo/pointer_unittest.cc
+++ b/chromium/components/exo/pointer_unittest.cc
@@ -12,6 +12,7 @@
#include "base/run_loop.h"
#include "base/test/scoped_feature_list.h"
#include "build/chromeos_buildflags.h"
+#include "chromeos/ui/base/window_properties.h"
#include "components/exo/buffer.h"
#include "components/exo/data_source.h"
#include "components/exo/data_source_delegate.h"
@@ -26,6 +27,7 @@
#include "components/exo/test/exo_test_base.h"
#include "components/exo/test/exo_test_data_exchange_delegate.h"
#include "components/exo/test/exo_test_helper.h"
+#include "components/exo/test/shell_surface_builder.h"
#include "components/viz/common/quads/compositor_frame.h"
#include "components/viz/service/surfaces/surface.h"
#include "components/viz/service/surfaces/surface_manager.h"
@@ -44,11 +46,31 @@
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "ash/constants/ash_features.h"
+#include "ash/drag_drop/drag_drop_controller.h"
+#include "base/test/bind.h"
+#include "ui/aura/client/drag_drop_client.h"
+#include "ui/aura/window_tree_host.h"
+#include "ui/events/test/events_test_utils.h"
#endif
+using ::testing::_;
+using ::testing::AnyNumber;
+
namespace exo {
namespace {
+void DispatchGesture(ui::EventType gesture_type, gfx::Point location) {
+ ui::GestureEventDetails event_details(gesture_type);
+ ui::GestureEvent gesture_event(location.x(), location.y(), 0,
+ ui::EventTimeForNow(), event_details);
+ ui::EventSource* event_source =
+ ash::Shell::GetPrimaryRootWindow()->GetHost()->GetEventSource();
+ ui::EventSourceTestApi event_source_test(event_source);
+ ui::EventDispatchDetails details =
+ event_source_test.SendEventToSink(&gesture_event);
+ CHECK(!details.dispatcher_destroyed);
+}
+
class MockPointerDelegate : public PointerDelegate {
public:
MockPointerDelegate() {}
@@ -81,12 +103,26 @@ class MockRelativePointerDelegate : public RelativePointerDelegate {
class MockPointerConstraintDelegate : public PointerConstraintDelegate {
public:
- MockPointerConstraintDelegate() = default;
+ MockPointerConstraintDelegate() {
+ ON_CALL(*this, OnConstraintActivated).WillByDefault([this]() {
+ activated_count++;
+ });
+ ON_CALL(*this, OnConstraintBroken).WillByDefault([this]() {
+ broken_count++;
+ });
+ }
~MockPointerConstraintDelegate() = default;
// Overridden from PointerConstraintDelegate:
+ MOCK_METHOD0(OnConstraintActivated, void());
+ MOCK_METHOD0(OnAlreadyConstrained, void());
MOCK_METHOD0(OnConstraintBroken, void());
+ MOCK_METHOD0(IsPersistent, bool());
MOCK_METHOD0(GetConstrainedSurface, Surface*());
+ MOCK_METHOD0(OnDefunct, void());
+
+ int activated_count = 0;
+ int broken_count = 0;
};
class MockPointerStylusDelegate : public PointerStylusDelegate {
@@ -136,6 +172,75 @@ class PointerTest : public test::ExoTestBase {
}
};
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+class PointerConstraintTest : public PointerTest {
+ public:
+ PointerConstraintTest() = default;
+
+ PointerConstraintTest(const PointerConstraintTest&) = delete;
+ PointerConstraintTest& operator=(const PointerConstraintTest&) = delete;
+
+ void SetUp() override {
+ PointerTest::SetUp();
+ feature_list_.InitAndEnableFeature(chromeos::features::kExoPointerLock);
+
+ shell_surface_ = BuildShellSurfaceWhichPermitsPointerLock();
+ surface_ = shell_surface_->surface_for_testing();
+ seat_ = std::make_unique<Seat>();
+ pointer_ = std::make_unique<Pointer>(&delegate_, seat_.get());
+
+ focus_client_ =
+ aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow());
+ focus_client_->FocusWindow(surface_->window());
+
+ generator_ = std::make_unique<ui::test::EventGenerator>(
+ ash::Shell::GetPrimaryRootWindow());
+
+ EXPECT_CALL(delegate_, CanAcceptPointerEventsForSurface(surface_))
+ .WillRepeatedly(testing::Return(true));
+
+ EXPECT_CALL(constraint_delegate_, GetConstrainedSurface())
+ .WillRepeatedly(testing::Return(surface_));
+ }
+
+ void TearDown() override {
+ // Many objects need to be destroyed before teardown for various reasons.
+ seat_.reset();
+ shell_surface_.reset();
+ surface_ = nullptr;
+
+ // Some tests generate mouse events which Pointer::OnMouseEvent() handles
+ // during the run loop. That routine accesses WMHelper. So, make sure any
+ // such pending tasks finish before TearDown() destroys the WMHelper.
+ base::RunLoop().RunUntilIdle();
+
+ PointerTest::TearDown();
+ }
+
+ std::unique_ptr<ShellSurface> BuildShellSurfaceWhichPermitsPointerLock() {
+ std::unique_ptr<ShellSurface> shell_surface =
+ test::ShellSurfaceBuilder({10, 10}).BuildShellSurface();
+
+ shell_surface->surface_for_testing()
+ ->window()
+ ->GetToplevelWindow()
+ ->SetProperty(chromeos::kUseOverviewToExitPointerLock, true);
+
+ return shell_surface;
+ }
+
+ std::unique_ptr<ui::test::EventGenerator> generator_;
+ std::unique_ptr<Pointer> pointer_;
+ std::unique_ptr<Seat> seat_;
+ testing::NiceMock<MockPointerConstraintDelegate> constraint_delegate_;
+ testing::NiceMock<MockPointerDelegate> delegate_;
+ std::unique_ptr<ShellSurface> shell_surface_;
+ Surface* surface_;
+ base::test::ScopedFeatureList feature_list_;
+ aura::client::FocusClient* focus_client_;
+};
+#endif
+
TEST_F(PointerTest, SetCursor) {
std::unique_ptr<Surface> surface(new Surface);
std::unique_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get()));
@@ -972,6 +1077,104 @@ TEST_F(PointerTest, DragDropAbort) {
pointer.reset();
}
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+TEST_F(PointerTest, DragDropAndPointerEnterLeaveEvents) {
+ Seat seat(std::make_unique<TestDataExchangeDelegate>());
+ MockPointerDelegate pointer_delegate;
+ std::unique_ptr<Pointer> pointer(new Pointer(&pointer_delegate, &seat));
+ TestDataSourceDelegate data_source_delegate;
+ DataSource source(&data_source_delegate);
+ Surface origin;
+
+ // Make origin into a real window so the pointer can click it
+ ShellSurface shell_surface(&origin);
+ Buffer buffer(exo_test_helper()->CreateGpuMemoryBuffer(gfx::Size(10, 10)));
+ origin.Attach(&buffer);
+ origin.Commit();
+
+ ui::test::EventGenerator generator(ash::Shell::GetPrimaryRootWindow());
+
+ EXPECT_CALL(pointer_delegate, CanAcceptPointerEventsForSurface(&origin))
+ .WillRepeatedly(testing::Return(true));
+ EXPECT_CALL(pointer_delegate, OnPointerFrame()).Times(AnyNumber());
+ EXPECT_CALL(pointer_delegate, OnPointerEnter(&origin, gfx::PointF(), 0));
+ generator.MoveMouseTo(origin.window()->GetBoundsInScreen().origin());
+
+ auto* drag_drop_controller = static_cast<ash::DragDropController*>(
+ aura::client::GetDragDropClient(ash::Shell::GetPrimaryRootWindow()));
+ ASSERT_TRUE(drag_drop_controller);
+
+ generator.PressLeftButton();
+ seat.StartDrag(&source, &origin, /*icon=*/nullptr,
+ ui::mojom::DragEventSource::kMouse);
+ EXPECT_TRUE(seat.get_drag_drop_operation_for_testing());
+
+ // As soon as the runloop gets triggered, emit a mouse release event.
+ drag_drop_controller->SetLoopClosureForTesting(
+ base::BindLambdaForTesting([&]() {
+ EXPECT_CALL(pointer_delegate, OnPointerEnter(_, _, _));
+ generator.ReleaseLeftButton();
+ }),
+ base::DoNothing());
+
+ EXPECT_CALL(pointer_delegate, OnPointerLeave(_));
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_CALL(pointer_delegate, OnPointerDestroying(pointer.get()));
+ pointer.reset();
+}
+
+TEST_F(PointerTest, DragDropAndPointerEnterLeaveEvents_NoOpOnTouchDrag) {
+ Seat seat(std::make_unique<TestDataExchangeDelegate>());
+ MockPointerDelegate pointer_delegate;
+ std::unique_ptr<Pointer> pointer(new Pointer(&pointer_delegate, &seat));
+ TestDataSourceDelegate data_source_delegate;
+ DataSource source(&data_source_delegate);
+ Surface origin;
+
+ // Make origin into a real window so the pointer can click it
+ ShellSurface shell_surface(&origin);
+ Buffer buffer(exo_test_helper()->CreateGpuMemoryBuffer(gfx::Size(10, 10)));
+ origin.Attach(&buffer);
+ origin.Commit();
+
+ ui::test::EventGenerator generator(ash::Shell::GetPrimaryRootWindow());
+
+ EXPECT_CALL(pointer_delegate, CanAcceptPointerEventsForSurface(&origin))
+ .WillRepeatedly(testing::Return(true));
+ EXPECT_CALL(pointer_delegate, OnPointerFrame()).Times(AnyNumber());
+ EXPECT_CALL(pointer_delegate, OnPointerEnter(&origin, gfx::PointF(), 0));
+ generator.MoveMouseTo(origin.window()->GetBoundsInScreen().origin());
+
+ auto* drag_drop_controller = static_cast<ash::DragDropController*>(
+ aura::client::GetDragDropClient(ash::Shell::GetPrimaryRootWindow()));
+ ASSERT_TRUE(drag_drop_controller);
+
+ seat.StartDrag(&source, &origin, /*icon=*/nullptr,
+ ui::mojom::DragEventSource::kTouch);
+ EXPECT_TRUE(seat.get_drag_drop_operation_for_testing());
+
+ // Initiate the gesture sequence.
+ DispatchGesture(ui::ET_GESTURE_BEGIN, gfx::Point(10, 10));
+
+ // As soon as the runloop gets triggered, emit a mouse release event.
+ drag_drop_controller->SetLoopClosureForTesting(
+ base::BindLambdaForTesting([&]() {
+ EXPECT_CALL(pointer_delegate, OnPointerEnter(_, _, _)).Times(0);
+ // generator.ReleaseLeftButton();
+ generator.set_current_screen_location(gfx::Point(10, 10));
+ generator.PressMoveAndReleaseTouchBy(50, 50);
+ }),
+ base::DoNothing());
+
+ EXPECT_CALL(pointer_delegate, OnPointerLeave(_)).Times(0);
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_CALL(pointer_delegate, OnPointerDestroying(pointer.get()));
+ pointer.reset();
+}
+#endif
+
TEST_F(PointerTest, OnPointerRelativeMotion) {
auto surface = std::make_unique<Surface>();
auto shell_surface = std::make_unique<ShellSurface>(surface.get());
@@ -1134,212 +1337,293 @@ TEST_F(PointerTest, OrdinalMotionOverridesRelativeMotion) {
}
#if BUILDFLAG(IS_CHROMEOS_ASH)
-TEST_F(PointerTest, ConstrainPointer) {
- auto scoped_feature_list = std::make_unique<base::test::ScopedFeatureList>();
- scoped_feature_list->InitAndEnableFeature(
- chromeos::features::kExoPointerLock);
-
- auto surface = std::make_unique<Surface>();
- auto shell_surface = std::make_unique<ShellSurface>(surface.get());
- gfx::Size buffer_size(10, 10);
- auto buffer = std::make_unique<Buffer>(
- exo_test_helper()->CreateGpuMemoryBuffer(buffer_size));
- surface->Attach(buffer.get());
- surface->Commit();
-
- MockPointerDelegate delegate;
- MockPointerConstraintDelegate constraint_delegate;
- Seat seat;
- auto pointer = std::make_unique<Pointer>(&delegate, &seat);
- aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow())
- ->FocusWindow(surface->window());
- ui::test::EventGenerator generator(ash::Shell::GetPrimaryRootWindow());
-
- EXPECT_CALL(delegate, CanAcceptPointerEventsForSurface(surface.get()))
- .WillRepeatedly(testing::Return(true));
-
- EXPECT_CALL(constraint_delegate, GetConstrainedSurface())
- .WillRepeatedly(testing::Return(surface.get()));
- EXPECT_TRUE(pointer->ConstrainPointer(&constraint_delegate));
-
- EXPECT_CALL(delegate, OnPointerEnter(surface.get(), gfx::PointF(), 0));
- EXPECT_CALL(delegate, OnPointerFrame());
- generator.MoveMouseTo(surface->window()->GetBoundsInScreen().origin());
-
- EXPECT_CALL(delegate, OnPointerMotion(testing::_, testing::_)).Times(0);
- generator.MoveMouseTo(surface->window()->GetBoundsInScreen().origin() +
- gfx::Vector2d(-1, -1));
-
- auto child_surface = std::make_unique<Surface>();
- auto child_shell_surface = std::make_unique<ShellSurface>(
- child_surface.get(), gfx::Point(), /*can_minimize=*/false,
- ash::desks_util::GetActiveDeskContainerId());
- child_shell_surface->DisableMovement();
- child_shell_surface->SetParent(shell_surface.get());
- gfx::Size child_buffer_size(15, 15);
- auto child_buffer = std::make_unique<Buffer>(
- exo_test_helper()->CreateGpuMemoryBuffer(child_buffer_size));
- child_surface->Attach(child_buffer.get());
- child_surface->Commit();
-
- EXPECT_CALL(delegate, CanAcceptPointerEventsForSurface(child_surface.get()))
+TEST_F(PointerConstraintTest, ConstrainPointer) {
+ EXPECT_TRUE(pointer_->ConstrainPointer(&constraint_delegate_));
+
+ EXPECT_CALL(delegate_, OnPointerEnter(surface_, gfx::PointF(), 0));
+ EXPECT_CALL(delegate_, OnPointerFrame());
+ generator_->MoveMouseTo(surface_->window()->GetBoundsInScreen().origin());
+
+ EXPECT_CALL(delegate_, OnPointerMotion(testing::_, testing::_)).Times(0);
+ generator_->MoveMouseTo(surface_->window()->GetBoundsInScreen().origin() +
+ gfx::Vector2d(-1, -1));
+
+ auto child_shell_surface = test::ShellSurfaceBuilder({15, 15})
+ .SetParent(shell_surface_.get())
+ .SetDisableMovement()
+ .SetCanMinimize(false)
+ .BuildShellSurface();
+ Surface* child_surface = child_shell_surface->surface_for_testing();
+ EXPECT_CALL(delegate_, CanAcceptPointerEventsForSurface(child_surface))
.WillRepeatedly(testing::Return(true));
- generator.MoveMouseTo(child_surface->window()->GetBoundsInScreen().origin());
+ generator_->MoveMouseTo(
+ child_surface->window()->GetBoundsInScreen().origin());
- EXPECT_CALL(delegate, OnPointerLeave(surface.get()));
- EXPECT_CALL(delegate, OnPointerEnter(child_surface.get(), gfx::PointF(), 0));
- EXPECT_CALL(delegate, OnPointerFrame());
+ EXPECT_CALL(delegate_, OnPointerLeave(surface_));
+ EXPECT_CALL(delegate_, OnPointerEnter(child_surface, gfx::PointF(), 0));
+ EXPECT_CALL(delegate_, OnPointerFrame());
// Moving the cursor to a different surface should change the focus when
// the pointer is unconstrained.
- pointer->UnconstrainPointer();
- generator.MoveMouseTo(child_surface->window()->GetBoundsInScreen().origin());
+ pointer_->UnconstrainPointerByUserAction();
+ generator_->MoveMouseTo(
+ child_surface->window()->GetBoundsInScreen().origin());
- EXPECT_CALL(delegate, OnPointerDestroying(pointer.get()));
- pointer.reset();
+ pointer_->OnPointerConstraintDelegateDestroying(&constraint_delegate_);
+ EXPECT_CALL(delegate_, OnPointerDestroying(pointer_.get()));
+ pointer_.reset();
}
#endif
#if BUILDFLAG(IS_CHROMEOS_ASH)
-TEST_F(PointerTest, ConstrainPointerFailsWhenSurfaceIsNotActive) {
- auto scoped_feature_list = std::make_unique<base::test::ScopedFeatureList>();
- scoped_feature_list->InitAndEnableFeature(
- chromeos::features::kExoPointerLock);
-
- auto surface = std::make_unique<Surface>();
- auto shell_surface = std::make_unique<ShellSurface>(surface.get());
- gfx::Size buffer_size(10, 10);
- auto buffer = std::make_unique<Buffer>(
- exo_test_helper()->CreateGpuMemoryBuffer(buffer_size));
- surface->Attach(buffer.get());
- surface->Commit();
-
- MockPointerDelegate delegate;
- MockPointerConstraintDelegate constraint_delegate;
- Seat seat;
- auto pointer = std::make_unique<Pointer>(&delegate, &seat);
- aura::client::FocusClient* focus_client =
- aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow());
- ui::test::EventGenerator generator(ash::Shell::GetPrimaryRootWindow());
-
- EXPECT_CALL(delegate, CanAcceptPointerEventsForSurface(surface.get()))
- .WillRepeatedly(testing::Return(true));
+TEST_F(PointerConstraintTest, CanOnlyConstrainPermittedWindows) {
+ std::unique_ptr<ShellSurface> shell_surface =
+ test::ShellSurfaceBuilder({10, 10}).BuildShellSurface();
+ EXPECT_CALL(constraint_delegate_, GetConstrainedSurface())
+ .WillRepeatedly(testing::Return(shell_surface->surface_for_testing()));
+ // Called once when ConstrainPointer is denied, and again when the delegate
+ // is destroyed.
+ EXPECT_CALL(constraint_delegate_, OnDefunct()).Times(2);
+
+ EXPECT_FALSE(pointer_->ConstrainPointer(&constraint_delegate_));
+
+ pointer_->OnPointerConstraintDelegateDestroying(&constraint_delegate_);
+ EXPECT_CALL(delegate_, OnPointerDestroying(pointer_.get()));
+ pointer_.reset();
+}
+#endif
- EXPECT_CALL(constraint_delegate, GetConstrainedSurface())
- .WillRepeatedly(testing::Return(surface.get()));
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+TEST_F(PointerConstraintTest, OneConstraintPerSurface) {
+ ON_CALL(constraint_delegate_, IsPersistent())
+ .WillByDefault(testing::Return(false));
+ EXPECT_TRUE(pointer_->ConstrainPointer(&constraint_delegate_));
+
+ EXPECT_CALL(delegate_, OnPointerEnter(surface_, gfx::PointF(), 0));
+ EXPECT_CALL(delegate_, OnPointerFrame()).Times(testing::AtLeast(1));
+ generator_->MoveMouseTo(surface_->window()->GetBoundsInScreen().origin());
+
+ // Add a second constraint for the same surface, it should fail.
+ MockPointerConstraintDelegate second_constraint;
+ EXPECT_CALL(second_constraint, GetConstrainedSurface())
+ .WillRepeatedly(testing::Return(surface_));
+ ON_CALL(second_constraint, IsPersistent())
+ .WillByDefault(testing::Return(false));
+ EXPECT_CALL(second_constraint, OnAlreadyConstrained());
+ EXPECT_CALL(second_constraint, OnDefunct());
+ EXPECT_FALSE(pointer_->ConstrainPointer(&second_constraint));
+
+ pointer_->OnPointerConstraintDelegateDestroying(&constraint_delegate_);
+ EXPECT_CALL(delegate_, OnPointerDestroying(pointer_.get()));
+ pointer_.reset();
+}
+#endif
- auto second_surface = std::make_unique<Surface>();
- auto second_shell_surface =
- std::make_unique<ShellSurface>(second_surface.get());
- auto second_buffer = std::make_unique<Buffer>(
- exo_test_helper()->CreateGpuMemoryBuffer(buffer_size));
- second_surface->Attach(second_buffer.get());
- second_surface->Commit();
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+TEST_F(PointerConstraintTest, OneShotConstraintActivatedOnFirstFocus) {
+ auto second_shell_surface = BuildShellSurfaceWhichPermitsPointerLock();
+ Surface* second_surface = second_shell_surface->surface_for_testing();
- EXPECT_CALL(delegate, CanAcceptPointerEventsForSurface(second_surface.get()))
+ EXPECT_CALL(delegate_, CanAcceptPointerEventsForSurface(second_surface))
.WillRepeatedly(testing::Return(true));
- // Setting the focused window also makes it activated.
- focus_client->FocusWindow(second_surface->window());
- EXPECT_FALSE(pointer->ConstrainPointer(&constraint_delegate));
+ focus_client_->FocusWindow(second_surface->window());
- focus_client->FocusWindow(surface->window());
- EXPECT_TRUE(pointer->ConstrainPointer(&constraint_delegate));
+ // Assert: Can no longer activate the constraint on the first surface.
+ EXPECT_FALSE(pointer_->ConstrainPointer(&constraint_delegate_));
+ EXPECT_EQ(constraint_delegate_.activated_count, 0);
- EXPECT_CALL(delegate, OnPointerEnter(surface.get(), gfx::PointF(), 0));
- EXPECT_CALL(delegate, OnPointerFrame());
- generator.MoveMouseTo(surface->window()->GetBoundsInScreen().origin());
+ // Assert: Constraint is activated when first surface gains focus.
+ focus_client_->FocusWindow(surface_->window());
+ EXPECT_EQ(constraint_delegate_.activated_count, 1);
- pointer->UnconstrainPointer();
+ EXPECT_CALL(delegate_, OnPointerEnter(surface_, gfx::PointF(), 0));
+ EXPECT_CALL(delegate_, OnPointerFrame());
+ generator_->MoveMouseTo(surface_->window()->GetBoundsInScreen().origin());
- EXPECT_CALL(delegate, OnPointerDestroying(pointer.get()));
- pointer.reset();
+ // Teardown
+ pointer_->OnPointerConstraintDelegateDestroying(&constraint_delegate_);
+ EXPECT_CALL(delegate_, OnPointerDestroying(pointer_.get()));
+ pointer_.reset();
}
#endif
#if BUILDFLAG(IS_CHROMEOS_ASH)
-TEST_F(PointerTest, UnconstrainPointerWhenSurfaceIsDestroyed) {
- auto scoped_feature_list = std::make_unique<base::test::ScopedFeatureList>();
- scoped_feature_list->InitAndEnableFeature(
- chromeos::features::kExoPointerLock);
+TEST_F(PointerConstraintTest, UnconstrainPointerWhenSurfaceIsDestroyed) {
+ EXPECT_TRUE(pointer_->ConstrainPointer(&constraint_delegate_));
- auto surface = std::make_unique<Surface>();
- auto shell_surface = std::make_unique<ShellSurface>(surface.get());
- gfx::Size buffer_size(10, 10);
- auto buffer = std::make_unique<Buffer>(
- exo_test_helper()->CreateGpuMemoryBuffer(buffer_size));
- surface->Attach(buffer.get());
- surface->Commit();
+ EXPECT_CALL(delegate_, OnPointerEnter(surface_, gfx::PointF(), 0));
+ EXPECT_CALL(delegate_, OnPointerFrame());
+ generator_->MoveMouseTo(surface_->window()->GetBoundsInScreen().origin());
- MockPointerDelegate delegate;
- MockPointerConstraintDelegate constraint_delegate;
- Seat seat;
- auto pointer = std::make_unique<Pointer>(&delegate, &seat);
- aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow())
- ->FocusWindow(surface->window());
- ui::test::EventGenerator generator(ash::Shell::GetPrimaryRootWindow());
-
- EXPECT_CALL(delegate, CanAcceptPointerEventsForSurface(surface.get()))
- .WillRepeatedly(testing::Return(true));
-
- EXPECT_CALL(constraint_delegate, GetConstrainedSurface())
- .WillRepeatedly(testing::Return(surface.get()));
- EXPECT_TRUE(pointer->ConstrainPointer(&constraint_delegate));
+ // Constraint should be broken if surface is destroyed.
+ EXPECT_CALL(constraint_delegate_, OnConstraintBroken());
+ EXPECT_CALL(delegate_, OnPointerLeave(surface_));
+ EXPECT_CALL(delegate_, OnPointerFrame());
+ shell_surface_.reset();
- EXPECT_CALL(delegate, OnPointerEnter(surface.get(), gfx::PointF(), 0));
- EXPECT_CALL(delegate, OnPointerFrame());
- generator.MoveMouseTo(surface->window()->GetBoundsInScreen().origin());
+ EXPECT_CALL(delegate_, OnPointerDestroying(pointer_.get()));
+ pointer_.reset();
+}
+#endif
- // Constraint should be broken if surface is destroyed.
- EXPECT_CALL(constraint_delegate, OnConstraintBroken());
- EXPECT_CALL(delegate, OnPointerLeave(surface.get()));
- EXPECT_CALL(delegate, OnPointerFrame());
- pointer->OnSurfaceDestroying(surface.get());
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+TEST_F(PointerConstraintTest, UnconstrainPointerWhenWindowLosesFocus) {
+ ON_CALL(constraint_delegate_, IsPersistent())
+ .WillByDefault(testing::Return(false));
+ EXPECT_TRUE(pointer_->ConstrainPointer(&constraint_delegate_));
+
+ EXPECT_CALL(delegate_, OnPointerEnter(surface_, gfx::PointF(), 0));
+ EXPECT_CALL(delegate_, OnPointerFrame());
+ generator_->MoveMouseTo(surface_->window()->GetBoundsInScreen().origin());
+
+ EXPECT_CALL(constraint_delegate_, OnConstraintBroken());
+ EXPECT_CALL(constraint_delegate_, OnConstraintActivated()).Times(0);
+ focus_client_->FocusWindow(nullptr);
+ focus_client_->FocusWindow(surface_->window());
+
+ pointer_->OnPointerConstraintDelegateDestroying(&constraint_delegate_);
+ EXPECT_CALL(delegate_, OnPointerDestroying(pointer_.get()));
+ pointer_.reset();
+}
+#endif
- EXPECT_CALL(delegate, OnPointerDestroying(pointer.get()));
- pointer.reset();
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+TEST_F(PointerConstraintTest, PersistentConstraintActivatedOnRefocus) {
+ ON_CALL(constraint_delegate_, IsPersistent())
+ .WillByDefault(testing::Return(true));
+ EXPECT_TRUE(pointer_->ConstrainPointer(&constraint_delegate_));
+
+ EXPECT_CALL(delegate_, OnPointerEnter(surface_, gfx::PointF(), 0));
+ EXPECT_CALL(delegate_, OnPointerFrame());
+ generator_->MoveMouseTo(surface_->window()->GetBoundsInScreen().origin());
+
+ EXPECT_CALL(constraint_delegate_, OnConstraintBroken());
+ focus_client_->FocusWindow(nullptr);
+ EXPECT_CALL(constraint_delegate_, OnConstraintActivated());
+ focus_client_->FocusWindow(surface_->window());
+
+ pointer_->OnPointerConstraintDelegateDestroying(&constraint_delegate_);
+ EXPECT_CALL(delegate_, OnPointerDestroying(pointer_.get()));
+ pointer_.reset();
}
#endif
#if BUILDFLAG(IS_CHROMEOS_ASH)
-TEST_F(PointerTest, UnconstrainPointerWhenWindowLosesFocus) {
- auto scoped_feature_list = std::make_unique<base::test::ScopedFeatureList>();
- scoped_feature_list->InitAndEnableFeature(
- chromeos::features::kExoPointerLock);
+TEST_F(PointerConstraintTest, MultipleSurfacesCanBeConstrained) {
+ // Arrange: First surface + persistent constraint
+ ON_CALL(constraint_delegate_, IsPersistent())
+ .WillByDefault(testing::Return(true));
+ EXPECT_TRUE(pointer_->ConstrainPointer(&constraint_delegate_));
+
+ EXPECT_CALL(delegate_, OnPointerEnter(surface_, gfx::PointF(), 0));
+ EXPECT_CALL(delegate_, OnPointerFrame());
+ generator_->MoveMouseTo(surface_->window()->GetBoundsInScreen().origin());
+
+ EXPECT_EQ(constraint_delegate_.activated_count, 1);
+
+ // Arrange: Second surface + persistent constraint
+ auto second_shell_surface = BuildShellSurfaceWhichPermitsPointerLock();
+ Surface* second_surface = second_shell_surface->surface_for_testing();
+ focus_client_->FocusWindow(second_surface->window());
+ EXPECT_CALL(delegate_, CanAcceptPointerEventsForSurface(second_surface))
+ .WillRepeatedly(testing::Return(true));
+ testing::NiceMock<MockPointerConstraintDelegate> second_constraint;
+ EXPECT_CALL(second_constraint, GetConstrainedSurface())
+ .WillRepeatedly(testing::Return(second_surface));
+ ON_CALL(second_constraint, IsPersistent())
+ .WillByDefault(testing::Return(true));
+ EXPECT_TRUE(pointer_->ConstrainPointer(&second_constraint));
- auto surface = std::make_unique<Surface>();
- auto shell_surface = std::make_unique<ShellSurface>(surface.get());
- gfx::Size buffer_size(10, 10);
- auto buffer = std::make_unique<Buffer>(
- exo_test_helper()->CreateGpuMemoryBuffer(buffer_size));
- surface->Attach(buffer.get());
- surface->Commit();
+ EXPECT_EQ(constraint_delegate_.activated_count, 1);
+ EXPECT_EQ(second_constraint.activated_count, 1);
- MockPointerDelegate delegate;
- MockPointerConstraintDelegate constraint_delegate;
- Seat seat;
- auto pointer = std::make_unique<Pointer>(&delegate, &seat);
- aura::client::FocusClient* focus_client =
- aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow());
- focus_client->FocusWindow(surface->window());
- ui::test::EventGenerator generator(ash::Shell::GetPrimaryRootWindow());
+ // Act: Toggle focus, first surface's constraint should activate.
+ focus_client_->FocusWindow(surface_->window());
- EXPECT_CALL(delegate, CanAcceptPointerEventsForSurface(surface.get()))
- .WillRepeatedly(testing::Return(true));
+ EXPECT_EQ(constraint_delegate_.activated_count, 2);
+ EXPECT_EQ(second_constraint.activated_count, 1);
- EXPECT_CALL(constraint_delegate, GetConstrainedSurface())
- .WillRepeatedly(testing::Return(surface.get()));
- EXPECT_TRUE(pointer->ConstrainPointer(&constraint_delegate));
+ // Act: Toggle focus, second surface's constraint should activate.
+ focus_client_->FocusWindow(second_surface->window());
- EXPECT_CALL(delegate, OnPointerEnter(surface.get(), gfx::PointF(), 0));
- EXPECT_CALL(delegate, OnPointerFrame());
- generator.MoveMouseTo(surface->window()->GetBoundsInScreen().origin());
+ EXPECT_EQ(constraint_delegate_.activated_count, 2);
+ EXPECT_EQ(second_constraint.activated_count, 2);
- EXPECT_CALL(constraint_delegate, OnConstraintBroken());
- focus_client->FocusWindow(nullptr);
+ pointer_->OnPointerConstraintDelegateDestroying(&constraint_delegate_);
+ pointer_->OnPointerConstraintDelegateDestroying(&second_constraint);
+ EXPECT_CALL(delegate_, OnPointerDestroying(pointer_.get()));
+ pointer_.reset();
+}
+#endif
- EXPECT_CALL(delegate, OnPointerDestroying(pointer.get()));
- pointer.reset();
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+TEST_F(PointerConstraintTest, UserActionPreventsConstraint) {
+ ON_CALL(constraint_delegate_, IsPersistent())
+ .WillByDefault(testing::Return(false));
+ EXPECT_TRUE(pointer_->ConstrainPointer(&constraint_delegate_));
+
+ EXPECT_CALL(delegate_, OnPointerEnter(surface_, gfx::PointF(), 0));
+ EXPECT_CALL(delegate_, OnPointerFrame()).Times(testing::AtLeast(1));
+ generator_->MoveMouseTo(surface_->window()->GetBoundsInScreen().origin());
+
+ EXPECT_CALL(constraint_delegate_, OnConstraintBroken());
+ pointer_->UnconstrainPointerByUserAction();
+
+ // New constraints are no longer permitted.
+ MockPointerConstraintDelegate second_constraint;
+ EXPECT_CALL(second_constraint, GetConstrainedSurface())
+ .WillRepeatedly(testing::Return(surface_));
+ ON_CALL(second_constraint, IsPersistent())
+ .WillByDefault(testing::Return(false));
+ EXPECT_FALSE(pointer_->ConstrainPointer(&second_constraint));
+ EXPECT_EQ(second_constraint.activated_count, 0);
+
+ // A click event will activate the pending constraint.
+ generator_->ClickLeftButton();
+ EXPECT_EQ(second_constraint.activated_count, 1);
+
+ pointer_->OnPointerConstraintDelegateDestroying(&second_constraint);
+
+ // New constraints are now permitted too.
+ MockPointerConstraintDelegate third_constraint;
+ EXPECT_CALL(third_constraint, GetConstrainedSurface())
+ .WillRepeatedly(testing::Return(surface_));
+ ON_CALL(third_constraint, IsPersistent())
+ .WillByDefault(testing::Return(false));
+ EXPECT_TRUE(pointer_->ConstrainPointer(&third_constraint));
+ pointer_->OnPointerConstraintDelegateDestroying(&third_constraint);
+
+ pointer_->OnPointerConstraintDelegateDestroying(&constraint_delegate_);
+ EXPECT_CALL(delegate_, OnPointerDestroying(pointer_.get()));
+ pointer_.reset();
+}
+#endif
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+TEST_F(PointerConstraintTest, UserCanBreakAndActivatePersistentConstraint) {
+ ON_CALL(constraint_delegate_, IsPersistent())
+ .WillByDefault(testing::Return(true));
+ EXPECT_TRUE(pointer_->ConstrainPointer(&constraint_delegate_));
+ EXPECT_EQ(constraint_delegate_.activated_count, 1);
+ EXPECT_EQ(constraint_delegate_.broken_count, 0);
+
+ EXPECT_CALL(delegate_, OnPointerEnter(surface_, gfx::PointF(), 0));
+ EXPECT_CALL(delegate_, OnPointerFrame()).Times(testing::AtLeast(1));
+ generator_->MoveMouseTo(surface_->window()->GetBoundsInScreen().origin());
+
+ EXPECT_CALL(constraint_delegate_, OnConstraintBroken());
+ pointer_->UnconstrainPointerByUserAction();
+ EXPECT_EQ(constraint_delegate_.activated_count, 1);
+ EXPECT_EQ(constraint_delegate_.broken_count, 1);
+
+ // Click events re-enable the constraint.
+ generator_->ClickLeftButton();
+ EXPECT_EQ(constraint_delegate_.activated_count, 2);
+
+ pointer_->OnPointerConstraintDelegateDestroying(&constraint_delegate_);
+ EXPECT_CALL(delegate_, OnPointerDestroying(pointer_.get()));
+ pointer_.reset();
}
#endif
diff --git a/chromium/components/exo/protected_native_pixmap_query_delegate.h b/chromium/components/exo/protected_native_pixmap_query_delegate.h
new file mode 100644
index 00000000000..78c8ee57139
--- /dev/null
+++ b/chromium/components/exo/protected_native_pixmap_query_delegate.h
@@ -0,0 +1,28 @@
+// Copyright 2021 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.
+
+#ifndef COMPONENTS_EXO_PROTECTED_NATIVE_PIXMAP_QUERY_DELEGATE_H_
+#define COMPONENTS_EXO_PROTECTED_NATIVE_PIXMAP_QUERY_DELEGATE_H_
+
+#include "base/callback_forward.h"
+#include "base/files/scoped_file.h"
+
+namespace exo {
+// Interface for querying if a GMB handle is associated with a protected native
+// pixmap. This is needed for platforms with HW protected video so we set the
+// properties on the quad correctly.
+class ProtectedNativePixmapQueryDelegate {
+ public:
+ virtual ~ProtectedNativePixmapQueryDelegate() = default;
+
+ using IsProtectedNativePixmapHandleCallback = base::OnceCallback<void(bool)>;
+ // Queries the GPU process for whether or not the passed in handle is
+ // associated with protected native pixmap. Invokes the callback
+ // asynchronously with the result.
+ virtual void IsProtectedNativePixmapHandle(
+ base::ScopedFD handle,
+ IsProtectedNativePixmapHandleCallback callback) = 0;
+};
+} // namespace exo
+#endif // COMPONENTS_EXO_PROTECTED_NATIVE_PIXMAP_QUERY_DELEGATE_H_ \ No newline at end of file
diff --git a/chromium/components/exo/seat.cc b/chromium/components/exo/seat.cc
index d863f4f9287..9143fb1f88a 100644
--- a/chromium/components/exo/seat.cc
+++ b/chromium/components/exo/seat.cc
@@ -31,6 +31,7 @@
#include "ui/base/clipboard/clipboard_monitor.h"
#include "ui/base/clipboard/scoped_clipboard_writer.h"
#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
+#include "ui/base/data_transfer_policy/data_transfer_endpoint_serializer.h"
#include "ui/events/event_utils.h"
#include "ui/events/platform/platform_event_source.h"
#include "ui/gfx/geometry/point_f.h"
@@ -104,6 +105,22 @@ void Seat::RemoveObserver(SeatObserver* observer) {
observer_list.RemoveObserver(observer);
}
+void Seat::NotifyPointerCaptureEnabled(Pointer* pointer,
+ aura::Window* capture_window) {
+ for (auto& observer_list : priority_observer_list_) {
+ for (auto& observer : observer_list)
+ observer.OnPointerCaptureEnabled(pointer, capture_window);
+ }
+}
+
+void Seat::NotifyPointerCaptureDisabled(Pointer* pointer,
+ aura::Window* capture_window) {
+ for (auto& observer_list : priority_observer_list_) {
+ for (auto& observer : observer_list)
+ observer.OnPointerCaptureDisabled(pointer, capture_window);
+ }
+}
+
Surface* Seat::GetFocusedSurface() {
return GetTargetSurfaceForKeyboardFocus(
WMHelper::GetInstance()->GetFocusedWindow());
@@ -149,11 +166,30 @@ void Seat::SetSelection(DataSource* source) {
scoped_refptr<RefCountedScopedClipboardWriter> writer =
base::MakeRefCounted<RefCountedScopedClipboardWriter>(endpoint_type);
+ size_t num_data_read_callbacks = DataSource::kMaxDataTypes;
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+ // Lacros sends additional metadata, in a custom MIME type, to sync clipboard
+ // source metadata,
+ if (endpoint_type == ui::EndpointType::kLacros)
+ ++num_data_read_callbacks;
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
+
base::RepeatingClosure data_read_callback = base::BarrierClosure(
- DataSource::kMaxDataTypes,
+ num_data_read_callbacks,
base::BindOnce(&Seat::OnAllReadsFinished, weak_ptr_factory_.GetWeakPtr(),
writer));
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+ if (endpoint_type == ui::EndpointType::kLacros) {
+ source->ReadDataTransferEndpoint(
+ base::BindOnce(&Seat::OnDataTransferEndpointRead,
+ weak_ptr_factory_.GetWeakPtr(), writer,
+ data_read_callback),
+ data_read_callback);
+ }
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
+
source->GetDataForPreferredMimeTypes(
base::BindOnce(&Seat::OnTextRead, weak_ptr_factory_.GetWeakPtr(), writer,
data_read_callback),
@@ -185,6 +221,20 @@ class Seat::RefCountedScopedClipboardWriter
virtual ~RefCountedScopedClipboardWriter() = default;
};
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+void Seat::OnDataTransferEndpointRead(
+ scoped_refptr<RefCountedScopedClipboardWriter> writer,
+ base::OnceClosure callback,
+ const std::string& mime_type,
+ std::u16string data) {
+ std::string utf8_json = base::UTF16ToUTF8(data);
+ auto clipboard_source = ui::ConvertJsonToDataTransferEndpoint(utf8_json);
+
+ writer->SetDataSource(std::move(clipboard_source));
+ std::move(callback).Run();
+}
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
+
void Seat::OnTextRead(scoped_refptr<RefCountedScopedClipboardWriter> writer,
base::OnceClosure callback,
const std::string& mime_type,
diff --git a/chromium/components/exo/seat.h b/chromium/components/exo/seat.h
index 16796f593dc..619eda37fff 100644
--- a/chromium/components/exo/seat.h
+++ b/chromium/components/exo/seat.h
@@ -37,6 +37,7 @@ class KeyEvent;
namespace exo {
class DragDropOperation;
class DataExchangeDelegate;
+class Pointer;
class ScopedDataSource;
class SeatObserver;
class Surface;
@@ -81,7 +82,13 @@ class Seat : public aura::client::FocusChangeObserver,
return 0 <= priority && priority <= kMaxObserverPriority;
}
- // Returns currently focused surface. This is vertual so that we can override
+ // Notify observers about pointer capture state changes.
+ void NotifyPointerCaptureEnabled(Pointer* pointer,
+ aura::Window* capture_window);
+ void NotifyPointerCaptureDisabled(Pointer* pointer,
+ aura::Window* capture_window);
+
+ // Returns currently focused surface. This is virtual so that we can override
// the behavior for testing.
virtual Surface* GetFocusedSurface();
@@ -158,6 +165,18 @@ class Seat : public aura::client::FocusChangeObserver,
private:
class RefCountedScopedClipboardWriter;
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+ // Called when the focused window is a Lacros window and a source
+ // DataTransferEndpoint is read in the available MIME types. This
+ // is currently used to synchronize clipboard source metadata from
+ // Lacros to Ash.
+ void OnDataTransferEndpointRead(
+ scoped_refptr<RefCountedScopedClipboardWriter> writer,
+ base::OnceClosure callback,
+ const std::string& mime_type,
+ std::u16string data);
+#endif
+
// Called when data is read from FD passed from a client.
// |data| is read data. |source| is source of the data, or nullptr if
// DataSource has already been destroyed.
diff --git a/chromium/components/exo/seat_observer.h b/chromium/components/exo/seat_observer.h
index 0ca00ed3584..3d9fcc84a06 100644
--- a/chromium/components/exo/seat_observer.h
+++ b/chromium/components/exo/seat_observer.h
@@ -5,8 +5,13 @@
#ifndef COMPONENTS_EXO_SEAT_OBSERVER_H_
#define COMPONENTS_EXO_SEAT_OBSERVER_H_
+namespace aura {
+class Window;
+}
+
namespace exo {
+class Pointer;
class Surface;
// Observers can listen to various events on the Seats.
@@ -17,6 +22,14 @@ class SeatObserver {
Surface* lost_focus,
bool has_focused_client) = 0;
+ // Called when a pointer is captured by the given window.
+ virtual void OnPointerCaptureEnabled(Pointer* pointer,
+ aura::Window* capture_window) {}
+
+ // Called when the given pointer is no longer captured by the given window.
+ virtual void OnPointerCaptureDisabled(Pointer* pointer,
+ aura::Window* capture_window) {}
+
protected:
virtual ~SeatObserver() = default;
};
diff --git a/chromium/components/exo/seat_unittest.cc b/chromium/components/exo/seat_unittest.cc
index 46d19990c9e..b610ec0ff8c 100644
--- a/chromium/components/exo/seat_unittest.cc
+++ b/chromium/components/exo/seat_unittest.cc
@@ -4,6 +4,7 @@
#include "components/exo/seat.h"
+#include "base/containers/flat_map.h"
#include "base/files/file_util.h"
#include "base/memory/scoped_refptr.h"
#include "base/pickle.h"
@@ -59,11 +60,11 @@ class TestDataSourceDelegate : public DataSourceDelegate {
void OnDataSourceDestroying(DataSource* device) override {}
void OnTarget(const absl::optional<std::string>& mime_type) override {}
void OnSend(const std::string& mime_type, base::ScopedFD fd) override {
- if (!data_.has_value()) {
+ if (data_map_.empty()) {
const char kTestData[] = "TestData";
ASSERT_TRUE(base::WriteFileDescriptor(fd.get(), kTestData));
} else {
- ASSERT_TRUE(base::WriteFileDescriptor(fd.get(), *data_));
+ ASSERT_TRUE(base::WriteFileDescriptor(fd.get(), data_map_[mime_type]));
}
}
void OnCancelled() override { cancelled_ = true; }
@@ -74,13 +75,15 @@ class TestDataSourceDelegate : public DataSourceDelegate {
return can_accept_;
}
- void SetData(std::vector<uint8_t> data) { data_ = std::move(data); }
+ void SetData(const std::string& mime_type, std::vector<uint8_t> data) {
+ data_map_[mime_type] = std::move(data);
+ }
bool can_accept_ = true;
private:
bool cancelled_ = false;
- absl::optional<std::vector<uint8_t>> data_;
+ base::flat_map<std::string, std::vector<uint8_t>> data_map_;
};
void RunReadingTask() {
@@ -91,6 +94,9 @@ void RunReadingTask() {
class TestSeat : public Seat {
public:
TestSeat() : Seat(std::make_unique<TestDataExchangeDelegate>()) {}
+ explicit TestSeat(
+ std::unique_ptr<TestDataExchangeDelegate> data_exchange_delegate)
+ : Seat(std::move(data_exchange_delegate)) {}
TestSeat(const TestSeat&) = delete;
void operator=(const TestSeat&) = delete;
@@ -150,6 +156,95 @@ TEST_F(SeatTest, SetSelection) {
EXPECT_EQ(clipboard, std::string("TestData"));
}
+TEST_F(SeatTest, SetSelectionReadDteFromLacros) {
+ std::unique_ptr<TestDataExchangeDelegate> data_exchange_delegate(
+ std::make_unique<TestDataExchangeDelegate>());
+ data_exchange_delegate->set_endpoint_type(ui::EndpointType::kLacros);
+ TestSeat seat(std::move(data_exchange_delegate));
+ Surface focused_surface;
+ seat.set_focused_surface(&focused_surface);
+
+ const std::string kTestText = "TestData";
+ const std::string kEncodedTestDte =
+ R"({"endpoint_type":"url","url_origin":"https://www.google.com"})";
+
+ const std::string kTextMimeType = "text/plain;charset=utf-8";
+ const std::string kDteMimeType = "chromium/x-data-transfer-endpoint";
+
+ TestDataSourceDelegate delegate;
+ DataSource source(&delegate);
+
+ source.Offer(kTextMimeType);
+ delegate.SetData(kTextMimeType,
+ std::vector<uint8_t>(kTestText.begin(), kTestText.end()));
+ source.Offer(kDteMimeType);
+ delegate.SetData(kDteMimeType, std::vector<uint8_t>(kEncodedTestDte.begin(),
+ kEncodedTestDte.end()));
+ seat.SetSelection(&source);
+
+ RunReadingTask();
+
+ std::string clipboard;
+ ui::Clipboard::GetForCurrentThread()->ReadAsciiText(
+ ui::ClipboardBuffer::kCopyPaste, /*data_dst=*/nullptr, &clipboard);
+
+ EXPECT_EQ(clipboard, kTestText);
+
+ const ui::DataTransferEndpoint* source_dte =
+ ui::Clipboard::GetForCurrentThread()->GetSource(
+ ui::ClipboardBuffer::kCopyPaste);
+
+ ASSERT_TRUE(source_dte);
+ EXPECT_EQ(ui::EndpointType::kUrl, source_dte->type());
+
+ const ui::DataTransferEndpoint expected_dte = ui::DataTransferEndpoint(
+ url::Origin::Create(GURL("https://www.google.com")));
+ EXPECT_TRUE(
+ expected_dte.GetOrigin()->IsSameOriginWith(*source_dte->GetOrigin()));
+}
+
+TEST_F(SeatTest, SetSelectionIgnoreDteFromNonLacros) {
+ std::unique_ptr<TestDataExchangeDelegate> data_exchange_delegate(
+ std::make_unique<TestDataExchangeDelegate>());
+ data_exchange_delegate->set_endpoint_type(ui::EndpointType::kCrostini);
+ TestSeat seat(std::move(data_exchange_delegate));
+ Surface focused_surface;
+ seat.set_focused_surface(&focused_surface);
+
+ const std::string kTestText = "TestData";
+ const std::string kEncodedTestDte =
+ R"({"endpoint_type":"url","url_origin":"https://www.google.com"})";
+
+ const std::string kTextMimeType = "text/plain;charset=utf-8";
+ const std::string kDteMimeType = "chromium/x-data-transfer-endpoint";
+
+ TestDataSourceDelegate delegate;
+ DataSource source(&delegate);
+
+ source.Offer(kTextMimeType);
+ delegate.SetData(kTextMimeType,
+ std::vector<uint8_t>(kTestText.begin(), kTestText.end()));
+ source.Offer(kDteMimeType);
+ delegate.SetData(kDteMimeType, std::vector<uint8_t>(kEncodedTestDte.begin(),
+ kEncodedTestDte.end()));
+ seat.SetSelection(&source);
+
+ RunReadingTask();
+
+ std::string clipboard;
+ ui::Clipboard::GetForCurrentThread()->ReadAsciiText(
+ ui::ClipboardBuffer::kCopyPaste, /*data_dst=*/nullptr, &clipboard);
+
+ EXPECT_EQ(clipboard, kTestText);
+
+ const ui::DataTransferEndpoint* source_dte =
+ ui::Clipboard::GetForCurrentThread()->GetSource(
+ ui::ClipboardBuffer::kCopyPaste);
+
+ ASSERT_TRUE(source_dte);
+ EXPECT_EQ(ui::EndpointType::kCrostini, source_dte->type());
+}
+
TEST_F(SeatTest, SetSelectionTextUTF8) {
TestSeat seat;
Surface focused_surface;
@@ -166,9 +261,15 @@ TEST_F(SeatTest, SetSelectionTextUTF8) {
TestDataSourceDelegate delegate;
DataSource source(&delegate);
- source.Offer("text/plain;charset=utf-8");
- source.Offer("text/html;charset=utf-8");
- delegate.SetData(std::vector<uint8_t>(data, data + sizeof(data)));
+
+ const std::string kTextPlainType = "text/plain;charset=utf-8";
+ const std::string kTextHtmlType = "text/html;charset=utf-8";
+ source.Offer(kTextPlainType);
+ source.Offer(kTextHtmlType);
+ delegate.SetData(kTextPlainType,
+ std::vector<uint8_t>(data, data + sizeof(data)));
+ delegate.SetData(kTextHtmlType,
+ std::vector<uint8_t>(data, data + sizeof(data)));
seat.SetSelection(&source);
RunReadingTask();
@@ -202,8 +303,9 @@ TEST_F(SeatTest, SetSelectionTextUTF8Legacy) {
TestDataSourceDelegate delegate;
DataSource source(&delegate);
- source.Offer("UTF8_STRING");
- delegate.SetData(std::vector<uint8_t>(data, data + sizeof(data)));
+ const std::string kMimeType = "UTF8_STRING";
+ source.Offer(kMimeType);
+ delegate.SetData(kMimeType, std::vector<uint8_t>(data, data + sizeof(data)));
seat.SetSelection(&source);
RunReadingTask();
@@ -232,9 +334,14 @@ TEST_F(SeatTest, SetSelectionTextUTF16LE) {
TestDataSourceDelegate delegate;
DataSource source(&delegate);
- source.Offer("text/plain;charset=utf-16");
- source.Offer("text/html;charset=utf-16");
- delegate.SetData(std::vector<uint8_t>(data, data + sizeof(data)));
+ const std::string kTextPlainType = "text/plain;charset=utf-16";
+ const std::string kTextHtmlType = "text/html;charset=utf-16";
+ source.Offer(kTextPlainType);
+ source.Offer(kTextHtmlType);
+ delegate.SetData(kTextPlainType,
+ std::vector<uint8_t>(data, data + sizeof(data)));
+ delegate.SetData(kTextHtmlType,
+ std::vector<uint8_t>(data, data + sizeof(data)));
seat.SetSelection(&source);
RunReadingTask();
@@ -270,9 +377,14 @@ TEST_F(SeatTest, SetSelectionTextUTF16BE) {
TestDataSourceDelegate delegate;
DataSource source(&delegate);
- source.Offer("text/plain;charset=utf-16");
- source.Offer("text/html;charset=utf-16");
- delegate.SetData(std::vector<uint8_t>(data, data + sizeof(data)));
+ const std::string kTextPlainType = "text/plain;charset=utf-16";
+ const std::string kTextHtmlType = "text/html;charset=utf-16";
+ source.Offer(kTextPlainType);
+ source.Offer(kTextHtmlType);
+ delegate.SetData(kTextPlainType,
+ std::vector<uint8_t>(data, data + sizeof(data)));
+ delegate.SetData(kTextHtmlType,
+ std::vector<uint8_t>(data, data + sizeof(data)));
seat.SetSelection(&source);
RunReadingTask();
@@ -299,9 +411,14 @@ TEST_F(SeatTest, SetSelectionTextEmptyString) {
TestDataSourceDelegate delegate;
DataSource source(&delegate);
- source.Offer("text/plain;charset=utf-8");
- source.Offer("text/html;charset=utf-16");
- delegate.SetData(std::vector<uint8_t>(data, data + sizeof(data)));
+ const std::string kTextPlainType = "text/plain;charset=utf-8";
+ const std::string kTextHtmlType = "text/html;charset=utf-16";
+ source.Offer(kTextPlainType);
+ source.Offer(kTextHtmlType);
+ delegate.SetData(kTextPlainType,
+ std::vector<uint8_t>(data, data + sizeof(data)));
+ delegate.SetData(kTextHtmlType,
+ std::vector<uint8_t>(data, data + sizeof(data)));
seat.SetSelection(&source);
RunReadingTask();
@@ -343,12 +460,13 @@ TEST_F(SeatTest, SetSelectionFilenames) {
Surface focused_surface;
seat.set_focused_surface(&focused_surface);
- std::string data("file:///path1\r\nfile:///path2");
+ const std::string data("file:///path1\r\nfile:///path2");
TestDataSourceDelegate delegate;
- delegate.SetData(std::vector<uint8_t>(data.begin(), data.end()));
+ const std::string kMimeType = "text/uri-list";
+ delegate.SetData(kMimeType, std::vector<uint8_t>(data.begin(), data.end()));
DataSource source(&delegate);
- source.Offer("text/uri-list");
+ source.Offer(kMimeType);
seat.SetSelection(&source);
RunReadingTask();
diff --git a/chromium/components/exo/server/BUILD.gn b/chromium/components/exo/server/BUILD.gn
index f9e4b45861a..4adb85c4cde 100644
--- a/chromium/components/exo/server/BUILD.gn
+++ b/chromium/components/exo/server/BUILD.gn
@@ -8,7 +8,6 @@ import("//components/exo/buildflags.gni")
assert(is_chromeos_ash)
source_set("server") {
- testonly = enable_weston_test
sources = [
"wayland_server_controller.cc",
"wayland_server_controller.h",
diff --git a/chromium/components/exo/server/wayland_server_controller.cc b/chromium/components/exo/server/wayland_server_controller.cc
index 3521873225c..bdc17fd3bc7 100644
--- a/chromium/components/exo/server/wayland_server_controller.cc
+++ b/chromium/components/exo/server/wayland_server_controller.cc
@@ -51,6 +51,8 @@ WaylandServerController::~WaylandServerController() {
// TODO(https://crbug.com/1124106): Investigate if we can eliminate Shutdown
// methods.
display_->Shutdown();
+ DCHECK_EQ(g_instance, this);
+ g_instance = nullptr;
}
WaylandServerController::WaylandServerController(
diff --git a/chromium/components/exo/server/wayland_server_controller.h b/chromium/components/exo/server/wayland_server_controller.h
index 50f6f85f373..b2f38848908 100644
--- a/chromium/components/exo/server/wayland_server_controller.h
+++ b/chromium/components/exo/server/wayland_server_controller.h
@@ -58,8 +58,16 @@ class WaylandServerController {
std::unique_ptr<InputMethodSurfaceManager> input_method_surface_manager,
std::unique_ptr<ToastSurfaceManager> toast_surface_manager);
+ // Creates a wayland server with the given set of |capabilities|. Invokes
+ // |callback| with the success flag indicating whether the request
+ // succeeded/failed. If successful, the server and its |capabilities| will
+ // persist until DeleteServer() is called.
void CreateServer(std::unique_ptr<Capabilities> capabilities,
wayland::Server::StartCallback callback);
+
+ // Removes the wayland server with a socket at |path|. This server, along with
+ // its capabilities, will be deleted, and wayland clients will no longer be
+ // able to connect to it.
void DeleteServer(const base::FilePath& path);
private:
diff --git a/chromium/components/exo/shell_surface.cc b/chromium/components/exo/shell_surface.cc
index 32da0d89d05..a5fc1a37c25 100644
--- a/chromium/components/exo/shell_surface.cc
+++ b/chromium/components/exo/shell_surface.cc
@@ -13,10 +13,12 @@
#include "ash/wm/window_state.h"
#include "base/bind.h"
#include "base/logging.h"
+#include "base/strings/string_piece.h"
#include "base/strings/utf_string_conversions.h"
#include "base/trace_event/trace_event.h"
#include "chromeos/ui/base/window_state_type.h"
#include "components/exo/shell_surface_util.h"
+#include "components/exo/window_properties.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/client/cursor_client.h"
#include "ui/aura/env.h"
@@ -154,14 +156,19 @@ void ShellSurface::Maximize() {
TRACE_EVENT0("exo", "ShellSurface::Maximize");
if (!widget_) {
- initial_show_state_ = ui::SHOW_STATE_MAXIMIZED;
+ if (initial_show_state_ != ui::SHOW_STATE_FULLSCREEN ||
+ ShouldExitFullscreenFromRestoreOrMaximized())
+ initial_show_state_ = ui::SHOW_STATE_MAXIMIZED;
return;
}
- // Note: This will ask client to configure its surface even if already
- // maximized.
- ScopedConfigure scoped_configure(this, true);
- widget_->Maximize();
+ if (!widget_->IsFullscreen() ||
+ ShouldExitFullscreenFromRestoreOrMaximized()) {
+ // Note: This will ask client to configure its surface even if already
+ // maximized.
+ ScopedConfigure scoped_configure(this, true);
+ widget_->Maximize();
+ }
}
void ShellSurface::Minimize() {
@@ -182,21 +189,30 @@ void ShellSurface::Restore() {
TRACE_EVENT0("exo", "ShellSurface::Restore");
if (!widget_) {
- initial_show_state_ = ui::SHOW_STATE_NORMAL;
+ if (initial_show_state_ != ui::SHOW_STATE_FULLSCREEN ||
+ ShouldExitFullscreenFromRestoreOrMaximized())
+ initial_show_state_ = ui::SHOW_STATE_NORMAL;
return;
}
- // Note: This will ask client to configure its surface even if not already
- // maximized or minimized.
- ScopedConfigure scoped_configure(this, true);
- widget_->Restore();
+ if (!widget_->IsFullscreen() ||
+ ShouldExitFullscreenFromRestoreOrMaximized()) {
+ // Note: This will ask client to configure its surface even if already
+ // maximized.
+ ScopedConfigure scoped_configure(this, true);
+ widget_->Restore();
+ }
}
void ShellSurface::SetFullscreen(bool fullscreen) {
TRACE_EVENT1("exo", "ShellSurface::SetFullscreen", "fullscreen", fullscreen);
if (!widget_) {
- initial_show_state_ = ui::SHOW_STATE_FULLSCREEN;
+ if (fullscreen) {
+ initial_show_state_ = ui::SHOW_STATE_FULLSCREEN;
+ } else if (initial_show_state_ == ui::SHOW_STATE_FULLSCREEN) {
+ initial_show_state_ = ui::SHOW_STATE_DEFAULT;
+ }
return;
}
@@ -291,12 +307,7 @@ absl::optional<gfx::Rect> ShellSurface::GetWidgetBounds() const {
if (!pending_configs_.empty() || scoped_configure_)
return absl::nullopt;
- gfx::Rect visible_bounds = GetVisibleBounds();
- gfx::Rect new_widget_bounds =
- widget_->non_client_view()
- ? widget_->non_client_view()->GetWindowBoundsForClientBounds(
- visible_bounds)
- : visible_bounds;
+ gfx::Rect new_widget_bounds = GetWidgetBoundsFromVisibleBounds();
if (movement_disabled_) {
new_widget_bounds.set_origin(origin_);
@@ -360,6 +371,11 @@ void ShellSurface::OnWindowBoundsChanged(aura::Window* window,
if (new_bounds.size() == old_bounds.size())
return;
+ if (needs_layout_on_show_) {
+ needs_layout_on_show_ = false;
+ return;
+ }
+
// If size changed then give the client a chance to produce new contents
// before origin on screen is changed. Retain the old origin by reverting
// the origin delta until the next configure is acknowledged.
@@ -476,10 +492,9 @@ bool ShellSurface::OnPreWidgetCommit() {
if (host_window()->bounds().IsEmpty() &&
root_surface()->surface_hierarchy_content_bounds().IsEmpty()) {
Configure();
- // Widget should be created when |initial_show_state_| is minimize and
- // surface doesn not have a contents. TODO(https://crbug.com/1220680)
+
if (initial_show_state_ != ui::SHOW_STATE_MINIMIZED)
- return false;
+ needs_layout_on_show_ = true;
}
CreateShellSurfaceWidget(initial_show_state_);
diff --git a/chromium/components/exo/shell_surface_base.cc b/chromium/components/exo/shell_surface_base.cc
index a068765bad8..55a988fe74c 100644
--- a/chromium/components/exo/shell_surface_base.cc
+++ b/chromium/components/exo/shell_surface_base.cc
@@ -8,12 +8,14 @@
#include "ash/constants/ash_constants.h"
#include "ash/constants/ash_features.h"
+#include "ash/display/screen_orientation_controller.h"
#include "ash/frame/non_client_frame_view_ash.h"
#include "ash/public/cpp/ash_constants.h"
#include "ash/public/cpp/rounded_corner_utils.h"
#include "ash/public/cpp/shelf_types.h"
#include "ash/public/cpp/shell_window_ids.h"
#include "ash/public/cpp/window_properties.h"
+#include "ash/screen_util.h"
#include "ash/shell.h"
#include "ash/shell_delegate.h"
#include "ash/wm/desks/desks_controller.h"
@@ -78,10 +80,6 @@
#include "ui/wm/core/window_animations.h"
#include "ui/wm/core/window_util.h"
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-#include "ash/display/screen_orientation_controller.h"
-#endif // BUILDFLAG(IS_CHROMEOS_ASH)
-
namespace exo {
namespace {
@@ -744,6 +742,14 @@ void ShellSurfaceBase::RebindRootSurface(Surface* root_surface,
container_ = container;
this->root_surface()->RemoveSurfaceObserver(this);
root_surface->AddSurfaceObserver(this);
+ // Reset throttle status of the old root surface and apply the status to the
+ // new root surface.
+ if (widget_ && widget_->GetNativeWindow()) {
+ if (widget_->GetNativeWindow()->GetProperty(ash::kFrameRateThrottleKey)) {
+ this->root_surface()->ThrottleFrameRate(false);
+ root_surface->ThrottleFrameRate(true);
+ }
+ }
SetRootSurface(root_surface);
host_window()->Show();
if (widget_ && widget_->GetNativeWindow() &&
@@ -794,6 +800,7 @@ void ShellSurfaceBase::AddOverlay(OverlayParams&& overlay_params) {
params.activatable = views::Widget::InitParams::Activatable::kYes;
params.delegate = new views::WidgetDelegate();
+ params.delegate->SetOwnedByWidget(true);
params.delegate->SetContentsView(std::move(overlay_params.contents_view));
params.name = "Overlay";
@@ -1110,6 +1117,8 @@ void ShellSurfaceBase::OnWindowDestroying(aura::Window* window) {
if (window == parent_)
SetParentInternal(nullptr);
window->RemoveObserver(this);
+ if (widget_ && window == widget_->GetNativeWindow() && root_surface())
+ root_surface()->ThrottleFrameRate(false);
}
void ShellSurfaceBase::OnWindowPropertyChanged(aura::Window* window,
@@ -1124,6 +1133,9 @@ void ShellSurfaceBase::OnWindowPropertyChanged(aura::Window* window,
window->GetProperty(chromeos::kFrameRestoreLookKey));
} else if (key == aura::client::kWindowWorkspaceKey) {
root_surface()->OnDeskChanged(GetWindowDeskStateChanged(window));
+ } else if (key == ash::kFrameRateThrottleKey) {
+ root_surface()->ThrottleFrameRate(
+ window->GetProperty(ash::kFrameRateThrottleKey));
}
}
}
@@ -1285,15 +1297,6 @@ void ShellSurfaceBase::CreateShellSurfaceWidget(
window->AddObserver(this);
ash::WindowState* window_state = ash::WindowState::Get(window);
InitializeWindowState(window_state);
- // TODO(1261321): correct the initial origin once lacros can communicate
- // it instead of centering.
- if (show_state == ui::SHOW_STATE_MAXIMIZED) {
- gfx::Rect screen_size = display::Screen::GetScreen()
- ->GetDisplayNearestWindow(window)
- .work_area();
- screen_size.ClampToCenteredSize(initial_size_);
- window_state->SetRestoreBoundsInParent(screen_size);
- }
SetShellUseImmersiveForFullscreen(window, immersive_implied_by_fullscreen_);
@@ -1391,7 +1394,8 @@ void ShellSurfaceBase::UpdateSurfaceBounds() {
origin -= ToFlooredVector2d(ScaleVector2d(
root_surface_origin().OffsetFromOrigin(), 1.f / GetScale()));
- host_window()->SetBounds(gfx::Rect(origin, host_window()->bounds().size()));
+ if (host_window()->bounds().origin() != origin)
+ host_window()->SetBounds(gfx::Rect(origin, host_window()->bounds().size()));
}
void ShellSurfaceBase::UpdateShadow() {
@@ -1509,6 +1513,14 @@ gfx::Rect ShellSurfaceBase::GetClientViewBounds() const {
: gfx::Rect(widget_->GetWindowBoundsInScreen().size());
}
+gfx::Rect ShellSurfaceBase::GetWidgetBoundsFromVisibleBounds() const {
+ auto visible_bounds = GetVisibleBounds();
+ return widget_->non_client_view()
+ ? widget_->non_client_view()->GetWindowBoundsForClientBounds(
+ visible_bounds)
+ : visible_bounds;
+}
+
gfx::Rect ShellSurfaceBase::GetShadowBounds() const {
return shadow_bounds_->IsEmpty()
? gfx::Rect(widget_->GetNativeWindow()->bounds().size())
@@ -1536,6 +1548,14 @@ ShellSurfaceBase::CreateNonClientFrameViewInternal(views::Widget* widget) {
return frame_view;
}
+bool ShellSurfaceBase::ShouldExitFullscreenFromRestoreOrMaximized() {
+ if (widget_ && widget_->GetNativeWindow()) {
+ return widget_->GetNativeWindow()->GetProperty(
+ kRestoreOrMaximizeExitsFullscreen);
+ }
+ return false;
+}
+
////////////////////////////////////////////////////////////////////////////////
// ShellSurfaceBase, private:
@@ -1639,11 +1659,42 @@ void ShellSurfaceBase::CommitWidget() {
UpdateSurfaceBounds();
+ // Don't show yet if the shell surface doesn't have content or is minimized
+ // while waiting for content.
+ bool should_show =
+ !host_window()->bounds().IsEmpty() && !widget_->IsMinimized();
+ // Do not layout the window if the position should not be controlled by window
+ // manager. (popup, emulating x11 override direct, or requested not to move)
+ if (is_popup_ || movement_disabled_)
+ needs_layout_on_show_ = false;
+
// Show widget if needed.
- if (pending_show_widget_) {
+ if (pending_show_widget_ && should_show) {
DCHECK(!widget_->IsClosed());
DCHECK(!widget_->IsVisible());
pending_show_widget_ = false;
+
+ auto* window = widget_->GetNativeWindow();
+ auto* window_state = ash::WindowState::Get(window);
+
+ // TODO(crbug.com/1261321): correct the initial origin once lacros can
+ // communicate it instead of centering.
+ if (window_state->IsMaximizedOrFullscreenOrPinned()) {
+ gfx::Size current_content_size = CalculatePreferredSize();
+ gfx::Rect restore_bounds = display::Screen::GetScreen()
+ ->GetDisplayNearestWindow(window)
+ .work_area();
+ if (!current_content_size.IsEmpty())
+ restore_bounds.ClampToCenteredSize(current_content_size);
+
+ window_state->SetRestoreBoundsInScreen(restore_bounds);
+ }
+
+ // TODO(crbug.com/1291592): Hook this up with the WM's window positioning
+ // logic.
+ if (needs_layout_on_show_)
+ widget_->CenterWindow(GetWidgetBoundsFromVisibleBounds().size());
+
widget_->Show();
if (has_grab_)
StartCapture();
diff --git a/chromium/components/exo/shell_surface_base.h b/chromium/components/exo/shell_surface_base.h
index 71db71c32bd..b8ad9995458 100644
--- a/chromium/components/exo/shell_surface_base.h
+++ b/chromium/components/exo/shell_surface_base.h
@@ -309,9 +309,12 @@ class ShellSurfaceBase : public SurfaceTreeHost,
// Returns the "visible bounds" for the surface from the user's perspective.
gfx::Rect GetVisibleBounds() const;
- // Returns the bounds of the client area.nnn
+ // Returns the bounds of the client area.
gfx::Rect GetClientViewBounds() const;
+ // Computes the widget bounds using visible bounds.
+ gfx::Rect GetWidgetBoundsFromVisibleBounds() const;
+
// In the local coordinate system of the window.
virtual gfx::Rect GetShadowBounds() const;
@@ -337,6 +340,10 @@ class ShellSurfaceBase : public SurfaceTreeHost,
// without actually updating it.
bool CalculateCanResize() const;
+ // Returns true if this surface will exit fullscreen from a restore or
+ // maximize request. Currently only true for Lacros.
+ bool ShouldExitFullscreenFromRestoreOrMaximized();
+
views::Widget* widget_ = nullptr;
bool movement_disabled_ = false;
gfx::Point origin_;
@@ -354,6 +361,7 @@ class ShellSurfaceBase : public SurfaceTreeHost,
bool is_popup_ = false;
bool has_grab_ = false;
bool server_side_resize_ = false;
+ bool needs_layout_on_show_ = false;
// The orientation to be applied when widget is being created. Only set when
// widget is not created yet orientation lock is being set. This is currently
diff --git a/chromium/components/exo/shell_surface_unittest.cc b/chromium/components/exo/shell_surface_unittest.cc
index 5e1ceee46ca..138c6e979b1 100644
--- a/chromium/components/exo/shell_surface_unittest.cc
+++ b/chromium/components/exo/shell_surface_unittest.cc
@@ -28,9 +28,11 @@
#include "components/exo/shell_surface_util.h"
#include "components/exo/sub_surface.h"
#include "components/exo/surface.h"
+#include "components/exo/surface_test_util.h"
#include "components/exo/test/exo_test_base.h"
#include "components/exo/test/exo_test_helper.h"
#include "components/exo/test/shell_surface_builder.h"
+#include "components/exo/window_properties.h"
#include "components/exo/wm_helper.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/aura/client/aura_constants.h"
@@ -84,6 +86,16 @@ std::unique_ptr<ShellSurface> CreatePopupShellSurface(
return popup_shell_surface;
}
+std::unique_ptr<ShellSurface> CreateX11TransientShellSurface(
+ ShellSurface* parent,
+ const gfx::Size& size,
+ const gfx::Point& origin) {
+ return test::ShellSurfaceBuilder(size)
+ .SetParent(parent)
+ .SetOrigin(origin)
+ .BuildShellSurface();
+}
+
TEST_F(ShellSurfaceTest, AcknowledgeConfigure) {
gfx::Size buffer_size(32, 32);
std::unique_ptr<Buffer> buffer(
@@ -252,6 +264,44 @@ TEST_F(ShellSurfaceTest, CannotMaximizeNonResizableWindow) {
EXPECT_FALSE(shell_surface->CanMaximize());
}
+TEST_F(ShellSurfaceTest, MaximizeFromFullscreen) {
+ std::unique_ptr<ShellSurface> shell_surface =
+ test::ShellSurfaceBuilder({256, 256})
+ .SetMaximumSize(gfx::Size(10, 10))
+ .BuildShellSurface();
+ // Act: Maximize after fullscreen
+ shell_surface->root_surface()->Commit();
+ shell_surface->SetFullscreen(true);
+ shell_surface->root_surface()->Commit();
+ shell_surface->Maximize();
+ shell_surface->root_surface()->Commit();
+
+ // Assert: Window should stay fullscreen.
+ EXPECT_TRUE(shell_surface->GetWidget()->IsFullscreen());
+}
+
+TEST_F(ShellSurfaceTest, MaximizeExitsFullscreen) {
+ std::unique_ptr<ShellSurface> shell_surface =
+ test::ShellSurfaceBuilder({256, 256})
+ .SetMaximumSize(gfx::Size(10, 10))
+ .BuildShellSurface();
+
+ // Act: Set window property kRestoreOrMaximizeExitsFullscreen
+ // then maximize after fullscreen
+ shell_surface->root_surface()->Commit();
+ shell_surface->GetWidget()->GetNativeWindow()->SetProperty(
+ kRestoreOrMaximizeExitsFullscreen, true);
+ shell_surface->SetFullscreen(true);
+ shell_surface->root_surface()->Commit();
+ shell_surface->Maximize();
+ shell_surface->root_surface()->Commit();
+
+ // Assert: Window should exit fullscreen and be maximized.
+ EXPECT_TRUE(shell_surface->GetWidget()->GetNativeWindow()->GetProperty(
+ kRestoreOrMaximizeExitsFullscreen));
+ EXPECT_TRUE(shell_surface->GetWidget()->IsMaximized());
+}
+
TEST_F(ShellSurfaceTest, Minimize) {
gfx::Size buffer_size(256, 256);
std::unique_ptr<Buffer> buffer(
@@ -305,6 +355,44 @@ TEST_F(ShellSurfaceTest, Restore) {
shell_surface->GetWidget()->GetWindowBoundsInScreen().size().ToString());
}
+TEST_F(ShellSurfaceTest, RestoreFromFullscreen) {
+ std::unique_ptr<ShellSurface> shell_surface =
+ test::ShellSurfaceBuilder({256, 256})
+ .SetMaximumSize(gfx::Size(10, 10))
+ .BuildShellSurface();
+
+ // Act: Restore after fullscreen
+ shell_surface->SetFullscreen(true);
+ shell_surface->root_surface()->Commit();
+ shell_surface->Restore();
+ shell_surface->root_surface()->Commit();
+
+ // Assert: Window should stay fullscreen.
+ EXPECT_TRUE(shell_surface->GetWidget()->IsFullscreen());
+}
+
+TEST_F(ShellSurfaceTest, RestoreExitsFullscreen) {
+ std::unique_ptr<ShellSurface> shell_surface =
+ test::ShellSurfaceBuilder({256, 256})
+ .SetMaximumSize(gfx::Size(10, 10))
+ .BuildShellSurface();
+
+ // Act: Set window property kRestoreOrMaximizeExitsFullscreen
+ // then restore after fullscreen
+ shell_surface->root_surface()->Commit();
+ shell_surface->GetWidget()->GetNativeWindow()->SetProperty(
+ kRestoreOrMaximizeExitsFullscreen, true);
+ shell_surface->SetFullscreen(true);
+ shell_surface->Restore();
+ shell_surface->root_surface()->Commit();
+
+ // Assert: Window should exit fullscreen and be restored.
+ EXPECT_TRUE(shell_surface->GetWidget()->GetNativeWindow()->GetProperty(
+ kRestoreOrMaximizeExitsFullscreen));
+ EXPECT_EQ(gfx::Size(256, 256),
+ shell_surface->GetWidget()->GetWindowBoundsInScreen().size());
+}
+
TEST_F(ShellSurfaceTest, HostWindowBoundsUpdatedAfterCommitWidget) {
gfx::Size buffer_size(256, 256);
std::unique_ptr<Buffer> buffer(
@@ -345,6 +433,33 @@ TEST_F(ShellSurfaceTest, SetFullscreen) {
shell_surface->GetWidget()->GetWindowBoundsInScreen().ToString());
}
+TEST_F(ShellSurfaceTest, PreWidgetUnfullscreen) {
+ std::unique_ptr<ShellSurface> shell_surface =
+ test::ShellSurfaceBuilder({256, 256})
+ .SetNoCommit()
+ .SetMaximumSize(gfx::Size(10, 10))
+ .BuildShellSurface();
+ shell_surface->Maximize();
+ shell_surface->SetFullscreen(false);
+ EXPECT_EQ(shell_surface->GetWidget(), nullptr);
+ shell_surface->root_surface()->Commit();
+ EXPECT_TRUE(shell_surface->GetWidget()->IsMaximized());
+}
+
+TEST_F(ShellSurfaceTest, PreWidgetMaximizeFromFullscreen) {
+ std::unique_ptr<ShellSurface> shell_surface =
+ test::ShellSurfaceBuilder({256, 256})
+ .SetNoCommit()
+ .SetMaximumSize(gfx::Size(10, 10))
+ .BuildShellSurface();
+ // Fullscreen -> Maximize for non Lacros surfaces should stay fullscreen
+ shell_surface->SetFullscreen(true);
+ shell_surface->Maximize();
+ EXPECT_EQ(shell_surface->GetWidget(), nullptr);
+ shell_surface->root_surface()->Commit();
+ EXPECT_TRUE(shell_surface->GetWidget()->IsFullscreen());
+}
+
TEST_F(ShellSurfaceTest, SetTitle) {
gfx::Size buffer_size(256, 256);
std::unique_ptr<Buffer> buffer(
@@ -783,17 +898,21 @@ TEST_F(ShellSurfaceTest, ConfigureCallback) {
// suggested size as a mechanisms to ask the client size itself.
surface->Commit();
EXPECT_TRUE(suggested_size.IsEmpty());
+ EXPECT_TRUE(shell_surface->GetWidget());
+ EXPECT_FALSE(shell_surface->GetWidget()->IsVisible());
+ EXPECT_EQ(geometry.size(), shell_surface->CalculatePreferredSize());
- // Geometry should not be committed until surface has contents.
- EXPECT_TRUE(shell_surface->CalculatePreferredSize().IsEmpty());
+ gfx::Rect maximized_bounds =
+ display::Screen::GetScreen()->GetPrimaryDisplay().work_area();
- // Widget creation is deferred until the surface has contents.
+ // State change should be sent even if the content is not attached.
+ // See crbug.com/1138978.
shell_surface->Maximize();
shell_surface->AcknowledgeConfigure(0);
- EXPECT_FALSE(shell_surface->GetWidget());
- EXPECT_TRUE(suggested_size.IsEmpty());
- EXPECT_EQ(chromeos::WindowStateType::kNormal, has_state_type);
+ EXPECT_FALSE(suggested_size.IsEmpty());
+ EXPECT_EQ(maximized_bounds.size(), suggested_size);
+ EXPECT_EQ(chromeos::WindowStateType::kMaximized, has_state_type);
gfx::Size buffer_size(64, 64);
std::unique_ptr<Buffer> buffer(
@@ -801,8 +920,6 @@ TEST_F(ShellSurfaceTest, ConfigureCallback) {
surface->Attach(buffer.get());
surface->Commit();
- gfx::Rect maximized_bounds =
- display::Screen::GetScreen()->GetPrimaryDisplay().work_area();
EXPECT_TRUE(shell_surface->GetWidget());
EXPECT_EQ(maximized_bounds.size(), suggested_size);
EXPECT_EQ(chromeos::WindowStateType::kMaximized, has_state_type);
@@ -851,25 +968,118 @@ TEST_F(ShellSurfaceTest, CreateMinimizedWindow) {
gfx::Rect geometry(0, 0, 1, 1);
shell_surface->SetGeometry(geometry);
-
+ shell_surface->Minimize();
+ shell_surface->AcknowledgeConfigure(0);
// Commit without contents should result in a configure callback with empty
// suggested size as a mechanisms to ask the client size itself.
surface->Commit();
+
+ EXPECT_TRUE(shell_surface->GetWidget());
+ EXPECT_TRUE(shell_surface->GetWidget()->IsMinimized());
EXPECT_TRUE(suggested_size.IsEmpty());
+ EXPECT_EQ(geometry.size(), shell_surface->CalculatePreferredSize());
+}
- // Geometry should not be committed until surface has contents.
- EXPECT_TRUE(shell_surface->CalculatePreferredSize().IsEmpty());
+TEST_F(ShellSurfaceTest, CreateMinimizedWindow2) {
+ // Must be before shell_surface so it outlives it, for shell_surface's
+ // destructor calls Configure() referencing these 4 variables.
+ gfx::Size suggested_size;
+ auto has_state_type = chromeos::WindowStateType::kNormal;
+ bool is_resizing = false;
+ bool is_active = false;
+
+ std::unique_ptr<Surface> surface(new Surface);
+ std::unique_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get()));
+
+ shell_surface->set_configure_callback(base::BindRepeating(
+ &Configure, base::Unretained(&suggested_size),
+ base::Unretained(&has_state_type), base::Unretained(&is_resizing),
+ base::Unretained(&is_active)));
+
+ gfx::Rect geometry(0, 0, 1, 1);
+ shell_surface->SetGeometry(geometry);
+
+ // Commit without contents should result in a configure callback with empty
+ // suggested size as a mechanisms to ask the client size itself.
+ surface->Commit();
+ EXPECT_TRUE(suggested_size.IsEmpty());
+ EXPECT_TRUE(shell_surface->GetWidget());
+ EXPECT_FALSE(shell_surface->GetWidget()->IsVisible());
+ EXPECT_EQ(geometry.size(), shell_surface->CalculatePreferredSize());
shell_surface->Minimize();
shell_surface->AcknowledgeConfigure(0);
+
// Commit without contents should result in a configure callback with empty
// suggested size as a mechanisms to ask the client size itself.
surface->Commit();
EXPECT_TRUE(shell_surface->GetWidget());
EXPECT_TRUE(shell_surface->GetWidget()->IsMinimized());
- EXPECT_TRUE(suggested_size.IsEmpty());
EXPECT_EQ(geometry.size(), shell_surface->CalculatePreferredSize());
+
+ // Once the initial empty size is sent in configure,
+ // new configure should send the size requested.
+ EXPECT_EQ(geometry.size(), suggested_size);
+}
+
+TEST_F(ShellSurfaceTest,
+ CreateMaximizedWindowWithRestoreBoundsWithoutInitialBuffer) {
+ // Must be before shell_surface so it outlives it, for shell_surface's
+ // destructor calls Configure() referencing these 4 variables.
+ gfx::Size suggested_size;
+ chromeos::WindowStateType has_state_type = chromeos::WindowStateType::kNormal;
+ bool is_resizing = false;
+ bool is_active = false;
+ gfx::Size buffer_size(256, 256);
+
+ std::unique_ptr<ShellSurface> shell_surface =
+ test::ShellSurfaceBuilder(buffer_size)
+ .SetNoRootBuffer()
+ .BuildShellSurface();
+
+ shell_surface->set_configure_callback(base::BindRepeating(
+ &Configure, base::Unretained(&suggested_size),
+ base::Unretained(&has_state_type), base::Unretained(&is_resizing),
+ base::Unretained(&is_active)));
+
+ Surface* root_surface = shell_surface->surface_for_testing();
+ root_surface->Commit();
+ shell_surface->AcknowledgeConfigure(0);
+
+ // Ash may maximize the window.
+ EXPECT_TRUE(shell_surface->GetWidget());
+ EXPECT_FALSE(shell_surface->GetWidget()->IsVisible());
+ EXPECT_FALSE(shell_surface->GetWidget()->IsMaximized());
+
+ shell_surface->Maximize();
+ shell_surface->AcknowledgeConfigure(0);
+
+ EXPECT_FALSE(shell_surface->GetWidget()->IsVisible());
+ EXPECT_TRUE(shell_surface->GetWidget()->IsMaximized());
+
+ auto buffer = std::make_unique<Buffer>(
+ exo_test_helper()->CreateGpuMemoryBuffer(buffer_size));
+ root_surface->Attach(buffer.get());
+
+ gfx::Rect geometry_full(buffer_size);
+ shell_surface->SetGeometry(geometry_full);
+
+ // Commit without contents should result in a configure callback with empty
+ // suggested size as a mechanisms to ask the client size itself.
+ root_surface->Commit();
+ shell_surface->AcknowledgeConfigure(0);
+
+ EXPECT_TRUE(shell_surface->GetWidget()->IsVisible());
+ EXPECT_TRUE(shell_surface->GetWidget()->IsMaximized());
+
+ auto* window_state =
+ ash::WindowState::Get(shell_surface->GetWidget()->GetNativeWindow());
+
+ EXPECT_TRUE(window_state->HasRestoreBounds());
+
+ auto bounds = window_state->GetRestoreBoundsInParent();
+ EXPECT_EQ(geometry_full.size(), bounds.size());
}
TEST_F(ShellSurfaceTest, CreateMaximizedWindowWithRestoreBounds) {
@@ -1079,6 +1289,17 @@ TEST_F(ShellSurfaceTest, Transient) {
EXPECT_TRUE(child_window->IsVisible());
}
+TEST_F(ShellSurfaceTest, X11Transient) {
+ auto parent = test::ShellSurfaceBuilder({256, 256}).BuildShellSurface();
+
+ gfx::Point origin(50, 50);
+
+ auto transient =
+ CreateX11TransientShellSurface(parent.get(), gfx::Size(100, 100), origin);
+ EXPECT_TRUE(transient->GetWidget()->movement_disabled());
+ EXPECT_EQ(transient->GetWidget()->GetWindowBoundsInScreen().origin(), origin);
+}
+
TEST_F(ShellSurfaceTest, Popup) {
gfx::Size buffer_size(256, 256);
std::unique_ptr<Buffer> buffer(
@@ -1254,6 +1475,43 @@ TEST_F(ShellSurfaceTest, PopupWithInputRegion) {
}
}
+TEST_F(ShellSurfaceTest, PopupWithInvisibleParent) {
+ // Invisible main window.
+ std::unique_ptr<ShellSurface> root_shell_surface =
+ test::ShellSurfaceBuilder({256, 256})
+ .SetNoRootBuffer()
+ .BuildShellSurface();
+ EXPECT_FALSE(root_shell_surface->GetWidget()->IsVisible());
+
+ std::unique_ptr<ShellSurface> popup_shell_surface_1 =
+ test::ShellSurfaceBuilder({256, 256})
+ .SetNoRootBuffer()
+ .SetAsPopup()
+ .SetDisableMovement()
+ .SetParent(root_shell_surface.get())
+ .BuildShellSurface();
+
+ EXPECT_EQ(root_shell_surface->GetWidget()->GetNativeWindow(),
+ wm::GetTransientParent(
+ popup_shell_surface_1->GetWidget()->GetNativeWindow()));
+
+ EXPECT_FALSE(popup_shell_surface_1->GetWidget()->IsVisible());
+
+ // Create visible popup.
+ std::unique_ptr<ShellSurface> popup_shell_surface_2 =
+ test::ShellSurfaceBuilder({256, 256})
+ .SetAsPopup()
+ .SetDisableMovement()
+ .SetParent(popup_shell_surface_1.get())
+ .BuildShellSurface();
+
+ EXPECT_TRUE(popup_shell_surface_2->GetWidget()->IsVisible());
+
+ EXPECT_EQ(popup_shell_surface_1->GetWidget()->GetNativeWindow(),
+ wm::GetTransientParent(
+ popup_shell_surface_2->GetWidget()->GetNativeWindow()));
+}
+
TEST_F(ShellSurfaceTest, Caption) {
gfx::Size buffer_size(256, 256);
auto buffer = std::make_unique<Buffer>(
@@ -1882,4 +2140,76 @@ TEST_F(ShellSurfaceTest, Reparent) {
EXPECT_TRUE(widget2->ShouldPaintAsActive());
}
+TEST_F(ShellSurfaceTest, ThrottleFrameRate) {
+ auto shell_surface = test::ShellSurfaceBuilder({20, 20}).BuildShellSurface();
+ SurfaceObserverForTest observer;
+ shell_surface->root_surface()->AddSurfaceObserver(&observer);
+ aura::Window* window = shell_surface->GetWidget()->GetNativeWindow();
+
+ EXPECT_CALL(observer, ThrottleFrameRate(true));
+ window->SetProperty(ash::kFrameRateThrottleKey, true);
+
+ EXPECT_CALL(observer, ThrottleFrameRate(false));
+ window->SetProperty(ash::kFrameRateThrottleKey, false);
+
+ shell_surface->root_surface()->RemoveSurfaceObserver(&observer);
+}
+
+namespace {
+
+struct ShellSurfaceCallbacks {
+ struct ConfigureState {
+ gfx::Size bounds;
+ chromeos::WindowStateType state_type;
+ bool resizing;
+ bool activated;
+ };
+
+ uint32_t OnConfigure(const gfx::Size& size,
+ chromeos::WindowStateType state_type,
+ bool resizing,
+ bool activated,
+ const gfx::Vector2d& origin_offset) {
+ configure_state.emplace();
+ *configure_state = {size, state_type, resizing, activated};
+ return serial++;
+ }
+ void OnOriginChange(const gfx::Point& origin_) { origin = origin_; }
+ void Reset() {
+ configure_state.reset();
+ origin.reset();
+ }
+ absl::optional<ConfigureState> configure_state;
+ absl::optional<gfx::Point> origin;
+ int32_t serial = 1;
+};
+
+} // namespace
+
+// Make sure that the centering logic can use the correct size
+// even if there is a pending configure.
+TEST_F(ShellSurfaceTest, InitialCenteredBoundsWithConfigure) {
+ auto shell_surface = test::ShellSurfaceBuilder(gfx::Size(0, 0))
+ .SetNoRootBuffer()
+ .SetNoCommit()
+ .BuildShellSurface();
+ ShellSurfaceCallbacks callbacks;
+ shell_surface->set_configure_callback(base::BindRepeating(
+ &ShellSurfaceCallbacks::OnConfigure, base::Unretained(&callbacks)));
+ shell_surface->root_surface()->Commit();
+ EXPECT_FALSE(shell_surface->GetWidget()->IsVisible());
+
+ gfx::Size size(256, 256);
+ auto new_buffer =
+ std::make_unique<Buffer>(exo_test_helper()->CreateGpuMemoryBuffer(size));
+ shell_surface->root_surface()->Attach(new_buffer.get());
+ shell_surface->root_surface()->Commit();
+ EXPECT_TRUE(shell_surface->GetWidget()->IsVisible());
+
+ gfx::Rect expected =
+ display::Screen::GetScreen()->GetPrimaryDisplay().work_area();
+ expected.ClampToCenteredSize(size);
+ EXPECT_EQ(expected, shell_surface->GetWidget()->GetWindowBoundsInScreen());
+}
+
} // namespace exo
diff --git a/chromium/components/exo/sub_surface_unittest.cc b/chromium/components/exo/sub_surface_unittest.cc
index b790b6eab5e..e8b7e838e04 100644
--- a/chromium/components/exo/sub_surface_unittest.cc
+++ b/chromium/components/exo/sub_surface_unittest.cc
@@ -115,6 +115,45 @@ TEST_F(SubSurfaceTest, PlaceBelow) {
EXPECT_EQ(surface1->window(), parent->window()->children()[1]);
}
+TEST_F(SubSurfaceTest, ParentDamageOnReorder) {
+ auto surface_tree_host = std::make_unique<SurfaceTreeHost>("SubSurfaceTest");
+ LayerTreeFrameSinkHolder* frame_sink_holder =
+ surface_tree_host->layer_tree_frame_sink_holder();
+
+ auto parent = std::make_unique<Surface>();
+ parent->SetViewport({800.f, 600.f});
+ auto surface1 = std::make_unique<Surface>();
+ auto surface2 = std::make_unique<Surface>();
+ auto non_sibling_surface = std::make_unique<Surface>();
+ auto sub_surface1 =
+ std::make_unique<SubSurface>(surface1.get(), parent.get());
+ auto sub_surface2 =
+ std::make_unique<SubSurface>(surface2.get(), parent.get());
+
+ sub_surface2->PlaceBelow(surface1.get());
+ parent->Commit();
+
+ viz::CompositorFrame frame1;
+ frame1.render_pass_list.push_back(viz::CompositorRenderPass::Create());
+ parent->AppendSurfaceHierarchyContentsToFrame(
+ gfx::PointF{}, 1, frame_sink_holder->resource_manager(), &frame1);
+
+ // Parent surface damage is extended when sub_surface stacking order changes.
+ EXPECT_FALSE(frame1.render_pass_list.back()->damage_rect.IsEmpty());
+
+ sub_surface1->PlaceAbove(surface2.get()); // no-op
+ sub_surface2->PlaceBelow(surface1.get()); // no-op
+ parent->Commit();
+
+ viz::CompositorFrame frame2;
+ frame2.render_pass_list.push_back(viz::CompositorRenderPass::Create());
+ parent->AppendSurfaceHierarchyContentsToFrame(
+ gfx::PointF{}, 1, frame_sink_holder->resource_manager(), &frame2);
+
+ // Parent surface damage is unaffected.
+ EXPECT_TRUE(frame2.render_pass_list.back()->damage_rect.IsEmpty());
+}
+
TEST_F(SubSurfaceTest, SetCommitBehavior) {
auto parent = std::make_unique<Surface>();
auto shell_surface = std::make_unique<ShellSurface>(parent.get());
diff --git a/chromium/components/exo/surface.cc b/chromium/components/exo/surface.cc
index b3e3f879ee7..9dd9d9f3885 100644
--- a/chromium/components/exo/surface.cc
+++ b/chromium/components/exo/surface.cc
@@ -23,6 +23,7 @@
#include "components/exo/shell_surface_util.h"
#include "components/exo/surface_delegate.h"
#include "components/exo/surface_observer.h"
+#include "components/exo/window_properties.h"
#include "components/exo/wm_helper.h"
#include "components/viz/common/quads/compositor_render_pass.h"
#include "components/viz/common/quads/shared_quad_state.h"
@@ -30,6 +31,7 @@
#include "components/viz/common/quads/surface_draw_quad.h"
#include "components/viz/common/quads/texture_draw_quad.h"
#include "components/viz/common/resources/resource_id.h"
+#include "media/media_buildflags.h"
#include "third_party/khronos/GLES2/gl2.h"
#include "third_party/skia/include/core/SkColor.h"
#include "third_party/skia/include/core/SkPath.h"
@@ -47,6 +49,7 @@
#include "ui/display/screen.h"
#include "ui/events/event.h"
#include "ui/gfx/buffer_format_util.h"
+#include "ui/gfx/buffer_types.h"
#include "ui/gfx/geometry/dip_util.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/point_conversions.h"
@@ -306,7 +309,7 @@ Surface::~Surface() {
ImmediateExplicitRelease(
std::move(cached_state_.per_commit_explicit_release_callback_));
- WMHelper::GetInstance()->ResetDragDropDelegate(window_.get());
+ // Do not reset the DragDropDelegate in order to handle exit upon deletion.
}
// static
@@ -324,8 +327,10 @@ void Surface::Attach(Buffer* buffer, gfx::Vector2d offset) {
buffer ? static_cast<const void*>(buffer->gfx_buffer()) : nullptr,
"app_id", GetApplicationId(window_.get()));
has_pending_contents_ = true;
- pending_state_.buffer.Reset(buffer ? buffer->AsWeakPtr()
- : base::WeakPtr<Buffer>());
+ if (!pending_state_.buffer.has_value())
+ pending_state_.buffer.emplace();
+ pending_state_.buffer->Reset(buffer ? buffer->AsWeakPtr()
+ : base::WeakPtr<Buffer>());
pending_state_.basic_state.offset = offset;
}
@@ -334,7 +339,8 @@ gfx::Vector2d Surface::GetBufferOffset() {
}
bool Surface::HasPendingAttachedBuffer() const {
- return pending_state_.buffer.buffer() != nullptr;
+ return pending_state_.buffer.has_value() &&
+ pending_state_.buffer->buffer() != nullptr;
}
void Surface::Damage(const gfx::Rect& damage) {
@@ -499,8 +505,8 @@ void Surface::PlaceSubSurfaceBelow(Surface* sub_surface, Surface* sibling) {
return;
}
- auto sibling_it = FindListEntry(pending_sub_surfaces_, sibling);
- if (sibling_it == pending_sub_surfaces_.end()) {
+ auto position_it = FindListEntry(pending_sub_surfaces_, sibling);
+ if (position_it == pending_sub_surfaces_.end()) {
DLOG(WARNING) << "Client tried to place sub-surface below a surface that "
"is not a sibling";
return;
@@ -508,9 +514,12 @@ void Surface::PlaceSubSurfaceBelow(Surface* sub_surface, Surface* sibling) {
DCHECK(ListContainsEntry(pending_sub_surfaces_, sub_surface));
auto it = FindListEntry(pending_sub_surfaces_, sub_surface);
- if (it == sibling_it)
+
+ // If |sub_surface| is already immediately below |sibling|, do not do
+ // anything.
+ if (it == --position_it)
return;
- pending_sub_surfaces_.splice(sibling_it, pending_sub_surfaces_, it);
+ pending_sub_surfaces_.splice(++position_it, pending_sub_surfaces_, it);
sub_surfaces_changed_ = true;
}
@@ -721,10 +730,10 @@ void Surface::SetEmbeddedSurfaceSize(const gfx::Size& size) {
}
void Surface::SetAcquireFence(std::unique_ptr<gfx::GpuFence> gpu_fence) {
-#if defined(OS_POSIX)
+#if BUILDFLAG(IS_POSIX)
TRACE_EVENT1("exo", "Surface::SetAcquireFence", "fence_fd",
gpu_fence ? gpu_fence->GetGpuFenceHandle().owned_fd.get() : -1);
-#endif // defined(OS_POSIX)
+#endif // BUILDFLAG(IS_POSIX)
pending_state_.acquire_fence = std::move(gpu_fence);
}
@@ -745,11 +754,12 @@ bool Surface::HasPendingPerCommitBufferReleaseCallback() const {
}
void Surface::Commit() {
- TRACE_EVENT1("exo", "Surface::Commit", "buffer_id",
- static_cast<const void*>(
- pending_state_.buffer.buffer()
- ? pending_state_.buffer.buffer()->gfx_buffer()
- : nullptr));
+ TRACE_EVENT1(
+ "exo", "Surface::Commit", "buffer_id",
+ static_cast<const void*>(
+ pending_state_.buffer.has_value() && pending_state_.buffer->buffer()
+ ? pending_state_.buffer->buffer()->gfx_buffer()
+ : nullptr));
for (auto& observer : observers_)
observer.OnCommit(this);
@@ -761,9 +771,11 @@ void Surface::Commit() {
pending_state_.basic_state.only_visible_on_secure_output = false;
has_cached_contents_ |= has_pending_contents_;
has_pending_contents_ = false;
- cached_state_.buffer = std::move(pending_state_.buffer);
- cached_state_.rounded_corners_bounds =
- std::move(pending_state_.rounded_corners_bounds);
+ if (pending_state_.buffer.has_value()) {
+ cached_state_.buffer = std::move(pending_state_.buffer);
+ pending_state_.buffer.reset();
+ }
+ cached_state_.rounded_corners_bounds = pending_state_.rounded_corners_bounds;
cached_state_.overlay_priority_hint = pending_state_.overlay_priority_hint;
cached_state_.acquire_fence = std::move(pending_state_.acquire_fence);
cached_state_.per_commit_explicit_release_callback_ =
@@ -798,6 +810,11 @@ bool Surface::UpdateDisplay(int64_t old_display, int64_t new_display) {
if (!sub_surface->UpdateDisplay(old_display, new_display))
return false;
}
+
+ for (auto& observer : observers_) {
+ observer.OnDisplayChanged(this, old_display, new_display);
+ }
+
return true;
}
@@ -885,16 +902,20 @@ void Surface::CommitSurfaceHierarchy(bool synchronized) {
if (has_cached_contents_) {
has_cached_contents_ = false;
- bool current_invert_y =
- state_.buffer.buffer() && state_.buffer.buffer()->y_invert();
- cached_invert_y = cached_state_.buffer.buffer() &&
- cached_state_.buffer.buffer()->y_invert();
+ bool current_invert_y = state_.buffer.has_value() &&
+ state_.buffer->buffer() &&
+ state_.buffer->buffer()->y_invert();
+ cached_invert_y = cached_state_.buffer.has_value() &&
+ cached_state_.buffer->buffer() &&
+ cached_state_.buffer->buffer()->y_invert();
if (current_invert_y != cached_invert_y)
needs_update_buffer_transform = true;
- state_.buffer = std::move(cached_state_.buffer);
- state_.rounded_corners_bounds =
- std::move(cached_state_.rounded_corners_bounds);
+ if (cached_state_.buffer.has_value()) {
+ state_.buffer = std::move(cached_state_.buffer);
+ cached_state_.buffer.reset();
+ }
+ state_.rounded_corners_bounds = cached_state_.rounded_corners_bounds;
state_.overlay_priority_hint = cached_state_.overlay_priority_hint;
state_.acquire_fence = std::move(cached_state_.acquire_fence);
state_.per_commit_explicit_release_callback_ =
@@ -1137,16 +1158,16 @@ bool Surface::State::operator==(const State& other) const {
other.blend_mode == blend_mode && other.alpha == alpha;
}
-Surface::BufferAttachment::BufferAttachment() {}
+Surface::BufferAttachment::BufferAttachment() = default;
Surface::BufferAttachment::~BufferAttachment() {
if (buffer_)
buffer_->OnDetach();
}
-Surface::ExtendedState::ExtendedState() = default;
-
-Surface::ExtendedState::~ExtendedState() = default;
+Surface::BufferAttachment::BufferAttachment(BufferAttachment&& other) {
+ *this = std::move(other);
+}
Surface::BufferAttachment& Surface::BufferAttachment::operator=(
BufferAttachment&& other) {
@@ -1182,32 +1203,34 @@ void Surface::BufferAttachment::Reset(base::WeakPtr<Buffer> buffer) {
buffer_ = buffer;
}
+Surface::ExtendedState::ExtendedState() = default;
+
+Surface::ExtendedState::~ExtendedState() = default;
+
void Surface::UpdateResource(FrameSinkResourceManager* resource_manager) {
DCHECK(needs_update_resource_);
needs_update_resource_ = false;
- if (state_.buffer.buffer()) {
- if (state_.buffer.buffer()->ProduceTransferableResource(
+ if (state_.buffer.has_value() && state_.buffer->buffer()) {
+ if (state_.buffer->buffer()->ProduceTransferableResource(
resource_manager, std::move(state_.acquire_fence),
state_.basic_state.only_visible_on_secure_output,
&current_resource_,
+ window_->GetToplevelWindow()->GetProperty(
+ kProtectedNativePixmapQueryDelegate),
std::move(state_.per_commit_explicit_release_callback_))) {
current_resource_has_alpha_ =
- FormatHasAlpha(state_.buffer.buffer()->GetFormat());
- // Planar buffers are sampled as RGB. Technically, the driver is supposed
- // to preserve the colorspace, so we could still pass the primaries and
- // transfer function. However, we don't actually pass the colorspace
- // to the driver, and it's unclear what drivers would actually do if we
- // did. So in effect, the colorspace is undefined.
- if (NumberOfPlanesForLinearBufferFormat(
- state_.buffer.buffer()->GetFormat()) > 1) {
+ FormatHasAlpha(state_.buffer->buffer()->GetFormat());
+ // Setting colors for YUV buffers has been problematic in the past. See
+ // crrev.com/c/2331769
+ if (state_.buffer->buffer()->GetFormat() != gfx::BufferFormat::YVU_420)
current_resource_.color_space = state_.basic_state.color_space;
- }
} else {
current_resource_.id = viz::kInvalidResourceId;
// Use the buffer's size, so the AppendContentsToFrame() will append
// a SolidColorDrawQuad with the buffer's size.
- current_resource_.size = state_.buffer.size();
- current_resource_has_alpha_ = false;
+ current_resource_.size = state_.buffer->size();
+ SkColor color = state_.buffer->buffer()->GetColor().toSkColor();
+ current_resource_has_alpha_ = SkColorGetA(color) != SK_AlphaOPAQUE;
}
} else {
current_resource_.id = viz::kInvalidResourceId;
@@ -1454,6 +1477,14 @@ void Surface::AppendContentsToFrame(const gfx::PointF& origin,
break;
}
+#if BUILDFLAG(USE_ARC_PROTECTED_MEDIA)
+ if (state_.basic_state.only_visible_on_secure_output &&
+ state_.buffer.has_value() && state_.buffer->buffer() &&
+ state_.buffer->buffer()->NeedsHardwareProtection()) {
+ texture_quad->protected_video_type =
+ gfx::ProtectedVideoType::kHardwareProtected;
+ }
+#endif // BUILDFLAG(USE_ARC_PROTECTED_MEDIA)
frame->resource_list.push_back(current_resource_);
if (!damage_rect.IsEmpty()) {
@@ -1463,8 +1494,8 @@ void Surface::AppendContentsToFrame(const gfx::PointF& origin,
damage_rect = gfx::RectF();
}
}
- } else if (state_.buffer.buffer()) {
- SkColor color = state_.buffer.buffer()->GetColor().toSkColor();
+ } else if (state_.buffer.has_value() && state_.buffer->buffer()) {
+ SkColor color = state_.buffer->buffer()->GetColor().toSkColor();
viz::SolidColorDrawQuad* solid_quad =
render_pass->CreateAndAppendDrawQuad<viz::SolidColorDrawQuad>();
solid_quad->SetNew(quad_state, quad_rect, quad_rect, color,
@@ -1493,8 +1524,9 @@ void Surface::UpdateContentSize() {
content_size = state_.basic_state.crop.size();
} else {
content_size = gfx::ScaleSize(
- gfx::SizeF(ToTransformedSize(state_.buffer.size(),
- state_.basic_state.buffer_transform)),
+ gfx::SizeF(ToTransformedSize(
+ state_.buffer.has_value() ? state_.buffer->size() : gfx::Size(),
+ state_.basic_state.buffer_transform)),
1.0f / state_.basic_state.buffer_scale);
}
@@ -1564,4 +1596,9 @@ void Surface::Unpin() {
delegate_->Unpin();
}
+void Surface::ThrottleFrameRate(bool on) {
+ for (SurfaceObserver& observer : observers_)
+ observer.ThrottleFrameRate(on);
+}
+
} // namespace exo
diff --git a/chromium/components/exo/surface.h b/chromium/components/exo/surface.h
index 614d645c004..63d711a1718 100644
--- a/chromium/components/exo/surface.h
+++ b/chromium/components/exo/surface.h
@@ -403,6 +403,9 @@ class Surface final : public ui::PropertyHandler {
// Release the pinned mode and allows the user to do other things again.
void Unpin();
+ // Starts or ends throttling on the surface.
+ void ThrottleFrameRate(bool on);
+
private:
struct State {
State();
@@ -434,6 +437,7 @@ class Surface final : public ui::PropertyHandler {
~BufferAttachment();
+ BufferAttachment(BufferAttachment&& buffer);
BufferAttachment& operator=(BufferAttachment&& buffer);
base::WeakPtr<Buffer>& buffer();
@@ -446,6 +450,23 @@ class Surface final : public ui::PropertyHandler {
gfx::Size size_;
};
+ // State for this surface. State is committed in a three step process:
+ // 1. Pending state is accummulated into before commit.
+ // 2. On commit, state is copied to a cached state. This is to support
+ // synchronized commit of a tree of surfaces. When the tree of surfaces is
+ // set to be synchronized, the state of the tree will not be committed
+ // until the root of the tree (precisely, until a unsynchronized root of a
+ // subtree) is committed.
+ // 3. State is committed.
+ // Some fields are persisted between commits (e.g. which buffer is attached),
+ // and some fields are not (e.g. acquire fence). For fields that are
+ // persisted, they either need to be copyable, or if they are move only, they
+ // need to be wrapped in absl::optional and only copied on commit if they
+ // have been changed. Not doing this can lead to broken behaviour, such as
+ // losing the attached buffer if some unrelated field is updated in a commit.
+ // If you add new fields to this struct, please document whether the field
+ // should be persisted between commits.
+ // See crbug.com/1283305 for context.
struct ExtendedState {
ExtendedState();
~ExtendedState();
@@ -453,25 +474,33 @@ class Surface final : public ui::PropertyHandler {
State basic_state;
// The buffer that will become the content of surface.
- BufferAttachment buffer;
+ // Persisted between commits.
+ absl::optional<BufferAttachment> buffer;
// The rounded corners bounds for the surface.
+ // Persisted between commits.
gfx::RRectF rounded_corners_bounds;
// The damage region to schedule paint for.
+ // Not persisted between commits.
cc::Region damage;
// These lists contain the callbacks to notify the client when it is a good
// time to start producing a new frame.
+ // Not persisted between commits.
std::list<FrameCallback> frame_callbacks;
// These lists contain the callbacks to notify the client when surface
// contents have been presented.
+ // Not persisted between commits.
std::list<PresentationCallback> presentation_callbacks;
// The acquire gpu fence to associate with the surface buffer.
+ // Not persisted between commits.
std::unique_ptr<gfx::GpuFence> acquire_fence;
// Callback to notify about the per-commit buffer release. The wayland
// Exo backend uses this callback to implement the immediate_release
// event of the explicit sync protocol.
+ // Not persisted between commits.
Buffer::PerCommitExplicitReleaseCallback
per_commit_explicit_release_callback_;
// The hint for overlay prioritization
+ // Persisted between commits.
OverlayPriority overlay_priority_hint = OverlayPriority::REGULAR;
};
@@ -496,7 +525,9 @@ class Surface final : public ui::PropertyHandler {
void UpdateContentSize();
// This returns true when the surface has some contents assigned to it.
- bool has_contents() const { return !state_.buffer.size().IsEmpty(); }
+ bool has_contents() const {
+ return state_.buffer.has_value() && !state_.buffer->size().IsEmpty();
+ }
// This window has the layer which contains the Surface contents.
std::unique_ptr<aura::Window> window_;
diff --git a/chromium/components/exo/surface_observer.h b/chromium/components/exo/surface_observer.h
index f329dc7aa16..8ec8b9f4eec 100644
--- a/chromium/components/exo/surface_observer.h
+++ b/chromium/components/exo/surface_observer.h
@@ -5,6 +5,8 @@
#ifndef COMPONENTS_EXO_SURFACE_OBSERVER_H_
#define COMPONENTS_EXO_SURFACE_OBSERVER_H_
+#include <cstdint>
+
namespace exo {
class Surface;
@@ -34,6 +36,15 @@ class SurfaceObserver {
// or -1 for a window assigned to all desks.
virtual void OnDeskChanged(Surface* surface, int state) {}
+ // Called when the display of this surface has changed. Only called after
+ // successfully updating sub-surfaces.
+ virtual void OnDisplayChanged(Surface* surface,
+ int64_t old_display,
+ int64_t new_display) {}
+
+ // Starts or ends throttling.
+ virtual void ThrottleFrameRate(bool on) {}
+
protected:
virtual ~SurfaceObserver() {}
};
diff --git a/chromium/components/exo/surface_test_util.cc b/chromium/components/exo/surface_test_util.cc
new file mode 100644
index 00000000000..fbe5ceac98a
--- /dev/null
+++ b/chromium/components/exo/surface_test_util.cc
@@ -0,0 +1,12 @@
+// Copyright 2022 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.
+
+#include "components/exo/surface_test_util.h"
+
+namespace exo {
+
+SurfaceObserverForTest::SurfaceObserverForTest() = default;
+SurfaceObserverForTest::~SurfaceObserverForTest() = default;
+
+} // namespace exo
diff --git a/chromium/components/exo/surface_test_util.h b/chromium/components/exo/surface_test_util.h
new file mode 100644
index 00000000000..876709c1fb3
--- /dev/null
+++ b/chromium/components/exo/surface_test_util.h
@@ -0,0 +1,37 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_EXO_SURFACE_TEST_UTIL_H_
+#define COMPONENTS_EXO_SURFACE_TEST_UTIL_H_
+
+#include "components/exo/surface_observer.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace exo {
+
+class SurfaceObserverForTest : public SurfaceObserver {
+ public:
+ SurfaceObserverForTest();
+ SurfaceObserverForTest(const SurfaceObserverForTest&) = delete;
+ SurfaceObserverForTest& operator=(const SurfaceObserverForTest&) = delete;
+ virtual ~SurfaceObserverForTest();
+
+ // SurfaceObserver overrides
+ void OnSurfaceDestroying(Surface* surface) override {}
+
+ void OnWindowOcclusionChanged(Surface* surface) override {
+ num_occlusion_changes_++;
+ }
+
+ int num_occlusion_changes() const { return num_occlusion_changes_; }
+
+ MOCK_METHOD(void, ThrottleFrameRate, (bool on), (override));
+
+ private:
+ int num_occlusion_changes_ = 0;
+};
+
+} // namespace exo
+
+#endif // COMPONENTS_EXO_SURFACE_TEST_UTIL_H_
diff --git a/chromium/components/exo/surface_tree_host.cc b/chromium/components/exo/surface_tree_host.cc
index a43ca4c4ef3..197a9a296b0 100644
--- a/chromium/components/exo/surface_tree_host.cc
+++ b/chromium/components/exo/surface_tree_host.cc
@@ -4,6 +4,7 @@
#include "components/exo/surface_tree_host.h"
+#include <algorithm>
#include <utility>
#include <vector>
@@ -16,9 +17,11 @@
#include "components/exo/wm_helper.h"
#include "components/viz/common/gpu/context_provider.h"
#include "components/viz/common/quads/compositor_frame.h"
+#include "components/viz/common/quads/compositor_frame_metadata.h"
#include "components/viz/common/quads/compositor_render_pass.h"
#include "components/viz/common/quads/shared_quad_state.h"
#include "components/viz/common/quads/solid_color_draw_quad.h"
+#include "components/viz/common/resources/transferable_resource.h"
#include "gpu/command_buffer/client/gles2_interface.h"
#include "third_party/skia/include/core/SkPath.h"
#include "ui/aura/client/aura_constants.h"
@@ -34,6 +37,8 @@
#include "ui/compositor/layer.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
+#include "ui/gfx/color_space.h"
+#include "ui/gfx/display_color_spaces.h"
#include "ui/gfx/geometry/dip_util.h"
#include "ui/gfx/geometry/point_f.h"
#include "ui/gfx/geometry/size_conversions.h"
@@ -288,6 +293,13 @@ void SurfaceTreeHost::SubmitCompositorFrame() {
gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
gles2->VerifySyncTokensCHROMIUM(sync_tokens.data(), sync_tokens.size());
+ frame.metadata.content_color_usage = gfx::ContentColorUsage::kSRGB;
+ for (auto& resource : frame.resource_list) {
+ frame.metadata.content_color_usage =
+ std::max(frame.metadata.content_color_usage,
+ resource.color_space.GetContentColorUsage());
+ }
+
layer_tree_frame_sink_holder_->SubmitCompositorFrame(std::move(frame));
}
@@ -319,9 +331,10 @@ void SurfaceTreeHost::UpdateHostWindowBounds() {
// applied.
aura::WindowOcclusionTracker::ScopedPause pause_occlusion;
- gfx::Rect bounds = root_surface_->surface_hierarchy_content_bounds();
- host_window_->SetBounds(
- gfx::Rect(host_window_->bounds().origin(), bounds.size()));
+ const gfx::Rect& bounds = root_surface_->surface_hierarchy_content_bounds();
+ if (bounds != host_window_->bounds())
+ host_window_->SetBounds({host_window_->bounds().origin(), bounds.size()});
+
// TODO(yjliu): a) consolidate with ClientControlledShellSurface. b) use the
// scale factor the buffer is created for to set the transform for
// synchronization.
@@ -329,7 +342,8 @@ void SurfaceTreeHost::UpdateHostWindowBounds() {
gfx::Transform tr;
float scale = host_window_->layer()->device_scale_factor();
tr.Scale(1.0f / scale, 1.0f / scale);
- host_window_->SetTransform(tr);
+ if (host_window_->transform() != tr)
+ host_window_->SetTransform(tr);
}
const bool fills_bounds_opaquely =
gfx::SizeF(bounds.size()) == root_surface_->content_size() &&
@@ -337,8 +351,11 @@ void SurfaceTreeHost::UpdateHostWindowBounds() {
host_window_->SetTransparent(!fills_bounds_opaquely);
root_surface_origin_ = gfx::Point() - bounds.OffsetFromOrigin();
- root_surface_->window()->SetBounds(gfx::Rect(
- root_surface_origin_, root_surface_->window()->bounds().size()));
+ const gfx::Rect& window_bounds = root_surface_->window()->bounds();
+ if (root_surface_origin_ != window_bounds.origin()) {
+ gfx::Rect updated_bounds(root_surface_origin_, window_bounds.size());
+ root_surface_->window()->SetBounds(updated_bounds);
+ }
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/chromium/components/exo/surface_unittest.cc b/chromium/components/exo/surface_unittest.cc
index 774a86826c5..09491bf19c8 100644
--- a/chromium/components/exo/surface_unittest.cc
+++ b/chromium/components/exo/surface_unittest.cc
@@ -10,6 +10,7 @@
#include "components/exo/buffer.h"
#include "components/exo/shell_surface.h"
#include "components/exo/sub_surface.h"
+#include "components/exo/surface_test_util.h"
#include "components/exo/test/exo_test_base.h"
#include "components/exo/test/exo_test_helper.h"
#include "components/viz/common/quads/compositor_frame.h"
@@ -83,25 +84,6 @@ std::string TransformToString(Transform transform) {
return prefix + name;
}
-class SurfaceObserverForTest : public SurfaceObserver {
- public:
- SurfaceObserverForTest() = default;
-
- SurfaceObserverForTest(const SurfaceObserverForTest&) = delete;
- SurfaceObserverForTest& operator=(const SurfaceObserverForTest&) = delete;
-
- void OnSurfaceDestroying(Surface* surface) override {}
-
- void OnWindowOcclusionChanged(Surface* surface) override {
- num_occlusion_changes_++;
- }
-
- int num_occlusion_changes() const { return num_occlusion_changes_; }
-
- private:
- int num_occlusion_changes_ = 0;
-};
-
class SurfaceTest : public test::ExoTestBase,
public ::testing::WithParamInterface<float> {
public:
@@ -1425,7 +1407,15 @@ TEST_P(SurfaceTest, HasPendingPerCommitBufferReleaseCallback) {
EXPECT_FALSE(surface->HasPendingPerCommitBufferReleaseCallback());
}
-TEST_P(SurfaceTest, PerCommitBufferReleaseCallbackForSameSurface) {
+// TODO(crbug.com/1292674): Flaky on ChromeOS.
+#if BUILDFLAG(IS_CHROMEOS)
+#define MAYBE_PerCommitBufferReleaseCallbackForSameSurface \
+ DISABLED_PerCommitBufferReleaseCallbackForSameSurface
+#else
+#define MAYBE_PerCommitBufferReleaseCallbackForSameSurface \
+ PerCommitBufferReleaseCallbackForSameSurface
+#endif
+TEST_P(SurfaceTest, MAYBE_PerCommitBufferReleaseCallbackForSameSurface) {
gfx::Size buffer_size(1, 1);
auto buffer1 = std::make_unique<Buffer>(
exo_test_helper()->CreateGpuMemoryBuffer(buffer_size));
@@ -1466,7 +1456,15 @@ TEST_P(SurfaceTest, PerCommitBufferReleaseCallbackForSameSurface) {
EXPECT_EQ(buffer_release_count, 1);
}
-TEST_P(SurfaceTest, PerCommitBufferReleaseCallbackForDifferentSurfaces) {
+// TODO(crbug.com/1292674): Flaky on ChromeOS.
+#if BUILDFLAG(IS_CHROMEOS)
+#define MAYBE_PerCommitBufferReleaseCallbackForDifferentSurfaces \
+ DISABLED_PerCommitBufferReleaseCallbackForDifferentSurfaces
+#else
+#define MAYBE_PerCommitBufferReleaseCallbackForDifferentSurfaces \
+ PerCommitBufferReleaseCallbackForDifferentSurfaces
+#endif
+TEST_P(SurfaceTest, MAYBE_PerCommitBufferReleaseCallbackForDifferentSurfaces) {
gfx::Size buffer_size(1, 1);
auto buffer1 = std::make_unique<Buffer>(
exo_test_helper()->CreateGpuMemoryBuffer(buffer_size));
diff --git a/chromium/components/exo/text_input.cc b/chromium/components/exo/text_input.cc
index 1d93baf5fb9..7bb90d900c6 100644
--- a/chromium/components/exo/text_input.cc
+++ b/chromium/components/exo/text_input.cc
@@ -7,7 +7,6 @@
#include <algorithm>
#include <utility>
-#include "ash/keyboard/ui/keyboard_ui_controller.h"
#include "base/check.h"
#include "base/logging.h"
#include "base/strings/string_piece.h"
@@ -19,6 +18,7 @@
#include "ui/aura/window_tree_host.h"
#include "ui/base/ime/input_method.h"
#include "ui/base/ime/utf_offset.h"
+#include "ui/base/ime/virtual_keyboard_controller.h"
#include "ui/events/event.h"
namespace exo {
@@ -37,23 +37,17 @@ TextInput::TextInput(std::unique_ptr<Delegate> delegate)
: delegate_(std::move(delegate)) {}
TextInput::~TextInput() {
- if (keyboard_ui_controller_)
- keyboard_ui_controller_->RemoveObserver(this);
if (input_method_)
Deactivate();
}
void TextInput::Activate(Surface* surface) {
- DLOG_IF(ERROR, window_) << "Already activated with " << window_;
DCHECK(surface);
-
- window_ = surface->window();
- AttachInputMethod();
+ AttachInputMethod(surface->window());
}
void TextInput::Deactivate() {
DetachInputMethod();
- window_ = nullptr;
}
void TextInput::ShowVirtualKeyboardIfEnabled() {
@@ -62,12 +56,12 @@ void TextInput::ShowVirtualKeyboardIfEnabled() {
pending_vk_visible_ = true;
return;
}
- input_method_->ShowVirtualKeyboardIfEnabled();
+ input_method_->SetVirtualKeyboardVisibilityIfEnabled(true);
}
void TextInput::HideVirtualKeyboard() {
- if (keyboard_ui_controller_)
- keyboard_ui_controller_->HideKeyboardByUser();
+ if (input_method_)
+ input_method_->SetVirtualKeyboardVisibilityIfEnabled(false);
pending_vk_visible_ = false;
}
@@ -288,7 +282,11 @@ void TextInput::OnInputMethodChanged() {
if (input_method == input_method_)
return;
input_method_->DetachTextInputClient(this);
+ if (auto* controller = input_method_->GetVirtualKeyboardController())
+ controller->RemoveObserver(this);
input_method_ = input_method;
+ if (auto* controller = input_method_->GetVirtualKeyboardController())
+ controller->AddObserver(this);
input_method_->SetFocusedTextInputClient(this);
}
@@ -393,36 +391,40 @@ void GetActiveTextInputControlLayoutBounds(
NOTIMPLEMENTED_LOG_ONCE();
}
-void TextInput::OnKeyboardVisibilityChanged(bool is_visible) {
- delegate_->OnVirtualKeyboardVisibilityChanged(is_visible);
+void TextInput::OnKeyboardVisible(const gfx::Rect& keyboard_rect) {
+ delegate_->OnVirtualKeyboardVisibilityChanged(true);
}
-void TextInput::AttachInputMethod() {
+void TextInput::OnKeyboardHidden() {
+ delegate_->OnVirtualKeyboardVisibilityChanged(false);
+}
+
+void TextInput::AttachInputMethod(aura::Window* window) {
+ DCHECK(window);
+
+ if (window_) {
+ if (window == window_)
+ return;
+ DetachInputMethod();
+ }
DCHECK(!input_method_);
- ui::InputMethod* input_method = GetInputMethod(window_);
- if (!input_method) {
+ window_ = window;
+ input_method_ = GetInputMethod(window_);
+ if (!input_method_) {
LOG(ERROR) << "input method not found";
return;
}
input_mode_ = ui::TEXT_INPUT_MODE_TEXT;
input_type_ = ui::TEXT_INPUT_TYPE_TEXT;
- input_method_ = input_method;
+ if (auto* controller = input_method_->GetVirtualKeyboardController())
+ controller->AddObserver(this);
input_method_->SetFocusedTextInputClient(this);
delegate_->Activated();
- if (!keyboard_ui_controller_ &&
- keyboard::KeyboardUIController::HasInstance()) {
- auto* keyboard_ui_controller = keyboard::KeyboardUIController::Get();
- if (keyboard_ui_controller->IsEnabled()) {
- keyboard_ui_controller_ = keyboard_ui_controller;
- keyboard_ui_controller_->AddObserver(this);
- }
- }
-
if (pending_vk_visible_) {
- input_method_->ShowVirtualKeyboardIfEnabled();
+ input_method_->SetVirtualKeyboardVisibilityIfEnabled(true);
pending_vk_visible_ = false;
}
}
@@ -435,7 +437,10 @@ void TextInput::DetachInputMethod() {
input_mode_ = ui::TEXT_INPUT_MODE_DEFAULT;
input_type_ = ui::TEXT_INPUT_TYPE_NONE;
input_method_->DetachTextInputClient(this);
+ if (auto* controller = input_method_->GetVirtualKeyboardController())
+ controller->RemoveObserver(this);
input_method_ = nullptr;
+ window_ = nullptr;
delegate_->Deactivated();
}
diff --git a/chromium/components/exo/text_input.h b/chromium/components/exo/text_input.h
index fd5a490da8f..f735690c945 100644
--- a/chromium/components/exo/text_input.h
+++ b/chromium/components/exo/text_input.h
@@ -7,7 +7,6 @@
#include <string>
-#include "ash/public/cpp/keyboard/keyboard_controller_observer.h"
#include "base/i18n/rtl.h"
#include "base/strings/string_piece.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
@@ -16,6 +15,7 @@
#include "ui/base/ime/text_input_flags.h"
#include "ui/base/ime/text_input_mode.h"
#include "ui/base/ime/text_input_type.h"
+#include "ui/base/ime/virtual_keyboard_controller_observer.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/range/range.h"
@@ -23,16 +23,12 @@ namespace ui {
class InputMethod;
}
-namespace keyboard {
-class KeyboardUIController;
-}
-
namespace exo {
class Surface;
// This class bridges the ChromeOS input method and a text-input context.
class TextInput : public ui::TextInputClient,
- public ash::KeyboardControllerObserver {
+ public ui::VirtualKeyboardControllerObserver {
public:
class Delegate {
public:
@@ -180,17 +176,16 @@ class TextInput : public ui::TextInputClient,
absl::optional<gfx::Rect>* control_bounds,
absl::optional<gfx::Rect>* selection_bounds) override {}
- // ash::KeyboardControllerObserver:
- void OnKeyboardVisibilityChanged(bool is_visible) override;
+ // ui::VirtualKeyboardControllerObserver:
+ void OnKeyboardVisible(const gfx::Rect& keyboard_rect) override;
+ void OnKeyboardHidden() override;
private:
- void AttachInputMethod();
+ void AttachInputMethod(aura::Window* window);
void DetachInputMethod();
// Delegate to talk to actual its client.
std::unique_ptr<Delegate> delegate_;
- // Keyboard Controller to observe the visibility.
- keyboard::KeyboardUIController* keyboard_ui_controller_ = nullptr;
// On requesting to show Virtual Keyboard, InputMethod may not be connected.
// So, remember the request temporarily, and then on InputMethod connection
diff --git a/chromium/components/exo/text_input_unittest.cc b/chromium/components/exo/text_input_unittest.cc
index 2bc232c7362..354ad3fc874 100644
--- a/chromium/components/exo/text_input_unittest.cc
+++ b/chromium/components/exo/text_input_unittest.cc
@@ -185,10 +185,17 @@ TEST_F(TextInputTest, ShowVirtualKeyboardIfEnabled) {
testing::Mock::VerifyAndClearExpectations(&observer);
testing::Mock::VerifyAndClearExpectations(delegate());
+ // Currently, Virtual Keyboard Controller is not set up, and so
+ // the virtual keyboard events are gone. Here, we capture the callback
+ // from the observer and translate it to the ones of
+ // VirtualKeyboardControllerObserver event as if it is done via
+ // real VirtualKeyboardController implementation.
EXPECT_CALL(observer, OnVirtualKeyboardVisibilityChangedIfEnabled)
.WillOnce(testing::Invoke([this](bool should_show) {
if (should_show)
- text_input()->OnKeyboardVisibilityChanged(true);
+ text_input()->OnKeyboardVisible(gfx::Rect());
+ else
+ text_input()->OnKeyboardHidden();
}));
EXPECT_CALL(*delegate(), OnVirtualKeyboardVisibilityChanged(true)).Times(1);
text_input()->ShowVirtualKeyboardIfEnabled();
@@ -209,10 +216,18 @@ TEST_F(TextInputTest, ShowVirtualKeyboardIfEnabledBeforeActivated) {
text_input()->ShowVirtualKeyboardIfEnabled();
EXPECT_CALL(observer, OnTextInputStateChanged(text_input())).Times(1);
+
+ // Currently, Virtual Keyboard Controller is not set up, and so
+ // the virtual keyboard events are gone. Here, we capture the callback
+ // from the observer and translate it to the ones of
+ // VirtualKeyboardControllerObserver event as if it is done via
+ // real VirtualKeyboardController implementation.
EXPECT_CALL(observer, OnVirtualKeyboardVisibilityChangedIfEnabled)
.WillOnce(testing::Invoke([this](bool should_show) {
if (should_show)
- text_input()->OnKeyboardVisibilityChanged(true);
+ text_input()->OnKeyboardVisible(gfx::Rect());
+ else
+ text_input()->OnKeyboardHidden();
}));
EXPECT_CALL(*delegate(), Activated).Times(1);
EXPECT_CALL(*delegate(), OnVirtualKeyboardVisibilityChanged(true)).Times(1);
diff --git a/chromium/components/exo/ui_lock_controller.cc b/chromium/components/exo/ui_lock_controller.cc
index 9c1351b226c..1d7383cd8c4 100644
--- a/chromium/components/exo/ui_lock_controller.cc
+++ b/chromium/components/exo/ui_lock_controller.cc
@@ -8,6 +8,8 @@
#include "ash/constants/app_types.h"
#include "ash/constants/ash_features.h"
+#include "ash/public/cpp/keyboard/keyboard_controller.h"
+#include "ash/resources/vector_icons/vector_icons.h"
#include "ash/wm/window_state.h"
#include "ash/wm/window_state_observer.h"
#include "base/bind.h"
@@ -16,6 +18,7 @@
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "chromeos/ui/base/window_properties.h"
+#include "components/exo/pointer.h"
#include "components/exo/seat.h"
#include "components/exo/shell_surface_util.h"
#include "components/exo/surface.h"
@@ -29,6 +32,7 @@
#include "ui/base/l10n/l10n_util.h"
#include "ui/events/event_constants.h"
#include "ui/events/keycodes/dom/dom_code.h"
+#include "ui/gfx/paint_vector_icon.h"
#include "ui/strings/grit/ui_strings.h"
#include "ui/views/widget/widget.h"
@@ -40,15 +44,14 @@ namespace {
//
// The exit popup is a circle with an 'X' close icon which exits fullscreen when
// the user clicks it.
-// * It is not shown on windows such as borealis with property
-// kEscHoldExitFullscreenToMinimized.
+// * It is only shown on windows with property kEscHoldToExitFullscreen.
// * It is displayed when the mouse moves to the top 3px of the screen.
// * It will hide after a 3s timeout, or the user moves below 150px.
// * After hiding, there is a cooldown where it will not display again until the
// mouse moves below 150px.
-// Duration to show the 'Press and hold Esc' notification.
-constexpr auto kEscNotificationDuration = base::Seconds(4);
+// Duration to show notifications.
+constexpr auto kNotificationDuration = base::Seconds(4);
// Position of Esc notification from top of screen.
const int kEscNotificationTopPx = 45;
// Duration to show the exit 'X' popup.
@@ -58,17 +61,60 @@ constexpr float kExitPopupDisplayHeight = 3.f;
// Hide the exit popup if mouse is below this height.
constexpr float kExitPopupHideHeight = 150.f;
+// Once the pointer capture notification has finished showing without
+// being interrupted, don't show it again until this long has passed.
+constexpr auto kPointerCaptureNotificationCooldown = base::Minutes(5);
+
constexpr int kUILockControllerSeatObserverPriority = 1;
static_assert(
exo::Seat::IsValidObserverPriority(kUILockControllerSeatObserverPriority),
"kUILockCOntrollerSeatObserverPriority is not in the valid range");
+bool IsUILockControllerEnabled(aura::Window* window) {
+ if (!window)
+ return false;
+
+ if (window->GetProperty(chromeos::kEscHoldToExitFullscreen) ||
+ window->GetProperty(chromeos::kUseOverviewToExitFullscreen) ||
+ window->GetProperty(chromeos::kUseOverviewToExitPointerLock)) {
+ return true;
+ }
+ return false;
+}
+
+// Creates the separator view between bubble views of modifiers and key.
+std::unique_ptr<views::View> CreateIconView(const gfx::VectorIcon& icon) {
+ constexpr int kIconSize = 28;
+
+ std::unique_ptr<views::ImageView> view = std::make_unique<views::ImageView>();
+ gfx::ImageSkia image = gfx::CreateVectorIcon(icon, SK_ColorWHITE);
+ view->SetImage(ui::ImageModel::FromImageSkia(image));
+ view->SetImageSize(gfx::Size(kIconSize, kIconSize));
+ return view;
+}
+
// Create and position Esc notification.
-views::Widget* CreateEscNotification(aura::Window* parent) {
+views::Widget* CreateEscNotification(
+ aura::Window* parent,
+ int message_id,
+ std::initializer_list<int> key_message_ids) {
auto content_view = std::make_unique<SubtleNotificationView>();
- std::u16string accelerator = l10n_util::GetStringUTF16(IDS_APP_ESC_KEY);
- content_view->UpdateContent(l10n_util::GetStringFUTF16(
- IDS_FULLSCREEN_HOLD_ESC_TO_EXIT_FULLSCREEN, accelerator));
+
+ std::vector<std::u16string> key_names;
+ std::vector<std::unique_ptr<views::View>> icons;
+ for (int key_message_id : key_message_ids) {
+ key_names.push_back(l10n_util::GetStringUTF16(key_message_id));
+
+ if (key_message_id == IDS_APP_OVERVIEW_KEY) {
+ icons.push_back(CreateIconView(ash::kKsvOverviewIcon));
+ } else {
+ icons.push_back(nullptr);
+ }
+ }
+ content_view->UpdateContent(
+ l10n_util::GetStringFUTF16(message_id, key_names, nullptr),
+ std::move(icons));
+
gfx::Size size = content_view->GetPreferredSize();
views::Widget* popup = SubtleNotificationView::CreatePopupWidget(
parent, std::move(content_view));
@@ -81,42 +127,103 @@ views::Widget* CreateEscNotification(aura::Window* parent) {
return popup;
}
-// Exits fullscreen to either default or minimized.
+// Exits fullscreen to previous state.
void ExitFullscreen(aura::Window* window) {
ash::WindowState* window_state = ash::WindowState::Get(window);
- if (window->GetProperty(chromeos::kEscHoldExitFullscreenToMinimized))
- window_state->Minimize();
- else
+ if (window_state->IsFullscreen())
window_state->Restore();
}
-// Shows 'Press and hold ESC to exit fullscreen' message, and exit popup.
-class EscHoldNotifier : public ui::EventHandler,
- public ash::WindowStateObserver {
+// Owns the widgets for messages prompting to exit fullscreen/mouselock, and
+// the exit popup. Owned as a window property.
+class ExitNotifier : public ui::EventHandler, public ash::WindowStateObserver {
public:
- explicit EscHoldNotifier(aura::Window* window) : window_(window) {
+ explicit ExitNotifier(aura::Window* window) : window_(window) {
ash::WindowState* window_state = ash::WindowState::Get(window);
window_state_observation_.Observe(window_state);
if (window_state->IsFullscreen())
OnFullscreen();
}
- EscHoldNotifier(const EscHoldNotifier&) = delete;
- EscHoldNotifier& operator=(const EscHoldNotifier&) = delete;
+ ExitNotifier(const ExitNotifier&) = delete;
+ ExitNotifier& operator=(const ExitNotifier&) = delete;
+
+ ~ExitNotifier() override {
+ OnExitFullscreen();
+ ClosePointerCaptureNotification();
+ }
- ~EscHoldNotifier() override { CloseAll(); }
+ views::Widget* fullscreen_esc_notification() {
+ return fullscreen_esc_notification_;
+ }
- views::Widget* esc_notification() { return esc_notification_; }
+ views::Widget* pointer_capture_notification() {
+ return pointer_capture_notification_;
+ }
FullscreenControlPopup* exit_popup() { return exit_popup_.get(); }
+ void MaybeShowPointerCaptureNotification() {
+ // Respect cooldown.
+ if (base::TimeTicks::Now() < next_pointer_notify_time_)
+ return;
+
+ want_pointer_capture_notification_ = true;
+
+ // Don't show in fullscreen; the fullscreen notification will show and is
+ // prioritized.
+ ash::WindowState* window_state = ash::WindowState::Get(window_);
+ if (window_state->IsFullscreen())
+ return;
+
+ if (pointer_capture_notification_) {
+ pointer_capture_notification_->CloseWithReason(
+ views::Widget::ClosedReason::kUnspecified);
+ }
+
+ if (ash::KeyboardController::Get()->AreTopRowKeysFunctionKeys()) {
+ pointer_capture_notification_ =
+ CreateEscNotification(window_, IDS_PRESS_TO_EXIT_MOUSELOCK_TWO_KEYS,
+ {IDS_APP_SEARCH_KEY, IDS_APP_OVERVIEW_KEY});
+ } else {
+ pointer_capture_notification_ = CreateEscNotification(
+ window_, IDS_PRESS_TO_EXIT_MOUSELOCK, {IDS_APP_OVERVIEW_KEY});
+ }
+
+ pointer_capture_notification_->Show();
+
+ // Close Esc notification after 4s.
+ pointer_capture_notify_timer_.Start(
+ FROM_HERE, kNotificationDuration,
+ base::BindOnce(&ExitNotifier::OnPointerCaptureNotifyTimerFinished,
+ base::Unretained(this)));
+ }
+
+ void ClosePointerCaptureNotification() {
+ pointer_capture_notify_timer_.Stop();
+ if (pointer_capture_notification_) {
+ pointer_capture_notification_->CloseWithReason(
+ views::Widget::ClosedReason::kUnspecified);
+ pointer_capture_notification_ = nullptr;
+ }
+ }
+
private:
+ void OnPointerCaptureNotifyTimerFinished() {
+ // Start the cooldown when the timer successfully elapses, to ensure the
+ // notification was shown for a sufficiently long time.
+ next_pointer_notify_time_ =
+ base::TimeTicks::Now() + kPointerCaptureNotificationCooldown;
+ ClosePointerCaptureNotification();
+ want_pointer_capture_notification_ = false;
+ }
+
// Overridden from ui::EventHandler:
void OnMouseEvent(ui::MouseEvent* event) override {
gfx::PointF point = event->location_f();
aura::Window::ConvertPointToTarget(
static_cast<aura::Window*>(event->target()), window_, &point);
- if (!esc_notification_ && !exit_popup_cooldown_ &&
+ if (!fullscreen_esc_notification_ && !exit_popup_cooldown_ &&
window_ == exo::WMHelper::GetInstance()->GetActiveWindow() &&
point.y() <= kExitPopupDisplayHeight) {
// Show exit popup if mouse is above 3px, unless esc notification is
@@ -129,10 +236,10 @@ class EscHoldNotifier : public ui::EventHandler,
views::Widget* widget =
views::Widget::GetTopLevelWidgetForNativeView(window_);
exit_popup_->Show(widget->GetClientAreaBoundsInScreen());
- exit_popup_timer_.Start(FROM_HERE, kExitPopupDuration,
- base::BindOnce(&EscHoldNotifier::HideExitPopup,
- base::Unretained(this),
- /*animate=*/true));
+ exit_popup_timer_.Start(
+ FROM_HERE, kExitPopupDuration,
+ base::BindOnce(&ExitNotifier::HideExitPopup, base::Unretained(this),
+ /*animate=*/true));
exit_popup_cooldown_ = true;
} else if (point.y() > kExitPopupHideHeight) {
// Hide exit popup if mouse is below 150px, reset cooloff.
@@ -149,14 +256,14 @@ class EscHoldNotifier : public ui::EventHandler,
if (window_state->IsFullscreen()) {
OnFullscreen();
} else {
- CloseAll();
+ OnExitFullscreen();
}
}
void OnFullscreen() {
// Register ui::EventHandler to watch if mouse goes to top of screen.
if (!is_handling_events_ &&
- !window_->GetProperty(chromeos::kEscHoldExitFullscreenToMinimized)) {
+ window_->GetProperty(chromeos::kEscHoldToExitFullscreen)) {
window_->AddPreTargetHandler(this);
is_handling_events_ = true;
}
@@ -165,32 +272,71 @@ class EscHoldNotifier : public ui::EventHandler,
if (window_ != exo::WMHelper::GetInstance()->GetActiveWindow())
return;
- if (!esc_notification_)
- esc_notification_ = CreateEscNotification(window_);
- esc_notification_->Show();
+ // Fullscreen notifications override pointer capture notifications.
+ ClosePointerCaptureNotification();
+
+ if (fullscreen_esc_notification_) {
+ fullscreen_esc_notification_->CloseWithReason(
+ views::Widget::ClosedReason::kUnspecified);
+ }
+
+ if (window_->GetProperty(chromeos::kUseOverviewToExitFullscreen)) {
+ if (ash::KeyboardController::Get()->AreTopRowKeysFunctionKeys()) {
+ fullscreen_esc_notification_ = CreateEscNotification(
+ window_, IDS_FULLSCREEN_PRESS_TO_EXIT_FULLSCREEN_TWO_KEYS,
+ {IDS_APP_SEARCH_KEY, IDS_APP_OVERVIEW_KEY});
+ } else {
+ fullscreen_esc_notification_ = CreateEscNotification(
+ window_, IDS_FULLSCREEN_PRESS_TO_EXIT_FULLSCREEN,
+ {IDS_APP_OVERVIEW_KEY});
+ }
+ } else {
+ fullscreen_esc_notification_ = CreateEscNotification(
+ window_,
+ window_->GetProperty(chromeos::kEscHoldToExitFullscreen)
+ ? IDS_FULLSCREEN_HOLD_TO_EXIT_FULLSCREEN
+ : IDS_FULLSCREEN_PRESS_TO_EXIT_FULLSCREEN,
+ {IDS_APP_ESC_KEY});
+ }
+
+ fullscreen_esc_notification_->Show();
// Close Esc notification after 4s.
- esc_notification_timer_.Start(
- FROM_HERE, kEscNotificationDuration,
- base::BindOnce(&EscHoldNotifier::CloseEscNotification,
+ fullscreen_notify_timer_.Start(
+ FROM_HERE, kNotificationDuration,
+ base::BindOnce(&ExitNotifier::CloseFullscreenEscNotification,
base::Unretained(this)));
}
- void CloseAll() {
+ void OnExitFullscreen() {
if (is_handling_events_) {
window_->RemovePreTargetHandler(this);
is_handling_events_ = false;
}
- CloseEscNotification();
+ CloseFullscreenEscNotification();
HideExitPopup();
}
- void CloseEscNotification() {
- if (!esc_notification_)
+ void CloseFullscreenEscNotification() {
+ if (!fullscreen_esc_notification_)
return;
- esc_notification_->CloseWithReason(
+ fullscreen_esc_notification_->CloseWithReason(
views::Widget::ClosedReason::kUnspecified);
- esc_notification_ = nullptr;
+ fullscreen_esc_notification_ = nullptr;
+
+ // If a pointer capture notification was previously requested and didn't
+ // show (or didn't complete its timer), show it now.
+ //
+ // This is to prevent the following scenario:
+ // 1. App goes fullscreen
+ // 2. App immediately requests pointer capture; no notification is shown,
+ // since the fullscreen notification is already visible.
+ // 3. App immediately unfullscreens; the fullscreen notification closes.
+ //
+ // Without this check, the app would have gained pointer capture without
+ // any notification showing.
+ if (want_pointer_capture_notification_)
+ MaybeShowPointerCaptureNotification();
}
void HideExitPopup(bool animate = false) {
@@ -198,12 +344,16 @@ class EscHoldNotifier : public ui::EventHandler,
exit_popup_->Hide(animate);
}
- aura::Window* window_;
- views::Widget* esc_notification_ = nullptr;
+ aura::Window* const window_;
+ views::Widget* fullscreen_esc_notification_ = nullptr;
+ views::Widget* pointer_capture_notification_ = nullptr;
+ bool want_pointer_capture_notification_ = false;
std::unique_ptr<FullscreenControlPopup> exit_popup_;
bool is_handling_events_ = false;
bool exit_popup_cooldown_ = false;
- base::OneShotTimer esc_notification_timer_;
+ base::OneShotTimer fullscreen_notify_timer_;
+ base::OneShotTimer pointer_capture_notify_timer_;
+ base::TimeTicks next_pointer_notify_time_;
base::OneShotTimer exit_popup_timer_;
base::ScopedObservation<ash::WindowState, ash::WindowStateObserver>
window_state_observation_{this};
@@ -211,15 +361,35 @@ class EscHoldNotifier : public ui::EventHandler,
} // namespace
-DEFINE_UI_CLASS_PROPERTY_TYPE(EscHoldNotifier*)
+DEFINE_UI_CLASS_PROPERTY_TYPE(ExitNotifier*)
namespace exo {
namespace {
-DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(EscHoldNotifier,
- kEscHoldNotifierKey,
- nullptr)
+DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(ExitNotifier, kExitNotifierKey, nullptr)
+
+ExitNotifier* GetExitNotifier(aura::Window* window, bool create) {
+ if (!base::FeatureList::IsEnabled(chromeos::features::kExoLockNotification))
+ return nullptr;
+
+ if (!window)
+ return nullptr;
+
+ aura::Window* toplevel = window->GetToplevelWindow();
+ if (!IsUILockControllerEnabled(toplevel))
+ return nullptr;
+
+ ExitNotifier* notifier = toplevel->GetProperty(kExitNotifierKey);
+ if (!notifier && create) {
+ // Object is owned as a window property.
+ notifier = toplevel->SetProperty(kExitNotifierKey,
+ std::make_unique<ExitNotifier>(toplevel));
+ }
+
+ return notifier;
}
+} // namespace
+
constexpr auto kLongPressEscapeDuration = base::Seconds(2);
constexpr auto kExcludedFlags = ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN |
ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN |
@@ -263,29 +433,55 @@ void UILockController::OnSurfaceFocused(Surface* gained_focus,
return;
aura::Window* window = gained_focus->window()->GetToplevelWindow();
- if (!window)
+ if (!IsUILockControllerEnabled(window))
return;
- // If the window does not have kEscHoldToExitFullscreen, or we are already
- // tracking it, then ignore.
- if (!window->GetProperty(chromeos::kEscHoldToExitFullscreen) ||
- window->GetProperty(kEscHoldNotifierKey)) {
+ // Object is owned as a window property.
+ if (!window->GetProperty(kExitNotifierKey)) {
+ window->SetProperty(kExitNotifierKey,
+ std::make_unique<ExitNotifier>(window));
+ }
+}
+
+void UILockController::OnPointerCaptureEnabled(Pointer* pointer,
+ aura::Window* window) {
+ aura::Window* toplevel = window ? window->GetToplevelWindow() : nullptr;
+ if (!toplevel ||
+ !toplevel->GetProperty(chromeos::kUseOverviewToExitPointerLock))
return;
+
+ captured_pointers_.insert(pointer);
+ ExitNotifier* notifier = GetExitNotifier(window, false);
+ if (notifier)
+ notifier->MaybeShowPointerCaptureNotification();
+}
+
+void UILockController::OnPointerCaptureDisabled(Pointer* pointer,
+ aura::Window* window) {
+ if (captured_pointers_.empty())
+ return;
+
+ captured_pointers_.erase(pointer);
+ if (captured_pointers_.empty()) {
+ ExitNotifier* notifier = GetExitNotifier(window, false);
+ if (notifier)
+ notifier->ClosePointerCaptureNotification();
}
+}
- // Object is owned as a window property.
- window->SetProperty(kEscHoldNotifierKey,
- std::make_unique<EscHoldNotifier>(window));
+views::Widget* UILockController::GetPointerCaptureNotificationForTesting(
+ aura::Window* window) {
+ return window->GetProperty(kExitNotifierKey)->pointer_capture_notification();
}
views::Widget* UILockController::GetEscNotificationForTesting(
aura::Window* window) {
- return window->GetProperty(kEscHoldNotifierKey)->esc_notification();
+ return window->GetProperty(kExitNotifierKey)->fullscreen_esc_notification();
}
FullscreenControlPopup* UILockController::GetExitPopupForTesting(
aura::Window* window) {
- return window->GetProperty(kEscHoldNotifierKey)->exit_popup();
+ return window->GetProperty(kExitNotifierKey)->exit_popup();
}
namespace {
diff --git a/chromium/components/exo/ui_lock_controller.h b/chromium/components/exo/ui_lock_controller.h
index c10ddd9d1d7..4dd96bb8029 100644
--- a/chromium/components/exo/ui_lock_controller.h
+++ b/chromium/components/exo/ui_lock_controller.h
@@ -6,6 +6,7 @@
#define COMPONENTS_EXO_UI_LOCK_CONTROLLER_H_
#include "ash/shell.h"
+#include "base/containers/flat_set.h"
#include "base/timer/timer.h"
#include "components/exo/seat_observer.h"
#include "ui/events/event_handler.h"
@@ -14,18 +15,18 @@ class FullscreenControlPopup;
namespace exo {
+class Pointer;
class Seat;
extern const base::TimeDelta kLongPressEscapeDuration;
-// Listens for long presses on the Escape key, which breaks out of various
-// kinds of "locks" that a window may hold.
+// Helps users to break out of various kinds of "locks" that a window may hold
+// (fullscreen, pointer lock).
//
-// TODO(cpelling): For now this is just non-immersive fullscreen. Eventually
-// this should also break pointer lock.
-//
-// The "long keypress" design is inspired by Chromium's Keyboard Lock feature
-// (see https://chromestatus.com/feature/5642959835889664).
+// In some cases this is achieved by pressing and holding Escape, similar to
+// Chromium's Keyboard Lock feature
+// (see https://chromestatus.com/feature/5642959835889664). In other cases we
+// nudge the user to use Overview.
class UILockController : public ui::EventHandler, public SeatObserver {
public:
explicit UILockController(Seat* seat);
@@ -40,8 +41,13 @@ class UILockController : public ui::EventHandler, public SeatObserver {
void OnSurfaceFocused(Surface* gained_focus,
Surface* lost_focus,
bool has_focued_surface) override;
+ void OnPointerCaptureEnabled(Pointer* pointer,
+ aura::Window* capture_window) override;
+ void OnPointerCaptureDisabled(Pointer* pointer,
+ aura::Window* capture_window) override;
views::Widget* GetEscNotificationForTesting(aura::Window* window);
+ views::Widget* GetPointerCaptureNotificationForTesting(aura::Window* window);
FullscreenControlPopup* GetExitPopupForTesting(aura::Window* window);
private:
@@ -57,6 +63,9 @@ class UILockController : public ui::EventHandler, public SeatObserver {
// dangle if the Surface is destroyed while the timer is running. Valid only
// for comparison purposes.
Surface* focused_surface_to_unlock_ = nullptr;
+
+ // Pointers currently being captured.
+ base::flat_set<base::raw_ptr<Pointer>> captured_pointers_;
};
} // namespace exo
diff --git a/chromium/components/exo/ui_lock_controller_unittest.cc b/chromium/components/exo/ui_lock_controller_unittest.cc
index d2002e22704..6f8b1d96ea0 100644
--- a/chromium/components/exo/ui_lock_controller_unittest.cc
+++ b/chromium/components/exo/ui_lock_controller_unittest.cc
@@ -12,12 +12,16 @@
#include "chromeos/ui/base/window_properties.h"
#include "components/exo/buffer.h"
#include "components/exo/display.h"
+#include "components/exo/pointer.h"
+#include "components/exo/pointer_constraint_delegate.h"
+#include "components/exo/pointer_delegate.h"
#include "components/exo/shell_surface.h"
#include "components/exo/surface.h"
#include "components/exo/test/exo_test_base.h"
#include "components/exo/test/exo_test_helper.h"
#include "components/exo/wm_helper.h"
#include "components/fullscreen_control/fullscreen_control_popup.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/class_property.h"
#include "ui/gfx/animation/animation_test_api.h"
@@ -28,7 +32,7 @@ namespace exo {
namespace {
constexpr char kNoEscHoldAppId[] = "no-esc-hold";
-constexpr char kEscToMinimizeAppId[] = "esc-to-minimize";
+constexpr char kOverviewToExitAppId[] = "overview-to-exit";
struct SurfaceTriplet {
std::unique_ptr<Surface> surface;
@@ -60,6 +64,58 @@ struct SurfaceTriplet {
}
};
+class MockPointerDelegate : public PointerDelegate {
+ public:
+ MockPointerDelegate(Surface* surface) {
+ EXPECT_CALL(*this, CanAcceptPointerEventsForSurface(surface))
+ .WillRepeatedly(testing::Return(true));
+ }
+
+ // Overridden from PointerDelegate:
+ MOCK_METHOD1(OnPointerDestroying, void(Pointer*));
+ MOCK_CONST_METHOD1(CanAcceptPointerEventsForSurface, bool(Surface*));
+ MOCK_METHOD3(OnPointerEnter, void(Surface*, const gfx::PointF&, int));
+ MOCK_METHOD1(OnPointerLeave, void(Surface*));
+ MOCK_METHOD2(OnPointerMotion, void(base::TimeTicks, const gfx::PointF&));
+ MOCK_METHOD3(OnPointerButton, void(base::TimeTicks, int, bool));
+ MOCK_METHOD3(OnPointerScroll,
+ void(base::TimeTicks, const gfx::Vector2dF&, bool));
+ MOCK_METHOD1(OnPointerScrollStop, void(base::TimeTicks));
+ MOCK_METHOD0(OnPointerFrame, void());
+};
+
+class MockPointerConstraintDelegate : public PointerConstraintDelegate {
+ public:
+ MockPointerConstraintDelegate(Pointer* pointer, Surface* surface)
+ : pointer_(pointer) {
+ EXPECT_CALL(*this, GetConstrainedSurface())
+ .WillRepeatedly(testing::Return(surface));
+ ON_CALL(*this, OnConstraintActivated).WillByDefault([this]() {
+ activated_count++;
+ });
+ ON_CALL(*this, OnConstraintBroken).WillByDefault([this]() {
+ broken_count++;
+ });
+ }
+
+ ~MockPointerConstraintDelegate() {
+ // Notifying destruction here removes some boilerplate from tests.
+ pointer_->OnPointerConstraintDelegateDestroying(this);
+ }
+
+ // Overridden from PointerConstraintDelegate:
+ MOCK_METHOD0(OnConstraintActivated, void());
+ MOCK_METHOD0(OnAlreadyConstrained, void());
+ MOCK_METHOD0(OnConstraintBroken, void());
+ MOCK_METHOD0(IsPersistent, bool());
+ MOCK_METHOD0(GetConstrainedSurface, Surface*());
+ MOCK_METHOD0(OnDefunct, void());
+
+ raw_ptr<Pointer> pointer_;
+ int activated_count = 0;
+ int broken_count = 0;
+};
+
class UILockControllerTest : public test::ExoTestBase {
public:
UILockControllerTest()
@@ -77,11 +133,16 @@ class UILockControllerTest : public test::ExoTestBase {
void PopulateProperties(
const Params& params,
ui::PropertyHandler& out_properties_container) override {
- out_properties_container.SetProperty(chromeos::kEscHoldToExitFullscreen,
- params.app_id != kNoEscHoldAppId);
out_properties_container.SetProperty(
- chromeos::kEscHoldExitFullscreenToMinimized,
- params.app_id == kEscToMinimizeAppId);
+ chromeos::kEscHoldToExitFullscreen,
+ params.app_id != kNoEscHoldAppId &&
+ params.app_id != kOverviewToExitAppId);
+ out_properties_container.SetProperty(
+ chromeos::kUseOverviewToExitFullscreen,
+ params.app_id == kOverviewToExitAppId);
+ out_properties_container.SetProperty(
+ chromeos::kUseOverviewToExitPointerLock,
+ params.app_id == kOverviewToExitAppId);
}
};
@@ -89,8 +150,10 @@ class UILockControllerTest : public test::ExoTestBase {
void SetUp() override {
test::ExoTestBase::SetUp();
seat_ = std::make_unique<Seat>();
- scoped_feature_list_.InitAndEnableFeature(
- chromeos::features::kExoLockNotification);
+ scoped_feature_list_.InitWithFeatures(
+ {chromeos::features::kExoLockNotification,
+ chromeos::features::kExoPointerLock},
+ {});
WMHelper::GetInstance()->RegisterAppPropertyResolver(
std::make_unique<TestPropertyResolver>());
}
@@ -121,6 +184,11 @@ class UILockControllerTest : public test::ExoTestBase {
surface->GetTopLevelWindow());
}
+ views::Widget* GetPointerCaptureNotification(SurfaceTriplet* surface) {
+ return seat_->GetUILockControllerForTesting()
+ ->GetPointerCaptureNotificationForTesting(surface->GetTopLevelWindow());
+ }
+
bool IsExitPopupVisible(aura::Window* window) {
FullscreenControlPopup* popup =
seat_->GetUILockControllerForTesting()->GetExitPopupForTesting(window);
@@ -262,39 +330,6 @@ TEST_F(UILockControllerTest, ShortHoldEscapeDoesNotExitFullscreen) {
EXPECT_TRUE(window_state->IsFullscreen());
}
-TEST_F(UILockControllerTest, HoldingEscapeMinimizesIfPropertySet) {
- SurfaceTriplet test_surface = BuildSurface(1024, 768);
- // Set chromeos::kEscHoldExitFullscreenToMinimized on TopLevelWindow.
- test_surface.shell_surface->SetApplicationId(kEscToMinimizeAppId);
- test_surface.shell_surface->SetUseImmersiveForFullscreen(false);
- test_surface.shell_surface->SetFullscreen(true);
- test_surface.surface->Commit();
- auto* window_state = test_surface.GetTopLevelWindowState();
- EXPECT_TRUE(window_state->IsFullscreen());
-
- GetEventGenerator()->PressKey(ui::VKEY_ESCAPE, ui::EF_NONE);
- task_environment()->FastForwardBy(base::Seconds(1));
- EXPECT_TRUE(window_state->IsFullscreen()); // no change yet
-
- task_environment()->FastForwardBy(base::Seconds(1));
- EXPECT_FALSE(window_state->IsFullscreen());
- EXPECT_TRUE(window_state->IsMinimized());
-}
-
-TEST_F(UILockControllerTest, HoldingEscapeDoesNotMinimizeIfWindowed) {
- SurfaceTriplet test_surface = BuildSurface(1024, 768);
- // Set chromeos::kEscHoldExitFullscreenToMinimized on TopLevelWindow.
- test_surface.shell_surface->SetApplicationId(kEscToMinimizeAppId);
- test_surface.shell_surface->SetUseImmersiveForFullscreen(false);
- test_surface.surface->Commit();
- auto* window_state = test_surface.GetTopLevelWindowState();
-
- GetEventGenerator()->PressKey(ui::VKEY_ESCAPE, ui::EF_NONE);
- task_environment()->FastForwardBy(base::Seconds(2));
-
- EXPECT_FALSE(window_state->IsMinimized());
-}
-
TEST_F(UILockControllerTest, FullScreenShowsEscNotification) {
SurfaceTriplet test_surface = BuildSurface(1024, 768);
test_surface.shell_surface->SetUseImmersiveForFullscreen(false);
@@ -395,6 +430,85 @@ TEST_F(UILockControllerTest, EscNotificationShowsOnSecondaryDisplay) {
esc_notification->GetWindowBoundsInScreen()));
}
+TEST_F(UILockControllerTest, PointerLockShowsNotification) {
+ SurfaceTriplet test_surface = BuildSurface(1024, 768);
+ test_surface.shell_surface->SetApplicationId(kOverviewToExitAppId);
+ test_surface.surface->Commit();
+ testing::NiceMock<MockPointerDelegate> delegate(test_surface.surface.get());
+ Pointer pointer(&delegate, seat_.get());
+ testing::NiceMock<MockPointerConstraintDelegate> constraint(
+ &pointer, test_surface.surface.get());
+ EXPECT_FALSE(GetPointerCaptureNotification(&test_surface));
+
+ EXPECT_TRUE(pointer.ConstrainPointer(&constraint));
+
+ EXPECT_TRUE(GetPointerCaptureNotification(&test_surface));
+}
+
+TEST_F(UILockControllerTest, PointerLockNotificationObeysCooldown) {
+ // Arrange: Set up a pointer capture notification.
+ SurfaceTriplet test_surface = BuildSurface(1024, 768);
+ test_surface.shell_surface->SetApplicationId(kOverviewToExitAppId);
+ test_surface.surface->Commit();
+ testing::NiceMock<MockPointerDelegate> delegate(test_surface.surface.get());
+ Pointer pointer(&delegate, seat_.get());
+ testing::NiceMock<MockPointerConstraintDelegate> constraint(
+ &pointer, test_surface.surface.get());
+ EXPECT_TRUE(pointer.ConstrainPointer(&constraint));
+ EXPECT_TRUE(GetPointerCaptureNotification(&test_surface));
+
+ // Act: Wait for the notification to timeout.
+ task_environment()->FastForwardBy(base::Seconds(5));
+
+ // Assert: Notification has disappeared.
+ EXPECT_FALSE(GetPointerCaptureNotification(&test_surface));
+
+ // Act: Remove and re-apply the constraint.
+ pointer.OnPointerConstraintDelegateDestroying(&constraint);
+ EXPECT_TRUE(pointer.ConstrainPointer(&constraint));
+
+ // Assert: Notification not shown due to the cooldown.
+ EXPECT_FALSE(GetPointerCaptureNotification(&test_surface));
+
+ // Act: Wait for the cooldown, then re-apply again
+ pointer.OnPointerConstraintDelegateDestroying(&constraint);
+ task_environment()->FastForwardBy(base::Minutes(5));
+ EXPECT_TRUE(pointer.ConstrainPointer(&constraint));
+
+ // Assert: Cooldown has expired so notification is shown.
+ EXPECT_TRUE(GetPointerCaptureNotification(&test_surface));
+}
+
+TEST_F(UILockControllerTest, FullscreenNotificationHasPriority) {
+ // Arrange: Set up a pointer capture notification.
+ SurfaceTriplet test_surface = BuildSurface(1024, 768);
+ test_surface.shell_surface->SetApplicationId(kOverviewToExitAppId);
+ test_surface.surface->Commit();
+ testing::NiceMock<MockPointerDelegate> delegate(test_surface.surface.get());
+ Pointer pointer(&delegate, seat_.get());
+ testing::NiceMock<MockPointerConstraintDelegate> constraint(
+ &pointer, test_surface.surface.get());
+ EXPECT_TRUE(pointer.ConstrainPointer(&constraint));
+ EXPECT_TRUE(GetPointerCaptureNotification(&test_surface));
+
+ // Act: Go fullscreen.
+ test_surface.shell_surface->SetUseImmersiveForFullscreen(false);
+ test_surface.shell_surface->SetFullscreen(true);
+ test_surface.surface->Commit();
+
+ // Assert: Fullscreen notification overrides pointer notification.
+ EXPECT_FALSE(GetPointerCaptureNotification(&test_surface));
+ EXPECT_TRUE(GetEscNotification(&test_surface));
+
+ // Act: Exit fullscreen.
+ test_surface.shell_surface->SetFullscreen(false);
+ test_surface.surface->Commit();
+
+ // Assert: Pointer notification returns, since it was interrupted.
+ EXPECT_TRUE(GetPointerCaptureNotification(&test_surface));
+ EXPECT_FALSE(GetEscNotification(&test_surface));
+}
+
TEST_F(UILockControllerTest, ExitPopup) {
SurfaceTriplet test_surface = BuildSurface(1024, 768);
test_surface.shell_surface->SetUseImmersiveForFullscreen(false);
@@ -449,10 +563,10 @@ TEST_F(UILockControllerTest, ExitPopup) {
EXPECT_FALSE(IsExitPopupVisible(window));
}
-TEST_F(UILockControllerTest, ExitPopupNotShownIfPropertySet) {
+TEST_F(UILockControllerTest, ExitPopupNotShownForOverviewCase) {
SurfaceTriplet test_surface = BuildSurface(1024, 768);
- // Set chromeos::kEscHoldExitFullscreenToMinimized on TopLevelWindow.
- test_surface.shell_surface->SetApplicationId(kEscToMinimizeAppId);
+ // Set chromeos::kUseOverviewToExitFullscreen on TopLevelWindow.
+ test_surface.shell_surface->SetApplicationId(kOverviewToExitAppId);
test_surface.shell_surface->SetUseImmersiveForFullscreen(false);
test_surface.shell_surface->SetFullscreen(true);
test_surface.surface->Commit();
diff --git a/chromium/components/exo/wayland/BUILD.gn b/chromium/components/exo/wayland/BUILD.gn
index 4d4c05a482a..32f82268823 100644
--- a/chromium/components/exo/wayland/BUILD.gn
+++ b/chromium/components/exo/wayland/BUILD.gn
@@ -158,6 +158,7 @@ source_set("wayland") {
"wayland_keyboard_delegate.h",
"wayland_positioner.cc",
"wayland_positioner.h",
+ "weston_test.h",
"wl_shell.cc",
"wl_shell.h",
"xdg_shell.cc",
@@ -220,21 +221,34 @@ source_set("wayland") {
"//third_party/wayland-protocols:idle_inhibit_protocol",
"//ui/base/cursor/mojom:cursor_type",
]
+ }
+}
- if (enable_weston_test) {
- testonly = true
- deps += [
- "//third_party/wayland-protocols:weston_test",
- "//ui/base:test_support",
- ]
- sources += [
- "weston_test.cc",
- "weston_test.h",
- ]
- }
+static_library("weston_test") {
+ testonly = true
+ defines = [ "WESTON_TEST_IMPLEMENTATION" ]
+ deps = [
+ ":wayland",
+ "//base",
+ "//components/exo",
+ "//third_party/wayland:wayland_server",
+ "//third_party/wayland-protocols:weston_test",
+ "//ui/base:test_support",
+ "//ui/wm",
+ ]
+ sources = [ "weston_test.cc" ]
+ if (is_chromeos_ash) {
+ deps += [ "//ash" ]
}
}
+static_library("weston_test_stub") {
+ testonly = false
+ defines = [ "WESTON_TEST_IMPLEMENTATION" ]
+ sources = [ "weston_test_stub.cc" ]
+ deps = [ ":wayland" ]
+}
+
source_set("unit_tests") {
testonly = true
diff --git a/chromium/components/exo/wayland/clients/hdr.cc b/chromium/components/exo/wayland/clients/hdr.cc
index 026adbff93a..86efe8383cb 100644
--- a/chromium/components/exo/wayland/clients/hdr.cc
+++ b/chromium/components/exo/wayland/clients/hdr.cc
@@ -303,7 +303,7 @@ int main(int argc, char* argv[]) {
int32_t transfer1 = ZCR_COLOR_MANAGER_V1_EOTF_NAMES_SRGB;
// HDR BT2020, PQ, full range RGB
int32_t primary2 = ZCR_COLOR_MANAGER_V1_CHROMATICITY_NAMES_BT2020;
- int32_t transfer2 = ZCR_COLOR_MANAGER_V1_EOTF_NAMES_BT2087;
+ int32_t transfer2 = ZCR_COLOR_MANAGER_V1_EOTF_NAMES_PQ;
params.bo_usage =
GBM_BO_USE_SCANOUT | GBM_BO_USE_LINEAR | GBM_BO_USE_TEXTURING;
diff --git a/chromium/components/exo/wayland/protocol/aura-shell.xml b/chromium/components/exo/wayland/protocol/aura-shell.xml
index 9641ab1ab6b..d179af5413f 100644
--- a/chromium/components/exo/wayland/protocol/aura-shell.xml
+++ b/chromium/components/exo/wayland/protocol/aura-shell.xml
@@ -24,7 +24,7 @@
DEALINGS IN THE SOFTWARE.
</copyright>
- <interface name="zaura_shell" version="28">
+ <interface name="zaura_shell" version="29">
<description summary="aura_shell">
The global interface exposing aura shell capabilities is used to
instantiate an interface extension for a wl_surface object.
@@ -148,7 +148,7 @@
</request>
</interface>
- <interface name="zaura_surface" version="25">
+ <interface name="zaura_surface" version="29">
<description summary="aura shell interface to a wl_surface">
An additional interface to a wl_surface object, which allows the
client to access aura shell specific functionality for surface.
@@ -499,6 +499,17 @@
the window was locked with the trusted state or not.
</description>
</request>
+
+ <event name="start_throttle" since="29">
+ <description summary="start throttling on the surface">
+ Informs the client to start throttling on the surface.
+ </description>
+ </event>
+ <event name="end_throttle" since="29">
+ <description summary="end throttling on the surface">
+ Informs the client to end throttling on the surface.
+ </description>
+ </event>
</interface>
<interface name="zaura_output" version="6">
diff --git a/chromium/components/exo/wayland/protocol/chrome-color-management.xml b/chromium/components/exo/wayland/protocol/chrome-color-management.xml
index aa4a56d5fd8..458e5eff122 100644
--- a/chromium/components/exo/wayland/protocol/chrome-color-management.xml
+++ b/chromium/components/exo/wayland/protocol/chrome-color-management.xml
@@ -65,6 +65,7 @@
<entry name="srgb" value="2" summary="sRGB transfer function"/>
<entry name="bt2087" value="3" summary="BT.2087 transfer function"/>
<entry name="adobergb" value="4" summary="AdobeRGB transfer function"/>
+ <entry name="pq" value="5" summary="Perceptual quantizer / SMPTEST2084"/>
</enum>
<enum name="chromaticity_names">
diff --git a/chromium/components/exo/wayland/protocol/surface-augmenter.xml b/chromium/components/exo/wayland/protocol/surface-augmenter.xml
index 6730f07a219..66ec0556cf7 100644
--- a/chromium/components/exo/wayland/protocol/surface-augmenter.xml
+++ b/chromium/components/exo/wayland/protocol/surface-augmenter.xml
@@ -73,7 +73,9 @@
summary="the surface"/>
</request>
- <request name="get_augmented_subsurface">
+ <!-- Version 2 additions -->
+
+ <request name="get_augmented_subsurface" since="2">
<description summary="extend sub surface interface for delegation">
Instantiate an interface extension for the given wl_subsurface to
extend composition of its content. If the given wl_subsurface already has
@@ -130,7 +132,7 @@
</description>
<arg name="width" type="fixed" summary="width of the surface"/>
<arg name="height" type="fixed" summary="height of the surface"/>
- </request>\
+ </request>
<request name="set_rounded_clip_bounds" since="2">
<!-- Note that this might be moved to a different protocol if there is
diff --git a/chromium/components/exo/wayland/server.cc b/chromium/components/exo/wayland/server.cc
index 5f97d158ad3..1d0528734ad 100644
--- a/chromium/components/exo/wayland/server.cc
+++ b/chromium/components/exo/wayland/server.cc
@@ -79,6 +79,7 @@
#include <idle-inhibit-unstable-v1-server-protocol.h>
#include "ash/constants/ash_features.h"
#include "base/system/sys_info.h"
+#include "components/exo/wayland/weston_test.h"
#include "components/exo/wayland/wl_shell.h"
#include "components/exo/wayland/xdg_shell.h"
#include "components/exo/wayland/zcr_cursor_shapes.h"
@@ -101,11 +102,6 @@
#include "components/exo/wayland/zxdg_output_manager.h"
#include "components/exo/wayland/zxdg_shell.h"
-#if BUILDFLAG(ENABLE_WESTON_TEST)
-#include <weston-test-server-protocol.h>
-#include "components/exo/wayland/weston_test.h"
-#endif
-
#if BUILDFLAG(ENABLE_COLOR_MANAGER)
#include <chrome-color-management-server-protocol.h>
#include "components/exo/wayland/zcr_color_manager.h"
@@ -375,8 +371,8 @@ void Server::Initialize() {
&zwp_relative_pointer_manager_v1_interface, 1, display_,
bind_relative_pointer_manager);
#if BUILDFLAG(ENABLE_COLOR_MANAGER)
- wl_global_create(wl_display_.get(), &zcr_color_manager_v1_interface, 1,
- display_, bind_zcr_color_manager);
+ wl_global_create(wl_display_.get(), &zcr_color_manager_v1_interface, 1, this,
+ bind_zcr_color_manager);
#endif
wl_global_create(wl_display_.get(), &zxdg_decoration_manager_v1_interface, 1,
display_, bind_zxdg_decoration_manager);
@@ -389,12 +385,7 @@ void Server::Initialize() {
1, display_, bind_zwp_idle_inhibit_manager);
}
-#if BUILDFLAG(ENABLE_WESTON_TEST)
- weston_test_data_ = std::make_unique<WestonTestState>();
- wl_global_create(wl_display_.get(), &weston_test_interface,
- kWestonTestVersion, weston_test_data_.get(),
- bind_weston_test);
-#endif
+ weston_test_holder_ = std::make_unique<WestonTest>(this);
zcr_keyboard_extension_data_ =
std::make_unique<WaylandKeyboardExtension>(serial_tracker_.get());
diff --git a/chromium/components/exo/wayland/server.h b/chromium/components/exo/wayland/server.h
index 5630e7ef4e6..47c3cadd4bf 100644
--- a/chromium/components/exo/wayland/server.h
+++ b/chromium/components/exo/wayland/server.h
@@ -13,11 +13,10 @@
#include "base/files/file_path.h"
#include "base/files/scoped_temp_dir.h"
#include "base/time/time.h"
-#include "components/exo/wayland/scoped_wl.h"
-#include "ui/display/display_observer.h"
-
#include "build/chromeos_buildflags.h"
#include "components/exo/buildflags.h"
+#include "components/exo/wayland/scoped_wl.h"
+#include "ui/display/display_observer.h"
struct wl_resource;
struct wl_client;
@@ -38,7 +37,7 @@ struct WaylandTextInputManager;
struct WaylandXdgShell;
struct WaylandZxdgShell;
struct WaylandRemoteShellData;
-struct WestonTestState;
+class WestonTest;
class WaylandWatcher;
// This class is a thin wrapper around a Wayland display server. All Wayland
@@ -109,11 +108,14 @@ class Server : public display::DisplayObserver {
const base::FilePath& socket_path() const { return socket_path_; }
protected:
+ friend class WestonTest;
void AddWaylandOutput(int64_t id,
std::unique_ptr<WaylandDisplayOutput> output);
wl_display* GetWaylandDisplay() const { return wl_display_.get(); }
private:
+ friend class ScopedEventDispatchDisabler;
+
// This has the server's socket inside it, so it must be deleted last.
base::ScopedTempDir socket_dir_;
Display* const display_;
@@ -135,9 +137,7 @@ class Server : public display::DisplayObserver {
std::unique_ptr<WaylandZxdgShell> zxdg_shell_data_;
std::unique_ptr<WaylandXdgShell> xdg_shell_data_;
std::unique_ptr<WaylandRemoteShellData> remote_shell_data_;
-#if BUILDFLAG(ENABLE_WESTON_TEST)
- std::unique_ptr<WestonTestState> weston_test_data_;
-#endif
+ std::unique_ptr<WestonTest> weston_test_holder_;
#endif
};
diff --git a/chromium/components/exo/wayland/wayland_pointer_delegate.cc b/chromium/components/exo/wayland/wayland_pointer_delegate.cc
index 7bf9ffbbf37..8e705441e99 100644
--- a/chromium/components/exo/wayland/wayland_pointer_delegate.cc
+++ b/chromium/components/exo/wayland/wayland_pointer_delegate.cc
@@ -4,7 +4,7 @@
#include "components/exo/wayland/wayland_pointer_delegate.h"
-#include <linux/input.h>
+#include <linux/input-event-codes.h>
#include <wayland-server-core.h>
#include <wayland-server-protocol-core.h>
@@ -75,8 +75,8 @@ void WaylandPointerDelegate::OnPointerButton(base::TimeTicks time_stamp,
{ui::EF_LEFT_MOUSE_BUTTON, BTN_LEFT},
{ui::EF_RIGHT_MOUSE_BUTTON, BTN_RIGHT},
{ui::EF_MIDDLE_MOUSE_BUTTON, BTN_MIDDLE},
- {ui::EF_FORWARD_MOUSE_BUTTON, BTN_FORWARD},
- {ui::EF_BACK_MOUSE_BUTTON, BTN_BACK},
+ {ui::EF_FORWARD_MOUSE_BUTTON, BTN_EXTRA},
+ {ui::EF_BACK_MOUSE_BUTTON, BTN_SIDE},
};
for (auto button : buttons) {
if (button_flags & button.flag) {
diff --git a/chromium/components/exo/wayland/wayland_watcher.cc b/chromium/components/exo/wayland/wayland_watcher.cc
index 48a32ad26ff..44333b84873 100644
--- a/chromium/components/exo/wayland/wayland_watcher.cc
+++ b/chromium/components/exo/wayland/wayland_watcher.cc
@@ -12,16 +12,28 @@ namespace wayland {
WaylandWatcher::WaylandWatcher(wayland::Server* server)
: controller_(FROM_HERE), server_(server) {
- base::CurrentUIThread::Get()->WatchFileDescriptor(
- server_->GetFileDescriptor(),
- true, // persistent
- base::MessagePumpForUI::WATCH_READ, &controller_, this);
+ Start();
}
WaylandWatcher::~WaylandWatcher() {
controller_.StopWatchingFileDescriptor();
}
+void WaylandWatcher::StartForTesting() {
+ Start();
+}
+
+void WaylandWatcher::StopForTesting() {
+ controller_.StopWatchingFileDescriptor();
+}
+
+void WaylandWatcher::Start() {
+ base::CurrentUIThread::Get()->WatchFileDescriptor(
+ server_->GetFileDescriptor(),
+ true, // persistent
+ base::MessagePumpForUI::WATCH_READ, &controller_, this);
+}
+
void WaylandWatcher::OnFileCanReadWithoutBlocking(int fd) {
server_->Dispatch(base::TimeDelta());
server_->Flush();
diff --git a/chromium/components/exo/wayland/wayland_watcher.h b/chromium/components/exo/wayland/wayland_watcher.h
index 74bf4ca85ad..13ccbc275b5 100644
--- a/chromium/components/exo/wayland/wayland_watcher.h
+++ b/chromium/components/exo/wayland/wayland_watcher.h
@@ -22,7 +22,13 @@ class WaylandWatcher : public base::MessagePumpForUI::FdWatcher {
~WaylandWatcher() override;
+ // Start/Stop watching the fd for testing.
+ void StartForTesting();
+ void StopForTesting();
+
private:
+ void Start();
+
// base::MessagePumpForUI::FdWatcher:
void OnFileCanReadWithoutBlocking(int fd) override;
diff --git a/chromium/components/exo/wayland/weston_test.cc b/chromium/components/exo/wayland/weston_test.cc
index 68b7a793286..464754511ee 100644
--- a/chromium/components/exo/wayland/weston_test.cc
+++ b/chromium/components/exo/wayland/weston_test.cc
@@ -5,6 +5,7 @@
#include "components/exo/wayland/weston_test.h"
#include <linux/input.h>
+#include <stdint.h>
#include <wayland-server-core.h>
#include <weston-test-server-protocol.h>
@@ -12,7 +13,9 @@
#include "base/notreached.h"
#include "base/run_loop.h"
#include "components/exo/surface.h"
+#include "components/exo/wayland/server.h"
#include "components/exo/wayland/server_util.h"
+#include "components/exo/wayland/wayland_watcher.h"
#include "components/exo/wm_helper.h"
#include "components/exo/xkb_tracker.h"
#include "ui/base/test/ui_controls.h"
@@ -23,8 +26,48 @@
namespace exo {
namespace wayland {
+
+// Tracks button and mouse states for testing.
+struct WestonTest::WestonTestState {
+ explicit WestonTestState(Server* s) : server(s) {}
+
+ WestonTestState(const WestonTestState&) = delete;
+ WestonTestState& operator=(const WestonTestState&) = delete;
+
+ Server* server;
+
+ bool left_button_pressed = false;
+ bool middle_button_pressed = false;
+ bool right_button_pressed = false;
+
+ bool control_pressed = false;
+ bool alt_pressed = false;
+ bool shift_pressed = false;
+ bool command_pressed = false;
+};
+
+class ScopedEventDispatchDisabler {
+ public:
+ ScopedEventDispatchDisabler(Server* server) : server_(server) {
+ server_->wayland_watcher_->StopForTesting();
+ }
+ ScopedEventDispatchDisabler(const ScopedEventDispatchDisabler&) = delete;
+ ScopedEventDispatchDisabler& operator=(const ScopedEventDispatchDisabler&) =
+ delete;
+ ~ScopedEventDispatchDisabler() {
+ server_->wayland_watcher_->StartForTesting();
+ }
+
+ private:
+ Server* server_;
+};
+
namespace {
+using WestonTestState = WestonTest::WestonTestState;
+
+constexpr uint32_t kWestonTestVersion = 1;
+
static void weston_test_move_surface(struct wl_client* client,
struct wl_resource* resource,
struct wl_resource* surface_resource,
@@ -41,6 +84,8 @@ static void weston_test_move_pointer(struct wl_client* client,
uint32_t tv_nsec,
int32_t x,
int32_t y) {
+ auto* weston_test = GetUserDataAs<WestonTestState>(resource);
+
// Convert cursor point from window space to root space
gfx::Point point_in_root(x, y);
if (surface_resource) {
@@ -51,11 +96,14 @@ static void weston_test_move_pointer(struct wl_client* client,
base::RunLoop run_loop;
ui_controls::SendMouseMoveNotifyWhenDone(point_in_root.x(), point_in_root.y(),
run_loop.QuitClosure());
- run_loop.Run();
+ {
+ // Do not process incoming wayland events which may destroy resources.
+ ScopedEventDispatchDisabler disable(weston_test->server);
+ run_loop.Run();
+ }
+
// TODO(https://crbug.com/1284726): This should not be necessary.
- // At this point the resource could have been destroyed.
- if (GetUserDataAs<WestonTestState>(resource))
- weston_test_send_pointer_position(resource, x, y);
+ weston_test_send_pointer_position(resource, x, y);
}
static void weston_test_send_button(struct wl_client* client,
@@ -70,8 +118,8 @@ static void weston_test_send_button(struct wl_client* client,
DCHECK(button != BTN_BACK);
// Track mouse click state
- auto* weston_test = GetUserDataAs<WestonTestState>(resource);
ui_controls::MouseButton mouse_button = ui_controls::LEFT;
+ auto* weston_test = GetUserDataAs<WestonTestState>(resource);
switch (button) {
case BTN_LEFT:
mouse_button = ui_controls::LEFT;
@@ -95,17 +143,20 @@ static void weston_test_send_button(struct wl_client* client,
base::RunLoop run_loop;
ui_controls::SendMouseEventsNotifyWhenDone(mouse_button, mouse_state,
run_loop.QuitClosure());
- run_loop.Run();
-
+ {
+ // Do not process incoming wayland events which may destroy resources.
+ ScopedEventDispatchDisabler disable(weston_test->server);
+ run_loop.Run();
+ }
// TODO(https://crbug.com/1284726): This should not be necessary.
- // At this point the resource could have been destroyed.
- if (GetUserDataAs<WestonTestState>(resource))
- weston_test_send_pointer_button(resource, button, state);
+ weston_test_send_pointer_button(resource, button, state);
}
static void weston_test_reset_pointer(struct wl_client* client,
struct wl_resource* resource) {
auto* weston_test = GetUserDataAs<WestonTestState>(resource);
+ ScopedEventDispatchDisabler disable(weston_test->server);
+
if (weston_test->left_button_pressed) {
weston_test->left_button_pressed = false;
base::RunLoop run_loop;
@@ -113,11 +164,8 @@ static void weston_test_reset_pointer(struct wl_client* client,
ui_controls::LEFT, ui_controls::UP, run_loop.QuitClosure());
run_loop.Run();
// TODO(https://crbug.com/1284726): This should not be necessary.
- // At this point the resource could have been destroyed.
- if (GetUserDataAs<WestonTestState>(resource)) {
- weston_test_send_pointer_button(resource, BTN_LEFT,
- WL_POINTER_BUTTON_STATE_RELEASED);
- }
+ weston_test_send_pointer_button(resource, BTN_LEFT,
+ WL_POINTER_BUTTON_STATE_RELEASED);
}
if (weston_test->middle_button_pressed) {
weston_test->middle_button_pressed = false;
@@ -126,11 +174,8 @@ static void weston_test_reset_pointer(struct wl_client* client,
ui_controls::MIDDLE, ui_controls::UP, run_loop.QuitClosure());
run_loop.Run();
// TODO(https://crbug.com/1284726): This should not be necessary.
- // At this point the resource could have been destroyed.
- if (GetUserDataAs<WestonTestState>(resource)) {
- weston_test_send_pointer_button(resource, BTN_MIDDLE,
- WL_POINTER_BUTTON_STATE_RELEASED);
- }
+ weston_test_send_pointer_button(resource, BTN_MIDDLE,
+ WL_POINTER_BUTTON_STATE_RELEASED);
}
if (weston_test->right_button_pressed) {
weston_test->right_button_pressed = false;
@@ -139,11 +184,8 @@ static void weston_test_reset_pointer(struct wl_client* client,
ui_controls::RIGHT, ui_controls::UP, run_loop.QuitClosure());
run_loop.Run();
// TODO(https://crbug.com/1284726): This should not be necessary.
- // At this point the resource could have been destroyed.
- if (GetUserDataAs<WestonTestState>(resource)) {
- weston_test_send_pointer_button(resource, BTN_RIGHT,
- WL_POINTER_BUTTON_STATE_RELEASED);
- }
+ weston_test_send_pointer_button(resource, BTN_RIGHT,
+ WL_POINTER_BUTTON_STATE_RELEASED);
}
}
@@ -172,9 +214,10 @@ static void weston_test_send_key(struct wl_client* client,
uint32_t tv_nsec,
uint32_t key,
uint32_t state) {
- ui::DomCode dom_code = ui::KeycodeConverter::EvdevCodeToDomCode(key);
auto* weston_test = GetUserDataAs<WestonTestState>(resource);
+ ui::DomCode dom_code = ui::KeycodeConverter::EvdevCodeToDomCode(key);
+
// Get keyboard modifiers
switch (dom_code) {
case ui::DomCode::CONTROL_LEFT:
@@ -216,11 +259,13 @@ static void weston_test_send_key(struct wl_client* client,
weston_test->shift_pressed, weston_test->alt_pressed,
weston_test->command_pressed,
run_loop.QuitClosure());
- run_loop.Run();
- // TODO(https://crbug.com/1284726): This should not be necessary.
- // At this point the resource could have been destroyed.
- if (GetUserDataAs<WestonTestState>(resource))
- weston_test_send_keyboard_key(resource, key, state);
+ {
+ // Do not process incoming wayland events which may destroy resources.
+ ScopedEventDispatchDisabler disable(weston_test->server);
+ run_loop.Run();
+ }
+
+ weston_test_send_keyboard_key(resource, key, state);
}
static void weston_test_device_release(struct wl_client* client,
@@ -262,8 +307,6 @@ const struct weston_test_interface weston_test_implementation = {
weston_test_device_add, weston_test_capture_screenshot,
weston_test_send_touch};
-} // namespace
-
void bind_weston_test(wl_client* client,
void* data,
uint32_t version,
@@ -275,5 +318,15 @@ void bind_weston_test(wl_client* client,
nullptr);
}
+} // namespace
+
+WestonTest::WestonTest(Server* server)
+ : data_(std::make_unique<WestonTestState>(server)) {
+ wl_global_create(server->GetWaylandDisplay(), &weston_test_interface,
+ kWestonTestVersion, data_.get(), bind_weston_test);
+}
+
+WestonTest::~WestonTest() = default;
+
} // namespace wayland
} // namespace exo
diff --git a/chromium/components/exo/wayland/weston_test.h b/chromium/components/exo/wayland/weston_test.h
index 745280f39e1..8d93fcb6f58 100644
--- a/chromium/components/exo/wayland/weston_test.h
+++ b/chromium/components/exo/wayland/weston_test.h
@@ -5,39 +5,27 @@
#ifndef COMPONENTS_EXO_WAYLAND_WESTON_TEST_H_
#define COMPONENTS_EXO_WAYLAND_WESTON_TEST_H_
-#include <stdint.h>
+#include <memory>
-struct wl_client;
+#include "base/component_export.h"
namespace exo {
-class Display;
-
namespace wayland {
+class Server;
-// Tracks button and mouse states for testing.
-struct WestonTestState {
- WestonTestState() {}
-
- WestonTestState(const WestonTestState&) = delete;
- WestonTestState& operator=(const WestonTestState&) = delete;
+class COMPONENT_EXPORT(WESTON_TEST) WestonTest {
+ public:
+ explicit WestonTest(Server* server);
+ WestonTest(const WestonTest&) = delete;
+ WestonTest& operator=(const WestonTest&) = delete;
+ ~WestonTest();
- bool left_button_pressed = false;
- bool middle_button_pressed = false;
- bool right_button_pressed = false;
+ struct WestonTestState;
- bool control_pressed = false;
- bool alt_pressed = false;
- bool shift_pressed = false;
- bool command_pressed = false;
+ private:
+ std::unique_ptr<WestonTestState> data_;
};
-constexpr uint32_t kWestonTestVersion = 1;
-
-void bind_weston_test(wl_client* client,
- void* data,
- uint32_t version,
- uint32_t id);
-
} // namespace wayland
} // namespace exo
diff --git a/chromium/components/exo/wayland/weston_test_stub.cc b/chromium/components/exo/wayland/weston_test_stub.cc
new file mode 100644
index 00000000000..a69a9e361af
--- /dev/null
+++ b/chromium/components/exo/wayland/weston_test_stub.cc
@@ -0,0 +1,18 @@
+// Copyright 2021 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.
+
+#include "components/exo/wayland/weston_test.h"
+
+namespace exo {
+namespace wayland {
+class Server;
+
+struct WestonTest::WestonTestState {};
+
+WestonTest::WestonTest(Server* server) {}
+
+WestonTest::~WestonTest() = default;
+
+} // namespace wayland
+} // namespace exo
diff --git a/chromium/components/exo/wayland/zaura_shell.cc b/chromium/components/exo/wayland/zaura_shell.cc
index 25e27f7a1e9..ec37a2dbf86 100644
--- a/chromium/components/exo/wayland/zaura_shell.cc
+++ b/chromium/components/exo/wayland/zaura_shell.cc
@@ -591,6 +591,18 @@ void AuraSurface::OnDeskChanged(Surface* surface, int state) {
zaura_surface_send_desk_changed(resource_, state);
}
+void AuraSurface::ThrottleFrameRate(bool on) {
+ if (wl_resource_get_version(resource_) <
+ ZAURA_SURFACE_START_THROTTLE_SINCE_VERSION) {
+ return;
+ }
+ if (on)
+ zaura_surface_send_start_throttle(resource_);
+ else
+ zaura_surface_send_end_throttle(resource_);
+ wl_client_flush(wl_resource_get_client(resource_));
+}
+
void AuraSurface::MoveToDesk(int desk_index) {
constexpr int kToggleVisibleOnAllWorkspacesValue = -1;
if (desk_index == kToggleVisibleOnAllWorkspacesValue) {
diff --git a/chromium/components/exo/wayland/zaura_shell.h b/chromium/components/exo/wayland/zaura_shell.h
index 26ff224a6d5..3676965be35 100644
--- a/chromium/components/exo/wayland/zaura_shell.h
+++ b/chromium/components/exo/wayland/zaura_shell.h
@@ -21,7 +21,7 @@ class ShellSurfaceBase;
namespace wayland {
-constexpr uint32_t kZAuraShellVersion = 28;
+constexpr uint32_t kZAuraShellVersion = 29;
// Adds bindings to the Aura Shell. Normally this implies Ash on ChromeOS
// builds. On non-ChromeOS builds the protocol provides access to Aura windowing
@@ -73,6 +73,7 @@ class AuraSurface : public SurfaceObserver,
void OnWindowOcclusionChanged(Surface* surface) override;
void OnFrameLockingChanged(Surface* surface, bool lock) override;
void OnDeskChanged(Surface* surface, int state) override;
+ void ThrottleFrameRate(bool on) override;
// Overridden from ActivationChangeObserver:
void OnWindowActivating(ActivationReason reason,
diff --git a/chromium/components/exo/wayland/zcr_color_manager.cc b/chromium/components/exo/wayland/zcr_color_manager.cc
index b026431efb5..cc3d7a908e8 100644
--- a/chromium/components/exo/wayland/zcr_color_manager.cc
+++ b/chromium/components/exo/wayland/zcr_color_manager.cc
@@ -6,25 +6,180 @@
#include <chrome-color-management-server-protocol.h>
#include <wayland-server-core.h>
+#include <cstdint>
+#include <memory>
+#include "base/containers/fixed_flat_map.h"
#include "base/notreached.h"
+#include "base/strings/stringprintf.h"
+#include "components/exo/surface.h"
+#include "components/exo/surface_observer.h"
+#include "components/exo/wayland/server.h"
+#include "components/exo/wayland/server_util.h"
+#include "components/exo/wm_helper_chromeos.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "third_party/skia/include/core/SkColorSpace.h"
+#include "third_party/skia/include/third_party/skcms/skcms.h"
+#include "ui/gfx/color_space.h"
+#include "ui/gfx/display_color_spaces.h"
+#include "ui/gfx/geometry/triangle_f.h"
namespace exo {
namespace wayland {
namespace {
+#define PARAM_TO_FLOAT(x) (x / 10000.f)
+
+constexpr auto kDefaultColorSpace = gfx::ColorSpace::CreateSRGB();
+
+constexpr auto kChromaticityMap =
+ base::MakeFixedFlatMap<zcr_color_manager_v1_chromaticity_names,
+ gfx::ColorSpace::PrimaryID>(
+ {{ZCR_COLOR_MANAGER_V1_CHROMATICITY_NAMES_BT601_525_LINE,
+ gfx::ColorSpace::PrimaryID::SMPTE170M},
+ {ZCR_COLOR_MANAGER_V1_CHROMATICITY_NAMES_BT601_625_LINE,
+ gfx::ColorSpace::PrimaryID::BT470BG},
+ {ZCR_COLOR_MANAGER_V1_CHROMATICITY_NAMES_SMPTE170M,
+ gfx::ColorSpace::PrimaryID::SMPTE170M},
+ {ZCR_COLOR_MANAGER_V1_CHROMATICITY_NAMES_BT709,
+ gfx::ColorSpace::PrimaryID::BT709},
+ {ZCR_COLOR_MANAGER_V1_CHROMATICITY_NAMES_BT2020,
+ gfx::ColorSpace::PrimaryID::BT2020},
+ {ZCR_COLOR_MANAGER_V1_CHROMATICITY_NAMES_SRGB,
+ gfx::ColorSpace::PrimaryID::BT709},
+ {ZCR_COLOR_MANAGER_V1_CHROMATICITY_NAMES_DISPLAYP3,
+ gfx::ColorSpace::PrimaryID::P3},
+ {ZCR_COLOR_MANAGER_V1_CHROMATICITY_NAMES_ADOBERGB,
+ gfx::ColorSpace::PrimaryID::ADOBE_RGB}});
+
+constexpr auto kEotfMap =
+ base::MakeFixedFlatMap<zcr_color_manager_v1_eotf_names,
+ gfx::ColorSpace::TransferID>({
+ {ZCR_COLOR_MANAGER_V1_EOTF_NAMES_LINEAR,
+ gfx::ColorSpace::TransferID::LINEAR},
+ {ZCR_COLOR_MANAGER_V1_EOTF_NAMES_SRGB,
+ gfx::ColorSpace::TransferID::BT709},
+ {ZCR_COLOR_MANAGER_V1_EOTF_NAMES_BT2087,
+ gfx::ColorSpace::TransferID::GAMMA24},
+ {ZCR_COLOR_MANAGER_V1_EOTF_NAMES_ADOBERGB,
+ // This is ever so slightly inaccurate. The number ought to be
+ // 2.19921875f, not 2.2
+ gfx::ColorSpace::TransferID::GAMMA22},
+ {ZCR_COLOR_MANAGER_V1_EOTF_NAMES_PQ, gfx::ColorSpace::TransferID::PQ},
+ });
+
+// Wrapper around a |gfx::ColorSpace| that tracks additional data useful to the
+// protocol. These live as wayland resource data.
+class ColorManagerColorSpace {
+ public:
+ explicit ColorManagerColorSpace(gfx::ColorSpace color_space)
+ : color_space(color_space) {}
+ virtual ~ColorManagerColorSpace() = default;
+
+ const gfx::ColorSpace color_space;
+
+ virtual void SendColorSpaceInfo(wl_resource* color_space_resource) {
+ wl_resource_post_error(color_space_resource,
+ ZCR_COLOR_SPACE_V1_ERROR_NO_INFORMATION,
+ "No information available for color space");
+ }
+};
+
+class NameBasedColorSpace final : public ColorManagerColorSpace {
+ public:
+ explicit NameBasedColorSpace(
+ gfx::ColorSpace color_space,
+ zcr_color_manager_v1_chromaticity_names chromaticity,
+ zcr_color_manager_v1_eotf_names eotf,
+ zcr_color_manager_v1_whitepoint_names whitepoint)
+ : ColorManagerColorSpace(color_space),
+ chromaticity(chromaticity),
+ eotf(eotf),
+ whitepoint(whitepoint) {}
+
+ const zcr_color_manager_v1_chromaticity_names chromaticity;
+ const zcr_color_manager_v1_eotf_names eotf;
+ const zcr_color_manager_v1_whitepoint_names whitepoint;
+
+ void SendColorSpaceInfo(wl_resource* color_space_resource) override {
+ zcr_color_space_v1_send_names(color_space_resource, eotf, chromaticity,
+ whitepoint);
+ }
+};
+
+// Wrap a surface pointer and handle relevant events.
+// TODO(b/207031122): This class should also watch for display color space
+// changes and update clients.
+class ColorManagerSurface final : public SurfaceObserver {
+ public:
+ explicit ColorManagerSurface(Server* server,
+ wl_resource* color_manager_surface_resource,
+ Surface* surface)
+ : server_(server),
+ color_manager_surface_resource_(color_manager_surface_resource),
+ scoped_surface_(std::make_unique<ScopedSurface>(surface, this)) {}
+ ColorManagerSurface(ColorManagerSurface&) = delete;
+ ColorManagerSurface(ColorManagerSurface&&) = delete;
+ ~ColorManagerSurface() override = default;
+
+ // Safely set the color space (doing nothing if the surface was destroyed).
+ void SetColorSpace(gfx::ColorSpace color_space) {
+ Surface* surface = scoped_surface_->get();
+ if (!surface)
+ return;
+
+ surface->SetColorSpace(color_space);
+ }
+
+ private:
+ // SurfaceObserver:
+ void OnDisplayChanged(Surface* surface,
+ int64_t old_display,
+ int64_t new_display) override {
+ wl_client* client = wl_resource_get_client(color_manager_surface_resource_);
+ wl_resource* display_resource =
+ server_->GetOutputResource(client, new_display);
+
+ if (!display_resource)
+ return;
+
+ const auto* wm_helper = WMHelperChromeOS::GetInstance();
+
+ if (old_display != display::kInvalidDisplayId) {
+ const auto& old_display_info = wm_helper->GetDisplayInfo(old_display);
+ const auto& new_display_info = wm_helper->GetDisplayInfo(new_display);
+
+ if (old_display_info.display_color_spaces() ==
+ new_display_info.display_color_spaces())
+ return;
+ }
+
+ zcr_color_management_surface_v1_send_preferred_color_space(
+ color_manager_surface_resource_, display_resource);
+ }
+
+ void OnSurfaceDestroying(Surface* surface) override {
+ scoped_surface_.reset();
+ }
+
+ Server* server_;
+ wl_resource* color_manager_surface_resource_;
+ std::unique_ptr<ScopedSurface> scoped_surface_;
+};
+
////////////////////////////////////////////////////////////////////////////////
-// zcr_color_management_output_v1_interface:
+// zcr_color_management_color_space_v1_interface:
void color_space_get_information(struct wl_client* client,
- struct wl_resource* resource) {
- NOTIMPLEMENTED();
+ struct wl_resource* color_space_resource) {
+ GetUserDataAs<ColorManagerColorSpace>(color_space_resource)
+ ->SendColorSpaceInfo(color_space_resource);
}
void color_space_destroy(struct wl_client* client,
- struct wl_resource* resource) {
- wl_resource_destroy(resource);
+ struct wl_resource* color_space_resource) {
+ wl_resource_destroy(color_space_resource);
}
const struct zcr_color_space_v1_interface color_space_v1_implementation = {
@@ -33,9 +188,10 @@ const struct zcr_color_space_v1_interface color_space_v1_implementation = {
////////////////////////////////////////////////////////////////////////////////
// zcr_color_management_output_v1_interface:
-void color_management_output_get_color_space(struct wl_client* client,
- struct wl_resource* resource,
- uint32_t id) {
+void color_management_output_get_color_space(
+ struct wl_client* client,
+ struct wl_resource* color_management_output_resource,
+ uint32_t id) {
wl_resource* color_space_resource =
wl_resource_create(client, &zcr_color_space_v1_interface, 1, id);
@@ -44,9 +200,10 @@ void color_management_output_get_color_space(struct wl_client* client,
/*data=*/nullptr, /*destroy=*/nullptr);
}
-void color_management_output_destroy(struct wl_client* client,
- struct wl_resource* resource) {
- wl_resource_destroy(resource);
+void color_management_output_destroy(
+ struct wl_client* client,
+ struct wl_resource* color_management_output_resource) {
+ wl_resource_destroy(color_management_output_resource);
}
const struct zcr_color_management_output_v1_interface
@@ -57,32 +214,45 @@ const struct zcr_color_management_output_v1_interface
////////////////////////////////////////////////////////////////////////////////
// zcr_color_management_surface_v1_interface:
-void color_management_surface_set_alpha_mode(struct wl_client* client,
- struct wl_resource* resource,
- uint32_t alpha_mode) {
+void color_management_surface_set_alpha_mode(
+ struct wl_client* client,
+ struct wl_resource* color_management_surface_resource,
+ uint32_t alpha_mode) {
NOTIMPLEMENTED();
}
void color_management_surface_set_extended_dynamic_range(
struct wl_client* client,
- struct wl_resource* resource,
+ struct wl_resource* color_management_surface_resource,
uint32_t value) {
NOTIMPLEMENTED();
}
-void color_management_surface_set_color_space(struct wl_client* client,
- struct wl_resource* resource,
- struct wl_resource* color_space,
- uint32_t render_intent) {
- NOTIMPLEMENTED();
+
+void color_management_surface_set_color_space(
+ struct wl_client* client,
+ struct wl_resource* color_management_surface_resource,
+ struct wl_resource* color_space_resource,
+ uint32_t render_intent) {
+ auto* color_manager_color_space =
+ GetUserDataAs<ColorManagerColorSpace>(color_space_resource);
+ GetUserDataAs<ColorManagerSurface>(color_management_surface_resource)
+ ->SetColorSpace(color_manager_color_space->color_space);
}
+
void color_management_surface_set_default_color_space(
struct wl_client* client,
- struct wl_resource* resource) {
- NOTIMPLEMENTED();
+ struct wl_resource* color_management_surface_resource) {
+ GetUserDataAs<ColorManagerSurface>(color_management_surface_resource)
+ ->SetColorSpace(kDefaultColorSpace);
}
-void color_management_surface_destroy(struct wl_client* client,
- struct wl_resource* resource) {
- wl_resource_destroy(resource);
+
+void color_management_surface_destroy(
+ struct wl_client* client,
+ struct wl_resource* color_management_surface_resource) {
+ GetUserDataAs<ColorManagerSurface>(color_management_surface_resource)
+ ->SetColorSpace(kDefaultColorSpace);
+
+ wl_resource_destroy(color_management_surface_resource);
}
const struct zcr_color_management_surface_v1_interface
@@ -96,46 +266,156 @@ const struct zcr_color_management_surface_v1_interface
////////////////////////////////////////////////////////////////////////////////
// zcr_color_manager_v1_interface:
-void color_manager_create_color_space_from_icc(struct wl_client* client,
- struct wl_resource* resource,
- uint32_t id,
- int32_t icc) {
- NOTIMPLEMENTED();
+void CreateColorSpace(struct wl_client* client,
+ int32_t color_space_creator_id,
+ std::unique_ptr<ColorManagerColorSpace> color_space) {
+ wl_resource* color_space_resource = wl_resource_create(
+ client, &zcr_color_space_v1_interface, /*version=*/1, /*id=*/0);
+ SetImplementation(color_space_resource, &color_space_v1_implementation,
+ std::move(color_space));
+
+ wl_resource* color_space_creator_resource =
+ wl_resource_create(client, &zcr_color_space_creator_v1_interface,
+ /*version=*/1, color_space_creator_id);
+ zcr_color_space_creator_v1_send_created(color_space_creator_resource,
+ color_space_resource);
+ // The resource should be immediately destroyed once it's sent its event.
+ wl_resource_destroy(color_space_creator_resource);
}
-void color_manager_create_color_space_from_names(struct wl_client* client,
- struct wl_resource* resource,
- uint32_t id,
- uint32_t eotf,
- uint32_t chromaticity,
- uint32_t whitepoint) {
- wl_resource* color_space_resource =
- wl_resource_create(client, &zcr_color_space_v1_interface, 1, id);
+void SendColorCreationError(struct wl_client* client,
+ int32_t color_space_creator_id,
+ int32_t error_flags) {
+ wl_resource* color_space_creator_resource = wl_resource_create(
+ client, &zcr_color_space_creator_v1_interface, 1, color_space_creator_id);
- wl_resource_set_implementation(color_space_resource,
- &color_space_v1_implementation,
- /*data=*/nullptr, /*destroy=*/nullptr);
+ zcr_color_space_creator_v1_send_error(color_space_creator_resource,
+ error_flags);
+
+ // The resource should be immediately destroyed once it's sent its event.
+ wl_resource_destroy(color_space_creator_resource);
}
-void color_manager_create_color_space_from_params(struct wl_client* client,
- struct wl_resource* resource,
- uint32_t id,
- uint32_t eotf,
- uint32_t primary_r_x,
- uint32_t primary_r_y,
- uint32_t primary_g_x,
- uint32_t primary_g_y,
- uint32_t primary_b_x,
- uint32_t primary_b_y,
- uint32_t white_point_x,
- uint32_t white_point_y) {
+void color_manager_create_color_space_from_icc(
+ struct wl_client* client,
+ struct wl_resource* color_manager_resource,
+ uint32_t id,
+ int32_t icc) {
NOTIMPLEMENTED();
}
-void color_manager_get_color_management_output(struct wl_client* client,
- struct wl_resource* resource,
- uint32_t id,
- struct wl_resource* output) {
+// TODO(b/206971557): This doesn't handle the user-set white point yet.
+void color_manager_create_color_space_from_names(
+ struct wl_client* client,
+ struct wl_resource* color_manager_resource,
+ uint32_t id,
+ uint32_t eotf,
+ uint32_t chromaticity,
+ uint32_t whitepoint) {
+ uint32_t error_flags = 0;
+
+ auto chromaticity_id = gfx::ColorSpace::PrimaryID::INVALID;
+ const auto* maybe_primary = kChromaticityMap.find(chromaticity);
+ if (maybe_primary != std::end(kChromaticityMap)) {
+ chromaticity_id = maybe_primary->second;
+ } else {
+ DLOG(ERROR) << "Unable to find named chromaticity for id=" << chromaticity;
+ error_flags |= ZCR_COLOR_SPACE_CREATOR_V1_CREATION_ERROR_BAD_PRIMARIES;
+ }
+
+ auto eotf_id = gfx::ColorSpace::TransferID::INVALID;
+ const auto* maybe_eotf = kEotfMap.find(eotf);
+ if (maybe_eotf != std::end(kEotfMap)) {
+ eotf_id = maybe_eotf->second;
+ } else {
+ DLOG(ERROR) << "Unable to find named eotf for id=" << eotf;
+ wl_resource_post_error(color_manager_resource,
+ ZCR_COLOR_MANAGER_V1_ERROR_BAD_ENUM,
+ "Unable to find an EOTF matching %d", eotf);
+ }
+
+ if (error_flags)
+ SendColorCreationError(client, id, error_flags);
+
+ CreateColorSpace(
+ client, id,
+ std::make_unique<NameBasedColorSpace>(
+ gfx::ColorSpace(chromaticity_id, eotf_id),
+ static_cast<zcr_color_manager_v1_chromaticity_names>(chromaticity),
+ static_cast<zcr_color_manager_v1_eotf_names>(eotf),
+ static_cast<zcr_color_manager_v1_whitepoint_names>(whitepoint)));
+}
+
+void color_manager_create_color_space_from_params(
+ struct wl_client* client,
+ struct wl_resource* color_manager_resource,
+ uint32_t id,
+ uint32_t eotf,
+ uint32_t primary_r_x,
+ uint32_t primary_r_y,
+ uint32_t primary_g_x,
+ uint32_t primary_g_y,
+ uint32_t primary_b_x,
+ uint32_t primary_b_y,
+ uint32_t white_point_x,
+ uint32_t white_point_y) {
+ SkColorSpacePrimaries primaries = {
+ PARAM_TO_FLOAT(primary_r_x), PARAM_TO_FLOAT(primary_r_y),
+ PARAM_TO_FLOAT(primary_g_x), PARAM_TO_FLOAT(primary_g_y),
+ PARAM_TO_FLOAT(primary_b_x), PARAM_TO_FLOAT(primary_b_y),
+ PARAM_TO_FLOAT(white_point_x), PARAM_TO_FLOAT(white_point_y)};
+
+ gfx::PointF r(primaries.fRX, primaries.fRY);
+ gfx::PointF g(primaries.fGX, primaries.fGY);
+ gfx::PointF b(primaries.fBX, primaries.fBY);
+ gfx::PointF w(primaries.fWX, primaries.fWY);
+ if (!gfx::PointIsInTriangle(w, r, g, b)) {
+ auto error_message = base::StringPrintf(
+ "White point %s must be inside of the triangle r=%s g=%s b=%s",
+ w.ToString().c_str(), r.ToString().c_str(), g.ToString().c_str(),
+ b.ToString().c_str());
+ DLOG(ERROR) << error_message;
+ wl_resource_post_error(color_manager_resource,
+ ZCR_COLOR_MANAGER_V1_ERROR_BAD_PARAM, "%s",
+ error_message.c_str());
+ return;
+ }
+
+ auto eotf_id = gfx::ColorSpace::TransferID::INVALID;
+ const auto* maybe_eotf = kEotfMap.find(eotf);
+ if (maybe_eotf != std::end(kEotfMap)) {
+ eotf_id = maybe_eotf->second;
+ } else {
+ DLOG(ERROR) << "Unable to find named transfer function for id=" << eotf;
+ wl_resource_post_error(color_manager_resource,
+ ZCR_COLOR_MANAGER_V1_ERROR_BAD_ENUM,
+ "Unable to find an EOTF matching %d", eotf);
+ return;
+ }
+
+ skcms_Matrix3x3 xyzd50 = {};
+ if (!primaries.toXYZD50(&xyzd50)) {
+ DLOG(ERROR) << base::StringPrintf(
+ "Unable to translate color space primaries to XYZD50: "
+ "{%f, %f, %f, %f, %f, %f, %f, %f}",
+ primaries.fRX, primaries.fRY, primaries.fGX, primaries.fGY,
+ primaries.fBX, primaries.fBY, primaries.fWX, primaries.fWY);
+
+ SendColorCreationError(
+ client, id, ZCR_COLOR_SPACE_CREATOR_V1_CREATION_ERROR_BAD_PRIMARIES);
+ return;
+ }
+
+ CreateColorSpace(client, id,
+ std::make_unique<ColorManagerColorSpace>(
+ gfx::ColorSpace::CreateCustom(xyzd50, eotf_id)));
+}
+
+void color_manager_get_color_management_output(
+ struct wl_client* client,
+ struct wl_resource* color_manager_resource,
+ uint32_t id,
+ struct wl_resource* output) {
wl_resource* color_management_output_resource = wl_resource_create(
client, &zcr_color_management_output_v1_interface, 1, id);
@@ -144,21 +424,25 @@ void color_manager_get_color_management_output(struct wl_client* client,
/*data=*/nullptr, /*destroy=*/nullptr);
}
-void color_manager_get_color_management_surface(struct wl_client* client,
- struct wl_resource* resource,
- uint32_t id,
- struct wl_resource* surface) {
+void color_manager_get_color_management_surface(
+ struct wl_client* client,
+ struct wl_resource* color_manager_resource,
+ uint32_t id,
+ struct wl_resource* surface_resource) {
wl_resource* color_management_surface_resource = wl_resource_create(
client, &zcr_color_management_surface_v1_interface, 1, id);
- wl_resource_set_implementation(color_management_surface_resource,
- &color_management_surface_v1_implementation,
- /*data=*/nullptr, /*destroy=*/nullptr);
+ SetImplementation(color_management_surface_resource,
+ &color_management_surface_v1_implementation,
+ std::make_unique<ColorManagerSurface>(
+ GetUserDataAs<Server>(color_manager_resource),
+ color_management_surface_resource,
+ GetUserDataAs<Surface>(surface_resource)));
}
void color_manager_destroy(struct wl_client* client,
- struct wl_resource* resource) {
- wl_resource_destroy(resource);
+ struct wl_resource* color_manager_resource) {
+ wl_resource_destroy(color_manager_resource);
}
const struct zcr_color_manager_v1_interface color_manager_v1_implementation = {
@@ -168,17 +452,19 @@ const struct zcr_color_manager_v1_interface color_manager_v1_implementation = {
color_manager_get_color_management_output,
color_manager_get_color_management_surface,
color_manager_destroy};
+
} // namespace
void bind_zcr_color_manager(wl_client* client,
void* data,
uint32_t version,
uint32_t id) {
- wl_resource* resource =
+ wl_resource* color_manager_resource =
wl_resource_create(client, &zcr_color_manager_v1_interface, version, id);
- wl_resource_set_implementation(resource, &color_manager_v1_implementation,
- data, /*destroy=*/nullptr);
+ wl_resource_set_implementation(color_manager_resource,
+ &color_manager_v1_implementation, data,
+ /*destroy=*/nullptr);
}
} // namespace wayland
diff --git a/chromium/components/exo/wayland/zcr_color_manager.h b/chromium/components/exo/wayland/zcr_color_manager.h
index a8222e94326..7ab174f95d0 100644
--- a/chromium/components/exo/wayland/zcr_color_manager.h
+++ b/chromium/components/exo/wayland/zcr_color_manager.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef COMPONENTS_EXO_WAYLAND_ZWP_COLOR_MANAGER_H_
-#define COMPONENTS_EXO_WAYLAND_ZWP_COLOR_MANAGER_H_
+#ifndef COMPONENTS_EXO_WAYLAND_ZCR_COLOR_MANAGER_H_
+#define COMPONENTS_EXO_WAYLAND_ZCR_COLOR_MANAGER_H_
#include <stdint.h>
@@ -20,4 +20,4 @@ void bind_zcr_color_manager(wl_client* client,
} // namespace wayland
} // namespace exo
-#endif // COMPONENTS_EXO_WAYLAND_ZWP_COLOR_MANAGER_H_
+#endif // COMPONENTS_EXO_WAYLAND_ZCR_COLOR_MANAGER_H_
diff --git a/chromium/components/exo/wayland/zcr_remote_shell.cc b/chromium/components/exo/wayland/zcr_remote_shell.cc
index 9495622a6fb..a3e6365a7c1 100644
--- a/chromium/components/exo/wayland/zcr_remote_shell.cc
+++ b/chromium/components/exo/wayland/zcr_remote_shell.cc
@@ -134,7 +134,6 @@ const WaylandRemoteShellEventMapping wayland_remote_shell_event_mapping_v1 = {
ZCR_REMOTE_SHELL_V1_DEFAULT_DEVICE_SCALE_FACTOR_SINCE_VERSION,
ZCR_REMOTE_SURFACE_V1_CHANGE_ZOOM_LEVEL_SINCE_VERSION,
ZCR_REMOTE_SHELL_V1_WORKSPACE_INFO_SINCE_VERSION,
- ZCR_REMOTE_SURFACE_V1_BOUNDS_CHANGED_IN_OUTPUT_SINCE_VERSION,
ZCR_REMOTE_SHELL_V1_SET_USE_DEFAULT_DEVICE_SCALE_CANCELLATION_SINCE_VERSION,
};
diff --git a/chromium/components/exo/wayland/zcr_remote_shell_event_mapping.h b/chromium/components/exo/wayland/zcr_remote_shell_event_mapping.h
index c01faf8aab4..e5f6e794fd0 100644
--- a/chromium/components/exo/wayland/zcr_remote_shell_event_mapping.h
+++ b/chromium/components/exo/wayland/zcr_remote_shell_event_mapping.h
@@ -100,7 +100,6 @@ struct WaylandRemoteShellEventMapping {
int default_device_scale_factor_since_version;
int change_zoom_level_since_version;
int send_workspace_info_since_version;
- int send_bounds_changed_since_version;
int set_use_default_scale_cancellation_since_version;
};
diff --git a/chromium/components/exo/wayland/zcr_remote_shell_impl.cc b/chromium/components/exo/wayland/zcr_remote_shell_impl.cc
index 253a073d19d..ae1f21f8fda 100644
--- a/chromium/components/exo/wayland/zcr_remote_shell_impl.cc
+++ b/chromium/components/exo/wayland/zcr_remote_shell_impl.cc
@@ -434,6 +434,7 @@ WaylandRemoteShell::WaylandRemoteShell(
WMHelperChromeOS* helper = WMHelperChromeOS::GetInstance();
helper->AddTabletModeObserver(this);
helper->AddFrameThrottlingObserver();
+ helper->SetDefaultScaleCancellation(use_default_scale_cancellation_);
layout_mode_ = helper->InTabletMode()
? ZCR_REMOTE_SHELL_V1_LAYOUT_MODE_TABLET
@@ -773,33 +774,15 @@ void WaylandRemoteShell::OnRemoteSurfaceBoundsChanged(
}
}
- if (wl_resource_get_version(resource) >=
- event_mapping_.send_bounds_changed_since_version) {
- if (needs_send_display_metrics_) {
- // We store only the latest bounds for each |resource|.
- pending_bounds_changes_.insert_or_assign(
- std::move(resource),
- BoundsChangeData(display_id, bounds_in_display, reason));
- return;
- }
- SendBoundsChanged(resource, display_id, bounds_in_display, reason);
- } else {
- gfx::Rect bounds_in_screen = gfx::Rect(bounds_in_display);
- display::Display display;
- display::Screen::GetScreen()->GetDisplayWithDisplayId(display_id, &display);
- // The display ID should be valid.
- DCHECK(display.is_valid());
- if (display.is_valid())
- bounds_in_screen.Offset(display.bounds().OffsetFromOrigin());
- else
- LOG(ERROR) << "Invalid Display in send_bounds_changed:" << display_id;
-
- event_mapping_.send_bounds_changed(
- resource, static_cast<uint32_t>(display_id >> 32),
- static_cast<uint32_t>(display_id), bounds_in_screen.x(),
- bounds_in_screen.y(), bounds_in_screen.width(),
- bounds_in_screen.height(), reason);
+ if (needs_send_display_metrics_) {
+ // We store only the latest bounds for each |resource|.
+ pending_bounds_changes_.insert_or_assign(
+ std::move(resource),
+ BoundsChangeData(display_id, bounds_in_display, reason));
+ return;
}
+ SendBoundsChanged(resource, display_id, bounds_in_display, reason);
+
wl_client_flush(wl_resource_get_client(resource));
}
diff --git a/chromium/components/exo/wayland/zcr_remote_shell_impl_unittest.cc b/chromium/components/exo/wayland/zcr_remote_shell_impl_unittest.cc
index 1b7c1882307..907350928b7 100644
--- a/chromium/components/exo/wayland/zcr_remote_shell_impl_unittest.cc
+++ b/chromium/components/exo/wayland/zcr_remote_shell_impl_unittest.cc
@@ -61,8 +61,11 @@ class WaylandRemoteShellTest : public test::ExoTestBase {
wl_display_.reset(wl_display_create());
wl_client_.reset(wl_client_create(wl_display_.get(), reader_.release()));
- wl_shell_resource_.reset(wl_resource_create(
- wl_client_.get(), &zcr_remote_shell_v2_interface, 1, 1));
+ // Use 0 as the id here to avoid the id conflict (i.e. let wayland library
+ // choose the id from available ids.) Otherwise that will cause memory leak.
+ wl_shell_resource_.reset(wl_resource_create(wl_client_.get(),
+ &zcr_remote_shell_v2_interface,
+ /*version=*/1, /*id=*/0));
display_ = std::make_unique<Display>();
shell_ = std::make_unique<WaylandRemoteShell>(
@@ -172,7 +175,6 @@ class WaylandRemoteShellTest : public test::ExoTestBase {
/*default_device_scale_factor_since_version=*/0,
/*change_zoom_level_since_version=*/0,
/*send_workspace_info_since_version=*/0,
- /*send_bounds_changed_since_version=*/0,
/*set_use_default_scale_cancellation_since_version=*/0,
};
};
@@ -191,8 +193,8 @@ TEST_F(WaylandRemoteShellTest, DeferBoundsChangeWhileTabletTransition) {
auto shell_surface =
exo_test_helper()->CreateClientControlledShellSurface(surface.get());
- ScopedWlResource wl_res(
- wl_resource_create(wl_client(), &zcr_remote_surface_v2_interface, 1, 1));
+ ScopedWlResource wl_res(wl_resource_create(
+ wl_client(), &zcr_remote_surface_v2_interface, /*version=*/1, /*id=*/0));
shell_surface->set_delegate(
shell()->CreateShellSurfaceDelegate(wl_res.get()));
@@ -229,8 +231,8 @@ TEST_F(WaylandRemoteShellTest, DesktopFocusState) {
auto shell_surface =
exo_test_helper()->CreateClientControlledShellSurface(surface.get());
- ScopedWlResource wl_res(
- wl_resource_create(wl_client(), &zcr_remote_surface_v2_interface, 1, 1));
+ ScopedWlResource wl_res(wl_resource_create(
+ wl_client(), &zcr_remote_surface_v2_interface, /*version=*/1, /*id=*/0));
shell_surface->set_delegate(
shell()->CreateShellSurfaceDelegate(wl_res.get()));
SetSurfaceResource(surface.get(), wl_res.get());
diff --git a/chromium/components/exo/wayland/zcr_remote_shell_v2.cc b/chromium/components/exo/wayland/zcr_remote_shell_v2.cc
index 8d7196ff469..132e9d3ca12 100644
--- a/chromium/components/exo/wayland/zcr_remote_shell_v2.cc
+++ b/chromium/components/exo/wayland/zcr_remote_shell_v2.cc
@@ -60,7 +60,6 @@ const WaylandRemoteShellEventMapping wayland_remote_shell_event_mapping_v2 = {
1,
1,
1,
- 1,
};
const struct zcr_remote_surface_v2_interface remote_surface_implementation_v2 =
diff --git a/chromium/components/exo/wayland/zcr_touchpad_haptics.cc b/chromium/components/exo/wayland/zcr_touchpad_haptics.cc
index d829bf6e158..4c44948dfdd 100644
--- a/chromium/components/exo/wayland/zcr_touchpad_haptics.cc
+++ b/chromium/components/exo/wayland/zcr_touchpad_haptics.cc
@@ -8,10 +8,70 @@
#include <wayland-server-core.h>
#include <wayland-server-protocol-core.h>
+#include "base/feature_list.h"
+#include "base/logging.h"
+#include "components/exo/wayland/server_util.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "ui/events/devices/haptic_touchpad_effects.h"
+#include "ui/ozone/public/input_controller.h"
+#include "ui/ozone/public/ozone_platform.h"
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "ash/constants/ash_features.h"
+#endif
+
namespace exo {
namespace wayland {
namespace {
+class WaylandTouchpadHapticsDelegate {
+ public:
+ explicit WaylandTouchpadHapticsDelegate(wl_resource* resource)
+ : resource_{resource} {}
+ ~WaylandTouchpadHapticsDelegate() = default;
+
+ void UpdateTouchpadHapticsState() {
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+ if (!base::FeatureList::IsEnabled(
+ chromeos::features::kExoHapticFeedbackSupport))
+ return;
+#endif
+
+ ui::InputController* controller =
+ ui::OzonePlatform::GetInstance()->GetInputController();
+ if (!controller) {
+ LOG(ERROR) << "InputController is not available.";
+ return;
+ }
+ if (last_activation_state_ &&
+ *last_activation_state_ == controller->HasHapticTouchpad()) {
+ // No need to send the update.
+ return;
+ }
+ last_activation_state_ = controller->HasHapticTouchpad();
+ if (*last_activation_state_)
+ zcr_touchpad_haptics_v1_send_activated(resource_);
+ else
+ zcr_touchpad_haptics_v1_send_deactivated(resource_);
+ }
+
+ void Play(uint32_t effect, int32_t strength) {
+ ui::InputController* controller =
+ ui::OzonePlatform::GetInstance()->GetInputController();
+ if (!controller) {
+ LOG(ERROR) << "InputController is not available.";
+ return;
+ }
+ controller->PlayHapticTouchpadEffect(
+ static_cast<ui::HapticTouchpadEffect>(effect),
+ static_cast<ui::HapticTouchpadEffectStrength>(strength));
+ }
+
+ private:
+ wl_resource* const resource_;
+ absl::optional<bool> last_activation_state_;
+};
+
void touchpad_haptics_destroy(wl_client* client, wl_resource* resource) {
wl_resource_destroy(resource);
}
@@ -20,7 +80,13 @@ void touchpad_haptics_play(wl_client* client,
wl_resource* resource,
uint32_t effect,
int32_t strength) {
- // TODO(b/205702807): Call InputController::PlayHapticTouchpadEffect.
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+ if (!base::FeatureList::IsEnabled(
+ chromeos::features::kExoHapticFeedbackSupport))
+ return;
+#endif
+ GetUserDataAs<WaylandTouchpadHapticsDelegate>(resource)->Play(effect,
+ strength);
}
const struct zcr_touchpad_haptics_v1_interface touchpad_haptics_implementation =
@@ -38,8 +104,10 @@ void bind_touchpad_haptics(wl_client* client,
wl_resource* resource = wl_resource_create(
client, &zcr_touchpad_haptics_v1_interface, version, id);
- wl_resource_set_implementation(resource, &touchpad_haptics_implementation,
- nullptr, nullptr);
+ SetImplementation(resource, &touchpad_haptics_implementation,
+ std::make_unique<WaylandTouchpadHapticsDelegate>(resource));
+ GetUserDataAs<WaylandTouchpadHapticsDelegate>(resource)
+ ->UpdateTouchpadHapticsState();
}
} // namespace wayland
diff --git a/chromium/components/exo/wayland/zwp_linux_dmabuf.cc b/chromium/components/exo/wayland/zwp_linux_dmabuf.cc
index be54e2f28fc..aa3973fe0b4 100644
--- a/chromium/components/exo/wayland/zwp_linux_dmabuf.cc
+++ b/chromium/components/exo/wayland/zwp_linux_dmabuf.cc
@@ -8,6 +8,7 @@
#include <linux-dmabuf-unstable-v1-server-protocol.h>
#include "base/bind.h"
+#include "base/containers/contains.h"
#include "components/exo/buffer.h"
#include "components/exo/display.h"
#include "components/exo/wayland/server_util.h"
@@ -37,14 +38,16 @@ void HandleBufferReleaseCallback(wl_resource* resource) {
const struct dmabuf_supported_format {
uint32_t dmabuf_format;
gfx::BufferFormat buffer_format;
-} dmabuf_supported_formats[] = {
+} kSupportedDmaBufFormats[] = {
{DRM_FORMAT_RGB565, gfx::BufferFormat::BGR_565},
{DRM_FORMAT_XBGR8888, gfx::BufferFormat::RGBX_8888},
{DRM_FORMAT_ABGR8888, gfx::BufferFormat::RGBA_8888},
{DRM_FORMAT_XRGB8888, gfx::BufferFormat::BGRX_8888},
{DRM_FORMAT_ARGB8888, gfx::BufferFormat::BGRA_8888},
{DRM_FORMAT_NV12, gfx::BufferFormat::YUV_420_BIPLANAR},
- {DRM_FORMAT_YVU420, gfx::BufferFormat::YVU_420}};
+ {DRM_FORMAT_YVU420, gfx::BufferFormat::YVU_420},
+ {DRM_FORMAT_ABGR2101010, gfx::BufferFormat::RGBA_1010102},
+ {DRM_FORMAT_ARGB2101010, gfx::BufferFormat::BGRA_1010102}};
struct LinuxBufferParams {
struct Plane {
@@ -78,10 +81,10 @@ void linux_buffer_params_add(wl_client* client,
const uint64_t modifier = (static_cast<uint64_t>(modifier_hi) << 32) | modifier_lo;
LinuxBufferParams::Plane plane{base::ScopedFD(fd), stride, offset, modifier};
- const auto& inserted = linux_buffer_params->planes.insert(
- std::pair<uint32_t, LinuxBufferParams::Plane>(plane_idx,
- std::move(plane)));
- if (!inserted.second) { // The plane was already there.
+ bool inserted = linux_buffer_params->planes
+ .insert(std::make_pair(plane_idx, std::move(plane)))
+ .second;
+ if (!inserted) { // The plane was already there.
wl_resource_post_error(resource, ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_PLANE_SET,
"plane already set");
}
@@ -119,8 +122,7 @@ bool ValidateLinuxBufferParams(wl_resource* resource,
// Validate that we have planes 0..num_planes-1
for (uint32_t i = 0; i < num_planes; ++i) {
- auto plane_it = linux_buffer_params->planes.find(i);
- if (plane_it == linux_buffer_params->planes.end()) {
+ if (!base::Contains(linux_buffer_params->planes, i)) {
wl_resource_post_error(resource,
ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE,
"missing a plane");
@@ -150,11 +152,11 @@ wl_resource* create_buffer(wl_client* client,
uint32_t format,
uint32_t flags) {
const auto* supported_format = std::find_if(
- std::begin(dmabuf_supported_formats), std::end(dmabuf_supported_formats),
+ std::begin(kSupportedDmaBufFormats), std::end(kSupportedDmaBufFormats),
[format](const dmabuf_supported_format& supported_format) {
return supported_format.dmabuf_format == format;
});
- if (supported_format == std::end(dmabuf_supported_formats)) {
+ if (supported_format == std::end(kSupportedDmaBufFormats)) {
wl_resource_post_error(resource,
ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_FORMAT,
"format not supported");
@@ -162,8 +164,9 @@ wl_resource* create_buffer(wl_client* client,
}
if (!ValidateLinuxBufferParams(resource, width, height,
- supported_format->buffer_format, flags))
+ supported_format->buffer_format, flags)) {
return nullptr;
+ }
LinuxBufferParams* linux_buffer_params =
GetUserDataAs<LinuxBufferParams>(resource);
@@ -279,7 +282,7 @@ void bind_linux_dmabuf(wl_client* client,
wl_resource_set_implementation(resource, &linux_dmabuf_implementation, data,
nullptr);
- for (const auto& supported_format : dmabuf_supported_formats)
+ for (const auto& supported_format : kSupportedDmaBufFormats)
zwp_linux_dmabuf_v1_send_format(resource, supported_format.dmabuf_format);
}
diff --git a/chromium/components/exo/wayland/zwp_pointer_constraints.cc b/chromium/components/exo/wayland/zwp_pointer_constraints.cc
index 2bddf4a89c9..8bcda6b066f 100644
--- a/chromium/components/exo/wayland/zwp_pointer_constraints.cc
+++ b/chromium/components/exo/wayland/zwp_pointer_constraints.cc
@@ -21,6 +21,14 @@ namespace wayland {
namespace {
+// Implements a PointerConstraintDelegate in terms of the zwp_locked_pointer
+// Wayland protocol.
+//
+// Lifetime note: The underlying Wayland protocol gives control over this
+// object's lifetime to the client. However, it's possible that its
+// dependencies could be destroyed prior to the client destroying it.
+// At this point we consider the object "defunct" and its |surface_| member
+// to be potentially dangling. |pointer_| is correctly nulled when appropriate.
class WaylandPointerConstraintDelegate : public PointerConstraintDelegate {
public:
WaylandPointerConstraintDelegate(wl_resource* constraint_resource,
@@ -30,43 +38,56 @@ class WaylandPointerConstraintDelegate : public PointerConstraintDelegate {
uint32_t lifetime)
: constraint_resource_(constraint_resource),
pointer_(pointer),
- surface_(surface) {
- if (pointer->ConstrainPointer(this))
- EnableConstraint();
- else
- pointer_ = nullptr;
+ surface_(surface),
+ is_persistent_(lifetime ==
+ ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT) {
+ pointer->ConstrainPointer(this);
}
~WaylandPointerConstraintDelegate() override {
- if (pointer_)
- pointer_->UnconstrainPointer();
+ if (pointer_) {
+ pointer_->OnPointerConstraintDelegateDestroying(this);
+ pointer_ = nullptr;
+ }
}
- void OnConstraintBroken() override {
- DisableConstraint();
- pointer_ = nullptr;
+ // PointerConstraintDelegate::
+ void OnConstraintActivated() override { SendLocked(); }
+ void OnAlreadyConstrained() override {
+ wl_resource_post_error(
+ constraint_resource_,
+ ZWP_POINTER_CONSTRAINTS_V1_ERROR_ALREADY_CONSTRAINED,
+ "A pointer constraint was already requested for this wl_pointer "
+ "on this wl_surface.");
}
-
+ void OnConstraintBroken() override { SendUnlocked(); }
+ bool IsPersistent() override { return is_persistent_; }
Surface* GetConstrainedSurface() override { return surface_; }
+ void OnDefunct() override { pointer_ = nullptr; }
private:
- void EnableConstraint() {
+ // Inform the client of the state of the lock.
+ void SendLocked() {
+ VLOG(1) << "send_locked(" << constraint_resource_ << ")";
zwp_locked_pointer_v1_send_locked(constraint_resource_);
}
- void DisableConstraint() {
+ void SendUnlocked() {
+ VLOG(1) << "send_unlocked(" << constraint_resource_ << ")";
zwp_locked_pointer_v1_send_unlocked(constraint_resource_);
}
- wl_resource* constraint_resource_;
+ wl_resource* const constraint_resource_;
Pointer* pointer_;
- Surface* surface_;
+ Surface* const surface_;
+ bool is_persistent_;
};
////////////////////////////////////////////////////////////////////////////////
// zwp_locked_pointer
void locked_pointer_destroy(wl_client* client, wl_resource* resource) {
+ VLOG(1) << "locked_pointer_destroy(" << client << ", " << resource << ")";
wl_resource_destroy(resource);
}
@@ -110,6 +131,8 @@ const struct zwp_confined_pointer_v1_interface confined_pointer_implementation =
// zwp_pointer_constraints
void pointer_constraints_destroy(wl_client* client, wl_resource* resource) {
+ VLOG(1) << "pointer_constraints_destroy(" << client << ", " << resource
+ << ")";
wl_resource_destroy(resource);
}
@@ -125,6 +148,13 @@ void pointer_constraints_lock_pointer(wl_client* client,
SkRegion* region =
region_resource ? GetUserDataAs<SkRegion>(region_resource) : nullptr;
+ VLOG(1) << "lock_pointer(" << client << ", " << resource << "; Surface "
+ << surface << " @ window '"
+ << (surface && surface->window() ? surface->window()->GetTitle()
+ : base::EmptyString16())
+ << "', "
+ << "Pointer " << pointer << ")";
+
wl_resource* locked_pointer_resource =
wl_resource_create(client, &zwp_locked_pointer_v1_interface, 1, id);
SetImplementation(
@@ -143,8 +173,8 @@ void pointer_constraints_confine_pointer(wl_client* client,
// Confined pointer is not currently supported.
wl_resource* confined_pointer_resource =
wl_resource_create(client, &zwp_confined_pointer_v1_interface, 1, id);
- SetImplementation<WaylandPointerConstraintDelegate>(
- confined_pointer_resource, &confined_pointer_implementation, nullptr);
+ SetImplementation<int>(confined_pointer_resource,
+ &confined_pointer_implementation, nullptr);
}
const struct zwp_pointer_constraints_v1_interface
diff --git a/chromium/components/exo/wayland/zwp_text_input_manager.cc b/chromium/components/exo/wayland/zwp_text_input_manager.cc
index 7eec62f3452..96922b84b85 100644
--- a/chromium/components/exo/wayland/zwp_text_input_manager.cc
+++ b/chromium/components/exo/wayland/zwp_text_input_manager.cc
@@ -68,7 +68,11 @@ class WaylandTextInputDelegate : public TextInput::Delegate {
}
void OnVirtualKeyboardVisibilityChanged(bool is_visible) override {
- zwp_text_input_v1_send_input_panel_state(text_input_, is_visible);
+ // The detailed spec of |state| is implementation dependent.
+ // So, now we use the lowest bit to indicate whether keyboard is visible.
+ // This behavior is consistent with ozone/wayland to support Lacros.
+ zwp_text_input_v1_send_input_panel_state(text_input_,
+ static_cast<uint32_t>(is_visible));
wl_client_flush(client());
}
@@ -383,7 +387,7 @@ void text_input_set_content_type(wl_client* client,
type = ui::TEXT_INPUT_TYPE_EMAIL;
break;
case ZWP_TEXT_INPUT_V1_CONTENT_PURPOSE_PASSWORD:
- DCHECK(!should_do_learning);
+ should_do_learning = false;
type = ui::TEXT_INPUT_TYPE_PASSWORD;
break;
case ZWP_TEXT_INPUT_V1_CONTENT_PURPOSE_DATE:
diff --git a/chromium/components/exo/window_properties.cc b/chromium/components/exo/window_properties.cc
index a5f63955d86..212e29f1b89 100644
--- a/chromium/components/exo/window_properties.cc
+++ b/chromium/components/exo/window_properties.cc
@@ -4,8 +4,16 @@
#include "components/exo/window_properties.h"
+DEFINE_UI_CLASS_PROPERTY_TYPE(exo::ProtectedNativePixmapQueryDelegate*)
+
namespace exo {
DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(std::string, kApplicationIdKey, nullptr)
+DEFINE_UI_CLASS_PROPERTY_KEY(bool, kRestoreOrMaximizeExitsFullscreen, false)
+
+DEFINE_UI_CLASS_PROPERTY_KEY(ProtectedNativePixmapQueryDelegate*,
+ kProtectedNativePixmapQueryDelegate,
+ nullptr)
+
} // namespace exo
diff --git a/chromium/components/exo/window_properties.h b/chromium/components/exo/window_properties.h
index 303066cc625..fc626f283a7 100644
--- a/chromium/components/exo/window_properties.h
+++ b/chromium/components/exo/window_properties.h
@@ -7,6 +7,7 @@
#include <string>
+#include "components/exo/protected_native_pixmap_query_delegate.h"
#include "ui/base/class_property.h"
namespace exo {
@@ -16,6 +17,14 @@ namespace exo {
// "org.chromium.lacros.<window-id>" for Lacros browser shell surfaces.
extern const ui::ClassProperty<std::string*>* const kApplicationIdKey;
+// Whether Restore and Maximize should exit full screen for this window.
+// Currently only set to true for Lacros windows.
+extern const ui::ClassProperty<bool>* const kRestoreOrMaximizeExitsFullscreen;
+
+// Provides access to a delegate for determining if a native pixmap corresponds
+// to a HW protected buffer.
+extern const ui::ClassProperty<ProtectedNativePixmapQueryDelegate*>* const
+ kProtectedNativePixmapQueryDelegate;
} // namespace exo
#endif // COMPONENTS_EXO_WINDOW_PROPERTIES_H_
diff --git a/chromium/components/exo/wm_helper.h b/chromium/components/exo/wm_helper.h
index dffec51d354..06ea3f12e8c 100644
--- a/chromium/components/exo/wm_helper.h
+++ b/chromium/components/exo/wm_helper.h
@@ -19,6 +19,7 @@ class Window;
namespace client {
class CaptureClient;
class CursorClient;
+class DragDropClient;
class FocusChangeObserver;
} // namespace client
} // namespace aura
@@ -52,15 +53,13 @@ class WMHelper : public aura::client::DragDropDelegate {
class DragDropObserver {
public:
using DropCallback =
- base::OnceCallback<void(const ui::DropTargetEvent& event,
- ui::mojom::DragOperation& output_drag_op)>;
+ base::OnceCallback<void(ui::mojom::DragOperation& output_drag_op)>;
virtual void OnDragEntered(const ui::DropTargetEvent& event) = 0;
virtual aura::client::DragUpdateInfo OnDragUpdated(
const ui::DropTargetEvent& event) = 0;
virtual void OnDragExited() = 0;
- virtual ui::mojom::DragOperation OnPerformDrop(
- const ui::DropTargetEvent& event) = 0;
+ virtual ui::mojom::DragOperation OnPerformDrop() = 0;
virtual DropCallback GetDropCallback(const ui::DropTargetEvent& event) = 0;
protected:
@@ -155,6 +154,7 @@ class WMHelper : public aura::client::DragDropDelegate {
virtual aura::Window* GetFocusedWindow() const = 0;
virtual aura::Window* GetRootWindowForNewWindows() const = 0;
virtual aura::client::CursorClient* GetCursorClient() = 0;
+ virtual aura::client::DragDropClient* GetDragDropClient() = 0;
virtual void AddPreTargetHandler(ui::EventHandler* handler) = 0;
virtual void PrependPreTargetHandler(ui::EventHandler* handler) = 0;
virtual void RemovePreTargetHandler(ui::EventHandler* handler) = 0;
diff --git a/chromium/components/exo/wm_helper_chromeos.cc b/chromium/components/exo/wm_helper_chromeos.cc
index c89f90c3d36..39f8d579b36 100644
--- a/chromium/components/exo/wm_helper_chromeos.cc
+++ b/chromium/components/exo/wm_helper_chromeos.cc
@@ -12,6 +12,7 @@
#include "base/callback_helpers.h"
#include "base/memory/singleton.h"
#include "components/exo/wm_helper.h"
+#include "ui/aura/client/drag_drop_client.h"
#include "ui/aura/client/drag_drop_delegate.h"
#include "ui/aura/client/focus_client.h"
#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
@@ -151,7 +152,7 @@ ui::mojom::DragOperation WMHelperChromeOS::OnPerformDrop(
std::unique_ptr<ui::OSExchangeData> data) {
auto drop_cb = GetDropCallback(event);
auto output_drag_op = ui::mojom::DragOperation::kNone;
- std::move(drop_cb).Run(event, std::move(data), output_drag_op);
+ std::move(drop_cb).Run(std::move(data), output_drag_op);
return output_drag_op;
}
@@ -224,6 +225,10 @@ aura::client::CursorClient* WMHelperChromeOS::GetCursorClient() {
return aura::client::GetCursorClient(ash::Shell::GetPrimaryRootWindow());
}
+aura::client::DragDropClient* WMHelperChromeOS::GetDragDropClient() {
+ return aura::client::GetDragDropClient(ash::Shell::GetPrimaryRootWindow());
+}
+
void WMHelperChromeOS::AddPreTargetHandler(ui::EventHandler* handler) {
ash::Shell::Get()->AddPreTargetHandler(handler);
}
@@ -292,12 +297,11 @@ float GetDefaultDeviceScaleFactor() {
void WMHelperChromeOS::PerformDrop(
std::vector<WMHelper::DragDropObserver::DropCallback> drop_callbacks,
- const ui::DropTargetEvent& event,
std::unique_ptr<ui::OSExchangeData> data,
ui::mojom::DragOperation& output_drag_op) {
for (auto& drop_cb : drop_callbacks) {
auto operation = ui::mojom::DragOperation::kNone;
- std::move(drop_cb).Run(event, operation);
+ std::move(drop_cb).Run(operation);
if (operation != ui::mojom::DragOperation::kNone)
output_drag_op = operation;
}
diff --git a/chromium/components/exo/wm_helper_chromeos.h b/chromium/components/exo/wm_helper_chromeos.h
index ce289b74dab..648b0205a5e 100644
--- a/chromium/components/exo/wm_helper_chromeos.h
+++ b/chromium/components/exo/wm_helper_chromeos.h
@@ -93,6 +93,7 @@ class WMHelperChromeOS : public WMHelper, public VSyncTimingManager::Delegate {
aura::Window* GetFocusedWindow() const override;
aura::Window* GetRootWindowForNewWindows() const override;
aura::client::CursorClient* GetCursorClient() override;
+ aura::client::DragDropClient* GetDragDropClient() override;
void AddPreTargetHandler(ui::EventHandler* handler) override;
void PrependPreTargetHandler(ui::EventHandler* handler) override;
void RemovePreTargetHandler(ui::EventHandler* handler) override;
@@ -125,7 +126,6 @@ class WMHelperChromeOS : public WMHelper, public VSyncTimingManager::Delegate {
private:
void PerformDrop(
std::vector<WMHelper::DragDropObserver::DropCallback> drop_callbacks,
- const ui::DropTargetEvent& event,
std::unique_ptr<ui::OSExchangeData> data,
ui::mojom::DragOperation& output_drag_op);
diff --git a/chromium/components/exo/wm_helper_chromeos_unittest.cc b/chromium/components/exo/wm_helper_chromeos_unittest.cc
index 66ef23e19b1..e49512e0572 100644
--- a/chromium/components/exo/wm_helper_chromeos_unittest.cc
+++ b/chromium/components/exo/wm_helper_chromeos_unittest.cc
@@ -44,14 +44,13 @@ class MockDragDropObserver : public WMHelper::DragDropObserver {
return aura::client::DragUpdateInfo();
}
void OnDragExited() override {}
- DragOperation OnPerformDrop(const ui::DropTargetEvent& event) override {
- return drop_result_;
- }
+ DragOperation OnPerformDrop() override { return drop_result_; }
WMHelper::DragDropObserver::DropCallback GetDropCallback(
const ui::DropTargetEvent& event) override {
return base::BindOnce(
- [](DragOperation drop_result, const ui::DropTargetEvent& event,
- DragOperation& output_drag_op) { output_drag_op = drop_result; },
+ [](DragOperation drop_result, DragOperation& output_drag_op) {
+ output_drag_op = drop_result;
+ },
drop_result_);
}
diff --git a/chromium/components/exo/xdg_shell_surface.cc b/chromium/components/exo/xdg_shell_surface.cc
index 15d09c4f85c..3793a37f75a 100644
--- a/chromium/components/exo/xdg_shell_surface.cc
+++ b/chromium/components/exo/xdg_shell_surface.cc
@@ -6,6 +6,7 @@
#include "ash/frame/non_client_frame_view_ash.h"
#include "chromeos/ui/base/window_properties.h"
+#include "ui/aura/client/aura_constants.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
#include "ui/gfx/geometry/rect.h"
@@ -34,6 +35,13 @@ void XdgShellSurface::OverrideInitParams(views::Widget::InitParams* params) {
chromeos::kAutoMaximizeXdgShellEnabled);
if (auto_maximize_enabled && ShouldAutoMaximize())
params->show_state = ui::SHOW_STATE_MAXIMIZED;
+
+ // Show state should be overridden when set via window property.
+ if (params->init_properties_container.GetProperty(
+ aura::client::kShowStateKey)) {
+ params->show_state = params->init_properties_container.GetProperty(
+ aura::client::kShowStateKey);
+ }
}
bool XdgShellSurface::ShouldAutoMaximize() {
diff --git a/chromium/components/external_intents/android/BUILD.gn b/chromium/components/external_intents/android/BUILD.gn
index e3ab9740539..44c58770bcd 100644
--- a/chromium/components/external_intents/android/BUILD.gn
+++ b/chromium/components/external_intents/android/BUILD.gn
@@ -40,7 +40,7 @@ android_resources("java_resources") {
sources = []
deps = [
"//components/browser_ui/strings/android:browser_ui_strings_grd",
- "//components/browser_ui/styles/android:java_resources",
+ "//components/browser_ui/widget/android:java_resources",
]
}
diff --git a/chromium/components/external_intents/android/javatests/src/org/chromium/components/external_intents/ExternalNavigationHandlerTest.java b/chromium/components/external_intents/android/javatests/src/org/chromium/components/external_intents/ExternalNavigationHandlerTest.java
index 49e938eeff5..d831c7c386c 100644
--- a/chromium/components/external_intents/android/javatests/src/org/chromium/components/external_intents/ExternalNavigationHandlerTest.java
+++ b/chromium/components/external_intents/android/javatests/src/org/chromium/components/external_intents/ExternalNavigationHandlerTest.java
@@ -56,7 +56,7 @@ import org.chromium.content_public.browser.WebContents;
import org.chromium.content_public.browser.test.NativeLibraryTestUtils;
import org.chromium.ui.base.PageTransition;
import org.chromium.ui.base.WindowAndroid;
-import org.chromium.ui.test.util.DummyUiActivity;
+import org.chromium.ui.test.util.BlankUiTestActivity;
import org.chromium.url.GURL;
import org.chromium.url.Origin;
@@ -337,15 +337,18 @@ public class ExternalNavigationHandlerTest {
@Test
@SmallTest
- public void testRedirectFromFormSubmit_NoUserGesture_OnIntentRedirectChain() {
+ public void testRedirectFromFormSubmit_NoUserGesture_OnIntentRedirectChain() throws Exception {
mDelegate.add(new IntentActivity(YOUTUBE_URL, YOUTUBE_PACKAGE_NAME));
- RedirectHandler redirectHandler = new RedirectHandler() {
- @Override
- public boolean isOnEffectiveIntentRedirectChain() {
- return true;
- }
- };
+ RedirectHandler redirectHandler = RedirectHandler.create();
+
+ redirectHandler.updateIntent(
+ Intent.parseUri("http://example.test", Intent.URI_INTENT_SCHEME),
+ !IS_CUSTOM_TAB_INTENT, !SEND_TO_EXTERNAL_APPS,
+ IS_CCT_EXTERNAL_LINK_HANDLING_ENABLED, !INTENT_STARTED_TASK);
+ redirectHandler.updateNewUrlLoading(
+ PageTransition.LINK | PageTransition.FROM_API, false, false, 0, 0, true);
+ redirectHandler.updateNewUrlLoading(PageTransition.FORM_SUBMIT, false, false, 0, 0, false);
// If the redirect is not associated with a user gesture but came from an incoming intent,
// then allow those to launch external intents.
@@ -356,7 +359,7 @@ public class ExternalNavigationHandlerTest {
.withRedirectHandler(redirectHandler)
.expecting(OverrideUrlLoadingResultType.OVERRIDE_WITH_EXTERNAL_INTENT,
START_OTHER_ACTIVITY);
- checkUrl("http://youtube.com://")
+ checkUrl("http://youtube.com")
.withPageTransition(PageTransition.FORM_SUBMIT)
.withIsRedirect(true)
.withHasUserGesture(false)
@@ -451,12 +454,12 @@ public class ExternalNavigationHandlerTest {
.expecting(OverrideUrlLoadingResultType.OVERRIDE_WITH_EXTERNAL_INTENT,
START_OTHER_ACTIVITY);
- Assert.assertNotNull(mDelegate.startActivityIntent);
- Uri uri = mDelegate.startActivityIntent.getData();
+ Assert.assertNotNull(mUrlHandler.mStartActivityIntent);
+ Uri uri = mUrlHandler.mStartActivityIntent.getData();
Assert.assertEquals("market", uri.getScheme());
Assert.assertEquals(Uri.decode(ENCODED_MARKET_REFERRER), uri.getQueryParameter("referrer"));
Assert.assertEquals(Uri.parse(KEEP_URL),
- mDelegate.startActivityIntent.getParcelableExtra(Intent.EXTRA_REFERRER));
+ mUrlHandler.mStartActivityIntent.getParcelableExtra(Intent.EXTRA_REFERRER));
}
@Test
@@ -468,8 +471,8 @@ public class ExternalNavigationHandlerTest {
.expecting(OverrideUrlLoadingResultType.OVERRIDE_WITH_EXTERNAL_INTENT,
START_OTHER_ACTIVITY);
- Assert.assertNotNull(mDelegate.startActivityIntent);
- Uri uri = mDelegate.startActivityIntent.getData();
+ Assert.assertNotNull(mUrlHandler.mStartActivityIntent);
+ Uri uri = mUrlHandler.mStartActivityIntent.getData();
Assert.assertEquals("market", uri.getScheme());
Assert.assertEquals(getPackageName(), uri.getQueryParameter("referrer"));
}
@@ -522,6 +525,31 @@ public class ExternalNavigationHandlerTest {
.withIsRedirect(true)
.expecting(OverrideUrlLoadingResultType.OVERRIDE_WITH_EXTERNAL_INTENT,
START_OTHER_ACTIVITY);
+
+ // http://crbug.com/1310795
+ mDelegate.setIsChromeAppInForeground(false);
+ checkUrl(YOUTUBE_URL)
+ .withPageTransition(transitionTypeIncomingIntent)
+ .withIsRedirect(true)
+ .withChromeAppInForegroundRequired(true)
+ .expecting(OverrideUrlLoadingResultType.OVERRIDE_WITH_EXTERNAL_INTENT,
+ START_OTHER_ACTIVITY);
+ }
+
+ @Test
+ @SmallTest
+ public void testIncomingIntentRedirect_FallbackUrl() {
+ // IMDB app isn't installed.
+ mDelegate.setCanResolveActivityForExternalSchemes(false);
+ mDelegate.setIsChromeAppInForeground(false);
+ int transitionTypeIncomingIntent = PageTransition.LINK | PageTransition.FROM_API;
+
+ // http://crbug.com/1310795
+ checkUrl(INTENT_URL_WITH_FALLBACK_URL)
+ .withPageTransition(transitionTypeIncomingIntent)
+ .withIsRedirect(true)
+ .withChromeAppInForegroundRequired(true)
+ .expecting(OverrideUrlLoadingResultType.OVERRIDE_WITH_CLOBBERING_TAB, IGNORE);
}
@Test
@@ -529,22 +557,30 @@ public class ExternalNavigationHandlerTest {
public void testIntentScheme() {
String url = "intent:wtai://wp/#Intent;action=android.settings.SETTINGS;"
+ "component=package/class;end";
- String urlWithSel = "intent:wtai://wp/#Intent;SEL;action=android.settings.SETTINGS;"
- + "component=package/class;end";
+
String urlWithNullData = "intent:#Intent;package=com.google.zxing.client.android;"
+ "action=android.settings.SETTINGS;end";
checkUrl(url).expecting(
OverrideUrlLoadingResultType.OVERRIDE_WITH_EXTERNAL_INTENT, START_OTHER_ACTIVITY);
- // http://crbug.com/370399
- checkUrl(urlWithSel)
+ checkUrl(urlWithNullData)
.expecting(OverrideUrlLoadingResultType.OVERRIDE_WITH_EXTERNAL_INTENT,
START_OTHER_ACTIVITY);
+ }
- checkUrl(urlWithNullData)
+ // http://crbug.com/1254422
+ @Test
+ @SmallTest
+ public void testIntentSelectorRemoved() {
+ String urlWithSel = "intent:wtai://wp/#Intent;SEL;action=android.settings.SETTINGS;"
+ + "component=package/class;end";
+
+ checkUrl(urlWithSel)
.expecting(OverrideUrlLoadingResultType.OVERRIDE_WITH_EXTERNAL_INTENT,
START_OTHER_ACTIVITY);
+
+ Assert.assertNull(mUrlHandler.mStartActivityIntent.getSelector());
}
@Test
@@ -766,7 +802,7 @@ public class ExternalNavigationHandlerTest {
checkUrl(INTENT_URL_FOR_SELF_CUSTOM_TABS)
.withIsIncognito(true)
.expecting(OverrideUrlLoadingResultType.OVERRIDE_WITH_CLOBBERING_TAB, IGNORE);
- Assert.assertNull(mDelegate.startActivityIntent);
+ Assert.assertNull(mUrlHandler.mStartActivityIntent);
Assert.assertEquals("http://example.com/", mUrlHandler.mNewUrlAfterClobbering);
}
@@ -777,7 +813,7 @@ public class ExternalNavigationHandlerTest {
.withIsIncognito(false)
.expecting(OverrideUrlLoadingResultType.OVERRIDE_WITH_EXTERNAL_INTENT,
START_OTHER_ACTIVITY);
- Assert.assertNotNull(mDelegate.startActivityIntent);
+ Assert.assertNotNull(mUrlHandler.mStartActivityIntent);
}
@Test
@@ -788,14 +824,14 @@ public class ExternalNavigationHandlerTest {
checkUrl(INTENT_URL_FOR_SELF)
.withIsIncognito(true)
.expecting(OverrideUrlLoadingResultType.OVERRIDE_WITH_CLOBBERING_TAB, IGNORE);
- Assert.assertNull(mDelegate.startActivityIntent);
+ Assert.assertNull(mUrlHandler.mStartActivityIntent);
Assert.assertEquals("http://example.com/", mUrlHandler.mNewUrlAfterClobbering);
mUrlHandler.mResolveInfoContainsSelf = false;
checkUrl(INTENT_URL_FOR_SELF)
.withIsIncognito(true)
.expecting(OverrideUrlLoadingResultType.OVERRIDE_WITH_CLOBBERING_TAB, IGNORE);
- Assert.assertNull(mDelegate.startActivityIntent);
+ Assert.assertNull(mUrlHandler.mStartActivityIntent);
Assert.assertEquals(YOUTUBE_URL, mUrlHandler.mNewUrlAfterClobbering);
}
@@ -857,7 +893,7 @@ public class ExternalNavigationHandlerTest {
checkUrl(intentUrl).expecting(OverrideUrlLoadingResultType.OVERRIDE_WITH_EXTERNAL_INTENT,
START_OTHER_ACTIVITY | PROXY_FOR_INSTANT_APPS);
Assert.assertTrue(
- mDelegate.startActivityIntent.getBooleanExtra(IS_INSTANT_APP_EXTRA, false));
+ mUrlHandler.mStartActivityIntent.getBooleanExtra(IS_INSTANT_APP_EXTRA, false));
// Check that we block all instant app intent:// URLs not from SERP.
mUrlHandler.mIsSerpReferrer = false;
@@ -870,7 +906,7 @@ public class ExternalNavigationHandlerTest {
checkUrl(intentUrl).expecting(
OverrideUrlLoadingResultType.OVERRIDE_WITH_EXTERNAL_INTENT, START_OTHER_ACTIVITY);
Assert.assertFalse(
- mDelegate.startActivityIntent.getBooleanExtra(IS_INSTANT_APP_EXTRA, true));
+ mUrlHandler.mStartActivityIntent.getBooleanExtra(IS_INSTANT_APP_EXTRA, true));
}
@Test
@@ -884,7 +920,7 @@ public class ExternalNavigationHandlerTest {
.expecting(OverrideUrlLoadingResultType.OVERRIDE_WITH_EXTERNAL_INTENT,
START_OTHER_ACTIVITY);
- Intent invokedIntent = mDelegate.startActivityIntent;
+ Intent invokedIntent = mUrlHandler.mStartActivityIntent;
Assert.assertEquals(IMDB_APP_INTENT_FOR_TOM_HANKS, invokedIntent.getData().toString());
Assert.assertNull("The invoked intent should not have browser_fallback_url\n",
invokedIntent.getStringExtra(ExternalNavigationHandler.EXTRA_BROWSER_FALLBACK_URL));
@@ -934,7 +970,7 @@ public class ExternalNavigationHandlerTest {
checkUrl(INTENT_URL_WITH_FALLBACK_URL)
.withReferrer(SEARCH_RESULT_URL_FOR_TOM_HANKS)
.expecting(OverrideUrlLoadingResultType.OVERRIDE_WITH_CLOBBERING_TAB, IGNORE);
- Assert.assertNull(mDelegate.startActivityIntent);
+ Assert.assertNull(mUrlHandler.mStartActivityIntent);
Assert.assertEquals(IMDB_WEBPAGE_FOR_TOM_HANKS, mUrlHandler.mNewUrlAfterClobbering);
Assert.assertEquals(SEARCH_RESULT_URL_FOR_TOM_HANKS, mUrlHandler.mReferrerUrlForClobbering);
}
@@ -951,7 +987,7 @@ public class ExternalNavigationHandlerTest {
.withReferrer(SEARCH_RESULT_URL_FOR_TOM_HANKS)
.expecting(OverrideUrlLoadingResultType.OVERRIDE_WITH_CLOBBERING_TAB, IGNORE);
- Assert.assertNull(mDelegate.startActivityIntent);
+ Assert.assertNull(mUrlHandler.mStartActivityIntent);
Assert.assertEquals(IMDB_WEBPAGE_FOR_TOM_HANKS, mUrlHandler.mNewUrlAfterClobbering);
Assert.assertEquals(SEARCH_RESULT_URL_FOR_TOM_HANKS, mUrlHandler.mReferrerUrlForClobbering);
}
@@ -969,7 +1005,7 @@ public class ExternalNavigationHandlerTest {
OverrideUrlLoadingResultType.OVERRIDE_WITH_EXTERNAL_INTENT, START_OTHER_ACTIVITY);
Assert.assertEquals("market://details?id=com.imdb.mobile&referrer=mypage",
- mDelegate.startActivityIntent.getDataString());
+ mUrlHandler.mStartActivityIntent.getDataString());
String intentNoRef = "intent:///name/nm0000158#Intent;scheme=imdb;package=com.imdb.mobile;"
+ "S." + ExternalNavigationHandler.EXTRA_BROWSER_FALLBACK_URL + "="
@@ -979,7 +1015,7 @@ public class ExternalNavigationHandlerTest {
START_OTHER_ACTIVITY);
Assert.assertEquals("market://details?id=com.imdb.mobile&referrer=" + getPackageName(),
- mDelegate.startActivityIntent.getDataString());
+ mUrlHandler.mStartActivityIntent.getDataString());
String intentBadUrl = "intent:///name/nm0000158#Intent;scheme=imdb;package=com.imdb.mobile;"
+ "S." + ExternalNavigationHandler.EXTRA_BROWSER_FALLBACK_URL + "="
@@ -991,12 +1027,14 @@ public class ExternalNavigationHandlerTest {
@Test
@MediumTest
public void testFallbackUrl_FallbackToMarketApp_Incognito() {
+ // Test uses an ActivityMonitor to catch the outgoing intent.
+ mUrlHandler.sendIntentsForReal();
IntentFilter filter = new IntentFilter(Intent.ACTION_VIEW);
filter.addCategory(Intent.CATEGORY_BROWSABLE);
filter.addDataScheme("market");
ActivityMonitor monitor = InstrumentationRegistry.getInstrumentation().addMonitor(
filter, new Instrumentation.ActivityResult(Activity.RESULT_OK, null), true);
- Intent dummyIntent = new Intent(mApplicationContextToRestore, DummyUiActivity.class);
+ Intent dummyIntent = new Intent(mApplicationContextToRestore, BlankUiTestActivity.class);
dummyIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Activity activity =
InstrumentationRegistry.getInstrumentation().startActivitySync(dummyIntent);
@@ -1016,7 +1054,7 @@ public class ExternalNavigationHandlerTest {
checkUrl(intent).withIsIncognito(true).withHasUserGesture(true).expecting(
OverrideUrlLoadingResultType.OVERRIDE_WITH_ASYNC_ACTION,
OverrideUrlLoadingAsyncActionType.UI_GATING_INTENT_LAUNCH, START_INCOGNITO);
- Assert.assertNull(mDelegate.startActivityIntent);
+ Assert.assertNull(mUrlHandler.mStartActivityIntent);
Assert.assertNull(mUrlHandler.mNewUrlAfterClobbering);
mUrlHandler.mShownIncognitoAlertDialog.cancel();
});
@@ -1028,7 +1066,7 @@ public class ExternalNavigationHandlerTest {
checkUrl(intent).withIsIncognito(true).withHasUserGesture(true).expecting(
OverrideUrlLoadingResultType.OVERRIDE_WITH_ASYNC_ACTION,
OverrideUrlLoadingAsyncActionType.UI_GATING_INTENT_LAUNCH, START_INCOGNITO);
- Assert.assertNull(mDelegate.startActivityIntent);
+ Assert.assertNull(mUrlHandler.mStartActivityIntent);
mUrlHandler.mShownIncognitoAlertDialog.getButton(DialogInterface.BUTTON_POSITIVE)
.performClick();
});
@@ -1037,7 +1075,7 @@ public class ExternalNavigationHandlerTest {
Assert.assertNull(mUrlHandler.mNewUrlAfterClobbering);
Assert.assertEquals(1, monitor.getHits());
Assert.assertEquals("market://details?id=com.imdb.mobile&referrer=mypage",
- mDelegate.startActivityIntent.getDataString());
+ mUrlHandler.mStartActivityIntent.getDataString());
});
} finally {
if (mUrlHandler.mShownIncognitoAlertDialog != null) {
@@ -1048,11 +1086,9 @@ public class ExternalNavigationHandlerTest {
}
}
- @Test
- @MediumTest
- public void testFallbackUrl_ChromeCanHandle_Incognito() {
+ private void doTestFallbackUrl_ChromeCanHandle_Incognito(final boolean clearRedirectHandler) {
mDelegate.add(new IntentActivity("https", "package"));
- Intent dummyIntent = new Intent(mApplicationContextToRestore, DummyUiActivity.class);
+ Intent dummyIntent = new Intent(mApplicationContextToRestore, BlankUiTestActivity.class);
dummyIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Activity activity =
InstrumentationRegistry.getInstrumentation().startActivitySync(dummyIntent);
@@ -1065,11 +1101,18 @@ public class ExternalNavigationHandlerTest {
mUrlHandler.mResolveInfoContainsSelf = true;
mUrlHandler.mCanShowIncognitoDialog = true;
ThreadUtils.runOnUiThreadBlocking(() -> {
- checkUrl(intent).withIsIncognito(true).withHasUserGesture(true).expecting(
- OverrideUrlLoadingResultType.OVERRIDE_WITH_ASYNC_ACTION,
- OverrideUrlLoadingAsyncActionType.UI_GATING_INTENT_LAUNCH, START_INCOGNITO);
- Assert.assertNull(mDelegate.startActivityIntent);
+ RedirectHandler redirectHandler = RedirectHandler.create();
+ redirectHandler.updateNewUrlLoading(PageTransition.LINK, false, true, 0, 0, false);
+ checkUrl(intent)
+ .withIsIncognito(true)
+ .withHasUserGesture(true)
+ .withRedirectHandler(redirectHandler)
+ .expecting(OverrideUrlLoadingResultType.OVERRIDE_WITH_ASYNC_ACTION,
+ OverrideUrlLoadingAsyncActionType.UI_GATING_INTENT_LAUNCH,
+ START_INCOGNITO);
+ Assert.assertNull(mUrlHandler.mStartActivityIntent);
Assert.assertNull(mUrlHandler.mNewUrlAfterClobbering);
+ if (clearRedirectHandler) redirectHandler.clear();
mUrlHandler.mShownIncognitoAlertDialog.cancel();
});
// Cancel callback is posted, so continue after posting to the task queue.
@@ -1078,10 +1121,17 @@ public class ExternalNavigationHandlerTest {
mUrlHandler.mNewUrlAfterClobbering = null;
mUrlHandler.mResolveInfoContainsSelf = false;
- checkUrl(intent).withIsIncognito(true).withHasUserGesture(true).expecting(
- OverrideUrlLoadingResultType.OVERRIDE_WITH_ASYNC_ACTION,
- OverrideUrlLoadingAsyncActionType.UI_GATING_INTENT_LAUNCH, START_INCOGNITO);
- Assert.assertNull(mDelegate.startActivityIntent);
+ RedirectHandler redirectHandler = RedirectHandler.create();
+ redirectHandler.updateNewUrlLoading(PageTransition.LINK, false, true, 0, 0, false);
+ checkUrl(intent)
+ .withIsIncognito(true)
+ .withHasUserGesture(true)
+ .withRedirectHandler(redirectHandler)
+ .expecting(OverrideUrlLoadingResultType.OVERRIDE_WITH_ASYNC_ACTION,
+ OverrideUrlLoadingAsyncActionType.UI_GATING_INTENT_LAUNCH,
+ START_INCOGNITO);
+ Assert.assertNull(mUrlHandler.mStartActivityIntent);
+ if (clearRedirectHandler) redirectHandler.clear();
mUrlHandler.mShownIncognitoAlertDialog.cancel();
});
// Click callback is posted, so continue after posting to the task queue.
@@ -1098,13 +1148,28 @@ public class ExternalNavigationHandlerTest {
@Test
@MediumTest
+ public void testFallbackUrl_ChromeCanHandle_Incognito() {
+ doTestFallbackUrl_ChromeCanHandle_Incognito(false);
+ }
+
+ // https://crbug.com/1302566
+ @Test
+ @MediumTest
+ public void testFallbackUrl_ChromeCanHandle_Incognito_ClearRedirectHandler() {
+ doTestFallbackUrl_ChromeCanHandle_Incognito(true);
+ }
+
+ @Test
+ @MediumTest
public void testFallbackUrl_FallbackToMarketApp_Incognito_DelegateHandleDialogPresentation() {
+ // Test uses an ActivityMonitor to catch the outgoing intent.
+ mUrlHandler.sendIntentsForReal();
IntentFilter filter = new IntentFilter(Intent.ACTION_VIEW);
filter.addCategory(Intent.CATEGORY_BROWSABLE);
filter.addDataScheme("market");
ActivityMonitor monitor = InstrumentationRegistry.getInstrumentation().addMonitor(
filter, new Instrumentation.ActivityResult(Activity.RESULT_OK, null), true);
- Intent dummyIntent = new Intent(mApplicationContextToRestore, DummyUiActivity.class);
+ Intent dummyIntent = new Intent(mApplicationContextToRestore, BlankUiTestActivity.class);
dummyIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Activity activity =
InstrumentationRegistry.getInstrumentation().startActivitySync(dummyIntent);
@@ -1125,7 +1190,7 @@ public class ExternalNavigationHandlerTest {
checkUrl(intent).withIsIncognito(true).withHasUserGesture(true).expecting(
OverrideUrlLoadingResultType.OVERRIDE_WITH_ASYNC_ACTION,
OverrideUrlLoadingAsyncActionType.UI_GATING_INTENT_LAUNCH, START_INCOGNITO);
- Assert.assertNull(mDelegate.startActivityIntent);
+ Assert.assertNull(mUrlHandler.mStartActivityIntent);
Assert.assertNull(mUrlHandler.mNewUrlAfterClobbering);
// Verify that the incognito dialog was not shown.
@@ -1144,7 +1209,7 @@ public class ExternalNavigationHandlerTest {
checkUrl(intent).withIsIncognito(true).withHasUserGesture(true).expecting(
OverrideUrlLoadingResultType.OVERRIDE_WITH_ASYNC_ACTION,
OverrideUrlLoadingAsyncActionType.UI_GATING_INTENT_LAUNCH, START_INCOGNITO);
- Assert.assertNull(mDelegate.startActivityIntent);
+ Assert.assertNull(mUrlHandler.mStartActivityIntent);
// Verify that the incognito dialog was not shown.
Assert.assertNull(mUrlHandler.mShownIncognitoAlertDialog);
@@ -1158,7 +1223,7 @@ public class ExternalNavigationHandlerTest {
Assert.assertNull(mUrlHandler.mNewUrlAfterClobbering);
Assert.assertEquals(1, monitor.getHits());
Assert.assertEquals("market://details?id=com.imdb.mobile&referrer=mypage",
- mDelegate.startActivityIntent.getDataString());
+ mUrlHandler.mStartActivityIntent.getDataString());
});
} finally {
activity.finish();
@@ -1170,7 +1235,7 @@ public class ExternalNavigationHandlerTest {
@MediumTest
public void testFallbackUrl_ChromeCanHandle_Incognito_DelegateHandleDialogPresentation() {
mDelegate.add(new IntentActivity("https", "package"));
- Intent dummyIntent = new Intent(mApplicationContextToRestore, DummyUiActivity.class);
+ Intent dummyIntent = new Intent(mApplicationContextToRestore, BlankUiTestActivity.class);
dummyIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Activity activity =
InstrumentationRegistry.getInstrumentation().startActivitySync(dummyIntent);
@@ -1187,7 +1252,7 @@ public class ExternalNavigationHandlerTest {
checkUrl(intent).withIsIncognito(true).withHasUserGesture(true).expecting(
OverrideUrlLoadingResultType.OVERRIDE_WITH_ASYNC_ACTION,
OverrideUrlLoadingAsyncActionType.UI_GATING_INTENT_LAUNCH, START_INCOGNITO);
- Assert.assertNull(mDelegate.startActivityIntent);
+ Assert.assertNull(mUrlHandler.mStartActivityIntent);
Assert.assertNull(mUrlHandler.mNewUrlAfterClobbering);
// Verify that the incognito dialog was not shown.
@@ -1208,7 +1273,7 @@ public class ExternalNavigationHandlerTest {
checkUrl(intent).withIsIncognito(true).withHasUserGesture(true).expecting(
OverrideUrlLoadingResultType.OVERRIDE_WITH_ASYNC_ACTION,
OverrideUrlLoadingAsyncActionType.UI_GATING_INTENT_LAUNCH, START_INCOGNITO);
- Assert.assertNull(mDelegate.startActivityIntent);
+ Assert.assertNull(mUrlHandler.mStartActivityIntent);
// Verify that the incognito dialog was not shown.
Assert.assertNull(mUrlHandler.mShownIncognitoAlertDialog);
@@ -1245,7 +1310,7 @@ public class ExternalNavigationHandlerTest {
.expecting(OverrideUrlLoadingResultType.OVERRIDE_WITH_EXTERNAL_INTENT,
START_OTHER_ACTIVITY);
Assert.assertEquals("market://details?id=com.imdb.mobile&referrer=mypage",
- mDelegate.startActivityIntent.getDataString());
+ mUrlHandler.mStartActivityIntent.getDataString());
redirectHandler = RedirectHandler.create();
redirectHandler.updateNewUrlLoading(PageTransition.LINK, false, true, 0, 0, false);
@@ -1287,7 +1352,7 @@ public class ExternalNavigationHandlerTest {
START_OTHER_ACTIVITY);
Assert.assertEquals("market://details?id=com.imdb.mobile&referrer=mypage",
- mDelegate.startActivityIntent.getDataString());
+ mUrlHandler.mStartActivityIntent.getDataString());
}
@Test
@@ -1337,7 +1402,7 @@ public class ExternalNavigationHandlerTest {
.withReferrer(SEARCH_RESULT_URL_FOR_TOM_HANKS)
.expecting(OverrideUrlLoadingResultType.OVERRIDE_WITH_CLOBBERING_TAB, IGNORE);
- Assert.assertNull(mDelegate.startActivityIntent);
+ Assert.assertNull(mUrlHandler.mStartActivityIntent);
Assert.assertEquals(IMDB_WEBPAGE_FOR_TOM_HANKS, mUrlHandler.mNewUrlAfterClobbering);
Assert.assertEquals(SEARCH_RESULT_URL_FOR_TOM_HANKS, mUrlHandler.mReferrerUrlForClobbering);
}
@@ -1353,7 +1418,7 @@ public class ExternalNavigationHandlerTest {
.withIsIncognito(true)
.expecting(OverrideUrlLoadingResultType.OVERRIDE_WITH_CLOBBERING_TAB, IGNORE);
- Assert.assertNull(mDelegate.startActivityIntent);
+ Assert.assertNull(mUrlHandler.mStartActivityIntent);
Assert.assertEquals(IMDB_WEBPAGE_FOR_TOM_HANKS, mUrlHandler.mNewUrlAfterClobbering);
Assert.assertEquals(SEARCH_RESULT_URL_FOR_TOM_HANKS, mUrlHandler.mReferrerUrlForClobbering);
}
@@ -1520,9 +1585,9 @@ public class ExternalNavigationHandlerTest {
OverrideUrlLoadingResult result = mUrlHandler.shouldOverrideUrlLoading(params);
Assert.assertEquals(
OverrideUrlLoadingResultType.OVERRIDE_WITH_EXTERNAL_INTENT, result.getResultType());
- Assert.assertTrue(mDelegate.startActivityIntent != null);
- Assert.assertTrue(
- mDelegate.startActivityIntent.getBooleanExtra(Browser.EXTRA_CREATE_NEW_TAB, false));
+ Assert.assertTrue(mUrlHandler.mStartActivityIntent != null);
+ Assert.assertTrue(mUrlHandler.mStartActivityIntent.getBooleanExtra(
+ Browser.EXTRA_CREATE_NEW_TAB, false));
}
@Test
@@ -1618,7 +1683,7 @@ public class ExternalNavigationHandlerTest {
.expecting(OverrideUrlLoadingResultType.OVERRIDE_WITH_EXTERNAL_INTENT,
START_OTHER_ACTIVITY);
Assert.assertEquals(ExternalNavigationHandler.ALLOWED_INTENT_FLAGS,
- mDelegate.startActivityIntent.getFlags());
+ mUrlHandler.mStartActivityIntent.getFlags());
}
@Test
@@ -1651,7 +1716,7 @@ public class ExternalNavigationHandlerTest {
.expecting(OverrideUrlLoadingResultType.OVERRIDE_WITH_EXTERNAL_INTENT,
START_OTHER_ACTIVITY);
// Schemes on Android are case-sensitive, so ensure the scheme is passed through as-is.
- Assert.assertEquals("w3irD", mDelegate.startActivityIntent.getScheme());
+ Assert.assertEquals("w3irD", mUrlHandler.mStartActivityIntent.getScheme());
}
@Test
@@ -1687,7 +1752,7 @@ public class ExternalNavigationHandlerTest {
.expecting(OverrideUrlLoadingResultType.OVERRIDE_WITH_EXTERNAL_INTENT,
START_OTHER_ACTIVITY);
Assert.assertEquals(Uri.parse(referrer),
- mDelegate.startActivityIntent.getParcelableExtra(Intent.EXTRA_REFERRER));
+ mUrlHandler.mStartActivityIntent.getParcelableExtra(Intent.EXTRA_REFERRER));
}
@Test
@@ -1777,8 +1842,8 @@ public class ExternalNavigationHandlerTest {
.expecting(OverrideUrlLoadingResultType.OVERRIDE_WITH_EXTERNAL_INTENT,
START_OTHER_ACTIVITY);
- Assert.assertNotNull(mDelegate.startActivityIntent);
- Assert.assertEquals(TEXT_APP_2_PACKAGE_NAME, mDelegate.startActivityIntent.getPackage());
+ Assert.assertNotNull(mUrlHandler.mStartActivityIntent);
+ Assert.assertEquals(TEXT_APP_2_PACKAGE_NAME, mUrlHandler.mStartActivityIntent.getPackage());
}
@Test
@@ -1795,8 +1860,8 @@ public class ExternalNavigationHandlerTest {
.expecting(OverrideUrlLoadingResultType.OVERRIDE_WITH_EXTERNAL_INTENT,
START_OTHER_ACTIVITY);
- Assert.assertNotNull(mDelegate.startActivityIntent);
- Assert.assertNull(mDelegate.startActivityIntent.getPackage());
+ Assert.assertNotNull(mUrlHandler.mStartActivityIntent);
+ Assert.assertNull(mUrlHandler.mStartActivityIntent.getPackage());
}
@Test
@@ -1812,8 +1877,8 @@ public class ExternalNavigationHandlerTest {
.expecting(OverrideUrlLoadingResultType.OVERRIDE_WITH_EXTERNAL_INTENT,
START_OTHER_ACTIVITY);
- Assert.assertNotNull(mDelegate.startActivityIntent);
- Assert.assertEquals(TEXT_APP_2_PACKAGE_NAME, mDelegate.startActivityIntent.getPackage());
+ Assert.assertNotNull(mUrlHandler.mStartActivityIntent);
+ Assert.assertEquals(TEXT_APP_2_PACKAGE_NAME, mUrlHandler.mStartActivityIntent.getPackage());
}
/**
@@ -1917,8 +1982,8 @@ public class ExternalNavigationHandlerTest {
.expecting(OverrideUrlLoadingResultType.OVERRIDE_WITH_EXTERNAL_INTENT,
START_OTHER_ACTIVITY);
- Assert.assertNotNull(mDelegate.startActivityIntent);
- Assert.assertTrue(mDelegate.startActivityIntent.getScheme().startsWith("market"));
+ Assert.assertNotNull(mUrlHandler.mStartActivityIntent);
+ Assert.assertTrue(mUrlHandler.mStartActivityIntent.getScheme().startsWith("market"));
}
@Test
@@ -1927,7 +1992,7 @@ public class ExternalNavigationHandlerTest {
mDelegate.setCanResolveActivityForMarket(false);
checkUrl("market://1234").expecting(OverrideUrlLoadingResultType.NO_OVERRIDE, IGNORE);
- Assert.assertNull(mDelegate.startActivityIntent);
+ Assert.assertNull(mUrlHandler.mStartActivityIntent);
}
@Test
@@ -2003,6 +2068,7 @@ public class ExternalNavigationHandlerTest {
@SmallTest
public void testAutofillAssistantIntentWithFallback_InRegular() {
RedirectHandler redirectHandler = RedirectHandler.create();
+ redirectHandler.updateNewUrlLoading(PageTransition.LINK, false, true, 0, 0, true);
mDelegate.setIsIntentToAutofillAssistant(true);
checkUrl(AUTOFILL_ASSISTANT_INTENT_URL_WITH_FALLBACK)
@@ -2010,7 +2076,7 @@ public class ExternalNavigationHandlerTest {
.expecting(OverrideUrlLoadingResultType.OVERRIDE_WITH_CLOBBERING_TAB, IGNORE);
Assert.assertTrue(redirectHandler.shouldNotOverrideUrlLoading());
- Assert.assertNull(mDelegate.startActivityIntent);
+ Assert.assertNull(mUrlHandler.mStartActivityIntent);
}
@Test
@@ -2021,7 +2087,7 @@ public class ExternalNavigationHandlerTest {
.withIsIncognito(true)
.expecting(OverrideUrlLoadingResultType.OVERRIDE_WITH_CLOBBERING_TAB, IGNORE);
- Assert.assertNull(mDelegate.startActivityIntent);
+ Assert.assertNull(mUrlHandler.mStartActivityIntent);
}
@Test
@@ -2032,7 +2098,7 @@ public class ExternalNavigationHandlerTest {
.withIsIncognito(false)
.expecting(OverrideUrlLoadingResultType.NO_OVERRIDE, IGNORE);
- Assert.assertNull(mDelegate.startActivityIntent);
+ Assert.assertNull(mUrlHandler.mStartActivityIntent);
}
@Test
@@ -2043,7 +2109,7 @@ public class ExternalNavigationHandlerTest {
.withIsIncognito(true)
.expecting(OverrideUrlLoadingResultType.NO_OVERRIDE, IGNORE);
- Assert.assertNull(mDelegate.startActivityIntent);
+ Assert.assertNull(mUrlHandler.mStartActivityIntent);
}
@Test
@@ -2058,7 +2124,7 @@ public class ExternalNavigationHandlerTest {
.expecting(OverrideUrlLoadingResultType.OVERRIDE_WITH_EXTERNAL_INTENT,
START_OTHER_ACTIVITY);
- Assert.assertNotNull(mDelegate.startActivityIntent);
+ Assert.assertNotNull(mUrlHandler.mStartActivityIntent);
}
@Test
@@ -2067,6 +2133,7 @@ public class ExternalNavigationHandlerTest {
mDelegate.add(new IntentActivity("https://someapp.com", "someapp"));
RedirectHandler redirectHandler = RedirectHandler.create();
+ redirectHandler.updateNewUrlLoading(PageTransition.LINK, false, true, 0, 0, true);
mUrlHandler.mIsGoogleReferrer = true;
mDelegate.setIsIntentToAutofillAssistant(true);
@@ -2080,7 +2147,7 @@ public class ExternalNavigationHandlerTest {
Assert.assertFalse(
redirectHandler
.getAndClearShouldNotBlockOverrideUrlLoadingOnCurrentRedirectionChain());
- Assert.assertNull(mDelegate.startActivityIntent);
+ Assert.assertNull(mUrlHandler.mStartActivityIntent);
}
@Test
@@ -2095,7 +2162,7 @@ public class ExternalNavigationHandlerTest {
.withIsIncognito(true)
.expecting(OverrideUrlLoadingResultType.OVERRIDE_WITH_CLOBBERING_TAB, IGNORE);
- Assert.assertNull(mDelegate.startActivityIntent);
+ Assert.assertNull(mUrlHandler.mStartActivityIntent);
}
@Test
@@ -2323,7 +2390,7 @@ public class ExternalNavigationHandlerTest {
.expecting(OverrideUrlLoadingResultType.OVERRIDE_WITH_EXTERNAL_INTENT,
START_OTHER_ACTIVITY);
- Assert.assertNull(mDelegate.startActivityIntent.getPackage());
+ Assert.assertNull(mUrlHandler.mStartActivityIntent.getPackage());
mDelegate.setTargetPackageName("target.package");
@@ -2331,7 +2398,15 @@ public class ExternalNavigationHandlerTest {
.expecting(OverrideUrlLoadingResultType.OVERRIDE_WITH_EXTERNAL_INTENT,
START_OTHER_ACTIVITY);
- Assert.assertEquals("target.package", mDelegate.startActivityIntent.getPackage());
+ Assert.assertEquals("target.package", mUrlHandler.mStartActivityIntent.getPackage());
+ }
+
+ @Test
+ @SmallTest
+ public void testBlockNonExportedActivity() {
+ mDelegate.add(new IntentActivity(YOUTUBE_URL, YOUTUBE_PACKAGE_NAME, false));
+
+ checkUrl(YOUTUBE_URL).expecting(OverrideUrlLoadingResultType.NO_OVERRIDE, IGNORE);
}
private static List<ResolveInfo> makeResolveInfos(ResolveInfo... infos) {
@@ -2342,6 +2417,7 @@ public class ExternalNavigationHandlerTest {
ActivityInfo ai = new ActivityInfo();
ai.packageName = packageName;
ai.name = "Name: " + packageName;
+ ai.exported = true;
ResolveInfo ri = new ResolveInfo();
ri.activityInfo = ai;
return ri;
@@ -2352,17 +2428,23 @@ public class ExternalNavigationHandlerTest {
ResolveInfo info = newResolveInfo(packageName);
info.filter = new IntentFilter(Intent.ACTION_VIEW);
info.filter.addDataAuthority(activity.mUrlPrefix, null);
+ info.activityInfo.exported = activity.isExported();
return info;
}
private static class IntentActivity {
private String mUrlPrefix;
private String mPackageName;
- private boolean mIsWebApk;
+ private boolean mIsExported;
public IntentActivity(String urlPrefix, String packageName) {
+ this(urlPrefix, packageName, true);
+ }
+
+ public IntentActivity(String urlPrefix, String packageName, boolean isExported) {
mUrlPrefix = urlPrefix;
mPackageName = packageName;
+ mIsExported = isExported;
}
public String urlPrefix() {
@@ -2373,6 +2455,10 @@ public class ExternalNavigationHandlerTest {
return mPackageName;
}
+ public boolean isExported() {
+ return mIsExported;
+ }
+
public boolean isSpecialized() {
// Specialized if URL prefix is more than just a scheme.
return Pattern.compile("[^:/]+://.+").matcher(mUrlPrefix).matches();
@@ -2393,6 +2479,9 @@ public class ExternalNavigationHandlerTest {
public boolean mCanShowIncognitoDialog;
public AlertDialog mShownIncognitoAlertDialog;
public boolean mResolveInfoContainsSelf;
+ public Intent mStartActivityIntent;
+ public boolean mCalledWithProxy;
+ private boolean mSendIntentsForReal;
public ExternalNavigationHandlerForTesting(ExternalNavigationDelegate delegate) {
super(delegate);
@@ -2471,6 +2560,29 @@ public class ExternalNavigationHandlerTest {
protected boolean resolveInfoContainsSelf(List<ResolveInfo> resolveInfos) {
return mResolveInfoContainsSelf;
}
+
+ @Override
+ protected OverrideUrlLoadingResult startActivity(Intent intent, boolean proxy,
+ boolean requiresIntentChooser, List<ResolveInfo> resolvingInfos,
+ ResolveActivitySupplier resolveActivity, GURL browserFallbackUrl,
+ GURL intentDataUrl, GURL referrerUrl) {
+ mStartActivityIntent = intent;
+ mCalledWithProxy = proxy;
+ if (mSendIntentsForReal) {
+ return super.startActivity(intent, proxy, requiresIntentChooser, resolvingInfos,
+ resolveActivity, browserFallbackUrl, intentDataUrl, referrerUrl);
+ }
+ return OverrideUrlLoadingResult.forExternalIntent();
+ }
+
+ public void sendIntentsForReal() {
+ mSendIntentsForReal = true;
+ }
+
+ public void reset() {
+ mCalledWithProxy = false;
+ mStartActivityIntent = null;
+ }
};
private static class TestExternalNavigationDelegate implements ExternalNavigationDelegate {
@@ -2547,21 +2659,6 @@ public class ExternalNavigationHandlerTest {
public void dispatchAuthenticatedIntent(Intent intent) {}
@Override
- public void didStartActivity(Intent intent) {
- startActivityIntent = intent;
- }
-
- @Override
- public @StartActivityIfNeededResult int maybeHandleStartActivityIfNeeded(
- Intent intent, boolean proxy) {
- // For simplicity, don't distinguish between startActivityIfNeeded and startActivity
- // until a test requires this distinction.
- startActivityIntent = intent;
- mCalledWithProxy = proxy;
- return StartActivityIfNeededResult.HANDLED_WITH_ACTIVITY_START;
- }
-
- @Override
public boolean canLoadUrlInCurrentTab() {
return mCanLoadUrlInTab;
}
@@ -2695,9 +2792,7 @@ public class ExternalNavigationHandlerTest {
}
public void reset() {
- startActivityIntent = null;
startIncognitoIntentCalled = false;
- mCalledWithProxy = false;
}
public void setContext(Context context) {
@@ -2781,7 +2876,6 @@ public class ExternalNavigationHandlerTest {
mWillResolveToDisambiguationDialog = value;
}
- public Intent startActivityIntent;
public boolean startIncognitoIntentCalled;
public boolean maybeSetRequestMetadataCalled;
public Callback<Boolean> incognitoDialogUserDecisionCallback;
@@ -2793,7 +2887,6 @@ public class ExternalNavigationHandlerTest {
private boolean mCanResolveActivityForMarket = true;
private boolean mCanHandleWithInstantApp;
private boolean mHandleWithAutofillAssistant;
- public boolean mCalledWithProxy;
public boolean mIsChromeAppInForeground = true;
private boolean mIsCallingAppTrusted;
private boolean mShouldDisableExternalIntentRequests;
@@ -2917,6 +3010,7 @@ public class ExternalNavigationHandlerTest {
boolean expectProxyForIA = (otherExpectation & PROXY_FOR_INSTANT_APPS) != 0;
mDelegate.reset();
+ mUrlHandler.reset();
ExternalNavigationParams params =
new ExternalNavigationParams
@@ -2936,9 +3030,7 @@ public class ExternalNavigationHandlerTest {
boolean startActivityCalled = false;
boolean startWebApkCalled = false;
- // Incognito intent launching gets caught by the test URL handler, whereas non-incgonito
- // intent launching gets caught by the test delegate.
- Intent startActivityIntent = mDelegate.startActivityIntent;
+ Intent startActivityIntent = mUrlHandler.mStartActivityIntent;
if (startActivityIntent != null) {
startActivityCalled = true;
@@ -2954,7 +3046,7 @@ public class ExternalNavigationHandlerTest {
Assert.assertEquals(expectStartActivity, startActivityCalled);
Assert.assertEquals(expectStartWebApk, startWebApkCalled);
Assert.assertEquals(expectStartFile, mUrlHandler.mStartFileIntentCalled);
- Assert.assertEquals(expectProxyForIA, mDelegate.mCalledWithProxy);
+ Assert.assertEquals(expectProxyForIA, mUrlHandler.mCalledWithProxy);
if (startActivityCalled && expectSaneIntent) {
checkIntentSanity(startActivityIntent, "Intent");
diff --git a/chromium/components/external_intents/android/javatests/src/org/chromium/components/external_intents/RedirectHandlerTest.java b/chromium/components/external_intents/android/javatests/src/org/chromium/components/external_intents/RedirectHandlerTest.java
index 4926f244a6b..70f1d6f943d 100644
--- a/chromium/components/external_intents/android/javatests/src/org/chromium/components/external_intents/RedirectHandlerTest.java
+++ b/chromium/components/external_intents/android/javatests/src/org/chromium/components/external_intents/RedirectHandlerTest.java
@@ -4,6 +4,7 @@
package org.chromium.components.external_intents;
+import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
@@ -14,17 +15,18 @@ import android.test.mock.MockPackageManager;
import androidx.test.filters.SmallTest;
+import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.chromium.base.CommandLine;
import org.chromium.base.ContextUtils;
import org.chromium.base.Function;
import org.chromium.base.PackageManagerUtils;
import org.chromium.base.test.BaseJUnit4ClassRunner;
import org.chromium.base.test.util.AdvancedMockContext;
+import org.chromium.base.test.util.Batch;
import org.chromium.base.test.util.Feature;
import org.chromium.ui.base.PageTransition;
@@ -36,6 +38,7 @@ import java.util.List;
* Unittests for tab redirect handler.
*/
@RunWith(BaseJUnit4ClassRunner.class)
+@Batch(Batch.UNIT_TESTS)
public class RedirectHandlerTest {
private static final int TRANS_TYPE_OF_LINK_FROM_INTENT =
PageTransition.LINK | PageTransition.FROM_API;
@@ -47,6 +50,8 @@ public class RedirectHandlerTest {
private Function<Intent, List<ResolveInfo>> mQueryIntentFunction =
(Intent intent) -> queryIntentActivities(intent);
+ private Context mContextToRestore;
+
static {
try {
sYtIntent = Intent.parseUri("http://youtube.com/", Intent.URI_INTENT_SCHEME);
@@ -59,10 +64,15 @@ public class RedirectHandlerTest {
@Before
public void setUp() {
- CommandLine.init(new String[0]);
+ mContextToRestore = ContextUtils.getApplicationContext();
ContextUtils.initApplicationContextForTests(new TestContext());
}
+ @After
+ public void tearDown() {
+ ContextUtils.initApplicationContextForTests(mContextToRestore);
+ }
+
private List<ResolveInfo> queryIntentActivities(Intent intent) {
return PackageManagerUtils.queryIntentActivities(intent, 0);
}
@@ -179,7 +189,6 @@ public class RedirectHandlerTest {
handler.clear();
Assert.assertFalse(handler.isOnNavigation());
- Assert.assertFalse(handler.isOnEffectiveIntentRedirectChain());
Assert.assertTrue(handler.hasNewResolver(
queryIntentActivities(sMoblieYtIntent), mQueryIntentFunction));
Assert.assertTrue(
@@ -253,8 +262,6 @@ public class RedirectHandlerTest {
fooIntent.putExtra(Browser.EXTRA_APPLICATION_ID, TEST_PACKAGE_NAME);
handler.updateIntent(fooIntent, false, false, false, false);
Assert.assertFalse(handler.isOnNavigation());
- Assert.assertTrue(handler.shouldStayInApp(false));
- Assert.assertFalse(handler.shouldStayInApp(true));
handler.updateNewUrlLoading(TRANS_TYPE_OF_LINK_FROM_INTENT, false, false, 0, 0, false);
Assert.assertTrue(handler.shouldStayInApp(false));
@@ -283,7 +290,6 @@ public class RedirectHandlerTest {
RedirectHandler handler = RedirectHandler.create();
handler.updateIntent(sYtIntent, false, false, false, false);
Assert.assertFalse(handler.isOnNavigation());
- Assert.assertFalse(handler.isNavigationFromUserTyping());
handler.updateNewUrlLoading(PageTransition.TYPED, false, false, 0, 0, false);
Assert.assertTrue(handler.isNavigationFromUserTyping());
@@ -311,8 +317,6 @@ public class RedirectHandlerTest {
fooIntent.setPackage(TEST_PACKAGE_NAME);
handler.updateIntent(fooIntent, false, false, false, false);
Assert.assertFalse(handler.isOnNavigation());
- Assert.assertTrue(handler.shouldStayInApp(false));
- Assert.assertFalse(handler.shouldStayInApp(true));
handler.updateNewUrlLoading(TRANS_TYPE_OF_LINK_FROM_INTENT, false, false, 0, 0, false);
Assert.assertTrue(handler.shouldStayInApp(false));
@@ -343,9 +347,9 @@ public class RedirectHandlerTest {
/////////////////////////////////////////////////////
RedirectHandler handler = RedirectHandler.create();
handler.updateIntent(sYtIntent, false, false, false, false);
- Assert.assertFalse(handler.shouldNotOverrideUrlLoading());
handler.updateNewUrlLoading(PageTransition.LINK, false, true, 0, 0, false);
+ Assert.assertFalse(handler.shouldNotOverrideUrlLoading());
handler.setShouldNotOverrideUrlLoadingOnCurrentRedirectChain();
handler.updateNewUrlLoading(PageTransition.LINK, true, false, 0, 0, false);
@@ -357,9 +361,9 @@ public class RedirectHandlerTest {
/////////////////////////////////////////////////////
handler = RedirectHandler.create();
handler.updateIntent(sYtIntent, false, false, false, false);
- Assert.assertFalse(handler.shouldNotOverrideUrlLoading());
handler.updateNewUrlLoading(PageTransition.LINK, false, true, 0, 0, false);
+ Assert.assertFalse(handler.shouldNotOverrideUrlLoading());
handler.setShouldNotOverrideUrlLoadingOnCurrentRedirectChain();
// Effective redirection occurred.
@@ -384,8 +388,6 @@ public class RedirectHandlerTest {
RedirectHandler handler = RedirectHandler.create();
handler.updateIntent(sYtIntent, false, false, false, false);
Assert.assertFalse(handler.isOnNavigation());
- Assert.assertFalse(handler.shouldStayInApp(false));
- Assert.assertFalse(handler.shouldStayInApp(true));
long lastUserInteractionTime = SystemClock.elapsedRealtime();
handler.updateNewUrlLoading(
@@ -417,8 +419,6 @@ public class RedirectHandlerTest {
RedirectHandler handler = RedirectHandler.create();
handler.updateIntent(sYtIntent, false, false, false, false);
Assert.assertFalse(handler.isOnNavigation());
- Assert.assertFalse(handler.shouldStayInApp(false));
- Assert.assertFalse(handler.shouldStayInApp(true));
long lastUserInteractionTime = SystemClock.elapsedRealtime();
handler.updateNewUrlLoading(
@@ -450,15 +450,14 @@ public class RedirectHandlerTest {
RedirectHandler handler = RedirectHandler.create();
handler.updateIntent(sYtIntent, false, false, false, false);
Assert.assertFalse(handler.isOnNavigation());
- Assert.assertFalse(handler.shouldStayInApp(false));
- Assert.assertFalse(handler.shouldStayInApp(true));
- Assert.assertFalse(handler.hasUserStartedNonInitialNavigation());
long lastUserInteractionTime = SystemClock.elapsedRealtime();
handler.updateNewUrlLoading(PageTransition.FORM_SUBMIT | PageTransition.FORWARD_BACK, false,
true, lastUserInteractionTime, 0, false);
Assert.assertTrue(handler.shouldStayInApp(false));
Assert.assertTrue(handler.shouldStayInApp(true));
+ Assert.assertTrue(handler.hasUserStartedNonInitialNavigation());
+
handler.updateNewUrlLoading(PageTransition.LINK, false, false, lastUserInteractionTime, 1,
false /* isInitialNavigation */);
Assert.assertTrue(handler.shouldStayInApp(false));
@@ -490,10 +489,10 @@ public class RedirectHandlerTest {
Assert.assertFalse(handler.isOnNavigation());
handler.updateNewUrlLoading(PageTransition.LINK, false, true,
- uninitializedUserInteractionTime, RedirectHandler.INVALID_ENTRY_INDEX,
+ uninitializedUserInteractionTime, RedirectHandler.NO_COMMITTED_ENTRY_INDEX,
true /* isInitialNavigation */);
Assert.assertTrue(handler.isOnNavigation());
- Assert.assertEquals(RedirectHandler.INVALID_ENTRY_INDEX,
+ Assert.assertEquals(RedirectHandler.NO_COMMITTED_ENTRY_INDEX,
handler.getLastCommittedEntryIndexBeforeStartingNavigation());
Assert.assertFalse(handler.hasUserStartedNonInitialNavigation());
}
@@ -527,6 +526,19 @@ public class RedirectHandlerTest {
Assert.assertFalse(handler.hasUserStartedNonInitialNavigation());
}
+ @Test
+ @SmallTest
+ @Feature({"IntentHandling"})
+ public void testLastCommittedIndexPersistsThroughClear() {
+ int lastIndex = 1234;
+ RedirectHandler handler = RedirectHandler.create();
+ handler.updateNewUrlLoading(PageTransition.LINK, false /* isRedirect */,
+ false /* hasUserGesture */, 0, lastIndex, true /* isInitialNavigation */);
+ handler.clear();
+ Assert.assertEquals(
+ lastIndex, handler.getLastCommittedEntryIndexBeforeStartingNavigation());
+ }
+
private static class TestPackageManager extends MockPackageManager {
@Override
public List<ResolveInfo> queryIntentActivities(Intent intent, int flags) {
diff --git a/chromium/components/favicon/content/content_favicon_driver.cc b/chromium/components/favicon/content/content_favicon_driver.cc
index 13025e86be5..6ca56f53160 100644
--- a/chromium/components/favicon/content/content_favicon_driver.cc
+++ b/chromium/components/favicon/content/content_favicon_driver.cc
@@ -173,7 +173,7 @@ void ContentFaviconDriver::DidUpdateFaviconURL(
if (!entry)
return;
- if (!rfh->IsDocumentOnLoadCompletedInMainFrame())
+ if (!rfh->IsDocumentOnLoadCompletedInPrimaryMainFrame())
return;
OnUpdateCandidates(rfh->GetLastCommittedURL(),
@@ -188,7 +188,7 @@ void ContentFaviconDriver::DidUpdateWebManifestURL(
// occur when loading an initially blank page.
content::NavigationEntry* entry =
web_contents()->GetController().GetLastCommittedEntry();
- if (!entry || !rfh->IsDocumentOnLoadCompletedInMainFrame())
+ if (!entry || !rfh->IsDocumentOnLoadCompletedInPrimaryMainFrame())
return;
DocumentManifestData* document_data =
diff --git a/chromium/components/favicon/content/content_favicon_driver_unittest.cc b/chromium/components/favicon/content/content_favicon_driver_unittest.cc
index c0ace2fdf5c..4ea8e835afe 100644
--- a/chromium/components/favicon/content/content_favicon_driver_unittest.cc
+++ b/chromium/components/favicon/content/content_favicon_driver_unittest.cc
@@ -145,8 +145,9 @@ TEST_F(ContentFaviconDriverTest, UseManifestURLAFterOnLoad) {
favicon_driver->GetManifestURL(web_contents()->GetMainFrame()));
}
-// Test that no download is initiated when DocumentOnLoadCompletedInMainFrame()
-// is not triggered (e.g. user stopped an ongoing page load).
+// Test that no download is initiated when
+// DocumentOnLoadCompletedInPrimaryMainFrame() is not triggered (e.g. user
+// stopped an ongoing page load).
TEST_F(ContentFaviconDriverTest, ShouldNotCauseImageDownload) {
ContentFaviconDriver* favicon_driver =
ContentFaviconDriver::FromWebContents(web_contents());
diff --git a/chromium/components/favicon/core/favicon_database.cc b/chromium/components/favicon/core/favicon_database.cc
index b9e0e966e57..9b9eb09b8cb 100644
--- a/chromium/components/favicon/core/favicon_database.cc
+++ b/chromium/components/favicon/core/favicon_database.cc
@@ -8,13 +8,13 @@
#include <stdint.h>
#include <algorithm>
#include <string>
+#include <tuple>
#include <utility>
#include "base/bind.h"
#include "base/bits.h"
#include "base/debug/alias.h"
#include "base/files/file_util.h"
-#include "base/ignore_result.h"
#include "base/logging.h"
#include "base/memory/ref_counted_memory.h"
#include "base/metrics/histogram_macros.h"
@@ -29,7 +29,7 @@
#include "sql/transaction.h"
#include "third_party/sqlite/sqlite3.h"
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
#include "base/mac/backup_util.h"
#endif
@@ -223,7 +223,7 @@ void DatabaseErrorCallback(sql::Database* db,
// or hardware issues, not coding errors at the client level, so displaying
// the error would probably lead to confusion. The ignored call signals the
// test-expectation framework that the error was handled.
- ignore_result(sql::Database::IsExpectedSqliteError(extended_error));
+ std::ignore = sql::Database::IsExpectedSqliteError(extended_error);
return;
}
@@ -368,7 +368,7 @@ void FaviconDatabase::RollbackTransaction() {
void FaviconDatabase::Vacuum() {
DCHECK(db_.transaction_nesting() == 0)
<< "Can not have a transaction when vacuuming.";
- ignore_result(db_.Execute("VACUUM"));
+ std::ignore = db_.Execute("VACUUM");
}
void FaviconDatabase::TrimMemory() {
@@ -1080,13 +1080,13 @@ sql::InitStatus FaviconDatabase::InitImpl(const base::FilePath& db_name) {
// TODO(shess): Failing Begin() implies that something serious is
// wrong with the database. Raze() may be in order.
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
// Exclude the favicons file from backups.
base::mac::SetBackupExclusion(db_name);
#endif
// thumbnails table has been obsolete for a long time, remove any detritus.
- ignore_result(db_.Execute("DROP TABLE IF EXISTS thumbnails"));
+ std::ignore = db_.Execute("DROP TABLE IF EXISTS thumbnails");
// At some point, operations involving temporary tables weren't done
// atomically and users have been stranded. Drop those tables and
@@ -1094,9 +1094,9 @@ sql::InitStatus FaviconDatabase::InitImpl(const base::FilePath& db_name) {
// TODO(shess): Prove it? Audit all cases and see if it's possible
// that this implies non-atomic update, and should thus be handled
// via the corruption handler.
- ignore_result(db_.Execute("DROP TABLE IF EXISTS temp_favicons"));
- ignore_result(db_.Execute("DROP TABLE IF EXISTS temp_favicon_bitmaps"));
- ignore_result(db_.Execute("DROP TABLE IF EXISTS temp_icon_mapping"));
+ std::ignore = db_.Execute("DROP TABLE IF EXISTS temp_favicons");
+ std::ignore = db_.Execute("DROP TABLE IF EXISTS temp_favicon_bitmaps");
+ std::ignore = db_.Execute("DROP TABLE IF EXISTS temp_icon_mapping");
// Create the tables.
if (!meta_table_.Init(&db_, kCurrentVersionNumber,
diff --git a/chromium/components/favicon/core/favicon_database_unittest.cc b/chromium/components/favicon/core/favicon_database_unittest.cc
index ebb845fc1bd..12a3b7f2fc2 100644
--- a/chromium/components/favicon/core/favicon_database_unittest.cc
+++ b/chromium/components/favicon/core/favicon_database_unittest.cc
@@ -98,7 +98,7 @@ void VerifyDatabaseEmpty(sql::Database* db) {
}
// Helper to check that an expected mapping exists.
-WARN_UNUSED_RESULT bool CheckPageHasIcon(
+[[nodiscard]] bool CheckPageHasIcon(
FaviconDatabase* db,
const GURL& page_url,
favicon_base::IconType expected_icon_type,
diff --git a/chromium/components/favicon/core/favicon_driver_impl.cc b/chromium/components/favicon/core/favicon_driver_impl.cc
index 5c48be419d0..d7a0c996774 100644
--- a/chromium/components/favicon/core/favicon_driver_impl.cc
+++ b/chromium/components/favicon/core/favicon_driver_impl.cc
@@ -16,7 +16,7 @@
namespace favicon {
namespace {
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
const bool kEnableTouchIcon = true;
#else
const bool kEnableTouchIcon = false;
diff --git a/chromium/components/favicon/ios/web_favicon_driver.h b/chromium/components/favicon/ios/web_favicon_driver.h
index 1b0c8e2374a..84bbb2a546b 100644
--- a/chromium/components/favicon/ios/web_favicon_driver.h
+++ b/chromium/components/favicon/ios/web_favicon_driver.h
@@ -11,6 +11,7 @@
#import "ios/web/public/web_state_user_data.h"
namespace web {
+struct FaviconStatus;
class WebState;
}
@@ -73,6 +74,13 @@ class WebFaviconDriver : public web::WebStateObserver,
void FaviconUrlUpdatedInternal(
const std::vector<favicon::FaviconURL>& candidates);
+ // Invoked to set the WebState's favicon and notify the observers.
+ void SetFaviconStatus(
+ const GURL& page_url,
+ const web::FaviconStatus& favicon_status,
+ FaviconDriverObserver::NotificationIconType notification_icon_type,
+ bool icon_url_changed);
+
// Image Fetcher used to fetch favicon.
image_fetcher::IOSImageDataFetcherWrapper image_fetcher_;
diff --git a/chromium/components/favicon/ios/web_favicon_driver.mm b/chromium/components/favicon/ios/web_favicon_driver.mm
index f4d231a5c77..00ca6e83c37 100644
--- a/chromium/components/favicon/ios/web_favicon_driver.mm
+++ b/chromium/components/favicon/ios/web_favicon_driver.mm
@@ -36,30 +36,15 @@ void WebFaviconDriver::CreateForWebState(web::WebState* web_state,
}
gfx::Image WebFaviconDriver::GetFavicon() const {
- web::NavigationItem* item = nil;
- if (web_state_->IsRealized()) {
- item = web_state_->GetNavigationManager()->GetLastCommittedItem();
- }
-
- return item ? item->GetFavicon().image : gfx::Image();
+ return web_state_->GetFaviconStatus().image;
}
bool WebFaviconDriver::FaviconIsValid() const {
- web::NavigationItem* item = nil;
- if (web_state_->IsRealized()) {
- item = web_state_->GetNavigationManager()->GetLastCommittedItem();
- }
-
- return item ? item->GetFavicon().valid : false;
+ return web_state_->GetFaviconStatus().valid;
}
GURL WebFaviconDriver::GetActiveURL() {
- web::NavigationItem* item = nil;
- if (web_state_->IsRealized()) {
- item = web_state_->GetNavigationManager()->GetLastCommittedItem();
- }
-
- return item ? item->GetURL() : GURL();
+ return web_state_->GetLastCommittedURL();
}
int WebFaviconDriver::DownloadImage(const GURL& url,
@@ -111,41 +96,20 @@ void WebFaviconDriver::OnFaviconUpdated(
const GURL& icon_url,
bool icon_url_changed,
const gfx::Image& image) {
- // Check whether the active URL has changed since FetchFavicon() was called.
- // On iOS, the active URL can change between calls to FetchFavicon(). For
- // instance, FetchFavicon() is not synchronously called when the active URL
- // changes as a result of CRWSessionController::goToEntry().
- web::NavigationItem* item =
- web_state_->GetNavigationManager()->GetLastCommittedItem();
- if (!item || item->GetURL() != page_url)
- return;
-
- web::FaviconStatus& favicon_status = item->GetFavicon();
+ web::FaviconStatus favicon_status;
favicon_status.valid = true;
favicon_status.image = image;
favicon_status.url = icon_url;
- NotifyFaviconUpdatedObservers(notification_icon_type, icon_url,
- icon_url_changed, image);
+ SetFaviconStatus(page_url, favicon_status, notification_icon_type,
+ icon_url_changed);
}
void WebFaviconDriver::OnFaviconDeleted(
const GURL& page_url,
FaviconDriverObserver::NotificationIconType notification_icon_type) {
- // Check whether the active URL has changed since FetchFavicon() was called.
- // On iOS, the active URL can change between calls to FetchFavicon(). For
- // instance, FetchFavicon() is not synchronously called when the active URL
- // changes as a result of CRWSessionController::goToEntry().
- web::NavigationItem* item =
- web_state_->GetNavigationManager()->GetLastCommittedItem();
- if (!item || item->GetURL() != page_url)
- return;
-
- item->GetFavicon() = web::FaviconStatus();
-
- NotifyFaviconUpdatedObservers(notification_icon_type, /*icon_url=*/GURL(),
- /*icon_url_changed=*/true,
- item->GetFavicon().image);
+ SetFaviconStatus(page_url, web::FaviconStatus(), notification_icon_type,
+ /*icon_url_changed=*/true);
}
WebFaviconDriver::WebFaviconDriver(web::WebState* web_state,
@@ -185,6 +149,23 @@ void WebFaviconDriver::WebStateDestroyed(web::WebState* web_state) {
web_state_ = nullptr;
}
+void WebFaviconDriver::SetFaviconStatus(
+ const GURL& page_url,
+ const web::FaviconStatus& favicon_status,
+ FaviconDriverObserver::NotificationIconType notification_icon_type,
+ bool icon_url_changed) {
+ // Check whether the active URL has changed since FetchFavicon() was called.
+ // On iOS, the active URL can change between calls to FetchFavicon(). For
+ // instance, FetchFavicon() is not synchronously called when the active URL
+ // changes as a result of CRWSessionController::goToEntry().
+ if (web_state_->GetLastCommittedURL() != page_url)
+ return;
+
+ web_state_->SetFaviconStatus(favicon_status);
+ NotifyFaviconUpdatedObservers(notification_icon_type, favicon_status.url,
+ icon_url_changed, favicon_status.image);
+}
+
WEB_STATE_USER_DATA_KEY_IMPL(WebFaviconDriver)
} // namespace favicon
diff --git a/chromium/components/favicon_base/favicon_url_parser.cc b/chromium/components/favicon_base/favicon_url_parser.cc
index 83a7b5f6ec2..a8c23a8a8d6 100644
--- a/chromium/components/favicon_base/favicon_url_parser.cc
+++ b/chromium/components/favicon_base/favicon_url_parser.cc
@@ -94,7 +94,7 @@ bool ParseFaviconPathWithFavicon2Format(const std::string& path,
*parsed = chrome::ParsedFaviconPath();
for (net::QueryIterator it(query_url); !it.IsAtEnd(); it.Advance()) {
- const std::string key = it.GetKey();
+ const base::StringPiece key = it.GetKey();
// Note: each of these keys can be used in chrome://favicon2 path. See file
// "favicon_url_parser.h" for a description of what each one does.
if (key == "allow_google_server_fallback") {
diff --git a/chromium/components/favicon_base/favicon_util.cc b/chromium/components/favicon_base/favicon_util.cc
index ae9a68dd009..c179615cc5a 100644
--- a/chromium/components/favicon_base/favicon_util.cc
+++ b/chromium/components/favicon_base/favicon_util.cc
@@ -24,9 +24,9 @@
#include "ui/gfx/image/image_png_rep.h"
#include "ui/gfx/image/image_skia.h"
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
#include "base/mac/mac_util.h"
-#endif // defined(OS_MAC)
+#endif // BUILDFLAG(IS_MAC)
namespace favicon_base {
namespace {
@@ -161,9 +161,9 @@ std::vector<float> GetFaviconScales() {
}
void SetFaviconColorSpace(gfx::Image* image) {
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
image->SetSourceColorSpace(base::mac::GetSystemColorSpace());
-#endif // defined(OS_MAC)
+#endif // BUILDFLAG(IS_MAC)
}
gfx::Image SelectFaviconFramesFromPNGs(
diff --git a/chromium/components/favicon_base/favicon_util.h b/chromium/components/favicon_base/favicon_util.h
index 274bc3cc83b..d9a2e3ffec0 100644
--- a/chromium/components/favicon_base/favicon_util.h
+++ b/chromium/components/favicon_base/favicon_util.h
@@ -45,6 +45,6 @@ favicon_base::FaviconRawBitmapResult ResizeFaviconBitmapResult(
favicon_bitmap_results,
int desired_size_in_pixel);
-} // namspace favicon_base
+} // namespace favicon_base
#endif // COMPONENTS_FAVICON_BASE_FAVICON_UTIL_H_
diff --git a/chromium/components/favicon_base/select_favicon_frames_unittest.cc b/chromium/components/favicon_base/select_favicon_frames_unittest.cc
index e6e729d89c5..6d0bc46ef5f 100644
--- a/chromium/components/favicon_base/select_favicon_frames_unittest.cc
+++ b/chromium/components/favicon_base/select_favicon_frames_unittest.cc
@@ -103,7 +103,7 @@ TEST(SelectFaviconFramesTest, _16From16) {
EXPECT_EQ(16, image.height());
EXPECT_EQ(SK_ColorGREEN, GetColor1x(image));
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
const gfx::ImageSkiaRep& rep = image.GetRepresentation(1.5f);
EXPECT_EQ(1.5f, rep.scale());
EXPECT_EQ(16, rep.GetWidth());
@@ -186,7 +186,7 @@ TEST(SelectFaviconFramesTest, _16From16_Scale2x_32_From_32) {
EXPECT_EQ(SK_ColorGREEN, GetColor1x(image));
EXPECT_EQ(SK_ColorBLUE, GetColor2x(image));
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
const gfx::ImageSkiaRep& rep = image.GetRepresentation(1.5f);
EXPECT_EQ(1.5f, rep.scale());
EXPECT_EQ(16, rep.GetWidth());
diff --git a/chromium/components/feature_engagement/README.md b/chromium/components/feature_engagement/README.md
index 8080a8e33c4..a915d69fee9 100644
--- a/chromium/components/feature_engagement/README.md
+++ b/chromium/components/feature_engagement/README.md
@@ -564,16 +564,37 @@ into the same field trial.
**Examples**
+Trigger the IPH once every 4 months if the `download_completed` event has
+triggered at least one time and the `download_home_iph_trigger` (download home
+IPH) hasn't triggered in the last 90 days. The feature needs to have been
+available for more than a month and no other IPH has been shown for the current
+session.
+
+The event we are trying to increase the usage of is `download_home_opened` and
+is allowed to have previously happened for the IPH to trigger.
```
{
"availability": ">=30",
"session_rate": "<1",
"event_used": "name:download_home_opened;comparator:any;window:90;storage:360",
- "event_trigger": "name:download_home_iph_trigger;comparator:any;window:90;storage:360",
+ "event_trigger": "name:download_home_iph_trigger;comparator:==0;window:90;storage:360",
"event_1": "name:download_completed;comparator:>=1;window:120;storage:180"
}
```
+Trigger the IPH once per week, up to 3 times per year as long as the user
+hasn't triggered `shopping_list_track_price_from_menu`. The IPH should be ready
+to trigger as long as no other IPH has been shown.
+```
+{
+ "availability": ">=0",
+ "session_rate": "<1",
+ "event_used": "name:shopping_list_track_price_from_menu;comparator:==0;window:360;storage:360",
+ "event_trigger": "shopping_list_menu_item_iph_triggered;comparator:==0;window:7;storage:7",
+ "event_trigger_1": "shopping_list_menu_item_iph_triggered;comparator:<3;window:36;storage:360"
+}
+```
+
### EventConfig
Format:
@@ -613,9 +634,21 @@ all described below:
**Examples**
+The user_opened_app_menu event hasn't triggered in the last two weeks. Keep
+existing events for 90 days.
```
name:user_opened_app_menu;comparator:==0;window:14;storage:90
+```
+
+The user_has_seen_dino event has occurred at least 5 times in the last 30 days.
+Keep existing events for about a year.
+```
name:user_has_seen_dino;comparator:>=5;window:30;storage:360
+```
+
+The user_has_seen_wifi event has occurred at least once in the last 30 days.
+Keep existing events for 6 months.
+```
name:user_has_seen_wifi;comparator:>=1;window:30;storage:180
```
diff --git a/chromium/components/feature_engagement/internal/android/tracker_impl_android.cc b/chromium/components/feature_engagement/internal/android/tracker_impl_android.cc
index 175cff08d98..4a591df1bbc 100644
--- a/chromium/components/feature_engagement/internal/android/tracker_impl_android.cc
+++ b/chromium/components/feature_engagement/internal/android/tracker_impl_android.cc
@@ -18,6 +18,7 @@
#include "components/feature_engagement/internal/jni_headers/TrackerImpl_jni.h"
#include "components/feature_engagement/public/feature_list.h"
#include "components/feature_engagement/public/tracker.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
namespace feature_engagement {
@@ -185,6 +186,51 @@ TrackerImplAndroid::AcquireDisplayLock(
return lock_handle_android.release()->GetJavaObject();
}
+void TrackerImplAndroid::SetPriorityNotification(
+ JNIEnv* env,
+ const base::android::JavaRef<jobject>& jobj,
+ const base::android::JavaParamRef<jstring>& jfeature) {
+ std::string feature = ConvertJavaStringToUTF8(env, jfeature);
+ DCHECK(features_.find(feature) != features_.end());
+
+ return tracker_->SetPriorityNotification(*features_[feature]);
+}
+
+base::android::ScopedJavaLocalRef<jstring>
+TrackerImplAndroid::GetPendingPriorityNotification(
+ JNIEnv* env,
+ const base::android::JavaRef<jobject>& jobj) {
+ auto notification = tracker_->GetPendingPriorityNotification();
+ std::string pending_notification_string =
+ notification.value_or(std::string());
+ return base::android::ConvertUTF8ToJavaString(env,
+ pending_notification_string);
+}
+
+void TrackerImplAndroid::RegisterPriorityNotificationHandler(
+ JNIEnv* env,
+ const base::android::JavaRef<jobject>& jobj,
+ const base::android::JavaParamRef<jstring>& jfeature,
+ const base::android::JavaRef<jobject>& jrunnable) {
+ std::string feature = ConvertJavaStringToUTF8(env, jfeature);
+ DCHECK(features_.find(feature) != features_.end());
+
+ return tracker_->RegisterPriorityNotificationHandler(
+ *features_[feature],
+ base::BindOnce(&base::android::RunRunnableAndroid,
+ base::android::ScopedJavaGlobalRef<jobject>(jrunnable)));
+}
+
+void TrackerImplAndroid::UnregisterPriorityNotificationHandler(
+ JNIEnv* env,
+ const base::android::JavaRef<jobject>& jobj,
+ const base::android::JavaParamRef<jstring>& jfeature) {
+ std::string feature = ConvertJavaStringToUTF8(env, jfeature);
+ DCHECK(features_.find(feature) != features_.end());
+
+ return tracker_->UnregisterPriorityNotificationHandler(*features_[feature]);
+}
+
bool TrackerImplAndroid::IsInitialized(
JNIEnv* env,
const base::android::JavaRef<jobject>& jobj) {
diff --git a/chromium/components/feature_engagement/internal/android/tracker_impl_android.h b/chromium/components/feature_engagement/internal/android/tracker_impl_android.h
index e8776973a48..9a686747acf 100644
--- a/chromium/components/feature_engagement/internal/android/tracker_impl_android.h
+++ b/chromium/components/feature_engagement/internal/android/tracker_impl_android.h
@@ -111,6 +111,22 @@ class TrackerImplAndroid : public base::SupportsUserData::Data {
virtual base::android::ScopedJavaLocalRef<jobject> AcquireDisplayLock(
JNIEnv* env,
const base::android::JavaRef<jobject>& jobj);
+ virtual void SetPriorityNotification(
+ JNIEnv* env,
+ const base::android::JavaRef<jobject>& jobj,
+ const base::android::JavaParamRef<jstring>& jfeature);
+ virtual base::android::ScopedJavaLocalRef<jstring>
+ GetPendingPriorityNotification(JNIEnv* env,
+ const base::android::JavaRef<jobject>& jobj);
+ virtual void RegisterPriorityNotificationHandler(
+ JNIEnv* env,
+ const base::android::JavaRef<jobject>& jobj,
+ const base::android::JavaParamRef<jstring>& jfeature,
+ const base::android::JavaRef<jobject>& jcallback);
+ virtual void UnregisterPriorityNotificationHandler(
+ JNIEnv* env,
+ const base::android::JavaRef<jobject>& jobj,
+ const base::android::JavaParamRef<jstring>& jfeature);
virtual bool IsInitialized(JNIEnv* env,
const base::android::JavaRef<jobject>& jobj);
virtual void AddOnInitializedCallback(
diff --git a/chromium/components/feature_engagement/internal/condition_validator.cc b/chromium/components/feature_engagement/internal/condition_validator.cc
index 155cbdf79ed..2bada26e9cd 100644
--- a/chromium/components/feature_engagement/internal/condition_validator.cc
+++ b/chromium/components/feature_engagement/internal/condition_validator.cc
@@ -21,6 +21,7 @@ ConditionValidator::Result::Result(bool initial_values)
availability_ok(initial_values),
display_lock_ok(initial_values),
snooze_expiration_ok(initial_values),
+ priority_notification_ok(initial_values),
should_show_snooze(initial_values) {}
ConditionValidator::Result::Result(const Result& other) = default;
@@ -32,7 +33,7 @@ bool ConditionValidator::Result::NoErrors() const {
return event_model_ready_ok && currently_showing_ok && feature_enabled_ok &&
config_ok && used_ok && trigger_ok && preconditions_ok &&
session_rate_ok && availability_model_ready_ok && availability_ok &&
- display_lock_ok && snooze_expiration_ok;
+ display_lock_ok && snooze_expiration_ok && priority_notification_ok;
}
std::ostream& operator<<(std::ostream& os,
@@ -50,6 +51,7 @@ std::ostream& operator<<(std::ostream& os,
<< ", availability_ok=" << result.availability_ok
<< ", display_lock_ok=" << result.display_lock_ok
<< ", snooze_expiration_ok=" << result.snooze_expiration_ok
+ << ", priority_notification_ok=" << result.priority_notification_ok
<< ", should_show_snooze=" << result.should_show_snooze << " }";
}
diff --git a/chromium/components/feature_engagement/internal/condition_validator.h b/chromium/components/feature_engagement/internal/condition_validator.h
index edd4700d7e3..facd64dc12a 100644
--- a/chromium/components/feature_engagement/internal/condition_validator.h
+++ b/chromium/components/feature_engagement/internal/condition_validator.h
@@ -13,6 +13,7 @@
#include "components/feature_engagement/public/configuration.h"
#include "components/feature_engagement/public/feature_list.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
namespace base {
struct Feature;
@@ -73,6 +74,10 @@ class ConditionValidator {
// Whether the current snooze timer has expired.
bool snooze_expiration_ok;
+ // Whether the given feature is a priority notification, or there are no
+ // other priority notifications.
+ bool priority_notification_ok;
+
// Whether the snooze option should be shown.
// This value is excluded from the NoErrors() check.
bool should_show_snooze;
@@ -106,6 +111,14 @@ class ConditionValidator {
// Must be called to notify that the |feature| is no longer showing.
virtual void NotifyDismissed(const base::Feature& feature) = 0;
+ // Called to notify that we have a priority notification to be shown next. All
+ // other IPHs will be blocked until then.
+ virtual void SetPriorityNotification(
+ const absl::optional<std::string>& feature) = 0;
+
+ // Called to get if there is a pending priority notification to be shown next.
+ virtual absl::optional<std::string> GetPendingPriorityNotification() = 0;
+
protected:
ConditionValidator() = default;
};
diff --git a/chromium/components/feature_engagement/internal/condition_validator_unittest.cc b/chromium/components/feature_engagement/internal/condition_validator_unittest.cc
index 860d396d2da..70c734aea89 100644
--- a/chromium/components/feature_engagement/internal/condition_validator_unittest.cc
+++ b/chromium/components/feature_engagement/internal/condition_validator_unittest.cc
@@ -82,6 +82,12 @@ TEST(ConditionValidatorResultTest, TestDisplayLockFailed) {
EXPECT_FALSE(result.NoErrors());
}
+TEST(ConditionValidatorResultTest, TestPriorityNotificationFailed) {
+ ConditionValidator::Result result(true);
+ result.priority_notification_ok = false;
+ EXPECT_FALSE(result.NoErrors());
+}
+
TEST(ConditionValidatorResultTest, TestMultipleErrors) {
ConditionValidator::Result result(true);
result.preconditions_ok = false;
diff --git a/chromium/components/feature_engagement/internal/feature_config_condition_validator.cc b/chromium/components/feature_engagement/internal/feature_config_condition_validator.cc
index 11449457c33..7c5ae7f80f7 100644
--- a/chromium/components/feature_engagement/internal/feature_config_condition_validator.cc
+++ b/chromium/components/feature_engagement/internal/feature_config_condition_validator.cc
@@ -18,6 +18,7 @@
#include "components/feature_engagement/internal/proto/feature_event.pb.h"
#include "components/feature_engagement/public/configuration.h"
#include "components/feature_engagement/public/feature_list.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
namespace feature_engagement {
@@ -63,6 +64,10 @@ ConditionValidator::Result FeatureConfigConditionValidator::MeetsConditions(
(event_model.GetLastSnoozeTimestamp(config.trigger.name) <
base::Time::Now() - base::Days(config.snooze_params.snooze_interval));
+ result.priority_notification_ok =
+ !pending_priority_notification_.has_value() ||
+ pending_priority_notification_.value() == feature.name;
+
result.should_show_snooze =
result.snooze_expiration_ok &&
event_model.GetSnoozeCount(config.trigger.name, config.trigger.window,
@@ -115,6 +120,17 @@ bool FeatureConfigConditionValidator::EventConfigMeetsConditions(
return event_config.comparator.MeetsCriteria(event_count);
}
+void FeatureConfigConditionValidator::SetPriorityNotification(
+ const absl::optional<std::string>& feature) {
+ DCHECK(!pending_priority_notification_.has_value() || !feature.has_value());
+ pending_priority_notification_ = feature;
+}
+
+absl::optional<std::string>
+FeatureConfigConditionValidator::GetPendingPriorityNotification() {
+ return pending_priority_notification_;
+}
+
bool FeatureConfigConditionValidator::AvailabilityMeetsConditions(
const base::Feature& feature,
Comparator comparator,
diff --git a/chromium/components/feature_engagement/internal/feature_config_condition_validator.h b/chromium/components/feature_engagement/internal/feature_config_condition_validator.h
index 4e1583c2d85..37bf99d80e6 100644
--- a/chromium/components/feature_engagement/internal/feature_config_condition_validator.h
+++ b/chromium/components/feature_engagement/internal/feature_config_condition_validator.h
@@ -10,6 +10,7 @@
#include <set>
#include "components/feature_engagement/internal/condition_validator.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
namespace feature_engagement {
class AvailabilityModel;
@@ -43,6 +44,9 @@ class FeatureConfigConditionValidator : public ConditionValidator {
const FeatureConfig& config,
const std::vector<std::string>& all_feature_names) override;
void NotifyDismissed(const base::Feature& feature) override;
+ void SetPriorityNotification(
+ const absl::optional<std::string>& feature) override;
+ absl::optional<std::string> GetPendingPriorityNotification() override;
private:
bool EventConfigMeetsConditions(const EventConfig& event_config,
@@ -69,6 +73,9 @@ class FeatureConfigConditionValidator : public ConditionValidator {
// By default, all features impact each other, but some features override this
// through the use of |session_rate_impact|.
std::map<std::string, uint32_t> times_shown_for_feature_;
+
+ // Pending priority notification to be shown if any.
+ absl::optional<std::string> pending_priority_notification_;
};
} // namespace feature_engagement
diff --git a/chromium/components/feature_engagement/internal/feature_config_condition_validator_unittest.cc b/chromium/components/feature_engagement/internal/feature_config_condition_validator_unittest.cc
index ca69e340c09..bb10b170a02 100644
--- a/chromium/components/feature_engagement/internal/feature_config_condition_validator_unittest.cc
+++ b/chromium/components/feature_engagement/internal/feature_config_condition_validator_unittest.cc
@@ -440,6 +440,50 @@ TEST_F(FeatureConfigConditionValidatorTest, TwoFailingPreconditions) {
EXPECT_FALSE(result.preconditions_ok);
}
+TEST_F(FeatureConfigConditionValidatorTest, PriorityNotification) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitWithFeatures(
+ {kFeatureConfigTestFeatureFoo, kFeatureConfigTestFeatureBar}, {});
+ std::vector<std::string> all_feature_names = {
+ kFeatureConfigTestFeatureFoo.name, kFeatureConfigTestFeatureBar.name};
+
+ FeatureConfig foo_config = GetAcceptingFeatureConfig();
+ FeatureConfig bar_config = GetAcceptingFeatureConfig();
+
+ EXPECT_TRUE(
+ GetResultForDayZeroForFeature(kFeatureConfigTestFeatureFoo, foo_config)
+ .NoErrors());
+ EXPECT_TRUE(
+ GetResultForDayZeroForFeature(kFeatureConfigTestFeatureBar, bar_config)
+ .NoErrors());
+
+ validator_.SetPriorityNotification(kFeatureConfigTestFeatureFoo.name);
+ EXPECT_TRUE(
+ GetResultForDayZeroForFeature(kFeatureConfigTestFeatureFoo, foo_config)
+ .NoErrors());
+ ConditionValidator::Result result =
+ GetResultForDayZeroForFeature(kFeatureConfigTestFeatureBar, bar_config);
+ EXPECT_FALSE(result.NoErrors());
+ EXPECT_FALSE(result.priority_notification_ok);
+
+ validator_.SetPriorityNotification(absl::nullopt);
+ validator_.SetPriorityNotification(kFeatureConfigTestFeatureBar.name);
+ EXPECT_FALSE(
+ GetResultForDayZeroForFeature(kFeatureConfigTestFeatureFoo, foo_config)
+ .NoErrors());
+ EXPECT_TRUE(
+ GetResultForDayZeroForFeature(kFeatureConfigTestFeatureBar, bar_config)
+ .NoErrors());
+
+ validator_.SetPriorityNotification(absl::nullopt);
+ EXPECT_TRUE(
+ GetResultForDayZeroForFeature(kFeatureConfigTestFeatureFoo, foo_config)
+ .NoErrors());
+ EXPECT_TRUE(
+ GetResultForDayZeroForFeature(kFeatureConfigTestFeatureBar, bar_config)
+ .NoErrors());
+}
+
TEST_F(FeatureConfigConditionValidatorTest, SessionRate) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitWithFeatures(
diff --git a/chromium/components/feature_engagement/internal/never_condition_validator.cc b/chromium/components/feature_engagement/internal/never_condition_validator.cc
index 5108c06a364..7fbfa601e1c 100644
--- a/chromium/components/feature_engagement/internal/never_condition_validator.cc
+++ b/chromium/components/feature_engagement/internal/never_condition_validator.cc
@@ -4,6 +4,8 @@
#include "components/feature_engagement/internal/never_condition_validator.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
namespace feature_engagement {
NeverConditionValidator::NeverConditionValidator() = default;
@@ -28,4 +30,12 @@ void NeverConditionValidator::NotifyIsShowing(
void NeverConditionValidator::NotifyDismissed(const base::Feature& feature) {}
+void NeverConditionValidator::SetPriorityNotification(
+ const absl::optional<std::string>& feature) {}
+
+absl::optional<std::string>
+NeverConditionValidator::GetPendingPriorityNotification() {
+ return absl::nullopt;
+}
+
} // namespace feature_engagement
diff --git a/chromium/components/feature_engagement/internal/never_condition_validator.h b/chromium/components/feature_engagement/internal/never_condition_validator.h
index b7ecdba0101..b5f6c15a621 100644
--- a/chromium/components/feature_engagement/internal/never_condition_validator.h
+++ b/chromium/components/feature_engagement/internal/never_condition_validator.h
@@ -7,6 +7,7 @@
#include "components/feature_engagement/internal/condition_validator.h"
#include "components/feature_engagement/public/feature_list.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
namespace base {
struct Feature;
@@ -42,6 +43,9 @@ class NeverConditionValidator : public ConditionValidator {
const FeatureConfig& config,
const std::vector<std::string>& all_feature_names) override;
void NotifyDismissed(const base::Feature& feature) override;
+ void SetPriorityNotification(
+ const absl::optional<std::string>& feature) override;
+ absl::optional<std::string> GetPendingPriorityNotification() override;
};
} // namespace feature_engagement
diff --git a/chromium/components/feature_engagement/internal/never_condition_validator_unittest.cc b/chromium/components/feature_engagement/internal/never_condition_validator_unittest.cc
index fcaea750f3b..e3da1cbc484 100644
--- a/chromium/components/feature_engagement/internal/never_condition_validator_unittest.cc
+++ b/chromium/components/feature_engagement/internal/never_condition_validator_unittest.cc
@@ -98,6 +98,7 @@ TEST_F(NeverConditionValidatorTest, ShouldNeverMeetConditions) {
event_model_, availability_model_,
display_lock_controller_, nullptr, 0u)
.NoErrors());
+ EXPECT_FALSE(validator_.GetPendingPriorityNotification().has_value());
}
} // namespace feature_engagement
diff --git a/chromium/components/feature_engagement/internal/once_condition_validator.cc b/chromium/components/feature_engagement/internal/once_condition_validator.cc
index 975d8596222..629329df953 100644
--- a/chromium/components/feature_engagement/internal/once_condition_validator.cc
+++ b/chromium/components/feature_engagement/internal/once_condition_validator.cc
@@ -6,6 +6,7 @@
#include "components/feature_engagement/internal/event_model.h"
#include "components/feature_engagement/public/configuration.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
namespace feature_engagement {
@@ -38,6 +39,10 @@ ConditionValidator::Result OnceConditionValidator::MeetsConditions(
(event_model.GetLastSnoozeTimestamp(config.trigger.name) <
base::Time::Now() - base::Days(config.snooze_params.snooze_interval));
+ result.priority_notification_ok =
+ !pending_priority_notification_.has_value() ||
+ pending_priority_notification_.value() == feature.name;
+
result.should_show_snooze =
result.snooze_expiration_ok &&
event_model.GetSnoozeCount(config.trigger.name, config.trigger.window,
@@ -61,4 +66,14 @@ void OnceConditionValidator::NotifyDismissed(const base::Feature& feature) {
currently_showing_feature_.clear();
}
+void OnceConditionValidator::SetPriorityNotification(
+ const absl::optional<std::string>& feature) {
+ pending_priority_notification_ = feature;
+}
+
+absl::optional<std::string>
+OnceConditionValidator::GetPendingPriorityNotification() {
+ return pending_priority_notification_;
+}
+
} // namespace feature_engagement
diff --git a/chromium/components/feature_engagement/internal/once_condition_validator.h b/chromium/components/feature_engagement/internal/once_condition_validator.h
index 726493e4538..aa8791f8fc0 100644
--- a/chromium/components/feature_engagement/internal/once_condition_validator.h
+++ b/chromium/components/feature_engagement/internal/once_condition_validator.h
@@ -9,6 +9,7 @@
#include "components/feature_engagement/internal/condition_validator.h"
#include "components/feature_engagement/public/feature_list.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
namespace base {
struct Feature;
@@ -55,6 +56,9 @@ class OnceConditionValidator : public ConditionValidator {
const FeatureConfig& config,
const std::vector<std::string>& all_feature_names) override;
void NotifyDismissed(const base::Feature& feature) override;
+ void SetPriorityNotification(
+ const absl::optional<std::string>& feature) override;
+ absl::optional<std::string> GetPendingPriorityNotification() override;
private:
// Contains all features that have met conditions within the current session.
@@ -63,6 +67,9 @@ class OnceConditionValidator : public ConditionValidator {
// Which feature that is currently being shown, or nullptr if nothing is
// currently showing.
std::string currently_showing_feature_;
+
+ // Pending priority notification to be shown if any.
+ absl::optional<std::string> pending_priority_notification_;
};
} // namespace feature_engagement
diff --git a/chromium/components/feature_engagement/internal/once_condition_validator_unittest.cc b/chromium/components/feature_engagement/internal/once_condition_validator_unittest.cc
index c7e8a65a718..64305c396cf 100644
--- a/chromium/components/feature_engagement/internal/once_condition_validator_unittest.cc
+++ b/chromium/components/feature_engagement/internal/once_condition_validator_unittest.cc
@@ -176,6 +176,22 @@ TEST_F(OnceConditionValidatorTest, OnlyTriggerIfNothingElseIsShowing) {
.NoErrors());
}
+TEST_F(OnceConditionValidatorTest, PriorityNotificationBlocksOtherIPHs) {
+ validator_.SetPriorityNotification("test_bar");
+ ConditionValidator::Result result = validator_.MeetsConditions(
+ kOnceTestFeatureFoo, kValidFeatureConfig, event_model_,
+ availability_model_, display_lock_controller_, nullptr, 0u);
+ EXPECT_FALSE(result.NoErrors());
+ EXPECT_FALSE(result.priority_notification_ok);
+
+ validator_.SetPriorityNotification(absl::nullopt);
+ EXPECT_TRUE(validator_
+ .MeetsConditions(kOnceTestFeatureFoo, kValidFeatureConfig,
+ event_model_, availability_model_,
+ display_lock_controller_, nullptr, 0u)
+ .NoErrors());
+}
+
TEST_F(OnceConditionValidatorTest, DoNotTriggerForInvalidConfig) {
ConditionValidator::Result result = validator_.MeetsConditions(
kOnceTestFeatureFoo, kInvalidFeatureConfig, event_model_,
diff --git a/chromium/components/feature_engagement/internal/tracker_impl.cc b/chromium/components/feature_engagement/internal/tracker_impl.cc
index 885df49c488..66842b9cf65 100644
--- a/chromium/components/feature_engagement/internal/tracker_impl.cc
+++ b/chromium/components/feature_engagement/internal/tracker_impl.cc
@@ -36,6 +36,7 @@
#include "components/feature_engagement/public/feature_constants.h"
#include "components/feature_engagement/public/feature_list.h"
#include "components/leveldb_proto/public/proto_database_provider.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
namespace feature_engagement {
@@ -296,6 +297,46 @@ std::unique_ptr<DisplayLockHandle> TrackerImpl::AcquireDisplayLock() {
return display_lock_controller_->AcquireDisplayLock();
}
+void TrackerImpl::SetPriorityNotification(const base::Feature& feature) {
+ // If the handler hasn't been registered.
+ auto iter = priority_notification_handlers_.find(feature.name);
+ if (iter == priority_notification_handlers_.end()) {
+ condition_validator_->SetPriorityNotification(feature.name);
+ return;
+ }
+
+ // We already have a handler. Serve the request and remove the handler.
+ condition_validator_->SetPriorityNotification(absl::nullopt);
+ std::move(iter->second).Run();
+ priority_notification_handlers_.erase(feature.name);
+}
+
+absl::optional<std::string> TrackerImpl::GetPendingPriorityNotification() {
+ return condition_validator_->GetPendingPriorityNotification();
+}
+
+void TrackerImpl::RegisterPriorityNotificationHandler(
+ const base::Feature& feature,
+ base::OnceClosure callback) {
+ // If we already have a pending notification, handle it right away.
+ auto pending_priority_notification =
+ condition_validator_->GetPendingPriorityNotification();
+ if (pending_priority_notification.has_value() &&
+ pending_priority_notification.value() == feature.name) {
+ std::move(callback).Run();
+ condition_validator_->SetPriorityNotification(absl::nullopt);
+ return;
+ }
+
+ // We don't have the notification yet. Cache the handler.
+ priority_notification_handlers_.emplace(feature.name, std::move(callback));
+}
+
+void TrackerImpl::UnregisterPriorityNotificationHandler(
+ const base::Feature& feature) {
+ priority_notification_handlers_.erase(feature.name);
+}
+
bool TrackerImpl::IsInitialized() const {
return event_model_->IsReady() && availability_model_->IsReady();
}
diff --git a/chromium/components/feature_engagement/internal/tracker_impl.h b/chromium/components/feature_engagement/internal/tracker_impl.h
index 0c1621bd14d..21580b3c7ba 100644
--- a/chromium/components/feature_engagement/internal/tracker_impl.h
+++ b/chromium/components/feature_engagement/internal/tracker_impl.h
@@ -12,6 +12,7 @@
#include "base/feature_list.h"
#include "base/memory/weak_ptr.h"
#include "components/feature_engagement/public/tracker.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
namespace feature_engagement {
class AvailabilityModel;
@@ -53,6 +54,12 @@ class TrackerImpl : public Tracker {
std::unique_ptr<DisplayLockHandle> AcquireDisplayLock() override;
bool IsInitialized() const override;
void AddOnInitializedCallback(OnInitializedCallback callback) override;
+ void SetPriorityNotification(const base::Feature& feature) override;
+ absl::optional<std::string> GetPendingPriorityNotification() override;
+ void RegisterPriorityNotificationHandler(const base::Feature& feature,
+ base::OnceClosure callback) override;
+ void UnregisterPriorityNotificationHandler(
+ const base::Feature& feature) override;
private:
// Invoked by the EventModel when it has been initialized.
@@ -102,6 +109,9 @@ class TrackerImpl : public Tracker {
// is cleared after the initialization has happened.
std::vector<OnInitializedCallback> on_initialized_callbacks_;
+ // Registered priority notification handlers for various features.
+ std::map<std::string, base::OnceClosure> priority_notification_handlers_;
+
base::WeakPtrFactory<TrackerImpl> weak_ptr_factory_{this};
};
diff --git a/chromium/components/feature_engagement/internal/tracker_impl_unittest.cc b/chromium/components/feature_engagement/internal/tracker_impl_unittest.cc
index ad76feed214..0b407e602f3 100644
--- a/chromium/components/feature_engagement/internal/tracker_impl_unittest.cc
+++ b/chromium/components/feature_engagement/internal/tracker_impl_unittest.cc
@@ -9,12 +9,14 @@
#include <utility>
#include "base/bind.h"
+#include "base/callback_forward.h"
#include "base/callback_helpers.h"
#include "base/feature_list.h"
#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/single_thread_task_runner.h"
+#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/metrics/user_action_tester.h"
#include "base/test/task_environment.h"
@@ -646,6 +648,85 @@ TEST_F(FailingAvailabilityModelInitTrackerImplTest, AvailabilityModelNotReady) {
EXPECT_FALSE(callback.success());
}
+TEST_F(TrackerImplTest, TestSetPriorityNotificationBeforeRegistration) {
+ // Ensure all initialization is finished.
+ StoringInitializedCallback callback;
+ tracker_->AddOnInitializedCallback(base::BindOnce(
+ &StoringInitializedCallback::OnInitialized, base::Unretained(&callback)));
+ base::RunLoop().RunUntilIdle();
+
+ bool invoked = false;
+
+ // Set priority notification, and then register handler. IPH will show up
+ // immediately after registration.
+ tracker_->SetPriorityNotification(kTrackerTestFeatureFoo);
+ tracker_->RegisterPriorityNotificationHandler(
+ kTrackerTestFeatureFoo,
+ base::BindLambdaForTesting([&]() { invoked = true; }));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(invoked);
+
+ // Try registering handler once again. The IPH won't show up again since the
+ // notification has been consumed.
+ invoked = false;
+ tracker_->RegisterPriorityNotificationHandler(
+ kTrackerTestFeatureFoo,
+ base::BindLambdaForTesting([&]() { invoked = true; }));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(invoked);
+
+ // Set priority notification one more time. Now the IPH will show up.
+ tracker_->SetPriorityNotification(kTrackerTestFeatureFoo);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(invoked);
+}
+
+TEST_F(TrackerImplTest, TestSetPriorityNotificationAfterRegistration) {
+ // Ensure all initialization is finished.
+ StoringInitializedCallback callback;
+ tracker_->AddOnInitializedCallback(base::BindOnce(
+ &StoringInitializedCallback::OnInitialized, base::Unretained(&callback)));
+ base::RunLoop().RunUntilIdle();
+
+ bool invoked = false;
+
+ // Register the handler first, and then set priority notification.
+ tracker_->RegisterPriorityNotificationHandler(
+ kTrackerTestFeatureFoo,
+ base::BindLambdaForTesting([&]() { invoked = true; }));
+ tracker_->SetPriorityNotification(kTrackerTestFeatureFoo);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(invoked);
+
+ // Set priority notification again. The IPH won't show up again, since the
+ // handler is good for only one use.
+ invoked = false;
+ tracker_->SetPriorityNotification(kTrackerTestFeatureFoo);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(invoked);
+}
+
+TEST_F(TrackerImplTest, TestUnregisterPriorityNotification) {
+ // Ensure all initialization is finished.
+ StoringInitializedCallback callback;
+ tracker_->AddOnInitializedCallback(base::BindOnce(
+ &StoringInitializedCallback::OnInitialized, base::Unretained(&callback)));
+ base::RunLoop().RunUntilIdle();
+
+ bool invoked = false;
+
+ // Register the handler, and unregister before setting the notification. The
+ // IPH won't show up.
+ invoked = false;
+ tracker_->RegisterPriorityNotificationHandler(
+ kTrackerTestFeatureFoo,
+ base::BindLambdaForTesting([&]() { invoked = true; }));
+ tracker_->UnregisterPriorityNotificationHandler(kTrackerTestFeatureFoo);
+ tracker_->SetPriorityNotification(kTrackerTestFeatureFoo);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(invoked);
+}
+
TEST_F(TrackerImplTest, TestTriggering) {
// Ensure all initialization is finished.
StoringInitializedCallback callback;
diff --git a/chromium/components/feature_engagement/public/android/wrapping_test_tracker.cc b/chromium/components/feature_engagement/public/android/wrapping_test_tracker.cc
index 951bbb755aa..71c1dd1f537 100644
--- a/chromium/components/feature_engagement/public/android/wrapping_test_tracker.cc
+++ b/chromium/components/feature_engagement/public/android/wrapping_test_tracker.cc
@@ -10,6 +10,7 @@
#include "base/android/jni_string.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/feature_engagement/public/jni_headers/CppWrappedTestTracker_jni.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
namespace feature_engagement {
@@ -91,6 +92,21 @@ std::unique_ptr<DisplayLockHandle> WrappingTestTracker::AcquireDisplayLock() {
return nullptr;
}
+void WrappingTestTracker::SetPriorityNotification(
+ const base::Feature& feature) {}
+
+absl::optional<std::string>
+WrappingTestTracker::GetPendingPriorityNotification() {
+ return absl::nullopt;
+}
+
+void WrappingTestTracker::RegisterPriorityNotificationHandler(
+ const base::Feature& feature,
+ base::OnceClosure callback) {}
+
+void WrappingTestTracker::UnregisterPriorityNotificationHandler(
+ const base::Feature& feature) {}
+
bool WrappingTestTracker::IsInitialized() const {
return Java_CppWrappedTestTracker_isInitialized(
base::android::AttachCurrentThread(), java_tracker_);
diff --git a/chromium/components/feature_engagement/public/android/wrapping_test_tracker.h b/chromium/components/feature_engagement/public/android/wrapping_test_tracker.h
index 5fb0f68afca..ee39acd0954 100644
--- a/chromium/components/feature_engagement/public/android/wrapping_test_tracker.h
+++ b/chromium/components/feature_engagement/public/android/wrapping_test_tracker.h
@@ -11,6 +11,7 @@
#include "base/android/jni_android.h"
#include "base/callback.h"
#include "components/feature_engagement/public/tracker.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
namespace feature_engagement {
// This class wraps a Tracker from Java and forwards to it all calls received.
@@ -37,6 +38,12 @@ class WrappingTestTracker : public Tracker {
void DismissedWithSnooze(const base::Feature& feature,
absl::optional<SnoozeAction> snooze_action) override;
std::unique_ptr<DisplayLockHandle> AcquireDisplayLock() override;
+ absl::optional<std::string> GetPendingPriorityNotification() override;
+ void SetPriorityNotification(const base::Feature& feature) override;
+ void RegisterPriorityNotificationHandler(const base::Feature& feature,
+ base::OnceClosure callback) override;
+ void UnregisterPriorityNotificationHandler(
+ const base::Feature& feature) override;
bool IsInitialized() const override;
void AddOnInitializedCallback(OnInitializedCallback callback) override;
diff --git a/chromium/components/feature_engagement/public/event_constants.cc b/chromium/components/feature_engagement/public/event_constants.cc
index 90cf0e87d47..711103ea601 100644
--- a/chromium/components/feature_engagement/public/event_constants.cc
+++ b/chromium/components/feature_engagement/public/event_constants.cc
@@ -10,8 +10,8 @@ namespace feature_engagement {
namespace events {
-#if defined(OS_WIN) || defined(OS_APPLE) || defined(OS_LINUX) || \
- defined(OS_CHROMEOS) || defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) || \
+ BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_FUCHSIA)
const char kNewTabOpened[] = "new_tab_opened";
const char kSixthTabOpened[] = "sixth_tab_opened";
const char kTabGroupCreated[] = "tab_group_created";
@@ -47,10 +47,10 @@ const char kFocusHelpBubbleAcceleratorPressed[] =
const char kFocusHelpBubbleAcceleratorPromoRead[] =
"focus_help_bubble_accelerator_promo_read";
-#endif // defined(OS_WIN) || defined(OS_APPLE) || defined(OS_LINUX) ||
- // defined(OS_CHROMEOS) || defined(OS_FUCHSIA)
+#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) ||
+ // BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_FUCHSIA)
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
const char kChromeOpened[] = "chrome_opened";
const char kIncognitoTabOpened[] = "incognito_tab_opened";
const char kClearedBrowsingData[] = "cleared_browsing_data";
@@ -58,11 +58,13 @@ const char kViewedReadingList[] = "viewed_reading_list";
const char kTriggeredTranslateInfobar[] = "triggered_translate_infobar";
const char kBottomToolbarOpened[] = "bottom_toolbar_opened";
const char kDiscoverFeedLoaded[] = "discover_feed_loaded";
-#endif // defined(OS_IOS)
+const char kDesktopVersionRequested[] = "desktop_version_requested";
+const char kDefaultSiteViewShown[] = "default_site_view_shown";
+#endif // BUILDFLAG(IS_IOS)
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
const char kPwaInstallMenuSelected[] = "pwa_install_menu_clicked";
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
} // namespace events
diff --git a/chromium/components/feature_engagement/public/event_constants.h b/chromium/components/feature_engagement/public/event_constants.h
index 6fe7602c4a1..489f67ef0e5 100644
--- a/chromium/components/feature_engagement/public/event_constants.h
+++ b/chromium/components/feature_engagement/public/event_constants.h
@@ -12,8 +12,8 @@ namespace feature_engagement {
namespace events {
// Desktop
-#if defined(OS_WIN) || defined(OS_APPLE) || defined(OS_LINUX) || \
- defined(OS_CHROMEOS) || defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) || \
+ BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_FUCHSIA)
// The user has explicitly opened a new tab via an entry point from inside of
// Chrome.
extern const char kNewTabOpened[];
@@ -75,10 +75,10 @@ extern const char kFocusHelpBubbleAcceleratorPressed[];
// the user.
extern const char kFocusHelpBubbleAcceleratorPromoRead[];
-#endif // defined(OS_WIN) || defined(OS_APPLE) || defined(OS_LINUX) ||
- // defined(OS_CHROMEOS) || defined(OS_FUCHSIA)
+#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) ||
+ // BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_FUCHSIA)
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
// The user has opened Chrome (cold start or from background).
extern const char kChromeOpened[];
@@ -99,13 +99,19 @@ extern const char kBottomToolbarOpened[];
// The Discover feed has loaded content in the NTP.
extern const char kDiscoverFeedLoaded[];
-#endif // defined(OS_IOS)
+
+// The user has requested the desktop version of a page.
+extern const char kDesktopVersionRequested[];
+
+// The default site view tip is shown.
+extern const char kDefaultSiteViewShown[];
+#endif // BUILDFLAG(IS_IOS)
// Android.
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// The user has explicitly used the Install menu item under the App Menu.
extern const char kPwaInstallMenuSelected[];
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
} // namespace events
diff --git a/chromium/components/feature_engagement/public/feature_configurations.cc b/chromium/components/feature_engagement/public/feature_configurations.cc
index 4599ebb1f69..e2a88b038d3 100644
--- a/chromium/components/feature_engagement/public/feature_configurations.cc
+++ b/chromium/components/feature_engagement/public/feature_configurations.cc
@@ -4,16 +4,38 @@
#include "components/feature_engagement/public/feature_configurations.h"
+#include "base/strings/string_util.h"
#include "build/build_config.h"
#include "components/feature_engagement/public/configuration.h"
#include "components/feature_engagement/public/feature_constants.h"
namespace feature_engagement {
+FeatureConfig CreateAlwaysTriggerConfig(const base::Feature* feature) {
+ // Trim "IPH_" prefix from the feature name to use for trigger and used
+ // events.
+ const char* prefix = "IPH_";
+ std::string stripped_feature_name = feature->name;
+ if (base::StartsWith(stripped_feature_name, prefix,
+ base::CompareCase::SENSITIVE))
+ stripped_feature_name = stripped_feature_name.substr(strlen(prefix));
+
+ // A config that always meets condition to trigger IPH.
+ FeatureConfig config;
+ config.valid = true;
+ config.availability = Comparator(ANY, 0);
+ config.session_rate = Comparator(ANY, 0);
+ config.trigger = EventConfig(stripped_feature_name + "_trigger",
+ Comparator(ANY, 0), 90, 90);
+ config.used =
+ EventConfig(stripped_feature_name + "_used", Comparator(ANY, 0), 90, 90);
+ return config;
+}
+
absl::optional<FeatureConfig> GetClientSideFeatureConfig(
const base::Feature* feature) {
-#if defined(OS_WIN) || defined(OS_APPLE) || defined(OS_LINUX) || \
- defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) || \
+ BUILDFLAG(IS_CHROMEOS)
if (kIPHPasswordsAccountStorageFeature.name == feature->name) {
absl::optional<FeatureConfig> config = FeatureConfig();
config->valid = true;
@@ -87,10 +109,11 @@ absl::optional<FeatureConfig> GetClientSideFeatureConfig(
Comparator(EQUAL, 0), 7, 360));
return config;
}
-#endif // defined(OS_WIN) || defined(OS_APPLE) || defined(OS_LINUX) ||
- // defined(OS_CHROMEOS)
-#if defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) ||
+ // BUILDFLAG(IS_CHROMEOS)
+
+#if BUILDFLAG(IS_ANDROID)
constexpr int k10YearsInDays = 365 * 10;
@@ -210,6 +233,71 @@ absl::optional<FeatureConfig> GetClientSideFeatureConfig(
return config;
}
+ // Feature notification guide help UI promos that are shown in response to a
+ // notification click.
+ if (kIPHFeatureNotificationGuideDefaultBrowserPromoFeature.name ==
+ feature->name ||
+ kIPHFeatureNotificationGuideSignInHelpBubbleFeature.name ==
+ feature->name ||
+ kIPHFeatureNotificationGuideIncognitoTabHelpBubbleFeature.name ==
+ feature->name ||
+ kIPHFeatureNotificationGuideNTPSuggestionCardHelpBubbleFeature.name ==
+ feature->name ||
+ kIPHFeatureNotificationGuideVoiceSearchHelpBubbleFeature.name ==
+ feature->name) {
+ return CreateAlwaysTriggerConfig(feature);
+ }
+
+ // A generic feature that always returns true.
+ if (kIPHGenericAlwaysTriggerHelpUiFeature.name == feature->name) {
+ return CreateAlwaysTriggerConfig(feature);
+ }
+
+ if (kIPHFeatureNotificationGuideIncognitoTabUsedFeature.name ==
+ feature->name) {
+ // A config that allows to check whether use has used incognito tabs before.
+ absl::optional<FeatureConfig> config = FeatureConfig();
+ config->valid = true;
+ config->availability = Comparator(ANY, 0);
+ config->session_rate = Comparator(ANY, 0);
+ config->session_rate_impact.type = SessionRateImpact::Type::NONE;
+ config->blocked_by.type = BlockedBy::Type::NONE;
+ config->blocking.type = Blocking::Type::NONE;
+ // unused.
+ config->trigger =
+ EventConfig("feature_notification_guide_dummy_feature_trigger",
+ Comparator(ANY, 0), 90, 90);
+ config->used = EventConfig("feature_notification_guide_dummy_feature_used",
+ Comparator(ANY, 0), 90, 90);
+ config->event_configs.insert(
+ EventConfig("app_menu_new_incognito_tab_clicked",
+ Comparator(GREATER_THAN_OR_EQUAL, 1), 90, 90));
+ return config;
+ }
+
+ if (kIPHFeatureNotificationGuideVoiceSearchUsedFeature.name ==
+ feature->name) {
+ // A config that allows to check whether use has used voice search from NTP
+ // before.
+ absl::optional<FeatureConfig> config = FeatureConfig();
+ config->valid = true;
+ config->availability = Comparator(ANY, 0);
+ config->session_rate = Comparator(ANY, 0);
+ config->session_rate_impact.type = SessionRateImpact::Type::NONE;
+ config->blocked_by.type = BlockedBy::Type::NONE;
+ config->blocking.type = Blocking::Type::NONE;
+ // unused.
+ config->trigger =
+ EventConfig("feature_notification_guide_dummy_feature_trigger",
+ Comparator(ANY, 0), 90, 90);
+ config->used = EventConfig("feature_notification_guide_dummy_feature_used",
+ Comparator(ANY, 0), 90, 90);
+ config->event_configs.insert(
+ EventConfig("ntp_voice_search_button_clicked",
+ Comparator(GREATER_THAN_OR_EQUAL, 1), 90, 90));
+ return config;
+ }
+
if (kIPHFeatureNotificationGuideIncognitoTabNotificationShownFeature.name ==
feature->name) {
// A config that allows the feature guide incognito tab notification to be
@@ -224,9 +312,8 @@ absl::optional<FeatureConfig> GetClientSideFeatureConfig(
config->trigger = EventConfig(
"feature_notification_guide_incognito_tab_notification_trigger",
Comparator(LESS_THAN, 1), 90, 90);
- config->used = EventConfig(
- "feature_notification_guide_incognito_tab_notification_used",
- Comparator(EQUAL, 0), 90, 90);
+ config->used = EventConfig("app_menu_new_incognito_tab_clicked",
+ Comparator(EQUAL, 0), 90, 90);
return config;
}
@@ -266,9 +353,8 @@ absl::optional<FeatureConfig> GetClientSideFeatureConfig(
config->trigger = EventConfig(
"feature_notification_guide_voice_search_notification_trigger",
Comparator(LESS_THAN, 1), 90, 90);
- config->used =
- EventConfig("feature_notification_guide_voice_search_notification_used",
- Comparator(EQUAL, 0), 90, 90);
+ config->used = EventConfig("ntp_voice_search_button_clicked",
+ Comparator(EQUAL, 0), 90, 90);
return config;
}
@@ -314,6 +400,24 @@ absl::optional<FeatureConfig> GetClientSideFeatureConfig(
return config;
}
+ if (kIPHLowUserEngagementDetectorFeature.name == feature->name) {
+ absl::optional<FeatureConfig> config = FeatureConfig();
+ config->valid = true;
+ config->availability = Comparator(GREATER_THAN_OR_EQUAL, 14);
+ config->session_rate = Comparator(ANY, 0);
+ config->session_rate_impact.type = SessionRateImpact::Type::NONE;
+ config->blocked_by.type = BlockedBy::Type::NONE;
+ config->blocking.type = Blocking::Type::NONE;
+ config->trigger = EventConfig("low_user_engagement_detector_trigger",
+ Comparator(ANY, 0), 90, 90);
+ config->used = EventConfig("low_user_engagement_detector_used",
+ Comparator(ANY, 0), 90, 90);
+ config->event_configs.insert(EventConfig("foreground_session_destroyed",
+ Comparator(LESS_THAN_OR_EQUAL, 3),
+ 14, 14));
+ return config;
+ }
+
if (kIPHFeedHeaderMenuFeature.name == feature->name) {
// A config that allows the feed header menu IPH to be shown only once when
// the user starts using a version of the feed that uploads click and view
@@ -675,30 +779,92 @@ absl::optional<FeatureConfig> GetClientSideFeatureConfig(
return config;
}
- if (kIPHKeyboardAccessoryPaymentVirtualCardFeature.name == feature->name) {
- // A config that allows the virtual card IPH to be shown when a user
- // interacts with the payment form and triggers the credit card suggestion
- // list.
+ if (kIPHReadLaterAppMenuBookmarkThisPageFeature.name == feature->name) {
+ // A config that allows the reading list IPH bubble to prompt the user to
+ // bookmark this page.
+ // This will only occur once every 60 days.
+
absl::optional<FeatureConfig> config = FeatureConfig();
config->valid = true;
config->availability = Comparator(ANY, 0);
config->session_rate = Comparator(ANY, 0);
config->trigger =
- EventConfig("keyboard_accessory_payment_virtual_card_iph_trigger",
- Comparator(LESS_THAN, 3), 90, 360);
- config->used = EventConfig("keyboard_accessory_payment_suggestion_accepted",
+ EventConfig("read_later_app_menu_bookmark_this_page_iph_trigger",
+ Comparator(EQUAL, 0), 60, 60);
+ config->used = EventConfig("app_menu_bookmark_star_icon_pressed",
+ Comparator(EQUAL, 0), 60, 60);
+
+ return config;
+ }
+
+ if (kIPHReadLaterAppMenuBookmarksFeature.name == feature->name) {
+ // A config that allows the reading list IPH bubble to promopt the user to
+ // open the reading list.
+ // This will only occur once every 60 days.
+
+ absl::optional<FeatureConfig> config = FeatureConfig();
+ config->valid = true;
+ config->availability = Comparator(ANY, 0);
+ config->session_rate = Comparator(ANY, 0);
+ config->trigger = EventConfig("read_later_app_menu_bookmarks_iph_trigger",
+ Comparator(EQUAL, 0), 60, 60);
+ config->used = EventConfig("read_later_bookmark_folder_opened",
+ Comparator(EQUAL, 0), 60, 60);
+ config->event_configs.insert(
+ EventConfig("read_later_article_saved",
+ Comparator(GREATER_THAN_OR_EQUAL, 1), 60, 60));
+ return config;
+ }
+
+ if (kIPHReadLaterContextMenuFeature.name == feature->name) {
+ // A config that allows the reading list label on the context menu to show
+ // when the context menu "copy" option is clicked.
+ // This will only occur once every 60 days.
+
+ absl::optional<FeatureConfig> config = FeatureConfig();
+ config->valid = true;
+ config->availability = Comparator(ANY, 0);
+ config->session_rate = Comparator(ANY, 0);
+ config->trigger = EventConfig("read_later_context_menu_tapped_iph_trigger",
+ Comparator(EQUAL, 0), 60, 60);
+ config->used = EventConfig("read_later_context_menu_tapped",
+ Comparator(EQUAL, 0), 60, 60);
+ return config;
+ }
+#endif // BUILDFLAG(IS_ANDROID)
+
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) || \
+ BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_FUCHSIA)
+ if (kIPHAutofillVirtualCardSuggestionFeature.name == feature->name) {
+ // A config that allows the virtual card credit card suggestion IPH to be
+ // shown when:
+ // * it has been shown less than three times in last 90 days;
+ // * the virtual card suggestion has been selected less than twice in last
+ // 90 days.
+
+ absl::optional<FeatureConfig> config = FeatureConfig();
+ config->valid = true;
+ config->availability = Comparator(ANY, 0);
+ config->session_rate = Comparator(EQUAL, 0);
+ config->trigger = EventConfig("autofill_virtual_card_iph_trigger",
+ Comparator(LESS_THAN, 3), 90, 360);
+ config->used = EventConfig("autofill_virtual_card_suggestion_accepted",
Comparator(LESS_THAN, 2), 90, 360);
+#if BUILDFLAG(IS_ANDROID)
SessionRateImpact session_rate_impact;
session_rate_impact.type = SessionRateImpact::Type::EXPLICIT;
std::vector<std::string> affected_features;
affected_features.push_back("IPH_KeyboardAccessoryBarSwiping");
session_rate_impact.affected_features = affected_features;
config->session_rate_impact = session_rate_impact;
+#endif // BUILDFLAG(IS_ANDROID)
+
return config;
}
-
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) ||
+ // BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) ||
+ // BUILDFLAG(IS_FUCHSIA)
if (kIPHDummyFeature.name == feature->name) {
// Only used for tests. Various magic tricks are used below to ensure this
diff --git a/chromium/components/feature_engagement/public/feature_constants.cc b/chromium/components/feature_engagement/public/feature_constants.cc
index 1785b43e2b4..afa48650ef0 100644
--- a/chromium/components/feature_engagement/public/feature_constants.cc
+++ b/chromium/components/feature_engagement/public/feature_constants.cc
@@ -4,6 +4,8 @@
#include "components/feature_engagement/public/feature_constants.h"
+#include "build/build_config.h"
+
namespace feature_engagement {
// Features used by the In-Product Help system.
@@ -19,8 +21,8 @@ const base::Feature kUseClientConfigIPH{"UseClientConfigIPH",
const base::Feature kIPHDummyFeature{"IPH_Dummy",
base::FEATURE_DISABLED_BY_DEFAULT};
-#if defined(OS_WIN) || defined(OS_APPLE) || defined(OS_LINUX) || \
- defined(OS_CHROMEOS) || defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) || \
+ BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_FUCHSIA)
const base::Feature kIPHDesktopSharedHighlightingFeature{
"IPH_DesktopSharedHighlighting", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kIPHDesktopTabGroupsNewGroupFeature{
@@ -31,6 +33,8 @@ const base::Feature kIPHGMCCastStartStopFeature{
"IPH_GMCCastStartStop", base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kIPHLiveCaptionFeature{"IPH_LiveCaption",
base::FEATURE_ENABLED_BY_DEFAULT};
+const base::Feature kIPHTabAudioMutingFeature{"IPH_TabAudioMuting",
+ base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kIPHPasswordsAccountStorageFeature{
"IPH_PasswordsAccountStorage", base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kIPHReadingListDiscoveryFeature{
@@ -53,10 +57,10 @@ const base::Feature kIPHDesktopPwaInstallFeature{
"IPH_DesktopPwaInstall", base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kIPHProfileSwitchFeature{"IPH_ProfileSwitch",
base::FEATURE_ENABLED_BY_DEFAULT};
-#endif // defined(OS_WIN) || defined(OS_APPLE) || defined(OS_LINUX) ||
- // defined(OS_CHROMEOS) || defined(OS_FUCHSIA)
+#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) ||
+ // BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_FUCHSIA)
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
const base::Feature kIPHAdaptiveButtonInTopToolbarCustomizationNewTabFeature{
"IPH_AdaptiveButtonInTopToolbarCustomization_NewTab",
base::FEATURE_DISABLED_BY_DEFAULT};
@@ -119,11 +123,11 @@ const base::Feature kIPHDownloadInfoBarDownloadsAreFasterFeature{
const base::Feature kIPHQuietNotificationPromptsFeature{
"IPH_QuietNotificationPrompts", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kIPHReadLaterContextMenuFeature{
- "IPH_ReadLaterContextMenu", base::FEATURE_DISABLED_BY_DEFAULT};
+ "IPH_ReadLaterContextMenu", base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kIPHReadLaterAppMenuBookmarkThisPageFeature{
- "IPH_ReadLaterAppMenuBookmarkThisPage", base::FEATURE_DISABLED_BY_DEFAULT};
+ "IPH_ReadLaterAppMenuBookmarkThisPage", base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kIPHReadLaterAppMenuBookmarksFeature{
- "IPH_ReadLaterAppMenuBookmarks", base::FEATURE_DISABLED_BY_DEFAULT};
+ "IPH_ReadLaterAppMenuBookmarks", base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kIPHReadLaterBottomSheetFeature{
"IPH_ReadLaterBottomSheet", base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kIPHShoppingListSaveFlowFeature{
@@ -149,8 +153,32 @@ const base::Feature
kIPHFeatureNotificationGuideVoiceSearchNotificationShownFeature{
"IPH_FeatureNotificationGuideVoiceSearchNotificationShown",
base::FEATURE_ENABLED_BY_DEFAULT};
+const base::Feature kIPHFeatureNotificationGuideDefaultBrowserPromoFeature{
+ "IPH_FeatureNotificationGuideDefaultBrowserPromo",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+const base::Feature kIPHFeatureNotificationGuideSignInHelpBubbleFeature{
+ "IPH_FeatureNotificationGuideSignInHelpBubble",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+const base::Feature kIPHFeatureNotificationGuideIncognitoTabHelpBubbleFeature{
+ "IPH_FeatureNotificationGuideIncognitoTabHelpBubble",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+const base::Feature
+ kIPHFeatureNotificationGuideNTPSuggestionCardHelpBubbleFeature{
+ "IPH_FeatureNotificationGuideNTPSuggestionCardHelpBubble",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+const base::Feature kIPHFeatureNotificationGuideVoiceSearchHelpBubbleFeature{
+ "IPH_FeatureNotificationGuideVoiceSearchHelpBubble",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+const base::Feature kIPHFeatureNotificationGuideIncognitoTabUsedFeature{
+ "IPH_FeatureNotificationGuideIncognitoTabUsed",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+const base::Feature kIPHFeatureNotificationGuideVoiceSearchUsedFeature{
+ "IPH_FeatureNotificationGuideVoiceSearchUsed",
+ base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kIPHFeedCardMenuFeature{"IPH_FeedCardMenu",
base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kIPHGenericAlwaysTriggerHelpUiFeature{
+ "IPH_GenericAlwaysTriggerHelpUiFeature", base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kIPHHomepagePromoCardFeature{
"IPH_HomepagePromoCard", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kIPHIdentityDiscFeature{"IPH_IdentityDisc",
@@ -167,9 +195,8 @@ const base::Feature kIPHKeyboardAccessoryPaymentFillingFeature{
"IPH_KeyboardAccessoryPaymentFilling", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kIPHKeyboardAccessoryPaymentOfferFeature{
"IPH_KeyboardAccessoryPaymentOffer", base::FEATURE_DISABLED_BY_DEFAULT};
-const base::Feature kIPHKeyboardAccessoryPaymentVirtualCardFeature{
- "IPH_KeyboardAccessoryPaymentVirtualCard",
- base::FEATURE_ENABLED_BY_DEFAULT};
+const base::Feature kIPHLowUserEngagementDetectorFeature{
+ "IPH_LowUserEngagementDetector", base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kIPHNewTabPageHomeButtonFeature{
"IPH_NewTabPageHomeButton", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kIPHMicToolbarFeature{"IPH_MicToolbar",
@@ -236,9 +263,9 @@ const base::Feature kIPHStartSurfaceTabSwitcherHomeButton{
"IPH_StartSurfaceTabSwitcherHomeButton", base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kIPHSharingHubWebnotesStylizeFeature{
"IPH_SharingHubWebnotesStylize", base::FEATURE_ENABLED_BY_DEFAULT};
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
const base::Feature kIPHBottomToolbarTipFeature{
"IPH_BottomToolbarTip", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kIPHLongPressToolbarTipFeature{
@@ -255,14 +282,19 @@ const base::Feature kIPHBadgedTranslateManualTriggerFeature{
"IPH_BadgedTranslateManualTrigger", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kIPHDiscoverFeedHeaderFeature{
"IPH_DiscoverFeedHeaderMenu", base::FEATURE_DISABLED_BY_DEFAULT};
-#endif // defined(OS_IOS)
+const base::Feature kIPHDefaultSiteViewFeature{
+ "IPH_DefaultSiteView", base::FEATURE_DISABLED_BY_DEFAULT};
+#endif // BUILDFLAG(IS_IOS)
-#if defined(OS_WIN) || defined(OS_APPLE) || defined(OS_LINUX) || \
- defined(OS_CHROMEOS) || defined(OS_ANDROID) || defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) || \
+ BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_FUCHSIA)
+const base::Feature kIPHAutofillVirtualCardSuggestionFeature{
+ "IPH_AutofillVirtualCardSuggestion", base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kIPHUpdatedConnectionSecurityIndicatorsFeature{
"IPH_UpdatedConnectionSecurityIndicators",
base::FEATURE_DISABLED_BY_DEFAULT};
-#endif // defined(OS_WIN) || defined(OS_APPLE) || defined(OS_LINUX) ||
- // defined(OS_CHROMEOS) || defined(OS_ANDROID) || defined(OS_FUCHSIA)
+#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) ||
+ // BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) ||
+ // BUILDFLAG(IS_FUCHSIA)
} // namespace feature_engagement
diff --git a/chromium/components/feature_engagement/public/feature_constants.h b/chromium/components/feature_engagement/public/feature_constants.h
index cbaaf7bf6f1..c7cfa79a1b7 100644
--- a/chromium/components/feature_engagement/public/feature_constants.h
+++ b/chromium/components/feature_engagement/public/feature_constants.h
@@ -29,13 +29,14 @@ extern const base::Feature kUseClientConfigIPH;
// A feature to ensure all arrays can contain at least one feature.
extern const base::Feature kIPHDummyFeature;
-#if defined(OS_WIN) || defined(OS_APPLE) || defined(OS_LINUX) || \
- defined(OS_CHROMEOS) || defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) || \
+ BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_FUCHSIA)
extern const base::Feature kIPHDesktopSharedHighlightingFeature;
extern const base::Feature kIPHDesktopTabGroupsNewGroupFeature;
extern const base::Feature kIPHFocusHelpBubbleScreenReaderPromoFeature;
extern const base::Feature kIPHGMCCastStartStopFeature;
extern const base::Feature kIPHLiveCaptionFeature;
+extern const base::Feature kIPHTabAudioMutingFeature;
extern const base::Feature kIPHPasswordsAccountStorageFeature;
extern const base::Feature kIPHReadingListDiscoveryFeature;
extern const base::Feature kIPHReadingListEntryPointFeature;
@@ -48,13 +49,13 @@ extern const base::Feature kIPHDesktopSnoozeFeature;
extern const base::Feature kIPHDesktopPwaInstallFeature;
extern const base::Feature kIPHProfileSwitchFeature;
extern const base::Feature kIPHUpdatedConnectionSecurityIndicatorsFeature;
-#endif // defined(OS_WIN) || defined(OS_APPLE) || defined(OS_LINUX) ||
- // defined(OS_CHROMEOS) || defined(OS_FUCHSIA)
+#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) ||
+ // BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_FUCHSIA)
// All the features declared for Android below that are also used in Java,
// should also be declared in:
// org.chromium.components.feature_engagement.FeatureConstants.
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
extern const base::Feature
kIPHAdaptiveButtonInTopToolbarCustomizationNewTabFeature;
extern const base::Feature
@@ -96,7 +97,19 @@ extern const base::Feature
kIPHFeatureNotificationGuideNTPSuggestionCardNotificationShownFeature;
extern const base::Feature
kIPHFeatureNotificationGuideVoiceSearchNotificationShownFeature;
+extern const base::Feature
+ kIPHFeatureNotificationGuideDefaultBrowserPromoFeature;
+extern const base::Feature kIPHFeatureNotificationGuideSignInHelpBubbleFeature;
+extern const base::Feature
+ kIPHFeatureNotificationGuideIncognitoTabHelpBubbleFeature;
+extern const base::Feature
+ kIPHFeatureNotificationGuideNTPSuggestionCardHelpBubbleFeature;
+extern const base::Feature
+ kIPHFeatureNotificationGuideVoiceSearchHelpBubbleFeature;
+extern const base::Feature kIPHFeatureNotificationGuideIncognitoTabUsedFeature;
+extern const base::Feature kIPHFeatureNotificationGuideVoiceSearchUsedFeature;
extern const base::Feature kIPHFeedCardMenuFeature;
+extern const base::Feature kIPHGenericAlwaysTriggerHelpUiFeature;
extern const base::Feature kIPHHomePageButtonFeature;
extern const base::Feature kIPHHomepageTileFeature;
extern const base::Feature kIPHHomepagePromoCardFeature;
@@ -107,7 +120,7 @@ extern const base::Feature kIPHKeyboardAccessoryBarSwipingFeature;
extern const base::Feature kIPHKeyboardAccessoryPasswordFillingFeature;
extern const base::Feature kIPHKeyboardAccessoryPaymentFillingFeature;
extern const base::Feature kIPHKeyboardAccessoryPaymentOfferFeature;
-extern const base::Feature kIPHKeyboardAccessoryPaymentVirtualCardFeature;
+extern const base::Feature kIPHLowUserEngagementDetectorFeature;
extern const base::Feature kIPHMicToolbarFeature;
extern const base::Feature kIPHNewTabPageHomeButtonFeature;
extern const base::Feature kIPHPageInfoFeature;
@@ -147,9 +160,9 @@ extern const base::Feature kIPHSharedHighlightingBuilder;
extern const base::Feature kIPHSharedHighlightingReceiverFeature;
extern const base::Feature kIPHStartSurfaceTabSwitcherHomeButton;
extern const base::Feature kIPHSharingHubWebnotesStylizeFeature;
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
extern const base::Feature kIPHBottomToolbarTipFeature;
extern const base::Feature kIPHLongPressToolbarTipFeature;
extern const base::Feature kIPHNewTabTipFeature;
@@ -158,12 +171,16 @@ extern const base::Feature kIPHBadgedReadingListFeature;
extern const base::Feature kIPHReadingListMessagesFeature;
extern const base::Feature kIPHBadgedTranslateManualTriggerFeature;
extern const base::Feature kIPHDiscoverFeedHeaderFeature;
-#endif // defined(OS_IOS)
+extern const base::Feature kIPHDefaultSiteViewFeature;
+#endif // BUILDFLAG(IS_IOS)
-#if defined(OS_WIN) || defined(OS_APPLE) || defined(OS_LINUX) || \
- defined(OS_CHROMEOS) || defined(OS_ANDROID) || defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) || \
+ BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_FUCHSIA)
+extern const base::Feature kIPHAutofillVirtualCardSuggestionFeature;
extern const base::Feature kIPHUpdatedConnectionSecurityIndicatorsFeature;
-#endif
+#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) ||
+ // BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) ||
+ // BUILDFLAG(IS_FUCHSIA)
} // namespace feature_engagement
diff --git a/chromium/components/feature_engagement/public/feature_list.cc b/chromium/components/feature_engagement/public/feature_list.cc
index 2706fa1749c..35c9729e50d 100644
--- a/chromium/components/feature_engagement/public/feature_list.cc
+++ b/chromium/components/feature_engagement/public/feature_list.cc
@@ -5,6 +5,7 @@
#include "components/feature_engagement/public/feature_list.h"
#include "base/cxx17_backports.h"
+#include "build/build_config.h"
#include "components/feature_engagement/public/feature_constants.h"
namespace feature_engagement {
@@ -15,7 +16,7 @@ namespace {
// |kIPHDemoModeChoiceVariations| array.
const base::Feature* const kAllFeatures[] = {
&kIPHDummyFeature, // Ensures non-empty array for all platforms.
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
&kIPHAdaptiveButtonInTopToolbarCustomizationNewTabFeature,
&kIPHAdaptiveButtonInTopToolbarCustomizationShareFeature,
&kIPHAdaptiveButtonInTopToolbarCustomizationVoiceSearchFeature,
@@ -52,7 +53,15 @@ const base::Feature* const kAllFeatures[] = {
&kIPHFeatureNotificationGuideIncognitoTabNotificationShownFeature,
&kIPHFeatureNotificationGuideNTPSuggestionCardNotificationShownFeature,
&kIPHFeatureNotificationGuideVoiceSearchNotificationShownFeature,
+ &kIPHFeatureNotificationGuideDefaultBrowserPromoFeature,
+ &kIPHFeatureNotificationGuideSignInHelpBubbleFeature,
+ &kIPHFeatureNotificationGuideIncognitoTabHelpBubbleFeature,
+ &kIPHFeatureNotificationGuideVoiceSearchHelpBubbleFeature,
+ &kIPHFeatureNotificationGuideNTPSuggestionCardHelpBubbleFeature,
+ &kIPHFeatureNotificationGuideIncognitoTabUsedFeature,
+ &kIPHFeatureNotificationGuideVoiceSearchUsedFeature,
&kIPHFeedCardMenuFeature,
+ &kIPHGenericAlwaysTriggerHelpUiFeature,
&kIPHHomepagePromoCardFeature,
&kIPHIdentityDiscFeature,
&kIPHInstanceSwitcherFeature,
@@ -61,7 +70,7 @@ const base::Feature* const kAllFeatures[] = {
&kIPHKeyboardAccessoryPasswordFillingFeature,
&kIPHKeyboardAccessoryPaymentFillingFeature,
&kIPHKeyboardAccessoryPaymentOfferFeature,
- &kIPHKeyboardAccessoryPaymentVirtualCardFeature,
+ &kIPHLowUserEngagementDetectorFeature,
&kIPHMicToolbarFeature,
&kIPHNewTabPageHomeButtonFeature,
&kIPHPageInfoFeature,
@@ -99,8 +108,8 @@ const base::Feature* const kAllFeatures[] = {
&kIPHStartSurfaceTabSwitcherHomeButton,
&kIPHUpdatedConnectionSecurityIndicatorsFeature,
&kIPHSharingHubWebnotesStylizeFeature,
-#endif // defined(OS_ANDROID)
-#if defined(OS_IOS)
+#endif // BUILDFLAG(IS_ANDROID)
+#if BUILDFLAG(IS_IOS)
&kIPHBottomToolbarTipFeature,
&kIPHLongPressToolbarTipFeature,
&kIPHNewTabTipFeature,
@@ -109,13 +118,15 @@ const base::Feature* const kAllFeatures[] = {
&kIPHReadingListMessagesFeature,
&kIPHBadgedTranslateManualTriggerFeature,
&kIPHDiscoverFeedHeaderFeature,
-#endif // defined(OS_IOS)
-#if defined(OS_WIN) || defined(OS_APPLE) || defined(OS_LINUX) || \
- defined(OS_CHROMEOS) || defined(OS_FUCHSIA)
+ &kIPHDefaultSiteViewFeature,
+#endif // BUILDFLAG(IS_IOS)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) || \
+ BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_FUCHSIA)
&kIPHDesktopTabGroupsNewGroupFeature,
&kIPHFocusHelpBubbleScreenReaderPromoFeature,
&kIPHGMCCastStartStopFeature,
&kIPHLiveCaptionFeature,
+ &kIPHTabAudioMutingFeature,
&kIPHPasswordsAccountStorageFeature,
&kIPHReadingListDiscoveryFeature,
&kIPHReadingListEntryPointFeature,
@@ -128,8 +139,15 @@ const base::Feature* const kAllFeatures[] = {
&kIPHProfileSwitchFeature,
&kIPHUpdatedConnectionSecurityIndicatorsFeature,
&kIPHDesktopSharedHighlightingFeature,
-#endif // defined(OS_WIN) || defined(OS_APPLE) || defined(OS_LINUX) ||
- // defined(OS_CHROMEOS) || defined(OS_FUCHSIA)
+#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) ||
+ // BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_FUCHSIA)
+
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) || \
+ BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_FUCHSIA)
+ &kIPHAutofillVirtualCardSuggestionFeature,
+#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) ||
+ // BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) ||
+ // BUILDFLAG(IS_FUCHSIA)
};
} // namespace
diff --git a/chromium/components/feature_engagement/public/feature_list.h b/chromium/components/feature_engagement/public/feature_list.h
index a750f07b7dd..fc2071604f8 100644
--- a/chromium/components/feature_engagement/public/feature_list.h
+++ b/chromium/components/feature_engagement/public/feature_list.h
@@ -45,7 +45,7 @@ namespace {
// Defines a flags_ui::FeatureEntry::FeatureParam for each feature.
DEFINE_VARIATION_PARAM(kIPHDummyFeature, "IPH_Dummy");
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
DEFINE_VARIATION_PARAM(kIPHAdaptiveButtonInTopToolbarCustomizationNewTabFeature,
"IPH_AdaptiveButtonInTopToolbarCustomization_NewTab");
DEFINE_VARIATION_PARAM(kIPHAdaptiveButtonInTopToolbarCustomizationShareFeature,
@@ -115,7 +115,21 @@ DEFINE_VARIATION_PARAM(
DEFINE_VARIATION_PARAM(
kIPHFeatureNotificationGuideVoiceSearchNotificationShownFeature,
"IPH_FeatureNotificationGuideVoiceSearchNotificationShown");
+DEFINE_VARIATION_PARAM(kIPHFeatureNotificationGuideDefaultBrowserPromoFeature,
+ "IPH_FeatureNotificationGuideDefaultBrowserPromo");
+DEFINE_VARIATION_PARAM(kIPHFeatureNotificationGuideSignInHelpBubbleFeature,
+ "IPH_FeatureNotificationGuideSignInHelpBubble");
+DEFINE_VARIATION_PARAM(
+ kIPHFeatureNotificationGuideIncognitoTabHelpBubbleFeature,
+ "IPH_FeatureNotificationGuideIncognitoTabHelpBubble");
+DEFINE_VARIATION_PARAM(
+ kIPHFeatureNotificationGuideNTPSuggestionCardHelpBubbleFeature,
+ "IPH_FeatureNotificationGuideNTPSuggestionCardHelpBubble");
+DEFINE_VARIATION_PARAM(kIPHFeatureNotificationGuideVoiceSearchHelpBubbleFeature,
+ "IPH_FeatureNotificationGuideVoiceSearchHelpBubble");
DEFINE_VARIATION_PARAM(kIPHFeedCardMenuFeature, "IPH_FeedCardMenu");
+DEFINE_VARIATION_PARAM(kIPHGenericAlwaysTriggerHelpUiFeature,
+ "IPH_GenericAlwaysTriggerHelpUiFeature");
DEFINE_VARIATION_PARAM(kIPHHomepagePromoCardFeature, "IPH_HomepagePromoCard");
DEFINE_VARIATION_PARAM(kIPHIdentityDiscFeature, "IPH_IdentityDisc");
DEFINE_VARIATION_PARAM(kIPHInstanceSwitcherFeature, "IPH_InstanceSwitcher");
@@ -129,8 +143,6 @@ DEFINE_VARIATION_PARAM(kIPHKeyboardAccessoryPaymentFillingFeature,
"IPH_KeyboardAccessoryPaymentFilling");
DEFINE_VARIATION_PARAM(kIPHKeyboardAccessoryPaymentOfferFeature,
"IPH_KeyboardAccessoryPaymentOffer");
-DEFINE_VARIATION_PARAM(kIPHKeyboardAccessoryPaymentVirtualCardFeature,
- "IPH_KeyboardAccessoryPaymentVirtualCard");
DEFINE_VARIATION_PARAM(kIPHMicToolbarFeature, "IPH_MicToolbar");
DEFINE_VARIATION_PARAM(kIPHNewTabPageButtonFeature, "IPH_NewTabPageHomeButton");
DEFINE_VARIATION_PARAM(kIPHPageInfoFeature, "IPH_PageInfo");
@@ -194,8 +206,8 @@ DEFINE_VARIATION_PARAM(kIPHUpdatedConnectionSecurityIndicatorsFeature,
"IPH_UpdatedConnectionSecurityIndicators");
DEFINE_VARIATION_PARAM(kIPHSharingHubWebnotesStylizeFeature,
"IPH_SharingHubWebnotesStylize");
-#endif // defined(OS_ANDROID)
-#if defined(OS_IOS)
+#endif // BUILDFLAG(IS_ANDROID)
+#if BUILDFLAG(IS_IOS)
DEFINE_VARIATION_PARAM(kIPHBottomToolbarTipFeature, "IPH_BottomToolbarTip");
DEFINE_VARIATION_PARAM(kIPHLongPressToolbarTipFeature,
"IPH_LongPressToolbarTip");
@@ -208,10 +220,11 @@ DEFINE_VARIATION_PARAM(kIPHBadgedTranslateManualTriggerFeature,
"IPH_BadgedTranslateManualTrigger");
DEFINE_VARIATION_PARAM(kIPHDiscoverFeedHeaderFeature,
"IPH_DiscoverFeedHeaderMenu");
-#endif // defined(OS_IOS)
+DEFINE_VARIATION_PARAM(kIPHDefaultSiteViewFeature, "IPH_DefaultSiteView");
+#endif // BUILDFLAG(IS_IOS)
-#if defined(OS_WIN) || defined(OS_APPLE) || defined(OS_LINUX) || \
- defined(OS_CHROMEOS) || defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) || \
+ BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_FUCHSIA)
DEFINE_VARIATION_PARAM(kIPHDesktopTabGroupsNewGroupFeature,
"IPH_DesktopTabGroupsNewGroup");
DEFINE_VARIATION_PARAM(kIPHFocusModeFeature, "IPH_FocusMode");
@@ -228,6 +241,7 @@ DEFINE_VARIATION_PARAM(kIPHReadingListInSidePanelFeature,
"IPH_ReadingListInSidePanel");
DEFINE_VARIATION_PARAM(kIPHReopenTabFeature, "IPH_ReopenTab");
DEFINE_VARIATION_PARAM(kIPHSideSearchFeature, "IPH_SideSearch");
+DEFINE_VARIATION_PARAM(kIPHTabAudioMutingFeature, "IPH_TabAudioMuting");
DEFINE_VARIATION_PARAM(kIPHTabSearchFeature, "IPH_TabSearch");
DEFINE_VARIATION_PARAM(kIPHWebUITabStripFeature, "IPH_WebUITabStrip");
DEFINE_VARIATION_PARAM(kIPHDesktopPwaInstallFeature, "IPH_DesktopPwaInstall");
@@ -236,8 +250,16 @@ DEFINE_VARIATION_PARAM(kIPHUpdatedConnectionSecurityIndicatorsFeature,
"IPH_UpdatedConnectionSecurityIndicators");
DEFINE_VARIATION_PARAM(kIPHDesktopSharedHighlightingFeature,
"IPH_DesktopSharedHighlighting");
-#endif // defined(OS_WIN) || defined(OS_APPLE) || defined(OS_LINUX) ||
- // defined(OS_CHROMEOS) || defined(OS_FUCHSIA)
+#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) ||
+ // BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_FUCHSIA)
+
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) || \
+ BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_FUCHSIA)
+DEFINE_VARIATION_PARAM(kIPHAutofillVirtualCardSuggestionFeature,
+ "IPH_AutofillVirtualCardSuggestion");
+#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) ||
+ // BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) ||
+ // BUILDFLAG(IS_FUCHSIA)
} // namespace
@@ -246,7 +268,7 @@ DEFINE_VARIATION_PARAM(kIPHDesktopSharedHighlightingFeature,
// are possible to enable on their own in demo mode.
constexpr flags_ui::FeatureEntry::FeatureVariation
kIPHDemoModeChoiceVariations[] = {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
VARIATION_ENTRY(
kIPHAdaptiveButtonInTopToolbarCustomizationNewTabFeature),
VARIATION_ENTRY(
@@ -290,7 +312,6 @@ constexpr flags_ui::FeatureEntry::FeatureVariation
VARIATION_ENTRY(kIPHKeyboardAccessoryPasswordFillingFeature),
VARIATION_ENTRY(kIPHKeyboardAccessoryPaymentFillingFeature),
VARIATION_ENTRY(kIPHKeyboardAccessoryPaymentOfferFeature),
- VARIATION_ENTRY(kIPHKeyboardAccessoryPaymentVirtualCardFeature),
VARIATION_ENTRY(kIPHMicToolbarFeature),
VARIATION_ENTRY(kIPHNewTabPageButtonFeature),
VARIATION_ENTRY(kIPHPageInfoFeature),
@@ -318,6 +339,7 @@ constexpr flags_ui::FeatureEntry::FeatureVariation
VARIATION_ENTRY(kIPHVideoTutorialTryNowFeature),
VARIATION_ENTRY(kIPHExploreSitesTileFeature),
VARIATION_ENTRY(kIPHFeedHeaderMenuFeature),
+ VARIATION_ENTRY(kIPHFeedSwipeRefresh),
VARIATION_ENTRY(kIPHShareScreenshotFeature),
VARIATION_ENTRY(kIPHSharingHubLinkToggleFeature),
VARIATION_ENTRY(kIPHWebFeedFollowFeature),
@@ -326,7 +348,7 @@ constexpr flags_ui::FeatureEntry::FeatureVariation
VARIATION_ENTRY(kIPHSharedHighlightingReceiverFeature),
VARIATION_ENTRY(kIPHUpdatedConnectionSecurityIndicatorsFeature),
VARIATION_ENTRY(kIPHSharingHubWebnotesStylizeFeature),
-#elif defined(OS_IOS)
+#elif BUILDFLAG(IS_IOS)
VARIATION_ENTRY(kIPHBottomToolbarTipFeature),
VARIATION_ENTRY(kIPHLongPressToolbarTipFeature),
VARIATION_ENTRY(kIPHNewTabTipFeature),
@@ -335,8 +357,9 @@ constexpr flags_ui::FeatureEntry::FeatureVariation
VARIATION_ENTRY(kIPHReadingListMessagesFeature),
VARIATION_ENTRY(kIPHBadgedTranslateManualTriggerFeature),
VARIATION_ENTRY(kIPHDiscoverFeedHeaderFeature),
-#elif defined(OS_WIN) || defined(OS_MAC) || defined(OS_LINUX) || \
- defined(OS_CHROMEOS) || defined(OS_FUCHSIA)
+ VARIATION_ENTRY(kIPHDefaultSiteViewFeature),
+#elif BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || \
+ BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_FUCHSIA)
VARIATION_ENTRY(kIPHDesktopTabGroupsNewGroupFeature),
VARIATION_ENTRY(kIPHFocusModeFeature),
VARIATION_ENTRY(kIPHGlobalMediaControls),
@@ -348,14 +371,22 @@ constexpr flags_ui::FeatureEntry::FeatureVariation
VARIATION_ENTRY(kIPHReadingListInSidePanelFeature),
VARIATION_ENTRY(kIPHReopenTabFeature),
VARIATION_ENTRY(kIPHSideSearchFeature),
+ VARIATION_ENTRY(kIPHTabAudioMutingFeature),
VARIATION_ENTRY(kIPHTabSearchFeature),
VARIATION_ENTRY(kIPHWebUITabStripFeature),
VARIATION_ENTRY(kIPHDesktopPwaInstallFeature),
VARIATION_ENTRY(kIPHProfileSwitchFeature),
VARIATION_ENTRY(kIPHUpdatedConnectionSecurityIndicatorsFeature),
VARIATION_ENTRY(kIPHDesktopSharedHighlightingFeature),
-#endif // defined(OS_WIN) || defined(OS_MAC) || defined(OS_LINUX) ||
- // defined(OS_CHROMEOS) || defined(OS_FUCHSIA)
+#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) ||
+ // BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_FUCHSIA)
+
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) || \
+ BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_FUCHSIA)
+ VARIATION_ENTRY(kIPHAutofillVirtualCardSuggestionFeature),
+#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) ||
+ // BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) ||
+ // BUILDFLAG(IS_FUCHSIA)
};
#undef DEFINE_VARIATION_PARAM
diff --git a/chromium/components/feature_engagement/public/tracker.h b/chromium/components/feature_engagement/public/tracker.h
index 18e423e73d9..899eef8e2a4 100644
--- a/chromium/components/feature_engagement/public/tracker.h
+++ b/chromium/components/feature_engagement/public/tracker.h
@@ -9,7 +9,6 @@
#include <string>
#include "base/callback.h"
-#include "base/compiler_specific.h"
#include "base/feature_list.h"
#include "base/files/file_path.h"
#include "base/memory/ref_counted.h"
@@ -17,10 +16,11 @@
#include "base/task/sequenced_task_runner.h"
#include "build/build_config.h"
#include "components/keyed_service/core/keyed_service.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "base/android/jni_android.h"
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
namespace leveldb_proto {
class ProtoDatabaseProvider;
@@ -96,11 +96,11 @@ class Tracker : public KeyedService, public base::SupportsUserData {
bool should_show_snooze_;
};
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Returns a Java object of the type Tracker for the given Tracker.
static base::android::ScopedJavaLocalRef<jobject> GetJavaObject(
Tracker* feature_engagement);
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
// Invoked when the tracker has been initialized. The |success| parameter
// indicates that the initialization was a success and the tracker is ready to
@@ -125,8 +125,8 @@ class Tracker : public KeyedService, public base::SupportsUserData {
// help must happen.
// If |true| is returned, the caller *must* call Dismissed(...) when display
// of feature enlightenment ends.
- virtual bool ShouldTriggerHelpUI(const base::Feature& feature)
- WARN_UNUSED_RESULT = 0;
+ [[nodiscard]] virtual bool ShouldTriggerHelpUI(
+ const base::Feature& feature) = 0;
// For callers interested in showing a snooze button. For other callers, use
// the ShouldTriggerHelpUI(..) method.
@@ -192,6 +192,27 @@ class Tracker : public KeyedService, public base::SupportsUserData {
// This method returns nullptr if no handle could be retrieved.
virtual std::unique_ptr<DisplayLockHandle> AcquireDisplayLock() = 0;
+ // Called by the client to notify the tracker that a priority notification
+ // should be shown. If a handler has already been registered, the IPH will be
+ // shown right away. Otherwise, the tracker will cache the priority feature
+ // and will show the IPH whenever a handler is registered in future. All other
+ // IPHs will be blocked until then. It isn't allowed to invoke this method
+ // again with another notification before the existing one is processed.
+ virtual void SetPriorityNotification(const base::Feature& feature) = 0;
+
+ // Called to get if there is a pending priority notification to be shown next.
+ virtual absl::optional<std::string> GetPendingPriorityNotification() = 0;
+
+ // Called by the client to register a handler for priority notifications. This
+ // will essentially contain the code to spin up an IPH.
+ virtual void RegisterPriorityNotificationHandler(
+ const base::Feature& feature,
+ base::OnceClosure callback) = 0;
+
+ // Unregister the handler. Must be called during client destruction.
+ virtual void UnregisterPriorityNotificationHandler(
+ const base::Feature& feature) = 0;
+
// Returns whether the tracker has been successfully initialized. During
// startup, this will be false until the internal models have been loaded at
// which point it is set to true if the initialization was successful. The
diff --git a/chromium/components/federated_learning/BUILD.gn b/chromium/components/federated_learning/BUILD.gn
deleted file mode 100644
index fb66edb1508..00000000000
--- a/chromium/components/federated_learning/BUILD.gn
+++ /dev/null
@@ -1,45 +0,0 @@
-# Copyright 2020 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.
-
-static_library("federated_learning") {
- sources = [
- "features/features.cc",
- "features/features.h",
- "floc_constants.cc",
- "floc_constants.h",
- "floc_id.cc",
- "floc_id.h",
- "floc_sorting_lsh_clusters_service.cc",
- "floc_sorting_lsh_clusters_service.h",
- "sim_hash.cc",
- "sim_hash.h",
- ]
-
- public_deps = [
- "//content/public/common:common",
- "//third_party/protobuf:protobuf_lite",
- ]
-
- deps = [
- "//base",
- "//components/prefs:prefs",
- ]
-}
-
-source_set("unit_tests") {
- testonly = true
- sources = [
- "floc_id_unittest.cc",
- "floc_sorting_lsh_clusters_service_unittest.cc",
- "sim_hash_unittest.cc",
- ]
-
- deps = [
- ":federated_learning",
- "//base",
- "//base/test:test_support",
- "//components/prefs:test_support",
- "//testing/gtest",
- ]
-}
diff --git a/chromium/components/federated_learning/COMMON_METADATA b/chromium/components/federated_learning/COMMON_METADATA
deleted file mode 100644
index 0e6c030558f..00000000000
--- a/chromium/components/federated_learning/COMMON_METADATA
+++ /dev/null
@@ -1 +0,0 @@
-team_email: "privacy-sandbox-dev@chromium.org"
diff --git a/chromium/components/federated_learning/DEPS b/chromium/components/federated_learning/DEPS
deleted file mode 100644
index 9a49fbd7c95..00000000000
--- a/chromium/components/federated_learning/DEPS
+++ /dev/null
@@ -1,6 +0,0 @@
-include_rules = [
- "+third_party/protobuf",
- "+content/public/common",
- "+components/prefs",
- "+third_party/blink/public",
-]
diff --git a/chromium/components/federated_learning/DIR_METADATA b/chromium/components/federated_learning/DIR_METADATA
deleted file mode 100644
index ea6a8e28933..00000000000
--- a/chromium/components/federated_learning/DIR_METADATA
+++ /dev/null
@@ -1 +0,0 @@
-mixins: "//components/federated_learning/COMMON_METADATA"
diff --git a/chromium/components/federated_learning/OWNERS b/chromium/components/federated_learning/OWNERS
deleted file mode 100644
index 424ff9bd8e0..00000000000
--- a/chromium/components/federated_learning/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-jkarlin@chromium.org
-yaoxia@chromium.org
-
-# TODO(yaoxia): Add a crbug component for FloC.
diff --git a/chromium/components/federated_learning/README.md b/chromium/components/federated_learning/README.md
deleted file mode 100644
index 63c2c190e73..00000000000
--- a/chromium/components/federated_learning/README.md
+++ /dev/null
@@ -1,7 +0,0 @@
-# Federated Learning Component
-The FLoC (Federated Learning of Cohorts) project aims to group users based on
-their browsing habits in a privacy preserving way, that would allow
-interest-based advertising without exposing a user’s browsing history.
-
-This component contains data types (e.g. FlocID) that other layers could access
-(e.g. chrome/browser, services/network).
diff --git a/chromium/components/federated_learning/features/features.cc b/chromium/components/federated_learning/features/features.cc
deleted file mode 100644
index cd05f2693f2..00000000000
--- a/chromium/components/federated_learning/features/features.cc
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright 2020 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.
-
-#include "components/federated_learning/features/features.h"
-
-#include "base/feature_list.h"
-
-namespace federated_learning {
-
-// If enabled, the check for whether the IP address is publicly routable will be
-// bypassed when determining the eligibility for a page to be included in floc
-// computation. This is useful for developers to test FLoC in local environment.
-const base::Feature kFlocBypassIPIsPubliclyRoutableCheck{
- "FlocBypassIPIsPubliclyRoutableCheck", base::FEATURE_DISABLED_BY_DEFAULT};
-
-// Enables or disables the FlocIdComputed event logging, which happens when a
-// floc id is first computed for a browsing session or is refreshed due to a
-// long period of time has passed since the last computation.
-const base::Feature kFlocIdComputedEventLogging{
- "FlocIdComputedEventLogging", base::FEATURE_ENABLED_BY_DEFAULT};
-
-// If enabled, pages that had ad resources will be included in floc computation;
-// otherwise, only pages that used the document.interestCohort API will be
-// included. This flag affects a bit to be stored at page viewing time, so it
-// may take a full computation cycle for the floc to meet the configured
-// criteria.
-const base::Feature kFlocPagesWithAdResourcesDefaultIncludedInFlocComputation{
- "FlocPagesWithAdResourcesDefaultIncludedInFlocComputation",
- base::FEATURE_DISABLED_BY_DEFAULT};
-
-// The main floc feature for all the subsidiary control and setting params. It's
-// controlling the floc update rate, and the minimum history domain size
-// required.
-// TODO(yaoxia): merge other floc features into this one.
-const base::Feature kFederatedLearningOfCohorts{
- "FederatedLearningOfCohorts", base::FEATURE_DISABLED_BY_DEFAULT};
-constexpr base::FeatureParam<base::TimeDelta> kFlocIdScheduledUpdateInterval{
- &kFederatedLearningOfCohorts, "update_interval", base::Days(7)};
-constexpr base::FeatureParam<int> kFlocIdMinimumHistoryDomainSizeRequired{
- &kFederatedLearningOfCohorts, "minimum_history_domain_size_required", 3};
-constexpr base::FeatureParam<int> kFlocIdFinchConfigVersion{
- &kFederatedLearningOfCohorts, "finch_config_version", 1};
-
-} // namespace federated_learning
diff --git a/chromium/components/federated_learning/features/features.h b/chromium/components/federated_learning/features/features.h
deleted file mode 100644
index 2de1234c788..00000000000
--- a/chromium/components/federated_learning/features/features.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2020 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.
-
-#ifndef COMPONENTS_FEDERATED_LEARNING_FEATURES_FEATURES_H_
-#define COMPONENTS_FEDERATED_LEARNING_FEATURES_FEATURES_H_
-
-#include "base/feature_list.h"
-#include "base/metrics/field_trial_params.h"
-
-namespace federated_learning {
-
-extern const base::Feature kFlocBypassIPIsPubliclyRoutableCheck;
-extern const base::Feature kFlocIdComputedEventLogging;
-extern const base::Feature
- kFlocPagesWithAdResourcesDefaultIncludedInFlocComputation;
-
-extern const base::Feature kFederatedLearningOfCohorts;
-extern const base::FeatureParam<base::TimeDelta> kFlocIdScheduledUpdateInterval;
-extern const base::FeatureParam<int> kFlocIdMinimumHistoryDomainSizeRequired;
-extern const base::FeatureParam<int> kFlocIdFinchConfigVersion;
-
-} // namespace federated_learning
-
-#endif // COMPONENTS_FEDERATED_LEARNING_FEATURES_FEATURES_H_
diff --git a/chromium/components/federated_learning/floc_constants.cc b/chromium/components/federated_learning/floc_constants.cc
deleted file mode 100644
index 9974c4ff6d9..00000000000
--- a/chromium/components/federated_learning/floc_constants.cc
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2020 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.
-
-#include "components/federated_learning/floc_constants.h"
-
-#include <limits>
-
-namespace federated_learning {
-
-// This is only for experimentation and won't be served to websites.
-const uint8_t kMaxNumberOfBitsInFloc = 50;
-static_assert(kMaxNumberOfBitsInFloc > 0 &&
- kMaxNumberOfBitsInFloc <=
- std::numeric_limits<uint64_t>::digits,
- "Number of bits in the floc id must be greater than 0 and no "
- "greater than 64.");
-
-const char kFlocIdValuePrefKey[] = "federated_learning.floc_id.value";
-
-const char kFlocIdStatusPrefKey[] = "federated_learning.floc_id.status";
-
-const char kFlocIdHistoryBeginTimePrefKey[] =
- "federated_learning.floc_id.history_begin_time";
-
-const char kFlocIdHistoryEndTimePrefKey[] =
- "federated_learning.floc_id.history_end_time";
-
-const char kFlocIdFinchConfigVersionPrefKey[] =
- "federated_learning.floc_id.finch_config_version";
-
-const char kFlocIdSortingLshVersionPrefKey[] =
- "federated_learning.floc_id.sorting_lsh_version";
-
-const char kFlocIdComputeTimePrefKey[] =
- "federated_learning.floc_id.compute_time";
-
-const char kManifestFlocComponentFormatKey[] = "floc_component_format";
-
-const int kCurrentFlocComponentFormatVersion = 3;
-
-const uint8_t kSortingLshMaxBits = 7;
-
-const uint32_t kSortingLshBlockedMask = 0b1000000;
-
-const uint32_t kSortingLshSizeMask = 0b0111111;
-
-const base::FilePath::CharType kTopLevelDirectoryName[] =
- FILE_PATH_LITERAL("Floc");
-
-const base::FilePath::CharType kSortingLshClustersFileName[] =
- FILE_PATH_LITERAL("SortingLshClusters");
-
-} // namespace federated_learning
diff --git a/chromium/components/federated_learning/floc_constants.h b/chromium/components/federated_learning/floc_constants.h
deleted file mode 100644
index 0c5627c376f..00000000000
--- a/chromium/components/federated_learning/floc_constants.h
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2020 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.
-
-#ifndef COMPONENTS_FEDERATED_LEARNING_FLOC_CONSTANTS_H_
-#define COMPONENTS_FEDERATED_LEARNING_FLOC_CONSTANTS_H_
-
-#include "base/files/file_path.h"
-
-namespace federated_learning {
-
-extern const uint8_t kMaxNumberOfBitsInFloc;
-
-// ---------------------------
-// For the preferences storage
-// ---------------------------
-extern const char kFlocIdValuePrefKey[];
-extern const char kFlocIdStatusPrefKey[];
-extern const char kFlocIdHistoryBeginTimePrefKey[];
-extern const char kFlocIdHistoryEndTimePrefKey[];
-extern const char kFlocIdFinchConfigVersionPrefKey[];
-extern const char kFlocIdSortingLshVersionPrefKey[];
-extern const char kFlocIdComputeTimePrefKey[];
-extern const char kManifestFlocComponentFormatKey[];
-
-// -----------------------------
-// For the sorting-lsh algorithm
-// -----------------------------
-extern const uint8_t kSortingLshMaxBits;
-extern const uint32_t kSortingLshBlockedMask;
-extern const uint32_t kSortingLshSizeMask;
-
-// ------------------------------
-// For the floc component updater
-// ------------------------------
-extern const int kCurrentFlocComponentFormatVersion;
-
-// The name of the top-level directory under the user data directory that
-// contains all files and subdirectories related to the floc.
-extern const base::FilePath::CharType kTopLevelDirectoryName[];
-
-// The name of the file that stores the sorting-lsh clusters. The file lives
-// under under |kTopLevelDirectoryName|
-extern const base::FilePath::CharType kSortingLshClustersFileName[];
-
-} // namespace federated_learning
-
-#endif // COMPONENTS_FEDERATED_LEARNING_FLOC_CONSTANTS_H_ \ No newline at end of file
diff --git a/chromium/components/federated_learning/floc_id.cc b/chromium/components/federated_learning/floc_id.cc
deleted file mode 100644
index e282b2fccbd..00000000000
--- a/chromium/components/federated_learning/floc_id.cc
+++ /dev/null
@@ -1,169 +0,0 @@
-// Copyright 2020 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.
-
-#include "components/federated_learning/floc_id.h"
-
-#include "base/strings/strcat.h"
-#include "base/strings/string_number_conversions.h"
-#include "components/federated_learning/features/features.h"
-#include "components/federated_learning/floc_constants.h"
-#include "components/federated_learning/sim_hash.h"
-#include "components/prefs/pref_registry_simple.h"
-#include "components/prefs/pref_service.h"
-#include "third_party/blink/public/mojom/federated_learning/floc.mojom.h"
-
-namespace federated_learning {
-
-// static
-uint64_t FlocId::SimHashHistory(
- const std::unordered_set<std::string>& domains) {
- return SimHashStrings(domains, kMaxNumberOfBitsInFloc);
-}
-
-// static
-FlocId FlocId::CreateInvalid(Status status) {
- DCHECK_NE(Status::kValid, status);
- DCHECK_NE(Status::kInvalidNoStatusPrefs, status);
- return FlocId(/*id=*/0, status,
- /*history_begin_time=*/base::Time(),
- /*history_end_time=*/base::Time(),
- kFlocIdFinchConfigVersion.Get(),
- /*sorting_lsh_version=*/0,
- /*compute_time=*/base::Time::Now());
-}
-
-// static
-FlocId FlocId::CreateValid(uint64_t id,
- base::Time history_begin_time,
- base::Time history_end_time,
- uint32_t sorting_lsh_version) {
- return FlocId(id, Status::kValid, history_begin_time, history_end_time,
- kFlocIdFinchConfigVersion.Get(), sorting_lsh_version,
- /*compute_time=*/base::Time::Now());
-}
-
-FlocId::FlocId(const FlocId& id) = default;
-
-FlocId::~FlocId() = default;
-
-FlocId& FlocId::operator=(const FlocId& id) = default;
-
-FlocId& FlocId::operator=(FlocId&& id) = default;
-
-bool FlocId::IsValid() const {
- return status_ == Status::kValid;
-}
-
-bool FlocId::operator==(const FlocId& other) const {
- return id_ == other.id_ && status_ == other.status_ &&
- history_begin_time_ == other.history_begin_time_ &&
- history_end_time_ == other.history_end_time_ &&
- finch_config_version_ == other.finch_config_version_ &&
- sorting_lsh_version_ == other.sorting_lsh_version_ &&
- compute_time_ == other.compute_time_;
-}
-
-bool FlocId::operator!=(const FlocId& other) const {
- return !(*this == other);
-}
-
-blink::mojom::InterestCohortPtr FlocId::ToInterestCohortForJsApi() const {
- // TODO(yaoxia): consider returning the version part even when floc is
- // invalid.
-
- DCHECK_EQ(Status::kValid, status_);
-
- blink::mojom::InterestCohortPtr result = blink::mojom::InterestCohort::New();
- result->id = base::NumberToString(id_);
- result->version =
- base::StrCat({"chrome.", base::NumberToString(finch_config_version_), ".",
- base::NumberToString(sorting_lsh_version_)});
- return result;
-}
-
-uint64_t FlocId::ToUint64() const {
- DCHECK_EQ(Status::kValid, status_);
- return id_;
-}
-
-// static
-void FlocId::RegisterPrefs(PrefRegistrySimple* registry) {
- registry->RegisterUint64Pref(kFlocIdValuePrefKey, 0);
- registry->RegisterIntegerPref(
- kFlocIdStatusPrefKey, static_cast<int>(Status::kInvalidNoStatusPrefs));
- registry->RegisterTimePref(kFlocIdHistoryBeginTimePrefKey, base::Time());
- registry->RegisterTimePref(kFlocIdHistoryEndTimePrefKey, base::Time());
- registry->RegisterUint64Pref(kFlocIdFinchConfigVersionPrefKey, 0);
- registry->RegisterUint64Pref(kFlocIdSortingLshVersionPrefKey, 0);
- registry->RegisterTimePref(kFlocIdComputeTimePrefKey, base::Time());
-}
-
-void FlocId::SaveToPrefs(PrefService* prefs) {
- DCHECK_NE(status_, Status::kInvalidNoStatusPrefs);
-
- prefs->SetUint64(kFlocIdValuePrefKey, id_);
- prefs->SetInteger(kFlocIdStatusPrefKey, static_cast<int>(status_));
- prefs->SetTime(kFlocIdHistoryBeginTimePrefKey, history_begin_time_);
- prefs->SetTime(kFlocIdHistoryEndTimePrefKey, history_end_time_);
- prefs->SetUint64(kFlocIdFinchConfigVersionPrefKey, finch_config_version_);
- prefs->SetUint64(kFlocIdSortingLshVersionPrefKey, sorting_lsh_version_);
- prefs->SetTime(kFlocIdComputeTimePrefKey, compute_time_);
-}
-
-void FlocId::UpdateStatusAndSaveToPrefs(PrefService* prefs, Status status) {
- DCHECK_NE(status, Status::kValid);
- DCHECK_NE(status, Status::kInvalidNoStatusPrefs);
- status_ = status;
- prefs->SetInteger(kFlocIdStatusPrefKey, static_cast<int>(status_));
-}
-
-void FlocId::ResetComputeTimeAndSaveToPrefs(base::Time compute_time,
- PrefService* prefs) {
- compute_time_ = compute_time;
- prefs->SetTime(kFlocIdComputeTimePrefKey, compute_time_);
-}
-
-// static
-FlocId FlocId::ReadFromPrefs(PrefService* prefs) {
- Status status = Status::kInvalidNoStatusPrefs;
-
- // We rely on the time to tell whether it's a fresh profile.
- if (!prefs->GetTime(kFlocIdComputeTimePrefKey).is_null()) {
- // In some previous pref version before the status field is introduced, we
- // used to use null path to represent invalid floc. After the status field
- // is introduced, that state is represented in status.
- if (prefs->HasPrefPath(kFlocIdValuePrefKey)) {
- if (prefs->HasPrefPath(kFlocIdStatusPrefKey)) {
- status = static_cast<Status>(prefs->GetInteger(kFlocIdStatusPrefKey));
- DCHECK_NE(status, Status::kInvalidNoStatusPrefs);
- } else {
- status = Status::kValid;
- }
- }
- }
-
- return FlocId(prefs->GetUint64(kFlocIdValuePrefKey), status,
- prefs->GetTime(kFlocIdHistoryBeginTimePrefKey),
- prefs->GetTime(kFlocIdHistoryEndTimePrefKey),
- prefs->GetUint64(kFlocIdFinchConfigVersionPrefKey),
- prefs->GetUint64(kFlocIdSortingLshVersionPrefKey),
- prefs->GetTime(kFlocIdComputeTimePrefKey));
-}
-
-FlocId::FlocId(uint64_t id,
- Status status,
- base::Time history_begin_time,
- base::Time history_end_time,
- uint32_t finch_config_version,
- uint32_t sorting_lsh_version,
- base::Time compute_time)
- : id_(id),
- status_(status),
- history_begin_time_(history_begin_time),
- history_end_time_(history_end_time),
- finch_config_version_(finch_config_version),
- sorting_lsh_version_(sorting_lsh_version),
- compute_time_(compute_time) {}
-
-} // namespace federated_learning
diff --git a/chromium/components/federated_learning/floc_id.h b/chromium/components/federated_learning/floc_id.h
deleted file mode 100644
index 39d50beac56..00000000000
--- a/chromium/components/federated_learning/floc_id.h
+++ /dev/null
@@ -1,158 +0,0 @@
-// Copyright 2020 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.
-
-#ifndef COMPONENTS_FEDERATED_LEARNING_FLOC_ID_H_
-#define COMPONENTS_FEDERATED_LEARNING_FLOC_ID_H_
-
-#include "base/time/time.h"
-#include "base/version.h"
-#include "components/prefs/prefs_export.h"
-#include "third_party/blink/public/mojom/federated_learning/floc.mojom-forward.h"
-
-#include <stdint.h>
-
-#include <string>
-#include <unordered_set>
-
-class PrefRegistrySimple;
-class PrefService;
-
-namespace federated_learning {
-
-// ID used to represent a cohort of people with similar browsing habits. For
-// more context, see the explainer at
-// https://github.com/jkarlin/floc/blob/master/README.md
-class FlocId {
- public:
- enum class Status {
- kValid = 0,
-
- // The default invalid reason that a fresh profile comes with. An
- // outstanding cohort can also have this state after a prefs update where
- // the previous reason is unknown or ambiguous.
- kInvalidNoStatusPrefs = 1,
-
- // The cohort computation is ready to run, but is waiting for other signals
- // to start (e.g. sorting-lsh file is ready).
- kInvalidWaitingToStart = 2,
-
- kInvalidDisallowedByUserSettings = 3,
- kInvalidNotEnoughElgibleHistoryDomains = 4,
-
- // Set if the sorting-lsh process returns an empty hash value. This often
- // implies that the cohort is blocked, but in principle can also be due to
- // file sanitization errors.
- // TODO(yaoxia): consider distinguishing between the underlying reasons.
- kInvalidBlocked = 5,
-
- kInvalidHistoryDeleted = 6,
-
- // This reason is set when the user deletes cookies or resets cohort through
- // a dedicated FLoC settings page until it's time to calculate at the next
- // epoch.
- kInvalidReset = 7,
- };
-
- static uint64_t SimHashHistory(
- const std::unordered_set<std::string>& domains);
-
- // Create an invalid floc. The `finch_config_version_` and the `compute_time_`
- // will be set to the current.
- static FlocId CreateInvalid(Status status);
-
- // Create a newly computed and valid floc. The `finch_config_version_` and
- // the `compute_time_` will be set to the current.
- static FlocId CreateValid(uint64_t id,
- base::Time history_begin_time,
- base::Time history_end_time,
- uint32_t sorting_lsh_version);
-
- FlocId(const FlocId& id);
- ~FlocId();
- FlocId& operator=(const FlocId& id);
- FlocId& operator=(FlocId&& id);
-
- bool operator==(const FlocId& other) const;
- bool operator!=(const FlocId& other) const;
-
- // True if the floc is successfully computed and hasn't been invalidated
- // since the last computation. Note that an invalid FlocId still often has a
- // legitimate compute time and finch config version, unless it's read from a
- // fresh profile prefs.
- bool IsValid() const;
-
- // Get the blink::mojom::InterestCohort representation of this floc, with
- // interest_cohort.id being "<id>" and interest_cohort.version being
- // "chrome.<finch_config_version>.<sorting_lsh_version>". This is the format
- // to be exposed to the JS API. Precondition: the floc must be valid.
- blink::mojom::InterestCohortPtr ToInterestCohortForJsApi() const;
-
- // Returns the internal uint64_t number. Precondition: the floc must be valid.
- uint64_t ToUint64() const;
-
- Status status() const { return status_; }
-
- base::Time history_begin_time() const { return history_begin_time_; }
-
- base::Time history_end_time() const { return history_end_time_; }
-
- uint32_t finch_config_version() const { return finch_config_version_; }
-
- uint32_t sorting_lsh_version() const { return sorting_lsh_version_; }
-
- base::Time compute_time() const { return compute_time_; }
-
- static void RegisterPrefs(PrefRegistrySimple* registry);
-
- void SaveToPrefs(PrefService* prefs);
- static FlocId ReadFromPrefs(PrefService* prefs);
-
- // Update `status_` and the corresponding prefs entry. This can be used to
- // invalidate the floc or to assign a new invalid reason.
- void UpdateStatusAndSaveToPrefs(PrefService* prefs, Status status);
-
- // Resets `compute_time_` to provided `compute_time` and saves it to prefs.
- // This should at least be called if the floc compute timer is reset, to
- // ensure that the compute cycle continues at the expected frequency.
- void ResetComputeTimeAndSaveToPrefs(base::Time compute_time,
- PrefService* prefs);
-
- private:
- friend class FlocIdTester;
-
- // Create a floc with stated params. This will only be used to create a floc
- // read from prefs.
- explicit FlocId(uint64_t id,
- Status status,
- base::Time history_begin_time,
- base::Time history_end_time,
- uint32_t finch_config_version,
- uint32_t sorting_lsh_version,
- base::Time compute_time);
-
- uint64_t id_ = 0;
-
- Status status_;
-
- // The time range of the actual history used to compute the floc. This should
- // always be within the time range of each history query.
- base::Time history_begin_time_;
- base::Time history_end_time_;
-
- // The kFlocIdFinchConfigVersion feature param. When floc is loaded from
- // prefs, this could be different from the current feature param state.
- uint32_t finch_config_version_ = 0;
-
- // The main version (i.e. 1st int) of the sorting lsh component version.
- uint32_t sorting_lsh_version_ = 0;
-
- // The time when the floc was computed. compute_time_.is_null() means the
- // floc has never been computed before, and implies that the floc is also
- // invalid.
- base::Time compute_time_;
-};
-
-} // namespace federated_learning
-
-#endif // COMPONENTS_FEDERATED_LEARNING_FLOC_ID_H_
diff --git a/chromium/components/federated_learning/floc_id_unittest.cc b/chromium/components/federated_learning/floc_id_unittest.cc
deleted file mode 100644
index 70ce5c9493e..00000000000
--- a/chromium/components/federated_learning/floc_id_unittest.cc
+++ /dev/null
@@ -1,304 +0,0 @@
-// Copyright 2020 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.
-
-#include "components/federated_learning/floc_id.h"
-
-#include "base/test/scoped_feature_list.h"
-#include "base/test/task_environment.h"
-#include "components/federated_learning/features/features.h"
-#include "components/federated_learning/floc_constants.h"
-#include "components/prefs/testing_pref_service.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/mojom/federated_learning/floc.mojom.h"
-
-namespace federated_learning {
-
-namespace {
-
-blink::mojom::InterestCohortPtr InterestCohortResult(
- const std::string& id,
- const std::string& version) {
- blink::mojom::InterestCohortPtr result = blink::mojom::InterestCohort::New();
- result->id = id;
- result->version = version;
- return result;
-}
-
-const base::Time kTime0 = base::Time();
-const base::Time kTime1 = base::Time::FromTimeT(1);
-const base::Time kTime2 = base::Time::FromTimeT(2);
-
-} // namespace
-
-class FlocIdUnitTest : public testing::Test {
- public:
- FlocIdUnitTest()
- : task_environment_(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
-
- ~FlocIdUnitTest() override = default;
-
- protected:
- base::test::SingleThreadTaskEnvironment task_environment_;
-};
-
-TEST_F(FlocIdUnitTest, IsValid) {
- EXPECT_FALSE(
- FlocId::CreateInvalid(FlocId::Status::kInvalidWaitingToStart).IsValid());
- EXPECT_TRUE(FlocId::CreateValid(0, kTime0, kTime0, 0).IsValid());
- EXPECT_TRUE(FlocId::CreateValid(0, kTime1, kTime2, 1).IsValid());
-}
-
-TEST_F(FlocIdUnitTest, Comparison) {
- EXPECT_EQ(FlocId::CreateInvalid(FlocId::Status::kInvalidWaitingToStart),
- FlocId::CreateInvalid(FlocId::Status::kInvalidWaitingToStart));
-
- EXPECT_NE(FlocId::CreateInvalid(FlocId::Status::kInvalidWaitingToStart),
- FlocId::CreateInvalid(FlocId::Status::kInvalidBlocked));
-
- EXPECT_EQ(FlocId::CreateValid(0, kTime0, kTime0, 0),
- FlocId::CreateValid(0, kTime0, kTime0, 0));
- EXPECT_EQ(FlocId::CreateValid(0, kTime1, kTime1, 1),
- FlocId::CreateValid(0, kTime1, kTime1, 1));
- EXPECT_EQ(FlocId::CreateValid(0, kTime1, kTime2, 1),
- FlocId::CreateValid(0, kTime1, kTime2, 1));
-
- EXPECT_NE(FlocId::CreateInvalid(FlocId::Status::kInvalidWaitingToStart),
- FlocId::CreateValid(0, kTime0, kTime0, 0));
- EXPECT_NE(FlocId::CreateValid(0, kTime0, kTime0, 0),
- FlocId::CreateValid(1, kTime0, kTime0, 0));
- EXPECT_NE(FlocId::CreateValid(0, kTime0, kTime1, 0),
- FlocId::CreateValid(0, kTime1, kTime1, 0));
- EXPECT_NE(FlocId::CreateValid(0, kTime0, kTime0, 0),
- FlocId::CreateValid(0, kTime0, kTime0, 1));
-}
-
-TEST_F(FlocIdUnitTest, ToInterestCohortForJsApi) {
- EXPECT_EQ(
- InterestCohortResult("0", "chrome.1.0"),
- FlocId::CreateValid(0, kTime0, kTime0, 0).ToInterestCohortForJsApi());
- EXPECT_EQ(
- InterestCohortResult("12345", "chrome.1.0"),
- FlocId::CreateValid(12345, kTime0, kTime0, 0).ToInterestCohortForJsApi());
- EXPECT_EQ(
- InterestCohortResult("12345", "chrome.1.2"),
- FlocId::CreateValid(12345, kTime1, kTime1, 2).ToInterestCohortForJsApi());
-
- base::test::ScopedFeatureList feature_list;
- feature_list.InitAndEnableFeatureWithParameters(
- kFederatedLearningOfCohorts, {{"finch_config_version", "99"}});
-
- EXPECT_EQ(
- InterestCohortResult("0", "chrome.99.0"),
- FlocId::CreateValid(0, kTime0, kTime0, 0).ToInterestCohortForJsApi());
- EXPECT_EQ(
- InterestCohortResult("12345", "chrome.99.0"),
- FlocId::CreateValid(12345, kTime0, kTime0, 0).ToInterestCohortForJsApi());
- EXPECT_EQ(
- InterestCohortResult("12345", "chrome.99.2"),
- FlocId::CreateValid(12345, kTime1, kTime1, 2).ToInterestCohortForJsApi());
-}
-
-TEST_F(FlocIdUnitTest, ReadFromPrefs_DefaultInvalid) {
- TestingPrefServiceSimple prefs;
- FlocId::RegisterPrefs(prefs.registry());
-
- FlocId floc_id = FlocId::ReadFromPrefs(&prefs);
-
- EXPECT_FALSE(floc_id.IsValid());
- EXPECT_EQ(FlocId::Status::kInvalidNoStatusPrefs, floc_id.status());
- EXPECT_TRUE(floc_id.history_begin_time().is_null());
- EXPECT_TRUE(floc_id.history_end_time().is_null());
- EXPECT_EQ(0u, floc_id.finch_config_version());
- EXPECT_EQ(0u, floc_id.sorting_lsh_version());
- EXPECT_TRUE(floc_id.compute_time().is_null());
-}
-
-TEST_F(FlocIdUnitTest, ReadFromPrefs_SavedInvalidNoIdPrefs_NoStatusPref) {
- TestingPrefServiceSimple prefs;
- FlocId::RegisterPrefs(prefs.registry());
-
- prefs.SetTime(kFlocIdHistoryBeginTimePrefKey, base::Time::FromTimeT(1));
- prefs.SetTime(kFlocIdHistoryEndTimePrefKey, base::Time::FromTimeT(2));
- prefs.SetUint64(kFlocIdFinchConfigVersionPrefKey, 3);
- prefs.SetUint64(kFlocIdSortingLshVersionPrefKey, 4);
- prefs.SetTime(kFlocIdComputeTimePrefKey, base::Time::FromTimeT(5));
-
- FlocId floc_id = FlocId::ReadFromPrefs(&prefs);
- EXPECT_FALSE(floc_id.IsValid());
- EXPECT_EQ(FlocId::Status::kInvalidNoStatusPrefs, floc_id.status());
- EXPECT_EQ(base::Time::FromTimeT(1), floc_id.history_begin_time());
- EXPECT_EQ(base::Time::FromTimeT(2), floc_id.history_end_time());
- EXPECT_EQ(3u, floc_id.finch_config_version());
- EXPECT_EQ(4u, floc_id.sorting_lsh_version());
- EXPECT_EQ(base::Time::FromTimeT(5), floc_id.compute_time());
-}
-
-TEST_F(FlocIdUnitTest, ReadFromPrefs_SavedValid_NoStatusPref) {
- TestingPrefServiceSimple prefs;
- FlocId::RegisterPrefs(prefs.registry());
-
- prefs.SetUint64(kFlocIdValuePrefKey, 123);
- prefs.SetTime(kFlocIdHistoryBeginTimePrefKey, base::Time::FromTimeT(1));
- prefs.SetTime(kFlocIdHistoryEndTimePrefKey, base::Time::FromTimeT(2));
- prefs.SetUint64(kFlocIdFinchConfigVersionPrefKey, 3);
- prefs.SetUint64(kFlocIdSortingLshVersionPrefKey, 4);
- prefs.SetTime(kFlocIdComputeTimePrefKey, base::Time::FromTimeT(5));
-
- FlocId floc_id = FlocId::ReadFromPrefs(&prefs);
- EXPECT_TRUE(floc_id.IsValid());
- EXPECT_EQ(FlocId::Status::kValid, floc_id.status());
- EXPECT_EQ(base::Time::FromTimeT(1), floc_id.history_begin_time());
- EXPECT_EQ(base::Time::FromTimeT(2), floc_id.history_end_time());
- EXPECT_EQ(3u, floc_id.finch_config_version());
- EXPECT_EQ(4u, floc_id.sorting_lsh_version());
- EXPECT_EQ(base::Time::FromTimeT(5), floc_id.compute_time());
- EXPECT_EQ(InterestCohortResult("123", "chrome.3.4"),
- floc_id.ToInterestCohortForJsApi());
-}
-
-TEST_F(FlocIdUnitTest, ReadFromPrefs_SavedInvalid) {
- TestingPrefServiceSimple prefs;
- FlocId::RegisterPrefs(prefs.registry());
-
- prefs.SetUint64(kFlocIdValuePrefKey, 0);
- prefs.SetInteger(
- kFlocIdStatusPrefKey,
- static_cast<int>(FlocId::Status::kInvalidDisallowedByUserSettings));
- prefs.SetTime(kFlocIdHistoryBeginTimePrefKey, base::Time::FromTimeT(1));
- prefs.SetTime(kFlocIdHistoryEndTimePrefKey, base::Time::FromTimeT(2));
- prefs.SetUint64(kFlocIdFinchConfigVersionPrefKey, 3);
- prefs.SetUint64(kFlocIdSortingLshVersionPrefKey, 4);
- prefs.SetTime(kFlocIdComputeTimePrefKey, base::Time::FromTimeT(5));
-
- FlocId floc_id = FlocId::ReadFromPrefs(&prefs);
- EXPECT_FALSE(floc_id.IsValid());
- EXPECT_EQ(FlocId::Status::kInvalidDisallowedByUserSettings, floc_id.status());
- EXPECT_EQ(base::Time::FromTimeT(1), floc_id.history_begin_time());
- EXPECT_EQ(base::Time::FromTimeT(2), floc_id.history_end_time());
- EXPECT_EQ(3u, floc_id.finch_config_version());
- EXPECT_EQ(4u, floc_id.sorting_lsh_version());
- EXPECT_EQ(base::Time::FromTimeT(5), floc_id.compute_time());
-}
-
-TEST_F(FlocIdUnitTest, ReadFromPrefs_SavedValid) {
- TestingPrefServiceSimple prefs;
- FlocId::RegisterPrefs(prefs.registry());
-
- prefs.SetUint64(kFlocIdValuePrefKey, 123);
- prefs.SetInteger(kFlocIdStatusPrefKey,
- static_cast<int>(FlocId::Status::kValid));
- prefs.SetTime(kFlocIdHistoryBeginTimePrefKey, base::Time::FromTimeT(1));
- prefs.SetTime(kFlocIdHistoryEndTimePrefKey, base::Time::FromTimeT(2));
- prefs.SetUint64(kFlocIdFinchConfigVersionPrefKey, 3);
- prefs.SetUint64(kFlocIdSortingLshVersionPrefKey, 4);
- prefs.SetTime(kFlocIdComputeTimePrefKey, base::Time::FromTimeT(5));
-
- FlocId floc_id = FlocId::ReadFromPrefs(&prefs);
- EXPECT_TRUE(floc_id.IsValid());
- EXPECT_EQ(FlocId::Status::kValid, floc_id.status());
- EXPECT_EQ(base::Time::FromTimeT(1), floc_id.history_begin_time());
- EXPECT_EQ(base::Time::FromTimeT(2), floc_id.history_end_time());
- EXPECT_EQ(3u, floc_id.finch_config_version());
- EXPECT_EQ(4u, floc_id.sorting_lsh_version());
- EXPECT_EQ(base::Time::FromTimeT(5), floc_id.compute_time());
- EXPECT_EQ(InterestCohortResult("123", "chrome.3.4"),
- floc_id.ToInterestCohortForJsApi());
-}
-
-TEST_F(FlocIdUnitTest, SaveToPrefs_InvalidFloc) {
- TestingPrefServiceSimple prefs;
- FlocId::RegisterPrefs(prefs.registry());
-
- FlocId floc_id =
- FlocId::CreateInvalid(FlocId::Status::kInvalidWaitingToStart);
- floc_id.SaveToPrefs(&prefs);
-
- EXPECT_TRUE(prefs.HasPrefPath(kFlocIdValuePrefKey));
- EXPECT_TRUE(prefs.HasPrefPath(kFlocIdStatusPrefKey));
- EXPECT_TRUE(prefs.HasPrefPath(kFlocIdHistoryBeginTimePrefKey));
- EXPECT_TRUE(prefs.HasPrefPath(kFlocIdHistoryEndTimePrefKey));
- EXPECT_TRUE(prefs.HasPrefPath(kFlocIdFinchConfigVersionPrefKey));
- EXPECT_TRUE(prefs.HasPrefPath(kFlocIdSortingLshVersionPrefKey));
- EXPECT_TRUE(prefs.HasPrefPath(kFlocIdComputeTimePrefKey));
-
- EXPECT_EQ(0u, prefs.GetUint64(kFlocIdValuePrefKey));
- EXPECT_EQ(
- FlocId::Status::kInvalidWaitingToStart,
- static_cast<FlocId::Status>(prefs.GetInteger(kFlocIdStatusPrefKey)));
- EXPECT_TRUE(prefs.GetTime(kFlocIdHistoryBeginTimePrefKey).is_null());
- EXPECT_TRUE(prefs.GetTime(kFlocIdHistoryEndTimePrefKey).is_null());
- EXPECT_EQ(1u, prefs.GetUint64(kFlocIdFinchConfigVersionPrefKey));
- EXPECT_EQ(0u, prefs.GetUint64(kFlocIdSortingLshVersionPrefKey));
- EXPECT_EQ(base::Time::Now(), prefs.GetTime(kFlocIdComputeTimePrefKey));
-}
-
-TEST_F(FlocIdUnitTest, SaveToPrefs_ValidFloc) {
- TestingPrefServiceSimple prefs;
- FlocId::RegisterPrefs(prefs.registry());
-
- FlocId floc_id = FlocId::CreateValid(123, base::Time::FromTimeT(1),
- base::Time::FromTimeT(2), 3);
- floc_id.SaveToPrefs(&prefs);
-
- EXPECT_TRUE(prefs.HasPrefPath(kFlocIdValuePrefKey));
- EXPECT_TRUE(prefs.HasPrefPath(kFlocIdStatusPrefKey));
- EXPECT_TRUE(prefs.HasPrefPath(kFlocIdHistoryBeginTimePrefKey));
- EXPECT_TRUE(prefs.HasPrefPath(kFlocIdHistoryEndTimePrefKey));
- EXPECT_TRUE(prefs.HasPrefPath(kFlocIdFinchConfigVersionPrefKey));
- EXPECT_TRUE(prefs.HasPrefPath(kFlocIdSortingLshVersionPrefKey));
- EXPECT_TRUE(prefs.HasPrefPath(kFlocIdComputeTimePrefKey));
-
- EXPECT_EQ(123u, prefs.GetUint64(kFlocIdValuePrefKey));
- EXPECT_EQ(
- FlocId::Status::kValid,
- static_cast<FlocId::Status>(prefs.GetInteger(kFlocIdStatusPrefKey)));
- EXPECT_EQ(base::Time::FromTimeT(1),
- prefs.GetTime(kFlocIdHistoryBeginTimePrefKey));
- EXPECT_EQ(base::Time::FromTimeT(2),
- prefs.GetTime(kFlocIdHistoryEndTimePrefKey));
- EXPECT_EQ(1u, prefs.GetUint64(kFlocIdFinchConfigVersionPrefKey));
- EXPECT_EQ(3u, prefs.GetUint64(kFlocIdSortingLshVersionPrefKey));
- EXPECT_EQ(base::Time::Now(), prefs.GetTime(kFlocIdComputeTimePrefKey));
-}
-
-TEST_F(FlocIdUnitTest, UpdateStatusAndSaveToPrefs) {
- TestingPrefServiceSimple prefs;
- FlocId::RegisterPrefs(prefs.registry());
-
- FlocId floc_id = FlocId::CreateValid(123, base::Time::FromTimeT(1),
- base::Time::FromTimeT(2), 3);
- floc_id.SaveToPrefs(&prefs);
-
- floc_id.UpdateStatusAndSaveToPrefs(&prefs,
- FlocId::Status::kInvalidHistoryDeleted);
- EXPECT_FALSE(floc_id.IsValid());
- EXPECT_EQ(FlocId::Status::kInvalidHistoryDeleted, floc_id.status());
-
- EXPECT_EQ(123u, prefs.GetUint64(kFlocIdValuePrefKey));
- EXPECT_EQ(
- FlocId::Status::kInvalidHistoryDeleted,
- static_cast<FlocId::Status>(prefs.GetInteger(kFlocIdStatusPrefKey)));
- EXPECT_EQ(base::Time::FromTimeT(1),
- prefs.GetTime(kFlocIdHistoryBeginTimePrefKey));
- EXPECT_EQ(base::Time::FromTimeT(2),
- prefs.GetTime(kFlocIdHistoryEndTimePrefKey));
- EXPECT_EQ(1u, prefs.GetUint64(kFlocIdFinchConfigVersionPrefKey));
- EXPECT_EQ(3u, prefs.GetUint64(kFlocIdSortingLshVersionPrefKey));
- EXPECT_EQ(base::Time::Now(), prefs.GetTime(kFlocIdComputeTimePrefKey));
-}
-
-TEST_F(FlocIdUnitTest, ResetComputeTimeAndSaveToPrefs) {
- TestingPrefServiceSimple prefs;
- FlocId::RegisterPrefs(prefs.registry());
-
- FlocId floc_id = FlocId::CreateValid(123, base::Time::FromTimeT(1),
- base::Time::FromTimeT(2), 3);
- floc_id.SaveToPrefs(&prefs);
- EXPECT_EQ(base::Time::Now(), prefs.GetTime(kFlocIdComputeTimePrefKey));
-
- floc_id.ResetComputeTimeAndSaveToPrefs(base::Time::FromTimeT(4), &prefs);
- EXPECT_EQ(base::Time::FromTimeT(4), prefs.GetTime(kFlocIdComputeTimePrefKey));
-}
-
-} // namespace federated_learning
diff --git a/chromium/components/federated_learning/floc_sorting_lsh_clusters_service.cc b/chromium/components/federated_learning/floc_sorting_lsh_clusters_service.cc
deleted file mode 100644
index f179581d554..00000000000
--- a/chromium/components/federated_learning/floc_sorting_lsh_clusters_service.cc
+++ /dev/null
@@ -1,180 +0,0 @@
-// Copyright 2020 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.
-
-#include "components/federated_learning/floc_sorting_lsh_clusters_service.h"
-
-#include <utility>
-
-#include "base/files/file.h"
-#include "base/files/file_util.h"
-#include "base/task/post_task.h"
-#include "base/task/task_runner_util.h"
-#include "base/task/thread_pool.h"
-#include "components/federated_learning/floc_constants.h"
-#include "third_party/protobuf/src/google/protobuf/io/coded_stream.h"
-#include "third_party/protobuf/src/google/protobuf/io/zero_copy_stream_impl_lite.h"
-
-namespace federated_learning {
-
-namespace {
-
-class CopyingFileInputStream : public google::protobuf::io::CopyingInputStream {
- public:
- explicit CopyingFileInputStream(base::File file) : file_(std::move(file)) {}
-
- CopyingFileInputStream(const CopyingFileInputStream&) = delete;
- CopyingFileInputStream& operator=(const CopyingFileInputStream&) = delete;
-
- ~CopyingFileInputStream() override = default;
-
- // google::protobuf::io::CopyingInputStream:
- int Read(void* buffer, int size) override {
- return file_.ReadAtCurrentPosNoBestEffort(static_cast<char*>(buffer), size);
- }
-
- private:
- base::File file_;
-};
-
-absl::optional<uint64_t> ApplySortingLshOnBackgroundThread(
- uint64_t sim_hash,
- const base::FilePath& file_path) {
- base::File sorting_lsh_clusters_file(
- file_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
- if (!sorting_lsh_clusters_file.IsValid())
- return absl::nullopt;
-
- CopyingFileInputStream copying_stream(std::move(sorting_lsh_clusters_file));
- google::protobuf::io::CopyingInputStreamAdaptor zero_copy_stream_adaptor(
- &copying_stream);
-
- google::protobuf::io::CodedInputStream input_stream(
- &zero_copy_stream_adaptor);
-
- // The file should contain a list of integers. The 7th-order bit represents
- // whether the cohort should be blocked. The number represented by the 1st-6th
- // bits should be within the range [0, MaxNumberOfBitsInFloc]. Suppose the
- // list is l, then S(i) = 2^(l[i] & 0b111111) represents the the number of
- // hashes that can be associated with this floc id. The cumulative sum of S(i)
- // represents the boundary sim_hash values. We will use the higher index to
- // encode |sim_hash|, i.e. if sim_hash is within range
- // [CumSum(S(i-1)), CumSum(S(i))), |i| will be output floc.
- //
- // 0 is always an implicit CumSum boundary, i.e. if
- // 0 <= |sim_hash| < 2^(l[0]), then the index 0 will be the output floc.
- //
- // However, if the is_blocked bit (i.e. l[i] & 0b1000000) indicates that the
- // cohort should be blocked, we will output an invalid floc id.
-
- // Input sanitization: As we compute on the fly, we will check to make sure
- // each encountered entry, after dropping the is_blocked bit, is within
- // [0, MaxNumberOfBitsInFloc]. Besides, the cumulative sum should be no
- // greater than 2^MaxNumberOfBitsInFloc at any given time. If we cannot find
- // an index i, it means the the final cumulative sum is less than
- // 2^MaxNumberOfBitsInFloc, while we expect it to be exactly
- // 2^MaxNumberOfBitsInFloc, and we should also fail in this case. When some
- // check fails, we will also output an invalid floc id.
- //
- // A stricter sanitization would be to always stream all numbers and check
- // properties. We skip doing this to save some computation cost.
- const uint64_t kExpectedFinalCumulativeSum = (1ULL << kMaxNumberOfBitsInFloc);
- DCHECK_LT(sim_hash, kExpectedFinalCumulativeSum);
-
- uint64_t cumulative_sum = 0;
- uint32_t next_combined;
-
- // TODO(yaoxia): Add metrics for when the file has unexpected format.
-
- for (uint64_t index = 0; input_stream.ReadVarint32(&next_combined); ++index) {
- // Sanitizing error: the entry used more than |kSortingLshMaxBits| bits.
- if ((next_combined >> kSortingLshMaxBits) > 0)
- return absl::nullopt;
-
- bool is_blocked = next_combined & kSortingLshBlockedMask;
- uint32_t next = next_combined & kSortingLshSizeMask;
-
- // Sanitizing error
- if (next > kMaxNumberOfBitsInFloc)
- return absl::nullopt;
-
- cumulative_sum += (1ULL << next);
-
- // Sanitizing error
- if (cumulative_sum > kExpectedFinalCumulativeSum)
- return absl::nullopt;
-
- // Found the sim-hash upper bound. Use the index as the new floc.
- if (cumulative_sum > sim_hash) {
- if (is_blocked)
- return absl::nullopt;
-
- return index;
- }
- }
-
- // Sanitizing error: we didn't find a sim-hash upper bound, but we expect to
- // always find it after finish iterating through the list.
- return absl::nullopt;
-}
-
-} // namespace
-
-FlocSortingLshClustersService::FlocSortingLshClustersService()
- : background_task_runner_(base::ThreadPool::CreateSequencedTaskRunner(
- {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
- base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})),
- weak_ptr_factory_(this) {}
-
-FlocSortingLshClustersService::~FlocSortingLshClustersService() = default;
-
-void FlocSortingLshClustersService::AddObserver(Observer* observer) {
- observers_.AddObserver(observer);
-}
-
-void FlocSortingLshClustersService::RemoveObserver(Observer* observer) {
- observers_.RemoveObserver(observer);
-}
-
-bool FlocSortingLshClustersService::IsSortingLshClustersFileReady() const {
- return first_file_ready_seen_;
-}
-
-void FlocSortingLshClustersService::OnSortingLshClustersFileReady(
- const base::FilePath& file_path,
- const base::Version& version) {
- sorting_lsh_clusters_file_path_ = file_path;
- sorting_lsh_clusters_version_ = version;
- first_file_ready_seen_ = true;
-
- for (auto& observer : observers_)
- observer.OnSortingLshClustersFileReady();
-}
-
-void FlocSortingLshClustersService::ApplySortingLsh(
- uint64_t sim_hash,
- ApplySortingLshCallback callback) {
- DCHECK(first_file_ready_seen_);
-
- base::PostTaskAndReplyWithResult(
- background_task_runner_.get(), FROM_HERE,
- base::BindOnce(&ApplySortingLshOnBackgroundThread, sim_hash,
- sorting_lsh_clusters_file_path_),
- base::BindOnce(&FlocSortingLshClustersService::DidApplySortingLsh,
- weak_ptr_factory_.GetWeakPtr(), std::move(callback),
- sorting_lsh_clusters_version_));
-}
-
-void FlocSortingLshClustersService::SetBackgroundTaskRunnerForTesting(
- scoped_refptr<base::SequencedTaskRunner> background_task_runner) {
- background_task_runner_ = background_task_runner;
-}
-
-void FlocSortingLshClustersService::DidApplySortingLsh(
- ApplySortingLshCallback callback,
- base::Version version,
- absl::optional<uint64_t> final_hash) {
- std::move(callback).Run(std::move(final_hash), std::move(version));
-}
-
-} // namespace federated_learning
diff --git a/chromium/components/federated_learning/floc_sorting_lsh_clusters_service.h b/chromium/components/federated_learning/floc_sorting_lsh_clusters_service.h
deleted file mode 100644
index 443b77c2c32..00000000000
--- a/chromium/components/federated_learning/floc_sorting_lsh_clusters_service.h
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright 2020 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.
-
-#ifndef COMPONENTS_FEDERATED_LEARNING_FLOC_SORTING_LSH_CLUSTERS_SERVICE_H_
-#define COMPONENTS_FEDERATED_LEARNING_FLOC_SORTING_LSH_CLUSTERS_SERVICE_H_
-
-#include <stdint.h>
-
-#include "base/callback.h"
-#include "base/files/file_path.h"
-#include "base/memory/scoped_refptr.h"
-#include "base/memory/weak_ptr.h"
-#include "base/observer_list.h"
-#include "base/version.h"
-#include "components/federated_learning/floc_id.h"
-#include "third_party/abseil-cpp/absl/types/optional.h"
-
-namespace base {
-class FilePath;
-class SequencedTaskRunner;
-} // namespace base
-
-namespace federated_learning {
-
-// Responsible for loading the sorting-lsh clusters with custom encoding and
-// and calculating the sorting-lsh based floc.
-//
-// File reading and parsing is posted to |background_task_runner_|.
-class FlocSortingLshClustersService {
- public:
- using ApplySortingLshCallback =
- base::OnceCallback<void(absl::optional<uint64_t>, base::Version)>;
-
- class Observer {
- public:
- virtual void OnSortingLshClustersFileReady() = 0;
- };
-
- FlocSortingLshClustersService();
- virtual ~FlocSortingLshClustersService();
-
- FlocSortingLshClustersService(const FlocSortingLshClustersService&) = delete;
- FlocSortingLshClustersService& operator=(
- const FlocSortingLshClustersService&) = delete;
-
- // Adds/Removes an Observer.
- void AddObserver(Observer* observer);
- void RemoveObserver(Observer* observer);
-
- bool IsSortingLshClustersFileReady() const;
-
- // Virtual for testing.
- virtual void OnSortingLshClustersFileReady(const base::FilePath& file_path,
- const base::Version& version);
-
- // Virtual for testing.
- virtual void ApplySortingLsh(uint64_t sim_hash,
- ApplySortingLshCallback callback);
-
- void SetBackgroundTaskRunnerForTesting(
- scoped_refptr<base::SequencedTaskRunner> background_task_runner);
-
- private:
- friend class FlocSortingLshClustersServiceTest;
-
- void DidApplySortingLsh(ApplySortingLshCallback callback,
- base::Version version,
- absl::optional<uint64_t> final_hash);
-
- // Runner for tasks that do not influence user experience.
- scoped_refptr<base::SequencedTaskRunner> background_task_runner_;
-
- base::ObserverList<Observer>::Unchecked observers_;
-
- bool first_file_ready_seen_ = false;
- base::FilePath sorting_lsh_clusters_file_path_;
- base::Version sorting_lsh_clusters_version_;
-
- base::WeakPtrFactory<FlocSortingLshClustersService> weak_ptr_factory_;
-};
-
-} // namespace federated_learning
-
-#endif // COMPONENTS_FEDERATED_LEARNING_FLOC_SORTING_LSH_CLUSTERS_SERVICE_H_
diff --git a/chromium/components/federated_learning/floc_sorting_lsh_clusters_service_unittest.cc b/chromium/components/federated_learning/floc_sorting_lsh_clusters_service_unittest.cc
deleted file mode 100644
index 9e9de368649..00000000000
--- a/chromium/components/federated_learning/floc_sorting_lsh_clusters_service_unittest.cc
+++ /dev/null
@@ -1,284 +0,0 @@
-// Copyright 2020 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.
-
-#include "components/federated_learning/floc_sorting_lsh_clusters_service.h"
-
-#include <string>
-#include <vector>
-
-#include "base/files/file_util.h"
-#include "base/files/scoped_temp_dir.h"
-#include "base/run_loop.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/test/bind.h"
-#include "base/test/task_environment.h"
-#include "base/test/test_simple_task_runner.h"
-#include "components/federated_learning/floc_constants.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/protobuf/src/google/protobuf/io/coded_stream.h"
-#include "third_party/protobuf/src/google/protobuf/io/zero_copy_stream_impl_lite.h"
-
-namespace federated_learning {
-
-namespace {
-
-const uint64_t kMaxSimHash = (1ULL << kMaxNumberOfBitsInFloc) - 1;
-
-class CopyingFileOutputStream
- : public google::protobuf::io::CopyingOutputStream {
- public:
- explicit CopyingFileOutputStream(base::File file) : file_(std::move(file)) {}
-
- CopyingFileOutputStream(const CopyingFileOutputStream&) = delete;
- CopyingFileOutputStream& operator=(const CopyingFileOutputStream&) = delete;
-
- ~CopyingFileOutputStream() override = default;
-
- // google::protobuf::io::CopyingOutputStream:
- bool Write(const void* buffer, int size) override {
- return file_.WriteAtCurrentPos(static_cast<const char*>(buffer), size) ==
- size;
- }
-
- private:
- base::File file_;
-};
-
-struct ApplySortingLshResult {
- absl::optional<uint64_t> final_hash;
- base::Version version;
-};
-
-} // namespace
-
-class FlocSortingLshClustersServiceTest : public ::testing::Test {
- public:
- FlocSortingLshClustersServiceTest()
- : background_task_runner_(
- base::MakeRefCounted<base::TestSimpleTaskRunner>()) {}
-
- FlocSortingLshClustersServiceTest(const FlocSortingLshClustersServiceTest&) =
- delete;
- FlocSortingLshClustersServiceTest& operator=(
- const FlocSortingLshClustersServiceTest&) = delete;
-
- protected:
- void SetUp() override {
- service_ = std::make_unique<FlocSortingLshClustersService>();
- service_->SetBackgroundTaskRunnerForTesting(background_task_runner_);
- }
-
- base::FilePath GetUniqueTemporaryPath() {
- CHECK(scoped_temp_dir_.IsValid() || scoped_temp_dir_.CreateUniqueTempDir());
- return scoped_temp_dir_.GetPath().AppendASCII(
- base::NumberToString(next_unique_file_suffix_++));
- }
-
- base::FilePath CreateTestSortingLshClustersFile(
- const std::vector<std::pair<uint32_t, bool>>& sorting_lsh_clusters) {
- base::FilePath file_path = GetUniqueTemporaryPath();
- base::File file(file_path, base::File::FLAG_CREATE | base::File::FLAG_READ |
- base::File::FLAG_WRITE);
- CHECK(file.IsValid());
-
- CopyingFileOutputStream copying_stream(std::move(file));
- google::protobuf::io::CopyingOutputStreamAdaptor zero_copy_stream_adaptor(
- &copying_stream);
-
- google::protobuf::io::CodedOutputStream output_stream(
- &zero_copy_stream_adaptor);
-
- for (const auto& p : sorting_lsh_clusters) {
- uint32_t next = p.first;
- bool is_blocked = p.second;
- if (is_blocked) {
- next |= kSortingLshBlockedMask;
- }
- output_stream.WriteVarint32(next);
- }
-
- CHECK(!output_stream.HadError());
-
- return file_path;
- }
-
- base::FilePath InitializeSortingLshClustersFile(
- const std::vector<std::pair<uint32_t, bool>>& sorting_lsh_clusters,
- const base::Version& version) {
- base::FilePath file_path =
- CreateTestSortingLshClustersFile(sorting_lsh_clusters);
- service()->OnSortingLshClustersFileReady(file_path, version);
- EXPECT_TRUE(sorting_lsh_clusters_file_path().has_value());
- return file_path;
- }
-
- FlocSortingLshClustersService* service() { return service_.get(); }
-
- absl::optional<base::FilePath> sorting_lsh_clusters_file_path() {
- if (!service()->first_file_ready_seen_)
- return absl::nullopt;
-
- return service()->sorting_lsh_clusters_file_path_;
- }
-
- ApplySortingLshResult ApplySortingLsh(uint64_t sim_hash) {
- ApplySortingLshResult result;
-
- base::RunLoop run_loop;
- auto cb = base::BindLambdaForTesting(
- [&](absl::optional<uint64_t> final_hash, base::Version version) {
- result.final_hash = final_hash;
- result.version = version;
- run_loop.Quit();
- });
-
- service()->ApplySortingLsh(sim_hash, std::move(cb));
- background_task_runner_->RunPendingTasks();
- run_loop.Run();
-
- return result;
- }
-
- protected:
- base::test::TaskEnvironment task_environment_;
- base::ScopedTempDir scoped_temp_dir_;
- int next_unique_file_suffix_ = 1;
-
- scoped_refptr<base::TestSimpleTaskRunner> background_task_runner_;
-
- std::unique_ptr<FlocSortingLshClustersService> service_;
-};
-
-TEST_F(FlocSortingLshClustersServiceTest, NoFilePath) {
- EXPECT_FALSE(sorting_lsh_clusters_file_path().has_value());
-}
-
-TEST_F(FlocSortingLshClustersServiceTest, EmptyList) {
- InitializeSortingLshClustersFile({}, base::Version("2.3.4"));
-
- EXPECT_EQ(absl::nullopt, ApplySortingLsh(0).final_hash);
- EXPECT_EQ(absl::nullopt, ApplySortingLsh(1).final_hash);
- EXPECT_EQ(absl::nullopt, ApplySortingLsh(kMaxSimHash).final_hash);
-}
-
-TEST_F(FlocSortingLshClustersServiceTest, List_0) {
- InitializeSortingLshClustersFile({{0, false}}, base::Version("2.3.4"));
-
- EXPECT_EQ(0u, ApplySortingLsh(0).final_hash.value());
- EXPECT_EQ(base::Version("2.3.4"), ApplySortingLsh(0).version);
- EXPECT_EQ(absl::nullopt, ApplySortingLsh(1).final_hash);
- EXPECT_EQ(absl::nullopt, ApplySortingLsh(kMaxSimHash).final_hash);
-}
-
-TEST_F(FlocSortingLshClustersServiceTest, List_0_Blocked) {
- InitializeSortingLshClustersFile({{0, true}}, base::Version("2.3.4"));
-
- EXPECT_EQ(absl::nullopt, ApplySortingLsh(0).final_hash);
- EXPECT_EQ(absl::nullopt, ApplySortingLsh(1).final_hash);
- EXPECT_EQ(absl::nullopt, ApplySortingLsh(kMaxSimHash).final_hash);
-}
-
-TEST_F(FlocSortingLshClustersServiceTest, List_UnexpectedNumber) {
- InitializeSortingLshClustersFile({{1 << 8, false}}, base::Version("2.3.4"));
-
- EXPECT_EQ(absl::nullopt, ApplySortingLsh(0).final_hash);
- EXPECT_EQ(absl::nullopt, ApplySortingLsh(1).final_hash);
- EXPECT_EQ(absl::nullopt, ApplySortingLsh(kMaxSimHash).final_hash);
-}
-
-TEST_F(FlocSortingLshClustersServiceTest, List_1) {
- InitializeSortingLshClustersFile({{1, false}}, base::Version("2.3.4"));
-
- EXPECT_EQ(0u, ApplySortingLsh(0).final_hash.value());
- EXPECT_EQ(0u, ApplySortingLsh(1).final_hash.value());
- EXPECT_EQ(absl::nullopt, ApplySortingLsh(2).final_hash);
- EXPECT_EQ(absl::nullopt, ApplySortingLsh(kMaxSimHash).final_hash);
-}
-
-TEST_F(FlocSortingLshClustersServiceTest, List_0_0) {
- InitializeSortingLshClustersFile({{0, false}, {0, false}},
- base::Version("2.3.4"));
-
- EXPECT_EQ(0u, ApplySortingLsh(0).final_hash.value());
- EXPECT_EQ(1u, ApplySortingLsh(1).final_hash.value());
- EXPECT_EQ(absl::nullopt, ApplySortingLsh(2).final_hash);
- EXPECT_EQ(absl::nullopt, ApplySortingLsh(kMaxSimHash).final_hash);
-}
-
-TEST_F(FlocSortingLshClustersServiceTest, List_0_1) {
- InitializeSortingLshClustersFile({{0, false}, {1, false}},
- base::Version("2.3.4"));
-
- EXPECT_EQ(0u, ApplySortingLsh(0).final_hash.value());
- EXPECT_EQ(1u, ApplySortingLsh(1).final_hash.value());
- EXPECT_EQ(1u, ApplySortingLsh(2).final_hash.value());
- EXPECT_EQ(absl::nullopt, ApplySortingLsh(3).final_hash);
- EXPECT_EQ(absl::nullopt, ApplySortingLsh(kMaxSimHash).final_hash);
-}
-
-TEST_F(FlocSortingLshClustersServiceTest, List_1_0) {
- InitializeSortingLshClustersFile({{1, false}, {0, false}},
- base::Version("2.3.4"));
-
- EXPECT_EQ(0u, ApplySortingLsh(0).final_hash.value());
- EXPECT_EQ(0u, ApplySortingLsh(1).final_hash.value());
- EXPECT_EQ(1u, ApplySortingLsh(2).final_hash.value());
- EXPECT_EQ(absl::nullopt, ApplySortingLsh(3).final_hash);
- EXPECT_EQ(absl::nullopt, ApplySortingLsh(kMaxSimHash).final_hash);
-}
-
-TEST_F(FlocSortingLshClustersServiceTest, List_SingleCluster) {
- InitializeSortingLshClustersFile({{kMaxNumberOfBitsInFloc, false}},
- base::Version("2.3.4"));
-
- EXPECT_EQ(0u, ApplySortingLsh(0).final_hash.value());
- EXPECT_EQ(0u, ApplySortingLsh(1).final_hash.value());
- EXPECT_EQ(0u, ApplySortingLsh(12345).final_hash.value());
- EXPECT_EQ(0u, ApplySortingLsh(kMaxSimHash).final_hash.value());
-}
-
-TEST_F(FlocSortingLshClustersServiceTest, List_TwoClustersEqualSize) {
- InitializeSortingLshClustersFile({{kMaxNumberOfBitsInFloc - 1, false},
- {kMaxNumberOfBitsInFloc - 1, false}},
- base::Version("2.3.4"));
-
- uint64_t middle_value = (1ULL << (kMaxNumberOfBitsInFloc - 1));
- EXPECT_EQ(0u, ApplySortingLsh(0).final_hash.value());
- EXPECT_EQ(0u, ApplySortingLsh(1).final_hash.value());
- EXPECT_EQ(0u, ApplySortingLsh(middle_value - 1).final_hash.value());
- EXPECT_EQ(1u, ApplySortingLsh(middle_value).final_hash.value());
- EXPECT_EQ(1u, ApplySortingLsh(middle_value + 1).final_hash.value());
- EXPECT_EQ(1u, ApplySortingLsh(kMaxSimHash).final_hash.value());
-}
-
-TEST_F(FlocSortingLshClustersServiceTest,
- FileDeletedAfterSortingLshTaskScheduled) {
- base::FilePath file_path =
- InitializeSortingLshClustersFile({{0, false}}, base::Version("2.3.4"));
-
- base::RunLoop run_loop;
- auto cb = base::BindLambdaForTesting(
- [&](absl::optional<uint64_t> final_hash, base::Version version) {
- // Since the file has been deleted, expect an invalid final_hash.
- EXPECT_EQ(absl::nullopt, final_hash);
- EXPECT_EQ(base::Version("2.3.4"), version);
- run_loop.Quit();
- });
-
- service()->ApplySortingLsh(/*sim_hash=*/0, std::move(cb));
- base::DeleteFile(file_path);
-
- background_task_runner_->RunPendingTasks();
- run_loop.Run();
-}
-
-TEST_F(FlocSortingLshClustersServiceTest, MultipleUpdate_LatestOneUsed) {
- InitializeSortingLshClustersFile({}, base::Version("2.3.4"));
- InitializeSortingLshClustersFile({{0, false}}, base::Version("6.7.8.9"));
-
- EXPECT_EQ(0u, ApplySortingLsh(0).final_hash.value());
- EXPECT_EQ(base::Version("6.7.8.9"), ApplySortingLsh(0).version);
-}
-
-} // namespace federated_learning
diff --git a/chromium/components/federated_learning/sim_hash.cc b/chromium/components/federated_learning/sim_hash.cc
deleted file mode 100644
index 36f0ba51910..00000000000
--- a/chromium/components/federated_learning/sim_hash.cc
+++ /dev/null
@@ -1,91 +0,0 @@
-// Copyright 2020 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.
-
-#include "components/federated_learning/sim_hash.h"
-
-#include "base/hash/legacy_hash.h"
-
-#include <algorithm>
-#include <cmath>
-
-namespace federated_learning {
-
-namespace {
-
-uint64_t g_seed1 = 1ULL;
-uint64_t g_seed2 = 2ULL;
-constexpr double kTwoPi = 2.0 * 3.141592653589793;
-
-// Hashes i and j to create a uniform RV in [0,1].
-double RandomUniform(uint64_t i, uint64_t j, uint64_t seed) {
- uint64_t arr[2] = {i, j};
- uint64_t hashed = base::legacy::CityHash64WithSeed(
- base::as_bytes(
- base::make_span(reinterpret_cast<const char*>(arr), sizeof(arr))),
- seed);
-
- return static_cast<double>(hashed) /
- static_cast<double>(std::numeric_limits<uint64_t>::max());
-}
-
-// Uses the Box-Muller transform to generate a Gaussian from two uniform RVs in
-// [0,1] derived from i and j.
-double RandomGaussian(uint64_t i, uint64_t j) {
- double rv1 = RandomUniform(i, j, g_seed1);
- double rv2 = RandomUniform(j, i, g_seed2);
-
- DCHECK_LE(rv1, 1);
- DCHECK_GE(rv1, 0);
- DCHECK_LE(rv2, 1);
- DCHECK_GE(rv2, 0);
-
- // BoxMuller
- return std::sqrt(-2.0 * std::log(rv1)) * std::cos(kTwoPi * rv2);
-}
-
-} // namespace
-
-void SetSeedsForTesting(uint64_t seed1, uint64_t seed2) {
- g_seed1 = seed1;
- g_seed2 = seed2;
-}
-
-uint64_t SimHashWeightedFeatures(const WeightedFeatures& features,
- uint8_t output_dimensions) {
- DCHECK_LT(0u, output_dimensions);
- DCHECK_LE(output_dimensions, 64u);
-
- uint64_t result = 0;
- for (uint8_t d = 0; d < output_dimensions; ++d) {
- double acc = 0;
-
- for (const auto& feature_weight_pair : features) {
- acc += RandomGaussian(d, feature_weight_pair.first) *
- feature_weight_pair.second;
- }
-
- if (acc > 0)
- result |= (1ULL << d);
- }
-
- return result;
-}
-
-uint64_t SimHashStrings(const std::unordered_set<std::string>& input,
- uint8_t output_dimensions) {
- DCHECK_LT(0u, output_dimensions);
- DCHECK_LE(output_dimensions, 64u);
-
- WeightedFeatures features;
-
- for (const std::string& s : input) {
- FeatureEncoding string_hash =
- base::legacy::CityHash64(base::as_bytes(base::make_span(s)));
- features.emplace(string_hash, FeatureWeight(1));
- }
-
- return SimHashWeightedFeatures(features, output_dimensions);
-}
-
-} // namespace federated_learning
diff --git a/chromium/components/federated_learning/sim_hash.h b/chromium/components/federated_learning/sim_hash.h
deleted file mode 100644
index 1898788710d..00000000000
--- a/chromium/components/federated_learning/sim_hash.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2020 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.
-
-#ifndef COMPONENTS_FEDERATED_LEARNING_SIM_HASH_H_
-#define COMPONENTS_FEDERATED_LEARNING_SIM_HASH_H_
-
-#include <stdint.h>
-#include <map>
-#include <string>
-#include <unordered_set>
-
-namespace federated_learning {
-
-using FeatureEncoding = uint64_t;
-using FeatureWeight = int;
-using WeightedFeatures = std::map<FeatureEncoding, FeatureWeight>;
-
-// Set the two seeds used for generating the random gaussian.
-void SetSeedsForTesting(uint64_t seed1, uint64_t seed2);
-
-// SimHash a set of weighted features to an |output_dimensions| bit number.
-// |output_dimensions| must be greater than 0 and no greater than 64.
-uint64_t SimHashWeightedFeatures(const WeightedFeatures& features,
- uint8_t output_dimensions);
-
-// SimHash a set of strings to an |output_dimensions| bit number.
-// |output_dimensions| must be greater than 0 and no greater than 64.
-uint64_t SimHashStrings(const std::unordered_set<std::string>& input,
- uint8_t output_dimensions);
-
-} // namespace federated_learning
-
-#endif // COMPONENTS_FEDERATED_LEARNING_SIM_HASH_H_
diff --git a/chromium/components/federated_learning/sim_hash_unittest.cc b/chromium/components/federated_learning/sim_hash_unittest.cc
deleted file mode 100644
index 9a99990904a..00000000000
--- a/chromium/components/federated_learning/sim_hash_unittest.cc
+++ /dev/null
@@ -1,228 +0,0 @@
-// Copyright 2020 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.
-
-#include "components/federated_learning/sim_hash.h"
-
-#include <cmath>
-
-#include "base/check_op.h"
-#include "base/hash/legacy_hash.h"
-#include "base/rand_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace federated_learning {
-
-namespace {
-
-// Sparse representation of a 2^64 bit vector. Each number in the set represents
-// the position of a bit that is being set.
-using LargeBitVector = std::set<uint64_t>;
-
-// Roll our own random uint64_t generator as we want deterministic outcome
-// across different test runs.
-uint64_t RandUint64() {
- static uint64_t seed = 0;
- ++seed;
- uint64_t arr[2] = {1234ULL, 4321ULL};
- return base::legacy::CityHash64WithSeed(
- base::as_bytes(
- base::make_span(reinterpret_cast<const char*>(arr), sizeof(arr))),
- seed);
-}
-
-// Inclusive [min, max]
-uint64_t RandUint64InRange(uint64_t min, uint64_t max) {
- DCHECK_LE(min, max);
- if (min == 0ULL && max == std::numeric_limits<uint64_t>::max())
- return RandUint64();
-
- uint64_t range = max - min + 1;
- DCHECK_LE(2ULL, range);
-
- // We must discard random results above this number, as they would
- // make the random generator non-uniform.
- uint64_t max_acceptable_value =
- (std::numeric_limits<uint64_t>::max() / range) * range - 1;
-
- uint64_t rand_value;
- do {
- rand_value = RandUint64();
- } while (rand_value > max_acceptable_value);
-
- uint64_t result = (rand_value % range) + min;
-
- DCHECK_GE(result, min);
- DCHECK_LE(result, max);
- return result;
-}
-
-LargeBitVector RandLargeBitVector(
- size_t number_of_bits_set,
- uint64_t max_bit_position = std::numeric_limits<uint64_t>::max()) {
- LargeBitVector result;
- while (result.size() < number_of_bits_set) {
- result.insert(RandUint64InRange(0ULL, max_bit_position));
- }
- return result;
-}
-
-float DotProduct(const LargeBitVector& v1, const LargeBitVector& v2) {
- float result = 0;
- for (uint64_t pos : v1) {
- if (v2.count(pos))
- result += 1;
- }
- return result;
-}
-
-float Norm(const LargeBitVector& v) {
- return std::sqrt(DotProduct(v, v));
-}
-
-WeightedFeatures ToWeightedFeatures(const LargeBitVector& v) {
- WeightedFeatures result;
- for (FeatureEncoding feature : v) {
- result.emplace(feature, FeatureWeight(1));
- }
- return result;
-}
-
-size_t MultipleSimHashGetNumOutputBitsEqual(size_t repeat_times,
- uint8_t dimensions,
- const WeightedFeatures& f1,
- const WeightedFeatures& f2) {
- uint64_t seed1 = 1;
- uint64_t seed2 = 100000;
-
- uint64_t num_output_bits_equal = 0;
- for (size_t i = 0; i < repeat_times; ++i) {
- SetSeedsForTesting(seed1++, seed2++);
-
- uint64_t o1 = SimHashWeightedFeatures(f1, dimensions);
- uint64_t o2 = SimHashWeightedFeatures(f2, dimensions);
- for (uint8_t j = 0; j < dimensions; ++j) {
- if ((o1 & 1) == (o2 & 1))
- ++num_output_bits_equal;
- o1 >>= 1;
- o2 >>= 1;
- }
- }
- return num_output_bits_equal;
-}
-
-TEST(SimHashTest, HashValue) {
- WeightedFeatures empty;
- EXPECT_EQ(SimHashWeightedFeatures(empty, 1u), 0ULL);
- EXPECT_EQ(SimHashWeightedFeatures(empty, 16u), 0ULL);
-
- WeightedFeatures f0;
- f0.emplace(FeatureEncoding(0), FeatureWeight(1));
- EXPECT_EQ(SimHashWeightedFeatures(f0, 1u), 0ULL);
- EXPECT_EQ(SimHashWeightedFeatures(f0, 16u), 8632ULL);
-
- WeightedFeatures f1;
- f1.emplace(FeatureEncoding(0), FeatureWeight(123));
- EXPECT_EQ(SimHashWeightedFeatures(f1, 1u), 0ULL);
- EXPECT_EQ(SimHashWeightedFeatures(f1, 16u), 8632ULL);
-
- WeightedFeatures f2;
- f2.emplace(FeatureEncoding(999999), FeatureWeight(1));
- EXPECT_EQ(SimHashWeightedFeatures(f2, 1u), 1ULL);
- EXPECT_EQ(SimHashWeightedFeatures(f2, 16u), 28603ULL);
-
- WeightedFeatures f3;
- f3.emplace(FeatureEncoding(0), FeatureWeight(1));
- f3.emplace(FeatureEncoding(1), FeatureWeight(1));
- EXPECT_EQ(SimHashWeightedFeatures(f3, 1u), 0ULL);
- EXPECT_EQ(SimHashWeightedFeatures(f3, 16u), 10682ULL);
-
- WeightedFeatures f4;
- f4.emplace(FeatureEncoding(0), FeatureWeight(2));
- f4.emplace(FeatureEncoding(1), FeatureWeight(3));
- EXPECT_EQ(SimHashWeightedFeatures(f4, 1u), 0ULL);
- EXPECT_EQ(SimHashWeightedFeatures(f4, 16u), 2490ULL);
-}
-
-// Test that given random equally weighted input features, the chances of each
-// bit in the SimHash result to be 0 and 1 are equally likely.
-TEST(SimHashTest, ExpectationOnRandomUniformInput) {
- const uint8_t dimensions = 16u;
- const size_t repeat_times = 10000u;
-
- uint64_t totals[dimensions] = {0};
-
- for (size_t i = 0; i < repeat_times; ++i) {
- LargeBitVector v = RandLargeBitVector(RandUint64InRange(1u, 10u));
- uint64_t hash_result =
- SimHashWeightedFeatures(ToWeightedFeatures(v), dimensions);
-
- for (uint8_t j = 0; j < dimensions; ++j) {
- totals[j] += (hash_result & 1);
- hash_result >>= 1;
- }
- }
-
- const double expectation = 0.5;
- const double err_tolerance = 0.03;
-
- for (uint8_t j = 0; j < dimensions; ++j) {
- double avg = 1.0 * totals[j] / repeat_times;
- EXPECT_LT(avg, expectation + err_tolerance);
- EXPECT_GT(avg, expectation - err_tolerance);
- }
-}
-
-// Test that the cosine similarity is preserved.
-TEST(SimHashTest, CosineSimilarity_NonOrthogonalInput) {
- const float kPi = 3.141592653589793;
- const uint8_t dimensions = 50u;
- const size_t repeat_times = 100u;
-
- // Generate v1 and v2 that are likely non-orthogonal.
- LargeBitVector v1 = RandLargeBitVector(4000u, 10000);
- LargeBitVector v2 = RandLargeBitVector(5000u, 10000);
-
- size_t num_output_bits_equal = MultipleSimHashGetNumOutputBitsEqual(
- repeat_times, dimensions, ToWeightedFeatures(v1), ToWeightedFeatures(v2));
- float avg = 1.0 * num_output_bits_equal / dimensions / repeat_times;
- float expectation =
- 1.0 - std::acos(DotProduct(v1, v2) / (Norm(v1) * Norm(v2))) / kPi;
-
- // Verify that the expectation is different from 0.5 and 1 to make sure the
- // test is non-trivial.
- EXPECT_LT(expectation, 0.7);
- EXPECT_GT(expectation, 0.6);
-
- // Verify that SimHash(v1) and SimHash(v2) have approximately |expectation|
- // fraction of their bits in common.
- const double err_tolerance = 0.03;
- EXPECT_LT(avg, expectation + err_tolerance);
- EXPECT_GT(avg, expectation - err_tolerance);
-}
-
-// Test that when input v1 and v2 are orthogonal, SimHash(v1) and SimHash(v2)
-// have approximately half their bits in common.
-TEST(SimHashTest, CosineSimilarity_OrthogonalInput) {
- const uint8_t dimensions = 50u;
- const size_t repeat_times = 100u;
-
- // Generate v1 and v2 that are likely orthogonal
- LargeBitVector v1 = RandLargeBitVector(1u);
- LargeBitVector v2 = RandLargeBitVector(1u);
-
- size_t num_output_bits_equal = MultipleSimHashGetNumOutputBitsEqual(
- repeat_times, dimensions, ToWeightedFeatures(v1), ToWeightedFeatures(v2));
- float avg = 1.0 * num_output_bits_equal / dimensions / repeat_times;
- float expectation = 0.5;
-
- // Verify that SimHash(v1) and SimHash(v2) have approximately half their bits
- // in common.
- const double err_tolerance = 0.03;
- EXPECT_LT(avg, expectation + err_tolerance);
- EXPECT_GT(avg, expectation - err_tolerance);
-}
-
-} // namespace
-
-} // namespace federated_learning
diff --git a/chromium/components/feed/content/renderer/rss_link_reader.cc b/chromium/components/feed/content/renderer/rss_link_reader.cc
index 65b3ee12f7e..42c18fbdf85 100644
--- a/chromium/components/feed/content/renderer/rss_link_reader.cc
+++ b/chromium/components/feed/content/renderer/rss_link_reader.cc
@@ -6,7 +6,9 @@
#include <string>
+#include "base/metrics/histogram_functions.h"
#include "base/strings/string_util.h"
+#include "base/time/time.h"
#include "components/feed/mojom/rss_link_reader.mojom.h"
#include "content/public/renderer/render_frame.h"
#include "services/service_manager/public/cpp/binder_registry.h"
@@ -93,9 +95,13 @@ RssLinkReader::RssLinkReader(content::RenderFrame* render_frame,
RssLinkReader::~RssLinkReader() = default;
void RssLinkReader::GetRssLinks(GetRssLinksCallback callback) {
+ base::TimeTicks start_time = base::TimeTicks::Now();
blink::WebDocument document = render_frame()->GetWebFrame()->GetDocument();
std::move(callback).Run(
mojom::RssLinks::New(document.Url(), GetRssLinksFromDocument(document)));
+ base::UmaHistogramMicrosecondsTimes(
+ "ContentSuggestions.Feed.WebFeed.GetRssLinksRendererTime",
+ base::TimeTicks::Now() - start_time);
}
void RssLinkReader::OnDestruct() {
diff --git a/chromium/components/feed/core/common/pref_names.cc b/chromium/components/feed/core/common/pref_names.cc
index 44ac516e0f7..f064504ccc6 100644
--- a/chromium/components/feed/core/common/pref_names.cc
+++ b/chromium/components/feed/core/common/pref_names.cc
@@ -6,6 +6,7 @@
#include <string>
+#include "build/build_config.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
@@ -19,10 +20,10 @@ const char kHostOverrideBlessNonce[] = "feed.host_override.bless_nonce";
const char kHasReachedClickAndViewActionsUploadConditions[] =
"feed.clicks_and_views_upload_conditions_reached";
const char kLastFetchHadNoticeCard[] = "feed.last_fetch_had_notice_card";
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
const char kLastFetchHadLoggingEnabled[] =
"feed.last_fetch_had_logging_enabled";
-#endif // defined(OS_IOS)
+#endif // BUILDFLAG(IS_IOS)
const char kNoticeCardViewsCount[] = "feed.notice_card_views_count";
const char kNoticeCardClicksCount[] = "feed.notice_card_clicks_count";
@@ -50,39 +51,11 @@ const char kNoticeStates[] = "feed.notice_states";
// Deprecated prefs:
namespace {
-// Deprecated 02/2021
-const char kLastRefreshWasSignedIn[] = "feed.last_refresh_was_signed_in";
-const char kBackgroundRefreshPeriod[] = "feed.background_refresh_period";
-const char kThrottlerRequestCount[] = "feed.refresh_throttler.count";
-const char kThrottlerRequestsDay[] = "feed.refresh_throttler.day";
-const char kUserClassifierAverageSuggestionsViwedPerHour[] =
- "feed.user_classifier.average_suggestions_veiwed_per_hour";
-const char kUserClassifierAverageSuggestionsUsedPerHour[] =
- "feed.user_classifier.average_suggestions_used_per_hour";
-const char kUserClassifierLastTimeToViewSuggestions[] =
- "feed.user_classifier.last_time_to_view_suggestions";
-const char kUserClassifierLastTimeToUseSuggestions[] =
- "feed.user_classifier.last_time_to_use_suggestions";
// Deprecated May/June 2021
const char kEnableWebFeedUI[] = "webfeed_ui.enable";
const char kIsWebFeedSubscriber[] = "webfeed.is_subscriber";
-void RegisterObsoletePrefsFeb_2021(PrefRegistrySimple* registry) {
- registry->RegisterBooleanPref(kLastRefreshWasSignedIn, false);
- registry->RegisterTimeDeltaPref(kBackgroundRefreshPeriod, base::TimeDelta());
- registry->RegisterIntegerPref(kThrottlerRequestCount, 0);
- registry->RegisterIntegerPref(kThrottlerRequestsDay, 0);
- registry->RegisterDoublePref(kUserClassifierAverageSuggestionsViwedPerHour,
- 0.0);
- registry->RegisterDoublePref(kUserClassifierAverageSuggestionsUsedPerHour,
- 0.0);
- registry->RegisterTimePref(kUserClassifierLastTimeToViewSuggestions,
- base::Time());
- registry->RegisterTimePref(kUserClassifierLastTimeToUseSuggestions,
- base::Time());
-}
-
void RegisterObsoletePrefsJune_2021(PrefRegistrySimple* registry) {
registry->RegisterBooleanPref(kEnableWebFeedUI, false);
registry->RegisterBooleanPref(kIsWebFeedSubscriber, false);
@@ -117,26 +90,14 @@ void RegisterProfilePrefs(PrefRegistrySimple* registry) {
registry->RegisterIntegerPref(feed::prefs::kLastSeenFeedType, 0);
registry->RegisterDictionaryPref(feed::prefs::kNoticeStates, 0);
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
registry->RegisterBooleanPref(feed::prefs::kLastFetchHadLoggingEnabled,
false);
-#endif // defined(OS_IOS)
+#endif // BUILDFLAG(IS_IOS)
- RegisterObsoletePrefsFeb_2021(registry);
RegisterObsoletePrefsJune_2021(registry);
}
-void MigrateObsoleteProfilePrefsFeb_2021(PrefService* prefs) {
- prefs->ClearPref(kLastRefreshWasSignedIn);
- prefs->ClearPref(kBackgroundRefreshPeriod);
- prefs->ClearPref(kThrottlerRequestCount);
- prefs->ClearPref(kThrottlerRequestsDay);
- prefs->ClearPref(kUserClassifierAverageSuggestionsViwedPerHour);
- prefs->ClearPref(kUserClassifierAverageSuggestionsUsedPerHour);
- prefs->ClearPref(kUserClassifierLastTimeToViewSuggestions);
- prefs->ClearPref(kUserClassifierLastTimeToUseSuggestions);
-}
-
void MigrateObsoleteProfilePrefsJune_2021(PrefService* prefs) {
prefs->ClearPref(kEnableWebFeedUI);
prefs->ClearPref(kIsWebFeedSubscriber);
diff --git a/chromium/components/feed/core/common/pref_names.h b/chromium/components/feed/core/common/pref_names.h
index dbb6c4b6cc5..995041426e6 100644
--- a/chromium/components/feed/core/common/pref_names.h
+++ b/chromium/components/feed/core/common/pref_names.h
@@ -19,6 +19,7 @@ extern const char kHostOverrideHost[];
// The pref name for the feed host override auth token.
extern const char kHostOverrideBlessNonce[];
+// TODO(b/213622639): This pref is unused and should be cleared / removed.
// The pref name for the bit that determines whether the conditions are reached
// to enable the upload of click and view actions in the feed with the notice
// card when using the feature kInterestFeedConditionalClickAndViewActionUpload.
@@ -35,9 +36,9 @@ extern const char kLastFetchHadNoticeCard[];
// The pref name for the bit that determines whether logging is enabled for the
// feed in the last fetch of content. iOS only.
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
extern const char kLastFetchHadLoggingEnabled[];
-#endif // defined(OS_IOS)
+#endif // BUILDFLAG(IS_IOS)
// The pref name for the counter for the number of views on the privacy notice
// card.
diff --git a/chromium/components/feed/core/proto/v2/store.proto b/chromium/components/feed/core/proto/v2/store.proto
index 13d683061b8..4c4efd9e988 100644
--- a/chromium/components/feed/core/proto/v2/store.proto
+++ b/chromium/components/feed/core/proto/v2/store.proto
@@ -28,6 +28,7 @@ option optimize_for = LITE_RUNTIME;
// subs -> subscribed_web_feeds
// recommendedIndex -> recommended_web_feed_index
// R/<web_feed_id> -> recommended_web_feed
+// W/<operation-id> -> pending_web_feed_operation
message Record {
oneof data {
StreamData stream_data = 1;
@@ -39,6 +40,7 @@ message Record {
SubscribedWebFeeds subscribed_web_feeds = 7;
WebFeedInfo recommended_web_feed = 8;
RecommendedWebFeedIndex recommended_web_feed_index = 9;
+ PendingWebFeedOperation pending_web_feed_operation = 10;
}
}
@@ -54,6 +56,10 @@ message StreamData {
repeated feedwire.ContentId shared_state_ids = 6;
// Was this feed signed in.
bool signed_in = 7;
+ // If signed_in, this is the account gaia tied to this stream data.
+ string gaia = 13;
+ // If signed_in, this is the account email tied to this stream data.
+ string email = 14;
// Is activity logging enabled?
bool logging_enabled = 8;
// Has the privacy notice been fulfilled?
@@ -114,6 +120,12 @@ message Metadata {
repeated StreamMetadata stream_metadata = 5;
// The GAIA ID associated with the store.
string gaia = 6;
+ // Whether WAA is enabled for this user, as reported by the last FeedQuery
+ // response.
+ bool web_and_app_activity_enabled = 7;
+ // Whether personalization is enabled for Discover, as reported by the last
+ // FeedQuery response.
+ bool discover_personalization_enabled = 8;
}
// A set of StreamStructures that should be applied to a stream.
@@ -254,3 +266,19 @@ message WebFeedInfo {
State state = 9;
repeated feedwire.webfeed.WebFeedMatcher matchers = 10;
}
+
+message PendingWebFeedOperation {
+ enum Kind {
+ KIND_UNSPECIFIED = 0;
+ SUBSCRIBE = 1;
+ UNSUBSCRIBE = 2;
+ }
+ // Unique ID, for sorting operations.
+ int64 id = 1;
+ // The operation kind.
+ Kind kind = 2;
+ // The web feed ID to either subscribe or unsubscribe.
+ string web_feed_id = 3;
+ // Number of times the operation has been attempted.
+ int32 attempts = 4;
+}
diff --git a/chromium/components/feed/core/proto/v2/wire/action_payload.proto b/chromium/components/feed/core/proto/v2/wire/action_payload.proto
index 28ef27a2052..e8697d75c4e 100644
--- a/chromium/components/feed/core/proto/v2/wire/action_payload.proto
+++ b/chromium/components/feed/core/proto/v2/wire/action_payload.proto
@@ -9,5 +9,5 @@ package feedwire;
option optimize_for = LITE_RUNTIME;
message ActionPayload {
- optional bytes action_payload_data = 257605906;
+ repeated bytes batched_action_payload_data = 370974597;
}
diff --git a/chromium/components/feed/core/proto/v2/wire/chrome_feed_response_metadata.proto b/chromium/components/feed/core/proto/v2/wire/chrome_feed_response_metadata.proto
index d8cd4d67b4c..c64892c8034 100644
--- a/chromium/components/feed/core/proto/v2/wire/chrome_feed_response_metadata.proto
+++ b/chromium/components/feed/core/proto/v2/wire/chrome_feed_response_metadata.proto
@@ -13,6 +13,8 @@ message ChromeFeedResponseMetadata {
optional bool logging_enabled = 2;
optional string session_id = 3;
repeated Experiment experiments = 4;
+ optional bool web_and_app_activity_enabled = 5;
+ optional bool discover_personalization_enabled = 6;
}
message Experiment {
optional string trial_name = 1;
diff --git a/chromium/components/feed/core/proto/v2/wire/reliability_logging_enums.proto b/chromium/components/feed/core/proto/v2/wire/reliability_logging_enums.proto
index 035465a63e5..320dfc12219 100644
--- a/chromium/components/feed/core/proto/v2/wire/reliability_logging_enums.proto
+++ b/chromium/components/feed/core/proto/v2/wire/reliability_logging_enums.proto
@@ -23,8 +23,17 @@ enum DiscoverLaunchResult {
NO_CARDS_RESPONSE_ERROR_ZERO_CARDS = 27;
NO_CARDS_UNKNOWN_REASON = 29;
FAILED_TO_RENDER = 5;
+ SEARCH_BOX_TAPPED = 7;
+ VOICE_SEARCH_TAPPED = 8;
NAVIGATED_TO_ANOTHER_TAB = 10;
+ ACCOUNT_PARTICLE_DISC_TAPPED = 13;
+ OVERFLOW_MANAGE_INTERESTS_TAPPED = 31;
+ CARD_TAPPED = 46;
+ CONFIGURATION_CHANGED = 30;
FRAGMENT_STOPPED = 11 [deprecated = true];
+ FRAGMENT_PAUSED = 43;
+ UNKNOWN_HIDE_REASON = 44;
+ NAVIGATED_BACK = 9;
ABORTED_DUE_TO_INVALID_STATE = 6;
NAVIGATED_AWAY_IN_APP = 35;
FEED_HIDDEN = 36;
diff --git a/chromium/components/feed/core/proto/v2/wire/upload_actions_request.proto b/chromium/components/feed/core/proto/v2/wire/upload_actions_request.proto
index 9e45f512a45..0271afb0308 100644
--- a/chromium/components/feed/core/proto/v2/wire/upload_actions_request.proto
+++ b/chromium/components/feed/core/proto/v2/wire/upload_actions_request.proto
@@ -7,6 +7,7 @@ syntax = "proto3";
package feedwire;
import "components/feed/core/proto/v2/wire/action_diagnostic_info.proto";
+import "components/feed/core/proto/v2/wire/client_info.proto";
import "components/feed/core/proto/v2/wire/consistency_token.proto";
import "components/feed/core/proto/v2/wire/feed_action.proto";
@@ -16,4 +17,5 @@ message UploadActionsRequest {
repeated FeedAction feed_actions = 1;
ConsistencyToken consistency_token = 2;
ActionDiagnosticInfo action_diagnostic_info = 5;
+ ClientInfo client_info = 6;
}
diff --git a/chromium/components/feed/core/proto/v2/wire/web_feeds.proto b/chromium/components/feed/core/proto/v2/wire/web_feeds.proto
index 2f60e302dd7..b404d74b246 100644
--- a/chromium/components/feed/core/proto/v2/wire/web_feeds.proto
+++ b/chromium/components/feed/core/proto/v2/wire/web_feeds.proto
@@ -43,6 +43,7 @@ message FollowWebFeedRequest {
string name = 1;
string web_page_uri = 2;
}
+ string canonical_uri = 5;
repeated string page_rss_uris = 3;
ConsistencyToken consistency_token = 4;
}
diff --git a/chromium/components/feed/core/v2/BUILD.gn b/chromium/components/feed/core/v2/BUILD.gn
index 74b51b47cd0..d5a0513de6a 100644
--- a/chromium/components/feed/core/v2/BUILD.gn
+++ b/chromium/components/feed/core/v2/BUILD.gn
@@ -13,6 +13,7 @@ source_set("feed_core_v2") {
"public/feed_api.h",
"public/feed_service.h",
"public/feed_stream_surface.h",
+ "public/logging_parameters.h",
"public/persistent_key_value_store.h",
"public/persistent_key_value_store.h",
"public/refresh_task_scheduler.h",
@@ -49,6 +50,8 @@ source_set("feed_core_v2") {
"launch_reliability_logger.h",
"metrics_reporter.cc",
"metrics_reporter.h",
+ "operation_token.cc",
+ "operation_token.h",
"persistent_key_value_store_impl.cc",
"persistent_key_value_store_impl.h",
"prefs.cc",
@@ -60,6 +63,7 @@ source_set("feed_core_v2") {
"public/feed_api.cc",
"public/feed_service.cc",
"public/feed_stream_surface.cc",
+ "public/logging_parameters.cc",
"public/persistent_key_value_store.cc",
"public/public_types.cc",
"public/stream_type.cc",
@@ -74,8 +78,6 @@ source_set("feed_core_v2") {
"stream/privacy_notice_card_tracker.h",
"stream/unread_content_notifier.cc",
"stream/unread_content_notifier.h",
- "stream/upload_criteria.cc",
- "stream/upload_criteria.h",
"stream_model.cc",
"stream_model.h",
"stream_model/ephemeral_change.cc",
@@ -114,6 +116,12 @@ source_set("feed_core_v2") {
"web_feed_subscriptions/unsubscribe_from_web_feed_task.h",
"web_feed_subscriptions/web_feed_index.cc",
"web_feed_subscriptions/web_feed_index.h",
+ "web_feed_subscriptions/web_feed_metadata_model.cc",
+ "web_feed_subscriptions/web_feed_metadata_model.h",
+ "web_feed_subscriptions/web_feed_subscription_model.cc",
+ "web_feed_subscriptions/web_feed_subscription_model.h",
+ "web_feed_subscriptions/web_feed_types.cc",
+ "web_feed_subscriptions/web_feed_types.h",
"web_feed_subscriptions/wire_to_store.cc",
"web_feed_subscriptions/wire_to_store.h",
"wire_response_translator.cc",
@@ -193,10 +201,12 @@ source_set("core_unit_tests") {
"feedstore_util_unittest.cc",
"image_fetcher_unittest.cc",
"metrics_reporter_unittest.cc",
+ "operation_token_unittest.cc",
"persistent_key_value_store_impl_unittest.cc",
"proto_util_unittest.cc",
"protocol_translator_unittest.cc",
"public/feed_service_unittest.cc",
+ "public/logging_parameters_unittest.cc",
"public/public_types_unittest.cc",
"request_throttler_unittest.cc",
"scheduling_unittest.cc",
diff --git a/chromium/components/feed/core/v2/api_test/feed_api_notice_card_unittest.cc b/chromium/components/feed/core/v2/api_test/feed_api_notice_card_unittest.cc
index 45d8d5bf695..20774f3f733 100644
--- a/chromium/components/feed/core/v2/api_test/feed_api_notice_card_unittest.cc
+++ b/chromium/components/feed/core/v2/api_test/feed_api_notice_card_unittest.cc
@@ -31,17 +31,6 @@ class FeedApiNoticeCardTest : public FeedApiTest {
StreamModelUpdateRequestGenerator model_generator_;
};
-class FeedStreamConditionalActionsUploadTest : public FeedApiNoticeCardTest {
- public:
- FeedStreamConditionalActionsUploadTest() {
- scoped_feature_list_.InitAndEnableFeature(
- feed::kInterestFeedV2ClicksAndViewsConditionalUpload);
- }
-
- private:
- base::test::ScopedFeatureList scoped_feature_list_;
-};
-
TEST_F(FeedApiNoticeCardTest, LoadStreamSendsNoticeCardAcknowledgement) {
response_translator_.InjectResponse(model_generator_.MakeFirstPage());
@@ -76,162 +65,6 @@ TEST_F(FeedApiNoticeCardTest, LoadStreamSendsNoticeCardAcknowledgement) {
.notice_card_acknowledged());
}
-TEST_F(FeedStreamConditionalActionsUploadTest,
- NoActionsUploadUntilReachedConditions) {
- // Tests the flow where we:
- // (1) Perform a ThereAndBackAgain action and a View action while upload
- // isn't enabled => (2) Attempt an upload while the upload conditions aren't
- // reached => (3) Reach upload conditions => (4) Perform another View action
- // that should be dropped => (5) Simulate the backgrounding of the app to
- // enable actions upload => (6) Trigger an upload which will upload the
- // stored ThereAndBackAgain action.
-
- // WebFeed stream is only fetched when there's a subscription.
- network_.InjectListWebFeedsResponse({MakeWireWebFeed("cats")});
- response_translator_.InjectResponse(model_generator_.MakeFirstPage());
- TestWebFeedSurface surface(stream_.get());
- WaitForIdleTaskQueue();
-
- // Process the view action and the ThereAndBackAgain action while the upload
- // conditions aren't reached.
- stream_->ProcessViewAction(MakeFeedAction(42ul).SerializeAsString());
- WaitForIdleTaskQueue();
- // Verify that the view action was dropped.
- ASSERT_EQ(0ul, ReadStoredActions(stream_->GetStore()).size());
-
- stream_->ProcessThereAndBackAgain(
- MakeThereAndBackAgainData(42ul).SerializeAsString());
- WaitForIdleTaskQueue();
- // Verify that the ThereAndBackAgain action is in the action store.
- ASSERT_EQ(1ul, ReadStoredActions(stream_->GetStore()).size());
-
- // Attempt an upload.
- stream_->OnEnterBackground();
- WaitForIdleTaskQueue();
- // Verify that no upload is done because the conditions aren't reached.
- EXPECT_EQ(0, network_.GetActionRequestCount());
-
- // Reach conditions.
- stream_->ReportSliceViewed(
- surface.GetSurfaceId(), surface.GetStreamType(),
- surface.initial_state->updated_slices(0).slice().slice_id());
-
- // Verify that the view action is still dropped because we haven't
- // transitioned out of the current surface.
- stream_->ProcessViewAction(MakeFeedAction(42ul).SerializeAsString());
- WaitForIdleTaskQueue();
- ASSERT_EQ(1ul, ReadStoredActions(stream_->GetStore()).size());
-
- // Enable the upload bit and trigger the upload of actions.
- surface.Detach();
- stream_->OnEnterBackground();
- WaitForIdleTaskQueue();
-
- // Verify that the ThereAndBackAgain action was uploaded but not the view
- // action.
- ASSERT_EQ(1, network_.GetActionRequestCount());
- EXPECT_EQ(1, network_.GetActionRequestSent()->feed_actions_size());
-}
-
-TEST_F(FeedStreamConditionalActionsUploadTest, EnableUploadOnSurfaceAttached) {
- response_translator_.InjectResponse(model_generator_.MakeFirstPage());
- TestForYouSurface surface(stream_.get());
- WaitForIdleTaskQueue();
-
- // Perform a ThereAndBackAgain action.
- stream_->ProcessThereAndBackAgain(
- MakeThereAndBackAgainData(42ul).SerializeAsString());
- WaitForIdleTaskQueue();
-
- // Reach conditions.
- stream_->ReportSliceViewed(
- surface.GetSurfaceId(), surface.GetStreamType(),
- surface.initial_state->updated_slices(0).slice().slice_id());
-
- // Attach a new surface to update the bit to enable uploads.
- TestForYouSurface surface2(stream_.get());
-
- // Trigger an upload through load more to isolate the effect of the on-attach
- // event on enabling uploads.
- response_translator_.InjectResponse(model_generator_.MakeNextPage());
- stream_->LoadMore(surface, base::DoNothing());
- WaitForIdleTaskQueue();
-
- // Verify that the ThereAndBackAgain action was uploaded.
- ASSERT_EQ(1, network_.GetActionRequestCount());
- EXPECT_EQ(1, network_.GetActionRequestSent()->feed_actions_size());
-}
-
-TEST_F(FeedStreamConditionalActionsUploadTest, EnableUploadOnEnterBackground) {
- response_translator_.InjectResponse(model_generator_.MakeFirstPage());
- TestForYouSurface surface(stream_.get());
- WaitForIdleTaskQueue();
-
- // Perform a ThereAndBackAgain action.
- stream_->ProcessThereAndBackAgain(
- MakeThereAndBackAgainData(42ul).SerializeAsString());
- WaitForIdleTaskQueue();
-
- // Reach conditions.
- stream_->ReportSliceViewed(
- surface.GetSurfaceId(), surface.GetStreamType(),
- surface.initial_state->updated_slices(0).slice().slice_id());
-
- surface.Detach();
- stream_->OnEnterBackground();
- WaitForIdleTaskQueue();
-
- // Verify that the ThereAndBackAgain action was uploaded.
- ASSERT_EQ(1, network_.GetActionRequestCount());
- EXPECT_EQ(1, network_.GetActionRequestSent()->feed_actions_size());
-}
-
-TEST_F(FeedStreamConditionalActionsUploadTest,
- AllowActionsUploadWhenNoticeCardNotPresentRegardlessOfConditions) {
- model_generator_.privacy_notice_fulfilled = false;
- response_translator_.InjectResponse(model_generator_.MakeFirstPage());
- TestForYouSurface surface(stream_.get());
- WaitForIdleTaskQueue();
-
- // Process the view action and the ThereAndBackAgain action while the upload
- // conditions aren't reached.
- stream_->ProcessViewAction(MakeFeedAction(42ul).SerializeAsString());
- WaitForIdleTaskQueue();
- stream_->ProcessThereAndBackAgain(
- MakeThereAndBackAgainData(42ul).SerializeAsString());
- WaitForIdleTaskQueue();
-
- // Trigger an upload through a query.
- surface.Detach();
- stream_->OnEnterBackground();
- WaitForIdleTaskQueue();
-
- // Verify the ThereAndBackAgain action and the view action were uploaded.
- ASSERT_EQ(1, network_.GetActionRequestCount());
- EXPECT_EQ(2, network_.GetActionRequestSent()->feed_actions_size());
-}
-
-TEST_F(FeedStreamConditionalActionsUploadTest,
- ResetTheUploadEnableBitsOnClearAll) {
- response_translator_.InjectResponse(model_generator_.MakeFirstPage());
- TestForYouSurface surface(stream_.get());
- WaitForIdleTaskQueue();
-
- // Reach conditions.
- stream_->ReportSliceViewed(
- surface.GetSurfaceId(), surface.GetStreamType(),
- surface.initial_state->updated_slices(0).slice().slice_id());
- surface.Detach();
- stream_->OnEnterBackground();
- ASSERT_TRUE(stream_->CanUploadActions());
-
- // Trigger a ClearAll, and ensure actions cannot be uploaded until conditions
- // are reached again.
- stream_->OnSignedOut();
- WaitForIdleTaskQueue();
- ASSERT_FALSE(stream_->CanUploadActions());
-}
-
TEST_F(FeedApiNoticeCardTest, LoadStreamUpdateNoticeCardFulfillmentHistogram) {
base::HistogramTester histograms;
@@ -266,66 +99,6 @@ TEST_F(FeedApiNoticeCardTest, LoadStreamUpdateNoticeCardFulfillmentHistogram) {
1, 1);
}
-TEST_F(FeedStreamConditionalActionsUploadTest,
- DontTriggerActionsUploadWhenWasNotSignedIn) {
- auto update_request = model_generator_.MakeFirstPage();
- update_request->stream_data.set_signed_in(false);
- response_translator_.InjectResponse(std::move(update_request));
- TestForYouSurface surface(stream_.get());
- WaitForIdleTaskQueue();
-
- // Try to reach conditions.
- stream_->ReportSliceViewed(
- surface.GetSurfaceId(), surface.GetStreamType(),
- surface.initial_state->updated_slices(1).slice().slice_id());
-
- // Try to trigger an upload through a query.
- stream_->OnEnterBackground();
- WaitForIdleTaskQueue();
-
- // Verify that even if the conditions were reached, the pref that enables the
- // upload wasn't set to true because the latest refresh request wasn't signed
- // in.
- ASSERT_FALSE(stream_->CanUploadActions());
-}
-
-TEST_F(FeedStreamConditionalActionsUploadTest,
- LoadMoreDoesntUpdateNoticeCardPrefAndHistogram) {
- // The initial stream load has the notice card.
- response_translator_.InjectResponse(model_generator_.MakeFirstPage());
- TestForYouSurface surface(stream_.get());
- WaitForIdleTaskQueue();
-
- // Inject a response for the LoadMore fetch that doesn't have the notice card.
- // It shouldn't overwrite the notice card pref.
- model_generator_.privacy_notice_fulfilled = false;
- response_translator_.InjectResponse(model_generator_.MakeNextPage());
-
- // Start tracking histograms after the initial stream load to isolate the
- // effect of load more.
- base::HistogramTester histograms;
-
- stream_->LoadMore(surface, base::DoNothing());
- WaitForIdleTaskQueue();
-
- // Process a view action that should be dropped because the upload of actions
- // is still disabled because there is still a notice card.
- stream_->ProcessViewAction(MakeFeedAction(42ul).SerializeAsString());
- WaitForIdleTaskQueue();
-
- // Trigger an upload.
- stream_->OnEnterBackground();
- WaitForIdleTaskQueue();
-
- // Verify that there were no uploads.
- EXPECT_EQ(0, network_.GetActionRequestCount());
-
- // Verify that the notice card fulfillment histogram isn't recorded for load
- // more.
- histograms.ExpectTotalCount("ContentSuggestions.Feed.NoticeCardFulfilled2",
- 0);
-}
-
} // namespace
} // namespace test
} // namespace feed
diff --git a/chromium/components/feed/core/v2/api_test/feed_api_reliability_logging_unittest.cc b/chromium/components/feed/core/v2/api_test/feed_api_reliability_logging_unittest.cc
index da4c51d536d..5f1f9e7589f 100644
--- a/chromium/components/feed/core/v2/api_test/feed_api_reliability_logging_unittest.cc
+++ b/chromium/components/feed/core/v2/api_test/feed_api_reliability_logging_unittest.cc
@@ -277,7 +277,7 @@ TEST_F(FeedApiReliabilityLoggingTest, LoadStreamComplete_NoResponseReceived) {
"LogRequestFinished result=-7 id=1\n"
"LogLaunchFinishedAfterStreamUpdate "
- "result=NO_CARDS_RESPONSE_ERROR_NON_200\n"
+ "result=NO_CARDS_REQUEST_ERROR_OTHER\n"
"LogAboveTheFoldRender result=FULL_FEED_ERROR\n",
surface.reliability_logging_bridge.GetEventsString());
@@ -394,8 +394,8 @@ TEST_F(FeedApiReliabilityLoggingTest, CacheRead_Okay) {
TEST_F(FeedApiReliabilityLoggingTest, UploadActions) {
response_translator_.InjectResponse(MakeTypicalInitialModelState());
- stream_->UploadAction(MakeFeedAction(1ul), /*upload_now=*/false,
- base::DoNothing());
+ stream_->UploadAction(MakeFeedAction(1ul), CreateLoggingParameters(),
+ /*upload_now=*/false, base::DoNothing());
TestForYouSurface surface(stream_.get());
WaitForIdleTaskQueue();
@@ -451,4 +451,4 @@ TEST_F(FeedApiReliabilityLoggingTest, IdChangeOnMetricsIdChange) {
} // namespace
} // namespace test
-} // namespace feed \ No newline at end of file
+} // namespace feed
diff --git a/chromium/components/feed/core/v2/api_test/feed_api_stream_unittest.cc b/chromium/components/feed/core/v2/api_test/feed_api_stream_unittest.cc
index f1c6c33102d..2eedfee52c3 100644
--- a/chromium/components/feed/core/v2/api_test/feed_api_stream_unittest.cc
+++ b/chromium/components/feed/core/v2/api_test/feed_api_stream_unittest.cc
@@ -21,6 +21,7 @@
#include "components/feed/core/v2/public/feed_api.h"
#include "components/feed/core/v2/public/feed_service.h"
#include "components/feed/core/v2/public/stream_type.h"
+#include "components/feed/core/v2/public/types.h"
#include "components/feed/core/v2/scheduling.h"
#include "components/feed/core/v2/stream/notice_card_tracker.h"
#include "components/feed/core/v2/test/callback_receiver.h"
@@ -127,12 +128,14 @@ TEST_F(FeedApiTest, BackgroundRefreshNotAttemptedAfterModelIsLoaded) {
}
TEST_F(FeedApiTest, SurfaceReceivesInitialContent) {
- {
- auto model = CreateStreamModel();
- model->Update(MakeTypicalInitialModelState());
- stream_->LoadModelForTesting(kForYouStream, std::move(model));
- }
+ response_translator_.InjectResponse(MakeTypicalInitialModelState());
+ // Use `the_first_surface` to force loading content.
+ TestForYouSurface the_first_surface(stream_.get());
+ WaitForIdleTaskQueue();
+
TestForYouSurface surface(stream_.get());
+ WaitForIdleTaskQueue();
+
ASSERT_TRUE(surface.initial_state);
const feedui::StreamUpdate& initial_state = surface.initial_state.value();
ASSERT_EQ(2, initial_state.updated_slices().size());
@@ -156,13 +159,10 @@ TEST_F(FeedApiTest, SurfaceReceivesInitialContent) {
}
TEST_F(FeedApiTest, SurfaceReceivesInitialContentLoadedAfterAttach) {
+ response_translator_.InjectResponse(MakeTypicalInitialModelState());
TestForYouSurface surface(stream_.get());
ASSERT_FALSE(surface.initial_state);
- {
- auto model = CreateStreamModel();
- model->Update(MakeTypicalInitialModelState());
- stream_->LoadModelForTesting(kForYouStream, std::move(model));
- }
+ WaitForIdleTaskQueue();
ASSERT_EQ("loading -> [user@foo] 2 slices", surface.DescribeUpdates());
const feedui::StreamUpdate& initial_state = surface.initial_state.value();
@@ -201,8 +201,7 @@ TEST_F(FeedApiTest, SurfaceReceivesUpdatedContent) {
const feedui::StreamUpdate& initial_state = surface.initial_state.value();
const feedui::StreamUpdate& update = surface.update.value();
- ASSERT_EQ("[View logging only user@foo] 2 slices -> 2 slices",
- surface.DescribeUpdates());
+ ASSERT_EQ("2 slices -> 2 slices", surface.DescribeUpdates());
// First slice is just an ID that matches the old 1st slice ID.
EXPECT_EQ(initial_state.updated_slices(0).slice().slice_id(),
update.updated_slices(0).slice_id());
@@ -237,8 +236,7 @@ TEST_F(FeedApiTest, SurfaceReceivesSecondUpdatedContent) {
// The last update should have only one new piece of content.
// This verifies the current content set is tracked properly.
- ASSERT_EQ("[View logging only user@foo] 2 slices -> 3 slices -> 4 slices",
- surface.DescribeUpdates());
+ ASSERT_EQ("2 slices -> 3 slices -> 4 slices", surface.DescribeUpdates());
ASSERT_EQ(4, surface.update->updated_slices().size());
EXPECT_FALSE(surface.update->updated_slices(0).has_slice());
@@ -783,7 +781,7 @@ TEST_F(FeedApiTest, ForceSignedOutRequestAfterHistoryIsDeleted) {
// Validate that the network request was sent as signed out.
ASSERT_EQ(1, network_.send_query_call_count);
- EXPECT_EQ("", network_.last_gaia);
+ EXPECT_EQ(AccountInfo{}, network_.last_account_info);
EXPECT_TRUE(network_.query_request_sent->feed_request()
.client_info()
.chrome_client_info()
@@ -791,10 +789,7 @@ TEST_F(FeedApiTest, ForceSignedOutRequestAfterHistoryIsDeleted) {
.empty());
// Validate the downstream consumption of the response.
- // TODO(crbug.com/1268575): We should disable view logging for the signed-out
- // feed even if the user is signed-in.
- EXPECT_EQ("loading -> [View logging only user@foo] 2 slices",
- surface.DescribeUpdates());
+ EXPECT_EQ("loading -> 2 slices", surface.DescribeUpdates());
EXPECT_EQ(kSessionId, stream_->GetMetadata().session_id().token());
EXPECT_FALSE(stream_->GetModel(surface.GetStreamType())->signed_in());
@@ -811,7 +806,7 @@ TEST_F(FeedApiTest, ForceSignedOutRequestAfterHistoryIsDeleted) {
// Validate that the network request was sent as signed out and
// contained the session id.
ASSERT_EQ(2, network_.send_query_call_count);
- EXPECT_EQ("", network_.last_gaia);
+ EXPECT_EQ(AccountInfo{}, network_.last_account_info);
EXPECT_EQ(kSessionId, stream_->GetMetadata().session_id().token());
EXPECT_EQ(network_.query_request_sent->feed_request()
.client_info()
@@ -832,7 +827,7 @@ TEST_F(FeedApiTest, ForceSignedOutRequestAfterHistoryIsDeleted) {
// Validate that a signed-in request was sent.
ASSERT_EQ(3, network_.send_query_call_count);
- EXPECT_NE("", network_.last_gaia);
+ EXPECT_NE(AccountInfo{}, network_.last_account_info);
// The model should now be in the signed-in state.
EXPECT_TRUE(stream_->GetModel(kForYouStream)->signed_in());
@@ -853,7 +848,7 @@ TEST_F(FeedApiTest, WebFeedUsesSignedInRequestAfterHistoryIsDeleted) {
WaitForIdleTaskQueue();
ASSERT_EQ(1, network_.send_query_call_count);
- EXPECT_NE("", network_.last_gaia);
+ EXPECT_NE(AccountInfo{}, network_.last_account_info);
}
TEST_F(FeedApiTest, AllowSignedInRequestAfterHistoryIsDeletedAfterDelay) {
@@ -864,7 +859,7 @@ TEST_F(FeedApiTest, AllowSignedInRequestAfterHistoryIsDeletedAfterDelay) {
WaitForIdleTaskQueue();
EXPECT_EQ("loading -> [user@foo] 2 slices", surface.DescribeUpdates());
- EXPECT_NE("", network_.last_gaia);
+ EXPECT_NE(AccountInfo{}, network_.last_account_info);
EXPECT_TRUE(stream_->GetMetadata().session_id().token().empty());
}
@@ -900,6 +895,20 @@ TEST_F(FeedApiTest, LoadStreamFromStore) {
stream_->GetModel(kForYouStream)->DumpStateForTesting());
}
+TEST_F(FeedApiTest, LoadStreamFromStoreValidatesUser) {
+ // Fill the store with stream data for another user.
+ {
+ auto state = MakeTypicalInitialModelState();
+ state->stream_data.set_email("other@gmail.com");
+ store_->OverwriteStream(kForYouStream, std::move(state), base::DoNothing());
+ }
+
+ TestForYouSurface surface(stream_.get());
+ WaitForIdleTaskQueue();
+
+ ASSERT_EQ("loading -> cant-refresh", surface.DescribeUpdates());
+}
+
TEST_F(FeedApiTest, LoadingSpinnerIsSentInitially) {
store_->OverwriteStream(kForYouStream, MakeTypicalInitialModelState(),
base::DoNothing());
@@ -1209,9 +1218,8 @@ TEST_P(FeedStreamTestForAllStreamTypes, LoadMoreAppendsContent) {
ASSERT_EQ(absl::optional<bool>(true), callback.GetResult());
EXPECT_EQ("4 slices +spinner -> 6 slices", surface.DescribeUpdates());
// The root ID should not change for next-page content.
- EXPECT_EQ(
- MakeRootEventId(),
- stream_->GetLoggingParameters(surface.GetStreamType()).root_event_id);
+ EXPECT_EQ(MakeRootEventId(),
+ surface.update->logging_parameters().root_event_id());
}
TEST_P(FeedStreamTestForAllStreamTypes, LoadMorePersistsData) {
@@ -1422,7 +1430,7 @@ TEST_F(FeedApiTest, ReadNetworkResponse) {
schedule.refresh_offsets);
// The stream's user attributes are set, so activity logging is enabled.
- EXPECT_TRUE(stream_->IsActivityLoggingEnabled(kForYouStream));
+ EXPECT_TRUE(surface.update->logging_parameters().logging_enabled());
// This network response has content.
EXPECT_TRUE(stream_->HasUnreadContent(kForYouStream));
}
@@ -1480,21 +1488,23 @@ TEST_F(FeedApiTest, ClearAllWhileLoadingMoreDoesNotLoadMore) {
EXPECT_EQ(false, cr.GetResult());
EXPECT_EQ(
"loading -> [user@foo] 2 slices -> 2 slices +spinner -> 2 slices -> "
- "loading -> [NO logging user@foo] 2 slices",
+ "loading -> 2 slices",
surface.DescribeUpdates());
}
TEST_F(FeedApiTest, ClearAllWipesAllState) {
// Trigger saving a consistency token, so it can be cleared later.
network_.consistency_token = "token-11";
- stream_->UploadAction(MakeFeedAction(42ul), true, base::DoNothing());
+ stream_->UploadAction(MakeFeedAction(42ul), CreateLoggingParameters(), true,
+ base::DoNothing());
// Trigger saving a feed stream, so it can be cleared later.
response_translator_.InjectResponse(MakeTypicalInitialModelState());
TestForYouSurface surface(stream_.get());
WaitForIdleTaskQueue();
// Enqueue an action, so it can be cleared later.
- stream_->UploadAction(MakeFeedAction(43ul), false, base::DoNothing());
+ stream_->UploadAction(MakeFeedAction(43ul), CreateLoggingParameters(), false,
+ base::DoNothing());
// Trigger ClearAll, this should erase everything.
stream_->OnCacheDataCleared();
@@ -1511,11 +1521,12 @@ TEST_F(FeedApiTest, ClearAllWipesAllState) {
)",
DumpStoreState(true));
EXPECT_EQ("", stream_->GetMetadata().consistency_token());
- EXPECT_FALSE(stream_->IsActivityLoggingEnabled(kForYouStream));
+ EXPECT_FALSE(surface.update->logging_parameters().logging_enabled());
}
TEST_F(FeedApiTest, StorePendingAction) {
- stream_->UploadAction(MakeFeedAction(42ul), false, base::DoNothing());
+ stream_->UploadAction(MakeFeedAction(42ul), CreateLoggingParameters(), false,
+ base::DoNothing());
WaitForIdleTaskQueue();
std::vector<feedstore::StoredAction> result =
@@ -1527,17 +1538,19 @@ TEST_F(FeedApiTest, StorePendingAction) {
}
TEST_F(FeedApiTest, UploadActionWhileSignedOutIsNoOp) {
- signed_in_gaia_ = "";
- ASSERT_EQ(stream_->GetSyncSignedInGaia(), "");
- stream_->UploadAction(MakeFeedAction(42ul), false, base::DoNothing());
+ account_info_ = {};
+ ASSERT_EQ(stream_->GetAccountInfo(), AccountInfo{});
+ stream_->UploadAction(MakeFeedAction(42ul), CreateLoggingParameters(), false,
+ base::DoNothing());
WaitForIdleTaskQueue();
EXPECT_EQ(0ul, ReadStoredActions(stream_->GetStore()).size());
}
TEST_F(FeedApiTest, SignOutWhileUploadActionDoesNotUpload) {
- stream_->UploadAction(MakeFeedAction(42ul), true, base::DoNothing());
- signed_in_gaia_ = "";
+ stream_->UploadAction(MakeFeedAction(42ul), CreateLoggingParameters(), true,
+ base::DoNothing());
+ account_info_ = {};
WaitForIdleTaskQueue();
@@ -1548,7 +1561,8 @@ TEST_F(FeedApiTest, SignOutWhileUploadActionDoesNotUpload) {
TEST_F(FeedApiTest, ClearAllWhileUploadActionDoesNotUpload) {
CallbackReceiver<UploadActionsTask::Result> cr;
- stream_->UploadAction(MakeFeedAction(42ul), true, cr.Bind());
+ stream_->UploadAction(MakeFeedAction(42ul), CreateLoggingParameters(), true,
+ cr.Bind());
stream_->OnCacheDataCleared(); // triggers ClearAll().
WaitForIdleTaskQueue();
@@ -1561,9 +1575,10 @@ TEST_F(FeedApiTest, ClearAllWhileUploadActionDoesNotUpload) {
TEST_F(FeedApiTest, WrongUserUploadActionDoesNotUpload) {
CallbackReceiver<UploadActionsTask::Result> cr;
- stream_->UploadAction(MakeFeedAction(42ul), true, cr.Bind());
- // Sign in as another user.
- signed_in_gaia_ = "someothergaia";
+ LoggingParameters logging_parameters = CreateLoggingParameters();
+ logging_parameters.email = "someothergaia";
+ stream_->UploadAction(MakeFeedAction(42ul), logging_parameters, true,
+ cr.Bind());
WaitForIdleTaskQueue();
@@ -1575,6 +1590,23 @@ TEST_F(FeedApiTest, WrongUserUploadActionDoesNotUpload) {
EXPECT_EQ(0ul, cr.GetResult()->upload_attempt_count);
}
+TEST_F(FeedApiTest, LoggingPropertiesWithNoAccountDoesNotUpload) {
+ CallbackReceiver<UploadActionsTask::Result> cr;
+ LoggingParameters logging_parameters = CreateLoggingParameters();
+ logging_parameters.email.clear();
+ stream_->UploadAction(MakeFeedAction(42ul), logging_parameters, true,
+ cr.Bind());
+
+ WaitForIdleTaskQueue();
+
+ // Action should not upload.
+ EXPECT_EQ(UploadActionsStatus::kAbortUploadForSignedOutUser,
+ metrics_reporter_->upload_action_status);
+ EXPECT_EQ(0, network_.GetActionRequestCount());
+ ASSERT_TRUE(cr.GetResult());
+ EXPECT_EQ(0ul, cr.GetResult()->upload_attempt_count);
+}
+
TEST_F(FeedApiTest, StorePendingActionAndUploadNow) {
network_.consistency_token = "token-11";
@@ -1583,7 +1615,8 @@ TEST_F(FeedApiTest, StorePendingActionAndUploadNow) {
{
feedwire::ThereAndBackAgainData msg;
*msg.mutable_action_payload() = MakeFeedAction(42ul).action_payload();
- stream_->ProcessThereAndBackAgain(msg.SerializeAsString());
+ stream_->ProcessThereAndBackAgain(msg.SerializeAsString(),
+ CreateLoggingParameters());
}
WaitForIdleTaskQueue();
@@ -1597,7 +1630,8 @@ TEST_F(FeedApiTest, StorePendingActionAndUploadNow) {
TEST_F(FeedApiTest, ProcessViewActionResultsInDelayedUpload) {
network_.consistency_token = "token-11";
- stream_->ProcessViewAction(MakeFeedAction(42ul).SerializeAsString());
+ stream_->ProcessViewAction(MakeFeedAction(42ul).SerializeAsString(),
+ CreateLoggingParameters());
WaitForIdleTaskQueue();
// Verify it's not uploaded immediately.
ASSERT_EQ(0, network_.GetActionRequestCount());
@@ -1610,16 +1644,30 @@ TEST_F(FeedApiTest, ProcessViewActionResultsInDelayedUpload) {
EXPECT_EQ(1, network_.GetActionRequestCount());
}
+TEST_F(FeedApiTest, ProcessViewActionDroppedBecauseNotEnabled) {
+ network_.consistency_token = "token-11";
+ LoggingParameters logging_parameters = CreateLoggingParameters();
+ logging_parameters.view_actions_enabled = false;
+ stream_->ProcessViewAction(MakeFeedAction(42ul).SerializeAsString(),
+ logging_parameters);
+ WaitForIdleTaskQueue();
+ // Verify it's not uploaded, and not stored.
+ ASSERT_EQ(0, network_.GetActionRequestCount());
+ ASSERT_EQ(0ull, ReadStoredActions(stream_->GetStore()).size());
+}
+
TEST_F(FeedApiTest, ActionsUploadWithoutConditionsWhenFeatureDisabled) {
response_translator_.InjectResponse(MakeTypicalInitialModelState());
TestForYouSurface surface(stream_.get());
WaitForIdleTaskQueue();
stream_->ProcessViewAction(
- feedwire::FeedAction::default_instance().SerializeAsString());
+ feedwire::FeedAction::default_instance().SerializeAsString(),
+ surface.GetLoggingParameters());
WaitForIdleTaskQueue();
stream_->ProcessThereAndBackAgain(
- MakeThereAndBackAgainData(42ul).SerializeAsString());
+ MakeThereAndBackAgainData(42ul).SerializeAsString(),
+ surface.GetLoggingParameters());
WaitForIdleTaskQueue();
// Verify the actions were uploaded.
@@ -1628,7 +1676,8 @@ TEST_F(FeedApiTest, ActionsUploadWithoutConditionsWhenFeatureDisabled) {
}
TEST_F(FeedApiTest, LoadStreamFromNetworkUploadsActions) {
- stream_->UploadAction(MakeFeedAction(99ul), false, base::DoNothing());
+ stream_->UploadAction(MakeFeedAction(99ul), CreateLoggingParameters(), false,
+ base::DoNothing());
WaitForIdleTaskQueue();
TestForYouSurface surface(stream_.get());
@@ -1638,7 +1687,8 @@ TEST_F(FeedApiTest, LoadStreamFromNetworkUploadsActions) {
EXPECT_EQ(1, network_.GetActionRequestSent()->feed_actions_size());
// Uploaded action should have been erased from store.
- stream_->UploadAction(MakeFeedAction(100ul), true, base::DoNothing());
+ stream_->UploadAction(MakeFeedAction(100ul), CreateLoggingParameters(), true,
+ base::DoNothing());
WaitForIdleTaskQueue();
EXPECT_EQ(2, network_.GetActionRequestCount());
EXPECT_EQ(1, network_.GetActionRequestSent()->feed_actions_size());
@@ -1646,15 +1696,19 @@ TEST_F(FeedApiTest, LoadStreamFromNetworkUploadsActions) {
TEST_F(FeedApiTest, UploadedActionsHaveSequentialNumbers) {
// Send 3 actions.
- stream_->UploadAction(MakeFeedAction(1ul), false, base::DoNothing());
- stream_->UploadAction(MakeFeedAction(2ul), false, base::DoNothing());
- stream_->UploadAction(MakeFeedAction(3ul), true, base::DoNothing());
+ stream_->UploadAction(MakeFeedAction(1ul), CreateLoggingParameters(), false,
+ base::DoNothing());
+ stream_->UploadAction(MakeFeedAction(2ul), CreateLoggingParameters(), false,
+ base::DoNothing());
+ stream_->UploadAction(MakeFeedAction(3ul), CreateLoggingParameters(), true,
+ base::DoNothing());
WaitForIdleTaskQueue();
ASSERT_EQ(1, network_.GetActionRequestCount());
feedwire::UploadActionsRequest request1 = *network_.GetActionRequestSent();
// Send another action in a new request.
- stream_->UploadAction(MakeFeedAction(4ul), true, base::DoNothing());
+ stream_->UploadAction(MakeFeedAction(4ul), CreateLoggingParameters(), true,
+ base::DoNothing());
WaitForIdleTaskQueue();
ASSERT_EQ(2, network_.GetActionRequestCount());
feedwire::UploadActionsRequest request2 = *network_.GetActionRequestSent();
@@ -1674,7 +1728,8 @@ TEST_F(FeedApiTest, LoadMoreUploadsActions) {
TestForYouSurface surface(stream_.get());
WaitForIdleTaskQueue();
- stream_->UploadAction(MakeFeedAction(99ul), false, base::DoNothing());
+ stream_->UploadAction(MakeFeedAction(99ul), CreateLoggingParameters(), false,
+ base::DoNothing());
WaitForIdleTaskQueue();
network_.consistency_token = "token-12";
@@ -1687,7 +1742,8 @@ TEST_F(FeedApiTest, LoadMoreUploadsActions) {
// Uploaded action should have been erased from the store.
network_.ClearTestData();
- stream_->UploadAction(MakeFeedAction(100ul), true, base::DoNothing());
+ stream_->UploadAction(MakeFeedAction(100ul), CreateLoggingParameters(), true,
+ base::DoNothing());
WaitForIdleTaskQueue();
EXPECT_EQ(1, network_.GetActionRequestSent()->feed_actions_size());
@@ -1697,32 +1753,25 @@ TEST_F(FeedApiTest, LoadMoreUploadsActions) {
network_.GetActionRequestSent()->feed_actions(0).action_payload()));
}
-TEST_F(FeedApiTest, LoadMoreUpdatesIsActivityLoggingEnabled) {
- EXPECT_FALSE(stream_->IsActivityLoggingEnabled(kForYouStream));
+TEST_F(FeedApiTest, LoadMoreDoesNotUpdateLoggingEnabled) {
response_translator_.InjectResponse(MakeTypicalInitialModelState());
TestForYouSurface surface(stream_.get());
WaitForIdleTaskQueue();
- EXPECT_TRUE(stream_->IsActivityLoggingEnabled(kForYouStream));
+ EXPECT_TRUE(surface.update->logging_parameters().logging_enabled());
int page = 2;
- for (bool signed_in : {true, false}) {
- for (bool waa_on : {true, false}) {
- for (bool privacy_notice_fulfilled : {true, false}) {
- response_translator_.InjectResponse(
- MakeTypicalNextPageState(page++, kTestTimeEpoch, signed_in, waa_on,
- privacy_notice_fulfilled));
- CallbackReceiver<bool> callback;
- stream_->LoadMore(surface, callback.Bind());
- WaitForIdleTaskQueue();
- EXPECT_EQ(
- stream_->IsActivityLoggingEnabled(kForYouStream),
- (signed_in && waa_on) ||
- (!signed_in && GetFeedConfig().send_signed_out_session_logs))
- << "signed_in=" << signed_in << " waa_on=" << waa_on
- << " privacy_notice_fulfilled=" << privacy_notice_fulfilled
- << " send_signed_out_session_logs="
- << GetFeedConfig().send_signed_out_session_logs;
- }
+ // A NextPage request will not work when signed-out.
+ const bool signed_in = true;
+
+ // Logging parameters are not updated on LoadMore(), so logging remains
+ // enabled until the next refresh.
+ for (bool waa_on : {true, false}) {
+ for (bool privacy_notice_fulfilled : {true, false}) {
+ response_translator_.InjectResponse(MakeTypicalNextPageState(
+ page++, kTestTimeEpoch, signed_in, waa_on, privacy_notice_fulfilled));
+ stream_->LoadMore(surface, base::DoNothing());
+ WaitForIdleTaskQueue();
+ EXPECT_TRUE(surface.update->logging_parameters().logging_enabled());
}
}
}
@@ -1731,13 +1780,14 @@ TEST_F(FeedApiTest, LoadStreamWithLoggingEnabled) {
response_translator_.InjectResponse(MakeTypicalInitialModelState());
TestForYouSurface surface(stream_.get());
WaitForIdleTaskQueue();
- EXPECT_TRUE(stream_->IsActivityLoggingEnabled(kForYouStream));
+ EXPECT_TRUE(surface.update->logging_parameters().logging_enabled());
EXPECT_EQ("loading -> [user@foo] 2 slices", surface.DescribeUpdates());
}
TEST_F(FeedApiTest, BackgroundingAppUploadsActions) {
- stream_->UploadAction(MakeFeedAction(1ul), false, base::DoNothing());
+ stream_->UploadAction(MakeFeedAction(1ul), CreateLoggingParameters(), false,
+ base::DoNothing());
stream_->OnEnterBackground();
WaitForIdleTaskQueue();
EXPECT_EQ(1, network_.GetActionRequestSent()->feed_actions_size());
@@ -1752,14 +1802,16 @@ TEST_F(FeedApiTest, BackgroundingAppDoesNotUploadActions) {
config.upload_actions_on_enter_background = false;
SetFeedConfigForTesting(config);
- stream_->UploadAction(MakeFeedAction(1ul), false, base::DoNothing());
+ stream_->UploadAction(MakeFeedAction(1ul), CreateLoggingParameters(), false,
+ base::DoNothing());
stream_->OnEnterBackground();
WaitForIdleTaskQueue();
EXPECT_EQ(0, network_.GetActionRequestCount());
}
TEST_F(FeedApiTest, UploadedActionsAreNotSentAgain) {
- stream_->UploadAction(MakeFeedAction(1ul), false, base::DoNothing());
+ stream_->UploadAction(MakeFeedAction(1ul), CreateLoggingParameters(), false,
+ base::DoNothing());
stream_->OnEnterBackground();
WaitForIdleTaskQueue();
ASSERT_EQ(1, network_.GetActionRequestCount());
@@ -1777,7 +1829,8 @@ TEST_F(FeedApiTest, UploadActionsOneBatch) {
EXPECT_EQ(1, network_.GetActionRequestCount());
EXPECT_EQ(3, network_.GetActionRequestSent()->feed_actions_size());
- stream_->UploadAction(MakeFeedAction(99ul), true, base::DoNothing());
+ stream_->UploadAction(MakeFeedAction(99ul), CreateLoggingParameters(), true,
+ base::DoNothing());
WaitForIdleTaskQueue();
EXPECT_EQ(2, network_.GetActionRequestCount());
EXPECT_EQ(1, network_.GetActionRequestSent()->feed_actions_size());
@@ -1799,20 +1852,23 @@ TEST_F(FeedApiTest, UploadActionsMultipleBatches) {
EXPECT_EQ(3, network_.GetActionRequestCount());
- stream_->UploadAction(MakeFeedAction(99ul), true, base::DoNothing());
+ stream_->UploadAction(MakeFeedAction(99ul), CreateLoggingParameters(), true,
+ base::DoNothing());
WaitForIdleTaskQueue();
EXPECT_EQ(4, network_.GetActionRequestCount());
EXPECT_EQ(1, network_.GetActionRequestSent()->feed_actions_size());
}
TEST_F(FeedApiTest, UploadActionsSkipsStaleActionsByTimestamp) {
- stream_->UploadAction(MakeFeedAction(2ul), false, base::DoNothing());
+ stream_->UploadAction(MakeFeedAction(2ul), CreateLoggingParameters(), false,
+ base::DoNothing());
WaitForIdleTaskQueue();
task_environment_.FastForwardBy(base::Hours(25));
// Trigger upload
CallbackReceiver<UploadActionsTask::Result> cr;
- stream_->UploadAction(MakeFeedAction(3ul), true, cr.Bind());
+ stream_->UploadAction(MakeFeedAction(3ul), CreateLoggingParameters(), true,
+ cr.Bind());
WaitForIdleTaskQueue();
// Just one action should have been uploaded.
@@ -1831,14 +1887,18 @@ TEST_F(FeedApiTest, UploadActionsSkipsStaleActionsByTimestamp) {
TEST_F(FeedApiTest, UploadActionsErasesStaleActionsByAttempts) {
// Three failed uploads, plus one more to cause the first action to be erased.
network_.InjectEmptyActionRequestResult();
- stream_->UploadAction(MakeFeedAction(0ul), true, base::DoNothing());
+ stream_->UploadAction(MakeFeedAction(0ul), CreateLoggingParameters(), true,
+ base::DoNothing());
network_.InjectEmptyActionRequestResult();
- stream_->UploadAction(MakeFeedAction(1ul), true, base::DoNothing());
+ stream_->UploadAction(MakeFeedAction(1ul), CreateLoggingParameters(), true,
+ base::DoNothing());
network_.InjectEmptyActionRequestResult();
- stream_->UploadAction(MakeFeedAction(2ul), true, base::DoNothing());
+ stream_->UploadAction(MakeFeedAction(2ul), CreateLoggingParameters(), true,
+ base::DoNothing());
CallbackReceiver<UploadActionsTask::Result> cr;
- stream_->UploadAction(MakeFeedAction(3ul), true, cr.Bind());
+ stream_->UploadAction(MakeFeedAction(3ul), CreateLoggingParameters(), true,
+ cr.Bind());
WaitForIdleTaskQueue();
// Four requests, three pending actions in the last request.
@@ -1858,7 +1918,7 @@ TEST_F(FeedApiTest, MetadataLoadedWhenDatabaseInitialized) {
feedstore::Metadata initial_metadata;
feedstore::SetSessionId(initial_metadata, "session-id", kExpiry);
initial_metadata.set_consistency_token("token");
- initial_metadata.set_gaia(GetSyncSignedInGaia());
+ initial_metadata.set_gaia(GetAccountInfo().gaia);
store_->WriteMetadata(initial_metadata, base::DoNothing());
}
@@ -2016,7 +2076,7 @@ TEST_F(FeedApiTest, SignedOutSessionIdConsistency) {
const std::string kSessionToken1("session-token-1");
const std::string kSessionToken2("session-token-2");
- signed_in_gaia_ = "";
+ account_info_ = {};
StreamModelUpdateRequestGenerator model_generator;
model_generator.signed_in = false;
@@ -2116,7 +2176,7 @@ TEST_F(FeedApiTest, SignedOutSessionIdConsistency) {
}
TEST_F(FeedApiTest, ClearAllResetsSessionId) {
- signed_in_gaia_ = "";
+ account_info_ = {};
// Initialize a session id.
feedstore::Metadata metadata = stream_->GetMetadata();
@@ -2137,7 +2197,7 @@ TEST_F(FeedApiTest, SignedOutSessionIdExpiry) {
const std::string kSessionToken1("session-token-1");
const std::string kSessionToken2("session-token-2");
- signed_in_gaia_ = "";
+ account_info_ = {};
StreamModelUpdateRequestGenerator model_generator;
model_generator.signed_in = false;
@@ -2206,7 +2266,7 @@ TEST_F(FeedApiTest, SessionIdPersistsAcrossStreamLoads) {
StreamModelUpdateRequestGenerator model_generator;
model_generator.signed_in = false;
- signed_in_gaia_ = "";
+ account_info_ = {};
// (1) Do an initial load of the store
// - this should trigger a network request
@@ -2497,8 +2557,51 @@ TEST_F(FeedApiTest, ClearAllOnStartupIfFeedIsDisabled) {
// Re-create the feed, and verify ClearAll isn't called again.
on_clear_all.Clear();
+ base::HistogramTester histograms;
CreateStream();
EXPECT_FALSE(on_clear_all.called());
+ histograms.ExpectUniqueSample("ContentSuggestions.Feed.UserSettingsOnStart",
+ UserSettingsOnStart::kFeedNotEnabledByPolicy,
+ 1);
+}
+
+TEST_F(FeedApiTest, ReportUserSettingsFromMetadataWaaOnDpOff) {
+ // Fetch a feed, so that there's stored data.
+ {
+ RefreshResponseData response;
+ response.model_update_request = MakeTypicalInitialModelState();
+ response.web_and_app_activity_enabled = true;
+ response_translator_.InjectResponse(std::move(response));
+ }
+ TestForYouSurface surface(stream_.get());
+ WaitForIdleTaskQueue();
+
+ // Simulate a Chrome restart.
+ base::HistogramTester histograms;
+ CreateStream();
+ histograms.ExpectUniqueSample("ContentSuggestions.Feed.UserSettingsOnStart",
+ UserSettingsOnStart::kSignedInWaaOnDpOff, 1);
+ EXPECT_EQ(
+ std::vector<std::string>({"SignedInNoRecentData", "SignedInWaaOnDpOff"}),
+ register_feed_user_settings_field_trial_calls_);
+}
+
+TEST_F(FeedApiTest, ReportUserSettingsFromMetadataWaaOffDpOn) {
+ // Fetch a feed, so that there's stored data.
+ {
+ RefreshResponseData response;
+ response.model_update_request = MakeTypicalInitialModelState();
+ response.discover_personalization_enabled = true;
+ response_translator_.InjectResponse(std::move(response));
+ }
+ TestForYouSurface surface(stream_.get());
+ WaitForIdleTaskQueue();
+
+ // Simulate a Chrome restart.
+ base::HistogramTester histograms;
+ CreateStream();
+ histograms.ExpectUniqueSample("ContentSuggestions.Feed.UserSettingsOnStart",
+ UserSettingsOnStart::kSignedInWaaOffDpOn, 1);
}
TEST_F(FeedStreamTestForAllStreamTypes, ManualRefreshInterestFeedSuccess) {
@@ -2519,6 +2622,13 @@ TEST_F(FeedStreamTestForAllStreamTypes, ManualRefreshInterestFeedSuccess) {
EXPECT_EQ("3 slices", surface.DescribeUpdates());
EXPECT_EQ(LoadStreamStatus::kLoadedFromNetwork,
metrics_reporter_->load_stream_status);
+
+ // Check that the root event ID has been updated.
+ EXPECT_EQ(MakeTypicalRefreshModelState()->stream_data.root_event_id(),
+ surface.update->logging_parameters().root_event_id());
+ EXPECT_NE(MakeTypicalInitialModelState()->stream_data.root_event_id(),
+ surface.update->logging_parameters().root_event_id());
+
// Verify stored state is equivalent to in-memory model.
EXPECT_STRINGS_EQUAL(
stream_->GetModel(surface.GetStreamType())->DumpStateForTesting(),
@@ -2781,7 +2891,7 @@ TEST_F(FeedApiTest, ContentOrderPrefOverridesFinch) {
// This is a regression test for crbug.com/1249772.
TEST_F(FeedApiTest, SignInWhileSurfaceIsOpen) {
- signed_in_gaia_.clear(); // not signed in initially.
+ account_info_ = {}; // not signed in initially.
// Load content and simulate a restart, so that there is stored content.
{
response_translator_.InjectResponse(MakeTypicalInitialModelState());
@@ -2796,7 +2906,7 @@ TEST_F(FeedApiTest, SignInWhileSurfaceIsOpen) {
stream_->ReportFeedViewed(surface.GetStreamType(), surface.GetSurfaceId());
TestUnreadContentObserver observer;
stream_->AddUnreadContentObserver(kForYouStream, &observer);
- signed_in_gaia_ = "gaia";
+ account_info_ = TestAccountInfo();
stream_->OnSignedIn();
response_translator_.InjectResponse(MakeTypicalRefreshModelState());
WaitForIdleTaskQueue();
@@ -2812,7 +2922,7 @@ TEST_F(FeedApiTest, SignOutWhileSurfaceIsOpen) {
response_translator_.InjectResponse(MakeTypicalInitialModelState());
TestForYouSurface surface(stream_.get());
WaitForIdleTaskQueue();
- signed_in_gaia_ = "";
+ account_info_ = {};
stream_->OnSignedOut();
response_translator_.InjectResponse(MakeTypicalRefreshModelState());
WaitForIdleTaskQueue();
diff --git a/chromium/components/feed/core/v2/api_test/feed_api_subscriptions_unittest.cc b/chromium/components/feed/core/v2/api_test/feed_api_subscriptions_unittest.cc
index 354b5822876..b56d6e45807 100644
--- a/chromium/components/feed/core/v2/api_test/feed_api_subscriptions_unittest.cc
+++ b/chromium/components/feed/core/v2/api_test/feed_api_subscriptions_unittest.cc
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "components/feed/core/proto/v2/wire/web_feeds.pb.h"
#include "components/feed/core/v2/api_test/feed_api_test.h"
@@ -14,6 +15,8 @@
#include "components/feed/core/v2/public/types.h"
#include "components/feed/core/v2/public/web_feed_subscriptions.h"
#include "components/feed/core/v2/test/callback_receiver.h"
+#include "components/feed/core/v2/test/proto_printer.h"
+#include "components/feed/core/v2/web_feed_subscription_coordinator.h"
#include "components/feed/feed_feature_list.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -23,6 +26,10 @@ namespace test {
namespace {
using testing::PrintToString;
+AccountInfo TestAccountInfo() {
+ return {"examplegaia", "example@foo.com"};
+}
+
FeedNetwork::RawResponse MakeFailedResponse() {
FeedNetwork::RawResponse network_response;
network_response.response_info.status_code = 400;
@@ -42,10 +49,26 @@ void WriteRecommendedFeeds(
store.WriteRecommendedFeeds(index, recommended_feeds, base::DoNothing());
}
+void WriteSubscribedFeeds(
+ FeedStore& store,
+ std::vector<feedstore::WebFeedInfo> recommended_feeds) {
+ feedstore::SubscribedWebFeeds record;
+ for (const feedstore::WebFeedInfo& info : recommended_feeds) {
+ *record.add_feeds() = info;
+ }
+ record.set_update_time_millis(
+ feedstore::ToTimestampMillis(base::Time::Now()));
+
+ store.WriteSubscribedFeeds(record, base::DoNothing());
+}
+
class FeedApiSubscriptionsTest : public FeedApiTest {
public:
void SetUp() override {
FeedApiTest::SetUp();
+ subscriptions().SetHooksForTesting(&web_feed_subscription_hooks);
+ web_feed_subscription_hooks.before_clear_all = base::DoNothing();
+ web_feed_subscription_hooks.after_clear_all = base::DoNothing();
}
// The test fixture disables the delayed fetch after startup. This function
@@ -72,6 +95,30 @@ class FeedApiSubscriptionsTest : public FeedApiTest {
return result;
}
+ // The stored pending operations in WebFeedMetadataModel are eventually
+ // consistent with those in the database. This verifies that the in-memory
+ // copy in WebFeedMetadataModel are equivalent to the stored copy.
+ void CheckPendingOperationsAreStored() {
+ std::vector<feedstore::PendingWebFeedOperation> stored =
+ GetAllPendingOperations();
+ std::vector<feedstore::PendingWebFeedOperation> in_memory =
+ subscriptions().GetPendingOperationStateForTesting();
+ auto sort_fn = [](feedstore::PendingWebFeedOperation& a,
+ feedstore::PendingWebFeedOperation& b) {
+ return a.id() < b.id();
+ };
+ std::sort(stored.begin(), stored.end(), sort_fn);
+ std::sort(in_memory.begin(), in_memory.end(), sort_fn);
+ EXPECT_EQ(PrintToString(stored), PrintToString(in_memory));
+ }
+
+ std::vector<feedstore::PendingWebFeedOperation> GetAllPendingOperations() {
+ // Get subscriptions stored in memory.
+ CallbackReceiver<FeedStore::WebFeedStartupData> startup_data;
+ store_->ReadWebFeedStartupData(startup_data.Bind());
+ return startup_data.RunAndGetResult().pending_operations;
+ }
+
// Get all recommended web feeds.
std::vector<WebFeedMetadata> GetRecommendedFeeds() {
std::vector<WebFeedIndex::Entry> index_entries =
@@ -102,6 +149,13 @@ class FeedApiSubscriptionsTest : public FeedApiTest {
return recommended_feeds;
}
+ WebFeedMetadata FindWebFeedInfoForWebFeedIdSync(
+ const std::string& web_feed_id) {
+ CallbackReceiver<WebFeedMetadata> callback;
+ subscriptions().FindWebFeedInfoForWebFeedId(web_feed_id, callback.Bind());
+ return callback.RunAndGetResult();
+ }
+
void InjectRecommendedWebFeedsResponse(
std::vector<feedwire::webfeed::WebFeed> web_feeds) {
feedwire::webfeed::ListRecommendedWebFeedsResponse response;
@@ -111,9 +165,20 @@ class FeedApiSubscriptionsTest : public FeedApiTest {
network_.InjectResponse(response);
}
+ void SetupWithSubscriptions(
+ std::vector<feedwire::webfeed::WebFeed> subscribed_feeds) {
+ CallbackReceiver<WebFeedSubscriptions::RefreshResult> refresh_result;
+ network_.InjectListWebFeedsResponse(subscribed_feeds);
+ subscriptions().RefreshSubscriptions(refresh_result.Bind());
+ refresh_result.RunUntilCalled();
+ }
+
WebFeedSubscriptionCoordinator& subscriptions() {
return stream_->subscriptions();
}
+
+ protected:
+ WebFeedSubscriptionCoordinator::HooksForTesting web_feed_subscription_hooks;
};
TEST_F(FeedApiSubscriptionsTest, FollowWebFeedSuccess) {
@@ -129,14 +194,13 @@ TEST_F(FeedApiSubscriptionsTest, FollowWebFeedSuccess) {
WebFeedPageInformation page_info =
MakeWebFeedPageInformation("http://cats.com");
page_info.SetRssUrls({GURL("http://rss1/"), GURL("http://rss2/")});
-
subscriptions().FollowWebFeed(page_info, callback.Bind());
-
EXPECT_EQ(WebFeedSubscriptionRequestStatus::kSuccess,
callback.RunAndGetResult().request_status);
auto sent_request = network_.GetApiRequestSent<FollowWebFeedDiscoverApi>();
ASSERT_THAT(sent_request->page_rss_uris(),
testing::ElementsAre("http://rss1/", "http://rss2/"));
+ EXPECT_EQ(sent_request->canonical_uri(), "");
EXPECT_EQ("token", sent_request->consistency_token().token());
EXPECT_EQ(
"WebFeedMetadata{ id=id_cats title=Title cats "
@@ -157,13 +221,143 @@ TEST_F(FeedApiSubscriptionsTest, FollowWebFeedSuccess) {
"ContentSuggestions.Feed.WebFeed.NewFollow.IsRecommended", 0, 1);
}
+TEST_F(FeedApiSubscriptionsTest, FollowWebFeedAbortOnClearAll) {
+ // The goal of this test is to test the task order:
+ // ClearAllTask, SubscribeToWebFeedTask.
+
+ // Set up a function to fetch the status of the "cats" webfeed. First, use
+ // GetAllSubscriptions to force the internal model to load. This ensures that
+ // FindWebFeedInfoForWebFeedId() will call its callback without a PostTask.
+ subscriptions().GetAllSubscriptions(base::DoNothing());
+ WaitForIdleTaskQueue();
+
+ auto find_cats_subscription_status = [&]() {
+ CallbackReceiver<WebFeedMetadata> result;
+ subscriptions().FindWebFeedInfoForWebFeedId("cats", result.Bind());
+ EXPECT_TRUE(result.GetResult());
+ if (!result.GetResult())
+ return WebFeedSubscriptionStatus::kUnknown;
+ return result.GetResult()->subscription_status;
+ };
+
+ stream_->OnCacheDataCleared();
+ CallbackReceiver<WebFeedSubscriptions::FollowWebFeedResult> follow_callback;
+
+ // Try to follow cats.com.
+ subscriptions().FollowWebFeed("cats", /*is_durable_request=*/false,
+ follow_callback.Bind());
+ EXPECT_EQ(WebFeedSubscriptionStatus::kSubscribeInProgress,
+ find_cats_subscription_status());
+
+ // Run until ClearAllTask completes, this should update the subscription
+ // status.
+ base::RunLoop run_loop;
+ web_feed_subscription_hooks.after_clear_all =
+ base::BindLambdaForTesting([&]() {
+ // The Follow task has not yet completed, and the subscription is no
+ // longer in progress due to ClearAll.
+ EXPECT_FALSE(follow_callback.GetResult());
+ EXPECT_EQ(WebFeedSubscriptionStatus::kNotSubscribed,
+ find_cats_subscription_status());
+ run_loop.Quit();
+ });
+ run_loop.Run();
+
+ // Finally, let the subscription task complete.
+ EXPECT_EQ(WebFeedSubscriptionRequestStatus::
+ kAbortWebFeedSubscriptionPendingClearAll,
+ follow_callback.RunAndGetResult().request_status);
+ EXPECT_EQ(WebFeedSubscriptionStatus::kNotSubscribed,
+ find_cats_subscription_status());
+}
+
+TEST_F(FeedApiSubscriptionsTest, UnfollowWebFeedAbortOnClearAll) {
+ // Follow 'cats'.
+ network_.InjectResponse(SuccessfulFollowResponse("cats"));
+ CallbackReceiver<WebFeedSubscriptions::FollowWebFeedResult> follow_callback;
+ subscriptions().FollowWebFeed(MakeWebFeedPageInformation("http://cats.com"),
+ follow_callback.Bind());
+ follow_callback.RunUntilCalled();
+
+ // Test task order: ClearAllTask, UnsubscribeToWebFeedTask.
+ stream_->OnCacheDataCleared();
+ CallbackReceiver<WebFeedSubscriptions::UnfollowWebFeedResult>
+ unfollow_callback;
+ network_.InjectResponse(SuccessfulUnfollowResponse());
+ subscriptions().UnfollowWebFeed(
+ follow_callback.GetResult()->web_feed_metadata.web_feed_id,
+ /*is_durable_request=*/false, unfollow_callback.Bind());
+
+ EXPECT_EQ(WebFeedSubscriptionRequestStatus::
+ kAbortWebFeedSubscriptionPendingClearAll,
+ unfollow_callback.RunAndGetResult().request_status);
+}
+
+TEST_F(FeedApiSubscriptionsTest, SubscribedWebFeedsAreLoadedFromStore) {
+ // Store a subscribed web feed, and ensure it is loaded.
+ WriteSubscribedFeeds(*store_, {MakeWebFeedInfo("catfood")});
+
+ CallbackReceiver<std::vector<WebFeedMetadata>> subscriptions_callback;
+ subscriptions().GetAllSubscriptions(subscriptions_callback.Bind());
+
+ EXPECT_EQ(
+ "{ WebFeedMetadata{ id=id_catfood title=Title catfood "
+ "publisher_url=https://catfood.com/ status=kSubscribed } }",
+ PrintToString(subscriptions_callback.RunAndGetResult()));
+}
+
+TEST_F(FeedApiSubscriptionsTest, ClearAllAbortsModelLoad) {
+ // In this test, we want to trigger model loading, hit ClearAllFinished, and
+ // then verify the model loading completes. This unfortunately requires a
+ // test-only hook.
+
+ // Store a subscribed feed.
+ WriteSubscribedFeeds(*store_, {MakeWebFeedInfo("catfood")});
+
+ // Trigger ClearAll. Just before processing ClearAllFinished, trigger a model
+ // load.
+ CallbackReceiver<std::vector<WebFeedMetadata>> subscriptions_callback;
+ web_feed_subscription_hooks.before_clear_all =
+ base::BindLambdaForTesting([&]() {
+ subscriptions().GetAllSubscriptions(subscriptions_callback.Bind());
+ EXPECT_FALSE(subscriptions_callback.called());
+ EXPECT_TRUE(subscriptions().is_loading_model_for_testing());
+ });
+ stream_->OnCacheDataCleared();
+ WaitForIdleTaskQueue();
+
+ // Model should be loaded, and GetAllSubscriptions should complete.
+ EXPECT_TRUE(subscriptions_callback.called());
+ EXPECT_FALSE(subscriptions().is_loading_model_for_testing());
+ // This call uses the model, and confirms it is non-null.
+ EXPECT_EQ(WebFeedSubscriptionStatus::kUnknown,
+ subscriptions().FindSubscriptionInfoById("catfood").status);
+ // Unlike the SubscribedWebFeedsAreLoadedFromStore test, there are no
+ // subscribed feeds loaded.
+ EXPECT_EQ("{}", PrintToString(*subscriptions_callback.GetResult()));
+}
+
+TEST_F(FeedApiSubscriptionsTest, FollowWebFeedSendsCanonicalUrl) {
+ network_.InjectResponse(SuccessfulFollowResponse("cats"));
+ CallbackReceiver<WebFeedSubscriptions::FollowWebFeedResult> callback;
+ WebFeedPageInformation page_info =
+ MakeWebFeedPageInformation("http://cats.com");
+ page_info.SetCanonicalUrl(GURL("http://felis-catus.com"));
+ subscriptions().FollowWebFeed(page_info, callback.Bind());
+ callback.RunUntilCalled();
+
+ auto sent_request = network_.GetApiRequestSent<FollowWebFeedDiscoverApi>();
+ EXPECT_EQ("http://felis-catus.com/", sent_request->canonical_uri());
+}
+
TEST_F(FeedApiSubscriptionsTest, FollowRecommendedWebFeedById) {
base::HistogramTester histograms;
WriteRecommendedFeeds(*store_, {MakeWebFeedInfo("catfood")});
CreateStream();
network_.InjectResponse(SuccessfulFollowResponse("catfood"));
CallbackReceiver<WebFeedSubscriptions::FollowWebFeedResult> callback;
- subscriptions().FollowWebFeed("id_catfood", callback.Bind());
+ subscriptions().FollowWebFeed("id_catfood", /*is_durable_request=*/false,
+ callback.Bind());
EXPECT_EQ(
"WebFeedMetadata{ id=id_catfood is_recommended title=Title catfood "
"publisher_url=https://catfood.com/ status=kSubscribed }",
@@ -273,7 +467,8 @@ TEST_F(FeedApiSubscriptionsTest, CantFollowWebFeedByIdWhileOffline) {
network_.InjectResponse(SuccessfulFollowResponse("cats"));
CallbackReceiver<WebFeedSubscriptions::FollowWebFeedResult> callback;
- subscriptions().FollowWebFeed("feed_id", callback.Bind());
+ subscriptions().FollowWebFeed("feed_id", /*is_durable_request=*/false,
+ callback.Bind());
EXPECT_EQ(0, network_.GetFollowRequestCount());
EXPECT_EQ(WebFeedSubscriptionRequestStatus::kFailedOffline,
@@ -321,7 +516,7 @@ TEST_F(FeedApiSubscriptionsTest, UnfollowAFollowedWebFeed) {
network_.InjectResponse(SuccessfulUnfollowResponse());
subscriptions().UnfollowWebFeed(
follow_callback.GetResult()->web_feed_metadata.web_feed_id,
- unfollow_callback.Bind());
+ /*is_durable_request=*/false, unfollow_callback.Bind());
unfollow_callback.RunUntilCalled();
EXPECT_EQ(1, network_.GetUnfollowRequestCount());
@@ -356,10 +551,10 @@ TEST_F(FeedApiSubscriptionsTest, UnfollowAFollowedWebFeedTwiceAtOnce) {
network_.InjectResponse(SuccessfulUnfollowResponse());
subscriptions().UnfollowWebFeed(
follow_callback.GetResult()->web_feed_metadata.web_feed_id,
- unfollow_callback1.Bind());
+ /*is_durable_request=*/false, unfollow_callback1.Bind());
subscriptions().UnfollowWebFeed(
follow_callback.GetResult()->web_feed_metadata.web_feed_id,
- unfollow_callback2.Bind());
+ /*is_durable_request=*/false, unfollow_callback2.Bind());
unfollow_callback1.RunUntilCalled();
unfollow_callback2.RunUntilCalled();
@@ -385,7 +580,7 @@ TEST_F(FeedApiSubscriptionsTest, UnfollowNetworkFailure) {
stream_->SetStreamStale(kWebFeedStream, false);
subscriptions().UnfollowWebFeed(
follow_callback.GetResult()->web_feed_metadata.web_feed_id,
- unfollow_callback.Bind());
+ /*is_durable_request=*/false, unfollow_callback.Bind());
unfollow_callback.RunUntilCalled();
EXPECT_EQ(1, network_.GetUnfollowRequestCount());
@@ -412,7 +607,7 @@ TEST_F(FeedApiSubscriptionsTest, UnfollowWhileOffline) {
network_.InjectUnfollowResponse(MakeFailedResponse());
subscriptions().UnfollowWebFeed(
follow_callback.GetResult()->web_feed_metadata.web_feed_id,
- unfollow_callback.Bind());
+ /*is_durable_request=*/false, unfollow_callback.Bind());
unfollow_callback.RunUntilCalled();
EXPECT_EQ(0, network_.GetUnfollowRequestCount());
@@ -426,7 +621,8 @@ TEST_F(FeedApiSubscriptionsTest, UnfollowAnUnfollowedWebFeed) {
CallbackReceiver<WebFeedSubscriptions::UnfollowWebFeedResult>
unfollow_callback;
network_.InjectResponse(SuccessfulUnfollowResponse());
- subscriptions().UnfollowWebFeed("notfollowed", unfollow_callback.Bind());
+ subscriptions().UnfollowWebFeed("notfollowed", /*is_durable_request=*/false,
+ unfollow_callback.Bind());
unfollow_callback.RunUntilCalled();
EXPECT_EQ(0, network_.GetUnfollowRequestCount());
@@ -581,7 +777,7 @@ TEST_F(FeedApiSubscriptionsTest,
network_.InjectResponse(SuccessfulUnfollowResponse());
subscriptions().UnfollowWebFeed(
follow_callback.GetResult()->web_feed_metadata.web_feed_id,
- unfollow_callback.Bind());
+ /*is_durable_request=*/false, unfollow_callback.Bind());
{
CallbackReceiver<WebFeedMetadata> metadata;
@@ -632,7 +828,8 @@ TEST_F(FeedApiSubscriptionsTest, GetAllSubscriptionsWithSomeSubscriptions) {
network_.SendResponsesOnCommand(true);
CallbackReceiver<WebFeedSubscriptions::UnfollowWebFeedResult>
unfollow_callback;
- subscriptions().UnfollowWebFeed("id_dogs", unfollow_callback.Bind());
+ subscriptions().UnfollowWebFeed("id_dogs", /*is_durable_request=*/false,
+ unfollow_callback.Bind());
subscriptions().FollowWebFeed(MakeWebFeedPageInformation("http://mice.com"),
follow_callback.Bind());
@@ -719,7 +916,7 @@ TEST_F(FeedApiSubscriptionsTest, RecommendedWebFeedsAreClearedOnSignOut) {
}
// Sign out, and verify recommended web feeds are cleared.
- signed_in_gaia_ = "";
+ account_info_ = {};
stream_->OnSignedOut();
WaitForIdleTaskQueue();
ASSERT_EQ(1, network_.GetListRecommendedWebFeedsRequestCount());
@@ -739,12 +936,12 @@ TEST_F(FeedApiSubscriptionsTest,
ASSERT_EQ(1, network_.GetListRecommendedWebFeedsRequestCount());
// Sign out, this clears recommended Web Feeds.
- signed_in_gaia_ = "";
+ account_info_ = {};
stream_->OnSignedOut();
WaitForIdleTaskQueue();
// Sign in, and verify web feeds are fetched and stored.
- signed_in_gaia_ = "examplegaia";
+ account_info_ = TestAccountInfo();
stream_->OnSignedIn();
WaitForIdleTaskQueue();
@@ -861,7 +1058,7 @@ TEST_F(FeedApiSubscriptionsTest, SubscribedWebFeedsAreClearedOnSignOut) {
}
// Sign out, and verify recommended web feeds are cleared.
- signed_in_gaia_ = "";
+ account_info_ = {};
stream_->OnSignedOut();
WaitForIdleTaskQueue();
ASSERT_EQ(1, network_.GetListFollowedWebFeedsRequestCount());
@@ -881,14 +1078,14 @@ TEST_F(FeedApiSubscriptionsTest,
ASSERT_EQ(1, network_.GetListFollowedWebFeedsRequestCount());
// Sign out, and verify no web feeds are fetched.
- signed_in_gaia_ = "";
+ account_info_ = {};
stream_->OnSignedOut();
WaitForIdleTaskQueue();
ASSERT_EQ(1, network_.GetListFollowedWebFeedsRequestCount());
EXPECT_EQ("{}", PrintToString(CheckAllSubscriptions()));
// Sign in, and verify web feeds are fetched and stored.
- signed_in_gaia_ = "examplegaia";
+ account_info_ = TestAccountInfo();
stream_->OnSignedIn();
WaitForIdleTaskQueue();
@@ -1001,6 +1198,26 @@ TEST_F(FeedApiSubscriptionsTest, RefreshSubscriptionsDuringRefresh) {
PrintToString(CheckAllSubscriptions()));
}
+TEST_F(FeedApiSubscriptionsTest, FetchRecommendedWebFeedsAbortOnClearAll) {
+ // Test task ordering: ClearAllTask, FetchRecommendedWebFeedsTask.
+ stream_->OnCacheDataCleared();
+ CallbackReceiver<WebFeedSubscriptions::RefreshResult> callback;
+ InjectRecommendedWebFeedsResponse({MakeWireWebFeed("cats")});
+ subscriptions().RefreshRecommendedFeeds(callback.Bind());
+
+ EXPECT_FALSE(callback.RunAndGetResult().success);
+}
+
+TEST_F(FeedApiSubscriptionsTest, FetchSubscribedWebFeedsAbortOnClearAll) {
+ // Test task ordering: ClearAllTask, FetchSubscribedWebFeedsTask.
+ stream_->OnCacheDataCleared();
+ CallbackReceiver<WebFeedSubscriptions::RefreshResult> callback;
+ network_.InjectListWebFeedsResponse({MakeWireWebFeed("cats")});
+ subscriptions().RefreshSubscriptions(callback.Bind());
+
+ EXPECT_FALSE(callback.RunAndGetResult().success);
+}
+
TEST_F(FeedApiSubscriptionsTest, FieldTrialRegistered_OneFollow) {
// Follow one web feed, and recreate FeedStream to simulate a Chrome restart.
network_.InjectResponse(SuccessfulFollowResponse("cats"));
@@ -1018,6 +1235,226 @@ TEST_F(FeedApiSubscriptionsTest, FieldTrialRegistered_OneFollow) {
register_following_feed_follow_count_field_trial_calls_);
}
+TEST_F(FeedApiSubscriptionsTest, FollowWebFeedDurableSuccess) {
+ network_.InjectResponse(SuccessfulFollowResponse("cats"));
+ CallbackReceiver<WebFeedSubscriptions::FollowWebFeedResult> callback;
+
+ subscriptions().FollowWebFeed("cats", /*is_durable_request=*/true,
+ callback.Bind());
+
+ EXPECT_EQ(WebFeedSubscriptionRequestStatus::kSuccess,
+ callback.RunAndGetResult().request_status);
+ EXPECT_EQ("{}", PrintToString(GetAllPendingOperations()));
+ EXPECT_EQ("Subscribed to id_cats\n",
+ subscriptions().DescribeStateForTesting());
+ CheckPendingOperationsAreStored();
+}
+
+TEST_F(FeedApiSubscriptionsTest, FollowWebFeedDurable_RemainsAfterFailure) {
+ network_.InjectFollowResponse(MakeFailedResponse());
+ CallbackReceiver<WebFeedSubscriptions::FollowWebFeedResult> callback;
+
+ subscriptions().FollowWebFeed("id_cats", /*is_durable_request=*/true,
+ callback.Bind());
+
+ // The request fails, but we retain the pending operation.
+ EXPECT_EQ(WebFeedSubscriptionRequestStatus::kFailedUnknownError,
+ callback.RunAndGetResult().request_status);
+ EXPECT_EQ("Pending SUBSCRIBE id_cats attempts=1\n",
+ subscriptions().DescribeStateForTesting());
+ EXPECT_EQ(WebFeedSubscriptionStatus::kSubscribeInProgress,
+ FindWebFeedInfoForWebFeedIdSync("id_cats").subscription_status);
+ CheckPendingOperationsAreStored();
+}
+
+TEST_F(FeedApiSubscriptionsTest, UnfollowWebFeedDurable_RemainsAfterFailure) {
+ SetupWithSubscriptions({MakeWireWebFeed("cats")});
+
+ network_.InjectUnfollowResponse(MakeFailedResponse());
+ CallbackReceiver<WebFeedSubscriptions::UnfollowWebFeedResult> callback;
+ subscriptions().UnfollowWebFeed("id_cats", /*is_durable_request=*/true,
+ callback.Bind());
+
+ // The request fails, but we retain the pending operation.
+ EXPECT_EQ(WebFeedSubscriptionRequestStatus::kFailedUnknownError,
+ callback.RunAndGetResult().request_status);
+ EXPECT_EQ(
+ "Pending UNSUBSCRIBE id_cats attempts=1\n"
+ "Subscribed to id_cats\n",
+ subscriptions().DescribeStateForTesting());
+ EXPECT_EQ(WebFeedSubscriptionStatus::kUnsubscribeInProgress,
+ FindWebFeedInfoForWebFeedIdSync("id_cats").subscription_status);
+ CheckPendingOperationsAreStored();
+}
+
+TEST_F(FeedApiSubscriptionsTest, FollowWebFeedDurable_AbortsPreviousDurable) {
+ SetupWithSubscriptions({MakeWireWebFeed("cats")});
+
+ network_.InjectUnfollowResponse(MakeFailedResponse());
+ network_.InjectFollowResponse(MakeFailedResponse());
+
+ subscriptions().UnfollowWebFeed("id_cats", /*is_durable_request=*/true,
+ base::DoNothing());
+ WaitForIdleTaskQueue();
+ subscriptions().FollowWebFeed("id_cats", /*is_durable_request=*/true,
+ base::DoNothing());
+ WaitForIdleTaskQueue();
+
+ // The Follow request aborted the Unfollow request, so there are no pending
+ // requests.
+ EXPECT_EQ("Subscribed to id_cats\n",
+ subscriptions().DescribeStateForTesting());
+ CheckPendingOperationsAreStored();
+}
+
+TEST_F(FeedApiSubscriptionsTest, RetryPendingOperations_Success) {
+ SetupWithSubscriptions({MakeWireWebFeed("cats")});
+
+ network_.InjectUnfollowResponse(MakeFailedResponse());
+ network_.InjectFollowResponse(MakeFailedResponse());
+ subscriptions().UnfollowWebFeed("id_cats", /*is_durable_request=*/true,
+ base::DoNothing());
+ subscriptions().FollowWebFeed("id_dogs", /*is_durable_request=*/true,
+ base::DoNothing());
+ WaitForIdleTaskQueue();
+
+ network_.InjectResponse(SuccessfulUnfollowResponse());
+ network_.InjectResponse(SuccessfulFollowResponse("dogs"));
+ subscriptions().RetryPendingOperationsForTesting();
+ WaitForIdleTaskQueue();
+
+ EXPECT_EQ("Subscribed to id_dogs\n",
+ subscriptions().DescribeStateForTesting());
+ CheckPendingOperationsAreStored();
+}
+
+TEST_F(FeedApiSubscriptionsTest, RetryPendingOperations_Failure) {
+ SetupWithSubscriptions({MakeWireWebFeed("cats")});
+
+ network_.InjectUnfollowResponse(MakeFailedResponse());
+ network_.InjectFollowResponse(MakeFailedResponse());
+ subscriptions().UnfollowWebFeed("id_cats", /*is_durable_request=*/true,
+ base::DoNothing());
+ subscriptions().FollowWebFeed("id_dogs", /*is_durable_request=*/true,
+ base::DoNothing());
+ WaitForIdleTaskQueue();
+
+ network_.InjectUnfollowResponse(MakeFailedResponse());
+ network_.InjectFollowResponse(MakeFailedResponse());
+ subscriptions().RetryPendingOperationsForTesting();
+ WaitForIdleTaskQueue();
+
+ EXPECT_EQ(R"(Pending UNSUBSCRIBE id_cats attempts=2
+Pending SUBSCRIBE id_dogs attempts=2
+Subscribed to id_cats
+)",
+ subscriptions().DescribeStateForTesting());
+ CheckPendingOperationsAreStored();
+}
+
+TEST_F(FeedApiSubscriptionsTest, RetryPendingOperations_ExceedsRetryLimit) {
+ SetupWithSubscriptions({MakeWireWebFeed("cats")});
+
+ for (int i = 0; i < WebFeedInFlightChange::kMaxDurableOperationAttempts + 1;
+ ++i) {
+ network_.InjectUnfollowResponse(MakeFailedResponse());
+ network_.InjectFollowResponse(MakeFailedResponse());
+ }
+
+ subscriptions().UnfollowWebFeed("id_cats", /*is_durable_request=*/true,
+ base::DoNothing());
+ subscriptions().FollowWebFeed("id_dogs", /*is_durable_request=*/true,
+ base::DoNothing());
+ WaitForIdleTaskQueue();
+
+ for (int i = 0; i < WebFeedInFlightChange::kMaxDurableOperationAttempts;
+ ++i) {
+ subscriptions().RetryPendingOperationsForTesting();
+ WaitForIdleTaskQueue();
+ }
+
+ EXPECT_EQ(R"(Subscribed to id_cats
+)",
+ subscriptions().DescribeStateForTesting());
+ CheckPendingOperationsAreStored();
+}
+
+TEST_F(FeedApiSubscriptionsTest, RetryPendingOperations_AbortsWhenOffline) {
+ network_.InjectFollowResponse(MakeFailedResponse());
+ subscriptions().FollowWebFeed("id_dogs", /*is_durable_request=*/true,
+ base::DoNothing());
+ WaitForIdleTaskQueue();
+
+ is_offline_ = true;
+ subscriptions().RetryPendingOperationsForTesting();
+ WaitForIdleTaskQueue();
+
+ // Only one attempt has been tried.
+ EXPECT_EQ("Pending SUBSCRIBE id_dogs attempts=1\n",
+ subscriptions().DescribeStateForTesting());
+}
+
+TEST_F(FeedApiSubscriptionsTest, RefreshSubscriptions_TriggersRetryPending) {
+ network_.InjectFollowResponse(MakeFailedResponse());
+ subscriptions().FollowWebFeed("id_dogs", /*is_durable_request=*/true,
+ base::DoNothing());
+ WaitForIdleTaskQueue();
+
+ network_.InjectResponse(SuccessfulFollowResponse("dogs"));
+
+ // Use RefreshSubscriptions(),
+ CallbackReceiver<WebFeedSubscriptions::RefreshResult> refresh_callback;
+ network_.InjectListWebFeedsResponse(
+ {MakeWireWebFeed("dogs"), MakeWireWebFeed("cats")});
+ subscriptions().RefreshSubscriptions(refresh_callback.Bind());
+ EXPECT_TRUE(refresh_callback.RunAndGetResult().success);
+
+ // Make sure kListWebFeeds is last.
+ EXPECT_EQ(std::vector<NetworkRequestType>({
+ NetworkRequestType::kFollowWebFeed,
+ NetworkRequestType::kFollowWebFeed,
+ NetworkRequestType::kListWebFeeds,
+ }),
+ network_.sent_request_types());
+ EXPECT_EQ(
+ "Subscribed to id_dogs\n"
+ "Subscribed to id_cats\n",
+ subscriptions().DescribeStateForTesting());
+}
+
+TEST_F(FeedApiSubscriptionsTest, Startup_PendingRequestsAreEventuallyRetried) {
+ // Fail a durable request so that there is a pending request stored.
+ network_.InjectFollowResponse(MakeFailedResponse());
+ subscriptions().FollowWebFeed("id_dogs", /*is_durable_request=*/true,
+ base::DoNothing());
+ WaitForIdleTaskQueue();
+
+ // Simulate a restart, using the regular configuration that allows for delayed
+ // tasks at startup.
+ SetUpWithDefaultConfig();
+
+ // Wait and verify that the follow request is retried.
+ network_.InjectResponse(SuccessfulFollowResponse("dogs"));
+ task_environment_.FastForwardBy(GetFeedConfig().fetch_web_feed_info_delay +
+ base::Seconds(1));
+
+ EXPECT_EQ("Subscribed to id_dogs\n",
+ subscriptions().DescribeStateForTesting());
+}
+
+TEST_F(FeedApiSubscriptionsTest, PendingOperations_RemovedOnClearAll) {
+ network_.InjectFollowResponse(MakeFailedResponse());
+ subscriptions().FollowWebFeed("id_dogs", /*is_durable_request=*/true,
+ base::DoNothing());
+ WaitForIdleTaskQueue();
+
+ stream_->OnCacheDataCleared();
+ WaitForIdleTaskQueue();
+
+ EXPECT_EQ("", subscriptions().DescribeStateForTesting());
+ CheckPendingOperationsAreStored();
+}
+
} // namespace
} // namespace test
} // namespace feed
diff --git a/chromium/components/feed/core/v2/api_test/feed_api_test.cc b/chromium/components/feed/core/v2/api_test/feed_api_test.cc
index 900704cc4c6..e49a78cf56d 100644
--- a/chromium/components/feed/core/v2/api_test/feed_api_test.cc
+++ b/chromium/components/feed/core/v2/api_test/feed_api_test.cc
@@ -8,7 +8,9 @@
#include "components/feed/core/proto/v2/wire/web_feeds.pb.h"
#include "components/feed/core/v2/enums.h"
#include "components/feed/core/v2/feed_network.h"
+#include "components/feed/core/v2/public/logging_parameters.h"
#include "components/feed/core/v2/public/reliability_logging_bridge.h"
+#include "components/feed/core/v2/types.h"
#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
#include "base/callback.h"
@@ -50,7 +52,8 @@ std::unique_ptr<StreamModel> LoadModelFromStore(const StreamType& stream_type,
std::unique_ptr<StreamModelUpdateRequest> data =
StoredModelData(stream_type, store);
if (data) {
- auto model = std::make_unique<StreamModel>(context);
+ auto model = std::make_unique<StreamModel>(
+ context, MakeLoggingParameters("client-instance", *data));
model->Update(std::move(data));
return model;
}
@@ -67,8 +70,9 @@ std::unique_ptr<StreamModelUpdateRequest> StoredModelData(
LoadStreamFromStoreTask load_task(
LoadStreamFromStoreTask::LoadType::kFullLoad, nullptr, stream_type, store,
/*missed_last_refresh=*/false, base::BindLambdaForTesting(complete));
- // We want to load the data no matter how stale.
+ // We want to load the data no matter how stale, or which account.
load_task.IgnoreStalenessForTesting();
+ load_task.IngoreAccountForTesting();
base::RunLoop run_loop;
load_task.Execute(run_loop.QuitClosure());
@@ -86,7 +90,7 @@ std::string ModelStateFor(
std::vector<feedstore::DataOperation> operations,
std::vector<feedstore::DataOperation> more_operations) {
StreamModel::Context context;
- StreamModel model(&context);
+ StreamModel model(&context, LoggingParameters{});
model.Update(std::move(update_request));
model.ExecuteOperations(operations);
model.ExecuteOperations(more_operations);
@@ -110,7 +114,7 @@ feedwire::FeedAction MakeFeedAction(int64_t id, size_t pad_size) {
pad = " " + std::string(pad_size - 1, 'a');
}
- action.mutable_action_payload()->set_action_payload_data(
+ action.mutable_action_payload()->add_batched_action_payload_data(
base::StrCat({base::NumberToString(id), pad}));
return action;
}
@@ -212,6 +216,11 @@ std::map<std::string, std::string> TestSurfaceBase::GetDataStoreEntries()
const {
return data_store_entries_;
}
+LoggingParameters TestSurfaceBase::GetLoggingParameters() const {
+ if (update)
+ return FromProto(update->logging_parameters());
+ return {};
+}
std::string TestSurfaceBase::CurrentState() {
if (update && IsInitialLoadSpinnerUpdate(*update))
return "loading";
@@ -230,6 +239,7 @@ std::string TestSurfaceBase::CurrentState() {
if (update->logging_parameters().logging_enabled()) {
// View actions will always be enabled if logging is enabled.
CHECK(update->logging_parameters().view_actions_enabled());
+ CHECK_NE("", update->logging_parameters().email());
logging_parameters_description = update->logging_parameters().email();
} else if (!update->logging_parameters().email().empty()) {
if (update->logging_parameters().view_actions_enabled()) {
@@ -405,9 +415,10 @@ TestFeedNetwork::~TestFeedNetwork() = default;
void TestFeedNetwork::SendQueryRequest(
NetworkRequestType request_type,
const feedwire::Request& request,
- const std::string& gaia,
+ const AccountInfo& account_info,
base::OnceCallback<void(QueryRequestResult)> callback) {
- last_gaia = gaia;
+ sent_request_types_.push_back(NetworkRequestType::kFeedQuery);
+ last_account_info = account_info;
++send_query_call_count;
// Emulate a successful response.
// The response body is currently an empty message, because most of the
@@ -422,7 +433,7 @@ void TestFeedNetwork::SendQueryRequest(
result.response_info.response_body_bytes = 100;
result.response_info.fetch_duration = base::Milliseconds(42);
- result.response_info.was_signed_in = true;
+ result.response_info.account_info = account_info;
if (injected_response_) {
result.response_body = std::make_unique<feedwire::Response>(
std::move(injected_response_.value()));
@@ -467,9 +478,11 @@ void TestFeedNetwork::SendDiscoverApiRequest(
base::StringPiece api_path,
base::StringPiece method,
std::string request_bytes,
- const std::string& gaia,
+ const AccountInfo& account_info,
+ absl::optional<RequestMetadata> request_metadata,
base::OnceCallback<void(RawResponse)> callback) {
- last_gaia = gaia;
+ sent_request_types_.push_back(request_type);
+ last_account_info = account_info;
api_requests_sent_[request_type] = request_bytes;
++api_request_count_[request_type];
std::vector<RawResponse>& injected_responses =
@@ -656,17 +669,29 @@ TestWireResponseTranslator::~TestWireResponseTranslator() = default;
RefreshResponseData TestWireResponseTranslator::TranslateWireResponse(
feedwire::Response response,
StreamModelUpdateRequest::Source source,
- bool was_signed_in_request,
+ const AccountInfo& account_info,
base::Time current_time) const {
if (!injected_responses_.empty()) {
if (injected_responses_[0].model_update_request)
injected_responses_[0].model_update_request->source = source;
RefreshResponseData result = std::move(injected_responses_[0]);
injected_responses_.erase(injected_responses_.begin());
+ // Update the injected response so that it matches the account info.
+ if (result.model_update_request) {
+ if (account_info.IsEmpty()) {
+ result.model_update_request->stream_data.set_signed_in(false);
+ result.model_update_request->stream_data.clear_gaia();
+ result.model_update_request->stream_data.clear_email();
+ } else {
+ result.model_update_request->stream_data.set_signed_in(true);
+ result.model_update_request->stream_data.set_gaia(account_info.gaia);
+ result.model_update_request->stream_data.set_email(account_info.email);
+ }
+ }
return result;
}
return WireResponseTranslator::TranslateWireResponse(
- std::move(response), source, was_signed_in_request, current_time);
+ std::move(response), source, account_info, current_time);
}
void TestWireResponseTranslator::InjectResponse(
std::unique_ptr<StreamModelUpdateRequest> response,
@@ -825,17 +850,18 @@ bool FeedApiTest::IsEulaAccepted() {
bool FeedApiTest::IsOffline() {
return is_offline_;
}
-std::string FeedApiTest::GetSyncSignedInGaia() {
- return signed_in_gaia_;
-}
-std::string FeedApiTest::GetSyncSignedInEmail() {
- return signed_in_gaia_.empty() ? "" : signed_in_email_;
+AccountInfo FeedApiTest::GetAccountInfo() {
+ return account_info_;
}
void FeedApiTest::RegisterFollowingFeedFollowCountFieldTrial(
size_t follow_count) {
register_following_feed_follow_count_field_trial_calls_.push_back(
follow_count);
}
+void FeedApiTest::RegisterFeedUserSettingsFieldTrial(base::StringPiece group) {
+ register_feed_user_settings_field_trial_calls_.push_back(
+ static_cast<std::string>(group));
+}
DisplayMetrics FeedApiTest::GetDisplayMetrics() {
DisplayMetrics result;
result.density = 200;
@@ -875,7 +901,8 @@ void FeedApiTest::CreateStream(bool wait_for_initialization,
}
std::unique_ptr<StreamModel> FeedApiTest::CreateStreamModel() {
- return std::make_unique<StreamModel>(&stream_model_context_);
+ return std::make_unique<StreamModel>(&stream_model_context_,
+ LoggingParameters{});
}
bool FeedApiTest::IsTaskQueueIdle() const {
@@ -884,10 +911,23 @@ bool FeedApiTest::IsTaskQueueIdle() const {
}
void FeedApiTest::WaitForIdleTaskQueue() {
- RunLoopUntil(base::BindLambdaForTesting([&]() {
- return IsTaskQueueIdle() &&
- !stream_->subscriptions().is_loading_model_for_testing();
- }));
+ RunLoopUntil(
+ base::BindLambdaForTesting([&]() {
+ return IsTaskQueueIdle() &&
+ !stream_->subscriptions().is_loading_model_for_testing();
+ }),
+ base::BindLambdaForTesting([&]() -> std::string {
+ std::stringstream ss;
+ if (!IsTaskQueueIdle()) {
+ ss << "Task queue not idle. Queue state:\n"
+ << stream_->GetTaskQueueForTesting().GetStateForTesting() << '\n';
+ }
+ if (stream_->subscriptions().is_loading_model_for_testing()) {
+ ss << "Subscription model still loading\n";
+ }
+
+ return ss.str();
+ }));
}
void FeedApiTest::UnloadModel(const StreamType& stream_type) {
@@ -926,12 +966,19 @@ void FeedApiTest::FollowWebFeed(const WebFeedPageInformation page_info) {
EXPECT_EQ(WebFeedSubscriptionRequestStatus::kSuccess,
callback.RunAndGetResult().request_status);
}
-
+LoggingParameters FeedApiTest::CreateLoggingParameters() {
+ LoggingParameters result;
+ result.logging_enabled = true;
+ result.view_actions_enabled = true;
+ result.client_instance_id = "instance1";
+ result.email = account_info_.email;
+ return result;
+}
void FeedApiTest::UploadActions(std::vector<feedwire::FeedAction> actions) {
size_t actions_remaining = actions.size();
for (feedwire::FeedAction& action : actions) {
- stream_->UploadAction(action, (--actions_remaining) == 0ul,
- base::DoNothing());
+ stream_->UploadAction(action, CreateLoggingParameters(),
+ (--actions_remaining) == 0ul, base::DoNothing());
}
}
diff --git a/chromium/components/feed/core/v2/api_test/feed_api_test.h b/chromium/components/feed/core/v2/api_test/feed_api_test.h
index a0cef994d95..baa563bdc63 100644
--- a/chromium/components/feed/core/v2/api_test/feed_api_test.h
+++ b/chromium/components/feed/core/v2/api_test/feed_api_test.h
@@ -140,6 +140,8 @@ class TestSurfaceBase : public FeedStreamSurface {
std::string DescribeState();
std::map<std::string, std::string> GetDataStoreEntries() const;
+ // Returns the logging parameters last sent to the surface.
+ LoggingParameters GetLoggingParameters() const;
// The initial state of the stream, if it was received. This is nullopt if
// only the loading spinner was seen.
@@ -200,7 +202,7 @@ class TestFeedNetwork : public FeedNetwork {
void SendQueryRequest(
NetworkRequestType request_type,
const feedwire::Request& request,
- const std::string& gaia,
+ const AccountInfo& account_info,
base::OnceCallback<void(QueryRequestResult)> callback) override;
void SendDiscoverApiRequest(
@@ -208,7 +210,8 @@ class TestFeedNetwork : public FeedNetwork {
base::StringPiece api_path,
base::StringPiece method,
std::string request_bytes,
- const std::string& gaia,
+ const AccountInfo& account_info,
+ absl::optional<RequestMetadata> request_metadata,
base::OnceCallback<void(RawResponse)> callback) override;
void CancelRequests() override;
@@ -227,6 +230,7 @@ class TestFeedNetwork : public FeedNetwork {
response.response_info.status_code = 200;
response.response_bytes = response_message.SerializeAsString();
response.response_info.response_body_bytes = response.response_bytes.size();
+ response.response_info.account_info = last_account_info;
InjectApiRawResponse<API>(std::move(response));
}
@@ -260,6 +264,9 @@ class TestFeedNetwork : public FeedNetwork {
}
InjectResponse(response);
}
+ void InjectListWebFeedsResponse(const FeedNetwork::RawResponse& response) {
+ InjectApiRawResponse<ListWebFeedsDiscoverApi>(response);
+ }
void InjectEmptyActionRequestResult();
@@ -303,6 +310,10 @@ class TestFeedNetwork : public FeedNetwork {
return GetApiRequestCount<ListWebFeedsDiscoverApi>();
}
+ std::vector<NetworkRequestType> sent_request_types() const {
+ return sent_request_types_;
+ }
+
void ClearTestData();
// Enable (or disable) manual triggering of sending responses. When enabled,
@@ -314,7 +325,7 @@ class TestFeedNetwork : public FeedNetwork {
absl::optional<feedwire::Request> query_request_sent;
// Number of FeedQuery requests sent (including Web Feed ListContents).
int send_query_call_count = 0;
- std::string last_gaia;
+ AccountInfo last_account_info;
// The consistency token to use when constructing default network responses.
std::string consistency_token;
bool forced_signed_out_request = false;
@@ -331,6 +342,7 @@ class TestFeedNetwork : public FeedNetwork {
injected_api_responses_;
std::map<NetworkRequestType, std::string> api_requests_sent_;
std::map<NetworkRequestType, int> api_request_count_;
+ std::vector<NetworkRequestType> sent_request_types_;
absl::optional<feedwire::Response> injected_response_;
};
@@ -343,7 +355,7 @@ class TestWireResponseTranslator : public WireResponseTranslator {
RefreshResponseData TranslateWireResponse(
feedwire::Response response,
StreamModelUpdateRequest::Source source,
- bool was_signed_in_request,
+ const AccountInfo& account_info,
base::Time current_time) const override;
void InjectResponse(std::unique_ptr<StreamModelUpdateRequest> response,
absl::optional<std::string> session_id = absl::nullopt);
@@ -439,11 +451,11 @@ class FeedApiTest : public testing::Test, public FeedStream::Delegate {
std::string GetLanguageTag() override;
bool IsAutoplayEnabled() override;
void ClearAll() override;
- std::string GetSyncSignedInGaia() override;
- std::string GetSyncSignedInEmail() override;
+ AccountInfo GetAccountInfo() override;
void PrefetchImage(const GURL& url) override;
void RegisterExperiments(const Experiments& experiments) override {}
void RegisterFollowingFeedFollowCountFieldTrial(size_t follow_count) override;
+ void RegisterFeedUserSettingsFieldTrial(base::StringPiece group) override;
// For tests.
@@ -460,6 +472,9 @@ class FeedApiTest : public testing::Test, public FeedStream::Delegate {
std::string DumpStoreState(bool print_keys = false);
void UploadActions(std::vector<feedwire::FeedAction> actions);
+ // Returns some logging parameters for the current signed in user. Prefer to
+ // use the logging parameters passed to TestSurface*.
+ LoggingParameters CreateLoggingParameters();
protected:
base::test::TaskEnvironment task_environment_{
@@ -490,12 +505,12 @@ class FeedApiTest : public testing::Test, public FeedStream::Delegate {
std::unique_ptr<FeedStream> stream_;
bool is_eula_accepted_ = true;
bool is_offline_ = false;
- std::string signed_in_gaia_ = "examplegaia";
- std::string signed_in_email_ = "user@foo";
+ AccountInfo account_info_ = TestAccountInfo();
int prefetch_image_call_count_ = 0;
std::vector<GURL> prefetched_images_;
base::RepeatingClosure on_clear_all_;
std::vector<size_t> register_following_feed_follow_count_field_trial_calls_;
+ std::vector<std::string> register_feed_user_settings_field_trial_calls_;
private:
base::test::ScopedFeatureList scoped_feature_list_;
diff --git a/chromium/components/feed/core/v2/config.h b/chromium/components/feed/core/v2/config.h
index 80985522a75..26d5ce20f8c 100644
--- a/chromium/components/feed/core/v2/config.h
+++ b/chromium/components/feed/core/v2/config.h
@@ -67,6 +67,8 @@ struct Config {
base::TimeDelta web_feed_stale_content_threshold = base::Hours(1);
// TimeDelta after startup to fetch recommended and subscribed Web Feeds if
// they are stale. If zero, no fetching is done.
+ // This delay is also used to trigger retrying stored follow/unfollow requests
+ // on startup.
base::TimeDelta fetch_web_feed_info_delay = base::Seconds(40);
// How long before cached recommended feed data on the device is considered
// stale and refetched.
diff --git a/chromium/components/feed/core/v2/enums.cc b/chromium/components/feed/core/v2/enums.cc
index 7980cb932d5..6c17d4606d2 100644
--- a/chromium/components/feed/core/v2/enums.cc
+++ b/chromium/components/feed/core/v2/enums.cc
@@ -5,11 +5,42 @@
#include "components/feed/core/v2/enums.h"
#include <ostream>
+#include "base/strings/string_piece.h"
namespace feed {
// Included for debug builds only for reduced binary size.
+std::ostream& operator<<(std::ostream& out, NetworkRequestType value) {
+#ifndef NDEBUG
+ switch (value) {
+ case NetworkRequestType::kFeedQuery:
+ return out << "kFeedQuery";
+ case NetworkRequestType::kUploadActions:
+ return out << "kUploadActions";
+ case NetworkRequestType::kNextPage:
+ return out << "kNextPage";
+ case NetworkRequestType::kListWebFeeds:
+ return out << "kListWebFeeds";
+ case NetworkRequestType::kUnfollowWebFeed:
+ return out << "kUnfollowWebFeed";
+ case NetworkRequestType::kFollowWebFeed:
+ return out << "kFollowWebFeed";
+ case NetworkRequestType::kListRecommendedWebFeeds:
+ return out << "kListRecommendedWebFeeds";
+ case NetworkRequestType::kWebFeedListContents:
+ return out << "kWebFeedListContents";
+ case NetworkRequestType::kQueryInteractiveFeed:
+ return out << "kQueryInteractiveFeed";
+ case NetworkRequestType::kQueryBackgroundFeed:
+ return out << "kQueryBackgroundFeed";
+ case NetworkRequestType::kQueryNextPage:
+ return out << "kQueryNextPage";
+ }
+#endif
+ return out << (static_cast<int>(value));
+}
+
std::ostream& operator<<(std::ostream& out, LoadStreamStatus value) {
#ifndef NDEBUG
switch (value) {
@@ -69,6 +100,12 @@ std::ostream& operator<<(std::ostream& out, LoadStreamStatus value) {
return out << "kAlreadyHaveUnreadContent";
case LoadStreamStatus::kNotAWebFeedSubscriber:
return out << "kNotAWebFeedSubscriber";
+ case LoadStreamStatus::kAccountTokenFetchFailedWrongAccount:
+ return out << "kAccountTokenFetchFailedWrongAccount";
+ case LoadStreamStatus::kAccountTokenFetchTimedOut:
+ return out << "kAccountTokenFetchTimedOut";
+ case LoadStreamStatus::kNetworkFetchTimedOut:
+ return out << "kNetworkFetchTimedOut";
}
#else
return out << (static_cast<int>(value));
@@ -106,6 +143,10 @@ bool IsLoadingSuccessfulAndFresh(LoadStreamStatus status) {
case LoadStreamStatus::kAbortWithPendingClearAll:
case LoadStreamStatus::kAlreadyHaveUnreadContent:
case LoadStreamStatus::kNotAWebFeedSubscriber:
+
+ case LoadStreamStatus::kAccountTokenFetchFailedWrongAccount:
+ case LoadStreamStatus::kAccountTokenFetchTimedOut:
+ case LoadStreamStatus::kNetworkFetchTimedOut:
return false;
}
}
@@ -177,4 +218,31 @@ std::ostream& operator<<(std::ostream& out, WebFeedRefreshStatus value) {
}
}
+base::StringPiece ToString(UserSettingsOnStart v) {
+ switch (v) {
+ case UserSettingsOnStart::kFeedNotEnabledByPolicy:
+ return "FeedNotEnabledByPolicy";
+ case UserSettingsOnStart::kFeedNotVisibleSignedOut:
+ return "FeedNotVisibleSignedOut";
+ case UserSettingsOnStart::kFeedNotVisibleSignedIn:
+ return "FeedNotVisibleSignedIn";
+ case UserSettingsOnStart::kSignedOut:
+ return "SignedOut";
+ case UserSettingsOnStart::kSignedInWaaOnDpOn:
+ return "SignedInWaaOnDpOn";
+ case UserSettingsOnStart::kSignedInWaaOnDpOff:
+ return "SignedInWaaOnDpOff";
+ case UserSettingsOnStart::kSignedInWaaOffDpOn:
+ return "SignedInWaaOffDpOn";
+ case UserSettingsOnStart::kSignedInWaaOffDpOff:
+ return "SignedInWaaOffDpOff";
+ case UserSettingsOnStart::kSignedInNoRecentData:
+ return "SignedInNoRecentData";
+ }
+ return "Unknown";
+}
+std::ostream& operator<<(std::ostream& out, UserSettingsOnStart value) {
+ return out << ToString(value);
+}
+
} // namespace feed
diff --git a/chromium/components/feed/core/v2/enums.h b/chromium/components/feed/core/v2/enums.h
index 73c5cd30dc3..2468d7e409e 100644
--- a/chromium/components/feed/core/v2/enums.h
+++ b/chromium/components/feed/core/v2/enums.h
@@ -6,6 +6,7 @@
#define COMPONENTS_FEED_CORE_V2_ENUMS_H_
#include <iosfwd>
+#include "base/strings/string_piece_forward.h"
namespace feed {
@@ -23,6 +24,7 @@ enum class NetworkRequestType : int {
kQueryBackgroundFeed = 9,
kQueryNextPage = 10,
};
+std::ostream& operator<<(std::ostream& out, NetworkRequestType value);
// Denotes how the stream content loading is used for.
enum class LoadType {
@@ -81,7 +83,10 @@ enum class LoadStreamStatus {
kAbortWithPendingClearAll = 24,
kAlreadyHaveUnreadContent = 25,
kNotAWebFeedSubscriber = 26,
- kMaxValue = kNotAWebFeedSubscriber,
+ kAccountTokenFetchFailedWrongAccount = 27,
+ kAccountTokenFetchTimedOut = 28,
+ kNetworkFetchTimedOut = 29,
+ kMaxValue = kNetworkFetchTimedOut,
};
// Were we able to load fresh Feed data. This should be 'true' unless some kind
@@ -100,6 +105,7 @@ enum class UploadActionsStatus {
kUpdatedConsistencyToken = 4,
kFinishedWithoutUpdatingConsistencyToken = 5,
kAbortUploadForSignedOutUser = 6,
+ // TODO(b/213622639): This is unused, remove it.
kAbortUploadBecauseDisabled = 7,
kAbortUploadForWrongUser = 8,
kAbortUploadActionsWithPendingClearAll = 9,
@@ -151,6 +157,35 @@ enum class NoticeAcknowledgementPath {
kMaxValue = kViaDismissal,
};
+// This must be kept in sync with FeedUserSettingsOnStart in enums.xml.
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
+// Reports last known state of user settings which affect Feed content.
+// This includes WAA (whether activity is recorded), and DP (whether
+// Discover personalization is enabled).
+enum class UserSettingsOnStart {
+ // The Feed is disabled by enterprise policy.
+ kFeedNotEnabledByPolicy = 0,
+ // The Feed is enabled by enterprise policy, but the user has hidden and
+ // disabled the Feed, so other user settings beyond sign-in status are not
+ // available.
+ kFeedNotVisibleSignedOut = 1,
+ kFeedNotVisibleSignedIn = 2,
+ // The Feed is enabled, the user is not signed in.
+ kSignedOut = 3,
+ // The Feed is enabled, the user is signed in, and setting states are known.
+ kSignedInWaaOnDpOn = 4,
+ kSignedInWaaOnDpOff = 5,
+ kSignedInWaaOffDpOn = 6,
+ kSignedInWaaOffDpOff = 7,
+ // The Feed is enabled, but there is no recent Feed data, so user settings
+ // state is unknown.
+ kSignedInNoRecentData = 8,
+ kMaxValue = kSignedInNoRecentData,
+};
+base::StringPiece ToString(UserSettingsOnStart v);
+std::ostream& operator<<(std::ostream& out, UserSettingsOnStart value);
+
} // namespace feed
#endif // COMPONENTS_FEED_CORE_V2_ENUMS_H_
diff --git a/chromium/components/feed/core/v2/feed_network.h b/chromium/components/feed/core/v2/feed_network.h
index 489de1fe9d3..f79f341ebbe 100644
--- a/chromium/components/feed/core/v2/feed_network.h
+++ b/chromium/components/feed/core/v2/feed_network.h
@@ -17,6 +17,7 @@
#include "components/feed/core/proto/v2/wire/web_feeds.pb.h"
#include "components/feed/core/v2/enums.h"
#include "components/feed/core/v2/public/types.h"
+#include "components/feed/core/v2/types.h"
namespace feedwire {
class Request;
@@ -24,9 +25,12 @@ class Response;
} // namespace feedwire
namespace feed {
+struct AccountInfo;
// DiscoverApi types. Defines information about each discover API. For use with
// `FeedNetwork::SendApiRequest()`.
+// Some APIs do not send request metadata because it is already included in the
+// `feedwire::Request` proto and is therefore redundant.
struct QueryInteractiveFeedDiscoverApi {
using Request = feedwire::Request;
@@ -37,6 +41,7 @@ struct QueryInteractiveFeedDiscoverApi {
static base::StringPiece RequestPath(const Request&) {
return "v1:queryInteractiveFeed";
}
+ static bool SendRequestMetadata() { return false; }
};
struct QueryBackgroundFeedDiscoverApi {
@@ -48,6 +53,7 @@ struct QueryBackgroundFeedDiscoverApi {
static base::StringPiece RequestPath(const Request&) {
return "v1:queryBackgroundFeed";
}
+ static bool SendRequestMetadata() { return false; }
};
struct QueryNextPageDiscoverApi {
@@ -59,6 +65,7 @@ struct QueryNextPageDiscoverApi {
static base::StringPiece RequestPath(const Request&) {
return "v1:queryNextPage";
}
+ static bool SendRequestMetadata() { return false; }
};
struct UploadActionsDiscoverApi {
@@ -70,6 +77,7 @@ struct UploadActionsDiscoverApi {
static base::StringPiece RequestPath(const Request&) {
return "v1/actions:upload";
}
+ static bool SendRequestMetadata() { return true; }
};
struct ListWebFeedsDiscoverApi {
@@ -79,6 +87,7 @@ struct ListWebFeedsDiscoverApi {
NetworkRequestType::kListWebFeeds;
static base::StringPiece Method() { return "POST"; }
static base::StringPiece RequestPath(const Request&) { return "v1/webFeeds"; }
+ static bool SendRequestMetadata() { return true; }
};
struct ListRecommendedWebFeedDiscoverApi {
@@ -90,6 +99,7 @@ struct ListRecommendedWebFeedDiscoverApi {
static base::StringPiece RequestPath(const Request&) {
return "v1/recommendedWebFeeds";
}
+ static bool SendRequestMetadata() { return true; }
};
struct FollowWebFeedDiscoverApi {
@@ -101,6 +111,7 @@ struct FollowWebFeedDiscoverApi {
static base::StringPiece RequestPath(const Request&) {
return "v1:followWebFeed";
}
+ static bool SendRequestMetadata() { return true; }
};
struct UnfollowWebFeedDiscoverApi {
@@ -112,6 +123,7 @@ struct UnfollowWebFeedDiscoverApi {
static base::StringPiece RequestPath(const Request&) {
return "v1:unfollowWebFeed";
}
+ static bool SendRequestMetadata() { return true; }
};
struct WebFeedListContentsDiscoverApi {
@@ -121,6 +133,7 @@ struct WebFeedListContentsDiscoverApi {
NetworkRequestType::kWebFeedListContents;
static base::StringPiece Method() { return "POST"; }
static base::StringPiece RequestPath(const Request&) { return "v1/contents"; }
+ static bool SendRequestMetadata() { return false; }
};
class FeedNetwork {
@@ -164,7 +177,7 @@ class FeedNetwork {
virtual void SendQueryRequest(
NetworkRequestType request_type,
const feedwire::Request& request,
- const std::string& gaia,
+ const AccountInfo& account_info,
base::OnceCallback<void(QueryRequestResult)> callback) = 0;
// Send a Discover API request. Usage:
@@ -172,13 +185,21 @@ class FeedNetwork {
template <typename API>
void SendApiRequest(
const typename API::Request& request,
- const std::string& gaia,
+ const AccountInfo& account_info,
+ RequestMetadata request_metadata,
base::OnceCallback<void(ApiResult<typename API::Response>)> callback) {
std::string binary_proto;
request.SerializeToString(&binary_proto);
+ absl::optional<RequestMetadata> optional_request_metadata;
+ if (API::SendRequestMetadata()) {
+ optional_request_metadata =
+ absl::make_optional(std::move(request_metadata));
+ }
+
SendDiscoverApiRequest(
API::kRequestType, API::RequestPath(request), API::Method(),
- std::move(binary_proto), gaia,
+ std::move(binary_proto), account_info,
+ std::move(optional_request_metadata),
base::BindOnce(&ParseAndForwardApiResponse<API>, std::move(callback)));
}
@@ -195,7 +216,8 @@ class FeedNetwork {
base::StringPiece api_path,
base::StringPiece method,
std::string request_bytes,
- const std::string& gaia,
+ const AccountInfo& account_info,
+ absl::optional<RequestMetadata> request_metadata,
base::OnceCallback<void(RawResponse)> callback) = 0;
template <typename API>
diff --git a/chromium/components/feed/core/v2/feed_network_impl.cc b/chromium/components/feed/core/v2/feed_network_impl.cc
index 874580536a4..938cda663c9 100644
--- a/chromium/components/feed/core/v2/feed_network_impl.cc
+++ b/chromium/components/feed/core/v2/feed_network_impl.cc
@@ -7,6 +7,7 @@
#include <memory>
#include <utility>
+#include "base/base64.h"
#include "base/base64url.h"
#include "base/bind.h"
#include "base/command_line.h"
@@ -16,6 +17,8 @@
#include "base/metrics/histogram_macros.h"
#include "base/strings/strcat.h"
#include "base/strings/string_util.h"
+#include "base/task/post_task.h"
+#include "base/threading/sequenced_task_runner_handle.h"
#include "base/time/time.h"
#include "components/feed/core/common/pref_names.h"
#include "components/feed/core/proto/v2/wire/feed_query.pb.h"
@@ -24,6 +27,7 @@
#include "components/feed/core/proto/v2/wire/upload_actions_request.pb.h"
#include "components/feed/core/proto/v2/wire/upload_actions_response.pb.h"
#include "components/feed/core/v2/metrics_reporter.h"
+#include "components/feed/core/v2/proto_util.h"
#include "components/prefs/pref_service.h"
#include "components/signin/public/identity_manager/access_token_info.h"
#include "components/signin/public/identity_manager/identity_manager.h"
@@ -86,6 +90,17 @@ GURL GetUrlWithoutQuery(const GURL& url) {
}
using RawResponse = FeedNetwork::RawResponse;
+
+net::HttpRequestHeaders CreateApiRequestHeaders(
+ const RequestMetadata& request_metadata) {
+ std::string encoded_client_info;
+ base::Base64Encode(CreateClientInfo(request_metadata).SerializeAsString(),
+ &encoded_client_info);
+ net::HttpRequestHeaders headers;
+ headers.SetHeader(kClientInfoHeader, encoded_client_info);
+ return headers;
+}
+
} // namespace
namespace {
@@ -162,7 +177,8 @@ class FeedNetworkImpl::NetworkFetch {
signin::IdentityManager* identity_manager,
network::SharedURLLoaderFactory* loader_factory,
const std::string& api_key,
- const std::string& gaia,
+ const AccountInfo& account_info,
+ net::HttpRequestHeaders headers,
bool allow_bless_auth)
: url_(url),
request_method_(request_method),
@@ -172,7 +188,8 @@ class FeedNetworkImpl::NetworkFetch {
loader_factory_(loader_factory),
api_key_(api_key),
entire_send_start_ticks_(base::TimeTicks::Now()),
- gaia_(gaia),
+ account_info_(account_info),
+ headers_(std::move(headers)),
allow_bless_auth_(allow_bless_auth) {}
~NetworkFetch() = default;
NetworkFetch(const NetworkFetch&) = delete;
@@ -181,7 +198,13 @@ class FeedNetworkImpl::NetworkFetch {
void Start(base::OnceCallback<void(RawResponse)> done_callback) {
done_callback_ = std::move(done_callback);
- if (gaia_.empty()) {
+ if (delegate_->IsOffline()) {
+ std::move(done_callback_)
+ .Run(MakeFailureResponse(net::ERR_INTERNET_DISCONNECTED,
+ AccountTokenFetchStatus::kUnspecified));
+ return;
+ }
+ if (account_info_.IsEmpty()) {
StartLoader();
return;
}
@@ -191,19 +214,44 @@ class FeedNetworkImpl::NetworkFetch {
private:
void StartAccessTokenFetch() {
- // It's safe to pass base::Unretained(this) since deleting the token fetcher
- // will prevent the callback from being completed.
token_fetcher_ = std::make_unique<signin::PrimaryAccountAccessTokenFetcher>(
"feed", identity_manager_, GetAuthScopes(),
- base::BindOnce(&NetworkFetch::AccessTokenFetchFinished,
- base::Unretained(this), base::TimeTicks::Now()),
+ base::BindOnce(&NetworkFetch::AccessTokenFetchFinished, GetWeakPtr(),
+ base::TimeTicks::Now()),
signin::PrimaryAccountAccessTokenFetcher::Mode::kWaitUntilAvailable);
+ base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE,
+ base::BindOnce(&NetworkFetch::AccessTokenTimeout, GetWeakPtr()),
+ kAccessTokenFetchTimeout);
+ }
+
+ static RawResponse MakeFailureResponse(
+ int32_t status_code,
+ AccountTokenFetchStatus token_fetch_status) {
+ NetworkResponseInfo response_info;
+ RawResponse raw_response;
+ response_info.status_code = status_code;
+ response_info.account_token_fetch_status = token_fetch_status;
+ raw_response.response_info = std::move(response_info);
+ return raw_response;
+ }
+
+ void AccessTokenTimeout() {
+ if (access_token_fetch_complete_)
+ return;
+ access_token_fetch_complete_ = true;
+ std::move(done_callback_)
+ .Run(MakeFailureResponse(net::ERR_TIMED_OUT,
+ AccountTokenFetchStatus::kTimedOut));
}
void AccessTokenFetchFinished(base::TimeTicks token_start_ticks,
GoogleServiceAuthError error,
signin::AccessTokenInfo access_token_info) {
- DCHECK(!gaia_.empty());
+ DCHECK(!account_info_.IsEmpty());
+ if (access_token_fetch_complete_)
+ return;
+ access_token_fetch_complete_ = true;
UMA_HISTOGRAM_ENUMERATION(
"ContentSuggestions.Feed.Network.TokenFetchStatus", error.state(),
GoogleServiceAuthError::NUM_STATES);
@@ -215,12 +263,11 @@ class FeedNetworkImpl::NetworkFetch {
access_token_ = access_token_info.token;
// Abort if the signed-in user doesn't match.
- if (delegate_->GetSyncSignedInGaia() != gaia_) {
- NetworkResponseInfo response_info;
- RawResponse raw_response;
- response_info.status_code = net::ERR_INVALID_ARGUMENT;
- raw_response.response_info = std::move(response_info);
- std::move(done_callback_).Run(std::move(raw_response));
+ if (delegate_->GetAccountInfo() != account_info_) {
+ std::move(done_callback_)
+ .Run(
+ MakeFailureResponse(net::ERR_INVALID_ARGUMENT,
+ AccountTokenFetchStatus::kUnexpectedAccount));
return;
}
@@ -238,30 +285,30 @@ class FeedNetworkImpl::NetworkFetch {
std::unique_ptr<network::SimpleURLLoader> MakeLoader() {
net::NetworkTrafficAnnotationTag traffic_annotation =
net::DefineNetworkTrafficAnnotation("interest_feedv2_send", R"(
- semantics {
- sender: "Feed Library"
- description: "Chrome can show content suggestions (e.g. articles) "
- "in the form of a feed. For signed-in users, these may be "
- "personalized based on interest signals in the user's account."
- trigger: "Triggered periodically in the background, or upon "
- "explicit user request."
- data: "The locale of the device and data describing the suggested "
- "content that the user interacted with. For signed-in users "
- "the request is authenticated. "
- destination: GOOGLE_OWNED_SERVICE
- }
- policy {
- cookies_allowed: YES
- cookies_store: "user"
- setting: "This can be disabled from the New Tab Page by collapsing "
- "the articles section."
- chrome_policy {
- NTPContentSuggestionsEnabled {
- policy_options {mode: MANDATORY}
- NTPContentSuggestionsEnabled: false
- }
+ semantics {
+ sender: "Feed Library"
+ description: "Chrome can show content suggestions (e.g. articles) "
+ "in the form of a feed. For signed-in users, these may be "
+ "personalized based on interest signals in the user's account."
+ trigger: "Triggered periodically in the background, or upon "
+ "explicit user request."
+ data: "The locale of the device and data describing the suggested "
+ "content that the user interacted with. For signed-in users "
+ "the request is authenticated. "
+ destination: GOOGLE_OWNED_SERVICE
+ }
+ policy {
+ cookies_allowed: YES
+ cookies_store: "user"
+ setting: "This can be disabled from the New Tab Page by collapsing "
+ "the articles section."
+ chrome_policy {
+ NTPContentSuggestionsEnabled {
+ policy_options {mode: MANDATORY}
+ NTPContentSuggestionsEnabled: false
}
- })");
+ }
+ })");
GURL url(url_);
if (access_token_.empty() && !api_key_.empty())
@@ -318,6 +365,8 @@ class FeedNetworkImpl::NetworkFetch {
request.headers.SetHeader("Content-Encoding", "gzip");
}
+ request.headers.MergeFrom(headers_);
+
variations::SignedIn signed_in_status = variations::SignedIn::kNo;
if (!access_token_.empty()) {
base::StringPiece token = access_token_;
@@ -346,7 +395,9 @@ class FeedNetworkImpl::NetworkFetch {
base::TimeTicks::Now() - entire_send_start_ticks_;
response_info.fetch_time = base::Time::Now();
response_info.base_request_url = GetUrlWithoutQuery(url_);
- response_info.was_signed_in = !access_token_.empty();
+ if (!access_token_.empty()) {
+ response_info.account_info = account_info_;
+ }
response_info.loader_start_time_ticks = loader_only_start_ticks_;
response_info.encoded_size_bytes =
completion_status ? completion_status->encoded_data_length : 0;
@@ -408,10 +459,14 @@ class FeedNetworkImpl::NetworkFetch {
raw_response.response_bytes = std::move(response_body);
std::move(done_callback_).Run(std::move(raw_response));
}
+ base::WeakPtr<NetworkFetch> GetWeakPtr() {
+ return weak_ptr_factory_.GetWeakPtr();
+ }
GURL url_;
const std::string request_method_;
std::string access_token_;
+ bool access_token_fetch_complete_ = false;
const std::string request_body_;
raw_ptr<FeedNetworkImpl::Delegate> delegate_;
const raw_ptr<signin::IdentityManager> identity_manager_;
@@ -424,12 +479,14 @@ class FeedNetworkImpl::NetworkFetch {
// Set when the NetworkFetch is constructed, before token and article fetch.
const base::TimeTicks entire_send_start_ticks_;
- const std::string gaia_;
+ const AccountInfo account_info_;
+ const net::HttpRequestHeaders headers_;
// Should be set right before the article fetch, and after the token fetch if
// there is one.
base::TimeTicks loader_only_start_ticks_;
bool allow_bless_auth_ = false;
+ base::WeakPtrFactory<NetworkFetch> weak_ptr_factory_{this};
};
FeedNetworkImpl::FeedNetworkImpl(
@@ -449,7 +506,7 @@ FeedNetworkImpl::~FeedNetworkImpl() = default;
void FeedNetworkImpl::SendQueryRequest(
NetworkRequestType request_type,
const feedwire::Request& request,
- const std::string& gaia,
+ const AccountInfo& account_info,
base::OnceCallback<void(QueryRequestResult)> callback) {
std::string binary_proto;
request.SerializeToString(&binary_proto);
@@ -496,7 +553,8 @@ void FeedNetworkImpl::SendQueryRequest(
AddMothershipPayloadQueryParams(base64proto, delegate_->GetLanguageTag(),
url);
Send(url, "GET", /*request_body=*/{},
- /*allow_bless_auth=*/host_overridden, gaia,
+ /*allow_bless_auth=*/host_overridden, account_info,
+ net::HttpRequestHeaders(),
base::BindOnce(&ParseAndForwardQueryResponse, request_type,
std::move(callback)));
}
@@ -509,12 +567,13 @@ void FeedNetworkImpl::Send(const GURL& url,
base::StringPiece request_method,
std::string request_body,
bool allow_bless_auth,
- const std::string& gaia,
+ const AccountInfo& account_info,
+ net::HttpRequestHeaders headers,
base::OnceCallback<void(RawResponse)> callback) {
auto fetch = std::make_unique<NetworkFetch>(
url, request_method, std::move(request_body), delegate_,
- identity_manager_, loader_factory_.get(), api_key_, gaia,
- allow_bless_auth);
+ identity_manager_, loader_factory_.get(), api_key_, account_info,
+ std::move(headers), allow_bless_auth);
NetworkFetch* fetch_unowned = fetch.get();
pending_requests_.emplace(std::move(fetch));
@@ -530,7 +589,8 @@ void FeedNetworkImpl::SendDiscoverApiRequest(
base::StringPiece request_path,
base::StringPiece method,
std::string request_body,
- const std::string& gaia,
+ const AccountInfo& account_info,
+ absl::optional<RequestMetadata> request_metadata,
base::OnceCallback<void(RawResponse)> callback) {
GURL url(base::StrCat({kDiscoverHost, request_path}));
// Override url if requested.
@@ -543,8 +603,13 @@ void FeedNetworkImpl::SendDiscoverApiRequest(
}
}
+ net::HttpRequestHeaders headers =
+ request_metadata ? CreateApiRequestHeaders(*request_metadata)
+ : net::HttpRequestHeaders();
+
Send(url, method, std::move(request_body),
- /*allow_bless_auth=*/false, gaia, std::move(callback));
+ /*allow_bless_auth=*/false, account_info, std::move(headers),
+ std::move(callback));
}
void FeedNetworkImpl::SendComplete(
diff --git a/chromium/components/feed/core/v2/feed_network_impl.h b/chromium/components/feed/core/v2/feed_network_impl.h
index 917e3637f10..a0181fce573 100644
--- a/chromium/components/feed/core/v2/feed_network_impl.h
+++ b/chromium/components/feed/core/v2/feed_network_impl.h
@@ -15,7 +15,9 @@
#include "base/strings/string_piece.h"
#include "components/feed/core/v2/enums.h"
#include "components/feed/core/v2/feed_network.h"
+#include "components/feed/core/v2/types.h"
#include "components/version_info/channel.h"
+#include "net/http/http_request_headers.h"
#include "url/gurl.h"
class PrefService;
@@ -27,6 +29,8 @@ class SharedURLLoaderFactory;
} // namespace network
namespace feed {
+constexpr base::TimeDelta kAccessTokenFetchTimeout = base::Seconds(10);
+constexpr char kClientInfoHeader[] = "search.now.clientinfo-bin";
class FeedNetworkImpl : public FeedNetwork {
public:
@@ -37,9 +41,11 @@ class FeedNetworkImpl : public FeedNetwork {
// Returns a string which represents the top locale and region of the
// device.
virtual std::string GetLanguageTag() = 0;
- // Returns the GAIA string for the signed in user if they are sync-enabled,
- // or the empty string otherwise.
- virtual std::string GetSyncSignedInGaia() = 0;
+ // Returns the AccountInfo for the signed in user if they are sync-enabled,
+ // or empty otherwise.
+ virtual AccountInfo GetAccountInfo() = 0;
+ // Returns whether the device is offline.
+ virtual bool IsOffline() = 0;
};
FeedNetworkImpl(Delegate* delegate,
@@ -56,7 +62,7 @@ class FeedNetworkImpl : public FeedNetwork {
void SendQueryRequest(
NetworkRequestType request_type,
const feedwire::Request& request,
- const std::string& gaia,
+ const AccountInfo& account_info,
base::OnceCallback<void(QueryRequestResult)> callback) override;
void SendDiscoverApiRequest(
@@ -64,7 +70,8 @@ class FeedNetworkImpl : public FeedNetwork {
base::StringPiece api_path,
base::StringPiece method,
std::string request_bytes,
- const std::string& gaia,
+ const AccountInfo& account_info,
+ absl::optional<RequestMetadata> request_metadata,
base::OnceCallback<void(RawResponse)> callback) override;
// Cancels all pending requests immediately. This could be used, for example,
@@ -80,7 +87,8 @@ class FeedNetworkImpl : public FeedNetwork {
base::StringPiece request_method,
std::string request_body,
bool allow_bless_auth,
- const std::string& gaia,
+ const AccountInfo& account_info,
+ net::HttpRequestHeaders request_metadata,
base::OnceCallback<void(FeedNetworkImpl::RawResponse)> callback);
void SendComplete(NetworkFetch* fetch,
diff --git a/chromium/components/feed/core/v2/feed_network_impl_unittest.cc b/chromium/components/feed/core/v2/feed_network_impl_unittest.cc
index 1cf2fb67de3..7849e243609 100644
--- a/chromium/components/feed/core/v2/feed_network_impl_unittest.cc
+++ b/chromium/components/feed/core/v2/feed_network_impl_unittest.cc
@@ -7,6 +7,7 @@
#include <memory>
#include <utility>
+#include "base/base64.h"
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/memory/raw_ptr.h"
@@ -17,11 +18,13 @@
#include "base/test/task_environment.h"
#include "build/chromeos_buildflags.h"
#include "components/feed/core/common/pref_names.h"
+#include "components/feed/core/proto/v2/wire/client_info.pb.h"
#include "components/feed/core/proto/v2/wire/request.pb.h"
#include "components/feed/core/proto/v2/wire/response.pb.h"
#include "components/feed/core/proto/v2/wire/upload_actions_request.pb.h"
#include "components/feed/core/proto/v2/wire/upload_actions_response.pb.h"
#include "components/feed/core/proto/v2/wire/web_feeds.pb.h"
+#include "components/feed/core/v2/public/types.h"
#include "components/feed/core/v2/test/callback_receiver.h"
#include "components/prefs/testing_pref_service.h"
#include "components/signin/public/identity_manager/identity_test_environment.h"
@@ -44,9 +47,31 @@
namespace feed {
namespace {
+MATCHER_P(EqualsProto,
+ message,
+ "Match a proto Message equal to the matcher's argument.") {
+ return arg.ShortDebugString() == message.ShortDebugString();
+}
+
using testing::ElementsAre;
using QueryRequestResult = FeedNetwork::QueryRequestResult;
+feedwire::ClientInfo ExpectHasClientInfoHeader(
+ network::ResourceRequest request) {
+ EXPECT_TRUE(request.headers.HasHeader(feed::kClientInfoHeader));
+ std::string clientinfo;
+ EXPECT_TRUE(request.headers.GetHeader(feed::kClientInfoHeader, &clientinfo));
+ std::string decoded_clientinfo;
+ EXPECT_TRUE(base::Base64Decode(clientinfo, &decoded_clientinfo));
+ feedwire::ClientInfo clientinfo_proto;
+ EXPECT_TRUE(clientinfo_proto.ParseFromString(decoded_clientinfo));
+ return clientinfo_proto;
+}
+
+void ExpectNoClientInfoHeader(network::ResourceRequest request) {
+ EXPECT_FALSE(request.headers.HasHeader(feed::kClientInfoHeader));
+}
+
feedwire::Request GetTestFeedRequest(feedwire::FeedQuery::RequestReason reason =
feedwire::FeedQuery::MANUAL_REFRESH) {
feedwire::Request request;
@@ -79,12 +104,14 @@ class TestDelegate : public FeedNetworkImpl::Delegate {
: identity_test_env_(identity_test_env) {}
std::string GetLanguageTag() override { return "en"; }
- std::string GetSyncSignedInGaia() override {
- return identity_test_env_->identity_manager()
- ->GetPrimaryAccountInfo(signin::ConsentLevel::kSync)
- .gaia;
+ AccountInfo GetAccountInfo() override {
+ return AccountInfo{
+ identity_test_env_->identity_manager()->GetPrimaryAccountInfo(
+ signin::ConsentLevel::kSync)};
}
+ bool IsOffline() override { return is_offline_; }
+ bool is_offline_ = false;
raw_ptr<signin::IdentityTestEnvironment> identity_test_env_;
};
@@ -116,7 +143,20 @@ class FeedNetworkTest : public testing::Test {
return &identity_test_env_;
}
- std::string gaia() { return delegate_.GetSyncSignedInGaia(); }
+ AccountInfo account_info() { return delegate_.GetAccountInfo(); }
+ RequestMetadata request_metadata() {
+ RequestMetadata request_metadata;
+ request_metadata.chrome_info.version = base::Version({1, 2, 3, 4});
+ request_metadata.chrome_info.channel = version_info::Channel::STABLE;
+ request_metadata.chrome_info.start_surface = false;
+ request_metadata.display_metrics.density = 1;
+ request_metadata.display_metrics.width_pixels = 2;
+ request_metadata.display_metrics.height_pixels = 3;
+ request_metadata.language_tag = "en-US";
+ request_metadata.client_instance_id = "client_instance_id";
+
+ return request_metadata;
+ }
network::TestURLLoaderFactory* test_factory() { return &test_factory_; }
@@ -173,6 +213,9 @@ class FeedNetworkTest : public testing::Test {
test_factory()->GetPendingRequest(0);
CHECK(pending_request);
network::ResourceRequest resource_request = pending_request->request;
+
+ ExpectNoClientInfoHeader(resource_request);
+
Respond(pending_request->request.url,
PrependResponseLength(response_string), code);
task_environment_.FastForwardUntilNoTasksRemain();
@@ -205,18 +248,22 @@ class FeedNetworkTest : public testing::Test {
net::HttpStatusCode code) {
std::string binary_proto;
response_message.SerializeToString(&binary_proto);
- return RespondToDiscoverRequest(binary_proto, code);
+ network::ResourceRequest resource_request =
+ RespondToDiscoverRequest(binary_proto, code);
+ ExpectHasClientInfoHeader(resource_request);
+ return resource_request;
}
protected:
scoped_refptr<net::HttpResponseHeaders> response_headers_;
- private:
+ protected:
signin::IdentityTestEnvironment identity_test_env_;
TestDelegate delegate_{&identity_test_env_};
variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{
variations::VariationsIdsProvider::Mode::kUseSignedInState};
std::unique_ptr<FeedNetwork> feed_network_;
+ RequestMetadata request_metadata_;
network::TestURLLoaderFactory test_factory_;
scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory_;
TestingPrefServiceSimple profile_prefs_;
@@ -226,7 +273,7 @@ class FeedNetworkTest : public testing::Test {
TEST_F(FeedNetworkTest, SendQueryRequestEmpty) {
CallbackReceiver<QueryRequestResult> receiver;
feed_network()->SendQueryRequest(NetworkRequestType::kFeedQuery,
- feedwire::Request(), gaia(),
+ feedwire::Request(), account_info(),
receiver.Bind());
ASSERT_TRUE(receiver.GetResult());
@@ -238,7 +285,7 @@ TEST_F(FeedNetworkTest, SendQueryRequestEmpty) {
TEST_F(FeedNetworkTest, SendQueryRequestSendsValidRequest) {
CallbackReceiver<QueryRequestResult> receiver;
feed_network()->SendQueryRequest(NetworkRequestType::kFeedQuery,
- GetTestFeedRequest(), gaia(),
+ GetTestFeedRequest(), account_info(),
receiver.Bind());
network::ResourceRequest resource_request =
RespondToQueryRequest("", net::HTTP_OK);
@@ -260,7 +307,7 @@ TEST_F(FeedNetworkTest, SendQueryRequestSendsValidRequest) {
TEST_F(FeedNetworkTest, SendQueryRequestForceSignedOut) {
CallbackReceiver<QueryRequestResult> receiver;
feed_network()->SendQueryRequest(NetworkRequestType::kFeedQuery,
- GetTestFeedRequest(), /*gaia=*/"",
+ GetTestFeedRequest(), AccountInfo{},
receiver.Bind());
network::ResourceRequest resource_request =
RespondToQueryRequest("", net::HTTP_OK);
@@ -269,13 +316,15 @@ TEST_F(FeedNetworkTest, SendQueryRequestForceSignedOut) {
"https://www.google.com/httpservice/retry/TrellisClankService/"
"FeedQuery?reqpld=CAHCPgQSAggB&fmt=bin&hl=en&key=dummy_api_key",
resource_request.url);
+ EXPECT_EQ(AccountInfo{},
+ receiver.RunAndGetResult().response_info.account_info);
EXPECT_FALSE(resource_request.headers.HasHeader("Authorization"));
}
TEST_F(FeedNetworkTest, SendQueryRequestInvalidResponse) {
CallbackReceiver<QueryRequestResult> receiver;
feed_network()->SendQueryRequest(NetworkRequestType::kFeedQuery,
- GetTestFeedRequest(), gaia(),
+ GetTestFeedRequest(), account_info(),
receiver.Bind());
RespondToQueryRequest("invalid", net::HTTP_OK);
@@ -288,7 +337,7 @@ TEST_F(FeedNetworkTest, SendQueryRequestInvalidResponse) {
TEST_F(FeedNetworkTest, SendQueryRequestReceivesResponse) {
CallbackReceiver<QueryRequestResult> receiver;
feed_network()->SendQueryRequest(NetworkRequestType::kFeedQuery,
- GetTestFeedRequest(), gaia(),
+ GetTestFeedRequest(), account_info(),
receiver.Bind());
RespondToQueryRequest(GetTestFeedResponse(), net::HTTP_OK);
@@ -299,7 +348,7 @@ TEST_F(FeedNetworkTest, SendQueryRequestReceivesResponse) {
"https://www.google.com/httpservice/retry/TrellisClankService/FeedQuery",
result.response_info.base_request_url);
EXPECT_NE(base::Time(), result.response_info.fetch_time);
- EXPECT_TRUE(result.response_info.was_signed_in);
+ EXPECT_EQ(account_info(), result.response_info.account_info);
EXPECT_EQ(GetTestFeedResponse().response_version(),
result.response_body->response_version());
}
@@ -307,7 +356,7 @@ TEST_F(FeedNetworkTest, SendQueryRequestReceivesResponse) {
TEST_F(FeedNetworkTest, SendQueryRequestIgnoresBodyForNon200Response) {
CallbackReceiver<QueryRequestResult> receiver;
feed_network()->SendQueryRequest(NetworkRequestType::kFeedQuery,
- GetTestFeedRequest(), gaia(),
+ GetTestFeedRequest(), account_info(),
receiver.Bind());
RespondToQueryRequest(GetTestFeedResponse(), net::HTTP_FORBIDDEN);
@@ -322,9 +371,9 @@ TEST_F(FeedNetworkTest, SendQueryRequestIgnoresBodyForNon200Response) {
TEST_F(FeedNetworkTest, SendQueryRequestFailsForWrongUser) {
CallbackReceiver<QueryRequestResult> receiver;
- feed_network()->SendQueryRequest(NetworkRequestType::kFeedQuery,
- GetTestFeedRequest(), "some_other_gaia",
- receiver.Bind());
+ feed_network()->SendQueryRequest(
+ NetworkRequestType::kFeedQuery, GetTestFeedRequest(),
+ {"other-gaia", "other@foo.com"}, receiver.Bind());
task_environment_.RunUntilIdle();
network::TestURLLoaderFactory::PendingRequest* pending_request =
test_factory()->GetPendingRequest(0);
@@ -333,6 +382,8 @@ TEST_F(FeedNetworkTest, SendQueryRequestFailsForWrongUser) {
ASSERT_TRUE(receiver.GetResult());
const QueryRequestResult& result = *receiver.GetResult();
EXPECT_EQ(net::ERR_INVALID_ARGUMENT, result.response_info.status_code);
+ EXPECT_EQ(AccountTokenFetchStatus::kUnexpectedAccount,
+ result.response_info.account_token_fetch_status);
EXPECT_FALSE(result.response_body);
histogram().ExpectBucketCount(
"ContentSuggestions.Feed.Network.ResponseStatus.FeedQuery",
@@ -342,7 +393,7 @@ TEST_F(FeedNetworkTest, SendQueryRequestFailsForWrongUser) {
TEST_F(FeedNetworkTest, CancelRequest) {
CallbackReceiver<QueryRequestResult> receiver;
feed_network()->SendQueryRequest(NetworkRequestType::kFeedQuery,
- GetTestFeedRequest(), gaia(),
+ GetTestFeedRequest(), account_info(),
receiver.Bind());
feed_network()->CancelRequests();
task_environment_.FastForwardUntilNoTasksRemain();
@@ -354,7 +405,7 @@ TEST_F(FeedNetworkTest, RequestTimeout) {
base::HistogramTester histogram_tester;
CallbackReceiver<QueryRequestResult> receiver;
feed_network()->SendQueryRequest(NetworkRequestType::kFeedQuery,
- GetTestFeedRequest(), gaia(),
+ GetTestFeedRequest(), account_info(),
receiver.Bind());
task_environment_.FastForwardBy(base::Seconds(30));
@@ -365,16 +416,93 @@ TEST_F(FeedNetworkTest, RequestTimeout) {
"ContentSuggestions.Feed.Network.Duration", base::Seconds(30), 1);
}
+TEST_F(FeedNetworkTest, AccountTokenFetchTimeout) {
+ identity_test_env_.RemoveRefreshTokenForPrimaryAccount();
+ identity_test_env_.SetAutomaticIssueOfAccessTokens(false);
+
+ CallbackReceiver<QueryRequestResult> receiver;
+ feed_network()->SendQueryRequest(NetworkRequestType::kFeedQuery,
+ GetTestFeedRequest(), account_info(),
+ receiver.Bind());
+ task_environment_.FastForwardBy(kAccessTokenFetchTimeout - base::Seconds(1));
+ ASSERT_FALSE(receiver.GetResult());
+
+ task_environment_.FastForwardBy(base::Seconds(1));
+
+ ASSERT_TRUE(receiver.GetResult());
+ const QueryRequestResult& result = *receiver.GetResult();
+ EXPECT_EQ(AccountTokenFetchStatus::kTimedOut,
+ result.response_info.account_token_fetch_status);
+ EXPECT_EQ(net::ERR_TIMED_OUT, result.response_info.status_code);
+}
+
+TEST_F(FeedNetworkTest, AccountTokenRefreshCompleteAfterFetchTimeout) {
+ identity_test_env_.SetAutomaticIssueOfAccessTokens(false);
+
+ CallbackReceiver<QueryRequestResult> receiver;
+ feed_network()->SendQueryRequest(NetworkRequestType::kFeedQuery,
+ GetTestFeedRequest(), account_info(),
+ receiver.Bind());
+ // Time-out the token fetch and then complete it.
+ task_environment_.FastForwardBy(kAccessTokenFetchTimeout);
+ identity_test_env_.SetAutomaticIssueOfAccessTokens(true);
+ identity_test_env_.SetRefreshTokenForPrimaryAccount();
+
+ // Ensure the fetch failed.
+ const QueryRequestResult& result = receiver.RunAndGetResult();
+ EXPECT_EQ(AccountTokenFetchStatus::kTimedOut,
+ result.response_info.account_token_fetch_status);
+ EXPECT_EQ(net::ERR_TIMED_OUT, result.response_info.status_code);
+}
+
+TEST_F(FeedNetworkTest, AccountTokenRefreshCompleteBeforeFetchTimeout) {
+ identity_test_env_.SetAutomaticIssueOfAccessTokens(false);
+
+ CallbackReceiver<QueryRequestResult> receiver;
+ feed_network()->SendQueryRequest(NetworkRequestType::kFeedQuery,
+ GetTestFeedRequest(), account_info(),
+ receiver.Bind());
+ // Time-out the token fetch just after it completes.
+ identity_test_env_.SetAutomaticIssueOfAccessTokens(true);
+ identity_test_env_.SetRefreshTokenForPrimaryAccount();
+ task_environment_.FastForwardBy(kAccessTokenFetchTimeout);
+ RespondToQueryRequest(GetTestFeedResponse(), net::HTTP_OK);
+
+ // Ensure the fetch failed.
+ const QueryRequestResult& result = receiver.RunAndGetResult();
+ EXPECT_EQ(AccountTokenFetchStatus::kUnspecified,
+ result.response_info.account_token_fetch_status);
+ EXPECT_EQ(net::HTTP_OK, result.response_info.status_code);
+}
+
+TEST_F(FeedNetworkTest, FetchImmediatelyAbortsIfOffline) {
+ // Trying to fetch the token would timeout, but because the device is offline,
+ // the fetch quits immediately.
+ identity_test_env_.RemoveRefreshTokenForPrimaryAccount();
+ identity_test_env_.SetAutomaticIssueOfAccessTokens(false);
+ delegate_.is_offline_ = true;
+
+ CallbackReceiver<QueryRequestResult> receiver;
+ feed_network()->SendQueryRequest(NetworkRequestType::kFeedQuery,
+ GetTestFeedRequest(), account_info(),
+ receiver.Bind());
+ ASSERT_TRUE(receiver.GetResult());
+ const QueryRequestResult& result = *receiver.GetResult();
+ EXPECT_EQ(AccountTokenFetchStatus::kUnspecified,
+ result.response_info.account_token_fetch_status);
+ EXPECT_EQ(net::ERR_INTERNET_DISCONNECTED, result.response_info.status_code);
+}
+
TEST_F(FeedNetworkTest, ParallelRequests) {
CallbackReceiver<QueryRequestResult> receiver1, receiver2;
feed_network()->SendQueryRequest(NetworkRequestType::kFeedQuery,
- GetTestFeedRequest(), gaia(),
+ GetTestFeedRequest(), account_info(),
receiver1.Bind());
// Make another request with a different URL so Respond() won't affect both
// requests.
feed_network()->SendQueryRequest(
NetworkRequestType::kFeedQuery,
- GetTestFeedRequest(feedwire::FeedQuery::NEXT_PAGE_SCROLL), gaia(),
+ GetTestFeedRequest(feedwire::FeedQuery::NEXT_PAGE_SCROLL), account_info(),
receiver2.Bind());
// Respond to both requests, avoiding FastForwardUntilNoTasksRemain until
@@ -398,7 +526,7 @@ TEST_F(FeedNetworkTest, ShouldReportResponseStatusCode) {
CallbackReceiver<QueryRequestResult> receiver;
base::HistogramTester histogram_tester;
feed_network()->SendQueryRequest(NetworkRequestType::kFeedQuery,
- GetTestFeedRequest(), gaia(),
+ GetTestFeedRequest(), account_info(),
receiver.Bind());
RespondToQueryRequest(GetTestFeedResponse(), net::HTTP_FORBIDDEN);
@@ -414,7 +542,7 @@ TEST_F(FeedNetworkTest, ShouldIncludeAPIKeyForAuthError) {
base::HistogramTester histogram_tester;
feed_network()->SendQueryRequest(NetworkRequestType::kFeedQuery,
- GetTestFeedRequest(), gaia(),
+ GetTestFeedRequest(), account_info(),
receiver.Bind());
identity_env()->WaitForAccessTokenRequestIfNecessaryAndRespondWithError(
GoogleServiceAuthError(
@@ -441,7 +569,7 @@ TEST_F(FeedNetworkTest, ShouldIncludeAPIKeyForNoSignedInUser) {
identity_env()->ClearPrimaryAccount();
CallbackReceiver<QueryRequestResult> receiver;
feed_network()->SendQueryRequest(NetworkRequestType::kFeedQuery,
- GetTestFeedRequest(), gaia(),
+ GetTestFeedRequest(), account_info(),
receiver.Bind());
network::ResourceRequest resource_request =
@@ -458,7 +586,7 @@ TEST_F(FeedNetworkTest, TestDurationHistogram) {
const base::TimeDelta kDuration = base::Milliseconds(12345);
feed_network()->SendQueryRequest(NetworkRequestType::kFeedQuery,
- GetTestFeedRequest(), gaia(),
+ GetTestFeedRequest(), account_info(),
receiver.Bind());
task_environment_.FastForwardBy(kDuration);
RespondToQueryRequest(GetTestFeedResponse(), net::HTTP_OK);
@@ -475,7 +603,7 @@ TEST_F(FeedNetworkTest, TestHostOverrideWithAuthHeader) {
profile_prefs().SetString(feed::prefs::kHostOverrideHost,
"http://www.newhost.com/");
feed_network()->SendQueryRequest(NetworkRequestType::kFeedQuery,
- GetTestFeedRequest(), gaia(),
+ GetTestFeedRequest(), account_info(),
receiver.Bind());
ASSERT_EQ("www.newhost.com", GetPendingRequestURL().host());
@@ -496,7 +624,7 @@ TEST_F(FeedNetworkTest, TestHostOverrideWithPath) {
profile_prefs().SetString(feed::prefs::kHostOverrideHost,
"http://www.newhost.com/testpath");
feed_network()->SendQueryRequest(NetworkRequestType::kFeedQuery,
- GetTestFeedRequest(), gaia(),
+ GetTestFeedRequest(), account_info(),
receiver.Bind());
ASSERT_EQ("www.newhost.com", GetPendingRequestURL().host());
@@ -509,7 +637,7 @@ TEST_F(FeedNetworkTest, TestHostOverrideWithPathTrailingSlash) {
profile_prefs().SetString(feed::prefs::kHostOverrideHost,
"http://www.newhost.com/testpath/");
feed_network()->SendQueryRequest(NetworkRequestType::kFeedQuery,
- GetTestFeedRequest(), gaia(),
+ GetTestFeedRequest(), account_info(),
receiver.Bind());
ASSERT_EQ("www.newhost.com", GetPendingRequestURL().host());
@@ -521,23 +649,70 @@ TEST_F(FeedNetworkTest, SendApiRequest_UploadActions) {
CallbackReceiver<FeedNetwork::ApiResult<feedwire::UploadActionsResponse>>
receiver;
feed_network()->SendApiRequest<UploadActionsDiscoverApi>(
- GetTestActionRequest(), gaia(), receiver.Bind());
- RespondToActionRequest(GetTestActionResponse(), net::HTTP_OK);
+ GetTestActionRequest(), account_info(), request_metadata(),
+ receiver.Bind());
+
+ network::ResourceRequest request =
+ RespondToActionRequest(GetTestActionResponse(), net::HTTP_OK);
ASSERT_TRUE(receiver.GetResult());
const FeedNetwork::ApiResult<feedwire::UploadActionsResponse>& result =
*receiver.GetResult();
EXPECT_EQ(net::HTTP_OK, result.response_info.status_code);
EXPECT_TRUE(result.response_body);
+
histogram().ExpectBucketCount(
"ContentSuggestions.Feed.Network.ResponseStatus.UploadActions", 200, 1);
}
+TEST_F(FeedNetworkTest, SendApiRequest_DecodesClientInfo_WithClientInstanceId) {
+ CallbackReceiver<FeedNetwork::ApiResult<feedwire::UploadActionsResponse>>
+ receiver;
+ feed_network()->SendApiRequest<UploadActionsDiscoverApi>(
+ GetTestActionRequest(), account_info(), request_metadata(),
+ receiver.Bind());
+
+ network::ResourceRequest request =
+ RespondToActionRequest(GetTestActionResponse(), net::HTTP_OK);
+ feedwire::ClientInfo client_info = ExpectHasClientInfoHeader(request);
+
+ EXPECT_EQ(feedwire::ClientInfo::CHROME_ANDROID, client_info.app_type());
+ EXPECT_EQ(feedwire::Version::RELEASE, client_info.app_version().build_type());
+ EXPECT_EQ(1, client_info.app_version().major());
+ EXPECT_EQ(2, client_info.app_version().minor());
+ EXPECT_EQ(3, client_info.app_version().build());
+ EXPECT_EQ(4, client_info.app_version().revision());
+ EXPECT_FALSE(client_info.chrome_client_info().start_surface());
+ EXPECT_EQ("client_instance_id", client_info.client_instance_id());
+}
+
+TEST_F(FeedNetworkTest, SendApiRequest_DecodesClientInfo_WithSessionId) {
+ RequestMetadata request_metadata_with_session = request_metadata();
+ request_metadata_with_session.session_id = "session_id";
+ request_metadata_with_session.client_instance_id = "";
+
+ CallbackReceiver<FeedNetwork::ApiResult<feedwire::UploadActionsResponse>>
+ receiver;
+ feed_network()->SendApiRequest<UploadActionsDiscoverApi>(
+ GetTestActionRequest(), account_info(),
+ std::move(request_metadata_with_session), receiver.Bind());
+ network::ResourceRequest request =
+ RespondToActionRequest(GetTestActionResponse(), net::HTTP_OK);
+ feedwire::ClientInfo client_info = ExpectHasClientInfoHeader(request);
+
+ EXPECT_EQ("session_id", client_info.chrome_client_info().session_id());
+ EXPECT_EQ("", client_info.client_instance_id());
+}
+
TEST_F(FeedNetworkTest, SendApiRequest_UploadActionsFailsForWrongUser) {
CallbackReceiver<FeedNetwork::ApiResult<feedwire::UploadActionsResponse>>
receiver;
+ AccountInfo other_account;
+ other_account.gaia = "some_other_gaia";
+ other_account.email = "some@other.com";
feed_network()->SendApiRequest<UploadActionsDiscoverApi>(
- GetTestActionRequest(), "some_other_gaia", receiver.Bind());
+ GetTestActionRequest(), other_account, request_metadata(),
+ receiver.Bind());
task_environment_.RunUntilIdle();
network::TestURLLoaderFactory::PendingRequest* pending_request =
test_factory()->GetPendingRequest(0);
@@ -547,6 +722,8 @@ TEST_F(FeedNetworkTest, SendApiRequest_UploadActionsFailsForWrongUser) {
const FeedNetwork::ApiResult<feedwire::UploadActionsResponse>& result =
*receiver.GetResult();
EXPECT_EQ(net::ERR_INVALID_ARGUMENT, result.response_info.status_code);
+ EXPECT_EQ(AccountTokenFetchStatus::kUnexpectedAccount,
+ result.response_info.account_token_fetch_status);
EXPECT_FALSE(result.response_body);
histogram().ExpectBucketCount(
"ContentSuggestions.Feed.Network.ResponseStatus.UploadActions",
@@ -557,7 +734,8 @@ TEST_F(FeedNetworkTest, SendApiRequestSendsValidRequest_UploadActions) {
CallbackReceiver<FeedNetwork::ApiResult<feedwire::UploadActionsResponse>>
receiver;
feed_network()->SendApiRequest<UploadActionsDiscoverApi>(
- GetTestActionRequest(), gaia(), receiver.Bind());
+ GetTestActionRequest(), account_info(), request_metadata(),
+ receiver.Bind());
network::ResourceRequest resource_request =
RespondToActionRequest(GetTestActionResponse(), net::HTTP_OK);
@@ -593,8 +771,8 @@ TEST_F(FeedNetworkTest, SendApiRequest_Unfollow) {
CallbackReceiver<
FeedNetwork::ApiResult<feedwire::webfeed::UnfollowWebFeedResponse>>
receiver;
- feed_network()->SendApiRequest<UnfollowWebFeedDiscoverApi>({}, gaia(),
- receiver.Bind());
+ feed_network()->SendApiRequest<UnfollowWebFeedDiscoverApi>(
+ {}, account_info(), request_metadata(), receiver.Bind());
RespondToDiscoverRequest("", net::HTTP_OK);
ASSERT_TRUE(receiver.GetResult());
@@ -607,8 +785,8 @@ TEST_F(FeedNetworkTest, SendApiRequest_Unfollow) {
}
TEST_F(FeedNetworkTest, SendApiRequest_ListWebFeedsSendsCorrectContentType) {
- feed_network()->SendApiRequest<ListWebFeedsDiscoverApi>({}, gaia(),
- base::DoNothing());
+ feed_network()->SendApiRequest<ListWebFeedsDiscoverApi>(
+ {}, account_info(), request_metadata(), base::DoNothing());
std::string requested_content_type;
RespondToDiscoverRequest("", net::HTTP_OK)
.headers.GetHeader("content-type", &requested_content_type);
@@ -620,7 +798,8 @@ TEST_F(FeedNetworkTest, TestOverrideHostDoesNotAffectDiscoverApis) {
profile_prefs().SetString(feed::prefs::kHostOverrideHost,
"http://www.newhost.com/");
feed_network()->SendApiRequest<UploadActionsDiscoverApi>(
- GetTestActionRequest(), gaia(), base::DoNothing());
+ GetTestActionRequest(), account_info(), request_metadata(),
+ base::DoNothing());
EXPECT_EQ(GURL("https://discover-pa.googleapis.com/v1/actions:upload"),
GetPendingRequestURL());
@@ -630,7 +809,8 @@ TEST_F(FeedNetworkTest, TestOverrideDiscoverEndpoint) {
profile_prefs().SetString(feed::prefs::kDiscoverAPIEndpointOverride,
"http://www.newhost.com/");
feed_network()->SendApiRequest<UploadActionsDiscoverApi>(
- GetTestActionRequest(), gaia(), base::DoNothing());
+ GetTestActionRequest(), account_info(), request_metadata(),
+ base::DoNothing());
EXPECT_EQ(GURL("http://www.newhost.com/v1/actions:upload"),
GetPendingRequestURL());
diff --git a/chromium/components/feed/core/v2/feed_store.cc b/chromium/components/feed/core/v2/feed_store.cc
index 48b4b949ace..070eb8c4164 100644
--- a/chromium/components/feed/core/v2/feed_store.cc
+++ b/chromium/components/feed/core/v2/feed_store.cc
@@ -38,10 +38,12 @@ namespace {
// subs -> subscribed_web_feeds
// recommendedIndex -> recommended_web_feed_index
// R/<web_feed_id> -> recommended_web_feed
+// W/<operation-id> -> pending_web_feed_operation
constexpr char kLocalActionPrefix[] = "a/";
constexpr char kMetadataKey[] = "m";
constexpr char kSubscribedFeedsKey[] = "subs";
constexpr char kRecommendedIndexKey[] = "recommendedIndex";
+constexpr char kPendingWebFeedOperationPrefix[] = "W/";
leveldb::ReadOptions CreateReadOptions() {
leveldb::ReadOptions opts;
@@ -153,6 +155,10 @@ std::string KeyForRecord(const feedstore::Record& record) {
return base::StrCat({"R/", record.recommended_web_feed().web_feed_id()});
case feedstore::Record::kRecommendedWebFeedIndex:
return kRecommendedIndexKey;
+ case feedstore::Record::kPendingWebFeedOperation:
+ return base::StrCat(
+ {"W/",
+ base::NumberToString(record.pending_web_feed_operation().id())});
case feedstore::Record::DATA_NOT_SET:
break;
}
@@ -221,6 +227,12 @@ feedstore::Record MakeRecord(feedstore::WebFeedInfo web_feed_info) {
return record;
}
+feedstore::Record MakeRecord(feedstore::PendingWebFeedOperation operation) {
+ feedstore::Record record;
+ *record.mutable_pending_web_feed_operation() = std::move(operation);
+ return record;
+}
+
template <typename T>
std::pair<std::string, feedstore::Record> MakeKeyAndRecord(T record_data) {
std::pair<std::string, feedstore::Record> result;
@@ -286,6 +298,13 @@ FeedStore::StartupData::~StartupData() = default;
FeedStore::StartupData& FeedStore::StartupData::operator=(StartupData&&) =
default;
+FeedStore::WebFeedStartupData::WebFeedStartupData() = default;
+FeedStore::WebFeedStartupData::WebFeedStartupData(WebFeedStartupData&&) =
+ default;
+FeedStore::WebFeedStartupData::~WebFeedStartupData() = default;
+FeedStore::WebFeedStartupData& FeedStore::WebFeedStartupData::operator=(
+ WebFeedStartupData&&) = default;
+
FeedStore::FeedStore(
std::unique_ptr<leveldb_proto::ProtoDatabase<feedstore::Record>> database)
: database_status_(leveldb_proto::Enums::InitStatus::kNotInitialized),
@@ -653,9 +672,15 @@ void FeedStore::ReadMetadata(
void FeedStore::ReadWebFeedStartupData(
base::OnceCallback<void(WebFeedStartupData)> callback) {
- ReadMany({kSubscribedFeedsKey, kRecommendedIndexKey},
- base::BindOnce(&FeedStore::OnReadWebFeedStartupDataFinished,
- GetWeakPtr(), std::move(callback)));
+ auto is_startup_data_filter = [](const std::string& key) {
+ return key == kSubscribedFeedsKey || key == kRecommendedIndexKey ||
+ base::StartsWith(key, kPendingWebFeedOperationPrefix);
+ };
+
+ database_->LoadEntriesWithFilter(
+ base::BindRepeating(is_startup_data_filter),
+ base::BindOnce(&FeedStore::OnReadWebFeedStartupDataFinished, GetWeakPtr(),
+ std::move(callback)));
}
void FeedStore::OnReadWebFeedStartupDataFinished(
@@ -671,6 +696,9 @@ void FeedStore::OnReadWebFeedStartupDataFinished(
} else if (r.has_subscribed_web_feeds()) {
result.subscribed_web_feeds =
std::move(*r.mutable_subscribed_web_feeds());
+ } else if (r.has_pending_web_feed_operation()) {
+ result.pending_operations.push_back(
+ std::move(*r.mutable_pending_web_feed_operation()));
} else {
DLOG(ERROR) << "OnReadWebFeedStartupDataFinished: Got record with no "
"useful data. data_case="
@@ -790,4 +818,20 @@ void FeedStore::ReadRecommendedWebFeedInfoFinished(
base::WrapUnique(record->release_recommended_web_feed()));
}
+void FeedStore::WritePendingWebFeedOperation(
+ feedstore::PendingWebFeedOperation operation) {
+ Write({MakeRecord(std::move(operation))}, base::DoNothing());
+}
+
+void FeedStore::RemovePendingWebFeedOperation(int64_t operation_id) {
+ auto keys_to_remove = std::make_unique<std::vector<std::string>>();
+ keys_to_remove->push_back(base::StrCat(
+ {kPendingWebFeedOperationPrefix, base::NumberToString(operation_id)}));
+
+ database_->UpdateEntries(
+ /*entries_to_save=*/std::make_unique<
+ std::vector<std::pair<std::string, feedstore::Record>>>(),
+ std::move(keys_to_remove), base::DoNothing());
+}
+
} // namespace feed
diff --git a/chromium/components/feed/core/v2/feed_store.h b/chromium/components/feed/core/v2/feed_store.h
index 737109662ee..f5ec4cef134 100644
--- a/chromium/components/feed/core/v2/feed_store.h
+++ b/chromium/components/feed/core/v2/feed_store.h
@@ -52,8 +52,14 @@ class FeedStore {
std::vector<feedstore::StreamData> stream_data;
};
struct WebFeedStartupData {
+ WebFeedStartupData();
+ WebFeedStartupData(WebFeedStartupData&&);
+ ~WebFeedStartupData();
+ WebFeedStartupData& operator=(WebFeedStartupData&&);
+
feedstore::SubscribedWebFeeds subscribed_web_feeds;
feedstore::RecommendedWebFeedIndex recommended_feed_index;
+ std::vector<feedstore::PendingWebFeedOperation> pending_operations;
};
explicit FeedStore(
@@ -136,6 +142,12 @@ class FeedStore {
const std::string& web_feed_id,
base::OnceCallback<void(std::unique_ptr<feedstore::WebFeedInfo>)>
callback);
+ void ReadAllPendingWebFeedOperations(
+ base::OnceCallback<
+ void(std::vector<feedstore::PendingWebFeedOperation>)>);
+ void RemovePendingWebFeedOperation(int64_t operation_id);
+ void WritePendingWebFeedOperation(
+ feedstore::PendingWebFeedOperation operation);
bool IsInitializedForTesting() const;
diff --git a/chromium/components/feed/core/v2/feed_stream.cc b/chromium/components/feed/core/v2/feed_stream.cc
index f9b44853ee5..10dca036024 100644
--- a/chromium/components/feed/core/v2/feed_stream.cc
+++ b/chromium/components/feed/core/v2/feed_stream.cc
@@ -12,6 +12,7 @@
#include "base/callback_helpers.h"
#include "base/containers/cxx20_erase.h"
#include "base/feature_list.h"
+#include "base/location.h"
#include "base/metrics/histogram_macros.h"
#include "base/notreached.h"
#include "base/threading/thread_task_runner_handle.h"
@@ -35,6 +36,7 @@
#include "components/feed/core/v2/protocol_translator.h"
#include "components/feed/core/v2/public/feed_api.h"
#include "components/feed/core/v2/public/feed_stream_surface.h"
+#include "components/feed/core/v2/public/logging_parameters.h"
#include "components/feed/core/v2/public/refresh_task_scheduler.h"
#include "components/feed/core/v2/public/reliability_logging_bridge.h"
#include "components/feed/core/v2/public/stream_type.h"
@@ -132,7 +134,6 @@ FeedStream::FeedStream(RefreshTaskScheduler* refresh_task_scheduler,
chrome_info_(chrome_info),
task_queue_(this),
request_throttler_(profile_prefs),
- upload_criteria_(profile_prefs),
privacy_notice_card_tracker_(profile_prefs) {
DCHECK(persistent_key_value_store_);
DCHECK(feed_network_);
@@ -157,9 +158,11 @@ FeedStream::FeedStream(RefreshTaskScheduler* refresh_task_scheduler,
// Inserting this task first ensures that |store_| is initialized before
// it is used.
- task_queue_.AddTask(std::make_unique<WaitForStoreInitializeTask>(
- store_, this,
- base::BindOnce(&FeedStream::InitializeComplete, base::Unretained(this))));
+ task_queue_.AddTask(FROM_HERE,
+ std::make_unique<WaitForStoreInitializeTask>(
+ store_, this,
+ base::BindOnce(&FeedStream::InitializeComplete,
+ base::Unretained(this))));
EnabledPreferencesChanged();
}
@@ -218,9 +221,11 @@ feedwire::DiscoverLaunchResult FeedStream::TriggerStreamLoad(
stream.surface_updater->LoadStreamStarted(/*manual_refreshing=*/false);
LoadStreamTask::Options options;
options.stream_type = stream_type;
- task_queue_.AddTask(std::make_unique<LoadStreamTask>(
- options, this,
- base::BindOnce(&FeedStream::StreamLoadComplete, base::Unretained(this))));
+ task_queue_.AddTask(FROM_HERE,
+ std::make_unique<LoadStreamTask>(
+ options, this,
+ base::BindOnce(&FeedStream::StreamLoadComplete,
+ base::Unretained(this))));
return feedwire::DiscoverLaunchResult::CARDS_UNSPECIFIED;
}
@@ -236,6 +241,10 @@ void FeedStream::InitializeComplete(WaitForStoreInitializeTask::Result result) {
}
}
metadata_populated_ = true;
+ metrics_reporter_->OnMetadataInitialized(IsFeedEnabledByEnterprisePolicy(),
+ IsArticlesListVisible(),
+ IsSignedIn(), metadata_);
+
web_feed_subscription_coordinator_->Populate(result.web_feed_startup_data);
for (const feedstore::StreamData& stream_data :
@@ -259,16 +268,12 @@ void FeedStream::StreamLoadComplete(LoadStreamTask::Result result) {
if (result.load_type == LoadType::kManualRefresh)
UnloadModel(result.stream_type);
- // TODO(crbug.com/1268575): SetLastFetchHadNoticeCard is duplicated here to
- // ensure that the pref is updated before LoadModel(), which needs this
- // information. This is fragile, we should instead store this information
- // along with the stream.
- if (result.fetched_content_has_notice_card.has_value())
- feed::prefs::SetLastFetchHadNoticeCard(
- *profile_prefs_, *result.fetched_content_has_notice_card);
-
if (result.update_request) {
- auto model = std::make_unique<StreamModel>(&stream_model_context_);
+ auto model = std::make_unique<StreamModel>(
+ &stream_model_context_,
+ feed::MakeLoggingParameters(prefs::GetClientInstanceId(*profile_prefs_),
+
+ *result.update_request));
model->Update(std::move(result.update_request));
if (!model->HasVisibleContent() &&
@@ -295,7 +300,6 @@ void FeedStream::StreamLoadComplete(LoadStreamTask::Result result) {
content_stats, GetRequestMetadata(stream.type, false),
std::move(result.latencies));
- UpdateIsActivityLoggingEnabled(result.stream_type);
stream.model_loading_in_progress = false;
stream.surface_updater->LoadStreamComplete(
stream.model != nullptr, result.final_status, result.launch_result);
@@ -312,10 +316,12 @@ void FeedStream::StreamLoadComplete(LoadStreamTask::Result result) {
options.load_type = LoadType::kBackgroundRefresh;
options.stream_type = kWebFeedStream;
options.abort_if_unread_content = true;
- task_queue_.AddTask(std::make_unique<LoadStreamTask>(
- options, this,
- base::BindOnce(&FeedStream::BackgroundRefreshComplete,
- base::Unretained(this))));
+ task_queue_.AddTask(
+ FROM_HERE,
+ std::make_unique<LoadStreamTask>(
+ options, this,
+ base::BindOnce(&FeedStream::BackgroundRefreshComplete,
+ base::Unretained(this))));
}
}
}
@@ -329,49 +335,18 @@ void FeedStream::StreamLoadComplete(LoadStreamTask::Result result) {
}
}
-LoggingParameters FeedStream::GetLoggingParameters(
- const StreamType& stream_type) {
- LoggingParameters logging_params;
- logging_params.client_instance_id = GetClientInstanceId();
- logging_params.logging_enabled = IsActivityLoggingEnabled(stream_type);
- Stream& stream = GetStream(stream_type);
- if (stream.model) {
- logging_params.root_event_id = stream.model->GetRootEventId();
- }
- logging_params.view_actions_enabled = CanLogViews();
- // We provide account name even if logging is disabled, so that account name
- // can be verified for action uploads.
- logging_params.email = delegate_->GetSyncSignedInEmail();
-
- return logging_params;
-}
-
void FeedStream::OnEnterBackground() {
metrics_reporter_->OnEnterBackground();
if (GetFeedConfig().upload_actions_on_enter_background) {
- task_queue_.AddTask(std::make_unique<UploadActionsTask>(
- this,
- /*launch_reliability_logger=*/nullptr,
- base::BindOnce(&FeedStream::UploadActionsComplete,
- base::Unretained(this))));
+ task_queue_.AddTask(FROM_HERE,
+ std::make_unique<UploadActionsTask>(
+ this,
+ /*launch_reliability_logger=*/nullptr,
+ base::BindOnce(&FeedStream::UploadActionsComplete,
+ base::Unretained(this))));
}
}
-bool FeedStream::IsActivityLoggingEnabled(const StreamType& stream_type) const {
- const Stream* stream = FindStream(stream_type);
- return stream && stream->is_activity_logging_enabled && CanUploadActions();
-}
-
-void FeedStream::UpdateIsActivityLoggingEnabled(const StreamType& stream_type) {
- Stream& stream = GetStream(stream_type);
-
- stream.is_activity_logging_enabled =
- stream.model &&
- ((stream.model->signed_in() && stream.model->logging_enabled()) ||
- (!stream.model->signed_in() &&
- GetFeedConfig().send_signed_out_session_logs));
-}
-
std::string FeedStream::GetSessionId() const {
return metadata_.session_id().token();
}
@@ -436,14 +411,12 @@ void FeedStream::AttachSurface(FeedStreamSurface* surface) {
// Cancel any scheduled model unload task.
++stream.unload_on_detach_sequence_number;
- upload_criteria_.SurfaceOpenedOrClosed();
}
void FeedStream::DetachSurface(FeedStreamSurface* surface) {
Stream& stream = GetStream(surface->GetStreamType());
metrics_reporter_->SurfaceClosed(surface->GetSurfaceId());
stream.surfaces.SurfaceRemoved(surface);
- upload_criteria_.SurfaceOpenedOrClosed();
ScheduleModelUnloadIfNoSurfacesAttached(surface->GetStreamType());
}
@@ -485,8 +458,9 @@ void FeedStream::AddUnloadModelIfNoSurfacesAttachedTask(
// Don't continue if unload_on_detach_sequence_number_ has changed.
if (stream.unload_on_detach_sequence_number != sequence_number)
return;
- task_queue_.AddTask(std::make_unique<offline_pages::ClosureTask>(
- base::BindOnce(&FeedStream::UnloadModelIfNoSurfacesAttachedTask,
+ task_queue_.AddTask(
+ FROM_HERE, std::make_unique<offline_pages::ClosureTask>(base::BindOnce(
+ &FeedStream::UnloadModelIfNoSurfacesAttachedTask,
base::Unretained(this), stream_type)));
}
@@ -502,10 +476,6 @@ bool FeedStream::IsArticlesListVisible() {
return articles_list_visible_.GetValue();
}
-std::string FeedStream::GetClientInstanceId() const {
- return prefs::GetClientInstanceId(*profile_prefs_);
-}
-
bool FeedStream::IsFeedEnabledByEnterprisePolicy() {
return enable_snippets_.GetValue();
}
@@ -543,9 +513,11 @@ void FeedStream::LoadMore(const FeedStreamSurface& surface,
// to all requestors.
stream.load_more_complete_callbacks.push_back(std::move(callback));
if (stream.load_more_complete_callbacks.size() == 1) {
- task_queue_.AddTask(std::make_unique<LoadMoreTask>(
- surface.GetStreamType(), this,
- base::BindOnce(&FeedStream::LoadMoreComplete, base::Unretained(this))));
+ task_queue_.AddTask(FROM_HERE,
+ std::make_unique<LoadMoreTask>(
+ surface.GetStreamType(), this,
+ base::BindOnce(&FeedStream::LoadMoreComplete,
+ base::Unretained(this))));
}
}
@@ -557,7 +529,6 @@ void FeedStream::LoadMoreComplete(LoadMoreTask::Result result) {
if (result.request_schedule)
SetRequestSchedule(stream.type, *result.request_schedule);
- UpdateIsActivityLoggingEnabled(stream.type);
metrics_reporter_->OnLoadMore(
result.stream_type, result.final_status,
stream.model ? stream.model->GetContentStats() : ContentStats());
@@ -588,10 +559,11 @@ void FeedStream::ManualRefresh(const StreamType& stream_type,
LoadStreamTask::Options options;
options.stream_type = stream_type;
options.load_type = LoadType::kManualRefresh;
- task_queue_.AddTask(std::make_unique<LoadStreamTask>(
- options, this,
- base::BindOnce(&FeedStream::StreamLoadComplete,
- base::Unretained(this))));
+ task_queue_.AddTask(FROM_HERE,
+ std::make_unique<LoadStreamTask>(
+ options, this,
+ base::BindOnce(&FeedStream::StreamLoadComplete,
+ base::Unretained(this))));
}
}
@@ -649,46 +621,35 @@ bool FeedStream::RejectEphemeralChange(const StreamType& stream_type,
return model->RejectEphemeralChange(id);
}
-void FeedStream::ProcessThereAndBackAgain(base::StringPiece data) {
+void FeedStream::ProcessThereAndBackAgain(
+ base::StringPiece data,
+ const LoggingParameters& logging_parameters) {
feedwire::ThereAndBackAgainData msg;
msg.ParseFromArray(data.data(), data.size());
if (msg.has_action_payload()) {
feedwire::FeedAction action_msg;
*action_msg.mutable_action_payload() = std::move(msg.action_payload());
- UploadAction(std::move(action_msg), /*upload_now=*/true,
+ UploadAction(std::move(action_msg), logging_parameters,
+ /*upload_now=*/true,
base::BindOnce(&FeedStream::UploadActionsComplete,
base::Unretained(this)));
}
}
-void FeedStream::ProcessThereAndBackAgain(
+void FeedStream::ProcessViewAction(
base::StringPiece data,
- const feedui::LoggingParameters& logging_parameters) {
- // TODO(crbug.com/1268575): Thread logging parameters to UploadActionTask when
- // it's always available.
- ProcessThereAndBackAgain(data);
-}
-
-void FeedStream::ProcessViewAction(base::StringPiece data) {
- if (!CanLogViews()) {
+ const LoggingParameters& logging_parameters) {
+ if (!logging_parameters.view_actions_enabled)
return;
- }
feedwire::FeedAction msg;
msg.ParseFromArray(data.data(), data.size());
- UploadAction(std::move(msg), /*upload_now=*/false,
+ UploadAction(std::move(msg), logging_parameters,
+ /*upload_now=*/false,
base::BindOnce(&FeedStream::UploadActionsComplete,
base::Unretained(this)));
}
-void FeedStream::ProcessViewAction(
- base::StringPiece data,
- const feedui::LoggingParameters& logging_parameters) {
- // TODO(crbug.com/1268575): Thread logging parameters to UploadActionTask when
- // it's always available.
- ProcessViewAction(data);
-}
-
void FeedStream::UploadActionsComplete(UploadActionsTask::Result result) {
PopulateDebugStreamData(result, *profile_prefs_);
}
@@ -706,9 +667,10 @@ DebugStreamData FeedStream::GetDebugStreamData() {
void FeedStream::ForceRefreshForDebugging(const StreamType& stream_type) {
// Avoid request throttling for debug refreshes.
feed::prefs::SetThrottlerRequestCounts({}, *profile_prefs_);
- task_queue_.AddTask(std::make_unique<offline_pages::ClosureTask>(
- base::BindOnce(&FeedStream::ForceRefreshForDebuggingTask,
- base::Unretained(this), stream_type)));
+ task_queue_.AddTask(
+ FROM_HERE, std::make_unique<offline_pages::ClosureTask>(
+ base::BindOnce(&FeedStream::ForceRefreshForDebuggingTask,
+ base::Unretained(this), stream_type)));
}
void FeedStream::ForceRefreshTask(const StreamType& stream_type) {
@@ -794,6 +756,9 @@ void FeedStream::SubscribedWebFeedCount(
base::OnceCallback<void(int)> callback) {
subscriptions().SubscribedWebFeedCount(std::move(callback));
}
+void FeedStream::RegisterFeedUserSettingsFieldTrial(base::StringPiece group) {
+ delegate_->RegisterFeedUserSettingsFieldTrial(group);
+}
void FeedStream::SetIdleCallbackForTesting(
base::RepeatingClosure idle_callback) {
@@ -856,7 +821,7 @@ LaunchResult FeedStream::ShouldAttemptLoad(const StreamType& stream_type,
// be called again from within the LoadStreamTask, and then the metadata
// will be initialized.
if (metadata_populated_ &&
- delegate_->GetSyncSignedInGaia() != metadata_.gaia()) {
+ delegate_->GetAccountInfo().gaia != metadata_.gaia()) {
return {LoadStreamStatus::kDataInStoreIsForAnotherUser,
feedwire::DiscoverLaunchResult::DATA_IN_STORE_IS_FOR_ANOTHER_USER};
}
@@ -923,10 +888,9 @@ bool FeedStream::ShouldForceSignedOutFeedQueryRequest(
base::TimeTicks::Now() < signed_out_for_you_refreshes_until_;
}
-RequestMetadata FeedStream::GetRequestMetadata(const StreamType& stream_type,
- bool is_for_next_page) const {
- const Stream* stream = FindStream(stream_type);
- DCHECK(stream);
+RequestMetadata FeedStream::GetCommonRequestMetadata(
+ bool signed_in_request,
+ bool allow_expired_session_id) const {
RequestMetadata result;
result.chrome_info = chrome_info_;
result.display_metrics = delegate_->GetDisplayMetrics();
@@ -936,34 +900,51 @@ RequestMetadata FeedStream::GetRequestMetadata(const StreamType& stream_type,
result.autoplay_enabled = delegate_->IsAutoplayEnabled();
result.acknowledged_notice_keys =
NoticeCardTracker::GetAllAckowledgedKeys(profile_prefs_);
- if (stream_type.IsWebFeed()) {
- result.content_order = GetValidWebFeedContentOrder(*profile_prefs_);
+
+ if (signed_in_request) {
+ result.client_instance_id = prefs::GetClientInstanceId(*profile_prefs_);
+ } else {
+ std::string session_id = GetSessionId();
+ if (!session_id.empty() &&
+ (allow_expired_session_id ||
+ feedstore::GetSessionIdExpiryTime(metadata_) > base::Time::Now())) {
+ result.session_id = session_id;
+ }
}
+ DCHECK(result.session_id.empty() || result.client_instance_id.empty());
+ return result;
+}
+
+RequestMetadata FeedStream::GetSignedInRequestMetadata() const {
+ return GetCommonRequestMetadata(/*signed_in_request =*/true,
+ /*allow_expired_session_id =*/true);
+}
+
+RequestMetadata FeedStream::GetRequestMetadata(const StreamType& stream_type,
+ bool is_for_next_page) const {
+ const Stream* stream = FindStream(stream_type);
+ DCHECK(stream);
+ RequestMetadata result;
if (is_for_next_page) {
// If we are continuing an existing feed, use whatever session continuity
// mechanism is currently associated with the stream: client-instance-id
// for signed-in feed, session_id token for signed-out.
DCHECK(stream->model);
- if (stream->model->signed_in()) {
- result.client_instance_id = GetClientInstanceId();
- } else {
- result.session_id = GetSessionId();
- }
+ result = GetCommonRequestMetadata(stream->model->signed_in(),
+ /*allow_expired_session_id =*/true);
} else {
// The request is for the first page of the feed. Use client_instance_id
// for signed in requests and session_id token (if any, and not expired)
// for signed-out.
- if (IsSignedIn() && !ShouldForceSignedOutFeedQueryRequest(stream_type)) {
- result.client_instance_id = GetClientInstanceId();
- } else if (!GetSessionId().empty() && feedstore::GetSessionIdExpiryTime(
- metadata_) > base::Time::Now()) {
- result.session_id = GetSessionId();
- }
+ result = GetCommonRequestMetadata(
+ IsSignedIn() && !ShouldForceSignedOutFeedQueryRequest(stream_type),
+ /*allow_expired_session_id =*/false);
}
- DCHECK(result.session_id.empty() || result.client_instance_id.empty());
-
+ if (stream_type.IsWebFeed()) {
+ result.content_order = GetValidWebFeedContentOrder(*profile_prefs_);
+ }
return result;
}
@@ -1039,10 +1020,11 @@ void FeedStream::ExecuteRefreshTask(RefreshTaskId task_id) {
options.stream_type = stream_type;
options.load_type = LoadType::kBackgroundRefresh;
options.refresh_even_when_not_stale = true;
- task_queue_.AddTask(std::make_unique<LoadStreamTask>(
- options, this,
- base::BindOnce(&FeedStream::BackgroundRefreshComplete,
- base::Unretained(this))));
+ task_queue_.AddTask(FROM_HERE,
+ std::make_unique<LoadStreamTask>(
+ options, this,
+ base::BindOnce(&FeedStream::BackgroundRefreshComplete,
+ base::Unretained(this))));
}
void FeedStream::BackgroundRefreshComplete(LoadStreamTask::Result result) {
@@ -1054,7 +1036,7 @@ void FeedStream::BackgroundRefreshComplete(LoadStreamTask::Result result) {
// Add prefetch images to task queue without waiting to finish
// since we treat them as best-effort.
if (result.stream_type.IsForYou())
- task_queue_.AddTask(std::make_unique<PrefetchImagesTask>(this));
+ task_queue_.AddTask(FROM_HERE, std::make_unique<PrefetchImagesTask>(this));
RefreshTaskId task_id;
if (result.stream_type.GetRefreshTaskId(task_id)) {
@@ -1065,14 +1047,11 @@ void FeedStream::BackgroundRefreshComplete(LoadStreamTask::Result result) {
// Performs work that is necessary for both background and foreground load
// tasks.
void FeedStream::LoadTaskComplete(const LoadStreamTask::Result& result) {
- if (delegate_->GetSyncSignedInGaia() != metadata_.gaia()) {
+ if (delegate_->GetAccountInfo().gaia != metadata_.gaia()) {
ClearAll();
return;
}
PopulateDebugStreamData(result, *profile_prefs_);
- if (result.fetched_content_has_notice_card.has_value())
- feed::prefs::SetLastFetchHadNoticeCard(
- *profile_prefs_, *result.fetched_content_has_notice_card);
if (!result.content_ids.IsEmpty()) {
GetStream(result.stream_type).content_ids = result.content_ids;
}
@@ -1109,7 +1088,7 @@ void FeedStream::ClearAll() {
metrics_reporter_->OnClearAll(base::Time::Now() -
GetLastFetchTime(kForYouStream));
clear_all_in_progress_ = true;
- task_queue_.AddTask(std::make_unique<ClearAllTask>(this));
+ task_queue_.AddTask(FROM_HERE, std::make_unique<ClearAllTask>(this));
}
void FeedStream::FinishClearAll() {
@@ -1117,8 +1096,7 @@ void FeedStream::FinishClearAll() {
has_stored_data_.SetValue(false);
feed::prefs::SetExperiments({}, *profile_prefs_);
feed::prefs::ClearClientInstanceId(*profile_prefs_);
- upload_criteria_.Clear();
- SetMetadata(feedstore::MakeMetadata(delegate_->GetSyncSignedInGaia()));
+ SetMetadata(feedstore::MakeMetadata(delegate_->GetAccountInfo().gaia));
delegate_->ClearAll();
@@ -1150,34 +1128,26 @@ void FeedStream::CancelImageFetch(ImageFetchId id) {
void FeedStream::UploadAction(
feedwire::FeedAction action,
+ const LoggingParameters& logging_parameters,
bool upload_now,
base::OnceCallback<void(UploadActionsTask::Result)> callback) {
- if (!IsSignedIn()) {
- DLOG(WARNING)
- << "Called UploadActions while user is signed-out, dropping upload";
- return;
- }
- task_queue_.AddTask(std::make_unique<UploadActionsTask>(
- std::move(action), upload_now, this, std::move(callback)));
+ task_queue_.AddTask(
+ FROM_HERE, std::make_unique<UploadActionsTask>(
+ std::move(action), upload_now, logging_parameters, this,
+ std::move(callback)));
}
void FeedStream::LoadModel(const StreamType& stream_type,
std::unique_ptr<StreamModel> model) {
+ DCHECK(model);
Stream& stream = GetStream(stream_type);
DCHECK(!stream.model);
stream.model = std::move(model);
stream.model->SetStreamType(stream_type);
stream.model->SetStoreObserver(this);
- // TODO(crbug.com/1268575): Once the internal changes to support per-item
- // logging parameters is submitted, we should remove
- // UpdateIsActivityLoggingEnabled() and instead store the logging parameters
- // on the model.
- UpdateIsActivityLoggingEnabled(stream_type);
-
stream.content_ids = stream.model->GetContentIds();
- stream.surface_updater->SetModel(stream.model.get(),
- GetLoggingParameters(stream_type));
+ stream.surface_updater->SetModel(stream.model.get());
ScheduleModelUnloadIfNoSurfacesAttached(stream_type);
MaybeNotifyHasUnreadContent(stream_type);
}
@@ -1210,7 +1180,7 @@ void FeedStream::UnloadModel(const StreamType& stream_type) {
Stream* stream = FindStream(stream_type);
if (!stream || !stream->model)
return;
- stream->surface_updater->SetModel(nullptr, LoggingParameters());
+ stream->surface_updater->SetModel(nullptr);
stream->model.reset();
}
@@ -1285,16 +1255,6 @@ void FeedStream::ReportSliceViewed(SurfaceId surface_id,
stream.model->FindContentId(ToContentRevision(slice_id)));
}
-// TODO(crbug/1147237): Rename this method and related members?
-bool FeedStream::CanUploadActions() const {
- return upload_criteria_.CanUploadActions();
-}
-
-bool FeedStream::CanLogViews() const {
- // TODO(crbug/1152592): Determine notice card behavior with web feeds.
- return CanUploadActions();
-}
-
// Notifies observers if 'HasUnreadContent' has changed for `stream_type`.
// Stream content has been seen if StreamData::content_hash ==
// Metadata::StreamMetadata::view_content_hash. This should be called:
@@ -1410,6 +1370,7 @@ void FeedStream::SetContentOrder(const StreamType& stream_type,
// want a full refresh.
// * it will add quite a bit of complexity to do it right
task_queue_.AddTask(
+ FROM_HERE,
std::make_unique<offline_pages::ClosureTask>(base::BindOnce(
&FeedStream::ForceRefreshTask, base::Unretained(this), stream_type)));
}
diff --git a/chromium/components/feed/core/v2/feed_stream.h b/chromium/components/feed/core/v2/feed_stream.h
index 3c981d3069a..b43e1a21fff 100644
--- a/chromium/components/feed/core/v2/feed_stream.h
+++ b/chromium/components/feed/core/v2/feed_stream.h
@@ -26,11 +26,11 @@
#include "components/feed/core/v2/persistent_key_value_store_impl.h"
#include "components/feed/core/v2/protocol_translator.h"
#include "components/feed/core/v2/public/feed_api.h"
+#include "components/feed/core/v2/public/logging_parameters.h"
#include "components/feed/core/v2/public/stream_type.h"
#include "components/feed/core/v2/request_throttler.h"
#include "components/feed/core/v2/scheduling.h"
#include "components/feed/core/v2/stream/privacy_notice_card_tracker.h"
-#include "components/feed/core/v2/stream/upload_criteria.h"
#include "components/feed/core/v2/stream_model.h"
#include "components/feed/core/v2/stream_surface_set.h"
#include "components/feed/core/v2/tasks/load_more_task.h"
@@ -77,10 +77,11 @@ class FeedStream : public FeedApi,
virtual std::string GetLanguageTag() = 0;
virtual bool IsAutoplayEnabled() = 0;
virtual void ClearAll() = 0;
- virtual std::string GetSyncSignedInGaia() = 0;
- virtual std::string GetSyncSignedInEmail() = 0;
+ virtual AccountInfo GetAccountInfo() = 0;
virtual void PrefetchImage(const GURL& url) = 0;
virtual void RegisterExperiments(const Experiments& experiments) = 0;
+ virtual void RegisterFeedUserSettingsFieldTrial(
+ base::StringPiece group) = 0;
};
FeedStream(RefreshTaskScheduler* refresh_task_scheduler,
@@ -100,7 +101,6 @@ class FeedStream : public FeedApi,
// FeedApi.
WebFeedSubscriptionCoordinator& subscriptions() override;
- bool IsActivityLoggingEnabled(const StreamType& stream_type) const override;
std::string GetSessionId() const override;
void AttachSurface(FeedStreamSurface*) override;
void DetachSurface(FeedStreamSurface*) override;
@@ -109,7 +109,6 @@ class FeedStream : public FeedApi,
void RemoveUnreadContentObserver(const StreamType& stream_type,
UnreadContentObserver* observer) override;
bool IsArticlesListVisible() override;
- std::string GetClientInstanceId() const override;
void ExecuteRefreshTask(RefreshTaskId task_id) override;
ImageFetchId FetchImage(
const GURL& url,
@@ -133,14 +132,11 @@ class FeedStream : public FeedApi,
EphemeralChangeId id) override;
bool RejectEphemeralChange(const StreamType& stream_type,
EphemeralChangeId id) override;
- void ProcessThereAndBackAgain(base::StringPiece data) override;
void ProcessThereAndBackAgain(
base::StringPiece data,
- const feedui::LoggingParameters& logging_parameters) override;
- void ProcessViewAction(base::StringPiece data) override;
- void ProcessViewAction(
- base::StringPiece data,
- const feedui::LoggingParameters& logging_parameters) override;
+ const LoggingParameters& logging_parameters) override;
+ void ProcessViewAction(base::StringPiece data,
+ const LoggingParameters& logging_parameters) override;
bool WasUrlRecentlyNavigatedFromFeed(const GURL& url) override;
DebugStreamData GetDebugStreamData() override;
void ForceRefreshForDebugging(const StreamType& stream_type) override;
@@ -185,6 +181,7 @@ class FeedStream : public FeedApi,
// MetricsReporter::Delegate.
void SubscribedWebFeedCount(base::OnceCallback<void(int)> callback) override;
+ void RegisterFeedUserSettingsFieldTrial(base::StringPiece group) override;
// StreamModel::StoreObserver.
void OnStoreChange(StreamModel::StoreUpdate update) override;
@@ -216,6 +213,7 @@ class FeedStream : public FeedApi,
// called with |true| if the consistency token was written to the store.
void UploadAction(
feedwire::FeedAction action,
+ const LoggingParameters& logging_parameters,
bool upload_now,
base::OnceCallback<void(UploadActionsTask::Result)> callback);
@@ -231,10 +229,8 @@ class FeedStream : public FeedApi,
void PrefetchImage(const GURL& url);
- bool IsSignedIn() const { return !delegate_->GetSyncSignedInGaia().empty(); }
- std::string GetSyncSignedInGaia() const {
- return delegate_->GetSyncSignedInGaia();
- }
+ bool IsSignedIn() const { return !delegate_->GetAccountInfo().IsEmpty(); }
+ AccountInfo GetAccountInfo() const { return delegate_->GetAccountInfo(); }
// Determines if we should attempt loading the stream or refreshing at all.
// Returns |LoadStreamStatus::kNoStatus| if loading may be attempted.
@@ -278,6 +274,14 @@ class FeedStream : public FeedApi,
// Returns the model if it is loaded, or null otherwise.
StreamModel* GetModel(const StreamType& stream_type);
+ // Gets request metadata assuming the account is signed-in. This is useful for
+ // uploading actions where stream type is not known, but sign-in status is
+ // required.
+ RequestMetadata GetSignedInRequestMetadata() const;
+
+ // Gets request metadata, looking up if session ID or client instance ID
+ // should be used based on the login state of Chrome and the model for the
+ // appropriate Stream.
RequestMetadata GetRequestMetadata(const StreamType& stream_type,
bool is_for_next_page) const;
@@ -306,13 +310,11 @@ class FeedStream : public FeedApi,
}
void SetIdleCallbackForTesting(base::RepeatingClosure idle_callback);
- bool CanUploadActions() const;
-
bool ClearAllInProgress() const { return clear_all_in_progress_; }
bool IsEnabledAndVisible();
- LoggingParameters GetLoggingParameters(const StreamType& stream_type);
+ PrefService* profile_prefs() const { return profile_prefs_; }
base::WeakPtr<FeedStream> GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
@@ -351,9 +353,6 @@ class FeedStream : public FeedApi,
void SetRequestSchedule(RefreshTaskId task_id, RequestSchedule schedule);
- // Re-evaluate whether or not activity logging should currently be enabled.
- void UpdateIsActivityLoggingEnabled(const StreamType& stream_type);
-
// A single function task to delete stored feed data and force a refresh.
// To only be called from within a |Task|.
void ForceRefreshForDebuggingTask(const StreamType& stream_type);
@@ -375,8 +374,6 @@ class FeedStream : public FeedApi,
bool HasReachedConditionsToUploadActionsWithNoticeCard();
- bool CanLogViews() const;
-
void MaybeNotifyHasUnreadContent(const StreamType& stream_type);
void EnabledPreferencesChanged();
@@ -387,6 +384,9 @@ class FeedStream : public FeedApi,
NoticeCardTracker& GetNoticeCardTracker(const std::string& key);
+ RequestMetadata GetCommonRequestMetadata(bool signed_in_request,
+ bool allow_expired_session_id) const;
+
// Unowned.
raw_ptr<RefreshTaskScheduler> refresh_task_scheduler_;
@@ -431,7 +431,6 @@ class FeedStream : public FeedApi,
// internals page for debugging purpose.
feedui::StreamUpdate forced_stream_update_for_debugging_;
- feed_stream::UploadCriteria upload_criteria_;
PrivacyNoticeCardTracker privacy_notice_card_tracker_;
std::map<std::string, NoticeCardTracker> notice_card_trackers_;
diff --git a/chromium/components/feed/core/v2/ios_shared_prefs.h b/chromium/components/feed/core/v2/ios_shared_prefs.h
index d07a466e377..abcda7f5abb 100644
--- a/chromium/components/feed/core/v2/ios_shared_prefs.h
+++ b/chromium/components/feed/core/v2/ios_shared_prefs.h
@@ -11,6 +11,9 @@ namespace feed {
namespace prefs {
void SetLastFetchHadNoticeCard(PrefService& pref_service, bool value);
bool GetLastFetchHadNoticeCard(const PrefService& pref_service);
+
+// TODO(b/213622639): These two functions are still used for iOS, but should
+// be removed along with any calling code.
void SetHasReachedClickAndViewActionsUploadConditions(PrefService& pref_service,
bool value);
bool GetHasReachedClickAndViewActionsUploadConditions(
diff --git a/chromium/components/feed/core/v2/metrics_reporter.cc b/chromium/components/feed/core/v2/metrics_reporter.cc
index bf233cdb7af..ab45f85c933 100644
--- a/chromium/components/feed/core/v2/metrics_reporter.cc
+++ b/chromium/components/feed/core/v2/metrics_reporter.cc
@@ -16,6 +16,8 @@
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "build/build_config.h"
+#include "components/feed/core/v2/enums.h"
+#include "components/feed/core/v2/feedstore_util.h"
#include "components/feed/core/v2/prefs.h"
#include "components/feed/core/v2/public/common_enums.h"
#include "components/feed/core/v2/public/feed_api.h"
@@ -104,7 +106,7 @@ base::StringPiece ContentOrderToString(ContentOrder content_order) {
switch (content_order) {
case ContentOrder::kUnspecified:
NOTREACHED();
- FALLTHROUGH;
+ [[fallthrough]];
case ContentOrder::kGrouped:
return "Grouped";
case ContentOrder::kReverseChron:
@@ -170,6 +172,45 @@ std::string NoticeUmaName(const StreamType& stream_type,
uma_base_name, ".", normalized_key});
}
+UserSettingsOnStart GetUserSettingsOnStart(
+ bool isEnabledByEnterprisePolicy,
+ bool isFeedVisible,
+ bool isSignedIn,
+ const feedstore::Metadata& metadata) {
+ if (!isEnabledByEnterprisePolicy)
+ return UserSettingsOnStart::kFeedNotEnabledByPolicy;
+ if (!isFeedVisible) {
+ if (isSignedIn)
+ return UserSettingsOnStart::kFeedNotVisibleSignedIn;
+ return UserSettingsOnStart::kFeedNotVisibleSignedOut;
+ }
+ if (!isSignedIn)
+ return UserSettingsOnStart::kSignedOut;
+
+ const base::Time now = base::Time::Now();
+ bool has_recent_data = false;
+ for (const feedstore::Metadata::StreamMetadata& stream_meta :
+ metadata.stream_metadata()) {
+ base::TimeDelta delta = now - feedstore::FromTimestampMillis(
+ stream_meta.last_fetch_time_millis());
+ if (delta >= base::TimeDelta() && delta <= kUserSettingsMaxAge)
+ has_recent_data = true;
+ }
+
+ if (!has_recent_data)
+ return UserSettingsOnStart::kSignedInNoRecentData;
+
+ if (metadata.web_and_app_activity_enabled()) {
+ if (metadata.discover_personalization_enabled())
+ return UserSettingsOnStart::kSignedInWaaOnDpOn;
+ return UserSettingsOnStart::kSignedInWaaOnDpOff;
+ } else {
+ if (metadata.discover_personalization_enabled())
+ return UserSettingsOnStart::kSignedInWaaOffDpOn;
+ return UserSettingsOnStart::kSignedInWaaOffDpOff;
+ }
+}
+
} // namespace
MetricsReporter::SurfaceWaiting::SurfaceWaiting() = default;
@@ -201,6 +242,18 @@ void MetricsReporter::Initialize(Delegate* delegate) {
delegate_ = delegate;
}
+void MetricsReporter::OnMetadataInitialized(
+ bool isEnabledByEnterprisePolicy,
+ bool isFeedVisible,
+ bool isSignedIn,
+ const feedstore::Metadata& metadata) {
+ UserSettingsOnStart settings = GetUserSettingsOnStart(
+ isEnabledByEnterprisePolicy, isFeedVisible, isSignedIn, metadata);
+ delegate_->RegisterFeedUserSettingsFieldTrial(ToString(settings));
+ base::UmaHistogramEnumeration("ContentSuggestions.Feed.UserSettingsOnStart",
+ settings);
+}
+
void MetricsReporter::OnEnterBackground() {
FinalizeMetrics();
}
@@ -494,6 +547,11 @@ void MetricsReporter::OtherUserAction(const StreamType& stream_type,
base::UserMetricsAction("ContentSuggestions.Feed.CardAction.Share"));
RecordInteraction(stream_type);
break;
+ case FeedUserActionType::kTappedManage:
+ base::RecordAction(
+ base::UserMetricsAction("ContentSuggestions.Feed.CardAction.Manage"));
+ RecordInteraction(stream_type);
+ break;
case FeedUserActionType::kEphemeralChange:
case FeedUserActionType::kEphemeralChangeRejected:
case FeedUserActionType::kTappedTurnOn:
@@ -642,7 +700,7 @@ void MetricsReporter::NetworkRequestComplete(
VVLOG << "Network Request Complete type=" << NetworkRequestTypeUmaName(type)
<< " status=" << response_info.status_code
<< " url=" << response_info.base_request_url
- << " signed_in=" << response_info.was_signed_in
+ << " account_info=" << response_info.account_info
<< " response_size=" << response_info.encoded_size_bytes
<< " duration=" << response_info.fetch_duration;
diff --git a/chromium/components/feed/core/v2/metrics_reporter.h b/chromium/components/feed/core/v2/metrics_reporter.h
index 0b85649d98c..6c6cec16eed 100644
--- a/chromium/components/feed/core/v2/metrics_reporter.h
+++ b/chromium/components/feed/core/v2/metrics_reporter.h
@@ -19,7 +19,13 @@
#include "third_party/abseil-cpp/absl/types/optional.h"
class PrefService;
+namespace feedstore {
+class Metadata;
+}
+
namespace feed {
+// If cached user setting info is older than this, it will not be reported.
+constexpr base::TimeDelta kUserSettingsMaxAge = base::Days(14);
// Reports UMA metrics for feed.
// Note this is inherited only for testing.
@@ -36,6 +42,8 @@ class MetricsReporter {
// subscribed.
virtual void SubscribedWebFeedCount(
base::OnceCallback<void(int)> callback) = 0;
+ virtual void RegisterFeedUserSettingsFieldTrial(
+ base::StringPiece group) = 0;
};
explicit MetricsReporter(PrefService* profile_prefs);
@@ -46,6 +54,11 @@ class MetricsReporter {
// Two-step initialization, required for circular dependency.
void Initialize(Delegate* delegate);
+ void OnMetadataInitialized(bool isEnabledByEnterprisePolicy,
+ bool isFeedVisible,
+ bool isSignedIn,
+ const feedstore::Metadata& metadata);
+
// User interactions. See |FeedApi| for definitions.
virtual void ContentSliceViewed(const StreamType& stream_type,
diff --git a/chromium/components/feed/core/v2/metrics_reporter_unittest.cc b/chromium/components/feed/core/v2/metrics_reporter_unittest.cc
index faad54c89c7..9543da1ae38 100644
--- a/chromium/components/feed/core/v2/metrics_reporter_unittest.cc
+++ b/chromium/components/feed/core/v2/metrics_reporter_unittest.cc
@@ -11,11 +11,15 @@
#include "base/test/metrics/user_action_tester.h"
#include "base/test/task_environment.h"
#include "components/feed/core/common/pref_names.h"
+#include "components/feed/core/proto/v2/store.pb.h"
#include "components/feed/core/shared_prefs/pref_names.h"
+#include "components/feed/core/v2/enums.h"
+#include "components/feed/core/v2/feedstore_util.h"
#include "components/feed/core/v2/public/common_enums.h"
#include "components/feed/core/v2/public/feed_api.h"
#include "components/feed/core/v2/public/stream_type.h"
#include "components/feed/core/v2/public/types.h"
+#include "components/feed/core/v2/test/callback_receiver.h"
#include "components/feed/core/v2/types.h"
#include "components/prefs/testing_pref_service.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -57,13 +61,13 @@ class MetricsReporterTest : public testing::Test, MetricsReporter::Delegate {
std::map<FeedEngagementType, int> result;
const char* histogram_name;
switch (stream_type.GetType()) {
- case StreamType::Type::kForYou:
+ case StreamKind::kForYou:
histogram_name = "ContentSuggestions.Feed.EngagementType";
break;
- case StreamType::Type::kWebFeed:
+ case StreamKind::kFollowing:
histogram_name = "ContentSuggestions.Feed.WebFeed.EngagementType";
break;
- case StreamType::Type::kUnspecified:
+ case StreamKind::kUnknown:
histogram_name = "ContentSuggestions.Feed.AllFeeds.EngagementType";
break;
}
@@ -83,6 +87,10 @@ class MetricsReporterTest : public testing::Test, MetricsReporter::Delegate {
void SubscribedWebFeedCount(base::OnceCallback<void(int)> callback) override {
std::move(callback).Run(kSubscriptionCount);
}
+ void RegisterFeedUserSettingsFieldTrial(base::StringPiece group) override {
+ register_feed_user_settings_field_trial_calls_.push_back(
+ static_cast<std::string>(group));
+ }
base::test::TaskEnvironment task_environment_{
base::test::TaskEnvironment::TimeSource::MOCK_TIME};
@@ -90,6 +98,7 @@ class MetricsReporterTest : public testing::Test, MetricsReporter::Delegate {
std::unique_ptr<MetricsReporter> reporter_;
base::HistogramTester histogram_;
base::UserActionTester user_actions_;
+ std::vector<std::string> register_feed_user_settings_field_trial_calls_;
};
TEST_F(MetricsReporterTest, SliceViewedReportsSuggestionShown) {
@@ -1017,4 +1026,140 @@ TEST_F(MetricsReporterTest, ReportNotice) {
.empty());
}
+TEST_F(MetricsReporterTest, UserSettingsOnStart_FeedNotEnabled) {
+ reporter_->OnMetadataInitialized(/*isEnabledByEnterprisePolicy=*/false,
+ /*isFeedVisible=*/false,
+ /*isSignedIn=*/false, feedstore::Metadata());
+ histogram_.ExpectUniqueSample("ContentSuggestions.Feed.UserSettingsOnStart",
+ UserSettingsOnStart::kFeedNotEnabledByPolicy,
+ 1);
+ EXPECT_EQ(std::vector<std::string>({"FeedNotEnabledByPolicy"}),
+ register_feed_user_settings_field_trial_calls_);
+}
+
+TEST_F(MetricsReporterTest, UserSettingsOnStart_FeedNotVisible_SignedOut) {
+ reporter_->OnMetadataInitialized(/*isEnabledByEnterprisePolicy=*/true,
+ /*isFeedVisible=*/false,
+ /*isSignedIn=*/false, feedstore::Metadata());
+ histogram_.ExpectUniqueSample("ContentSuggestions.Feed.UserSettingsOnStart",
+ UserSettingsOnStart::kFeedNotVisibleSignedOut,
+ 1);
+ EXPECT_EQ(std::vector<std::string>({"FeedNotVisibleSignedOut"}),
+ register_feed_user_settings_field_trial_calls_);
+}
+
+TEST_F(MetricsReporterTest, UserSettingsOnStart_FeedNotVisible_SignedIn) {
+ reporter_->OnMetadataInitialized(/*isEnabledByEnterprisePolicy=*/true,
+ /*isFeedVisible=*/false,
+ /*isSignedIn=*/true, feedstore::Metadata());
+ histogram_.ExpectUniqueSample("ContentSuggestions.Feed.UserSettingsOnStart",
+ UserSettingsOnStart::kFeedNotVisibleSignedIn,
+ 1);
+ EXPECT_EQ(std::vector<std::string>({"FeedNotVisibleSignedIn"}),
+ register_feed_user_settings_field_trial_calls_);
+}
+
+TEST_F(MetricsReporterTest, UserSettingsOnStart_EnabledSignedOut) {
+ reporter_->OnMetadataInitialized(/*isEnabledByEnterprisePolicy=*/true,
+ /*isFeedVisible=*/true,
+ /*isSignedIn=*/false, feedstore::Metadata());
+ histogram_.ExpectUniqueSample("ContentSuggestions.Feed.UserSettingsOnStart",
+ UserSettingsOnStart::kSignedOut, 1);
+ EXPECT_EQ(std::vector<std::string>({"SignedOut"}),
+ register_feed_user_settings_field_trial_calls_);
+}
+
+TEST_F(MetricsReporterTest, UserSettingsOnStart_WaaOffDpOff) {
+ feedstore::Metadata metadata;
+ // Content age is within kUserSettingsMaxAge.
+ metadata.add_stream_metadata()->set_last_fetch_time_millis(
+ feedstore::ToTimestampMillis(base::Time::Now() - kUserSettingsMaxAge));
+ reporter_->OnMetadataInitialized(/*isEnabledByEnterprisePolicy=*/true,
+ /*isFeedVisible=*/true,
+ /*isSignedIn=*/true, metadata);
+ histogram_.ExpectUniqueSample("ContentSuggestions.Feed.UserSettingsOnStart",
+ UserSettingsOnStart::kSignedInWaaOffDpOff, 1);
+ EXPECT_EQ(std::vector<std::string>({"SignedInWaaOffDpOff"}),
+ register_feed_user_settings_field_trial_calls_);
+}
+
+TEST_F(MetricsReporterTest, UserSettingsOnStart_WaaOnDpOff) {
+ feedstore::Metadata metadata;
+ // Content age is within kUserSettingsMaxAge.
+ metadata.add_stream_metadata()->set_last_fetch_time_millis(
+ feedstore::ToTimestampMillis(base::Time::Now()));
+ metadata.set_web_and_app_activity_enabled(true);
+ reporter_->OnMetadataInitialized(/*isEnabledByEnterprisePolicy=*/true,
+ /*isFeedVisible=*/true,
+ /*isSignedIn=*/true, metadata);
+ histogram_.ExpectUniqueSample("ContentSuggestions.Feed.UserSettingsOnStart",
+ UserSettingsOnStart::kSignedInWaaOnDpOff, 1);
+ EXPECT_EQ(std::vector<std::string>({"SignedInWaaOnDpOff"}),
+ register_feed_user_settings_field_trial_calls_);
+}
+
+TEST_F(MetricsReporterTest, UserSettingsOnStart_WaaOffDpOn) {
+ feedstore::Metadata metadata;
+ // Only the first stream has age less than kUserSettingsMaxAge.
+ metadata.add_stream_metadata()->set_last_fetch_time_millis(
+ feedstore::ToTimestampMillis(base::Time::Now()));
+ metadata.add_stream_metadata()->set_last_fetch_time_millis(
+ feedstore::ToTimestampMillis(base::Time::Now() - kUserSettingsMaxAge -
+ base::Seconds(1)));
+ metadata.set_discover_personalization_enabled(true);
+ reporter_->OnMetadataInitialized(/*isEnabledByEnterprisePolicy=*/true,
+ /*isFeedVisible=*/true,
+ /*isSignedIn=*/true, metadata);
+ histogram_.ExpectUniqueSample("ContentSuggestions.Feed.UserSettingsOnStart",
+ UserSettingsOnStart::kSignedInWaaOffDpOn, 1);
+ EXPECT_EQ(std::vector<std::string>({"SignedInWaaOffDpOn"}),
+ register_feed_user_settings_field_trial_calls_);
+}
+
+TEST_F(MetricsReporterTest, UserSettingsOnStart_WaaOnDpOn) {
+ feedstore::Metadata metadata;
+ // Only the second stream has age less than kUserSettingsMaxAge.
+ metadata.add_stream_metadata()->set_last_fetch_time_millis(
+ feedstore::ToTimestampMillis(base::Time::Now() - kUserSettingsMaxAge -
+ base::Seconds(1)));
+ metadata.add_stream_metadata()->set_last_fetch_time_millis(
+ feedstore::ToTimestampMillis(base::Time::Now()));
+ metadata.set_discover_personalization_enabled(true);
+ metadata.set_web_and_app_activity_enabled(true);
+ reporter_->OnMetadataInitialized(/*isEnabledByEnterprisePolicy=*/true,
+ /*isFeedVisible=*/true,
+ /*isSignedIn=*/true, metadata);
+ histogram_.ExpectUniqueSample("ContentSuggestions.Feed.UserSettingsOnStart",
+ UserSettingsOnStart::kSignedInWaaOnDpOn, 1);
+ EXPECT_EQ(std::vector<std::string>({"SignedInWaaOnDpOn"}),
+ register_feed_user_settings_field_trial_calls_);
+}
+
+TEST_F(MetricsReporterTest, UserSettingsOnStart_FeedDataTooOld) {
+ feedstore::Metadata metadata;
+ metadata.add_stream_metadata()->set_last_fetch_time_millis(
+ feedstore::ToTimestampMillis(base::Time::Now() - kUserSettingsMaxAge -
+ base::Seconds(1)));
+ reporter_->OnMetadataInitialized(/*isEnabledByEnterprisePolicy=*/true,
+ /*isFeedVisible=*/true,
+ /*isSignedIn=*/true, metadata);
+ histogram_.ExpectUniqueSample("ContentSuggestions.Feed.UserSettingsOnStart",
+ UserSettingsOnStart::kSignedInNoRecentData, 1);
+ EXPECT_EQ(std::vector<std::string>({"SignedInNoRecentData"}),
+ register_feed_user_settings_field_trial_calls_);
+}
+
+TEST_F(MetricsReporterTest, UserSettingsOnStart_FeedDataFromFuture) {
+ feedstore::Metadata metadata;
+ metadata.add_stream_metadata()->set_last_fetch_time_millis(
+ feedstore::ToTimestampMillis(base::Time::Now() + base::Seconds(1)));
+ reporter_->OnMetadataInitialized(/*isEnabledByEnterprisePolicy=*/true,
+ /*isFeedVisible=*/true,
+ /*isSignedIn=*/true, metadata);
+ histogram_.ExpectUniqueSample("ContentSuggestions.Feed.UserSettingsOnStart",
+ UserSettingsOnStart::kSignedInNoRecentData, 1);
+ EXPECT_EQ(std::vector<std::string>({"SignedInNoRecentData"}),
+ register_feed_user_settings_field_trial_calls_);
+}
+
} // namespace feed
diff --git a/chromium/components/feed/core/v2/operation_token.cc b/chromium/components/feed/core/v2/operation_token.cc
new file mode 100644
index 00000000000..60195b720e5
--- /dev/null
+++ b/chromium/components/feed/core/v2/operation_token.cc
@@ -0,0 +1,31 @@
+// Copyright 2022 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.
+
+#include "components/feed/core/v2/operation_token.h"
+
+namespace feed {
+
+OperationToken::~OperationToken() = default;
+OperationToken::OperationToken(const OperationToken& src) = default;
+OperationToken& OperationToken::operator=(const OperationToken& src) = default;
+OperationToken::OperationToken(base::WeakPtr<Operation> token)
+ : token_(token) {}
+
+// static
+OperationToken OperationToken::MakeInvalid() {
+ return OperationToken(base::WeakPtr<Operation>{});
+}
+OperationToken::operator bool() const {
+ return token_.MaybeValid();
+}
+OperationToken::Operation::Operation() = default;
+OperationToken::Operation::~Operation() = default;
+void OperationToken::Operation::Reset() {
+ weak_ptr_factory_.InvalidateWeakPtrs();
+}
+OperationToken OperationToken::Operation::Token() {
+ return OperationToken{weak_ptr_factory_.GetWeakPtr()};
+}
+
+} // namespace feed
diff --git a/chromium/components/feed/core/v2/operation_token.h b/chromium/components/feed/core/v2/operation_token.h
new file mode 100644
index 00000000000..8275c596308
--- /dev/null
+++ b/chromium/components/feed/core/v2/operation_token.h
@@ -0,0 +1,48 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_FEED_CORE_V2_OPERATION_TOKEN_H_
+#define COMPONENTS_FEED_CORE_V2_OPERATION_TOKEN_H_
+
+#include "base/memory/weak_ptr.h"
+
+namespace feed {
+
+// A copyable object which Tracks whether or not an `Operation` is alive.
+class OperationToken {
+ public:
+ static OperationToken MakeInvalid();
+ ~OperationToken();
+ OperationToken(const OperationToken& src);
+ OperationToken& operator=(const OperationToken& src);
+
+ // Returns whether the operation is alive. Returns `false` if the operation
+ // has been destroyed.
+ explicit operator bool() const;
+
+ // An operation which can be tracked by `OperationToken`.
+ class Operation {
+ public:
+ Operation();
+ ~Operation();
+ Operation(const Operation&) = delete;
+ Operation& operator=(const Operation&) const = delete;
+
+ // Reset the operation, and start a new one. All existing operation
+ // tokens will report this operation as destroyed.
+ void Reset();
+ // Return a token pointing to this operation.
+ OperationToken Token();
+
+ private:
+ base::WeakPtrFactory<Operation> weak_ptr_factory_{this};
+ };
+
+ private:
+ explicit OperationToken(base::WeakPtr<Operation> token);
+ base::WeakPtr<Operation> token_;
+};
+} // namespace feed
+
+#endif // COMPONENTS_FEED_CORE_V2_OPERATION_TOKEN_H_
diff --git a/chromium/components/feed/core/v2/operation_token_unittest.cc b/chromium/components/feed/core/v2/operation_token_unittest.cc
new file mode 100644
index 00000000000..90a6c836f4b
--- /dev/null
+++ b/chromium/components/feed/core/v2/operation_token_unittest.cc
@@ -0,0 +1,47 @@
+// Copyright 2022 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.
+
+#include "components/feed/core/v2/operation_token.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace feed {
+
+TEST(OperationToken, IsInitiallyValid) {
+ OperationToken::Operation op;
+ EXPECT_TRUE(op.Token());
+}
+
+TEST(OperationToken, NotValidAfterDestructor) {
+ OperationToken token = OperationToken::MakeInvalid();
+ {
+ OperationToken::Operation op;
+ token = op.Token();
+ EXPECT_TRUE(token);
+ }
+ EXPECT_FALSE(token);
+}
+
+TEST(OperationToken, NotValidAfterReset) {
+ OperationToken::Operation op;
+ OperationToken token = op.Token();
+
+ op.Reset();
+ EXPECT_FALSE(token);
+}
+
+TEST(OperationToken, NewTokensAfterReset) {
+ OperationToken::Operation op;
+ OperationToken token = op.Token();
+ op.Reset();
+ token = op.Token();
+
+ EXPECT_TRUE(token);
+}
+
+TEST(OperationToken, MakeInvalid) {
+ EXPECT_FALSE(OperationToken::MakeInvalid());
+}
+
+} // namespace feed
diff --git a/chromium/components/feed/core/v2/persistent_key_value_store_impl.h b/chromium/components/feed/core/v2/persistent_key_value_store_impl.h
index fa28c4be7c6..f178c027035 100644
--- a/chromium/components/feed/core/v2/persistent_key_value_store_impl.h
+++ b/chromium/components/feed/core/v2/persistent_key_value_store_impl.h
@@ -5,7 +5,6 @@
#ifndef COMPONENTS_FEED_CORE_V2_PERSISTENT_KEY_VALUE_STORE_IMPL_H_
#define COMPONENTS_FEED_CORE_V2_PERSISTENT_KEY_VALUE_STORE_IMPL_H_
-#include <list>
#include <memory>
#include <string>
diff --git a/chromium/components/feed/core/v2/prefs.cc b/chromium/components/feed/core/v2/prefs.cc
index 7d5b485e4bc..27195f95a8d 100644
--- a/chromium/components/feed/core/v2/prefs.cc
+++ b/chromium/components/feed/core/v2/prefs.cc
@@ -31,7 +31,8 @@ const char* RequestSchedulePrefName(RefreshTaskId task_id) {
std::vector<int> GetThrottlerRequestCounts(PrefService& pref_service) {
std::vector<int> result;
const auto& value_list =
- pref_service.GetList(kThrottlerRequestCountListPrefName)->GetList();
+ pref_service.GetList(kThrottlerRequestCountListPrefName)
+ ->GetListDeprecated();
for (const base::Value& value : value_list) {
result.push_back(value.is_int() ? value.GetInt() : 0);
}
diff --git a/chromium/components/feed/core/v2/proto_util.cc b/chromium/components/feed/core/v2/proto_util.cc
index 3cf3d7ea0ed..71b92235cb9 100644
--- a/chromium/components/feed/core/v2/proto_util.cc
+++ b/chromium/components/feed/core/v2/proto_util.cc
@@ -27,7 +27,7 @@
#include "components/feed/feed_feature_list.h"
#include "components/reading_list/features/reading_list_switches.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "base/android/build_info.h"
#endif
@@ -91,7 +91,7 @@ feedwire::Version GetPlatformVersionMessage() {
result.set_major(major);
result.set_minor(minor);
result.set_revision(revision);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
result.set_api_version(base::android::BuildInfo::GetInstance()->sdk_int());
#endif
return result;
@@ -110,7 +110,7 @@ feedwire::Version GetAppVersionMessage(const ChromeInfo& chrome_info) {
result.set_revision(static_cast<int32_t>(numbers[3]));
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
result.set_api_version(base::android::BuildInfo::GetInstance()->sdk_int());
#endif
return result;
@@ -276,9 +276,9 @@ feedwire::ClientInfo CreateClientInfo(const RequestMetadata& request_metadata) {
client_info.set_locale(request_metadata.language_tag);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
client_info.set_platform_type(feedwire::ClientInfo::ANDROID_ID);
-#elif defined(OS_IOS)
+#elif BUILDFLAG(IS_IOS)
client_info.set_platform_type(feedwire::ClientInfo::IOS);
#endif
client_info.set_app_type(feedwire::ClientInfo::CHROME_ANDROID);
diff --git a/chromium/components/feed/core/v2/protocol_translator.cc b/chromium/components/feed/core/v2/protocol_translator.cc
index be0c7409e6f..a795d3c2716 100644
--- a/chromium/components/feed/core/v2/protocol_translator.cc
+++ b/chromium/components/feed/core/v2/protocol_translator.cc
@@ -270,7 +270,7 @@ absl::optional<feedstore::DataOperation> TranslateDataOperation(
RefreshResponseData TranslateWireResponse(
feedwire::Response response,
StreamModelUpdateRequest::Source source,
- bool was_signed_in_request,
+ const AccountInfo& account_info,
base::Time current_time) {
if (response.response_version() != feedwire::Response::FEED_RESPONSE)
return {};
@@ -330,7 +330,9 @@ RefreshResponseData TranslateWireResponse(
result->stream_data.set_root_event_id(
response_metadata.event_id().SerializeAsString());
}
- result->stream_data.set_signed_in(was_signed_in_request);
+ result->stream_data.set_signed_in(!account_info.IsEmpty());
+ result->stream_data.set_gaia(account_info.gaia);
+ result->stream_data.set_email(account_info.email);
result->stream_data.set_logging_enabled(
chrome_response_metadata.logging_enabled());
result->stream_data.set_privacy_notice_fulfilled(
@@ -340,7 +342,7 @@ RefreshResponseData TranslateWireResponse(
}
absl::optional<std::string> session_id = absl::nullopt;
- if (was_signed_in_request) {
+ if (!account_info.IsEmpty()) {
// Signed-in requests don't use session_id tokens; set an empty value to
// ensure that there are no old session_id tokens left hanging around.
session_id = std::string();
@@ -375,6 +377,10 @@ RefreshResponseData TranslateWireResponse(
feed_response->feed_response_metadata().event_id().time_usec() * 1'000;
response_data.server_response_sent_timestamp_ns =
feed_response->feed_response_metadata().response_time_ms() * 1'000'000;
+ response_data.web_and_app_activity_enabled =
+ chrome_response_metadata.web_and_app_activity_enabled();
+ response_data.discover_personalization_enabled =
+ chrome_response_metadata.discover_personalization_enabled();
return response_data;
}
diff --git a/chromium/components/feed/core/v2/protocol_translator.h b/chromium/components/feed/core/v2/protocol_translator.h
index 850f9c1979d..d3d290d0cc2 100644
--- a/chromium/components/feed/core/v2/protocol_translator.h
+++ b/chromium/components/feed/core/v2/protocol_translator.h
@@ -13,6 +13,7 @@
#include "components/feed/core/proto/v2/store.pb.h"
#include "components/feed/core/proto/v2/wire/data_operation.pb.h"
#include "components/feed/core/proto/v2/wire/response.pb.h"
+#include "components/feed/core/v2/public/types.h"
#include "components/feed/core/v2/scheduling.h"
#include "components/feed/core/v2/types.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
@@ -80,6 +81,9 @@ struct RefreshResponseData {
// each other but not to client timestamps.
int64_t server_request_received_timestamp_ns;
int64_t server_response_sent_timestamp_ns;
+
+ bool web_and_app_activity_enabled = false;
+ bool discover_personalization_enabled = false;
};
absl::optional<feedstore::DataOperation> TranslateDataOperation(
@@ -89,7 +93,7 @@ absl::optional<feedstore::DataOperation> TranslateDataOperation(
RefreshResponseData TranslateWireResponse(
feedwire::Response response,
StreamModelUpdateRequest::Source source,
- bool was_signed_in_request,
+ const AccountInfo& account_info,
base::Time current_time);
std::vector<feedstore::DataOperation> TranslateDismissData(
diff --git a/chromium/components/feed/core/v2/protocol_translator_unittest.cc b/chromium/components/feed/core/v2/protocol_translator_unittest.cc
index cbde876d904..8ec372bf2cc 100644
--- a/chromium/components/feed/core/v2/protocol_translator_unittest.cc
+++ b/chromium/components/feed/core/v2/protocol_translator_unittest.cc
@@ -4,6 +4,7 @@
#include "components/feed/core/v2/protocol_translator.h"
+#include <initializer_list>
#include <sstream>
#include <string>
#include <utility>
@@ -26,6 +27,12 @@ namespace {
const char kResponsePbPath[] = "components/test/data/feed/response.binarypb";
const base::Time kCurrentTime = base::Time::UnixEpoch() + base::Days(123);
+AccountInfo TestAccountInfo() {
+ AccountInfo account_info;
+ account_info.gaia = "gaia";
+ account_info.email = "user@foo.com";
+ return account_info;
+}
feedwire::Response TestWireResponse() {
// Read and parse response.binarypb.
@@ -85,14 +92,14 @@ feedwire::DataOperation MakeDataOperationWithRenderData(
// Helpers to add some common params.
RefreshResponseData TranslateWireResponse(feedwire::Response response,
- bool was_signed_in_request) {
+ const AccountInfo& account_info) {
return TranslateWireResponse(response,
StreamModelUpdateRequest::Source::kNetworkUpdate,
- was_signed_in_request, kCurrentTime);
+ account_info, kCurrentTime);
}
RefreshResponseData TranslateWireResponse(feedwire::Response response) {
- return TranslateWireResponse(response, true);
+ return TranslateWireResponse(response, TestAccountInfo());
}
absl::optional<feedstore::DataOperation> TranslateDataOperation(
feedwire::DataOperation operation) {
@@ -146,12 +153,13 @@ TEST(ProtocolTranslatorTest, RootEventIdNotPresent) {
TEST(ProtocolTranslatorTest, WasSignedInRequest) {
feedwire::Response response = EmptyWireResponse();
- for (bool was_signed_in_request_state : {true, false}) {
- RefreshResponseData refresh =
- TranslateWireResponse(response, was_signed_in_request_state);
+
+ for (AccountInfo account_info :
+ std::initializer_list<AccountInfo>{{"gaia", "user@foo.com"}, {}}) {
+ RefreshResponseData refresh = TranslateWireResponse(response, account_info);
ASSERT_TRUE(refresh.model_update_request);
EXPECT_EQ(refresh.model_update_request->stream_data.signed_in(),
- was_signed_in_request_state);
+ !account_info.IsEmpty());
}
}
diff --git a/chromium/components/feed/core/v2/public/common_enums.cc b/chromium/components/feed/core/v2/public/common_enums.cc
index 110e01709e1..3ab3c238c93 100644
--- a/chromium/components/feed/core/v2/public/common_enums.cc
+++ b/chromium/components/feed/core/v2/public/common_enums.cc
@@ -94,6 +94,8 @@ std::ostream& operator<<(std::ostream& out, FeedUserActionType value) {
return out << "kOpenedAutoplaySettings";
case FeedUserActionType::kTappedAddToReadingList:
return out << "kTappedAddToReadingList";
+ case FeedUserActionType::kTappedManage:
+ return out << "kTappedManage";
}
}
diff --git a/chromium/components/feed/core/v2/public/common_enums.h b/chromium/components/feed/core/v2/public/common_enums.h
index 94b7c7b61da..a94cc7b94ad 100644
--- a/chromium/components/feed/core/v2/public/common_enums.h
+++ b/chromium/components/feed/core/v2/public/common_enums.h
@@ -119,8 +119,10 @@ enum class FeedUserActionType {
kOpenedAutoplaySettings = 40,
// User tapped "Add to Reading List" in the context menu.
kTappedAddToReadingList = 41,
+ // User tapped "Manage" icon to open the manage intestitial.
+ kTappedManage = 42,
- kMaxValue = kTappedAddToReadingList,
+ kMaxValue = kTappedManage,
};
// For testing and debugging only.
diff --git a/chromium/components/feed/core/v2/public/feed_api.h b/chromium/components/feed/core/v2/public/feed_api.h
index a334aab4916..0126f1ac767 100644
--- a/chromium/components/feed/core/v2/public/feed_api.h
+++ b/chromium/components/feed/core/v2/public/feed_api.h
@@ -22,7 +22,6 @@
namespace feedui {
class StreamUpdate;
-class LoggingParameters;
} // namespace feedui
namespace feedstore {
class DataOperation;
@@ -32,6 +31,7 @@ namespace feed {
class FeedStreamSurface;
class PersistentKeyValueStore;
class WebFeedSubscriptions;
+struct LoggingParameters;
// This is the public access point for interacting with the Feed contents.
// FeedApi serves multiple streams of data, one for each StreamType.
@@ -58,16 +58,6 @@ class FeedApi {
virtual bool IsArticlesListVisible() = 0;
- // Returns true if activity logging is enabled. The returned value is
- // ephemeral, this should be called for each candidate log, as it can change
- // as the feed is refreshed or the user signs in/out.
- virtual bool IsActivityLoggingEnabled(
- const StreamType& stream_type) const = 0;
-
- // Returns the signed-in client_instance_id. This value is reset whenever the
- // feed stream is cleared (on sign-in, sign-out, and some data clear events).
- virtual std::string GetClientInstanceId() const = 0;
-
// Returns the client's signed-out session id. This value is reset whenever
// the feed stream is cleared (on sign-in, sign-out, and some data clear
// events).
@@ -139,17 +129,15 @@ class FeedApi {
// Sends 'ThereAndBackAgainData' back to the server. |data| is a serialized
// |feedwire::ThereAndBackAgainData| message.
- virtual void ProcessThereAndBackAgain(base::StringPiece data) = 0;
virtual void ProcessThereAndBackAgain(
base::StringPiece data,
- const feedui::LoggingParameters& logging_parameters) = 0;
+ const LoggingParameters& logging_parameters) = 0;
// Saves a view action for eventual upload. |data| is a serialized
//|feedwire::FeedAction| message. `logging_parameters` are the logging
// parameters associated with this item, see `feedui::StreamUpdate`.
- virtual void ProcessViewAction(base::StringPiece data) = 0;
virtual void ProcessViewAction(
base::StringPiece data,
- const feedui::LoggingParameters& logging_parameters) = 0;
+ const LoggingParameters& logging_parameters) = 0;
// Returns whether `url` is a suggested Feed URLs, recently
// navigated to by the user.
diff --git a/chromium/components/feed/core/v2/public/feed_service.cc b/chromium/components/feed/core/v2/public/feed_service.cc
index 2853fbf2b7a..36a89723c72 100644
--- a/chromium/components/feed/core/v2/public/feed_service.cc
+++ b/chromium/components/feed/core/v2/public/feed_service.cc
@@ -105,11 +105,13 @@ class FeedService::NetworkDelegateImpl : public FeedNetworkImpl::Delegate {
return service_delegate_->GetLanguageTag();
}
- std::string GetSyncSignedInGaia() override {
- return identity_manager_->GetPrimaryAccountInfo(signin::ConsentLevel::kSync)
- .gaia;
+ AccountInfo GetAccountInfo() override {
+ return AccountInfo(
+ identity_manager_->GetPrimaryAccountInfo(signin::ConsentLevel::kSync));
}
+ bool IsOffline() override { return net::NetworkChangeNotifier::IsOffline(); }
+
private:
raw_ptr<FeedService::Delegate> service_delegate_;
raw_ptr<signin::IdentityManager> identity_manager_;
@@ -151,13 +153,9 @@ class FeedService::StreamDelegateImpl : public FeedStream::Delegate {
void PrefetchImage(const GURL& url) override {
service_delegate_->PrefetchImage(url);
}
- std::string GetSyncSignedInGaia() override {
- return identity_manager_->GetPrimaryAccountInfo(signin::ConsentLevel::kSync)
- .gaia;
- }
- std::string GetSyncSignedInEmail() override {
- return identity_manager_->GetPrimaryAccountInfo(signin::ConsentLevel::kSync)
- .email;
+ AccountInfo GetAccountInfo() override {
+ return AccountInfo(
+ identity_manager_->GetPrimaryAccountInfo(signin::ConsentLevel::kSync));
}
void RegisterExperiments(const Experiments& experiments) override {
service_delegate_->RegisterExperiments(experiments);
@@ -166,6 +164,9 @@ class FeedService::StreamDelegateImpl : public FeedStream::Delegate {
size_t follow_count) override {
service_delegate_->RegisterFollowingFeedFollowCountFieldTrial(follow_count);
}
+ void RegisterFeedUserSettingsFieldTrial(base::StringPiece group) override {
+ service_delegate_->RegisterFeedUserSettingsFieldTrial(group);
+ }
private:
raw_ptr<FeedService::Delegate> service_delegate_;
@@ -256,7 +257,7 @@ FeedService::FeedService(
delegate_->RegisterExperiments(prefs::GetExperiments(*profile_prefs));
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
application_status_listener_ =
base::android::ApplicationStatusListener::New(base::BindRepeating(
&FeedService::OnApplicationStateChange, base::Unretained(this)));
@@ -305,7 +306,7 @@ uint64_t FeedService::GetReliabilityLoggingId(const std::string& metrics_id,
{metrics_id, std::string(reinterpret_cast<char*>(&salt), sizeof(salt))}));
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
void FeedService::OnApplicationStateChange(
base::android::ApplicationState state) {
if (state == base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES) {
diff --git a/chromium/components/feed/core/v2/public/feed_service.h b/chromium/components/feed/core/v2/public/feed_service.h
index 7b87963fb81..04f6a68fd04 100644
--- a/chromium/components/feed/core/v2/public/feed_service.h
+++ b/chromium/components/feed/core/v2/public/feed_service.h
@@ -17,7 +17,7 @@
#include "components/leveldb_proto/public/proto_database.h"
#include "components/web_resource/eula_accepted_notifier.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "base/android/application_status_listener.h"
#endif
@@ -76,6 +76,9 @@ class FeedService : public KeyedService {
// Registers a synthetic field trial "FollowingFeedFollowCount".
virtual void RegisterFollowingFeedFollowCountFieldTrial(
size_t follow_count) = 0;
+ // Registers a synthetic field trial "FeedUserSettings".
+ virtual void RegisterFeedUserSettingsFieldTrial(
+ base::StringPiece group) = 0;
};
// Construct a FeedService given an already constructed FeedStream.
@@ -127,7 +130,7 @@ class FeedService : public KeyedService {
class IdentityManagerObserverImpl;
FeedService();
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
void OnApplicationStateChange(base::android::ApplicationState state);
#endif
@@ -144,7 +147,7 @@ class FeedService : public KeyedService {
std::unique_ptr<RefreshTaskScheduler> refresh_task_scheduler_;
std::unique_ptr<HistoryObserverImpl> history_observer_;
std::unique_ptr<IdentityManagerObserverImpl> identity_manager_observer_;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
bool foregrounded_ = true;
std::unique_ptr<base::android::ApplicationStatusListener>
application_status_listener_;
diff --git a/chromium/components/feed/core/v2/public/ios/notice_card_tracker_unittest.cc b/chromium/components/feed/core/v2/public/ios/notice_card_tracker_unittest.cc
index 758289be5e6..dd206b68478 100644
--- a/chromium/components/feed/core/v2/public/ios/notice_card_tracker_unittest.cc
+++ b/chromium/components/feed/core/v2/public/ios/notice_card_tracker_unittest.cc
@@ -111,6 +111,10 @@ TEST_F(IOSNoticeCardTrackerTest,
TEST_F(IOSNoticeCardTrackerTest,
DontAcknowledgedNoticeCardWhenFeatureDisabled) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndDisableFeature(
+ feed::kInterestFeedNoticeCardAutoDismiss);
+
// Generate enough views and clicks on the notice card to reach the threshold,
// but the feature is disabled.
feed::prefs::IncrementNoticeCardClicksCount(profile_prefs_);
diff --git a/chromium/components/feed/core/v2/public/logging_parameters.cc b/chromium/components/feed/core/v2/public/logging_parameters.cc
new file mode 100644
index 00000000000..ae64b4c95b0
--- /dev/null
+++ b/chromium/components/feed/core/v2/public/logging_parameters.cc
@@ -0,0 +1,74 @@
+// Copyright 2021 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.
+
+#include "components/feed/core/v2/public/logging_parameters.h"
+
+#include "base/logging.h"
+#include "components/feed/core/proto/v2/store.pb.h"
+#include "components/feed/core/proto/v2/ui.pb.h"
+#include "components/feed/core/v2/config.h"
+#include "components/feed/core/v2/protocol_translator.h"
+
+namespace feed {
+
+LoggingParameters::LoggingParameters() = default;
+LoggingParameters::~LoggingParameters() = default;
+LoggingParameters::LoggingParameters(const LoggingParameters&) = default;
+LoggingParameters::LoggingParameters(LoggingParameters&&) = default;
+LoggingParameters& LoggingParameters::operator=(const LoggingParameters&) =
+ default;
+
+bool LoggingParameters::operator==(const LoggingParameters& rhs) const {
+ return std::tie(email, client_instance_id, logging_enabled,
+ view_actions_enabled, root_event_id) ==
+ std::tie(rhs.email, rhs.client_instance_id, logging_enabled,
+ view_actions_enabled, root_event_id);
+}
+
+LoggingParameters MakeLoggingParameters(
+ const std::string client_instance_id,
+ const StreamModelUpdateRequest& update_request) {
+ const feedstore::StreamData& stream_data = update_request.stream_data;
+ bool signed_in = stream_data.signed_in() && !stream_data.email().empty() &&
+ !stream_data.gaia().empty();
+
+ LoggingParameters logging_params;
+ logging_params.client_instance_id = client_instance_id;
+ logging_params.root_event_id = stream_data.root_event_id();
+ logging_params.logging_enabled =
+ ((signed_in && stream_data.logging_enabled()) ||
+ (!signed_in && GetFeedConfig().send_signed_out_session_logs));
+ logging_params.view_actions_enabled = logging_params.logging_enabled;
+
+ if (signed_in) {
+ DCHECK(!stream_data.email().empty());
+ DCHECK(!stream_data.gaia().empty());
+ // We provide account name even if logging is disabled, so that account
+ // name can be verified for action uploads.
+ logging_params.email = stream_data.email();
+ }
+
+ return logging_params;
+}
+
+LoggingParameters FromProto(const feedui::LoggingParameters& proto) {
+ LoggingParameters result;
+ result.email = proto.email();
+ result.client_instance_id = proto.client_instance_id();
+ result.logging_enabled = proto.logging_enabled();
+ result.view_actions_enabled = proto.view_actions_enabled();
+ result.root_event_id = proto.root_event_id();
+ return result;
+}
+
+void ToProto(const LoggingParameters& logging_parameters,
+ feedui::LoggingParameters& proto) {
+ proto.set_email(logging_parameters.email);
+ proto.set_client_instance_id(logging_parameters.client_instance_id);
+ proto.set_logging_enabled(logging_parameters.logging_enabled);
+ proto.set_view_actions_enabled(logging_parameters.view_actions_enabled);
+ proto.set_root_event_id(logging_parameters.root_event_id);
+}
+
+} // namespace feed
diff --git a/chromium/components/feed/core/v2/public/logging_parameters.h b/chromium/components/feed/core/v2/public/logging_parameters.h
new file mode 100644
index 00000000000..b206cf9de56
--- /dev/null
+++ b/chromium/components/feed/core/v2/public/logging_parameters.h
@@ -0,0 +1,48 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_FEED_CORE_V2_PUBLIC_LOGGING_PARAMETERS_H_
+#define COMPONENTS_FEED_CORE_V2_PUBLIC_LOGGING_PARAMETERS_H_
+
+#include <string>
+
+namespace feedui {
+class LoggingParameters;
+}
+
+namespace feed {
+struct StreamModelUpdateRequest;
+
+struct LoggingParameters {
+ LoggingParameters();
+ ~LoggingParameters();
+ LoggingParameters(const LoggingParameters&);
+ LoggingParameters(LoggingParameters&&);
+ LoggingParameters& operator=(const LoggingParameters&);
+
+ // User ID, if the user is signed-in.
+ std::string email;
+ // A unique ID for this client. Used for reliability logging.
+ std::string client_instance_id;
+ // Whether attention / interaction logging is enabled.
+ bool logging_enabled = false;
+ // Whether view actions may be recorded.
+ bool view_actions_enabled = false;
+ // EventID of the first page response.
+ std::string root_event_id;
+
+ bool operator==(const LoggingParameters& rhs) const;
+};
+
+LoggingParameters MakeLoggingParameters(
+ const std::string client_instance_id,
+ const StreamModelUpdateRequest& update_request);
+
+LoggingParameters FromProto(const feedui::LoggingParameters& proto);
+void ToProto(const LoggingParameters& logging_parameters,
+ feedui::LoggingParameters& proto);
+
+} // namespace feed
+
+#endif // COMPONENTS_FEED_CORE_V2_PUBLIC_LOGGING_PARAMETERS_H_
diff --git a/chromium/components/feed/core/v2/public/logging_parameters_unittest.cc b/chromium/components/feed/core/v2/public/logging_parameters_unittest.cc
new file mode 100644
index 00000000000..ab0e1b8a24e
--- /dev/null
+++ b/chromium/components/feed/core/v2/public/logging_parameters_unittest.cc
@@ -0,0 +1,42 @@
+// Copyright 2021 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.
+
+#include "components/feed/core/v2/public/logging_parameters.h"
+
+#include "components/feed/core/proto/v2/ui.pb.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace feed {
+
+TEST(LoggingParameters, ToFromProto_Set) {
+ LoggingParameters params;
+ params.email = "foo@bar.com";
+ params.client_instance_id = "instanceid";
+ params.logging_enabled = true;
+ params.view_actions_enabled = true;
+
+ feedui::LoggingParameters proto;
+ ToProto(params, proto);
+
+ EXPECT_EQ("foo@bar.com", proto.email());
+ EXPECT_EQ("instanceid", proto.client_instance_id());
+ EXPECT_EQ(true, proto.logging_enabled());
+ EXPECT_EQ(true, proto.view_actions_enabled());
+ EXPECT_EQ(params, FromProto(proto));
+}
+
+TEST(LoggingParameters, ToFromProto_Empty) {
+ LoggingParameters params;
+
+ feedui::LoggingParameters proto;
+ ToProto(params, proto);
+
+ EXPECT_EQ("", proto.email());
+ EXPECT_EQ("", proto.client_instance_id());
+ EXPECT_EQ(false, proto.logging_enabled());
+ EXPECT_EQ(false, proto.view_actions_enabled());
+ EXPECT_EQ(params, FromProto(proto));
+}
+
+} // namespace feed
diff --git a/chromium/components/feed/core/v2/public/public_types.cc b/chromium/components/feed/core/v2/public/public_types.cc
index 34224ae0dbb..bbd116f3523 100644
--- a/chromium/components/feed/core/v2/public/public_types.cc
+++ b/chromium/components/feed/core/v2/public/public_types.cc
@@ -5,8 +5,32 @@
#include "components/feed/core/v2/public/types.h"
#include <ostream>
+#include <tuple>
+#include "components/feed/core/proto/v2/ui.pb.h"
namespace feed {
+
+AccountInfo::AccountInfo() = default;
+AccountInfo::AccountInfo(const std::string& gaia, const std::string& email)
+ : gaia(gaia), email(email) {}
+AccountInfo::AccountInfo(CoreAccountInfo account_info)
+ : gaia(std::move(account_info.gaia)),
+ email(std::move(account_info.email)) {}
+bool AccountInfo::IsEmpty() const {
+ DCHECK_EQ(gaia.empty(), email.empty());
+ return gaia.empty();
+}
+bool AccountInfo::operator==(const AccountInfo& rhs) const {
+ return tie(gaia, email) == tie(rhs.gaia, rhs.email);
+}
+
+std::ostream& operator<<(std::ostream& os, const AccountInfo& o) {
+ if (o.IsEmpty()) {
+ return os << "signed-out";
+ }
+ return os << o.gaia << ":" << o.email;
+}
+
WebFeedMetadata::WebFeedMetadata() = default;
WebFeedMetadata::WebFeedMetadata(const WebFeedMetadata&) = default;
WebFeedMetadata::WebFeedMetadata(WebFeedMetadata&&) = default;
@@ -29,7 +53,11 @@ void WebFeedPageInformation::SetUrl(const GURL& url) {
clear_ref.ClearRef();
url_ = url.ReplaceComponents(clear_ref);
}
-
+void WebFeedPageInformation::SetCanonicalUrl(const GURL& url) {
+ url::Replacements<char> clear_ref;
+ clear_ref.ClearRef();
+ canonical_url_ = url.ReplaceComponents(clear_ref);
+}
void WebFeedPageInformation::SetRssUrls(const std::vector<GURL>& rss_urls) {
rss_urls_ = rss_urls;
}
@@ -37,6 +65,9 @@ void WebFeedPageInformation::SetRssUrls(const std::vector<GURL>& rss_urls) {
std::ostream& operator<<(std::ostream& os,
const WebFeedPageInformation& value) {
os << "{ " << value.url() << " ";
+ if (value.canonical_url().is_valid()) {
+ os << "canonical=" << value.canonical_url() << ' ';
+ }
os << "RSS:\n";
for (const GURL& url : value.GetRssUrls()) {
os << url << '\n';
@@ -56,7 +87,7 @@ std::ostream& operator<<(std::ostream& os, const NetworkResponseInfo& o) {
<< " bless_nonce=" << o.bless_nonce
<< " base_request_url=" << o.base_request_url
<< " response_body_bytes=" << o.response_body_bytes
- << " was_signed_in=" << o.was_signed_in << "}";
+ << " account_info=" << o.account_info << "}";
}
std::ostream& operator<<(std::ostream& out, WebFeedSubscriptionStatus value) {
@@ -123,4 +154,16 @@ std::ostream& operator<<(std::ostream& out, const WebFeedMetadata& value) {
return out << " }";
}
+std::ostream& operator<<(std::ostream& out,
+ WebFeedPageInformationRequestReason value) {
+ switch (value) {
+ case WebFeedPageInformationRequestReason::kUserRequestedFollow:
+ return out << "kUserRequestedFollow";
+ case WebFeedPageInformationRequestReason::kFollowRecommendation:
+ return out << "kFollowRecommendation";
+ case WebFeedPageInformationRequestReason::kMenuItemPresentation:
+ return out << "kMenuItemPresentation";
+ }
+}
+
} // namespace feed
diff --git a/chromium/components/feed/core/v2/public/public_types_unittest.cc b/chromium/components/feed/core/v2/public/public_types_unittest.cc
index e02959e435e..7a2421c1f97 100644
--- a/chromium/components/feed/core/v2/public/public_types_unittest.cc
+++ b/chromium/components/feed/core/v2/public/public_types_unittest.cc
@@ -98,4 +98,10 @@ TEST(WebFeedPageInformation, SetUrlStripsFragment) {
EXPECT_EQ(GURL("https://chromium.org"), info.url());
}
+TEST(WebFeedPageInformation, SetCanonicalUrlStripsFragment) {
+ WebFeedPageInformation info;
+ info.SetCanonicalUrl(GURL("https://chromium.org#1"));
+ EXPECT_EQ(GURL("https://chromium.org"), info.canonical_url());
+}
+
} // namespace feed
diff --git a/chromium/components/feed/core/v2/public/stream_type.cc b/chromium/components/feed/core/v2/public/stream_type.cc
index 077d5e7f418..d2096fb5217 100644
--- a/chromium/components/feed/core/v2/public/stream_type.cc
+++ b/chromium/components/feed/core/v2/public/stream_type.cc
@@ -7,12 +7,12 @@
namespace feed {
std::string StreamType::ToString() const {
- switch (type_) {
- case Type::kUnspecified:
- return "Unspecified";
- case Type::kForYou:
+ switch (kind_) {
+ case StreamKind::kUnknown:
+ return "Unknown";
+ case StreamKind::kForYou:
return "ForYou";
- case Type::kWebFeed:
+ case StreamKind::kFollowing:
return "WebFeed";
}
}
@@ -28,13 +28,13 @@ StreamType StreamType::ForTaskId(RefreshTaskId task_id) {
}
bool StreamType::GetRefreshTaskId(RefreshTaskId& out_id) const {
- switch (type_) {
- case Type::kUnspecified:
+ switch (kind_) {
+ case StreamKind::kUnknown:
return false;
- case Type::kForYou:
+ case StreamKind::kForYou:
out_id = RefreshTaskId::kRefreshForYouFeed;
return true;
- case Type::kWebFeed:
+ case StreamKind::kFollowing:
return false;
}
}
diff --git a/chromium/components/feed/core/v2/public/stream_type.h b/chromium/components/feed/core/v2/public/stream_type.h
index c15764ce9f5..df8cde3fb6c 100644
--- a/chromium/components/feed/core/v2/public/stream_type.h
+++ b/chromium/components/feed/core/v2/public/stream_type.h
@@ -16,23 +16,14 @@ namespace feed {
// parameters.
class StreamType {
public:
- enum class Type {
- // An unspecified stream type. Used only to represent an uninitialized
- // stream type value.
- kUnspecified,
- // The For-You feed stream.
- kForYou,
- // The Web Feed stream.
- kWebFeed,
- };
constexpr StreamType() = default;
- constexpr explicit StreamType(Type t) : type_(t) {}
- bool operator<(const StreamType& rhs) const { return type_ < rhs.type_; }
- bool operator==(const StreamType& rhs) const { return type_ == rhs.type_; }
- bool IsForYou() const { return type_ == Type::kForYou; }
- bool IsWebFeed() const { return type_ == Type::kWebFeed; }
- bool IsValid() const { return type_ != Type::kUnspecified; }
- Type GetType() const { return type_; }
+ constexpr explicit StreamType(StreamKind k) : kind_(k) {}
+ bool operator<(const StreamType& rhs) const { return kind_ < rhs.kind_; }
+ bool operator==(const StreamType& rhs) const { return kind_ == rhs.kind_; }
+ bool IsForYou() const { return kind_ == StreamKind::kForYou; }
+ bool IsWebFeed() const { return kind_ == StreamKind::kFollowing; }
+ bool IsValid() const { return kind_ != StreamKind::kUnknown; }
+ StreamKind GetType() const { return kind_; }
// Returns a human-readable value, for debugging/DCHECK prints.
std::string ToString() const;
@@ -44,11 +35,11 @@ class StreamType {
static StreamType ForTaskId(RefreshTaskId task_id);
private:
- Type type_ = Type::kUnspecified;
+ StreamKind kind_ = StreamKind::kUnknown;
};
-constexpr StreamType kForYouStream(StreamType::Type::kForYou);
-constexpr StreamType kWebFeedStream(StreamType::Type::kWebFeed);
+constexpr StreamType kForYouStream(StreamKind::kForYou);
+constexpr StreamType kWebFeedStream(StreamKind::kFollowing);
inline std::ostream& operator<<(std::ostream& os,
const StreamType& stream_type) {
diff --git a/chromium/components/feed/core/v2/public/types.h b/chromium/components/feed/core/v2/public/types.h
index ef1b79144d5..72f6ee1ecda 100644
--- a/chromium/components/feed/core/v2/public/types.h
+++ b/chromium/components/feed/core/v2/public/types.h
@@ -13,19 +13,47 @@
#include "base/time/time.h"
#include "base/types/id_type.h"
#include "base/version.h"
+#include "components/signin/public/identity_manager/account_info.h"
#include "components/version_info/channel.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "url/gurl.h"
namespace feed {
+// Information about the user account. Currently, for Feed purposes, we use
+// account information only when the user is signed-in with Sync enabled. If
+// Sync is disabled, AccountInfo should be empty.
+struct AccountInfo {
+ AccountInfo();
+ AccountInfo(const std::string& gaia, const std::string& email);
+ explicit AccountInfo(CoreAccountInfo account_info);
+ bool operator==(const AccountInfo& rhs) const;
+ bool operator!=(const AccountInfo& rhs) const { return !(*this == rhs); }
+ bool IsEmpty() const;
+
+ std::string gaia;
+ std::string email;
+};
+std::ostream& operator<<(std::ostream& os, const AccountInfo& o);
+
enum class RefreshTaskId {
kRefreshForYouFeed,
- // TODO(1152592): Refresh is not currently used for the Web Feed. Remove this
- // code if we don't need it.
+ // TODO(1152592): Refresh is not currently used for the Web Feed. Remove
+ // this code if we don't need it.
kRefreshWebFeed,
};
+enum class AccountTokenFetchStatus {
+ // Token fetch was not attempted, or status is unknown.
+ kUnspecified = 0,
+ // Successfully fetch the correct token.
+ kSuccess = 1,
+ // The primary account changed before fetching the token completed.
+ kUnexpectedAccount = 2,
+ // Timed out while fetching the token.
+ kTimedOut = 3,
+};
+
// Information about the Chrome build and feature flags.
struct ChromeInfo {
version_info::Channel channel{};
@@ -63,7 +91,10 @@ struct NetworkResponseInfo {
GURL base_request_url;
size_t response_body_bytes = 0;
size_t encoded_size_bytes = 0;
- bool was_signed_in = false;
+ // If it was a signed-in request, this is the associated account info.
+ AccountInfo account_info;
+ AccountTokenFetchStatus account_token_fetch_status =
+ AccountTokenFetchStatus::kUnspecified;
base::TimeTicks fetch_time_ticks;
base::TimeTicks loader_start_time_ticks;
};
@@ -99,8 +130,8 @@ std::string SerializeDebugStreamData(const DebugStreamData& data);
absl::optional<DebugStreamData> DeserializeDebugStreamData(
base::StringPiece base64_encoded);
-// Information about a web page which may be used to determine an associated web
-// feed.
+// Information about a web page which may be used to determine an associated
+// web feed.
class WebFeedPageInformation {
public:
WebFeedPageInformation();
@@ -112,16 +143,23 @@ class WebFeedPageInformation {
// The URL for the page. `url().has_ref()` is always false.
const GURL& url() const { return url_; }
+ // The Canonical URL for the page, if one was found. `url().has_ref()` is
+ // always false
+ const GURL& canonical_url() const { return canonical_url_; }
// The list of RSS urls embedded in the page with the <link> tag.
const std::vector<GURL>& GetRssUrls() const { return rss_urls_; }
// Set the URL for the page. Trims off the URL ref.
void SetUrl(const GURL& url);
+ // Set the canonical URL for the page. Trims off the URL ref.
+ void SetCanonicalUrl(const GURL& url);
+
void SetRssUrls(const std::vector<GURL>& rss_urls);
private:
GURL url_;
+ GURL canonical_url_;
std::vector<GURL> rss_urls_;
};
std::ostream& operator<<(std::ostream& os, const WebFeedPageInformation& value);
@@ -169,9 +207,9 @@ struct WebFeedMetadata {
};
std::ostream& operator<<(std::ostream& out, const WebFeedMetadata& value);
-// This must be kept in sync with WebFeedSubscriptionRequestStatus in enums.xml.
-// These values are persisted to logs. Entries should not be renumbered and
-// numeric values should never be reused.
+// This must be kept in sync with WebFeedSubscriptionRequestStatus in
+// enums.xml. These values are persisted to logs. Entries should not be
+// renumbered and numeric values should never be reused.
// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.feed.webfeed
enum class WebFeedSubscriptionRequestStatus {
kUnknown = 0,
@@ -187,6 +225,40 @@ std::ostream& operator<<(std::ostream& out,
using NetworkRequestId = base::IdTypeU32<class NetworkRequestIdClass>;
+// Values for the UMA
+// ContentSuggestions.Feed.WebFeed.PageInformationRequested histogram.
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused. This must be kept in sync with
+// WebFeedPageInformationRequestReason in enums.xml.
+// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.feed.webfeed
+enum class WebFeedPageInformationRequestReason : int {
+ // The user requested to Follow the current web page.
+ kUserRequestedFollow = 0,
+ // A Follow recommendation is being considered the current web page.
+ kFollowRecommendation = 1,
+ // The Follow menu item state needs to reflect the current web page.
+ kMenuItemPresentation = 2,
+
+ kMaxValue = kMenuItemPresentation,
+};
+
+// Values for feed type
+// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.feed
+enum class StreamKind : int {
+ // Stream type is unknown.
+ kUnknown = 0,
+ // For you stream.
+ kForYou = 1,
+ // Following stream.
+ kFollowing = 2,
+
+ kMaxValue = kFollowing,
+};
+
+// For testing and debugging only.
+std::ostream& operator<<(std::ostream& out,
+ WebFeedPageInformationRequestReason value);
+
} // namespace feed
#endif // COMPONENTS_FEED_CORE_V2_PUBLIC_TYPES_H_
diff --git a/chromium/components/feed/core/v2/public/web_feed_subscriptions.h b/chromium/components/feed/core/v2/public/web_feed_subscriptions.h
index 4e1f7e8b82b..ff31b36754b 100644
--- a/chromium/components/feed/core/v2/public/web_feed_subscriptions.h
+++ b/chromium/components/feed/core/v2/public/web_feed_subscriptions.h
@@ -26,14 +26,18 @@ class WebFeedSubscriptions {
};
// Follow a web feed given information about a web page. Calls `callback` when
// complete. The callback parameter reports whether the url is now considered
- // followed.
+ // followed. This always creates a non-durable request.
virtual void FollowWebFeed(
const WebFeedPageInformation& page_info,
base::OnceCallback<void(FollowWebFeedResult)> callback) = 0;
// Follow a web feed given a web feed ID.
+ // If `is_durable_request` is true, the request to follow will be persisted
+ // and retried later if necessary. `callback` provides the result of the
+ // initial Follow request, but not any later retries.
virtual void FollowWebFeed(
const std::string& web_feed_id,
+ bool is_durable_request,
base::OnceCallback<void(FollowWebFeedResult)> callback) = 0;
struct UnfollowWebFeedResult {
@@ -45,8 +49,12 @@ class WebFeedSubscriptions {
// Follow a web feed given a URL. Calls `callback` when complete. The callback
// parameter reports whether the url is now considered followed.
+ // If `is_durable_request` is true, the request to follow will be persisted
+ // and retried later if necessary. `callback` provides the result of the
+ // initial Follow request, but not any later retries.
virtual void UnfollowWebFeed(
const std::string& web_feed_id,
+ bool is_durable_request,
base::OnceCallback<void(UnfollowWebFeedResult)> callback) = 0;
// Web Feed lookup for pages. These functions fetch `WebFeedMetadata` for any
diff --git a/chromium/components/feed/core/v2/scheduling.cc b/chromium/components/feed/core/v2/scheduling.cc
index 51fa9ed04ac..9122c3c0cae 100644
--- a/chromium/components/feed/core/v2/scheduling.cc
+++ b/chromium/components/feed/core/v2/scheduling.cc
@@ -25,7 +25,7 @@ bool ValueToVector(const base::Value& value,
std::vector<base::TimeDelta>* result) {
if (!value.is_list())
return false;
- for (const base::Value& entry : value.GetList()) {
+ for (const base::Value& entry : value.GetListDeprecated()) {
absl::optional<base::TimeDelta> delta = base::ValueToTimeDelta(entry);
if (!delta)
return false;
diff --git a/chromium/components/feed/core/v2/stream/privacy_notice_card_tracker.cc b/chromium/components/feed/core/v2/stream/privacy_notice_card_tracker.cc
index 3170abc8ba0..8062a7b864d 100644
--- a/chromium/components/feed/core/v2/stream/privacy_notice_card_tracker.cc
+++ b/chromium/components/feed/core/v2/stream/privacy_notice_card_tracker.cc
@@ -43,19 +43,6 @@ void PrivacyNoticeCardTracker::OnCardViewed(
if (!IsPrivacyNoticeCard(content_id))
return;
- // Do two things if the notice card was viewed:
- // * If kInterestFeedV2ClicksAndViewsConditionalUpload is enabled, remember
- // the notice card was viewed.
- // * If the notice card is viewed and auto-dismiss is enabled, increment view
- // count.
-
- if (is_signed_in &&
- base::FeatureList::IsEnabled(
- feed::kInterestFeedV2ClicksAndViewsConditionalUpload)) {
- feed::prefs::SetHasReachedClickAndViewActionsUploadConditions(
- *profile_prefs_, true);
- }
-
auto now = base::TimeTicks::Now();
if (now - last_view_time_ < base::Minutes(5))
return;
diff --git a/chromium/components/feed/core/v2/stream/upload_criteria.cc b/chromium/components/feed/core/v2/stream/upload_criteria.cc
deleted file mode 100644
index 035f2aa268f..00000000000
--- a/chromium/components/feed/core/v2/stream/upload_criteria.cc
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2021 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.
-
-#include "components/feed/core/v2/stream/upload_criteria.h"
-
-#include "base/feature_list.h"
-#include "components/feed/core/v2/ios_shared_prefs.h"
-#include "components/feed/core/v2/prefs.h"
-#include "components/feed/core/v2/stream/notice_card_tracker.h"
-#include "components/feed/feed_feature_list.h"
-#include "components/prefs/pref_service.h"
-
-namespace feed {
-namespace feed_stream {
-
-UploadCriteria::UploadCriteria(PrefService* profile_prefs)
- : profile_prefs_(profile_prefs) {
- UpdateCanUploadActionsWithNoticeCard();
-}
-
-bool UploadCriteria::CanUploadActions() const {
- return can_upload_actions_with_notice_card_ ||
- !feed::prefs::GetLastFetchHadNoticeCard(*profile_prefs_);
-}
-
-void UploadCriteria::SurfaceOpenedOrClosed() {
- UpdateCanUploadActionsWithNoticeCard();
-}
-
-void UploadCriteria::Clear() {
- // Set this to false since we don't know whether there will be a notice card.
- feed::prefs::SetLastFetchHadNoticeCard(*profile_prefs_, true);
- feed::prefs::SetHasReachedClickAndViewActionsUploadConditions(*profile_prefs_,
- false);
- can_upload_actions_with_notice_card_ = false;
-}
-
-bool UploadCriteria::HasReachedConditionsToUploadActionsWithNoticeCard() {
- if (base::FeatureList::IsEnabled(
- feed::kInterestFeedV2ClicksAndViewsConditionalUpload)) {
- return feed::prefs::GetHasReachedClickAndViewActionsUploadConditions(
- *profile_prefs_);
- }
- // Consider the conditions as already reached to enable uploads when the
- // feature is disabled. This will also have the effect of not updating the
- // related pref.
- return true;
-}
-
-void UploadCriteria::UpdateCanUploadActionsWithNoticeCard() {
- can_upload_actions_with_notice_card_ =
- HasReachedConditionsToUploadActionsWithNoticeCard();
-}
-
-} // namespace feed_stream
-} // namespace feed
diff --git a/chromium/components/feed/core/v2/stream/upload_criteria.h b/chromium/components/feed/core/v2/stream/upload_criteria.h
deleted file mode 100644
index a1b1440fa77..00000000000
--- a/chromium/components/feed/core/v2/stream/upload_criteria.h
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2021 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.
-
-#ifndef COMPONENTS_FEED_CORE_V2_STREAM_UPLOAD_CRITERIA_H_
-#define COMPONENTS_FEED_CORE_V2_STREAM_UPLOAD_CRITERIA_H_
-
-#include "base/memory/raw_ptr.h"
-
-class PrefService;
-
-namespace feed {
-namespace feed_stream {
-
-// Determines whether we can upload actions.
-class UploadCriteria {
- public:
- explicit UploadCriteria(PrefService* profile_prefs);
- UploadCriteria(const UploadCriteria&) = delete;
- UploadCriteria& operator=(const UploadCriteria&) = delete;
-
- bool CanUploadActions() const;
-
- // Events to update criteria.
- void SurfaceOpenedOrClosed();
- void Clear();
-
- private:
- bool HasReachedConditionsToUploadActionsWithNoticeCard();
- void UpdateCanUploadActionsWithNoticeCard();
-
- raw_ptr<PrefService> profile_prefs_;
- // Whether the feed stream can upload actions with the notice card in the
- // feed. This is cached so that we enable uploads in the session after the
- // criteria was met.
- bool can_upload_actions_with_notice_card_ = false;
-};
-
-} // namespace feed_stream
-} // namespace feed
-
-#endif // COMPONENTS_FEED_CORE_V2_STREAM_UPLOAD_CRITERIA_H_
diff --git a/chromium/components/feed/core/v2/stream_model.cc b/chromium/components/feed/core/v2/stream_model.cc
index dc0e02457bf..6d3c9db4916 100644
--- a/chromium/components/feed/core/v2/stream_model.cc
+++ b/chromium/components/feed/core/v2/stream_model.cc
@@ -19,6 +19,7 @@
#include "components/feed/core/v2/feedstore_util.h"
#include "components/feed/core/v2/proto_util.h"
#include "components/feed/core/v2/protocol_translator.h"
+#include "components/feed/core/v2/types.h"
namespace feed {
namespace {
@@ -64,8 +65,10 @@ StoreUpdate::~StoreUpdate() = default;
StoreUpdate::StoreUpdate(StoreUpdate&&) = default;
StoreUpdate& StoreUpdate::operator=(StoreUpdate&&) = default;
-StreamModel::StreamModel(Context* context)
- : content_map_(&(context->revision_generator)) {}
+StreamModel::StreamModel(Context* context,
+ const LoggingParameters& logging_parameters)
+ : logging_parameters_(logging_parameters),
+ content_map_(&(context->revision_generator)) {}
StreamModel::~StreamModel() = default;
diff --git a/chromium/components/feed/core/v2/stream_model.h b/chromium/components/feed/core/v2/stream_model.h
index e9394422358..d53af5d4fea 100644
--- a/chromium/components/feed/core/v2/stream_model.h
+++ b/chromium/components/feed/core/v2/stream_model.h
@@ -17,6 +17,7 @@
#include "components/feed/core/proto/v2/store.pb.h"
#include "components/feed/core/proto/v2/wire/content_id.pb.h"
#include "components/feed/core/v2/proto_util.h"
+#include "components/feed/core/v2/public/logging_parameters.h"
#include "components/feed/core/v2/public/stream_type.h"
#include "components/feed/core/v2/stream_model/ephemeral_change.h"
#include "components/feed/core/v2/stream_model/feature_tree.h"
@@ -90,9 +91,7 @@ class StreamModel {
virtual void OnStoreChange(StoreUpdate update) = 0;
};
- // TODO(crbug.com/1268575): Add LoggingParameters here, as they should stay
- // constant over the life of the model.
- explicit StreamModel(Context* context);
+ StreamModel(Context* context, const LoggingParameters& logging_parameters);
~StreamModel();
StreamModel(const StreamModel& src) = delete;
@@ -105,6 +104,10 @@ class StreamModel {
// Data access.
+ const LoggingParameters& GetLoggingParameters() const {
+ return logging_parameters_;
+ }
+
// Was this feed signed in.
bool signed_in() const { return stream_data_.signed_in(); }
@@ -177,6 +180,7 @@ class StreamModel {
void UpdateFlattenedTree();
+ const LoggingParameters logging_parameters_;
// The stream type for which this model is used. Used only for forwarding to
// observers.
StreamType stream_type_;
diff --git a/chromium/components/feed/core/v2/stream_model_unittest.cc b/chromium/components/feed/core/v2/stream_model_unittest.cc
index 6cb94714301..2e562f8ac9a 100644
--- a/chromium/components/feed/core/v2/stream_model_unittest.cc
+++ b/chromium/components/feed/core/v2/stream_model_unittest.cc
@@ -14,6 +14,7 @@
#include "components/feed/core/proto/v2/wire/content_id.pb.h"
#include "components/feed/core/v2/protocol_translator.h"
#include "components/feed/core/v2/test/stream_builder.h"
+#include "components/feed/core/v2/types.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
@@ -73,7 +74,7 @@ class TestStoreObserver : public StreamModel::StoreObserver {
TEST(StreamModelTest, ConstructEmptyModel) {
StreamModel::Context model_context;
- StreamModel model(&model_context);
+ StreamModel model(&model_context, LoggingParameters());
TestObserver observer(&model);
EXPECT_EQ(0UL, model.GetContentList().size());
@@ -81,7 +82,7 @@ TEST(StreamModelTest, ConstructEmptyModel) {
TEST(StreamModelTest, ExecuteOperationsTypicalStream) {
StreamModel::Context model_context;
- StreamModel model(&model_context);
+ StreamModel model(&model_context, LoggingParameters());
TestObserver observer(&model);
TestStoreObserver store_observer(&model);
@@ -95,7 +96,7 @@ TEST(StreamModelTest, ExecuteOperationsTypicalStream) {
TEST(StreamModelTest, AddContentWithoutRoot) {
StreamModel::Context model_context;
- StreamModel model(&model_context);
+ StreamModel model(&model_context, LoggingParameters());
TestObserver observer(&model);
std::vector<feedstore::DataOperation> operations{
@@ -112,7 +113,7 @@ TEST(StreamModelTest, AddContentWithoutRoot) {
// Verify Stream -> Content works.
TEST(StreamModelTest, AddStreamContent) {
StreamModel::Context model_context;
- StreamModel model(&model_context);
+ StreamModel model(&model_context, LoggingParameters());
TestObserver observer(&model);
std::vector<feedstore::DataOperation> operations{
@@ -128,7 +129,7 @@ TEST(StreamModelTest, AddStreamContent) {
TEST(StreamModelTest, AddRootAsChild) {
// When the root is added as a child, it's no longer considered a root.
StreamModel::Context model_context;
- StreamModel model(&model_context);
+ StreamModel model(&model_context, LoggingParameters());
TestObserver observer(&model);
feedstore::StreamStructure stream_with_parent = MakeStream();
*stream_with_parent.mutable_parent_id() = MakeContentContentId(0);
@@ -146,7 +147,7 @@ TEST(StreamModelTest, AddRootAsChild) {
TEST(StreamModelTest, RemoveCluster) {
StreamModel::Context model_context;
- StreamModel model(&model_context);
+ StreamModel model(&model_context, LoggingParameters());
TestObserver observer(&model);
std::vector<feedstore::DataOperation> operations =
@@ -160,7 +161,7 @@ TEST(StreamModelTest, RemoveCluster) {
TEST(StreamModelTest, RemoveContent) {
StreamModel::Context model_context;
- StreamModel model(&model_context);
+ StreamModel model(&model_context, LoggingParameters());
TestObserver observer(&model);
std::vector<feedstore::DataOperation> operations =
@@ -174,7 +175,7 @@ TEST(StreamModelTest, RemoveContent) {
TEST(StreamModelTest, RemoveRoot) {
StreamModel::Context model_context;
- StreamModel model(&model_context);
+ StreamModel model(&model_context, LoggingParameters());
TestObserver observer(&model);
std::vector<feedstore::DataOperation> operations =
@@ -188,7 +189,7 @@ TEST(StreamModelTest, RemoveRoot) {
TEST(StreamModelTest, RemoveAndAddRoot) {
StreamModel::Context model_context;
- StreamModel model(&model_context);
+ StreamModel model(&model_context, LoggingParameters());
TestObserver observer(&model);
std::vector<feedstore::DataOperation> operations =
@@ -203,7 +204,7 @@ TEST(StreamModelTest, RemoveAndAddRoot) {
TEST(StreamModelTest, SecondRootStreamIsIgnored) {
StreamModel::Context model_context;
- StreamModel model(&model_context);
+ StreamModel model(&model_context, LoggingParameters());
TestObserver observer(&model);
// Add a second stream root, but it is ignored.
@@ -226,7 +227,7 @@ TEST(StreamModelTest, SecondRootStreamIsIgnored) {
TEST(StreamModelTest, SecondRootWithIsRootIsSelected) {
StreamModel::Context model_context;
- StreamModel model(&model_context);
+ StreamModel model(&model_context, LoggingParameters());
TestObserver observer(&model);
// Set up operations which add two roots. The second root is chosen because it
@@ -246,7 +247,7 @@ TEST(StreamModelTest, RemoveAndUpdateCluster) {
// Remove a cluster and add it back. Adding it back keeps its original
// placement.
StreamModel::Context model_context;
- StreamModel model(&model_context);
+ StreamModel model(&model_context, LoggingParameters());
TestObserver observer(&model);
std::vector<feedstore::DataOperation> operations =
@@ -262,7 +263,7 @@ TEST(StreamModelTest, RemoveAndUpdateCluster) {
TEST(StreamModelTest, RemoveAndAppendToNewParent) {
// Attempt to re-parent a node. This is not allowed, the old parent remains.
StreamModel::Context model_context;
- StreamModel model(&model_context);
+ StreamModel model(&model_context, LoggingParameters());
TestObserver observer(&model);
std::vector<feedstore::DataOperation> operations =
@@ -277,7 +278,7 @@ TEST(StreamModelTest, RemoveAndAppendToNewParent) {
TEST(StreamModelTest, EphemeralNewCluster) {
StreamModel::Context model_context;
- StreamModel model(&model_context);
+ StreamModel model(&model_context, LoggingParameters());
TestObserver observer(&model);
model.ExecuteOperations(MakeTypicalStreamOperations());
@@ -296,7 +297,7 @@ TEST(StreamModelTest, EphemeralNewCluster) {
TEST(StreamModelTest, CommitEphemeralChange) {
StreamModel::Context model_context;
- StreamModel model(&model_context);
+ StreamModel model(&model_context, LoggingParameters());
TestObserver observer(&model);
model.ExecuteOperations(MakeTypicalStreamOperations());
@@ -329,7 +330,7 @@ TEST(StreamModelTest, CommitEphemeralChange) {
TEST(StreamModelTest, RejectEphemeralChange) {
StreamModel::Context model_context;
- StreamModel model(&model_context);
+ StreamModel model(&model_context, LoggingParameters());
TestObserver observer(&model);
model.ExecuteOperations(MakeTypicalStreamOperations());
@@ -350,7 +351,7 @@ TEST(StreamModelTest, RejectEphemeralChange) {
TEST(StreamModelTest, RejectFirstEphemeralChange) {
StreamModel::Context model_context;
- StreamModel model(&model_context);
+ StreamModel model(&model_context, LoggingParameters());
TestObserver observer(&model);
model.ExecuteOperations(MakeTypicalStreamOperations());
@@ -378,7 +379,7 @@ TEST(StreamModelTest, RejectFirstEphemeralChange) {
TEST(StreamModelTest, InitialLoad) {
StreamModel::Context model_context;
- StreamModel model(&model_context);
+ StreamModel model(&model_context, LoggingParameters());
TestObserver observer(&model);
TestStoreObserver store_observer(&model);
model.Update(MakeTypicalInitialModelState());
@@ -397,7 +398,7 @@ TEST(StreamModelTest, InitialLoad) {
TEST(StreamModelTest, StoreObserverReceivesIncreasingSequenceNumbers) {
StreamModel::Context model_context;
- StreamModel model(&model_context);
+ StreamModel model(&model_context, LoggingParameters());
TestObserver observer(&model);
TestStoreObserver store_observer(&model);
@@ -423,7 +424,7 @@ TEST(StreamModelTest, StoreObserverReceivesIncreasingSequenceNumbers) {
TEST(StreamModelTest, SharedStateCanBeAddedOnlyOnce) {
StreamModel::Context model_context;
- StreamModel model(&model_context);
+ StreamModel model(&model_context, LoggingParameters());
TestObserver observer(&model);
TestStoreObserver store_observer(&model);
@@ -447,7 +448,7 @@ TEST(StreamModelTest, SharedStateCanBeAddedOnlyOnce) {
TEST(StreamModelTest, SharedStateUpdatesKeepOriginal) {
StreamModel::Context model_context;
- StreamModel model(&model_context);
+ StreamModel model(&model_context, LoggingParameters());
TestObserver observer(&model);
TestStoreObserver store_observer(&model);
model.Update(MakeTypicalInitialModelState());
@@ -469,7 +470,7 @@ TEST(StreamModelTest, SharedStateUpdatesKeepOriginal) {
TEST(StreamModelTest, ClearAllErasesSharedStates) {
StreamModel::Context model_context;
- StreamModel model(&model_context);
+ StreamModel model(&model_context, LoggingParameters());
TestObserver observer(&model);
TestStoreObserver store_observer(&model);
// CLEAR_ALL is the first operation in the typical initial model state.
diff --git a/chromium/components/feed/core/v2/surface_updater.cc b/chromium/components/feed/core/v2/surface_updater.cc
index 1a60ffccc40..64fe159ccbf 100644
--- a/chromium/components/feed/core/v2/surface_updater.cc
+++ b/chromium/components/feed/core/v2/surface_updater.cc
@@ -85,7 +85,6 @@ StreamUpdateAndType MakeStreamUpdate(
const std::vector<std::string>& updated_shared_state_ids,
const base::flat_set<ContentRevision>& already_sent_content,
const StreamModel* model,
- const LoggingParameters& logging_parameters,
const DrawState& state) {
DCHECK(!state.loading_initial || !state.loading_more)
<< "logic bug: requested both top and bottom spinners.";
@@ -137,25 +136,24 @@ StreamUpdateAndType MakeStreamUpdate(
if (model) {
update.stream_update.set_fetch_time_ms(
model->GetLastAddedTime().ToDeltaSinceWindowsEpoch().InMilliseconds());
+ ToProto(model->GetLoggingParameters(),
+ *update.stream_update.mutable_logging_parameters());
+ } else {
+ ToProto(LoggingParameters{},
+ *update.stream_update.mutable_logging_parameters());
}
- ToProto(logging_parameters,
- *update.stream_update.mutable_logging_parameters());
-
return update;
}
-StreamUpdateAndType GetUpdateForNewSurface(
- const DrawState& state,
- const StreamModel* model,
- const LoggingParameters& logging_parameters) {
+StreamUpdateAndType GetUpdateForNewSurface(const DrawState& state,
+ const StreamModel* model) {
std::vector<std::string> updated_shared_state_ids;
if (model) {
updated_shared_state_ids = model->GetSharedStateIds();
}
return MakeStreamUpdate(std::move(updated_shared_state_ids),
- /*already_sent_content=*/{}, model,
- logging_parameters, state);
+ /*already_sent_content=*/{}, model, state);
}
base::flat_set<ContentRevision> GetContentSet(const StreamModel* model) {
@@ -173,6 +171,9 @@ feedui::ZeroStateSlice::Type GetZeroStateType(LoadStreamStatus status) {
case LoadStreamStatus::kCannotLoadFromNetworkOffline:
case LoadStreamStatus::kCannotLoadFromNetworkThrottled:
case LoadStreamStatus::kNetworkFetchFailed:
+ case LoadStreamStatus::kAccountTokenFetchFailedWrongAccount:
+ case LoadStreamStatus::kAccountTokenFetchTimedOut:
+ case LoadStreamStatus::kNetworkFetchTimedOut:
return feedui::ZeroStateSlice::CANT_REFRESH;
case LoadStreamStatus::kNotAWebFeedSubscriber:
return feedui::ZeroStateSlice::NO_WEB_FEED_SUBSCRIPTIONS;
@@ -218,14 +219,12 @@ SurfaceUpdater::SurfaceUpdater(MetricsReporter* metrics_reporter,
SurfaceUpdater::~SurfaceUpdater() = default;
-void SurfaceUpdater::SetModel(StreamModel* model,
- const LoggingParameters& logging_parameters) {
+void SurfaceUpdater::SetModel(StreamModel* model) {
if (model_ == model)
return;
if (model_)
model_->RemoveObserver(this);
model_ = model;
- logging_parameters_ = logging_parameters;
sent_content_.clear();
if (model_) {
model_->AddObserver(this);
@@ -264,8 +263,7 @@ void SurfaceUpdater::SurfaceAdded(
logger.LogLaunchFinishedAfterStreamUpdate(loading_not_allowed_reason);
}
- StreamUpdateAndType update =
- GetUpdateForNewSurface(GetState(), model_, logging_parameters_);
+ StreamUpdateAndType update = GetUpdateForNewSurface(GetState(), model_);
launch_reliability_logger_.OnStreamUpdate(update.type, *surface);
SendUpdateToSurface(surface, update.stream_update);
@@ -346,8 +344,7 @@ void SurfaceUpdater::SendStreamUpdate(
const std::vector<std::string>& updated_shared_state_ids) {
DrawState state = GetState();
StreamUpdateAndType update =
- MakeStreamUpdate(updated_shared_state_ids, sent_content_, model_,
- logging_parameters_, state);
+ MakeStreamUpdate(updated_shared_state_ids, sent_content_, model_, state);
if (load_stream_started_ && !loading_more_)
launch_reliability_logger_.OnStreamUpdate(update.type);
diff --git a/chromium/components/feed/core/v2/surface_updater.h b/chromium/components/feed/core/v2/surface_updater.h
index 416f5827ce0..1b330e00519 100644
--- a/chromium/components/feed/core/v2/surface_updater.h
+++ b/chromium/components/feed/core/v2/surface_updater.h
@@ -45,8 +45,7 @@ class SurfaceUpdater : public StreamModel::Observer,
// surfaces, so they will keep any content they may have been displaying
// before. We don't send a zero-state in this case, since we might want to
// immediately trigger a load.
- void SetModel(StreamModel* model,
- const LoggingParameters& logging_parameters);
+ void SetModel(StreamModel* model);
// StreamModel::Observer.
void OnUiUpdate(const StreamModel::UiUpdate& update) override;
@@ -110,7 +109,6 @@ class SurfaceUpdater : public StreamModel::Observer,
bool loading_more_ = false;
bool loading_initial_ = false;
bool load_stream_failed_ = false;
- LoggingParameters logging_parameters_;
LoadStreamStatus load_stream_status_ = LoadStreamStatus::kNoStatus;
// The |DrawState| when the last update was sent to all surfaces.
diff --git a/chromium/components/feed/core/v2/tasks/load_more_task.cc b/chromium/components/feed/core/v2/tasks/load_more_task.cc
index b13b9986606..07f73cbf6e7 100644
--- a/chromium/components/feed/core/v2/tasks/load_more_task.cc
+++ b/chromium/components/feed/core/v2/tasks/load_more_task.cc
@@ -15,12 +15,14 @@
#include "components/feed/core/proto/v2/wire/client_info.pb.h"
#include "components/feed/core/proto/v2/wire/feed_request.pb.h"
#include "components/feed/core/proto/v2/wire/request.pb.h"
+#include "components/feed/core/v2/enums.h"
#include "components/feed/core/v2/feed_network.h"
#include "components/feed/core/v2/feed_stream.h"
#include "components/feed/core/v2/feedstore_util.h"
#include "components/feed/core/v2/proto_util.h"
#include "components/feed/core/v2/protocol_translator.h"
#include "components/feed/core/v2/stream_model.h"
+#include "components/feed/core/v2/tasks/load_stream_task.h"
#include "components/feed/core/v2/tasks/upload_actions_task.h"
#include "components/feed/core/v2/wire_response_translator.h"
#include "components/feed/feed_feature_list.h"
@@ -80,26 +82,27 @@ void LoadMoreTask::UploadActionsComplete(UploadActionsTask::Result result) {
// content determines the sign-in state of the subsequent load more requests.
// This avoids a possible situation where there would be a mix of signed-in
// and signed-out content, which we don't want.
- std::string gaia =
- model->signed_in() ? stream_.GetSyncSignedInGaia() : std::string();
+ AccountInfo account_info =
+ model->signed_in() ? stream_.GetAccountInfo() : AccountInfo{};
// Send network request.
fetch_start_time_ = base::TimeTicks::Now();
- feedwire::Request request = CreateFeedQueryLoadMoreRequest(
+ RequestMetadata request_metadata =
stream_.GetRequestMetadata(stream_type_,
- /*is_for_next_page=*/true),
- stream_.GetMetadata().consistency_token(),
+ /*is_for_next_page=*/true);
+ feedwire::Request request = CreateFeedQueryLoadMoreRequest(
+ request_metadata, stream_.GetMetadata().consistency_token(),
stream_.GetModel(stream_type_)->GetNextPageToken());
// TODO(crbug/1152592): Send a different network request type for
// WebFeeds.
if (base::FeatureList::IsEnabled(kDiscoFeedEndpoint)) {
stream_.GetNetwork().SendApiRequest<QueryNextPageDiscoverApi>(
- request, gaia,
+ request, account_info, std::move(request_metadata),
base::BindOnce(&LoadMoreTask::QueryApiRequestComplete, GetWeakPtr()));
} else {
stream_.GetNetwork().SendQueryRequest(
- NetworkRequestType::kNextPage, request, gaia,
+ NetworkRequestType::kNextPage, request, account_info,
base::BindOnce(&LoadMoreTask::QueryRequestComplete, GetWeakPtr()));
}
}
@@ -122,13 +125,16 @@ void LoadMoreTask::ProcessNetworkResponse(
StreamModel* model = stream_.GetModel(stream_type_);
DCHECK(model) << "Model was unloaded outside of a Task";
- if (!response_body)
- return Done(LoadStreamStatus::kNoResponseBody);
+ LoadStreamStatus network_status = LoadStreamTask::LaunchResultFromNetworkInfo(
+ response_info, response_body != nullptr)
+ .load_stream_status;
+ if (network_status != LoadStreamStatus::kNoStatus)
+ return Done(network_status);
RefreshResponseData translated_response =
stream_.GetWireResponseTranslator().TranslateWireResponse(
*response_body, StreamModelUpdateRequest::Source::kNetworkLoadMore,
- response_info.was_signed_in, base::Time::Now());
+ response_info.account_info, base::Time::Now());
if (!translated_response.model_update_request)
return Done(LoadStreamStatus::kProtoTranslationFailed);
diff --git a/chromium/components/feed/core/v2/tasks/load_stream_from_store_task.cc b/chromium/components/feed/core/v2/tasks/load_stream_from_store_task.cc
index 01a6f464666..bda6f54bf09 100644
--- a/chromium/components/feed/core/v2/tasks/load_stream_from_store_task.cc
+++ b/chromium/components/feed/core/v2/tasks/load_stream_from_store_task.cc
@@ -7,6 +7,7 @@
#include <algorithm>
#include <utility>
+#include "base/check.h"
#include "base/time/time.h"
#include "components/feed/core/proto/v2/store.pb.h"
#include "components/feed/core/proto/v2/wire/reliability_logging_enums.pb.h"
@@ -65,6 +66,26 @@ void LoadStreamFromStoreTask::LoadStreamDone(
feedwire::DiscoverCardReadCacheResult::EMPTY_SESSION);
return;
}
+ if (!ignore_account_) {
+ const AccountInfo& account_info = feed_stream_.GetAccountInfo();
+ if (result.stream_data.signed_in() && result.stream_data.gaia().empty()) {
+ // TODO(crbug.com/1268575): For backward compatibility, set the gaia in
+ // stream_data if it is unset. Remove this code after it's been in at
+ // least one Chrome release.
+ result.stream_data.set_gaia(account_info.gaia);
+ result.stream_data.set_email(account_info.email);
+ }
+
+ if (result.stream_data.signed_in()) {
+ if (result.stream_data.gaia() != account_info.gaia ||
+ result.stream_data.email() != account_info.email) {
+ Complete(LoadStreamStatus::kDataInStoreIsForAnotherUser,
+ feedwire::DiscoverCardReadCacheResult::FAILED);
+ return;
+ }
+ }
+ }
+
content_ids_ = feedstore::GetContentIds(result.stream_data);
if (!ignore_staleness_) {
content_age_ =
diff --git a/chromium/components/feed/core/v2/tasks/load_stream_from_store_task.h b/chromium/components/feed/core/v2/tasks/load_stream_from_store_task.h
index 88bf7e949be..ab5aedbd566 100644
--- a/chromium/components/feed/core/v2/tasks/load_stream_from_store_task.h
+++ b/chromium/components/feed/core/v2/tasks/load_stream_from_store_task.h
@@ -67,6 +67,7 @@ class LoadStreamFromStoreTask : public offline_pages::Task {
LoadStreamFromStoreTask& operator=(const LoadStreamFromStoreTask&) = delete;
void IgnoreStalenessForTesting() { ignore_staleness_ = true; }
+ void IngoreAccountForTesting() { ignore_account_ = true; }
private:
void Run() override;
@@ -88,6 +89,7 @@ class LoadStreamFromStoreTask : public offline_pages::Task {
raw_ptr<FeedStore> store_; // Unowned.
bool ignore_staleness_ = false;
bool missed_last_refresh_ = false;
+ bool ignore_account_ = false;
base::OnceCallback<void(Result)> result_callback_;
// Data to be stuffed into the Result when the task is complete.
diff --git a/chromium/components/feed/core/v2/tasks/load_stream_task.cc b/chromium/components/feed/core/v2/tasks/load_stream_task.cc
index 264e75b8c71..42570910982 100644
--- a/chromium/components/feed/core/v2/tasks/load_stream_task.cc
+++ b/chromium/components/feed/core/v2/tasks/load_stream_task.cc
@@ -22,13 +22,16 @@
#include "components/feed/core/v2/feed_network.h"
#include "components/feed/core/v2/feed_stream.h"
#include "components/feed/core/v2/feedstore_util.h"
+#include "components/feed/core/v2/ios_shared_prefs.h"
#include "components/feed/core/v2/metrics_reporter.h"
#include "components/feed/core/v2/proto_util.h"
#include "components/feed/core/v2/protocol_translator.h"
+#include "components/feed/core/v2/public/types.h"
#include "components/feed/core/v2/stream_model.h"
#include "components/feed/core/v2/tasks/upload_actions_task.h"
#include "components/feed/core/v2/types.h"
#include "components/feed/feed_feature_list.h"
+#include "net/base/net_errors.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
namespace feed {
@@ -64,6 +67,47 @@ Result::~Result() = default;
Result::Result(Result&&) = default;
Result& Result::operator=(Result&&) = default;
+// static
+LaunchResult LoadStreamTask::LaunchResultFromNetworkInfo(
+ const NetworkResponseInfo& response_info,
+ bool has_parsed_body) {
+ if (response_info.status_code == 200) {
+ if (has_parsed_body) {
+ // Success.
+ return {LoadStreamStatus::kNoStatus,
+ feedwire::DiscoverLaunchResult::CARDS_UNSPECIFIED};
+ }
+ if (response_info.response_body_bytes > 0) {
+ return {
+ LoadStreamStatus::kCannotParseNetworkResponseBody,
+ feedwire::DiscoverLaunchResult::NO_CARDS_RESPONSE_ERROR_ZERO_CARDS};
+ }
+ return {LoadStreamStatus::kNoResponseBody,
+ feedwire::DiscoverLaunchResult::NO_CARDS_RESPONSE_ERROR_ZERO_CARDS};
+ }
+
+ switch (response_info.account_token_fetch_status) {
+ case AccountTokenFetchStatus::kUnspecified:
+ if (response_info.status_code == net::ERR_TIMED_OUT) {
+ return {LoadStreamStatus::kNetworkFetchTimedOut,
+ feedwire::DiscoverLaunchResult::NO_CARDS_REQUEST_ERROR_OTHER};
+ }
+ break;
+ case AccountTokenFetchStatus::kSuccess:
+ break;
+ case AccountTokenFetchStatus::kUnexpectedAccount:
+ return {
+ LoadStreamStatus::kAccountTokenFetchFailedWrongAccount,
+ feedwire::DiscoverLaunchResult::NO_CARDS_FAILED_TO_GET_AUTH_TOKEN};
+ case AccountTokenFetchStatus::kTimedOut:
+ return {
+ LoadStreamStatus::kAccountTokenFetchTimedOut,
+ feedwire::DiscoverLaunchResult::NO_CARDS_FAILED_TO_GET_AUTH_TOKEN};
+ }
+ return {LoadStreamStatus::kNetworkFetchFailed,
+ feedwire::DiscoverLaunchResult::NO_CARDS_RESPONSE_ERROR_NON_200};
+}
+
LoadStreamTask::LoadStreamTask(const Options& options,
FeedStream* stream,
base::OnceCallback<void(Result)> done_callback)
@@ -243,7 +287,7 @@ void LoadStreamTask::UploadActionsComplete(UploadActionsTask::Result result) {
else if (options_.stream_type.IsWebFeed())
network_request_id_ = launch_reliability_logger_.LogWebFeedRequestStart();
}
- const feed::RequestMetadata request_metadata =
+ RequestMetadata request_metadata =
stream_.GetRequestMetadata(options_.stream_type,
/*is_for_next_page=*/false);
@@ -252,9 +296,8 @@ void LoadStreamTask::UploadActionsComplete(UploadActionsTask::Result result) {
GetRequestReason(options_.stream_type, options_.load_type),
request_metadata, stream_.GetMetadata().consistency_token());
- const std::string gaia =
- force_signed_out_request ? std::string() : stream_.GetSyncSignedInGaia();
-
+ const AccountInfo account_info =
+ force_signed_out_request ? AccountInfo{} : stream_.GetAccountInfo();
stream_.GetMetricsReporter().NetworkRefreshRequestStarted(
options_.stream_type, request_metadata.content_order);
@@ -265,7 +308,7 @@ void LoadStreamTask::UploadActionsComplete(UploadActionsTask::Result result) {
// Special case: web feed that is not using Feed Query requests go to
// WebFeedListContentsDiscoverApi.
network.SendApiRequest<WebFeedListContentsDiscoverApi>(
- std::move(request), gaia,
+ std::move(request), account_info, std::move(request_metadata),
base::BindOnce(&LoadStreamTask::QueryApiRequestComplete, GetWeakPtr()));
} else if (options_.stream_type.IsForYou() &&
base::FeatureList::IsEnabled(kDiscoFeedEndpoint)) {
@@ -275,13 +318,13 @@ void LoadStreamTask::UploadActionsComplete(UploadActionsTask::Result result) {
case LoadType::kInitialLoad:
case LoadType::kManualRefresh:
network.SendApiRequest<QueryInteractiveFeedDiscoverApi>(
- request, gaia,
+ request, account_info, std::move(request_metadata),
base::BindOnce(&LoadStreamTask::QueryApiRequestComplete,
GetWeakPtr()));
break;
case LoadType::kBackgroundRefresh:
network.SendApiRequest<QueryBackgroundFeedDiscoverApi>(
- request, gaia,
+ request, account_info, std::move(request_metadata),
base::BindOnce(&LoadStreamTask::QueryApiRequestComplete,
GetWeakPtr()));
break;
@@ -292,7 +335,7 @@ void LoadStreamTask::UploadActionsComplete(UploadActionsTask::Result result) {
} else {
// Other requests use GWS.
network.SendQueryRequest(
- NetworkRequestType::kFeedQuery, request, gaia,
+ NetworkRequestType::kFeedQuery, request, account_info,
base::BindOnce(&LoadStreamTask::QueryRequestComplete, GetWeakPtr()));
}
}
@@ -321,28 +364,15 @@ void LoadStreamTask::ProcessNetworkResponse(
network_response_info_ = response_info;
- if (response_info.status_code != 200) {
- return RequestFinished(
- {LoadStreamStatus::kNetworkFetchFailed,
- feedwire::DiscoverLaunchResult::NO_CARDS_RESPONSE_ERROR_NON_200});
- }
-
- if (!response_body) {
- if (response_info.response_body_bytes > 0) {
- return RequestFinished(
- {LoadStreamStatus::kCannotParseNetworkResponseBody,
- feedwire::DiscoverLaunchResult::NO_CARDS_RESPONSE_ERROR_ZERO_CARDS});
- } else {
- return RequestFinished(
- {LoadStreamStatus::kNoResponseBody,
- feedwire::DiscoverLaunchResult::NO_CARDS_RESPONSE_ERROR_ZERO_CARDS});
- }
- }
+ LaunchResult network_status =
+ LaunchResultFromNetworkInfo(response_info, response_body != nullptr);
+ if (network_status.load_stream_status != LoadStreamStatus::kNoStatus)
+ return RequestFinished(network_status);
RefreshResponseData response_data =
stream_.GetWireResponseTranslator().TranslateWireResponse(
*response_body, StreamModelUpdateRequest::Source::kNetworkUpdate,
- response_info.was_signed_in, base::Time::Now());
+ response_info.account_info, base::Time::Now());
server_send_timestamp_ns_ =
response_data.server_request_received_timestamp_ns;
server_receive_timestamp_ns_ =
@@ -363,14 +393,19 @@ void LoadStreamTask::ProcessNetworkResponse(
*response_data.model_update_request),
base::DoNothing());
- fetched_content_has_notice_card_ =
+ const bool fetched_content_has_notice_card =
response_data.model_update_request->stream_data
.privacy_notice_fulfilled();
+ feed::prefs::SetLastFetchHadNoticeCard(*stream_.profile_prefs(),
+ fetched_content_has_notice_card);
+ MetricsReporter::NoticeCardFulfilled(fetched_content_has_notice_card);
- MetricsReporter::NoticeCardFulfilled(*fetched_content_has_notice_card_);
-
- auto updated_metadata = stream_.GetMetadata();
+ feedstore::Metadata updated_metadata = stream_.GetMetadata();
SetLastFetchTime(updated_metadata, options_.stream_type, base::Time::Now());
+ updated_metadata.set_web_and_app_activity_enabled(
+ response_data.web_and_app_activity_enabled);
+ updated_metadata.set_discover_personalization_enabled(
+ response_data.discover_personalization_enabled);
feedstore::MaybeUpdateSessionId(updated_metadata, response_data.session_id);
if (response_data.content_lifetime) {
feedstore::SetContentLifetime(updated_metadata, options_.stream_type,
@@ -424,7 +459,6 @@ void LoadStreamTask::Done(LaunchResult launch_result) {
result.network_response_info = network_response_info_;
result.loaded_new_content_from_network = loaded_new_content_from_network_;
result.latencies = std::move(latencies_);
- result.fetched_content_has_notice_card = fetched_content_has_notice_card_;
result.upload_actions_result = std::move(upload_actions_result_);
result.experiments = experiments_;
result.launch_result = launch_result.launch_result;
diff --git a/chromium/components/feed/core/v2/tasks/load_stream_task.h b/chromium/components/feed/core/v2/tasks/load_stream_task.h
index 162444f283a..6289b810401 100644
--- a/chromium/components/feed/core/v2/tasks/load_stream_task.h
+++ b/chromium/components/feed/core/v2/tasks/load_stream_task.h
@@ -6,6 +6,7 @@
#define COMPONENTS_FEED_CORE_V2_TASKS_LOAD_STREAM_TASK_H_
#include <memory>
+#include <utility>
#include "base/callback.h"
#include "base/memory/weak_ptr.h"
@@ -35,6 +36,14 @@ class FeedStream;
// This task has three modes, see |LoadType| in enums.h.
class LoadStreamTask : public offline_pages::Task {
public:
+ // Returns the `LaunchResult` that contains the terminal failure result if the
+ // parameters do not represent a successful Feed response. Returns a
+ // `load_stream_status` of `LoadStreamStatus::kNoStatus` if there was no
+ // failure.
+ static LaunchResult LaunchResultFromNetworkInfo(
+ const NetworkResponseInfo& network_response_info,
+ bool has_parsed_body);
+
struct Options {
// The stream type to load.
StreamType stream_type;
@@ -68,7 +77,6 @@ class LoadStreamTask : public offline_pages::Task {
absl::optional<NetworkResponseInfo> network_response_info;
bool loaded_new_content_from_network = false;
std::unique_ptr<LoadLatencyTimes> latencies;
- absl::optional<bool> fetched_content_has_notice_card;
// Result of the upload actions task.
std::unique_ptr<UploadActionsTask::Result> upload_actions_result;
@@ -134,7 +142,6 @@ class LoadStreamTask : public offline_pages::Task {
base::OnceCallback<void(Result)> done_callback_;
std::unique_ptr<UploadActionsTask> upload_actions_task_;
std::unique_ptr<UploadActionsTask::Result> upload_actions_result_;
- absl::optional<bool> fetched_content_has_notice_card_;
LaunchReliabilityLogger& launch_reliability_logger_;
int64_t server_receive_timestamp_ns_ = 0l;
int64_t server_send_timestamp_ns_ = 0l;
diff --git a/chromium/components/feed/core/v2/tasks/prefetch_images_task.cc b/chromium/components/feed/core/v2/tasks/prefetch_images_task.cc
index ac6ab91acaa..7ee34ac2cba 100644
--- a/chromium/components/feed/core/v2/tasks/prefetch_images_task.cc
+++ b/chromium/components/feed/core/v2/tasks/prefetch_images_task.cc
@@ -72,7 +72,7 @@ void PrefetchImagesTask::LoadStreamComplete(
// surfaces to update. For this reason, we're not going to retain the loaded
// model for use outside of this task.
StreamModel::Context model_context;
- StreamModel model(&model_context);
+ StreamModel model(&model_context, LoggingParameters{});
model.Update(std::move(result.update_request));
PrefetchImagesFromModel(model);
}
diff --git a/chromium/components/feed/core/v2/tasks/upload_actions_task.cc b/chromium/components/feed/core/v2/tasks/upload_actions_task.cc
index 980073e9b19..b2d1fe1d5d8 100644
--- a/chromium/components/feed/core/v2/tasks/upload_actions_task.cc
+++ b/chromium/components/feed/core/v2/tasks/upload_actions_task.cc
@@ -13,14 +13,17 @@
#include "components/feed/core/proto/v2/wire/upload_actions_request.pb.h"
#include "components/feed/core/proto/v2/wire/upload_actions_response.pb.h"
#include "components/feed/core/v2/config.h"
+#include "components/feed/core/v2/enums.h"
#include "components/feed/core/v2/feed_network.h"
#include "components/feed/core/v2/feed_store.h"
#include "components/feed/core/v2/feed_stream.h"
#include "components/feed/core/v2/feedstore_util.h"
+#include "components/feed/core/v2/ios_shared_prefs.h"
#include "components/feed/core/v2/launch_reliability_logger.h"
#include "components/feed/core/v2/metrics_reporter.h"
#include "components/feed/core/v2/proto_util.h"
#include "components/feed/core/v2/request_throttler.h"
+#include "components/feed/core/v2/types.h"
namespace feed {
using feedstore::StoredAction;
@@ -107,20 +110,28 @@ class UploadActionsTask::Batch {
};
UploadActionsTask::UploadActionsTask(
+ FeedStream* stream,
+ base::OnceCallback<void(UploadActionsTask::Result)> callback)
+ : stream_(*stream), callback_(std::move(callback)) {
+ account_info_ = stream_.GetAccountInfo();
+}
+
+UploadActionsTask::UploadActionsTask(
feedwire::FeedAction action,
bool upload_now,
+ const LoggingParameters& logging_parameters,
FeedStream* stream,
base::OnceCallback<void(UploadActionsTask::Result)> callback)
- : stream_(*stream),
- upload_now_(upload_now),
- wire_action_(std::move(action)),
- callback_(std::move(callback)) {
+ : UploadActionsTask(stream, std::move(callback)) {
+ upload_now_ = upload_now;
+ logging_parameters_ = logging_parameters;
+ wire_action_ = std::move(action);
+
auto* client_data = wire_action_->mutable_client_data();
client_data->set_timestamp_seconds(
(base::Time::Now() - base::Time::UnixEpoch()).InSeconds());
client_data->set_action_surface(
feedwire::ActionSurface::ANDROID_CHROME_NEW_TAB);
- gaia_ = stream_.GetSyncSignedInGaia();
}
UploadActionsTask::UploadActionsTask(
@@ -128,22 +139,18 @@ UploadActionsTask::UploadActionsTask(
FeedStream* stream,
LaunchReliabilityLogger* launch_reliability_logger,
base::OnceCallback<void(UploadActionsTask::Result)> callback)
- : stream_(*stream),
- pending_actions_(std::move(pending_actions)),
- callback_(std::move(callback)),
- launch_reliability_logger_(launch_reliability_logger) {
- gaia_ = stream_.GetSyncSignedInGaia();
+ : UploadActionsTask(stream, std::move(callback)) {
+ pending_actions_ = std::move(pending_actions);
+ launch_reliability_logger_ = launch_reliability_logger;
}
UploadActionsTask::UploadActionsTask(
FeedStream* stream,
LaunchReliabilityLogger* launch_reliability_logger,
base::OnceCallback<void(UploadActionsTask::Result)> callback)
- : stream_(*stream),
- read_pending_actions_(true),
- callback_(std::move(callback)),
- launch_reliability_logger_(launch_reliability_logger) {
- gaia_ = stream_.GetSyncSignedInGaia();
+ : UploadActionsTask(stream, std::move(callback)) {
+ read_pending_actions_ = true;
+ launch_reliability_logger_ = launch_reliability_logger;
}
UploadActionsTask::~UploadActionsTask() = default;
@@ -159,7 +166,21 @@ void UploadActionsTask::Run() {
// From constructor 1: If there is an action to store, store it and maybe try
// to upload all pending actions.
if (wire_action_) {
+ // Abort if we shouldn't be sending or storing this action.
+ if (logging_parameters_.email.empty()) {
+ Done(UploadActionsStatus::kAbortUploadForSignedOutUser);
+ return;
+ }
+ // Are logging parameters associated with a different account?
+ if (logging_parameters_.email != account_info_.email
+ // Is the datastore associated with a different account?
+ || stream_.GetMetadata().gaia() != account_info_.gaia) {
+ Done(UploadActionsStatus::kAbortUploadForWrongUser);
+ return;
+ }
+
StoredAction action;
+
feedstore::Metadata metadata = stream_.GetMetadata();
int32_t action_id = feedstore::GetNextActionId(metadata).GetUnsafeValue();
stream_.SetMetadata(std::move(metadata));
@@ -196,11 +217,6 @@ void UploadActionsTask::OnStorePendingActionFinished(bool write_ok) {
return;
}
- if (!stream_.CanUploadActions()) {
- Done(UploadActionsStatus::kAbortUploadBecauseDisabled);
- return;
- }
-
// If the new action was stored and upload_now was set, load all pending
// actions and try to upload.
ReadActions();
@@ -229,14 +245,12 @@ void UploadActionsTask::UploadPendingActions() {
return;
}
// Can't upload actions for another user, so abort.
- if (stream_.GetSyncSignedInGaia() != gaia_) {
+ if (stream_.GetAccountInfo() != account_info_ ||
+ // Is the datastore associated with a different account?
+ stream_.GetMetadata().gaia() != account_info_.gaia) {
Done(UploadActionsStatus::kAbortUploadForWrongUser);
return;
}
- if (!stream_.CanUploadActions()) {
- Done(UploadActionsStatus::kAbortUploadBecauseDisabled);
- return;
- }
UpdateAndUploadNextBatch();
}
@@ -284,7 +298,7 @@ void UploadActionsTask::OnUpdateActionsFinished(
}
stream_.GetNetwork().SendApiRequest<UploadActionsDiscoverApi>(
- *request, gaia_,
+ *request, account_info_, stream_.GetSignedInRequestMetadata(),
base::BindOnce(&UploadActionsTask::OnUploadFinished,
weak_ptr_factory_.GetWeakPtr(), std::move(batch)));
}
diff --git a/chromium/components/feed/core/v2/tasks/upload_actions_task.h b/chromium/components/feed/core/v2/tasks/upload_actions_task.h
index ca288cdbd7c..0c6ee271d9d 100644
--- a/chromium/components/feed/core/v2/tasks/upload_actions_task.h
+++ b/chromium/components/feed/core/v2/tasks/upload_actions_task.h
@@ -18,6 +18,7 @@
#include "components/feed/core/v2/feed_network.h"
#include "components/feed/core/v2/feed_store.h"
#include "components/feed/core/v2/launch_reliability_logger.h"
+#include "components/feed/core/v2/public/logging_parameters.h"
#include "components/feed/core/v2/types.h"
#include "components/offline_pages/task/task.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
@@ -61,6 +62,7 @@ class UploadActionsTask : public offline_pages::Task {
// string if no token was received).
UploadActionsTask(feedwire::FeedAction action,
bool upload_now,
+ const LoggingParameters& logging_parameters,
FeedStream* stream,
base::OnceCallback<void(Result)> callback);
// Upload |pending_actions| and update the store. Note: |pending_actions|
@@ -80,6 +82,9 @@ class UploadActionsTask : public offline_pages::Task {
UploadActionsTask& operator=(const UploadActionsTask&) = delete;
private:
+ explicit UploadActionsTask(
+ FeedStream* stream,
+ base::OnceCallback<void(UploadActionsTask::Result)> callback);
class Batch;
void Run() override;
@@ -103,6 +108,7 @@ class UploadActionsTask : public offline_pages::Task {
FeedStream& stream_;
bool upload_now_ = false;
bool read_pending_actions_ = false;
+ LoggingParameters logging_parameters_;
// Pending action to be stored.
absl::optional<feedwire::FeedAction> wire_action_;
@@ -120,9 +126,7 @@ class UploadActionsTask : public offline_pages::Task {
// Number of stale actions.
size_t stale_count_ = 0;
absl::optional<NetworkResponseInfo> last_network_response_info_;
-
- std::string gaia_;
-
+ AccountInfo account_info_;
raw_ptr<LaunchReliabilityLogger> launch_reliability_logger_ = nullptr;
NetworkRequestId last_network_request_id_;
diff --git a/chromium/components/feed/core/v2/tasks/wait_for_store_initialize_task.cc b/chromium/components/feed/core/v2/tasks/wait_for_store_initialize_task.cc
index 47b4649bc24..83052447709 100644
--- a/chromium/components/feed/core/v2/tasks/wait_for_store_initialize_task.cc
+++ b/chromium/components/feed/core/v2/tasks/wait_for_store_initialize_task.cc
@@ -34,7 +34,7 @@ void WaitForStoreInitializeTask::OnStoreInitialized() {
void WaitForStoreInitializeTask::ReadStartupDataDone(
FeedStore::StartupData startup_data) {
if (startup_data.metadata &&
- startup_data.metadata->gaia() != stream_.GetSyncSignedInGaia()) {
+ startup_data.metadata->gaia() != stream_.GetAccountInfo().gaia) {
store_.ClearAll(base::BindOnce(&WaitForStoreInitializeTask::ClearAllDone,
base::Unretained(this)));
return;
@@ -57,7 +57,7 @@ void WaitForStoreInitializeTask::MaybeUpgradeStreamSchema() {
if (metadata.stream_schema_version() != 1) {
result_.startup_data.stream_data.clear();
if (metadata.gaia().empty()) {
- metadata.set_gaia(stream_.GetSyncSignedInGaia());
+ metadata.set_gaia(stream_.GetAccountInfo().gaia);
}
store_.UpgradeFromStreamSchemaV0(
std::move(metadata),
diff --git a/chromium/components/feed/core/v2/types.cc b/chromium/components/feed/core/v2/types.cc
index 9194128aebd..2ded74d9208 100644
--- a/chromium/components/feed/core/v2/types.cc
+++ b/chromium/components/feed/core/v2/types.cc
@@ -13,7 +13,7 @@
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
#include "base/values.h"
-#include "components/feed/core/proto/v2/ui.pb.h"
+#include "components/feed/core/v2/proto_util.h"
#include "components/feed/core/v2/public/types.h"
// Note: This file contains implementation for both types.h and public/types.h.
@@ -81,7 +81,6 @@ bool UnpickleOptionalNetworkResponseInfo(
}
void PickleDebugStreamData(const DebugStreamData& value, base::Pickle& pickle) {
- (void)PickleOptionalNetworkResponseInfo;
pickle.WriteInt(DebugStreamData::kVersion);
PickleOptionalNetworkResponseInfo(value.fetch_info, pickle);
PickleOptionalNetworkResponseInfo(value.upload_info, pickle);
@@ -103,6 +102,9 @@ RequestMetadata::RequestMetadata() = default;
RequestMetadata::~RequestMetadata() = default;
RequestMetadata::RequestMetadata(RequestMetadata&&) = default;
RequestMetadata& RequestMetadata::operator=(RequestMetadata&&) = default;
+feedwire::ClientInfo RequestMetadata::ToClientInfo() const {
+ return CreateClientInfo(*this);
+}
NetworkResponseInfo::NetworkResponseInfo() = default;
NetworkResponseInfo::~NetworkResponseInfo() = default;
@@ -224,37 +226,4 @@ LaunchResult::LaunchResult(const LaunchResult& other) = default;
LaunchResult::~LaunchResult() = default;
LaunchResult& LaunchResult::operator=(const LaunchResult& other) = default;
-LoggingParameters::LoggingParameters() = default;
-LoggingParameters::~LoggingParameters() = default;
-LoggingParameters::LoggingParameters(const LoggingParameters&) = default;
-LoggingParameters::LoggingParameters(LoggingParameters&&) = default;
-LoggingParameters& LoggingParameters::operator=(const LoggingParameters&) =
- default;
-
-bool LoggingParameters::operator==(const LoggingParameters& rhs) const {
- return std::tie(email, client_instance_id, logging_enabled,
- view_actions_enabled) ==
- std::tie(rhs.email, rhs.client_instance_id, logging_enabled,
- view_actions_enabled);
-}
-
-LoggingParameters FromProto(const feedui::LoggingParameters& proto) {
- LoggingParameters result;
- result.email = proto.email();
- result.client_instance_id = proto.client_instance_id();
- result.logging_enabled = proto.logging_enabled();
- result.view_actions_enabled = proto.view_actions_enabled();
- result.root_event_id = proto.root_event_id();
- return result;
-}
-
-void ToProto(const LoggingParameters& logging_parameters,
- feedui::LoggingParameters& proto) {
- proto.set_email(logging_parameters.email);
- proto.set_client_instance_id(logging_parameters.client_instance_id);
- proto.set_logging_enabled(logging_parameters.logging_enabled);
- proto.set_view_actions_enabled(logging_parameters.view_actions_enabled);
- proto.set_root_event_id(logging_parameters.root_event_id);
-}
-
} // namespace feed
diff --git a/chromium/components/feed/core/v2/types.h b/chromium/components/feed/core/v2/types.h
index 8aacaf6b9ef..3973ffdca60 100644
--- a/chromium/components/feed/core/v2/types.h
+++ b/chromium/components/feed/core/v2/types.h
@@ -14,14 +14,12 @@
#include "base/time/time.h"
#include "base/types/id_type.h"
#include "base/values.h"
+#include "components/feed/core/proto/v2/wire/client_info.pb.h"
#include "components/feed/core/proto/v2/wire/reliability_logging_enums.pb.h"
#include "components/feed/core/v2/enums.h"
#include "components/feed/core/v2/public/common_enums.h"
#include "components/feed/core/v2/public/types.h"
-namespace feedui {
-class LoggingParameters;
-}
namespace feed {
// Make sure public types are included here too.
@@ -49,6 +47,8 @@ struct RequestMetadata {
RequestMetadata(RequestMetadata&&);
RequestMetadata& operator=(RequestMetadata&&);
+ feedwire::ClientInfo ToClientInfo() const;
+
ChromeInfo chrome_info;
std::string language_tag;
std::string client_instance_id;
@@ -149,31 +149,6 @@ struct LaunchResult {
LaunchResult& operator=(const LaunchResult& other);
};
-struct LoggingParameters {
- LoggingParameters();
- ~LoggingParameters();
- LoggingParameters(const LoggingParameters&);
- LoggingParameters(LoggingParameters&&);
- LoggingParameters& operator=(const LoggingParameters&);
-
- // User ID, if the user is signed-in.
- std::string email;
- // A unique ID for this client. Used for reliability logging.
- std::string client_instance_id;
- // Whether attention / interaction logging is enabled.
- bool logging_enabled = false;
- // Whether view actions may be recorded.
- bool view_actions_enabled = false;
- // EventID of the first page response.
- std::string root_event_id;
-
- bool operator==(const LoggingParameters& rhs) const;
-};
-
-LoggingParameters FromProto(const feedui::LoggingParameters& proto);
-void ToProto(const LoggingParameters& logging_parameters,
- feedui::LoggingParameters& proto);
-
} // namespace feed
#endif // COMPONENTS_FEED_CORE_V2_TYPES_H_
diff --git a/chromium/components/feed/core/v2/types_unittest.cc b/chromium/components/feed/core/v2/types_unittest.cc
index 9c8ef7ef380..08907c265ea 100644
--- a/chromium/components/feed/core/v2/types_unittest.cc
+++ b/chromium/components/feed/core/v2/types_unittest.cc
@@ -5,7 +5,6 @@
#include "components/feed/core/v2/types.h"
#include "base/json/json_writer.h"
#include "base/strings/string_util.h"
-#include "components/feed/core/proto/v2/ui.pb.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace feed {
@@ -62,34 +61,4 @@ TEST(Types, ContentIdSet) {
EXPECT_TRUE(ContentIdSet().IsEmpty());
}
-TEST(Types, LoggingParametersSet_ToFromProto) {
- LoggingParameters params;
- params.email = "foo@bar.com";
- params.client_instance_id = "instanceid";
- params.logging_enabled = true;
- params.view_actions_enabled = true;
-
- feedui::LoggingParameters proto;
- ToProto(params, proto);
-
- EXPECT_EQ("foo@bar.com", proto.email());
- EXPECT_EQ("instanceid", proto.client_instance_id());
- EXPECT_EQ(true, proto.logging_enabled());
- EXPECT_EQ(true, proto.view_actions_enabled());
- EXPECT_EQ(params, FromProto(proto));
-}
-
-TEST(Types, LoggingParametersEmpty_ToFromProto) {
- LoggingParameters params;
-
- feedui::LoggingParameters proto;
- ToProto(params, proto);
-
- EXPECT_EQ("", proto.email());
- EXPECT_EQ("", proto.client_instance_id());
- EXPECT_EQ(false, proto.logging_enabled());
- EXPECT_EQ(false, proto.view_actions_enabled());
- EXPECT_EQ(params, FromProto(proto));
-}
-
} // namespace feed
diff --git a/chromium/components/feed/core/v2/web_feed_subscription_coordinator.cc b/chromium/components/feed/core/v2/web_feed_subscription_coordinator.cc
index 00f8b741acc..0e4e25d7ac5 100644
--- a/chromium/components/feed/core/v2/web_feed_subscription_coordinator.cc
+++ b/chromium/components/feed/core/v2/web_feed_subscription_coordinator.cc
@@ -8,7 +8,9 @@
#include <ostream>
#include "base/callback_helpers.h"
+#include "base/debug/stack_trace.h"
#include "base/feature_list.h"
+#include "base/location.h"
#include "base/memory/raw_ptr.h"
#include "base/task/post_task.h"
#include "base/threading/sequenced_task_runner_handle.h"
@@ -19,9 +21,14 @@
#include "components/feed/core/v2/feed_stream.h"
#include "components/feed/core/v2/feedstore_util.h"
#include "components/feed/core/v2/metrics_reporter.h"
+#include "components/feed/core/v2/operation_token.h"
#include "components/feed/core/v2/public/feed_api.h"
#include "components/feed/core/v2/public/types.h"
+#include "components/feed/core/v2/types.h"
+#include "components/feed/core/v2/web_feed_subscriptions/fetch_subscribed_web_feeds_task.h"
#include "components/feed/core/v2/web_feed_subscriptions/subscribe_to_web_feed_task.h"
+#include "components/feed/core/v2/web_feed_subscriptions/web_feed_metadata_model.h"
+#include "components/feed/core/v2/web_feed_subscriptions/web_feed_subscription_model.h"
#include "components/feed/feed_feature_list.h"
#include "components/offline_pages/task/closure_task.h"
#include "components/prefs/pref_service.h"
@@ -29,9 +36,6 @@
namespace feed {
namespace {
-using InFlightChange = feed::internal::InFlightChange;
-using SubscriptionInfo = WebFeedSubscriptionCoordinator::SubscriptionInfo;
-
WebFeedMetadata MakeWebFeedMetadata(
WebFeedSubscriptionStatus subscribe_status,
const feedstore::WebFeedInfo& web_feed_info) {
@@ -59,148 +63,28 @@ WebFeedMetadata MakeWebFeedMetadata(WebFeedSubscriptionStatus subscribe_status,
return result;
}
-feedstore::WebFeedInfo Remove(
- const std::string& web_feed_id,
- std::vector<feedstore::WebFeedInfo>& feed_info_list) {
- feedstore::WebFeedInfo result;
- for (size_t i = 0; i < feed_info_list.size(); ++i) {
- if (feed_info_list[i].web_feed_id() == web_feed_id) {
- result = std::move(feed_info_list[i]);
- feed_info_list.erase(feed_info_list.begin() + i);
- break;
- }
+bool IsTerminalStatus(WebFeedSubscriptionRequestStatus status) {
+ switch (status) {
+ case WebFeedSubscriptionRequestStatus::kUnknown:
+ return false;
+ case WebFeedSubscriptionRequestStatus::kSuccess:
+ return true;
+ case WebFeedSubscriptionRequestStatus::kFailedOffline:
+ return false;
+ case WebFeedSubscriptionRequestStatus::kFailedTooManySubscriptions:
+ return true;
+ case WebFeedSubscriptionRequestStatus::kFailedUnknownError:
+ return false;
+ case WebFeedSubscriptionRequestStatus::
+ kAbortWebFeedSubscriptionPendingClearAll:
+ return true;
}
- return result;
}
} // namespace
-namespace internal {
-struct InFlightChange {
- // Either subscribing or unsubscribing.
- bool subscribing = false;
- // Set only when subscribing from a web page.
- absl::optional<WebFeedPageInformation> page_information;
- // We may or may not know about this web feed when subscribing; always known
- // when unsubscribing.
- absl::optional<feedstore::WebFeedInfo> web_feed_info;
-};
-
-// An in-memory model of the subscribed web feeds. This should be loaded before
-// making any changes to stored web feeds, so that we rarely need to wait on
-// other tasks to load the subscribed feeds. Additionally, any changes to stored
-// feeds also need to update this in-memory model.
-class WebFeedSubscriptionModel {
- public:
- WebFeedSubscriptionModel(
- FeedStore* store,
- WebFeedIndex* index,
- std::vector<feedstore::WebFeedInfo>* recent_subscriptions,
- const feedstore::SubscribedWebFeeds& feeds)
- : store_(store),
- index_(index),
- recent_unsubscribed_(recent_subscriptions) {
- subscriptions_.assign(feeds.feeds().begin(), feeds.feeds().end());
- update_time_millis_ = feeds.update_time_millis();
- }
-
- SubscriptionInfo GetSubscriptionInfo(const std::string& web_feed_id) {
- SubscriptionInfo result;
- for (const feedstore::WebFeedInfo& info : *recent_unsubscribed_) {
- if (info.web_feed_id() == web_feed_id) {
- result.status = WebFeedSubscriptionStatus::kNotSubscribed;
- result.web_feed_info = info;
- break;
- }
- }
-
- for (const feedstore::WebFeedInfo& info : subscriptions_) {
- if (info.web_feed_id() == web_feed_id) {
- result.status = WebFeedSubscriptionStatus::kSubscribed;
- result.web_feed_info = info;
- break;
- }
- }
-
- return result;
- }
-
- void OnSubscribed(const feedstore::WebFeedInfo& info) {
- Remove(info.web_feed_id(), *recent_unsubscribed_);
- Remove(info.web_feed_id(), subscriptions_);
- subscriptions_.emplace_back(info);
- UpdateIndexAndStore();
- }
-
- void OnUnsubscribed(const std::string& web_feed_id) {
- feedstore::WebFeedInfo info = Remove(web_feed_id, subscriptions_);
- if (!info.web_feed_id().empty()) {
- recent_unsubscribed_->push_back(std::move(info));
- }
- UpdateIndexAndStore();
- }
-
- void UpdateIndexAndStore() {
- feedstore::SubscribedWebFeeds state;
- for (const feedstore::WebFeedInfo& info : subscriptions_) {
- *state.add_feeds() = info;
- }
- state.set_update_time_millis(update_time_millis_);
- index_->Populate(state);
- store_->WriteSubscribedFeeds(std::move(state), base::DoNothing());
- }
-
- // Updates recommended web feeds in both index and store.
- void UpdateRecommendedFeeds(
- std::vector<feedstore::WebFeedInfo> recommended_web_feeds) {
- feedstore::RecommendedWebFeedIndex store_index;
- store_index.set_update_time_millis(
- feedstore::ToTimestampMillis(base::Time::Now()));
- for (const feedstore::WebFeedInfo& info : recommended_web_feeds) {
- feedstore::RecommendedWebFeedIndex::Entry& entry =
- *store_index.add_entries();
- entry.set_web_feed_id(info.web_feed_id());
- *entry.mutable_matchers() = info.matchers();
- }
- index_->Populate(store_index);
- store_->WriteRecommendedFeeds(std::move(store_index),
- std::move(recommended_web_feeds),
- base::DoNothing());
- }
-
- // Updates subscribed web feeds in both index and store.
- void UpdateSubscribedFeeds(
- std::vector<feedstore::WebFeedInfo> subscribed_web_feeds) {
- feedstore::SubscribedWebFeeds store_index;
- update_time_millis_ = feedstore::ToTimestampMillis(base::Time::Now());
- store_index.set_update_time_millis(update_time_millis_);
- for (const feedstore::WebFeedInfo& info : subscribed_web_feeds) {
- *store_index.add_feeds() = info;
- }
- index_->Populate(store_index);
- store_->WriteSubscribedFeeds(std::move(store_index), base::DoNothing());
- subscriptions_ = subscribed_web_feeds;
- }
-
- const std::vector<feedstore::WebFeedInfo>& subscriptions() const {
- return subscriptions_;
- }
-
- private:
- // Each of these are non-null and guaranteed to remain valid for the lifetime
- // of WebFeedSubscriptionModel.
- raw_ptr<FeedStore> store_;
- raw_ptr<WebFeedIndex> index_;
- // Owned by WebFeedSubscriptionCoordinator so that memory of recent
- // subscriptions is retained when the model is deleted.
- raw_ptr<std::vector<feedstore::WebFeedInfo>> recent_unsubscribed_;
-
- // The current known state of subscriptions.
- std::vector<feedstore::WebFeedInfo> subscriptions_;
- int64_t update_time_millis_ = 0;
-};
-
-} // namespace internal
+WebFeedSubscriptionCoordinator::HooksForTesting::HooksForTesting() = default;
+WebFeedSubscriptionCoordinator::HooksForTesting::~HooksForTesting() = default;
WebFeedSubscriptionCoordinator::WebFeedSubscriptionCoordinator(
Delegate* delegate,
@@ -221,6 +105,11 @@ WebFeedSubscriptionCoordinator::WebFeedSubscriptionCoordinator(
&WebFeedSubscriptionCoordinator::FetchSubscribedWebFeedsIfStale,
GetWeakPtr(), std::move(do_nothing)),
delay);
+ base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE,
+ base::BindOnce(&WebFeedSubscriptionCoordinator::RetryPendingOperations,
+ GetWeakPtr()),
+ delay);
}
}
@@ -235,6 +124,8 @@ void WebFeedSubscriptionCoordinator::Populate(
const FeedStore::WebFeedStartupData& startup_data) {
index_.Populate(startup_data.recommended_feed_index);
index_.Populate(startup_data.subscribed_web_feeds);
+ metadata_model_ = std::make_unique<WebFeedMetadataModel>(
+ &feed_stream_->GetStore(), std::move(startup_data.pending_operations));
populated_ = true;
if (IsSignedInAndWebFeedsEnabled()) {
@@ -249,16 +140,34 @@ void WebFeedSubscriptionCoordinator::Populate(
}
void WebFeedSubscriptionCoordinator::ClearAllFinished() {
+ if (hooks_for_testing_)
+ hooks_for_testing_->before_clear_all.Run();
+
+ token_generator_.Reset();
index_.Clear();
- model_.reset();
+ if (metadata_model_) {
+ metadata_model_ = std::make_unique<WebFeedMetadataModel>(
+ &feed_stream_->GetStore(),
+ std::vector<feedstore::PendingWebFeedOperation>());
+ }
+ if (model_) {
+ model_ = std::make_unique<WebFeedSubscriptionModel>(
+ &feed_stream_->GetStore(), &index_, &recent_unsubscribed_,
+ feedstore::SubscribedWebFeeds(), metadata_model_.get());
+ }
FetchRecommendedWebFeedsIfStale();
FetchSubscribedWebFeedsIfStale(base::DoNothing());
+
+ if (hooks_for_testing_)
+ hooks_for_testing_->after_clear_all.Run();
}
void WebFeedSubscriptionCoordinator::FollowWebFeed(
const WebFeedPageInformation& page_info,
base::OnceCallback<void(FollowWebFeedResult)> callback) {
- EnqueueInFlightChange(/*subscribing=*/true, page_info,
+ EnqueueInFlightChange(/*subscribing=*/true,
+ WebFeedInFlightChangeStrategy::kNotDurableRequest,
+ page_info,
/*info=*/absl::nullopt);
WithModel(
base::BindOnce(&WebFeedSubscriptionCoordinator::FollowWebFeedFromUrlStart,
@@ -273,38 +182,79 @@ void WebFeedSubscriptionCoordinator::FollowWebFeedFromUrlStart(
SubscribeToWebFeedTask::Request request;
request.page_info = page_info;
- feed_stream_->GetTaskQueue().AddTask(std::make_unique<SubscribeToWebFeedTask>(
- feed_stream_, std::move(request),
- base::BindOnce(&WebFeedSubscriptionCoordinator::FollowWebFeedComplete,
- base::Unretained(this), std::move(callback),
- /*followed_with_id=*/false)));
+ feed_stream_->GetTaskQueue().AddTask(
+ FROM_HERE,
+ std::make_unique<SubscribeToWebFeedTask>(
+ feed_stream_, token_generator_.Token(), std::move(request),
+ base::BindOnce(&WebFeedSubscriptionCoordinator::FollowWebFeedComplete,
+ base::Unretained(this), std::move(callback),
+ /*followed_with_id=*/false)));
}
void WebFeedSubscriptionCoordinator::FollowWebFeed(
const std::string& web_feed_id,
+ bool is_durable_request,
+ base::OnceCallback<void(FollowWebFeedResult)> callback) {
+ FollowWebFeedInternal(web_feed_id,
+ is_durable_request
+ ? WebFeedInFlightChangeStrategy::kNewDurableRequest
+ : WebFeedInFlightChangeStrategy::kNotDurableRequest,
+ std::move(callback));
+}
+
+void WebFeedSubscriptionCoordinator::FollowWebFeedInternal(
+ const std::string& web_feed_id,
+ WebFeedInFlightChangeStrategy strategy,
base::OnceCallback<void(FollowWebFeedResult)> callback) {
feedstore::WebFeedInfo info;
info.set_web_feed_id(web_feed_id);
- EnqueueInFlightChange(/*subscribing=*/true,
+ EnqueueInFlightChange(/*subscribing=*/true, strategy,
/*page_information=*/absl::nullopt, info);
- WithModel(
- base::BindOnce(&WebFeedSubscriptionCoordinator::FollowWebFeedFromIdStart,
- base::Unretained(this), web_feed_id, std::move(callback)));
+ WithModel(base::BindOnce(
+ &WebFeedSubscriptionCoordinator::FollowWebFeedFromIdStart,
+ base::Unretained(this), web_feed_id, strategy, std::move(callback)));
+}
+
+void WebFeedSubscriptionCoordinator::UpdatePendingOperationBeforeAttempt(
+ const std::string& web_feed_id,
+ WebFeedInFlightChangeStrategy strategy,
+ feedstore::PendingWebFeedOperation::Kind kind) {
+ DCHECK(metadata_model_);
+ switch (strategy) {
+ case WebFeedInFlightChangeStrategy::kNewDurableRequest:
+ metadata_model_->AddPendingOperation(kind, web_feed_id);
+ break;
+ case WebFeedInFlightChangeStrategy::kNotDurableRequest:
+ // Let other user actions override previous requests to follow or
+ // unfollow.
+ metadata_model_->RemovePendingOperationsForWebFeed(web_feed_id);
+ break;
+ case WebFeedInFlightChangeStrategy::kRetry:
+ break;
+ case WebFeedInFlightChangeStrategy::kPending:
+ NOTREACHED();
+ break;
+ }
}
void WebFeedSubscriptionCoordinator::FollowWebFeedFromIdStart(
const std::string& web_feed_id,
+ WebFeedInFlightChangeStrategy strategy,
base::OnceCallback<void(FollowWebFeedResult)> callback) {
DCHECK(model_);
- SubscriptionInfo info = model_->GetSubscriptionInfo(web_feed_id);
+ UpdatePendingOperationBeforeAttempt(
+ web_feed_id, strategy, feedstore::PendingWebFeedOperation::SUBSCRIBE);
+ WebFeedSubscriptionInfo info = model_->GetSubscriptionInfo(web_feed_id);
SubscribeToWebFeedTask::Request request;
request.web_feed_id = web_feed_id;
- feed_stream_->GetTaskQueue().AddTask(std::make_unique<SubscribeToWebFeedTask>(
- feed_stream_, std::move(request),
- base::BindOnce(&WebFeedSubscriptionCoordinator::FollowWebFeedComplete,
- base::Unretained(this), std::move(callback),
- /*followed_with_id=*/true)));
+ feed_stream_->GetTaskQueue().AddTask(
+ FROM_HERE,
+ std::make_unique<SubscribeToWebFeedTask>(
+ feed_stream_, token_generator_.Token(), std::move(request),
+ base::BindOnce(&WebFeedSubscriptionCoordinator::FollowWebFeedComplete,
+ base::Unretained(this), std::move(callback),
+ /*followed_with_id=*/true)));
}
void WebFeedSubscriptionCoordinator::FollowWebFeedComplete(
@@ -312,12 +262,22 @@ void WebFeedSubscriptionCoordinator::FollowWebFeedComplete(
bool followed_with_id,
SubscribeToWebFeedTask::Result result) {
DCHECK(model_);
- DequeueInflightChange();
+ WebFeedInFlightChange change = DequeueInflightChange();
+ if (change.strategy != WebFeedInFlightChangeStrategy::kNotDurableRequest) {
+ if (IsTerminalStatus(result.request_status)) {
+ metadata_model_->RemovePendingOperationsForWebFeed(
+ change.web_feed_info->web_feed_id());
+ } else {
+ metadata_model_->RecordPendingOperationsForWebFeedAttempt(
+ change.web_feed_info->web_feed_id());
+ }
+ }
+
if (result.request_status == WebFeedSubscriptionRequestStatus::kSuccess) {
model_->OnSubscribed(result.web_feed_info);
feed_stream_->SetStreamStale(kWebFeedStream, true);
}
- SubscriptionInfo info =
+ WebFeedSubscriptionInfo info =
model_->GetSubscriptionInfo(result.followed_web_feed_id);
FollowWebFeedResult callback_result;
callback_result.web_feed_metadata =
@@ -333,26 +293,43 @@ void WebFeedSubscriptionCoordinator::FollowWebFeedComplete(
void WebFeedSubscriptionCoordinator::UnfollowWebFeed(
const std::string& web_feed_id,
+ bool is_durable_request,
base::OnceCallback<void(UnfollowWebFeedResult)> callback) {
- WithModel(
- base::BindOnce(&WebFeedSubscriptionCoordinator::UnfollowWebFeedStart,
- base::Unretained(this), web_feed_id, std::move(callback)));
+ UnfollowWebFeedInternal(
+ web_feed_id,
+ is_durable_request ? WebFeedInFlightChangeStrategy::kNewDurableRequest
+ : WebFeedInFlightChangeStrategy::kNotDurableRequest,
+ std::move(callback));
+}
+
+void WebFeedSubscriptionCoordinator::UnfollowWebFeedInternal(
+ const std::string& web_feed_id,
+ WebFeedInFlightChangeStrategy strategy,
+ base::OnceCallback<void(UnfollowWebFeedResult)> callback) {
+ WithModel(base::BindOnce(
+ &WebFeedSubscriptionCoordinator::UnfollowWebFeedStart,
+ base::Unretained(this), web_feed_id, strategy, std::move(callback)));
}
void WebFeedSubscriptionCoordinator::UnfollowWebFeedStart(
const std::string& web_feed_id,
+ WebFeedInFlightChangeStrategy strategy,
base::OnceCallback<void(UnfollowWebFeedResult)> callback) {
- SubscriptionInfo info = model_->GetSubscriptionInfo(web_feed_id);
+ UpdatePendingOperationBeforeAttempt(
+ web_feed_id, strategy, feedstore::PendingWebFeedOperation::UNSUBSCRIBE);
- EnqueueInFlightChange(/*subscribing=*/false,
- /*page_information=*/absl::nullopt,
- info.status != WebFeedSubscriptionStatus::kUnknown
- ? absl::make_optional(info.web_feed_info)
- : absl::nullopt);
+ WebFeedSubscriptionInfo info_lookup =
+ model_->GetSubscriptionInfo(web_feed_id);
+
+ feedstore::WebFeedInfo info = info_lookup.web_feed_info;
+ info.set_web_feed_id(web_feed_id);
+ EnqueueInFlightChange(/*subscribing=*/false, strategy,
+ /*page_information=*/absl::nullopt, info);
feed_stream_->GetTaskQueue().AddTask(
+ FROM_HERE,
std::make_unique<UnsubscribeFromWebFeedTask>(
- feed_stream_, web_feed_id,
+ feed_stream_, token_generator_.Token(), web_feed_id,
base::BindOnce(
&WebFeedSubscriptionCoordinator::UnfollowWebFeedComplete,
base::Unretained(this), std::move(callback))));
@@ -365,7 +342,19 @@ void WebFeedSubscriptionCoordinator::UnfollowWebFeedComplete(
model_->OnUnsubscribed(result.unsubscribed_feed_name);
feed_stream_->SetStreamStale(kWebFeedStream, true);
}
- DequeueInflightChange();
+
+ WebFeedInFlightChange change = DequeueInflightChange();
+
+ if (change.strategy != WebFeedInFlightChangeStrategy::kNotDurableRequest) {
+ if (IsTerminalStatus(result.request_status)) {
+ metadata_model_->RemovePendingOperationsForWebFeed(
+ change.web_feed_info->web_feed_id());
+ } else {
+ metadata_model_->RecordPendingOperationsForWebFeedAttempt(
+ change.web_feed_info->web_feed_id());
+ }
+ }
+
UnfollowWebFeedResult callback_result;
callback_result.request_status = result.request_status;
callback_result.subscription_count = index_.SubscriptionCount();
@@ -432,9 +421,8 @@ void WebFeedSubscriptionCoordinator::LookupWebFeedDataAndRespond(
WebFeedSubscriptionStatus::kUnknown;
// Override status and `web_feed_info` if there's an in-flight operation.
std::string id = web_feed_id;
- const InFlightChange* in_flight_change =
+ const WebFeedInFlightChange* in_flight_change =
FindInflightChange(id, maybe_page_info);
-
const feedstore::WebFeedInfo* web_feed_info = nullptr;
if (in_flight_change) {
@@ -459,7 +447,7 @@ void WebFeedSubscriptionCoordinator::LookupWebFeedDataAndRespond(
}
// Try using `model_` if it's loaded.
- SubscriptionInfo subscription_info;
+ WebFeedSubscriptionInfo subscription_info;
if (!web_feed_info && model_ && !id.empty()) {
subscription_info = model_->GetSubscriptionInfo(id);
if (subscription_info.status != WebFeedSubscriptionStatus::kUnknown &&
@@ -524,28 +512,30 @@ void WebFeedSubscriptionCoordinator::WithModel(base::OnceClosure closure) {
when_model_loads_.push_back(std::move(closure));
if (!loading_model_) {
loading_model_ = true;
- LoadSubscriptionModel();
+ loading_token_ = token_generator_.Token();
+ feed_stream_->GetStore().ReadWebFeedStartupData(
+ base::BindOnce(&WebFeedSubscriptionCoordinator::ModelDataLoaded,
+ base::Unretained(this)));
}
}
}
-void WebFeedSubscriptionCoordinator::LoadSubscriptionModel() {
- DCHECK(!model_);
- feed_stream_->GetStore().ReadWebFeedStartupData(
- base::BindOnce(&WebFeedSubscriptionCoordinator::ModelDataLoaded,
- base::Unretained(this)));
-}
-
void WebFeedSubscriptionCoordinator::ModelDataLoaded(
FeedStore::WebFeedStartupData startup_data) {
DCHECK(loading_model_);
+ DCHECK(metadata_model_);
DCHECK(!model_);
loading_model_ = false;
+ if (!loading_token_) {
+ // ClearAll happened, so ignore any stored data and allow the model to load.
+ startup_data = {};
+ }
+
// TODO(crbug/1152592): Don't need recommended feed data, we could add a new
// function on FeedStore to fetch only subscribed feed data.
model_ = std::make_unique<WebFeedSubscriptionModel>(
&feed_stream_->GetStore(), &index_, &recent_unsubscribed_,
- startup_data.subscribed_web_feeds);
+ std::move(startup_data.subscribed_web_feeds), metadata_model_.get());
for (base::OnceClosure& callback : when_model_loads_) {
std::move(callback).Run();
}
@@ -554,25 +544,39 @@ void WebFeedSubscriptionCoordinator::ModelDataLoaded(
void WebFeedSubscriptionCoordinator::EnqueueInFlightChange(
bool subscribing,
+ WebFeedInFlightChangeStrategy strategy,
absl::optional<WebFeedPageInformation> page_information,
absl::optional<feedstore::WebFeedInfo> info) {
- in_flight_changes_.push_back(
- {subscribing, std::move(page_information), std::move(info)});
+ WebFeedInFlightChange change;
+ change.token = token_generator_.Token();
+ change.subscribing = subscribing;
+ change.strategy = strategy;
+ change.page_information = std::move(page_information);
+ change.web_feed_info = std::move(info);
+ in_flight_changes_.push_back(std::move(change));
}
-void WebFeedSubscriptionCoordinator::DequeueInflightChange() {
+WebFeedInFlightChange WebFeedSubscriptionCoordinator::DequeueInflightChange() {
// O(N), but N is very small.
DCHECK(!in_flight_changes_.empty());
+ auto top = std::move(in_flight_changes_.front());
in_flight_changes_.erase(in_flight_changes_.begin());
+ return top;
}
// Return the last in-flight change which matches either `id` or
-// `maybe_page_info`.
-const InFlightChange* WebFeedSubscriptionCoordinator::FindInflightChange(
+// `maybe_page_info`, ignoring changes before ClearAll.
+const WebFeedInFlightChange* WebFeedSubscriptionCoordinator::FindInflightChange(
const std::string& web_feed_id,
const WebFeedPageInformation* maybe_page_info) {
- const InFlightChange* result = nullptr;
- for (const InFlightChange& change : in_flight_changes_) {
+ const WebFeedInFlightChange* result = nullptr;
+ if (metadata_model_) {
+ result = metadata_model_->FindInFlightChange(web_feed_id);
+ }
+
+ for (const WebFeedInFlightChange& change : in_flight_changes_) {
+ if (!change.token)
+ continue;
if ((maybe_page_info && change.page_information &&
change.page_information->url() == maybe_page_info->url()) ||
(!web_feed_id.empty() && change.web_feed_info &&
@@ -596,7 +600,7 @@ void WebFeedSubscriptionCoordinator::GetAllSubscriptionsStart(
std::vector<WebFeedMetadata> result;
for (const feedstore::WebFeedInfo& info : model_->subscriptions()) {
WebFeedSubscriptionStatus status = WebFeedSubscriptionStatus::kSubscribed;
- const InFlightChange* change =
+ const WebFeedInFlightChange* change =
FindInflightChange(info.web_feed_id(), /*maybe_page_info=*/nullptr);
if (change && !change->subscribing) {
status = WebFeedSubscriptionStatus::kUnsubscribeInProgress;
@@ -608,6 +612,8 @@ void WebFeedSubscriptionCoordinator::GetAllSubscriptionsStart(
void WebFeedSubscriptionCoordinator::RefreshSubscriptions(
base::OnceCallback<void(RefreshResult)> callback) {
+ RetryPendingOperations();
+
on_refresh_subscriptions_.push_back(std::move(callback));
WithModel(base::BindOnce(
@@ -615,12 +621,13 @@ void WebFeedSubscriptionCoordinator::RefreshSubscriptions(
base::Unretained(this)));
}
-SubscriptionInfo WebFeedSubscriptionCoordinator::FindSubscriptionInfo(
+WebFeedSubscriptionInfo WebFeedSubscriptionCoordinator::FindSubscriptionInfo(
const WebFeedPageInformation& page_info) {
DCHECK(model_);
return model_->GetSubscriptionInfo(index_.FindWebFeed(page_info).web_feed_id);
}
-SubscriptionInfo WebFeedSubscriptionCoordinator::FindSubscriptionInfoById(
+WebFeedSubscriptionInfo
+WebFeedSubscriptionCoordinator::FindSubscriptionInfoById(
const std::string& web_feed_id) {
DCHECK(model_);
return model_->GetSubscriptionInfo(web_feed_id);
@@ -652,8 +659,9 @@ void WebFeedSubscriptionCoordinator::FetchRecommendedWebFeedsStart() {
return;
fetching_recommended_web_feeds_ = true;
feed_stream_->GetTaskQueue().AddTask(
+ FROM_HERE,
std::make_unique<FetchRecommendedWebFeedsTask>(
- feed_stream_,
+ feed_stream_, token_generator_.Token(),
base::BindOnce(
&WebFeedSubscriptionCoordinator::FetchRecommendedWebFeedsComplete,
base::Unretained(this))));
@@ -726,8 +734,9 @@ void WebFeedSubscriptionCoordinator::FetchSubscribedWebFeedsStart() {
}
fetching_subscribed_web_feeds_ = true;
feed_stream_->GetTaskQueue().AddTask(
+ FROM_HERE,
std::make_unique<FetchSubscribedWebFeedsTask>(
- feed_stream_,
+ feed_stream_, token_generator_.Token(),
base::BindOnce(
&WebFeedSubscriptionCoordinator::FetchSubscribedWebFeedsComplete,
base::Unretained(this))));
@@ -735,14 +744,18 @@ void WebFeedSubscriptionCoordinator::FetchSubscribedWebFeedsStart() {
void WebFeedSubscriptionCoordinator::FetchSubscribedWebFeedsComplete(
FetchSubscribedWebFeedsTask::Result result) {
- DCHECK(model_);
feed_stream_->GetMetricsReporter().RefreshSubscribedWebFeedsAttempted(
fetching_subscribed_web_feeds_because_stale_, result.status,
result.subscribed_web_feeds.size());
- fetching_subscribed_web_feeds_because_stale_ = false;
- fetching_subscribed_web_feeds_ = false;
- if (result.status == WebFeedRefreshStatus::kSuccess)
- model_->UpdateSubscribedFeeds(std::move(result.subscribed_web_feeds));
+
+ if (result.status !=
+ WebFeedRefreshStatus::kAbortFetchWebFeedPendingClearAll) {
+ DCHECK(model_);
+ fetching_subscribed_web_feeds_because_stale_ = false;
+ fetching_subscribed_web_feeds_ = false;
+ if (result.status == WebFeedRefreshStatus::kSuccess)
+ model_->UpdateSubscribedFeeds(std::move(result.subscribed_web_feeds));
+ }
CallRefreshCompleteCallbacks(
RefreshResult{result.status == WebFeedRefreshStatus::kSuccess});
@@ -792,4 +805,68 @@ void WebFeedSubscriptionCoordinator::SubscribedWebFeedCountDone(
IsSignedInAndWebFeedsEnabled() ? index_.SubscriptionCount() : 0);
}
+void WebFeedSubscriptionCoordinator::RetryPendingOperations() {
+ // Since metadata is loaded directly after startup, this is usually available.
+ // If not, just give up.
+ if (!metadata_model_) {
+ DLOG(WARNING) << "RetryPendingOperations running before loading metadata.";
+ return;
+ }
+
+ // Skip if offline.
+ if (feed_stream_->IsOffline())
+ return;
+
+ for (const WebFeedMetadataModel::Operation& op :
+ metadata_model_->pending_operations()) {
+ switch (op.operation.kind()) {
+ case feedstore::PendingWebFeedOperation::SUBSCRIBE:
+ FollowWebFeedInternal(op.operation.web_feed_id(),
+ WebFeedInFlightChangeStrategy::kRetry,
+ base::DoNothing());
+ break;
+ case feedstore::PendingWebFeedOperation::UNSUBSCRIBE:
+ UnfollowWebFeedInternal(op.operation.web_feed_id(),
+ WebFeedInFlightChangeStrategy::kRetry,
+ base::DoNothing());
+ break;
+ default:
+ NOTREACHED() << "Unsupported operation kind " << op.operation.kind();
+ }
+ }
+}
+
+std::string WebFeedSubscriptionCoordinator::DescribeStateForTesting() const {
+ std::stringstream ss;
+ if (!populated_) {
+ ss << "Not yet populated\n";
+ }
+ if (metadata_model_) {
+ for (const WebFeedMetadataModel::Operation& op :
+ metadata_model_->pending_operations()) {
+ ss << "Pending " << op << '\n';
+ }
+ }
+
+ for (const WebFeedInFlightChange& change : in_flight_changes_) {
+ DCHECK_NE(change.strategy, WebFeedInFlightChangeStrategy::kPending);
+ ss << change << '\n';
+ }
+ for (const WebFeedIndex::Entry& entry :
+ index_.GetSubscribedEntriesForTesting()) {
+ ss << "Subscribed to " << entry.web_feed_id << '\n';
+ }
+ return ss.str();
+}
+
+std::vector<feedstore::PendingWebFeedOperation>
+WebFeedSubscriptionCoordinator::GetPendingOperationStateForTesting() {
+ std::vector<feedstore::PendingWebFeedOperation> result;
+ for (const WebFeedMetadataModel::Operation& op :
+ metadata_model_->pending_operations()) {
+ result.push_back(op.operation);
+ }
+ return result;
+}
+
} // namespace feed
diff --git a/chromium/components/feed/core/v2/web_feed_subscription_coordinator.h b/chromium/components/feed/core/v2/web_feed_subscription_coordinator.h
index 480ef99a879..052ad635f76 100644
--- a/chromium/components/feed/core/v2/web_feed_subscription_coordinator.h
+++ b/chromium/components/feed/core/v2/web_feed_subscription_coordinator.h
@@ -11,20 +11,19 @@
#include "base/callback_forward.h"
#include "base/memory/raw_ptr.h"
#include "components/feed/core/proto/v2/store.pb.h"
+#include "components/feed/core/v2/operation_token.h"
#include "components/feed/core/v2/public/web_feed_subscriptions.h"
#include "components/feed/core/v2/web_feed_subscriptions/fetch_recommended_web_feeds_task.h"
#include "components/feed/core/v2/web_feed_subscriptions/fetch_subscribed_web_feeds_task.h"
#include "components/feed/core/v2/web_feed_subscriptions/subscribe_to_web_feed_task.h"
#include "components/feed/core/v2/web_feed_subscriptions/unsubscribe_from_web_feed_task.h"
#include "components/feed/core/v2/web_feed_subscriptions/web_feed_index.h"
+#include "components/feed/core/v2/web_feed_subscriptions/web_feed_types.h"
namespace feed {
-namespace internal {
-class WebFeedSubscriptionModel;
-struct InFlightChange;
-
-} // namespace internal
class FeedStream;
+class WebFeedSubscriptionModel;
+class WebFeedMetadataModel;
// Coordinates the state of subscription to web feeds.
class WebFeedSubscriptionCoordinator : public WebFeedSubscriptions {
@@ -55,9 +54,11 @@ class WebFeedSubscriptionCoordinator : public WebFeedSubscriptions {
base::OnceCallback<void(FollowWebFeedResult)> callback) override;
void FollowWebFeed(
const std::string& web_feed_id,
+ bool is_durable_request,
base::OnceCallback<void(FollowWebFeedResult)> callback) override;
void UnfollowWebFeed(
const std::string& web_feed_id,
+ bool is_durable_request,
base::OnceCallback<void(UnfollowWebFeedResult)> callback) override;
void FindWebFeedInfoForPage(
const WebFeedPageInformation& page_info,
@@ -77,39 +78,55 @@ class WebFeedSubscriptionCoordinator : public WebFeedSubscriptions {
// Types / functions exposed for task implementations.
- struct SubscriptionInfo {
- WebFeedSubscriptionStatus status = WebFeedSubscriptionStatus::kUnknown;
- feedstore::WebFeedInfo web_feed_info;
- };
-
const feedstore::WebFeedInfo* FindRecentSubscription(
const std::string& subscription_id);
- SubscriptionInfo FindSubscriptionInfo(
+ WebFeedSubscriptionInfo FindSubscriptionInfo(
const WebFeedPageInformation& page_info);
- SubscriptionInfo FindSubscriptionInfoById(const std::string& web_feed_id);
+ WebFeedSubscriptionInfo FindSubscriptionInfoById(
+ const std::string& web_feed_id);
WebFeedIndex& index() { return index_; }
bool is_loading_model_for_testing() const { return loading_model_; }
+ std::string DescribeStateForTesting() const;
+ void RetryPendingOperationsForTesting() { RetryPendingOperations(); }
+ std::vector<feedstore::PendingWebFeedOperation>
+ GetPendingOperationStateForTesting();
+
+ struct HooksForTesting {
+ HooksForTesting();
+ ~HooksForTesting();
+ base::RepeatingClosure before_clear_all;
+ base::RepeatingClosure after_clear_all;
+ };
+ void SetHooksForTesting(HooksForTesting* hooks) {
+ hooks_for_testing_ = hooks;
+ }
private:
- using WebFeedSubscriptionModel = internal::WebFeedSubscriptionModel;
- using InFlightChange = internal::InFlightChange;
base::WeakPtr<WebFeedSubscriptionCoordinator> GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
bool IsSignedInAndWebFeedsEnabled() const;
+ // Queues up tasks to retry any pending subscribe / unsubscribe operations.
+ void RetryPendingOperations();
void FindWebFeedInfoForPageStart(
const WebFeedPageInformation& page_info,
base::OnceCallback<void(WebFeedMetadata)> callback);
+
+ void FollowWebFeedInternal(
+ const std::string& web_feed_id,
+ WebFeedInFlightChangeStrategy strategy,
+ base::OnceCallback<void(FollowWebFeedResult)> callback);
void FollowWebFeedFromUrlStart(
const WebFeedPageInformation& page_info,
base::OnceCallback<void(FollowWebFeedResult)> callback);
void FollowWebFeedFromIdStart(
const std::string& web_feed_id,
+ WebFeedInFlightChangeStrategy strategy,
base::OnceCallback<void(FollowWebFeedResult)> callback);
void LookupWebFeedDataAndRespond(
@@ -130,7 +147,6 @@ class WebFeedSubscriptionCoordinator : public WebFeedSubscriptions {
// Run `closure` after the model is loaded.
void WithModel(base::OnceClosure closure);
- void LoadSubscriptionModel();
void ModelDataLoaded(FeedStore::WebFeedStartupData startup_data);
void FindWebFeedInfoNonRecommended(
const std::string& web_feed_id,
@@ -141,8 +157,13 @@ class WebFeedSubscriptionCoordinator : public WebFeedSubscriptions {
bool followed_with_id,
SubscribeToWebFeedTask::Result result);
+ void UnfollowWebFeedInternal(
+ const std::string& web_feed_id,
+ WebFeedInFlightChangeStrategy strategy,
+ base::OnceCallback<void(UnfollowWebFeedResult)> callback);
void UnfollowWebFeedStart(
const std::string& web_feed_id,
+ WebFeedInFlightChangeStrategy strategy,
base::OnceCallback<void(UnfollowWebFeedResult)> callback);
void UnfollowWebFeedComplete(
base::OnceCallback<void(UnfollowWebFeedResult)> callback,
@@ -150,12 +171,13 @@ class WebFeedSubscriptionCoordinator : public WebFeedSubscriptions {
void EnqueueInFlightChange(
bool subscribing,
+ WebFeedInFlightChangeStrategy strategy,
absl::optional<WebFeedPageInformation> page_information,
absl::optional<feedstore::WebFeedInfo> info);
- const InFlightChange* FindInflightChange(
+ const WebFeedInFlightChange* FindInflightChange(
const std::string& web_feed_id,
const WebFeedPageInformation* maybe_page_info);
- void DequeueInflightChange();
+ WebFeedInFlightChange DequeueInflightChange();
void FetchRecommendedWebFeedsIfStale();
void FetchRecommendedWebFeedsStart();
@@ -171,21 +193,32 @@ class WebFeedSubscriptionCoordinator : public WebFeedSubscriptions {
void IsWebFeedSubscriberDone(base::OnceCallback<void(bool)> callback);
void SubscribedWebFeedCountDone(base::OnceCallback<void(int)> callback);
+ void UpdatePendingOperationBeforeAttempt(
+ const std::string& web_feed_id,
+ WebFeedInFlightChangeStrategy strategy,
+ feedstore::PendingWebFeedOperation::Kind kind);
+
raw_ptr<Delegate> delegate_; // Always non-null.
raw_ptr<FeedStream> feed_stream_; // Always non-null, it owns this.
WebFeedIndex index_;
// Whether `Populate()` has been called.
bool populated_ = false;
std::vector<base::OnceClosure> on_populated_;
-
+ // Non-null after `Populate()`.
+ std::unique_ptr<WebFeedMetadataModel> metadata_model_;
// A model of subscriptions. In memory only while needed.
// TODO(harringtond): Unload the model eventually.
std::unique_ptr<WebFeedSubscriptionModel> model_;
bool loading_model_ = false;
+ OperationToken loading_token_ = OperationToken::MakeInvalid();
+
+ // This operation is destroyed upon a ClearAll event, to cancel all
+ // in flight operations. Note that we don't destroy the whole coordinator
+ // on a ClearAll event to ensure that all callbacks are eventually called.
+ OperationToken::Operation token_generator_;
+
+ std::vector<WebFeedInFlightChange> in_flight_changes_;
- // Queue of in-flight changes. For each of these, there exists a task in the
- // TaskQueue.
- std::vector<InFlightChange> in_flight_changes_;
// Feeds which were subscribed to recently, but are no longer.
// These are not persisted, so we only remember recent subscriptions until the
// Chrome process goes down.
@@ -199,6 +232,8 @@ class WebFeedSubscriptionCoordinator : public WebFeedSubscriptions {
bool fetching_subscribed_web_feeds_ = false;
bool fetching_subscribed_web_feeds_because_stale_ = false;
+ HooksForTesting* hooks_for_testing_ = nullptr;
+
base::WeakPtrFactory<WebFeedSubscriptionCoordinator> weak_ptr_factory_{this};
};
diff --git a/chromium/components/feed/core/v2/web_feed_subscriptions/fetch_recommended_web_feeds_task.cc b/chromium/components/feed/core/v2/web_feed_subscriptions/fetch_recommended_web_feeds_task.cc
index 44c8cf992ff..2d6ab29128e 100644
--- a/chromium/components/feed/core/v2/web_feed_subscriptions/fetch_recommended_web_feeds_task.cc
+++ b/chromium/components/feed/core/v2/web_feed_subscriptions/fetch_recommended_web_feeds_task.cc
@@ -21,12 +21,15 @@ FetchRecommendedWebFeedsTask::Result::operator=(Result&&) = default;
FetchRecommendedWebFeedsTask::FetchRecommendedWebFeedsTask(
FeedStream* stream,
+ const OperationToken& operation_token,
base::OnceCallback<void(Result)> callback)
- : stream_(*stream), callback_(std::move(callback)) {}
+ : stream_(*stream),
+ operation_token_(operation_token),
+ callback_(std::move(callback)) {}
FetchRecommendedWebFeedsTask::~FetchRecommendedWebFeedsTask() = default;
void FetchRecommendedWebFeedsTask::Run() {
- if (stream_.ClearAllInProgress()) {
+ if (!operation_token_) {
Done(WebFeedRefreshStatus::kAbortFetchWebFeedPendingClearAll);
return;
}
@@ -38,7 +41,7 @@ void FetchRecommendedWebFeedsTask::Run() {
feedwire::webfeed::ListRecommendedWebFeedsRequest request;
SetConsistencyToken(request, stream_.GetMetadata().consistency_token());
stream_.GetNetwork().SendApiRequest<ListRecommendedWebFeedDiscoverApi>(
- request, stream_.GetSyncSignedInGaia(),
+ request, stream_.GetAccountInfo(), stream_.GetSignedInRequestMetadata(),
base::BindOnce(&FetchRecommendedWebFeedsTask::RequestComplete,
base::Unretained(this)));
}
@@ -46,6 +49,9 @@ void FetchRecommendedWebFeedsTask::Run() {
void FetchRecommendedWebFeedsTask::RequestComplete(
FeedNetwork::ApiResult<feedwire::webfeed::ListRecommendedWebFeedsResponse>
response) {
+ // This will always be valid, because ClearAllTask cannot have run after this
+ // task starts.
+ DCHECK(operation_token_);
if (!response.response_body) {
Done(WebFeedRefreshStatus::kNetworkFailure);
return;
diff --git a/chromium/components/feed/core/v2/web_feed_subscriptions/fetch_recommended_web_feeds_task.h b/chromium/components/feed/core/v2/web_feed_subscriptions/fetch_recommended_web_feeds_task.h
index 71c9d6a0210..1d62f40b0aa 100644
--- a/chromium/components/feed/core/v2/web_feed_subscriptions/fetch_recommended_web_feeds_task.h
+++ b/chromium/components/feed/core/v2/web_feed_subscriptions/fetch_recommended_web_feeds_task.h
@@ -9,6 +9,7 @@
#include "components/feed/core/proto/v2/wire/web_feeds.pb.h"
#include "components/feed/core/v2/enums.h"
#include "components/feed/core/v2/feed_network.h"
+#include "components/feed/core/v2/operation_token.h"
#include "components/feed/core/v2/public/types.h"
#include "components/offline_pages/task/task.h"
@@ -36,6 +37,7 @@ class FetchRecommendedWebFeedsTask : public offline_pages::Task {
};
FetchRecommendedWebFeedsTask(FeedStream* stream,
+ const OperationToken& operation_token,
base::OnceCallback<void(Result)> callback);
~FetchRecommendedWebFeedsTask() override;
FetchRecommendedWebFeedsTask(const FetchRecommendedWebFeedsTask&) = delete;
@@ -50,6 +52,7 @@ class FetchRecommendedWebFeedsTask : public offline_pages::Task {
void Done(WebFeedRefreshStatus status);
FeedStream& stream_;
+ OperationToken operation_token_;
Result result_;
base::OnceCallback<void(Result)> callback_;
};
diff --git a/chromium/components/feed/core/v2/web_feed_subscriptions/fetch_subscribed_web_feeds_task.cc b/chromium/components/feed/core/v2/web_feed_subscriptions/fetch_subscribed_web_feeds_task.cc
index eac899307ed..3b3066a6a20 100644
--- a/chromium/components/feed/core/v2/web_feed_subscriptions/fetch_subscribed_web_feeds_task.cc
+++ b/chromium/components/feed/core/v2/web_feed_subscriptions/fetch_subscribed_web_feeds_task.cc
@@ -23,12 +23,15 @@ FetchSubscribedWebFeedsTask::Result::operator=(Result&&) = default;
FetchSubscribedWebFeedsTask::FetchSubscribedWebFeedsTask(
FeedStream* stream,
+ const OperationToken& operation_token,
base::OnceCallback<void(Result)> callback)
- : stream_(*stream), callback_(std::move(callback)) {}
+ : stream_(*stream),
+ operation_token_(operation_token),
+ callback_(std::move(callback)) {}
FetchSubscribedWebFeedsTask::~FetchSubscribedWebFeedsTask() = default;
void FetchSubscribedWebFeedsTask::Run() {
- if (stream_.ClearAllInProgress()) {
+ if (!operation_token_) {
Done(WebFeedRefreshStatus::kAbortFetchWebFeedPendingClearAll);
return;
}
@@ -40,13 +43,17 @@ void FetchSubscribedWebFeedsTask::Run() {
feedwire::webfeed::ListWebFeedsRequest request;
SetConsistencyToken(request, stream_.GetMetadata().consistency_token());
stream_.GetNetwork().SendApiRequest<ListWebFeedsDiscoverApi>(
- request, stream_.GetSyncSignedInGaia(),
+ request, stream_.GetAccountInfo(), stream_.GetSignedInRequestMetadata(),
base::BindOnce(&FetchSubscribedWebFeedsTask::RequestComplete,
base::Unretained(this)));
}
void FetchSubscribedWebFeedsTask::RequestComplete(
FeedNetwork::ApiResult<feedwire::webfeed::ListWebFeedsResponse> response) {
+ // This will always be valid, because ClearAllTask cannot have run after this
+ // task starts.
+ DCHECK(operation_token_);
+
if (!response.response_body) {
Done(WebFeedRefreshStatus::kNetworkFailure);
return;
diff --git a/chromium/components/feed/core/v2/web_feed_subscriptions/fetch_subscribed_web_feeds_task.h b/chromium/components/feed/core/v2/web_feed_subscriptions/fetch_subscribed_web_feeds_task.h
index f36f84dd642..280fd9e082e 100644
--- a/chromium/components/feed/core/v2/web_feed_subscriptions/fetch_subscribed_web_feeds_task.h
+++ b/chromium/components/feed/core/v2/web_feed_subscriptions/fetch_subscribed_web_feeds_task.h
@@ -9,6 +9,7 @@
#include "components/feed/core/proto/v2/wire/web_feeds.pb.h"
#include "components/feed/core/v2/enums.h"
#include "components/feed/core/v2/feed_network.h"
+#include "components/feed/core/v2/operation_token.h"
#include "components/feed/core/v2/public/types.h"
#include "components/offline_pages/task/task.h"
@@ -30,6 +31,7 @@ class FetchSubscribedWebFeedsTask : public offline_pages::Task {
};
FetchSubscribedWebFeedsTask(FeedStream* stream,
+ const OperationToken& operation_token,
base::OnceCallback<void(Result)> callback);
~FetchSubscribedWebFeedsTask() override;
FetchSubscribedWebFeedsTask(const FetchSubscribedWebFeedsTask&) = delete;
@@ -43,6 +45,7 @@ class FetchSubscribedWebFeedsTask : public offline_pages::Task {
void Done(WebFeedRefreshStatus status);
FeedStream& stream_;
+ OperationToken operation_token_;
Result result_;
base::OnceCallback<void(Result)> callback_;
};
diff --git a/chromium/components/feed/core/v2/web_feed_subscriptions/subscribe_to_web_feed_task.cc b/chromium/components/feed/core/v2/web_feed_subscriptions/subscribe_to_web_feed_task.cc
index 146aeb9495c..d391330249d 100644
--- a/chromium/components/feed/core/v2/web_feed_subscriptions/subscribe_to_web_feed_task.cc
+++ b/chromium/components/feed/core/v2/web_feed_subscriptions/subscribe_to_web_feed_task.cc
@@ -11,29 +11,32 @@
#include "components/feed/core/v2/feed_stream.h"
#include "components/feed/core/v2/feedstore_util.h"
#include "components/feed/core/v2/web_feed_subscription_coordinator.h"
+#include "components/feed/core/v2/web_feed_subscriptions/web_feed_types.h"
#include "components/feed/core/v2/web_feed_subscriptions/wire_to_store.h"
namespace feed {
SubscribeToWebFeedTask::SubscribeToWebFeedTask(
FeedStream* stream,
+ const OperationToken& operation_token,
Request request,
base::OnceCallback<void(Result)> callback)
: stream_(*stream),
+ operation_token_(operation_token),
request_(std::move(request)),
callback_(std::move(callback)) {}
SubscribeToWebFeedTask::~SubscribeToWebFeedTask() = default;
void SubscribeToWebFeedTask::Run() {
- if (stream_.ClearAllInProgress()) {
+ if (!operation_token_) {
Done(WebFeedSubscriptionRequestStatus::
kAbortWebFeedSubscriptionPendingClearAll);
return;
}
if (!request_.web_feed_id.empty()) {
DCHECK(request_.page_info.url().is_empty());
- WebFeedSubscriptionCoordinator::SubscriptionInfo info =
+ WebFeedSubscriptionInfo info =
stream_.subscriptions().FindSubscriptionInfoById(request_.web_feed_id);
if (info.status == WebFeedSubscriptionStatus::kSubscribed) {
subscribed_web_feed_info_ = info.web_feed_info;
@@ -48,12 +51,12 @@ void SubscribeToWebFeedTask::Run() {
SetConsistencyToken(request, stream_.GetMetadata().consistency_token());
request.set_name(request_.web_feed_id);
stream_.GetNetwork().SendApiRequest<FollowWebFeedDiscoverApi>(
- request, stream_.GetSyncSignedInGaia(),
+ request, stream_.GetAccountInfo(), stream_.GetSignedInRequestMetadata(),
base::BindOnce(&SubscribeToWebFeedTask::RequestComplete,
base::Unretained(this)));
} else {
DCHECK(request_.page_info.url().is_valid());
- WebFeedSubscriptionCoordinator::SubscriptionInfo info =
+ WebFeedSubscriptionInfo info =
stream_.subscriptions().FindSubscriptionInfo(request_.page_info);
if (info.status == WebFeedSubscriptionStatus::kSubscribed) {
subscribed_web_feed_info_ = info.web_feed_info;
@@ -67,11 +70,14 @@ void SubscribeToWebFeedTask::Run() {
feedwire::webfeed::FollowWebFeedRequest request;
SetConsistencyToken(request, stream_.GetMetadata().consistency_token());
request.set_web_page_uri(request_.page_info.url().spec());
+ if (request_.page_info.canonical_url().is_valid()) {
+ request.set_canonical_uri(request_.page_info.canonical_url().spec());
+ }
for (const GURL& rss_url : request_.page_info.GetRssUrls()) {
request.add_page_rss_uris(rss_url.spec());
}
stream_.GetNetwork().SendApiRequest<FollowWebFeedDiscoverApi>(
- request, stream_.GetSyncSignedInGaia(),
+ request, stream_.GetAccountInfo(), stream_.GetSignedInRequestMetadata(),
base::BindOnce(&SubscribeToWebFeedTask::RequestComplete,
base::Unretained(this)));
}
@@ -79,6 +85,10 @@ void SubscribeToWebFeedTask::Run() {
void SubscribeToWebFeedTask::RequestComplete(
FeedNetwork::ApiResult<feedwire::webfeed::FollowWebFeedResponse> result) {
+ // This will always be valid, because ClearAllTask cannot have run after this
+ // task starts.
+ DCHECK(operation_token_);
+
if (result.response_body) {
stream_.SetMetadata(feedstore::MaybeUpdateConsistencyToken(
stream_.GetMetadata(), result.response_body->consistency_token()));
diff --git a/chromium/components/feed/core/v2/web_feed_subscriptions/subscribe_to_web_feed_task.h b/chromium/components/feed/core/v2/web_feed_subscriptions/subscribe_to_web_feed_task.h
index 2deee3acc5b..3cb2828ab19 100644
--- a/chromium/components/feed/core/v2/web_feed_subscriptions/subscribe_to_web_feed_task.h
+++ b/chromium/components/feed/core/v2/web_feed_subscriptions/subscribe_to_web_feed_task.h
@@ -10,6 +10,7 @@
#include "components/feed/core/v2/enums.h"
#include "components/feed/core/v2/feed_network.h"
#include "components/feed/core/v2/feed_store.h"
+#include "components/feed/core/v2/operation_token.h"
#include "components/offline_pages/task/task.h"
#include "url/gurl.h"
@@ -24,6 +25,8 @@ class SubscribeToWebFeedTask : public offline_pages::Task {
struct Request {
WebFeedPageInformation page_info;
std::string web_feed_id;
+ // Whether the subscription request will be stored and retried if failed.
+ bool durable = false;
};
struct Result {
WebFeedSubscriptionRequestStatus request_status =
@@ -34,6 +37,7 @@ class SubscribeToWebFeedTask : public offline_pages::Task {
feedstore::WebFeedInfo web_feed_info;
};
SubscribeToWebFeedTask(FeedStream* stream,
+ const OperationToken& operation_token,
Request request,
base::OnceCallback<void(Result)> callback);
~SubscribeToWebFeedTask() override;
@@ -49,6 +53,7 @@ class SubscribeToWebFeedTask : public offline_pages::Task {
void Done(WebFeedSubscriptionRequestStatus status);
FeedStream& stream_;
+ OperationToken operation_token_;
Request request_;
feedstore::WebFeedInfo subscribed_web_feed_info_;
base::OnceCallback<void(Result)> callback_;
diff --git a/chromium/components/feed/core/v2/web_feed_subscriptions/unsubscribe_from_web_feed_task.cc b/chromium/components/feed/core/v2/web_feed_subscriptions/unsubscribe_from_web_feed_task.cc
index 7a4230fb4ce..a6d1e0ff1d7 100644
--- a/chromium/components/feed/core/v2/web_feed_subscriptions/unsubscribe_from_web_feed_task.cc
+++ b/chromium/components/feed/core/v2/web_feed_subscriptions/unsubscribe_from_web_feed_task.cc
@@ -16,26 +16,30 @@
#include "components/feed/core/v2/feedstore_util.h"
#include "components/feed/core/v2/proto_util.h"
#include "components/feed/core/v2/web_feed_subscription_coordinator.h"
+#include "components/feed/core/v2/web_feed_subscriptions/web_feed_types.h"
namespace feed {
UnsubscribeFromWebFeedTask::UnsubscribeFromWebFeedTask(
FeedStream* stream,
+ const OperationToken& operation_token,
const std::string& web_feed_id,
base::OnceCallback<void(Result)> callback)
: stream_(*stream),
+ operation_token_(operation_token),
web_feed_name_(web_feed_id),
callback_(std::move(callback)) {}
UnsubscribeFromWebFeedTask::~UnsubscribeFromWebFeedTask() = default;
void UnsubscribeFromWebFeedTask::Run() {
- if (stream_.ClearAllInProgress()) {
+ if (!operation_token_) {
Done(WebFeedSubscriptionRequestStatus::
kAbortWebFeedSubscriptionPendingClearAll);
return;
}
- WebFeedSubscriptionCoordinator::SubscriptionInfo info =
+
+ WebFeedSubscriptionInfo info =
stream_.subscriptions().FindSubscriptionInfoById(web_feed_name_);
if (info.status != WebFeedSubscriptionStatus::kSubscribed) {
Done(WebFeedSubscriptionRequestStatus::kSuccess);
@@ -51,13 +55,16 @@ void UnsubscribeFromWebFeedTask::Run() {
SetConsistencyToken(request, stream_.GetMetadata().consistency_token());
request.set_name(web_feed_name_);
stream_.GetNetwork().SendApiRequest<UnfollowWebFeedDiscoverApi>(
- request, stream_.GetSyncSignedInGaia(),
+ request, stream_.GetAccountInfo(), stream_.GetSignedInRequestMetadata(),
base::BindOnce(&UnsubscribeFromWebFeedTask::RequestComplete,
base::Unretained(this)));
}
void UnsubscribeFromWebFeedTask::RequestComplete(
FeedNetwork::ApiResult<feedwire::webfeed::UnfollowWebFeedResponse> result) {
+ // This will always be valid, because ClearAllTask cannot have run after this
+ // task starts.
+ DCHECK(operation_token_);
if (!result.response_body) {
Done(WebFeedSubscriptionRequestStatus::kFailedUnknownError);
return;
diff --git a/chromium/components/feed/core/v2/web_feed_subscriptions/unsubscribe_from_web_feed_task.h b/chromium/components/feed/core/v2/web_feed_subscriptions/unsubscribe_from_web_feed_task.h
index d8efe4ae881..8527849d87c 100644
--- a/chromium/components/feed/core/v2/web_feed_subscriptions/unsubscribe_from_web_feed_task.h
+++ b/chromium/components/feed/core/v2/web_feed_subscriptions/unsubscribe_from_web_feed_task.h
@@ -8,6 +8,7 @@
#include "components/feed/core/proto/v2/wire/web_feeds.pb.h"
#include "components/feed/core/v2/enums.h"
#include "components/feed/core/v2/feed_network.h"
+#include "components/feed/core/v2/operation_token.h"
#include "components/offline_pages/task/task.h"
namespace feed {
@@ -25,6 +26,7 @@ class UnsubscribeFromWebFeedTask : public offline_pages::Task {
explicit UnsubscribeFromWebFeedTask(
FeedStream* stream,
+ const OperationToken& operation_token,
const std::string& web_feed_id,
base::OnceCallback<void(Result)> callback);
~UnsubscribeFromWebFeedTask() override;
@@ -40,6 +42,7 @@ class UnsubscribeFromWebFeedTask : public offline_pages::Task {
void Done(WebFeedSubscriptionRequestStatus status);
FeedStream& stream_;
+ OperationToken operation_token_;
Result result_;
std::string web_feed_name_;
base::OnceCallback<void(Result)> callback_;
diff --git a/chromium/components/feed/core/v2/web_feed_subscriptions/web_feed_index.cc b/chromium/components/feed/core/v2/web_feed_subscriptions/web_feed_index.cc
index 918bfc85a62..239e445dae4 100644
--- a/chromium/components/feed/core/v2/web_feed_subscriptions/web_feed_index.cc
+++ b/chromium/components/feed/core/v2/web_feed_subscriptions/web_feed_index.cc
@@ -488,6 +488,11 @@ std::vector<WebFeedIndex::Entry> WebFeedIndex::GetRecommendedEntriesForTesting()
return recommended_->entries();
}
+std::vector<WebFeedIndex::Entry> WebFeedIndex::GetSubscribedEntriesForTesting()
+ const {
+ return subscribed_->entries();
+}
+
void WebFeedIndex::DumpStateForDebugging(std::ostream& os) {
os << "recommended: ";
recommended_->DumpStateForDebugging(os);
diff --git a/chromium/components/feed/core/v2/web_feed_subscriptions/web_feed_index.h b/chromium/components/feed/core/v2/web_feed_subscriptions/web_feed_index.h
index fa377eb92cd..a049715b4d7 100644
--- a/chromium/components/feed/core/v2/web_feed_subscriptions/web_feed_index.h
+++ b/chromium/components/feed/core/v2/web_feed_subscriptions/web_feed_index.h
@@ -65,6 +65,7 @@ class WebFeedIndex {
int RecommendedWebFeedCount() const;
std::vector<Entry> GetRecommendedEntriesForTesting() const;
+ std::vector<Entry> GetSubscribedEntriesForTesting() const;
void DumpStateForDebugging(std::ostream& os);
private:
diff --git a/chromium/components/feed/core/v2/web_feed_subscriptions/web_feed_metadata_model.cc b/chromium/components/feed/core/v2/web_feed_subscriptions/web_feed_metadata_model.cc
new file mode 100644
index 00000000000..9a8cb52705e
--- /dev/null
+++ b/chromium/components/feed/core/v2/web_feed_subscriptions/web_feed_metadata_model.cc
@@ -0,0 +1,107 @@
+// Copyright 2022 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.
+
+#include "components/feed/core/v2/web_feed_subscriptions/web_feed_metadata_model.h"
+
+#include <ostream>
+
+#include "base/strings/string_piece.h"
+
+namespace feed {
+
+WebFeedMetadataModel::WebFeedMetadataModel(
+ FeedStore* store,
+ std::vector<feedstore::PendingWebFeedOperation> pending_operations)
+ : store_(store) {
+ for (const feedstore::PendingWebFeedOperation& operation :
+ pending_operations) {
+ if (next_id_ <= operation.id()) {
+ next_id_ = operation.id() + 1;
+ }
+ pending_operations_.push_back(
+ {operation, MakePendingInFlightChange(operation)});
+ }
+}
+
+WebFeedMetadataModel::~WebFeedMetadataModel() = default;
+
+void WebFeedMetadataModel::AddPendingOperation(
+ feedstore::PendingWebFeedOperation::Kind kind,
+ const std::string& web_feed_id) {
+ // Don't allow more than one operation for a web feed, just overwrite the
+ // old one.
+ RemovePendingOperationsForWebFeed(web_feed_id);
+ feedstore::PendingWebFeedOperation operation;
+ operation.set_kind(kind);
+ operation.set_web_feed_id(web_feed_id);
+ operation.set_id(next_id_++);
+ store_->WritePendingWebFeedOperation(operation);
+
+ pending_operations_.push_back(
+ {operation, MakePendingInFlightChange(operation)});
+}
+
+void WebFeedMetadataModel::RemovePendingOperationsForWebFeed(
+ base::StringPiece web_feed_id) {
+ for (auto it = pending_operations_.begin(); it != pending_operations_.end();
+ ++it) {
+ if (it->operation.web_feed_id() != web_feed_id)
+ continue;
+ store_->RemovePendingWebFeedOperation(it->operation.id());
+ pending_operations_.erase(it);
+ break;
+ }
+}
+
+void WebFeedMetadataModel::RecordPendingOperationsForWebFeedAttempt(
+ base::StringPiece web_feed_id) {
+ for (Operation& op : pending_operations_) {
+ if (op.operation.web_feed_id() != web_feed_id)
+ continue;
+ if (op.operation.attempts() >=
+ WebFeedInFlightChange::kMaxDurableOperationAttempts) {
+ RemovePendingOperationsForWebFeed(web_feed_id);
+ return;
+ }
+ op.operation.set_attempts(op.operation.attempts() + 1);
+ store_->WritePendingWebFeedOperation(op.operation);
+ return;
+ }
+}
+
+WebFeedInFlightChange* WebFeedMetadataModel::FindInFlightChange(
+ base::StringPiece web_feed_id) {
+ Operation* op = FindOperation(web_feed_id);
+ return op ? &op->change : nullptr;
+}
+
+// static
+WebFeedInFlightChange WebFeedMetadataModel::MakePendingInFlightChange(
+ const feedstore::PendingWebFeedOperation& operation) {
+ WebFeedInFlightChange change;
+ change.subscribing =
+ operation.kind() == feedstore::PendingWebFeedOperation::SUBSCRIBE;
+ change.strategy = WebFeedInFlightChangeStrategy::kPending;
+ change.web_feed_info = feedstore::WebFeedInfo();
+ change.web_feed_info->set_web_feed_id(operation.web_feed_id());
+ return change;
+}
+
+WebFeedMetadataModel::Operation* WebFeedMetadataModel::FindOperation(
+ base::StringPiece web_feed_id) {
+ for (auto& op : pending_operations_) {
+ if (op.operation.web_feed_id() == web_feed_id)
+ return &op;
+ }
+ return nullptr;
+}
+
+std::ostream& operator<<(std::ostream& os,
+ const WebFeedMetadataModel::Operation& op) {
+ return os << feedstore::PendingWebFeedOperation_Kind_Name(op.operation.kind())
+ << " " << op.operation.web_feed_id()
+ << " attempts=" << op.operation.attempts();
+}
+
+} // namespace feed
diff --git a/chromium/components/feed/core/v2/web_feed_subscriptions/web_feed_metadata_model.h b/chromium/components/feed/core/v2/web_feed_subscriptions/web_feed_metadata_model.h
new file mode 100644
index 00000000000..2466b91ea57
--- /dev/null
+++ b/chromium/components/feed/core/v2/web_feed_subscriptions/web_feed_metadata_model.h
@@ -0,0 +1,62 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_FEED_CORE_V2_WEB_FEED_SUBSCRIPTIONS_WEB_FEED_METADATA_MODEL_H_
+#define COMPONENTS_FEED_CORE_V2_WEB_FEED_SUBSCRIPTIONS_WEB_FEED_METADATA_MODEL_H_
+
+#include <iosfwd>
+#include <vector>
+
+#include "components/feed/core/proto/v2/store.pb.h"
+#include "components/feed/core/v2/feed_store.h"
+#include "components/feed/core/v2/operation_token.h"
+#include "components/feed/core/v2/public/types.h"
+#include "components/feed/core/v2/web_feed_subscriptions/web_feed_types.h"
+
+// This file has some in-memory model definitions used internally by
+// WebFeedSubscriptionCoordinator.
+namespace feed {
+
+// Unlike WebFeedSubscriptionModel, this model is loaded in at startup, but it
+// has less data.
+class WebFeedMetadataModel {
+ public:
+ struct Operation {
+ // The stored operation.
+ feedstore::PendingWebFeedOperation operation;
+ // Data from `operation`, mirrored in an `WebFeedInFlightChange`.
+ WebFeedInFlightChange change;
+ };
+
+ WebFeedMetadataModel(
+ FeedStore* store,
+ std::vector<feedstore::PendingWebFeedOperation> pending_operations);
+ WebFeedMetadataModel(const WebFeedMetadataModel&) = delete;
+ WebFeedMetadataModel& operator=(const WebFeedMetadataModel&) = delete;
+ ~WebFeedMetadataModel();
+
+ void AddPendingOperation(feedstore::PendingWebFeedOperation::Kind kind,
+ const std::string& web_feed_id);
+ void RemovePendingOperationsForWebFeed(base::StringPiece web_feed_id);
+ void RecordPendingOperationsForWebFeedAttempt(base::StringPiece web_feed_id);
+
+ WebFeedInFlightChange* FindInFlightChange(base::StringPiece web_feed_id);
+ const std::vector<Operation>& pending_operations() const {
+ return pending_operations_;
+ }
+
+ private:
+ static WebFeedInFlightChange MakePendingInFlightChange(
+ const feedstore::PendingWebFeedOperation& operation);
+ Operation* FindOperation(base::StringPiece web_feed_id);
+ raw_ptr<FeedStore> store_;
+ std::vector<Operation> pending_operations_;
+ int next_id_ = 0;
+};
+
+std::ostream& operator<<(std::ostream& os,
+ const WebFeedMetadataModel::Operation& op);
+} // namespace feed
+
+#endif // COMPONENTS_FEED_CORE_V2_WEB_FEED_SUBSCRIPTIONS_WEB_FEED_METADATA_MODEL_H_
diff --git a/chromium/components/feed/core/v2/web_feed_subscriptions/web_feed_subscription_model.cc b/chromium/components/feed/core/v2/web_feed_subscriptions/web_feed_subscription_model.cc
new file mode 100644
index 00000000000..72facbf32dd
--- /dev/null
+++ b/chromium/components/feed/core/v2/web_feed_subscriptions/web_feed_subscription_model.cc
@@ -0,0 +1,132 @@
+// Copyright 2022 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.
+
+#include "components/feed/core/v2/web_feed_subscriptions/web_feed_subscription_model.h"
+
+#include "components/feed/core/proto/v2/store.pb.h"
+#include "components/feed/core/v2/feed_store.h"
+#include "components/feed/core/v2/feedstore_util.h"
+#include "components/feed/core/v2/web_feed_subscriptions/web_feed_index.h"
+#include "components/feed/core/v2/web_feed_subscriptions/web_feed_metadata_model.h"
+
+namespace feed {
+namespace {
+
+feedstore::WebFeedInfo Remove(
+ const std::string& web_feed_id,
+ std::vector<feedstore::WebFeedInfo>& feed_info_list) {
+ feedstore::WebFeedInfo result;
+ for (size_t i = 0; i < feed_info_list.size(); ++i) {
+ if (feed_info_list[i].web_feed_id() == web_feed_id) {
+ result = std::move(feed_info_list[i]);
+ feed_info_list.erase(feed_info_list.begin() + i);
+ break;
+ }
+ }
+ return result;
+}
+
+} // namespace
+
+WebFeedSubscriptionModel::WebFeedSubscriptionModel(
+ FeedStore* store,
+ WebFeedIndex* index,
+ std::vector<feedstore::WebFeedInfo>* recent_subscriptions,
+ feedstore::SubscribedWebFeeds feeds,
+ WebFeedMetadataModel* metadata_model)
+ : store_(store),
+ index_(index),
+ metadata_model_(metadata_model),
+ recent_unsubscribed_(recent_subscriptions) {
+ subscriptions_.assign(std::make_move_iterator(feeds.feeds().begin()),
+ std::make_move_iterator(feeds.feeds().end()));
+ update_time_millis_ = feeds.update_time_millis();
+}
+
+WebFeedSubscriptionModel::~WebFeedSubscriptionModel() = default;
+
+WebFeedSubscriptionInfo WebFeedSubscriptionModel::GetSubscriptionInfo(
+ const std::string& web_feed_id) {
+ WebFeedSubscriptionInfo result;
+ for (const feedstore::WebFeedInfo& info : *recent_unsubscribed_) {
+ if (info.web_feed_id() == web_feed_id) {
+ result.status = WebFeedSubscriptionStatus::kNotSubscribed;
+ result.web_feed_info = info;
+ break;
+ }
+ }
+
+ for (const feedstore::WebFeedInfo& info : subscriptions_) {
+ if (info.web_feed_id() == web_feed_id) {
+ result.status = WebFeedSubscriptionStatus::kSubscribed;
+ result.web_feed_info = info;
+ break;
+ }
+ }
+
+ return result;
+}
+
+void WebFeedSubscriptionModel::OnSubscribed(
+ const feedstore::WebFeedInfo& info) {
+ Remove(info.web_feed_id(), *recent_unsubscribed_);
+ Remove(info.web_feed_id(), subscriptions_);
+ metadata_model_->RemovePendingOperationsForWebFeed(info.web_feed_id());
+
+ subscriptions_.emplace_back(info);
+ UpdateIndexAndStore();
+}
+
+void WebFeedSubscriptionModel::OnUnsubscribed(const std::string& web_feed_id) {
+ feedstore::WebFeedInfo info = Remove(web_feed_id, subscriptions_);
+ if (!info.web_feed_id().empty()) {
+ metadata_model_->RemovePendingOperationsForWebFeed(info.web_feed_id());
+ recent_unsubscribed_->push_back(std::move(info));
+ }
+ UpdateIndexAndStore();
+}
+
+void WebFeedSubscriptionModel::UpdateIndexAndStore() {
+ feedstore::SubscribedWebFeeds state;
+ for (const feedstore::WebFeedInfo& info : subscriptions_) {
+ *state.add_feeds() = info;
+ }
+ state.set_update_time_millis(update_time_millis_);
+ index_->Populate(state);
+ store_->WriteSubscribedFeeds(std::move(state), base::DoNothing());
+}
+
+// Updates recommended web feeds in both index and store.
+void WebFeedSubscriptionModel::UpdateRecommendedFeeds(
+ std::vector<feedstore::WebFeedInfo> recommended_web_feeds) {
+ feedstore::RecommendedWebFeedIndex store_index;
+ store_index.set_update_time_millis(
+ feedstore::ToTimestampMillis(base::Time::Now()));
+ for (const feedstore::WebFeedInfo& info : recommended_web_feeds) {
+ feedstore::RecommendedWebFeedIndex::Entry& entry =
+ *store_index.add_entries();
+ entry.set_web_feed_id(info.web_feed_id());
+ *entry.mutable_matchers() = info.matchers();
+ }
+ index_->Populate(store_index);
+ store_->WriteRecommendedFeeds(std::move(store_index),
+ std::move(recommended_web_feeds),
+ base::DoNothing());
+}
+
+// Updates subscribed web feeds in both index and store.
+void WebFeedSubscriptionModel::UpdateSubscribedFeeds(
+ std::vector<feedstore::WebFeedInfo> subscribed_web_feeds) {
+ feedstore::SubscribedWebFeeds store_index;
+ update_time_millis_ = feedstore::ToTimestampMillis(base::Time::Now());
+ store_index.set_update_time_millis(update_time_millis_);
+ for (const feedstore::WebFeedInfo& info : subscribed_web_feeds) {
+ *store_index.add_feeds() = info;
+ }
+ index_->Populate(store_index);
+ store_->WriteSubscribedFeeds(std::move(store_index), base::DoNothing());
+ subscriptions_ = subscribed_web_feeds;
+}
+
+} // namespace feed
diff --git a/chromium/components/feed/core/v2/web_feed_subscriptions/web_feed_subscription_model.h b/chromium/components/feed/core/v2/web_feed_subscriptions/web_feed_subscription_model.h
new file mode 100644
index 00000000000..af62449f9f0
--- /dev/null
+++ b/chromium/components/feed/core/v2/web_feed_subscriptions/web_feed_subscription_model.h
@@ -0,0 +1,70 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_FEED_CORE_V2_WEB_FEED_SUBSCRIPTIONS_WEB_FEED_SUBSCRIPTION_MODEL_H_
+#define COMPONENTS_FEED_CORE_V2_WEB_FEED_SUBSCRIPTIONS_WEB_FEED_SUBSCRIPTION_MODEL_H_
+
+#include <vector>
+
+#include "components/feed/core/proto/v2/store.pb.h"
+#include "components/feed/core/v2/operation_token.h"
+#include "components/feed/core/v2/public/types.h"
+#include "components/feed/core/v2/web_feed_subscriptions/web_feed_types.h"
+
+namespace feed {
+class WebFeedIndex;
+class WebFeedMetadataModel;
+class FeedStore;
+
+// An in-memory model of the subscribed web feeds. This should be loaded before
+// making any changes to stored web feeds, so that we rarely need to wait on
+// other tasks to load the subscribed feeds. Additionally, any changes to stored
+// feeds also need to update this in-memory model.
+class WebFeedSubscriptionModel {
+ public:
+ WebFeedSubscriptionModel(
+ FeedStore* store,
+ WebFeedIndex* index,
+ std::vector<feedstore::WebFeedInfo>* recent_subscriptions,
+ feedstore::SubscribedWebFeeds feeds,
+ WebFeedMetadataModel* metadata_model);
+ WebFeedSubscriptionModel(const WebFeedSubscriptionModel&) = delete;
+ WebFeedSubscriptionModel& operator=(const WebFeedSubscriptionModel&) = delete;
+ ~WebFeedSubscriptionModel();
+
+ WebFeedSubscriptionInfo GetSubscriptionInfo(const std::string& web_feed_id);
+ void OnSubscribed(const feedstore::WebFeedInfo& info);
+ void OnUnsubscribed(const std::string& web_feed_id);
+ void UpdateIndexAndStore();
+
+ // Updates recommended web feeds in both index and store.
+ void UpdateRecommendedFeeds(
+ std::vector<feedstore::WebFeedInfo> recommended_web_feeds);
+
+ // Updates subscribed web feeds in both index and store.
+ void UpdateSubscribedFeeds(
+ std::vector<feedstore::WebFeedInfo> subscribed_web_feeds);
+
+ const std::vector<feedstore::WebFeedInfo>& subscriptions() const {
+ return subscriptions_;
+ }
+
+ private:
+ // Each of these are non-null and guaranteed to remain valid for the lifetime
+ // of WebFeedSubscriptionModel.
+ raw_ptr<FeedStore> store_;
+ raw_ptr<WebFeedIndex> index_;
+ raw_ptr<WebFeedMetadataModel> metadata_model_;
+ // Owned by WebFeedSubscriptionCoordinator so that memory of recent
+ // subscriptions is retained when the model is deleted.
+ raw_ptr<std::vector<feedstore::WebFeedInfo>> recent_unsubscribed_;
+
+ // The current known state of subscriptions.
+ std::vector<feedstore::WebFeedInfo> subscriptions_;
+ int64_t update_time_millis_ = 0;
+};
+
+} // namespace feed
+
+#endif // COMPONENTS_FEED_CORE_V2_WEB_FEED_SUBSCRIPTIONS_WEB_FEED_SUBSCRIPTION_MODEL_H_
diff --git a/chromium/components/feed/core/v2/web_feed_subscriptions/web_feed_types.cc b/chromium/components/feed/core/v2/web_feed_subscriptions/web_feed_types.cc
new file mode 100644
index 00000000000..33a00b2365d
--- /dev/null
+++ b/chromium/components/feed/core/v2/web_feed_subscriptions/web_feed_types.cc
@@ -0,0 +1,52 @@
+// Copyright 2022 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.
+
+#include "components/feed/core/v2/web_feed_subscriptions/web_feed_types.h"
+
+#include <ostream>
+
+namespace feed {
+
+WebFeedInFlightChange::WebFeedInFlightChange() = default;
+WebFeedInFlightChange::WebFeedInFlightChange(const WebFeedInFlightChange&) =
+ default;
+WebFeedInFlightChange::WebFeedInFlightChange(WebFeedInFlightChange&&) = default;
+WebFeedInFlightChange& WebFeedInFlightChange::operator=(
+ WebFeedInFlightChange&&) = default;
+WebFeedInFlightChange& WebFeedInFlightChange::operator=(
+ const WebFeedInFlightChange&) = default;
+WebFeedInFlightChange::~WebFeedInFlightChange() = default;
+
+std::ostream& operator<<(std::ostream& os,
+ const WebFeedInFlightChange& change) {
+ os << "Change{";
+ if (change.strategy != WebFeedInFlightChangeStrategy::kPending &&
+ !change.token)
+ os << "Expired ";
+
+ os << (change.subscribing ? "subscribing " : "unsubscribing ");
+ os << change.strategy << " ";
+ if (change.page_information)
+ os << *change.page_information << ' ';
+
+ if (change.web_feed_info)
+ os << "web_feed_id=" << change.web_feed_info->web_feed_id() << ' ';
+
+ return os << "}";
+}
+
+std::ostream& operator<<(std::ostream& os,
+ const WebFeedInFlightChangeStrategy& strategy) {
+ switch (strategy) {
+ case WebFeedInFlightChangeStrategy::kNotDurableRequest:
+ return os << "regular";
+ case WebFeedInFlightChangeStrategy::kNewDurableRequest:
+ return os << "durable";
+ case WebFeedInFlightChangeStrategy::kRetry:
+ return os << "retry";
+ case WebFeedInFlightChangeStrategy::kPending:
+ return os << "pending";
+ }
+}
+} // namespace feed
diff --git a/chromium/components/feed/core/v2/web_feed_subscriptions/web_feed_types.h b/chromium/components/feed/core/v2/web_feed_subscriptions/web_feed_types.h
new file mode 100644
index 00000000000..0bdcb4f3dc3
--- /dev/null
+++ b/chromium/components/feed/core/v2/web_feed_subscriptions/web_feed_types.h
@@ -0,0 +1,65 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_FEED_CORE_V2_WEB_FEED_SUBSCRIPTIONS_WEB_FEED_TYPES_H_
+#define COMPONENTS_FEED_CORE_V2_WEB_FEED_SUBSCRIPTIONS_WEB_FEED_TYPES_H_
+
+#include <iosfwd>
+
+#include "components/feed/core/proto/v2/store.pb.h"
+#include "components/feed/core/v2/operation_token.h"
+#include "components/feed/core/v2/public/types.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+// Defines some types needed by WebFeedSubscriptionCoordinator and its models.
+
+namespace feed {
+
+struct WebFeedSubscriptionInfo {
+ WebFeedSubscriptionStatus status = WebFeedSubscriptionStatus::kUnknown;
+ feedstore::WebFeedInfo web_feed_info;
+};
+
+// Identifies how the in flight change should be processed.
+enum class WebFeedInFlightChangeStrategy {
+ // The follow/unfollow attempt is aborted upon network failure.
+ kNotDurableRequest,
+ // A new follow/unfollow attempt to be retried after failure.
+ kNewDurableRequest,
+ // A durable request, on subsequent tries.
+ kRetry,
+ // Used when the `InFlightChange` is stored for later execution.
+ kPending,
+};
+std::ostream& operator<<(std::ostream& os,
+ const WebFeedInFlightChangeStrategy& strategy);
+
+// Represents an in-progress attempt to change a Web Feed subscription.
+struct WebFeedInFlightChange {
+ // Maximum number of tries for a durable subscribe/unsubscribe operation.
+ // TODO(b/205770750): Add metrics to help optimize this value.
+ static constexpr int kMaxDurableOperationAttempts = 4;
+
+ WebFeedInFlightChange();
+ WebFeedInFlightChange(const WebFeedInFlightChange&);
+ WebFeedInFlightChange(WebFeedInFlightChange&&);
+ WebFeedInFlightChange& operator=(WebFeedInFlightChange&&);
+ WebFeedInFlightChange& operator=(const WebFeedInFlightChange&);
+ ~WebFeedInFlightChange();
+
+ OperationToken token = OperationToken::MakeInvalid();
+ // Either subscribing or unsubscribing.
+ bool subscribing = false;
+ WebFeedInFlightChangeStrategy strategy;
+ // Set only when subscribing from a web page.
+ absl::optional<WebFeedPageInformation> page_information;
+ // We may or may not know about this web feed when subscribing; always known
+ // when unsubscribing.
+ absl::optional<feedstore::WebFeedInfo> web_feed_info;
+};
+std::ostream& operator<<(std::ostream& os, const WebFeedInFlightChange& change);
+
+} // namespace feed
+
+#endif // COMPONENTS_FEED_CORE_V2_WEB_FEED_SUBSCRIPTIONS_WEB_FEED_TYPES_H_
diff --git a/chromium/components/feed/core/v2/wire_response_translator.cc b/chromium/components/feed/core/v2/wire_response_translator.cc
index daefe46ecdf..6a418c5f816 100644
--- a/chromium/components/feed/core/v2/wire_response_translator.cc
+++ b/chromium/components/feed/core/v2/wire_response_translator.cc
@@ -9,10 +9,10 @@ namespace feed {
RefreshResponseData WireResponseTranslator::TranslateWireResponse(
feedwire::Response response,
StreamModelUpdateRequest::Source source,
- bool was_signed_in_request,
+ const AccountInfo& account_info,
base::Time current_time) const {
return ::feed::TranslateWireResponse(std::move(response), source,
- was_signed_in_request, current_time);
+ account_info, current_time);
}
} // namespace feed
diff --git a/chromium/components/feed/core/v2/wire_response_translator.h b/chromium/components/feed/core/v2/wire_response_translator.h
index c4b8b9912aa..a9a34ae4701 100644
--- a/chromium/components/feed/core/v2/wire_response_translator.h
+++ b/chromium/components/feed/core/v2/wire_response_translator.h
@@ -8,6 +8,7 @@
#include "components/feed/core/v2/protocol_translator.h"
namespace feed {
+struct AccountInfo;
// Forwards to |feed::TranslateWireResponse()| by default. Can be overridden
// for testing.
@@ -18,7 +19,7 @@ class WireResponseTranslator {
virtual RefreshResponseData TranslateWireResponse(
feedwire::Response response,
StreamModelUpdateRequest::Source source,
- bool was_signed_in_request,
+ const AccountInfo& account_info,
base::Time current_time) const;
};
diff --git a/chromium/components/feed/feed_feature_list.cc b/chromium/components/feed/feed_feature_list.cc
index 3c9f81ff702..9cb07cad67a 100644
--- a/chromium/components/feed/feed_feature_list.cc
+++ b/chromium/components/feed/feed_feature_list.cc
@@ -47,9 +47,9 @@ const base::Feature kInterestFeedV2ClicksAndViewsConditionalUpload{
"InterestFeedV2ClickAndViewActionsConditionalUpload",
base::FEATURE_DISABLED_BY_DEFAULT};
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
const base::Feature kInterestFeedNoticeCardAutoDismiss{
- "InterestFeedNoticeCardAutoDismiss", base::FEATURE_DISABLED_BY_DEFAULT};
+ "InterestFeedNoticeCardAutoDismiss", base::FEATURE_ENABLED_BY_DEFAULT};
#endif
const base::Feature kInterestFeedSpinnerAlwaysAnimate{
@@ -61,9 +61,9 @@ const base::Feature kDiscoFeedEndpoint{"DiscoFeedEndpoint",
const base::Feature kXsurfaceMetricsReporting{
"XsurfaceMetricsReporting", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kReliabilityLogging{"FeedReliabilityLogging",
- base::FEATURE_DISABLED_BY_DEFAULT};
+ base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kFeedInteractiveRefresh{"FeedInteractiveRefresh",
- base::FEATURE_DISABLED_BY_DEFAULT};
+ base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kFeedLoadingPlaceholder{"FeedLoadingPlaceholder",
base::FEATURE_DISABLED_BY_DEFAULT};
const base::FeatureParam<bool>
@@ -75,8 +75,6 @@ const base::Feature kFeedClearImageMemoryCache{
"FeedClearImageMemoryCache", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kFeedBackToTop{"FeedBackToTop",
base::FEATURE_DISABLED_BY_DEFAULT};
-const base::Feature kFeedSignInPromoDismiss{"FeedSignInPromoDismiss",
- base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kFeedStamp{"FeedStamp", base::FEATURE_DISABLED_BY_DEFAULT};
const char kDefaultReferrerUrl[] = "https://www.google.com/";
@@ -88,6 +86,12 @@ const base::Feature kEnableOpenInNewTabFromStartSurfaceFeed{
"EnableOpenInNewTabFromStartSurfaceFeed",
base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kWebUiFeed{"FeedWebUi", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::FeatureParam<std::string> kWebUiScriptFetchUrl{
+ &kWebUiFeed, "scripturl", "chrome-untrusted://feed/feed.js"};
+const base::FeatureParam<bool> kWebUiDisableContentSecurityPolicy{
+ &kWebUiFeed, "disableCsp", false};
+
std::string GetFeedReferrerUrl() {
const base::Feature* feature = base::FeatureList::IsEnabled(kInterestFeedV2)
? &kInterestFeedV2
diff --git a/chromium/components/feed/feed_feature_list.h b/chromium/components/feed/feed_feature_list.h
index 5c8b037d07a..0447c7320db 100644
--- a/chromium/components/feed/feed_feature_list.h
+++ b/chromium/components/feed/feed_feature_list.h
@@ -27,6 +27,8 @@ extern const base::FeatureParam<int> kTimeoutDurationSeconds;
extern const base::FeatureParam<bool> kThrottleBackgroundFetches;
extern const base::FeatureParam<bool> kOnlySetLastRefreshAttemptOnSuccess;
+// TODO(b/213622639): The following two features are obsolete and should be
+// removed.
// Determines whether conditions should be reached before enabling the upload of
// click and view actions in the feed (e.g., the user needs to view X cards).
// For example, this is needed when the notice card is at the second position in
@@ -36,7 +38,7 @@ extern const base::Feature kInterestFeedV2ClicksAndViewsConditionalUpload;
// Feature that allows the client to automatically dismiss the notice card based
// on the clicks and views on the notice card.
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
extern const base::Feature kInterestFeedNoticeCardAutoDismiss;
#endif
@@ -80,10 +82,6 @@ extern const base::Feature kFeedClearImageMemoryCache;
// feeds quickly.
extern const base::Feature kFeedBackToTop;
-// Feature that enables the 'X' in the signin promo in the Feed. Without the 'X'
-// the signin promo is not dismissible without opting to sign in.
-extern const base::Feature kFeedSignInPromoDismiss;
-
// Feature that enables StAMP cards in the feed.
extern const base::Feature kFeedStamp;
@@ -94,6 +92,11 @@ extern const base::Feature kWebFeedSort;
// on Start Surface.
extern const base::Feature kEnableOpenInNewTabFromStartSurfaceFeed;
+// Feature that causes the WebUI version of the Feed to be enabled.
+extern const base::Feature kWebUiFeed;
+extern const base::FeatureParam<std::string> kWebUiScriptFetchUrl;
+extern const base::FeatureParam<bool> kWebUiDisableContentSecurityPolicy;
+
std::string GetFeedReferrerUrl();
} // namespace feed
diff --git a/chromium/components/feedback/BUILD.gn b/chromium/components/feedback/BUILD.gn
index c9388cc46da..22d15168306 100644
--- a/chromium/components/feedback/BUILD.gn
+++ b/chromium/components/feedback/BUILD.gn
@@ -18,6 +18,7 @@ static_library("feedback") {
"feedback_uploader.h",
"feedback_util.cc",
"feedback_util.h",
+ "pii_types.h",
"redaction_tool.cc",
"redaction_tool.h",
"system_logs/system_logs_fetcher.cc",
diff --git a/chromium/components/feedback/feedback_data.cc b/chromium/components/feedback/feedback_data.cc
index 27d722403ff..89e262835f0 100644
--- a/chromium/components/feedback/feedback_data.cc
+++ b/chromium/components/feedback/feedback_data.cc
@@ -32,11 +32,9 @@ const char kHistogramsAttachmentName[] = "histograms.zip";
} // namespace
-FeedbackData::FeedbackData(FeedbackUploader* uploader,
+FeedbackData::FeedbackData(base::WeakPtr<feedback::FeedbackUploader> uploader,
TracingManager* tracing_manager)
- : uploader_(uploader), tracing_manager_(tracing_manager) {
- CHECK(uploader_);
-}
+ : uploader_(std::move(uploader)), tracing_manager_(tracing_manager) {}
FeedbackData::~FeedbackData() = default;
@@ -87,7 +85,7 @@ void FeedbackData::AttachAndCompressFileData(std::string attached_filedata) {
return;
++pending_op_count_;
base::FilePath attached_file =
- base::FilePath::FromUTF8Unsafe(attached_filename_);
+ base::FilePath::FromUTF8Unsafe(attached_filename_);
base::ThreadPool::PostTaskAndReply(
FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT},
base::BindOnce(&FeedbackData::CompressFile, this, attached_file,
@@ -123,7 +121,7 @@ bool FeedbackData::IsDataComplete() {
void FeedbackData::SendReport() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- if (IsDataComplete() && !report_sent_) {
+ if (uploader_ && IsDataComplete() && !report_sent_) {
report_sent_ = true;
userfeedback::ExtensionSubmit feedback_data;
PrepareReport(&feedback_data);
diff --git a/chromium/components/feedback/feedback_data.h b/chromium/components/feedback/feedback_data.h
index 219ef69f97e..72e0ba52a1b 100644
--- a/chromium/components/feedback/feedback_data.h
+++ b/chromium/components/feedback/feedback_data.h
@@ -10,6 +10,7 @@
#include "base/callback.h"
#include "base/memory/raw_ptr.h"
+#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "components/feedback/feedback_common.h"
#include "components/feedback/feedback_uploader.h"
@@ -25,7 +26,8 @@ namespace feedback {
class FeedbackData : public FeedbackCommon {
public:
- FeedbackData(FeedbackUploader* uploader, TracingManager* tracing_manager);
+ FeedbackData(base::WeakPtr<feedback::FeedbackUploader> uploader,
+ TracingManager* tracing_manager);
FeedbackData(const FeedbackData&) = delete;
FeedbackData& operator=(const FeedbackData&) = delete;
@@ -114,7 +116,9 @@ class FeedbackData : public FeedbackCommon {
SEQUENCE_CHECKER(sequence_checker_);
- const raw_ptr<feedback::FeedbackUploader> uploader_ = nullptr; // Not owned.
+ // The uploader_ is tied to a profile. When the profile is deleted, the
+ // uploader_ will be destroyed.
+ base::WeakPtr<feedback::FeedbackUploader> uploader_;
std::string attached_filename_ GUARDED_BY_CONTEXT(sequence_checker_);
std::string attached_file_uuid_ GUARDED_BY_CONTEXT(sequence_checker_);
diff --git a/chromium/components/feedback/feedback_data_unittest.cc b/chromium/components/feedback/feedback_data_unittest.cc
index ed65c1a4dde..04a144065c7 100644
--- a/chromium/components/feedback/feedback_data_unittest.cc
+++ b/chromium/components/feedback/feedback_data_unittest.cc
@@ -72,7 +72,10 @@ class FeedbackDataTest : public testing::Test {
test_shared_loader_factory_,
base::BindOnce(&FeedbackDataTest::set_send_report_callback,
base::Unretained(this)));
- data_ = base::MakeRefCounted<FeedbackData>(uploader_.get(), nullptr);
+ base::WeakPtr<feedback::FeedbackUploader> wkptr_uploader =
+ base::AsWeakPtr(uploader_.get());
+ data_ =
+ base::MakeRefCounted<FeedbackData>(std::move(wkptr_uploader), nullptr);
}
void Send() {
diff --git a/chromium/components/feedback/feedback_uploader.cc b/chromium/components/feedback/feedback_uploader.cc
index 791cc267329..3a7e98c36d5 100644
--- a/chromium/components/feedback/feedback_uploader.cc
+++ b/chromium/components/feedback/feedback_uploader.cc
@@ -7,6 +7,7 @@
#include "base/bind.h"
#include "base/callback.h"
#include "base/command_line.h"
+#include "base/metrics/histogram_macros.h"
#include "base/task/post_task.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
@@ -23,6 +24,17 @@ namespace feedback {
namespace {
+constexpr char kReportSendingResultHistogramName[] =
+ "Feedback.ReportSending.Result";
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
+enum class FeedbackReportSendingResult {
+ kSuccessAtFirstTry = 0, // The report was uploaded successfully without retry
+ kSuccessAfterRetry = 1, // The report was uploaded successfully after retry
+ kDropped = 2, // The report is corrupt or invalid and was dropped
+ kMaxValue = kDropped,
+};
+
constexpr base::FilePath::CharType kFeedbackReportPath[] =
FILE_PATH_LITERAL("Feedback Reports");
@@ -111,6 +123,13 @@ void FeedbackUploader::StartDispatchingReport() {
}
void FeedbackUploader::OnReportUploadSuccess() {
+ if (retry_delay_ == g_minimum_retry_delay) {
+ UMA_HISTOGRAM_ENUMERATION(kReportSendingResultHistogramName,
+ FeedbackReportSendingResult::kSuccessAtFirstTry);
+ } else {
+ UMA_HISTOGRAM_ENUMERATION(kReportSendingResultHistogramName,
+ FeedbackReportSendingResult::kSuccessAfterRetry);
+ }
retry_delay_ = g_minimum_retry_delay;
is_dispatching_ = false;
// Explicitly release the successfully dispatched report.
@@ -128,6 +147,8 @@ void FeedbackUploader::OnReportUploadFailure(bool should_retry) {
} else {
// The report won't be retried, hence explicitly delete its file on disk.
report_being_dispatched_->DeleteReportOnDisk();
+ UMA_HISTOGRAM_ENUMERATION(kReportSendingResultHistogramName,
+ FeedbackReportSendingResult::kDropped);
}
// The report dispatching failed, and should either be retried or not. In all
diff --git a/chromium/components/feedback/feedback_uploader_unittest.cc b/chromium/components/feedback/feedback_uploader_unittest.cc
index 9fa89739b1f..d7bf425168b 100644
--- a/chromium/components/feedback/feedback_uploader_unittest.cc
+++ b/chromium/components/feedback/feedback_uploader_unittest.cc
@@ -192,7 +192,7 @@ TEST_F(FeedbackUploaderTest, QueueMultipleWithFailures) {
EXPECT_EQ(uploader()->dispatched_reports().at(kReportFive), 1u);
}
-#if defined(OS_MAC) && defined(ARCH_CPU_ARM64)
+#if BUILDFLAG(IS_MAC) && defined(ARCH_CPU_ARM64)
// https://crbug.com/1222877
#define MAYBE_SimulateOfflineReports DISABLED_SimulateOfflineReports
#else
diff --git a/chromium/components/feedback/feedback_util.cc b/chromium/components/feedback/feedback_util.cc
index 81531e1fd57..9a295ef3762 100644
--- a/chromium/components/feedback/feedback_util.cc
+++ b/chromium/components/feedback/feedback_util.cc
@@ -11,6 +11,7 @@
#include "base/files/scoped_temp_dir.h"
#include "base/logging.h"
#include "base/strings/string_util.h"
+#include "build/build_config.h"
#include "components/feedback/feedback_report.h"
#include "third_party/zlib/google/zip.h"
@@ -78,7 +79,7 @@ std::string LogsToString(const FeedbackCommon::SystemLogsMap& sys_info) {
// not pass on OS_WIN.
// This function is only called on ChromeOS and Lacros build.
// See https://crbug.com/1119560.
-#if !defined(OS_WIN)
+#if !BUILDFLAG(IS_WIN)
bool ReadEndOfFile(const base::FilePath& path,
size_t max_size,
std::string* contents) {
@@ -135,6 +136,6 @@ bool ReadEndOfFile(const base::FilePath& path,
return true;
}
-#endif // !OS_WIN
+#endif // !BUILDFLAG(IS_WIN)
} // namespace feedback_util
diff --git a/chromium/components/feedback/feedback_util.h b/chromium/components/feedback/feedback_util.h
index c426acf0eca..83e93861d7a 100644
--- a/chromium/components/feedback/feedback_util.h
+++ b/chromium/components/feedback/feedback_util.h
@@ -21,7 +21,7 @@ bool ZipString(const base::FilePath& filename,
// creating a system_logs.txt file attached to feedback reports.
std::string LogsToString(const FeedbackCommon::SystemLogsMap& sys_info);
-#if !defined(OS_WIN)
+#if !BUILDFLAG(IS_WIN)
// Returns true if the data from the file specified by |path| is read into
// |contents| successfully.
// If the file size is greater than |max_size| in bytes, the data will be
diff --git a/chromium/components/feedback/pii_types.h b/chromium/components/feedback/pii_types.h
new file mode 100644
index 00000000000..8a6425ad23b
--- /dev/null
+++ b/chromium/components/feedback/pii_types.h
@@ -0,0 +1,66 @@
+// Copyright 2021 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.
+
+#ifndef COMPONENTS_FEEDBACK_PII_TYPES_H_
+#define COMPONENTS_FEEDBACK_PII_TYPES_H_
+
+namespace feedback {
+
+// PII (Personally Identifiable Information) types that can be detected in the
+// debug data.
+enum class PIIType {
+ // Indicates no PII. Mainly for testing.
+ kNone,
+ // Android App Storage paths. The path starts with either
+ // /home/root/<hash>/data/data/<package_name>/ or
+ // /home/root/<hash>/data/user_de/<number>/<package_name>/, the path
+ // components following <package_name>/ are app specific and will be
+ // considered as PII sensitive data.
+ kAndroidAppStoragePath,
+ // BSSID (Basic Service Set Identifier) of a wifi service.
+ kBSSID,
+ // Unique identifier of the cell of the Cell tower object that's used by
+ // ModemManager.
+ kCellID,
+ // Email addresses.
+ kEmail,
+ // GAIA (Google Accounts and ID Administration) ID. Gaia ID is a 64-bit
+ // integer.
+ kGaiaID,
+ // Hexadecimal strings of length 32, 40 and 64 are considered to be hashes.
+ kHash,
+ // IPP (Internet Printing Protocol) Addresses.
+ kIPPAddress,
+ // IP (Internet Protocol) address. Stores data in two versions: IPv4 (e.g.
+ // 127.0.0.1) or IPv6 (e.g. 2001:0db8:85a3:0000:0000:8a2e:0370:7334).
+ kIPAddress,
+ // The Location Area Code (LAC) for GSM and WCDMA networks of the Cell tower
+ // object that's used by ModemManager.
+ kLocationAreaCode,
+ // MAC address is a unique identifier assigned to a network interface
+ // controller (NIC) for use as a network address in communications within a
+ // network segment (e.g 00:00:5e:00:53:af). MAC addresses with general meaning
+ // like ARP failure result MAC and Broadcast MAC won't be treated as PII
+ // sensitive data and won't be included in this category.
+ kMACAddress,
+ // Window titles that appear in UI hierarchy.
+ kUIHierarchyWindowTitles,
+ // URLs that can appear in logs.
+ kURL,
+ // Universal Unique Identifiers (UUIDs). UUID can also be given by 'blkid',
+ // 'lvs' and 'pvs' tools.
+ kUUID,
+ // Serial numbers.
+ kSerial,
+ // SSID (Service Set Identifier) of wifi networks can be detected in the logs
+ // provided by wpa_supplicant and shill.
+ kSSID,
+ // Volume labels presented in the 'blkid' tool, and as part of removable
+ // media paths shown in various logs such as cros-disks (in syslog).
+ kVolumeLabel,
+};
+
+} // namespace feedback
+
+#endif // COMPONENTS_FEEDBACK_PII_TYPES_H_ \ No newline at end of file
diff --git a/chromium/components/feedback/redaction_tool.cc b/chromium/components/feedback/redaction_tool.cc
index 02498a53613..824e21e43e9 100644
--- a/chromium/components/feedback/redaction_tool.cc
+++ b/chromium/components/feedback/redaction_tool.cc
@@ -4,6 +4,7 @@
#include "components/feedback/redaction_tool.h"
+#include <set>
#include <utility>
#include <vector>
@@ -14,6 +15,7 @@
#include "base/strings/stringprintf.h"
#include "base/threading/thread_restrictions.h"
#include "build/chromeos_buildflags.h"
+#include "components/feedback/pii_types.h"
#include "net/base/ip_address.h"
#include "third_party/re2/src/re2/re2.h"
@@ -36,7 +38,7 @@ namespace {
// Every matched identifier (in the context of the whole pattern) is redacted
// by replacing it with an incremental instance identifier. Every different
// pattern defines a separate instance identifier space. See the unit test for
-// RedactionTool::RedactCustomPatterns for pattern redaction examples.
+// RedactionToolTest::RedactCustomPatterns for pattern redaction examples.
//
// Useful regular expression syntax:
//
@@ -47,17 +49,19 @@ namespace {
// (?:regex) denotes non-capturing parentheses group.
CustomPatternWithAlias kCustomPatternsWithContext[] = {
// ModemManager
- {"CellID", "(\\bCell ID: ')([0-9a-fA-F]+)(')"},
- {"LocAC", "(\\bLocation area code: ')([0-9a-fA-F]+)(')"},
+ {"CellID", "(\\bCell ID: ')([0-9a-fA-F]+)(')", PIIType::kCellID},
+ {"LocAC", "(\\bLocation area code: ')([0-9a-fA-F]+)(')",
+ PIIType::kLocationAreaCode},
// wpa_supplicant
- {"SSID", "(?i-s)(\\bssid[= ]')(.+)(')"},
- {"SSID", "(?i-s)(\\bssid[= ]\")(.+)(\")"},
- {"SSID", "(\\* SSID=)(.+)($)"},
- {"SSIDHex", "(?-s)(\\bSSID - hexdump\\(len=[0-9]+\\): )(.+)()"},
+ {"SSID", "(?i-s)(\\bssid[= ]')(.+)(')", PIIType::kSSID},
+ {"SSID", "(?i-s)(\\bssid[= ]\")(.+)(\")", PIIType::kSSID},
+ {"SSID", "(\\* SSID=)(.+)($)", PIIType::kSSID},
+ {"SSIDHex", "(?-s)(\\bSSID - hexdump\\(len=[0-9]+\\): )(.+)()",
+ PIIType::kSSID},
// shill
- {"SSID", "(?-s)(\\[SSID=)(.+?)(\\])"},
+ {"SSID", "(?-s)(\\[SSID=)(.+?)(\\])", PIIType::kSSID},
// Serial numbers. The actual serial number itself can include any alphanum
// char as well as dashes, periods, colons, slashes and unprintable ASCII
@@ -66,34 +70,43 @@ CustomPatternWithAlias kCustomPatternsWithContext[] = {
// many other cases that we don't want to redact.
{"Serial",
"(?i-s)(\\bserial\\s*_?(?:number)?['\"]?\\s*[:=|]\\s*['\"]?)"
- "([0-9a-zA-Z\\-.:\\/\\\\\\x00-\\x09\\x0B-\\x1F]+)(\\b)"},
- {"Serial", "( Serial Number )(\\d+)(\\b)"},
+ "([0-9a-zA-Z\\-.:\\/\\\\\\x00-\\x09\\x0B-\\x1F]+)(\\b)",
+ PIIType::kSerial},
+ {"Serial", "( Serial Number )(\\d+)(\\b)", PIIType::kSerial},
+ // The attested device id, a serial number, that comes from vpd_2.0.txt.
+ // The pattern was recently clarified as being a case insensitive string of
+ // ASCII letters and digits, plus the dash/hyphen character. The dash cannot
+ // appear first or last
+ {"Serial", "(\"attested_device_id\"=\")([^-][0-9a-zA-Z-]+[^-])(\")",
+ PIIType::kSerial},
// GAIA IDs
- {"GAIA", R"xxx((\"?\bgaia_id\"?[=:]['\"])(\d+)(\b['\"]))xxx"},
- {"GAIA", R"xxx((\{id: )(\d+)(, email:))xxx"},
+ {"GAIA", R"xxx((\"?\bgaia_id\"?[=:]['\"])(\d+)(\b['\"]))xxx",
+ PIIType::kGaiaID},
+ {"GAIA", R"xxx((\{id: )(\d+)(, email:))xxx", PIIType::kGaiaID},
// UUIDs given by the 'blkid' tool. These don't necessarily look like
// standard UUIDs, so treat them specially.
- {"UUID", R"xxx((UUID=")([0-9a-zA-Z-]+)("))xxx"},
+ {"UUID", R"xxx((UUID=")([0-9a-zA-Z-]+)("))xxx", PIIType::kUUID},
// Also cover UUIDs given by the 'lvs' and 'pvs' tools, which similarly
// don't necessarily look like standard UUIDs.
- {"UUID", R"xxx(("[lp]v_uuid":")([0-9a-zA-Z-]+)("))xxx"},
+ {"UUID", R"xxx(("[lp]v_uuid":")([0-9a-zA-Z-]+)("))xxx", PIIType::kUUID},
// Volume labels presented in the 'blkid' tool, and as part of removable
// media paths shown in various logs such as cros-disks (in syslog).
// There isn't a well-defined format for these. For labels in blkid,
// capture everything between the open and closing quote.
- {"Volume Label", R"xxx((LABEL=")([^"]+)("))xxx"},
+ {"Volume Label", R"xxx((LABEL=")([^"]+)("))xxx", PIIType::kVolumeLabel},
// For paths, this is harder. The only restricted characters are '/' and
// NUL, so use a simple heuristic. cros-disks generally quotes paths using
// single-quotes, so capture everything until a quote character. For lsblk,
// capture everything until the end of the line, since the mount path is the
// last field.
- {"Volume Label", R"xxx((/media/removable/)(.+?)(['"/\n]|$))xxx"},
+ {"Volume Label", R"xxx((/media/removable/)(.+?)(['"/\n]|$))xxx",
+ PIIType::kVolumeLabel},
// IPP (Internet Printing Protocol) Addresses
- {"IPP Address", R"xxx((ipp:\/\/)(.+?)(\/ipp))xxx"},
+ {"IPP Address", R"xxx((ipp:\/\/)(.+?)(\/ipp))xxx", PIIType::kIPPAddress},
};
bool MaybeUnmapAddress(net::IPAddress* addr) {
@@ -237,6 +250,7 @@ std::string MaybeScrubIPAddress(const std::string& addr) {
#define LS32 NCG(H16 ":" H16 "|" IPV4ADDRESS)
#define WB "\\b"
+// clang-format off
#define IPV6ADDRESS NCG( \
WB NCG(H16 ":") "{6}" LS32 WB "|" \
"::" NCG(H16 ":") "{5}" LS32 WB "|" \
@@ -247,6 +261,7 @@ std::string MaybeScrubIPAddress(const std::string& addr) {
OPT_NCG( WB NCG(H16 ":") "{0,4}" H16) "::" LS32 WB "|" \
OPT_NCG( WB NCG(H16 ":") "{0,5}" H16) "::" H16 WB "|" \
OPT_NCG( WB NCG(H16 ":") "{0,6}" H16) "::")
+// clang-format on
#define IPVFUTURE \
"v" HEXDIG \
@@ -360,18 +375,19 @@ std::string MaybeScrubIPAddress(const std::string& addr) {
// The |kCustomPatternWithoutContext| array defines further patterns to match
// and redact. Each pattern consists of a single capturing group.
CustomPatternWithAlias kCustomPatternsWithoutContext[] = {
- {"URL", "(?i)(" IRI ")"},
+ {"URL", "(?i)(" IRI ")", PIIType::kURL},
// Email Addresses need to come after URLs because they can be part
// of a query parameter.
- {"email", "(?i)([0-9a-z._%+-]+@[a-z0-9.-]+\\.[a-z]{2,6})"},
+ {"email", "(?i)([0-9a-z._%+-]+@[a-z0-9.-]+\\.[a-z]{2,6})", PIIType::kEmail},
// IP filter rules need to come after URLs so that they don't disturb the
// URL pattern in case the IP address is part of a URL.
- {"IPv4", "(?i)(" IPV4ADDRESS ")"},
- {"IPv6", "(?i)(" IPV6ADDRESS ")"},
+ {"IPv4", "(?i)(" IPV4ADDRESS ")", PIIType::kIPAddress},
+ {"IPv6", "(?i)(" IPV6ADDRESS ")", PIIType::kIPAddress},
// Universal Unique Identifiers (UUIDs).
{"UUID",
"(?i)([0-9a-zA-Z]{8}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{4}-"
- "[0-9a-zA-Z]{12})"},
+ "[0-9a-zA-Z]{12})",
+ PIIType::kUUID},
};
// Like RE2's FindAndConsume, searches for the first occurrence of |pattern| in
@@ -396,8 +412,9 @@ bool FindAndConsumeAndGetSkippedN(re2::StringPiece* input,
re2::RE2::Arg a0(argc > 0 ? args[0] : nullptr);
re2::RE2::Arg a1(argc > 1 ? args[1] : nullptr);
re2::RE2::Arg a2(argc > 2 ? args[2] : nullptr);
- const re2::RE2::Arg* const wrapped_args[] = {&a0, &a1, &a2};
- CHECK_LE(argc, 3);
+ re2::RE2::Arg a3(argc > 3 ? args[3] : nullptr);
+ const re2::RE2::Arg* const wrapped_args[] = {&a0, &a1, &a2, &a3};
+ CHECK_LE(argc, 4);
bool result = re2::RE2::FindAndConsumeN(input, pattern, wrapped_args, argc);
@@ -441,16 +458,57 @@ RedactionTool::~RedactionTool() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
-std::string RedactionTool::Redact(const std::string& input) {
+std::map<PIIType, std::set<std::string>> RedactionTool::Detect(
+ const std::string& input) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
base::AssertLongCPUWorkAllowed();
- std::string redacted = RedactMACAddresses(input);
- redacted = RedactAndroidAppStoragePaths(std::move(redacted));
- redacted = RedactCustomPatterns(std::move(redacted));
+ std::map<PIIType, std::set<std::string>> detected;
+
+ RedactMACAddresses(input, &detected);
+ // This function will add to |detected| only on Chrome OS as Android app
+ // storage paths are only detected for Chrome OS.
+ RedactAndroidAppStoragePaths(input, &detected);
+ DetectWithCustomPatterns(input, &detected);
// Do hashes last since they may appear in URLs and they also prevent us from
// properly recognizing the Android storage paths.
- redacted = RedactHashes(std::move(redacted));
+ RedactHashes(input, &detected);
+ return detected;
+}
+
+std::string RedactionTool::Redact(const std::string& input) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ return RedactAndKeepSelected(input, /*pii_types_to_keep=*/{});
+}
+
+std::string RedactionTool::RedactAndKeepSelected(
+ const std::string& input,
+ const std::set<PIIType>& pii_types_to_keep) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ base::AssertLongCPUWorkAllowed();
+
+ // Copy |input| so we can modify it.
+ std::string redacted = input;
+
+ if (pii_types_to_keep.find(PIIType::kMACAddress) == pii_types_to_keep.end()) {
+ redacted = RedactMACAddresses(std::move(redacted), nullptr);
+ }
+ if (pii_types_to_keep.find(PIIType::kAndroidAppStoragePath) ==
+ pii_types_to_keep.end()) {
+ redacted = RedactAndroidAppStoragePaths(std::move(redacted), nullptr);
+ }
+
+ redacted = RedactAndKeepSelectedCustomPatterns(std::move(redacted),
+ pii_types_to_keep);
+
+ // Do hashes last since they may appear in URLs and they also prevent us
+ // from properly recognizing the Android storage paths.
+ if (pii_types_to_keep.find(PIIType::kHash) == pii_types_to_keep.end()) {
+ // URLs and Android storage paths will be partially redacted (only hashes)
+ // if |pii_types_to_keep| contains PIIType::kURL or
+ // PIIType::kAndroidAppStoragePath and not PIIType::kHash.
+ redacted = RedactHashes(std::move(redacted), nullptr);
+ }
return redacted;
}
@@ -468,7 +526,9 @@ RE2* RedactionTool::GetRegExp(const std::string& pattern) {
return regexp_cache_[pattern].get();
}
-std::string RedactionTool::RedactMACAddresses(const std::string& input) {
+std::string RedactionTool::RedactMACAddresses(
+ const std::string& input,
+ std::map<PIIType, std::set<std::string>>* detected) {
// This regular expression finds the next MAC address. It splits the data into
// an OUI (Organizationally Unique Identifier) part and a NIC (Network
// Interface Controller) specific part. We also match on dash and underscore
@@ -506,7 +566,9 @@ std::string RedactionTool::RedactMACAddresses(const std::string& input) {
oui_string.c_str(), mac_id);
mac_addresses_[mac] = replacement_mac;
}
-
+ if (detected != nullptr) {
+ (*detected)[PIIType::kMACAddress].insert(mac);
+ }
skipped.AppendToString(&result);
result += replacement_mac;
}
@@ -515,7 +577,9 @@ std::string RedactionTool::RedactMACAddresses(const std::string& input) {
return result;
}
-std::string RedactionTool::RedactHashes(const std::string& input) {
+std::string RedactionTool::RedactHashes(
+ const std::string& input,
+ std::map<PIIType, std::set<std::string>>* detected) {
// This will match hexadecimal strings from length 32 to 64 that have a word
// boundary at each end. We then check to make sure they are one of our valid
// hash lengths before replacing.
@@ -559,6 +623,9 @@ std::string RedactionTool::RedactHashes(const std::string& input) {
"<HASH:%s %zd>", hash_prefix_string.c_str(), hashes_.size());
hashes_[hash] = replacement_hash;
}
+ if (detected != nullptr) {
+ (*detected)[PIIType::kHash].insert(hash);
+ }
result += replacement_hash;
}
@@ -568,7 +635,8 @@ std::string RedactionTool::RedactHashes(const std::string& input) {
}
std::string RedactionTool::RedactAndroidAppStoragePaths(
- const std::string& input) {
+ const std::string& input,
+ std::map<PIIType, std::set<std::string>>* detected) {
// We only use this on Chrome OS and there's differences in the API for
// FilePath on Windows which prevents this from compiling, so only enable this
// code for Chrome OS.
@@ -576,20 +644,28 @@ std::string RedactionTool::RedactAndroidAppStoragePaths(
std::string result;
result.reserve(input.size());
- // This is for redacting 'android_app_storage' output. When the path starts
- // either /home/root/<hash>/data/data/<package_name>/ or
- // /home/root/<hash>/data/user_de/<number>/<package_name>/, this function will
- // redact path components following <package_name>/.
+ // This is for redacting Android data paths included in 'android_app_storage'
+ // and 'audit_log' output. <app_specific_path> in the following data paths
+ // will be redacted.
+ // - /data/data/<package_name>/<app_specific_path>
+ // - /data/app/<package_name>/<app_specific_path>
+ // - /data/user_de/<number>/<package_name>/<app_specific_path>
+ // These data paths are preceded by "/home/root/<user_hash>/android-data" in
+ // 'android_app_storage' output, and preceded by "path=" or "exe=" in
+ // 'audit_log' output.
RE2* path_re = GetRegExp(
- "(?m)(\\t/home/root/[\\da-f]+/android-data/data/"
- "(data|user_de/\\d+)/[^/\\n]+)("
- "/[^\\n]+)");
+ R"((?m)((path=|exe=|/home/root/[\da-f]+/android-data))"
+ R"(/data/(data|app|user_de/\d+)/[^/\n]+)(/[^\n\s]+))");
// Keep consuming, building up a result string as we go.
re2::StringPiece text(input);
- re2::StringPiece skipped, path_prefix, ignored, app_specific;
+ re2::StringPiece skipped;
+ re2::StringPiece path_prefix; // path before app_specific;
+ re2::StringPiece pre_data; // (path=|exe=|/home/root/<hash>/android-data)
+ re2::StringPiece post_data; // (data|app|user_de/\d+)
+ re2::StringPiece app_specific; // (/[^\n\s]+)
while (FindAndConsumeAndGetSkipped(&text, *path_re, &skipped, &path_prefix,
- &ignored, &app_specific)) {
+ &pre_data, &post_data, &app_specific)) {
// We can record these parts as-is.
skipped.AppendToString(&result);
path_prefix.AppendToString(&result);
@@ -601,8 +677,7 @@ std::string RedactionTool::RedactAndroidAppStoragePaths(
// one.
// - If the original component has 2 or more bytes, add '_'.
const base::FilePath path(app_specific.as_string());
- std::vector<std::string> components;
- path.GetComponents(&components);
+ std::vector<std::string> components = path.GetComponents();
DCHECK(!components.empty());
auto it = components.begin() + 1; // ignore the leading slash
@@ -614,6 +689,10 @@ std::string RedactionTool::RedactAndroidAppStoragePaths(
if (component.length() > 1)
result += '_';
}
+ if (detected != nullptr) {
+ (*detected)[PIIType::kAndroidAppStoragePath].insert(
+ app_specific.as_string());
+ }
}
text.AppendToString(&result);
@@ -623,21 +702,37 @@ std::string RedactionTool::RedactAndroidAppStoragePaths(
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
}
-std::string RedactionTool::RedactCustomPatterns(std::string input) {
- for (size_t i = 0; i < base::size(kCustomPatternsWithContext); i++) {
- input =
- RedactCustomPatternWithContext(input, kCustomPatternsWithContext[i]);
+std::string RedactionTool::RedactAndKeepSelectedCustomPatterns(
+ std::string input,
+ const std::set<PIIType>& pii_types_to_keep) {
+ for (const auto& pattern : kCustomPatternsWithContext) {
+ if (pii_types_to_keep.find(pattern.pii_type) == pii_types_to_keep.end()) {
+ input = RedactCustomPatternWithContext(input, pattern, nullptr);
+ }
}
- for (size_t i = 0; i < base::size(kCustomPatternsWithoutContext); i++) {
- input = RedactCustomPatternWithoutContext(input,
- kCustomPatternsWithoutContext[i]);
+ for (const auto& pattern : kCustomPatternsWithoutContext) {
+ if (pii_types_to_keep.find(pattern.pii_type) == pii_types_to_keep.end()) {
+ input = RedactCustomPatternWithoutContext(input, pattern, nullptr);
+ }
}
return input;
}
+void RedactionTool::DetectWithCustomPatterns(
+ std::string input,
+ std::map<PIIType, std::set<std::string>>* detected) {
+ for (const auto& pattern : kCustomPatternsWithContext) {
+ RedactCustomPatternWithContext(input, pattern, detected);
+ }
+ for (const auto& pattern : kCustomPatternsWithoutContext) {
+ RedactCustomPatternWithoutContext(input, pattern, detected);
+ }
+}
+
std::string RedactionTool::RedactCustomPatternWithContext(
const std::string& input,
- const CustomPatternWithAlias& pattern) {
+ const CustomPatternWithAlias& pattern,
+ std::map<PIIType, std::set<std::string>>* detected) {
RE2* re = GetRegExp(pattern.pattern);
DCHECK_EQ(3, re->NumberOfCapturingGroups());
std::map<std::string, std::string>* identifier_space =
@@ -664,7 +759,9 @@ std::string RedactionTool::RedactCustomPatternWithContext(
} else {
replacement_id = (*identifier_space)[matched_id_as_string];
}
-
+ if (detected != nullptr) {
+ (*detected)[pattern.pii_type].insert(matched_id_as_string);
+ }
skipped.AppendToString(&result);
pre_matched_id.AppendToString(&result);
result += replacement_id;
@@ -682,6 +779,11 @@ bool IsUrlExempt(re2::StringPiece url,
if (url.contains("?"))
return false;
+ // Last part of an SELinux context is misdetected as a URL.
+ // e.g. "u:object_r:system_data_file:s0:c512,c768"
+ if (url.starts_with("file:s0"))
+ return true;
+
// Check for chrome:// URLs that are exempt.
if (url.starts_with("chrome://")) {
// We allow everything in chrome://resources/.
@@ -720,7 +822,8 @@ bool IsUrlExempt(re2::StringPiece url,
std::string RedactionTool::RedactCustomPatternWithoutContext(
const std::string& input,
- const CustomPatternWithAlias& pattern) {
+ const CustomPatternWithAlias& pattern,
+ std::map<PIIType, std::set<std::string>>* detected) {
RE2* re = GetRegExp(pattern.pattern);
DCHECK_EQ(1, re->NumberOfCapturingGroups());
@@ -761,9 +864,15 @@ std::string RedactionTool::RedactCustomPatternWithoutContext(
replacement_id.empty() ? pattern.alias : replacement_id.c_str(),
base::NumberToString(identifier_space->size() + 1).c_str());
(*identifier_space)[matched_id_as_string] = replacement_id;
+ if (detected != nullptr) {
+ (*detected)[pattern.pii_type].insert(matched_id_as_string);
+ }
}
} else {
replacement_id = (*identifier_space)[matched_id_as_string];
+ if (detected != nullptr) {
+ (*detected)[pattern.pii_type].insert(matched_id_as_string);
+ }
}
skipped.AppendToString(&result);
diff --git a/chromium/components/feedback/redaction_tool.h b/chromium/components/feedback/redaction_tool.h
index b144c1af795..6ddc4cc3caf 100644
--- a/chromium/components/feedback/redaction_tool.h
+++ b/chromium/components/feedback/redaction_tool.h
@@ -7,12 +7,14 @@
#include <map>
#include <memory>
+#include <set>
#include <string>
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/sequence_checker.h"
#include "base/task/sequenced_task_runner.h"
+#include "components/feedback/pii_types.h"
namespace re2 {
class RE2;
@@ -27,6 +29,8 @@ struct CustomPatternWithAlias {
// A RE2 regexp used in the replacing logic. Matches will be replaced by the
// alias reference described above.
const char* pattern;
+ // PII category of the data that will be detected using this pattern.
+ PIIType pii_type;
};
// Formerly known as AnonymizerTool, RedactionTool provides functions for
@@ -46,27 +50,73 @@ class RedactionTool {
explicit RedactionTool(const char* const* first_party_extension_ids);
~RedactionTool();
+ // Return a map of [PII-sensitive data type -> set of data] that are detected
+ // in |input|.
+ std::map<PIIType, std::set<std::string>> Detect(const std::string& input);
+
// Returns an redacted version of |input|. PII-sensitive data (such as MAC
// addresses) in |input| is replaced with unique identifiers.
// This is an expensive operation. Make sure not to execute this on the UI
// thread.
std::string Redact(const std::string& input);
+ // Attempts to redact PII sensitive data from |input| except the data that
+ // fits in one of the PII types in |pii_types_to_keep| and returns the
+ // redacted version.
+ // Note that URLs and Android storage paths may contain hashes. URLs and
+ // Android storage paths will be partially redacted (only hashes) if
+ // |pii_types_to_keep| contains PIIType::kURL or
+ // PIIType::kAndroidAppStoragePath and not PIIType::kHash.
+ std::string RedactAndKeepSelected(const std::string& input,
+ const std::set<PIIType>& pii_types_to_keep);
+
private:
friend class RedactionToolTest;
re2::RE2* GetRegExp(const std::string& pattern);
- std::string RedactMACAddresses(const std::string& input);
- std::string RedactAndroidAppStoragePaths(const std::string& input);
- std::string RedactHashes(const std::string& input);
- std::string RedactCustomPatterns(std::string input);
+ // Redacts MAC addresses from |input| and returns the redacted string. Adds
+ // the redacted MAC addresses to |detected| if |detected| is not nullptr.
+ std::string RedactMACAddresses(
+ const std::string& input,
+ std::map<PIIType, std::set<std::string>>* detected);
+ // Redacts Android app storage paths from |input| and returns the redacted
+ // string. Adds the redacted app storage paths to |detected| if |detected| is
+ // not nullptr. This function returns meaningpul output only on Chrome OS.
+ std::string RedactAndroidAppStoragePaths(
+ const std::string& input,
+ std::map<PIIType, std::set<std::string>>* detected);
+ // Redacts hashes from |input| and returns the redacted string. Adds the
+ // redacted hashes to |detected| if |detected| is not nullptr.
+ std::string RedactHashes(const std::string& input,
+ std::map<PIIType, std::set<std::string>>* detected);
+
+ // Redacts PII sensitive data that matches |pattern| from |input| and returns
+ // the redacted string. Keeps the PII data that belongs to PII type in
+ // |pii_types_to_keep| in the returned string.
+ std::string RedactAndKeepSelectedCustomPatterns(
+ std::string input,
+ const std::set<PIIType>& pii_types_to_keep);
+
+ // Detects PII sensitive data in |input| using custom patterns. Adds the
+ // detected PII sensitive data to corresponding PII type key in |detected|.
+ void DetectWithCustomPatterns(
+ std::string input,
+ std::map<PIIType, std::set<std::string>>* detected);
+ // Redacts PII sensitive data that matches |pattern| from |input| and returns
+ // the redacted string. Adds the redacted PII sensitive data to |detected| if
+ // |detected| is not nullptr.
std::string RedactCustomPatternWithContext(
const std::string& input,
- const CustomPatternWithAlias& pattern);
+ const CustomPatternWithAlias& pattern,
+ std::map<PIIType, std::set<std::string>>* detected);
+ // Redacts PII sensitive data that matches |pattern| from |input| and returns
+ // the redacted string. Adds the redacted PII sensitive data to |detected| if
+ // |detected| is not nullptr.
std::string RedactCustomPatternWithoutContext(
const std::string& input,
- const CustomPatternWithAlias& pattern);
+ const CustomPatternWithAlias& pattern,
+ std::map<PIIType, std::set<std::string>>* detected);
// Null-terminated list of first party extension IDs. We need to have this
// passed into us because we can't refer to the code where these are defined.
diff --git a/chromium/components/feedback/redaction_tool_unittest.cc b/chromium/components/feedback/redaction_tool_unittest.cc
index eacb2641c30..0c8a7475b8f 100644
--- a/chromium/components/feedback/redaction_tool_unittest.cc
+++ b/chromium/components/feedback/redaction_tool_unittest.cc
@@ -5,43 +5,225 @@
#include "components/feedback/redaction_tool.h"
#include <gtest/gtest.h>
+#include <set>
+#include <utility>
#include "base/strings/string_util.h"
#include "build/chromeos_buildflags.h"
+#include "components/feedback/pii_types.h"
namespace feedback {
const char kFakeFirstPartyID[] = "nkoccljplnhpfnfiajclkommnmllphnl";
const char* const kFakeFirstPartyExtensionIDs[] = {kFakeFirstPartyID, nullptr};
+struct StringWithRedaction {
+ // The raw version of the string before redaction. May contain PII sensitive
+ // data.
+ std::string pre_redaction;
+ // The string that's redacted of PII sensitive data.
+ std::string post_redaction;
+ // The PII type that string contains. PIIType::kNone if the string doesn't
+ // contain any PII sensitive data.
+ PIIType pii_type;
+};
+
+// For better readability, put all the pre/post redaction strings in an array of
+// StringWithRedaction struct, and then convert that to two strings which become
+// the input and output of the redactor.
+const StringWithRedaction kStringsWithRedactions[] = {
+ {"aaaaaaaa [SSID=123aaaaaa]aaaaa", // SSID.
+ "aaaaaaaa [SSID=<SSID: 1>]aaaaa", PIIType::kSSID},
+ {"aaaaaaaahttp://tets.comaaaaaaa", // URL.
+ "aaaaaaaa<URL: 1>", PIIType::kURL},
+ {"u:object_r:system_data_file:s0:c512,c768", // No PII, it is an SELinux context.
+ "u:object_r:system_data_file:s0:c512,c768", PIIType::kNone},
+ {"aaaaaemail@example.comaaa", // Email address.
+ "<email: 1>", PIIType::kEmail},
+ {"example@@1234", // No PII, it is not a valid email address.
+ "example@@1234", PIIType::kNone},
+ {"255.255.155.2", // IP address.
+ "<IPv4: 1>", PIIType::kIPAddress},
+ {"255.255.155.255", // IP address.
+ "<IPv4: 2>", PIIType::kIPAddress},
+ {"127.0.0.1", // IPv4 loopback.
+ "<127.0.0.0/8: 3>", PIIType::kIPAddress},
+ {"127.255.0.1", // IPv4 loopback.
+ "<127.0.0.0/8: 4>", PIIType::kIPAddress},
+ {"0.0.0.0", // Any IPv4.
+ "<0.0.0.0/8: 5>", PIIType::kIPAddress},
+ {"0.255.255.255", // Any IPv4.
+ "<0.0.0.0/8: 6>", PIIType::kIPAddress},
+ {"10.10.10.100", // IPv4 private class A.
+ "<10.0.0.0/8: 7>", PIIType::kIPAddress},
+ {"10.10.10.100", // Intentional duplicate.
+ "<10.0.0.0/8: 7>", PIIType::kIPAddress},
+ {"10.10.10.101", // IPv4 private class A.
+ "<10.0.0.0/8: 8>", PIIType::kIPAddress},
+ {"10.255.255.255", // IPv4 private class A.
+ "<10.0.0.0/8: 9>", PIIType::kIPAddress},
+ {"172.16.0.0", // IPv4 private class B.
+ "<172.16.0.0/12: 10>", PIIType::kIPAddress},
+ {"172.31.255.255", // IPv4 private class B.
+ "<172.16.0.0/12: 11>", PIIType::kIPAddress},
+ {"172.11.5.5", // IP address.
+ "<IPv4: 12>", PIIType::kIPAddress},
+ {"172.111.5.5", // IP address.
+ "<IPv4: 13>", PIIType::kIPAddress},
+ {"192.168.0.0", // IPv4 private class C.
+ "<192.168.0.0/16: 14>", PIIType::kIPAddress},
+ {"192.168.255.255", // IPv4 private class C.
+ "<192.168.0.0/16: 15>", PIIType::kIPAddress},
+ {"192.169.2.120", // IP address.
+ "<IPv4: 16>", PIIType::kIPAddress},
+ {"169.254.0.1", // Link local.
+ "<169.254.0.0/16: 17>", PIIType::kIPAddress},
+ {"169.200.0.1", // IP address.
+ "<IPv4: 18>", PIIType::kIPAddress},
+ {"fe80::", // Link local.
+ "<fe80::/10: 1>", PIIType::kIPAddress},
+ {"fe80::ffff", // Link local.
+ "<fe80::/10: 2>", PIIType::kIPAddress},
+ {"febf:ffff::ffff", // Link local.
+ "<fe80::/10: 3>", PIIType::kIPAddress},
+ {"fecc::1111", // IP address.
+ "<IPv6: 4>", PIIType::kIPAddress},
+ {"224.0.0.24", // Multicast.
+ "<224.0.0.0/4: 19>", PIIType::kIPAddress},
+ {"240.0.0.0", // IP address.
+ "<IPv4: 20>", PIIType::kIPAddress},
+ {"255.255.255.255", // Broadcast.
+ "255.255.255.255", PIIType::kNone},
+ {"100.115.92.92", // ChromeOS.
+ "100.115.92.92", PIIType::kNone},
+ {"100.115.91.92", // IP address.
+ "<IPv4: 21>", PIIType::kIPAddress},
+ {"1.1.1.1", // DNS
+ "1.1.1.1", PIIType::kNone},
+ {"8.8.8.8", // DNS
+ "8.8.8.8", PIIType::kNone},
+ {"8.8.4.4", // DNS
+ "8.8.4.4", PIIType::kNone},
+ {"8.8.8.4", // IP address.
+ "<IPv4: 22>", PIIType::kIPAddress},
+ {"255.255.259.255", // Not an IP address.
+ "255.255.259.255", PIIType::kNone},
+ {"255.300.255.255", // Not an IP address.
+ "255.300.255.255", PIIType::kNone},
+ {"3-1.2.3.4", // USB path, not an IP address.
+ "3-1.2.3.4", PIIType::kNone},
+ {"aaaa123.123.45.4aaa", // IP address.
+ "aaaa<IPv4: 23>aaa", PIIType::kIPAddress},
+ {"11:11;11::11", // IP address.
+ "11:11;<IPv6: 5>", PIIType::kIPAddress},
+ {"11::11", // IP address.
+ "<IPv6: 5>", PIIType::kIPAddress},
+ {"11:11:abcdef:0:0:0:0:0", // No PII.
+ "11:11:abcdef:0:0:0:0:0", PIIType::kNone},
+ {"::", // Unspecified.
+ "::", PIIType::kNone},
+ {"::1", // Local host.
+ "::1", PIIType::kNone},
+ {"Instance::Set", // Ignore match, no PII.
+ "Instance::Set", PIIType::kNone},
+ {"Instant::ff", // Ignore match, no PII.
+ "Instant::ff", PIIType::kNone},
+ {"net::ERR_CONN_TIMEOUT", // Ignore match, no PII.
+ "net::ERR_CONN_TIMEOUT", PIIType::kNone},
+ {"ff01::1", // All nodes address (interface local).
+ "ff01::1", PIIType::kNone},
+ {"ff01::2", // All routers (interface local).
+ "ff01::2", PIIType::kNone},
+ {"ff01::3", // Multicast (interface local).
+ "<ff01::/16: 6>", PIIType::kIPAddress},
+ {"ff02::1", // All nodes address (link local).
+ "ff02::1", PIIType::kNone},
+ {"ff02::2", // All routers (link local).
+ "ff02::2", PIIType::kNone},
+ {"ff02::3", // Multicast (link local).
+ "<ff02::/16: 7>", PIIType::kIPAddress},
+ {"ff02::fb", // mDNSv6 (link local).
+ "<ff02::/16: 8>", PIIType::kIPAddress},
+ {"ff08::fb", // mDNSv6.
+ "<IPv6: 9>", PIIType::kIPAddress},
+ {"ff0f::101", // All NTP servers.
+ "<IPv6: 10>", PIIType::kIPAddress},
+ {"::ffff:cb0c:10ea", // IPv4-mapped IPV6 (IP address).
+ "<IPv6: 11>", PIIType::kIPAddress},
+ {"::ffff:a0a:a0a", // IPv4-mapped IPV6 (private class A).
+ "<M 10.0.0.0/8: 12>", PIIType::kIPAddress},
+ {"::ffff:a0a:a0a", // Intentional duplicate.
+ "<M 10.0.0.0/8: 12>", PIIType::kIPAddress},
+ {"::ffff:ac1e:1e1e", // IPv4-mapped IPV6 (private class B).
+ "<M 172.16.0.0/12: 13>", PIIType::kIPAddress},
+ {"::ffff:c0a8:640a", // IPv4-mapped IPV6 (private class C).
+ "<M 192.168.0.0/16: 14>", PIIType::kIPAddress},
+ {"::ffff:6473:5c01", // IPv4-mapped IPV6 (Chrome).
+ "<M 100.115.92.1: 15>", PIIType::kIPAddress},
+ {"64:ff9b::a0a:a0a", // IPv4-translated 6to4 IPV6 (private class A).
+ "<T 10.0.0.0/8: 16>", PIIType::kIPAddress},
+ {"64:ff9b::6473:5c01", // IPv4-translated 6to4 IPV6 (Chrome).
+ "<T 100.115.92.1: 17>", PIIType::kIPAddress},
+ {"::0101:ffff:c0a8:640a", // IP address.
+ "<IPv6: 18>", PIIType::kIPAddress},
+ {"aa:aa:aa:aa:aa:aa", // MAC address (BSSID).
+ "[MAC OUI=aa:aa:aa IFACE=1]", PIIType::kMACAddress},
+ {"chrome://resources/foo", // Secure chrome resource, exempt.
+ "chrome://resources/foo", PIIType::kNone},
+ {"chrome://settings/crisper.js", // Exempt settings URLs.
+ "chrome://settings/crisper.js", PIIType::kNone},
+ // Exempt first party extension.
+ {"chrome-extension://nkoccljplnhpfnfiajclkommnmllphnl/foobar.js",
+ "chrome-extension://nkoccljplnhpfnfiajclkommnmllphnl/foobar.js",
+ PIIType::kNone},
+ {"chrome://resources/f?user=bar", // Potentially PII in parameter.
+ "<URL: 2>", PIIType::kURL},
+ {"chrome-extension://nkoccljplnhpfnfiajclkommnmllphnl/foobar.js?bar=x",
+ "<URL: 3>", PIIType::kURL}, // Potentially PII in parameter.
+ {"/root/27540283740a0897ab7c8de0f809add2bacde78f/foo",
+ "/root/<HASH:2754 1>/foo", PIIType::kHash}, // Hash string.
+#if BUILDFLAG(IS_CHROMEOS_ASH) // We only redact Android paths on Chrome OS.
+ // Allowed android storage path.
+ {"112K\t/home/root/deadbeef1234/android-data/data/system_de",
+ "112K\t/home/root/deadbeef1234/android-data/data/system_de",
+ PIIType::kNone},
+ // Redacted app-specific storage path.
+ {"8.0K\t/home/root/deadbeef1234/android-data/data/data/pa.ckage2/de",
+ "8.0K\t/home/root/deadbeef1234/android-data/data/data/pa.ckage2/d_",
+ PIIType::kAndroidAppStoragePath},
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
+};
+
class RedactionToolTest : public testing::Test {
protected:
std::string RedactMACAddresses(const std::string& input) {
- return redactor_.RedactMACAddresses(input);
+ return redactor_.RedactMACAddresses(input, nullptr);
}
std::string RedactHashes(const std::string& input) {
- return redactor_.RedactHashes(input);
+ return redactor_.RedactHashes(input, nullptr);
}
std::string RedactAndroidAppStoragePaths(const std::string& input) {
- return redactor_.RedactAndroidAppStoragePaths(input);
+ return redactor_.RedactAndroidAppStoragePaths(input, nullptr);
}
std::string RedactCustomPatterns(const std::string& input) {
- return redactor_.RedactCustomPatterns(input);
+ return redactor_.RedactAndKeepSelectedCustomPatterns(
+ input,
+ /*pii_types_to_keep=*/{});
}
std::string RedactCustomPatternWithContext(
const std::string& input,
const CustomPatternWithAlias& pattern) {
- return redactor_.RedactCustomPatternWithContext(input, pattern);
+ return redactor_.RedactCustomPatternWithContext(input, pattern, nullptr);
}
std::string RedactCustomPatternWithoutContext(
const std::string& input,
const CustomPatternWithAlias& pattern) {
- return redactor_.RedactCustomPatternWithoutContext(input, pattern);
+ return redactor_.RedactCustomPatternWithoutContext(input, pattern, nullptr);
}
RedactionTool redactor_{kFakeFirstPartyExtensionIDs};
@@ -206,6 +388,16 @@ TEST_F(RedactionToolTest, RedactCustomPatterns) {
RedactCustomPatterns("serial |0x1cc04417"));
EXPECT_EQ("serial|<Serial: 10>", RedactCustomPatterns("serial|0x1cc04418"));
EXPECT_EQ("serial|<Serial: 11>", RedactCustomPatterns("serial|agnagna"));
+ // redact attested device id that is also a serial number
+ EXPECT_EQ("\"attested_device_id\"=\"<Serial: 12>\"",
+ RedactCustomPatterns("\"attested_device_id\"=\"5CD045B0DZ\""));
+ EXPECT_EQ("\"attested_device_id\"=\"<Serial: 13>\"",
+ RedactCustomPatterns("\"attested_device_id\"=\"5CD04-5B0DZ\""));
+ // The dash cannot appear first or last.
+ EXPECT_EQ("\"attested_device_id\"=\"-5CD045B0DZ\"",
+ RedactCustomPatterns("\"attested_device_id\"=\"-5CD045B0DZ\""));
+ EXPECT_EQ("\"attested_device_id\"=\"5CD045B0DZ-\"",
+ RedactCustomPatterns("\"attested_device_id\"=\"5CD045B0DZ-\""));
EXPECT_EQ("\"gaia_id\":\"<GAIA: 1>\"",
RedactCustomPatterns("\"gaia_id\":\"1234567890\""));
@@ -273,9 +465,14 @@ TEST_F(RedactionToolTest, RedactCustomPatterns) {
}
TEST_F(RedactionToolTest, RedactCustomPatternWithContext) {
- const CustomPatternWithAlias kPattern1 = {"ID", "(\\b(?i)id:? ')(\\d+)(')"};
- const CustomPatternWithAlias kPattern2 = {"ID", "(\\b(?i)id=')(\\d+)(')"};
- const CustomPatternWithAlias kPattern3 = {"IDG", "(\\b(?i)idg=')(\\d+)(')"};
+ // The PIIType for the CustomPatternWithAlias is not relevant, only for
+ // testing.
+ const CustomPatternWithAlias kPattern1 = {"ID", "(\\b(?i)id:? ')(\\d+)(')",
+ PIIType::kUUID};
+ const CustomPatternWithAlias kPattern2 = {"ID", "(\\b(?i)id=')(\\d+)(')",
+ PIIType::kUUID};
+ const CustomPatternWithAlias kPattern3 = {"IDG", "(\\b(?i)idg=')(\\d+)(')",
+ PIIType::kCellID};
EXPECT_EQ("", RedactCustomPatternWithContext("", kPattern1));
EXPECT_EQ("foo\nbar\n",
RedactCustomPatternWithContext("foo\nbar\n", kPattern1));
@@ -301,180 +498,165 @@ TEST_F(RedactionToolTest, RedactCustomPatternWithContext) {
}
TEST_F(RedactionToolTest, RedactCustomPatternWithoutContext) {
- CustomPatternWithAlias kPattern = {"pattern", "(o+)"};
+ // The PIIType for the CustomPatternWithAlias here is not relevant, only for
+ // testing.
+ CustomPatternWithAlias kPattern = {"pattern", "(o+)", PIIType::kEmail};
EXPECT_EQ("", RedactCustomPatternWithoutContext("", kPattern));
EXPECT_EQ("f<pattern: 1>\nf<pattern: 2>z\nf<pattern: 1>l\n",
RedactCustomPatternWithoutContext("fo\nfooz\nfol\n", kPattern));
}
TEST_F(RedactionToolTest, RedactChunk) {
- // For better readability, put all the pre/post redaction strings in an array
- // of pairs, and then convert that to two strings which become the input and
- // output of the redactor.
- std::pair<std::string, std::string> data[] = {
- {"aaaaaaaa [SSID=123aaaaaa]aaaaa", // SSID.
- "aaaaaaaa [SSID=<SSID: 1>]aaaaa"},
- {"aaaaaaaahttp://tets.comaaaaaaa", // URL.
- "aaaaaaaa<URL: 1>"},
- {"aaaaaemail@example.comaaa", // Email address.
- "<email: 1>"},
- {"example@@1234", // No PII, it is not invalid email address.
- "example@@1234"},
- {"255.255.155.2", // IP address.
- "<IPv4: 1>"},
- {"255.255.155.255", // IP address.
- "<IPv4: 2>"},
- {"127.0.0.1", // IPv4 loopback.
- "<127.0.0.0/8: 3>"},
- {"127.255.0.1", // IPv4 loopback.
- "<127.0.0.0/8: 4>"},
- {"0.0.0.0", // Any IPv4.
- "<0.0.0.0/8: 5>"},
- {"0.255.255.255", // Any IPv4.
- "<0.0.0.0/8: 6>"},
- {"10.10.10.100", // IPv4 private class A.
- "<10.0.0.0/8: 7>"},
- {"10.10.10.100", // Intentional duplicate.
- "<10.0.0.0/8: 7>"},
- {"10.10.10.101", // IPv4 private class A.
- "<10.0.0.0/8: 8>"},
- {"10.255.255.255", // IPv4 private class A.
- "<10.0.0.0/8: 9>"},
- {"172.16.0.0", // IPv4 private class B.
- "<172.16.0.0/12: 10>"},
- {"172.31.255.255", // IPv4 private class B.
- "<172.16.0.0/12: 11>"},
- {"172.11.5.5", // IP address.
- "<IPv4: 12>"},
- {"172.111.5.5", // IP address.
- "<IPv4: 13>"},
- {"192.168.0.0", // IPv4 private class C.
- "<192.168.0.0/16: 14>"},
- {"192.168.255.255", // IPv4 private class C.
- "<192.168.0.0/16: 15>"},
- {"192.169.2.120", // IP address.
- "<IPv4: 16>"},
- {"169.254.0.1", // Link local.
- "<169.254.0.0/16: 17>"},
- {"169.200.0.1", // IP address.
- "<IPv4: 18>"},
- {"fe80::", // Link local.
- "<fe80::/10: 1>"},
- {"fe80::ffff", // Link local.
- "<fe80::/10: 2>"},
- {"febf:ffff::ffff", // Link local.
- "<fe80::/10: 3>"},
- {"fecc::1111", // IP address.
- "<IPv6: 4>"},
- {"224.0.0.24", // Multicast.
- "<224.0.0.0/4: 19>"},
- {"240.0.0.0", // IP address.
- "<IPv4: 20>"},
- {"255.255.255.255", // Broadcast.
- "255.255.255.255"},
- {"100.115.92.92", // ChromeOS.
- "100.115.92.92"},
- {"100.115.91.92", // IP address.
- "<IPv4: 21>"},
- {"1.1.1.1", // DNS
- "1.1.1.1"},
- {"8.8.8.8", // DNS
- "8.8.8.8"},
- {"8.8.4.4", // DNS
- "8.8.4.4"},
- {"8.8.8.4", // IP address.
- "<IPv4: 22>"},
- {"255.255.259.255", // Not an IP address.
- "255.255.259.255"},
- {"255.300.255.255", // Not an IP address.
- "255.300.255.255"},
- {"3-1.2.3.4", // USB path, not an IP address.
- "3-1.2.3.4"},
- {"aaaa123.123.45.4aaa", // IP address.
- "aaaa<IPv4: 23>aaa"},
- {"11:11;11::11", // IP address.
- "11:11;<IPv6: 5>"},
- {"11::11", // IP address.
- "<IPv6: 5>"},
- {"11:11:abcdef:0:0:0:0:0", // No PII.
- "11:11:abcdef:0:0:0:0:0"},
- {"::", // Unspecified.
- "::"},
- {"::1", // Local host.
- "::1"},
- {"Instance::Set", // Ignore match, no PII.
- "Instance::Set"},
- {"Instant::ff", // Ignore match, no PII.
- "Instant::ff"},
- {"net::ERR_CONN_TIMEOUT", // Ignore match, no PII.
- "net::ERR_CONN_TIMEOUT"},
- {"ff01::1", // All nodes address (interface local).
- "ff01::1"},
- {"ff01::2", // All routers (interface local).
- "ff01::2"},
- {"ff01::3", // Multicast (interface local).
- "<ff01::/16: 6>"},
- {"ff02::1", // All nodes address (link local).
- "ff02::1"},
- {"ff02::2", // All routers (link local).
- "ff02::2"},
- {"ff02::3", // Multicast (link local).
- "<ff02::/16: 7>"},
- {"ff02::fb", // mDNSv6 (link local).
- "<ff02::/16: 8>"},
- {"ff08::fb", // mDNSv6.
- "<IPv6: 9>"},
- {"ff0f::101", // All NTP servers.
- "<IPv6: 10>"},
- {"::ffff:cb0c:10ea", // IPv4-mapped IPV6 (IP address).
- "<IPv6: 11>"},
- {"::ffff:a0a:a0a", // IPv4-mapped IPV6 (private class A).
- "<M 10.0.0.0/8: 12>"},
- {"::ffff:a0a:a0a", // Intentional duplicate.
- "<M 10.0.0.0/8: 12>"},
- {"::ffff:ac1e:1e1e", // IPv4-mapped IPV6 (private class B).
- "<M 172.16.0.0/12: 13>"},
- {"::ffff:c0a8:640a", // IPv4-mapped IPV6 (private class C).
- "<M 192.168.0.0/16: 14>"},
- {"::ffff:6473:5c01", // IPv4-mapped IPV6 (Chrome).
- "<M 100.115.92.1: 15>"},
- {"64:ff9b::a0a:a0a", // IPv4-translated 6to4 IPV6 (private class A).
- "<T 10.0.0.0/8: 16>"},
- {"64:ff9b::6473:5c01", // IPv4-translated 6to4 IPV6 (Chrome).
- "<T 100.115.92.1: 17>"},
- {"::0101:ffff:c0a8:640a", // IP address.
- "<IPv6: 18>"},
- {"aa:aa:aa:aa:aa:aa", // MAC address (BSSID).
- "[MAC OUI=aa:aa:aa IFACE=1]"},
- {"chrome://resources/foo", // Secure chrome resource, exempt.
- "chrome://resources/foo"},
- {"chrome://settings/crisper.js", // Exempt settings URLs.
- "chrome://settings/crisper.js"},
- // Exempt first party extension.
- {"chrome-extension://nkoccljplnhpfnfiajclkommnmllphnl/foobar.js",
- "chrome-extension://nkoccljplnhpfnfiajclkommnmllphnl/foobar.js"},
- {"chrome://resources/f?user=bar", // Potentially PII in parameter.
- "<URL: 2>"},
- {"chrome-extension://nkoccljplnhpfnfiajclkommnmllphnl/foobar.js?bar=x",
- "<URL: 3>"}, // Potentially PII in parameter.
+ std::string redaction_input;
+ std::string redaction_output;
+ for (const auto& s : kStringsWithRedactions) {
+ redaction_input.append(s.pre_redaction).append("\n");
+ redaction_output.append(s.post_redaction).append("\n");
+ }
+ EXPECT_EQ(redaction_output, redactor_.Redact(redaction_input));
+}
+
+TEST_F(RedactionToolTest, RedactAndKeepSelected) {
+ std::string redaction_input;
+ std::string redaction_output;
+ for (const auto& s : kStringsWithRedactions) {
+ redaction_input.append(s.pre_redaction).append("\n");
+ redaction_output.append(s.post_redaction).append("\n");
+ }
+ // Test RedactAndKeepSelected() with no PII type to keep.
+ EXPECT_EQ(redaction_output,
+ redactor_.RedactAndKeepSelected(redaction_input, {}));
+ // Test RedactAndKeepSelected() by only keeping IP addresses in the redacted
+ // output.
+ std::string redaction_output_ip;
+ for (const auto& s : kStringsWithRedactions) {
+ if (s.pii_type == PIIType::kIPAddress) {
+ redaction_output_ip.append(s.pre_redaction).append("\n");
+ } else {
+ redaction_output_ip.append(s.post_redaction).append("\n");
+ }
+ }
+ EXPECT_EQ(redaction_output_ip, redactor_.RedactAndKeepSelected(
+ redaction_input, {PIIType::kIPAddress}));
+ // Test RedactAndKeepSelected() by keeping MAC addresses and hashes in the
+ // redacted output. The hashes that URLs and Android storage paths contain
+ // will be redacted with the URL or Android storage path that they're part of.
+ std::string redaction_output_mac_and_hashes;
+ for (const auto& s : kStringsWithRedactions) {
+ if (s.pii_type == PIIType::kMACAddress || s.pii_type == PIIType::kHash) {
+ redaction_output_mac_and_hashes.append(s.pre_redaction).append("\n");
+ } else {
+ redaction_output_mac_and_hashes.append(s.post_redaction).append("\n");
+ }
+ }
+ EXPECT_EQ(redaction_output_mac_and_hashes,
+ redactor_.RedactAndKeepSelected(
+ redaction_input, {PIIType::kMACAddress, PIIType::kHash}));
+}
+
+TEST_F(RedactionToolTest, RedactAndKeepSelectedHashes) {
+ // Array of pairs containing pre/post redaction versions of the same string.
+ // Will be appended to create input and expected output for the test. Keep
+ // URLs and Android app storage paths but redact hashes. URLs and Android app
+ // storage paths that contain hashes will be partially redacted.
+ const std::pair<std::string, std::string> redaction_strings_with_hashes[] = {
+ {"chrome://resources/"
+ "f?user="
+ "99887766554433221100ffeeddccbbaaaabbccddeeff00112233445566778899",
+ "chrome://resources/f?user=<HASH:9988 1>"}, // URL that contains a hash.
{"/root/27540283740a0897ab7c8de0f809add2bacde78f/foo",
- "/root/<HASH:2754 1>/foo"}, // Hash string.
-#if BUILDFLAG(IS_CHROMEOS_ASH) // We only redact Android paths on Chrome OS.
- // Allowed android storage path.
- {"112K\t/home/root/deadbeef1234/android-data/data/system_de",
- "112K\t/home/root/deadbeef1234/android-data/data/system_de"},
- // Redacted app-specific storage path.
- {"8.0K\t/home/root/deadbeef1234/android-data/data/data/pa.ckage2/de",
- "8.0K\t/home/root/deadbeef1234/android-data/data/data/pa.ckage2/d_"},
+ "/root/<HASH:2754 2>/foo"}, // String that contains a hash.
+ {"this is the user hash that we need to redact "
+ "aabbccddeeff00112233445566778899",
+ "this is the user hash that we need to redact <HASH:aabb 3>"}, // String
+ // that
+ // contains
+ // a hash.
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+ {"8.0K\t/home/root/aabbccddeeff00112233445566778899/"
+ "android-data/data/data/pa.ckage2/de", // Android app storage
+ // path that contains a
+ // hash.
+ "8.0K\t/home/root/<HASH:aabb 3>/android-data/data/data/pa.ckage2/de"}
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
};
std::string redaction_input;
std::string redaction_output;
- for (const auto& s : data) {
+ for (const auto& s : redaction_strings_with_hashes) {
redaction_input.append(s.first).append("\n");
redaction_output.append(s.second).append("\n");
}
- EXPECT_EQ(redaction_output, redactor_.Redact(redaction_input));
+ EXPECT_EQ(
+ redaction_output,
+ redactor_.RedactAndKeepSelected(
+ redaction_input, {PIIType::kAndroidAppStoragePath, PIIType::kURL}));
+}
+
+TEST_F(RedactionToolTest, DetectPII) {
+ std::string redaction_input;
+ for (const auto& s : kStringsWithRedactions) {
+ redaction_input.append(s.pre_redaction).append("\n");
+ }
+ std::map<PIIType, std::set<std::string>> pii_in_data {
+#if BUILDFLAG(IS_CHROMEOS_ASH) // We only detect Android paths on Chrome OS.
+ {PIIType::kAndroidAppStoragePath, {"/de"}},
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
+ {PIIType::kSSID, {"123aaaaaa"}},
+ {PIIType::kURL,
+ {"http://tets.comaaaaaaa", "chrome://resources/f?user=bar",
+ "chrome-extension://nkoccljplnhpfnfiajclkommnmllphnl/"
+ "foobar.js?bar=x"}},
+ {PIIType::kEmail, {"aaaaaemail@example.comaaa"}},
+ {PIIType::kIPAddress,
+ {
+ "255.255.155.2",
+ "255.255.155.255",
+ "127.0.0.1",
+ "127.255.0.1",
+ "0.0.0.0",
+ "0.255.255.255",
+ "10.10.10.100",
+ "10.10.10.101",
+ "10.255.255.255",
+ "172.16.0.0",
+ "172.31.255.255",
+ "172.11.5.5",
+ "172.111.5.5",
+ "192.168.0.0",
+ "192.168.255.255",
+ "192.169.2.120",
+ "169.254.0.1",
+ "169.200.0.1",
+ "224.0.0.24",
+ "240.0.0.0",
+ "100.115.91.92",
+ "8.8.8.4",
+ "123.123.45.4",
+ "fe80::",
+ "fe80::ffff",
+ "febf:ffff::ffff",
+ "fecc::1111",
+ "11::11",
+ "ff01::3",
+ "ff02::3",
+ "ff02::fb",
+ "ff08::fb",
+ "ff0f::101",
+ "::ffff:cb0c:10ea",
+ "::ffff:a0a:a0a",
+ "::ffff:ac1e:1e1e",
+ "::ffff:c0a8:640a",
+ "::ffff:6473:5c01",
+ "64:ff9b::a0a:a0a",
+ "64:ff9b::6473:5c01",
+ "::0101:ffff:c0a8:640a",
+ }},
+ {PIIType::kMACAddress, {"aa:aa:aa:aa:aa:aa"}}, {
+ PIIType::kHash, { "27540283740a0897ab7c8de0f809add2bacde78f" }
+ }
+ };
+
+ EXPECT_EQ(pii_in_data, redactor_.Detect(redaction_input));
}
#if BUILDFLAG(IS_CHROMEOS_ASH) // We only redact Android paths on Chrome OS.
@@ -495,15 +677,16 @@ TEST_F(RedactionToolTest, RedactAndroidAppStoragePaths) {
"\xe3\x81\x82\xe3\x81\x83\n"
"8.0K\t/home/root/deadbeef1234/android-data/data/data/pa.ckage2/ef\n"
"24K\t/home/root/deadbeef1234/android-data/data/data/pa.ckage2\n"
- // /data/app won't.
"8.0K\t/home/root/deadbeef1234/android-data/data/app/pack.age1/a\n"
"8.0K\t/home/root/deadbeef1234/android-data/data/app/pack.age1/bc\n"
"24K\t/home/root/deadbeef1234/android-data/data/app/pack.age1\n"
- // /data/user_de will.
"8.0K\t/home/root/deadbeef1234/android-data/data/user_de/0/pack.age1/a\n"
"8.0K\t/home/root/deadbeef1234/android-data/data/user_de/0/pack.age1/bc\n"
"24K\t/home/root/deadbeef1234/android-data/data/user_de/0/pack.age1\n"
- "78M\t/home/root/deadbeef1234/android-data/data/data\n";
+ "78M\t/home/root/deadbeef1234/android-data/data/data\n"
+ "key=value path=/data/data/pack.age1/bc key=value\n"
+ "key=value path=/data/user_de/0/pack.age1/bc key=value\n"
+ "key=value exe=/data/app/pack.age1/bc key=value\n";
constexpr char kDuOutputRedacted[] =
"112K\t/home/root/deadbeef1234/android-data/data/system_de\n"
"8.0K\t/home/root/deadbeef1234/android-data/data/data/pack.age1/a\n"
@@ -516,12 +699,15 @@ TEST_F(RedactionToolTest, RedactAndroidAppStoragePaths) {
"8.0K\t/home/root/deadbeef1234/android-data/data/data/pa.ckage2/e_\n"
"24K\t/home/root/deadbeef1234/android-data/data/data/pa.ckage2\n"
"8.0K\t/home/root/deadbeef1234/android-data/data/app/pack.age1/a\n"
- "8.0K\t/home/root/deadbeef1234/android-data/data/app/pack.age1/bc\n"
+ "8.0K\t/home/root/deadbeef1234/android-data/data/app/pack.age1/b_\n"
"24K\t/home/root/deadbeef1234/android-data/data/app/pack.age1\n"
"8.0K\t/home/root/deadbeef1234/android-data/data/user_de/0/pack.age1/a\n"
"8.0K\t/home/root/deadbeef1234/android-data/data/user_de/0/pack.age1/b_\n"
"24K\t/home/root/deadbeef1234/android-data/data/user_de/0/pack.age1\n"
- "78M\t/home/root/deadbeef1234/android-data/data/data\n";
+ "78M\t/home/root/deadbeef1234/android-data/data/data\n"
+ "key=value path=/data/data/pack.age1/b_ key=value\n"
+ "key=value path=/data/user_de/0/pack.age1/b_ key=value\n"
+ "key=value exe=/data/app/pack.age1/b_ key=value\n";
EXPECT_EQ(kDuOutputRedacted, RedactAndroidAppStoragePaths(kDuOutput));
}
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chromium/components/filename_generation/filename_generation.cc b/chromium/components/filename_generation/filename_generation.cc
index 06f55a8776f..3a0a1db5c95 100644
--- a/chromium/components/filename_generation/filename_generation.cc
+++ b/chromium/components/filename_generation/filename_generation.cc
@@ -162,10 +162,10 @@ bool TruncateFilename(base::FilePath* path, size_t limit) {
// Encoding specific truncation logic.
base::FilePath::StringType truncated;
-#if BUILDFLAG(IS_CHROMEOS_ASH) || defined(OS_APPLE)
+#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_APPLE)
// UTF-8.
base::TruncateUTF8ToByteSize(name, limit, &truncated);
-#elif defined(OS_WIN)
+#elif BUILDFLAG(IS_WIN)
// UTF-16.
DCHECK(name.size() > limit);
truncated = name.substr(0, CBU16_IS_TRAIL(name[limit]) ? limit - 1 : limit);
diff --git a/chromium/components/filename_generation/filename_generation_unittest.cc b/chromium/components/filename_generation/filename_generation_unittest.cc
index 43ba448fd07..1aeda89daa2 100644
--- a/chromium/components/filename_generation/filename_generation_unittest.cc
+++ b/chromium/components/filename_generation/filename_generation_unittest.cc
@@ -19,7 +19,7 @@ namespace filename_generation {
#define FPL FILE_PATH_LITERAL
#define HTML_EXTENSION ".html"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#define FPL_HTML_EXTENSION L".html"
#else
#define FPL_HTML_EXTENSION ".html"
@@ -58,7 +58,7 @@ static const struct {
};
// Crashing on Windows, see http://crbug.com/79365
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#define MAYBE_TestEnsureHtmlExtension DISABLED_TestEnsureHtmlExtension
#else
#define MAYBE_TestEnsureHtmlExtension TestEnsureHtmlExtension
@@ -75,7 +75,7 @@ TEST(FilenameGenerationTest, MAYBE_TestEnsureHtmlExtension) {
}
// Crashing on Windows, see http://crbug.com/79365
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#define MAYBE_TestEnsureMimeExtension DISABLED_TestEnsureMimeExtension
#else
#define MAYBE_TestEnsureMimeExtension TestEnsureMimeExtension
@@ -89,11 +89,11 @@ TEST(FilenameGenerationTest, MAYBE_TestEnsureMimeExtension) {
{FPL("filename.html"), FPL("filename.html"), "text/html"},
{FPL("filename.htm"), FPL("filename.htm"), "text/html"},
{FPL("filename.xhtml"), FPL("filename.xhtml"), "text/html"},
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
{FPL("filename"), FPL("filename.htm"), "text/html"},
-#else // defined(OS_WIN)
+#else // BUILDFLAG(IS_WIN)
{FPL("filename"), FPL("filename.html"), "text/html"},
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
{FPL("filename.html"), FPL("filename.html"), "text/xml"},
{FPL("filename.xml"), FPL("filename.xml"), "text/xml"},
{FPL("filename"), FPL("filename.xml"), "text/xml"},
@@ -160,7 +160,7 @@ static const struct GenerateFilenameTestCase {
};
// Crashing on Windows, see http://crbug.com/79365
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#define MAYBE_TestGenerateFilename DISABLED_TestGenerateFilename
#else
#define MAYBE_TestGenerateFilename TestGenerateFilename
@@ -190,7 +190,7 @@ TEST(FilenameGenerationTest, TestBasicTruncation) {
// The file path will only be truncated o the platforms that have known
// encoding. Otherwise no truncation will be performed.
-#if defined(OS_WIN) || defined(OS_APPLE) || BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_CHROMEOS_ASH)
// The file name length is truncated to max_length.
EXPECT_TRUE(TruncateFilename(&truncated_path, max_length));
EXPECT_EQ(size_t(max_length), truncated_path.BaseName().value().size());
diff --git a/chromium/components/find_in_page/android/BUILD.gn b/chromium/components/find_in_page/android/BUILD.gn
index c0296a25b93..1f83721a240 100644
--- a/chromium/components/find_in_page/android/BUILD.gn
+++ b/chromium/components/find_in_page/android/BUILD.gn
@@ -3,7 +3,6 @@
# found in the LICENSE file.
import("//build/config/android/rules.gni")
-import("//build/config/locales.gni")
android_library("java") {
sources = [
diff --git a/chromium/components/find_in_page/find_tab_helper.cc b/chromium/components/find_in_page/find_tab_helper.cc
index 4d1d160c9c8..f84bfe7433f 100644
--- a/chromium/components/find_in_page/find_tab_helper.cc
+++ b/chromium/components/find_in_page/find_tab_helper.cc
@@ -139,7 +139,7 @@ std::u16string FindTabHelper::GetInitialSearchText() {
return delegate_ ? delegate_->GetSearchPrepopulateText() : std::u16string();
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
void FindTabHelper::ActivateNearestFindResult(float x, float y) {
if (!find_op_aborted_ && !find_text_.empty()) {
GetWebContents().ActivateNearestFindResult(x, y);
diff --git a/chromium/components/find_in_page/find_tab_helper.h b/chromium/components/find_in_page/find_tab_helper.h
index de4ee2cbf9e..f0c7424a7c5 100644
--- a/chromium/components/find_in_page/find_tab_helper.h
+++ b/chromium/components/find_in_page/find_tab_helper.h
@@ -107,7 +107,7 @@ class FindTabHelper : public content::WebContentsUserData<FindTabHelper> {
bool should_find_match() const { return should_find_match_; }
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Selects and zooms to the find result nearest to the point (x,y)
// defined in find-in-page coordinates.
void ActivateNearestFindResult(float x, float y);
diff --git a/chromium/components/flags_ui/feature_entry.cc b/chromium/components/flags_ui/feature_entry.cc
index 7f13669e30a..882dc41b533 100644
--- a/chromium/components/flags_ui/feature_entry.cc
+++ b/chromium/components/flags_ui/feature_entry.cc
@@ -5,6 +5,9 @@
#include "components/flags_ui/feature_entry.h"
#include "base/check_op.h"
+#include "base/logging.h"
+#include "base/notreached.h"
+#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
@@ -85,8 +88,9 @@ std::u16string FeatureEntry::DescriptionForOption(int index) const {
const char* description = nullptr;
if (type == FeatureEntry::ENABLE_DISABLE_VALUE ||
type == FeatureEntry::FEATURE_VALUE) {
- const char* kEnableDisableDescriptions[] = {
- kGenericExperimentChoiceDefault, kGenericExperimentChoiceEnabled,
+ const char* const kEnableDisableDescriptions[] = {
+ kGenericExperimentChoiceDefault,
+ kGenericExperimentChoiceEnabled,
kGenericExperimentChoiceDisabled,
};
description = kEnableDisableDescriptions[index];
@@ -98,11 +102,9 @@ std::u16string FeatureEntry::DescriptionForOption(int index) const {
} else if (index < NumOptions() - 1) {
// First two options do not have variations params.
int variation_index = index - 2;
- return base::ASCIIToUTF16(
- base::StringPiece(kGenericExperimentChoiceEnabled)) +
- u" " +
- base::ASCIIToUTF16(
- feature.feature_variations[variation_index].description_text);
+ return base::ASCIIToUTF16(base::StrCat(
+ {kGenericExperimentChoiceEnabled, " ",
+ feature.feature_variations[variation_index].description_text}));
} else {
DCHECK_EQ(NumOptions() - 1, index);
description = kGenericExperimentChoiceDisabled;
@@ -110,7 +112,7 @@ std::u16string FeatureEntry::DescriptionForOption(int index) const {
} else {
description = choices[index].description;
}
- return base::ASCIIToUTF16(base::StringPiece(description));
+ return base::ASCIIToUTF16(description);
}
const FeatureEntry::Choice& FeatureEntry::ChoiceForOption(int index) const {
@@ -148,6 +150,69 @@ const FeatureEntry::FeatureVariation* FeatureEntry::VariationForOption(
return nullptr;
}
+bool FeatureEntry::IsValid() const {
+ switch (type) {
+ case FeatureEntry::SINGLE_VALUE:
+ case FeatureEntry::SINGLE_DISABLE_VALUE:
+ case FeatureEntry::ORIGIN_LIST_VALUE:
+ return true;
+ case FeatureEntry::MULTI_VALUE:
+ if (choices.size() == 0) {
+ LOG(ERROR) << "no choice is found";
+ return false;
+ }
+ if (!ChoiceForOption(0).command_line_switch) {
+ LOG(ERROR) << "command_line_swtich is null";
+ return false;
+ }
+ if (ChoiceForOption(0).command_line_switch[0] != '\0') {
+ LOG(ERROR) << "The command line value of the first item must be empty";
+ return false;
+ }
+ return true;
+ case FeatureEntry::ENABLE_DISABLE_VALUE:
+ if (!switches.command_line_switch) {
+ LOG(ERROR) << "command_line_switch is null";
+ return false;
+ }
+ if (!switches.command_line_value) {
+ LOG(ERROR) << "command_line_value is null";
+ return false;
+ }
+ if (!switches.disable_command_line_switch) {
+ LOG(ERROR) << "disable_command_line_switch is null";
+ return false;
+ }
+ if (!switches.disable_command_line_value) {
+ LOG(ERROR) << "disable_command_line_value is null";
+ return false;
+ }
+ return true;
+ case FeatureEntry::FEATURE_VALUE:
+ if (!feature.feature) {
+ LOG(ERROR) << "no feature is set";
+ return false;
+ }
+ return true;
+ case FeatureEntry::FEATURE_WITH_PARAMS_VALUE:
+ if (!feature.feature) {
+ LOG(ERROR) << "no feature is set";
+ return false;
+ }
+ if (feature.feature_variations.size() == 0) {
+ LOG(ERROR) << "feature_variations is empty";
+ return false;
+ }
+ if (!feature.feature_trial_name) {
+ LOG(ERROR) << "feature_trial_name is null";
+ return false;
+ }
+ return true;
+ }
+ NOTREACHED();
+ return false;
+}
+
namespace testing {
const char kMultiSeparator[] = {kMultiSeparatorChar, '\0'};
diff --git a/chromium/components/flags_ui/feature_entry.h b/chromium/components/flags_ui/feature_entry.h
index 23c409eb491..c7d9a177db7 100644
--- a/chromium/components/flags_ui/feature_entry.h
+++ b/chromium/components/flags_ui/feature_entry.h
@@ -217,6 +217,10 @@ struct FeatureEntry {
// variation associated at |index|. Only applicable for types FEATURE_VALUE
// and FEATURE_WITH_PARAMS_VALUE.
const FeatureEntry::FeatureVariation* VariationForOption(int index) const;
+
+ // Returns true if the entry is considered as valid.
+ // See the implenetation for the details of what is valid.
+ bool IsValid() const;
};
namespace testing {
diff --git a/chromium/components/flags_ui/flags_state.cc b/chromium/components/flags_ui/flags_state.cc
index 8859f36b0a8..f6241ea4655 100644
--- a/chromium/components/flags_ui/flags_state.cc
+++ b/chromium/components/flags_ui/flags_state.cc
@@ -65,38 +65,6 @@ void AddOsStrings(unsigned bitmask, base::Value* list) {
}
}
-// Confirms that an entry is valid, used in a DCHECK in
-// SanitizeList below.
-bool IsValidFeatureEntry(const FeatureEntry& e) {
- switch (e.type) {
- case FeatureEntry::SINGLE_VALUE:
- case FeatureEntry::SINGLE_DISABLE_VALUE:
- case FeatureEntry::ORIGIN_LIST_VALUE:
- return true;
- case FeatureEntry::MULTI_VALUE:
- DCHECK_GT(e.choices.size(), 0u);
- DCHECK(e.ChoiceForOption(0).command_line_switch);
- DCHECK_EQ('\0', e.ChoiceForOption(0).command_line_switch[0]);
- return true;
- case FeatureEntry::ENABLE_DISABLE_VALUE:
- DCHECK(e.switches.command_line_switch);
- DCHECK(e.switches.command_line_value);
- DCHECK(e.switches.disable_command_line_switch);
- DCHECK(e.switches.disable_command_line_value);
- return true;
- case FeatureEntry::FEATURE_VALUE:
- DCHECK(e.feature.feature);
- return true;
- case FeatureEntry::FEATURE_WITH_PARAMS_VALUE:
- DCHECK(e.feature.feature);
- DCHECK(e.feature.feature_variations.size());
- DCHECK(e.feature.feature_trial_name);
- return true;
- }
- NOTREACHED();
- return false;
-}
-
// Returns true if none of this entry's options have been enabled.
bool IsDefaultValue(const FeatureEntry& entry,
const std::set<std::string>& enabled_entries) {
@@ -454,7 +422,7 @@ void FlagsState::RemoveFlagsSwitches(
// The below is either a std::string or a std::u16string based on platform.
const auto& existing_value = (*switch_list)[switch_name];
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
const std::string existing_value_utf8 = base::WideToUTF8(existing_value);
#else
const std::string& existing_value_utf8 = existing_value;
@@ -476,7 +444,7 @@ void FlagsState::RemoveFlagsSwitches(
switch_list->erase(switch_name);
} else {
std::string switch_value = base::JoinString(remaining_features, ",");
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
(*switch_list)[switch_name] = base::UTF8ToWide(switch_value);
#else
(*switch_list)[switch_name] = switch_value;
@@ -645,20 +613,20 @@ void FlagsState::GetFlagFeatureEntries(
// static
unsigned short FlagsState::GetCurrentPlatform() {
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
return kOsIos;
-#elif defined(OS_MAC)
+#elif BUILDFLAG(IS_MAC)
return kOsMac;
-#elif defined(OS_WIN)
+#elif BUILDFLAG(IS_WIN)
return kOsWin;
#elif BUILDFLAG(IS_CHROMEOS_ASH)
return kOsCrOS;
-#elif (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) || \
- defined(OS_OPENBSD)
+#elif (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) || \
+ BUILDFLAG(IS_OPENBSD)
return kOsLinux;
-#elif defined(OS_ANDROID)
+#elif BUILDFLAG(IS_ANDROID)
return kOsAndroid;
-#elif defined(OS_FUCHSIA)
+#elif BUILDFLAG(IS_FUCHSIA)
return kOsFuchsia;
#else
#error Unknown platform
@@ -907,7 +875,7 @@ bool FlagsState::IsSupportedFeature(const FlagsStorage* storage,
const std::string& name,
int platform_mask) const {
for (const auto& entry : feature_entries_) {
- DCHECK(IsValidFeatureEntry(entry));
+ DCHECK(entry.IsValid());
if (!(entry.supported_platforms & platform_mask))
continue;
if (!entry.InternalNameMatches(name))
diff --git a/chromium/components/flags_ui/flags_state_unittest.cc b/chromium/components/flags_ui/flags_state_unittest.cc
index 46e90945195..6331fdfce6d 100644
--- a/chromium/components/flags_ui/flags_state_unittest.cc
+++ b/chromium/components/flags_ui/flags_state_unittest.cc
@@ -247,10 +247,10 @@ TEST_F(FlagsStateTest, AddTwoFlagsRemoveOne) {
const base::Value* entries_list = prefs_.GetList(prefs::kAboutFlagsEntries);
ASSERT_TRUE(entries_list != nullptr);
- ASSERT_EQ(2u, entries_list->GetList().size());
+ ASSERT_EQ(2u, entries_list->GetListDeprecated().size());
- std::string s0 = entries_list->GetList()[0].GetString();
- std::string s1 = entries_list->GetList()[1].GetString();
+ std::string s0 = entries_list->GetListDeprecated()[0].GetString();
+ std::string s1 = entries_list->GetListDeprecated()[1].GetString();
EXPECT_TRUE(s0 == kFlags1 || s1 == kFlags1);
EXPECT_TRUE(s0 == kFlags2 || s1 == kFlags2);
@@ -260,8 +260,8 @@ TEST_F(FlagsStateTest, AddTwoFlagsRemoveOne) {
entries_list = prefs_.GetList(prefs::kAboutFlagsEntries);
ASSERT_TRUE(entries_list != nullptr);
- ASSERT_EQ(1u, entries_list->GetList().size());
- s0 = entries_list->GetList()[0].GetString();
+ ASSERT_EQ(1u, entries_list->GetListDeprecated().size());
+ s0 = entries_list->GetListDeprecated()[0].GetString();
EXPECT_TRUE(s0 == kFlags1);
}
@@ -276,7 +276,8 @@ TEST_F(FlagsStateTest, AddTwoFlagsRemoveBoth) {
flags_state_->SetFeatureEntryEnabled(&flags_storage_, kFlags1, false);
flags_state_->SetFeatureEntryEnabled(&flags_storage_, kFlags2, false);
entries_list = prefs_.GetList(prefs::kAboutFlagsEntries);
- EXPECT_TRUE(entries_list == nullptr || entries_list->GetList().size() == 0);
+ EXPECT_TRUE(entries_list == nullptr ||
+ entries_list->GetListDeprecated().size() == 0);
}
TEST_F(FlagsStateTest, CombineOriginListValues) {
@@ -439,7 +440,7 @@ TEST_F(FlagsStateTest, RegisterAllFeatureVariationParametersWithDefaultTrials) {
}
base::CommandLine::StringType CreateSwitch(const std::string& value) {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
return base::ASCIIToWide(value);
#else
return value;
@@ -572,10 +573,10 @@ TEST_F(FlagsStateTest, PersistAndPrune) {
// FeatureEntry 3 should show still be persisted in preferences though.
const base::Value* entries_list = prefs_.GetList(prefs::kAboutFlagsEntries);
ASSERT_TRUE(entries_list);
- EXPECT_EQ(2U, entries_list->GetList().size());
- std::string s0 = entries_list->GetList()[0].GetString();
+ EXPECT_EQ(2U, entries_list->GetListDeprecated().size());
+ std::string s0 = entries_list->GetListDeprecated()[0].GetString();
EXPECT_EQ(kFlags1, s0);
- std::string s1 = entries_list->GetList()[1].GetString();
+ std::string s1 = entries_list->GetListDeprecated()[1].GetString();
EXPECT_EQ(kFlags3, s1);
}
@@ -602,7 +603,7 @@ TEST_F(FlagsStateTest, CheckValues) {
// Confirm that there is no '=' in the command line for simple switches.
std::string switch1_with_equals =
std::string("--") + std::string(kSwitch1) + std::string("=");
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
EXPECT_EQ(std::wstring::npos, command_line.GetCommandLineString().find(
base::ASCIIToWide(switch1_with_equals)));
#else
@@ -613,7 +614,7 @@ TEST_F(FlagsStateTest, CheckValues) {
// And confirm there is a '=' for switches with values.
std::string switch2_with_equals =
std::string("--") + std::string(kSwitch2) + std::string("=");
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
EXPECT_NE(std::wstring::npos, command_line.GetCommandLineString().find(
base::ASCIIToWide(switch2_with_equals)));
#else
@@ -624,10 +625,10 @@ TEST_F(FlagsStateTest, CheckValues) {
// And it should persist.
const base::Value* entries_list = prefs_.GetList(prefs::kAboutFlagsEntries);
ASSERT_TRUE(entries_list);
- EXPECT_EQ(2U, entries_list->GetList().size());
- std::string s0 = entries_list->GetList()[0].GetString();
+ EXPECT_EQ(2U, entries_list->GetListDeprecated().size());
+ std::string s0 = entries_list->GetListDeprecated()[0].GetString();
EXPECT_EQ(kFlags1, s0);
- std::string s1 = entries_list->GetList()[1].GetString();
+ std::string s1 = entries_list->GetListDeprecated()[1].GetString();
EXPECT_EQ(kFlags2, s1);
}
diff --git a/chromium/components/flags_ui/flags_test_helpers.cc b/chromium/components/flags_ui/flags_test_helpers.cc
index b9b71c10571..1d62b71b43c 100644
--- a/chromium/components/flags_ui/flags_test_helpers.cc
+++ b/chromium/components/flags_ui/flags_test_helpers.cc
@@ -68,11 +68,11 @@ FlagMetadataMap LoadFlagMetadata() {
base::Value metadata_json = FileContents(FlagFile::kFlagMetadata);
FlagMetadataMap metadata;
- for (const auto& entry : metadata_json.GetList()) {
+ for (const auto& entry : metadata_json.GetListDeprecated()) {
std::string name = entry.FindKey("name")->GetString();
std::vector<std::string> owners;
if (const base::Value* e = entry.FindKey("owners")) {
- for (const auto& owner : e->GetList())
+ for (const auto& owner : e->GetListDeprecated())
owners.push_back(owner.GetString());
}
int expiry_milestone = entry.FindKey("expiry_milestone")->GetInt();
@@ -86,7 +86,7 @@ std::vector<std::string> LoadFlagNeverExpireList() {
base::Value list_json = FileContents(FlagFile::kFlagNeverExpire);
std::vector<std::string> result;
- for (const auto& entry : list_json.GetList()) {
+ for (const auto& entry : list_json.GetListDeprecated()) {
result.push_back(entry.GetString());
}
return result;
@@ -275,7 +275,7 @@ void EnsureFlagsAreListedInAlphabeticalOrder() {
std::vector<std::string> normalized_names;
std::vector<std::string> names;
- for (const auto& entry : metadata_json.GetList()) {
+ for (const auto& entry : metadata_json.GetListDeprecated()) {
normalized_names.push_back(
NormalizeName(entry.FindKey("name")->GetString()));
names.push_back(entry.FindKey("name")->GetString());
@@ -287,7 +287,7 @@ void EnsureFlagsAreListedInAlphabeticalOrder() {
normalized_names.clear();
names.clear();
- for (const auto& entry : expiration_json.GetList()) {
+ for (const auto& entry : expiration_json.GetListDeprecated()) {
normalized_names.push_back(NormalizeName(entry.GetString()));
names.push_back(entry.GetString());
}
diff --git a/chromium/components/flags_ui/flags_ui_constants.cc b/chromium/components/flags_ui/flags_ui_constants.cc
index 0a6cf43f60d..e7de91f837d 100644
--- a/chromium/components/flags_ui/flags_ui_constants.cc
+++ b/chromium/components/flags_ui/flags_ui_constants.cc
@@ -4,12 +4,14 @@
#include "components/flags_ui/flags_ui_constants.h"
+#include "build/build_config.h"
+
namespace flags_ui {
// Resource paths.
const char kFlagsJS[] = "flags.js";
const char kFlagsCSS[] = "flags.css";
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS)
const char kFlagsSVG[] = "os_flags_app_icon.svg";
#endif
@@ -18,7 +20,7 @@ const char kEnableExperimentalFeature[] = "enableExperimentalFeature";
const char kRequestExperimentalFeatures[] = "requestExperimentalFeatures";
const char kSetOriginListFlag[] = "setOriginListFlag";
const char kResetAllFlags[] = "resetAllFlags";
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS)
const char kCrosUrlFlagsRedirect[] = "crosUrlFlagsRedirect";
#endif
const char kRestartBrowser[] = "restartBrowser";
diff --git a/chromium/components/flags_ui/flags_ui_constants.h b/chromium/components/flags_ui/flags_ui_constants.h
index 5853574350c..1b857bc751a 100644
--- a/chromium/components/flags_ui/flags_ui_constants.h
+++ b/chromium/components/flags_ui/flags_ui_constants.h
@@ -5,13 +5,15 @@
#ifndef COMPONENTS_FLAGS_UI_FLAGS_UI_CONSTANTS_H_
#define COMPONENTS_FLAGS_UI_FLAGS_UI_CONSTANTS_H_
+#include "build/build_config.h"
+
namespace flags_ui {
// Resource paths.
// Must match the resource file names.
extern const char kFlagsJS[];
extern const char kFlagsCSS[];
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS)
extern const char kFlagsSVG[];
#endif
@@ -21,7 +23,7 @@ extern const char kEnableExperimentalFeature[];
extern const char kRequestExperimentalFeatures[];
extern const char kSetOriginListFlag[];
extern const char kResetAllFlags[];
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS)
extern const char kCrosUrlFlagsRedirect[];
#endif
extern const char kRestartBrowser[];
diff --git a/chromium/components/flags_ui/pref_service_flags_storage.cc b/chromium/components/flags_ui/pref_service_flags_storage.cc
index 8b79adecdf7..b531ebe9e94 100644
--- a/chromium/components/flags_ui/pref_service_flags_storage.cc
+++ b/chromium/components/flags_ui/pref_service_flags_storage.cc
@@ -25,7 +25,7 @@ std::set<std::string> PrefServiceFlagsStorage::GetFlags() const {
const base::Value* enabled_experiments =
prefs_->GetList(prefs::kAboutFlagsEntries);
std::set<std::string> flags;
- for (const auto& entry : enabled_experiments->GetList()) {
+ for (const auto& entry : enabled_experiments->GetListDeprecated()) {
if (!entry.is_string()) {
LOG(WARNING) << "Invalid entry in " << prefs::kAboutFlagsEntries;
continue;
@@ -62,7 +62,7 @@ void PrefServiceFlagsStorage::SetOriginListFlag(
const std::string& internal_entry_name,
const std::string& origin_list_value) {
DictionaryPrefUpdate update(prefs_, prefs::kAboutFlagsOriginLists);
- update->SetString(internal_entry_name, origin_list_value);
+ update->SetStringPath(internal_entry_name, origin_list_value);
}
void PrefServiceFlagsStorage::CommitPendingWrites() {
diff --git a/chromium/components/flags_ui/resources/flags.css b/chromium/components/flags_ui/resources/flags.css
index 8ee6c6bea6c..ecd392e542d 100644
--- a/chromium/components/flags_ui/resources/flags.css
+++ b/chromium/components/flags_ui/resources/flags.css
@@ -533,35 +533,8 @@ html.focus-outline-visible button.primary:focus {
text-align: right; /* csschecker-disable-line left-right */
}
-.os-link-container {
- align-items: center;
- border: 1px solid rgb(232, 234, 237);
- border-radius: 4px;
- display: flex;
- font-size: 14px;
- line-height: 20px;
- margin-bottom: 28px;
- padding: 12px;
-}
-
-@media (prefers-color-scheme: dark) {
- .os-link-container {
- border: 1px solid rgb(18, 21, 23);
- }
-}
-
-.os-link-icon {
- background-image: url(chrome://flags/os_flags_app_icon.svg);
- background-size: 16px 16px;
- height: 16px;
- margin-inline-end: 16px;
- width: 16px;
-}
-
-#os-link-href {
- font-size: 14px;
- line-height: 20px;
- padding-inline-start: 4px;
+#os-flags-link-container {
+ background-image: url(chrome://resources/images/os_flags_app_icon.svg);
}
@media (max-width: 360px) {
diff --git a/chromium/components/flags_ui/resources/flags.html b/chromium/components/flags_ui/resources/flags.html
index 2bf3f56a04a..bbc88ba9589 100644
--- a/chromium/components/flags_ui/resources/flags.html
+++ b/chromium/components/flags_ui/resources/flags.html
@@ -47,7 +47,7 @@
<div id="flagsTemplate">
<if expr="lacros or chromeos">
<div class="os-link-container" id="os-link-container">
- <span class="os-link-icon"></span>
+ <span id="os-flags-link-container" class="os-link-icon"></span>
<span aria-hidden="true" id="os-link-desc">$i18n{os-flags-text1}</span>
<a href="#" id="os-link-href" tabindex="4" aria-describedby="os-link-desc">
$i18n{os-flags-link}
diff --git a/chromium/components/fullscreen_control/subtle_notification_view.cc b/chromium/components/fullscreen_control/subtle_notification_view.cc
index 9f2e552c18f..f1a87bf2325 100644
--- a/chromium/components/fullscreen_control/subtle_notification_view.cc
+++ b/chromium/components/fullscreen_control/subtle_notification_view.cc
@@ -41,6 +41,9 @@ const int kKeyNameBorderPx = 1;
const int kKeyNameCornerRadius = 2;
const int kKeyNamePaddingPx = 5;
+// Spacing between the key name and image, if any.
+const int kKeyNameImageSpacingPx = 3;
+
// The context used to obtain typography for the instruction text. It's not
// really a dialog, but a dialog title is a good fit.
constexpr int kInstructionTextContext = views::style::CONTEXT_DIALOG_TITLE;
@@ -65,12 +68,16 @@ class SubtleNotificationView::InstructionView : public views::View {
std::u16string GetText() const;
void SetText(const std::u16string& text);
+ void SetTextAndImages(const std::u16string& text,
+ std::vector<std::unique_ptr<views::View>> key_images);
private:
// Adds a label to the end of the notification text. If |format_as_key|,
// surrounds the label in a rounded-rect border to indicate that it is a
// keyboard key.
- void AddTextSegment(const std::u16string& text, bool format_as_key);
+ void AddTextSegment(const std::u16string& text,
+ bool format_as_key,
+ std::unique_ptr<views::View> key_image);
std::u16string text_;
};
@@ -91,8 +98,14 @@ std::u16string SubtleNotificationView::InstructionView::GetText() const {
void SubtleNotificationView::InstructionView::SetText(
const std::u16string& text) {
+ SetTextAndImages(text, std::vector<std::unique_ptr<views::View>>());
+}
+
+void SubtleNotificationView::InstructionView::SetTextAndImages(
+ const std::u16string& text,
+ std::vector<std::unique_ptr<views::View>> key_images) {
// Avoid replacing the contents with the same text.
- if (text == text_)
+ if (text == text_ && key_images.empty())
return;
RemoveAllChildViews();
@@ -106,11 +119,26 @@ void SubtleNotificationView::InstructionView::SetText(
// list is also empty (rather than containing a single empty string).
DCHECK(segments.empty() || segments.size() % 2 == 1);
+ // Every second segment is formatted as a key, so should have an image
+ // specified for it (even if that image is an empty unique_ptr).
+ // Or, we can have no key images at all.
+ //
+ // There should always be one non-key segment preceding each key segment
+ // (even if empty, as above) and one segment at the end, so the total number
+ // of segments should be double the number of key segments, plus one.
+ DCHECK(key_images.empty() || key_images.size() * 2 + 1 == segments.size());
+
// Add text segment, alternating between non-key (no border) and key (border)
// formatting.
bool format_as_key = false;
+ int idx = 0;
for (const auto& segment : segments) {
- AddTextSegment(segment, format_as_key);
+ std::unique_ptr<views::View> key_image;
+ if (!key_images.empty() && format_as_key) {
+ key_image = std::move(key_images[idx]);
+ idx++;
+ }
+ AddTextSegment(segment, format_as_key, std::move(key_image));
format_as_key = !format_as_key;
}
@@ -119,7 +147,8 @@ void SubtleNotificationView::InstructionView::SetText(
void SubtleNotificationView::InstructionView::AddTextSegment(
const std::u16string& text,
- bool format_as_key) {
+ bool format_as_key,
+ std::unique_ptr<views::View> key_image) {
constexpr SkColor kForegroundColor = SK_ColorWHITE;
views::Label* label = new views::Label(text, kInstructionTextContext);
@@ -127,6 +156,7 @@ void SubtleNotificationView::InstructionView::AddTextSegment(
label->SetBackgroundColor(kSubtleNotificationBackgroundColor);
if (!format_as_key) {
+ DCHECK(!key_image);
AddChildView(label);
return;
}
@@ -134,10 +164,12 @@ void SubtleNotificationView::InstructionView::AddTextSegment(
views::View* key = new views::View;
auto key_name_layout = std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kHorizontal,
- gfx::Insets(0, kKeyNamePaddingPx), 0);
+ gfx::Insets(0, kKeyNamePaddingPx), kKeyNameImageSpacingPx);
key_name_layout->set_minimum_cross_axis_size(
label->GetPreferredSize().height() + kKeyNamePaddingPx * 2);
key->SetLayoutManager(std::move(key_name_layout));
+ if (key_image)
+ key->AddChildView(std::move(key_image));
key->AddChildView(label);
// The key name has a border around it.
std::unique_ptr<views::Border> border(views::CreateRoundedRectBorder(
@@ -177,6 +209,14 @@ void SubtleNotificationView::UpdateContent(
Layout();
}
+void SubtleNotificationView::UpdateContent(
+ const std::u16string& instruction_text,
+ std::vector<std::unique_ptr<views::View>> key_images) {
+ instruction_view_->SetTextAndImages(instruction_text, std::move(key_images));
+ instruction_view_->SetVisible(!instruction_text.empty());
+ Layout();
+}
+
// static
views::Widget* SubtleNotificationView::CreatePopupWidget(
gfx::NativeView parent_view,
diff --git a/chromium/components/fullscreen_control/subtle_notification_view.h b/chromium/components/fullscreen_control/subtle_notification_view.h
index 700820c6e4c..5fe18082563 100644
--- a/chromium/components/fullscreen_control/subtle_notification_view.h
+++ b/chromium/components/fullscreen_control/subtle_notification_view.h
@@ -7,10 +7,12 @@
#include <memory>
#include <string>
+#include <vector>
#include "base/memory/raw_ptr.h"
#include "ui/base/metadata/metadata_header_macros.h"
#include "ui/gfx/native_widget_types.h"
+#include "ui/views/controls/image_view.h"
#include "ui/views/view.h"
namespace views {
@@ -35,6 +37,14 @@ class SubtleNotificationView : public views::View {
// empty hide the view.
void UpdateContent(const std::u16string& instruction_text);
+ // Display the |instruction_text| to the user, with the |key_images| inside
+ // the rectangles that represent keys. |key_images| must either be empty, or
+ // the same length as the number of text segments inside pipe characters.
+ //
+ // If |instruction_text| is empty hide the view.
+ void UpdateContent(const std::u16string& instruction_text,
+ std::vector<std::unique_ptr<views::View>> key_images);
+
// Creates a Widget containing a SubtleNotificationView.
static views::Widget* CreatePopupWidget(
gfx::NativeView parent_view,
diff --git a/chromium/components/fullscreen_control_strings.grdp b/chromium/components/fullscreen_control_strings.grdp
index 269e155502c..a25d25b634e 100644
--- a/chromium/components/fullscreen_control_strings.grdp
+++ b/chromium/components/fullscreen_control_strings.grdp
@@ -3,10 +3,19 @@
<message name="IDS_EXIT_FULLSCREEN_MODE" desc="Clickable message displayed on entering full screen mode. Clicking on the link exits full screen mode.">
Exit full screen
</message>
- <message name="IDS_FULLSCREEN_HOLD_ESC_TO_EXIT_FULLSCREEN" desc="Text displayed in the bubble to tell users how to return from fullscreen mode (where the web page occupies the entire screen) to normal mode. Please surround the name of the key (e.g. 'Esc') in pipe characters so it can be rendered as a key.">
+ <message name="IDS_FULLSCREEN_HOLD_TO_EXIT_FULLSCREEN" desc="Text displayed in the bubble to tell users how to return from fullscreen mode (where the web page occupies the entire screen) to normal mode. Please surround the name of the key (e.g. 'Esc') in pipe characters so it can be rendered as a key.">
Press and hold |<ph name="ACCELERATOR">$1<ex>Esc</ex></ph>| to exit full screen
</message>
- <message name="IDS_FULLSCREEN_PRESS_ESC_TO_EXIT_FULLSCREEN" desc="Text displayed in the bubble to tell users how to return from fullscreen mode (where the web page occupies the entire screen) to normal mode. Please surround the name of the key (e.g. 'Esc') in pipe characters so it can be rendered as a key.">
+ <message name="IDS_FULLSCREEN_PRESS_TO_EXIT_FULLSCREEN" desc="Text displayed in the bubble to tell users how to return from fullscreen mode (where the web page occupies the entire screen) to normal mode. Please surround the name of the key (e.g. 'Esc') in pipe characters so it can be rendered as a key.">
Press |<ph name="ACCELERATOR">$1<ex>Esc</ex></ph>| to exit full screen
</message>
+ <message name="IDS_FULLSCREEN_PRESS_TO_EXIT_FULLSCREEN_TWO_KEYS" desc="Text displayed in the bubble to tell users how to leave fullscreen mode, in the case where two keys must be pressed together. Please surround the names of the keys (e.g. 'Overview') in pipe characters so it can be rendered as a key.">
+ Press |<ph name="ACCELERATOR1">$1<ex>Search</ex></ph>| + |<ph name="ACCELERATOR2">$2<ex>Overview</ex></ph>| to exit full screen
+ </message>
+ <message name="IDS_PRESS_TO_EXIT_MOUSELOCK" desc="Text displayed in the bubble to tell users how to escape from mouselock mode (where the mouse cursor is hidden) by activating Chrome OS's Overview mode. Please surround the name of the key (e.g. 'Overview') in pipe characters so it can be rendered as a key.">
+ Press |<ph name="ACCELERATOR">$1<ex>Overview</ex></ph>| to show your cursor
+ </message>
+ <message name="IDS_PRESS_TO_EXIT_MOUSELOCK_TWO_KEYS" desc="Text displayed in the bubble to tell users how to escape from mouselock mode (where the mouse cursor is hidden) by activating Chrome OS's Overview mode, in the case where two keys must be pressed together. Please surround the names of the keys (e.g. 'Overview') in pipe characters so it can be rendered as a key.">
+ Press |<ph name="ACCELERATOR1">$1<ex>Search</ex></ph>| + |<ph name="ACCELERATOR2">$2<ex>Overview</ex></ph>| to show your cursor
+ </message>
</grit-part>
diff --git a/chromium/components/fullscreen_control_strings_grdp/IDS_FULLSCREEN_HOLD_ESC_TO_EXIT_FULLSCREEN.png.sha1 b/chromium/components/fullscreen_control_strings_grdp/IDS_FULLSCREEN_HOLD_TO_EXIT_FULLSCREEN.png.sha1
index eabb423a156..eabb423a156 100644
--- a/chromium/components/fullscreen_control_strings_grdp/IDS_FULLSCREEN_HOLD_ESC_TO_EXIT_FULLSCREEN.png.sha1
+++ b/chromium/components/fullscreen_control_strings_grdp/IDS_FULLSCREEN_HOLD_TO_EXIT_FULLSCREEN.png.sha1
diff --git a/chromium/components/fullscreen_control_strings_grdp/IDS_FULLSCREEN_PRESS_ESC_TO_EXIT_FULLSCREEN.png.sha1 b/chromium/components/fullscreen_control_strings_grdp/IDS_FULLSCREEN_PRESS_TO_EXIT_FULLSCREEN.png.sha1
index f4f6c339cda..f4f6c339cda 100644
--- a/chromium/components/fullscreen_control_strings_grdp/IDS_FULLSCREEN_PRESS_ESC_TO_EXIT_FULLSCREEN.png.sha1
+++ b/chromium/components/fullscreen_control_strings_grdp/IDS_FULLSCREEN_PRESS_TO_EXIT_FULLSCREEN.png.sha1
diff --git a/chromium/components/fullscreen_control_strings_grdp/IDS_FULLSCREEN_PRESS_TO_EXIT_FULLSCREEN_TWO_KEYS.png.sha1 b/chromium/components/fullscreen_control_strings_grdp/IDS_FULLSCREEN_PRESS_TO_EXIT_FULLSCREEN_TWO_KEYS.png.sha1
new file mode 100644
index 00000000000..79a03cf7074
--- /dev/null
+++ b/chromium/components/fullscreen_control_strings_grdp/IDS_FULLSCREEN_PRESS_TO_EXIT_FULLSCREEN_TWO_KEYS.png.sha1
@@ -0,0 +1 @@
+2ee33ccf41f4252fed184bfa12ba0639a62282d3 \ No newline at end of file
diff --git a/chromium/components/fullscreen_control_strings_grdp/IDS_PRESS_TO_EXIT_MOUSELOCK.png.sha1 b/chromium/components/fullscreen_control_strings_grdp/IDS_PRESS_TO_EXIT_MOUSELOCK.png.sha1
new file mode 100644
index 00000000000..5c4eaaea288
--- /dev/null
+++ b/chromium/components/fullscreen_control_strings_grdp/IDS_PRESS_TO_EXIT_MOUSELOCK.png.sha1
@@ -0,0 +1 @@
+6dcd489062a9bdba9d982b7034a95aee2b4083ef \ No newline at end of file
diff --git a/chromium/components/fullscreen_control_strings_grdp/IDS_PRESS_TO_EXIT_MOUSELOCK_TWO_KEYS.png.sha1 b/chromium/components/fullscreen_control_strings_grdp/IDS_PRESS_TO_EXIT_MOUSELOCK_TWO_KEYS.png.sha1
new file mode 100644
index 00000000000..b746df7b099
--- /dev/null
+++ b/chromium/components/fullscreen_control_strings_grdp/IDS_PRESS_TO_EXIT_MOUSELOCK_TWO_KEYS.png.sha1
@@ -0,0 +1 @@
+8bd44112256eb50717633978a56c91360121b52b \ No newline at end of file
diff --git a/chromium/components/gcm_driver/crypto/BUILD.gn b/chromium/components/gcm_driver/crypto/BUILD.gn
index e4f6e45a4f3..34319118279 100644
--- a/chromium/components/gcm_driver/crypto/BUILD.gn
+++ b/chromium/components/gcm_driver/crypto/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-import("//build/config/crypto.gni")
+import("//crypto/features.gni")
static_library("crypto") {
sources = [
diff --git a/chromium/components/gcm_driver/crypto/gcm_message_cryptographer.h b/chromium/components/gcm_driver/crypto/gcm_message_cryptographer.h
index 1332708e0d9..0c30316dbf7 100644
--- a/chromium/components/gcm_driver/crypto/gcm_message_cryptographer.h
+++ b/chromium/components/gcm_driver/crypto/gcm_message_cryptographer.h
@@ -10,7 +10,6 @@
#include <memory>
#include <string>
-#include "base/compiler_specific.h"
#include "base/gtest_prod_util.h"
#include "base/strings/string_piece.h"
@@ -100,14 +99,14 @@ class GCMMessageCryptographer {
// |plaintext|: The plaintext that is to be encrypted.
// |*record_size|: Out parameter in which the record size will be written.
// |*ciphertext|: Out parameter in which the ciphertext will be written.
- bool Encrypt(const base::StringPiece& recipient_public_key,
- const base::StringPiece& sender_public_key,
- const base::StringPiece& ecdh_shared_secret,
- const base::StringPiece& auth_secret,
- const base::StringPiece& salt,
- const base::StringPiece& plaintext,
- size_t* record_size,
- std::string* ciphertext) const WARN_UNUSED_RESULT;
+ [[nodiscard]] bool Encrypt(const base::StringPiece& recipient_public_key,
+ const base::StringPiece& sender_public_key,
+ const base::StringPiece& ecdh_shared_secret,
+ const base::StringPiece& auth_secret,
+ const base::StringPiece& salt,
+ const base::StringPiece& plaintext,
+ size_t* record_size,
+ std::string* ciphertext) const;
// Decrypts the |ciphertext| in accordance with the Web Push Encryption scheme
// this cryptographer represents, storing the result in |*plaintext|. Returns
@@ -122,14 +121,14 @@ class GCMMessageCryptographer {
// |record_size|: Size of a single record. Must be larger than or equal to
// len(plaintext) plus the ciphertext's overhead (18 bytes).
// |*plaintext|: Out parameter in which the plaintext will be written.
- bool Decrypt(const base::StringPiece& recipient_public_key,
- const base::StringPiece& sender_public_key,
- const base::StringPiece& ecdh_shared_secret,
- const base::StringPiece& auth_secret,
- const base::StringPiece& salt,
- const base::StringPiece& ciphertext,
- size_t record_size,
- std::string* plaintext) const WARN_UNUSED_RESULT;
+ [[nodiscard]] bool Decrypt(const base::StringPiece& recipient_public_key,
+ const base::StringPiece& sender_public_key,
+ const base::StringPiece& ecdh_shared_secret,
+ const base::StringPiece& auth_secret,
+ const base::StringPiece& salt,
+ const base::StringPiece& ciphertext,
+ size_t record_size,
+ std::string* plaintext) const;
private:
FRIEND_TEST_ALL_PREFIXES(GCMMessageCryptographerTest, AuthSecretAffectsPRK);
diff --git a/chromium/components/gcm_driver/crypto/p256_key_util.h b/chromium/components/gcm_driver/crypto/p256_key_util.h
index 05bd36c6e9c..e47df5c5d03 100644
--- a/chromium/components/gcm_driver/crypto/p256_key_util.h
+++ b/chromium/components/gcm_driver/crypto/p256_key_util.h
@@ -7,7 +7,6 @@
#include <string>
-#include "base/compiler_specific.h"
#include "base/strings/string_piece.h"
namespace crypto {
@@ -19,14 +18,14 @@ namespace gcm {
// Writes the public key associated with the |key| to |*public_key| in
// uncompressed point format. That is, a 65-octet sequence that starts with a
// 0x04 octet. Returns whether the public key could be extracted successfully.
-bool GetRawPublicKey(const crypto::ECPrivateKey& key,
- std::string* public_key) WARN_UNUSED_RESULT;
+[[nodiscard]] bool GetRawPublicKey(const crypto::ECPrivateKey& key,
+ std::string* public_key);
// Writes the private key associated with the |key| to |*private_key| as a PKCS
// #8 PrivateKeyInfo block. Returns whether the private key could be extracted
// successfully.
-bool GetRawPrivateKey(const crypto::ECPrivateKey& key,
- std::string* private_key) WARN_UNUSED_RESULT;
+[[nodiscard]] bool GetRawPrivateKey(const crypto::ECPrivateKey& key,
+ std::string* private_key);
// Computes the shared secret between |key| and |peer_public_key|.The
// |peer_public_key| must be an octet string in uncompressed form per
@@ -34,9 +33,10 @@ bool GetRawPrivateKey(const crypto::ECPrivateKey& key,
//
// Returns whether the secret could be computed, and was written to the out
// argument.
-bool ComputeSharedP256Secret(crypto::ECPrivateKey& key,
- const base::StringPiece& peer_public_key,
- std::string* out_shared_secret) WARN_UNUSED_RESULT;
+[[nodiscard]] bool ComputeSharedP256Secret(
+ crypto::ECPrivateKey& key,
+ const base::StringPiece& peer_public_key,
+ std::string* out_shared_secret);
} // namespace gcm
diff --git a/chromium/components/gcm_driver/features.cc b/chromium/components/gcm_driver/features.cc
index 9f6507687b1..a6ff0709b56 100644
--- a/chromium/components/gcm_driver/features.cc
+++ b/chromium/components/gcm_driver/features.cc
@@ -6,6 +6,7 @@
#include "base/metrics/field_trial_param_associator.h"
#include "base/metrics/field_trial_params.h"
#include "base/strings/string_number_conversions.h"
+#include "base/time/time.h"
#include <algorithm>
#include <map>
diff --git a/chromium/components/gcm_driver/features.h b/chromium/components/gcm_driver/features.h
index 9539efe6e65..a6fe8bb10c8 100644
--- a/chromium/components/gcm_driver/features.h
+++ b/chromium/components/gcm_driver/features.h
@@ -7,6 +7,10 @@
#include "base/feature_list.h"
+namespace base {
+class TimeDelta;
+}
+
namespace gcm {
namespace features {
diff --git a/chromium/components/gcm_driver/gcm_desktop_utils.cc b/chromium/components/gcm_driver/gcm_desktop_utils.cc
index b24d10ec526..6eac900aa05 100644
--- a/chromium/components/gcm_driver/gcm_desktop_utils.cc
+++ b/chromium/components/gcm_driver/gcm_desktop_utils.cc
@@ -21,17 +21,17 @@ namespace gcm {
namespace {
GCMClient::ChromePlatform GetPlatform() {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
return GCMClient::PLATFORM_WIN;
-#elif defined(OS_APPLE)
+#elif BUILDFLAG(IS_APPLE)
return GCMClient::PLATFORM_MAC;
-#elif defined(OS_IOS)
+#elif BUILDFLAG(IS_IOS)
return GCMClient::PLATFORM_IOS;
-#elif defined(OS_ANDROID)
+#elif BUILDFLAG(IS_ANDROID)
return GCMClient::PLATFORM_ANDROID;
#elif BUILDFLAG(IS_CHROMEOS_ASH)
return GCMClient::PLATFORM_CROS;
-#elif defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
+#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
return GCMClient::PLATFORM_LINUX;
#else
// For all other platforms, return as LINUX.
diff --git a/chromium/components/global_media_controls/public/media_item_manager.h b/chromium/components/global_media_controls/public/media_item_manager.h
index 0c840897759..e53b7a14ad8 100644
--- a/chromium/components/global_media_controls/public/media_item_manager.h
+++ b/chromium/components/global_media_controls/public/media_item_manager.h
@@ -5,6 +5,7 @@
#ifndef COMPONENTS_GLOBAL_MEDIA_CONTROLS_PUBLIC_MEDIA_ITEM_MANAGER_H_
#define COMPONENTS_GLOBAL_MEDIA_CONTROLS_PUBLIC_MEDIA_ITEM_MANAGER_H_
+#include <memory>
#include <string>
#include "base/component_export.h"
diff --git a/chromium/components/global_media_controls/public/views/media_item_ui_view_unittest.cc b/chromium/components/global_media_controls/public/views/media_item_ui_view_unittest.cc
index 1327564603a..fd758248cb5 100644
--- a/chromium/components/global_media_controls/public/views/media_item_ui_view_unittest.cc
+++ b/chromium/components/global_media_controls/public/views/media_item_ui_view_unittest.cc
@@ -132,11 +132,11 @@ class MediaItemUIViewTest : public views::ViewsTestBase {
GetFocusManager()->SetFocusedView(item_ui_->GetDismissButtonForTesting());
// On Mac OS, we need to use the space bar to press a button.
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
ui::KeyboardCode button_press_keycode = ui::VKEY_SPACE;
#else
ui::KeyboardCode button_press_keycode = ui::VKEY_RETURN;
-#endif // defined(OS_MAC)
+#endif // BUILDFLAG(IS_MAC)
ui::test::EventGenerator generator(GetRootWindow(widget_.get()));
generator.PressKey(button_press_keycode, 0);
diff --git a/chromium/components/grpc_support/bidirectional_stream_unittest.cc b/chromium/components/grpc_support/bidirectional_stream_unittest.cc
index 189022f66b3..43d16a053c7 100644
--- a/chromium/components/grpc_support/bidirectional_stream_unittest.cc
+++ b/chromium/components/grpc_support/bidirectional_stream_unittest.cc
@@ -643,7 +643,7 @@ TEST_P(MAYBE_BidirectionalStreamTest, ReadFailsBeforeRequestStarted) {
}
// TODO(https://crbug.com/880474): This test is flaky on fuchsia_x64 builder.
-#if defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_FUCHSIA)
#define MAYBE_StreamFailBeforeReadIsExecutedOnNetworkThread \
DISABLED_StreamFailBeforeReadIsExecutedOnNetworkThread
#else
@@ -725,7 +725,7 @@ TEST_P(MAYBE_BidirectionalStreamTest, StreamFailAfterStreamReadyCallback) {
}
// TODO(crbug.com/1246489): Flaky on Win64.
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#define MAYBE_StreamFailBeforeWriteIsExecutedOnNetworkThread \
DISABLED_StreamFailBeforeWriteIsExecutedOnNetworkThread
#else
diff --git a/chromium/components/guest_view/browser/BUILD.gn b/chromium/components/guest_view/browser/BUILD.gn
index 896e0191f55..5bc153ac065 100644
--- a/chromium/components/guest_view/browser/BUILD.gn
+++ b/chromium/components/guest_view/browser/BUILD.gn
@@ -23,8 +23,8 @@ static_library("browser") {
"//components/guest_view/browser/guest_view_manager_delegate.cc",
"//components/guest_view/browser/guest_view_manager_delegate.h",
"//components/guest_view/browser/guest_view_manager_factory.h",
- "//components/guest_view/browser/guest_view_message_filter.cc",
- "//components/guest_view/browser/guest_view_message_filter.h",
+ "//components/guest_view/browser/guest_view_message_handler.cc",
+ "//components/guest_view/browser/guest_view_message_handler.h",
]
public_deps = [
@@ -34,12 +34,10 @@ static_library("browser") {
deps = [
"//build:chromeos_buildflags",
"//components/crash/core/common:crash_key",
- "//components/keyed_service/content",
- "//components/keyed_service/core",
+ "//components/guest_view/common:mojom",
"//components/zoom",
"//content/public/browser",
"//content/public/common",
- "//ipc",
"//third_party/blink/public/common",
"//url",
]
diff --git a/chromium/components/guest_view/browser/DEPS b/chromium/components/guest_view/browser/DEPS
index 5b0cbd043af..84bd166d3ec 100644
--- a/chromium/components/guest_view/browser/DEPS
+++ b/chromium/components/guest_view/browser/DEPS
@@ -1,11 +1,8 @@
include_rules = [
"+components/crash/core/common/crash_key.h",
- "+components/keyed_service/content/browser_context_keyed_service_shutdown_notifier_factory.h",
- "+components/keyed_service/core/keyed_service_shutdown_notifier.h",
"+components/zoom",
"+content/public/browser",
"+content/public/common",
- "+ipc",
"+third_party/blink/public/common/page/page_zoom.h",
"+third_party/blink/public/common/input/web_gesture_event.h",
"+third_party/blink/public/common/input/web_input_event.h",
diff --git a/chromium/components/guest_view/browser/bad_message.cc b/chromium/components/guest_view/browser/bad_message.cc
index 81240a02d87..28f5345cf1b 100644
--- a/chromium/components/guest_view/browser/bad_message.cc
+++ b/chromium/components/guest_view/browser/bad_message.cc
@@ -6,7 +6,6 @@
#include "base/logging.h"
#include "base/metrics/histogram_functions.h"
-#include "content/public/browser/browser_message_filter.h"
#include "content/public/browser/render_process_host.h"
namespace guest_view {
@@ -37,11 +36,5 @@ void ReceivedBadMessage(int render_process_id, BadMessageReason reason) {
ReceivedBadMessage(rph, reason);
}
-void ReceivedBadMessage(content::BrowserMessageFilter* filter,
- BadMessageReason reason) {
- LogBadMessage(reason);
- filter->ShutdownForBadMessage();
-}
-
} // namespace bad_message
} // namespace guest_view
diff --git a/chromium/components/guest_view/browser/bad_message.h b/chromium/components/guest_view/browser/bad_message.h
index 1a38fa6daa9..3de2636bf84 100644
--- a/chromium/components/guest_view/browser/bad_message.h
+++ b/chromium/components/guest_view/browser/bad_message.h
@@ -6,7 +6,6 @@
#define COMPONENTS_GUEST_VIEW_BROWSER_BAD_MESSAGE_H_
namespace content {
-class BrowserMessageFilter;
class RenderProcessHost;
} // namespace content
@@ -41,12 +40,6 @@ void ReceivedBadMessage(content::RenderProcessHost* host,
BadMessageReason reason);
void ReceivedBadMessage(int render_process_id, BadMessageReason reason);
-// Called when a browser message filter receives a bad IPC message from a
-// renderer process. Logs the event, records a histogram metric for the
-// |reason|, and terminates the process for |filter|.
-void ReceivedBadMessage(content::BrowserMessageFilter* filter,
- BadMessageReason reason);
-
} // namespace bad_message
} // namespace guest_view
diff --git a/chromium/components/guest_view/browser/guest_view_base.cc b/chromium/components/guest_view/browser/guest_view_base.cc
index 8fe70ba32cd..3b579b818d1 100644
--- a/chromium/components/guest_view/browser/guest_view_base.cc
+++ b/chromium/components/guest_view/browser/guest_view_base.cc
@@ -15,7 +15,6 @@
#include "components/guest_view/browser/guest_view_event.h"
#include "components/guest_view/browser/guest_view_manager.h"
#include "components/guest_view/common/guest_view_constants.h"
-#include "components/guest_view/common/guest_view_messages.h"
#include "components/zoom/page_zoom.h"
#include "components/zoom/zoom_controller.h"
#include "content/public/browser/color_chooser.h"
@@ -239,7 +238,8 @@ void GuestViewBase::InitWithWebContents(
GetGuestViewManager()->AddGuest(guest_instance_id_, guest_web_contents);
// Populate the view instance ID if we have it on creation.
- create_params.GetInteger(kParameterInstanceId, &view_instance_id_);
+ view_instance_id_ = create_params.FindIntKey(kParameterInstanceId)
+ .value_or(view_instance_id_);
SetUpSizing(create_params);
@@ -466,7 +466,8 @@ void GuestViewBase::Destroy(bool also_delete) {
void GuestViewBase::SetAttachParams(const base::DictionaryValue& params) {
attach_params_.reset(params.DeepCopy());
- attach_params_->GetInteger(kParameterInstanceId, &view_instance_id_);
+ view_instance_id_ = attach_params_->FindIntKey(kParameterInstanceId)
+ .value_or(view_instance_id_);
}
void GuestViewBase::SetOpener(GuestViewBase* guest) {
@@ -491,14 +492,18 @@ void GuestViewBase::WillAttach(WebContents* embedder_web_contents,
bool is_full_page_plugin,
base::OnceClosure completion_callback) {
WillAttach(embedder_web_contents, nullptr, element_instance_id,
- is_full_page_plugin, std::move(completion_callback));
-}
-
-void GuestViewBase::WillAttach(WebContents* embedder_web_contents,
- content::RenderFrameHost* outer_contents_frame,
- int element_instance_id,
- bool is_full_page_plugin,
- base::OnceClosure completion_callback) {
+ is_full_page_plugin, std::move(completion_callback),
+ base::NullCallback());
+}
+
+void GuestViewBase::WillAttach(
+ WebContents* embedder_web_contents,
+ content::RenderFrameHost* outer_contents_frame,
+ int element_instance_id,
+ bool is_full_page_plugin,
+ base::OnceClosure completion_callback,
+ GuestViewMessageHandler::AttachToEmbedderFrameCallback
+ attachment_callback) {
// Stop tracking the old embedder's zoom level.
if (owner_web_contents())
StopTrackingEmbedderZoomLevel();
@@ -524,14 +529,12 @@ void GuestViewBase::WillAttach(WebContents* embedder_web_contents,
owner_web_contents_->AttachInnerWebContents(
base::WrapUnique<WebContents>(web_contents()), outer_contents_frame,
is_full_page_plugin);
- // TODO(ekaramad): MimeHandlerViewGuest might not need this ACK
- // (https://crbug.com/659750).
// We don't ACK until after AttachToOuterWebContentsFrame, so that
- // |outer_contents_frame| gets swapped before the AttachIframeGuest callback
- // is run. We also need to send the ACK before queued events are sent in
- // DidAttach.
- embedder_web_contents->GetMainFrame()->Send(
- new GuestViewMsg_AttachToEmbedderFrame_ACK(element_instance_id));
+ // |outer_contents_frame| gets swapped before the AttachToEmbedderFrame
+ // callback is run. We also need to send the ACK before queued events are sent
+ // in DidAttach.
+ if (attachment_callback)
+ std::move(attachment_callback).Run();
// Completing attachment will resume suspended resource loads and then send
// queued events.
@@ -710,6 +713,7 @@ content::RenderWidgetHost* GuestViewBase::GetOwnerRenderWidgetHost() {
// embedded in a cross-process frame, this method should be overrode for that
// specific guest type. For all other guests, the owner RenderWidgetHost is
// that of the owner WebContents.
+ DCHECK(!CanBeEmbeddedInsideCrossProcessFrames());
auto* owner = GetOwnerWebContents();
if (owner && owner->GetRenderWidgetHostView())
return owner->GetRenderWidgetHostView()->GetRenderWidgetHost();
@@ -722,6 +726,7 @@ content::SiteInstance* GuestViewBase::GetOwnerSiteInstance() {
// embedded in a cross-process frame, this method should be overrode for that
// specific guest type. For all other guests, the owner site instance can be
// from the owner WebContents.
+ DCHECK(!CanBeEmbeddedInsideCrossProcessFrames());
if (auto* owner_contents = GetOwnerWebContents())
return owner_contents->GetSiteInstance();
return nullptr;
@@ -730,12 +735,14 @@ content::SiteInstance* GuestViewBase::GetOwnerSiteInstance() {
void GuestViewBase::AttachToOuterWebContentsFrame(
content::RenderFrameHost* embedder_frame,
int32_t element_instance_id,
- bool is_full_page_plugin) {
+ bool is_full_page_plugin,
+ GuestViewMessageHandler::AttachToEmbedderFrameCallback
+ attachment_callback) {
auto completion_callback =
base::BindOnce(&GuestViewBase::DidAttach, weak_ptr_factory_.GetWeakPtr());
WillAttach(WebContents::FromRenderFrameHost(embedder_frame), embedder_frame,
element_instance_id, is_full_page_plugin,
- std::move(completion_callback));
+ std::move(completion_callback), std::move(attachment_callback));
}
void GuestViewBase::OnZoomChanged(
@@ -814,15 +821,15 @@ void GuestViewBase::SetUpSizing(const base::DictionaryValue& params) {
params.FindBoolKey(kAttributeAutoSize);
bool auto_size_enabled = auto_size_enabled_opt.value_or(auto_size_enabled_);
- int max_height = max_auto_size_.height();
- int max_width = max_auto_size_.width();
- params.GetInteger(kAttributeMaxHeight, &max_height);
- params.GetInteger(kAttributeMaxWidth, &max_width);
+ int max_height =
+ params.FindIntKey(kAttributeMaxHeight).value_or(max_auto_size_.height());
+ int max_width =
+ params.FindIntKey(kAttributeMaxWidth).value_or(max_auto_size_.width());
- int min_height = min_auto_size_.height();
- int min_width = min_auto_size_.width();
- params.GetInteger(kAttributeMinHeight, &min_height);
- params.GetInteger(kAttributeMinWidth, &min_width);
+ int min_height =
+ params.FindIntKey(kAttributeMinHeight).value_or(min_auto_size_.height());
+ int min_width =
+ params.FindIntKey(kAttributeMinWidth).value_or(min_auto_size_.width());
double element_height = params.FindDoublePath(kElementHeight).value_or(0.0);
double element_width = params.FindDoublePath(kElementWidth).value_or(0.0);
@@ -912,7 +919,7 @@ void GuestViewBase::SetOwnerHost() {
: std::string();
}
-bool GuestViewBase::CanBeEmbeddedInsideCrossProcessFrames() {
+bool GuestViewBase::CanBeEmbeddedInsideCrossProcessFrames() const {
return false;
}
diff --git a/chromium/components/guest_view/browser/guest_view_base.h b/chromium/components/guest_view/browser/guest_view_base.h
index 13074cab054..c6dc516e006 100644
--- a/chromium/components/guest_view/browser/guest_view_base.h
+++ b/chromium/components/guest_view/browser/guest_view_base.h
@@ -11,6 +11,7 @@
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/values.h"
+#include "components/guest_view/browser/guest_view_message_handler.h"
#include "components/guest_view/common/guest_view_constants.h"
#include "components/zoom/zoom_observer.h"
#include "content/public/browser/browser_plugin_guest_delegate.h"
@@ -164,7 +165,10 @@ class GuestViewBase : public content::BrowserPluginGuestDelegate,
// Returns the user browser context of the embedder.
content::BrowserContext* browser_context() const { return browser_context_; }
- // Returns the URL of the owner WebContents.
+ // Returns the URL of the owner WebContents' SiteInstance.
+ // WARNING: Be careful using this with GuestViews where
+ // `CanBeEmbeddedInsideCrossProcessFrames` is true. This returns the site of
+ // the WebContents, not the embedding frame.
const GURL& GetOwnerSiteURL() const;
// Returns the host of the owner WebContents. For extensions, this is the
@@ -195,13 +199,16 @@ class GuestViewBase : public content::BrowserPluginGuestDelegate,
// |embedder_frame| is a frame in the embedder WebContents (owned by a
// HTMLFrameOwnerElement associated with the GuestView's element in the
// embedder process) which will be used for attaching.
- void AttachToOuterWebContentsFrame(content::RenderFrameHost* embedder_frame,
- int32_t element_instance_id,
- bool is_full_page_plugin);
+ void AttachToOuterWebContentsFrame(
+ content::RenderFrameHost* embedder_frame,
+ int32_t element_instance_id,
+ bool is_full_page_plugin,
+ GuestViewMessageHandler::AttachToEmbedderFrameCallback
+ attachment_callback);
// Returns true if the corresponding guest is allowed to be embedded inside an
// <iframe> which is cross process.
- virtual bool CanBeEmbeddedInsideCrossProcessFrames();
+ virtual bool CanBeEmbeddedInsideCrossProcessFrames() const;
protected:
explicit GuestViewBase(content::WebContents* owner_web_contents);
@@ -400,7 +407,9 @@ class GuestViewBase : public content::BrowserPluginGuestDelegate,
content::RenderFrameHost* outer_contents_frame,
int browser_plugin_instance_id,
bool is_full_page_plugin,
- base::OnceClosure completion_callback);
+ base::OnceClosure completion_callback,
+ GuestViewMessageHandler::AttachToEmbedderFrameCallback
+ attachment_callback);
// This guest tracks the lifetime of the WebContents specified by
// |owner_web_contents_|. If |owner_web_contents_| is destroyed then this
diff --git a/chromium/components/guest_view/browser/guest_view_manager.h b/chromium/components/guest_view/browser/guest_view_manager.h
index c76e6604427..105ce7af2d6 100644
--- a/chromium/components/guest_view/browser/guest_view_manager.h
+++ b/chromium/components/guest_view/browser/guest_view_manager.h
@@ -139,7 +139,7 @@ class GuestViewManager : public content::BrowserPluginGuestManager,
protected:
friend class GuestViewBase;
friend class GuestViewEvent;
- friend class GuestViewMessageFilter;
+ friend class GuestViewMessageHandler;
class EmbedderRenderProcessHostObserver;
diff --git a/chromium/components/guest_view/browser/guest_view_message_filter.cc b/chromium/components/guest_view/browser/guest_view_message_filter.cc
deleted file mode 100644
index 9a762e36d22..00000000000
--- a/chromium/components/guest_view/browser/guest_view_message_filter.cc
+++ /dev/null
@@ -1,177 +0,0 @@
-// Copyright 2015 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.
-
-#include "components/guest_view/browser/guest_view_message_filter.h"
-
-#include <memory>
-
-#include "base/memory/singleton.h"
-#include "components/guest_view/browser/bad_message.h"
-#include "components/guest_view/browser/guest_view_base.h"
-#include "components/guest_view/browser/guest_view_manager.h"
-#include "components/guest_view/browser/guest_view_manager_delegate.h"
-#include "components/guest_view/common/guest_view_messages.h"
-#include "components/keyed_service/content/browser_context_keyed_service_shutdown_notifier_factory.h"
-#include "content/public/browser/render_frame_host.h"
-#include "content/public/browser/render_process_host.h"
-#include "content/public/browser/render_view_host.h"
-#include "ipc/ipc_message_macros.h"
-
-using content::BrowserContext;
-using content::BrowserThread;
-using content::RenderFrameHost;
-using content::WebContents;
-
-namespace guest_view {
-
-namespace {
-
-class ShutdownNotifierFactory
- : public BrowserContextKeyedServiceShutdownNotifierFactory {
- public:
- static ShutdownNotifierFactory* GetInstance() {
- return base::Singleton<ShutdownNotifierFactory>::get();
- }
-
- private:
- friend struct base::DefaultSingletonTraits<ShutdownNotifierFactory>;
-
- ShutdownNotifierFactory()
- : BrowserContextKeyedServiceShutdownNotifierFactory(
- "GuestViewMessageFilter") {}
- ~ShutdownNotifierFactory() override = default;
-};
-
-} // namespace
-
-GuestViewMessageFilter::GuestViewMessageFilter(
- const uint32_t* message_classes_to_filter,
- size_t num_message_classes_to_filter,
- int render_process_id,
- BrowserContext* context)
- : BrowserMessageFilter(message_classes_to_filter,
- num_message_classes_to_filter),
- render_process_id_(render_process_id),
- browser_context_(context) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- browser_context_shutdown_subscription_ =
- ShutdownNotifierFactory::GetInstance()->Get(context)->Subscribe(
- base::BindRepeating(&GuestViewMessageFilter::OnBrowserContextShutdown,
- base::Unretained(this)));
-}
-
-GuestViewMessageFilter::~GuestViewMessageFilter() {
- // The filter is destroyed on the UI thread as
- // |browser_context_shutdown_subscription_| was created there.
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
-}
-
-void GuestViewMessageFilter::EnsureShutdownNotifierFactoryBuilt() {
- ShutdownNotifierFactory::GetInstance();
-}
-
-void GuestViewMessageFilter::OnBrowserContextShutdown() {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- browser_context_ = nullptr;
- browser_context_shutdown_subscription_ = {};
-}
-
-GuestViewManager* GuestViewMessageFilter::GetOrCreateGuestViewManager() {
- DCHECK(browser_context_);
- auto* manager = GuestViewManager::FromBrowserContext(browser_context_);
- if (!manager) {
- manager = GuestViewManager::CreateWithDelegate(
- browser_context_, std::make_unique<GuestViewManagerDelegate>());
- }
- return manager;
-}
-
-GuestViewManager* GuestViewMessageFilter::GetGuestViewManagerOrKill() {
- DCHECK(browser_context_);
- auto* manager = GuestViewManager::FromBrowserContext(browser_context_);
- if (!manager) {
- bad_message::ReceivedBadMessage(
- this, bad_message::GVMF_UNEXPECTED_MESSAGE_BEFORE_GVM_CREATION);
- }
- return manager;
-}
-
-void GuestViewMessageFilter::OverrideThreadForMessage(
- const IPC::Message& message,
- BrowserThread::ID* thread) {
- if (IPC_MESSAGE_CLASS(message) == GuestViewMsgStart)
- *thread = BrowserThread::UI;
-}
-
-void GuestViewMessageFilter::OnDestruct() const {
- BrowserThread::DeleteOnUIThread::Destruct(this);
-}
-
-bool GuestViewMessageFilter::OnMessageReceived(const IPC::Message& message) {
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(GuestViewMessageFilter, message)
- IPC_MESSAGE_HANDLER(GuestViewHostMsg_AttachToEmbedderFrame,
- OnAttachToEmbedderFrame)
- IPC_MESSAGE_HANDLER(GuestViewHostMsg_ViewCreated, OnViewCreated)
- IPC_MESSAGE_HANDLER(GuestViewHostMsg_ViewGarbageCollected,
- OnViewGarbageCollected)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
- return handled;
-}
-
-void GuestViewMessageFilter::OnViewCreated(int view_instance_id,
- const std::string& view_type) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- if (!browser_context_)
- return;
- GetOrCreateGuestViewManager()->ViewCreated(render_process_id_,
- view_instance_id, view_type);
-}
-
-void GuestViewMessageFilter::OnViewGarbageCollected(int view_instance_id) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- if (!browser_context_)
- return;
- GetOrCreateGuestViewManager()->ViewGarbageCollected(render_process_id_,
- view_instance_id);
-}
-
-void GuestViewMessageFilter::OnAttachToEmbedderFrame(
- int embedder_local_render_frame_id,
- int element_instance_id,
- int guest_instance_id,
- const base::DictionaryValue& params) {
- if (!browser_context_)
- return;
-
- // We should have a GuestViewManager at this point. If we don't then the
- // embedder is misbehaving.
- auto* manager = GetGuestViewManagerOrKill();
- if (!manager)
- return;
-
- content::WebContents* guest_web_contents =
- manager->GetGuestByInstanceIDSafely(guest_instance_id,
- render_process_id_);
- if (!guest_web_contents)
- return;
-
- auto* guest = GuestViewBase::FromWebContents(guest_web_contents);
- content::WebContents* owner_web_contents = guest->owner_web_contents();
- DCHECK(owner_web_contents);
- auto* embedder_frame = RenderFrameHost::FromID(
- render_process_id_, embedder_local_render_frame_id);
-
- // Update the guest manager about the attachment.
- // This sets up the embedder and guest pairing information inside
- // the manager.
- manager->AttachGuest(render_process_id_, element_instance_id,
- guest_instance_id, params);
-
- guest->AttachToOuterWebContentsFrame(embedder_frame, element_instance_id,
- false /* is_full_page_plugin */);
-}
-
-} // namespace guest_view
diff --git a/chromium/components/guest_view/browser/guest_view_message_filter.h b/chromium/components/guest_view/browser/guest_view_message_filter.h
deleted file mode 100644
index 6403f21892d..00000000000
--- a/chromium/components/guest_view/browser/guest_view_message_filter.h
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright 2015 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.
-
-#ifndef COMPONENTS_GUEST_VIEW_BROWSER_GUEST_VIEW_MESSAGE_FILTER_H_
-#define COMPONENTS_GUEST_VIEW_BROWSER_GUEST_VIEW_MESSAGE_FILTER_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <string>
-
-#include "base/memory/raw_ptr.h"
-#include "components/keyed_service/core/keyed_service_shutdown_notifier.h"
-#include "content/public/browser/browser_message_filter.h"
-#include "content/public/browser/browser_thread.h"
-
-namespace base {
-class DictionaryValue;
-}
-
-namespace content {
-class BrowserContext;
-}
-
-namespace guest_view {
-class GuestViewManager;
-
-// This class filters out incoming GuestView-specific IPC messages from the
-// renderer process. It is created on the UI thread. Messages may be handled on
-// the IO thread or the UI thread.
-class GuestViewMessageFilter : public content::BrowserMessageFilter {
- public:
- GuestViewMessageFilter(const GuestViewMessageFilter&) = delete;
- GuestViewMessageFilter& operator=(const GuestViewMessageFilter&) = delete;
-
- static void EnsureShutdownNotifierFactoryBuilt();
-
- protected:
- GuestViewMessageFilter(const uint32_t* message_classes_to_filter,
- size_t num_message_classes_to_filter,
- int render_process_id,
- content::BrowserContext* context);
-
- ~GuestViewMessageFilter() override;
-
- // Returns the GuestViewManager for |browser_context_| if one already exists,
- // or creates and returns one for |browser_context_| otherwise.
- virtual GuestViewManager* GetOrCreateGuestViewManager();
-
- // Returns the GuestViewManager for |browser_context_| if it exists.
- // Callers consider the renderer to be misbehaving if we don't have a
- // GuestViewManager at this point, in which case we kill the renderer and
- // return nullptr.
- GuestViewManager* GetGuestViewManagerOrKill();
-
- // content::BrowserMessageFilter implementation.
- void OverrideThreadForMessage(const IPC::Message& message,
- content::BrowserThread::ID* thread) override;
- void OnDestruct() const override;
- bool OnMessageReceived(const IPC::Message& message) override;
-
- const int render_process_id_;
-
- // Should only be accessed on the UI thread.
- // May become null if this filter outlives the BrowserContext.
- raw_ptr<content::BrowserContext> browser_context_;
-
- private:
- friend class content::BrowserThread;
- friend class base::DeleteHelper<GuestViewMessageFilter>;
-
- // Message handlers on the UI thread.
- void OnAttachToEmbedderFrame(int embedder_local_render_frame_id,
- int element_instance_id,
- int guest_instance_id,
- const base::DictionaryValue& params);
- void OnViewCreated(int view_instance_id, const std::string& view_type);
- void OnViewGarbageCollected(int view_instance_id);
-
- void OnBrowserContextShutdown();
-
- base::CallbackListSubscription browser_context_shutdown_subscription_;
-};
-
-} // namespace guest_view
-
-#endif // COMPONENTS_GUEST_VIEW_BROWSER_GUEST_VIEW_MESSAGE_FILTER_H_
diff --git a/chromium/components/guest_view/browser/guest_view_message_handler.cc b/chromium/components/guest_view/browser/guest_view_message_handler.cc
new file mode 100644
index 00000000000..caf901e2ef3
--- /dev/null
+++ b/chromium/components/guest_view/browser/guest_view_message_handler.cc
@@ -0,0 +1,123 @@
+// Copyright 2022 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.
+
+#include "components/guest_view/browser/guest_view_message_handler.h"
+
+#include <memory>
+
+#include "components/guest_view/browser/bad_message.h"
+#include "components/guest_view/browser/guest_view_base.h"
+#include "components/guest_view/browser/guest_view_manager.h"
+#include "components/guest_view/browser/guest_view_manager_delegate.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_process_host.h"
+
+using content::BrowserThread;
+using content::RenderFrameHost;
+
+namespace guest_view {
+
+GuestViewMessageHandler::GuestViewMessageHandler(int render_process_id)
+ : render_process_id_(render_process_id) {}
+
+GuestViewMessageHandler::~GuestViewMessageHandler() = default;
+
+GuestViewManager* GuestViewMessageHandler::GetOrCreateGuestViewManager() {
+ auto* browser_context = GetBrowserContext();
+ auto* manager = GuestViewManager::FromBrowserContext(browser_context);
+ if (!manager) {
+ manager = GuestViewManager::CreateWithDelegate(
+ browser_context, CreateGuestViewManagerDelegate(browser_context));
+ }
+ return manager;
+}
+
+GuestViewManager* GuestViewMessageHandler::GetGuestViewManagerOrKill() {
+ auto* manager = GuestViewManager::FromBrowserContext(GetBrowserContext());
+ if (!manager) {
+ bad_message::ReceivedBadMessage(
+ render_process_id(),
+ bad_message::GVMF_UNEXPECTED_MESSAGE_BEFORE_GVM_CREATION);
+ }
+ return manager;
+}
+
+std::unique_ptr<GuestViewManagerDelegate>
+GuestViewMessageHandler::CreateGuestViewManagerDelegate(
+ content::BrowserContext* context) const {
+ return std::make_unique<GuestViewManagerDelegate>();
+}
+
+content::BrowserContext* GuestViewMessageHandler::GetBrowserContext() const {
+ auto* rph = content::RenderProcessHost::FromID(render_process_id());
+ return rph ? rph->GetBrowserContext() : nullptr;
+}
+
+void GuestViewMessageHandler::ViewCreated(int view_instance_id,
+ const std::string& view_type) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ if (!GetBrowserContext())
+ return;
+ GetOrCreateGuestViewManager()->ViewCreated(render_process_id(),
+ view_instance_id, view_type);
+}
+
+void GuestViewMessageHandler::ViewGarbageCollected(int view_instance_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ if (!GetBrowserContext())
+ return;
+ GetOrCreateGuestViewManager()->ViewGarbageCollected(render_process_id(),
+ view_instance_id);
+}
+
+void GuestViewMessageHandler::AttachToEmbedderFrame(
+ int embedder_local_render_frame_id,
+ int element_instance_id,
+ int guest_instance_id,
+ base::Value params,
+ AttachToEmbedderFrameCallback callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ if (!GetBrowserContext()) {
+ std::move(callback).Run();
+ return;
+ }
+
+ // We should have a GuestViewManager at this point. If we don't then the
+ // embedder is misbehaving.
+ auto* manager = GetGuestViewManagerOrKill();
+ if (!manager) {
+ // The renderer has been killed, and this event logged, by
+ // `ReceivedBadMessage`, so we can just return.
+ std::move(callback).Run();
+ return;
+ }
+
+ content::WebContents* guest_web_contents =
+ manager->GetGuestByInstanceIDSafely(guest_instance_id,
+ render_process_id());
+ if (!guest_web_contents) {
+ std::move(callback).Run();
+ return;
+ }
+
+ auto* guest = GuestViewBase::FromWebContents(guest_web_contents);
+ content::WebContents* owner_web_contents = guest->owner_web_contents();
+ DCHECK(owner_web_contents);
+ auto* embedder_frame = RenderFrameHost::FromID(
+ render_process_id(), embedder_local_render_frame_id);
+
+ // Update the guest manager about the attachment.
+ // This sets up the embedder and guest pairing information inside
+ // the manager.
+ manager->AttachGuest(render_process_id(), element_instance_id,
+ guest_instance_id,
+ base::Value::AsDictionaryValue(params));
+
+ guest->AttachToOuterWebContentsFrame(embedder_frame, element_instance_id,
+ false /* is_full_page_plugin */,
+ std::move(callback));
+}
+
+} // namespace guest_view
diff --git a/chromium/components/guest_view/browser/guest_view_message_handler.h b/chromium/components/guest_view/browser/guest_view_message_handler.h
new file mode 100644
index 00000000000..6ff5fba692e
--- /dev/null
+++ b/chromium/components/guest_view/browser/guest_view_message_handler.h
@@ -0,0 +1,64 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_GUEST_VIEW_BROWSER_GUEST_VIEW_MESSAGE_HANDLER_H_
+#define COMPONENTS_GUEST_VIEW_BROWSER_GUEST_VIEW_MESSAGE_HANDLER_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+
+#include "components/guest_view/common/guest_view.mojom.h"
+
+namespace content {
+class BrowserContext;
+}
+
+namespace guest_view {
+class GuestViewManager;
+class GuestViewManagerDelegate;
+
+class GuestViewMessageHandler : public mojom::GuestViewHost {
+ public:
+ GuestViewMessageHandler(const GuestViewMessageHandler&) = delete;
+ GuestViewMessageHandler& operator=(const GuestViewMessageHandler&) = delete;
+ ~GuestViewMessageHandler() override;
+
+ protected:
+ explicit GuestViewMessageHandler(int render_process_id);
+
+ int render_process_id() const { return render_process_id_; }
+
+ private:
+ // Returns the GuestViewManager for the BrowserContext of our associated
+ // render process if one already exists, otherwise creates and returns one.
+ GuestViewManager* GetOrCreateGuestViewManager();
+
+ // Returns the GuestViewManager for the BrowserContext of our associated
+ // render process if it exists. Callers consider the renderer to be
+ // misbehaving if we don't have a GuestViewManager at this point, in which
+ // case we kill the renderer and return nullptr.
+ GuestViewManager* GetGuestViewManagerOrKill();
+
+ virtual std::unique_ptr<GuestViewManagerDelegate>
+ CreateGuestViewManagerDelegate(content::BrowserContext* context) const;
+
+ content::BrowserContext* GetBrowserContext() const;
+
+ // mojom::GuestViewHost
+ void AttachToEmbedderFrame(int embedder_local_render_frame_id,
+ int element_instance_id,
+ int guest_instance_id,
+ base::Value params,
+ AttachToEmbedderFrameCallback callback) override;
+ void ViewCreated(int view_instance_id, const std::string& view_type) override;
+ void ViewGarbageCollected(int view_instance_id) override;
+
+ const int render_process_id_;
+};
+
+} // namespace guest_view
+
+#endif // COMPONENTS_GUEST_VIEW_BROWSER_GUEST_VIEW_MESSAGE_HANDLER_H_
diff --git a/chromium/components/guest_view/common/BUILD.gn b/chromium/components/guest_view/common/BUILD.gn
index 9916d95a111..da6741e5b57 100644
--- a/chromium/components/guest_view/common/BUILD.gn
+++ b/chromium/components/guest_view/common/BUILD.gn
@@ -1,15 +1,16 @@
+import("//mojo/public/tools/bindings/mojom.gni")
+
static_library("common") {
output_name = "guest_view_common"
sources = [
"guest_view_constants.cc",
"guest_view_constants.h",
- "guest_view_message_generator.cc",
- "guest_view_message_generator.h",
- "guest_view_messages.h",
]
+}
- deps = [
- "//base",
- "//ipc",
- ]
+mojom("mojom") {
+ cpp_only = true
+ disable_variants = true
+ sources = [ "guest_view.mojom" ]
+ public_deps = [ "//mojo/public/mojom/base" ]
}
diff --git a/chromium/components/guest_view/common/OWNERS b/chromium/components/guest_view/common/OWNERS
index 42444bcd16d..1feb5149750 100644
--- a/chromium/components/guest_view/common/OWNERS
+++ b/chromium/components/guest_view/common/OWNERS
@@ -1,2 +1,4 @@
-per-file *_messages*.h=set noparent
-per-file *_messages*.h=file://ipc/SECURITY_OWNERS
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
+per-file *_mojom_traits*.*=set noparent
+per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
diff --git a/chromium/components/guest_view/common/guest_view.mojom b/chromium/components/guest_view/common/guest_view.mojom
new file mode 100644
index 00000000000..8929e45a9d4
--- /dev/null
+++ b/chromium/components/guest_view/common/guest_view.mojom
@@ -0,0 +1,32 @@
+// Copyright 2022 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.
+
+module guest_view.mojom;
+
+import "mojo/public/mojom/base/values.mojom";
+
+// The renderer uses this interface to create GuestViews, make requests to the
+// browser to attach a GuestView to a container frame, and notify the browser
+// of state relating to a guest's container.
+interface GuestViewHost {
+ // We have a RenderFrame with routing id of |embedder_local_frame_routing_id|.
+ // We want this local frame to be replaced with a remote frame that points
+ // to a GuestView. This message will attach the local frame to the guest.
+ // The GuestView is identified by its ID: |guest_instance_id|.
+ AttachToEmbedderFrame(
+ int32 embedder_local_frame_routing_id,
+ int32 element_instance_id,
+ int32 guest_instance_id,
+ mojo_base.mojom.DictionaryValue params) => ();
+
+ // Sent by the renderer when a GuestView (identified by |view_instance_id|)
+ // has been created in JavaScript.
+ ViewCreated(int32 view_instance_id, string view_type);
+
+ // Sent by the renderer when a GuestView (identified by |view_instance_id|)
+ // has been garbage collected in JavaScript.
+ // TODO(mcnee): Instead of a separate message for cleanup, consider having
+ // `ViewCreated` incorporate a "keep alive" interface.
+ ViewGarbageCollected(int32 view_instance_id);
+};
diff --git a/chromium/components/guest_view/common/guest_view_message_generator.cc b/chromium/components/guest_view/common/guest_view_message_generator.cc
deleted file mode 100644
index 363c62a4be4..00000000000
--- a/chromium/components/guest_view/common/guest_view_message_generator.cc
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2015 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.
-
-// Get basic type definitions.
-#define IPC_MESSAGE_IMPL
-#include "components/guest_view/common/guest_view_message_generator.h"
-
-// Generate constructors.
-#include "ipc/struct_constructor_macros.h"
-#include "components/guest_view/common/guest_view_message_generator.h"
-
-// Generate param traits write methods.
-#include "ipc/param_traits_write_macros.h"
-namespace IPC {
-#include "components/guest_view/common/guest_view_message_generator.h"
-} // namespace IPC
-
-// Generate param traits read methods.
-#include "ipc/param_traits_read_macros.h"
-namespace IPC {
-#include "components/guest_view/common/guest_view_message_generator.h"
-} // namespace IPC
-
-// Generate param traits log methods.
-#include "ipc/param_traits_log_macros.h"
-namespace IPC {
-#include "components/guest_view/common/guest_view_message_generator.h"
-} // namespace IPC
diff --git a/chromium/components/guest_view/common/guest_view_message_generator.h b/chromium/components/guest_view/common/guest_view_message_generator.h
deleted file mode 100644
index 9f1bb10b405..00000000000
--- a/chromium/components/guest_view/common/guest_view_message_generator.h
+++ /dev/null
@@ -1,8 +0,0 @@
-// Copyright 2015 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.
-
-// Multiply-included file, no traditional include guard.
-
-#undef COMPONENTS_GUEST_VIEW_COMMON_GUEST_VIEW_MESSAGES_H_
-#include "components/guest_view/common/guest_view_messages.h"
diff --git a/chromium/components/guest_view/common/guest_view_messages.h b/chromium/components/guest_view/common/guest_view_messages.h
deleted file mode 100644
index 82a0d4ea1d3..00000000000
--- a/chromium/components/guest_view/common/guest_view_messages.h
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright 2015 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.
-
-// IPC messages for GuestViews.
-
-#ifndef COMPONENTS_GUEST_VIEW_COMMON_GUEST_VIEW_MESSAGES_H_
-#define COMPONENTS_GUEST_VIEW_COMMON_GUEST_VIEW_MESSAGES_H_
-
-#include "base/values.h"
-#include "ipc/ipc_message_macros.h"
-#include "ipc/ipc_message_start.h"
-
-#define IPC_MESSAGE_START GuestViewMsgStart
-
-// Messages sent from the browser to the renderer.
-
-// Tells the embedder that a guest has been attached in --site-per-process mode.
-IPC_MESSAGE_CONTROL1(GuestViewMsg_AttachToEmbedderFrame_ACK,
- int /* element_instance_id */)
-
-// Messages sent from the renderer to the browser.
-
-// We have a RenderFrame with routing id of |embedder_local_frame_routing_id|.
-// We want this local frame to be replaced with a remote frame that points
-// to a GuestView. This message will attach the local frame to the guest.
-// The GuestView is identified by its ID: |guest_instance_id|.
-IPC_MESSAGE_CONTROL4(GuestViewHostMsg_AttachToEmbedderFrame,
- int /* embedder_local_frame_routing_id */,
- int /* element_instance_id */,
- int /* guest_instance_id */,
- base::DictionaryValue /* params */)
-
-// Sent by the renderer when a GuestView (identified by |view_instance_id|) has
-// been created in JavaScript.
-IPC_MESSAGE_CONTROL2(GuestViewHostMsg_ViewCreated,
- int /* view_instance_id */,
- std::string /* view_type */)
-
-// Sent by the renderer when a GuestView (identified by |view_instance_id|) has
-// been garbage collected in JavaScript.
-IPC_MESSAGE_CONTROL1(GuestViewHostMsg_ViewGarbageCollected,
- int /* view_instance_id */)
-
-#endif // COMPONENTS_GUEST_VIEW_COMMON_GUEST_VIEW_MESSAGES_H_
diff --git a/chromium/components/guest_view/renderer/BUILD.gn b/chromium/components/guest_view/renderer/BUILD.gn
index 13065887efd..bd63370d960 100644
--- a/chromium/components/guest_view/renderer/BUILD.gn
+++ b/chromium/components/guest_view/renderer/BUILD.gn
@@ -12,24 +12,18 @@ static_library("renderer") {
sources = [
"guest_view_container.cc",
"guest_view_container.h",
- "guest_view_container_dispatcher.cc",
- "guest_view_container_dispatcher.h",
"guest_view_request.cc",
"guest_view_request.h",
- "iframe_guest_view_container.cc",
- "iframe_guest_view_container.h",
- "iframe_guest_view_request.cc",
- "iframe_guest_view_request.h",
]
deps = [
"//base",
"//components/guest_view/common",
+ "//components/guest_view/common:mojom",
"//content/public/common",
"//content/public/renderer",
+ "//ipc",
"//third_party/blink/public:blink",
"//v8",
]
-
- public_deps = [ "//ipc" ]
}
diff --git a/chromium/components/guest_view/renderer/guest_view_container.cc b/chromium/components/guest_view/renderer/guest_view_container.cc
index 4aece41201b..ec7e13fc293 100644
--- a/chromium/components/guest_view/renderer/guest_view_container.cc
+++ b/chromium/components/guest_view/renderer/guest_view_container.cc
@@ -9,11 +9,9 @@
#include "base/bind.h"
#include "base/lazy_instance.h"
#include "components/guest_view/common/guest_view_constants.h"
-#include "components/guest_view/common/guest_view_messages.h"
#include "components/guest_view/renderer/guest_view_request.h"
#include "content/public/renderer/render_frame.h"
#include "content/public/renderer/render_frame_observer.h"
-#include "content/public/renderer/render_view.h"
#include "ui/gfx/geometry/size.h"
#include "v8/include/v8-context.h"
#include "v8/include/v8-function.h"
@@ -112,7 +110,7 @@ void GuestViewContainer::Destroy(bool embedder_frame_destroyed) {
pending_response_->ExecuteCallbackIfAvailable(0 /* argc */, nullptr);
while (pending_requests_.size() > 0) {
- std::unique_ptr<GuestViewRequest> pending_request =
+ std::unique_ptr<GuestViewAttachRequest> pending_request =
std::move(pending_requests_.front());
pending_requests_.pop_front();
// Call the JavaScript callbacks with no arguments which implies an error.
@@ -137,13 +135,13 @@ void GuestViewContainer::RenderFrameDestroyed() {
}
void GuestViewContainer::IssueRequest(
- std::unique_ptr<GuestViewRequest> request) {
+ std::unique_ptr<GuestViewAttachRequest> request) {
EnqueueRequest(std::move(request));
PerformPendingRequest();
}
void GuestViewContainer::EnqueueRequest(
- std::unique_ptr<GuestViewRequest> request) {
+ std::unique_ptr<GuestViewAttachRequest> request) {
pending_requests_.push_back(std::move(request));
}
@@ -151,21 +149,13 @@ void GuestViewContainer::PerformPendingRequest() {
if (pending_requests_.empty() || pending_response_.get())
return;
- std::unique_ptr<GuestViewRequest> pending_request =
+ std::unique_ptr<GuestViewAttachRequest> pending_request =
std::move(pending_requests_.front());
pending_requests_.pop_front();
pending_request->PerformRequest();
pending_response_ = std::move(pending_request);
}
-void GuestViewContainer::HandlePendingResponseCallback(
- const IPC::Message& message) {
- CHECK(pending_response_);
- std::unique_ptr<GuestViewRequest> pending_response =
- std::move(pending_response_);
- pending_response->HandleResponse(message);
-}
-
void GuestViewContainer::RunDestructionCallback(bool embedder_frame_destroyed) {
// Do not attempt to run |destruction_callback_| if the embedder frame was
// destroyed. Trying to invoke callback on RenderFrame destruction results in
@@ -178,8 +168,8 @@ void GuestViewContainer::RunDestructionCallback(bool embedder_frame_destroyed) {
v8::HandleScope handle_scope(destruction_isolate_);
v8::Local<v8::Function> callback = v8::Local<v8::Function>::New(
destruction_isolate_, destruction_callback_);
- v8::Local<v8::Context> context = callback->CreationContext();
- if (context.IsEmpty())
+ v8::Local<v8::Context> context;
+ if (!callback->GetCreationContext().ToLocal(&context))
return;
v8::Context::Scope context_scope(context);
@@ -191,11 +181,16 @@ void GuestViewContainer::RunDestructionCallback(bool embedder_frame_destroyed) {
}
}
-void GuestViewContainer::OnHandleCallback(const IPC::Message& message) {
+void GuestViewContainer::OnRequestAcknowledged(
+ GuestViewAttachRequest* request) {
base::WeakPtr<GuestViewContainer> weak_ptr(weak_ptr_factory_.GetWeakPtr());
// Handle the callback for the current request with a pending response.
- HandlePendingResponseCallback(message);
+ CHECK(pending_response_);
+ DCHECK_EQ(pending_response_.get(), request);
+ std::unique_ptr<GuestViewAttachRequest> pending_response =
+ std::move(pending_response_);
+ pending_response->ExecuteCallbackIfAvailable(0, nullptr);
// Check that this container has not been deleted (crbug.com/718292).
if (!weak_ptr)
@@ -205,18 +200,6 @@ void GuestViewContainer::OnHandleCallback(const IPC::Message& message) {
PerformPendingRequest();
}
-bool GuestViewContainer::OnMessage(const IPC::Message& message) {
- return false;
-}
-
-bool GuestViewContainer::OnMessageReceived(const IPC::Message& message) {
- if (OnMessage(message))
- return true;
-
- OnHandleCallback(message);
- return true;
-}
-
void GuestViewContainer::SetElementInstanceID(int element_instance_id) {
DCHECK_EQ(element_instance_id_, guest_view::kInstanceIDNone);
element_instance_id_ = element_instance_id;
@@ -249,8 +232,8 @@ void GuestViewContainer::CallElementResizeCallback(
v8::HandleScope handle_scope(element_resize_isolate_);
v8::Local<v8::Function> callback = v8::Local<v8::Function>::New(
element_resize_isolate_, element_resize_callback_);
- v8::Local<v8::Context> context = callback->CreationContext();
- if (context.IsEmpty())
+ v8::Local<v8::Context> context;
+ if (!callback->GetCreationContext().ToLocal(&context))
return;
const int argc = 2;
diff --git a/chromium/components/guest_view/renderer/guest_view_container.h b/chromium/components/guest_view/renderer/guest_view_container.h
index 6ea89fe3007..f5539fdcd97 100644
--- a/chromium/components/guest_view/renderer/guest_view_container.h
+++ b/chromium/components/guest_view/renderer/guest_view_container.h
@@ -9,7 +9,6 @@
#include "base/containers/circular_deque.h"
#include "base/memory/weak_ptr.h"
-#include "ipc/ipc_message.h"
#include "v8/include/v8-forward.h"
#include "v8/include/v8-persistent-handle.h"
@@ -23,7 +22,7 @@ class RenderFrame;
namespace guest_view {
-class GuestViewRequest;
+class GuestViewAttachRequest;
class GuestViewContainer {
public:
@@ -37,14 +36,13 @@ class GuestViewContainer {
// IssueRequest queues up a |request| until the container is ready and
// the browser process has responded to the last request if it's still
// pending.
- void IssueRequest(std::unique_ptr<GuestViewRequest> request);
+ void IssueRequest(std::unique_ptr<GuestViewAttachRequest> request);
int element_instance_id() const { return element_instance_id_; }
content::RenderFrame* render_frame() const { return render_frame_; }
- // Called by GuestViewContainerDispatcher to dispatch message to this
- // container.
- bool OnMessageReceived(const IPC::Message& message);
+ // Called when a previously issued `request` was acknowledged by the browser.
+ void OnRequestAcknowledged(GuestViewAttachRequest* request);
// Destroys this GuestViewContainer after performing necessary cleanup.
// |embedder_frame_destroyed| is true if this destruction is due to the
@@ -59,10 +57,6 @@ class GuestViewContainer {
// Called when the embedding RenderFrame is destroyed.
virtual void OnRenderFrameDestroyed() {}
- // Called to respond to IPCs from the browser process that have not been
- // handled by GuestViewContainer.
- virtual bool OnMessage(const IPC::Message& message);
-
// Called to perform actions when a GuestViewContainer is about to be
// destroyed.
// Note that this should be called exactly once.
@@ -76,17 +70,14 @@ class GuestViewContainer {
protected:
virtual ~GuestViewContainer();
- void OnHandleCallback(const IPC::Message& message);
-
private:
class RenderFrameLifetimeObserver;
friend class RenderFrameLifetimeObserver;
void RenderFrameDestroyed();
- void EnqueueRequest(std::unique_ptr<GuestViewRequest> request);
+ void EnqueueRequest(std::unique_ptr<GuestViewAttachRequest> request);
void PerformPendingRequest();
- void HandlePendingResponseCallback(const IPC::Message& message);
void RunDestructionCallback(bool embedder_frame_destroyed);
void CallElementResizeCallback(const gfx::Size& new_size);
@@ -96,8 +87,9 @@ class GuestViewContainer {
bool in_destruction_;
- base::circular_deque<std::unique_ptr<GuestViewRequest>> pending_requests_;
- std::unique_ptr<GuestViewRequest> pending_response_;
+ base::circular_deque<std::unique_ptr<GuestViewAttachRequest>>
+ pending_requests_;
+ std::unique_ptr<GuestViewAttachRequest> pending_response_;
v8::Global<v8::Function> destruction_callback_;
v8::Isolate* destruction_isolate_;
diff --git a/chromium/components/guest_view/renderer/guest_view_container_dispatcher.cc b/chromium/components/guest_view/renderer/guest_view_container_dispatcher.cc
deleted file mode 100644
index a21c58226d7..00000000000
--- a/chromium/components/guest_view/renderer/guest_view_container_dispatcher.cc
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2015 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.
-
-#include "components/guest_view/renderer/guest_view_container_dispatcher.h"
-
-#include "components/guest_view/common/guest_view_constants.h"
-#include "components/guest_view/renderer/guest_view_container.h"
-#include "ipc/ipc_message_macros.h"
-#include "ipc/ipc_message_start.h"
-
-namespace guest_view {
-
-GuestViewContainerDispatcher::GuestViewContainerDispatcher() {
-}
-
-GuestViewContainerDispatcher::~GuestViewContainerDispatcher() {
-}
-
-bool GuestViewContainerDispatcher::HandlesMessage(const IPC::Message& message) {
- return IPC_MESSAGE_CLASS(message) == GuestViewMsgStart;
-}
-
-bool GuestViewContainerDispatcher::OnControlMessageReceived(
- const IPC::Message& message) {
- if (!HandlesMessage(message))
- return false;
-
- int element_instance_id = kInstanceIDNone;
- base::PickleIterator iter(message);
- bool success = iter.ReadInt(&element_instance_id);
- DCHECK(success);
-
- auto* container = GuestViewContainer::FromID(element_instance_id);
- if (!container)
- return false;
-
- return container->OnMessageReceived(message);
-}
-
-} // namespace guest_view
diff --git a/chromium/components/guest_view/renderer/guest_view_container_dispatcher.h b/chromium/components/guest_view/renderer/guest_view_container_dispatcher.h
deleted file mode 100644
index aefadb7a73e..00000000000
--- a/chromium/components/guest_view/renderer/guest_view_container_dispatcher.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2015 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.
-
-#ifndef COMPONENTS_GUEST_VIEW_RENDERER_GUEST_VIEW_CONTAINER_DISPATCHER_H_
-#define COMPONENTS_GUEST_VIEW_RENDERER_GUEST_VIEW_CONTAINER_DISPATCHER_H_
-
-#include "content/public/renderer/render_thread_observer.h"
-#include "ipc/ipc_message.h"
-
-namespace guest_view {
-
-// Dispatcher used to route messages to GuestViewContainer.
-class GuestViewContainerDispatcher : public content::RenderThreadObserver {
- public:
- GuestViewContainerDispatcher();
-
- GuestViewContainerDispatcher(const GuestViewContainerDispatcher&) = delete;
- GuestViewContainerDispatcher& operator=(const GuestViewContainerDispatcher&) =
- delete;
-
- ~GuestViewContainerDispatcher() override;
-
- protected:
- // Returns true if |message| is handled for a GuestViewContainer.
- virtual bool HandlesMessage(const IPC::Message& message);
-
- // content::RenderThreadObserver implementation.
- bool OnControlMessageReceived(const IPC::Message& message) override;
-};
-
-} // namespace guest_view
-
-#endif // COMPONENTS_GUEST_VIEW_RENDERER_GUEST_VIEW_CONTAINER_DISPATCHER_H_
diff --git a/chromium/components/guest_view/renderer/guest_view_request.cc b/chromium/components/guest_view/renderer/guest_view_request.cc
index 118e070249e..a315dd269cf 100644
--- a/chromium/components/guest_view/renderer/guest_view_request.cc
+++ b/chromium/components/guest_view/renderer/guest_view_request.cc
@@ -7,10 +7,13 @@
#include <tuple>
#include <utility>
-#include "components/guest_view/common/guest_view_messages.h"
+#include "base/no_destructor.h"
+#include "components/guest_view/common/guest_view.mojom.h"
#include "components/guest_view/renderer/guest_view_container.h"
#include "content/public/renderer/render_frame.h"
+#include "content/public/renderer/render_thread.h"
#include "content/public/renderer/render_view.h"
+#include "ipc/ipc_sync_channel.h"
#include "third_party/blink/public/web/web_local_frame.h"
#include "third_party/blink/public/web/web_remote_frame.h"
#include "third_party/blink/public/web/web_view.h"
@@ -20,33 +23,66 @@
namespace guest_view {
-GuestViewRequest::GuestViewRequest(GuestViewContainer* container,
- v8::Local<v8::Function> callback,
- v8::Isolate* isolate)
+namespace {
+
+mojom::GuestViewHost* GetGuestViewHost() {
+ static base::NoDestructor<mojo::AssociatedRemote<mojom::GuestViewHost>>
+ guest_view_host;
+ if (!*guest_view_host) {
+ content::RenderThread::Get()->GetChannel()->GetRemoteAssociatedInterface(
+ guest_view_host.get());
+ }
+
+ return guest_view_host->get();
+}
+
+} // namespace
+
+GuestViewAttachRequest::GuestViewAttachRequest(
+ guest_view::GuestViewContainer* container,
+ int render_frame_routing_id,
+ int guest_instance_id,
+ std::unique_ptr<base::DictionaryValue> params,
+ v8::Local<v8::Function> callback,
+ v8::Isolate* isolate)
: container_(container),
callback_(isolate, callback),
- isolate_(isolate) {
+ isolate_(isolate),
+ render_frame_routing_id_(render_frame_routing_id),
+ guest_instance_id_(guest_instance_id),
+ params_(std::move(params)) {}
+
+GuestViewAttachRequest::~GuestViewAttachRequest() = default;
+
+void GuestViewAttachRequest::PerformRequest() {
+ GetGuestViewHost()->AttachToEmbedderFrame(
+ render_frame_routing_id_, container_->element_instance_id(),
+ guest_instance_id_, params_->Clone(),
+ base::BindOnce(&GuestViewAttachRequest::OnAcknowledged,
+ weak_ptr_factory_.GetWeakPtr()));
}
-GuestViewRequest::~GuestViewRequest() {
+void GuestViewAttachRequest::OnAcknowledged() {
+ // Destroys `this`.
+ container_->OnRequestAcknowledged(this);
}
-void GuestViewRequest::ExecuteCallbackIfAvailable(
+void GuestViewAttachRequest::ExecuteCallbackIfAvailable(
int argc,
std::unique_ptr<v8::Local<v8::Value>[]> argv) {
if (callback_.IsEmpty())
return;
- v8::HandleScope handle_scope(isolate());
+ v8::HandleScope handle_scope(isolate_);
v8::Local<v8::Function> callback =
v8::Local<v8::Function>::New(isolate_, callback_);
- v8::Local<v8::Context> context = callback->CreationContext();
- if (context.IsEmpty())
+ v8::Local<v8::Context> context;
+ if (!callback->GetCreationContext().ToLocal(&context))
return;
v8::Context::Scope context_scope(context);
- v8::MicrotasksScope microtasks(
- isolate(), v8::MicrotasksScope::kDoNotRunMicrotasks);
+ v8::MicrotasksScope microtasks(isolate_,
+ v8::MicrotasksScope::kDoNotRunMicrotasks);
callback->Call(context, context->Global(), argc, argv.get())
.FromMaybe(v8::Local<v8::Value>());
diff --git a/chromium/components/guest_view/renderer/guest_view_request.h b/chromium/components/guest_view/renderer/guest_view_request.h
index d26f3a72f45..ec5456df891 100644
--- a/chromium/components/guest_view/renderer/guest_view_request.h
+++ b/chromium/components/guest_view/renderer/guest_view_request.h
@@ -7,7 +7,8 @@
#include <memory>
-#include "ipc/ipc_message.h"
+#include "base/memory/weak_ptr.h"
+#include "base/values.h"
#include "v8/include/v8-forward.h"
#include "v8/include/v8-persistent-handle.h"
@@ -15,30 +16,29 @@ namespace guest_view {
class GuestViewContainer;
-// A GuestViewRequest is the base class for an asynchronous operation performed
-// on a GuestView or GuestViewContainer from JavaScript. This operation may be
-// queued until the container is ready to be operated upon (it has geometry).
-// A GuestViewRequest may or may not have a callback back into JavaScript.
-// Typically, performing a request involves sending an IPC to the browser
-// process in PerformRequest. Handling a response involves receiving a related
-// IPC from the browser process in HandleResponse.
-class GuestViewRequest {
+// This class represents an attach request from Javascript.
+// A GuestViewAttachRequest is an asynchronous operation performed on a
+// GuestView or GuestViewContainer from JavaScript. This operation may be queued
+// until the container is ready to be operated upon (it has geometry). A
+// GuestViewAttachRequest may or may not have a callback back into JavaScript.
+// Performing a request involves sending an IPC to the browser process in
+// PerformRequest which the browser will acknowledge.
+class GuestViewAttachRequest {
public:
- GuestViewRequest(GuestViewContainer* container,
- v8::Local<v8::Function> callback,
- v8::Isolate* isolate);
+ GuestViewAttachRequest(GuestViewContainer* container,
+ int render_frame_routing_id,
+ int guest_instance_id,
+ std::unique_ptr<base::DictionaryValue> params,
+ v8::Local<v8::Function> callback,
+ v8::Isolate* isolate);
- GuestViewRequest(const GuestViewRequest&) = delete;
- GuestViewRequest& operator=(const GuestViewRequest&) = delete;
+ GuestViewAttachRequest(const GuestViewAttachRequest&) = delete;
+ GuestViewAttachRequest& operator=(const GuestViewAttachRequest&) = delete;
- virtual ~GuestViewRequest();
+ ~GuestViewAttachRequest();
// Performs the associated request.
- virtual void PerformRequest() = 0;
-
- // Called by GuestViewContainer when the browser process has responded to the
- // request initiated by PerformRequest.
- virtual void HandleResponse(const IPC::Message& message) = 0;
+ void PerformRequest();
// Called to call the callback associated with this request if one is
// available.
@@ -47,14 +47,17 @@ class GuestViewRequest {
void ExecuteCallbackIfAvailable(int argc,
std::unique_ptr<v8::Local<v8::Value>[]> argv);
- GuestViewContainer* container() const { return container_; }
-
- v8::Isolate* isolate() const { return isolate_; }
-
private:
+ void OnAcknowledged();
+
GuestViewContainer* const container_;
v8::Global<v8::Function> callback_;
v8::Isolate* const isolate_;
+ const int render_frame_routing_id_;
+ const int guest_instance_id_;
+ std::unique_ptr<base::DictionaryValue> params_;
+
+ base::WeakPtrFactory<GuestViewAttachRequest> weak_ptr_factory_{this};
};
} // namespace guest_view
diff --git a/chromium/components/guest_view/renderer/iframe_guest_view_container.cc b/chromium/components/guest_view/renderer/iframe_guest_view_container.cc
deleted file mode 100644
index aa244a5c83b..00000000000
--- a/chromium/components/guest_view/renderer/iframe_guest_view_container.cc
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2015 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.
-
-#include "components/guest_view/renderer/iframe_guest_view_container.h"
-
-#include "base/feature_list.h"
-#include "components/guest_view/common/guest_view_messages.h"
-#include "content/public/common/content_features.h"
-#include "content/public/renderer/render_frame.h"
-
-namespace guest_view {
-
-IframeGuestViewContainer::IframeGuestViewContainer(
- content::RenderFrame* render_frame)
- : GuestViewContainer(render_frame) {
-}
-
-IframeGuestViewContainer::~IframeGuestViewContainer() {
-}
-
-bool IframeGuestViewContainer::OnMessage(const IPC::Message& message) {
- if (message.type() != GuestViewMsg_AttachToEmbedderFrame_ACK::ID)
- return false;
-
- OnHandleCallback(message);
- return true;
-}
-
-} // namespace guest_view
diff --git a/chromium/components/guest_view/renderer/iframe_guest_view_container.h b/chromium/components/guest_view/renderer/iframe_guest_view_container.h
deleted file mode 100644
index 03f8a323979..00000000000
--- a/chromium/components/guest_view/renderer/iframe_guest_view_container.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2015 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.
-
-#ifndef COMPONENTS_GUEST_VIEW_RENDERER_IFRAME_GUEST_VIEW_CONTAINER_H_
-#define COMPONENTS_GUEST_VIEW_RENDERER_IFRAME_GUEST_VIEW_CONTAINER_H_
-
-#include "components/guest_view/renderer/guest_view_container.h"
-
-namespace guest_view {
-
-// A GuestViewContainer whose container element is backed by an out-of-process
-// <iframe>.
-// This container handles messages related to guest attachment in
-// --site-per-process.
-class IframeGuestViewContainer : public GuestViewContainer {
- public:
- explicit IframeGuestViewContainer(content::RenderFrame* render_frame);
-
- IframeGuestViewContainer(const IframeGuestViewContainer&) = delete;
- IframeGuestViewContainer& operator=(const IframeGuestViewContainer&) = delete;
-
- ~IframeGuestViewContainer() override;
-
- // GuestViewContainer overrides.
- bool OnMessage(const IPC::Message& message) override;
-};
-
-} // namespace guest_view
-
-#endif // COMPONENTS_GUEST_VIEW_RENDERER_IFRAME_GUEST_VIEW_CONTAINER_H_
diff --git a/chromium/components/guest_view/renderer/iframe_guest_view_request.cc b/chromium/components/guest_view/renderer/iframe_guest_view_request.cc
deleted file mode 100644
index 08545af43b9..00000000000
--- a/chromium/components/guest_view/renderer/iframe_guest_view_request.cc
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2015 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.
-
-#include "components/guest_view/renderer/iframe_guest_view_request.h"
-
-#include <utility>
-
-#include "components/guest_view/common/guest_view_messages.h"
-#include "components/guest_view/renderer/guest_view_container.h"
-#include "content/public/renderer/render_frame.h"
-
-namespace guest_view {
-
-GuestViewAttachIframeRequest::GuestViewAttachIframeRequest(
- guest_view::GuestViewContainer* container,
- int render_frame_routing_id,
- int guest_instance_id,
- std::unique_ptr<base::DictionaryValue> params,
- v8::Local<v8::Function> callback,
- v8::Isolate* isolate)
- : GuestViewRequest(container, callback, isolate),
- render_frame_routing_id_(render_frame_routing_id),
- guest_instance_id_(guest_instance_id),
- params_(std::move(params)) {}
-
-GuestViewAttachIframeRequest::~GuestViewAttachIframeRequest() {
-}
-
-void GuestViewAttachIframeRequest::PerformRequest() {
- DCHECK(container()->render_frame());
-
- container()->render_frame()->Send(new GuestViewHostMsg_AttachToEmbedderFrame(
- render_frame_routing_id_, container()->element_instance_id(),
- guest_instance_id_, *params_));
-}
-
-void GuestViewAttachIframeRequest::HandleResponse(const IPC::Message& message) {
- GuestViewMsg_AttachToEmbedderFrame_ACK::Param param;
- bool message_read_status =
- GuestViewMsg_AttachToEmbedderFrame_ACK::Read(&message, &param);
- DCHECK(message_read_status);
-
- ExecuteCallbackIfAvailable(0, nullptr);
-}
-
-} // namespace guest_view
diff --git a/chromium/components/guest_view/renderer/iframe_guest_view_request.h b/chromium/components/guest_view/renderer/iframe_guest_view_request.h
deleted file mode 100644
index de702eddbed..00000000000
--- a/chromium/components/guest_view/renderer/iframe_guest_view_request.h
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2015 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.
-
-#ifndef COMPONENTS_GUEST_VIEW_RENDERER_IFRAME_GUEST_VIEW_REQUEST_H_
-#define COMPONENTS_GUEST_VIEW_RENDERER_IFRAME_GUEST_VIEW_REQUEST_H_
-
-#include <memory>
-
-#include "base/values.h"
-#include "components/guest_view/renderer/guest_view_request.h"
-#include "ipc/ipc_message.h"
-#include "v8/include/v8-forward.h"
-
-namespace guest_view {
-class GuestViewContainer;
-
-// This class represents an AttachGuest request in --site-per-process from
-// Javascript. It includes
-// the input parameters and the callback function.
-class GuestViewAttachIframeRequest : public guest_view::GuestViewRequest {
- public:
- GuestViewAttachIframeRequest(GuestViewContainer* container,
- int render_frame_routing_id,
- int guest_instance_id,
- std::unique_ptr<base::DictionaryValue> params,
- v8::Local<v8::Function> callback,
- v8::Isolate* isolate);
-
- GuestViewAttachIframeRequest(const GuestViewAttachIframeRequest&) = delete;
- GuestViewAttachIframeRequest& operator=(const GuestViewAttachIframeRequest&) =
- delete;
-
- ~GuestViewAttachIframeRequest() override;
-
- void PerformRequest() override;
- void HandleResponse(const IPC::Message& message) override;
-
- private:
- const int render_frame_routing_id_;
- const int guest_instance_id_;
- std::unique_ptr<base::DictionaryValue> params_;
-};
-
-} // namespace guest_view
-
-#endif // COMPONENTS_GUEST_VIEW_RENDERER_IFRAME_GUEST_VIEW_REQUEST_H_
diff --git a/chromium/components/gwp_asan/client/guarded_page_allocator.cc b/chromium/components/gwp_asan/client/guarded_page_allocator.cc
index aa54ddd3a6d..0dc74ff6a20 100644
--- a/chromium/components/gwp_asan/client/guarded_page_allocator.cc
+++ b/chromium/components/gwp_asan/client/guarded_page_allocator.cc
@@ -12,7 +12,6 @@
#include "base/debug/stack_trace.h"
#include "base/logging.h"
#include "base/memory/page_size.h"
-#include "base/no_destructor.h"
#include "base/rand_util.h"
#include "base/strings/stringprintf.h"
#include "base/synchronization/lock.h"
@@ -22,11 +21,11 @@
#include "components/gwp_asan/common/crash_key_name.h"
#include "components/gwp_asan/common/pack_stack_trace.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "components/crash/core/app/crashpad.h" // nogncheck
#endif
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
#include <pthread.h>
#endif
@@ -39,7 +38,7 @@ size_t GetStackTrace(void** trace, size_t count) {
// TODO(vtsyrklevich): Investigate using trace_event::CFIBacktraceAndroid
// on 32-bit Android for canary/dev (where we can dynamically load unwind
// data.)
-#if defined(OS_ANDROID) && BUILDFLAG(CAN_UNWIND_WITH_FRAME_POINTERS)
+#if BUILDFLAG(IS_ANDROID) && BUILDFLAG(CAN_UNWIND_WITH_FRAME_POINTERS)
// Android release builds ship without unwind tables so the normal method of
// stack trace collection for base::debug::StackTrace doesn't work; however,
// AArch64 builds ship with frame pointers so we can still collect stack
@@ -54,7 +53,7 @@ size_t GetStackTrace(void** trace, size_t count) {
// Report a tid that matches what crashpad collects which may differ from what
// base::PlatformThread::CurrentId() returns.
uint64_t ReportTid() {
-#if !defined(OS_APPLE)
+#if !BUILDFLAG(IS_APPLE)
return base::PlatformThread::CurrentId();
#else
uint64_t tid = base::kInvalidThreadId;
@@ -188,7 +187,7 @@ void GuardedPageAllocator::Init(size_t max_alloced_pages,
std::make_unique<AllocatorState::SlotMetadata[]>(state_.num_metadata);
state_.metadata_addr = reinterpret_cast<uintptr_t>(metadata_.get());
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Explicitly allow memory ranges the crash_handler needs to read. This is
// required for WebView because it has a stricter set of privacy constraints
// on what it reads from the crashing process.
@@ -320,7 +319,7 @@ size_t GuardedPageAllocator::GetRequestedSize(const void* ptr) const {
const uintptr_t addr = reinterpret_cast<uintptr_t>(ptr);
AllocatorState::SlotIdx slot = state_.AddrToSlot(state_.GetPageAddr(addr));
AllocatorState::MetadataIdx metadata_idx = slot_to_metadata_idx_[slot];
-#if !defined(OS_APPLE)
+#if !BUILDFLAG(IS_APPLE)
CHECK_LT(metadata_idx, state_.num_metadata);
CHECK_EQ(addr, metadata_[metadata_idx].alloc_ptr);
#else
diff --git a/chromium/components/gwp_asan/client/guarded_page_allocator_posix.cc b/chromium/components/gwp_asan/client/guarded_page_allocator_posix.cc
index 868617af679..c4b6d3c5285 100644
--- a/chromium/components/gwp_asan/client/guarded_page_allocator_posix.cc
+++ b/chromium/components/gwp_asan/client/guarded_page_allocator_posix.cc
@@ -19,10 +19,9 @@ void* GuardedPageAllocator::MapRegion() {
void GuardedPageAllocator::UnmapRegion() {
CHECK(state_.pages_base_addr);
- int err =
+ [[maybe_unused]] int err =
munmap(reinterpret_cast<void*>(state_.pages_base_addr), RegionSize());
DPCHECK(err == 0) << "munmap";
- (void)err;
}
void GuardedPageAllocator::MarkPageReadWrite(void* ptr) {
diff --git a/chromium/components/gwp_asan/client/guarded_page_allocator_unittest.cc b/chromium/components/gwp_asan/client/guarded_page_allocator_unittest.cc
index 149e85ad84b..7c032b054df 100644
--- a/chromium/components/gwp_asan/client/guarded_page_allocator_unittest.cc
+++ b/chromium/components/gwp_asan/client/guarded_page_allocator_unittest.cc
@@ -111,7 +111,7 @@ TEST_P(GuardedPageAllocatorTest, PointerIsMine) {
TEST_P(GuardedPageAllocatorTest, GetRequestedSize) {
void* buf = gpa_.Allocate(100);
EXPECT_EQ(gpa_.GetRequestedSize(buf), 100U);
-#if !defined(OS_APPLE)
+#if !BUILDFLAG(IS_APPLE)
EXPECT_DEATH({ gpa_.GetRequestedSize((char*)buf + 1); }, "");
#else
EXPECT_EQ(gpa_.GetRequestedSize((char*)buf + 1), 0U);
@@ -295,7 +295,7 @@ class ThreadedHighContentionDelegate
// Test that allocator remains in consistent state under high contention and
// doesn't double-allocate pages or fail to deallocate pages.
TEST_P(GuardedPageAllocatorTest, ThreadedHighContention) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
constexpr size_t num_threads = 200;
#else
constexpr size_t num_threads = 1000;
diff --git a/chromium/components/gwp_asan/client/guarded_page_allocator_win.cc b/chromium/components/gwp_asan/client/guarded_page_allocator_win.cc
index fac270f303a..b6c516fe011 100644
--- a/chromium/components/gwp_asan/client/guarded_page_allocator_win.cc
+++ b/chromium/components/gwp_asan/client/guarded_page_allocator_win.cc
@@ -26,10 +26,9 @@ void* GuardedPageAllocator::MapRegion() {
void GuardedPageAllocator::UnmapRegion() {
CHECK(state_.pages_base_addr);
- BOOL err = VirtualFree(reinterpret_cast<void*>(state_.pages_base_addr), 0,
- MEM_RELEASE);
+ [[maybe_unused]] BOOL err = VirtualFree(
+ reinterpret_cast<void*>(state_.pages_base_addr), 0, MEM_RELEASE);
DPCHECK(err) << "VirtualFree";
- (void)err;
}
void GuardedPageAllocator::MarkPageReadWrite(void* ptr) {
diff --git a/chromium/components/gwp_asan/client/gwp_asan.cc b/chromium/components/gwp_asan/client/gwp_asan.cc
index 1365989dec6..1f9fc22a5d4 100644
--- a/chromium/components/gwp_asan/client/gwp_asan.cc
+++ b/chromium/components/gwp_asan/client/gwp_asan.cc
@@ -7,12 +7,12 @@
#include <algorithm>
#include <cmath>
#include <limits>
+#include <tuple>
#include "base/allocator/buildflags.h"
#include "base/callback_helpers.h"
#include "base/debug/crash_logging.h"
#include "base/feature_list.h"
-#include "base/ignore_result.h"
#include "base/logging.h"
#include "base/metrics/field_trial_params.h"
#include "base/numerics/safe_math.h"
@@ -56,7 +56,7 @@ constexpr double kDefaultProcessSamplingProbability = 0.015;
// we want to perform additional testing (e.g., on canary/dev builds).
constexpr int kDefaultProcessSamplingBoost2 = 10;
-#if defined(OS_WIN) || defined(OS_APPLE)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE)
constexpr base::FeatureState kDefaultEnabled = base::FEATURE_ENABLED_BY_DEFAULT;
#else
constexpr base::FeatureState kDefaultEnabled =
@@ -197,9 +197,9 @@ void EnableForMalloc(bool boost_sampling, const char* process_type) {
settings->total_pages, settings->sampling_frequency, base::DoNothing());
return true;
}();
- ignore_result(init_once);
+ std::ignore = init_once;
#else
- ignore_result(internal::kGwpAsanMalloc);
+ std::ignore = internal::kGwpAsanMalloc;
DLOG(WARNING) << "base::allocator shims are unavailable for GWP-ASan.";
#endif // BUILDFLAG(USE_ALLOCATOR_SHIM)
}
@@ -217,9 +217,9 @@ void EnableForPartitionAlloc(bool boost_sampling, const char* process_type) {
settings->total_pages, settings->sampling_frequency, base::DoNothing());
return true;
}();
- ignore_result(init_once);
+ std::ignore = init_once;
#else
- ignore_result(internal::kGwpAsanPartitionAlloc);
+ std::ignore = internal::kGwpAsanPartitionAlloc;
DLOG(WARNING) << "PartitionAlloc hooks are unavailable for GWP-ASan.";
#endif // BUILDFLAG(USE_PARTITION_ALLOC)
}
diff --git a/chromium/components/gwp_asan/client/sampling_malloc_shims.cc b/chromium/components/gwp_asan/client/sampling_malloc_shims.cc
index 83d1d934bee..448b33084b8 100644
--- a/chromium/components/gwp_asan/client/sampling_malloc_shims.cc
+++ b/chromium/components/gwp_asan/client/sampling_malloc_shims.cc
@@ -10,7 +10,6 @@
#include "base/allocator/allocator_shim.h"
#include "base/check_op.h"
#include "base/compiler_specific.h"
-#include "base/no_destructor.h"
#include "base/numerics/safe_math.h"
#include "base/process/process_metrics.h"
#include "base/rand_util.h"
@@ -21,7 +20,7 @@
#include "components/gwp_asan/client/sampling_state.h"
#include "components/gwp_asan/common/crash_key_name.h"
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
#include <pthread.h>
#endif
diff --git a/chromium/components/gwp_asan/client/sampling_malloc_shims_unittest.cc b/chromium/components/gwp_asan/client/sampling_malloc_shims_unittest.cc
index 3cdbe70ea4d..a1e5066e7ba 100644
--- a/chromium/components/gwp_asan/client/sampling_malloc_shims_unittest.cc
+++ b/chromium/components/gwp_asan/client/sampling_malloc_shims_unittest.cc
@@ -27,17 +27,17 @@
// These tests install global allocator shims so they are not safe to run in
// multi-threaded contexts. Instead they're implemented as multi-process tests.
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include <malloc.h>
static size_t GetUsableSize(void* mem) {
return _msize(mem);
}
-#elif defined(OS_APPLE)
+#elif BUILDFLAG(IS_APPLE)
#include <malloc/malloc.h>
static size_t GetUsableSize(void* mem) {
return malloc_size(mem);
}
-#elif defined(OS_LINUX) || defined(OS_CHROMEOS)
+#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
#include <malloc.h>
static size_t GetUsableSize(void* mem) {
return malloc_usable_size(mem);
@@ -62,9 +62,9 @@ constexpr int kFailure = 1;
class SamplingMallocShimsTest : public base::MultiProcessTest {
public:
static void multiprocessTestSetup() {
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
base::allocator::InitializeAllocatorShim();
-#endif // defined(OS_APPLE)
+#endif // BUILDFLAG(IS_APPLE)
crash_reporter::InitializeCrashKeys();
InstallMallocHooks(AllocatorState::kMaxMetadata,
AllocatorState::kMaxMetadata, AllocatorState::kMaxSlots,
@@ -123,15 +123,15 @@ MULTIPROCESS_TEST_MAIN_WITH_SETUP(
EXPECT_TRUE(allocationCheck([&] { return realloc(nullptr, page_size); },
&free, &failures));
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
EXPECT_TRUE(allocationCheck([&] { return _aligned_malloc(123, 16); },
&_aligned_free, &failures));
EXPECT_TRUE(
allocationCheck([&] { return _aligned_realloc(nullptr, 123, 16); },
&_aligned_free, &failures));
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
-#if defined(OS_POSIX)
+#if BUILDFLAG(IS_POSIX)
EXPECT_TRUE(allocationCheck(
[&]() -> void* {
void* ptr;
@@ -140,7 +140,7 @@ MULTIPROCESS_TEST_MAIN_WITH_SETUP(
return ptr;
},
&free, &failures));
-#endif // defined(OS_POSIX)
+#endif // BUILDFLAG(IS_POSIX)
EXPECT_TRUE(allocationCheck([&] { return std::malloc(page_size); },
&std::free, &failures));
@@ -169,7 +169,7 @@ MULTIPROCESS_TEST_MAIN_WITH_SETUP(
}
// Flaky on Mac: https://crbug.com/1087372
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
#define MAYBE_BasicFunctionality DISABLED_BasicFunctionality
#else
#define MAYBE_BasicFunctionality BasicFunctionality
@@ -249,7 +249,7 @@ TEST_F(SamplingMallocShimsTest, CrashKey) {
#endif // !defined(COMPONENT_BUILD)
// malloc_usable_size() is not currently used/shimmed on Android.
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
MULTIPROCESS_TEST_MAIN_WITH_SETUP(
GetSizeEstimate,
SamplingMallocShimsTest::multiprocessTestSetup) {
@@ -273,7 +273,7 @@ TEST_F(SamplingMallocShimsTest, GetSizeEstimate) {
}
#endif
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
MULTIPROCESS_TEST_MAIN_WITH_SETUP(
AlignedRealloc,
SamplingMallocShimsTest::multiprocessTestSetup) {
@@ -294,10 +294,10 @@ MULTIPROCESS_TEST_MAIN_WITH_SETUP(
TEST_F(SamplingMallocShimsTest, AlignedRealloc) {
runTest("AlignedRealloc");
}
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
// PartitionAlloc-Everywhere does not support batch_malloc / batch_free.
-#if defined(OS_APPLE) && !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
+#if BUILDFLAG(IS_APPLE) && !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
MULTIPROCESS_TEST_MAIN_WITH_SETUP(
BatchFree,
SamplingMallocShimsTest::multiprocessTestSetup) {
@@ -325,7 +325,7 @@ MULTIPROCESS_TEST_MAIN_WITH_SETUP(
TEST_F(SamplingMallocShimsTest, BatchFree) {
runTest("BatchFree");
}
-#endif // defined(OS_APPLE) && !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
+#endif // BUILDFLAG(IS_APPLE) && !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
} // namespace
diff --git a/chromium/components/gwp_asan/client/sampling_partitionalloc_shims_unittest.cc b/chromium/components/gwp_asan/client/sampling_partitionalloc_shims_unittest.cc
index ad157d71c33..3ae38ad88de 100644
--- a/chromium/components/gwp_asan/client/sampling_partitionalloc_shims_unittest.cc
+++ b/chromium/components/gwp_asan/client/sampling_partitionalloc_shims_unittest.cc
@@ -58,7 +58,7 @@ constexpr base::PartitionOptions kAllocatorOptions = {
base::PartitionOptions::Cookie::kAllowed,
base::PartitionOptions::BackupRefPtr::kDisabled,
base::PartitionOptions::UseConfigurablePool::kNo,
- base::PartitionOptions::LazyCommit::kEnabled};
+};
static void HandleOOM(size_t unused_size) {
LOG(FATAL) << "Out of memory.";
diff --git a/chromium/components/gwp_asan/client/sampling_state.h b/chromium/components/gwp_asan/client/sampling_state.h
index 707e16ca0a1..a52caeda95c 100644
--- a/chromium/components/gwp_asan/client/sampling_state.h
+++ b/chromium/components/gwp_asan/client/sampling_state.h
@@ -13,7 +13,7 @@
#include "base/rand_util.h"
#include "build/build_config.h"
-#if defined(OS_APPLE) || defined(OS_ANDROID)
+#if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_ANDROID)
#define USE_PTHREAD_TLS
#include <pthread.h>
#endif
diff --git a/chromium/components/gwp_asan/crash_handler/crash_analyzer.cc b/chromium/components/gwp_asan/crash_handler/crash_analyzer.cc
index 5e3029b8c5b..2b685812cee 100644
--- a/chromium/components/gwp_asan/crash_handler/crash_analyzer.cc
+++ b/chromium/components/gwp_asan/crash_handler/crash_analyzer.cc
@@ -26,11 +26,11 @@
#include "third_party/crashpad/crashpad/snapshot/process_snapshot.h"
#include "third_party/crashpad/crashpad/util/process/process_memory.h"
-#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID)
#include <signal.h>
-#elif defined(OS_APPLE)
+#elif BUILDFLAG(IS_APPLE)
#include <mach/exception_types.h>
-#elif defined(OS_WIN)
+#elif BUILDFLAG(IS_WIN)
#include <windows.h>
#endif
@@ -81,13 +81,13 @@ bool CrashAnalyzer::GetExceptionInfo(
crashpad::VMAddress CrashAnalyzer::GetAccessAddress(
const crashpad::ExceptionSnapshot& exception) {
-#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID)
if (exception.Exception() == SIGSEGV || exception.Exception() == SIGBUS)
return exception.ExceptionAddress();
-#elif defined(OS_APPLE)
+#elif BUILDFLAG(IS_APPLE)
if (exception.Exception() == EXC_BAD_ACCESS)
return exception.ExceptionAddress();
-#elif defined(OS_WIN)
+#elif BUILDFLAG(IS_WIN)
if (exception.Exception() == EXCEPTION_ACCESS_VIOLATION) {
const std::vector<uint64_t>& codes = exception.Codes();
if (codes.size() < 2)
diff --git a/chromium/components/gwp_asan/crash_handler/crash_analyzer_unittest.cc b/chromium/components/gwp_asan/crash_handler/crash_analyzer_unittest.cc
index f5e5034f426..39d4af75d63 100644
--- a/chromium/components/gwp_asan/crash_handler/crash_analyzer_unittest.cc
+++ b/chromium/components/gwp_asan/crash_handler/crash_analyzer_unittest.cc
@@ -29,7 +29,7 @@
#include "third_party/crashpad/crashpad/test/process_type.h"
#include "third_party/crashpad/crashpad/util/process/process_memory_native.h"
-#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
#include "third_party/crashpad/crashpad/test/linux/fake_ptrace_connection.h"
#endif
@@ -78,13 +78,14 @@ class CrashAnalyzerTest : public testing::Test {
crashpad::CPUArchitecture::kCPUArchitectureX86;
#endif
-#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
ASSERT_TRUE(connection_.Initialize(getpid()));
auto memory = std::make_unique<crashpad::ProcessMemoryLinux>(&connection_);
#else
auto memory = std::make_unique<crashpad::ProcessMemoryNative>();
ASSERT_TRUE(memory->Initialize(crashpad::test::GetSelfProcess()));
-#endif // OS_ANDROID || OS_LINUX || OS_CHROMEOS
+#endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) ||
+ // BUILDFLAG(IS_CHROMEOS)
process_snapshot_.AddModule(std::move(module));
process_snapshot_.SetException(std::move(exception));
@@ -93,7 +94,7 @@ class CrashAnalyzerTest : public testing::Test {
GuardedPageAllocator gpa_;
crashpad::test::TestProcessSnapshot process_snapshot_;
-#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
crashpad::test::FakePtraceConnection connection_;
#endif
@@ -102,7 +103,7 @@ class CrashAnalyzerTest : public testing::Test {
// Stack trace collection on Android builds with frame pointers enabled does
// not use base::debug::StackTrace, so the stack traces may vary slightly and
// break this test.
-#if !defined(OS_ANDROID) || !BUILDFLAG(CAN_UNWIND_WITH_FRAME_POINTERS)
+#if !BUILDFLAG(IS_ANDROID) || !BUILDFLAG(CAN_UNWIND_WITH_FRAME_POINTERS)
TEST_F(CrashAnalyzerTest, StackTraceCollection) {
void* ptr = gpa_.Allocate(10);
ASSERT_NE(ptr, nullptr);
diff --git a/chromium/components/gwp_asan/crash_handler/crash_handler.cc b/chromium/components/gwp_asan/crash_handler/crash_handler.cc
index a401b416e51..7dffbeae0d2 100644
--- a/chromium/components/gwp_asan/crash_handler/crash_handler.cc
+++ b/chromium/components/gwp_asan/crash_handler/crash_handler.cc
@@ -8,7 +8,6 @@
#include <memory>
#include <string>
-#include "base/compiler_specific.h"
#include "base/logging.h"
#include "components/gwp_asan/crash_handler/crash.pb.h"
#include "components/gwp_asan/crash_handler/crash_analyzer.h"
@@ -42,9 +41,8 @@ BufferExtensionStreamDataSource::BufferExtensionStreamDataSource(
uint32_t stream_type,
const Crash& crash)
: crashpad::MinidumpUserExtensionStreamDataSource(stream_type) {
- bool result = crash.SerializeToString(&data_);
+ [[maybe_unused]] bool result = crash.SerializeToString(&data_);
DCHECK(result);
- ALLOW_UNUSED_LOCAL(result);
}
size_t BufferExtensionStreamDataSource::StreamDataSize() {
diff --git a/chromium/components/gwp_asan/crash_handler/crash_handler_unittest.cc b/chromium/components/gwp_asan/crash_handler/crash_handler_unittest.cc
index 67a58a51efd..2233791ee4d 100644
--- a/chromium/components/gwp_asan/crash_handler/crash_handler_unittest.cc
+++ b/chromium/components/gwp_asan/crash_handler/crash_handler_unittest.cc
@@ -34,7 +34,7 @@
#include "third_party/crashpad/crashpad/snapshot/minidump/process_snapshot_minidump.h"
#include "third_party/crashpad/crashpad/tools/tool_support.h"
-#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID)
#include "third_party/crashpad/crashpad/snapshot/sanitized/sanitization_information.h"
#endif
@@ -47,7 +47,7 @@ constexpr size_t kAllocationSize = 902;
constexpr int kSuccess = 0;
constexpr size_t kTotalPages = AllocatorState::kMaxSlots;
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
int HandlerMainAdaptor(int argc, char* argv[]) {
crashpad::UserStreamDataSources user_stream_data_sources;
user_stream_data_sources.push_back(
@@ -60,7 +60,7 @@ MULTIPROCESS_TEST_MAIN(CrashpadHandler) {
base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
// Remove the --test-child-process argument from argv and launch crashpad.
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
std::vector<wchar_t*> argv;
for (auto& arg : cmd_line->argv()) {
if (arg.find(L"test-child-process") == std::string::npos)
@@ -80,11 +80,11 @@ MULTIPROCESS_TEST_MAIN(CrashpadHandler) {
return 0;
}
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
// Child process that launches the crashpad handler and then crashes.
MULTIPROCESS_TEST_MAIN(CrashingProcess) {
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
// Disable the system crash reporter from inspecting this crash (it is slow
// and causes test timeouts.)
crashpad::CrashpadInfo::GetCrashpadInfo()
@@ -122,7 +122,7 @@ MULTIPROCESS_TEST_MAIN(CrashingProcess) {
std::map<std::string, std::string> annotations;
std::vector<std::string> arguments;
-#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID)
static crashpad::SanitizationInformation sanitization_info = {};
static crashpad::SanitizationAllowedMemoryRanges allowed_memory_ranges;
if (cmd_line->HasSwitch("sanitize")) {
@@ -145,12 +145,12 @@ MULTIPROCESS_TEST_MAIN(CrashingProcess) {
}
#endif
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
arguments.push_back("--test-child-process=CrashpadHandler");
#endif
crashpad::CrashpadClient* client = new crashpad::CrashpadClient();
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
bool handler =
client->StartHandlerAtCrash(/* handler */ cmd_line->GetProgram(),
/* database */ directory,
@@ -158,7 +158,7 @@ MULTIPROCESS_TEST_MAIN(CrashingProcess) {
/* url */ "",
/* annotations */ annotations,
/* arguments */ arguments);
-#elif defined(OS_ANDROID)
+#elif BUILDFLAG(IS_ANDROID)
// TODO: Once the minSdkVersion is >= Q define a CrashpadHandlerMain() and
// use the /system/bin/linker approach instead of using
// libchrome_crashpad_handler.so
@@ -225,7 +225,7 @@ MULTIPROCESS_TEST_MAIN(CrashingProcess) {
gpa->Deallocate(ptrs[0]);
// Take the remaining metadata slot with an allocation on a different page.
- while (1) {
+ while (true) {
void* new_alloc = gpa->Allocate(1);
if (new_alloc != ptrs[0])
break;
@@ -292,13 +292,13 @@ class CrashHandlerTest : public base::MultiProcessTest,
cmd_line.AppendSwitch("sanitize");
base::LaunchOptions options;
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
options.start_hidden = true;
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
base::Process process =
base::SpawnMultiProcessTestChild("CrashingProcess", cmd_line, options);
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
int exit_code = -1;
EXPECT_TRUE(WaitForMultiprocessTestChildExit(
process, TestTimeouts::action_max_timeout(), &exit_code));
@@ -402,7 +402,7 @@ class CrashHandlerTest : public base::MultiProcessTest,
bool gwp_asan_found_;
};
-#if defined(ADDRESS_SANITIZER) && (defined(OS_WIN) || defined(OS_ANDROID))
+#if defined(ADDRESS_SANITIZER) && (BUILDFLAG(IS_WIN) || BUILDFLAG(IS_ANDROID))
// ASan intercepts crashes and crashpad doesn't have a chance to see them.
#define MAYBE_DISABLED(name) DISABLED_ ##name
#else
@@ -458,7 +458,7 @@ TEST_P(CrashHandlerTest, MAYBE_DISABLED(UnrelatedException)) {
INSTANTIATE_TEST_SUITE_P(VaryAllocator,
CrashHandlerTest,
testing::Values(
-#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID)
TestParams("malloc", true),
#endif
TestParams("malloc", false),
diff --git a/chromium/components/handoff/handoff_manager.h b/chromium/components/handoff/handoff_manager.h
index 7bf06d3ec76..f6d9bbad64e 100644
--- a/chromium/components/handoff/handoff_manager.h
+++ b/chromium/components/handoff/handoff_manager.h
@@ -13,7 +13,7 @@
@class NSUserActivity;
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
namespace user_prefs {
class PrefRegistrySyncable;
} // namespace user_prefs
@@ -23,7 +23,7 @@ class PrefRegistrySyncable;
// hand off the current active URL to other devices.
@interface HandoffManager : NSObject
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
// Registers preferences related to Handoff.
+ (void)registerBrowserStatePrefs:(user_prefs::PrefRegistrySyncable*)registry;
#endif
@@ -42,7 +42,7 @@ class PrefRegistrySyncable;
@end
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
@interface HandoffManager (TestingOnly)
- (NSURL*)userActivityWebpageURL;
- (NSString*)userActivityTitle;
diff --git a/chromium/components/handoff/handoff_manager.mm b/chromium/components/handoff/handoff_manager.mm
index 853c554b847..e90c66af0d4 100644
--- a/chromium/components/handoff/handoff_manager.mm
+++ b/chromium/components/handoff/handoff_manager.mm
@@ -12,12 +12,12 @@
#include "build/build_config.h"
#include "net/base/mac/url_conversions.h"
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
#include "components/handoff/pref_names_ios.h"
#include "components/pref_registry/pref_registry_syncable.h" // nogncheck
#endif
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
#include "base/mac/mac_util.h"
#endif
@@ -42,7 +42,7 @@
@synthesize userActivity = _userActivity;
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
+ (void)registerBrowserStatePrefs:(user_prefs::PrefRegistrySyncable*)registry {
registry->RegisterBooleanPref(
prefs::kIosHandoffToOtherDevices, true,
@@ -53,9 +53,9 @@
- (instancetype)init {
self = [super init];
if (self) {
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
_origin = handoff::ORIGIN_MAC;
-#elif defined(OS_IOS)
+#elif BUILDFLAG(IS_IOS)
_origin = handoff::ORIGIN_IOS;
#else
NOTREACHED();
@@ -113,7 +113,7 @@
@end
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
@implementation HandoffManager (TestingOnly)
- (NSURL*)userActivityWebpageURL {
diff --git a/chromium/components/heap_profiling/in_process/heap_profiler_controller.cc b/chromium/components/heap_profiling/in_process/heap_profiler_controller.cc
index dd1d2f55143..8b17b88148a 100644
--- a/chromium/components/heap_profiling/in_process/heap_profiler_controller.cc
+++ b/chromium/components/heap_profiling/in_process/heap_profiler_controller.cc
@@ -5,6 +5,7 @@
#include "components/heap_profiling/in_process/heap_profiler_controller.h"
#include <cmath>
+#include <limits>
#include "base/bind.h"
#include "base/feature_list.h"
@@ -14,6 +15,8 @@
#include "base/profiler/module_cache.h"
#include "base/rand_util.h"
#include "base/sampling_heap_profiler/sampling_heap_profiler.h"
+#include "base/strings/strcat.h"
+#include "base/strings/string_piece.h"
#include "base/task/post_task.h"
#include "base/task/thread_pool.h"
#include "base/threading/sequenced_task_runner_handle.h"
@@ -27,16 +30,16 @@ namespace {
// Platform-specific parameter defaults.
-#if defined(OS_IOS) || defined(OS_ANDROID)
+#if BUILDFLAG(IS_IOS) || BUILDFLAG(IS_ANDROID)
// Average 1M bytes per sample.
-constexpr int kDefaultSamplingRate = 1000000;
+constexpr int kDefaultSamplingRateBytes = 1'000'000;
// Default on iOS is equal to mean value of up process time. Android is
// more similar to iOS than to Desktop.
constexpr int kDefaultCollectionIntervalInMinutes = 30;
#else
// Average 10M bytes per sample.
-constexpr int kDefaultSamplingRate = 10000000;
+constexpr int kDefaultSamplingRateBytes = 10'000'000;
// Default on desktop is once per day.
constexpr int kDefaultCollectionIntervalInMinutes = 24 * 60;
@@ -55,9 +58,9 @@ constexpr base::FeatureParam<double> kNonStableProbability{
0.5};
// Sets heap sampling interval in bytes.
-constexpr base::FeatureParam<int> kSamplingRate{
+constexpr base::FeatureParam<int> kSamplingRateBytes{
&HeapProfilerController::kHeapProfilerReporting, "sampling-rate",
- kDefaultSamplingRate};
+ kDefaultSamplingRateBytes};
// Sets the interval between snapshots.
constexpr base::FeatureParam<int> kCollectionIntervalMinutes{
@@ -68,7 +71,12 @@ constexpr base::FeatureParam<int> kCollectionIntervalMinutes{
base::TimeDelta RandomInterval(base::TimeDelta mean) {
// Time intervals between profile collections form a Poisson stream with
// given mean interval.
- return -std::log(base::RandDouble()) * mean;
+ double rnd = base::RandDouble();
+ if (rnd == 0) {
+ // log(0) is an error.
+ rnd = std::numeric_limits<double>::min();
+ }
+ return -std::log(rnd) * mean;
}
bool DecideIfCollectionIsEnabled(version_info::Channel channel) {
@@ -83,6 +91,30 @@ bool DecideIfCollectionIsEnabled(version_info::Channel channel) {
return base::RandDouble() < probability;
}
+// Records a time histogram for the `interval` between snapshots, using the
+// appropriate histogram buckets for the platform (desktop or mobile).
+// `recording_time` must be one of the {RecordingTime} token variants in the
+// definition of HeapProfiling.InProcess.SnapshotInterval.{Platform}.
+// {RecordingTime} in tools/metrics/histograms/metadata/memory/histograms.xml.
+void RecordUmaSnapshotInterval(base::TimeDelta interval,
+ base::StringPiece recording_time) {
+#if BUILDFLAG(IS_IOS) || BUILDFLAG(IS_ANDROID)
+ // On mobile, the interval is distributed around a mean of 30 minutes.
+ constexpr base::TimeDelta kMinHistogramTime = base::Seconds(30);
+ constexpr base::TimeDelta kMaxHistogramTime = base::Hours(3);
+ constexpr const char* const kPlatform = "Mobile";
+#else
+ // On desktop, the interval is distributed around a mean of 1 day.
+ constexpr base::TimeDelta kMinHistogramTime = base::Minutes(30);
+ constexpr base::TimeDelta kMaxHistogramTime = base::Days(6);
+ constexpr const char* const kPlatform = "Desktop";
+#endif
+ base::UmaHistogramCustomTimes(
+ base::StrCat({"HeapProfiling.InProcess.SnapshotInterval.", kPlatform, ".",
+ recording_time}),
+ interval, kMinHistogramTime, kMaxHistogramTime, 50);
+}
+
} // namespace
constexpr base::Feature HeapProfilerController::kHeapProfilerReporting{
@@ -101,9 +133,9 @@ void HeapProfilerController::Start() {
profiling_enabled_);
if (!profiling_enabled_)
return;
- int sampling_rate = kSamplingRate.Get();
- if (sampling_rate > 0)
- base::SamplingHeapProfiler::Get()->SetSamplingInterval(sampling_rate);
+ int sampling_rate_bytes = kSamplingRateBytes.Get();
+ if (sampling_rate_bytes > 0)
+ base::SamplingHeapProfiler::Get()->SetSamplingInterval(sampling_rate_bytes);
base::SamplingHeapProfiler::Get()->Start();
const int interval = kCollectionIntervalMinutes.Get();
DCHECK_GT(interval, 0);
@@ -120,23 +152,26 @@ void HeapProfilerController::SuppressRandomnessForTesting() {
void HeapProfilerController::ScheduleNextSnapshot(
scoped_refptr<StoppedFlag> stopped,
CollectionInterval heap_collection_interval) {
- base::TimeDelta next_interval =
+ base::TimeDelta interval =
heap_collection_interval.use_random_interval
? RandomInterval(heap_collection_interval.interval)
: heap_collection_interval.interval;
+ RecordUmaSnapshotInterval(interval, "Scheduled");
base::ThreadPool::PostDelayedTask(
FROM_HERE, {base::TaskPriority::BEST_EFFORT},
base::BindOnce(&HeapProfilerController::TakeSnapshot, std::move(stopped),
- heap_collection_interval),
- next_interval);
+ heap_collection_interval, /*previous_interval=*/interval),
+ interval);
}
// static
void HeapProfilerController::TakeSnapshot(
scoped_refptr<StoppedFlag> stopped,
- CollectionInterval heap_collection_interval) {
+ CollectionInterval heap_collection_interval,
+ base::TimeDelta previous_interval) {
if (stopped->data.IsSet())
return;
+ RecordUmaSnapshotInterval(previous_interval, "Taken");
RetrieveAndSendSnapshot();
ScheduleNextSnapshot(std::move(stopped), heap_collection_interval);
}
@@ -145,6 +180,8 @@ void HeapProfilerController::TakeSnapshot(
void HeapProfilerController::RetrieveAndSendSnapshot() {
std::vector<Sample> samples =
base::SamplingHeapProfiler::Get()->GetSamples(0);
+ base::UmaHistogramCounts100000("HeapProfiling.InProcess.SamplesPerSnapshot",
+ samples.size());
if (samples.empty())
return;
diff --git a/chromium/components/heap_profiling/in_process/heap_profiler_controller.h b/chromium/components/heap_profiling/in_process/heap_profiler_controller.h
index 0d482eb8521..65ce8929580 100644
--- a/chromium/components/heap_profiling/in_process/heap_profiler_controller.h
+++ b/chromium/components/heap_profiling/in_process/heap_profiler_controller.h
@@ -76,8 +76,15 @@ class HeapProfilerController {
};
static void ScheduleNextSnapshot(scoped_refptr<StoppedFlag> stopped,
CollectionInterval heap_collection_interval);
+
+ // Takes a heap snapshot unless the `stopped` flag is set.
+ // `heap_collection_interval` is used to schedule the next snapshot.
+ // `previous_interval` is the time since the previous snapshot, which is used
+ // to log metrics about snapshot frequency.
static void TakeSnapshot(scoped_refptr<StoppedFlag> stopped,
- CollectionInterval heap_collection_interval);
+ CollectionInterval heap_collection_interval,
+ base::TimeDelta previous_interval);
+
static void RetrieveAndSendSnapshot();
// On startup this will be determined randomly based on the current channel
diff --git a/chromium/components/heap_profiling/in_process/heap_profiler_controller_unittest.cc b/chromium/components/heap_profiling/in_process/heap_profiler_controller_unittest.cc
index c10eba27ea1..cbd0258ec32 100644
--- a/chromium/components/heap_profiling/in_process/heap_profiler_controller_unittest.cc
+++ b/chromium/components/heap_profiling/in_process/heap_profiler_controller_unittest.cc
@@ -32,30 +32,35 @@ namespace {
constexpr size_t kSamplingRate = 1024;
constexpr size_t kAllocationSize = 42 * kSamplingRate;
-// Configurations of the HeapProfilerReporting feature to test.
-// The default parameters always enable reporting on all channels.
-struct HeapProfilerReportingConfig {
- bool enabled = true;
- double stable_probability = 1.0;
- double nonstable_probability = 1.0;
-};
+} // namespace
-// A wrapper that sets up a HeapProfilerController for testing.
-class HeapProfilerControllerTester {
+// HeapProfilerControllerTest can't be in an anonymous namespace because it is a
+// friend of SamplingHeapProfiler.
+class HeapProfilerControllerTest : public ::testing::Test {
public:
- HeapProfilerControllerTester(
- version_info::Channel channel,
- base::RepeatingCallback<void(base::TimeTicks, metrics::SampledProfile)>
- receiver_callback,
- const HeapProfilerReportingConfig& feature_config =
- HeapProfilerReportingConfig()) {
- if (feature_config.enabled) {
+ // Sets `sample_received_` to true if any sample is received. This will work
+ // even without stack unwinding since it doesn't check the contents of the
+ // sample. This must be public so that BindRepeating can access it from
+ // subclasses.
+ void RecordSampleReceived(base::TimeTicks, metrics::SampledProfile) {
+ sample_received_ = true;
+ }
+
+ protected:
+ // The default constructor parameters enable the HeapProfilerReporting feature
+ // on all channels. Child classes can override the constructor to create test
+ // suites that test different configurations.
+ explicit HeapProfilerControllerTest(bool feature_enabled = true,
+ double stable_probability = 1.0,
+ double nonstable_probability = 1.0) {
+ // ScopedFeatureList must be initialized in the constructor, before any
+ // threads are started.
+ if (feature_enabled) {
feature_list_.InitAndEnableFeatureWithParameters(
HeapProfilerController::kHeapProfilerReporting,
- {{"stable-probability",
- base::NumberToString(feature_config.stable_probability)},
+ {{"stable-probability", base::NumberToString(stable_probability)},
{"nonstable-probability",
- base::NumberToString(feature_config.nonstable_probability)},
+ base::NumberToString(nonstable_probability)},
{"sampling-rate", base::NumberToString(kSamplingRate)}});
} else {
feature_list_.InitAndDisableFeature(
@@ -64,44 +69,6 @@ class HeapProfilerControllerTester {
base::SamplingHeapProfiler::Get()->SetSamplingInterval(kSamplingRate);
}
- metrics::CallStackProfileBuilder::SetBrowserProcessReceiverCallback(
- std::move(receiver_callback));
-
- controller_ = std::make_unique<HeapProfilerController>(channel);
- controller_->SuppressRandomnessForTesting();
- }
-
- ~HeapProfilerControllerTester() {
- metrics::CallStackProfileBuilder::SetBrowserProcessReceiverCallback(
- base::DoNothing());
- }
-
- HeapProfilerControllerTester(const HeapProfilerControllerTester&) = delete;
- HeapProfilerControllerTester& operator=(const HeapProfilerControllerTester&) =
- delete;
-
- HeapProfilerController& controller() { return *controller_; }
-
- const base::HistogramTester& histogram_tester() const {
- return histogram_tester_;
- }
-
- private:
- std::unique_ptr<HeapProfilerController> controller_;
- base::test::ScopedFeatureList feature_list_;
- base::HistogramTester histogram_tester_;
-};
-
-// A callback that fails the test if any samples are received.
-void ExpectNoSamples(base::TimeTicks, metrics::SampledProfile) {
- ADD_FAILURE();
-}
-
-} // namespace
-
-class HeapProfilerControllerTest : public ::testing::Test {
- protected:
- HeapProfilerControllerTest() {
// Clear any samples set in the global SamplingHeapProfiler before the
// ScopedMuteHookedSamplesForTesting was created.
base::SamplingHeapProfiler::Get()->ClearSamplesForTesting();
@@ -110,6 +77,23 @@ class HeapProfilerControllerTest : public ::testing::Test {
~HeapProfilerControllerTest() override {
base::PoissonAllocationSampler::Get()->SuppressRandomnessForTest(false);
+
+ // Remove any callback that was set in StartHeapProfiling.
+ metrics::CallStackProfileBuilder::SetBrowserProcessReceiverCallback(
+ base::DoNothing());
+ }
+
+ void StartHeapProfiling(
+ version_info::Channel channel,
+ base::RepeatingCallback<void(base::TimeTicks, metrics::SampledProfile)>
+ receiver_callback) {
+ ASSERT_FALSE(controller_) << "StartHeapProfiling called twice";
+ metrics::CallStackProfileBuilder::SetBrowserProcessReceiverCallback(
+ std::move(receiver_callback));
+
+ controller_ = std::make_unique<HeapProfilerController>(channel);
+ controller_->SuppressRandomnessForTesting();
+ controller_->Start();
}
void AddOneSampleAndWait() {
@@ -124,31 +108,45 @@ class HeapProfilerControllerTest : public ::testing::Test {
sampler->RecordFree(reinterpret_cast<void*>(0x1337));
}
+ // Initialize `mute_hooks_` before `task_environment_` so that memory
+ // allocations aren't sampled while TaskEnvironment creates a thread. The
+ // sampling is crashing in the hooked FreeFunc on some test bots.
+ base::PoissonAllocationSampler::ScopedMuteHookedSamplesForTesting mute_hooks_;
+
+ // Create `feature_list_` before `task_environment_` and destroy it after to
+ // avoid a race in destruction.
+ base::test::ScopedFeatureList feature_list_;
+
base::test::TaskEnvironment task_environment_{
base::test::TaskEnvironment::TimeSource::MOCK_TIME};
- base::PoissonAllocationSampler::ScopedMuteHookedSamplesForTesting mute_hooks_;
+
+ std::unique_ptr<HeapProfilerController> controller_;
+ base::HistogramTester histogram_tester_;
+
+ // `sample_received_` is read from the main thread and written from a
+ // background thread, but does not need to be atomic because the write happens
+ // during a scheduled sample and the read happens well after that.
+ bool sample_received_ = false;
};
+namespace {
+
TEST_F(HeapProfilerControllerTest, EmptyProfileIsNotEmitted) {
- HeapProfilerControllerTester tester(version_info::Channel::STABLE,
- base::BindRepeating(&ExpectNoSamples));
- tester.controller().Start();
+ StartHeapProfiling(
+ version_info::Channel::STABLE,
+ base::BindRepeating(&HeapProfilerControllerTest::RecordSampleReceived,
+ base::Unretained(this)));
+
// Advance several days to be sure the sample isn't scheduled right on the
// boundary of the fast-forward.
task_environment_.FastForwardBy(base::Days(2));
+
+ EXPECT_FALSE(sample_received_);
}
// Sampling profiler is not capable of unwinding stack on Android under tests.
-#if !defined(OS_ANDROID)
-
-// See crbug.com/1276033
-#if defined(OS_APPLE)
-#define MAYBE_ProfileCollectionsScheduler DISABLED_ProfileCollectionsScheduler
-#else
-#define MAYBE_ProfileCollectionsScheduler ProfileCollectionsScheduler
-#endif
-
-TEST_F(HeapProfilerControllerTest, MAYBE_ProfileCollectionsScheduler) {
+#if !BUILDFLAG(IS_ANDROID)
+TEST_F(HeapProfilerControllerTest, ProfileCollectionsScheduler) {
constexpr int kSnapshotsToCollect = 3;
std::atomic<int> profile_count{0};
@@ -174,9 +172,8 @@ TEST_F(HeapProfilerControllerTest, MAYBE_ProfileCollectionsScheduler) {
++profile_count;
};
- HeapProfilerControllerTester tester(
- version_info::Channel::STABLE, base::BindLambdaForTesting(check_profile));
- tester.controller().Start();
+ StartHeapProfiling(version_info::Channel::STABLE,
+ base::BindLambdaForTesting(check_profile));
auto* sampler = base::PoissonAllocationSampler::Get();
sampler->RecordAlloc(reinterpret_cast<void*>(0x1337), kAllocationSize,
@@ -198,84 +195,81 @@ TEST_F(HeapProfilerControllerTest, MAYBE_ProfileCollectionsScheduler) {
}
#endif
-// Test that disabling the HeapProfilerReporting feature disables metrics
-// uploading.
-TEST_F(HeapProfilerControllerTest, DisableFeature) {
- HeapProfilerControllerTester tester(
- version_info::Channel::STABLE, base::BindRepeating(&ExpectNoSamples),
- HeapProfilerReportingConfig{.enabled = false});
- tester.controller().Start();
- tester.histogram_tester().ExpectUniqueSample(
- "HeapProfiling.InProcess.Enabled", false, 1);
- AddOneSampleAndWait();
-}
+// Configurations of the HeapProfilerReporting feature to test.
+struct FeatureTestParams {
+ bool feature_enabled = true;
+ double stable_probability = 1.0;
+ double nonstable_probability = 1.0;
+ bool expect_stable_sample = true;
+ bool expect_nonstable_sample = true;
+};
+constexpr FeatureTestParams kAllFeatureConfigs[] = {
+ // Disabled.
+ {.feature_enabled = false,
+ .expect_stable_sample = false,
+ .expect_nonstable_sample = false},
+ // Enabled, but with probability 0 on all channels.
+ {.feature_enabled = true,
+ .stable_probability = 0.0,
+ .nonstable_probability = 0.0,
+ .expect_stable_sample = false,
+ .expect_nonstable_sample = false},
+ // Enabled on all channels.
+ {.feature_enabled = true,
+ .stable_probability = 1.0,
+ .nonstable_probability = 1.0,
+ .expect_stable_sample = true,
+ .expect_nonstable_sample = true},
+ // Enabled on stable channel only.
+ {.feature_enabled = true,
+ .stable_probability = 1.0,
+ .nonstable_probability = 0.0,
+ .expect_stable_sample = true,
+ .expect_nonstable_sample = false},
+ // Enabled on non-stable channels only.
+ {.feature_enabled = true,
+ .stable_probability = 0.0,
+ .nonstable_probability = 1.0,
+ .expect_stable_sample = false,
+ .expect_nonstable_sample = true},
+};
-// Test that the "stable-probability" param can disable metrics uploading on the
-// stable channel.
-TEST_F(HeapProfilerControllerTest, StableProbability) {
- HeapProfilerReportingConfig feature_config{
- .enabled = true, .stable_probability = 0.0, .nonstable_probability = 1.0};
-
- // Test stable channel.
- {
- HeapProfilerControllerTester tester(version_info::Channel::STABLE,
- base::BindRepeating(&ExpectNoSamples),
- feature_config);
- tester.controller().Start();
- tester.histogram_tester().ExpectUniqueSample(
- "HeapProfiling.InProcess.Enabled", false, 1);
- AddOneSampleAndWait();
- }
+class HeapProfilerControllerFeatureTest
+ : public HeapProfilerControllerTest,
+ public ::testing::WithParamInterface<FeatureTestParams> {
+ public:
+ HeapProfilerControllerFeatureTest()
+ : HeapProfilerControllerTest(GetParam().feature_enabled,
+ GetParam().stable_probability,
+ GetParam().nonstable_probability) {}
+};
- // Test canary channel.
- {
- std::atomic<bool> got_sample;
- auto watch_for_sample = [&](base::TimeTicks, metrics::SampledProfile) {
- got_sample = true;
- };
- HeapProfilerControllerTester tester(
- version_info::Channel::CANARY,
- base::BindLambdaForTesting(watch_for_sample), feature_config);
- tester.controller().Start();
- tester.histogram_tester().ExpectUniqueSample(
- "HeapProfiling.InProcess.Enabled", true, 1);
- AddOneSampleAndWait();
- EXPECT_TRUE(got_sample);
- }
+INSTANTIATE_TEST_SUITE_P(All,
+ HeapProfilerControllerFeatureTest,
+ ::testing::ValuesIn(kAllFeatureConfigs));
+
+TEST_P(HeapProfilerControllerFeatureTest, StableChannel) {
+ StartHeapProfiling(
+ version_info::Channel::STABLE,
+ base::BindRepeating(&HeapProfilerControllerTest::RecordSampleReceived,
+ base::Unretained(this)));
+ histogram_tester_.ExpectUniqueSample("HeapProfiling.InProcess.Enabled",
+ GetParam().expect_stable_sample, 1);
+ AddOneSampleAndWait();
+ EXPECT_EQ(sample_received_, GetParam().expect_stable_sample);
}
-// Test that the "nonstable-probability" param can disable metrics uploading on
-// the canary channel.
-TEST_F(HeapProfilerControllerTest, NonStableProbability) {
- HeapProfilerReportingConfig feature_config{
- .enabled = true, .stable_probability = 1.0, .nonstable_probability = 0.0};
-
- // Test stable channel.
- {
- std::atomic<bool> got_sample;
- auto watch_for_sample = [&](base::TimeTicks, metrics::SampledProfile) {
- got_sample = true;
- };
- HeapProfilerControllerTester tester(
- version_info::Channel::STABLE,
- base::BindLambdaForTesting(watch_for_sample), feature_config);
- tester.controller().Start();
- tester.histogram_tester().ExpectUniqueSample(
- "HeapProfiling.InProcess.Enabled", true, 1);
- AddOneSampleAndWait();
- EXPECT_TRUE(got_sample);
- }
-
- // Test canary channel.
- {
- HeapProfilerControllerTester tester(version_info::Channel::CANARY,
- base::BindRepeating(&ExpectNoSamples),
- feature_config);
- tester.controller().Start();
- tester.histogram_tester().ExpectUniqueSample(
- "HeapProfiling.InProcess.Enabled", false, 1);
- AddOneSampleAndWait();
- }
+TEST_P(HeapProfilerControllerFeatureTest, CanaryChannel) {
+ StartHeapProfiling(
+ version_info::Channel::CANARY,
+ base::BindRepeating(&HeapProfilerControllerTest::RecordSampleReceived,
+ base::Unretained(this)));
+ histogram_tester_.ExpectUniqueSample("HeapProfiling.InProcess.Enabled",
+ GetParam().expect_nonstable_sample, 1);
+ AddOneSampleAndWait();
+ EXPECT_EQ(sample_received_, GetParam().expect_nonstable_sample);
}
+} // namespace
+
} // namespace heap_profiling
diff --git a/chromium/components/heap_profiling/multi_process/supervisor.h b/chromium/components/heap_profiling/multi_process/supervisor.h
index 7bceaca6ee9..a94a69c157d 100644
--- a/chromium/components/heap_profiling/multi_process/supervisor.h
+++ b/chromium/components/heap_profiling/multi_process/supervisor.h
@@ -6,6 +6,7 @@
#define COMPONENTS_HEAP_PROFILING_MULTI_PROCESS_SUPERVISOR_H_
#include "base/memory/weak_ptr.h"
+#include "base/no_destructor.h"
#include "base/process/process.h"
#include "components/services/heap_profiling/public/mojom/heap_profiling_client.mojom.h"
#include "services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom.h"
diff --git a/chromium/components/heap_profiling/multi_process/test_driver.cc b/chromium/components/heap_profiling/multi_process/test_driver.cc
index 557a47ce812..13a547ed53a 100644
--- a/chromium/components/heap_profiling/multi_process/test_driver.cc
+++ b/chromium/components/heap_profiling/multi_process/test_driver.cc
@@ -89,7 +89,7 @@ int NumProcessesWithName(base::Value* dump_json,
std::vector<int>* pids) {
int num_processes = 0;
base::Value* events = dump_json->FindKey("traceEvents");
- for (const base::Value& event : events->GetList()) {
+ for (const base::Value& event : events->GetListDeprecated()) {
const base::Value* found_name =
event.FindKeyOfType("name", base::Value::Type::STRING);
if (!found_name)
@@ -128,7 +128,7 @@ base::Value* FindArgDump(base::ProcessId pid,
base::Value* events = dump_json->FindKey("traceEvents");
base::Value* dumps = nullptr;
base::Value* heaps_v2 = nullptr;
- for (base::Value& event : events->GetList()) {
+ for (base::Value& event : events->GetListDeprecated()) {
const base::Value* found_name =
event.FindKeyOfType("name", base::Value::Type::STRING);
if (!found_name)
@@ -160,7 +160,7 @@ using NodeMap = std::unordered_map<uint64_t, Node>;
// Parses maps.types and maps.strings. Returns |true| on success.
bool ParseTypes(base::Value* heaps_v2, NodeMap* output) {
base::Value* types = heaps_v2->FindPath({"maps", "types"});
- for (const base::Value& type_value : types->GetList()) {
+ for (const base::Value& type_value : types->GetListDeprecated()) {
const base::Value* id = type_value.FindKey("id");
const base::Value* name_sid = type_value.FindKey("name_sid");
if (!id || !name_sid) {
@@ -174,7 +174,7 @@ bool ParseTypes(base::Value* heaps_v2, NodeMap* output) {
}
base::Value* strings = heaps_v2->FindPath({"maps", "strings"});
- for (const base::Value& string_value : strings->GetList()) {
+ for (const base::Value& string_value : strings->GetListDeprecated()) {
const base::Value* id = string_value.FindKey("id");
const base::Value* string = string_value.FindKey("string");
if (!id || !string) {
@@ -206,7 +206,7 @@ bool GetAllocatorSubarray(base::Value* heaps_v2,
return false;
}
- base::Value::ConstListView subarray_list = subarray->GetList();
+ base::Value::ConstListView subarray_list = subarray->GetListDeprecated();
if (expected_size && subarray_list.size() != expected_size) {
LOG(ERROR) << subarray_name << " has wrong size";
return false;
@@ -300,7 +300,7 @@ bool ValidateProcessMmaps(base::Value* process_mmaps,
size_t count = 0;
if (process_mmaps) {
vm_regions = process_mmaps->FindKey("vm_regions");
- count = vm_regions->GetList().size();
+ count = vm_regions->GetListDeprecated().size();
}
if (!should_have_contents) {
if (count != 0) {
@@ -317,7 +317,7 @@ bool ValidateProcessMmaps(base::Value* process_mmaps,
// File paths may contain PII. Make sure that "mf" entries only contain the
// basename, rather than a full path.
- for (const base::Value& vm_region : vm_regions->GetList()) {
+ for (const base::Value& vm_region : vm_regions->GetListDeprecated()) {
const base::Value* file_path_value = vm_region.FindKey("mf");
if (file_path_value) {
std::string file_path = file_path_value->GetString();
@@ -343,13 +343,14 @@ TestDriver::TestDriver()
: wait_for_ui_thread_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
base::WaitableEvent::InitialState::NOT_SIGNALED) {
base::PartitionAllocGlobalInit(HandleOOM);
- partition_allocator_.init({base::PartitionOptions::AlignedAlloc::kDisallowed,
- base::PartitionOptions::ThreadCache::kDisabled,
- base::PartitionOptions::Quarantine::kDisallowed,
- base::PartitionOptions::Cookie::kAllowed,
- base::PartitionOptions::BackupRefPtr::kDisabled,
- base::PartitionOptions::UseConfigurablePool::kNo,
- base::PartitionOptions::LazyCommit::kEnabled});
+ partition_allocator_.init({
+ base::PartitionOptions::AlignedAlloc::kDisallowed,
+ base::PartitionOptions::ThreadCache::kDisabled,
+ base::PartitionOptions::Quarantine::kDisallowed,
+ base::PartitionOptions::Cookie::kAllowed,
+ base::PartitionOptions::BackupRefPtr::kDisabled,
+ base::PartitionOptions::UseConfigurablePool::kNo,
+ });
}
TestDriver::~TestDriver() {
base::PartitionAllocGlobalUninitForTesting();
@@ -633,7 +634,7 @@ bool TestDriver::ValidateBrowserAllocations(base::Value* dump_json) {
bool result = false;
bool should_validate_dumps = true;
-#if defined(OS_ANDROID) && !defined(OFFICIAL_BUILD)
+#if BUILDFLAG(IS_ANDROID) && !defined(OFFICIAL_BUILD)
// TODO(ajwong): This step fails on Nexus 5X devices running kit-kat. It works
// on Nexus 5X devices running oreo. The problem is that all allocations have
// the same [an effectively empty] backtrace and get glommed together. More
diff --git a/chromium/components/heavy_ad_intervention/heavy_ad_helper.cc b/chromium/components/heavy_ad_intervention/heavy_ad_helper.cc
index 5f5f7c7e138..387d44d64c3 100644
--- a/chromium/components/heavy_ad_intervention/heavy_ad_helper.cc
+++ b/chromium/components/heavy_ad_intervention/heavy_ad_helper.cc
@@ -37,20 +37,20 @@ std::string PrepareHeavyAdPage(const std::string& application_locale) {
// Populate load time data.
base::DictionaryValue load_time_data;
- load_time_data.SetString("type", "HEAVYAD");
- load_time_data.SetString(
+ load_time_data.SetStringKey("type", "HEAVYAD");
+ load_time_data.SetStringKey(
"heading", l10n_util::GetStringUTF16(IDS_HEAVY_AD_INTERVENTION_HEADING));
- load_time_data.SetString(
+ load_time_data.SetStringKey(
"openDetails",
l10n_util::GetStringUTF16(IDS_HEAVY_AD_INTERVENTION_BUTTON_DETAILS));
- load_time_data.SetString(
+ load_time_data.SetStringKey(
"explanationParagraph",
l10n_util::GetStringUTF16(IDS_HEAVY_AD_INTERVENTION_SUMMARY));
// Ad frames are never the main frame, so we do not need a tab title.
- load_time_data.SetString("tabTitle", "");
- load_time_data.SetBoolean("overridable", false);
- load_time_data.SetBoolean("is_giant", false);
+ load_time_data.SetStringKey("tabTitle", "");
+ load_time_data.SetBoolKey("overridable", false);
+ load_time_data.SetBoolKey("is_giant", false);
webui::SetLoadTimeDataDefaults(application_locale, &load_time_data);
diff --git a/chromium/components/history/core/browser/BUILD.gn b/chromium/components/history/core/browser/BUILD.gn
index f8b31a4a247..0ecdd68a276 100644
--- a/chromium/components/history/core/browser/BUILD.gn
+++ b/chromium/components/history/core/browser/BUILD.gn
@@ -180,6 +180,8 @@ bundle_data("unit_tests_bundle_data") {
"//components/test/data/history/history.48.sql",
"//components/test/data/history/history.49.sql",
"//components/test/data/history/history.50.sql",
+ "//components/test/data/history/history.51.sql",
+ "//components/test/data/history/history.52.sql",
"//components/test/data/history/thumbnail_wild/Favicons.corrupt_meta.disable",
"//components/test/data/history/thumbnail_wild/Favicons.v2.init.sql",
"//components/test/data/history/thumbnail_wild/Favicons.v3.init.sql",
@@ -213,6 +215,7 @@ source_set("unit_tests") {
"top_sites_database_unittest.cc",
"top_sites_impl_unittest.cc",
"url_database_unittest.cc",
+ "url_row_unittest.cc",
"url_utils_unittest.cc",
"visit_annotations_database_unittest.cc",
"visit_annotations_test_utils.cc",
diff --git a/chromium/components/history/core/browser/browsing_history_service.cc b/chromium/components/history/core/browser/browsing_history_service.cc
index 3f6a214ec81..4233f6ba278 100644
--- a/chromium/components/history/core/browser/browsing_history_service.cc
+++ b/chromium/components/history/core/browser/browsing_history_service.cc
@@ -687,22 +687,22 @@ void BrowsingHistoryService::WebHistoryQueryComplete(
has_synced_results_ = true;
if (const base::Value* events = results_value->FindListKey("event")) {
state->remote_results.reserve(state->remote_results.size() +
- events->GetList().size());
+ events->GetListDeprecated().size());
std::string host_name_utf8 = base::UTF16ToUTF8(state->search_text);
- for (const base::Value& event : events->GetList()) {
+ for (const base::Value& event : events->GetListDeprecated()) {
if (!event.is_dict())
continue;
const base::Value* results = event.FindListKey("result");
- if (!results || results->GetList().empty())
+ if (!results || results->GetListDeprecated().empty())
continue;
- const base::Value& result = results->GetList()[0];
+ const base::Value& result = results->GetListDeprecated()[0];
if (!result.is_dict())
continue;
const std::string* url = result.FindStringKey("url");
if (!url)
continue;
const base::Value* ids = result.FindListKey("id");
- if (!ids || ids->GetList().empty())
+ if (!ids || ids->GetListDeprecated().empty())
continue;
GURL gurl(*url);
@@ -729,7 +729,7 @@ void BrowsingHistoryService::WebHistoryQueryComplete(
// Extract the timestamps of all the visits to this URL.
// They are referred to as "IDs" by the server.
- for (const base::Value& id : ids->GetList()) {
+ for (const base::Value& id : ids->GetListDeprecated()) {
const std::string* timestamp_string;
int64_t timestamp_usec = 0;
diff --git a/chromium/components/history/core/browser/download_database.cc b/chromium/components/history/core/browser/download_database.cc
index b043c70b94c..56f1d24b854 100644
--- a/chromium/components/history/core/browser/download_database.cc
+++ b/chromium/components/history/core/browser/download_database.cc
@@ -44,7 +44,7 @@ enum DroppedReason {
DROPPED_REASON_MAX
};
-#if defined(OS_POSIX) || defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
// Binds/reads the given file path to the given column of the given statement.
void BindFilePath(sql::Statement& statement,
@@ -296,6 +296,11 @@ bool DownloadDatabase::MigrateDownloadSiteInstanceUrl() {
return EnsureColumnExists("site_url", "VARCHAR NOT NULL DEFAULT ''");
}
+bool DownloadDatabase::MigrateEmbedderDownloadData() {
+ return EnsureColumnExists("embedder_download_data",
+ "VARCHAR NOT NULL DEFAULT ''");
+}
+
bool DownloadDatabase::MigrateDownloadLastAccessTime() {
return EnsureColumnExists("last_access_time", "INTEGER NOT NULL DEFAULT 0");
}
@@ -332,16 +337,20 @@ bool DownloadDatabase::InitDownloadTable() {
"referrer VARCHAR NOT NULL," // HTTP Referrer
"site_url VARCHAR NOT NULL," // Site URL for initiating site
// instance.
- "tab_url VARCHAR NOT NULL," // Tab URL for initiator.
- "tab_referrer_url VARCHAR NOT NULL," // Tag referrer URL for
- // initiator.
- "http_method VARCHAR NOT NULL," // HTTP method.
- "by_ext_id VARCHAR NOT NULL," // ID of extension that started the
- // download
- "by_ext_name VARCHAR NOT NULL," // name of extension
- "etag VARCHAR NOT NULL," // ETag
- "last_modified VARCHAR NOT NULL," // Last-Modified header
- "mime_type VARCHAR(255) NOT NULL," // MIME type.
+ "embedder_download_data VARCHAR NOT NULL," // Serialized proto for
+ // embedder data pertaining to
+ // the initiating site
+ // instance.
+ "tab_url VARCHAR NOT NULL," // Tab URL for initiator.
+ "tab_referrer_url VARCHAR NOT NULL," // Tag referrer URL for
+ // initiator.
+ "http_method VARCHAR NOT NULL," // HTTP method.
+ "by_ext_id VARCHAR NOT NULL," // ID of extension that started the
+ // download
+ "by_ext_name VARCHAR NOT NULL," // name of extension
+ "etag VARCHAR NOT NULL," // ETag
+ "last_modified VARCHAR NOT NULL," // Last-Modified header
+ "mime_type VARCHAR(255) NOT NULL," // MIME type.
"original_mime_type VARCHAR(255) NOT NULL)" // Original MIME type.
,
kDownloadsTable);
@@ -439,9 +448,10 @@ void DownloadDatabase::QueryDownloads(std::vector<DownloadRow>* results) {
"SELECT id, guid, current_path, target_path, mime_type, "
"original_mime_type, start_time, received_bytes, total_bytes, state, "
"danger_type, interrupt_reason, hash, end_time, opened, "
- "last_access_time, transient, referrer, site_url, tab_url, "
- "tab_referrer_url, http_method, by_ext_id, by_ext_name, etag, "
- "last_modified FROM %s ORDER BY start_time",
+ "last_access_time, transient, referrer, site_url, "
+ "embedder_download_data, tab_url, tab_referrer_url, http_method, "
+ "by_ext_id, by_ext_name, etag, last_modified FROM %s ORDER BY "
+ "start_time",
kDownloadsTable)
.c_str()));
@@ -478,6 +488,7 @@ void DownloadDatabase::QueryDownloads(std::vector<DownloadRow>* results) {
info->transient = statement_main.ColumnInt(column++) != 0;
info->referrer_url = GURL(statement_main.ColumnString(column++));
info->site_url = GURL(statement_main.ColumnString(column++));
+ info->embedder_download_data = statement_main.ColumnString(column++);
info->tab_url = GURL(statement_main.ColumnString(column++));
info->tab_referrer_url = GURL(statement_main.ColumnString(column++));
info->http_method = statement_main.ColumnString(column++);
@@ -675,15 +686,14 @@ bool DownloadDatabase::CreateDownload(const DownloadRow& info) {
base::StringPrintf(
"INSERT INTO %s "
"(id, guid, current_path, target_path, mime_type, "
- "original_mime_type, "
- " start_time, received_bytes, total_bytes, state, danger_type, "
- " interrupt_reason, hash, end_time, opened, last_access_time, "
- "transient, referrer, site_url, tab_url, tab_referrer_url, "
- "http_method, "
- " by_ext_id, by_ext_name, etag, last_modified) "
+ "original_mime_type, start_time, received_bytes, total_bytes, "
+ "state, danger_type, interrupt_reason, hash, end_time, opened, "
+ "last_access_time, transient, referrer, site_url, "
+ "embedder_download_data, tab_url, tab_referrer_url, http_method, "
+ "by_ext_id, by_ext_name, etag, last_modified) "
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, "
" ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, "
- " ?, ?, ?, ?, ?, ?)",
+ " ?, ?, ?, ?, ?, ?, ?)",
kDownloadsTable)
.c_str()));
@@ -710,6 +720,7 @@ bool DownloadDatabase::CreateDownload(const DownloadRow& info) {
statement_insert.BindInt(column++, info.transient ? 1 : 0);
statement_insert.BindString(column++, info.referrer_url.spec());
statement_insert.BindString(column++, info.site_url.spec());
+ statement_insert.BindString(column++, info.embedder_download_data);
statement_insert.BindString(column++, info.tab_url.spec());
statement_insert.BindString(column++, info.tab_referrer_url.spec());
statement_insert.BindString(column++, info.http_method);
diff --git a/chromium/components/history/core/browser/download_database.h b/chromium/components/history/core/browser/download_database.h
index 4dd05e2658a..160aafb9501 100644
--- a/chromium/components/history/core/browser/download_database.h
+++ b/chromium/components/history/core/browser/download_database.h
@@ -96,6 +96,10 @@ class DownloadDatabase {
// table.
bool MigrateDownloadSiteInstanceUrl();
+ // Returns true if able to add the embedder_download_data column to the
+ // download table.
+ bool MigrateEmbedderDownloadData();
+
// Returns true if able to add last_access_time column to the download table.
bool MigrateDownloadLastAccessTime();
diff --git a/chromium/components/history/core/browser/download_row.cc b/chromium/components/history/core/browser/download_row.cc
index 54564d1ffa6..d607b55594b 100644
--- a/chromium/components/history/core/browser/download_row.cc
+++ b/chromium/components/history/core/browser/download_row.cc
@@ -18,8 +18,9 @@ DownloadRow& DownloadRow::operator=(const DownloadRow& other) = default;
bool DownloadRow::operator==(const DownloadRow& rhs) const {
return current_path == rhs.current_path && target_path == rhs.target_path &&
url_chain == rhs.url_chain && referrer_url == rhs.referrer_url &&
- site_url == rhs.site_url && tab_url == rhs.tab_url &&
- tab_referrer_url == rhs.tab_referrer_url &&
+ site_url == rhs.site_url &&
+ embedder_download_data == rhs.embedder_download_data &&
+ tab_url == rhs.tab_url && tab_referrer_url == rhs.tab_referrer_url &&
http_method == rhs.http_method && mime_type == rhs.mime_type &&
original_mime_type == rhs.original_mime_type &&
start_time == rhs.start_time && end_time == rhs.end_time &&
diff --git a/chromium/components/history/core/browser/download_row.h b/chromium/components/history/core/browser/download_row.h
index 3cee2a072f8..1fa2fa2cd4e 100644
--- a/chromium/components/history/core/browser/download_row.h
+++ b/chromium/components/history/core/browser/download_row.h
@@ -50,6 +50,11 @@ struct DownloadRow {
// The site URL for the site instance that initiated the download.
GURL site_url;
+ // The serialized proto for embedder-specific data that pertains to the site
+ // instance that initiated the download. The embedder is responsible for
+ // serializing and deserializing this data.
+ std::string embedder_download_data;
+
// The URL of the tab that initiated the download, if any. Not changed by
// UpdateDownload().
GURL tab_url;
diff --git a/chromium/components/history/core/browser/download_types.h b/chromium/components/history/core/browser/download_types.h
index 59035a7a7d9..0ab45531e1f 100644
--- a/chromium/components/history/core/browser/download_types.h
+++ b/chromium/components/history/core/browser/download_types.h
@@ -8,8 +8,6 @@
#include <stdint.h>
#include <iosfwd>
-#include "base/compiler_specific.h"
-
namespace history {
// DownloadState represents the state of a DownloadRow saved into the
@@ -56,7 +54,7 @@ using DownloadId = uint32_t;
// Utility functions to convert between int and DownloadId for
// serialization to the download database.
-bool ConvertIntToDownloadId(int64_t id, DownloadId* out) WARN_UNUSED_RESULT;
+[[nodiscard]] bool ConvertIntToDownloadId(int64_t id, DownloadId* out);
int64_t DownloadIdToInt(DownloadId id);
} // namespace history
diff --git a/chromium/components/history/core/browser/expire_history_backend.cc b/chromium/components/history/core/browser/expire_history_backend.cc
index f72e86bbf81..12a3312b3ef 100644
--- a/chromium/components/history/core/browser/expire_history_backend.cc
+++ b/chromium/components/history/core/browser/expire_history_backend.cc
@@ -142,7 +142,7 @@ bool IsAnyURLPinned(HistoryBackendClient* backend_client,
namespace internal {
// Clearing old on-demand favicons is only enabled on mobile.
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
constexpr bool kClearOldOnDemandFaviconsEnabled = true;
#else
constexpr bool kClearOldOnDemandFaviconsEnabled = false;
diff --git a/chromium/components/history/core/browser/history_backend.cc b/chromium/components/history/core/browser/history_backend.cc
index 697351d37c9..f9d56d6e003 100644
--- a/chromium/components/history/core/browser/history_backend.cc
+++ b/chromium/components/history/core/browser/history_backend.cc
@@ -58,7 +58,7 @@
#include "url/gurl.h"
#include "url/url_constants.h"
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
#include "base/ios/scoped_critical_action.h"
#endif
@@ -287,6 +287,15 @@ HistoryBackend::~HistoryBackend() {
// Release stashed embedder object before cleaning up the databases.
supports_user_data_helper_.reset();
+ // Clear the error callback. The error callback that is installed does not
+ // process an error immediately, rather it uses a PostTask() with `this`. As
+ // `this` is being deleted, scheduling a PostTask() with `this` would be
+ // fatal (use-after-free). Additionally, as we're in shutdown, there isn't
+ // much point in trying to handle the error. If the error is really fatal,
+ // we'll cleanup the next time the backend is created.
+ if (db_)
+ db_->reset_error_callback();
+
// First close the databases before optionally running the "destroy" task.
CloseAllDatabases();
@@ -349,7 +358,7 @@ void HistoryBackend::Closing() {
CancelScheduledCommit();
}
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
void HistoryBackend::PersistState() {
TRACE_EVENT0("browser", "HistoryBackend::PersistState");
Commit();
@@ -474,10 +483,10 @@ void HistoryBackend::UpdateWithPageEndTime(ContextID context_id,
UpdateVisitDuration(visit_id, end_ts);
}
-void HistoryBackend::SetFlocAllowed(ContextID context_id,
- int nav_entry_id,
- const GURL& url) {
- TRACE_EVENT0("browser", "HistoryBackend::SetFlocAllowed");
+void HistoryBackend::SetBrowsingTopicsAllowed(ContextID context_id,
+ int nav_entry_id,
+ const GURL& url) {
+ TRACE_EVENT0("browser", "HistoryBackend::SetBrowsingTopicsAllowed");
if (!db_)
return;
@@ -491,11 +500,11 @@ void HistoryBackend::SetFlocAllowed(ContextID context_id,
VisitContentAnnotations annotations;
if (db_->GetContentAnnotationsForVisit(visit_id, &annotations)) {
annotations.annotation_flags |=
- VisitContentAnnotationFlag::kFlocEligibleRelaxed;
+ VisitContentAnnotationFlag::kBrowsingTopicsEligible;
db_->UpdateContentAnnotationsForVisit(visit_id, annotations);
} else {
annotations.annotation_flags |=
- VisitContentAnnotationFlag::kFlocEligibleRelaxed;
+ VisitContentAnnotationFlag::kBrowsingTopicsEligible;
db_->AddContentAnnotationsForVisit(visit_id, annotations);
}
ScheduleCommit();
@@ -522,6 +531,11 @@ void HistoryBackend::AddContentModelAnnotationsForVisit(
annotations.model_annotations = model_annotations;
db_->AddContentAnnotationsForVisit(visit_id, annotations);
}
+ URLRow url_row;
+ if (db_->GetURLRow(visit_row.url_id, &url_row)) {
+ delegate_->NotifyContentModelAnnotationModified(url_row,
+ model_annotations);
+ }
ScheduleCommit();
}
}
@@ -550,6 +564,33 @@ void HistoryBackend::AddRelatedSearchesForVisit(
}
}
+void HistoryBackend::AddSearchMetadataForVisit(
+ VisitID visit_id,
+ const GURL& search_normalized_url,
+ const std::u16string& search_terms) {
+ TRACE_EVENT0("browser", "HistoryBackend::AddSearchMetadataForVisit");
+
+ if (!db_)
+ return;
+
+ // Only add to the annotations table if the visit_id exists in the visits
+ // table.
+ VisitRow visit_row;
+ if (db_->GetRowForVisit(visit_id, &visit_row)) {
+ VisitContentAnnotations annotations;
+ if (db_->GetContentAnnotationsForVisit(visit_id, &annotations)) {
+ annotations.search_normalized_url = search_normalized_url;
+ annotations.search_terms = search_terms;
+ db_->UpdateContentAnnotationsForVisit(visit_id, annotations);
+ } else {
+ annotations.search_normalized_url = search_normalized_url;
+ annotations.search_terms = search_terms;
+ db_->AddContentAnnotationsForVisit(visit_id, annotations);
+ }
+ ScheduleCommit();
+ }
+}
+
void HistoryBackend::UpdateVisitDuration(VisitID visit_id, const Time end_ts) {
if (!db_)
return;
@@ -888,7 +929,7 @@ void HistoryBackend::InitImpl(
// The frequency of this UMA will indicate how often history
// initialization fails.
UMA_HISTOGRAM_BOOLEAN("History.AttemptedToFixProfileError", kill_db);
- FALLTHROUGH;
+ [[fallthrough]];
}
case sql::INIT_TOO_NEW: {
db_diagnostics_ += sql::GetCorruptFileDiagnosticsInfo(history_name);
@@ -1325,7 +1366,7 @@ DomainDiversityResults HistoryBackend::GetDomainDiversity(
std::min(number_of_days_to_report, kDomainDiversityMaxBacktrackedDays);
base::Time current_midnight = report_time.LocalMidnight();
- SCOPED_UMA_HISTOGRAM_TIMER("History.DomainCountQueryTime");
+ SCOPED_UMA_HISTOGRAM_TIMER("History.DomainCountQueryTime_V2");
for (int days_back = 0; days_back < number_of_days_to_report; ++days_back) {
DomainMetricSet single_metric_set;
@@ -1720,7 +1761,7 @@ bool HistoryBackend::CreateDownload(const DownloadRow& history_info) {
if (!db_)
return false;
bool success = db_->CreateDownload(history_info);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// On android, browser process can get easily killed. Download will no longer
// be able to resume and the temporary file will linger forever if the
// download is not committed before that. Do the commit right away to avoid
@@ -2251,7 +2292,7 @@ void HistoryBackend::Commit() {
if (!db_)
return;
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
// Attempts to get the application running long enough to commit the database
// transaction if it is currently being backgrounded.
base::ios::ScopedCriticalAction scoped_critical_action(
@@ -2673,7 +2714,7 @@ bool HistoryBackend::ClearAllFaviconHistory(
if (!favicon_backend_->ClearAllExcept(kept_urls))
return false;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// TODO(michaelbai): Add the unit test once AndroidProviderBackend is
// available in HistoryBackend.
db_->ClearAndroidURLRows();
diff --git a/chromium/components/history/core/browser/history_backend.h b/chromium/components/history/core/browser/history_backend.h
index e1fcb8318a6..6bc6d6ea6fc 100644
--- a/chromium/components/history/core/browser/history_backend.h
+++ b/chromium/components/history/core/browser/history_backend.h
@@ -177,6 +177,14 @@ class HistoryBackend : public base::RefCountedThreadSafe<HistoryBackend>,
// thread.
virtual void NotifyKeywordSearchTermDeleted(URLID url_id) = 0;
+ // Notify HistoryService that content model annotation associated with
+ // the URL for `row` has been modified. Changes to the floc and related
+ // searches annotations will not trigger this. The event will be forwarded
+ // to the HistoryServiceObservers in the correct thread.
+ virtual void NotifyContentModelAnnotationModified(
+ const URLRow& row,
+ const VisitContentModelAnnotations& model_annotations) = 0;
+
// Invoked when the backend has finished loading the db.
virtual void DBLoaded() = 0;
};
@@ -216,7 +224,7 @@ class HistoryBackend : public base::RefCountedThreadSafe<HistoryBackend>,
// actually be deleted.
void Closing();
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
// Persists any in-flight state, without actually shutting down the history
// system. This is intended for use when the application is backgrounded.
void PersistState();
@@ -244,13 +252,18 @@ class HistoryBackend : public base::RefCountedThreadSafe<HistoryBackend>,
int nav_entry_id,
const GURL& url,
base::Time end_ts);
- void SetFlocAllowed(ContextID context_id, int nav_entry_id, const GURL& url);
+ void SetBrowsingTopicsAllowed(ContextID context_id,
+ int nav_entry_id,
+ const GURL& url);
void AddContentModelAnnotationsForVisit(
VisitID visit_id,
const VisitContentModelAnnotations& model_annotations);
void AddRelatedSearchesForVisit(
VisitID visit_id,
const std::vector<std::string>& related_searches);
+ void AddSearchMetadataForVisit(VisitID visit_id,
+ const GURL& search_normalized_url,
+ const std::u16string& search_terms);
// Querying ------------------------------------------------------------------
diff --git a/chromium/components/history/core/browser/history_backend_db_unittest.cc b/chromium/components/history/core/browser/history_backend_db_unittest.cc
index 439983e2dec..5b7415f0a0c 100644
--- a/chromium/components/history/core/browser/history_backend_db_unittest.cc
+++ b/chromium/components/history/core/browser/history_backend_db_unittest.cc
@@ -733,6 +733,56 @@ TEST_F(HistoryBackendDBTest, MigrateDownloadSiteInstanceUrl) {
}
}
+TEST_F(HistoryBackendDBTest, MigrateEmbedderDownloadData) {
+ ASSERT_NO_FATAL_FAILURE(CreateDBVersion(50));
+ {
+ sql::Database db;
+ ASSERT_TRUE(db.Open(history_dir_.Append(kHistoryFilename)));
+ {
+ sql::Statement s(db.GetUniqueStatement(
+ "INSERT INTO downloads ("
+ " id, guid, current_path, target_path, start_time, received_bytes,"
+ " total_bytes, state, danger_type, interrupt_reason, hash,"
+ " end_time, opened, last_access_time, transient, referrer, "
+ " site_url, tab_url, tab_referrer_url, http_method, by_ext_id, "
+ " by_ext_name, etag, last_modified, mime_type, original_mime_type)"
+ "VALUES("
+ " 1, '435A5C7A-F6B7-4DF2-8696-22E4FCBA3EB2', 'foo.txt', 'foo.txt',"
+ " 13104873187307670, 11, 11, 1, 0, 0, X'', 13104873187521021, 0, "
+ " 13104873187521021, 1, 'http://example.com/dl/',"
+ " 'http://example.com', '', '', '', '', '', '', '',"
+ " 'text/plain', 'text/plain')"));
+ ASSERT_TRUE(s.Run());
+ }
+ }
+
+ // Re-open the db using the HistoryDatabase, which should migrate to the
+ // current version, creating the embedder_download_data column.
+ CreateBackendAndDatabase();
+ DeleteBackend();
+ {
+ // Re-open the db for manual manipulation.
+ sql::Database db;
+ ASSERT_TRUE(db.Open(history_dir_.Append(kHistoryFilename)));
+ // The version should have been updated.
+ int cur_version = HistoryDatabase::GetCurrentVersion();
+ ASSERT_LE(51, cur_version);
+ {
+ sql::Statement s(db.GetUniqueStatement(
+ "SELECT value FROM meta WHERE key = 'version'"));
+ EXPECT_TRUE(s.Step());
+ EXPECT_EQ(cur_version, s.ColumnInt(0));
+ }
+ {
+ sql::Statement s(db.GetUniqueStatement(
+ "SELECT guid, embedder_download_data from downloads"));
+ EXPECT_TRUE(s.Step());
+ EXPECT_EQ("435A5C7A-F6B7-4DF2-8696-22E4FCBA3EB2", s.ColumnString(0));
+ EXPECT_EQ(std::string(), s.ColumnString(1));
+ }
+ }
+}
+
// Tests that downloads_slices table are automatically added when migrating to
// version 33.
TEST_F(HistoryBackendDBTest, MigrateDownloadsSlicesTable) {
@@ -891,6 +941,7 @@ TEST_F(HistoryBackendDBTest, DownloadCreateAndQuery) {
download_A.url_chain = url_chain;
download_A.referrer_url = GURL("http://example.com/referrer");
download_A.site_url = GURL("http://example.com");
+ download_A.embedder_download_data = "embedder_download_data";
download_A.tab_url = GURL("http://example.com/tab-url");
download_A.tab_referrer_url = GURL("http://example.com/tab-referrer");
download_A.http_method = "GET";
@@ -928,6 +979,7 @@ TEST_F(HistoryBackendDBTest, DownloadCreateAndQuery) {
download_B.url_chain = url_chain;
download_B.referrer_url = GURL("http://example.com/referrer2");
download_B.site_url = GURL("http://2.example.com");
+ download_B.embedder_download_data = "embedder_download_data2";
download_B.tab_url = GURL("http://example.com/tab-url2");
download_B.tab_referrer_url = GURL("http://example.com/tab-referrer2");
download_B.http_method = "POST";
@@ -986,6 +1038,7 @@ TEST_F(HistoryBackendDBTest, DownloadCreateAndUpdate_VolatileFields) {
download.url_chain = url_chain;
download.referrer_url = GURL("http://example.com/referrer");
download.site_url = GURL("http://example.com");
+ download.embedder_download_data = "embedder_download_data";
download.tab_url = GURL("http://example.com/tab-url");
download.tab_referrer_url = GURL("http://example.com/tab-referrer");
download.http_method = "GET";
@@ -1126,7 +1179,7 @@ TEST_F(HistoryBackendDBTest, DownloadNukeRecordsMissingURLs) {
download.interrupt_reason = kTestDownloadInterruptReasonNone;
download.id = 1;
download.guid = "05AF6C8E-E4E0-45D7-B5CE-BC99F7019918";
- download.opened = 0;
+ download.opened = false;
download.last_access_time = now;
download.transient = false;
download.by_ext_id = "by_ext_id";
@@ -1246,6 +1299,7 @@ TEST_F(HistoryBackendDBTest, CreateAndUpdateDownloadingSlice) {
download.url_chain.push_back(GURL("http://example.com/a"));
download.referrer_url = GURL("http://example.com/referrer");
download.site_url = GURL("http://example.com");
+ download.embedder_download_data = "embedder_download_data";
download.tab_url = GURL("http://example.com/tab-url");
download.tab_referrer_url = GURL("http://example.com/tab-referrer");
download.http_method = "GET";
@@ -1295,6 +1349,7 @@ TEST_F(HistoryBackendDBTest, UpdateDownloadWithNewSlice) {
download.url_chain.push_back(GURL("http://example.com/a"));
download.referrer_url = GURL("http://example.com/referrer");
download.site_url = GURL("http://example.com");
+ download.embedder_download_data = "embedder_download_data";
download.tab_url = GURL("http://example.com/tab-url");
download.tab_referrer_url = GURL("http://example.com/tab-referrer");
download.http_method = "GET";
@@ -1339,6 +1394,7 @@ TEST_F(HistoryBackendDBTest, DownloadSliceDeletedIfEmpty) {
download.url_chain.push_back(GURL("http://example.com/a"));
download.referrer_url = GURL("http://example.com/referrer");
download.site_url = GURL("http://example.com");
+ download.embedder_download_data = "embedder_download_data";
download.tab_url = GURL("http://example.com/tab-url");
download.tab_referrer_url = GURL("http://example.com/tab-referrer");
download.http_method = "GET";
@@ -1395,6 +1451,7 @@ TEST_F(HistoryBackendDBTest, CreateAndUpdateDownloadRerouteInfoThenRemoveItem) {
download.url_chain.emplace_back(GURL("http://example.com/a"));
download.referrer_url = GURL("http://example.com/referrer");
download.site_url = GURL("http://example.com");
+ download.embedder_download_data = "embedder_download_data";
download.tab_url = GURL("http://example.com/tab-url");
download.tab_referrer_url = GURL("http://example.com/tab-referrer");
download.http_method = "GET";
@@ -1497,6 +1554,7 @@ TEST_F(HistoryBackendDBTest, DownloadRerouteInfoDeletedIfEmpty) {
download.url_chain.emplace_back(GURL("http://example.com/a"));
download.referrer_url = GURL("http://example.com/referrer");
download.site_url = GURL("http://example.com");
+ download.embedder_download_data = "embedder_download_data";
download.tab_url = GURL("http://example.com/tab-url");
download.tab_referrer_url = GURL("http://example.com/tab-referrer");
download.http_method = "GET";
@@ -2094,7 +2152,7 @@ TEST_F(HistoryBackendDBTest, MigrateFlocAllowedToAnnotationsTable) {
EXPECT_EQ(-1, s.ColumnDouble(1));
EXPECT_EQ("", s.ColumnString(2));
EXPECT_EQ(-1, s.ColumnInt64(3));
- EXPECT_EQ(VisitContentAnnotationFlag::kFlocEligibleRelaxed,
+ EXPECT_EQ(VisitContentAnnotationFlag::kDeprecatedFlocEligibleRelaxed,
static_cast<uint64_t>(s.ColumnInt64(4)));
EXPECT_TRUE(s.Step());
@@ -2110,7 +2168,7 @@ TEST_F(HistoryBackendDBTest, MigrateFlocAllowedToAnnotationsTable) {
EXPECT_EQ(-1, s.ColumnDouble(1));
EXPECT_EQ("", s.ColumnString(2));
EXPECT_EQ(-1, s.ColumnInt64(3));
- EXPECT_EQ(VisitContentAnnotationFlag::kFlocEligibleRelaxed,
+ EXPECT_EQ(VisitContentAnnotationFlag::kDeprecatedFlocEligibleRelaxed,
static_cast<uint64_t>(s.ColumnInt64(4)));
EXPECT_FALSE(s.Step());
@@ -2488,6 +2546,50 @@ TEST_F(HistoryBackendDBTest,
}
}
+TEST_F(HistoryBackendDBTest,
+ MigrateContentAnnotationsAddSearchMetadataColumns) {
+ ASSERT_NO_FATAL_FAILURE(CreateDBVersion(52));
+
+ const VisitID visit_id1 = 1;
+
+ // Open the db for manual manipulation.
+ sql::Database db;
+ ASSERT_TRUE(db.Open(history_dir_.Append(kHistoryFilename)));
+
+ const char kInsertContentAnnotationsStatement[] =
+ "INSERT INTO content_annotations "
+ "(visit_id, floc_protected_score, categories, page_topics_model_version, "
+ "annotation_flags, entities, related_searches) "
+ "VALUES (?, ?, ?, ?, ?, ?, ?)";
+
+ // Add an entry to "content_annotations" table.
+ {
+ sql::Statement s(db.GetUniqueStatement(kInsertContentAnnotationsStatement));
+ s.BindInt64(0, visit_id1);
+ s.BindDouble(1, -1);
+ s.BindString(2, "");
+ s.BindInt64(3, -1);
+ s.BindInt64(4, 0);
+ s.BindString(5, "");
+ s.BindString(6, "");
+ ASSERT_TRUE(s.Run());
+ }
+
+ // Re-open the db, triggering migration.
+ CreateBackendAndDatabase();
+
+ // The version should have been updated.
+ ASSERT_GE(HistoryDatabase::GetCurrentVersion(), 53);
+
+ // After the migration, the search metadata should be empty.
+ {
+ VisitContentAnnotations visit_content_annotations;
+ db_->GetContentAnnotationsForVisit(visit_id1, &visit_content_annotations);
+ EXPECT_TRUE(visit_content_annotations.search_normalized_url.is_empty());
+ EXPECT_TRUE(visit_content_annotations.search_terms.empty());
+ }
+}
+
bool FilterURL(const GURL& url) {
return url.SchemeIsHTTPOrHTTPS();
}
diff --git a/chromium/components/history/core/browser/history_backend_unittest.cc b/chromium/components/history/core/browser/history_backend_unittest.cc
index f3097778e73..b1ce43dac59 100644
--- a/chromium/components/history/core/browser/history_backend_unittest.cc
+++ b/chromium/components/history/core/browser/history_backend_unittest.cc
@@ -150,6 +150,9 @@ class HistoryBackendTestDelegate : public HistoryBackend::Delegate {
KeywordID keyword_id,
const std::u16string& term) override;
void NotifyKeywordSearchTermDeleted(URLID url_id) override;
+ void NotifyContentModelAnnotationModified(
+ const URLRow& row,
+ const VisitContentModelAnnotations& model_annotations) override;
void DBLoaded() override;
private:
@@ -218,12 +221,18 @@ class HistoryBackendTestBase : public testing::Test {
return urls_deleted_notifications_;
}
+ const std::vector<VisitContentModelAnnotations>
+ modified_content_model_annotations() const {
+ return modified_content_model_annotations_;
+ }
+
void ClearBroadcastedNotifications() {
url_visited_notifications_.clear();
urls_modified_notifications_.clear();
urls_deleted_notifications_.clear();
favicon_changed_notifications_page_urls_.clear();
favicon_changed_notifications_icon_urls_.clear();
+ modified_content_model_annotations_.clear();
}
base::FilePath test_dir() { return test_dir_; }
@@ -268,6 +277,12 @@ class HistoryBackendTestBase : public testing::Test {
mem_backend_->OnKeywordSearchTermDeleted(nullptr, url_id);
}
+ void NotifyContentModelAnnotationModified(
+ const URLRow& row,
+ const VisitContentModelAnnotations& model_annotations) {
+ modified_content_model_annotations_.push_back(model_annotations);
+ }
+
base::test::TaskEnvironment task_environment_;
HistoryClientFakeBookmarks history_client_;
scoped_refptr<TestHistoryBackend> backend_; // Will be NULL on init failure.
@@ -309,6 +324,7 @@ class HistoryBackendTestBase : public testing::Test {
URLVisitedList url_visited_notifications_;
URLsModifiedList urls_modified_notifications_;
URLsDeletedList urls_deleted_notifications_;
+ std::vector<VisitContentModelAnnotations> modified_content_model_annotations_;
base::FilePath test_dir_;
};
@@ -351,6 +367,12 @@ void HistoryBackendTestDelegate::NotifyKeywordSearchTermDeleted(URLID url_id) {
test_->NotifyKeywordSearchTermDeleted(url_id);
}
+void HistoryBackendTestDelegate::NotifyContentModelAnnotationModified(
+ const URLRow& row,
+ const VisitContentModelAnnotations& model_annotations) {
+ test_->NotifyContentModelAnnotationModified(row, model_annotations);
+}
+
void HistoryBackendTestDelegate::DBLoaded() {
test_->loaded_ = true;
}
@@ -606,11 +628,11 @@ const char16_t InMemoryHistoryBackendTest::kTestSearchTerm1[] = u"banana";
const char16_t InMemoryHistoryBackendTest::kTestSearchTerm2[] = u"orange";
// http://crbug.com/114287
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#define MAYBE_Loaded DISABLED_Loaded
#else
#define MAYBE_Loaded Loaded
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
TEST_F(HistoryBackendTest, MAYBE_Loaded) {
ASSERT_TRUE(backend_.get());
ASSERT_TRUE(loaded_);
@@ -1275,7 +1297,7 @@ TEST_F(HistoryBackendTest, SetPageTitleFiresNotificationWithCorrectDetails) {
}
// There's no importer on Android.
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
TEST_F(HistoryBackendTest, ImportedFaviconsTest) {
// Setup test data - two Urls in the history, one with favicon assigned and
// one without.
@@ -1349,7 +1371,7 @@ TEST_F(HistoryBackendTest, ImportedFaviconsTest) {
EXPECT_NE(0, backend_->db_->GetRowForURL(url3, &url_row3));
EXPECT_EQ(0, url_row3.visit_count());
}
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
TEST_F(HistoryBackendTest, StripUsernamePasswordTest) {
ASSERT_TRUE(backend_.get());
@@ -1640,6 +1662,7 @@ TEST_F(HistoryBackendTest, AddContentModelAnnotationsWithNoEntryInVisitTable) {
VisitContentAnnotations got_content_annotations;
ASSERT_FALSE(backend_->db()->GetContentAnnotationsForVisit(
visit_id, &got_content_annotations));
+ ASSERT_TRUE(modified_content_model_annotations().empty());
}
TEST_F(HistoryBackendTest, AddRelatedSearchesWithNoEntryInVisitTable) {
@@ -1675,7 +1698,40 @@ TEST_F(HistoryBackendTest, AddRelatedSearchesWithNoEntryInVisitTable) {
visit_id, &got_content_annotations));
}
-TEST_F(HistoryBackendTest, SetFlocAllowed) {
+TEST_F(HistoryBackendTest, AddSearchMetadataWithNoEntryInVisitTable) {
+ ASSERT_TRUE(backend_.get());
+
+ GURL url("http://pagewithvisit.com?q=search");
+ ContextID context_id = reinterpret_cast<ContextID>(1);
+ int nav_entry_id = 1;
+
+ HistoryAddPageArgs request(url, base::Time::Now(), context_id, nav_entry_id,
+ GURL(), RedirectList(), ui::PAGE_TRANSITION_TYPED,
+ false, SOURCE_BROWSED, false, true, false);
+ backend_->AddPage(request);
+
+ VisitVector visits;
+ URLRow row;
+ URLID id = backend_->db()->GetRowForURL(url, &row);
+ ASSERT_TRUE(backend_->db()->GetVisitsForURL(id, &visits));
+ ASSERT_EQ(1U, visits.size());
+ VisitID visit_id = visits[0].visit_id;
+
+ // Delete the visit.
+ backend_->DeleteURL(url);
+
+ // Try adding the search metadata. It should be a no-op as there's no
+ // matching entry in the visits table.
+ backend_->AddSearchMetadataForVisit(
+ visit_id, GURL("http://pagewithvisit.com?q=search"), u"search");
+
+ // The content_annotations table should have no entries.
+ VisitContentAnnotations got_content_annotations;
+ ASSERT_FALSE(backend_->db()->GetContentAnnotationsForVisit(
+ visit_id, &got_content_annotations));
+}
+
+TEST_F(HistoryBackendTest, SetBrowsingTopicsAllowed) {
ASSERT_TRUE(backend_.get());
GURL url("http://test-set-floc-allowed.com");
@@ -1694,13 +1750,13 @@ TEST_F(HistoryBackendTest, SetFlocAllowed) {
ASSERT_EQ(1U, visits.size());
VisitID visit_id = visits[0].visit_id;
- backend_->SetFlocAllowed(context_id, nav_entry_id, url);
+ backend_->SetBrowsingTopicsAllowed(context_id, nav_entry_id, url);
VisitContentAnnotations got_content_annotations;
ASSERT_TRUE(backend_->db()->GetContentAnnotationsForVisit(
visit_id, &got_content_annotations));
- EXPECT_EQ(VisitContentAnnotationFlag::kFlocEligibleRelaxed,
+ EXPECT_EQ(VisitContentAnnotationFlag::kBrowsingTopicsEligible,
got_content_annotations.annotation_flags);
EXPECT_EQ(-1, got_content_annotations.model_annotations.visibility_score);
EXPECT_TRUE(got_content_annotations.model_annotations.categories.empty());
@@ -1712,7 +1768,7 @@ TEST_F(HistoryBackendTest, SetFlocAllowed) {
QueryResults results = backend_->QueryHistory(/*text_query=*/{}, options);
ASSERT_EQ(results.size(), 1u);
- EXPECT_EQ(VisitContentAnnotationFlag::kFlocEligibleRelaxed,
+ EXPECT_EQ(VisitContentAnnotationFlag::kBrowsingTopicsEligible,
results[0].content_annotations().annotation_flags);
EXPECT_EQ(
-1, results[0].content_annotations().model_annotations.visibility_score);
@@ -1746,6 +1802,11 @@ TEST_F(HistoryBackendTest, AddContentModelAnnotations) {
0.5f, {{/*id=*/"1", /*weight=*/1}, {/*id=*/"2", /*weight=*/1}}, 123, {}};
backend_->AddContentModelAnnotationsForVisit(
visit_id, model_annotations_without_entities);
+ std::vector<VisitContentModelAnnotations> annotations =
+ modified_content_model_annotations();
+ ASSERT_EQ(annotations.size(), 1u);
+ ASSERT_EQ(annotations.at(0).visibility_score, 0.5f);
+ ASSERT_EQ(annotations.at(0).categories.size(), 2u);
VisitContentModelAnnotations model_annotations_only_entities = {
-1.0f,
{},
@@ -1757,6 +1818,10 @@ TEST_F(HistoryBackendTest, AddContentModelAnnotations) {
VisitContentAnnotations got_content_annotations;
ASSERT_TRUE(backend_->db()->GetContentAnnotationsForVisit(
visit_id, &got_content_annotations));
+ annotations = modified_content_model_annotations();
+ ASSERT_EQ(annotations.size(), 2u);
+ ASSERT_EQ(annotations.at(1).visibility_score, -1.0f);
+ ASSERT_EQ(annotations.at(1).categories.size(), 0u);
// Model annotations should be merged from both calls.
EXPECT_EQ(VisitContentAnnotationFlag::kNone,
@@ -1864,6 +1929,69 @@ TEST_F(HistoryBackendTest, AddRelatedSearches) {
visit_id, &got_content_annotations));
}
+TEST_F(HistoryBackendTest, AddSearchMetadata) {
+ ASSERT_TRUE(backend_.get());
+
+ GURL url("http://pagewithvisit.com?q=search#garbage");
+ ContextID context_id = reinterpret_cast<ContextID>(1);
+ int nav_entry_id = 1;
+
+ HistoryAddPageArgs request(url, base::Time::Now(), context_id, nav_entry_id,
+ GURL(), RedirectList(), ui::PAGE_TRANSITION_TYPED,
+ false, SOURCE_BROWSED, false, true, false);
+ backend_->AddPage(request);
+
+ VisitVector visits;
+ URLRow row;
+ URLID id = backend_->db()->GetRowForURL(url, &row);
+ ASSERT_TRUE(backend_->db()->GetVisitsForURL(id, &visits));
+ ASSERT_EQ(1U, visits.size());
+ VisitID visit_id = visits[0].visit_id;
+
+ backend_->AddSearchMetadataForVisit(
+ visit_id, GURL("http://pagewithvisit.com?q=search"), u"search");
+
+ VisitContentAnnotations got_content_annotations;
+ ASSERT_TRUE(backend_->db()->GetContentAnnotationsForVisit(
+ visit_id, &got_content_annotations));
+
+ EXPECT_EQ(VisitContentAnnotationFlag::kNone,
+ got_content_annotations.annotation_flags);
+ EXPECT_EQ(-1.0f, got_content_annotations.model_annotations.visibility_score);
+ ASSERT_TRUE(got_content_annotations.model_annotations.categories.empty());
+ EXPECT_EQ(
+ -1, got_content_annotations.model_annotations.page_topics_model_version);
+ ASSERT_TRUE(got_content_annotations.model_annotations.entities.empty());
+ ASSERT_TRUE(got_content_annotations.related_searches.empty());
+ EXPECT_EQ(got_content_annotations.search_normalized_url,
+ GURL("http://pagewithvisit.com?q=search"));
+ EXPECT_EQ(got_content_annotations.search_terms, u"search");
+
+ QueryOptions options;
+ options.duplicate_policy = QueryOptions::KEEP_ALL_DUPLICATES;
+ QueryResults results = backend_->QueryHistory(/*text_query=*/{}, options);
+
+ ASSERT_EQ(results.size(), 1u);
+ EXPECT_EQ(VisitContentAnnotationFlag::kNone,
+ results[0].content_annotations().annotation_flags);
+ EXPECT_EQ(VisitContentAnnotationFlag::kNone,
+ got_content_annotations.annotation_flags);
+ EXPECT_EQ(-1.0f, got_content_annotations.model_annotations.visibility_score);
+ ASSERT_TRUE(got_content_annotations.model_annotations.categories.empty());
+ EXPECT_EQ(
+ -1, got_content_annotations.model_annotations.page_topics_model_version);
+ ASSERT_TRUE(got_content_annotations.model_annotations.entities.empty());
+ EXPECT_TRUE(got_content_annotations.related_searches.empty());
+ EXPECT_EQ(got_content_annotations.search_normalized_url,
+ GURL("http://pagewithvisit.com?q=search"));
+ EXPECT_EQ(got_content_annotations.search_terms, u"search");
+
+ // Now, delete the URL. Content Annotations should be deleted.
+ backend_->DeleteURL(url);
+ ASSERT_FALSE(backend_->db()->GetContentAnnotationsForVisit(
+ visit_id, &got_content_annotations));
+}
+
TEST_F(HistoryBackendTest, MixedContentAnnotationsRequestTypes) {
ASSERT_TRUE(backend_.get());
@@ -1883,7 +2011,7 @@ TEST_F(HistoryBackendTest, MixedContentAnnotationsRequestTypes) {
ASSERT_EQ(1U, visits.size());
VisitID visit_id = visits[0].visit_id;
- backend_->SetFlocAllowed(context_id, nav_entry_id, url);
+ backend_->SetBrowsingTopicsAllowed(context_id, nav_entry_id, url);
VisitContentModelAnnotations model_annotations = {
0.5f,
@@ -1896,7 +2024,7 @@ TEST_F(HistoryBackendTest, MixedContentAnnotationsRequestTypes) {
ASSERT_TRUE(backend_->db()->GetContentAnnotationsForVisit(
visit_id, &got_content_annotations));
- EXPECT_EQ(VisitContentAnnotationFlag::kFlocEligibleRelaxed,
+ EXPECT_EQ(VisitContentAnnotationFlag::kBrowsingTopicsEligible,
got_content_annotations.annotation_flags);
EXPECT_EQ(0.5f, got_content_annotations.model_annotations.visibility_score);
EXPECT_THAT(
@@ -1917,7 +2045,7 @@ TEST_F(HistoryBackendTest, MixedContentAnnotationsRequestTypes) {
QueryResults results = backend_->QueryHistory(/*text_query=*/{}, options);
ASSERT_EQ(results.size(), 1u);
- EXPECT_EQ(VisitContentAnnotationFlag::kFlocEligibleRelaxed,
+ EXPECT_EQ(VisitContentAnnotationFlag::kBrowsingTopicsEligible,
results[0].content_annotations().annotation_flags);
EXPECT_EQ(
0.5f,
@@ -2898,7 +3026,7 @@ TEST_F(HistoryBackendTest, DeleteFTSIndexDatabases) {
base::WriteFile(db1_wal, data, data_len));
ASSERT_EQ(static_cast<int>(data_len),
base::WriteFile(db2_actual, data, data_len));
-#if defined(OS_POSIX)
+#if BUILDFLAG(IS_POSIX)
EXPECT_TRUE(base::CreateSymbolicLink(db2_actual, db2_symlink));
#endif
diff --git a/chromium/components/history/core/browser/history_database.cc b/chromium/components/history/core/browser/history_database.cc
index e0eb2ac945c..5ff83d2e1fe 100644
--- a/chromium/components/history/core/browser/history_database.cc
+++ b/chromium/components/history/core/browser/history_database.cc
@@ -9,11 +9,11 @@
#include <algorithm>
#include <set>
#include <string>
+#include <tuple>
#include <utility>
#include <vector>
#include "base/files/file_util.h"
-#include "base/ignore_result.h"
#include "base/logging.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
@@ -27,7 +27,7 @@
#include "sql/statement.h"
#include "sql/transaction.h"
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
#include "base/mac/backup_util.h"
#endif
@@ -38,7 +38,7 @@ namespace {
// Current version number. We write databases at the "current" version number,
// but any previous version that can read the "compatible" one can make do with
// our database without *too* many bad effects.
-const int kCurrentVersionNumber = 51;
+const int kCurrentVersionNumber = 53;
const int kCompatibleVersionNumber = 16;
const char kEarlyExpirationThresholdKey[] = "early_expiration_threshold";
@@ -108,7 +108,7 @@ sql::InitStatus HistoryDatabase::Init(const base::FilePath& history_name) {
if (!committer.Begin())
return LogInitFailure(InitStep::TRANSACTION_BEGIN);
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
// Exclude the history file from backups.
base::mac::SetBackupExclusion(history_name);
#endif
@@ -262,7 +262,7 @@ int HistoryDatabase::CountUniqueDomainsVisited(base::Time begin_time,
void HistoryDatabase::BeginExclusiveMode() {
// We need to use a PRAGMA statement here as the DB has already been created.
- ignore_result(db_.Execute("PRAGMA locking_mode=EXCLUSIVE"));
+ std::ignore = db_.Execute("PRAGMA locking_mode=EXCLUSIVE");
}
// static
@@ -315,7 +315,7 @@ bool HistoryDatabase::RecreateAllTablesButURL() {
void HistoryDatabase::Vacuum() {
DCHECK_EQ(0, db_.transaction_nesting()) <<
"Can not have a transaction when vacuuming.";
- ignore_result(db_.Execute("VACUUM"));
+ std::ignore = db_.Execute("VACUUM");
}
void HistoryDatabase::TrimMemory() {
@@ -403,7 +403,7 @@ sql::InitStatus HistoryDatabase::EnsureCurrentVersion() {
}
if (cur_version == 16) {
-#if !defined(OS_WIN)
+#if !BUILDFLAG(IS_WIN)
// In this version we bring the time format on Mac & Linux in sync with the
// Windows version so that profiles can be moved between computers.
MigrateTimeEpoch();
@@ -447,7 +447,7 @@ sql::InitStatus HistoryDatabase::EnsureCurrentVersion() {
if (cur_version == 21) {
// The android_urls table's data schemal was changed in version 21.
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
if (!MigrateToVersion22())
return LogMigrationFailure(21);
#endif
@@ -667,6 +667,20 @@ sql::InitStatus HistoryDatabase::EnsureCurrentVersion() {
meta_table_.SetVersionNumber(cur_version);
}
+ if (cur_version == 51) {
+ if (!MigrateEmbedderDownloadData())
+ return LogMigrationFailure(51);
+ cur_version++;
+ meta_table_.SetVersionNumber(cur_version);
+ }
+
+ if (cur_version == 52) {
+ if (!MigrateContentAnnotationsAddSearchMetadata())
+ return LogMigrationFailure(52);
+ cur_version++;
+ meta_table_.SetVersionNumber(cur_version);
+ }
+
// ========================= ^^ new migration code goes here ^^
// ADDING NEW MIGRATION CODE
// =========================
@@ -691,21 +705,21 @@ sql::InitStatus HistoryDatabase::EnsureCurrentVersion() {
return sql::INIT_OK;
}
-#if !defined(OS_WIN)
+#if !BUILDFLAG(IS_WIN)
void HistoryDatabase::MigrateTimeEpoch() {
// Update all the times in the URLs and visits table in the main database.
- ignore_result(db_.Execute(
+ std::ignore = db_.Execute(
"UPDATE urls "
"SET last_visit_time = last_visit_time + 11644473600000000 "
- "WHERE id IN (SELECT id FROM urls WHERE last_visit_time > 0);"));
- ignore_result(db_.Execute(
+ "WHERE id IN (SELECT id FROM urls WHERE last_visit_time > 0);");
+ std::ignore = db_.Execute(
"UPDATE visits "
"SET visit_time = visit_time + 11644473600000000 "
- "WHERE id IN (SELECT id FROM visits WHERE visit_time > 0);"));
- ignore_result(db_.Execute(
+ "WHERE id IN (SELECT id FROM visits WHERE visit_time > 0);");
+ std::ignore = db_.Execute(
"UPDATE segment_usage "
"SET time_slot = time_slot + 11644473600000000 "
- "WHERE id IN (SELECT id FROM segment_usage WHERE time_slot > 0);"));
+ "WHERE id IN (SELECT id FROM segment_usage WHERE time_slot > 0);");
}
#endif
diff --git a/chromium/components/history/core/browser/history_database.h b/chromium/components/history/core/browser/history_database.h
index 8ca512b9c6a..335672d31ae 100644
--- a/chromium/components/history/core/browser/history_database.h
+++ b/chromium/components/history/core/browser/history_database.h
@@ -20,7 +20,7 @@
#include "sql/init_status.h"
#include "sql/meta_table.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "components/history/core/browser/android/android_cache_database.h"
#include "components/history/core/browser/android/android_urls_database.h"
#endif
@@ -41,7 +41,7 @@ namespace history {
// as the storage interface. Logic for manipulating this storage layer should
// be in HistoryBackend.cc.
class HistoryDatabase : public DownloadDatabase,
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
public AndroidURLsDatabase,
public AndroidCacheDatabase,
#endif
@@ -80,6 +80,7 @@ class HistoryDatabase : public DownloadDatabase,
void set_error_callback(const sql::Database::ErrorCallback& error_callback) {
db_.set_error_callback(error_callback);
}
+ void reset_error_callback() { db_.reset_error_callback(); }
// Must call this function to complete initialization. Will return
// sql::INIT_OK on success. Otherwise, no other function should be called. You
@@ -168,7 +169,7 @@ class HistoryDatabase : public DownloadDatabase,
virtual void UpdateEarlyExpirationThreshold(base::Time threshold);
private:
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// AndroidProviderBackend uses the `db_`.
friend class AndroidProviderBackend;
FRIEND_TEST_ALL_PREFIXES(AndroidURLsMigrationTest, MigrateToVersion22);
@@ -192,7 +193,7 @@ class HistoryDatabase : public DownloadDatabase,
// may commit the transaction and start a new one if migration requires it.
sql::InitStatus EnsureCurrentVersion();
-#if !defined(OS_WIN)
+#if !BUILDFLAG(IS_WIN)
// Converts the time epoch in the database from being 1970-based to being
// 1601-based which corresponds to the change in Time.internal_value_.
void MigrateTimeEpoch();
diff --git a/chromium/components/history/core/browser/history_service.cc b/chromium/components/history/core/browser/history_service.cc
index c20f25648e7..296e7315b49 100644
--- a/chromium/components/history/core/browser/history_service.cc
+++ b/chromium/components/history/core/browser/history_service.cc
@@ -55,7 +55,7 @@
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/page_transition_types.h"
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
#include "base/critical_closure.h"
#endif
@@ -137,6 +137,15 @@ class HistoryService::BackendDelegate : public HistoryBackend::Delegate {
history_service_, url_id));
}
+ void NotifyContentModelAnnotationModified(
+ const URLRow& row,
+ const VisitContentModelAnnotations& model_annotations) override {
+ service_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(&HistoryService::NotifyContentModelAnnotationModified,
+ history_service_, row, model_annotations));
+ }
+
void DBLoaded() override {
service_task_runner_->PostTask(
FROM_HERE,
@@ -167,7 +176,7 @@ bool HistoryService::BackendLoaded() {
return backend_loaded_;
}
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
void HistoryService::HandleBackgrounding() {
TRACE_EVENT0("browser", "HistoryService::HandleBackgrounding");
@@ -460,15 +469,15 @@ void HistoryService::UpdateWithPageEndTime(ContextID context_id,
context_id, nav_entry_id, url, end_ts));
}
-void HistoryService::SetFlocAllowed(ContextID context_id,
- int nav_entry_id,
- const GURL& url) {
- TRACE_EVENT0("browser", "HistoryService::SetFlocAllowed");
+void HistoryService::SetBrowsingTopicsAllowed(ContextID context_id,
+ int nav_entry_id,
+ const GURL& url) {
+ TRACE_EVENT0("browser", "HistoryService::SetBrowsingTopicsAllowed");
DCHECK(backend_task_runner_) << "History service being called after cleanup";
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
ScheduleTask(PRIORITY_NORMAL,
- base::BindOnce(&HistoryBackend::SetFlocAllowed, history_backend_,
- context_id, nav_entry_id, url));
+ base::BindOnce(&HistoryBackend::SetBrowsingTopicsAllowed,
+ history_backend_, context_id, nav_entry_id, url));
}
void HistoryService::AddContentModelAnnotationsForVisit(
@@ -494,6 +503,19 @@ void HistoryService::AddRelatedSearchesForVisit(
history_backend_, visit_id, related_searches));
}
+void HistoryService::AddSearchMetadataForVisit(
+ const GURL& search_normalized_url,
+ const std::u16string& search_terms,
+ VisitID visit_id) {
+ TRACE_EVENT0("browser", "HistoryService::AddSearchMetadataForVisit");
+ DCHECK(backend_task_runner_) << "History service being called after cleanup";
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ ScheduleTask(PRIORITY_NORMAL,
+ base::BindOnce(&HistoryBackend::AddSearchMetadataForVisit,
+ history_backend_, visit_id, search_normalized_url,
+ search_terms));
+}
+
void HistoryService::AddPageWithDetails(const GURL& url,
const std::u16string& title,
int visit_count,
@@ -1233,8 +1255,8 @@ void HistoryService::DeleteLocalAndRemoteHistoryBetween(
// TODO(crbug.com/929111): This should be factored out into a separate class
// that dispatches deletions to the proper places.
if (web_history) {
- delete_directive_handler_->CreateDeleteDirectives(std::set<int64_t>(),
- begin_time, end_time);
+ delete_directive_handler_->CreateTimeRangeDeleteDirective(begin_time,
+ end_time);
// Attempt online deletion from the history server, but ignore the result.
// Deletion directives ensure that the results will eventually be deleted.
@@ -1401,4 +1423,12 @@ void HistoryService::NotifyFaviconsChanged(const std::set<GURL>& page_urls,
favicons_changed_callback_list_.Notify(page_urls, icon_url);
}
+void HistoryService::NotifyContentModelAnnotationModified(
+ const URLRow& row,
+ const VisitContentModelAnnotations& model_annotations) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ for (HistoryServiceObserver& observer : observers_)
+ observer.OnContentModelAnnotationModified(this, row, model_annotations);
+}
+
} // namespace history
diff --git a/chromium/components/history/core/browser/history_service.h b/chromium/components/history/core/browser/history_service.h
index 1fe8d5498c9..17a8e0cd2cd 100644
--- a/chromium/components/history/core/browser/history_service.h
+++ b/chromium/components/history/core/browser/history_service.h
@@ -113,7 +113,7 @@ class HistoryService : public KeyedService {
// Returns true if the backend has finished loading.
bool backend_loaded() const { return backend_loaded_; }
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
// Causes the history backend to commit any in-progress transactions. Called
// when the application is being backgrounded.
void HandleBackgrounding();
@@ -220,10 +220,12 @@ class HistoryService : public KeyedService {
const GURL& url,
base::Time end_ts);
- // Updates the history database by setting the floc allowed bit. The page can
- // be identified by the combination of the context id, the navigation entry id
- // and the url. No-op if the page is not found.
- void SetFlocAllowed(ContextID context_id, int nav_entry_id, const GURL& url);
+ // Updates the history database by setting the browsing topics allowed bit.
+ // The page can be identified by the combination of the context id, the
+ // navigation entry id and the url. No-op if the page is not found.
+ void SetBrowsingTopicsAllowed(ContextID context_id,
+ int nav_entry_id,
+ const GURL& url);
// Updates the history database with the content model annotations for the
// visit.
@@ -237,6 +239,12 @@ class HistoryService : public KeyedService {
const std::vector<std::string>& related_searches,
VisitID visit_id);
+ // Updates the history database with the search metadata for a search-like
+ // visit.
+ void AddSearchMetadataForVisit(const GURL& search_normalized_url,
+ const std::u16string& search_terms,
+ VisitID visit_id);
+
// Querying ------------------------------------------------------------------
// Returns the information about the requested URL. If the URL is found,
@@ -359,7 +367,7 @@ class HistoryService : public KeyedService {
// time range [`begin_time`, `end_time`). If the given host has not been
// visited in the given time range, the callback will be called with a null
// base::Time.
- base::CancelableTaskTracker::TaskId GetLastVisitToHost(
+ virtual base::CancelableTaskTracker::TaskId GetLastVisitToHost(
const std::string& host,
base::Time begin_time,
base::Time end_time,
@@ -587,8 +595,8 @@ class HistoryService : public KeyedService {
// Add a callback to the list. The callback will remain registered until the
// returned subscription is destroyed. The subscription must be destroyed
// before HistoryService is destroyed.
- base::CallbackListSubscription AddFaviconsChangedCallback(
- const FaviconsChangedCallback& callback) WARN_UNUSED_RESULT;
+ [[nodiscard]] base::CallbackListSubscription AddFaviconsChangedCallback(
+ const FaviconsChangedCallback& callback);
// Testing -------------------------------------------------------------------
@@ -741,6 +749,13 @@ class HistoryService : public KeyedService {
// deleted. `url_id` is the id of the url row.
void NotifyKeywordSearchTermDeleted(URLID url_id);
+ // Notify all HistoryServiceObservers registered that content model
+ // annotations for the URL associated with `row` have changed. `row` contains
+ // the URL information for the page.
+ void NotifyContentModelAnnotationModified(
+ const URLRow& row,
+ const VisitContentModelAnnotations& model_annotations);
+
// Favicon -------------------------------------------------------------------
// These favicon methods are exposed to the FaviconService. Instead of calling
diff --git a/chromium/components/history/core/browser/history_service_observer.h b/chromium/components/history/core/browser/history_service_observer.h
index 99491c20e3c..5eb17271ddc 100644
--- a/chromium/components/history/core/browser/history_service_observer.h
+++ b/chromium/components/history/core/browser/history_service_observer.h
@@ -67,6 +67,13 @@ class HistoryServiceObserver {
// `url_id` is the id of the url row.
virtual void OnKeywordSearchTermDeleted(HistoryService* history_service,
URLID url_id) {}
+
+ // Called when content model annotation is modified for a url.
+ // `url_id` is the id of the url row.
+ virtual void OnContentModelAnnotationModified(
+ HistoryService* history_service,
+ const URLRow& row,
+ const VisitContentModelAnnotations& model_annotations) {}
};
} // namespace history
diff --git a/chromium/components/history/core/browser/history_types.cc b/chromium/components/history/core/browser/history_types.cc
index 99d8b5220bd..4d5518ad628 100644
--- a/chromium/components/history/core/browser/history_types.cc
+++ b/chromium/components/history/core/browser/history_types.cc
@@ -405,12 +405,17 @@ AnnotatedVisit::AnnotatedVisit(URLRow url_row,
opener_visit_of_redirect_chain_start),
source(source) {}
AnnotatedVisit::AnnotatedVisit(const AnnotatedVisit&) = default;
+AnnotatedVisit::AnnotatedVisit(AnnotatedVisit&&) = default;
AnnotatedVisit& AnnotatedVisit::operator=(const AnnotatedVisit&) = default;
+AnnotatedVisit& AnnotatedVisit::operator=(AnnotatedVisit&&) = default;
AnnotatedVisit::~AnnotatedVisit() = default;
ClusterVisit::ClusterVisit() = default;
ClusterVisit::~ClusterVisit() = default;
ClusterVisit::ClusterVisit(const ClusterVisit&) = default;
+ClusterVisit::ClusterVisit(ClusterVisit&&) = default;
+ClusterVisit& ClusterVisit::operator=(const ClusterVisit&) = default;
+ClusterVisit& ClusterVisit::operator=(ClusterVisit&&) = default;
Cluster::Cluster() = default;
Cluster::Cluster(int64_t cluster_id,
@@ -423,7 +428,9 @@ Cluster::Cluster(int64_t cluster_id,
should_show_on_prominent_ui_surfaces(
should_show_on_prominent_ui_surfaces) {}
Cluster::Cluster(const Cluster&) = default;
+Cluster::Cluster(Cluster&&) = default;
Cluster& Cluster::operator=(const Cluster&) = default;
+Cluster& Cluster::operator=(Cluster&&) = default;
Cluster::~Cluster() = default;
ClusterRow::ClusterRow() = default;
diff --git a/chromium/components/history/core/browser/history_types.h b/chromium/components/history/core/browser/history_types.h
index 45d5afa97d2..ea1f75c44f8 100644
--- a/chromium/components/history/core/browser/history_types.h
+++ b/chromium/components/history/core/browser/history_types.h
@@ -758,7 +758,9 @@ struct AnnotatedVisit {
VisitID opener_visit_of_redirect_chain_start,
VisitSource visit);
AnnotatedVisit(const AnnotatedVisit&);
+ AnnotatedVisit(AnnotatedVisit&&);
AnnotatedVisit& operator=(const AnnotatedVisit&);
+ AnnotatedVisit& operator=(AnnotatedVisit&&);
~AnnotatedVisit();
URLRow url_row;
@@ -805,6 +807,9 @@ struct ClusterVisit {
ClusterVisit();
~ClusterVisit();
ClusterVisit(const ClusterVisit&);
+ ClusterVisit(ClusterVisit&&);
+ ClusterVisit& operator=(const ClusterVisit&);
+ ClusterVisit& operator=(ClusterVisit&&);
AnnotatedVisit annotated_visit;
@@ -812,21 +817,36 @@ struct ClusterVisit {
// visit is to the containing cluster.
float score = 0.0;
- // A list of `VisitID`s considered duplicates of this cluster visit. The best
- // visit among all the duplicates will list the worse duplicate visit IDs in
- // its vector. The worse duplicates will have an empty vector here.
- std::vector<VisitID> duplicate_visit_ids;
+ // Flagged as true if this cluster visit matches the user's search query.
+ // This value depends on the user's search query, and is not meant to be ever
+ // persisted. It's a UI-state-specific flag that's convenient to buffer here.
+ bool matches_search_query = false;
- // The normalized URL for the visit (i.e. a SRP URL normalized based on the
- // user's default search provider).
- GURL normalized_url;
-
- // Whether this visit contained a user-input search or query.
- bool is_search_visit = false;
+ // A list of visits that have been de-duplicated into this visit. The parent
+ // visit is considered the best visit among all the duplicates, and the worse
+ // visits are now contained here.
+ std::vector<ClusterVisit> duplicate_visits;
// The site engagement score of the URL associated with this visit. This
// should not be used by the UI.
float engagement_score = 0.0;
+
+ // The visit URL modified for better dupe finding. The result may not be
+ // navigable or even valid; it's only meant to be used for detecting
+ // duplicates. This is similar in intent to
+ // `AutocompleteMatch::stripped_destination_url`, but is not the same, as
+ // History Clusters and Omnibox have different deduping requirements.
+ GURL url_for_deduping;
+
+ // TODO(crbug/1296394): Remove the below fields once most clients have
+ // persisted search metadata.
+
+ // The normalized URL for the visit (i.e. a SRP URL normalized based on the
+ // user's default search provider).
+ GURL normalized_url;
+
+ // The user-input search query if this visit is a search visit.
+ std::u16string search_terms;
};
// A cluster of `ClusterVisit`s with associated metadata (i.e. `keywords` and
@@ -838,7 +858,9 @@ struct Cluster {
const std::vector<std::u16string>& keywords,
bool should_show_on_prominent_ui_surfaces = true);
Cluster(const Cluster&);
+ Cluster(Cluster&&);
Cluster& operator=(const Cluster&);
+ Cluster& operator=(Cluster&&);
~Cluster();
int64_t cluster_id = 0;
diff --git a/chromium/components/history/core/browser/in_memory_database.cc b/chromium/components/history/core/browser/in_memory_database.cc
index 1aa8937611a..7ba67e86514 100644
--- a/chromium/components/history/core/browser/in_memory_database.cc
+++ b/chromium/components/history/core/browser/in_memory_database.cc
@@ -4,8 +4,9 @@
#include "components/history/core/browser/in_memory_database.h"
+#include <tuple>
+
#include "base/files/file_path.h"
-#include "base/ignore_result.h"
#include "base/metrics/histogram_macros.h"
#include "base/notreached.h"
#include "base/strings/utf_string_conversions.h"
@@ -26,7 +27,7 @@ bool InMemoryDatabase::InitDB() {
}
// No reason to leave data behind in memory when rows are removed.
- ignore_result(db_.Execute("PRAGMA auto_vacuum=1"));
+ std::ignore = db_.Execute("PRAGMA auto_vacuum=1");
// Create the URL table, but leave it empty for now.
if (!CreateURLTable(false)) {
@@ -62,7 +63,7 @@ bool InMemoryDatabase::InitFromDisk(const base::FilePath& history_name) {
// Attach to the history database on disk. (We can't ATTACH in the middle of
// a transaction.)
sql::Statement attach(GetDB().GetUniqueStatement("ATTACH ? AS history"));
-#if defined(OS_POSIX) || defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
attach.BindString(0, history_name.value());
#else
attach.BindString(0, base::WideToUTF8(history_name.value()));
diff --git a/chromium/components/history/core/browser/sync/delete_directive_handler.cc b/chromium/components/history/core/browser/sync/delete_directive_handler.cc
index 4c46eea11f3..79e2c77e65c 100644
--- a/chromium/components/history/core/browser/sync/delete_directive_handler.cc
+++ b/chromium/components/history/core/browser/sync/delete_directive_handler.cc
@@ -248,13 +248,12 @@ void DeleteDirectiveHandler::DeleteDirectiveTask::
return;
// Call backend to expire history of directives in each group.
- for (GlobalIdTimesGroup::const_iterator group_it = id_times_group.begin();
- group_it != id_times_group.end(); ++group_it) {
+ for (const auto& [begin_and_end_times, times] : id_times_group) {
+ const auto& [begin_time, end_time] = begin_and_end_times;
// Add 1us to cover history entries visited at the end time because time
// range in directive is inclusive.
- history_backend->ExpireHistoryForTimes(
- group_it->second, group_it->first.first,
- group_it->first.second + base::Microseconds(1));
+ history_backend->ExpireHistoryForTimes(times, begin_time,
+ end_time + base::Microseconds(1));
}
}
@@ -348,8 +347,7 @@ void DeleteDirectiveHandler::OnBackendLoaded() {
std::move(wait_until_ready_to_sync_cb_).Run();
}
-bool DeleteDirectiveHandler::CreateDeleteDirectives(
- const std::set<int64_t>& global_ids,
+bool DeleteDirectiveHandler::CreateTimeRangeDeleteDirective(
base::Time begin_time,
base::Time end_time) {
base::Time now = base::Time::Now();
@@ -365,20 +363,11 @@ bool DeleteDirectiveHandler::CreateDeleteDirectives(
// -1 because end time in delete directives is inclusive.
int64_t end_time_usecs = TimeToUnixUsec(end) - 1;
- if (global_ids.empty()) {
- sync_pb::TimeRangeDirective* time_range_directive =
- delete_directive.mutable_time_range_directive();
- time_range_directive->set_start_time_usec(begin_time_usecs);
- time_range_directive->set_end_time_usec(end_time_usecs);
- } else {
- for (auto it = global_ids.begin(); it != global_ids.end(); ++it) {
- sync_pb::GlobalIdDirective* global_id_directive =
- delete_directive.mutable_global_id_directive();
- global_id_directive->add_global_id(*it);
- global_id_directive->set_start_time_usec(begin_time_usecs);
- global_id_directive->set_end_time_usec(end_time_usecs);
- }
- }
+ sync_pb::TimeRangeDirective* time_range_directive =
+ delete_directive.mutable_time_range_directive();
+ time_range_directive->set_start_time_usec(begin_time_usecs);
+ time_range_directive->set_end_time_usec(end_time_usecs);
+
absl::optional<syncer::ModelError> error =
ProcessLocalDeleteDirective(delete_directive);
return !error.has_value();
diff --git a/chromium/components/history/core/browser/sync/delete_directive_handler.h b/chromium/components/history/core/browser/sync/delete_directive_handler.h
index 51da3e16a30..0abb6a8fd42 100644
--- a/chromium/components/history/core/browser/sync/delete_directive_handler.h
+++ b/chromium/components/history/core/browser/sync/delete_directive_handler.h
@@ -5,10 +5,7 @@
#ifndef COMPONENTS_HISTORY_CORE_BROWSER_SYNC_DELETE_DIRECTIVE_HANDLER_H_
#define COMPONENTS_HISTORY_CORE_BROWSER_SYNC_DELETE_DIRECTIVE_HANDLER_H_
-#include <stdint.h>
-
#include <memory>
-#include <set>
#include "base/callback_forward.h"
#include "base/memory/weak_ptr.h"
@@ -20,6 +17,10 @@
class GURL;
+namespace base {
+class Time;
+}
+
namespace sync_pb {
class HistoryDeleteDirectiveSpecifics;
}
@@ -50,12 +51,10 @@ class DeleteDirectiveHandler : public syncer::SyncableService {
// handle sync events.
void OnBackendLoaded();
- // Create delete directives for the deletion of visits identified by
- // `global_ids` (which may be empty), in the time range specified by
- // `begin_time` and `end_time`.
- bool CreateDeleteDirectives(const std::set<int64_t>& global_ids,
- base::Time begin_time,
- base::Time end_time);
+ // Create delete directives for the deletion of visits in the time range
+ // specified by `begin_time` and `end_time`.
+ bool CreateTimeRangeDeleteDirective(base::Time begin_time,
+ base::Time end_time);
bool CreateUrlDeleteDirective(const GURL& url);
diff --git a/chromium/components/history/core/browser/sync/delete_directive_handler_unittest.cc b/chromium/components/history/core/browser/sync/delete_directive_handler_unittest.cc
index 13f3822d65a..069dd2f27ee 100644
--- a/chromium/components/history/core/browser/sync/delete_directive_handler_unittest.cc
+++ b/chromium/components/history/core/browser/sync/delete_directive_handler_unittest.cc
@@ -60,6 +60,9 @@ class TestHistoryBackendDelegate : public HistoryBackend::Delegate {
KeywordID keyword_id,
const std::u16string& term) override {}
void NotifyKeywordSearchTermDeleted(URLID url_id) override {}
+ void NotifyContentModelAnnotationModified(
+ const URLRow& row,
+ const VisitContentModelAnnotations& model_annotations) override {}
void DBLoaded() override {}
};
diff --git a/chromium/components/history/core/browser/sync/typed_url_sync_bridge.cc b/chromium/components/history/core/browser/sync/typed_url_sync_bridge.cc
index 8773d1f9242..9aa0b5fa587 100644
--- a/chromium/components/history/core/browser/sync/typed_url_sync_bridge.cc
+++ b/chromium/components/history/core/browser/sync/typed_url_sync_bridge.cc
@@ -4,26 +4,16 @@
#include "components/history/core/browser/sync/typed_url_sync_bridge.h"
-#include <memory>
-
#include "base/auto_reset.h"
#include "base/big_endian.h"
#include "base/logging.h"
#include "base/metrics/histogram_functions.h"
+#include "base/ranges/algorithm.h"
#include "base/strings/utf_string_conversions.h"
#include "components/sync/model/mutable_data_batch.h"
#include "components/sync/model/sync_metadata_store_change_list.h"
#include "net/base/url_util.h"
-using sync_pb::TypedUrlSpecifics;
-using syncer::EntityChange;
-using syncer::EntityChangeList;
-using syncer::EntityData;
-using syncer::MetadataChangeList;
-using syncer::ModelError;
-using syncer::ModelTypeChangeProcessor;
-using syncer::MutableDataBatch;
-
namespace history {
namespace {
@@ -62,17 +52,9 @@ enum class SyncTypedUrlDatabaseError {
kMaxValue = kLoadMetadataRead
};
-// Enforce oldest to newest visit order.
-static bool CheckVisitOrdering(const VisitVector& visits) {
- int64_t previous_visit_time = 0;
- for (auto visit = visits.begin(); visit != visits.end(); ++visit) {
- if (visit != visits.begin() &&
- previous_visit_time > visit->visit_time.ToInternalValue())
- return false;
-
- previous_visit_time = visit->visit_time.ToInternalValue();
- }
- return true;
+static bool VisitsAreSorted(const std::vector<VisitRow>& visits) {
+ return base::ranges::is_sorted(
+ visits, /*comp=*/{}, [](const VisitRow& row) { return row.visit_time; });
}
std::string GetStorageKeyFromURLRow(const URLRow& row) {
@@ -82,7 +64,7 @@ std::string GetStorageKeyFromURLRow(const URLRow& row) {
return storage_key;
}
-bool HasTypedUrl(const VisitVector& visits) {
+bool HasTypedUrl(const std::vector<VisitRow>& visits) {
auto typed_url_visit =
std::find_if(visits.begin(), visits.end(), [](const VisitRow& visit) {
return ui::PageTransitionCoreTypeIs(visit.transition,
@@ -97,57 +79,64 @@ void RecordDatabaseError(SyncTypedUrlDatabaseError error) {
} // namespace
+TypedURLSyncBridge::URLWithVisits::URLWithVisits(
+ const GURL& url,
+ const std::vector<VisitInfo>& visits)
+ : url(url), visits(visits) {}
+
+TypedURLSyncBridge::URLWithVisits::~URLWithVisits() = default;
+
+TypedURLSyncBridge::URLWithVisits::URLWithVisits(URLWithVisits&&) = default;
+
TypedURLSyncBridge::TypedURLSyncBridge(
HistoryBackend* history_backend,
TypedURLSyncMetadataDatabase* sync_metadata_database,
- std::unique_ptr<ModelTypeChangeProcessor> change_processor)
+ std::unique_ptr<syncer::ModelTypeChangeProcessor> change_processor)
: ModelTypeSyncBridge(std::move(change_processor)),
history_backend_(history_backend),
- processing_syncer_changes_(false),
sync_metadata_database_(sync_metadata_database) {
DCHECK(history_backend_);
DCHECK(sequence_checker_.CalledOnValidSequence());
}
-TypedURLSyncBridge::~TypedURLSyncBridge() {}
+TypedURLSyncBridge::~TypedURLSyncBridge() = default;
-std::unique_ptr<MetadataChangeList>
+std::unique_ptr<syncer::MetadataChangeList>
TypedURLSyncBridge::CreateMetadataChangeList() {
DCHECK(sequence_checker_.CalledOnValidSequence());
return std::make_unique<syncer::SyncMetadataStoreChangeList>(
sync_metadata_database_, syncer::TYPED_URLS);
}
-absl::optional<ModelError> TypedURLSyncBridge::MergeSyncData(
- std::unique_ptr<MetadataChangeList> metadata_change_list,
- EntityChangeList entity_data) {
+absl::optional<syncer::ModelError> TypedURLSyncBridge::MergeSyncData(
+ std::unique_ptr<syncer::MetadataChangeList> metadata_change_list,
+ syncer::EntityChangeList entity_data) {
DCHECK(sequence_checker_.CalledOnValidSequence());
- // Create a mapping of all local data by URLID. These will be narrowed down
+ // Create a mapping of all local data by URL. These will be narrowed down
// by MergeURLWithSync() to include only the entries different from sync
// server data.
- TypedURLMap new_db_urls;
-
- // Get all the visits and map the URLRows by URL.
- URLVisitVectorMap local_visit_vectors;
+ std::map<GURL, URLRow> new_db_urls;
+ std::map<GURL, std::vector<VisitRow>> local_visit_vectors;
if (!GetValidURLsAndVisits(&local_visit_vectors, &new_db_urls)) {
RecordDatabaseError(SyncTypedUrlDatabaseError::kMergeSyncDataRead);
- return ModelError(
+ return syncer::ModelError(
FROM_HERE, "Could not get the typed_url entries from HistoryBackend.");
}
// New sync data organized for different write operations to history backend.
- URLRows new_synced_urls;
- URLRows updated_synced_urls;
- TypedURLVisitVector new_synced_visits;
+ std::vector<URLRow> new_synced_urls;
+ std::vector<URLRow> updated_synced_urls;
+ std::vector<URLWithVisits> new_synced_visits;
// Iterate through entity_data and check for all the urls that
// sync already knows about. MergeURLWithSync() will remove urls that
// are the same as the synced ones from `new_db_urls`.
- for (const std::unique_ptr<EntityChange>& entity_change : entity_data) {
+ for (const std::unique_ptr<syncer::EntityChange>& entity_change :
+ entity_data) {
DCHECK(entity_change->data().specifics.has_typed_url());
- const TypedUrlSpecifics& specifics =
+ const sync_pb::TypedUrlSpecifics& specifics =
entity_change->data().specifics.typed_url();
if (ShouldIgnoreUrl(GURL(specifics.url())))
continue;
@@ -168,7 +157,7 @@ absl::optional<ModelError> TypedURLSyncBridge::MergeSyncData(
&updated_synced_urls);
}
- absl::optional<ModelError> error =
+ absl::optional<syncer::ModelError> error =
WriteToHistoryBackend(&new_synced_urls, &updated_synced_urls, nullptr,
&new_synced_visits, nullptr);
if (error) {
@@ -178,7 +167,8 @@ absl::optional<ModelError> TypedURLSyncBridge::MergeSyncData(
// Update storage key here first, and then send updated typed URL to sync
// below, otherwise processor will have duplicate entries.
- for (const std::unique_ptr<EntityChange>& entity_change : entity_data) {
+ for (const std::unique_ptr<syncer::EntityChange>& entity_change :
+ entity_data) {
DCHECK(entity_change->data().specifics.has_typed_url());
std::string storage_key = GetStorageKeyInternal(
entity_change->data().specifics.typed_url().url());
@@ -193,12 +183,12 @@ absl::optional<ModelError> TypedURLSyncBridge::MergeSyncData(
}
// Send new/updated typed URL to sync.
- for (const auto& kv : new_db_urls) {
- SendTypedURLToProcessor(kv.second, local_visit_vectors[kv.first],
+ for (const auto& [url, url_row] : new_db_urls) {
+ SendTypedURLToProcessor(url_row, local_visit_vectors[url],
metadata_change_list.get());
}
- absl::optional<ModelError> metadata_error =
+ absl::optional<syncer::ModelError> metadata_error =
static_cast<syncer::SyncMetadataStoreChangeList*>(
metadata_change_list.get())
->TakeError();
@@ -208,19 +198,20 @@ absl::optional<ModelError> TypedURLSyncBridge::MergeSyncData(
return metadata_error;
}
-absl::optional<ModelError> TypedURLSyncBridge::ApplySyncChanges(
- std::unique_ptr<MetadataChangeList> metadata_change_list,
- EntityChangeList entity_changes) {
+absl::optional<syncer::ModelError> TypedURLSyncBridge::ApplySyncChanges(
+ std::unique_ptr<syncer::MetadataChangeList> metadata_change_list,
+ syncer::EntityChangeList entity_changes) {
DCHECK(sequence_checker_.CalledOnValidSequence());
std::vector<GURL> pending_deleted_urls;
- TypedURLVisitVector new_synced_visits;
- VisitVector deleted_visits;
- URLRows updated_synced_urls;
- URLRows new_synced_urls;
-
- for (const std::unique_ptr<EntityChange>& entity_change : entity_changes) {
- if (entity_change->type() == EntityChange::ACTION_DELETE) {
+ std::vector<URLWithVisits> new_synced_visits;
+ std::vector<VisitRow> deleted_visits;
+ std::vector<URLRow> updated_synced_urls;
+ std::vector<URLRow> new_synced_urls;
+
+ for (const std::unique_ptr<syncer::EntityChange>& entity_change :
+ entity_changes) {
+ if (entity_change->type() == syncer::EntityChange::ACTION_DELETE) {
URLRow url_row;
int64_t url_id = TypedURLSyncMetadataDatabase::StorageKeyToURLID(
entity_change->storage_key());
@@ -235,7 +226,7 @@ absl::optional<ModelError> TypedURLSyncBridge::ApplySyncChanges(
}
DCHECK(entity_change->data().specifics.has_typed_url());
- const TypedUrlSpecifics& specifics =
+ const sync_pb::TypedUrlSpecifics& specifics =
entity_change->data().specifics.typed_url();
GURL url(specifics.url());
@@ -252,7 +243,7 @@ absl::optional<ModelError> TypedURLSyncBridge::ApplySyncChanges(
&updated_synced_urls, &new_synced_urls);
}
- absl::optional<ModelError> error = WriteToHistoryBackend(
+ absl::optional<syncer::ModelError> error = WriteToHistoryBackend(
&new_synced_urls, &updated_synced_urls, &pending_deleted_urls,
&new_synced_visits, &deleted_visits);
if (error) {
@@ -262,8 +253,9 @@ absl::optional<ModelError> TypedURLSyncBridge::ApplySyncChanges(
// New entities were either ignored or written to history DB and assigned a
// storage key. Notify processor about updated storage keys.
- for (const std::unique_ptr<EntityChange>& entity_change : entity_changes) {
- if (entity_change->type() == EntityChange::ACTION_ADD) {
+ for (const std::unique_ptr<syncer::EntityChange>& entity_change :
+ entity_changes) {
+ if (entity_change->type() == syncer::EntityChange::ACTION_ADD) {
std::string storage_key = GetStorageKeyInternal(
entity_change->data().specifics.typed_url().url());
if (storage_key.empty()) {
@@ -277,7 +269,7 @@ absl::optional<ModelError> TypedURLSyncBridge::ApplySyncChanges(
}
}
- absl::optional<ModelError> metadata_error =
+ absl::optional<syncer::ModelError> metadata_error =
static_cast<syncer::SyncMetadataStoreChangeList*>(
metadata_change_list.get())
->TakeError();
@@ -292,7 +284,7 @@ void TypedURLSyncBridge::GetData(StorageKeyList storage_keys,
DataCallback callback) {
DCHECK(sequence_checker_.CalledOnValidSequence());
- auto batch = std::make_unique<MutableDataBatch>();
+ auto batch = std::make_unique<syncer::MutableDataBatch>();
for (const std::string& key : storage_keys) {
URLRow url_row;
URLID url_id = TypedURLSyncMetadataDatabase::StorageKeyToURLID(key);
@@ -303,7 +295,7 @@ void TypedURLSyncBridge::GetData(StorageKeyList storage_keys,
continue;
}
- VisitVector visits_vector;
+ std::vector<VisitRow> visits_vector;
if (!FixupURLAndGetVisits(&url_row, &visits_vector) ||
visits_vector.empty()) {
continue;
@@ -324,16 +316,16 @@ void TypedURLSyncBridge::GetData(StorageKeyList storage_keys,
void TypedURLSyncBridge::GetAllDataForDebugging(DataCallback callback) {
DCHECK(sequence_checker_.CalledOnValidSequence());
- URLRows typed_urls;
+ std::vector<URLRow> typed_urls;
if (!history_backend_->GetAllTypedURLs(&typed_urls)) {
change_processor()->ReportError(
{FROM_HERE, "Could not get the typed_url entries."});
return;
}
- auto batch = std::make_unique<MutableDataBatch>();
+ auto batch = std::make_unique<syncer::MutableDataBatch>();
for (URLRow& url : typed_urls) {
- VisitVector visits_vector;
+ std::vector<VisitRow> visits_vector;
if (!FixupURLAndGetVisits(&url, &visits_vector) || visits_vector.empty()) {
continue;
}
@@ -354,7 +346,8 @@ void TypedURLSyncBridge::GetAllDataForDebugging(DataCallback callback) {
// the previous (Directory + SyncableService) iteration of sync integration.
// This can be large but it is assumed that this is not held in memory at steady
// state.
-std::string TypedURLSyncBridge::GetClientTag(const EntityData& entity_data) {
+std::string TypedURLSyncBridge::GetClientTag(
+ const syncer::EntityData& entity_data) {
DCHECK(sequence_checker_.CalledOnValidSequence());
DCHECK(entity_data.specifics.has_typed_url())
<< "EntityData does not have typed urls specifics.";
@@ -364,7 +357,8 @@ std::string TypedURLSyncBridge::GetClientTag(const EntityData& entity_data) {
// Prefer to use URLRow::id() to uniquely identify entities when coordinating
// with sync because it has a significantly low memory cost than a URL.
-std::string TypedURLSyncBridge::GetStorageKey(const EntityData& entity_data) {
+std::string TypedURLSyncBridge::GetStorageKey(
+ const syncer::EntityData& entity_data) {
NOTREACHED() << "TypedURLSyncBridge do not support GetStorageKey.";
return std::string();
}
@@ -390,7 +384,7 @@ void TypedURLSyncBridge::OnURLVisited(HistoryBackend* history_backend,
if (!ShouldSyncVisit(row.typed_count(), transition))
return;
- std::unique_ptr<MetadataChangeList> metadata_change_list =
+ std::unique_ptr<syncer::MetadataChangeList> metadata_change_list =
CreateMetadataChangeList();
UpdateSyncFromLocal(row, /*is_from_expiration=*/false,
@@ -398,7 +392,7 @@ void TypedURLSyncBridge::OnURLVisited(HistoryBackend* history_backend,
}
void TypedURLSyncBridge::OnURLsModified(HistoryBackend* history_backend,
- const URLRows& changed_urls,
+ const std::vector<URLRow>& changed_urls,
bool is_from_expiration) {
DCHECK(sequence_checker_.CalledOnValidSequence());
DCHECK(sync_metadata_database_);
@@ -409,10 +403,10 @@ void TypedURLSyncBridge::OnURLsModified(HistoryBackend* history_backend,
if (!change_processor()->IsTrackingMetadata())
return; // Sync processor not yet ready, don't sync.
- std::unique_ptr<MetadataChangeList> metadata_change_list =
+ std::unique_ptr<syncer::MetadataChangeList> metadata_change_list =
CreateMetadataChangeList();
- for (const auto& row : changed_urls) {
+ for (const URLRow& row : changed_urls) {
DCHECK_GE(row.typed_count(), 0);
// If there were any errors updating the sync node, just ignore them and
// continue on to process the next URL.
@@ -423,7 +417,7 @@ void TypedURLSyncBridge::OnURLsModified(HistoryBackend* history_backend,
void TypedURLSyncBridge::OnURLsDeleted(HistoryBackend* history_backend,
bool all_history,
bool expired,
- const URLRows& deleted_rows,
+ const std::vector<URLRow>& deleted_rows,
const std::set<GURL>& favicon_urls) {
DCHECK(sequence_checker_.CalledOnValidSequence());
DCHECK(sync_metadata_database_);
@@ -447,7 +441,7 @@ void TypedURLSyncBridge::OnURLsDeleted(HistoryBackend* history_backend,
return;
}
- std::unique_ptr<MetadataChangeList> metadata_change_list =
+ std::unique_ptr<syncer::MetadataChangeList> metadata_change_list =
CreateMetadataChangeList();
if (all_history) {
@@ -462,8 +456,8 @@ void TypedURLSyncBridge::OnURLsDeleted(HistoryBackend* history_backend,
}
syncer::EntityMetadataMap metadata_map(batch->TakeAllMetadata());
- for (const auto& kv : metadata_map) {
- change_processor()->Delete(kv.first, metadata_change_list.get());
+ for (const auto& [storage_key, metadata] : metadata_map) {
+ change_processor()->Delete(storage_key, metadata_change_list.get());
}
} else {
// Delete rows.
@@ -491,8 +485,8 @@ void TypedURLSyncBridge::OnDatabaseError() {
// static
bool TypedURLSyncBridge::WriteToTypedUrlSpecifics(
const URLRow& url,
- const VisitVector& visits,
- TypedUrlSpecifics* typed_url) {
+ const std::vector<VisitRow>& visits,
+ sync_pb::TypedUrlSpecifics* typed_url) {
DCHECK(!url.last_visit().is_null());
DCHECK(!visits.empty());
DCHECK_EQ(url.last_visit().ToInternalValue(),
@@ -502,7 +496,7 @@ bool TypedURLSyncBridge::WriteToTypedUrlSpecifics(
typed_url->set_title(base::UTF16ToUTF8(url.title()));
typed_url->set_hidden(url.hidden());
- DCHECK(CheckVisitOrdering(visits));
+ DCHECK(VisitsAreSorted(visits));
bool only_typed = false;
int skip_count = 0;
@@ -516,7 +510,7 @@ bool TypedURLSyncBridge::WriteToTypedUrlSpecifics(
int typed_count = 0;
int total = 0;
// Walk the passed-in visit vector and count the # of typed visits.
- for (VisitRow visit : visits) {
+ for (const VisitRow& visit : visits) {
// We ignore reload visits.
if (PageTransitionCoreTypeIs(visit.transition,
ui::PAGE_TRANSITION_RELOAD)) {
@@ -543,7 +537,7 @@ bool TypedURLSyncBridge::WriteToTypedUrlSpecifics(
}
}
- for (const auto& visit : visits) {
+ for (const VisitRow& visit : visits) {
// Skip reload visits.
if (PageTransitionCoreTypeIs(visit.transition, ui::PAGE_TRANSITION_RELOAD))
continue;
@@ -577,9 +571,9 @@ bool TypedURLSyncBridge::WriteToTypedUrlSpecifics(
// static
TypedURLSyncBridge::MergeResult TypedURLSyncBridge::MergeUrls(
- const TypedUrlSpecifics& sync_url,
+ const sync_pb::TypedUrlSpecifics& sync_url,
const URLRow& url,
- VisitVector* visits,
+ std::vector<VisitRow>* visits,
URLRow* new_url,
std::vector<VisitInfo>* new_visits) {
DCHECK(new_url);
@@ -668,29 +662,28 @@ TypedURLSyncBridge::MergeResult TypedURLSyncBridge::MergeUrls(
}
}
- DCHECK(CheckVisitOrdering(*visits));
+ DCHECK(VisitsAreSorted(*visits));
if (different & DIFF_LOCAL_VISITS_ADDED) {
// If the server does not have the same visits as the local db, then the
// new visits from the server need to be added to the vector containing
// local visits. These visits will be passed to the server.
// Insert new visits into the appropriate place in the visits vector.
auto visit_ix = visits->begin();
- for (auto new_visit = new_visits->begin(); new_visit != new_visits->end();
- ++new_visit) {
+ for (const auto& [new_visit_time, new_page_transition] : *new_visits) {
while (visit_ix != visits->end() &&
- new_visit->first > visit_ix->visit_time) {
+ new_visit_time > visit_ix->visit_time) {
++visit_ix;
}
visit_ix = visits->insert(
visit_ix,
- VisitRow(url.id(), new_visit->first, /*arg_referring_visit=*/0,
- new_visit->second, /*arg_segment_id=*/0,
- HistoryBackend::IsTypedIncrement(new_visit->second),
+ VisitRow(url.id(), new_visit_time, /*arg_referring_visit=*/0,
+ new_page_transition, /*arg_segment_id=*/0,
+ HistoryBackend::IsTypedIncrement(new_page_transition),
/*arg_opener_visit=*/0));
++visit_ix;
}
}
- DCHECK(CheckVisitOrdering(*visits));
+ DCHECK(VisitsAreSorted(*visits));
new_url->set_last_visit(visits->back().visit_time);
return different;
@@ -698,10 +691,10 @@ TypedURLSyncBridge::MergeResult TypedURLSyncBridge::MergeUrls(
// static
void TypedURLSyncBridge::DiffVisits(
- const VisitVector& history_visits,
+ const std::vector<VisitRow>& history_visits,
const sync_pb::TypedUrlSpecifics& sync_specifics,
std::vector<VisitInfo>* new_visits,
- VisitVector* removed_visits) {
+ std::vector<VisitRow>* removed_visits) {
DCHECK(new_visits);
size_t old_visit_count = history_visits.size();
size_t new_visit_count = sync_specifics.visits_size();
@@ -746,7 +739,7 @@ void TypedURLSyncBridge::DiffVisits(
// static
void TypedURLSyncBridge::UpdateURLRowFromTypedUrlSpecifics(
- const TypedUrlSpecifics& typed_url,
+ const sync_pb::TypedUrlSpecifics& typed_url,
URLRow* new_url) {
DCHECK_GT(typed_url.visits_size(), 0);
CHECK_EQ(typed_url.visit_transitions_size(), typed_url.visits_size());
@@ -784,11 +777,11 @@ void TypedURLSyncBridge::LoadMetadata() {
void TypedURLSyncBridge::MergeURLWithSync(
const sync_pb::TypedUrlSpecifics& server_typed_url,
- TypedURLMap* local_typed_urls,
- URLVisitVectorMap* local_visit_vectors,
- URLRows* new_synced_urls,
- TypedURLVisitVector* new_synced_visits,
- URLRows* updated_synced_urls) {
+ std::map<GURL, URLRow>* local_typed_urls,
+ std::map<GURL, std::vector<VisitRow>>* local_visit_vectors,
+ std::vector<URLRow>* new_synced_urls,
+ std::vector<URLWithVisits>* new_synced_visits,
+ std::vector<URLRow>* updated_synced_urls) {
DCHECK_NE(0, server_typed_url.visits_size());
DCHECK_EQ(server_typed_url.visits_size(),
server_typed_url.visit_transitions_size());
@@ -800,7 +793,7 @@ void TypedURLSyncBridge::MergeURLWithSync(
}
// Now, get rid of the expired visits. If there are no un-expired visits
// left, ignore this url - any local data should just replace it.
- TypedUrlSpecifics sync_url = FilterExpiredVisits(server_typed_url);
+ sync_pb::TypedUrlSpecifics sync_url = FilterExpiredVisits(server_typed_url);
if (sync_url.visits_size() == 0) {
DVLOG(1) << "Ignoring expired URL in sync DB: " << sync_url.url();
return;
@@ -820,7 +813,7 @@ void TypedURLSyncBridge::MergeURLWithSync(
history_backend_->GetURL(untyped_url.url(), &untyped_url);
if (is_existing_url) {
// Add a new entry to `local_typed_urls`, and set the iterator to it.
- VisitVector untyped_visits;
+ std::vector<VisitRow> untyped_visits;
// TODO(crbug.com/1075573): We early return on urls with all visits
// expired. It does not feel right as we might get new non-expired visits
// through sync.
@@ -855,31 +848,31 @@ void TypedURLSyncBridge::MergeURLWithSync(
ui::PageTransitionFromInt(sync_url.visit_transitions(index));
added_visits.push_back(VisitInfo(visit_time, transition));
}
- new_synced_visits->push_back(
- std::pair<GURL, std::vector<VisitInfo>>(new_url.url(), added_visits));
+ new_synced_visits->emplace_back(new_url.url(), added_visits);
return;
}
}
// Same URL exists in sync data and in history data - compare the
// entries to see if there's any difference.
- VisitVector& visits = (*local_visit_vectors)[it->first];
+ auto& [url, url_row] = *it;
+ std::vector<VisitRow>& visits = (*local_visit_vectors)[url];
std::vector<VisitInfo> added_visits;
// Empty URLs should be filtered out by ShouldIgnoreUrl() previously.
- DCHECK(!it->second.url().spec().empty());
+ DCHECK(!url_row.url().spec().empty());
// Initialize fields in `new_url` to the same values as the fields in
// the existing URLRow in the history DB. This is needed because we
// overwrite the existing value in WriteToHistoryBackend(), but some of
// the values in that structure are not synced (like typed_count).
- URLRow new_url(it->second);
+ URLRow new_url(url_row);
MergeResult difference =
- MergeUrls(sync_url, it->second, &visits, &new_url, &added_visits);
+ MergeUrls(sync_url, url_row, &visits, &new_url, &added_visits);
if (difference != DIFF_NONE) {
- it->second = new_url;
+ url_row = new_url;
if (difference & DIFF_UPDATE_NODE) {
// We don't want to resurrect old visits that have been aged out by
// other clients, so remove all visits that are older than the
@@ -906,13 +899,12 @@ void TypedURLSyncBridge::MergeURLWithSync(
}
if (difference & DIFF_LOCAL_ROW_CHANGED) {
// Add entry to updated_synced_urls to update the local db.
- DCHECK_EQ(it->second.id(), new_url.id());
+ DCHECK_EQ(url_row.id(), new_url.id());
updated_synced_urls->push_back(new_url);
}
if (difference & DIFF_LOCAL_VISITS_ADDED) {
// Add entry with new visits to new_synced_visits to update the local db.
- new_synced_visits->push_back(
- std::pair<GURL, std::vector<VisitInfo>>(it->first, added_visits));
+ new_synced_visits->emplace_back(url, added_visits);
}
} else {
// No difference in urls, erase from map
@@ -922,12 +914,12 @@ void TypedURLSyncBridge::MergeURLWithSync(
void TypedURLSyncBridge::UpdateFromSync(
const sync_pb::TypedUrlSpecifics& typed_url,
- TypedURLVisitVector* visits_to_add,
- VisitVector* visits_to_remove,
- URLRows* updated_urls,
- URLRows* new_urls) {
+ std::vector<URLWithVisits>* visits_to_add,
+ std::vector<VisitRow>* visits_to_remove,
+ std::vector<URLRow>* updated_urls,
+ std::vector<URLRow>* new_urls) {
URLRow new_url(GURL(typed_url.url()));
- VisitVector existing_visits;
+ std::vector<VisitRow> existing_visits;
bool existing_url = history_backend_->GetURL(new_url.url(), &new_url);
if (existing_url) {
// This URL already exists locally - fetch the visits so we can
@@ -940,14 +932,13 @@ void TypedURLSyncBridge::UpdateFromSync(
return;
}
}
- visits_to_add->push_back(std::pair<GURL, std::vector<VisitInfo>>(
- new_url.url(), std::vector<VisitInfo>()));
+ visits_to_add->emplace_back(new_url.url(), std::vector<VisitInfo>());
// Update the URL with information from the typed URL.
UpdateURLRowFromTypedUrlSpecifics(typed_url, &new_url);
// Figure out which visits we need to add.
- DiffVisits(existing_visits, typed_url, &visits_to_add->back().second,
+ DiffVisits(existing_visits, typed_url, &visits_to_add->back().visits,
visits_to_remove);
if (existing_url) {
@@ -960,12 +951,12 @@ void TypedURLSyncBridge::UpdateFromSync(
void TypedURLSyncBridge::UpdateSyncFromLocal(
URLRow row,
bool is_from_expiration,
- MetadataChangeList* metadata_change_list) {
+ syncer::MetadataChangeList* metadata_change_list) {
if (ShouldIgnoreUrl(row.url()))
return;
// Get the visits for this node.
- VisitVector visit_vector;
+ std::vector<VisitRow> visit_vector;
if (!FixupURLAndGetVisits(&row, &visit_vector)) {
return;
}
@@ -1002,18 +993,19 @@ void TypedURLSyncBridge::ExpireMetadataForURL(const URLRow& row) {
change_processor()->UntrackEntityForStorageKey(storage_key);
}
-absl::optional<ModelError> TypedURLSyncBridge::WriteToHistoryBackend(
- const URLRows* new_urls,
- const URLRows* updated_urls,
+absl::optional<syncer::ModelError> TypedURLSyncBridge::WriteToHistoryBackend(
+ const std::vector<URLRow>* new_urls,
+ const std::vector<URLRow>* updated_urls,
const std::vector<GURL>* deleted_urls,
- const TypedURLVisitVector* new_visits,
- const VisitVector* deleted_visits) {
+ const std::vector<URLWithVisits>* new_visits,
+ const std::vector<VisitRow>* deleted_visits) {
DCHECK_EQ(processing_syncer_changes_, false);
// Set flag to stop accepting history change notifications from backend.
base::AutoReset<bool> processing_changes(&processing_syncer_changes_, true);
- if (deleted_urls && !deleted_urls->empty())
+ if (deleted_urls && !deleted_urls->empty()) {
history_backend_->DeleteURLs(*deleted_urls);
+ }
if (new_urls) {
history_backend_->AddPagesWithDetails(*new_urls, SOURCE_SYNCED);
@@ -1031,21 +1023,21 @@ absl::optional<ModelError> TypedURLSyncBridge::WriteToHistoryBackend(
}
if (new_visits) {
- for (const auto& visits : *new_visits) {
+ for (const auto& [url, visit_infos] : *new_visits) {
// If there are no visits to add, just skip this.
- if (visits.second.empty())
+ if (visit_infos.empty())
continue;
- if (!history_backend_->AddVisits(visits.first, visits.second,
- SOURCE_SYNCED)) {
- return ModelError(FROM_HERE, "Could not add visits to HistoryBackend.");
+ if (!history_backend_->AddVisits(url, visit_infos, SOURCE_SYNCED)) {
+ return syncer::ModelError(FROM_HERE,
+ "Could not add visits to HistoryBackend.");
}
}
}
if (deleted_visits) {
if (!history_backend_->RemoveVisits(*deleted_visits)) {
- return ModelError(FROM_HERE,
- "Could not remove visits from HistoryBackend.");
+ return syncer::ModelError(FROM_HERE,
+ "Could not remove visits from HistoryBackend.");
// This is bad news, since it means we may end up resurrecting history
// entries on the next reload. It's unavoidable so we'll just keep on
// syncing.
@@ -1055,10 +1047,10 @@ absl::optional<ModelError> TypedURLSyncBridge::WriteToHistoryBackend(
return {};
}
-TypedUrlSpecifics TypedURLSyncBridge::FilterExpiredVisits(
- const TypedUrlSpecifics& source) {
+sync_pb::TypedUrlSpecifics TypedURLSyncBridge::FilterExpiredVisits(
+ const sync_pb::TypedUrlSpecifics& source) {
// Make a copy of the source, then regenerate the visits.
- TypedUrlSpecifics specifics(source);
+ sync_pb::TypedUrlSpecifics specifics(source);
specifics.clear_visits();
specifics.clear_visit_transitions();
for (int i = 0; i < source.visits_size(); ++i) {
@@ -1096,7 +1088,8 @@ bool TypedURLSyncBridge::ShouldIgnoreUrl(const GURL& url) {
return false;
}
-bool TypedURLSyncBridge::ShouldIgnoreVisits(const VisitVector& visits) {
+bool TypedURLSyncBridge::ShouldIgnoreVisits(
+ const std::vector<VisitRow>& visits) {
// We ignore URLs that were imported, but have never been visited by
// chromium.
static const int kFirstImportedSource = SOURCE_FIREFOX_IMPORTED;
@@ -1105,7 +1098,7 @@ bool TypedURLSyncBridge::ShouldIgnoreVisits(const VisitVector& visits) {
return false; // If we can't read the visit, assume it's not imported.
// Walk the list of visits and look for a non-imported item.
- for (const auto& visit : visits) {
+ for (const VisitRow& visit : visits) {
if (map.count(visit.visit_id) == 0 ||
map[visit.visit_id] < kFirstImportedSource) {
return false;
@@ -1130,7 +1123,7 @@ bool TypedURLSyncBridge::ShouldSyncVisit(int typed_count,
}
bool TypedURLSyncBridge::FixupURLAndGetVisits(URLRow* url,
- VisitVector* visits) {
+ std::vector<VisitRow>* visits) {
if (!history_backend_->GetMostRecentVisitsForURL(url->id(), kMaxVisitsToFetch,
visits)) {
// Couldn't load the visits for this URL due to some kind of DB error.
@@ -1170,13 +1163,13 @@ bool TypedURLSyncBridge::FixupURLAndGetVisits(URLRow* url,
// the last visit in our visit array (they come from different tables, so
// crashes/bugs can cause them to mismatch), so just set it here.
url->set_last_visit(visits->back().visit_time);
- DCHECK(CheckVisitOrdering(*visits));
+ DCHECK(VisitsAreSorted(*visits));
// Removes all visits that are older than the current expiration time. Visits
// are in ascending order now, so we can check from beginning to check how
// many expired visits.
size_t num_expired_visits = 0;
- for (auto& visit : *visits) {
+ for (const VisitRow& visit : *visits) {
base::Time time = visit.visit_time;
if (history_backend_->IsExpiredVisitTime(time)) {
++num_expired_visits;
@@ -1192,16 +1185,17 @@ bool TypedURLSyncBridge::FixupURLAndGetVisits(URLRow* url,
}
visits->erase(visits->begin(), visits->begin() + num_expired_visits);
}
- DCHECK(CheckVisitOrdering(*visits));
+ DCHECK(VisitsAreSorted(*visits));
return true;
}
-std::unique_ptr<EntityData> TypedURLSyncBridge::CreateEntityData(
+std::unique_ptr<syncer::EntityData> TypedURLSyncBridge::CreateEntityData(
const URLRow& row,
- const VisitVector& visits) {
- auto entity_data = std::make_unique<EntityData>();
- TypedUrlSpecifics* specifics = entity_data->specifics.mutable_typed_url();
+ const std::vector<VisitRow>& visits) {
+ auto entity_data = std::make_unique<syncer::EntityData>();
+ sync_pb::TypedUrlSpecifics* specifics =
+ entity_data->specifics.mutable_typed_url();
if (!WriteToTypedUrlSpecifics(row, visits, specifics)) {
// Cannot write to specifics, ex. no TYPED visits.
@@ -1211,12 +1205,13 @@ std::unique_ptr<EntityData> TypedURLSyncBridge::CreateEntityData(
return entity_data;
}
-bool TypedURLSyncBridge::GetValidURLsAndVisits(URLVisitVectorMap* url_to_visit,
- TypedURLMap* url_to_urlrow) {
+bool TypedURLSyncBridge::GetValidURLsAndVisits(
+ std::map<GURL, std::vector<VisitRow>>* url_to_visit,
+ std::map<GURL, URLRow>* url_to_urlrow) {
DCHECK(url_to_visit);
DCHECK(url_to_urlrow);
- URLRows local_typed_urls;
+ std::vector<URLRow> local_typed_urls;
if (!history_backend_->GetAllTypedURLs(&local_typed_urls)) {
return false;
}
@@ -1252,8 +1247,8 @@ std::string TypedURLSyncBridge::GetStorageKeyInternal(const std::string& url) {
void TypedURLSyncBridge::SendTypedURLToProcessor(
const URLRow& row,
- const VisitVector& visits,
- MetadataChangeList* metadata_change_list) {
+ const std::vector<VisitRow>& visits,
+ syncer::MetadataChangeList* metadata_change_list) {
DCHECK(!visits.empty());
DCHECK(metadata_change_list);
diff --git a/chromium/components/history/core/browser/sync/typed_url_sync_bridge.h b/chromium/components/history/core/browser/sync/typed_url_sync_bridge.h
index 73ff82857b5..b48f35a5c0a 100644
--- a/chromium/components/history/core/browser/sync/typed_url_sync_bridge.h
+++ b/chromium/components/history/core/browser/sync/typed_url_sync_bridge.h
@@ -61,12 +61,12 @@ class TypedURLSyncBridge : public syncer::ModelTypeSyncBridge,
const RedirectList& redirects,
base::Time visit_time) override;
void OnURLsModified(HistoryBackend* history_backend,
- const URLRows& changed_urls,
+ const std::vector<URLRow>& changed_urls,
bool is_from_expiration) override;
void OnURLsDeleted(HistoryBackend* history_backend,
bool all_history,
bool expired,
- const URLRows& deleted_rows,
+ const std::vector<URLRow>& deleted_rows,
const std::set<GURL>& favicon_urls) override;
// Must be called after creation and before any operations.
@@ -78,23 +78,23 @@ class TypedURLSyncBridge : public syncer::ModelTypeSyncBridge,
// Return true if this function successfully converts the passed URL
// information to a TypedUrlSpecifics structure for writing to the sync DB.
- static bool WriteToTypedUrlSpecifics(const URLRow& url,
- const VisitVector& visits,
- sync_pb::TypedUrlSpecifics* specifics)
- WARN_UNUSED_RESULT;
+ [[nodiscard]] static bool WriteToTypedUrlSpecifics(
+ const URLRow& url,
+ const std::vector<VisitRow>& visits,
+ sync_pb::TypedUrlSpecifics* specifics);
private:
friend class TypedURLSyncBridgeTest;
- typedef std::vector<std::pair<GURL, std::vector<VisitInfo>>>
- TypedURLVisitVector;
+ struct URLWithVisits {
+ URLWithVisits(const GURL& url, const std::vector<VisitInfo>& visits);
+ ~URLWithVisits();
- // This is a helper map used only in Merge functions.
- typedef std::map<GURL, URLRow> TypedURLMap;
+ URLWithVisits(URLWithVisits&&);
- // This is a helper map used to associate visit vectors from the history db
- // to the typed urls in the above map `TypedURLMap`.
- typedef std::map<GURL, VisitVector> URLVisitVectorMap;
+ GURL url;
+ std::vector<VisitInfo> visits;
+ };
// Bitfield returned from MergeUrls to specify the result of a merge.
typedef uint32_t MergeResult;
@@ -115,7 +115,7 @@ class TypedURLSyncBridge : public syncer::ModelTypeSyncBridge,
// written to the DB - each client is left to age out visits on their own.
static MergeResult MergeUrls(const sync_pb::TypedUrlSpecifics& typed_url,
const URLRow& url,
- VisitVector* visits,
+ std::vector<VisitRow>* visits,
URLRow* new_url,
std::vector<VisitInfo>* new_visits);
@@ -124,10 +124,10 @@ class TypedURLSyncBridge : public syncer::ModelTypeSyncBridge,
// `removed_visits` that can be applied to the history DB to make it match
// the sync DB version. `removed_visits` can be null if the caller does not
// care about which visits to remove.
- static void DiffVisits(const VisitVector& history_visits,
+ static void DiffVisits(const std::vector<VisitRow>& history_visits,
const sync_pb::TypedUrlSpecifics& sync_specifics,
std::vector<VisitInfo>* new_visits,
- VisitVector* removed_visits);
+ std::vector<VisitRow>* removed_visits);
// Fills `new_url` with formatted data from `typed_url`.
static void UpdateURLRowFromTypedUrlSpecifics(
@@ -142,11 +142,11 @@ class TypedURLSyncBridge : public syncer::ModelTypeSyncBridge,
// how to merge any existing data, and updates appropriate data containers to
// write to server and backend.
void MergeURLWithSync(const sync_pb::TypedUrlSpecifics& server_typed_url,
- TypedURLMap* local_typed_urls,
- URLVisitVectorMap* visit_vectors,
- URLRows* new_synced_urls,
- TypedURLVisitVector* new_synced_visits,
- URLRows* updated_synced_urls);
+ std::map<GURL, URLRow>* local_typed_urls,
+ std::map<GURL, std::vector<VisitRow>>* visit_vectors,
+ std::vector<URLRow>* new_synced_urls,
+ std::vector<URLWithVisits>* new_synced_visits,
+ std::vector<URLRow>* updated_synced_urls);
// Given a typed URL in the sync DB, looks for an existing entry in the
// local history DB and generates a list of visits to add to the
@@ -156,10 +156,10 @@ class TypedURLSyncBridge : public syncer::ModelTypeSyncBridge,
// `updated_urls` or `new_urls` depending on whether the URL already existed
// in the history DB.
void UpdateFromSync(const sync_pb::TypedUrlSpecifics& typed_url,
- TypedURLVisitVector* visits_to_add,
- VisitVector* visits_to_remove,
- URLRows* updated_urls,
- URLRows* new_urls);
+ std::vector<URLWithVisits>* visits_to_add,
+ std::vector<VisitRow>* visits_to_remove,
+ std::vector<URLRow>* updated_urls,
+ std::vector<URLRow>* new_urls);
// Utility routine that (a) updates an existing sync node or (b) creates a
// new one for the passed `typed_url` if one does not already exist or (c)
@@ -176,11 +176,11 @@ class TypedURLSyncBridge : public syncer::ModelTypeSyncBridge,
// Writes new typed url data from sync server to history backend.
absl::optional<syncer::ModelError> WriteToHistoryBackend(
- const URLRows* new_urls,
- const URLRows* updated_urls,
+ const std::vector<URLRow>* new_urls,
+ const std::vector<URLRow>* updated_urls,
const std::vector<GURL>* deleted_urls,
- const TypedURLVisitVector* new_visits,
- const VisitVector* deleted_visits);
+ const std::vector<URLWithVisits>* new_visits,
+ const std::vector<VisitRow>* deleted_visits);
// Given a TypedUrlSpecifics object, removes all visits that are older than
// the current expiration time. Note that this can result in having no visits
@@ -194,7 +194,7 @@ class TypedURLSyncBridge : public syncer::ModelTypeSyncBridge,
// Helper function that determines if we should ignore a URL for the purposes
// of sync, based on the visits the URL had.
- bool ShouldIgnoreVisits(const VisitVector& visits);
+ bool ShouldIgnoreVisits(const std::vector<VisitRow>& visits);
// Returns true if the caller should sync as a result of the passed visit
// notification. We use this to throttle the number of sync changes we send
@@ -212,18 +212,19 @@ class TypedURLSyncBridge : public syncer::ModelTypeSyncBridge,
// Returns false if we could not fetch the visits for the passed URL, DB
// error. If there are no visits for the passed url, or all the visits are
// expired, it returns true but `visits` is empty.
- bool FixupURLAndGetVisits(URLRow* url, VisitVector* visits);
+ bool FixupURLAndGetVisits(URLRow* url, std::vector<VisitRow>* visits);
// Create an EntityData by URL `row` and its visits `visits`.
std::unique_ptr<syncer::EntityData> CreateEntityData(
const URLRow& row,
- const VisitVector& visits);
+ const std::vector<VisitRow>& visits);
// Get all the typed urls and visits from the history db, after filtering
// them, put them into `url_to_visit` and `url_to_urlrow`.
// Return false if cannot get urls from HistoryBackend.
- bool GetValidURLsAndVisits(URLVisitVectorMap* url_to_visit,
- TypedURLMap* url_to_urlrow);
+ bool GetValidURLsAndVisits(
+ std::map<GURL, std::vector<VisitRow>>* url_to_visit,
+ std::map<GURL, URLRow>* url_to_urlrow);
// Get URLID from HistoryBackend, and return URLID as storage key.
std::string GetStorageKeyInternal(const std::string& url);
@@ -231,7 +232,7 @@ class TypedURLSyncBridge : public syncer::ModelTypeSyncBridge,
// Send local typed url to processor().
void SendTypedURLToProcessor(
const URLRow& row,
- const VisitVector& visits,
+ const std::vector<VisitRow>& visits,
syncer::MetadataChangeList* metadata_change_list);
// A non-owning pointer to the backend, which we're syncing local changes from
@@ -240,7 +241,7 @@ class TypedURLSyncBridge : public syncer::ModelTypeSyncBridge,
// Whether we're currently processing changes from the syncer. While this is
// true, we ignore any local url changes, since we triggered them.
- bool processing_syncer_changes_;
+ bool processing_syncer_changes_ = false;
// A non-owning pointer to the database, which is for storing typed urls sync
// metadata and state.
diff --git a/chromium/components/history/core/browser/sync/typed_url_sync_bridge_unittest.cc b/chromium/components/history/core/browser/sync/typed_url_sync_bridge_unittest.cc
index e0cedda91cb..84ecac18208 100644
--- a/chromium/components/history/core/browser/sync/typed_url_sync_bridge_unittest.cc
+++ b/chromium/components/history/core/browser/sync/typed_url_sync_bridge_unittest.cc
@@ -119,7 +119,7 @@ bool URLsEqual(const URLRow& lhs, const URLRow& rhs) {
void AddNewestVisit(ui::PageTransition transition,
int64_t visit_time,
URLRow* url,
- VisitVector* visits) {
+ std::vector<VisitRow>* visits) {
Time time = SinceEpoch(visit_time);
visits->insert(visits->begin(),
VisitRow(url->id(), time, 0, transition, 0,
@@ -136,7 +136,7 @@ void AddNewestVisit(ui::PageTransition transition,
void AddOldestVisit(ui::PageTransition transition,
int visit_time,
URLRow* url,
- VisitVector* visits) {
+ std::vector<VisitRow>* visits) {
Time time = SinceEpoch(visit_time);
visits->push_back(VisitRow(url->id(), time, 0, transition, 0,
HistoryBackend::IsTypedIncrement(transition), 0));
@@ -155,7 +155,7 @@ URLRow MakeTypedUrlRow(const std::string& url,
int typed_count,
int64_t last_visit,
bool hidden,
- VisitVector* visits) {
+ std::vector<VisitRow>* visits) {
// Give each URL a unique ID, to mimic the behavior of the real database.
GURL gurl(url);
URLRow history_url(gurl);
@@ -186,7 +186,7 @@ URLRow MakeTypedUrlRowWithTwoVisits(const std::string& url,
const std::string& title,
int64_t typed_visit,
int64_t reload_visit,
- VisitVector* visits) {
+ std::vector<VisitRow>* visits) {
// Give each URL a unique ID, to mimic the behavior of the real database.
GURL gurl(url);
URLRow history_url(gurl);
@@ -228,10 +228,10 @@ void VerifyEqual(const TypedUrlSpecifics& s1, const TypedUrlSpecifics& s2) {
void VerifyDataBatch(std::map<std::string, TypedUrlSpecifics> expected,
std::unique_ptr<DataBatch> batch) {
while (batch->HasNext()) {
- const KeyAndData& pair = batch->Next();
- auto iter = expected.find(pair.first);
+ auto [key, data] = batch->Next();
+ auto iter = expected.find(key);
ASSERT_NE(iter, expected.end());
- VerifyEqual(iter->second, pair.second->specifics.typed_url());
+ VerifyEqual(iter->second, data->specifics.typed_url());
// Removing allows us to verify we don't see the same item multiple times,
// and that we saw everything we expected.
expected.erase(iter);
@@ -271,12 +271,15 @@ class TestHistoryBackendDelegate : public HistoryBackend::Delegate {
const URLRow& row,
const RedirectList& redirects,
Time visit_time) override {}
- void NotifyURLsModified(const URLRows& changed_urls) override {}
+ void NotifyURLsModified(const std::vector<URLRow>& changed_urls) override {}
void NotifyURLsDeleted(DeletionInfo deletion_info) override {}
void NotifyKeywordSearchTermUpdated(const URLRow& row,
KeywordID keyword_id,
const std::u16string& term) override {}
void NotifyKeywordSearchTermDeleted(URLID url_id) override {}
+ void NotifyContentModelAnnotationModified(
+ const URLRow& row,
+ const VisitContentModelAnnotations& model_annotations) override {}
void DBLoaded() override {}
};
@@ -296,7 +299,7 @@ class TestHistoryBackendForSync : public HistoryBackend {
return db()->GetRowForURL(gurl, nullptr);
}
- void SetVisitsForUrl(URLRow* new_url, const VisitVector visits) {
+ void SetVisitsForUrl(URLRow* new_url, const std::vector<VisitRow> visits) {
if (!GetURL(new_url->url(), nullptr)) {
URLRow to_insert = *new_url;
// AddVisits() increments counts so we should decrement it now to get a
@@ -369,11 +372,12 @@ class TypedURLSyncBridgeTest : public testing::Test {
EXPECT_FALSE(error);
}
- void BuildAndPushLocalChanges(size_t num_typed_urls,
- size_t num_reload_urls,
- const std::vector<std::string>& urls,
- URLRows* rows,
- std::vector<VisitVector>* visit_vectors) {
+ void BuildAndPushLocalChanges(
+ size_t num_typed_urls,
+ size_t num_reload_urls,
+ const std::vector<std::string>& urls,
+ std::vector<URLRow>* rows,
+ std::vector<std::vector<VisitRow>>* visit_vectors) {
const size_t total_urls = num_typed_urls + num_reload_urls;
DCHECK(urls.size() >= total_urls);
DCHECK(bridge());
@@ -381,11 +385,11 @@ class TypedURLSyncBridgeTest : public testing::Test {
if (total_urls) {
// Create new URL rows, populate the mock backend with its visits, and
// send to the sync service.
- URLRows changed_urls;
+ std::vector<URLRow> changed_urls;
for (size_t i = 0; i < total_urls; ++i) {
const int typed = i < num_typed_urls ? 1 : 0;
- VisitVector visits;
+ std::vector<VisitRow> visits;
visit_vectors->push_back(visits);
rows->push_back(MakeTypedUrlRow(urls[i], kTitle, typed, i + 3, false,
&visit_vectors->back()));
@@ -399,13 +403,14 @@ class TypedURLSyncBridgeTest : public testing::Test {
}
}
- VisitVector ApplyUrlAndVisitsChange(const std::string& url,
- const std::string& title,
- int typed_count,
- int64_t last_visit,
- bool hidden,
- EntityChange::ChangeType change_type) {
- VisitVector visits;
+ std::vector<VisitRow> ApplyUrlAndVisitsChange(
+ const std::string& url,
+ const std::string& title,
+ int typed_count,
+ int64_t last_visit,
+ bool hidden,
+ EntityChange::ChangeType change_type) {
+ std::vector<VisitRow> visits;
URLRow row =
MakeTypedUrlRow(url, title, typed_count, last_visit, hidden, &visits);
sync_pb::TypedUrlSpecifics typed_url_specifics;
@@ -443,7 +448,7 @@ class TypedURLSyncBridgeTest : public testing::Test {
// Fills `specifics` with the sync data for `url` and `visits`.
static bool WriteToTypedUrlSpecifics(const URLRow& url,
- const VisitVector& visits,
+ const std::vector<VisitRow>& visits,
TypedUrlSpecifics* specifics) {
return TypedURLSyncBridge::WriteToTypedUrlSpecifics(url, visits, specifics);
}
@@ -456,8 +461,9 @@ class TypedURLSyncBridgeTest : public testing::Test {
MetadataBatch metadata_batch;
metadata_store()->GetAllSyncMetadata(&metadata_batch);
std::set<std::string> keys;
- for (const auto& kv : metadata_batch.GetAllMetadata()) {
- keys.insert(kv.first);
+ for (const auto& [storage_key, metadata] :
+ metadata_batch.GetAllMetadata()) {
+ keys.insert(storage_key);
}
return keys;
}
@@ -499,10 +505,10 @@ class TypedURLSyncBridgeTest : public testing::Test {
base::BindOnce(&VerifyDataBatch, ExpectedMap(expected)));
}
- static void DiffVisits(const VisitVector& history_visits,
+ static void DiffVisits(const std::vector<VisitRow>& history_visits,
const sync_pb::TypedUrlSpecifics& sync_specifics,
std::vector<VisitInfo>* new_visits,
- VisitVector* removed_visits) {
+ std::vector<VisitRow>* removed_visits) {
TypedURLSyncBridge::DiffVisits(history_visits, sync_specifics, new_visits,
removed_visits);
}
@@ -515,7 +521,7 @@ class TypedURLSyncBridgeTest : public testing::Test {
static TypedURLSyncBridge::MergeResult MergeUrls(
const sync_pb::TypedUrlSpecifics& typed_url,
const URLRow& url,
- VisitVector* visits,
+ std::vector<VisitRow>* visits,
URLRow* new_url,
std::vector<VisitInfo>* new_visits) {
return TypedURLSyncBridge::MergeUrls(typed_url, url, visits, new_url,
@@ -562,7 +568,7 @@ class TypedURLSyncBridgeTest : public testing::Test {
// Add two typed urls locally and verify bridge can get them from GetAllData.
TEST_F(TypedURLSyncBridgeTest, GetAllData) {
// Add two urls to backend.
- VisitVector visits1, visits2, visits3;
+ std::vector<VisitRow> visits1, visits2, visits3;
URLRow row1 = MakeTypedUrlRow(kURL, kTitle, 1, 3, false, &visits1);
URLRow row2 = MakeTypedUrlRow(kURL2, kTitle2, 2, 4, false, &visits2);
URLRow expired_row = MakeTypedUrlRow("http://expired.com/", kTitle, 1,
@@ -583,7 +589,7 @@ TEST_F(TypedURLSyncBridgeTest, GetAllData) {
// Add two typed urls locally and verify bridge can get them from GetData.
TEST_F(TypedURLSyncBridgeTest, GetData) {
// Add two urls to backend.
- VisitVector visits1, visits2;
+ std::vector<VisitRow> visits1, visits2;
URLRow row1 = MakeTypedUrlRow(kURL, kTitle, 1, 3, false, &visits1);
URLRow row2 = MakeTypedUrlRow(kURL2, kTitle2, 2, 4, false, &visits2);
fake_history_backend_->SetVisitsForUrl(&row1, visits1);
@@ -603,7 +609,7 @@ TEST_F(TypedURLSyncBridgeTest, GetData) {
// should result in no changes.
TEST_F(TypedURLSyncBridgeTest, MergeUrlNoChange) {
// Add a url to backend.
- VisitVector visits;
+ std::vector<VisitRow> visits;
URLRow row = MakeTypedUrlRow(kURL, kTitle, 1, 3, false, &visits);
fake_history_backend_->SetVisitsForUrl(&row, visits);
@@ -631,7 +637,7 @@ TEST_F(TypedURLSyncBridgeTest, MergeUrlNoChange) {
// url visit. Starting sync should not pick up this url.
TEST_F(TypedURLSyncBridgeTest, MergeUrlNoTypedUrl) {
// Add a url to backend.
- VisitVector visits;
+ std::vector<VisitRow> visits;
URLRow row = MakeTypedUrlRow(kURL, kTitle, 0, 3, false, &visits);
// Mark typed_count to 1 even when there is no typed url visit.
@@ -649,7 +655,7 @@ TEST_F(TypedURLSyncBridgeTest, MergeUrlNoTypedUrl) {
// Starting sync with no sync data should just push the local url to sync.
TEST_F(TypedURLSyncBridgeTest, MergeUrlEmptySync) {
// Add a url to backend.
- VisitVector visits;
+ std::vector<VisitRow> visits;
URLRow row = MakeTypedUrlRow(kURL, kTitle, 1, 3, false, &visits);
fake_history_backend_->SetVisitsForUrl(&row, visits);
@@ -682,7 +688,7 @@ TEST_F(TypedURLSyncBridgeTest, MergeUrlEmptySync) {
// backend.
TEST_F(TypedURLSyncBridgeTest, MergeUrlEmptyLocal) {
// Create the sync data.
- VisitVector visits;
+ std::vector<VisitRow> visits;
URLRow row = MakeTypedUrlRow(kURL, kTitle, 1, 3, false, &visits);
sync_pb::EntitySpecifics entity_specifics;
sync_pb::TypedUrlSpecifics* typed_url = entity_specifics.mutable_typed_url();
@@ -697,7 +703,7 @@ TEST_F(TypedURLSyncBridgeTest, MergeUrlEmptyLocal) {
StartSyncing({*typed_url});
// Check that the backend was updated correctly.
- VisitVector all_visits;
+ std::vector<VisitRow> all_visits;
Time server_time = SinceEpoch(3);
URLID url_id = fake_history_backend_->GetIdByUrl(GURL(kURL));
ASSERT_NE(0, url_id);
@@ -715,12 +721,12 @@ TEST_F(TypedURLSyncBridgeTest, MergeUrlEmptyLocal) {
// timestamp.
TEST_F(TypedURLSyncBridgeTest, MergeUrlOldLocal) {
// Add a url to backend.
- VisitVector visits;
+ std::vector<VisitRow> visits;
URLRow local_row = MakeTypedUrlRow(kURL, kTitle, 1, 3, false, &visits);
fake_history_backend_->SetVisitsForUrl(&local_row, visits);
// Create sync data for the same url with a more recent visit.
- VisitVector server_visits;
+ std::vector<VisitRow> server_visits;
URLRow server_row =
MakeTypedUrlRow(kURL, kTitle2, 1, 6, false, &server_visits);
server_row.set_id(fake_history_backend_->GetIdByUrl(GURL(kURL)));
@@ -734,7 +740,7 @@ TEST_F(TypedURLSyncBridgeTest, MergeUrlOldLocal) {
StartSyncing({*typed_url});
// Check that the backend was updated correctly.
- VisitVector all_visits;
+ std::vector<VisitRow> all_visits;
Time server_time = SinceEpoch(6);
URLID url_id = fake_history_backend_->GetIdByUrl(GURL(kURL));
ASSERT_NE(0, url_id);
@@ -769,12 +775,12 @@ TEST_F(TypedURLSyncBridgeTest, MergeUrlOldLocal) {
// recent timestamp.
TEST_F(TypedURLSyncBridgeTest, MergeUrlOldSync) {
// Add a url to backend.
- VisitVector visits;
+ std::vector<VisitRow> visits;
URLRow local_row = MakeTypedUrlRow(kURL, kTitle2, 1, 3, false, &visits);
fake_history_backend_->SetVisitsForUrl(&local_row, visits);
// Create sync data for the same url with an older visit.
- VisitVector server_visits;
+ std::vector<VisitRow> server_visits;
URLRow server_row =
MakeTypedUrlRow(kURL, kTitle, 1, 2, false, &server_visits);
sync_pb::EntitySpecifics entity_specifics;
@@ -787,7 +793,7 @@ TEST_F(TypedURLSyncBridgeTest, MergeUrlOldSync) {
StartSyncing({*typed_url});
// Check that the backend was not updated.
- VisitVector all_visits;
+ std::vector<VisitRow> all_visits;
Time local_visit_time = SinceEpoch(3);
URLID url_id = fake_history_backend_->GetIdByUrl(GURL(kURL));
ASSERT_NE(0, url_id);
@@ -816,12 +822,12 @@ TEST_F(TypedURLSyncBridgeTest, MergeUrlsWithUsernameAndPassword) {
"http://username:password@pie.com/";
// Add a url to backend.
- VisitVector visits;
+ std::vector<VisitRow> visits;
URLRow local_row = MakeTypedUrlRow(kURL, kTitle2, 1, 3, false, &visits);
fake_history_backend_->SetVisitsForUrl(&local_row, visits);
// Create sync data for the same url but contain username and password.
- VisitVector server_visits;
+ std::vector<VisitRow> server_visits;
URLRow server_row = MakeTypedUrlRow(kURLWithUsernameAndPassword, kTitle, 1, 3,
false, &server_visits);
sync_pb::EntitySpecifics entity_specifics;
@@ -844,12 +850,12 @@ TEST_F(TypedURLSyncBridgeTest, MergeUrlsWithUsernameAndPassword) {
// visit. After merge, both local and sync should have two same visits.
TEST_F(TypedURLSyncBridgeTest, SimpleMerge) {
// Add a url to backend.
- VisitVector visits1;
+ std::vector<VisitRow> visits1;
URLRow row1 = MakeTypedUrlRow(kURL, kTitle, 1, 3, false, &visits1);
fake_history_backend_->SetVisitsForUrl(&row1, visits1);
// Create the sync data.
- VisitVector visits2;
+ std::vector<VisitRow> visits2;
URLRow row2 = MakeTypedUrlRow(kURL, kTitle, 1, 4, false, &visits2);
sync_pb::EntitySpecifics entity_specifics;
sync_pb::TypedUrlSpecifics* typed_url = entity_specifics.mutable_typed_url();
@@ -860,7 +866,7 @@ TEST_F(TypedURLSyncBridgeTest, SimpleMerge) {
StartSyncing({*typed_url});
// Check that the backend was updated correctly.
- VisitVector all_visits;
+ std::vector<VisitRow> all_visits;
URLID url_id = fake_history_backend_->GetIdByUrl(GURL(kURL));
ASSERT_NE(0, url_id);
fake_history_backend_->GetVisitsForURL(url_id, &all_visits);
@@ -878,8 +884,8 @@ TEST_F(TypedURLSyncBridgeTest, SimpleMerge) {
TEST_F(TypedURLSyncBridgeTest, AddLocalTypedUrl) {
// Create a local typed URL (simulate a typed visit) that is not already
// in sync. Check that sync is sent an ADD change for the existing URL.
- URLRows url_rows;
- std::vector<VisitVector> visit_vectors;
+ std::vector<URLRow> url_rows;
+ std::vector<std::vector<VisitRow>> visit_vectors;
std::vector<std::string> urls;
urls.push_back(kURL);
@@ -890,7 +896,7 @@ TEST_F(TypedURLSyncBridgeTest, AddLocalTypedUrl) {
BuildAndPushLocalChanges(1, 0, urls, &url_rows, &visit_vectors);
URLRow url_row = url_rows.front();
- VisitVector visits = visit_vectors.front();
+ std::vector<VisitRow> visits = visit_vectors.front();
// Get typed url specifics.
const sync_pb::TypedUrlSpecifics& url_specifics =
@@ -907,16 +913,16 @@ TEST_F(TypedURLSyncBridgeTest, AddLocalTypedUrl) {
// Update a local typed URL that is already synced. Check that sync is sent an
// UPDATE for the existing url, but RELOAD visits aren't synced.
TEST_F(TypedURLSyncBridgeTest, UpdateLocalTypedUrl) {
- URLRows url_rows;
- std::vector<VisitVector> visit_vectors;
+ std::vector<URLRow> url_rows;
+ std::vector<std::vector<VisitRow>> visit_vectors;
std::vector<std::string> urls;
urls.push_back(kURL);
StartSyncing(std::vector<TypedUrlSpecifics>());
// Update the URL row, adding another typed visit to the visit vector.
- URLRows changed_urls;
- VisitVector visits;
+ std::vector<URLRow> changed_urls;
+ std::vector<VisitRow> visits;
URLRow url_row = MakeTypedUrlRow(kURL, kTitle, 1, 3, false, &visits);
AddNewestVisit(ui::PAGE_TRANSITION_TYPED, 7, &url_row, &visits);
AddNewestVisit(ui::PAGE_TRANSITION_RELOAD, 8, &url_row, &visits);
@@ -953,8 +959,8 @@ TEST_F(TypedURLSyncBridgeTest, UpdateLocalTypedUrl) {
// Append a RELOAD visit to a typed url that is already synced. Check that sync
// does not receive any updates.
TEST_F(TypedURLSyncBridgeTest, ReloadVisitLocalTypedUrl) {
- URLRows url_rows;
- std::vector<VisitVector> visit_vectors;
+ std::vector<URLRow> url_rows;
+ std::vector<std::vector<VisitRow>> visit_vectors;
StartSyncing(std::vector<TypedUrlSpecifics>());
@@ -967,8 +973,8 @@ TEST_F(TypedURLSyncBridgeTest, ReloadVisitLocalTypedUrl) {
// Update the URL row, adding another typed visit to the visit vector.
URLRow url_row = url_rows.front();
- URLRows changed_urls;
- VisitVector new_visits;
+ std::vector<URLRow> changed_urls;
+ std::vector<VisitRow> new_visits;
AddNewestVisit(ui::PAGE_TRANSITION_RELOAD, 7, &url_row, &new_visits);
fake_history_backend_->SetVisitsForUrl(&url_row, new_visits);
changed_urls.push_back(url_row);
@@ -983,8 +989,8 @@ TEST_F(TypedURLSyncBridgeTest, ReloadVisitLocalTypedUrl) {
// Appends a LINK visit to an existing typed url. Check that sync does not
// receive any changes.
TEST_F(TypedURLSyncBridgeTest, LinkVisitLocalTypedUrl) {
- URLRows url_rows;
- std::vector<VisitVector> visit_vectors;
+ std::vector<URLRow> url_rows;
+ std::vector<std::vector<VisitRow>> visit_vectors;
std::vector<std::string> urls;
urls.push_back(kURL);
@@ -998,7 +1004,7 @@ TEST_F(TypedURLSyncBridgeTest, LinkVisitLocalTypedUrl) {
// Update the URL row, adding a non-typed visit to the visit vector.
URLRow url_row = url_rows.front();
- VisitVector new_visits;
+ std::vector<VisitRow> new_visits;
AddNewestVisit(ui::PAGE_TRANSITION_LINK, 6, &url_row, &new_visits);
fake_history_backend_->SetVisitsForUrl(&url_row, new_visits);
@@ -1012,15 +1018,15 @@ TEST_F(TypedURLSyncBridgeTest, LinkVisitLocalTypedUrl) {
// Appends a series of LINK visits followed by a TYPED one to an existing typed
// url. Check that sync receives an UPDATE with the newest visit data.
TEST_F(TypedURLSyncBridgeTest, TypedVisitLocalTypedUrl) {
- URLRows url_rows;
- std::vector<VisitVector> visit_vectors;
+ std::vector<URLRow> url_rows;
+ std::vector<std::vector<VisitRow>> visit_vectors;
std::vector<std::string> urls;
urls.push_back(kURL);
StartSyncing(std::vector<TypedUrlSpecifics>());
// Update the URL row, adding another typed visit to the visit vector.
- VisitVector visits;
+ std::vector<VisitRow> visits;
URLRow url_row = MakeTypedUrlRow(kURL, kTitle, 1, 3, false, &visits);
AddOldestVisit(ui::PAGE_TRANSITION_LINK, 1, &url_row, &visits);
AddNewestVisit(ui::PAGE_TRANSITION_LINK, 6, &url_row, &visits);
@@ -1055,8 +1061,8 @@ TEST_F(TypedURLSyncBridgeTest, TypedVisitLocalTypedUrl) {
// Delete several (but not all) local typed urls. Check that sync receives the
// DELETE changes, and the non-deleted urls remain synced.
TEST_F(TypedURLSyncBridgeTest, DeleteLocalTypedUrl) {
- URLRows url_rows;
- std::vector<VisitVector> visit_vectors;
+ std::vector<URLRow> url_rows;
+ std::vector<std::vector<VisitRow>> visit_vectors;
std::vector<std::string> urls;
urls.push_back("http://pie.com/");
urls.push_back("http://cake.com/");
@@ -1070,7 +1076,7 @@ TEST_F(TypedURLSyncBridgeTest, DeleteLocalTypedUrl) {
BuildAndPushLocalChanges(4, 0, urls, &url_rows, &visit_vectors);
// Delete some urls from backend and create deleted row vector.
- URLRows rows;
+ std::vector<URLRow> rows;
std::set<std::string> deleted_storage_keys;
for (size_t i = 0; i < 3u; ++i) {
const std::string storage_key = GetStorageKey(url_rows[i].url().spec());
@@ -1091,7 +1097,7 @@ TEST_F(TypedURLSyncBridgeTest, DeleteLocalTypedUrl) {
// that sync receives the DELETE changes, and the non-deleted urls remain
// synced.
TEST_F(TypedURLSyncBridgeTest, DeleteLocalTypedUrlVisit) {
- VisitVector visits1, visits2;
+ std::vector<VisitRow> visits1, visits2;
URLRow row1 = MakeTypedUrlRowWithTwoVisits(kURL, kTitle,
/*typed_visit=*/2,
/*reload_visit=*/4, &visits1);
@@ -1110,7 +1116,7 @@ TEST_F(TypedURLSyncBridgeTest, DeleteLocalTypedUrlVisit) {
/*user_initiated*/ true);
URLRow row1_updated;
ASSERT_TRUE(fake_history_backend_->GetURL(GURL(kURL), &row1_updated));
- URLRows changed_urls{row1_updated};
+ std::vector<URLRow> changed_urls{row1_updated};
EXPECT_CALL(mock_processor_, Delete(GetStorageKey(kURL), _));
bridge()->OnURLsModified(fake_history_backend_.get(), changed_urls,
/*is_from_expiration=*/false);
@@ -1123,7 +1129,7 @@ TEST_F(TypedURLSyncBridgeTest, ExpireLocalTypedUrl) {
// Add two URLs into the history db and notify the bridge to get it synced up
// and thus also metadata written into the DB.
- VisitVector visits1, visits2;
+ std::vector<VisitRow> visits1, visits2;
URLRow row1 = MakeTypedUrlRow(kURL, kTitle, /*typed_count=*/1,
/*last_visit=*/2, /*hidden=*/false, &visits1);
URLRow row2 = MakeTypedUrlRow(kURL2, kTitle2, /*typed_count=*/1,
@@ -1165,7 +1171,7 @@ TEST_F(TypedURLSyncBridgeTest, ExpireLocalTypedVisit) {
// Add two URLs into the history db and notify the bridge to get it synced up
// and thus also metadata written into the DB.
- VisitVector visits1, visits2;
+ std::vector<VisitRow> visits1, visits2;
URLRow row1 = MakeTypedUrlRowWithTwoVisits(kURL, kTitle, /*typed_visit=*/2,
/*reload_visit=*/5, &visits1);
URLRow row2 = MakeTypedUrlRow(kURL2, kTitle2, /*typed_count=*/1,
@@ -1212,7 +1218,7 @@ TEST_F(TypedURLSyncBridgeTest, ExpireLastLocalVisit) {
// Add two URLs into the history db and notify the bridge to get it synced up
// and thus also metadata written into the DB.
- VisitVector visits1, visits2;
+ std::vector<VisitRow> visits1, visits2;
URLRow row1 = MakeTypedUrlRow(kURL, kTitle, /*typed_count=*/1,
/*last_visit=*/1, /*hidden=*/false, &visits1);
URLRow row2 = MakeTypedUrlRow(kURL2, kTitle2, /*typed_count=*/1,
@@ -1260,8 +1266,8 @@ TEST_F(TypedURLSyncBridgeTest, ExpireLastLocalVisit) {
// Check that no more than kMaxTypedURLVisits are synced, and that LINK visits
// are dropped rather than TYPED ones.
TEST_F(TypedURLSyncBridgeTest, MaxVisitLocalTypedUrl) {
- URLRows url_rows;
- std::vector<VisitVector> visit_vectors;
+ std::vector<URLRow> url_rows;
+ std::vector<std::vector<VisitRow>> visit_vectors;
std::vector<std::string> urls;
urls.push_back(kURL);
@@ -1270,7 +1276,7 @@ TEST_F(TypedURLSyncBridgeTest, MaxVisitLocalTypedUrl) {
BuildAndPushLocalChanges(0, 1, urls, &url_rows, &visit_vectors);
URLRow url_row = url_rows.front();
- VisitVector visits;
+ std::vector<VisitRow> visits;
// Add `kMaxTypedUrlVisits` + 10 visits to the url. The 10 oldest
// non-typed visits are expected to be skipped.
@@ -1318,8 +1324,8 @@ TEST_F(TypedURLSyncBridgeTest, MaxVisitLocalTypedUrl) {
// sync does not receive an update until the proper throttle interval has been
// reached.
TEST_F(TypedURLSyncBridgeTest, ThrottleVisitLocalTypedUrl) {
- URLRows url_rows;
- std::vector<VisitVector> visit_vectors;
+ std::vector<URLRow> url_rows;
+ std::vector<std::vector<VisitRow>> visit_vectors;
std::vector<std::string> urls;
urls.push_back(kURL);
@@ -1328,7 +1334,7 @@ TEST_F(TypedURLSyncBridgeTest, ThrottleVisitLocalTypedUrl) {
BuildAndPushLocalChanges(0, 1, urls, &url_rows, &visit_vectors);
URLRow url_row = url_rows.front();
- VisitVector visits;
+ std::vector<VisitRow> visits;
// Add enough visits to the url so that typed count is above the throttle
// limit, and not right on the interval that gets synced.
@@ -1369,12 +1375,12 @@ TEST_F(TypedURLSyncBridgeTest, AddUrlAndVisits) {
UpdateStorageKey(
AllOf(HasURLInSpecifics(kURL), HasTitleInSpecifics(kTitle)),
IntToStorageKey(1), _));
- VisitVector visits =
+ std::vector<VisitRow> visits =
ApplyUrlAndVisitsChange(kURL, kTitle, /*typed_count=*/1, /*last_visit=*/3,
/*hidden=*/false, EntityChange::ACTION_ADD);
Time visit_time = SinceEpoch(3);
- VisitVector all_visits;
+ std::vector<VisitRow> all_visits;
URLID url_id = fake_history_backend_->GetIdByUrl(GURL(kURL));
ASSERT_NE(0, url_id);
fake_history_backend_->GetVisitsForURL(url_id, &all_visits);
@@ -1409,11 +1415,11 @@ TEST_F(TypedURLSyncBridgeTest, AddExpiredUrlAndVisits) {
TEST_F(TypedURLSyncBridgeTest, UpdateUrlAndVisits) {
StartSyncing(std::vector<TypedUrlSpecifics>());
- VisitVector visits =
+ std::vector<VisitRow> visits =
ApplyUrlAndVisitsChange(kURL, kTitle, /*typed_count=*/1, /*last_visit=*/3,
/*hidden=*/false, EntityChange::ACTION_ADD);
Time visit_time = SinceEpoch(3);
- VisitVector all_visits;
+ std::vector<VisitRow> all_visits;
URLRow url_row;
URLID url_id = fake_history_backend_->GetIdByUrl(GURL(kURL));
@@ -1428,7 +1434,7 @@ TEST_F(TypedURLSyncBridgeTest, UpdateUrlAndVisits) {
EXPECT_TRUE(fake_history_backend_->GetURL(GURL(kURL), &url_row));
EXPECT_EQ(kTitle, base::UTF16ToUTF8(url_row.title()));
- VisitVector new_visits = ApplyUrlAndVisitsChange(
+ std::vector<VisitRow> new_visits = ApplyUrlAndVisitsChange(
kURL, kTitle2, /*typed_count=*/2, /*last_visit=*/6,
/*hidden=*/false, EntityChange::ACTION_UPDATE);
@@ -1448,8 +1454,8 @@ TEST_F(TypedURLSyncBridgeTest, UpdateUrlAndVisits) {
// Delete a typed urls which already synced. Check that local DB receives the
// DELETE changes.
TEST_F(TypedURLSyncBridgeTest, DeleteUrlAndVisits) {
- URLRows url_rows;
- std::vector<VisitVector> visit_vectors;
+ std::vector<URLRow> url_rows;
+ std::vector<std::vector<VisitRow>> visit_vectors;
std::vector<std::string> urls;
urls.push_back(kURL);
@@ -1459,7 +1465,7 @@ TEST_F(TypedURLSyncBridgeTest, DeleteUrlAndVisits) {
BuildAndPushLocalChanges(1, 0, urls, &url_rows, &visit_vectors);
Time visit_time = SinceEpoch(3);
- VisitVector all_visits;
+ std::vector<VisitRow> all_visits;
URLID url_id = fake_history_backend_->GetIdByUrl(GURL(kURL));
ASSERT_NE(0, url_id);
fake_history_backend_->GetVisitsForURL(url_id, &all_visits);
@@ -1486,7 +1492,7 @@ TEST_F(TypedURLSyncBridgeTest, DeleteUrlAndVisits) {
// Create two set of visits for history DB and sync DB, two same set of visits
// are same. Check DiffVisits will return empty set of diff visits.
TEST_F(TypedURLSyncBridgeTest, DiffVisitsSame) {
- VisitVector old_visits;
+ std::vector<VisitRow> old_visits;
sync_pb::TypedUrlSpecifics new_url;
const int64_t visits[] = {1024, 2065, 65534, 1237684};
@@ -1499,7 +1505,7 @@ TEST_F(TypedURLSyncBridgeTest, DiffVisitsSame) {
}
std::vector<VisitInfo> new_visits;
- VisitVector removed_visits;
+ std::vector<VisitRow> removed_visits;
DiffVisits(old_visits, new_url, &new_visits, &removed_visits);
EXPECT_TRUE(new_visits.empty());
@@ -1509,7 +1515,7 @@ TEST_F(TypedURLSyncBridgeTest, DiffVisitsSame) {
// Create two set of visits for history DB and sync DB. Check DiffVisits will
// return correct set of diff visits.
TEST_F(TypedURLSyncBridgeTest, DiffVisitsRemove) {
- VisitVector old_visits;
+ std::vector<VisitRow> old_visits;
sync_pb::TypedUrlSpecifics new_url;
const int64_t visits_left[] = {1, 2, 1024, 1500, 2065,
@@ -1532,7 +1538,7 @@ TEST_F(TypedURLSyncBridgeTest, DiffVisitsRemove) {
}
std::vector<VisitInfo> new_visits;
- VisitVector removed_visits;
+ std::vector<VisitRow> removed_visits;
DiffVisits(old_visits, new_url, &new_visits, &removed_visits);
EXPECT_TRUE(new_visits.empty());
@@ -1546,7 +1552,7 @@ TEST_F(TypedURLSyncBridgeTest, DiffVisitsRemove) {
// Create two set of visits for history DB and sync DB. Check DiffVisits will
// return correct set of diff visits.
TEST_F(TypedURLSyncBridgeTest, DiffVisitsAdd) {
- VisitVector old_visits;
+ std::vector<VisitRow> old_visits;
sync_pb::TypedUrlSpecifics new_url;
const int64_t visits_left[] = {1024, 2065, 65534, 1237684};
@@ -1566,7 +1572,7 @@ TEST_F(TypedURLSyncBridgeTest, DiffVisitsAdd) {
}
std::vector<VisitInfo> new_visits;
- VisitVector removed_visits;
+ std::vector<VisitRow> removed_visits;
DiffVisits(old_visits, new_url, &new_visits, &removed_visits);
EXPECT_TRUE(removed_visits.empty());
@@ -1581,7 +1587,7 @@ TEST_F(TypedURLSyncBridgeTest, DiffVisitsAdd) {
// Create three visits, check RELOAD visit is removed by
// WriteToTypedUrlSpecifics so it won't apply to sync DB.
TEST_F(TypedURLSyncBridgeTest, WriteTypedUrlSpecifics) {
- VisitVector visits;
+ std::vector<VisitRow> visits;
visits.push_back(CreateVisit(ui::PAGE_TRANSITION_TYPED, 1));
visits.push_back(CreateVisit(ui::PAGE_TRANSITION_RELOAD, 2));
visits.push_back(CreateVisit(ui::PAGE_TRANSITION_LINK, 3));
@@ -1602,7 +1608,7 @@ TEST_F(TypedURLSyncBridgeTest, WriteTypedUrlSpecifics) {
// Create 101 visits, check WriteToTypedUrlSpecifics will only keep 100 visits.
TEST_F(TypedURLSyncBridgeTest, TooManyVisits) {
- VisitVector visits;
+ std::vector<VisitRow> visits;
int64_t timestamp = 1000;
visits.push_back(CreateVisit(ui::PAGE_TRANSITION_TYPED, timestamp++));
for (int i = 0; i < 100; ++i) {
@@ -1627,7 +1633,7 @@ TEST_F(TypedURLSyncBridgeTest, TooManyVisits) {
// Create 306 visits, check WriteToTypedUrlSpecifics will only keep 100 typed
// visits.
TEST_F(TypedURLSyncBridgeTest, TooManyTypedVisits) {
- VisitVector visits;
+ std::vector<VisitRow> visits;
int64_t timestamp = 1000;
for (int i = 0; i < 102; ++i) {
visits.push_back(CreateVisit(ui::PAGE_TRANSITION_TYPED, timestamp++));
@@ -1653,7 +1659,7 @@ TEST_F(TypedURLSyncBridgeTest, TooManyTypedVisits) {
// Create a typed url without visit, check WriteToTypedUrlSpecifics will return
// false for it.
TEST_F(TypedURLSyncBridgeTest, NoTypedVisits) {
- VisitVector visits;
+ std::vector<VisitRow> visits;
URLRow url(MakeTypedUrlRow(kURL, kTitle, 0, 1000, false, &visits));
sync_pb::TypedUrlSpecifics typed_url;
EXPECT_FALSE(WriteToTypedUrlSpecifics(url, visits, &typed_url));
@@ -1662,7 +1668,7 @@ TEST_F(TypedURLSyncBridgeTest, NoTypedVisits) {
}
TEST_F(TypedURLSyncBridgeTest, MergeUrls) {
- VisitVector visits1;
+ std::vector<VisitRow> visits1;
URLRow row1(MakeTypedUrlRow(kURL, kTitle, 2, 3, false, &visits1));
sync_pb::TypedUrlSpecifics specs1(
MakeTypedUrlSpecifics(kURL, kTitle, 3, false));
@@ -1672,11 +1678,11 @@ TEST_F(TypedURLSyncBridgeTest, MergeUrls) {
&new_row1, &new_visits1) ==
TypedURLSyncBridgeTest::DIFF_NONE);
- VisitVector visits2;
+ std::vector<VisitRow> visits2;
URLRow row2(MakeTypedUrlRow(kURL, kTitle, 2, 3, false, &visits2));
sync_pb::TypedUrlSpecifics specs2(
MakeTypedUrlSpecifics(kURL, kTitle, 3, true));
- VisitVector expected_visits2;
+ std::vector<VisitRow> expected_visits2;
URLRow expected2(
MakeTypedUrlRow(kURL, kTitle, 2, 3, true, &expected_visits2));
URLRow new_row2((GURL(kURL)));
@@ -1686,11 +1692,11 @@ TEST_F(TypedURLSyncBridgeTest, MergeUrls) {
TypedURLSyncBridgeTest::DIFF_LOCAL_ROW_CHANGED);
EXPECT_TRUE(URLsEqual(new_row2, expected2));
- VisitVector visits3;
+ std::vector<VisitRow> visits3;
URLRow row3(MakeTypedUrlRow(kURL, kTitle, 2, 3, false, &visits3));
sync_pb::TypedUrlSpecifics specs3(
MakeTypedUrlSpecifics(kURL, kTitle2, 3, true));
- VisitVector expected_visits3;
+ std::vector<VisitRow> expected_visits3;
URLRow expected3(
MakeTypedUrlRow(kURL, kTitle2, 2, 3, true, &expected_visits3));
URLRow new_row3((GURL(kURL)));
@@ -1703,11 +1709,11 @@ TEST_F(TypedURLSyncBridgeTest, MergeUrls) {
// Create one node in history DB with timestamp of 3, and one node in sync
// DB with timestamp of 4. Result should contain one new item (4).
- VisitVector visits4;
+ std::vector<VisitRow> visits4;
URLRow row4(MakeTypedUrlRow(kURL, kTitle, 2, 3, false, &visits4));
sync_pb::TypedUrlSpecifics specs4(
MakeTypedUrlSpecifics(kURL, kTitle2, 4, false));
- VisitVector expected_visits4;
+ std::vector<VisitRow> expected_visits4;
URLRow expected4(
MakeTypedUrlRow(kURL, kTitle2, 2, 4, false, &expected_visits4));
URLRow new_row4((GURL(kURL)));
@@ -1722,11 +1728,11 @@ TEST_F(TypedURLSyncBridgeTest, MergeUrls) {
EXPECT_TRUE(URLsEqual(new_row4, expected4));
EXPECT_EQ(2U, visits4.size());
- VisitVector visits5;
+ std::vector<VisitRow> visits5;
URLRow row5(MakeTypedUrlRow(kURL, kTitle, 1, 4, false, &visits5));
sync_pb::TypedUrlSpecifics specs5(
MakeTypedUrlSpecifics(kURL, kTitle, 3, false));
- VisitVector expected_visits5;
+ std::vector<VisitRow> expected_visits5;
URLRow expected5(
MakeTypedUrlRow(kURL, kTitle, 2, 3, false, &expected_visits5));
URLRow new_row5((GURL(kURL)));
@@ -1745,7 +1751,7 @@ TEST_F(TypedURLSyncBridgeTest, MergeUrls) {
// deleted from the history DB but still exist in the sync DB).
TEST_F(TypedURLSyncBridgeTest, MergeUrlsAfterExpiration) {
// First, create a history row that has two visits, with timestamps 2 and 3.
- VisitVector(history_visits);
+ std::vector<VisitRow>(history_visits);
history_visits.push_back(
VisitRow(0, SinceEpoch(2), 0, ui::PAGE_TRANSITION_TYPED, 0, true, 0));
URLRow history_url(
@@ -1784,8 +1790,8 @@ TEST_F(TypedURLSyncBridgeTest, MergeUrlsAfterExpiration) {
// expired visit, OnURLsModified should only send the non expired visit to sync.
TEST_F(TypedURLSyncBridgeTest, LocalExpiredTypedUrlDoNotSync) {
URLRow row;
- URLRows changed_urls;
- VisitVector visits;
+ std::vector<URLRow> changed_urls;
+ std::vector<VisitRow> visits;
// Add an expired typed URL to local.
row = MakeTypedUrlRow(kURL, kTitle, 1, kExpiredVisit, false, &visits);
diff --git a/chromium/components/history/core/browser/top_sites_database.cc b/chromium/components/history/core/browser/top_sites_database.cc
index 2ff354ffee4..a4b169a1fed 100644
--- a/chromium/components/history/core/browser/top_sites_database.cc
+++ b/chromium/components/history/core/browser/top_sites_database.cc
@@ -6,11 +6,12 @@
#include <stddef.h>
#include <stdint.h>
+
+#include <tuple>
#include <utility>
#include "base/bind.h"
#include "base/files/file_util.h"
-#include "base/ignore_result.h"
#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/string_piece.h"
@@ -128,7 +129,7 @@ void FixTopSitesTable(sql::Database* db, int version) {
"DELETE FROM thumbnails "
"WHERE (url_rank = -1 AND last_forced = 0) "
"OR (url_rank <> -1 AND last_forced <> 0)";
- ignore_result(db->Execute(kFixRankSql));
+ std::ignore = db->Execute(kFixRankSql);
if (db->GetLastChangeCount() > 0)
RecordRecoveryEvent(RECOVERY_EVENT_INVARIANT_RANK);
}
@@ -140,8 +141,8 @@ void FixTopSitesTable(sql::Database* db, int version) {
static const char kFixRedirectsSql[] =
"DELETE FROM %s "
"WHERE url <> substr(redirects, -length(url), length(url))";
- ignore_result(
- db->Execute(base::StringPrintf(kFixRedirectsSql, kTableName).c_str()));
+ std::ignore =
+ db->Execute(base::StringPrintf(kFixRedirectsSql, kTableName).c_str());
if (db->GetLastChangeCount() > 0)
RecordRecoveryEvent(RECOVERY_EVENT_INVARIANT_REDIRECT);
@@ -256,7 +257,7 @@ void DatabaseErrorCallback(sql::Database* db,
// or hardware issues, not coding errors at the client level, so displaying
// the error would probably lead to confusion. The ignored call signals the
// test-expectation framework that the error was handled.
- ignore_result(sql::Database::IsExpectedSqliteError(extended_error));
+ std::ignore = sql::Database::IsExpectedSqliteError(extended_error);
return;
}
diff --git a/chromium/components/history/core/browser/top_sites_impl.cc b/chromium/components/history/core/browser/top_sites_impl.cc
index d921aa5f524..6f5d994b66e 100644
--- a/chromium/components/history/core/browser/top_sites_impl.cc
+++ b/chromium/components/history/core/browser/top_sites_impl.cc
@@ -65,14 +65,14 @@ bool DoTitlesDiffer(const MostVisitedURLList& old_list,
constexpr base::TimeDelta kFirstDelayAtStartup = base::Seconds(15);
// The delay for the all HistoryService queries other than the first one.
-#if defined(OS_IOS) || defined(OS_ANDROID)
+#if BUILDFLAG(IS_IOS) || BUILDFLAG(IS_ANDROID)
// On mobile, having the max at 60 minutes results in the topsites database
// being not updated often enough since the app isn't usually running for long
// stretches of time.
constexpr base::TimeDelta kDelayForUpdates = base::Minutes(5);
#else
constexpr base::TimeDelta kDelayForUpdates = base::Minutes(60);
-#endif // defined(OS_IOS) || defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_IOS) || BUILDFLAG(IS_ANDROID)
// Key for preference listing the URLs that should not be shown as most visited
// tiles.
diff --git a/chromium/components/history/core/browser/url_database.cc b/chromium/components/history/core/browser/url_database.cc
index fa3537793e8..befdf2bffe2 100644
--- a/chromium/components/history/core/browser/url_database.cc
+++ b/chromium/components/history/core/browser/url_database.cc
@@ -731,17 +731,6 @@ bool URLDatabase::CreateURLTable(bool is_temporary) {
// during this period. Once Sync come back, Sync would use ROWIDs and
// timestamps to see if there are any updates need to be synced. And sync
// will only see the new URL, but missed the deleted URL.
- //
- // IMPORTANT NOTE: Currently new tables are created with AUTOINCREMENT
- // but the migration code is disabled. This means that you will not
- // be able to count on AUTOINCREMENT behavior without adding
- // additional migration steps.
- //
- // Along with this, an unused favicon_id column will exist for tables
- // without AUTOINCREMENT. This should be removed everywhere.
- //
- // TODO(https://crbug.com/736136) figure out how to update users to use
- // AUTOINCREMENT and remove the favicon_id column consistently.
"id INTEGER PRIMARY KEY AUTOINCREMENT,"
"url LONGVARCHAR,"
"title LONGVARCHAR,"
diff --git a/chromium/components/history/core/browser/url_row.cc b/chromium/components/history/core/browser/url_row.cc
index c66a2989e8a..f8bd64ed0a5 100644
--- a/chromium/components/history/core/browser/url_row.cc
+++ b/chromium/components/history/core/browser/url_row.cc
@@ -94,13 +94,51 @@ VisitContentModelAnnotations::VisitContentModelAnnotations(
const VisitContentModelAnnotations&) = default;
VisitContentModelAnnotations::~VisitContentModelAnnotations() = default;
+// static
+void VisitContentModelAnnotations::MergeCategoryIntoVector(
+ const Category& category,
+ std::vector<Category>* categories) {
+ DCHECK(categories);
+ for (auto& this_category : *categories) {
+ // If this visit already has the category, upgrade the weight.
+ if (category.id == this_category.id) {
+ this_category.weight = std::max(this_category.weight, category.weight);
+ return;
+ }
+ }
+
+ // Append the category since it wasn't found in our existing `categories`.
+ categories->push_back(category);
+}
+
+void VisitContentModelAnnotations::MergeFrom(
+ const VisitContentModelAnnotations& other) {
+ // To be conservative, we use the lesser of the two visibility scores, but
+ // ignore sentinel values (which are negative).
+ if (other.visibility_score >= 0 &&
+ other.visibility_score < visibility_score) {
+ visibility_score = other.visibility_score;
+ }
+
+ for (auto& other_category : other.categories) {
+ MergeCategoryIntoVector(other_category, &categories);
+ }
+ for (auto& other_entity : other.entities) {
+ MergeCategoryIntoVector(other_entity, &entities);
+ }
+}
+
VisitContentAnnotations::VisitContentAnnotations(
VisitContentAnnotationFlags annotation_flags,
VisitContentModelAnnotations model_annotations,
- const std::vector<std::string>& related_searches)
+ const std::vector<std::string>& related_searches,
+ const GURL& search_normalized_url,
+ const std::u16string& search_terms)
: annotation_flags(annotation_flags),
model_annotations(model_annotations),
- related_searches(related_searches) {}
+ related_searches(related_searches),
+ search_normalized_url(search_normalized_url),
+ search_terms(search_terms) {}
VisitContentAnnotations::VisitContentAnnotations() = default;
VisitContentAnnotations::VisitContentAnnotations(
const VisitContentAnnotations&) = default;
diff --git a/chromium/components/history/core/browser/url_row.h b/chromium/components/history/core/browser/url_row.h
index 2b4ad9098b0..96849ebf104 100644
--- a/chromium/components/history/core/browser/url_row.h
+++ b/chromium/components/history/core/browser/url_row.h
@@ -153,20 +153,25 @@ typedef std::vector<URLRow> URLRows;
// A set of binary state related to a page visit. To be used for bit masking
// operations.
+//
+// These values are persisted in database. Entries should not be renumbered and
+// numeric values should never be reused.
enum VisitContentAnnotationFlag : uint64_t {
kNone = 0,
- // Indicates that the annotated page can be included in FLoC clustering
- // (https://github.com/WICG/floc) based on a relaxed opt-in condition. A page
- // visit is eligible for FLoC clustering if all of the conditions hold:
+ // No longer used in production code. Only referenced in a database migration
+ // test.
+ kDeprecatedFlocEligibleRelaxed = 1ULL << 0,
+
+ // Indicates that the annotated page can be included in browsing topics
+ // calculation (https://github.com/jkarlin/topics). A page visit is eligible
+ // for browsing topics calculation if all of the conditions hold:
// 1. The IP of this visit is publicly routable, i.e. the IP is NOT within
// the ranges reserved for "private" internet
// (https://tools.ietf.org/html/rfc1918).
- // 2. The interest-cohort Permissions Policy feature is allowed in the page.
- // 3. Page opted in / Either one of the following holds:
- // - document.interestCohort API is used in the page
- // - the page has heuristically detected ad resources
- kFlocEligibleRelaxed = 1 << 0,
+ // 2. The browsing-topics Permissions Policy feature is allowed in the page.
+ // 3. Page opted in: document.browsingTopics() API is used in the page.
+ kBrowsingTopicsEligible = 1ULL << 1,
};
using VisitContentAnnotationFlags = uint64_t;
@@ -201,6 +206,15 @@ struct VisitContentModelAnnotations {
VisitContentModelAnnotations(const VisitContentModelAnnotations& other);
~VisitContentModelAnnotations();
+ // Merges `category` into `categories`. It upgrades the weight if it already
+ // exists, and appends it if it doesn't.
+ static void MergeCategoryIntoVector(const Category& category,
+ std::vector<Category>* categories);
+
+ // Merges the max-score, categories, and entities from `other`, which is the
+ // content model annotations of a duplicate visit.
+ void MergeFrom(const VisitContentModelAnnotations& other);
+
// A value from 0 to 1 that represents how prominent, or visible, the page
// might be considered on UI surfaces.
float visibility_score = kDefaultVisibilityScore;
@@ -224,7 +238,9 @@ struct VisitContentAnnotations {
VisitContentAnnotations();
VisitContentAnnotations(VisitContentAnnotationFlags annotation_flags,
VisitContentModelAnnotations model_annotations,
- const std::vector<std::string>& related_searches);
+ const std::vector<std::string>& related_searches,
+ const GURL& search_normalized_url,
+ const std::u16string& search_terms);
VisitContentAnnotations(const VisitContentAnnotations& other);
~VisitContentAnnotations();
@@ -233,6 +249,8 @@ struct VisitContentAnnotations {
VisitContentModelAnnotations model_annotations;
// A vector that contains related searches for a Google SRP visit.
std::vector<std::string> related_searches;
+ GURL search_normalized_url;
+ std::u16string search_terms;
};
class URLResult : public URLRow {
diff --git a/chromium/components/history/core/browser/url_row_unittest.cc b/chromium/components/history/core/browser/url_row_unittest.cc
new file mode 100644
index 00000000000..49ed3fe307c
--- /dev/null
+++ b/chromium/components/history/core/browser/url_row_unittest.cc
@@ -0,0 +1,39 @@
+// Copyright 2022 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.
+
+#include "components/history/core/browser/url_row.h"
+
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::ElementsAre;
+
+namespace history {
+
+namespace {
+
+TEST(HistoryUrlRowTest, MergeCategoryIntoVector) {
+ std::vector<VisitContentModelAnnotations::Category> categories;
+ categories.emplace_back("category1", 40);
+ categories.emplace_back("category2", 20);
+
+ VisitContentModelAnnotations::MergeCategoryIntoVector({"category1", 50},
+ &categories);
+ EXPECT_THAT(
+ categories,
+ ElementsAre(VisitContentModelAnnotations::Category("category1", 50),
+ VisitContentModelAnnotations::Category("category2", 20)));
+
+ VisitContentModelAnnotations::MergeCategoryIntoVector({"category3", 30},
+ &categories);
+ EXPECT_THAT(
+ categories,
+ ElementsAre(VisitContentModelAnnotations::Category("category1", 50),
+ VisitContentModelAnnotations::Category("category2", 20),
+ VisitContentModelAnnotations::Category("category3", 30)));
+}
+
+} // namespace
+
+} // namespace history
diff --git a/chromium/components/history/core/browser/visit_annotations_database.cc b/chromium/components/history/core/browser/visit_annotations_database.cc
index 84c3704fddf..335c07fa216 100644
--- a/chromium/components/history/core/browser/visit_annotations_database.cc
+++ b/chromium/components/history/core/browser/visit_annotations_database.cc
@@ -21,9 +21,10 @@ namespace history {
namespace {
-#define HISTORY_CONTENT_ANNOTATIONS_ROW_FIELDS \
- " visit_id,visibility_score,categories,page_topics_model_version," \
- "annotation_flags,entities,related_searches "
+#define HISTORY_CONTENT_ANNOTATIONS_ROW_FIELDS \
+ " visit_id,visibility_score,categories,page_topics_model_version," \
+ "annotation_flags,entities,related_searches,search_normalized_url," \
+ "search_terms "
#define HISTORY_CONTEXT_ANNOTATIONS_ROW_FIELDS \
" visit_id,context_annotation_flags,duration_since_last_visit," \
"page_end_reason,total_foreground_duration "
@@ -188,7 +189,9 @@ bool VisitAnnotationsDatabase::InitVisitAnnotationsTables() {
"page_topics_model_version INTEGER,"
"annotation_flags INTEGER NOT NULL,"
"entities VARCHAR,"
- "related_searches VARCHAR)")) {
+ "related_searches VARCHAR,"
+ "search_normalized_url VARCHAR,"
+ "search_terms LONGVARCHAR)")) {
return false;
}
@@ -245,7 +248,7 @@ void VisitAnnotationsDatabase::AddContentAnnotationsForVisit(
sql::Statement statement(GetDB().GetCachedStatement(
SQL_FROM_HERE,
"INSERT INTO content_annotations(" HISTORY_CONTENT_ANNOTATIONS_ROW_FIELDS
- ")VALUES(?,?,?,?,?,?,?)"));
+ ")VALUES(?,?,?,?,?,?,?,?,?)"));
statement.BindInt64(0, visit_id);
statement.BindDouble(
1, static_cast<double>(
@@ -261,6 +264,9 @@ void VisitAnnotationsDatabase::AddContentAnnotationsForVisit(
visit_content_annotations.model_annotations.entities));
statement.BindString(6, ConvertRelatedSearchesToStringColumn(
visit_content_annotations.related_searches));
+ statement.BindString(7,
+ visit_content_annotations.search_normalized_url.spec());
+ statement.BindString16(8, visit_content_annotations.search_terms);
if (!statement.Run()) {
DVLOG(0) << "Failed to execute 'content_annotations' insert statement: "
@@ -295,14 +301,14 @@ void VisitAnnotationsDatabase::UpdateContentAnnotationsForVisit(
VisitID visit_id,
const VisitContentAnnotations& visit_content_annotations) {
DCHECK_GT(visit_id, 0);
- sql::Statement statement(
- GetDB().GetCachedStatement(SQL_FROM_HERE,
- "UPDATE content_annotations SET "
- "visibility_score=?,categories=?,"
- "page_topics_model_version=?,"
- "annotation_flags=?,entities=?,"
- "related_searches=? "
- "WHERE visit_id=?"));
+ sql::Statement statement(GetDB().GetCachedStatement(
+ SQL_FROM_HERE,
+ "UPDATE content_annotations SET "
+ "visibility_score=?,categories=?,"
+ "page_topics_model_version=?,"
+ "annotation_flags=?,entities=?,"
+ "related_searches=?,search_normalized_url=?,search_terms=? "
+ "WHERE visit_id=?"));
statement.BindDouble(
0, static_cast<double>(
visit_content_annotations.model_annotations.visibility_score));
@@ -317,7 +323,10 @@ void VisitAnnotationsDatabase::UpdateContentAnnotationsForVisit(
visit_content_annotations.model_annotations.entities));
statement.BindString(5, ConvertRelatedSearchesToStringColumn(
visit_content_annotations.related_searches));
- statement.BindInt64(6, visit_id);
+ statement.BindString(6,
+ visit_content_annotations.search_normalized_url.spec());
+ statement.BindString16(7, visit_content_annotations.search_terms);
+ statement.BindInt64(8, visit_id);
if (!statement.Run()) {
DVLOG(0)
@@ -380,6 +389,9 @@ bool VisitAnnotationsDatabase::GetContentAnnotationsForVisit(
GetCategoriesFromStringColumn(statement.ColumnString(5));
out_content_annotations->related_searches =
GetRelatedSearchesFromStringColumn(statement.ColumnString(6));
+ out_content_annotations->search_normalized_url =
+ GURL(statement.ColumnString(7));
+ out_content_annotations->search_terms = statement.ColumnString16(8);
return true;
}
@@ -678,4 +690,23 @@ bool VisitAnnotationsDatabase::
"ADD COLUMN total_foreground_duration NUMERIC DEFAULT -1000000");
}
+bool VisitAnnotationsDatabase::MigrateContentAnnotationsAddSearchMetadata() {
+ if (!GetDB().DoesTableExist("content_annotations")) {
+ NOTREACHED() << " Content annotations table should exist before migration";
+ return false;
+ }
+
+ if (GetDB().DoesColumnExist("content_annotations", "search_normalized_url") &&
+ GetDB().DoesColumnExist("content_annotations", "search_terms")) {
+ return true;
+ }
+
+ // Add the `search_normalized_url` and `search_terms` columns to the older
+ // versions of the table.
+ return GetDB().Execute(
+ "ALTER TABLE content_annotations "
+ "ADD COLUMN search_normalized_url; \n"
+ "ALTER TABLE content_annotations ADD COLUMN search_terms LONGVARCHAR");
+}
+
} // namespace history
diff --git a/chromium/components/history/core/browser/visit_annotations_database.h b/chromium/components/history/core/browser/visit_annotations_database.h
index d9b01c64793..f12518b8988 100644
--- a/chromium/components/history/core/browser/visit_annotations_database.h
+++ b/chromium/components/history/core/browser/visit_annotations_database.h
@@ -129,13 +129,17 @@ class VisitAnnotationsDatabase {
// table by adding a related searches column.
bool MigrateContentAnnotationsAddRelatedSearchesColumn();
- // Called by the drived classes to migrate the older content_annotations
+ // Called by the derived classes to migrate the older content_annotations
// table by adding a visibility score column.
bool MigrateContentAnnotationsAddVisibilityScore();
- // Called by the drived classes to migrate the older context_annotations
+ // Called by the derived classes to migrate the older context_annotations
// table by adding a total foreground duration column.
bool MigrateContextAnnotationsAddTotalForegroundDuration();
+
+ // Called by the derived classes to migrate the older content_annotations
+ // table by adding the search_normalized_url and search_terms columns.
+ bool MigrateContentAnnotationsAddSearchMetadata();
};
} // namespace history
diff --git a/chromium/components/history/core/browser/visit_annotations_database_unittest.cc b/chromium/components/history/core/browser/visit_annotations_database_unittest.cc
index 154ee90ff98..9a1c5c39258 100644
--- a/chromium/components/history/core/browser/visit_annotations_database_unittest.cc
+++ b/chromium/components/history/core/browser/visit_annotations_database_unittest.cc
@@ -95,11 +95,12 @@ TEST_F(VisitAnnotationsDatabaseTest, AddContentAnnotationsForVisit) {
123,
{{/*id=*/"entity1", /*weight=*/1}, {/*id=*/"entity2", /*weight=*/1}}};
VisitContentAnnotationFlags annotation_flags =
- VisitContentAnnotationFlag::kFlocEligibleRelaxed;
+ VisitContentAnnotationFlag::kBrowsingTopicsEligible;
std::vector<std::string> related_searches{"related searches",
"búsquedas relacionadas"};
VisitContentAnnotations content_annotations{
- annotation_flags, model_annotations, related_searches};
+ annotation_flags, model_annotations, related_searches,
+ GURL("http://pagewithvisit.com?q=search"), u"search"};
AddContentAnnotationsForVisit(visit_id, content_annotations);
// Query for it.
@@ -107,7 +108,7 @@ TEST_F(VisitAnnotationsDatabaseTest, AddContentAnnotationsForVisit) {
ASSERT_TRUE(
GetContentAnnotationsForVisit(visit_id, &got_content_annotations));
- EXPECT_EQ(VisitContentAnnotationFlag::kFlocEligibleRelaxed,
+ EXPECT_EQ(VisitContentAnnotationFlag::kBrowsingTopicsEligible,
got_content_annotations.annotation_flags);
EXPECT_EQ(0.5f, got_content_annotations.model_annotations.visibility_score);
EXPECT_THAT(
@@ -124,6 +125,9 @@ TEST_F(VisitAnnotationsDatabaseTest, AddContentAnnotationsForVisit) {
/*id=*/"entity2", /*weight=*/1)));
EXPECT_THAT(got_content_annotations.related_searches,
ElementsAre("related searches", "búsquedas relacionadas"));
+ EXPECT_EQ(GURL("http://pagewithvisit.com?q=search"),
+ got_content_annotations.search_normalized_url);
+ EXPECT_EQ(u"search", got_content_annotations.search_terms);
}
TEST_F(VisitAnnotationsDatabaseTest,
@@ -175,22 +179,26 @@ TEST_F(VisitAnnotationsDatabaseTest, UpdateContentAnnotationsForVisit) {
{{/*id=*/"entity1", /*weight=*/1}, {/*id=*/"entity2", /*weight=*/1}}};
std::vector<std::string> related_searches{"related searches"};
VisitContentAnnotationFlags annotation_flags =
- VisitContentAnnotationFlag::kFlocEligibleRelaxed;
- VisitContentAnnotations original{annotation_flags, model_annotations,
- related_searches};
+ VisitContentAnnotationFlag::kBrowsingTopicsEligible;
+ VisitContentAnnotations original{
+ annotation_flags, model_annotations, related_searches,
+ GURL("http://pagewithvisit.com?q=search"), u"search"};
AddContentAnnotationsForVisit(visit_id, original);
// Mutate that row.
VisitContentAnnotations modification(original);
modification.model_annotations.visibility_score = 0.3f;
modification.related_searches.emplace_back("búsquedas relacionadas");
+ modification.search_normalized_url =
+ GURL("http://pagewithvisit.com?q=search2");
+ modification.search_terms = u"search2";
UpdateContentAnnotationsForVisit(visit_id, modification);
// Check that the mutated version was written.
VisitContentAnnotations final;
ASSERT_TRUE(GetContentAnnotationsForVisit(visit_id, &final));
- EXPECT_EQ(VisitContentAnnotationFlag::kFlocEligibleRelaxed,
+ EXPECT_EQ(VisitContentAnnotationFlag::kBrowsingTopicsEligible,
final.annotation_flags);
EXPECT_EQ(0.3f, final.model_annotations.visibility_score);
EXPECT_THAT(
@@ -206,6 +214,9 @@ TEST_F(VisitAnnotationsDatabaseTest, UpdateContentAnnotationsForVisit) {
/*id=*/"entity2", /*weight=*/1)));
EXPECT_THAT(final.related_searches,
ElementsAre("related searches", "búsquedas relacionadas"));
+ EXPECT_EQ(final.search_normalized_url,
+ GURL("http://pagewithvisit.com?q=search2"));
+ EXPECT_EQ(final.search_terms, u"search2");
}
TEST_F(VisitAnnotationsDatabaseTest,
@@ -271,7 +282,8 @@ TEST_F(VisitAnnotationsDatabaseTest, DeleteAnnotationsForVisit) {
VisitContentAnnotationFlags annotation_flags =
VisitContentAnnotationFlag::kNone;
VisitContentAnnotations content_annotations{
- annotation_flags, model_annotations, related_searches};
+ annotation_flags, model_annotations, related_searches,
+ GURL("http://pagewithvisit.com?q=search"), u"search"};
AddContentAnnotationsForVisit(visit_id, content_annotations);
VisitContentAnnotations got_content_annotations;
diff --git a/chromium/components/history/metrics/domain_diversity_reporter.cc b/chromium/components/history/metrics/domain_diversity_reporter.cc
index 6de974f5acb..9ede2b3b442 100644
--- a/chromium/components/history/metrics/domain_diversity_reporter.cc
+++ b/chromium/components/history/metrics/domain_diversity_reporter.cc
@@ -4,7 +4,7 @@
#include "components/history/metrics/domain_diversity_reporter.h"
-#include "base/metrics/histogram_macros.h"
+#include "base/metrics/histogram_functions.h"
#include "base/task/post_task.h"
#include "base/task/task_traits.h"
#include "base/threading/thread_task_runner_handle.h"
@@ -139,12 +139,12 @@ void DomainDiversityReporter::ReportDomainMetrics(
return;
for (auto& result_one_day : result) {
- UMA_HISTOGRAM_COUNTS_1000("History.DomainCount1Day",
- result_one_day.one_day_metric.value().count);
- UMA_HISTOGRAM_COUNTS_1000("History.DomainCount7Day",
- result_one_day.seven_day_metric.value().count);
- UMA_HISTOGRAM_COUNTS_1000(
- "History.DomainCount28Day",
+ base::UmaHistogramCounts1000("History.DomainCount1Day_V2",
+ result_one_day.one_day_metric.value().count);
+ base::UmaHistogramCounts1000("History.DomainCount7Day_V2",
+ result_one_day.seven_day_metric.value().count);
+ base::UmaHistogramCounts1000(
+ "History.DomainCount28Day_V2",
result_one_day.twenty_eight_day_metric.value().count);
}
diff --git a/chromium/components/history/metrics/domain_diversity_reporter_unittest.cc b/chromium/components/history/metrics/domain_diversity_reporter_unittest.cc
index 5ca1e5cca60..f4f6c064ded 100644
--- a/chromium/components/history/metrics/domain_diversity_reporter_unittest.cc
+++ b/chromium/components/history/metrics/domain_diversity_reporter_unittest.cc
@@ -135,22 +135,22 @@ TEST_F(DomainDiversityReporterTest, HistoryNotLoaded) {
task_environment_.RunUntilIdle();
// Since History is not yet loaded, there should be no histograms.
- histograms().ExpectTotalCount("History.DomainCountQueryTime", 0);
- histograms().ExpectTotalCount("History.DomainCount1Day", 0);
- histograms().ExpectTotalCount("History.DomainCount7Day", 0);
- histograms().ExpectTotalCount("History.DomainCount28Day", 0);
+ histograms().ExpectTotalCount("History.DomainCountQueryTime_V2", 0);
+ histograms().ExpectTotalCount("History.DomainCount1Day_V2", 0);
+ histograms().ExpectTotalCount("History.DomainCount7Day_V2", 0);
+ histograms().ExpectTotalCount("History.DomainCount28Day_V2", 0);
// Load history. This should trigger reporter, via HistoryService observer.
ASSERT_TRUE(LoadHistory());
Wait();
- histograms().ExpectTotalCount("History.DomainCountQueryTime", 1);
+ histograms().ExpectTotalCount("History.DomainCountQueryTime_V2", 1);
// No domains were visited, but there should be 7 samples. The last
// reporting date, since it has never been set, was defaulted to epoch.
- histograms().ExpectUniqueSample("History.DomainCount1Day", 0, 7);
- histograms().ExpectUniqueSample("History.DomainCount7Day", 0, 7);
- histograms().ExpectUniqueSample("History.DomainCount28Day", 0, 7);
+ histograms().ExpectUniqueSample("History.DomainCount1Day_V2", 0, 7);
+ histograms().ExpectUniqueSample("History.DomainCount7Day_V2", 0, 7);
+ histograms().ExpectUniqueSample("History.DomainCount28Day_V2", 0, 7);
}
TEST_F(DomainDiversityReporterTest, HistoryLoaded) {
@@ -165,9 +165,9 @@ TEST_F(DomainDiversityReporterTest, HistoryLoaded) {
task_environment_.RunUntilIdle();
// Since History is already loaded, there should be a sample reported.
- histograms().ExpectUniqueSample("History.DomainCount1Day", 0, 1);
- histograms().ExpectUniqueSample("History.DomainCount7Day", 0, 1);
- histograms().ExpectUniqueSample("History.DomainCount28Day", 0, 1);
+ histograms().ExpectUniqueSample("History.DomainCount1Day_V2", 0, 1);
+ histograms().ExpectUniqueSample("History.DomainCount7Day_V2", 0, 1);
+ histograms().ExpectUniqueSample("History.DomainCount28Day_V2", 0, 1);
}
TEST_F(DomainDiversityReporterTest, HostAddedSimple) {
@@ -182,24 +182,24 @@ TEST_F(DomainDiversityReporterTest, HostAddedSimple) {
history_service()->AddPage(GURL("http://www.google.com"), two_days_ago,
history::VisitSource::SOURCE_BROWSED);
- histograms().ExpectTotalCount("History.DomainCountQueryTime", 0);
+ histograms().ExpectTotalCount("History.DomainCountQueryTime_V2", 0);
CreateDomainDiversityReporter();
task_environment_.RunUntilIdle();
- histograms().ExpectTotalCount("History.DomainCountQueryTime", 1);
+ histograms().ExpectTotalCount("History.DomainCountQueryTime_V2", 1);
// There are 3 samples for each histogram. One sample of DomainCount1Day,
// two samples of DomainCount7Day and two samples of DomainCount28Day
// should have a visit count of 1.
- histograms().ExpectBucketCount("History.DomainCount1Day", 1, 1);
- histograms().ExpectBucketCount("History.DomainCount1Day", 0, 2);
+ histograms().ExpectBucketCount("History.DomainCount1Day_V2", 1, 1);
+ histograms().ExpectBucketCount("History.DomainCount1Day_V2", 0, 2);
- histograms().ExpectBucketCount("History.DomainCount7Day", 1, 2);
- histograms().ExpectBucketCount("History.DomainCount7Day", 0, 1);
+ histograms().ExpectBucketCount("History.DomainCount7Day_V2", 1, 2);
+ histograms().ExpectBucketCount("History.DomainCount7Day_V2", 0, 1);
- histograms().ExpectBucketCount("History.DomainCount28Day", 1, 2);
- histograms().ExpectBucketCount("History.DomainCount28Day", 0, 1);
+ histograms().ExpectBucketCount("History.DomainCount28Day_V2", 1, 2);
+ histograms().ExpectBucketCount("History.DomainCount28Day_V2", 0, 1);
}
TEST_F(DomainDiversityReporterTest, HostAddedLongAgo) {
@@ -235,15 +235,15 @@ TEST_F(DomainDiversityReporterTest, HostAddedLongAgo) {
CreateDomainDiversityReporter();
task_environment_.RunUntilIdle();
- histograms().ExpectTotalCount("History.DomainCountQueryTime", 1);
+ histograms().ExpectTotalCount("History.DomainCountQueryTime_V2", 1);
- histograms().ExpectUniqueSample("History.DomainCount1Day", 0, 3);
- histograms().ExpectUniqueSample("History.DomainCount7Day", 0, 3);
+ histograms().ExpectUniqueSample("History.DomainCount1Day_V2", 0, 3);
+ histograms().ExpectUniqueSample("History.DomainCount7Day_V2", 0, 3);
// Two of the three DomainCount28Day samples should reflect the
// 4 domain visits 29 days ago.
- histograms().ExpectBucketCount("History.DomainCount28Day", 4, 2);
- histograms().ExpectBucketCount("History.DomainCount28Day", 0, 1);
+ histograms().ExpectBucketCount("History.DomainCount28Day_V2", 4, 2);
+ histograms().ExpectBucketCount("History.DomainCount28Day_V2", 0, 1);
}
TEST_F(DomainDiversityReporterTest, ScheduleNextDay) {
@@ -288,13 +288,13 @@ TEST_F(DomainDiversityReporterTest, ScheduleNextDay) {
task_environment_.RunUntilIdle();
// Two domains visited two days ago.
- histograms().ExpectTotalCount("History.DomainCountQueryTime", 1);
- histograms().ExpectBucketCount("History.DomainCount1Day", 2, 1);
- histograms().ExpectBucketCount("History.DomainCount1Day", 0, 3);
- histograms().ExpectBucketCount("History.DomainCount7Day", 1, 2);
- histograms().ExpectBucketCount("History.DomainCount7Day", 3, 2);
- histograms().ExpectBucketCount("History.DomainCount28Day", 2, 2);
- histograms().ExpectBucketCount("History.DomainCount28Day", 4, 2);
+ histograms().ExpectTotalCount("History.DomainCountQueryTime_V2", 1);
+ histograms().ExpectBucketCount("History.DomainCount1Day_V2", 2, 1);
+ histograms().ExpectBucketCount("History.DomainCount1Day_V2", 0, 3);
+ histograms().ExpectBucketCount("History.DomainCount7Day_V2", 1, 2);
+ histograms().ExpectBucketCount("History.DomainCount7Day_V2", 3, 2);
+ histograms().ExpectBucketCount("History.DomainCount28Day_V2", 2, 2);
+ histograms().ExpectBucketCount("History.DomainCount28Day_V2", 4, 2);
test_clock().SetTime(MidnightNDaysLater(test_clock().Now(), 1) +
base::Hours(10));
@@ -302,18 +302,18 @@ TEST_F(DomainDiversityReporterTest, ScheduleNextDay) {
// The new report will include the four domain visits on the last
// repoting date.
- histograms().ExpectTotalCount("History.DomainCountQueryTime", 2);
- histograms().ExpectBucketCount("History.DomainCount1Day", 4, 1);
- histograms().ExpectBucketCount("History.DomainCount1Day", 2, 1);
- histograms().ExpectBucketCount("History.DomainCount1Day", 0, 3);
-
- histograms().ExpectBucketCount("History.DomainCount7Day", 5, 1);
- histograms().ExpectBucketCount("History.DomainCount7Day", 1, 2);
- histograms().ExpectBucketCount("History.DomainCount7Day", 3, 2);
-
- histograms().ExpectBucketCount("History.DomainCount28Day", 6, 1);
- histograms().ExpectBucketCount("History.DomainCount28Day", 2, 2);
- histograms().ExpectBucketCount("History.DomainCount28Day", 4, 2);
+ histograms().ExpectTotalCount("History.DomainCountQueryTime_V2", 2);
+ histograms().ExpectBucketCount("History.DomainCount1Day_V2", 4, 1);
+ histograms().ExpectBucketCount("History.DomainCount1Day_V2", 2, 1);
+ histograms().ExpectBucketCount("History.DomainCount1Day_V2", 0, 3);
+
+ histograms().ExpectBucketCount("History.DomainCount7Day_V2", 5, 1);
+ histograms().ExpectBucketCount("History.DomainCount7Day_V2", 1, 2);
+ histograms().ExpectBucketCount("History.DomainCount7Day_V2", 3, 2);
+
+ histograms().ExpectBucketCount("History.DomainCount28Day_V2", 6, 1);
+ histograms().ExpectBucketCount("History.DomainCount28Day_V2", 2, 2);
+ histograms().ExpectBucketCount("History.DomainCount28Day_V2", 4, 2);
}
TEST_F(DomainDiversityReporterTest, SaveTimestampInPreference) {
@@ -326,7 +326,7 @@ TEST_F(DomainDiversityReporterTest, SaveTimestampInPreference) {
CreateDomainDiversityReporter();
task_environment_.RunUntilIdle();
- histograms().ExpectTotalCount("History.DomainCountQueryTime", 1);
+ histograms().ExpectTotalCount("History.DomainCountQueryTime_V2", 1);
// Reporter should have updated the pref to the time of the request.
EXPECT_EQ(test_clock().Now(),
@@ -343,10 +343,10 @@ TEST_F(DomainDiversityReporterTest, OnlyOneReportPerDay) {
CreateDomainDiversityReporter();
task_environment_.RunUntilIdle();
- histograms().ExpectTotalCount("History.DomainCountQueryTime", 1);
- histograms().ExpectUniqueSample("History.DomainCount1Day", 0, 1);
- histograms().ExpectUniqueSample("History.DomainCount7Day", 0, 1);
- histograms().ExpectUniqueSample("History.DomainCount28Day", 0, 1);
+ histograms().ExpectTotalCount("History.DomainCountQueryTime_V2", 1);
+ histograms().ExpectUniqueSample("History.DomainCount1Day_V2", 0, 1);
+ histograms().ExpectUniqueSample("History.DomainCount7Day_V2", 0, 1);
+ histograms().ExpectUniqueSample("History.DomainCount28Day_V2", 0, 1);
history_service()->AddPage(GURL("http://www.google.com"), test_clock().Now(),
history::VisitSource::SOURCE_BROWSED);
@@ -363,9 +363,9 @@ TEST_F(DomainDiversityReporterTest, OnlyOneReportPerDay) {
// This could happen when the last report occurred very early
// on a day longer than 24 hours (e.g. the day on which daylight saving
// time ends).
- histograms().ExpectTotalCount("History.DomainCountQueryTime", 1);
- histograms().ExpectUniqueSample("History.DomainCount1Day", 0, 1);
- histograms().ExpectUniqueSample("History.DomainCount7Day", 0, 1);
- histograms().ExpectUniqueSample("History.DomainCount28Day", 0, 1);
+ histograms().ExpectTotalCount("History.DomainCountQueryTime_V2", 1);
+ histograms().ExpectUniqueSample("History.DomainCount1Day_V2", 0, 1);
+ histograms().ExpectUniqueSample("History.DomainCount7Day_V2", 0, 1);
+ histograms().ExpectUniqueSample("History.DomainCount28Day_V2", 0, 1);
}
} // namespace history
diff --git a/chromium/components/history_clusters/core/BUILD.gn b/chromium/components/history_clusters/core/BUILD.gn
index a464f56752c..836ce2a56fe 100644
--- a/chromium/components/history_clusters/core/BUILD.gn
+++ b/chromium/components/history_clusters/core/BUILD.gn
@@ -28,8 +28,11 @@ static_library("core") {
"history_clusters_prefs.h",
"history_clusters_service.cc",
"history_clusters_service.h",
- "history_clusters_types.cc",
"history_clusters_types.h",
+ "history_clusters_util.cc",
+ "history_clusters_util.h",
+ "query_clusters_state.cc",
+ "query_clusters_state.h",
]
if (build_with_on_device_clustering_backend) {
sources += [
@@ -66,7 +69,6 @@ static_library("core") {
":history_clusters_buildflags",
"//base",
"//components/history/core/browser",
- "//components/history_clusters/core/proto",
"//components/keyed_service/core",
"//components/optimization_guide/core:entities",
"//components/pref_registry",
@@ -88,6 +90,8 @@ source_set("unit_tests") {
"features_unittest.cc",
"history_clusters_db_tasks_unittest.cc",
"history_clusters_service_unittest.cc",
+ "history_clusters_util_unittest.cc",
+ "query_clusters_state_unittest.cc",
]
if (build_with_on_device_clustering_backend) {
sources += [
@@ -110,9 +114,9 @@ source_set("unit_tests") {
"//base/test:test_support",
"//components/history/core/browser",
"//components/history/core/test",
- "//components/history_clusters/core/proto",
"//components/optimization_guide/core:entities",
"//components/search_engines",
+ "//components/site_engagement/core",
"//services/network:test_support",
"//testing/gtest",
]
diff --git a/chromium/components/history_clusters/core/clusterer.cc b/chromium/components/history_clusters/core/clusterer.cc
index 292055f6d6e..b1563f49e83 100644
--- a/chromium/components/history_clusters/core/clusterer.cc
+++ b/chromium/components/history_clusters/core/clusterer.cc
@@ -4,11 +4,43 @@
#include "components/history_clusters/core/clusterer.h"
+#include "base/containers/adapters.h"
#include "components/history/core/browser/history_types.h"
#include "components/history_clusters/core/on_device_clustering_features.h"
namespace history_clusters {
+namespace {
+
+// Returns whether |visit| should be added to |cluster|.
+bool ShouldAddVisitToCluster(const history::ClusterVisit& visit,
+ const history::Cluster& cluster) {
+ if ((visit.annotated_visit.visit_row.visit_time -
+ cluster.visits.back().annotated_visit.visit_row.visit_time) >
+ features::ClusterNavigationTimeCutoff()) {
+ return false;
+ }
+ if (features::ShouldSplitClustersAtSearchVisits() &&
+ !visit.search_terms.empty()) {
+ // If we want to split the clusters at search visits and we are at a search
+ // visit, only add the visit to the cluster if the last search visit was
+ // also a search visit with the same terms. Also break the cluster if there
+ // was not already a search visit already.
+ absl::optional<history::ClusterVisit> last_search_visit;
+ for (const auto& existing_visit : base::Reversed(cluster.visits)) {
+ if (!existing_visit.search_terms.empty()) {
+ last_search_visit = existing_visit;
+ break;
+ }
+ }
+ return last_search_visit &&
+ visit.search_terms == last_search_visit->search_terms;
+ }
+ return true;
+}
+
+} // namespace
+
Clusterer::Clusterer() = default;
Clusterer::~Clusterer() = default;
@@ -48,14 +80,12 @@ std::vector<history::Cluster> Clusterer::CreateInitialClustersFromVisits(
}
DCHECK(!cluster_idx || (*cluster_idx < clusters.size()));
- // Even if above conditions were met, add it to a new cluster if the last
- // visit in the cluster's navigation time exceeds a certain duration.
+ // Even if above conditions were met, see if we should add it to the cluster
+ // based on the characteristics of the in progress cluster and the current
+ // visit we are processing.
if (cluster_idx) {
auto in_progress_cluster = clusters[*cluster_idx];
- auto last_visit_nav_time = in_progress_cluster.visits.back()
- .annotated_visit.visit_row.visit_time;
- if ((visit.annotated_visit.visit_row.visit_time - last_visit_nav_time) >
- features::ClusterNavigationTimeCutoff()) {
+ if (!ShouldAddVisitToCluster(visit, in_progress_cluster)) {
// Erase all visits in the cluster from the maps since we no longer
// want to consider anything in the cluster as a referrer.
auto finalized_cluster = clusters[*cluster_idx];
diff --git a/chromium/components/history_clusters/core/clusterer_unittest.cc b/chromium/components/history_clusters/core/clusterer_unittest.cc
index 37c795ef3fe..67321001931 100644
--- a/chromium/components/history_clusters/core/clusterer_unittest.cc
+++ b/chromium/components/history_clusters/core/clusterer_unittest.cc
@@ -197,5 +197,84 @@ TEST_F(ClustererTest, SplitClusterOnNavigationTime) {
ElementsAre(testing::VisitResult(3, 1.0))));
}
+TEST_F(ClustererTest, SplitClusterOnSearchVisit) {
+ std::vector<history::ClusterVisit> visits;
+
+ history::AnnotatedVisit visit =
+ testing::CreateDefaultAnnotatedVisit(1, GURL("https://google.com/"));
+ visit.visit_row.visit_time = base::Time::Now();
+ visits.push_back(testing::CreateClusterVisit(visit));
+
+ // Visit2 has a different URL but is linked by referring id to visit.
+ history::AnnotatedVisit visit2 =
+ testing::CreateDefaultAnnotatedVisit(2, GURL("https://bar.com/"));
+ visit2.referring_visit_of_redirect_chain_start = 1;
+ visit2.visit_row.visit_time = base::Time::Now() + base::Minutes(5);
+ visits.push_back(testing::CreateClusterVisit(visit2));
+
+ // Visit3 has a different URL but is linked by referring id to visit but the
+ // cutoff has passed so it should be in a different cluster.
+ history::AnnotatedVisit visit3 =
+ testing::CreateDefaultAnnotatedVisit(3, GURL("https://foo.com/"));
+ visit3.referring_visit_of_redirect_chain_start = 1;
+ visit3.visit_row.visit_time = base::Time::Now() + base::Hours(2);
+ visits.push_back(testing::CreateClusterVisit(visit3));
+
+ // Visit4 was referred by visit 3 but is a search visit.
+ history::AnnotatedVisit visit4 =
+ testing::CreateDefaultAnnotatedVisit(4, GURL("https://search.com/"));
+ visit4.referring_visit_of_redirect_chain_start = 3;
+ visit4.visit_row.visit_time =
+ base::Time::Now() + base::Hours(2) + base::Minutes(1);
+ history::ClusterVisit cluster_visit4 = testing::CreateClusterVisit(visit4);
+ cluster_visit4.search_terms = u"whatever";
+ visits.push_back(cluster_visit4);
+
+ // Visit5 was referred by visit 4.
+ history::AnnotatedVisit visit5 =
+ testing::CreateDefaultAnnotatedVisit(5, GURL("https://resultlink.com/"));
+ visit5.referring_visit_of_redirect_chain_start = 4;
+ visit5.visit_row.visit_time =
+ base::Time::Now() + base::Hours(2) + base::Minutes(1);
+ visits.push_back(testing::CreateClusterVisit(visit5));
+
+ // Visit6 is a search visit (back-forward) and has the same search terms as
+ // visit 4.
+ history::AnnotatedVisit visit6 =
+ testing::CreateDefaultAnnotatedVisit(6, GURL("https://search.com/"));
+ visit6.visit_row.visit_time =
+ base::Time::Now() + base::Hours(2) + base::Minutes(2);
+ history::ClusterVisit cluster_visit6 = testing::CreateClusterVisit(visit6);
+ cluster_visit6.search_terms = u"whatever";
+ visits.push_back(cluster_visit6);
+
+ // Visit7 was referred by visit 6, is a search visit but has different search
+ // terms as visit 6.
+ history::AnnotatedVisit visit7 =
+ testing::CreateDefaultAnnotatedVisit(7, GURL("https://search.com/"));
+ visit7.referring_visit_of_redirect_chain_start = 6;
+ visit7.visit_row.visit_time =
+ base::Time::Now() + base::Hours(2) + base::Minutes(3);
+ history::ClusterVisit cluster_visit7 = testing::CreateClusterVisit(visit7);
+ cluster_visit7.search_terms = u"different";
+ visits.push_back(cluster_visit7);
+
+ std::vector<history::Cluster> result_clusters =
+ CreateInitialClustersFromVisits(visits);
+ EXPECT_THAT(
+ testing::ToVisitResults(result_clusters),
+ ElementsAre(
+ ElementsAre(testing::VisitResult(1, 1.0),
+ testing::VisitResult(2, 1.0)),
+ ElementsAre(testing::VisitResult(3, 1.0)),
+ ElementsAre(testing::VisitResult(4, 1.0, /*duplicate_visits=*/{},
+ u"whatever"),
+ testing::VisitResult(5, 1.0),
+ testing::VisitResult(6, 1.0, /*duplicate_visits=*/{},
+ u"whatever")),
+ ElementsAre(testing::VisitResult(7, 1.0, /*duplicate_visits=*/{},
+ u"different"))));
+}
+
} // namespace
} // namespace history_clusters
diff --git a/chromium/components/history_clusters/core/clustering_backend.h b/chromium/components/history_clusters/core/clustering_backend.h
index 6220b740559..097fa105d3a 100644
--- a/chromium/components/history_clusters/core/clustering_backend.h
+++ b/chromium/components/history_clusters/core/clustering_backend.h
@@ -10,6 +10,8 @@
namespace history_clusters {
+enum class ClusteringRequestSource { kKeywordCacheGeneration, kJourneysPage };
+
// An abstract interface for a swappable clustering backend.
class ClusteringBackend {
public:
@@ -23,6 +25,7 @@ class ClusteringBackend {
// clusters can be in arbitrary order too. Caller is responsible for sorting
// the output however they want it.
virtual void GetClusters(
+ ClusteringRequestSource clustering_request_source,
ClustersCallback callback,
const std::vector<history::AnnotatedVisit>& visits) = 0;
};
diff --git a/chromium/components/history_clusters/core/clustering_test_utils.cc b/chromium/components/history_clusters/core/clustering_test_utils.cc
index 8e46f332b47..8559b721ad2 100644
--- a/chromium/components/history_clusters/core/clustering_test_utils.cc
+++ b/chromium/components/history_clusters/core/clustering_test_utils.cc
@@ -4,39 +4,74 @@
#include "components/history_clusters/core/clustering_test_utils.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
+#include "components/history_clusters/core/history_clusters_util.h"
namespace history_clusters {
namespace testing {
-VisitResult::VisitResult(
- int visit_id,
- float score,
- const std::vector<history::VisitID>& duplicate_visit_ids,
- bool is_search_visit)
+VisitResult::VisitResult(int visit_id,
+ float score,
+ const std::vector<VisitResult>& duplicate_visits,
+ std::u16string search_terms)
: visit_id_(visit_id),
score_(score),
- duplicate_visit_ids_(duplicate_visit_ids),
- is_search_visit_(is_search_visit) {}
+ duplicate_visits_(duplicate_visits),
+ search_terms_(search_terms) {}
VisitResult::VisitResult(const history::ClusterVisit& visit)
: visit_id_(visit.annotated_visit.visit_row.visit_id),
score_(visit.score),
- duplicate_visit_ids_(visit.duplicate_visit_ids),
- is_search_visit_(visit.is_search_visit) {}
+ search_terms_(visit.search_terms) {
+ for (const auto& duplicate : visit.duplicate_visits) {
+ duplicate_visits_.emplace_back(duplicate);
+ }
+}
VisitResult::VisitResult(const VisitResult& other) = default;
VisitResult::~VisitResult() = default;
+std::string VisitResult::ToString() const {
+ std::string duplicate_visits_string = "{}";
+ if (!duplicate_visits_.empty()) {
+ std::vector<std::string> duplicate_visits_strings;
+ for (const auto& dup_visit : duplicate_visits_) {
+ // In case of multiple layers of nesting, indent inner layers a bit more.
+ std::string dup_visit_string = dup_visit.ToString();
+ base::ReplaceChars(dup_visit_string, "\n", "\n ", &dup_visit_string);
+ duplicate_visits_strings.push_back(dup_visit_string);
+ }
+ duplicate_visits_string = base::StringPrintf(
+ "{\n %s\n}",
+ base::JoinString(duplicate_visits_strings, "\n ").c_str());
+ }
+ return base::StringPrintf(
+ "VisitResult(visit_id=%d, score=%f, duplicate_visits=%s, "
+ "search_terms=%s)",
+ visit_id_, score_, duplicate_visits_string.c_str(),
+ base::UTF16ToUTF8(search_terms_).c_str());
+}
+
+std::ostream& operator<<(std::ostream& os, const VisitResult& vr) {
+ os << vr.ToString();
+ return os;
+}
+
bool VisitResult::operator==(const VisitResult& rhs) const {
- return visit_id_ == rhs.visit_id_ && score_ == rhs.score_ &&
- duplicate_visit_ids_ == rhs.duplicate_visit_ids_ &&
- is_search_visit_ == rhs.is_search_visit_;
+ constexpr const double kScoreTolerance = 1e-6;
+ return visit_id_ == rhs.visit_id_ &&
+ abs(score_ - rhs.score_) <= kScoreTolerance &&
+ duplicate_visits_ == rhs.duplicate_visits_ &&
+ search_terms_ == rhs.search_terms_;
}
history::AnnotatedVisit CreateDefaultAnnotatedVisit(int visit_id,
- const GURL& url) {
+ const GURL& url,
+ base::Time visit_time) {
history::AnnotatedVisit visit;
visit.visit_row.visit_id = visit_id;
+ visit.visit_row.visit_time = visit_time;
visit.url_row.set_url(url);
visit.visit_row.visit_duration = base::Seconds(10);
return visit;
@@ -44,12 +79,15 @@ history::AnnotatedVisit CreateDefaultAnnotatedVisit(int visit_id,
history::ClusterVisit CreateClusterVisit(
const history::AnnotatedVisit& annotated_visit,
- absl::optional<GURL> normalized_url) {
+ absl::optional<GURL> normalized_url,
+ float score) {
history::ClusterVisit cluster_visit;
cluster_visit.annotated_visit = annotated_visit;
- cluster_visit.score = 1.0;
+ cluster_visit.score = score;
cluster_visit.normalized_url =
normalized_url ? *normalized_url : annotated_visit.url_row.url();
+ cluster_visit.url_for_deduping =
+ ComputeURLForDeduping(cluster_visit.normalized_url);
return cluster_visit;
}
diff --git a/chromium/components/history_clusters/core/clustering_test_utils.h b/chromium/components/history_clusters/core/clustering_test_utils.h
index 16b1d030070..87c95f108f4 100644
--- a/chromium/components/history_clusters/core/clustering_test_utils.h
+++ b/chromium/components/history_clusters/core/clustering_test_utils.h
@@ -5,8 +5,10 @@
#ifndef COMPONENTS_HISTORY_CLUSTERS_CORE_CLUSTERING_TEST_UTILS_H_
#define COMPONENTS_HISTORY_CLUSTERS_CORE_CLUSTERING_TEST_UTILS_H_
+#include <ostream>
#include <vector>
+#include "base/time/time.h"
#include "components/history/core/browser/history_types.h"
namespace history_clusters {
@@ -18,37 +20,46 @@ class VisitResult {
public:
VisitResult(int visit_id,
float score,
- const std::vector<history::VisitID>& duplicate_visit_ids = {},
- bool is_search_visit = false);
+ const std::vector<VisitResult>& duplicate_visits = {},
+ std::u16string search_terms = u"");
explicit VisitResult(const history::ClusterVisit& visit);
VisitResult(const VisitResult& other);
~VisitResult();
bool operator==(const VisitResult& rhs) const;
+ std::string ToString() const;
+
private:
+ friend std::ostream& operator<<(std::ostream& os, const VisitResult& dt);
+
const int visit_id_;
const float score_;
- const std::vector<history::VisitID> duplicate_visit_ids_;
- const bool is_search_visit_;
+ std::vector<VisitResult> duplicate_visits_;
+ const std::u16string search_terms_;
};
+std::ostream& operator<<(std::ostream& os, const VisitResult& dt);
+
// Converts |clusters| to VisitResults which are easier to test equality for.
std::vector<std::vector<testing::VisitResult>> ToVisitResults(
const std::vector<history::Cluster>& clusters);
// Creates a default AnnotatedVisit that has the minimal set of fields required.
-history::AnnotatedVisit CreateDefaultAnnotatedVisit(int visit_id,
- const GURL& url);
+history::AnnotatedVisit CreateDefaultAnnotatedVisit(
+ int visit_id,
+ const GURL& url,
+ base::Time visit_time = base::Time());
// Creates a ClusterVisit from |annotated_visit|. Will populate the returned
// ClusterVisit's normalized_url with |normalized_url| if present but otherwise
// will use the URL contained in the AnnotatedVisit.
history::ClusterVisit CreateClusterVisit(
const history::AnnotatedVisit& annotated_visit,
- absl::optional<GURL> normalized_url = absl::nullopt);
+ absl::optional<GURL> normalized_url = absl::nullopt,
+ float score = 1.0);
} // namespace testing
} // namespace history_clusters
-#endif // COMPONENTS_HISTORY_CLUSTERS_CORE_CLUSTERING_TEST_UTILS_H_ \ No newline at end of file
+#endif // COMPONENTS_HISTORY_CLUSTERS_CORE_CLUSTERING_TEST_UTILS_H_
diff --git a/chromium/components/history_clusters/core/features.cc b/chromium/components/history_clusters/core/features.cc
index a3eb07b66d2..8d61acb0e3e 100644
--- a/chromium/components/history_clusters/core/features.cc
+++ b/chromium/components/history_clusters/core/features.cc
@@ -17,7 +17,7 @@ namespace history_clusters {
namespace {
constexpr auto enabled_by_default_desktop_only =
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
base::FEATURE_DISABLED_BY_DEFAULT;
#else
base::FEATURE_ENABLED_BY_DEFAULT;
@@ -69,6 +69,9 @@ const base::FeatureParam<double> kMinScoreToAlwaysShowAboveTheFold{
const base::FeatureParam<int> kNumVisitsToAlwaysShowAboveTheFold{
&internal::kJourneys, "JourneysNumVisitsToAlwaysShowAboveTheFold", 3};
+const base::FeatureParam<bool> kRescoreVisitsWithinClustersForQuery{
+ &internal::kJourneys, "JourneysRescoreVisitsWithinClustersForQuery", true};
+
// Default to true, as this new alternate action text was recommended by our UX
// writers.
const base::FeatureParam<bool> kAlternateOmniboxActionText{
diff --git a/chromium/components/history_clusters/core/features.h b/chromium/components/history_clusters/core/features.h
index c1e31ce0525..0703661b09f 100644
--- a/chromium/components/history_clusters/core/features.h
+++ b/chromium/components/history_clusters/core/features.h
@@ -55,10 +55,6 @@ extern const base::FeatureParam<bool> kPersistClustersInHistoryDb;
// builds, so it won't work in unofficial builds.
extern const base::FeatureParam<bool> kUseOnDeviceClusteringBackend;
-// If enabled, changes the History Clusters omnibox action text to be:
-// "Resume your research" instead of "Resume your journey".
-extern const base::FeatureParam<bool> kAlternateOmniboxActionText;
-
// If enabled, this is the min score that a visit needs to have to always be
// shown above the fold regardless of the number of visits already shown.
extern const base::FeatureParam<double> kMinScoreToAlwaysShowAboveTheFold;
@@ -67,6 +63,14 @@ extern const base::FeatureParam<double> kMinScoreToAlwaysShowAboveTheFold;
// above the fold regardless of score.
extern const base::FeatureParam<int> kNumVisitsToAlwaysShowAboveTheFold;
+// If enabled, when there is a Journeys search query, the backend re-scores
+// visits within a cluster to account for whether or not that visit matches.
+extern const base::FeatureParam<bool> kRescoreVisitsWithinClustersForQuery;
+
+// If enabled, changes the History Clusters omnibox action text to be:
+// "Resume your research" instead of "Resume your journey".
+extern const base::FeatureParam<bool> kAlternateOmniboxActionText;
+
// Features
namespace internal {
diff --git a/chromium/components/history_clusters/core/history_clusters_db_tasks.cc b/chromium/components/history_clusters/core/history_clusters_db_tasks.cc
index 2ad7e344821..57d4a34b161 100644
--- a/chromium/components/history_clusters/core/history_clusters_db_tasks.cc
+++ b/chromium/components/history_clusters/core/history_clusters_db_tasks.cc
@@ -41,14 +41,12 @@ GetAnnotatedVisitsToCluster::GetAnnotatedVisitsToCluster(
HistoryClustersService::IncompleteVisitMap incomplete_visit_map,
base::Time begin_time,
base::Time end_time,
- size_t max_count,
Callback callback)
: incomplete_visit_map_(incomplete_visit_map),
begin_time_limit_(
std::max(begin_time, base::Time::Now() - base::Days(90))),
original_end_time_(end_time),
continuation_end_time_(end_time),
- visit_soft_cap_(max_count),
callback_(std::move(callback)) {}
GetAnnotatedVisitsToCluster::~GetAnnotatedVisitsToCluster() = default;
diff --git a/chromium/components/history_clusters/core/history_clusters_db_tasks.h b/chromium/components/history_clusters/core/history_clusters_db_tasks.h
index dcb4891afd2..ebb83afbc8d 100644
--- a/chromium/components/history_clusters/core/history_clusters_db_tasks.h
+++ b/chromium/components/history_clusters/core/history_clusters_db_tasks.h
@@ -37,7 +37,6 @@ class GetAnnotatedVisitsToCluster : public history::HistoryDBTask {
HistoryClustersService::IncompleteVisitMap incomplete_visit_map,
base::Time begin_time,
base::Time end_time,
- size_t max_count,
Callback callback);
~GetAnnotatedVisitsToCluster() override;
@@ -66,11 +65,11 @@ class GetAnnotatedVisitsToCluster : public history::HistoryDBTask {
// True if we have exhausted history up to `begin_time_limit_` or all of
// History; i.e., we didn't hit the visit count cap.
bool exhausted_history_ = false;
- // This task stops fetching days of History once we've hit this soft cap,
- // which is controlled by the UI. Note there is a separate
- // parameter-controlled hard cap to prevent OOM errors if a single day has too
- // many visits.
- size_t visit_soft_cap_;
+ // This task stops fetching days of History once we've hit this soft cap.
+ // Note there is a separate parameter-controlled hard cap to prevent OOM
+ // errors if a single day has too many visits. We chose this value fairly
+ // arbitrarily, but in practice it fills the WebUI above-the-fold area well.
+ const size_t visit_soft_cap_ = 30;
// Persisted visits retrieved from the history DB thread and returned through
// the callback on the main thread.
std::vector<history::AnnotatedVisit> annotated_visits_;
diff --git a/chromium/components/history_clusters/core/history_clusters_service.cc b/chromium/components/history_clusters/core/history_clusters_service.cc
index 15828742994..1a27cae155f 100644
--- a/chromium/components/history_clusters/core/history_clusters_service.cc
+++ b/chromium/components/history_clusters/core/history_clusters_service.cc
@@ -17,12 +17,10 @@
#include "base/i18n/case_conversion.h"
#include "base/json/json_writer.h"
#include "base/metrics/histogram_functions.h"
-#include "base/ranges/algorithm.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/system/sys_info.h"
-#include "base/task/thread_pool.h"
#include "base/time/time.h"
#include "base/time/time_to_iso8601.h"
#include "base/timer/elapsed_timer.h"
@@ -38,7 +36,6 @@
#include "components/optimization_guide/core/entity_metadata_provider.h"
#include "components/search_engines/template_url_service.h"
#include "components/site_engagement/core/site_engagement_score_provider.h"
-#include "components/url_formatter/url_formatter.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "ui/base/l10n/time_format.h"
@@ -50,116 +47,6 @@ namespace history_clusters {
namespace {
-// Returns true if `find_nodes` matches `cluster`.
-// This is deliberately meant to closely mirror the History implementation..
-// TODO(tommycli): Merge with `URLDatabase::GetTextMatchesWithAlgorithm()`.
-bool DoesQueryMatchCluster(const query_parser::QueryNodeVector& find_nodes,
- const history::Cluster& cluster) {
- query_parser::QueryWordVector find_in_words;
-
- // All of the cluster's `keyword`s go into `find_in_words`.
- // Each `keyword` may have multiple terms, so loop over them.
- for (auto& keyword : cluster.keywords) {
- query_parser::QueryParser::ExtractQueryWords(base::i18n::ToLower(keyword),
- &find_in_words);
- }
-
- // Also extract all of the visits' URLs and titles into `find_in_words`.
- for (const auto& visit : cluster.visits) {
- GURL gurl = visit.annotated_visit.url_row.url();
-
- std::u16string url_lower =
- base::i18n::ToLower(base::UTF8ToUTF16(gurl.possibly_invalid_spec()));
- query_parser::QueryParser::ExtractQueryWords(url_lower, &find_in_words);
-
- if (gurl.is_valid()) {
- // Decode punycode to match IDN.
- std::u16string ascii = base::ASCIIToUTF16(gurl.host());
- std::u16string utf = url_formatter::IDNToUnicode(gurl.host());
- if (ascii != utf)
- query_parser::QueryParser::ExtractQueryWords(utf, &find_in_words);
- }
-
- std::u16string title_lower =
- base::i18n::ToLower(visit.annotated_visit.url_row.title());
- query_parser::QueryParser::ExtractQueryWords(title_lower, &find_in_words);
- }
-
- return query_parser::QueryParser::DoesQueryMatch(find_in_words, find_nodes);
-}
-
-// Filter `clusters` matching `query`. There are additional filters (e.g.
-// `max_time`) used when requesting `QueryClusters()`, but this function is only
-// responsible for matching `query`.
-void FilterClustersMatchingQuery(std::string query,
- std::vector<history::Cluster>* clusters) {
- DCHECK(clusters);
- if (query.empty()) {
- // For the empty-query state, only show clusters with
- // `should_show_on_prominent_ui_surfaces` set to true. This restriction is
- // NOT applied when the user is searching for a specific keyword.
- clusters->erase(base::ranges::remove_if(
- *clusters,
- [](const history::Cluster& cluster) {
- return !cluster.should_show_on_prominent_ui_surfaces;
- }),
- clusters->end());
- return;
- }
-
- // Extract query nodes from the query string.
- query_parser::QueryNodeVector find_nodes;
- query_parser::QueryParser::ParseQueryNodes(
- base::UTF8ToUTF16(query),
- query_parser::MatchingAlgorithm::ALWAYS_PREFIX_SEARCH, &find_nodes);
-
- clusters->erase(base::ranges::remove_if(
- *clusters,
- [&find_nodes](const history::Cluster& cluster) {
- return !DoesQueryMatchCluster(find_nodes, cluster);
- }),
- clusters->end());
-}
-
-// Enforces the reverse-chronological invariant of clusters, as well the
-// by-score sorting of visits within clusters.
-void SortClusters(std::vector<Cluster>* clusters) {
- DCHECK(clusters);
- // Within each cluster, sort visits from best to worst using score.
- // TODO(tommycli): Once cluster persistence is done, maybe we can eliminate
- // this sort step, if they are stored in-order.
- for (auto& cluster : *clusters) {
- base::ranges::sort(cluster.visits, [](auto& v1, auto& v2) {
- if (v1.score != v2.score) {
- // Use v1 > v2 to get higher scored visits BEFORE lower scored visits.
- return v1.score > v2.score;
- }
-
- // Use v1 > v2 to get more recent visits BEFORE older visits.
- return v1.annotated_visit.visit_row.visit_time >
- v2.annotated_visit.visit_row.visit_time;
- });
- }
-
- // After that, sort clusters reverse-chronologically based on their highest
- // scored visit.
- base::ranges::sort(*clusters, [&](auto& c1, auto& c2) {
- // TODO(tommycli): If we can establish an invariant that no backend will
- // ever return an empty cluster, we can simplify the below code.
- base::Time c1_time;
- if (!c1.visits.empty()) {
- c1_time = c1.visits.front().annotated_visit.visit_row.visit_time;
- }
- base::Time c2_time;
- if (!c1.visits.empty()) {
- c2_time = c2.visits.front().annotated_visit.visit_row.visit_time;
- }
-
- // Use c1 > c2 to get more recent clusters BEFORE older clusters.
- return c1_time > c2_time;
- });
-}
-
// Gets a loggable JSON representation of `visits`.
std::string GetDebugJSONForVisits(
const std::vector<history::AnnotatedVisit>& visits) {
@@ -237,8 +124,9 @@ std::string GetDebugJSONForClusters(
debug_visit.SetKey("entities", std::move(debug_entities));
base::ListValue debug_duplicate_visits;
- for (const auto duplicate_visit : visit.duplicate_visit_ids) {
- debug_duplicate_visits.Append(int(duplicate_visit));
+ for (const auto& duplicate_visit : visit.duplicate_visits) {
+ debug_duplicate_visits.Append(static_cast<int>(
+ duplicate_visit.annotated_visit.visit_row.visit_id));
}
debug_visit.SetKey("duplicate_visits", std::move(debug_duplicate_visits));
@@ -258,8 +146,21 @@ std::string GetDebugJSONForClusters(
return debug_string;
}
-// TODO(tommycli): Explicitly link this number to what's in WebUI.
-constexpr int kMaxCountForKeywordCacheBatch = 10;
+std::string GetDebugJSONForKeywordSet(
+ const HistoryClustersService::KeywordSet& keyword_set) {
+ std::vector<base::Value> keyword_list;
+ for (const auto& keyword : keyword_set) {
+ keyword_list.emplace_back(keyword);
+ }
+
+ std::string debug_string;
+ if (!base::JSONWriter::WriteWithOptions(
+ base::Value(keyword_list), base::JSONWriter::OPTIONS_PRETTY_PRINT,
+ &debug_string)) {
+ debug_string = "Error: Could not write keywords list to JSON.";
+ }
+ return debug_string;
+}
} // namespace
@@ -291,9 +192,7 @@ HistoryClustersService::HistoryClustersService(
: is_journeys_enabled_(
::history_clusters::IsJourneysEnabled(application_locale)),
history_service_(history_service),
- visit_deletion_observer_(this),
- post_processing_task_runner_(base::ThreadPool::CreateSequencedTaskRunner(
- {base::MayBlock(), base::TaskPriority::USER_VISIBLE})) {
+ visit_deletion_observer_(this) {
DCHECK(history_service_);
visit_deletion_observer_.AttachToHistoryService(history_service);
@@ -307,6 +206,10 @@ HistoryClustersService::HistoryClustersService(
HistoryClustersService::~HistoryClustersService() = default;
+base::WeakPtr<HistoryClustersService> HistoryClustersService::GetWeakPtr() {
+ return weak_ptr_factory_.GetWeakPtr();
+}
+
void HistoryClustersService::Shutdown() {}
void HistoryClustersService::AddObserver(Observer* obs) {
@@ -367,50 +270,35 @@ void HistoryClustersService::CompleteVisitContextAnnotationsIfReady(
}
void HistoryClustersService::QueryClusters(
- const std::string& query,
+ ClusteringRequestSource clustering_request_source,
base::Time begin_time,
base::Time end_time,
- const size_t max_count,
QueryClustersCallback callback,
base::CancelableTaskTracker* task_tracker) {
NotifyDebugMessage("HistoryClustersService::QueryClusters()");
+ NotifyDebugMessage(
+ " begin_time = " +
+ (begin_time.is_null() ? "null" : base::TimeToISO8601(begin_time)));
NotifyDebugMessage(" end_time = " + (end_time.is_null()
? "null"
: base::TimeToISO8601(end_time)));
- NotifyDebugMessage(" max_count = " + base::NumberToString(max_count));
if (!backend_) {
NotifyDebugMessage(
"HistoryClustersService::QueryClusters Error: ClusteringBackend is "
"nullptr. Returning empty cluster vector.");
- std::move(callback).Run({});
+ std::move(callback).Run({}, base::Time());
return;
}
DCHECK(history_service_);
-
- size_t max_visit_count = kMaxVisitsToCluster.Get();
- if (max_count > 0) {
- // As a primitive heuristic, fetch 3x the amount of visits as requested
- // clusters. We don't know in advance how big the clusters will be.
- max_visit_count = max_count * 3;
- }
-
- NotifyDebugMessage("Starting History Query:");
- NotifyDebugMessage(" end_time = " + (end_time.is_null()
- ? "null"
- : base::TimeToISO8601(end_time)));
- NotifyDebugMessage(base::StringPrintf(" max_count = %zu", max_count));
-
- // TODO(crbug/1243049) : Add timing metrics for the history service DB query.
history_service_->ScheduleDBTask(
FROM_HERE,
std::make_unique<GetAnnotatedVisitsToCluster>(
incomplete_visit_context_annotations_, begin_time, end_time,
- max_visit_count,
base::BindOnce(&HistoryClustersService::OnGotHistoryVisits,
- weak_ptr_factory_.GetWeakPtr(), query,
- std::move(callback))),
+ weak_ptr_factory_.GetWeakPtr(),
+ clustering_request_source, std::move(callback))),
task_tracker);
}
@@ -444,28 +332,17 @@ bool HistoryClustersService::DoesQueryMatchAnyCluster(
// (The cache_query_task_tracker_ should also do this.)
all_keywords_cache_timestamp_ = base::Time::Now();
- // Query for 30 days of clusters since older visits won't have keywords.
- const auto begin_time = base::Time::Now() - base::Days(30);
- // TODO(tommycli): This `QueryClusters()` correctly returns only clusters
- // with `should_show_on_prominent_ui_surfaces` set to true because the
- // `query` parameter is set to empty. However, it would be nice if this
- // was more explicit, rather than just a happy coincidence. Likely the real
- // solution will be to explicitly ask the backend for this bag of keywords.
+ NotifyDebugMessage("Starting all_keywords_cache_ generation.");
QueryClusters(
- /*query=*/"", begin_time, /*end_time=*/
- base::Time(), kMaxCountForKeywordCacheBatch,
+ ClusteringRequestSource::kKeywordCacheGeneration,
+ /*begin_time=*/base::Time(),
+ /*end_time=*/base::Time(),
base::BindOnce(&HistoryClustersService::PopulateClusterKeywordCache,
- weak_ptr_factory_.GetWeakPtr(), begin_time,
+ weak_ptr_factory_.GetWeakPtr(),
+ /*begin_time=*/base::Time(),
std::make_unique<std::vector<std::u16string>>(),
&all_keywords_cache_),
&cache_query_task_tracker_);
-
- // Once `all_keywords_cache_` has been updated, we could clear
- // `short_keyword_cache_` as its keywords will be contained in
- // `all_keywords_cache_`. However, since `all_keywords_cache_` is updated
- // asynchronously, we don't clear `short_keyword_cache_` to avoid
- // introducing another layer of callbacks.
-
} else if (!cache_query_task_tracker_.HasTrackedTasks() &&
(base::Time::Now() - all_keywords_cache_timestamp_).InSeconds() >
10 &&
@@ -474,10 +351,10 @@ bool HistoryClustersService::DoesQueryMatchAnyCluster(
// Update the timestamp right away, to prevent this from running again.
short_keyword_cache_timestamp_ = base::Time::Now();
+ NotifyDebugMessage("Starting short_keywords_cache_ generation.");
QueryClusters(
- /*query=*/"",
- /*begin_time=*/all_keywords_cache_timestamp_, /*end_time=*/
- base::Time(), kMaxCountForKeywordCacheBatch,
+ ClusteringRequestSource::kKeywordCacheGeneration,
+ /*begin_time=*/all_keywords_cache_timestamp_, /*end_time=*/base::Time(),
base::BindOnce(&HistoryClustersService::PopulateClusterKeywordCache,
weak_ptr_factory_.GetWeakPtr(),
all_keywords_cache_timestamp_,
@@ -497,67 +374,6 @@ bool HistoryClustersService::DoesQueryMatchAnyCluster(
all_keywords_cache_.contains(query_lower);
}
-// static
-std::vector<Cluster> HistoryClustersService::CollapseDuplicateVisits(
- const std::vector<history::Cluster>& raw_clusters) {
- std::vector<Cluster> result_clusters;
- for (const auto& raw_cluster : raw_clusters) {
- Cluster cluster;
- cluster.cluster_id = raw_cluster.cluster_id;
- cluster.keywords = raw_cluster.keywords;
-
- // First stash all visits within the cluster in a id-keyed map.
- base::flat_map<int64_t, Visit> visits_map;
- visits_map.reserve(raw_cluster.visits.size());
- for (const auto& raw_visit : raw_cluster.visits) {
- Visit visit;
- visit.annotated_visit = raw_visit.annotated_visit;
- visit.normalized_url = raw_visit.normalized_url;
- visit.score = raw_visit.score;
-
- visits_map[visit.annotated_visit.visit_row.visit_id] = std::move(visit);
- }
-
- // Now do the actual un-flattening in a second loop.
- for (const auto& raw_visit : raw_cluster.visits) {
- int64_t visit_id = raw_visit.annotated_visit.visit_row.visit_id;
-
- // For every duplicate marked in the original raw visit, find the visit
- // in the id-keyed map, move it to the canonical visit's vector, and
- // erase it from the map.
- for (auto& duplicate_id : raw_visit.duplicate_visit_ids) {
- auto duplicate_visit = visits_map.find(duplicate_id);
- if (duplicate_visit == visits_map.end()) {
- NOTREACHED() << "Visit has missing duplicate ID.";
- continue;
- }
-
- // Move the duplicate visit into the vector of the canonical visit.
- DCHECK(duplicate_visit->second.duplicate_visits.empty())
- << "Duplicates shouldn't themselves have duplicates. "
- "If they do, the output is undefined.";
- auto& canonical_visit = visits_map[visit_id];
- canonical_visit.duplicate_visits.push_back(
- std::move(duplicate_visit->second));
-
- // Remove the duplicate from the map.
- visits_map.erase(duplicate_visit);
- }
- }
-
- // Now move all our surviving visits, which should all be canonical visits,
- // to the final cluster.
- for (auto& visit_pair : visits_map) {
- cluster.visits.push_back(std::move(visit_pair.second));
- }
-
- result_clusters.push_back(std::move(cluster));
- }
-
- DCHECK_EQ(result_clusters.size(), raw_clusters.size());
- return result_clusters;
-}
-
void HistoryClustersService::ClearKeywordCache() {
all_keywords_cache_timestamp_ = base::Time();
short_keyword_cache_timestamp_ = base::Time();
@@ -570,11 +386,17 @@ void HistoryClustersService::PopulateClusterKeywordCache(
base::Time begin_time,
std::unique_ptr<std::vector<std::u16string>> keyword_accumulator,
KeywordSet* cache,
- QueryClustersResult result) {
+ std::vector<history::Cluster> clusters,
+ base::Time continuation_end_time) {
const size_t max_keyword_phrases = kMaxKeywordPhrases.Get();
// Copy keywords from every cluster into a the accumulator set.
- for (auto& cluster : result.clusters) {
+ for (auto& cluster : clusters) {
+ if (!cluster.should_show_on_prominent_ui_surfaces) {
+ // `clusters` doesn't have any post-processing, so we need to skip
+ // sensitive clusters here.
+ continue;
+ }
if (cluster.visits.size() < 2) {
// Only accept keywords from clusters with at least two visits. This is a
// simple first-pass technique to avoid overtriggering the omnibox action.
@@ -602,12 +424,12 @@ void HistoryClustersService::PopulateClusterKeywordCache(
// Make a continuation request to get the next page of clusters and their
// keywords only if both 1) there is more clusters remaining, and 2) we
// haven't reached the soft cap `max_keyword_phrases` (or there is no cap).
- if (result.continuation_end_time &&
+ if (!continuation_end_time.is_null() &&
(max_keyword_phrases == 0 ||
keyword_accumulator->size() < max_keyword_phrases)) {
QueryClusters(
- /*query=*/"", begin_time, *result.continuation_end_time,
- kMaxCountForKeywordCacheBatch,
+ ClusteringRequestSource::kKeywordCacheGeneration, begin_time,
+ continuation_end_time,
base::BindOnce(&HistoryClustersService::PopulateClusterKeywordCache,
weak_ptr_factory_.GetWeakPtr(), begin_time,
// Pass on the accumulator set to the next callback.
@@ -620,6 +442,8 @@ void HistoryClustersService::PopulateClusterKeywordCache(
// via the constructor for efficiency (as recommended by the flat_set docs).
// De-duplication is handled by the flat_set itself.
*cache = KeywordSet(*keyword_accumulator);
+ NotifyDebugMessage("Cache construction complete:");
+ NotifyDebugMessage(GetDebugJSONForKeywordSet(*cache));
// Record keyword phrase & keyword counts for the appropriate cache.
if (cache == &all_keywords_cache_) {
@@ -640,7 +464,7 @@ void HistoryClustersService::PopulateClusterKeywordCache(
}
void HistoryClustersService::OnGotHistoryVisits(
- const std::string& query,
+ ClusteringRequestSource clustering_request_source,
QueryClustersCallback callback,
std::vector<history::AnnotatedVisit> annotated_visits,
base::Time continuation_end_time) const {
@@ -654,11 +478,7 @@ void HistoryClustersService::OnGotHistoryVisits(
if (annotated_visits.empty()) {
// Early exit without calling backend if there's no annotated visits.
- QueryClustersResult result;
- if (!continuation_end_time.is_null()) {
- result.continuation_end_time = continuation_end_time;
- }
- std::move(callback).Run(std::move(result));
+ std::move(callback).Run({}, continuation_end_time);
return;
}
@@ -670,82 +490,29 @@ void HistoryClustersService::OnGotHistoryVisits(
static_cast<int>(annotated_visits.size()));
backend_->GetClusters(
+ clustering_request_source,
base::BindOnce(&HistoryClustersService::OnGotRawClusters,
- weak_ptr_factory_.GetWeakPtr(), query,
- continuation_end_time, base::TimeTicks::Now(),
- std::move(callback)),
+ weak_ptr_factory_.GetWeakPtr(), continuation_end_time,
+ base::TimeTicks::Now(), std::move(callback)),
annotated_visits);
}
void HistoryClustersService::OnGotRawClusters(
- const std::string& query,
base::Time continuation_end_time,
base::TimeTicks cluster_start_time,
QueryClustersCallback callback,
std::vector<history::Cluster> clusters) const {
NotifyDebugMessage("HistoryClustersService::OnGotRawClusters()");
- int clusters_from_backend_count = clusters.size();
base::UmaHistogramTimes("History.Clusters.Backend.GetClustersLatency",
base::TimeTicks::Now() - cluster_start_time);
base::UmaHistogramCounts1000("History.Clusters.Backend.NumClustersReturned",
- clusters_from_backend_count);
+ clusters.size());
NotifyDebugMessage(" Raw Clusters from Backend JSON follows:");
NotifyDebugMessage(GetDebugJSONForClusters(clusters));
- // Post-process the clusters (expensive task) on an anonymous thread to
- // prevent janks.
- base::ElapsedTimer post_processing_timer; // Create here to time the task.
- post_processing_task_runner_->PostTaskAndReplyWithResult(
- FROM_HERE,
- base::BindOnce(&HistoryClustersService::PostProcessClusters, query,
- continuation_end_time, std::move(clusters)),
- base::BindOnce(&HistoryClustersService::OnProcessedClusters,
- weak_ptr_factory_.GetWeakPtr(),
- std::move(post_processing_timer),
- clusters_from_backend_count, std::move(callback)));
-}
-
-// static
-QueryClustersResult HistoryClustersService::PostProcessClusters(
- const std::string& query,
- base::Time continuation_end_time,
- std::vector<history::Cluster> raw_clusters) {
- QueryClustersResult result;
- if (!continuation_end_time.is_null()) {
- result.continuation_end_time = continuation_end_time;
- }
-
- FilterClustersMatchingQuery(query, &raw_clusters);
- result.clusters = CollapseDuplicateVisits(raw_clusters);
- SortClusters(&result.clusters);
-
- return result;
-}
-
-void HistoryClustersService::OnProcessedClusters(
- base::ElapsedTimer post_processing_timer,
- size_t clusters_from_backend_count,
- QueryClustersCallback callback,
- QueryClustersResult result) const {
- NotifyDebugMessage("HistoryClustersService::OnProcesedClusters()");
-
- base::TimeDelta clustering_duration = post_processing_timer.Elapsed();
- base::UmaHistogramLongTimes("History.Clusters.ProcessClustersDuration",
- clustering_duration);
-
- if (clusters_from_backend_count > 0) {
- // Log the percentage of clusters that get filtered (e.g., 100 - % of
- // clusters that remain).
- base::UmaHistogramCounts100(
- "History.Clusters.PercentClustersFilteredByQuery",
- static_cast<int>(100 - (result.clusters.size() /
- (1.0 * clusters_from_backend_count) * 100)));
- }
-
- NotifyDebugMessage(" Passing results back to original caller now.");
- std::move(callback).Run(std::move(result));
+ std::move(callback).Run(clusters, continuation_end_time);
}
} // namespace history_clusters
diff --git a/chromium/components/history_clusters/core/history_clusters_service.h b/chromium/components/history_clusters/core/history_clusters_service.h
index 0dc96da953b..69304b0656b 100644
--- a/chromium/components/history_clusters/core/history_clusters_service.h
+++ b/chromium/components/history_clusters/core/history_clusters_service.h
@@ -17,9 +17,7 @@
#include "base/observer_list.h"
#include "base/scoped_observation.h"
#include "base/task/cancelable_task_tracker.h"
-#include "base/task/sequenced_task_runner.h"
#include "base/time/time.h"
-#include "base/timer/elapsed_timer.h"
#include "components/history/core/browser/history_service.h"
#include "components/history/core/browser/history_service_observer.h"
#include "components/history/core/browser/history_types.h"
@@ -95,6 +93,10 @@ class HistoryClustersService : public KeyedService {
HistoryClustersService& operator=(const HistoryClustersService&) = delete;
~HistoryClustersService() override;
+ // Gets a weak pointer to this service. Used when UIs want to create a query
+ // state object whose lifetime might exceed the service.
+ base::WeakPtr<HistoryClustersService> GetWeakPtr();
+
// KeyedService:
void Shutdown() override;
@@ -129,8 +131,12 @@ class HistoryClustersService : public KeyedService {
// have been recorded. References retrieved prior will no longer be valid.
void CompleteVisitContextAnnotationsIfReady(int64_t nav_id);
+ // This is a low-level API that doesn't support querying by search terms or
+ // de-duplication across multiple batches. Any UI should almost certainly use
+ // `QueryClustersState` instead.
+ //
// Returns the freshest clusters created from the user visit history based on
- // `query`, `begin_time`, `end_time`, and `max_count`.
+ // `query`, `begin_time`, and `end_time`.
// - `begin_time` is an inclusive lower bound. In the general case where the
// caller wants to traverse to the start of history, `base::Time()` should
// be used.
@@ -139,10 +145,12 @@ class HistoryClustersService : public KeyedService {
// The returned clusters are sorted in reverse-chronological order based on
// their highest scoring visit. The visits within each cluster are sorted by
// score, from highest to lowest.
- void QueryClusters(const std::string& query,
+ //
+ // TODO(tommycli): Investigate entirely hiding access to this low-level method
+ // behind QueryClustersState.
+ void QueryClusters(ClusteringRequestSource clustering_request_source,
base::Time begin_time,
base::Time end_time,
- size_t max_count,
QueryClustersCallback callback,
base::CancelableTaskTracker* task_tracker);
@@ -159,12 +167,6 @@ class HistoryClustersService : public KeyedService {
// keystroke, the cache may be ready and return true then.
bool DoesQueryMatchAnyCluster(const std::string& query);
- // Converts the vector of history::Cluster types to history_clusters::Cluster
- // by collapsing all the duplicate visits into the canonical visits, thereby
- // "unflattening" the output of the backend. Public for testing purposes.
- static std::vector<Cluster> CollapseDuplicateVisits(
- const std::vector<history::Cluster>& raw_clusters);
-
// Clears `all_keywords_cache_` and cancels any pending tasks to populate it.
void ClearKeywordCache();
@@ -179,33 +181,21 @@ class HistoryClustersService : public KeyedService {
base::Time begin_time,
std::unique_ptr<std::vector<std::u16string>> keyword_accumulator,
KeywordSet* cache,
- QueryClustersResult result);
+ std::vector<history::Cluster> clusters,
+ base::Time continuation_end_time);
// Internally used callback for `QueryClusters()`.
- void OnGotHistoryVisits(const std::string& query,
+ void OnGotHistoryVisits(ClusteringRequestSource clustering_request_source,
QueryClustersCallback callback,
std::vector<history::AnnotatedVisit> annotated_visits,
base::Time continuation_end_time) const;
// Runs on UI thread. Internally used callback for `OnGotHistoryVisits()`.
- void OnGotRawClusters(const std::string& query,
- base::Time continuation_end_time,
+ void OnGotRawClusters(base::Time continuation_end_time,
base::TimeTicks cluster_start_time,
QueryClustersCallback callback,
std::vector<history::Cluster> clusters) const;
- // Runs on `post_processing_task_runner_`, posted by `OnGotRawClusters()`.
- static QueryClustersResult PostProcessClusters(
- const std::string& query,
- base::Time continuation_end_time,
- std::vector<history::Cluster> clusters);
-
- // Runs on UI thread. Used as the 'reply' part from `PostProcessClusters()`.
- void OnProcessedClusters(base::ElapsedTimer post_processing_timer,
- size_t clusters_from_backend_count,
- QueryClustersCallback callback,
- QueryClustersResult result) const;
-
// True if the Journeys feature is enabled for the application locale.
const bool is_journeys_enabled_;
@@ -247,9 +237,6 @@ class HistoryClustersService : public KeyedService {
VisitDeletionObserver visit_deletion_observer_;
- // A task runner to run all the post-processing tasks on.
- scoped_refptr<base::SequencedTaskRunner> post_processing_task_runner_;
-
// Weak pointers issued from this factory never get invalidated before the
// service is destroyed.
base::WeakPtrFactory<HistoryClustersService> weak_ptr_factory_{this};
diff --git a/chromium/components/history_clusters/core/history_clusters_service_test_api.cc b/chromium/components/history_clusters/core/history_clusters_service_test_api.cc
index 749ad4f7bab..bd110fd8fc6 100644
--- a/chromium/components/history_clusters/core/history_clusters_service_test_api.cc
+++ b/chromium/components/history_clusters/core/history_clusters_service_test_api.cc
@@ -6,6 +6,7 @@
#include "base/time/time.h"
#include "components/history/core/browser/history_types.h"
+#include "components/history_clusters/core/history_clusters_util.h"
namespace history_clusters {
@@ -82,4 +83,23 @@ std::vector<history::AnnotatedVisit> GetHardcodedTestVisits() {
return visits;
}
+history::ClusterVisit GetHardcodedClusterVisit(history::VisitID visit_id) {
+ const auto& visits = GetHardcodedTestVisits();
+ for (const auto& visit : visits) {
+ if (visit.visit_row.visit_id != visit_id)
+ continue;
+
+ history::ClusterVisit cluster_visit;
+ cluster_visit.annotated_visit = visit;
+ cluster_visit.normalized_url = visit.url_row.url();
+ cluster_visit.url_for_deduping =
+ ComputeURLForDeduping(cluster_visit.normalized_url);
+ cluster_visit.score = 0.5;
+ return cluster_visit;
+ }
+
+ NOTREACHED();
+ return history::ClusterVisit();
+}
+
} // namespace history_clusters
diff --git a/chromium/components/history_clusters/core/history_clusters_service_test_api.h b/chromium/components/history_clusters/core/history_clusters_service_test_api.h
index 4209c680c80..8a4f0c78d6a 100644
--- a/chromium/components/history_clusters/core/history_clusters_service_test_api.h
+++ b/chromium/components/history_clusters/core/history_clusters_service_test_api.h
@@ -58,13 +58,6 @@ class HistoryClustersServiceTestApi {
history_clusters_service_->short_keyword_cache_timestamp_ = time;
}
- void FlushPostProcessingTaskRunner() {
- base::RunLoop loop;
- history_clusters_service_->post_processing_task_runner_->PostTask(
- FROM_HERE, loop.QuitClosure());
- loop.Run();
- }
-
HistoryClustersService* const history_clusters_service_;
history::HistoryService* const history_service_;
};
@@ -72,6 +65,9 @@ class HistoryClustersServiceTestApi {
// Fetches two hardcoded test visits.
std::vector<history::AnnotatedVisit> GetHardcodedTestVisits();
+// Fetches the hardcoded `ClusterVisit` with ID `visit_id`.
+history::ClusterVisit GetHardcodedClusterVisit(history::VisitID visit_id);
+
} // namespace history_clusters
#endif // COMPONENTS_HISTORY_CLUSTERS_CORE_HISTORY_CLUSTERS_SERVICE_TEST_API_H_
diff --git a/chromium/components/history_clusters/core/history_clusters_service_unittest.cc b/chromium/components/history_clusters/core/history_clusters_service_unittest.cc
index c41871e1a85..e69082be652 100644
--- a/chromium/components/history_clusters/core/history_clusters_service_unittest.cc
+++ b/chromium/components/history_clusters/core/history_clusters_service_unittest.cc
@@ -39,6 +39,7 @@ namespace {
class TestClusteringBackend : public ClusteringBackend {
public:
void GetClusters(
+ ClusteringRequestSource clustering_request_source,
ClustersCallback callback,
const std::vector<history::AnnotatedVisit>& visits) override {
callback_ = std::move(callback);
@@ -177,15 +178,13 @@ class HistoryClustersServiceTestBase : public testing::Test {
}
// Verifies that the hardcoded visits were passed to the clustering backend.
- void AwaitAndVerifyTestClusteringBackendRequest(bool for_keywords = false) {
+ void AwaitAndVerifyTestClusteringBackendRequest() {
test_clustering_backend_->WaitForGetClustersCall();
std::vector<history::AnnotatedVisit> visits =
test_clustering_backend_->LastClusteredVisits();
- // Keyword requests should not fetch visits older than 30 days; cluster
- // requests should fetch all visits.
- ASSERT_EQ(visits.size(), for_keywords ? 2u : 3u);
+ ASSERT_EQ(visits.size(), 3u);
auto& visit = visits[0];
EXPECT_EQ(visit.visit_row.visit_id, 2);
@@ -203,10 +202,8 @@ class HistoryClustersServiceTestBase : public testing::Test {
EXPECT_EQ(visit.url_row.url(), "https://google.com/");
EXPECT_EQ(visit.context_annotations.page_end_reason, 3);
- if (!for_keywords) {
- visit = visits[2];
- EXPECT_EQ(visit.visit_row.visit_id, 4);
- }
+ visit = visits[2];
+ EXPECT_EQ(visit.visit_row.visit_id, 4);
// TODO(tommycli): Add back visit.referring_visit_id() check after updating
// the HistoryService test methods to support that field.
@@ -247,171 +244,6 @@ class HistoryClustersServiceTest : public HistoryClustersServiceTestBase {
}
};
-TEST_F(HistoryClustersServiceTest, ClusterAndVisitSorting) {
- base::HistogramTester histogram_tester;
- AddHardcodedTestDataToHistoryService();
-
- history_clusters_service_->QueryClusters(
- /*query=*/"", /*begin_time=*/base::Time(), /*end_time=*/base::Time(),
- /* max_count=*/0,
- // This "expect" block is not run until after the fake response is sent
- // further down in this method.
- base::BindLambdaForTesting([&](QueryClustersResult result) {
- auto& clusters = result.clusters;
- ASSERT_EQ(clusters.size(), 2u);
-
- auto& visits = clusters[0].visits;
- ASSERT_EQ(visits.size(), 1u);
- EXPECT_EQ(visits[0].annotated_visit.url_row.url(),
- "https://github.com/");
- EXPECT_FLOAT_EQ(visits[0].score, 0.1);
-
- visits = clusters[1].visits;
- ASSERT_EQ(visits.size(), 2u);
- EXPECT_EQ(visits[0].annotated_visit.url_row.url(),
- "https://google.com/");
- EXPECT_FLOAT_EQ(visits[0].score, 0.9);
- EXPECT_EQ(visits[1].annotated_visit.url_row.url(),
- "https://github.com/");
- EXPECT_FLOAT_EQ(visits[1].score, 0.5);
-
- run_loop_quit_.Run();
- }),
- &task_tracker_);
-
- AwaitAndVerifyTestClusteringBackendRequest();
-
- std::vector<history::Cluster> clusters;
- // This first cluster is meant to validate that the higher scoring "visit 1"
- // gets sorted to the top, even though "visit 1" is older in the hardcoded
- // test data. It's to validate the within-cluster sorting.
- clusters.push_back(
- history::Cluster(0,
- {
- test_clustering_backend_->GetVisitById(2, 0.5),
- test_clustering_backend_->GetVisitById(1, 0.9),
- },
- {}));
- clusters.push_back(
- history::Cluster(0,
- {
- test_clustering_backend_->GetVisitById(2, 0.1),
- },
- {}));
- test_clustering_backend_->FulfillCallback(clusters);
-
- // Verify the callback is invoked.
- run_loop_.Run();
-
- history::BlockUntilHistoryProcessesPendingRequests(history_service_.get());
- histogram_tester.ExpectUniqueSample(
- "History.Clusters.Backend.NumClustersReturned",
- static_cast<int>(clusters.size()), 1);
- histogram_tester.ExpectUniqueSample(
- "History.Clusters.Backend.NumVisitsToCluster", 3, 1);
- histogram_tester.ExpectUniqueSample(
- "History.Clusters.PercentClustersFilteredByQuery", 0, 1);
- histogram_tester.ExpectTotalCount(
- "History.Clusters.Backend.GetClustersLatency", 1);
-}
-
-TEST_F(HistoryClustersServiceTest, UnflattenDuplicatesIntegrationTest) {
- AddHardcodedTestDataToHistoryService();
-
- history_clusters_service_->QueryClusters(
- /*query=*/"", /*begin_time=*/base::Time(), /*end_time=*/base::Time(),
- /* max_count=*/0,
- // This "expect" block is not run until after the fake response is sent
- // further down in this method.
- base::BindLambdaForTesting([&](QueryClustersResult result) {
- auto& clusters = result.clusters;
- ASSERT_EQ(clusters.size(), 1u);
-
- auto& visits = clusters[0].visits;
- ASSERT_EQ(visits.size(), 1u);
- EXPECT_EQ(visits[0].annotated_visit.url_row.url(),
- "https://google.com/");
- EXPECT_EQ(visits[0].normalized_url.spec(), "https://google.com/");
- EXPECT_FLOAT_EQ(visits[0].score, 0.9);
-
- ASSERT_EQ(visits[0].duplicate_visits.size(), 1u);
- EXPECT_EQ(visits[0].duplicate_visits[0].annotated_visit.url_row.url(),
- "https://github.com/");
- EXPECT_EQ(visits[0].duplicate_visits[0].normalized_url.spec(),
- "https://github.com/");
- EXPECT_FLOAT_EQ(visits[0].duplicate_visits[0].score, 0.5);
-
- run_loop_quit_.Run();
- }),
- &task_tracker_);
-
- AwaitAndVerifyTestClusteringBackendRequest();
-
- std::vector<history::ClusterVisit> visits = {
- test_clustering_backend_->GetVisitById(2, 0.5),
- test_clustering_backend_->GetVisitById(1, 0.9),
- };
- visits[1].duplicate_visit_ids = {2};
-
- std::vector<history::Cluster> clusters;
- clusters.push_back(history::Cluster(0, visits, {}));
- test_clustering_backend_->FulfillCallback(clusters);
-
- // Verify the callback is invoked.
- run_loop_.Run();
-
- history::BlockUntilHistoryProcessesPendingRequests(history_service_.get());
-}
-
-TEST_F(HistoryClustersServiceTest, UnflattenDuplicatesUnitTest) {
- // This tests the unflatten-duplicates method in more detail as a unit test.
- history::Cluster raw_cluster;
- auto& raw_visits = raw_cluster.visits;
-
- // Add ten visits, numbered from 1 to 8. (1-based, just like History.)
- for (size_t i = 0; i < 8; ++i) {
- raw_visits.emplace_back();
- raw_visits[i].annotated_visit.visit_row.visit_id = i + 1;
- }
-
- // Collapse 1, 2, 3 into visit 4. Visits 1 and 2 have related searches.
- // Visit 3 had omnibox_url_copied == true.
- ASSERT_EQ(raw_visits[3].annotated_visit.visit_row.visit_id, 4);
- raw_visits[3].duplicate_visit_ids = {1, 2, 3};
-
- // Collapse 7 into visit 6.
- ASSERT_EQ(raw_visits[5].annotated_visit.visit_row.visit_id, 6);
- raw_visits[5].duplicate_visit_ids = {7};
-
- // Canonical visits should be {4, {1,2,3}}, {5, {}}, {6, {7}}, {8, {}}.
- auto clusters =
- history_clusters_service_->CollapseDuplicateVisits({raw_cluster});
- ASSERT_EQ(clusters.size(), 1u);
- auto& visits = clusters[0].visits;
- ASSERT_EQ(visits.size(), 4u);
-
- // Visit 4 should have 1, 2, and 3 as duplicates.
- EXPECT_EQ(visits[0].annotated_visit.visit_row.visit_id, 4);
- ASSERT_EQ(visits[0].duplicate_visits.size(), 3u);
- EXPECT_EQ(visits[0].duplicate_visits[0].annotated_visit.visit_row.visit_id,
- 1);
- EXPECT_EQ(visits[0].duplicate_visits[1].annotated_visit.visit_row.visit_id,
- 2);
- EXPECT_EQ(visits[0].duplicate_visits[2].annotated_visit.visit_row.visit_id,
- 3);
-
- EXPECT_EQ(visits[1].annotated_visit.visit_row.visit_id, 5);
- ASSERT_EQ(visits[1].duplicate_visits.size(), 0u);
-
- EXPECT_EQ(visits[2].annotated_visit.visit_row.visit_id, 6);
- ASSERT_EQ(visits[2].duplicate_visits.size(), 1u);
- EXPECT_EQ(visits[2].duplicate_visits[0].annotated_visit.visit_row.visit_id,
- 7);
-
- EXPECT_EQ(visits[3].annotated_visit.visit_row.visit_id, 8);
- ASSERT_EQ(visits[3].duplicate_visits.size(), 0u);
-}
-
TEST_F(HistoryClustersServiceTest, HardCapOnVisitsFetchedFromHistory) {
base::test::ScopedFeatureList feature_list;
feature_list.InitAndEnableFeatureWithParameters(
@@ -452,8 +284,8 @@ TEST_F(HistoryClustersServiceTest, HardCapOnVisitsFetchedFromHistory) {
history::BlockUntilHistoryProcessesPendingRequests(history_service_.get());
history_clusters_service_->QueryClusters(
- /*query=*/"", /*begin_time=*/base::Time(), /*end_time=*/base::Time::Now(),
- /* max_count=*/0,
+ ClusteringRequestSource::kKeywordCacheGeneration,
+ /*begin_time=*/base::Time(), /*end_time=*/base::Time::Now(),
base::DoNothing(), // Only need to verify the correct request is sent.
&task_tracker_);
@@ -484,8 +316,8 @@ TEST_F(HistoryClustersServiceTest, QueryClustersIncompleteAndPersistedVisits) {
// a non-visible page transition.
history_clusters_service_->QueryClusters(
- /*query=*/"", /*begin_time=*/base::Time(), /*end_time=*/base::Time::Now(),
- /* max_count=*/0,
+ ClusteringRequestSource::kJourneysPage,
+ /*begin_time=*/base::Time(), /*end_time=*/base::Time::Now(),
base::DoNothing(), // Only need to verify the correct request is sent.
&task_tracker_);
@@ -504,61 +336,25 @@ TEST_F(HistoryClustersServiceTest, QueryClustersIncompleteAndPersistedVisits) {
EXPECT_EQ(visits[3].visit_row.visit_id, 5);
}
-TEST_F(HistoryClustersServiceTest, QueryClustersVariousQueries) {
+TEST_F(HistoryClustersServiceTest, EndToEndWithBackend) {
base::HistogramTester histogram_tester;
AddHardcodedTestDataToHistoryService();
- struct TestData {
- std::string query;
- const bool expect_first_cluster;
- const bool expect_second_cluster;
- } test_data[] = {
- // Empty query should get only the second, because the first is marked
- // hidden on prominent UI surfaces, including the zero query state.
- {"", false, true},
- // Non matching query should get none.
- {"non_matching_query", false, false},
- // Query matching one cluster.
- {"oran", true, false},
- // This verifies the memory doesn't flicker away as the user is typing
- // out: "red oran" one key at a time. Also tests out multi-term queries.
- {"red", true, false},
- {"red ", true, false},
- {"red o", true, false},
- {"red or", true, false},
- {"red ora", true, false},
- {"red oran", true, false},
- // Verify that we can search by URL.
- {"goog", true, false},
- // Verify we can search by page title, even mismatching case.
- {"code", true, true},
- // Verify that we match if the input query spans cluster keywords,
- // visit URLs, and visit titles.
- {"goog code apples", true, false},
- };
+ base::RunLoop run_loop;
+ auto run_loop_quit = run_loop.QuitClosure();
+
+ history_clusters_service_->QueryClusters(
+ ClusteringRequestSource::kJourneysPage,
+ /*begin_time=*/base::Time(),
+ /*end_time=*/base::Time(),
+ // This "expect" block is not run until after the fake response is sent
+ // further down in this method.
+ base::BindLambdaForTesting(
+ [&](std::vector<history::Cluster> clusters, base::Time) {
+ ASSERT_EQ(clusters.size(), 2U);
- for (size_t i = 0; i < base::size(test_data); ++i) {
- SCOPED_TRACE(base::StringPrintf("Testing case i=%d, query=%s", int(i),
- test_data[i].query.c_str()));
-
- base::RunLoop run_loop;
- auto run_loop_quit = run_loop.QuitClosure();
-
- history_clusters_service_->QueryClusters(
- test_data[i].query, /*begin_time=*/base::Time(),
- /*end_time=*/base::Time(),
- /* max_count=*/0,
- // This "expect" block is not run until after the fake response is sent
- // further down in this method.
- base::BindLambdaForTesting([&](QueryClustersResult result) {
- auto& clusters = result.clusters;
- size_t expected_size = int(test_data[i].expect_first_cluster) +
- int(test_data[i].expect_second_cluster);
- ASSERT_EQ(clusters.size(), expected_size);
-
- if (test_data[i].expect_first_cluster) {
- const auto& cluster = clusters[0];
- const auto& visits = cluster.visits;
+ auto& cluster = clusters[0];
+ auto& visits = cluster.visits;
ASSERT_EQ(visits.size(), 2u);
EXPECT_EQ(visits[0].annotated_visit.url_row.url(),
"https://github.com/");
@@ -589,12 +385,9 @@ TEST_F(HistoryClustersServiceTest, QueryClustersVariousQueries) {
ASSERT_EQ(cluster.keywords.size(), 2u);
EXPECT_EQ(cluster.keywords[0], u"apples");
EXPECT_EQ(cluster.keywords[1], u"Red Oranges");
- }
- if (test_data[i].expect_second_cluster) {
- const auto& cluster =
- test_data[i].expect_first_cluster ? clusters[1] : clusters[0];
- const auto& visits = cluster.visits;
+ cluster = clusters[1];
+ visits = cluster.visits;
ASSERT_EQ(visits.size(), 1u);
EXPECT_EQ(visits[0].annotated_visit.url_row.url(),
"https://github.com/");
@@ -603,53 +396,41 @@ TEST_F(HistoryClustersServiceTest, QueryClustersVariousQueries) {
EXPECT_EQ(visits[0].annotated_visit.url_row.title(),
u"Code Storage Title");
EXPECT_TRUE(cluster.keywords.empty());
- }
-
- run_loop_quit.Run();
- }),
- &task_tracker_);
-
- AwaitAndVerifyTestClusteringBackendRequest();
-
- std::vector<history::Cluster> clusters;
- // This first cluster with keywords is marked hidden on sensitive UI
- // surfaces. This test thus verifies that it's hidden in the zero-query
- // state, but the user can still get to it by searching for its keywords.
- clusters.push_back(
- history::Cluster(0,
- {
- test_clustering_backend_->GetVisitById(1),
- test_clustering_backend_->GetVisitById(2),
- },
- {u"apples", u"Red Oranges"},
- /*should_show_on_prominent_ui_surfaces=*/false));
- clusters.push_back(
- history::Cluster(0,
- {
- test_clustering_backend_->GetVisitById(2),
- },
- {},
- /*should_show_on_prominent_ui_surfaces=*/true));
- test_clustering_backend_->FulfillCallback(clusters);
-
- // Verify the callback is invoked.
- run_loop.Run();
- }
+
+ run_loop_quit.Run();
+ }),
+ &task_tracker_);
+
+ AwaitAndVerifyTestClusteringBackendRequest();
+
+ std::vector<history::Cluster> clusters;
+ clusters.push_back(
+ history::Cluster(0,
+ {
+ test_clustering_backend_->GetVisitById(2),
+ test_clustering_backend_->GetVisitById(1),
+ },
+ {u"apples", u"Red Oranges"},
+ /*should_show_on_prominent_ui_surfaces=*/true));
+ clusters.push_back(
+ history::Cluster(0,
+ {
+ test_clustering_backend_->GetVisitById(2),
+ },
+ {},
+ /*should_show_on_prominent_ui_surfaces=*/true));
+ test_clustering_backend_->FulfillCallback(clusters);
+
+ // Verify the callback is invoked.
+ run_loop.Run();
history::BlockUntilHistoryProcessesPendingRequests(history_service_.get());
histogram_tester.ExpectBucketCount(
- "History.Clusters.Backend.NumClustersReturned", 2, base::size(test_data));
- histogram_tester.ExpectBucketCount(
- "History.Clusters.Backend.NumVisitsToCluster", 3, base::size(test_data));
+ "History.Clusters.Backend.NumClustersReturned", 2, 1);
histogram_tester.ExpectBucketCount(
- "History.Clusters.PercentClustersFilteredByQuery", 0, 1);
- histogram_tester.ExpectBucketCount(
- "History.Clusters.PercentClustersFilteredByQuery", 100, 1);
- histogram_tester.ExpectBucketCount(
- "History.Clusters.PercentClustersFilteredByQuery", 50,
- base::size(test_data) - 2);
+ "History.Clusters.Backend.NumVisitsToCluster", 3, 1);
histogram_tester.ExpectTotalCount(
- "History.Clusters.Backend.GetClustersLatency", base::size(test_data));
+ "History.Clusters.Backend.GetClustersLatency", 1);
}
TEST_F(HistoryClustersServiceTest, CompleteVisitContextAnnotationsIfReady) {
@@ -789,9 +570,8 @@ TEST_F(HistoryClustersServiceTest, DoesQueryMatchAnyCluster) {
EXPECT_FALSE(history_clusters_service_->DoesQueryMatchAnyCluster("apples"));
// Providing the response and running the task loop should populate the cache.
- // This will also verify that visits older than 30 days are not included for
- // keyword requests.
- AwaitAndVerifyTestClusteringBackendRequest(true);
+ // This also verifies that visits older than 30 days are also included.
+ AwaitAndVerifyTestClusteringBackendRequest();
std::vector<history::Cluster> clusters;
clusters.push_back(
@@ -818,7 +598,7 @@ TEST_F(HistoryClustersServiceTest, DoesQueryMatchAnyCluster) {
{u"singlevisit"},
/*should_show_on_prominent_ui_surfaces=*/true));
test_clustering_backend_->FulfillCallback(clusters);
- history_clusters_service_test_api_->FlushPostProcessingTaskRunner();
+ history::BlockUntilHistoryProcessesPendingRequests(history_service_.get());
// Now the exact query should match the populated cache.
EXPECT_TRUE(history_clusters_service_->DoesQueryMatchAnyCluster("apples"));
@@ -863,9 +643,8 @@ TEST_F(HistoryClustersServiceTest, DoesQueryMatchAnyCluster) {
// The keyword cache should be repopulated.
test_clustering_backend_->WaitForGetClustersCall();
test_clustering_backend_->FulfillCallback(clusters);
- history_clusters_service_test_api_->FlushPostProcessingTaskRunner();
- EXPECT_TRUE(history_clusters_service_->DoesQueryMatchAnyCluster("apples"));
history::BlockUntilHistoryProcessesPendingRequests(history_service_.get());
+ EXPECT_TRUE(history_clusters_service_->DoesQueryMatchAnyCluster("apples"));
}
TEST_F(HistoryClustersServiceTest, DoesQueryMatchAnyClusterSecondaryCache) {
@@ -907,10 +686,8 @@ TEST_F(HistoryClustersServiceTest, DoesQueryMatchAnyClusterSecondaryCache) {
{u"peach", u""},
/*should_show_on_prominent_ui_surfaces=*/true));
test_clustering_backend_->FulfillCallback(clusters2);
- history_clusters_service_test_api_->FlushPostProcessingTaskRunner();
- EXPECT_TRUE(history_clusters_service_->DoesQueryMatchAnyCluster("peach"));
-
history::BlockUntilHistoryProcessesPendingRequests(history_service_.get());
+ EXPECT_TRUE(history_clusters_service_->DoesQueryMatchAnyCluster("peach"));
}
class HistoryClustersServiceMaxKeywordsTest
@@ -987,7 +764,7 @@ TEST_F(HistoryClustersServiceMaxKeywordsTest,
{u"eight"},
/*should_show_on_prominent_ui_surfaces=*/true));
test_clustering_backend_->FulfillCallback(clusters);
- history_clusters_service_test_api_->FlushPostProcessingTaskRunner();
+ history::BlockUntilHistoryProcessesPendingRequests(history_service_.get());
// The 1st cluster's phrases should always be cached.
EXPECT_TRUE(history_clusters_service_->DoesQueryMatchAnyCluster("one"));
diff --git a/chromium/components/history_clusters/core/history_clusters_types.cc b/chromium/components/history_clusters/core/history_clusters_types.cc
deleted file mode 100644
index fadf1181e29..00000000000
--- a/chromium/components/history_clusters/core/history_clusters_types.cc
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2021 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.
-
-#include "components/history_clusters/core/history_clusters_types.h"
-
-namespace history_clusters {
-
-Visit::Visit() = default;
-Visit::~Visit() = default;
-Visit::Visit(const Visit&) = default;
-
-Cluster::Cluster() = default;
-Cluster::~Cluster() = default;
-Cluster::Cluster(const Cluster&) = default;
-
-QueryClustersResult::QueryClustersResult() = default;
-QueryClustersResult::~QueryClustersResult() = default;
-QueryClustersResult::QueryClustersResult(const QueryClustersResult&) = default;
-
-} // namespace history_clusters
diff --git a/chromium/components/history_clusters/core/history_clusters_types.h b/chromium/components/history_clusters/core/history_clusters_types.h
index bcc0bcb0b9e..e164bee30c7 100644
--- a/chromium/components/history_clusters/core/history_clusters_types.h
+++ b/chromium/components/history_clusters/core/history_clusters_types.h
@@ -14,62 +14,11 @@
namespace history_clusters {
-// Differs from history::ClusterVisit in that the duplicate visits are
-// collapsed inline with the metadata subsumed into the canonical visit.
-struct Visit {
- Visit();
- ~Visit();
- Visit(const Visit&);
-
- history::AnnotatedVisit annotated_visit;
-
- // A floating point score in the range [0, 1] describing how important this
- // visit is to the containing cluster.
- float score = 0.0;
-
- // A list of visits that have been de-duplicated into this visit.
- std::vector<Visit> duplicate_visits;
-
- // The normalized URL for the visit (i.e. an SRP URL normalized based on the
- // user's default search provider).
- GURL normalized_url;
-};
-
-// Differs from history::Cluster in that the visits are de-duplicated and
-// metadata collapsed already.
-struct Cluster {
- Cluster();
- ~Cluster();
- Cluster(const Cluster&);
-
- // An unique but opaque cluster ID.
- int64_t cluster_id;
-
- // The constituent already de-duplicated visits of this cluster.
- std::vector<Visit> visits;
-
- // The keywords associated with this cluster that should never be explicitly
- // presented within the UI.
- // TODO(tommycli): Eliminate this field after removing the usage in
- // `PopulateClusterKeywordCache()`.
- std::vector<std::u16string> keywords;
-};
-
-// The result data returned by `QueryClusters()`.
-struct QueryClustersResult {
- QueryClustersResult();
- ~QueryClustersResult();
- QueryClustersResult(const QueryClustersResult&);
-
- std::vector<Cluster> clusters;
-
- // A nullopt `continuation_end_time` means we have exhausted History.
- // Note that this differs from History itself, which uses base::Time() as the
- // value to indicate we've exhausted history. I've found that to be not
- // explicit enough in practice. This value will never be base::Time().
- absl::optional<base::Time> continuation_end_time;
-};
-using QueryClustersCallback = base::OnceCallback<void(QueryClustersResult)>;
+// If `continuation_end_time` is base::Time(), then we've exhausted History.
+// This matches the same semantics as returned directly from History.
+using QueryClustersCallback =
+ base::OnceCallback<void(std::vector<history::Cluster> clusters,
+ base::Time continuation_end_time)>;
// Tracks which fields have been or are pending recording. This helps 1) avoid
// re-recording fields and 2) determine whether a visit is compete (i.e. has all
diff --git a/chromium/components/history_clusters/core/history_clusters_util.cc b/chromium/components/history_clusters/core/history_clusters_util.cc
new file mode 100644
index 00000000000..2fc03d19180
--- /dev/null
+++ b/chromium/components/history_clusters/core/history_clusters_util.cc
@@ -0,0 +1,209 @@
+// Copyright 2022 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.
+
+#include "components/history_clusters/core/history_clusters_util.h"
+
+#include <algorithm>
+
+#include "base/i18n/case_conversion.h"
+#include "base/ranges/algorithm.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/history/core/browser/history_types.h"
+#include "components/history_clusters/core/features.h"
+#include "components/query_parser/query_parser.h"
+#include "components/url_formatter/url_formatter.h"
+
+namespace history_clusters {
+
+namespace {
+
+// Returns true if `find_nodes` matches `cluster_keywords`.
+bool DoesQueryMatchClusterKeywords(
+ const query_parser::QueryNodeVector& find_nodes,
+ const std::vector<std::u16string>& cluster_keywords) {
+ // All of the cluster's `keyword`s go into `find_in_words`.
+ // Each `keyword` may have multiple terms, so loop over them.
+ query_parser::QueryWordVector find_in_words;
+ for (auto& keyword : cluster_keywords) {
+ query_parser::QueryParser::ExtractQueryWords(base::i18n::ToLower(keyword),
+ &find_in_words);
+ }
+
+ return query_parser::QueryParser::DoesQueryMatch(find_in_words, find_nodes);
+}
+
+// Flags any elements within `cluster_visits` that match `find_nodes`. The
+// matching is deliberately meant to closely mirror the History implementation.
+// Returns true if any elements match, and returns false if none of them do.
+bool FlagMatchingVisits(const query_parser::QueryNodeVector& find_nodes,
+ std::vector<history::ClusterVisit>* cluster_visits) {
+ DCHECK(cluster_visits);
+
+ bool any_visits_match = false;
+
+ for (auto& visit : *cluster_visits) {
+ query_parser::QueryWordVector find_in_words;
+ GURL gurl = visit.annotated_visit.url_row.url();
+
+ std::u16string url_lower =
+ base::i18n::ToLower(base::UTF8ToUTF16(gurl.possibly_invalid_spec()));
+ query_parser::QueryParser::ExtractQueryWords(url_lower, &find_in_words);
+
+ if (gurl.is_valid()) {
+ // Decode punycode to match IDN.
+ std::u16string ascii = base::ASCIIToUTF16(gurl.host());
+ std::u16string utf = url_formatter::IDNToUnicode(gurl.host());
+ if (ascii != utf)
+ query_parser::QueryParser::ExtractQueryWords(utf, &find_in_words);
+ }
+
+ std::u16string title_lower =
+ base::i18n::ToLower(visit.annotated_visit.url_row.title());
+ query_parser::QueryParser::ExtractQueryWords(title_lower, &find_in_words);
+
+ if (query_parser::QueryParser::DoesQueryMatch(find_in_words, find_nodes)) {
+ visit.matches_search_query = true;
+ any_visits_match = true;
+ }
+ }
+
+ return any_visits_match;
+}
+
+// Re-scores and re-sorts `cluster_visits` so that all visits that match the
+// search query are promoted above all visits that don't match the search query.
+// All visits are likely to be rescored in this case.
+//
+// Note, this should NOT be called for `cluster_visits` with NO matching visits.
+void PromoteMatchingVisitsAboveNonMatchingVisits(
+ std::vector<history::ClusterVisit>* cluster_visits) {
+ DCHECK(cluster_visits);
+ for (auto& visit : *cluster_visits) {
+ if (visit.matches_search_query) {
+ // Smash all matching scores into the range that's above the fold.
+ visit.score = kMinScoreToAlwaysShowAboveTheFold.Get() +
+ visit.score * (1 - kMinScoreToAlwaysShowAboveTheFold.Get());
+ } else {
+ // Smash all non-matching scores into the range that's below the fold.
+ visit.score = visit.score * kMinScoreToAlwaysShowAboveTheFold.Get();
+ }
+ }
+
+ StableSortVisits(cluster_visits);
+}
+
+} // namespace
+
+GURL ComputeURLForDeduping(const GURL& url) {
+ // Below is a simplified version of `AutocompleteMatch::GURLToStrippedGURL`
+ // that is thread-safe, stateless, never hits the disk, a bit more aggressive,
+ // and without a dependency on omnibox components.
+ if (!url.is_valid())
+ return url;
+
+ GURL url_for_deduping = url;
+
+ GURL::Replacements replacements;
+
+ // Strip out www, but preserve the eTLD+1. This matches the omnibox behavior.
+ // Make an explicit local, as a StringPiece can't point to a temporary.
+ std::string stripped_host = url_formatter::StripWWW(url_for_deduping.host());
+ replacements.SetHostStr(base::StringPiece(stripped_host));
+
+ // Replace http protocol with https. It's just for deduplication.
+ if (url_for_deduping.SchemeIs(url::kHttpScheme))
+ replacements.SetSchemeStr(url::kHttpsScheme);
+
+ if (url.has_ref())
+ replacements.ClearRef();
+
+ url_for_deduping = url_for_deduping.ReplaceComponents(replacements);
+ return url_for_deduping;
+}
+
+void StableSortVisits(std::vector<history::ClusterVisit>* visits) {
+ DCHECK(visits);
+ base::ranges::stable_sort(*visits, [](auto& v1, auto& v2) {
+ if (v1.score != v2.score) {
+ // Use v1 > v2 to get higher scored visits BEFORE lower scored visits.
+ return v1.score > v2.score;
+ }
+
+ // Use v1 > v2 to get more recent visits BEFORE older visits.
+ return v1.annotated_visit.visit_row.visit_time >
+ v2.annotated_visit.visit_row.visit_time;
+ });
+}
+
+void ApplySearchQuery(const std::string& query,
+ std::vector<history::Cluster>* clusters) {
+ DCHECK(clusters);
+ if (query.empty())
+ return;
+
+ // Extract query nodes from the query string.
+ query_parser::QueryNodeVector find_nodes;
+ query_parser::QueryParser::ParseQueryNodes(
+ base::UTF8ToUTF16(query),
+ query_parser::MatchingAlgorithm::ALWAYS_PREFIX_SEARCH, &find_nodes);
+
+ // Move all the passed in `clusters` into `all_clusters`, and start rebuilding
+ // `clusters` to only contain the matching ones.
+ std::vector<history::Cluster> all_clusters;
+ std::swap(all_clusters, *clusters);
+
+ for (auto& cluster : all_clusters) {
+ bool any_visits_match = FlagMatchingVisits(find_nodes, &cluster.visits);
+ if (any_visits_match && kRescoreVisitsWithinClustersForQuery.Get()) {
+ PromoteMatchingVisitsAboveNonMatchingVisits(&cluster.visits);
+ }
+
+ // If any of the visits match, or if any of the `cluster.keywords` match,
+ // move this cluster into the list of surviving clusters.
+ if (any_visits_match ||
+ DoesQueryMatchClusterKeywords(find_nodes, cluster.keywords)) {
+ clusters->push_back(std::move(cluster));
+ }
+ }
+}
+
+void CullNonProminentOrDuplicateClusters(
+ std::string query,
+ std::vector<history::Cluster>* clusters,
+ std::set<GURL>* seen_single_visit_cluster_urls) {
+ DCHECK(clusters);
+ DCHECK(seen_single_visit_cluster_urls);
+ if (query.empty()) {
+ // For the empty-query state, only show clusters with
+ // `should_show_on_prominent_ui_surfaces` set to true. This restriction is
+ // NOT applied when the user is searching for a specific keyword.
+ clusters->erase(base::ranges::remove_if(
+ *clusters,
+ [](const history::Cluster& cluster) {
+ return !cluster.should_show_on_prominent_ui_surfaces;
+ }),
+ clusters->end());
+ } else {
+ clusters->erase(base::ranges::remove_if(
+ *clusters,
+ [&](const history::Cluster& cluster) {
+ // Erase all duplicate single-visit non-prominent
+ // clusters.
+ if (!cluster.should_show_on_prominent_ui_surfaces &&
+ cluster.visits.size() == 1) {
+ auto [unused_iterator, newly_inserted] =
+ seen_single_visit_cluster_urls->insert(
+ cluster.visits[0].url_for_deduping);
+ return !newly_inserted;
+ }
+
+ return false;
+ }),
+ clusters->end());
+ }
+}
+
+} // namespace history_clusters
diff --git a/chromium/components/history_clusters/core/history_clusters_util.h b/chromium/components/history_clusters/core/history_clusters_util.h
new file mode 100644
index 00000000000..074dd6c50d0
--- /dev/null
+++ b/chromium/components/history_clusters/core/history_clusters_util.h
@@ -0,0 +1,47 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_HISTORY_CLUSTERS_CORE_HISTORY_CLUSTERS_UTIL_H_
+#define COMPONENTS_HISTORY_CLUSTERS_CORE_HISTORY_CLUSTERS_UTIL_H_
+
+#include <set>
+#include <string>
+#include <vector>
+
+#include "components/history/core/browser/history_types.h"
+#include "url/gurl.h"
+
+namespace history_clusters {
+
+// Computes a simplified GURL for deduping purposes only. The resulting GURL may
+// not be valid or navigable, and is only intended for History Cluster deduping.
+//
+// Note, this is NOT meant to be applied to Search Result Page URLs. Those
+// should be separately canonicalized by TemplateURLService and not sent here.
+GURL ComputeURLForDeduping(const GURL& url);
+
+// Stable sorts visits according to score, then reverse-chronologically.
+void StableSortVisits(std::vector<history::ClusterVisit>* visits);
+
+// Erases all clusters that don't match `query`. Also may re-score the visits
+// within matching clusters.
+//
+// If `query` is an empty string, leaves `clusters` unmodified.
+void ApplySearchQuery(const std::string& query,
+ std::vector<history::Cluster>* clusters);
+
+// If `query` is empty, erases all non-prominent clusters.
+//
+// If `query` is non-empty, we assume that the user is searching for something,
+// so we only cull duplicate occurrences of single-visit non-prominent clusters.
+// The set of single-visit clusters we've already seen is tracked by
+// `seen_single_visit_cluster_urls` and this function updates that set.
+void CullNonProminentOrDuplicateClusters(
+ std::string query,
+ std::vector<history::Cluster>* clusters,
+ std::set<GURL>* seen_single_visit_cluster_urls);
+
+} // namespace history_clusters
+
+#endif // COMPONENTS_HISTORY_CLUSTERS_CORE_HISTORY_CLUSTERS_UTIL_H_
diff --git a/chromium/components/history_clusters/core/history_clusters_util_unittest.cc b/chromium/components/history_clusters/core/history_clusters_util_unittest.cc
new file mode 100644
index 00000000000..68e74a89fc4
--- /dev/null
+++ b/chromium/components/history_clusters/core/history_clusters_util_unittest.cc
@@ -0,0 +1,151 @@
+// Copyright 2022 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.
+
+#include "components/history_clusters/core/history_clusters_util.h"
+
+#include "base/strings/stringprintf.h"
+#include "components/history_clusters/core/history_clusters_service_test_api.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace history_clusters {
+namespace {
+
+TEST(HistoryClustersUtilTest, ComputeURLForDeduping) {
+ EXPECT_EQ(ComputeURLForDeduping(GURL("https://www.google.com/")),
+ "https://google.com/")
+ << "Strip off WWW.";
+ EXPECT_EQ(ComputeURLForDeduping(GURL("http://google.com/")),
+ "https://google.com/")
+ << "Normalizes scheme to https.";
+ EXPECT_EQ(
+ ComputeURLForDeduping(GURL("https://google.com/path?foo=bar#reftag")),
+ "https://google.com/path?foo=bar")
+ << "Strips ref, leaves path and query.";
+ EXPECT_EQ(
+ ComputeURLForDeduping(GURL("http://www.google.com/path?foo=bar#reftag")),
+ "https://google.com/path?foo=bar")
+ << "Does all of the above at once.";
+ EXPECT_EQ(ComputeURLForDeduping(GURL("https://google.com/path?foo=bar")),
+ "https://google.com/path?foo=bar")
+ << "Sanity check when no replacements needed.";
+}
+
+TEST(HistoryClustersUtilTest, FilterClustersMatchingQuery) {
+ std::vector<history::Cluster> all_clusters;
+ all_clusters.push_back(
+ history::Cluster(1,
+ {
+ GetHardcodedClusterVisit(2),
+ GetHardcodedClusterVisit(1),
+ },
+ {u"apples", u"Red Oranges"},
+ /*should_show_on_prominent_ui_surfaces=*/false));
+ all_clusters.push_back(
+ history::Cluster(2,
+ {
+ GetHardcodedClusterVisit(2),
+ },
+ {},
+ /*should_show_on_prominent_ui_surfaces=*/true));
+
+ struct TestData {
+ std::string query;
+ const bool expect_first_cluster;
+ const bool expect_second_cluster;
+ } test_data[] = {
+ // Empty query should get both clusters, even the non-prominent one,
+ // because this function only filters for query, and ignores whether the
+ // cluster is prominent or not.
+ {"", true, true},
+ // Non matching query should get none.
+ {"non_matching_query", false, false},
+ // Query matching one cluster.
+ {"oran", true, false},
+ // This verifies the memory doesn't flicker away as the user is typing
+ // out: "red oran" one key at a time. Also tests out multi-term queries.
+ {"red", true, false},
+ {"red ", true, false},
+ {"red o", true, false},
+ {"red or", true, false},
+ {"red ora", true, false},
+ {"red oran", true, false},
+ // Verify that we can search by URL.
+ {"goog", true, false},
+ // Verify we can search by page title, even mismatching case.
+ {"code", true, true},
+ // Verify that we match if the query spans the title and URL of a single
+ // visit.
+ {"goog search", true, false},
+ // Verify that we DON'T match if the query spans the title and URL of a
+ // multiple visits.
+ {"goog code", false, false},
+ // Verify that we DON'T match if the query spans both the visit and
+ // keywords.
+ {"goog red", false, false},
+ };
+
+ for (size_t i = 0; i < base::size(test_data); ++i) {
+ SCOPED_TRACE(base::StringPrintf("Testing case i=%d, query=%s",
+ static_cast<int>(i),
+ test_data[i].query.c_str()));
+
+ auto clusters = all_clusters;
+ ApplySearchQuery(test_data[i].query, &clusters);
+
+ size_t expected_size =
+ static_cast<size_t>(test_data[i].expect_first_cluster) +
+ static_cast<size_t>(test_data[i].expect_second_cluster);
+ ASSERT_EQ(clusters.size(), expected_size);
+
+ if (test_data[i].expect_first_cluster) {
+ EXPECT_EQ(clusters[0].cluster_id, 1);
+ }
+
+ if (test_data[i].expect_second_cluster) {
+ const auto& cluster =
+ test_data[i].expect_first_cluster ? clusters[1] : clusters[0];
+ EXPECT_EQ(cluster.cluster_id, 2);
+ }
+ }
+}
+
+TEST(HistoryClustersUtilTest, PromoteMatchingVisitsAboveNonMatchingVisits) {
+ std::vector<history::Cluster> all_clusters;
+ all_clusters.push_back(
+ history::Cluster(0,
+ {
+ GetHardcodedClusterVisit(1),
+ GetHardcodedClusterVisit(2),
+ },
+ {u"apples", u"Red Oranges"},
+ /*should_show_on_prominent_ui_surfaces=*/false));
+
+ // No promotion when we match a keyword.
+ {
+ std::vector clusters = all_clusters;
+ ApplySearchQuery("apples", &clusters);
+ ASSERT_EQ(clusters.size(), 1U);
+ ASSERT_EQ(clusters[0].visits.size(), 2U);
+ EXPECT_EQ(clusters[0].visits[0].annotated_visit.visit_row.visit_id, 1);
+ EXPECT_FLOAT_EQ(clusters[0].visits[0].score, 0.5);
+ EXPECT_EQ(clusters[0].visits[1].annotated_visit.visit_row.visit_id, 2);
+ EXPECT_FLOAT_EQ(clusters[0].visits[1].score, 0.5);
+ }
+
+ // Promote the second visit over the first if we match the second visit.
+ {
+ std::vector clusters = all_clusters;
+ ApplySearchQuery("git", &clusters);
+ ASSERT_EQ(clusters.size(), 1U);
+ ASSERT_EQ(clusters[0].visits.size(), 2U);
+ EXPECT_EQ(clusters[0].visits[0].annotated_visit.visit_row.visit_id, 2);
+ EXPECT_FLOAT_EQ(clusters[0].visits[0].score, 0.75);
+ EXPECT_EQ(clusters[0].visits[1].annotated_visit.visit_row.visit_id, 1);
+ EXPECT_FLOAT_EQ(clusters[0].visits[1].score, 0.25);
+ }
+}
+
+} // namespace
+} // namespace history_clusters
diff --git a/chromium/components/history_clusters/core/keyword_cluster_finalizer.cc b/chromium/components/history_clusters/core/keyword_cluster_finalizer.cc
index b4e43d2229a..6fead3511a5 100644
--- a/chromium/components/history_clusters/core/keyword_cluster_finalizer.cc
+++ b/chromium/components/history_clusters/core/keyword_cluster_finalizer.cc
@@ -6,6 +6,7 @@
#include "base/containers/flat_set.h"
#include "base/strings/utf_string_conversions.h"
+#include "components/history/core/browser/history_types.h"
#include "components/history_clusters/core/on_device_clustering_features.h"
#include "components/history_clusters/core/on_device_clustering_util.h"
diff --git a/chromium/components/history_clusters/core/keyword_cluster_finalizer_unittest.cc b/chromium/components/history_clusters/core/keyword_cluster_finalizer_unittest.cc
index 0143ce0c97b..80f5471c823 100644
--- a/chromium/components/history_clusters/core/keyword_cluster_finalizer_unittest.cc
+++ b/chromium/components/history_clusters/core/keyword_cluster_finalizer_unittest.cc
@@ -57,8 +57,8 @@ TEST_F(KeywordClusterFinalizerTest, IncludesKeywordsBasedOnFeatureParameters) {
{"category", 1}};
history::ClusterVisit visit3 = testing::CreateClusterVisit(
- testing::CreateDefaultAnnotatedVisit(2, GURL("https://baz.com/")));
- visit3.duplicate_visit_ids.push_back(1);
+ testing::CreateDefaultAnnotatedVisit(3, GURL("https://baz.com/")));
+ visit3.duplicate_visits.push_back(visit);
visit3.engagement_score = 1.0;
visit3.annotated_visit.content_annotations.model_annotations.entities = {
{"github", 1}, {"otherentity", 1}};
@@ -66,7 +66,7 @@ TEST_F(KeywordClusterFinalizerTest, IncludesKeywordsBasedOnFeatureParameters) {
{"category", 1}};
history::Cluster cluster;
- cluster.visits = {visit, visit2, visit3};
+ cluster.visits = {visit2, visit3};
FinalizeCluster(cluster);
EXPECT_THAT(cluster.keywords,
UnorderedElementsAre(u"github", u"otherentity"));
@@ -115,7 +115,7 @@ TEST_F(KeywordClusterFinalizerIncludeAllTest,
history::ClusterVisit visit3 = testing::CreateClusterVisit(
testing::CreateDefaultAnnotatedVisit(2, GURL("https://baz.com/")));
- visit3.duplicate_visit_ids.push_back(1);
+ visit3.duplicate_visits.push_back(visit);
visit3.engagement_score = 1.0;
visit3.annotated_visit.content_annotations.model_annotations.entities = {
{"github", 1}, {"otherentity", 1}};
@@ -123,7 +123,7 @@ TEST_F(KeywordClusterFinalizerIncludeAllTest,
{"category", 1}};
history::Cluster cluster;
- cluster.visits = {visit, visit2, visit3};
+ cluster.visits = {visit2, visit3};
FinalizeCluster(cluster);
EXPECT_THAT(cluster.keywords,
UnorderedElementsAre(u"github", u"category", u"onlyinnoisyvisit",
diff --git a/chromium/components/history_clusters/core/noisy_cluster_finalizer.cc b/chromium/components/history_clusters/core/noisy_cluster_finalizer.cc
index 1940e0cdb40..a46c2dc01a4 100644
--- a/chromium/components/history_clusters/core/noisy_cluster_finalizer.cc
+++ b/chromium/components/history_clusters/core/noisy_cluster_finalizer.cc
@@ -18,7 +18,8 @@ void NoisyClusterFinalizer::FinalizeCluster(history::Cluster& cluster) {
ScopedFilterClusterMetricsRecorder metrics_recorder("NoisyCluster");
for (const auto& visit : cluster.visits) {
if (!IsNoisyVisit(visit)) {
- interesting_visit_cnt += 1;
+ // Use the canonical visit's noisiness for all its duplicates too.
+ interesting_visit_cnt += 1 + visit.duplicate_visits.size();
}
if (interesting_visit_cnt >=
features::NumberInterestingVisitsFilterThreshold()) {
diff --git a/chromium/components/history_clusters/core/noisy_cluster_finalizer_unittest.cc b/chromium/components/history_clusters/core/noisy_cluster_finalizer_unittest.cc
index 7adbbc17faf..02af04dbe3d 100644
--- a/chromium/components/history_clusters/core/noisy_cluster_finalizer_unittest.cc
+++ b/chromium/components/history_clusters/core/noisy_cluster_finalizer_unittest.cc
@@ -45,11 +45,11 @@ TEST_F(NoisyClusterFinalizerTest, FilterHighEngagementClusters) {
history::ClusterVisit visit2 = testing::CreateClusterVisit(
testing::CreateDefaultAnnotatedVisit(2, GURL("https://bar.com/")));
- visit2.duplicate_visit_ids.push_back(1);
+ visit2.duplicate_visits.push_back(visit);
visit2.engagement_score = 25.0;
history::Cluster cluster;
- cluster.visits = {visit, visit2};
+ cluster.visits = {visit2};
FinalizeCluster(cluster);
EXPECT_FALSE(cluster.should_show_on_prominent_ui_surfaces);
}
@@ -62,18 +62,18 @@ TEST_F(NoisyClusterFinalizerTest, HideClusterWithOnlyOneInterestingVisit) {
history::ClusterVisit visit2 = testing::CreateClusterVisit(
testing::CreateDefaultAnnotatedVisit(2, GURL("https://bar.com/")));
- visit2.duplicate_visit_ids.push_back(1);
+ visit2.duplicate_visits.push_back(visit);
visit2.engagement_score = 25.0;
history::Cluster cluster;
- cluster.visits = {visit, visit2};
+ cluster.visits = {visit2};
FinalizeCluster(cluster);
EXPECT_FALSE(cluster.should_show_on_prominent_ui_surfaces);
histogram_tester.ExpectUniqueSample(
"History.Clusters.Backend.WasClusterFiltered.NoisyCluster", true, 1);
}
-TEST_F(NoisyClusterFinalizerTest, KeepClusterWitihAtLeastTwoInterestingVisits) {
+TEST_F(NoisyClusterFinalizerTest, KeepClusterWithAtLeastTwoInterestingVisits) {
base::HistogramTester histogram_tester;
history::ClusterVisit visit = testing::CreateClusterVisit(
testing::CreateDefaultAnnotatedVisit(1, GURL("https://bar.com/")));
@@ -81,15 +81,15 @@ TEST_F(NoisyClusterFinalizerTest, KeepClusterWitihAtLeastTwoInterestingVisits) {
history::ClusterVisit visit2 = testing::CreateClusterVisit(
testing::CreateDefaultAnnotatedVisit(2, GURL("https://bar.com/")));
- visit2.duplicate_visit_ids.push_back(1);
visit2.engagement_score = 25.0;
history::ClusterVisit visit3 = testing::CreateClusterVisit(
testing::CreateDefaultAnnotatedVisit(3, GURL("https://foo.com/")));
+ visit3.duplicate_visits.push_back(visit);
visit3.engagement_score = 5.0;
history::Cluster cluster;
- cluster.visits = {visit, visit2, visit3};
+ cluster.visits = {visit2, visit3};
FinalizeCluster(cluster);
EXPECT_TRUE(cluster.should_show_on_prominent_ui_surfaces);
histogram_tester.ExpectUniqueSample(
diff --git a/chromium/components/history_clusters/core/on_device_clustering_backend.cc b/chromium/components/history_clusters/core/on_device_clustering_backend.cc
index 023e26ce1ab..6541ebc19c5 100644
--- a/chromium/components/history_clusters/core/on_device_clustering_backend.cc
+++ b/chromium/components/history_clusters/core/on_device_clustering_backend.cc
@@ -15,12 +15,16 @@
#include "base/task/task_runner_util.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
+#include "base/threading/thread_task_runner_handle.h"
#include "components/history/core/browser/history_types.h"
#include "components/history_clusters/core/content_annotations_cluster_processor.h"
#include "components/history_clusters/core/content_visibility_cluster_finalizer.h"
+#include "components/history_clusters/core/features.h"
+#include "components/history_clusters/core/history_clusters_util.h"
#include "components/history_clusters/core/keyword_cluster_finalizer.h"
#include "components/history_clusters/core/noisy_cluster_finalizer.h"
#include "components/history_clusters/core/on_device_clustering_features.h"
+#include "components/history_clusters/core/on_device_clustering_util.h"
#include "components/history_clusters/core/ranking_cluster_finalizer.h"
#include "components/history_clusters/core/similar_visit_deduper_cluster_finalizer.h"
#include "components/history_clusters/core/single_visit_cluster_finalizer.h"
@@ -34,9 +38,9 @@ namespace history_clusters {
namespace {
-// Returns the normalized URL for the search provider if the URL for the visit
-// is a Search URL. Otherwise, returns nullopt.
-absl::optional<GURL> GetNormalizedURLForSearchVisit(
+// Returns the normalized URL and the search terms for the search provider if
+// the URL for the visit is a Search URL. Otherwise, returns nullopt.
+absl::optional<std::pair<GURL, std::u16string>> GetSearchMetadataForVisit(
const history::AnnotatedVisit& visit,
const TemplateURLService* template_url_service) {
if (!template_url_service)
@@ -63,8 +67,10 @@ absl::optional<GURL> GetNormalizedURLForSearchVisit(
if (!search_url_ref.SupportsReplacement(search_terms_data))
return absl::nullopt;
- return GURL(
- search_url_ref.ReplaceSearchTerms(search_terms_args, search_terms_data));
+ return std::make_pair(
+ GURL(search_url_ref.ReplaceSearchTerms(search_terms_args,
+ search_terms_data)),
+ base::i18n::ToLower(base::CollapseWhitespace(search_terms, false)));
}
} // namespace
@@ -76,14 +82,24 @@ OnDeviceClusteringBackend::OnDeviceClusteringBackend(
: template_url_service_(template_url_service),
entity_metadata_provider_(entity_metadata_provider),
engagement_score_provider_(engagement_score_provider),
- background_task_runner_(base::ThreadPool::CreateSequencedTaskRunner(
- {base::MayBlock(), base::TaskPriority::USER_VISIBLE})) {}
+ high_priority_background_task_runner_(
+ base::ThreadPool::CreateSequencedTaskRunner(
+ {base::MayBlock(), base::TaskPriority::USER_VISIBLE})),
+ low_priority_background_task_runner_(
+ base::ThreadPool::CreateSequencedTaskRunner(
+ {base::MayBlock(), base::TaskPriority::BEST_EFFORT})),
+ engagement_score_cache_last_refresh_timestamp_(base::TimeTicks::Now()),
+ engagement_score_cache_(
+ GetFieldTrialParamByFeatureAsInt(features::kUseEngagementScoreCache,
+ "engagement_score_cache_size",
+ 100)) {}
OnDeviceClusteringBackend::~OnDeviceClusteringBackend() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
void OnDeviceClusteringBackend::GetClusters(
+ ClusteringRequestSource clustering_request_source,
ClustersCallback callback,
const std::vector<history::AnnotatedVisit>& visits) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -96,10 +112,10 @@ void OnDeviceClusteringBackend::GetClusters(
// Just start clustering without getting entity metadata if we don't have a
// provider to translate the entities.
if (!entity_metadata_provider_) {
- OnBatchEntityMetadataRetrieved(/*completed_task=*/nullptr, visits,
- /*entity_metadata_start=*/absl::nullopt,
- std::move(callback),
- /*entity_metadata_map=*/{});
+ OnBatchEntityMetadataRetrieved(
+ clustering_request_source, /*completed_task=*/nullptr, visits,
+ /*entity_metadata_start=*/absl::nullopt, std::move(callback),
+ /*entity_metadata_map=*/{});
return;
}
@@ -115,10 +131,10 @@ void OnDeviceClusteringBackend::GetClusters(
// Don't bother with getting entity metadata if there's nothing to get
// metadata for.
if (entity_ids.empty()) {
- OnBatchEntityMetadataRetrieved(/*completed_task=*/nullptr, visits,
- /*entity_metadata_start=*/absl::nullopt,
- std::move(callback),
- /*entity_metadata_map=*/{});
+ OnBatchEntityMetadataRetrieved(
+ clustering_request_source, /*completed_task=*/nullptr, visits,
+ /*entity_metadata_start=*/absl::nullopt, std::move(callback),
+ /*entity_metadata_map=*/{});
return;
}
@@ -132,13 +148,15 @@ void OnDeviceClusteringBackend::GetClusters(
auto* batch_entity_metadata_task_ptr = batch_entity_metadata_task.get();
in_flight_batch_entity_metadata_tasks_.insert(
std::move(batch_entity_metadata_task));
- batch_entity_metadata_task_ptr->Execute(base::BindOnce(
- &OnDeviceClusteringBackend::OnBatchEntityMetadataRetrieved,
- weak_ptr_factory_.GetWeakPtr(), batch_entity_metadata_task_ptr, visits,
- base::TimeTicks::Now(), std::move(callback)));
+ batch_entity_metadata_task_ptr->Execute(
+ base::BindOnce(&OnDeviceClusteringBackend::OnBatchEntityMetadataRetrieved,
+ weak_ptr_factory_.GetWeakPtr(), clustering_request_source,
+ batch_entity_metadata_task_ptr, visits,
+ base::TimeTicks::Now(), std::move(callback)));
}
void OnDeviceClusteringBackend::OnBatchEntityMetadataRetrieved(
+ ClusteringRequestSource clustering_request_source,
optimization_guide::BatchEntityMetadataTask* completed_task,
const std::vector<history::AnnotatedVisit>& annotated_visits,
absl::optional<base::TimeTicks> entity_metadata_start,
@@ -147,6 +165,16 @@ void OnDeviceClusteringBackend::OnBatchEntityMetadataRetrieved(
entity_metadata_map) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ if (base::FeatureList::IsEnabled(features::kUseEngagementScoreCache) &&
+ base::TimeTicks::Now() >
+ engagement_score_cache_last_refresh_timestamp_ +
+ base::Minutes(GetFieldTrialParamByFeatureAsInt(
+ features::kUseEngagementScoreCache,
+ "engagement_score_cache_refresh_duration_minutes", 120))) {
+ engagement_score_cache_.Clear();
+ engagement_score_cache_last_refresh_timestamp_ = base::TimeTicks::Now();
+ }
+
if (entity_metadata_start) {
base::UmaHistogramTimes("History.Clusters.Backend.BatchEntityLookupLatency",
*entity_metadata_start - base::TimeTicks::Now());
@@ -154,18 +182,90 @@ void OnDeviceClusteringBackend::OnBatchEntityMetadataRetrieved(
// Rewrite the visits based on the mapping and normalize URLs here.
std::vector<history::ClusterVisit> cluster_visits;
cluster_visits.reserve(annotated_visits.size());
- for (const auto& visit : annotated_visits) {
+
+ ProcessBatchOfVisits(clustering_request_source, 0, std::move(cluster_visits),
+ completed_task, annotated_visits, entity_metadata_start,
+ std::move(callback), entity_metadata_map);
+}
+
+void OnDeviceClusteringBackend::ProcessBatchOfVisits(
+ ClusteringRequestSource clustering_request_source,
+ size_t index_to_process,
+ std::vector<history::ClusterVisit> cluster_visits,
+ optimization_guide::BatchEntityMetadataTask* completed_task,
+ const std::vector<history::AnnotatedVisit>& annotated_visits,
+ absl::optional<base::TimeTicks> entity_metadata_start,
+ ClustersCallback callback,
+ const base::flat_map<std::string, optimization_guide::EntityMetadata>&
+ entity_metadata_map) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ // Entries in |annotated_visits| that have index greater than or equal to
+ // |index_stop_batch_processing| should not be processed in this task loop.
+ size_t index_stop_batch_processing =
+ index_to_process + features::GetClusteringTasksBatchSize();
+
+ // Process all entries in one go in certain cases. e.g., if
+ // |clustering_request_source| is user blocking.
+ if (!base::FeatureList::IsEnabled(
+ features::kSplitClusteringTasksToSmallerBatches) ||
+ clustering_request_source == ClusteringRequestSource::kJourneysPage ||
+ annotated_visits.size() <= 1) {
+ index_stop_batch_processing = annotated_visits.size();
+ }
+
+ // Avoid overflows.
+ index_stop_batch_processing =
+ std::min(index_stop_batch_processing, annotated_visits.size());
+
+ base::UmaHistogramCounts1000(
+ "Journeys.PartialOnBatchEntityMetadataRetrieved.BatchSize",
+ index_stop_batch_processing - index_to_process);
+
+ while (index_to_process < index_stop_batch_processing) {
+ const auto& visit = annotated_visits[index_to_process];
+ ++index_to_process;
history::ClusterVisit cluster_visit;
cluster_visit.annotated_visit = visit;
- absl::optional<GURL> maybe_normalized_url =
- GetNormalizedURLForSearchVisit(visit, template_url_service_);
- cluster_visit.is_search_visit = maybe_normalized_url.has_value();
- cluster_visit.normalized_url =
- maybe_normalized_url.value_or(visit.url_row.url());
+ const std::string& visit_host = visit.url_row.url().host();
+
+ if (visit.content_annotations.search_normalized_url.is_empty()) {
+ // TODO(crbug/1296394): Remove this logic once most clients have a Stable
+ // release of persisted search metadata.
+ absl::optional<std::pair<GURL, std::u16string>> maybe_search_metadata =
+ GetSearchMetadataForVisit(visit, template_url_service_);
+ if (maybe_search_metadata) {
+ cluster_visit.normalized_url = maybe_search_metadata->first;
+ cluster_visit.url_for_deduping = cluster_visit.normalized_url;
+ cluster_visit.search_terms = maybe_search_metadata->second;
+ } else {
+ cluster_visit.normalized_url = visit.url_row.url();
+ cluster_visit.url_for_deduping =
+ ComputeURLForDeduping(cluster_visit.normalized_url);
+ }
+ } else {
+ cluster_visit.normalized_url =
+ visit.content_annotations.search_normalized_url;
+ // Search visits just use the `normalized_url` for deduping.
+ cluster_visit.url_for_deduping = cluster_visit.normalized_url;
+ cluster_visit.search_terms = visit.content_annotations.search_terms;
+ }
if (engagement_score_provider_) {
- cluster_visit.engagement_score =
- engagement_score_provider_->GetScore(visit.url_row.url());
+ if (base::FeatureList::IsEnabled(features::kUseEngagementScoreCache)) {
+ auto it = engagement_score_cache_.Peek(visit_host);
+ if (it != engagement_score_cache_.end()) {
+ cluster_visit.engagement_score = it->second;
+ } else {
+ float score =
+ engagement_score_provider_->GetScore(visit.url_row.url());
+ engagement_score_cache_.Put(visit_host, score);
+ cluster_visit.engagement_score = score;
+ }
+ } else {
+ cluster_visit.engagement_score =
+ engagement_score_provider_->GetScore(visit.url_row.url());
+ }
}
// Rewrite the entities for the visit, but only if it is possible that we
@@ -214,6 +314,28 @@ void OnDeviceClusteringBackend::OnBatchEntityMetadataRetrieved(
cluster_visits.push_back(cluster_visit);
}
+ if (index_to_process >= annotated_visits.size()) {
+ OnAllVisitsFinishedProcessing(clustering_request_source, completed_task,
+ cluster_visits, std::move(callback));
+ return;
+ }
+
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::BindOnce(&OnDeviceClusteringBackend::ProcessBatchOfVisits,
+ weak_ptr_factory_.GetWeakPtr(), clustering_request_source,
+ index_to_process, std::move(cluster_visits),
+ completed_task, annotated_visits, entity_metadata_start,
+ std::move(callback), entity_metadata_map));
+}
+
+void OnDeviceClusteringBackend::OnAllVisitsFinishedProcessing(
+ ClusteringRequestSource clustering_request_source,
+ optimization_guide::BatchEntityMetadataTask* completed_task,
+ const std::vector<history::ClusterVisit>& cluster_visits,
+ ClustersCallback callback) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
// Mark the task as completed, which will destruct |entity_metadata_map|.
if (completed_task) {
auto it = in_flight_batch_entity_metadata_tasks_.find(completed_task);
@@ -223,19 +345,36 @@ void OnDeviceClusteringBackend::OnBatchEntityMetadataRetrieved(
// Post the actual clustering work onto the thread pool, then reply on the
// calling sequence. This is to prevent UI jank.
- background_task_runner_->PostTaskAndReplyWithResult(
+ if (base::FeatureList::IsEnabled(
+ features::kSplitClusteringTasksToSmallerBatches) &&
+ clustering_request_source ==
+ ClusteringRequestSource::kKeywordCacheGeneration) {
+ low_priority_background_task_runner_->PostTaskAndReplyWithResult(
+ FROM_HERE,
+ base::BindOnce(
+ &OnDeviceClusteringBackend::ClusterVisitsOnBackgroundThread,
+ engagement_score_provider_ != nullptr, cluster_visits),
+ std::move(callback));
+ return;
+ }
+
+ DCHECK(clustering_request_source == ClusteringRequestSource::kJourneysPage ||
+ clustering_request_source ==
+ ClusteringRequestSource::kKeywordCacheGeneration);
+
+ high_priority_background_task_runner_->PostTaskAndReplyWithResult(
FROM_HERE,
base::BindOnce(
&OnDeviceClusteringBackend::ClusterVisitsOnBackgroundThread,
- base::Unretained(this), cluster_visits),
+ engagement_score_provider_ != nullptr, cluster_visits),
std::move(callback));
}
+// static
std::vector<history::Cluster>
OnDeviceClusteringBackend::ClusterVisitsOnBackgroundThread(
+ bool engagement_score_provider_is_valid,
const std::vector<history::ClusterVisit>& visits) {
- DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
-
// TODO(crbug.com/1260145): All of these objects are "stateless" between
// requests for clusters. If there needs to be shared state, the entire
// backend needs to be refactored to separate these objects from the UI and
@@ -269,7 +408,8 @@ OnDeviceClusteringBackend::ClusterVisitsOnBackgroundThread(
std::make_unique<SingleVisitClusterFinalizer>());
}
// Add feature to turn on/off site engagement score filter.
- if (engagement_score_provider_ && features::ShouldFilterNoisyClusters()) {
+ if (engagement_score_provider_is_valid &&
+ features::ShouldFilterNoisyClusters()) {
cluster_finalizers.push_back(std::make_unique<NoisyClusterFinalizer>());
}
cluster_finalizers.push_back(std::make_unique<KeywordClusterFinalizer>());
@@ -295,6 +435,10 @@ OnDeviceClusteringBackend::ClusterVisitsOnBackgroundThread(
keyword_sizes.emplace_back(cluster.keywords.size());
}
+ // It's a bit strange that this is essentially a `ClusterProcessor` but has
+ // to operate after the finalizers.
+ SortClusters(&clusters);
+
if (!visits_in_clusters.empty()) {
// We check for empty to ensure the below code doesn't crash, but
// realistically this vector should never be empty.
diff --git a/chromium/components/history_clusters/core/on_device_clustering_backend.h b/chromium/components/history_clusters/core/on_device_clustering_backend.h
index 1775b8f1789..ef2f044566f 100644
--- a/chromium/components/history_clusters/core/on_device_clustering_backend.h
+++ b/chromium/components/history_clusters/core/on_device_clustering_backend.h
@@ -7,6 +7,7 @@
#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
+#include "base/containers/lru_cache.h"
#include "base/containers/unique_ptr_adapters.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
@@ -41,7 +42,8 @@ class OnDeviceClusteringBackend : public ClusteringBackend {
~OnDeviceClusteringBackend() override;
// ClusteringBackend:
- void GetClusters(ClustersCallback callback,
+ void GetClusters(ClusteringRequestSource clustering_request_source,
+ ClustersCallback callback,
const std::vector<history::AnnotatedVisit>& visits) override;
private:
@@ -49,6 +51,7 @@ class OnDeviceClusteringBackend : public ClusteringBackend {
// |completed_task|. This will normalize |annotated_visits| and proceed to
// cluster them after normalization.
void OnBatchEntityMetadataRetrieved(
+ ClusteringRequestSource clustering_request_source,
optimization_guide::BatchEntityMetadataTask* completed_task,
const std::vector<history::AnnotatedVisit>& annotated_visits,
absl::optional<base::TimeTicks> entity_metadata_start,
@@ -56,8 +59,28 @@ class OnDeviceClusteringBackend : public ClusteringBackend {
const base::flat_map<std::string, optimization_guide::EntityMetadata>&
entity_metadata_map);
+ // ProcessBatchOfVisits is called repeatedly to process the visits in batches.
+ void ProcessBatchOfVisits(
+ ClusteringRequestSource clustering_request_source,
+ size_t index_to_process,
+ std::vector<history::ClusterVisit> cluster_visits,
+ optimization_guide::BatchEntityMetadataTask* completed_task,
+ const std::vector<history::AnnotatedVisit>& annotated_visits,
+ absl::optional<base::TimeTicks> entity_metadata_start,
+ ClustersCallback callback,
+ const base::flat_map<std::string, optimization_guide::EntityMetadata>&
+ entity_metadata_map);
+
+ // Called when all visits have been processed.
+ void OnAllVisitsFinishedProcessing(
+ ClusteringRequestSource clustering_request_source,
+ optimization_guide::BatchEntityMetadataTask* completed_task,
+ const std::vector<history::ClusterVisit>& cluster_visits,
+ ClustersCallback callback);
+
// Clusters |visits| on background thread.
- std::vector<history::Cluster> ClusterVisitsOnBackgroundThread(
+ static std::vector<history::Cluster> ClusterVisitsOnBackgroundThread(
+ bool engagement_score_provider_is_valid,
const std::vector<history::ClusterVisit>& visits);
// The object used to normalize SRP URLs. Not owned. Must outlive |this|.
@@ -74,8 +97,17 @@ class OnDeviceClusteringBackend : public ClusteringBackend {
base::UniquePtrComparator>
in_flight_batch_entity_metadata_tasks_;
- // The task runner to run all clustering passes on.
- scoped_refptr<base::SequencedTaskRunner> background_task_runner_;
+ // The task runners to run clustering passes on.
+ // |high_priority_background_task_runner_| should be used iff clustering is
+ // blocking content on a page that user is actively looking at.
+ scoped_refptr<base::SequencedTaskRunner>
+ high_priority_background_task_runner_;
+ scoped_refptr<base::SequencedTaskRunner> low_priority_background_task_runner_;
+
+ // Last time |engagement_score_cache_| was refreshed.
+ base::TimeTicks engagement_score_cache_last_refresh_timestamp_;
+ // URL host to score mapping.
+ base::HashingLRUCache<std::string, float> engagement_score_cache_;
SEQUENCE_CHECKER(sequence_checker_);
diff --git a/chromium/components/history_clusters/core/on_device_clustering_backend_unittest.cc b/chromium/components/history_clusters/core/on_device_clustering_backend_unittest.cc
index 88680900dae..7103ce67d79 100644
--- a/chromium/components/history_clusters/core/on_device_clustering_backend_unittest.cc
+++ b/chromium/components/history_clusters/core/on_device_clustering_backend_unittest.cc
@@ -12,6 +12,7 @@
#include "components/history_clusters/core/on_device_clustering_features.h"
#include "components/optimization_guide/core/entity_metadata_provider.h"
#include "components/search_engines/template_url_service.h"
+#include "components/site_engagement/core/site_engagement_score_provider.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -22,6 +23,27 @@ using ::testing::ElementsAre;
using ::testing::FloatEq;
using ::testing::UnorderedElementsAre;
+class TestSiteEngagementScoreProvider
+ : public site_engagement::SiteEngagementScoreProvider {
+ public:
+ TestSiteEngagementScoreProvider() = default;
+ ~TestSiteEngagementScoreProvider() = default;
+
+ double GetScore(const GURL& url) const override {
+ ++count_get_score_invocations_;
+ return 0;
+ }
+
+ double GetTotalEngagementPoints() const override { return 1; }
+
+ size_t count_get_score_invocations() const {
+ return count_get_score_invocations_;
+ }
+
+ private:
+ mutable size_t count_get_score_invocations_ = 0;
+};
+
class TestEntityMetadataProvider
: public optimization_guide::EntityMetadataProvider {
public:
@@ -74,23 +96,26 @@ class OnDeviceClusteringWithoutContentBackendTest : public ::testing::Test {
{"dedupe_similar_visits", "false"},
{"min_page_topics_model_version_for_visibility", "125"},
{"include_categories_in_keywords", "true"},
- {"exclude_keywords_from_noisy_visits", "false"}});
+ {"exclude_keywords_from_noisy_visits", "false"},
+ {"split_clusters_at_search_visits", "false"}});
}
void SetUp() override {
clustering_backend_ = std::make_unique<OnDeviceClusteringBackend>(
/*template_url_service=*/nullptr, /*entity_metadata_provider=*/nullptr,
- /*engagement_score_provider=*/nullptr);
+ &test_site_engagement_provider_);
}
void TearDown() override { clustering_backend_.reset(); }
std::vector<history::Cluster> ClusterVisits(
+ ClusteringRequestSource clustering_request_source,
const std::vector<history::AnnotatedVisit>& visits) {
std::vector<history::Cluster> clusters;
base::RunLoop run_loop;
clustering_backend_->GetClusters(
+ clustering_request_source,
base::BindOnce(
[](base::RunLoop* run_loop,
std::vector<history::Cluster>* out_clusters,
@@ -105,16 +130,22 @@ class OnDeviceClusteringWithoutContentBackendTest : public ::testing::Test {
return clusters;
}
+ size_t GetSiteEngagementGetScoreInvocationCount() const {
+ return test_site_engagement_provider_.count_get_score_invocations();
+ }
+
protected:
std::unique_ptr<OnDeviceClusteringBackend> clustering_backend_;
base::test::TaskEnvironment task_environment_;
private:
base::test::ScopedFeatureList scoped_feature_list_;
+ TestSiteEngagementScoreProvider test_site_engagement_provider_;
};
TEST_F(OnDeviceClusteringWithoutContentBackendTest, ClusterNoVisits) {
- EXPECT_TRUE(ClusterVisits({}).empty());
+ EXPECT_TRUE(
+ ClusterVisits(ClusteringRequestSource::kJourneysPage, {}).empty());
}
TEST_F(OnDeviceClusteringWithoutContentBackendTest, ClusterOneVisit) {
@@ -125,7 +156,8 @@ TEST_F(OnDeviceClusteringWithoutContentBackendTest, ClusterOneVisit) {
testing::CreateDefaultAnnotatedVisit(1, GURL("https://google.com/"));
visits.push_back(visit);
- std::vector<history::Cluster> result_clusters = ClusterVisits(visits);
+ std::vector<history::Cluster> result_clusters =
+ ClusterVisits(ClusteringRequestSource::kJourneysPage, visits);
EXPECT_THAT(testing::ToVisitResults(result_clusters),
ElementsAre(ElementsAre(testing::VisitResult(1, 1.0))));
}
@@ -149,7 +181,8 @@ TEST_F(OnDeviceClusteringWithoutContentBackendTest,
visit2.referring_visit_of_redirect_chain_start = 1;
visits.push_back(visit2);
- std::vector<history::Cluster> result_clusters = ClusterVisits(visits);
+ std::vector<history::Cluster> result_clusters =
+ ClusterVisits(ClusteringRequestSource::kJourneysPage, visits);
EXPECT_THAT(testing::ToVisitResults(result_clusters),
ElementsAre(ElementsAre(testing::VisitResult(1, 1.0),
testing::VisitResult(2, 1.0))));
@@ -183,7 +216,8 @@ TEST_F(OnDeviceClusteringWithoutContentBackendTest,
visit2.opener_visit_of_redirect_chain_start = 1;
visits.push_back(visit2);
- std::vector<history::Cluster> result_clusters = ClusterVisits(visits);
+ std::vector<history::Cluster> result_clusters =
+ ClusterVisits(ClusteringRequestSource::kJourneysPage, visits);
EXPECT_THAT(testing::ToVisitResults(result_clusters),
ElementsAre(ElementsAre(testing::VisitResult(1, 1.0),
testing::VisitResult(2, 1.0))));
@@ -210,14 +244,15 @@ TEST_F(OnDeviceClusteringWithoutContentBackendTest, ClusterTwoVisitsTiedByURL) {
testing::CreateDefaultAnnotatedVisit(2, GURL("https://google.com/"));
visits.push_back(visit2);
- std::vector<history::Cluster> result_clusters = ClusterVisits(visits);
+ std::vector<history::Cluster> result_clusters =
+ ClusterVisits(ClusteringRequestSource::kJourneysPage, visits);
EXPECT_THAT(testing::ToVisitResults(result_clusters),
- ElementsAre(ElementsAre(testing::VisitResult(1, 0.0),
- testing::VisitResult(2, 1.0, {1}))));
+ ElementsAre(ElementsAre(testing::VisitResult(
+ 2, 1.0, {testing::VisitResult(1, 0.0)}))));
histogram_tester.ExpectUniqueSample(
- "History.Clusters.Backend.ClusterSize.Min", 2, 1);
+ "History.Clusters.Backend.ClusterSize.Min", 1, 1);
histogram_tester.ExpectUniqueSample(
- "History.Clusters.Backend.ClusterSize.Max", 2, 1);
+ "History.Clusters.Backend.ClusterSize.Max", 1, 1);
histogram_tester.ExpectUniqueSample(
"History.Clusters.Backend.NumKeywordsPerCluster.Min", 0, 1);
histogram_tester.ExpectUniqueSample(
@@ -236,10 +271,11 @@ TEST_F(OnDeviceClusteringWithoutContentBackendTest, DedupeClusters) {
testing::CreateDefaultAnnotatedVisit(2, GURL("https://google.com/"));
visits.push_back(visit2);
- std::vector<history::Cluster> result_clusters = ClusterVisits(visits);
+ std::vector<history::Cluster> result_clusters =
+ ClusterVisits(ClusteringRequestSource::kJourneysPage, visits);
EXPECT_THAT(testing::ToVisitResults(result_clusters),
- ElementsAre(ElementsAre(testing::VisitResult(1, 0.0),
- testing::VisitResult(2, 1.0, {1}))));
+ ElementsAre(ElementsAre(testing::VisitResult(
+ 2, 1.0, {testing::VisitResult(1, 0.0)}))));
}
TEST_F(OnDeviceClusteringWithoutContentBackendTest,
@@ -256,7 +292,8 @@ TEST_F(OnDeviceClusteringWithoutContentBackendTest,
visit2.referring_visit_of_redirect_chain_start = 1;
visits.push_back(visit2);
- std::vector<history::Cluster> result_clusters = ClusterVisits(visits);
+ std::vector<history::Cluster> result_clusters =
+ ClusterVisits(ClusteringRequestSource::kJourneysPage, visits);
EXPECT_THAT(testing::ToVisitResults(result_clusters),
ElementsAre(ElementsAre(testing::VisitResult(1, 1.0),
testing::VisitResult(2, 1.0))));
@@ -296,17 +333,19 @@ TEST_F(OnDeviceClusteringWithoutContentBackendTest, MultipleClusters) {
testing::CreateDefaultAnnotatedVisit(3, GURL("https://whatever.com/"));
visits.push_back(visit3);
- std::vector<history::Cluster> result_clusters = ClusterVisits(visits);
- EXPECT_THAT(testing::ToVisitResults(result_clusters),
- ElementsAre(ElementsAre(testing::VisitResult(1, 0.0),
- testing::VisitResult(2, 1.0),
- testing::VisitResult(4, 1.0, {1})),
- ElementsAre(testing::VisitResult(3, 1.0)),
- ElementsAre(testing::VisitResult(10, 1.0))));
+ std::vector<history::Cluster> result_clusters =
+ ClusterVisits(ClusteringRequestSource::kJourneysPage, visits);
+ EXPECT_THAT(
+ testing::ToVisitResults(result_clusters),
+ ElementsAre(ElementsAre(testing::VisitResult(2, 1.0),
+ testing::VisitResult(
+ 4, 1.0, {testing::VisitResult(1, 0.0)})),
+ ElementsAre(testing::VisitResult(3, 1.0)),
+ ElementsAre(testing::VisitResult(10, 1.0))));
histogram_tester.ExpectUniqueSample(
"History.Clusters.Backend.ClusterSize.Min", 1, 1);
histogram_tester.ExpectUniqueSample(
- "History.Clusters.Backend.ClusterSize.Max", 3, 1);
+ "History.Clusters.Backend.ClusterSize.Max", 2, 1);
histogram_tester.ExpectUniqueSample(
"History.Clusters.Backend.NumKeywordsPerCluster.Min", 0, 1);
histogram_tester.ExpectUniqueSample(
@@ -338,11 +377,12 @@ TEST_F(OnDeviceClusteringWithoutContentBackendTest,
visit3.visit_row.visit_time = base::Time::Now() + base::Hours(2);
visits.push_back(visit3);
- std::vector<history::Cluster> result_clusters = ClusterVisits(visits);
+ std::vector<history::Cluster> result_clusters =
+ ClusterVisits(ClusteringRequestSource::kJourneysPage, visits);
EXPECT_THAT(testing::ToVisitResults(result_clusters),
- ElementsAre(ElementsAre(testing::VisitResult(1, 1.0),
- testing::VisitResult(2, 1.0)),
- ElementsAre(testing::VisitResult(3, 1.0))));
+ ElementsAre(ElementsAre(testing::VisitResult(3, 1.0)),
+ ElementsAre(testing::VisitResult(2, 1.0),
+ testing::VisitResult(1, 1.0))));
histogram_tester.ExpectUniqueSample(
"History.Clusters.Backend.ClusterSize.Min", 1, 1);
histogram_tester.ExpectUniqueSample(
@@ -411,12 +451,13 @@ TEST_F(OnDeviceClusteringWithContentBackendTest, ClusterOnContent) {
visit5.referring_visit_of_redirect_chain_start = 6;
visits.push_back(visit5);
- std::vector<history::Cluster> result_clusters = ClusterVisits(visits);
- EXPECT_THAT(
- testing::ToVisitResults(result_clusters),
- ElementsAre(ElementsAre(
- testing::VisitResult(1, 0.0), testing::VisitResult(2, 1.0),
- testing::VisitResult(4, 1.0, {1}), testing::VisitResult(10, 0.5))));
+ std::vector<history::Cluster> result_clusters =
+ ClusterVisits(ClusteringRequestSource::kJourneysPage, visits);
+ EXPECT_THAT(testing::ToVisitResults(result_clusters),
+ ElementsAre(ElementsAre(
+ testing::VisitResult(2, 1.0),
+ testing::VisitResult(4, 1.0, {testing::VisitResult(1, 0.0)}),
+ testing::VisitResult(10, 0.5))));
}
TEST_F(OnDeviceClusteringWithContentBackendTest,
@@ -459,16 +500,18 @@ TEST_F(OnDeviceClusteringWithContentBackendTest,
visit5.content_annotations.model_annotations.entities = {{"irrelevant", 1}};
visits.push_back(visit5);
- std::vector<history::Cluster> result_clusters = ClusterVisits(visits);
- EXPECT_THAT(testing::ToVisitResults(result_clusters),
- ElementsAre(ElementsAre(testing::VisitResult(1, 0.0),
- testing::VisitResult(2, 1.0),
- testing::VisitResult(4, 1.0, {1})),
- ElementsAre(testing::VisitResult(10, 1.0))));
+ std::vector<history::Cluster> result_clusters =
+ ClusterVisits(ClusteringRequestSource::kJourneysPage, visits);
+ EXPECT_THAT(
+ testing::ToVisitResults(result_clusters),
+ ElementsAre(ElementsAre(testing::VisitResult(2, 1.0),
+ testing::VisitResult(
+ 4, 1.0, {testing::VisitResult(1, 0.0)})),
+ ElementsAre(testing::VisitResult(10, 1.0))));
histogram_tester.ExpectUniqueSample(
"History.Clusters.Backend.ClusterSize.Min", 1, 1);
histogram_tester.ExpectUniqueSample(
- "History.Clusters.Backend.ClusterSize.Max", 3, 1);
+ "History.Clusters.Backend.ClusterSize.Max", 2, 1);
histogram_tester.ExpectUniqueSample(
"History.Clusters.Backend.NumKeywordsPerCluster.Min", 1, 1);
histogram_tester.ExpectUniqueSample(
@@ -523,47 +566,54 @@ TEST_F(OnDeviceClusteringWithAllTheBackendsTest,
history::AnnotatedVisit visit3 = testing::CreateDefaultAnnotatedVisit(
3, GURL("http://non-default-engine.com/?q=nometadata#whatever"));
- visit2.content_annotations.model_annotations.entities = {
+ visit3.content_annotations.model_annotations.entities = {
history::VisitContentModelAnnotations::Category("nometadata", 30),
};
+ visit3.content_annotations.search_terms = u"nometadata";
+ visit3.content_annotations.search_normalized_url =
+ GURL("http://non-default-engine.com/?q=nometadata");
visit3.content_annotations.model_annotations.page_topics_model_version = 127;
visit3.content_annotations.model_annotations.visibility_score = 0.5;
visits.push_back(visit3);
- std::vector<history::Cluster> result_clusters = ClusterVisits(visits);
+ std::vector<history::Cluster> result_clusters =
+ ClusterVisits(ClusteringRequestSource::kJourneysPage, visits);
ASSERT_EQ(result_clusters.size(), 2u);
- EXPECT_THAT(testing::ToVisitResults(result_clusters),
- ElementsAre(ElementsAre(testing::VisitResult(1, 0.0, {}, true),
- testing::VisitResult(2, 1.0, {1}, true)),
- ElementsAre(testing::VisitResult(3, 1.0, {}, true))));
+ EXPECT_THAT(
+ testing::ToVisitResults(result_clusters),
+ ElementsAre(
+ ElementsAre(testing::VisitResult(
+ 2, 1.0, {testing::VisitResult(1, 0.0, {}, u"foo")}, u"foo")),
+ ElementsAre(testing::VisitResult(3, 1.0, {}, u"nometadata"))));
// Make sure visits are normalized.
history::Cluster cluster = result_clusters.at(0);
- ASSERT_EQ(cluster.visits.size(), 2u);
- // The first visit should have a normalized URL.
- EXPECT_EQ(cluster.visits.at(0).normalized_url,
- GURL("http://default-engine.com/?q=foo"));
- EXPECT_THAT(cluster.visits.at(0)
- .annotated_visit.content_annotations.model_annotations
- .visibility_score,
- FloatEq(-1.0));
- // The second visit should have its original URL as the normalized URL and
+ ASSERT_EQ(cluster.visits.size(), 1u);
+ // The first visit should have its original URL as the normalized URL and
// also have its entities rewritten.
- history::ClusterVisit second_result_visit = cluster.visits.at(1);
- EXPECT_EQ(second_result_visit.normalized_url,
+ history::ClusterVisit better_visit = cluster.visits.at(0);
+ EXPECT_EQ(better_visit.normalized_url,
GURL("http://default-engine.com/?q=foo"));
std::vector<history::VisitContentModelAnnotations::Category> entities =
- second_result_visit.annotated_visit.content_annotations.model_annotations
+ better_visit.annotated_visit.content_annotations.model_annotations
.entities;
ASSERT_EQ(entities.size(), 1u);
EXPECT_EQ(entities.at(0).id, "rewritten-foo");
std::vector<history::VisitContentModelAnnotations::Category> categories =
- second_result_visit.annotated_visit.content_annotations.model_annotations
+ better_visit.annotated_visit.content_annotations.model_annotations
.categories;
ASSERT_EQ(categories.size(), 1u);
EXPECT_EQ(categories.at(0).id, "category-foo");
- EXPECT_THAT(second_result_visit.annotated_visit.content_annotations
- .model_annotations.visibility_score,
+ EXPECT_THAT(better_visit.annotated_visit.content_annotations.model_annotations
+ .visibility_score,
FloatEq(0.5));
+ // The second visit should have a normalized URL, but be the worse duplicate.
+ EXPECT_EQ(cluster.visits.at(0).duplicate_visits.at(0).normalized_url,
+ GURL("http://default-engine.com/?q=foo"));
+ EXPECT_THAT(cluster.visits.at(0)
+ .duplicate_visits.at(0)
+ .annotated_visit.content_annotations.model_annotations
+ .visibility_score,
+ FloatEq(-1));
history::Cluster cluster2 = result_clusters.at(1);
ASSERT_EQ(cluster2.visits.size(), 1u);
@@ -580,7 +630,7 @@ TEST_F(OnDeviceClusteringWithAllTheBackendsTest,
histogram_tester.ExpectUniqueSample(
"History.Clusters.Backend.ClusterSize.Min", 1, 1);
histogram_tester.ExpectUniqueSample(
- "History.Clusters.Backend.ClusterSize.Max", 2, 1);
+ "History.Clusters.Backend.ClusterSize.Max", 1, 1);
histogram_tester.ExpectUniqueSample(
"History.Clusters.Backend.NumKeywordsPerCluster.Min", 0, 1);
histogram_tester.ExpectUniqueSample(
@@ -591,5 +641,166 @@ TEST_F(OnDeviceClusteringWithAllTheBackendsTest,
"History.Clusters.Backend.BatchEntityLookupSize", 2, 1);
}
+class EngagementCacheOnDeviceClusteringWithoutContentBackendTest
+ : public OnDeviceClusteringWithoutContentBackendTest,
+ public ::testing::WithParamInterface<bool> {
+ public:
+ EngagementCacheOnDeviceClusteringWithoutContentBackendTest() {
+ const base::FieldTrialParams on_device_clustering_feature_parameters = {
+ {"content_clustering_enabled", "false"},
+ {"dedupe_similar_visits", "false"},
+ {"min_page_topics_model_version_for_visibility", "125"},
+ {"include_categories_in_keywords", "true"},
+ {"exclude_keywords_from_noisy_visits", "false"}};
+
+ if (GetParam()) {
+ scoped_feature_list_.InitWithFeaturesAndParameters(
+ {{features::kOnDeviceClustering,
+ on_device_clustering_feature_parameters},
+ {{features::kUseEngagementScoreCache}, {}}},
+ {});
+ } else {
+ scoped_feature_list_.InitWithFeaturesAndParameters(
+ {{features::kOnDeviceClustering,
+ on_device_clustering_feature_parameters}},
+ {features::kUseEngagementScoreCache});
+ }
+ }
+
+ bool IsCacheStoreFeatureEnabled() const { return GetParam(); }
+
+ private:
+ base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+TEST_P(EngagementCacheOnDeviceClusteringWithoutContentBackendTest,
+ EngagementScoreCache) {
+ base::HistogramTester histogram_tester;
+ std::vector<history::AnnotatedVisit> visits;
+
+ // Add 2 different hosts to |visits|.
+ history::AnnotatedVisit visit1 =
+ testing::CreateDefaultAnnotatedVisit(1, GURL("https://github.com/"));
+ visits.push_back(visit1);
+
+ history::AnnotatedVisit visit2 =
+ testing::CreateDefaultAnnotatedVisit(2, GURL("https://github.com/"));
+ visits.push_back(visit2);
+
+ history::AnnotatedVisit visit3 =
+ testing::CreateDefaultAnnotatedVisit(4, GURL("https://github.com/"));
+ visits.push_back(visit3);
+
+ history::AnnotatedVisit visit4 =
+ testing::CreateDefaultAnnotatedVisit(10, GURL("https://github.com/"));
+ visits.push_back(visit4);
+
+ history::AnnotatedVisit visit5 =
+ testing::CreateDefaultAnnotatedVisit(3, GURL("https://github2.com/"));
+ visits.push_back(visit5);
+
+ std::vector<history::Cluster> result_clusters_1 =
+ ClusterVisits(ClusteringRequestSource::kJourneysPage, visits);
+ EXPECT_EQ(IsCacheStoreFeatureEnabled() ? 2u : 5u,
+ GetSiteEngagementGetScoreInvocationCount());
+
+ // No new queries should be issued when cache store is enabled.
+ std::vector<history::Cluster> result_clusters_2 =
+ ClusterVisits(ClusteringRequestSource::kJourneysPage, visits);
+ EXPECT_EQ(IsCacheStoreFeatureEnabled() ? 2u : 10u,
+ GetSiteEngagementGetScoreInvocationCount());
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ All,
+ EngagementCacheOnDeviceClusteringWithoutContentBackendTest,
+ ::testing::Bool());
+
+class BatchedClusteringTaskOnDeviceClusteringWithoutContentBackendTest
+ : public OnDeviceClusteringWithoutContentBackendTest,
+ public ::testing::WithParamInterface<
+ std::tuple<bool, ClusteringRequestSource>> {
+ public:
+ BatchedClusteringTaskOnDeviceClusteringWithoutContentBackendTest() {
+ const base::FieldTrialParams on_device_clustering_feature_parameters = {
+ {"content_clustering_enabled", "false"},
+ {"dedupe_similar_visits", "false"},
+ {"min_page_topics_model_version_for_visibility", "125"},
+ {"include_categories_in_keywords", "true"},
+ {"exclude_keywords_from_noisy_visits", "false"}};
+
+ base::test::ScopedFeatureList::FeatureAndParams on_device_clustering(
+ features::kOnDeviceClustering, on_device_clustering_feature_parameters);
+
+ // expected_size_of_batches is 1.
+ const base::FieldTrialParams batched_clustering_feature_parameters = {
+ {"clustering_task_batch_size", "1"}};
+ base::test::ScopedFeatureList::FeatureAndParams batched_clustering(
+ features::kSplitClusteringTasksToSmallerBatches,
+ batched_clustering_feature_parameters);
+
+ if (IsBatchingEnabled()) {
+ scoped_feature_list_.InitWithFeaturesAndParameters(
+ {{on_device_clustering, batched_clustering}}, {});
+ } else {
+ scoped_feature_list_.InitWithFeaturesAndParameters(
+ {{features::kOnDeviceClustering,
+ on_device_clustering_feature_parameters}},
+ {features::kSplitClusteringTasksToSmallerBatches});
+ }
+ }
+
+ bool IsBatchingEnabled() const { return std::get<0>(GetParam()); }
+
+ ClusteringRequestSource GetClusteringRequestSource() const {
+ return std::get<1>(GetParam());
+ }
+
+ private:
+ base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+TEST_P(BatchedClusteringTaskOnDeviceClusteringWithoutContentBackendTest,
+ Baseline) {
+ base::HistogramTester histogram_tester;
+ std::vector<history::AnnotatedVisit> visits;
+
+ // Add 1000 visits to |visits|.
+ for (int i = 0; i < 1000; ++i) {
+ visits.push_back(testing::CreateDefaultAnnotatedVisit(
+ i + 1, GURL("https://github.com/")));
+ }
+
+ std::vector<history::Cluster> result_clusters_1 =
+ ClusterVisits(GetClusteringRequestSource(), visits);
+ EXPECT_EQ(1u, GetSiteEngagementGetScoreInvocationCount());
+
+ size_t expected_number_of_batches = 1;
+ size_t expected_size_of_batches = 1000;
+ if (IsBatchingEnabled() &&
+ GetClusteringRequestSource() ==
+ ClusteringRequestSource::kKeywordCacheGeneration) {
+ expected_number_of_batches = 1000;
+ expected_size_of_batches = 1;
+ }
+
+ histogram_tester.ExpectTotalCount(
+ "Journeys.PartialOnBatchEntityMetadataRetrieved.BatchSize",
+ expected_number_of_batches);
+ histogram_tester.ExpectUniqueSample(
+ "Journeys.PartialOnBatchEntityMetadataRetrieved.BatchSize",
+ expected_size_of_batches, expected_number_of_batches);
+}
+
+const bool kDirectExecutorEnabled[]{true, false};
+
+INSTANTIATE_TEST_SUITE_P(
+ BatchedClusteringTaskOnDeviceClusteringWithoutContentBackendTest,
+ BatchedClusteringTaskOnDeviceClusteringWithoutContentBackendTest,
+ ::testing::Combine(
+ ::testing::ValuesIn(kDirectExecutorEnabled),
+ ::testing::Values(ClusteringRequestSource::kJourneysPage,
+ ClusteringRequestSource::kKeywordCacheGeneration)));
+
} // namespace
} // namespace history_clusters
diff --git a/chromium/components/history_clusters/core/on_device_clustering_features.cc b/chromium/components/history_clusters/core/on_device_clustering_features.cc
index e49f842870e..4090f3d45cf 100644
--- a/chromium/components/history_clusters/core/on_device_clustering_features.cc
+++ b/chromium/components/history_clusters/core/on_device_clustering_features.cc
@@ -17,6 +17,13 @@ namespace features {
const base::Feature kOnDeviceClustering{"HistoryClustersOnDeviceClustering",
base::FEATURE_ENABLED_BY_DEFAULT};
+const base::Feature kUseEngagementScoreCache{"JourneysUseEngagementScoreCache",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+
+const base::Feature kSplitClusteringTasksToSmallerBatches{
+ "JourneysSplitClusteringTasksToSmallerBatches",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+
base::TimeDelta ClusterNavigationTimeCutoff() {
return base::Minutes(GetFieldTrialParamByFeatureAsInt(
kOnDeviceClustering, "navigation_time_cutoff_minutes", 60));
@@ -114,6 +121,12 @@ float SearchResultsPageRankingWeight() {
return std::max(0.f, weight);
}
+float HasPageTitleRankingWeight() {
+ float weight = GetFieldTrialParamByFeatureAsDouble(
+ kOnDeviceClustering, "has_page_title_ranking_weight", 2.0);
+ return std::max(0.f, weight);
+}
+
bool ContentClusterOnIntersectionSimilarity() {
return GetFieldTrialParamByFeatureAsBool(
kOnDeviceClustering, "use_content_clustering_intersection_similarity",
@@ -135,5 +148,16 @@ bool ShouldExcludeKeywordsFromNoisyVisits() {
kOnDeviceClustering, "exclude_keywords_from_noisy_visits", false);
}
+size_t GetClusteringTasksBatchSize() {
+ return GetFieldTrialParamByFeatureAsInt(
+ features::kSplitClusteringTasksToSmallerBatches,
+ "clustering_task_batch_size", 250);
+}
+
+bool ShouldSplitClustersAtSearchVisits() {
+ return GetFieldTrialParamByFeatureAsBool(
+ kOnDeviceClustering, "split_clusters_at_search_visits", true);
+}
+
} // namespace features
} // namespace history_clusters
diff --git a/chromium/components/history_clusters/core/on_device_clustering_features.h b/chromium/components/history_clusters/core/on_device_clustering_features.h
index 4923484c3f0..4e0f676756e 100644
--- a/chromium/components/history_clusters/core/on_device_clustering_features.h
+++ b/chromium/components/history_clusters/core/on_device_clustering_features.h
@@ -17,6 +17,12 @@ namespace features {
// Enables configuring the on-device clustering backend.
extern const base::Feature kOnDeviceClustering;
+// Uses an in-memory cache that stores engagement score.
+extern const base::Feature kUseEngagementScoreCache;
+
+// Splits clustering task into smaller batches.
+extern const base::Feature kSplitClusteringTasksToSmallerBatches;
+
// Returns the maximum duration between navigations that
// a visit can be considered for the same cluster.
base::TimeDelta ClusterNavigationTimeCutoff();
@@ -81,6 +87,10 @@ float BookmarkRankingWeight();
// visits within a cluster. Will always be greater than or equal to 0.
float SearchResultsPageRankingWeight();
+// Returns the weight to use for visits that have page titles ranking visits
+// within a cluster. Will always be greater than or equal to 0.
+float HasPageTitleRankingWeight();
+
// Returns true if content clustering should use the intersection similarity
// score. Note, if this is used, the threshold used for clustering by content
// score should be < .5 (see ContentClusteringSimilarityThreshold above) or the
@@ -99,6 +109,12 @@ bool ShouldIncludeCategoriesInKeywords();
// user (i.e. highly engaged, non-SRP).
bool ShouldExcludeKeywordsFromNoisyVisits();
+// Returns the default batch size for annotating visits when clustering.
+size_t GetClusteringTasksBatchSize();
+
+// Whether to split the clusters when a search visit is encountered.
+bool ShouldSplitClustersAtSearchVisits();
+
} // namespace features
} // namespace history_clusters
diff --git a/chromium/components/history_clusters/core/on_device_clustering_util.cc b/chromium/components/history_clusters/core/on_device_clustering_util.cc
index 1463aaa9ccb..296b069b2fa 100644
--- a/chromium/components/history_clusters/core/on_device_clustering_util.cc
+++ b/chromium/components/history_clusters/core/on_device_clustering_util.cc
@@ -5,12 +5,13 @@
#include "components/history_clusters/core/on_device_clustering_util.h"
#include "base/containers/contains.h"
+#include "components/history_clusters/core/history_clusters_util.h"
#include "components/history_clusters/core/on_device_clustering_features.h"
namespace history_clusters {
void MergeDuplicateVisitIntoCanonicalVisit(
- const history::ClusterVisit& duplicate_visit,
+ history::ClusterVisit&& duplicate_visit,
history::ClusterVisit& canonical_visit) {
// Upgrade the canonical visit's annotations (i.e. is-bookmarked) with
// those of the duplicate visits.
@@ -43,6 +44,11 @@ void MergeDuplicateVisitIntoCanonicalVisit(
}
}
+ // Merge over the model annotations (categories and entities) too.
+ canonical_visit.annotated_visit.content_annotations.model_annotations
+ .MergeFrom(duplicate_visit.annotated_visit.content_annotations
+ .model_annotations);
+
// Roll up the visit duration from the duplicate visit into the canonical
// visit.
canonical_visit.annotated_visit.visit_row.visit_duration +=
@@ -63,25 +69,39 @@ void MergeDuplicateVisitIntoCanonicalVisit(
: duplicate_foreground_duration;
}
- // Add the duplicate visit into the canonical visit's duplicate IDs.
- canonical_visit.duplicate_visit_ids.push_back(
- duplicate_visit.annotated_visit.visit_row.visit_id);
+ // Update the canonical_visit with the more recent timestamp.
+ canonical_visit.annotated_visit.visit_row.visit_time =
+ std::max(canonical_visit.annotated_visit.visit_row.visit_time,
+ duplicate_visit.annotated_visit.visit_row.visit_time);
+
+ canonical_visit.duplicate_visits.push_back(std::move(duplicate_visit));
}
-base::flat_set<history::VisitID> CalculateAllDuplicateVisitsForCluster(
- const history::Cluster& cluster) {
- base::flat_set<history::VisitID> duplicate_visit_ids;
- for (const auto& visit : cluster.visits) {
- duplicate_visit_ids.insert(visit.duplicate_visit_ids.begin(),
- visit.duplicate_visit_ids.end());
+void SortClusters(std::vector<history::Cluster>* clusters) {
+ DCHECK(clusters);
+ // Within each cluster, sort visits.
+ for (auto& cluster : *clusters) {
+ StableSortVisits(&cluster.visits);
}
- return duplicate_visit_ids;
+
+ // After that, sort clusters reverse-chronologically based on their highest
+ // scored visit.
+ base::ranges::stable_sort(*clusters, [&](auto& c1, auto& c2) {
+ DCHECK(!c1.visits.empty());
+ base::Time c1_time = c1.visits.front().annotated_visit.visit_row.visit_time;
+
+ DCHECK(!c2.visits.empty());
+ base::Time c2_time = c2.visits.front().annotated_visit.visit_row.visit_time;
+
+ // Use c1 > c2 to get more recent clusters BEFORE older clusters.
+ return c1_time > c2_time;
+ });
}
bool IsNoisyVisit(const history::ClusterVisit& visit) {
return visit.engagement_score >
features::NoisyClusterVisitEngagementThreshold() &&
- !visit.is_search_visit;
+ visit.search_terms.empty();
}
} // namespace history_clusters
diff --git a/chromium/components/history_clusters/core/on_device_clustering_util.h b/chromium/components/history_clusters/core/on_device_clustering_util.h
index 65c83f16528..bcc0de40598 100644
--- a/chromium/components/history_clusters/core/on_device_clustering_util.h
+++ b/chromium/components/history_clusters/core/on_device_clustering_util.h
@@ -9,15 +9,15 @@
namespace history_clusters {
-// Merges |duplicate_visit| into |canonical_visit|.
+// Moves |duplicate_visit| into |canonical_visit|'s list of duplicate visits.
+// |duplicate_visit| should be considered invalid after this call.
void MergeDuplicateVisitIntoCanonicalVisit(
- const history::ClusterVisit& duplicate_visit,
+ history::ClusterVisit&& duplicate_visit,
history::ClusterVisit& canonical_visit);
-// Calculates all the visits within |cluster| that are considered
-// "duplicates" and stores their ids in |duplicate_visit_ids|.
-base::flat_set<history::VisitID> CalculateAllDuplicateVisitsForCluster(
- const history::Cluster& cluster);
+// Enforces the reverse-chronological invariant of clusters, as well the
+// by-score sorting of visits within clusters. Exposed for testing.
+void SortClusters(std::vector<history::Cluster>* clusters);
// Whether the visit is considered a noisy visit (i.e. high engagement,
// non-SRP).
diff --git a/chromium/components/history_clusters/core/on_device_clustering_util_unittest.cc b/chromium/components/history_clusters/core/on_device_clustering_util_unittest.cc
index 120a12224cd..91e39a1d6df 100644
--- a/chromium/components/history_clusters/core/on_device_clustering_util_unittest.cc
+++ b/chromium/components/history_clusters/core/on_device_clustering_util_unittest.cc
@@ -5,6 +5,7 @@
#include "components/history_clusters/core/on_device_clustering_util.h"
#include "base/test/task_environment.h"
+#include "components/history/core/browser/url_row.h"
#include "components/history_clusters/core/clustering_test_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -36,6 +37,13 @@ TEST_F(OnDeviceClusteringUtilTest, MergeDuplicateVisitIntoCanonicalVisit) {
duplicate_visit.annotated_visit.context_annotations
.total_foreground_duration = base::Seconds(20);
+ duplicate_visit.annotated_visit.content_annotations.model_annotations
+ .visibility_score = 0.6;
+ duplicate_visit.annotated_visit.content_annotations.model_annotations
+ .categories.emplace_back("category1", 40);
+ duplicate_visit.annotated_visit.content_annotations.model_annotations.entities
+ .emplace_back("entity1", 20);
+
history::ClusterVisit canonical_visit =
testing::CreateClusterVisit(testing::CreateDefaultAnnotatedVisit(
2, GURL("https://example.com/normalized")));
@@ -54,8 +62,13 @@ TEST_F(OnDeviceClusteringUtilTest, MergeDuplicateVisitIntoCanonicalVisit) {
false;
canonical_visit.annotated_visit.context_annotations
.total_foreground_duration = base::Seconds(20);
+ canonical_visit.annotated_visit.content_annotations.model_annotations
+ .visibility_score = 0.5;
+ canonical_visit.annotated_visit.content_annotations.model_annotations
+ .categories.emplace_back("category1", 20);
- MergeDuplicateVisitIntoCanonicalVisit(duplicate_visit, canonical_visit);
+ MergeDuplicateVisitIntoCanonicalVisit(std::move(duplicate_visit),
+ canonical_visit);
EXPECT_TRUE(
canonical_visit.annotated_visit.context_annotations.omnibox_url_copied);
EXPECT_TRUE(
@@ -76,46 +89,112 @@ TEST_F(OnDeviceClusteringUtilTest, MergeDuplicateVisitIntoCanonicalVisit) {
EXPECT_EQ(canonical_visit.annotated_visit.context_annotations
.total_foreground_duration,
base::Seconds(20 * 2));
-}
-TEST_F(OnDeviceClusteringUtilTest, CalculateAllDuplicateVisitsForCluster) {
- history::ClusterVisit visit = testing::CreateClusterVisit(
- testing::CreateDefaultAnnotatedVisit(1, GURL("https://google.com/")));
- history::ClusterVisit visit2 = testing::CreateClusterVisit(
- testing::CreateDefaultAnnotatedVisit(2, GURL("https://foo.com/")));
- visit2.duplicate_visit_ids = {1};
-
- history::Cluster cluster;
- cluster.visits = {visit, visit2};
+ EXPECT_FLOAT_EQ(canonical_visit.annotated_visit.content_annotations
+ .model_annotations.visibility_score,
+ 0.5);
+
+ ASSERT_EQ(canonical_visit.annotated_visit.content_annotations
+ .model_annotations.categories.size(),
+ 1U);
+ EXPECT_EQ(
+ canonical_visit.annotated_visit.content_annotations.model_annotations
+ .categories[0]
+ .id,
+ "category1");
+ EXPECT_EQ(
+ canonical_visit.annotated_visit.content_annotations.model_annotations
+ .categories[0]
+ .weight,
+ 40);
+
+ ASSERT_EQ(canonical_visit.annotated_visit.content_annotations
+ .model_annotations.entities.size(),
+ 1U);
+ EXPECT_EQ(
+ canonical_visit.annotated_visit.content_annotations.model_annotations
+ .entities[0]
+ .id,
+ "entity1");
+ EXPECT_EQ(
+ canonical_visit.annotated_visit.content_annotations.model_annotations
+ .entities[0]
+ .weight,
+ 20);
+}
- EXPECT_THAT(CalculateAllDuplicateVisitsForCluster(cluster),
- UnorderedElementsAre(1));
+TEST_F(OnDeviceClusteringUtilTest, SortClusters) {
+ std::vector<history::Cluster> clusters;
+ // This first cluster is meant to validate that the higher scoring "visit 1"
+ // gets sorted to the top, even though "visit 1" is older than "visit 2".
+ // It's to validate the within-cluster sorting.
+ clusters.push_back(history::Cluster(
+ 0,
+ {
+ testing::CreateClusterVisit(
+ testing::CreateDefaultAnnotatedVisit(2, GURL("https://two.com/"),
+ base::Time::FromTimeT(10)),
+ absl::nullopt, 0.5),
+ testing::CreateClusterVisit(
+ testing::CreateDefaultAnnotatedVisit(1, GURL("https://one.com/"),
+ base::Time::FromTimeT(5)),
+ absl::nullopt, 0.9),
+ },
+ {}));
+ // The second cluster is lower scoring, but newer, because the top visit is
+ // newer. It should be sorted above the first cluster because of reverse
+ // chronological between-cluster sorting.
+ clusters.push_back(history::Cluster(
+ 0,
+ {
+ testing::CreateClusterVisit(
+ testing::CreateDefaultAnnotatedVisit(2, GURL("https://two.com/"),
+ base::Time::FromTimeT(10)),
+ absl::nullopt, 0.1),
+ },
+ {}));
+
+ SortClusters(&clusters);
+
+ ASSERT_EQ(clusters.size(), 2u);
+
+ auto& visits = clusters[0].visits;
+ ASSERT_EQ(visits.size(), 1u);
+ EXPECT_EQ(visits[0].annotated_visit.url_row.url(), "https://two.com/");
+ EXPECT_FLOAT_EQ(visits[0].score, 0.1);
+
+ visits = clusters[1].visits;
+ ASSERT_EQ(visits.size(), 2u);
+ EXPECT_EQ(visits[0].annotated_visit.url_row.url(), "https://one.com/");
+ EXPECT_FLOAT_EQ(visits[0].score, 0.9);
+ EXPECT_EQ(visits[1].annotated_visit.url_row.url(), "https://two.com/");
+ EXPECT_FLOAT_EQ(visits[1].score, 0.5);
}
TEST_F(OnDeviceClusteringUtilTest, IsNoisyVisitSearchHighEngagementVisit) {
history::ClusterVisit visit;
- visit.is_search_visit = true;
+ visit.search_terms = u"search";
visit.engagement_score = 90.0;
EXPECT_FALSE(IsNoisyVisit(visit));
}
TEST_F(OnDeviceClusteringUtilTest, IsNoisyVisitNotSearchHighEngagementVisit) {
history::ClusterVisit visit;
- visit.is_search_visit = false;
+ visit.search_terms = u"";
visit.engagement_score = 90.0;
EXPECT_TRUE(IsNoisyVisit(visit));
}
TEST_F(OnDeviceClusteringUtilTest, IsNoisyVisitNotSearchLowEngagementVisit) {
history::ClusterVisit visit;
- visit.is_search_visit = false;
+ visit.search_terms = u"";
visit.engagement_score = 1.0;
EXPECT_FALSE(IsNoisyVisit(visit));
}
TEST_F(OnDeviceClusteringUtilTest, IsNoisyVisitSearchLowEngagementVisit) {
history::ClusterVisit visit;
- visit.is_search_visit = true;
+ visit.search_terms = u"search";
visit.engagement_score = 1.0;
EXPECT_FALSE(IsNoisyVisit(visit));
}
diff --git a/chromium/components/history_clusters/core/proto/BUILD.gn b/chromium/components/history_clusters/core/proto/BUILD.gn
deleted file mode 100644
index 20e7e6e4afa..00000000000
--- a/chromium/components/history_clusters/core/proto/BUILD.gn
+++ /dev/null
@@ -1,9 +0,0 @@
-# Copyright 2021 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.
-
-import("//third_party/protobuf/proto_library.gni")
-
-proto_library("proto") {
- sources = [ "clusters.proto" ]
-}
diff --git a/chromium/components/history_clusters/core/proto/clusters.proto b/chromium/components/history_clusters/core/proto/clusters.proto
deleted file mode 100644
index 23faed267c2..00000000000
--- a/chromium/components/history_clusters/core/proto/clusters.proto
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright 2021 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.
-syntax = "proto3";
-
-option optimize_for = LITE_RUNTIME;
-
-package history_clusters.proto;
-
-// Below this line sourced from Google3 for debug (non-production) usage only.
-
-message GetClustersRequest {
- // Represents a set of visits.
- repeated AnnotatedVisit visits = 1;
- // The experiment name that controls the clustering behavior served for
- // this request.
- string experiment_name = 2;
-}
-
-message GetClustersResponse {
- // Represents a set of clusters calculated from the request.
- repeated Cluster clusters = 1;
-}
-
-message AnnotatedVisit {
- // The ID associated with this visit.
- int64 visit_id = 1;
- // The URL for the visit.
- string url = 2;
- // The origin for the visit.
- string origin = 3;
- // The amount of time the page load was in the foreground in seconds.
- // TODO(tommycli): Kind of a misnomer. We are just using visit_duration,
- // which may or may not be in the foreground.
- int64 foreground_time_secs = 4;
- // Relative time of navigation for this page load.
- int64 navigation_time_ms = 5;
- // Site engagement score rounded to nearest ten.
- int64 site_engagement_score = 6;
- // The page end reason.
- int64 page_end_reason = 7;
- // Page transition.
- int64 page_transition = 8;
- // Whether the page load originated from Google Search.
- bool is_from_google_search = 9;
- // The visit ID that referred this visit, if not a new navigation.
- int64 referring_visit_id = 10;
-}
-
-message ClusterVisit {
- // The ID of the visit where visit_id corresponds to the visit in the history
- // table.
- int64 visit_id = 1;
- // The score associated with this visit.
- //
- // Used for calculating ordering of visits within a cluster.
- float score = 2;
-}
-
-message Cluster {
- reserved 2;
-
- // The keywords that the cluster contains/is related to.
- repeated string keywords = 1;
- // The visits that are attached to this cluster.
- repeated ClusterVisit cluster_visits = 3;
-}
diff --git a/chromium/components/history_clusters/core/query_clusters_state.cc b/chromium/components/history_clusters/core/query_clusters_state.cc
new file mode 100644
index 00000000000..2ee185c37a2
--- /dev/null
+++ b/chromium/components/history_clusters/core/query_clusters_state.cc
@@ -0,0 +1,148 @@
+// Copyright 2022 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.
+
+#include "components/history_clusters/core/query_clusters_state.h"
+
+#include <set>
+
+#include "base/memory/ref_counted_delete_on_sequence.h"
+#include "base/metrics/histogram_functions.h"
+#include "base/task/thread_pool.h"
+#include "components/history_clusters/core/history_clusters_service.h"
+#include "components/history_clusters/core/history_clusters_util.h"
+#include "url/gurl.h"
+
+namespace history_clusters {
+
+// Helper class that lives and is destroyed on the `sequenced_task_runner`,
+// although it's created on the main thread. It allows us to store state that
+// is only accessed on `sequenced_task_runner` that persists between batches.
+class QueryClustersState::PostProcessor
+ : public base::RefCountedDeleteOnSequence<PostProcessor> {
+ public:
+ PostProcessor(scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner,
+ const std::string query)
+ : base::RefCountedDeleteOnSequence<PostProcessor>(sequenced_task_runner),
+ query_(query) {}
+ PostProcessor(const PostProcessor& other) = delete;
+ PostProcessor& operator=(const PostProcessor& other) = delete;
+
+ std::vector<history::Cluster> PostProcess(
+ std::vector<history::Cluster> clusters) {
+ ApplySearchQuery(query_, &clusters);
+ CullNonProminentOrDuplicateClusters(query_, &clusters,
+ &seen_single_visit_cluster_urls_);
+ return clusters;
+ }
+
+ private:
+ friend class base::RefCountedDeleteOnSequence<PostProcessor>;
+ friend class base::DeleteHelper<PostProcessor>;
+
+ // Ref-counted object should only be deleted via ref-counting.
+ ~PostProcessor() = default;
+
+ const std::string query_;
+
+ // URLs of single-visit non-prominent clusters we've already seen.
+ std::set<GURL> seen_single_visit_cluster_urls_;
+};
+
+QueryClustersState::QueryClustersState(
+ base::WeakPtr<HistoryClustersService> service,
+ const std::string& query)
+ : service_(service),
+ query_(query),
+ post_processing_task_runner_(base::ThreadPool::CreateSequencedTaskRunner(
+ {base::MayBlock(), base::TaskPriority::USER_VISIBLE})),
+ post_processing_state_(
+ base::MakeRefCounted<PostProcessor>(post_processing_task_runner_,
+ query)) {}
+
+QueryClustersState::~QueryClustersState() = default;
+
+void QueryClustersState::LoadNextBatchOfClusters(ResultCallback callback) {
+ if (!service_)
+ return;
+
+ base::TimeTicks query_start_time = base::TimeTicks::Now();
+ base::Time end_time = continuation_end_time_.value_or(base::Time());
+ service_->QueryClusters(ClusteringRequestSource::kJourneysPage,
+ /*begin_time=*/base::Time(), end_time,
+ base::BindOnce(&QueryClustersState::OnGotRawClusters,
+ weak_factory_.GetWeakPtr(),
+ query_start_time, std::move(callback)),
+ &task_tracker_);
+}
+
+void QueryClustersState::OnGotRawClusters(
+ base::TimeTicks query_start_time,
+ ResultCallback callback,
+ std::vector<history::Cluster> clusters,
+ base::Time continuation_end_time) const {
+ // Post-process the clusters (expensive task) on an anonymous thread to
+ // prevent janks.
+ base::ElapsedTimer post_processing_timer; // Create here to time the task.
+
+ size_t clusters_from_backend_count = clusters.size();
+ post_processing_task_runner_->PostTaskAndReplyWithResult(
+ FROM_HERE,
+ base::BindOnce(&PostProcessor::PostProcess, post_processing_state_,
+ std::move(clusters)),
+ base::BindOnce(
+ &QueryClustersState::OnGotClusters, weak_factory_.GetWeakPtr(),
+ std::move(post_processing_timer), clusters_from_backend_count,
+ query_start_time, std::move(callback), continuation_end_time));
+}
+
+void QueryClustersState::OnGotClusters(base::ElapsedTimer post_processing_timer,
+ size_t clusters_from_backend_count,
+ base::TimeTicks query_start_time,
+ ResultCallback callback,
+ base::Time continuation_end_time,
+ std::vector<history::Cluster> clusters) {
+ base::UmaHistogramLongTimes("History.Clusters.ProcessClustersDuration",
+ post_processing_timer.Elapsed());
+
+ if (clusters_from_backend_count > 0) {
+ // Log the percentage of clusters that get filtered (e.g., 100 - % of
+ // clusters that remain).
+ base::UmaHistogramCounts100(
+ "History.Clusters.PercentClustersFilteredByQuery",
+ static_cast<int>(100 - (clusters.size() /
+ (1.0 * clusters_from_backend_count) * 100)));
+ }
+
+ continuation_end_time_.reset();
+ if (!continuation_end_time.is_null())
+ continuation_end_time_ = continuation_end_time;
+
+ // In case no clusters came back, recursively ask for more here. We do this
+ // to fulfill the mojom contract where we always return at least one cluster,
+ // or we exhaust History. We don't do this in the service because of task
+ // tracker lifetime difficulty. In practice, this only happens when the user
+ // has a search query that doesn't match any of the clusters in the "page".
+ // https://crbug.com/1263728
+ //
+ // This is distinct from the "tall monitor" case because the page may already
+ // be full of clusters. In that case, the WebUI would not know to make another
+ // request for clusters.
+ if (clusters.empty() && continuation_end_time_.has_value()) {
+ LoadNextBatchOfClusters(std::move(callback));
+ return;
+ }
+
+ bool can_load_more = continuation_end_time_.has_value();
+ std::move(callback).Run(query_, std::move(clusters), can_load_more,
+ is_continuation_);
+
+ // Further responses should be consider continuations.
+ is_continuation_ = true;
+
+ // Log metrics after delivering the results to the page.
+ base::TimeDelta service_latency = base::TimeTicks::Now() - query_start_time;
+ base::UmaHistogramTimes("History.Clusters.ServiceLatency", service_latency);
+}
+
+} // namespace history_clusters
diff --git a/chromium/components/history_clusters/core/query_clusters_state.h b/chromium/components/history_clusters/core/query_clusters_state.h
new file mode 100644
index 00000000000..e8dc66960c3
--- /dev/null
+++ b/chromium/components/history_clusters/core/query_clusters_state.h
@@ -0,0 +1,107 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_HISTORY_CLUSTERS_CORE_QUERY_CLUSTERS_STATE_H_
+#define COMPONENTS_HISTORY_CLUSTERS_CORE_QUERY_CLUSTERS_STATE_H_
+
+#include <vector>
+
+#include "base/callback_forward.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/task/cancelable_task_tracker.h"
+#include "base/task/sequenced_task_runner.h"
+#include "base/time/time.h"
+#include "base/timer/elapsed_timer.h"
+#include "components/history/core/browser/history_types.h"
+#include "components/history_clusters/core/history_clusters_types.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace history_clusters {
+
+class HistoryClustersService;
+
+// This object encapsulates the results of a query to HistoryClustersService.
+// It manages fetching more pages from the clustering backend as the user
+// scrolls down.
+//
+// In the future, it will also manage reusing results for new searches, as well
+// as collapsing duplicate clusters across pages.
+//
+// It's the history_clusters equivalent to history::QueryHistoryState.
+class QueryClustersState {
+ public:
+ // `is_continuation` is true for all 'next-page' responses, but false for the
+ // first page.
+ using ResultCallback =
+ base::OnceCallback<void(const std::string& query,
+ std::vector<history::Cluster> cluster_batch,
+ bool can_load_more,
+ bool is_continuation)>;
+
+ QueryClustersState(base::WeakPtr<HistoryClustersService> service,
+ const std::string& query);
+ ~QueryClustersState();
+
+ QueryClustersState(const QueryClustersState&) = delete;
+
+ // Returns the current query the state contains.
+ const std::string& query() const { return query_; }
+
+ // Used to request another batch of clusters of the same query.
+ void LoadNextBatchOfClusters(ResultCallback callback);
+
+ private:
+ friend class QueryClustersStateTest;
+
+ // Private class containing state that's only accessed on
+ // `post_processing_task_runner`.
+ class PostProcessor;
+
+ // Callback to `LoadNextBatchOfClusters()`.
+ void OnGotRawClusters(base::TimeTicks query_start_time,
+ ResultCallback callback,
+ std::vector<history::Cluster> clusters,
+ base::Time continuation_end_time) const;
+
+ // Callback to `OnGotRawClusters()`.
+ void OnGotClusters(base::ElapsedTimer post_processing_timer,
+ size_t clusters_from_backend_count,
+ base::TimeTicks query_start_time,
+ ResultCallback callback,
+ base::Time continuation_end_time,
+ std::vector<history::Cluster> clusters);
+
+ // A weak pointer to the service in case we outlive the service.
+ // Never nullptr, except in unit tests.
+ const base::WeakPtr<HistoryClustersService> service_;
+
+ // The string query the user entered into the searchbox.
+ const std::string query_;
+
+ // A nullopt `continuation_end_time` means we have exhausted History.
+ // Note that this differs from History itself, which uses base::Time() as the
+ // value to indicate we've exhausted history. I've found that to be not
+ // explicit enough in practice. This value will never be base::Time().
+ absl::optional<base::Time> continuation_end_time_;
+
+ // True for all 'next-page' responses, but false for the first page.
+ bool is_continuation_ = false;
+
+ // Used only to fast-cancel tasks in case we are destroyed.
+ base::CancelableTaskTracker task_tracker_;
+
+ // A task runner to run all the post-processing tasks on.
+ scoped_refptr<base::SequencedTaskRunner> post_processing_task_runner_;
+
+ // The private state used for post-processing. It's created on the main
+ // thread, but used and freed on `post_processing_task_runner`.
+ scoped_refptr<PostProcessor> post_processing_state_;
+
+ base::WeakPtrFactory<QueryClustersState> weak_factory_{this};
+};
+
+} // namespace history_clusters
+
+#endif // COMPONENTS_HISTORY_CLUSTERS_CORE_QUERY_CLUSTERS_STATE_H_
diff --git a/chromium/components/history_clusters/core/query_clusters_state_unittest.cc b/chromium/components/history_clusters/core/query_clusters_state_unittest.cc
new file mode 100644
index 00000000000..5f7ee1401a3
--- /dev/null
+++ b/chromium/components/history_clusters/core/query_clusters_state_unittest.cc
@@ -0,0 +1,130 @@
+// Copyright 2022 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.
+
+#include "components/history_clusters/core/query_clusters_state.h"
+
+#include "base/run_loop.h"
+#include "base/test/bind.h"
+#include "base/test/metrics/histogram_tester.h"
+#include "base/test/task_environment.h"
+#include "components/history/core/browser/history_types.h"
+#include "components/history_clusters/core/history_clusters_service_test_api.h"
+#include "components/history_clusters/core/history_clusters_types.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace history_clusters {
+
+class QueryClustersStateTest : public testing::Test {
+ public:
+ QueryClustersStateTest()
+ : task_environment_(
+ base::test::SingleThreadTaskEnvironment::TimeSource::MOCK_TIME) {}
+
+ QueryClustersStateTest(const QueryClustersStateTest&) = delete;
+ QueryClustersStateTest& operator=(const QueryClustersStateTest&) = delete;
+
+ protected:
+ std::vector<history::Cluster> InjectRawClustersAndAwaitPostProcessing(
+ QueryClustersState* state,
+ const std::vector<history::Cluster>& raw_clusters) {
+ // This block injects the fake `raw_clusters` data for post-processing and
+ // spins the message loop until we finish post-processing.
+ std::vector<history::Cluster> result;
+ {
+ base::RunLoop loop;
+ state->OnGotRawClusters(
+ base::TimeTicks(),
+ base::BindLambdaForTesting(
+ [&](const std::string& query,
+ std::vector<history::Cluster> cluster_batch,
+ bool can_load_more, bool is_continuation) {
+ result = std::move(cluster_batch);
+ loop.Quit();
+ }),
+ raw_clusters, base::Time());
+ loop.Run();
+ }
+ return result;
+ }
+
+ base::test::TaskEnvironment task_environment_;
+};
+
+TEST_F(QueryClustersStateTest, PostProcessingOccursAndLogsHistograms) {
+ base::HistogramTester histogram_tester;
+ QueryClustersState state(nullptr, "");
+
+ std::vector<history::Cluster> raw_clusters;
+ raw_clusters.push_back(
+ history::Cluster(1, {}, {u"keyword_one"},
+ /*should_show_on_prominent_ui_surfaces=*/false));
+ raw_clusters.push_back(
+ history::Cluster(2, {}, {u"keyword_two"},
+ /*should_show_on_prominent_ui_surfaces=*/true));
+
+ auto result = InjectRawClustersAndAwaitPostProcessing(&state, raw_clusters);
+
+ // Just a basic test to verify that post-processing did indeed occur.
+ // Detailed tests for the behavior of the filtering are in
+ // `HistoryClustersUtil`.
+ ASSERT_EQ(result.size(), 1U);
+ EXPECT_EQ(result[0].cluster_id, 2);
+
+ histogram_tester.ExpectBucketCount(
+ "History.Clusters.PercentClustersFilteredByQuery", 50, 1);
+ histogram_tester.ExpectTotalCount("History.Clusters.ServiceLatency", 1);
+}
+
+TEST_F(QueryClustersStateTest, CrossBatchDeduplication) {
+ QueryClustersState state(nullptr, "myquery");
+
+ {
+ std::vector<history::Cluster> raw_clusters;
+ // Verify that non-matching prominent clusters are filtered out.
+ raw_clusters.push_back(
+ history::Cluster(1, {}, {u"keyword_one"},
+ /*should_show_on_prominent_ui_surfaces=*/true));
+ // Verify that matching non-prominent clusters still are shown.
+ raw_clusters.push_back(
+ history::Cluster(2, {GetHardcodedClusterVisit(1)}, {u"myquery"},
+ /*should_show_on_prominent_ui_surfaces=*/false));
+
+ auto result = InjectRawClustersAndAwaitPostProcessing(&state, raw_clusters);
+
+ ASSERT_EQ(result.size(), 1U);
+ EXPECT_EQ(result[0].cluster_id, 2);
+ ASSERT_EQ(result[0].visits.size(), 1U);
+ EXPECT_EQ(result[0].visits[0].annotated_visit.visit_row.visit_id, 1);
+ }
+
+ // Send through a second batch of raw clusters. This verifies the stateful
+ // cross-batch de-duplication.
+ {
+ std::vector<history::Cluster> raw_clusters;
+ // Verify that a matching non-prominent non-duplicate cluster is still
+ // allowed.
+ raw_clusters.push_back(
+ history::Cluster(3, {GetHardcodedClusterVisit(2)}, {u"myquery"},
+ /*should_show_on_prominent_ui_surfaces=*/false));
+
+ // Verify that a matching non-prominent duplicate cluster is filtered out.
+ raw_clusters.push_back(
+ history::Cluster(4, {GetHardcodedClusterVisit(1)}, {u"myquery"},
+ /*should_show_on_prominent_ui_surfaces=*/false));
+
+ // Verify that a matching prominent duplicate cluster is still allowed.
+ raw_clusters.push_back(
+ history::Cluster(5, {GetHardcodedClusterVisit(1)}, {u"myquery"},
+ /*should_show_on_prominent_ui_surfaces=*/true));
+
+ auto result = InjectRawClustersAndAwaitPostProcessing(&state, raw_clusters);
+
+ ASSERT_EQ(result.size(), 2U);
+ EXPECT_EQ(result[0].cluster_id, 3);
+ EXPECT_EQ(result[1].cluster_id, 5);
+ }
+}
+
+} // namespace history_clusters
diff --git a/chromium/components/history_clusters/core/ranking_cluster_finalizer.cc b/chromium/components/history_clusters/core/ranking_cluster_finalizer.cc
index 9f1e895d511..7ad00bf1049 100644
--- a/chromium/components/history_clusters/core/ranking_cluster_finalizer.cc
+++ b/chromium/components/history_clusters/core/ranking_cluster_finalizer.cc
@@ -4,18 +4,13 @@
#include "components/history_clusters/core/ranking_cluster_finalizer.h"
+#include "base/containers/adapters.h"
#include "components/history_clusters/core/on_device_clustering_util.h"
namespace history_clusters {
namespace {
-bool IsCanonicalVisit(const base::flat_set<history::VisitID>& duplicate_ids,
- const history::ClusterVisit& visit) {
- return duplicate_ids.find(visit.annotated_visit.visit_row.visit_id) ==
- duplicate_ids.end();
-}
-
// See https://en.wikipedia.org/wiki/Smoothstep.
float clamp(float x, float lowerlimit, float upperlimit) {
if (x < lowerlimit)
@@ -41,25 +36,16 @@ RankingClusterFinalizer::~RankingClusterFinalizer() = default;
void RankingClusterFinalizer::FinalizeCluster(history::Cluster& cluster) {
base::flat_map<history::VisitID, VisitScores> url_visit_scores;
- const base::flat_set<history::VisitID>& duplicate_visit_ids =
- CalculateAllDuplicateVisitsForCluster(cluster);
- CalculateVisitDurationScores(cluster, url_visit_scores, duplicate_visit_ids);
- CalculateVisitAttributeScoring(cluster, url_visit_scores,
- duplicate_visit_ids);
- ComputeFinalVisitScores(cluster, url_visit_scores, duplicate_visit_ids);
+ CalculateVisitDurationScores(cluster, url_visit_scores);
+ CalculateVisitAttributeScoring(cluster, url_visit_scores);
+ ComputeFinalVisitScores(cluster, url_visit_scores);
}
void RankingClusterFinalizer::CalculateVisitAttributeScoring(
history::Cluster& cluster,
- base::flat_map<history::VisitID, VisitScores>& url_visit_scores,
- const base::flat_set<history::VisitID>& duplicate_visit_ids) {
- for (auto visit_it = cluster.visits.rbegin();
- visit_it != cluster.visits.rend(); ++visit_it) {
- auto& visit = *visit_it;
- if (!IsCanonicalVisit(duplicate_visit_ids, visit)) {
- continue;
- }
+ base::flat_map<history::VisitID, VisitScores>& url_visit_scores) {
+ for (const history::ClusterVisit& visit : base::Reversed(cluster.visits)) {
auto it = url_visit_scores.find(visit.annotated_visit.visit_row.visit_id);
if (it == url_visit_scores.end()) {
auto visit_score = VisitScores();
@@ -75,18 +61,21 @@ void RankingClusterFinalizer::CalculateVisitAttributeScoring(
}
// Check if the visit contained a search query.
- if (visit.is_search_visit) {
+ if (!visit.search_terms.empty()) {
it->second.set_is_srp();
}
+ if (!visit.annotated_visit.url_row.title().empty()) {
+ it->second.set_has_page_title();
+ }
+
// Additional/future attribute checks go here.
}
}
void RankingClusterFinalizer::CalculateVisitDurationScores(
history::Cluster& cluster,
- base::flat_map<history::VisitID, VisitScores>& url_visit_scores,
- const base::flat_set<history::VisitID>& duplicate_visit_ids) {
+ base::flat_map<history::VisitID, VisitScores>& url_visit_scores) {
// |max_visit_duration| and |max_foreground_duration| must be > 0 for
// reshaping between 0 and 1.
base::TimeDelta max_visit_duration = base::Seconds(1);
@@ -103,12 +92,7 @@ void RankingClusterFinalizer::CalculateVisitDurationScores(
visit.annotated_visit.context_annotations.total_foreground_duration;
}
}
- for (auto visit_it = cluster.visits.rbegin();
- visit_it != cluster.visits.rend(); ++visit_it) {
- auto& visit = *visit_it;
- if (!IsCanonicalVisit(duplicate_visit_ids, visit)) {
- continue;
- }
+ for (const history::ClusterVisit& visit : base::Reversed(cluster.visits)) {
float visit_duration_score =
Smoothstep(0.0f, max_visit_duration.InSecondsF(),
visit.annotated_visit.visit_row.visit_duration.InSecondsF());
@@ -134,21 +118,17 @@ void RankingClusterFinalizer::CalculateVisitDurationScores(
void RankingClusterFinalizer::ComputeFinalVisitScores(
history::Cluster& cluster,
- base::flat_map<history::VisitID, VisitScores>& url_visit_scores,
- const base::flat_set<history::VisitID>& duplicate_visit_ids) {
+ base::flat_map<history::VisitID, VisitScores>& url_visit_scores) {
float max_score = -1.0;
- for (auto visit_it = cluster.visits.rbegin();
- visit_it != cluster.visits.rend(); ++visit_it) {
- auto& visit = *visit_it;
-
+ for (history::ClusterVisit& visit : base::Reversed(cluster.visits)) {
// Only canonical visits should have scores > 0.0.
- if (!IsCanonicalVisit(duplicate_visit_ids, visit)) {
+ for (auto& duplicate_visit : visit.duplicate_visits) {
// Check that no individual scores have been given a visit that is not
// canonical a score.
- DCHECK(url_visit_scores.find(visit.annotated_visit.visit_row.visit_id) ==
+ DCHECK(url_visit_scores.find(
+ duplicate_visit.annotated_visit.visit_row.visit_id) ==
url_visit_scores.end());
- visit.score = 0.0;
- continue;
+ duplicate_visit.score = 0.0;
}
// Determine the max score to use for normalizing all the scores.
@@ -167,9 +147,7 @@ void RankingClusterFinalizer::ComputeFinalVisitScores(
// Now normalize the score by `max_score` so they values are all between 0
// and 1.
- for (auto visit_it = cluster.visits.rbegin();
- visit_it != cluster.visits.rend(); ++visit_it) {
- auto& visit = *visit_it;
+ for (history::ClusterVisit& visit : base::Reversed(cluster.visits)) {
visit.score = visit.score / max_score;
}
}
diff --git a/chromium/components/history_clusters/core/ranking_cluster_finalizer.h b/chromium/components/history_clusters/core/ranking_cluster_finalizer.h
index e13a0dc1fa1..844dadabe2a 100644
--- a/chromium/components/history_clusters/core/ranking_cluster_finalizer.h
+++ b/chromium/components/history_clusters/core/ranking_cluster_finalizer.h
@@ -25,7 +25,8 @@ class VisitScores {
foreground_duration_score_ *
features::ForegroundDurationRankingWeight() +
bookmark_score_ * features::BookmarkRankingWeight() +
- srp_score_ * features::SearchResultsPageRankingWeight();
+ srp_score_ * features::SearchResultsPageRankingWeight() +
+ page_title_score_ * features::HasPageTitleRankingWeight();
}
void set_visit_duration_score(float score) { visit_duration_score_ = score; }
@@ -38,6 +39,8 @@ class VisitScores {
void set_is_srp() { srp_score_ = 1.0; }
+ void set_has_page_title() { page_title_score_ = 1.0; }
+
private:
// The score for the duration associated with a visit.
float visit_duration_score_ = 0.0;
@@ -47,6 +50,8 @@ class VisitScores {
float bookmark_score_ = 0.0;
// The score for whether the visit was on a search results page.
float srp_score_ = 0.0;
+ // The score for whether the visit had a page title.
+ float page_title_score_ = 0.0;
};
// A cluster finalizer that scores visits based on visit duration.
@@ -60,28 +65,22 @@ class RankingClusterFinalizer : public ClusterFinalizer {
private:
// Calculates the scores for the visits within |cluster| based on
- // their total visit duration and updates |url_visit_scores|. Only
- // visits not in |duplicate_visit_ids| will be scored.
+ // their total visit duration and updates |url_visit_scores|.
void CalculateVisitDurationScores(
history::Cluster& cluster,
- base::flat_map<history::VisitID, VisitScores>& url_visit_scores,
- const base::flat_set<history::VisitID>& duplicate_visit_ids);
+ base::flat_map<history::VisitID, VisitScores>& url_visit_scores);
// Calculates the scores for the visits within |cluster| based on
- // their binary attributes and updates |url_visit_scores|. Only
- // visits not in |duplicate_visit_ids| will be scored.
+ // their binary attributes and updates |url_visit_scores|.
void CalculateVisitAttributeScoring(
history::Cluster& cluster,
- base::flat_map<history::VisitID, VisitScores>& url_visit_scores,
- const base::flat_set<history::VisitID>& duplicate_visit_ids);
+ base::flat_map<history::VisitID, VisitScores>& url_visit_scores);
// Computes the final scores for each visit based on the current
- // individual scores for each visit in |url_visit_scores|. Only
- // visits not in |duplicate_visit_ids| will be scored.
+ // individual scores for each visit in |url_visit_scores|.
void ComputeFinalVisitScores(
history::Cluster& cluster,
- base::flat_map<history::VisitID, VisitScores>& url_visit_scores,
- const base::flat_set<history::VisitID>& duplicate_visit_ids);
+ base::flat_map<history::VisitID, VisitScores>& url_visit_scores);
};
} // namespace history_clusters
diff --git a/chromium/components/history_clusters/core/ranking_cluster_finalizer_unittest.cc b/chromium/components/history_clusters/core/ranking_cluster_finalizer_unittest.cc
index bef78791741..3ee6da7cba4 100644
--- a/chromium/components/history_clusters/core/ranking_cluster_finalizer_unittest.cc
+++ b/chromium/components/history_clusters/core/ranking_cluster_finalizer_unittest.cc
@@ -38,14 +38,14 @@ TEST_F(RankingClusterFinalizerTest, ScoreTwoVisitsSameURL) {
history::ClusterVisit visit2 = testing::CreateClusterVisit(
testing::CreateDefaultAnnotatedVisit(2, GURL("https://bar.com/")));
- visit2.duplicate_visit_ids.push_back(1);
+ visit2.duplicate_visits.push_back(visit);
history::Cluster cluster;
- cluster.visits = {visit, visit2};
+ cluster.visits = {visit2};
FinalizeCluster(cluster);
EXPECT_THAT(testing::ToVisitResults({cluster}),
- ElementsAre(ElementsAre(testing::VisitResult(1, 0.0),
- testing::VisitResult(2, 1.0, {1}))));
+ ElementsAre(ElementsAre(testing::VisitResult(
+ 2, 1.0, {testing::VisitResult(1, 0.0)}))));
}
TEST_F(RankingClusterFinalizerTest, ScoreTwoVisitsDifferentURLs) {
@@ -73,14 +73,14 @@ TEST_F(RankingClusterFinalizerTest, ScoreTwoVisitsSimilarURL) {
history::ClusterVisit visit2 =
testing::CreateClusterVisit(testing::CreateDefaultAnnotatedVisit(
2, GURL("https://example.com/normalized")));
- visit2.duplicate_visit_ids.push_back(1);
+ visit2.duplicate_visits.push_back(visit);
history::Cluster cluster;
- cluster.visits = {visit, visit2};
+ cluster.visits = {visit2};
FinalizeCluster(cluster);
EXPECT_THAT(testing::ToVisitResults({cluster}),
- ElementsAre(ElementsAre(testing::VisitResult(1, 0.0),
- testing::VisitResult(2, 1.0, {1}))));
+ ElementsAre(ElementsAre(testing::VisitResult(
+ 2, 1.0, {testing::VisitResult(1, 0.0)}))));
}
TEST_F(RankingClusterFinalizerTest, ScoreMultipleVisitsDifferentDurations) {
@@ -98,7 +98,7 @@ TEST_F(RankingClusterFinalizerTest, ScoreMultipleVisitsDifferentDurations) {
history::ClusterVisit visit4 = testing::CreateClusterVisit(
testing::CreateDefaultAnnotatedVisit(4, GURL("https://github.com/")));
visit4.annotated_visit.visit_row.visit_duration = base::Seconds(20);
- visit4.duplicate_visit_ids.push_back(1);
+ visit4.duplicate_visits.push_back(visit);
history::ClusterVisit visit5 =
testing::CreateClusterVisit(testing::CreateDefaultAnnotatedVisit(
@@ -107,13 +107,13 @@ TEST_F(RankingClusterFinalizerTest, ScoreMultipleVisitsDifferentDurations) {
visit5.annotated_visit.visit_row.visit_duration = base::Seconds(10);
history::Cluster cluster;
- cluster.visits = {visit, visit2, visit4, visit5};
+ cluster.visits = {visit2, visit4, visit5};
FinalizeCluster(cluster);
- EXPECT_THAT(
- testing::ToVisitResults({cluster}),
- ElementsAre(ElementsAre(
- testing::VisitResult(1, 0.0), testing::VisitResult(2, 1.0),
- testing::VisitResult(4, 1.0, {1}), testing::VisitResult(10, 0.5))));
+ EXPECT_THAT(testing::ToVisitResults({cluster}),
+ ElementsAre(ElementsAre(
+ testing::VisitResult(2, 1.0),
+ testing::VisitResult(4, 1.0, {testing::VisitResult(1, 0.0)}),
+ testing::VisitResult(10, 0.5))));
}
TEST_F(RankingClusterFinalizerTest, ScoreTwoVisitsSameURLBookmarked) {
@@ -124,14 +124,14 @@ TEST_F(RankingClusterFinalizerTest, ScoreTwoVisitsSameURLBookmarked) {
history::ClusterVisit visit2 = testing::CreateClusterVisit(
testing::CreateDefaultAnnotatedVisit(2, GURL("https://bar.com/")));
- visit2.duplicate_visit_ids.push_back(1);
+ visit2.duplicate_visits.push_back(visit);
history::Cluster cluster;
- cluster.visits = {visit, visit2};
+ cluster.visits = {visit2};
FinalizeCluster(cluster);
EXPECT_THAT(testing::ToVisitResults({cluster}),
- ElementsAre(ElementsAre(testing::VisitResult(1, 0.0),
- testing::VisitResult(2, 1.0, {1}))));
+ ElementsAre(ElementsAre(testing::VisitResult(
+ 2, 1.0, {testing::VisitResult(1, 0.0)}))));
}
TEST_F(RankingClusterFinalizerTest, ScoreTwoVisitsWithBookmarksAndDuration) {
@@ -190,43 +190,74 @@ TEST_F(RankingClusterFinalizerTest, ScoreTwoCanonicalSearchResultsPages) {
testing::CreateDefaultAnnotatedVisit(
1, GURL("https://google.com/search?q=whatever#abc")),
GURL("https://google.com/search?q=whatever"));
- visit.is_search_visit = true;
+ visit.search_terms = u"whatever";
history::ClusterVisit visit2 = testing::CreateClusterVisit(
testing::CreateDefaultAnnotatedVisit(
2, GURL("https://google.com/search?q=bar#abc")),
GURL("https://google.com/search?q=bar"));
- visit2.is_search_visit = true;
+ visit2.search_terms = u"bar";
history::Cluster cluster;
cluster.visits = {visit, visit2};
FinalizeCluster(cluster);
- EXPECT_THAT(testing::ToVisitResults({cluster}),
- ElementsAre(ElementsAre(testing::VisitResult(1, 1.0, {}, true),
- testing::VisitResult(2, 1.0, {}, true))));
+ EXPECT_THAT(
+ testing::ToVisitResults({cluster}),
+ ElementsAre(ElementsAre(testing::VisitResult(1, 1.0, {}, u"whatever"),
+ testing::VisitResult(2, 1.0, {}, u"bar"))));
}
TEST_F(RankingClusterFinalizerTest, ScoreSearchResultsPagesOneDuplicate) {
+ history::ClusterVisit visit2 = testing::CreateClusterVisit(
+ testing::CreateDefaultAnnotatedVisit(
+ 2, GURL("https://google.com/search?q=bar")),
+ GURL("https://google.com/search?q=bar"));
+ visit2.search_terms = u"bar";
+
// Visit2 is marked as a duplicate of visit
history::ClusterVisit visit = testing::CreateClusterVisit(
testing::CreateDefaultAnnotatedVisit(
1, GURL("https://google.com/search?q=whatever#abc")),
GURL("https://google.com/search?q=whatever"));
- visit.duplicate_visit_ids = {2};
- visit.is_search_visit = true;
+ visit.duplicate_visits = {visit2};
+ visit.search_terms = u"whatever";
+
+ history::Cluster cluster;
+ cluster.visits = {visit};
+ FinalizeCluster(cluster);
+ EXPECT_THAT(
+ testing::ToVisitResults({cluster}),
+ ElementsAre(ElementsAre(testing::VisitResult(
+ 1, 1.0, {testing::VisitResult(2, 0.0, {}, u"bar")}, u"whatever"))));
+}
+
+TEST_F(RankingClusterFinalizerTest, ScoreVisitsOnHasPageTitle) {
+ history::ClusterVisit visit1 = testing::CreateClusterVisit(
+ testing::CreateDefaultAnnotatedVisit(1, GURL("https://foo.com/")),
+ GURL("https://foo.com/"));
+ visit1.annotated_visit.url_row.set_title(u"chocolate");
history::ClusterVisit visit2 = testing::CreateClusterVisit(
- testing::CreateDefaultAnnotatedVisit(
- 2, GURL("https://google.com/search?q=bar")),
- GURL("https://google.com/search?q=bar"));
- visit2.is_search_visit = true;
+ testing::CreateDefaultAnnotatedVisit(2, GURL("https://bar.com/")),
+ GURL("https://bar.com/"));
+ visit2.annotated_visit.url_row.set_title(std::u16string());
+
+ history::ClusterVisit visit3 = testing::CreateClusterVisit(
+ testing::CreateDefaultAnnotatedVisit(3, GURL("https://baz.com/")),
+ GURL("https://baz.com/"));
+ visit3.annotated_visit.url_row.set_title(u"vanilla");
history::Cluster cluster;
- cluster.visits = {visit, visit2};
+ cluster.visits = {visit1, visit2, visit3};
FinalizeCluster(cluster);
EXPECT_THAT(testing::ToVisitResults({cluster}),
- ElementsAre(ElementsAre(testing::VisitResult(1, 1.0, {2}, true),
- testing::VisitResult(2, 0.0, {}, true))));
+ ElementsAre(ElementsAre(
+ testing::VisitResult(/*visit_id=*/1, /*score=*/1.0,
+ /*duplicate_visits=*/{}),
+ testing::VisitResult(/*visit_id=*/2, /*score=*/0.333333,
+ /*duplicate_visits=*/{}),
+ testing::VisitResult(/*visit_id=*/3, /*score=*/1.0,
+ /*duplicate_visits=*/{}))));
}
} // namespace
diff --git a/chromium/components/history_clusters/core/similar_visit_deduper_cluster_finalizer.cc b/chromium/components/history_clusters/core/similar_visit_deduper_cluster_finalizer.cc
index fc03077da27..2349022d08c 100644
--- a/chromium/components/history_clusters/core/similar_visit_deduper_cluster_finalizer.cc
+++ b/chromium/components/history_clusters/core/similar_visit_deduper_cluster_finalizer.cc
@@ -4,6 +4,8 @@
#include "components/history_clusters/core/similar_visit_deduper_cluster_finalizer.h"
+#include "base/ranges/algorithm.h"
+#include "components/history/core/browser/history_types.h"
#include "components/history_clusters/core/on_device_clustering_util.h"
namespace history_clusters {
@@ -14,18 +16,18 @@ struct SimilarVisit {
SimilarVisit() = default;
explicit SimilarVisit(const history::ClusterVisit& visit)
: title(visit.annotated_visit.url_row.title()),
- host(visit.normalized_url.host()) {}
+ url_for_deduping(visit.url_for_deduping) {}
SimilarVisit(const SimilarVisit&) = default;
~SimilarVisit() = default;
std::u16string title;
- std::string host;
+ GURL url_for_deduping;
struct Comp {
bool operator()(const SimilarVisit& lhs, const SimilarVisit& rhs) const {
if (lhs.title != rhs.title)
return lhs.title < rhs.title;
- return lhs.host < rhs.host;
+ return lhs.url_for_deduping < rhs.url_for_deduping;
}
};
};
@@ -39,24 +41,37 @@ SimilarVisitDeduperClusterFinalizer::~SimilarVisitDeduperClusterFinalizer() =
void SimilarVisitDeduperClusterFinalizer::FinalizeCluster(
history::Cluster& cluster) {
- base::flat_map<SimilarVisit, size_t, SimilarVisit::Comp>
- similar_visit_to_last_visit_idx;
- for (auto visit_it = cluster.visits.rbegin();
- visit_it != cluster.visits.rend(); ++visit_it) {
- auto& visit = *visit_it;
- SimilarVisit similar_visit(visit);
- auto it = similar_visit_to_last_visit_idx.find(similar_visit);
- if (it != similar_visit_to_last_visit_idx.end()) {
- DCHECK(it != similar_visit_to_last_visit_idx.end());
- DCHECK_LT(it->second, cluster.visits.size());
- auto& canonical_visit = cluster.visits.at(it->second);
- MergeDuplicateVisitIntoCanonicalVisit(visit, canonical_visit);
- } else {
- similar_visit_to_last_visit_idx.insert(
- {similar_visit,
- std::distance(cluster.visits.begin(), visit_it.base()) - 1});
- }
+ base::flat_map<SimilarVisit, history::ClusterVisit*, SimilarVisit::Comp>
+ similar_visit_to_canonical_visits;
+ // First do a prepass to find the canonical visit for each SimilarVisit key.
+ // This simply marks the last visit in `cluster` with any given SimilarVisit
+ // key as the canonical one.
+ for (auto& visit : cluster.visits) {
+ similar_visit_to_canonical_visits[SimilarVisit(visit)] = &visit;
}
+
+ cluster.visits.erase(
+ base::ranges::remove_if(
+ cluster.visits,
+ [&](auto& visit) {
+ // We are guaranteed to find a matching canonical visit, due to our
+ // prepass above.
+ auto it =
+ similar_visit_to_canonical_visits.find(SimilarVisit(visit));
+ DCHECK(it != similar_visit_to_canonical_visits.end());
+ history::ClusterVisit* canonical_visit = it->second;
+
+ // If a DIFFERENT visit is the canonical visit for this key, merge
+ // this visit in, and mark this visit as to be removed.
+ if (&visit != canonical_visit) {
+ MergeDuplicateVisitIntoCanonicalVisit(std::move(visit),
+ *canonical_visit);
+ return true;
+ }
+
+ return false;
+ }),
+ cluster.visits.end());
}
} // namespace history_clusters
diff --git a/chromium/components/history_clusters/core/similar_visit_deduper_cluster_finalizer_unittest.cc b/chromium/components/history_clusters/core/similar_visit_deduper_cluster_finalizer_unittest.cc
index 1c5c66dfbe5..1fd06ac30f2 100644
--- a/chromium/components/history_clusters/core/similar_visit_deduper_cluster_finalizer_unittest.cc
+++ b/chromium/components/history_clusters/core/similar_visit_deduper_cluster_finalizer_unittest.cc
@@ -42,16 +42,16 @@ TEST_F(SimilarVisitDeduperClusterFinalizerTest, DedupeExactSimilarVisit) {
base::Seconds(20);
history::ClusterVisit canonical_visit = testing::CreateClusterVisit(
- testing::CreateDefaultAnnotatedVisit(2, GURL("https://google.com/abc")));
+ testing::CreateDefaultAnnotatedVisit(2, GURL("https://google.com/#abc")));
canonical_visit.annotated_visit.url_row.set_title(u"sametitle");
history::Cluster cluster;
cluster.visits = {visit, canonical_visit};
FinalizeCluster(cluster);
EXPECT_THAT(testing::ToVisitResults({cluster}),
- ElementsAre(ElementsAre(testing::VisitResult(1, 1.0),
- testing::VisitResult(2, 1.0, {1}))));
- const auto& actual_canonical_visit = cluster.visits.at(1);
+ ElementsAre(ElementsAre(testing::VisitResult(
+ 2, 1.0, {testing::VisitResult(1, 1.0)}))));
+ const auto& actual_canonical_visit = cluster.visits.at(0);
// Make sure total foreground duration is updated correctly even if some don't
// have the field populated.
EXPECT_EQ(actual_canonical_visit.annotated_visit.context_annotations
@@ -65,7 +65,7 @@ TEST_F(SimilarVisitDeduperClusterFinalizerTest,
testing::CreateDefaultAnnotatedVisit(1, GURL("https://google.com/")));
history::ClusterVisit canonical_visit = testing::CreateClusterVisit(
- testing::CreateDefaultAnnotatedVisit(2, GURL("https://foo.com/")));
+ testing::CreateDefaultAnnotatedVisit(2, GURL("https://google.com/")));
canonical_visit.annotated_visit.url_row.set_title(u"someothertitle");
history::Cluster cluster;
@@ -121,9 +121,9 @@ TEST_F(SimilarVisitDeduperClusterFinalizerTest, MergesAnnotations) {
cluster.visits = {duplicate_visit, canonical_visit};
FinalizeCluster(cluster);
EXPECT_THAT(testing::ToVisitResults({cluster}),
- ElementsAre(ElementsAre(testing::VisitResult(1, 1.0),
- testing::VisitResult(2, 1.0, {1}))));
- const auto& actual_canonical_visit = cluster.visits.at(1);
+ ElementsAre(ElementsAre(testing::VisitResult(
+ 2, 1.0, {testing::VisitResult(1, 1.0)}))));
+ const auto& actual_canonical_visit = cluster.visits.at(0);
EXPECT_TRUE(actual_canonical_visit.annotated_visit.context_annotations
.omnibox_url_copied);
EXPECT_TRUE(actual_canonical_visit.annotated_visit.context_annotations
diff --git a/chromium/components/history_clusters/core/single_visit_cluster_finalizer.cc b/chromium/components/history_clusters/core/single_visit_cluster_finalizer.cc
index f40849e690b..4087a7cda92 100644
--- a/chromium/components/history_clusters/core/single_visit_cluster_finalizer.cc
+++ b/chromium/components/history_clusters/core/single_visit_cluster_finalizer.cc
@@ -17,28 +17,7 @@ void SingleVisitClusterFinalizer::FinalizeCluster(history::Cluster& cluster) {
if (cluster.visits.size() <= 1) {
cluster.should_show_on_prominent_ui_surfaces = false;
metrics_recorder.set_was_filtered(true);
- return;
}
-
- int canonical_visits_seen = 0;
- base::flat_set<history::VisitID> duplicate_visit_ids =
- CalculateAllDuplicateVisitsForCluster(cluster);
- for (const auto& visit : cluster.visits) {
- if (!duplicate_visit_ids.contains(
- visit.annotated_visit.visit_row.visit_id)) {
- canonical_visits_seen++;
- }
- if (canonical_visits_seen > 1) {
- // Should not explicitly mark as false if multiple canonical visits in the
- // cluster. Just return early.
- return;
- }
- }
-
- // If we get here, then we have only seen at most 1 canonical visit. Do not
- // show this cluster on prominent UI surfaces.
- cluster.should_show_on_prominent_ui_surfaces = false;
- metrics_recorder.set_was_filtered(true);
}
} // namespace history_clusters
diff --git a/chromium/components/history_clusters/core/single_visit_cluster_finalizer_unittest.cc b/chromium/components/history_clusters/core/single_visit_cluster_finalizer_unittest.cc
index ee42c58776f..9f83fd6f0bf 100644
--- a/chromium/components/history_clusters/core/single_visit_cluster_finalizer_unittest.cc
+++ b/chromium/components/history_clusters/core/single_visit_cluster_finalizer_unittest.cc
@@ -77,10 +77,10 @@ TEST_F(SingleVisitClusterFinalizerTest,
testing::CreateDefaultAnnotatedVisit(1, GURL("https://google.com/")));
history::ClusterVisit visit2 = testing::CreateClusterVisit(
testing::CreateDefaultAnnotatedVisit(2, GURL("https://foo.com/")));
- visit2.duplicate_visit_ids = {1};
+ visit2.duplicate_visits = {visit};
history::Cluster cluster;
- cluster.visits = {visit, visit2};
+ cluster.visits = {visit2};
FinalizeCluster(cluster);
EXPECT_FALSE(cluster.should_show_on_prominent_ui_surfaces);
histogram_tester.ExpectUniqueSample(
diff --git a/chromium/components/history_clusters/core/url_deduper_cluster_finalizer.cc b/chromium/components/history_clusters/core/url_deduper_cluster_finalizer.cc
index 0f915415879..40ea34f58e0 100644
--- a/chromium/components/history_clusters/core/url_deduper_cluster_finalizer.cc
+++ b/chromium/components/history_clusters/core/url_deduper_cluster_finalizer.cc
@@ -4,6 +4,7 @@
#include "components/history_clusters/core/url_deduper_cluster_finalizer.h"
+#include "base/ranges/algorithm.h"
#include "components/history_clusters/core/on_device_clustering_util.h"
namespace history_clusters {
@@ -12,24 +13,34 @@ UrlDeduperClusterFinalizer::UrlDeduperClusterFinalizer() = default;
UrlDeduperClusterFinalizer::~UrlDeduperClusterFinalizer() = default;
void UrlDeduperClusterFinalizer::FinalizeCluster(history::Cluster& cluster) {
- base::flat_map<GURL, size_t> url_to_last_visit_idx;
- for (auto visit_it = cluster.visits.rbegin();
- visit_it != cluster.visits.rend(); ++visit_it) {
- auto& visit = *visit_it;
- auto visit_url = visit.normalized_url;
- auto it = url_to_last_visit_idx.find(visit_url);
- if (it != url_to_last_visit_idx.end()) {
- auto last_visit_it = url_to_last_visit_idx.find(visit_url);
- DCHECK(last_visit_it != url_to_last_visit_idx.end());
- DCHECK_LT(last_visit_it->second, cluster.visits.size());
- auto& canonical_visit = cluster.visits.at(last_visit_it->second);
- MergeDuplicateVisitIntoCanonicalVisit(visit, canonical_visit);
- } else {
- url_to_last_visit_idx.insert(
- {visit_url,
- std::distance(cluster.visits.begin(), visit_it.base()) - 1});
- }
+ base::flat_map<GURL, history::ClusterVisit*> url_to_canonical_visit;
+ // First do a prepass to find the canonical visit for each URL. This simply
+ // marks the last visit in `cluster` with any given URL as the canonical one.
+ for (auto& visit : cluster.visits) {
+ url_to_canonical_visit[visit.url_for_deduping] = &visit;
}
+
+ cluster.visits.erase(
+ base::ranges::remove_if(
+ cluster.visits,
+ [&](auto& visit) {
+ // We are guaranteed to find a matching canonical visit, due to our
+ // prepass above.
+ auto it = url_to_canonical_visit.find(visit.url_for_deduping);
+ DCHECK(it != url_to_canonical_visit.end());
+ history::ClusterVisit* canonical_visit = it->second;
+
+ // If a DIFFERENT visit is the canonical visit for this key, merge
+ // this visit in, and mark this visit as to be removed.
+ if (&visit != canonical_visit) {
+ MergeDuplicateVisitIntoCanonicalVisit(std::move(visit),
+ *canonical_visit);
+ return true;
+ }
+
+ return false;
+ }),
+ cluster.visits.end());
}
} // namespace history_clusters
diff --git a/chromium/components/history_clusters/core/url_deduper_cluster_finalizer_unittest.cc b/chromium/components/history_clusters/core/url_deduper_cluster_finalizer_unittest.cc
index 6842ca1fbea..51414d22f3f 100644
--- a/chromium/components/history_clusters/core/url_deduper_cluster_finalizer_unittest.cc
+++ b/chromium/components/history_clusters/core/url_deduper_cluster_finalizer_unittest.cc
@@ -46,9 +46,9 @@ TEST_F(UrlDeduperClusterFinalizerTest, DedupeExactURL) {
cluster.visits = {visit, canonical_visit};
FinalizeCluster(cluster);
EXPECT_THAT(testing::ToVisitResults({cluster}),
- ElementsAre(ElementsAre(testing::VisitResult(1, 1.0),
- testing::VisitResult(2, 1.0, {1}))));
- const auto& actual_canonical_visit = cluster.visits.at(1);
+ ElementsAre(ElementsAre(testing::VisitResult(
+ 2, 1.0, {testing::VisitResult(1, 1.0)}))));
+ const auto& actual_canonical_visit = cluster.visits.at(0);
// Make sure total foreground duration is updated correctly even if some don't
// have the field populated.
EXPECT_EQ(actual_canonical_visit.annotated_visit.context_annotations
@@ -86,9 +86,9 @@ TEST_F(UrlDeduperClusterFinalizerTest, DedupeNormalizedUrl) {
cluster.visits = {visit, canonical_visit};
FinalizeCluster(cluster);
EXPECT_THAT(testing::ToVisitResults({cluster}),
- ElementsAre(ElementsAre(testing::VisitResult(1, 1.0),
- testing::VisitResult(2, 1.0, {1}))));
- const auto& actual_canonical_visit = cluster.visits.at(1);
+ ElementsAre(ElementsAre(testing::VisitResult(
+ 2, 1.0, {testing::VisitResult(1, 1.0)}))));
+ const auto& actual_canonical_visit = cluster.visits.at(0);
// Make sure total foreground duration not updated if none of the visits have
// it populated.
EXPECT_EQ(actual_canonical_visit.annotated_visit.context_annotations
@@ -139,9 +139,9 @@ TEST_F(UrlDeduperClusterFinalizerTest, MergesAnnotations) {
cluster.visits = {duplicate_visit, canonical_visit};
FinalizeCluster(cluster);
EXPECT_THAT(testing::ToVisitResults({cluster}),
- ElementsAre(ElementsAre(testing::VisitResult(1, 1.0),
- testing::VisitResult(2, 1.0, {1}))));
- const auto& actual_canonical_visit = cluster.visits.at(1);
+ ElementsAre(ElementsAre(testing::VisitResult(
+ 2, 1.0, {testing::VisitResult(1, 1.0)}))));
+ const auto& actual_canonical_visit = cluster.visits.at(0);
EXPECT_TRUE(actual_canonical_visit.annotated_visit.context_annotations
.omnibox_url_copied);
EXPECT_TRUE(actual_canonical_visit.annotated_visit.context_annotations
diff --git a/chromium/components/image_fetcher/BUILD.gn b/chromium/components/image_fetcher/BUILD.gn
index db74499477e..a2927f56be3 100644
--- a/chromium/components/image_fetcher/BUILD.gn
+++ b/chromium/components/image_fetcher/BUILD.gn
@@ -20,6 +20,7 @@ android_library("java") {
"//content/public/android:content_main_dex_java",
"//third_party/androidx:androidx_annotation_annotation_java",
"//third_party/gif_player:gif_player_java",
+ "//url:gurl_java",
]
annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
srcjar_deps = [ "//components/image_fetcher/core:java_enums_srcjar" ]
@@ -69,5 +70,7 @@ java_library("junit") {
"//third_party/gif_player:gif_player_java",
"//third_party/junit",
"//third_party/mockito:mockito_java",
+ "//url:gurl_java",
+ "//url:gurl_junit_test_support",
]
}
diff --git a/chromium/components/image_fetcher/android/junit/src/org/chromium/components/image_fetcher/ImageFetcherBridgeTest.java b/chromium/components/image_fetcher/android/junit/src/org/chromium/components/image_fetcher/ImageFetcherBridgeTest.java
index bb2a40da7fb..a817ecfb20a 100644
--- a/chromium/components/image_fetcher/android/junit/src/org/chromium/components/image_fetcher/ImageFetcherBridgeTest.java
+++ b/chromium/components/image_fetcher/android/junit/src/org/chromium/components/image_fetcher/ImageFetcherBridgeTest.java
@@ -27,6 +27,7 @@ import org.robolectric.annotation.Config;
import org.chromium.base.Callback;
import org.chromium.base.test.BaseRobolectricTestRunner;
import org.chromium.components.embedder_support.simple_factory_key.SimpleFactoryKeyHandle;
+import org.chromium.url.JUnitTestGURLs;
import jp.tomorrowkey.android.gifplayer.BaseGifImage;
@@ -93,7 +94,8 @@ public class ImageFetcherBridgeTest {
mBridge.fetchImage(-1,
ImageFetcher.Params.createWithExpirationInterval(
- "url", "clientname", WIDTH_PX, HEIGHT_PX, EXPIRATION_INTERVAL_MINS),
+ JUnitTestGURLs.getGURL(JUnitTestGURLs.EXAMPLE_URL), "clientname", WIDTH_PX,
+ HEIGHT_PX, EXPIRATION_INTERVAL_MINS),
mBitmapCallback);
verify(mBitmapCallback).onResult(bitmap);
}
diff --git a/chromium/components/image_fetcher/android/junit/src/org/chromium/components/image_fetcher/ImageFetcherTest.java b/chromium/components/image_fetcher/android/junit/src/org/chromium/components/image_fetcher/ImageFetcherTest.java
index 37123700117..953f102b7f7 100644
--- a/chromium/components/image_fetcher/android/junit/src/org/chromium/components/image_fetcher/ImageFetcherTest.java
+++ b/chromium/components/image_fetcher/android/junit/src/org/chromium/components/image_fetcher/ImageFetcherTest.java
@@ -24,6 +24,8 @@ import org.robolectric.annotation.Config;
import org.chromium.base.Callback;
import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.url.GURL;
+import org.chromium.url.JUnitTestGURLs;
import jp.tomorrowkey.android.gifplayer.BaseGifImage;
@@ -33,7 +35,8 @@ import jp.tomorrowkey.android.gifplayer.BaseGifImage;
@RunWith(BaseRobolectricTestRunner.class)
@Config(manifest = Config.NONE)
public class ImageFetcherTest {
- private static final String URL = "https://www.example.com/image";
+ private static final GURL URL = JUnitTestGURLs.getGURL(JUnitTestGURLs.EXAMPLE_URL);
+ private static final GURL URL_2 = JUnitTestGURLs.getGURL(JUnitTestGURLs.URL_2);
private static final String CLIENT_NAME = "client";
private static final int WIDTH_PX = 100;
private static final int HEIGHT_PX = 200;
@@ -119,7 +122,7 @@ public class ImageFetcherTest {
public void testCreateParams() {
// Verifies params without size specified.
ImageFetcher.Params params = ImageFetcher.Params.create(URL, CLIENT_NAME);
- assertEquals(URL, params.url);
+ assertEquals(URL.getSpec(), params.url);
assertEquals(CLIENT_NAME, params.clientName);
assertEquals(0, params.width);
assertEquals(0, params.height);
@@ -127,7 +130,7 @@ public class ImageFetcherTest {
// Verifies params with size.
params = ImageFetcher.Params.create(URL, CLIENT_NAME, WIDTH_PX, HEIGHT_PX);
- assertEquals(URL, params.url);
+ assertEquals(URL.getSpec(), params.url);
assertEquals(CLIENT_NAME, params.clientName);
assertEquals(WIDTH_PX, params.width);
assertEquals(HEIGHT_PX, params.height);
@@ -139,7 +142,7 @@ public class ImageFetcherTest {
// Verifies params with expiration interval.
ImageFetcher.Params params = ImageFetcher.Params.createWithExpirationInterval(
URL, CLIENT_NAME, WIDTH_PX, HEIGHT_PX, EXPIRATION_INTERVAL);
- assertEquals(URL, params.url);
+ assertEquals(URL.getSpec(), params.url);
assertEquals(CLIENT_NAME, params.clientName);
assertEquals(WIDTH_PX, params.width);
assertEquals(HEIGHT_PX, params.height);
@@ -150,7 +153,7 @@ public class ImageFetcherTest {
public void testParamsEqual() {
// Different URLs.
ImageFetcher.Params params1 = ImageFetcher.Params.create(URL, CLIENT_NAME);
- ImageFetcher.Params params2 = ImageFetcher.Params.create("Not the same URL", CLIENT_NAME);
+ ImageFetcher.Params params2 = ImageFetcher.Params.create(URL_2, CLIENT_NAME);
assertFalse(params1.equals(params2));
assertFalse(params2.equals(params1));
assertNotEquals(params1.hashCode(), params2.hashCode());
diff --git a/chromium/components/infobars/README.md b/chromium/components/infobars/README.md
index 6c005f891c0..25e19005096 100644
--- a/chromium/components/infobars/README.md
+++ b/chromium/components/infobars/README.md
@@ -15,6 +15,10 @@ Infobars is a layered component
(https://sites.google.com/a/chromium.org/dev/developers/design-documents/layered-components-design)
to enable it to be shared cleanly on iOS.
+On Android, Infobars have been deprecated in favor of the new Message UI.
+Please consider using this new Message UI.
+See components/messages/README.md for more details.
+
Directory structure:
android/: Android-specific specializations
core/: Shared code that does not depend on src/content/
diff --git a/chromium/components/infobars/android/BUILD.gn b/chromium/components/infobars/android/BUILD.gn
index c110cd1edbe..a4871503121 100644
--- a/chromium/components/infobars/android/BUILD.gn
+++ b/chromium/components/infobars/android/BUILD.gn
@@ -18,6 +18,7 @@ android_resources("java_resources") {
"res/drawable-xxxhdpi/infobar_shadow_top.png",
"res/drawable/infobar_wrapper_bg.xml",
"res/layout/infobar_control_icon_with_description.xml",
+ "res/layout/infobar_control_icon_with_title.xml",
"res/layout/infobar_control_message.xml",
"res/layout/infobar_control_spinner.xml",
"res/layout/infobar_control_spinner_drop_down.xml",
diff --git a/chromium/components/infobars/android/res/layout/infobar_control_icon_with_title.xml b/chromium/components/infobars/android/res/layout/infobar_control_icon_with_title.xml
new file mode 100644
index 00000000000..e32693ddccc
--- /dev/null
+++ b/chromium/components/infobars/android/res/layout/infobar_control_icon_with_title.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2022 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. -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="36dp"
+ android:gravity="center_vertical">
+
+ <ImageView
+ android:id="@+id/control_title_icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/dual_control_margin_between_items"
+ android:scaleType="centerInside"
+ tools:ignore="ContentDescription" />
+
+ <TextView
+ android:id="@+id/control_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="@style/TextAppearance.TextLarge.Primary" />
+
+</LinearLayout>
diff --git a/chromium/components/infobars/android/res/layout/infobar_control_message.xml b/chromium/components/infobars/android/res/layout/infobar_control_message.xml
index 53fc78601cc..720ea96b6a7 100644
--- a/chromium/components/infobars/android/res/layout/infobar_control_message.xml
+++ b/chromium/components/infobars/android/res/layout/infobar_control_message.xml
@@ -10,4 +10,4 @@
android:layout_height="wrap_content"
android:textDirection="locale"
android:textAppearance="@style/TextAppearance.TextLarge.Primary"
- android:textColorLink="@color/default_text_color_link" />
+ android:textColorLink="@macro/default_text_color_link" />
diff --git a/chromium/components/infobars/core/confirm_infobar_delegate.cc b/chromium/components/infobars/core/confirm_infobar_delegate.cc
index 5157ebb1a3c..944097b8dfb 100644
--- a/chromium/components/infobars/core/confirm_infobar_delegate.cc
+++ b/chromium/components/infobars/core/confirm_infobar_delegate.cc
@@ -50,11 +50,20 @@ ui::ImageModel ConfirmInfoBarDelegate::GetButtonImage(
return ui::ImageModel();
}
+bool ConfirmInfoBarDelegate::GetButtonEnabled(InfoBarButton button) const {
+ return true;
+}
+
+std::u16string ConfirmInfoBarDelegate::GetButtonTooltip(
+ InfoBarButton button) const {
+ return std::u16string();
+}
+
bool ConfirmInfoBarDelegate::OKButtonTriggersUACPrompt() const {
return false;
}
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
bool ConfirmInfoBarDelegate::UseIconBackgroundTint() const {
return true;
}
diff --git a/chromium/components/infobars/core/confirm_infobar_delegate.h b/chromium/components/infobars/core/confirm_infobar_delegate.h
index ef9fb22b150..afa7d1772e9 100644
--- a/chromium/components/infobars/core/confirm_infobar_delegate.h
+++ b/chromium/components/infobars/core/confirm_infobar_delegate.h
@@ -61,11 +61,19 @@ class ConfirmInfoBarDelegate : public infobars::InfoBarDelegate {
// returns an empty image.
virtual ui::ImageModel GetButtonImage(InfoBarButton button) const;
+ // Returns whether the specified button is enabled. The default implementation
+ // returns true.
+ virtual bool GetButtonEnabled(InfoBarButton button) const;
+
+ // Returns the tooltip for the specified button. The default implementation
+ // returns an empty tooltip.
+ virtual std::u16string GetButtonTooltip(InfoBarButton button) const;
+
// Returns whether or not the OK button will trigger a UAC elevation prompt on
// Windows.
virtual bool OKButtonTriggersUACPrompt() const;
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
// Returns whether or not a tint should be applied to the icon background.
// Defaults to true.
virtual bool UseIconBackgroundTint() const;
diff --git a/chromium/components/infobars/core/infobar_delegate.cc b/chromium/components/infobars/core/infobar_delegate.cc
index 352970f3f3b..80a1d73b06b 100644
--- a/chromium/components/infobars/core/infobar_delegate.cc
+++ b/chromium/components/infobars/core/infobar_delegate.cc
@@ -10,7 +10,7 @@
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/vector_icon_types.h"
-#if !defined(OS_IOS) && !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_IOS) && !BUILDFLAG(IS_ANDROID)
#include "ui/gfx/color_palette.h"
#include "ui/gfx/paint_vector_icon.h"
#endif
@@ -37,7 +37,7 @@ const gfx::VectorIcon& InfoBarDelegate::GetVectorIcon() const {
}
gfx::Image InfoBarDelegate::GetIcon() const {
-#if !defined(OS_IOS) && !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_IOS) && !BUILDFLAG(IS_ANDROID)
const gfx::VectorIcon& vector_icon = GetVectorIcon();
if (!vector_icon.is_empty()) {
return gfx::Image(
@@ -114,7 +114,7 @@ translate::TranslateInfoBarDelegate*
return nullptr;
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
offline_pages::OfflinePageInfoBarDelegate*
InfoBarDelegate::AsOfflinePageInfoBarDelegate() {
return nullptr;
diff --git a/chromium/components/infobars/core/infobar_delegate.h b/chromium/components/infobars/core/infobar_delegate.h
index 5d89e301913..8e73df46136 100644
--- a/chromium/components/infobars/core/infobar_delegate.h
+++ b/chromium/components/infobars/core/infobar_delegate.h
@@ -20,7 +20,7 @@ namespace blocked_content {
class PopupBlockedInfoBarDelegate;
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
namespace offline_pages {
class OfflinePageInfoBarDelegate;
}
@@ -132,7 +132,7 @@ class InfoBarDelegate {
DANGEROUS_DOWNLOAD_INFOBAR_DELEGATE_ANDROID = 61,
// Removed: DESKTOP_SEARCH_REDIRECTION_INFOBAR_DELEGATE = 62,
UPDATE_PASSWORD_INFOBAR_DELEGATE_MOBILE = 63,
- DATA_REDUCTION_PROMO_INFOBAR_DELEGATE_ANDROID = 64,
+ // Removed: DATA_REDUCTION_PROMO_INFOBAR_DELEGATE_ANDROID = 64,
AUTOFILL_CREDIT_CARD_FILLING_INFOBAR_DELEGATE_ANDROID = 65,
ADS_BLOCKED_INFOBAR_DELEGATE_ANDROID = 66,
INSTANT_APPS_INFOBAR_DELEGATE_ANDROID = 67,
@@ -151,7 +151,7 @@ class InfoBarDelegate {
INSTALLABLE_AMBIENT_BADGE_INFOBAR_DELEGATE = 80,
// Removed: PAGE_LOAD_CAPPING_INFOBAR_DELEGATE = 81,
DOWNLOAD_PROGRESS_INFOBAR_ANDROID = 82,
- AR_CORE_UPGRADE_ANDROID = 83,
+ // Removed: AR_CORE_UPGRADE_ANDROID = 83,
BLOATED_RENDERER_INFOBAR_DELEGATE = 84,
// Removed: SUPERVISED_USERS_DEPRECATED_INFOBAR_DELEGATE = 85,
NEAR_OOM_REDUCTION_INFOBAR_ANDROID = 86,
@@ -176,6 +176,9 @@ class InfoBarDelegate {
AUTOFILL_OFFER_NOTIFICATION_INFOBAR_DELEGATE = 105,
AUTOFILL_ADDRESS_PROFILE_INFOBAR_DELEGATE_IOS = 106,
ADD_TO_READING_LIST_IOS = 107,
+ IOS_PERMISSIONS_INFOBAR_DELEGATE = 108,
+ SUPPORTED_LINKS_INFOBAR_DELEGATE_CHROMEOS = 109,
+ AUTOFILL_VIRTUAL_CARD_ENROLLMENT_INFOBAR_DELEGATE_MOBILE = 110,
};
// Describes navigation events, used to decide whether infobars should be
@@ -275,7 +278,7 @@ class InfoBarDelegate {
AsPopupBlockedInfoBarDelegate();
virtual ThemeInstalledInfoBarDelegate* AsThemePreviewInfobarDelegate();
virtual translate::TranslateInfoBarDelegate* AsTranslateInfoBarDelegate();
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
virtual offline_pages::OfflinePageInfoBarDelegate*
AsOfflinePageInfoBarDelegate();
#endif
diff --git a/chromium/components/javascript_dialogs/app_modal_dialog_controller.cc b/chromium/components/javascript_dialogs/app_modal_dialog_controller.cc
index 75f27d75c82..41edbfa3ba1 100644
--- a/chromium/components/javascript_dialogs/app_modal_dialog_controller.cc
+++ b/chromium/components/javascript_dialogs/app_modal_dialog_controller.cc
@@ -18,7 +18,7 @@ namespace {
AppModalDialogObserver* app_modal_dialog_observer = nullptr;
// Control maximum sizes of various texts passed to us from javascript.
-#if defined(OS_POSIX) && !defined(OS_APPLE)
+#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_APPLE)
// Two-dimensional eliding. Reformat the text of the message dialog
// inserting line breaks because otherwise a single long line can overflow
// the message dialog (and crash/hang the GTK, depending on the version).
diff --git a/chromium/components/js_injection/browser/js_communication_host.cc b/chromium/components/js_injection/browser/js_communication_host.cc
index 99138cac4e5..c27106501f3 100644
--- a/chromium/components/js_injection/browser/js_communication_host.cc
+++ b/chromium/components/js_injection/browser/js_communication_host.cc
@@ -92,7 +92,7 @@ JsCommunicationHost::AddDocumentStartJavaScript(
scripts_.emplace_back(script, origin_matcher, next_script_id_++);
- web_contents()->ForEachFrame(base::BindRepeating(
+ web_contents()->GetMainFrame()->ForEachRenderFrameHost(base::BindRepeating(
&JsCommunicationHost::NotifyFrameForAddDocumentStartJavaScript,
base::Unretained(this), &*scripts_.rbegin()));
result.script_id = scripts_.rbegin()->script_id_;
@@ -103,9 +103,10 @@ bool JsCommunicationHost::RemoveDocumentStartJavaScript(int script_id) {
for (auto it = scripts_.begin(); it != scripts_.end(); ++it) {
if (it->script_id_ == script_id) {
scripts_.erase(it);
- web_contents()->ForEachFrame(base::BindRepeating(
- &JsCommunicationHost::NotifyFrameForRemoveDocumentStartJavaScript,
- base::Unretained(this), script_id));
+ web_contents()->GetMainFrame()->ForEachRenderFrameHost(
+ base::BindRepeating(
+ &JsCommunicationHost::NotifyFrameForRemoveDocumentStartJavaScript,
+ base::Unretained(this), script_id));
return true;
}
}
@@ -131,7 +132,7 @@ std::u16string JsCommunicationHost::AddWebMessageHostFactory(
js_objects_.push_back(std::make_unique<JsObject>(
js_object_name, origin_matcher, std::move(factory)));
- web_contents()->ForEachFrame(base::BindRepeating(
+ web_contents()->GetMainFrame()->ForEachRenderFrameHost(base::BindRepeating(
&JsCommunicationHost::NotifyFrameForWebMessageListener,
base::Unretained(this)));
return std::u16string();
@@ -143,9 +144,10 @@ void JsCommunicationHost::RemoveWebMessageHostFactory(
++iterator) {
if ((*iterator)->name == js_object_name) {
js_objects_.erase(iterator);
- web_contents()->ForEachFrame(base::BindRepeating(
- &JsCommunicationHost::NotifyFrameForWebMessageListener,
- base::Unretained(this)));
+ web_contents()->GetMainFrame()->ForEachRenderFrameHost(
+ base::BindRepeating(
+ &JsCommunicationHost::NotifyFrameForWebMessageListener,
+ base::Unretained(this)));
break;
}
}
diff --git a/chromium/components/js_injection/browser/js_to_browser_messaging.cc b/chromium/components/js_injection/browser/js_to_browser_messaging.cc
index e2cc9cf415c..7867deb13b3 100644
--- a/chromium/components/js_injection/browser/js_to_browser_messaging.cc
+++ b/chromium/components/js_injection/browser/js_to_browser_messaging.cc
@@ -56,6 +56,7 @@ class JsToBrowserMessaging::ReplyProxyImpl : public WebMessageReplyProxy {
return render_frame_host_->GetLifecycleState() ==
content::RenderFrameHost::LifecycleState::kInBackForwardCache;
}
+ content::Page& GetPage() override { return render_frame_host_->GetPage(); }
private:
raw_ptr<content::RenderFrameHost> render_frame_host_;
diff --git a/chromium/components/js_injection/browser/web_message_reply_proxy.h b/chromium/components/js_injection/browser/web_message_reply_proxy.h
index 2eb52975efe..3b887ee9dc1 100644
--- a/chromium/components/js_injection/browser/web_message_reply_proxy.h
+++ b/chromium/components/js_injection/browser/web_message_reply_proxy.h
@@ -5,6 +5,10 @@
#ifndef COMPONENTS_JS_INJECTION_BROWSER_WEB_MESSAGE_REPLY_PROXY_H_
#define COMPONENTS_JS_INJECTION_BROWSER_WEB_MESSAGE_REPLY_PROXY_H_
+namespace content {
+class Page;
+}
+
namespace js_injection {
struct WebMessage;
@@ -18,6 +22,9 @@ class WebMessageReplyProxy {
// forward cache.
virtual bool IsInBackForwardCache() = 0;
+ // Returns the page the messages are sent to.
+ virtual content::Page& GetPage() = 0;
+
protected:
virtual ~WebMessageReplyProxy() = default;
};
diff --git a/chromium/components/js_injection/common/origin_matcher.cc b/chromium/components/js_injection/common/origin_matcher.cc
index bdfc9fa3eaf..3aa0bce1951 100644
--- a/chromium/components/js_injection/common/origin_matcher.cc
+++ b/chromium/components/js_injection/common/origin_matcher.cc
@@ -4,6 +4,7 @@
#include "components/js_injection/common/origin_matcher.h"
+#include "base/containers/adapters.h"
#include "components/js_injection/common/origin_matcher_internal.h"
#include "net/base/ip_address.h"
#include "net/base/ip_endpoint.h"
@@ -105,8 +106,9 @@ bool OriginMatcher::AddRuleFromString(const std::string& raw_untrimmed) {
bool OriginMatcher::Matches(const url::Origin& origin) const {
GURL origin_url = origin.GetURL();
// Since we only do kInclude vs kNoMatch, the order doesn't actually matter.
- for (auto it = rules_.rbegin(); it != rules_.rend(); ++it) {
- net::SchemeHostPortMatcherResult result = (*it)->Evaluate(origin_url);
+ for (const std::unique_ptr<OriginMatcherRule>& rule :
+ base::Reversed(rules_)) {
+ net::SchemeHostPortMatcherResult result = rule->Evaluate(origin_url);
if (result == net::SchemeHostPortMatcherResult::kInclude)
return true;
}
diff --git a/chromium/components/keep_alive_registry/keep_alive_registry.cc b/chromium/components/keep_alive_registry/keep_alive_registry.cc
index 0f77ce7b3be..adf76ec6274 100644
--- a/chromium/components/keep_alive_registry/keep_alive_registry.cc
+++ b/chromium/components/keep_alive_registry/keep_alive_registry.cc
@@ -9,7 +9,7 @@
#include "components/keep_alive_registry/keep_alive_state_observer.h"
#include "components/keep_alive_registry/keep_alive_types.h"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include "components/browser_watcher/activity_data_names.h"
#include "components/browser_watcher/extended_crash_reporting.h"
#endif
@@ -173,7 +173,7 @@ void KeepAliveRegistry::Unregister(KeepAliveOrigin origin,
void KeepAliveRegistry::OnKeepAliveStateChanged(bool new_keeping_alive) {
DVLOG(1) << "Notifying KeepAliveStateObservers: KeepingAlive changed to: "
<< new_keeping_alive;
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
browser_watcher::ExtendedCrashReporting::SetDataBool(
browser_watcher::kActivityKeepAlive, new_keeping_alive);
#endif
@@ -184,7 +184,7 @@ void KeepAliveRegistry::OnKeepAliveStateChanged(bool new_keeping_alive) {
void KeepAliveRegistry::OnRestartAllowedChanged(bool new_restart_allowed) {
DVLOG(1) << "Notifying KeepAliveStateObservers: Restart changed to: "
<< new_restart_allowed;
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
browser_watcher::ExtendedCrashReporting::SetDataBool(
browser_watcher::kActivityRestartAllowed, new_restart_allowed);
#endif
diff --git a/chromium/components/keep_alive_registry/keep_alive_types.cc b/chromium/components/keep_alive_registry/keep_alive_types.cc
index 180fc476013..4b7b71cc016 100644
--- a/chromium/components/keep_alive_registry/keep_alive_types.cc
+++ b/chromium/components/keep_alive_registry/keep_alive_types.cc
@@ -14,6 +14,8 @@ std::ostream& operator<<(std::ostream& out, const KeepAliveOrigin& origin) {
return out << "BROWSER";
case KeepAliveOrigin::BROWSER_PROCESS_CHROMEOS:
return out << "BROWSER_PROCESS_CHROMEOS";
+ case KeepAliveOrigin::BROWSER_PROCESS_FUCHSIA:
+ return out << "BROWSER_PROCESS_FUCHSIA";
case KeepAliveOrigin::BROWSER_PROCESS_LACROS:
return out << "BROWSER_PROCESS_LACROS";
case KeepAliveOrigin::SESSION_RESTORE:
@@ -36,6 +38,8 @@ std::ostream& operator<<(std::ostream& out, const KeepAliveOrigin& origin) {
return out << "REMOTE_DEBUGGING";
case KeepAliveOrigin::DEVTOOLS_WINDOW:
return out << "DEVTOOLS_WINDOW";
+ case KeepAliveOrigin::NATIVE_MESSAGING_HOST_ERROR_REPORT:
+ return out << "NATIVE_MESSAGING_HOST_ERROR_REPORT";
case KeepAliveOrigin::NOTIFICATION:
return out << "NOTIFICATION";
case KeepAliveOrigin::PENDING_NOTIFICATION_CLICK_EVENT:
@@ -48,10 +52,6 @@ std::ostream& operator<<(std::ostream& out, const KeepAliveOrigin& origin) {
return out << "APP_LIST_SERVICE_VIEWS";
case KeepAliveOrigin::APP_LIST_SHOWER:
return out << "APP_LIST_SHOWER";
- case KeepAliveOrigin::APP_MANIFEST_UPDATE:
- return out << "APP_MANIFEST_UPDATE";
- case KeepAliveOrigin::APP_START_URL_MIGRATION:
- return out << "APP_START_URL_MIGRATION";
case KeepAliveOrigin::CHROME_APP_DELEGATE:
return out << "CHROME_APP_DELEGATE";
case KeepAliveOrigin::CHROME_VIEWS_DELEGATE:
@@ -68,10 +68,16 @@ std::ostream& operator<<(std::ostream& out, const KeepAliveOrigin& origin) {
return out << "USER_MANAGER_VIEW";
case KeepAliveOrigin::CREDENTIAL_PROVIDER_SIGNIN_DIALOG:
return out << "CREDENTIAL_PROVIDER_SIGNIN_DIALOG";
- case KeepAliveOrigin::NATIVE_MESSAGING_HOST_ERROR_REPORT:
- return out << "NATIVE_MESSAGING_HOST_ERROR_REPORT";
case KeepAliveOrigin::WEB_APP_INTENT_PICKER:
return out << "WEB_APP_INTENT_PICKER";
+ case KeepAliveOrigin::WEB_APP_UNINSTALL:
+ return out << "WEB_APP_UNINSTALL";
+ case KeepAliveOrigin::APP_MANIFEST_UPDATE:
+ return out << "APP_MANIFEST_UPDATE";
+ case KeepAliveOrigin::APP_START_URL_MIGRATION:
+ return out << "APP_START_URL_MIGRATION";
+ case KeepAliveOrigin::APP_GET_INFO:
+ return out << "APP_GET_INFO";
case KeepAliveOrigin::SESSION_DATA_DELETER:
return out << "SESSION_DATA_DELETER";
}
diff --git a/chromium/components/keep_alive_registry/keep_alive_types.h b/chromium/components/keep_alive_registry/keep_alive_types.h
index bcb4867cdef..a867de7123f 100644
--- a/chromium/components/keep_alive_registry/keep_alive_types.h
+++ b/chromium/components/keep_alive_registry/keep_alive_types.h
@@ -18,6 +18,7 @@ enum class KeepAliveOrigin {
APP_CONTROLLER,
BROWSER,
BROWSER_PROCESS_CHROMEOS,
+ BROWSER_PROCESS_FUCHSIA,
BROWSER_PROCESS_LACROS,
SESSION_RESTORE,
@@ -64,9 +65,13 @@ enum class KeepAliveOrigin {
CREDENTIAL_PROVIDER_SIGNIN_DIALOG,
WEB_APP_INTENT_PICKER,
+ // c/b/ui/web_applications
+ WEB_APP_UNINSTALL,
+
// c/b/web_applications
APP_MANIFEST_UPDATE,
APP_START_URL_MIGRATION,
+ APP_GET_INFO,
// c/b/sessions
SESSION_DATA_DELETER,
diff --git a/chromium/components/keyed_service/content/browser_context_dependency_manager.h b/chromium/components/keyed_service/content/browser_context_dependency_manager.h
index f525cf2111d..6c45b15891d 100644
--- a/chromium/components/keyed_service/content/browser_context_dependency_manager.h
+++ b/chromium/components/keyed_service/content/browser_context_dependency_manager.h
@@ -7,7 +7,6 @@
#include "base/callback_forward.h"
#include "base/callback_list.h"
-#include "base/compiler_specific.h"
#include "base/no_destructor.h"
#include "components/keyed_service/core/dependency_manager.h"
#include "components/keyed_service/core/keyed_service_export.h"
@@ -59,8 +58,9 @@ class KEYED_SERVICE_EXPORT BrowserContextDependencyManager
// CreateBrowserContextServices() or CreateBrowserContextServicesForTest().
// This can be useful in browser tests which wish to substitute test or mock
// builders for the keyed services.
- base::CallbackListSubscription RegisterCreateServicesCallbackForTesting(
- const CreateServicesCallback& callback) WARN_UNUSED_RESULT;
+ [[nodiscard]] base::CallbackListSubscription
+ RegisterCreateServicesCallbackForTesting(
+ const CreateServicesCallback& callback);
// Runtime assertion called as a part of GetServiceForBrowserContext() to
// check if |context| is considered stale. This will NOTREACHED() or
diff --git a/chromium/components/keyed_service/core/dependency_graph.h b/chromium/components/keyed_service/core/dependency_graph.h
index 66c55cea045..2b7562529a8 100644
--- a/chromium/components/keyed_service/core/dependency_graph.h
+++ b/chromium/components/keyed_service/core/dependency_graph.h
@@ -10,7 +10,6 @@
#include <vector>
#include "base/callback.h"
-#include "base/compiler_specific.h"
#include "components/keyed_service/core/keyed_service_export.h"
class DependencyNode;
@@ -35,13 +34,11 @@ class KEYED_SERVICE_EXPORT DependencyGraph {
// Topologically sorts nodes to produce a safe construction order
// (all nodes after their dependees).
- bool GetConstructionOrder(std::vector<DependencyNode*>* order)
- WARN_UNUSED_RESULT;
+ [[nodiscard]] bool GetConstructionOrder(std::vector<DependencyNode*>* order);
// Topologically sorts nodes to produce a safe destruction order
// (all nodes before their dependees).
- bool GetDestructionOrder(std::vector<DependencyNode*>* order)
- WARN_UNUSED_RESULT;
+ [[nodiscard]] bool GetDestructionOrder(std::vector<DependencyNode*>* order);
// Returns representation of the dependency graph in graphviz format.
std::string DumpAsGraphviz(
@@ -54,7 +51,7 @@ class KEYED_SERVICE_EXPORT DependencyGraph {
// Populates |construction_order_| with computed construction order.
// Returns true on success.
- bool BuildConstructionOrder() WARN_UNUSED_RESULT;
+ [[nodiscard]] bool BuildConstructionOrder();
// Keeps track of all live nodes (see AddNode, RemoveNode).
std::vector<DependencyNode*> all_nodes_;
diff --git a/chromium/components/keyed_service/core/dependency_manager.cc b/chromium/components/keyed_service/core/dependency_manager.cc
index 9f603c6ebab..553c937794b 100644
--- a/chromium/components/keyed_service/core/dependency_manager.cc
+++ b/chromium/components/keyed_service/core/dependency_manager.cc
@@ -4,6 +4,8 @@
#include "components/keyed_service/core/dependency_manager.h"
+#include <ostream>
+
#include "base/bind.h"
#include "base/check.h"
#include "base/debug/dump_without_crashing.h"
@@ -157,15 +159,11 @@ void DependencyManager::DestroyFactoriesInOrder(
void DependencyManager::AssertContextWasntDestroyed(void* context) const {
if (dead_context_pointers_.find(context) != dead_context_pointers_.end()) {
-#if DCHECK_IS_ON()
- NOTREACHED() << "Attempted to access a context that was ShutDown(). "
+ // We want to see all possible use-after-destroy in production environment.
+ CHECK(false) << "Attempted to access a context that was ShutDown(). "
<< "This is most likely a heap smasher in progress. After "
<< "KeyedService::Shutdown() completes, your service MUST "
<< "NOT refer to depended services again.";
-#else // DCHECK_IS_ON()
- // We want to see all possible use-after-destroy in production environment.
- base::debug::DumpWithoutCrashing();
-#endif // DCHECK_IS_ON()
}
}
diff --git a/chromium/components/keyed_service/core/dependency_manager.h b/chromium/components/keyed_service/core/dependency_manager.h
index 9174ae932a2..b2712da240e 100644
--- a/chromium/components/keyed_service/core/dependency_manager.h
+++ b/chromium/components/keyed_service/core/dependency_manager.h
@@ -75,8 +75,8 @@ class KEYED_SERVICE_EXPORT DependencyManager {
void DestroyContextServices(void* context);
// Runtime assertion called as a part of GetServiceForContext() to check if
- // |context| is considered stale. This will NOTREACHED() or
- // base::debug::DumpWithoutCrashing() depending on the DCHECK_IS_ON() value.
+ // |context| is considered stale. This will CHECK(false) to avoid a potential
+ // use-after-free from services created after context destruction.
void AssertContextWasntDestroyed(void* context) const;
// Marks |context| as live (i.e., not stale). This method can be called as a
diff --git a/chromium/components/keyed_service/core/simple_key_map.cc b/chromium/components/keyed_service/core/simple_key_map.cc
index c1e42c819be..fcb27e21454 100644
--- a/chromium/components/keyed_service/core/simple_key_map.cc
+++ b/chromium/components/keyed_service/core/simple_key_map.cc
@@ -5,6 +5,7 @@
#include "components/keyed_service/core/simple_key_map.h"
#include "base/check.h"
+#include "base/no_destructor.h"
SimpleKeyMap::SimpleKeyMap() = default;
diff --git a/chromium/components/language/content/browser/geo_language_provider.cc b/chromium/components/language/content/browser/geo_language_provider.cc
index 90773bf1328..a252fbcfd6a 100644
--- a/chromium/components/language/content/browser/geo_language_provider.cc
+++ b/chromium/components/language/content/browser/geo_language_provider.cc
@@ -73,9 +73,10 @@ void GeoLanguageProvider::StartUp(PrefService* const prefs) {
prefs_ = prefs;
- const base::ListValue* const cached_languages_list =
+ const base::Value* const cached_languages_list =
prefs_->GetList(kCachedGeoLanguagesPref);
- for (const auto& language_value : cached_languages_list->GetList()) {
+ for (const auto& language_value :
+ cached_languages_list->GetListDeprecated()) {
languages_.push_back(language_value.GetString());
}
@@ -198,8 +199,8 @@ void GeoLanguageProvider::SetGeoLanguages(
languages_ = languages;
base::ListValue cache_list;
- for (size_t i = 0; i < languages_.size(); ++i) {
- cache_list.Set(i, std::make_unique<base::Value>(languages_[i]));
+ for (const std::string& language : languages_) {
+ cache_list.Append(language);
}
prefs_->Set(kCachedGeoLanguagesPref, cache_list);
}
diff --git a/chromium/components/language/content/browser/geo_language_provider_unittest.cc b/chromium/components/language/content/browser/geo_language_provider_unittest.cc
index 7c374607f86..45cd11b866b 100644
--- a/chromium/components/language/content/browser/geo_language_provider_unittest.cc
+++ b/chromium/components/language/content/browser/geo_language_provider_unittest.cc
@@ -65,17 +65,18 @@ class GeoLanguageProviderTest : public testing::Test {
void SetUpCachedLanguages(const std::vector<std::string>& languages) {
base::ListValue cache_list;
- for (size_t i = 0; i < languages.size(); ++i) {
- cache_list.Set(i, std::make_unique<base::Value>(languages[i]));
+ for (const std::string& language : languages) {
+ cache_list.Append(language);
}
local_state_.Set(GeoLanguageProvider::kCachedGeoLanguagesPref, cache_list);
}
const std::vector<std::string> GetCachedLanguages() {
std::vector<std::string> languages;
- const base::ListValue* const cached_languages_list =
+ const base::Value* const cached_languages_list =
local_state_.GetList(GeoLanguageProvider::kCachedGeoLanguagesPref);
- for (const auto& language_value : cached_languages_list->GetList()) {
+ for (const auto& language_value :
+ cached_languages_list->GetListDeprecated()) {
languages.push_back(language_value.GetString());
}
return languages;
diff --git a/chromium/components/language/content/browser/ulp_language_code_locator/ulp_language_code_locator.cc b/chromium/components/language/content/browser/ulp_language_code_locator/ulp_language_code_locator.cc
index 73d782611fc..8cd8296bd87 100644
--- a/chromium/components/language/content/browser/ulp_language_code_locator/ulp_language_code_locator.cc
+++ b/chromium/components/language/content/browser/ulp_language_code_locator/ulp_language_code_locator.cc
@@ -55,14 +55,14 @@ std::vector<std::string> UlpLanguageCodeLocator::GetLanguageCodes(
std::vector<std::string> languages;
ListPrefUpdate update(prefs_, kCachedGeoLanguagesPref);
- base::ListValue* celllangs_cached = update.Get();
+ base::Value* celllangs_cached = update.Get();
for (size_t index = 0; index < serialized_langtrees_.size(); index++) {
std::string language;
bool is_cached = false;
const base::Value* celllang_cached = nullptr;
- if (index < celllangs_cached->GetList().size()) {
- celllang_cached = &celllangs_cached->GetList()[index];
+ if (index < celllangs_cached->GetListDeprecated().size()) {
+ celllang_cached = &celllangs_cached->GetListDeprecated()[index];
is_cached = celllang_cached->is_dict();
}
@@ -84,7 +84,7 @@ std::vector<std::string> UlpLanguageCodeLocator::GetLanguageCodes(
language = root.Get(cell, &level);
if (level != -1) {
if (is_cached) {
- celllangs_cached->GetList()[index] =
+ celllangs_cached->GetListDeprecated()[index] =
GetCellLanguagePairValue(cell.parent(level), language);
} else {
celllangs_cached->Append(
diff --git a/chromium/components/language/core/browser/BUILD.gn b/chromium/components/language/core/browser/BUILD.gn
index 777634b4f93..fdba4ca9088 100644
--- a/chromium/components/language/core/browser/BUILD.gn
+++ b/chromium/components/language/core/browser/BUILD.gn
@@ -37,6 +37,7 @@ static_library("browser") {
source_set("unit_tests") {
testonly = true
sources = [
+ "language_model_manager_unittest.cc",
"language_prefs_unittest.cc",
"language_usage_metrics_unittest.cc",
"ulp_metrics_logger_unittest.cc",
@@ -47,6 +48,7 @@ source_set("unit_tests") {
":test_support",
"//base",
"//build:chromeos_buildflags",
+ "//components/language/core/language_model",
"//components/pref_registry:pref_registry",
"//components/prefs",
"//components/prefs:test_support",
diff --git a/chromium/components/language/core/browser/DEPS b/chromium/components/language/core/browser/DEPS
index c82644068ba..0a3361a45be 100644
--- a/chromium/components/language/core/browser/DEPS
+++ b/chromium/components/language/core/browser/DEPS
@@ -1,4 +1,5 @@
include_rules = [
"+components/keyed_service/core",
+ "+components/translate/core/browser",
"+ui/base/l10n",
]
diff --git a/chromium/components/language/core/browser/language_model_manager.cc b/chromium/components/language/core/browser/language_model_manager.cc
index 705e5694f54..afb0a656010 100644
--- a/chromium/components/language/core/browser/language_model_manager.cc
+++ b/chromium/components/language/core/browser/language_model_manager.cc
@@ -26,10 +26,18 @@ void LanguageModelManager::SetPrimaryModel(ModelType type) {
}
LanguageModel* LanguageModelManager::GetPrimaryModel() const {
+ if (models_.find(primary_model_type_) == models_.end()) {
+ return nullptr;
+ }
return models_.at(primary_model_type_).get();
}
-LanguageModel* LanguageModelManager::GetLanguageModel(ModelType type) {
+LanguageModelManager::ModelType LanguageModelManager::GetPrimaryModelType()
+ const {
+ return primary_model_type_;
+}
+
+LanguageModel* LanguageModelManager::GetLanguageModel(ModelType type) const {
if (models_.find(type) == models_.end()) {
return nullptr;
}
diff --git a/chromium/components/language/core/browser/language_model_manager.h b/chromium/components/language/core/browser/language_model_manager.h
index ba2ce031076..96895c9817f 100644
--- a/chromium/components/language/core/browser/language_model_manager.h
+++ b/chromium/components/language/core/browser/language_model_manager.h
@@ -41,7 +41,8 @@ class LanguageModelManager : public KeyedService {
// through a call to AddModel.
void SetPrimaryModel(ModelType type);
LanguageModel* GetPrimaryModel() const;
- LanguageModel* GetLanguageModel(ModelType type);
+ ModelType GetPrimaryModelType() const;
+ LanguageModel* GetLanguageModel(ModelType type) const;
private:
std::unique_ptr<LanguageModel> default_model_;
diff --git a/chromium/components/language/core/browser/language_model_manager_unittest.cc b/chromium/components/language/core/browser/language_model_manager_unittest.cc
new file mode 100644
index 00000000000..c2ee8e3da0b
--- /dev/null
+++ b/chromium/components/language/core/browser/language_model_manager_unittest.cc
@@ -0,0 +1,77 @@
+// Copyright 2021 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.
+
+#include "components/language/core/browser/language_model_manager.h"
+
+#include <memory>
+
+#include "components/language/core/browser/language_model.h"
+#include "components/language/core/browser/language_prefs.h"
+#include "components/language/core/language_model/fluent_language_model.h"
+#include "components/language/core/language_model/ulp_language_model.h"
+#include "components/prefs/testing_pref_service.h"
+#include "components/sync_preferences/testing_pref_service_syncable.h"
+#include "components/translate/core/browser/translate_prefs.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace language {
+
+struct PrefRegistration {
+ explicit PrefRegistration(user_prefs::PrefRegistrySyncable* registry) {
+ language::LanguagePrefs::RegisterProfilePrefs(registry);
+ translate::TranslatePrefs::RegisterProfilePrefs(registry);
+ }
+};
+
+class LanguageModelManagerTest : public testing::Test {
+ protected:
+ LanguageModelManagerTest()
+ : prefs_registration_(prefs_.registry()), manager_(&prefs_, "en") {}
+
+ void SetUp() override {
+ manager_.AddModel(LanguageModelManager::ModelType::FLUENT,
+ std::make_unique<FluentLanguageModel>(&prefs_));
+ }
+
+ sync_preferences::TestingPrefServiceSyncable prefs_;
+ PrefRegistration prefs_registration_;
+ LanguageModelManager manager_;
+};
+
+TEST_F(LanguageModelManagerTest, GetPrimaryModelTypeTest) {
+ // Default primary model type is BASELINE.
+ EXPECT_EQ(manager_.GetPrimaryModelType(),
+ LanguageModelManager::ModelType::BASELINE);
+
+ // Change primary model to FLUENT.
+ manager_.SetPrimaryModel(LanguageModelManager::ModelType::FLUENT);
+ EXPECT_EQ(manager_.GetPrimaryModelType(),
+ LanguageModelManager::ModelType::FLUENT);
+}
+
+TEST_F(LanguageModelManagerTest, GetPrimaryModelTest) {
+ // Default primary model type is BASELINE, but test manager only has the
+ // fluent model set.
+ EXPECT_EQ(manager_.GetPrimaryModel(), nullptr);
+
+ // Change primary model to FLUENT, for which there is a corresponding
+ // LanguageModel set.
+ manager_.SetPrimaryModel(LanguageModelManager::ModelType::FLUENT);
+ EXPECT_NE(manager_.GetPrimaryModel(), nullptr);
+}
+
+TEST_F(LanguageModelManagerTest, GetLanguageModelTest) {
+ EXPECT_NE(manager_.GetLanguageModel(LanguageModelManager::ModelType::FLUENT),
+ nullptr);
+
+ // After adding a language model instance, the corresponding LanguageModel in
+ // the test manager should be set.
+ EXPECT_EQ(manager_.GetLanguageModel(LanguageModelManager::ModelType::ULP),
+ nullptr);
+ manager_.AddModel(LanguageModelManager::ModelType::ULP,
+ std::make_unique<ULPLanguageModel>());
+ EXPECT_NE(manager_.GetLanguageModel(LanguageModelManager::ModelType::ULP),
+ nullptr);
+}
+} // namespace language
diff --git a/chromium/components/language/core/browser/language_prefs.cc b/chromium/components/language/core/browser/language_prefs.cc
index 0c34853eba1..26f86d67c32 100644
--- a/chromium/components/language/core/browser/language_prefs.cc
+++ b/chromium/components/language/core/browser/language_prefs.cc
@@ -48,7 +48,7 @@ void LanguagePrefs::RegisterProfilePrefs(
language::prefs::kPreferredLanguagesSyncable, "",
user_prefs::PrefRegistrySyncable::SYNCABLE_OS_PREF);
#endif
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
registry->RegisterBooleanPref(
language::prefs::kAppLanguagePromptShown, false,
user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
@@ -107,8 +107,8 @@ void LanguagePrefs::GetDeduplicatedUserLanguages(
forced_languages_set_.clear();
// Add policy languages.
- for (const auto& language :
- prefs_->GetList(language::prefs::kForcedLanguages)->GetList()) {
+ for (const auto& language : prefs_->GetList(language::prefs::kForcedLanguages)
+ ->GetListDeprecated()) {
if (forced_languages_set_.find(language.GetString()) ==
forced_languages_set_.end()) {
deduplicated_languages.emplace_back(language.GetString());
diff --git a/chromium/components/language/core/browser/locale_util.cc b/chromium/components/language/core/browser/locale_util.cc
index 1ea2fe1dd64..9e3a7318e8d 100644
--- a/chromium/components/language/core/browser/locale_util.cc
+++ b/chromium/components/language/core/browser/locale_util.cc
@@ -17,7 +17,7 @@ std::string GetApplicationLocale(PrefService* local_state) {
// LoadLocaleResources(), which is how the global locale is set.
// TODO(asvitkine): We should try to refactor things so that the logic is not
// duplicated in multiple files.
-#if !defined(OS_APPLE)
+#if !BUILDFLAG(IS_APPLE)
// The pref isn't always registered in unit tests.
if (local_state->HasPrefPath(prefs::kApplicationLocale))
preferred_locale = local_state->GetString(prefs::kApplicationLocale);
diff --git a/chromium/components/language/core/browser/locale_util.h b/chromium/components/language/core/browser/locale_util.h
index a2343031526..941df661283 100644
--- a/chromium/components/language/core/browser/locale_util.h
+++ b/chromium/components/language/core/browser/locale_util.h
@@ -11,6 +11,10 @@ class PrefService;
namespace language {
+// This method is responsible for determining the initial locale based on
+// command line flags, preferences, and OS settings. In nearly all cases you
+// shouldn't call this, rather use GetApplicationLocale defined on browser
+// process.
// Returns the current application locale (e.g. "en-US").
std::string GetApplicationLocale(PrefService* local_state);
diff --git a/chromium/components/language/core/browser/pref_names.cc b/chromium/components/language/core/browser/pref_names.cc
index a76b9fb165d..04896bb62c0 100644
--- a/chromium/components/language/core/browser/pref_names.cc
+++ b/chromium/components/language/core/browser/pref_names.cc
@@ -33,7 +33,7 @@ const char kPreferredLanguagesSyncable[] =
// Important: Refer to header file for how to use this.
const char kApplicationLocale[] = "intl.app_locale";
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
const char kAppLanguagePromptShown[] = "language.app_language_prompt_shown";
#endif
diff --git a/chromium/components/language/core/browser/pref_names.h b/chromium/components/language/core/browser/pref_names.h
index 77a40d7b2ce..394bbc64ea0 100644
--- a/chromium/components/language/core/browser/pref_names.h
+++ b/chromium/components/language/core/browser/pref_names.h
@@ -28,7 +28,7 @@ extern const char kPreferredLanguagesSyncable[];
// the user selected, if applicable.
extern const char kApplicationLocale[];
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
extern const char kAppLanguagePromptShown[];
#endif
diff --git a/chromium/components/language/core/browser/url_language_histogram.cc b/chromium/components/language/core/browser/url_language_histogram.cc
index b06ffbf1f70..7663776fd26 100644
--- a/chromium/components/language/core/browser/url_language_histogram.cc
+++ b/chromium/components/language/core/browser/url_language_histogram.cc
@@ -25,31 +25,29 @@ const float kCutoffRatio = 0.005f;
const float kDiscountFactor = 0.75f;
// Gets the sum of the counter for all languages in the histogram.
-int GetCountersSum(const base::DictionaryValue& dict) {
+int GetCountersSum(const base::Value& dict) {
int sum = 0;
- for (base::DictionaryValue::Iterator itr(dict); !itr.IsAtEnd();
- itr.Advance()) {
- if (itr.value().is_int())
- sum += itr.value().GetInt();
+ for (const auto itr : dict.DictItems()) {
+ if (itr.second.is_int())
+ sum += itr.second.GetInt();
}
return sum;
}
// Removes languages with small counter values and discount remaining counters.
-void DiscountAndCleanCounters(base::DictionaryValue* dict) {
+void DiscountAndCleanCounters(base::Value* dict) {
std::set<std::string> remove_keys;
- for (base::DictionaryValue::Iterator itr(*dict); !itr.IsAtEnd();
- itr.Advance()) {
+ for (const auto itr : dict->DictItems()) {
// Remove languages with invalid or small values.
- if (!itr.value().is_int() ||
- itr.value().GetInt() < (kCutoffRatio * kMaxCountersSum)) {
- remove_keys.insert(itr.key());
+ if (!itr.second.is_int() ||
+ itr.second.GetInt() < (kCutoffRatio * kMaxCountersSum)) {
+ remove_keys.insert(itr.first);
continue;
}
// Discount the value.
- dict->SetInteger(itr.key(), itr.value().GetInt() * kDiscountFactor);
+ dict->SetIntKey(itr.first, itr.second.GetInt() * kDiscountFactor);
}
for (const std::string& lang_to_remove : remove_keys)
@@ -58,7 +56,7 @@ void DiscountAndCleanCounters(base::DictionaryValue* dict) {
// Transforms the counters from prefs into a list of LanguageInfo structs.
std::vector<UrlLanguageHistogram::LanguageInfo> GetAllLanguages(
- const base::DictionaryValue& dict) {
+ const base::Value& dict) {
int counters_sum = GetCountersSum(dict);
// If the sample is not large enough yet, pretend there are no top languages.
@@ -66,12 +64,11 @@ std::vector<UrlLanguageHistogram::LanguageInfo> GetAllLanguages(
return std::vector<UrlLanguageHistogram::LanguageInfo>();
std::vector<UrlLanguageHistogram::LanguageInfo> top_languages;
- for (base::DictionaryValue::Iterator itr(dict); !itr.IsAtEnd();
- itr.Advance()) {
- if (!itr.value().is_int())
+ for (const auto itr : dict.DictItems()) {
+ if (!itr.second.is_int())
continue;
top_languages.emplace_back(
- itr.key(), static_cast<float>(itr.value().GetInt()) / counters_sum);
+ itr.first, static_cast<float>(itr.second.GetInt()) / counters_sum);
}
return top_languages;
}
@@ -106,27 +103,25 @@ UrlLanguageHistogram::GetTopLanguages() const {
float UrlLanguageHistogram::GetLanguageFrequency(
const std::string& language_code) const {
- const base::DictionaryValue* dict =
+ const base::Value* dict =
pref_service_->GetDictionary(kUrlLanguageHistogramCounters);
int counters_sum = GetCountersSum(*dict);
// If the sample is not large enough yet, pretend there are no top languages.
if (counters_sum < kMinCountersSum)
return 0;
- int counter_value = 0;
// If the key |language_code| does not exist, |counter_value| stays 0.
- dict->GetInteger(language_code, &counter_value);
+ int counter_value = dict->FindIntKey(language_code).value_or(0);
return static_cast<float>(counter_value) / counters_sum;
}
void UrlLanguageHistogram::OnPageVisited(const std::string& language_code) {
DictionaryPrefUpdate update(pref_service_, kUrlLanguageHistogramCounters);
- base::DictionaryValue* dict = update.Get();
- int counter_value = 0;
+ base::Value* dict = update.Get();
// If the key |language_code| does not exist, |counter_value| stays 0.
- dict->GetInteger(language_code, &counter_value);
- dict->SetInteger(language_code, counter_value + 1);
+ int counter_value = dict->FindIntKey(language_code).value_or(0);
+ dict->SetIntKey(language_code, counter_value + 1);
if (GetCountersSum(*dict) > kMaxCountersSum)
DiscountAndCleanCounters(dict);
diff --git a/chromium/components/language/core/common/language_experiments.cc b/chromium/components/language/core/common/language_experiments.cc
index 42261a2862c..2dad33b7ecd 100644
--- a/chromium/components/language/core/common/language_experiments.cc
+++ b/chromium/components/language/core/common/language_experiments.cc
@@ -7,7 +7,6 @@
#include <map>
#include <string>
-#include "base/feature_list.h"
#include "base/metrics/field_trial_params.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/string_number_conversions.h"
@@ -23,18 +22,10 @@ const base::Feature kAppLanguagePrompt{"AppLanguagePrompt",
base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kForceAppLanguagePrompt{"ForceAppLanguagePrompt",
base::FEATURE_DISABLED_BY_DEFAULT};
-const base::Feature kUseFluentLanguageModel {
- "UseFluentLanguageModel",
-#if defined(OS_IOS)
- base::FEATURE_DISABLED_BY_DEFAULT
-#else
- base::FEATURE_ENABLED_BY_DEFAULT
-#endif
-};
const base::Feature kNotifySyncOnLanguageDetermined{
"NotifySyncOnLanguageDetermined", base::FEATURE_ENABLED_BY_DEFAULT};
-const base::Feature kDetailedLanguageSettings{
- "DetailedLanguageSettings", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kDetailedLanguageSettings{"DetailedLanguageSettings",
+ base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kDesktopRestructuredLanguageSettings{
"DesktopRestructuredLanguageSettings", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kDesktopDetailedLanguageSettings{
@@ -43,8 +34,6 @@ const base::Feature kTranslateAssistContent{"TranslateAssistContent",
base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kTranslateIntent{"TranslateIntent",
base::FEATURE_DISABLED_BY_DEFAULT};
-const base::Feature kDetectedSourceLanguageOption{
- "DetectedSourceLanguageOption", base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kContentLanguagesInLanguagePicker{
"ContentLanguagesInLanguagePicker", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kUseULPLanguagesInChrome{"UseULPLanguagesInChrome",
@@ -63,20 +52,15 @@ OverrideLanguageModel GetOverrideLanguageModel() {
bool should_override_model = base::GetFieldTrialParamsByFeature(
kOverrideTranslateTriggerInIndia, &params);
- // The model overrides ordering is important as it allows us to
- // have concurrent overrides in experiment without having to partition them
- // explicitly. For example, we may have a FLUENT experiment globally and a
- // GEO experiment in India only.
+ // Note: when there are multiple possible override models, the overrides
+ // ordering is important as it allows us to have concurrent overrides in
+ // experiment without having to partition them explicitly.
if (should_override_model &&
params[kOverrideModelKey] == kOverrideModelGeoValue) {
return OverrideLanguageModel::GEO;
}
- if (base::FeatureList::IsEnabled(kUseFluentLanguageModel)) {
- return OverrideLanguageModel::FLUENT;
- }
-
return OverrideLanguageModel::DEFAULT;
}
diff --git a/chromium/components/language/core/common/language_experiments.h b/chromium/components/language/core/common/language_experiments.h
index 9f36a454d3c..f2d071e20c1 100644
--- a/chromium/components/language/core/common/language_experiments.h
+++ b/chromium/components/language/core/common/language_experiments.h
@@ -52,10 +52,6 @@ extern const base::Feature kTranslateAssistContent;
// This feature enables an intent that starts translating the foreground tab.
extern const base::Feature kTranslateIntent;
-// This feature renames the "Unknown" source language option to "Detected
-// Language" and enables translation of unknown source language pages on
-// Android.
-extern const base::Feature kDetectedSourceLanguageOption;
// This feature enables an intent that starts translating the foreground tab.
extern const base::Feature kContentLanguagesInLanguagePicker;
@@ -64,7 +60,6 @@ extern const base::Feature kUseULPLanguagesInChrome;
enum class OverrideLanguageModel {
DEFAULT,
- FLUENT,
GEO,
};
diff --git a/chromium/components/language/core/common/language_util.cc b/chromium/components/language/core/common/language_util.cc
index e983c110205..a14e0a9883e 100644
--- a/chromium/components/language/core/common/language_util.cc
+++ b/chromium/components/language/core/common/language_util.cc
@@ -6,7 +6,6 @@
#include <stddef.h>
#include <algorithm>
-#include <tuple>
#include "base/strings/strcat.h"
#include "base/strings/string_piece.h"
@@ -110,8 +109,7 @@ void ToChromeLanguageSynonym(std::string* language) {
}
}
- base::StringPiece main_part, tail_part;
- std::tie(main_part, tail_part) = language::SplitIntoMainAndTail(*language);
+ auto [main_part, tail_part] = language::SplitIntoMainAndTail(*language);
if (main_part.empty())
return;
diff --git a/chromium/components/language/core/common/locale_util_unittest.cc b/chromium/components/language/core/common/locale_util_unittest.cc
index c9fb3cb09d2..3dbb1a807c0 100644
--- a/chromium/components/language/core/common/locale_util_unittest.cc
+++ b/chromium/components/language/core/common/locale_util_unittest.cc
@@ -58,7 +58,7 @@ TEST_F(LocaleUtilTest, ConvertToActualUILocale) {
locale = es_locale;
is_ui = ConvertToActualUILocale(&locale);
EXPECT_TRUE(is_ui) << es_locale;
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
// iOS uses a different name for es-419 (es-MX).
EXPECT_EQ("es-MX", locale) << es_locale;
#else
@@ -70,7 +70,7 @@ TEST_F(LocaleUtilTest, ConvertToActualUILocale) {
locale = "en";
is_ui = ConvertToActualUILocale(&locale);
EXPECT_TRUE(is_ui);
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
// On Apple platforms, "en" is used instead of "en-US".
EXPECT_EQ("en", locale);
#else
@@ -89,7 +89,7 @@ TEST_F(LocaleUtilTest, ConvertToActualUILocale) {
locale = "pt";
is_ui = ConvertToActualUILocale(&locale);
EXPECT_TRUE(is_ui);
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
// On iOS, "pt" is used instead of "pt-BR".
EXPECT_EQ("pt", locale);
#else
@@ -121,15 +121,11 @@ TEST_F(LocaleUtilTest, ConvertToActualUILocale) {
//---------------------------------------------------------------------------
// This only matters for ChromeOS and Windows, as they are the only systems
// where users can set the display UI.
-#if BUILDFLAG(IS_CHROMEOS_ASH) || defined(OS_WIN)
+#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_WIN)
locale = "sd"; // Sindhi
is_ui = ConvertToActualUILocale(&locale);
EXPECT_FALSE(is_ui);
- locale = "af"; // Afrikaans
- is_ui = ConvertToActualUILocale(&locale);
- EXPECT_FALSE(is_ui);
-
locale = "ga"; // Irish
is_ui = ConvertToActualUILocale(&locale);
EXPECT_FALSE(is_ui);
@@ -137,10 +133,6 @@ TEST_F(LocaleUtilTest, ConvertToActualUILocale) {
locale = "ky"; // Kyrgyz
is_ui = ConvertToActualUILocale(&locale);
EXPECT_FALSE(is_ui);
-
- locale = "zu"; // Zulu
- is_ui = ConvertToActualUILocale(&locale);
- EXPECT_FALSE(is_ui);
#endif
}
diff --git a/chromium/components/language/core/language_model/BUILD.gn b/chromium/components/language/core/language_model/BUILD.gn
index d02b4db7fdb..27357f263c5 100644
--- a/chromium/components/language/core/language_model/BUILD.gn
+++ b/chromium/components/language/core/language_model/BUILD.gn
@@ -4,8 +4,6 @@
static_library("language_model") {
sources = [
- "baseline_language_model.cc",
- "baseline_language_model.h",
"fluent_language_model.cc",
"fluent_language_model.h",
"ulp_language_model.cc",
@@ -28,10 +26,7 @@ static_library("language_model") {
source_set("unit_tests") {
testonly = true
- sources = [
- "baseline_language_model_unittest.cc",
- "fluent_language_model_unittest.cc",
- ]
+ sources = [ "fluent_language_model_unittest.cc" ]
deps = [
"//base",
"//build:chromeos_buildflags",
diff --git a/chromium/components/language/core/language_model/baseline_language_model.cc b/chromium/components/language/core/language_model/baseline_language_model.cc
deleted file mode 100644
index ee68dc8c4ae..00000000000
--- a/chromium/components/language/core/language_model/baseline_language_model.cc
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright 2017 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.
-
-#include "components/language/core/language_model/baseline_language_model.h"
-
-#include <unordered_set>
-
-#include "base/feature_list.h"
-#include "base/strings/string_split.h"
-#include "components/prefs/pref_service.h"
-
-namespace language {
-
-namespace {
-constexpr float kUrlLanguageFreqCutoff = 0.3f;
-} // namespace
-
-BaselineLanguageModel::BaselineLanguageModel(
- PrefService* const pref_service,
- const std::string& ui_lang,
- const std::string& accept_langs_pref)
- : pref_service_(pref_service),
- ui_lang_(ui_lang),
- accept_langs_pref_(accept_langs_pref),
- lang_histogram_(pref_service) {
- DCHECK(pref_service);
- DCHECK(!ui_lang.empty());
- DCHECK(!accept_langs_pref.empty());
- DCHECK(pref_service->FindPreference(accept_langs_pref));
-}
-
-std::vector<LanguageModel::LanguageDetails>
-BaselineLanguageModel::GetLanguages() {
- // Start with UI language.
- std::vector<LanguageDetails> lang_details = {LanguageDetails(ui_lang_, 1.0f)};
- std::unordered_set<std::string> seen = {ui_lang_};
-
- // Then add sufficiently-frequent URL languages.
- const std::vector<UrlLanguageHistogram::LanguageInfo> hist_langs =
- lang_histogram_.GetTopLanguages();
- for (const UrlLanguageHistogram::LanguageInfo& lang_info : hist_langs) {
- if (lang_info.frequency < kUrlLanguageFreqCutoff)
- break;
-
- if (seen.find(lang_info.language_code) != seen.end())
- continue;
-
- lang_details.push_back(LanguageDetails(lang_info.language_code,
- 1.0f / (lang_details.size() + 1)));
- seen.insert(lang_info.language_code);
- }
-
- // Then add accept languages.
- const std::vector<std::string> accept_langs =
- base::SplitString(pref_service_->GetString(accept_langs_pref_), ",",
- base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
- for (const std::string& lang_code : accept_langs) {
- if (seen.find(lang_code) != seen.end())
- continue;
-
- lang_details.push_back(
- LanguageDetails(lang_code, 1.0f / (lang_details.size() + 1)));
- seen.insert(lang_code);
- }
-
- return lang_details;
-}
-
-} // namespace language
diff --git a/chromium/components/language/core/language_model/baseline_language_model.h b/chromium/components/language/core/language_model/baseline_language_model.h
deleted file mode 100644
index 9acf41ed80a..00000000000
--- a/chromium/components/language/core/language_model/baseline_language_model.h
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2017 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.
-
-#ifndef COMPONENTS_LANGUAGE_CORE_LANGUAGE_MODEL_BASELINE_LANGUAGE_MODEL_H_
-#define COMPONENTS_LANGUAGE_CORE_LANGUAGE_MODEL_BASELINE_LANGUAGE_MODEL_H_
-
-#include <string>
-#include <vector>
-
-#include "base/memory/raw_ptr.h"
-#include "components/language/core/browser/language_model.h"
-#include "components/language/core/browser/url_language_histogram.h"
-
-class PrefService;
-
-namespace language {
-
-// A language model that attempts to approximate Chrome's legacy behaviour as
-// much as possible.
-//
-// Produces a list of languages in the following order:
-// 1) Chrome's UI language,
-// 2) The most frequently occuring languages in visited URLs (if they surpass a
-// given frequency threshold),
-// 3) The user's accept languages.
-//
-// No code appears twice in the list. Codes with region subtags may appear in
-// the list and are not backed-off. Entries are scored by inverse rank (i.e. 1,
-// 1/2, 1/3, ...).
-//
-// NOTE: This model reads URL language histogram and accept language information
-// from user preferences. Hence, both sources must be registered on the
-// PrefService passed in at construction time.
-class BaselineLanguageModel : public LanguageModel {
- public:
- BaselineLanguageModel(PrefService* pref_service,
- const std::string& ui_lang,
- const std::string& accept_langs_pref);
-
- // LanguageModel implementation.
- std::vector<LanguageDetails> GetLanguages() override;
-
- private:
- const raw_ptr<const PrefService> pref_service_;
- const std::string ui_lang_;
- const std::string accept_langs_pref_;
- const UrlLanguageHistogram lang_histogram_;
-};
-
-} // namespace language
-
-#endif // COMPONENTS_LANGUAGE_CORE_LANGUAGE_MODEL_BASELINE_LANGUAGE_MODEL_H_
diff --git a/chromium/components/language/core/language_model/baseline_language_model_unittest.cc b/chromium/components/language/core/language_model/baseline_language_model_unittest.cc
deleted file mode 100644
index ddd5cc956bb..00000000000
--- a/chromium/components/language/core/language_model/baseline_language_model_unittest.cc
+++ /dev/null
@@ -1,135 +0,0 @@
-// Copyright 2017 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.
-
-#include "components/language/core/language_model/baseline_language_model.h"
-
-#include <cmath>
-
-#include "components/language/core/browser/url_language_histogram.h"
-#include "components/prefs/pref_registry_simple.h"
-#include "components/prefs/testing_pref_service.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace language {
-
-using testing::ElementsAre;
-using Ld = BaselineLanguageModel::LanguageDetails;
-
-constexpr static float kFloatEps = 0.00001f;
-constexpr static char kAcceptPref[] = "intl.accept_languages";
-
-class BaselineLanguageModelTest : public testing::Test {
- protected:
- void SetUp() override {
- // The URL language histogram and accept language list are inputs to the
- // baseline model.
- UrlLanguageHistogram::RegisterProfilePrefs(prefs_.registry());
- prefs_.registry()->RegisterStringPref(kAcceptPref, std::string());
- }
-
- TestingPrefServiceSimple prefs_;
-};
-
-// Compares LanguageDetails.
-MATCHER_P(EqualsLd, lang_details, "") {
- return arg.lang_code == lang_details.lang_code &&
- std::abs(arg.score - lang_details.score) < kFloatEps;
-}
-
-// Check the minimum model: just a UI language.
-TEST_F(BaselineLanguageModelTest, UiOnly) {
- BaselineLanguageModel model(&prefs_, "en", kAcceptPref);
- EXPECT_THAT(model.GetLanguages(), ElementsAre(EqualsLd(Ld("en", 1.0f))));
-}
-
-// Check with UI language and language browsing history.
-TEST_F(BaselineLanguageModelTest, UiAndHist) {
- // Simulate many website visits, as there is a minimum frequency threshold for
- // histogram languages.
- UrlLanguageHistogram hist(&prefs_);
- for (int i = 0; i < 100; ++i) {
- hist.OnPageVisited("it");
- hist.OnPageVisited("it");
- hist.OnPageVisited("de");
- }
-
- BaselineLanguageModel model(&prefs_, "en", kAcceptPref);
- EXPECT_THAT(model.GetLanguages(), ElementsAre(EqualsLd(Ld("en", 1.0f)),
- EqualsLd(Ld("it", 1.0f / 2)),
- EqualsLd(Ld("de", 1.0f / 3))));
-}
-
-// Check with UI language and accept languages.
-TEST_F(BaselineLanguageModelTest, UiAndAccept) {
- prefs_.SetString(kAcceptPref, "ja,fr");
-
- BaselineLanguageModel model(&prefs_, "en", kAcceptPref);
- EXPECT_THAT(model.GetLanguages(), ElementsAre(EqualsLd(Ld("en", 1.0f)),
- EqualsLd(Ld("ja", 1.0f / 2)),
- EqualsLd(Ld("fr", 1.0f / 3))));
-}
-
-// Check with all three sources.
-TEST_F(BaselineLanguageModelTest, UiAndHistAndAccept) {
- // Simulate many website visits, as there is a minimum frequency threshold for
- // histogram languages.
- UrlLanguageHistogram hist(&prefs_);
- for (int i = 0; i < 100; ++i) {
- hist.OnPageVisited("it");
- hist.OnPageVisited("it");
- hist.OnPageVisited("de");
- }
-
- prefs_.SetString(kAcceptPref, "ja,fr");
-
- BaselineLanguageModel model(&prefs_, "en", kAcceptPref);
- EXPECT_THAT(
- model.GetLanguages(),
- ElementsAre(EqualsLd(Ld("en", 1.0f)), EqualsLd(Ld("it", 1.0f / 2)),
- EqualsLd(Ld("de", 1.0f / 3)), EqualsLd(Ld("ja", 1.0f / 4)),
- EqualsLd(Ld("fr", 1.0f / 5))));
-}
-
-// Check that repeats among sources are ignored.
-TEST_F(BaselineLanguageModelTest, Repeats) {
- // Simulate many website visits, as there is a minimum frequency threshold for
- // histogram languages.
- UrlLanguageHistogram hist(&prefs_);
- for (int i = 0; i < 100; ++i) {
- hist.OnPageVisited("en");
- hist.OnPageVisited("en");
- hist.OnPageVisited("it");
- }
-
- prefs_.SetString(kAcceptPref, "en,ja,it");
-
- BaselineLanguageModel model(&prefs_, "en", kAcceptPref);
- EXPECT_THAT(model.GetLanguages(), ElementsAre(EqualsLd(Ld("en", 1.0f)),
- EqualsLd(Ld("it", 1.0f / 2)),
- EqualsLd(Ld("ja", 1.0f / 3))));
-}
-
-// Check that regions are not backed off.
-TEST_F(BaselineLanguageModelTest, Regions) {
- // Simulate many website visits, as there is a minimum frequency threshold for
- // histogram languages.
- UrlLanguageHistogram hist(&prefs_);
- for (int i = 0; i < 100; ++i) {
- hist.OnPageVisited("en-AU");
- hist.OnPageVisited("en-AU");
- hist.OnPageVisited("en-CA");
- }
-
- prefs_.SetString(kAcceptPref, "en-GB");
-
- BaselineLanguageModel model(&prefs_, "en", kAcceptPref);
- EXPECT_THAT(
- model.GetLanguages(),
- ElementsAre(EqualsLd(Ld("en", 1.0f)), EqualsLd(Ld("en-AU", 1.0f / 2)),
- EqualsLd(Ld("en-CA", 1.0f / 3)),
- EqualsLd(Ld("en-GB", 1.0f / 4))));
-}
-
-} // namespace language
diff --git a/chromium/components/lens/lens_features.cc b/chromium/components/lens/lens_features.cc
index 485403bab34..a324c58bee5 100644
--- a/chromium/components/lens/lens_features.cc
+++ b/chromium/components/lens/lens_features.cc
@@ -11,54 +11,44 @@ namespace lens {
namespace features {
const base::Feature kLensStandalone{"LensStandalone",
- base::FEATURE_DISABLED_BY_DEFAULT};
-
-const base::Feature kLensRegionSearch{"LensRegionSearch",
- base::FEATURE_DISABLED_BY_DEFAULT};
+ base::FEATURE_ENABLED_BY_DEFAULT};
const base::FeatureParam<bool> kRegionSearchMacCursorFix{
- &kLensRegionSearch, "region-search-mac-cursor-fix", true};
+ &kLensStandalone, "region-search-mac-cursor-fix", true};
const base::FeatureParam<bool> kRegionSearchUseMenuItemAltText1{
- &kLensRegionSearch, "use-menu-item-alt-text-1", false};
+ &kLensStandalone, "use-menu-item-alt-text-1", false};
const base::FeatureParam<bool> kRegionSearchUseMenuItemAltText2{
- &kLensRegionSearch, "use-menu-item-alt-text-2", false};
+ &kLensStandalone, "use-menu-item-alt-text-2", false};
const base::FeatureParam<bool> kRegionSearchUseMenuItemAltText3{
- &kLensRegionSearch, "use-menu-item-alt-text-3", false};
+ &kLensStandalone, "use-menu-item-alt-text-3", false};
const base::FeatureParam<bool> kRegionSearchUseMenuItemAltText4{
- &kLensRegionSearch, "use-menu-item-alt-text-4", true};
+ &kLensStandalone, "use-menu-item-alt-text-4", true};
const base::FeatureParam<bool> kEnableUKMLoggingForRegionSearch{
- &kLensRegionSearch, "region-search-enable-ukm-logging", false};
+ &kLensStandalone, "region-search-enable-ukm-logging", true};
const base::FeatureParam<bool> kEnableUKMLoggingForImageSearch{
- &kLensStandalone, "enable-ukm-logging", false};
-
-const base::FeatureParam<bool> kEnableSidePanelForLensRegionSearch{
- &kLensRegionSearch, "region-search-enable-side-panel", true};
+ &kLensStandalone, "enable-ukm-logging", true};
-const base::FeatureParam<bool> kEnableSidePanelForLensImageSearch{
+const base::FeatureParam<bool> kEnableSidePanelForLens{
&kLensStandalone, "enable-side-panel", false};
constexpr base::FeatureParam<int> kMaxPixelsForRegionSearch{
- &kLensRegionSearch, "region-search-dimensions-max-pixels", 1000};
+ &kLensStandalone, "region-search-dimensions-max-pixels", 1000};
constexpr base::FeatureParam<int> kMaxAreaForRegionSearch{
- &kLensRegionSearch, "region-search-dimensions-max-area", 1000000};
+ &kLensStandalone, "region-search-dimensions-max-area", 1000000};
constexpr base::FeatureParam<int> kMaxPixelsForImageSearch{
&kLensStandalone, "dimensions-max-pixels", 1000};
-constexpr base::FeatureParam<std::string> kHomepageURLForImageSearch{
+constexpr base::FeatureParam<std::string> kHomepageURLForLens{
&kLensStandalone, "lens-homepage-url", "https://lens.google.com/"};
-constexpr base::FeatureParam<std::string> kHomepageURLForRegionSearch{
- &kLensRegionSearch, "region-search-lens-homepage-url",
- "https://lens.google.com/"};
-
bool GetEnableUKMLoggingForRegionSearch() {
return kEnableUKMLoggingForRegionSearch.Get();
}
@@ -79,12 +69,13 @@ int GetMaxPixelsForImageSearch() {
return kMaxPixelsForImageSearch.Get();
}
-std::string GetHomepageURLForImageSearch() {
- return kHomepageURLForImageSearch.Get();
+std::string GetHomepageURLForLens() {
+ return kHomepageURLForLens.Get();
}
-std::string GetHomepageURLForRegionSearch() {
- return kHomepageURLForRegionSearch.Get();
+bool IsLensSidePanelEnabled() {
+ return base::FeatureList::IsEnabled(kLensStandalone) &&
+ kEnableSidePanelForLens.Get();
}
} // namespace features
diff --git a/chromium/components/lens/lens_features.h b/chromium/components/lens/lens_features.h
index 095e9fdd71a..73a7988ac87 100644
--- a/chromium/components/lens/lens_features.h
+++ b/chromium/components/lens/lens_features.h
@@ -8,6 +8,7 @@
#include <string>
#include "base/feature_list.h"
+#include "base/metrics/field_trial_params.h"
namespace lens {
namespace features {
@@ -40,11 +41,8 @@ extern const base::FeatureParam<bool> kEnableUKMLoggingForRegionSearch;
// Enables UKM logging for the LensStandalone feature.
extern const base::FeatureParam<bool> kEnableUKMLoggingForImageSearch;
-// Enables the side panel for Lens Region Search.
-extern const base::FeatureParam<bool> kEnableSidePanelForLensRegionSearch;
-
-// Enables the side panel for Lens Image Search.
-extern const base::FeatureParam<bool> kEnableSidePanelForLensImageSearch;
+// Enables the side panel for Lens features on Chrome where supported.
+extern const base::FeatureParam<bool> kEnableSidePanelForLens;
// Returns whether to enable UKM logging for Lens Region Search feature.
extern bool GetEnableUKMLoggingForRegionSearch();
@@ -63,10 +61,10 @@ extern int GetMaxAreaForRegionSearch();
extern int GetMaxPixelsForImageSearch();
// The URL for the Lens home page.
-extern std::string GetHomepageURLForImageSearch();
+extern std::string GetHomepageURLForLens();
-// The URL for the Lens home page as defined by Lens Region Search feature.
-extern std::string GetHomepageURLForRegionSearch();
+// Returns whether the Lens side panel is enabled.
+extern bool IsLensSidePanelEnabled();
} // namespace features
} // namespace lens
diff --git a/chromium/components/leveldb_proto/internal/proto_database_perftest.cc b/chromium/components/leveldb_proto/internal/proto_database_perftest.cc
index 154678e3f04..00f3464dccf 100644
--- a/chromium/components/leveldb_proto/internal/proto_database_perftest.cc
+++ b/chromium/components/leveldb_proto/internal/proto_database_perftest.cc
@@ -564,7 +564,7 @@ class ProtoDBPerfTest : public testing::Test {
};
// Flakily times out on Windows and Mac, see http://crbug.com/918874.
-#if defined(OS_WIN) || defined(OS_MAC)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
#define MAYBE_InsertMultipleDBsAlternating_Individual_100b \
DISABLED_InsertMultipleDBsAlternating_Individual_100b
#else
@@ -579,7 +579,7 @@ TEST_F(ProtoDBPerfTest, MAYBE_InsertMultipleDBsAlternating_Individual_100b) {
}
// Flakily times out on Windows and Mac, see http://crbug.com/918874.
-#if defined(OS_WIN) || defined(OS_MAC)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
#define MAYBE_InsertMultipleDBsAlternating_Individual_1000b \
DISABLED_InsertMultipleDBsAlternating_Individual_1000b
#else
@@ -594,7 +594,7 @@ TEST_F(ProtoDBPerfTest, MAYBE_InsertMultipleDBsAlternating_Individual_1000b) {
}
// Flakily times out on Windows and Mac, see http://crbug.com/918874.
-#if defined(OS_WIN) || defined(OS_MAC)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
#define MAYBE_InsertSingleDBAlternating_Individual_100b \
DISABLED_InsertSingleDBAlternating_Individual_100b
#else
@@ -609,7 +609,7 @@ TEST_F(ProtoDBPerfTest, MAYBE_InsertSingleDBAlternating_Individual_100b) {
}
// Flakily times out on Windows and Mac, see http://crbug.com/918874.
-#if defined(OS_WIN) || defined(OS_MAC)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
#define MAYBE_InsertSingleDBAlternating_Individual_1000b \
DISABLED_InsertSingleDBAlternating_Individual_1000b
#else
@@ -662,7 +662,7 @@ TEST_F(ProtoDBPerfTest, DistributionTestSmall_FewEntries_Multi) {
}
// Flakily times out on Mac, see http://crbug.com/918874.
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
#define MAYBE_DistributionTestSmall_ManyEntries_Single \
DISABLED_DistributionTestSmall_ManyEntries_Single
#else
@@ -675,7 +675,7 @@ TEST_F(ProtoDBPerfTest, MAYBE_DistributionTestSmall_ManyEntries_Single) {
}
// Flakily times out on Mac, see http://crbug.com/918874.
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
#define MAYBE_DistributionTestSmall_ManyEntries_Multi \
DISABLED_DistributionTestSmall_ManyEntries_Multi
#else
@@ -688,7 +688,7 @@ TEST_F(ProtoDBPerfTest, MAYBE_DistributionTestSmall_ManyEntries_Multi) {
}
// Flakily times out on Mac, see http://crbug.com/918874.
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
#define MAYBE_DistributionTestSmall_ManyEntries_Batch_Single \
DISABLED_DistributionTestSmall_ManyEntries_Batch_Single
#else
@@ -701,7 +701,7 @@ TEST_F(ProtoDBPerfTest, MAYBE_DistributionTestSmall_ManyEntries_Batch_Single) {
}
// Flakily times out on Mac, see http://crbug.com/918874.
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
#define MAYBE_DistributionTestSmall_ManyEntries_Batch_Multi \
DISABLED_DistributionTestSmall_ManyEntries_Batch_Multi
#else
diff --git a/chromium/components/leveldb_proto/internal/proto_database_selector.cc b/chromium/components/leveldb_proto/internal/proto_database_selector.cc
index 1c564b0a2a9..0e6f6485baf 100644
--- a/chromium/components/leveldb_proto/internal/proto_database_selector.cc
+++ b/chromium/components/leveldb_proto/internal/proto_database_selector.cc
@@ -473,7 +473,7 @@ void ProtoDatabaseSelector::AddTransaction(base::OnceClosure task) {
break;
case InitStatus::NOT_STARTED:
NOTREACHED();
- FALLTHROUGH;
+ [[fallthrough]];
case InitStatus::DONE:
std::move(task).Run();
break;
diff --git a/chromium/components/leveldb_proto/internal/proto_leveldb_wrapper.cc b/chromium/components/leveldb_proto/internal/proto_leveldb_wrapper.cc
index f07b745d95d..44b477b5009 100644
--- a/chromium/components/leveldb_proto/internal/proto_leveldb_wrapper.cc
+++ b/chromium/components/leveldb_proto/internal/proto_leveldb_wrapper.cc
@@ -427,7 +427,7 @@ void ProtoLevelDBWrapper::SetMetricsId(const std::string& id) {
bool ProtoLevelDBWrapper::GetApproximateMemoryUse(uint64_t* approx_mem_use) {
if (!db_)
- return 0;
+ return false;
return db_->GetApproximateMemoryUse(approx_mem_use);
}
diff --git a/chromium/components/leveldb_proto/internal/shared_proto_database_client.cc b/chromium/components/leveldb_proto/internal/shared_proto_database_client.cc
index af84fd7e7a3..60d6ba5cfc1 100644
--- a/chromium/components/leveldb_proto/internal/shared_proto_database_client.cc
+++ b/chromium/components/leveldb_proto/internal/shared_proto_database_client.cc
@@ -44,50 +44,78 @@ class ObsoleteClientsDbHolder
Callbacks::UpdateCallback callback_;
};
+PhysicalKey MakePhysicalKey(const KeyPrefix& prefix, const LogicalKey& key) {
+ return PhysicalKey(base::StrCat({prefix.value(), key.value()}));
+}
+
} // namespace
// static
-bool SharedProtoDatabaseClient::HasPrefix(const std::string& key,
- const std::string& prefix) {
- return base::StartsWith(key, prefix, base::CompareCase::SENSITIVE);
+bool SharedProtoDatabaseClient::HasPrefix(const PhysicalKey& key,
+ const KeyPrefix& prefix) {
+ return base::StartsWith(key.value(), prefix.value(),
+ base::CompareCase::SENSITIVE);
}
// static
-std::string SharedProtoDatabaseClient::StripPrefix(const std::string& key,
- const std::string& prefix) {
- DCHECK(HasPrefix(key, prefix));
- return HasPrefix(key, prefix) ? key.substr(prefix.length()) : key;
+absl::optional<LogicalKey> SharedProtoDatabaseClient::StripPrefix(
+ const PhysicalKey& key,
+ const KeyPrefix& prefix) {
+ if (!HasPrefix(key, prefix))
+ return absl::nullopt;
+ return LogicalKey(key.value().substr(prefix.value().length()));
}
// static
std::unique_ptr<KeyVector> SharedProtoDatabaseClient::PrefixStrings(
std::unique_ptr<KeyVector> strings,
- const std::string& prefix) {
+ const KeyPrefix& prefix) {
for (auto& str : *strings)
- str.assign(base::StrCat({prefix, str}));
+ str.assign(MakePhysicalKey(prefix, LogicalKey(str)).value());
return strings;
}
// static
bool SharedProtoDatabaseClient::KeyFilterStripPrefix(
const KeyFilter& key_filter,
- const std::string& prefix,
- const std::string& key) {
+ const KeyPrefix& prefix,
+ const PhysicalKey& key) {
if (key_filter.is_null())
return true;
- return key_filter.Run(StripPrefix(key, prefix));
+ absl::optional<LogicalKey> stripped = StripPrefix(key, prefix);
+ if (!stripped)
+ return false;
+ return key_filter.Run(stripped->value());
+}
+
+// static
+bool SharedProtoDatabaseClient::KeyStringFilterStripPrefix(
+ const KeyFilter& key_filter,
+ const KeyPrefix& prefix,
+ const std::string& key) {
+ return KeyFilterStripPrefix(key_filter, prefix, PhysicalKey(key));
}
// static
Enums::KeyIteratorAction
SharedProtoDatabaseClient::KeyIteratorControllerStripPrefix(
const KeyIteratorController& controller,
- const std::string& prefix,
- const std::string& key) {
+ const KeyPrefix& prefix,
+ const PhysicalKey& key) {
DCHECK(!controller.is_null());
- if (!HasPrefix(key, prefix))
+ absl::optional<LogicalKey> stripped = StripPrefix(key, prefix);
+ if (!stripped)
return Enums::kSkipAndStop;
- return controller.Run(StripPrefix(key, prefix));
+ return controller.Run(stripped->value());
+}
+
+// static
+Enums::KeyIteratorAction
+SharedProtoDatabaseClient::KeyStringIteratorControllerStripPrefix(
+ const KeyIteratorController& controller,
+ const KeyPrefix& prefix,
+ const std::string& key) {
+ return KeyIteratorControllerStripPrefix(controller, prefix, PhysicalKey(key));
}
// static
@@ -132,7 +160,7 @@ void SharedProtoDatabaseClient::DestroyObsoleteSharedProtoDatabaseClients(
// the prefix contains the client namespace at the beginning.
db_wrapper_ptr->RemoveKeys(
base::BindRepeating([](const std::string& key) { return true; }),
- SharedProtoDatabaseClient::PrefixForDatabase(list[i]),
+ SharedProtoDatabaseClient::PrefixForDatabase(list[i]).value(),
std::move(callback_wrapper));
}
}
@@ -144,8 +172,8 @@ void SharedProtoDatabaseClient::SetObsoleteClientListForTesting(
}
// static
-std::string SharedProtoDatabaseClient::PrefixForDatabase(ProtoDbType db_type) {
- return base::StringPrintf("%d_", static_cast<int>(db_type));
+KeyPrefix SharedProtoDatabaseClient::PrefixForDatabase(ProtoDbType db_type) {
+ return KeyPrefix(base::StringPrintf("%d_", static_cast<int>(db_type)));
}
SharedProtoDatabaseClient::SharedProtoDatabaseClient(
@@ -165,7 +193,8 @@ SharedProtoDatabaseClient::~SharedProtoDatabaseClient() {
void SharedProtoDatabaseClient::Init(const std::string& client_uma_name,
Callbacks::InitStatusCallback callback) {
SetMetricsId(client_uma_name);
- GetSharedDatabaseInitStatusAsync(prefix_, parent_db_, std::move(callback));
+ GetSharedDatabaseInitStatusAsync(client_db_id(), parent_db_,
+ std::move(callback));
}
void SharedProtoDatabaseClient::InitWithDatabase(
@@ -204,8 +233,10 @@ void SharedProtoDatabaseClient::UpdateEntriesWithRemoveFilter(
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
UniqueProtoDatabase::UpdateEntriesWithRemoveFilter(
PrefixKeyEntryVector(std::move(entries_to_save), prefix_),
- base::BindRepeating(&KeyFilterStripPrefix, delete_key_filter, prefix_),
- prefix_ + target_prefix, std::move(callback));
+ base::BindRepeating(&KeyStringFilterStripPrefix, delete_key_filter,
+ prefix_),
+ MakePhysicalKey(prefix_, LogicalKey(target_prefix)).value(),
+ std::move(callback));
}
void SharedProtoDatabaseClient::LoadEntries(Callbacks::LoadCallback callback) {
@@ -228,8 +259,9 @@ void SharedProtoDatabaseClient::LoadEntriesWithFilter(
Callbacks::LoadCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
UniqueProtoDatabase::LoadEntriesWithFilter(
- base::BindRepeating(&KeyFilterStripPrefix, filter, prefix_), options,
- prefix_ + target_prefix, std::move(callback));
+ base::BindRepeating(&KeyStringFilterStripPrefix, filter, prefix_),
+ options, MakePhysicalKey(prefix_, LogicalKey(target_prefix)).value(),
+ std::move(callback));
}
void SharedProtoDatabaseClient::LoadKeys(Callbacks::LoadKeysCallback callback) {
@@ -241,7 +273,7 @@ void SharedProtoDatabaseClient::LoadKeys(const std::string& target_prefix,
Callbacks::LoadKeysCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
UniqueProtoDatabase::LoadKeys(
- prefix_ + target_prefix,
+ MakePhysicalKey(prefix_, LogicalKey(target_prefix)).value(),
base::BindOnce(&SharedProtoDatabaseClient::StripPrefixLoadKeysCallback,
std::move(callback), prefix_));
}
@@ -265,8 +297,8 @@ void SharedProtoDatabaseClient::LoadKeysAndEntriesWithFilter(
Callbacks::LoadKeysAndEntriesCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
UniqueProtoDatabase::LoadKeysAndEntriesWithFilter(
- base::BindRepeating(&KeyFilterStripPrefix, filter, prefix_), options,
- prefix_ + target_prefix,
+ base::BindRepeating(&KeyStringFilterStripPrefix, filter, prefix_),
+ options, MakePhysicalKey(prefix_, LogicalKey(target_prefix)).value(),
base::BindOnce(
&SharedProtoDatabaseClient::StripPrefixLoadKeysAndEntriesCallback,
std::move(callback), prefix_));
@@ -278,7 +310,8 @@ void SharedProtoDatabaseClient::LoadKeysAndEntriesInRange(
Callbacks::LoadKeysAndEntriesCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
UniqueProtoDatabase::LoadKeysAndEntriesInRange(
- prefix_ + start, prefix_ + end,
+ MakePhysicalKey(prefix_, LogicalKey(start)).value(),
+ MakePhysicalKey(prefix_, LogicalKey(end)).value(),
base::BindOnce(
&SharedProtoDatabaseClient::StripPrefixLoadKeysAndEntriesCallback,
std::move(callback), prefix_));
@@ -290,8 +323,8 @@ void SharedProtoDatabaseClient::LoadKeysAndEntriesWhile(
Callbacks::LoadKeysAndEntriesCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
UniqueProtoDatabase::LoadKeysAndEntriesWhile(
- prefix_ + start,
- base::BindRepeating(&KeyIteratorControllerStripPrefix, controller,
+ MakePhysicalKey(prefix_, LogicalKey(start)).value(),
+ base::BindRepeating(&KeyStringIteratorControllerStripPrefix, controller,
prefix_),
base::BindOnce(
&SharedProtoDatabaseClient::StripPrefixLoadKeysAndEntriesCallback,
@@ -301,7 +334,8 @@ void SharedProtoDatabaseClient::LoadKeysAndEntriesWhile(
void SharedProtoDatabaseClient::GetEntry(const std::string& key,
Callbacks::GetCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- UniqueProtoDatabase::GetEntry(prefix_ + key, std::move(callback));
+ UniqueProtoDatabase::GetEntry(
+ MakePhysicalKey(prefix_, LogicalKey(key)).value(), std::move(callback));
}
void SharedProtoDatabaseClient::Destroy(Callbacks::DestroyCallback callback) {
@@ -320,7 +354,7 @@ void SharedProtoDatabaseClient::UpdateClientInitMetadata(
migration_status_ = migration_status;
// Tell the SharedProtoDatabase that we've seen the corruption state so it's
// safe to update its records for this client.
- UpdateClientMetadataAsync(parent_db_, prefix_, migration_status_,
+ UpdateClientMetadataAsync(parent_db_, client_db_id(), migration_status_,
base::BindOnce([](bool success) {
// TODO(thildebr): Should we do anything special
// here? If the shared DB can't update the
@@ -333,25 +367,33 @@ void SharedProtoDatabaseClient::UpdateClientInitMetadata(
// static
void SharedProtoDatabaseClient::StripPrefixLoadKeysCallback(
Callbacks::LoadKeysCallback callback,
- const std::string& prefix,
+ const KeyPrefix& prefix,
bool success,
std::unique_ptr<leveldb_proto::KeyVector> keys) {
auto stripped_keys = std::make_unique<leveldb_proto::KeyVector>();
- for (auto& key : *keys)
- stripped_keys->emplace_back(StripPrefix(key, prefix));
+ for (auto& key : *keys) {
+ absl::optional<LogicalKey> stripped = StripPrefix(PhysicalKey(key), prefix);
+ if (!stripped)
+ continue;
+ stripped_keys->emplace_back(stripped->value());
+ }
std::move(callback).Run(success, std::move(stripped_keys));
}
// static
void SharedProtoDatabaseClient::StripPrefixLoadKeysAndEntriesCallback(
Callbacks::LoadKeysAndEntriesCallback callback,
- const std::string& prefix,
+ const KeyPrefix& prefix,
bool success,
std::unique_ptr<KeyValueMap> keys_entries) {
auto stripped_keys_map = std::make_unique<KeyValueMap>();
for (auto& key_entry : *keys_entries) {
+ absl::optional<LogicalKey> stripped_key =
+ StripPrefix(PhysicalKey(key_entry.first), prefix);
+ if (!stripped_key)
+ continue;
stripped_keys_map->insert(
- std::make_pair(StripPrefix(key_entry.first, prefix), key_entry.second));
+ std::make_pair(stripped_key->value(), key_entry.second));
}
std::move(callback).Run(success, std::move(stripped_keys_map));
}
@@ -359,9 +401,10 @@ void SharedProtoDatabaseClient::StripPrefixLoadKeysAndEntriesCallback(
// static
std::unique_ptr<KeyValueVector> SharedProtoDatabaseClient::PrefixKeyEntryVector(
std::unique_ptr<KeyValueVector> kev,
- const std::string& prefix) {
+ const KeyPrefix& prefix) {
for (auto& key_entry_pair : *kev) {
- key_entry_pair.first = base::StrCat({prefix, key_entry_pair.first});
+ key_entry_pair.first =
+ MakePhysicalKey(prefix, LogicalKey(key_entry_pair.first)).value();
}
return kev;
}
diff --git a/chromium/components/leveldb_proto/internal/shared_proto_database_client.h b/chromium/components/leveldb_proto/internal/shared_proto_database_client.h
index 29b29edb261..f284119262e 100644
--- a/chromium/components/leveldb_proto/internal/shared_proto_database_client.h
+++ b/chromium/components/leveldb_proto/internal/shared_proto_database_client.h
@@ -11,13 +11,22 @@
#include "base/bind.h"
#include "base/component_export.h"
#include "base/sequence_checker.h"
+#include "base/types/strong_alias.h"
#include "components/leveldb_proto/internal/leveldb_database.h"
#include "components/leveldb_proto/internal/proto/shared_db_metadata.pb.h"
#include "components/leveldb_proto/internal/unique_proto_database.h"
#include "components/leveldb_proto/public/shared_proto_database_client_list.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
namespace leveldb_proto {
+// Key prefix not visible to the client.
+using KeyPrefix = base::StrongAlias<class KeyPrefixTag, std::string>;
+// Logical key visible to the client.
+using LogicalKey = base::StrongAlias<class LogicalKeyTag, std::string>;
+// Physical key used in the underlying db.
+using PhysicalKey = base::StrongAlias<class PhysicalKeyTag, std::string>;
+
class SharedProtoDatabase;
// TODO: Move all these as static or member functions in the class.
@@ -32,22 +41,29 @@ using SharedClientInitCallback =
class COMPONENT_EXPORT(LEVELDB_PROTO) SharedProtoDatabaseClient
: public UniqueProtoDatabase {
public:
- static std::string PrefixForDatabase(ProtoDbType db_type);
+ static KeyPrefix PrefixForDatabase(ProtoDbType db_type);
- static bool HasPrefix(const std::string& key, const std::string& prefix);
- static std::string StripPrefix(const std::string& key,
- const std::string& prefix);
+ static bool HasPrefix(const PhysicalKey& key, const KeyPrefix& prefix);
+ static absl::optional<LogicalKey> StripPrefix(const PhysicalKey& key,
+ const KeyPrefix& prefix);
static std::unique_ptr<KeyVector> PrefixStrings(
std::unique_ptr<KeyVector> strings,
- const std::string& prefix);
+ const KeyPrefix& prefix);
static bool KeyFilterStripPrefix(const KeyFilter& key_filter,
- const std::string& prefix,
- const std::string& key);
+ const KeyPrefix& prefix,
+ const PhysicalKey& key);
+ static bool KeyStringFilterStripPrefix(const KeyFilter& key_filter,
+ const KeyPrefix& prefix,
+ const std::string& key);
static Enums::KeyIteratorAction KeyIteratorControllerStripPrefix(
const KeyIteratorController& controller,
- const std::string& prefix,
+ const KeyPrefix& prefix,
+ const PhysicalKey& key);
+ static Enums::KeyIteratorAction KeyStringIteratorControllerStripPrefix(
+ const KeyIteratorController& controller,
+ const KeyPrefix& prefix,
const std::string& key);
static void GetSharedDatabaseInitStatusAsync(
@@ -141,7 +157,7 @@ class COMPONENT_EXPORT(LEVELDB_PROTO) SharedProtoDatabaseClient
Callbacks::InitCallback GetInitCallback() const;
- const std::string& client_db_id() const { return prefix_; }
+ const std::string& client_db_id() const { return prefix_.value(); }
void set_migration_status(
SharedDBMetadataProto::MigrationStatus migration_status) {
@@ -168,18 +184,18 @@ class COMPONENT_EXPORT(LEVELDB_PROTO) SharedProtoDatabaseClient
static void StripPrefixLoadKeysCallback(
Callbacks::LoadKeysCallback callback,
- const std::string& prefix,
+ const KeyPrefix& prefix,
bool success,
std::unique_ptr<leveldb_proto::KeyVector> keys);
static void StripPrefixLoadKeysAndEntriesCallback(
Callbacks::LoadKeysAndEntriesCallback callback,
- const std::string& prefix,
+ const KeyPrefix& prefix,
bool success,
std::unique_ptr<KeyValueMap> keys_entries);
static std::unique_ptr<KeyValueVector> PrefixKeyEntryVector(
std::unique_ptr<KeyValueVector> kev,
- const std::string& prefix);
+ const KeyPrefix& prefix);
SEQUENCE_CHECKER(sequence_checker_);
@@ -190,7 +206,7 @@ class COMPONENT_EXPORT(LEVELDB_PROTO) SharedProtoDatabaseClient
SharedDBMetadataProto::MigrationStatus migration_status_ =
SharedDBMetadataProto::MIGRATION_NOT_ATTEMPTED;
- const std::string prefix_;
+ const KeyPrefix prefix_;
scoped_refptr<SharedProtoDatabase> parent_db_;
diff --git a/chromium/components/leveldb_proto/internal/shared_proto_database_client_unittest.cc b/chromium/components/leveldb_proto/internal/shared_proto_database_client_unittest.cc
index 09263f53fa0..5307fca32a9 100644
--- a/chromium/components/leveldb_proto/internal/shared_proto_database_client_unittest.cc
+++ b/chromium/components/leveldb_proto/internal/shared_proto_database_client_unittest.cc
@@ -89,7 +89,8 @@ class SharedProtoDatabaseClientTest : public testing::Test {
auto full_key =
db_type == ProtoDbType::LAST
? key
- : SharedProtoDatabaseClient::PrefixForDatabase(db_type) + key;
+ : SharedProtoDatabaseClient::PrefixForDatabase(db_type).value() +
+ key;
if (key_set.find(full_key) == key_set.end())
return false;
}
@@ -104,7 +105,8 @@ class SharedProtoDatabaseClientTest : public testing::Test {
entry_id_set.insert(entry);
// Entry IDs don't include the full prefix, so we don't look for that here.
- auto prefix = SharedProtoDatabaseClient::PrefixForDatabase(db_type);
+ std::string prefix =
+ SharedProtoDatabaseClient::PrefixForDatabase(db_type).value();
for (auto& key : db_keys) {
if (entry_id_set.find(prefix + key) == entry_id_set.end())
return false;
@@ -120,7 +122,7 @@ class SharedProtoDatabaseClientTest : public testing::Test {
std::make_unique<ProtoDatabase<std::string>::KeyEntryVector>();
for (auto& key : keys) {
std::string value;
- value = client->prefix_ + key;
+ value = client->prefix_.value() + key;
entries->emplace_back(std::make_pair(key, std::move(value)));
}
@@ -148,7 +150,7 @@ class SharedProtoDatabaseClientTest : public testing::Test {
std::make_unique<ProtoDatabase<std::string>::KeyEntryVector>();
for (auto& key : keys) {
std::string value;
- value = client->prefix_ + key;
+ value = client->prefix_.value() + key;
entries->emplace_back(std::make_pair(key, std::move(value)));
}
@@ -304,7 +306,7 @@ class SharedProtoDatabaseClientTest : public testing::Test {
wait_loop.QuitClosure());
client->set_migration_status(migration_status);
SharedProtoDatabaseClient::UpdateClientMetadataAsync(
- client->parent_db_, client->prefix_, migration_status,
+ client->parent_db_, client->client_db_id(), migration_status,
std::move(wait_callback));
wait_loop.Run();
}
@@ -608,10 +610,12 @@ TEST_F(SharedProtoDatabaseClientTest, GetEntry) {
UpdateEntries(client_a.get(), key_list, leveldb_proto::KeyVector(), true);
UpdateEntries(client_b.get(), key_list, leveldb_proto::KeyVector(), true);
- auto a_prefix =
- SharedProtoDatabaseClient::PrefixForDatabase(ProtoDbType::TEST_DATABASE0);
- auto b_prefix =
- SharedProtoDatabaseClient::PrefixForDatabase(ProtoDbType::TEST_DATABASE2);
+ std::string a_prefix =
+ SharedProtoDatabaseClient::PrefixForDatabase(ProtoDbType::TEST_DATABASE0)
+ .value();
+ std::string b_prefix =
+ SharedProtoDatabaseClient::PrefixForDatabase(ProtoDbType::TEST_DATABASE2)
+ .value();
for (auto& key : key_list) {
auto entry = GetEntry(client_a.get(), key, true);
diff --git a/chromium/components/leveldb_proto/internal/shared_proto_database_unittest.cc b/chromium/components/leveldb_proto/internal/shared_proto_database_unittest.cc
index 8298c74fb9f..252042af5f3 100644
--- a/chromium/components/leveldb_proto/internal/shared_proto_database_unittest.cc
+++ b/chromium/components/leveldb_proto/internal/shared_proto_database_unittest.cc
@@ -126,7 +126,7 @@ TEST_F(SharedProtoDatabaseTest, CreateClient_SucceedsWithCreate) {
}
// TODO(912117): Fix flaky test!
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
TEST_F(SharedProtoDatabaseTest, DISABLED_CreateClient_FailsWithoutCreate) {
#else
TEST_F(SharedProtoDatabaseTest, CreateClient_FailsWithoutCreate) {
diff --git a/chromium/components/leveldb_proto/public/shared_proto_database_client_list.cc b/chromium/components/leveldb_proto/public/shared_proto_database_client_list.cc
index 2dd09cd08b5..efb23692c3b 100644
--- a/chromium/components/leveldb_proto/public/shared_proto_database_client_list.cc
+++ b/chromium/components/leveldb_proto/public/shared_proto_database_client_list.cc
@@ -15,7 +15,6 @@
namespace leveldb_proto {
-
// static
std::string SharedProtoDatabaseClientList::ProtoDbTypeToString(
ProtoDbType db_type) {
@@ -107,6 +106,10 @@ std::string SharedProtoDatabaseClientList::ProtoDbTypeToString(
return "VideoTutorialsV2Database";
case ProtoDbType::COUPON_DATABASE:
return "CouponDatabase";
+ case ProtoDbType::PAGE_ENTITY_METADATA_STORE:
+ return "PageEntityMetadataDatabase";
+ case ProtoDbType::WEBRTC_VIDEO_STATS_DB:
+ return "WebrtcVideoStatsDB";
case ProtoDbType::LAST:
NOTREACHED();
return std::string();
diff --git a/chromium/components/leveldb_proto/public/shared_proto_database_client_list.h b/chromium/components/leveldb_proto/public/shared_proto_database_client_list.h
index dc7f30aea66..bc2171cd329 100644
--- a/chromium/components/leveldb_proto/public/shared_proto_database_client_list.h
+++ b/chromium/components/leveldb_proto/public/shared_proto_database_client_list.h
@@ -66,6 +66,8 @@ enum class ProtoDbType {
SIGNAL_STORAGE_CONFIG_DATABASE = 39,
VIDEO_TUTORIALS_V2_DATABASE = 40,
COUPON_DATABASE = 41,
+ PAGE_ENTITY_METADATA_STORE = 42,
+ WEBRTC_VIDEO_STATS_DB = 43,
LAST,
};
diff --git a/chromium/components/link_header_util/link_header_util_fuzzer.cc b/chromium/components/link_header_util/link_header_util_fuzzer.cc
index de959f76a8f..3f6737ab602 100644
--- a/chromium/components/link_header_util/link_header_util_fuzzer.cc
+++ b/chromium/components/link_header_util/link_header_util_fuzzer.cc
@@ -5,6 +5,7 @@
#include <assert.h>
#include <string>
+#include <tuple>
#include <unordered_map>
#include "components/link_header_util/link_header_util.h"
@@ -20,7 +21,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
assert(pair.first < pair.second);
std::string url;
std::unordered_map<std::string, absl::optional<std::string>> params;
- (void)ParseLinkHeaderValue(pair.first, pair.second, &url, &params);
+ std::ignore = ParseLinkHeaderValue(pair.first, pair.second, &url, &params);
}
return 0;
diff --git a/chromium/components/live_caption/live_caption_controller.cc b/chromium/components/live_caption/live_caption_controller.cc
index 1a80de3711b..100ff82e78e 100644
--- a/chromium/components/live_caption/live_caption_controller.cc
+++ b/chromium/components/live_caption/live_caption_controller.cc
@@ -9,6 +9,7 @@
#include "base/bind.h"
#include "base/command_line.h"
#include "base/metrics/histogram_functions.h"
+#include "build/build_config.h"
#include "components/live_caption/caption_bubble_context.h"
#include "components/live_caption/caption_bubble_controller.h"
#include "components/live_caption/caption_util.h"
@@ -68,9 +69,6 @@ void LiveCaptionController::Init() {
if (!media::IsLiveCaptionFeatureEnabled())
return;
- base::UmaHistogramBoolean(
- "Accessibility.LiveCaption.UseSodaForLiveCaption",
- base::FeatureList::IsEnabled(media::kUseSodaForLiveCaption));
pref_change_registrar_ = std::make_unique<PrefChangeRegistrar>();
pref_change_registrar_->Init(profile_prefs_);
auto* command_line = base::CommandLine::ForCurrentProcess();
@@ -124,11 +122,6 @@ bool LiveCaptionController::IsLiveCaptionEnabled() {
void LiveCaptionController::StartLiveCaption() {
DCHECK(enabled_);
- if (!base::FeatureList::IsEnabled(media::kUseSodaForLiveCaption)) {
- CreateUI();
- return;
- }
-
// The SodaInstaller determines whether SODA is already on the device and
// whether or not to download. Once SODA is on the device and ready, the
// SODAInstaller calls OnSodaInstalled on its observers. The UI is created at
@@ -225,7 +218,7 @@ void LiveCaptionController::OnLanguageIdentificationEvent(
// TODO(crbug.com/1175357): Implement the UI for language identification.
}
-#if defined(OS_MAC) || defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS)
void LiveCaptionController::OnToggleFullscreen(
CaptionBubbleContext* caption_bubble_context) {
if (!enabled_)
diff --git a/chromium/components/live_caption/live_caption_controller.h b/chromium/components/live_caption/live_caption_controller.h
index 9f2886e5ca3..3d54187fd22 100644
--- a/chromium/components/live_caption/live_caption_controller.h
+++ b/chromium/components/live_caption/live_caption_controller.h
@@ -73,7 +73,7 @@ class LiveCaptionController : public KeyedService,
// Mac and ChromeOS move the fullscreened window into a new workspace. When
// the WebContents associated with the CaptionBubbleContext goes
// fullscreen, ensure that the Live Caption bubble moves to the new workspace.
-#if defined(OS_MAC) || defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS)
void OnToggleFullscreen(CaptionBubbleContext* caption_bubble_context);
#endif
diff --git a/chromium/components/live_caption/pref_names.cc b/chromium/components/live_caption/pref_names.cc
index 22b5e1feee9..79adaacf3d4 100644
--- a/chromium/components/live_caption/pref_names.cc
+++ b/chromium/components/live_caption/pref_names.cc
@@ -10,7 +10,7 @@
#include "build/build_config.h"
#include "components/prefs/pref_service.h"
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
#include "components/soda/constants.h"
#include "media/base/media_switches.h"
#endif
diff --git a/chromium/components/live_caption/views/caption_bubble.cc b/chromium/components/live_caption/views/caption_bubble.cc
index 3d893509a50..922821283c6 100644
--- a/chromium/components/live_caption/views/caption_bubble.cc
+++ b/chromium/components/live_caption/views/caption_bubble.cc
@@ -53,7 +53,7 @@
// document navigation. It is suspected that other screen readers on Windows and
// Linux will need this behavior, too. VoiceOver and ChromeVox do not need the
// label to be focusable.
-#if BUILDFLAG_INTERNAL_HAS_NATIVE_ACCESSIBILITY() && !defined(OS_MAC)
+#if BUILDFLAG_INTERNAL_HAS_NATIVE_ACCESSIBILITY() && !BUILDFLAG(IS_MAC)
#define NEED_FOCUS_FOR_ACCESSIBILITY
#endif
@@ -151,7 +151,7 @@ bool ParseNonTransparentRGBACSSColorString(std::string css_string,
if (!match || a == 0)
return false;
uint16_t a_int = base::ClampRound<uint16_t>(a * 255);
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
// On Mac, any opacity lower than 90% leaves rendering artifacts which make
// it appear like there is a layer of faint text beneath the actual text.
// TODO(crbug.com/1199419): Fix the rendering issue and then remove this
diff --git a/chromium/components/login/base_screen_handler_utils.cc b/chromium/components/login/base_screen_handler_utils.cc
index c984d7bd92e..231698bedf2 100644
--- a/chromium/components/login/base_screen_handler_utils.cc
+++ b/chromium/components/login/base_screen_handler_utils.cc
@@ -24,7 +24,7 @@ template <typename StringListType>
bool ParseStringList(const base::Value* value, StringListType* out_value) {
if (!value->is_list())
return false;
- base::Value::ConstListView list = value->GetList();
+ base::Value::ConstListView list = value->GetListDeprecated();
out_value->resize(list.size());
for (size_t i = 0; i < list.size(); ++i) {
if (!list[i].is_string())
diff --git a/chromium/components/login/base_screen_handler_utils.h b/chromium/components/login/base_screen_handler_utils.h
index 49518d89f00..f050e16e1c7 100644
--- a/chromium/components/login/base_screen_handler_utils.h
+++ b/chromium/components/login/base_screen_handler_utils.h
@@ -45,10 +45,10 @@ bool LOGIN_EXPORT ParseValue(const base::Value* value, AccountId* out_value);
template <typename T>
inline bool GetArg(const base::ListValue* args, size_t index, T* out_value) {
- const base::Value* value;
- if (!args->Get(index, &value))
+ const auto& list = args->GetListDeprecated();
+ if (list.size() <= index)
return false;
- return ParseValue(value, out_value);
+ return ParseValue(&list[index], out_value);
}
base::Value LOGIN_EXPORT MakeValue(bool v);
@@ -87,7 +87,7 @@ inline void DispatchToCallback(
const base::ListValue* args,
std::index_sequence<Ns...> indexes) {
DCHECK(args);
- DCHECK_EQ(sizeof...(Args), args->GetList().size());
+ DCHECK_EQ(sizeof...(Args), args->GetListDeprecated().size());
callback.Run(ParseArg<Args, Ns>(args)...);
}
diff --git a/chromium/components/login/localized_values_builder.cc b/chromium/components/login/localized_values_builder.cc
index 17898ab9aec..80a1ffa967f 100644
--- a/chromium/components/login/localized_values_builder.cc
+++ b/chromium/components/login/localized_values_builder.cc
@@ -20,29 +20,31 @@ LocalizedValuesBuilder::LocalizedValuesBuilder(const std::string& prefix,
void LocalizedValuesBuilder::Add(const std::string& key,
const std::string& message) {
- dict_->SetString(prefix_ + key, message);
+ dict_->SetStringPath(prefix_ + key, message);
}
void LocalizedValuesBuilder::Add(const std::string& key,
const std::u16string& message) {
- dict_->SetString(prefix_ + key, message);
+ dict_->SetStringPath(prefix_ + key, message);
}
void LocalizedValuesBuilder::Add(const std::string& key, int message_id) {
- dict_->SetString(prefix_ + key, l10n_util::GetStringUTF16(message_id));
+ dict_->SetStringPath(prefix_ + key, l10n_util::GetStringUTF16(message_id));
}
void LocalizedValuesBuilder::AddF(const std::string& key,
int message_id,
const std::u16string& a) {
- dict_->SetString(prefix_ + key, l10n_util::GetStringFUTF16(message_id, a));
+ dict_->SetStringPath(prefix_ + key,
+ l10n_util::GetStringFUTF16(message_id, a));
}
void LocalizedValuesBuilder::AddF(const std::string& key,
int message_id,
const std::u16string& a,
const std::u16string& b) {
- dict_->SetString(prefix_ + key, l10n_util::GetStringFUTF16(message_id, a, b));
+ dict_->SetStringPath(prefix_ + key,
+ l10n_util::GetStringFUTF16(message_id, a, b));
}
void LocalizedValuesBuilder::AddF(const std::string& key,
@@ -50,8 +52,8 @@ void LocalizedValuesBuilder::AddF(const std::string& key,
const std::u16string& a,
const std::u16string& b,
const std::u16string& c) {
- dict_->SetString(prefix_ + key,
- l10n_util::GetStringFUTF16(message_id, a, b, c));
+ dict_->SetStringPath(prefix_ + key,
+ l10n_util::GetStringFUTF16(message_id, a, b, c));
}
void LocalizedValuesBuilder::AddF(const std::string& key,
diff --git a/chromium/components/lookalikes/DEPS b/chromium/components/lookalikes/DEPS
index d725daeca95..0201bde8e72 100644
--- a/chromium/components/lookalikes/DEPS
+++ b/chromium/components/lookalikes/DEPS
@@ -5,6 +5,7 @@ include_rules = [
"+components/security_state",
"+components/strings/grit/components_strings.h",
"+components/url_formatter",
+ "+components/version_info/channel.h",
"+net/base",
"+services/metrics/public/cpp",
"+ui/base",
diff --git a/chromium/components/lookalikes/core/BUILD.gn b/chromium/components/lookalikes/core/BUILD.gn
index c46ad6f7e1d..d0686c16fea 100644
--- a/chromium/components/lookalikes/core/BUILD.gn
+++ b/chromium/components/lookalikes/core/BUILD.gn
@@ -24,6 +24,7 @@ static_library("core") {
"//components/url_formatter/spoof_checks/top_domains:common",
"//components/url_formatter/spoof_checks/top_domains:top500_domains",
"//components/url_formatter/spoof_checks/top_domains:top500_domains_header",
+ "//components/version_info:channel",
"//net",
"//services/metrics/public/cpp:metrics_cpp",
"//services/metrics/public/cpp:ukm_builders",
@@ -39,6 +40,7 @@ source_set("unit_tests") {
":core",
":features",
"//components/reputation/core",
+ "//components/version_info:channel",
"//net:test_support",
"//testing/gtest",
]
diff --git a/chromium/components/lookalikes/core/lookalike_url_ui_util.cc b/chromium/components/lookalikes/core/lookalike_url_ui_util.cc
index c5077385bf0..cd9dc9958e8 100644
--- a/chromium/components/lookalikes/core/lookalike_url_ui_util.cc
+++ b/chromium/components/lookalikes/core/lookalike_url_ui_util.cc
@@ -89,7 +89,7 @@ void PopulateLookalikeUrlBlockingPageStrings(base::Value* load_time_data,
load_time_data->SetStringKey(
"primaryButtonText",
l10n_util::GetStringUTF16(IDS_LOOKALIKE_URL_BACK_TO_SAFETY));
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
// On iOS, offer to close the page instead of navigating to NTP when the
// safe URL is empty or invalid, and unable to go back.
absl::optional<bool> maybe_cant_go_back =
diff --git a/chromium/components/lookalikes/core/lookalike_url_util.cc b/chromium/components/lookalikes/core/lookalike_url_util.cc
index 497e4a25fa5..040bfa111c1 100644
--- a/chromium/components/lookalikes/core/lookalike_url_util.cc
+++ b/chromium/components/lookalikes/core/lookalike_url_util.cc
@@ -10,12 +10,12 @@
#include "base/callback.h"
#include "base/containers/contains.h"
#include "base/feature_list.h"
+#include "base/hash/sha1.h"
#include "base/i18n/char_iterator.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/singleton.h"
#include "base/metrics/field_trial_params.h"
#include "base/metrics/histogram_macros.h"
-#include "base/no_destructor.h"
#include "base/strings/strcat.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_split.h"
@@ -93,6 +93,16 @@ Top500DomainsParams* GetTopDomainParams() {
return &params;
}
+// Minimum length of the eTLD+1 without registry needed to show the punycode
+// interstitial. IDN whose eTLD+1 without registry is shorter than this are
+// still displayed in punycode, but don't show an interstitial.
+const size_t kMinimumE2LDLengthToShowPunycodeInterstitial = 2;
+
+// Default launch percentage of a new heuristic on Canary/Dev and Beta. These
+// are used if there is a launch config for the heuristic in the proto.
+const int kDefaultLaunchPercentageOnCanaryDev = 90;
+const int kDefaultLaunchPercentageOnBeta = 50;
+
bool SkeletonsMatch(const url_formatter::Skeletons& skeletons1,
const url_formatter::Skeletons& skeletons2) {
DCHECK(!skeletons1.empty());
@@ -715,7 +725,7 @@ bool ShouldBlockLookalikeUrlNavigation(LookalikeUrlMatchType match_type) {
return true;
}
if (match_type == LookalikeUrlMatchType::kTargetEmbedding) {
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
// TODO(crbug.com/1104384): Only enable target embedding on iOS once we can
// check engaged sites. Otherwise, false positives are too high.
return false;
@@ -1021,6 +1031,16 @@ bool IsASCIIAndEmojiOnly(const base::StringPiece16& text) {
return true;
}
+// Returns true if the e2LD of domain is long enough to display a punycode
+// interstitial.
+bool IsPunycodeInterstitialCandidate(const DomainInfo& domain) {
+ const url_formatter::IDNConversionResult idn_result =
+ url_formatter::UnsafeIDNToUnicodeWithDetails(
+ domain.domain_without_registry);
+ return idn_result.result.size() >=
+ kMinimumE2LDLengthToShowPunycodeInterstitial;
+}
+
bool ShouldBlockBySpoofCheckResult(const DomainInfo& navigated_domain) {
// Here, only a subset of spoof checks that cause an IDN to fallback to
// punycode are configured to show an interstitial.
@@ -1031,7 +1051,8 @@ bool ShouldBlockBySpoofCheckResult(const DomainInfo& navigated_domain) {
case url_formatter::IDNSpoofChecker::Result::kICUSpoofChecks:
// If the eTLD+1 contains only a mix of ASCII + Emoji, allow.
- return !IsASCIIAndEmojiOnly(navigated_domain.idn_result.result);
+ return !IsASCIIAndEmojiOnly(navigated_domain.idn_result.result) &&
+ IsPunycodeInterstitialCandidate(navigated_domain);
case url_formatter::IDNSpoofChecker::Result::kDeviationCharacters:
// Failures because of deviation characters, especially ß, is common.
@@ -1044,7 +1065,7 @@ bool ShouldBlockBySpoofCheckResult(const DomainInfo& navigated_domain) {
case url_formatter::IDNSpoofChecker::Result::
kNonAsciiLatinCharMixedWithNonLatin:
case url_formatter::IDNSpoofChecker::Result::kDangerousPattern:
- return true;
+ return IsPunycodeInterstitialCandidate(navigated_domain);
}
}
@@ -1052,7 +1073,7 @@ bool IsAllowedByEnterprisePolicy(const PrefService* pref_service,
const GURL& url) {
const auto* list =
pref_service->GetList(prefs::kLookalikeWarningAllowlistDomains);
- for (const auto& domain_val : list->GetList()) {
+ for (const auto& domain_val : list->GetListDeprecated()) {
auto domain = domain_val.GetString();
if (url.DomainIs(domain)) {
return true;
@@ -1113,4 +1134,44 @@ void ResetTop500DomainsParamsForTesting() {
Top500DomainsParams* params = GetTopDomainParams();
*params = {top500_domains::kTop500EditDistanceSkeletons,
top500_domains::kNumTop500EditDistanceSkeletons};
+}
+
+bool IsHeuristicEnabledForHostname(
+ const reputation::SafetyTipsConfig* config_proto,
+ const reputation::HeuristicLaunchConfig::Heuristic heuristic,
+ const std::string& lookalike_etld_plus_one,
+ version_info::Channel channel) {
+ DCHECK(!lookalike_etld_plus_one.empty());
+ if (!config_proto) {
+ return false;
+ }
+ const unsigned char* bytes =
+ reinterpret_cast<const unsigned char*>(lookalike_etld_plus_one.c_str());
+ unsigned char data[base::kSHA1Length];
+ base::SHA1HashBytes(bytes, lookalike_etld_plus_one.length(), data);
+
+ float cohort = data[0] / 2.56;
+ for (const reputation::HeuristicLaunchConfig& config :
+ config_proto->launch_config()) {
+ if (heuristic == config.heuristic()) {
+ switch (channel) {
+ // Enable by default on local builds.
+ case version_info::Channel::UNKNOWN:
+ return true;
+
+ // Use pre-defined launch percentages for Canary/Dev and Beta. Use the
+ // launch percentage from config for Stable.
+ case version_info::Channel::CANARY:
+ case version_info::Channel::DEV:
+ return kDefaultLaunchPercentageOnCanaryDev > cohort;
+
+ case version_info::Channel::BETA:
+ return kDefaultLaunchPercentageOnBeta > cohort;
+
+ case version_info::Channel::STABLE:
+ return config.launch_percentage() > cohort;
+ }
+ }
+ }
+ return false;
} \ No newline at end of file
diff --git a/chromium/components/lookalikes/core/lookalike_url_util.h b/chromium/components/lookalikes/core/lookalike_url_util.h
index 98b71fe07cd..d691115d524 100644
--- a/chromium/components/lookalikes/core/lookalike_url_util.h
+++ b/chromium/components/lookalikes/core/lookalike_url_util.h
@@ -13,6 +13,7 @@
#include "components/prefs/pref_service.h"
#include "components/reputation/core/safety_tips.pb.h"
#include "components/url_formatter/url_formatter.h"
+#include "components/version_info/channel.h"
#include "url/gurl.h"
class GURL;
@@ -171,7 +172,8 @@ bool IsTopDomain(const DomainInfo& domain_info);
// which doesn't have a notion of private registries.
std::string GetETLDPlusOne(const std::string& hostname);
-// Returns true if a lookalike interstitial should be shown.
+// Returns true if a lookalike interstitial should be shown for the given
+// match type.
bool ShouldBlockLookalikeUrlNavigation(LookalikeUrlMatchType match_type);
// Returns true if a domain is visually similar to the hostname of |url|. The
@@ -234,4 +236,12 @@ void SetTop500DomainsParamsForTesting(const Top500DomainsParams& params);
// Resets information about top 500 domains for testing.
void ResetTop500DomainsParamsForTesting();
+// Returns true if the launch configuration provided by the component updater
+// enables `heuristic` for the given `etld_plus_one`.
+bool IsHeuristicEnabledForHostname(
+ const reputation::SafetyTipsConfig* config_proto,
+ reputation::HeuristicLaunchConfig::Heuristic heuristic,
+ const std::string& lookalike_etld_plus_one,
+ version_info::Channel channel);
+
#endif // COMPONENTS_LOOKALIKES_CORE_LOOKALIKE_URL_UTIL_H_
diff --git a/chromium/components/lookalikes/core/lookalike_url_util_unittest.cc b/chromium/components/lookalikes/core/lookalike_url_util_unittest.cc
index ce47215a261..b899b09a9d4 100644
--- a/chromium/components/lookalikes/core/lookalike_url_util_unittest.cc
+++ b/chromium/components/lookalikes/core/lookalike_url_util_unittest.cc
@@ -9,8 +9,11 @@
#include "components/lookalikes/core/features.h"
#include "components/reputation/core/safety_tip_test_utils.h"
#include "components/reputation/core/safety_tips_config.h"
+#include "components/version_info/channel.h"
#include "testing/gtest/include/gtest/gtest.h"
+using version_info::Channel;
+
std::string TargetEmbeddingTypeToString(TargetEmbeddingType type) {
switch (type) {
case TargetEmbeddingType::kNone:
@@ -177,7 +180,39 @@ struct TargetEmbeddingHeuristicTestCase {
const TargetEmbeddingType expected_type;
};
-TEST(LookalikeUrlUtilTest, TargetEmbedding) {
+TEST(LookalikeUrlUtilTest, ShouldBlockBySpoofCheckResult) {
+ EXPECT_FALSE(ShouldBlockBySpoofCheckResult(
+ GetDomainInfo(GURL("https://example.com"))));
+ // ASCII short eTLD+1:
+ EXPECT_FALSE(
+ ShouldBlockBySpoofCheckResult(GetDomainInfo(GURL("https://e.com"))));
+ EXPECT_FALSE(ShouldBlockBySpoofCheckResult(
+ GetDomainInfo(GURL("https://subdomain.e.com"))));
+ // Unicode single character e2LD:
+ EXPECT_FALSE(
+ ShouldBlockBySpoofCheckResult(GetDomainInfo(GURL("https://Ï„.com"))));
+ EXPECT_FALSE(
+ ShouldBlockBySpoofCheckResult(GetDomainInfo(GURL("https://test.Ï„.com"))));
+ // Unicode single character e2LD with a unicode registry.
+ EXPECT_FALSE(
+ ShouldBlockBySpoofCheckResult(GetDomainInfo(GURL("https://τ.рф"))));
+ EXPECT_FALSE(
+ ShouldBlockBySpoofCheckResult(GetDomainInfo(GURL("https://test.τ.рф"))));
+ // Non-unique hostname:
+ EXPECT_FALSE(ShouldBlockBySpoofCheckResult(GetDomainInfo(GURL("https://Ï„"))));
+
+ // Multi character e2LD with disallowed characters:
+ EXPECT_TRUE(
+ ShouldBlockBySpoofCheckResult(GetDomainInfo(GURL("https://Ï„Ï„.com"))));
+ EXPECT_TRUE(ShouldBlockBySpoofCheckResult(
+ GetDomainInfo(GURL("https://test.Ï„Ï„.com"))));
+ EXPECT_TRUE(
+ ShouldBlockBySpoofCheckResult(GetDomainInfo(GURL("https://ττ.рф"))));
+ EXPECT_TRUE(
+ ShouldBlockBySpoofCheckResult(GetDomainInfo(GURL("https://test.ττ.рф"))));
+}
+
+TEST(LookalikeUrlUtilTest, TargetEmbeddingTest) {
const std::vector<DomainInfo> kEngagedSites = {
GetDomainInfo(GURL("https://highengagement.com")),
GetDomainInfo(GURL("https://highengagement.inthesubdomain.com")),
@@ -467,3 +502,88 @@ TEST(LookalikeUrlUtilTest, HasOneCharacterSwap) {
<< "when comparing " << test_case.str1 << " with " << test_case.str2;
}
}
+
+TEST(LookalikeUrlUtilTest, IsHeuristicEnabledForHostname) {
+ reputation::SafetyTipsConfig proto;
+ reputation::HeuristicLaunchConfig* config = proto.add_launch_config();
+ config->set_heuristic(reputation::HeuristicLaunchConfig::
+ HEURISTIC_CHARACTER_SWAP_ENGAGED_SITES);
+
+ // Minimum rollout percentages to enable a heuristic on each site on Stable
+ // channel:
+ // example1.com: 79%
+ // example2.com: 16%
+ // example3.com: 36%
+
+ // Slowly ramp up the launch and cover more sites on Stable channel.
+ config->set_launch_percentage(0);
+ EXPECT_FALSE(IsHeuristicEnabledForHostname(
+ &proto,
+ reputation::HeuristicLaunchConfig::HEURISTIC_CHARACTER_SWAP_ENGAGED_SITES,
+ "example1.com", Channel::STABLE));
+ EXPECT_FALSE(IsHeuristicEnabledForHostname(
+ &proto,
+ reputation::HeuristicLaunchConfig::HEURISTIC_CHARACTER_SWAP_ENGAGED_SITES,
+ "example2.com", Channel::STABLE));
+ EXPECT_FALSE(IsHeuristicEnabledForHostname(
+ &proto,
+ reputation::HeuristicLaunchConfig::HEURISTIC_CHARACTER_SWAP_ENGAGED_SITES,
+ "example3.com", Channel::STABLE));
+
+ config->set_launch_percentage(25);
+ EXPECT_FALSE(IsHeuristicEnabledForHostname(
+ &proto,
+ reputation::HeuristicLaunchConfig::HEURISTIC_CHARACTER_SWAP_ENGAGED_SITES,
+ "example1.com", Channel::STABLE));
+ EXPECT_TRUE(IsHeuristicEnabledForHostname(
+ &proto,
+ reputation::HeuristicLaunchConfig::HEURISTIC_CHARACTER_SWAP_ENGAGED_SITES,
+ "example2.com", Channel::STABLE));
+ EXPECT_FALSE(IsHeuristicEnabledForHostname(
+ &proto,
+ reputation::HeuristicLaunchConfig::HEURISTIC_CHARACTER_SWAP_ENGAGED_SITES,
+ "example3.com", Channel::STABLE));
+
+ config->set_launch_percentage(50);
+ EXPECT_FALSE(IsHeuristicEnabledForHostname(
+ &proto,
+ reputation::HeuristicLaunchConfig::HEURISTIC_CHARACTER_SWAP_ENGAGED_SITES,
+ "example1.com", Channel::STABLE));
+ EXPECT_TRUE(IsHeuristicEnabledForHostname(
+ &proto,
+ reputation::HeuristicLaunchConfig::HEURISTIC_CHARACTER_SWAP_ENGAGED_SITES,
+ "example2.com", Channel::STABLE));
+ EXPECT_TRUE(IsHeuristicEnabledForHostname(
+ &proto,
+ reputation::HeuristicLaunchConfig::HEURISTIC_CHARACTER_SWAP_ENGAGED_SITES,
+ "example3.com", Channel::STABLE));
+
+ config->set_launch_percentage(100);
+ EXPECT_TRUE(IsHeuristicEnabledForHostname(
+ &proto,
+ reputation::HeuristicLaunchConfig::HEURISTIC_CHARACTER_SWAP_ENGAGED_SITES,
+ "example1.com", Channel::STABLE));
+ EXPECT_TRUE(IsHeuristicEnabledForHostname(
+ &proto,
+ reputation::HeuristicLaunchConfig::HEURISTIC_CHARACTER_SWAP_ENGAGED_SITES,
+ "example2.com", Channel::STABLE));
+ EXPECT_TRUE(IsHeuristicEnabledForHostname(
+ &proto,
+ reputation::HeuristicLaunchConfig::HEURISTIC_CHARACTER_SWAP_ENGAGED_SITES,
+ "example3.com", Channel::STABLE));
+
+ // On Beta, launch is always at 50%.
+ config->set_launch_percentage(0);
+ EXPECT_FALSE(IsHeuristicEnabledForHostname(
+ &proto,
+ reputation::HeuristicLaunchConfig::HEURISTIC_CHARACTER_SWAP_ENGAGED_SITES,
+ "example1.com", Channel::BETA));
+ EXPECT_TRUE(IsHeuristicEnabledForHostname(
+ &proto,
+ reputation::HeuristicLaunchConfig::HEURISTIC_CHARACTER_SWAP_ENGAGED_SITES,
+ "example2.com", Channel::BETA));
+ EXPECT_TRUE(IsHeuristicEnabledForHostname(
+ &proto,
+ reputation::HeuristicLaunchConfig::HEURISTIC_CHARACTER_SWAP_ENGAGED_SITES,
+ "example3.com", Channel::BETA));
+} \ No newline at end of file
diff --git a/chromium/components/management_strings.grdp b/chromium/components/management_strings.grdp
index b0c2cdb4ace..dcb1d1abcfa 100644
--- a/chromium/components/management_strings.grdp
+++ b/chromium/components/management_strings.grdp
@@ -81,6 +81,11 @@
</message>
</if>
+ <!--
+ If you are adding or modifying a privacy string to be displayed on
+ chrome://management for managed devices, please add it to
+ go/chrome-policy-privacy-note-mappings
+ -->
<if expr="chromeos">
<!-- Strings related to Local trust roots section -->
<message name="IDS_MANAGEMENT_LOCAL_TRUST_ROOTS" desc="Title of the types of local trust roots section of the page">
@@ -105,6 +110,9 @@
<message name="IDS_MANAGEMENT_REPORT_DEVICE_ACTIVITY_TIMES" desc="Message stating that administrators see device activity times.">
Who has used the device recently and when
</message>
+ <message name="IDS_MANAGEMENT_REPORT_DEVICE_AUDIO_STATUS" desc="Message stating that administrators see attached audio peripherals.">
+ Audio peripherals attached
+ </message>
<message name="IDS_MANAGEMENT_REPORT_DEVICE_HARDWARE_STATUS" desc="Message stating that administrators see device hardware status.">
Device statistics such as CPU/RAM usage
</message>
@@ -112,7 +120,7 @@
Detailed system logs
</message>
<message name="IDS_MANAGEMENT_REPORT_DEVICE_NETWORK_DATA" desc="Message stating that administrators see device network interfaces.">
- Network addresses
+ Networking information such as addresses, interface configuration, and connection quality
</message>
<message name="IDS_MANAGEMENT_REPORT_DEVICE_HARDWARE_DATA" desc="Message stating that administrators see device hardware status.">
Device statistics such as CPU/RAM usage and hardware specifications
@@ -137,6 +145,9 @@
<message name="IDS_MANAGEMENT_REPORT_LOGIN_LOGOUT" desc="Message stating that administrators can see device Login and Logout events.">
Device login/logout history, including timestamps and failed attempts
</message>
+ <message name="IDS_MANAGEMENT_REPORT_CRD_SESSIONS" desc="Message stating that administrators can see Chrome Remote Desktop events.">
+ Chrome Remote Desktop history, including timestamps, hosts and client session ids
+ </message>
<message name="IDS_MANAGEMENT_CROSTINI" desc="Message stating that administrators can see Crostini usage">
Linux apps installed and when they were last used
</message>
@@ -192,10 +203,10 @@
<!-- Strings related to browser reporting section of the management page -->
- <message name="IDS_MANAGEMENT_BROWSER_REPORTING" desc="Title of the types of browser reporting section of the page">
+ <message name="IDS_MANAGEMENT_BROWSER_REPORTING" desc="Title of the types of browser reporting section of the page" formatter_data="android_java">
Browser
</message>
- <message name="IDS_MANAGEMENT_BROWSER_REPORTING_EXPLANATION" desc="Message explaining browser reporting">
+ <message name="IDS_MANAGEMENT_BROWSER_REPORTING_EXPLANATION" desc="Message explaining browser reporting" formatter_data="android_java">
Your administrator can see:
</message>
<message name="IDS_MANAGEMENT_EXTENSION_REPORT_MACHINE_NAME" desc="Message explaining that an extension currently reports the user's machine name">
@@ -204,10 +215,10 @@
<message name="IDS_MANAGEMENT_EXTENSION_REPORT_MACHINE_NAME_ADDRESS" desc="Message explaining that an extension currently reports the user's machine name and address">
Your device name and network address
</message>
- <message name="IDS_MANAGEMENT_EXTENSION_REPORT_USERNAME" desc="Message explaining that an extension currently reports the user's username">
+ <message name="IDS_MANAGEMENT_EXTENSION_REPORT_USERNAME" desc="Message explaining that an extension currently reports the user's username" formatter_data="android_java">
Your device username and Chrome username
</message>
- <message name="IDS_MANAGEMENT_EXTENSION_REPORT_VERSION" desc="Message explaining that an extension currently reports the user's browser and machine version">
+ <message name="IDS_MANAGEMENT_EXTENSION_REPORT_VERSION" desc="Message explaining that an extension currently reports the user's browser and machine version" formatter_data="android_java">
Version information about your device and browser
</message>
<message name="IDS_MANAGEMENT_EXTENSION_REPORT_EXTENSIONS_PLUGINS" desc="Message explaining that an extension currently reports the user's exensions and plugins">
@@ -245,6 +256,9 @@
<message name="IDS_MANAGEMENT_TEXT_ENTERED_EVENT" desc="Event for the text entry scanning feature.">
Text is entered
</message>
+ <message name="IDS_MANAGEMENT_PAGE_PRINTED_EVENT" desc="Event for the page print scanning feature.">
+ Page is printed
+ </message>
<message name="IDS_MANAGEMENT_ENTERPRISE_REPORTING_EVENT" desc="Event for the enterprise reporting feature">
Security event occurs
</message>
@@ -260,6 +274,9 @@
<message name="IDS_MANAGEMENT_TEXT_ENTERED_VISIBLE_DATA" desc="Description of the visible data for the text entry scanning feature.">
Text you paste or attach is sent to Google Cloud or third parties for analysis. For example, it might be scanned for sensitive data.
</message>
+ <message name="IDS_MANAGEMENT_PAGE_PRINTED_VISIBLE_DATA" desc="Description of the visible data for the page print scanning feature.">
+ The content of pages you print is sent to Google Cloud or third parties for analysis. For example, it might be scanned for sensitive data.
+ </message>
<message name="IDS_MANAGEMENT_ENTERPRISE_REPORTING_VISIBLE_DATA" desc="Description of the visible data for the Connectors reporting feature">
When security events are flagged by Chrome, relevant data about the events is sent to your administrator. This can include URLs of pages you visit in Chrome, file names or metadata, and the username that you use to sign in to web based applications, your device and Chrome.
</message>
diff --git a/chromium/components/management_strings_grdp/IDS_MANAGEMENT_PAGE_PRINTED_EVENT.png.sha1 b/chromium/components/management_strings_grdp/IDS_MANAGEMENT_PAGE_PRINTED_EVENT.png.sha1
new file mode 100644
index 00000000000..5e7810c4898
--- /dev/null
+++ b/chromium/components/management_strings_grdp/IDS_MANAGEMENT_PAGE_PRINTED_EVENT.png.sha1
@@ -0,0 +1 @@
+0b4070b8a3c7f607fe81cf8a4d97e383266d1ba8 \ No newline at end of file
diff --git a/chromium/components/management_strings_grdp/IDS_MANAGEMENT_PAGE_PRINTED_VISIBLE_DATA.png.sha1 b/chromium/components/management_strings_grdp/IDS_MANAGEMENT_PAGE_PRINTED_VISIBLE_DATA.png.sha1
new file mode 100644
index 00000000000..5e7810c4898
--- /dev/null
+++ b/chromium/components/management_strings_grdp/IDS_MANAGEMENT_PAGE_PRINTED_VISIBLE_DATA.png.sha1
@@ -0,0 +1 @@
+0b4070b8a3c7f607fe81cf8a4d97e383266d1ba8 \ No newline at end of file
diff --git a/chromium/components/management_strings_grdp/IDS_MANAGEMENT_REPORT_CRD_SESSIONS.png.sha1 b/chromium/components/management_strings_grdp/IDS_MANAGEMENT_REPORT_CRD_SESSIONS.png.sha1
new file mode 100644
index 00000000000..52a082ea5df
--- /dev/null
+++ b/chromium/components/management_strings_grdp/IDS_MANAGEMENT_REPORT_CRD_SESSIONS.png.sha1
@@ -0,0 +1 @@
+7dc395c7a54d4206cf4004cd34553177330f565d \ No newline at end of file
diff --git a/chromium/components/management_strings_grdp/IDS_MANAGEMENT_REPORT_DEVICE_AUDIO_STATUS.png.sha1 b/chromium/components/management_strings_grdp/IDS_MANAGEMENT_REPORT_DEVICE_AUDIO_STATUS.png.sha1
new file mode 100644
index 00000000000..a35f637b45e
--- /dev/null
+++ b/chromium/components/management_strings_grdp/IDS_MANAGEMENT_REPORT_DEVICE_AUDIO_STATUS.png.sha1
@@ -0,0 +1 @@
+6ae24d707315c1692e3e309050c3eb3b03854321 \ No newline at end of file
diff --git a/chromium/components/management_strings_grdp/IDS_MANAGEMENT_REPORT_DEVICE_NETWORK_DATA.png.sha1 b/chromium/components/management_strings_grdp/IDS_MANAGEMENT_REPORT_DEVICE_NETWORK_DATA.png.sha1
index 3cde1204d2f..cc873bfd3bf 100644
--- a/chromium/components/management_strings_grdp/IDS_MANAGEMENT_REPORT_DEVICE_NETWORK_DATA.png.sha1
+++ b/chromium/components/management_strings_grdp/IDS_MANAGEMENT_REPORT_DEVICE_NETWORK_DATA.png.sha1
@@ -1 +1 @@
-78c4753ac68a32d71da371fce6d61e9eea040c5e \ No newline at end of file
+8e08fc100983a56268946050c07d2e10ed9c057d \ No newline at end of file
diff --git a/chromium/components/media_message_center/media_controls_progress_view_unittest.cc b/chromium/components/media_message_center/media_controls_progress_view_unittest.cc
index 6c350e3f2e6..62ba7a01326 100644
--- a/chromium/components/media_message_center/media_controls_progress_view_unittest.cc
+++ b/chromium/components/media_message_center/media_controls_progress_view_unittest.cc
@@ -126,7 +126,9 @@ TEST_F(MAYBE_MediaControlsProgressViewTest, UpdateProgress) {
EXPECT_EQ(progress_view_->progress_bar_for_testing()->GetValue(), .55);
}
-TEST_F(MAYBE_MediaControlsProgressViewTest, UpdateProgressFastPlayback) {
+// Flaky on multiple platforms. crbug.com/1293864
+TEST_F(MAYBE_MediaControlsProgressViewTest,
+ DISABLED_UpdateProgressFastPlayback) {
media_session::MediaPosition media_position(
/*playback_rate=*/2, /*duration=*/base::Seconds(600),
/*position=*/base::Seconds(300), /*end_of_media=*/false);
diff --git a/chromium/components/media_message_center/media_notification_view_impl_unittest.cc b/chromium/components/media_message_center/media_notification_view_impl_unittest.cc
index cb09bfb629d..e674187e7a7 100644
--- a/chromium/components/media_message_center/media_notification_view_impl_unittest.cc
+++ b/chromium/components/media_message_center/media_notification_view_impl_unittest.cc
@@ -302,7 +302,7 @@ TEST_F(MediaNotificationViewImplTest, ButtonsSanityCheck) {
EXPECT_FALSE(GetButtonForAction(MediaSessionAction::kExitPictureInPicture));
}
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#define MAYBE_ButtonsFocusCheck DISABLED_ButtonsFocusCheck
#else
#define MAYBE_ButtonsFocusCheck ButtonsFocusCheck
diff --git a/chromium/components/media_message_center/media_notification_view_modern_impl_unittest.cc b/chromium/components/media_message_center/media_notification_view_modern_impl_unittest.cc
index 7d98a49394e..fc184986cd4 100644
--- a/chromium/components/media_message_center/media_notification_view_modern_impl_unittest.cc
+++ b/chromium/components/media_message_center/media_notification_view_modern_impl_unittest.cc
@@ -287,7 +287,7 @@ TEST_F(MediaNotificationViewModernImplTest, ButtonsSanityCheck) {
EXPECT_FALSE(GetButtonForAction(MediaSessionAction::kExitPictureInPicture));
}
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#define MAYBE_ButtonsFocusCheck DISABLED_ButtonsFocusCheck
#else
#define MAYBE_ButtonsFocusCheck ButtonsFocusCheck
diff --git a/chromium/components/media_router/OWNERS b/chromium/components/media_router/OWNERS
index 5a0f44e0a79..916a3da50b0 100644
--- a/chromium/components/media_router/OWNERS
+++ b/chromium/components/media_router/OWNERS
@@ -1,3 +1,4 @@
-mfoltz@chromium.org
-btolsch@chromium.org
-takumif@chromium.org
+file://chrome/browser/media/router/OWNERS
+
+
+
diff --git a/chromium/components/media_router/browser/android/junit/src/org/chromium/components/media_router/caf/CafBaseMediaRouteProviderTest.java b/chromium/components/media_router/browser/android/junit/src/org/chromium/components/media_router/caf/CafBaseMediaRouteProviderTest.java
index 93a8a543fc1..4bc342f0c9c 100644
--- a/chromium/components/media_router/browser/android/junit/src/org/chromium/components/media_router/caf/CafBaseMediaRouteProviderTest.java
+++ b/chromium/components/media_router/browser/android/junit/src/org/chromium/components/media_router/caf/CafBaseMediaRouteProviderTest.java
@@ -41,6 +41,7 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
+import org.robolectric.annotation.LooperMode;
import org.robolectric.shadows.ShadowLooper;
import org.chromium.base.test.BaseRobolectricTestRunner;
@@ -59,7 +60,10 @@ import java.util.List;
*/
@RunWith(BaseRobolectricTestRunner.class)
@Config(manifest = Config.NONE,
- shadows = {ShadowMediaRouter.class, ShadowCastContext.class, ShadowLooper.class})
+ shadows = {ShadowMediaRouter.class, ShadowCastContext.class, ShadowLooper.class},
+ // Required to mock final.
+ instrumentedPackages = {"androidx.mediarouter.media.MediaRouteSelector"})
+@LooperMode(LooperMode.Mode.LEGACY)
public class CafBaseMediaRouteProviderTest {
private Context mContext;
private TestMRP mProvider;
diff --git a/chromium/components/media_router/browser/android/media_router_android.cc b/chromium/components/media_router/browser/android/media_router_android.cc
index e3cb4ead682..5384bcd0cc0 100644
--- a/chromium/components/media_router/browser/android/media_router_android.cc
+++ b/chromium/components/media_router/browser/android/media_router_android.cc
@@ -198,9 +198,6 @@ void MediaRouterAndroid::UnregisterMediaSinksObserver(
void MediaRouterAndroid::RegisterMediaRoutesObserver(
MediaRoutesObserver* observer) {
DVLOG(2) << "Added MediaRoutesObserver: " << observer;
- if (!observer->source_id().empty())
- NOTIMPLEMENTED() << "Joinable routes query not implemented.";
-
routes_observers_.AddObserver(observer);
}
@@ -240,7 +237,7 @@ void MediaRouterAndroid::OnRouteCreated(const MediaRoute::Id& route_id,
return;
MediaRoute route(route_id, request->media_source, sink_id, std::string(),
- is_local, true); // TODO(avayvod): Populate for_display.
+ is_local);
std::unique_ptr<RouteRequestResult> result =
RouteRequestResult::FromSuccess(route, request->presentation_id);
@@ -254,7 +251,7 @@ void MediaRouterAndroid::OnRouteCreated(const MediaRoute::Id& route_id,
active_routes_.push_back(route);
for (auto& observer : routes_observers_)
- observer.OnRoutesUpdated(active_routes_, std::vector<MediaRoute::Id>());
+ observer.OnRoutesUpdated(active_routes_);
if (is_local) {
MediaRouterMetrics::RecordCreateRouteResultCode(
result->result_code(), mojom::MediaRouteProviderId::ANDROID_CAF);
@@ -341,7 +338,7 @@ void MediaRouterAndroid::RemoveRoute(const MediaRoute::Id& route_id) {
}
for (auto& observer : routes_observers_)
- observer.OnRoutesUpdated(active_routes_, std::vector<MediaRoute::Id>());
+ observer.OnRoutesUpdated(active_routes_);
}
std::unique_ptr<media::FlingingController>
diff --git a/chromium/components/media_router/browser/issue_manager.cc b/chromium/components/media_router/browser/issue_manager.cc
index fb760be3b8b..e2ae6ad4974 100644
--- a/chromium/components/media_router/browser/issue_manager.cc
+++ b/chromium/components/media_router/browser/issue_manager.cc
@@ -7,6 +7,7 @@
#include <algorithm>
#include "base/bind.h"
+#include "base/time/time.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
diff --git a/chromium/components/media_router/browser/logger_impl.cc b/chromium/components/media_router/browser/logger_impl.cc
index 48bb1872cf5..a5a62281ea3 100644
--- a/chromium/components/media_router/browser/logger_impl.cc
+++ b/chromium/components/media_router/browser/logger_impl.cc
@@ -96,7 +96,7 @@ void LoggerImpl::LogError(mojom::LogCategory category,
sink_id, media_source, session_id);
}
-void LoggerImpl::Bind(mojo::PendingReceiver<mojom::Logger> receiver) {
+void LoggerImpl::BindReceiver(mojo::PendingReceiver<mojom::Logger> receiver) {
receivers_.Add(this, std::move(receiver));
}
diff --git a/chromium/components/media_router/browser/logger_impl.h b/chromium/components/media_router/browser/logger_impl.h
index fcf7b60d72e..49a96968847 100644
--- a/chromium/components/media_router/browser/logger_impl.h
+++ b/chromium/components/media_router/browser/logger_impl.h
@@ -47,8 +47,7 @@ class LoggerImpl : mojom::Logger {
const std::string& sink_id,
const std::string& media_source,
const std::string& session_id) override;
-
- void Bind(mojo::PendingReceiver<mojom::Logger> receiver);
+ void BindReceiver(mojo::PendingReceiver<mojom::Logger> receiver) override;
std::string GetLogsAsJson() const;
base::Value GetLogsAsValue() const;
diff --git a/chromium/components/media_router/browser/logger_impl_unittest.cc b/chromium/components/media_router/browser/logger_impl_unittest.cc
index 799ed199bad..59e5914e16d 100644
--- a/chromium/components/media_router/browser/logger_impl_unittest.cc
+++ b/chromium/components/media_router/browser/logger_impl_unittest.cc
@@ -53,7 +53,7 @@ class LoggerImplTest : public testing::Test {
std::string GetAttributeOfFirstEntry(const std::string& logs_json,
const std::string& attribute) {
base::Value logs = base::JSONReader::Read(logs_json).value();
- return *logs.GetList()[0].FindStringKey(attribute);
+ return *logs.GetListDeprecated()[0].FindStringKey(attribute);
}
};
diff --git a/chromium/components/media_router/browser/media_router.h b/chromium/components/media_router/browser/media_router.h
index cc7137bee5b..fe0fe6b39f1 100644
--- a/chromium/components/media_router/browser/media_router.h
+++ b/chromium/components/media_router/browser/media_router.h
@@ -27,12 +27,12 @@
#include "media/base/flinging_controller.h"
#include "third_party/blink/public/mojom/presentation/presentation.mojom.h"
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
#include "components/media_router/browser/logger_impl.h"
#include "components/media_router/common/mojom/media_controller.mojom.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
namespace content {
class WebContents;
@@ -50,6 +50,11 @@ class MediaSinksObserver;
class PresentationConnectionStateObserver;
class RouteRequestResult;
+// Commandline flag to disable the default media route providers for tests that
+// are sensitive to the presence of sinks e.g. on the local network.
+constexpr char kDisableMediaRouteProvidersForTestSwitch[] =
+ "disable-media-route-providers-for-test";
+
// Type of callback used in |CreateRoute()| and |JoinRoute()|. Callback is
// invoked when the route request either succeeded or failed. |connection| is
// set depending on whether the MRP chooses to setup the PresentationConnections
@@ -142,10 +147,6 @@ class MediaRouter : public KeyedService {
const MediaRoute::Id& route_id,
const content::PresentationConnectionStateChangedCallback& callback) = 0;
- // Called when the incognito profile for this instance is being shut down.
- // This will terminate all incognito media routes.
- virtual void OnIncognitoProfileShutdown() = 0;
-
// Returns the media routes that currently exist. To get notified whenever
// there is a change to the media routes, subclass MediaRoutesObserver.
virtual std::vector<MediaRoute> GetCurrentRoutes() const = 0;
@@ -156,7 +157,7 @@ class MediaRouter : public KeyedService {
virtual std::unique_ptr<media::FlingingController> GetFlingingController(
const MediaRoute::Id& route_id) = 0;
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
// Binds |controller| for sending media commands to a route. The controller
// will notify |observer| whenever there is a change to the status of the
// media. It may invalidate bindings from previous calls to this method.
@@ -170,7 +171,7 @@ class MediaRouter : public KeyedService {
// Returns logs collected from Media Router components.
virtual base::Value GetLogs() const = 0;
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
// Returns media router state as a JSON string represented by base::Value.
// Includes known sinks and sink compatibility with media sources.
diff --git a/chromium/components/media_router/browser/media_router_base.cc b/chromium/components/media_router/browser/media_router_base.cc
index a96dc1f107c..452c31c9778 100644
--- a/chromium/components/media_router/browser/media_router_base.cc
+++ b/chromium/components/media_router/browser/media_router_base.cc
@@ -8,6 +8,7 @@
#include "base/bind.h"
#include "base/guid.h"
+#include "build/build_config.h"
#include "content/public/browser/browser_thread.h"
using blink::mojom::PresentationConnectionState;
@@ -16,11 +17,17 @@ namespace media_router {
// A MediaRoutesObserver that maintains state about the current set of media
// routes.
+//
+// TODO(crbug.com/1297324): This observer is used to implement
+// HasJoinableRoute() and GetRoute(), which are used internally by
+// MediaRouterMojoImpl; it would be simpler to move route tracking to a separate
+// object owned by MRMI, and then MediaRouterBase could likely be deleted
+// entirely.
class MediaRouterBase::InternalMediaRoutesObserver
: public MediaRoutesObserver {
public:
explicit InternalMediaRoutesObserver(MediaRouter* router)
- : MediaRoutesObserver(router), has_route(false) {}
+ : MediaRoutesObserver(router) {}
InternalMediaRoutesObserver(const InternalMediaRoutesObserver&) = delete;
InternalMediaRoutesObserver& operator=(const InternalMediaRoutesObserver&) =
@@ -29,23 +36,16 @@ class MediaRouterBase::InternalMediaRoutesObserver
~InternalMediaRoutesObserver() override {}
// MediaRoutesObserver
- void OnRoutesUpdated(
- const std::vector<MediaRoute>& routes,
- const std::vector<MediaRoute::Id>& joinable_route_ids) override {
- current_routes = routes;
- off_the_record_route_ids.clear();
- // TODO(crbug.com/611486): Have the MRPM pass a list of joinable route ids
- // via |joinable_route_ids|, and check here if it is non-empty.
- has_route = !routes.empty();
- for (const auto& route : routes) {
- if (route.is_off_the_record())
- off_the_record_route_ids.push_back(route.media_route_id());
- }
+ void OnRoutesUpdated(const std::vector<MediaRoute>& routes) override {
+ current_routes_ = routes;
}
- bool has_route;
- std::vector<MediaRoute> current_routes;
- std::vector<MediaRoute::Id> off_the_record_route_ids;
+ const std::vector<MediaRoute>& current_routes() const {
+ return current_routes_;
+ }
+
+ private:
+ std::vector<MediaRoute> current_routes_;
};
MediaRouterBase::~MediaRouterBase() {
@@ -69,18 +69,12 @@ MediaRouterBase::AddPresentationConnectionStateChangedCallback(
return callbacks->Add(callback);
}
-void MediaRouterBase::OnIncognitoProfileShutdown() {
- for (const auto& route_id :
- internal_routes_observer_->off_the_record_route_ids)
- TerminateRoute(route_id);
-}
-
IssueManager* MediaRouterBase::GetIssueManager() {
return &issue_manager_;
}
std::vector<MediaRoute> MediaRouterBase::GetCurrentRoutes() const {
- return internal_routes_observer_->current_routes;
+ return internal_routes_observer_->current_routes();
}
std::unique_ptr<media::FlingingController>
@@ -88,7 +82,7 @@ MediaRouterBase::GetFlingingController(const MediaRoute::Id& route_id) {
return nullptr;
}
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
void MediaRouterBase::GetMediaController(
const MediaRoute::Id& route_id,
mojo::PendingReceiver<mojom::MediaController> controller,
@@ -97,7 +91,7 @@ void MediaRouterBase::GetMediaController(
base::Value MediaRouterBase::GetLogs() const {
return base::Value();
}
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
MediaRouterBase::MediaRouterBase() : initialized_(false) {}
@@ -135,12 +129,12 @@ void MediaRouterBase::NotifyPresentationConnectionClose(
}
bool MediaRouterBase::HasJoinableRoute() const {
- return internal_routes_observer_->has_route;
+ return !(internal_routes_observer_->current_routes().empty());
}
const MediaRoute* MediaRouterBase::GetRoute(
const MediaRoute::Id& route_id) const {
- const auto& routes = internal_routes_observer_->current_routes;
+ const auto& routes = internal_routes_observer_->current_routes();
auto it = std::find_if(routes.begin(), routes.end(),
[&route_id](const MediaRoute& route) {
return route.media_route_id() == route_id;
diff --git a/chromium/components/media_router/browser/media_router_base.h b/chromium/components/media_router/browser/media_router_base.h
index 30f44ebe88b..0a08e86dc21 100644
--- a/chromium/components/media_router/browser/media_router_base.h
+++ b/chromium/components/media_router/browser/media_router_base.h
@@ -18,11 +18,11 @@
#include "components/media_router/common/media_route.h"
#include "third_party/blink/public/mojom/presentation/presentation.mojom.h"
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
#include "components/media_router/common/mojom/media_controller.mojom.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
namespace media_router {
@@ -34,25 +34,24 @@ class MediaRouterBase : public MediaRouter {
~MediaRouterBase() override;
// Must be called before invoking any other method.
- void Initialize();
+ virtual void Initialize();
// MediaRouter implementation.
base::CallbackListSubscription AddPresentationConnectionStateChangedCallback(
const MediaRoute::Id& route_id,
const content::PresentationConnectionStateChangedCallback& callback)
override;
- void OnIncognitoProfileShutdown() override;
IssueManager* GetIssueManager() final;
std::vector<MediaRoute> GetCurrentRoutes() const override;
std::unique_ptr<media::FlingingController> GetFlingingController(
const MediaRoute::Id& route_id) override;
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
void GetMediaController(
const MediaRoute::Id& route_id,
mojo::PendingReceiver<mojom::MediaController> controller,
mojo::PendingRemote<mojom::MediaStatusObserver> observer) override;
base::Value GetLogs() const override;
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
base::Value GetState() const override;
void GetProviderState(
mojom::MediaRouteProviderId provider_id,
diff --git a/chromium/components/media_router/browser/media_router_base_unittest.cc b/chromium/components/media_router/browser/media_router_base_unittest.cc
index a6c860d3844..45826a9da67 100644
--- a/chromium/components/media_router/browser/media_router_base_unittest.cc
+++ b/chromium/components/media_router/browser/media_router_base_unittest.cc
@@ -33,10 +33,6 @@ class MockMediaRouterBase : public MockMediaRouter {
route_id, callback);
}
- void OnIncognitoProfileShutdown() override {
- MediaRouterBase::OnIncognitoProfileShutdown();
- }
-
std::vector<MediaRoute> GetCurrentRoutes() const override {
return MediaRouterBase::GetCurrentRoutes();
}
@@ -120,20 +116,18 @@ TEST_F(MediaRouterBaseTest, NotifyCallbacks) {
TEST_F(MediaRouterBaseTest, GetCurrentRoutes) {
MediaSource source1("source_1");
MediaSource source2("source_1");
- MediaRoute route1("route_1", source1, "sink_1", "", false, false);
- MediaRoute route2("route_2", source2, "sink_2", "", true, false);
+ MediaRoute route1("route_1", source1, "sink_1", "", false);
+ MediaRoute route2("route_2", source2, "sink_2", "", true);
std::vector<MediaRoute> routes = {route1, route2};
- std::vector<MediaRoute::Id> joinable_route_ids = {"route_1"};
EXPECT_TRUE(router_.GetCurrentRoutes().empty());
- routes_observer_->OnRoutesUpdated(routes, joinable_route_ids);
+ routes_observer_->OnRoutesUpdated(routes);
std::vector<MediaRoute> current_routes = router_.GetCurrentRoutes();
ASSERT_EQ(current_routes.size(), 2u);
EXPECT_EQ(current_routes[0], route1);
EXPECT_EQ(current_routes[1], route2);
- routes_observer_->OnRoutesUpdated(std::vector<MediaRoute>(),
- std::vector<MediaRoute::Id>());
+ routes_observer_->OnRoutesUpdated(std::vector<MediaRoute>());
EXPECT_TRUE(router_.GetCurrentRoutes().empty());
}
diff --git a/chromium/components/media_router/browser/media_router_dialog_controller_unittest.cc b/chromium/components/media_router/browser/media_router_dialog_controller_unittest.cc
index 3f8c03b98cb..8fe7657ecf4 100644
--- a/chromium/components/media_router/browser/media_router_dialog_controller_unittest.cc
+++ b/chromium/components/media_router/browser/media_router_dialog_controller_unittest.cc
@@ -21,7 +21,7 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "components/media_router/browser/android/media_router_dialog_controller_android.h"
#endif
@@ -101,7 +101,7 @@ class MediaRouterDialogControllerTest
std::unique_ptr<MockWebContentsDelegate> web_contents_delegate_;
};
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// The non-Android implementation is tested in
// MediaRouterDialogControllerViewsTest.
TEST_F(MediaRouterDialogControllerTest, CreateForWebContents) {
@@ -170,7 +170,7 @@ TEST_F(MediaRouterDialogControllerTest, StartPresentationContext) {
base::Unretained(this)));
MediaRoute route("routeId", MediaSource::ForTab(1), "sinkId", "Description",
- false, false);
+ false);
auto result = RouteRequestResult::FromSuccess(route, "presentationId");
EXPECT_CALL(*this, RequestSuccess(_, _, _)).Times(1);
diff --git a/chromium/components/media_router/browser/media_router_metrics.cc b/chromium/components/media_router/browser/media_router_metrics.cc
index b79abba60d1..d728859f4f1 100644
--- a/chromium/components/media_router/browser/media_router_metrics.cc
+++ b/chromium/components/media_router/browser/media_router_metrics.cc
@@ -104,10 +104,6 @@ MediaRouterMetrics::~MediaRouterMetrics() = default;
// static
const char MediaRouterMetrics::kHistogramCloseLatency[] =
"MediaRouter.Ui.Action.CloseLatency";
-const char MediaRouterMetrics::kHistogramCloudPrefAtDialogOpen[] =
- "MediaRouter.Cloud.PrefAtDialogOpen";
-const char MediaRouterMetrics::kHistogramCloudPrefAtInit[] =
- "MediaRouter.Cloud.PrefAtInit";
const char MediaRouterMetrics::kHistogramIconClickLocation[] =
"MediaRouter.Icon.Click.Location";
const char MediaRouterMetrics::kHistogramMediaRouterFileFormat[] =
@@ -314,16 +310,6 @@ void MediaRouterMetrics::RecordIconStateAtInit(bool is_pinned) {
}
// static
-void MediaRouterMetrics::RecordCloudPrefAtDialogOpen(bool enabled) {
- base::UmaHistogramBoolean(kHistogramCloudPrefAtDialogOpen, enabled);
-}
-
-// static
-void MediaRouterMetrics::RecordCloudPrefAtInit(bool enabled) {
- base::UmaHistogramBoolean(kHistogramCloudPrefAtInit, enabled);
-}
-
-// static
void MediaRouterMetrics::RecordCreateRouteResultCode(
RouteRequestResult::ResultCode result_code,
absl::optional<mojom::MediaRouteProviderId> provider_id) {
diff --git a/chromium/components/media_router/browser/media_router_metrics.h b/chromium/components/media_router/browser/media_router_metrics.h
index a48c1205245..91f878ad37d 100644
--- a/chromium/components/media_router/browser/media_router_metrics.h
+++ b/chromium/components/media_router/browser/media_router_metrics.h
@@ -34,25 +34,25 @@ enum class DialogActivationLocationAndCastMode {
kPinnedIconAndPresentation,
kPinnedIconAndTabMirror,
kPinnedIconAndDesktopMirror,
- kPinnedIconAndLocalFile,
+ kPinnedIconAndLocalFile, // Obsolete.
// One can start casting from an ephemeral icon by stopping a session, then
// starting another from the same dialog.
kEphemeralIconAndPresentation,
kEphemeralIconAndTabMirror,
kEphemeralIconAndDesktopMirror,
- kEphemeralIconAndLocalFile,
+ kEphemeralIconAndLocalFile, // Obsolete.
kContextMenuAndPresentation,
kContextMenuAndTabMirror,
kContextMenuAndDesktopMirror,
- kContextMenuAndLocalFile,
+ kContextMenuAndLocalFile, // Obsolete.
kPageAndPresentation,
kPageAndTabMirror,
kPageAndDesktopMirror,
- kPageAndLocalFile,
+ kPageAndLocalFile, // Obsolete.
kAppMenuAndPresentation,
kAppMenuAndTabMirror,
kAppMenuAndDesktopMirror,
- kAppMenuAndLocalFile,
+ kAppMenuAndLocalFile, // Obsolete.
// NOTE: Do not reorder existing entries, and add entries only immediately
// above this line.
@@ -125,8 +125,6 @@ class MediaRouterMetrics {
// UMA histogram names.
static const char kHistogramCloseLatency[];
- static const char kHistogramCloudPrefAtDialogOpen[];
- static const char kHistogramCloudPrefAtInit[];
static const char kHistogramIconClickLocation[];
static const char kHistogramMediaRouterFileFormat[];
static const char kHistogramMediaRouterFileSize[];
@@ -232,14 +230,6 @@ class MediaRouterMetrics {
// Recorded whenever the browser is initialized.
static void RecordIconStateAtInit(bool is_pinned);
- // Records the pref value to enable the cloud services. Recorded whenever the
- // Cast dialog is opened.
- static void RecordCloudPrefAtDialogOpen(bool enabled);
-
- // Records the pref value to enable the cloud services. Recorded whenever the
- // browser is initialized.
- static void RecordCloudPrefAtInit(bool enabled);
-
// Records the outcome of a create route request to a Media Route Provider.
// This and the following methods that record ResultCode use per-provider
// histograms.
diff --git a/chromium/components/media_router/browser/media_router_metrics_unittest.cc b/chromium/components/media_router/browser/media_router_metrics_unittest.cc
index ebe0055d891..74e6b665805 100644
--- a/chromium/components/media_router/browser/media_router_metrics_unittest.cc
+++ b/chromium/components/media_router/browser/media_router_metrics_unittest.cc
@@ -292,18 +292,6 @@ TEST(MediaRouterMetricsTest, RecordIconStateAtInit) {
MediaRouterMetrics::kHistogramUiIconStateAtInit);
}
-TEST(MediaRouterMetricsTest, RecordCloudPrefAtDialogOpen) {
- TestRecordBooleanMetric(
- base::BindRepeating(&MediaRouterMetrics::RecordCloudPrefAtDialogOpen),
- MediaRouterMetrics::kHistogramCloudPrefAtDialogOpen);
-}
-
-TEST(MediaRouterMetricsTest, RecordCloudPrefAtInit) {
- TestRecordBooleanMetric(
- base::BindRepeating(&MediaRouterMetrics::RecordCloudPrefAtInit),
- MediaRouterMetrics::kHistogramCloudPrefAtInit);
-}
-
TEST(MediaRouterMetricsTest, RecordCreateRouteResultCode) {
TestRouteResultCodeHistograms(
base::BindRepeating(&MediaRouterMetrics::RecordCreateRouteResultCode),
diff --git a/chromium/components/media_router/browser/media_routes_observer.cc b/chromium/components/media_router/browser/media_routes_observer.cc
index 74a0999aec6..38464917428 100644
--- a/chromium/components/media_router/browser/media_routes_observer.cc
+++ b/chromium/components/media_router/browser/media_routes_observer.cc
@@ -9,9 +9,8 @@
namespace media_router {
-MediaRoutesObserver::MediaRoutesObserver(MediaRouter* router,
- const MediaSource::Id& source_id)
- : router_(router), source_id_(source_id) {
+MediaRoutesObserver::MediaRoutesObserver(MediaRouter* router)
+ : router_(router) {
DCHECK(router_);
router_->RegisterMediaRoutesObserver(this);
}
diff --git a/chromium/components/media_router/browser/media_routes_observer.h b/chromium/components/media_router/browser/media_routes_observer.h
index 8c10005c226..426cc674096 100644
--- a/chromium/components/media_router/browser/media_routes_observer.h
+++ b/chromium/components/media_router/browser/media_routes_observer.h
@@ -22,9 +22,7 @@ class MediaRouter;
// |source_id| is supplied, then the idea of joinable routes no longer applies.
class MediaRoutesObserver {
public:
- explicit MediaRoutesObserver(MediaRouter* router)
- : MediaRoutesObserver(router, MediaSource::Id()) {}
- MediaRoutesObserver(MediaRouter* router, const MediaSource::Id& source_id);
+ explicit MediaRoutesObserver(MediaRouter* router);
MediaRoutesObserver(const MediaRoutesObserver&) = delete;
MediaRoutesObserver& operator=(const MediaRoutesObserver&) = delete;
@@ -32,22 +30,17 @@ class MediaRoutesObserver {
virtual ~MediaRoutesObserver();
// Invoked when the list of routes and their associated sinks have been
- // updated with the context of the |source_id|. This will return a list of
- // |routes| and a list of |joinable_route_ids|. A route is joinable only if
- // it is joinable in the context of the |source_id|.
+ // updated.
+ //
// Implementations may not perform operations that modify the Media Router's
// observer list. In particular, invoking this observer's destructor within
// OnRoutesUpdated will result in undefined behavior.
- virtual void OnRoutesUpdated(
- const std::vector<MediaRoute>& routes,
- const std::vector<MediaRoute::Id>& joinable_route_ids) {}
+ virtual void OnRoutesUpdated(const std::vector<MediaRoute>& routes) {}
MediaRouter* router() const { return router_; }
- const MediaSource::Id source_id() const { return source_id_; }
private:
const raw_ptr<MediaRouter> router_;
- const MediaSource::Id source_id_;
};
} // namespace media_router
diff --git a/chromium/components/media_router/browser/presentation/local_presentation_manager_unittest.cc b/chromium/components/media_router/browser/presentation/local_presentation_manager_unittest.cc
index f3c0b32e7f7..01b39b9079d 100644
--- a/chromium/components/media_router/browser/presentation/local_presentation_manager_unittest.cc
+++ b/chromium/components/media_router/browser/presentation/local_presentation_manager_unittest.cc
@@ -41,8 +41,7 @@ class LocalPresentationManagerTest : public content::RenderViewHostTestHarness {
LocalPresentationManagerTest()
: render_frame_host_id_(1, 1),
presentation_info_(GURL(kPresentationUrl), kPresentationId),
- route_("route_1", MediaSource("source_1"), "sink_1", "", false, false) {
- }
+ route_("route_1", MediaSource("source_1"), "sink_1", "", false) {}
LocalPresentationManager* manager() { return &manager_; }
@@ -337,7 +336,7 @@ TEST_F(LocalPresentationManagerTest, TestIsLocalPresentationWithWebContents) {
TEST_F(LocalPresentationManagerTest, TestRegisterAndGetRoute) {
MediaSource source("source_1");
- MediaRoute route("route_1", source, "sink_1", "", false, false);
+ MediaRoute route("route_1", source, "sink_1", "", false);
EXPECT_FALSE(manager()->GetRoute(kPresentationId));
mojo::PendingRemote<blink::mojom::PresentationConnection> controller;
diff --git a/chromium/components/media_router/browser/presentation/presentation_service_delegate_impl.cc b/chromium/components/media_router/browser/presentation/presentation_service_delegate_impl.cc
index 06d76139d14..0819fa08b23 100644
--- a/chromium/components/media_router/browser/presentation/presentation_service_delegate_impl.cc
+++ b/chromium/components/media_router/browser/presentation/presentation_service_delegate_impl.cc
@@ -17,6 +17,7 @@
#include "base/memory/ptr_util.h"
#include "base/memory/raw_ptr.h"
#include "base/strings/string_util.h"
+#include "build/build_config.h"
#include "components/media_router/browser/media_router.h"
#include "components/media_router/browser/media_router_dialog_controller.h"
#include "components/media_router/browser/media_router_factory.h"
@@ -38,7 +39,7 @@
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "url/gurl.h"
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
#include "components/media_router/common/pref_names.h"
#include "components/prefs/pref_service.h"
#include "components/user_prefs/user_prefs.h"
@@ -501,7 +502,7 @@ void PresentationServiceDelegateImpl::ReconnectPresentation(
return;
}
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
if (IsAutoJoinPresentationId(presentation_id) &&
ShouldCancelAutoJoinForOrigin(request.frame_origin)) {
std::move(error_cb).Run(
@@ -509,7 +510,7 @@ void PresentationServiceDelegateImpl::ReconnectPresentation(
"Auto-join request cancelled by user preferences."));
return;
}
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
auto* local_presentation_manager =
LocalPresentationManagerFactory::GetOrCreateForWebContents(
@@ -708,16 +709,16 @@ MediaRoute::Id PresentationServiceDelegateImpl::GetRouteId(
: MediaRoute::Id();
}
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
bool PresentationServiceDelegateImpl::ShouldCancelAutoJoinForOrigin(
const url::Origin& origin) {
- const base::ListValue* origins =
+ const base::Value* origins =
user_prefs::UserPrefs::Get(GetWebContents().GetBrowserContext())
->GetList(prefs::kMediaRouterTabMirroringSources);
- return origins &&
- base::Contains(origins->GetList(), base::Value(origin.Serialize()));
+ return origins && base::Contains(origins->GetListDeprecated(),
+ base::Value(origin.Serialize()));
}
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
void PresentationServiceDelegateImpl::EnsurePresentationConnection(
const content::GlobalRenderFrameHostId& render_frame_host_id,
diff --git a/chromium/components/media_router/browser/presentation/presentation_service_delegate_impl.h b/chromium/components/media_router/browser/presentation/presentation_service_delegate_impl.h
index 37c9c667bda..bebfa22e732 100644
--- a/chromium/components/media_router/browser/presentation/presentation_service_delegate_impl.h
+++ b/chromium/components/media_router/browser/presentation/presentation_service_delegate_impl.h
@@ -204,7 +204,7 @@ class PresentationServiceDelegateImpl
const content::GlobalRenderFrameHostId& render_frame_host_id,
const std::string& presentation_id) const;
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
// Returns true if auto-join requests should be cancelled for |origin|.
bool ShouldCancelAutoJoinForOrigin(const url::Origin& origin);
#endif
diff --git a/chromium/components/media_router/common/discovery/media_sink_internal.h b/chromium/components/media_router/common/discovery/media_sink_internal.h
index edbe0bb6845..f68ea891955 100644
--- a/chromium/components/media_router/common/discovery/media_sink_internal.h
+++ b/chromium/components/media_router/common/discovery/media_sink_internal.h
@@ -14,6 +14,9 @@
namespace media_router {
+// Default Cast control port to open Cast Socket.
+static constexpr int kCastControlPort = 8009;
+
// Extra data for DIAL media sink.
struct DialSinkExtraData {
net::IPAddress ip_address;
@@ -53,6 +56,9 @@ struct CastSinkExtraData {
// True if Cast channel is opened from DIAL sink.
bool discovered_by_dial = false;
+ // True if Cast Device was discovered via access code.
+ bool discovered_by_access_code = false;
+
CastSinkExtraData();
CastSinkExtraData(const CastSinkExtraData& other);
CastSinkExtraData(CastSinkExtraData&& other);
diff --git a/chromium/components/media_router/common/media_route.cc b/chromium/components/media_router/common/media_route.cc
index 6986549d82a..e1d1ef15121 100644
--- a/chromium/components/media_router/common/media_route.cc
+++ b/chromium/components/media_router/common/media_route.cc
@@ -74,18 +74,16 @@ MediaRoute::MediaRoute(const MediaRoute::Id& media_route_id,
const MediaSource& media_source,
const MediaSink::Id& media_sink_id,
const std::string& description,
- bool is_local,
- bool for_display)
+ bool is_local)
: media_route_id_(media_route_id),
media_source_(media_source),
media_sink_id_(media_sink_id),
description_(description),
- is_local_(is_local),
- for_display_(for_display) {}
+ is_local_(is_local) {}
MediaRoute::MediaRoute(const MediaRoute& other) = default;
-MediaRoute::MediaRoute() {}
+MediaRoute::MediaRoute() = default;
MediaRoute::~MediaRoute() = default;
bool MediaRoute::operator==(const MediaRoute& other) const {
@@ -96,7 +94,6 @@ bool MediaRoute::operator==(const MediaRoute& other) const {
media_sink_name_ == other.media_sink_name_ &&
description_ == other.description_ && is_local_ == other.is_local_ &&
controller_type_ == other.controller_type_ &&
- for_display_ == other.for_display_ &&
is_off_the_record_ == other.is_off_the_record_ &&
is_local_presentation_ == other.is_local_presentation_ &&
is_connecting_ == other.is_connecting_;
diff --git a/chromium/components/media_router/common/media_route.h b/chromium/components/media_router/common/media_route.h
index d4521edc3ba..3f3f0ac378a 100644
--- a/chromium/components/media_router/common/media_route.h
+++ b/chromium/components/media_router/common/media_route.h
@@ -43,14 +43,11 @@ class MediaRoute {
// |description|: Human readable description of the casting activity.
// |is_local|: true if the route was created from this browser.
// provider. empty otherwise.
- // |for_display|: Set to true if this route should be displayed for
- // |media_sink_id| in UI.
MediaRoute(const MediaRoute::Id& media_route_id,
const MediaSource& media_source,
const MediaSink::Id& media_sink_id,
const std::string& description,
- bool is_local,
- bool for_display);
+ bool is_local);
MediaRoute(const MediaRoute& other);
MediaRoute();
@@ -96,9 +93,6 @@ class MediaRoute {
}
RouteControllerType controller_type() const { return controller_type_; }
- void set_for_display(bool for_display) { for_display_ = for_display; }
- bool for_display() const { return for_display_; }
-
void set_off_the_record(bool is_off_the_record) {
is_off_the_record_ = is_off_the_record;
}
@@ -144,9 +138,6 @@ class MediaRoute {
// The type of MediaRouteController supported by this route.
RouteControllerType controller_type_ = RouteControllerType::kNone;
- // |true| if the route can be displayed in the UI.
- bool for_display_ = false;
-
// |true| if the route was created by an OffTheRecord profile.
bool is_off_the_record_ = false;
diff --git a/chromium/components/media_router/common/media_route_unittest.cc b/chromium/components/media_router/common/media_route_unittest.cc
index 174cac3e408..7ef3e863d52 100644
--- a/chromium/components/media_router/common/media_route_unittest.cc
+++ b/chromium/components/media_router/common/media_route_unittest.cc
@@ -21,35 +21,31 @@ namespace media_router {
TEST(MediaRouteTest, TestEquals) {
const MediaSource& media_source =
MediaSource::ForPresentationUrl(GURL(kPresentationUrl));
- MediaRoute route1(kRouteId1, media_source, "sinkId", "Description", false,
- false);
+ MediaRoute route1(kRouteId1, media_source, "sinkId", "Description", false);
MediaRoute route1_copy(route1);
EXPECT_EQ(route1, route1_copy);
// Same as route1 with different sink ID.
MediaRoute route2(kRouteId1, media_source, "differentSinkId", "Description",
- false, false);
+ false);
EXPECT_FALSE(route1 == route2);
// Same as route1 with different description.
MediaRoute route3(kRouteId1, media_source, "sinkId", "differentDescription",
- false, false);
+ false);
EXPECT_FALSE(route1 == route3);
// Same as route1 with different is_local.
- MediaRoute route4(kRouteId1, media_source, "sinkId", "Description", true,
- false);
+ MediaRoute route4(kRouteId1, media_source, "sinkId", "Description", true);
EXPECT_FALSE(route1 == route4);
// The ID is different from route1's.
- MediaRoute route5(kRouteId2, media_source, "sinkId", "Description", false,
- false);
+ MediaRoute route5(kRouteId2, media_source, "sinkId", "Description", false);
EXPECT_FALSE(route1 == route5);
// Same as route1 with different off_the_record.
- MediaRoute route6(kRouteId1, media_source, "sinkId", "Description", true,
- false);
+ MediaRoute route6(kRouteId1, media_source, "sinkId", "Description", true);
route6.set_off_the_record(true);
EXPECT_FALSE(route1 == route6);
}
diff --git a/chromium/components/media_router/common/media_source.h b/chromium/components/media_router/common/media_source.h
index 33e568741d8..d30d6070d0c 100644
--- a/chromium/components/media_router/common/media_source.h
+++ b/chromium/components/media_router/common/media_source.h
@@ -54,8 +54,8 @@ class MediaSource {
public:
using Id = std::string;
- // TODO(jrw): Eliminate this constructor and use optional<MediaSource> where
- // needed.
+ // TODO(crbug.com/1291731): Eliminate this constructor and use
+ // optional<MediaSource> where needed.
MediaSource();
// Create from an arbitrary string, which may or may not be a presentation
diff --git a/chromium/components/media_router/common/mojom/logger.mojom b/chromium/components/media_router/common/mojom/logger.mojom
index 340062e46ca..edde0c45066 100644
--- a/chromium/components/media_router/common/mojom/logger.mojom
+++ b/chromium/components/media_router/common/mojom/logger.mojom
@@ -50,4 +50,8 @@ interface Logger {
string sink_id,
string media_source,
string session_id);
+
+ // Binds this logger to a new pending receiver, allowing any code with access
+ // to a Logger to create a new receiver for it.
+ BindReceiver(pending_receiver<Logger> receiver);
};
diff --git a/chromium/components/media_router/common/mojom/media_router.mojom b/chromium/components/media_router/common/mojom/media_router.mojom
index 075e3eb1a18..6eabc090542 100644
--- a/chromium/components/media_router/common/mojom/media_router.mojom
+++ b/chromium/components/media_router/common/mojom/media_router.mojom
@@ -119,8 +119,6 @@ struct MediaRoute {
// The type of route controller that can be created for this route. See
// media_controller.mojom for details.
RouteControllerType controller_type;
- // Set to true if this route should be displayed for |media_sink_id| in UI.
- bool for_display;
// Set to true if this route was created by an OffTheRecord profile.
bool is_off_the_record;
// Set to true if this route corresponds to a local presentation.
@@ -337,30 +335,8 @@ interface MediaRouteProvider {
// Stops querying sinks for |media_source|.
StopObservingMediaSinks(string media_source);
- // Starts reporting the state of active media routes via
- // OnRoutesUpdated() in the context of the |media_source|. The
- // |media_source| represents the application interested in the media
- // routes (usually the web page from which the content originates).
- // If no |media_source| is given, this should be considered an
- // observer that is not associated with a media source, and thus
- // cannot connect to a remote route without showing a source. The
- // |media_source| should be considered when returning joinable routes in the
- // OnRoutesUpdated() call. If an empty |media_source| is given, there is no
- // context in which a joinable route makes sense and therefore, there should
- // not be any joinable routes returned in OnRoutesUpdated().
- // Querying will continue until StopObservingMediaRoutes() is called with
- // the same |media_source| (even if it's an empty string).
- StartObservingMediaRoutes(string media_source);
-
- // Stops querying the state of all media routes in the context of
- // the |media_source|. StartObservingMediaRoutes() has
- // to be called with the same |media_source| for this to have any effect even
- // if it's empty. Thus, StartObservingMediaRoutes(media_source) must be
- // matched with StopObservingMediaRoutes(media_source).
- // Calling StopObservingMediaRoutes() without a media_source will stop
- // any media routes queries associated with emtpy strings (queries
- // that being with StartObservingMediaRoutes()).
- StopObservingMediaRoutes(string media_source);
+ // Starts reporting the state of active media routes.
+ StartObservingMediaRoutes();
// Starts listening for messages from the media sink for the route given by
// |route_id|.
@@ -435,13 +411,9 @@ interface MediaRouter {
// Called when issues are reported for media routes.
OnIssue(Issue issue);
- // Called when list of routes for a MediaRouteProvider has been updated in the
- // context of the calling |media_source|. The array |joinable_route_ids|
- // should contain route IDs of joinable routes found in the |routes| array.
+ // Called when list of routes for a MediaRouteProvider has been updated.
OnRoutesUpdated(MediaRouteProviderId provider_id,
- array<MediaRoute> routes,
- string media_source,
- array<string> joinable_route_ids);
+ array<MediaRoute> routes);
// Called when the state of presentation connected to route |route_id| has
// changed to |state|.
diff --git a/chromium/components/media_router/common/mojom/media_router_mojom_traits.cc b/chromium/components/media_router/common/mojom/media_router_mojom_traits.cc
index e5278ba9e4b..fc1e99840d3 100644
--- a/chromium/components/media_router/common/mojom/media_router_mojom_traits.cc
+++ b/chromium/components/media_router/common/mojom/media_router_mojom_traits.cc
@@ -216,7 +216,6 @@ bool StructTraits<media_router::mojom::MediaRouteDataView,
out->set_controller_type(controller_type);
out->set_local(data.is_local());
- out->set_for_display(data.for_display());
out->set_off_the_record(data.is_off_the_record());
out->set_local_presentation(data.is_local_presentation());
out->set_is_connecting(data.is_connecting());
diff --git a/chromium/components/media_router/common/mojom/media_router_mojom_traits.h b/chromium/components/media_router/common/mojom/media_router_mojom_traits.h
index 614df7b62fa..5d25b4367fd 100644
--- a/chromium/components/media_router/common/mojom/media_router_mojom_traits.h
+++ b/chromium/components/media_router/common/mojom/media_router_mojom_traits.h
@@ -378,10 +378,6 @@ struct StructTraits<media_router::mojom::MediaRouteDataView,
return route.controller_type();
}
- static bool for_display(const media_router::MediaRoute& route) {
- return route.for_display();
- }
-
static bool is_off_the_record(const media_router::MediaRoute& route) {
return route.is_off_the_record();
}
@@ -415,9 +411,9 @@ struct EnumTraits<media_router::mojom::RouteRequestResultCode,
return media_router::mojom::RouteRequestResultCode::SINK_NOT_FOUND;
case media_router::RouteRequestResult::INVALID_ORIGIN:
return media_router::mojom::RouteRequestResultCode::INVALID_ORIGIN;
- case media_router::RouteRequestResult::OFF_THE_RECORD_MISMATCH:
+ case media_router::RouteRequestResult::DEPRECATED_OFF_THE_RECORD_MISMATCH:
return media_router::mojom::RouteRequestResultCode::
- OFF_THE_RECORD_MISMATCH;
+ DEPRECATED_OFF_THE_RECORD_MISMATCH;
case media_router::RouteRequestResult::NO_SUPPORTED_PROVIDER:
return media_router::mojom::RouteRequestResultCode::
NO_SUPPORTED_PROVIDER;
@@ -460,8 +456,10 @@ struct EnumTraits<media_router::mojom::RouteRequestResultCode,
case media_router::mojom::RouteRequestResultCode::INVALID_ORIGIN:
*output = media_router::RouteRequestResult::INVALID_ORIGIN;
return true;
- case media_router::mojom::RouteRequestResultCode::OFF_THE_RECORD_MISMATCH:
- *output = media_router::RouteRequestResult::OFF_THE_RECORD_MISMATCH;
+ case media_router::mojom::RouteRequestResultCode::
+ DEPRECATED_OFF_THE_RECORD_MISMATCH:
+ *output = media_router::RouteRequestResult::
+ DEPRECATED_OFF_THE_RECORD_MISMATCH;
return true;
case media_router::mojom::RouteRequestResultCode::NO_SUPPORTED_PROVIDER:
*output = media_router::RouteRequestResult::NO_SUPPORTED_PROVIDER;
diff --git a/chromium/components/media_router/common/mojom/route_request_result_code.mojom b/chromium/components/media_router/common/mojom/route_request_result_code.mojom
index 999fc4eaf0f..88a0099d45d 100644
--- a/chromium/components/media_router/common/mojom/route_request_result_code.mojom
+++ b/chromium/components/media_router/common/mojom/route_request_result_code.mojom
@@ -7,7 +7,6 @@ module media_router.mojom;
// Keep in sync with:
// - RouteRequestResult::ResultCode in route_request_result.h
// - MediaRouteProviderResult enum in tools/metrics/histograms.xml.
-// - mr.RouteRequestResultCode in route_request_error.js
// - media_router_mojom_traits.h
enum RouteRequestResultCode {
UNKNOWN_ERROR,
@@ -16,7 +15,7 @@ enum RouteRequestResultCode {
ROUTE_NOT_FOUND,
SINK_NOT_FOUND,
INVALID_ORIGIN,
- OFF_THE_RECORD_MISMATCH,
+ DEPRECATED_OFF_THE_RECORD_MISMATCH, // Deprecated.
NO_SUPPORTED_PROVIDER,
CANCELLED,
ROUTE_ALREADY_EXISTS,
diff --git a/chromium/components/media_router/common/pref_names.cc b/chromium/components/media_router/common/pref_names.cc
index 62e7967d5eb..87a4e348bdc 100644
--- a/chromium/components/media_router/common/pref_names.cc
+++ b/chromium/components/media_router/common/pref_names.cc
@@ -7,13 +7,6 @@
namespace media_router {
namespace prefs {
-// Whether or not the user has explicitly set the cloud services preference
-// through the first run flow.
-const char kMediaRouterCloudServicesPrefSet[] =
- "media_router.cloudservices.prefset";
-// Whether or not the user has enabled cloud services with Media Router.
-const char kMediaRouterEnableCloudServices[] =
- "media_router.cloudservices.enabled";
// Whether or not the user has enabled Media Remoting. Defaults to true.
const char kMediaRouterMediaRemotingEnabled[] =
"media_router.media_remoting.enabled";
diff --git a/chromium/components/media_router/common/pref_names.h b/chromium/components/media_router/common/pref_names.h
index 07eee135b19..dc607250711 100644
--- a/chromium/components/media_router/common/pref_names.h
+++ b/chromium/components/media_router/common/pref_names.h
@@ -8,8 +8,6 @@
namespace media_router {
namespace prefs {
-extern const char kMediaRouterCloudServicesPrefSet[];
-extern const char kMediaRouterEnableCloudServices[];
extern const char kMediaRouterMediaRemotingEnabled[];
extern const char kMediaRouterTabMirroringSources[];
diff --git a/chromium/components/media_router/common/providers/cast/cast_media_source.cc b/chromium/components/media_router/common/providers/cast/cast_media_source.cc
index fb656b8cc8c..67e4615c525 100644
--- a/chromium/components/media_router/common/providers/cast/cast_media_source.cc
+++ b/chromium/components/media_router/common/providers/cast/cast_media_source.cc
@@ -152,15 +152,13 @@ base::flat_map<std::string, std::string> MakeQueryMap(const GURL& url) {
base::flat_map<std::string, std::string> result;
for (net::QueryIterator query_it(url); !query_it.IsAtEnd();
query_it.Advance()) {
- result[query_it.GetKey()] = query_it.GetUnescapedValue();
+ result[std::string(query_it.GetKey())] = query_it.GetUnescapedValue();
}
return result;
}
-// TODO(jrw): Move to common utils?
-//
-// TODO(jrw): Should this use net::UnescapeURLComponent instead of
-// url::DecodeURLEscapeSequences?
+// TODO(crbug.com/1291718): Move to common utils? Should this use
+// net::UnescapeURLComponent instead of url::DecodeURLEscapeSequences?
std::string DecodeURLComponent(const std::string& encoded) {
url::RawCanonOutputT<char16_t> unescaped;
std::string output;
diff --git a/chromium/components/media_router/common/providers/cast/cast_media_source.h b/chromium/components/media_router/common/providers/cast/cast_media_source.h
index b7ab2b2741b..ab4180e6f68 100644
--- a/chromium/components/media_router/common/providers/cast/cast_media_source.h
+++ b/chromium/components/media_router/common/providers/cast/cast_media_source.h
@@ -36,9 +36,9 @@ static constexpr base::TimeDelta kDefaultLaunchTimeout = base::Seconds(60);
// Class for storing a bitwise OR of enum values.
//
-// TODO(jrw): Make values of cast_channel::CastDeviceCapability consecutive and
-// store sets of values using a class like v8::base::EnumSet instead of this
-// monstrosity.
+// TODO(crbug.com/1291715): Make values of cast_channel::CastDeviceCapability
+// consecutive and store sets of values using a class like v8::base::EnumSet
+// instead of this monstrosity.
template <typename E, typename T = std::underlying_type_t<E>>
class BitwiseOr {
public:
@@ -57,7 +57,7 @@ class BitwiseOr {
return (bits_ & other.bits_) == other.bits_;
}
bool operator==(const BitwiseOr& other) const { return bits_ == other.bits_; }
- bool operator!=(const BitwiseOr& other) const { return *this != other; }
+ bool operator!=(const BitwiseOr& other) const { return !(*this == other); }
private:
explicit constexpr BitwiseOr(T bits) : bits_(bits) {}
diff --git a/chromium/components/media_router/common/route_request_result.h b/chromium/components/media_router/common/route_request_result.h
index 988cfcc42af..f4423951408 100644
--- a/chromium/components/media_router/common/route_request_result.h
+++ b/chromium/components/media_router/common/route_request_result.h
@@ -41,7 +41,7 @@ class RouteRequestResult {
ROUTE_NOT_FOUND = 3,
SINK_NOT_FOUND = 4,
INVALID_ORIGIN = 5,
- OFF_THE_RECORD_MISMATCH = 6,
+ DEPRECATED_OFF_THE_RECORD_MISMATCH = 6, // DEPRECATED.
NO_SUPPORTED_PROVIDER = 7,
CANCELLED = 8,
ROUTE_ALREADY_EXISTS = 9,
diff --git a/chromium/components/memory_pressure/system_memory_pressure_evaluator.cc b/chromium/components/memory_pressure/system_memory_pressure_evaluator.cc
index 6722ffa2694..2e47c6e0208 100644
--- a/chromium/components/memory_pressure/system_memory_pressure_evaluator.cc
+++ b/chromium/components/memory_pressure/system_memory_pressure_evaluator.cc
@@ -8,18 +8,18 @@
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
-#if defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_FUCHSIA)
#include "components/memory_pressure/system_memory_pressure_evaluator_fuchsia.h"
-#elif defined(OS_MAC)
+#elif BUILDFLAG(IS_MAC)
#include "components/memory_pressure/system_memory_pressure_evaluator_mac.h"
-#elif defined(OS_WIN)
+#elif BUILDFLAG(IS_WIN)
#include "base/win/windows_version.h"
#include "components/memory_pressure/system_memory_pressure_evaluator_win.h"
#endif
namespace memory_pressure {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
constexpr base::Feature kUseWinOSMemoryPressureSignals{
"UseWinOSMemoryPressureSignals", base::FEATURE_DISABLED_BY_DEFAULT};
#endif
@@ -28,14 +28,14 @@ constexpr base::Feature kUseWinOSMemoryPressureSignals{
std::unique_ptr<SystemMemoryPressureEvaluator>
SystemMemoryPressureEvaluator::CreateDefaultSystemEvaluator(
MultiSourceMemoryPressureMonitor* monitor) {
-#if defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_FUCHSIA)
return std::make_unique<
memory_pressure::SystemMemoryPressureEvaluatorFuchsia>(
monitor->CreateVoter());
-#elif defined(OS_MAC)
+#elif BUILDFLAG(IS_MAC)
return std::make_unique<memory_pressure::mac::SystemMemoryPressureEvaluator>(
monitor->CreateVoter());
-#elif defined(OS_WIN)
+#elif BUILDFLAG(IS_WIN)
auto evaluator =
std::make_unique<memory_pressure::win::SystemMemoryPressureEvaluator>(
monitor->CreateVoter());
diff --git a/chromium/components/memory_pressure/system_memory_pressure_evaluator_fuchsia.cc b/chromium/components/memory_pressure/system_memory_pressure_evaluator_fuchsia.cc
index 6dc0b8f29fd..5e0b795fc62 100644
--- a/chromium/components/memory_pressure/system_memory_pressure_evaluator_fuchsia.cc
+++ b/chromium/components/memory_pressure/system_memory_pressure_evaluator_fuchsia.cc
@@ -8,6 +8,7 @@
#include "base/fuchsia/fuchsia_logging.h"
#include "base/fuchsia/process_context.h"
+#include "base/strings/string_piece.h"
#include "base/time/time.h"
#include "components/memory_pressure/memory_pressure_voter.h"
diff --git a/chromium/components/memory_pressure/system_memory_pressure_evaluator_win_unittest.cc b/chromium/components/memory_pressure/system_memory_pressure_evaluator_win_unittest.cc
index e457cadc8d9..c770e1af91d 100644
--- a/chromium/components/memory_pressure/system_memory_pressure_evaluator_win_unittest.cc
+++ b/chromium/components/memory_pressure/system_memory_pressure_evaluator_win_unittest.cc
@@ -13,7 +13,7 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include <windows.h>
#endif
diff --git a/chromium/components/messages/OWNERS b/chromium/components/messages/OWNERS
index 176a5092755..3e383e56e43 100644
--- a/chromium/components/messages/OWNERS
+++ b/chromium/components/messages/OWNERS
@@ -1,4 +1,4 @@
-pavely@chromium.org
twellington@chromium.org
mdjones@chromium.org
lazzzis@google.com
+aishwaryarj@google.com
diff --git a/chromium/components/messages/README.md b/chromium/components/messages/README.md
new file mode 100644
index 00000000000..560d317b6a8
--- /dev/null
+++ b/chromium/components/messages/README.md
@@ -0,0 +1,236 @@
+# Messages UI
+
+Message UI is an alternative to InfoBar UI on Android. It provides a set of APIs
+and a consistent, ephemeral and trustworthy UI with various lifecycles and
+priorities.
+
+[TOC]
+
+## Overview
+
+Each message should include at least 3 properties: title, primary icon and
+primary button text.
+
+Each message will automatically be displayed, hidden and dismissed according to
+given scope (see details below) and can be dismissed automatically or manually.
+By default, each message will be automatically dismissed after around 10s after
+it is displayed. The timer will be reset if the text or icon on the UI is
+changed or if the Message is re-shown. Also, users can dismiss the message by
+swiping the UI upwards, leftwards and rightwards. The feature clients can also
+manually dismiss the message through provided APIs if necessary.
+
+
+## Developing a new Message UI Feature
+
+You need to do the following things to enable your message UI, all described in
+detail below.
+
+1. [Declare your message UI](#Declaring-your-message-ui) by adding a Message Identifier.
+2. [Build a message model](#Build-a-message-model).
+3. [Enqueue your message model](#Enqueue-your-message-model).
+
+
+## Declare your message UI
+
+You need to create a `MessageIdentifier` that represents your Message UI, which
+distinguishes it from other message UIs and enables some feature-specific metrics
+to be recorded.
+
+The MessageIdentifier is defined as an `enum` and a string, which should be
+appended in following files (you can refer to
+[this CL](https://chromium-review.googlesource.com/c/chromium/src/+/3139695) as an example):
+
+1. `components/messages/android/message_enums.h` [[1](https://chromium-review.googlesource.com/c/chromium/src/+/3139695/4/components/messages/android/message_enums.h#90)]
+2. MessageIdentifier in `tools/metrics/histograms/enums.xml` [[1](https://chromium-review.googlesource.com/c/chromium/src/+/3139695/4/tools/metrics/histograms/enums.xml#55511)]
+3. MessageIdentifier in `tools/metrics/histograms/metadata/android/histograms.xml` [[1](https://chromium-review.googlesource.com/c/chromium/src/+/3139695/4/tools/metrics/histograms/metadata/android/histograms.xml#97)]
+4. MessageIdentifier string in `components/messages/android/java/src/org/chromium/components/messages/MessagesMetrics.java` [[1](https://chromium-review.googlesource.com/c/chromium/src/+/3139695/4/components/messages/android/internal/java/src/org/chromium/components/messages/MessagesMetrics.java#102)]
+
+
+## Build a message model
+
+All available model properties are defined in [components/messages/android/…/MessageBannerProperties.java](https://source.chromium.org/chromium/chromium/src/+/main:components/messages/android/java/src/org/chromium/components/messages/MessageBannerProperties.java)
+
+Only some of them are required:
+
+1. TITLE: the main text of the message UI
+2. ICON / ICON_RESOURCE_ID: the primary icon of the message UI, located at the
+ start side of the UI.
+3. PRIMARY_BUTTON_TEXT: the label of the primary button, located at the end of
+ the message UI.
+
+The rest are optional, but some of those are very commonly used:
+
+1. DESCRIPTION: the description / subtitle of the message UI, usually used to
+ help explain the purpose of the message UI.
+2. ON_PRIMARY_ACTION: the callback function triggered when the user clicks on
+ the primary button. Only called once. After this function is triggered, the
+ message itself will be dismissed.
+3. ON_SECONDARY_ACTION / SECONDARY_BUTTON_MENU_TEXT / SECONDARY_ICON_CONTENT_DESCRIPTION
+ / SECONDARY_ICON / SECONDARY_ICON_RESOURCE_ID: these are used to set a
+ secondary action / menu. If SECONDARY_BUTTON_MENU_TEXT is configured, clicking
+ on the secondary button will trigger a single-menu-item popup menu.
+ Clicking on the secondary icon does not guarantee that the message will be
+ automatically dismissed. We recommend the feature code to manually dismiss
+ the message when secondary action callback is triggered.
+ 1. Note: there are changes in-flight to allow multiple menu items.
+ Documentation will be updated once that lands.
+4. ON_DISMISSED: the callback function triggered when the message UI is dismissed.
+ Dismiss means the message has been removed from the queue and will not be displayed again.
+
+You can refer to
+[this CL](https://chromium-review.googlesource.com/c/chromium/src/+/3039479/17/chrome/android/java/src/org/chromium/chrome/browser/survey/ChromeSurveyController.java#239)
+as an example on the Java side and
+[this CL](https://chromium-review.googlesource.com/c/chromium/src/+/3161257/5/chrome/browser/android/oom_intervention/near_oom_reduction_message_delegate.cc#35)
+as an example on the Native side.
+
+Some other, less commonly used properties are:
+
+* ICON_TINT_COLOR: the default icon color is blue. Use this to update the icon
+ color and set TINT_NONE to disable the icon tint color.
+* DESCRIPTION_MAX_LINES: set max lines of the description. The default when this
+ property isn't set is to show all the description texts, which may occupy too much screen space.
+
+
+## Enqueue your message model
+
+After the model is defined and ready to be displayed, it should be enqueued by
+calling MessageDispatcher#enqueueMessage and providing the model, scope,
+and priority.
+
+
+### MessageDispatcher
+
+MessageDispatcher is per-window object. In Java, use
+[MessageDispatcherProvider#from](https://source.chromium.org/chromium/chromium/src/+/main:components/messages/android/java/src/org/chromium/components/messages/MessageDispatcherProvider.java;l=35)
+to get a dispatcher available in the current window, which can be null if native
+initialization is not finished yet. In C++, use
+messages::MessageDispatcherBridge::Get() instead.
+
+
+### Scope
+
+Message scope can also be seen as the life cycle of a message UI. It pre-defines
+when and where messages should be displayed and dismissed. There are 3 scopes in
+total (components/messages/android/message_enums.h):
+
+1. **Navigation**: messages of navigation will be displayed only on the web page
+ for which they are enqueued. It will be hidden (not dismissed) when the user
+ switches to another tab and displayed again when the user returns to the
+ target tab. It will be dismissed when user navigates to another page, such as
+ navigating to [https://chromium.org](https://chromium.org) from
+ [https://google.com](https://google.com) or navigating to
+ [https://google.com/about](https://google.com/about) from
+ [https://google.com/settings](https://google.com/settings), and also
+ dismissed when the tab where the page lives is closed. This should be used
+ when the content and purpose of the Message is tightly related to a certain
+ page. For example, password messages should be only displayed on the page
+ where the user submits the password and dismissed if the user navigates to
+ another page.
+2. **Window**: messages of window scope will be displayed as long as the current
+ window is alive (current window is dead usually when app is closed or user
+ merges windows). It can be displayed on any tab and web page. So this scope
+ should be used only when the content and purpose of the message is unrelated
+ to the web page. For example, Sync Error message is related to the app rather
+ than the page and works as an app-level notification. Use
+ #EnqueueWindowScopedMessage to enqueue a window-scoped message.
+3. **Web_Contents**: this one is rarely used and usually not recommended unless
+ really necessary. The only difference between web_contents scope and navigation
+ scope is that messages of web_contents scope do not dismiss when the user
+ navigates to another page; i.e. it is only dismissed when its associated
+ tab is closed.
+
+
+### Priority
+
+There are two types of priority: urgent (a.k.a high) and normal (a.k.a low).
+
+Urgent messages will be displayed ASAP, in spite of enqueued messages of normal
+properties. Urgent should only be used when the message is so important that you
+want users to take an action ASAP, such as a serious security risk found on the
+page the user is visiting. Otherwise, use normal in most cases.
+
+
+## Dismiss your message
+
+As explained in [Overview](#Overview), by default, the message will be dismissed
+in the following cases:
+
+* Timeout
+* Swiping gesture
+* Primary action button is clicked
+* The given scope is destroyed
+
+In addition, messages can be dismissed by feature client code so that the
+message won’t be displayed any more. Use MessageDispatcher#dismissMessage to
+dismiss the message. The dismiss callback will still be triggered.
+
+
+## Ownership in native
+
+In native, MessageDispatcherBridge#EnqueueMessage will return a MessageWrapper
+object. The feature client is responsible for managing it. We recommend
+dismissing the message manually if the MessageWrapper object is still alive when
+the owner of the MessageWrapper object is destroyed.
+
+
+## Test
+
+On the Java side,
+[components/messages/android/test/…/messages/MessagesTestHelper.java](https://source.chromium.org/chromium/chromium/src/+/main:components/messages/android/test/java/src/org/chromium/components/messages/MessagesTestHelper.java)
+is available to get all current enqueued messages and get the property model of a certain message.
+
+In native, components/messages/android/mock_message_dispatcher_bridge.h is
+available to test whether a message is enqueued and trigger some callbacks
+manually. You can refer to
+[this CL](https://chromium-review.googlesource.com/c/chromium/src/+/3161257/5/chrome/browser/android/oom_intervention/near_oom_reduction_message_delegate_unittest.cc)
+as an example.
+
+
+## Built-in Metrics
+
+Some metrics have been pre-defined to help evaluate the effectiveness of a message.
+
+**Android.Messages.Enqueued**
+
+Records the message identifier each time a message is enqueued through
+MessageDispatcher. This histogram can be used for getting a count of messages
+broken down by message identifier.
+
+**Android.Messages.Dismissed.{MessageIdentifier}**
+
+Records the reason why this message is dismissed, such as primary action, timer,
+gesture and so on.
+
+**Android.Messages.TimeToAction.Dismiss.{MessageIdentifier}**
+
+Records the time interval the message was displayed on the screen before the
+user dismissed it with a gesture. The metric is NOT recorded when the user
+presses primary or secondary button or when the message is auto-dismissed based
+on timer.
+
+**Android.Messages.TimeToAction.{MessageIdentifier}**
+
+Records the time interval the message was displayed on the screen before the
+user explicitly dismissed it. The metric is recorded when the user presses the
+primary or secondary button, or dismisses the message with a gesture.
+
+
+## Built-in Finch Parameter to control the duration
+
+Using `autodismiss_duration_ms_{MessageIdentifier}` inside the feature
+`MessagesForAndroidInfrastructure` to configure the duration through finch.
+This method does not require any code changes in clients. E.g.:
+
+
+```
+// update the default timer duration of Sync Error Message to 30000 ms
+Feature MessagesForAndroidInfrastructure {
+ params = {
+ autodismiss_duration_ms_SyncError = 30000
+ }
+}
+```
+
+> **Warning**: MessagesForAndroidInfrastructure is enabled by default.
+> **DO NOT** disable it in any group. Disabling MessagesForAndroidInfrastructure
+> will break other experiments depending on that flag.
diff --git a/chromium/components/messages/android/internal/BUILD.gn b/chromium/components/messages/android/internal/BUILD.gn
index 3d04eb08571..46d55acde4d 100644
--- a/chromium/components/messages/android/internal/BUILD.gn
+++ b/chromium/components/messages/android/internal/BUILD.gn
@@ -95,8 +95,10 @@ android_library("javatests") {
android_resources("java_resources") {
sources = [
- "java/res/drawable/message_bg_tinted.xml",
+ "java/res/drawable-v23/message_bg_tinted.xml",
+ "java/res/drawable-v31/message_bg_tinted.xml",
"java/res/layout/message_banner_view.xml",
+ "java/res/values-night/dimens.xml",
"java/res/values/dimens.xml",
]
deps = [
diff --git a/chromium/components/messages/android/internal/java/res/drawable/message_bg_tinted.xml b/chromium/components/messages/android/internal/java/res/drawable-v23/message_bg_tinted.xml
index bdbfa194682..5465a4ab556 100644
--- a/chromium/components/messages/android/internal/java/res/drawable/message_bg_tinted.xml
+++ b/chromium/components/messages/android/internal/java/res/drawable-v23/message_bg_tinted.xml
@@ -9,7 +9,7 @@
<item>
<shape>
<corners android:radius="@dimen/message_banner_radius"/>
- <solid android:color="@color/dialog_bg_color"/>
+ <solid android:color="@color/dialog_bg_color_baseline"/>
</shape>
</item>
</layer-list>
diff --git a/chromium/components/messages/android/internal/java/res/drawable-v31/message_bg_tinted.xml b/chromium/components/messages/android/internal/java/res/drawable-v31/message_bg_tinted.xml
new file mode 100644
index 00000000000..8601c314962
--- /dev/null
+++ b/chromium/components/messages/android/internal/java/res/drawable-v31/message_bg_tinted.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2022 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. -->
+
+<org.chromium.components.browser_ui.widget.SurfaceColorDrawable
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:shape="rectangle"
+ app:surfaceElevation="@dimen/message_bg_tinted_elev">
+ <corners android:radius="@dimen/message_banner_radius"/>
+</org.chromium.components.browser_ui.widget.SurfaceColorDrawable>
diff --git a/chromium/components/messages/android/internal/java/res/layout/message_banner_view.xml b/chromium/components/messages/android/internal/java/res/layout/message_banner_view.xml
index b1684837c4a..68afc88de31 100644
--- a/chromium/components/messages/android/internal/java/res/layout/message_banner_view.xml
+++ b/chromium/components/messages/android/internal/java/res/layout/message_banner_view.xml
@@ -46,20 +46,23 @@
android:textDirection="locale"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
- <TextView
+ <org.chromium.components.browser_ui.widget.text.TextViewWithCompoundDrawables
android:id="@+id/message_description"
style="@style/TextAppearance.TextSmall.Secondary"
android:visibility="gone"
android:breakStrategy="simple"
android:textDirection="locale"
android:layout_width="match_parent"
- android:layout_height="wrap_content" />
+ android:layout_height="wrap_content"
+ android:drawablePadding="@dimen/message_description_icon_padding"
+ app:drawableWidth="@dimen/message_description_icon_size"
+ app:drawableHeight="@dimen/message_description_icon_size"/>
</LinearLayout>
<!-- Content description is set programmatically according to secondary button icon. -->
<org.chromium.components.browser_ui.widget.listmenu.ListMenuButton
android:id="@+id/message_secondary_button"
- app:tint="@color/default_icon_color_secondary"
+ app:tint="@macro/default_icon_color_secondary"
app:menuVerticalOverlapAnchor="false"
android:visibility="gone"
android:contentDescription="@null"
diff --git a/chromium/components/messages/android/internal/java/res/values-night/dimens.xml b/chromium/components/messages/android/internal/java/res/values-night/dimens.xml
new file mode 100644
index 00000000000..e18fbcd1eeb
--- /dev/null
+++ b/chromium/components/messages/android/internal/java/res/values-night/dimens.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2022 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. -->
+
+<resources>
+ <dimen name="message_bg_tinted_elev">@dimen/default_elevation_3</dimen>
+</resources>
diff --git a/chromium/components/messages/android/internal/java/res/values/dimens.xml b/chromium/components/messages/android/internal/java/res/values/dimens.xml
index 5b748f5e92e..bd8839034be 100644
--- a/chromium/components/messages/android/internal/java/res/values/dimens.xml
+++ b/chromium/components/messages/android/internal/java/res/values/dimens.xml
@@ -15,12 +15,15 @@
<dimen name="message_icon_margin">12dp</dimen>
<dimen name="message_icon_size">24dp</dimen>
<dimen name="message_icon_size_large">36dp</dimen>
+ <dimen name="message_description_icon_size">18dp</dimen>
+ <dimen name="message_description_icon_padding">8dp</dimen>
<dimen name="message_divider_margin">12dp</dimen>
<dimen name="message_shadow_lateral_margin">12dp</dimen>
<dimen name="message_shadow_bottom_margin">16dp</dimen>
<dimen name="message_vertical_hide_threshold">16dp</dimen>
- <dimen name="message_horizontal_hide_threshold">24dp</dimen>
+ <dimen name="message_horizontal_hide_threshold">10dp</dimen>
<dimen name="message_max_horizontal_translation">360dp</dimen>
<dimen name="message_max_width">380dp</dimen>
+ <dimen name="message_bg_tinted_elev">@dimen/default_elevation_0</dimen>
</resources>
diff --git a/chromium/components/messages/android/internal/java/src/org/chromium/components/messages/MessageBannerMediator.java b/chromium/components/messages/android/internal/java/src/org/chromium/components/messages/MessageBannerMediator.java
index 5fc9cc4b10a..7e8adf9dbd4 100644
--- a/chromium/components/messages/android/internal/java/src/org/chromium/components/messages/MessageBannerMediator.java
+++ b/chromium/components/messages/android/internal/java/src/org/chromium/components/messages/MessageBannerMediator.java
@@ -214,18 +214,15 @@ class MessageBannerMediator implements SwipeHandler {
final float velocity = isVertical ? velocityY : velocityX;
float translateTo;
if (isVertical) {
- translateTo = velocity < 0 ? -mMaxTranslationYSupplier.get() : 0;
+ final float translationY = mModel.get(TRANSLATION_Y);
+ translateTo = translationY < 0 ? -mMaxTranslationYSupplier.get() : 0;
} else {
final float translationX = mModel.get(TRANSLATION_X);
-
- if (velocity < 0) {
- translateTo = translationX > mHorizontalHideThresholdPx
- ? 0
- : -mMaxHorizontalTranslationPx.get();
+ if (Math.abs(translationX) < mHorizontalHideThresholdPx) {
+ translateTo = 0;
} else {
- translateTo = translationX < -mHorizontalHideThresholdPx
- ? 0
- : mMaxHorizontalTranslationPx.get();
+ translateTo =
+ MathUtils.flipSignIf(mMaxHorizontalTranslationPx.get(), translationX < 0);
}
}
diff --git a/chromium/components/messages/android/internal/java/src/org/chromium/components/messages/MessageBannerMediatorUnitTest.java b/chromium/components/messages/android/internal/java/src/org/chromium/components/messages/MessageBannerMediatorUnitTest.java
index 5511997fbac..ac254f91821 100644
--- a/chromium/components/messages/android/internal/java/src/org/chromium/components/messages/MessageBannerMediatorUnitTest.java
+++ b/chromium/components/messages/android/internal/java/src/org/chromium/components/messages/MessageBannerMediatorUnitTest.java
@@ -279,7 +279,7 @@ public class MessageBannerMediatorUnitTest {
}
@Test
- public void testHorizontalFlingFromOutsideThresholdToCenterNotDismissed() {
+ public void testHorizontalFlingFromOutsideThresholdToCenterDismissed() {
mMediator.show(mShownRunnable);
shadowOf(getMainLooper()).idle();
@@ -295,19 +295,8 @@ public class MessageBannerMediatorUnitTest {
shadowOf(getMainLooper()).idle();
- assertModelState(0, 0, 1, "animated to idle position after fling.");
- verify(mDismissedRunnable, times(0)).run();
-
- // More than the threshold to dismiss, fling back to center
- swipeHorizontal(-30, 100);
-
- // Alpha .75 is 1 (fully opaque) - 30 (translationY) / 120 (maxTranslation)
- assertModelState(-30, 0, .75f, "after swipe.");
-
- shadowOf(getMainLooper()).idle();
-
- assertModelState(0, 0, 1, "animated to idle position after fling.");
- verify(mDismissedRunnable, times(0)).run();
+ assertModelState(120, 0, 0, "after swipe");
+ verify(mDismissedRunnable).run();
}
@Test
@@ -327,19 +316,8 @@ public class MessageBannerMediatorUnitTest {
shadowOf(getMainLooper()).idle();
- assertModelState(0, 0, 1, "animated to idle position after fling.");
- verify(mDismissedRunnable, times(0)).run();
-
- // Less than the threshold to dismiss, fling back to center
- swipeVertical(-10, 100);
-
- // .9 is 1 (fully opaque) - 10 (translationY) / 100 (maxTranslation)
- assertModelState(0, -10, .9f, "after swipe.");
-
- shadowOf(getMainLooper()).idle();
-
- assertModelState(0, 0, 1, "animated to idle position after fling.");
- verify(mDismissedRunnable, times(0)).run();
+ assertModelState(0, -100, 0, "after swipe");
+ verify(mDismissedRunnable, times(1)).run();
}
@Test
@@ -398,7 +376,7 @@ public class MessageBannerMediatorUnitTest {
}
@Test
- public void testLeftFlingWithinThresholdPositiveXDismisses() {
+ public void testLeftFlingWithinThresholdPositiveXNoDismisses() {
mMediator.show(mShownRunnable);
shadowOf(getMainLooper()).idle();
@@ -414,12 +392,12 @@ public class MessageBannerMediatorUnitTest {
shadowOf(getMainLooper()).idle();
- assertModelState(-120, 0, 0, "dismissed to left after fling.");
- verify(mDismissedRunnable, times(1)).run();
+ assertModelState(0, 0, 1, "animate back to center.");
+ verify(mDismissedRunnable, times(0)).run();
}
@Test
- public void testLeftFlingWithinThresholdNegativeXDismisses() {
+ public void testLeftFlingWithinThresholdNegativeXNoDismisses() {
mMediator.show(mShownRunnable);
shadowOf(getMainLooper()).idle();
@@ -435,12 +413,12 @@ public class MessageBannerMediatorUnitTest {
shadowOf(getMainLooper()).idle();
- assertModelState(-120, 0, 0, "dismissed to left after fling.");
- verify(mDismissedRunnable, times(1)).run();
+ assertModelState(0, 0, 1, "animate back to center.");
+ verify(mDismissedRunnable, times(0)).run();
}
@Test
- public void testRightFlingWithinThresholdNegativeXDismisses() {
+ public void testRightFlingWithinThresholdNegativeXNoDismisses() {
mMediator.show(mShownRunnable);
shadowOf(getMainLooper()).idle();
@@ -456,12 +434,12 @@ public class MessageBannerMediatorUnitTest {
shadowOf(getMainLooper()).idle();
- assertModelState(120, 0, 0, "dismissed to right after fling.");
- verify(mDismissedRunnable, times(1)).run();
+ assertModelState(0, 0, 1, "animate back to center.");
+ verify(mDismissedRunnable, times(0)).run();
}
@Test
- public void testRightFlingWithinThresholdPositiveXDismisses() {
+ public void testRightFlingWithinThresholdPositiveXNoDismisses() {
mMediator.show(mShownRunnable);
shadowOf(getMainLooper()).idle();
@@ -477,8 +455,8 @@ public class MessageBannerMediatorUnitTest {
shadowOf(getMainLooper()).idle();
- assertModelState(120, 0, 0, "dismissed to right after fling.");
- verify(mDismissedRunnable, times(1)).run();
+ assertModelState(0, 0, 1, "animate back to center.");
+ verify(mDismissedRunnable, times(0)).run();
}
@Test
diff --git a/chromium/components/messages/android/internal/java/src/org/chromium/components/messages/MessageBannerRenderTest.java b/chromium/components/messages/android/internal/java/src/org/chromium/components/messages/MessageBannerRenderTest.java
index bd8332da470..1b6ffd2df60 100644
--- a/chromium/components/messages/android/internal/java/src/org/chromium/components/messages/MessageBannerRenderTest.java
+++ b/chromium/components/messages/android/internal/java/src/org/chromium/components/messages/MessageBannerRenderTest.java
@@ -32,7 +32,7 @@ import org.chromium.base.test.util.Feature;
import org.chromium.content_public.browser.test.util.TestThreadUtils;
import org.chromium.ui.modelutil.PropertyModel;
import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
-import org.chromium.ui.test.util.DummyUiActivityTestCase;
+import org.chromium.ui.test.util.BlankUiTestActivityTestCase;
import org.chromium.ui.test.util.NightModeTestUtils;
import org.chromium.ui.test.util.RenderTestRule;
@@ -42,7 +42,7 @@ import java.util.List;
*/
@RunWith(ParameterizedRunner.class)
@UseRunnerDelegate(BaseJUnit4RunnerDelegate.class)
-public class MessageBannerRenderTest extends DummyUiActivityTestCase {
+public class MessageBannerRenderTest extends BlankUiTestActivityTestCase {
@ClassParameter
private static List<ParameterSet> sClassParams =
new NightModeTestUtils.NightModeParams().getParameters();
@@ -51,7 +51,7 @@ public class MessageBannerRenderTest extends DummyUiActivityTestCase {
public RenderTestRule mRenderTestRule = RenderTestRule.Builder.withPublicCorpus().build();
public MessageBannerRenderTest(boolean nightModeEnabled) {
- NightModeTestUtils.setUpNightModeForDummyUiActivity(nightModeEnabled);
+ NightModeTestUtils.setUpNightModeForBlankUiTestActivity(nightModeEnabled);
mRenderTestRule.setNightModeEnabled(nightModeEnabled);
}
diff --git a/chromium/components/messages/android/internal/java/src/org/chromium/components/messages/MessageBannerView.java b/chromium/components/messages/android/internal/java/src/org/chromium/components/messages/MessageBannerView.java
index 9e24fb66bc4..c19da98abd4 100644
--- a/chromium/components/messages/android/internal/java/src/org/chromium/components/messages/MessageBannerView.java
+++ b/chromium/components/messages/android/internal/java/src/org/chromium/components/messages/MessageBannerView.java
@@ -30,6 +30,7 @@ import org.chromium.components.browser_ui.widget.listmenu.ListMenuButton;
import org.chromium.components.browser_ui.widget.listmenu.ListMenuButton.PopupMenuShownListener;
import org.chromium.components.browser_ui.widget.listmenu.ListMenuButtonDelegate;
import org.chromium.components.browser_ui.widget.listmenu.ListMenuItemProperties;
+import org.chromium.components.browser_ui.widget.text.TextViewWithCompoundDrawables;
import org.chromium.ui.base.ViewUtils;
import org.chromium.ui.modelutil.MVCListAdapter;
import org.chromium.ui.modelutil.PropertyModel;
@@ -40,7 +41,7 @@ import org.chromium.ui.modelutil.PropertyModel;
public class MessageBannerView extends BoundedLinearLayout {
private ImageView mIconView;
private TextView mTitle;
- private TextView mDescription;
+ private TextViewWithCompoundDrawables mDescription;
private TextView mPrimaryButton;
private ListMenuButton mSecondaryButton;
private View mDivider;
@@ -50,6 +51,7 @@ public class MessageBannerView extends BoundedLinearLayout {
private Runnable mOnTitleChanged;
private int mCornerRadius = -1;
private PopupMenuShownListener mPopupMenuShownListener;
+ private Drawable mDescriptionDrawable;
public MessageBannerView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
@@ -72,11 +74,37 @@ public class MessageBannerView extends BoundedLinearLayout {
if (mOnTitleChanged != null) mOnTitleChanged.run();
}
- void setDescription(CharSequence description) {
+ void setTitleContentDescription(String description) {
+ mTitle.setContentDescription(description);
+ }
+
+ void setDescriptionText(CharSequence description) {
mDescription.setVisibility(TextUtils.isEmpty(description) ? GONE : VISIBLE);
mDescription.setText(description);
}
+ void setDescriptionIcon(Drawable drawable) {
+ mDescription.setVisibility(drawable == null ? GONE : VISIBLE);
+ mDescriptionDrawable = drawable;
+ ((TextView) mDescription).setCompoundDrawablesRelative(drawable, null, null, null);
+ }
+
+ void enableDescriptionIconIntrinsicDimensions(boolean enabled) {
+ if (mDescriptionDrawable != null) {
+ int defaultIconSize =
+ getResources().getDimensionPixelOffset(R.dimen.message_description_icon_size);
+ if (enabled) {
+ int newWidth = defaultIconSize * mDescriptionDrawable.getIntrinsicWidth()
+ / mDescriptionDrawable.getIntrinsicHeight();
+ mDescription.setDrawableWidth(newWidth);
+ } else {
+ mDescription.setDrawableWidth(defaultIconSize);
+ }
+ ((TextView) mDescription)
+ .setCompoundDrawablesRelative(mDescriptionDrawable, null, null, null);
+ }
+ }
+
void setDescriptionMaxLines(int maxLines) {
mDescription.setMaxLines(maxLines);
mDescription.setEllipsize(TextUtils.TruncateAt.END);
diff --git a/chromium/components/messages/android/internal/java/src/org/chromium/components/messages/MessageBannerViewBinder.java b/chromium/components/messages/android/internal/java/src/org/chromium/components/messages/MessageBannerViewBinder.java
index 6975e7456b2..e087f98a4d0 100644
--- a/chromium/components/messages/android/internal/java/src/org/chromium/components/messages/MessageBannerViewBinder.java
+++ b/chromium/components/messages/android/internal/java/src/org/chromium/components/messages/MessageBannerViewBinder.java
@@ -6,6 +6,7 @@ package org.chromium.components.messages;
import static org.chromium.components.messages.MessageBannerProperties.ALPHA;
import static org.chromium.components.messages.MessageBannerProperties.DESCRIPTION;
+import static org.chromium.components.messages.MessageBannerProperties.DESCRIPTION_ICON;
import static org.chromium.components.messages.MessageBannerProperties.DESCRIPTION_MAX_LINES;
import static org.chromium.components.messages.MessageBannerProperties.ICON;
import static org.chromium.components.messages.MessageBannerProperties.ICON_RESOURCE_ID;
@@ -16,11 +17,13 @@ import static org.chromium.components.messages.MessageBannerProperties.ON_SECOND
import static org.chromium.components.messages.MessageBannerProperties.ON_TOUCH_RUNNABLE;
import static org.chromium.components.messages.MessageBannerProperties.PRIMARY_BUTTON_CLICK_LISTENER;
import static org.chromium.components.messages.MessageBannerProperties.PRIMARY_BUTTON_TEXT;
+import static org.chromium.components.messages.MessageBannerProperties.RESIZE_DESCRIPTION_ICON;
import static org.chromium.components.messages.MessageBannerProperties.SECONDARY_BUTTON_MENU_TEXT;
import static org.chromium.components.messages.MessageBannerProperties.SECONDARY_ICON;
import static org.chromium.components.messages.MessageBannerProperties.SECONDARY_ICON_CONTENT_DESCRIPTION;
import static org.chromium.components.messages.MessageBannerProperties.SECONDARY_ICON_RESOURCE_ID;
import static org.chromium.components.messages.MessageBannerProperties.TITLE;
+import static org.chromium.components.messages.MessageBannerProperties.TITLE_CONTENT_DESCRIPTION;
import static org.chromium.components.messages.MessageBannerProperties.TRANSLATION_X;
import static org.chromium.components.messages.MessageBannerProperties.TRANSLATION_Y;
@@ -43,8 +46,15 @@ public class MessageBannerViewBinder {
view.setPrimaryButtonClickListener(model.get(PRIMARY_BUTTON_CLICK_LISTENER));
} else if (propertyKey == TITLE) {
view.setTitle(model.get(TITLE));
+ } else if (propertyKey == TITLE_CONTENT_DESCRIPTION) {
+ view.setTitleContentDescription(model.get(TITLE_CONTENT_DESCRIPTION));
} else if (propertyKey == DESCRIPTION) {
- view.setDescription(model.get(DESCRIPTION));
+ view.setDescriptionText(model.get(DESCRIPTION));
+ } else if (propertyKey == DESCRIPTION_ICON) {
+ view.setDescriptionIcon(model.get(DESCRIPTION_ICON));
+ view.enableDescriptionIconIntrinsicDimensions(model.get(RESIZE_DESCRIPTION_ICON));
+ } else if (propertyKey == RESIZE_DESCRIPTION_ICON) {
+ view.enableDescriptionIconIntrinsicDimensions(model.get(RESIZE_DESCRIPTION_ICON));
} else if (propertyKey == DESCRIPTION_MAX_LINES) {
view.setDescriptionMaxLines(model.get(DESCRIPTION_MAX_LINES));
} else if (propertyKey == ICON) {
diff --git a/chromium/components/messages/android/internal/java/src/org/chromium/components/messages/MessageBannerViewTest.java b/chromium/components/messages/android/internal/java/src/org/chromium/components/messages/MessageBannerViewTest.java
index f3943d09162..5cc340125af 100644
--- a/chromium/components/messages/android/internal/java/src/org/chromium/components/messages/MessageBannerViewTest.java
+++ b/chromium/components/messages/android/internal/java/src/org/chromium/components/messages/MessageBannerViewTest.java
@@ -35,8 +35,8 @@ import org.chromium.components.browser_ui.widget.listmenu.ListMenuButton.PopupMe
import org.chromium.content_public.browser.test.util.TestThreadUtils;
import org.chromium.ui.modelutil.PropertyModel;
import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
+import org.chromium.ui.test.util.BlankUiTestActivity;
import org.chromium.ui.test.util.DisableAnimationsTestRule;
-import org.chromium.ui.test.util.DummyUiActivity;
/**
* Instrumentation tests for MessageBannerView.
@@ -51,8 +51,8 @@ public class MessageBannerViewTest {
new DisableAnimationsTestRule();
@ClassRule
- public static BaseActivityTestRule<DummyUiActivity> sActivityTestRule =
- new BaseActivityTestRule<>(DummyUiActivity.class);
+ public static BaseActivityTestRule<BlankUiTestActivity> sActivityTestRule =
+ new BaseActivityTestRule<>(BlankUiTestActivity.class);
private static Activity sActivity;
private static ViewGroup sContentView;
diff --git a/chromium/components/messages/android/internal/java/src/org/chromium/components/messages/SingleActionMessageTest.java b/chromium/components/messages/android/internal/java/src/org/chromium/components/messages/SingleActionMessageTest.java
index b96743cc3f8..874da49e693 100644
--- a/chromium/components/messages/android/internal/java/src/org/chromium/components/messages/SingleActionMessageTest.java
+++ b/chromium/components/messages/android/internal/java/src/org/chromium/components/messages/SingleActionMessageTest.java
@@ -33,8 +33,8 @@ import org.chromium.base.test.BaseJUnit4ClassRunner;
import org.chromium.base.test.util.CallbackHelper;
import org.chromium.content_public.browser.test.util.TestThreadUtils;
import org.chromium.ui.modelutil.PropertyModel;
+import org.chromium.ui.test.util.BlankUiTestActivity;
import org.chromium.ui.test.util.DisableAnimationsTestRule;
-import org.chromium.ui.test.util.DummyUiActivity;
/**
* Tests for {@link SingleActionMessage}.
@@ -45,8 +45,8 @@ public class SingleActionMessageTest {
public static DisableAnimationsTestRule sDisableAnimationsRule =
new DisableAnimationsTestRule();
@ClassRule
- public static BaseActivityTestRule<DummyUiActivity> sActivityTestRule =
- new BaseActivityTestRule<>(DummyUiActivity.class);
+ public static BaseActivityTestRule<BlankUiTestActivity> sActivityTestRule =
+ new BaseActivityTestRule<>(BlankUiTestActivity.class);
private static Activity sActivity;
diff --git a/chromium/components/messages/android/message_dispatcher_bridge.cc b/chromium/components/messages/android/message_dispatcher_bridge.cc
index 9d0a26ce499..6585e3ab92a 100644
--- a/chromium/components/messages/android/message_dispatcher_bridge.cc
+++ b/chromium/components/messages/android/message_dispatcher_bridge.cc
@@ -85,9 +85,11 @@ int MessageDispatcherBridge::MapToJavaDrawableId(int resource_id) {
return resource_id_mapper_.Run(resource_id);
}
-void MessageDispatcherBridge::SetResourceIdMapper(
- ResourceIdMapper resource_id_mapper) {
+void MessageDispatcherBridge::Initialize(ResourceIdMapper resource_id_mapper) {
resource_id_mapper_ = std::move(resource_id_mapper);
+ // resource_id_mapper_ will only be initialized in an embedder that supports
+ // the Messages UI.
+ messages_enabled_for_embedder_ = true;
}
} // namespace messages
diff --git a/chromium/components/messages/android/message_dispatcher_bridge.h b/chromium/components/messages/android/message_dispatcher_bridge.h
index 97fc73e66c5..ba05dea484f 100644
--- a/chromium/components/messages/android/message_dispatcher_bridge.h
+++ b/chromium/components/messages/android/message_dispatcher_bridge.h
@@ -42,10 +42,13 @@ class MessageDispatcherBridge {
// code that doesn't have access to ResourceMapper, e.g. code in //components.
virtual int MapToJavaDrawableId(int resource_id);
- void SetResourceIdMapper(ResourceIdMapper resource_id_mapper);
+ void Initialize(ResourceIdMapper resource_id_mapper);
+
+ bool IsMessagesEnabledForEmbedder() { return messages_enabled_for_embedder_; }
protected:
virtual ~MessageDispatcherBridge();
+ bool messages_enabled_for_embedder_;
private:
ResourceIdMapper resource_id_mapper_;
diff --git a/chromium/components/messages/android/message_enums.h b/chromium/components/messages/android/message_enums.h
index 3f3f7249734..56c6bd51a18 100644
--- a/chromium/components/messages/android/message_enums.h
+++ b/chromium/components/messages/android/message_enums.h
@@ -98,6 +98,8 @@ enum class MessageIdentifier {
TAILORED_SECURITY_ENABLED = 23,
VR_SERVICES_UPGRADE = 24,
TAILORED_SECURITY_DISABLED = 25,
+ AR_CORE_UPGRADE = 26,
+ INSTANT_APPS = 27,
// Insert new values before this line.
COUNT
diff --git a/chromium/components/messages/android/messages_feature.cc b/chromium/components/messages/android/messages_feature.cc
index 4ff584b0a8e..081cee51df2 100644
--- a/chromium/components/messages/android/messages_feature.cc
+++ b/chromium/components/messages/android/messages_feature.cc
@@ -9,7 +9,7 @@
namespace messages {
const base::Feature kMessagesForAndroidAdsBlocked{
- "MessagesForAndroidAdsBlocked", base::FEATURE_DISABLED_BY_DEFAULT};
+ "MessagesForAndroidAdsBlocked", base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kMessagesForAndroidChromeSurvey{
"MessagesForAndroidChromeSurvey", base::FEATURE_DISABLED_BY_DEFAULT};
@@ -17,8 +17,11 @@ const base::Feature kMessagesForAndroidChromeSurvey{
const base::Feature kMessagesForAndroidInfrastructure{
"MessagesForAndroidInfrastructure", base::FEATURE_ENABLED_BY_DEFAULT};
+const base::Feature kMessagesForAndroidInstantApps{
+ "MessagesForAndroidInstantApps", base::FEATURE_DISABLED_BY_DEFAULT};
+
const base::Feature kMessagesForAndroidNearOomReduction{
- "MessagesForAndroidNearOomReduction", base::FEATURE_DISABLED_BY_DEFAULT};
+ "MessagesForAndroidNearOomReduction", base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kMessagesForAndroidNotificationBlocked{
"MessagesForAndroidNotificationBlocked", base::FEATURE_DISABLED_BY_DEFAULT};
@@ -35,7 +38,7 @@ const base::Feature kMessagesForAndroidPermissionUpdate{
"MessagesForAndroidPermissionUpdate", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kMessagesForAndroidPopupBlocked{
- "MessagesForAndroidPopupBlocked", base::FEATURE_DISABLED_BY_DEFAULT};
+ "MessagesForAndroidPopupBlocked", base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kMessagesForAndroidReaderMode{
"MessagesForAndroidReaderMode", base::FEATURE_ENABLED_BY_DEFAULT};
@@ -55,7 +58,7 @@ constexpr base::FeatureParam<bool> kMessagesForAndroidSaveCard_UseGPayIcon{
&kMessagesForAndroidSaveCard, "save_card_message_use_gpay_icon", true};
const base::Feature kMessagesForAndroidSyncError{
- "MessagesForAndroidSyncError", base::FEATURE_DISABLED_BY_DEFAULT};
+ "MessagesForAndroidSyncError", base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kMessagesForAndroidUpdatePassword{
"MessagesForAndroidUpdatePassword", base::FEATURE_DISABLED_BY_DEFAULT};
@@ -72,6 +75,11 @@ bool IsAdsBlockedMessagesUiEnabled() {
base::FeatureList::IsEnabled(kMessagesForAndroidAdsBlocked);
}
+bool IsInstantAppsMessagesUiEnabled() {
+ return base::FeatureList::IsEnabled(kMessagesForAndroidInfrastructure) &&
+ base::FeatureList::IsEnabled(kMessagesForAndroidInstantApps);
+}
+
bool IsNearOomReductionMessagesUiEnabled() {
return base::FeatureList::IsEnabled(kMessagesForAndroidInfrastructure) &&
base::FeatureList::IsEnabled(kMessagesForAndroidNearOomReduction);
diff --git a/chromium/components/messages/android/messages_feature.h b/chromium/components/messages/android/messages_feature.h
index 570224c9321..9a0eceeb8c3 100644
--- a/chromium/components/messages/android/messages_feature.h
+++ b/chromium/components/messages/android/messages_feature.h
@@ -22,6 +22,10 @@ extern const base::Feature kMessagesForAndroidChromeSurvey;
// implementations also fallback to Infobar implementations.
extern const base::Feature kMessagesForAndroidInfrastructure;
+// Feature that controls whether "instant apps" messages use Messages or
+// Infobars infrastructure.
+extern const base::Feature kMessagesForAndroidInstantApps;
+
// Feature that controls whether "near OOM reduction" messages use Messages or
// Infobars infrastructure.
extern const base::Feature kMessagesForAndroidNearOomReduction;
@@ -68,6 +72,8 @@ extern const base::Feature kMessagesForAndroidReduceLayoutChanges;
bool IsAdsBlockedMessagesUiEnabled();
+bool IsInstantAppsMessagesUiEnabled();
+
bool IsNearOomReductionMessagesUiEnabled();
bool IsNotificationBlockedMessagesUiEnabled();
diff --git a/chromium/components/messages/android/mock_message_dispatcher_bridge.cc b/chromium/components/messages/android/mock_message_dispatcher_bridge.cc
index 4980a69fc93..41355611ed5 100644
--- a/chromium/components/messages/android/mock_message_dispatcher_bridge.cc
+++ b/chromium/components/messages/android/mock_message_dispatcher_bridge.cc
@@ -13,4 +13,9 @@ int MockMessageDispatcherBridge::MapToJavaDrawableId(int resource_id) {
return -1;
}
+void MockMessageDispatcherBridge::SetMessagesEnabledForEmbedder(
+ bool messages_enabled_for_embedder) {
+ messages_enabled_for_embedder_ = messages_enabled_for_embedder;
+}
+
} // namespace messages
diff --git a/chromium/components/messages/android/mock_message_dispatcher_bridge.h b/chromium/components/messages/android/mock_message_dispatcher_bridge.h
index 8787ad565a2..a6acf186c9a 100644
--- a/chromium/components/messages/android/mock_message_dispatcher_bridge.h
+++ b/chromium/components/messages/android/mock_message_dispatcher_bridge.h
@@ -28,6 +28,7 @@ class MockMessageDispatcherBridge : public MessageDispatcherBridge {
DismissReason dismiss_reason),
(override));
int MapToJavaDrawableId(int resource_id) override;
+ void SetMessagesEnabledForEmbedder(bool messages_enabled_for_embedder);
};
} // namespace messages
diff --git a/chromium/components/messages/android/test/BUILD.gn b/chromium/components/messages/android/test/BUILD.gn
index 372808c2bfd..e6ce55fe1c0 100644
--- a/chromium/components/messages/android/test/BUILD.gn
+++ b/chromium/components/messages/android/test/BUILD.gn
@@ -4,6 +4,11 @@
import("//build/config/android/rules.gni")
+generate_jni("jni_headers") {
+ sources =
+ [ "java/src/org/chromium/components/messages/MessagesTestHelper.java" ]
+}
+
android_library("test_support_java") {
testonly = true
sources =
@@ -16,3 +21,16 @@ android_library("test_support_java") {
"//ui/android:ui_no_recycler_view_java",
]
}
+
+static_library("test_support_cpp") {
+ testonly = true
+ sources = [
+ "messages_test_helper.cc",
+ "messages_test_helper.h",
+ ]
+ deps = [
+ ":jni_headers",
+ "//base",
+ "//ui/android:android",
+ ]
+}
diff --git a/chromium/components/metal_util/BUILD.gn b/chromium/components/metal_util/BUILD.gn
index 26aa275f7ef..7ad8ede3f9b 100644
--- a/chromium/components/metal_util/BUILD.gn
+++ b/chromium/components/metal_util/BUILD.gn
@@ -19,8 +19,6 @@ component("metal_util") {
"hdr_copier_layer.h",
"hdr_copier_layer.mm",
"metal_util_export.h",
- "switches.cc",
- "switches.h",
"test_shader.h",
"test_shader.mm",
"types.h",
diff --git a/chromium/components/metal_util/hdr_copier_layer.mm b/chromium/components/metal_util/hdr_copier_layer.mm
index 21c337189ac..f690418f520 100644
--- a/chromium/components/metal_util/hdr_copier_layer.mm
+++ b/chromium/components/metal_util/hdr_copier_layer.mm
@@ -126,11 +126,11 @@ const char* tonemapping_shader_source =
// unsupported.
uint32_t GetTransferFunctionIndex(const gfx::ColorSpace& color_space) {
switch (color_space.GetTransferID()) {
- case gfx::ColorSpace::TransferID::IEC61966_2_1_HDR:
+ case gfx::ColorSpace::TransferID::SRGB_HDR:
return 1;
- case gfx::ColorSpace::TransferID::SMPTEST2084:
+ case gfx::ColorSpace::TransferID::PQ:
return 2;
- case gfx::ColorSpace::TransferID::ARIB_STD_B67:
+ case gfx::ColorSpace::TransferID::HLG:
return 3;
default:
return 0;
diff --git a/chromium/components/metal_util/switches.cc b/chromium/components/metal_util/switches.cc
deleted file mode 100644
index 3d9fc1dcc5d..00000000000
--- a/chromium/components/metal_util/switches.cc
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright 2020 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.
-
-#include "components/metal_util/switches.h"
-
-namespace switches {
-
-const char kDisableMetalTestShaders[] = "disable-metal-test-shaders";
-
-} // namespace switches
diff --git a/chromium/components/metal_util/switches.h b/chromium/components/metal_util/switches.h
deleted file mode 100644
index 58d311a1b63..00000000000
--- a/chromium/components/metal_util/switches.h
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2020 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.
-
-#ifndef COMPONENTS_METAL_UTIL_SWITCHES_H_
-#define COMPONENTS_METAL_UTIL_SWITCHES_H_
-
-#include "components/metal_util/metal_util_export.h"
-
-namespace switches {
-
-METAL_UTIL_EXPORT extern const char kDisableMetalTestShaders[];
-
-} // namespace switches
-
-#endif // COMPONENTS_METAL_UTIL_SWITCHES_H_
diff --git a/chromium/components/metal_util/test_shader.mm b/chromium/components/metal_util/test_shader.mm
index abb8cbab5d2..c83f89533ef 100644
--- a/chromium/components/metal_util/test_shader.mm
+++ b/chromium/components/metal_util/test_shader.mm
@@ -8,7 +8,7 @@
#import <Metal/Metal.h>
#include "base/bind.h"
-#include "base/command_line.h"
+#include "base/feature_list.h"
#include "base/mac/scoped_dispatch_object.h"
#include "base/mac/scoped_nsobject.h"
#include "base/memory/ref_counted.h"
@@ -20,12 +20,14 @@
#include "base/task/thread_pool.h"
#include "components/crash/core/common/crash_key.h"
#include "components/metal_util/device.h"
-#include "components/metal_util/switches.h"
namespace metal {
namespace {
+base::Feature kMetalTestShaders{"MetalTestShaders",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
const char* kTestShaderSource =
""
"#include <metal_stdlib>\n"
@@ -874,10 +876,7 @@ void TestShaderNow(base::scoped_nsprotocol<id<MTLDevice>> device,
void TestShader(TestShaderCallback callback,
const base::TimeDelta& delay,
const base::TimeDelta& timeout) {
- bool disabled_at_command_line =
- base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableMetalTestShaders);
- if (disabled_at_command_line)
+ if (!base::FeatureList::IsEnabled(kMetalTestShaders))
return;
// Select a component to test at random.
diff --git a/chromium/components/metrics/BUILD.gn b/chromium/components/metrics/BUILD.gn
index 8c36b62da86..f523a79eda2 100644
--- a/chromium/components/metrics/BUILD.gn
+++ b/chromium/components/metrics/BUILD.gn
@@ -156,6 +156,8 @@ static_library("metrics") {
if (is_linux || is_chromeos) {
sources += [
"drive_metrics_provider_linux.cc",
+ "psi_memory_parser.h",
+ "psi_memory_parser_linux.cc",
"system_memory_stats_recorder_linux.cc",
]
}
@@ -475,6 +477,7 @@ source_set("unit_tests") {
":test_support",
":ui",
"//base",
+ "//base:base_stack_sampling_profiler_test_util",
"//base/test:test_support",
"//build:chromeos_buildflags",
"//components/component_updater:test_support",
@@ -513,7 +516,10 @@ source_set("unit_tests") {
}
if (is_linux || is_chromeos) {
- sources += [ "serialization/serialization_utils_unittest.cc" ]
+ sources += [
+ "psi_memory_parser_linux_unittest.cc",
+ "serialization/serialization_utils_unittest.cc",
+ ]
deps += [ ":serialization" ]
}
diff --git a/chromium/components/metrics/call_stack_profile_builder.cc b/chromium/components/metrics/call_stack_profile_builder.cc
index 4bfc44e3e46..dd2215834d0 100644
--- a/chromium/components/metrics/call_stack_profile_builder.cc
+++ b/chromium/components/metrics/call_stack_profile_builder.cc
@@ -150,7 +150,7 @@ void CallStackProfileBuilder::OnSampleCompleted(
// Write CallStackProfile::Location protobuf message.
uintptr_t instruction_pointer = frame.instruction_pointer;
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
#if !TARGET_IPHONE_SIMULATOR
// Some iOS devices enable pointer authentication, which uses the
// higher-order bits of pointers to store a signature. Strip that signature
@@ -159,7 +159,7 @@ void CallStackProfileBuilder::OnSampleCompleted(
// available.
instruction_pointer &= 0xFFFFFFFFF;
#endif // !TARGET_IPHONE_SIMULATOR
-#endif // defined(OS_IOS)
+#endif // BUILDFLAG(IS_IOS)
ptrdiff_t module_offset =
reinterpret_cast<const char*>(instruction_pointer) -
diff --git a/chromium/components/metrics/call_stack_profile_builder_unittest.cc b/chromium/components/metrics/call_stack_profile_builder_unittest.cc
index 2b2aefff535..fe564b78a4f 100644
--- a/chromium/components/metrics/call_stack_profile_builder_unittest.cc
+++ b/chromium/components/metrics/call_stack_profile_builder_unittest.cc
@@ -8,6 +8,7 @@
#include "base/files/file_path.h"
#include "base/profiler/module_cache.h"
+#include "base/profiler/stack_sampling_profiler_test_util.h"
#include "base/test/bind.h"
#include "base/test/mock_callback.h"
#include "base/time/time.h"
@@ -20,29 +21,6 @@ namespace metrics {
namespace {
-// Stub module for testing.
-class TestModule : public base::ModuleCache::Module {
- public:
- TestModule(uintptr_t base_address = 0,
- const std::string& id = "",
- const base::FilePath& debug_basename = base::FilePath())
- : base_address_(base_address), id_(id), debug_basename_(debug_basename) {}
-
- TestModule(const TestModule&) = delete;
- TestModule& operator=(const TestModule&) = delete;
-
- uintptr_t GetBaseAddress() const override { return base_address_; }
- std::string GetId() const override { return id_; }
- base::FilePath GetDebugBasename() const override { return debug_basename_; }
- size_t GetSize() const override { return 0; }
- bool IsNative() const override { return true; }
-
- private:
- uintptr_t base_address_;
- std::string id_;
- base::FilePath debug_basename_;
-};
-
constexpr CallStackProfileParams kProfileParams = {
CallStackProfileParams::Process::kBrowser,
CallStackProfileParams::Thread::kMain,
@@ -104,7 +82,7 @@ TEST(CallStackProfileBuilderTest, ProfilingCompleted) {
kProfileParams, nullptr, mock_closure.Get());
base::MetadataRecorder metadata_recorder;
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
uint64_t module_md5 = 0x46C3E4166659AC02ULL;
base::FilePath module_path(L"c:\\some\\path\\to\\chrome.exe");
#else
@@ -113,15 +91,21 @@ TEST(CallStackProfileBuilderTest, ProfilingCompleted) {
#endif
const uintptr_t module_base_address1 = 0x1000;
- TestModule module1(module_base_address1, "1", module_path);
+ base::TestModule module1(module_base_address1);
+ module1.set_id("1");
+ module1.set_debug_basename(module_path);
base::Frame frame1 = {module_base_address1 + 0x10, &module1};
const uintptr_t module_base_address2 = 0x1100;
- TestModule module2(module_base_address2, "2", module_path);
+ base::TestModule module2(module_base_address2);
+ module2.set_id("2");
+ module2.set_debug_basename(module_path);
base::Frame frame2 = {module_base_address2 + 0x10, &module2};
const uintptr_t module_base_address3 = 0x1010;
- TestModule module3(module_base_address3, "3", module_path);
+ base::TestModule module3(module_base_address3);
+ module3.set_id("3");
+ module3.set_debug_basename(module_path);
base::Frame frame3 = {module_base_address3 + 0x10, &module3};
std::vector<base::Frame> frames1 = {frame1, frame2};
@@ -190,7 +174,7 @@ TEST(CallStackProfileBuilderTest, CustomWeightsAndCounts) {
auto profile_builder =
std::make_unique<TestingCallStackProfileBuilder>(kProfileParams);
- TestModule module1;
+ base::TestModule module1;
base::Frame frame1 = {0x10, &module1};
std::vector<base::Frame> frames = {frame1};
@@ -219,10 +203,10 @@ TEST(CallStackProfileBuilderTest, StacksDeduped) {
std::make_unique<TestingCallStackProfileBuilder>(kProfileParams);
base::MetadataRecorder metadata_recorder;
- TestModule module1;
+ base::TestModule module1;
base::Frame frame1 = {0x10, &module1};
- TestModule module2;
+ base::TestModule module2;
base::Frame frame2 = {0x20, &module2};
std::vector<base::Frame> frames = {frame1, frame2};
@@ -260,10 +244,10 @@ TEST(CallStackProfileBuilderTest, StacksNotDeduped) {
std::make_unique<TestingCallStackProfileBuilder>(kProfileParams);
base::MetadataRecorder metadata_recorder;
- TestModule module1;
+ base::TestModule module1;
base::Frame frame1 = {0x10, &module1};
- TestModule module2;
+ base::TestModule module2;
base::Frame frame2 = {0x20, &module2};
std::vector<base::Frame> frames1 = {frame1};
@@ -305,14 +289,16 @@ TEST(CallStackProfileBuilderTest, Modules) {
base::Frame frame1 = {0x1010, nullptr};
const uintptr_t module_base_address2 = 0x1100;
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
uint64_t module_md5 = 0x46C3E4166659AC02ULL;
base::FilePath module_path(L"c:\\some\\path\\to\\chrome.exe");
#else
uint64_t module_md5 = 0x554838A8451AC36CULL;
base::FilePath module_path("/some/path/to/chrome");
#endif
- TestModule module2(module_base_address2, "2", module_path);
+ base::TestModule module2(module_base_address2);
+ module2.set_id("2");
+ module2.set_debug_basename(module_path);
base::Frame frame2 = {module_base_address2 + 0x10, &module2};
std::vector<base::Frame> frames = {frame1, frame2};
@@ -355,7 +341,7 @@ TEST(CallStackProfileBuilderTest, DedupModules) {
const uintptr_t module_base_address = 0x1000;
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
uint64_t module_md5 = 0x46C3E4166659AC02ULL;
base::FilePath module_path(L"c:\\some\\path\\to\\chrome.exe");
#else
@@ -363,7 +349,9 @@ TEST(CallStackProfileBuilderTest, DedupModules) {
base::FilePath module_path("/some/path/to/chrome");
#endif
- TestModule module(module_base_address, "1", module_path);
+ base::TestModule module(module_base_address);
+ module.set_id("1");
+ module.set_debug_basename(module_path);
base::Frame frame1 = {module_base_address + 0x10, &module};
base::Frame frame2 = {module_base_address + 0x20, &module};
@@ -417,7 +405,7 @@ TEST(CallStackProfileBuilderTest, WorkIds) {
kProfileParams, &work_id_recorder);
base::MetadataRecorder metadata_recorder;
- TestModule module;
+ base::TestModule module;
base::Frame frame = {0x10, &module};
// Id 0 means the message loop hasn't been started yet, so the sample should
@@ -464,7 +452,7 @@ TEST(CallStackProfileBuilderTest, ProfileStartTime) {
auto profile_builder =
std::make_unique<TestingCallStackProfileBuilder>(kProfileParams);
- TestModule module;
+ base::TestModule module;
const base::Frame frame = {0x10, &module};
const base::TimeTicks first_sample_time = base::TimeTicks::UnixEpoch();
@@ -484,7 +472,7 @@ TEST(CallStackProfileBuilderTest, RecordMetadata) {
auto profile_builder =
std::make_unique<TestingCallStackProfileBuilder>(kProfileParams, nullptr);
- TestModule module;
+ base::TestModule module;
base::Frame frame = {0x10, &module};
metadata_recorder.Set(100, absl::nullopt, 10);
@@ -520,7 +508,7 @@ TEST(CallStackProfileBuilderTest, ApplyMetadataRetrospectively_Basic) {
auto profile_builder =
std::make_unique<TestingCallStackProfileBuilder>(kProfileParams, nullptr);
- TestModule module;
+ base::TestModule module;
base::Frame frame = {0x10, &module};
base::TimeTicks profile_start_time = base::TimeTicks::UnixEpoch();
base::TimeDelta sample_time_delta = base::Seconds(1);
@@ -585,7 +573,7 @@ TEST(CallStackProfileBuilderTest,
auto profile_builder =
std::make_unique<TestingCallStackProfileBuilder>(kProfileParams, nullptr);
- TestModule module;
+ base::TestModule module;
base::Frame frame = {0x10, &module};
base::TimeTicks profile_start_time = base::TimeTicks::UnixEpoch();
base::TimeDelta sample_time_delta = base::Seconds(1);
diff --git a/chromium/components/metrics/call_stack_profile_metadata_unittest.cc b/chromium/components/metrics/call_stack_profile_metadata_unittest.cc
index 40f85e30b30..f1a04077e32 100644
--- a/chromium/components/metrics/call_stack_profile_metadata_unittest.cc
+++ b/chromium/components/metrics/call_stack_profile_metadata_unittest.cc
@@ -5,6 +5,7 @@
#include "components/metrics/call_stack_profile_metadata.h"
#include <algorithm>
+#include <tuple>
#include <utility>
#include "base/strings/strcat.h"
@@ -142,7 +143,7 @@ TEST(CallStackProfileMetadataTest, MetadataRecorder_RepeatItem) {
metadata_recorder.Set(100, absl::nullopt, 10);
metadata.RecordMetadata(
base::MetadataRecorder::MetadataProvider(&metadata_recorder));
- (void)metadata.CreateSampleMetadata(&name_hashes);
+ std::ignore = metadata.CreateSampleMetadata(&name_hashes);
metadata.RecordMetadata(
base::MetadataRecorder::MetadataProvider(&metadata_recorder));
@@ -163,7 +164,7 @@ TEST(CallStackProfileMetadataTest, MetadataRecorder_RepeatKeyedItem) {
metadata_recorder.Set(100, 50, 10);
metadata.RecordMetadata(
base::MetadataRecorder::MetadataProvider(&metadata_recorder));
- (void)metadata.CreateSampleMetadata(&name_hashes);
+ std::ignore = metadata.CreateSampleMetadata(&name_hashes);
metadata.RecordMetadata(
base::MetadataRecorder::MetadataProvider(&metadata_recorder));
@@ -184,7 +185,7 @@ TEST(CallStackProfileMetadataTest, MetadataRecorder_ModifiedItem) {
metadata_recorder.Set(100, absl::nullopt, 10);
metadata.RecordMetadata(
base::MetadataRecorder::MetadataProvider(&metadata_recorder));
- (void)metadata.CreateSampleMetadata(&name_hashes);
+ std::ignore = metadata.CreateSampleMetadata(&name_hashes);
metadata_recorder.Set(100, absl::nullopt, 11);
metadata.RecordMetadata(
@@ -208,7 +209,7 @@ TEST(CallStackProfileMetadataTest, MetadataRecorder_ModifiedKeyedItem) {
metadata_recorder.Set(100, 50, 10);
metadata.RecordMetadata(
base::MetadataRecorder::MetadataProvider(&metadata_recorder));
- (void)metadata.CreateSampleMetadata(&name_hashes);
+ std::ignore = metadata.CreateSampleMetadata(&name_hashes);
metadata_recorder.Set(100, 50, 11);
metadata.RecordMetadata(
@@ -233,7 +234,7 @@ TEST(CallStackProfileMetadataTest, MetadataRecorder_NewItem) {
metadata_recorder.Set(100, absl::nullopt, 10);
metadata.RecordMetadata(
base::MetadataRecorder::MetadataProvider(&metadata_recorder));
- (void)metadata.CreateSampleMetadata(&name_hashes);
+ std::ignore = metadata.CreateSampleMetadata(&name_hashes);
metadata_recorder.Set(101, absl::nullopt, 11);
metadata.RecordMetadata(
@@ -258,7 +259,7 @@ TEST(CallStackProfileMetadataTest, MetadataRecorder_NewKeyedItem) {
metadata_recorder.Set(100, 50, 10);
metadata.RecordMetadata(
base::MetadataRecorder::MetadataProvider(&metadata_recorder));
- (void)metadata.CreateSampleMetadata(&name_hashes);
+ std::ignore = metadata.CreateSampleMetadata(&name_hashes);
metadata_recorder.Set(101, 50, 11);
metadata.RecordMetadata(
@@ -284,7 +285,7 @@ TEST(CallStackProfileMetadataTest, MetadataRecorder_RemovedItem) {
metadata_recorder.Set(100, absl::nullopt, 10);
metadata.RecordMetadata(
base::MetadataRecorder::MetadataProvider(&metadata_recorder));
- (void)metadata.CreateSampleMetadata(&name_hashes);
+ std::ignore = metadata.CreateSampleMetadata(&name_hashes);
metadata_recorder.Remove(100, absl::nullopt);
metadata.RecordMetadata(
@@ -308,7 +309,7 @@ TEST(CallStackProfileMetadataTest, MetadataRecorder_RemovedKeyedItem) {
metadata_recorder.Set(100, 50, 10);
metadata.RecordMetadata(
base::MetadataRecorder::MetadataProvider(&metadata_recorder));
- (void)metadata.CreateSampleMetadata(&name_hashes);
+ std::ignore = metadata.CreateSampleMetadata(&name_hashes);
metadata_recorder.Remove(100, 50);
metadata.RecordMetadata(
@@ -360,7 +361,7 @@ TEST(CallStackProfileMetadataTest,
metadata_recorder.Set(100, 50, 10);
metadata.RecordMetadata(
base::MetadataRecorder::MetadataProvider(&metadata_recorder));
- (void)metadata.CreateSampleMetadata(&name_hashes);
+ std::ignore = metadata.CreateSampleMetadata(&name_hashes);
metadata_recorder.Remove(100, absl::nullopt);
metadata.RecordMetadata(
diff --git a/chromium/components/metrics/clean_exit_beacon.cc b/chromium/components/metrics/clean_exit_beacon.cc
index 64820d74098..32581d0daa1 100644
--- a/chromium/components/metrics/clean_exit_beacon.cc
+++ b/chromium/components/metrics/clean_exit_beacon.cc
@@ -19,6 +19,7 @@
#include "base/metrics/histogram_macros.h"
#include "base/path_service.h"
#include "base/threading/thread_restrictions.h"
+#include "build/build_config.h"
#include "components/metrics/metrics_pref_names.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
@@ -26,7 +27,7 @@
#include "components/variations/service/variations_safe_mode_constants.h"
#include "components/variations/variations_switches.h"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include <windows.h>
#include "base/strings/string_util_win.h"
#include "base/strings/utf_string_conversions.h"
@@ -42,11 +43,41 @@ using ::variations::kExtendedSafeModeTrial;
using ::variations::kSignalAndWriteViaFileUtilGroup;
using ::variations::prefs::kVariationsCrashStreak;
+const char kMonitoringStageKey[] = "monitoring_stage";
+
// Denotes whether Chrome should perform clean shutdown steps: signaling that
// Chrome is exiting cleanly and then CHECKing that is has shutdown cleanly.
// This may be modified by SkipCleanShutdownStepsForTesting().
bool g_skip_clean_shutdown_steps = false;
+// Records the monitoring stage in which a previous session failed to exit
+// cleanly.
+void RecordMonitoringStage(base::Value* beacon_file_contents) {
+ BeaconMonitoringStage stage;
+ if (beacon_file_contents) {
+ base::Value* beacon_file_stage = beacon_file_contents->FindKeyOfType(
+ kMonitoringStageKey, base::Value::Type::INTEGER);
+ if (beacon_file_stage) {
+ stage = static_cast<BeaconMonitoringStage>(beacon_file_stage->GetInt());
+ } else {
+ // The beacon file of Extended Variations Safe Mode experiment group
+ // clients may not include the monitoring stage as this info was not added
+ // until M100.
+ stage = BeaconMonitoringStage::kMissing;
+ }
+ } else {
+ DCHECK_NE(base::FieldTrialList::FindFullName(kExtendedSafeModeTrial),
+ kSignalAndWriteViaFileUtilGroup);
+ // Clients that are not in the experiment group always emit kStatusQuo.
+ stage = BeaconMonitoringStage::kStatusQuo;
+ }
+ // The metric should not be emitted when Chrome exited cleanly, i.e. when
+ // Chrome was not monitoring for crashes.
+ DCHECK_NE(stage, BeaconMonitoringStage::kNotMonitoring);
+ UMA_STABILITY_HISTOGRAM_ENUMERATION("UMA.CleanExitBeacon.MonitoringStage",
+ stage);
+}
+
// Records the the combined state of two distinct beacons' values in the given
// histogram. One beacon is stored in Local State while the other is stored
// elsewhere (e.g. in platform-specific storage, like the Windows registry, or
@@ -122,6 +153,12 @@ void MaybeIncrementCrashStreak(bool did_previous_session_exit_cleanly,
base::clamp(num_crashes, 0, 100));
}
+// Records |file_state| in a histogram.
+void RecordBeaconFileState(BeaconFileState file_state) {
+ base::UmaHistogramEnumeration(
+ "Variations.ExtendedSafeMode.BeaconFileStateAtStartup", file_state);
+}
+
// Returns the contents of the file at |beacon_file_path| if the following
// conditions are all true. Otherwise, returns nullptr.
//
@@ -130,36 +167,53 @@ void MaybeIncrementCrashStreak(bool did_previous_session_exit_cleanly,
// 3. The file is successfully read.
// 4. The file contents are in the expected format with the expected info.
//
-// The file is not expected to exist for clients that do not belong to the
-// kSignalAndWriteViaFileUtilGroup, but even among clients in that group, there
-// are some edge cases. MaybeGetFileContents() is called before clients are
-// assigned to an Extended Variations Safe Mode experiment group, so a client
-// that is later assigned to the kSignalAndWriteViaFileUtilGroup will not have
-// the file in the first session after updating. It is also possible for a user
-// to delete the file or to reset their variations state with
-// kResetVariationState.
+// The file is not expected to exist for clients that have never been in the
+// Extended Variations Safe Mode experiment group,
+// kSignalAndWriteViaFileUtilGroup. The file may not exist for all experiment
+// group clients because there are some are some edge cases. First,
+// MaybeGetFileContents() is called before clients are assigned to an Extended
+// Variations Safe Mode group, so a client that is later assigned to the
+// experiment group will not have the file in the first session after updating
+// to or installing a Chrome version with the experiment. Second, Android Chrome
+// experiment group clients with repeated background sessions may never write a
+// beacon file. Finally, it is possible for a user to delete the file or to
+// reset their variations state with kResetVariationState.
+//
+// Note that not all beacon files are expected to have a monitoring stage as
+// this info was added in M100.
std::unique_ptr<base::Value> MaybeGetFileContents(
const base::FilePath& beacon_file_path) {
if (beacon_file_path.empty())
return nullptr;
+ int error_code;
JSONFileValueDeserializer deserializer(beacon_file_path);
- std::unique_ptr<base::Value> beacon_file_contents = deserializer.Deserialize(
- /*error_code=*/nullptr, /*error_message=*/nullptr);
-
- bool got_beacon_file_contents =
- beacon_file_contents && beacon_file_contents->is_dict() &&
- beacon_file_contents->FindKeyOfType(kVariationsCrashStreak,
- base::Value::Type::INTEGER) &&
- beacon_file_contents->FindKeyOfType(prefs::kStabilityExitedCleanly,
- base::Value::Type::BOOLEAN);
- base::UmaHistogramBoolean(
- "Variations.ExtendedSafeMode.GotVariationsFileContents",
- got_beacon_file_contents);
-
- if (got_beacon_file_contents)
- return beacon_file_contents;
- return nullptr;
+ std::unique_ptr<base::Value> beacon_file_contents =
+ deserializer.Deserialize(&error_code, /*error_message=*/nullptr);
+
+ if (!beacon_file_contents) {
+ RecordBeaconFileState(BeaconFileState::kNotDeserializable);
+ base::UmaHistogramSparse(
+ "Variations.ExtendedSafeMode.BeaconFileDeserializationError",
+ error_code);
+ return nullptr;
+ }
+ if (!beacon_file_contents->is_dict() || beacon_file_contents->DictEmpty()) {
+ RecordBeaconFileState(BeaconFileState::kMissingDictionary);
+ return nullptr;
+ }
+ if (!beacon_file_contents->FindKeyOfType(kVariationsCrashStreak,
+ base::Value::Type::INTEGER)) {
+ RecordBeaconFileState(BeaconFileState::kMissingCrashStreak);
+ return nullptr;
+ }
+ if (!beacon_file_contents->FindKeyOfType(prefs::kStabilityExitedCleanly,
+ base::Value::Type::BOOLEAN)) {
+ RecordBeaconFileState(BeaconFileState::kMissingBeacon);
+ return nullptr;
+ }
+ RecordBeaconFileState(BeaconFileState::kReadable);
+ return beacon_file_contents;
}
// Returns the channel to use for setting up the Extended Variations Safe Mode
@@ -193,25 +247,19 @@ version_info::Channel GetChannel(version_info::Channel channel) {
return channel;
}
-// Sets up the Extended Variations Safe Mode experiment, which is enabled on
-// only some channels. If assigned to an experiment group, returns the name of
-// the group name, e.g. "Control"; otherwise, returns the empty string.
+// Sets up the Extended Variations Safe Mode experiment, whose groups have
+// channel-specific weights. Returns the name of the client's experiment group
+// name, e.g. "Control".
std::string SetUpExtendedSafeModeTrial(version_info::Channel channel) {
- if (channel != version_info::Channel::UNKNOWN &&
- channel != version_info::Channel::CANARY &&
- channel != version_info::Channel::DEV &&
- channel != version_info::Channel::BETA) {
- return std::string();
- }
-
int default_group;
scoped_refptr<base::FieldTrial> trial(
base::FieldTrialList::FactoryGetFieldTrial(
kExtendedSafeModeTrial, 100, kDefaultGroup,
base::FieldTrial::ONE_TIME_RANDOMIZED, &default_group));
- trial->AppendGroup(kControlGroup, 50);
- trial->AppendGroup(kSignalAndWriteViaFileUtilGroup, 50);
+ int group_probability = channel == version_info::Channel::STABLE ? 1 : 50;
+ trial->AppendGroup(kControlGroup, group_probability);
+ trial->AppendGroup(kSignalAndWriteViaFileUtilGroup, group_probability);
return trial->group_name();
}
@@ -250,13 +298,6 @@ void CleanExitBeacon::Initialize() {
did_previous_session_exit_cleanly_ =
DidPreviousSessionExitCleanly(beacon_file_contents.get());
-#if defined(OS_ANDROID)
- // TODO(crbug/1248239): Use the beacon file, if any, to determine the crash
- // crash once the Extended Variations Safe Mode experiment is fully enabled
- // on Android Chrome.
- beacon_file_contents.reset();
-#endif // defined(OS_ANDROID)
-
MaybeIncrementCrashStreak(did_previous_session_exit_cleanly_,
beacon_file_contents.get(), local_state_);
initialized_ = true;
@@ -270,11 +311,11 @@ bool CleanExitBeacon::DidPreviousSessionExitCleanly(
local_state_->GetBoolean(prefs::kStabilityExitedCleanly));
}
-#if defined(OS_WIN) || defined(OS_IOS)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_IOS)
absl::optional<bool> backup_beacon_value = ExitedCleanly();
RecordBeaconConsistency("UMA.CleanExitBeaconConsistency2",
backup_beacon_value, local_state_beacon_value);
-#endif // defined(OS_WIN) || defined(OS_IOS)
+#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_IOS)
absl::optional<bool> beacon_file_beacon_value;
bool use_beacon_file =
@@ -290,27 +331,24 @@ bool CleanExitBeacon::DidPreviousSessionExitCleanly(
beacon_file_beacon_value, local_state_beacon_value);
}
-#if defined(OS_ANDROID)
- // TODO(crbug/1248239): Fully enable the Extended Variations Safe Mode
- // experiment on Android Chrome by using the beacon file's beacon value for
- // clients in the SignalAndWriteViaFileUtil group.
- return local_state_beacon_value.value_or(true);
-#else
-#if defined(OS_IOS)
+ bool did_previous_session_exit_cleanly =
+ use_beacon_file ? beacon_file_beacon_value.value_or(true)
+ : local_state_beacon_value.value_or(true);
+ if (!did_previous_session_exit_cleanly)
+ RecordMonitoringStage(use_beacon_file ? beacon_file_contents : nullptr);
+
+#if BUILDFLAG(IS_IOS)
// For the time being, this is a no-op to avoid interference with the Extended
// Variations Safe Mode experiment; i.e., ShouldUseUserDefaultsBeacon() always
// returns false.
if (ShouldUseUserDefaultsBeacon())
return backup_beacon_value.value_or(true);
-#endif // defined(OS_IOS)
-
- return use_beacon_file ? beacon_file_beacon_value.value_or(true)
- : local_state_beacon_value.value_or(true);
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_IOS)
+ return did_previous_session_exit_cleanly;
}
void CleanExitBeacon::WriteBeaconValue(bool exited_cleanly,
- bool write_synchronously) {
+ bool is_extended_safe_mode) {
DCHECK(initialized_);
if (g_skip_clean_shutdown_steps)
return;
@@ -320,11 +358,30 @@ void CleanExitBeacon::WriteBeaconValue(bool exited_cleanly,
const std::string group_name =
base::FieldTrialList::FindFullName(kExtendedSafeModeTrial);
- if (write_synchronously) {
+ if (is_extended_safe_mode) {
DCHECK_EQ(group_name, kSignalAndWriteViaFileUtilGroup);
+ DCHECK(!exited_cleanly);
SCOPED_UMA_HISTOGRAM_TIMER_MICROS(
"Variations.ExtendedSafeMode.WritePrefsTime");
- WriteBeaconFile(exited_cleanly);
+ // The beacon value is written to disk synchronously twice during
+ // startup for clients in the Extended Variations Safe Mode experiment
+ // group. The first time is via
+ // VariationsFieldTrialCreator::MaybeExtendVariationsSafeMode(). This is
+ // when Chrome begins monitoring for crashes, i.e. |exited_cleanly| is
+ // false. This is the only point at which (a) the WritePrefsTime metric is
+ // emitted and (b) the kExtended monitoring stage is written.
+ //
+ // Later on in startup, such clients call CleanExitBeacon::WriteBeaconFile()
+ // again with |exited_cleanly| and |is_extended_safe_mode| set to false via
+ // MetricsService::LogNeedForCleanShutdown() for desktop and
+ // MetricsService::OnAppEnterForeground() for mobile, which is the status
+ // quo point at which Chrome monitors for crashes. At this point, a
+ // different monitoring stage is written to the beacon file.
+ //
+ // For Android, note that Chrome does not monitor for crashes in background
+ // sessions. See VariationsFieldTrialCreator::SetUpFieldTrials() and
+ // MetricsService::InitializeMetricsState().
+ WriteBeaconFile(exited_cleanly, BeaconMonitoringStage::kExtended);
} else {
local_state_->SetBoolean(prefs::kStabilityExitedCleanly, exited_cleanly);
local_state_->CommitPendingWrite(); // Schedule a write.
@@ -332,25 +389,33 @@ void CleanExitBeacon::WriteBeaconValue(bool exited_cleanly,
// Clients in this group write to the Variations Safe Mode file whenever
// |kStabilityExitedCleanly| is updated. The file is kept in sync with the
// pref because the file is used in the next session.
- WriteBeaconFile(exited_cleanly);
+ //
+ // If |exited_cleanly| is true, then Chrome is not monitoring for crashes,
+ // so the kNotMonitoringStage is used. Otherwise, kStatusQuo is written
+ // because startup has reached the point at which the status quo
+ // Variations-Safe-Mode-related code begins watching for crashes. See the
+ // comment in the above if block for more details.
+ WriteBeaconFile(exited_cleanly,
+ exited_cleanly ? BeaconMonitoringStage::kNotMonitoring
+ : BeaconMonitoringStage::kStatusQuo);
}
}
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
base::win::RegKey regkey;
if (regkey.Create(HKEY_CURRENT_USER, backup_registry_key_.c_str(),
KEY_ALL_ACCESS) == ERROR_SUCCESS) {
regkey.WriteValue(base::ASCIIToWide(prefs::kStabilityExitedCleanly).c_str(),
exited_cleanly ? 1u : 0u);
}
-#elif defined(OS_IOS)
+#elif BUILDFLAG(IS_IOS)
SetUserDefaultsBeacon(exited_cleanly);
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
}
-#if defined(OS_WIN) || defined(OS_IOS)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_IOS)
absl::optional<bool> CleanExitBeacon::ExitedCleanly() {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
base::win::RegKey regkey;
DWORD value = 0u;
if (regkey.Open(HKEY_CURRENT_USER, backup_registry_key_.c_str(),
@@ -361,14 +426,14 @@ absl::optional<bool> CleanExitBeacon::ExitedCleanly() {
return value ? true : false;
}
return absl::nullopt;
-#endif // defined(OS_WIN)
-#if defined(OS_IOS)
+#endif // BUILDFLAG(IS_WIN)
+#if BUILDFLAG(IS_IOS)
if (HasUserDefaultsBeacon())
return GetUserDefaultsBeacon();
return absl::nullopt;
-#endif // defined(OS_IOS)
+#endif // BUILDFLAG(IS_IOS)
}
-#endif // #if defined(OS_WIN) || defined(OS_IOS)
+#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_IOS)
void CleanExitBeacon::UpdateLastLiveTimestamp() {
local_state_->SetTime(prefs::kStabilityBrowserLastLiveTimeStamp,
@@ -400,18 +465,18 @@ void CleanExitBeacon::SetStabilityExitedCleanlyForTesting(
PrefService* local_state,
bool exited_cleanly) {
local_state->SetBoolean(prefs::kStabilityExitedCleanly, exited_cleanly);
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
SetUserDefaultsBeacon(exited_cleanly);
-#endif // defined(OS_IOS)
+#endif // BUILDFLAG(IS_IOS)
}
// static
void CleanExitBeacon::ResetStabilityExitedCleanlyForTesting(
PrefService* local_state) {
local_state->ClearPref(prefs::kStabilityExitedCleanly);
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
ResetUserDefaultsBeacon();
-#endif // defined(OS_IOS)
+#endif // BUILDFLAG(IS_IOS)
}
// static
@@ -419,23 +484,32 @@ void CleanExitBeacon::SkipCleanShutdownStepsForTesting() {
g_skip_clean_shutdown_steps = true;
}
-void CleanExitBeacon::WriteBeaconFile(bool exited_cleanly) const {
+void CleanExitBeacon::WriteBeaconFile(
+ bool exited_cleanly,
+ BeaconMonitoringStage monitoring_stage) const {
DCHECK_EQ(base::FieldTrialList::FindFullName(kExtendedSafeModeTrial),
kSignalAndWriteViaFileUtilGroup);
base::Value dict(base::Value::Type::DICTIONARY);
dict.SetBoolKey(prefs::kStabilityExitedCleanly, exited_cleanly);
dict.SetIntKey(kVariationsCrashStreak,
local_state_->GetInteger(kVariationsCrashStreak));
+ dict.SetIntKey(kMonitoringStageKey, static_cast<int>(monitoring_stage));
+
std::string json_string;
JSONStringValueSerializer serializer(&json_string);
bool success = serializer.Serialize(dict);
DCHECK(success);
int data_size = static_cast<int>(json_string.size());
DCHECK_NE(data_size, 0);
+ int bytes_written;
{
base::ScopedAllowBlocking allow_io;
- base::WriteFile(beacon_file_path_, json_string.data(), data_size);
+ // WriteFile() returns -1 on error.
+ bytes_written =
+ base::WriteFile(beacon_file_path_, json_string.data(), data_size);
}
+ base::UmaHistogramBoolean("Variations.ExtendedSafeMode.BeaconFileWrite",
+ bytes_written != -1);
}
} // namespace metrics
diff --git a/chromium/components/metrics/clean_exit_beacon.h b/chromium/components/metrics/clean_exit_beacon.h
index b0a5776c048..c3f49037287 100644
--- a/chromium/components/metrics/clean_exit_beacon.h
+++ b/chromium/components/metrics/clean_exit_beacon.h
@@ -22,6 +22,9 @@ namespace metrics {
// Captures all possible beacon value permutations for two distinct beacons.
// Exposed for testing.
+//
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
enum class CleanExitBeaconConsistency {
kCleanClean = 0,
kCleanDirty = 1,
@@ -35,6 +38,39 @@ enum class CleanExitBeaconConsistency {
kMaxValue = kMissingMissing,
};
+// Denotes the state of the beacon file. Exposed for testing.
+//
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
+enum class BeaconFileState {
+ kReadable = 0,
+ kNotDeserializable = 1,
+ kMissingDictionary = 2,
+ kMissingCrashStreak = 3,
+ kMissingBeacon = 4,
+ kMaxValue = kMissingBeacon,
+};
+
+// Denotes whether Chrome is monitoring for browser crashes via the
+// CleanExitBeacon, and if so, whether the monitoring is due to the Extended
+// Variations Safe Mode experiment or the status quo code. Exposed for
+// testing.
+enum class BeaconMonitoringStage {
+ // The beacon file lacks a monitoring stage. This is possible because the
+ // monitoring stage was added in a later milestone. Used by only experiment
+ // group clients.
+ kMissing = 0,
+ // Chrome is not monitoring for crashes.
+ kNotMonitoring = 1,
+ // Chrome is monitoring for crashes earlier on in startup as a result of the
+ // experiment. Used by only experiment group clients.
+ kExtended = 2,
+ // Chrome is monitoring for crashes in the code covered by the status quo
+ // Variations Safe Mode mechanism.
+ kStatusQuo = 3,
+ kMaxValue = kStatusQuo,
+};
+
// Reads and updates a beacon used to detect whether the previous browser
// process exited cleanly.
class CleanExitBeacon {
@@ -79,14 +115,15 @@ class CleanExitBeacon {
}
// Sets the beacon value to |exited_cleanly| and updates the last live
- // timestamp. If |write_synchronously| is true, then the beacon value is
+ // timestamp. If |is_extended_safe_mode| is true, then the beacon value is
// written to disk synchronously. If false, a write is scheduled, and for
// clients in the Extended Variations Safe Mode experiment, a synchronous
// write is done, too.
//
- // Note: |write_synchronously| should be true only for some clients in the
+ // Note: |is_extended_safe_mode| should be true only for some clients in the
// Extended Variations Safe Mode experiment.
- void WriteBeaconValue(bool exited_cleanly, bool write_synchronously = false);
+ void WriteBeaconValue(bool exited_cleanly,
+ bool is_extended_safe_mode = false);
// Updates the last live timestamp.
void UpdateLastLiveTimestamp();
@@ -104,7 +141,7 @@ class CleanExitBeacon {
// CHECKs that Chrome exited cleanly.
static void EnsureCleanShutdown(PrefService* local_state);
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
// Sets the NSUserDefaults beacon value.
static void SetUserDefaultsBeacon(bool exited_cleanly);
@@ -116,7 +153,7 @@ class CleanExitBeacon {
// Syncs feature kUseUserDefaultsForExitedCleanlyBeacon to NSUserDefaults
// kUserDefaultsFeatureFlagForExitedCleanlyBeacon.
static void SyncUseUserDefaultsBeacon();
-#endif // defined(OS_IOS)
+#endif // BUILDFLAG(IS_IOS)
// Prevents a test browser from performing two clean shutdown steps. First, it
// prevents the beacon value from being updated after this function is called.
@@ -128,23 +165,27 @@ class CleanExitBeacon {
// Returns true if the previous session exited cleanly. Either Local State
// or |beacon_file_contents| is used to get this information. Which is used
// depends on the client's Extended Variations Safe Mode experiment group in
- // the previous session.
+ // the previous session. Also, records several metrics.
+ //
+ // Should be called only once: at startup.
+ //
// TODO(crbug/1241702): Update this comment when experimentation is over.
bool DidPreviousSessionExitCleanly(base::Value* beacon_file_contents);
- // Writes |exited_cleanly| and the crash streak to the file located at
- // |beacon_file_path_|.
- void WriteBeaconFile(bool exited_cleanly) const;
+ // Writes |exited_cleanly|, |monitoring_stage|, and the crash streak to the
+ // file located at |beacon_file_path_|.
+ void WriteBeaconFile(bool exited_cleanly,
+ BeaconMonitoringStage monitoring_stage) const;
-#if defined(OS_WIN) || defined(OS_IOS)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_IOS)
// Returns whether Chrome exited cleanly in the previous session according to
// the platform-specific beacon (the registry for Windows or NSUserDefaults
// for iOS). Returns absl::nullopt if the platform-specific location does not
// have beacon info.
absl::optional<bool> ExitedCleanly();
-#endif // defined(OS_WIN) || defined(OS_IOS)
+#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_IOS)
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
// Returns true if the NSUserDefaults beacon value is set.
static bool HasUserDefaultsBeacon();
@@ -153,7 +194,7 @@ class CleanExitBeacon {
// Clears the NSUserDefaults beacon value.
static void ResetUserDefaultsBeacon();
-#endif // defined(OS_IOS)
+#endif // BUILDFLAG(IS_IOS)
// Indicates whether the CleanExitBeacon has been initialized.
bool initialized_ = false;
diff --git a/chromium/components/metrics/clean_exit_beacon_unittest.cc b/chromium/components/metrics/clean_exit_beacon_unittest.cc
index c55dd30cdcb..ceba28d7f6a 100644
--- a/chromium/components/metrics/clean_exit_beacon_unittest.cc
+++ b/chromium/components/metrics/clean_exit_beacon_unittest.cc
@@ -7,6 +7,7 @@
#include <memory>
#include <string>
+#include "base/containers/contains.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
@@ -39,9 +40,26 @@ using ::variations::SetUpExtendedSafeModeExperiment;
const wchar_t kDummyWindowsRegistryKey[] = L"";
// Creates and returns well-formed beacon file contents with the given values.
-std::string CreateWellFormedBeaconFileContents(bool exited_cleanly,
- int crash_streak) {
+std::string CreateWellFormedBeaconFileContents(
+ bool exited_cleanly,
+ int crash_streak,
+ absl::optional<BeaconMonitoringStage> stage = absl::nullopt) {
const std::string exited_cleanly_str = exited_cleanly ? "true" : "false";
+ if (stage) {
+ const std::string stage_str =
+ base::NumberToString(static_cast<int>(stage.value()));
+ return base::StringPrintf(
+ "{\n"
+ " \"monitoring_stage\": %s,\n"
+ " \"user_experience_metrics.stability.exited_cleanly\": %s,\n"
+ " \"variations_crash_streak\": %s\n"
+ "}",
+ stage_str.data(), exited_cleanly_str.data(),
+ base::NumberToString(crash_streak).data());
+ }
+ // The monitoring stage was added to the beacon file in a later milestone,
+ // so beacon files of clients running older Chrome versions may not always
+ // have it.
return base::StringPrintf(
"{\n"
" \"user_experience_metrics.stability.exited_cleanly\": %s,\n"
@@ -56,11 +74,12 @@ class TestCleanExitBeacon : public CleanExitBeacon {
public:
explicit TestCleanExitBeacon(
PrefService* local_state,
- const base::FilePath& user_data_dir = base::FilePath())
+ const base::FilePath& user_data_dir = base::FilePath(),
+ version_info::Channel channel = version_info::Channel::UNKNOWN)
: CleanExitBeacon(kDummyWindowsRegistryKey,
user_data_dir,
local_state,
- version_info::Channel::UNKNOWN) {
+ channel) {
Initialize();
}
@@ -83,13 +102,11 @@ class CleanExitBeaconTest : public ::testing::Test {
base::test::TaskEnvironment task_environment_;
};
-class BeaconFileTest : public testing::WithParamInterface<std::string>,
- public CleanExitBeaconTest {};
-
struct BadBeaconTestParams {
const std::string test_name;
bool beacon_file_exists;
const std::string beacon_file_contents;
+ BeaconFileState beacon_file_state;
};
// Used for testing beacon files that are not well-formed, do not exist, etc.
@@ -109,15 +126,32 @@ struct BeaconConsistencyTestParams {
// Used for testing the logic that emits CleanExitBeaconConsistency to
// histograms.
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
class BackupBeaconConsistencyTest
: public testing::WithParamInterface<BeaconConsistencyTestParams>,
public CleanExitBeaconTest {};
-#endif // defined(OS_IOS)
+#endif // BUILDFLAG(IS_IOS)
+
class BeaconFileConsistencyTest
: public testing::WithParamInterface<BeaconConsistencyTestParams>,
public CleanExitBeaconTest {};
+struct MonitoringStageTestParams {
+ const std::string test_name;
+ const std::string experiment_group;
+ bool exited_cleanly;
+ bool is_extended_safe_mode;
+ absl::optional<BeaconMonitoringStage> stage;
+};
+
+class MonitoringStageMetricTest
+ : public testing::WithParamInterface<MonitoringStageTestParams>,
+ public CleanExitBeaconTest {};
+
+class MonitoringStageWritingTest
+ : public testing::WithParamInterface<MonitoringStageTestParams>,
+ public CleanExitBeaconTest {};
+
// Verify that the crash streak metric is 0 when default pref values are used.
TEST_F(CleanExitBeaconTest, CrashStreakMetricWithDefaultPrefs) {
CleanExitBeacon::ResetStabilityExitedCleanlyForTesting(&prefs_);
@@ -182,7 +216,7 @@ TEST_F(CleanExitBeaconTest, InitWithoutUserDataDir) {
EXPECT_FALSE(
base::FieldTrialList::IsTrialActive(variations::kExtendedSafeModeTrial));
histogram_tester_.ExpectTotalCount(
- "Variations.ExtendedSafeMode.GotVariationsFileContents", 0);
+ "Variations.ExtendedSafeMode.BeaconFileStateAtStartup", 0);
}
// Verify that the beacon file is not read when the client is not in the
@@ -217,41 +251,51 @@ TEST_F(CleanExitBeaconTest, FileIgnoredByControlGroup) {
EXPECT_EQ(prefs_.GetInteger(variations::prefs::kVariationsCrashStreak),
expected_crash_streak);
histogram_tester_.ExpectTotalCount(
- "Variations.ExtendedSafeMode.GotVariationsFileContents", 0);
+ "Variations.ExtendedSafeMode.BeaconFileStateAtStartup", 0);
}
INSTANTIATE_TEST_SUITE_P(
All,
BadBeaconFileTest,
::testing::Values(
- BadBeaconTestParams{.test_name = "NoVariationsFile",
- .beacon_file_exists = false,
- .beacon_file_contents = ""},
- BadBeaconTestParams{.test_name = "EmptyVariationsFile",
- .beacon_file_exists = true,
- .beacon_file_contents = ""},
- BadBeaconTestParams{.test_name = "NotDictionary",
- .beacon_file_exists = true,
- .beacon_file_contents = "{abc123"},
- BadBeaconTestParams{.test_name = "EmptyDictionary",
- .beacon_file_exists = true,
- .beacon_file_contents = "{}"},
+ BadBeaconTestParams{
+ .test_name = "NoVariationsFile",
+ .beacon_file_exists = false,
+ .beacon_file_contents = "",
+ .beacon_file_state = BeaconFileState::kNotDeserializable},
+ BadBeaconTestParams{
+ .test_name = "EmptyVariationsFile",
+ .beacon_file_exists = true,
+ .beacon_file_contents = "",
+ .beacon_file_state = BeaconFileState::kNotDeserializable},
+ BadBeaconTestParams{
+ .test_name = "NotDictionary",
+ .beacon_file_exists = true,
+ .beacon_file_contents = "{abc123",
+ .beacon_file_state = BeaconFileState::kNotDeserializable},
+ BadBeaconTestParams{
+ .test_name = "EmptyDictionary",
+ .beacon_file_exists = true,
+ .beacon_file_contents = "{}",
+ .beacon_file_state = BeaconFileState::kMissingDictionary},
BadBeaconTestParams{
.test_name = "MissingCrashStreak",
.beacon_file_exists = true,
.beacon_file_contents =
- "{\"user_experience_metrics.stability.exited_cleanly\": true}"},
+ "{\"user_experience_metrics.stability.exited_cleanly\": true}",
+ .beacon_file_state = BeaconFileState::kMissingCrashStreak},
BadBeaconTestParams{
.test_name = "MissingBeacon",
.beacon_file_exists = true,
- .beacon_file_contents = "{\"variations_crash_streak\": 1}"}),
+ .beacon_file_contents = "{\"variations_crash_streak\": 1}",
+ .beacon_file_state = BeaconFileState::kMissingBeacon}),
[](const ::testing::TestParamInfo<BadBeaconTestParams>& params) {
return params.param.test_name;
});
// Verify that the inability to get the beacon file's contents for a plethora of
-// reasons (a) doesn't crash and (b) correctly records the
-// GotVariationsFileContents metric.
+// reasons (a) doesn't crash and (b) correctly records the BeaconFileState
+// metric.
TEST_P(BadBeaconFileTest, InitWithUnusableBeaconFile) {
SetUpExtendedSafeModeExperiment(variations::kSignalAndWriteViaFileUtilGroup);
BadBeaconTestParams params = GetParam();
@@ -266,12 +310,10 @@ TEST_P(BadBeaconFileTest, InitWithUnusableBeaconFile) {
TestCleanExitBeacon beacon(&prefs_, user_data_dir_path);
histogram_tester_.ExpectUniqueSample(
- "Variations.ExtendedSafeMode.GotVariationsFileContents", false, 1);
+ "Variations.ExtendedSafeMode.BeaconFileStateAtStartup",
+ params.beacon_file_state, 1);
}
-// TODO(crbug/1248239): Enable these tests on Android when the Extended
-// Variations Safe Mode experiment is fully enabled on Android Chrome.
-#if !defined(OS_ANDROID)
// Verify that successfully reading the beacon file's contents results in
// correctly (a) setting the |did_previous_session_exit_cleanly_| field and (b)
// recording metrics when the last session exited cleanly.
@@ -289,7 +331,8 @@ TEST_F(CleanExitBeaconTest, InitWithBeaconFile) {
TestCleanExitBeacon clean_exit_beacon(&prefs_, user_data_dir_path);
histogram_tester_.ExpectUniqueSample(
- "Variations.ExtendedSafeMode.GotVariationsFileContents", true, 1);
+ "Variations.ExtendedSafeMode.BeaconFileStateAtStartup",
+ BeaconFileState::kReadable, 1);
EXPECT_TRUE(clean_exit_beacon.exited_cleanly());
histogram_tester_.ExpectUniqueSample("Variations.SafeMode.Streak.Crashes",
num_crashes, 1);
@@ -313,12 +356,12 @@ TEST_F(CleanExitBeaconTest, InitWithCrashAndBeaconFile) {
const int updated_num_crashes = last_session_num_crashes + 1;
TestCleanExitBeacon clean_exit_beacon(&prefs_, user_data_dir_path);
histogram_tester_.ExpectUniqueSample(
- "Variations.ExtendedSafeMode.GotVariationsFileContents", true, 1);
+ "Variations.ExtendedSafeMode.BeaconFileStateAtStartup",
+ BeaconFileState::kReadable, 1);
EXPECT_FALSE(clean_exit_beacon.exited_cleanly());
histogram_tester_.ExpectUniqueSample("Variations.SafeMode.Streak.Crashes",
updated_num_crashes, 1);
}
-#endif // !defined(OS_ANDROID)
// The below CleanExitBeaconTest.BeaconState*ExtendedSafeMode tests verify that
// the logic for recording UMA.CleanExitBeacon.BeaconFileConsistency is correct
@@ -403,45 +446,181 @@ TEST_P(BeaconFileConsistencyTest, BeaconConsistency) {
1);
}
-#if defined(OS_ANDROID)
-// TODO(crbug/1248239): Remove this test once the Extended Variations Safe Mode
-// experiment is fully enabled on Android Chrome.
+INSTANTIATE_TEST_SUITE_P(
+ All,
+ MonitoringStageMetricTest,
+ ::testing::Values(
+ // Verify that UMA.CleanExitBeacon.MonitoringStage is not emitted when
+ // Chrome exited cleanly.
+ MonitoringStageTestParams{.test_name = "ControlGroup_CleanExit",
+ .experiment_group = variations::kControlGroup,
+ .exited_cleanly = true,
+ .stage = absl::nullopt},
+ MonitoringStageTestParams{
+ .test_name = "ExperimentGroup_CleanExit",
+ .experiment_group = variations::kSignalAndWriteViaFileUtilGroup,
+ .exited_cleanly = true,
+ .stage = absl::nullopt},
+ // Verify that BeaconMonitoringStage::kMissing is emitted when the
+ // beacon file does not have a monitoring stage. This can happen because
+ // the monitoring stage was added in a later milestone.
+ MonitoringStageTestParams{
+ .test_name = "ExperimentGroup_DirtyExit_Missing",
+ .experiment_group = variations::kSignalAndWriteViaFileUtilGroup,
+ .exited_cleanly = false,
+ .stage = BeaconMonitoringStage::kMissing},
+ // Verify that BeaconMonitoringStage::kExtended is emitted when the
+ // beacon file's monitoring stage indicates that the unclean exit was
+ // detected due to the Extended Variations Safe Mode experiment.
+ MonitoringStageTestParams{
+ .test_name = "ExperimentGroup_DirtyExit_Extended",
+ .experiment_group = variations::kSignalAndWriteViaFileUtilGroup,
+ .exited_cleanly = false,
+ .stage = BeaconMonitoringStage::kExtended},
+ // Verify that BeaconMonitoringStage::kStatusQuo is emitted when the
+ // unclean exit was detected as a result of the status quo monitoring
+ // code.
+ MonitoringStageTestParams{
+ .test_name = "ControlGroup_DirtyExit_StatusQuo",
+ .experiment_group = variations::kControlGroup,
+ .exited_cleanly = false,
+ .stage = BeaconMonitoringStage::kStatusQuo},
+ MonitoringStageTestParams{
+ .test_name = "ExperimentGroup_DirtyExit_StatusQuo",
+ .experiment_group = variations::kControlGroup,
+ .exited_cleanly = false,
+ .stage = BeaconMonitoringStage::kStatusQuo}),
+ [](const ::testing::TestParamInfo<MonitoringStageTestParams>& params) {
+ return params.param.test_name;
+ });
-// Verify that the beacon file, if any, is ignored on Android.
-TEST_F(CleanExitBeaconTest, BeaconFileIgnoredOnAndroid) {
- // Set up the beacon file such that the previous session did not exit cleanly
- // and the running crash streak is 2. The file (and thus these values) are
- // expected to be ignored.
+TEST_P(MonitoringStageMetricTest, CheckMonitoringStageMetric) {
+ MonitoringStageTestParams params = GetParam();
+ SetUpExtendedSafeModeExperiment(params.experiment_group);
+
+ // |crash_streak|'s value is arbitrary and not important. We specify it since
+ // well-formed beacon files include the streak and set it in Local State to be
+ // consistent.
+ const int crash_streak = 1;
+ // Set up Local State prefs. If the control group behavior is under test, then
+ // Local State is used and the beacon file is ignored.
+ CleanExitBeacon::SetStabilityExitedCleanlyForTesting(&prefs_,
+ params.exited_cleanly);
+ prefs_.SetInteger(variations::prefs::kVariationsCrashStreak, crash_streak);
+ // Set up the beacon file. If the experiment group behavior is under test,
+ // then the beacon file is used and Local State is ignored.
const base::FilePath user_data_dir_path = user_data_dir_.GetPath();
const base::FilePath temp_beacon_file_path =
user_data_dir_path.Append(variations::kVariationsFilename);
- const int last_session_num_crashes = 2;
ASSERT_LT(0, base::WriteFile(temp_beacon_file_path,
CreateWellFormedBeaconFileContents(
- /*exited_cleanly=*/false,
- /*crash_streak=*/last_session_num_crashes)
+ /*exited_cleanly=*/params.exited_cleanly,
+ /*crash_streak=*/crash_streak,
+ /*stage=*/params.stage)
.data()));
- // Set up the PrefService such that the previous session exited cleanly and
- // the running crash streak is 0. The PrefService (and thus these values) are
- // expected to be used.
- CleanExitBeacon::SetStabilityExitedCleanlyForTesting(&prefs_, true);
- const int expected_num_crashes = 0;
- prefs_.SetInteger(variations::prefs::kVariationsCrashStreak,
- expected_num_crashes);
+ // Create and initialize the CleanExitBeacon.
+ TestCleanExitBeacon clean_exit_beacon(&prefs_, user_data_dir_path);
+
+ if (params.exited_cleanly) {
+ ASSERT_TRUE(clean_exit_beacon.exited_cleanly());
+ // Verify that the metric is not emitted when Chrome exited cleanly.
+ histogram_tester_.ExpectTotalCount("UMA.CleanExitBeacon.MonitoringStage",
+ 0);
+ } else {
+ ASSERT_FALSE(clean_exit_beacon.exited_cleanly());
+ // Verify that the expected BeaconMonitoringStage is emitted.
+ histogram_tester_.ExpectUniqueSample("UMA.CleanExitBeacon.MonitoringStage",
+ params.stage.value(), 1);
+ }
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ All,
+ MonitoringStageWritingTest,
+ ::testing::Values(
+ // Verify that the beacon file is not written for control group clients.
+ MonitoringStageTestParams{.test_name = "ControlGroup_CleanExit",
+ .experiment_group = variations::kControlGroup,
+ .exited_cleanly = true,
+ .is_extended_safe_mode = false},
+ MonitoringStageTestParams{.test_name = "ControlGroup_DirtyExit",
+ .experiment_group = variations::kControlGroup,
+ .exited_cleanly = false,
+ .is_extended_safe_mode = false},
+ // Verify that signaling that Chrome should stop watching for crashes
+ // for experiment group clients results in a beacon file with the
+ // kNotMonitoring stage.
+ MonitoringStageTestParams{
+ .test_name = "ExperimentGroup_CleanExit_AsynchronousWrite",
+ .experiment_group = variations::kSignalAndWriteViaFileUtilGroup,
+ .exited_cleanly = true,
+ .is_extended_safe_mode = false,
+ .stage = BeaconMonitoringStage::kNotMonitoring},
+ // Verify that signaling that Chrome should watch for crashes with
+ // |is_extended_safe_mode| set to true for experiment group clients
+ // results in a beacon file with the kExtended stage.
+ MonitoringStageTestParams{
+ .test_name = "ExperimentGroup_DirtyExit_SynchronousWrite",
+ .experiment_group = variations::kSignalAndWriteViaFileUtilGroup,
+ .exited_cleanly = false,
+ .is_extended_safe_mode = true,
+ .stage = BeaconMonitoringStage::kExtended},
+ // Verify that signaling that Chrome should watch for crashes with
+ // |is_extended_safe_mode| set to false for experiment group clients
+ // results in a beacon file with the kStatusQuo stage.
+ MonitoringStageTestParams{
+ .test_name = "ExperimentGroup_DirtyExit_AsynchronousWrite",
+ .experiment_group = variations::kSignalAndWriteViaFileUtilGroup,
+ .exited_cleanly = false,
+ .is_extended_safe_mode = false,
+ .stage = BeaconMonitoringStage::kStatusQuo}),
+ [](const ::testing::TestParamInfo<MonitoringStageTestParams>& params) {
+ return params.param.test_name;
+ });
+
+TEST_P(MonitoringStageWritingTest, CheckMonitoringStage) {
+ MonitoringStageTestParams params = GetParam();
+ const std::string group = params.experiment_group;
+ SetUpExtendedSafeModeExperiment(group);
+
+ const base::FilePath user_data_dir_path = user_data_dir_.GetPath();
+ const base::FilePath expected_beacon_file_path =
+ user_data_dir_path.Append(variations::kVariationsFilename);
+ ASSERT_FALSE(base::PathExists(expected_beacon_file_path));
+ // Create and initialize the CleanExitBeacon.
TestCleanExitBeacon clean_exit_beacon(&prefs_, user_data_dir_path);
- // Verify that the Local State beacon was used (not the beacon file beacon).
- EXPECT_TRUE(clean_exit_beacon.exited_cleanly());
- histogram_tester_.ExpectUniqueSample("Variations.SafeMode.Streak.Crashes",
- expected_num_crashes, 1);
+ clean_exit_beacon.WriteBeaconValue(params.exited_cleanly,
+ params.is_extended_safe_mode);
+
+ // Check that experiment group clients have a beacon file and that control
+ // group clients do not.
+ EXPECT_EQ(group == variations::kSignalAndWriteViaFileUtilGroup,
+ base::PathExists(expected_beacon_file_path));
+
+ if (group == variations::kSignalAndWriteViaFileUtilGroup) {
+ // For experiment group clients, check the beacon file contents.
+ std::string beacon_file_contents;
+ ASSERT_TRUE(base::ReadFileToString(expected_beacon_file_path,
+ &beacon_file_contents));
+
+ const std::string expected_stage =
+ "monitoring_stage\":" +
+ base::NumberToString(static_cast<int>(params.stage.value()));
+ const std::string exited_cleanly = params.exited_cleanly ? "true" : "false";
+ const std::string expected_beacon_value =
+ "exited_cleanly\":" + exited_cleanly;
+ EXPECT_TRUE(base::Contains(beacon_file_contents, expected_stage));
+ EXPECT_TRUE(base::Contains(beacon_file_contents, expected_beacon_value));
+ }
}
-#endif // defined(OS_ANDROID)
// Verify that attempting to write synchronously DCHECKs for clients that do not
// belong to the SignalAndWriteViaFileUtil experiment group.
-TEST_F(CleanExitBeaconTest, WriteBeaconValue_SynchronousWriteDcheck) {
+TEST_F(CleanExitBeaconTest,
+ WriteBeaconValue_SynchronousWriteDcheck_ControlGroup) {
SetUpExtendedSafeModeExperiment(variations::kControlGroup);
ASSERT_EQ(variations::kControlGroup, base::FieldTrialList::FindFullName(
variations::kExtendedSafeModeTrial));
@@ -449,14 +628,35 @@ TEST_F(CleanExitBeaconTest, WriteBeaconValue_SynchronousWriteDcheck) {
TestCleanExitBeacon clean_exit_beacon(&prefs_, user_data_dir_.GetPath());
EXPECT_DCHECK_DEATH(
clean_exit_beacon.WriteBeaconValue(/*exited_cleanly=*/false,
- /*write_synchronously=*/true));
+ /*is_extended_safe_mode=*/true));
+
+ // Verify metrics.
histogram_tester_.ExpectTotalCount(
"Variations.ExtendedSafeMode.WritePrefsTime", 0);
+ histogram_tester_.ExpectTotalCount(
+ "Variations.ExtendedSafeMode.BeaconFileWrite", 0);
+}
+
+// Verify that there's a DCHECK when an Extended Variations Safe Mode client
+// attempts to write a clean beacon with |is_extended_safe_mode| set to true.
+// |is_extended_safe_mode| should only be set to true in one call site:
+// VariationsFieldTrialCreator::MaybeExtendVariationsSafeMode().
+TEST_F(CleanExitBeaconTest,
+ WriteBeaconValue_SynchronousWriteDcheck_ExperimentGroup) {
+ SetUpExtendedSafeModeExperiment(variations::kSignalAndWriteViaFileUtilGroup);
+ ASSERT_EQ(
+ variations::kSignalAndWriteViaFileUtilGroup,
+ base::FieldTrialList::FindFullName(variations::kExtendedSafeModeTrial));
+
+ TestCleanExitBeacon clean_exit_beacon(&prefs_, user_data_dir_.GetPath());
+ EXPECT_DCHECK_DEATH(
+ clean_exit_beacon.WriteBeaconValue(/*exited_cleanly=*/true,
+ /*is_extended_safe_mode=*/true));
}
// The below CleanExitBeaconTest.BeaconState_* tests verify that the logic for
// recording UMA.CleanExitBeaconConsistency2 is correct.
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
INSTANTIATE_TEST_SUITE_P(
All,
BackupBeaconConsistencyTest,
@@ -524,6 +724,6 @@ TEST_P(BackupBeaconConsistencyTest, BeaconConsistency) {
histogram_tester_.ExpectUniqueSample("UMA.CleanExitBeaconConsistency2",
params.expected_consistency, 1);
}
-#endif // defined(OS_IOS)
+#endif // BUILDFLAG(IS_IOS)
} // namespace metrics
diff --git a/chromium/components/metrics/content/DEPS b/chromium/components/metrics/content/DEPS
index c8b278323d6..01ec3c78768 100644
--- a/chromium/components/metrics/content/DEPS
+++ b/chromium/components/metrics/content/DEPS
@@ -10,5 +10,9 @@ specific_include_rules = {
"subprocess_metrics_provider_browsertest\.cc": [
"+content/shell/browser/shell.h",
"+net/dns/mock_host_resolver.h",
+ ],
+
+ "content_stability_metrics_provider_browsertest\.cc": [
+ "+sandbox"
]
}
diff --git a/chromium/components/metrics/content/content_stability_metrics_provider.cc b/chromium/components/metrics/content/content_stability_metrics_provider.cc
index f2f4b51cbe3..092ce17c9e4 100644
--- a/chromium/components/metrics/content/content_stability_metrics_provider.cc
+++ b/chromium/components/metrics/content/content_stability_metrics_provider.cc
@@ -5,49 +5,56 @@
#include "components/metrics/content/content_stability_metrics_provider.h"
#include "base/check.h"
+#include "base/containers/cxx20_erase.h"
+#include "base/lazy_instance.h"
#include "base/notreached.h"
#include "build/build_config.h"
#include "components/metrics/content/extensions_helper.h"
#include "content/public/browser/browser_child_process_observer.h"
#include "content/public/browser/child_process_data.h"
#include "content/public/browser/child_process_termination_info.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/browser/notification_types.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/common/process_type.h"
#include "ppapi/buildflags/buildflags.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "components/crash/content/browser/crash_metrics_reporter_android.h"
#endif
namespace metrics {
+namespace {
+
+using content::RenderProcessHost;
+
+base::LazyInstance<std::vector<ContentStabilityMetricsProvider*>>::Leaky
+ g_providers;
+
+} // namespace
ContentStabilityMetricsProvider::ContentStabilityMetricsProvider(
PrefService* local_state,
std::unique_ptr<ExtensionsHelper> extensions_helper)
: helper_(local_state), extensions_helper_(std::move(extensions_helper)) {
BrowserChildProcessObserver::Add(this);
+ g_providers.Get().push_back(this);
- registrar_.Add(this, content::NOTIFICATION_LOAD_START,
- content::NotificationService::AllSources());
- registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
- content::NotificationService::AllSources());
- registrar_.Add(this, content::NOTIFICATION_RENDER_WIDGET_HOST_HANG,
- content::NotificationService::AllSources());
- registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CREATED,
- content::NotificationService::AllSources());
+ // Observe existing render processes. (When a new render process is created,
+ // we will observe it in OnRenderProcessHostCreated.)
+ for (auto it = RenderProcessHost::AllHostsIterator(); !it.IsAtEnd();
+ it.Advance()) {
+ scoped_observations_.AddObservation(it.GetCurrentValue());
+ }
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
auto* crash_manager = crash_reporter::CrashMetricsReporter::GetInstance();
DCHECK(crash_manager);
scoped_observation_.Observe(crash_manager);
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
}
ContentStabilityMetricsProvider::~ContentStabilityMetricsProvider() {
- registrar_.RemoveAll();
BrowserChildProcessObserver::Remove(this);
+ base::Erase(g_providers.Get(), this);
}
void ContentStabilityMetricsProvider::OnRecordingEnabled() {}
@@ -63,62 +70,12 @@ void ContentStabilityMetricsProvider::ClearSavedStabilityMetrics() {
helper_.ClearSavedStabilityMetrics();
}
-void ContentStabilityMetricsProvider::Observe(
- int type,
- const content::NotificationSource& source,
- const content::NotificationDetails& details) {
- switch (type) {
- case content::NOTIFICATION_LOAD_START:
- helper_.LogLoadStarted();
- break;
-
- case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: {
- content::ChildProcessTerminationInfo* process_info =
- content::Details<content::ChildProcessTerminationInfo>(details).ptr();
- bool was_extension_process =
- extensions_helper_ &&
- extensions_helper_->IsExtensionProcess(
- content::Source<content::RenderProcessHost>(source).ptr());
- helper_.LogRendererCrash(was_extension_process, process_info->status,
- process_info->exit_code);
- break;
- }
-
- case content::NOTIFICATION_RENDER_WIDGET_HOST_HANG:
- helper_.LogRendererHang();
- break;
-
- case content::NOTIFICATION_RENDERER_PROCESS_CREATED: {
- bool was_extension_process =
- extensions_helper_ &&
- extensions_helper_->IsExtensionProcess(
- content::Source<content::RenderProcessHost>(source).ptr());
- helper_.LogRendererLaunched(was_extension_process);
- break;
- }
-
- default:
- NOTREACHED();
- break;
- }
-}
-
void ContentStabilityMetricsProvider::BrowserChildProcessCrashed(
const content::ChildProcessData& data,
const content::ChildProcessTerminationInfo& info) {
DCHECK(!data.metrics_name.empty());
-#if BUILDFLAG(ENABLE_PLUGINS)
- // Exclude plugin crashes from the count below because we report them via
- // a separate UMA metric.
- if (data.process_type == content::PROCESS_TYPE_PPAPI_PLUGIN ||
- data.process_type == content::PROCESS_TYPE_PPAPI_BROKER) {
- return;
- }
-#endif
-
if (data.process_type == content::PROCESS_TYPE_UTILITY)
helper_.BrowserUtilityProcessCrashed(data.metrics_name, info.exit_code);
- helper_.BrowserChildProcessCrashed();
}
void ContentStabilityMetricsProvider::BrowserChildProcessLaunchedAndConnected(
@@ -128,7 +85,61 @@ void ContentStabilityMetricsProvider::BrowserChildProcessLaunchedAndConnected(
helper_.BrowserUtilityProcessLaunched(data.metrics_name);
}
-#if defined(OS_ANDROID)
+void ContentStabilityMetricsProvider::BrowserChildProcessLaunchFailed(
+ const content::ChildProcessData& data,
+ const content::ChildProcessTerminationInfo& info) {
+ DCHECK(!data.metrics_name.empty());
+ DCHECK_EQ(info.status, base::TERMINATION_STATUS_LAUNCH_FAILED);
+ if (data.process_type == content::PROCESS_TYPE_UTILITY)
+ helper_.BrowserUtilityProcessLaunchFailed(data.metrics_name, info.exit_code
+#if BUILDFLAG(IS_WIN)
+ ,
+ info.last_error
+#endif
+ );
+}
+
+void ContentStabilityMetricsProvider::OnRenderProcessHostCreated(
+ RenderProcessHost* host) {
+ // Sometimes, the same host will cause multiple notifications in tests so
+ // could possibly do the same in a release build.
+ if (!scoped_observations_.IsObservingSource(host))
+ scoped_observations_.AddObservation(host);
+
+ bool is_extension_process =
+ extensions_helper_ && extensions_helper_->IsExtensionProcess(host);
+ helper_.LogRendererLaunched(is_extension_process);
+}
+
+void ContentStabilityMetricsProvider::RenderProcessExited(
+ RenderProcessHost* host,
+ const content::ChildProcessTerminationInfo& info) {
+ bool was_extension_process =
+ extensions_helper_ && extensions_helper_->IsExtensionProcess(host);
+ helper_.LogRendererCrash(was_extension_process, info.status, info.exit_code);
+}
+
+void ContentStabilityMetricsProvider::RenderProcessHostDestroyed(
+ RenderProcessHost* host) {
+ scoped_observations_.RemoveObservation(host);
+}
+
+void ContentStabilityMetricsProvider::DidStartLoading() {
+ helper_.LogLoadStarted();
+}
+
+void ContentStabilityMetricsProvider::OnRendererUnresponsive() {
+ helper_.LogRendererHang();
+}
+
+void ContentStabilityMetricsProvider::SetupWebContentsObserver(
+ content::WebContents* web_contents) {
+ web_contents->SetUserData(
+ WebContentsObserverImpl::UserDataKey(),
+ base::WrapUnique(new WebContentsObserverImpl(web_contents)));
+}
+
+#if BUILDFLAG(IS_ANDROID)
void ContentStabilityMetricsProvider::OnCrashDumpProcessed(
int rph_id,
const crash_reporter::CrashMetricsReporter::ReportedCrashTypeSet&
@@ -142,6 +153,26 @@ void ContentStabilityMetricsProvider::OnCrashDumpProcessed(
helper_.IncreaseGpuCrashCount();
}
}
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
+
+ContentStabilityMetricsProvider::WebContentsObserverImpl::
+ WebContentsObserverImpl(content::WebContents* web_contents)
+ : content::WebContentsObserver(web_contents),
+ content::WebContentsUserData<WebContentsObserverImpl>(*web_contents) {}
+
+void ContentStabilityMetricsProvider::WebContentsObserverImpl::
+ DidStartLoading() {
+ for (auto* provider : g_providers.Get())
+ provider->DidStartLoading();
+}
+
+void ContentStabilityMetricsProvider::WebContentsObserverImpl::
+ OnRendererUnresponsive(RenderProcessHost* host) {
+ for (auto* provider : g_providers.Get())
+ provider->OnRendererUnresponsive();
+}
+
+WEB_CONTENTS_USER_DATA_KEY_IMPL(
+ ContentStabilityMetricsProvider::WebContentsObserverImpl);
} // namespace metrics
diff --git a/chromium/components/metrics/content/content_stability_metrics_provider.h b/chromium/components/metrics/content/content_stability_metrics_provider.h
index 3710e37e5a5..c58db139e09 100644
--- a/chromium/components/metrics/content/content_stability_metrics_provider.h
+++ b/chromium/components/metrics/content/content_stability_metrics_provider.h
@@ -8,17 +8,21 @@
#include <memory>
#include "base/gtest_prod_util.h"
+#include "base/scoped_multi_source_observation.h"
#include "base/scoped_observation.h"
#include "build/build_config.h"
#include "components/metrics/metrics_provider.h"
#include "components/metrics/stability_metrics_helper.h"
#include "content/public/browser/browser_child_process_observer.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/render_process_host_creation_observer.h"
+#include "content/public/browser/render_process_host_observer.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "content/public/browser/web_contents_user_data.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "components/crash/content/browser/crash_metrics_reporter_android.h"
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
class PrefService;
@@ -31,10 +35,11 @@ class ExtensionsHelper;
class ContentStabilityMetricsProvider
: public MetricsProvider,
public content::BrowserChildProcessObserver,
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
public crash_reporter::CrashMetricsReporter::Observer,
#endif
- public content::NotificationObserver {
+ public content::RenderProcessHostCreationObserver,
+ public content::RenderProcessHostObserver {
public:
// |extensions_helper| is used to determine if a process corresponds to an
// extension and is optional. If an ExtensionsHelper is not supplied it is
@@ -55,6 +60,8 @@ class ContentStabilityMetricsProvider
SystemProfileProto* system_profile_proto) override;
void ClearSavedStabilityMetrics() override;
+ static void SetupWebContentsObserver(content::WebContents* web_contents);
+
private:
FRIEND_TEST_ALL_PREFIXES(ContentStabilityMetricsProviderTest,
BrowserChildProcessObserverGpu);
@@ -65,19 +72,29 @@ class ContentStabilityMetricsProvider
FRIEND_TEST_ALL_PREFIXES(ContentStabilityMetricsProviderTest,
ExtensionsNotificationObserver);
- // content::NotificationObserver:
- void Observe(int type,
- const content::NotificationSource& source,
- const content::NotificationDetails& details) override;
-
// content::BrowserChildProcessObserver:
void BrowserChildProcessCrashed(
const content::ChildProcessData& data,
const content::ChildProcessTerminationInfo& info) override;
void BrowserChildProcessLaunchedAndConnected(
const content::ChildProcessData& data) override;
+ void BrowserChildProcessLaunchFailed(
+ const content::ChildProcessData& data,
+ const content::ChildProcessTerminationInfo& info) override;
+
+ // content::RenderProcessHostCreationObserver:
+ void OnRenderProcessHostCreated(content::RenderProcessHost* host) override;
+
+ // content::RenderProcessHostObserver:
+ void RenderProcessExited(
+ content::RenderProcessHost* host,
+ const content::ChildProcessTerminationInfo& info) override;
+ void RenderProcessHostDestroyed(content::RenderProcessHost* host) override;
-#if defined(OS_ANDROID)
+ void DidStartLoading();
+ void OnRendererUnresponsive();
+
+#if BUILDFLAG(IS_ANDROID)
// crash_reporter::CrashMetricsReporter::Observer:
void OnCrashDumpProcessed(
int rph_id,
@@ -87,14 +104,27 @@ class ContentStabilityMetricsProvider
base::ScopedObservation<crash_reporter::CrashMetricsReporter,
crash_reporter::CrashMetricsReporter::Observer>
scoped_observation_{this};
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
StabilityMetricsHelper helper_;
- // Registrar for receiving stability-related notifications.
- content::NotificationRegistrar registrar_;
-
std::unique_ptr<ExtensionsHelper> extensions_helper_;
+
+ base::ScopedMultiSourceObservation<content::RenderProcessHost,
+ content::RenderProcessHostObserver>
+ scoped_observations_{this};
+
+ class WebContentsObserverImpl
+ : public content::WebContentsObserver,
+ public content::WebContentsUserData<WebContentsObserverImpl> {
+ public:
+ explicit WebContentsObserverImpl(content::WebContents* web_contents);
+
+ void DidStartLoading() override;
+ void OnRendererUnresponsive(content::RenderProcessHost* host) override;
+
+ WEB_CONTENTS_USER_DATA_KEY_DECL();
+ };
};
} // namespace metrics
diff --git a/chromium/components/metrics/content/content_stability_metrics_provider_browsertest.cc b/chromium/components/metrics/content/content_stability_metrics_provider_browsertest.cc
new file mode 100644
index 00000000000..541328f716f
--- /dev/null
+++ b/chromium/components/metrics/content/content_stability_metrics_provider_browsertest.cc
@@ -0,0 +1,124 @@
+// Copyright 2021 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.
+
+#include "components/metrics/content/content_stability_metrics_provider.h"
+
+#include <string>
+
+#include "base/callback.h"
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/metrics/histogram.h"
+#include "base/test/metrics/histogram_tester.h"
+#include "build/build_config.h"
+#include "components/metrics/content/extensions_helper.h"
+#include "components/prefs/testing_pref_service.h"
+#include "components/variations/hashing.h"
+#include "content/public/browser/browser_child_process_observer.h"
+#include "content/public/browser/child_process_data.h"
+#include "content/public/browser/service_process_host.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/test/browser_test.h"
+#include "content/public/test/browser_test_base.h"
+#include "content/public/test/content_browser_test.h"
+#include "content/public/test/content_browser_test_utils.h"
+#include "content/public/test/test_service.mojom.h"
+#include "sandbox/policy/mojom/sandbox.mojom.h"
+
+#if BUILDFLAG(IS_WIN)
+#include <windows.h>
+
+#include "sandbox/win/src/sandbox_types.h"
+#endif
+
+namespace content {
+
+template <>
+sandbox::mojom::Sandbox GetServiceSandboxType<content::mojom::TestService>() {
+ // On Windows, the sandbox does not like having a different binary name
+ // 'non_existent_path' from the browser process, so set no sandbox here.
+#if BUILDFLAG(IS_WIN)
+ return sandbox::mojom::Sandbox::kNoSandbox;
+#else
+ return sandbox::mojom::Sandbox::kService;
+#endif
+}
+
+} // namespace content
+
+namespace metrics {
+
+class ContentStabilityProviderBrowserTest
+ : public content::ContentBrowserTest,
+ content::BrowserChildProcessObserver {
+ public:
+ // Either the process launched, or did not launch. Both cause the run_loop to
+ // terminate.
+ void BrowserChildProcessLaunchFailed(
+ const content::ChildProcessData& data,
+ const content::ChildProcessTerminationInfo& info) override {
+ if (data.metrics_name == content::mojom::TestService::Name_)
+ std::move(done_closure_).Run();
+ }
+
+ void BrowserChildProcessLaunchedAndConnected(
+ const content::ChildProcessData& data) override {
+ if (data.metrics_name == content::mojom::TestService::Name_)
+ std::move(done_closure_).Run();
+ }
+
+ protected:
+ void AddObserver() { content::BrowserChildProcessObserver::Add(this); }
+
+ void RemoveObserver() { content::BrowserChildProcessObserver::Remove(this); }
+
+ base::OnceClosure done_closure_;
+ TestingPrefServiceSimple prefs_;
+};
+
+IN_PROC_BROWSER_TEST_F(ContentStabilityProviderBrowserTest,
+ FailedUtilityProcessLaunches) {
+ base::RunLoop run_loop;
+ done_closure_ = run_loop.QuitClosure();
+ AddObserver();
+
+ ContentStabilityMetricsProvider provider(&prefs_, nullptr);
+ base::HistogramTester histogram_tester;
+
+ // Simulate a catastrophic utility process launch failure by specifying a bad
+ // path.
+ base::CommandLine::ForCurrentProcess()->AppendSwitchPath(
+ switches::kBrowserSubprocessPath,
+ base::FilePath(FILE_PATH_LITERAL("non_existent_path")));
+ mojo::Remote<content::mojom::TestService> test_service;
+ content::ServiceProcessHost::Launch(
+ test_service.BindNewPipeAndPassReceiver());
+
+ // run_loop runs until either the process launches or fails to launch.
+ run_loop.Run();
+
+ RemoveObserver();
+
+ histogram_tester.ExpectUniqueSample(
+ "ChildProcess.LaunchFailed.UtilityProcessHash",
+ variations::HashName(content::mojom::TestService::Name_), 1);
+#if BUILDFLAG(IS_WIN)
+ int expected_error_code =
+ sandbox::SBOX_ERROR_CANNOT_LAUNCH_UNSANDBOXED_PROCESS;
+#else
+ int expected_error_code =
+ 1003; // content::LaunchResultCode::LAUNCH_RESULT_FAILURE.
+#endif
+ histogram_tester.ExpectUniqueSample(
+ "ChildProcess.LaunchFailed.UtilityProcessErrorCode", expected_error_code,
+ 1);
+
+#if BUILDFLAG(IS_WIN)
+ // Last Error is only recorded on Windows.
+ histogram_tester.ExpectUniqueSample("ChildProcess.LaunchFailed.WinLastError",
+ DWORD{ERROR_FILE_NOT_FOUND}, 1);
+#endif
+}
+
+} // namespace metrics
diff --git a/chromium/components/metrics/content/content_stability_metrics_provider_unittest.cc b/chromium/components/metrics/content/content_stability_metrics_provider_unittest.cc
index d8671c38c15..9d04a65c3ec 100644
--- a/chromium/components/metrics/content/content_stability_metrics_provider_unittest.cc
+++ b/chromium/components/metrics/content/content_stability_metrics_provider_unittest.cc
@@ -31,7 +31,6 @@ namespace metrics {
namespace {
-const char kTestGpuProcessName[] = "content_gpu";
const char kTestUtilityProcessName[] = "test_utility_process";
class MockExtensionsHelper : public ExtensionsHelper {
@@ -73,38 +72,6 @@ class ContentStabilityMetricsProviderTest : public testing::Test {
content::BrowserTaskEnvironment task_environment_;
};
-TEST_F(ContentStabilityMetricsProviderTest, BrowserChildProcessObserverGpu) {
- base::HistogramTester histogram_tester;
- metrics::ContentStabilityMetricsProvider provider(prefs(), nullptr);
-
- content::ChildProcessData child_process_data(content::PROCESS_TYPE_GPU);
- child_process_data.metrics_name = kTestGpuProcessName;
-
- provider.BrowserChildProcessLaunchedAndConnected(child_process_data);
- content::ChildProcessTerminationInfo abnormal_termination_info;
- abnormal_termination_info.status =
- base::TERMINATION_STATUS_ABNORMAL_TERMINATION;
- abnormal_termination_info.exit_code = 1;
- provider.BrowserChildProcessCrashed(child_process_data,
- abnormal_termination_info);
- provider.BrowserChildProcessCrashed(child_process_data,
- abnormal_termination_info);
-
- // Call ProvideStabilityMetrics to check that it will force pending tasks to
- // be executed immediately.
- metrics::SystemProfileProto system_profile;
-
- provider.ProvideStabilityMetrics(&system_profile);
-
- // Check current number of instances created.
- const metrics::SystemProfileProto_Stability& stability =
- system_profile.stability();
-
- EXPECT_EQ(2, stability.child_process_crash_count());
- EXPECT_TRUE(
- histogram_tester.GetTotalCountsForPrefix("ChildProcess.").empty());
-}
-
TEST_F(ContentStabilityMetricsProviderTest,
BrowserChildProcessObserverUtility) {
base::HistogramTester histogram_tester;
@@ -124,28 +91,19 @@ TEST_F(ContentStabilityMetricsProviderTest,
provider.BrowserChildProcessCrashed(child_process_data,
abnormal_termination_info);
- // Call ProvideStabilityMetrics to check that it will force pending tasks to
- // be executed immediately.
- metrics::SystemProfileProto system_profile;
-
- provider.ProvideStabilityMetrics(&system_profile);
-
- // Check current number of instances created.
- const metrics::SystemProfileProto_Stability& stability =
- system_profile.stability();
-
- EXPECT_EQ(2, stability.child_process_crash_count());
-
- // Utility processes also log an entries for the hashed name of the process
- // for launches and crashes.
+ // Verify metrics.
histogram_tester.ExpectUniqueSample(
"ChildProcess.Launched.UtilityProcessHash",
variations::HashName(kTestUtilityProcessName), 1);
+ histogram_tester.ExpectBucketCount("Stability.Counts2",
+ StabilityEventType::kUtilityLaunch, 1);
histogram_tester.ExpectUniqueSample(
"ChildProcess.Crashed.UtilityProcessHash",
variations::HashName(kTestUtilityProcessName), 2);
histogram_tester.ExpectUniqueSample(
"ChildProcess.Crashed.UtilityProcessExitCode", kExitCode, 2);
+ histogram_tester.ExpectBucketCount("Stability.Counts2",
+ StabilityEventType::kUtilityCrash, 2);
}
TEST_F(ContentStabilityMetricsProviderTest, NotificationObserver) {
@@ -163,36 +121,24 @@ TEST_F(ContentStabilityMetricsProviderTest, NotificationObserver) {
content::ChildProcessTerminationInfo crash_details;
crash_details.status = base::TERMINATION_STATUS_PROCESS_CRASHED;
crash_details.exit_code = 1;
- provider.Observe(
- content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
- content::Source<content::RenderProcessHost>(host),
- content::Details<content::ChildProcessTerminationInfo>(&crash_details));
+ provider.RenderProcessExited(host, crash_details);
content::ChildProcessTerminationInfo term_details;
term_details.status = base::TERMINATION_STATUS_ABNORMAL_TERMINATION;
term_details.exit_code = 1;
- provider.Observe(
- content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
- content::Source<content::RenderProcessHost>(host),
- content::Details<content::ChildProcessTerminationInfo>(&term_details));
+ provider.RenderProcessExited(host, term_details);
// Kill does not increment renderer crash count.
content::ChildProcessTerminationInfo kill_details;
kill_details.status = base::TERMINATION_STATUS_PROCESS_WAS_KILLED;
kill_details.exit_code = 1;
- provider.Observe(
- content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
- content::Source<content::RenderProcessHost>(host),
- content::Details<content::ChildProcessTerminationInfo>(&kill_details));
+ provider.RenderProcessExited(host, kill_details);
// Failed launch increments failed launch count.
content::ChildProcessTerminationInfo failed_launch_details;
failed_launch_details.status = base::TERMINATION_STATUS_LAUNCH_FAILED;
failed_launch_details.exit_code = 1;
- provider.Observe(content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
- content::Source<content::RenderProcessHost>(host),
- content::Details<content::ChildProcessTerminationInfo>(
- &failed_launch_details));
+ provider.RenderProcessExited(host, failed_launch_details);
metrics::SystemProfileProto system_profile;
@@ -229,19 +175,13 @@ TEST_F(ContentStabilityMetricsProviderTest, ExtensionsNotificationObserver) {
content::ChildProcessTerminationInfo crash_details;
crash_details.status = base::TERMINATION_STATUS_PROCESS_CRASHED;
crash_details.exit_code = 1;
- provider.Observe(
- content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
- content::Source<content::RenderProcessHost>(extension_host),
- content::Details<content::ChildProcessTerminationInfo>(&crash_details));
+ provider.RenderProcessExited(extension_host, crash_details);
// Failed launch increments failed launch count.
content::ChildProcessTerminationInfo failed_launch_details;
failed_launch_details.status = base::TERMINATION_STATUS_LAUNCH_FAILED;
failed_launch_details.exit_code = 1;
- provider.Observe(content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
- content::Source<content::RenderProcessHost>(extension_host),
- content::Details<content::ChildProcessTerminationInfo>(
- &failed_launch_details));
+ provider.RenderProcessExited(extension_host, failed_launch_details);
metrics::SystemProfileProto system_profile;
provider.ProvideStabilityMetrics(&system_profile);
diff --git a/chromium/components/metrics/data_use_tracker.cc b/chromium/components/metrics/data_use_tracker.cc
index dcedc8f3392..49fbf8a8d10 100644
--- a/chromium/components/metrics/data_use_tracker.cc
+++ b/chromium/components/metrics/data_use_tracker.cc
@@ -38,7 +38,7 @@ std::unique_ptr<DataUseTracker> DataUseTracker::Create(
std::unique_ptr<DataUseTracker> data_use_tracker;
// Instantiate DataUseTracker only on Android. UpdateMetricsUsagePrefs() honors
// this rule too.
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
data_use_tracker = std::make_unique<DataUseTracker>(local_state);
#endif
return data_use_tracker;
@@ -56,11 +56,11 @@ void DataUseTracker::UpdateMetricsUsagePrefs(int message_size,
bool is_metrics_service_usage,
PrefService* local_state) {
// Instantiate DataUseTracker only on Android. Create() honors this rule too.
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
metrics::DataUseTracker tracker(local_state);
tracker.UpdateMetricsUsagePrefsInternal(message_size, is_cellular,
is_metrics_service_usage);
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
}
void DataUseTracker::UpdateMetricsUsagePrefsInternal(
@@ -113,10 +113,9 @@ void DataUseTracker::UpdateUsagePref(const std::string& pref_name,
DictionaryPrefUpdate pref_updater(local_state_, pref_name);
std::string todays_key = GetCurrentMeasurementDateAsString();
- const base::DictionaryValue* user_pref_dict =
- local_state_->GetDictionary(pref_name);
+ const base::Value* user_pref_dict = local_state_->GetDictionary(pref_name);
int todays_traffic = user_pref_dict->FindIntKey(todays_key).value_or(0);
- pref_updater->SetInteger(todays_key, todays_traffic + message_size);
+ pref_updater->SetIntKey(todays_key, todays_traffic + message_size);
}
void DataUseTracker::RemoveExpiredEntries() {
@@ -128,18 +127,16 @@ void DataUseTracker::RemoveExpiredEntries() {
void DataUseTracker::RemoveExpiredEntriesForPref(const std::string& pref_name) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- const base::DictionaryValue* user_pref_dict =
- local_state_->GetDictionary(pref_name);
+ const base::Value* user_pref_dict = local_state_->GetDictionary(pref_name);
const base::Time current_date = GetCurrentMeasurementDate();
const base::Time week_ago = current_date - base::Days(7);
- base::DictionaryValue user_pref_new_dict;
- for (base::DictionaryValue::Iterator it(*user_pref_dict); !it.IsAtEnd();
- it.Advance()) {
+ base::Value user_pref_new_dict{base::Value::Type::DICTIONARY};
+ for (const auto it : user_pref_dict->DictItems()) {
base::Time key_date;
- if (base::Time::FromUTCString(it.key().c_str(), &key_date) &&
+ if (base::Time::FromUTCString(it.first.c_str(), &key_date) &&
key_date > week_ago)
- user_pref_new_dict.SetPath(it.key(), it.value().Clone());
+ user_pref_new_dict.SetPath(it.first, it.second.Clone());
}
local_state_->Set(pref_name, user_pref_new_dict);
}
@@ -152,11 +149,9 @@ int DataUseTracker::ComputeTotalDataUse(const std::string& pref_name) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
int total_data_use = 0;
- const base::DictionaryValue* pref_dict =
- local_state_->GetDictionary(pref_name);
- for (base::DictionaryValue::Iterator it(*pref_dict); !it.IsAtEnd();
- it.Advance()) {
- total_data_use += it.value().GetIfInt().value_or(0);
+ const base::Value* pref_dict = local_state_->GetDictionary(pref_name);
+ for (const auto it : pref_dict->DictItems()) {
+ total_data_use += it.second.GetIfInt().value_or(0);
}
return total_data_use;
}
diff --git a/chromium/components/metrics/demographics/user_demographics.cc b/chromium/components/metrics/demographics/user_demographics.cc
index 2d6490f1a38..581c0752298 100644
--- a/chromium/components/metrics/demographics/user_demographics.cc
+++ b/chromium/components/metrics/demographics/user_demographics.cc
@@ -101,8 +101,7 @@ bool HasEligibleBirthYear(base::Time now, int user_birth_year, int offset) {
// Gets the synced user's birth year from synced prefs, see doc of
// DemographicMetricsProvider in demographic_metrics_provider.h for more
// details.
-absl::optional<int> GetUserBirthYear(
- const base::DictionaryValue* demographics) {
+absl::optional<int> GetUserBirthYear(const base::Value* demographics) {
const base::Value* value =
demographics->FindPath(kSyncDemographicsBirthYearPath);
int birth_year = (value != nullptr && value->is_int())
@@ -120,7 +119,7 @@ absl::optional<int> GetUserBirthYear(
// DemographicMetricsProvider in demographic_metrics_provider.h for more
// details.
absl::optional<UserDemographicsProto_Gender> GetUserGender(
- const base::DictionaryValue* demographics) {
+ const base::Value* demographics) {
const base::Value* value =
demographics->FindPath(kSyncDemographicsGenderPath);
int gender_int = (value != nullptr && value->is_int())
@@ -216,7 +215,7 @@ UserDemographicsResult GetUserNoisedBirthYearAndGenderFromPrefs(
// user_demographics.h for more details.
// Get the pref that contains the user's birth year and gender.
- const base::DictionaryValue* demographics =
+ const base::Value* demographics =
pref_service->GetDictionary(kSyncDemographicsPrefName);
DCHECK(demographics != nullptr);
diff --git a/chromium/components/metrics/drive_metrics_provider_win.cc b/chromium/components/metrics/drive_metrics_provider_win.cc
index 9e3a3f84781..12b354b57eb 100644
--- a/chromium/components/metrics/drive_metrics_provider_win.cc
+++ b/chromium/components/metrics/drive_metrics_provider_win.cc
@@ -16,8 +16,7 @@ namespace metrics {
// static
bool DriveMetricsProvider::HasSeekPenalty(const base::FilePath& path,
bool* has_seek_penalty) {
- std::vector<base::FilePath::StringType> components;
- path.GetComponents(&components);
+ std::vector<base::FilePath::StringType> components = path.GetComponents();
base::File volume(base::FilePath(L"\\\\.\\" + components[0]),
base::File::FLAG_OPEN);
diff --git a/chromium/components/metrics/field_trials_provider_unittest.cc b/chromium/components/metrics/field_trials_provider_unittest.cc
index 0c5bab7ab89..00b2a1ecfe0 100644
--- a/chromium/components/metrics/field_trials_provider_unittest.cc
+++ b/chromium/components/metrics/field_trials_provider_unittest.cc
@@ -8,6 +8,7 @@
#include "base/threading/platform_thread.h"
#include "components/variations/active_field_trials.h"
#include "components/variations/synthetic_trial_registry.h"
+#include "components/variations/synthetic_trials.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/metrics_proto/system_profile.pb.h"
@@ -61,13 +62,15 @@ class FieldTrialsProviderTest : public ::testing::Test {
// Register trials which should get recorded.
void RegisterExpectedSyntheticTrials() {
for (const ActiveGroupId& id : kSyntheticTrialIds) {
- registry_.RegisterSyntheticFieldTrial(
- SyntheticTrialGroup(id.name, id.group));
+ registry_.RegisterSyntheticFieldTrial(SyntheticTrialGroup(
+ id.name, id.group,
+ variations::SyntheticTrialAnnotationMode::kNextLog));
}
}
// Register trial which shouldn't get recorded.
void RegisterExtraSyntheticTrial() {
- registry_.RegisterSyntheticFieldTrial(SyntheticTrialGroup(100, 1000));
+ registry_.RegisterSyntheticFieldTrial(SyntheticTrialGroup(
+ 100, 1000, variations::SyntheticTrialAnnotationMode::kNextLog));
}
// Waits until base::TimeTicks::Now() no longer equals |value|. This should
diff --git a/chromium/components/metrics/file_metrics_provider.cc b/chromium/components/metrics/file_metrics_provider.cc
index b658066db3d..0112c8ce534 100644
--- a/chromium/components/metrics/file_metrics_provider.cc
+++ b/chromium/components/metrics/file_metrics_provider.cc
@@ -125,7 +125,7 @@ struct FileMetricsProvider::SourceInfo {
switch (type) {
case SOURCE_HISTOGRAMS_ACTIVE_FILE:
DCHECK(prefs_key.empty());
- FALLTHROUGH;
+ [[fallthrough]];
case SOURCE_HISTOGRAMS_ATOMIC_FILE:
path = params.path;
break;
@@ -926,10 +926,10 @@ bool FileMetricsProvider::SimulateIndependentMetrics() {
ListPrefUpdate list_value(pref_service_,
metrics::prefs::kMetricsFileMetricsMetadata);
- if (list_value->GetList().empty())
+ if (list_value->GetListDeprecated().empty())
return false;
- base::Value::ListView mutable_list = list_value->GetList();
+ base::Value::ListView mutable_list = list_value->GetListDeprecated();
size_t count = pref_service_->GetInteger(
metrics::prefs::kStabilityFileMetricsUnsentSamplesCount);
pref_service_->SetInteger(
@@ -937,7 +937,7 @@ bool FileMetricsProvider::SimulateIndependentMetrics() {
mutable_list[0].GetInt() + count);
pref_service_->SetInteger(
metrics::prefs::kStabilityFileMetricsUnsentFilesCount,
- list_value->GetList().size() - 1);
+ list_value->GetListDeprecated().size() - 1);
list_value->EraseListIter(mutable_list.begin());
return true;
diff --git a/chromium/components/metrics/file_metrics_provider.h b/chromium/components/metrics/file_metrics_provider.h
index 73e5d2bcbb5..6e4aa5163a7 100644
--- a/chromium/components/metrics/file_metrics_provider.h
+++ b/chromium/components/metrics/file_metrics_provider.h
@@ -70,7 +70,6 @@ class FileMetricsProvider : public MetricsProvider,
// inactive for any period of time only to be opened again and have new
// data written to them. The file should probably never be deleted because
// there would be no guarantee that the data has been reported.
- // TODO(bcwhite): Enable when read/write mem-mapped files are supported.
SOURCE_HISTOGRAMS_ACTIVE_FILE,
};
diff --git a/chromium/components/metrics/generate_expired_histograms_array.gni b/chromium/components/metrics/generate_expired_histograms_array.gni
index 7be1c08b9d1..f3baf3a27fb 100644
--- a/chromium/components/metrics/generate_expired_histograms_array.gni
+++ b/chromium/components/metrics/generate_expired_histograms_array.gni
@@ -34,6 +34,7 @@ template("generate_expired_histograms_array") {
inputs = [
"//tools/metrics/histograms/histograms.xml",
"//tools/metrics/histograms/metadata/accessibility/histograms.xml",
+ "//tools/metrics/histograms/metadata/account_manager/histograms.xml",
"//tools/metrics/histograms/metadata/android/histograms.xml",
"//tools/metrics/histograms/metadata/apps/histograms.xml",
"//tools/metrics/histograms/metadata/arc/histograms.xml",
@@ -45,12 +46,13 @@ template("generate_expired_histograms_array") {
"//tools/metrics/histograms/metadata/background/histograms.xml",
"//tools/metrics/histograms/metadata/blink/histograms.xml",
"//tools/metrics/histograms/metadata/bluetooth/histograms.xml",
+ "//tools/metrics/histograms/metadata/bookmarks/histograms.xml",
"//tools/metrics/histograms/metadata/borealis/histograms.xml",
"//tools/metrics/histograms/metadata/browser/histograms.xml",
"//tools/metrics/histograms/metadata/chrome/histograms.xml",
"//tools/metrics/histograms/metadata/chromeos/histograms.xml",
"//tools/metrics/histograms/metadata/chromeos_hps/histograms.xml",
- "//tools/metrics/histograms/metadata/cloud/histograms.xml",
+ "//tools/metrics/histograms/metadata/chromeos_settings/histograms.xml",
"//tools/metrics/histograms/metadata/commerce/histograms.xml",
"//tools/metrics/histograms/metadata/compositing/histograms.xml",
"//tools/metrics/histograms/metadata/content/histograms.xml",
@@ -71,8 +73,8 @@ template("generate_expired_histograms_array") {
"//tools/metrics/histograms/metadata/download/histograms.xml",
"//tools/metrics/histograms/metadata/enterprise/histograms.xml",
"//tools/metrics/histograms/metadata/event/histograms.xml",
- "//tools/metrics/histograms/metadata/extension/histograms.xml",
"//tools/metrics/histograms/metadata/extensions/histograms.xml",
+ "//tools/metrics/histograms/metadata/families/histograms.xml",
"//tools/metrics/histograms/metadata/feature_engagement/histograms.xml",
"//tools/metrics/histograms/metadata/file/histograms.xml",
"//tools/metrics/histograms/metadata/fingerprint/histograms.xml",
@@ -123,6 +125,7 @@ template("generate_expired_histograms_array") {
"//tools/metrics/histograms/metadata/prefetch/histograms.xml",
"//tools/metrics/histograms/metadata/print/histograms.xml",
"//tools/metrics/histograms/metadata/printing/histograms.xml",
+ "//tools/metrics/histograms/metadata/privacy_budget/histograms.xml",
"//tools/metrics/histograms/metadata/profile/histograms.xml",
"//tools/metrics/histograms/metadata/quickoffice/histograms.xml",
"//tools/metrics/histograms/metadata/quota/histograms.xml",
diff --git a/chromium/components/metrics/machine_id_provider_nonwin_unittest.cc b/chromium/components/metrics/machine_id_provider_nonwin_unittest.cc
index c815f661231..1b8a31ae03e 100644
--- a/chromium/components/metrics/machine_id_provider_nonwin_unittest.cc
+++ b/chromium/components/metrics/machine_id_provider_nonwin_unittest.cc
@@ -13,7 +13,7 @@ namespace metrics {
TEST(MachineIdProviderNonWinTest, GetId) {
const bool has_machine_name = !base::SysInfo::HardwareModelName().empty();
-#if defined(OS_ANDROID) || defined(OS_APPLE)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_APPLE)
DCHECK(has_machine_name);
#endif
diff --git a/chromium/components/metrics/machine_id_provider_win.cc b/chromium/components/metrics/machine_id_provider_win.cc
index 31fe9b46f1f..028b882afc2 100644
--- a/chromium/components/metrics/machine_id_provider_win.cc
+++ b/chromium/components/metrics/machine_id_provider_win.cc
@@ -38,8 +38,8 @@ std::string MachineIdProvider::GetMachineId() {
return std::string();
}
- std::vector<base::FilePath::StringType> path_components;
- executable_path.GetComponents(&path_components);
+ std::vector<base::FilePath::StringType> path_components =
+ executable_path.GetComponents();
if (path_components.empty()) {
NOTREACHED();
return std::string();
diff --git a/chromium/components/metrics/metrics_data_validation.h b/chromium/components/metrics/metrics_data_validation.h
index 5988a26a1fe..6ac4e2ff599 100644
--- a/chromium/components/metrics/metrics_data_validation.h
+++ b/chromium/components/metrics/metrics_data_validation.h
@@ -7,6 +7,7 @@
#include "base/base_export.h"
#include "base/feature_list.h"
+#include "base/metrics/field_trial_params.h"
#include "base/time/time.h"
// Features and functions in this file are necessary to set up artificial A / B
diff --git a/chromium/components/metrics/metrics_log.cc b/chromium/components/metrics/metrics_log.cc
index ebbd596e3a4..34793c7a9be 100644
--- a/chromium/components/metrics/metrics_log.cc
+++ b/chromium/components/metrics/metrics_log.cc
@@ -44,11 +44,11 @@
#include "third_party/metrics_proto/system_profile.pb.h"
#include "third_party/metrics_proto/user_action_event.pb.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "base/android/build_info.h"
#endif
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include <windows.h>
#include "base/win/current_module.h"
#endif
@@ -313,7 +313,7 @@ void MetricsLog::RecordCoreSystemProfile(
if (!app_os_arch.empty())
hardware->set_app_cpu_architecture(app_os_arch);
hardware->set_system_ram_mb(base::SysInfo::AmountOfPhysicalMemoryMB());
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
// Remove any trailing null characters.
// TODO(crbug/1247379): Verify that this is WAI. If so, inline this into
// iOS's implementation of HardwareModelName().
@@ -322,8 +322,8 @@ void MetricsLog::RecordCoreSystemProfile(
hardware_class.substr(0, strlen(hardware_class.c_str())));
#else
hardware->set_hardware_class(base::SysInfo::HardwareModelName());
-#endif // defined(OS_IOS)
-#if defined(OS_WIN)
+#endif // BUILDFLAG(IS_IOS)
+#if BUILDFLAG(IS_WIN)
hardware->set_dll_base(reinterpret_cast<uint64_t>(CURRENT_MODULE()));
#endif
@@ -343,20 +343,20 @@ void MetricsLog::RecordCoreSystemProfile(
// OperatingSystemVersion refers to the ChromeOS release version.
#if BUILDFLAG(IS_CHROMEOS_ASH)
os->set_kernel_version(base::SysInfo::KernelVersion());
-#elif defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
+#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
// Linux operating system version is copied over into kernel version to be
// consistent.
os->set_kernel_version(base::SysInfo::OperatingSystemVersion());
#endif
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
const auto* build_info = base::android::BuildInfo::GetInstance();
os->set_build_fingerprint(build_info->android_build_fp());
if (!package_name.empty() && package_name != "com.android.chrome")
system_profile->set_app_package_name(package_name);
system_profile->set_installer_package(
internal::ToInstallerPackage(build_info->installer_package_name()));
-#elif defined(OS_IOS)
+#elif BUILDFLAG(IS_IOS)
os->set_build_number(base::SysInfo::GetIOSBuildNumber());
#endif
}
@@ -534,4 +534,12 @@ void MetricsLog::GetEncodedLog(std::string* encoded_log) {
uma_proto_.SerializeToString(encoded_log);
}
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+void MetricsLog::SetUserId(const std::string& user_id) {
+ uint64_t hashed_user_id = Hash(user_id);
+ uma_proto_.set_user_id(hashed_user_id);
+ log_metadata_.user_id = hashed_user_id;
+}
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
+
} // namespace metrics
diff --git a/chromium/components/metrics/metrics_log.h b/chromium/components/metrics/metrics_log.h
index 5730462f6df..728afa22d31 100644
--- a/chromium/components/metrics/metrics_log.h
+++ b/chromium/components/metrics/metrics_log.h
@@ -218,6 +218,12 @@ class MetricsLog {
// record. Must only be called after CloseLog() has been called.
void GetEncodedLog(std::string* encoded_log);
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+ // Assigns a user ID to the log. This should be called immediately after
+ // consotruction if it should be applied.
+ void SetUserId(const std::string& user_id);
+#endif
+
LogType log_type() const { return log_type_; }
const LogMetadata& log_metadata() const { return log_metadata_; }
diff --git a/chromium/components/metrics/metrics_log_store_unittest.cc b/chromium/components/metrics/metrics_log_store_unittest.cc
index f546a57baee..929c5925333 100644
--- a/chromium/components/metrics/metrics_log_store_unittest.cc
+++ b/chromium/components/metrics/metrics_log_store_unittest.cc
@@ -59,7 +59,7 @@ class MetricsLogStoreTest : public testing::Test {
const char* pref = log_type == MetricsLog::INITIAL_STABILITY_LOG
? prefs::kMetricsInitialLogs
: prefs::kMetricsOngoingLogs;
- return pref_service_.GetList(pref)->GetList().size();
+ return pref_service_.GetList(pref)->GetListDeprecated().size();
}
TestMetricsServiceClient client_;
diff --git a/chromium/components/metrics/metrics_log_unittest.cc b/chromium/components/metrics/metrics_log_unittest.cc
index 685165a8ca1..3f967cca105 100644
--- a/chromium/components/metrics/metrics_log_unittest.cc
+++ b/chromium/components/metrics/metrics_log_unittest.cc
@@ -38,11 +38,11 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/metrics_proto/chrome_user_metrics_extension.pb.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "base/android/build_info.h"
#endif
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include "base/win/current_module.h"
#endif
@@ -202,7 +202,7 @@ TEST_F(MetricsLogTest, BasicRecord) {
hardware->set_app_cpu_architecture(app_os_arch);
hardware->set_system_ram_mb(base::SysInfo::AmountOfPhysicalMemoryMB());
hardware->set_hardware_class(GetExpectedHardwareClass());
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
hardware->set_dll_base(reinterpret_cast<uint64_t>(CURRENT_MODULE()));
#endif
@@ -218,14 +218,14 @@ TEST_F(MetricsLogTest, BasicRecord) {
#if BUILDFLAG(IS_CHROMEOS_ASH)
system_profile->mutable_os()->set_kernel_version(
base::SysInfo::KernelVersion());
-#elif defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
+#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
system_profile->mutable_os()->set_kernel_version(
base::SysInfo::OperatingSystemVersion());
-#elif defined(OS_ANDROID)
+#elif BUILDFLAG(IS_ANDROID)
system_profile->mutable_os()->set_build_fingerprint(
base::android::BuildInfo::GetInstance()->android_build_fp());
system_profile->set_app_package_name("test app");
-#elif defined(OS_IOS)
+#elif BUILDFLAG(IS_IOS)
system_profile->mutable_os()->set_build_number(
base::SysInfo::GetIOSBuildNumber());
#endif
@@ -233,7 +233,7 @@ TEST_F(MetricsLogTest, BasicRecord) {
// Hard to mock.
system_profile->set_build_timestamp(
parsed.system_profile().build_timestamp());
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
system_profile->set_installer_package(
parsed.system_profile().installer_package());
#endif
diff --git a/chromium/components/metrics/metrics_pref_names.cc b/chromium/components/metrics/metrics_pref_names.cc
index 3d1365a1c60..ca3b01261fd 100644
--- a/chromium/components/metrics/metrics_pref_names.cc
+++ b/chromium/components/metrics/metrics_pref_names.cc
@@ -109,12 +109,6 @@ const char kLastClonedResetTimestamp[] = "cloned_install.last_timestamp";
const char kStabilityBrowserLastLiveTimeStamp[] =
"user_experience_metrics.stability.browser_last_live_timestamp";
-// Total number of child process crashes (other than renderer / extension
-// renderer ones, and plugin children, which are counted separately) since the
-// last report.
-const char kStabilityChildProcessCrashCount[] =
- "user_experience_metrics.stability.child_process_crash_count";
-
// Number of times the application exited uncleanly since the last report.
// On Android this does not count the ones due to Gms Core updates (below).
const char kStabilityCrashCount[] =
@@ -179,11 +173,6 @@ const char kStabilityRendererCrashCount[] =
const char kStabilityRendererFailedLaunchCount[] =
"user_experience_metrics.stability.renderer_failed_launch_count";
-// Number of times the renderer has become non-responsive since the last
-// report.
-const char kStabilityRendererHangCount[] =
- "user_experience_metrics.stability.renderer_hang_count";
-
// Number of times a renderer process successfully launched since the last
// report.
const char kStabilityRendererLaunchCount[] =
diff --git a/chromium/components/metrics/metrics_pref_names.h b/chromium/components/metrics/metrics_pref_names.h
index ebac80b1ec2..59c57eb14d6 100644
--- a/chromium/components/metrics/metrics_pref_names.h
+++ b/chromium/components/metrics/metrics_pref_names.h
@@ -41,7 +41,6 @@ extern const char kMetricsLastSeenPrefix[];
// Preferences for recording stability logs.
extern const char kStabilityBrowserLastLiveTimeStamp[];
-extern const char kStabilityChildProcessCrashCount[];
extern const char kStabilityCrashCount[];
extern const char kStabilityCrashCountDueToGmsCoreUpdate[];
extern const char kStabilityExitedCleanly[];
@@ -56,7 +55,6 @@ extern const char kStabilityLaunchCount[];
extern const char kStabilityPageLoadCount[];
extern const char kStabilityRendererCrashCount[];
extern const char kStabilityRendererFailedLaunchCount[];
-extern const char kStabilityRendererHangCount[];
extern const char kStabilityRendererLaunchCount[];
extern const char kStabilitySavedSystemProfile[];
extern const char kStabilitySavedSystemProfileHash[];
diff --git a/chromium/components/metrics/metrics_scheduler.cc b/chromium/components/metrics/metrics_scheduler.cc
index 975dbc65442..c3043f4fc48 100644
--- a/chromium/components/metrics/metrics_scheduler.cc
+++ b/chromium/components/metrics/metrics_scheduler.cc
@@ -11,7 +11,7 @@ namespace metrics {
namespace {
// The delay, in seconds, after startup before sending the first log message.
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
// Sessions are more likely to be short on a mobile device, so handle the
// initial log quickly.
const int kInitialIntervalSeconds = 15;
diff --git a/chromium/components/metrics/metrics_service.cc b/chromium/components/metrics/metrics_service.cc
index 3c617a578da..8f7643acba0 100644
--- a/chromium/components/metrics/metrics_service.cc
+++ b/chromium/components/metrics/metrics_service.cc
@@ -131,6 +131,7 @@
#include "base/callback.h"
#include "base/location.h"
#include "base/metrics/histogram_base.h"
+#include "base/metrics/histogram_flattener.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/metrics/histogram_samples.h"
@@ -169,9 +170,27 @@ namespace metrics {
namespace {
+// Used to mark histogram samples as reported so that they are not included in
+// the next log. A histogram's snapshot samples are simply discarded/ignored
+// when attempting to record them through this |HistogramFlattener|.
+class DiscardingFlattener : public base::HistogramFlattener {
+ public:
+ DiscardingFlattener() = default;
+
+ DiscardingFlattener(const DiscardingFlattener&) = delete;
+ DiscardingFlattener& operator=(const DiscardingFlattener&) = delete;
+
+ ~DiscardingFlattener() override = default;
+
+ void RecordDelta(const base::HistogramBase& histogram,
+ const base::HistogramSamples& snapshot) override {
+ // No-op. We discard the samples.
+ }
+};
+
// The delay, in seconds, after starting recording before doing expensive
// initialization work.
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
// On mobile devices, a significant portion of sessions last less than a minute.
// Use a shorter timer on these platforms to avoid losing data.
// TODO(dfalcantara): To avoid delaying startup, tighten up initialization so
@@ -392,7 +411,7 @@ void MetricsService::RecordCompletedSessionEnd() {
LogCleanShutdown(true);
}
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
void MetricsService::OnAppEnterBackground(bool keep_recording_in_background) {
is_in_foreground_ = false;
if (!keep_recording_in_background) {
@@ -438,7 +457,7 @@ void MetricsService::OnAppEnterForeground(bool force_open_new_log) {
void MetricsService::LogNeedForCleanShutdown() {
state_manager_->LogHasSessionShutdownCleanly(false);
}
-#endif // defined(OS_ANDROID) || defined(OS_IOS)
+#endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
void MetricsService::ClearSavedStabilityMetrics() {
delegating_provider_.ClearSavedStabilityMetrics();
@@ -447,6 +466,15 @@ void MetricsService::ClearSavedStabilityMetrics() {
local_state_->CommitPendingWrite();
}
+void MetricsService::MarkCurrentHistogramsAsReported() {
+ DiscardingFlattener flattener;
+ base::HistogramSnapshotManager snapshot_manager(&flattener);
+ base::StatisticsRecorder::PrepareDeltas(
+ /*include_persistent=*/true, /*flags_to_set=*/base::Histogram::kNoFlags,
+ /*required_flags=*/base::Histogram::kUmaTargetedHistogramFlag,
+ &snapshot_manager);
+}
+
#if BUILDFLAG(IS_CHROMEOS_ASH)
void MetricsService::SetUserLogStore(
std::unique_ptr<UnsentLogStore> user_log_store) {
@@ -504,6 +532,14 @@ void MetricsService::InitPerUserMetrics() {
client_->InitPerUserMetrics();
}
+absl::optional<bool> MetricsService::GetCurrentUserMetricsConsent() const {
+ return client_->GetCurrentUserMetricsConsent();
+}
+
+absl::optional<std::string> MetricsService::GetCurrentUserId() const {
+ return client_->GetCurrentUserId();
+}
+
void MetricsService::UpdateCurrentUserMetricsConsent(
bool user_metrics_consent) {
client_->UpdateCurrentUserMetricsConsent(user_metrics_consent);
@@ -562,7 +598,7 @@ void MetricsService::InitializeMetricsState() {
if (!was_last_shutdown_clean) {
provider.LogCrash(
state_manager_->clean_exit_beacon()->browser_last_live_timestamp());
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
if (!state_manager_->is_foreground_session()) {
// Android can have background sessions in which the app may not come to
// the foreground, so signal that Chrome should stop watching for crashes
@@ -580,7 +616,7 @@ void MetricsService::InitializeMetricsState() {
// TODO(crbug/1245676): Ditto for WebView.
state_manager_->clean_exit_beacon()->WriteBeaconValue(true);
}
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
}
// HasPreviousSessionData is called first to ensure it is never bypassed.
@@ -903,8 +939,16 @@ bool MetricsService::ShouldResetClientIdsOnClonedInstall() {
std::unique_ptr<MetricsLog> MetricsService::CreateLog(
MetricsLog::LogType log_type) {
- return std::make_unique<MetricsLog>(state_manager_->client_id(), session_id_,
- log_type, client_);
+ auto new_metrics_log = std::make_unique<MetricsLog>(
+ state_manager_->client_id(), session_id_, log_type, client_);
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+ absl::optional<std::string> user_id = GetCurrentUserId();
+ if (user_id.has_value())
+ new_metrics_log->SetUserId(user_id.value());
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
+
+ return new_metrics_log;
}
void MetricsService::SetPersistentSystemProfile(
diff --git a/chromium/components/metrics/metrics_service.h b/chromium/components/metrics/metrics_service.h
index 8df2ae6d091..f8a3f313be2 100644
--- a/chromium/components/metrics/metrics_service.h
+++ b/chromium/components/metrics/metrics_service.h
@@ -127,7 +127,7 @@ class MetricsService : public base::HistogramFlattener {
// that session end was successful.
void RecordCompletedSessionEnd();
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
// Called when the application is going into background mode.
// If |keep_recording_in_background| is true, UMA is still recorded and
// reported while in the background.
@@ -139,7 +139,7 @@ class MetricsService : public base::HistogramFlattener {
// Signals that the session has not yet exited cleanly. Calling this later
// requires a call to LogCleanShutdown().
void LogNeedForCleanShutdown();
-#endif // defined(OS_ANDROID) || defined(OS_IOS)
+#endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
bool recording_active() const;
bool reporting_active() const;
@@ -160,6 +160,12 @@ class MetricsService : public base::HistogramFlattener {
// Clears the stability metrics that are saved in local state.
void ClearSavedStabilityMetrics();
+ // Marks current histograms as reported by snapshotting them, without
+ // actually saving the deltas. At a higher level, this is used to throw
+ // away new histogram samples (since the last log) so that they will not
+ // be included in the next log.
+ void MarkCurrentHistogramsAsReported();
+
#if BUILDFLAG(IS_CHROMEOS_ASH)
// Binds a user log store to store unsent logs. This log store will be
// fully managed by MetricsLogStore. This will no-op if another log store has
@@ -197,6 +203,17 @@ class MetricsService : public base::HistogramFlattener {
// are created happen after MetricsService is initialized.
void InitPerUserMetrics();
+ // Returns the current user metrics consent if it should be applied to
+ // determine metrics reporting state.
+ //
+ // See comments at MetricsServiceClient::GetCurrentUserMetricsConsent() for
+ // more details.
+ absl::optional<bool> GetCurrentUserMetricsConsent() const;
+
+ // Returns the current logged in user id. See comments at
+ // MetricsServiceClient::GetCurrentUserId() for more details.
+ absl::optional<std::string> GetCurrentUserId() const;
+
// Updates the current user metrics consent. No-ops if no user has logged in.
void UpdateCurrentUserMetricsConsent(bool user_metrics_consent);
@@ -223,7 +240,7 @@ class MetricsService : public base::HistogramFlattener {
return &delegating_provider_;
}
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
bool IsInForegroundForTesting() const { return is_in_foreground_; }
#endif
@@ -437,7 +454,7 @@ class MetricsService : public base::HistogramFlattener {
// Indicates if loading of independent metrics is currently active.
bool independent_loader_active_ = false;
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
// Indicates whether OnAppEnterForeground() (true) or OnAppEnterBackground
// (false) was called.
bool is_in_foreground_ = false;
diff --git a/chromium/components/metrics/metrics_service_accessor.cc b/chromium/components/metrics/metrics_service_accessor.cc
index 53192fa37c0..919bdae4c38 100644
--- a/chromium/components/metrics/metrics_service_accessor.cc
+++ b/chromium/components/metrics/metrics_service_accessor.cc
@@ -45,21 +45,24 @@ bool MetricsServiceAccessor::IsMetricsReportingEnabled(
bool MetricsServiceAccessor::RegisterSyntheticFieldTrial(
MetricsService* metrics_service,
base::StringPiece trial_name,
- base::StringPiece group_name) {
+ base::StringPiece group_name,
+ variations::SyntheticTrialAnnotationMode annotation_mode) {
return RegisterSyntheticFieldTrialWithNameAndGroupHash(
metrics_service, variations::HashName(trial_name),
- variations::HashName(group_name));
+ variations::HashName(group_name), annotation_mode);
}
// static
bool MetricsServiceAccessor::RegisterSyntheticFieldTrialWithNameAndGroupHash(
MetricsService* metrics_service,
uint32_t trial_name_hash,
- uint32_t group_name_hash) {
+ uint32_t group_name_hash,
+ variations::SyntheticTrialAnnotationMode annotation_mode) {
if (!metrics_service)
return false;
- variations::SyntheticTrialGroup trial_group(trial_name_hash, group_name_hash);
+ variations::SyntheticTrialGroup trial_group(trial_name_hash, group_name_hash,
+ annotation_mode);
metrics_service->synthetic_trial_registry()->RegisterSyntheticFieldTrial(
trial_group);
return true;
@@ -71,4 +74,9 @@ void MetricsServiceAccessor::SetForceIsMetricsReportingEnabledPrefLookup(
g_force_official_enabled_test = value;
}
+// static
+bool MetricsServiceAccessor::IsForceMetricsReportingEnabledPrefLookup() {
+ return g_force_official_enabled_test;
+}
+
} // namespace metrics
diff --git a/chromium/components/metrics/metrics_service_accessor.h b/chromium/components/metrics/metrics_service_accessor.h
index e16d7a020a9..621ecab8e56 100644
--- a/chromium/components/metrics/metrics_service_accessor.h
+++ b/chromium/components/metrics/metrics_service_accessor.h
@@ -8,6 +8,7 @@
#include <stdint.h>
#include "base/strings/string_piece.h"
+#include "components/variations/synthetic_trials.h"
class PrefService;
@@ -23,6 +24,10 @@ class MetricsServiceAccessor {
MetricsServiceAccessor(const MetricsServiceAccessor&) = delete;
MetricsServiceAccessor& operator=(const MetricsServiceAccessor&) = delete;
+ // Returns the value assigned by
+ // SetForceIsMetricsReportingEnabledPrefLookup(). Default value is false.
+ static bool IsForceMetricsReportingEnabledPrefLookup();
+
protected:
// Constructor declared as protected to enable inheritance. Descendants should
// disallow instantiation.
@@ -35,19 +40,24 @@ class MetricsServiceAccessor {
// Registers a field trial name and group with |metrics_service| (if not
// null), to be used to annotate a UMA report with a particular configuration
- // state. Returns true on success.
+ // state. The |annotation_mode| parameter determines when UMA reports should
+ // start being annotated with this trial and group. Returns true on success.
// See the comment on SyntheticTrialRegistry::RegisterSyntheticFieldTrial()
- // for details.
- static bool RegisterSyntheticFieldTrial(MetricsService* metrics_service,
- base::StringPiece trial_name,
- base::StringPiece group_name);
+ // and ChromeMetricsServiceAccessor::RegisterSyntheticFieldTrial() for more
+ // details.
+ static bool RegisterSyntheticFieldTrial(
+ MetricsService* metrics_service,
+ base::StringPiece trial_name,
+ base::StringPiece group_name,
+ variations::SyntheticTrialAnnotationMode annotation_mode);
// Same as RegisterSyntheticFieldTrial above, but takes in the trial and group
// names as hashes rather than computing those hashes from the strings.
static bool RegisterSyntheticFieldTrialWithNameAndGroupHash(
MetricsService* metrics_service,
uint32_t trial_name_hash,
- uint32_t group_name_hash);
+ uint32_t group_name_hash,
+ variations::SyntheticTrialAnnotationMode annotation_mode);
// IsMetricsReportingEnabled() in non-official builds unconditionally returns
// false. This results in different behavior for tests running in official vs
diff --git a/chromium/components/metrics/metrics_service_client.cc b/chromium/components/metrics/metrics_service_client.cc
index e15e31c2be5..f3fc1d53959 100644
--- a/chromium/components/metrics/metrics_service_client.cc
+++ b/chromium/components/metrics/metrics_service_client.cc
@@ -26,12 +26,12 @@ constexpr int kMetricsUploadIntervalSecMinimum = 20;
// then we will discard the log, and not try to retransmit it. We also don't
// persist the log to the prefs for transmission during the next chrome session
// if this limit is exceeded.
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS)
// Increase CrOS limit to accommodate SampledProfile data (crbug.com/1210595).
constexpr size_t kMaxOngoingLogSize = 1024 * 1024; // 1 MiB
#else
constexpr size_t kMaxOngoingLogSize = 100 * 1024; // 100 KiB
-#endif // defined(OS_CHROMEOS)
+#endif // BUILDFLAG(IS_CHROMEOS)
// The number of bytes of logs to save of each type (initial/ongoing). This
// ensures that a reasonable amount of history will be stored even if there is a
@@ -163,4 +163,13 @@ bool MetricsServiceClient::IsMetricsReportingForceEnabled() const {
return ::metrics::IsMetricsReportingForceEnabled();
}
+absl::optional<bool> MetricsServiceClient::GetCurrentUserMetricsConsent()
+ const {
+ return absl::nullopt;
+}
+
+absl::optional<std::string> MetricsServiceClient::GetCurrentUserId() const {
+ return absl::nullopt;
+}
+
} // namespace metrics
diff --git a/chromium/components/metrics/metrics_service_client.h b/chromium/components/metrics/metrics_service_client.h
index 2296f20b5a7..63ef4017065 100644
--- a/chromium/components/metrics/metrics_service_client.h
+++ b/chromium/components/metrics/metrics_service_client.h
@@ -6,7 +6,6 @@
#define COMPONENTS_METRICS_METRICS_SERVICE_CLIENT_H_
#include <stdint.h>
-
#include <memory>
#include <string>
@@ -204,6 +203,27 @@ class MetricsServiceClient {
// should no-op for other platforms.
virtual void UpdateCurrentUserMetricsConsent(bool user_metrics_consent) {}
+ // Returns the current user metrics consent if it should be applied to decide
+ // the current metrics reporting state. This allows embedders to determine
+ // when a user metric consent state should not be applied (ie no logged in
+ // user or managed policy).
+ //
+ // Will return absl::nullopt if there is no current user or current user
+ // metrics consent should not be applied to determine metrics reporting state.
+ //
+ // Not all platforms support per-user consent. If per-user consent is not
+ // supported, this function should return absl::nullopt.
+ virtual absl::optional<bool> GetCurrentUserMetricsConsent() const;
+
+ // Returns the current user id.
+ //
+ // Will return absl::nullopt if there is no current user, metrics reporting is
+ // disabled, or current user should not have a user id.
+ //
+ // Not all platforms support per-user consent. If per-user consent is not
+ // supported, this function should return absl::nullopt.
+ virtual absl::optional<std::string> GetCurrentUserId() const;
+
private:
base::RepeatingClosure update_running_services_;
};
diff --git a/chromium/components/metrics/metrics_service_unittest.cc b/chromium/components/metrics/metrics_service_unittest.cc
index dee72797ae3..a6a1d605145 100644
--- a/chromium/components/metrics/metrics_service_unittest.cc
+++ b/chromium/components/metrics/metrics_service_unittest.cc
@@ -292,6 +292,16 @@ class ExperimentTestMetricsProvider : public TestMetricsProvider {
raw_ptr<base::FieldTrial> session_data_trial_;
};
+bool HistogramExists(base::StringPiece name) {
+ return base::StatisticsRecorder::FindHistogram(name) != nullptr;
+}
+
+base::HistogramBase::Count GetHistogramDeltaTotalCount(base::StringPiece name) {
+ return base::StatisticsRecorder::FindHistogram(name)
+ ->SnapshotDelta()
+ ->TotalCount();
+}
+
} // namespace
TEST_F(MetricsServiceTest, InitialStabilityLogAfterCleanShutDown) {
@@ -442,12 +452,12 @@ TEST_P(MetricsServiceTestWithStartupVisibility, InitialStabilityLogAfterCrash) {
// Verify that Chrome is (or is not) watching for crashes by checking the
// beacon value.
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
EXPECT_EQ(local_state->GetBoolean(prefs::kStabilityExitedCleanly),
params.expected_beacon_value);
#else
EXPECT_FALSE(local_state->GetBoolean(prefs::kStabilityExitedCleanly));
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
// The initial stability log should be generated and persisted in unsent logs.
MetricsLogStore* test_log_store = service.LogStoreForTest();
@@ -526,6 +536,38 @@ TEST_F(MetricsServiceTest, InitialLogsHaveOnDidCreateMetricsLogHistograms) {
EXPECT_EQ(1, GetSampleCountOfOnDidCreateLogHistogram(test_log_store));
}
+TEST_F(MetricsServiceTest, MarkCurrentHistogramsAsReported) {
+ EnableMetricsReporting();
+ TestMetricsServiceClient client;
+ TestMetricsService service(GetMetricsStateManager(), &client,
+ GetLocalState());
+
+ // Emit to histogram |Test.Before.Histogram|.
+ ASSERT_FALSE(HistogramExists("Test.Before.Histogram"));
+ base::UmaHistogramBoolean("Test.Before.Histogram", true);
+ ASSERT_TRUE(HistogramExists("Test.Before.Histogram"));
+
+ // Mark histogram data that has been collected until now (in particular, the
+ // |Test.Before.Histogram| sample) as reported.
+ service.MarkCurrentHistogramsAsReported();
+
+ // Emit to histogram |Test.After.Histogram|.
+ ASSERT_FALSE(HistogramExists("Test.After.Histogram"));
+ base::UmaHistogramBoolean("Test.After.Histogram", true);
+ ASSERT_TRUE(HistogramExists("Test.After.Histogram"));
+
+ // Verify that the |Test.Before.Histogram| sample was marked as reported, and
+ // is not included in the next snapshot.
+ EXPECT_EQ(0, GetHistogramDeltaTotalCount("Test.Before.Histogram"));
+ // Verify that the |Test.After.Histogram| sample was not marked as reported,
+ // and is included in the next snapshot.
+ EXPECT_EQ(1, GetHistogramDeltaTotalCount("Test.After.Histogram"));
+
+ // Clean up histograms.
+ base::StatisticsRecorder::ForgetHistogramForTesting("Test.Before.Histogram");
+ base::StatisticsRecorder::ForgetHistogramForTesting("Test.After.Histogram");
+}
+
TEST_F(MetricsServiceTest, FirstLogCreatedBeforeUnsentLogsSent) {
EnableMetricsReporting();
TestMetricsServiceClient client;
diff --git a/chromium/components/metrics/metrics_state_manager.cc b/chromium/components/metrics/metrics_state_manager.cc
index 25b14283c48..5da316cc612 100644
--- a/chromium/components/metrics/metrics_state_manager.cc
+++ b/chromium/components/metrics/metrics_state_manager.cc
@@ -10,16 +10,15 @@
#include <memory>
#include <random>
#include <string>
+#include <tuple>
#include <utility>
#include "base/base_switches.h"
#include "base/callback_helpers.h"
#include "base/check.h"
#include "base/command_line.h"
-#include "base/compiler_specific.h"
#include "base/debug/leak_annotations.h"
#include "base/guid.h"
-#include "base/ignore_result.h"
#include "base/memory/raw_ptr.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
@@ -254,7 +253,7 @@ MetricsStateManager::MetricsStateManager(
DCHECK(!load_client_info_.is_null());
ResetMetricsIDsIfNecessary();
- bool is_first_run = false;
+ [[maybe_unused]] bool is_first_run = false;
int64_t install_date = local_state_->GetInt64(prefs::kInstallDate);
// Set the install date if this is our first run.
@@ -272,9 +271,7 @@ MetricsStateManager::MetricsStateManager(
ForceClientIdCreation();
}
-#if defined(OS_WIN)
- ALLOW_UNUSED_LOCAL(is_first_run);
-#else
+#if !BUILDFLAG(IS_WIN)
if (is_first_run) {
// If this is a first run (no install date) and there's no client id, then
// generate a provisional client id now. This id will be used for field
@@ -295,7 +292,7 @@ MetricsStateManager::MetricsStateManager(
if (client_id_.empty())
provisional_client_id_ = base::GenerateGUID();
}
-#endif // !defined(OS_WIN)
+#endif // !BUILDFLAG(IS_WIN)
// The |initial_client_id_| should only be set if UMA is enabled or there's a
// provisional client id.
@@ -350,7 +347,7 @@ void MetricsStateManager::InstantiateFieldTrialList(
base::FieldTrialList* leaked_field_trial_list =
new base::FieldTrialList(std::move(entropy_provider));
ANNOTATE_LEAKING_OBJECT_PTR(leaked_field_trial_list);
- ignore_result(leaked_field_trial_list);
+ std::ignore = leaked_field_trial_list;
}
// TODO(crbug/1257204): Some FieldTrial-setup-related code is here and some is
@@ -403,9 +400,9 @@ void MetricsStateManager::InstantiateFieldTrialList(
void MetricsStateManager::LogHasSessionShutdownCleanly(
bool has_session_shutdown_cleanly,
- bool write_synchronously) {
+ bool is_extended_safe_mode) {
clean_exit_beacon_.WriteBeaconValue(has_session_shutdown_cleanly,
- write_synchronously);
+ is_extended_safe_mode);
}
void MetricsStateManager::ForceClientIdCreation() {
diff --git a/chromium/components/metrics/metrics_state_manager.h b/chromium/components/metrics/metrics_state_manager.h
index bc2314598fa..6212396a6a3 100644
--- a/chromium/components/metrics/metrics_state_manager.h
+++ b/chromium/components/metrics/metrics_state_manager.h
@@ -37,10 +37,14 @@ class MetricsProvider;
// which the browser process starts; does some work, e.g. servicing a sync; and
// ends without ever becoming visible. Note that the point in startup at which
// this value is determined is likely before the UI is visible.
+//
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
enum class StartupVisibility {
kUnknown = 0,
kBackground = 1,
kForeground = 2,
+ kMaxValue = kForeground,
};
// Denotes the type of EntropyProvider to use for one-time randomization.
@@ -125,15 +129,15 @@ class MetricsStateManager final {
// that Chrome crashed or otherwise did not shut down cleanly, e.g. maybe the
// OS crashed.
//
- // If |write_synchronously| is true, then |has_session_shutdown_cleanly| is
+ // If |is_extended_safe_mode| is true, then |has_session_shutdown_cleanly| is
// written to disk synchronously. If false, a write is scheduled, and for
// clients in the Extended Variations Safe Mode experiment, a synchronous
// write is done, too.
//
- // Note: |write_synchronously| should be true only for the Extended Variations
- // Safe Mode experiment.
+ // Note: |is_extended_safe_mode| should be true only for the Extended
+ // Variations Safe Mode experiment.
void LogHasSessionShutdownCleanly(bool has_session_shutdown_cleanly,
- bool write_synchronously = false);
+ bool is_extended_safe_mode = false);
// Forces the client ID to be generated. This is useful in case it's needed
// before recording.
diff --git a/chromium/components/metrics/metrics_state_manager_unittest.cc b/chromium/components/metrics/metrics_state_manager_unittest.cc
index 0530f6f0eef..caab1380822 100644
--- a/chromium/components/metrics/metrics_state_manager_unittest.cc
+++ b/chromium/components/metrics/metrics_state_manager_unittest.cc
@@ -320,7 +320,7 @@ TEST_F(MetricsStateManagerTest,
EXPECT_EQ(client_info_load_count_, 1);
}
-#if !defined(OS_WIN)
+#if !BUILDFLAG(IS_WIN)
TEST_F(MetricsStateManagerTest, ProvisionalClientId_PromotedToClientId) {
std::unique_ptr<MetricsStateManager> state_manager(CreateStateManager());
@@ -383,7 +383,7 @@ TEST_F(MetricsStateManagerTest, ProvisionalClientId_NotPersisted) {
MetricsStateManager::ENTROPY_SOURCE_LOW);
}
}
-#endif // !defined(OS_WIN)
+#endif // !BUILDFLAG(IS_WIN)
TEST_F(MetricsStateManagerTest, LoadPrefs) {
ClientInfo client_info;
diff --git a/chromium/components/metrics/net/cellular_logic_helper.cc b/chromium/components/metrics/net/cellular_logic_helper.cc
index ba6909da05b..2083b6fbf44 100644
--- a/chromium/components/metrics/net/cellular_logic_helper.cc
+++ b/chromium/components/metrics/net/cellular_logic_helper.cc
@@ -15,7 +15,7 @@ namespace metrics {
namespace {
// Standard interval between log uploads, in seconds.
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
const int kStandardUploadIntervalSeconds = 5 * 60; // Five minutes.
const int kStandardUploadIntervalCellularSeconds = 15 * 60; // Fifteen minutes.
#else
@@ -30,7 +30,7 @@ const base::Feature kMoreFrequentUmaUploads{"MoreFrequentUmaUploads",
constexpr base::TimeDelta kMoreFrequentUploadInterval = base::Minutes(5);
#endif // IS_CHROMEOS_ASH
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
const bool kDefaultCellularLogicEnabled = true;
#else
const bool kDefaultCellularLogicEnabled = false;
@@ -39,7 +39,7 @@ const bool kDefaultCellularLogicEnabled = false;
} // namespace
base::TimeDelta GetUploadInterval(bool use_cellular_upload_interval) {
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
if (use_cellular_upload_interval)
return base::Seconds(kStandardUploadIntervalCellularSeconds);
#elif BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chromium/components/metrics/net/network_metrics_provider.cc b/chromium/components/metrics/net/network_metrics_provider.cc
index 5602575fd34..03b1998fe99 100644
--- a/chromium/components/metrics/net/network_metrics_provider.cc
+++ b/chromium/components/metrics/net/network_metrics_provider.cc
@@ -26,7 +26,7 @@
#include "net/nqe/effective_connection_type_observer.h"
#include "net/nqe/network_quality_estimator.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "services/network/public/cpp/network_connection_tracker.h"
#endif
@@ -109,7 +109,7 @@ void NetworkMetricsProvider::SetNetworkConnectionTracker(
}
void NetworkMetricsProvider::FinalizingMetricsLogRecord() {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Metrics logged here will be included in every metrics log record. It's not
// yet clear if these metrics are generally useful enough to warrant being
// added to the SystemProfile proto, so they are logged here as histograms for
diff --git a/chromium/components/metrics/net/network_metrics_provider_unittest.cc b/chromium/components/metrics/net/network_metrics_provider_unittest.cc
index feb82e02570..bd6b6fda305 100644
--- a/chromium/components/metrics/net/network_metrics_provider_unittest.cc
+++ b/chromium/components/metrics/net/network_metrics_provider_unittest.cc
@@ -20,13 +20,13 @@
#include "chromeos/network/network_handler_test_helper.h"
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
#include "ios/web/public/test/web_task_environment.h"
using MetricsTaskEnvironment = web::WebTaskEnvironment;
-#else // !defined(OS_IOS)
+#else // !BUILDFLAG(IS_IOS)
#include "content/public/test/browser_task_environment.h"
using MetricsTaskEnvironment = content::BrowserTaskEnvironment;
-#endif // defined(OS_IOS)
+#endif // BUILDFLAG(IS_IOS)
namespace metrics {
diff --git a/chromium/components/metrics/persistent_histograms.cc b/chromium/components/metrics/persistent_histograms.cc
index b53ad1e8923..7c7d7cb0376 100644
--- a/chromium/components/metrics/persistent_histograms.cc
+++ b/chromium/components/metrics/persistent_histograms.cc
@@ -31,7 +31,7 @@ const base::FeatureParam<std::string> kPersistentHistogramsStorage{
// Creating a "spare" file for persistent metrics involves a lot of I/O and
// isn't important so delay the operation for a while after startup.
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Android needs the spare file and also launches faster.
constexpr bool kSpareFileRequired = true;
constexpr int kSpareFileCreateDelaySeconds = 10;
@@ -43,7 +43,7 @@ constexpr bool kSpareFileRequired = false;
constexpr int kSpareFileCreateDelaySeconds = 90;
#endif
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// Windows sometimes creates files of the form MyFile.pma~RF71cb1793.TMP
// when trying to rename a file to something that exists but is in-use, and
@@ -81,7 +81,7 @@ void DeleteOldWindowsTempFiles(const base::FilePath& dir) {
// spending time on clean-up efforts.
constexpr base::TimeDelta kDeleteOldWindowsTempFilesDelay = base::Minutes(2);
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
// Create persistent/shared memory and allow histograms to be stored in
// it. Memory that is not actually used won't be physically mapped by the
@@ -222,14 +222,14 @@ void InstantiatePersistentHistogramsImpl(const base::FilePath& metrics_dir,
// Create tracking histograms for the allocator and record storage file.
allocator->CreateTrackingHistograms(kBrowserMetricsName);
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
base::ThreadPool::PostDelayedTask(
FROM_HERE,
{base::MayBlock(), base::TaskPriority::LOWEST,
base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
base::BindOnce(&DeleteOldWindowsTempFiles, std::move(metrics_dir)),
kDeleteOldWindowsTempFilesDelay);
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
}
} // namespace
@@ -251,7 +251,7 @@ void InstantiatePersistentHistograms(const base::FilePath& metrics_dir) {
// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
// of lacros-chrome is complete.
-#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
// Linux kernel 4.4.0.* shows a huge number of SIGBUS crashes with persistent
// histograms enabled using a mapped file. Change this to use local memory.
// https://bugs.chromium.org/p/chromium/issues/detail?id=753741
diff --git a/chromium/components/metrics/psi_memory_parser.h b/chromium/components/metrics/psi_memory_parser.h
new file mode 100644
index 00000000000..c1384dd2ed1
--- /dev/null
+++ b/chromium/components/metrics/psi_memory_parser.h
@@ -0,0 +1,114 @@
+// Copyright 2021 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.
+
+#ifndef COMPONENTS_METRICS_PSI_MEMORY_PARSER_H_
+#define COMPONENTS_METRICS_PSI_MEMORY_PARSER_H_
+
+#include <string>
+
+#include "base/gtest_prod_util.h"
+#include "base/strings/string_piece.h"
+
+namespace metrics {
+
+// Items in internal are - as the name implies - NOT for outside consumption.
+// Defined here to allow access to unit test.
+namespace internal {
+
+// Finds the bounds for a substring of |content| which is sandwiched between
+// the given |prefix| and |suffix| indices. Search only considers
+// the portion of the string starting from |search_start|.
+// Returns false if the prefix and/or suffix are not found, true otherwise.
+// |start| and |end| are output parameters populated with the indices
+// for the middle string.
+bool FindMiddleString(const base::StringPiece& content,
+ size_t search_start,
+ const base::StringPiece& prefix,
+ const base::StringPiece& suffix,
+ size_t* start,
+ size_t* end);
+
+} // namespace internal
+
+// Values as logged in the histogram for memory pressure.
+constexpr int kMemPressureMin = 1; // As 0 is for underflow.
+constexpr int kMemPressureExclusiveMax = 10000;
+constexpr int kMemPressureHistogramBuckets = 100;
+
+// Enumeration representing success and various failure modes for parsing PSI
+// memory data. These values are persisted to logs. Entries should not be
+// renumbered and numeric values should never be reused.
+enum class ParsePSIMemStatus {
+ kSuccess,
+ kReadFileFailed,
+ kUnexpectedDataFormat,
+ kInvalidMetricFormat,
+ kParsePSIValueFailed,
+ // Magic constant used by the histogram macros.
+ kMaxValue = kParsePSIValueFailed,
+};
+
+// PSIMemoryParser has logic to parse results from /proc/memory/pressure
+// in Linux, which can be used for memory pressure metrics.
+class PSIMemoryParser {
+ public:
+ explicit PSIMemoryParser(uint32_t period);
+ ~PSIMemoryParser();
+
+ // Parses PSI memory pressure from |content|, for the currently configured
+ // metrics period (10, 60 or 300 seconds).
+ // The some and full values are output to |metricSome| and |metricFull|,
+ // respectively.
+ // Returns status of the parse operation - ParsePSIMemStatus::kSuccess
+ // or error code otherwise.
+ ParsePSIMemStatus ParseMetrics(const base::StringPiece& content,
+ int* metric_some,
+ int* metric_full);
+
+ // Raw buffer overload
+ ParsePSIMemStatus ParseMetrics(const uint8_t* content,
+ uint32_t len,
+ int* metric_some,
+ int* metric_full);
+
+ uint32_t GetPeriod() const;
+ void LogParseStatus(ParsePSIMemStatus stat);
+
+ PSIMemoryParser(const PSIMemoryParser&) = delete;
+ PSIMemoryParser& operator=(const PSIMemoryParser&) = delete;
+ PSIMemoryParser() = delete;
+
+ private:
+ // Friend it so it can see private members for testing
+ friend class PSIMemoryParserTest;
+ FRIEND_TEST_ALL_PREFIXES(PSIMemoryParserTest, CustomInterval);
+ FRIEND_TEST_ALL_PREFIXES(PSIMemoryParserTest, InvalidInterval);
+ FRIEND_TEST_ALL_PREFIXES(PSIMemoryParserTest, InternalsA);
+ FRIEND_TEST_ALL_PREFIXES(PSIMemoryParserTest, InternalsB);
+ FRIEND_TEST_ALL_PREFIXES(PSIMemoryParserTest, InternalsC);
+ FRIEND_TEST_ALL_PREFIXES(PSIMemoryParserTest, InternalsD);
+ FRIEND_TEST_ALL_PREFIXES(PSIMemoryParserTest, InternalsE);
+
+ ParsePSIMemStatus ParseMetricsInternal(const std::string& content,
+ int* metric_some,
+ int* metric_full);
+
+ // Retrieves one metric value from |content|, for the currently configured
+ // metrics category (10, 60 or 300 seconds).
+ // Only considers the substring between |start| (inclusive) and |end|
+ // (exclusive).
+ // Returns the floating-point string representation converted into an integer
+ // which has the value multiplied by 100 - (10.20 = 1020), for
+ // histogram usage.
+ int GetMetricValue(const base::StringPiece& content,
+ size_t start,
+ size_t end);
+
+ std::string metric_prefix_;
+ uint32_t period_;
+};
+
+} // namespace metrics
+
+#endif // COMPONENTS_METRICS_PSI_MEMORY_PARSER_H_
diff --git a/chromium/components/metrics/psi_memory_parser_linux.cc b/chromium/components/metrics/psi_memory_parser_linux.cc
new file mode 100644
index 00000000000..f5fddb04e7f
--- /dev/null
+++ b/chromium/components/metrics/psi_memory_parser_linux.cc
@@ -0,0 +1,185 @@
+// Copyright 2021 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.
+
+#include "components/metrics/psi_memory_parser.h"
+
+#include <stddef.h>
+
+#include <cinttypes>
+#include <map>
+#include <memory>
+#include <string>
+
+#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_functions.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "components/metrics/metrics_log_store.h"
+
+namespace metrics {
+
+namespace {
+
+// Periods supported by standard Linux PSI metricvs.
+constexpr uint32_t kMinCollectionInterval = 10;
+constexpr uint32_t kMidCollectionInterval = 60;
+constexpr uint32_t kMaxCollectionInterval = 300;
+
+constexpr uint32_t kDefaultCollectionInterval = kMinCollectionInterval;
+
+// Name of the histogram that represents the success and various failure modes
+// for parsing PSI memory data.
+const char kParsePSIMemoryHistogramName[] = "ChromeOS.CWP.ParsePSIMemory";
+
+constexpr base::StringPiece kContentPrefixSome = "some";
+constexpr base::StringPiece kContentPrefixFull = "full";
+constexpr base::StringPiece kContentTerminator = " total=";
+constexpr base::StringPiece kMetricTerminator = " ";
+
+const char kMetricPrefixFormat[] = "avg%d=";
+
+} // namespace
+
+PSIMemoryParser::PSIMemoryParser(uint32_t period)
+ : period_(kDefaultCollectionInterval) {
+ if (period == kMinCollectionInterval || period == kMidCollectionInterval ||
+ period == kMaxCollectionInterval) {
+ period_ = period;
+ } else {
+ LOG(WARNING) << "Ignoring invalid interval [" << period << "]";
+ }
+
+ metric_prefix_ = base::StringPrintf(kMetricPrefixFormat, period_);
+}
+
+PSIMemoryParser::~PSIMemoryParser() = default;
+
+uint32_t PSIMemoryParser::GetPeriod() const {
+ return period_;
+}
+
+int PSIMemoryParser::GetMetricValue(const base::StringPiece& content,
+ size_t start,
+ size_t end) {
+ size_t value_start;
+ size_t value_end;
+ if (!internal::FindMiddleString(content, start, metric_prefix_,
+ kMetricTerminator, &value_start,
+ &value_end)) {
+ return -1;
+ }
+ if (value_end > end) {
+ return -1; // Out of bounds of the search area.
+ }
+
+ double n;
+ const base::StringPiece metric_value_text =
+ content.substr(value_start, value_end - value_start);
+ if (!base::StringToDouble(metric_value_text, &n)) {
+ return -1; // Unable to convert string to number
+ }
+
+ // Want to multiply by 100, but to avoid integer truncation,
+ // do best-effort rounding.
+ const int preround = static_cast<int>(n * 1000);
+ return (preround + 5) / 10;
+}
+
+void PSIMemoryParser::LogParseStatus(ParsePSIMemStatus stat) {
+ constexpr int statCeiling =
+ static_cast<int>(ParsePSIMemStatus::kMaxValue) + 1;
+ base::UmaHistogramExactLinear(kParsePSIMemoryHistogramName,
+ static_cast<int>(stat), statCeiling);
+}
+
+ParsePSIMemStatus PSIMemoryParser::ParseMetrics(
+ const base::StringPiece& content,
+ int* metric_some,
+ int* metric_full) {
+ size_t str_some_start;
+ size_t str_some_end;
+ size_t str_full_start;
+ size_t str_full_end;
+
+ // Example of content:
+ // some avg10=0.00 avg60=0.00 avg300=0.00 total=417963
+ // full avg10=0.00 avg60=0.00 avg300=0.00 total=205933
+ // we will pick one of the columns depending on the colleciton period set
+
+ DCHECK_NE(metric_some, nullptr);
+ DCHECK_NE(metric_full, nullptr);
+
+ if (!internal::FindMiddleString(content, 0, kContentPrefixSome,
+ kContentTerminator, &str_some_start,
+ &str_some_end)) {
+ return ParsePSIMemStatus::kUnexpectedDataFormat;
+ }
+
+ if (!internal::FindMiddleString(content,
+ str_some_end + kContentTerminator.length(),
+ kContentPrefixFull, kContentTerminator,
+ &str_full_start, &str_full_end)) {
+ return ParsePSIMemStatus::kUnexpectedDataFormat;
+ }
+
+ int compute_some = GetMetricValue(content, str_some_start, str_some_end);
+ if (compute_some < 0) {
+ return ParsePSIMemStatus::kInvalidMetricFormat;
+ }
+
+ int compute_full = GetMetricValue(content, str_full_start, str_full_end);
+ if (compute_full < 0) {
+ return ParsePSIMemStatus::kInvalidMetricFormat;
+ }
+
+ *metric_some = compute_some;
+ *metric_full = compute_full;
+
+ return ParsePSIMemStatus::kSuccess;
+}
+
+ParsePSIMemStatus PSIMemoryParser::ParseMetrics(const uint8_t* content,
+ uint32_t len,
+ int* metric_some,
+ int* metric_full) {
+ // The cast below is admittedly sneaky, but inherently safe because
+ // we are translating a const pointer into another const pointer,
+ // and the data sizes of the pointed object are the same.
+ const char* string_content = reinterpret_cast<const char*>(content);
+
+ return ParseMetrics(base::StringPiece(string_content, len), metric_some,
+ metric_full);
+}
+
+namespace internal {
+
+bool FindMiddleString(const base::StringPiece& content,
+ size_t search_start,
+ const base::StringPiece& prefix,
+ const base::StringPiece& suffix,
+ size_t* start,
+ size_t* end) {
+ DCHECK_NE(start, nullptr);
+ DCHECK_NE(end, nullptr);
+
+ size_t compute_start = content.find(prefix, search_start);
+ if (compute_start == std::string::npos) {
+ return false;
+ }
+ compute_start += prefix.length();
+
+ size_t compute_end = content.find(suffix, compute_start);
+ if (compute_end == std::string::npos) {
+ return false;
+ }
+
+ *start = compute_start;
+ *end = compute_end;
+
+ return true;
+}
+
+} // namespace internal
+
+} // namespace metrics
diff --git a/chromium/components/metrics/psi_memory_parser_linux_unittest.cc b/chromium/components/metrics/psi_memory_parser_linux_unittest.cc
new file mode 100644
index 00000000000..0536975f514
--- /dev/null
+++ b/chromium/components/metrics/psi_memory_parser_linux_unittest.cc
@@ -0,0 +1,163 @@
+// Copyright 2021 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.
+
+#include "components/metrics/psi_memory_parser.h"
+
+#include <memory>
+
+#include "base/files/file_util.h"
+#include "base/metrics/statistics_recorder.h"
+#include "base/test/metrics/histogram_tester.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace metrics {
+
+namespace {
+
+// Just as the kernel outputs.
+const char kFileContents1[] =
+ "some avg10=23.10 avg60=5.06 avg300=15.10 total=417963\n"
+ "full avg10=9.00 avg60=19.20 avg300=3.23 total=205933\n";
+
+// Number of decimals not consistent, slightly malformed - but acceptable.
+const char kFileContents2[] =
+ "some avg10=24 avg60=5.06 avg300=15.10 total=417963\n"
+ "full avg10=9.2 avg60=19.20 avg300=3.23 total=205933\n";
+
+} // namespace
+
+class PSIMemoryParserTest : public testing::Test {
+ public:
+ PSIMemoryParserTest() = default;
+ ~PSIMemoryParserTest() override = default;
+
+ void Init(uint32_t period) {
+ cit_ = std::make_unique<PSIMemoryParser>(period);
+ }
+
+ uint32_t GetPeriod() { return cit_->GetPeriod(); }
+ base::HistogramTester& Histograms() { return histogram_tester_; }
+ std::unique_ptr<PSIMemoryParser>& Cit() { return cit_; }
+ const std::string& GetMetricPrefix() { return cit_->metric_prefix_; }
+
+ void KillCit() { cit_.reset(); }
+
+ private:
+ std::unique_ptr<PSIMemoryParser> cit_;
+ base::HistogramTester histogram_tester_;
+};
+
+TEST_F(PSIMemoryParserTest, CustomInterval) {
+ Init(60u);
+
+ EXPECT_EQ(60u, GetPeriod());
+}
+
+TEST_F(PSIMemoryParserTest, InvalidInterval) {
+ Init(15u);
+
+ EXPECT_EQ(10u, GetPeriod());
+}
+
+TEST_F(PSIMemoryParserTest, InternalsA) {
+ Init(10u);
+
+ std::string testContent1 = "prefix" + GetMetricPrefix() + "9.37 suffix";
+ EXPECT_EQ(10u, GetPeriod());
+
+ size_t s = 0;
+ size_t e = 0;
+
+ EXPECT_EQ(false, internal::FindMiddleString(testContent1, 0, "nothere",
+ "suffix", &s, &e));
+
+ EXPECT_EQ(false, internal::FindMiddleString(testContent1, 0, "prefix",
+ "notthere", &s, &e));
+
+ EXPECT_EQ(true, internal::FindMiddleString(testContent1, 0, "prefix",
+ "suffix", &s, &e));
+ EXPECT_EQ(6u, s);
+ EXPECT_EQ(17u, e);
+
+ EXPECT_EQ(937, Cit()->GetMetricValue(testContent1, s, e));
+
+ std::string testContent2 = "extra " + testContent1;
+ EXPECT_EQ(true, internal::FindMiddleString(testContent2, 0, "prefix",
+ "suffix", &s, &e));
+ EXPECT_EQ(12u, s);
+ EXPECT_EQ(23u, e);
+
+ EXPECT_EQ(937, Cit()->GetMetricValue(testContent2, s, e));
+}
+
+TEST_F(PSIMemoryParserTest, InternalsB) {
+ Init(300);
+
+ int msome;
+ int mfull;
+ ParsePSIMemStatus stat;
+
+ stat = Cit()->ParseMetrics(kFileContents1, &msome, &mfull);
+
+ EXPECT_EQ(ParsePSIMemStatus::kSuccess, stat);
+ EXPECT_EQ(1510, msome);
+ EXPECT_EQ(323, mfull);
+}
+
+TEST_F(PSIMemoryParserTest, InternalsC) {
+ Init(60);
+
+ int msome;
+ int mfull;
+ ParsePSIMemStatus stat;
+
+ stat = Cit()->ParseMetrics(kFileContents1, &msome, &mfull);
+
+ EXPECT_EQ(ParsePSIMemStatus::kSuccess, stat);
+ EXPECT_EQ(506, msome);
+ EXPECT_EQ(1920, mfull);
+}
+
+TEST_F(PSIMemoryParserTest, InternalsD) {
+ Init(10);
+
+ int msome;
+ int mfull;
+ ParsePSIMemStatus stat;
+
+ stat = Cit()->ParseMetrics(kFileContents1, &msome, &mfull);
+
+ EXPECT_EQ(ParsePSIMemStatus::kSuccess, stat);
+ EXPECT_EQ(2310, msome);
+ EXPECT_EQ(900, mfull);
+}
+
+TEST_F(PSIMemoryParserTest, InternalsE) {
+ Init(10);
+
+ int msome;
+ int mfull;
+ ParsePSIMemStatus stat;
+
+ stat = Cit()->ParseMetrics(kFileContents2, &msome, &mfull);
+
+ EXPECT_EQ(ParsePSIMemStatus::kSuccess, stat);
+ EXPECT_EQ(2400, msome);
+ EXPECT_EQ(920, mfull);
+}
+
+TEST_F(PSIMemoryParserTest, ParseResultCounter) {
+ Init(10);
+
+ Cit()->LogParseStatus(ParsePSIMemStatus::kSuccess);
+ Cit()->LogParseStatus(ParsePSIMemStatus::kInvalidMetricFormat);
+ Cit()->LogParseStatus(ParsePSIMemStatus::kInvalidMetricFormat);
+
+ Histograms().ExpectBucketCount("ChromeOS.CWP.ParsePSIMemory",
+ ParsePSIMemStatus::kSuccess, 1);
+ Histograms().ExpectBucketCount("ChromeOS.CWP.ParsePSIMemory",
+ ParsePSIMemStatus::kInvalidMetricFormat, 2);
+}
+
+} // namespace metrics
diff --git a/chromium/components/metrics/single_sample_metrics_factory_impl_unittest.cc b/chromium/components/metrics/single_sample_metrics_factory_impl_unittest.cc
index f63e7ef2e01..089542166f3 100644
--- a/chromium/components/metrics/single_sample_metrics_factory_impl_unittest.cc
+++ b/chromium/components/metrics/single_sample_metrics_factory_impl_unittest.cc
@@ -145,7 +145,7 @@ TEST_F(SingleSampleMetricsFactoryImplTest, DefaultSingleSampleMetricWithValue) {
TEST_F(SingleSampleMetricsFactoryImplTest, MultithreadedMetrics) {
// Allow EXPECT_DCHECK_DEATH for multiple threads.
- // https://github.com/google/googletest/blob/master/docs/advanced.md#death-tests-and-threads
+ // https://github.com/google/googletest/blob/main/docs/advanced.md#death-tests-and-threads
testing::FLAGS_gtest_death_test_style = "threadsafe";
base::HistogramTester tester;
diff --git a/chromium/components/metrics/stability_metrics_helper.cc b/chromium/components/metrics/stability_metrics_helper.cc
index 29c56a54193..9e7ebaefb7f 100644
--- a/chromium/components/metrics/stability_metrics_helper.cc
+++ b/chromium/components/metrics/stability_metrics_helper.cc
@@ -21,15 +21,15 @@
#include "extensions/buildflags/buildflags.h"
#include "third_party/metrics_proto/system_profile.pb.h"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include <windows.h> // Needed for STATUS_* codes
#endif
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS)
#include "components/metrics/system_memory_stats_recorder.h"
#endif
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "base/android/application_status_listener.h"
#endif
@@ -49,7 +49,7 @@ enum RendererType {
// Converts an exit code into something that can be inserted into our
// histograms (which expect non-negative numbers less than MAX_INT).
int MapCrashExitCodeForHistogram(int exit_code) {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// Since |abs(STATUS_GUARD_PAGE_VIOLATION) == MAX_INT| it causes problems in
// histograms.cc. Solve this by remapping it to a smaller value, which
// hopefully doesn't conflict with other codes.
@@ -85,12 +85,6 @@ void StabilityMetricsHelper::ProvideStabilityMetrics(
local_state_->SetInteger(prefs::kStabilityPageLoadCount, 0);
}
- count = local_state_->GetInteger(prefs::kStabilityChildProcessCrashCount);
- if (count) {
- stability_proto->set_child_process_crash_count(count);
- local_state_->SetInteger(prefs::kStabilityChildProcessCrashCount, 0);
- }
-
count = local_state_->GetInteger(prefs::kStabilityGpuCrashCount);
if (count) {
stability_proto->set_gpu_crash_count(count);
@@ -130,12 +124,6 @@ void StabilityMetricsHelper::ProvideStabilityMetrics(
prefs::kStabilityExtensionRendererFailedLaunchCount, 0);
}
- count = local_state_->GetInteger(prefs::kStabilityRendererHangCount);
- if (count) {
- stability_proto->set_renderer_hang_count(count);
- local_state_->SetInteger(prefs::kStabilityRendererHangCount, 0);
- }
-
count =
local_state_->GetInteger(prefs::kStabilityExtensionRendererLaunchCount);
if (count) {
@@ -146,7 +134,6 @@ void StabilityMetricsHelper::ProvideStabilityMetrics(
void StabilityMetricsHelper::ClearSavedStabilityMetrics() {
// Clear all the prefs used in this class in UMA reports.
- local_state_->SetInteger(prefs::kStabilityChildProcessCrashCount, 0);
local_state_->SetInteger(prefs::kStabilityExtensionRendererCrashCount, 0);
local_state_->SetInteger(prefs::kStabilityExtensionRendererFailedLaunchCount,
0);
@@ -155,13 +142,11 @@ void StabilityMetricsHelper::ClearSavedStabilityMetrics() {
local_state_->SetInteger(prefs::kStabilityPageLoadCount, 0);
local_state_->SetInteger(prefs::kStabilityRendererCrashCount, 0);
local_state_->SetInteger(prefs::kStabilityRendererFailedLaunchCount, 0);
- local_state_->SetInteger(prefs::kStabilityRendererHangCount, 0);
local_state_->SetInteger(prefs::kStabilityRendererLaunchCount, 0);
}
// static
void StabilityMetricsHelper::RegisterPrefs(PrefRegistrySimple* registry) {
- registry->RegisterIntegerPref(prefs::kStabilityChildProcessCrashCount, 0);
registry->RegisterIntegerPref(prefs::kStabilityExtensionRendererCrashCount,
0);
registry->RegisterIntegerPref(
@@ -172,7 +157,6 @@ void StabilityMetricsHelper::RegisterPrefs(PrefRegistrySimple* registry) {
registry->RegisterIntegerPref(prefs::kStabilityPageLoadCount, 0);
registry->RegisterIntegerPref(prefs::kStabilityRendererCrashCount, 0);
registry->RegisterIntegerPref(prefs::kStabilityRendererFailedLaunchCount, 0);
- registry->RegisterIntegerPref(prefs::kStabilityRendererHangCount, 0);
registry->RegisterIntegerPref(prefs::kStabilityRendererLaunchCount, 0);
}
@@ -183,6 +167,7 @@ void StabilityMetricsHelper::IncreaseRendererCrashCount() {
void StabilityMetricsHelper::IncreaseGpuCrashCount() {
IncrementPrefValue(prefs::kStabilityGpuCrashCount);
+ local_state_->CommitPendingWrite(); // Schedule a Local State write.
RecordStabilityEvent(StabilityEventType::kGpuCrash);
}
@@ -190,6 +175,7 @@ void StabilityMetricsHelper::BrowserUtilityProcessLaunched(
const std::string& metrics_name) {
uint32_t hash = variations::HashName(metrics_name);
base::UmaHistogramSparse("ChildProcess.Launched.UtilityProcessHash", hash);
+ RecordStabilityEvent(StabilityEventType::kUtilityLaunch);
}
void StabilityMetricsHelper::BrowserUtilityProcessCrashed(
@@ -199,11 +185,28 @@ void StabilityMetricsHelper::BrowserUtilityProcessCrashed(
base::UmaHistogramSparse("ChildProcess.Crashed.UtilityProcessHash", hash);
base::UmaHistogramSparse("ChildProcess.Crashed.UtilityProcessExitCode",
exit_code);
+ RecordStabilityEvent(StabilityEventType::kUtilityCrash);
}
-void StabilityMetricsHelper::BrowserChildProcessCrashed() {
- IncrementPrefValue(prefs::kStabilityChildProcessCrashCount);
- RecordStabilityEvent(StabilityEventType::kChildProcessCrash);
+void StabilityMetricsHelper::BrowserUtilityProcessLaunchFailed(
+ const std::string& metrics_name,
+ int launch_error_code
+#if BUILDFLAG(IS_WIN)
+ ,
+ DWORD last_error
+#endif
+) {
+ uint32_t hash = variations::HashName(metrics_name);
+ base::UmaHistogramSparse("ChildProcess.LaunchFailed.UtilityProcessHash",
+ hash);
+ base::UmaHistogramSparse("ChildProcess.LaunchFailed.UtilityProcessErrorCode",
+ launch_error_code);
+#if BUILDFLAG(IS_WIN)
+ base::UmaHistogramSparse("ChildProcess.LaunchFailed.WinLastError",
+ last_error);
+#endif
+ // TODO(wfh): Decide if this utility process launch failure should also
+ // trigger a Stability Event.
}
void StabilityMetricsHelper::LogLoadStarted() {
@@ -245,12 +248,12 @@ void StabilityMetricsHelper::LogRendererCrash(bool was_extension_process,
case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
RecordChildKills(histogram_type);
break;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
case base::TERMINATION_STATUS_OOM_PROTECTED:
// TODO(wfh): Check if this should be a Kill or a Crash on Android.
break;
#endif
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS)
case base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM:
RecordChildKills(histogram_type);
base::UmaHistogramExactLinear("BrowserRenderProcessHost.ChildKills.OOM",
@@ -275,7 +278,7 @@ void StabilityMetricsHelper::LogRendererCrash(bool was_extension_process,
"BrowserRenderProcessHost.ChildLaunchFailureCodes", exit_code);
LogRendererLaunchFailed(was_extension_process);
break;
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
case base::TERMINATION_STATUS_INTEGRITY_FAILURE:
base::UmaHistogramEnumeration(
"BrowserRenderProcessHost.ChildCodeIntegrityFailures", histogram_type,
@@ -309,11 +312,6 @@ void StabilityMetricsHelper::LogRendererLaunchFailed(
: prefs::kStabilityRendererFailedLaunchCount;
RecordStabilityEvent(metric);
IncrementPrefValue(pref);
- // TODO(crbug/1278145): Remove the scheduled write if it doesn't help resolve
- // the discrepancy.
- // Schedule a Local State write to help diagnose a discrepancy with
- // Stability.Counts.
- local_state_->CommitPendingWrite();
}
void StabilityMetricsHelper::IncrementPrefValue(const char* path) {
@@ -322,7 +320,7 @@ void StabilityMetricsHelper::IncrementPrefValue(const char* path) {
}
void StabilityMetricsHelper::LogRendererHang() {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
base::android::ApplicationState app_state =
base::android::ApplicationStatusListener::GetState();
bool is_foreground =
@@ -334,8 +332,6 @@ void StabilityMetricsHelper::LogRendererHang() {
base::UmaHistogramMemoryMB(
"ChildProcess.HungRendererAvailableMemoryMB",
base::SysInfo::AmountOfAvailablePhysicalMemory() / 1024 / 1024);
- IncrementPrefValue(prefs::kStabilityRendererHangCount);
- RecordStabilityEvent(StabilityEventType::kRendererHang);
}
// static
diff --git a/chromium/components/metrics/stability_metrics_helper.h b/chromium/components/metrics/stability_metrics_helper.h
index 5f09aa66fa6..66409d0ef5d 100644
--- a/chromium/components/metrics/stability_metrics_helper.h
+++ b/chromium/components/metrics/stability_metrics_helper.h
@@ -9,6 +9,11 @@
#include "base/memory/raw_ptr.h"
#include "base/process/kill.h"
+#include "build/build_config.h"
+
+#if BUILDFLAG(IS_WIN)
+#include "base/win/windows_types.h"
+#endif
class PrefRegistrySimple;
class PrefService;
@@ -24,16 +29,19 @@ enum class StabilityEventType {
kRendererCrash = 3,
kRendererHang = 4,
kExtensionCrash = 5,
- kChildProcessCrash = 6,
+ // kChildProcessCrash = 6, // Removed due to disuse and alternative metrics.
kLaunch = 15,
kBrowserCrash = 16,
// kIncompleteShutdown = 17, // Removed due to disuse and correctness issues.
+ kPluginCrash = 22,
kRendererFailedLaunch = 24,
kExtensionRendererFailedLaunch = 25,
kRendererLaunch = 26,
kExtensionRendererLaunch = 27,
kGpuCrash = 31,
- kMaxValue = kGpuCrash
+ kUtilityCrash = 32,
+ kUtilityLaunch = 33,
+ kMaxValue = kUtilityLaunch,
};
class SystemProfileProto;
@@ -62,8 +70,16 @@ class StabilityMetricsHelper {
void BrowserUtilityProcessCrashed(const std::string& metrics_name,
int exit_code);
- // Records a browser child process crash.
- void BrowserChildProcessCrashed();
+ // Records that a utility process with name |metrics_name| failed to launch.
+ // The |launch_error_code| is a platform-specific error code. On Windows, a
+ // |last_error| is also supplied to help diagnose the launch failure.
+ void BrowserUtilityProcessLaunchFailed(const std::string& metrics_name,
+ int launch_error_code
+#if BUILDFLAG(IS_WIN)
+ ,
+ DWORD last_error
+#endif
+ );
// Logs the initiation of a page load.
void LogLoadStarted();
diff --git a/chromium/components/metrics/stability_metrics_helper_unittest.cc b/chromium/components/metrics/stability_metrics_helper_unittest.cc
index ea11527d192..dc3205b3141 100644
--- a/chromium/components/metrics/stability_metrics_helper_unittest.cc
+++ b/chromium/components/metrics/stability_metrics_helper_unittest.cc
@@ -47,28 +47,6 @@ class StabilityMetricsHelperTest : public testing::Test {
} // namespace
-TEST_F(StabilityMetricsHelperTest, BrowserChildProcessCrashed) {
- StabilityMetricsHelper helper(prefs());
- base::HistogramTester histogram_tester;
-
- helper.BrowserChildProcessCrashed();
- helper.BrowserChildProcessCrashed();
-
- // Call ProvideStabilityMetrics to check that it will force pending tasks to
- // be executed immediately.
- metrics::SystemProfileProto system_profile;
-
- helper.ProvideStabilityMetrics(&system_profile);
-
- // Check current number of instances created.
- const metrics::SystemProfileProto_Stability& stability =
- system_profile.stability();
-
- EXPECT_EQ(2, stability.child_process_crash_count());
- histogram_tester.ExpectUniqueSample(
- "Stability.Counts2", StabilityEventType::kChildProcessCrash, 2);
-}
-
TEST_F(StabilityMetricsHelperTest, LogRendererCrash) {
StabilityMetricsHelper helper(prefs());
base::HistogramTester histogram_tester;
diff --git a/chromium/components/metrics/stability_metrics_provider.cc b/chromium/components/metrics/stability_metrics_provider.cc
index d5157bf942a..8afdf546de0 100644
--- a/chromium/components/metrics/stability_metrics_provider.cc
+++ b/chromium/components/metrics/stability_metrics_provider.cc
@@ -16,10 +16,10 @@
#include "components/prefs/scoped_user_pref_update.h"
#include "third_party/metrics_proto/system_profile.pb.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "base/android/build_info.h"
#endif
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include "components/metrics/system_session_analyzer/system_session_analyzer_win.h"
#endif
@@ -27,7 +27,7 @@ namespace metrics {
namespace {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
bool HasGmsCoreVersionChanged(PrefService* local_state) {
std::string previous_version =
local_state->GetString(prefs::kStabilityGmsCoreVersion);
@@ -64,18 +64,18 @@ void StabilityMetricsProvider::RegisterPrefs(PrefRegistrySimple* registry) {
registry->RegisterIntegerPref(prefs::kStabilityFileMetricsUnsentSamplesCount,
0);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
registry->RegisterStringPref(prefs::kStabilityGmsCoreVersion, "");
registry->RegisterIntegerPref(prefs::kStabilityCrashCountDueToGmsCoreUpdate,
0);
#endif
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
registry->RegisterIntegerPref(prefs::kStabilitySystemCrashCount, 0);
#endif
}
void StabilityMetricsProvider::Init() {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// This method has to be called after HasGmsCoreVersionChanged() to avoid
// overwriting thie result.
UpdateGmsCoreVersionPref(local_state_);
@@ -91,7 +91,7 @@ void StabilityMetricsProvider::ClearSavedStabilityMetrics() {
local_state_->ClearPref(prefs::kStabilityFileMetricsUnsentFilesCount);
local_state_->ClearPref(prefs::kStabilityFileMetricsUnsentSamplesCount);
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
local_state_->SetInteger(prefs::kStabilitySystemCrashCount, 0);
#endif
}
@@ -109,7 +109,7 @@ void StabilityMetricsProvider::ProvideStabilityMetrics(
if (GetAndClearPrefValue(prefs::kStabilityCrashCount, &pref_value))
stability->set_crash_count(pref_value);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
if (GetAndClearPrefValue(prefs::kStabilityCrashCountDueToGmsCoreUpdate,
&pref_value)) {
stability->set_crash_count_due_to_gms_core_update(pref_value);
@@ -135,7 +135,7 @@ void StabilityMetricsProvider::ProvideStabilityMetrics(
local_state_->ClearPref(prefs::kStabilityFileMetricsUnsentSamplesCount);
}
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
if (GetAndClearPrefValue(prefs::kStabilitySystemCrashCount, &pref_value)) {
UMA_STABILITY_HISTOGRAM_COUNTS_100("Stability.Internals.SystemCrashCount",
pref_value);
@@ -144,7 +144,7 @@ void StabilityMetricsProvider::ProvideStabilityMetrics(
}
void StabilityMetricsProvider::LogCrash(base::Time last_live_timestamp) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// On Android, if there is an update for GMS Core when Chrome is running,
// Chrome will be killed, counting as a crash. This is expected and should not
// be counted in stability crash counts. Thus these crashes are added to a
@@ -158,7 +158,7 @@ void StabilityMetricsProvider::LogCrash(base::Time last_live_timestamp) {
StabilityMetricsHelper::RecordStabilityEvent(
StabilityEventType::kBrowserCrash);
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
MaybeLogSystemCrash(last_live_timestamp);
#endif
}
@@ -168,7 +168,7 @@ void StabilityMetricsProvider::LogLaunch() {
StabilityMetricsHelper::RecordStabilityEvent(StabilityEventType::kLaunch);
}
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
bool StabilityMetricsProvider::IsUncleanSystemSession(
base::Time last_live_timestamp) {
DCHECK_NE(base::Time(), last_live_timestamp);
diff --git a/chromium/components/metrics/stability_metrics_provider.h b/chromium/components/metrics/stability_metrics_provider.h
index abea6ac673c..8e04c30dce6 100644
--- a/chromium/components/metrics/stability_metrics_provider.h
+++ b/chromium/components/metrics/stability_metrics_provider.h
@@ -33,7 +33,7 @@ class StabilityMetricsProvider : public MetricsProvider {
void LogLaunch();
private:
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// This function is virtual for testing. The |last_live_timestamp| is a
// time point where the previous browser was known to be alive, and is used
// to determine whether the system session embedding that timestamp terminated
diff --git a/chromium/components/metrics/stability_metrics_provider_unittest.cc b/chromium/components/metrics/stability_metrics_provider_unittest.cc
index 17be0767bc4..cc96636f862 100644
--- a/chromium/components/metrics/stability_metrics_provider_unittest.cc
+++ b/chromium/components/metrics/stability_metrics_provider_unittest.cc
@@ -73,7 +73,7 @@ TEST_F(StabilityMetricsProviderTest, RecordStabilityMetrics) {
}
}
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
namespace {
class TestingStabilityMetricsProvider : public StabilityMetricsProvider {
diff --git a/chromium/components/metrics/structured/external_metrics_unittest.cc b/chromium/components/metrics/structured/external_metrics_unittest.cc
index 4446e14e093..fb6ff915d50 100644
--- a/chromium/components/metrics/structured/external_metrics_unittest.cc
+++ b/chromium/components/metrics/structured/external_metrics_unittest.cc
@@ -3,12 +3,14 @@
// found in the LICENSE file.
#include "components/metrics/structured/external_metrics.h"
+#include "components/metrics/structured/structured_metrics_features.h"
#include <memory>
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/logging.h"
+#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "components/metrics/structured/storage.pb.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -52,7 +54,15 @@ void AssertEqualsTestingProto(const EventsProto& proto,
class ExternalMetricsTest : public testing::Test {
public:
- void SetUp() override { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); }
+ void SetUp() override {
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+
+ // TODO(b/181724341): Remove this when the bluetooth metrics feature is
+ // enabled by default.
+ scoped_feature_list_.InitWithFeatures(
+ /*enabled_features=*/{},
+ /*disabled_features=*/{kBluetoothSessionizedMetrics});
+ }
void Init() {
// We don't use the scheduling feature when testing ExternalMetrics, instead
@@ -86,6 +96,7 @@ class ExternalMetricsTest : public testing::Test {
void Wait() { task_environment_.RunUntilIdle(); }
+ base::test::ScopedFeatureList scoped_feature_list_;
base::ScopedTempDir temp_dir_;
std::unique_ptr<ExternalMetrics> external_metrics_;
absl::optional<EventsProto> proto_;
diff --git a/chromium/components/metrics/structured/histogram_util.cc b/chromium/components/metrics/structured/histogram_util.cc
index 3b497bd0d75..702abd88565 100644
--- a/chromium/components/metrics/structured/histogram_util.cc
+++ b/chromium/components/metrics/structured/histogram_util.cc
@@ -26,11 +26,6 @@ void LogKeyValidation(KeyValidationState state) {
UMA_HISTOGRAM_ENUMERATION("UMA.StructuredMetrics.KeyValidationState", state);
}
-void LogClientInitializationSuccessful(bool success) {
- UMA_HISTOGRAM_BOOLEAN("UMA.StructuredMetrics.ClientInitializationSuccessful",
- success);
-}
-
void LogIsEventRecordedUsingMojo(bool used_mojo_api) {
UMA_HISTOGRAM_BOOLEAN("UMA.StructuredMetrics.EventsRecordedUsingMojo",
used_mojo_api);
diff --git a/chromium/components/metrics/structured/histogram_util.h b/chromium/components/metrics/structured/histogram_util.h
index e810723dd07..c79ee550f38 100644
--- a/chromium/components/metrics/structured/histogram_util.h
+++ b/chromium/components/metrics/structured/histogram_util.h
@@ -66,8 +66,6 @@ void LogKeyValidation(KeyValidationState state);
// ProvideCurrentSessionData.
void LogNumEventsInUpload(int num_events);
-void LogClientInitializationSuccessful(bool success);
-
// Logs that an event was recorded using the mojo API.
void LogIsEventRecordedUsingMojo(bool used_mojo_api);
diff --git a/chromium/components/metrics/structured/recorder.cc b/chromium/components/metrics/structured/recorder.cc
index da7f99d9f2e..34fdb163e0b 100644
--- a/chromium/components/metrics/structured/recorder.cc
+++ b/chromium/components/metrics/structured/recorder.cc
@@ -8,6 +8,7 @@
#include "base/bind.h"
#include "base/feature_list.h"
+#include "base/no_destructor.h"
#include "base/task/current_thread.h"
#include "base/task/post_task.h"
#include "components/metrics/structured/event_base.h"
diff --git a/chromium/components/metrics/structured/structured_metrics_features.cc b/chromium/components/metrics/structured/structured_metrics_features.cc
index 4023d198ef2..c98b74a3a7f 100644
--- a/chromium/components/metrics/structured/structured_metrics_features.cc
+++ b/chromium/components/metrics/structured/structured_metrics_features.cc
@@ -14,7 +14,7 @@ const base::Feature kStructuredMetrics{"EnableStructuredMetrics",
// TODO(b/181724341): Remove this experimental once the feature is rolled out.
const base::Feature kBluetoothSessionizedMetrics{
- "BluetoothSessionizedMetrics", base::FEATURE_DISABLED_BY_DEFAULT};
+ "BluetoothSessionizedMetrics", base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kUseCrosApiInterface{"UseCrosApiInterface",
base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/chromium/components/metrics/structured/structured_metrics_provider.cc b/chromium/components/metrics/structured/structured_metrics_provider.cc
index 3114014df7a..210466bc751 100644
--- a/chromium/components/metrics/structured/structured_metrics_provider.cc
+++ b/chromium/components/metrics/structured/structured_metrics_provider.cc
@@ -106,9 +106,11 @@ void StructuredMetricsProvider::OnWrite(const WriteStatus status) {
void StructuredMetricsProvider::OnExternalMetricsCollected(
const EventsProto& events) {
DCHECK(base::CurrentUIThread::IsSet());
- events_.get()->get()->mutable_uma_events()->MergeFrom(events.uma_events());
- events_.get()->get()->mutable_non_uma_events()->MergeFrom(
- events.non_uma_events());
+ if (recording_enabled_) {
+ events_.get()->get()->mutable_uma_events()->MergeFrom(events.uma_events());
+ events_.get()->get()->mutable_non_uma_events()->MergeFrom(
+ events.non_uma_events());
+ }
}
void StructuredMetricsProvider::Purge() {
diff --git a/chromium/components/metrics/structured/structured_metrics_provider_unittest.cc b/chromium/components/metrics/structured/structured_metrics_provider_unittest.cc
index 26c5cf4d9b8..e863ca358a9 100644
--- a/chromium/components/metrics/structured/structured_metrics_provider_unittest.cc
+++ b/chromium/components/metrics/structured/structured_metrics_provider_unittest.cc
@@ -667,6 +667,24 @@ TEST_F(StructuredMetricsProviderTest, ExternalMetricsAreReported) {
EXPECT_EQ(GetSessionData().events_size(), 3);
}
+TEST_F(StructuredMetricsProviderTest,
+ ExternalMetricsDroppedWhenRecordingDisabled) {
+ const base::FilePath events_dir(TempDirPath().Append("events"));
+ base::CreateDirectory(events_dir);
+
+ const auto proto = MakeExternalEventProto({111, 222, 333});
+ ASSERT_TRUE(
+ base::WriteFile(events_dir.Append("event"), proto.SerializeAsString()));
+
+ provider_ = std::make_unique<StructuredMetricsProvider>();
+ OnProfileAdded(TempDirPath());
+ OnRecordingDisabled();
+ SetExternalMetricsDirForTest(events_dir);
+ task_environment_.AdvanceClock(base::Hours(10));
+ Wait();
+ EXPECT_EQ(GetSessionData().events_size(), 0);
+}
+
// Test that events reported at various stages before and during initialization
// are ignored (and don't cause a crash).
TEST_F(StructuredMetricsProviderTest, EventsNotRecordedBeforeInitialization) {
diff --git a/chromium/components/metrics/ui/screen_info_metrics_provider.cc b/chromium/components/metrics/ui/screen_info_metrics_provider.cc
index 7dcbcd608a1..20111512a57 100644
--- a/chromium/components/metrics/ui/screen_info_metrics_provider.cc
+++ b/chromium/components/metrics/ui/screen_info_metrics_provider.cc
@@ -11,13 +11,13 @@
#include "ui/display/display.h"
#include "ui/display/screen.h"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include <windows.h>
#endif
namespace metrics {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
namespace {
@@ -58,7 +58,7 @@ void WriteScreenDPIInformationProto(SystemProfileProto::Hardware* hardware) {
} // namespace
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
ScreenInfoMetricsProvider::ScreenInfoMetricsProvider() {
}
@@ -82,7 +82,7 @@ void ScreenInfoMetricsProvider::ProvideSystemProfileMetrics(
hardware->set_primary_screen_scale_factor(GetScreenDeviceScaleFactor());
hardware->set_screen_count(GetScreenCount());
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
WriteScreenDPIInformationProto(hardware);
#endif
}
diff --git a/chromium/components/metrics/unsent_log_store.cc b/chromium/components/metrics/unsent_log_store.cc
index c77358386c2..6b0ce7cebe6 100644
--- a/chromium/components/metrics/unsent_log_store.cc
+++ b/chromium/components/metrics/unsent_log_store.cc
@@ -237,19 +237,19 @@ void UnsentLogStore::Purge() {
local_state_->ClearPref(metadata_pref_name_);
}
-void UnsentLogStore::ReadLogsFromPrefList(const base::ListValue& list_value) {
- if (list_value.GetList().empty()) {
+void UnsentLogStore::ReadLogsFromPrefList(const base::Value& list_value) {
+ if (list_value.GetListDeprecated().empty()) {
metrics_->RecordLogReadStatus(UnsentLogStoreMetrics::LIST_EMPTY);
return;
}
- const size_t log_count = list_value.GetList().size();
+ const size_t log_count = list_value.GetListDeprecated().size();
DCHECK(list_.empty());
list_.resize(log_count);
for (size_t i = 0; i < log_count; ++i) {
- const base::Value& value = list_value.GetList()[i];
+ const base::Value& value = list_value.GetListDeprecated()[i];
const base::DictionaryValue* dict = nullptr;
if (value.is_dict())
dict = &base::Value::AsDictionaryValue(value);
@@ -335,24 +335,23 @@ void UnsentLogStore::TrimLogs() {
}
}
-void UnsentLogStore::WriteLogsToPrefList(base::ListValue* list_value) const {
+void UnsentLogStore::WriteLogsToPrefList(base::Value* list_value) const {
list_value->ClearList();
base::HistogramBase::Count unsent_samples_count = 0;
size_t unsent_persisted_size = 0;
for (auto& log : list_) {
- std::unique_ptr<base::DictionaryValue> dict_value(
- new base::DictionaryValue);
- dict_value->SetString(kLogHashKey, EncodeToBase64(log->hash));
- dict_value->SetString(kLogSignatureKey, EncodeToBase64(log->signature));
- dict_value->SetString(kLogDataKey,
- EncodeToBase64(log->compressed_log_data));
- dict_value->SetString(kLogTimestampKey, log->timestamp);
+ base::Value dict_value{base::Value::Type::DICTIONARY};
+ dict_value.SetStringKey(kLogHashKey, EncodeToBase64(log->hash));
+ dict_value.SetStringKey(kLogSignatureKey, EncodeToBase64(log->signature));
+ dict_value.SetStringKey(kLogDataKey,
+ EncodeToBase64(log->compressed_log_data));
+ dict_value.SetStringKey(kLogTimestampKey, log->timestamp);
auto user_id = log->log_metadata.user_id;
if (user_id.has_value()) {
- dict_value->SetString(
+ dict_value.SetStringKey(
kLogUserIdKey, EncodeToBase64(base::NumberToString(user_id.value())));
}
list_value->Append(std::move(dict_value));
@@ -375,7 +374,7 @@ void UnsentLogStore::WriteToMetricsPref(
return;
DictionaryPrefUpdate update(local_state_, metadata_pref_name_);
- base::DictionaryValue* pref_data = update.Get();
+ base::Value* pref_data = update.Get();
pref_data->SetKey(kLogUnsentCountKey, base::Value(unsent_samples_count));
pref_data->SetKey(kLogSentCountKey, base::Value(sent_samples_count));
// Round up to kb.
@@ -388,8 +387,7 @@ void UnsentLogStore::RecordMetaDataMetrics() {
if (metadata_pref_name_ == nullptr)
return;
- const base::DictionaryValue* value =
- local_state_->GetDictionary(metadata_pref_name_);
+ const base::Value* value = local_state_->GetDictionary(metadata_pref_name_);
if (!value)
return;
diff --git a/chromium/components/metrics/unsent_log_store.h b/chromium/components/metrics/unsent_log_store.h
index 3a59d097cef..5bf1f69ea11 100644
--- a/chromium/components/metrics/unsent_log_store.h
+++ b/chromium/components/metrics/unsent_log_store.h
@@ -112,10 +112,10 @@ class UnsentLogStore : public LogStore {
void TrimLogs();
// Writes the list of logs to |list|.
- void WriteLogsToPrefList(base::ListValue* list) const;
+ void WriteLogsToPrefList(base::Value* list) const;
// Reads the list of logs from |list|.
- void ReadLogsFromPrefList(const base::ListValue& list);
+ void ReadLogsFromPrefList(const base::Value& list);
// Writes the unsent log info to the |metadata_pref_name_| preference.
void WriteToMetricsPref(base::HistogramBase::Count unsent_samples_count,
diff --git a/chromium/components/metrics/unsent_log_store_unittest.cc b/chromium/components/metrics/unsent_log_store_unittest.cc
index 7d923be049f..c79ce104872 100644
--- a/chromium/components/metrics/unsent_log_store_unittest.cc
+++ b/chromium/components/metrics/unsent_log_store_unittest.cc
@@ -138,8 +138,8 @@ TEST_F(UnsentLogStoreTest, EmptyLogList) {
TestUnsentLogStore unsent_log_store(&prefs_, kLogByteLimit);
unsent_log_store.TrimAndPersistUnsentLogs();
- const base::ListValue* list_value = prefs_.GetList(kTestPrefName);
- EXPECT_EQ(0U, list_value->GetList().size());
+ const base::Value* list_value = prefs_.GetList(kTestPrefName);
+ EXPECT_EQ(0U, list_value->GetListDeprecated().size());
TestUnsentLogStore result_unsent_log_store(&prefs_, kLogByteLimit);
result_unsent_log_store.LoadPersistedUnsentLogs();
diff --git a/chromium/components/metrics/version_utils.cc b/chromium/components/metrics/version_utils.cc
index 562450340d4..6b17690da8d 100644
--- a/chromium/components/metrics/version_utils.cc
+++ b/chromium/components/metrics/version_utils.cc
@@ -9,7 +9,7 @@
#include "build/build_config.h"
#include "components/version_info/version_info.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "base/android/build_info.h"
#endif
@@ -49,7 +49,7 @@ SystemProfileProto::Channel AsProtobufChannel(version_info::Channel channel) {
}
std::string GetAppPackageName() {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
return base::android::BuildInfo::GetInstance()->package_name();
#else
return std::string();
diff --git a/chromium/components/minidump_uploader/BUILD.gn b/chromium/components/minidump_uploader/BUILD.gn
index c6ae7a39939..bf257d3d595 100644
--- a/chromium/components/minidump_uploader/BUILD.gn
+++ b/chromium/components/minidump_uploader/BUILD.gn
@@ -17,6 +17,9 @@ static_library("minidump_uploader") {
deps = [
":minidump_uploader_jni_headers",
"//base",
+ "//components/crash/android:anr_skipped_reason",
+ "//components/version_info",
+ "//components/version_info/android:channel_getter",
"//third_party/crashpad/crashpad/client",
"//third_party/crashpad/crashpad/handler",
"//third_party/crashpad/crashpad/snapshot",
@@ -28,6 +31,8 @@ static_library("minidump_uploader") {
android_library("minidump_uploader_java") {
deps = [
"//base:base_java",
+ "//components/crash/android:anr_collector_java",
+ "//net/android:net_java",
"//third_party/androidx:androidx_annotation_annotation_java",
]
diff --git a/chromium/components/minidump_uploader/DEPS b/chromium/components/minidump_uploader/DEPS
index b164637815e..2fe865c7442 100644
--- a/chromium/components/minidump_uploader/DEPS
+++ b/chromium/components/minidump_uploader/DEPS
@@ -1,4 +1,7 @@
include_rules = [
"+components/minidump_uploader/minidump_uploader_jni_headers",
+ "+components/crash/android",
+ "+components/version_info",
+ "+net",
"+third_party/crashpad",
]
diff --git a/chromium/components/minidump_uploader/OWNERS b/chromium/components/minidump_uploader/OWNERS
index 340c57928d1..c1dcc7b2be7 100644
--- a/chromium/components/minidump_uploader/OWNERS
+++ b/chromium/components/minidump_uploader/OWNERS
@@ -1 +1,2 @@
-isherman@chromium.org
+hazems@chromium.org
+wnwen@chromium.org
diff --git a/chromium/components/minidump_uploader/rewrite_minidumps_as_mimes.cc b/chromium/components/minidump_uploader/rewrite_minidumps_as_mimes.cc
index e5c9bbdbffa..0dbdc37b57c 100644
--- a/chromium/components/minidump_uploader/rewrite_minidumps_as_mimes.cc
+++ b/chromium/components/minidump_uploader/rewrite_minidumps_as_mimes.cc
@@ -6,13 +6,17 @@
#include <utility>
+#include "base/android/build_info.h"
#include "base/android/jni_array.h"
#include "base/android/jni_string.h"
#include "base/metrics/histogram_macros.h"
#include "base/notreached.h"
#include "base/strings/stringprintf.h"
#include "build/build_config.h"
+#include "components/crash/android/anr_skipped_reason.h"
#include "components/minidump_uploader/minidump_uploader_jni_headers/CrashReportMimeWriter_jni.h"
+#include "components/version_info/android/channel_getter.h"
+#include "components/version_info/version_info.h"
#include "third_party/crashpad/crashpad/handler/minidump_to_upload_parameters.h"
#include "third_party/crashpad/crashpad/snapshot/exception_snapshot.h"
#include "third_party/crashpad/crashpad/snapshot/minidump/process_snapshot_minidump.h"
@@ -25,7 +29,7 @@ namespace minidump_uploader {
namespace {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
enum class ProcessedMinidumpCounts {
@@ -36,7 +40,7 @@ enum class ProcessedMinidumpCounts {
kUtility = 4,
kMaxValue = kUtility
};
-#endif // OS_ANDROID
+#endif // BUILDFLAG(IS_ANDROID)
bool MimeifyReportWithKeyValuePairs(
const crashpad::CrashReportDatabase::UploadReport& report,
@@ -77,7 +81,7 @@ bool MimeifyReportWithKeyValuePairs(
crashes_key_value_arr->push_back(kv.first);
crashes_key_value_arr->push_back(kv.second);
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
if (kv.first == kPtypeKey) {
const crashpad::ExceptionSnapshot* exception =
minidump_process_snapshot.Exception();
@@ -106,7 +110,7 @@ bool MimeifyReportWithKeyValuePairs(
}
// TODO(wnwen): Add histogram for number of null exceptions.
}
-#endif // OS_ANDROID
+#endif // BUILDFLAG(IS_ANDROID)
}
}
@@ -216,6 +220,80 @@ void RewriteMinidumpsAsMIMEs(const base::FilePath& src_dir,
}
}
+static void reportAnrUploadFailure(AnrSkippedReason reason) {
+ UMA_HISTOGRAM_ENUMERATION("Crashpad.AnrUpload.Skipped", reason);
+}
+
+static void WriteAnrAsMime(crashpad::FileReader* anr_reader,
+ crashpad::FileWriter* writer,
+ const std::string& version_number,
+ const std::string& anr_file_name) {
+ static constexpr char kAnrKey[] = "anr_data";
+
+ crashpad::HTTPMultipartBuilder builder;
+ builder.SetFormData("version", version_number);
+ builder.SetFormData("product", "Chrome_Android");
+ std::string channel =
+ version_info::GetChannelString(version_info::android::GetChannel());
+ builder.SetFormData("channel", channel);
+
+ // We can't use crashpad::AnnotationList::Get() as it contains a number of
+ // fields which change on each Chrome restart.
+ base::android::BuildInfo* info = base::android::BuildInfo::GetInstance();
+ builder.SetFormData("android_build_id", info->android_build_id());
+ builder.SetFormData("android_build_fp", info->android_build_fp());
+ builder.SetFormData("sdk", base::StringPrintf("%d", info->sdk_int()));
+ builder.SetFormData("device", info->device());
+ builder.SetFormData("model", info->model());
+ builder.SetFormData("brand", info->brand());
+ builder.SetFormData("board", info->board());
+ builder.SetFormData("installer_package_name", info->installer_package_name());
+ builder.SetFormData("abi_name", info->abi_name());
+ builder.SetFormData("custom_themes", info->custom_themes());
+ builder.SetFormData("resources_version", info->resources_version());
+ builder.SetFormData("gms_core_version", info->gms_version_code());
+ builder.SetFileAttachment(kAnrKey, anr_file_name, anr_reader,
+ "application/octet-stream");
+ if (!WriteBodyToFile(builder.GetBodyStream().get(), writer)) {
+ reportAnrUploadFailure(AnrSkippedReason::kFilesystemWriteFailure);
+ }
+}
+
+static void JNI_CrashReportMimeWriter_RewriteAnrsAsMIMEs(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobjectArray>& j_anr_files,
+ const base::android::JavaParamRef<jobjectArray>& j_version_numbers,
+ const base::android::JavaParamRef<jstring>& j_dest_dir) {
+ std::vector<std::string> anr_files;
+ AppendJavaStringArrayToStringVector(env, j_anr_files, &anr_files);
+ std::vector<std::string> version_numbers;
+ AppendJavaStringArrayToStringVector(env, j_version_numbers, &version_numbers);
+ // We are assuming a 1:1 mapping between an ANR and its version number.
+ DCHECK_EQ(anr_files.size(), version_numbers.size());
+ std::string dest_dir;
+ base::android::ConvertJavaStringToUTF8(env, j_dest_dir, &dest_dir);
+
+ for (size_t i = 0; i < anr_files.size(); ++i) {
+ crashpad::FileWriter writer;
+ crashpad::FileReader reader;
+ crashpad::UUID uuid;
+ uuid.InitializeWithNew();
+ std::string anr_file_name = uuid.ToString() + "_ANR.dmp";
+ if (!reader.Open(base::FilePath(anr_files[i]))) {
+ reportAnrUploadFailure(AnrSkippedReason::kFilesystemReadFailure);
+ continue;
+ }
+ if (!writer.Open(base::FilePath(dest_dir).Append(anr_file_name),
+ crashpad::FileWriteMode::kCreateOrFail,
+ crashpad::FilePermissions::kOwnerOnly)) {
+ reportAnrUploadFailure(AnrSkippedReason::kFilesystemWriteFailure);
+ continue;
+ }
+
+ WriteAnrAsMime(&reader, &writer, version_numbers[i], anr_file_name);
+ }
+}
+
static void JNI_CrashReportMimeWriter_RewriteMinidumpsAsMIMEs(
JNIEnv* env,
const base::android::JavaParamRef<jstring>& j_src_dir,
diff --git a/chromium/components/mirroring/browser/single_client_video_capture_host.cc b/chromium/components/mirroring/browser/single_client_video_capture_host.cc
index 11019526383..1b0de5e414a 100644
--- a/chromium/components/mirroring/browser/single_client_video_capture_host.cc
+++ b/chromium/components/mirroring/browser/single_client_video_capture_host.cc
@@ -186,6 +186,11 @@ void SingleClientVideoCaptureHost::OnFrameDropped(
// Ignore this call.
}
+void SingleClientVideoCaptureHost::OnFrameWithEmptyRegionCapture() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ // Ignore this call.
+}
+
void SingleClientVideoCaptureHost::OnLog(
const base::UnguessableToken& device_id,
const std::string& message) {
diff --git a/chromium/components/mirroring/browser/single_client_video_capture_host.h b/chromium/components/mirroring/browser/single_client_video_capture_host.h
index cb90c34bb8b..fca01ed805a 100644
--- a/chromium/components/mirroring/browser/single_client_video_capture_host.h
+++ b/chromium/components/mirroring/browser/single_client_video_capture_host.h
@@ -89,6 +89,7 @@ class SingleClientVideoCaptureHost final
void OnBufferRetired(int buffer_id) override;
void OnError(media::VideoCaptureError error) override;
void OnFrameDropped(media::VideoCaptureFrameDropReason reason) override;
+ void OnFrameWithEmptyRegionCapture() override;
void OnLog(const std::string& message) override;
void OnStarted() override;
void OnStartedUsingGpuDecode() override;
diff --git a/chromium/components/mirroring/browser/single_client_video_capture_host_unittest.cc b/chromium/components/mirroring/browser/single_client_video_capture_host_unittest.cc
index 416db33d02e..69d7581d408 100644
--- a/chromium/components/mirroring/browser/single_client_video_capture_host_unittest.cc
+++ b/chromium/components/mirroring/browser/single_client_video_capture_host_unittest.cc
@@ -47,8 +47,9 @@ class MockVideoCaptureDevice final
base::OnceClosure done_cb) override {}
MOCK_METHOD0(MaybeSuspendDevice, void());
MOCK_METHOD0(ResumeDevice, void());
- MOCK_METHOD2(Crop,
+ MOCK_METHOD3(Crop,
void(const base::Token&,
+ uint32_t,
base::OnceCallback<void(media::mojom::CropRequestResult)>));
MOCK_METHOD0(RequestRefreshFrame, void());
MOCK_METHOD2(OnUtilizationReport, void(int, media::VideoCaptureFeedback));
@@ -76,6 +77,12 @@ class FakeDeviceLauncher final : public content::VideoCaptureDeviceLauncher {
base::OnceClosure connection_lost_cb,
Callbacks* callbacks,
base::OnceClosure done_cb) override {
+ if (!params.IsValid()) {
+ callbacks->OnDeviceLaunchFailed(
+ media::VideoCaptureError::
+ kVideoCaptureControllerInvalidOrUnsupportedVideoCaptureParametersRequested);
+ return;
+ }
base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(&FakeDeviceLauncher::OnDeviceLaunched,
weak_factory_.GetWeakPtr(), receiver,
@@ -158,8 +165,12 @@ class MockVideoCaptureObserver final
OnVideoCaptureErrorCall(result->get_error_code());
}
- void Start() {
- host_->Start(device_id_, session_id_, VideoCaptureParams(),
+ void Start(bool valid_params) {
+ VideoCaptureParams params = VideoCaptureParams();
+ if (!valid_params)
+ params.requested_format.frame_rate = std::numeric_limits<float>::max();
+
+ host_->Start(device_id_, session_id_, params,
receiver_.BindNewPipeAndPassRemote());
}
@@ -194,7 +205,9 @@ media::mojom::VideoFrameInfoPtr GetVideoFrameInfo() {
class SingleClientVideoCaptureHostTest : public ::testing::Test {
public:
- SingleClientVideoCaptureHostTest() {
+ SingleClientVideoCaptureHostTest() = default;
+
+ void CustomSetUp(bool valid_params = true) {
auto host_impl = std::make_unique<SingleClientVideoCaptureHost>(
std::string(), blink::mojom::MediaStreamType::GUM_TAB_VIDEO_CAPTURE,
base::BindRepeating(
@@ -205,14 +218,25 @@ class SingleClientVideoCaptureHostTest : public ::testing::Test {
host.InitWithNewPipeAndPassReceiver());
consumer_ = std::make_unique<MockVideoCaptureObserver>(std::move(host));
base::RunLoop run_loop;
- EXPECT_CALL(*this, OnDeviceLaunchedCall())
- .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit));
- consumer_->Start();
+ if (valid_params) {
+ EXPECT_CALL(*this, OnDeviceLaunchedCall())
+ .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit));
+ } else {
+ EXPECT_CALL(
+ *consumer_,
+ OnVideoCaptureErrorCall(
+ media::VideoCaptureError::
+ kVideoCaptureControllerInvalidOrUnsupportedVideoCaptureParametersRequested))
+ .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit));
+ }
+ consumer_->Start(valid_params);
run_loop.Run();
- // The video capture device is launched.
- EXPECT_TRUE(launched_device_);
- EXPECT_TRUE(frame_receiver_);
+ if (valid_params) {
+ // The video capture device is launched.
+ EXPECT_TRUE(launched_device_);
+ EXPECT_TRUE(frame_receiver_);
+ }
}
~SingleClientVideoCaptureHostTest() override {
@@ -293,13 +317,19 @@ class SingleClientVideoCaptureHostTest : public ::testing::Test {
};
TEST_F(SingleClientVideoCaptureHostTest, Basic) {
+ CustomSetUp();
CreateBuffer(1, 0);
FrameReadyInBuffer(1, 0, 5);
FinishConsumingBuffer(0, 5, media::VideoCaptureFeedback(1.0));
RetireBuffer(1, 0);
}
+TEST_F(SingleClientVideoCaptureHostTest, InvalidParams) {
+ CustomSetUp(false);
+}
+
TEST_F(SingleClientVideoCaptureHostTest, ReuseBufferId) {
+ CustomSetUp();
CreateBuffer(0, 0);
FrameReadyInBuffer(0, 0, 3);
// Retire buffer 0. The consumer is not expected to receive OnBufferDestroyed
@@ -328,6 +358,7 @@ TEST_F(SingleClientVideoCaptureHostTest, ReuseBufferId) {
}
TEST_F(SingleClientVideoCaptureHostTest, StopCapturingWhileBuffersInUse) {
+ CustomSetUp();
for (int i = 0; i < 10; ++i) {
CreateBuffer(i, i);
FrameReadyInBuffer(i, i, i);
diff --git a/chromium/components/mirroring/service/fake_network_service.h b/chromium/components/mirroring/service/fake_network_service.h
index bc985ebb4de..e27376ad206 100644
--- a/chromium/components/mirroring/service/fake_network_service.h
+++ b/chromium/components/mirroring/service/fake_network_service.h
@@ -13,12 +13,13 @@
#include "mojo/public/cpp/bindings/remote.h"
#include "services/network/public/mojom/udp_socket.mojom.h"
#include "services/network/test/test_network_context.h"
+#include "services/network/test/test_udp_socket.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace mirroring {
-class MockUdpSocket final : public network::mojom::UDPSocket {
+class MockUdpSocket final : public network::TestUDPSocket {
public:
MockUdpSocket(
mojo::PendingReceiver<network::mojom::UDPSocket> receiver,
@@ -35,29 +36,10 @@ class MockUdpSocket final : public network::mojom::UDPSocket {
void Connect(const net::IPEndPoint& remote_addr,
network::mojom::UDPSocketOptionsPtr options,
ConnectCallback callback) override;
- void Bind(const net::IPEndPoint& local_addr,
- network::mojom::UDPSocketOptionsPtr options,
- BindCallback callback) override {}
- void SetBroadcast(bool broadcast, SetBroadcastCallback callback) override {}
- void SetSendBufferSize(int32_t send_buffer_size,
- SetSendBufferSizeCallback callback) override {}
- void SetReceiveBufferSize(int32_t receive_buffer_size,
- SetReceiveBufferSizeCallback callback) override {}
- void JoinGroup(const net::IPAddress& group_address,
- JoinGroupCallback callback) override {}
- void LeaveGroup(const net::IPAddress& group_address,
- LeaveGroupCallback callback) override {}
void ReceiveMore(uint32_t num_additional_datagrams) override;
- void ReceiveMoreWithBufferSize(uint32_t num_additional_datagrams,
- uint32_t buffer_size) override {}
- void SendTo(const net::IPEndPoint& dest_addr,
- base::span<const uint8_t> data,
- const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
- SendToCallback callback) override {}
void Send(base::span<const uint8_t> data,
const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
SendCallback callback) override;
- void Close() override {}
// Simulate receiving a packet from the network.
void OnReceivedPacket(const media::cast::Packet& packet);
diff --git a/chromium/components/mirroring/service/remoting_sender.cc b/chromium/components/mirroring/service/remoting_sender.cc
index a9159700b3f..7338039bd44 100644
--- a/chromium/components/mirroring/service/remoting_sender.cc
+++ b/chromium/components/mirroring/service/remoting_sender.cc
@@ -54,25 +54,8 @@ void RemotingSender::SendFrame(uint32_t frame_size) {
void RemotingSender::CancelInFlightData() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-// TODO(crbug.com/647423): The following code is something we want to do as an
-// optimization. However, as-is, it's not quite correct. We can only cancel
-// frames where no packets have actually hit the network yet. Said another
-// way, we can only cancel frames the receiver has definitely not seen any
-// part of (including kickstarting!).
-#if 0
- if (latest_acked_frame_id_ < last_sent_frame_id_) {
- std::vector<media::cast::FrameId> frames_to_cancel;
- do {
- ++latest_acked_frame_id_;
- frames_to_cancel.push_back(latest_acked_frame_id_);
- } while (latest_acked_frame_id_ < last_sent_frame_id_);
- transport_->CancelSendingFrames(ssrc_, frames_to_cancel);
- }
-#endif
-
// Flag that all pending input operations should discard data.
input_queue_discards_remaining_ = input_queue_.size();
-
flow_restart_pending_ = true;
VLOG(1) << "Now restarting because in-flight data was just canceled.";
}
diff --git a/chromium/components/mirroring/service/remoting_sender_unittest.cc b/chromium/components/mirroring/service/remoting_sender_unittest.cc
index 04fce61f981..1e1b9d08d6e 100644
--- a/chromium/components/mirroring/service/remoting_sender_unittest.cc
+++ b/chromium/components/mirroring/service/remoting_sender_unittest.cc
@@ -8,7 +8,6 @@
#include "base/bind.h"
#include "base/callback_helpers.h"
-#include "base/compiler_specific.h"
#include "base/run_loop.h"
#include "base/test/task_environment.h"
#include "base/time/default_tick_clock.h"
@@ -173,7 +172,7 @@ class RemotingSenderTest : public ::testing::Test {
return remoting_sender_->flow_restart_pending_;
}
- bool ProduceDataChunk(size_t offset, size_t size) WARN_UNUSED_RESULT {
+ [[nodiscard]] bool ProduceDataChunk(size_t offset, size_t size) {
std::vector<uint8_t> fake_chunk(size);
for (size_t i = 0; i < size; ++i)
fake_chunk[i] = static_cast<uint8_t>(offset + i);
@@ -367,9 +366,7 @@ TEST_F(RemotingSenderTest, CancelsUnsentFrame) {
EXPECT_TRUE(ExpectNoFramesCanceled());
}
-// http://crbug.com/647423
-#define MAYBE_CancelsFramesInFlight DISABLED_CancelsFramesInFlight
-TEST_F(RemotingSenderTest, MAYBE_CancelsFramesInFlight) {
+TEST_F(RemotingSenderTest, CancelsFramesInFlight) {
EXPECT_TRUE(IsFlowRestartPending());
// Send 10 frames.
@@ -388,23 +385,21 @@ TEST_F(RemotingSenderTest, MAYBE_CancelsFramesInFlight) {
EXPECT_TRUE(ExpectFramesCanceled(media::cast::FrameId::first(),
media::cast::FrameId::first()));
- // Cancel all in-flight data. This should cause the remaining 9 frames to be
- // canceled.
+ // Despite the name, this does not actually cancel in-flight frames, as that
+ // capability was never implemented.
CancelInFlightData();
RunPendingTasks();
EXPECT_TRUE(IsFlowRestartPending());
- EXPECT_EQ(0, NumberOfFramesInFlight());
- EXPECT_TRUE(ExpectFramesCanceled(media::cast::FrameId::first() + 1,
- media::cast::FrameId::first() + 9));
+ EXPECT_EQ(9, NumberOfFramesInFlight());
// Send one more frame and ack it.
ASSERT_TRUE(ProduceDataChunk(0, 16));
SendFrame(16);
RunPendingTasks();
EXPECT_FALSE(IsFlowRestartPending());
- EXPECT_EQ(1, NumberOfFramesInFlight());
+ EXPECT_EQ(10, NumberOfFramesInFlight());
AckOldestInFlightFrames(1);
- EXPECT_EQ(0, NumberOfFramesInFlight());
+ EXPECT_EQ(9, NumberOfFramesInFlight());
// Check that the dependency metadata was set correctly to indicate a frame
// that immediately follows a CancelInFlightData() operation.
diff --git a/chromium/components/mirroring/service/session.cc b/chromium/components/mirroring/service/session.cc
index b4a1d9351b8..cf749acaad6 100644
--- a/chromium/components/mirroring/service/session.cc
+++ b/chromium/components/mirroring/service/session.cc
@@ -169,14 +169,14 @@ bool IsHardwareH264EncodingSupported(
// TODO(crbug.com/1015482): Look into why H.264 hardware encoder on MacOS is
// broken.
// TODO(crbug.com/1015482): Look into HW encoder initialization issues on Win.
-#if !defined(OS_APPLE) && !defined(OS_WIN)
+#if !BUILDFLAG(IS_APPLE) && !BUILDFLAG(IS_WIN)
for (const auto& vea_profile : profiles) {
if (vea_profile.profile >= media::H264PROFILE_MIN &&
vea_profile.profile <= media::H264PROFILE_MAX) {
return true;
}
}
-#endif // !defined(OS_APPLE) && !defined(OS_WIN)
+#endif // !BUILDFLAG(IS_APPLE) && !BUILDFLAG(IS_WIN)
return false;
}
diff --git a/chromium/components/mirroring/service/session_unittest.cc b/chromium/components/mirroring/service/session_unittest.cc
index 8b64a610faa..036baaa3dd6 100644
--- a/chromium/components/mirroring/service/session_unittest.cc
+++ b/chromium/components/mirroring/service/session_unittest.cc
@@ -140,7 +140,7 @@ class SessionTest : public mojom::ResourceProvider,
ASSERT_TRUE(offer);
auto* raw_streams = offer->FindKey("supportedStreams");
if (raw_streams) {
- base::Value::ListView streams = raw_streams->GetList();
+ base::Value::ListView streams = raw_streams->GetListDeprecated();
for (auto it = streams.begin(); it != streams.end(); ++it) {
EXPECT_EQ(it->FindKey("targetDelay")->GetInt(),
target_playout_delay_ms_);
diff --git a/chromium/components/mirroring/service/value_util.cc b/chromium/components/mirroring/service/value_util.cc
index 63eec3d9999..2815cf85e09 100644
--- a/chromium/components/mirroring/service/value_util.cc
+++ b/chromium/components/mirroring/service/value_util.cc
@@ -66,7 +66,7 @@ bool GetIntArray(const base::Value& value,
return true;
if (!found->is_list())
return false;
- for (const auto& number_value : found->GetList()) {
+ for (const auto& number_value : found->GetListDeprecated()) {
if (number_value.is_int())
result->emplace_back(number_value.GetInt());
else
@@ -83,7 +83,7 @@ bool GetStringArray(const base::Value& value,
return true;
if (!found->is_list())
return false;
- for (const auto& string_value : found->GetList()) {
+ for (const auto& string_value : found->GetListDeprecated()) {
if (string_value.is_string())
result->emplace_back(string_value.GetString());
else
diff --git a/chromium/components/mirroring/service/video_capture_client.cc b/chromium/components/mirroring/service/video_capture_client.cc
index 7529568291a..d520080ca47 100644
--- a/chromium/components/mirroring/service/video_capture_client.cc
+++ b/chromium/components/mirroring/service/video_capture_client.cc
@@ -129,7 +129,7 @@ void VideoCaptureClient::OnNewBuffer(
if (!buffer_handle->is_read_only_shmem_region() &&
!buffer_handle->is_shared_buffer_handle()) {
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
if (!buffer_handle->is_gpu_memory_buffer_handle()) {
NOTIMPLEMENTED();
return;
@@ -197,7 +197,7 @@ void VideoCaptureClient::OnBufferReady(
scoped_refptr<media::VideoFrame> frame;
BufferFinishedCallback buffer_finished_callback;
if (buffer_iter->second->is_gpu_memory_buffer_handle()) {
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
frame = media::VideoFrame::WrapUnacceleratedIOSurface(
buffer_iter->second->get_gpu_memory_buffer_handle().Clone(),
buffer->info->visible_rect, buffer->info->timestamp);
@@ -282,7 +282,7 @@ void VideoCaptureClient::OnBufferReady(
nv12_to_i420_pool_->CreateFrame(
media::PIXEL_FORMAT_I420, frame->coded_size(),
frame->visible_rect(), frame->natural_size(), frame->timestamp());
- media::Status status =
+ media::EncoderStatus status =
media::ConvertAndScaleFrame(*frame, *new_frame, nv12_to_i420_tmp_buf_);
if (!status.is_ok()) {
LOG(DFATAL) << "Unable to convert frame to I420.";
diff --git a/chromium/components/nacl/broker/BUILD.gn b/chromium/components/nacl/broker/BUILD.gn
index ecad577970b..31a7822c7ee 100644
--- a/chromium/components/nacl/broker/BUILD.gn
+++ b/chromium/components/nacl/broker/BUILD.gn
@@ -48,7 +48,7 @@ source_set("broker") {
source_set("content_dummy") {
check_includes = false
sources = [
- "//content/public/common/sandbox_init.h",
+ "//content/public/common/sandbox_init_win.h",
"//content/public/common/sandboxed_process_launcher_delegate.h",
]
}
diff --git a/chromium/components/nacl/common/BUILD.gn b/chromium/components/nacl/common/BUILD.gn
index c39d5ed7afc..12a1022a288 100644
--- a/chromium/components/nacl/common/BUILD.gn
+++ b/chromium/components/nacl/common/BUILD.gn
@@ -62,8 +62,6 @@ if (enable_nacl) {
sources = [
"nacl_host_messages.cc",
"nacl_host_messages.h",
- "nacl_nonsfi_util.cc",
- "nacl_nonsfi_util.h",
"pnacl_types.cc",
"pnacl_types.h",
]
diff --git a/chromium/components/nacl/loader/BUILD.gn b/chromium/components/nacl/loader/BUILD.gn
index 75f2adf0d35..8deff671fe8 100644
--- a/chromium/components/nacl/loader/BUILD.gn
+++ b/chromium/components/nacl/loader/BUILD.gn
@@ -61,14 +61,14 @@ source_set("minimal") {
# as "minimal" (stuff that should not be in the nacl64.exe build).
source_set("minimal_content_dummy") {
check_includes = false
- sources = [
- "//content/public/common/main_function_params.h",
- "//content/public/common/sandbox_init.h",
- ]
+ sources = [ "//content/public/common/main_function_params.h" ]
# Deps required by the above headers.
deps = [ "//media:media_buildflags" ]
+ if (is_win) {
+ sources += [ "//content/public/common/sandbox_init_win.h" ]
+ }
if (is_linux || is_chromeos) {
sources += [ "//content/public/common/zygote/sandbox_support_linux.h" ]
}
diff --git a/chromium/components/nacl/loader/sandbox_linux/BUILD.gn b/chromium/components/nacl/loader/sandbox_linux/BUILD.gn
index ec71a0346fc..ff0382e7ae5 100644
--- a/chromium/components/nacl/loader/sandbox_linux/BUILD.gn
+++ b/chromium/components/nacl/loader/sandbox_linux/BUILD.gn
@@ -21,7 +21,6 @@ source_set("sandbox_linux") {
"//base",
"//components/nacl/common",
"//components/nacl/loader",
- "//content/public/common",
"//crypto",
"//ipc",
"//sandbox",
diff --git a/chromium/components/navigation_interception/intercept_navigation_delegate.cc b/chromium/components/navigation_interception/intercept_navigation_delegate.cc
index 897acfdbd5c..337e9c07f85 100644
--- a/chromium/components/navigation_interception/intercept_navigation_delegate.cc
+++ b/chromium/components/navigation_interception/intercept_navigation_delegate.cc
@@ -32,8 +32,6 @@ namespace navigation_interception {
namespace {
-const int kMaxValidityOfUserGestureCarryoverInSeconds = 10;
-
const void* const kInterceptNavigationDelegateUserDataKey =
&kInterceptNavigationDelegateUserDataKey;
@@ -119,20 +117,11 @@ bool InterceptNavigationDelegate::ShouldIgnoreNavigation(
if (jdelegate.is_null())
return false;
- bool has_user_gesture_carryover =
- !navigation_params_to_use.has_user_gesture() &&
- base::TimeTicks::Now() - last_user_gesture_carryover_timestamp_ <=
- base::Seconds(kMaxValidityOfUserGestureCarryoverInSeconds);
-
- ScopedJavaLocalRef<jobject> jobject_params = CreateJavaNavigationParams(
- env, navigation_params_to_use, has_user_gesture_carryover);
+ ScopedJavaLocalRef<jobject> jobject_params =
+ CreateJavaNavigationParams(env, navigation_params_to_use);
return Java_InterceptNavigationDelegate_shouldIgnoreNavigation(
env, jdelegate, jobject_params);
}
-void InterceptNavigationDelegate::UpdateLastUserGestureCarryoverTimestamp() {
- last_user_gesture_carryover_timestamp_ = base::TimeTicks::Now();
-}
-
} // namespace navigation_interception
diff --git a/chromium/components/navigation_interception/intercept_navigation_delegate.h b/chromium/components/navigation_interception/intercept_navigation_delegate.h
index 4452c3303d1..a6da027e7fe 100644
--- a/chromium/components/navigation_interception/intercept_navigation_delegate.h
+++ b/chromium/components/navigation_interception/intercept_navigation_delegate.h
@@ -66,13 +66,8 @@ class InterceptNavigationDelegate : public base::SupportsUserData::Data {
virtual bool ShouldIgnoreNavigation(
const NavigationParams& navigation_params);
- // Updates |last_user_gesture_carryover_timestamp_| when user gesture is
- // carried over.
- void UpdateLastUserGestureCarryoverTimestamp();
-
private:
JavaObjectWeakGlobalRef weak_jdelegate_;
- base::TimeTicks last_user_gesture_carryover_timestamp_;
bool escape_external_handler_value_ = false;
};
diff --git a/chromium/components/navigation_interception/intercept_navigation_throttle.cc b/chromium/components/navigation_interception/intercept_navigation_throttle.cc
index 44cbcab46e4..6d55db8188f 100644
--- a/chromium/components/navigation_interception/intercept_navigation_throttle.cc
+++ b/chromium/components/navigation_interception/intercept_navigation_throttle.cc
@@ -29,14 +29,16 @@ InterceptNavigationThrottle::~InterceptNavigationThrottle() = default;
content::NavigationThrottle::ThrottleCheckResult
InterceptNavigationThrottle::WillStartRequest() {
DCHECK(!should_ignore_);
- return CheckIfShouldIgnoreNavigation(false /* is_redirect */);
+ DCHECK(!navigation_handle()->WasServerRedirect());
+ return CheckIfShouldIgnoreNavigation();
}
content::NavigationThrottle::ThrottleCheckResult
InterceptNavigationThrottle::WillRedirectRequest() {
if (should_ignore_)
return content::NavigationThrottle::CANCEL_AND_IGNORE;
- return CheckIfShouldIgnoreNavigation(true /* is_redirect */);
+ DCHECK(navigation_handle()->WasServerRedirect());
+ return CheckIfShouldIgnoreNavigation();
}
content::NavigationThrottle::ThrottleCheckResult
@@ -58,19 +60,19 @@ const char* InterceptNavigationThrottle::GetNameForLogging() {
}
content::NavigationThrottle::ThrottleCheckResult
-InterceptNavigationThrottle::CheckIfShouldIgnoreNavigation(bool is_redirect) {
+InterceptNavigationThrottle::CheckIfShouldIgnoreNavigation() {
if (ShouldCheckAsynchronously()) {
pending_checks_++;
ui_task_runner_->PostTask(
- FROM_HERE, base::BindOnce(&InterceptNavigationThrottle::RunCheckAsync,
- weak_factory_.GetWeakPtr(),
- GetNavigationParams(is_redirect)));
+ FROM_HERE,
+ base::BindOnce(&InterceptNavigationThrottle::RunCheckAsync,
+ weak_factory_.GetWeakPtr(), GetNavigationParams()));
return content::NavigationThrottle::PROCEED;
}
// No need to set |should_ignore_| since if it is true, we'll cancel the
// navigation immediately.
return should_ignore_callback_.Run(navigation_handle()->GetWebContents(),
- GetNavigationParams(is_redirect))
+ GetNavigationParams())
? content::NavigationThrottle::CANCEL_AND_IGNORE
: content::NavigationThrottle::PROCEED;
// Careful, |this| can be deleted at this point.
@@ -113,14 +115,14 @@ bool InterceptNavigationThrottle::ShouldCheckAsynchronously() const {
base::FeatureList::IsEnabled(kAsyncCheck);
}
-NavigationParams InterceptNavigationThrottle::GetNavigationParams(
- bool is_redirect) const {
+NavigationParams InterceptNavigationThrottle::GetNavigationParams() const {
return NavigationParams(navigation_handle()->GetURL(),
content::Referrer(navigation_handle()->GetReferrer()),
navigation_handle()->GetNavigationId(),
navigation_handle()->HasUserGesture(),
navigation_handle()->IsPost(),
- navigation_handle()->GetPageTransition(), is_redirect,
+ navigation_handle()->GetPageTransition(),
+ navigation_handle()->WasServerRedirect(),
navigation_handle()->IsExternalProtocol(), true,
navigation_handle()->IsRendererInitiated(),
navigation_handle()->GetBaseURLForDataURL(),
diff --git a/chromium/components/navigation_interception/intercept_navigation_throttle.h b/chromium/components/navigation_interception/intercept_navigation_throttle.h
index 571d2e7f003..3cb593fb234 100644
--- a/chromium/components/navigation_interception/intercept_navigation_throttle.h
+++ b/chromium/components/navigation_interception/intercept_navigation_throttle.h
@@ -57,13 +57,13 @@ class InterceptNavigationThrottle : public content::NavigationThrottle {
const char* GetNameForLogging() override;
private:
- ThrottleCheckResult CheckIfShouldIgnoreNavigation(bool is_redirect);
+ ThrottleCheckResult CheckIfShouldIgnoreNavigation();
void RunCheckAsync(const NavigationParams& params);
bool ShouldCheckAsynchronously() const;
// Constructs NavigationParams for this navigation.
- NavigationParams GetNavigationParams(bool is_redirect) const;
+ NavigationParams GetNavigationParams() const;
// This callback should be called at the start of navigation and every
// redirect, until |should_ignore_| is true.
diff --git a/chromium/components/navigation_interception/intercept_navigation_throttle_unittest.cc b/chromium/components/navigation_interception/intercept_navigation_throttle_unittest.cc
index 4c250a149ab..579d31c46cc 100644
--- a/chromium/components/navigation_interception/intercept_navigation_throttle_unittest.cc
+++ b/chromium/components/navigation_interception/intercept_navigation_throttle_unittest.cc
@@ -124,7 +124,7 @@ class InterceptNavigationThrottleTest
// TODO(https://crbug.com/1009359): Fix flakes on win10_chromium_x64_rel_ng and
// re-enable this test.
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#define MAYBE_RequestCompletesIfNavigationNotIgnored \
DISABLED_RequestCompletesIfNavigationNotIgnored
#else
@@ -146,7 +146,7 @@ TEST_P(InterceptNavigationThrottleTest,
// TODO(https://crbug.com/1010187): Fix flakes on win10_chromium_x64_rel_ng and
// re-enable this test.
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#define MAYBE_RequestCancelledIfNavigationIgnored \
DISABLED_RequestCancelledIfNavigationIgnored
#else
diff --git a/chromium/components/navigation_interception/navigation_params_android.cc b/chromium/components/navigation_interception/navigation_params_android.cc
index 8e593a7ef8f..996391781e1 100644
--- a/chromium/components/navigation_interception/navigation_params_android.cc
+++ b/chromium/components/navigation_interception/navigation_params_android.cc
@@ -11,8 +11,7 @@ namespace navigation_interception {
base::android::ScopedJavaLocalRef<jobject> CreateJavaNavigationParams(
JNIEnv* env,
- const NavigationParams& params,
- bool has_user_gesture_carryover) {
+ const NavigationParams& params) {
const GURL& url = params.base_url_for_data_url().is_empty()
? params.url()
: params.base_url_for_data_url();
@@ -23,7 +22,7 @@ base::android::ScopedJavaLocalRef<jobject> CreateJavaNavigationParams(
params.navigation_id(), params.is_post(), params.has_user_gesture(),
params.transition_type(), params.is_redirect(),
params.is_external_protocol(), params.is_main_frame(),
- params.is_renderer_initiated(), has_user_gesture_carryover,
+ params.is_renderer_initiated(),
params.initiator_origin() ? params.initiator_origin()->CreateJavaObject()
: nullptr);
}
diff --git a/chromium/components/navigation_interception/navigation_params_android.h b/chromium/components/navigation_interception/navigation_params_android.h
index 7bb164dd98c..4c68f8ce86b 100644
--- a/chromium/components/navigation_interception/navigation_params_android.h
+++ b/chromium/components/navigation_interception/navigation_params_android.h
@@ -13,8 +13,7 @@ namespace navigation_interception {
base::android::ScopedJavaLocalRef<jobject> CreateJavaNavigationParams(
JNIEnv* env,
- const NavigationParams& params,
- bool has_user_gesture_carryover);
+ const NavigationParams& params);
} // namespace navigation_interception
diff --git a/chromium/components/net_log/chrome_net_log.cc b/chromium/components/net_log/chrome_net_log.cc
index e41611e4bb3..bb4650932ac 100644
--- a/chromium/components/net_log/chrome_net_log.cc
+++ b/chromium/components/net_log/chrome_net_log.cc
@@ -26,21 +26,21 @@ std::unique_ptr<base::DictionaryValue> GetPlatformConstantsForNetLog(
base::DictionaryValue dict;
// We have everything we need to send the right values.
- dict.SetString("name", version_info::GetProductName());
- dict.SetString("version", version_info::GetVersionNumber());
- dict.SetString("cl", version_info::GetLastChange());
- dict.SetString("version_mod", channel_string);
- dict.SetString("official",
- version_info::IsOfficialBuild() ? "official" : "unofficial");
+ dict.SetStringKey("name", version_info::GetProductName());
+ dict.SetStringKey("version", version_info::GetVersionNumber());
+ dict.SetStringKey("cl", version_info::GetLastChange());
+ dict.SetStringKey("version_mod", channel_string);
+ dict.SetStringKey(
+ "official", version_info::IsOfficialBuild() ? "official" : "unofficial");
std::string os_type = base::StringPrintf(
"%s: %s (%s)", base::SysInfo::OperatingSystemName().c_str(),
base::SysInfo::OperatingSystemVersion().c_str(),
base::SysInfo::OperatingSystemArchitecture().c_str());
- dict.SetString("os_type", os_type);
-#if defined(OS_WIN)
- dict.SetString("command_line", base::WideToUTF8(command_line_string));
+ dict.SetStringKey("os_type", os_type);
+#if BUILDFLAG(IS_WIN)
+ dict.SetStringKey("command_line", base::WideToUTF8(command_line_string));
#else
- dict.SetString("command_line", command_line_string);
+ dict.SetStringKey("command_line", command_line_string);
#endif
constants_dict->SetKey("clientInfo", std::move(dict));
diff --git a/chromium/components/net_log/net_export_file_writer.cc b/chromium/components/net_log/net_export_file_writer.cc
index 9ff36e0de51..9e9df04eebf 100644
--- a/chromium/components/net_log/net_export_file_writer.cc
+++ b/chromium/components/net_log/net_export_file_writer.cc
@@ -14,6 +14,7 @@
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/scoped_file.h"
+#include "base/strings/utf_string_conversions.h"
#include "base/task/post_task.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/task_runner_util.h"
@@ -235,7 +236,7 @@ std::unique_ptr<base::DictionaryValue> NetExportFileWriter::GetState() const {
auto dict = std::make_unique<base::DictionaryValue>();
- dict->SetString("file", log_path_.LossyDisplayName());
+ dict->SetStringKey("file", base::UTF16ToUTF8(log_path_.LossyDisplayName()));
base::StringPiece state_string;
switch (state_) {
@@ -258,11 +259,11 @@ std::unique_ptr<base::DictionaryValue> NetExportFileWriter::GetState() const {
state_string = "STOPPING_LOG";
break;
}
- dict->SetString("state", state_string);
+ dict->SetStringKey("state", state_string);
- dict->SetBoolean("logExists", log_exists_);
- dict->SetBoolean("logCaptureModeKnown", log_capture_mode_known_);
- dict->SetString("captureMode", CaptureModeToString(log_capture_mode_));
+ dict->SetBoolKey("logExists", log_exists_);
+ dict->SetBoolKey("logCaptureModeKnown", log_capture_mode_known_);
+ dict->SetStringKey("captureMode", CaptureModeToString(log_capture_mode_));
return dict;
}
diff --git a/chromium/components/net_log/net_export_file_writer_unittest.cc b/chromium/components/net_log/net_export_file_writer_unittest.cc
index ad661544bd5..bf43d70c08e 100644
--- a/chromium/components/net_log/net_export_file_writer_unittest.cc
+++ b/chromium/components/net_log/net_export_file_writer_unittest.cc
@@ -10,7 +10,6 @@
#include "base/bind.h"
#include "base/command_line.h"
-#include "base/compiler_specific.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/scoped_file.h"
@@ -107,7 +106,7 @@ bool SetPathToGivenAndReturnTrue(const base::FilePath& path_to_return,
}
// Checks the "state" string of a NetExportFileWriter state.
-WARN_UNUSED_RESULT ::testing::AssertionResult VerifyState(
+[[nodiscard]] ::testing::AssertionResult VerifyState(
std::unique_ptr<base::DictionaryValue> state,
const std::string& expected_state_string) {
std::string actual_state_string;
@@ -127,19 +126,20 @@ WARN_UNUSED_RESULT ::testing::AssertionResult VerifyState(
// Checks all fields of a NetExportFileWriter state except possibly the
// "captureMode" string; that field is only checked if
// |expected_log_capture_mode_known| is true.
-WARN_UNUSED_RESULT ::testing::AssertionResult VerifyState(
+[[nodiscard]] ::testing::AssertionResult VerifyState(
std::unique_ptr<base::DictionaryValue> state,
const std::string& expected_state_string,
bool expected_log_exists,
bool expected_log_capture_mode_known,
const std::string& expected_log_capture_mode_string) {
base::DictionaryValue expected_state;
- expected_state.SetString("state", expected_state_string);
- expected_state.SetBoolean("logExists", expected_log_exists);
- expected_state.SetBoolean("logCaptureModeKnown",
+ expected_state.SetStringKey("state", expected_state_string);
+ expected_state.SetBoolKey("logExists", expected_log_exists);
+ expected_state.SetBoolKey("logCaptureModeKnown",
expected_log_capture_mode_known);
if (expected_log_capture_mode_known) {
- expected_state.SetString("captureMode", expected_log_capture_mode_string);
+ expected_state.SetStringKey("captureMode",
+ expected_log_capture_mode_string);
} else {
state->RemoveKey("captureMode");
}
@@ -167,7 +167,7 @@ WARN_UNUSED_RESULT ::testing::AssertionResult VerifyState(
return ::testing::AssertionSuccess();
}
-WARN_UNUSED_RESULT ::testing::AssertionResult ReadCompleteLogFile(
+[[nodiscard]] ::testing::AssertionResult ReadCompleteLogFile(
const base::FilePath& log_path,
std::unique_ptr<base::DictionaryValue>* root) {
DCHECK(!log_path.empty());
@@ -179,7 +179,7 @@ WARN_UNUSED_RESULT ::testing::AssertionResult ReadCompleteLogFile(
// Check file permissions. These tests are only done on POSIX for simplicity,
// since base has better support for the POSIX permission model.
-#if defined(OS_POSIX)
+#if BUILDFLAG(IS_POSIX)
int actual_permissions = 0;
if (!base::GetPosixFilePermissions(log_path, &actual_permissions)) {
return ::testing::AssertionFailure()
@@ -193,7 +193,7 @@ WARN_UNUSED_RESULT ::testing::AssertionResult ReadCompleteLogFile(
// 640 rather than 644.
int expected_permissions = base::FILE_PERMISSION_READ_BY_USER |
base::FILE_PERMISSION_WRITE_BY_USER
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
| base::FILE_PERMISSION_READ_BY_GROUP |
base::FILE_PERMISSION_READ_BY_OTHERS
#endif
@@ -205,7 +205,7 @@ WARN_UNUSED_RESULT ::testing::AssertionResult ReadCompleteLogFile(
<< base::StringPrintf("%o", actual_permissions) << " vs "
<< base::StringPrintf("%o", expected_permissions);
}
-#endif // defined(OS_POSIX)
+#endif // BUILDFLAG(IS_POSIX)
// Parse log file contents into a dictionary
std::string log_string;
@@ -335,7 +335,7 @@ class NetExportFileWriterTest : public ::testing::Test {
return test_callback.WaitForResult();
}
- WARN_UNUSED_RESULT ::testing::AssertionResult InitializeThenVerifyNewState(
+ [[nodiscard]] ::testing::AssertionResult InitializeThenVerifyNewState(
bool expected_initialize_success,
bool expected_log_exists) {
file_writer_.Initialize();
@@ -368,7 +368,7 @@ class NetExportFileWriterTest : public ::testing::Test {
// If |custom_log_path| is empty path, |file_writer_| will use its
// default log path, which is cached in |default_log_path_|.
- WARN_UNUSED_RESULT::testing::AssertionResult StartThenVerifyNewState(
+ [[nodiscard]] ::testing::AssertionResult StartThenVerifyNewState(
const base::FilePath& custom_log_path,
net::NetLogCaptureMode capture_mode,
const std::string& expected_capture_mode_string,
@@ -410,7 +410,7 @@ class NetExportFileWriterTest : public ::testing::Test {
// If |custom_log_path| is empty path, it's assumed the log file with be at
// |default_log_path_|.
- WARN_UNUSED_RESULT ::testing::AssertionResult StopThenVerifyNewStateAndFile(
+ [[nodiscard]] ::testing::AssertionResult StopThenVerifyNewStateAndFile(
const base::FilePath& custom_log_path,
std::unique_ptr<base::DictionaryValue> polled_data,
const std::string& expected_capture_mode_string) {
@@ -702,7 +702,7 @@ TEST_F(NetExportFileWriterTest, StopWithPolledData) {
const char kDummyPolledDataString[] = "dummy_info";
std::unique_ptr<base::DictionaryValue> dummy_polled_data =
std::make_unique<base::DictionaryValue>();
- dummy_polled_data->SetString(kDummyPolledDataPath, kDummyPolledDataString);
+ dummy_polled_data->SetStringKey(kDummyPolledDataPath, kDummyPolledDataString);
ASSERT_TRUE(StartThenVerifyNewState(
base::FilePath(), net::NetLogCaptureMode::kDefault,
@@ -802,7 +802,7 @@ TEST_F(NetExportFileWriterTest, StartWithNetworkContextActive) {
ASSERT_TRUE(root->GetList("events", &events));
// Check there is at least one event as a result of the ongoing request.
- ASSERT_GE(events->GetList().size(), 1u);
+ ASSERT_GE(events->GetListDeprecated().size(), 1u);
// Check the URL in the params of the first event.
base::DictionaryValue* event;
diff --git a/chromium/components/network_hints/renderer/dns_prefetch_queue_unittest.cc b/chromium/components/network_hints/renderer/dns_prefetch_queue_unittest.cc
index 9c2322f3d3b..83263a8fbab 100644
--- a/chromium/components/network_hints/renderer/dns_prefetch_queue_unittest.cc
+++ b/chromium/components/network_hints/renderer/dns_prefetch_queue_unittest.cc
@@ -181,8 +181,7 @@ TEST(DnsQueueTest, FillThenEmptyCheck) {
EXPECT_GE(write_success, 10U) << "Couldn't even write 10 one digit strings "
"in " << buffer_size << " byte buffer";
-
- while (1) {
+ while (true) {
if (!tester.Pop())
break;
write_success--;
diff --git a/chromium/components/network_hints/renderer/renderer_dns_prefetch.cc b/chromium/components/network_hints/renderer/renderer_dns_prefetch.cc
index e65032f8419..cda0ef32b24 100644
--- a/chromium/components/network_hints/renderer/renderer_dns_prefetch.cc
+++ b/chromium/components/network_hints/renderer/renderer_dns_prefetch.cc
@@ -15,6 +15,7 @@
#include "base/check_op.h"
#include "base/location.h"
#include "base/threading/sequenced_task_runner_handle.h"
+#include "base/time/time.h"
#include "components/network_hints/renderer/dns_prefetch_queue.h"
namespace network_hints {
diff --git a/chromium/components/network_session_configurator/android/BUILD.gn b/chromium/components/network_session_configurator/android/BUILD.gn
new file mode 100644
index 00000000000..7e78678fc4a
--- /dev/null
+++ b/chromium/components/network_session_configurator/android/BUILD.gn
@@ -0,0 +1,22 @@
+# Copyright 2022 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.
+
+assert(is_android)
+
+import("//build/config/android/rules.gni")
+
+java_cpp_strings("java_switches_srcjar") {
+ # External code should depend on ":network_session_configurator_java" instead.
+ visibility = [ ":*" ]
+ sources =
+ [ "//components/network_session_configurator/common/network_switches.cc" ]
+ template = "NetworkSessionSwitches.java.tmpl"
+}
+
+# If there's already an android_library target, you can add
+# java_switches_srcjar to that target's srcjar_deps. Otherwise, the best
+# practice is to create a new android_library just for this target.
+android_library("network_session_configurator_java") {
+ srcjar_deps = [ ":java_switches_srcjar" ]
+}
diff --git a/chromium/components/network_session_configurator/android/NetworkSessionSwitches.java.tmpl b/chromium/components/network_session_configurator/android/NetworkSessionSwitches.java.tmpl
new file mode 100644
index 00000000000..26dea8d2dd5
--- /dev/null
+++ b/chromium/components/network_session_configurator/android/NetworkSessionSwitches.java.tmpl
@@ -0,0 +1,18 @@
+// Copyright 2022 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.
+
+package org.chromium.components.network_session_configurator;
+
+/**
+* Contains command line switches that are specific to
+* configuring network sessions via network_session_configurator.
+*/
+public final class NetworkSessionSwitches {{
+
+{NATIVE_STRINGS}
+
+ // Prevents instantiation.
+ private NetworkSessionSwitches() {{}}
+}}
+
diff --git a/chromium/components/network_session_configurator/browser/network_session_configurator.cc b/chromium/components/network_session_configurator/browser/network_session_configurator.cc
index 00511e8e7ae..3582b609a0c 100644
--- a/chromium/components/network_session_configurator/browser/network_session_configurator.cc
+++ b/chromium/components/network_session_configurator/browser/network_session_configurator.cc
@@ -27,15 +27,15 @@
#include "net/base/host_mapping_rules.h"
#include "net/http/http_network_session.h"
#include "net/http/http_stream_factory.h"
-#include "net/quic/platform/impl/quic_flags_impl.h"
#include "net/quic/quic_context.h"
#include "net/spdy/spdy_session.h"
#include "net/spdy/spdy_session_pool.h"
+#include "net/third_party/quiche/overrides/quiche_platform_impl/quic_flags_impl.h"
#include "net/third_party/quiche/src/quic/core/quic_packets.h"
#include "net/third_party/quiche/src/quic/core/quic_tag.h"
#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h"
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
#include "base/mac/mac_util.h"
#endif
@@ -121,13 +121,15 @@ void ConfigureHttp2Params(const base::CommandLine& command_line,
return;
}
- // After parsing initial settings, optionally add a setting with reserved
- // identifier to "grease" settings, see
- // https://tools.ietf.org/html/draft-bishop-httpbis-grease-00.
params->http2_settings = GetHttp2Settings(http2_trial_params);
- if (command_line.HasSwitch(switches::kHttp2GreaseSettings) ||
- GetVariationParam(http2_trial_params, "http2_grease_settings") ==
- "true") {
+
+ // Enable/disable greasing SETTINGS, see
+ // https://tools.ietf.org/html/draft-bishop-httpbis-grease-00.
+ if (command_line.HasSwitch(switches::kDisableHttp2GreaseSettings)) {
+ params->enable_http2_settings_grease = false;
+ } else if (command_line.HasSwitch(switches::kEnableHttp2GreaseSettings) ||
+ GetVariationParam(http2_trial_params, "http2_grease_settings") ==
+ "true") {
params->enable_http2_settings_grease = true;
}
@@ -757,7 +759,7 @@ void ParseCommandLineAndFieldTrials(const base::CommandLine& command_line,
}
net::URLRequestContextBuilder::HttpCacheParams::Type ChooseCacheType() {
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
const std::string experiment_name =
base::FieldTrialList::FindFullName("SimpleCacheTrial");
if (base::StartsWith(experiment_name, "Disable",
@@ -771,18 +773,18 @@ net::URLRequestContextBuilder::HttpCacheParams::Type ChooseCacheType() {
// muddles the experiment data, but as this was written to be considered for
// backport, having it behave differently than in stable would be a bigger
// problem.
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
if (base::mac::IsAtLeastOS10_14())
return net::URLRequestContextBuilder::HttpCacheParams::DISK_SIMPLE;
-#endif // defined(OS_MAC)
+#endif // BUILDFLAG(IS_MAC)
if (base::StartsWith(experiment_name, "ExperimentYes",
base::CompareCase::INSENSITIVE_ASCII)) {
return net::URLRequestContextBuilder::HttpCacheParams::DISK_SIMPLE;
}
-#endif // #if !defined(OS_ANDROID)
+#endif // #if !BUILDFLAG(IS_ANDROID)
-#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
return net::URLRequestContextBuilder::HttpCacheParams::DISK_SIMPLE;
#else
return net::URLRequestContextBuilder::HttpCacheParams::DISK_BLOCKFILE;
diff --git a/chromium/components/network_session_configurator/browser/network_session_configurator_unittest.cc b/chromium/components/network_session_configurator/browser/network_session_configurator_unittest.cc
index 7239cc7396d..2bf58ffa655 100644
--- a/chromium/components/network_session_configurator/browser/network_session_configurator_unittest.cc
+++ b/chromium/components/network_session_configurator/browser/network_session_configurator_unittest.cc
@@ -26,7 +26,7 @@
#include "net/url_request/url_request_context_builder.h"
#include "testing/gtest/include/gtest/gtest.h"
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
#include "base/mac/mac_util.h"
#endif
@@ -71,7 +71,6 @@ TEST_F(NetworkSessionConfiguratorTest, Defaults) {
EXPECT_FALSE(params_.enable_http2_settings_grease);
EXPECT_FALSE(params_.greased_http2_frame);
EXPECT_FALSE(params_.http2_end_stream_with_data_frame);
- EXPECT_TRUE(params_.enable_websocket_over_http2);
EXPECT_TRUE(params_.enable_quic);
EXPECT_TRUE(quic_params_.retry_without_alt_svc_on_quic_errors);
@@ -150,12 +149,12 @@ TEST_F(NetworkSessionConfiguratorTest, EnableQuicFromParams) {
}
TEST_F(NetworkSessionConfiguratorTest, ValidQuicParams) {
- quic::ParsedQuicVersion version = quic::ParsedQuicVersion::Draft29();
+ quic::ParsedQuicVersion version = net::DefaultSupportedQuicVersions().front();
std::map<std::string, std::string> field_trial_params;
field_trial_params["enable_quic"] = "true";
field_trial_params["channel"] = "T";
field_trial_params["epoch"] = "90001234"; // Epoch in the far future.
- field_trial_params["quic_version"] = quic::AlpnForVersion(version);
+ field_trial_params["quic_version"] = quic::ParsedQuicVersionToString(version);
variations::AssociateVariationParams("QUIC", "ValidQuicParams",
field_trial_params);
base::FieldTrialList::CreateFieldTrial("QUIC", "ValidQuicParams");
@@ -170,11 +169,11 @@ TEST_F(NetworkSessionConfiguratorTest, ValidQuicParams) {
}
TEST_F(NetworkSessionConfiguratorTest, InvalidQuicParams) {
- quic::ParsedQuicVersion version = quic::ParsedQuicVersion::Draft29();
+ quic::ParsedQuicVersion version = net::DefaultSupportedQuicVersions().front();
std::map<std::string, std::string> field_trial_params;
field_trial_params["enable_quic"] = "true";
// These params are missing channel and epoch.
- field_trial_params["quic_version"] = quic::AlpnForVersion(version);
+ field_trial_params["quic_version"] = quic::ParsedQuicVersionToString(version);
variations::AssociateVariationParams("QUIC", "InvalidQuicParams",
field_trial_params);
base::FieldTrialList::CreateFieldTrial("QUIC", "InvalidQuicParams");
@@ -536,9 +535,9 @@ TEST_F(NetworkSessionConfiguratorTest, QuicVersionFromFieldTrialParams) {
}
TEST_F(NetworkSessionConfiguratorTest, QuicVersionFromFieldTrialParamsAlpn) {
- quic::ParsedQuicVersion version = quic::AllSupportedVersions().front();
+ quic::ParsedQuicVersion version = net::DefaultSupportedQuicVersions().front();
std::map<std::string, std::string> field_trial_params;
- field_trial_params["quic_version"] = quic::AlpnForVersion(version);
+ field_trial_params["quic_version"] = quic::ParsedQuicVersionToString(version);
variations::AssociateVariationParams("QUIC", "Enabled", field_trial_params);
base::FieldTrialList::CreateFieldTrial("QUIC", "Enabled");
@@ -553,11 +552,12 @@ TEST_F(NetworkSessionConfiguratorTest,
ASSERT_LE(2u, quic::AllSupportedVersions().size());
quic::ParsedQuicVersion version1 = quic::AllSupportedVersions()[0];
quic::ParsedQuicVersion version2 = quic::AllSupportedVersions()[1];
- std::string quic_versions =
- quic::AlpnForVersion(version1) + "," + quic::AlpnForVersion(version2);
+ std::string quic_versions = quic::ParsedQuicVersionToString(version1) + "," +
+ quic::ParsedQuicVersionToString(version2);
std::map<std::string, std::string> field_trial_params;
field_trial_params["quic_version"] = quic_versions;
+ field_trial_params["obsolete_versions_allowed"] = "true";
variations::AssociateVariationParams("QUIC", "Enabled", field_trial_params);
base::FieldTrialList::CreateFieldTrial("QUIC", "Enabled");
@@ -776,10 +776,10 @@ TEST_F(NetworkSessionConfiguratorTest, HostRules) {
}
TEST_F(NetworkSessionConfiguratorTest, DefaultCacheBackend) {
-#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
EXPECT_EQ(net::URLRequestContextBuilder::HttpCacheParams::DISK_SIMPLE,
ChooseCacheType());
-#elif defined(OS_MAC)
+#elif BUILDFLAG(IS_MAC)
EXPECT_EQ(
base::mac::IsAtLeastOS10_14()
? net::URLRequestContextBuilder::HttpCacheParams::DISK_SIMPLE
@@ -799,10 +799,10 @@ TEST_F(NetworkSessionConfiguratorTest, SimpleCacheTrialExperimentYes) {
TEST_F(NetworkSessionConfiguratorTest, SimpleCacheTrialDisable) {
base::FieldTrialList::CreateFieldTrial("SimpleCacheTrial", "Disable");
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
EXPECT_EQ(net::URLRequestContextBuilder::HttpCacheParams::DISK_BLOCKFILE,
ChooseCacheType());
-#else // defined(OS_ANDROID)
+#else // BUILDFLAG(IS_ANDROID)
// Android always uses the simple cache.
EXPECT_EQ(net::URLRequestContextBuilder::HttpCacheParams::DISK_SIMPLE,
ChooseCacheType());
@@ -822,7 +822,7 @@ TEST_F(NetworkSessionConfiguratorTest, QuicHeadersIncludeH2StreamDependency) {
TEST_F(NetworkSessionConfiguratorTest, Http2GreaseSettingsFromCommandLine) {
base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
- command_line.AppendSwitch(switches::kHttp2GreaseSettings);
+ command_line.AppendSwitch(switches::kEnableHttp2GreaseSettings);
ParseCommandLineAndFieldTrials(command_line);
@@ -840,6 +840,21 @@ TEST_F(NetworkSessionConfiguratorTest, Http2GreaseSettingsFromFieldTrial) {
EXPECT_TRUE(params_.enable_http2_settings_grease);
}
+TEST_F(NetworkSessionConfiguratorTest,
+ DisableHttp2GreaseSettingsFromCommandLineOverridesFieldTrial) {
+ base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
+ command_line.AppendSwitch(switches::kDisableHttp2GreaseSettings);
+
+ std::map<std::string, std::string> field_trial_params;
+ field_trial_params["http2_grease_settings"] = "true";
+ variations::AssociateVariationParams("HTTP2", "Enabled", field_trial_params);
+ base::FieldTrialList::CreateFieldTrial("HTTP2", "Enabled");
+
+ ParseCommandLineAndFieldTrials(command_line);
+
+ EXPECT_FALSE(params_.enable_http2_settings_grease);
+}
+
TEST_F(NetworkSessionConfiguratorTest, Http2GreaseFrameTypeFromCommandLine) {
base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
command_line.AppendSwitch(switches::kHttp2GreaseFrameType);
@@ -923,7 +938,7 @@ TEST_P(NetworkSessionConfiguratorWithQuicVersionTest, QuicVersionAlpn) {
base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
command_line.AppendSwitch(switches::kEnableQuic);
command_line.AppendSwitchASCII(switches::kQuicVersion,
- quic::AlpnForVersion(version_));
+ quic::ParsedQuicVersionToString(version_));
ParseCommandLineAndFieldTrials(command_line);
quic::ParsedQuicVersionVector expected_versions = {version_};
EXPECT_EQ(expected_versions, quic_params_.supported_versions);
@@ -964,8 +979,8 @@ TEST_P(NetworkSessionConfiguratorWithQuicVersionTest,
// ObsoleteQuicVersion tests.
return;
}
- std::string quic_versions =
- quic::AlpnForVersion(version_) + "," + quic::AlpnForVersion(version_);
+ std::string quic_versions = quic::ParsedQuicVersionToString(version_) + "," +
+ quic::ParsedQuicVersionToString(version_);
std::map<std::string, std::string> field_trial_params;
field_trial_params["quic_version"] = quic_versions;
variations::AssociateVariationParams("QUIC", "Enabled", field_trial_params);
@@ -983,7 +998,7 @@ TEST_P(NetworkSessionConfiguratorWithQuicVersionTest, ObsoleteQuicVersion) {
// Only test obsolete versions here.
return;
}
- std::string quic_versions = quic::AlpnForVersion(version_);
+ std::string quic_versions = quic::ParsedQuicVersionToString(version_);
std::map<std::string, std::string> field_trial_params;
field_trial_params["quic_version"] = quic_versions;
variations::AssociateVariationParams("QUIC", "Enabled", field_trial_params);
@@ -1002,7 +1017,7 @@ TEST_P(NetworkSessionConfiguratorWithQuicVersionTest,
// Only test obsolete versions here.
return;
}
- std::string quic_versions = quic::AlpnForVersion(version_);
+ std::string quic_versions = quic::ParsedQuicVersionToString(version_);
std::map<std::string, std::string> field_trial_params;
field_trial_params["quic_version"] = quic_versions;
field_trial_params["obsolete_versions_allowed"] = "true";
@@ -1024,8 +1039,8 @@ TEST_P(NetworkSessionConfiguratorWithQuicVersionTest,
return;
}
quic::ParsedQuicVersion good_version = quic::AllSupportedVersions().front();
- std::string quic_versions =
- quic::AlpnForVersion(version_) + "," + quic::AlpnForVersion(good_version);
+ std::string quic_versions = quic::ParsedQuicVersionToString(version_) + "," +
+ quic::ParsedQuicVersionToString(good_version);
std::map<std::string, std::string> field_trial_params;
field_trial_params["quic_version"] = quic_versions;
variations::AssociateVariationParams("QUIC", "Enabled", field_trial_params);
@@ -1046,8 +1061,8 @@ TEST_P(NetworkSessionConfiguratorWithQuicVersionTest,
return;
}
quic::ParsedQuicVersion good_version = quic::AllSupportedVersions().front();
- std::string quic_versions =
- quic::AlpnForVersion(version_) + "," + quic::AlpnForVersion(good_version);
+ std::string quic_versions = quic::ParsedQuicVersionToString(version_) + "," +
+ quic::ParsedQuicVersionToString(good_version);
std::map<std::string, std::string> field_trial_params;
field_trial_params["quic_version"] = quic_versions;
field_trial_params["obsolete_versions_allowed"] = "true";
diff --git a/chromium/components/network_session_configurator/common/network_switch_list.h b/chromium/components/network_session_configurator/common/network_switch_list.h
index 9c7fc50180a..08c20da35d2 100644
--- a/chromium/components/network_session_configurator/common/network_switch_list.h
+++ b/chromium/components/network_session_configurator/common/network_switch_list.h
@@ -62,10 +62,9 @@ NETWORK_SWITCH(kTestingFixedHttpsPort, "testing-fixed-https-port")
// useful.
NETWORK_SWITCH(kHostRules, "host-rules")
-// Enable "greasing" HTTP/2, that is, sending SETTINGS parameters with reserved
-// identifiers and sending frames of reserved types, respectively. See
-// https://tools.ietf.org/html/draft-bishop-httpbis-grease-00 for more detail.
-NETWORK_SWITCH(kHttp2GreaseSettings, "http2-grease-settings")
+// Enable "greasing" HTTP/2 frame types, that is, sending frames of reserved
+// types. See https://tools.ietf.org/html/draft-bishop-httpbis-grease-00 for
+// more detail.
NETWORK_SWITCH(kHttp2GreaseFrameType, "http2-grease-frame-type")
// If request has no body, close the stream not by setting END_STREAM flag on
diff --git a/chromium/components/network_session_configurator/common/network_switches.cc b/chromium/components/network_session_configurator/common/network_switches.cc
index 429ee7aa02c..5bb1a3b55b7 100644
--- a/chromium/components/network_session_configurator/common/network_switches.cc
+++ b/chromium/components/network_session_configurator/common/network_switches.cc
@@ -9,6 +9,11 @@
namespace switches {
+// `kEnableHttp2GreaseSettings` does not include the word "enable" for
+// historical reasons.
+const char kEnableHttp2GreaseSettings[] = "http2-grease-settings";
+const char kDisableHttp2GreaseSettings[] = "disable-http2-grease-settings";
+
#define NETWORK_SWITCH(name, value) const char name[] = value;
#include "components/network_session_configurator/common/network_switch_list.h"
#undef NETWORK_SWITCH
@@ -20,6 +25,8 @@ namespace network_session_configurator {
void CopyNetworkSwitches(const base::CommandLine& src_command_line,
base::CommandLine* dest_command_line) {
static const char* const kSwitchNames[] = {
+ switches::kEnableHttp2GreaseSettings,
+ switches::kDisableHttp2GreaseSettings,
#define NETWORK_SWITCH(name, value) switches::name,
#include "components/network_session_configurator/common/network_switch_list.h"
#undef NETWORK_SWITCH
diff --git a/chromium/components/network_session_configurator/common/network_switches.h b/chromium/components/network_session_configurator/common/network_switches.h
index ee5ea753788..795b56922ba 100644
--- a/chromium/components/network_session_configurator/common/network_switches.h
+++ b/chromium/components/network_session_configurator/common/network_switches.h
@@ -13,6 +13,17 @@ class CommandLine;
namespace switches {
+// These two switches are not in network_switch_list.h so that
+// java_cpp_strings.py can parse them. TODO(bnc): Remove switches after
+// launching feature.
+// Enable/disable "greasing" HTTP/2 SETTINGS, that is, sending SETTINGS
+// parameters with reserved identifiers. See
+// https://tools.ietf.org/html/draft-bishop-httpbis-grease-00 for more detail.
+NETWORK_SESSION_CONFIGURATOR_EXPORT extern const char
+ kEnableHttp2GreaseSettings[];
+NETWORK_SESSION_CONFIGURATOR_EXPORT extern const char
+ kDisableHttp2GreaseSettings[];
+
#define NETWORK_SWITCH(name, value) \
NETWORK_SESSION_CONFIGURATOR_EXPORT extern const char name[];
#include "components/network_session_configurator/common/network_switch_list.h"
diff --git a/chromium/components/network_time/BUILD.gn b/chromium/components/network_time/BUILD.gn
index 1c9f285f796..51013f352c9 100644
--- a/chromium/components/network_time/BUILD.gn
+++ b/chromium/components/network_time/BUILD.gn
@@ -4,6 +4,8 @@
static_library("network_time") {
sources = [
+ "historical_latencies_container.cc",
+ "historical_latencies_container.h",
"network_time_pref_names.cc",
"network_time_pref_names.h",
"network_time_tracker.cc",
@@ -24,7 +26,10 @@ static_library("network_time") {
source_set("unit_tests") {
testonly = true
- sources = [ "network_time_tracker_unittest.cc" ]
+ sources = [
+ "historical_latencies_container_unittest.cc",
+ "network_time_tracker_unittest.cc",
+ ]
deps = [
":network_time",
diff --git a/chromium/components/network_time/historical_latencies_container.cc b/chromium/components/network_time/historical_latencies_container.cc
new file mode 100644
index 00000000000..dddc3af7501
--- /dev/null
+++ b/chromium/components/network_time/historical_latencies_container.cc
@@ -0,0 +1,66 @@
+// Copyright 2022 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.
+
+#include "components/network_time/historical_latencies_container.h"
+
+#include <cmath>
+
+#include "base/metrics/field_trial_params.h"
+#include "base/numerics/checked_math.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/time/time.h"
+#include "components/network_time/network_time_tracker.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace network_time {
+
+// Number of previous latencies to use for computing the standard deviation.
+// Should be greater or equal 0 and less or equal kMaxNumHistoricalLatencies. If
+// 0, the standard deviation will not be reported.
+constexpr base::FeatureParam<int> kNumHistoricalLatencies{
+ &kNetworkTimeServiceQuerying, "NumHistoricalLatencies", 3};
+
+void HistoricalLatenciesContainer::Record(base::TimeDelta latency) {
+ latencies_.SaveToBuffer(latency);
+}
+
+absl::optional<base::TimeDelta> HistoricalLatenciesContainer::StdDeviation()
+ const {
+ int num_historical_latencies = kNumHistoricalLatencies.Get();
+ if (num_historical_latencies <= 0 ||
+ num_historical_latencies > kMaxNumHistoricalLatencies) {
+ return absl::nullopt;
+ }
+
+ base::CheckedNumeric<int64_t> mean;
+ {
+ auto it = latencies_.End();
+ for (int i = 0; i < num_historical_latencies; ++i, --it) {
+ if (!it) // Less than `num_historical_latencies` recorded so far.
+ return absl::nullopt;
+ mean += it->InMicroseconds();
+ }
+ mean = mean / num_historical_latencies;
+ }
+
+ base::CheckedNumeric<int64_t> variance;
+ {
+ auto it = latencies_.End();
+ for (int i = 0; i < num_historical_latencies; ++i, --it) {
+ base::CheckedNumeric<int64_t> diff_from_mean =
+ mean - it->InMicroseconds();
+ variance += diff_from_mean * diff_from_mean;
+ }
+ }
+ if (!variance.IsValid())
+ return absl::nullopt;
+ base::TimeDelta std_deviation = base::Microseconds(
+ std::lround(std::sqrt(base::strict_cast<double>(variance.ValueOrDie()))));
+
+ if (std_deviation.is_inf())
+ return absl::nullopt;
+ return std_deviation;
+}
+
+} // namespace network_time
diff --git a/chromium/components/network_time/historical_latencies_container.h b/chromium/components/network_time/historical_latencies_container.h
new file mode 100644
index 00000000000..7ff1bcca88a
--- /dev/null
+++ b/chromium/components/network_time/historical_latencies_container.h
@@ -0,0 +1,35 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_NETWORK_TIME_HISTORICAL_LATENCIES_CONTAINER_H_
+#define COMPONENTS_NETWORK_TIME_HISTORICAL_LATENCIES_CONTAINER_H_
+
+#include "base/containers/ring_buffer.h"
+#include "base/time/time.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace network_time {
+
+// Number of historical latencies to record.
+constexpr int kMaxNumHistoricalLatencies = 16;
+
+// A class to record latencies of the previous `kNumHistoricalLatencies` time
+// fetches.
+class HistoricalLatenciesContainer {
+ public:
+ // Records a new latency in the container.
+ void Record(base::TimeDelta latency);
+
+ // Computes the standard deviation of the latest latencies. Returns nullopt
+ // if not enough latencies have been recorded yet.
+ absl::optional<base::TimeDelta> StdDeviation() const;
+
+ private:
+ base::RingBuffer<base::TimeDelta, size_t{kMaxNumHistoricalLatencies}>
+ latencies_;
+};
+
+} // namespace network_time
+
+#endif // COMPONENTS_NETWORK_TIME_HISTORICAL_LATENCIES_CONTAINER_H_
diff --git a/chromium/components/network_time/historical_latencies_container_unittest.cc b/chromium/components/network_time/historical_latencies_container_unittest.cc
new file mode 100644
index 00000000000..e0b4bf0324b
--- /dev/null
+++ b/chromium/components/network_time/historical_latencies_container_unittest.cc
@@ -0,0 +1,73 @@
+// Copyright 2014 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.
+
+#include "components/network_time/historical_latencies_container.h"
+
+#include "base/metrics/field_trial_params.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/time/time.h"
+#include "components/network_time/network_time_tracker.h"
+#include "testing/gmock/include/gmock/gmock-matchers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace network_time {
+
+TEST(HistoricalLatenciesContainerTest, StdDeviation) {
+ network_time::HistoricalLatenciesContainer latencies;
+ latencies.Record(base::Seconds(1));
+ EXPECT_EQ(absl::nullopt, latencies.StdDeviation());
+
+ latencies.Record(base::Seconds(1));
+ EXPECT_EQ(absl::nullopt, latencies.StdDeviation());
+
+ latencies.Record(base::Seconds(1));
+ EXPECT_THAT(latencies.StdDeviation(), testing::Optional(base::Seconds(0)));
+
+ latencies.Record(base::Seconds(2));
+ EXPECT_NE(absl::nullopt, latencies.StdDeviation());
+ // The standard deviation of [1,1,2] is 0.816.
+ EXPECT_EQ(816, latencies.StdDeviation().value().InMilliseconds());
+
+ latencies.Record(-base::Seconds(10));
+ EXPECT_NE(absl::nullopt, latencies.StdDeviation());
+ // The standard deviation of [1,2,-10] is 9.416.
+ EXPECT_EQ(9416, latencies.StdDeviation().value().InMilliseconds());
+
+ {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeatureWithParameters(
+ kNetworkTimeServiceQuerying,
+ base::FieldTrialParams({{"NumHistoricalLatencies", "2"}}));
+ EXPECT_NE(absl::nullopt, latencies.StdDeviation());
+ // The standard deviation of [2,-10] is 8.485.
+ EXPECT_EQ(8485, latencies.StdDeviation().value().InMilliseconds());
+ }
+
+ {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeatureWithParameters(
+ kNetworkTimeServiceQuerying,
+ base::FieldTrialParams({{"NumHistoricalLatencies", "0"}}));
+ EXPECT_EQ(absl::nullopt, latencies.StdDeviation());
+ }
+
+ {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeatureWithParameters(
+ kNetworkTimeServiceQuerying,
+ base::FieldTrialParams({{"NumHistoricalLatencies", "-10"}}));
+ EXPECT_EQ(absl::nullopt, latencies.StdDeviation());
+ }
+
+ {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeatureWithParameters(
+ kNetworkTimeServiceQuerying,
+ base::FieldTrialParams({{"NumHistoricalLatencies", "200"}}));
+ EXPECT_EQ(absl::nullopt, latencies.StdDeviation());
+ }
+}
+
+} // namespace network_time
diff --git a/chromium/components/network_time/network_time_test_utils.cc b/chromium/components/network_time/network_time_test_utils.cc
index f916dc47991..547aea9f7e6 100644
--- a/chromium/components/network_time/network_time_test_utils.cc
+++ b/chromium/components/network_time/network_time_test_utils.cc
@@ -22,21 +22,27 @@ namespace network_time {
// and the x-cup-server-proof header into |kGoodTimeResponseBody| and
// |kGoodTimeResponseServerProofHeader| respectively, and the
// 'current_time_millis' value of the response into
-// |kGoodTimeResponseHandlerJsTime|. Do this twice, so that the two requests
-// appear in order below.
+// |kGoodTimeResponseHandlerJsTime|. Do this three times, so that the three
+// requests appear in order below.
const char* kGoodTimeResponseBody[] = {
")]}'\n{\"current_time_millis\":1619464140565,"
"\"server_nonce\":-1.656679479914492E230}",
")]}'\n{\"current_time_millis\":1619464273366,"
- "\"server_nonce\":2.1195306862817135E-5}"};
+ "\"server_nonce\":2.1195306862817135E-5}",
+ ")]}'\n{\"current_time_millis\":1642162812422,"
+ "\"server_nonce\":3.374791108303444E207}"};
const char* kGoodTimeResponseServerProofHeader[] = {
"3045022100f829ced2af34ade53400f66eef6df9af732fa8bfe08517287c2805c92891e321"
"022062fb405b2cf12bc3e2ac037985c4b8065a62e86e29a2e745ebff80fd52189c6a:"
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"3046022100c78436ad47904634aacd33f4c4bcb55bd6f7f2ed84a620fda0deaede99c32de6"
"022100b595458bd03d83f33bfb891de1327b26620d576937f3713af59bb1f2c53f2e8b:"
+ "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+ "3045022100f50a8e6f97d8c362f878e2c988ab2c983e536de4dc2116a314699a4010d7d8b8"
+ "02202ace752a45721399ec6dd704da55700c9b11626f7c55a72037db255b79992476:"
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"};
-const double kGoodTimeResponseHandlerJsTime[] = {1619464140565, 1619464273366};
+const double kGoodTimeResponseHandlerJsTime[] = {1619464140565, 1619464273366,
+ 1642162812422};
std::unique_ptr<net::test_server::HttpResponse> GoodTimeResponseHandler(
const net::test_server::HttpRequest& request) {
diff --git a/chromium/components/network_time/network_time_test_utils.h b/chromium/components/network_time/network_time_test_utils.h
index 58b7f73eb0a..65efbfa2aaa 100644
--- a/chromium/components/network_time/network_time_test_utils.h
+++ b/chromium/components/network_time/network_time_test_utils.h
@@ -26,16 +26,16 @@ namespace network_time {
// version and 123123123 as the nonce. Use
// NetworkTimeTracker::OverrideNonceForTesting() to set the nonce so
// that this response validates.
-extern const char* kGoodTimeResponseBody[2];
+extern const char* kGoodTimeResponseBody[3];
// The x-cup-server-proof header values that should be served along with
// |kGoodTimeResponseBody| to make a test server response be accepted by
// NetworkTimeTracker as a valid response.
-extern const char* kGoodTimeResponseServerProofHeader[2];
+extern const char* kGoodTimeResponseServerProofHeader[3];
// The times that |kGoodTimeResponseBody| uses. Can be converted to a
// base::Time with base::Time::FromJsTime.
-extern const double kGoodTimeResponseHandlerJsTime[2];
+extern const double kGoodTimeResponseHandlerJsTime[3];
// Returns a valid network time response using the constants above. See
// comments in the .cc for how to update the time returned in the response.
diff --git a/chromium/components/network_time/network_time_tracker.cc b/chromium/components/network_time/network_time_tracker.cc
index 16b763068ca..b53b5d1da50 100644
--- a/chromium/components/network_time/network_time_tracker.cc
+++ b/chromium/components/network_time/network_time_tracker.cc
@@ -16,6 +16,7 @@
#include "base/json/json_reader.h"
#include "base/logging.h"
#include "base/metrics/field_trial_params.h"
+#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros_local.h"
#include "base/rand_util.h"
#include "base/run_loop.h"
@@ -23,6 +24,7 @@
#include "base/strings/string_piece.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/tick_clock.h"
+#include "base/time/time.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "components/client_update_protocol/ecdsa.h"
@@ -57,7 +59,7 @@ namespace network_time {
// Network time queries are enabled on all desktop platforms except ChromeOS,
// which uses tlsdated to set the system time.
-#if defined(OS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_IOS)
const base::Feature kNetworkTimeServiceQuerying{
"NetworkTimeServiceQuerying", base::FEATURE_DISABLED_BY_DEFAULT};
#else
@@ -159,6 +161,12 @@ void RecordFetchValidHistogram(bool valid) {
LOCAL_HISTOGRAM_BOOLEAN("NetworkTimeTracker.UpdateTimeFetchValid", valid);
}
+void UmaHistogramCustomTimesClockSkew(const char* name,
+ base::TimeDelta sample) {
+ base::UmaHistogramCustomTimes(name, sample, base::Milliseconds(1),
+ base::Days(7), 50);
+}
+
} // namespace
// static
@@ -180,7 +188,7 @@ NetworkTimeTracker::NetworkTimeTracker(
tick_clock_(std::move(tick_clock)),
pref_service_(pref_service),
time_query_completed_(false) {
- const base::DictionaryValue* time_mapping =
+ const base::Value* time_mapping =
pref_service_->GetDictionary(prefs::kNetworkTimeMapping);
absl::optional<double> time_js = time_mapping->FindDoubleKey(kPrefTime);
absl::optional<double> ticks_js = time_mapping->FindDoubleKey(kPrefTicks);
@@ -288,8 +296,8 @@ void NetworkTimeTracker::SetPublicKeyForTesting(base::StringPiece key) {
query_signer_ = client_update_protocol::Ecdsa::Create(kKeyVersion, key);
}
-bool NetworkTimeTracker::QueryTimeServiceForTesting() {
- CheckTime();
+bool NetworkTimeTracker::QueryTimeServiceForTesting(bool on_demand) {
+ CheckTime(on_demand ? CheckTimeType::ON_DEMAND : CheckTimeType::BACKGROUND);
return time_fetcher_ != nullptr;
}
@@ -308,6 +316,10 @@ void NetworkTimeTracker::OverrideNonceForTesting(uint32_t nonce) {
query_signer_->OverrideNonceForTesting(kKeyVersion, nonce);
}
+void NetworkTimeTracker::OverrideUMANoiseFactorForTesting(double noise_factor) {
+ uma_noise_factor_ = noise_factor;
+}
+
base::TimeDelta NetworkTimeTracker::GetTimerDelayForTesting() const {
DCHECK(timer_.IsRunning());
return timer_.GetCurrentDelay();
@@ -397,7 +409,7 @@ bool NetworkTimeTracker::StartTimeFetch(base::OnceClosure closure) {
// Cancel any fetches that are scheduled for the future, and try to
// start one now.
timer_.Stop();
- CheckTime();
+ CheckTime(CheckTimeType::ON_DEMAND);
// CheckTime() does not necessarily start a fetch; for example, time
// queries might be disabled or network time might already be
@@ -410,7 +422,7 @@ bool NetworkTimeTracker::StartTimeFetch(base::OnceClosure closure) {
return true;
}
-void NetworkTimeTracker::CheckTime() {
+void NetworkTimeTracker::CheckTime(CheckTimeType check_type) {
DCHECK(thread_checker_.CalledOnValidThread());
base::TimeDelta interval = kCheckTimeInterval.Get();
@@ -469,7 +481,7 @@ void NetworkTimeTracker::CheckTime() {
time_fetcher_->DownloadToString(
url_loader_factory_.get(),
base::BindOnce(&NetworkTimeTracker::OnURLLoaderComplete,
- base::Unretained(this)),
+ base::Unretained(this), check_type),
max_response_size_);
fetch_started_ = tick_clock_->NowTicks();
@@ -478,6 +490,7 @@ void NetworkTimeTracker::CheckTime() {
}
bool NetworkTimeTracker::UpdateTimeFromResponse(
+ CheckTimeType check_type,
std::unique_ptr<std::string> response_body) {
int response_code = 0;
if (time_fetcher_->ResponseInfo() && time_fetcher_->ResponseInfo()->headers)
@@ -536,6 +549,7 @@ bool NetworkTimeTracker::UpdateTimeFromResponse(
// between time fetches.
base::TimeDelta latency = tick_clock_->NowTicks() - fetch_started_;
LOCAL_HISTOGRAM_TIMES("NetworkTimeTracker.TimeQueryLatency", latency);
+
if (!last_fetched_time_.is_null()) {
LOCAL_HISTOGRAM_CUSTOM_TIMES("NetworkTimeTracker.TimeBetweenFetches",
current_time - last_fetched_time_,
@@ -543,7 +557,8 @@ bool NetworkTimeTracker::UpdateTimeFromResponse(
}
last_fetched_time_ = current_time;
- RecordClockSkewHistograms(current_time, latency);
+ if (check_type == CheckTimeType::BACKGROUND)
+ RecordClockSkewHistograms(current_time, latency);
UpdateNetworkTime(current_time, resolution, latency, tick_clock_->NowTicks());
return true;
@@ -551,47 +566,40 @@ bool NetworkTimeTracker::UpdateTimeFromResponse(
void NetworkTimeTracker::RecordClockSkewHistograms(
base::Time current_time,
- base::TimeDelta fetch_latency) const {
+ base::TimeDelta fetch_latency) {
// Compute the skew by comparing the reference clock to the system clock. Note
// that the server processed our query roughly `fetch_latency/2` units of time
// in the past. Adjust the `current_time` accordingly.
- const base::TimeDelta system_clock_skew =
- base::Time::NowFromSystemTime() - (current_time + fetch_latency / 2);
-
- enum class ClockSkewRange {
- TooSmall = 0,
- InRange = 1,
- TooBig = 2,
- kMaxValue = TooBig,
- };
-
- auto DetermineClockSkewRange =
- [](base::TimeDelta system_clock_skew) -> ClockSkewRange {
- // These bounds must be updated if/when we switch to a custom "times"
- // histogram. For now, they are calibrated for `LOCAL_HISTOGRAM_TIMES`.
- if (system_clock_skew > base::Seconds(10))
- return ClockSkewRange::TooBig;
- if (system_clock_skew < base::Milliseconds(1))
- return ClockSkewRange::TooSmall;
- return ClockSkewRange::InRange;
- };
+ base::TimeDelta system_clock_skew =
+ clock_->Now() - (current_time + fetch_latency / 2);
+
+ // Add noise for privacy reasons.
+ system_clock_skew +=
+ system_clock_skew * (2 * base::RandDouble() - 1) * uma_noise_factor_;
// Explicitly record clock skew of zero in the "positive" histograms.
if (system_clock_skew >= base::TimeDelta()) {
- LOCAL_HISTOGRAM_TIMES("NetworkTimeTracker.ClockSkew.Magnitude.Positive",
- system_clock_skew);
- LOCAL_HISTOGRAM_ENUMERATION("NetworkTimeTracker.ClockSkew.Range.Positive",
- DetermineClockSkewRange(system_clock_skew));
+ UmaHistogramCustomTimesClockSkew(
+ "PrivacyBudget.ClockSkew.Magnitude.Positive", system_clock_skew);
} else if (system_clock_skew.is_negative()) {
- base::TimeDelta magnitude = system_clock_skew.magnitude();
- LOCAL_HISTOGRAM_TIMES("NetworkTimeTracker.ClockSkew.Magnitude.Negative",
- magnitude);
- LOCAL_HISTOGRAM_ENUMERATION("NetworkTimeTracker.ClockSkew.Range.Negative",
- DetermineClockSkewRange(magnitude));
+ UmaHistogramCustomTimesClockSkew(
+ "PrivacyBudget.ClockSkew.Magnitude.Negative", -system_clock_skew);
+ }
+
+ base::UmaHistogramTimes("PrivacyBudget.ClockSkew.FetchLatency",
+ fetch_latency);
+ historical_latencies_.Record(fetch_latency);
+
+ absl::optional<base::TimeDelta> latency_jitter =
+ historical_latencies_.StdDeviation();
+ if (latency_jitter.has_value()) {
+ base::UmaHistogramTimes("PrivacyBudget.ClockSkew.FetchLatencyJitter",
+ latency_jitter.value());
}
}
void NetworkTimeTracker::OnURLLoaderComplete(
+ CheckTimeType check_type,
std::unique_ptr<std::string> response_body) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(time_fetcher_);
@@ -601,6 +609,7 @@ void NetworkTimeTracker::OnURLLoaderComplete(
// After completion of a query, whether succeeded or failed, go to sleep for a
// long time.
if (!UpdateTimeFromResponse(
+ check_type,
std::move(response_body))) { // On error, back off.
if (backoff_ < base::Days(2)) {
backoff_ *= 2;
@@ -628,7 +637,10 @@ void NetworkTimeTracker::QueueCheckTime(base::TimeDelta delay) {
FetchBehavior behavior = kFetchBehavior.Get();
if (behavior == FETCHES_IN_BACKGROUND_ONLY ||
behavior == FETCHES_IN_BACKGROUND_AND_ON_DEMAND) {
- timer_.Start(FROM_HERE, delay, this, &NetworkTimeTracker::CheckTime);
+ timer_.Start(
+ FROM_HERE, delay,
+ base::BindRepeating(&NetworkTimeTracker::CheckTime,
+ base::Unretained(this), CheckTimeType::BACKGROUND));
}
}
diff --git a/chromium/components/network_time/network_time_tracker.h b/chromium/components/network_time/network_time_tracker.h
index d9b58840344..71ad26f045a 100644
--- a/chromium/components/network_time/network_time_tracker.h
+++ b/chromium/components/network_time/network_time_tracker.h
@@ -17,6 +17,7 @@
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "build/build_config.h"
+#include "components/network_time/historical_latencies_container.h"
#include "url/gurl.h"
class PrefRegistrySimple;
@@ -38,7 +39,7 @@ class SharedURLLoaderFactory;
namespace network_time {
// Clock resolution is platform dependent.
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
const int64_t kTicksResolutionMs = base::Time::kMinLowResolutionThresholdMs;
#else
const int64_t kTicksResolutionMs = 1; // Assume 1ms for non-windows platforms.
@@ -156,30 +157,40 @@ class NetworkTimeTracker {
GURL GetTimeServerURLForTesting() const;
- bool QueryTimeServiceForTesting();
+ bool QueryTimeServiceForTesting(bool on_demand = true);
void WaitForFetchForTesting(uint32_t nonce);
void OverrideNonceForTesting(uint32_t nonce);
+ void OverrideUMANoiseFactorForTesting(double noise_factor);
+
base::TimeDelta GetTimerDelayForTesting() const;
private:
+ // Tells how a call to CheckTime was initiated.
+ enum class CheckTimeType {
+ ON_DEMAND,
+ BACKGROUND,
+ };
+
// Checks whether a network time query should be issued, and issues one if so.
// Upon response, execution resumes in |OnURLFetchComplete|.
- void CheckTime();
+ void CheckTime(CheckTimeType check_type);
// Updates network time from a time server response, returning true
// if successful.
- bool UpdateTimeFromResponse(std::unique_ptr<std::string> response_body);
+ bool UpdateTimeFromResponse(CheckTimeType check_type,
+ std::unique_ptr<std::string> response_body);
// Records histograms related to clock skew. All of these histograms are
// currently local-only. See https://crbug.com/1258624.
void RecordClockSkewHistograms(base::Time current_time,
- base::TimeDelta fetch_latency) const;
+ base::TimeDelta fetch_latency);
// Called to process responses from the secure time service.
- void OnURLLoaderComplete(std::unique_ptr<std::string> response_body);
+ void OnURLLoaderComplete(CheckTimeType check_type,
+ std::unique_ptr<std::string> response_body);
// Sets the next time query to be run at the specified time.
void QueueCheckTime(base::TimeDelta delay);
@@ -238,6 +249,15 @@ class NetworkTimeTracker {
// Callbacks to run when the in-progress time fetch completes.
std::vector<base::OnceClosure> fetch_completion_callbacks_;
+ // Computes statistics over a sliding window of the most recent fetch
+ // latencies.
+ HistoricalLatenciesContainer historical_latencies_;
+
+ // Clock skews reported to UMA will have ±`uma_noise_factor_` noise (relative
+ // to the clock skew itself) for privacy reasons. For example, specifying 0.1
+ // here means ±10% noise.
+ double uma_noise_factor_ = 0.1;
+
base::ThreadChecker thread_checker_;
};
diff --git a/chromium/components/network_time/network_time_tracker_unittest.cc b/chromium/components/network_time/network_time_tracker_unittest.cc
index 3a40a5fe223..c4e0feb5849 100644
--- a/chromium/components/network_time/network_time_tracker_unittest.cc
+++ b/chromium/components/network_time/network_time_tracker_unittest.cc
@@ -17,6 +17,7 @@
#include "base/test/simple_test_clock.h"
#include "base/test/simple_test_tick_clock.h"
#include "base/test/task_environment.h"
+#include "base/time/time.h"
#include "build/build_config.h"
#include "components/client_update_protocol/ecdsa.h"
#include "components/network_time/network_time_pref_names.h"
@@ -395,7 +396,7 @@ TEST_F(NetworkTimeTrackerTest, DeserializeOldFormat) {
EXPECT_EQ(NetworkTimeTracker::NETWORK_TIME_AVAILABLE,
tracker_->GetNetworkTime(&out_network_time, nullptr));
absl::optional<double> local, network;
- const base::DictionaryValue* saved_prefs =
+ const base::Value* saved_prefs =
pref_service_.GetDictionary(prefs::kNetworkTimeMapping);
local = saved_prefs->FindDoubleKey("local");
network = saved_prefs->FindDoubleKey("network");
@@ -695,7 +696,7 @@ TEST_F(NetworkTimeTrackerTest, UpdateFromNetworkServerError) {
histograms.ExpectTotalCount(kFetchValidHistogram, 0);
}
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
// http://crbug.com/658619
#define MAYBE_UpdateFromNetworkNetworkError \
DISABLED_UpdateFromNetworkNetworkError
@@ -911,4 +912,110 @@ TEST_F(NetworkTimeTrackerTest, TimeBetweenFetchesHistogram) {
1);
}
+TEST_F(NetworkTimeTrackerTest, ClockSkewHistograms) {
+ MultipleGoodTimeResponseHandler response_handler;
+ base::HistogramTester histograms;
+
+ test_server_->RegisterRequestHandler(
+ base::BindRepeating(&MultipleGoodTimeResponseHandler::ResponseHandler,
+ base::Unretained(&response_handler)));
+ EXPECT_TRUE(test_server_->Start());
+ tracker_->SetTimeServerURLForTesting(test_server_->GetURL("/"));
+
+ // Disable noise for deterministic tests.
+ tracker_->OverrideUMANoiseFactorForTesting(0.0);
+
+ clock_->SetNow(
+ base::Time::FromJsTime(kGoodTimeResponseHandlerJsTime[0] + 3500));
+ EXPECT_TRUE(tracker_->QueryTimeServiceForTesting(/*on_demand=*/false));
+ // Simulate 1s latency.
+ tick_clock_->Advance(base::Seconds(1));
+ tracker_->WaitForFetchForTesting(123123123);
+
+ histograms.ExpectUniqueTimeSample(
+ "PrivacyBudget.ClockSkew.Magnitude.Positive", base::Seconds(3), 1);
+ histograms.ExpectTotalCount("PrivacyBudget.ClockSkew.Magnitude.Negative", 0);
+ histograms.ExpectUniqueTimeSample("PrivacyBudget.ClockSkew.FetchLatency",
+ base::Seconds(1), 1);
+ histograms.ExpectTotalCount("PrivacyBudget.ClockSkew.FetchLatencyJitter", 0);
+
+ clock_->SetNow(
+ base::Time::FromJsTime(kGoodTimeResponseHandlerJsTime[1] + 3500));
+ EXPECT_TRUE(tracker_->QueryTimeServiceForTesting(/*on_demand=*/false));
+ // Simulate 1s latency.
+ tick_clock_->Advance(base::Seconds(1));
+ tracker_->WaitForFetchForTesting(123123123);
+
+ histograms.ExpectUniqueTimeSample(
+ "PrivacyBudget.ClockSkew.Magnitude.Positive", base::Seconds(3), 2);
+ histograms.ExpectTotalCount("PrivacyBudget.ClockSkew.Magnitude.Negative", 0);
+ histograms.ExpectUniqueTimeSample("PrivacyBudget.ClockSkew.FetchLatency",
+ base::Seconds(1), 2);
+ histograms.ExpectTotalCount("PrivacyBudget.ClockSkew.FetchLatencyJitter", 0);
+
+ clock_->SetNow(
+ base::Time::FromJsTime(kGoodTimeResponseHandlerJsTime[2] - 2500));
+ EXPECT_TRUE(tracker_->QueryTimeServiceForTesting(/*on_demand=*/false));
+ // Simulate 1s latency.
+ tick_clock_->Advance(base::Seconds(1));
+ tracker_->WaitForFetchForTesting(123123123);
+
+ histograms.ExpectUniqueTimeSample(
+ "PrivacyBudget.ClockSkew.Magnitude.Positive", base::Seconds(3), 2);
+ histograms.ExpectUniqueTimeSample(
+ "PrivacyBudget.ClockSkew.Magnitude.Negative", base::Seconds(3), 1);
+ histograms.ExpectUniqueTimeSample("PrivacyBudget.ClockSkew.FetchLatency",
+ base::Seconds(1), 3);
+ // After three fetches, the FetchLatencyJitter should be reported.
+ histograms.ExpectUniqueTimeSample(
+ "PrivacyBudget.ClockSkew.FetchLatencyJitter", base::Seconds(0), 1);
+}
+
+TEST_F(NetworkTimeTrackerTest, ClockSkewHistogramsNoise) {
+ MultipleGoodTimeResponseHandler response_handler;
+ base::HistogramTester histograms;
+
+ test_server_->RegisterRequestHandler(
+ base::BindRepeating(&MultipleGoodTimeResponseHandler::ResponseHandler,
+ base::Unretained(&response_handler)));
+ EXPECT_TRUE(test_server_->Start());
+ tracker_->SetTimeServerURLForTesting(test_server_->GetURL("/"));
+
+ clock_->SetNow(
+ base::Time::FromJsTime(kGoodTimeResponseHandlerJsTime[0] + 3500));
+ EXPECT_TRUE(tracker_->QueryTimeServiceForTesting(/*on_demand=*/false));
+ // Simulate 1s latency.
+ tick_clock_->Advance(base::Seconds(1));
+ tracker_->WaitForFetchForTesting(123123123);
+
+ std::vector<base::Bucket> buckets =
+ histograms.GetAllSamples("PrivacyBudget.ClockSkew.Magnitude.Positive");
+
+ // The real clock skew is 3000ms. With 10% noise, this means that there should
+ // be exactly one sample between 2700 and 3300.
+ const int64_t sum =
+ histograms.GetTotalSum("PrivacyBudget.ClockSkew.Magnitude.Positive");
+ EXPECT_LE(2700, sum);
+ EXPECT_LE(sum, 3300);
+}
+
+TEST_F(NetworkTimeTrackerTest, ClockSkewHistogramsEmptyForOnDemandChecks) {
+ MultipleGoodTimeResponseHandler response_handler;
+ base::HistogramTester histograms;
+
+ test_server_->RegisterRequestHandler(
+ base::BindRepeating(&MultipleGoodTimeResponseHandler::ResponseHandler,
+ base::Unretained(&response_handler)));
+ EXPECT_TRUE(test_server_->Start());
+ tracker_->SetTimeServerURLForTesting(test_server_->GetURL("/"));
+
+ EXPECT_TRUE(tracker_->QueryTimeServiceForTesting(/*on_demand=*/true));
+ tracker_->WaitForFetchForTesting(123123123);
+
+ histograms.ExpectTotalCount("PrivacyBudget.ClockSkew.Magnitude.Positive", 0);
+ histograms.ExpectTotalCount("PrivacyBudget.ClockSkew.Magnitude.Negative", 0);
+ histograms.ExpectTotalCount("PrivacyBudget.ClockSkew.FetchLatency", 0);
+ histograms.ExpectTotalCount("PrivacyBudget.ClockSkew.FetchLatencyJitter", 0);
+}
+
} // namespace network_time
diff --git a/chromium/components/new_or_sad_tab_strings.grdp b/chromium/components/new_or_sad_tab_strings.grdp
index a02ab8acb82..be16d7f17ae 100644
--- a/chromium/components/new_or_sad_tab_strings.grdp
+++ b/chromium/components/new_or_sad_tab_strings.grdp
@@ -156,14 +156,26 @@
<message name="IDS_NEW_TAB_OTR_SUBTITLE_WITH_READING_LIST" desc="Subtitle of the Incognito new tab page, explaining to the user that the Incognito mode hides their browsing activity from other people using the same device. The second sentence clarifies that there are two important exceptions from this rule - downloaded files and added bookmarks will be persisted even after the Incognito session is closed." formatter_data="android_java">
Now you can browse privately, and other people who use this device won’t see your activity. However, downloads, bookmarks and reading list items will be saved.
</message>
- <message name="IDS_NEW_TAB_OTR_NOT_SAVED" desc="Bullet points listing data that are not saved in the Incognito mode. 'Browsing history' means a history of visited websites. 'Cookies and site data' refers to data saved by websites on the user's device (e.g. sign-in state, preferences, etc.). 'Information entered in forms' refers to names, addresses, passwords etc. that users enter into forms on the web." formatter_data="android_java">
- Chrome <ph name="BEGIN_EMPHASIS">&lt;em&gt;</ph>won’t save<ph name="END_EMPHASIS">&lt;/em&gt;</ph> the following information:
- <ph name="BEGIN_LIST">&lt;ul&gt;</ph>
- <ph name="LIST_ITEM">&lt;li&gt;</ph>Your browsing history
- <ph name="LIST_ITEM">&lt;li&gt;</ph>Cookies and site data
- <ph name="LIST_ITEM">&lt;li&gt;</ph>Information entered in forms
- <ph name="END_LIST">&lt;/ul&gt;</ph>
- </message>
+ <if expr="_google_chrome">
+ <message name="IDS_NEW_TAB_OTR_NOT_SAVED" desc="Bullet points listing data that are not saved in the Incognito mode. 'Browsing history' means a history of visited websites. 'Cookies and site data' refers to data saved by websites on the user's device (e.g. sign-in state, preferences, etc.). 'Information entered in forms' refers to names, addresses, passwords etc. that users enter into forms on the web." formatter_data="android_java">
+ Chrome <ph name="BEGIN_EMPHASIS">&lt;em&gt;</ph>won’t save<ph name="END_EMPHASIS">&lt;/em&gt;</ph> the following information:
+ <ph name="BEGIN_LIST">&lt;ul&gt;</ph>
+ <ph name="LIST_ITEM">&lt;li&gt;</ph>Your browsing history
+ <ph name="LIST_ITEM">&lt;li&gt;</ph>Cookies and site data
+ <ph name="LIST_ITEM">&lt;li&gt;</ph>Information entered in forms
+ <ph name="END_LIST">&lt;/ul&gt;</ph>
+ </message>
+ </if>
+ <if expr="not _google_chrome">
+ <message name="IDS_NEW_TAB_OTR_NOT_SAVED" desc="Bullet points listing data that are not saved in the Incognito mode. 'Browsing history' means a history of visited websites. 'Cookies and site data' refers to data saved by websites on the user's device (e.g. sign-in state, preferences, etc.). 'Information entered in forms' refers to names, addresses, passwords etc. that users enter into forms on the web." formatter_data="android_java">
+ Chromium <ph name="BEGIN_EMPHASIS">&lt;em&gt;</ph>won’t save<ph name="END_EMPHASIS">&lt;/em&gt;</ph> the following information:
+ <ph name="BEGIN_LIST">&lt;ul&gt;</ph>
+ <ph name="LIST_ITEM">&lt;li&gt;</ph>Your browsing history
+ <ph name="LIST_ITEM">&lt;li&gt;</ph>Cookies and site data
+ <ph name="LIST_ITEM">&lt;li&gt;</ph>Information entered in forms
+ <ph name="END_LIST">&lt;/ul&gt;</ph>
+ </message>
+ </if>
<message name="IDS_NEW_TAB_OTR_VISIBLE" desc="Bullet points listing entities that might be able to see the user's Incognito activity. The bullet points elaborate on the fact that Incognito only provides privacy with respect to other users on the same device. Websites you visit still know that you visited them. Your employer, school, and/or internet service provider can still monitor network traffic, even if it comes from the Incognito mode." formatter_data="android_java">
Your activity <ph name="BEGIN_EMPHASIS">&lt;em&gt;</ph>might still be visible<ph name="END_EMPHASIS">&lt;/em&gt;</ph> to:
<ph name="BEGIN_LIST">&lt;ul&gt;</ph>
@@ -186,33 +198,65 @@
<!-- Revamped Incognito New Tab Page strings -->
- <message name="IDS_REVAMPED_INCOGNITO_NTP_TITLE" desc="Title of the Incognito new tab page." formatter_data="android_java">
- Incognito
- </message>
+ <if expr="_google_chrome">
+ <message name="IDS_REVAMPED_INCOGNITO_NTP_TITLE" desc="Title of the Incognito new tab page." formatter_data="android_java">
+ Incognito in Chrome
+ </message>
+ </if>
+ <if expr="not _google_chrome">
+ <message name="IDS_REVAMPED_INCOGNITO_NTP_TITLE" desc="Title of the Incognito new tab page." formatter_data="android_java">
+ Incognito in Chromium
+ </message>
+ </if>
<message name="IDS_REVAMPED_INCOGNITO_NTP_DOES_HEADER" desc="Header for the 'Incognito does' section that informs users about what happens while browsing Incognito: browsing activity, search history and information entered in forms are not saved locally." formatter_data="android_java">
What Incognito does
</message>
- <message name="IDS_REVAMPED_INCOGNITO_NTP_DOES_DESCRIPTION" desc="Paragraph that informs users about Incognito's functionalities: browsing activity, search history and information entered in forms are not saved locally, they are cleared after closing all Incognito tabs. 'Browsing activity' refers to the browsing history (list of visited websites) and the cookies (data saved by websites on the user's device such as: sign-in state, preferences, etc.). 'Search history from this device' means that searches will not be saved locally or used as search suggestions in the future. 'Information entered in forms' refers to names, addresses, passwords etc. that users enter into forms on the web." formatter_data="android_java">
- After closing all Incognito tabs, Chrome clears:
- <ph name="BEGIN_LIST">&lt;ul&gt;</ph>
- <ph name="LIST_ITEM">&lt;li&gt;</ph>Your browsing activity from this device<ph name="END_LIST_ITEM">&lt;/li&gt;</ph>
- <ph name="LIST_ITEM">&lt;li&gt;</ph>Your search history from this device<ph name="END_LIST_ITEM">&lt;/li&gt;</ph>
- <ph name="LIST_ITEM">&lt;li&gt;</ph>Information entered in forms<ph name="END_LIST_ITEM">&lt;/li&gt;</ph>
- <ph name="END_LIST">&lt;/ul&gt;</ph>
- </message>
+ <if expr="_google_chrome">
+ <message name="IDS_REVAMPED_INCOGNITO_NTP_DOES_DESCRIPTION" desc="Paragraph that informs users about Incognito's functionalities: browsing activity, search history and information entered in forms are not saved locally, they are cleared after closing all Incognito tabs. 'Browsing activity' refers to the browsing history (list of visited websites) and the cookies (data saved by websites on the user's device such as: sign-in state, preferences, etc.). 'Search history from this device' means that searches will not be saved locally or used as search suggestions in the future. 'Information entered in forms' refers to names, addresses, passwords etc. that users enter into forms on the web." formatter_data="android_java">
+ When you close all Chrome Incognito tabs, your activity in those tabs is cleared from this device:
+ <ph name="BEGIN_LIST">&lt;ul&gt;</ph>
+ <ph name="LIST_ITEM">&lt;li&gt;</ph>Browsing activity<ph name="END_LIST_ITEM">&lt;/li&gt;</ph>
+ <ph name="LIST_ITEM">&lt;li&gt;</ph>Search history<ph name="END_LIST_ITEM">&lt;/li&gt;</ph>
+ <ph name="LIST_ITEM">&lt;li&gt;</ph>Information entered in forms<ph name="END_LIST_ITEM">&lt;/li&gt;</ph>
+ <ph name="END_LIST">&lt;/ul&gt;</ph>
+ </message>
+ </if>
+ <if expr="not _google_chrome">
+ <message name="IDS_REVAMPED_INCOGNITO_NTP_DOES_DESCRIPTION" desc="Paragraph that informs users about Incognito's functionalities: browsing activity, search history and information entered in forms are not saved locally, they are cleared after closing all Incognito tabs. 'Browsing activity' refers to the browsing history (list of visited websites) and the cookies (data saved by websites on the user's device such as: sign-in state, preferences, etc.). 'Search history from this device' means that searches will not be saved locally or used as search suggestions in the future. 'Information entered in forms' refers to names, addresses, passwords etc. that users enter into forms on the web." formatter_data="android_java">
+ When you close all Chromium Incognito tabs, your activity in those tabs is cleared from this device:
+ <ph name="BEGIN_LIST">&lt;ul&gt;</ph>
+ <ph name="LIST_ITEM">&lt;li&gt;</ph>Browsing activity<ph name="END_LIST_ITEM">&lt;/li&gt;</ph>
+ <ph name="LIST_ITEM">&lt;li&gt;</ph>Search history<ph name="END_LIST_ITEM">&lt;/li&gt;</ph>
+ <ph name="LIST_ITEM">&lt;li&gt;</ph>Information entered in forms<ph name="END_LIST_ITEM">&lt;/li&gt;</ph>
+ <ph name="END_LIST">&lt;/ul&gt;</ph>
+ </message>
+ </if>
<message name="IDS_REVAMPED_INCOGNITO_NTP_DOES_NOT_HEADER" desc="Header for the 'Incognito doesn’t do' section that informs users that they are not invisible online." formatter_data="android_java">
What Incognito doesn’t do
</message>
<message name="IDS_REVAMPED_INCOGNITO_NTP_DOES_NOT_DESCRIPTION" desc="Paragraph that informs users that their online activity is still visible while using Incognito. The bullet points list some examples of entities to which users are not invisible in Incognito and what they can observe. The bullet points elaborate on the fact that Incognito only provides privacy with respect to other users on the same device. Websites you visit still know that you visited them. Employers and schools can still track users' browsing activity and internet service providers can still monitor web traffic, even if it comes from the Incognito mode." formatter_data="android_java">
Incognito does not make you invisible online:
<ph name="BEGIN_LIST">&lt;ul&gt;</ph>
- <ph name="LIST_ITEM">&lt;li&gt;</ph>Sites know when you visit them<ph name="END_LIST_ITEM">&lt;/li&gt;</ph>
+ <ph name="LIST_ITEM">&lt;li&gt;</ph>Sites and the services they use can see visits<ph name="END_LIST_ITEM">&lt;/li&gt;</ph>
<ph name="LIST_ITEM">&lt;li&gt;</ph>Employers or schools can track browsing activity<ph name="END_LIST_ITEM">&lt;/li&gt;</ph>
- <ph name="LIST_ITEM">&lt;li&gt;</ph>Internet service providers may monitor web traffic<ph name="END_LIST_ITEM">&lt;/li&gt;</ph>
+ <ph name="LIST_ITEM">&lt;li&gt;</ph>Internet service providers can monitor web traffic<ph name="END_LIST_ITEM">&lt;/li&gt;</ph>
<ph name="END_LIST">&lt;/ul&gt;</ph>
</message>
- <message name="IDS_REVAMPED_INCOGNITO_NTP_LEARN_MORE" desc="The link text displayed on the Incognito new tab page pointing users to the Incognito learn more page." formatter_data="android_java">
- <ph name="BEGIN_LINK">&lt;a&gt;</ph>Learn more<ph name="END_LINK">&lt;/a&gt;</ph> about Incognito
+ <if expr="_google_chrome">
+ <message name="IDS_REVAMPED_INCOGNITO_NTP_LEARN_MORE" desc="The link text displayed on the Incognito new tab page pointing users to the Incognito learn more page." formatter_data="android_java">
+ <ph name="BEGIN_LINK">&lt;a&gt;</ph>Learn more about Incognito in Chrome<ph name="END_LINK">&lt;/a&gt;</ph>
+ </message>
+ </if>
+ <if expr="not _google_chrome">
+ <message name="IDS_REVAMPED_INCOGNITO_NTP_LEARN_MORE" desc="The link text displayed on the Incognito new tab page pointing users to the Incognito learn more page." formatter_data="android_java">
+ <ph name="BEGIN_LINK">&lt;a&gt;</ph>Learn more about Incognito in Chromium<ph name="END_LINK">&lt;/a&gt;</ph>
+ </message>
+ </if>
+ <message name="IDS_REVAMPED_INCOGNITO_NTP_OTR_THIRD_PARTY_COOKIE" desc="Label for the Block 3rd-party cookie checkbox on the Cookies category." formatter_data="android_java">
+ Block third party cookies in Incognito
+ </message>
+ <message name="IDS_REVAMPED_INCOGNITO_NTP_OTR_THIRD_PARTY_COOKIE_SUBLABEL" desc="A sub-label below the Block 3rd-party cookie checkbox." formatter_data="android_java">
+ Sites can't use cookies that track you across the web. Features on some sites may break.
</message>
</grit-part>
diff --git a/chromium/components/new_or_sad_tab_strings_grdp/IDS_NEW_TAB_OTR_NOT_SAVED.png.sha1 b/chromium/components/new_or_sad_tab_strings_grdp/IDS_NEW_TAB_OTR_NOT_SAVED.png.sha1
index 10a0a494bbb..2ba8ce2e2a0 100644
--- a/chromium/components/new_or_sad_tab_strings_grdp/IDS_NEW_TAB_OTR_NOT_SAVED.png.sha1
+++ b/chromium/components/new_or_sad_tab_strings_grdp/IDS_NEW_TAB_OTR_NOT_SAVED.png.sha1
@@ -1 +1 @@
-766f31860505ce1f7a2b6519d755e84a75bb8753 \ No newline at end of file
+32586090c10825b791d015dee57db1bd00b3328f \ No newline at end of file
diff --git a/chromium/components/new_or_sad_tab_strings_grdp/IDS_REVAMPED_INCOGNITO_NTP_DOES_DESCRIPTION.png.sha1 b/chromium/components/new_or_sad_tab_strings_grdp/IDS_REVAMPED_INCOGNITO_NTP_DOES_DESCRIPTION.png.sha1
index cc5dad8e122..9f82ce21a21 100644
--- a/chromium/components/new_or_sad_tab_strings_grdp/IDS_REVAMPED_INCOGNITO_NTP_DOES_DESCRIPTION.png.sha1
+++ b/chromium/components/new_or_sad_tab_strings_grdp/IDS_REVAMPED_INCOGNITO_NTP_DOES_DESCRIPTION.png.sha1
@@ -1 +1 @@
-707bcf09903cc18191f2f3ad16e675bfbb7f27ce \ No newline at end of file
+53baedcec162646ba0ca45ffa1f045ce93977180 \ No newline at end of file
diff --git a/chromium/components/new_or_sad_tab_strings_grdp/IDS_REVAMPED_INCOGNITO_NTP_DOES_HEADER.png.sha1 b/chromium/components/new_or_sad_tab_strings_grdp/IDS_REVAMPED_INCOGNITO_NTP_DOES_HEADER.png.sha1
index cc5dad8e122..9f82ce21a21 100644
--- a/chromium/components/new_or_sad_tab_strings_grdp/IDS_REVAMPED_INCOGNITO_NTP_DOES_HEADER.png.sha1
+++ b/chromium/components/new_or_sad_tab_strings_grdp/IDS_REVAMPED_INCOGNITO_NTP_DOES_HEADER.png.sha1
@@ -1 +1 @@
-707bcf09903cc18191f2f3ad16e675bfbb7f27ce \ No newline at end of file
+53baedcec162646ba0ca45ffa1f045ce93977180 \ No newline at end of file
diff --git a/chromium/components/new_or_sad_tab_strings_grdp/IDS_REVAMPED_INCOGNITO_NTP_DOES_NOT_DESCRIPTION.png.sha1 b/chromium/components/new_or_sad_tab_strings_grdp/IDS_REVAMPED_INCOGNITO_NTP_DOES_NOT_DESCRIPTION.png.sha1
index cc5dad8e122..9f82ce21a21 100644
--- a/chromium/components/new_or_sad_tab_strings_grdp/IDS_REVAMPED_INCOGNITO_NTP_DOES_NOT_DESCRIPTION.png.sha1
+++ b/chromium/components/new_or_sad_tab_strings_grdp/IDS_REVAMPED_INCOGNITO_NTP_DOES_NOT_DESCRIPTION.png.sha1
@@ -1 +1 @@
-707bcf09903cc18191f2f3ad16e675bfbb7f27ce \ No newline at end of file
+53baedcec162646ba0ca45ffa1f045ce93977180 \ No newline at end of file
diff --git a/chromium/components/new_or_sad_tab_strings_grdp/IDS_REVAMPED_INCOGNITO_NTP_DOES_NOT_HEADER.png.sha1 b/chromium/components/new_or_sad_tab_strings_grdp/IDS_REVAMPED_INCOGNITO_NTP_DOES_NOT_HEADER.png.sha1
index cc5dad8e122..9f82ce21a21 100644
--- a/chromium/components/new_or_sad_tab_strings_grdp/IDS_REVAMPED_INCOGNITO_NTP_DOES_NOT_HEADER.png.sha1
+++ b/chromium/components/new_or_sad_tab_strings_grdp/IDS_REVAMPED_INCOGNITO_NTP_DOES_NOT_HEADER.png.sha1
@@ -1 +1 @@
-707bcf09903cc18191f2f3ad16e675bfbb7f27ce \ No newline at end of file
+53baedcec162646ba0ca45ffa1f045ce93977180 \ No newline at end of file
diff --git a/chromium/components/new_or_sad_tab_strings_grdp/IDS_REVAMPED_INCOGNITO_NTP_LEARN_MORE.png.sha1 b/chromium/components/new_or_sad_tab_strings_grdp/IDS_REVAMPED_INCOGNITO_NTP_LEARN_MORE.png.sha1
index cc5dad8e122..9f82ce21a21 100644
--- a/chromium/components/new_or_sad_tab_strings_grdp/IDS_REVAMPED_INCOGNITO_NTP_LEARN_MORE.png.sha1
+++ b/chromium/components/new_or_sad_tab_strings_grdp/IDS_REVAMPED_INCOGNITO_NTP_LEARN_MORE.png.sha1
@@ -1 +1 @@
-707bcf09903cc18191f2f3ad16e675bfbb7f27ce \ No newline at end of file
+53baedcec162646ba0ca45ffa1f045ce93977180 \ No newline at end of file
diff --git a/chromium/components/new_or_sad_tab_strings_grdp/IDS_REVAMPED_INCOGNITO_NTP_OTR_THIRD_PARTY_COOKIE.png.sha1 b/chromium/components/new_or_sad_tab_strings_grdp/IDS_REVAMPED_INCOGNITO_NTP_OTR_THIRD_PARTY_COOKIE.png.sha1
new file mode 100644
index 00000000000..7b66ca66622
--- /dev/null
+++ b/chromium/components/new_or_sad_tab_strings_grdp/IDS_REVAMPED_INCOGNITO_NTP_OTR_THIRD_PARTY_COOKIE.png.sha1
@@ -0,0 +1 @@
+00ec8f397ac8e05f59687fd9dc2dc815c9688d2e \ No newline at end of file
diff --git a/chromium/components/new_or_sad_tab_strings_grdp/IDS_REVAMPED_INCOGNITO_NTP_OTR_THIRD_PARTY_COOKIE_SUBLABEL.png.sha1 b/chromium/components/new_or_sad_tab_strings_grdp/IDS_REVAMPED_INCOGNITO_NTP_OTR_THIRD_PARTY_COOKIE_SUBLABEL.png.sha1
new file mode 100644
index 00000000000..7b66ca66622
--- /dev/null
+++ b/chromium/components/new_or_sad_tab_strings_grdp/IDS_REVAMPED_INCOGNITO_NTP_OTR_THIRD_PARTY_COOKIE_SUBLABEL.png.sha1
@@ -0,0 +1 @@
+00ec8f397ac8e05f59687fd9dc2dc815c9688d2e \ No newline at end of file
diff --git a/chromium/components/new_or_sad_tab_strings_grdp/IDS_REVAMPED_INCOGNITO_NTP_TITLE.png.sha1 b/chromium/components/new_or_sad_tab_strings_grdp/IDS_REVAMPED_INCOGNITO_NTP_TITLE.png.sha1
index 19928862079..9f82ce21a21 100644
--- a/chromium/components/new_or_sad_tab_strings_grdp/IDS_REVAMPED_INCOGNITO_NTP_TITLE.png.sha1
+++ b/chromium/components/new_or_sad_tab_strings_grdp/IDS_REVAMPED_INCOGNITO_NTP_TITLE.png.sha1
@@ -1 +1 @@
-fb31dc9f167eab341e72738c560883a635e0b9f9 \ No newline at end of file
+53baedcec162646ba0ca45ffa1f045ce93977180 \ No newline at end of file
diff --git a/chromium/components/no_state_prefetch/browser/no_state_prefetch_handle.cc b/chromium/components/no_state_prefetch/browser/no_state_prefetch_handle.cc
index 82206930e81..5dffd2e9c71 100644
--- a/chromium/components/no_state_prefetch/browser/no_state_prefetch_handle.cc
+++ b/chromium/components/no_state_prefetch/browser/no_state_prefetch_handle.cc
@@ -8,6 +8,7 @@
#include "base/check_op.h"
#include "components/no_state_prefetch/browser/no_state_prefetch_contents.h"
+#include "components/no_state_prefetch/common/no_state_prefetch_final_status.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/web_contents.h"
@@ -63,6 +64,10 @@ NoStatePrefetchContents* NoStatePrefetchHandle::contents() const {
return prefetch_data_ ? prefetch_data_->contents() : nullptr;
}
+const GURL& NoStatePrefetchHandle::prerender_url() const {
+ return prerender_url_;
+}
+
NoStatePrefetchHandle::NoStatePrefetchHandle(
NoStatePrefetchManager::NoStatePrefetchData* prefetch_data)
: observer_(nullptr) {
@@ -70,6 +75,9 @@ NoStatePrefetchHandle::NoStatePrefetchHandle(
if (prefetch_data) {
prefetch_data_ = prefetch_data->AsWeakPtr();
prefetch_data->OnHandleCreated(this);
+ if (prefetch_data->contents()) {
+ prerender_url_ = prefetch_data->contents()->prerender_url();
+ }
}
}
diff --git a/chromium/components/no_state_prefetch/browser/no_state_prefetch_handle.h b/chromium/components/no_state_prefetch/browser/no_state_prefetch_handle.h
index 82442566a30..b245bb5811c 100644
--- a/chromium/components/no_state_prefetch/browser/no_state_prefetch_handle.h
+++ b/chromium/components/no_state_prefetch/browser/no_state_prefetch_handle.h
@@ -8,6 +8,7 @@
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "components/no_state_prefetch/browser/no_state_prefetch_manager.h"
+#include "url/gurl.h"
namespace prerender {
@@ -68,6 +69,8 @@ class NoStatePrefetchHandle : public NoStatePrefetchContents::Observer {
NoStatePrefetchContents* contents() const;
+ const GURL& prerender_url() const;
+
// Returns whether this NoStatePrefetchHandle represents the same prefetch as
// the other NoStatePrefetchHandle object specified.
bool RepresentingSamePrefetchAs(NoStatePrefetchHandle* other) const;
@@ -86,6 +89,9 @@ class NoStatePrefetchHandle : public NoStatePrefetchContents::Observer {
raw_ptr<Observer> observer_;
+ // The prerendered URL for this handle.
+ GURL prerender_url_;
+
base::WeakPtr<NoStatePrefetchManager::NoStatePrefetchData> prefetch_data_;
base::WeakPtrFactory<NoStatePrefetchHandle> weak_ptr_factory_{this};
};
diff --git a/chromium/components/no_state_prefetch/browser/no_state_prefetch_link_manager.cc b/chromium/components/no_state_prefetch/browser/no_state_prefetch_link_manager.cc
index dbf0eaf2023..3854a8c13dc 100644
--- a/chromium/components/no_state_prefetch/browser/no_state_prefetch_link_manager.cc
+++ b/chromium/components/no_state_prefetch/browser/no_state_prefetch_link_manager.cc
@@ -28,7 +28,7 @@
#include "url/origin.h"
// TODO(crbug.com/722453): Use a dedicated build flag for GuestView.
-#if !defined(OS_ANDROID) && !defined(OS_IOS) && !defined(OS_FUCHSIA)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) && !BUILDFLAG(IS_FUCHSIA)
#include "components/guest_view/browser/guest_view_base.h" // nogncheck
#endif
@@ -92,7 +92,7 @@ absl::optional<int> NoStatePrefetchLinkManager::OnStartLinkTrigger(
blink::mojom::PrerenderAttributesPtr attributes,
const url::Origin& initiator_origin) {
// TODO(crbug.com/722453): Use a dedicated build flag for GuestView.
-#if !defined(OS_ANDROID) && !defined(OS_IOS) && !defined(OS_FUCHSIA)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) && !BUILDFLAG(IS_FUCHSIA)
content::RenderViewHost* rvh = content::RenderViewHost::FromID(
launcher_render_process_id, launcher_render_view_id);
content::WebContents* web_contents =
diff --git a/chromium/components/no_state_prefetch/browser/no_state_prefetch_manager.cc b/chromium/components/no_state_prefetch/browser/no_state_prefetch_manager.cc
index bbacc38c448..cd4e60e7396 100644
--- a/chromium/components/no_state_prefetch/browser/no_state_prefetch_manager.cc
+++ b/chromium/components/no_state_prefetch/browser/no_state_prefetch_manager.cc
@@ -16,6 +16,7 @@
#include "base/callback_helpers.h"
#include "base/check_op.h"
#include "base/command_line.h"
+#include "base/containers/adapters.h"
#include "base/containers/contains.h"
#include "base/containers/cxx20_erase.h"
#include "base/location.h"
@@ -193,7 +194,7 @@ NoStatePrefetchManager::StartPrefetchingFromLinkRelPrerender(
if (!source_web_contents)
return nullptr;
if (origin == ORIGIN_LINK_REL_PRERENDER_CROSSDOMAIN &&
- source_web_contents->GetURL().host_piece() == url.host_piece()) {
+ source_web_contents->GetVisibleURL().host_piece() == url.host_piece()) {
origin = ORIGIN_LINK_REL_PRERENDER_SAMEDOMAIN;
}
// TODO(ajwong): This does not correctly handle storage for isolated apps.
@@ -360,8 +361,8 @@ bool NoStatePrefetchManager::HasRecentlyBeenNavigatedTo(Origin origin,
CleanUpOldNavigations(&navigations_,
base::Milliseconds(kNavigationRecordWindowMs));
- for (auto it = navigations_.rbegin(); it != navigations_.rend(); ++it) {
- if (it->url == url)
+ for (const NavigationRecord& navigation : base::Reversed(navigations_)) {
+ if (navigation.url == url)
return true;
}
@@ -841,14 +842,14 @@ bool NoStatePrefetchManager::GetPrefetchInformation(
if (origin)
*origin = ORIGIN_NONE;
- for (auto it = prefetches_.crbegin(); it != prefetches_.crend(); ++it) {
- if (it->url == url) {
+ for (const NavigationRecord& prefetch : base::Reversed(prefetches_)) {
+ if (prefetch.url == url) {
if (prefetch_age)
- *prefetch_age = GetCurrentTimeTicks() - it->time;
+ *prefetch_age = GetCurrentTimeTicks() - prefetch.time;
if (final_status)
- *final_status = it->final_status;
+ *final_status = prefetch.final_status;
if (origin)
- *origin = it->origin;
+ *origin = prefetch.origin;
return true;
}
}
@@ -858,9 +859,9 @@ bool NoStatePrefetchManager::GetPrefetchInformation(
void NoStatePrefetchManager::SetPrefetchFinalStatusForUrl(
const GURL& url,
FinalStatus final_status) {
- for (auto it = prefetches_.rbegin(); it != prefetches_.rend(); ++it) {
- if (it->url == url) {
- it->final_status = final_status;
+ for (NavigationRecord& prefetch : base::Reversed(prefetches_)) {
+ if (prefetch.url == url) {
+ prefetch.final_status = final_status;
break;
}
}
diff --git a/chromium/components/no_state_prefetch/browser/prerender_history.cc b/chromium/components/no_state_prefetch/browser/prerender_history.cc
index 5204bae4df6..95d2eb52d1b 100644
--- a/chromium/components/no_state_prefetch/browser/prerender_history.cc
+++ b/chromium/components/no_state_prefetch/browser/prerender_history.cc
@@ -8,6 +8,7 @@
#include <utility>
#include "base/check_op.h"
+#include "base/containers/adapters.h"
#include "base/strings/string_number_conversions.h"
#include "base/values.h"
@@ -36,8 +37,7 @@ std::unique_ptr<base::Value> PrerenderHistory::CopyEntriesAsValue() const {
auto return_list = std::make_unique<base::ListValue>();
// Javascript needs times in terms of milliseconds since Jan 1, 1970.
base::Time epoch_start = base::Time::UnixEpoch();
- for (auto it = entries_.rbegin(); it != entries_.rend(); ++it) {
- const Entry& entry = *it;
+ for (const Entry& entry : base::Reversed(entries_)) {
auto entry_dict = std::make_unique<base::DictionaryValue>();
entry_dict->SetString("url", entry.url.spec());
entry_dict->SetString("final_status",
diff --git a/chromium/components/no_state_prefetch/browser/prerender_history_unittest.cc b/chromium/components/no_state_prefetch/browser/prerender_history_unittest.cc
index 712e2a6bf66..56654091fd6 100644
--- a/chromium/components/no_state_prefetch/browser/prerender_history_unittest.cc
+++ b/chromium/components/no_state_prefetch/browser/prerender_history_unittest.cc
@@ -61,7 +61,7 @@ TEST(PrerenderHistoryTest, GetAsValue) {
entry_value = history.CopyEntriesAsValue();
ASSERT_TRUE(entry_value.get() != nullptr);
ASSERT_TRUE(entry_value->is_list());
- EXPECT_TRUE(entry_value->GetList().empty());
+ EXPECT_TRUE(entry_value->GetListDeprecated().empty());
// Base time used for all events. Each event is given a time 1 millisecond
// after that of the previous one.
@@ -77,8 +77,8 @@ TEST(PrerenderHistoryTest, GetAsValue) {
entry_value = history.CopyEntriesAsValue();
ASSERT_TRUE(entry_value.get() != nullptr);
ASSERT_TRUE(entry_value->is_list());
- EXPECT_EQ(1u, entry_value->GetList().size());
- EXPECT_TRUE(ListEntryMatches(entry_value->GetList(), 0u, kFirstUrl,
+ EXPECT_EQ(1u, entry_value->GetListDeprecated().size());
+ EXPECT_TRUE(ListEntryMatches(entry_value->GetListDeprecated(), 0u, kFirstUrl,
kFirstFinalStatus, kFirstOrigin, "0"));
// Add a second entry and make sure both first and second appear.
@@ -92,10 +92,10 @@ TEST(PrerenderHistoryTest, GetAsValue) {
entry_value = history.CopyEntriesAsValue();
ASSERT_TRUE(entry_value.get() != nullptr);
ASSERT_TRUE(entry_value->is_list());
- EXPECT_EQ(2u, entry_value->GetList().size());
- EXPECT_TRUE(ListEntryMatches(entry_value->GetList(), 0u, kSecondUrl,
+ EXPECT_EQ(2u, entry_value->GetListDeprecated().size());
+ EXPECT_TRUE(ListEntryMatches(entry_value->GetListDeprecated(), 0u, kSecondUrl,
kSecondFinalStatus, kSecondOrigin, "1"));
- EXPECT_TRUE(ListEntryMatches(entry_value->GetList(), 1u, kFirstUrl,
+ EXPECT_TRUE(ListEntryMatches(entry_value->GetListDeprecated(), 1u, kFirstUrl,
kFirstFinalStatus, kFirstOrigin, "0"));
// Add a third entry and make sure that the first one drops off.
@@ -109,10 +109,10 @@ TEST(PrerenderHistoryTest, GetAsValue) {
entry_value = history.CopyEntriesAsValue();
ASSERT_TRUE(entry_value.get() != nullptr);
ASSERT_TRUE(entry_value->is_list());
- EXPECT_EQ(2u, entry_value->GetList().size());
- EXPECT_TRUE(ListEntryMatches(entry_value->GetList(), 0u, kThirdUrl,
+ EXPECT_EQ(2u, entry_value->GetListDeprecated().size());
+ EXPECT_TRUE(ListEntryMatches(entry_value->GetListDeprecated(), 0u, kThirdUrl,
kThirdFinalStatus, kThirdOrigin, "2"));
- EXPECT_TRUE(ListEntryMatches(entry_value->GetList(), 1u, kSecondUrl,
+ EXPECT_TRUE(ListEntryMatches(entry_value->GetListDeprecated(), 1u, kSecondUrl,
kSecondFinalStatus, kSecondOrigin, "1"));
// Make sure clearing history acts as expected.
@@ -120,7 +120,7 @@ TEST(PrerenderHistoryTest, GetAsValue) {
entry_value = history.CopyEntriesAsValue();
ASSERT_TRUE(entry_value.get() != nullptr);
ASSERT_TRUE(entry_value->is_list());
- EXPECT_TRUE(entry_value->GetList().empty());
+ EXPECT_TRUE(entry_value->GetListDeprecated().empty());
}
} // namespace
diff --git a/chromium/components/no_state_prefetch/common/BUILD.gn b/chromium/components/no_state_prefetch/common/BUILD.gn
index fa2f83603dd..dc029a830a4 100644
--- a/chromium/components/no_state_prefetch/common/BUILD.gn
+++ b/chromium/components/no_state_prefetch/common/BUILD.gn
@@ -2,6 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//extensions/buildflags/buildflags.gni")
import("//mojo/public/tools/bindings/mojom.gni")
static_library("common") {
@@ -18,7 +19,7 @@ static_library("common") {
deps = [
":mojo_bindings",
"//content/public/common:common",
- "//extensions/common:common_constants",
+ "//extensions/buildflags",
"//ipc",
"//ipc:message_support",
"//ipc:param_traits",
@@ -26,6 +27,10 @@ static_library("common") {
"//ui/gfx",
"//url",
]
+
+ if (enable_extensions) {
+ deps += [ "//extensions/common:common_constants" ]
+ }
}
mojom("mojo_bindings") {
diff --git a/chromium/components/no_state_prefetch/common/DEPS b/chromium/components/no_state_prefetch/common/DEPS
index 2cfa3620fa8..88db2d0095e 100644
--- a/chromium/components/no_state_prefetch/common/DEPS
+++ b/chromium/components/no_state_prefetch/common/DEPS
@@ -1,5 +1,6 @@
include_rules = [
"+content/public/common",
+ "+extensions/buildflags/buildflags.h",
"+extensions/common",
"+ipc",
"+mojo/public/cpp/bindings",
diff --git a/chromium/components/no_state_prefetch/common/no_state_prefetch_utils.cc b/chromium/components/no_state_prefetch/common/no_state_prefetch_utils.cc
index ccf5e5bff8a..8c5f3560fb3 100644
--- a/chromium/components/no_state_prefetch/common/no_state_prefetch_utils.cc
+++ b/chromium/components/no_state_prefetch/common/no_state_prefetch_utils.cc
@@ -9,10 +9,15 @@
#include "base/metrics/histogram_macros.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
-#include "extensions/common/constants.h"
+#include "extensions/buildflags/buildflags.h"
#include "url/gurl.h"
#include "url/url_constants.h"
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+// GN doesn't understand conditional includes, so we need nogncheck here.
+#include "extensions/common/constants.h" // nogncheck
+#endif
+
namespace prerender {
namespace {
@@ -45,7 +50,9 @@ const char kFollowOnlyWhenPrerenderShown[] = "follow-only-when-prerender-shown";
bool DoesURLHaveValidScheme(const GURL& url) {
return (url.SchemeIsHTTPOrHTTPS() ||
+#if BUILDFLAG(ENABLE_EXTENSIONS)
url.SchemeIs(extensions::kExtensionScheme) ||
+#endif
url.SchemeIs(url::kDataScheme));
}
diff --git a/chromium/components/no_state_prefetch/common/prerender_url_loader_throttle.cc b/chromium/components/no_state_prefetch/common/prerender_url_loader_throttle.cc
index c38edbb5772..eaf32aa20d6 100644
--- a/chromium/components/no_state_prefetch/common/prerender_url_loader_throttle.cc
+++ b/chromium/components/no_state_prefetch/common/prerender_url_loader_throttle.cc
@@ -91,7 +91,7 @@ void PrerenderURLLoaderThrottle::WillStartRequest(
return;
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
if (request->is_favicon) {
// Delay icon fetching until the contents are getting swapped in
// to conserve network usage in mobile devices.
@@ -111,7 +111,7 @@ void PrerenderURLLoaderThrottle::WillStartRequest(
original_request_priority_ = request->priority;
request->priority = net::IDLE;
}
-#endif // OS_ANDROID
+#endif // BUILDFLAG(IS_ANDROID)
detached_timer_.Start(
FROM_HERE, base::Milliseconds(content::kDefaultDetachableCancelDelayMs),
diff --git a/chromium/components/ntp_snippets/category_rankers/click_based_category_ranker.cc b/chromium/components/ntp_snippets/category_rankers/click_based_category_ranker.cc
index 4fec4210cbd..5961545f7e2 100644
--- a/chromium/components/ntp_snippets/category_rankers/click_based_category_ranker.cc
+++ b/chromium/components/ntp_snippets/category_rankers/click_based_category_ranker.cc
@@ -347,13 +347,13 @@ base::Time ParseLastDismissedDate(const base::DictionaryValue& value) {
bool ClickBasedCategoryRanker::ReadOrderFromPrefs(
std::vector<RankedCategory>* result_categories) const {
result_categories->clear();
- const base::ListValue* list =
+ const base::Value* list =
pref_service_->GetList(prefs::kClickBasedCategoryRankerOrderWithClicks);
- if (!list || list->GetList().size() == 0) {
+ if (!list || list->GetListDeprecated().size() == 0) {
return false;
}
- for (const base::Value& value : list->GetList()) {
+ for (const base::Value& value : list->GetListDeprecated()) {
const base::DictionaryValue* dictionary;
if (!value.GetAsDictionary(&dictionary)) {
LOG(DFATAL) << "Failed to parse category data from prefs param "
@@ -384,9 +384,9 @@ void ClickBasedCategoryRanker::StoreOrderToPrefs(
base::ListValue list;
for (const RankedCategory& category : ordered_categories) {
auto dictionary = std::make_unique<base::DictionaryValue>();
- dictionary->SetInteger(kCategoryIdKey, category.category.id());
- dictionary->SetInteger(kClicksKey, category.clicks);
- dictionary->SetString(
+ dictionary->SetIntKey(kCategoryIdKey, category.category.id());
+ dictionary->SetIntKey(kClicksKey, category.clicks);
+ dictionary->SetStringKey(
kLastDismissedKey,
base::NumberToString(SerializeTime(category.last_dismissed)));
list.Append(std::move(dictionary));
diff --git a/chromium/components/ntp_snippets/content_suggestions_service.cc b/chromium/components/ntp_snippets/content_suggestions_service.cc
index dc827a1be4c..8f916538783 100644
--- a/chromium/components/ntp_snippets/content_suggestions_service.cc
+++ b/chromium/components/ntp_snippets/content_suggestions_service.cc
@@ -673,9 +673,8 @@ void ContentSuggestionsService::RestoreDismissedCategoriesFromPrefs() {
DCHECK(dismissed_providers_by_category_.empty());
DCHECK(providers_by_category_.empty());
- const base::ListValue* list =
- pref_service_->GetList(prefs::kDismissedCategories);
- for (const base::Value& entry : list->GetList()) {
+ const base::Value* list = pref_service_->GetList(prefs::kDismissedCategories);
+ for (const base::Value& entry : list->GetListDeprecated()) {
if (!entry.is_int()) {
DLOG(WARNING) << "Invalid category pref value: " << entry;
continue;
diff --git a/chromium/components/ntp_snippets/features.cc b/chromium/components/ntp_snippets/features.cc
index c5ea510f1e5..afd397161e1 100644
--- a/chromium/components/ntp_snippets/features.cc
+++ b/chromium/components/ntp_snippets/features.cc
@@ -18,11 +18,11 @@ namespace ntp_snippets {
namespace {
// All platforms proxy for whether the simplified NTP is enabled.
bool IsSimplifiedNtpEnabled() {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
return true;
#else
return false;
-#endif // OS_ANDROID
+#endif // BUILDFLAG(IS_ANDROID)
}
} // namespace
diff --git a/chromium/components/ntp_snippets/pref_util.cc b/chromium/components/ntp_snippets/pref_util.cc
index f004a7561e9..e84c1b75686 100644
--- a/chromium/components/ntp_snippets/pref_util.cc
+++ b/chromium/components/ntp_snippets/pref_util.cc
@@ -15,8 +15,8 @@ namespace prefs {
std::set<std::string> ReadDismissedIDsFromPrefs(const PrefService& pref_service,
const std::string& pref_name) {
std::set<std::string> dismissed_ids;
- const base::ListValue* list = pref_service.GetList(pref_name);
- for (const base::Value& value : list->GetList()) {
+ const base::Value* list = pref_service.GetList(pref_name);
+ for (const base::Value& value : list->GetListDeprecated()) {
DCHECK(value.is_string())
<< "Failed to parse dismissed id from prefs param " << pref_name
<< " into string.";
diff --git a/chromium/components/ntp_snippets/remote/json_request.cc b/chromium/components/ntp_snippets/remote/json_request.cc
index 49b28624fe7..ccc40b7aea3 100644
--- a/chromium/components/ntp_snippets/remote/json_request.cc
+++ b/chromium/components/ntp_snippets/remote/json_request.cc
@@ -101,8 +101,8 @@ std::string ISO639FromPosixLocale(const std::string& locale) {
void AppendLanguageInfoToList(base::ListValue* list,
const UrlLanguageHistogram::LanguageInfo& info) {
auto lang = std::make_unique<base::DictionaryValue>();
- lang->SetString("language", info.language_code);
- lang->SetDouble("frequency", info.frequency);
+ lang->SetStringKey("language", info.language_code);
+ lang->SetDoubleKey("frequency", info.frequency);
list->Append(std::move(lang));
}
@@ -309,12 +309,12 @@ std::string JsonRequest::Builder::BuildBody() const {
auto request = std::make_unique<base::DictionaryValue>();
std::string user_locale = PosixLocaleFromBCP47Language(params_.language_code);
if (!user_locale.empty()) {
- request->SetString("uiLanguage", user_locale);
+ request->SetStringKey("uiLanguage", user_locale);
}
- request->SetString("priority", params_.interactive_request
- ? "USER_ACTION"
- : "BACKGROUND_PREFETCH");
+ request->SetStringKey("priority", params_.interactive_request
+ ? "USER_ACTION"
+ : "BACKGROUND_PREFETCH");
auto excluded = std::make_unique<base::ListValue>();
for (const auto& id : params_.excluded_ids) {
@@ -323,11 +323,11 @@ std::string JsonRequest::Builder::BuildBody() const {
request->Set("excludedSuggestionIds", std::move(excluded));
if (!user_class_.empty()) {
- request->SetString("userActivenessClass", user_class_);
+ request->SetStringKey("userActivenessClass", user_class_);
}
if (!display_capability_.empty()) {
- request->SetString("displayCapability", display_capability_);
+ request->SetStringKey("displayCapability", display_capability_);
}
language::UrlLanguageHistogram::LanguageInfo ui_language;
@@ -348,10 +348,10 @@ std::string JsonRequest::Builder::BuildBody() const {
// |exclusive_category|.
if (params_.exclusive_category.has_value()) {
base::DictionaryValue exclusive_category_parameters;
- exclusive_category_parameters.SetInteger(
+ exclusive_category_parameters.SetIntKey(
"id", params_.exclusive_category->remote_id());
- exclusive_category_parameters.SetInteger("numSuggestions",
- params_.count_to_fetch);
+ exclusive_category_parameters.SetIntKey("numSuggestions",
+ params_.count_to_fetch);
base::ListValue category_parameters;
category_parameters.Append(std::move(exclusive_category_parameters));
request->SetKey("categoryParameters", std::move(category_parameters));
diff --git a/chromium/components/ntp_snippets/remote/json_to_categories.cc b/chromium/components/ntp_snippets/remote/json_to_categories.cc
index d024ecb43b3..65a57cd0ca4 100644
--- a/chromium/components/ntp_snippets/remote/json_to_categories.cc
+++ b/chromium/components/ntp_snippets/remote/json_to_categories.cc
@@ -21,7 +21,7 @@ bool AddSuggestionsFromListValue(int remote_category_id,
const base::Time& fetch_time) {
DCHECK(list.is_list());
- for (const base::Value& value : list.GetList()) {
+ for (const base::Value& value : list.GetListDeprecated()) {
const base::DictionaryValue* dict = nullptr;
if (!value.GetAsDictionary(&dict)) {
return false;
@@ -93,7 +93,7 @@ bool JsonToCategories(const base::Value& parsed,
return false;
}
- for (const base::Value& v : categories_value->GetList()) {
+ for (const base::Value& v : categories_value->GetListDeprecated()) {
if (!v.is_dict())
return false;
diff --git a/chromium/components/ntp_snippets/remote/remote_suggestion.cc b/chromium/components/ntp_snippets/remote/remote_suggestion.cc
index 3abc92bd361..8e9be081717 100644
--- a/chromium/components/ntp_snippets/remote/remote_suggestion.cc
+++ b/chromium/components/ntp_snippets/remote/remote_suggestion.cc
@@ -18,26 +18,38 @@
namespace {
// dict.Get() specialization for base::Time values
-bool GetTimeValue(const base::DictionaryValue& dict,
+bool GetTimeValue(const base::Value& dict,
const std::string& key,
base::Time* time) {
- std::string time_value;
- return dict.GetString(key, &time_value) &&
- base::Time::FromString(time_value.c_str(), time);
+ const std::string* time_value = dict.FindStringKey(key);
+ if (!time_value) {
+ return false;
+ }
+ return base::Time::FromString(time_value->c_str(), time);
}
// dict.Get() specialization for GURL values
-bool GetURLValue(const base::DictionaryValue& dict,
- const std::string& key,
- GURL* url) {
- std::string spec;
- if (!dict.GetString(key, &spec)) {
+bool GetURLValue(const base::Value& dict, const std::string& key, GURL* url) {
+ const std::string* spec = dict.FindStringKey(key);
+ if (!spec) {
return false;
}
- *url = GURL(spec);
+ *url = GURL(*spec);
return url->is_valid();
}
+// dict.Get() specialization for std::string values
+bool GetStringValue(const base::Value& dict,
+ const std::string& key,
+ std::string* str) {
+ const std::string* str_value = dict.FindStringKey(key);
+ if (!str_value) {
+ return false;
+ }
+ *str = *str_value;
+ return true;
+}
+
} // namespace
namespace ntp_snippets {
@@ -72,7 +84,7 @@ RemoteSuggestion::CreateFromContentSuggestionsDictionary(
return nullptr;
}
std::vector<std::string> parsed_ids;
- for (const base::Value& value : ids->GetList()) {
+ for (const base::Value& value : ids->GetListDeprecated()) {
if (!value.is_string()) {
return nullptr;
}
@@ -85,16 +97,16 @@ RemoteSuggestion::CreateFromContentSuggestionsDictionary(
auto snippet = MakeUnique(parsed_ids, remote_category_id);
snippet->fetch_date_ = fetch_date;
- if (!(dict.GetString("title", &snippet->title_) &&
+ if (!(GetStringValue(dict, "title", &snippet->title_) &&
GetTimeValue(dict, "creationTime", &snippet->publish_date_) &&
GetTimeValue(dict, "expirationTime", &snippet->expiry_date_) &&
- dict.GetString("attribution", &snippet->publisher_name_) &&
+ GetStringValue(dict, "attribution", &snippet->publisher_name_) &&
GetURLValue(dict, "fullPageUrl", &snippet->url_))) {
return nullptr;
}
// Optional fields.
- dict.GetString("snippet", &snippet->snippet_);
+ GetStringValue(dict, "snippet", &snippet->snippet_);
GetURLValue(dict, "imageUrl", &snippet->salient_image_url_);
GetURLValue(dict, "ampUrl", &snippet->amp_url_);
@@ -140,7 +152,7 @@ RemoteSuggestion::CreateFromContentSuggestionsDictionary(
// content_type_ of the class |RemoteSuggestion| is by default initialized to
// ContentType::UNKNOWN.
std::string content_type;
- if (dict.GetString("contentType", &content_type)) {
+ if (GetStringValue(dict, "contentType", &content_type)) {
if (content_type == "VIDEO") {
snippet->content_type_ = ContentType::VIDEO;
} else {
diff --git a/chromium/components/ntp_snippets/remote/remote_suggestion_unittest.cc b/chromium/components/ntp_snippets/remote/remote_suggestion_unittest.cc
index 5778688f788..c3bc9c773f0 100644
--- a/chromium/components/ntp_snippets/remote/remote_suggestion_unittest.cc
+++ b/chromium/components/ntp_snippets/remote/remote_suggestion_unittest.cc
@@ -180,8 +180,8 @@ TEST(RemoteSuggestionTest, CreateFromProtoIgnoreMissingSalientImageAndSnippet) {
TEST(RemoteSuggestionTest, NotifcationInfoAllSpecified) {
auto json = TestSnippetJsonValue();
- json.SetBoolean("notificationInfo.shouldNotify", true);
- json.SetString("notificationInfo.deadline", "2016-06-30T13:01:37.000Z");
+ json.SetBoolPath("notificationInfo.shouldNotify", true);
+ json.SetStringPath("notificationInfo.deadline", "2016-06-30T13:01:37.000Z");
auto snippet = RemoteSuggestion::CreateFromContentSuggestionsDictionary(
json, 0, base::Time());
EXPECT_TRUE(snippet->should_notify());
@@ -192,8 +192,8 @@ TEST(RemoteSuggestionTest, NotifcationInfoAllSpecified) {
TEST(RemoteSuggestionTest, NotificationInfoDeadlineInvalid) {
auto json = TestSnippetJsonValue();
- json.SetBoolean("notificationInfo.shouldNotify", true);
- json.SetString("notificationInfo.deadline", "abcd");
+ json.SetBoolPath("notificationInfo.shouldNotify", true);
+ json.SetStringPath("notificationInfo.deadline", "abcd");
auto snippet = RemoteSuggestion::CreateFromContentSuggestionsDictionary(
json, 0, base::Time());
EXPECT_TRUE(snippet->should_notify());
@@ -202,7 +202,7 @@ TEST(RemoteSuggestionTest, NotificationInfoDeadlineInvalid) {
TEST(RemoteSuggestionTest, NotificationInfoDeadlineAbsent) {
auto json = TestSnippetJsonValue();
- json.SetBoolean("notificationInfo.shouldNotify", true);
+ json.SetBoolPath("notificationInfo.shouldNotify", true);
json.RemovePath("notificationInfo.deadline");
auto snippet = RemoteSuggestion::CreateFromContentSuggestionsDictionary(
json, 0, base::Time());
@@ -212,7 +212,7 @@ TEST(RemoteSuggestionTest, NotificationInfoDeadlineAbsent) {
TEST(RemoteSuggestionTest, NotificationInfoShouldNotifyInvalid) {
auto json = TestSnippetJsonValue();
- json.SetString("notificationInfo.shouldNotify", "non-bool");
+ json.SetStringPath("notificationInfo.shouldNotify", "non-bool");
auto snippet = RemoteSuggestion::CreateFromContentSuggestionsDictionary(
json, 0, base::Time());
EXPECT_FALSE(snippet->should_notify());
@@ -220,7 +220,7 @@ TEST(RemoteSuggestionTest, NotificationInfoShouldNotifyInvalid) {
TEST(RemoteSuggestionTest, NotificationInfoAbsent) {
auto json = TestSnippetJsonValue();
- json.SetBoolean("notificationInfo.shouldNotify", false);
+ json.SetBoolPath("notificationInfo.shouldNotify", false);
auto snippet = RemoteSuggestion::CreateFromContentSuggestionsDictionary(
json, 0, base::Time());
EXPECT_FALSE(snippet->should_notify());
@@ -276,7 +276,7 @@ TEST(RemoteSuggestionTest, ToContentSuggestionWithNotificationInfo) {
TEST(RemoteSuggestionTest, ToContentSuggestionWithContentTypeVideo) {
auto json = TestSnippetJsonValue();
- json.SetString("contentType", "VIDEO");
+ json.SetStringKey("contentType", "VIDEO");
auto snippet = RemoteSuggestion::CreateFromContentSuggestionsDictionary(
json, 0, base::Time());
ASSERT_THAT(snippet, NotNull());
@@ -288,7 +288,7 @@ TEST(RemoteSuggestionTest, ToContentSuggestionWithContentTypeVideo) {
TEST(RemoteSuggestionTest, ToContentSuggestionWithContentTypeUnknown) {
auto json = TestSnippetJsonValue();
- json.SetString("contentType", "UNKNOWN");
+ json.SetStringKey("contentType", "UNKNOWN");
auto snippet = RemoteSuggestion::CreateFromContentSuggestionsDictionary(
json, 0, base::Time());
ASSERT_THAT(snippet, NotNull());
@@ -313,7 +313,7 @@ TEST(RemoteSuggestionTest, ToContentSuggestionWithLargeImageDominantColor) {
auto json = TestSnippetJsonValue();
// JSON does not support unsigned types. As a result the value is parsed as
// int if it fits and as double otherwise.
- json.SetDouble("imageDominantColor", 4289379276.);
+ json.SetDoubleKey("imageDominantColor", 4289379276.);
auto snippet = RemoteSuggestion::CreateFromContentSuggestionsDictionary(
json, 0, base::Time());
ASSERT_THAT(snippet, NotNull());
@@ -329,7 +329,7 @@ TEST(RemoteSuggestionTest, ToContentSuggestionWithSmallImageDominantColor) {
auto json = TestSnippetJsonValue();
// JSON does not support unsigned types. As a result the value is parsed as
// int if it fits and as double otherwise.
- json.SetInteger("imageDominantColor", 16777216 /*=0x1000000*/);
+ json.SetIntKey("imageDominantColor", 16777216 /*=0x1000000*/);
auto snippet = RemoteSuggestion::CreateFromContentSuggestionsDictionary(
json, 0, base::Time());
ASSERT_THAT(snippet, NotNull());
diff --git a/chromium/components/ntp_snippets/remote/remote_suggestions_provider_impl.cc b/chromium/components/ntp_snippets/remote/remote_suggestions_provider_impl.cc
index a57e9ed756b..76eba1ebaa0 100644
--- a/chromium/components/ntp_snippets/remote/remote_suggestions_provider_impl.cc
+++ b/chromium/components/ntp_snippets/remote/remote_suggestions_provider_impl.cc
@@ -10,6 +10,7 @@
#include "base/bind.h"
#include "base/command_line.h"
+#include "base/containers/adapters.h"
#include "base/containers/contains.h"
#include "base/containers/cxx20_erase.h"
#include "base/location.h"
@@ -93,13 +94,12 @@ void AddFetchedCategoriesToRankerBasedOnArticlesCategory(
// Insert categories which follow "Articles" in the response. Note that we
// insert them in reversed order, because they are inserted right after
// "Articles", which reverses the order.
- for (auto fetched_category_it = fetched_categories.rbegin();
- fetched_category_it != fetched_categories.rend();
- ++fetched_category_it) {
- if (fetched_category_it->category == articles_category) {
+ for (const FetchedCategory& fetched_category :
+ base::Reversed(fetched_categories)) {
+ if (fetched_category.category == articles_category) {
return;
}
- ranker->InsertCategoryAfterIfNecessary(fetched_category_it->category,
+ ranker->InsertCategoryAfterIfNecessary(fetched_category.category,
articles_category);
}
NOTREACHED() << "Articles category was not found.";
@@ -273,11 +273,12 @@ void CallWithEmptyResults(FetchDoneCallback callback, const Status& status) {
void AddDismissedIdsToRequest(const RemoteSuggestion::PtrVector& dismissed,
RequestParams* request_params) {
// The latest ids are added first, because they are more relevant.
- for (auto it = dismissed.rbegin(); it != dismissed.rend(); ++it) {
+ for (const std::unique_ptr<RemoteSuggestion>& suggestion :
+ base::Reversed(dismissed)) {
if (request_params->excluded_ids.size() == kMaxExcludedDismissedIds) {
break;
}
- request_params->excluded_ids.insert((*it)->id());
+ request_params->excluded_ids.insert(suggestion->id());
}
}
@@ -1555,9 +1556,9 @@ void RemoteSuggestionsProviderImpl::RestoreCategoriesFromPrefs() {
// This must only be called at startup, before there are any categories.
DCHECK(category_contents_.empty());
- const base::ListValue* list =
+ const base::Value* list =
pref_service_->GetList(prefs::kRemoteSuggestionCategories);
- for (const base::Value& entry : list->GetList()) {
+ for (const base::Value& entry : list->GetListDeprecated()) {
const base::DictionaryValue* dict = nullptr;
if (!entry.GetAsDictionary(&dict)) {
DLOG(WARNING) << "Invalid category pref value: " << entry;
@@ -1623,14 +1624,14 @@ void RemoteSuggestionsProviderImpl::StoreCategoriesToPrefs() {
const Category& category = entry.first;
const CategoryContent& content = *entry.second;
auto dict = std::make_unique<base::DictionaryValue>();
- dict->SetInteger(kCategoryContentId, category.id());
+ dict->SetIntKey(kCategoryContentId, category.id());
// TODO(tschumann): Persist other properties of the CategoryInfo.
- dict->SetString(kCategoryContentTitle, content.info.title());
- dict->SetBoolean(kCategoryContentProvidedByServer,
+ dict->SetStringKey(kCategoryContentTitle, content.info.title());
+ dict->SetBoolKey(kCategoryContentProvidedByServer,
content.included_in_last_server_response);
bool has_fetch_action = content.info.additional_action() ==
ContentSuggestionsAdditionalAction::FETCH;
- dict->SetBoolean(kCategoryContentAllowFetchingMore, has_fetch_action);
+ dict->SetBoolKey(kCategoryContentAllowFetchingMore, has_fetch_action);
list.Append(std::move(dict));
}
// Finally, store the result in the pref service.
diff --git a/chromium/components/ntp_tiles/BUILD.gn b/chromium/components/ntp_tiles/BUILD.gn
index ed264fa8827..0832570118e 100644
--- a/chromium/components/ntp_tiles/BUILD.gn
+++ b/chromium/components/ntp_tiles/BUILD.gn
@@ -2,6 +2,8 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//extensions/buildflags/buildflags.gni")
+
if (is_android) {
import("//build/config/android/rules.gni")
}
@@ -66,7 +68,7 @@ static_library("ntp_tiles") {
"//components/variations",
"//components/variations/service",
"//components/webapps/common:common",
- "//extensions/common:common_constants",
+ "//extensions/buildflags",
"//services/data_decoder/public/cpp",
"//services/network/public/cpp",
"//ui/base",
@@ -78,6 +80,10 @@ static_library("ntp_tiles") {
"country_code_ios.mm",
]
}
+
+ if (enable_extensions) {
+ deps += [ "//extensions/common:common_constants" ]
+ }
}
source_set("unit_tests") {
@@ -105,6 +111,7 @@ source_set("unit_tests") {
"//components/prefs:prefs",
"//components/sync_preferences:test_support",
"//components/webapps/common:common",
+ "//extensions/buildflags",
"//net:test_support",
"//services/data_decoder/public/cpp:test_support",
"//services/network:test_support",
diff --git a/chromium/components/ntp_tiles/DEPS b/chromium/components/ntp_tiles/DEPS
index 1740de3d433..bc2bbf30997 100644
--- a/chromium/components/ntp_tiles/DEPS
+++ b/chromium/components/ntp_tiles/DEPS
@@ -15,6 +15,7 @@ include_rules = [
"+components/url_formatter",
"+components/variations",
"+components/webapps",
+ "+extensions/buildflags/buildflags.h",
"+extensions/common/constants.h",
"+jni",
"+net",
diff --git a/chromium/components/ntp_tiles/custom_links_manager_impl_unittest.cc b/chromium/components/ntp_tiles/custom_links_manager_impl_unittest.cc
index 4f3bd5cdec4..51c9af938bb 100644
--- a/chromium/components/ntp_tiles/custom_links_manager_impl_unittest.cc
+++ b/chromium/components/ntp_tiles/custom_links_manager_impl_unittest.cc
@@ -15,6 +15,7 @@
#include "components/history/core/test/history_service_test_util.h"
#include "components/ntp_tiles/pref_names.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
+#include "extensions/buildflags/buildflags.h"
#include "testing/gtest/include/gtest/gtest.h"
using Link = ntp_tiles::CustomLinksManager::Link;
@@ -51,9 +52,11 @@ const char kTestTitle[] = "Test";
const char16_t kTestTitle16[] = u"Test";
const char kTestUrl[] = "http://test.com/";
+#if BUILDFLAG(ENABLE_EXTENSIONS)
const char16_t kTestGmail16[] = u"Gmail";
const char kTestGmailURL[] =
"chrome-extension://pjkljhegncpnkpknbcohdijeoejaedia/index.html";
+#endif
base::Value::ListStorage FillTestListStorage(const char* url,
const char* title,
@@ -321,6 +324,9 @@ TEST_F(CustomLinksManagerImplTest, DeleteLink) {
EXPECT_TRUE(custom_links_->GetLinks().empty());
}
+// The following tests include a default chrome app; these tests are only
+// relevant if extensions and apps are enabled.
+#if BUILDFLAG(ENABLE_EXTENSIONS)
TEST_F(CustomLinksManagerImplTest, MigratedDefaultAppDeletedSingle) {
NTPTilesVector initial_tiles;
AddTile(&initial_tiles, kTestGmailURL, kTestGmail16);
@@ -348,6 +354,7 @@ TEST_F(CustomLinksManagerImplTest, DeletedMigratedDefaultAppMultiLink) {
Link{GURL(kTestCase2[1].url), kTestCase2[1].title, true}}),
custom_links_test_->GetLinks());
}
+#endif // BUILDFLAG(ENABLE_EXTENSIONS)
TEST_F(CustomLinksManagerImplTest, DeleteLinkWhenUrlDoesNotExist) {
// Initialize.
diff --git a/chromium/components/ntp_tiles/custom_links_store.cc b/chromium/components/ntp_tiles/custom_links_store.cc
index f6cbb1dfe59..82a119b9d97 100644
--- a/chromium/components/ntp_tiles/custom_links_store.cc
+++ b/chromium/components/ntp_tiles/custom_links_store.cc
@@ -34,10 +34,9 @@ CustomLinksStore::~CustomLinksStore() = default;
std::vector<CustomLinksManager::Link> CustomLinksStore::RetrieveLinks() {
std::vector<CustomLinksManager::Link> links;
- const base::ListValue* stored_links =
- prefs_->GetList(prefs::kCustomLinksList);
+ const base::Value* stored_links = prefs_->GetList(prefs::kCustomLinksList);
- for (const base::Value& link : stored_links->GetList()) {
+ for (const base::Value& link : stored_links->GetListDeprecated()) {
const base::Value* url_value = link.FindKey(kDictionaryKeyUrl);
const base::Value* title_value = link.FindKey(kDictionaryKeyTitle);
const base::Value* mv_value = link.FindKey(kDictionaryKeyIsMostVisited);
diff --git a/chromium/components/ntp_tiles/icon_cacher_impl_unittest.cc b/chromium/components/ntp_tiles/icon_cacher_impl_unittest.cc
index 9cf8cad6f76..3f5c97a1f60 100644
--- a/chromium/components/ntp_tiles/icon_cacher_impl_unittest.cc
+++ b/chromium/components/ntp_tiles/icon_cacher_impl_unittest.cc
@@ -169,7 +169,7 @@ class IconCacherTestPopularSites : public IconCacherTestBase {
ui::ResourceBundle::CleanupSharedInstance();
}
base::FilePath pak_path;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
base::PathService::Get(ui::DIR_RESOURCE_PAKS_ANDROID, &pak_path);
#else
base::PathService::Get(base::DIR_ASSETS, &pak_path);
diff --git a/chromium/components/ntp_tiles/most_visited_sites.cc b/chromium/components/ntp_tiles/most_visited_sites.cc
index ab8d89f2538..f3b3ca884ef 100644
--- a/chromium/components/ntp_tiles/most_visited_sites.cc
+++ b/chromium/components/ntp_tiles/most_visited_sites.cc
@@ -31,7 +31,12 @@
#include "components/prefs/pref_service.h"
#include "components/search/ntp_features.h"
#include "components/webapps/common/constants.h"
-#include "extensions/common/constants.h"
+#include "extensions/buildflags/buildflags.h"
+
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+// GN doesn't understand conditional includes, so we need nogncheck here.
+#include "extensions/common/constants.h" // nogncheck
+#endif
using history::TopSites;
@@ -749,17 +754,21 @@ void MostVisitedSites::SaveTilesAndNotify(
// static
bool MostVisitedSites::IsNtpTileFromPreinstalledApp(GURL url) {
+#if BUILDFLAG(ENABLE_EXTENSIONS)
return url.is_valid() && url.SchemeIs(extensions::kExtensionScheme) &&
extension_misc::IsPreinstalledAppId(url.host());
+#else
+ return false;
+#endif
}
// static
bool MostVisitedSites::WasNtpAppMigratedToWebApp(PrefService* prefs, GURL url) {
- const base::ListValue* migrated_apps =
+ const base::Value* migrated_apps =
prefs->GetList(webapps::kWebAppsMigratedPreinstalledApps);
if (!migrated_apps)
return false;
- for (const auto& val : migrated_apps->GetList()) {
+ for (const auto& val : migrated_apps->GetListDeprecated()) {
if (val.is_string() && val.GetString() == url.host())
return true;
}
diff --git a/chromium/components/ntp_tiles/most_visited_sites_unittest.cc b/chromium/components/ntp_tiles/most_visited_sites_unittest.cc
index 5f18044c09d..918195db4b0 100644
--- a/chromium/components/ntp_tiles/most_visited_sites_unittest.cc
+++ b/chromium/components/ntp_tiles/most_visited_sites_unittest.cc
@@ -38,6 +38,7 @@
#include "components/ntp_tiles/switches.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "components/webapps/common/constants.h"
+#include "extensions/buildflags/buildflags.h"
#include "services/data_decoder/public/cpp/test_support/in_process_data_decoder.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
@@ -658,6 +659,9 @@ TEST_P(MostVisitedSitesTest, ShouldHaveHomepageFirstInListWhenFull) {
EXPECT_THAT(tiles[0], MatchesTile(u"", kHomepageUrl, TileSource::HOMEPAGE));
}
+// The following test exercises behavior with a preinstalled chrome app; this
+// is only relevant if extensions and apps are enabled.
+#if BUILDFLAG(ENABLE_EXTENSIONS)
TEST_P(MostVisitedSitesTest, ShouldNotContainDefaultPreinstalledApp) {
const char kTestUrl[] = "http://site1/";
const char16_t kTestTitle[] = u"Site 1";
@@ -684,6 +688,7 @@ TEST_P(MostVisitedSitesTest, ShouldNotContainDefaultPreinstalledApp) {
Contains(MatchesTile(kTestTitle, kTestUrl,
TileSource::TOP_SITES))));
}
+#endif // BUILDFLAG(ENABLE_EXTENSIONS)
TEST_P(MostVisitedSitesTest, ShouldHaveHomepageFirstInListWhenNotFull) {
FakeHomepageClient* homepage_client = RegisterNewHomepageClient();
@@ -1077,7 +1082,7 @@ TEST(MostVisitedSitesTest, ShouldDeduplicateDomainByReplacingMobilePrefixes) {
"www.cnn.com"));
}
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
class MostVisitedSitesWithCustomLinksTest : public MostVisitedSitesTest {
public:
MostVisitedSitesWithCustomLinksTest() {
diff --git a/chromium/components/ntp_tiles/popular_sites_impl.cc b/chromium/components/ntp_tiles/popular_sites_impl.cc
index fbdbfef0819..c166ae2efe3 100644
--- a/chromium/components/ntp_tiles/popular_sites_impl.cc
+++ b/chromium/components/ntp_tiles/popular_sites_impl.cc
@@ -39,13 +39,13 @@
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "services/network/public/cpp/simple_url_loader.h"
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
#include "base/json/json_reader.h"
#include "components/grit/components_resources.h"
#include "ui/base/resource/resource_bundle.h"
#endif
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
#include "components/ntp_tiles/country_code_ios.h"
#endif
@@ -115,21 +115,30 @@ std::string GetVariationDirectory() {
"directory");
}
-PopularSites::SitesVector ParseSiteList(const base::ListValue& list) {
+PopularSites::SitesVector ParseSiteList(
+ const base::Value::ConstListView& list) {
PopularSites::SitesVector sites;
- for (const base::Value& item_value : list.GetList()) {
+ for (const base::Value& item_value : list) {
if (!item_value.is_dict())
continue;
const base::DictionaryValue& item =
base::Value::AsDictionaryValue(item_value);
std::u16string title;
+ if (const std::string* ptr = item.FindStringKey("title"))
+ title = base::UTF8ToUTF16(*ptr);
+ else
+ continue;
std::string url;
- if (!item.GetString("title", &title) || !item.GetString("url", &url))
+ if (const std::string* ptr = item.FindStringKey("url"))
+ url = *ptr;
+ else
continue;
std::string favicon_url;
- item.GetString("favicon_url", &favicon_url);
+ if (const std::string* ptr = item.FindStringKey("favicon_url"))
+ favicon_url = *ptr;
std::string large_icon_url;
- item.GetString("large_icon_url", &large_icon_url);
+ if (const std::string* ptr = item.FindStringKey("large_icon_url"))
+ large_icon_url = *ptr;
TileTitleSource title_source = TileTitleSource::UNKNOWN;
absl::optional<int> title_source_int = item.FindIntKey("title_source");
@@ -155,17 +164,17 @@ PopularSites::SitesVector ParseSiteList(const base::ListValue& list) {
}
std::map<SectionType, PopularSites::SitesVector> ParseVersion5(
- const base::ListValue& list) {
+ const base::Value::ConstListView& list) {
return {{SectionType::PERSONALIZED, ParseSiteList(list)}};
}
std::map<SectionType, PopularSites::SitesVector> ParseVersion6OrAbove(
- const base::ListValue& list) {
+ const base::Value::ConstListView& list) {
// Valid lists would have contained at least the PERSONALIZED section.
std::map<SectionType, PopularSites::SitesVector> sections = {
std::make_pair(SectionType::PERSONALIZED, PopularSites::SitesVector{})};
- for (size_t i = 0; i < list.GetList().size(); i++) {
- const base::Value& item_value = list.GetList()[i];
+ for (size_t i = 0; i < list.size(); i++) {
+ const base::Value& item_value = list[i];
if (!item_value.is_dict()) {
LOG(WARNING) << "Parsed SitesExploration list contained an invalid "
<< "section at position " << i << ".";
@@ -182,18 +191,16 @@ std::map<SectionType, PopularSites::SitesVector> ParseVersion6OrAbove(
SectionType section_type = static_cast<SectionType>(section);
if (section_type != SectionType::PERSONALIZED)
continue;
- const base::DictionaryValue& item =
- base::Value::AsDictionaryValue(item_value);
- const base::ListValue* sites_list;
- if (!item.GetList("sites", &sites_list))
+ const base::Value* sites_list = item_value.FindListKey("sites");
+ if (!sites_list)
continue;
- sections[section_type] = ParseSiteList(*sites_list);
+ sections[section_type] = ParseSiteList(sites_list->GetListDeprecated());
}
return sections;
}
std::map<SectionType, PopularSites::SitesVector> ParseSites(
- const base::ListValue& list,
+ const base::Value::ConstListView& list,
int version) {
if (version >= kSitesExplorationStartVersion)
return ParseVersion6OrAbove(list);
@@ -201,11 +208,11 @@ std::map<SectionType, PopularSites::SitesVector> ParseSites(
}
#if BUILDFLAG(GOOGLE_CHROME_BRANDING) && \
- (defined(OS_ANDROID) || defined(OS_IOS))
+ (BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS))
void SetDefaultResourceForSite(size_t index,
int resource_id,
base::Value* sites) {
- base::Value::ListView list = sites->GetList();
+ base::Value::ListView list = sites->GetListDeprecated();
if (index >= list.size() || !list[index].is_dict())
return;
@@ -215,7 +222,7 @@ void SetDefaultResourceForSite(size_t index,
// Creates the list of popular sites based on a snapshot available for mobile.
base::Value DefaultPopularSites() {
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
return base::Value(base::Value::Type::LIST);
#else
if (!base::FeatureList::IsEnabled(kPopularSitesBakedInContentFeature))
@@ -224,7 +231,7 @@ base::Value DefaultPopularSites() {
absl::optional<base::Value> sites = base::JSONReader::Read(
ui::ResourceBundle::GetSharedInstance().LoadDataResourceString(
IDR_DEFAULT_POPULAR_SITES_JSON));
- for (base::Value& site : sites.value().GetList())
+ for (base::Value& site : sites.value().GetListDeprecated())
site.SetBoolKey("baked_in", true);
#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
@@ -238,7 +245,7 @@ base::Value DefaultPopularSites() {
}
#endif // BUILDFLAG(GOOGLE_CHROME_BRANDING)
return std::move(sites.value());
-#endif // OS_ANDROID || OS_IOS
+#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
}
} // namespace
@@ -270,9 +277,9 @@ PopularSitesImpl::PopularSitesImpl(
variations_(variations_service),
url_loader_factory_(std::move(url_loader_factory)),
is_fallback_(false),
- sections_(
- ParseSites(*prefs->GetList(prefs::kPopularSitesJsonPref),
- prefs_->GetInteger(prefs::kPopularSitesVersionPref))) {}
+ sections_(ParseSites(
+ prefs->GetList(prefs::kPopularSitesJsonPref)->GetListDeprecated(),
+ prefs_->GetInteger(prefs::kPopularSitesVersionPref))) {}
PopularSitesImpl::~PopularSitesImpl() {}
@@ -368,7 +375,7 @@ std::string PopularSitesImpl::GetCountryToFetch() {
if (country_code.empty() && variations_)
country_code = variations_->GetStoredPermanentCountry();
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
if (country_code.empty())
country_code = GetDeviceCountryCode();
#endif
@@ -396,7 +403,8 @@ std::string PopularSitesImpl::GetVersionToFetch() {
}
const base::ListValue* PopularSitesImpl::GetCachedJson() {
- return prefs_->GetList(prefs::kPopularSitesJsonPref);
+ return &base::Value::AsListValue(
+ *prefs_->GetList(prefs::kPopularSitesJsonPref));
}
// static
@@ -476,20 +484,19 @@ void PopularSitesImpl::OnJsonParsed(
return;
}
- std::unique_ptr<base::ListValue> list = base::ListValue::From(
- base::Value::ToUniquePtrValue(std::move(*result.value)));
- if (!list) {
+ base::Value list = std::move(*result.value);
+ if (!list.is_list()) {
DLOG(WARNING) << "JSON is not a list";
OnDownloadFailed();
return;
}
- prefs_->Set(prefs::kPopularSitesJsonPref, *list);
+ prefs_->Set(prefs::kPopularSitesJsonPref, list);
prefs_->SetInt64(prefs::kPopularSitesLastDownloadPref,
base::Time::Now().ToInternalValue());
prefs_->SetInteger(prefs::kPopularSitesVersionPref, version_in_pending_url_);
prefs_->SetString(prefs::kPopularSitesURLPref, pending_url_.spec());
- sections_ = ParseSites(*list, version_in_pending_url_);
+ sections_ = ParseSites(list.GetListDeprecated(), version_in_pending_url_);
std::move(callback_).Run(true);
}
diff --git a/chromium/components/ntp_tiles/popular_sites_impl_unittest.cc b/chromium/components/ntp_tiles/popular_sites_impl_unittest.cc
index 47f795228ab..158fb0ebe51 100644
--- a/chromium/components/ntp_tiles/popular_sites_impl_unittest.cc
+++ b/chromium/components/ntp_tiles/popular_sites_impl_unittest.cc
@@ -71,7 +71,7 @@ using TestPopularSectionVector = std::vector<TestPopularSection>;
}
size_t GetNumberOfDefaultPopularSitesForPlatform() {
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
return 8ul;
#else
return 0ul;
@@ -298,7 +298,7 @@ TEST_F(PopularSitesTest, PopulatesWithDefaultResoucesOnFailure) {
EXPECT_THAT(sites.size(), Eq(GetNumberOfDefaultPopularSitesForPlatform()));
}
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
TEST_F(PopularSitesTest, AddsIconResourcesToDefaultPages) {
std::unique_ptr<PopularSites> popular_sites = CreatePopularSites();
diff --git a/chromium/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.cc b/chromium/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.cc
index 33ac642754c..2d43720be8f 100644
--- a/chromium/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.cc
+++ b/chromium/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.cc
@@ -98,7 +98,7 @@ void NTPTilesInternalsMessageHandler::HandleRegisterForEvents(
SendTiles(NTPTilesVector(), FaviconResultMap());
return;
}
- DCHECK_EQ(0u, args->GetList().size());
+ DCHECK_EQ(0u, args->GetListDeprecated().size());
popular_sites_json_.clear();
most_visited_sites_ = client_->MakeMostVisitedSites();
@@ -112,8 +112,8 @@ void NTPTilesInternalsMessageHandler::HandleUpdate(
return;
}
- DCHECK_EQ(1u, args->GetList().size());
- const base::Value& dict = args->GetList()[0];
+ DCHECK_EQ(1u, args->GetListDeprecated().size());
+ const base::Value& dict = args->GetListDeprecated()[0];
DCHECK(dict.is_dict());
PrefService* prefs = client_->GetPrefs();
@@ -166,7 +166,7 @@ void NTPTilesInternalsMessageHandler::HandleUpdate(
void NTPTilesInternalsMessageHandler::HandleViewPopularSitesJson(
const base::ListValue* args) {
- DCHECK_EQ(0u, args->GetList().size());
+ DCHECK_EQ(0u, args->GetListDeprecated().size());
if (!most_visited_sites_ ||
!most_visited_sites_->DoesSourceExist(ntp_tiles::TileSource::POPULAR)) {
return;
diff --git a/chromium/components/offline_items_collection/core/BUILD.gn b/chromium/components/offline_items_collection/core/BUILD.gn
index 09cfe44e658..cded3c41230 100644
--- a/chromium/components/offline_items_collection/core/BUILD.gn
+++ b/chromium/components/offline_items_collection/core/BUILD.gn
@@ -56,7 +56,10 @@ static_library("core") {
"android/offline_item_visuals_bridge.h",
]
- deps += [ ":jni_headers" ]
+ deps += [
+ ":jni_headers",
+ "//url:gurl_android",
+ ]
}
}
@@ -112,6 +115,7 @@ if (is_android) {
deps = [
"//base:base_java",
"//third_party/androidx:androidx_annotation_annotation_java",
+ "//url:gurl_java",
]
}
diff --git a/chromium/components/offline_items_collection/core/android/offline_item_bridge.cc b/chromium/components/offline_items_collection/core/android/offline_item_bridge.cc
index f9f685fe214..0ffd468895b 100644
--- a/chromium/components/offline_items_collection/core/android/offline_item_bridge.cc
+++ b/chromium/components/offline_items_collection/core/android/offline_item_bridge.cc
@@ -6,6 +6,7 @@
#include "base/android/jni_string.h"
#include "components/offline_items_collection/core/jni_headers/OfflineItemBridge_jni.h"
+#include "url/android/gurl_android.h"
using base::android::ConvertUTF8ToJavaString;
using base::android::ScopedJavaLocalRef;
@@ -38,7 +39,7 @@ JNI_OfflineItemBridge_createOfflineItemAndMaybeAddToList(
item.completion_time.ToJavaTime(), item.last_accessed_time.ToJavaTime(),
item.is_openable, ConvertUTF8ToJavaString(env, item.file_path.value()),
ConvertUTF8ToJavaString(env, item.mime_type),
- ConvertUTF8ToJavaString(env, item.url.spec()),
+ url::GURLAndroid::FromNativeGURL(env, item.url),
ConvertUTF8ToJavaString(env, item.original_url.spec()),
item.is_off_the_record, ConvertUTF8ToJavaString(env, item.otr_profile_id),
static_cast<jint>(item.state), static_cast<jint>(item.fail_state),
diff --git a/chromium/components/offline_items_collection/core/offline_content_aggregator.cc b/chromium/components/offline_items_collection/core/offline_content_aggregator.cc
index 9246cb48253..9741f84dec4 100644
--- a/chromium/components/offline_items_collection/core/offline_content_aggregator.cc
+++ b/chromium/components/offline_items_collection/core/offline_content_aggregator.cc
@@ -250,6 +250,12 @@ void OfflineContentAggregator::OnItemsAdded(const OfflineItemList& items) {
void OfflineContentAggregator::OnItemRemoved(const ContentId& id) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ if (!pending_providers_.empty()) {
+ auto item = std::find_if(aggregated_items_.begin(), aggregated_items_.end(),
+ [id](const OfflineItem& p) { return p.id == id; });
+ aggregated_items_.erase(item);
+ }
NotifyItemRemoved(id);
}
@@ -257,6 +263,14 @@ void OfflineContentAggregator::OnItemUpdated(
const OfflineItem& item,
const absl::optional<UpdateDelta>& update_delta) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ if (!pending_providers_.empty()) {
+ for (auto& offline_item : aggregated_items_) {
+ if (offline_item.id == item.id) {
+ offline_item = item;
+ break;
+ }
+ }
+ }
NotifyItemUpdated(item, update_delta);
}
diff --git a/chromium/components/offline_items_collection/core/offline_content_aggregator_unittest.cc b/chromium/components/offline_items_collection/core/offline_content_aggregator_unittest.cc
index 3f2b104b173..e6561dc8e9d 100644
--- a/chromium/components/offline_items_collection/core/offline_content_aggregator_unittest.cc
+++ b/chromium/components/offline_items_collection/core/offline_content_aggregator_unittest.cc
@@ -75,6 +75,28 @@ class OpenItemRemovalOfflineContentProvider
}
};
+// A helper class that delays GetAllItems() callback until RunCallback()
+// is called.
+class DelayedGetAllItemOfflineContentProvider
+ : public ScopedMockOfflineContentProvider {
+ public:
+ DelayedGetAllItemOfflineContentProvider(const std::string& name_space,
+ OfflineContentAggregator* aggregator)
+ : ScopedMockOfflineContentProvider(name_space, aggregator) {}
+ ~DelayedGetAllItemOfflineContentProvider() override = default;
+
+ void GetAllItems(MultipleItemCallback callback) override {
+ callback_ = std::move(callback);
+ }
+
+ void RunCallback(const OfflineItemList& items) {
+ std::move(callback_).Run(items);
+ }
+
+ private:
+ MultipleItemCallback callback_;
+};
+
class OfflineContentAggregatorTest : public testing::Test {
public:
OfflineContentAggregatorTest()
@@ -359,5 +381,66 @@ TEST_F(OfflineContentAggregatorTest, SameProviderWithMultipleNamespaces) {
EXPECT_FALSE(provider.HasObserver(&aggregator_));
}
+// Tests that if the aggregator is in the mid of GetAllItems() call and is
+// waiting from multiple providers, it will remove deleted items from its
+// response when notified.
+TEST_F(OfflineContentAggregatorTest,
+ ItemRemovedWhileWaitingForItemsFromOtherProviders) {
+ ScopedMockOfflineContentProvider provider1("1", &aggregator_);
+ DelayedGetAllItemOfflineContentProvider provider2("2", &aggregator_);
+
+ ContentId id1 = ContentId("1", "A");
+ OfflineContentProvider::OfflineItemList items1;
+ OfflineItem item1(id1);
+ OfflineItem item2(ContentId("1", "B"));
+ items1.push_back(item1);
+ items1.push_back(item2);
+
+ OfflineContentProvider::OfflineItemList items2;
+ items2.push_back(OfflineItem(ContentId("2", "C")));
+ items2.push_back(OfflineItem(ContentId("2", "D")));
+
+ provider1.SetItems(items1);
+ provider2.SetItems(items2);
+
+ OfflineContentProvider::OfflineItemList combined_items;
+ combined_items.push_back(item2);
+ combined_items.insert(combined_items.end(), items2.begin(), items2.end());
+ GetAllItemsAndVerify(&aggregator_, combined_items);
+ provider1.NotifyOnItemRemoved(id1);
+ provider2.RunCallback(items2);
+}
+
+// Tests that if the aggregator is in the mid of GetAllItems() call and is
+// waiting from multiple providers, it will properly update items in its
+// response when notified.
+TEST_F(OfflineContentAggregatorTest,
+ ItemUpdatedWhileWaitingForItemsFromOtherProviders) {
+ ScopedMockOfflineContentProvider provider1("1", &aggregator_);
+ DelayedGetAllItemOfflineContentProvider provider2("2", &aggregator_);
+
+ OfflineContentProvider::OfflineItemList items1;
+ OfflineItem item1(ContentId("1", "A"));
+ OfflineItem item2(ContentId("1", "B"));
+ items1.push_back(item1);
+ items1.push_back(item2);
+
+ OfflineContentProvider::OfflineItemList items2;
+ items2.push_back(OfflineItem(ContentId("2", "C")));
+ items2.push_back(OfflineItem(ContentId("2", "D")));
+
+ provider1.SetItems(items1);
+ provider2.SetItems(items2);
+
+ OfflineContentProvider::OfflineItemList combined_items;
+ item1.title = "test";
+ combined_items.push_back(item1);
+ combined_items.push_back(item2);
+ combined_items.insert(combined_items.end(), items2.begin(), items2.end());
+ GetAllItemsAndVerify(&aggregator_, combined_items);
+ provider1.NotifyOnItemUpdated(item1, absl::nullopt);
+ provider2.RunCallback(items2);
+}
+
} // namespace
} // namespace offline_items_collection
diff --git a/chromium/components/offline_pages/content/background_loader/background_loader_contents.cc b/chromium/components/offline_pages/content/background_loader/background_loader_contents.cc
index 53fad64f87a..2834e3ee577 100644
--- a/chromium/components/offline_pages/content/background_loader/background_loader_contents.cc
+++ b/chromium/components/offline_pages/content/background_loader/background_loader_contents.cc
@@ -6,6 +6,7 @@
#include <utility>
+#include "build/build_config.h"
#include "content/public/browser/web_contents.h"
#include "third_party/blink/public/mojom/mediastream/media_stream.mojom-shared.h"
@@ -100,7 +101,7 @@ void BackgroundLoaderContents::AddNewContents(
*was_blocked = true;
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
bool BackgroundLoaderContents::ShouldBlockMediaRequest(const GURL& url) {
// Background pages should not have access to media.
return true;
@@ -125,13 +126,6 @@ bool BackgroundLoaderContents::CheckMediaAccessPermission(
return false; // No permissions granted.
}
-void BackgroundLoaderContents::AdjustPreviewsStateForNavigation(
- content::WebContents* web_contents,
- blink::PreviewsState* previews_state) {
- if (*previews_state == 0)
- *previews_state = blink::PreviewsTypes::PREVIEWS_OFF;
-}
-
bool BackgroundLoaderContents::ShouldAllowLazyLoad() {
return false;
}
diff --git a/chromium/components/offline_pages/content/background_loader/background_loader_contents.h b/chromium/components/offline_pages/content/background_loader/background_loader_contents.h
index c1926fc79e9..c6bd5c19f8a 100644
--- a/chromium/components/offline_pages/content/background_loader/background_loader_contents.h
+++ b/chromium/components/offline_pages/content/background_loader/background_loader_contents.h
@@ -77,7 +77,7 @@ class BackgroundLoaderContents : public content::WebContentsDelegate {
bool user_gesture,
bool* was_blocked) override;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
bool ShouldBlockMediaRequest(const GURL& url) override;
#endif
@@ -88,9 +88,6 @@ class BackgroundLoaderContents : public content::WebContentsDelegate {
bool CheckMediaAccessPermission(content::RenderFrameHost* render_frame_host,
const GURL& security_origin,
blink::mojom::MediaStreamType type) override;
- void AdjustPreviewsStateForNavigation(
- content::WebContents* web_contents,
- blink::PreviewsState* previews_state) override;
bool ShouldAllowLazyLoad() override;
private:
diff --git a/chromium/components/offline_pages/content/background_loader/background_loader_contents_unittest.cc b/chromium/components/offline_pages/content/background_loader/background_loader_contents_unittest.cc
index b916c7c868a..85de9a123a3 100644
--- a/chromium/components/offline_pages/content/background_loader/background_loader_contents_unittest.cc
+++ b/chromium/components/offline_pages/content/background_loader/background_loader_contents_unittest.cc
@@ -184,16 +184,4 @@ TEST_F(BackgroundLoaderContentsTest, CheckMediaAccessPermissionFalse) {
blink::mojom::MediaStreamType::GUM_TAB_VIDEO_CAPTURE /* type */));
}
-TEST_F(BackgroundLoaderContentsTest, AdjustPreviewsState) {
- blink::PreviewsState previews_state;
-
- // If the state starts out as off or disabled, it should stay that way.
- previews_state = blink::PreviewsTypes::PREVIEWS_OFF;
- contents()->AdjustPreviewsStateForNavigation(nullptr, &previews_state);
- EXPECT_EQ(previews_state, blink::PreviewsTypes::PREVIEWS_OFF);
- previews_state = blink::PreviewsTypes::PREVIEWS_NO_TRANSFORM;
- contents()->AdjustPreviewsStateForNavigation(nullptr, &previews_state);
- EXPECT_EQ(previews_state, blink::PreviewsTypes::PREVIEWS_NO_TRANSFORM);
-}
-
} // namespace background_loader
diff --git a/chromium/components/offline_pages/core/archive_manager.cc b/chromium/components/offline_pages/core/archive_manager.cc
index 78550fce5c8..56b1385b12e 100644
--- a/chromium/components/offline_pages/core/archive_manager.cc
+++ b/chromium/components/offline_pages/core/archive_manager.cc
@@ -72,7 +72,7 @@ void GetStorageStatsImpl(const base::FilePath& temporary_archives_dir,
base::FileEnumerator file_enumerator(public_archives_dir, false,
base::FileEnumerator::FILES);
while (!file_enumerator.Next().empty()) {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
std::string extension = base::WideToUTF8(
file_enumerator.GetInfo().GetName().FinalExtension());
#else
diff --git a/chromium/components/offline_pages/core/archive_validator.cc b/chromium/components/offline_pages/core/archive_validator.cc
index 18bc800c144..eef8f11b7d1 100644
--- a/chromium/components/offline_pages/core/archive_validator.cc
+++ b/chromium/components/offline_pages/core/archive_validator.cc
@@ -9,10 +9,11 @@
#include "base/files/file.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
+#include "build/build_config.h"
#include "crypto/secure_hash.h"
#include "crypto/sha2.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "base/android/content_uri_utils.h"
#endif
@@ -44,15 +45,15 @@ std::string ArchiveValidator::ComputeDigest(const base::FilePath& file_path) {
std::pair<int64_t, std::string> ArchiveValidator::GetSizeAndComputeDigest(
const base::FilePath& file_path) {
base::File file;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
if (file_path.IsContentUri()) {
file = base::OpenContentUriForRead(file_path);
} else {
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
file.Initialize(file_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
}
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
if (!file.IsValid())
return std::make_pair(0LL, std::string());
diff --git a/chromium/components/offline_pages/core/archive_validator_unittest.cc b/chromium/components/offline_pages/core/archive_validator_unittest.cc
index 9f57a48bdcf..ae826c2ab98 100644
--- a/chromium/components/offline_pages/core/archive_validator_unittest.cc
+++ b/chromium/components/offline_pages/core/archive_validator_unittest.cc
@@ -12,9 +12,9 @@
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "base/test/test_file_util.h"
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
namespace offline_pages {
@@ -25,9 +25,9 @@ const char kTestData2[] = "Hello World!";
const int kSmallFileSize = 2 * 1024;
const int kBigFileSize = 3 * 1024 * 1024;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
const int kSizeForTestContentUri = 173;
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
// Digest for kTestData1 + kTestData2.
const std::string kExpectedDigestForTestData(
@@ -61,7 +61,7 @@ std::string MakeContentOfSize(int size) {
return result;
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
base::FilePath GetContentUriPathForTest() {
base::FilePath test_dir;
base::PathService::Get(base::DIR_SOURCE_ROOT, &test_dir);
@@ -79,7 +79,7 @@ base::FilePath GetContentUriPathForTest() {
return path;
}
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
} // namespace
@@ -141,7 +141,7 @@ TEST_F(ArchiveValidatorTest, GetSizeAndComputeDigestOnBigFile) {
EXPECT_EQ(kExpectedDigestForBigFile, actual_size_and_digest.second);
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Flaky. https://crbug.com/1022323
TEST_F(ArchiveValidatorTest, DISABLED_GetSizeAndComputeDigestOnContentUri) {
base::FilePath content_uri_path = GetContentUriPathForTest();
@@ -150,7 +150,7 @@ TEST_F(ArchiveValidatorTest, DISABLED_GetSizeAndComputeDigestOnContentUri) {
EXPECT_EQ(kSizeForTestContentUri, actual_size_and_digest.first);
EXPECT_EQ(kExpectedDigestForContentUri, actual_size_and_digest.second);
}
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
TEST_F(ArchiveValidatorTest, ValidateSmallFile) {
std::string expected_data(MakeContentOfSize(kSmallFileSize));
@@ -166,13 +166,13 @@ TEST_F(ArchiveValidatorTest, ValidateBigFile) {
kExpectedDigestForBigFile));
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Flaky. https://crbug.com/1022322
TEST_F(ArchiveValidatorTest, DISABLED_ValidateContentUri) {
base::FilePath content_uri_path = GetContentUriPathForTest();
EXPECT_TRUE(ArchiveValidator::ValidateFile(
content_uri_path, kSizeForTestContentUri, kExpectedDigestForContentUri));
}
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/background_snapshot_controller.cc b/chromium/components/offline_pages/core/background_snapshot_controller.cc
index a99657807f9..d01fa50a3ab 100644
--- a/chromium/components/offline_pages/core/background_snapshot_controller.cc
+++ b/chromium/components/offline_pages/core/background_snapshot_controller.cc
@@ -58,14 +58,13 @@ void BackgroundSnapshotController::Stop() {
void BackgroundSnapshotController::RenovationsCompleted() {
}
-void BackgroundSnapshotController::DocumentOnLoadCompletedInMainFrame() {
- // Post a delayed task to snapshot and then stop this controller.
- task_runner_->PostDelayedTask(
- FROM_HERE,
- base::BindOnce(
- &BackgroundSnapshotController::MaybeStartSnapshotThenStop,
- weak_ptr_factory_.GetWeakPtr()),
- base::Milliseconds(delay_after_document_on_load_completed_ms_));
+void BackgroundSnapshotController::DocumentOnLoadCompletedInPrimaryMainFrame() {
+ // Post a delayed task to snapshot and then stop this controller.
+ task_runner_->PostDelayedTask(
+ FROM_HERE,
+ base::BindOnce(&BackgroundSnapshotController::MaybeStartSnapshotThenStop,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Milliseconds(delay_after_document_on_load_completed_ms_));
}
void BackgroundSnapshotController::MaybeStartSnapshot() {
diff --git a/chromium/components/offline_pages/core/background_snapshot_controller.h b/chromium/components/offline_pages/core/background_snapshot_controller.h
index ced24a4a516..0581ce26f53 100644
--- a/chromium/components/offline_pages/core/background_snapshot_controller.h
+++ b/chromium/components/offline_pages/core/background_snapshot_controller.h
@@ -75,8 +75,8 @@ class BackgroundSnapshotController {
// The Client calls this when renovations have completed.
void RenovationsCompleted();
- // Invoked from WebContentObserver::DocumentOnLoadCompletedInMainFrame
- void DocumentOnLoadCompletedInMainFrame();
+ // Invoked from WebContentObserver::DocumentOnLoadCompletedInPrimaryMainFrame
+ void DocumentOnLoadCompletedInPrimaryMainFrame();
int64_t GetDelayAfterDocumentOnLoadCompletedForTest();
int64_t GetDelayAfterRenovationsCompletedForTest();
diff --git a/chromium/components/offline_pages/core/background_snapshot_controller_unittest.cc b/chromium/components/offline_pages/core/background_snapshot_controller_unittest.cc
index e6fa55d44f8..e2d9233f65d 100644
--- a/chromium/components/offline_pages/core/background_snapshot_controller_unittest.cc
+++ b/chromium/components/offline_pages/core/background_snapshot_controller_unittest.cc
@@ -77,7 +77,7 @@ void BackgroundSnapshotControllerTest::FastForwardBy(base::TimeDelta delta) {
TEST_F(BackgroundSnapshotControllerTest, OnLoad) {
// Onload should make snapshot after its delay.
- controller()->DocumentOnLoadCompletedInMainFrame();
+ controller()->DocumentOnLoadCompletedInPrimaryMainFrame();
PumpLoop();
EXPECT_EQ(0, snapshot_count());
FastForwardBy(base::Milliseconds(
@@ -87,7 +87,7 @@ TEST_F(BackgroundSnapshotControllerTest, OnLoad) {
TEST_F(BackgroundSnapshotControllerTest, Stop) {
// OnDOM should make snapshot after a delay.
- controller()->DocumentOnLoadCompletedInMainFrame();
+ controller()->DocumentOnLoadCompletedInPrimaryMainFrame();
PumpLoop();
EXPECT_EQ(0, snapshot_count());
controller()->Stop();
@@ -96,21 +96,21 @@ TEST_F(BackgroundSnapshotControllerTest, Stop) {
// Should not start snapshots
EXPECT_EQ(0, snapshot_count());
// Also should not start snapshot.
- controller()->DocumentOnLoadCompletedInMainFrame();
+ controller()->DocumentOnLoadCompletedInPrimaryMainFrame();
EXPECT_EQ(0, snapshot_count());
}
// This simulated a Reset while there is ongoing snapshot, which is reported
// as done later. That reporting should have no effect nor crash.
TEST_F(BackgroundSnapshotControllerTest, ClientReset) {
- controller()->DocumentOnLoadCompletedInMainFrame();
+ controller()->DocumentOnLoadCompletedInPrimaryMainFrame();
FastForwardBy(base::Milliseconds(
controller()->GetDelayAfterDocumentOnLoadCompletedForTest()));
EXPECT_EQ(1, snapshot_count());
// This normally happens when navigation starts.
controller()->Reset();
// Next snapshot should be initiated when new document is loaded.
- controller()->DocumentOnLoadCompletedInMainFrame();
+ controller()->DocumentOnLoadCompletedInPrimaryMainFrame();
FastForwardBy(base::Milliseconds(
controller()->GetDelayAfterDocumentOnLoadCompletedForTest()));
// No snapshot since session was reset.
diff --git a/chromium/components/offline_pages/core/model/offline_page_model_taskified_unittest.cc b/chromium/components/offline_pages/core/model/offline_page_model_taskified_unittest.cc
index 8b06eda7243..fe1dc83c4ea 100644
--- a/chromium/components/offline_pages/core/model/offline_page_model_taskified_unittest.cc
+++ b/chromium/components/offline_pages/core/model/offline_page_model_taskified_unittest.cc
@@ -1046,7 +1046,7 @@ TEST_F(OfflinePageModelTaskifiedTest, GetOfflineIdsForClientId) {
// This test is affected by https://crbug.com/725685, which only affects windows
// platform.
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#define MAYBE_CheckTempPagesSavedInCorrectDir \
DISABLED_CheckTempPagesSavedInCorrectDir
#else
@@ -1084,7 +1084,7 @@ TEST_F(OfflinePageModelTaskifiedTest, MAYBE_CheckTempPagesSavedInCorrectDir) {
// This test is affected by https://crbug.com/725685, which only affects windows
// platform.
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#define MAYBE_CheckPersistenPagesSavedInCorrectDir \
DISABLED_CheckPersistenPagesSavedInCorrectDir
#else
@@ -1124,7 +1124,7 @@ TEST_F(OfflinePageModelTaskifiedTest,
// This test is affected by https://crbug.com/725685, which only affects windows
// platform.
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#define MAYBE_PublishPageFailure DISABLED_PublishPageFailure
#else
#define MAYBE_PublishPageFailure PublishPageFailure
@@ -1155,7 +1155,7 @@ TEST_F(OfflinePageModelTaskifiedTest, MAYBE_PublishPageFailure) {
// This test is affected by https://crbug.com/725685, which only affects windows
// platform.
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#define MAYBE_CheckPublishInternalArchive DISABLED_CheckPublishInternalArchive
#else
#define MAYBE_CheckPublishInternalArchive CheckPublishInternalArchive
@@ -1239,7 +1239,7 @@ TEST_F(OfflinePageModelTaskifiedTest, GetAllPages) {
// This test is affected by https://crbug.com/725685, which only affects windows
// platform.
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#define MAYBE_StartupMaintenanceTaskExecuted \
DISABLED_StartupMaintenanceTaskExecuted
#else
@@ -1361,7 +1361,7 @@ TEST_F(OfflinePageModelTaskifiedTest, ClearStorage) {
// This test is affected by https://crbug.com/725685, which only affects windows
// platform.
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#define MAYBE_PersistentPageConsistencyCheckExecuted \
DISABLED_PersistentPageConsistencyCheckExecuted
#else
diff --git a/chromium/components/offline_pages/core/model/offline_page_model_utils.cc b/chromium/components/offline_pages/core/model/offline_page_model_utils.cc
index 4ec5da555be..056abc93637 100644
--- a/chromium/components/offline_pages/core/model/offline_page_model_utils.cc
+++ b/chromium/components/offline_pages/core/model/offline_page_model_utils.cc
@@ -76,11 +76,11 @@ base::FilePath GenerateUniqueFilenameForOfflinePage(
int uniquifier = base::GetUniquePathNumber(suggested_path);
base::FilePath::StringType suffix;
if (uniquifier > 0)
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
suffix = base::StringPrintf(L" (%d)", uniquifier);
-#else // defined(OS_WIN)
+#else // BUILDFLAG(IS_WIN)
suffix = base::StringPrintf(" (%d)", uniquifier);
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
// Truncation.
int max_path_component_length =
diff --git a/chromium/components/offline_pages/core/model/offline_page_model_utils_unittest.cc b/chromium/components/offline_pages/core/model/offline_page_model_utils_unittest.cc
index 39732cf2624..96bf3763a8b 100644
--- a/chromium/components/offline_pages/core/model/offline_page_model_utils_unittest.cc
+++ b/chromium/components/offline_pages/core/model/offline_page_model_utils_unittest.cc
@@ -74,7 +74,7 @@ const std::vector<GenerateUniqueFilenameTestCase>& UniqueFilenameCases() {
}
// Crashing on Windows, see http://crbug.com/79365
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#define MAYBE_TestGenerateUniqueFilename DISABLED_TestGenerateUniqueFilename
#else
#define MAYBE_TestGenerateUniqueFilename TestGenerateUniqueFilename
diff --git a/chromium/components/offline_pages/core/model/persistent_page_consistency_check_task_unittest.cc b/chromium/components/offline_pages/core/model/persistent_page_consistency_check_task_unittest.cc
index 6a48600bfe8..99f53ee3af6 100644
--- a/chromium/components/offline_pages/core/model/persistent_page_consistency_check_task_unittest.cc
+++ b/chromium/components/offline_pages/core/model/persistent_page_consistency_check_task_unittest.cc
@@ -50,7 +50,7 @@ class PersistentPageConsistencyCheckTaskTest : public ModelTaskTestBase {
// This test is affected by https://crbug.com/725685, which only affects windows
// platform.
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#define MAYBE_ClearExpiredPersistentPages DISABLED_ClearExpiredPersistentPages
#else
#define MAYBE_ClearExpiredPersistentPages ClearExpiredPersistentPages
@@ -119,7 +119,7 @@ TEST_F(PersistentPageConsistencyCheckTaskTest,
static_cast<int>(SyncOperationResult::SUCCESS), 1);
}
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#define MAYBE_ClearExpiredPersistentPagesByFilePath \
DISABLED_ClearExpiredPersistentPagesByFilePath
#else
diff --git a/chromium/components/offline_pages/core/model/startup_maintenance_task_unittest.cc b/chromium/components/offline_pages/core/model/startup_maintenance_task_unittest.cc
index 0b5f645bbe0..ae53e37228b 100644
--- a/chromium/components/offline_pages/core/model/startup_maintenance_task_unittest.cc
+++ b/chromium/components/offline_pages/core/model/startup_maintenance_task_unittest.cc
@@ -75,7 +75,7 @@ PagePresence StartupMaintenanceTaskTest::CheckPagePresence(
// This test is affected by https://crbug.com/725685, which only affects windows
// platform.
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#define MAYBE_TestDeletePageInLegacyArchivesDir \
DISABLED_TestDeletePageInLegacyArchivesDir
#else
@@ -114,7 +114,7 @@ TEST_F(StartupMaintenanceTaskTest, MAYBE_TestDeletePageInLegacyArchivesDir) {
// This test is affected by https://crbug.com/725685, which only affects windows
// platform.
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#define MAYBE_TestDeleteFileWithoutDbEntry DISABLED_TestDeleteFileWithoutDbEntry
#else
#define MAYBE_TestDeleteFileWithoutDbEntry TestDeleteFileWithoutDbEntry
@@ -170,7 +170,7 @@ TEST_F(StartupMaintenanceTaskTest, MAYBE_TestDeleteFileWithoutDbEntry) {
// This test is affected by https://crbug.com/725685, which only affects windows
// platform.
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#define MAYBE_TestDeleteDbEntryWithoutFile DISABLED_TestDeleteDbEntryWithoutFile
#else
#define MAYBE_TestDeleteDbEntryWithoutFile TestDeleteDbEntryWithoutFile
@@ -222,7 +222,7 @@ TEST_F(StartupMaintenanceTaskTest, MAYBE_TestDeleteDbEntryWithoutFile) {
// This test is affected by https://crbug.com/725685, which only affects windows
// platform.
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#define MAYBE_CombinedTest DISABLED_CombinedTest
#else
#define MAYBE_CombinedTest CombinedTest
diff --git a/chromium/components/offline_pages/core/offline_page_client_policy.cc b/chromium/components/offline_pages/core/offline_page_client_policy.cc
index 321d247b2d2..94e363c7afb 100644
--- a/chromium/components/offline_pages/core/offline_page_client_policy.cc
+++ b/chromium/components/offline_pages/core/offline_page_client_policy.cc
@@ -64,7 +64,7 @@ PolicyData BuildPolicies() {
{
auto policy = OfflinePageClientPolicy::CreateTemporary(
kSuggestedArticlesNamespace, base::Days(30));
- policy.is_supported_by_download = 1;
+ policy.is_supported_by_download = true;
policy.is_suggested = true;
all_policies.push_back(policy);
}
diff --git a/chromium/components/offline_pages/core/offline_page_feature.cc b/chromium/components/offline_pages/core/offline_page_feature.cc
index d1a9a4fca37..21b689819c4 100644
--- a/chromium/components/offline_pages/core/offline_page_feature.cc
+++ b/chromium/components/offline_pages/core/offline_page_feature.cc
@@ -27,7 +27,7 @@ const base::Feature kOfflinePagesLivePageSharingFeature{
"OfflinePagesLivePageSharing", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kPrefetchingOfflinePagesFeature{
- "OfflinePagesPrefetching", base::FEATURE_ENABLED_BY_DEFAULT};
+ "OfflinePagesPrefetching", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kOfflinePagesCTV2Feature{"OfflinePagesCTV2",
base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/chromium/components/offline_pages/core/offline_page_metadata_store.h b/chromium/components/offline_pages/core/offline_page_metadata_store.h
index dbb3c48287b..0c6692606c6 100644
--- a/chromium/components/offline_pages/core/offline_page_metadata_store.h
+++ b/chromium/components/offline_pages/core/offline_page_metadata_store.h
@@ -9,7 +9,6 @@
#include "base/bind.h"
#include "base/files/file_path.h"
-#include "base/location.h"
#include "base/memory/weak_ptr.h"
#include "base/task/task_runner_util.h"
#include "base/threading/thread_task_runner_handle.h"
diff --git a/chromium/components/offline_pages/core/prefetch/prefetch_importer_impl_unittest.cc b/chromium/components/offline_pages/core/prefetch/prefetch_importer_impl_unittest.cc
index 8d4e6b66f1d..ca9782b99a7 100644
--- a/chromium/components/offline_pages/core/prefetch/prefetch_importer_impl_unittest.cc
+++ b/chromium/components/offline_pages/core/prefetch/prefetch_importer_impl_unittest.cc
@@ -4,9 +4,10 @@
#include "components/offline_pages/core/prefetch/prefetch_importer_impl.h"
+#include <tuple>
+
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
-#include "base/ignore_result.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/test_simple_task_runner.h"
@@ -36,7 +37,7 @@ std::string TestAttribution() {
class TestOfflinePageModel : public StubOfflinePageModel {
public:
- TestOfflinePageModel() { ignore_result(archive_dir_.CreateUniqueTempDir()); }
+ TestOfflinePageModel() { std::ignore = archive_dir_.CreateUniqueTempDir(); }
TestOfflinePageModel(const TestOfflinePageModel&) = delete;
TestOfflinePageModel& operator=(const TestOfflinePageModel&) = delete;
diff --git a/chromium/components/offline_pages/core/prefetch/store/prefetch_store.h b/chromium/components/offline_pages/core/prefetch/store/prefetch_store.h
index 587fa639bb2..3b158ef5d88 100644
--- a/chromium/components/offline_pages/core/prefetch/store/prefetch_store.h
+++ b/chromium/components/offline_pages/core/prefetch/store/prefetch_store.h
@@ -8,7 +8,6 @@
#include "base/bind.h"
#include "base/callback.h"
#include "base/files/file_path.h"
-#include "base/location.h"
#include "base/memory/weak_ptr.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/task_runner_util.h"
diff --git a/chromium/components/offline_pages/core/prefetch/tasks/add_unique_urls_task.cc b/chromium/components/offline_pages/core/prefetch/tasks/add_unique_urls_task.cc
index 748dda1f7ce..ce5646b7edc 100644
--- a/chromium/components/offline_pages/core/prefetch/tasks/add_unique_urls_task.cc
+++ b/chromium/components/offline_pages/core/prefetch/tasks/add_unique_urls_task.cc
@@ -11,6 +11,7 @@
#include "base/bind.h"
#include "base/callback.h"
#include "base/check.h"
+#include "base/containers/adapters.h"
#include "base/metrics/histogram_macros.h"
#include "base/time/time.h"
#include "components/offline_pages/core/offline_clock.h"
@@ -109,10 +110,8 @@ Result AddUniqueUrlsSync(
base::Time now = OfflineTimeNow();
// Insert rows in reverse order to ensure that the beginning of the list has
// the most recent timestamps so that it is prefetched first.
- for (auto candidate_iter = candidate_prefetch_urls.rbegin();
- candidate_iter != candidate_prefetch_urls.rend(); ++candidate_iter) {
- const PrefetchURL& prefetch_url = *candidate_iter;
-
+ for (const PrefetchURL& prefetch_url :
+ base::Reversed(candidate_prefetch_urls)) {
if (!prefetch_url.url.is_valid() || !prefetch_url.url.SchemeIsHTTPOrHTTPS())
continue;
diff --git a/chromium/components/offline_pages/core/prefetch/test_download_service.h b/chromium/components/offline_pages/core/prefetch/test_download_service.h
index d807f16dafd..87d9940deb4 100644
--- a/chromium/components/offline_pages/core/prefetch/test_download_service.h
+++ b/chromium/components/offline_pages/core/prefetch/test_download_service.h
@@ -5,7 +5,6 @@
#ifndef COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_TEST_DOWNLOAD_SERVICE_H_
#define COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_TEST_DOWNLOAD_SERVICE_H_
-#include <list>
#include <string>
#include "base/files/scoped_temp_dir.h"
diff --git a/chromium/components/offline_pages/core/snapshot_controller.cc b/chromium/components/offline_pages/core/snapshot_controller.cc
index 2807320b749..99728e36f05 100644
--- a/chromium/components/offline_pages/core/snapshot_controller.cc
+++ b/chromium/components/offline_pages/core/snapshot_controller.cc
@@ -63,7 +63,7 @@ void SnapshotController::PendingSnapshotCompleted() {
state_ = State::READY;
}
-void SnapshotController::DocumentAvailableInMainFrame() {
+void SnapshotController::PrimaryMainDocumentElementAvailable() {
DCHECK_EQ(PageQuality::POOR, current_page_quality_);
// Post a delayed task to snapshot.
task_runner_->PostDelayedTask(
@@ -74,7 +74,7 @@ void SnapshotController::DocumentAvailableInMainFrame() {
base::Milliseconds(delay_after_document_available_ms_));
}
-void SnapshotController::DocumentOnLoadCompletedInMainFrame() {
+void SnapshotController::DocumentOnLoadCompletedInPrimaryMainFrame() {
// Post a delayed task to snapshot and then stop this controller.
task_runner_->PostDelayedTask(
FROM_HERE,
diff --git a/chromium/components/offline_pages/core/snapshot_controller.h b/chromium/components/offline_pages/core/snapshot_controller.h
index a17b9fbd4a0..817de175225 100644
--- a/chromium/components/offline_pages/core/snapshot_controller.h
+++ b/chromium/components/offline_pages/core/snapshot_controller.h
@@ -82,11 +82,11 @@ class SnapshotController {
// now completed (so the next one can be started).
void PendingSnapshotCompleted();
- // Invoked from WebContentObserver::DocumentAvailableInMainFrame
- void DocumentAvailableInMainFrame();
+ // Invoked from WebContentObserver::PrimaryMainDocumentElementAvailable
+ void PrimaryMainDocumentElementAvailable();
- // Invoked from WebContentObserver::DocumentOnLoadCompletedInMainFrame
- void DocumentOnLoadCompletedInMainFrame();
+ // Invoked from WebContentObserver::DocumentOnLoadCompletedInPrimaryMainFrame
+ void DocumentOnLoadCompletedInPrimaryMainFrame();
int64_t GetDelayAfterDocumentAvailableForTest();
int64_t GetDelayAfterDocumentOnLoadCompletedForTest();
diff --git a/chromium/components/offline_pages/core/snapshot_controller_unittest.cc b/chromium/components/offline_pages/core/snapshot_controller_unittest.cc
index 0d4bb43026f..d12eccc09b4 100644
--- a/chromium/components/offline_pages/core/snapshot_controller_unittest.cc
+++ b/chromium/components/offline_pages/core/snapshot_controller_unittest.cc
@@ -76,7 +76,7 @@ void SnapshotControllerTest::FastForwardBy(base::TimeDelta delta) {
TEST_F(SnapshotControllerTest, OnLoad) {
// Onload should make snapshot after its delay.
- controller()->DocumentOnLoadCompletedInMainFrame();
+ controller()->DocumentOnLoadCompletedInPrimaryMainFrame();
PumpLoop();
EXPECT_EQ(0, snapshot_count());
FastForwardBy(base::Milliseconds(
@@ -87,7 +87,7 @@ TEST_F(SnapshotControllerTest, OnLoad) {
TEST_F(SnapshotControllerTest, OnDocumentAvailable) {
EXPECT_GT(controller()->GetDelayAfterDocumentAvailableForTest(), 0LL);
// OnDOM should make snapshot after a delay.
- controller()->DocumentAvailableInMainFrame();
+ controller()->PrimaryMainDocumentElementAvailable();
PumpLoop();
EXPECT_EQ(0, snapshot_count());
FastForwardBy(base::Milliseconds(
@@ -100,10 +100,10 @@ TEST_F(SnapshotControllerTest, OnLoadSnapshotIsTheLastOne) {
EXPECT_GT(controller()->GetDelayAfterDocumentAvailableForTest(),
controller()->GetDelayAfterDocumentOnLoadCompletedForTest());
// OnDOM should make snapshot after a delay.
- controller()->DocumentAvailableInMainFrame();
+ controller()->PrimaryMainDocumentElementAvailable();
PumpLoop();
EXPECT_EQ(0, snapshot_count());
- controller()->DocumentOnLoadCompletedInMainFrame();
+ controller()->DocumentOnLoadCompletedInPrimaryMainFrame();
// Advance time to OnLoadCompleted delay to trigger snapshot.
FastForwardBy(base::Milliseconds(
controller()->GetDelayAfterDocumentOnLoadCompletedForTest()));
@@ -119,7 +119,7 @@ TEST_F(SnapshotControllerTest, OnLoadSnapshotIsTheLastOne) {
TEST_F(SnapshotControllerTest, OnLoadSnapshotAfterLongDelay) {
// OnDOM should make snapshot after a delay.
- controller()->DocumentAvailableInMainFrame();
+ controller()->PrimaryMainDocumentElementAvailable();
PumpLoop();
EXPECT_EQ(0, snapshot_count());
FastForwardBy(base::Milliseconds(
@@ -128,7 +128,7 @@ TEST_F(SnapshotControllerTest, OnLoadSnapshotAfterLongDelay) {
// Report that snapshot is completed.
controller()->PendingSnapshotCompleted();
// OnLoad should make 2nd snapshot after its delay.
- controller()->DocumentOnLoadCompletedInMainFrame();
+ controller()->DocumentOnLoadCompletedInPrimaryMainFrame();
FastForwardBy(base::Milliseconds(
controller()->GetDelayAfterDocumentOnLoadCompletedForTest()));
EXPECT_EQ(2, snapshot_count());
@@ -136,7 +136,7 @@ TEST_F(SnapshotControllerTest, OnLoadSnapshotAfterLongDelay) {
TEST_F(SnapshotControllerTest, Stop) {
// OnDOM should make snapshot after a delay.
- controller()->DocumentAvailableInMainFrame();
+ controller()->PrimaryMainDocumentElementAvailable();
PumpLoop();
EXPECT_EQ(0, snapshot_count());
controller()->Stop();
@@ -145,25 +145,25 @@ TEST_F(SnapshotControllerTest, Stop) {
// Should not start snapshots
EXPECT_EQ(0, snapshot_count());
// Also should not start snapshot.
- controller()->DocumentOnLoadCompletedInMainFrame();
+ controller()->DocumentOnLoadCompletedInPrimaryMainFrame();
EXPECT_EQ(0, snapshot_count());
}
TEST_F(SnapshotControllerTest, ClientReset) {
- controller()->DocumentAvailableInMainFrame();
+ controller()->PrimaryMainDocumentElementAvailable();
controller()->Reset();
FastForwardBy(base::Milliseconds(
controller()->GetDelayAfterDocumentAvailableForTest()));
// No snapshot since session was reset.
EXPECT_EQ(0, snapshot_count());
- controller()->DocumentOnLoadCompletedInMainFrame();
+ controller()->DocumentOnLoadCompletedInPrimaryMainFrame();
FastForwardBy(base::Milliseconds(
controller()->GetDelayAfterDocumentOnLoadCompletedForTest()));
EXPECT_EQ(1, snapshot_count());
controller()->Reset();
- controller()->DocumentAvailableInMainFrame();
+ controller()->PrimaryMainDocumentElementAvailable();
FastForwardBy(base::Milliseconds(
controller()->GetDelayAfterDocumentAvailableForTest()));
// No snapshot since session was reset.
@@ -173,7 +173,7 @@ TEST_F(SnapshotControllerTest, ClientReset) {
// This simulated a Reset while there is ongoing snapshot, which is reported
// as done later. That reporting should have no effect nor crash.
TEST_F(SnapshotControllerTest, ClientResetWhileSnapshotting) {
- controller()->DocumentOnLoadCompletedInMainFrame();
+ controller()->DocumentOnLoadCompletedInPrimaryMainFrame();
FastForwardBy(base::Milliseconds(
controller()->GetDelayAfterDocumentOnLoadCompletedForTest()));
EXPECT_EQ(1, snapshot_count());
@@ -181,7 +181,7 @@ TEST_F(SnapshotControllerTest, ClientResetWhileSnapshotting) {
controller()->Reset();
controller()->PendingSnapshotCompleted();
// Next snapshot should be initiated when new document is loaded.
- controller()->DocumentAvailableInMainFrame();
+ controller()->PrimaryMainDocumentElementAvailable();
FastForwardBy(base::Milliseconds(
controller()->GetDelayAfterDocumentAvailableForTest()));
// No snapshot since session was reset.
diff --git a/chromium/components/offline_pages/task/task.h b/chromium/components/offline_pages/task/task.h
index 1d168cae9e4..084604afca8 100644
--- a/chromium/components/offline_pages/task/task.h
+++ b/chromium/components/offline_pages/task/task.h
@@ -49,6 +49,7 @@ class Task {
kWaiting,
kRunning,
kSuspended,
+ kPendingResume,
kCompleted,
};
// TaskQueue outlives and owns this task. Non-null only when this task is
diff --git a/chromium/components/offline_pages/task/task_queue.cc b/chromium/components/offline_pages/task/task_queue.cc
index 952a9a7815f..4cb63f99a1d 100644
--- a/chromium/components/offline_pages/task/task_queue.cc
+++ b/chromium/components/offline_pages/task/task_queue.cc
@@ -19,11 +19,14 @@ namespace offline_pages {
struct TaskQueue::Entry {
Entry() = default;
explicit Entry(std::unique_ptr<Task> task) : task(std::move(task)) {}
+ Entry(const base::Location& location, std::unique_ptr<Task> task)
+ : task(std::move(task)), from_here(location) {}
Entry(std::unique_ptr<Task> task, base::OnceClosure resume_callback)
: task(std::move(task)), resume_callback(std::move(resume_callback)) {}
std::unique_ptr<Task> task;
base::OnceClosure resume_callback;
+ base::Location from_here;
};
TaskQueue::TaskQueue(Delegate* delegate)
@@ -40,6 +43,15 @@ void TaskQueue::AddTask(std::unique_ptr<Task> task) {
StartTaskIfAvailable();
}
+void TaskQueue::AddTask(const base::Location& from_here,
+ std::unique_ptr<Task> task) {
+ DVLOG(2) << "Adding task " << from_here.ToString();
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ task->task_queue_ = this;
+ tasks_.emplace_back(from_here, std::move(task));
+ StartTaskIfAvailable();
+}
+
bool TaskQueue::HasPendingTasks() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return !tasks_.empty() || HasRunningTask();
@@ -65,6 +77,8 @@ void TaskQueue::StartTaskIfAvailable() {
}
current_task_ = std::move(tasks_.front().task);
+ current_task_location_ = tasks_.front().from_here;
+
base::OnceClosure resume_callback = std::move(tasks_.front().resume_callback);
tasks_.pop_front();
if (resume_callback) {
@@ -80,13 +94,15 @@ void TaskQueue::StartTaskIfAvailable() {
}
void TaskQueue::RunCurrentTask() {
+ DVLOG(2) << "Running task " << current_task_location_.ToString();
current_task_->Execute(base::BindOnce(&TaskCompletedCallback, task_runner_,
weak_ptr_factory_.GetWeakPtr(),
current_task_.get()));
}
void TaskQueue::ResumeCurrentTask(base::OnceClosure on_resume) {
- DCHECK_EQ(Task::TaskState::kSuspended, current_task_->state_);
+ DVLOG(2) << "Resuming task " << current_task_location_.ToString();
+ DCHECK_EQ(Task::TaskState::kPendingResume, current_task_->state_);
current_task_->state_ = Task::TaskState::kRunning;
std::move(on_resume).Run();
}
@@ -105,6 +121,7 @@ void TaskQueue::TaskCompleted(Task* task) {
// Normally, the completed task is the current task.
if (task == current_task_.get()) {
current_task_.reset(nullptr);
+ DVLOG(2) << "Current task completed " << current_task_location_.ToString();
StartTaskIfAvailable();
return;
}
@@ -112,16 +129,9 @@ void TaskQueue::TaskCompleted(Task* task) {
// If the task is in the suspended_tasks_ list, remove it.
for (auto iter = suspended_tasks_.begin(); iter != suspended_tasks_.end();
++iter) {
- if (iter->get() == task) {
- suspended_tasks_.erase(iter);
- return;
- }
- }
-
- // Otherwise, this is an enqueued task. Find and remove it.
- for (auto iter = tasks_.begin(); iter != tasks_.end(); ++iter) {
if (iter->task.get() == task) {
- tasks_.erase(iter);
+ DVLOG(2) << "Suspended task completed " << iter->from_here.ToString();
+ suspended_tasks_.erase(iter);
return;
}
}
@@ -134,7 +144,8 @@ void TaskQueue::SuspendTask(Task* task) {
// Task::Suspend() sets state to kSuspended.
DCHECK_EQ(Task::TaskState::kSuspended, task->state_);
DCHECK_EQ(task, current_task_.get());
- suspended_tasks_.push_back(std::move(current_task_));
+ suspended_tasks_.emplace_back(current_task_location_,
+ std::move(current_task_));
StartTaskIfAvailable();
}
@@ -143,9 +154,11 @@ void TaskQueue::ResumeTask(Task* task, base::OnceClosure on_resume) {
DCHECK_EQ(Task::TaskState::kSuspended, task->state_);
for (auto iter = suspended_tasks_.begin(); iter != suspended_tasks_.end();
++iter) {
- if (iter->get() == task) {
- tasks_.emplace_back(std::move(*iter), std::move(on_resume));
+ if (iter->task.get() == task) {
+ iter->resume_callback = std::move(on_resume);
+ tasks_.push_back(std::move(*iter));
suspended_tasks_.erase(iter);
+ task->state_ = Task::TaskState::kPendingResume;
StartTaskIfAvailable();
return;
}
@@ -159,4 +172,25 @@ void TaskQueue::InformTaskQueueIsIdle() {
delegate_->OnTaskQueueIsIdle();
}
+// Returns a human-readable string describing the contents of the task queue.
+std::string TaskQueue::GetStateForTesting() const {
+ std::stringstream ss;
+ if (current_task_) {
+ ss << "Current task: " << current_task_location_.ToString() << '\n';
+ } else {
+ ss << "No current task\n";
+ }
+ int number = 1;
+ for (const auto& entry : tasks_) {
+ ss << "Pending task " << number++ << ": " << entry.from_here.ToString()
+ << '\n';
+ }
+ number = 1;
+ for (const auto& entry : suspended_tasks_) {
+ ss << "Suspended task " << number++ << ": " << entry.from_here.ToString()
+ << '\n';
+ }
+ return ss.str();
+}
+
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/task/task_queue.h b/chromium/components/offline_pages/task/task_queue.h
index eddc0c0122f..1689786e84d 100644
--- a/chromium/components/offline_pages/task/task_queue.h
+++ b/chromium/components/offline_pages/task/task_queue.h
@@ -10,6 +10,7 @@
#include "base/callback.h"
#include "base/containers/circular_deque.h"
+#include "base/location.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
@@ -53,12 +54,17 @@ class TaskQueue {
~TaskQueue();
- // Adds a task to the queue. Queue takes ownership of the task.
+ // Adds a task to the queue. Queue takes ownership of the task. Optionally,
+ // use FROM_HERE as the first parameter for debugging.
void AddTask(std::unique_ptr<Task> task);
+ void AddTask(const base::Location& from_here, std::unique_ptr<Task> task);
+
// Whether the task queue has any pending (not-running) tasks.
bool HasPendingTasks() const;
// Whether there is a task currently running.
bool HasRunningTask() const;
+ // Returns a human-readable string describing the contents of the task queue.
+ std::string GetStateForTesting() const;
private:
friend Task;
@@ -93,12 +99,13 @@ class TaskQueue {
// Currently running tasks.
std::unique_ptr<Task> current_task_;
+ base::Location current_task_location_;
// A FIFO queue of tasks that will be run using this task queue.
base::circular_deque<Entry> tasks_;
// A set of tasks which are suspended.
- std::vector<std::unique_ptr<Task>> suspended_tasks_;
+ std::vector<Entry> suspended_tasks_;
SEQUENCE_CHECKER(sequence_checker_);
diff --git a/chromium/components/omnibox/browser/BUILD.gn b/chromium/components/omnibox/browser/BUILD.gn
index 1bd804371ad..7995bce0507 100644
--- a/chromium/components/omnibox/browser/BUILD.gn
+++ b/chromium/components/omnibox/browser/BUILD.gn
@@ -6,6 +6,7 @@ import("//build/buildflag_header.gni")
import("//build/config/ui.gni")
import("//components/vector_icons/vector_icons.gni")
import("//device/vr/buildflags/buildflags.gni")
+import("//extensions/buildflags/buildflags.gni")
import("//testing/libfuzzer/fuzzer_test.gni")
import("//third_party/protobuf/proto_library.gni")
@@ -102,6 +103,7 @@ static_library("browser") {
"autocomplete_classifier.h",
"autocomplete_controller.cc",
"autocomplete_controller.h",
+ "autocomplete_i18n.h",
"autocomplete_match.cc",
"autocomplete_match.h",
"autocomplete_match_classification.cc",
@@ -114,6 +116,7 @@ static_library("browser") {
"autocomplete_provider_client.h",
"autocomplete_provider_debouncer.cc",
"autocomplete_provider_debouncer.h",
+ "autocomplete_provider_listener.h",
"autocomplete_result.cc",
"autocomplete_result.h",
"base_search_provider.cc",
@@ -130,6 +133,8 @@ static_library("browser") {
"document_suggestions_service.h",
"favicon_cache.cc",
"favicon_cache.h",
+ "history_fuzzy_provider.cc",
+ "history_fuzzy_provider.h",
"history_match.cc",
"history_match.h",
"history_provider.cc",
@@ -183,14 +188,14 @@ static_library("browser") {
"omnibox_triggered_feature_service.h",
"omnibox_view.cc",
"omnibox_view.h",
- "omnibox_watcher.cc",
- "omnibox_watcher.h",
"on_device_head_model.cc",
"on_device_head_model.h",
"on_device_head_provider.cc",
"on_device_head_provider.h",
"on_device_model_update_listener.cc",
"on_device_model_update_listener.h",
+ "open_tab_provider.cc",
+ "open_tab_provider.h",
"query_tile_provider.cc",
"query_tile_provider.h",
"remote_suggestions_service.cc",
@@ -271,7 +276,7 @@ static_library("browser") {
"//components/url_formatter",
"//components/variations",
"//components/variations/net",
- "//extensions/common:common_constants",
+ "//extensions/buildflags",
"//net",
"//services/network/public/cpp",
"//services/network/public/mojom",
@@ -291,6 +296,16 @@ static_library("browser") {
deps += [ "//components/keyed_service/content" ]
}
+ if (enable_extensions) {
+ deps += [ "//extensions/common:common_constants" ]
+ sources += [
+ "omnibox_input_watcher.cc",
+ "omnibox_input_watcher.h",
+ "omnibox_suggestions_watcher.cc",
+ "omnibox_suggestions_watcher.h",
+ ]
+ }
+
if (is_android) {
sources += [
"autocomplete_match_android.cc",
@@ -399,6 +414,7 @@ if (is_android) {
"android/java/src/org/chromium/components/omnibox/SecurityButtonAnimationDelegate.java",
"android/java/src/org/chromium/components/omnibox/SecurityStatusIcon.java",
"android/java/src/org/chromium/components/omnibox/SuggestionAnswer.java",
+ "android/java/src/org/chromium/components/omnibox/action/OmniboxPedal.java",
]
resources_package = "org.chromium.components.omnibox"
@@ -423,6 +439,7 @@ if (is_android) {
java_cpp_enum("browser_java_enums_srcjar") {
sources = [
+ "actions/omnibox_pedal_concepts.h",
"autocomplete_match.h",
"autocomplete_match_type.h",
"suggestion_answer.h",
@@ -436,6 +453,7 @@ if (is_android) {
"android/java/src/org/chromium/components/omnibox/AutocompleteSchemeClassifier.java",
"android/java/src/org/chromium/components/omnibox/OmniboxUrlEmphasizer.java",
"android/java/src/org/chromium/components/omnibox/SuggestionAnswer.java",
+ "android/java/src/org/chromium/components/omnibox/action/OmniboxPedal.java",
]
}
}
@@ -537,6 +555,7 @@ source_set("unit_tests") {
"document_provider_unittest.cc",
"document_suggestions_service_unittest.cc",
"favicon_cache_unittest.cc",
+ "history_fuzzy_provider_unittest.cc",
"history_provider_unittest.cc",
"history_quick_provider_unittest.cc",
"history_url_provider_unittest.cc",
diff --git a/chromium/components/omnibox_strings.grdp b/chromium/components/omnibox_strings.grdp
index 3eedbc66f64..517e01ac0c7 100644
--- a/chromium/components/omnibox_strings.grdp
+++ b/chromium/components/omnibox_strings.grdp
@@ -4,6 +4,38 @@
referencing .grdp file or translation console pipeline breaks. -->
<part file="omnibox_pedal_ui_strings.grdp" />
+ <!-- The IDS_ANDROID_OMNIBOX_PEDAL_* strings below are platform-specific
+ variations of the user-facing UI strings in
+ omnibox_pedal_ui_strings.grdp referenced above. The changes are made
+ here instead of in that file because these are manual overrides for
+ the main strings generated by pedal_processor, and we do not want
+ to lose the changes when regenerating omnibox_pedal_ui_strings.grdp. -->
+ <!-- Same as IDS_OMNIBOX_PEDAL_RUN_CHROME_SAFETY_CHECK_HINT but
+ with "safety check" capitalized to "Safety Check". -->
+ <message name="IDS_ANDROID_OMNIBOX_PEDAL_RUN_CHROME_SAFETY_CHECK_HINT" desc="The button text contents to suggest pedal action, RUN_CHROME_SAFETY_CHECK">
+ Run Chrome Safety Check
+ </message>
+ <!-- Same as IDS_OMNIBOX_PEDAL_LAUNCH_INCOGNITO_HINT but
+ with "window" changed to "tab". -->
+ <message name="IDS_ANDROID_OMNIBOX_PEDAL_LAUNCH_INCOGNITO_HINT" desc="The button text contents to suggest pedal action, LAUNCH_INCOGNITO">
+ Open Incognito tab
+ </message>
+ <!-- Same as IDS_OMNIBOX_PEDAL_LAUNCH_INCOGNITO_SUGGESTION_CONTENTS but
+ with "window" changed to "tab". -->
+ <message name="IDS_ANDROID_OMNIBOX_PEDAL_LAUNCH_INCOGNITO_SUGGESTION_CONTENTS" desc="The button hover tooltip text to describe pedal action, LAUNCH_INCOGNITO">
+ Open a new Incognito tab to browse privately
+ </message>
+ <!-- Same as IDS_ACC_OMNIBOX_PEDAL_LAUNCH_INCOGNITO_SUFFIX but
+ with "window" changed to "tab". -->
+ <message name="IDS_ANDROID_ACC_OMNIBOX_PEDAL_LAUNCH_INCOGNITO_SUFFIX" desc="Suffix for spoken suggestion description with pedal action button, to explain keystroke used to LAUNCH_INCOGNITO.">
+ <ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT">$1<ex>The Chromium Projects http://www.chromium.org bookmark</ex></ph>, press Tab then Enter to open a new Incognito tab to browse privately
+ </message>
+ <!-- Same as IDS_ACC_OMNIBOX_PEDAL_LAUNCH_INCOGNITO but
+ with "window" changed to "tab". -->
+ <message name="IDS_ANDROID_ACC_OMNIBOX_PEDAL_LAUNCH_INCOGNITO" desc="Announcement when pedal action button is focused, LAUNCH_INCOGNITO">
+ Open Incognito tab button, press Enter to open a new Incognito tab to browse privately
+ </message>
+
<message name="IDS_AUTOCOMPLETE_SEARCH_DESCRIPTION" desc="Description for the default search match.">
<ph name="ENGINE">$1<ex>Google</ex></ph> Search
</message>
diff --git a/chromium/components/omnibox_strings_grdp/IDS_ANDROID_ACC_OMNIBOX_PEDAL_LAUNCH_INCOGNITO.png.sha1 b/chromium/components/omnibox_strings_grdp/IDS_ANDROID_ACC_OMNIBOX_PEDAL_LAUNCH_INCOGNITO.png.sha1
new file mode 100644
index 00000000000..772bbb03a16
--- /dev/null
+++ b/chromium/components/omnibox_strings_grdp/IDS_ANDROID_ACC_OMNIBOX_PEDAL_LAUNCH_INCOGNITO.png.sha1
@@ -0,0 +1 @@
+2931c0e5ce9ed87dad962bffc0810d412704c3e8 \ No newline at end of file
diff --git a/chromium/components/omnibox_strings_grdp/IDS_ANDROID_ACC_OMNIBOX_PEDAL_LAUNCH_INCOGNITO_SUFFIX.png.sha1 b/chromium/components/omnibox_strings_grdp/IDS_ANDROID_ACC_OMNIBOX_PEDAL_LAUNCH_INCOGNITO_SUFFIX.png.sha1
new file mode 100644
index 00000000000..772bbb03a16
--- /dev/null
+++ b/chromium/components/omnibox_strings_grdp/IDS_ANDROID_ACC_OMNIBOX_PEDAL_LAUNCH_INCOGNITO_SUFFIX.png.sha1
@@ -0,0 +1 @@
+2931c0e5ce9ed87dad962bffc0810d412704c3e8 \ No newline at end of file
diff --git a/chromium/components/omnibox_strings_grdp/IDS_ANDROID_OMNIBOX_PEDAL_LAUNCH_INCOGNITO_HINT.png.sha1 b/chromium/components/omnibox_strings_grdp/IDS_ANDROID_OMNIBOX_PEDAL_LAUNCH_INCOGNITO_HINT.png.sha1
new file mode 100644
index 00000000000..772bbb03a16
--- /dev/null
+++ b/chromium/components/omnibox_strings_grdp/IDS_ANDROID_OMNIBOX_PEDAL_LAUNCH_INCOGNITO_HINT.png.sha1
@@ -0,0 +1 @@
+2931c0e5ce9ed87dad962bffc0810d412704c3e8 \ No newline at end of file
diff --git a/chromium/components/omnibox_strings_grdp/IDS_ANDROID_OMNIBOX_PEDAL_LAUNCH_INCOGNITO_SUGGESTION_CONTENTS.png.sha1 b/chromium/components/omnibox_strings_grdp/IDS_ANDROID_OMNIBOX_PEDAL_LAUNCH_INCOGNITO_SUGGESTION_CONTENTS.png.sha1
new file mode 100644
index 00000000000..772bbb03a16
--- /dev/null
+++ b/chromium/components/omnibox_strings_grdp/IDS_ANDROID_OMNIBOX_PEDAL_LAUNCH_INCOGNITO_SUGGESTION_CONTENTS.png.sha1
@@ -0,0 +1 @@
+2931c0e5ce9ed87dad962bffc0810d412704c3e8 \ No newline at end of file
diff --git a/chromium/components/omnibox_strings_grdp/IDS_ANDROID_OMNIBOX_PEDAL_RUN_CHROME_SAFETY_CHECK_HINT.png.sha1 b/chromium/components/omnibox_strings_grdp/IDS_ANDROID_OMNIBOX_PEDAL_RUN_CHROME_SAFETY_CHECK_HINT.png.sha1
new file mode 100644
index 00000000000..6ee72937f56
--- /dev/null
+++ b/chromium/components/omnibox_strings_grdp/IDS_ANDROID_OMNIBOX_PEDAL_RUN_CHROME_SAFETY_CHECK_HINT.png.sha1
@@ -0,0 +1 @@
+396ed356a2c3b857d1dfd7a3647bb11f6a510302 \ No newline at end of file
diff --git a/chromium/components/on_load_script_injector/browser/on_load_script_injector_host.cc b/chromium/components/on_load_script_injector/browser/on_load_script_injector_host.cc
index 20277371c72..8936e4ecff8 100644
--- a/chromium/components/on_load_script_injector/browser/on_load_script_injector_host.cc
+++ b/chromium/components/on_load_script_injector/browser/on_load_script_injector_host.cc
@@ -113,14 +113,12 @@ template <typename ScriptId>
bool OnLoadScriptInjectorHost<ScriptId>::IsUrlMatchedByOriginList(
const GURL& url,
const std::vector<url::Origin>& allowed_origins) {
- url::Origin url_origin = url::Origin::Create(url);
-
for (const url::Origin& allowed_origin : allowed_origins) {
if (allowed_origin == kMatchAllOrigins)
return true;
DCHECK(!allowed_origin.opaque());
- if (url_origin.IsSameOriginWith(allowed_origin))
+ if (allowed_origin.IsSameOriginWith(url))
return true;
}
diff --git a/chromium/components/onc/DIR_METADATA b/chromium/components/onc/DIR_METADATA
index 5c6791b38f3..d7ce3c3d805 100644
--- a/chromium/components/onc/DIR_METADATA
+++ b/chromium/components/onc/DIR_METADATA
@@ -1,3 +1,7 @@
+buganizer {
+ component_id: 1131775
+}
monorail {
- component: "OS>Systems>Network"
+ component: "OS>Systems>Network>General"
}
+team_email: "cros-connectivity@google.com"
diff --git a/chromium/components/onc/docs/onc_spec.md b/chromium/components/onc/docs/onc_spec.md
index 3eb379e7b6f..dc995570399 100644
--- a/chromium/components/onc/docs/onc_spec.md
+++ b/chromium/components/onc/docs/onc_spec.md
@@ -592,6 +592,7 @@ field **VPN** must be set to an object of type [VPN](#VPN-type).
* (required) - **string**
* Allowed values are:
* *ARCVPN*
+ * *IPsec*
* *L2TP-IPsec*
* *OpenVPN*
* *ThirdPartyVPN*
@@ -605,9 +606,11 @@ field **VPN** must be set to an object of type [VPN](#VPN-type).
* (required) - **string**
* Allowed values are:
* *Cert*
+ * *EAP*
* *PSK*
* If *Cert* is used, **ClientCertType** and *ServerCARefs* (or the
deprecated *ServerCARef*) must be set.
+ * *EAP* is only valid if **IKEVersion** is 2.
* **ClientCertProvisioningProfileId**
* (required if **ClientCertType** is *ProvisioningProfileId*, otherwise
@@ -655,6 +658,10 @@ field **VPN** must be set to an object of type [VPN](#VPN-type).
* (required) - **integer**
* Version of IKE protocol to use.
+* **LocalIdentity**
+ * (optional if **IKEVersion** is 2, otherwise ignored) - **string**
+ * The local identity used in IKE authentication.
+
* **PSK**
* (optional if **AuthenticationType** is *PSK*, otherwise ignored)
- **string**
@@ -662,6 +669,10 @@ field **VPN** must be set to an object of type [VPN](#VPN-type).
If the value is saved but not known, this may be set to an empty value,
indicating that the UI does not need to provide it.
+* **RemoteIdentity**
+ * (optional if **IKEVersion** is 2, otherwise ignored) - **string**
+ * The remote identity used in IKE authentication.
+
* **SaveCredentials**
* (optional if **AuthenticationType**
is *PSK*, otherwise ignored, defaults to *false*) - **boolean**
@@ -1299,6 +1310,7 @@ type exists to configure the authentication.
* *EAP-TTLS*
* *EAP-SIM*
* *PEAP*
+ * *MSCHAPv2* (only valid for IPsec-IKEv2 VPNs)
* **Password**
* (optional) - **string**
@@ -1929,9 +1941,10 @@ expansions. These allow one ONC to have basic user-specific variations.
## String Substitutions
-The value of **WiFi.EAP.Password** is subject to string substitution. These
-differ from the **String Expansions** section above in that an exact match of
-the substitution variable is required in order to substitute the real value.
+The values of **WiFi.EAP.Password** and **VPN.L2TP.Password** are subject to
+string substitution. These differ from the **String Expansions** section above
+in that an exact match of the substitution variable is required in order to
+substitute the real value.
### Example expansions, assuming the user password was *helloworld*:
diff --git a/chromium/components/onc/onc_constants.cc b/chromium/components/onc/onc_constants.cc
index 5e6cd9ee054..04e50f035c8 100644
--- a/chromium/components/onc/onc_constants.cc
+++ b/chromium/components/onc/onc_constants.cc
@@ -366,7 +366,9 @@ const char kCert[] = "Cert";
const char kEAP[] = "EAP";
const char kGroup[] = "Group";
const char kIKEVersion[] = "IKEVersion";
+const char kLocalIdentity[] = "LocalIdentity";
const char kPSK[] = "PSK";
+const char kRemoteIdentity[] = "RemoteIdentity";
const char kServerCAPEMs[] = "ServerCAPEMs";
const char kServerCARef[] = "ServerCARef";
const char kServerCARefs[] = "ServerCARefs";
diff --git a/chromium/components/onc/onc_constants.h b/chromium/components/onc/onc_constants.h
index 6a6a22130e1..d60c9168685 100644
--- a/chromium/components/onc/onc_constants.h
+++ b/chromium/components/onc/onc_constants.h
@@ -382,7 +382,9 @@ COMPONENT_EXPORT(ONC) extern const char kCert[];
COMPONENT_EXPORT(ONC) extern const char kEAP[];
COMPONENT_EXPORT(ONC) extern const char kGroup[];
COMPONENT_EXPORT(ONC) extern const char kIKEVersion[];
+COMPONENT_EXPORT(ONC) extern const char kLocalIdentity[];
COMPONENT_EXPORT(ONC) extern const char kPSK[];
+COMPONENT_EXPORT(ONC) extern const char kRemoteIdentity[];
COMPONENT_EXPORT(ONC) extern const char kServerCAPEMs[];
COMPONENT_EXPORT(ONC) extern const char kServerCARef[];
COMPONENT_EXPORT(ONC) extern const char kServerCARefs[];
diff --git a/chromium/components/open_from_clipboard/clipboard_recent_content_generic.cc b/chromium/components/open_from_clipboard/clipboard_recent_content_generic.cc
index 8b000d5526e..42330ed4400 100644
--- a/chromium/components/open_from_clipboard/clipboard_recent_content_generic.cc
+++ b/chromium/components/open_from_clipboard/clipboard_recent_content_generic.cc
@@ -13,7 +13,7 @@
#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
#include "url/url_util.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "ui/base/clipboard/clipboard_android.h"
#endif
@@ -72,12 +72,12 @@ ClipboardRecentContentGeneric::GetRecentURLFromClipboard() {
ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
ui::DataTransferEndpoint data_dst = ui::DataTransferEndpoint(
ui::EndpointType::kDefault, /*notify_if_restricted=*/false);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
clipboard->ReadBookmark(&data_dst, nullptr, &gurl_string);
#else
clipboard->ReadAsciiText(ui::ClipboardBuffer::kCopyPaste, &data_dst,
&gurl_string);
-#endif // #if defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
base::TrimWhitespaceASCII(gurl_string, base::TrimPositions::TRIM_ALL,
&gurl_string);
diff --git a/chromium/components/open_from_clipboard/clipboard_recent_content_generic_unittest.cc b/chromium/components/open_from_clipboard/clipboard_recent_content_generic_unittest.cc
index e5794749403..ad59ef4c29d 100644
--- a/chromium/components/open_from_clipboard/clipboard_recent_content_generic_unittest.cc
+++ b/chromium/components/open_from_clipboard/clipboard_recent_content_generic_unittest.cc
@@ -240,14 +240,14 @@ TEST_F(ClipboardRecentContentGenericTest, HasRecentContentFromClipboard_URL) {
base::Time now = base::Time::Now();
std::string title = "foo";
std::string url_text = "http://example.com/";
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
// The linux and chromeos clipboard treats the presence of text on the
// clipboard as the url format being available.
test_clipboard_->WriteText(url_text.data(), url_text.length());
#else
test_clipboard_->WriteBookmark(title.data(), title.length(), url_text.data(),
url_text.length());
-#endif // defined(OS_LINUX) || defined(OS_CHROMEOS)
+#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
test_clipboard_->SetLastModifiedTime(now - base::Seconds(10));
HasDataCallbackWaiter waiter(&recent_content);
diff --git a/chromium/components/optimization_guide/DEPS b/chromium/components/optimization_guide/DEPS
index c22edf8e983..ba9c08904b4 100644
--- a/chromium/components/optimization_guide/DEPS
+++ b/chromium/components/optimization_guide/DEPS
@@ -1,6 +1,4 @@
include_rules = [
- "+components/data_reduction_proxy/core/browser",
- "+components/data_reduction_proxy/core/common",
"+components/leveldb_proto",
"+components/prefs",
"+components/sync_preferences",
diff --git a/chromium/components/optimization_guide/content/browser/BUILD.gn b/chromium/components/optimization_guide/content/browser/BUILD.gn
index 0d26cc4b455..09a22e1ea29 100644
--- a/chromium/components/optimization_guide/content/browser/BUILD.gn
+++ b/chromium/components/optimization_guide/content/browser/BUILD.gn
@@ -54,10 +54,6 @@ static_library("browser") {
"//third_party/tflite_support",
"//third_party/tflite_support:tflite_support_proto",
]
-
- if (build_with_internal_optimization_guide) {
- deps = [ "//components/optimization_guide/internal" ]
- }
}
}
@@ -83,7 +79,9 @@ source_set("unit_tests") {
"page_text_dump_result_unittest.cc",
"page_text_observer_unittest.cc",
]
- if (build_with_tflite_lib) {
+
+ # crbug.com/1279884 Flaky on CrOS
+ if (!is_chromeos && build_with_tflite_lib) {
sources += [ "page_content_annotations_model_manager_unittest.cc" ]
}
deps = [
diff --git a/chromium/components/optimization_guide/content/browser/page_content_annotations_model_manager.cc b/chromium/components/optimization_guide/content/browser/page_content_annotations_model_manager.cc
index 0deb1b9d4aa..52339bd11a7 100644
--- a/chromium/components/optimization_guide/content/browser/page_content_annotations_model_manager.cc
+++ b/chromium/components/optimization_guide/content/browser/page_content_annotations_model_manager.cc
@@ -4,6 +4,7 @@
#include "components/optimization_guide/content/browser/page_content_annotations_model_manager.h"
+#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros_local.h"
#include "base/strings/string_number_conversions.h"
#include "base/task/sequenced_task_runner.h"
@@ -17,7 +18,7 @@
#include "content/public/browser/browser_thread.h"
#if BUILDFLAG(BUILD_WITH_INTERNAL_OPTIMIZATION_GUIDE)
-#include "components/optimization_guide/internal/page_entities_model_executor_impl.h"
+#include "components/optimization_guide/core/page_entities_model_executor_impl.h"
#endif
namespace optimization_guide {
@@ -47,34 +48,23 @@ GetOrCreateCurrentContentModelAnnotations(
return std::make_unique<history::VisitContentModelAnnotations>();
}
-void PretendToExecuteJob(base::OnceClosure callback,
- std::unique_ptr<PageContentAnnotationJob> job) {
- while (absl::optional<std::string> input = job->GetNextInput()) {
- job->PostNewResult(
- BatchAnnotationResult::CreatePageTopicsResult(*input, absl::nullopt));
- }
- // Note to future self: The ordering of these callbacks being run will be
- // important once actually being run on an executor.
- job->OnComplete();
- std::move(callback).Run();
-}
-
} // namespace
PageContentAnnotationsModelManager::PageContentAnnotationsModelManager(
const std::string& application_locale,
- OptimizationGuideModelProvider* optimization_guide_model_provider) {
- for (auto opt_target :
- features::GetPageContentModelsToExecute(application_locale)) {
- if (opt_target == proto::OPTIMIZATION_TARGET_PAGE_TOPICS) {
- SetUpPageTopicsModel(optimization_guide_model_provider);
- ordered_models_to_execute_.push_back(opt_target);
- } else if (opt_target == proto::OPTIMIZATION_TARGET_PAGE_ENTITIES) {
- SetUpPageEntitiesModel(optimization_guide_model_provider);
- ordered_models_to_execute_.push_back(opt_target);
- } else {
- // TODO(crbug/1228790): Add histogram for if this happens.
- }
+ OptimizationGuideModelProvider* optimization_guide_model_provider)
+ : optimization_guide_model_provider_(optimization_guide_model_provider) {
+ if (features::ShouldExecutePageVisibilityModelOnPageContent(
+ application_locale)) {
+ SetUpPageTopicsModel(optimization_guide_model_provider);
+ ordered_models_to_execute_.push_back(
+ proto::OPTIMIZATION_TARGET_PAGE_TOPICS);
+ }
+ if (features::ShouldExecutePageEntitiesModelOnPageContent(
+ application_locale)) {
+ SetUpPageEntitiesModel(optimization_guide_model_provider);
+ ordered_models_to_execute_.push_back(
+ proto::OPTIMIZATION_TARGET_PAGE_ENTITIES);
}
}
@@ -234,6 +224,9 @@ void PageContentAnnotationsModelManager::SetUpPageTopicsV2Model(
if (!features::PageTopicsBatchAnnotationsEnabled())
return;
+ if (on_demand_page_topics_model_executor_)
+ return;
+
on_demand_page_topics_model_executor_ =
std::make_unique<PageTopicsModelExecutor>(
optimization_guide_model_provider,
@@ -247,6 +240,9 @@ void PageContentAnnotationsModelManager::SetUpPageVisibilityModel(
if (!features::PageVisibilityBatchAnnotationsEnabled())
return;
+ if (page_visibility_model_executor_)
+ return;
+
page_visibility_model_executor_ =
std::make_unique<PageVisibilityModelExecutor>(
optimization_guide_model_provider,
@@ -477,24 +473,32 @@ void PageContentAnnotationsModelManager::
out_content_annotations->categories = final_categories;
}
-void PageContentAnnotationsModelManager::NotifyWhenModelAvailable(
+void PageContentAnnotationsModelManager::RequestAndNotifyWhenModelAvailable(
AnnotationType type,
base::OnceCallback<void(bool)> callback) {
- if (type == AnnotationType::kPageTopics &&
- on_demand_page_topics_model_executor_) {
- on_demand_page_topics_model_executor_->AddOnModelUpdatedCallback(
- base::BindOnce(std::move(callback), true));
- return;
+ if (type == AnnotationType::kPageTopics) {
+ // No-op if the executor is already setup.
+ SetUpPageTopicsV2Model(optimization_guide_model_provider_);
+
+ if (on_demand_page_topics_model_executor_) {
+ on_demand_page_topics_model_executor_->AddOnModelUpdatedCallback(
+ base::BindOnce(std::move(callback), true));
+ return;
+ }
}
- if (type == AnnotationType::kContentVisibility &&
- page_visibility_model_executor_) {
- page_visibility_model_executor_->AddOnModelUpdatedCallback(
- base::BindOnce(std::move(callback), true));
- return;
+ if (type == AnnotationType::kContentVisibility) {
+ // No-op if the executor is already setup.
+ SetUpPageVisibilityModel(optimization_guide_model_provider_);
+
+ if (page_visibility_model_executor_) {
+ page_visibility_model_executor_->AddOnModelUpdatedCallback(
+ base::BindOnce(std::move(callback), true));
+ return;
+ }
}
- // TODO(crbug/1249632): Add support for page entities.
+ // TODO(crbug/1278828): Add support for page entities.
std::move(callback).Run(false);
}
@@ -506,6 +510,11 @@ PageContentAnnotationsModelManager::GetModelInfoForType(
on_demand_page_topics_model_executor_) {
return on_demand_page_topics_model_executor_->GetModelInfo();
}
+ if (type == AnnotationType::kContentVisibility &&
+ page_visibility_model_executor_) {
+ return page_visibility_model_executor_->GetModelInfo();
+ }
+ // TODO(crbug/1278828): Add support for page entities.
return absl::nullopt;
}
@@ -513,6 +522,11 @@ void PageContentAnnotationsModelManager::Annotate(
BatchAnnotationCallback callback,
const std::vector<std::string>& inputs,
AnnotationType annotation_type) {
+ base::UmaHistogramCounts100(
+ "OptimizationGuide.PageContentAnnotations.BatchRequestedSize." +
+ AnnotationTypeToString(annotation_type),
+ inputs.size());
+
std::unique_ptr<PageContentAnnotationJob> job =
std::make_unique<PageContentAnnotationJob>(std::move(callback), inputs,
annotation_type);
@@ -592,11 +606,15 @@ void PageContentAnnotationsModelManager::MaybeStartNextAnnotationJob() {
return;
}
- // TODO(crbug/1249632): Actually run the model instead.
- content::GetUIThreadTaskRunner({})->PostTask(
- FROM_HERE,
- base::BindOnce(&PretendToExecuteJob, std::move(on_job_complete_callback),
- std::move(job)));
+ // TODO(crbug/1278828): Add support for page entities.
+ if (job->type() == AnnotationType::kPageEntities) {
+ job->FillWithNullOutputs();
+ job->OnComplete();
+ job.reset();
+ std::move(on_job_complete_callback).Run();
+ return;
+ }
+ NOTREACHED();
}
} // namespace optimization_guide
diff --git a/chromium/components/optimization_guide/content/browser/page_content_annotations_model_manager.h b/chromium/components/optimization_guide/content/browser/page_content_annotations_model_manager.h
index 44ce32c15d3..dc43f852d23 100644
--- a/chromium/components/optimization_guide/content/browser/page_content_annotations_model_manager.h
+++ b/chromium/components/optimization_guide/content/browser/page_content_annotations_model_manager.h
@@ -5,6 +5,7 @@
#ifndef COMPONENTS_OPTIMIZATION_GUIDE_CONTENT_BROWSER_PAGE_CONTENT_ANNOTATIONS_MODEL_MANAGER_H_
#define COMPONENTS_OPTIMIZATION_GUIDE_CONTENT_BROWSER_PAGE_CONTENT_ANNOTATIONS_MODEL_MANAGER_H_
+#include "base/memory/raw_ptr.h"
#include "components/history/core/browser/url_row.h"
#include "components/optimization_guide/content/browser/page_content_annotator.h"
#include "components/optimization_guide/core/bert_model_handler.h"
@@ -49,6 +50,7 @@ class PageContentAnnotationsModelManager : public PageContentAnnotator {
// This will execute all supported models of the PageContentAnnotationsService
// feature and is only used by the History service code path. See the below
// |Annotate| for the publicly available Annotation code path.
+ // TODO(crbug/1278833): Remove this.
void Annotate(const std::string& text, PageContentAnnotatedCallback callback);
// PageContentAnnotator:
@@ -56,16 +58,16 @@ class PageContentAnnotationsModelManager : public PageContentAnnotator {
const std::vector<std::string>& inputs,
AnnotationType annotation_type) override;
- // Runs |callback| with true when the model that powers |BatchAnnotate| for
- // the given annotation type is ready to execute. If the model is ready now,
- // the callback is run immediately. If the model will never become ready, due
- // to feature flags for example, the callback run with false.
- void NotifyWhenModelAvailable(AnnotationType type,
- base::OnceCallback<void(bool)> callback);
+ // Requests that the given model for |type| be loaded in the background and
+ // then runs |callback| with true when the model is ready to execute. If the
+ // model is ready now, the callback is run immediately. If the model file will
+ // never be available, the callback is run with false.
+ void RequestAndNotifyWhenModelAvailable(
+ AnnotationType type,
+ base::OnceCallback<void(bool)> callback);
// Returns the model info associated with the given AnnotationType, if it is
// available and loaded.
- // TODO(crbug/1249632): Add support for more than just page topics.
absl::optional<ModelInfo> GetModelInfoForType(AnnotationType type) const;
// Returns the version of the page topics model that is currently being used
@@ -92,7 +94,7 @@ class PageContentAnnotationsModelManager : public PageContentAnnotator {
// All publicly posted jobs will have this priority level.
kNormal = 1,
- // TODO(crbug/1249632): Add a kHigh value for internal jobs.
+ // TODO(crbug/1278833): Add a kHigh value for internal jobs.
// Always keep this last and as the highest priority + 1. This value is
// passed to the priority queue ctor as "how many level of priorities are
@@ -215,7 +217,7 @@ class PageContentAnnotationsModelManager : public PageContentAnnotator {
// Runs the next job in |job_queue_| if there is any.
void MaybeStartNextAnnotationJob();
- // Called when a job finishes executing.
+ // Called when a |job| finishes executing, just before it is deleted.
void OnJobExecutionComplete();
// The model executor responsible for executing the page topics model.
@@ -254,6 +256,9 @@ class PageContentAnnotationsModelManager : public PageContentAnnotator {
// The current state of the running job, if any.
JobExecutionState job_state_ = JobExecutionState::kIdle;
+ // The model provider, not owned.
+ raw_ptr<OptimizationGuideModelProvider> optimization_guide_model_provider_;
+
base::WeakPtrFactory<PageContentAnnotationsModelManager> weak_ptr_factory_{
this};
};
diff --git a/chromium/components/optimization_guide/content/browser/page_content_annotations_model_manager_unittest.cc b/chromium/components/optimization_guide/content/browser/page_content_annotations_model_manager_unittest.cc
index caae58be379..10237a060e6 100644
--- a/chromium/components/optimization_guide/content/browser/page_content_annotations_model_manager_unittest.cc
+++ b/chromium/components/optimization_guide/content/browser/page_content_annotations_model_manager_unittest.cc
@@ -11,6 +11,7 @@
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/scoped_run_loop_timeout.h"
+#include "build/build_config.h"
#include "components/optimization_guide/core/execution_status.h"
#include "components/optimization_guide/core/optimization_guide_features.h"
#include "components/optimization_guide/core/page_entities_model_executor.h"
@@ -117,9 +118,8 @@ class FakePageEntitiesModelExecutor : public PageEntitiesModelExecutor {
class PageContentAnnotationsModelManagerTest : public testing::Test {
public:
PageContentAnnotationsModelManagerTest() {
- scoped_feature_list_.InitAndEnableFeatureWithParameters(
- features::kPageContentAnnotations,
- {{"models_to_execute_v2", "OPTIMIZATION_TARGET_PAGE_TOPICS"}});
+ scoped_feature_list_.InitAndEnableFeature(
+ features::kPageVisibilityPageContentAnnotations);
}
~PageContentAnnotationsModelManagerTest() override = default;
@@ -172,7 +172,8 @@ class PageContentAnnotationsModelManagerTest : public testing::Test {
}
void SetupPageTopicsV2ModelExecutor() {
- model_manager()->SetUpPageTopicsV2Model(model_observer_tracker());
+ model_manager()->RequestAndNotifyWhenModelAvailable(
+ AnnotationType::kPageTopics, base::DoNothing());
// If the feature flag is disabled, the executor won't have been created so
// skip everything else.
if (!model_manager()->on_demand_page_topics_model_executor_)
@@ -204,7 +205,8 @@ class PageContentAnnotationsModelManagerTest : public testing::Test {
void SendPageVisibilityModelToExecutor(
const absl::optional<proto::Any>& model_metadata) {
- model_manager()->SetUpPageVisibilityModel(model_observer_tracker());
+ model_manager()->RequestAndNotifyWhenModelAvailable(
+ AnnotationType::kContentVisibility, base::DoNothing());
// If the feature flag is disabled, the executor won't have been created so
// skip everything else.
if (!model_manager()->page_visibility_model_executor_)
@@ -562,7 +564,13 @@ TEST_F(PageContentAnnotationsModelManagerTest,
EXPECT_FALSE(GetMetadataForEntityId("someid").has_value());
}
-TEST_F(PageContentAnnotationsModelManagerTest, BatchAnnotate_PageTopics) {
+// TODO(crbug.com/1286473): Flaky on Chrome OS.
+#if BUILDFLAG(IS_CHROMEOS)
+#define MAYBE_BatchAnnotate_PageTopics DISABLED_BatchAnnotate_PageTopics
+#else
+#define MAYBE_BatchAnnotate_PageTopics BatchAnnotate_PageTopics
+#endif
+TEST_F(PageContentAnnotationsModelManagerTest, MAYBE_BatchAnnotate_PageTopics) {
SetupPageTopicsV2ModelExecutor();
// Running the actual model can take a while.
@@ -591,6 +599,18 @@ TEST_F(PageContentAnnotationsModelManagerTest, BatchAnnotate_PageTopics) {
"OptimizationGuide.ModelExecutor.ExecutionStatus.PageTopicsV2",
ExecutionStatus::kSuccess, 1);
+ histogram_tester.ExpectUniqueSample(
+ "OptimizationGuide.PageContentAnnotations.BatchRequestedSize.PageTopics",
+ 1, 1);
+ histogram_tester.ExpectUniqueSample(
+ "OptimizationGuide.PageContentAnnotations.BatchSuccess.PageTopics", true,
+ 1);
+ histogram_tester.ExpectTotalCount(
+ "OptimizationGuide.PageContentAnnotations.JobExecutionTime.PageTopics",
+ 1);
+ histogram_tester.ExpectTotalCount(
+ "OptimizationGuide.PageContentAnnotations.JobScheduleTime.PageTopics", 1);
+
EXPECT_TRUE(model_observer_tracker()->DidRegisterForTarget(
proto::OptimizationTarget::OPTIMIZATION_TARGET_PAGE_TOPICS_V2, nullptr));
@@ -628,6 +648,17 @@ TEST_F(PageContentAnnotationsModelManagerTest,
base::RunLoop().RunUntilIdle();
histogram_tester.ExpectTotalCount(
"OptimizationGuide.ModelExecutor.ExecutionStatus.PageTopicsV2", 0);
+ histogram_tester.ExpectUniqueSample(
+ "OptimizationGuide.PageContentAnnotations.BatchRequestedSize.PageTopics",
+ 1, 1);
+ histogram_tester.ExpectUniqueSample(
+ "OptimizationGuide.PageContentAnnotations.BatchSuccess.PageTopics", false,
+ 1);
+ histogram_tester.ExpectTotalCount(
+ "OptimizationGuide.PageContentAnnotations.JobExecutionTime.PageTopics",
+ 1);
+ histogram_tester.ExpectTotalCount(
+ "OptimizationGuide.PageContentAnnotations.JobScheduleTime.PageTopics", 1);
EXPECT_FALSE(model_observer_tracker()->DidRegisterForTarget(
proto::OptimizationTarget::OPTIMIZATION_TARGET_PAGE_TOPICS_V2, nullptr));
@@ -641,6 +672,7 @@ TEST_F(PageContentAnnotationsModelManagerTest,
}
TEST_F(PageContentAnnotationsModelManagerTest, BatchAnnotate_PageEntities) {
+ base::HistogramTester histogram_tester;
base::RunLoop run_loop;
std::vector<BatchAnnotationResult> result;
BatchAnnotationCallback callback = base::BindOnce(
@@ -654,10 +686,22 @@ TEST_F(PageContentAnnotationsModelManagerTest, BatchAnnotate_PageEntities) {
model_manager()->Annotate(std::move(callback), {"input"},
AnnotationType::kPageEntities);
+ histogram_tester.ExpectUniqueSample(
+ "OptimizationGuide.PageContentAnnotations.BatchRequestedSize."
+ "PageEntities",
+ 1, 1);
+ histogram_tester.ExpectUniqueSample(
+ "OptimizationGuide.PageContentAnnotations.BatchSuccess.PageEntities",
+ false, 1);
+ histogram_tester.ExpectTotalCount(
+ "OptimizationGuide.PageContentAnnotations.JobExecutionTime.PageEntities",
+ 1);
+ histogram_tester.ExpectTotalCount(
+ "OptimizationGuide.PageContentAnnotations.JobScheduleTime.PageEntities",
+ 1);
+
run_loop.Run();
- // TODO(crbug/1249632): Check the corresponding output once the model is being
- // run.
ASSERT_EQ(result.size(), 1U);
EXPECT_EQ(result[0].input(), "input");
EXPECT_EQ(result[0].topics(), absl::nullopt);
@@ -665,7 +709,15 @@ TEST_F(PageContentAnnotationsModelManagerTest, BatchAnnotate_PageEntities) {
EXPECT_EQ(result[0].visibility_score(), absl::nullopt);
}
-TEST_F(PageContentAnnotationsModelManagerTest, BatchAnnotate_PageVisibility) {
+// TODO(crbug.com/1286473): Flaky on Chrome OS.
+#if BUILDFLAG(IS_CHROMEOS)
+#define MAYBE_BatchAnnotate_PageVisibility DISABLED_BatchAnnotate_PageVisibility
+#else
+#define MAYBE_BatchAnnotate_PageVisibility BatchAnnotate_PageVisibility
+#endif
+TEST_F(PageContentAnnotationsModelManagerTest,
+ MAYBE_BatchAnnotate_PageVisibility) {
+ base::HistogramTester histogram_tester;
proto::Any any_metadata;
any_metadata.set_type_url(
"type.googleapis.com/com.foo.PageTopicsModelMetadata");
@@ -697,6 +749,21 @@ TEST_F(PageContentAnnotationsModelManagerTest, BatchAnnotate_PageVisibility) {
EXPECT_TRUE(model_observer_tracker()->DidRegisterForTarget(
proto::OptimizationTarget::OPTIMIZATION_TARGET_PAGE_VISIBILITY, nullptr));
+ histogram_tester.ExpectUniqueSample(
+ "OptimizationGuide.PageContentAnnotations.BatchRequestedSize."
+ "ContentVisibility",
+ 1, 1);
+ histogram_tester.ExpectUniqueSample(
+ "OptimizationGuide.PageContentAnnotations.BatchSuccess.ContentVisibility",
+ true, 1);
+ histogram_tester.ExpectTotalCount(
+ "OptimizationGuide.PageContentAnnotations.JobExecutionTime."
+ "ContentVisibility",
+ 1);
+ histogram_tester.ExpectTotalCount(
+ "OptimizationGuide.PageContentAnnotations.JobScheduleTime."
+ "ContentVisibility",
+ 1);
ASSERT_EQ(result.size(), 1U);
EXPECT_EQ(result[0].input(), "input");
@@ -707,6 +774,7 @@ TEST_F(PageContentAnnotationsModelManagerTest, BatchAnnotate_PageVisibility) {
TEST_F(PageContentAnnotationsModelManagerTest,
BatchAnnotate_PageVisibilityDisabled) {
+ base::HistogramTester histogram_tester;
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndDisableFeature(
features::kPageVisibilityBatchAnnotations);
@@ -739,6 +807,21 @@ TEST_F(PageContentAnnotationsModelManagerTest,
EXPECT_FALSE(model_observer_tracker()->DidRegisterForTarget(
proto::OptimizationTarget::OPTIMIZATION_TARGET_PAGE_VISIBILITY, nullptr));
+ histogram_tester.ExpectUniqueSample(
+ "OptimizationGuide.PageContentAnnotations.BatchRequestedSize."
+ "ContentVisibility",
+ 1, 1);
+ histogram_tester.ExpectUniqueSample(
+ "OptimizationGuide.PageContentAnnotations.BatchSuccess.ContentVisibility",
+ false, 1);
+ histogram_tester.ExpectTotalCount(
+ "OptimizationGuide.PageContentAnnotations.JobExecutionTime."
+ "ContentVisibility",
+ 1);
+ histogram_tester.ExpectTotalCount(
+ "OptimizationGuide.PageContentAnnotations.JobScheduleTime."
+ "ContentVisibility",
+ 1);
ASSERT_EQ(result.size(), 1U);
EXPECT_EQ(result[0].input(), "input");
@@ -747,7 +830,14 @@ TEST_F(PageContentAnnotationsModelManagerTest,
EXPECT_EQ(result[0].visibility_score(), absl::nullopt);
}
-TEST_F(PageContentAnnotationsModelManagerTest, BatchAnnotate_CalledTwice) {
+// TODO(crbug.com/1286473): Flaky on Chrome OS.
+#if BUILDFLAG(IS_CHROMEOS)
+#define MAYBE_BatchAnnotate_CalledTwice DISABLED_BatchAnnotate_CalledTwice
+#else
+#define MAYBE_BatchAnnotate_CalledTwice BatchAnnotate_CalledTwice
+#endif
+TEST_F(PageContentAnnotationsModelManagerTest,
+ MAYBE_BatchAnnotate_CalledTwice) {
SetupPageTopicsV2ModelExecutor();
base::HistogramTester histogram_tester;
@@ -790,6 +880,18 @@ TEST_F(PageContentAnnotationsModelManagerTest, BatchAnnotate_CalledTwice) {
EXPECT_TRUE(model_observer_tracker()->DidRegisterForTarget(
proto::OptimizationTarget::OPTIMIZATION_TARGET_PAGE_TOPICS_V2, nullptr));
+ histogram_tester.ExpectUniqueSample(
+ "OptimizationGuide.PageContentAnnotations.BatchRequestedSize.PageTopics",
+ 1, 2);
+ histogram_tester.ExpectUniqueSample(
+ "OptimizationGuide.PageContentAnnotations.BatchSuccess.PageTopics", true,
+ 2);
+ histogram_tester.ExpectTotalCount(
+ "OptimizationGuide.PageContentAnnotations.JobExecutionTime.PageTopics",
+ 2);
+ histogram_tester.ExpectTotalCount(
+ "OptimizationGuide.PageContentAnnotations.JobScheduleTime.PageTopics", 2);
+
// The model should have only been loaded once and then used for both jobs.
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.ModelExecutor.ModelAvailableToLoad.PageTopicsV2", true,
@@ -816,6 +918,8 @@ TEST_F(PageContentAnnotationsModelManagerTest, GetModelInfoForType) {
model_manager()->GetModelInfoForType(AnnotationType::kContentVisibility));
SetupPageTopicsV2ModelExecutor();
+ EXPECT_TRUE(
+ model_manager()->GetModelInfoForType(AnnotationType::kPageTopics));
proto::Any any_metadata;
any_metadata.set_type_url(
@@ -829,59 +933,61 @@ TEST_F(PageContentAnnotationsModelManagerTest, GetModelInfoForType) {
SendPageVisibilityModelToExecutor(any_metadata);
EXPECT_TRUE(
- model_manager()->GetModelInfoForType(AnnotationType::kPageTopics));
- EXPECT_FALSE(
model_manager()->GetModelInfoForType(AnnotationType::kContentVisibility));
}
TEST_F(PageContentAnnotationsModelManagerTest,
- NotifyWhenModelAvailable_NotAvailable) {
- absl::optional<bool> topics_callback_success;
- absl::optional<bool> visibility_callback_success;
+ NotifyWhenModelAvailable_TopicsOnly) {
+ SetupPageTopicsV2ModelExecutor();
- model_manager()->NotifyWhenModelAvailable(
+ base::RunLoop topics_run_loop;
+ bool topics_callback_success = false;
+
+ model_manager()->RequestAndNotifyWhenModelAvailable(
AnnotationType::kPageTopics,
- base::BindOnce([](absl::optional<bool>* out_success,
- bool success) { *out_success = success; },
- &topics_callback_success));
- model_manager()->NotifyWhenModelAvailable(
- AnnotationType::kContentVisibility,
- base::BindOnce([](absl::optional<bool>* out_success,
- bool success) { *out_success = success; },
- &visibility_callback_success));
-
- ASSERT_TRUE(topics_callback_success);
- ASSERT_TRUE(visibility_callback_success);
- EXPECT_FALSE(*topics_callback_success);
- EXPECT_FALSE(*visibility_callback_success);
+ base::BindOnce(
+ [](base::RunLoop* run_loop, bool* out_success, bool success) {
+ *out_success = success;
+ run_loop->Quit();
+ },
+ &topics_run_loop, &topics_callback_success));
+
+ topics_run_loop.Run();
+
+ EXPECT_TRUE(topics_callback_success);
}
TEST_F(PageContentAnnotationsModelManagerTest,
- NotifyWhenModelAvailable_TopicsOnly) {
- SetupPageTopicsV2ModelExecutor();
+ NotifyWhenModelAvailable_VisibilityOnly) {
+ proto::Any any_metadata;
+ any_metadata.set_type_url(
+ "type.googleapis.com/com.foo.PageTopicsModelMetadata");
+ proto::PageTopicsModelMetadata page_topics_model_metadata;
+ page_topics_model_metadata.set_version(123);
+ page_topics_model_metadata.mutable_output_postprocessing_params()
+ ->mutable_visibility_params()
+ ->set_category_name("DO NOT EVALUATE");
+ page_topics_model_metadata.SerializeToString(any_metadata.mutable_value());
+ SendPageVisibilityModelToExecutor(any_metadata);
- absl::optional<bool> topics_callback_success;
- absl::optional<bool> visibility_callback_success;
+ base::RunLoop visibility_run_loop;
+ bool visibility_callback_success = false;
- model_manager()->NotifyWhenModelAvailable(
- AnnotationType::kPageTopics,
- base::BindOnce([](absl::optional<bool>* out_success,
- bool success) { *out_success = success; },
- &topics_callback_success));
- model_manager()->NotifyWhenModelAvailable(
+ model_manager()->RequestAndNotifyWhenModelAvailable(
AnnotationType::kContentVisibility,
- base::BindOnce([](absl::optional<bool>* out_success,
- bool success) { *out_success = success; },
- &visibility_callback_success));
-
- ASSERT_TRUE(topics_callback_success);
- ASSERT_TRUE(visibility_callback_success);
- EXPECT_TRUE(*topics_callback_success);
- EXPECT_FALSE(*visibility_callback_success);
+ base::BindOnce(
+ [](base::RunLoop* run_loop, bool* out_success, bool success) {
+ *out_success = success;
+ run_loop->Quit();
+ },
+ &visibility_run_loop, &visibility_callback_success));
+
+ visibility_run_loop.Run();
+
+ EXPECT_TRUE(visibility_callback_success);
}
-TEST_F(PageContentAnnotationsModelManagerTest,
- NotifyWhenModelAvailable_VisibilityOnly) {
+TEST_F(PageContentAnnotationsModelManagerTest, NotifyWhenModelAvailable_Both) {
proto::Any any_metadata;
any_metadata.set_type_url(
"type.googleapis.com/com.foo.PageTopicsModelMetadata");
@@ -893,33 +999,44 @@ TEST_F(PageContentAnnotationsModelManagerTest,
page_topics_model_metadata.SerializeToString(any_metadata.mutable_value());
SendPageVisibilityModelToExecutor(any_metadata);
- absl::optional<bool> topics_callback_success;
- absl::optional<bool> visibility_callback_success;
+ SetupPageTopicsV2ModelExecutor();
+
+ base::RunLoop topics_run_loop;
+ base::RunLoop visibility_run_loop;
+ bool topics_callback_success = false;
+ bool visibility_callback_success = false;
- model_manager()->NotifyWhenModelAvailable(
+ model_manager()->RequestAndNotifyWhenModelAvailable(
AnnotationType::kPageTopics,
- base::BindOnce([](absl::optional<bool>* out_success,
- bool success) { *out_success = success; },
- &topics_callback_success));
- model_manager()->NotifyWhenModelAvailable(
+ base::BindOnce(
+ [](base::RunLoop* run_loop, bool* out_success, bool success) {
+ *out_success = success;
+ run_loop->Quit();
+ },
+ &topics_run_loop, &topics_callback_success));
+ model_manager()->RequestAndNotifyWhenModelAvailable(
AnnotationType::kContentVisibility,
- base::BindOnce([](absl::optional<bool>* out_success,
- bool success) { *out_success = success; },
- &visibility_callback_success));
-
- ASSERT_TRUE(topics_callback_success);
- ASSERT_TRUE(visibility_callback_success);
- EXPECT_FALSE(*topics_callback_success);
- EXPECT_TRUE(*visibility_callback_success);
+ base::BindOnce(
+ [](base::RunLoop* run_loop, bool* out_success, bool success) {
+ *out_success = success;
+ run_loop->Quit();
+ },
+ &visibility_run_loop, &visibility_callback_success));
+
+ topics_run_loop.Run();
+ visibility_run_loop.Run();
+
+ EXPECT_TRUE(topics_callback_success);
+ EXPECT_TRUE(visibility_callback_success);
}
class PageContentAnnotationsModelManagerEntitiesOnlyTest
: public PageContentAnnotationsModelManagerTest {
public:
PageContentAnnotationsModelManagerEntitiesOnlyTest() {
- scoped_feature_list_.InitAndEnableFeatureWithParameters(
- features::kPageContentAnnotations,
- {{"models_to_execute_v2", "OPTIMIZATION_TARGET_PAGE_ENTITIES"}});
+ scoped_feature_list_.InitWithFeatures(
+ {features::kPageEntitiesPageContentAnnotations},
+ {features::kPageVisibilityPageContentAnnotations});
}
private:
@@ -999,11 +1116,10 @@ class PageContentAnnotationsModelManagerMultipleModelsTest
: public PageContentAnnotationsModelManagerTest {
public:
PageContentAnnotationsModelManagerMultipleModelsTest() {
- scoped_feature_list_.InitAndEnableFeatureWithParameters(
- features::kPageContentAnnotations,
- {{"models_to_execute_v2",
- "OPTIMIZATION_TARGET_PAGE_ENTITIES,OPTIMIZATION_TARGET_PAGE_"
- "TOPICS"}});
+ scoped_feature_list_.InitWithFeatures(
+ {features::kPageEntitiesPageContentAnnotations,
+ features::kPageVisibilityPageContentAnnotations},
+ {});
}
private:
diff --git a/chromium/components/optimization_guide/content/browser/page_content_annotations_service.cc b/chromium/components/optimization_guide/content/browser/page_content_annotations_service.cc
index 8d1421253f2..a88b7181f85 100644
--- a/chromium/components/optimization_guide/content/browser/page_content_annotations_service.cc
+++ b/chromium/components/optimization_guide/content/browser/page_content_annotations_service.cc
@@ -4,14 +4,22 @@
#include "components/optimization_guide/content/browser/page_content_annotations_service.h"
+#include "base/callback_helpers.h"
#include "base/metrics/histogram_functions.h"
+#include "base/metrics/histogram_macros_local.h"
+#include "base/rand_util.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/time/default_tick_clock.h"
+#include "base/timer/timer.h"
#include "components/history/core/browser/history_service.h"
+#include "components/leveldb_proto/public/proto_database_provider.h"
+#include "components/optimization_guide/core/local_page_entities_metadata_provider.h"
#include "components/optimization_guide/core/noisy_metrics_recorder.h"
#include "components/optimization_guide/core/optimization_guide_enums.h"
#include "components/optimization_guide/core/optimization_guide_features.h"
#include "components/optimization_guide/core/optimization_guide_model_provider.h"
+#include "components/optimization_guide/core/optimization_guide_switches.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/web_contents.h"
#include "services/metrics/public/cpp/metrics_utils.h"
@@ -71,14 +79,27 @@ void MaybeRecordVisibilityUKM(
}
#endif /* BUILDFLAG(BUILD_WITH_TFLITE_LIB) */
+const char kDummyTextBlob[] =
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod "
+ "tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim "
+ "veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea "
+ "commodo consequat. Duis aute irure dolor in reprehenderit in voluptate "
+ "velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint "
+ "occaecat cupidatat non proident, sunt in culpa qui officia deserunt "
+ "mollit anim id est laborum";
+
} // namespace
PageContentAnnotationsService::PageContentAnnotationsService(
const std::string& application_locale,
OptimizationGuideModelProvider* optimization_guide_model_provider,
- history::HistoryService* history_service)
+ history::HistoryService* history_service,
+ leveldb_proto::ProtoDatabaseProvider* database_provider,
+ const base::FilePath& database_dir,
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner)
: last_annotated_history_visits_(
- features::MaxContentAnnotationRequestsCached()) {
+ features::MaxContentAnnotationRequestsCached()),
+ annotated_text_cache_(features::MaxVisitAnnotationCacheSize()) {
DCHECK(optimization_guide_model_provider);
DCHECK(history_service);
history_service_ = history_service;
@@ -87,12 +108,28 @@ PageContentAnnotationsService::PageContentAnnotationsService(
application_locale, optimization_guide_model_provider);
annotator_ = model_manager_.get();
#endif
+
+ if (features::UseLocalPageEntitiesMetadataProvider()) {
+ local_page_entities_metadata_provider_ =
+ std::make_unique<LocalPageEntitiesMetadataProvider>();
+ local_page_entities_metadata_provider_->Initialize(
+ database_provider, database_dir, background_task_runner);
+ }
+
+ if (features::BatchAnnotationsValidationEnabled()) {
+ validation_timer_ = std::make_unique<base::OneShotTimer>(
+ base::DefaultTickClock::GetInstance());
+ validation_timer_->Start(
+ FROM_HERE, features::BatchAnnotationValidationStartupDelay(),
+ base::BindRepeating(
+ &PageContentAnnotationsService::RunBatchAnnotationValidation,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
}
PageContentAnnotationsService::~PageContentAnnotationsService() = default;
-void PageContentAnnotationsService::Annotate(const HistoryVisit& visit,
- const std::string& text) {
+void PageContentAnnotationsService::Annotate(const HistoryVisit& visit) {
if (last_annotated_history_visits_.Peek(visit) !=
last_annotated_history_visits_.end()) {
// We have already been requested to annotate this visit, so don't submit
@@ -102,13 +139,88 @@ void PageContentAnnotationsService::Annotate(const HistoryVisit& visit,
last_annotated_history_visits_.Put(visit, true);
#if BUILDFLAG(BUILD_WITH_TFLITE_LIB)
- model_manager_->Annotate(
- text,
- base::BindOnce(&PageContentAnnotationsService::OnPageContentAnnotated,
- weak_ptr_factory_.GetWeakPtr(), visit));
+ if (!visit.text_to_annotate)
+ return;
+ // Used for testing.
+ LOCAL_HISTOGRAM_BOOLEAN(
+ "PageContentAnnotations.AnnotateVisit.AnnotationRequested", true);
+
+ auto it = annotated_text_cache_.Peek(*visit.text_to_annotate);
+ if (it != annotated_text_cache_.end()) {
+ // We have annotations the text for this visit, so return that immediately
+ // rather than re-executing the model.
+ //
+ // TODO(crbug.com/1291275): If the model was updated, the cached value could
+ // be stale so we should invalidate the cache on model updates.
+ OnPageContentAnnotated(visit, it->second);
+ base::UmaHistogramBoolean(
+ "OptimizationGuide.PageContentAnnotations.AnnotateVisitResultCached",
+ true);
+ return;
+ }
+ visits_to_annotate_.emplace_back(visit);
+ base::UmaHistogramBoolean(
+ "OptimizationGuide.PageContentAnnotations.AnnotateVisitResultCached",
+ false);
+ if (visits_to_annotate_.size() >= features::AnnotateVisitBatchSize()) {
+ if (current_visit_annotation_batch_.empty()) {
+ // Used for testing.
+ LOCAL_HISTOGRAM_BOOLEAN(
+ "PageContentAnnotations.AnnotateVisit.BatchAnnotationStarted", true);
+ current_visit_annotation_batch_ = std::move(visits_to_annotate_);
+ AnnotateVisitBatch();
+ return;
+ }
+ // The queue is full and an batch annotation is actively being done so
+ // we will remove the "oldest" visit.
+ visits_to_annotate_.erase(visits_to_annotate_.begin());
+ // Used for testing.
+ LOCAL_HISTOGRAM_BOOLEAN(
+ "PageContentAnnotations.AnnotateVisit.QueueFullVisitDropped", true);
+ }
+ // Used for testing.
+ LOCAL_HISTOGRAM_BOOLEAN(
+ "PageContentAnnotations.AnnotateVisit.AnnotationRequestQueued", true);
#endif
}
+#if BUILDFLAG(BUILD_WITH_TFLITE_LIB)
+void PageContentAnnotationsService::AnnotateVisitBatch() {
+ DCHECK(!current_visit_annotation_batch_.empty());
+
+ if (switches::StopHistoryVisitBatchAnnotateForTesting()) {
+ // Code beyond this is tested in multiple places. This just ensures the
+ // calls up to this point can be more easily configured.
+ return;
+ }
+
+ if (current_visit_annotation_batch_.empty()) {
+ return;
+ }
+ auto visit = current_visit_annotation_batch_.back();
+ DCHECK(visit.text_to_annotate);
+ if (visit.text_to_annotate) {
+ model_manager_->Annotate(
+ *(visit.text_to_annotate),
+ base::BindOnce(&PageContentAnnotationsService::OnBatchVisitAnnotated,
+ weak_ptr_factory_.GetWeakPtr(), visit));
+ }
+}
+
+void PageContentAnnotationsService::OnBatchVisitAnnotated(
+ const HistoryVisit& visit,
+ const absl::optional<history::VisitContentModelAnnotations>&
+ content_annotations) {
+ OnPageContentAnnotated(visit, content_annotations);
+ DCHECK_EQ(visit.navigation_id,
+ current_visit_annotation_batch_.back().navigation_id);
+ current_visit_annotation_batch_.pop_back();
+ if (!current_visit_annotation_batch_.empty()) {
+ AnnotateVisitBatch();
+ }
+}
+#endif
+
void PageContentAnnotationsService::OverridePageContentAnnotatorForTesting(
PageContentAnnotator* annotator) {
annotator_ = annotator;
@@ -135,17 +247,27 @@ absl::optional<ModelInfo> PageContentAnnotationsService::GetModelInfoForType(
#endif
}
-void PageContentAnnotationsService::NotifyWhenModelAvailable(
+void PageContentAnnotationsService::RequestAndNotifyWhenModelAvailable(
AnnotationType type,
base::OnceCallback<void(bool)> callback) {
#if BUILDFLAG(BUILD_WITH_TFLITE_LIB)
DCHECK(model_manager_);
- model_manager_->NotifyWhenModelAvailable(type, std::move(callback));
+ model_manager_->RequestAndNotifyWhenModelAvailable(type, std::move(callback));
#else
std::move(callback).Run(false);
#endif
}
+void PageContentAnnotationsService::PersistSearchMetadata(
+ const HistoryVisit& visit,
+ const SearchMetadata& search_metadata) {
+ QueryURL(visit,
+ base::BindOnce(&history::HistoryService::AddSearchMetadataForVisit,
+ history_service_->AsWeakPtr(),
+ search_metadata.normalized_url,
+ search_metadata.search_terms));
+}
+
void PageContentAnnotationsService::ExtractRelatedSearches(
const HistoryVisit& visit,
content::WebContents* web_contents) {
@@ -166,6 +288,10 @@ void PageContentAnnotationsService::OnPageContentAnnotated(
if (!content_annotations)
return;
+ if (annotated_text_cache_.Peek(*visit.text_to_annotate) ==
+ annotated_text_cache_.end()) {
+ annotated_text_cache_.Put(*visit.text_to_annotate, *content_annotations);
+ }
MaybeRecordVisibilityUKM(visit, content_annotations);
if (!features::ShouldWriteContentAnnotationsToHistoryService())
@@ -258,6 +384,13 @@ void PageContentAnnotationsService::OnURLQueried(
void PageContentAnnotationsService::GetMetadataForEntityId(
const std::string& entity_id,
EntityMetadataRetrievedCallback callback) {
+ if (features::UseLocalPageEntitiesMetadataProvider()) {
+ DCHECK(local_page_entities_metadata_provider_);
+ local_page_entities_metadata_provider_->GetMetadataForEntityId(
+ entity_id, std::move(callback));
+ return;
+ }
+
#if BUILDFLAG(BUILD_WITH_TFLITE_LIB)
model_manager_->GetMetadataForEntityId(entity_id, std::move(callback));
#else
@@ -277,14 +410,51 @@ void PageContentAnnotationsService::PersistRemotePageEntities(
history_service_->AsWeakPtr(), annotations));
}
+void PageContentAnnotationsService::RunBatchAnnotationValidation() {
+ DCHECK(features::BatchAnnotationsValidationEnabled());
+ DCHECK(validation_timer_);
+ validation_timer_.reset();
+
+ std::vector<std::string> dummy_inputs;
+ dummy_inputs.reserve(features::BatchAnnotationsValidationBatchSize());
+ for (size_t i = 0; i < features::BatchAnnotationsValidationBatchSize(); i++) {
+ // Pick a random substring of the dummy blob so that we can't do any caching
+ // or deduping.
+ size_t half_length = std::strlen(kDummyTextBlob) / 2;
+ size_t rand_start = base::RandInt(0, half_length - 1);
+ dummy_inputs.emplace_back(
+ std::string(kDummyTextBlob + rand_start, half_length));
+ }
+
+ LOCAL_HISTOGRAM_COUNTS_100(
+ "OptimizationGuide.PageContentAnnotationsService.ValidationRun",
+ dummy_inputs.size());
+
+ BatchAnnotate(base::DoNothing(), dummy_inputs,
+ AnnotationType::kContentVisibility);
+}
+
// static
HistoryVisit PageContentAnnotationsService::CreateHistoryVisitFromWebContents(
content::WebContents* web_contents,
int64_t navigation_id) {
- HistoryVisit visit = {
+ HistoryVisit visit(
web_contents->GetController().GetLastCommittedEntry()->GetTimestamp(),
- web_contents->GetLastCommittedURL(), navigation_id};
+ web_contents->GetLastCommittedURL(), navigation_id);
return visit;
}
+HistoryVisit::HistoryVisit() = default;
+
+HistoryVisit::HistoryVisit(base::Time nav_entry_timestamp,
+ GURL url,
+ int64_t navigation_id) {
+ this->nav_entry_timestamp = nav_entry_timestamp;
+ this->url = url;
+ this->navigation_id = navigation_id;
+}
+
+HistoryVisit::~HistoryVisit() = default;
+HistoryVisit::HistoryVisit(const HistoryVisit&) = default;
+
} // namespace optimization_guide
diff --git a/chromium/components/optimization_guide/content/browser/page_content_annotations_service.h b/chromium/components/optimization_guide/content/browser/page_content_annotations_service.h
index 4e361811f85..7931d37b30e 100644
--- a/chromium/components/optimization_guide/content/browser/page_content_annotations_service.h
+++ b/chromium/components/optimization_guide/content/browser/page_content_annotations_service.h
@@ -9,12 +9,14 @@
#include "base/callback_forward.h"
#include "base/containers/lru_cache.h"
+#include "base/files/file_path.h"
#include "base/hash/hash.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
#include "base/task/cancelable_task_tracker.h"
+#include "base/task/sequenced_task_runner.h"
#include "components/continuous_search/browser/search_result_extractor_client.h"
#include "components/continuous_search/browser/search_result_extractor_client_status.h"
#include "components/continuous_search/common/public/mojom/continuous_search.mojom.h"
@@ -26,8 +28,13 @@
#include "components/optimization_guide/core/model_info.h"
#include "components/optimization_guide/core/page_content_annotations_common.h"
#include "components/optimization_guide/machine_learning_tflite_buildflags.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
#include "url/gurl.h"
+namespace base {
+class OneShotTimer;
+} // namespace base
+
namespace content {
class WebContents;
} // namespace content
@@ -36,8 +43,13 @@ namespace history {
class HistoryService;
} // namespace history
+namespace leveldb_proto {
+class ProtoDatabaseProvider;
+} // namespace leveldb_proto
+
namespace optimization_guide {
+class LocalPageEntitiesMetadataProvider;
class OptimizationGuideModelProvider;
class PageContentAnnotationsModelManager;
class PageContentAnnotationsServiceBrowserTest;
@@ -45,9 +57,15 @@ class PageContentAnnotationsWebContentsObserver;
// The information used by HistoryService to identify a visit to a URL.
struct HistoryVisit {
+ HistoryVisit();
+ HistoryVisit(base::Time nav_entry_timestamp, GURL url, int64_t navigation_id);
+ ~HistoryVisit();
+ HistoryVisit(const HistoryVisit&);
+
base::Time nav_entry_timestamp;
GURL url;
- int64_t navigation_id;
+ int64_t navigation_id = 0;
+ absl::optional<std::string> text_to_annotate;
struct Comp {
bool operator()(const HistoryVisit& lhs, const HistoryVisit& rhs) const {
@@ -58,6 +76,12 @@ struct HistoryVisit {
};
};
+// The information about a search visit to store in HistoryService.
+struct SearchMetadata {
+ GURL normalized_url;
+ std::u16string search_terms;
+};
+
// A KeyedService that annotates page content.
class PageContentAnnotationsService : public KeyedService,
public EntityMetadataProvider {
@@ -65,38 +89,44 @@ class PageContentAnnotationsService : public KeyedService,
PageContentAnnotationsService(
const std::string& application_locale,
OptimizationGuideModelProvider* optimization_guide_model_provider,
- history::HistoryService* history_service);
+ history::HistoryService* history_service,
+ leveldb_proto::ProtoDatabaseProvider* database_provider,
+ const base::FilePath& database_dir,
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner);
~PageContentAnnotationsService() override;
PageContentAnnotationsService(const PageContentAnnotationsService&) = delete;
PageContentAnnotationsService& operator=(
const PageContentAnnotationsService&) = delete;
// This is the main entry point for page content annotations by external
- // callers.
+ // callers. Callers must call |RequestAndNotifyWhenModelAvailable| as close to
+ // session start as possible to allow time for the model file to be
+ // downloaded.
void BatchAnnotate(BatchAnnotationCallback callback,
const std::vector<std::string>& inputs,
AnnotationType annotation_type);
- // Overrides the PageContentAnnotator for testing. See
- // test_page_content_annotator.h for an implementation designed for testing.
- void OverridePageContentAnnotatorForTesting(PageContentAnnotator* annotator);
+ // Requests that the given model for |type| be loaded in the background and
+ // then runs |callback| with true when the model is ready to execute. If the
+ // model is ready now, the callback is run immediately. If the model file will
+ // never be available, the callback is run with false.
+ void RequestAndNotifyWhenModelAvailable(
+ AnnotationType type,
+ base::OnceCallback<void(bool)> callback);
// Returns the model info for the given annotation type, if the model file is
// available.
absl::optional<ModelInfo> GetModelInfoForType(AnnotationType type) const;
- // Runs |callback| with true when the model that powers |BatchAnnotate| for
- // the given annotation type is ready to execute. If the model is ready now,
- // the callback is run immediately. If the model file will never be available,
- // the callback is run with false.
- void NotifyWhenModelAvailable(AnnotationType type,
- base::OnceCallback<void(bool)> callback);
-
// EntityMetadataProvider:
void GetMetadataForEntityId(
const std::string& entity_id,
EntityMetadataRetrievedCallback callback) override;
+ // Overrides the PageContentAnnotator for testing. See
+ // test_page_content_annotator.h for an implementation designed for testing.
+ void OverridePageContentAnnotatorForTesting(PageContentAnnotator* annotator);
+
private:
#if BUILDFLAG(BUILD_WITH_TFLITE_LIB)
// Callback invoked when |visit| has been annotated.
@@ -105,7 +135,20 @@ class PageContentAnnotationsService : public KeyedService,
const absl::optional<history::VisitContentModelAnnotations>&
content_annotations);
+ // Runs the page annotation models available to |model_manager_| on all the
+ // visits within |current_visit_annotation_batch_|.
+ void AnnotateVisitBatch();
+
+ // Callback run after the annotations for a |visit| of a batch has been
+ // determined. |current_visit_annotation_batch_| is updated to remove
+ // the annotated visit and will trigger the next visit to be annotated.
+ void OnBatchVisitAnnotated(
+ const HistoryVisit& visit,
+ const absl::optional<history::VisitContentModelAnnotations>&
+ content_annotations);
+
std::unique_ptr<PageContentAnnotationsModelManager> model_manager_;
+
#endif
// The annotator to use for requests to |BatchAnnotate|. In prod, this is
@@ -123,13 +166,17 @@ class PageContentAnnotationsService : public KeyedService,
friend class PageContentAnnotationsWebContentsObserver;
friend class PageContentAnnotationsServiceBrowserTest;
// Virtualized for testing.
- virtual void Annotate(const HistoryVisit& visit, const std::string& text);
+ virtual void Annotate(const HistoryVisit& visit);
// Creates a HistoryVisit based on the current state of |web_contents|.
static HistoryVisit CreateHistoryVisitFromWebContents(
content::WebContents* web_contents,
int64_t navigation_id);
+ // Persist |search_metadata| for |visit| in |history_service_|.
+ virtual void PersistSearchMetadata(const HistoryVisit& visit,
+ const SearchMetadata& search_metadata);
+
// Requests |search_result_extractor_client_| to extract related searches from
// the Google SRP DOM associated with |web_contents|.
//
@@ -165,6 +212,17 @@ class PageContentAnnotationsService : public KeyedService,
PersistAnnotationsCallback callback,
history::QueryURLResult url_result);
+ // Runs a batch annotation validation, that is calls |BatchAnnotate| with
+ // dummy input and discards the output.
+ void RunBatchAnnotationValidation();
+
+ // A metadata-only provider for page entities (as opposed to |model_manager_|
+ // which does both entity model execution and metadata providing) that uses a
+ // local database to provide the metadata for a given entity id. This is only
+ // non-null and initialized when its feature flag is enabled.
+ std::unique_ptr<LocalPageEntitiesMetadataProvider>
+ local_page_entities_metadata_provider_;
+
// The history service to write content annotations to. Not owned. Guaranteed
// to outlive |this|.
raw_ptr<history::HistoryService> history_service_;
@@ -180,6 +238,23 @@ class PageContentAnnotationsService : public KeyedService,
base::LRUCache<HistoryVisit, bool, HistoryVisit::Comp>
last_annotated_history_visits_;
+ // A LRU cache of the annotation results for visits. If the text of the visit
+ // is in the cache, the cached model annotations will be used.
+ base::HashingLRUCache<std::string, history::VisitContentModelAnnotations>
+ annotated_text_cache_;
+
+ // The set of visits to be annotated, this is added to by Annotate requests
+ // from the web content observer. These will be annotated when the set is full
+ // and annotations can be scheduled with minimal impact to browsing.
+ std::vector<HistoryVisit> visits_to_annotate_;
+
+ // The batch of visits being annotated. If this is empty, it is assumed that
+ // no visits are actively be annotated and a new batch can be started.
+ std::vector<HistoryVisit> current_visit_annotation_batch_;
+
+ // Is only ever set when the feature is enabled.
+ std::unique_ptr<base::OneShotTimer> validation_timer_;
+
base::WeakPtrFactory<PageContentAnnotationsService> weak_ptr_factory_{this};
};
diff --git a/chromium/components/optimization_guide/content/browser/page_content_annotations_web_contents_observer.cc b/chromium/components/optimization_guide/content/browser/page_content_annotations_web_contents_observer.cc
index 8eea9f2744e..d91df2d5163 100644
--- a/chromium/components/optimization_guide/content/browser/page_content_annotations_web_contents_observer.cc
+++ b/chromium/components/optimization_guide/content/browser/page_content_annotations_web_contents_observer.cc
@@ -11,6 +11,7 @@
#include "components/optimization_guide/content/browser/optimization_guide_decider.h"
#include "components/optimization_guide/content/browser/page_content_annotations_service.h"
#include "components/optimization_guide/core/optimization_guide_features.h"
+#include "components/optimization_guide/core/optimization_guide_switches.h"
#include "components/optimization_guide/proto/page_entities_metadata.pb.h"
#include "components/search_engines/template_url_service.h"
#include "content/public/browser/navigation_entry.h"
@@ -21,24 +22,38 @@ namespace optimization_guide {
namespace {
-// Returns the search query if |url| is a valid Search URL according to
+// Returns search metadata if |url| is a valid Search URL according to
// |template_url_service|.
-absl::optional<std::u16string> ExtractSearchTerms(
+absl::optional<SearchMetadata> ExtractSearchMetadata(
const TemplateURLService* template_url_service,
const GURL& url) {
- const TemplateURL* default_search_provider =
- template_url_service->GetDefaultSearchProvider();
+ if (!template_url_service)
+ return absl::nullopt;
+
+ const TemplateURL* template_url =
+ template_url_service->GetTemplateURLForHost(url.host());
const SearchTermsData& search_terms_data =
template_url_service->search_terms_data();
std::u16string search_terms;
- if (default_search_provider &&
- default_search_provider->ExtractSearchTermsFromURL(url, search_terms_data,
- &search_terms) &&
- !search_terms.empty()) {
- return search_terms;
- }
- return absl::nullopt;
+ bool is_valid_search_url = template_url &&
+ template_url->ExtractSearchTermsFromURL(
+ url, search_terms_data, &search_terms) &&
+ !search_terms.empty();
+ if (!is_valid_search_url)
+ return absl::nullopt;
+
+ const std::u16string& normalized_search_query =
+ base::i18n::ToLower(base::CollapseWhitespace(search_terms, false));
+ TemplateURLRef::SearchTermsArgs search_terms_args(normalized_search_query);
+ const TemplateURLRef& search_url_ref = template_url->url_ref();
+ if (!search_url_ref.SupportsReplacement(search_terms_data))
+ return absl::nullopt;
+
+ return SearchMetadata{
+ GURL(search_url_ref.ReplaceSearchTerms(search_terms_args,
+ search_terms_data)),
+ base::i18n::ToLower(base::CollapseWhitespace(search_terms, false))};
}
// Data scoped to a single page. PageData has the same lifetime as the page's
@@ -147,16 +162,24 @@ void PageContentAnnotationsWebContentsObserver::DidFinishNavigation(
web_contents());
}
- absl::optional<std::u16string> search_terms =
- ExtractSearchTerms(template_url_service_, navigation_handle->GetURL());
- if (search_terms) {
+ absl::optional<SearchMetadata> search_metadata = ExtractSearchMetadata(
+ template_url_service_, navigation_handle->GetURL());
+ if (search_metadata) {
if (page_data) {
page_data->set_annotation_was_requested();
}
- const std::u16string& normalized_search_query =
- base::i18n::ToLower(base::CollapseWhitespace(*search_terms, false));
- page_content_annotations_service_->Annotate(
- history_visit, base::UTF16ToUTF8(normalized_search_query));
+ history_visit.text_to_annotate =
+ base::UTF16ToUTF8(search_metadata->search_terms);
+ page_content_annotations_service_->Annotate(history_visit);
+ page_content_annotations_service_->PersistSearchMetadata(
+ history_visit, *search_metadata);
+
+ if (switches::ShouldLogPageContentAnnotationsInput()) {
+ LOG(ERROR) << "Annotating search terms: \n"
+ << "URL: " << navigation_handle->GetURL() << "\n"
+ << "Text: " << *(history_visit.text_to_annotate);
+ }
+
return;
}
}
@@ -168,8 +191,15 @@ void PageContentAnnotationsWebContentsObserver::DidFinishNavigation(
page_data->set_annotation_was_requested();
}
// Annotate the title instead.
- page_content_annotations_service_->Annotate(
- history_visit, base::UTF16ToUTF8(web_contents()->GetTitle()));
+ history_visit.text_to_annotate =
+ base::UTF16ToUTF8(web_contents()->GetTitle());
+ page_content_annotations_service_->Annotate(history_visit);
+
+ if (switches::ShouldLogPageContentAnnotationsInput()) {
+ LOG(ERROR) << "Annotating same document navigation: \n"
+ << "URL: " << navigation_handle->GetURL() << "\n"
+ << "Text: " << *(history_visit.text_to_annotate);
+ }
}
}
@@ -191,8 +221,15 @@ void PageContentAnnotationsWebContentsObserver::TitleWasSet(
optimization_guide::HistoryVisit history_visit = optimization_guide::
PageContentAnnotationsService::CreateHistoryVisitFromWebContents(
web_contents(), page_data->navigation_id());
- page_content_annotations_service_->Annotate(
- history_visit, base::UTF16ToUTF8(entry->GetTitleForDisplay()));
+ history_visit.text_to_annotate =
+ base::UTF16ToUTF8(entry->GetTitleForDisplay());
+ page_content_annotations_service_->Annotate(history_visit);
+
+ if (switches::ShouldLogPageContentAnnotationsInput()) {
+ LOG(ERROR) << "Annotating main frame navigation: \n"
+ << "URL: " << entry->GetURL() << "\n"
+ << "Text: " << *(history_visit.text_to_annotate);
+ }
}
std::unique_ptr<PageTextObserver::ConsumerTextDumpRequest>
@@ -230,7 +267,7 @@ PageContentAnnotationsWebContentsObserver::MaybeRequestFrameTextDump(
}
void PageContentAnnotationsWebContentsObserver::OnTextDumpReceived(
- const HistoryVisit& visit,
+ HistoryVisit visit,
const PageTextDumpResult& result) {
DCHECK(!features::ShouldAnnotateTitleInsteadOfPageContent());
@@ -241,12 +278,22 @@ void PageContentAnnotationsWebContentsObserver::OnTextDumpReceived(
// If the page had AMP frames, then only use that content. Otherwise, use the
// mainframe.
if (result.GetAMPTextContent()) {
- page_content_annotations_service_->Annotate(visit,
- *result.GetAMPTextContent());
+ visit.text_to_annotate = *result.GetAMPTextContent();
+ page_content_annotations_service_->Annotate(visit);
+ if (switches::ShouldLogPageContentAnnotationsInput()) {
+ LOG(ERROR) << "Annotating AMP text content: \n"
+ << "URL: " << visit.url << "\n"
+ << "Text: " << *(visit.text_to_annotate);
+ }
return;
}
- page_content_annotations_service_->Annotate(
- visit, *result.GetMainFrameTextContent());
+ visit.text_to_annotate = *result.GetMainFrameTextContent();
+ page_content_annotations_service_->Annotate(visit);
+ if (switches::ShouldLogPageContentAnnotationsInput()) {
+ LOG(ERROR) << "Annotating main frame text content: \n"
+ << "URL: " << visit.url << "\n"
+ << "Text: " << *(visit.text_to_annotate);
+ }
}
void PageContentAnnotationsWebContentsObserver::OnRemotePageEntitiesReceived(
diff --git a/chromium/components/optimization_guide/content/browser/page_content_annotations_web_contents_observer.h b/chromium/components/optimization_guide/content/browser/page_content_annotations_web_contents_observer.h
index c0417821386..de084693c39 100644
--- a/chromium/components/optimization_guide/content/browser/page_content_annotations_web_contents_observer.h
+++ b/chromium/components/optimization_guide/content/browser/page_content_annotations_web_contents_observer.h
@@ -62,8 +62,7 @@ class PageContentAnnotationsWebContentsObserver
content::NavigationHandle* navigation_handle) override;
// Callback invoked when a text dump has been received for the |visit|.
- void OnTextDumpReceived(const HistoryVisit& visit,
- const PageTextDumpResult& result);
+ void OnTextDumpReceived(HistoryVisit visit, const PageTextDumpResult& result);
// Callback invoked when the page entities have been received from
// |optimization_guide_decider_| for |visit|.
diff --git a/chromium/components/optimization_guide/content/browser/page_content_annotations_web_contents_observer_unittest.cc b/chromium/components/optimization_guide/content/browser/page_content_annotations_web_contents_observer_unittest.cc
index c08c20f7276..49397fca3e7 100644
--- a/chromium/components/optimization_guide/content/browser/page_content_annotations_web_contents_observer_unittest.cc
+++ b/chromium/components/optimization_guide/content/browser/page_content_annotations_web_contents_observer_unittest.cc
@@ -62,11 +62,14 @@ class FakePageContentAnnotationsService : public PageContentAnnotationsService {
history::HistoryService* history_service)
: PageContentAnnotationsService("en-US",
optimization_guide_model_provider,
- history_service) {}
+ history_service,
+ nullptr,
+ base::FilePath(),
+ nullptr) {}
~FakePageContentAnnotationsService() override = default;
- void Annotate(const HistoryVisit& visit, const std::string& text) override {
- last_annotation_request_.emplace(std::make_pair(visit, text));
+ void Annotate(const HistoryVisit& visit) override {
+ last_annotation_request_.emplace(visit);
}
void ExtractRelatedSearches(const HistoryVisit& visit,
@@ -75,8 +78,7 @@ class FakePageContentAnnotationsService : public PageContentAnnotationsService {
std::make_pair(visit, web_contents));
}
- absl::optional<std::pair<HistoryVisit, std::string>> last_annotation_request()
- const {
+ absl::optional<HistoryVisit> last_annotation_request() const {
return last_annotation_request_;
}
@@ -103,14 +105,24 @@ class FakePageContentAnnotationsService : public PageContentAnnotationsService {
return last_entities_persistence_request_;
}
+ void PersistSearchMetadata(const HistoryVisit& visit,
+ const SearchMetadata& search_metadata) override {
+ last_search_metadata_ = search_metadata;
+ }
+
+ absl::optional<SearchMetadata> last_search_metadata_persisted() const {
+ return last_search_metadata_;
+ }
+
private:
- absl::optional<std::pair<HistoryVisit, std::string>> last_annotation_request_;
+ absl::optional<HistoryVisit> last_annotation_request_;
absl::optional<std::pair<HistoryVisit, content::WebContents*>>
last_related_searches_extraction_request_;
absl::optional<
std::pair<HistoryVisit,
std::vector<history::VisitContentModelAnnotations::Category>>>
last_entities_persistence_request_;
+ absl::optional<SearchMetadata> last_search_metadata_;
};
class FakeOptimizationGuideDecider : public TestOptimizationGuideDecider {
@@ -322,11 +334,11 @@ TEST_F(PageContentAnnotationsWebContentsObserverTest,
result.AddFrameTextDumpResult(frame_result);
std::move(request->callback).Run(std::move(result));
- absl::optional<std::pair<HistoryVisit, std::string>> last_annotation_request =
+ absl::optional<HistoryVisit> last_annotation_request =
service()->last_annotation_request();
EXPECT_TRUE(last_annotation_request.has_value());
- EXPECT_EQ(last_annotation_request->first.url, GURL("http://test.com"));
- EXPECT_EQ(last_annotation_request->second, "some text");
+ EXPECT_EQ(last_annotation_request->url, GURL("http://test.com"));
+ EXPECT_EQ(last_annotation_request->text_to_annotate, "some text");
service()->ClearLastAnnotationRequest();
@@ -355,11 +367,11 @@ TEST_F(PageContentAnnotationsWebContentsObserverTest,
navigation_simulator->CommitSameDocument();
// The title should be what is requested to be annotated.
- absl::optional<std::pair<HistoryVisit, std::string>> last_annotation_request =
+ absl::optional<HistoryVisit> last_annotation_request =
service()->last_annotation_request();
EXPECT_TRUE(last_annotation_request.has_value());
- EXPECT_EQ(last_annotation_request->first.url, url2);
- EXPECT_EQ(last_annotation_request->second, "Title");
+ EXPECT_EQ(last_annotation_request->url, url2);
+ EXPECT_EQ(last_annotation_request->text_to_annotate, "Title");
}
TEST_F(PageContentAnnotationsWebContentsObserverTest,
@@ -369,12 +381,19 @@ TEST_F(PageContentAnnotationsWebContentsObserverTest,
web_contents(), GURL("http://default-engine.com/search?q=a"));
// The search query should be what is requested to be annotated.
- absl::optional<std::pair<HistoryVisit, std::string>> last_annotation_request =
+ absl::optional<HistoryVisit> last_annotation_request =
service()->last_annotation_request();
ASSERT_TRUE(last_annotation_request.has_value());
- EXPECT_EQ(last_annotation_request->first.url,
+ EXPECT_EQ(last_annotation_request->url,
+ GURL("http://default-engine.com/search?q=a"));
+ EXPECT_EQ(last_annotation_request->text_to_annotate, "a");
+
+ absl::optional<SearchMetadata> last_search_metadata_persisted =
+ service()->last_search_metadata_persisted();
+ ASSERT_TRUE(last_search_metadata_persisted.has_value());
+ EXPECT_EQ(last_search_metadata_persisted->normalized_url,
GURL("http://default-engine.com/search?q=a"));
- EXPECT_EQ(last_annotation_request->second, "a");
+ EXPECT_EQ(last_search_metadata_persisted->search_terms, u"a");
}
TEST_F(PageContentAnnotationsWebContentsObserverTest,
@@ -460,11 +479,11 @@ TEST_F(PageContentAnnotationsWebContentsObserverAnnotateTitleTest,
navigation_simulator->CommitSameDocument();
// The title should be what is requested to be annotated.
- absl::optional<std::pair<HistoryVisit, std::string>> last_annotation_request =
+ absl::optional<HistoryVisit> last_annotation_request =
service()->last_annotation_request();
EXPECT_TRUE(last_annotation_request.has_value());
- EXPECT_EQ(last_annotation_request->first.url, url2);
- EXPECT_EQ(last_annotation_request->second, "Title");
+ EXPECT_EQ(last_annotation_request->url, url2);
+ EXPECT_EQ(last_annotation_request->text_to_annotate, "Title");
service()->ClearLastAnnotationRequest();
@@ -489,12 +508,11 @@ TEST_F(PageContentAnnotationsWebContentsObserverAnnotateTitleTest,
title);
// The title should be what is requested to be annotated.
- absl::optional<std::pair<HistoryVisit, std::string>> last_annotation_request =
+ absl::optional<HistoryVisit> last_annotation_request =
service()->last_annotation_request();
EXPECT_TRUE(last_annotation_request.has_value());
- EXPECT_EQ(last_annotation_request->first.url,
- GURL("http://www.foo.com/someurl"));
- EXPECT_EQ(last_annotation_request->second, "Title");
+ EXPECT_EQ(last_annotation_request->url, GURL("http://www.foo.com/someurl"));
+ EXPECT_EQ(last_annotation_request->text_to_annotate, "Title");
service()->ClearLastAnnotationRequest();
diff --git a/chromium/components/optimization_guide/content/browser/test_page_content_annotator.cc b/chromium/components/optimization_guide/content/browser/test_page_content_annotator.cc
index 5df206b2994..f1c12bed097 100644
--- a/chromium/components/optimization_guide/content/browser/test_page_content_annotator.cc
+++ b/chromium/components/optimization_guide/content/browser/test_page_content_annotator.cc
@@ -17,7 +17,7 @@ void TestPageContentAnnotator::Annotate(BatchAnnotationCallback callback,
if (annotation_type == AnnotationType::kPageTopics) {
for (const std::string& input : inputs) {
auto it = topics_by_input_.find(input);
- absl::optional<std::vector<WeightedString>> output;
+ absl::optional<std::vector<WeightedIdentifier>> output;
if (it != topics_by_input_.end()) {
output = it->second;
}
@@ -54,7 +54,7 @@ void TestPageContentAnnotator::Annotate(BatchAnnotationCallback callback,
}
void TestPageContentAnnotator::UsePageTopics(
- const base::flat_map<std::string, std::vector<WeightedString>>&
+ const base::flat_map<std::string, std::vector<WeightedIdentifier>>&
topics_by_input) {
topics_by_input_ = topics_by_input;
}
diff --git a/chromium/components/optimization_guide/content/browser/test_page_content_annotator.h b/chromium/components/optimization_guide/content/browser/test_page_content_annotator.h
index dc52ac14b03..a38e1ccd5c4 100644
--- a/chromium/components/optimization_guide/content/browser/test_page_content_annotator.h
+++ b/chromium/components/optimization_guide/content/browser/test_page_content_annotator.h
@@ -23,7 +23,7 @@ class TestPageContentAnnotator : public PageContentAnnotator {
// The given page topics are used for the matching BatchAnnotationResults by
// input string. If the input is not found, the output is left as nullopt.
void UsePageTopics(
- const base::flat_map<std::string, std::vector<WeightedString>>&
+ const base::flat_map<std::string, std::vector<WeightedIdentifier>>&
topics_by_input);
// The given page entities are used for the matching BatchAnnotationResults by
@@ -43,7 +43,7 @@ class TestPageContentAnnotator : public PageContentAnnotator {
AnnotationType annotation_type) override;
private:
- base::flat_map<std::string, std::vector<WeightedString>> topics_by_input_;
+ base::flat_map<std::string, std::vector<WeightedIdentifier>> topics_by_input_;
base::flat_map<std::string, std::vector<ScoredEntityMetadata>>
entities_by_input_;
base::flat_map<std::string, double> visibility_scores_for_input_;
diff --git a/chromium/components/optimization_guide/core/BUILD.gn b/chromium/components/optimization_guide/core/BUILD.gn
index e66d20fc9ba..90eaa54e934 100644
--- a/chromium/components/optimization_guide/core/BUILD.gn
+++ b/chromium/components/optimization_guide/core/BUILD.gn
@@ -1,5 +1,5 @@
-# Copyright 2017 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
+# Copyright 2017 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.
if (is_android) {
@@ -32,14 +32,66 @@ static_library("entities") {
]
}
+static_library("model_executor") {
+ sources = [
+ "execution_status.cc",
+ "execution_status.h",
+ "model_enums.h",
+ "model_executor.h",
+ "model_info.cc",
+ "model_info.h",
+ "model_util.cc",
+ "model_util.h",
+ ]
+ if (build_with_tflite_lib) {
+ sources += [
+ "base_model_executor.h",
+ "base_model_executor_helpers.h",
+ "bert_model_executor.cc",
+ "bert_model_executor.h",
+ "tflite_model_executor.h",
+ ]
+ }
+
+ public_deps = [
+ "//components/optimization_guide:machine_learning_tflite_buildflags",
+ "//third_party/re2",
+ ]
+ if (build_with_tflite_lib) {
+ public_deps += [
+ "//components/optimization_guide/core:machine_learning",
+ "//third_party/abseil-cpp:absl",
+ "//third_party/tflite",
+ "//third_party/tflite:tflite_public_headers",
+ "//third_party/tflite_support",
+ "//third_party/tflite_support:tflite_support_proto",
+ ]
+ }
+ deps = [
+ "//base",
+ "//components/optimization_guide/proto:optimization_guide_proto",
+ "//net",
+ "//url",
+ ]
+}
+
+if (build_with_tflite_lib) {
+ static_library("machine_learning") {
+ sources = [
+ "tflite_op_resolver.cc",
+ "tflite_op_resolver.h",
+ ]
+ deps = [
+ "//third_party/tflite",
+ "//third_party/tflite:tflite_public_headers",
+ ]
+ }
+}
+
static_library("core") {
sources = [
"command_line_top_host_provider.cc",
"command_line_top_host_provider.h",
- "decision_tree_prediction_model.cc",
- "decision_tree_prediction_model.h",
- "execution_status.cc",
- "execution_status.h",
"hint_cache.cc",
"hint_cache.h",
"hints_component_info.h",
@@ -54,12 +106,11 @@ static_library("core") {
"hints_processing_util.cc",
"hints_processing_util.h",
"insertion_ordered_set.h",
+ "local_page_entities_metadata_provider.cc",
+ "local_page_entities_metadata_provider.h",
"memory_hint.cc",
"memory_hint.h",
- "model_executor.h",
"model_handler.h",
- "model_info.cc",
- "model_info.h",
"noisy_metrics_recorder.cc",
"noisy_metrics_recorder.h",
"optimization_filter.cc",
@@ -70,6 +121,8 @@ static_library("core") {
"optimization_guide_enums.h",
"optimization_guide_features.cc",
"optimization_guide_features.h",
+ "optimization_guide_logger.cc",
+ "optimization_guide_logger.h",
"optimization_guide_model_provider.h",
"optimization_guide_navigation_data.cc",
"optimization_guide_navigation_data.h",
@@ -93,8 +146,6 @@ static_library("core") {
"page_content_annotation_job.h",
"page_content_annotations_common.cc",
"page_content_annotations_common.h",
- "prediction_model.cc",
- "prediction_model.h",
"prediction_model_fetcher.h",
"prediction_model_fetcher_impl.cc",
"prediction_model_fetcher_impl.h",
@@ -108,10 +159,6 @@ static_library("core") {
]
if (build_with_tflite_lib) {
sources += [
- "base_model_executor.h",
- "base_model_executor_helpers.h",
- "bert_model_executor.cc",
- "bert_model_executor.h",
"bert_model_handler.cc",
"bert_model_handler.h",
"model_validator.cc",
@@ -123,12 +170,20 @@ static_library("core") {
"page_topics_model_executor.h",
"page_visibility_model_executor.cc",
"page_visibility_model_executor.h",
- "tflite_model_executor.h",
]
+ if (build_with_internal_optimization_guide) {
+ sources += [
+ "entity_annotator_native_library.cc",
+ "entity_annotator_native_library.h",
+ "page_entities_model_executor_impl.cc",
+ "page_entities_model_executor_impl.h",
+ ]
+ }
}
public_deps = [
":entities",
+ ":model_executor",
"//components/optimization_guide:machine_learning_tflite_buildflags",
"//third_party/re2",
]
@@ -146,7 +201,6 @@ static_library("core") {
deps = [
":bloomfilter",
"//base",
- "//components/data_reduction_proxy/core/browser",
"//components/leveldb_proto",
"//components/optimization_guide/proto:optimization_guide_proto",
"//components/prefs",
@@ -161,17 +215,9 @@ static_library("core") {
"//ui/base:base",
"//url:url",
]
-}
-
-if (build_with_tflite_lib) {
- static_library("machine_learning") {
- sources = [
- "tflite_op_resolver.cc",
- "tflite_op_resolver.h",
- ]
- deps = [
- "//third_party/tflite",
- "//third_party/tflite:tflite_public_headers",
+ if (build_with_tflite_lib && build_with_internal_optimization_guide) {
+ data_deps = [
+ "//components/optimization_guide/internal:optimization_guide_internal",
]
}
}
@@ -244,13 +290,13 @@ source_set("unit_tests") {
"batch_entity_metadata_task_unittest.cc",
"bloom_filter_unittest.cc",
"command_line_top_host_provider_unittest.cc",
- "decision_tree_prediction_model_unittest.cc",
"hint_cache_unittest.cc",
"hints_component_util_unittest.cc",
"hints_fetcher_unittest.cc",
"hints_manager_unittest.cc",
"hints_processing_util_unittest.cc",
"insertion_ordered_set_unittest.cc",
+ "local_page_entities_metadata_provider_unittest.cc",
"model_handler_unittest.cc",
"noisy_metrics_recorder_unittest.cc",
"optimization_filter_unittest.cc",
@@ -264,7 +310,6 @@ source_set("unit_tests") {
"optimization_metadata_unittest.cc",
"page_content_annotation_job_unittest.cc",
"prediction_model_fetcher_unittest.cc",
- "prediction_model_unittest.cc",
"store_update_data_unittest.cc",
"url_pattern_with_wildcards_unittest.cc",
]
@@ -277,6 +322,12 @@ source_set("unit_tests") {
"page_visibility_model_executor_unittest.cc",
"tflite_model_executor_unittest.cc",
]
+ if (build_with_internal_optimization_guide) {
+ sources += [
+ "entity_annotator_native_library_unittest.cc",
+ "page_entities_model_executor_impl_unittest.cc",
+ ]
+ }
}
deps = [
@@ -286,8 +337,6 @@ source_set("unit_tests") {
":test_support",
"//base",
"//base/test:test_support",
- "//components/data_reduction_proxy/core/browser",
- "//components/data_reduction_proxy/core/common",
"//components/leveldb_proto:test_support",
"//components/optimization_guide/proto:optimization_guide_proto",
"//components/prefs:test_support",
@@ -319,3 +368,17 @@ if (is_android) {
visibility = [ "//chrome/browser/optimization_guide/android:*" ]
}
}
+
+if (is_mac && build_with_internal_optimization_guide) {
+ # We need to copy the optimization guide shared library so that the
+ # bundle_data dependencies have a "copy" target type.Otherwise for
+ # "shared_library" target types it will try to link things into
+ # Chromium Framework when we want to keep it separate instead.
+ copy("optimization_guide_internal_library_copy") {
+ sources = [ "$root_out_dir/liboptimization_guide_internal.dylib" ]
+ outputs = [ "$root_out_dir/og_intermediates/{{source_file_part}}" ]
+ deps = [
+ "//components/optimization_guide/internal:optimization_guide_internal",
+ ]
+ }
+}
diff --git a/chromium/components/optimization_guide/core/DEPS b/chromium/components/optimization_guide/core/DEPS
index 3ab01bf2788..74dc5dfb565 100644
--- a/chromium/components/optimization_guide/core/DEPS
+++ b/chromium/components/optimization_guide/core/DEPS
@@ -1,7 +1,5 @@
include_rules = [
"+components/ukm/test_ukm_recorder.h",
"+services/metrics/public/cpp",
- "+third_party/abseil-cpp/absl/types/optional.h",
- "+third_party/abseil-cpp/absl/status/status.h",
"+ui/base/l10n",
]
diff --git a/chromium/components/optimization_guide/core/base_model_executor.h b/chromium/components/optimization_guide/core/base_model_executor.h
index 76bd8b96a46..78e064b4256 100644
--- a/chromium/components/optimization_guide/core/base_model_executor.h
+++ b/chromium/components/optimization_guide/core/base_model_executor.h
@@ -69,9 +69,9 @@ class BaseModelExecutor : public TFLiteModelExecutor<OutputType, InputTypes...>,
}
// InferenceDelegate:
- absl::Status Preprocess(const std::vector<TfLiteTensor*>& input_tensors,
- InputTypes... input) override = 0;
- OutputType Postprocess(
+ bool Preprocess(const std::vector<TfLiteTensor*>& input_tensors,
+ InputTypes... input) override = 0;
+ absl::optional<OutputType> Postprocess(
const std::vector<const TfLiteTensor*>& output_tensors) override = 0;
};
diff --git a/chromium/components/optimization_guide/core/base_model_executor_helpers.h b/chromium/components/optimization_guide/core/base_model_executor_helpers.h
index 0b9717eee2c..986ce04589d 100644
--- a/chromium/components/optimization_guide/core/base_model_executor_helpers.h
+++ b/chromium/components/optimization_guide/core/base_model_executor_helpers.h
@@ -11,6 +11,7 @@
#include "base/check.h"
#include "base/memory/raw_ptr.h"
#include "components/optimization_guide/core/execution_status.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/tflite_support/src/tensorflow_lite_support/cc/task/core/base_task_api.h"
namespace optimization_guide {
@@ -18,13 +19,13 @@ namespace optimization_guide {
template <class OutputType, class... InputTypes>
class InferenceDelegate {
public:
- // Preprocesses |args| into |input_tensors|.
- virtual absl::Status Preprocess(
- const std::vector<TfLiteTensor*>& input_tensors,
- InputTypes... args) = 0;
+ // Preprocesses |args| into |input_tensors|. Returns true on success.
+ virtual bool Preprocess(const std::vector<TfLiteTensor*>& input_tensors,
+ InputTypes... args) = 0;
- // Postprocesses |output_tensors| into the desired |OutputType|.
- virtual OutputType Postprocess(
+ // Postprocesses |output_tensors| into the desired |OutputType|, returning
+ // absl::nullopt on error.
+ virtual absl::optional<OutputType> Postprocess(
const std::vector<const TfLiteTensor*>& output_tensors) = 0;
};
@@ -59,12 +60,24 @@ class GenericModelExecutionTask
// BaseTaskApi:
absl::Status Preprocess(const std::vector<TfLiteTensor*>& input_tensors,
InputTypes... args) override {
- return delegate_->Preprocess(input_tensors, args...);
+ bool success = delegate_->Preprocess(input_tensors, args...);
+ if (success) {
+ return absl::OkStatus();
+ }
+ return absl::InternalError(
+ "error during preprocessing. See stderr for more information if "
+ "available");
}
tflite::support::StatusOr<OutputType> Postprocess(
const std::vector<const TfLiteTensor*>& output_tensors,
InputTypes... api_inputs) override {
- return delegate_->Postprocess(output_tensors);
+ absl::optional<OutputType> output = delegate_->Postprocess(output_tensors);
+ if (!output) {
+ return absl::InternalError(
+ "error during postprocessing. See stderr for more infomation if "
+ "available");
+ }
+ return *output;
}
private:
diff --git a/chromium/components/optimization_guide/core/bert_model_executor.cc b/chromium/components/optimization_guide/core/bert_model_executor.cc
index ab2b7306726..fcd4df0e96d 100644
--- a/chromium/components/optimization_guide/core/bert_model_executor.cc
+++ b/chromium/components/optimization_guide/core/bert_model_executor.cc
@@ -5,9 +5,9 @@
#include "components/optimization_guide/core/bert_model_executor.h"
#include "base/trace_event/trace_event.h"
-#include "components/optimization_guide/core/optimization_guide_util.h"
+#include "components/optimization_guide/core/model_util.h"
#include "components/optimization_guide/core/tflite_op_resolver.h"
-#include "third_party/tflite_support/src/tensorflow_lite_support/cc/task/text/nlclassifier/bert_nl_classifier.h"
+#include "third_party/tflite_support/src/tensorflow_lite_support/cc/task/text/bert_nl_classifier.h"
namespace optimization_guide {
@@ -28,18 +28,21 @@ BertModelExecutor::Execute(ModelExecutionTask* execution_task,
GetStringNameForOptimizationTarget(optimization_target_),
"input_length", input.size());
*out_status = ExecutionStatus::kSuccess;
- return static_cast<tflite::task::text::nlclassifier::BertNLClassifier*>(
- execution_task)
+ return static_cast<tflite::task::text::BertNLClassifier*>(execution_task)
->Classify(input);
}
std::unique_ptr<BertModelExecutor::ModelExecutionTask>
BertModelExecutor::BuildModelExecutionTask(base::MemoryMappedFile* model_file,
ExecutionStatus* out_status) {
+ tflite::task::text::BertNLClassifierOptions options;
+ *options.mutable_base_options()
+ ->mutable_model_file()
+ ->mutable_file_content() = std::string(
+ reinterpret_cast<const char*>(model_file->data()), model_file->length());
auto maybe_nl_classifier =
- tflite::task::text::nlclassifier::BertNLClassifier::CreateFromBuffer(
- reinterpret_cast<const char*>(model_file->data()),
- model_file->length(), std::make_unique<TFLiteOpResolver>());
+ tflite::task::text::BertNLClassifier::CreateFromOptions(
+ std::move(options), std::make_unique<TFLiteOpResolver>());
if (maybe_nl_classifier.ok())
return std::move(maybe_nl_classifier.value());
*out_status = ExecutionStatus::kErrorModelFileNotValid;
diff --git a/chromium/components/optimization_guide/core/bloom_filter_unittest.cc b/chromium/components/optimization_guide/core/bloom_filter_unittest.cc
index a2551a522fe..e0cf1884b67 100644
--- a/chromium/components/optimization_guide/core/bloom_filter_unittest.cc
+++ b/chromium/components/optimization_guide/core/bloom_filter_unittest.cc
@@ -103,7 +103,7 @@ TEST(BloomFilterTest, EverythingMatches) {
}
// Disable this test in configurations that don't print CHECK failures.
-#if !defined(OS_IOS) && !(defined(OFFICIAL_BUILD) && defined(NDEBUG))
+#if !BUILDFLAG(IS_IOS) && !(defined(OFFICIAL_BUILD) && defined(NDEBUG))
TEST(BloomFilterTest, ByteVectorTooSmall) {
std::string data(1023, 0xff);
EXPECT_DEATH(
diff --git a/chromium/components/optimization_guide/core/decision_tree_prediction_model.cc b/chromium/components/optimization_guide/core/decision_tree_prediction_model.cc
deleted file mode 100644
index f8f5906c072..00000000000
--- a/chromium/components/optimization_guide/core/decision_tree_prediction_model.cc
+++ /dev/null
@@ -1,237 +0,0 @@
-// Copyright 2020 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.
-
-#include "components/optimization_guide/core/decision_tree_prediction_model.h"
-
-#include <utility>
-
-namespace optimization_guide {
-
-DecisionTreePredictionModel::DecisionTreePredictionModel(
- const proto::PredictionModel& prediction_model)
- : PredictionModel(prediction_model) {}
-
-DecisionTreePredictionModel::~DecisionTreePredictionModel() = default;
-
-bool DecisionTreePredictionModel::ValidatePredictionModel() const {
- // Only the top-level ensemble or decision tree must have a threshold. Any
- // submodels of an ensemble will have model weights but no threshold.
- if (!model_.has_threshold())
- return false;
- return ValidateModel(model_);
-}
-
-bool DecisionTreePredictionModel::ValidateModel(
- const proto::Model& model) const {
- if (model.has_ensemble()) {
- return ValidateEnsembleModel(model.ensemble());
- }
- if (model.has_decision_tree()) {
- return ValidateDecisionTree(model.decision_tree());
- }
- return false;
-}
-
-bool DecisionTreePredictionModel::ValidateEnsembleModel(
- const proto::Ensemble& ensemble) const {
- if (ensemble.members_size() == 0)
- return false;
-
- for (const auto& member : ensemble.members()) {
- if (!ValidateModel(member.submodel())) {
- return false;
- }
- }
- return true;
-}
-
-bool DecisionTreePredictionModel::ValidateDecisionTree(
- const proto::DecisionTree& tree) const {
- if (tree.nodes_size() == 0)
- return false;
- return ValidateTreeNode(tree, tree.nodes(0), 0);
-}
-
-bool DecisionTreePredictionModel::ValidateLeaf(const proto::Leaf& leaf) const {
- return leaf.has_vector() && leaf.vector().value_size() == 1 &&
- leaf.vector().value(0).has_double_value();
-}
-
-bool DecisionTreePredictionModel::ValidateInequalityTest(
- const proto::InequalityTest& inequality_test) const {
- if (!inequality_test.has_threshold())
- return false;
- if (!inequality_test.threshold().has_float_value())
- return false;
- if (!inequality_test.has_feature_id())
- return false;
- if (!inequality_test.feature_id().has_id())
- return false;
- if (!inequality_test.has_type())
- return false;
- return true;
-}
-
-bool DecisionTreePredictionModel::ValidateTreeNode(
- const proto::DecisionTree& tree,
- const proto::TreeNode& node,
- int node_index) const {
- if (node.has_leaf())
- return ValidateLeaf(node.leaf());
-
- if (!node.has_binary_node())
- return false;
-
- proto::BinaryNode binary_node = node.binary_node();
- if (!binary_node.has_inequality_left_child_test())
- return false;
-
- if (!ValidateInequalityTest(binary_node.inequality_left_child_test()))
- return false;
-
- if (!binary_node.left_child_id().has_value())
- return false;
- if (!binary_node.right_child_id().has_value())
- return false;
-
- if (binary_node.left_child_id().value() >= tree.nodes_size())
- return false;
- if (binary_node.right_child_id().value() >= tree.nodes_size())
- return false;
-
- // Assure that no parent has an child index less than itself in order to
- // prevent loops.
- if (node_index >= binary_node.left_child_id().value())
- return false;
- if (node_index >= binary_node.right_child_id().value())
- return false;
-
- if (!ValidateTreeNode(tree, tree.nodes(binary_node.left_child_id().value()),
- binary_node.left_child_id().value())) {
- return false;
- }
- if (!ValidateTreeNode(tree, tree.nodes(binary_node.right_child_id().value()),
- binary_node.right_child_id().value())) {
- return false;
- }
- return true;
-}
-
-OptimizationTargetDecision DecisionTreePredictionModel::Predict(
- const base::flat_map<std::string, float>& model_features,
- double* prediction_score) {
- *prediction_score = 0.0;
- // TODO(mcrouse): Add metrics to record if the model evaluation fails.
- if (!EvaluateModel(model_, model_features, prediction_score))
- return OptimizationTargetDecision::kUnknown;
- if (*prediction_score > model_.threshold().value())
- return OptimizationTargetDecision::kPageLoadMatches;
- return OptimizationTargetDecision::kPageLoadDoesNotMatch;
-}
-
-bool DecisionTreePredictionModel::TraverseTree(
- const proto::DecisionTree& tree,
- const proto::TreeNode& node,
- const base::flat_map<std::string, float>& model_features,
- double* result) {
- if (node.has_leaf()) {
- *result = node.leaf().vector().value(0).double_value();
- return true;
- }
-
- proto::BinaryNode binary_node = node.binary_node();
- float threshold =
- binary_node.inequality_left_child_test().threshold().float_value();
- std::string feature_name =
- binary_node.inequality_left_child_test().feature_id().id().value();
- auto it = model_features.find(feature_name);
- if (it == model_features.end())
- return false;
- switch (binary_node.inequality_left_child_test().type()) {
- case proto::InequalityTest::LESS_OR_EQUAL:
- if (it->second <= threshold)
- return TraverseTree(tree,
- tree.nodes(binary_node.left_child_id().value()),
- model_features, result);
- return TraverseTree(tree,
- tree.nodes(binary_node.right_child_id().value()),
- model_features, result);
- case proto::InequalityTest::LESS_THAN:
- if (it->second < threshold)
- return TraverseTree(tree,
- tree.nodes(binary_node.left_child_id().value()),
- model_features, result);
- return TraverseTree(tree,
- tree.nodes(binary_node.right_child_id().value()),
- model_features, result);
- case proto::InequalityTest::GREATER_OR_EQUAL:
- if (it->second >= threshold)
- return TraverseTree(tree,
- tree.nodes(binary_node.left_child_id().value()),
- model_features, result);
- return TraverseTree(tree,
- tree.nodes(binary_node.right_child_id().value()),
- model_features, result);
- case proto::InequalityTest::GREATER_THAN:
- if (it->second > threshold)
- return TraverseTree(tree,
- tree.nodes(binary_node.left_child_id().value()),
- model_features, result);
- return TraverseTree(tree,
- tree.nodes(binary_node.right_child_id().value()),
- model_features, result);
- default:
- return false;
- }
-}
-
-bool DecisionTreePredictionModel::EvaluateDecisionTree(
- const proto::DecisionTree& tree,
- const base::flat_map<std::string, float>& model_features,
- double* result) {
- if (TraverseTree(tree, tree.nodes(0), model_features, result)) {
- *result *= tree.weight();
- return true;
- }
- return false;
-}
-
-bool DecisionTreePredictionModel::EvaluateEnsembleModel(
- const proto::Ensemble& ensemble,
- const base::flat_map<std::string, float>& model_features,
- double* result) {
- if (ensemble.members_size() == 0)
- return false;
-
- double score = 0.0;
- for (const auto& member : ensemble.members()) {
- if (!EvaluateModel(member.submodel(), model_features, &score)) {
- *result = 0.0;
- return false;
- }
-
- *result += score;
- }
- *result = *result / ensemble.members_size();
- return true;
-}
-
-bool DecisionTreePredictionModel::EvaluateModel(
- const proto::Model& model,
- const base::flat_map<std::string, float>& model_features,
- double* result) {
- DCHECK(result);
- // Clear the result value.
- *result = 0.0;
-
- if (model.has_ensemble()) {
- return EvaluateEnsembleModel(model.ensemble(), model_features, result);
- }
- if (model.has_decision_tree()) {
- return EvaluateDecisionTree(model.decision_tree(), model_features, result);
- }
- return false;
-}
-
-} // namespace optimization_guide
diff --git a/chromium/components/optimization_guide/core/decision_tree_prediction_model.h b/chromium/components/optimization_guide/core/decision_tree_prediction_model.h
deleted file mode 100644
index a31ef93d1cd..00000000000
--- a/chromium/components/optimization_guide/core/decision_tree_prediction_model.h
+++ /dev/null
@@ -1,97 +0,0 @@
-// Copyright 2020 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.
-
-#ifndef COMPONENTS_OPTIMIZATION_GUIDE_CORE_DECISION_TREE_PREDICTION_MODEL_H_
-#define COMPONENTS_OPTIMIZATION_GUIDE_CORE_DECISION_TREE_PREDICTION_MODEL_H_
-
-#include <memory>
-#include <string>
-
-#include "base/containers/flat_map.h"
-#include "components/optimization_guide/core/prediction_model.h"
-#include "components/optimization_guide/proto/models.pb.h"
-
-namespace optimization_guide {
-
-// A concrete PredictionModel capable of evaluating the decision tree model type
-// supported by the optimization guide.
-class DecisionTreePredictionModel : public PredictionModel {
- public:
- explicit DecisionTreePredictionModel(
- const proto::PredictionModel& prediction_model);
-
- DecisionTreePredictionModel(const DecisionTreePredictionModel&) = delete;
- DecisionTreePredictionModel& operator=(const DecisionTreePredictionModel&) =
- delete;
-
- ~DecisionTreePredictionModel() override;
-
- // PredictionModel implementation:
- OptimizationTargetDecision Predict(
- const base::flat_map<std::string, float>& model_features,
- double* prediction_score) override;
-
- private:
- // Evaluates the provided model, either an ensemble or decision tree model,
- // with the |model_features| and stores the output in |result|. Returns false
- // if evaluation fails.
- bool EvaluateModel(const proto::Model& model,
- const base::flat_map<std::string, float>& model_features,
- double* result);
-
- // Evaluates the decision tree model with the |model_features| and
- // stores the output in |result|. Returns false if the evaluation fails.
- bool EvaluateDecisionTree(
- const proto::DecisionTree& tree,
- const base::flat_map<std::string, float>& model_features,
- double* result);
-
- // Evaluates an ensemble model with the |model_features| and
- // stores the output in |result|. Returns false if the evaluation fails.
- bool EvaluateEnsembleModel(
- const proto::Ensemble& ensemble,
- const base::flat_map<std::string, float>& model_features,
- double* result);
-
- // Performs a depth first traversal the |tree| based on |model_features|
- // and stores the value of the leaf in |result|. Returns false if the
- // traversal or node evaluation fails.
- bool TraverseTree(const proto::DecisionTree& tree,
- const proto::TreeNode& node,
- const base::flat_map<std::string, float>& model_features,
- double* result);
-
- // PredictionModel implementation:
- bool ValidatePredictionModel() const override;
-
- // Validates a model or submodel of an ensemble. Returns
- // false if the model is invalid.
- bool ValidateModel(const proto::Model& model) const;
-
- // Validates an ensemble model. Returns false if the ensemble
- // if invalid.
- bool ValidateEnsembleModel(const proto::Ensemble& ensemble) const;
-
- // Validates a decision tree model. Returns false if the
- // decision tree model is invalid.
- bool ValidateDecisionTree(const proto::DecisionTree& tree) const;
-
- // Validates a leaf. Returns false if the leaf is invalid.
- bool ValidateLeaf(const proto::Leaf& leaf) const;
-
- // Validates an inequality test. Returns false if the
- // inequality test is invalid.
- bool ValidateInequalityTest(
- const proto::InequalityTest& inequality_test) const;
-
- // Validates each node of a decision tree by traversing every
- // node of the |tree|. Returns false if any part of the tree is invalid.
- bool ValidateTreeNode(const proto::DecisionTree& tree,
- const proto::TreeNode& node,
- int node_index) const;
-};
-
-} // namespace optimization_guide
-
-#endif // COMPONENTS_OPTIMIZATION_GUIDE_CORE_DECISION_TREE_PREDICTION_MODEL_H_
diff --git a/chromium/components/optimization_guide/core/decision_tree_prediction_model_unittest.cc b/chromium/components/optimization_guide/core/decision_tree_prediction_model_unittest.cc
deleted file mode 100644
index 4a479d11038..00000000000
--- a/chromium/components/optimization_guide/core/decision_tree_prediction_model_unittest.cc
+++ /dev/null
@@ -1,434 +0,0 @@
-// Copyright 2020 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.
-
-#include "components/optimization_guide/core/decision_tree_prediction_model.h"
-
-#include <memory>
-#include <utility>
-
-#include "base/containers/flat_map.h"
-#include "base/containers/flat_set.h"
-#include "components/optimization_guide/core/prediction_model.h"
-#include "components/optimization_guide/proto/models.pb.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace optimization_guide {
-
-proto::PredictionModel GetValidDecisionTreePredictionModel() {
- proto::PredictionModel prediction_model;
- prediction_model.mutable_model()->mutable_threshold()->set_value(5.0);
-
- proto::DecisionTree decision_tree_model = proto::DecisionTree();
- decision_tree_model.set_weight(2.0);
-
- proto::TreeNode* tree_node = decision_tree_model.add_nodes();
- tree_node->mutable_node_id()->set_value(0);
- tree_node->mutable_binary_node()->mutable_left_child_id()->set_value(1);
- tree_node->mutable_binary_node()->mutable_right_child_id()->set_value(2);
- tree_node->mutable_binary_node()
- ->mutable_inequality_left_child_test()
- ->mutable_feature_id()
- ->mutable_id()
- ->set_value("agg1");
- tree_node->mutable_binary_node()
- ->mutable_inequality_left_child_test()
- ->set_type(proto::InequalityTest::LESS_OR_EQUAL);
- tree_node->mutable_binary_node()
- ->mutable_inequality_left_child_test()
- ->mutable_threshold()
- ->set_float_value(1.0);
-
- tree_node = decision_tree_model.add_nodes();
- tree_node->mutable_node_id()->set_value(1);
- tree_node->mutable_leaf()->mutable_vector()->add_value()->set_double_value(
- 2.);
-
- tree_node = decision_tree_model.add_nodes();
- tree_node->mutable_node_id()->set_value(2);
- tree_node->mutable_leaf()->mutable_vector()->add_value()->set_double_value(
- 4.);
-
- *prediction_model.mutable_model()->mutable_decision_tree() =
- decision_tree_model;
- return prediction_model;
-}
-
-proto::PredictionModel GetValidEnsemblePredictionModel() {
- proto::PredictionModel prediction_model;
- prediction_model.mutable_model()->mutable_threshold()->set_value(5.0);
- proto::Ensemble ensemble = proto::Ensemble();
- *ensemble.add_members()->mutable_submodel() =
- *GetValidDecisionTreePredictionModel().mutable_model();
-
- *ensemble.add_members()->mutable_submodel() =
- *GetValidDecisionTreePredictionModel().mutable_model();
-
- *prediction_model.mutable_model()->mutable_ensemble() = ensemble;
- return prediction_model;
-}
-
-TEST(DecisionTreePredictionModel, ValidDecisionTreeModel) {
- proto::PredictionModel prediction_model =
- GetValidDecisionTreePredictionModel();
-
- proto::ModelInfo* model_info = prediction_model.mutable_model_info();
- model_info->set_version(1);
- model_info->add_supported_model_types(
- proto::ModelType::MODEL_TYPE_DECISION_TREE);
- model_info->add_supported_host_model_features("agg1");
-
- std::unique_ptr<PredictionModel> model =
- PredictionModel::Create(prediction_model);
- EXPECT_TRUE(model);
-
- double prediction_score;
- EXPECT_EQ(OptimizationTargetDecision::kPageLoadDoesNotMatch,
- model->Predict({{"agg1", 1.0}}, &prediction_score));
- EXPECT_EQ(4., prediction_score);
- EXPECT_EQ(OptimizationTargetDecision::kPageLoadMatches,
- model->Predict({{"agg1", 2.0}}, &prediction_score));
- EXPECT_EQ(8., prediction_score);
-}
-
-TEST(DecisionTreePredictionModel, InequalityLessThan) {
- proto::PredictionModel prediction_model =
- GetValidDecisionTreePredictionModel();
-
- prediction_model.mutable_model()
- ->mutable_decision_tree()
- ->mutable_nodes(0)
- ->mutable_binary_node()
- ->mutable_inequality_left_child_test()
- ->set_type(proto::InequalityTest::LESS_THAN);
-
- proto::ModelInfo* model_info = prediction_model.mutable_model_info();
- model_info->set_version(1);
- model_info->add_supported_model_types(
- proto::ModelType::MODEL_TYPE_DECISION_TREE);
- model_info->add_supported_host_model_features("agg1");
-
- std::unique_ptr<PredictionModel> model =
- PredictionModel::Create(std::move(prediction_model));
- EXPECT_TRUE(model);
-
- double prediction_score;
- EXPECT_EQ(OptimizationTargetDecision::kPageLoadDoesNotMatch,
- model->Predict({{"agg1", 0.5}}, &prediction_score));
- EXPECT_EQ(4., prediction_score);
- EXPECT_EQ(OptimizationTargetDecision::kPageLoadMatches,
- model->Predict({{"agg1", 2.0}}, &prediction_score));
- EXPECT_EQ(8., prediction_score);
-}
-
-TEST(DecisionTreePredictionModel, InequalityGreaterOrEqual) {
- proto::PredictionModel prediction_model =
- GetValidDecisionTreePredictionModel();
-
- prediction_model.mutable_model()
- ->mutable_decision_tree()
- ->mutable_nodes(0)
- ->mutable_binary_node()
- ->mutable_inequality_left_child_test()
- ->set_type(proto::InequalityTest::GREATER_OR_EQUAL);
-
- proto::ModelInfo* model_info = prediction_model.mutable_model_info();
- model_info->set_version(1);
- model_info->add_supported_model_types(
- proto::ModelType::MODEL_TYPE_DECISION_TREE);
- model_info->add_supported_host_model_features("agg1");
-
- std::unique_ptr<PredictionModel> model =
- PredictionModel::Create(prediction_model);
- EXPECT_TRUE(model);
-
- double prediction_score;
- EXPECT_EQ(OptimizationTargetDecision::kPageLoadMatches,
- model->Predict({{"agg1", 0.5}}, &prediction_score));
- EXPECT_EQ(8., prediction_score);
- EXPECT_EQ(OptimizationTargetDecision::kPageLoadDoesNotMatch,
- model->Predict({{"agg1", 1.0}}, &prediction_score));
- EXPECT_EQ(4., prediction_score);
-}
-
-TEST(DecisionTreePredictionModel, InequalityGreaterThan) {
- proto::PredictionModel prediction_model =
- GetValidDecisionTreePredictionModel();
-
- prediction_model.mutable_model()
- ->mutable_decision_tree()
- ->mutable_nodes(0)
- ->mutable_binary_node()
- ->mutable_inequality_left_child_test()
- ->set_type(proto::InequalityTest::GREATER_THAN);
-
- proto::ModelInfo* model_info = prediction_model.mutable_model_info();
- model_info->set_version(1);
- model_info->add_supported_model_types(
- proto::ModelType::MODEL_TYPE_DECISION_TREE);
- model_info->add_supported_host_model_features("agg1");
-
- std::unique_ptr<PredictionModel> model =
- PredictionModel::Create(std::move(prediction_model));
- EXPECT_TRUE(model);
-
- double prediction_score;
- EXPECT_EQ(OptimizationTargetDecision::kPageLoadMatches,
- model->Predict({{"agg1", 0.5}}, &prediction_score));
- EXPECT_EQ(8., prediction_score);
- EXPECT_EQ(OptimizationTargetDecision::kPageLoadDoesNotMatch,
- model->Predict({{"agg1", 2.0}}, &prediction_score));
- EXPECT_EQ(4., prediction_score);
-}
-
-TEST(DecisionTreePredictionModel, MissingInequalityTest) {
- proto::PredictionModel prediction_model =
- GetValidDecisionTreePredictionModel();
-
- prediction_model.mutable_model()
- ->mutable_decision_tree()
- ->mutable_nodes(0)
- ->mutable_binary_node()
- ->mutable_inequality_left_child_test()
- ->Clear();
-
- proto::ModelInfo* model_info = prediction_model.mutable_model_info();
- model_info->set_version(1);
- model_info->add_supported_model_types(
- proto::ModelType::MODEL_TYPE_DECISION_TREE);
- model_info->add_supported_host_model_features("agg1");
-
- std::unique_ptr<PredictionModel> model =
- PredictionModel::Create(std::move(prediction_model));
- EXPECT_FALSE(model);
-}
-
-TEST(DecisionTreePredictionModel, NoDecisionTreeThreshold) {
- proto::PredictionModel prediction_model =
- GetValidDecisionTreePredictionModel();
-
- prediction_model.mutable_model()->clear_threshold();
-
- proto::ModelInfo* model_info = prediction_model.mutable_model_info();
- model_info->set_version(1);
- model_info->add_supported_model_types(
- proto::ModelType::MODEL_TYPE_DECISION_TREE);
- model_info->add_supported_host_model_features("agg1");
-
- std::unique_ptr<PredictionModel> model =
- PredictionModel::Create(prediction_model);
- EXPECT_FALSE(model);
-}
-
-TEST(DecisionTreePredictionModel, EmptyTree) {
- proto::PredictionModel prediction_model =
- GetValidDecisionTreePredictionModel();
-
- prediction_model.mutable_model()->mutable_decision_tree()->clear_nodes();
-
- proto::ModelInfo* model_info = prediction_model.mutable_model_info();
- model_info->set_version(1);
- model_info->add_supported_model_types(
- proto::ModelType::MODEL_TYPE_DECISION_TREE);
- model_info->add_supported_host_model_features("agg1");
-
- std::unique_ptr<PredictionModel> model =
- PredictionModel::Create(std::move(prediction_model));
- EXPECT_FALSE(model);
-}
-
-TEST(DecisionTreePredictionModel, ModelFeatureNotInFeatureMap) {
- proto::PredictionModel prediction_model =
- GetValidDecisionTreePredictionModel();
-
- prediction_model.mutable_model()->mutable_decision_tree()->clear_nodes();
-
- proto::ModelInfo* model_info = prediction_model.mutable_model_info();
- model_info->set_version(1);
- model_info->add_supported_model_types(
- proto::ModelType::MODEL_TYPE_DECISION_TREE);
- model_info->add_supported_host_model_features("agg1");
-
- std::unique_ptr<PredictionModel> model =
- PredictionModel::Create(prediction_model);
- EXPECT_FALSE(model);
-}
-
-TEST(DecisionTreePredictionModel, DecisionTreeMissingLeaf) {
- proto::PredictionModel prediction_model =
- GetValidDecisionTreePredictionModel();
-
- prediction_model.mutable_model()
- ->mutable_decision_tree()
- ->mutable_nodes(1)
- ->mutable_leaf()
- ->Clear();
-
- proto::ModelInfo* model_info = prediction_model.mutable_model_info();
- model_info->set_version(1);
- model_info->add_supported_model_types(
- proto::ModelType::MODEL_TYPE_DECISION_TREE);
- model_info->add_supported_host_model_features("agg1");
-
- std::unique_ptr<PredictionModel> model =
- PredictionModel::Create(prediction_model);
- EXPECT_FALSE(model);
-}
-
-TEST(DecisionTreePredictionModel, DecisionTreeLeftChildIndexInvalid) {
- proto::PredictionModel prediction_model =
- GetValidDecisionTreePredictionModel();
-
- prediction_model.mutable_model()
- ->mutable_decision_tree()
- ->mutable_nodes(0)
- ->mutable_binary_node()
- ->mutable_left_child_id()
- ->set_value(3);
-
- proto::ModelInfo* model_info = prediction_model.mutable_model_info();
- model_info->set_version(1);
- model_info->add_supported_model_types(
- proto::ModelType::MODEL_TYPE_DECISION_TREE);
- model_info->add_supported_host_model_features("agg1");
-
- std::unique_ptr<PredictionModel> model =
- PredictionModel::Create(std::move(prediction_model));
- EXPECT_FALSE(model);
-}
-
-TEST(DecisionTreePredictionModel, DecisionTreeRightChildIndexInvalid) {
- proto::PredictionModel prediction_model =
- GetValidDecisionTreePredictionModel();
-
- prediction_model.mutable_model()
- ->mutable_decision_tree()
- ->mutable_nodes(0)
- ->mutable_binary_node()
- ->mutable_right_child_id()
- ->set_value(3);
-
- proto::ModelInfo* model_info = prediction_model.mutable_model_info();
- model_info->set_version(1);
- model_info->add_supported_model_types(
- proto::ModelType::MODEL_TYPE_DECISION_TREE);
- model_info->add_supported_host_model_features("agg1");
-
- std::unique_ptr<PredictionModel> model =
- PredictionModel::Create(prediction_model);
- EXPECT_FALSE(model);
-}
-
-TEST(DecisionTreePredictionModel, DecisionTreeWithLoopOnLeftChild) {
- proto::PredictionModel prediction_model =
- GetValidDecisionTreePredictionModel();
-
- proto::TreeNode* tree_node =
- prediction_model.mutable_model()->mutable_decision_tree()->mutable_nodes(
- 1);
-
- tree_node->mutable_node_id()->set_value(0);
- tree_node->mutable_binary_node()
- ->mutable_inequality_left_child_test()
- ->mutable_feature_id()
- ->mutable_id()
- ->set_value("agg1");
- tree_node->mutable_binary_node()
- ->mutable_inequality_left_child_test()
- ->set_type(proto::InequalityTest::LESS_OR_EQUAL);
- tree_node->mutable_binary_node()
- ->mutable_inequality_left_child_test()
- ->mutable_threshold()
- ->set_float_value(1.0);
-
- tree_node->mutable_binary_node()->mutable_left_child_id()->set_value(0);
- tree_node->mutable_binary_node()->mutable_right_child_id()->set_value(2);
-
- proto::ModelInfo* model_info = prediction_model.mutable_model_info();
- model_info->set_version(1);
- model_info->add_supported_model_types(
- proto::ModelType::MODEL_TYPE_DECISION_TREE);
- model_info->add_supported_host_model_features("agg1");
-
- std::unique_ptr<PredictionModel> model =
- PredictionModel::Create(prediction_model);
- EXPECT_FALSE(model);
-}
-
-TEST(DecisionTreePredictionModel, DecisionTreeWithLoopOnRightChild) {
- proto::PredictionModel prediction_model =
- GetValidDecisionTreePredictionModel();
-
- proto::TreeNode* tree_node =
- prediction_model.mutable_model()->mutable_decision_tree()->mutable_nodes(
- 1);
-
- tree_node->mutable_node_id()->set_value(0);
- tree_node->mutable_binary_node()
- ->mutable_inequality_left_child_test()
- ->mutable_feature_id()
- ->mutable_id()
- ->set_value("agg1");
- tree_node->mutable_binary_node()
- ->mutable_inequality_left_child_test()
- ->set_type(proto::InequalityTest::LESS_OR_EQUAL);
- tree_node->mutable_binary_node()
- ->mutable_inequality_left_child_test()
- ->mutable_threshold()
- ->set_float_value(1.0);
-
- tree_node->mutable_binary_node()->mutable_left_child_id()->set_value(2);
- tree_node->mutable_binary_node()->mutable_right_child_id()->set_value(0);
-
- proto::ModelInfo* model_info = prediction_model.mutable_model_info();
- model_info->set_version(1);
- model_info->add_supported_model_types(
- proto::ModelType::MODEL_TYPE_DECISION_TREE);
- model_info->add_supported_host_model_features("agg1");
-
- std::unique_ptr<PredictionModel> model =
- PredictionModel::Create(prediction_model);
- EXPECT_FALSE(model);
-}
-
-TEST(DecisionTreePredictionModel, ValidEnsembleModel) {
- proto::PredictionModel prediction_model = GetValidEnsemblePredictionModel();
-
- proto::ModelInfo* model_info = prediction_model.mutable_model_info();
- model_info->set_version(1);
- model_info->add_supported_model_types(
- proto::ModelType::MODEL_TYPE_DECISION_TREE);
- model_info->add_supported_host_model_features("agg1");
-
- std::unique_ptr<PredictionModel> model =
- PredictionModel::Create(prediction_model);
- EXPECT_TRUE(model);
-
- double prediction_score;
- EXPECT_EQ(OptimizationTargetDecision::kPageLoadDoesNotMatch,
- model->Predict({{"agg1", 1.0}}, &prediction_score));
- EXPECT_EQ(4., prediction_score);
- EXPECT_EQ(OptimizationTargetDecision::kPageLoadMatches,
- model->Predict({{"agg1", 2.0}}, &prediction_score));
- EXPECT_EQ(8., prediction_score);
-}
-
-TEST(DecisionTreePredictionModel, EnsembleWithNoMembers) {
- proto::PredictionModel prediction_model = GetValidEnsemblePredictionModel();
- prediction_model.mutable_model()
- ->mutable_ensemble()
- ->mutable_members()
- ->Clear();
-
- proto::ModelInfo* model_info = prediction_model.mutable_model_info();
- model_info->set_version(1);
- model_info->add_supported_model_types(
- proto::ModelType::MODEL_TYPE_DECISION_TREE);
- model_info->add_supported_host_model_features("agg1");
-
- std::unique_ptr<PredictionModel> model =
- PredictionModel::Create(prediction_model);
- EXPECT_FALSE(model);
-}
-
-} // namespace optimization_guide
diff --git a/chromium/components/optimization_guide/core/entity_annotator_native_library.cc b/chromium/components/optimization_guide/core/entity_annotator_native_library.cc
new file mode 100644
index 00000000000..1382ef228fc
--- /dev/null
+++ b/chromium/components/optimization_guide/core/entity_annotator_native_library.cc
@@ -0,0 +1,445 @@
+// Copyright 2022 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.
+
+#include "components/optimization_guide/core/entity_annotator_native_library.h"
+
+#include "base/base_paths.h"
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/path_service.h"
+#include "build/build_config.h"
+#include "components/optimization_guide/core/model_util.h"
+#include "components/optimization_guide/core/optimization_guide_util.h"
+#include "components/optimization_guide/proto/page_entities_model_metadata.pb.h"
+
+#if BUILDFLAG(IS_MAC)
+#include "base/mac/bundle_locations.h"
+#include "base/mac/foundation_util.h"
+#endif
+
+// IMPORTANT: All functions in this file that call dlsym()'ed
+// functions should be annotated with DISABLE_CFI_ICALL.
+
+namespace optimization_guide {
+
+namespace {
+
+const char kModelMetadataBaseName[] = "model_metadata.pb";
+const char kWordEmbeddingsBaseName[] = "word_embeddings";
+const char kNameTableBaseName[] = "entities_names";
+const char kMetadataTableBaseName[] = "entities_metadata";
+const char kNameFilterBaseName[] = "entities_names_filter";
+const char kPrefixFilterBaseName[] = "entities_prefixes_filter";
+
+// Sets |field_to_set| with the full file path of |base_name|'s entry in
+// |base_to_full_file_path|. Returns whether |base_name| is in
+// |base_to_full_file_path|.
+absl::optional<std::string> GetFilePathFromMap(
+ const std::string& base_name,
+ const base::flat_map<std::string, base::FilePath>& base_to_full_file_path) {
+ auto it = base_to_full_file_path.find(base_name);
+ return it == base_to_full_file_path.end()
+ ? absl::nullopt
+ : absl::make_optional(FilePathToString(it->second));
+}
+
+// Returns the expected base name for |slice|. Will be of the form
+// |slice|-|base_name|.
+std::string GetSliceBaseName(const std::string& slice,
+ const std::string& base_name) {
+ return slice + "-" + base_name;
+}
+
+} // namespace
+
+EntityAnnotatorNativeLibrary::EntityAnnotatorNativeLibrary(
+ base::NativeLibrary native_library)
+ : native_library_(std::move(native_library)) {
+ LoadFunctions();
+}
+EntityAnnotatorNativeLibrary::~EntityAnnotatorNativeLibrary() = default;
+
+// static
+std::unique_ptr<EntityAnnotatorNativeLibrary>
+EntityAnnotatorNativeLibrary::Create() {
+ base::FilePath base_dir;
+#if BUILDFLAG(IS_MAC)
+ if (base::mac::AmIBundled()) {
+ base_dir = base::mac::FrameworkBundlePath().Append("Libraries");
+ } else {
+#endif
+ if (!base::PathService::Get(base::DIR_MODULE, &base_dir)) {
+ LOG(ERROR) << "Error getting app dir";
+ return nullptr;
+ }
+#if BUILDFLAG(IS_MAC)
+ }
+#endif
+
+ base::NativeLibraryLoadError error;
+ base::NativeLibrary native_library = base::LoadNativeLibrary(
+ base_dir.AppendASCII(
+ base::GetNativeLibraryName("optimization_guide_internal")),
+ &error);
+ if (!native_library) {
+ LOG(ERROR) << "Failed to initialize optimization guide internal: "
+ << error.ToString();
+ return nullptr;
+ }
+
+ std::unique_ptr<EntityAnnotatorNativeLibrary>
+ entity_annotator_native_library =
+ base::WrapUnique<EntityAnnotatorNativeLibrary>(
+ new EntityAnnotatorNativeLibrary(std::move(native_library)));
+ if (entity_annotator_native_library->IsValid()) {
+ return entity_annotator_native_library;
+ }
+ LOG(ERROR) << "Could not find all required functions for optimization guide "
+ "internal library";
+ return nullptr;
+}
+
+DISABLE_CFI_ICALL
+void EntityAnnotatorNativeLibrary::LoadFunctions() {
+ get_max_supported_feature_flag_func_ =
+ reinterpret_cast<GetMaxSupportedFeatureFlagFunc>(
+ base::GetFunctionPointerFromNativeLibrary(
+ native_library_,
+ "OptimizationGuideEntityAnnotatorGetMaxSupportedFeatureFlag"));
+
+ create_from_options_func_ = reinterpret_cast<CreateFromOptionsFunc>(
+ base::GetFunctionPointerFromNativeLibrary(
+ native_library_,
+ "OptimizationGuideEntityAnnotatorCreateFromOptions"));
+ get_creation_error_func_ = reinterpret_cast<GetCreationErrorFunc>(
+ base::GetFunctionPointerFromNativeLibrary(
+ native_library_, "OptimizationGuideEntityAnnotatorGetCreationError"));
+ delete_func_ =
+ reinterpret_cast<DeleteFunc>(base::GetFunctionPointerFromNativeLibrary(
+ native_library_, "OptimizationGuideEntityAnnotatorDelete"));
+
+ annotate_job_create_func_ = reinterpret_cast<AnnotateJobCreateFunc>(
+ base::GetFunctionPointerFromNativeLibrary(
+ native_library_,
+ "OptimizationGuideEntityAnnotatorAnnotateJobCreate"));
+ annotate_job_delete_func_ = reinterpret_cast<AnnotateJobDeleteFunc>(
+ base::GetFunctionPointerFromNativeLibrary(
+ native_library_,
+ "OptimizationGuideEntityAnnotatorAnnotateJobDelete"));
+ run_annotate_job_func_ = reinterpret_cast<RunAnnotateJobFunc>(
+ base::GetFunctionPointerFromNativeLibrary(
+ native_library_, "OptimizationGuideEntityAnnotatorRunAnnotateJob"));
+ annotate_get_output_metadata_at_index_func_ = reinterpret_cast<
+ AnnotateGetOutputMetadataAtIndexFunc>(
+ base::GetFunctionPointerFromNativeLibrary(
+ native_library_,
+ "OptimizationGuideEntityAnnotatorAnnotateGetOutputMetadataAtIndex"));
+ annotate_get_output_metadata_score_at_index_func_ =
+ reinterpret_cast<AnnotateGetOutputMetadataScoreAtIndexFunc>(
+ base::GetFunctionPointerFromNativeLibrary(
+ native_library_,
+ "OptimizationGuideEntityAnnotatorAnnotateGetOutputMetadataScoreAt"
+ "Index"));
+
+ entity_metadata_job_create_func_ =
+ reinterpret_cast<EntityMetadataJobCreateFunc>(
+ base::GetFunctionPointerFromNativeLibrary(
+ native_library_,
+ "OptimizationGuideEntityAnnotatorEntityMetadataJobCreate"));
+ entity_metadata_job_delete_func_ =
+ reinterpret_cast<EntityMetadataJobDeleteFunc>(
+ base::GetFunctionPointerFromNativeLibrary(
+ native_library_,
+ "OptimizationGuideEntityAnnotatorEntityMetadataJobDelete"));
+ run_entity_metadata_job_func_ = reinterpret_cast<RunEntityMetadataJobFunc>(
+ base::GetFunctionPointerFromNativeLibrary(
+ native_library_,
+ "OptimizationGuideEntityAnnotatorRunEntityMetadataJob"));
+
+ options_create_func_ = reinterpret_cast<OptionsCreateFunc>(
+ base::GetFunctionPointerFromNativeLibrary(
+ native_library_, "OptimizationGuideEntityAnnotatorOptionsCreate"));
+ options_set_model_file_path_func_ =
+ reinterpret_cast<OptionsSetModelFilePathFunc>(
+ base::GetFunctionPointerFromNativeLibrary(
+ native_library_,
+ "OptimizationGuideEntityAnnotatorOptionsSetModelFilePath"));
+ options_set_model_metadata_file_path_func_ = reinterpret_cast<
+ OptionsSetModelMetadataFilePathFunc>(
+ base::GetFunctionPointerFromNativeLibrary(
+ native_library_,
+ "OptimizationGuideEntityAnnotatorOptionsSetModelMetadataFilePath"));
+ options_set_word_embeddings_file_path_func_ = reinterpret_cast<
+ OptionsSetWordEmbeddingsFilePathFunc>(
+ base::GetFunctionPointerFromNativeLibrary(
+ native_library_,
+ "OptimizationGuideEntityAnnotatorOptionsSetWordEmbeddingsFilePath"));
+ options_add_model_slice_func_ = reinterpret_cast<OptionsAddModelSliceFunc>(
+ base::GetFunctionPointerFromNativeLibrary(
+ native_library_,
+ "OptimizationGuideEntityAnnotatorOptionsAddModelSlice"));
+ options_delete_func_ = reinterpret_cast<OptionsDeleteFunc>(
+ base::GetFunctionPointerFromNativeLibrary(
+ native_library_, "OptimizationGuideEntityAnnotatorOptionsDelete"));
+
+ entity_metadata_get_entity_id_func_ =
+ reinterpret_cast<EntityMetadataGetEntityIdFunc>(
+ base::GetFunctionPointerFromNativeLibrary(
+ native_library_, "OptimizationGuideEntityMetadataGetEntityID"));
+ entity_metadata_get_human_readable_name_func_ =
+ reinterpret_cast<EntityMetadataGetHumanReadableNameFunc>(
+ base::GetFunctionPointerFromNativeLibrary(
+ native_library_,
+ "OptimizationGuideEntityMetadataGetHumanReadableName"));
+ entity_metadata_get_human_readable_categories_count_func_ = reinterpret_cast<
+ EntityMetadataGetHumanReadableCategoriesCountFunc>(
+ base::GetFunctionPointerFromNativeLibrary(
+ native_library_,
+ "OptimizationGuideEntityMetadataGetHumanReadableCategoriesCount"));
+ entity_metadata_get_human_readable_category_name_at_index_func_ =
+ reinterpret_cast<EntityMetadataGetHumanReadableCategoryNameAtIndexFunc>(
+ base::GetFunctionPointerFromNativeLibrary(
+ native_library_,
+ "OptimizationGuideEntityMetadataGetHumanReadableCategoryNameAtInd"
+ "ex"));
+ entity_metadata_get_human_readable_category_score_at_index_func_ =
+ reinterpret_cast<EntityMetadataGetHumanReadableCategoryScoreAtIndexFunc>(
+ base::GetFunctionPointerFromNativeLibrary(
+ native_library_,
+ "OptimizationGuideEntityMetadataGetHumanReadableCategoryScoreAtIn"
+ "dex"));
+}
+
+DISABLE_CFI_ICALL
+bool EntityAnnotatorNativeLibrary::IsValid() const {
+ return get_max_supported_feature_flag_func_ && create_from_options_func_ &&
+ get_creation_error_func_ && delete_func_ &&
+ annotate_job_create_func_ && annotate_job_delete_func_ &&
+ run_annotate_job_func_ &&
+ annotate_get_output_metadata_at_index_func_ &&
+ annotate_get_output_metadata_score_at_index_func_ &&
+ entity_metadata_job_create_func_ && entity_metadata_job_delete_func_ &&
+ run_entity_metadata_job_func_ && options_create_func_ &&
+ options_set_model_file_path_func_ &&
+ options_set_model_metadata_file_path_func_ &&
+ options_set_word_embeddings_file_path_func_ &&
+ options_add_model_slice_func_ && options_delete_func_ &&
+ entity_metadata_get_entity_id_func_ &&
+ entity_metadata_get_human_readable_name_func_ &&
+ entity_metadata_get_human_readable_categories_count_func_ &&
+ entity_metadata_get_human_readable_category_name_at_index_func_ &&
+ entity_metadata_get_human_readable_category_score_at_index_func_;
+}
+
+DISABLE_CFI_ICALL
+int32_t EntityAnnotatorNativeLibrary::GetMaxSupportedFeatureFlag() {
+ DCHECK(IsValid());
+ if (!IsValid()) {
+ return -1;
+ }
+
+ return get_max_supported_feature_flag_func_();
+}
+
+DISABLE_CFI_ICALL
+void* EntityAnnotatorNativeLibrary::CreateEntityAnnotator(
+ const ModelInfo& model_info) {
+ DCHECK(IsValid());
+ if (!IsValid()) {
+ return nullptr;
+ }
+
+ void* options = options_create_func_();
+ if (!PopulateEntityAnnotatorOptionsFromModelInfo(options, model_info)) {
+ options_delete_func_(options);
+ return nullptr;
+ }
+
+ void* entity_annotator = create_from_options_func_(options);
+ const char* creation_error = get_creation_error_func_(entity_annotator);
+ if (creation_error) {
+ LOG(ERROR) << "Failed to create entity annotator: " << creation_error;
+ DeleteEntityAnnotator(entity_annotator);
+ entity_annotator = nullptr;
+ }
+ options_delete_func_(options);
+ return entity_annotator;
+}
+
+DISABLE_CFI_ICALL
+bool EntityAnnotatorNativeLibrary::PopulateEntityAnnotatorOptionsFromModelInfo(
+ void* options,
+ const ModelInfo& model_info) {
+ // We don't know which files are intended for use if we don't have model
+ // metadata, so return early.
+ if (!model_info.GetModelMetadata()) {
+ return false;
+ }
+
+ // // Validate the model metadata.
+ absl::optional<proto::PageEntitiesModelMetadata> entities_model_metadata =
+ ParsedAnyMetadata<proto::PageEntitiesModelMetadata>(
+ model_info.GetModelMetadata().value());
+ if (!entities_model_metadata) {
+ return false;
+ }
+ if (entities_model_metadata->slice_size() == 0) {
+ return false;
+ }
+
+ // Build the entity annotator options.
+ options_set_model_file_path_func_(
+ options, FilePathToString(model_info.GetModelFilePath()).c_str());
+
+ // Attach the additional files required by the model.
+ base::flat_map<std::string, base::FilePath> base_to_full_file_path;
+ for (const auto& model_file : model_info.GetAdditionalFiles()) {
+ base_to_full_file_path.insert(
+ {FilePathToString(model_file.BaseName()), model_file});
+ }
+ absl::optional<std::string> model_metadata_file_path =
+ GetFilePathFromMap(kModelMetadataBaseName, base_to_full_file_path);
+ if (!model_metadata_file_path) {
+ return false;
+ }
+ options_set_model_metadata_file_path_func_(options,
+ model_metadata_file_path->c_str());
+ absl::optional<std::string> word_embeddings_file_path =
+ GetFilePathFromMap(kWordEmbeddingsBaseName, base_to_full_file_path);
+ if (!word_embeddings_file_path) {
+ return false;
+ }
+ options_set_word_embeddings_file_path_func_(
+ options, word_embeddings_file_path->c_str());
+
+ base::flat_set<std::string> slices(entities_model_metadata->slice().begin(),
+ entities_model_metadata->slice().end());
+ for (const auto& slice_id : slices) {
+ absl::optional<std::string> name_filter_path =
+ GetFilePathFromMap(GetSliceBaseName(slice_id, kNameFilterBaseName),
+ base_to_full_file_path);
+ if (!name_filter_path) {
+ return false;
+ }
+ absl::optional<std::string> name_table_path = GetFilePathFromMap(
+ GetSliceBaseName(slice_id, kNameTableBaseName), base_to_full_file_path);
+ if (!name_table_path) {
+ return false;
+ }
+ absl::optional<std::string> prefix_filter_path =
+ GetFilePathFromMap(GetSliceBaseName(slice_id, kPrefixFilterBaseName),
+ base_to_full_file_path);
+ if (!prefix_filter_path) {
+ return false;
+ }
+ absl::optional<std::string> metadata_table_path =
+ GetFilePathFromMap(GetSliceBaseName(slice_id, kMetadataTableBaseName),
+ base_to_full_file_path);
+ if (!metadata_table_path) {
+ return false;
+ }
+ options_add_model_slice_func_(
+ options, slice_id.c_str(), name_filter_path->c_str(),
+ name_table_path->c_str(), prefix_filter_path->c_str(),
+ metadata_table_path->c_str());
+ }
+
+ return true;
+}
+
+DISABLE_CFI_ICALL
+void EntityAnnotatorNativeLibrary::DeleteEntityAnnotator(
+ void* entity_annotator) {
+ DCHECK(IsValid());
+ if (!IsValid()) {
+ return;
+ }
+
+ delete_func_(reinterpret_cast<void*>(entity_annotator));
+}
+
+DISABLE_CFI_ICALL
+absl::optional<std::vector<ScoredEntityMetadata>>
+EntityAnnotatorNativeLibrary::AnnotateText(void* annotator,
+ const std::string& text) {
+ DCHECK(IsValid());
+ if (!IsValid()) {
+ return absl::nullopt;
+ }
+
+ if (!annotator) {
+ return absl::nullopt;
+ }
+
+ void* job = annotate_job_create_func_(reinterpret_cast<void*>(annotator));
+ int32_t output_metadata_count = run_annotate_job_func_(job, text.c_str());
+ if (output_metadata_count <= 0) {
+ return absl::nullopt;
+ }
+ std::vector<ScoredEntityMetadata> scored_md;
+ scored_md.reserve(output_metadata_count);
+ for (int32_t i = 0; i < output_metadata_count; i++) {
+ ScoredEntityMetadata md;
+ md.score = annotate_get_output_metadata_score_at_index_func_(job, i);
+ md.metadata = GetEntityMetadataFromOptimizationGuideEntityMetadata(
+ annotate_get_output_metadata_at_index_func_(job, i));
+ scored_md.emplace_back(md);
+ }
+ annotate_job_delete_func_(job);
+ return scored_md;
+}
+
+DISABLE_CFI_ICALL
+absl::optional<EntityMetadata>
+EntityAnnotatorNativeLibrary::GetEntityMetadataForEntityId(
+ void* annotator,
+ const std::string& entity_id) {
+ DCHECK(IsValid());
+ if (!IsValid()) {
+ return absl::nullopt;
+ }
+ if (!annotator) {
+ return absl::nullopt;
+ }
+
+ void* job =
+ entity_metadata_job_create_func_(reinterpret_cast<void*>(annotator));
+ const void* entity_metadata =
+ run_entity_metadata_job_func_(job, entity_id.c_str());
+ if (!entity_metadata) {
+ return absl::nullopt;
+ }
+ EntityMetadata md =
+ GetEntityMetadataFromOptimizationGuideEntityMetadata(entity_metadata);
+ entity_metadata_job_delete_func_(job);
+ return md;
+}
+
+DISABLE_CFI_ICALL
+EntityMetadata EntityAnnotatorNativeLibrary::
+ GetEntityMetadataFromOptimizationGuideEntityMetadata(
+ const void* og_entity_metadata) {
+ EntityMetadata entity_metadata;
+ entity_metadata.entity_id =
+ entity_metadata_get_entity_id_func_(og_entity_metadata);
+ entity_metadata.human_readable_name =
+ entity_metadata_get_human_readable_name_func_(og_entity_metadata);
+
+ int32_t human_readable_categories_count =
+ entity_metadata_get_human_readable_categories_count_func_(
+ og_entity_metadata);
+ for (int32_t i = 0; i < human_readable_categories_count; i++) {
+ std::string category_name =
+ entity_metadata_get_human_readable_category_name_at_index_func_(
+ og_entity_metadata, i);
+ float category_score =
+ entity_metadata_get_human_readable_category_score_at_index_func_(
+ og_entity_metadata, i);
+ entity_metadata.human_readable_categories[category_name] = category_score;
+ }
+ return entity_metadata;
+}
+
+} // namespace optimization_guide \ No newline at end of file
diff --git a/chromium/components/optimization_guide/core/entity_annotator_native_library.h b/chromium/components/optimization_guide/core/entity_annotator_native_library.h
new file mode 100644
index 00000000000..a1fc4973269
--- /dev/null
+++ b/chromium/components/optimization_guide/core/entity_annotator_native_library.h
@@ -0,0 +1,143 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_OPTIMIZATION_GUIDE_CORE_ENTITY_ANNOTATOR_NATIVE_LIBRARY_H_
+#define COMPONENTS_OPTIMIZATION_GUIDE_CORE_ENTITY_ANNOTATOR_NATIVE_LIBRARY_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/native_library.h"
+#include "components/optimization_guide/core/entity_metadata.h"
+#include "components/optimization_guide/core/model_info.h"
+
+namespace optimization_guide {
+
+// Handles interactions with the native library that contains logic for the
+// entity annotator.
+class EntityAnnotatorNativeLibrary {
+ public:
+ // Creates an EntityAnnotatorNativeLibrary, which loads a native library and
+ // relevant functions required. Will return nullptr if fails.
+ static std::unique_ptr<EntityAnnotatorNativeLibrary> Create();
+
+ EntityAnnotatorNativeLibrary(const EntityAnnotatorNativeLibrary&) = delete;
+ EntityAnnotatorNativeLibrary& operator=(const EntityAnnotatorNativeLibrary&) =
+ delete;
+ ~EntityAnnotatorNativeLibrary();
+
+ // Returns whether this instance is valid (i.e. all necessary functions have
+ // been loaded.)
+ bool IsValid() const;
+
+ // Gets the max supported feature from this native library.
+ int32_t GetMaxSupportedFeatureFlag();
+
+ // Creates an entity annotator from |model_info|.
+ void* CreateEntityAnnotator(const ModelInfo& model_info);
+
+ // Deletes |entity_annotator|.
+ void DeleteEntityAnnotator(void* entity_annotator);
+
+ // Uses |annotator| to annotate entities present in |text|.
+ absl::optional<std::vector<ScoredEntityMetadata>> AnnotateText(
+ void* annotator,
+ const std::string& text);
+
+ // Returns entity metadata from |annotator| for |entity_id|.
+ absl::optional<EntityMetadata> GetEntityMetadataForEntityId(
+ void* annotator,
+ const std::string& entity_id);
+
+ private:
+ EntityAnnotatorNativeLibrary(base::NativeLibrary native_library);
+
+ // Loads the functions exposed by the native library.
+ void LoadFunctions();
+
+ // Populates |options| based on |model_info|. Returns false if |model_info|
+ // cannot construct a valid options object.
+ bool PopulateEntityAnnotatorOptionsFromModelInfo(void* options,
+ const ModelInfo& model_info);
+
+ // Returns an entity metadata from the C-API representation.
+ EntityMetadata GetEntityMetadataFromOptimizationGuideEntityMetadata(
+ const void* og_entity_metadata);
+
+ base::NativeLibrary native_library_;
+
+ // Functions exposed by native library.
+ using GetMaxSupportedFeatureFlagFunc = int32_t (*)();
+ GetMaxSupportedFeatureFlagFunc get_max_supported_feature_flag_func_ = nullptr;
+
+ using CreateFromOptionsFunc = void* (*)(const void*);
+ CreateFromOptionsFunc create_from_options_func_ = nullptr;
+ using GetCreationErrorFunc = const char* (*)(const void*);
+ GetCreationErrorFunc get_creation_error_func_ = nullptr;
+ using DeleteFunc = void (*)(void*);
+ DeleteFunc delete_func_ = nullptr;
+
+ using AnnotateJobCreateFunc = void* (*)(void*);
+ AnnotateJobCreateFunc annotate_job_create_func_ = nullptr;
+ using AnnotateJobDeleteFunc = void (*)(void*);
+ AnnotateJobDeleteFunc annotate_job_delete_func_ = nullptr;
+ using RunAnnotateJobFunc = int32_t (*)(void*, const char*);
+ RunAnnotateJobFunc run_annotate_job_func_ = nullptr;
+ using AnnotateGetOutputMetadataAtIndexFunc = const void* (*)(void*, int32_t);
+ AnnotateGetOutputMetadataAtIndexFunc
+ annotate_get_output_metadata_at_index_func_ = nullptr;
+ using AnnotateGetOutputMetadataScoreAtIndexFunc = float (*)(void*, int32_t);
+ AnnotateGetOutputMetadataScoreAtIndexFunc
+ annotate_get_output_metadata_score_at_index_func_ = nullptr;
+
+ using EntityMetadataJobCreateFunc = void* (*)(void*);
+ EntityMetadataJobCreateFunc entity_metadata_job_create_func_ = nullptr;
+ using EntityMetadataJobDeleteFunc = void (*)(void*);
+ EntityMetadataJobDeleteFunc entity_metadata_job_delete_func_ = nullptr;
+ using RunEntityMetadataJobFunc = const void* (*)(void*, const char*);
+ RunEntityMetadataJobFunc run_entity_metadata_job_func_ = nullptr;
+
+ using OptionsCreateFunc = void* (*)();
+ OptionsCreateFunc options_create_func_ = nullptr;
+ using OptionsSetModelFilePathFunc = void (*)(void*, const char*);
+ OptionsSetModelFilePathFunc options_set_model_file_path_func_ = nullptr;
+ using OptionsSetModelMetadataFilePathFunc = void (*)(void*, const char*);
+ OptionsSetModelMetadataFilePathFunc
+ options_set_model_metadata_file_path_func_ = nullptr;
+ using OptionsSetWordEmbeddingsFilePathFunc = void (*)(void*, const char*);
+ OptionsSetWordEmbeddingsFilePathFunc
+ options_set_word_embeddings_file_path_func_ = nullptr;
+ using OptionsAddModelSliceFunc = void (*)(void*,
+ const char*,
+ const char*,
+ const char*,
+ const char*,
+ const char*);
+ OptionsAddModelSliceFunc options_add_model_slice_func_ = nullptr;
+ using OptionsDeleteFunc = void (*)(void*);
+ OptionsDeleteFunc options_delete_func_ = nullptr;
+
+ using EntityMetadataGetEntityIdFunc = const char* (*)(const void*);
+ EntityMetadataGetEntityIdFunc entity_metadata_get_entity_id_func_ = nullptr;
+ using EntityMetadataGetHumanReadableNameFunc = const char* (*)(const void*);
+ EntityMetadataGetHumanReadableNameFunc
+ entity_metadata_get_human_readable_name_func_ = nullptr;
+ using EntityMetadataGetHumanReadableCategoriesCountFunc =
+ int32_t (*)(const void*);
+ EntityMetadataGetHumanReadableCategoriesCountFunc
+ entity_metadata_get_human_readable_categories_count_func_ = nullptr;
+ using EntityMetadataGetHumanReadableCategoryNameAtIndexFunc =
+ const char* (*)(const void*, int32_t);
+ EntityMetadataGetHumanReadableCategoryNameAtIndexFunc
+ entity_metadata_get_human_readable_category_name_at_index_func_ = nullptr;
+ using EntityMetadataGetHumanReadableCategoryScoreAtIndexFunc =
+ float (*)(const void*, int32_t);
+ EntityMetadataGetHumanReadableCategoryScoreAtIndexFunc
+ entity_metadata_get_human_readable_category_score_at_index_func_ =
+ nullptr;
+};
+
+} // namespace optimization_guide
+
+#endif // COMPONENTS_OPTIMIZATION_GUIDE_CORE_ENTITY_ANNOTATOR_NATIVE_LIBRARY_H_ \ No newline at end of file
diff --git a/chromium/components/optimization_guide/core/entity_annotator_native_library_unittest.cc b/chromium/components/optimization_guide/core/entity_annotator_native_library_unittest.cc
new file mode 100644
index 00000000000..3155e9bf10c
--- /dev/null
+++ b/chromium/components/optimization_guide/core/entity_annotator_native_library_unittest.cc
@@ -0,0 +1,22 @@
+// Copyright 2022 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.
+
+#include "components/optimization_guide/core/entity_annotator_native_library.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace optimization_guide {
+namespace {
+
+using EntityAnnotatorNativeLibraryTest = ::testing::Test;
+
+TEST_F(EntityAnnotatorNativeLibraryTest, CanCreateValidLibrary) {
+ std::unique_ptr<EntityAnnotatorNativeLibrary> lib =
+ EntityAnnotatorNativeLibrary::Create();
+ ASSERT_TRUE(lib);
+ EXPECT_TRUE(lib->IsValid());
+}
+
+} // namespace
+} // namespace optimization_guide
diff --git a/chromium/components/optimization_guide/core/entity_metadata.cc b/chromium/components/optimization_guide/core/entity_metadata.cc
index 6ca1930d1fd..2f8301579f3 100644
--- a/chromium/components/optimization_guide/core/entity_metadata.cc
+++ b/chromium/components/optimization_guide/core/entity_metadata.cc
@@ -4,6 +4,7 @@
#include "components/optimization_guide/core/entity_metadata.h"
+#include <ostream>
#include <string>
#include <vector>
diff --git a/chromium/components/optimization_guide/core/entity_metadata_provider.h b/chromium/components/optimization_guide/core/entity_metadata_provider.h
index 54ec81d7e01..14f7def09a8 100644
--- a/chromium/components/optimization_guide/core/entity_metadata_provider.h
+++ b/chromium/components/optimization_guide/core/entity_metadata_provider.h
@@ -6,6 +6,7 @@
#define COMPONENTS_OPTIMIZATION_GUIDE_CORE_ENTITY_METADATA_PROVIDER_H_
#include "components/optimization_guide/core/entity_metadata.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
namespace optimization_guide {
diff --git a/chromium/components/optimization_guide/core/hints_fetcher.cc b/chromium/components/optimization_guide/core/hints_fetcher.cc
index 3909ae5c3f8..7d58512dc42 100644
--- a/chromium/components/optimization_guide/core/hints_fetcher.cc
+++ b/chromium/components/optimization_guide/core/hints_fetcher.cc
@@ -11,9 +11,11 @@
#include "base/feature_list.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
+#include "base/strings/strcat.h"
#include "base/time/default_clock.h"
#include "components/optimization_guide/core/hints_processing_util.h"
#include "components/optimization_guide/core/optimization_guide_features.h"
+#include "components/optimization_guide/core/optimization_guide_logger.h"
#include "components/optimization_guide/core/optimization_guide_prefs.h"
#include "components/optimization_guide/core/optimization_guide_switches.h"
#include "components/optimization_guide/core/optimization_guide_util.h"
@@ -27,7 +29,6 @@
#include "net/http/http_response_headers.h"
#include "net/http/http_status_code.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
-#include "services/network/public/cpp/network_connection_tracker.h"
#include "services/network/public/cpp/resource_request.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "services/network/public/cpp/simple_url_loader.h"
@@ -62,23 +63,9 @@ std::string GetStringNameForRequestContext(
return std::string();
}
-// Returns the subset of URLs from |urls| for which the URL is considered
-// valid and can be included in a hints fetch.
-std::vector<GURL> GetValidURLsForFetching(const std::vector<GURL>& urls) {
- std::vector<GURL> valid_urls;
- for (const auto& url : urls) {
- if (valid_urls.size() >=
- features::MaxUrlsForOptimizationGuideServiceHintsFetch()) {
- break;
- }
- if (IsValidURLForURLKeyedHint(url))
- valid_urls.push_back(url);
- }
- return valid_urls;
-}
-
void RecordRequestStatusHistogram(proto::RequestContext request_context,
HintsFetcherRequestStatus status) {
+ DCHECK_NE(status, HintsFetcherRequestStatus::kDeprecatedNetworkOffline);
base::UmaHistogramEnumeration(
"OptimizationGuide.HintsFetcher.RequestStatus." +
GetStringNameForRequestContext(request_context),
@@ -91,14 +78,14 @@ HintsFetcher::HintsFetcher(
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
const GURL& optimization_guide_service_url,
PrefService* pref_service,
- network::NetworkConnectionTracker* network_connection_tracker)
+ OptimizationGuideLogger* optimization_guide_logger)
: optimization_guide_service_url_(net::AppendOrReplaceQueryParameter(
optimization_guide_service_url,
"key",
features::GetOptimizationGuideServiceAPIKey())),
pref_service_(pref_service),
- network_connection_tracker_(network_connection_tracker),
- time_clock_(base::DefaultClock::GetInstance()) {
+ time_clock_(base::DefaultClock::GetInstance()),
+ optimization_guide_logger_(optimization_guide_logger) {
url_loader_factory_ = std::move(url_loader_factory);
// Allow non-https scheme only when it is overridden in command line. This is
// needed for iOS EG2 tests which don't support HTTPS embedded test servers
@@ -190,16 +177,13 @@ bool HintsFetcher::FetchOptimizationGuideServiceHints(
HintsFetchedCallback hints_fetched_callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK_GT(optimization_types.size(), 0u);
-
- if (network_connection_tracker_->IsOffline()) {
- RecordRequestStatusHistogram(request_context,
- HintsFetcherRequestStatus::kNetworkOffline);
- std::move(hints_fetched_callback).Run(absl::nullopt);
- return false;
- }
+ request_context_ = request_context;
if (active_url_loader_) {
- RecordRequestStatusHistogram(request_context,
+ OPTIMIZATION_GUIDE_LOG(
+ optimization_guide_logger_,
+ "No hints fetched: HintsFetcher busy in another fetch");
+ RecordRequestStatusHistogram(request_context_,
HintsFetcherRequestStatus::kFetcherBusy);
std::move(hints_fetched_callback).Run(absl::nullopt);
return false;
@@ -207,10 +191,12 @@ bool HintsFetcher::FetchOptimizationGuideServiceHints(
std::vector<std::string> filtered_hosts =
GetSizeLimitedHostsDueForHintsRefresh(hosts);
- std::vector<GURL> valid_urls = GetValidURLsForFetching(urls);
+ std::vector<GURL> valid_urls = GetSizeLimitedURLsForFetching(urls);
if (filtered_hosts.empty() && valid_urls.empty()) {
+ OPTIMIZATION_GUIDE_LOG(optimization_guide_logger_,
+ "No hints fetched: No hosts/URLs");
RecordRequestStatusHistogram(
- request_context, HintsFetcherRequestStatus::kNoHostsOrURLsToFetch);
+ request_context_, HintsFetcherRequestStatus::kNoHostsOrURLsToFetch);
std::move(hints_fetched_callback).Run(absl::nullopt);
return false;
}
@@ -221,15 +207,16 @@ bool HintsFetcher::FetchOptimizationGuideServiceHints(
valid_urls.size());
if (optimization_types.empty()) {
+ OPTIMIZATION_GUIDE_LOG(optimization_guide_logger_,
+ "No hints fetched: No supported optimization types");
RecordRequestStatusHistogram(
- request_context,
+ request_context_,
HintsFetcherRequestStatus::kNoSupportedOptimizationTypes);
std::move(hints_fetched_callback).Run(absl::nullopt);
return false;
}
hints_fetch_start_time_ = base::TimeTicks::Now();
- request_context_ = request_context;
proto::GetHintsRequest get_hints_request;
get_hints_request.add_supported_key_representations(proto::HOST);
@@ -445,6 +432,38 @@ void HintsFetcher::OnURLLoadComplete(
HandleResponse(response_body ? *response_body : "", net_error, response_code);
}
+// Returns the subset of URLs from |urls| for which the URL is considered
+// valid and can be included in a hints fetch.
+std::vector<GURL> HintsFetcher::GetSizeLimitedURLsForFetching(
+ const std::vector<GURL>& urls) const {
+ std::vector<GURL> valid_urls;
+ for (size_t i = 0; i < urls.size(); i++) {
+ if (valid_urls.size() >=
+ features::MaxUrlsForOptimizationGuideServiceHintsFetch()) {
+ base::UmaHistogramCounts100(
+ "OptimizationGuide.HintsFetcher.GetHintsRequest.DroppedUrls." +
+ GetStringNameForRequestContext(request_context_),
+ urls.size() - i);
+ OPTIMIZATION_GUIDE_LOG(
+ optimization_guide_logger_,
+ base::StrCat({"Skipped adding URL due to limit, context:",
+ GetStringNameForRequestContext(request_context_),
+ " URL:", urls[i].possibly_invalid_spec()}));
+ break;
+ }
+ if (IsValidURLForURLKeyedHint(urls[i])) {
+ valid_urls.push_back(urls[i]);
+ } else {
+ OPTIMIZATION_GUIDE_LOG(
+ optimization_guide_logger_,
+ base::StrCat({"Skipped adding invalid URL, context:",
+ GetStringNameForRequestContext(request_context_),
+ " URL:", urls[i].possibly_invalid_spec()}));
+ }
+ }
+ return valid_urls;
+}
+
std::vector<std::string> HintsFetcher::GetSizeLimitedHostsDueForHintsRefresh(
const std::vector<std::string>& hosts) const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -455,7 +474,17 @@ std::vector<std::string> HintsFetcher::GetSizeLimitedHostsDueForHintsRefresh(
std::vector<std::string> target_hosts;
target_hosts.reserve(hosts.size());
- for (const auto& host : hosts) {
+ for (size_t i = 0; i < hosts.size(); i++) {
+ if (target_hosts.size() >=
+ features::MaxHostsForOptimizationGuideServiceHintsFetch()) {
+ base::UmaHistogramCounts100(
+ "OptimizationGuide.HintsFetcher.GetHintsRequest.DroppedHosts." +
+ GetStringNameForRequestContext(request_context_),
+ hosts.size() - i);
+ break;
+ }
+
+ std::string host = hosts[i];
// Skip over localhosts, IP addresses, and invalid hosts.
if (net::HostStringIsLocalhost(host))
continue;
@@ -463,6 +492,9 @@ std::vector<std::string> HintsFetcher::GetSizeLimitedHostsDueForHintsRefresh(
std::string canonicalized_host(net::CanonicalizeHost(host, &host_info));
if (host_info.IsIPAddress() ||
!net::IsCanonicalizedHostCompliant(canonicalized_host)) {
+ OPTIMIZATION_GUIDE_LOG(
+ optimization_guide_logger_,
+ base::StrCat({"Skipped adding invalid host:", host}));
continue;
}
@@ -477,12 +509,12 @@ std::vector<std::string> HintsFetcher::GetSizeLimitedHostsDueForHintsRefresh(
(host_valid_time - features::GetHostHintsFetchRefreshDuration() <=
time_clock_->Now());
}
- if (host_hints_due_for_refresh)
+ if (host_hints_due_for_refresh) {
target_hosts.push_back(host);
-
- if (target_hosts.size() >=
- features::MaxHostsForOptimizationGuideServiceHintsFetch()) {
- break;
+ } else {
+ OPTIMIZATION_GUIDE_LOG(
+ optimization_guide_logger_,
+ base::StrCat({"Skipped refreshing hints for host:", host}));
}
}
DCHECK_GE(features::MaxHostsForOptimizationGuideServiceHintsFetch(),
diff --git a/chromium/components/optimization_guide/core/hints_fetcher.h b/chromium/components/optimization_guide/core/hints_fetcher.h
index 95c2000513c..0ef0a13dea7 100644
--- a/chromium/components/optimization_guide/core/hints_fetcher.h
+++ b/chromium/components/optimization_guide/core/hints_fetcher.h
@@ -20,10 +20,10 @@
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "url/gurl.h"
+class OptimizationGuideLogger;
class PrefService;
namespace network {
-class NetworkConnectionTracker;
class SharedURLLoaderFactory;
class SimpleURLLoader;
} // namespace network
@@ -41,8 +41,8 @@ enum class HintsFetcherRequestStatus {
kSuccess,
// Fetch request was sent but no response received.
kResponseError,
- // Fetch request not sent because of offline network status.
- kNetworkOffline,
+ // DEPRECATED: Fetch request not sent because of offline network status.
+ kDeprecatedNetworkOffline,
// Fetch request not sent because fetcher was busy with another request.
kFetcherBusy,
// Fetch request not sent because the host and URL lists were empty.
@@ -71,7 +71,7 @@ class HintsFetcher {
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
const GURL& optimization_guide_service_url,
PrefService* pref_service,
- network::NetworkConnectionTracker* network_connection_tracker);
+ OptimizationGuideLogger* optimization_guide_logger);
HintsFetcher(const HintsFetcher&) = delete;
HintsFetcher& operator=(const HintsFetcher&) = delete;
@@ -142,6 +142,11 @@ class HintsFetcher {
// in the pref.
void UpdateHostsSuccessfullyFetched(base::TimeDelta valid_duration);
+ // Returns the subset of URLs from |urls| for which the URL is considered
+ // valid and can be included in a hints fetch.
+ std::vector<GURL> GetSizeLimitedURLsForFetching(
+ const std::vector<GURL>& urls) const;
+
// Returns the subset of hosts from |hosts| for which the hints should be
// refreshed. The count of returned hosts is limited to
// features::MaxHostsForOptimizationGuideServiceHintsFetch().
@@ -165,10 +170,6 @@ class HintsFetcher {
// A reference to the PrefService for this profile. Not owned.
raw_ptr<PrefService> pref_service_ = nullptr;
- // Listens to changes around the network connection. Not owned. Guaranteed to
- // outlive |this|.
- raw_ptr<network::NetworkConnectionTracker> network_connection_tracker_;
-
// Holds the hosts being requested by the hints fetcher.
std::vector<std::string> hosts_fetched_;
@@ -182,6 +183,9 @@ class HintsFetcher {
// retrieving hints from the remote Optimization Guide Service.
base::TimeTicks hints_fetch_start_time_;
+ // Owned by OptimizationGuideKeyedService and outlives |this|.
+ raw_ptr<OptimizationGuideLogger> optimization_guide_logger_;
+
SEQUENCE_CHECKER(sequence_checker_);
};
diff --git a/chromium/components/optimization_guide/core/hints_fetcher_factory.cc b/chromium/components/optimization_guide/core/hints_fetcher_factory.cc
index cd63684f63a..b6e454fa336 100644
--- a/chromium/components/optimization_guide/core/hints_fetcher_factory.cc
+++ b/chromium/components/optimization_guide/core/hints_fetcher_factory.cc
@@ -5,7 +5,6 @@
#include "components/optimization_guide/core/hints_fetcher.h"
#include "components/prefs/pref_service.h"
-#include "services/network/public/cpp/network_connection_tracker.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
namespace optimization_guide {
@@ -13,19 +12,18 @@ namespace optimization_guide {
HintsFetcherFactory::HintsFetcherFactory(
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
const GURL& optimization_guide_service_url,
- PrefService* pref_service,
- network::NetworkConnectionTracker* network_connection_tracker)
+ PrefService* pref_service)
: url_loader_factory_(url_loader_factory),
optimization_guide_service_url_(optimization_guide_service_url),
- pref_service_(pref_service),
- network_connection_tracker_(network_connection_tracker) {}
+ pref_service_(pref_service) {}
HintsFetcherFactory::~HintsFetcherFactory() = default;
-std::unique_ptr<HintsFetcher> HintsFetcherFactory::BuildInstance() {
+std::unique_ptr<HintsFetcher> HintsFetcherFactory::BuildInstance(
+ OptimizationGuideLogger* optimization_guide_logger) {
return std::make_unique<HintsFetcher>(
url_loader_factory_, optimization_guide_service_url_, pref_service_,
- network_connection_tracker_);
+ optimization_guide_logger);
}
void HintsFetcherFactory::OverrideOptimizationGuideServiceUrlForTesting(
diff --git a/chromium/components/optimization_guide/core/hints_fetcher_factory.h b/chromium/components/optimization_guide/core/hints_fetcher_factory.h
index 67eb35c4c97..f8c8a7ffd3c 100644
--- a/chromium/components/optimization_guide/core/hints_fetcher_factory.h
+++ b/chromium/components/optimization_guide/core/hints_fetcher_factory.h
@@ -11,10 +11,10 @@
#include "base/memory/scoped_refptr.h"
#include "url/gurl.h"
+class OptimizationGuideLogger;
class PrefService;
namespace network {
-class NetworkConnectionTracker;
class SharedURLLoaderFactory;
} // namespace network
@@ -29,15 +29,15 @@ class HintsFetcherFactory {
HintsFetcherFactory(
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
const GURL& optimization_guide_service_url,
- PrefService* pref_service,
- network::NetworkConnectionTracker* network_connection_tracker);
+ PrefService* pref_service);
HintsFetcherFactory(const HintsFetcherFactory&) = delete;
HintsFetcherFactory& operator=(const HintsFetcherFactory&) = delete;
virtual ~HintsFetcherFactory();
// Creates a new instance of HintsFetcher. Virtualized for testing so that the
// testing code can override this to provide a mocked instance.
- virtual std::unique_ptr<HintsFetcher> BuildInstance();
+ virtual std::unique_ptr<HintsFetcher> BuildInstance(
+ OptimizationGuideLogger* optimization_guide_logger);
// Override the optimization guide hints server URL. Used for testing.
void OverrideOptimizationGuideServiceUrlForTesting(
@@ -53,10 +53,6 @@ class HintsFetcherFactory {
// A reference to the PrefService for this profile. Not owned.
raw_ptr<PrefService> pref_service_ = nullptr;
-
- // A reference to the object that listens for changes in network connection.
- // Not owned. Guaranteed to outlive |this|.
- raw_ptr<network::NetworkConnectionTracker> network_connection_tracker_;
};
} // namespace optimization_guide
diff --git a/chromium/components/optimization_guide/core/hints_fetcher_unittest.cc b/chromium/components/optimization_guide/core/hints_fetcher_unittest.cc
index 58e9c1470e2..b7c2c5e647b 100644
--- a/chromium/components/optimization_guide/core/hints_fetcher_unittest.cc
+++ b/chromium/components/optimization_guide/core/hints_fetcher_unittest.cc
@@ -25,7 +25,6 @@
#include "net/base/url_util.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
-#include "services/network/test/test_network_connection_tracker.h"
#include "services/network/test/test_url_loader_factory.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
@@ -56,8 +55,7 @@ class HintsFetcherTest : public testing::Test,
hints_fetcher_ = std::make_unique<HintsFetcher>(
shared_url_loader_factory_, GURL(optimization_guide_service_url),
- pref_service_.get(),
- network::TestNetworkConnectionTracker::GetInstance());
+ pref_service_.get(), /*optimization_guide_logger=*/nullptr);
hints_fetcher_->SetTimeClockForTesting(task_environment_.GetMockClock());
}
@@ -72,19 +70,7 @@ class HintsFetcherTest : public testing::Test,
hints_fetched_ = true;
}
- bool hints_fetched() { return hints_fetched_; }
-
- void SetConnectionOffline() {
- network_tracker_ = network::TestNetworkConnectionTracker::GetInstance();
- network_tracker_->SetConnectionType(
- network::mojom::ConnectionType::CONNECTION_NONE);
- }
-
- void SetConnectionOnline() {
- network_tracker_ = network::TestNetworkConnectionTracker::GetInstance();
- network_tracker_->SetConnectionType(
- network::mojom::ConnectionType::CONNECTION_4G);
- }
+ bool hints_fetched() const { return hints_fetched_; }
// Updates the pref so that hints for each of the host in |hosts| are set to
// expire at |host_invalid_time|.
@@ -177,7 +163,6 @@ class HintsFetcherTest : public testing::Test,
std::unique_ptr<TestingPrefServiceSimple> pref_service_;
scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory_;
network::TestURLLoaderFactory test_url_loader_factory_;
- raw_ptr<network::TestNetworkConnectionTracker> network_tracker_;
std::string last_request_body_;
};
@@ -355,35 +340,6 @@ TEST_P(HintsFetcherTest, FetchReturnBadResponse) {
HintsFetcherRequestStatus::kResponseError, 1);
}
-TEST_P(HintsFetcherTest, FetchAttemptWhenNetworkOffline) {
- base::HistogramTester histogram_tester;
-
- SetConnectionOffline();
- std::string response_content;
- EXPECT_FALSE(FetchHints({"foo.com"}, {} /* urls */));
- EXPECT_FALSE(hints_fetched());
-
- // Make sure histograms are recorded correctly on bad response.
- histogram_tester.ExpectTotalCount(
- "OptimizationGuide.HintsFetcher.GetHintsRequest.FetchLatency", 0);
- histogram_tester.ExpectUniqueSample(
- "OptimizationGuide.HintsFetcher.RequestStatus.BatchUpdateActiveTabs",
- HintsFetcherRequestStatus::kNetworkOffline, 1);
-
- SetConnectionOnline();
- EXPECT_TRUE(FetchHints({"foo.com"}, {} /* urls */));
- VerifyHasPendingFetchRequests();
- EXPECT_TRUE(SimulateResponse(response_content, net::HTTP_OK));
- EXPECT_TRUE(hints_fetched());
-
- histogram_tester.ExpectTotalCount(
- "OptimizationGuide.HintsFetcher.GetHintsRequest.FetchLatency", 1);
- histogram_tester.ExpectTotalCount(
- "OptimizationGuide.HintsFetcher.GetHintsRequest.FetchLatency."
- "BatchUpdateActiveTabs",
- 1);
-}
-
TEST_P(HintsFetcherTest, HintsFetchSuccessfulHostsRecorded) {
std::vector<std::string> hosts{"host1.com", "host2.com"};
std::string response_content;
@@ -606,6 +562,8 @@ TEST_P(HintsFetcherTest, HintsFetcherSuccessfullyFetchedHostsFull) {
}
TEST_P(HintsFetcherTest, MaxHostsForOptimizationGuideServiceHintsFetch) {
+ base::HistogramTester histogram_tester;
+
std::string response_content;
std::vector<std::string> all_hosts;
@@ -640,6 +598,12 @@ TEST_P(HintsFetcherTest, MaxHostsForOptimizationGuideServiceHintsFetch) {
EXPECT_TRUE(
WasHostCoveredByFetch("host" + base::NumberToString(i) + ".com"));
}
+
+ // extra1.com and extra2.com should have been considered "dropped".
+ histogram_tester.ExpectUniqueSample(
+ "OptimizationGuide.HintsFetcher.GetHintsRequest.DroppedHosts."
+ "BatchUpdateActiveTabs",
+ 2, 1);
}
TEST_P(HintsFetcherTest, MaxUrlsForOptimizationGuideServiceHintsFetch) {
@@ -677,6 +641,12 @@ TEST_P(HintsFetcherTest, MaxUrlsForOptimizationGuideServiceHintsFetch) {
EXPECT_EQ(last_request.urls(i).url(),
"https://url" + base::NumberToString(i) + ".com/");
}
+
+ // notfetched.com and notfetched-2.com should have been considered "dropped".
+ histogram_tester.ExpectUniqueSample(
+ "OptimizationGuide.HintsFetcher.GetHintsRequest.DroppedUrls."
+ "BatchUpdateActiveTabs",
+ 2, 1);
}
TEST_P(HintsFetcherTest, OnlyURLsToFetch) {
@@ -697,6 +667,11 @@ TEST_P(HintsFetcherTest, OnlyURLsToFetch) {
histogram_tester.ExpectUniqueSample(
"OptimizationGuide.HintsFetcher.RequestStatus.BatchUpdateActiveTabs",
static_cast<int>(HintsFetcherRequestStatus::kSuccess), 1);
+ // Nothing was dropped so this shouldn't be recorded.
+ histogram_tester.ExpectTotalCount(
+ "OptimizationGuide.HintsFetcher.GetHintsRequest.DroppedHosts", 0);
+ histogram_tester.ExpectTotalCount(
+ "OptimizationGuide.HintsFetcher.GetHintsRequest.DroppedUrls", 0);
}
TEST_P(HintsFetcherTest, NoHostsOrURLsToFetch) {
diff --git a/chromium/components/optimization_guide/core/hints_manager.cc b/chromium/components/optimization_guide/core/hints_manager.cc
index 7ae4f3a4fe0..3270962e174 100644
--- a/chromium/components/optimization_guide/core/hints_manager.cc
+++ b/chromium/components/optimization_guide/core/hints_manager.cc
@@ -17,6 +17,8 @@
#include "base/metrics/histogram_macros_local.h"
#include "base/notreached.h"
#include "base/rand_util.h"
+#include "base/strings/strcat.h"
+#include "base/strings/string_number_conversions.h"
#include "base/task/post_task.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/task_runner_util.h"
@@ -33,6 +35,7 @@
#include "components/optimization_guide/core/optimization_guide_constants.h"
#include "components/optimization_guide/core/optimization_guide_enums.h"
#include "components/optimization_guide/core/optimization_guide_features.h"
+#include "components/optimization_guide/core/optimization_guide_logger.h"
#include "components/optimization_guide/core/optimization_guide_navigation_data.h"
#include "components/optimization_guide/core/optimization_guide_permissions_util.h"
#include "components/optimization_guide/core/optimization_guide_prefs.h"
@@ -50,7 +53,6 @@
#include "services/metrics/public/cpp/ukm_recorder.h"
#include "services/metrics/public/cpp/ukm_source.h"
#include "services/metrics/public/cpp/ukm_source_id.h"
-#include "services/network/public/cpp/network_connection_tracker.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
namespace optimization_guide {
@@ -204,23 +206,31 @@ bool ShouldIgnoreNewlyRegisteredOptimizationType(
class ScopedCanApplyOptimizationLogger {
public:
- ScopedCanApplyOptimizationLogger(proto::OptimizationType opt_type, GURL url)
+ ScopedCanApplyOptimizationLogger(
+ proto::OptimizationType opt_type,
+ GURL url,
+ OptimizationGuideLogger* optimization_guide_logger)
: decision_(OptimizationGuideDecision::kUnknown),
type_decision_(OptimizationTypeDecision::kUnknown),
opt_type_(opt_type),
has_metadata_(false),
- url_(url) {}
+ url_(url),
+ optimization_guide_logger_(optimization_guide_logger) {}
~ScopedCanApplyOptimizationLogger() {
if (!switches::IsDebugLogsEnabled())
return;
DCHECK_NE(type_decision_, OptimizationTypeDecision::kUnknown);
- DVLOG(0) << "OptimizationGuide: CanApplyOptimization: "
- << GetStringNameForOptimizationType(opt_type_)
- << "\nqueried on: " << url_ << "\nDecision: "
- << GetStringForOptimizationGuideDecision(decision_)
- << "\nTypeDecision: " << static_cast<int>(type_decision_)
- << "\nHas Metadata: " << has_metadata_;
+ OPTIMIZATION_GUIDE_LOG(
+ optimization_guide_logger_,
+ base::StrCat(
+ {"OptimizationGuide: CanApplyOptimization: ",
+ GetStringNameForOptimizationType(opt_type_),
+ "\nqueried on: ", url_.possibly_invalid_spec(),
+ "\nDecision: ", GetStringForOptimizationGuideDecision(decision_),
+ "\nTypeDecision: ",
+ base::NumberToString(static_cast<int>(type_decision_)),
+ "\nHas Metadata: ", (has_metadata_ ? "True" : "False")}));
}
void set_has_metadata() { has_metadata_ = true; }
@@ -238,6 +248,9 @@ class ScopedCanApplyOptimizationLogger {
proto::OptimizationType opt_type_;
bool has_metadata_;
GURL url_;
+
+ // Not owned. Guaranteed to outlive |this| scoped object.
+ raw_ptr<OptimizationGuideLogger> optimization_guide_logger_;
};
// Reads component file and parses it into a Configuration proto. Should not be
@@ -264,23 +277,33 @@ void MaybeLogGetHintRequestInfo(
const base::flat_set<proto::OptimizationType>&
registered_optimization_types,
const std::vector<GURL>& urls_to_fetch,
- const std::vector<std::string>& hosts_to_fetch) {
+ const std::vector<std::string>& hosts_to_fetch,
+ OptimizationGuideLogger* optimization_guide_logger) {
if (!switches::IsDebugLogsEnabled())
return;
- DVLOG(0) << "OptimizationGuide: Starting fetch for request context "
- << proto::RequestContext_Name(request_context);
- DVLOG(0) << "OptimizationGuide: Registered Optimization Types: ";
+ OPTIMIZATION_GUIDE_LOG(
+ optimization_guide_logger,
+ base::StrCat({"OptimizationGuide: Starting fetch for request context ",
+ proto::RequestContext_Name(request_context)}));
+ OPTIMIZATION_GUIDE_LOG(optimization_guide_logger,
+ "OptimizationGuide: Registered Optimization Types: ");
for (const auto& optimization_type : registered_optimization_types) {
- DVLOG(0) << "OptimizationGuide: Optimization Type: "
- << proto::OptimizationType_Name(optimization_type);
+ OPTIMIZATION_GUIDE_LOG(
+ optimization_guide_logger,
+ base::StrCat({"OptimizationGuide: Optimization Type: ",
+ proto::OptimizationType_Name(optimization_type)}));
}
- DVLOG(0) << "OptimizationGuide: URLs and Hosts: ";
+ OPTIMIZATION_GUIDE_LOG(optimization_guide_logger,
+ "OptimizationGuide: URLs and Hosts: ");
for (const auto& url : urls_to_fetch) {
- DVLOG(0) << "OptimizationGuide: URL: " << url;
+ OPTIMIZATION_GUIDE_LOG(optimization_guide_logger,
+ base::StrCat({"OptimizationGuide: URL: ",
+ url.possibly_invalid_spec()}));
}
for (const auto& host : hosts_to_fetch) {
- DVLOG(0) << "OptimizationGuide: Host: " << host;
+ OPTIMIZATION_GUIDE_LOG(optimization_guide_logger,
+ base::StrCat({"OptimizationGuide: Host: ", host}));
}
}
@@ -294,8 +317,8 @@ HintsManager::HintsManager(
TopHostProvider* top_host_provider,
TabUrlProvider* tab_url_provider,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
- network::NetworkConnectionTracker* network_connection_tracker,
- std::unique_ptr<PushNotificationManager> push_notification_manager)
+ std::unique_ptr<PushNotificationManager> push_notification_manager,
+ OptimizationGuideLogger* optimization_guide_logger)
: is_off_the_record_(is_off_the_record),
application_locale_(application_locale),
pref_service_(pref_service),
@@ -308,11 +331,11 @@ HintsManager::HintsManager(
hints_fetcher_factory_(std::make_unique<HintsFetcherFactory>(
url_loader_factory,
features::GetOptimizationGuideServiceGetHintsURL(),
- pref_service,
- network_connection_tracker)),
+ pref_service)),
top_host_provider_(top_host_provider),
tab_url_provider_(tab_url_provider),
push_notification_manager_(std::move(push_notification_manager)),
+ optimization_guide_logger_(optimization_guide_logger),
clock_(base::DefaultClock::GetInstance()),
background_task_runner_(base::ThreadPool::CreateSequencedTaskRunner(
{base::MayBlock(), base::TaskPriority::BEST_EFFORT})) {
@@ -687,14 +710,14 @@ void HintsManager::FetchHintsForActiveTabs() {
top_hosts.insert(top_hosts.begin(), url.host());
}
}
- MaybeLogGetHintRequestInfo(proto::CONTEXT_BATCH_UPDATE_ACTIVE_TABS,
- registered_optimization_types_,
- active_tab_urls_to_refresh, top_hosts);
+ MaybeLogGetHintRequestInfo(
+ proto::CONTEXT_BATCH_UPDATE_ACTIVE_TABS, registered_optimization_types_,
+ active_tab_urls_to_refresh, top_hosts, optimization_guide_logger_);
if (!active_tabs_batch_update_hints_fetcher_) {
DCHECK(hints_fetcher_factory_);
active_tabs_batch_update_hints_fetcher_ =
- hints_fetcher_factory_->BuildInstance();
+ hints_fetcher_factory_->BuildInstance(optimization_guide_logger_);
}
active_tabs_batch_update_hints_fetcher_->FetchOptimizationGuideServiceHints(
top_hosts, active_tab_urls_to_refresh, registered_optimization_types_,
@@ -710,8 +733,12 @@ void HintsManager::OnHintsForActiveTabsFetched(
const base::flat_set<GURL>& urls_fetched,
absl::optional<std::unique_ptr<proto::GetHintsResponse>>
get_hints_response) {
- if (!get_hints_response)
+ if (!get_hints_response) {
+ if (switches::IsDebugLogsEnabled()) {
+ DVLOG(0) << "OptimizationGuide: OnHintsForActiveTabsFetched failed";
+ }
return;
+ }
hint_cache_->UpdateFetchedHints(
std::move(*get_hints_response),
@@ -719,8 +746,11 @@ void HintsManager::OnHintsForActiveTabsFetched(
hosts_fetched, urls_fetched,
base::BindOnce(&HintsManager::OnFetchedActiveTabsHintsStored,
weak_ptr_factory_.GetWeakPtr()));
- if (switches::IsDebugLogsEnabled())
- DVLOG(0) << "OptimizationGuide: OnHintsForActiveTabsFetched complete";
+ if (switches::IsDebugLogsEnabled()) {
+ OPTIMIZATION_GUIDE_LOG(
+ optimization_guide_logger_,
+ "OptimizationGuide: OnHintsForActiveTabsFetched complete");
+ }
}
void HintsManager::OnPageNavigationHintsFetched(
@@ -735,6 +765,10 @@ void HintsManager::OnPageNavigationHintsFetched(
}
if (!get_hints_response.has_value() || !get_hints_response.value()) {
+ if (switches::IsDebugLogsEnabled()) {
+ DVLOG(0) << "OptimizationGuide: OnPageNavigationHintsFetched failed";
+ }
+
if (navigation_url) {
PrepareToInvokeRegisteredCallbacks(*navigation_url);
}
@@ -748,6 +782,10 @@ void HintsManager::OnPageNavigationHintsFetched(
base::BindOnce(&HintsManager::OnFetchedPageNavigationHintsStored,
weak_ptr_factory_.GetWeakPtr(), navigation_data_weak_ptr,
navigation_url, page_navigation_hosts_requested));
+
+ if (switches::IsDebugLogsEnabled()) {
+ DVLOG(0) << "OptimizationGuide: OnPageNavigationHintsFetched complete";
+ }
}
void HintsManager::OnFetchedActiveTabsHintsStored() {
@@ -844,7 +882,8 @@ void HintsManager::FetchHintsForURLs(const std::vector<GURL>& urls,
return;
MaybeLogGetHintRequestInfo(request_context, registered_optimization_types_,
- target_urls.vector(), target_hosts.vector());
+ target_urls.vector(), target_hosts.vector(),
+ optimization_guide_logger_);
std::pair<int32_t, HintsFetcher*> request_id_and_fetcher =
CreateAndTrackBatchUpdateHintsFetcher();
@@ -898,8 +937,10 @@ void HintsManager::RegisterOptimizationTypes(
registered_optimization_types_.insert(optimization_type);
if (switches::IsDebugLogsEnabled()) {
- DVLOG(0) << "OptimizationGuide: Registered new OptimizationType: "
- << proto::OptimizationType_Name(optimization_type);
+ OPTIMIZATION_GUIDE_LOG(
+ optimization_guide_logger_,
+ base::StrCat({"OptimizationGuide: Registered new OptimizationType: ",
+ proto::OptimizationType_Name(optimization_type)}));
}
absl::optional<double> value = previously_registered_opt_types->FindBoolKey(
@@ -1030,7 +1071,8 @@ void HintsManager::CanApplyOptimizationOnDemand(
}
MaybeLogGetHintRequestInfo(request_context, registered_optimization_types_,
- urls_to_fetch.vector(), hosts_to_fetch.vector());
+ urls_to_fetch.vector(), hosts_to_fetch.vector(),
+ optimization_guide_logger_);
// Fetch the data for the entries we don't have all information for.
std::pair<int32_t, HintsFetcher*> request_id_and_fetcher =
@@ -1058,6 +1100,10 @@ void HintsManager::OnBatchUpdateHintsFetched(
CleanUpBatchUpdateHintsFetcher(request_id);
if (!get_hints_response.has_value() || !get_hints_response.value()) {
+ if (switches::IsDebugLogsEnabled()) {
+ DVLOG(0) << "OptimizationGuide: OnBatchUpdateHintsFetched for "
+ << proto::RequestContext_Name(request_context) << " failed";
+ }
OnBatchUpdateHintsStored(urls_with_pending_callback, optimization_types,
callback);
return;
@@ -1074,8 +1120,11 @@ void HintsManager::OnBatchUpdateHintsFetched(
optimization_types, callback));
if (switches::IsDebugLogsEnabled()) {
- DVLOG(0) << "OptimizationGuide: OnBatchUpdateHintsFetched for "
- << proto::RequestContext_Name(request_context) << " complete";
+ OPTIMIZATION_GUIDE_LOG(
+ optimization_guide_logger_,
+ base::StrCat({"OptimizationGuide: OnBatchUpdateHintsFetched for ",
+ proto::RequestContext_Name(request_context),
+ " complete"}));
}
}
@@ -1100,7 +1149,7 @@ std::pair<int32_t, HintsFetcher*>
HintsManager::CreateAndTrackBatchUpdateHintsFetcher() {
DCHECK(hints_fetcher_factory_);
std::unique_ptr<HintsFetcher> hints_fetcher =
- hints_fetcher_factory_->BuildInstance();
+ hints_fetcher_factory_->BuildInstance(optimization_guide_logger_);
HintsFetcher* hints_fetcher_ptr = hints_fetcher.get();
batch_update_hints_fetchers_.Put(batch_update_hints_fetcher_request_id_++,
std::move(hints_fetcher));
@@ -1161,8 +1210,8 @@ OptimizationTypeDecision HintsManager::CanApplyOptimization(
OptimizationMetadata* optimization_metadata) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- ScopedCanApplyOptimizationLogger scoped_logger(optimization_type,
- navigation_url);
+ ScopedCanApplyOptimizationLogger scoped_logger(
+ optimization_type, navigation_url, optimization_guide_logger_);
// Clear out optimization metadata if provided.
if (optimization_metadata)
*optimization_metadata = {};
@@ -1432,14 +1481,15 @@ void HintsManager::MaybeFetchHintsForNavigation(
DCHECK(hints_fetcher_factory_);
auto it = page_navigation_hints_fetchers_.Put(
- url, hints_fetcher_factory_->BuildInstance());
+ url, hints_fetcher_factory_->BuildInstance(optimization_guide_logger_));
UMA_HISTOGRAM_COUNTS_100(
"OptimizationGuide.HintsManager.ConcurrentPageNavigationFetches",
page_navigation_hints_fetchers_.size());
MaybeLogGetHintRequestInfo(proto::CONTEXT_PAGE_NAVIGATION,
- registered_optimization_types_, urls, hosts);
+ registered_optimization_types_, urls, hosts,
+ optimization_guide_logger_);
bool fetch_attempted = it->second->FetchOptimizationGuideServiceHints(
hosts, urls, registered_optimization_types_,
proto::CONTEXT_PAGE_NAVIGATION, application_locale_,
diff --git a/chromium/components/optimization_guide/core/hints_manager.h b/chromium/components/optimization_guide/core/hints_manager.h
index 59b0782d191..f6e39c1cbb1 100644
--- a/chromium/components/optimization_guide/core/hints_manager.h
+++ b/chromium/components/optimization_guide/core/hints_manager.h
@@ -27,21 +27,21 @@
#include "components/optimization_guide/proto/hints.pb.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
+class OptimizationGuideLogger;
class OptimizationGuideNavigationData;
class OptimizationGuideTestAppInterfaceWrapper;
class PrefService;
namespace network {
class SharedURLLoaderFactory;
-class NetworkConnectionTracker;
} // namespace network
namespace optimization_guide {
class HintCache;
class HintsFetcherFactory;
class OptimizationFilter;
-class OptimizationMetadata;
class OptimizationGuideStore;
+class OptimizationMetadata;
enum class OptimizationTypeDecision;
class StoreUpdateData;
class TabUrlProvider;
@@ -58,8 +58,8 @@ class HintsManager : public OptimizationHintsComponentObserver,
TopHostProvider* top_host_provider,
TabUrlProvider* tab_url_provider,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
- network::NetworkConnectionTracker* network_connection_tracker,
- std::unique_ptr<PushNotificationManager> push_notification_manager);
+ std::unique_ptr<PushNotificationManager> push_notification_manager,
+ OptimizationGuideLogger* optimization_guide_logger);
~HintsManager() override;
@@ -473,6 +473,11 @@ class HintsManager : public OptimizationHintsComponentObserver,
// what to do through the implemented Delegate above.
std::unique_ptr<PushNotificationManager> push_notification_manager_;
+ // The logger that plumbs the debug logs to the optimization guide
+ // internals page. Not owned. Guaranteed to outlive |this|, since the logger
+ // and |this| are owned by the optimization guide keyed service.
+ raw_ptr<OptimizationGuideLogger> optimization_guide_logger_;
+
// The clock used to schedule fetching from the remote Optimization Guide
// Service.
raw_ptr<const base::Clock> clock_;
diff --git a/chromium/components/optimization_guide/core/hints_manager_unittest.cc b/chromium/components/optimization_guide/core/hints_manager_unittest.cc
index 5f4fd3b8383..2b2ddb9d398 100644
--- a/chromium/components/optimization_guide/core/hints_manager_unittest.cc
+++ b/chromium/components/optimization_guide/core/hints_manager_unittest.cc
@@ -15,7 +15,6 @@
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
#include "components/optimization_guide/core/bloom_filter.h"
#include "components/optimization_guide/core/hint_cache.h"
#include "components/optimization_guide/core/hints_component_util.h"
@@ -38,10 +37,8 @@
#include "components/variations/scoped_variations_ids_provider.h"
#include "services/metrics/public/cpp/ukm_builders.h"
#include "services/metrics/public/cpp/ukm_source.h"
-#include "services/network/public/cpp/network_connection_tracker.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
-#include "services/network/test/test_network_connection_tracker.h"
#include "services/network/test/test_url_loader_factory.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -190,12 +187,12 @@ class TestHintsFetcher : public HintsFetcher {
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
GURL optimization_guide_service_url,
PrefService* pref_service,
- network::NetworkConnectionTracker* network_connection_tracker,
- const std::vector<HintsFetcherEndState>& fetch_states)
+ const std::vector<HintsFetcherEndState>& fetch_states,
+ OptimizationGuideLogger* optimization_guide_logger)
: HintsFetcher(url_loader_factory,
optimization_guide_service_url,
pref_service,
- network_connection_tracker),
+ optimization_guide_logger),
fetch_states_(fetch_states) {
DCHECK(!fetch_states_.empty());
}
@@ -266,18 +263,17 @@ class TestHintsFetcherFactory : public HintsFetcherFactory {
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
GURL optimization_guide_service_url,
PrefService* pref_service,
- const std::vector<HintsFetcherEndState>& fetch_states,
- network::NetworkConnectionTracker* network_connection_tracker)
+ const std::vector<HintsFetcherEndState>& fetch_states)
: HintsFetcherFactory(url_loader_factory,
optimization_guide_service_url,
- pref_service,
- network_connection_tracker),
+ pref_service),
fetch_states_(fetch_states) {}
- std::unique_ptr<HintsFetcher> BuildInstance() override {
+ std::unique_ptr<HintsFetcher> BuildInstance(
+ OptimizationGuideLogger* optimization_guide_logger) override {
return std::make_unique<TestHintsFetcher>(
url_loader_factory_, optimization_guide_service_url_, pref_service_,
- network_connection_tracker_, fetch_states_);
+ fetch_states_, optimization_guide_logger);
}
private:
@@ -313,8 +309,6 @@ class HintsManagerTest : public ProtoDatabaseProviderTestBase {
pref_service_ =
std::make_unique<sync_preferences::TestingPrefServiceSyncable>();
prefs::RegisterProfilePrefs(pref_service_->registry());
- pref_service_->registry()->RegisterBooleanPref(
- data_reduction_proxy::prefs::kDataSaverEnabled, false);
unified_consent::UnifiedConsentService::RegisterPrefs(
pref_service_->registry());
@@ -332,8 +326,8 @@ class HintsManagerTest : public ProtoDatabaseProviderTestBase {
/*is_off_the_record=*/false, /*application_locale=*/"en-US",
pref_service(), hint_store_->AsWeakPtr(), top_host_provider,
tab_url_provider_.get(), url_loader_factory_,
- network::TestNetworkConnectionTracker::GetInstance(),
- /*push_notification_manager=*/nullptr);
+ /*push_notification_manager=*/nullptr,
+ /*optimization_guide_logger=*/nullptr);
hints_manager_->SetClockForTesting(task_environment_.GetMockClock());
// Run until hint cache is initialized and the HintsManager is ready to
@@ -414,7 +408,7 @@ class HintsManagerTest : public ProtoDatabaseProviderTestBase {
const std::vector<HintsFetcherEndState>& fetch_states) {
return std::make_unique<TestHintsFetcherFactory>(
url_loader_factory_, GURL("https://hintsserver.com"), pref_service(),
- fetch_states, network::TestNetworkConnectionTracker::GetInstance());
+ fetch_states);
}
void MoveClockForwardBy(base::TimeDelta time_delta) {
@@ -441,16 +435,6 @@ class HintsManagerTest : public ProtoDatabaseProviderTestBase {
std::move(callback));
}
- void SetConnectionOffline() {
- network::TestNetworkConnectionTracker::GetInstance()->SetConnectionType(
- network::mojom::ConnectionType::CONNECTION_NONE);
- }
-
- void SetConnectionOnline() {
- network::TestNetworkConnectionTracker::GetInstance()->SetConnectionType(
- network::mojom::ConnectionType::CONNECTION_4G);
- }
-
HintsManager* hints_manager() const { return hints_manager_.get(); }
int32_t num_batch_update_hints_fetches_initiated() const {
@@ -1402,8 +1386,6 @@ TEST_F(HintsManagerTest, CanApplyOptimizationAndPopulatesAnyMetadata) {
TEST_F(HintsManagerTest, CanApplyOptimizationNoMatchingPageHint) {
InitializeWithDefaultConfig("1.0.0.0");
- // Set to online so fetch is activated.
- SetConnectionOnline();
auto navigation_data =
CreateTestNavigationData(GURL("https://somedomain.org/nomatch"), {});
base::RunLoop run_loop;
@@ -2074,8 +2056,6 @@ TEST_F(HintsManagerFetchingTest,
/*is_allowlist=*/true, &config);
ProcessHints(config, "1.0.0.0");
- // Set to online so fetch is activated.
- SetConnectionOnline();
auto navigation_data = CreateTestNavigationData(url_without_hints(),
{proto::LITE_PAGE_REDIRECT});
base::HistogramTester histogram_tester;
@@ -2096,8 +2076,6 @@ TEST_F(HintsManagerFetchingTest, HintsFetchedAtNavigationTime) {
hints_manager()->RegisterOptimizationTypes({proto::DEFER_ALL_SCRIPT});
InitializeWithDefaultConfig("1.0.0.0");
- // Set to online so fetch is activated.
- SetConnectionOnline();
auto navigation_data =
CreateTestNavigationData(url_without_hints(), {proto::DEFER_ALL_SCRIPT});
base::HistogramTester histogram_tester;
@@ -2120,8 +2098,6 @@ TEST_F(HintsManagerFetchingTest,
hints_manager()->RegisterOptimizationTypes({proto::DEFER_ALL_SCRIPT});
InitializeWithDefaultConfig("1.0.0.0");
- // Set to online so fetch is activated.
- SetConnectionOnline();
auto navigation_data =
CreateTestNavigationData(url_without_hints(), {proto::DEFER_ALL_SCRIPT});
hints_manager()->SetHintsFetcherFactoryForTesting(
@@ -2149,8 +2125,6 @@ TEST_F(HintsManagerFetchingTest,
BuildTestHintsFetcherFactory(
{HintsFetcherEndState::kFetchSuccessWithURLHints}));
- // Set to online so fetch is activated.
- SetConnectionOnline();
auto navigation_data =
CreateTestNavigationData(url_with_hints(), {proto::DEFER_ALL_SCRIPT});
base::HistogramTester histogram_tester;
@@ -2188,8 +2162,6 @@ TEST_F(HintsManagerFetchingTest,
switches::kDisableCheckingUserPermissionsForTesting);
hints_manager()->RegisterOptimizationTypes({proto::DEFER_ALL_SCRIPT});
- // Set to online so fetch is activated.
- SetConnectionOnline();
auto navigation_data =
CreateTestNavigationData(example_url, {proto::DEFER_ALL_SCRIPT});
base::HistogramTester histogram_tester;
@@ -2221,9 +2193,6 @@ TEST_F(HintsManagerFetchingTest, URLHintsNotFetchedAtNavigationTime) {
BuildTestHintsFetcherFactory(
{HintsFetcherEndState::kFetchSuccessWithURLHints}));
- // Set to online so fetch is activated.
- SetConnectionOnline();
-
{
base::HistogramTester histogram_tester;
auto navigation_data =
@@ -2282,9 +2251,6 @@ TEST_F(HintsManagerFetchingTest, URLWithNoHintsNotRefetchedAtNavigationTime) {
BuildTestHintsFetcherFactory(
{HintsFetcherEndState::kFetchSuccessWithHostHints}));
- // Set to online so fetch is activated.
- SetConnectionOnline();
-
base::HistogramTester histogram_tester;
{
auto navigation_data = CreateTestNavigationData(url_without_hints(),
@@ -2330,8 +2296,6 @@ TEST_F(HintsManagerFetchingTest, CanApplyOptimizationCalledMidFetch) {
hints_manager()->RegisterOptimizationTypes({proto::DEFER_ALL_SCRIPT});
InitializeWithDefaultConfig("1.0.0.0");
- // Set to online so fetch is activated.
- SetConnectionOnline();
auto navigation_data =
CreateTestNavigationData(url_without_hints(), {proto::DEFER_ALL_SCRIPT});
CallOnNavigationStartOrRedirect(navigation_data.get(), base::DoNothing());
@@ -2355,8 +2319,6 @@ TEST_F(HintsManagerFetchingTest,
BuildTestHintsFetcherFactory(
{HintsFetcherEndState::kFetchSuccessWithNoHints}));
- // Set to online so fetch is activated.
- SetConnectionOnline();
auto navigation_data =
CreateTestNavigationData(url_without_hints(), {proto::DEFER_ALL_SCRIPT});
CallOnNavigationStartOrRedirect(navigation_data.get(), base::DoNothing());
@@ -2381,8 +2343,6 @@ TEST_F(HintsManagerFetchingTest,
hints_manager()->SetHintsFetcherFactoryForTesting(
BuildTestHintsFetcherFactory({HintsFetcherEndState::kFetchFailed}));
- // Set to online so fetch is activated.
- SetConnectionOnline();
auto navigation_data =
CreateTestNavigationData(url_without_hints(), {proto::DEFER_ALL_SCRIPT});
CallOnNavigationStartOrRedirect(navigation_data.get(), base::DoNothing());
@@ -2408,8 +2368,6 @@ TEST_F(HintsManagerFetchingTest,
BuildTestHintsFetcherFactory(
{HintsFetcherEndState::kFetchSuccessWithURLHints}));
- // Set to online so fetch is activated.
- SetConnectionOnline();
auto navigation_data = CreateTestNavigationData(url_with_url_keyed_hint(),
{proto::DEFER_ALL_SCRIPT});
// Make sure URL-keyed hint is fetched and processed.
@@ -2437,9 +2395,6 @@ TEST_F(HintsManagerFetchingTest,
InitializeWithDefaultConfig("1.0.0.0");
- // Set to online so fetch is activated.
- SetConnectionOnline();
-
// Make sure both URL-Keyed and host-keyed hints are processed and cached.
hints_manager()->SetHintsFetcherFactoryForTesting(
BuildTestHintsFetcherFactory(
@@ -2467,9 +2422,6 @@ TEST_F(HintsManagerFetchingTest,
InitializeWithDefaultConfig("1.0.0.0");
- // Set to online so fetch is activated.
- SetConnectionOnline();
-
// Make sure both URL-Keyed and host-keyed hints are processed and cached.
hints_manager()->SetHintsFetcherFactoryForTesting(
BuildTestHintsFetcherFactory(
@@ -2497,9 +2449,6 @@ TEST_F(HintsManagerFetchingTest,
InitializeWithDefaultConfig("1.0.0.0");
- // Set to online so fetch is activated.
- SetConnectionOnline();
-
hints_manager()->SetHintsFetcherFactoryForTesting(
BuildTestHintsFetcherFactory(
{HintsFetcherEndState::kFetchSuccessWithNoHints}));
@@ -2528,9 +2477,6 @@ TEST_F(HintsManagerFetchingTest,
InitializeWithDefaultConfig("1.0.0.0");
- // Set to online so fetch is activated.
- SetConnectionOnline();
-
// Attempt to fetch a hint but call CanApplyOptimization right away to
// simulate being mid-fetch.
auto navigation_data = CreateTestNavigationData(
@@ -2557,9 +2503,6 @@ TEST_F(HintsManagerFetchingTest,
InitializeWithDefaultConfig("1.0.0.0");
- // Set to online so fetch is activated.
- SetConnectionOnline();
-
// Attempt to fetch a hint but initiate the next navigation right away to
// simulate being mid-fetch.
auto navigation_data =
@@ -2608,8 +2551,6 @@ TEST_F(HintsManagerFetchingTest,
InitializeWithDefaultConfig("1.0.0.0");
- // Set to online so fetch is activated.
- SetConnectionOnline();
hints_manager()->SetHintsFetcherFactoryForTesting(
BuildTestHintsFetcherFactory(
{HintsFetcherEndState::kFetchSuccessWithNoHints}));
@@ -2650,8 +2591,6 @@ TEST_F(HintsManagerFetchingTest,
InitializeWithDefaultConfig("1.0.0.0");
- // Set to online so fetch is activated.
- SetConnectionOnline();
hints_manager()->SetHintsFetcherFactoryForTesting(
BuildTestHintsFetcherFactory(
{HintsFetcherEndState::kFetchSuccessWithURLHints}));
@@ -2691,9 +2630,6 @@ TEST_F(HintsManagerFetchingTest,
hints_manager()->RegisterOptimizationTypes({proto::COMPRESS_PUBLIC_IMAGES});
InitializeWithDefaultConfig("1.0.0.0");
- // Set to online so fetch is activated.
- SetConnectionOnline();
-
hints_manager()->SetHintsFetcherFactoryForTesting(
BuildTestHintsFetcherFactory(
{HintsFetcherEndState::kFetchSuccessWithURLHints}));
@@ -2723,9 +2659,6 @@ TEST_F(HintsManagerFetchingTest,
hints_manager()->RegisterOptimizationTypes({proto::COMPRESS_PUBLIC_IMAGES});
InitializeWithDefaultConfig("1.0.0.0");
- // Set to online so fetch is activated.
- SetConnectionOnline();
-
hints_manager()->SetHintsFetcherFactoryForTesting(
BuildTestHintsFetcherFactory(
{HintsFetcherEndState::kFetchSuccessWithURLHints}));
@@ -2763,9 +2696,6 @@ TEST_F(
hints_manager()->RegisterOptimizationTypes({proto::RESOURCE_LOADING});
InitializeWithDefaultConfig("1.0.0.0");
- // Set to online so fetch is activated.
- SetConnectionOnline();
-
hints_manager()->SetHintsFetcherFactoryForTesting(
BuildTestHintsFetcherFactory(
{HintsFetcherEndState::kFetchSuccessWithURLHints}));
@@ -2795,9 +2725,6 @@ TEST_F(HintsManagerFetchingTest,
InitializeWithDefaultConfig("1.0.0.0");
- // Set to online so fetch is activated.
- SetConnectionOnline();
-
hints_manager()->SetHintsFetcherFactoryForTesting(
BuildTestHintsFetcherFactory({HintsFetcherEndState::kFetchFailed}));
auto navigation_data = CreateTestNavigationData(
@@ -2826,9 +2753,6 @@ TEST_F(HintsManagerFetchingTest,
InitializeWithDefaultConfig("1.0.0.0");
- // Set to online so fetch is activated.
- SetConnectionOnline();
-
hints_manager()->SetHintsFetcherFactoryForTesting(
BuildTestHintsFetcherFactory(
{HintsFetcherEndState::kFetchSuccessWithURLHints}));
@@ -2861,9 +2785,6 @@ TEST_F(HintsManagerFetchingTest,
InitializeWithDefaultConfig("1.0.0.0");
- // Set to online so fetch is activated.
- SetConnectionOnline();
-
hints_manager()->SetHintsFetcherFactoryForTesting(
BuildTestHintsFetcherFactory(
{HintsFetcherEndState::kFetchSuccessWithURLHints}));
@@ -2895,9 +2816,6 @@ TEST_F(HintsManagerFetchingTest,
InitializeWithDefaultConfig("1.0.0.0");
- // Set to online so fetch is activated.
- SetConnectionOnline();
-
hints_manager()->SetHintsFetcherFactoryForTesting(
BuildTestHintsFetcherFactory(
{HintsFetcherEndState::kFetchSuccessWithNoHints}));
@@ -2927,9 +2845,6 @@ TEST_F(HintsManagerFetchingTest,
InitializeWithDefaultConfig("1.0.0.0");
- // Set to offline so fetch is NOT activated.
- SetConnectionOffline();
-
GURL url_that_redirected("https://urlthatredirected.com");
auto navigation_data_redirect = CreateTestNavigationData(
url_that_redirected, {proto::COMPRESS_PUBLIC_IMAGES});
@@ -2958,9 +2873,6 @@ TEST_F(HintsManagerFetchingTest,
InitializeWithDefaultConfig("1.0.0.0");
- // Set to offline so fetch is NOT activated.
- SetConnectionOffline();
-
hints_manager()->SetHintsFetcherFactoryForTesting(
BuildTestHintsFetcherFactory(
{HintsFetcherEndState::kFetchSuccessWithNoHints}));
@@ -3053,9 +2965,6 @@ TEST_F(HintsManagerFetchingTest,
InitializeWithDefaultConfig("1.0.0.0");
- // Set to online so fetch is activated.
- SetConnectionOnline();
-
hints_manager()->SetHintsFetcherFactoryForTesting(
BuildTestHintsFetcherFactory(
{HintsFetcherEndState::kFetchSuccessWithURLHints}));
@@ -3099,9 +3008,6 @@ TEST_F(HintsManagerFetchingTest, NewOptTypeRegisteredClearsHintCache) {
GURL url("https://host.com/fetched_hint_host");
- // Set to online so fetch is activated.
- SetConnectionOnline();
-
hints_manager()->SetHintsFetcherFactoryForTesting(
BuildTestHintsFetcherFactory(
{HintsFetcherEndState::kFetchSuccessWithHostHints}));
@@ -3129,10 +3035,6 @@ TEST_F(HintsManagerFetchingTest, NewOptTypeRegisteredClearsHintCache) {
base::RunLoop run_loop;
- // Set to offline so fetch is NOT activated, so the cache state is known and
- // empty.
- SetConnectionOffline();
-
base::HistogramTester histogram_tester;
navigation_data = CreateTestNavigationData(url, {proto::DEFER_ALL_SCRIPT});
@@ -3159,9 +3061,6 @@ TEST_F(HintsManagerFetchingTest,
hints_manager()->RegisterOptimizationTypes({proto::COMPRESS_PUBLIC_IMAGES});
InitializeWithDefaultConfig("1.0.0.0");
- // Set to online so fetch is activated.
- SetConnectionOnline();
-
hints_manager()->SetHintsFetcherFactoryForTesting(
BuildTestHintsFetcherFactory(
{HintsFetcherEndState::kFetchSuccessWithURLHints}));
@@ -3196,9 +3095,6 @@ TEST_F(HintsManagerFetchingTest, BatchUpdateCalledMoreThanMaxConcurrent) {
hints_manager()->RegisterOptimizationTypes({proto::COMPRESS_PUBLIC_IMAGES});
InitializeWithDefaultConfig("1.0.0.0");
- // Set to online so fetch is activated.
- SetConnectionOnline();
-
hints_manager()->SetHintsFetcherFactoryForTesting(
BuildTestHintsFetcherFactory(
{HintsFetcherEndState::kFetchSuccessWithURLHints}));
@@ -3244,9 +3140,6 @@ TEST_F(
{proto::NOSCRIPT, proto::COMPRESS_PUBLIC_IMAGES});
InitializeWithDefaultConfig("1.0.0.0");
- // Set to online so fetch is activated.
- SetConnectionOnline();
-
hints_manager()->SetHintsFetcherFactoryForTesting(
BuildTestHintsFetcherFactory(
{HintsFetcherEndState::kFetchSuccessWithURLHints}));
@@ -3285,9 +3178,6 @@ TEST_F(HintsManagerFetchingTest,
{proto::NOSCRIPT, proto::COMPRESS_PUBLIC_IMAGES});
InitializeWithDefaultConfig("1.0.0.0");
- // Set to online so fetch is activated.
- SetConnectionOnline();
-
hints_manager()->SetHintsFetcherFactoryForTesting(
BuildTestHintsFetcherFactory({HintsFetcherEndState::kFetchFailed}));
std::unique_ptr<base::RunLoop> run_loop = std::make_unique<base::RunLoop>();
diff --git a/chromium/components/optimization_guide/core/local_page_entities_metadata_provider.cc b/chromium/components/optimization_guide/core/local_page_entities_metadata_provider.cc
new file mode 100644
index 00000000000..18a32f9a573
--- /dev/null
+++ b/chromium/components/optimization_guide/core/local_page_entities_metadata_provider.cc
@@ -0,0 +1,93 @@
+// Copyright 2021 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.
+
+#include "components/optimization_guide/core/local_page_entities_metadata_provider.h"
+
+#include "components/optimization_guide/core/entity_metadata.h"
+
+namespace optimization_guide {
+
+namespace {
+
+// The amount of data to build up in memory before converting to a sorted on-
+// disk file.
+constexpr size_t kDatabaseWriteBufferSizeBytes = 128 * 1024;
+
+} // namespace
+
+LocalPageEntitiesMetadataProvider::LocalPageEntitiesMetadataProvider() =
+ default;
+LocalPageEntitiesMetadataProvider::~LocalPageEntitiesMetadataProvider() =
+ default;
+
+void LocalPageEntitiesMetadataProvider::Initialize(
+ leveldb_proto::ProtoDatabaseProvider* database_provider,
+ const base::FilePath& database_dir,
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ background_task_runner_ = std::move(background_task_runner);
+ database_ = database_provider->GetDB<proto::EntityMetadataStorage>(
+ leveldb_proto::ProtoDbType::PAGE_ENTITY_METADATA_STORE, database_dir,
+ background_task_runner_);
+
+ leveldb_env::Options options = leveldb_proto::CreateSimpleOptions();
+ options.write_buffer_size = kDatabaseWriteBufferSizeBytes;
+ database_->Init(
+ options,
+ base::BindOnce(&LocalPageEntitiesMetadataProvider::OnDatabaseInitialized,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void LocalPageEntitiesMetadataProvider::InitializeForTesting(
+ std::unique_ptr<leveldb_proto::ProtoDatabase<proto::EntityMetadataStorage>>
+ database,
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner) {
+ database_ = std::move(database);
+ background_task_runner_ = std::move(background_task_runner);
+}
+
+void LocalPageEntitiesMetadataProvider::OnDatabaseInitialized(
+ leveldb_proto::Enums::InitStatus status) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ if (status != leveldb_proto::Enums::InitStatus::kOK) {
+ database_.reset();
+ return;
+ }
+}
+
+void LocalPageEntitiesMetadataProvider::GetMetadataForEntityId(
+ const std::string& entity_id,
+ EntityMetadataRetrievedCallback callback) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ if (!database_) {
+ std::move(callback).Run(absl::nullopt);
+ return;
+ }
+
+ database_->GetEntry(
+ entity_id, base::BindOnce(&LocalPageEntitiesMetadataProvider::OnGotEntry,
+ weak_ptr_factory_.GetWeakPtr(), entity_id,
+ std::move(callback)));
+}
+
+void LocalPageEntitiesMetadataProvider::OnGotEntry(
+ const std::string& entity_id,
+ EntityMetadataRetrievedCallback callback,
+ bool success,
+ std::unique_ptr<proto::EntityMetadataStorage> entry) {
+ if (!success || !entry) {
+ std::move(callback).Run(absl::nullopt);
+ return;
+ }
+
+ EntityMetadata md;
+ md.entity_id = entity_id;
+ md.human_readable_name = entry->entity_name();
+
+ std::move(callback).Run(md);
+}
+
+} // namespace optimization_guide \ No newline at end of file
diff --git a/chromium/components/optimization_guide/core/local_page_entities_metadata_provider.h b/chromium/components/optimization_guide/core/local_page_entities_metadata_provider.h
new file mode 100644
index 00000000000..11070c8961a
--- /dev/null
+++ b/chromium/components/optimization_guide/core/local_page_entities_metadata_provider.h
@@ -0,0 +1,67 @@
+// Copyright 2021 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.
+
+#ifndef COMPONENTS_OPTIMIZATION_GUIDE_CORE_LOCAL_PAGE_ENTITIES_METADATA_PROVIDER_H_
+#define COMPONENTS_OPTIMIZATION_GUIDE_CORE_LOCAL_PAGE_ENTITIES_METADATA_PROVIDER_H_
+
+#include "base/callback.h"
+#include "base/memory/weak_ptr.h"
+#include "base/sequence_checker.h"
+#include "components/leveldb_proto/public/proto_database.h"
+#include "components/leveldb_proto/public/proto_database_provider.h"
+#include "components/optimization_guide/core/entity_metadata_provider.h"
+#include "components/optimization_guide/proto/page_entities_metadata.pb.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace optimization_guide {
+
+// Provides EntityMetadata given an entity id by looking up entries in a local
+// database on-disk.
+class LocalPageEntitiesMetadataProvider : public EntityMetadataProvider {
+ public:
+ LocalPageEntitiesMetadataProvider();
+ ~LocalPageEntitiesMetadataProvider() override;
+ LocalPageEntitiesMetadataProvider(const LocalPageEntitiesMetadataProvider&) =
+ delete;
+ LocalPageEntitiesMetadataProvider& operator=(
+ const LocalPageEntitiesMetadataProvider&) = delete;
+
+ // Initializes this class, setting |database_| and |background_task_runner_|.
+ void Initialize(
+ leveldb_proto::ProtoDatabaseProvider* database_provider,
+ const base::FilePath& database_dir,
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner);
+
+ // Directly sets |database_| and |background_task_runner_| for tests.
+ void InitializeForTesting(
+ std::unique_ptr<
+ leveldb_proto::ProtoDatabase<proto::EntityMetadataStorage>> database,
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner);
+
+ // EntityMetadataProvider:
+ void GetMetadataForEntityId(
+ const std::string& entity_id,
+ EntityMetadataRetrievedCallback callback) override;
+
+ private:
+ void OnDatabaseInitialized(leveldb_proto::Enums::InitStatus status);
+ void OnGotEntry(const std::string& entity_id,
+ EntityMetadataRetrievedCallback callback,
+ bool success,
+ std::unique_ptr<proto::EntityMetadataStorage> entry);
+
+ std::unique_ptr<leveldb_proto::ProtoDatabase<proto::EntityMetadataStorage>>
+ database_;
+
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner_;
+
+ SEQUENCE_CHECKER(sequence_checker_);
+
+ base::WeakPtrFactory<LocalPageEntitiesMetadataProvider> weak_ptr_factory_{
+ this};
+};
+
+} // namespace optimization_guide
+
+#endif // COMPONENTS_OPTIMIZATION_GUIDE_CORE_LOCAL_PAGE_ENTITIES_METADATA_PROVIDER_H_ \ No newline at end of file
diff --git a/chromium/components/optimization_guide/core/local_page_entities_metadata_provider_unittest.cc b/chromium/components/optimization_guide/core/local_page_entities_metadata_provider_unittest.cc
new file mode 100644
index 00000000000..7a24cbe2430
--- /dev/null
+++ b/chromium/components/optimization_guide/core/local_page_entities_metadata_provider_unittest.cc
@@ -0,0 +1,134 @@
+// Copyright 2021 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.
+
+#include "components/optimization_guide/core/local_page_entities_metadata_provider.h"
+
+#include "base/test/task_environment.h"
+#include "components/leveldb_proto/testing/fake_db.h"
+#include "components/optimization_guide/core/optimization_guide_features.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace optimization_guide {
+
+class LocalPageEntitiesMetadataProviderTest : public testing::Test {
+ public:
+ LocalPageEntitiesMetadataProviderTest() = default;
+ ~LocalPageEntitiesMetadataProviderTest() override = default;
+
+ void SetUp() override {
+ auto db = std::make_unique<
+ leveldb_proto::test::FakeDB<proto::EntityMetadataStorage>>(&db_store_);
+ db_ = db.get();
+
+ provider_ = std::make_unique<LocalPageEntitiesMetadataProvider>();
+ provider_->InitializeForTesting(
+ std::move(db), task_environment_.GetMainThreadTaskRunner());
+ }
+
+ LocalPageEntitiesMetadataProvider* provider() { return provider_.get(); }
+
+ leveldb_proto::test::FakeDB<proto::EntityMetadataStorage>* db() {
+ return db_;
+ }
+
+ std::map<std::string, proto::EntityMetadataStorage>* store() {
+ return &db_store_;
+ }
+
+ private:
+ base::test::TaskEnvironment task_environment_;
+ std::unique_ptr<LocalPageEntitiesMetadataProvider> provider_;
+ leveldb_proto::test::FakeDB<proto::EntityMetadataStorage>* db_;
+ std::map<std::string, proto::EntityMetadataStorage> db_store_;
+};
+
+TEST_F(LocalPageEntitiesMetadataProviderTest, NonInitReturnsNullOpt) {
+ LocalPageEntitiesMetadataProvider provider;
+
+ absl::optional<EntityMetadata> md;
+ bool callback_ran = false;
+ provider.GetMetadataForEntityId(
+ "entity_id",
+ base::BindOnce(
+ [](bool* callback_ran_flag, absl::optional<EntityMetadata>* md_out,
+ const absl::optional<EntityMetadata>& md_in) {
+ *callback_ran_flag = true;
+ *md_out = md_in;
+ },
+ &callback_ran, &md));
+
+ ASSERT_TRUE(callback_ran);
+ EXPECT_EQ(absl::nullopt, md);
+}
+
+TEST_F(LocalPageEntitiesMetadataProviderTest, EmptyStoreReturnsNullOpt) {
+ absl::optional<EntityMetadata> md;
+ bool callback_ran = false;
+ provider()->GetMetadataForEntityId(
+ "entity_id",
+ base::BindOnce(
+ [](bool* callback_ran_flag, absl::optional<EntityMetadata>* md_out,
+ const absl::optional<EntityMetadata>& md_in) {
+ *callback_ran_flag = true;
+ *md_out = md_in;
+ },
+ &callback_ran, &md));
+
+ db()->GetCallback(/*success=*/true);
+
+ ASSERT_TRUE(callback_ran);
+ EXPECT_EQ(absl::nullopt, md);
+}
+
+TEST_F(LocalPageEntitiesMetadataProviderTest, PopulatedSuccess) {
+ proto::EntityMetadataStorage stored_proto;
+ stored_proto.set_entity_name("chip");
+ store()->emplace("chocolate", stored_proto);
+
+ EntityMetadata want_md;
+ want_md.entity_id = "chocolate";
+ want_md.human_readable_name = "chip";
+
+ absl::optional<EntityMetadata> md;
+ bool callback_ran = false;
+ provider()->GetMetadataForEntityId(
+ "chocolate",
+ base::BindOnce(
+ [](bool* callback_ran_flag, absl::optional<EntityMetadata>* md_out,
+ const absl::optional<EntityMetadata>& md_in) {
+ *callback_ran_flag = true;
+ *md_out = md_in;
+ },
+ &callback_ran, &md));
+
+ db()->GetCallback(/*success=*/true);
+
+ ASSERT_TRUE(callback_ran);
+ EXPECT_EQ(absl::make_optional(want_md), md);
+}
+
+TEST_F(LocalPageEntitiesMetadataProviderTest, PopulatedFailure) {
+ proto::EntityMetadataStorage stored_proto;
+ stored_proto.set_entity_name("chip");
+ store()->emplace("chocolate", stored_proto);
+
+ absl::optional<EntityMetadata> md;
+ bool callback_ran = false;
+ provider()->GetMetadataForEntityId(
+ "chocolate",
+ base::BindOnce(
+ [](bool* callback_ran_flag, absl::optional<EntityMetadata>* md_out,
+ const absl::optional<EntityMetadata>& md_in) {
+ *callback_ran_flag = true;
+ *md_out = md_in;
+ },
+ &callback_ran, &md));
+
+ db()->GetCallback(/*success=*/false);
+
+ ASSERT_TRUE(callback_ran);
+ EXPECT_EQ(absl::nullopt, md);
+}
+
+} // namespace optimization_guide \ No newline at end of file
diff --git a/chromium/components/optimization_guide/core/model_enums.h b/chromium/components/optimization_guide/core/model_enums.h
new file mode 100644
index 00000000000..1e6c495c753
--- /dev/null
+++ b/chromium/components/optimization_guide/core/model_enums.h
@@ -0,0 +1,57 @@
+// Copyright 2021 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.
+
+#ifndef COMPONENTS_OPTIMIZATION_GUIDE_CORE_MODEL_ENUMS_H_
+#define COMPONENTS_OPTIMIZATION_GUIDE_CORE_MODEL_ENUMS_H_
+
+namespace optimization_guide {
+
+// The types of decisions that can be made for an optimization target.
+//
+// Keep in sync with OptimizationGuideOptimizationTargetDecision in enums.xml.
+enum class OptimizationTargetDecision {
+ kUnknown = 0,
+ // The page load does not match the optimization target.
+ kPageLoadDoesNotMatch = 1,
+ // The page load matches the optimization target.
+ kPageLoadMatches = 2,
+ // The model needed to make the target decision was not available on the
+ // client.
+ kModelNotAvailableOnClient = 3,
+ // The page load is part of a model prediction holdback where all decisions
+ // will return |OptimizationGuideDecision::kFalse| in an attempt to not taint
+ // the data for understanding the production recall of the model.
+ kModelPredictionHoldback = 4,
+ // The OptimizationGuideDecider was not initialized yet.
+ kDeciderNotInitialized = 5,
+
+ // Add new values above this line.
+ kMaxValue = kDeciderNotInitialized,
+};
+
+// The statuses for a prediction model in the prediction manager when requested
+// to be evaluated.
+//
+// Keep in sync with OptimizationGuidePredictionManagerModelStatus in enums.xml.
+enum class PredictionManagerModelStatus {
+ kUnknown = 0,
+ // The model is loaded and available for use.
+ kModelAvailable = 1,
+ // The store is initialized but does not contain a model for the optimization
+ // target.
+ kStoreAvailableNoModelForTarget = 2,
+ // The store is initialized and contains a model for the optimization target
+ // but it is not loaded in memory.
+ kStoreAvailableModelNotLoaded = 3,
+ // The store is not initialized and it is unknown if it contains a model for
+ // the optimization target.
+ kStoreUnavailableModelUnknown = 4,
+
+ // Add new values above this line.
+ kMaxValue = kStoreUnavailableModelUnknown,
+};
+
+} // namespace optimization_guide
+
+#endif // COMPONENTS_OPTIMIZATION_GUIDE_CORE_OPTIMIZATION_GUIDE_ENUMS_H_
diff --git a/chromium/components/optimization_guide/core/model_executor.h b/chromium/components/optimization_guide/core/model_executor.h
index 542c604c9db..305b6a9e24b 100644
--- a/chromium/components/optimization_guide/core/model_executor.h
+++ b/chromium/components/optimization_guide/core/model_executor.h
@@ -17,7 +17,7 @@
namespace optimization_guide {
// This class handles the execution, loading, unloading, and associated metrics
-// of machine learning models in Optimization Guide on a background thread. This
+// of machine learning models in Optimization Guide on a specified thread. This
// class is meant to be used and owned by an instance of |ModelHandler|. A
// ModelExecutor must be passed to a ModelHandler's constructor, this design
// allows the implementer of a ModelExecutor to define how the model is built
@@ -25,21 +25,21 @@ namespace optimization_guide {
// base_model_executor_helpers.h in this directory for helpful derived classes.
//
// Lifetime: This class can be constructed on any thread but cannot do anything
-// useful until |InitializeAndMoveToBackgroundThread| is called. After that
+// useful until |InitializeAndMoveToExecutionThread| is called. After that
// method is called, all subsequent calls to this class must be made through the
-// |background_task_runner| that was passed to initialize. Furthermore, all
-// WeakPointers of this class must only be dereferenced on the background thread
-// as well. This in turn means that this class must be destroyed on the
-// background thread as well.
+// |execution_task_runner| that was passed to initialize. Furthermore, all
+// WeakPointers of this class must only be dereferenced on the
+// |execution_task_runner| thread as well. This in turn means that this class
+// must be destroyed on the |execution_task_runner| thread as well.
template <class OutputType, class... InputTypes>
class ModelExecutor {
public:
ModelExecutor() = default;
virtual ~ModelExecutor() = default;
- virtual void InitializeAndMoveToBackgroundThread(
+ virtual void InitializeAndMoveToExecutionThread(
proto::OptimizationTarget optimization_target,
- scoped_refptr<base::SequencedTaskRunner> background_task_runner,
+ scoped_refptr<base::SequencedTaskRunner> execution_task_runner,
scoped_refptr<base::SequencedTaskRunner> reply_task_runner) = 0;
virtual void UpdateModelFile(const base::FilePath& file_path) = 0;
@@ -53,21 +53,21 @@ class ModelExecutor {
using ExecutionCallback =
base::OnceCallback<void(const absl::optional<OutputType>&)>;
- virtual void SendForExecution(ExecutionCallback ui_callback_on_complete,
+ virtual void SendForExecution(ExecutionCallback callback_on_complete,
base::TimeTicks start_time,
InputTypes... args) = 0;
- // IMPORTANT: These WeakPointers must only be dereferenced on the background
- // thread.
- base::WeakPtr<ModelExecutor> GetBackgroundWeakPtr() {
- return background_weak_ptr_factory_.GetWeakPtr();
+ // IMPORTANT: These WeakPointers must only be dereferenced on the
+ // |execution_task_runner| thread.
+ base::WeakPtr<ModelExecutor> GetWeakPtrForExecutionThread() {
+ return weak_ptr_factory_.GetWeakPtr();
}
ModelExecutor(const ModelExecutor&) = delete;
ModelExecutor& operator=(const ModelExecutor&) = delete;
private:
- base::WeakPtrFactory<ModelExecutor> background_weak_ptr_factory_{this};
+ base::WeakPtrFactory<ModelExecutor> weak_ptr_factory_{this};
};
} // namespace optimization_guide
diff --git a/chromium/components/optimization_guide/core/model_handler.h b/chromium/components/optimization_guide/core/model_handler.h
index 010734bab35..ff1c332a4a7 100644
--- a/chromium/components/optimization_guide/core/model_handler.h
+++ b/chromium/components/optimization_guide/core/model_handler.h
@@ -16,6 +16,7 @@
#include "base/threading/sequenced_task_runner_handle.h"
#include "base/time/time.h"
#include "components/optimization_guide/core/model_executor.h"
+#include "components/optimization_guide/core/model_util.h"
#include "components/optimization_guide/core/optimization_guide_model_provider.h"
#include "components/optimization_guide/core/optimization_guide_util.h"
#include "components/optimization_guide/core/optimization_target_model_observer.h"
@@ -24,32 +25,33 @@
namespace optimization_guide {
-// This class owns and handles the execution of models on the UI thread. Derived
-// classes must provide an implementation of |ModelExecutor|
-// (see above) which is then owned by |this|. The passed executor will be called
-// and destroyed on a background thread, which is all handled by this class.
+// This class owns and handles the execution of models on the UI thread.
+// Derived classes must provide an implementation of |ModelExecutor|
+// which is then owned by |this|. The passed executor will be called
+// and destroyed on the thread specified by |model_executor_task_runner|,
+// which is all handled by this class.
template <class OutputType, class... InputTypes>
class ModelHandler : public OptimizationTargetModelObserver {
public:
- ModelHandler(OptimizationGuideModelProvider* model_provider,
- scoped_refptr<base::SequencedTaskRunner> background_task_runner,
- std::unique_ptr<ModelExecutor<OutputType, InputTypes...>>
- background_executor,
- proto::OptimizationTarget optimization_target,
- const absl::optional<proto::Any>& model_metadata)
+ ModelHandler(
+ OptimizationGuideModelProvider* model_provider,
+ scoped_refptr<base::SequencedTaskRunner> model_executor_task_runner,
+ std::unique_ptr<ModelExecutor<OutputType, InputTypes...>> model_executor,
+ proto::OptimizationTarget optimization_target,
+ const absl::optional<proto::Any>& model_metadata)
: model_provider_(model_provider),
optimization_target_(optimization_target),
- background_executor_(std::move(background_executor)),
- background_task_runner_(background_task_runner) {
+ model_executor_(std::move(model_executor)),
+ model_executor_task_runner_(model_executor_task_runner) {
DCHECK(model_provider_);
- DCHECK(background_executor_);
+ DCHECK(model_executor_);
DCHECK_NE(optimization_target_,
proto::OptimizationTarget::OPTIMIZATION_TARGET_UNKNOWN);
model_provider_->AddObserverForOptimizationTargetModel(
optimization_target_, model_metadata, this);
- background_executor_->InitializeAndMoveToBackgroundThread(
- optimization_target_, background_task_runner_,
+ model_executor_->InitializeAndMoveToExecutionThread(
+ optimization_target_, model_executor_task_runner_,
base::SequencedTaskRunnerHandle::Get());
}
~ModelHandler() override {
@@ -58,10 +60,10 @@ class ModelHandler : public OptimizationTargetModelObserver {
model_provider_->RemoveObserverForOptimizationTargetModel(
optimization_target_, this);
- // |background_executor_|'s WeakPtrs are used on the background thread, so
+ // |model_executor_|'s WeakPtrs are used on the model thread, so
// that is also where the class must be destroyed.
- background_task_runner_->DeleteSoon(FROM_HERE,
- std::move(background_executor_));
+ model_executor_task_runner_->DeleteSoon(FROM_HERE,
+ std::move(model_executor_));
}
ModelHandler(const ModelHandler&) = delete;
ModelHandler& operator=(const ModelHandler&) = delete;
@@ -79,32 +81,33 @@ class ModelHandler : public OptimizationTargetModelObserver {
ExecutionCallback on_complete_callback =
base::BindOnce(&ModelHandler::OnExecutionCompleted, std::move(callback),
optimization_target_, now);
- background_task_runner_->PostTask(
+ model_executor_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(
&ModelExecutor<OutputType, InputTypes...>::SendForExecution,
- background_executor_->GetBackgroundWeakPtr(),
+ model_executor_->GetWeakPtrForExecutionThread(),
std::move(on_complete_callback), now, input...));
}
void SetShouldUnloadModelOnComplete(bool should_auto_unload) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- background_task_runner_->PostTask(
+ model_executor_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(
&ModelExecutor<OutputType,
InputTypes...>::SetShouldUnloadModelOnComplete,
- background_executor_->GetBackgroundWeakPtr(), should_auto_unload));
+ model_executor_->GetWeakPtrForExecutionThread(),
+ should_auto_unload));
}
// Requests that the model executor unload the model from memory, if it is
// currently loaded.
void UnloadModel() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- background_task_runner_->PostTask(
+ model_executor_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&ModelExecutor<OutputType, InputTypes...>::UnloadModel,
- background_executor_->GetBackgroundWeakPtr()));
+ model_executor_->GetWeakPtrForExecutionThread()));
}
// OptimizationTargetModelObserver:
@@ -118,16 +121,16 @@ class ModelHandler : public OptimizationTargetModelObserver {
model_info_ = model_info;
model_available_ = true;
- background_task_runner_->PostTask(
+ model_executor_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(
&ModelExecutor<OutputType, InputTypes...>::UpdateModelFile,
- background_executor_->GetBackgroundWeakPtr(),
+ model_executor_->GetWeakPtrForExecutionThread(),
model_info.GetModelFilePath()));
// Run any observing callbacks after the model file is posted to the
- // background thread so that any model execution requests are posted to the
- // background thread after the model update.
+ // model executor thread so that any model execution requests are posted to
+ // the model executor thread after the model update.
on_model_updated_callbacks_.Notify();
}
@@ -168,7 +171,7 @@ class ModelHandler : public OptimizationTargetModelObserver {
}
private:
- // This is called by |background_executor_|. This method does not have to be
+ // This is called by |model_executor_|. This method does not have to be
// static, but because it is stateless we've made it static so that we don't
// have to have this class support WeakPointers.
static void OnExecutionCompleted(
@@ -198,15 +201,14 @@ class ModelHandler : public OptimizationTargetModelObserver {
const proto::OptimizationTarget optimization_target_;
- // The owned background executor.
- std::unique_ptr<ModelExecutor<OutputType, InputTypes...>>
- background_executor_;
+ // The owned model executor.
+ std::unique_ptr<ModelExecutor<OutputType, InputTypes...>> model_executor_;
- // The background task runner. Note that whenever a task is posted here, the
- // task takes a reference to the TaskRunner (in a cyclic dependency) so
+ // The model executor task runner. Note that whenever a task is posted here,
+ // the task takes a reference to the TaskRunner (in a cyclic dependency) so
// |base::Unretained| is not safe anywhere in this class or the
- // |background_executor_|.
- scoped_refptr<base::SequencedTaskRunner> background_task_runner_;
+ // |model_executor_|.
+ scoped_refptr<base::SequencedTaskRunner> model_executor_task_runner_;
// Set in |OnModelUpdated|.
absl::optional<ModelInfo> model_info_ GUARDED_BY_CONTEXT(sequence_checker_);
diff --git a/chromium/components/optimization_guide/core/model_info.cc b/chromium/components/optimization_guide/core/model_info.cc
index 077b95dc9b2..db16275f297 100644
--- a/chromium/components/optimization_guide/core/model_info.cc
+++ b/chromium/components/optimization_guide/core/model_info.cc
@@ -6,7 +6,9 @@
#include "base/memory/ptr_util.h"
#include "base/notreached.h"
-#include "components/optimization_guide/core/optimization_guide_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
+#include "components/optimization_guide/core/model_util.h"
namespace optimization_guide {
diff --git a/chromium/components/optimization_guide/core/model_util.cc b/chromium/components/optimization_guide/core/model_util.cc
new file mode 100644
index 00000000000..936d0e4c4cb
--- /dev/null
+++ b/chromium/components/optimization_guide/core/model_util.cc
@@ -0,0 +1,86 @@
+// Copyright 2021 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.
+
+#include "components/optimization_guide/core/model_util.h"
+
+#include "base/base64.h"
+#include "base/containers/flat_set.h"
+#include "base/notreached.h"
+#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
+#include "net/base/url_util.h"
+#include "url/url_canon.h"
+
+namespace optimization_guide {
+
+// These names are persisted to histograms, so don't change them.
+std::string GetStringNameForOptimizationTarget(
+ optimization_guide::proto::OptimizationTarget optimization_target) {
+ switch (optimization_target) {
+ case proto::OPTIMIZATION_TARGET_UNKNOWN:
+ return "Unknown";
+ case proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD:
+ return "PainfulPageLoad";
+ case proto::OPTIMIZATION_TARGET_LANGUAGE_DETECTION:
+ return "LanguageDetection";
+ case proto::OPTIMIZATION_TARGET_PAGE_TOPICS:
+ return "PageTopics";
+ case proto::OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB:
+ return "SegmentationNewTab";
+ case proto::OPTIMIZATION_TARGET_SEGMENTATION_SHARE:
+ return "SegmentationShare";
+ case proto::OPTIMIZATION_TARGET_SEGMENTATION_VOICE:
+ return "SegmentationVoice";
+ case proto::OPTIMIZATION_TARGET_MODEL_VALIDATION:
+ return "ModelValidation";
+ case proto::OPTIMIZATION_TARGET_PAGE_ENTITIES:
+ return "PageEntities";
+ case proto::OPTIMIZATION_TARGET_NOTIFICATION_PERMISSION_PREDICTIONS:
+ return "NotificationPermissions";
+ case proto::OPTIMIZATION_TARGET_SEGMENTATION_DUMMY:
+ return "SegmentationDummyFeature";
+ case proto::OPTIMIZATION_TARGET_SEGMENTATION_CHROME_START_ANDROID:
+ return "SegmentationChromeStartAndroid";
+ case proto::OPTIMIZATION_TARGET_SEGMENTATION_QUERY_TILES:
+ return "SegmentationQueryTiles";
+ case proto::OPTIMIZATION_TARGET_PAGE_VISIBILITY:
+ return "PageVisibility";
+ case proto::OPTIMIZATION_TARGET_AUTOFILL_ASSISTANT:
+ return "AutofillAssistant";
+ case proto::OPTIMIZATION_TARGET_PAGE_TOPICS_V2:
+ return "PageTopicsV2";
+ case proto::OPTIMIZATION_TARGET_SEGMENTATION_CHROME_LOW_USER_ENGAGEMENT:
+ return "SegmentationChromeLowUserEngagement";
+ // Whenever a new value is added, make sure to add it to the OptTarget
+ // variant list in
+ // //tools/metrics/histograms/metadata/optimization/histograms.xml.
+ }
+ NOTREACHED();
+ return std::string();
+}
+
+absl::optional<base::FilePath> StringToFilePath(const std::string& str_path) {
+ if (str_path.empty())
+ return absl::nullopt;
+
+#if BUILDFLAG(IS_WIN)
+ return base::FilePath(base::UTF8ToWide(str_path));
+#else
+ return base::FilePath(str_path);
+#endif
+}
+
+std::string FilePathToString(const base::FilePath& file_path) {
+#if BUILDFLAG(IS_WIN)
+ return base::WideToUTF8(file_path.value());
+#else
+ return file_path.value();
+#endif
+}
+
+base::FilePath GetBaseFileNameForModels() {
+ return base::FilePath(FILE_PATH_LITERAL("model.tflite"));
+}
+
+} // namespace optimization_guide
diff --git a/chromium/components/optimization_guide/core/model_util.h b/chromium/components/optimization_guide/core/model_util.h
new file mode 100644
index 00000000000..dbcf1d476db
--- /dev/null
+++ b/chromium/components/optimization_guide/core/model_util.h
@@ -0,0 +1,37 @@
+// Copyright 2021 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.
+
+#ifndef COMPONENTS_OPTIMIZATION_GUIDE_CORE_MODEL_UTIL_H_
+#define COMPONENTS_OPTIMIZATION_GUIDE_CORE_MODEL_UTIL_H_
+
+#include <string>
+
+#include "base/files/file_path.h"
+#include "components/optimization_guide/proto/models.pb.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace optimization_guide {
+
+// Returns the string than can be used to record histograms for the optimization
+// target. If adding a histogram to use the string or adding an optimization
+// target, update the OptimizationGuide.OptimizationTargets histogram suffixes
+// in histograms.xml.
+std::string GetStringNameForOptimizationTarget(
+ proto::OptimizationTarget optimization_target);
+
+// Returns the file path represented by the given string, handling platform
+// differences in the conversion. nullopt is only returned iff the passed string
+// is empty.
+absl::optional<base::FilePath> StringToFilePath(const std::string& str_path);
+
+// Returns a string representation of the given |file_path|, handling platform
+// differences in the conversion.
+std::string FilePathToString(const base::FilePath& file_path);
+
+// Returns the base file name to use for storing all prediction models.
+base::FilePath GetBaseFileNameForModels();
+
+} // namespace optimization_guide
+
+#endif // COMPONENTS_OPTIMIZATION_GUIDE_CORE_MODEL_UTIL_H_
diff --git a/chromium/components/optimization_guide/core/model_validator.cc b/chromium/components/optimization_guide/core/model_validator.cc
index b936f7470f5..bb09c0c8e80 100644
--- a/chromium/components/optimization_guide/core/model_validator.cc
+++ b/chromium/components/optimization_guide/core/model_validator.cc
@@ -53,18 +53,22 @@ ModelValidatorExecutor::ModelValidatorExecutor() = default;
ModelValidatorExecutor::~ModelValidatorExecutor() = default;
-absl::Status ModelValidatorExecutor::Preprocess(
+bool ModelValidatorExecutor::Preprocess(
const std::vector<TfLiteTensor*>& input_tensors,
const std::vector<float>& input) {
// Return error so that actual model execution does not happen.
- return absl::Status(absl::StatusCode::kUnimplemented,
- "Model execution not supported");
+ return false;
}
-float ModelValidatorExecutor::Postprocess(
+absl::optional<float> ModelValidatorExecutor::Postprocess(
const std::vector<const TfLiteTensor*>& output_tensors) {
std::vector<float> data;
- tflite::task::core::PopulateVector<float>(output_tensors[0], &data);
+ absl::Status status =
+ tflite::task::core::PopulateVector<float>(output_tensors[0], &data);
+ if (!status.ok()) {
+ NOTREACHED();
+ return absl::nullopt;
+ }
return data[0];
}
diff --git a/chromium/components/optimization_guide/core/model_validator.h b/chromium/components/optimization_guide/core/model_validator.h
index 4e48f4f4a2f..fc25cf6bd94 100644
--- a/chromium/components/optimization_guide/core/model_validator.h
+++ b/chromium/components/optimization_guide/core/model_validator.h
@@ -53,9 +53,9 @@ class ModelValidatorExecutor
protected:
// BaseModelExecutor:
- absl::Status Preprocess(const std::vector<TfLiteTensor*>& input_tensors,
- const std::vector<float>& input) override;
- float Postprocess(
+ bool Preprocess(const std::vector<TfLiteTensor*>& input_tensors,
+ const std::vector<float>& input) override;
+ absl::optional<float> Postprocess(
const std::vector<const TfLiteTensor*>& output_tensors) override;
};
diff --git a/chromium/components/optimization_guide/core/model_validator_unittest.cc b/chromium/components/optimization_guide/core/model_validator_unittest.cc
index 48a66a623eb..8792f0a9798 100644
--- a/chromium/components/optimization_guide/core/model_validator_unittest.cc
+++ b/chromium/components/optimization_guide/core/model_validator_unittest.cc
@@ -15,6 +15,7 @@
#include "base/test/metrics/histogram_tester.h"
#include "base/test/task_environment.h"
#include "build/build_config.h"
+#include "components/optimization_guide/core/model_util.h"
#include "components/optimization_guide/core/model_validator.h"
#include "components/optimization_guide/core/optimization_guide_switches.h"
#include "components/optimization_guide/core/optimization_guide_util.h"
@@ -125,8 +126,14 @@ TEST_F(ModelValidatorExecutorTest, ValidModel) {
proto::OptimizationTarget::OPTIMIZATION_TARGET_MODEL_VALIDATION),
ExecutionStatus::kErrorUnknown, 1);
+ histogram_tester().ExpectUniqueSample(
+ "OptimizationGuide.ModelExecutor.ModelLoadedSuccessfully." +
+ GetStringNameForOptimizationTarget(
+ proto::OptimizationTarget::OPTIMIZATION_TARGET_MODEL_VALIDATION),
+ true, 1);
+
histogram_tester().ExpectTotalCount(
- "OptimizationGuide.ModelExecutor.ModelLoadingDuration." +
+ "OptimizationGuide.ModelExecutor.ModelLoadingDuration2." +
GetStringNameForOptimizationTarget(
proto::OptimizationTarget::OPTIMIZATION_TARGET_MODEL_VALIDATION),
1);
@@ -147,8 +154,15 @@ TEST_F(ModelValidatorExecutorTest, DISABLED_InvalidModel) {
GetStringNameForOptimizationTarget(
proto::OptimizationTarget::OPTIMIZATION_TARGET_MODEL_VALIDATION),
ExecutionStatus::kErrorModelFileNotValid, 1);
+
+ histogram_tester().ExpectUniqueSample(
+ "OptimizationGuide.ModelExecutor.ModelLoadedSuccessfully." +
+ GetStringNameForOptimizationTarget(
+ proto::OptimizationTarget::OPTIMIZATION_TARGET_MODEL_VALIDATION),
+ false, 1);
+
histogram_tester().ExpectTotalCount(
- "OptimizationGuide.ModelExecutor.ModelLoadingDuration." +
+ "OptimizationGuide.ModelExecutor.ModelLoadingDuration2." +
GetStringNameForOptimizationTarget(
proto::OptimizationTarget::OPTIMIZATION_TARGET_MODEL_VALIDATION),
1);
diff --git a/chromium/components/optimization_guide/core/optimization_guide_constants.cc b/chromium/components/optimization_guide/core/optimization_guide_constants.cc
index a8102e2dcac..c6b1318da25 100644
--- a/chromium/components/optimization_guide/core/optimization_guide_constants.cc
+++ b/chromium/components/optimization_guide/core/optimization_guide_constants.cc
@@ -27,4 +27,7 @@ const base::FilePath::CharType
kOptimizationGuidePredictionModelAndFeaturesStore[] =
FILE_PATH_LITERAL("optimization_guide_model_and_features_store");
+const base::FilePath::CharType kPageEntitiesMetadataStore[] =
+ FILE_PATH_LITERAL("page_content_annotations_page_entities_metadata_store");
+
} // namespace optimization_guide
diff --git a/chromium/components/optimization_guide/core/optimization_guide_constants.h b/chromium/components/optimization_guide/core/optimization_guide_constants.h
index 8b94c027625..d095761b879 100644
--- a/chromium/components/optimization_guide/core/optimization_guide_constants.h
+++ b/chromium/components/optimization_guide/core/optimization_guide_constants.h
@@ -33,6 +33,9 @@ extern const base::FilePath::CharType kOptimizationGuideHintStore[];
extern const base::FilePath::CharType
kOptimizationGuidePredictionModelAndFeaturesStore[];
+// The folder where the page entities metadata store will be stored on disk.
+extern const base::FilePath::CharType kPageEntitiesMetadataStore[];
+
} // namespace optimization_guide
#endif // COMPONENTS_OPTIMIZATION_GUIDE_CORE_OPTIMIZATION_GUIDE_CONSTANTS_H_
diff --git a/chromium/components/optimization_guide/core/optimization_guide_enums.h b/chromium/components/optimization_guide/core/optimization_guide_enums.h
index 88d24bcf537..a7e817c2b5e 100644
--- a/chromium/components/optimization_guide/core/optimization_guide_enums.h
+++ b/chromium/components/optimization_guide/core/optimization_guide_enums.h
@@ -49,29 +49,6 @@ enum class OptimizationTypeDecision {
kMaxValue = kHintFetchStartedButNotAvailableInTime,
};
-// The types of decisions that can be made for an optimization target.
-//
-// Keep in sync with OptimizationGuideOptimizationTargetDecision in enums.xml.
-enum class OptimizationTargetDecision {
- kUnknown,
- // The page load does not match the optimization target.
- kPageLoadDoesNotMatch,
- // The page load matches the optimization target.
- kPageLoadMatches,
- // The model needed to make the target decision was not available on the
- // client.
- kModelNotAvailableOnClient,
- // The page load is part of a model prediction holdback where all decisions
- // will return |OptimizationGuideDecision::kFalse| in an attempt to not taint
- // the data for understanding the production recall of the model.
- kModelPredictionHoldback,
- // The OptimizationGuideDecider was not initialized yet.
- kDeciderNotInitialized,
-
- // Add new values above this line.
- kMaxValue = kDeciderNotInitialized,
-};
-
// The statuses for racing a hints fetch with the current navigation based
// on the availability of hints for both the current host and URL.
//
@@ -101,28 +78,6 @@ enum class RaceNavigationFetchAttemptStatus {
kDeprecatedRaceNavigationFetchNotAttemptedTooManyConcurrentFetches,
};
-// The statuses for a prediction model in the prediction manager when requested
-// to be evaluated.
-//
-// Keep in sync with OptimizationGuidePredictionManagerModelStatus in enums.xml.
-enum class PredictionManagerModelStatus {
- kUnknown,
- // The model is loaded and available for use.
- kModelAvailable,
- // The store is initialized but does not contain a model for the optimization
- // target.
- kStoreAvailableNoModelForTarget,
- // The store is initialized and contains a model for the optimization target
- // but it is not loaded in memory.
- kStoreAvailableModelNotLoaded,
- // The store is not initialized and it is unknown if it contains a model for
- // the optimization target.
- kStoreUnavailableModelUnknown,
-
- // Add new values above this line.
- kMaxValue = kStoreUnavailableModelUnknown,
-};
-
// The statuses for a download file containing a prediction model when verified
// and processed.
//
diff --git a/chromium/components/optimization_guide/core/optimization_guide_features.cc b/chromium/components/optimization_guide/core/optimization_guide_features.cc
index 8de77e545fd..6c3a200263f 100644
--- a/chromium/components/optimization_guide/core/optimization_guide_features.cc
+++ b/chromium/components/optimization_guide/core/optimization_guide_features.cc
@@ -25,15 +25,49 @@
namespace optimization_guide {
namespace features {
+namespace {
+
+// Returns whether |locale| is a supported locale for |feature|.
+//
+// This matches |locale| with the "supported_locales" feature param value in
+// |feature|, which is expected to be a comma-separated list of locales. A
+// feature param containing "en,es-ES,zh-TW" restricts the feature to English
+// language users from any locale and Spanish language users from the Spain
+// es-ES locale. A feature param containing "" is unrestricted by locale and any
+// user may load it.
+bool IsSupportedLocaleForFeature(const std::string locale,
+ const base::Feature& feature) {
+ if (!base::FeatureList::IsEnabled(feature)) {
+ return false;
+ }
+
+ std::string value =
+ base::GetFieldTrialParamValueByFeature(feature, "supported_locales");
+ std::vector<std::string> supported_locales = base::SplitString(
+ value, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+ // An empty allowlist admits any locale.
+ if (supported_locales.empty()) {
+ return true;
+ }
+
+ // Otherwise, the locale or the
+ // primary language subtag must match an element of the allowlist.
+ std::string locale_language = l10n_util::GetLanguage(locale);
+ return base::Contains(supported_locales, locale) ||
+ base::Contains(supported_locales, locale_language);
+}
+
+} // namespace
+
// Enables the syncing of the Optimization Hints component, which provides
// hints for what optimizations can be applied on a page load.
const base::Feature kOptimizationHints {
"OptimizationHints",
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
base::FEATURE_DISABLED_BY_DEFAULT
-#else // !defined(OS_IOS)
+#else // !BUILDFLAG(IS_IOS)
base::FEATURE_ENABLED_BY_DEFAULT
-#endif // defined(OS_IOS)
+#endif // BUILDFLAG(IS_IOS)
};
// Feature flag that contains a feature param that specifies the field trials
@@ -47,11 +81,11 @@ const base::Feature kRemoteOptimizationGuideFetching{
const base::Feature kRemoteOptimizationGuideFetchingAnonymousDataConsent {
"OptimizationHintsFetchingAnonymousDataConsent",
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
base::FEATURE_ENABLED_BY_DEFAULT
-#else // !defined(OS_ANDROID)
+#else // !BUILDFLAG(IS_ANDROID)
base::FEATURE_DISABLED_BY_DEFAULT
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
};
// Enables performance info in the context menu and fetching from a remote
@@ -78,6 +112,17 @@ const base::Feature kOptimizationGuideModelDownloading {
const base::Feature kPageContentAnnotations{"PageContentAnnotations",
base::FEATURE_DISABLED_BY_DEFAULT};
+// Enables the page entities model to be annotated on every page load.
+const base::Feature kPageEntitiesPageContentAnnotations{
+ "PageEntitiesPageContentAnnotations", base::FEATURE_DISABLED_BY_DEFAULT};
+// Enables the page visibility model to be annotated on every page load.
+const base::Feature kPageVisibilityPageContentAnnotations{
+ "PageVisibilityPageContentAnnotations", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// This feature flag enables resetting the entities model on shutdown.
+const base::Feature kPageEntitiesModelResetOnShutdown{
+ "PageEntitiesModelResetOnShutdown", base::FEATURE_DISABLED_BY_DEFAULT};
+
// Enables push notification of hints.
const base::Feature kPushNotifications{"OptimizationGuidePushNotifications",
base::FEATURE_DISABLED_BY_DEFAULT};
@@ -96,6 +141,12 @@ const base::Feature kPageTopicsBatchAnnotations{
const base::Feature kPageVisibilityBatchAnnotations{
"PageVisibilityBatchAnnotations", base::FEATURE_ENABLED_BY_DEFAULT};
+const base::Feature kUseLocalPageEntitiesMetadataProvider{
+ "UseLocalPageEntitiesMetadataProvider", base::FEATURE_DISABLED_BY_DEFAULT};
+
+const base::Feature kBatchAnnotationsValidation{
+ "BatchAnnotationsValidation", base::FEATURE_DISABLED_BY_DEFAULT};
+
// The default value here is a bit of a guess.
// TODO(crbug/1163244): This should be tuned once metrics are available.
base::TimeDelta PageTextExtractionOutstandingRequestsGracePeriod() {
@@ -264,14 +315,15 @@ base::TimeDelta StoredHostModelFeaturesFreshnessDuration() {
"max_store_duration_for_host_model_features_in_days", 7));
}
-base::TimeDelta StoredModelsInactiveDuration() {
+base::TimeDelta StoredModelsValidDuration() {
// TODO(crbug.com/1234054) This field should not be changed without VERY
- // careful consideration. Any model that is on device and expires will be
- // removed and triggered to refetch so any feature relying on the model could
- // have a period of time without a valid model.
+ // careful consideration. This is the default duration for models that do not
+ // specify retention, so changing this can cause models to be removed and
+ // refetch would only apply to newer models. Any feature relying on the model
+ // would have a period of time without a valid model, and would need to push a
+ // new version.
return base::Days(GetFieldTrialParamByFeatureAsInt(
- kOptimizationTargetPrediction, "inactive_duration_for_models_in_days",
- 30));
+ kOptimizationTargetPrediction, "valid_duration_for_models_in_days", 30));
}
base::TimeDelta URLKeyedHintValidCacheDuration() {
@@ -334,6 +386,11 @@ base::TimeDelta PredictionModelFetchRetryDelay() {
kOptimizationTargetPrediction, "fetch_retry_minutes", 2));
}
+base::TimeDelta PredictionModelFetchStartupDelay() {
+ return base::Milliseconds(GetFieldTrialParamByFeatureAsInt(
+ kOptimizationTargetPrediction, "fetch_startup_delay_ms", 2000));
+}
+
base::TimeDelta PredictionModelFetchInterval() {
return base::Hours(GetFieldTrialParamByFeatureAsInt(
kOptimizationTargetPrediction, "fetch_interval_hours", 24));
@@ -396,75 +453,20 @@ bool ShouldExtractRelatedSearches() {
return kContentAnnotationsExtractRelatedSearchesParam.Get();
}
-std::vector<optimization_guide::proto::OptimizationTarget>
-GetPageContentModelsToExecute(const std::string& locale) {
- if (!IsPageContentAnnotationEnabled())
- return {};
-
- // Use an updated parameter name that supports locale filtering. That way,
- // older clients that don't know how to interpret locale filtering ignore the
- // new parameter name and keep looking for the old one.
- std::string value = base::GetFieldTrialParamValueByFeature(
- kPageContentAnnotations, "models_to_execute_v2");
- if (value.empty()) {
- // If the updated parameter is empty, try getting the older parameter name
- // that doesn't support locale-specific models. That way, older parameter
- // configurations still work. We don't do a union because that's confusing.
- value = base::GetFieldTrialParamValueByFeature(kPageContentAnnotations,
- "models_to_execute");
- }
- if (value.empty()) {
- // If neither the newer or older parameter is set, run the page topics model
- // by default.
- return {optimization_guide::proto::OPTIMIZATION_TARGET_PAGE_TOPICS};
- }
-
- // The parameter value delimits models by commas, and per-model locale
- // restrictions by colon. For example:
- // FOO_MODEL:en:es-ES,BAR_MODEL,BAZ_MODEL:zh-TW
- // - FOO_MODEL is restricted to English language users from any locale, and
- // Spanish language users from the Spain es-ES locale.
- // - BAR_MODEL is unrestricted by locale, and any user may load it.
- // - BAZ_MODEL is restricted to zh-TW only, so zh-CN users won't load it.
- //
- // First split by comma to handle one model at a time.
- std::vector<std::string> model_target_strings = base::SplitString(
- value, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
-
- std::string locale_language = l10n_util::GetLanguage(locale);
+bool ShouldExecutePageEntitiesModelOnPageContent(const std::string& locale) {
+ return base::FeatureList::IsEnabled(kPageEntitiesPageContentAnnotations) &&
+ IsSupportedLocaleForFeature(locale,
+ kPageEntitiesPageContentAnnotations);
+}
- optimization_guide::InsertionOrderedSet<
- optimization_guide::proto::OptimizationTarget>
- model_targets;
- for (const auto& model_target_string : model_target_strings) {
- // Split by colon to extract the model name and allowlist, early continuing
- // for invalid values.
- std::vector<std::string> model_name_and_allowed_locales =
- base::SplitString(model_target_string, ":", base::TRIM_WHITESPACE,
- base::SPLIT_WANT_NONEMPTY);
- if (model_name_and_allowed_locales.empty())
- continue;
- std::string model_name = model_name_and_allowed_locales[0];
- std::vector<std::string> allowlist;
- for (size_t i = 1; i < model_name_and_allowed_locales.size(); ++i) {
- allowlist.push_back(model_name_and_allowed_locales[i]);
- }
-
- optimization_guide::proto::OptimizationTarget model_target;
- if (!optimization_guide::proto::OptimizationTarget_Parse(model_name,
- &model_target)) {
- continue;
- }
-
- // An empty allowlist admits any locale. Otherwise, the locale or the
- // primary language subtag must match an element of the allowlist.
- if (allowlist.empty() || base::Contains(allowlist, locale) ||
- base::Contains(allowlist, locale_language)) {
- model_targets.insert(model_target);
- }
- }
+bool ShouldResetPageEntitiesModelOnShutdown() {
+ return base::FeatureList::IsEnabled(kPageEntitiesModelResetOnShutdown);
+}
- return model_targets.vector();
+bool ShouldExecutePageVisibilityModelOnPageContent(const std::string& locale) {
+ return base::FeatureList::IsEnabled(kPageVisibilityPageContentAnnotations) &&
+ IsSupportedLocaleForFeature(locale,
+ kPageVisibilityPageContentAnnotations);
}
bool RemotePageEntitiesEnabled() {
@@ -501,7 +503,7 @@ bool ShouldMetadataValidationFetchHostKeyed() {
bool ShouldDeferStartupActiveTabsHintsFetch() {
return GetFieldTrialParamByFeatureAsBool(
kOptimizationHints, "defer_startup_active_tabs_hints_fetch",
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
true
#else
false
@@ -517,5 +519,37 @@ bool PageVisibilityBatchAnnotationsEnabled() {
return base::FeatureList::IsEnabled(kPageVisibilityBatchAnnotations);
}
+bool UseLocalPageEntitiesMetadataProvider() {
+ return base::FeatureList::IsEnabled(kUseLocalPageEntitiesMetadataProvider);
+}
+
+size_t AnnotateVisitBatchSize() {
+ return std::max(
+ 1, GetFieldTrialParamByFeatureAsInt(kPageContentAnnotations,
+ "annotate_visit_batch_size", 1));
+}
+
+bool BatchAnnotationsValidationEnabled() {
+ return base::FeatureList::IsEnabled(kBatchAnnotationsValidation);
+}
+
+base::TimeDelta BatchAnnotationValidationStartupDelay() {
+ return base::Seconds(
+ std::max(1, GetFieldTrialParamByFeatureAsInt(kBatchAnnotationsValidation,
+ "startup_delay", 30)));
+}
+
+size_t BatchAnnotationsValidationBatchSize() {
+ int batch_size = GetFieldTrialParamByFeatureAsInt(kBatchAnnotationsValidation,
+ "batch_size", 25);
+ return std::max(1, batch_size);
+}
+
+size_t MaxVisitAnnotationCacheSize() {
+ int batch_size = GetFieldTrialParamByFeatureAsInt(
+ kPageContentAnnotations, "max_visit_annotation_cache_size", 50);
+ return std::max(1, batch_size);
+}
+
} // namespace features
} // namespace optimization_guide
diff --git a/chromium/components/optimization_guide/core/optimization_guide_features.h b/chromium/components/optimization_guide/core/optimization_guide_features.h
index 9789dbc0b42..e69bd80e439 100644
--- a/chromium/components/optimization_guide/core/optimization_guide_features.h
+++ b/chromium/components/optimization_guide/core/optimization_guide_features.h
@@ -29,11 +29,15 @@ extern const base::Feature kContextMenuPerformanceInfoAndRemoteHintFetching;
extern const base::Feature kOptimizationTargetPrediction;
extern const base::Feature kOptimizationGuideModelDownloading;
extern const base::Feature kPageContentAnnotations;
+extern const base::Feature kPageEntitiesPageContentAnnotations;
+extern const base::Feature kPageVisibilityPageContentAnnotations;
extern const base::Feature kPageTextExtraction;
extern const base::Feature kPushNotifications;
extern const base::Feature kOptimizationGuideMetadataValidation;
extern const base::Feature kPageTopicsBatchAnnotations;
extern const base::Feature kPageVisibilityBatchAnnotations;
+extern const base::Feature kUseLocalPageEntitiesMetadataProvider;
+extern const base::Feature kBatchAnnotationsValidation;
// The grace period duration for how long to give outstanding page text dump
// requests to respond after DidFinishLoad.
@@ -133,7 +137,7 @@ base::TimeDelta StoredHostModelFeaturesFreshnessDuration();
// The maximum duration for which models can remain in the
// OptimizationGuideStore without being loaded.
-base::TimeDelta StoredModelsInactiveDuration();
+base::TimeDelta StoredModelsValidDuration();
// The amount of time URL-keyed hints within the hint cache will be
// allowed to be used and not be purged.
@@ -177,6 +181,10 @@ int PredictionModelFetchRandomMaxDelaySecs();
// models.
base::TimeDelta PredictionModelFetchRetryDelay();
+// Returns the time to wait after browser start before fetching prediciton
+// models.
+base::TimeDelta PredictionModelFetchStartupDelay();
+
// Returns the time to wait after a successful fetch of prediction models to
// refresh models.
base::TimeDelta PredictionModelFetchInterval();
@@ -214,15 +222,16 @@ size_t MaxContentAnnotationRequestsCached();
// as part of page content annotations.
bool ShouldExtractRelatedSearches();
-// Returns an ordered vector of models to execute on the page content for each
-// page load. It is guaranteed that an optimization target will only be present
-// at most once in the returned vector. However, it is not guaranteed that it
-// will only contain models that the current PageContentAnnotationsService
-// supports, so it is up to the caller to ensure that it can execute the
-// specified models. `locale` is used for implement client-side locale filtering
-// for models that only work for some locales.
-std::vector<optimization_guide::proto::OptimizationTarget>
-GetPageContentModelsToExecute(const std::string& locale);
+// Returns whether the page entities model should be executed on page content
+// for a user using |locale| as their browser language.
+bool ShouldExecutePageEntitiesModelOnPageContent(const std::string& locale);
+
+// Returns whether the page entities model should be reset on shutdown.
+bool ShouldResetPageEntitiesModelOnShutdown();
+
+// Returns whether the page visibility model should be executed on page content
+// for a user using |locale| as their browser language.
+bool ShouldExecutePageVisibilityModelOnPageContent(const std::string& locale);
// Returns whether page entities should be retrieved from the remote
// Optimization Guide service.
@@ -249,6 +258,27 @@ bool PageTopicsBatchAnnotationsEnabled();
// Returns if Page Visibility Batch Annotations are enabled.
bool PageVisibilityBatchAnnotationsEnabled();
+// Whether to use the leveldb-based page entities metadata provider.
+bool UseLocalPageEntitiesMetadataProvider();
+
+// The number of visits batch before running the page content annotation
+// models. A size of 1 is equivalent to annotating one page load at time
+// immediately after requested.
+size_t AnnotateVisitBatchSize();
+
+// Whether the batch annotation validation feature is enabled.
+bool BatchAnnotationsValidationEnabled();
+
+// The time period between browser start and running a running batch annotation
+// validation.
+base::TimeDelta BatchAnnotationValidationStartupDelay();
+
+// The size of batches to run for validation.
+size_t BatchAnnotationsValidationBatchSize();
+
+// The maximum size of the visit annotation cache.
+size_t MaxVisitAnnotationCacheSize();
+
} // namespace features
} // namespace optimization_guide
diff --git a/chromium/components/optimization_guide/core/optimization_guide_features_unittest.cc b/chromium/components/optimization_guide/core/optimization_guide_features_unittest.cc
index 152c621bfe3..48433bff52b 100644
--- a/chromium/components/optimization_guide/core/optimization_guide_features_unittest.cc
+++ b/chromium/components/optimization_guide/core/optimization_guide_features_unittest.cc
@@ -68,73 +68,72 @@ TEST(OptimizationGuideFeaturesTest, ValidPageContentRAPPORMetrics) {
EXPECT_EQ(.2, features::NoiseProbabilityForRAPPORMetrics());
}
-TEST(OptimizationGuideFeaturesTest, GetPageContentModelsToExecute) {
+TEST(OptimizationGuideFeaturesTest,
+ ShouldExecutePageEntitiesModelOnPageContentDisabled) {
base::test::ScopedFeatureList scoped_feature_list;
- scoped_feature_list.InitAndEnableFeatureWithParameters(
- features::kPageContentAnnotations,
- {{"models_to_execute_v2",
- "OPTIMIZATION_TARGET_PAGE_TOPICS,OPTIMIZATION_TARGET_PAGE_ENTITIES"}});
+ scoped_feature_list.InitAndDisableFeature(
+ features::kPageEntitiesPageContentAnnotations);
- auto models = features::GetPageContentModelsToExecute("en-US");
- ASSERT_EQ(2U, models.size());
- ASSERT_EQ(proto::OPTIMIZATION_TARGET_PAGE_TOPICS, models[0]);
- ASSERT_EQ(proto::OPTIMIZATION_TARGET_PAGE_ENTITIES, models[1]);
+ EXPECT_FALSE(features::ShouldExecutePageEntitiesModelOnPageContent("en-US"));
}
TEST(OptimizationGuideFeaturesTest,
- GetPageContentModelsToExecuteOldParameterName) {
+ ShouldExecutePageEntitiesModelOnPageContentEmptyAllowlist) {
+ base::test::ScopedFeatureList scoped_feature_list;
+
+ scoped_feature_list.InitAndEnableFeature(
+ features::kPageEntitiesPageContentAnnotations);
+
+ EXPECT_TRUE(features::ShouldExecutePageEntitiesModelOnPageContent("en-US"));
+}
+
+TEST(OptimizationGuideFeaturesTest,
+ ShouldExecutePageEntitiesModelOnPageContentWithAllowlist) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeatureWithParameters(
- features::kPageContentAnnotations,
- {{"models_to_execute",
- "OPTIMIZATION_TARGET_PAGE_TOPICS,OPTIMIZATION_TARGET_PAGE_ENTITIES"}});
+ features::kPageEntitiesPageContentAnnotations,
+ {{"supported_locales", "en,zh-TW"}});
- auto models = features::GetPageContentModelsToExecute("en-US");
- ASSERT_EQ(2U, models.size());
- ASSERT_EQ(proto::OPTIMIZATION_TARGET_PAGE_TOPICS, models[0]);
- ASSERT_EQ(proto::OPTIMIZATION_TARGET_PAGE_ENTITIES, models[1]);
+ EXPECT_TRUE(features::ShouldExecutePageEntitiesModelOnPageContent("en-US"));
+ EXPECT_FALSE(features::ShouldExecutePageEntitiesModelOnPageContent(""));
+ EXPECT_FALSE(features::ShouldExecutePageEntitiesModelOnPageContent("zh-CN"));
}
-TEST(OptimizationGuideFeaturesTest, GetPageContentModelsToExecuteLocales) {
+TEST(OptimizationGuideFeaturesTest,
+ ShouldExecutePageVisibilityModelOnPageContentDisabled) {
+ base::test::ScopedFeatureList scoped_feature_list;
+
+ scoped_feature_list.InitAndDisableFeature(
+ features::kPageVisibilityPageContentAnnotations);
+
+ EXPECT_FALSE(
+ features::ShouldExecutePageVisibilityModelOnPageContent("en-US"));
+}
+
+TEST(OptimizationGuideFeaturesTest,
+ ShouldExecutePageVisibilityModelOnPageContentEmptyAllowlist) {
+ base::test::ScopedFeatureList scoped_feature_list;
+
+ scoped_feature_list.InitAndEnableFeature(
+ features::kPageVisibilityPageContentAnnotations);
+
+ EXPECT_TRUE(features::ShouldExecutePageVisibilityModelOnPageContent("en-US"));
+}
+
+TEST(OptimizationGuideFeaturesTest,
+ ShouldExecutePageVisibilityModelOnPageContentWithAllowlist) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeatureWithParameters(
- features::kPageContentAnnotations,
- {{
- "models_to_execute_v2",
- // This string is meant to test language filtering, locale filtering,
- // and tolerance of whitespaces, as well as extra delimiters.
- "OPTIMIZATION_TARGET_PAGE_TOPICS:en:es-ES , OPTIMIZATION_TARGET_PAGE_"
- "ENTITIES,,OPTIMIZATION_TARGET_PAGE_VISIBILITY:zh-TW:",
- }});
-
- {
- auto models = features::GetPageContentModelsToExecute("en-US");
- ASSERT_EQ(2U, models.size());
- ASSERT_EQ(proto::OPTIMIZATION_TARGET_PAGE_TOPICS, models[0]);
- ASSERT_EQ(proto::OPTIMIZATION_TARGET_PAGE_ENTITIES, models[1]);
- }
-
- {
- auto models = features::GetPageContentModelsToExecute("");
- ASSERT_EQ(1U, models.size());
- ASSERT_EQ(proto::OPTIMIZATION_TARGET_PAGE_ENTITIES, models[0]);
- }
-
- {
- auto models = features::GetPageContentModelsToExecute("zh-CN");
- ASSERT_EQ(1U, models.size());
- ASSERT_EQ(proto::OPTIMIZATION_TARGET_PAGE_ENTITIES, models[0]);
- }
-
- {
- auto models = features::GetPageContentModelsToExecute("zh-TW");
- ASSERT_EQ(2U, models.size());
- ASSERT_EQ(proto::OPTIMIZATION_TARGET_PAGE_ENTITIES, models[0]);
- ASSERT_EQ(proto::OPTIMIZATION_TARGET_PAGE_VISIBILITY, models[1]);
- }
+ features::kPageVisibilityPageContentAnnotations,
+ {{"supported_locales", "en,zh-TW"}});
+
+ EXPECT_TRUE(features::ShouldExecutePageVisibilityModelOnPageContent("en-US"));
+ EXPECT_FALSE(features::ShouldExecutePageVisibilityModelOnPageContent(""));
+ EXPECT_FALSE(
+ features::ShouldExecutePageVisibilityModelOnPageContent("zh-CN"));
}
} // namespace
diff --git a/chromium/components/optimization_guide/core/optimization_guide_logger.cc b/chromium/components/optimization_guide/core/optimization_guide_logger.cc
new file mode 100644
index 00000000000..20cdbaf4d1a
--- /dev/null
+++ b/chromium/components/optimization_guide/core/optimization_guide_logger.cc
@@ -0,0 +1,32 @@
+// Copyright 2022 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.
+
+#include "components/optimization_guide/core/optimization_guide_logger.h"
+
+OptimizationGuideLogger::OptimizationGuideLogger() = default;
+
+OptimizationGuideLogger::~OptimizationGuideLogger() = default;
+
+void OptimizationGuideLogger::AddObserver(
+ OptimizationGuideLogger::Observer* observer) {
+ observers_.AddObserver(observer);
+}
+
+void OptimizationGuideLogger::RemoveObserver(
+ OptimizationGuideLogger::Observer* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+void OptimizationGuideLogger::OnLogMessageAdded(base::Time event_time,
+ const std::string& source_file,
+ int source_line,
+ const std::string& message) {
+ DCHECK(!observers_.empty());
+ for (Observer& obs : observers_)
+ obs.OnLogMessageAdded(event_time, source_file, source_line, message);
+}
+
+bool OptimizationGuideLogger::ShouldEnableDebugLogs() const {
+ return !observers_.empty();
+}
diff --git a/chromium/components/optimization_guide/core/optimization_guide_logger.h b/chromium/components/optimization_guide/core/optimization_guide_logger.h
new file mode 100644
index 00000000000..d9a2f169ba1
--- /dev/null
+++ b/chromium/components/optimization_guide/core/optimization_guide_logger.h
@@ -0,0 +1,45 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_OPTIMIZATION_GUIDE_CORE_OPTIMIZATION_GUIDE_LOGGER_H_
+#define COMPONENTS_OPTIMIZATION_GUIDE_CORE_OPTIMIZATION_GUIDE_LOGGER_H_
+
+#include <string>
+
+#include "base/observer_list.h"
+#include "base/observer_list_types.h"
+#include "base/time/time.h"
+
+// Interface to record the debug logs and send it to be shown in the
+// optimization guide internals page.
+class OptimizationGuideLogger {
+ public:
+ class Observer : public base::CheckedObserver {
+ public:
+ virtual void OnLogMessageAdded(base::Time event_time,
+ const std::string& source_file,
+ int source_line,
+ const std::string& message) = 0;
+ };
+ OptimizationGuideLogger();
+ ~OptimizationGuideLogger();
+
+ OptimizationGuideLogger(const OptimizationGuideLogger&) = delete;
+ OptimizationGuideLogger& operator=(const OptimizationGuideLogger&) = delete;
+
+ void AddObserver(OptimizationGuideLogger::Observer* observer);
+ void RemoveObserver(OptimizationGuideLogger::Observer* observer);
+ void OnLogMessageAdded(base::Time event_time,
+ const std::string& source_file,
+ int source_line,
+ const std::string& message);
+
+ // Whether debug logs should allowed to be recorded.
+ bool ShouldEnableDebugLogs() const;
+
+ private:
+ base::ObserverList<OptimizationGuideLogger::Observer> observers_;
+};
+
+#endif // COMPONENTS_OPTIMIZATION_GUIDE_CORE_OPTIMIZATION_GUIDE_LOGGER_H_
diff --git a/chromium/components/optimization_guide/core/optimization_guide_permissions_util.cc b/chromium/components/optimization_guide/core/optimization_guide_permissions_util.cc
index d7a71e2785e..fec08802020 100644
--- a/chromium/components/optimization_guide/core/optimization_guide_permissions_util.cc
+++ b/chromium/components/optimization_guide/core/optimization_guide_permissions_util.cc
@@ -7,21 +7,12 @@
#include <memory>
#include "base/feature_list.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h"
#include "components/optimization_guide/core/optimization_guide_features.h"
#include "components/optimization_guide/core/optimization_guide_switches.h"
#include "components/unified_consent/url_keyed_data_collection_consent_helper.h"
namespace {
-bool IsUserDataSaverEnabledAndAllowedToFetchFromRemoteService(
- bool is_off_the_record,
- PrefService* pref_service) {
- // Check if they are a data saver user.
- return data_reduction_proxy::DataReductionProxySettings::
- IsDataSaverEnabledByUser(is_off_the_record, pref_service);
-}
-
bool IsUserConsentedToAnonymousDataCollectionAndAllowedToFetchFromRemoteService(
PrefService* pref_service) {
if (!optimization_guide::features::
@@ -55,10 +46,6 @@ bool IsUserPermittedToFetchFromRemoteOptimizationGuide(
if (features::IsRemoteFetchingExplicitlyAllowedForPerformanceInfo())
return true;
- if (IsUserDataSaverEnabledAndAllowedToFetchFromRemoteService(
- is_off_the_record, pref_service))
- return true;
-
return IsUserConsentedToAnonymousDataCollectionAndAllowedToFetchFromRemoteService(
pref_service);
}
diff --git a/chromium/components/optimization_guide/core/optimization_guide_permissions_util_unittest.cc b/chromium/components/optimization_guide/core/optimization_guide_permissions_util_unittest.cc
index 9e879748e84..015955ccc26 100644
--- a/chromium/components/optimization_guide/core/optimization_guide_permissions_util_unittest.cc
+++ b/chromium/components/optimization_guide/core/optimization_guide_permissions_util_unittest.cc
@@ -7,8 +7,6 @@
#include "base/command_line.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
#include "components/optimization_guide/core/optimization_guide_features.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "components/unified_consent/pref_names.h"
@@ -22,13 +20,6 @@ class OptimizationGuidePermissionsUtilTest : public testing::Test {
void SetUp() override {
unified_consent::UnifiedConsentService::RegisterPrefs(
pref_service_.registry());
- pref_service_.registry()->RegisterBooleanPref(
- data_reduction_proxy::prefs::kDataSaverEnabled, false);
- }
-
- void SetDataSaverEnabled(bool enabled) {
- data_reduction_proxy::DataReductionProxySettings::
- SetDataSaverEnabledForTesting(&pref_service_, enabled);
}
void SetUrlKeyedAnonymizedDataCollectionEnabled(bool enabled) {
@@ -45,53 +36,38 @@ class OptimizationGuidePermissionsUtilTest : public testing::Test {
};
TEST_F(OptimizationGuidePermissionsUtilTest,
- IsUserPermittedToFetchHintsNonDataSaverUser) {
+ IsUserPermittedToFetchHintsDefaultUser) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeature(
{optimization_guide::features::kRemoteOptimizationGuideFetching});
- SetDataSaverEnabled(false);
EXPECT_FALSE(IsUserPermittedToFetchFromRemoteOptimizationGuide(
/*is_off_the_record=*/false, pref_service()));
}
-TEST_F(OptimizationGuidePermissionsUtilTest,
- IsUserPermittedToFetchHintsDataSaverUser) {
- base::test::ScopedFeatureList scoped_feature_list;
- scoped_feature_list.InitAndEnableFeature(
- {optimization_guide::features::kRemoteOptimizationGuideFetching});
- SetDataSaverEnabled(true);
-
- EXPECT_TRUE(IsUserPermittedToFetchFromRemoteOptimizationGuide(
- /*is_off_the_record=*/false, pref_service()));
-}
-
TEST_F(
OptimizationGuidePermissionsUtilTest,
- IsUserPermittedToFetchHintsNonDataSaverUserAnonymousDataCollectionEnabledFeatureEnabled) {
+ IsUserPermittedToFetchHintsDefaultUserAnonymousDataCollectionEnabledFeatureEnabled) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitWithFeatures(
{optimization_guide::features::kRemoteOptimizationGuideFetching,
optimization_guide::features::
kRemoteOptimizationGuideFetchingAnonymousDataConsent},
{});
- SetDataSaverEnabled(false);
SetUrlKeyedAnonymizedDataCollectionEnabled(true);
EXPECT_TRUE(IsUserPermittedToFetchFromRemoteOptimizationGuide(
/*is_off_the_record=*/false, pref_service()));
}
-TEST_F(
- OptimizationGuidePermissionsUtilTest,
- IsUserPermittedToFetchHintsNonDataSaverUserAnonymousDataCollectionDisabled) {
+TEST_F(OptimizationGuidePermissionsUtilTest,
+ IsUserPermittedToFetchHintsDefaultUserAnonymousDataCollectionDisabled) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitWithFeatures(
{optimization_guide::features::kRemoteOptimizationGuideFetching,
optimization_guide::features::
kRemoteOptimizationGuideFetchingAnonymousDataConsent},
{});
- SetDataSaverEnabled(false);
SetUrlKeyedAnonymizedDataCollectionEnabled(false);
EXPECT_FALSE(IsUserPermittedToFetchFromRemoteOptimizationGuide(
@@ -100,13 +76,12 @@ TEST_F(
TEST_F(
OptimizationGuidePermissionsUtilTest,
- IsUserPermittedToFetchHintsNonDataSaverUserAnonymousDataCollectionEnabledFeatureNotEnabled) {
+ IsUserPermittedToFetchHintsDefaultUserAnonymousDataCollectionEnabledFeatureNotEnabled) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitWithFeatures(
{optimization_guide::features::kRemoteOptimizationGuideFetching},
{optimization_guide::features::
kRemoteOptimizationGuideFetchingAnonymousDataConsent});
- SetDataSaverEnabled(false);
SetUrlKeyedAnonymizedDataCollectionEnabled(true);
EXPECT_FALSE(IsUserPermittedToFetchFromRemoteOptimizationGuide(
@@ -118,7 +93,6 @@ TEST_F(OptimizationGuidePermissionsUtilTest,
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitWithFeatures(
{}, {optimization_guide::features::kRemoteOptimizationGuideFetching});
- SetDataSaverEnabled(true);
SetUrlKeyedAnonymizedDataCollectionEnabled(true);
EXPECT_FALSE(IsUserPermittedToFetchFromRemoteOptimizationGuide(
@@ -133,7 +107,6 @@ TEST_F(OptimizationGuidePermissionsUtilTest,
optimization_guide::features::
kContextMenuPerformanceInfoAndRemoteHintFetching},
{});
- SetDataSaverEnabled(false);
SetUrlKeyedAnonymizedDataCollectionEnabled(false);
EXPECT_TRUE(IsUserPermittedToFetchFromRemoteOptimizationGuide(
@@ -150,7 +123,6 @@ TEST_F(OptimizationGuidePermissionsUtilTest,
optimization_guide::features::
kContextMenuPerformanceInfoAndRemoteHintFetching},
{});
- SetDataSaverEnabled(true);
SetUrlKeyedAnonymizedDataCollectionEnabled(true);
EXPECT_FALSE(IsUserPermittedToFetchFromRemoteOptimizationGuide(
diff --git a/chromium/components/optimization_guide/core/optimization_guide_store.cc b/chromium/components/optimization_guide/core/optimization_guide_store.cc
index 97a50f7812a..7b99acaa5ad 100644
--- a/chromium/components/optimization_guide/core/optimization_guide_store.cc
+++ b/chromium/components/optimization_guide/core/optimization_guide_store.cc
@@ -3,10 +3,13 @@
// found in the LICENSE file.
#include "components/optimization_guide/core/optimization_guide_store.h"
+#include <memory>
+#include <string>
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/files/file_util.h"
+#include "base/logging.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/sequence_checker.h"
@@ -17,9 +20,11 @@
#include "components/leveldb_proto/public/proto_database_provider.h"
#include "components/leveldb_proto/public/shared_proto_database_client_list.h"
#include "components/optimization_guide/core/memory_hint.h"
+#include "components/optimization_guide/core/model_util.h"
#include "components/optimization_guide/core/optimization_guide_features.h"
#include "components/optimization_guide/core/optimization_guide_util.h"
#include "components/optimization_guide/proto/hint_cache.pb.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
namespace optimization_guide {
@@ -62,9 +67,7 @@ enum class OptimizationGuideHintCacheLevelDBStoreLoadMetadataResult {
// recorded when it goes out of scope and its destructor is called.
class ScopedLoadMetadataResultRecorder {
public:
- ScopedLoadMetadataResultRecorder()
- : result_(OptimizationGuideHintCacheLevelDBStoreLoadMetadataResult::
- kSuccess) {}
+ ScopedLoadMetadataResultRecorder() = default;
~ScopedLoadMetadataResultRecorder() {
UMA_HISTOGRAM_ENUMERATION(
"OptimizationGuide.HintCacheLevelDBStore.LoadMetadataResult", result_);
@@ -76,7 +79,8 @@ class ScopedLoadMetadataResultRecorder {
}
private:
- OptimizationGuideHintCacheLevelDBStoreLoadMetadataResult result_;
+ OptimizationGuideHintCacheLevelDBStoreLoadMetadataResult result_ =
+ OptimizationGuideHintCacheLevelDBStoreLoadMetadataResult::kSuccess;
};
void RecordStatusChange(OptimizationGuideStore::Status status) {
@@ -289,20 +293,6 @@ void OptimizationGuideStore::PurgeExpiredFetchedHints() {
weak_ptr_factory_.GetWeakPtr()));
}
-void OptimizationGuideStore::PurgeExpiredHostModelFeatures() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
- if (!IsAvailable())
- return;
-
- // Load all the host model features to check their expiry times.
- database_->LoadKeysAndEntriesWithFilter(
- base::BindRepeating(&DatabasePrefixFilter,
- GetHostModelFeaturesEntryKeyPrefix()),
- base::BindOnce(&OptimizationGuideStore::OnLoadEntriesToPurgeExpired,
- weak_ptr_factory_.GetWeakPtr()));
-}
-
void OptimizationGuideStore::PurgeInactiveModels() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -453,14 +443,6 @@ base::Time OptimizationGuideStore::GetFetchedHintsUpdateTime() const {
return fetched_update_time_;
}
-base::Time OptimizationGuideStore::GetHostModelFeaturesUpdateTime() const {
- // If the store is not available, the metadata entries have not been loaded
- // so there are no host model features.
- if (!IsAvailable())
- return base::Time();
- return host_model_features_update_time_;
-}
-
// static
const char OptimizationGuideStore::kStoreSchemaVersion[] = "1";
@@ -530,14 +512,6 @@ OptimizationGuideStore::GetOptimizationTargetFromPredictionModelEntryKey(
return static_cast<proto::OptimizationTarget>(optimization_target_number);
}
-// static
-OptimizationGuideStore::EntryKeyPrefix
-OptimizationGuideStore::GetHostModelFeaturesEntryKeyPrefix() {
- return base::NumberToString(static_cast<int>(
- OptimizationGuideStore::StoreEntryType::kHostModelFeatures)) +
- kKeySectionDelimiter;
-}
-
void OptimizationGuideStore::UpdateStatus(Status new_status) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -780,24 +754,6 @@ void OptimizationGuideStore::OnLoadMetadata(
fetched_update_time_ = base::Time();
}
- auto host_model_features_entry = metadata_entries->find(
- GetMetadataTypeEntryKey(MetadataType::kHostModelFeatures));
- bool host_model_features_metadata_loaded = false;
- host_model_features_update_time_ = base::Time();
- if (host_model_features_entry != metadata_entries->end()) {
- DCHECK(host_model_features_entry->second.has_update_time_secs());
- host_model_features_update_time_ = base::Time::FromDeltaSinceWindowsEpoch(
- base::Seconds(host_model_features_entry->second.update_time_secs()));
- host_model_features_metadata_loaded = true;
- }
- // TODO(crbug/1001194): Metrics should be separated so that stores maintaining
- // different information types only record metrics for the types of entries
- // they store.
- UMA_HISTOGRAM_BOOLEAN(
- "OptimizationGuide.PredictionModelStore."
- "HostModelFeaturesLoadMetadataResult",
- host_model_features_metadata_loaded);
-
UpdateStatus(Status::kAvailable);
MaybeLoadEntryKeys(std::move(callback));
}
@@ -963,14 +919,30 @@ void OptimizationGuideStore::OnLoadModelsToBeUpdated(
bool had_entries_to_update_or_remove =
!update_vector->empty() || !remove_vector->empty();
for (const auto& entry : *entries) {
- bool should_delete_download_file = had_entries_to_update_or_remove;
+ absl::optional<std::string> delete_download_file;
+ if (had_entries_to_update_or_remove &&
+ entry.second.has_prediction_model() &&
+ !entry.second.prediction_model().model().download_url().empty()) {
+ delete_download_file =
+ entry.second.prediction_model().model().download_url();
+ }
+
// Only check expiry if we weren't explicitly passed in entries to update or
// remove.
if (!had_entries_to_update_or_remove) {
+ if (entry.second.keep_beyond_valid_duration()) {
+ continue;
+ }
if (entry.second.has_expiry_time_secs()) {
if (entry.second.expiry_time_secs() <= now_since_epoch) {
+ // Update the entry to remove the model.
+ if (entry.second.has_prediction_model() &&
+ !entry.second.prediction_model().model().download_url().empty()) {
+ delete_download_file =
+ entry.second.prediction_model().model().download_url();
+ }
+
remove_vector->push_back(entry.first);
- should_delete_download_file = true;
proto::OptimizationTarget optimization_target =
GetOptimizationTargetFromPredictionModelEntryKey(entry.first);
base::UmaHistogramBoolean(
@@ -984,20 +956,17 @@ void OptimizationGuideStore::OnLoadModelsToBeUpdated(
update_vector->push_back(entry);
update_vector->back().second.set_expiry_time_secs(
now_since_epoch +
- features::StoredModelsInactiveDuration().InSeconds());
+ features::StoredModelsValidDuration().InSeconds());
}
}
// Delete files (the model itself and any additional files) that are
// provided by the model in its directory.
- if (should_delete_download_file && entry.second.has_prediction_model() &&
- !entry.second.prediction_model().model().download_url().empty()) {
- // |GetFilePathFromPredictionModel| only returns nullopt when
- // |model().download_url()| is empty.
+ if (delete_download_file) {
+ // |StringToFilePath| only returns nullopt when
+ // |delete_download_file| is empty.
base::FilePath model_file_path =
- StringToFilePath(
- entry.second.prediction_model().model().download_url())
- .value();
+ StringToFilePath(*delete_download_file).value();
base::FilePath path_to_delete;
// Backwards compatibility: Once upon a time (<M93), model files were
@@ -1043,9 +1012,8 @@ bool OptimizationGuideStore::FindPredictionModelEntryKey(
*out_prediction_model_entry_key =
GetPredictionModelEntryKeyPrefix() +
base::NumberToString(static_cast<int>(optimization_target));
- if (entry_keys_->find(*out_prediction_model_entry_key) != entry_keys_->end())
- return true;
- return false;
+ return entry_keys_->find(*out_prediction_model_entry_key) !=
+ entry_keys_->end();
}
bool OptimizationGuideStore::RemovePredictionModelFromEntryKey(
@@ -1107,6 +1075,17 @@ void OptimizationGuideStore::OnLoadPredictionModel(
std::move(callback).Run(std::move(loaded_prediction_model));
return;
}
+ // Also ensure that nothing is returned if the model is expired.
+ int64_t now_since_epoch =
+ base::Time::Now().ToDeltaSinceWindowsEpoch().InSeconds();
+ if (!entry->keep_beyond_valid_duration() &&
+ entry->expiry_time_secs() <= now_since_epoch) {
+ // Leave the actual model deletions to |PurgeInactiveModels| and return
+ // early.
+ std::unique_ptr<proto::PredictionModel> loaded_prediction_model(nullptr);
+ std::move(callback).Run(std::move(loaded_prediction_model));
+ return;
+ }
std::unique_ptr<proto::PredictionModel> loaded_prediction_model(
entry->release_prediction_model());
@@ -1166,167 +1145,4 @@ void OptimizationGuideStore::OnModelFilePathVerified(
std::move(callback).Run(nullptr);
}
-std::unique_ptr<StoreUpdateData>
-OptimizationGuideStore::CreateUpdateDataForHostModelFeatures(
- base::Time host_model_features_update_time,
- base::Time expiry_time) const {
- // Create and returns a StoreUpdateData object. This object has host model
- // features from the GetModelsResponse moved into and organizes them in a
- // format usable by the store. The object will be stored with
- // UpdateHostModelFeatures().
- return StoreUpdateData::CreateHostModelFeaturesStoreUpdateData(
- host_model_features_update_time, expiry_time);
-}
-
-void OptimizationGuideStore::UpdateHostModelFeatures(
- std::unique_ptr<StoreUpdateData> host_model_features_update_data,
- base::OnceClosure callback) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK(host_model_features_update_data->update_time());
-
- if (!IsAvailable()) {
- std::move(callback).Run();
- return;
- }
-
- host_model_features_update_time_ =
- *host_model_features_update_data->update_time();
-
- entry_keys_.reset();
-
- // This will remove the host model features metadata entry and insert all the
- // entries currently in |host_model_features_update_data|.
- database_->UpdateEntriesWithRemoveFilter(
- host_model_features_update_data->TakeUpdateEntries(),
- base::BindRepeating(
- &DatabasePrefixFilter,
- GetMetadataTypeEntryKey(MetadataType::kHostModelFeatures)),
- base::BindOnce(&OptimizationGuideStore::OnUpdateStore,
- weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
-}
-
-bool OptimizationGuideStore::FindHostModelFeaturesEntryKey(
- const std::string& host,
- OptimizationGuideStore::EntryKey* out_host_model_features_entry_key) const {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
- if (!entry_keys_)
- return false;
-
- return FindEntryKeyForHostWithPrefix(host, out_host_model_features_entry_key,
- GetHostModelFeaturesEntryKeyPrefix());
-}
-
-void OptimizationGuideStore::LoadAllHostModelFeatures(
- AllHostModelFeaturesLoadedCallback callback) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
- if (!IsAvailable()) {
- std::move(callback).Run({});
- return;
- }
-
- // Load all the host model features within the store.
- database_->LoadEntriesWithFilter(
- base::BindRepeating(&DatabasePrefixFilter,
- GetHostModelFeaturesEntryKeyPrefix()),
- base::BindOnce(&OptimizationGuideStore::OnLoadAllHostModelFeatures,
- weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
-}
-
-void OptimizationGuideStore::LoadHostModelFeatures(
- const EntryKey& host_model_features_entry_key,
- HostModelFeaturesLoadedCallback callback) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
- if (!IsAvailable()) {
- std::move(callback).Run({});
- return;
- }
-
- // Load all the host model features within the store.
- database_->GetEntry(
- host_model_features_entry_key,
- base::BindOnce(&OptimizationGuideStore::OnLoadHostModelFeatures,
- weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
-}
-
-void OptimizationGuideStore::OnLoadHostModelFeatures(
- HostModelFeaturesLoadedCallback callback,
- bool success,
- std::unique_ptr<proto::StoreEntry> entry) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
- // If either the request failed or the store was set to unavailable after the
- // request was started, then the loaded host model features should not
- // be considered valid. Reset the entry so that nothing is returned to the
- // requester.
- if (!success || !IsAvailable()) {
- entry.reset();
- }
- if (!entry || !entry->has_host_model_features()) {
- std::move(callback).Run(nullptr);
- return;
- }
-
- std::unique_ptr<proto::HostModelFeatures> loaded_host_model_features(
- entry->release_host_model_features());
- std::move(callback).Run(std::move(loaded_host_model_features));
-}
-
-void OptimizationGuideStore::OnLoadAllHostModelFeatures(
- AllHostModelFeaturesLoadedCallback callback,
- bool success,
- std::unique_ptr<std::vector<proto::StoreEntry>> entries) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
- // If either the request failed or the store was set to unavailable after the
- // request was started, then the loaded host model features should not
- // be considered valid. Reset the entry so that nothing is returned to the
- // requester.
- if (!success || !IsAvailable()) {
- entries.reset();
- }
-
- if (!entries || entries->size() == 0) {
- std::unique_ptr<std::vector<proto::HostModelFeatures>>
- loaded_host_model_features(nullptr);
- std::move(callback).Run(std::move(loaded_host_model_features));
- return;
- }
-
- std::unique_ptr<std::vector<proto::HostModelFeatures>>
- loaded_host_model_features =
- std::make_unique<std::vector<proto::HostModelFeatures>>();
- for (auto& entry : *entries.get()) {
- if (!entry.has_host_model_features())
- continue;
- loaded_host_model_features->emplace_back(entry.host_model_features());
- }
- std::move(callback).Run(std::move(loaded_host_model_features));
-}
-
-void OptimizationGuideStore::ClearHostModelFeaturesFromDatabase() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
- base::UmaHistogramBoolean(
- "OptimizationGuide.ClearHostModelFeatures.StoreAvailable", IsAvailable());
- if (!IsAvailable())
- return;
-
- auto entries_to_save = std::make_unique<EntryVector>();
-
- entry_keys_.reset();
-
- // Removes all |kHostModelFeatures| store entries. OnUpdateStore will handle
- // updating status and re-filling entry_keys with the entries still in the
- // store.
- database_->UpdateEntriesWithRemoveFilter(
- std::move(entries_to_save), // this should be empty.
- base::BindRepeating(&DatabasePrefixFilter,
- GetHostModelFeaturesEntryKeyPrefix()),
- base::BindOnce(&OptimizationGuideStore::OnUpdateStore,
- weak_ptr_factory_.GetWeakPtr(), base::DoNothing()));
-}
-
} // namespace optimization_guide
diff --git a/chromium/components/optimization_guide/core/optimization_guide_store.h b/chromium/components/optimization_guide/core/optimization_guide_store.h
index 2b7a51f85af..38b70f16814 100644
--- a/chromium/components/optimization_guide/core/optimization_guide_store.h
+++ b/chromium/components/optimization_guide/core/optimization_guide_store.h
@@ -40,10 +40,6 @@ class OptimizationGuideStore {
base::OnceCallback<void(const std::string&, std::unique_ptr<MemoryHint>)>;
using PredictionModelLoadedCallback =
base::OnceCallback<void(std::unique_ptr<proto::PredictionModel>)>;
- using HostModelFeaturesLoadedCallback =
- base::OnceCallback<void(std::unique_ptr<proto::HostModelFeatures>)>;
- using AllHostModelFeaturesLoadedCallback = base::OnceCallback<void(
- std::unique_ptr<std::vector<proto::HostModelFeatures>>)>;
using EntryKey = std::string;
using StoreEntryProtoDatabase =
leveldb_proto::ProtoDatabase<proto::StoreEntry>;
@@ -80,16 +76,14 @@ class OptimizationGuideStore {
// cannot be changed, but new types can be added to the end.
// StoreEntryType should remain synchronized with the
// HintCacheStoreEntryType in enums.xml.
- // Also ensure to add to the OptimizationGuide.StoreEntryTypes histogram
- // suffixes if adding a new one.
enum class StoreEntryType {
kEmpty = 0,
kMetadata = 1,
kComponentHint = 2,
kFetchedHint = 3,
kPredictionModel = 4,
- kHostModelFeatures = 5,
- kMaxValue = kHostModelFeatures,
+ kDeprecatedHostModelFeatures = 5, // deprecated.
+ kMaxValue = kDeprecatedHostModelFeatures,
};
OptimizationGuideStore(
@@ -172,13 +166,9 @@ class OptimizationGuideStore {
// removed.
void PurgeExpiredFetchedHints();
- // Removes all host model features that have expired from the store.
- // |entry_keys_| is updated after the expired host model features are
- // removed.
- void PurgeExpiredHostModelFeatures();
-
// Removes all models that have not been loaded in the max inactive duration
// configured. |entry_keys| is updated after the inactive models are removed.
+ // Respects models' |keep_beyond_valid_duration| setting.
void PurgeInactiveModels();
// Creates and returns a StoreUpdateData object for Prediction Models. This
@@ -196,9 +186,9 @@ class OptimizationGuideStore {
std::unique_ptr<StoreUpdateData> prediction_models_update_data,
base::OnceClosure callback);
- // Finds the entry key for the prediction model if it is known to the store.
- // Returns true if an entry key is found and |out_prediction_model_entry_key|
- // is populated with the matching key.
+ // Finds the entry key for the prediction model if it is still valid in the
+ // store. Returns true if an entry key is valid and
+ // |out_prediction_model_entry_key| is populated with any matching key.
// Virtualized for testing.
virtual bool FindPredictionModelEntryKey(
proto::OptimizationTarget optimization_target,
@@ -218,60 +208,11 @@ class OptimizationGuideStore {
// false otherwise.
bool RemovePredictionModelFromEntryKey(const EntryKey& entry_key);
- // Creates and returns a StoreUpdateData object for host model features. This
- // object is used to collect a batch of host model features in a format that
- // is usable to update the store on a background thread. This is always
- // created when host model features have been successfully fetched from the
- // remote Optimization Guide Service so the store can update old host model
- // features.
- std::unique_ptr<StoreUpdateData> CreateUpdateDataForHostModelFeatures(
- base::Time host_model_features_update_time,
- base::Time expiry_time) const;
-
- // Updates the host model features contained in the store. The callback is run
- // asynchronously after the database stores the host model features.
- // Virtualized for testing.
- virtual void UpdateHostModelFeatures(
- std::unique_ptr<StoreUpdateData> host_model_features_update_data,
- base::OnceClosure callback);
-
- // Finds the entry key for the host model features for |host| if it is known
- // to the store. Returns true if an entry key is found and
- // |out_host_model_features_entry_key| is populated with the matching key.
- bool FindHostModelFeaturesEntryKey(
- const std::string& host,
- OptimizationGuideStore::EntryKey* out_host_model_features_entry_key)
- const;
-
- // Loads the host model features specified by |host_model_features_entry_key|.
- // After the load finishes, the host model features data is passed to
- // |callback|. In the case where the host model features cannot be loaded, the
- // callback is run with a nullptr. Depending on the load result, the callback
- // may be synchronous or asynchronous.
- void LoadHostModelFeatures(const EntryKey& host_model_features_entry_key,
- HostModelFeaturesLoadedCallback callback);
-
- // Loads all the host model features known to the store. After the load
- // finishes, the host model features data is passed back to |callback|. In the
- // case where the host model features cannot be loaded, the callback is run
- // with a nullptr. Depending on the load result, the callback may be
- // synchronous or asynchronous.
- // Virtualized for testing.
- virtual void LoadAllHostModelFeatures(
- AllHostModelFeaturesLoadedCallback callback);
-
- // Returns the time that the host model features in the store can be updated.
- // If |this| is not available, base::Time() is returned.
- base::Time GetHostModelFeaturesUpdateTime() const;
-
// Removes fetched hints whose keys are in |hint_keys| and runs |on_success|
// if successful, otherwise the callback is not run.
void RemoveFetchedHintsByKey(base::OnceClosure on_success,
const base::flat_set<std::string>& hint_keys);
- // Clears all host model features from the database and resets the entry keys.
- void ClearHostModelFeaturesFromDatabase();
-
// Returns true if the current status is Status::kAvailable.
bool IsAvailable() const;
@@ -304,7 +245,7 @@ class OptimizationGuideStore {
kSchema = 1,
kComponent = 2,
kFetched = 3,
- kHostModelFeatures = 4,
+ kDeprecatedHostModelFeatures = 4, // deprecated.
};
// Current schema version of the hint cache store. When this is changed,
@@ -331,9 +272,6 @@ class OptimizationGuideStore {
// Returns prefix of the key of every prediction model entry: "4_".
static EntryKeyPrefix GetPredictionModelEntryKeyPrefix();
- // Returns prefix of the key of every host model features entry: "5_".
- static EntryKeyPrefix GetHostModelFeaturesEntryKeyPrefix();
-
// Returns the OptimizationTarget from |prediction_model_entry_key|.
static proto::OptimizationTarget
GetOptimizationTargetFromPredictionModelEntryKey(
@@ -466,29 +404,6 @@ class OptimizationGuideStore {
PredictionModelLoadedCallback callback,
bool success);
- // Callback that runs after a host model features entry is loaded from the
- // database. If there's currently an in-flight update, then the data could be
- // invalidated, so loaded host model features data is discarded. Otherwise,
- // the host model features are released into the callback, allowing the caller
- // to own the host model features without copying it. Regardless of the
- // success or failure of retrieving the key, the callback always runs (it
- // simply runs with a nullptr on failure).
- void OnLoadHostModelFeatures(HostModelFeaturesLoadedCallback callback,
- bool success,
- std::unique_ptr<proto::StoreEntry> entry);
-
- // Callback that runs after all the host model features entries are loaded
- // from the database. If there's currently an in-flight update, then the data
- // could be invalidated, so loaded host model features data is discarded.
- // Otherwise, the host model features are released into the callback, allowing
- // the caller to own the host model features without copying it. Regardless of
- // the success or failure of retrieving the key, the callback always runs (it
- // simply runs with a nullptr on failure).
- void OnLoadAllHostModelFeatures(
- AllHostModelFeaturesLoadedCallback callback,
- bool success,
- std::unique_ptr<std::vector<proto::StoreEntry>> entry);
-
// Proto database used by the store.
std::unique_ptr<StoreEntryProtoDatabase> database_;
diff --git a/chromium/components/optimization_guide/core/optimization_guide_store_unittest.cc b/chromium/components/optimization_guide/core/optimization_guide_store_unittest.cc
index bf60d8a865d..6baa370ec39 100644
--- a/chromium/components/optimization_guide/core/optimization_guide_store_unittest.cc
+++ b/chromium/components/optimization_guide/core/optimization_guide_store_unittest.cc
@@ -15,6 +15,7 @@
#include "base/test/metrics/histogram_tester.h"
#include "base/test/task_environment.h"
#include "components/leveldb_proto/testing/fake_db.h"
+#include "components/optimization_guide/core/model_util.h"
#include "components/optimization_guide/core/optimization_guide_features.h"
#include "components/optimization_guide/core/optimization_guide_util.h"
#include "components/optimization_guide/core/store_update_data.h"
@@ -60,8 +61,8 @@ std::unique_ptr<proto::PredictionModel> CreatePredictionModel() {
model_info->set_version(1);
model_info->set_optimization_target(
proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD);
- model_info->add_supported_model_types(
- proto::ModelType::MODEL_TYPE_DECISION_TREE);
+ model_info->add_supported_model_engine_versions(
+ proto::ModelEngineVersion::MODEL_ENGINE_VERSION_DECISION_TREE);
return prediction_model;
}
@@ -87,8 +88,6 @@ class OptimizationGuideStoreTest : public testing::Test {
MetadataSchemaState state,
absl::optional<size_t> component_hint_count = absl::optional<size_t>(),
absl::optional<base::Time> fetched_hints_update =
- absl::optional<base::Time>(),
- absl::optional<base::Time> host_model_features_update =
absl::optional<base::Time>()) {
db_store_.clear();
@@ -135,13 +134,6 @@ class OptimizationGuideStoreTest : public testing::Test {
.set_update_time_secs(
fetched_hints_update->ToDeltaSinceWindowsEpoch().InSeconds());
}
- if (host_model_features_update) {
- db_store_[OptimizationGuideStore::GetMetadataTypeEntryKey(
- OptimizationGuideStore::MetadataType::kHostModelFeatures)]
- .set_update_time_secs(
- host_model_features_update->ToDeltaSinceWindowsEpoch()
- .InSeconds());
- }
}
// Moves the specified number of component hints into the update data.
@@ -176,38 +168,27 @@ class OptimizationGuideStoreTest : public testing::Test {
StoreUpdateData* update_data,
optimization_guide::proto::OptimizationTarget optimization_target,
absl::optional<base::FilePath> model_file_path = absl::nullopt,
- base::flat_set<base::FilePath> additional_file_paths = {}) {
+ absl::optional<proto::ModelInfo> info = absl::nullopt,
+ absl::optional<base::Time> expiry_time = absl::nullopt) {
std::unique_ptr<optimization_guide::proto::PredictionModel>
prediction_model = CreatePredictionModel();
+ if (info)
+ prediction_model->mutable_model_info()->MergeFrom(*info);
prediction_model->mutable_model_info()->set_optimization_target(
optimization_target);
+ if (expiry_time) {
+ auto diff = expiry_time.value() - base::Time::Now();
+ prediction_model->mutable_model_info()
+ ->mutable_valid_duration()
+ ->set_seconds(diff.InSeconds());
+ }
if (model_file_path) {
prediction_model->mutable_model()->set_download_url(
FilePathToString(*model_file_path));
}
- for (const base::FilePath& additional_file : additional_file_paths) {
- prediction_model->mutable_model_info()
- ->add_additional_files()
- ->set_file_path(FilePathToString(additional_file));
- }
update_data->CopyPredictionModelIntoUpdateData(*prediction_model);
}
- // Moves |host_model_features_count| into |update_data|.
- void SeedHostModelFeaturesUpdateData(StoreUpdateData* update_data,
- size_t host_model_features_count) {
- for (size_t i = 0; i < host_model_features_count; i++) {
- std::string host = GetHost(i);
- proto::HostModelFeatures host_model_features;
- proto::ModelFeature* model_feature =
- host_model_features.add_model_features();
- model_feature->set_feature_name("host_feat1");
- model_feature->set_double_value(2.0);
- host_model_features.set_host(host);
- update_data->CopyHostModelFeaturesIntoUpdateData(host_model_features);
- }
- }
-
void CreateDatabase() {
// Reset everything.
db_ = nullptr;
@@ -304,35 +285,12 @@ class OptimizationGuideStoreTest : public testing::Test {
}
}
- void UpdateHostModelFeatures(
- std::unique_ptr<StoreUpdateData> host_model_features_data,
- bool update_success = true,
- bool load_host_model_features_entry_keys_success = true) {
- EXPECT_CALL(*this, OnUpdateStore());
- guide_store()->UpdateHostModelFeatures(
- std::move(host_model_features_data),
- base::BindOnce(&OptimizationGuideStoreTest::OnUpdateStore,
- base::Unretained(this)));
- // OnUpdateStore callback
- db()->UpdateCallback(update_success);
- if (update_success) {
- // OnLoadEntryKeys callback
- db()->LoadCallback(load_host_model_features_entry_keys_success);
- }
- }
-
void ClearFetchedHintsFromDatabase() {
guide_store()->ClearFetchedHintsFromDatabase();
db()->UpdateCallback(true);
db()->LoadCallback(true);
}
- void ClearHostModelFeaturesFromDatabase() {
- guide_store()->ClearHostModelFeaturesFromDatabase();
- db()->UpdateCallback(true);
- db()->LoadCallback(true);
- }
-
void PurgeExpiredFetchedHints() {
guide_store()->PurgeExpiredFetchedHints();
@@ -344,17 +302,6 @@ class OptimizationGuideStoreTest : public testing::Test {
db()->LoadCallback(true);
}
- void PurgeExpiredHostModelFeatures() {
- guide_store()->PurgeExpiredHostModelFeatures();
-
- // OnLoadExpiredEntriesToPurge
- db()->LoadCallback(true);
- // OnUpdateStore
- db()->UpdateCallback(true);
- // OnLoadEntryKeys callback
- db()->LoadCallback(true);
- }
-
void PurgeInactiveModels() {
guide_store()->PurgeInactiveModels();
@@ -388,23 +335,6 @@ class OptimizationGuideStoreTest : public testing::Test {
}
}
- // Verifies that the host model features metadata has the expected next update
- // time.
- void ExpectHostModelFeaturesMetadata(base::Time update_time) const {
- const auto& metadata_entry =
- db_store_.find(OptimizationGuideStore::GetMetadataTypeEntryKey(
- OptimizationGuideStore::MetadataType::kHostModelFeatures));
- if (metadata_entry != db_store_.end()) {
- // The next update time should have same time up to the second as the
- // metadata entry is stored in seconds.
- EXPECT_TRUE(base::Time::FromDeltaSinceWindowsEpoch(base::Seconds(
- metadata_entry->second.update_time_secs())) -
- update_time <
- base::Seconds(1));
- } else {
- FAIL() << "No host model features metadata found";
- }
- }
// Verifies that the component metadata has the expected version and all
// expected component hints are present.
void ExpectComponentHintsPresent(const std::string& version,
@@ -458,14 +388,6 @@ class OptimizationGuideStoreTest : public testing::Test {
MemoryHint* last_loaded_hint() { return last_loaded_hint_.get(); }
- proto::HostModelFeatures* last_loaded_host_model_features() {
- return last_loaded_host_model_features_.get();
- }
-
- std::vector<proto::HostModelFeatures>* last_loaded_all_host_model_features() {
- return last_loaded_all_host_model_features_.get();
- }
-
proto::PredictionModel* last_loaded_prediction_model() {
return last_loaded_prediction_model_.get();
}
@@ -476,18 +398,6 @@ class OptimizationGuideStoreTest : public testing::Test {
last_loaded_hint_ = std::move(loaded_hint);
}
- void OnHostModelFeaturesLoaded(
- std::unique_ptr<proto::HostModelFeatures> loaded_host_model_features) {
- last_loaded_host_model_features_ = std::move(loaded_host_model_features);
- }
-
- void OnAllHostModelFeaturesLoaded(
- std::unique_ptr<std::vector<proto::HostModelFeatures>>
- loaded_all_host_model_features) {
- last_loaded_all_host_model_features_ =
- std::move(loaded_all_host_model_features);
- }
-
void OnPredictionModelLoaded(
std::unique_ptr<proto::PredictionModel> loaded_prediction_model) {
last_loaded_prediction_model_ = std::move(loaded_prediction_model);
@@ -507,9 +417,6 @@ class OptimizationGuideStoreTest : public testing::Test {
OptimizationGuideStore::EntryKey last_loaded_entry_key_;
std::unique_ptr<MemoryHint> last_loaded_hint_;
- std::unique_ptr<proto::HostModelFeatures> last_loaded_host_model_features_;
- std::unique_ptr<std::vector<proto::HostModelFeatures>>
- last_loaded_all_host_model_features_;
std::unique_ptr<proto::PredictionModel> last_loaded_prediction_model_;
};
@@ -737,10 +644,6 @@ TEST_F(OptimizationGuideStoreTest,
histogram_tester.ExpectBucketCount(
"OptimizationGuide.HintCacheLevelDBStore.LoadMetadataResult",
0 /* kSuccess */, 1);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.PredictionModelStore."
- "HostModelFeaturesLoadMetadataResult",
- false, 1);
histogram_tester.ExpectBucketCount(
"OptimizationGuide.HintCacheLevelDBStore.Status", 0 /* kUninitialized */,
@@ -839,11 +742,6 @@ TEST_F(OptimizationGuideStoreTest, InitializeSucceededWithValidSchemaEntry) {
6 /* kComponentAndFetchedMetadataMissing*/, 1);
histogram_tester.ExpectBucketCount(
- "OptimizationGuide.PredictionModelStore."
- "HostModelFeaturesLoadMetadataResult",
- false, 1);
-
- histogram_tester.ExpectBucketCount(
"OptimizationGuide.HintCacheLevelDBStore.Status", 0 /* kUninitialized */,
1);
histogram_tester.ExpectBucketCount(
@@ -901,9 +799,6 @@ TEST_F(OptimizationGuideStoreTest, InitializeSucceededWithPurgeExistingData) {
EXPECT_TRUE(IsMetadataSchemaEntryKeyPresent());
- histogram_tester.ExpectTotalCount(
- "OptimizationGuide.HintCacheLevelDBStore.LoadMetadataResult", 0);
-
histogram_tester.ExpectBucketCount(
"OptimizationGuide.HintCacheLevelDBStore.Status", 0 /* kUninitialized */,
1);
@@ -923,15 +818,14 @@ TEST_F(OptimizationGuideStoreTest,
MetadataSchemaState schema_state = MetadataSchemaState::kValid;
size_t component_hint_count = 10;
SeedInitialData(schema_state, component_hint_count,
- base::Time().Now(), /* fetch_update_time */
- base::Time().Now() /* host_model_features_update_time */);
+ base::Time().Now() /* fetch_update_time */);
CreateDatabase();
InitializeStore(schema_state);
// The store should contain the schema metadata entry, the component metadata
// entry, and all of the initial component hints.
EXPECT_EQ(GetDBStoreEntryCount(),
- static_cast<size_t>(component_hint_count + 4));
+ static_cast<size_t>(component_hint_count + 3));
EXPECT_EQ(GetStoreEntryKeyCount(), component_hint_count);
EXPECT_TRUE(IsMetadataSchemaEntryKeyPresent());
@@ -942,11 +836,6 @@ TEST_F(OptimizationGuideStoreTest,
0 /* kSuccess */, 1);
histogram_tester.ExpectBucketCount(
- "OptimizationGuide.PredictionModelStore."
- "HostModelFeaturesLoadMetadataResult",
- true, 1);
-
- histogram_tester.ExpectBucketCount(
"OptimizationGuide.HintCacheLevelDBStore.Status", 0 /* kUninitialized */,
1);
histogram_tester.ExpectBucketCount(
@@ -988,11 +877,6 @@ TEST_F(OptimizationGuideStoreTest,
6 /* kComponentAndFetchedMetadataMissing*/, 0);
histogram_tester.ExpectBucketCount(
- "OptimizationGuide.PredictionModelStore."
- "HostModelFeaturesLoadMetadataResult",
- false, 1);
-
- histogram_tester.ExpectBucketCount(
"OptimizationGuide.HintCacheLevelDBStore.Status", 0 /* kUninitialized */,
1);
histogram_tester.ExpectBucketCount(
@@ -1027,11 +911,6 @@ TEST_F(OptimizationGuideStoreTest,
4 /* kComponentMetadataMissing*/, 1);
histogram_tester.ExpectBucketCount(
- "OptimizationGuide.PredictionModelStore."
- "HostModelFeaturesLoadMetadataResult",
- false, 1);
-
- histogram_tester.ExpectBucketCount(
"OptimizationGuide.HintCacheLevelDBStore.Status", 0 /* kUninitialized */,
1);
histogram_tester.ExpectBucketCount(
@@ -1945,7 +1824,7 @@ TEST_F(OptimizationGuideStoreTest, FindPredictionModelEntryKey) {
std::unique_ptr<StoreUpdateData> update_data =
guide_store()->CreateUpdateDataForPredictionModels(
update_time +
- optimization_guide::features::StoredModelsInactiveDuration());
+ optimization_guide::features::StoredModelsValidDuration());
ASSERT_TRUE(update_data);
SeedPredictionModelUpdateData(update_data.get(),
proto::OPTIMIZATION_TARGET_UNKNOWN);
@@ -1971,7 +1850,7 @@ TEST_F(OptimizationGuideStoreTest,
std::unique_ptr<StoreUpdateData> update_data =
guide_store()->CreateUpdateDataForPredictionModels(
update_time +
- optimization_guide::features::StoredModelsInactiveDuration());
+ optimization_guide::features::StoredModelsValidDuration());
ASSERT_TRUE(update_data);
SeedPredictionModelUpdateData(update_data.get(),
proto::OPTIMIZATION_TARGET_UNKNOWN);
@@ -1994,7 +1873,7 @@ TEST_F(OptimizationGuideStoreTest, FindAndRemovePredictionModelEntryKey) {
std::unique_ptr<StoreUpdateData> update_data =
guide_store()->CreateUpdateDataForPredictionModels(
update_time +
- optimization_guide::features::StoredModelsInactiveDuration());
+ optimization_guide::features::StoredModelsValidDuration());
ASSERT_TRUE(update_data);
SeedPredictionModelUpdateData(update_data.get(),
proto::OPTIMIZATION_TARGET_UNKNOWN);
@@ -2034,7 +1913,7 @@ TEST_F(OptimizationGuideStoreTest, LoadPredictionModel) {
std::unique_ptr<StoreUpdateData> update_data =
guide_store()->CreateUpdateDataForPredictionModels(
update_time +
- optimization_guide::features::StoredModelsInactiveDuration());
+ optimization_guide::features::StoredModelsValidDuration());
ASSERT_TRUE(update_data);
SeedPredictionModelUpdateData(update_data.get(),
proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD);
@@ -2076,6 +1955,46 @@ TEST_F(OptimizationGuideStoreTest, LoadPredictionModelOnUnavailableStore) {
EXPECT_FALSE(last_loaded_prediction_model());
}
+TEST_F(OptimizationGuideStoreTest, LoadPredictionModelOnExpiredModel) {
+ base::HistogramTester histogram_tester;
+ size_t initial_hint_count = 10;
+ MetadataSchemaState schema_state = MetadataSchemaState::kValid;
+ SeedInitialData(schema_state, initial_hint_count);
+ CreateDatabase();
+ InitializeStore(schema_state);
+
+ // Add an update with models that are "inactive".
+ base::Time update_time = base::Time().Now();
+ std::unique_ptr<StoreUpdateData> update_data =
+ guide_store()->CreateUpdateDataForPredictionModels(
+ update_time -
+ optimization_guide::features::StoredModelsValidDuration());
+ ASSERT_TRUE(update_data);
+ SeedPredictionModelUpdateData(
+ update_data.get(), proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD,
+ /*model_file_path=*/absl::nullopt,
+ /*info=*/{},
+ update_time - optimization_guide::features::StoredModelsValidDuration());
+ UpdatePredictionModels(std::move(update_data));
+ // Since models haven't been purged yet it will initially show up as valid.
+ OptimizationGuideStore::EntryKey entry_key;
+ EXPECT_TRUE(guide_store()->FindPredictionModelEntryKey(
+ proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD, &entry_key));
+ guide_store()->LoadPredictionModel(
+ entry_key,
+ base::BindOnce(&OptimizationGuideStoreTest::OnPredictionModelLoaded,
+ base::Unretained(this)));
+ // OnPredictionModelLoaded callback
+ db()->GetCallback(true);
+ // After load completes, the key will still exist until after purge.
+ EXPECT_TRUE(guide_store()->FindPredictionModelEntryKey(
+ proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD, &entry_key));
+
+ // Verify that the OnPredictionModelLoaded callback runs when the store is
+ // unavailable and that the prediction model was correctly not available.
+ EXPECT_FALSE(last_loaded_prediction_model());
+}
+
TEST_F(OptimizationGuideStoreTest, LoadPredictionModelWithUpdateInFlight) {
base::HistogramTester histogram_tester;
MetadataSchemaState schema_state = MetadataSchemaState::kValid;
@@ -2087,7 +2006,7 @@ TEST_F(OptimizationGuideStoreTest, LoadPredictionModelWithUpdateInFlight) {
std::unique_ptr<StoreUpdateData> update_data =
guide_store()->CreateUpdateDataForPredictionModels(
update_time +
- optimization_guide::features::StoredModelsInactiveDuration());
+ optimization_guide::features::StoredModelsValidDuration());
ASSERT_TRUE(update_data);
SeedPredictionModelUpdateData(update_data.get(),
proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD);
@@ -2117,7 +2036,7 @@ TEST_F(OptimizationGuideStoreTest,
std::unique_ptr<StoreUpdateData> update_data =
guide_store()->CreateUpdateDataForPredictionModels(
update_time +
- optimization_guide::features::StoredModelsInactiveDuration());
+ optimization_guide::features::StoredModelsValidDuration());
ASSERT_TRUE(update_data);
SeedPredictionModelUpdateData(update_data.get(),
proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD,
@@ -2164,7 +2083,7 @@ TEST_F(OptimizationGuideStoreTest,
std::unique_ptr<StoreUpdateData> update_data =
guide_store()->CreateUpdateDataForPredictionModels(
update_time +
- optimization_guide::features::StoredModelsInactiveDuration());
+ optimization_guide::features::StoredModelsValidDuration());
ASSERT_TRUE(update_data);
base::FilePath model_file_path = temp_dir().AppendASCII("model.tflite");
@@ -2173,9 +2092,12 @@ TEST_F(OptimizationGuideStoreTest,
base::FilePath additional_file_path = temp_dir().AppendASCII("doesntexist");
- SeedPredictionModelUpdateData(
- update_data.get(), proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD,
- temp_dir().AppendASCII("doesntexist"), {additional_file_path});
+ proto::ModelInfo info;
+ info.add_additional_files()->set_file_path(
+ FilePathToString(additional_file_path));
+ SeedPredictionModelUpdateData(update_data.get(),
+ proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD,
+ temp_dir().AppendASCII("doesntexist"), info);
UpdatePredictionModels(std::move(update_data));
OptimizationGuideStore::EntryKey entry_key;
@@ -2221,7 +2143,7 @@ TEST_F(OptimizationGuideStoreTest,
std::unique_ptr<StoreUpdateData> update_data =
guide_store()->CreateUpdateDataForPredictionModels(
update_time +
- optimization_guide::features::StoredModelsInactiveDuration());
+ optimization_guide::features::StoredModelsValidDuration());
ASSERT_TRUE(update_data);
base::FilePath model_file_path = temp_dir().AppendASCII("model.tflite");
@@ -2232,10 +2154,12 @@ TEST_F(OptimizationGuideStoreTest,
temp_dir().AppendASCII("additional_file.txt");
ASSERT_EQ(static_cast<int32_t>(3),
base::WriteFile(additional_file_path, "ah!", 3));
-
+ proto::ModelInfo info;
+ info.add_additional_files()->set_file_path(
+ FilePathToString(additional_file_path));
SeedPredictionModelUpdateData(update_data.get(),
proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD,
- model_file_path, {additional_file_path});
+ model_file_path, info);
UpdatePredictionModels(std::move(update_data));
OptimizationGuideStore::EntryKey entry_key;
@@ -2277,7 +2201,7 @@ TEST_F(OptimizationGuideStoreTest,
std::unique_ptr<StoreUpdateData> update_data =
guide_store()->CreateUpdateDataForPredictionModels(
update_time +
- optimization_guide::features::StoredModelsInactiveDuration());
+ optimization_guide::features::StoredModelsValidDuration());
ASSERT_TRUE(update_data);
base::FilePath file_path = temp_dir().AppendASCII("file");
ASSERT_EQ(static_cast<int32_t>(3), base::WriteFile(file_path, "boo", 3));
@@ -2324,7 +2248,7 @@ TEST_F(OptimizationGuideStoreTest, UpdatePredictionModelsDeletesOldFile) {
std::unique_ptr<StoreUpdateData> update_data =
guide_store()->CreateUpdateDataForPredictionModels(
update_time +
- optimization_guide::features::StoredModelsInactiveDuration());
+ optimization_guide::features::StoredModelsValidDuration());
ASSERT_TRUE(update_data);
base::FilePath old_file_path = old_dir.AppendASCII("model.tflite");
ASSERT_EQ(static_cast<int32_t>(3), base::WriteFile(old_file_path, "boo", 3));
@@ -2341,7 +2265,7 @@ TEST_F(OptimizationGuideStoreTest, UpdatePredictionModelsDeletesOldFile) {
std::unique_ptr<StoreUpdateData> update_data2 =
guide_store()->CreateUpdateDataForPredictionModels(
update_time +
- optimization_guide::features::StoredModelsInactiveDuration());
+ optimization_guide::features::StoredModelsValidDuration());
ASSERT_TRUE(update_data2);
base::FilePath new_file_path = new_dir.AppendASCII("model.tflite");
ASSERT_EQ(static_cast<int32_t>(3), base::WriteFile(new_file_path, "boo", 3));
@@ -2380,7 +2304,7 @@ TEST_F(OptimizationGuideStoreTest,
std::unique_ptr<StoreUpdateData> update_data =
guide_store()->CreateUpdateDataForPredictionModels(
update_time +
- optimization_guide::features::StoredModelsInactiveDuration());
+ optimization_guide::features::StoredModelsValidDuration());
ASSERT_TRUE(update_data);
base::FilePath old_file_path = old_dir.AppendASCII("model_v1.tflite");
ASSERT_EQ(static_cast<int32_t>(3), base::WriteFile(old_file_path, "boo", 3));
@@ -2397,7 +2321,7 @@ TEST_F(OptimizationGuideStoreTest,
std::unique_ptr<StoreUpdateData> update_data2 =
guide_store()->CreateUpdateDataForPredictionModels(
update_time +
- optimization_guide::features::StoredModelsInactiveDuration());
+ optimization_guide::features::StoredModelsValidDuration());
ASSERT_TRUE(update_data2);
base::FilePath new_file_path = new_dir.Append(GetBaseFileNameForModels());
ASSERT_EQ(static_cast<int32_t>(3), base::WriteFile(new_file_path, "boo", 3));
@@ -2429,7 +2353,7 @@ TEST_F(OptimizationGuideStoreTest, RemovePredictionModelEntryKeyDeletesFile) {
std::unique_ptr<StoreUpdateData> update_data =
guide_store()->CreateUpdateDataForPredictionModels(
update_time +
- optimization_guide::features::StoredModelsInactiveDuration());
+ optimization_guide::features::StoredModelsValidDuration());
ASSERT_TRUE(update_data);
base::FilePath file_path = temp_dir().AppendASCII("file");
ASSERT_EQ(static_cast<int32_t>(3), base::WriteFile(file_path, "boo", 3));
@@ -2460,203 +2384,79 @@ TEST_F(OptimizationGuideStoreTest, RemovePredictionModelEntryKeyDeletesFile) {
EXPECT_FALSE(base::PathExists(file_path));
}
-TEST_F(OptimizationGuideStoreTest, HostModelFeaturesMetadataStored) {
- MetadataSchemaState schema_state = MetadataSchemaState::kValid;
- base::Time update_time = base::Time().Now();
- SeedInitialData(schema_state, 10, update_time,
- base::Time().Now() /* host_model_features_update_time */);
- CreateDatabase();
- InitializeStore(schema_state);
-
- ExpectHostModelFeaturesMetadata(update_time);
-}
-
-TEST_F(OptimizationGuideStoreTest, FindEntryKeyForHostModelFeatures) {
- MetadataSchemaState schema_state = MetadataSchemaState::kValid;
- size_t update_host_model_features_count = 5;
- base::Time update_time = base::Time().Now();
- SeedInitialData(schema_state, 0,
- base::Time().Now() /* host_model_features_update_time */);
- CreateDatabase();
- InitializeStore(schema_state);
-
- std::unique_ptr<StoreUpdateData> update_data =
- guide_store()->CreateUpdateDataForHostModelFeatures(
- update_time, update_time +
- optimization_guide::features::
- StoredHostModelFeaturesFreshnessDuration());
- ASSERT_TRUE(update_data);
- SeedHostModelFeaturesUpdateData(update_data.get(),
- update_host_model_features_count);
- UpdateHostModelFeatures(std::move(update_data));
-
- for (size_t i = 0; i < update_host_model_features_count; ++i) {
- std::string host = GetHost(i);
- OptimizationGuideStore::EntryKey entry_key;
- bool success =
- guide_store()->FindHostModelFeaturesEntryKey(host, &entry_key);
- EXPECT_EQ(success, i < update_host_model_features_count);
- }
-}
-
-TEST_F(OptimizationGuideStoreTest, LoadHostModelFeaturesForHost) {
+TEST_F(OptimizationGuideStoreTest, PurgeInactiveModels) {
base::HistogramTester histogram_tester;
- size_t update_host_model_features_count = 5;
- MetadataSchemaState schema_state = MetadataSchemaState::kValid;
- base::Time update_time = base::Time().Now();
- SeedInitialData(schema_state, 0, base::Time().Now());
- CreateDatabase();
- InitializeStore(schema_state);
-
- std::unique_ptr<StoreUpdateData> update_data =
- guide_store()->CreateUpdateDataForHostModelFeatures(
- update_time, update_time +
- optimization_guide::features::
- StoredHostModelFeaturesFreshnessDuration());
- ASSERT_TRUE(update_data);
- SeedHostModelFeaturesUpdateData(update_data.get(),
- update_host_model_features_count);
- UpdateHostModelFeatures(std::move(update_data));
-
- for (size_t i = 0; i < update_host_model_features_count; ++i) {
- std::string host = GetHost(i);
- OptimizationGuideStore::EntryKey entry_key;
- bool success =
- guide_store()->FindHostModelFeaturesEntryKey(host, &entry_key);
- EXPECT_TRUE(success);
-
- guide_store()->LoadHostModelFeatures(
- entry_key,
- base::BindOnce(&OptimizationGuideStoreTest::OnHostModelFeaturesLoaded,
- base::Unretained(this)));
- // OnPredictionModelLoaded callback
- db()->GetCallback(true);
-
- if (!last_loaded_host_model_features()) {
- FAIL() << "Loaded host model features was null for entry key: "
- << entry_key;
- }
-
- EXPECT_EQ(last_loaded_host_model_features()->host(), host);
- }
-}
-
-TEST_F(OptimizationGuideStoreTest, LoadAllHostModelFeatures) {
- base::HistogramTester histogram_tester;
- size_t update_host_model_features_count = 5;
MetadataSchemaState schema_state = MetadataSchemaState::kValid;
- base::Time update_time = base::Time().Now();
- SeedInitialData(schema_state, 0, base::Time().Now());
+ SeedInitialData(schema_state, 0);
CreateDatabase();
InitializeStore(schema_state);
- std::unique_ptr<StoreUpdateData> update_data =
- guide_store()->CreateUpdateDataForHostModelFeatures(
- update_time, update_time +
- optimization_guide::features::
- StoredHostModelFeaturesFreshnessDuration());
- ASSERT_TRUE(update_data);
- SeedHostModelFeaturesUpdateData(update_data.get(),
- update_host_model_features_count);
- UpdateHostModelFeatures(std::move(update_data));
- guide_store()->LoadAllHostModelFeatures(
- base::BindOnce(&OptimizationGuideStoreTest::OnAllHostModelFeaturesLoaded,
- base::Unretained(this)));
-
- // OnAllHostModelFeaturesLoaded callback
- db()->LoadCallback(true);
-
- std::vector<proto::HostModelFeatures>* all_host_model_features =
- last_loaded_all_host_model_features();
- EXPECT_TRUE(all_host_model_features);
- EXPECT_EQ(update_host_model_features_count, all_host_model_features->size());
-
- // Build a list of the hosts that are stored in the store.
- base::flat_set<std::string> hosts = {};
- for (size_t i = 0; i < update_host_model_features_count; i++)
- hosts.insert(GetHost(i));
-
- // Make sure all of the hosts of the host model features are returned.
- for (const auto& host_model_features : *all_host_model_features)
- EXPECT_NE(hosts.find(host_model_features.host()), hosts.end());
-}
-
-TEST_F(OptimizationGuideStoreTest, ClearHostModelFeatures) {
- base::HistogramTester histogram_tester;
- size_t update_host_model_features_count = 5;
- MetadataSchemaState schema_state = MetadataSchemaState::kValid;
+ // Add an update with models that are "inactive".
base::Time update_time = base::Time().Now();
- SeedInitialData(schema_state, 0, base::Time().Now());
- CreateDatabase();
- InitializeStore(schema_state);
-
std::unique_ptr<StoreUpdateData> update_data =
- guide_store()->CreateUpdateDataForHostModelFeatures(
- update_time, update_time +
- optimization_guide::features::
- StoredHostModelFeaturesFreshnessDuration());
+ guide_store()->CreateUpdateDataForPredictionModels(
+ update_time -
+ optimization_guide::features::StoredModelsValidDuration());
ASSERT_TRUE(update_data);
- SeedHostModelFeaturesUpdateData(update_data.get(),
- update_host_model_features_count);
- UpdateHostModelFeatures(std::move(update_data));
-
- for (size_t i = 0; i < update_host_model_features_count; ++i) {
- std::string host = GetHost(i);
- OptimizationGuideStore::EntryKey entry_key;
- EXPECT_TRUE(guide_store()->FindHostModelFeaturesEntryKey(host, &entry_key));
- }
+ base::FilePath old_file_path = temp_dir().AppendASCII("model_v1.tflite");
+ ASSERT_EQ(static_cast<int32_t>(3), base::WriteFile(old_file_path, "boo", 3));
+ SeedPredictionModelUpdateData(
+ update_data.get(), proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD,
+ old_file_path,
+ /*info=*/{},
+ update_time - optimization_guide::features::StoredModelsValidDuration());
+ UpdatePredictionModels(std::move(update_data));
- // Remove the host model features from the OptimizationGuideStore.
- ClearHostModelFeaturesFromDatabase();
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.ClearHostModelFeatures.StoreAvailable", true, 1);
+ // Add an update with models that are "active".
+ std::unique_ptr<StoreUpdateData> update_data2 =
+ guide_store()->CreateUpdateDataForPredictionModels(
+ update_time +
+ optimization_guide::features::StoredModelsValidDuration());
+ ASSERT_TRUE(update_data2);
+ SeedPredictionModelUpdateData(update_data2.get(),
+ proto::OPTIMIZATION_TARGET_LANGUAGE_DETECTION);
+ UpdatePredictionModels(std::move(update_data2));
- for (size_t i = 0; i < update_host_model_features_count; ++i) {
- std::string host = GetHost(i);
- OptimizationGuideStore::EntryKey entry_key;
- EXPECT_FALSE(
- guide_store()->FindHostModelFeaturesEntryKey(host, &entry_key));
- }
-}
+ // Make sure both models are in the store.
+ OptimizationGuideStore::EntryKey entry_key;
+ bool success = guide_store()->FindPredictionModelEntryKey(
+ proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD, &entry_key);
+ ASSERT_TRUE(success);
+ success = guide_store()->FindPredictionModelEntryKey(
+ proto::OPTIMIZATION_TARGET_LANGUAGE_DETECTION, &entry_key);
+ ASSERT_TRUE(success);
-TEST_F(OptimizationGuideStoreTest, PurgeExpiredHostModelFeatures) {
- base::HistogramTester histogram_tester;
- size_t update_host_model_features_count = 5;
- MetadataSchemaState schema_state = MetadataSchemaState::kValid;
- base::Time update_time = base::Time().Now();
- SeedInitialData(schema_state, 0, base::Time().Now());
- CreateDatabase();
- InitializeStore(schema_state);
+ PurgeInactiveModels();
+ RunUntilIdle();
+ // The expired model should be removed.
+ EXPECT_FALSE(guide_store()->FindPredictionModelEntryKey(
+ proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD, &entry_key));
+ EXPECT_FALSE(base::PathExists(old_file_path));
- std::unique_ptr<StoreUpdateData> update_data =
- guide_store()->CreateUpdateDataForHostModelFeatures(
- update_time, update_time -
- optimization_guide::features::
- StoredHostModelFeaturesFreshnessDuration());
- ASSERT_TRUE(update_data);
- SeedHostModelFeaturesUpdateData(update_data.get(),
- update_host_model_features_count);
- UpdateHostModelFeatures(std::move(update_data));
+ // Should not purge models that are still active.
+ EXPECT_TRUE(guide_store()->FindPredictionModelEntryKey(
+ proto::OPTIMIZATION_TARGET_LANGUAGE_DETECTION, &entry_key));
- for (size_t i = 0; i < update_host_model_features_count; ++i) {
- std::string host = GetHost(i);
- OptimizationGuideStore::EntryKey entry_key;
- EXPECT_TRUE(guide_store()->FindHostModelFeaturesEntryKey(host, &entry_key));
- }
+ histogram_tester.ExpectUniqueSample(
+ "OptimizationGuide.PredictionModelExpired.PainfulPageLoad", true, 1);
+ histogram_tester.ExpectTotalCount(
+ "OptimizationGuide.PredictionModelExpired.LanguageDetection", 0);
+}
- // Remove expired host model features from the opt. guide store.
- PurgeExpiredHostModelFeatures();
+struct ValidityTestCase {
+ std::string test_name;
+ bool keep_beyond_valid_duration;
+ bool initially_expired;
+ bool expect_kept;
+};
- for (size_t i = 0; i < update_host_model_features_count; ++i) {
- std::string host = GetHost(i);
- OptimizationGuideStore::EntryKey entry_key;
- EXPECT_FALSE(
- guide_store()->FindHostModelFeaturesEntryKey(host, &entry_key));
- }
-}
+class OptimizationGuideStoreValidityTest
+ : public OptimizationGuideStoreTest,
+ public ::testing::WithParamInterface<ValidityTestCase> {};
-TEST_F(OptimizationGuideStoreTest, PurgeInactiveModels) {
+TEST_P(OptimizationGuideStoreValidityTest, PurgeInactiveModels) {
+ const ValidityTestCase& test_case = GetParam();
base::HistogramTester histogram_tester;
MetadataSchemaState schema_state = MetadataSchemaState::kValid;
@@ -2664,22 +2464,30 @@ TEST_F(OptimizationGuideStoreTest, PurgeInactiveModels) {
CreateDatabase();
InitializeStore(schema_state);
- // Add an update with models that are "inactive".
+ // Add an update with one model according to ValidityTestCase settings.
base::Time update_time = base::Time().Now();
+ if (test_case.initially_expired) {
+ update_time -= optimization_guide::features::StoredModelsValidDuration();
+ } else {
+ update_time += optimization_guide::features::StoredModelsValidDuration();
+ }
std::unique_ptr<StoreUpdateData> update_data =
- guide_store()->CreateUpdateDataForPredictionModels(
- update_time -
- optimization_guide::features::StoredModelsInactiveDuration());
+ guide_store()->CreateUpdateDataForPredictionModels(update_time);
ASSERT_TRUE(update_data);
+ proto::ModelInfo info;
+ info.set_keep_beyond_valid_duration(test_case.keep_beyond_valid_duration);
+ base::FilePath old_file_path = temp_dir().AppendASCII("model_v1.tflite");
+ ASSERT_EQ(static_cast<int32_t>(3), base::WriteFile(old_file_path, "boo", 3));
SeedPredictionModelUpdateData(update_data.get(),
- proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD);
+ proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD,
+ old_file_path, info, update_time);
UpdatePredictionModels(std::move(update_data));
- // Add an update with models that are "active".
+ // Add an update with models that are "active" and should be unaffected.
std::unique_ptr<StoreUpdateData> update_data2 =
guide_store()->CreateUpdateDataForPredictionModels(
- update_time +
- optimization_guide::features::StoredModelsInactiveDuration());
+ base::Time().Now() +
+ optimization_guide::features::StoredModelsValidDuration());
ASSERT_TRUE(update_data2);
SeedPredictionModelUpdateData(update_data2.get(),
proto::OPTIMIZATION_TARGET_LANGUAGE_DETECTION);
@@ -2690,22 +2498,67 @@ TEST_F(OptimizationGuideStoreTest, PurgeInactiveModels) {
bool success = guide_store()->FindPredictionModelEntryKey(
proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD, &entry_key);
ASSERT_TRUE(success);
+ EXPECT_TRUE(base::PathExists(old_file_path));
+
success = guide_store()->FindPredictionModelEntryKey(
proto::OPTIMIZATION_TARGET_LANGUAGE_DETECTION, &entry_key);
ASSERT_TRUE(success);
PurgeInactiveModels();
-
- EXPECT_FALSE(guide_store()->FindPredictionModelEntryKey(
- proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD, &entry_key));
- // Should not purge models that are still active.
+ RunUntilIdle();
+ // Verify that the model file, entry key and histogram match expectations for
+ // PageLoad.
+ EXPECT_EQ(test_case.expect_kept,
+ guide_store()->FindPredictionModelEntryKey(
+ proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD, &entry_key));
+ EXPECT_EQ(test_case.expect_kept, base::PathExists(old_file_path));
+
+ if (test_case.expect_kept) {
+ histogram_tester.ExpectTotalCount(
+ "OptimizationGuide.PredictionModelExpired.PainfulPageLoad", 0);
+ } else {
+ histogram_tester.ExpectTotalCount(
+ "OptimizationGuide.PredictionModelExpired.PainfulPageLoad", 1);
+ }
+ // Verify that the other model is not deleted.
EXPECT_TRUE(guide_store()->FindPredictionModelEntryKey(
proto::OPTIMIZATION_TARGET_LANGUAGE_DETECTION, &entry_key));
-
- histogram_tester.ExpectUniqueSample(
- "OptimizationGuide.PredictionModelExpired.PainfulPageLoad", true, 1);
histogram_tester.ExpectTotalCount(
"OptimizationGuide.PredictionModelExpired.LanguageDetection", 0);
}
+INSTANTIATE_TEST_SUITE_P(
+ OptimizationGuideStoreValidityTests,
+ OptimizationGuideStoreValidityTest,
+ testing::ValuesIn<ValidityTestCase>({
+ {
+ "KeepDespiteInvalidModel",
+ /*keep_beyond_valid_duration=*/true,
+ /*initially_expired=*/true,
+ /*expect_kept=*/true,
+ },
+ {
+ "KeepAndInitiallyValid",
+ /*keep_beyond_valid_duration=*/true,
+ /*initially_expired=*/false,
+ /*expect_kept=*/true,
+ },
+ {
+ "DeleteAndInitiallyValid",
+ /*keep_beyond_valid_duration=*/false,
+ /*initially_expired=*/false,
+ /*expect_kept=*/true,
+ },
+ // Only in this case should the model be removed.
+ {
+ "DeleteAndInvalidModel",
+ /*keep_beyond_valid_duration=*/false,
+ /*initially_expired=*/true,
+ /*expect_kept=*/false,
+ },
+ }),
+ [](const testing::TestParamInfo<
+ OptimizationGuideStoreValidityTest::ParamType>& info) {
+ return info.param.test_name;
+ });
} // namespace optimization_guide
diff --git a/chromium/components/optimization_guide/core/optimization_guide_switches.cc b/chromium/components/optimization_guide/core/optimization_guide_switches.cc
index 8c55155bf31..e2026ddc1cf 100644
--- a/chromium/components/optimization_guide/core/optimization_guide_switches.cc
+++ b/chromium/components/optimization_guide/core/optimization_guide_switches.cc
@@ -27,12 +27,6 @@ const char kHintsProtoOverride[] = "optimization_guide_hints_override";
// hosts.
const char kFetchHintsOverride[] = "optimization-guide-fetch-hints-override";
-// Overrides scheduling and time delays for fetching prediction models and host
-// model features. This causes a prediction model and host model features fetch
-// immediately on start up.
-const char kFetchModelsAndHostModelFeaturesOverrideTimer[] =
- "optimization-guide-fetch-models-and-features-override";
-
// Overrides the hints fetch scheduling and delay, causing a hints fetch
// immediately on start up using the TopHostProvider. This is meant for testing.
const char kFetchHintsOverrideTimer[] =
@@ -87,6 +81,14 @@ const char kModelOverride[] = "optimization-guide-model-override";
// Triggers validation of the model. Used for manual testing.
const char kModelValidate[] = "optimization-guide-model-validate";
+// Prevents any models from being executing when in annotating a batch
+// of visits. This is used for testing only.
+const char kStopHistoryVisitBatchAnnotateForTesting[] =
+ "stop-history-visit-batch-annotate";
+
+const char kPageContentAnnotationsLoggingEnabled[] =
+ "enable-page-content-annotations-logging";
+
bool IsHintComponentProcessingDisabled() {
return base::CommandLine::ForCurrentProcess()->HasSwitch(kHintsProtoOverride);
}
@@ -134,11 +136,6 @@ bool ShouldOverrideFetchHintsTimer() {
kFetchHintsOverrideTimer);
}
-bool ShouldOverrideFetchModelsAndFeaturesTimer() {
- return base::CommandLine::ForCurrentProcess()->HasSwitch(
- kFetchModelsAndHostModelFeaturesOverrideTimer);
-}
-
std::unique_ptr<optimization_guide::proto::Configuration>
ParseComponentConfigFromCommandLine() {
base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
@@ -191,7 +188,7 @@ bool ShouldValidateModel() {
}
absl::optional<std::string> GetModelOverride() {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// TODO(crbug/1227996): The parsing below is not supported on Windows because
// ':' is used as a delimiter, but this must be used in the absolute file path
// on Windows.
@@ -206,5 +203,17 @@ absl::optional<std::string> GetModelOverride() {
#endif
}
+bool StopHistoryVisitBatchAnnotateForTesting() {
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+ if (command_line->HasSwitch(kStopHistoryVisitBatchAnnotateForTesting))
+ return true;
+ return false;
+}
+
+bool ShouldLogPageContentAnnotationsInput() {
+ return base::CommandLine::ForCurrentProcess()->HasSwitch(
+ kPageContentAnnotationsLoggingEnabled);
+}
+
} // namespace switches
} // namespace optimization_guide
diff --git a/chromium/components/optimization_guide/core/optimization_guide_switches.h b/chromium/components/optimization_guide/core/optimization_guide_switches.h
index 188d06c574b..c7e80ceeabb 100644
--- a/chromium/components/optimization_guide/core/optimization_guide_switches.h
+++ b/chromium/components/optimization_guide/core/optimization_guide_switches.h
@@ -22,7 +22,6 @@ namespace switches {
extern const char kHintsProtoOverride[];
extern const char kFetchHintsOverride[];
extern const char kFetchHintsOverrideTimer[];
-extern const char kFetchModelsAndHostModelFeaturesOverrideTimer[];
extern const char kOptimizationGuideServiceGetHintsURL[];
extern const char kOptimizationGuideServiceGetModelsURL[];
extern const char kOptimizationGuideServiceAPIKey[];
@@ -34,6 +33,8 @@ extern const char kDisableModelDownloadVerificationForTesting[];
extern const char kModelOverride[];
extern const char kDebugLoggingEnabled[];
extern const char kModelValidate[];
+extern const char kStopHistoryVisitBatchAnnotateForTesting[];
+extern const char kPageContentAnnotationsLoggingEnabled[];
// Returns whether the hint component should be processed.
// Available hint components are only processed if a proto override isn't being
@@ -58,10 +59,6 @@ ParseHintsFetchOverrideFromCommandLine();
// Whether the hints fetcher timer should be overridden.
bool ShouldOverrideFetchHintsTimer();
-// Whether the prediction model and host model features fetcher timer should be
-// overridden.
-bool ShouldOverrideFetchModelsAndFeaturesTimer();
-
// Attempts to parse a base64 encoded Optimization Guide Configuration proto
// from the command line. If no proto is given or if it is encoded incorrectly,
// nullptr is returned.
@@ -92,6 +89,13 @@ absl::optional<std::string> GetModelOverride();
// Returns true if debug logs are enabled for the optimization guide.
bool IsDebugLogsEnabled();
+// Whether to prevent annotations from happening when in a batch. For testing
+// purposes only.
+bool StopHistoryVisitBatchAnnotateForTesting();
+
+// Returns true if page content annotations input should be logged.
+bool ShouldLogPageContentAnnotationsInput();
+
} // namespace switches
} // namespace optimization_guide
diff --git a/chromium/components/optimization_guide/core/optimization_guide_switches_unittest.cc b/chromium/components/optimization_guide/core/optimization_guide_switches_unittest.cc
index ab401708455..267633cb400 100644
--- a/chromium/components/optimization_guide/core/optimization_guide_switches_unittest.cc
+++ b/chromium/components/optimization_guide/core/optimization_guide_switches_unittest.cc
@@ -14,7 +14,7 @@
namespace optimization_guide {
namespace switches {
-#if !defined(OS_WIN)
+#if !BUILDFLAG(IS_WIN)
TEST(OptimizationGuideSwitchesTest, ParseHintsFetchOverrideFromCommandLine) {
base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(kFetchHintsOverride,
diff --git a/chromium/components/optimization_guide/core/optimization_guide_test_util.cc b/chromium/components/optimization_guide/core/optimization_guide_test_util.cc
index f1e88b67197..e349570a811 100644
--- a/chromium/components/optimization_guide/core/optimization_guide_test_util.cc
+++ b/chromium/components/optimization_guide/core/optimization_guide_test_util.cc
@@ -9,7 +9,7 @@
namespace optimization_guide {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
const char kTestAbsoluteFilePath[] = "C:\\absolute/file/path";
const char kTestRelativeFilePath[] = "relative/file/path";
#else
diff --git a/chromium/components/optimization_guide/core/optimization_guide_util.cc b/chromium/components/optimization_guide/core/optimization_guide_util.cc
index 392f806ac5a..15acd17ad35 100644
--- a/chromium/components/optimization_guide/core/optimization_guide_util.cc
+++ b/chromium/components/optimization_guide/core/optimization_guide_util.cc
@@ -19,50 +19,6 @@
namespace optimization_guide {
-// These names are persisted to histograms, so don't change them.
-std::string GetStringNameForOptimizationTarget(
- optimization_guide::proto::OptimizationTarget optimization_target) {
- switch (optimization_target) {
- case proto::OPTIMIZATION_TARGET_UNKNOWN:
- return "Unknown";
- case proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD:
- return "PainfulPageLoad";
- case proto::OPTIMIZATION_TARGET_LANGUAGE_DETECTION:
- return "LanguageDetection";
- case proto::OPTIMIZATION_TARGET_PAGE_TOPICS:
- return "PageTopics";
- case proto::OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB:
- return "SegmentationNewTab";
- case proto::OPTIMIZATION_TARGET_SEGMENTATION_SHARE:
- return "SegmentationShare";
- case proto::OPTIMIZATION_TARGET_SEGMENTATION_VOICE:
- return "SegmentationVoice";
- case proto::OPTIMIZATION_TARGET_MODEL_VALIDATION:
- return "ModelValidation";
- case proto::OPTIMIZATION_TARGET_PAGE_ENTITIES:
- return "PageEntities";
- case proto::OPTIMIZATION_TARGET_NOTIFICATION_PERMISSION_PREDICTIONS:
- return "NotificationPermissions";
- case proto::OPTIMIZATION_TARGET_SEGMENTATION_DUMMY:
- return "SegmentationDummyFeature";
- case proto::OPTIMIZATION_TARGET_SEGMENTATION_CHROME_START_ANDROID:
- return "SegmentationChromeStartAndroid";
- case proto::OPTIMIZATION_TARGET_SEGMENTATION_QUERY_TILES:
- return "SegmentationQueryTiles";
- case proto::OPTIMIZATION_TARGET_PAGE_VISIBILITY:
- return "PageVisibility";
- case proto::OPTIMIZATION_TARGET_AUTOFILL_ASSISTANT:
- return "AutofillAssistant";
- case proto::OPTIMIZATION_TARGET_PAGE_TOPICS_V2:
- return "PageTopicsV2";
- // Whenever a new value is added, make sure to add it to the OptTarget
- // variant list in
- // //tools/metrics/histograms/metadata/optimization/histograms.xml.
- }
- NOTREACHED();
- return std::string();
-}
-
bool IsHostValidToFetchFromRemoteOptimizationGuide(const std::string& host) {
if (net::HostStringIsLocalhost(host))
return false;
@@ -108,29 +64,6 @@ GetActiveFieldTrialsAllowedForFetch() {
return filtered_active_field_trials;
}
-absl::optional<base::FilePath> StringToFilePath(const std::string& str_path) {
- if (str_path.empty())
- return absl::nullopt;
-
-#if defined(OS_WIN)
- return base::FilePath(base::UTF8ToWide(str_path));
-#else
- return base::FilePath(str_path);
-#endif
-}
-
-std::string FilePathToString(const base::FilePath& file_path) {
-#if defined(OS_WIN)
- return base::WideToUTF8(file_path.value());
-#else
- return file_path.value();
-#endif
-}
-
-base::FilePath GetBaseFileNameForModels() {
- return base::FilePath(FILE_PATH_LITERAL("model.tflite"));
-}
-
std::string GetStringForOptimizationGuideDecision(
OptimizationGuideDecision decision) {
switch (decision) {
@@ -149,7 +82,7 @@ absl::optional<
std::pair<std::string, absl::optional<optimization_guide::proto::Any>>>
GetModelOverrideForOptimizationTarget(
optimization_guide::proto::OptimizationTarget optimization_target) {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// TODO(crbug/1227996): The parsing below is not supported on Windows because
// ':' is used as a delimiter, but this must be used in the absolute file path
// on Windows.
diff --git a/chromium/components/optimization_guide/core/optimization_guide_util.h b/chromium/components/optimization_guide/core/optimization_guide_util.h
index f425dde56a1..90b70f34bc1 100644
--- a/chromium/components/optimization_guide/core/optimization_guide_util.h
+++ b/chromium/components/optimization_guide/core/optimization_guide_util.h
@@ -7,24 +7,28 @@
#include <string>
-#include "base/files/file_path.h"
#include "base/strings/string_split.h"
+#include "base/time/time.h"
#include "components/optimization_guide/core/optimization_guide_enums.h"
#include "components/optimization_guide/proto/common_types.pb.h"
#include "components/optimization_guide/proto/models.pb.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
+#define OPTIMIZATION_GUIDE_LOG(optimization_guide_logger, message) \
+ do { \
+ if (optimization_guide_logger && \
+ optimization_guide_logger->ShouldEnableDebugLogs()) { \
+ optimization_guide_logger->OnLogMessageAdded( \
+ base::Time::Now(), __FILE__, __LINE__, message); \
+ } \
+ if (optimization_guide::switches::IsDebugLogsEnabled()) \
+ DVLOG(0) << message; \
+ } while (0)
+
namespace optimization_guide {
enum class OptimizationGuideDecision;
-// Returns the string than can be used to record histograms for the optimization
-// target. If adding a histogram to use the string or adding an optimization
-// target, update the OptimizationGuide.OptimizationTargets histogram suffixes
-// in histograms.xml.
-std::string GetStringNameForOptimizationTarget(
- proto::OptimizationTarget optimization_target);
-
// Returns false if the host is an IP address, localhosts, or an invalid
// host that is not supported by the remote optimization guide.
bool IsHostValidToFetchFromRemoteOptimizationGuide(const std::string& host);
@@ -34,18 +38,6 @@ bool IsHostValidToFetchFromRemoteOptimizationGuide(const std::string& host);
google::protobuf::RepeatedPtrField<proto::FieldTrial>
GetActiveFieldTrialsAllowedForFetch();
-// Returns the file path represented by the given string, handling platform
-// differences in the conversion. nullopt is only returned iff the passed string
-// is empty.
-absl::optional<base::FilePath> StringToFilePath(const std::string& str_path);
-
-// Returns a string representation of the given |file_path|, handling platform
-// differences in the conversion.
-std::string FilePathToString(const base::FilePath& file_path);
-
-// Returns the base file name to use for storing all prediction models.
-base::FilePath GetBaseFileNameForModels();
-
// Validates that the metadata stored in |any_metadata_| is of the same type
// and is parseable as |T|. Will return metadata if all checks pass.
template <class T,
diff --git a/chromium/components/optimization_guide/core/optimization_guide_util_unittest.cc b/chromium/components/optimization_guide/core/optimization_guide_util_unittest.cc
index 1d400833462..f3a7fee11ae 100644
--- a/chromium/components/optimization_guide/core/optimization_guide_util_unittest.cc
+++ b/chromium/components/optimization_guide/core/optimization_guide_util_unittest.cc
@@ -63,7 +63,7 @@ TEST(OptimizationGuideUtilTest, ParsedAnyMetadataTest) {
EXPECT_TRUE(parsed_subresource.preconnect_only());
}
-#if !defined(OS_WIN)
+#if !BUILDFLAG(IS_WIN)
TEST(OptimizationGuideUtilTest,
GetModelOverrideForOptimizationTargetSwitchNotSet) {
diff --git a/chromium/components/optimization_guide/core/optimization_hints_component_update_listener.cc b/chromium/components/optimization_guide/core/optimization_hints_component_update_listener.cc
index 4ea36ecd4cb..019c0d464ef 100644
--- a/chromium/components/optimization_guide/core/optimization_hints_component_update_listener.cc
+++ b/chromium/components/optimization_guide/core/optimization_hints_component_update_listener.cc
@@ -5,6 +5,7 @@
#include "components/optimization_guide/core/optimization_hints_component_update_listener.h"
#include "base/metrics/histogram_functions.h"
+#include "base/no_destructor.h"
namespace optimization_guide {
diff --git a/chromium/components/optimization_guide/core/page_content_annotation_job.cc b/chromium/components/optimization_guide/core/page_content_annotation_job.cc
index 4ac77c0091b..45104edb920 100644
--- a/chromium/components/optimization_guide/core/page_content_annotation_job.cc
+++ b/chromium/components/optimization_guide/core/page_content_annotation_job.cc
@@ -5,6 +5,7 @@
#include "components/optimization_guide/core/page_content_annotation_job.h"
#include "base/check_op.h"
+#include "base/metrics/histogram_functions.h"
namespace optimization_guide {
@@ -14,11 +15,35 @@ PageContentAnnotationJob::PageContentAnnotationJob(
AnnotationType type)
: on_complete_callback_(std::move(on_complete_callback)),
type_(type),
- inputs_(inputs.begin(), inputs.end()) {
+ inputs_(inputs.begin(), inputs.end()),
+ job_creation_time_(base::TimeTicks::Now()) {
DCHECK(!inputs_.empty());
}
-PageContentAnnotationJob::~PageContentAnnotationJob() = default;
+PageContentAnnotationJob::~PageContentAnnotationJob() {
+ if (!job_execution_start_time_)
+ return;
+
+ base::TimeDelta job_scheduling_wait_time =
+ *job_execution_start_time_ - job_creation_time_;
+ base::TimeDelta job_exec_time =
+ base::TimeTicks::Now() - *job_execution_start_time_;
+
+ base::UmaHistogramMediumTimes(
+ "OptimizationGuide.PageContentAnnotations.JobExecutionTime." +
+ AnnotationTypeToString(type()),
+ job_exec_time);
+
+ base::UmaHistogramMediumTimes(
+ "OptimizationGuide.PageContentAnnotations.JobScheduleTime." +
+ AnnotationTypeToString(type()),
+ job_scheduling_wait_time);
+
+ base::UmaHistogramBoolean(
+ "OptimizationGuide.PageContentAnnotations.BatchSuccess." +
+ AnnotationTypeToString(type()),
+ HadAnySuccess());
+}
void PageContentAnnotationJob::FillWithNullOutputs() {
while (auto input = GetNextInput()) {
@@ -59,6 +84,10 @@ size_t PageContentAnnotationJob::CountOfRemainingNonNullInputs() const {
}
absl::optional<std::string> PageContentAnnotationJob::GetNextInput() {
+ if (!job_execution_start_time_) {
+ job_execution_start_time_ = base::TimeTicks::Now();
+ }
+
if (inputs_.empty()) {
return absl::nullopt;
}
@@ -72,4 +101,20 @@ void PageContentAnnotationJob::PostNewResult(
results_.push_back(result);
}
+bool PageContentAnnotationJob::HadAnySuccess() const {
+ for (const BatchAnnotationResult& result : results_) {
+ if (result.type() == AnnotationType::kPageTopics && result.topics()) {
+ return true;
+ }
+ if (result.type() == AnnotationType::kPageEntities && result.entities()) {
+ return true;
+ }
+ if (result.type() == AnnotationType::kContentVisibility &&
+ result.visibility_score()) {
+ return true;
+ }
+ }
+ return false;
+}
+
} // namespace optimization_guide
diff --git a/chromium/components/optimization_guide/core/page_content_annotation_job.h b/chromium/components/optimization_guide/core/page_content_annotation_job.h
index 989736df1e1..9ba68090c00 100644
--- a/chromium/components/optimization_guide/core/page_content_annotation_job.h
+++ b/chromium/components/optimization_guide/core/page_content_annotation_job.h
@@ -10,6 +10,7 @@
#include <vector>
#include "base/callback.h"
+#include "base/time/time.h"
#include "components/optimization_guide/core/page_content_annotations_common.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
@@ -21,8 +22,6 @@ namespace optimization_guide {
// container that matches the I/O of a single call to the PCA Service.
class PageContentAnnotationJob {
public:
- using WeightedCategories = std::vector<WeightedString>;
-
PageContentAnnotationJob(BatchAnnotationCallback on_complete_callback,
const std::vector<std::string>& inputs,
AnnotationType type);
@@ -46,6 +45,10 @@ class PageContentAnnotationJob {
// Posts a new result after an execution has completed.
void PostNewResult(const BatchAnnotationResult& result);
+ // Returns true if any element of |results_| was a successful execution. We
+ // expect that if one result is successful, many more will be as well.
+ bool HadAnySuccess() const;
+
AnnotationType type() const { return type_; }
PageContentAnnotationJob(const PageContentAnnotationJob&) = delete;
@@ -65,6 +68,12 @@ class PageContentAnnotationJob {
// Filled by |PostNewResult| with the complete annotations, specified by
// |type_|.
std::vector<BatchAnnotationResult> results_;
+
+ // The time the job was constructed.
+ const base::TimeTicks job_creation_time_;
+
+ // Set when |GetNextInput| is called for the first time.
+ absl::optional<base::TimeTicks> job_execution_start_time_;
};
} // namespace optimization_guide
diff --git a/chromium/components/optimization_guide/core/page_content_annotation_job_executor.cc b/chromium/components/optimization_guide/core/page_content_annotation_job_executor.cc
index 38f617cef94..779524c94d2 100644
--- a/chromium/components/optimization_guide/core/page_content_annotation_job_executor.cc
+++ b/chromium/components/optimization_guide/core/page_content_annotation_job_executor.cc
@@ -73,6 +73,8 @@ void PageContentAnnotationJobExecutor::OnJobExecutionComplete(
std::unique_ptr<PageContentAnnotationJob> job) {
job->OnComplete();
// Intentionally reset |job| here to make lifetime clearer and less bug-prone.
+ // Note that the job dtor also records some timing metrics which is better to
+ // do now rather than after the following callback.
job.reset();
std::move(on_job_complete_callback_from_caller).Run();
diff --git a/chromium/components/optimization_guide/core/page_content_annotation_job_executor_unittest.cc b/chromium/components/optimization_guide/core/page_content_annotation_job_executor_unittest.cc
index d16ffb6859f..5fe0a6a48a6 100644
--- a/chromium/components/optimization_guide/core/page_content_annotation_job_executor_unittest.cc
+++ b/chromium/components/optimization_guide/core/page_content_annotation_job_executor_unittest.cc
@@ -15,7 +15,7 @@
namespace optimization_guide {
namespace {
-const std::vector<WeightedString> kOutput{WeightedString("output", 1.0)};
+const std::vector<WeightedIdentifier> kOutput{WeightedIdentifier(1337, 1.0)};
}
class TestJobExecutor : public PageContentAnnotationJobExecutor {
diff --git a/chromium/components/optimization_guide/core/page_content_annotations_common.cc b/chromium/components/optimization_guide/core/page_content_annotations_common.cc
index 08bd362e404..62f637d7443 100644
--- a/chromium/components/optimization_guide/core/page_content_annotations_common.cc
+++ b/chromium/components/optimization_guide/core/page_content_annotations_common.cc
@@ -13,6 +13,9 @@
namespace optimization_guide {
+// Each of these string values is used in UMA histograms so please update the
+// variants there when any changes are made.
+// //tools/metrics/histograms/metadata/optimization/histograms.xml
std::string AnnotationTypeToString(AnnotationType type) {
switch (type) {
case AnnotationType::kUnknown:
@@ -26,26 +29,25 @@ std::string AnnotationTypeToString(AnnotationType type) {
}
}
-WeightedString::WeightedString(const std::string& value, double weight)
+WeightedIdentifier::WeightedIdentifier(int32_t value, double weight)
: value_(value), weight_(weight) {
DCHECK_GE(weight_, 0.0);
DCHECK_LE(weight_, 1.0);
}
-WeightedString::WeightedString(const WeightedString&) = default;
-WeightedString::~WeightedString() = default;
+WeightedIdentifier::WeightedIdentifier(const WeightedIdentifier&) = default;
+WeightedIdentifier::~WeightedIdentifier() = default;
-bool WeightedString::operator==(const WeightedString& other) const {
+bool WeightedIdentifier::operator==(const WeightedIdentifier& other) const {
constexpr double kWeightTolerance = 1e-6;
return this->value_ == other.value_ &&
abs(this->weight_ - other.weight_) <= kWeightTolerance;
}
-std::string WeightedString::ToString() const {
- return base::StringPrintf("WeightedString{\"%s\",%f}", value().c_str(),
- weight());
+std::string WeightedIdentifier::ToString() const {
+ return base::StringPrintf("WeightedIdentifier{%d,%f}", value(), weight());
}
-std::ostream& operator<<(std::ostream& stream, const WeightedString& ws) {
+std::ostream& operator<<(std::ostream& stream, const WeightedIdentifier& ws) {
stream << ws.ToString();
return stream;
}
@@ -58,11 +60,11 @@ BatchAnnotationResult::~BatchAnnotationResult() = default;
std::string BatchAnnotationResult::ToString() const {
std::string output = "nullopt";
if (topics_) {
- std::vector<std::string> all_weighted_strings;
- for (const WeightedString& ws : *topics_) {
- all_weighted_strings.push_back(ws.ToString());
+ std::vector<std::string> all_weighted_ids;
+ for (const WeightedIdentifier& wi : *topics_) {
+ all_weighted_ids.push_back(wi.ToString());
}
- output = "{" + base::JoinString(all_weighted_strings, ",") + "}";
+ output = "{" + base::JoinString(all_weighted_ids, ",") + "}";
} else if (entities_) {
std::vector<std::string> all_entities;
for (const ScoredEntityMetadata& md : *entities_) {
@@ -89,7 +91,7 @@ std::ostream& operator<<(std::ostream& stream,
// static
BatchAnnotationResult BatchAnnotationResult::CreatePageTopicsResult(
const std::string& input,
- absl::optional<std::vector<WeightedString>> topics) {
+ absl::optional<std::vector<WeightedIdentifier>> topics) {
BatchAnnotationResult result;
result.input_ = input;
result.topics_ = topics;
@@ -98,7 +100,7 @@ BatchAnnotationResult BatchAnnotationResult::CreatePageTopicsResult(
// Always sort the result (if present) by the given score.
if (result.topics_) {
std::sort(result.topics_->begin(), result.topics_->end(),
- [](const WeightedString& a, const WeightedString& b) {
+ [](const WeightedIdentifier& a, const WeightedIdentifier& b) {
return a.weight() < b.weight();
});
}
diff --git a/chromium/components/optimization_guide/core/page_content_annotations_common.h b/chromium/components/optimization_guide/core/page_content_annotations_common.h
index 5679064b8d0..4f77386485c 100644
--- a/chromium/components/optimization_guide/core/page_content_annotations_common.h
+++ b/chromium/components/optimization_guide/core/page_content_annotations_common.h
@@ -15,6 +15,10 @@
namespace optimization_guide {
// The type of annotation that is being done on the given input.
+//
+// Each of these is used in UMA histograms so please update the variants there
+// when any changes are made.
+// //tools/metrics/histograms/metadata/optimization/histograms.xml
enum class AnnotationType {
kUnknown,
@@ -33,25 +37,25 @@ enum class AnnotationType {
std::string AnnotationTypeToString(AnnotationType type);
-// A weighted string value.
-class WeightedString {
+// A weighted ID value.
+class WeightedIdentifier {
public:
- WeightedString(const std::string& value, double weight);
- WeightedString(const WeightedString&);
- ~WeightedString();
+ WeightedIdentifier(int32_t value, double weight);
+ WeightedIdentifier(const WeightedIdentifier&);
+ ~WeightedIdentifier();
- std::string value() const { return value_; }
+ int32_t value() const { return value_; }
double weight() const { return weight_; }
std::string ToString() const;
- bool operator==(const WeightedString& other) const;
+ bool operator==(const WeightedIdentifier& other) const;
friend std::ostream& operator<<(std::ostream& stream,
- const WeightedString& ws);
+ const WeightedIdentifier& ws);
private:
- std::string value_;
+ int32_t value_;
// In the range of [0.0, 1.0].
double weight_ = 0;
@@ -63,7 +67,7 @@ class BatchAnnotationResult {
// Creates a result for a page topics annotation.
static BatchAnnotationResult CreatePageTopicsResult(
const std::string& input,
- absl::optional<std::vector<WeightedString>> topics);
+ absl::optional<std::vector<WeightedIdentifier>> topics);
// Creates a result for a page entities annotation.
static BatchAnnotationResult CreatePageEntitiesResult(
@@ -84,7 +88,9 @@ class BatchAnnotationResult {
std::string input() const { return input_; }
AnnotationType type() const { return type_; }
- absl::optional<std::vector<WeightedString>> topics() const { return topics_; }
+ absl::optional<std::vector<WeightedIdentifier>> topics() const {
+ return topics_;
+ }
absl::optional<std::vector<ScoredEntityMetadata>> entities() const {
return entities_;
}
@@ -105,7 +111,7 @@ class BatchAnnotationResult {
// Output for page topics annotations, set only if the |type_| matches and the
// execution was successful.
- absl::optional<std::vector<WeightedString>> topics_;
+ absl::optional<std::vector<WeightedIdentifier>> topics_;
// Output for page entities annotations, set only if the |type_| matches and
// the execution was successful.
diff --git a/chromium/components/optimization_guide/core/page_entities_model_executor.h b/chromium/components/optimization_guide/core/page_entities_model_executor.h
index 919e7b76f76..5ea55c6e243 100644
--- a/chromium/components/optimization_guide/core/page_entities_model_executor.h
+++ b/chromium/components/optimization_guide/core/page_entities_model_executor.h
@@ -15,7 +15,7 @@
namespace optimization_guide {
-// TODO(crbug/1249632): Remove this entirely.
+// TODO(crbug/1278828): Remove this entirely.
class HumanReadablePageEntitiesModelExecutor {
public:
virtual ~HumanReadablePageEntitiesModelExecutor() = default;
diff --git a/chromium/components/optimization_guide/core/page_entities_model_executor_impl.cc b/chromium/components/optimization_guide/core/page_entities_model_executor_impl.cc
new file mode 100644
index 00000000000..d3a34832f6b
--- /dev/null
+++ b/chromium/components/optimization_guide/core/page_entities_model_executor_impl.cc
@@ -0,0 +1,230 @@
+// Copyright 2022 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.
+
+#include "components/optimization_guide/core/page_entities_model_executor_impl.h"
+
+#include "base/metrics/histogram_functions.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "base/timer/elapsed_timer.h"
+#include "components/optimization_guide/core/entity_annotator_native_library.h"
+#include "components/optimization_guide/core/optimization_guide_features.h"
+#include "components/optimization_guide/core/optimization_guide_model_provider.h"
+#include "components/optimization_guide/proto/page_entities_model_metadata.pb.h"
+
+namespace optimization_guide {
+
+namespace {
+
+const char kPageEntitiesModelMetadataTypeUrl[] =
+ "type.googleapis.com/"
+ "google.internal.chrome.optimizationguide.v1.PageEntitiesModelMetadata";
+
+} // namespace
+
+EntityAnnotatorHolder::EntityAnnotatorHolder(
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner,
+ scoped_refptr<base::SequencedTaskRunner> reply_task_runner)
+ : background_task_runner_(background_task_runner),
+ reply_task_runner_(reply_task_runner) {}
+
+EntityAnnotatorHolder::~EntityAnnotatorHolder() {
+ DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
+
+ if (features::ShouldResetPageEntitiesModelOnShutdown()) {
+ ResetEntityAnnotator();
+ }
+}
+
+void EntityAnnotatorHolder::
+ InitializeEntityAnnotatorNativeLibraryOnBackgroundThread(
+ base::OnceCallback<void(int32_t)> init_callback) {
+ DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
+
+ DCHECK(!entity_annotator_native_library_);
+ if (entity_annotator_native_library_) {
+ // We should only be initialized once but in case someone does something
+ // wrong in a non-debug build, we invoke the callback anyway.
+ reply_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(
+ std::move(init_callback),
+ entity_annotator_native_library_->GetMaxSupportedFeatureFlag()));
+ return;
+ }
+
+ entity_annotator_native_library_ = EntityAnnotatorNativeLibrary::Create();
+ if (!entity_annotator_native_library_) {
+ reply_task_runner_->PostTask(FROM_HERE,
+ base::BindOnce(std::move(init_callback), -1));
+ return;
+ }
+
+ int32_t max_supported_feature_flag =
+ entity_annotator_native_library_->GetMaxSupportedFeatureFlag();
+ reply_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(std::move(init_callback), max_supported_feature_flag));
+}
+
+void EntityAnnotatorHolder::ResetEntityAnnotator() {
+ DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
+
+ if (entity_annotator_) {
+ DCHECK(entity_annotator_native_library_);
+ entity_annotator_native_library_->DeleteEntityAnnotator(entity_annotator_);
+
+ entity_annotator_ = nullptr;
+ }
+}
+
+void EntityAnnotatorHolder::CreateAndSetEntityAnnotatorOnBackgroundThread(
+ const ModelInfo& model_info) {
+ DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
+
+ if (!entity_annotator_native_library_) {
+ return;
+ }
+
+ ResetEntityAnnotator();
+
+ entity_annotator_ =
+ entity_annotator_native_library_->CreateEntityAnnotator(model_info);
+}
+
+void EntityAnnotatorHolder::AnnotateEntitiesMetadataModelOnBackgroundThread(
+ const std::string& text,
+ PageEntitiesMetadataModelExecutedCallback callback) {
+ DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
+ base::ElapsedThreadTimer annotate_timer;
+
+ absl::optional<std::vector<ScoredEntityMetadata>> scored_md;
+ if (entity_annotator_) {
+ DCHECK(entity_annotator_native_library_);
+ base::TimeTicks start_time = base::TimeTicks::Now();
+ scored_md =
+ entity_annotator_native_library_->AnnotateText(entity_annotator_, text);
+ // The max of the below histograms is 1 hour because we want to understand
+ // tail behavior and catch long running model executions.
+ base::UmaHistogramLongTimes(
+ "OptimizationGuide.PageContentAnnotationsService.ModelExecutionLatency."
+ "PageEntities",
+ base::TimeTicks::Now() - start_time);
+
+ base::UmaHistogramLongTimes(
+ "OptimizationGuide.PageContentAnnotationsService."
+ "ModelThreadExecutionLatency.PageEntities",
+ annotate_timer.Elapsed());
+ }
+ reply_task_runner_->PostTask(FROM_HERE,
+ base::BindOnce(std::move(callback), scored_md));
+}
+
+void EntityAnnotatorHolder::GetMetadataForEntityIdOnBackgroundThread(
+ const std::string& entity_id,
+ PageEntitiesModelExecutor::PageEntitiesModelEntityMetadataRetrievedCallback
+ callback) {
+ DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
+
+ absl::optional<EntityMetadata> entity_metadata;
+ if (entity_annotator_) {
+ DCHECK(entity_annotator_native_library_);
+ entity_metadata =
+ entity_annotator_native_library_->GetEntityMetadataForEntityId(
+ entity_annotator_, entity_id);
+ }
+ reply_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(std::move(callback), std::move(entity_metadata)));
+}
+
+base::WeakPtr<EntityAnnotatorHolder>
+EntityAnnotatorHolder::GetBackgroundWeakPtr() {
+ return background_weak_ptr_factory_.GetWeakPtr();
+}
+
+PageEntitiesModelExecutorImpl::PageEntitiesModelExecutorImpl(
+ OptimizationGuideModelProvider* optimization_guide_model_provider,
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner)
+ : background_task_runner_(background_task_runner),
+ entity_annotator_holder_(std::make_unique<EntityAnnotatorHolder>(
+ background_task_runner_,
+ base::SequencedTaskRunnerHandle::Get())) {
+ background_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(
+ &EntityAnnotatorHolder::
+ InitializeEntityAnnotatorNativeLibraryOnBackgroundThread,
+ entity_annotator_holder_->GetBackgroundWeakPtr(),
+ base::BindOnce(&PageEntitiesModelExecutorImpl::
+ OnEntityAnnotatorLibraryInitialized,
+ weak_ptr_factory_.GetWeakPtr(),
+ optimization_guide_model_provider)));
+}
+
+void PageEntitiesModelExecutorImpl::OnEntityAnnotatorLibraryInitialized(
+ OptimizationGuideModelProvider* optimization_guide_model_provider,
+ int32_t max_model_format_feature_flag) {
+ if (max_model_format_feature_flag <= 0) {
+ return;
+ }
+
+ proto::Any any_metadata;
+ any_metadata.set_type_url(kPageEntitiesModelMetadataTypeUrl);
+ proto::PageEntitiesModelMetadata model_metadata;
+ model_metadata.set_max_model_format_feature_flag(
+ max_model_format_feature_flag);
+ model_metadata.SerializeToString(any_metadata.mutable_value());
+ optimization_guide_model_provider->AddObserverForOptimizationTargetModel(
+ proto::OptimizationTarget::OPTIMIZATION_TARGET_PAGE_ENTITIES,
+ any_metadata, this);
+}
+
+PageEntitiesModelExecutorImpl::~PageEntitiesModelExecutorImpl() {
+ // |entity_annotator_holder_|'s WeakPtrs are used on the background thread,
+ // so that is also where the class must be destroyed.
+ background_task_runner_->DeleteSoon(FROM_HERE,
+ std::move(entity_annotator_holder_));
+}
+
+void PageEntitiesModelExecutorImpl::OnModelUpdated(
+ proto::OptimizationTarget optimization_target,
+ const ModelInfo& model_info) {
+ if (optimization_target != proto::OPTIMIZATION_TARGET_PAGE_ENTITIES)
+ return;
+
+ background_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(
+ &EntityAnnotatorHolder::CreateAndSetEntityAnnotatorOnBackgroundThread,
+ entity_annotator_holder_->GetBackgroundWeakPtr(), model_info));
+}
+
+void PageEntitiesModelExecutorImpl::HumanReadableExecuteModelWithInput(
+ const std::string& text,
+ PageEntitiesMetadataModelExecutedCallback callback) {
+ if (text.empty()) {
+ std::move(callback).Run(absl::nullopt);
+ return;
+ }
+
+ background_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(&EntityAnnotatorHolder::
+ AnnotateEntitiesMetadataModelOnBackgroundThread,
+ entity_annotator_holder_->GetBackgroundWeakPtr(), text,
+ std::move(callback)));
+}
+
+void PageEntitiesModelExecutorImpl::GetMetadataForEntityId(
+ const std::string& entity_id,
+ PageEntitiesModelEntityMetadataRetrievedCallback callback) {
+ background_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(
+ &EntityAnnotatorHolder::GetMetadataForEntityIdOnBackgroundThread,
+ entity_annotator_holder_->GetBackgroundWeakPtr(), entity_id,
+ std::move(callback)));
+}
+
+} // namespace optimization_guide
diff --git a/chromium/components/optimization_guide/core/page_entities_model_executor_impl.h b/chromium/components/optimization_guide/core/page_entities_model_executor_impl.h
new file mode 100644
index 00000000000..d39944fc261
--- /dev/null
+++ b/chromium/components/optimization_guide/core/page_entities_model_executor_impl.h
@@ -0,0 +1,115 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_OPTIMIZATION_GUIDE_CORE_PAGE_ENTITIES_MODEL_EXECUTOR_IMPL_H_
+#define COMPONENTS_OPTIMIZATION_GUIDE_CORE_PAGE_ENTITIES_MODEL_EXECUTOR_IMPL_H_
+
+#include "base/task/sequenced_task_runner.h"
+#include "base/task/task_traits.h"
+#include "base/task/thread_pool.h"
+#include "components/optimization_guide/core/entity_metadata.h"
+#include "components/optimization_guide/core/optimization_target_model_observer.h"
+#include "components/optimization_guide/core/page_entities_model_executor.h"
+
+namespace optimization_guide {
+
+class EntityAnnotatorNativeLibrary;
+class OptimizationGuideModelProvider;
+
+// An object used to hold an entity annotator on a background thread.
+class EntityAnnotatorHolder {
+ public:
+ EntityAnnotatorHolder(
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner,
+ scoped_refptr<base::SequencedTaskRunner> reply_task_runner);
+ ~EntityAnnotatorHolder();
+
+ // Initializes the native library on a background thread. Will invoke
+ // |init_callback| on |reply_task_runner_| with the max version supported for
+ // the entity annotator on success. Otherwise, -1.
+ void InitializeEntityAnnotatorNativeLibraryOnBackgroundThread(
+ base::OnceCallback<void(int32_t)> init_callback);
+
+ // Creates an entity annotator on the background thread and sets it to
+ // |entity_annotator_|. Should be invoked on |background_task_runner_|.
+ void CreateAndSetEntityAnnotatorOnBackgroundThread(
+ const ModelInfo& model_info);
+
+ // Requests for |entity_annotator_| to execute its model for |text| and map
+ // the entities back to their metadata. Should be invoked on
+ // |background_task_runner_|.
+ using PageEntitiesMetadataModelExecutedCallback = base::OnceCallback<void(
+ const absl::optional<std::vector<ScoredEntityMetadata>>&)>;
+ void AnnotateEntitiesMetadataModelOnBackgroundThread(
+ const std::string& text,
+ PageEntitiesMetadataModelExecutedCallback callback);
+
+ // Returns entity metadata from |entity_annotator_| for |entity_id|.
+ // Should be invoked on |background_task_runner_|.
+ void GetMetadataForEntityIdOnBackgroundThread(
+ const std::string& entity_id,
+ PageEntitiesModelExecutor::
+ PageEntitiesModelEntityMetadataRetrievedCallback callback);
+
+ // Gets the weak ptr to |this| on the background thread.
+ base::WeakPtr<EntityAnnotatorHolder> GetBackgroundWeakPtr();
+
+ private:
+ void ResetEntityAnnotator();
+
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner_;
+ scoped_refptr<base::SequencedTaskRunner> reply_task_runner_;
+
+ std::unique_ptr<EntityAnnotatorNativeLibrary>
+ entity_annotator_native_library_;
+ void* entity_annotator_ = nullptr;
+
+ base::WeakPtrFactory<EntityAnnotatorHolder> background_weak_ptr_factory_{
+ this};
+};
+
+// Manages the loading and execution of the page entities model.
+class PageEntitiesModelExecutorImpl : public OptimizationTargetModelObserver,
+ public PageEntitiesModelExecutor {
+ public:
+ PageEntitiesModelExecutorImpl(
+ OptimizationGuideModelProvider* model_provider,
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner =
+ base::ThreadPool::CreateSequencedTaskRunner(
+ {base::MayBlock(), base::TaskPriority::BEST_EFFORT}));
+ ~PageEntitiesModelExecutorImpl() override;
+ PageEntitiesModelExecutorImpl(const PageEntitiesModelExecutorImpl&) = delete;
+ PageEntitiesModelExecutorImpl& operator=(
+ const PageEntitiesModelExecutorImpl&) = delete;
+
+ // PageEntitiesModelExecutor:
+ void GetMetadataForEntityId(
+ const std::string& entity_id,
+ PageEntitiesModelEntityMetadataRetrievedCallback callback) override;
+ void HumanReadableExecuteModelWithInput(
+ const std::string& text,
+ PageEntitiesMetadataModelExecutedCallback callback) override;
+
+ // OptimizationTargetModelObserver:
+ void OnModelUpdated(proto::OptimizationTarget optimization_target,
+ const ModelInfo& model_info) override;
+
+ private:
+ // Invoked on the UI thread when entity annotator library has been
+ // initialized.
+ void OnEntityAnnotatorLibraryInitialized(
+ OptimizationGuideModelProvider* model_provider,
+ int32_t max_model_format_feature_flag);
+
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner_;
+
+ // The holder used to hold the annotator used to annotate entities.
+ std::unique_ptr<EntityAnnotatorHolder> entity_annotator_holder_;
+
+ base::WeakPtrFactory<PageEntitiesModelExecutorImpl> weak_ptr_factory_{this};
+};
+
+} // namespace optimization_guide
+
+#endif // COMPONENTS_OPTIMIZATION_GUIDE_CORE_PAGE_ENTITIES_MODEL_EXECUTOR_IMPL_H_
diff --git a/chromium/components/optimization_guide/core/page_entities_model_executor_impl_unittest.cc b/chromium/components/optimization_guide/core/page_entities_model_executor_impl_unittest.cc
new file mode 100644
index 00000000000..e1954454829
--- /dev/null
+++ b/chromium/components/optimization_guide/core/page_entities_model_executor_impl_unittest.cc
@@ -0,0 +1,268 @@
+// Copyright 2022 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.
+
+#include "components/optimization_guide/core/page_entities_model_executor_impl.h"
+
+#include "base/observer_list.h"
+#include "base/path_service.h"
+#include "base/run_loop.h"
+#include "base/test/task_environment.h"
+#include "components/optimization_guide/core/model_util.h"
+#include "components/optimization_guide/core/optimization_guide_util.h"
+#include "components/optimization_guide/core/test_model_info_builder.h"
+#include "components/optimization_guide/core/test_optimization_guide_model_provider.h"
+#include "components/optimization_guide/proto/page_entities_model_metadata.pb.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace optimization_guide {
+namespace {
+
+using ::testing::ElementsAre;
+
+class ModelObserverTracker : public TestOptimizationGuideModelProvider {
+ public:
+ void AddObserverForOptimizationTargetModel(
+ proto::OptimizationTarget target,
+ const absl::optional<proto::Any>& model_metadata,
+ OptimizationTargetModelObserver* observer) override {
+ registered_model_metadata_.insert_or_assign(target, model_metadata);
+ registered_observers_.AddObserver(observer);
+ }
+
+ void RemoveObserverForOptimizationTargetModel(
+ proto::OptimizationTarget target,
+ OptimizationTargetModelObserver* observer) override {
+ registered_observers_.RemoveObserver(observer);
+ }
+
+ bool DidRegisterForTarget(
+ proto::OptimizationTarget target,
+ absl::optional<proto::Any>* out_model_metadata) const {
+ auto it = registered_model_metadata_.find(target);
+ if (it == registered_model_metadata_.end())
+ return false;
+ *out_model_metadata = registered_model_metadata_.at(target);
+ return true;
+ }
+
+ void PushModelInfoToObservers(const ModelInfo& model_info) {
+ for (auto& observer : registered_observers_) {
+ observer.OnModelUpdated(proto::OPTIMIZATION_TARGET_PAGE_ENTITIES,
+ model_info);
+ }
+ }
+
+ private:
+ base::flat_map<proto::OptimizationTarget, absl::optional<proto::Any>>
+ registered_model_metadata_;
+ base::ObserverList<OptimizationTargetModelObserver> registered_observers_;
+};
+
+class PageEntitiesModelExecutorImplTest : public testing::Test {
+ public:
+ void SetUp() override {
+ model_observer_tracker_ = std::make_unique<ModelObserverTracker>();
+ model_executor_ = std::make_unique<PageEntitiesModelExecutorImpl>(
+ model_observer_tracker_.get());
+
+ // Wait for PageEntitiesModelExecutor to set everything up.
+ task_environment_.RunUntilIdle();
+ }
+
+ void TearDown() override {
+ model_executor_.reset();
+ model_observer_tracker_.reset();
+
+ // Wait for PageEntitiesModelExecutor to clean everything up.
+ task_environment_.RunUntilIdle();
+ }
+
+ absl::optional<std::vector<ScoredEntityMetadata>> ExecuteHumanReadableModel(
+ const std::string& text) {
+ absl::optional<std::vector<ScoredEntityMetadata>> entity_metadata;
+
+ base::RunLoop run_loop;
+ model_executor_->HumanReadableExecuteModelWithInput(
+ text, base::BindOnce(
+ [](base::RunLoop* run_loop,
+ absl::optional<std::vector<ScoredEntityMetadata>>*
+ out_entity_metadata,
+ const absl::optional<std::vector<ScoredEntityMetadata>>&
+ entity_metadata) {
+ *out_entity_metadata = entity_metadata;
+ run_loop->Quit();
+ },
+ &run_loop, &entity_metadata));
+ run_loop.Run();
+
+ // Sort the result by score to make validating the output easier.
+ if (entity_metadata) {
+ std::sort(
+ entity_metadata->begin(), entity_metadata->end(),
+ [](const ScoredEntityMetadata& a, const ScoredEntityMetadata& b) {
+ return a.score > b.score;
+ });
+ }
+ return entity_metadata;
+ }
+
+ absl::optional<EntityMetadata> GetMetadataForEntityId(
+ const std::string& entity_id) {
+ absl::optional<EntityMetadata> entity_metadata;
+
+ base::RunLoop run_loop;
+ model_executor_->GetMetadataForEntityId(
+ entity_id,
+ base::BindOnce(
+ [](base::RunLoop* run_loop,
+ absl::optional<EntityMetadata>* out_entity_metadata,
+ const absl::optional<EntityMetadata>& entity_metadata) {
+ *out_entity_metadata = entity_metadata;
+ run_loop->Quit();
+ },
+ &run_loop, &entity_metadata));
+ run_loop.Run();
+
+ return entity_metadata;
+ }
+
+ ModelObserverTracker* model_observer_tracker() const {
+ return model_observer_tracker_.get();
+ }
+
+ base::FilePath GetModelTestDataDir() {
+ base::FilePath source_root_dir;
+ base::PathService::Get(base::DIR_SOURCE_ROOT, &source_root_dir);
+ return source_root_dir.AppendASCII("components")
+ .AppendASCII("optimization_guide")
+ .AppendASCII("internal")
+ .AppendASCII("testdata");
+ }
+
+ void PushModelInfoToObservers(const ModelInfo& model_info) {
+ model_observer_tracker_->PushModelInfoToObservers(model_info);
+ task_environment_.RunUntilIdle();
+ }
+
+ private:
+ base::test::TaskEnvironment task_environment_;
+ std::unique_ptr<ModelObserverTracker> model_observer_tracker_;
+ std::unique_ptr<PageEntitiesModelExecutorImpl> model_executor_;
+};
+
+TEST_F(PageEntitiesModelExecutorImplTest, CreateNoMetadata) {
+ std::unique_ptr<ModelInfo> model_info = TestModelInfoBuilder().Build();
+ ASSERT_TRUE(model_info);
+ PushModelInfoToObservers(*model_info);
+
+ // We expect that there will be no model to evaluate even for this input that
+ // has output in the test model.
+ EXPECT_EQ(ExecuteHumanReadableModel("Taylor Swift singer"), absl::nullopt);
+}
+
+TEST_F(PageEntitiesModelExecutorImplTest, CreateMetadataWrongType) {
+ proto::Any any;
+ any.set_type_url(any.GetTypeName());
+ proto::FieldTrial garbage;
+ garbage.SerializeToString(any.mutable_value());
+
+ proto::PredictionModel model;
+ model.mutable_model()->set_download_url(
+ FilePathToString(GetModelTestDataDir().AppendASCII("model.tflite")));
+ model.mutable_model_info()->set_version(123);
+ *model.mutable_model_info()->mutable_model_metadata() = any;
+ std::unique_ptr<ModelInfo> model_info = ModelInfo::Create(model);
+ ASSERT_TRUE(model_info);
+ PushModelInfoToObservers(*model_info);
+
+ // We expect that there will be no model to evaluate even for this input that
+ // has output in the test model.
+ EXPECT_EQ(ExecuteHumanReadableModel("Taylor Swift singer"), absl::nullopt);
+}
+
+TEST_F(PageEntitiesModelExecutorImplTest, CreateNoSlices) {
+ proto::Any any;
+ proto::PageEntitiesModelMetadata metadata;
+ any.set_type_url(metadata.GetTypeName());
+ metadata.SerializeToString(any.mutable_value());
+
+ proto::PredictionModel model;
+ model.mutable_model()->set_download_url(
+ FilePathToString(GetModelTestDataDir().AppendASCII("model.tflite")));
+ model.mutable_model_info()->set_version(123);
+ *model.mutable_model_info()->mutable_model_metadata() = any;
+ std::unique_ptr<ModelInfo> model_info = ModelInfo::Create(model);
+ ASSERT_TRUE(model_info);
+ PushModelInfoToObservers(*model_info);
+
+ // We expect that there will be no model to evaluate even for this input that
+ // has output in the test model.
+ EXPECT_EQ(ExecuteHumanReadableModel("Taylor Swift singer"), absl::nullopt);
+}
+
+TEST_F(PageEntitiesModelExecutorImplTest, CreateMissingFiles) {
+ proto::Any any;
+ proto::PageEntitiesModelMetadata metadata;
+ metadata.add_slice("global");
+ any.set_type_url(metadata.GetTypeName());
+ metadata.SerializeToString(any.mutable_value());
+
+ base::FilePath dir_path = GetModelTestDataDir();
+ base::flat_set<std::string> expected_additional_files = {
+ FilePathToString(dir_path.AppendASCII("model_metadata.pb")),
+ FilePathToString(dir_path.AppendASCII("word_embeddings")),
+ FilePathToString(dir_path.AppendASCII("global-entities_names")),
+ FilePathToString(dir_path.AppendASCII("global-entities_metadata")),
+ FilePathToString(dir_path.AppendASCII("global-entities_names_filter")),
+ FilePathToString(dir_path.AppendASCII("global-entities_prefixes_filter")),
+ };
+ // Remove one file for each iteration and make sure it fails.
+ for (const auto& missing_file_name : expected_additional_files) {
+ // Make a copy of the expected files and remove the one file from the set.
+ base::flat_set<std::string> additional_files = expected_additional_files;
+ additional_files.erase(missing_file_name);
+
+ proto::PredictionModel model;
+ model.mutable_model()->set_download_url(
+ FilePathToString(dir_path.AppendASCII("model.tflite")));
+ model.mutable_model_info()->set_version(123);
+ *model.mutable_model_info()->mutable_model_metadata() = any;
+ for (const auto& additional_file : additional_files) {
+ model.mutable_model_info()->add_additional_files()->set_file_path(
+ additional_file);
+ }
+ std::unique_ptr<ModelInfo> model_info = ModelInfo::Create(model);
+ ASSERT_TRUE(model_info);
+ PushModelInfoToObservers(*model_info);
+
+ // We expect that there will be no model to evaluate even for this input
+ // that has output in the test model.
+ EXPECT_EQ(ExecuteHumanReadableModel("Taylor Swift singer"), absl::nullopt);
+ }
+}
+
+TEST_F(PageEntitiesModelExecutorImplTest, GetMetadataForEntityIdNoModel) {
+ EXPECT_EQ(GetMetadataForEntityId("/m/0dl567"), absl::nullopt);
+}
+
+TEST_F(PageEntitiesModelExecutorImplTest, ExecuteHumanReadableModelNoModel) {
+ EXPECT_EQ(ExecuteHumanReadableModel("Taylor Swift singer"), absl::nullopt);
+}
+
+TEST_F(PageEntitiesModelExecutorImplTest,
+ SetsUpModelCorrectlyBasedOnFeatureParams) {
+ absl::optional<proto::Any> registered_model_metadata;
+ EXPECT_TRUE(model_observer_tracker()->DidRegisterForTarget(
+ proto::OPTIMIZATION_TARGET_PAGE_ENTITIES, &registered_model_metadata));
+ EXPECT_TRUE(registered_model_metadata.has_value());
+ absl::optional<proto::PageEntitiesModelMetadata>
+ page_entities_model_metadata =
+ ParsedAnyMetadata<proto::PageEntitiesModelMetadata>(
+ *registered_model_metadata);
+ EXPECT_TRUE(page_entities_model_metadata.has_value());
+}
+
+} // namespace
+} // namespace optimization_guide
diff --git a/chromium/components/optimization_guide/core/page_topics_model_executor.cc b/chromium/components/optimization_guide/core/page_topics_model_executor.cc
index b1c1707bc8e..dbc9a425889 100644
--- a/chromium/components/optimization_guide/core/page_topics_model_executor.cc
+++ b/chromium/components/optimization_guide/core/page_topics_model_executor.cc
@@ -17,7 +17,7 @@ namespace {
// The ID of the NONE category in the taxonomy. This node always exists.
// Semantically, the none category is attached to data for which we can say
// with certainty that no single label in the taxonomy is appropriate.
-const char kNoneCategoryId[] = "-2";
+const int32_t kNoneCategoryId = -2;
} // namespace
@@ -52,7 +52,7 @@ void PageTopicsModelExecutor::PostprocessCategoriesToBatchAnnotationResult(
const absl::optional<std::vector<tflite::task::core::Category>>& output) {
DCHECK_EQ(annotation_type, AnnotationType::kPageTopics);
- absl::optional<std::vector<WeightedString>> categories;
+ absl::optional<std::vector<WeightedIdentifier>> categories;
if (output) {
categories = ExtractCategoriesFromModelOutput(*output);
}
@@ -60,7 +60,7 @@ void PageTopicsModelExecutor::PostprocessCategoriesToBatchAnnotationResult(
BatchAnnotationResult::CreatePageTopicsResult(input, categories));
}
-absl::optional<std::vector<WeightedString>>
+absl::optional<std::vector<WeightedIdentifier>>
PageTopicsModelExecutor::ExtractCategoriesFromModelOutput(
const std::vector<tflite::task::core::Category>& model_output) const {
absl::optional<proto::PageTopicsModelMetadata> model_metadata =
@@ -79,7 +79,7 @@ PageTopicsModelExecutor::ExtractCategoriesFromModelOutput(
.category_name())
: absl::nullopt;
- std::vector<std::pair<std::string, float>> category_candidates;
+ std::vector<std::pair<int32_t, float>> category_candidates;
for (const auto& category : model_output) {
if (visibility_category_name &&
@@ -89,8 +89,8 @@ PageTopicsModelExecutor::ExtractCategoriesFromModelOutput(
// Assume everything else is for categories.
int category_id;
if (base::StringToInt(category.class_name, &category_id)) {
- category_candidates.emplace_back(std::make_pair(
- category.class_name, static_cast<float>(category.score)));
+ category_candidates.emplace_back(
+ std::make_pair(category_id, static_cast<float>(category.score)));
}
}
@@ -103,20 +103,19 @@ PageTopicsModelExecutor::ExtractCategoriesFromModelOutput(
model_metadata->output_postprocessing_params().category_params();
// Determine the categories with the highest weights.
- std::sort(category_candidates.begin(), category_candidates.end(),
- [](const std::pair<std::string, float>& a,
- const std::pair<std::string, float>& b) {
- return a.second > b.second;
- });
+ std::sort(
+ category_candidates.begin(), category_candidates.end(),
+ [](const std::pair<int32_t, float>& a,
+ const std::pair<int32_t, float>& b) { return a.second > b.second; });
size_t max_categories = static_cast<size_t>(category_params.max_categories());
float total_weight = 0.0;
float sum_positive_scores = 0.0;
absl::optional<std::pair<size_t, float>> none_idx_and_weight;
- std::vector<std::pair<std::string, float>> categories;
+ std::vector<std::pair<int32_t, float>> categories;
categories.reserve(max_categories);
for (size_t i = 0; i < category_candidates.size() && i < max_categories;
i++) {
- std::pair<std::string, float> candidate = category_candidates[i];
+ std::pair<int32_t, float> candidate = category_candidates[i];
categories.push_back(candidate);
total_weight += candidate.second;
@@ -132,7 +131,7 @@ PageTopicsModelExecutor::ExtractCategoriesFromModelOutput(
if (category_params.min_category_weight() > 0) {
categories.erase(
std::remove_if(categories.begin(), categories.end(),
- [&](const std::pair<std::string, float>& category) {
+ [&](const std::pair<int32_t, float>& category) {
return category.second <
category_params.min_category_weight();
}),
@@ -159,19 +158,19 @@ PageTopicsModelExecutor::ExtractCategoriesFromModelOutput(
categories.erase(
std::remove_if(
categories.begin(), categories.end(),
- [&](const std::pair<std::string, float>& category) {
+ [&](const std::pair<int32_t, float>& category) {
return (category.second / normalization_factor) <
category_params.min_normalized_weight_within_top_n();
}),
categories.end());
- std::vector<WeightedString> final_categories;
+ std::vector<WeightedIdentifier> final_categories;
final_categories.reserve(categories.size());
for (const auto& category : categories) {
// We expect the weight to be between 0 and 1.
DCHECK(category.second >= 0.0 && category.second <= 1.0);
final_categories.emplace_back(
- WeightedString(category.first, category.second));
+ WeightedIdentifier(category.first, category.second));
}
DCHECK_LE(final_categories.size(), max_categories);
diff --git a/chromium/components/optimization_guide/core/page_topics_model_executor.h b/chromium/components/optimization_guide/core/page_topics_model_executor.h
index fa396fafc4e..30e263872e5 100644
--- a/chromium/components/optimization_guide/core/page_topics_model_executor.h
+++ b/chromium/components/optimization_guide/core/page_topics_model_executor.h
@@ -42,7 +42,8 @@ class PageTopicsModelExecutor : public PageContentAnnotationJobExecutor,
// Extracts the scored categories from the output of the model.
// Public for testing.
- absl::optional<std::vector<WeightedString>> ExtractCategoriesFromModelOutput(
+ absl::optional<std::vector<WeightedIdentifier>>
+ ExtractCategoriesFromModelOutput(
const std::vector<tflite::task::core::Category>& model_output) const;
private:
diff --git a/chromium/components/optimization_guide/core/page_topics_model_executor_unittest.cc b/chromium/components/optimization_guide/core/page_topics_model_executor_unittest.cc
index 7fefca3bdc0..6ad49e17067 100644
--- a/chromium/components/optimization_guide/core/page_topics_model_executor_unittest.cc
+++ b/chromium/components/optimization_guide/core/page_topics_model_executor_unittest.cc
@@ -125,13 +125,13 @@ TEST_F(
{"0", 0.0001}, {"1", 0.1}, {"not an int", 0.9}, {"2", 0.2}, {"3", 0.3},
};
- absl::optional<std::vector<WeightedString>> categories =
+ absl::optional<std::vector<WeightedIdentifier>> categories =
model_executor()->ExtractCategoriesFromModelOutput(model_output);
ASSERT_TRUE(categories);
EXPECT_THAT(*categories,
- testing::UnorderedElementsAre(WeightedString("1", 0.1),
- WeightedString("2", 0.2),
- WeightedString("3", 0.3)));
+ testing::UnorderedElementsAre(WeightedIdentifier(1, 0.1),
+ WeightedIdentifier(2, 0.2),
+ WeightedIdentifier(3, 0.3)));
}
TEST_F(PageTopicsModelExecutorTest,
@@ -157,7 +157,7 @@ TEST_F(PageTopicsModelExecutorTest,
{"1", 0.2},
};
- absl::optional<std::vector<WeightedString>> categories =
+ absl::optional<std::vector<WeightedIdentifier>> categories =
model_executor()->ExtractCategoriesFromModelOutput(model_output);
EXPECT_FALSE(categories);
}
@@ -183,13 +183,13 @@ TEST_F(PageTopicsModelExecutorTest,
{"-2", 0.1}, {"0", 0.3}, {"1", 0.2}, {"2", 0.4}, {"3", 0.05},
};
- absl::optional<std::vector<WeightedString>> categories =
+ absl::optional<std::vector<WeightedIdentifier>> categories =
model_executor()->ExtractCategoriesFromModelOutput(model_output);
ASSERT_TRUE(categories);
EXPECT_THAT(*categories,
- testing::UnorderedElementsAre(WeightedString("0", 0.3),
- WeightedString("1", 0.2),
- WeightedString("2", 0.4)));
+ testing::UnorderedElementsAre(WeightedIdentifier(0, 0.3),
+ WeightedIdentifier(1, 0.2),
+ WeightedIdentifier(2, 0.4)));
}
TEST_F(PageTopicsModelExecutorTest,
@@ -216,13 +216,13 @@ TEST_F(PageTopicsModelExecutorTest,
{"3", 0.05},
};
- absl::optional<std::vector<WeightedString>> categories =
+ absl::optional<std::vector<WeightedIdentifier>> categories =
model_executor()->ExtractCategoriesFromModelOutput(model_output);
ASSERT_TRUE(categories);
EXPECT_THAT(*categories,
- testing::UnorderedElementsAre(WeightedString("0", 0.3),
- WeightedString("1", 0.25),
- WeightedString("2", 0.4)));
+ testing::UnorderedElementsAre(WeightedIdentifier(0, 0.3),
+ WeightedIdentifier(1, 0.25),
+ WeightedIdentifier(2, 0.4)));
}
TEST_F(PageTopicsModelExecutorTest,
@@ -260,10 +260,10 @@ TEST_F(PageTopicsModelExecutorTest,
&topics_result),
AnnotationType::kPageTopics, "input", model_output);
EXPECT_EQ(topics_result, BatchAnnotationResult::CreatePageTopicsResult(
- "input", std::vector<WeightedString>{
- WeightedString("0", 0.3),
- WeightedString("1", 0.25),
- WeightedString("2", 0.4),
+ "input", std::vector<WeightedIdentifier>{
+ WeightedIdentifier(0, 0.3),
+ WeightedIdentifier(1, 0.25),
+ WeightedIdentifier(2, 0.4),
}));
}
diff --git a/chromium/components/optimization_guide/core/prediction_model.cc b/chromium/components/optimization_guide/core/prediction_model.cc
deleted file mode 100644
index 1cf077bd71a..00000000000
--- a/chromium/components/optimization_guide/core/prediction_model.cc
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright 2020 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.
-
-#include "components/optimization_guide/core/prediction_model.h"
-
-#include <utility>
-
-#include "components/optimization_guide/core/decision_tree_prediction_model.h"
-
-namespace optimization_guide {
-
-// static
-std::unique_ptr<PredictionModel> PredictionModel::Create(
- const proto::PredictionModel& prediction_model) {
- // TODO(crbug/1009123): Add a histogram to record if the provided model is
- // constructed successfully or not.
- // TODO(crbug/1009123): Adding timing metrics around initialization due to
- // potential validation overhead.
- if (!prediction_model.has_model())
- return nullptr;
-
- if (!prediction_model.has_model_info())
- return nullptr;
-
- if (!prediction_model.model_info().has_version())
- return nullptr;
-
- // Enforce that only one ModelType is specified for the PredictionModel.
- if (prediction_model.model_info().supported_model_types_size() != 1) {
- return nullptr;
- }
-
- // Check that the client supports this type of model and is not an unknown
- // type.
- if (!proto::ModelType_IsValid(
- prediction_model.model_info().supported_model_types(0)) ||
- prediction_model.model_info().supported_model_types(0) ==
- proto::ModelType::MODEL_TYPE_UNKNOWN) {
- return nullptr;
- }
-
- std::unique_ptr<PredictionModel> model;
- // The Decision Tree model type is currently the only supported model type.
- if (prediction_model.model_info().supported_model_types(0) !=
- proto::ModelType::MODEL_TYPE_DECISION_TREE) {
- return nullptr;
- }
- model = std::make_unique<DecisionTreePredictionModel>(prediction_model);
-
- // Any constructed model must be validated for correctness according to its
- // model type before being returned.
- if (!model->ValidatePredictionModel())
- return nullptr;
-
- return model;
-}
-
-namespace {
-
-std::vector<std::string> ComputeModelFeatures(
- const proto::ModelInfo& model_info) {
- std::vector<std::string> features;
- features.reserve(model_info.supported_host_model_features_size());
- // Insert all the host model features for the owned |model_|.
- for (const auto& host_model_feature :
- model_info.supported_host_model_features()) {
- features.push_back(host_model_feature);
- }
- return features;
-}
-
-} // namespace
-
-PredictionModel::PredictionModel(const proto::PredictionModel& prediction_model)
- : model_(prediction_model.model()),
- model_features_(ComputeModelFeatures(prediction_model.model_info())),
- version_(prediction_model.model_info().version()) {}
-
-PredictionModel::~PredictionModel() = default;
-
-} // namespace optimization_guide
diff --git a/chromium/components/optimization_guide/core/prediction_model.h b/chromium/components/optimization_guide/core/prediction_model.h
deleted file mode 100644
index c4c3c024d0b..00000000000
--- a/chromium/components/optimization_guide/core/prediction_model.h
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright 2020 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.
-
-#ifndef COMPONENTS_OPTIMIZATION_GUIDE_CORE_PREDICTION_MODEL_H_
-#define COMPONENTS_OPTIMIZATION_GUIDE_CORE_PREDICTION_MODEL_H_
-
-#include <stdint.h>
-#include <memory>
-#include <string>
-
-#include "base/containers/flat_map.h"
-#include "base/containers/flat_set.h"
-#include "components/optimization_guide/core/optimization_guide_enums.h"
-#include "components/optimization_guide/proto/models.pb.h"
-
-namespace optimization_guide {
-
-// A PredictionModel supported by the optimization guide that makes an
-// OptimizationTargetDecision by evaluating a prediction model.
-class PredictionModel {
- public:
- PredictionModel(const PredictionModel&) = delete;
- PredictionModel& operator=(const PredictionModel&) = delete;
-
- virtual ~PredictionModel();
-
- // Creates an Prediction model of the correct ModelType specified in
- // |prediction_model|. The validation overhead of this factory can be high and
- // should should be called in the background.
- static std::unique_ptr<PredictionModel> Create(
- const proto::PredictionModel& prediction_model);
-
- // Returns the OptimizationTargetDecision by evaluating the |model_|
- // using the provided |model_features|. |prediction_score| will be populated
- // with the score output by the model.
- virtual OptimizationTargetDecision Predict(
- const base::flat_map<std::string, float>& model_features,
- double* prediction_score) = 0;
-
- // Provide the version of the |model_| by |this|.
- int64_t GetVersion() const { return version_; }
-
- // Provide the model features required for evaluation of the |model_| by
- // |this|.
- const base::flat_set<std::string>& GetModelFeatures() const {
- return model_features_;
- }
-
- protected:
- explicit PredictionModel(const proto::PredictionModel& prediction_model);
-
- // The in-memory model used for prediction.
- const proto::Model model_;
-
- private:
- // Determines if the |model_| is complete and can be successfully evaluated by
- // |this|.
- virtual bool ValidatePredictionModel() const = 0;
-
- // The set of features required by the |model_| to be evaluated.
- const base::flat_set<std::string> model_features_;
-
- // The version of the |model_|.
- const int64_t version_;
-};
-
-} // namespace optimization_guide
-
-#endif // COMPONENTS_OPTIMIZATION_GUIDE_CORE_PREDICTION_MODEL_H_
diff --git a/chromium/components/optimization_guide/core/prediction_model_fetcher_impl.cc b/chromium/components/optimization_guide/core/prediction_model_fetcher_impl.cc
index 79282f12248..1aba12cfa54 100644
--- a/chromium/components/optimization_guide/core/prediction_model_fetcher_impl.cc
+++ b/chromium/components/optimization_guide/core/prediction_model_fetcher_impl.cc
@@ -22,7 +22,6 @@
#include "net/http/http_response_headers.h"
#include "net/http/http_status_code.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
-#include "services/network/public/cpp/network_connection_tracker.h"
#include "services/network/public/cpp/resource_request.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "services/network/public/cpp/simple_url_loader.h"
@@ -32,16 +31,14 @@ namespace optimization_guide {
PredictionModelFetcherImpl::PredictionModelFetcherImpl(
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
- const GURL& optimization_guide_service_get_models_url,
- network::NetworkConnectionTracker* network_connection_tracker)
+ const GURL& optimization_guide_service_get_models_url)
: optimization_guide_service_get_models_url_(
net::AppendOrReplaceQueryParameter(
optimization_guide_service_get_models_url,
"key",
optimization_guide::features::
GetOptimizationGuideServiceAPIKey())),
- url_loader_factory_(url_loader_factory),
- network_connection_tracker_(network_connection_tracker) {
+ url_loader_factory_(url_loader_factory) {
CHECK(optimization_guide_service_get_models_url_.SchemeIs(url::kHttpsScheme));
}
@@ -55,11 +52,6 @@ bool PredictionModelFetcherImpl::FetchOptimizationGuideServiceModels(
ModelsFetchedCallback models_fetched_callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- if (network_connection_tracker_->IsOffline()) {
- std::move(models_fetched_callback).Run(absl::nullopt);
- return false;
- }
-
if (url_loader_)
return false;
diff --git a/chromium/components/optimization_guide/core/prediction_model_fetcher_impl.h b/chromium/components/optimization_guide/core/prediction_model_fetcher_impl.h
index 2d2557e8c15..969af65685a 100644
--- a/chromium/components/optimization_guide/core/prediction_model_fetcher_impl.h
+++ b/chromium/components/optimization_guide/core/prediction_model_fetcher_impl.h
@@ -19,7 +19,6 @@
#include "url/gurl.h"
namespace network {
-class NetworkConnectionTracker;
class SharedURLLoaderFactory;
class SimpleURLLoader;
} // namespace network
@@ -34,8 +33,7 @@ class PredictionModelFetcherImpl : public PredictionModelFetcher {
public:
PredictionModelFetcherImpl(
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
- const GURL& optimization_guide_service_get_models_url,
- network::NetworkConnectionTracker* network_connection_tracker);
+ const GURL& optimization_guide_service_get_models_url);
PredictionModelFetcherImpl(const PredictionModelFetcherImpl&) = delete;
PredictionModelFetcherImpl& operator=(const PredictionModelFetcherImpl&) =
@@ -82,10 +80,6 @@ class PredictionModelFetcherImpl : public PredictionModelFetcher {
// Used for creating a |url_loader_| when needed for request hints.
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
- // Listens to changes around the network connection. Not owned. Guaranteed to
- // outlive |this|.
- raw_ptr<network::NetworkConnectionTracker> network_connection_tracker_;
-
SEQUENCE_CHECKER(sequence_checker_);
};
diff --git a/chromium/components/optimization_guide/core/prediction_model_fetcher_unittest.cc b/chromium/components/optimization_guide/core/prediction_model_fetcher_unittest.cc
index 1b59d314c01..a4ca4b85255 100644
--- a/chromium/components/optimization_guide/core/prediction_model_fetcher_unittest.cc
+++ b/chromium/components/optimization_guide/core/prediction_model_fetcher_unittest.cc
@@ -21,7 +21,6 @@
#include "net/base/url_util.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
-#include "services/network/test/test_network_connection_tracker.h"
#include "services/network/test/test_url_loader_factory.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
@@ -37,11 +36,9 @@ class PredictionModelFetcherTest : public testing::Test {
: task_environment_(base::test::TaskEnvironment::MainThreadType::UI),
shared_url_loader_factory_(
base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
- &test_url_loader_factory_)),
- network_tracker_(network::TestNetworkConnectionTracker::GetInstance()) {
+ &test_url_loader_factory_)) {
prediction_model_fetcher_ = std::make_unique<PredictionModelFetcherImpl>(
- shared_url_loader_factory_, GURL(optimization_guide_service_url),
- network_tracker_);
+ shared_url_loader_factory_, GURL(optimization_guide_service_url));
}
PredictionModelFetcherTest(const PredictionModelFetcherTest&) = delete;
@@ -58,16 +55,6 @@ class PredictionModelFetcherTest : public testing::Test {
bool models_fetched() { return models_fetched_; }
- void SetConnectionOffline() {
- network_tracker_->SetConnectionType(
- network::mojom::ConnectionType::CONNECTION_NONE);
- }
-
- void SetConnectionOnline() {
- network_tracker_->SetConnectionType(
- network::mojom::ConnectionType::CONNECTION_4G);
- }
-
protected:
bool FetchModels(const std::vector<proto::ModelInfo> models_request_info,
const std::vector<proto::FieldTrial>& active_field_trials,
@@ -116,7 +103,6 @@ class PredictionModelFetcherTest : public testing::Test {
scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory_;
network::TestURLLoaderFactory test_url_loader_factory_;
- raw_ptr<network::TestNetworkConnectionTracker> network_tracker_;
};
TEST_F(PredictionModelFetcherTest, FetchOptimizationGuideServiceModels) {
@@ -173,26 +159,6 @@ TEST_F(PredictionModelFetcherTest, FetchReturnBadResponse) {
EXPECT_FALSE(models_fetched());
}
-TEST_F(PredictionModelFetcherTest, FetchAttemptWhenNetworkOffline) {
- SetConnectionOffline();
- std::string response_content;
- proto::ModelInfo model_info;
- model_info.set_optimization_target(
- proto::OptimizationTarget::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD);
- EXPECT_FALSE(FetchModels({model_info}, /*active_field_trials=*/{},
- proto::RequestContext::CONTEXT_BATCH_UPDATE_MODELS,
- "en-US"));
- EXPECT_FALSE(models_fetched());
-
- SetConnectionOnline();
- EXPECT_TRUE(FetchModels({model_info}, /*active_field_trials=*/{},
- proto::RequestContext::CONTEXT_BATCH_UPDATE_MODELS,
- "en-US"));
- VerifyHasPendingFetchRequests();
- EXPECT_TRUE(SimulateResponse(response_content, net::HTTP_OK));
- EXPECT_TRUE(models_fetched());
-}
-
TEST_F(PredictionModelFetcherTest, EmptyModelInfo) {
base::HistogramTester histogram_tester;
std::string response_content;
diff --git a/chromium/components/optimization_guide/core/prediction_model_unittest.cc b/chromium/components/optimization_guide/core/prediction_model_unittest.cc
deleted file mode 100644
index c928abdd5cf..00000000000
--- a/chromium/components/optimization_guide/core/prediction_model_unittest.cc
+++ /dev/null
@@ -1,134 +0,0 @@
-// Copyright 2020 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.
-
-#include "components/optimization_guide/core/prediction_model.h"
-
-#include <utility>
-
-#include "components/optimization_guide/proto/models.pb.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace optimization_guide {
-
-TEST(PredictionModelTest, ValidPredictionModel) {
- proto::PredictionModel prediction_model;
- prediction_model.mutable_model()->mutable_threshold()->set_value(5.0);
-
- proto::DecisionTree decision_tree_model = proto::DecisionTree();
- decision_tree_model.set_weight(2.0);
-
- proto::TreeNode* tree_node = decision_tree_model.add_nodes();
- tree_node->mutable_node_id()->set_value(0);
- tree_node->mutable_binary_node()->mutable_left_child_id()->set_value(1);
- tree_node->mutable_binary_node()->mutable_right_child_id()->set_value(2);
- tree_node->mutable_binary_node()
- ->mutable_inequality_left_child_test()
- ->mutable_feature_id()
- ->mutable_id()
- ->set_value("agg1");
- tree_node->mutable_binary_node()
- ->mutable_inequality_left_child_test()
- ->set_type(proto::InequalityTest::LESS_OR_EQUAL);
- tree_node->mutable_binary_node()
- ->mutable_inequality_left_child_test()
- ->mutable_threshold()
- ->set_float_value(1.0);
-
- tree_node = decision_tree_model.add_nodes();
- tree_node->mutable_node_id()->set_value(1);
- tree_node->mutable_leaf()->mutable_vector()->add_value()->set_double_value(
- 2.);
-
- tree_node = decision_tree_model.add_nodes();
- tree_node->mutable_node_id()->set_value(2);
- tree_node->mutable_leaf()->mutable_vector()->add_value()->set_double_value(
- 4.);
-
- *prediction_model.mutable_model()->mutable_decision_tree() =
- decision_tree_model;
-
- proto::ModelInfo* model_info = prediction_model.mutable_model_info();
- model_info->set_version(1);
- model_info->add_supported_model_types(
- proto::ModelType::MODEL_TYPE_DECISION_TREE);
- model_info->add_supported_host_model_features("agg1");
-
- std::unique_ptr<PredictionModel> model =
- PredictionModel::Create(prediction_model);
-
- EXPECT_EQ(1, model->GetVersion());
- EXPECT_EQ(1u, model->GetModelFeatures().size());
- EXPECT_TRUE(model->GetModelFeatures().count("agg1"));
-}
-
-TEST(PredictionModelTest, NoModel) {
- proto::PredictionModel prediction_model;
-
- std::unique_ptr<PredictionModel> model =
- PredictionModel::Create(prediction_model);
- EXPECT_FALSE(model);
-}
-
-TEST(PredictionModelTest, NoModelVersion) {
- proto::PredictionModel prediction_model;
-
- proto::DecisionTree* decision_tree_model =
- prediction_model.mutable_model()->mutable_decision_tree();
- decision_tree_model->set_weight(2.0);
-
- std::unique_ptr<PredictionModel> model =
- PredictionModel::Create(prediction_model);
- EXPECT_FALSE(model);
-}
-
-TEST(PredictionModelTest, NoModelType) {
- proto::PredictionModel prediction_model;
-
- proto::DecisionTree* decision_tree_model =
- prediction_model.mutable_model()->mutable_decision_tree();
- decision_tree_model->set_weight(2.0);
-
- proto::ModelInfo* model_info = prediction_model.mutable_model_info();
- model_info->set_version(1);
-
- std::unique_ptr<PredictionModel> model =
- PredictionModel::Create(std::move(prediction_model));
- EXPECT_FALSE(model);
-}
-
-TEST(PredictionModelTest, UnknownModelType) {
- proto::PredictionModel prediction_model;
-
- proto::DecisionTree* decision_tree_model =
- prediction_model.mutable_model()->mutable_decision_tree();
- decision_tree_model->set_weight(2.0);
-
- proto::ModelInfo* model_info = prediction_model.mutable_model_info();
- model_info->set_version(1);
- model_info->add_supported_model_types(proto::ModelType::MODEL_TYPE_UNKNOWN);
-
- std::unique_ptr<PredictionModel> model =
- PredictionModel::Create(prediction_model);
- EXPECT_FALSE(model);
-}
-
-TEST(PredictionModelTest, MultipleModelTypes) {
- proto::PredictionModel prediction_model;
-
- proto::DecisionTree* decision_tree_model =
- prediction_model.mutable_model()->mutable_decision_tree();
- decision_tree_model->set_weight(2.0);
-
- proto::ModelInfo* model_info = prediction_model.mutable_model_info();
- model_info->set_version(1);
- model_info->add_supported_model_types(
- proto::ModelType::MODEL_TYPE_DECISION_TREE);
- model_info->add_supported_model_types(proto::ModelType::MODEL_TYPE_UNKNOWN);
-
- std::unique_ptr<PredictionModel> model =
- PredictionModel::Create(prediction_model);
- EXPECT_FALSE(model);
-}
-
-} // namespace optimization_guide
diff --git a/chromium/components/optimization_guide/core/store_update_data.cc b/chromium/components/optimization_guide/core/store_update_data.cc
index 0afd12d3e80..d5c636ef16b 100644
--- a/chromium/components/optimization_guide/core/store_update_data.cc
+++ b/chromium/components/optimization_guide/core/store_update_data.cc
@@ -38,40 +38,6 @@ StoreUpdateData::CreatePredictionModelStoreUpdateData(base::Time expiry_time) {
return base::WrapUnique<StoreUpdateData>(new StoreUpdateData(expiry_time));
}
-// static
-std::unique_ptr<StoreUpdateData>
-StoreUpdateData::CreateHostModelFeaturesStoreUpdateData(
- base::Time host_model_features_update_time,
- base::Time expiry_time) {
- std::unique_ptr<StoreUpdateData> host_model_features_update_data(
- new StoreUpdateData(host_model_features_update_time, expiry_time));
- return host_model_features_update_data;
-}
-
-StoreUpdateData::StoreUpdateData(base::Time host_model_features_update_time,
- base::Time expiry_time)
- : update_time_(host_model_features_update_time),
- expiry_time_(expiry_time),
- entries_to_save_(std::make_unique<EntryVector>()) {
- entry_key_prefix_ =
- OptimizationGuideStore::GetHostModelFeaturesEntryKeyPrefix();
- proto::StoreEntry metadata_host_model_features_entry;
- metadata_host_model_features_entry.set_entry_type(
- static_cast<proto::StoreEntryType>(
- OptimizationGuideStore::StoreEntryType::kMetadata));
- metadata_host_model_features_entry.set_update_time_secs(
- host_model_features_update_time.ToDeltaSinceWindowsEpoch().InSeconds());
- entries_to_save_->emplace_back(
- OptimizationGuideStore::GetMetadataTypeEntryKey(
- OptimizationGuideStore::MetadataType::kHostModelFeatures),
- std::move(metadata_host_model_features_entry));
-
- // |this| may be modified on another thread after construction but all
- // future modifications, from that call forward, must be made on the same
- // thread.
- DETACH_FROM_SEQUENCE(sequence_checker_);
-}
-
StoreUpdateData::StoreUpdateData(base::Time expiry_time)
: expiry_time_(expiry_time),
entries_to_save_(std::make_unique<EntryVector>()) {
@@ -161,28 +127,6 @@ void StoreUpdateData::MoveHintIntoUpdateData(proto::Hint&& hint) {
std::move(entry_proto));
}
-void StoreUpdateData::CopyHostModelFeaturesIntoUpdateData(
- const proto::HostModelFeatures& host_model_features) {
- // All future modifications must be made by the same thread. Note, |this| may
- // have been constructed on another thread.
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK(!entry_key_prefix_.empty());
- DCHECK(expiry_time_);
-
- // To avoid any unnecessary copying, the host model feature data is moved into
- // proto::StoreEntry.
- OptimizationGuideStore::EntryKey host_model_features_entry_key =
- entry_key_prefix_ + host_model_features.host();
- proto::StoreEntry entry_proto;
- entry_proto.set_entry_type(static_cast<proto::StoreEntryType>(
- OptimizationGuideStore::StoreEntryType::kHostModelFeatures));
- entry_proto.set_expiry_time_secs(
- expiry_time_->ToDeltaSinceWindowsEpoch().InSeconds());
- entry_proto.mutable_host_model_features()->CopyFrom(host_model_features);
- entries_to_save_->emplace_back(std::move(host_model_features_entry_key),
- std::move(entry_proto));
-}
-
void StoreUpdateData::CopyPredictionModelIntoUpdateData(
const proto::PredictionModel& prediction_model) {
// All future modifications must be made by the same thread. Note, |this| may
@@ -200,8 +144,19 @@ void StoreUpdateData::CopyPredictionModelIntoUpdateData(
proto::StoreEntry entry_proto;
entry_proto.set_entry_type(static_cast<proto::StoreEntryType>(
OptimizationGuideStore::StoreEntryType::kPredictionModel));
+
+ base::TimeDelta expiry_duration;
+ if (prediction_model.model_info().has_valid_duration()) {
+ expiry_duration =
+ base::Seconds(prediction_model.model_info().valid_duration().seconds());
+ } else {
+ expiry_duration = features::StoredFetchedHintsFreshnessDuration();
+ }
+ expiry_time_ = base::Time::Now() + expiry_duration;
entry_proto.set_expiry_time_secs(
- expiry_time_->ToDeltaSinceWindowsEpoch().InSeconds());
+ expiry_time_.value().ToDeltaSinceWindowsEpoch().InSeconds());
+ entry_proto.set_keep_beyond_valid_duration(
+ prediction_model.model_info().keep_beyond_valid_duration());
entry_proto.mutable_prediction_model()->CopyFrom(prediction_model);
entries_to_save_->emplace_back(std::move(prediction_model_entry_key),
std::move(entry_proto));
diff --git a/chromium/components/optimization_guide/core/store_update_data.h b/chromium/components/optimization_guide/core/store_update_data.h
index 68a098a8ec3..05dbc9a872e 100644
--- a/chromium/components/optimization_guide/core/store_update_data.h
+++ b/chromium/components/optimization_guide/core/store_update_data.h
@@ -16,7 +16,6 @@
namespace optimization_guide {
namespace proto {
class Hint;
-class HostModelFeatures;
class PredictionModel;
class StoreEntry;
} // namespace proto
@@ -24,8 +23,7 @@ class StoreEntry;
using EntryVector =
leveldb_proto::ProtoDatabase<proto::StoreEntry>::KeyEntryVector;
-// Holds hint, prediction model, or host model features data for updating the
-// OptimizationGuideStore.
+// Holds hint or prediction model data for updating the OptimizationGuideStore.
class StoreUpdateData {
public:
StoreUpdateData(const StoreUpdateData&) = delete;
@@ -45,12 +43,6 @@ class StoreUpdateData {
static std::unique_ptr<StoreUpdateData> CreatePredictionModelStoreUpdateData(
base::Time expiry_time);
- // Creates an update data object for a host model features update.
- static std::unique_ptr<StoreUpdateData>
- CreateHostModelFeaturesStoreUpdateData(
- base::Time host_model_features_update_time,
- base::Time expiry_time);
-
// Returns the component version of a component hint update.
const absl::optional<base::Version> component_version() const {
return component_version_;
@@ -66,10 +58,6 @@ class StoreUpdateData {
// called, |hint| is no longer valid.
void MoveHintIntoUpdateData(proto::Hint&& hint);
- // Copies |host_model_features| into this update data.
- void CopyHostModelFeaturesIntoUpdateData(
- const proto::HostModelFeatures& host_model_features);
-
// Copies |prediction_model| into this update data.
void CopyPredictionModelIntoUpdateData(
const proto::PredictionModel& prediction_model);
@@ -81,8 +69,6 @@ class StoreUpdateData {
StoreUpdateData(absl::optional<base::Version> component_version,
absl::optional<base::Time> fetch_update_time,
absl::optional<base::Time> expiry_time);
- StoreUpdateData(base::Time host_model_features_update_time,
- base::Time expiry_time);
explicit StoreUpdateData(base::Time expiry_time);
// The component version of the update data for a component update.
diff --git a/chromium/components/optimization_guide/core/store_update_data_unittest.cc b/chromium/components/optimization_guide/core/store_update_data_unittest.cc
index 785033692bd..e36087ea00c 100644
--- a/chromium/components/optimization_guide/core/store_update_data_unittest.cc
+++ b/chromium/components/optimization_guide/core/store_update_data_unittest.cc
@@ -120,11 +120,13 @@ TEST(StoreUpdateDataTest, BuildPredictionModelUpdateData) {
model_info->set_version(1);
model_info->set_optimization_target(
proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD);
- model_info->add_supported_model_types(
- proto::ModelType::MODEL_TYPE_DECISION_TREE);
+ model_info->add_supported_model_engine_versions(
+ proto::ModelEngineVersion::MODEL_ENGINE_VERSION_DECISION_TREE);
+ model_info->set_keep_beyond_valid_duration(false);
- base::Time expected_expiry_time =
- base::Time::Now() + features::StoredModelsInactiveDuration();
+ model_info->mutable_valid_duration()->set_seconds(3);
+
+ base::Time expected_expiry_time = base::Time::Now() + base::Seconds(3);
std::unique_ptr<StoreUpdateData> prediction_model_update =
StoreUpdateData::CreatePredictionModelStoreUpdateData(
expected_expiry_time);
@@ -143,39 +145,14 @@ TEST(StoreUpdateDataTest, BuildPredictionModelUpdateData) {
found_prediction_model_entry = true;
EXPECT_EQ(expected_expiry_time.ToDeltaSinceWindowsEpoch().InSeconds(),
store_entry.expiry_time_secs());
+ EXPECT_EQ(store_entry.keep_beyond_valid_duration(),
+ model_info->keep_beyond_valid_duration());
break;
}
}
EXPECT_TRUE(found_prediction_model_entry);
}
-TEST(StoreUpdateDataTest, BuildHostModelFeaturesUpdateData) {
- // Verify creating a Prediction Model update data.
- base::Time host_model_features_update_time = base::Time::Now();
-
- proto::HostModelFeatures host_model_features;
- host_model_features.set_host("foo.com");
- proto::ModelFeature* model_feature = host_model_features.add_model_features();
- model_feature->set_feature_name("host_feat1");
- model_feature->set_double_value(2.0);
-
- std::unique_ptr<StoreUpdateData> host_model_features_update =
- StoreUpdateData::CreateHostModelFeaturesStoreUpdateData(
- host_model_features_update_time,
- host_model_features_update_time +
- optimization_guide::features::
- StoredHostModelFeaturesFreshnessDuration());
- host_model_features_update->CopyHostModelFeaturesIntoUpdateData(
- std::move(host_model_features));
- EXPECT_FALSE(host_model_features_update->component_version().has_value());
- EXPECT_TRUE(host_model_features_update->update_time().has_value());
- EXPECT_EQ(host_model_features_update_time,
- *host_model_features_update->update_time());
- // Verify there are 2 store entries, 1 for the metadata entry and 1 for the
- // added host model features entry.
- EXPECT_EQ(2ul, host_model_features_update->TakeUpdateEntries()->size());
-}
-
} // namespace
} // namespace optimization_guide
diff --git a/chromium/components/optimization_guide/core/test_model_executor.cc b/chromium/components/optimization_guide/core/test_model_executor.cc
index dbd8c4072b5..07c75aafcd7 100644
--- a/chromium/components/optimization_guide/core/test_model_executor.cc
+++ b/chromium/components/optimization_guide/core/test_model_executor.cc
@@ -7,13 +7,13 @@
namespace optimization_guide {
void TestModelExecutor::SendForExecution(
- ExecutionCallback ui_callback_on_complete,
+ ExecutionCallback callback_on_complete,
base::TimeTicks start_time,
const std::vector<float>& args) {
std::vector<float> results = std::vector<float>();
for (auto& arg : args)
results.push_back(arg);
- std::move(ui_callback_on_complete).Run(std::move(results));
+ std::move(callback_on_complete).Run(std::move(results));
}
} // namespace optimization_guide
diff --git a/chromium/components/optimization_guide/core/test_model_executor.h b/chromium/components/optimization_guide/core/test_model_executor.h
index 42dd3cfcff1..987942810e8 100644
--- a/chromium/components/optimization_guide/core/test_model_executor.h
+++ b/chromium/components/optimization_guide/core/test_model_executor.h
@@ -6,7 +6,6 @@
#define COMPONENTS_OPTIMIZATION_GUIDE_CORE_TEST_MODEL_EXECUTOR_H_
#include "components/optimization_guide/core/model_executor.h"
-#include "third_party/abseil-cpp/absl/status/status.h"
namespace optimization_guide {
@@ -16,7 +15,7 @@ class TestModelExecutor
TestModelExecutor() = default;
~TestModelExecutor() override = default;
- void InitializeAndMoveToBackgroundThread(
+ void InitializeAndMoveToExecutionThread(
proto::OptimizationTarget,
scoped_refptr<base::SequencedTaskRunner>,
scoped_refptr<base::SequencedTaskRunner>) override {}
@@ -29,7 +28,7 @@ class TestModelExecutor
using ExecutionCallback =
base::OnceCallback<void(const absl::optional<std::vector<float>>&)>;
- void SendForExecution(ExecutionCallback ui_callback_on_complete,
+ void SendForExecution(ExecutionCallback callback_on_complete,
base::TimeTicks start_time,
const std::vector<float>& args) override;
};
diff --git a/chromium/components/optimization_guide/core/test_model_info_builder.cc b/chromium/components/optimization_guide/core/test_model_info_builder.cc
index 9efa9d4892d..517462239da 100644
--- a/chromium/components/optimization_guide/core/test_model_info_builder.cc
+++ b/chromium/components/optimization_guide/core/test_model_info_builder.cc
@@ -4,8 +4,8 @@
#include "components/optimization_guide/core/test_model_info_builder.h"
+#include "components/optimization_guide/core/model_util.h"
#include "components/optimization_guide/core/optimization_guide_test_util.h"
-#include "components/optimization_guide/core/optimization_guide_util.h"
namespace optimization_guide {
diff --git a/chromium/components/optimization_guide/core/test_tflite_model_executor.cc b/chromium/components/optimization_guide/core/test_tflite_model_executor.cc
index 9b7ea803949..a310697de19 100644
--- a/chromium/components/optimization_guide/core/test_tflite_model_executor.cc
+++ b/chromium/components/optimization_guide/core/test_tflite_model_executor.cc
@@ -8,17 +8,19 @@
namespace optimization_guide {
-absl::Status TestTFLiteModelExecutor::Preprocess(
+bool TestTFLiteModelExecutor::Preprocess(
const std::vector<TfLiteTensor*>& input_tensors,
const std::vector<float>& input) {
- tflite::task::core::PopulateTensor<float>(input, input_tensors[0]);
- return absl::OkStatus();
+ return tflite::task::core::PopulateTensor<float>(input, input_tensors[0])
+ .ok();
}
-std::vector<float> TestTFLiteModelExecutor::Postprocess(
+absl::optional<std::vector<float>> TestTFLiteModelExecutor::Postprocess(
const std::vector<const TfLiteTensor*>& output_tensors) {
std::vector<float> data;
- tflite::task::core::PopulateVector<float>(output_tensors[0], &data);
+ absl::Status status =
+ tflite::task::core::PopulateVector<float>(output_tensors[0], &data);
+ DCHECK(status.ok());
return data;
}
diff --git a/chromium/components/optimization_guide/core/test_tflite_model_executor.h b/chromium/components/optimization_guide/core/test_tflite_model_executor.h
index ac33fd33603..39c99e4582a 100644
--- a/chromium/components/optimization_guide/core/test_tflite_model_executor.h
+++ b/chromium/components/optimization_guide/core/test_tflite_model_executor.h
@@ -16,10 +16,10 @@ class TestTFLiteModelExecutor
~TestTFLiteModelExecutor() override = default;
protected:
- absl::Status Preprocess(const std::vector<TfLiteTensor*>& input_tensors,
- const std::vector<float>& input) override;
+ bool Preprocess(const std::vector<TfLiteTensor*>& input_tensors,
+ const std::vector<float>& input) override;
- std::vector<float> Postprocess(
+ absl::optional<std::vector<float>> Postprocess(
const std::vector<const TfLiteTensor*>& output_tensors) override;
};
diff --git a/chromium/components/optimization_guide/core/tflite_model_executor.h b/chromium/components/optimization_guide/core/tflite_model_executor.h
index fe615dc6ee9..7b733101746 100644
--- a/chromium/components/optimization_guide/core/tflite_model_executor.h
+++ b/chromium/components/optimization_guide/core/tflite_model_executor.h
@@ -17,9 +17,9 @@
#include "base/time/time.h"
#include "base/trace_event/trace_event.h"
#include "components/optimization_guide/core/execution_status.h"
+#include "components/optimization_guide/core/model_enums.h"
#include "components/optimization_guide/core/model_executor.h"
-#include "components/optimization_guide/core/optimization_guide_enums.h"
-#include "components/optimization_guide/core/optimization_guide_util.h"
+#include "components/optimization_guide/core/model_util.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/tflite/src/tensorflow/lite/c/common.h"
#include "third_party/tflite_support/src/tensorflow_lite_support/cc/task/core/base_task_api.h"
@@ -34,8 +34,7 @@ class ScopedExecutionStatusResultRecorder {
public:
explicit ScopedExecutionStatusResultRecorder(
proto::OptimizationTarget optimization_target)
- : optimization_target_(optimization_target),
- start_time_(base::TimeTicks::Now()) {}
+ : optimization_target_(optimization_target) {}
~ScopedExecutionStatusResultRecorder() {
base::UmaHistogramEnumeration(
@@ -43,12 +42,6 @@ class ScopedExecutionStatusResultRecorder {
optimization_guide::GetStringNameForOptimizationTarget(
optimization_target_),
status_);
-
- base::UmaHistogramTimes(
- "OptimizationGuide.ModelExecutor.ModelLoadingDuration." +
- optimization_guide::GetStringNameForOptimizationTarget(
- optimization_target_),
- base::TimeTicks::Now() - start_time_);
}
ExecutionStatus* mutable_status() { return &status_; }
@@ -61,9 +54,6 @@ class ScopedExecutionStatusResultRecorder {
// The OptimizationTarget of the model being executed.
const proto::OptimizationTarget optimization_target_;
- // The time at which this instance was constructed.
- const base::TimeTicks start_time_;
-
ExecutionStatus status_ = ExecutionStatus::kUnknown;
};
@@ -88,26 +78,26 @@ class TFLiteModelExecutor : public ModelExecutor<OutputType, InputTypes...> {
}
// Should be called on the same sequence as the ctor, but once called |this|
- // must only be used from a background thread/sequence.
- void InitializeAndMoveToBackgroundThread(
+ // must only be used from the |execution_task_runner| thread/sequence.
+ void InitializeAndMoveToExecutionThread(
proto::OptimizationTarget optimization_target,
- scoped_refptr<base::SequencedTaskRunner> background_task_runner,
+ scoped_refptr<base::SequencedTaskRunner> execution_task_runner,
scoped_refptr<base::SequencedTaskRunner> reply_task_runner) override {
- DCHECK(!background_task_runner_);
+ DCHECK(!execution_task_runner_);
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK_NE(optimization_target,
proto::OptimizationTarget::OPTIMIZATION_TARGET_UNKNOWN);
DETACH_FROM_SEQUENCE(sequence_checker_);
optimization_target_ = optimization_target;
- background_task_runner_ = background_task_runner;
+ execution_task_runner_ = execution_task_runner;
reply_task_runner_ = reply_task_runner;
}
// Called when a model file is available to load. Depending on feature flags,
// the model may or may not be immediately loaded.
void UpdateModelFile(const base::FilePath& file_path) override {
- DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
+ DCHECK(execution_task_runner_->RunsTasksInCurrentSequence());
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
UnloadModel();
@@ -130,7 +120,7 @@ class TFLiteModelExecutor : public ModelExecutor<OutputType, InputTypes...> {
// called. False is the default behavior (see class comment).
void SetShouldUnloadModelOnComplete(
bool should_unload_model_on_complete) override {
- DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
+ DCHECK(execution_task_runner_->RunsTasksInCurrentSequence());
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
should_unload_model_on_complete_ = should_unload_model_on_complete;
}
@@ -142,21 +132,21 @@ class TFLiteModelExecutor : public ModelExecutor<OutputType, InputTypes...> {
"OptimizationTarget",
optimization_guide::GetStringNameForOptimizationTarget(
optimization_target_));
- DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
+ DCHECK(execution_task_runner_->RunsTasksInCurrentSequence());
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
loaded_model_.reset();
model_fb_.reset();
}
- // Starts the execution of the model. When complete, |ui_callback_on_complete|
- // will be run on the UI thread with the output of the model.
+ // Starts the execution of the model. When complete, |callback_on_complete|
+ // will be run via |reply_task_runner_| with the output of the model.
using ExecutionCallback =
base::OnceCallback<void(const absl::optional<OutputType>&)>;
- void SendForExecution(ExecutionCallback ui_callback_on_complete,
+ void SendForExecution(ExecutionCallback callback_on_complete,
base::TimeTicks start_time,
InputTypes... args) override {
- DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
+ DCHECK(execution_task_runner_->RunsTasksInCurrentSequence());
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(reply_task_runner_);
@@ -175,7 +165,7 @@ class TFLiteModelExecutor : public ModelExecutor<OutputType, InputTypes...> {
if (!loaded_model_ && !LoadModelFile(status_recorder.mutable_status())) {
reply_task_runner_->PostTask(
FROM_HERE,
- base::BindOnce(std::move(ui_callback_on_complete), absl::nullopt));
+ base::BindOnce(std::move(callback_on_complete), absl::nullopt));
// Some error status is expected, and derived classes should have set the
// status.
DCHECK_NE(status_recorder.status(), ExecutionStatus::kUnknown);
@@ -213,19 +203,13 @@ class TFLiteModelExecutor : public ModelExecutor<OutputType, InputTypes...> {
base::TimeTicks::Now() - execute_start_time);
}
- DCHECK(ui_callback_on_complete);
+ DCHECK(callback_on_complete);
reply_task_runner_->PostTask(
- FROM_HERE, base::BindOnce(std::move(ui_callback_on_complete), output));
+ FROM_HERE, base::BindOnce(std::move(callback_on_complete), output));
OnExecutionComplete();
}
- // IMPORTANT: These WeakPointers must only be dereferenced on the background
- // thread.
- base::WeakPtr<TFLiteModelExecutor> GetBackgroundWeakPtr() {
- return background_weak_ptr_factory_.GetWeakPtr();
- }
-
TFLiteModelExecutor(const TFLiteModelExecutor&) = delete;
TFLiteModelExecutor& operator=(const TFLiteModelExecutor&) = delete;
@@ -252,7 +236,7 @@ class TFLiteModelExecutor : public ModelExecutor<OutputType, InputTypes...> {
"OptimizationTarget",
optimization_guide::GetStringNameForOptimizationTarget(
optimization_target_));
- DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
+ DCHECK(execution_task_runner_->RunsTasksInCurrentSequence());
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
UnloadModel();
@@ -267,6 +251,8 @@ class TFLiteModelExecutor : public ModelExecutor<OutputType, InputTypes...> {
return false;
}
+ base::TimeTicks loading_start_time = base::TimeTicks::Now();
+
std::unique_ptr<base::MemoryMappedFile> model_fb =
std::make_unique<base::MemoryMappedFile>();
if (!model_fb->Initialize(*model_file_path_)) {
@@ -277,11 +263,28 @@ class TFLiteModelExecutor : public ModelExecutor<OutputType, InputTypes...> {
loaded_model_ = BuildModelExecutionTask(model_fb_.get(), out_status);
+ if (!!loaded_model_) {
+ // We only want to record successful loading times.
+ base::UmaHistogramTimes(
+ "OptimizationGuide.ModelExecutor.ModelLoadingDuration2." +
+ optimization_guide::GetStringNameForOptimizationTarget(
+ optimization_target_),
+ base::TimeTicks::Now() - loading_start_time);
+ }
+
+ // Local histogram used in integration testing.
+ base::BooleanHistogram::FactoryGet(
+ "OptimizationGuide.ModelExecutor.ModelLoadedSuccessfully." +
+ optimization_guide::GetStringNameForOptimizationTarget(
+ optimization_target_),
+ base::Histogram::kNoFlags)
+ ->Add(!!loaded_model_);
+
return !!loaded_model_;
}
void OnExecutionComplete() {
- DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
+ DCHECK(execution_task_runner_->RunsTasksInCurrentSequence());
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (should_unload_model_on_complete_) {
UnloadModel();
@@ -293,7 +296,7 @@ class TFLiteModelExecutor : public ModelExecutor<OutputType, InputTypes...> {
bool should_unload_model_on_complete_ = true;
- scoped_refptr<base::SequencedTaskRunner> background_task_runner_;
+ scoped_refptr<base::SequencedTaskRunner> execution_task_runner_;
scoped_refptr<base::SequencedTaskRunner> reply_task_runner_;
@@ -320,8 +323,6 @@ class TFLiteModelExecutor : public ModelExecutor<OutputType, InputTypes...> {
GUARDED_BY_CONTEXT(sequence_checker_);
SEQUENCE_CHECKER(sequence_checker_);
-
- base::WeakPtrFactory<TFLiteModelExecutor> background_weak_ptr_factory_{this};
};
} // namespace optimization_guide
diff --git a/chromium/components/optimization_guide/core/tflite_model_executor_unittest.cc b/chromium/components/optimization_guide/core/tflite_model_executor_unittest.cc
index 1c519e51639..c0f5f76f91e 100644
--- a/chromium/components/optimization_guide/core/tflite_model_executor_unittest.cc
+++ b/chromium/components/optimization_guide/core/tflite_model_executor_unittest.cc
@@ -187,6 +187,11 @@ TEST_F(TFLiteModelExecutorTest, ExecuteWithLoadedModel) {
optimization_guide::GetStringNameForOptimizationTarget(
proto::OptimizationTarget::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD),
ExecutionStatus::kSuccess, 1);
+ histogram_tester.ExpectUniqueSample(
+ "OptimizationGuide.ModelExecutor.ModelLoadedSuccessfully." +
+ optimization_guide::GetStringNameForOptimizationTarget(
+ proto::OptimizationTarget::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD),
+ true, 1);
}
TEST_F(TFLiteModelExecutorTest, ExecuteTwiceWithLoadedModel) {
@@ -228,6 +233,11 @@ TEST_F(TFLiteModelExecutorTest, ExecuteTwiceWithLoadedModel) {
optimization_guide::GetStringNameForOptimizationTarget(
proto::OptimizationTarget::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD),
ExecutionStatus::kSuccess, 1);
+ histogram_tester.ExpectUniqueSample(
+ "OptimizationGuide.ModelExecutor.ModelLoadedSuccessfully." +
+ optimization_guide::GetStringNameForOptimizationTarget(
+ proto::OptimizationTarget::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD),
+ true, 1);
// Second run.
run_loop = std::make_unique<base::RunLoop>();
@@ -253,6 +263,11 @@ TEST_F(TFLiteModelExecutorTest, ExecuteTwiceWithLoadedModel) {
optimization_guide::GetStringNameForOptimizationTarget(
proto::OptimizationTarget::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD),
ExecutionStatus::kSuccess, 2);
+ histogram_tester.ExpectUniqueSample(
+ "OptimizationGuide.ModelExecutor.ModelLoadedSuccessfully." +
+ optimization_guide::GetStringNameForOptimizationTarget(
+ proto::OptimizationTarget::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD),
+ true, 2);
histogram_tester.ExpectTotalCount(
"OptimizationGuide.ModelExecutor.TaskExecutionLatency." +
diff --git a/chromium/components/optimization_guide/core/tflite_op_resolver.cc b/chromium/components/optimization_guide/core/tflite_op_resolver.cc
index 1cd89433031..8674eb8d700 100644
--- a/chromium/components/optimization_guide/core/tflite_op_resolver.cc
+++ b/chromium/components/optimization_guide/core/tflite_op_resolver.cc
@@ -371,6 +371,10 @@ TFLiteOpResolver::TFLiteOpResolver() {
tflite::ops::builtin::Register_BATCH_MATMUL(),
/* min_version = */ 1,
/* max_version = */ 4);
+ AddBuiltin(tflite::BuiltinOperator_GELU,
+ tflite::ops::builtin::Register_GELU(),
+ /* min_version = */ 1,
+ /* max_version = */ 2);
}
} // namespace optimization_guide
diff --git a/chromium/components/optimization_guide/features.gni b/chromium/components/optimization_guide/features.gni
index 26d60df3f0d..2ed17e3165e 100644
--- a/chromium/components/optimization_guide/features.gni
+++ b/chromium/components/optimization_guide/features.gni
@@ -13,6 +13,18 @@ declare_args() {
# You can set the variable 'build_with_internal_optimization_guide' to true
# even in a developer build in args.gn. Setting this variable explicitly to true will
# cause your build to fail if the internal files are missing.
+ #
+ # If changing the value of this, you MUST also update the following files depending on the
+ # platform:
+ # ChromeOS: //lib/chrome_util.py in the Chromite repo (ex: https://crrev.com/c/3437291)
+ # Linux: Internal archive files. //chrome/installer/linux/common/installer.include handles the
+ # relevant files not being present.
+ # Mac: //chrome/installer/mac/signing/parts.py
+ # Windows: //chrome/installer/mini_installer/chrome.release and internal archive files
+ #
+ # The library this pulls in depends on open-source LevelDB which is not supported for Fuchsia.
+ # Android and iOS should just work but are not included in the set we release for, so we do
+ # not needlessly increase the binary.
build_with_internal_optimization_guide =
- is_chrome_branded && !is_android && !is_ios
+ is_chrome_branded && !is_android && !is_ios && !is_fuchsia
}
diff --git a/chromium/components/optimization_guide/optimization_guide_internals/resources/BUILD.gn b/chromium/components/optimization_guide/optimization_guide_internals/resources/BUILD.gn
new file mode 100644
index 00000000000..22359bed596
--- /dev/null
+++ b/chromium/components/optimization_guide/optimization_guide_internals/resources/BUILD.gn
@@ -0,0 +1,71 @@
+# Copyright 2022 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.
+
+import("//tools/grit/grit_rule.gni")
+import("//tools/polymer/html_to_js.gni")
+import("//tools/typescript/ts_library.gni")
+import("//ui/webui/resources/tools/generate_grd.gni")
+
+tsc_folder = "tsc"
+
+grit("resources") {
+ # These arguments are needed since the grd is generated at build time.
+ enable_input_discovery_for_gn_analyze = false
+ source = "$target_gen_dir/resources.grd"
+ deps = [ ":build_grd" ]
+
+ outputs = [
+ "grit/optimization_guide_internals_resources.h",
+ "grit/optimization_guide_internals_resources_map.cc",
+ "grit/optimization_guide_internals_resources_map.h",
+ "optimization_guide_internals_resources.pak",
+ ]
+
+ output_dir = "$root_gen_dir/components"
+}
+
+generate_grd("build_grd") {
+ grd_prefix = "optimization_guide_internals"
+ out_grd = "$target_gen_dir/resources.grd"
+ deps = [ ":build_ts" ]
+ manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
+ input_files = [ "optimization_guide_internals.html" ]
+ input_files_base_dir = rebase_path(".", "//")
+}
+
+html_to_js("web_components") {
+ js_files = [ "optimization_guide_internals.ts" ]
+}
+
+copy("copy_proxy") {
+ sources = [ "optimization_guide_internals_browser_proxy.ts" ]
+ outputs = [ "$target_gen_dir/{{source_file_part}}" ]
+}
+
+copy("copy_mojo") {
+ deps = [ "//components/optimization_guide/optimization_guide_internals/webui:mojo_bindings_webui_js" ]
+ mojom_folder = "$root_gen_dir/mojom-webui/components/optimization_guide/optimization_guide_internals/webui/"
+ sources = [ "$mojom_folder/optimization_guide_internals.mojom-webui.js" ]
+ outputs = [ "$target_gen_dir/{{source_file_part}}" ]
+}
+
+ts_library("build_ts") {
+ root_dir = "$target_gen_dir"
+ out_dir = "$target_gen_dir/$tsc_folder"
+ tsconfig_base = "tsconfig_base.json"
+ in_files = [
+ "optimization_guide_internals.ts",
+ "optimization_guide_internals_browser_proxy.ts",
+ "optimization_guide_internals.mojom-webui.js",
+ ]
+ deps = [
+ "//ui/webui/resources:library",
+ "//ui/webui/resources/js/browser_command:build_ts",
+ ]
+ extra_deps = [
+ ":copy_mojo",
+ ":copy_proxy",
+ ":web_components",
+ ]
+}
diff --git a/chromium/components/optimization_guide/optimization_guide_internals/resources/OWNERS b/chromium/components/optimization_guide/optimization_guide_internals/resources/OWNERS
new file mode 100644
index 00000000000..1ee724d06f4
--- /dev/null
+++ b/chromium/components/optimization_guide/optimization_guide_internals/resources/OWNERS
@@ -0,0 +1 @@
+file://components/optimization_guide/OWNERS
diff --git a/chromium/components/optimization_guide/optimization_guide_internals/resources/optimization_guide_internals.html b/chromium/components/optimization_guide/optimization_guide_internals/resources/optimization_guide_internals.html
new file mode 100644
index 00000000000..8237d8a8f29
--- /dev/null
+++ b/chromium/components/optimization_guide/optimization_guide_internals/resources/optimization_guide_internals.html
@@ -0,0 +1,29 @@
+<!doctype html>
+<html lang="en" dir="ltr">
+ <head>
+ <style>
+ .segment {
+ border: 1px outset black;
+ margin: 2px 2px 2px 2px;
+ }
+ </style>
+ <meta charset="utf-8">
+ <title>Optimization Guide Internals</title>
+ <meta name="viewport" content="width=device-width">
+ <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
+ </head>
+ <body>
+ <h1>Optimization Guide Internals - Debug Logs</h1>
+ <button id="log-messages-dump">Dump</button>
+ <table id="log-message-container">
+ <thead>
+ <tr>
+ <th>Time</th>
+ <th>Source Location</th>
+ <th>Log Message</th>
+ </tr>
+ </thead>
+ </table>
+ <script type="module" src="optimization_guide_internals.js"></script>
+ </body>
+</html> \ No newline at end of file
diff --git a/chromium/components/optimization_guide/optimization_guide_internals/resources/optimization_guide_internals.ts b/chromium/components/optimization_guide/optimization_guide_internals/resources/optimization_guide_internals.ts
new file mode 100644
index 00000000000..df91b5bcf79
--- /dev/null
+++ b/chromium/components/optimization_guide/optimization_guide_internals/resources/optimization_guide_internals.ts
@@ -0,0 +1,80 @@
+// Copyright 2022 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.
+
+import {$} from 'chrome://resources/js/util.m.js';
+import {Time} from 'chrome://resources/mojo/mojo/public/mojom/base/time.mojom-webui.js';
+
+import {OptimizationGuideInternalsBrowserProxy} from './optimization_guide_internals_browser_proxy.js';
+
+// Contains all the log events received when the internals page is open.
+const logMessages:
+ {eventTime: string, sourceLocation: string, message: string}[] = [];
+
+/**
+ * Converts a mojo time to a JS time.
+ * @param {!mojoBase.mojom.Time} mojoTime
+ * @return {!Date}
+ */
+function convertMojoTimeToJS(mojoTime: Time) {
+ // The JS Date() is based off of the number of milliseconds since the
+ // UNIX epoch (1970-01-01 00::00:00 UTC), while |internalValue| of the
+ // base::Time (represented in mojom.Time) represents the number of
+ // microseconds since the Windows FILETIME epoch (1601-01-01 00:00:00 UTC).
+ // This computes the final JS time by computing the epoch delta and the
+ // conversion from microseconds to milliseconds.
+ const windowsEpoch = Date.UTC(1601, 0, 1, 0, 0, 0, 0);
+ const unixEpoch = Date.UTC(1970, 0, 1, 0, 0, 0, 0);
+ // |epochDeltaInMs| equals to base::Time::kTimeTToMicrosecondsOffset.
+ const epochDeltaInMs = unixEpoch - windowsEpoch;
+ const timeInMs = Number(mojoTime.internalValue) / 1000;
+
+ return new Date(timeInMs - epochDeltaInMs);
+}
+
+/**
+ * The callback to button#log-messages-dump to save the logs to a file.
+ */
+function onLogMessagesDump() {
+ const data = JSON.stringify(logMessages);
+ const blob = new Blob([data], {'type': 'text/json'});
+ const url = URL.createObjectURL(blob);
+ const filename = 'optimization_guide_internals_logs_dump.json';
+
+ const a = document.createElement('a');
+ a.setAttribute('href', url);
+ a.setAttribute('download', filename);
+
+ const event = document.createEvent('MouseEvent');
+ event.initMouseEvent(
+ 'click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0,
+ null);
+ a.dispatchEvent(event);
+}
+
+function getProxy(): OptimizationGuideInternalsBrowserProxy {
+ return OptimizationGuideInternalsBrowserProxy.getInstance();
+}
+
+
+function initialize() {
+ const logMessageContainer = $('log-message-container') as HTMLTableElement;
+
+ $('log-messages-dump').addEventListener('click', onLogMessagesDump);
+
+ getProxy().getCallbackRouter().onLogMessageAdded.addListener(
+ (eventTime: Time, sourceFile: string, sourceLine: number,
+ message: string) => {
+ const eventTimeStr = convertMojoTimeToJS(eventTime).toISOString();
+ const sourceLocation = `${sourceFile}(${sourceLine})`;
+ logMessages.push({eventTime: eventTimeStr, sourceLocation, message});
+ if (logMessageContainer) {
+ const logmessage = logMessageContainer.insertRow();
+ logmessage.insertCell().innerHTML = eventTimeStr;
+ logmessage.insertCell().innerHTML = sourceLocation;
+ logmessage.insertCell().innerHTML = message;
+ }
+ });
+}
+
+document.addEventListener('DOMContentLoaded', initialize); \ No newline at end of file
diff --git a/chromium/components/optimization_guide/optimization_guide_internals/resources/optimization_guide_internals_browser_proxy.ts b/chromium/components/optimization_guide/optimization_guide_internals/resources/optimization_guide_internals_browser_proxy.ts
new file mode 100644
index 00000000000..b7636abbe61
--- /dev/null
+++ b/chromium/components/optimization_guide/optimization_guide_internals/resources/optimization_guide_internals_browser_proxy.ts
@@ -0,0 +1,26 @@
+// Copyright 2022 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.
+
+import {PageCallbackRouter, PageHandlerFactory} from './optimization_guide_internals.mojom-webui.js';
+
+export class OptimizationGuideInternalsBrowserProxy {
+ private callbackRouter: PageCallbackRouter;
+
+ constructor() {
+ this.callbackRouter = new PageCallbackRouter();
+ const factory = PageHandlerFactory.getRemote();
+ factory.createPageHandler(this.callbackRouter.$.bindNewPipeAndPassRemote());
+ }
+
+ static getInstance(): OptimizationGuideInternalsBrowserProxy {
+ return instance ||
+ (instance = new OptimizationGuideInternalsBrowserProxy());
+ }
+
+ getCallbackRouter(): PageCallbackRouter {
+ return this.callbackRouter;
+ }
+}
+
+let instance: OptimizationGuideInternalsBrowserProxy|null = null; \ No newline at end of file
diff --git a/chromium/components/optimization_guide/optimization_guide_internals/resources/tsconfig_base.json b/chromium/components/optimization_guide/optimization_guide_internals/resources/tsconfig_base.json
new file mode 100644
index 00000000000..cbf406ef813
--- /dev/null
+++ b/chromium/components/optimization_guide/optimization_guide_internals/resources/tsconfig_base.json
@@ -0,0 +1,6 @@
+{
+ "extends": "../../../../tools/typescript/tsconfig_base.json",
+ "compilerOptions": {
+ "allowJs": true
+ }
+} \ No newline at end of file
diff --git a/chromium/components/optimization_guide/optimization_guide_internals/webui/BUILD.gn b/chromium/components/optimization_guide/optimization_guide_internals/webui/BUILD.gn
new file mode 100644
index 00000000000..f5952e8ff2f
--- /dev/null
+++ b/chromium/components/optimization_guide/optimization_guide_internals/webui/BUILD.gn
@@ -0,0 +1,30 @@
+# Copyright 2022 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.
+
+import("//mojo/public/tools/bindings/mojom.gni")
+
+static_library("webui") {
+ sources = [
+ "optimization_guide_internals_page_handler_impl.cc",
+ "optimization_guide_internals_page_handler_impl.h",
+ "optimization_guide_internals_ui.cc",
+ "optimization_guide_internals_ui.h",
+ "url_constants.cc",
+ "url_constants.h",
+ ]
+ deps = [
+ "//base",
+ "//components/optimization_guide/core",
+ "//components/optimization_guide/optimization_guide_internals/resources:resources",
+ "//components/optimization_guide/optimization_guide_internals/webui:mojo_bindings",
+ "//third_party/abseil-cpp:absl",
+ "//ui/base",
+ "//ui/webui",
+ ]
+}
+mojom("mojo_bindings") {
+ sources = [ "optimization_guide_internals.mojom" ]
+ webui_module_path = "/"
+ public_deps = [ "//mojo/public/mojom/base" ]
+}
diff --git a/chromium/components/optimization_guide/optimization_guide_internals/webui/DEPS b/chromium/components/optimization_guide/optimization_guide_internals/webui/DEPS
new file mode 100644
index 00000000000..930de395723
--- /dev/null
+++ b/chromium/components/optimization_guide/optimization_guide_internals/webui/DEPS
@@ -0,0 +1,7 @@
+include_rules = [
+ "+mojo/public/cpp/bindings",
+ "+ui/base/webui/resource_path.h",
+ "+ui/webui/mojo_web_ui_controller.h",
+ "+components/grit/optimization_guide_internals_resources.h",
+ "+components/grit/optimization_guide_internals_resources_map.h",
+]
diff --git a/chromium/components/optimization_guide/optimization_guide_internals/webui/OWNERS b/chromium/components/optimization_guide/optimization_guide_internals/webui/OWNERS
new file mode 100644
index 00000000000..5245dc478f1
--- /dev/null
+++ b/chromium/components/optimization_guide/optimization_guide_internals/webui/OWNERS
@@ -0,0 +1,4 @@
+file://components/optimization_guide/OWNERS
+
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS \ No newline at end of file
diff --git a/chromium/components/optimization_guide/optimization_guide_internals/webui/optimization_guide_internals.mojom b/chromium/components/optimization_guide/optimization_guide_internals/webui/optimization_guide_internals.mojom
new file mode 100644
index 00000000000..b4eec080fa0
--- /dev/null
+++ b/chromium/components/optimization_guide/optimization_guide_internals/webui/optimization_guide_internals.mojom
@@ -0,0 +1,24 @@
+// Copyright 2022 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.
+
+
+module optimization_guide_internals.mojom;
+
+import "mojo/public/mojom/base/time.mojom";
+
+// Used by the WebUI page to bootstrap bidirectional communication.
+interface PageHandlerFactory {
+ // The WebUI calls this method when the page is first initialized.
+ CreatePageHandler(pending_remote<Page> page);
+};
+
+// Renderer-side handler for internal page to process the updates from
+// the OptimizationGuide service.
+interface Page {
+ // Notifies the page of a log event from the OptimizationGuide service.
+ OnLogMessageAdded(mojo_base.mojom.Time event_time,
+ string source_file,
+ int64 source_line,
+ string message);
+};
diff --git a/chromium/components/optimization_guide/optimization_guide_internals/webui/optimization_guide_internals_page_handler_impl.cc b/chromium/components/optimization_guide/optimization_guide_internals/webui/optimization_guide_internals_page_handler_impl.cc
new file mode 100644
index 00000000000..40ebfe372f0
--- /dev/null
+++ b/chromium/components/optimization_guide/optimization_guide_internals/webui/optimization_guide_internals_page_handler_impl.cc
@@ -0,0 +1,31 @@
+// Copyright 2022 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.
+
+#include "components/optimization_guide/optimization_guide_internals/webui/optimization_guide_internals_page_handler_impl.h"
+
+#include "base/time/time.h"
+
+OptimizationGuideInternalsPageHandlerImpl::
+ OptimizationGuideInternalsPageHandlerImpl(
+ mojo::PendingRemote<optimization_guide_internals::mojom::Page> page,
+ OptimizationGuideLogger* optimization_guide_logger)
+ : page_(std::move(page)),
+ optimization_guide_logger_(optimization_guide_logger) {
+ if (optimization_guide_logger_)
+ optimization_guide_logger_->AddObserver(this);
+}
+
+OptimizationGuideInternalsPageHandlerImpl::
+ ~OptimizationGuideInternalsPageHandlerImpl() {
+ if (optimization_guide_logger_)
+ optimization_guide_logger_->RemoveObserver(this);
+}
+
+void OptimizationGuideInternalsPageHandlerImpl::OnLogMessageAdded(
+ base::Time event_time,
+ const std::string& source_file,
+ int source_line,
+ const std::string& message) {
+ page_->OnLogMessageAdded(event_time, source_file, source_line, message);
+}
diff --git a/chromium/components/optimization_guide/optimization_guide_internals/webui/optimization_guide_internals_page_handler_impl.h b/chromium/components/optimization_guide/optimization_guide_internals/webui/optimization_guide_internals_page_handler_impl.h
new file mode 100644
index 00000000000..6816e3b68ec
--- /dev/null
+++ b/chromium/components/optimization_guide/optimization_guide_internals/webui/optimization_guide_internals_page_handler_impl.h
@@ -0,0 +1,44 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_OPTIMIZATION_GUIDE_OPTIMIZATION_GUIDE_INTERNALS_WEBUI_OPTIMIZATION_GUIDE_INTERNALS_PAGE_HANDLER_IMPL_H_
+#define COMPONENTS_OPTIMIZATION_GUIDE_OPTIMIZATION_GUIDE_INTERNALS_WEBUI_OPTIMIZATION_GUIDE_INTERNALS_PAGE_HANDLER_IMPL_H_
+
+#include <string>
+
+#include "components/optimization_guide/core/optimization_guide_logger.h"
+#include "components/optimization_guide/optimization_guide_internals/webui/optimization_guide_internals.mojom.h"
+#include "mojo/public/cpp/bindings/remote.h"
+
+// Handler for the internals page to receive and forward the log messages.
+class OptimizationGuideInternalsPageHandlerImpl
+ : public OptimizationGuideLogger::Observer {
+ public:
+ OptimizationGuideInternalsPageHandlerImpl(
+ mojo::PendingRemote<optimization_guide_internals::mojom::Page> page,
+ OptimizationGuideLogger* optimization_guide_logger);
+ ~OptimizationGuideInternalsPageHandlerImpl() override;
+
+ OptimizationGuideInternalsPageHandlerImpl(
+ const OptimizationGuideInternalsPageHandlerImpl&) = delete;
+ OptimizationGuideInternalsPageHandlerImpl& operator=(
+ const OptimizationGuideInternalsPageHandlerImpl&) = delete;
+
+ private:
+ // optimization_guide::OptimizationGuideLogger::Observer overrides.
+ void OnLogMessageAdded(base::Time event_time,
+ const std::string& source_file,
+ int source_line,
+ const std::string& message) override;
+
+ mojo::Remote<optimization_guide_internals::mojom::Page> page_;
+
+ // Logger to receive the debug logs from the optimization guide service. Not
+ // owned. Guaranteed to outlive |this|, since the logger is owned by the
+ // optimization guide keyed service, while |this| is part of
+ // RenderFrameHostImpl::WebUIImpl.
+ raw_ptr<OptimizationGuideLogger> optimization_guide_logger_;
+};
+
+#endif // COMPONENTS_OPTIMIZATION_GUIDE_OPTIMIZATION_GUIDE_INTERNALS_WEBUI_OPTIMIZATION_GUIDE_INTERNALS_PAGE_HANDLER_IMPL_H_
diff --git a/chromium/components/optimization_guide/optimization_guide_internals/webui/optimization_guide_internals_ui.cc b/chromium/components/optimization_guide/optimization_guide_internals/webui/optimization_guide_internals_ui.cc
new file mode 100644
index 00000000000..e69b01edbff
--- /dev/null
+++ b/chromium/components/optimization_guide/optimization_guide_internals/webui/optimization_guide_internals_ui.cc
@@ -0,0 +1,38 @@
+// Copyright 2022 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.
+
+#include "components/optimization_guide/optimization_guide_internals/webui/optimization_guide_internals_ui.h"
+
+#include "components/grit/optimization_guide_internals_resources.h"
+#include "components/grit/optimization_guide_internals_resources_map.h"
+#include "components/optimization_guide/optimization_guide_internals/webui/optimization_guide_internals_page_handler_impl.h"
+
+OptimizationGuideInternalsUI::OptimizationGuideInternalsUI(
+ content::WebUI* web_ui,
+ OptimizationGuideLogger* optimization_guide_logger,
+ SetupWebUIDataSourceCallback set_up_data_source_callback)
+ : MojoWebUIController(web_ui, /*enable_chrome_send=*/true),
+ optimization_guide_logger_(optimization_guide_logger) {
+ std::move(set_up_data_source_callback)
+ .Run(base::make_span(kOptimizationGuideInternalsResources,
+ kOptimizationGuideInternalsResourcesSize),
+ IDR_OPTIMIZATION_GUIDE_INTERNALS_OPTIMIZATION_GUIDE_INTERNALS_HTML);
+}
+
+OptimizationGuideInternalsUI::~OptimizationGuideInternalsUI() = default;
+
+void OptimizationGuideInternalsUI::BindInterface(
+ mojo::PendingReceiver<
+ optimization_guide_internals::mojom::PageHandlerFactory> receiver) {
+ optimization_guide_internals_page_factory_receiver_.Bind(std::move(receiver));
+}
+
+void OptimizationGuideInternalsUI::CreatePageHandler(
+ mojo::PendingRemote<optimization_guide_internals::mojom::Page> page) {
+ optimization_guide_internals_page_handler_ =
+ std::make_unique<OptimizationGuideInternalsPageHandlerImpl>(
+ std::move(page), optimization_guide_logger_);
+}
+
+WEB_UI_CONTROLLER_TYPE_IMPL(OptimizationGuideInternalsUI)
diff --git a/chromium/components/optimization_guide/optimization_guide_internals/webui/optimization_guide_internals_ui.h b/chromium/components/optimization_guide/optimization_guide_internals/webui/optimization_guide_internals_ui.h
new file mode 100644
index 00000000000..4421de745c8
--- /dev/null
+++ b/chromium/components/optimization_guide/optimization_guide_internals/webui/optimization_guide_internals_ui.h
@@ -0,0 +1,59 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_OPTIMIZATION_GUIDE_OPTIMIZATION_GUIDE_INTERNALS_WEBUI_OPTIMIZATION_GUIDE_INTERNALS_UI_H_
+#define COMPONENTS_OPTIMIZATION_GUIDE_OPTIMIZATION_GUIDE_INTERNALS_WEBUI_OPTIMIZATION_GUIDE_INTERNALS_UI_H_
+
+#include "components/optimization_guide/optimization_guide_internals/webui/optimization_guide_internals.mojom.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "ui/base/webui/resource_path.h"
+#include "ui/webui/mojo_web_ui_controller.h"
+
+class OptimizationGuideLogger;
+class OptimizationGuideInternalsPageHandlerImpl;
+
+// The WebUI controller for chrome://optimization-guide-internals.
+class OptimizationGuideInternalsUI
+ : public ui::MojoWebUIController,
+ public optimization_guide_internals::mojom::PageHandlerFactory {
+ public:
+ using SetupWebUIDataSourceCallback =
+ base::OnceCallback<void(base::span<const webui::ResourcePath> resources,
+ int default_resource)>;
+
+ explicit OptimizationGuideInternalsUI(
+ content::WebUI* web_ui,
+ OptimizationGuideLogger* optimization_guide_logger,
+ SetupWebUIDataSourceCallback set_up_data_source_callback);
+ ~OptimizationGuideInternalsUI() override;
+
+ OptimizationGuideInternalsUI(const OptimizationGuideInternalsUI&) = delete;
+ OptimizationGuideInternalsUI& operator=(const OptimizationGuideInternalsUI&) =
+ delete;
+
+ void BindInterface(
+ mojo::PendingReceiver<
+ optimization_guide_internals::mojom::PageHandlerFactory> receiver);
+
+ private:
+ // optimization_guide_internals::mojom::PageHandlerFactory impls.
+ void CreatePageHandler(
+ mojo::PendingRemote<optimization_guide_internals::mojom::Page> page)
+ override;
+
+ std::unique_ptr<OptimizationGuideInternalsPageHandlerImpl>
+ optimization_guide_internals_page_handler_;
+ mojo::Receiver<optimization_guide_internals::mojom::PageHandlerFactory>
+ optimization_guide_internals_page_factory_receiver_{this};
+
+ // Logger to receive the debug logs from the optimization guide service. Not
+ // owned. Guaranteed to outlive |this|, since the logger is owned by the
+ // optimization guide keyed service, while |this| is part of
+ // RenderFrameHostImpl::WebUIImpl.
+ raw_ptr<OptimizationGuideLogger> optimization_guide_logger_;
+
+ WEB_UI_CONTROLLER_TYPE_DECL();
+};
+
+#endif // COMPONENTS_OPTIMIZATION_GUIDE_OPTIMIZATION_GUIDE_INTERNALS_WEBUI_OPTIMIZATION_GUIDE_INTERNALS_UI_H_
diff --git a/chromium/components/optimization_guide/optimization_guide_internals/webui/url_constants.cc b/chromium/components/optimization_guide/optimization_guide_internals/webui/url_constants.cc
new file mode 100644
index 00000000000..3fc092ccddb
--- /dev/null
+++ b/chromium/components/optimization_guide/optimization_guide_internals/webui/url_constants.cc
@@ -0,0 +1,12 @@
+// Copyright 2022 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.
+
+#include "components/optimization_guide/optimization_guide_internals/webui/url_constants.h"
+
+namespace optimization_guide_internals {
+
+const char kChromeUIOptimizationGuideInternalsHost[] =
+ "optimization-guide-internals";
+
+}
diff --git a/chromium/components/optimization_guide/optimization_guide_internals/webui/url_constants.h b/chromium/components/optimization_guide/optimization_guide_internals/webui/url_constants.h
new file mode 100644
index 00000000000..14a21360f89
--- /dev/null
+++ b/chromium/components/optimization_guide/optimization_guide_internals/webui/url_constants.h
@@ -0,0 +1,15 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_OPTIMIZATION_GUIDE_OPTIMIZATION_GUIDE_INTERNALS_WEBUI_URL_CONSTANTS_H_
+#define COMPONENTS_OPTIMIZATION_GUIDE_OPTIMIZATION_GUIDE_INTERNALS_WEBUI_URL_CONSTANTS_H_
+
+namespace optimization_guide_internals {
+
+// The host of the optimization guide internals page URL.
+extern const char kChromeUIOptimizationGuideInternalsHost[];
+
+} // namespace optimization_guide_internals
+
+#endif // COMPONENTS_OPTIMIZATION_GUIDE_OPTIMIZATION_GUIDE_INTERNALS_WEBUI_URL_CONSTANTS_H_
diff --git a/chromium/components/optimization_guide/proto/BUILD.gn b/chromium/components/optimization_guide/proto/BUILD.gn
index 288e9fd2c25..2253201609c 100644
--- a/chromium/components/optimization_guide/proto/BUILD.gn
+++ b/chromium/components/optimization_guide/proto/BUILD.gn
@@ -17,6 +17,7 @@ proto_library("optimization_guide_proto") {
"loading_predictor_metadata.proto",
"models.proto",
"page_entities_metadata.proto",
+ "page_entities_model_metadata.proto",
"page_topics_model_metadata.proto",
"performance_hints_metadata.proto",
"public_image_metadata.proto",
diff --git a/chromium/components/optimization_guide/proto/hint_cache.proto b/chromium/components/optimization_guide/proto/hint_cache.proto
index a27430d3e53..e89dec22aa3 100644
--- a/chromium/components/optimization_guide/proto/hint_cache.proto
+++ b/chromium/components/optimization_guide/proto/hint_cache.proto
@@ -59,4 +59,6 @@ message StoreEntry {
optional PredictionModel prediction_model = 6;
// The actual HostModelFeature data.
optional HostModelFeatures host_model_features = 7;
+ // Whether to delete a model once expiry_time_secs is past.
+ optional bool keep_beyond_valid_duration = 8;
}
diff --git a/chromium/components/optimization_guide/proto/models.proto b/chromium/components/optimization_guide/proto/models.proto
index c69cb127eec..a916421b570 100644
--- a/chromium/components/optimization_guide/proto/models.proto
+++ b/chromium/components/optimization_guide/proto/models.proto
@@ -200,7 +200,7 @@ message AdditionalModelFile {
// Metadata for a prediction model for a specific optimization target.
//
-// Next ID: 8
+// Next ID: 10
message ModelInfo {
reserved 3;
@@ -208,8 +208,9 @@ message ModelInfo {
optional OptimizationTarget optimization_target = 1;
// The version of the model, which is specific to the optimization target.
optional int64 version = 2;
- // The set of model types the requesting client can use to make predictions.
- repeated ModelType supported_model_types = 4;
+ // The set of model engine versions the requesting client can use to do model
+ // inference.
+ repeated ModelEngineVersion supported_model_engine_versions = 4;
// The set of host model features that are referenced by the model.
//
// Note that this should only be populated if part of the response.
@@ -222,6 +223,11 @@ message ModelInfo {
// This does not need to be sent to the server in the request for an update to
// this model. The server will ignore this if sent.
repeated AdditionalModelFile additional_files = 7;
+ // How long the model will remain valid in client storage. If
+ // |keep_beyond_valid_duration| is true, will be ignored.
+ optional Duration valid_duration = 8;
+ // Whether to delete the model once valid_duration has passed.
+ optional bool keep_beyond_valid_duration = 9;
// Mechanism used for model owners to attach metadata to the request or
// response.
//
@@ -267,31 +273,38 @@ enum OptimizationTarget {
// Target for determining topics present on a page.
// TODO(crbug/1266504): Remove PAGE_TOPICS in favor of this target.
OPTIMIZATION_TARGET_PAGE_TOPICS_V2 = 15;
+ // Target for segmentation: Determine users with low engagement with chrome.
+ OPTIMIZATION_TARGET_SEGMENTATION_CHROME_LOW_USER_ENGAGEMENT = 16;
}
-// The types of models that can be evaluated.
+// The model engine versions that can be used to do model inference.
//
// Please only update these enums when a new major version of TFLite rolls.
//
// For example: v1.2.3
// ^
// Change when this number increments.
-enum ModelType {
- MODEL_TYPE_UNKNOWN = 0;
+enum ModelEngineVersion {
+ MODEL_ENGINE_VERSION_UNKNOWN = 0;
// A decision tree.
- MODEL_TYPE_DECISION_TREE = 1;
+ MODEL_ENGINE_VERSION_DECISION_TREE = 1;
// A model using only operations that are supported by TensorflowLite 2.3.0.
- MODEL_TYPE_TFLITE_2_3_0 = 2;
+ MODEL_ENGINE_VERSION_TFLITE_2_3_0 = 2;
// A model using only operations that are supported by TensorflowLite 2.3.0
// with updated FULLY_CONNECTED and BATCH_MUL versions for quantized models.
- MODEL_TYPE_TFLITE_2_3_0_1 = 3;
+ MODEL_ENGINE_VERSION_TFLITE_2_3_0_1 = 3;
// TensorflowLite version 2.4.2, and a bit more up to internal rev number
// 381280669.
- MODEL_TYPE_TFLITE_2_4 = 4;
+ MODEL_ENGINE_VERSION_TFLITE_2_4 = 4;
// TensorflowLite version 2.7.*. This is where regular ~HEAD rolls started.
- MODEL_TYPE_TFLITE_2_7 = 5;
+ MODEL_ENGINE_VERSION_TFLITE_2_7 = 5;
// A model using only operations that are supported by TensorflowLite 2.8.0.
- MODEL_TYPE_TFLITE_2_8 = 6;
+ MODEL_ENGINE_VERSION_TFLITE_2_8 = 6;
+ // A model using only operations that are supported by TensorflowLite 2.9.0.
+ MODEL_ENGINE_VERSION_TFLITE_2_9 = 7;
+ // A model using only operations that are supported by TensorflowLite 2.9.0.
+ // This adds GELU to the supported ops in Optimiziation Guide.
+ MODEL_ENGINE_VERSION_TFLITE_2_9_0_1 = 8;
}
// A set of model features and the host that it applies to.
diff --git a/chromium/components/optimization_guide/proto/page_entities_metadata.proto b/chromium/components/optimization_guide/proto/page_entities_metadata.proto
index 96a8479f179..1b5fa334a18 100644
--- a/chromium/components/optimization_guide/proto/page_entities_metadata.proto
+++ b/chromium/components/optimization_guide/proto/page_entities_metadata.proto
@@ -24,7 +24,18 @@ message Entity {
// entities on the page.
//
// It is only populated for the PAGE_ENTITIES optimization type.
+//
+// Note that the meaning of metadata here is in relation to a page load.
message PageEntitiesMetadata {
// A set of entities that are expected to be present on the page.
repeated Entity entities = 1;
}
+
+// The metadata associated with an |Entity|.
+//
+// Each |Entity| has some attached metadata about it which may be stored on
+// device for later lookup. Notably, this includes it's human-readable name as
+// opposed to the opaque entity_id.
+message EntityMetadataStorage {
+ optional string entity_name = 1;
+} \ No newline at end of file
diff --git a/chromium/components/optimization_guide/proto/page_entities_model_metadata.proto b/chromium/components/optimization_guide/proto/page_entities_model_metadata.proto
new file mode 100644
index 00000000000..cf239e37352
--- /dev/null
+++ b/chromium/components/optimization_guide/proto/page_entities_model_metadata.proto
@@ -0,0 +1,25 @@
+// Copyright 2022 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.
+
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+option java_package = "org.chromium.components.optimization_guide.proto";
+option java_outer_classname = "PageEntitiesModelMetadataProto";
+
+package optimization_guide.proto;
+
+message PageEntitiesModelMetadata {
+ // The maximum model format feature flag that is supported.
+ //
+ // If sent from the server, this is the maximum model format feature flag the
+ // returned model supports. If sent from the client, this is the maximum
+ // model format feature flag the client knows how to evaluate.
+ optional int32 max_model_format_feature_flag = 1;
+
+ // The slices to load into the entity annotator.
+ //
+ // Will only be populated by the server.
+ repeated string slice = 2;
+} \ No newline at end of file
diff --git a/chromium/components/optimization_guide/proto/page_topics_model_metadata.proto b/chromium/components/optimization_guide/proto/page_topics_model_metadata.proto
index 59e4a0441be..42516c9358a 100644
--- a/chromium/components/optimization_guide/proto/page_topics_model_metadata.proto
+++ b/chromium/components/optimization_guide/proto/page_topics_model_metadata.proto
@@ -50,7 +50,24 @@ message PageTopicsOutputPostprocessingParams {
optional PageTopicsCategoryPostprocessingParams category_params = 2;
}
+message Topic {
+ // The user-visible string of the taxonomy topic.
+ optional string topic_name = 1;
+ // The id of the topic.
+ optional int64 topic_id = 2;
+}
+
+message TopicTaxonomy {
+ // The version of this specific taxonomy, which is separate from the model
+ // version.
+ optional int64 version = 1;
+ // The topics supported by this taxonomy.
+ repeated Topic topics = 2;
+}
+
message PageTopicsModelMetadata {
+ reserved 4;
+
// The version of the model sent by the server, and thus, will only be
// populated by the server.
optional int64 version = 1;
@@ -64,4 +81,6 @@ message PageTopicsModelMetadata {
// populated by the server.
optional PageTopicsOutputPostprocessingParams output_postprocessing_params =
3;
+ // The taxonomy used by this model.
+ optional TopicTaxonomy topic_taxonomy = 5;
}
diff --git a/chromium/components/os_crypt/BUILD.gn b/chromium/components/os_crypt/BUILD.gn
index bd376411505..0afd3f7e942 100644
--- a/chromium/components/os_crypt/BUILD.gn
+++ b/chromium/components/os_crypt/BUILD.gn
@@ -41,6 +41,7 @@ component("os_crypt") {
deps = [
"//base",
"//build:branding_buildflags",
+ "//build:chromecast_buildflags",
"//build:chromeos_buildflags",
"//components/prefs",
"//crypto",
@@ -56,8 +57,7 @@ component("os_crypt") {
defines += [ "ALLOW_RUNTIME_CONFIGURABLE_KEY_STORAGE" ]
}
- if ((is_posix || is_fuchsia) && !is_apple &&
- (!(is_linux || is_chromeos_lacros) || is_chromecast)) {
+ if ((is_posix || is_fuchsia) && !is_apple && (!is_linux || is_chromecast)) {
sources += [ "os_crypt_posix.cc" ]
}
@@ -74,7 +74,7 @@ component("os_crypt") {
libs = [ "crypt32.lib" ]
}
- if ((is_linux || is_chromeos_lacros) && !is_chromecast) {
+ if (is_linux && !is_chromecast) {
sources += [
"key_storage_config_linux.cc",
"key_storage_config_linux.h",
@@ -130,7 +130,7 @@ static_library("test_support") {
"//base",
"//testing/gtest",
]
- if ((is_linux || is_chromeos_lacros) && !is_chromecast) {
+ if (is_linux && !is_chromecast) {
sources += [
"os_crypt_mocker_linux.cc",
"os_crypt_mocker_linux.h",
@@ -168,7 +168,7 @@ source_set("unit_tests") {
sources += [ "keychain_password_mac_unittest.mm" ]
}
- if ((is_linux || is_chromeos_lacros) && !is_chromecast) {
+ if (is_linux && !is_chromecast) {
sources += [
"key_storage_linux_unittest.cc",
"key_storage_util_linux_unittest.cc",
diff --git a/chromium/components/os_crypt/features.gni b/chromium/components/os_crypt/features.gni
index 73b6e870329..ec9c3da66af 100644
--- a/chromium/components/os_crypt/features.gni
+++ b/chromium/components/os_crypt/features.gni
@@ -8,7 +8,7 @@ import("//build/config/ui.gni")
declare_args() {
# Whether to use libgnome-keyring (deprecated by libsecret).
# See http://crbug.com/466975 and http://crbug.com/355223.
- use_gnome_keyring = (is_linux || is_chromeos_lacros) && use_glib
+ use_gnome_keyring = is_linux && use_glib
# Whether to make account and service names for the crypto key storage
# configurable at runtime for embedders.
diff --git a/chromium/components/os_crypt/key_storage_kwallet.cc b/chromium/components/os_crypt/key_storage_kwallet.cc
index 2ed42e9f782..b2bb1f09ef8 100644
--- a/chromium/components/os_crypt/key_storage_kwallet.cc
+++ b/chromium/components/os_crypt/key_storage_kwallet.cc
@@ -4,10 +4,10 @@
#include "components/os_crypt/key_storage_kwallet.h"
+#include <tuple>
#include <utility>
#include "base/base64.h"
-#include "base/ignore_result.h"
#include "base/notreached.h"
#include "base/rand_util.h"
#include "components/os_crypt/kwallet_dbus.h"
@@ -21,7 +21,7 @@ KeyStorageKWallet::~KeyStorageKWallet() {
// The handle is shared between programs that are using the same wallet.
// Closing the wallet is a nop in the typical case.
bool success = true;
- ignore_result(kwallet_dbus_->Close(handle_, false, app_name_, &success));
+ std::ignore = kwallet_dbus_->Close(handle_, false, app_name_, &success);
kwallet_dbus_->GetSessionBus()->ShutdownAndBlock();
}
diff --git a/chromium/components/os_crypt/kwallet_dbus.h b/chromium/components/os_crypt/kwallet_dbus.h
index 566832ffffd..97031743fc5 100644
--- a/chromium/components/os_crypt/kwallet_dbus.h
+++ b/chromium/components/os_crypt/kwallet_dbus.h
@@ -39,7 +39,7 @@ class COMPONENT_EXPORT(OS_CRYPT) KWalletDBus {
virtual dbus::Bus* GetSessionBus();
// Use KLauncher to start the KWallet service. Returns true if successful.
- virtual bool StartKWalletd() WARN_UNUSED_RESULT;
+ [[nodiscard]] virtual bool StartKWalletd();
// The functions below are wrappers for calling the eponymous KWallet dbus
// methods. They take pointers to locations where the return values will be
@@ -47,90 +47,90 @@ class COMPONENT_EXPORT(OS_CRYPT) KWalletDBus {
// https://api.kde.org/4.12-api/kdelibs-apidocs/kdeui/html/classKWallet_1_1Wallet.html
// Determine if the KDE wallet is enabled.
- virtual Error IsEnabled(bool* enabled) WARN_UNUSED_RESULT;
+ [[nodiscard]] virtual Error IsEnabled(bool* enabled);
// Get the name of the wallet used to store network passwords.
- virtual Error NetworkWallet(std::string* wallet_name_ptr) WARN_UNUSED_RESULT;
+ [[nodiscard]] virtual Error NetworkWallet(std::string* wallet_name_ptr);
// Open the |wallet_name| wallet for use.
- virtual Error Open(const std::string& wallet_name,
- const std::string& app_name,
- int* handle_ptr) WARN_UNUSED_RESULT;
+ [[nodiscard]] virtual Error Open(const std::string& wallet_name,
+ const std::string& app_name,
+ int* handle_ptr);
// Determine if the current folder has they entry key.
- virtual Error HasEntry(int wallet_handle,
- const std::string& folder_name,
- const std::string& signon_realm,
- const std::string& app_name,
- bool* has_entry_ptr) WARN_UNUSED_RESULT;
+ [[nodiscard]] virtual Error HasEntry(int wallet_handle,
+ const std::string& folder_name,
+ const std::string& signon_realm,
+ const std::string& app_name,
+ bool* has_entry_ptr);
// Read the entry key from the current folder.
- virtual Error ReadEntry(int wallet_handle,
- const std::string& folder_name,
- const std::string& signon_realm,
- const std::string& app_name,
- std::vector<uint8_t>* bytes_ptr) WARN_UNUSED_RESULT;
+ [[nodiscard]] virtual Error ReadEntry(int wallet_handle,
+ const std::string& folder_name,
+ const std::string& signon_realm,
+ const std::string& app_name,
+ std::vector<uint8_t>* bytes_ptr);
// Return the list of keys of all entries in this folder.
- virtual Error EntryList(int wallet_handle,
- const std::string& folder_name,
- const std::string& app_name,
- std::vector<std::string>* entry_list_ptr)
- WARN_UNUSED_RESULT;
+ [[nodiscard]] virtual Error EntryList(
+ int wallet_handle,
+ const std::string& folder_name,
+ const std::string& app_name,
+ std::vector<std::string>* entry_list_ptr);
// Remove the entry key from the current folder.
// |*return_code_ptr| is 0 on success.
- virtual Error RemoveEntry(int wallet_handle,
- const std::string& folder_name,
- const std::string& signon_realm,
- const std::string& app_name,
- int* return_code_ptr) WARN_UNUSED_RESULT;
+ [[nodiscard]] virtual Error RemoveEntry(int wallet_handle,
+ const std::string& folder_name,
+ const std::string& signon_realm,
+ const std::string& app_name,
+ int* return_code_ptr);
// Write a binary entry to the current folder.
// |*return_code_ptr| is 0 on success.
- virtual Error WriteEntry(int wallet_handle,
- const std::string& folder_name,
- const std::string& signon_realm,
- const std::string& app_name,
- const uint8_t* data,
- size_t length,
- int* return_code_ptr) WARN_UNUSED_RESULT;
+ [[nodiscard]] virtual Error WriteEntry(int wallet_handle,
+ const std::string& folder_name,
+ const std::string& signon_realm,
+ const std::string& app_name,
+ const uint8_t* data,
+ size_t length,
+ int* return_code_ptr);
// Determine if the folder |folder_name| exists in the wallet.
- virtual Error HasFolder(int handle,
- const std::string& folder_name,
- const std::string& app_name,
- bool* has_folder_ptr) WARN_UNUSED_RESULT;
+ [[nodiscard]] virtual Error HasFolder(int handle,
+ const std::string& folder_name,
+ const std::string& app_name,
+ bool* has_folder_ptr);
// Create the folder |folder_name|.
- virtual Error CreateFolder(int handle,
- const std::string& folder_name,
- const std::string& app_name,
- bool* success_ptr) WARN_UNUSED_RESULT;
+ [[nodiscard]] virtual Error CreateFolder(int handle,
+ const std::string& folder_name,
+ const std::string& app_name,
+ bool* success_ptr);
// Write a password to the current folder.
- virtual Error WritePassword(int handle,
- const std::string& folder_name,
- const std::string& key,
- const std::string& password,
- const std::string& app_name,
- bool* write_success_ptr) WARN_UNUSED_RESULT;
+ [[nodiscard]] virtual Error WritePassword(int handle,
+ const std::string& folder_name,
+ const std::string& key,
+ const std::string& password,
+ const std::string& app_name,
+ bool* write_success_ptr);
// Read the password for |key| from |folder_name|.
// Clear |password_ptr| if no such password exists.
- virtual Error ReadPassword(int handle,
- const std::string& folder_name,
- const std::string& key,
- const std::string& app_name,
- absl::optional<std::string>* const password_ptr)
- WARN_UNUSED_RESULT;
+ [[nodiscard]] virtual Error ReadPassword(
+ int handle,
+ const std::string& folder_name,
+ const std::string& key,
+ const std::string& app_name,
+ absl::optional<std::string>* const password_ptr);
// Close the wallet. The wallet will only be closed if it is open but not in
// use (rare), or if it is forced closed.
- virtual Error Close(int handle,
- bool force,
- const std::string& app_name,
- bool* success_ptr) WARN_UNUSED_RESULT;
+ [[nodiscard]] virtual Error Close(int handle,
+ bool force,
+ const std::string& app_name,
+ bool* success_ptr);
private:
// DBus handle for communication with klauncher and kwalletd.
diff --git a/chromium/components/os_crypt/os_crypt.h b/chromium/components/os_crypt/os_crypt.h
index a8380388517..bb0f5e8e51e 100644
--- a/chromium/components/os_crypt/os_crypt.h
+++ b/chromium/components/os_crypt/os_crypt.h
@@ -12,15 +12,13 @@
#include "base/memory/ref_counted.h"
#include "base/task/single_thread_task_runner.h"
#include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
+#include "build/chromecast_buildflags.h"
-// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
-// of lacros-chrome is complete.
-#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
+#if BUILDFLAG(IS_LINUX)
class KeyStorageLinux;
-#endif // defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
+#endif // BUILDFLAG(IS_LINUX)
-#if defined(OS_WIN) || defined(OS_MAC)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
class PrefRegistrySimple;
class PrefService;
#endif
@@ -39,25 +37,21 @@ class OSCrypt {
OSCrypt(const OSCrypt&) = delete;
OSCrypt& operator=(const OSCrypt&) = delete;
-// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
-// of lacros-chrome is complete.
-#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
+#if BUILDFLAG(IS_LINUX)
// Set the configuration of OSCrypt.
+ // This method, or SetRawEncryptionKey(), must be called before using
+ // EncryptString() and DecryptString().
static COMPONENT_EXPORT(OS_CRYPT) void SetConfig(
std::unique_ptr<os_crypt::Config> config);
-#endif // defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
+#endif // BUILDFLAG(IS_LINUX)
-// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
-// of lacros-chrome is complete.
-#if defined(OS_APPLE) || defined(OS_WIN) || \
- (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS))
// On Linux returns true iff the real secret key (not hardcoded one) is
// available. On MacOS returns true if Keychain is available (for mock
// Keychain it returns true if not using locked Keychain, false if using
// locked mock Keychain). On Windows returns true if non mock encryption
- // key is available.
+ // key is available. On other platforms, returns false as OSCrypt will use
+ // a hardcoded key.
static COMPONENT_EXPORT(OS_CRYPT) bool IsEncryptionAvailable();
-#endif
// Encrypt a string16. The output (second argument) is really an array of
// bytes, but we're passing it back as a std::string.
@@ -84,7 +78,7 @@ class OSCrypt {
const std::string& ciphertext,
std::string* plaintext);
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// Registers preferences used by OSCrypt.
static COMPONENT_EXPORT(OS_CRYPT) void RegisterLocalPrefs(
PrefRegistrySimple* registry);
@@ -94,9 +88,22 @@ class OSCrypt {
// encryption or decryption. Returns |true| if os_crypt successfully
// initialized.
static COMPONENT_EXPORT(OS_CRYPT) bool Init(PrefService* local_state);
+
+ // Initialises OSCrypt using an encryption key present in the |local_state|.
+ // It is similar to the Init() method above, however, it will not create
+ // a new encryption key if it is not present in the |local_state|.
+ enum InitResult {
+ kSuccess,
+ kKeyDoesNotExist,
+ kInvalidKeyFormat,
+ kDecryptionFailed
+ };
+
+ static COMPONENT_EXPORT(OS_CRYPT) InitResult
+ InitWithExistingKey(PrefService* local_state);
#endif
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
// For unit testing purposes we instruct the Encryptor to use a mock Keychain
// on the Mac. The default is to use the real Keychain. Use OSCryptMocker,
// instead of calling this method directly.
@@ -110,19 +117,23 @@ class OSCrypt {
bool use_locked);
#endif
-#if defined(OS_WIN) || defined(OS_APPLE)
- // Get the raw encryption key to be used for all AES encryption. Returns an
- // empty string in the case password access is denied or key generation error
- // occurs. This method is thread-safe.
+ // Get the raw encryption key to be used for all AES encryption. The result
+ // can be used to call SetRawEncryptionKey() in another process. Returns an
+ // empty string in some situations, for example:
+ // - password access is denied
+ // - key generation error
+ // - if a hardcoded password is used instead of a random per-user key
+ // This method is thread-safe.
static COMPONENT_EXPORT(OS_CRYPT) std::string GetRawEncryptionKey();
// Set the raw encryption key to be used for all AES encryption.
+ // On platforms that may use a hardcoded key, |key| can be empty and OSCrypt
+ // will default to the hardcoded key.
// This method is thread-safe.
static COMPONENT_EXPORT(OS_CRYPT) void SetRawEncryptionKey(
const std::string& key);
-#endif
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// For unit testing purposes we instruct the Encryptor to use a mock Key. The
// default is to use the real Key bound to profile. Use OSCryptMocker, instead
// of calling this method directly.
@@ -137,25 +148,23 @@ class OSCrypt {
// loaded via Init() or SetRawEncryptionkey().
static COMPONENT_EXPORT(OS_CRYPT) void ResetStateForTesting();
#endif
-};
-// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
-// of lacros-chrome is complete.
-#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
-// For unit testing purposes, inject methods to be used.
-// |get_key_storage_mock| provides the desired |KeyStorage| implementation.
-// If the provider returns |nullptr|, a hardcoded password will be used.
-// |get_password_v11_mock| provides a password to derive the encryption key from
-// If one parameter is |nullptr|, the function will be not be replaced.
-// If all parameters are |nullptr|, the real implementation is restored.
-COMPONENT_EXPORT(OS_CRYPT)
-void UseMockKeyStorageForTesting(
- std::unique_ptr<KeyStorageLinux> (*get_key_storage_mock)(),
- std::string* (*get_password_v11_mock)());
-
-// Clears any caching and most lazy initialisations performed by the production
-// code. Should be used after any test which required a password.
-COMPONENT_EXPORT(OS_CRYPT) void ClearCacheForTesting();
-#endif // defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
+#if (BUILDFLAG(IS_LINUX) && !BUILDFLAG(IS_CHROMECAST))
+ // For unit testing purposes, inject methods to be used.
+ // |get_key_storage_mock| provides the desired |KeyStorage| implementation.
+ // If the provider returns |nullptr|, a hardcoded password will be used.
+ // If |get_key_storage_mock| is nullptr, restores the real implementation.
+ static COMPONENT_EXPORT(OS_CRYPT) void UseMockKeyStorageForTesting(
+ std::unique_ptr<KeyStorageLinux> (*get_key_storage_mock)());
+
+ // Clears any caching and most lazy initialisations performed by the
+ // production code. Should be used after any test which required a password.
+ static COMPONENT_EXPORT(OS_CRYPT) void ClearCacheForTesting();
+
+ // Sets the password with which the encryption key is derived, e.g. "peanuts".
+ static COMPONENT_EXPORT(OS_CRYPT) void SetEncryptionPasswordForTesting(
+ const std::string& password);
+#endif // (BUILDFLAG(IS_LINUX) && !BUILDFLAG(IS_CHROMECAST))
+};
#endif // COMPONENTS_OS_CRYPT_OS_CRYPT_H_
diff --git a/chromium/components/os_crypt/os_crypt_linux.cc b/chromium/components/os_crypt/os_crypt_linux.cc
index 2b8e3b85a2e..07da4e55f17 100644
--- a/chromium/components/os_crypt/os_crypt_linux.cc
+++ b/chromium/components/os_crypt/os_crypt_linux.cc
@@ -55,10 +55,10 @@ const char kObfuscationPrefix[][4] = {
// Everything in Cache may be leaked on shutdown.
struct Cache {
// For password_v10, null means uninitialised.
- std::unique_ptr<std::string> password_v10_cache;
+ std::unique_ptr<crypto::SymmetricKey> password_v10_cache;
// For password_v11, null means no backend.
- std::unique_ptr<std::string> password_v11_cache;
- bool is_password_v11_cached;
+ std::unique_ptr<crypto::SymmetricKey> password_v11_cache;
+ bool is_password_v11_cached = false;
// |config| is used to initialise |password_v11_cache| and then cleared.
std::unique_ptr<os_crypt::Config> config;
// Guards access to |g_cache|, making lazy initialization of individual parts
@@ -71,7 +71,7 @@ base::LazyInstance<Cache>::Leaky g_cache = LAZY_INSTANCE_INITIALIZER;
// Create the KeyStorage. Will be null if no service is found. A Config must be
// set before every call to this function.
std::unique_ptr<KeyStorageLinux> CreateKeyStorage() {
- DCHECK(g_cache.Get().config);
+ CHECK(g_cache.Get().config);
std::unique_ptr<KeyStorageLinux> key_storage =
KeyStorageLinux::CreateService(*g_cache.Get().config);
g_cache.Get().config.reset();
@@ -83,26 +83,42 @@ std::unique_ptr<KeyStorageLinux> CreateKeyStorage() {
std::unique_ptr<KeyStorageLinux> (*g_key_storage_provider)() =
&CreateKeyStorage;
+// Generates a newly allocated SymmetricKey object based on a password.
+// Ownership of the key is passed to the caller. Returns null key if a key
+// generation error occurs.
+std::unique_ptr<crypto::SymmetricKey> GenerateEncryptionKey(
+ const std::string& password) {
+ std::string salt(kSalt);
+
+ // Create an encryption key from our password and salt.
+ std::unique_ptr<crypto::SymmetricKey> encryption_key(
+ crypto::SymmetricKey::DeriveKeyFromPasswordUsingPbkdf2(
+ crypto::SymmetricKey::AES, password, salt, kEncryptionIterations,
+ kDerivedKeySizeInBits));
+ DCHECK(encryption_key);
+
+ return encryption_key;
+}
+
// Returns a cached string of "peanuts". Is thread-safe.
-std::string* GetPasswordV10() {
+crypto::SymmetricKey* GetPasswordV10() {
base::AutoLock auto_lock(g_cache.Get().lock);
if (!g_cache.Get().password_v10_cache.get()) {
- g_cache.Get().password_v10_cache = std::make_unique<std::string>("peanuts");
+ g_cache.Get().password_v10_cache = GenerateEncryptionKey("peanuts");
}
return g_cache.Get().password_v10_cache.get();
}
// Caches and returns the password from the KeyStorage or null if there is no
// service. Is thread-safe.
-std::string* GetPasswordV11() {
+crypto::SymmetricKey* GetPasswordV11() {
base::AutoLock auto_lock(g_cache.Get().lock);
if (!g_cache.Get().is_password_v11_cached) {
std::unique_ptr<KeyStorageLinux> key_storage = g_key_storage_provider();
if (key_storage) {
absl::optional<std::string> key = key_storage->GetKey();
if (key.has_value()) {
- g_cache.Get().password_v11_cache =
- std::make_unique<std::string>(std::move(*key));
+ g_cache.Get().password_v11_cache = GenerateEncryptionKey(*key);
}
}
g_cache.Get().is_password_v11_cached = true;
@@ -112,30 +128,11 @@ std::string* GetPasswordV11() {
// Pointers to functions that return a password for deriving the encryption key.
// One function for each supported password version (see Version enum).
-std::string* (*g_get_password[])() = {
- &GetPasswordV10, &GetPasswordV11,
+crypto::SymmetricKey* (*g_get_password[])() = {
+ &GetPasswordV10,
+ &GetPasswordV11,
};
-// Generates a newly allocated SymmetricKey object based on a password.
-// Ownership of the key is passed to the caller. Returns null key if a key
-// generation error occurs.
-std::unique_ptr<crypto::SymmetricKey> GetEncryptionKey(Version version) {
- std::string salt(kSalt);
-
- std::string* password = g_get_password[version]();
- if (!password)
- return nullptr;
-
- // Create an encryption key from our password and salt.
- std::unique_ptr<crypto::SymmetricKey> encryption_key(
- crypto::SymmetricKey::DeriveKeyFromPasswordUsingPbkdf2(
- crypto::SymmetricKey::AES, *password, salt, kEncryptionIterations,
- kDerivedKeySizeInBits));
- DCHECK(encryption_key);
-
- return encryption_key;
-}
-
} // namespace
// static
@@ -166,11 +163,10 @@ bool OSCrypt::EncryptString(const std::string& plaintext,
// If we are able to create a V11 key (i.e. a KeyStorage was available), then
// we'll use it. If not, we'll use V10.
Version version = Version::V11;
- std::unique_ptr<crypto::SymmetricKey> encryption_key(
- GetEncryptionKey(version));
+ crypto::SymmetricKey* encryption_key = g_get_password[version]();
if (!encryption_key) {
version = Version::V10;
- encryption_key = GetEncryptionKey(version);
+ encryption_key = g_get_password[version]();
}
if (!encryption_key)
@@ -178,7 +174,7 @@ bool OSCrypt::EncryptString(const std::string& plaintext,
std::string iv(kIVBlockSizeAES128, ' ');
crypto::Encryptor encryptor;
- if (!encryptor.Init(encryption_key.get(), crypto::Encryptor::CBC, iv))
+ if (!encryptor.Init(encryption_key, crypto::Encryptor::CBC, iv))
return false;
if (!encryptor.Encrypt(plaintext, ciphertext))
@@ -214,8 +210,7 @@ bool OSCrypt::DecryptString(const std::string& ciphertext,
return true;
}
- std::unique_ptr<crypto::SymmetricKey> encryption_key(
- GetEncryptionKey(version));
+ crypto::SymmetricKey* encryption_key(g_get_password[version]());
if (!encryption_key) {
VLOG(1) << "Decryption failed: could not get the key";
return false;
@@ -223,7 +218,7 @@ bool OSCrypt::DecryptString(const std::string& ciphertext,
std::string iv(kIVBlockSizeAES128, ' ');
crypto::Encryptor encryptor;
- if (!encryptor.Init(encryption_key.get(), crypto::Encryptor::CBC, iv))
+ if (!encryptor.Init(encryption_key, crypto::Encryptor::CBC, iv))
return false;
// Strip off the versioning prefix before decrypting.
@@ -250,37 +245,54 @@ bool OSCrypt::IsEncryptionAvailable() {
return g_get_password[Version::V11]();
}
-void ClearCacheForTesting() {
+// static
+void OSCrypt::SetRawEncryptionKey(const std::string& raw_key) {
+ base::AutoLock auto_lock(g_cache.Get().lock);
+ // Check if the v11 password is already cached. If it is, then data encrypted
+ // with the old password might not be decryptable.
+ DCHECK(!g_cache.Get().is_password_v11_cached);
+ // The config won't be used if this function is being called. Callers should
+ // choose between setting a config and setting a raw encryption key.
+ DCHECK(!g_cache.Get().config);
+ if (!raw_key.empty()) {
+ g_cache.Get().password_v11_cache =
+ crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, raw_key);
+ }
+ // Always set |is_password_v11_cached|, even if given an empty string.
+ // Note that |raw_key| can be an empty string if real V11 encryption is not
+ // available, and setting |is_password_v11_cached| causes GetPasswordV11() to
+ // correctly return nullptr in that case.
+ g_cache.Get().is_password_v11_cached = true;
+}
+
+// static
+std::string OSCrypt::GetRawEncryptionKey() {
+ crypto::SymmetricKey* key = g_get_password[Version::V11]();
+ if (!key)
+ return std::string();
+ return key->key();
+}
+
+// static
+void OSCrypt::ClearCacheForTesting() {
g_cache.Get().password_v10_cache.reset();
g_cache.Get().password_v11_cache.reset();
g_cache.Get().is_password_v11_cached = false;
g_cache.Get().config.reset();
}
-void UseMockKeyStorageForTesting(
- std::unique_ptr<KeyStorageLinux> (*get_key_storage_mock)(),
- std::string* (*get_password_v11_mock)()) {
- // Save the real implementation to restore it later.
- static bool is_get_password_saved = false;
- static std::string* (*get_password_save[base::size(g_get_password)])();
- if (!is_get_password_saved) {
- std::copy(std::begin(g_get_password), std::end(g_get_password),
- std::begin(get_password_save));
- is_get_password_saved = true;
- }
-
- if (get_key_storage_mock || get_password_v11_mock) {
- // Bypass calling KeyStorage::CreateService and caching of the key for V11
- if (get_password_v11_mock)
- g_get_password[Version::V11] = get_password_v11_mock;
- // OSCrypt will determine the encryption version by checking if a
- // |KeyStorage| instance can be created. Enable V11 by returning the mock.
- if (get_key_storage_mock)
- g_key_storage_provider = get_key_storage_mock;
- } else {
- // Restore real implementation
- std::copy(std::begin(get_password_save), std::end(get_password_save),
- std::begin(g_get_password));
+// static
+void OSCrypt::UseMockKeyStorageForTesting(
+ std::unique_ptr<KeyStorageLinux> (*get_key_storage_mock)()) {
+ if (get_key_storage_mock)
+ g_key_storage_provider = get_key_storage_mock;
+ else
g_key_storage_provider = &CreateKeyStorage;
- }
+}
+
+// static
+void OSCrypt::SetEncryptionPasswordForTesting(const std::string& password) {
+ ClearCacheForTesting(); // IN-TEST
+ g_cache.Get().password_v11_cache = GenerateEncryptionKey(password);
+ g_cache.Get().is_password_v11_cached = true;
}
diff --git a/chromium/components/os_crypt/os_crypt_linux_unittest.cc b/chromium/components/os_crypt/os_crypt_linux_unittest.cc
index aa3dba4627e..b75c9f726b3 100644
--- a/chromium/components/os_crypt/os_crypt_linux_unittest.cc
+++ b/chromium/components/os_crypt/os_crypt_linux_unittest.cc
@@ -17,40 +17,27 @@ std::unique_ptr<KeyStorageLinux> GetNullKeyStorage() {
class OSCryptLinuxTest : public testing::Test {
public:
- OSCryptLinuxTest() : key_("something") { key_ptr_ = &key_; }
+ OSCryptLinuxTest() = default;
OSCryptLinuxTest(const OSCryptLinuxTest&) = delete;
OSCryptLinuxTest& operator=(const OSCryptLinuxTest&) = delete;
- ~OSCryptLinuxTest() override { key_ptr_ = nullptr; }
+ ~OSCryptLinuxTest() override = default;
void SetUp() override {
OSCryptMockerLinux::SetUp();
- UseMockKeyStorageForTesting(nullptr, OSCryptLinuxTest::GetKey);
+ OSCrypt::SetEncryptionPasswordForTesting("something");
}
void TearDown() override { OSCryptMockerLinux::TearDown(); }
-
- protected:
- void SetEncryptionKey(const std::string& key) { key_ = key; }
-
- // Get the key of the currently running test.
- static std::string* GetKey() { return key_ptr_; }
-
- private:
- std::string key_;
- // Points to the |key_| of the currently running test.
- static std::string* key_ptr_;
};
-std::string* OSCryptLinuxTest::key_ptr_;
-
TEST_F(OSCryptLinuxTest, VerifyV0) {
const std::string originaltext = "hello";
std::string ciphertext;
std::string decipheredtext;
- SetEncryptionKey(std::string());
+ OSCrypt::SetEncryptionPasswordForTesting(std::string());
ciphertext = originaltext; // No encryption
ASSERT_TRUE(OSCrypt::DecryptString(ciphertext, &decipheredtext));
ASSERT_EQ(originaltext, decipheredtext);
@@ -61,9 +48,9 @@ TEST_F(OSCryptLinuxTest, VerifyV10) {
std::string ciphertext;
std::string decipheredtext;
- SetEncryptionKey("peanuts");
+ OSCrypt::SetEncryptionPasswordForTesting("peanuts");
ASSERT_TRUE(OSCrypt::EncryptString(originaltext, &ciphertext));
- SetEncryptionKey("not_peanuts");
+ OSCrypt::SetEncryptionPasswordForTesting("not_peanuts");
ciphertext = ciphertext.substr(3).insert(0, "v10");
ASSERT_TRUE(OSCrypt::DecryptString(ciphertext, &decipheredtext));
ASSERT_EQ(originaltext, decipheredtext);
@@ -74,7 +61,7 @@ TEST_F(OSCryptLinuxTest, VerifyV11) {
std::string ciphertext;
std::string decipheredtext;
- SetEncryptionKey(std::string());
+ OSCrypt::SetEncryptionPasswordForTesting(std::string());
ASSERT_TRUE(OSCrypt::EncryptString(originaltext, &ciphertext));
ASSERT_EQ(ciphertext.substr(0, 3), "v11");
ASSERT_TRUE(OSCrypt::DecryptString(ciphertext, &decipheredtext));
@@ -83,11 +70,31 @@ TEST_F(OSCryptLinuxTest, VerifyV11) {
TEST_F(OSCryptLinuxTest, IsEncryptionAvailable) {
EXPECT_TRUE(OSCrypt::IsEncryptionAvailable());
- // Restore default GetKeyStorage and GetPassword functions.
- UseMockKeyStorageForTesting(nullptr, nullptr);
- // Mock only GetKeyStorage function.
- UseMockKeyStorageForTesting(GetNullKeyStorage, nullptr);
+ OSCrypt::ClearCacheForTesting();
+ // Mock the GetKeyStorage function.
+ OSCrypt::UseMockKeyStorageForTesting(GetNullKeyStorage);
EXPECT_FALSE(OSCrypt::IsEncryptionAvailable());
}
+TEST_F(OSCryptLinuxTest, SetRawEncryptionKey) {
+ const std::string originaltext = "hello";
+ std::string ciphertext;
+ std::string decipheredtext;
+
+ // Encrypt with not_peanuts and save the raw encryption key.
+ OSCrypt::SetEncryptionPasswordForTesting("not_peanuts");
+ ASSERT_TRUE(OSCrypt::EncryptString(originaltext, &ciphertext));
+ ASSERT_EQ(ciphertext.substr(0, 3), "v11");
+ std::string raw_key = OSCrypt::GetRawEncryptionKey();
+ ASSERT_FALSE(raw_key.empty());
+
+ // Clear the cached encryption key.
+ OSCrypt::ClearCacheForTesting();
+
+ // Set the raw encryption key and make sure decryption works.
+ OSCrypt::SetRawEncryptionKey(raw_key);
+ ASSERT_TRUE(OSCrypt::DecryptString(ciphertext, &decipheredtext));
+ ASSERT_EQ(originaltext, decipheredtext);
+}
+
} // namespace
diff --git a/chromium/components/os_crypt/os_crypt_mocker.cc b/chromium/components/os_crypt/os_crypt_mocker.cc
index 85af8f518e9..ca47d4c063a 100644
--- a/chromium/components/os_crypt/os_crypt_mocker.cc
+++ b/chromium/components/os_crypt/os_crypt_mocker.cc
@@ -4,6 +4,7 @@
#include "components/os_crypt/os_crypt_mocker.h"
+#include "build/build_config.h"
#include "components/os_crypt/os_crypt.h"
#if defined(USE_LIBSECRET) || defined(USE_KEYRING) || defined(USE_KWALLET)
@@ -12,23 +13,23 @@
// static
void OSCryptMocker::SetUp() {
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
OSCrypt::UseMockKeychainForTesting(true);
#elif defined(USE_LIBSECRET) || defined(USE_KEYRING) || defined(USE_KWALLET)
OSCryptMockerLinux::SetUp();
-#elif defined(OS_WIN)
+#elif BUILDFLAG(IS_WIN)
OSCrypt::UseMockKeyForTesting(true);
#endif
}
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
// static
void OSCryptMocker::SetBackendLocked(bool locked) {
OSCrypt::UseLockedMockKeychainForTesting(locked);
}
#endif
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// static
void OSCryptMocker::SetLegacyEncryption(bool legacy) {
OSCrypt::SetLegacyEncryptionForTesting(legacy);
@@ -42,11 +43,11 @@ void OSCryptMocker::ResetState() {
// static
void OSCryptMocker::TearDown() {
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
OSCrypt::UseMockKeychainForTesting(false);
#elif defined(USE_LIBSECRET) || defined(USE_KEYRING) || defined(USE_KWALLET)
OSCryptMockerLinux::TearDown();
-#elif defined(OS_WIN)
+#elif BUILDFLAG(IS_WIN)
OSCrypt::UseMockKeyForTesting(false);
#endif
}
diff --git a/chromium/components/os_crypt/os_crypt_mocker.h b/chromium/components/os_crypt/os_crypt_mocker.h
index 3de332d79d0..16e4e14837e 100644
--- a/chromium/components/os_crypt/os_crypt_mocker.h
+++ b/chromium/components/os_crypt/os_crypt_mocker.h
@@ -17,12 +17,12 @@ class OSCryptMocker {
// Inject mocking into OSCrypt.
static void SetUp();
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
// Pretend that backend for storing keys is unavailable.
static void SetBackendLocked(bool locked);
#endif
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// Store data using the older DPAPI interface rather than session key.
static void SetLegacyEncryption(bool legacy);
diff --git a/chromium/components/os_crypt/os_crypt_mocker_linux.cc b/chromium/components/os_crypt/os_crypt_mocker_linux.cc
index e40c99a7771..01ab41d7031 100644
--- a/chromium/components/os_crypt/os_crypt_mocker_linux.cc
+++ b/chromium/components/os_crypt/os_crypt_mocker_linux.cc
@@ -30,15 +30,13 @@ std::string* OSCryptMockerLinux::GetKeyPtr() {
// static
void OSCryptMockerLinux::SetUp() {
- UseMockKeyStorageForTesting(
- &CreateNewMock, nullptr /* get the key from the provider above */);
- OSCrypt::SetConfig(std::make_unique<os_crypt::Config>());
+ OSCrypt::UseMockKeyStorageForTesting(&CreateNewMock);
}
// static
void OSCryptMockerLinux::TearDown() {
- UseMockKeyStorageForTesting(nullptr, nullptr);
- ClearCacheForTesting();
+ OSCrypt::UseMockKeyStorageForTesting(nullptr);
+ OSCrypt::ClearCacheForTesting();
}
bool OSCryptMockerLinux::Init() {
diff --git a/chromium/components/os_crypt/os_crypt_posix.cc b/chromium/components/os_crypt/os_crypt_posix.cc
index d4ec897c6d1..76175a98a1b 100644
--- a/chromium/components/os_crypt/os_crypt_posix.cc
+++ b/chromium/components/os_crypt/os_crypt_posix.cc
@@ -140,3 +140,18 @@ bool OSCrypt::DecryptString(const std::string& ciphertext,
return true;
}
+
+// static
+bool OSCrypt::IsEncryptionAvailable() {
+ return false;
+}
+
+// static
+void OSCrypt::SetRawEncryptionKey(const std::string& raw_key) {
+ DCHECK(raw_key.empty());
+}
+
+// static
+std::string OSCrypt::GetRawEncryptionKey() {
+ return "";
+}
diff --git a/chromium/components/os_crypt/os_crypt_switches.cc b/chromium/components/os_crypt/os_crypt_switches.cc
index 4652238696d..32df6390bfc 100644
--- a/chromium/components/os_crypt/os_crypt_switches.cc
+++ b/chromium/components/os_crypt/os_crypt_switches.cc
@@ -8,11 +8,11 @@
namespace os_crypt {
namespace switches {
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
const char kUseMockKeychain[] = "use-mock-keychain";
-#endif // OS_APPLE
+#endif // BUILDFLAG(IS_APPLE)
} // namespace switches
} // namespace os_crypt
diff --git a/chromium/components/os_crypt/os_crypt_switches.h b/chromium/components/os_crypt/os_crypt_switches.h
index 2e046c2fb6a..fe4c2cebe42 100644
--- a/chromium/components/os_crypt/os_crypt_switches.h
+++ b/chromium/components/os_crypt/os_crypt_switches.h
@@ -13,13 +13,13 @@
namespace os_crypt {
namespace switches {
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
// Uses mock keychain for testing purposes, which prevents blocking dialogs
// from causing timeouts.
COMPONENT_EXPORT(OS_CRYPT) extern const char kUseMockKeychain[];
-#endif // OS_APPLE
+#endif // BUILDFLAG(IS_APPLE)
} // namespace switches
} // namespace os_crypt
diff --git a/chromium/components/os_crypt/os_crypt_unittest.cc b/chromium/components/os_crypt/os_crypt_unittest.cc
index 0be9c436daa..b71e5f43c54 100644
--- a/chromium/components/os_crypt/os_crypt_unittest.cc
+++ b/chromium/components/os_crypt/os_crypt_unittest.cc
@@ -20,11 +20,11 @@
// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
// of lacros-chrome is complete.
-#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
#include "components/os_crypt/os_crypt_mocker_linux.h"
#endif
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include "components/prefs/testing_pref_service.h"
#include "crypto/random.h"
#endif
@@ -165,7 +165,7 @@ class OSCryptConcurrencyTest : public testing::Test {
};
// Flaky on Win 7 (dbg) and win-asan, see https://crbug.com/1066699
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#define MAYBE_ConcurrentInitialization DISABLED_ConcurrentInitialization
#else
#define MAYBE_ConcurrentInitialization ConcurrentInitialization
@@ -198,7 +198,7 @@ TEST_F(OSCryptConcurrencyTest, MAYBE_ConcurrentInitialization) {
}
}
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
class OSCryptTestWin : public testing::Test {
public:
@@ -307,6 +307,6 @@ TEST_F(OSCryptTestWin, PrefsKeyTest) {
EXPECT_EQ(plaintext, decrypted);
}
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
} // namespace
diff --git a/chromium/components/os_crypt/os_crypt_win.cc b/chromium/components/os_crypt/os_crypt_win.cc
index 51433a89264..1a4042deee9 100644
--- a/chromium/components/os_crypt/os_crypt_win.cc
+++ b/chromium/components/os_crypt/os_crypt_win.cc
@@ -187,42 +187,27 @@ void OSCrypt::RegisterLocalPrefs(PrefRegistrySimple* registry) {
// static
bool OSCrypt::Init(PrefService* local_state) {
- DCHECK(GetEncryptionKeyFactory().empty()) << "Key already exists.";
- // Try and pull the key from local state.
- if (local_state->HasPrefPath(kOsCryptEncryptedKeyPrefName)) {
- std::string base64_encrypted_key =
- local_state->GetString(kOsCryptEncryptedKeyPrefName);
- std::string encrypted_key_with_header;
-
- base::Base64Decode(base64_encrypted_key, &encrypted_key_with_header);
-
- if (!base::StartsWith(encrypted_key_with_header, kDPAPIKeyPrefix,
- base::CompareCase::SENSITIVE)) {
- NOTREACHED() << "Invalid key format.";
- return false;
- }
- std::string encrypted_key =
- encrypted_key_with_header.substr(sizeof(kDPAPIKeyPrefix) - 1);
- std::string key;
- // This DPAPI decryption can fail if the user's password has been reset
- // by an Administrator.
- if (DecryptStringWithDPAPI(encrypted_key, &key)) {
- GetEncryptionKeyFactory().assign(key);
+ // Try to pull the key from the local state.
+ switch (InitWithExistingKey(local_state)) {
+ case kSuccess:
return true;
- }
- base::UmaHistogramSparse("OSCrypt.Win.KeyDecryptionError",
- ::GetLastError());
+ case kKeyDoesNotExist:
+ break;
+ case kInvalidKeyFormat:
+ return false;
+ case kDecryptionFailed:
+ break;
}
// If there is no key in the local state, or if DPAPI decryption fails,
// generate a new key.
std::string key;
-
crypto::RandBytes(base::WriteInto(&key, kKeyLength + 1), kKeyLength);
std::string encrypted_key;
if (!EncryptStringWithDPAPI(key, &encrypted_key))
return false;
+
// Add header indicating this key is encrypted with DPAPI.
encrypted_key.insert(0, kDPAPIKeyPrefix);
std::string base64_key;
@@ -233,6 +218,40 @@ bool OSCrypt::Init(PrefService* local_state) {
}
// static
+OSCrypt::InitResult OSCrypt::InitWithExistingKey(PrefService* local_state) {
+ DCHECK(GetEncryptionKeyFactory().empty()) << "Key already exists.";
+ // Try and pull the key from the local state.
+ if (!local_state->HasPrefPath(kOsCryptEncryptedKeyPrefName))
+ return kKeyDoesNotExist;
+
+ std::string base64_encrypted_key =
+ local_state->GetString(kOsCryptEncryptedKeyPrefName);
+ std::string encrypted_key_with_header;
+
+ base::Base64Decode(base64_encrypted_key, &encrypted_key_with_header);
+
+ if (!base::StartsWith(encrypted_key_with_header, kDPAPIKeyPrefix,
+ base::CompareCase::SENSITIVE)) {
+ NOTREACHED() << "Invalid key format.";
+ return kInvalidKeyFormat;
+ }
+
+ std::string encrypted_key =
+ encrypted_key_with_header.substr(sizeof(kDPAPIKeyPrefix) - 1);
+ std::string key;
+ // This DPAPI decryption can fail if the user's password has been reset
+ // by an Administrator.
+ if (!DecryptStringWithDPAPI(encrypted_key, &key)) {
+ base::UmaHistogramSparse("OSCrypt.Win.KeyDecryptionError",
+ ::GetLastError());
+ return kDecryptionFailed;
+ }
+
+ GetEncryptionKeyFactory().assign(key);
+ return kSuccess;
+}
+
+// static
void OSCrypt::SetRawEncryptionKey(const std::string& raw_key) {
DCHECK(!g_use_mock_key) << "Mock key in use.";
DCHECK(!raw_key.empty()) << "Bad key.";
diff --git a/chromium/components/ownership/BUILD.gn b/chromium/components/ownership/BUILD.gn
index 3c23b17948d..1c2d554e85f 100644
--- a/chromium/components/ownership/BUILD.gn
+++ b/chromium/components/ownership/BUILD.gn
@@ -3,8 +3,8 @@
# found in the LICENSE file.
import("//build/config/chromeos/ui_mode.gni")
-import("//build/config/crypto.gni")
import("//build/config/features.gni")
+import("//crypto/features.gni")
if (is_chromeos_ash) {
component("ownership") {
diff --git a/chromium/components/page_info/DEPS b/chromium/components/page_info/DEPS
index bf0ac7577f0..82c6f6f1fcb 100644
--- a/chromium/components/page_info/DEPS
+++ b/chromium/components/page_info/DEPS
@@ -2,6 +2,7 @@ include_rules = [
"+components/browser_ui",
"+components/browsing_data",
"+components/content_settings",
+ "+components/history/core/browser",
"+components/keyed_service/core",
"+components/optimization_guide/core",
"+components/optimization_guide/proto",
diff --git a/chromium/components/page_info/android/BUILD.gn b/chromium/components/page_info/android/BUILD.gn
index a2efa5d463d..c5e0d7fdfd8 100644
--- a/chromium/components/page_info/android/BUILD.gn
+++ b/chromium/components/page_info/android/BUILD.gn
@@ -33,16 +33,20 @@ static_library("android") {
android_resources("java_resources") {
sources = [
- "java/res/drawable/page_info_bg.xml",
+ "java/res/drawable-v23/page_info_bg.xml",
+ "java/res/drawable-v31/page_info_bg.xml",
+ "java/res/layout/button_preference_text_button.xml",
"java/res/layout/connection_info.xml",
"java/res/layout/page_info.xml",
"java/res/layout/page_info_container.xml",
"java/res/layout/page_info_row.xml",
"java/res/layout/page_info_summary.xml",
"java/res/layout/page_zoom_view.xml",
+ "java/res/values-night/dimens.xml",
"java/res/values/colors.xml",
"java/res/values/dimens.xml",
"java/res/values/ids.xml",
+ "java/res/xml/page_info_ad_personalization_preference.xml",
"java/res/xml/page_info_cookie_preference.xml",
]
deps = [
@@ -59,6 +63,8 @@ android_library("java") {
"java/src/org/chromium/components/page_info/CertificateViewer.java",
"java/src/org/chromium/components/page_info/ConnectionInfoView.java",
"java/src/org/chromium/components/page_info/ElidedUrlTextView.java",
+ "java/src/org/chromium/components/page_info/PageInfoAdPersonalizationController.java",
+ "java/src/org/chromium/components/page_info/PageInfoAdPersonalizationPreference.java",
"java/src/org/chromium/components/page_info/PageInfoConnectionController.java",
"java/src/org/chromium/components/page_info/PageInfoContainer.java",
"java/src/org/chromium/components/page_info/PageInfoController.java",
@@ -73,6 +79,7 @@ android_library("java") {
"java/src/org/chromium/components/page_info/PageInfoPageZoomController.java",
"java/src/org/chromium/components/page_info/PageInfoPageZoomView.java",
"java/src/org/chromium/components/page_info/PageInfoPermissionsController.java",
+ "java/src/org/chromium/components/page_info/PageInfoPreferenceSubpageController.java",
"java/src/org/chromium/components/page_info/PageInfoRowView.java",
"java/src/org/chromium/components/page_info/PageInfoSubpageController.java",
"java/src/org/chromium/components/page_info/PageInfoView.java",
@@ -87,7 +94,7 @@ android_library("java") {
"//base:base_java",
"//components/browser_ui/settings/android:java",
"//components/browser_ui/site_settings/android:java",
- "//components/browser_ui/styles/android:java_resources",
+ "//components/browser_ui/styles/android:java",
"//components/browser_ui/widget/android:java",
"//components/content_settings/android:content_settings_enums_java",
"//components/content_settings/android:java",
diff --git a/chromium/components/page_info/android/page_info_controller_android.cc b/chromium/components/page_info/android/page_info_controller_android.cc
index ca22eb4c28a..5ead1151b6d 100644
--- a/chromium/components/page_info/android/page_info_controller_android.cc
+++ b/chromium/components/page_info/android/page_info_controller_android.cc
@@ -38,6 +38,12 @@ static jlong JNI_PageInfoController_Init(
content::WebContents* web_contents =
content::WebContents::FromJavaWebContents(java_web_contents);
+ // Important to use GetVisibleEntry to match what's showing in the omnibox.
+ content::NavigationEntry* nav_entry =
+ web_contents->GetController().GetVisibleEntry();
+ if (!nav_entry || nav_entry->IsInitialEntry())
+ return 0;
+
return reinterpret_cast<intptr_t>(
new PageInfoControllerAndroid(env, obj, web_contents));
}
@@ -46,11 +52,8 @@ PageInfoControllerAndroid::PageInfoControllerAndroid(
JNIEnv* env,
jobject java_page_info_pop,
content::WebContents* web_contents) {
- // Important to use GetVisibleEntry to match what's showing in the omnibox.
content::NavigationEntry* nav_entry =
web_contents->GetController().GetVisibleEntry();
- if (!nav_entry || nav_entry->IsInitialEntry())
- return;
url_ = nav_entry->GetURL();
web_contents_ = web_contents;
diff --git a/chromium/components/page_info/core/BUILD.gn b/chromium/components/page_info/core/BUILD.gn
index f74b701453e..a1c64c0cbeb 100644
--- a/chromium/components/page_info/core/BUILD.gn
+++ b/chromium/components/page_info/core/BUILD.gn
@@ -30,15 +30,20 @@ static_library("core") {
"about_this_site_validation.h",
"features.cc",
"features.h",
+ "page_info_history_data_source.cc",
+ "page_info_history_data_source.h",
]
deps = [
"//base",
+ "//components/history/core/browser",
"//components/keyed_service/core",
"//components/optimization_guide/core",
"//components/page_info/core:proto",
+ "//components/strings:components_strings_grit",
"//services/metrics/public/cpp:metrics_cpp",
"//services/metrics/public/cpp:ukm_builders",
+ "//ui/base:base",
]
}
@@ -47,6 +52,7 @@ source_set("unit_tests") {
sources = [
"about_this_site_service_unittest.cc",
"about_this_site_validation_unittest.cc",
+ "page_info_history_data_source_unittest.cc",
]
deps = [
@@ -54,6 +60,7 @@ source_set("unit_tests") {
":proto",
"//base",
"//base/test:test_support",
+ "//components/history/core/browser",
"//components/optimization_guide/proto:optimization_guide_proto",
"//services/metrics/public/cpp:metrics_cpp",
"//testing/gtest",
diff --git a/chromium/components/page_info/core/about_this_site_service.cc b/chromium/components/page_info/core/about_this_site_service.cc
index 36c3c5002a1..2e4f521994d 100644
--- a/chromium/components/page_info/core/about_this_site_service.cc
+++ b/chromium/components/page_info/core/about_this_site_service.cc
@@ -43,8 +43,6 @@ absl::optional<proto::SiteInfo> AboutThisSiteService::GetAboutThisSiteInfo(
return about_this_site_metadata->site_info();
}
- // TODO(crbug.com/1250653): Remove returning fake data after server-side is
- // ready.
if (kShowSampleContent.Get()) {
page_info::proto::SiteInfo site_info;
if (url == GURL("https://example.com")) {
diff --git a/chromium/components/page_info/core/features.cc b/chromium/components/page_info/core/features.cc
index 82b3a34f34f..b9f11b7d9dc 100644
--- a/chromium/components/page_info/core/features.cc
+++ b/chromium/components/page_info/core/features.cc
@@ -6,20 +6,29 @@
#include "base/feature_list.h"
#include "base/metrics/field_trial_params.h"
+#include "build/build_config.h"
namespace page_info {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
const base::Feature kPageInfoHistory{"PageInfoHistory",
base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kPageInfoStoreInfo{"PageInfoStoreInfo",
base::FEATURE_DISABLED_BY_DEFAULT};
+
+const base::Feature kPageInfoDiscoverability{"PageInfoDiscoverability",
+ base::FEATURE_ENABLED_BY_DEFAULT};
#endif
const base::Feature kPageInfoAboutThisSite{"PageInfoAboutThisSite",
base::FEATURE_DISABLED_BY_DEFAULT};
const base::FeatureParam<bool> kShowSampleContent{&kPageInfoAboutThisSite,
- "ShowSampleContent", true};
+ "ShowSampleContent", false};
+
+#if !BUILDFLAG(IS_ANDROID)
+const base::Feature kPageInfoHistoryDesktop{"PageInfoHistoryDesktop",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+#endif
} // namespace page_info
diff --git a/chromium/components/page_info/core/features.h b/chromium/components/page_info/core/features.h
index 80bddfb02c4..c5f58cea15e 100644
--- a/chromium/components/page_info/core/features.h
+++ b/chromium/components/page_info/core/features.h
@@ -14,11 +14,15 @@ struct Feature;
namespace page_info {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Enables the history sub page for Page Info.
extern const base::Feature kPageInfoHistory;
// Enables the store info row for Page Info.
extern const base::Feature kPageInfoStoreInfo;
+
+// Used to experiment with different permission timeouts. The underlying feature
+// itself is already launched.
+extern const base::Feature kPageInfoDiscoverability;
#endif
// Enables the "About this site" section in Page Info.
@@ -27,6 +31,11 @@ extern const base::Feature kPageInfoAboutThisSite;
// Whether we show hard-coded content for some sites like https://example.com.
extern const base::FeatureParam<bool> kShowSampleContent;
+#if !BUILDFLAG(IS_ANDROID)
+// Enables the history section for Page Info on desktop.
+extern const base::Feature kPageInfoHistoryDesktop;
+#endif
+
} // namespace page_info
#endif // COMPONENTS_PAGE_INFO_CORE_FEATURES_H_
diff --git a/chromium/components/page_info/core/page_info_history_data_source.cc b/chromium/components/page_info/core/page_info_history_data_source.cc
new file mode 100644
index 00000000000..c0de2dd25f7
--- /dev/null
+++ b/chromium/components/page_info/core/page_info_history_data_source.cc
@@ -0,0 +1,100 @@
+// Copyright 2021 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.
+
+#include "components/page_info/core/page_info_history_data_source.h"
+
+#include "base/callback.h"
+#include "base/callback_helpers.h"
+#include "base/i18n/number_formatting.h"
+#include "base/i18n/time_formatting.h"
+#include "base/strings/string_util.h"
+#include "components/history/core/browser/history_service.h"
+#include "components/strings/grit/components_strings.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace page_info {
+
+PageInfoHistoryDataSource::PageInfoHistoryDataSource(
+ history::HistoryService* history_service,
+ const GURL& site_url)
+ : history_service_(history_service), site_url_(site_url) {}
+
+PageInfoHistoryDataSource::~PageInfoHistoryDataSource() = default;
+
+// static
+std::u16string PageInfoHistoryDataSource::FormatLastVisitedTimestamp(
+ base::Time last_visit,
+ base::Time now) {
+ if (last_visit.is_null())
+ return std::u16string();
+
+ constexpr base::TimeDelta kDay = base::Days(1);
+
+ const base::Time midnight_today = now.LocalMidnight();
+ const base::Time mightnight_last_visited = last_visit.LocalMidnight();
+ base::TimeDelta delta = midnight_today - mightnight_last_visited;
+ // Adjust delta for DST, add or remove one hour as need to make the delta
+ // divisible by 24 (in hours).
+ if (delta % kDay != base::Milliseconds(0)) {
+ DCHECK(delta % kDay == -base::Hours(23) || delta % kDay == base::Hours(1));
+ delta += delta % kDay == base::Hours(1) ? -base::Hours(1) : base::Hours(1);
+ }
+
+ if (delta == base::Milliseconds(0))
+ return l10n_util::GetStringUTF16(IDS_PAGE_INFO_HISTORY_LAST_VISIT_TODAY);
+
+ if (delta == kDay)
+ return l10n_util::GetStringUTF16(
+ IDS_PAGE_INFO_HISTORY_LAST_VISIT_YESTERDAY);
+
+ if (delta > kDay && delta <= kDay * 7)
+ return l10n_util::GetStringFUTF16Int(IDS_PAGE_INFO_HISTORY_LAST_VISIT_DAYS,
+ delta.InDays());
+
+ return l10n_util::GetStringFUTF16(IDS_PAGE_INFO_HISTORY_LAST_VISIT_DATE,
+ base::TimeFormatShortDate(last_visit));
+}
+
+void PageInfoHistoryDataSource::GetLastVisitedTimestamp(
+ base::OnceCallback<void(base::Time)> callback) {
+ // TODO(crbug.com/1275042): Use the data source in Android implementation.
+ base::Time now = base::Time::Now();
+ history_service_->GetLastVisitToHost(
+ site_url_.host(), base::Time() /* before_time */, now /* end_time */,
+ base::BindOnce(&PageInfoHistoryDataSource::
+ OnLastVisitBeforeRecentNavigationsComplete,
+ weak_factory_.GetWeakPtr(), site_url_.host(), now,
+ std::move(callback)),
+ &query_task_tracker_);
+}
+
+void PageInfoHistoryDataSource::OnLastVisitBeforeRecentNavigationsComplete(
+ const std::string& host_name,
+ base::Time query_start_time,
+ base::OnceCallback<void(base::Time)> callback,
+ history::HistoryLastVisitResult result) {
+ if (!result.success || result.last_visit.is_null()) {
+ std::move(callback).Run(base::Time());
+ return;
+ }
+
+ base::Time end_time =
+ result.last_visit < (query_start_time - base::Minutes(1))
+ ? result.last_visit
+ : query_start_time - base::Minutes(1);
+ history_service_->GetLastVisitToHost(
+ host_name, base::Time() /* before_time */, end_time /* end_time */,
+ base::BindOnce(&PageInfoHistoryDataSource::
+ OnLastVisitBeforeRecentNavigationsComplete2,
+ weak_factory_.GetWeakPtr(), std::move(callback)),
+ &query_task_tracker_);
+}
+
+void PageInfoHistoryDataSource::OnLastVisitBeforeRecentNavigationsComplete2(
+ base::OnceCallback<void(base::Time)> callback,
+ history::HistoryLastVisitResult result) {
+ std::move(callback).Run(result.last_visit);
+}
+
+} // namespace page_info
diff --git a/chromium/components/page_info/core/page_info_history_data_source.h b/chromium/components/page_info/core/page_info_history_data_source.h
new file mode 100644
index 00000000000..9f31765f19e
--- /dev/null
+++ b/chromium/components/page_info/core/page_info_history_data_source.h
@@ -0,0 +1,69 @@
+// Copyright 2021 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.
+
+#ifndef COMPONENTS_PAGE_INFO_CORE_PAGE_INFO_HISTORY_DATA_SOURCE_H_
+#define COMPONENTS_PAGE_INFO_CORE_PAGE_INFO_HISTORY_DATA_SOURCE_H_
+
+#include <string>
+
+#include "base/callback_forward.h"
+#include "base/task/cancelable_task_tracker.h"
+#include "base/time/time.h"
+#include "components/history/core/browser/history_types.h"
+
+namespace history {
+class HistoryService;
+} // namespace history
+
+namespace page_info {
+
+class PageInfoHistoryDataSource {
+ public:
+ explicit PageInfoHistoryDataSource(history::HistoryService* history_service,
+ const GURL& site_url);
+ ~PageInfoHistoryDataSource();
+
+ // Returns `last_visit` timestamp formatted as "Last visited: `last_visit`"
+ // string. If `last_visit` was today or yersterday, 'today' or 'yesterday'
+ // will be used. If the visit was this week, 'x days ago' will be used.
+ // Otherwise, the short date representation will be used.
+ static std::u16string FormatLastVisitedTimestamp(
+ base::Time last_visit,
+ base::Time now = base::Time::Now());
+
+ // Gets a version of the last time any webpage on the `site_url` host was
+ // visited, formatted as a string, by using the min("last navigation time", x
+ // minutes ago) as the upper bound of the GetLastVisitToHost query. This is
+ // done in order to provide the user with a more useful sneak peak into their
+ // navigation history, by excluding the site(s) they were just on.
+ void GetLastVisitedTimestamp(base::OnceCallback<void(base::Time)> callback);
+
+ private:
+ // Callback from the history system when the last visit query has completed.
+ // May need to do a second query based on the results.
+ void OnLastVisitBeforeRecentNavigationsComplete(
+ const std::string& host_name,
+ base::Time query_start_time,
+ base::OnceCallback<void(base::Time)> callback,
+ history::HistoryLastVisitResult result);
+
+ // Callback from the history system when the last visit query has completed
+ // the second time.
+ void OnLastVisitBeforeRecentNavigationsComplete2(
+ base::OnceCallback<void(base::Time)> callback,
+ history::HistoryLastVisitResult result);
+
+ raw_ptr<history::HistoryService> history_service_ = nullptr;
+
+ // Tracker for search requests to the history service.
+ base::CancelableTaskTracker query_task_tracker_;
+
+ GURL site_url_;
+
+ base::WeakPtrFactory<PageInfoHistoryDataSource> weak_factory_{this};
+};
+
+} // namespace page_info
+
+#endif // COMPONENTS_PAGE_INFO_CORE_PAGE_INFO_HISTORY_DATA_SOURCE_H_
diff --git a/chromium/components/page_info/core/page_info_history_data_source_unittest.cc b/chromium/components/page_info/core/page_info_history_data_source_unittest.cc
new file mode 100644
index 00000000000..46a44ae4035
--- /dev/null
+++ b/chromium/components/page_info/core/page_info_history_data_source_unittest.cc
@@ -0,0 +1,204 @@
+// Copyright 2022 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.
+
+#include "components/page_info/core/page_info_history_data_source.h"
+
+#include "base/callback.h"
+#include "base/callback_helpers.h"
+#include "base/i18n/time_formatting.h"
+#include "components/history/core/browser/history_service.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace history {
+
+class MockHistoryService : public HistoryService {
+ public:
+ MockHistoryService() = default;
+
+ MOCK_METHOD(base::CancelableTaskTracker::TaskId,
+ GetLastVisitToHost,
+ (const std::string& host,
+ base::Time begin_time,
+ base::Time end_time,
+ GetLastVisitCallback callback,
+ base::CancelableTaskTracker* tracker),
+ (override));
+};
+
+} // namespace history
+
+namespace page_info {
+
+using testing::_;
+using testing::Invoke;
+
+base::Time kBase = base::Time::FromTimeT(1000);
+base::Time kLastVisit = base::Time::FromTimeT(500);
+
+base::CancelableTaskTracker::TaskId ReturnVisitedNever(
+ const std::string& host,
+ base::Time begin_time,
+ base::Time end_time,
+ history::HistoryService::GetLastVisitCallback callback,
+ base::CancelableTaskTracker* tracker) {
+ history::HistoryLastVisitResult result;
+ result.success = true;
+ result.last_visit = base::Time();
+ std::move(callback).Run(result);
+ return 0;
+}
+
+base::CancelableTaskTracker::TaskId ReturnVisitedBase(
+ const std::string& host,
+ base::Time begin_time,
+ base::Time end_time,
+ history::HistoryService::GetLastVisitCallback callback,
+ base::CancelableTaskTracker* tracker) {
+ history::HistoryLastVisitResult result;
+ result.success = true;
+ result.last_visit = kBase;
+ std::move(callback).Run(result);
+ return 0;
+}
+
+base::CancelableTaskTracker::TaskId ReturnLastVisited(
+ const std::string& host,
+ base::Time begin_time,
+ base::Time end_time,
+ history::HistoryService::GetLastVisitCallback callback,
+ base::CancelableTaskTracker* tracker) {
+ history::HistoryLastVisitResult result;
+ result.success = true;
+ result.last_visit = kLastVisit;
+ std::move(callback).Run(result);
+ return 0;
+}
+
+void CheckFormattedStringsForBaseTime(base::Time now) {
+ // Tests all possible strings with minimal, middle and maximum values of the
+ // range.
+ base::Time midnight_today = now.LocalMidnight();
+
+ base::Time today = midnight_today + base::Hours(2);
+ base::Time today_min = midnight_today;
+ base::Time today_max =
+ (midnight_today + base::Days(1)).LocalMidnight() - base::Seconds(1);
+
+ base::Time yesterday = midnight_today - base::Days(1) + base::Hours(2);
+ base::Time yesterday_min = midnight_today - base::Seconds(1);
+ base::Time yesterday_max = midnight_today - base::Days(1);
+
+ base::Time two_days_ago = midnight_today - base::Days(2) + base::Hours(2);
+ base::Time two_days_ago_min =
+ (midnight_today - base::Days(1)).LocalMidnight() - base::Seconds(1);
+ base::Time two_days_ago_max = midnight_today - base::Days(2);
+
+ base::Time seven_days_ago = midnight_today - base::Days(7) + base::Hours(2);
+ base::Time seven_days_ago_min =
+ (midnight_today - base::Days(6)).LocalMidnight() - base::Seconds(1);
+ base::Time seven_days_ago_max = midnight_today - base::Days(7);
+
+ base::Time eight_days_ago =
+ (midnight_today - base::Days(7)).LocalMidnight() - base::Seconds(1);
+
+ EXPECT_EQ(PageInfoHistoryDataSource::FormatLastVisitedTimestamp(today, now),
+ u"Last visited today");
+ EXPECT_EQ(
+ PageInfoHistoryDataSource::FormatLastVisitedTimestamp(today_min, now),
+ u"Last visited today");
+ EXPECT_EQ(
+ PageInfoHistoryDataSource::FormatLastVisitedTimestamp(today_max, now),
+ u"Last visited today");
+
+ EXPECT_EQ(
+ PageInfoHistoryDataSource::FormatLastVisitedTimestamp(yesterday, now),
+ u"Last visited yesterday");
+ EXPECT_EQ(
+ PageInfoHistoryDataSource::FormatLastVisitedTimestamp(yesterday_min, now),
+ u"Last visited yesterday");
+ EXPECT_EQ(
+ PageInfoHistoryDataSource::FormatLastVisitedTimestamp(yesterday_max, now),
+ u"Last visited yesterday");
+
+ EXPECT_EQ(
+ PageInfoHistoryDataSource::FormatLastVisitedTimestamp(two_days_ago, now),
+ u"Last visited 2 days ago");
+ EXPECT_EQ(PageInfoHistoryDataSource::FormatLastVisitedTimestamp(
+ two_days_ago_min, now),
+ u"Last visited 2 days ago");
+ EXPECT_EQ(PageInfoHistoryDataSource::FormatLastVisitedTimestamp(
+ two_days_ago_max, now),
+ u"Last visited 2 days ago");
+
+ EXPECT_EQ(PageInfoHistoryDataSource::FormatLastVisitedTimestamp(
+ seven_days_ago, now),
+ u"Last visited 7 days ago");
+ EXPECT_EQ(PageInfoHistoryDataSource::FormatLastVisitedTimestamp(
+ seven_days_ago_min, now),
+ u"Last visited 7 days ago");
+ EXPECT_EQ(PageInfoHistoryDataSource::FormatLastVisitedTimestamp(
+ seven_days_ago_max, now),
+ u"Last visited 7 days ago");
+
+ EXPECT_EQ(PageInfoHistoryDataSource::FormatLastVisitedTimestamp(
+ eight_days_ago, now),
+ u"Last visited " + base::TimeFormatShortDate(eight_days_ago));
+}
+
+class PageInfoHistoryDataSourceTest : public testing::Test {
+ public:
+ void SetUp() override {
+ history_service_ =
+ std::make_unique<testing::StrictMock<history::MockHistoryService>>();
+ data_source_ = std::make_unique<PageInfoHistoryDataSource>(
+ history_service_.get(), GURL("https://foo.com"));
+ }
+
+ history::MockHistoryService* history_service() {
+ return history_service_.get();
+ }
+ PageInfoHistoryDataSource* data_source() { return data_source_.get(); }
+
+ private:
+ std::unique_ptr<history::MockHistoryService> history_service_;
+ std::unique_ptr<PageInfoHistoryDataSource> data_source_;
+};
+
+TEST_F(PageInfoHistoryDataSourceTest, NoHistory) {
+ // GetLastVisitToHost is called only once.
+ EXPECT_CALL(*history_service(), GetLastVisitToHost(_, _, _, _, _))
+ .WillOnce(Invoke(&ReturnVisitedNever));
+ data_source()->GetLastVisitedTimestamp(
+ base::BindOnce([](base::Time time) { EXPECT_TRUE(time.is_null()); }));
+}
+
+TEST_F(PageInfoHistoryDataSourceTest, LastVisitedTimestamp) {
+ // GetLastVisitToHost is called twice, once to get the latest visit (base) and
+ // the second to get the visit before it (last visit).
+ EXPECT_CALL(*history_service(), GetLastVisitToHost(_, _, _, _, _))
+ .WillOnce(Invoke(&ReturnVisitedBase))
+ .WillOnce(Invoke(&ReturnLastVisited));
+ data_source()->GetLastVisitedTimestamp(
+ base::BindOnce([](base::Time time) { EXPECT_EQ(time, kLastVisit); }));
+}
+
+// Consistently failing on US bots, after daylight saving time change in the US.
+// See crbug.com/1305929.
+TEST_F(PageInfoHistoryDataSourceTest, DISABLED_FormatTimestampString) {
+ CheckFormattedStringsForBaseTime(base::Time::Now());
+
+ // Test strings with the start of DST as the base time.
+ base::Time start_of_dst;
+ ASSERT_TRUE(base::Time::FromString("28 Mar 2021 10:30", &start_of_dst));
+ CheckFormattedStringsForBaseTime(start_of_dst);
+
+ // Test strings with 1 day after the end of DST as the base time.
+ base::Time end_of_dst;
+ ASSERT_TRUE(base::Time::FromString("1 Nov 2021 10:30", &end_of_dst));
+ CheckFormattedStringsForBaseTime(end_of_dst);
+}
+
+} // namespace page_info
diff --git a/chromium/components/page_info/page_info.cc b/chromium/components/page_info/page_info.cc
index 05e21918c0a..6b447cc77c5 100644
--- a/chromium/components/page_info/page_info.cc
+++ b/chromium/components/page_info/page_info.cc
@@ -39,7 +39,7 @@
#include "components/permissions/permission_result.h"
#include "components/permissions/permission_uma_util.h"
#include "components/permissions/permission_util.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "components/resources/android/theme_resources.h"
#endif
#include "build/chromeos_buildflags.h"
@@ -90,7 +90,7 @@ ContentSettingsType kPermissionType[] = {
ContentSettingsType::SENSORS,
ContentSettingsType::NOTIFICATIONS,
ContentSettingsType::JAVASCRIPT,
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
ContentSettingsType::IMAGES,
#endif
ContentSettingsType::POPUPS,
@@ -99,16 +99,16 @@ ContentSettingsType kPermissionType[] = {
ContentSettingsType::BACKGROUND_SYNC,
ContentSettingsType::SOUND,
ContentSettingsType::AUTOMATIC_DOWNLOADS,
-#if defined(OS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH) || defined(OS_WIN)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_WIN)
ContentSettingsType::PROTECTED_MEDIA_IDENTIFIER,
#endif
ContentSettingsType::MIDI_SYSEX,
ContentSettingsType::CLIPBOARD_READ_WRITE,
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
ContentSettingsType::NFC,
#endif
ContentSettingsType::USB_GUARD,
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
ContentSettingsType::HID_GUARD,
ContentSettingsType::SERIAL_GUARD,
ContentSettingsType::FILE_SYSTEM_WRITE_GUARD,
@@ -148,7 +148,7 @@ bool ShouldShowPermission(const PageInfo::PermissionInfo& info,
}
const bool is_incognito = web_contents->GetBrowserContext()->IsOffTheRecord();
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Special geolocation DSE settings apply only on Android, so make sure it
// gets checked there regardless of default setting on Desktop.
// DSE settings don't apply to incognito mode.
@@ -172,11 +172,11 @@ bool ShouldShowPermission(const PageInfo::PermissionInfo& info,
// Hide camera if camera PTZ is granted or blocked.
if (info.type == ContentSettingsType::MEDIASTREAM_CAMERA) {
- std::unique_ptr<base::Value> value = content_settings->GetWebsiteSetting(
+ const base::Value value = content_settings->GetWebsiteSetting(
site_url, site_url, ContentSettingsType::CAMERA_PAN_TILT_ZOOM, nullptr);
- DCHECK(value.get());
+ DCHECK(value.is_int());
ContentSetting camera_ptz_setting =
- content_settings::ValueToContentSetting(value.get());
+ content_settings::ValueToContentSetting(value);
if (camera_ptz_setting == CONTENT_SETTING_ALLOW ||
camera_ptz_setting == CONTENT_SETTING_BLOCK) {
return false;
@@ -264,10 +264,10 @@ const PageInfo::ChooserUIInfo kChooserUIInfo[] = {
IDS_PAGE_INFO_USB_DEVICE_SECONDARY_LABEL,
IDS_PAGE_INFO_USB_DEVICE_ALLOWED_BY_POLICY_LABEL,
IDS_PAGE_INFO_DELETE_USB_DEVICE},
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
{ContentSettingsType::HID_CHOOSER_DATA,
IDS_PAGE_INFO_HID_DEVICE_SECONDARY_LABEL,
- /*allowed_by_policy_description_string_id=*/-1,
+ IDS_PAGE_INFO_HID_DEVICE_ALLOWED_BY_POLICY_LABEL,
IDS_PAGE_INFO_DELETE_HID_DEVICE},
{ContentSettingsType::SERIAL_CHOOSER_DATA,
IDS_PAGE_INFO_SERIAL_PORT_SECONDARY_LABEL,
@@ -410,6 +410,7 @@ void PageInfo::InitializeUiState(PageInfoUI* ui, base::OnceClosure done) {
PresentSiteIdentity();
PresentPageFeatureInfo();
PresentSiteData(std::move(done));
+ PresentAdPersonalizationData();
}
void PageInfo::UpdateSecurityState() {
@@ -421,7 +422,7 @@ void PageInfo::RecordPageInfoAction(PageInfoAction action) {
if (action != PAGE_INFO_OPENED)
did_perform_action_ = true;
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
delegate_->OnPageInfoActionOccurred(action);
#endif
@@ -438,6 +439,38 @@ void PageInfo::RecordPageInfoAction(PageInfoAction action) {
security_state::GetSafetyTipHistogramName(
"Security.SafetyTips.PageInfo.Action", safety_tip_info_.status),
action, PAGE_INFO_COUNT);
+
+ // TODO(crbug.com/1286276): Add more user actions.
+ // Log user actions for metrics related to "Ad personalization".
+ auto* settings = GetPageSpecificContentSettings();
+ if (!settings)
+ return;
+
+ switch (action) {
+ case PageInfoAction::PAGE_INFO_OPENED:
+#if !BUILDFLAG(IS_ANDROID)
+ // TODO(crbug.com/1286276): Handle Topics metrics.
+ if (settings->HasJoinedUserToInterestGroup()) {
+ base::RecordAction(
+ base::UserMetricsAction("PageInfo.OpenedWithAdsPersonalization"));
+ }
+#endif
+ break;
+ case PageInfoAction::PAGE_INFO_AD_PERSONALIZATION_PAGE_OPENED:
+#if !BUILDFLAG(IS_ANDROID)
+ if (settings->HasJoinedUserToInterestGroup()) {
+ base::RecordAction(base::UserMetricsAction(
+ "PageInfo.AdPersonalization.OpenedWithFledge"));
+ }
+#endif
+ break;
+ case PageInfoAction::PAGE_INFO_AD_PERSONALIZATION_SETTINGS_OPENED:
+ base::RecordAction(base::UserMetricsAction(
+ "PageInfo.AdPersonalization.ManageInterestClicked"));
+ break;
+ default:
+ break;
+ }
}
void PageInfo::UpdatePermissions() {
@@ -530,7 +563,7 @@ void PageInfo::OnSiteChosenObjectDeleted(const ChooserUIInfo& ui_info,
void PageInfo::OnUIClosing(bool* reload_prompt) {
if (reload_prompt)
*reload_prompt = false;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
NOTREACHED();
#else
if (show_info_bar_ && web_contents_ && !web_contents_->IsBeingDestroyed()) {
@@ -552,7 +585,7 @@ void PageInfo::OnRevokeSSLErrorBypassButtonPressed() {
}
void PageInfo::OpenSiteSettingsView() {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
NOTREACHED();
#else
RecordPageInfoAction(PAGE_INFO_SITE_SETTINGS_OPENED);
@@ -561,7 +594,7 @@ void PageInfo::OpenSiteSettingsView() {
}
void PageInfo::OpenCookiesDialog() {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
NOTREACHED();
#else
if (!web_contents_ || web_contents_->IsBeingDestroyed())
@@ -573,7 +606,7 @@ void PageInfo::OpenCookiesDialog() {
}
void PageInfo::OpenCertificateDialog(net::X509Certificate* certificate) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
NOTREACHED();
#else
if (!web_contents_ || web_contents_->IsBeingDestroyed())
@@ -588,7 +621,7 @@ void PageInfo::OpenCertificateDialog(net::X509Certificate* certificate) {
}
void PageInfo::OpenSafetyTipHelpCenterPage() {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
NOTREACHED();
#else
RecordPageInfoAction(PAGE_INFO_SAFETY_TIP_HELP_OPENED);
@@ -597,7 +630,7 @@ void PageInfo::OpenSafetyTipHelpCenterPage() {
}
void PageInfo::OpenConnectionHelpCenterPage(const ui::Event& event) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
NOTREACHED();
#else
RecordPageInfoAction(PAGE_INFO_CONNECTION_HELP_OPENED);
@@ -607,7 +640,7 @@ void PageInfo::OpenConnectionHelpCenterPage(const ui::Event& event) {
void PageInfo::OpenContentSettingsExceptions(
ContentSettingsType content_settings_type) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
NOTREACHED();
#else
RecordPageInfoAction(PAGE_INFO_CONNECTION_HELP_OPENED);
@@ -647,7 +680,7 @@ std::u16string PageInfo::GetSimpleSiteName() const {
void PageInfo::ComputeUIInputs(const GURL& url) {
auto security_level = delegate_->GetSecurityLevel();
auto visible_security_state = delegate_->GetVisibleSecurityState();
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
// On desktop, internal URLs aren't handled by this class. Instead, a
// custom and simpler bubble is shown.
DCHECK(!url.SchemeIs(content::kChromeUIScheme) &&
@@ -657,7 +690,7 @@ void PageInfo::ComputeUIInputs(const GURL& url) {
#endif
bool is_chrome_ui_native_scheme = false;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
is_chrome_ui_native_scheme = url.SchemeIs(browser_ui::kChromeUINativeScheme);
#endif
@@ -665,7 +698,7 @@ void PageInfo::ComputeUIInputs(const GURL& url) {
// All about: URLs except about:blank are redirected.
DCHECK_EQ(url::kAboutBlankURL, url.spec());
site_identity_status_ = SITE_IDENTITY_STATUS_NO_CERT;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
identity_status_description_android_ =
l10n_util::GetStringUTF16(IDS_PAGE_INFO_SECURITY_TAB_INSECURE_IDENTITY);
#endif
@@ -678,7 +711,7 @@ void PageInfo::ComputeUIInputs(const GURL& url) {
if (url.SchemeIs(content::kChromeUIScheme) || is_chrome_ui_native_scheme) {
site_identity_status_ = SITE_IDENTITY_STATUS_INTERNAL_PAGE;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
identity_status_description_android_ =
l10n_util::GetStringUTF16(IDS_PAGE_INFO_INTERNAL_PAGE);
#endif
@@ -713,7 +746,7 @@ void PageInfo::ComputeUIInputs(const GURL& url) {
IDS_PAGE_INFO_SECURITY_TAB_UNKNOWN_PARTY));
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// This string is shown on all non-error HTTPS sites on Android when
// the user taps "Details" link on page info.
identity_status_description_android_.assign(l10n_util::GetStringFUTF16(
@@ -725,7 +758,7 @@ void PageInfo::ComputeUIInputs(const GURL& url) {
site_identity_status_ =
SITE_IDENTITY_STATUS_DEPRECATED_SIGNATURE_ALGORITHM;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
identity_status_description_android_ +=
u"\n\n" +
l10n_util::GetStringUTF16(
@@ -741,7 +774,7 @@ void PageInfo::ComputeUIInputs(const GURL& url) {
} else {
site_identity_status_ = SITE_IDENTITY_STATUS_ERROR;
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
const std::u16string bullet = u"\n • ";
std::vector<ssl_errors::ErrorInfo> errors;
ssl_errors::ErrorInfo::GetErrorsForCertStatus(
@@ -768,7 +801,7 @@ void PageInfo::ComputeUIInputs(const GURL& url) {
GetSafeBrowsingStatusByMaliciousContentStatus(
visible_security_state.malicious_content_status, &safe_browsing_status_,
&safe_browsing_details_);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
identity_status_description_android_ = safe_browsing_details_;
#endif
@@ -796,7 +829,7 @@ void PageInfo::ComputeUIInputs(const GURL& url) {
}
safety_tip_info_ = visible_security_state.safety_tip_info;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
if (security_state::IsSafetyTipUIFeatureEnabled()) {
// identity_status_description_android_ is only displayed on Android when
// the user taps "Details" link on the page info. Reuse the description from
@@ -920,12 +953,10 @@ void PageInfo::PresentSitePermissions() {
// TODO(crbug.com/1030245) Investigate why the value is queried from the low
// level routine GetWebsiteSettings.
- std::unique_ptr<base::Value> value = content_settings->GetWebsiteSetting(
+ const base::Value value = content_settings->GetWebsiteSetting(
site_url_, site_url_, permission_info.type, &info);
- DCHECK(value.get());
- if (value->type() == base::Value::Type::INTEGER) {
- permission_info.setting =
- content_settings::ValueToContentSetting(value.get());
+ if (value.is_int()) {
+ permission_info.setting = content_settings::ValueToContentSetting(value);
} else {
NOTREACHED();
}
@@ -1047,7 +1078,7 @@ void PageInfo::PresentSiteIdentity() {
if (security_state::IsSafetyTipUIFeatureEnabled()) {
info.safety_tip_info = safety_tip_info_;
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
info.identity_status_description_android =
UTF16ToUTF8(identity_status_description_android_);
#endif
@@ -1066,6 +1097,17 @@ void PageInfo::PresentPageFeatureInfo() {
ui_->SetPageFeatureInfo(info);
}
+void PageInfo::PresentAdPersonalizationData() {
+ PageInfoUI::AdPersonalizationInfo info;
+ auto* settings = GetPageSpecificContentSettings();
+ if (!settings)
+ return;
+
+ info.has_joined_user_to_interest_group =
+ settings->HasJoinedUserToInterestGroup();
+ ui_->SetAdPersonalizationInfo(info);
+}
+
#if BUILDFLAG(FULL_SAFE_BROWSING)
void PageInfo::RecordPasswordReuseEvent() {
auto* password_protection_service = delegate_->GetPasswordProtectionService();
diff --git a/chromium/components/page_info/page_info.h b/chromium/components/page_info/page_info.h
index 69dc8c30e44..d67d1b89b8a 100644
--- a/chromium/components/page_info/page_info.h
+++ b/chromium/components/page_info/page_info.h
@@ -147,6 +147,8 @@ class PageInfo {
PAGE_INFO_STORE_INFO_CLICKED = 27,
PAGE_INFO_ABOUT_THIS_SITE_PAGE_OPENED = 28,
PAGE_INFO_ABOUT_THIS_SITE_SOURCE_LINK_CLICKED = 29,
+ PAGE_INFO_AD_PERSONALIZATION_PAGE_OPENED = 30,
+ PAGE_INFO_AD_PERSONALIZATION_SETTINGS_OPENED = 31,
PAGE_INFO_COUNT
};
@@ -319,6 +321,9 @@ class PageInfo {
// presented in a headset.
void PresentPageFeatureInfo();
+ // Sets (presents) the information about ad personalization in the |ui_|.
+ void PresentAdPersonalizationData();
+
#if BUILDFLAG(FULL_SAFE_BROWSING)
// Records a password reuse event. If FULL_SAFE_BROWSING is defined, this
// function WILL record an event. Callers should check conditions beforehand.
@@ -395,7 +400,7 @@ class PageInfo {
// strings below to the corresponding UI code, in order to prevent
// unnecessary UTF-8 string conversions.
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Details about the website's identity. If the website's identity has been
// verified then |identity_status_description_android_| contains who verified
// the identity. This string will be displayed in the UI.
diff --git a/chromium/components/page_info/page_info_delegate.h b/chromium/components/page_info/page_info_delegate.h
index 932c14aa35d..66c065eb3fe 100644
--- a/chromium/components/page_info/page_info_delegate.h
+++ b/chromium/components/page_info/page_info_delegate.h
@@ -57,7 +57,7 @@ class PageInfoDelegate {
virtual permissions::PermissionResult GetPermissionStatus(
ContentSettingsType type,
const GURL& site_url) = 0;
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
// Creates an infobars::ContentInfoBarManager and an InfoBarDelegate using it,
// if possible. Returns true if an InfoBarDelegate was created, false
// otherwise.
@@ -94,7 +94,7 @@ class PageInfoDelegate {
virtual bool IsContentDisplayedInVrHeadset() = 0;
virtual security_state::SecurityLevel GetSecurityLevel() = 0;
virtual security_state::VisibleSecurityState GetVisibleSecurityState() = 0;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Gets the name of the embedder.
virtual const std::u16string GetClientApplicationName() = 0;
#endif
diff --git a/chromium/components/page_info/page_info_ui.cc b/chromium/components/page_info/page_info_ui.cc
index 8bd17c50079..dc41aa1f9ad 100644
--- a/chromium/components/page_info/page_info_ui.cc
+++ b/chromium/components/page_info/page_info_ui.cc
@@ -29,7 +29,7 @@
#include "services/device/public/cpp/device_features.h"
#include "ui/base/l10n/l10n_util.h"
#include "url/gurl.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "components/resources/android/theme_resources.h"
#else
#include "ui/gfx/color_palette.h"
@@ -98,7 +98,7 @@ static_assert(base::size(kPermissionButtonTextIDDefaultSetting) ==
CONTENT_SETTING_NUM_SETTINGS,
"kPermissionButtonTextIDDefaultSetting array size is incorrect");
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
// The resource IDs for the strings that are displayed on the sound permission
// button if the sound permission setting is managed by the user.
const int kSoundPermissionButtonTextIDUserManaged[] = {
@@ -154,7 +154,7 @@ base::span<const PageInfoUI::PermissionUIInfo> GetContentSettingsUIInfo() {
{ContentSettingsType::BACKGROUND_SYNC,
IDS_SITE_SETTINGS_TYPE_BACKGROUND_SYNC,
IDS_SITE_SETTINGS_TYPE_BACKGROUND_SYNC_MID_SENTENCE},
-#if defined(OS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH) || defined(OS_WIN)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_WIN)
{ContentSettingsType::PROTECTED_MEDIA_IDENTIFIER,
IDS_SITE_SETTINGS_TYPE_PROTECTED_MEDIA_ID,
IDS_SITE_SETTINGS_TYPE_PROTECTED_MEDIA_ID_MID_SENTENCE},
@@ -194,7 +194,7 @@ base::span<const PageInfoUI::PermissionUIInfo> GetContentSettingsUIInfo() {
IDS_SITE_SETTINGS_TYPE_CAMERA_PAN_TILT_ZOOM_MID_SENTENCE},
{ContentSettingsType::IDLE_DETECTION, IDS_SITE_SETTINGS_TYPE_IDLE_DETECTION,
IDS_SITE_SETTINGS_TYPE_IDLE_DETECTION_MID_SENTENCE},
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
// Page Info Permissions that are not defined in Android.
{ContentSettingsType::FILE_SYSTEM_WRITE_GUARD,
IDS_SITE_SETTINGS_TYPE_FILE_SYSTEM_ACCESS_WRITE,
@@ -448,7 +448,7 @@ PageInfoUI::GetSecurityDescription(const IdentityInfo& identity_info) const {
}
switch (identity_info.identity_status) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
case PageInfo::SITE_IDENTITY_STATUS_INTERNAL_PAGE:
return CreateSecurityDescription(SecuritySummaryColor::GREEN, 0,
IDS_PAGE_INFO_INTERNAL_PAGE,
@@ -493,7 +493,7 @@ PageInfoUI::GetSecurityDescription(const IdentityInfo& identity_info) const {
// Internal pages on desktop have their own UI implementations which
// should never call this function.
NOTREACHED();
- FALLTHROUGH;
+ [[fallthrough]];
case PageInfo::SITE_IDENTITY_STATUS_EV_CERT:
case PageInfo::SITE_IDENTITY_STATUS_CERT:
case PageInfo::SITE_IDENTITY_STATUS_ADMIN_PROVIDED_CERT:
@@ -585,7 +585,7 @@ std::u16string PageInfoUI::PermissionActionToUIString(
switch (source) {
case content_settings::SETTING_SOURCE_USER:
if (setting == CONTENT_SETTING_DEFAULT) {
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
if (type == ContentSettingsType::SOUND) {
// If the block autoplay enabled preference is enabled and the
// sound default setting is ALLOW, we will return a custom string
@@ -604,10 +604,10 @@ std::u16string PageInfoUI::PermissionActionToUIString(
button_text_ids = kPermissionButtonTextIDDefaultSetting;
break;
}
- FALLTHROUGH;
+ [[fallthrough]];
case content_settings::SETTING_SOURCE_POLICY:
case content_settings::SETTING_SOURCE_EXTENSION:
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
if (type == ContentSettingsType::SOUND) {
button_text_ids = kSoundPermissionButtonTextIDUserManaged;
break;
@@ -642,7 +642,7 @@ std::u16string PageInfoUI::PermissionStateToUIString(
permission.type, permission.setting, permission.default_setting);
switch (effective_setting) {
case CONTENT_SETTING_ALLOW:
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
if (permission.type == ContentSettingsType::SOUND &&
delegate->IsBlockAutoPlayEnabled() &&
permission.setting == CONTENT_SETTING_DEFAULT) {
@@ -652,7 +652,7 @@ std::u16string PageInfoUI::PermissionStateToUIString(
#endif
if (permission.setting == CONTENT_SETTING_DEFAULT) {
message_id = IDS_PAGE_INFO_STATE_TEXT_ALLOWED_BY_DEFAULT;
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
} else if (permission.is_one_time) {
DCHECK_EQ(permission.source, content_settings::SETTING_SOURCE_USER);
DCHECK(permissions::PermissionUtil::CanPermissionBeAllowedOnce(
@@ -667,7 +667,7 @@ std::u16string PageInfoUI::PermissionStateToUIString(
break;
case CONTENT_SETTING_BLOCK:
if (permission.setting == CONTENT_SETTING_DEFAULT) {
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
if (permission.type == ContentSettingsType::SOUND) {
message_id = IDS_PAGE_INFO_BUTTON_TEXT_MUTED_BY_DEFAULT;
break;
@@ -675,7 +675,7 @@ std::u16string PageInfoUI::PermissionStateToUIString(
#endif
message_id = IDS_PAGE_INFO_STATE_TEXT_NOT_ALLOWED_BY_DEFAULT;
} else {
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
if (permission.type == ContentSettingsType::SOUND) {
message_id = IDS_PAGE_INFO_STATE_TEXT_MUTED;
break;
@@ -881,7 +881,7 @@ SkColor PageInfoUI::GetSecondaryTextColor() {
return SK_ColorGRAY;
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// static
int PageInfoUI::GetIdentityIconID(PageInfo::SiteIdentityStatus status) {
switch (status) {
@@ -953,7 +953,7 @@ int PageInfoUI::GetConnectionIconColorID(
return 0;
}
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
// static
bool PageInfoUI::ContentSettingsTypeInPageInfo(ContentSettingsType type) {
diff --git a/chromium/components/page_info/page_info_ui.h b/chromium/components/page_info/page_info_ui.h
index 63b6f512f29..ede9ac16ebf 100644
--- a/chromium/components/page_info/page_info_ui.h
+++ b/chromium/components/page_info/page_info_ui.h
@@ -18,7 +18,7 @@
#include "ui/base/models/image_model.h"
#include "ui/gfx/native_widget_types.h"
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
#include "ui/gfx/image/image_skia.h"
#endif
@@ -119,7 +119,7 @@ class PageInfoUI {
// Textual description of the Safe Browsing status.
std::u16string safe_browsing_details;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Textual description of the site's identity status that is displayed to
// the user.
std::string identity_status_description_android;
@@ -158,6 +158,10 @@ class PageInfoUI {
int string_id_mid_sentence;
};
+ struct AdPersonalizationInfo {
+ bool has_joined_user_to_interest_group;
+ };
+
using CookieInfoList = std::vector<CookieInfo>;
using PermissionInfoList = std::vector<PageInfo::PermissionInfo>;
using ChosenObjectInfoList = std::vector<std::unique_ptr<ChosenObjectInfo>>;
@@ -217,7 +221,7 @@ class PageInfoUI {
// Returns the color to use for the permission decision reason strings.
static SkColor GetSecondaryTextColor();
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Returns the identity icon ID for the given identity |status|.
static int GetIdentityIconID(PageInfo::SiteIdentityStatus status);
@@ -229,7 +233,7 @@ class PageInfoUI {
// Returns the connection icon color ID for the given connection |status|.
static int GetConnectionIconColorID(PageInfo::SiteConnectionStatus status);
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
// Return true if the given ContentSettingsType is in PageInfoUI.
static bool ContentSettingsTypeInPageInfo(ContentSettingsType type);
@@ -256,6 +260,10 @@ class PageInfoUI {
// presented in a headset.
virtual void SetPageFeatureInfo(const PageFeatureInfo& page_feature_info) {}
+ // Sets ad personalization information.
+ virtual void SetAdPersonalizationInfo(
+ const AdPersonalizationInfo& ad_personalization_info) {}
+
// Helper to get security description info to display to the user.
std::unique_ptr<SecurityDescription> GetSecurityDescription(
const IdentityInfo& identity_info) const;
diff --git a/chromium/components/page_info/page_info_ui_delegate.h b/chromium/components/page_info/page_info_ui_delegate.h
index bc257c8cff7..bb8a34a6a62 100644
--- a/chromium/components/page_info/page_info_ui_delegate.h
+++ b/chromium/components/page_info/page_info_ui_delegate.h
@@ -12,7 +12,7 @@
class PageInfoUiDelegate {
public:
virtual ~PageInfoUiDelegate() = default;
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
virtual bool IsBlockAutoPlayEnabled() = 0;
virtual bool IsMultipleTabsOpen() = 0;
#endif
diff --git a/chromium/components/page_info_strings.grdp b/chromium/components/page_info_strings.grdp
index 929185b11a3..daf53123b88 100644
--- a/chromium/components/page_info_strings.grdp
+++ b/chromium/components/page_info_strings.grdp
@@ -447,8 +447,8 @@
<message name="IDS_PAGE_INFO_STATE_TEXT_IDLE_DETECTION_ASK" desc="The Page Info permission subpage and the main page info page contain a label which shows the state of the site permission. This is the text shown if the idle detection permission is in the ask state and the site can prompt the user to ask if they allow the site to know when you're actively using this device.">
Can ask to know when you're actively using this device
</message>
- <message name="IDS_PAGE_INFO_STATE_TEXT_WINDOW_PLACEMENT_ASK" desc="The Page Info permission subpage and the main page info page contain a label which shows the state of the site permission. This is the text shown if the window placement permission is in the ask state and the site can prompt the user to ask if they allow the site to open and place windows on your screens.">
- Can ask to open and place windows on your screens
+ <message name="IDS_PAGE_INFO_STATE_TEXT_WINDOW_PLACEMENT_ASK" desc="The Page Info permission subpage and the main page info page contain a label which shows the state of the site permission. This is the text shown if the window placement permission is in the ask state and the site can prompt the user to ask if they allow the site to use info about your screens to open and place windows.">
+ Can ask to use info about your screens
</message>
<message name="IDS_PAGE_INFO_STATE_TEXT_BLUETOOTH_SCANNING_ASK" desc="The Page Info permission subpage and the main page info page contain a label which shows the state of the site permission. This is the text shown if the bluetooth scanning permission is in the ask state and the site can prompt the user to ask if they allow the site to discover nearby Bluetooth devices.">
Can ask to discover nearby Bluetooth devices
@@ -482,6 +482,9 @@
<message name="IDS_PAGE_INFO_HID_DEVICE_SECONDARY_LABEL" desc="The label displayed underneath the device name to inform the user that the permission listed refers to a HID device.">
HID device
</message>
+ <message name="IDS_PAGE_INFO_HID_DEVICE_ALLOWED_BY_POLICY_LABEL" desc="The label displayed underneath the device name to inform the user that the item listed is refering to a HID device explicitly allowed by the user's enterprise policy.">
+ HID device allowed by your administrator
+ </message>
<message name="IDS_PAGE_INFO_DELETE_HID_DEVICE" desc="The tooltip displayed when hovering over the button that will remove permission to access a HID device that the user previously granted to the site.">
Revoke access
</message>
@@ -493,12 +496,6 @@
<message name="IDS_PAGE_INFO_SITE_SETTINGS_TOOLTIP" desc="The text of the tooltip on IDS_PAGE_INFO_SITE_SETTINGS_LINK.">
Go to site settings
</message>
- <message name="IDS_PAGE_INFO_APP_SETTINGS_LINK" desc="This is the text of the link pointing to the App Settings page. This appears at the bottom of the Permissions pane of the Page Information Window for app windows (in place of 'Site settings').">
- App settings
- </message>
- <message name="IDS_PAGE_INFO_APP_SETTINGS_TOOLTIP" desc="The text of the tooltip on IDS_PAGE_INFO_SITE_SETTINGS_LINK.">
- Go to app settings
- </message>
<!-- Permission decision strings -->
<message name="IDS_PAGE_INFO_PERMISSION_ALLOWED_BY_POLICY" desc="The label used underneath a permission listed in the Page Info bubble if the permission was explicitly allowed by the user's enterprise policy.">
@@ -693,12 +690,29 @@
<!-- About this site strings -->
<message name="IDS_PAGE_INFO_ABOUT_THIS_SITE_HEADER" desc="The header label of the 'About this site' subpage in Page Info bubble.">
- About this site
+ From the web
</message>
<message name="IDS_PAGE_INFO_ABOUT_THIS_SITE_TOOLTIP" desc="The tooltip of the button that opens 'About this site' subpage in Page Info bubble.">
- Show information about this site
+ Show information from the web
</message>
<message name="IDS_PAGE_INFO_ABOUT_THIS_SITE_SUBPAGE_FROM_LABEL" desc="The label containing the source of the description in the 'About this site' subpage in Page Info bubble.">
From <ph name="SOURCE_NAME">$1<ex>Wikipedia</ex></ph>
</message>
+
+ <!-- History strings -->
+ <message name="IDS_PAGE_INFO_HISTORY" desc="The button label of the 'History' row in Page Info bubble. The button opens history page for the site.">
+ History
+ </message>
+ <message name="IDS_PAGE_INFO_HISTORY_LAST_VISIT_TODAY" desc="Summary string for page info history row. The site was last visited today.">
+ Last visited today
+ </message>
+ <message name="IDS_PAGE_INFO_HISTORY_LAST_VISIT_YESTERDAY" desc="Summary string for page info history row. The site was last visited yesterday.">
+ Last visited yesterday
+ </message>
+ <message name="IDS_PAGE_INFO_HISTORY_LAST_VISIT_DAYS" desc="Summary string for page info history row. The site was last visited NUM_DAYS days ago.">
+ Last visited <ph name="NUM_DAYS">$1<ex>2</ex></ph> days ago
+ </message>
+ <message name="IDS_PAGE_INFO_HISTORY_LAST_VISIT_DATE" desc="Summary string for page info history row. The site was last visited on a particular date.">
+ Last visited <ph name="DATE">$1<ex>Apr 4, 2021</ex></ph>
+ </message>
</grit-part>
diff --git a/chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_ABOUT_THIS_SITE_HEADER.png.sha1 b/chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_ABOUT_THIS_SITE_HEADER.png.sha1
index 6ba6e64c710..f510453d0cf 100644
--- a/chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_ABOUT_THIS_SITE_HEADER.png.sha1
+++ b/chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_ABOUT_THIS_SITE_HEADER.png.sha1
@@ -1 +1 @@
-4d5f8be2407375d863954f3fcc6f4ab4429ed197 \ No newline at end of file
+6cf1fed797859159d14497eabe782c6841a3398a \ No newline at end of file
diff --git a/chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_ABOUT_THIS_SITE_TOOLTIP.png.sha1 b/chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_ABOUT_THIS_SITE_TOOLTIP.png.sha1
index 9518431224a..f510453d0cf 100644
--- a/chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_ABOUT_THIS_SITE_TOOLTIP.png.sha1
+++ b/chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_ABOUT_THIS_SITE_TOOLTIP.png.sha1
@@ -1 +1 @@
-8c190dc9e1c98c101a56d32d4232af8f35c91a35 \ No newline at end of file
+6cf1fed797859159d14497eabe782c6841a3398a \ No newline at end of file
diff --git a/chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_APP_SETTINGS_LINK.png.sha1 b/chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_APP_SETTINGS_LINK.png.sha1
deleted file mode 100644
index c1dfbe8d502..00000000000
--- a/chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_APP_SETTINGS_LINK.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-65616427d7ff11d4cf03f7cf0f0cfe4114a4395f \ No newline at end of file
diff --git a/chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_APP_SETTINGS_TOOLTIP.png.sha1 b/chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_APP_SETTINGS_TOOLTIP.png.sha1
deleted file mode 100644
index c1dfbe8d502..00000000000
--- a/chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_APP_SETTINGS_TOOLTIP.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-65616427d7ff11d4cf03f7cf0f0cfe4114a4395f \ No newline at end of file
diff --git a/chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_HID_DEVICE_ALLOWED_BY_POLICY_LABEL.png.sha1 b/chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_HID_DEVICE_ALLOWED_BY_POLICY_LABEL.png.sha1
new file mode 100644
index 00000000000..19dac9e5d79
--- /dev/null
+++ b/chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_HID_DEVICE_ALLOWED_BY_POLICY_LABEL.png.sha1
@@ -0,0 +1 @@
+b01f74a5070aefa46ab96b0b8b49803c6b908551 \ No newline at end of file
diff --git a/chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_HISTORY.png.sha1 b/chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_HISTORY.png.sha1
new file mode 100644
index 00000000000..ec116557bf1
--- /dev/null
+++ b/chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_HISTORY.png.sha1
@@ -0,0 +1 @@
+d927fd0497c9ae6a817e524517c925604b325b01 \ No newline at end of file
diff --git a/chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_HISTORY_LAST_VISIT_DATE.png.sha1 b/chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_HISTORY_LAST_VISIT_DATE.png.sha1
new file mode 100644
index 00000000000..4730ee6a1e2
--- /dev/null
+++ b/chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_HISTORY_LAST_VISIT_DATE.png.sha1
@@ -0,0 +1 @@
+c26a020f4ebb431a012f5669901dc5ee849c9bc8 \ No newline at end of file
diff --git a/chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_HISTORY_LAST_VISIT_DAYS.png.sha1 b/chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_HISTORY_LAST_VISIT_DAYS.png.sha1
new file mode 100644
index 00000000000..e2110ab3cea
--- /dev/null
+++ b/chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_HISTORY_LAST_VISIT_DAYS.png.sha1
@@ -0,0 +1 @@
+4d4e2d8b2d6f260963b8665c6718c3bd06c18b46 \ No newline at end of file
diff --git a/chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_HISTORY_LAST_VISIT_TODAY.png.sha1 b/chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_HISTORY_LAST_VISIT_TODAY.png.sha1
new file mode 100644
index 00000000000..ec116557bf1
--- /dev/null
+++ b/chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_HISTORY_LAST_VISIT_TODAY.png.sha1
@@ -0,0 +1 @@
+d927fd0497c9ae6a817e524517c925604b325b01 \ No newline at end of file
diff --git a/chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_HISTORY_LAST_VISIT_YESTERDAY.png.sha1 b/chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_HISTORY_LAST_VISIT_YESTERDAY.png.sha1
new file mode 100644
index 00000000000..116c98c9efb
--- /dev/null
+++ b/chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_HISTORY_LAST_VISIT_YESTERDAY.png.sha1
@@ -0,0 +1 @@
+8827e0588e5397a18d6dd782daf67ed28ed61d89 \ No newline at end of file
diff --git a/chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_STATE_TEXT_WINDOW_PLACEMENT_ASK.png.sha1 b/chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_STATE_TEXT_WINDOW_PLACEMENT_ASK.png.sha1
index e4f82342432..fc2bdfd4ad3 100644
--- a/chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_STATE_TEXT_WINDOW_PLACEMENT_ASK.png.sha1
+++ b/chromium/components/page_info_strings_grdp/IDS_PAGE_INFO_STATE_TEXT_WINDOW_PLACEMENT_ASK.png.sha1
@@ -1 +1 @@
-dea1b631a1b45af9457cf237f9bbe7a8c887ca1c \ No newline at end of file
+e4a5d5c55aac37fffcfa64e3fbfbe7e14aff46b0 \ No newline at end of file
diff --git a/chromium/components/page_load_metrics/browser/metrics_web_contents_observer.cc b/chromium/components/page_load_metrics/browser/metrics_web_contents_observer.cc
index db2dbb77e1c..526541a2f15 100644
--- a/chromium/components/page_load_metrics/browser/metrics_web_contents_observer.cc
+++ b/chromium/components/page_load_metrics/browser/metrics_web_contents_observer.cc
@@ -255,18 +255,6 @@ void MetricsWebContentsObserver::WillStartNavigationRequestImpl(
NotifyAbortedProvisionalLoadsNewNavigation(navigation_handle,
user_initiated_info);
- int chain_size_same_url = 0;
- int chain_size = 0;
- if (last_aborted) {
- if (last_aborted->MatchesOriginalNavigation(navigation_handle)) {
- chain_size_same_url = last_aborted->aborted_chain_size_same_url() + 1;
- } else if (last_aborted->aborted_chain_size_same_url() > 0) {
- LogAbortChainSameURLHistogram(
- last_aborted->aborted_chain_size_same_url());
- }
- chain_size = last_aborted->aborted_chain_size() + 1;
- }
-
if (!ShouldTrackMainFrameNavigation(navigation_handle))
return;
@@ -294,8 +282,7 @@ void MetricsWebContentsObserver::WillStartNavigationRequestImpl(
navigation_handle,
std::make_unique<PageLoadTracker>(
in_foreground, embedder_interface_.get(), currently_committed_url,
- !has_navigated_, navigation_handle, user_initiated_info, chain_size,
- chain_size_same_url)));
+ !has_navigated_, navigation_handle, user_initiated_info)));
DCHECK(insertion_result.second)
<< "provisional_loads_ already contains NavigationHandle.";
for (auto& observer : testing_observers_)
@@ -746,14 +733,6 @@ void MetricsWebContentsObserver::FinalizeCurrentlyCommittedLoad(
/*is_certainly_browser_timestamp=*/false);
if (committed_load_) {
- bool is_non_user_initiated_client_redirect =
- !IsNavigationUserInitiated(newly_committed_navigation) &&
- (newly_committed_navigation->GetPageTransition() &
- ui::PAGE_TRANSITION_CLIENT_REDIRECT) != 0;
- if (is_non_user_initiated_client_redirect) {
- committed_load_->NotifyClientRedirectTo(newly_committed_navigation);
- }
-
// Ensure that any pending update gets dispatched.
committed_load_->metrics_update_dispatcher()->FlushPendingTimingUpdates();
}
diff --git a/chromium/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc b/chromium/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc
index 545296cba3c..77e4b29567a 100644
--- a/chromium/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc
+++ b/chromium/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc
@@ -561,72 +561,6 @@ TEST_F(MetricsWebContentsObserverTest, ObservePartialNavigation) {
CheckTotalErrorEvents();
}
-TEST_F(MetricsWebContentsObserverTest, DontLogAbortChains) {
- NavigateAndCommit(GURL(kDefaultTestUrl));
- NavigateAndCommit(GURL(kDefaultTestUrl2));
- NavigateAndCommit(GURL(kDefaultTestUrl));
- histogram_tester_.ExpectTotalCount(internal::kAbortChainSizeNewNavigation, 0);
- CheckErrorNoIPCsReceivedIfNeeded(2);
- CheckTotalErrorEvents();
-}
-
-TEST_F(MetricsWebContentsObserverTest, LogAbortChains) {
- // Start and abort three loads before one finally commits.
- NavigationSimulator::NavigateAndFailFromBrowser(
- web_contents(), GURL(kDefaultTestUrl), net::ERR_ABORTED);
-
- NavigationSimulator::NavigateAndFailFromBrowser(
- web_contents(), GURL(kDefaultTestUrl2), net::ERR_ABORTED);
-
- NavigationSimulator::NavigateAndFailFromBrowser(
- web_contents(), GURL(kDefaultTestUrl), net::ERR_ABORTED);
-
- NavigationSimulator::NavigateAndCommitFromBrowser(web_contents(),
- GURL(kDefaultTestUrl2));
-
- histogram_tester_.ExpectTotalCount(internal::kAbortChainSizeNewNavigation, 1);
- histogram_tester_.ExpectBucketCount(internal::kAbortChainSizeNewNavigation, 3,
- 1);
- CheckNoErrorEvents();
-}
-
-TEST_F(MetricsWebContentsObserverTest, LogAbortChainsSameURL) {
- // Start and abort three loads before one finally commits.
- NavigationSimulator::NavigateAndFailFromBrowser(
- web_contents(), GURL(kDefaultTestUrl), net::ERR_ABORTED);
-
- NavigationSimulator::NavigateAndFailFromBrowser(
- web_contents(), GURL(kDefaultTestUrl), net::ERR_ABORTED);
-
- NavigationSimulator::NavigateAndFailFromBrowser(
- web_contents(), GURL(kDefaultTestUrl), net::ERR_ABORTED);
-
- NavigationSimulator::NavigateAndCommitFromBrowser(web_contents(),
- GURL(kDefaultTestUrl));
- histogram_tester_.ExpectTotalCount(internal::kAbortChainSizeNewNavigation, 1);
- histogram_tester_.ExpectBucketCount(internal::kAbortChainSizeNewNavigation, 3,
- 1);
- histogram_tester_.ExpectTotalCount(internal::kAbortChainSizeSameURL, 1);
- histogram_tester_.ExpectBucketCount(internal::kAbortChainSizeSameURL, 3, 1);
-}
-
-TEST_F(MetricsWebContentsObserverTest, LogAbortChainsNoCommit) {
- // Start and abort three loads before one finally commits.
- NavigationSimulator::NavigateAndFailFromBrowser(
- web_contents(), GURL(kDefaultTestUrl), net::ERR_ABORTED);
-
- NavigationSimulator::NavigateAndFailFromBrowser(
- web_contents(), GURL(kDefaultTestUrl2), net::ERR_ABORTED);
-
- NavigationSimulator::NavigateAndFailFromBrowser(
- web_contents(), GURL(kDefaultTestUrl), net::ERR_ABORTED);
-
- web_contents()->Stop();
-
- histogram_tester_.ExpectTotalCount(internal::kAbortChainSizeNoCommit, 1);
- histogram_tester_.ExpectBucketCount(internal::kAbortChainSizeNoCommit, 3, 1);
-}
-
TEST_F(MetricsWebContentsObserverTest, FlushMetricsOnAppEnterBackground) {
content::NavigationSimulator::NavigateAndCommitFromBrowser(
web_contents(), GURL(kDefaultTestUrl));
@@ -808,9 +742,6 @@ TEST_F(MetricsWebContentsObserverTest, OutOfOrderCrossFrameTiming2) {
GURL(kDefaultTestUrl2), subframe);
SimulateTimingUpdateWithoutFiringDispatchTimer(subframe_timing, subframe);
- histogram_tester_.ExpectTotalCount(
- page_load_metrics::internal::kHistogramOutOfOrderTiming, 1);
-
EXPECT_TRUE(GetMostRecentTimer()->IsRunning());
ASSERT_EQ(0, CountUpdatedTimingReported());
@@ -859,12 +790,6 @@ TEST_F(MetricsWebContentsObserverTest, OutOfOrderCrossFrameTiming2) {
ASSERT_EQ(2, CountUpdatedTimingReported());
EXPECT_LT(updated_first_paint, initial_first_paint);
- histogram_tester_.ExpectTotalCount(
- page_load_metrics::internal::kHistogramOutOfOrderTimingBuffered, 1);
- histogram_tester_.ExpectBucketCount(
- page_load_metrics::internal::kHistogramOutOfOrderTimingBuffered,
- (initial_first_paint - updated_first_paint).InMilliseconds(), 1);
-
CheckNoErrorEvents();
}
diff --git a/chromium/components/page_load_metrics/browser/observers/README.md b/chromium/components/page_load_metrics/browser/observers/README.md
new file mode 100644
index 00000000000..f8b91b39add
--- /dev/null
+++ b/chromium/components/page_load_metrics/browser/observers/README.md
@@ -0,0 +1 @@
+See [`chrome/browser/page_load_metrics/observers/README.md`](/chrome/browser/page_load_metrics/observers/README.md) \ No newline at end of file
diff --git a/chromium/components/page_load_metrics/browser/observers/ad_metrics/ads_page_load_metrics_observer.cc b/chromium/components/page_load_metrics/browser/observers/ad_metrics/ads_page_load_metrics_observer.cc
index 74cd511b56b..a9fdee69ef2 100644
--- a/chromium/components/page_load_metrics/browser/observers/ad_metrics/ads_page_load_metrics_observer.cc
+++ b/chromium/components/page_load_metrics/browser/observers/ad_metrics/ads_page_load_metrics_observer.cc
@@ -18,6 +18,7 @@
#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
#include "base/time/default_tick_clock.h"
+#include "build/build_config.h"
#include "components/heavy_ad_intervention/heavy_ad_blocklist.h"
#include "components/heavy_ad_intervention/heavy_ad_features.h"
#include "components/heavy_ad_intervention/heavy_ad_helper.h"
@@ -29,6 +30,7 @@
#include "components/page_load_metrics/common/page_end_reason.h"
#include "components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.h"
#include "components/subresource_filter/content/browser/content_subresource_filter_web_contents_helper.h"
+#include "components/subresource_filter/core/browser/subresource_filter_features.h"
#include "components/subresource_filter/core/common/common_features.h"
#include "components/subresource_filter/core/common/load_policy.h"
#include "components/subresource_filter/core/mojom/subresource_filter.mojom.h"
@@ -55,8 +57,6 @@
#include "ui/gfx/geometry/size.h"
#include "url/gurl.h"
-#include "components/subresource_filter/core/browser/subresource_filter_features.h"
-
namespace page_load_metrics {
namespace features {
@@ -624,7 +624,7 @@ void AdsPageLoadMetricsObserver::OnFrameIntersectionUpdate(
// TODO(https://crbug.com/1142669): Evaluate imposing width requirements
// for ad density violations.
void AdsPageLoadMetricsObserver::CheckForAdDensityViolation() {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
const int kMaxMobileAdDensityByHeight = 30;
if (page_ad_density_tracker_.MaxPageAdDensityByHeight() >
kMaxMobileAdDensityByHeight) {
diff --git a/chromium/components/page_load_metrics/browser/observers/ad_metrics/ads_page_load_metrics_observer.h b/chromium/components/page_load_metrics/browser/observers/ad_metrics/ads_page_load_metrics_observer.h
index 89b20ef74fc..5a710fe9926 100644
--- a/chromium/components/page_load_metrics/browser/observers/ad_metrics/ads_page_load_metrics_observer.h
+++ b/chromium/components/page_load_metrics/browser/observers/ad_metrics/ads_page_load_metrics_observer.h
@@ -6,7 +6,6 @@
#define COMPONENTS_PAGE_LOAD_METRICS_BROWSER_OBSERVERS_AD_METRICS_ADS_PAGE_LOAD_METRICS_OBSERVER_H_
#include <bitset>
-#include <list>
#include <map>
#include <memory>
diff --git a/chromium/components/page_load_metrics/browser/observers/back_forward_cache_page_load_metrics_observer.cc b/chromium/components/page_load_metrics/browser/observers/back_forward_cache_page_load_metrics_observer.cc
index e34938799e8..943ed7ab944 100644
--- a/chromium/components/page_load_metrics/browser/observers/back_forward_cache_page_load_metrics_observer.cc
+++ b/chromium/components/page_load_metrics/browser/observers/back_forward_cache_page_load_metrics_observer.cc
@@ -340,6 +340,16 @@ void BackForwardCachePageLoadMetricsObserver::RecordMetricsOnPageVisitEnd(
if (has_ever_entered_back_forward_cache_) {
page_load_metrics::RecordPageVisitFinalStatusForTiming(
timing, GetDelegate(), GetLastUkmSourceIdForBackForwardCacheRestore());
+ bool is_user_initiated_navigation =
+ // All browser initiated page loads are user-initiated.
+ GetDelegate().GetUserInitiatedInfo().browser_initiated ||
+ // Renderer-initiated navigations are user-initiated if there is an
+ // associated input event.
+ GetDelegate().GetUserInitiatedInfo().user_input_event;
+ ukm::builders::UserPerceivedPageVisit(
+ GetLastUkmSourceIdForBackForwardCacheRestore())
+ .SetUserInitiated(is_user_initiated_navigation)
+ .Record(ukm::UkmRecorder::Get());
}
}
diff --git a/chromium/components/page_load_metrics/browser/observers/back_forward_cache_page_load_metrics_observer_unittest.cc b/chromium/components/page_load_metrics/browser/observers/back_forward_cache_page_load_metrics_observer_unittest.cc
index 3152f6a458b..e0d7b0fb4a0 100644
--- a/chromium/components/page_load_metrics/browser/observers/back_forward_cache_page_load_metrics_observer_unittest.cc
+++ b/chromium/components/page_load_metrics/browser/observers/back_forward_cache_page_load_metrics_observer_unittest.cc
@@ -8,6 +8,7 @@
#include "base/test/simple_test_tick_clock.h"
#include "components/page_load_metrics/browser/fake_page_load_metrics_observer_delegate.h"
#include "components/page_load_metrics/browser/observers/page_load_metrics_observer_content_test_harness.h"
+#include "components/page_load_metrics/browser/page_load_metrics_observer.h"
#include "components/page_load_metrics/browser/page_load_tracker.h"
#include "content/public/test/mock_navigation_handle.h"
#include "services/metrics/public/cpp/metrics_utils.h"
@@ -534,3 +535,62 @@ TEST_F(BackForwardCachePageLoadMetricsObserverTest, TestLogsNonCWVPageVisit) {
EXPECT_FALSE(result_metrics[1].begin()->second);
}
}
+
+TEST_F(BackForwardCachePageLoadMetricsObserverTest, TestLogsUserInitiated) {
+ auto& test_ukm_recorder = tester()->test_ukm_recorder();
+ auto fake_bfcache_restore =
+ PageLoadMetricsObserverDelegate::BackForwardCacheRestore(
+ /*was_in_foreground=*/true, base::TimeTicks());
+ fake_delegate_->AddBackForwardCacheRestore(fake_bfcache_restore);
+
+ fake_delegate_->user_initiated_info_ =
+ page_load_metrics::UserInitiatedInfo::NotUserInitiated();
+ observer_with_fake_delegate_->OnComplete(timing_);
+
+ auto result_metrics = test_ukm_recorder.FilteredHumanReadableMetricForEntry(
+ UserPerceivedPageVisit::kEntryName,
+ UserPerceivedPageVisit::kUserInitiatedName);
+ EXPECT_EQ(1U, result_metrics.size());
+ EXPECT_EQ(UserPerceivedPageVisit::kUserInitiatedName,
+ result_metrics[0].begin()->first);
+ EXPECT_FALSE(result_metrics[0].begin()->second);
+
+ // Browser initiated; this is always considered user initiated.
+ fake_delegate_->user_initiated_info_ =
+ page_load_metrics::UserInitiatedInfo::BrowserInitiated();
+ observer_with_fake_delegate_->OnComplete(timing_);
+
+ result_metrics = test_ukm_recorder.FilteredHumanReadableMetricForEntry(
+ UserPerceivedPageVisit::kEntryName,
+ UserPerceivedPageVisit::kUserInitiatedName);
+ EXPECT_EQ(2U, result_metrics.size());
+ EXPECT_EQ(UserPerceivedPageVisit::kUserInitiatedName,
+ result_metrics[1].begin()->first);
+ EXPECT_TRUE(result_metrics[1].begin()->second);
+
+ // Renderer initiated, with user input, considered user initiated.
+ fake_delegate_->user_initiated_info_ =
+ page_load_metrics::UserInitiatedInfo::RenderInitiated(true, true);
+ observer_with_fake_delegate_->OnComplete(timing_);
+
+ result_metrics = test_ukm_recorder.FilteredHumanReadableMetricForEntry(
+ UserPerceivedPageVisit::kEntryName,
+ UserPerceivedPageVisit::kUserInitiatedName);
+ EXPECT_EQ(3U, result_metrics.size());
+ EXPECT_EQ(UserPerceivedPageVisit::kUserInitiatedName,
+ result_metrics[2].begin()->first);
+ EXPECT_TRUE(result_metrics[2].begin()->second);
+
+ // Renderer initiated, without user input, not considered user initiated.
+ fake_delegate_->user_initiated_info_ =
+ page_load_metrics::UserInitiatedInfo::RenderInitiated(false, false);
+ observer_with_fake_delegate_->OnComplete(timing_);
+
+ result_metrics = test_ukm_recorder.FilteredHumanReadableMetricForEntry(
+ UserPerceivedPageVisit::kEntryName,
+ UserPerceivedPageVisit::kUserInitiatedName);
+ EXPECT_EQ(4U, result_metrics.size());
+ EXPECT_EQ(UserPerceivedPageVisit::kUserInitiatedName,
+ result_metrics[3].begin()->first);
+ EXPECT_FALSE(result_metrics[3].begin()->second);
+}
diff --git a/chromium/components/page_load_metrics/browser/observers/core/largest_contentful_paint_handler.cc b/chromium/components/page_load_metrics/browser/observers/core/largest_contentful_paint_handler.cc
index fdf2a151bb7..78c9d3e850a 100644
--- a/chromium/components/page_load_metrics/browser/observers/core/largest_contentful_paint_handler.cc
+++ b/chromium/components/page_load_metrics/browser/observers/core/largest_contentful_paint_handler.cc
@@ -51,11 +51,12 @@ void MergeForSubframesWithAdjustedTime(
DCHECK(inout_timing);
const ContentfulPaintTimingInfo new_candidate(
candidate_new_time, candidate_new_size, inout_timing->TextOrImage(),
- inout_timing->InMainFrame(), inout_timing->Type());
+ inout_timing->InMainFrame(), inout_timing->Type(),
+ inout_timing->ImageBPP());
const ContentfulPaintTimingInfo& merged_candidate =
MergeTimingsBySizeAndTime(new_candidate, *inout_timing);
inout_timing->Reset(merged_candidate.Time(), merged_candidate.Size(),
- merged_candidate.Type());
+ merged_candidate.Type(), merged_candidate.ImageBPP());
}
bool IsSubframe(content::RenderFrameHost* subframe_rfh) {
@@ -63,7 +64,7 @@ bool IsSubframe(content::RenderFrameHost* subframe_rfh) {
}
void Reset(ContentfulPaintTimingInfo& timing) {
- timing.Reset(absl::nullopt, 0u, 0 /*type*/);
+ timing.Reset(absl::nullopt, 0u, /*type=*/0, /*image_bpp=*/0.0);
}
bool IsSameSite(const GURL& url1, const GURL& url2) {
@@ -90,12 +91,14 @@ ContentfulPaintTimingInfo::ContentfulPaintTimingInfo(
const absl::optional<base::TimeDelta>& time,
const uint64_t& size,
const LargestContentTextOrImage text_or_image,
+ double image_bpp,
bool in_main_frame,
uint32_t type)
: time_(time),
size_(size),
text_or_image_(text_or_image),
type_(type),
+ image_bpp_(image_bpp),
in_main_frame_(in_main_frame) {}
ContentfulPaintTimingInfo::ContentfulPaintTimingInfo(
@@ -135,10 +138,12 @@ void LargestContentfulPaintHandler::SetTestMode(bool enabled) {
void ContentfulPaintTimingInfo::Reset(
const absl::optional<base::TimeDelta>& time,
const uint64_t& size,
- uint32_t type) {
+ uint32_t type,
+ double image_bpp) {
size_ = size;
time_ = time;
type_ = type;
+ image_bpp_ = image_bpp;
}
ContentfulPaint::ContentfulPaint(bool in_main_frame, uint32_t type)
: text_(ContentfulPaintTimingInfo::LargestContentTextOrImage::kText,
@@ -281,13 +286,14 @@ void LargestContentfulPaintHandler::RecordMainFrameTiming(
if (IsValid(largest_contentful_paint.largest_text_paint)) {
main_frame_contentful_paint_.Text().Reset(
largest_contentful_paint.largest_text_paint,
- largest_contentful_paint.largest_text_paint_size, 0 /*type*/);
+ largest_contentful_paint.largest_text_paint_size, /*type=*/0,
+ /*image_bpp=*/0.0);
}
if (IsValid(largest_contentful_paint.largest_image_paint)) {
main_frame_contentful_paint_.Image().Reset(
largest_contentful_paint.largest_image_paint,
largest_contentful_paint.largest_image_paint_size,
- largest_contentful_paint.type);
+ largest_contentful_paint.type, largest_contentful_paint.image_bpp);
}
}
diff --git a/chromium/components/page_load_metrics/browser/observers/core/largest_contentful_paint_handler.h b/chromium/components/page_load_metrics/browser/observers/core/largest_contentful_paint_handler.h
index a6481cc0c58..9d47a27c3aa 100644
--- a/chromium/components/page_load_metrics/browser/observers/core/largest_contentful_paint_handler.h
+++ b/chromium/components/page_load_metrics/browser/observers/core/largest_contentful_paint_handler.h
@@ -32,25 +32,27 @@ class ContentfulPaintTimingInfo {
kMaxValue = kText,
};
- explicit ContentfulPaintTimingInfo(
- LargestContentTextOrImage largest_content_type,
- bool in_main_frame,
- blink::LargestContentfulPaintTypeMask type);
- explicit ContentfulPaintTimingInfo(
+ ContentfulPaintTimingInfo(LargestContentTextOrImage largest_content_type,
+ bool in_main_frame,
+ blink::LargestContentfulPaintTypeMask type);
+ ContentfulPaintTimingInfo(
const absl::optional<base::TimeDelta>&,
const uint64_t& size,
const LargestContentTextOrImage largest_content_type,
+ double image_bpp,
bool in_main_frame,
blink::LargestContentfulPaintTypeMask type);
ContentfulPaintTimingInfo(const ContentfulPaintTimingInfo& other);
void Reset(const absl::optional<base::TimeDelta>&,
const uint64_t& size,
- blink::LargestContentfulPaintTypeMask type);
+ blink::LargestContentfulPaintTypeMask type,
+ double image_bpp);
absl::optional<base::TimeDelta> Time() const { return time_; }
bool InMainFrame() const { return in_main_frame_; }
blink::LargestContentfulPaintTypeMask Type() const { return type_; }
uint64_t Size() const { return size_; }
LargestContentTextOrImage TextOrImage() const { return text_or_image_; }
+ double ImageBPP() const { return image_bpp_; }
// Returns true iff this object does not represent any paint.
bool Empty() const {
@@ -75,6 +77,7 @@ class ContentfulPaintTimingInfo {
uint64_t size_;
LargestContentTextOrImage text_or_image_;
blink::LargestContentfulPaintTypeMask type_ = 0;
+ double image_bpp_ = 0.0;
bool in_main_frame_;
};
diff --git a/chromium/components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer.cc b/chromium/components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer.cc
index fee77fd9eb5..33b80c53029 100644
--- a/chromium/components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer.cc
+++ b/chromium/components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer.cc
@@ -273,9 +273,6 @@ const char kHistogramLoadTypeParseStartNewNavigation[] =
const char kHistogramFirstForeground[] =
"PageLoad.PageTiming.NavigationToFirstForeground";
-const char kHistogramFailedProvisionalLoad[] =
- "PageLoad.PageTiming.NavigationToFailedProvisionalLoad";
-
const char kHistogramUserGestureNavigationToForwardBack[] =
"PageLoad.PageTiming.ForegroundDuration.PageEndReason."
"ForwardBackNavigation.UserGesture";
@@ -348,13 +345,6 @@ const char kHistogramLoadTypeNetworkBytesNewNavigation[] =
const char kHistogramLoadTypeCacheBytesNewNavigation[] =
"PageLoad.Experimental.Bytes.Cache2.LoadType.NewNavigation";
-const char kHistogramTotalCompletedResources[] =
- "PageLoad.Experimental.CompletedResources.Total2";
-const char kHistogramNetworkCompletedResources[] =
- "PageLoad.Experimental.CompletedResources.Network";
-const char kHistogramCacheCompletedResources[] =
- "PageLoad.Experimental.CompletedResources.Cache2";
-
const char kHistogramInputToNavigation[] =
"PageLoad.Experimental.InputTiming.InputToNavigationStart";
const char kBackgroundHistogramInputToNavigation[] =
@@ -429,8 +419,6 @@ const char kHistogramMemoryUpdateReceived[] =
UmaPageLoadMetricsObserver::UmaPageLoadMetricsObserver()
: transition_(ui::PAGE_TRANSITION_LINK),
was_no_store_main_resource_(false),
- num_cache_resources_(0),
- num_network_resources_(0),
cache_bytes_(0),
network_bytes_(0),
network_bytes_including_headers_(0),
@@ -832,17 +820,6 @@ UmaPageLoadMetricsObserver::FlushMetricsOnAppEnterBackground(
void UmaPageLoadMetricsObserver::OnFailedProvisionalLoad(
const page_load_metrics::FailedProvisionalLoadInfo& failed_load_info) {
- // Only handle actual failures; provisional loads that failed due to another
- // committed load or due to user action are recorded in
- // AbortsPageLoadMetricsObserver.
- if (failed_load_info.error != net::OK &&
- failed_load_info.error != net::ERR_ABORTED) {
- if (page_load_metrics::WasStartedInForegroundOptionalEventInForeground(
- failed_load_info.time_to_failed_provisional_load, GetDelegate())) {
- PAGE_LOAD_HISTOGRAM(internal::kHistogramFailedProvisionalLoad,
- failed_load_info.time_to_failed_provisional_load);
- }
- }
// Provide an empty PageLoadTiming, since we don't have any timing metrics
// for failed provisional loads.
RecordForegroundDurationHistograms(page_load_metrics::mojom::PageLoadTiming(),
@@ -942,10 +919,8 @@ void UmaPageLoadMetricsObserver::OnResourceDataUseObserved(
if (resource->cache_type ==
page_load_metrics::mojom::CacheType::kNotCached) {
network_bytes_ += resource->encoded_body_length;
- num_network_resources_++;
} else {
cache_bytes_ += resource->encoded_body_length;
- num_cache_resources_++;
}
}
network_bytes_including_headers_ += resource->delta_bytes;
@@ -1313,14 +1288,6 @@ void UmaPageLoadMetricsObserver::RecordByteAndResourceHistograms(
NOTREACHED();
break;
}
-
- PAGE_RESOURCE_COUNT_HISTOGRAM(internal::kHistogramNetworkCompletedResources,
- num_network_resources_);
- PAGE_RESOURCE_COUNT_HISTOGRAM(internal::kHistogramCacheCompletedResources,
- num_cache_resources_);
- PAGE_RESOURCE_COUNT_HISTOGRAM(internal::kHistogramTotalCompletedResources,
- num_cache_resources_ + num_network_resources_);
-
click_tracker_.RecordClickBurst(GetDelegate().GetPageUkmSourceId());
}
diff --git a/chromium/components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer.h b/chromium/components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer.h
index 015735ce91c..0fa04ed97e4 100644
--- a/chromium/components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer.h
+++ b/chromium/components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer.h
@@ -77,8 +77,6 @@ extern const char kHistogramLoadTypeParseStartReload[];
extern const char kHistogramLoadTypeParseStartForwardBack[];
extern const char kHistogramLoadTypeParseStartNewNavigation[];
-extern const char kHistogramFailedProvisionalLoad[];
-
extern const char kHistogramUserGestureNavigationToForwardBack[];
extern const char kHistogramPageTimingForegroundDuration[];
@@ -118,10 +116,6 @@ extern const char kHistogramLoadTypeTotalBytesNewNavigation[];
extern const char kHistogramLoadTypeNetworkBytesNewNavigation[];
extern const char kHistogramLoadTypeCacheBytesNewNavigation[];
-extern const char kHistogramTotalCompletedResources[];
-extern const char kHistogramNetworkCompletedResources[];
-extern const char kHistogramCacheCompletedResources[];
-
extern const char kHistogramInputToNavigation[];
extern const char kBackgroundHistogramInputToNavigation[];
extern const char kHistogramInputToNavigationLinkClick[];
@@ -280,10 +274,6 @@ class UmaPageLoadMetricsObserver
ui::PageTransition transition_;
bool was_no_store_main_resource_;
- // Number of complete resources loaded by the page.
- int num_cache_resources_;
- int num_network_resources_;
-
// The number of body (not header) prefilter bytes consumed by completed
// requests for the page.
int64_t cache_bytes_;
diff --git a/chromium/components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer_unittest.cc b/chromium/components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer_unittest.cc
index 28a0dd06829..17b0d3e0ef0 100644
--- a/chromium/components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer_unittest.cc
+++ b/chromium/components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer_unittest.cc
@@ -397,8 +397,6 @@ TEST_F(UmaPageLoadMetricsObserverTest, FailedProvisionalLoad) {
tester()->histogram_tester().ExpectTotalCount(internal::kHistogramLoad, 0);
tester()->histogram_tester().ExpectTotalCount(
internal::kHistogramFirstImagePaint, 0);
- tester()->histogram_tester().ExpectTotalCount(
- internal::kHistogramFailedProvisionalLoad, 1);
tester()->histogram_tester().ExpectTotalCount(
internal::kHistogramPageTimingForegroundDuration, 0);
@@ -406,18 +404,6 @@ TEST_F(UmaPageLoadMetricsObserverTest, FailedProvisionalLoad) {
internal::kHistogramPageTimingForegroundDurationNoCommit, 1);
}
-TEST_F(UmaPageLoadMetricsObserverTest, FailedBackgroundProvisionalLoad) {
- // Test that failed provisional event does not get logged in the
- // histogram if it happened in the background
- GURL url(kDefaultTestUrl);
- web_contents()->WasHidden();
- content::NavigationSimulator::NavigateAndFailFromDocument(
- url, net::ERR_TIMED_OUT, main_rfh());
-
- tester()->histogram_tester().ExpectTotalCount(
- internal::kHistogramFailedProvisionalLoad, 0);
-}
-
TEST_F(UmaPageLoadMetricsObserverTest, Reload) {
page_load_metrics::mojom::PageLoadTiming timing;
page_load_metrics::InitPageLoadTimingForTest(&timing);
@@ -687,12 +673,6 @@ TEST_F(UmaPageLoadMetricsObserverTest, BytesAndResourcesCounted) {
internal::kHistogramPageLoadCacheBytes, 1);
tester()->histogram_tester().ExpectTotalCount(
internal::kHistogramPageLoadNetworkBytesIncludingHeaders, 1);
- tester()->histogram_tester().ExpectTotalCount(
- internal::kHistogramTotalCompletedResources, 1);
- tester()->histogram_tester().ExpectTotalCount(
- internal::kHistogramNetworkCompletedResources, 1);
- tester()->histogram_tester().ExpectTotalCount(
- internal::kHistogramCacheCompletedResources, 1);
}
TEST_F(UmaPageLoadMetricsObserverTest, CpuUsageCounted) {
@@ -1180,32 +1160,7 @@ TEST_F(UmaPageLoadMetricsObserverTest,
TestAllFramesLCP(990, LargestContentTextOrImage::kText);
}
-TEST_F(UmaPageLoadMetricsObserverTest,
- NormalizedResponsivenessMetricsWithoutSendingAllLatencies) {
- page_load_metrics::mojom::InputTiming input_timing;
- input_timing.num_interactions = 3;
- input_timing.max_event_durations =
- UserInteractionLatencies::NewWorstInteractionLatency(
- base::Milliseconds(21));
- input_timing.total_event_durations =
- UserInteractionLatencies::NewWorstInteractionLatency(
- base::Milliseconds(56));
- NavigateAndCommit(GURL(kDefaultTestUrl));
- tester()->SimulateInputTimingUpdate(input_timing);
- // Navigate again to force histogram recording.
- NavigateAndCommit(GURL(kDefaultTestUrl2));
- EXPECT_THAT(
- tester()->histogram_tester().GetAllSamples(
- internal::kHistogramWorstUserInteractionLatencyMaxEventDuration),
- testing::ElementsAre(base::Bucket(21, 1)));
- EXPECT_THAT(
- tester()->histogram_tester().GetAllSamples(
- internal::kHistogramWorstUserInteractionLatencyTotalEventDuration),
- testing::ElementsAre(base::Bucket(50, 1)));
-}
-
-TEST_F(UmaPageLoadMetricsObserverTest,
- NormalizedResponsivenessMetricsWithSendingAllLatencies) {
+TEST_F(UmaPageLoadMetricsObserverTest, NormalizedResponsivenessMetrics) {
// Flip the flag.
base::test::ScopedFeatureList feature_list;
feature_list.InitAndEnableFeature(
diff --git a/chromium/components/page_load_metrics/browser/observers/layout_page_load_metrics_observer.cc b/chromium/components/page_load_metrics/browser/observers/layout_page_load_metrics_observer.cc
index 75b477fc718..bfb9c40ea8b 100644
--- a/chromium/components/page_load_metrics/browser/observers/layout_page_load_metrics_observer.cc
+++ b/chromium/components/page_load_metrics/browser/observers/layout_page_load_metrics_observer.cc
@@ -15,13 +15,6 @@ void Record(const PageRenderData& data) {
base::UmaHistogramPercentageObsoleteDoNotUse(
"Blink.Layout.NGRatio.Blocks",
data.ng_layout_block_count * 100 / data.all_layout_block_count);
-
- base::UmaHistogramPercentage(
- "Blink.Layout.NGRatio.FlexboxBlocks",
- data.flexbox_ng_layout_block_count * 100 / data.all_layout_block_count);
- base::UmaHistogramPercentage(
- "Blink.Layout.NGRatio.GridBlocks",
- data.grid_ng_layout_block_count * 100 / data.all_layout_block_count);
}
if (data.all_layout_call_count) {
base::UmaHistogramPercentageObsoleteDoNotUse(
diff --git a/chromium/components/page_load_metrics/browser/observers/page_load_metrics_observer_tester.cc b/chromium/components/page_load_metrics/browser/observers/page_load_metrics_observer_tester.cc
index 3419622595e..650d5395a9f 100644
--- a/chromium/components/page_load_metrics/browser/observers/page_load_metrics_observer_tester.cc
+++ b/chromium/components/page_load_metrics/browser/observers/page_load_metrics_observer_tester.cc
@@ -69,6 +69,10 @@ class TestPageLoadMetricsEmbedderInterface
bool IsExtensionUrl(const GURL& url) override { return false; }
+ bool IsSidePanel(content::WebContents* web_contents) override {
+ return false;
+ }
+
page_load_metrics::PageLoadMetricsMemoryTracker*
GetMemoryTrackerForBrowserContext(
content::BrowserContext* browser_context) override {
diff --git a/chromium/components/page_load_metrics/browser/observers/prerender_page_load_metrics_observer.cc b/chromium/components/page_load_metrics/browser/observers/prerender_page_load_metrics_observer.cc
index ea6e9bac852..042893705e5 100644
--- a/chromium/components/page_load_metrics/browser/observers/prerender_page_load_metrics_observer.cc
+++ b/chromium/components/page_load_metrics/browser/observers/prerender_page_load_metrics_observer.cc
@@ -180,7 +180,7 @@ std::string PrerenderPageLoadMetricsObserver::AppendSuffix(
return histogram_name + ".SpeculationRule";
case content::PrerenderTriggerType::kEmbedder:
DCHECK(!embedder_histogram_suffix_.empty());
- return histogram_name + ".Embedder" + embedder_histogram_suffix_;
+ return histogram_name + ".Embedder_" + embedder_histogram_suffix_;
}
NOTREACHED();
}
diff --git a/chromium/components/page_load_metrics/browser/observers/use_counter/ukm_features.cc b/chromium/components/page_load_metrics/browser/observers/use_counter/ukm_features.cc
index 303a43c301b..5f60d6911ce 100644
--- a/chromium/components/page_load_metrics/browser/observers/use_counter/ukm_features.cc
+++ b/chromium/components/page_load_metrics/browser/observers/use_counter/ukm_features.cc
@@ -205,7 +205,6 @@ UseCounterPageLoadMetricsObserver::GetAllowedUkmFeatures() {
WebFeature::kSerialPortOpen,
WebFeature::kHidRequestDevice,
WebFeature::kHidDeviceOpen,
- WebFeature::kCrossOriginWasmModuleSharing,
WebFeature::kControlledNonBlobURLWorkerWillBeUncontrolled,
WebFeature::kSameSiteCookieInclusionChangedByCrossSiteRedirect,
WebFeature::
diff --git a/chromium/components/page_load_metrics/browser/page_load_metrics_embedder_base.cc b/chromium/components/page_load_metrics/browser/page_load_metrics_embedder_base.cc
index d067aa026c1..74dfabafe63 100644
--- a/chromium/components/page_load_metrics/browser/page_load_metrics_embedder_base.cc
+++ b/chromium/components/page_load_metrics/browser/page_load_metrics_embedder_base.cc
@@ -24,7 +24,7 @@ PageLoadMetricsEmbedderBase::~PageLoadMetricsEmbedderBase() = default;
void PageLoadMetricsEmbedderBase::RegisterObservers(PageLoadTracker* tracker) {
// Register observers used by all embedders
- if (!IsNoStatePrefetch(web_contents())) {
+ if (!IsNoStatePrefetch(web_contents()) && !IsSidePanel(web_contents())) {
tracker->AddObserver(
std::make_unique<BackForwardCachePageLoadMetricsObserver>());
tracker->AddObserver(std::make_unique<UmaPageLoadMetricsObserver>());
diff --git a/chromium/components/page_load_metrics/browser/page_load_metrics_embedder_interface.h b/chromium/components/page_load_metrics/browser/page_load_metrics_embedder_interface.h
index e1f756742bd..e04fc8cd2cb 100644
--- a/chromium/components/page_load_metrics/browser/page_load_metrics_embedder_interface.h
+++ b/chromium/components/page_load_metrics/browser/page_load_metrics_embedder_interface.h
@@ -33,6 +33,7 @@ class PageLoadMetricsEmbedderInterface {
virtual std::unique_ptr<base::OneShotTimer> CreateTimer() = 0;
virtual bool IsNoStatePrefetch(content::WebContents* web_contents) = 0;
virtual bool IsExtensionUrl(const GURL& url) = 0;
+ virtual bool IsSidePanel(content::WebContents* web_contents) = 0;
// Returns the PageLoadMetricsMemoryTracker for the given BrowserContext if
// tracking is enabled.
diff --git a/chromium/components/page_load_metrics/browser/page_load_metrics_memory_tracker_unittest.cc b/chromium/components/page_load_metrics/browser/page_load_metrics_memory_tracker_unittest.cc
index 30757f5327a..a4f90c64471 100644
--- a/chromium/components/page_load_metrics/browser/page_load_metrics_memory_tracker_unittest.cc
+++ b/chromium/components/page_load_metrics/browser/page_load_metrics_memory_tracker_unittest.cc
@@ -49,6 +49,9 @@ class TestPageLoadMetricsEmbedder
return false;
}
bool IsExtensionUrl(const GURL& url) override { return false; }
+ bool IsSidePanel(content::WebContents* web_contents) override {
+ return false;
+ }
page_load_metrics::PageLoadMetricsMemoryTracker*
GetMemoryTrackerForBrowserContext(
diff --git a/chromium/components/page_load_metrics/browser/page_load_metrics_observer.h b/chromium/components/page_load_metrics/browser/page_load_metrics_observer.h
index 424d79c34a6..cc121a9525d 100644
--- a/chromium/components/page_load_metrics/browser/page_load_metrics_observer.h
+++ b/chromium/components/page_load_metrics/browser/page_load_metrics_observer.h
@@ -135,10 +135,6 @@ struct PageRenderData {
// How many times LayoutNG-based LayoutObject::UpdateLayout() is called.
uint64_t ng_layout_call_count = 0;
-
- uint64_t flexbox_ng_layout_block_count = 0;
-
- uint64_t grid_ng_layout_block_count = 0;
};
// Information related to layout shift normalization for different strategies.
diff --git a/chromium/components/page_load_metrics/browser/page_load_metrics_test_waiter.cc b/chromium/components/page_load_metrics/browser/page_load_metrics_test_waiter.cc
index 723efe838e1..ac05674c4a0 100644
--- a/chromium/components/page_load_metrics/browser/page_load_metrics_test_waiter.cc
+++ b/chromium/components/page_load_metrics/browser/page_load_metrics_test_waiter.cc
@@ -272,10 +272,6 @@ PageLoadMetricsTestWaiter::GetMatchedBits(
matched_bits.Set(TimingField::kFirstContentfulPaint);
if (timing.paint_timing->first_meaningful_paint)
matched_bits.Set(TimingField::kFirstMeaningfulPaint);
- if (metadata.behavior_flags &
- blink::LoadingBehaviorFlag::kLoadingBehaviorDocumentWriteBlockReload) {
- matched_bits.Set(TimingField::kDocumentWriteBlockReload);
- }
if (timing.paint_timing->largest_contentful_paint->largest_image_paint ||
timing.paint_timing->largest_contentful_paint->largest_text_paint) {
matched_bits.Set(TimingField::kLargestContentfulPaint);
diff --git a/chromium/components/page_load_metrics/browser/page_load_metrics_test_waiter.h b/chromium/components/page_load_metrics/browser/page_load_metrics_test_waiter.h
index 9ac078f58b9..b42b42d0e15 100644
--- a/chromium/components/page_load_metrics/browser/page_load_metrics_test_waiter.h
+++ b/chromium/components/page_load_metrics/browser/page_load_metrics_test_waiter.h
@@ -26,6 +26,7 @@ class PageLoadMetricsTestWaiter
kFirstPaint = 1 << 0,
kFirstContentfulPaint = 1 << 1,
kFirstMeaningfulPaint = 1 << 2,
+ // kDocumentWriteBlockReload is deprecated.
kDocumentWriteBlockReload = 1 << 3,
kLoadEvent = 1 << 4,
// kLoadTimingInfo waits for main frame timing info only.
diff --git a/chromium/components/page_load_metrics/browser/page_load_metrics_update_dispatcher.cc b/chromium/components/page_load_metrics/browser/page_load_metrics_update_dispatcher.cc
index e94f12ed591..b7ac0bca1a4 100644
--- a/chromium/components/page_load_metrics/browser/page_load_metrics_update_dispatcher.cc
+++ b/chromium/components/page_load_metrics/browser/page_load_metrics_update_dispatcher.cc
@@ -27,10 +27,6 @@ namespace internal {
const char kPageLoadTimingStatus[] = "PageLoad.Internal.PageLoadTimingStatus";
const char kPageLoadTimingDispatchStatus[] =
"PageLoad.Internal.PageLoadTimingStatus.AtTimingCallbackDispatch";
-const char kHistogramOutOfOrderTiming[] =
- "PageLoad.Internal.OutOfOrderInterFrameTiming";
-const char kHistogramOutOfOrderTimingBuffered[] =
- "PageLoad.Internal.OutOfOrderInterFrameTiming.AfterBuffering";
} // namespace internal
@@ -237,19 +233,6 @@ internal::PageLoadTimingStatus IsValidPageLoadTiming(
return internal::VALID;
}
-// If the updated value has an earlier time than the current value, log so we
-// can keep track of how often this happens.
-void LogIfOutOfOrderTiming(const absl::optional<base::TimeDelta>& current,
- const absl::optional<base::TimeDelta>& update) {
- if (!current || !update)
- return;
-
- if (update < current) {
- PAGE_LOAD_HISTOGRAM(internal::kHistogramOutOfOrderTimingBuffered,
- current.value() - update.value());
- }
-}
-
// PageLoadTimingMerger merges timing values received from different frames
// together.
class PageLoadTimingMerger {
@@ -318,8 +301,6 @@ class PageLoadTimingMerger {
// to happen occasionally, as inter-frame updates can arrive out of order.
// Record a histogram to track how frequently it happens, along with the
// magnitude of the delta.
- PAGE_LOAD_HISTOGRAM(internal::kHistogramOutOfOrderTiming,
- inout_existing_value->value() - candidate_new_value);
} else {
// We only want to set this for new updates. If there's already a value,
// then the window during which we buffer updates is over. We'll still
@@ -801,10 +782,6 @@ void PageLoadMetricsUpdateDispatcher::UpdatePageRenderData(
render_data.all_layout_call_count_delta;
page_render_data_.ng_layout_call_count +=
render_data.ng_layout_call_count_delta;
- page_render_data_.flexbox_ng_layout_block_count +=
- render_data.flexbox_ng_layout_block_count_delta;
- page_render_data_.grid_ng_layout_block_count +=
- render_data.grid_ng_layout_block_count_delta;
}
void PageLoadMetricsUpdateDispatcher::UpdateMainFrameRenderData(
@@ -823,10 +800,6 @@ void PageLoadMetricsUpdateDispatcher::UpdateMainFrameRenderData(
render_data.ng_layout_block_count_delta;
main_frame_render_data_.all_layout_call_count +=
render_data.all_layout_call_count_delta;
- main_frame_render_data_.flexbox_ng_layout_block_count +=
- render_data.flexbox_ng_layout_block_count_delta;
- page_render_data_.grid_ng_layout_block_count +=
- render_data.grid_ng_layout_block_count_delta;
}
void PageLoadMetricsUpdateDispatcher::OnSubFrameRenderDataChanged(
@@ -884,15 +857,6 @@ void PageLoadMetricsUpdateDispatcher::DispatchTimingUpdates() {
if (current_merged_page_timing_->Equals(*pending_merged_page_timing_))
return;
- LogIfOutOfOrderTiming(current_merged_page_timing_->paint_timing->first_paint,
- pending_merged_page_timing_->paint_timing->first_paint);
- LogIfOutOfOrderTiming(
- current_merged_page_timing_->paint_timing->first_image_paint,
- pending_merged_page_timing_->paint_timing->first_image_paint);
- LogIfOutOfOrderTiming(
- current_merged_page_timing_->paint_timing->first_contentful_paint,
- pending_merged_page_timing_->paint_timing->first_contentful_paint);
-
current_merged_page_timing_ = pending_merged_page_timing_->Clone();
internal::PageLoadTimingStatus status =
diff --git a/chromium/components/page_load_metrics/browser/page_load_metrics_update_dispatcher.h b/chromium/components/page_load_metrics/browser/page_load_metrics_update_dispatcher.h
index 0cabcbbaae5..5e587fa463e 100644
--- a/chromium/components/page_load_metrics/browser/page_load_metrics_update_dispatcher.h
+++ b/chromium/components/page_load_metrics/browser/page_load_metrics_update_dispatcher.h
@@ -97,8 +97,6 @@ enum PageLoadTimingStatus {
};
extern const char kPageLoadTimingStatus[];
-extern const char kHistogramOutOfOrderTiming[];
-extern const char kHistogramOutOfOrderTimingBuffered[];
} // namespace internal
diff --git a/chromium/components/page_load_metrics/browser/page_load_tracker.cc b/chromium/components/page_load_metrics/browser/page_load_tracker.cc
index c8f308ece92..57918aa1fc1 100644
--- a/chromium/components/page_load_metrics/browser/page_load_tracker.cc
+++ b/chromium/components/page_load_metrics/browser/page_load_tracker.cc
@@ -52,25 +52,10 @@ namespace page_load_metrics {
namespace internal {
const char kErrorEvents[] = "PageLoad.Internal.ErrorCode";
-const char kAbortChainSizeReload[] =
- "PageLoad.Internal.ProvisionalAbortChainSize.Reload";
-const char kAbortChainSizeForwardBack[] =
- "PageLoad.Internal.ProvisionalAbortChainSize.ForwardBack";
-const char kAbortChainSizeNewNavigation[] =
- "PageLoad.Internal.ProvisionalAbortChainSize.NewNavigation";
-const char kAbortChainSizeSameURL[] =
- "PageLoad.Internal.ProvisionalAbortChainSize.SameURL";
-const char kAbortChainSizeNoCommit[] =
- "PageLoad.Internal.ProvisionalAbortChainSize.NoCommit";
-const char kClientRedirectFirstPaintToNavigation[] =
- "PageLoad.Internal.ClientRedirect.FirstPaintToNavigation";
-const char kClientRedirectWithoutPaint[] =
- "PageLoad.Internal.ClientRedirect.NavigationWithoutPaint";
const char kPageLoadCompletedAfterAppBackground[] =
"PageLoad.Internal.PageLoadCompleted.AfterAppBackground";
const char kPageLoadStartedInForeground[] =
"PageLoad.Internal.NavigationStartedInForeground";
-const char kPageLoadPrerender[] = "PageLoad.Internal.Prerender";
const char kPageLoadPrerender2Event[] = "PageLoad.Internal.Prerender2.Event";
} // namespace internal
@@ -100,13 +85,6 @@ PageEndReason EndReasonForPageTransition(ui::PageTransition transition) {
return END_OTHER;
}
-void LogAbortChainSameURLHistogram(int aborted_chain_size_same_url) {
- if (aborted_chain_size_same_url > 0) {
- UMA_HISTOGRAM_COUNTS_1M(internal::kAbortChainSizeSameURL,
- aborted_chain_size_same_url);
- }
-}
-
bool IsNavigationUserInitiated(content::NavigationHandle* handle) {
// TODO(crbug.com/617904): Browser initiated navigations should have
// HasUserGesture() set to true. In the meantime, we consider all
@@ -230,9 +208,7 @@ PageLoadTracker::PageLoadTracker(
const GURL& currently_committed_url,
bool is_first_navigation_in_web_contents,
content::NavigationHandle* navigation_handle,
- UserInitiatedInfo user_initiated_info,
- int aborted_chain_size,
- int aborted_chain_size_same_url)
+ UserInitiatedInfo user_initiated_info)
: did_stop_tracking_(false),
app_entered_background_(false),
navigation_start_(navigation_handle->NavigationStart()),
@@ -245,8 +221,6 @@ PageLoadTracker::PageLoadTracker(
started_in_foreground_(in_foreground),
last_dispatched_merged_page_timing_(CreatePageLoadTiming()),
user_initiated_info_(user_initiated_info),
- aborted_chain_size_(aborted_chain_size),
- aborted_chain_size_same_url_(aborted_chain_size_same_url),
embedder_interface_(embedder_interface),
metrics_update_dispatcher_(this, navigation_handle, embedder_interface),
web_contents_(navigation_handle->GetWebContents()),
@@ -270,9 +244,6 @@ PageLoadTracker::PageLoadTracker(
UMA_HISTOGRAM_BOOLEAN(internal::kPageLoadStartedInForeground,
started_in_foreground_);
- if (embedder_interface_->IsNoStatePrefetch(
- navigation_handle->GetWebContents()))
- UMA_HISTOGRAM_BOOLEAN(internal::kPageLoadPrerender, true);
}
PageLoadTracker::~PageLoadTracker() {
@@ -297,14 +268,6 @@ PageLoadTracker::~PageLoadTracker() {
if (!did_commit_) {
if (!failed_provisional_load_info_)
RecordInternalError(ERR_NO_COMMIT_OR_FAILED_PROVISIONAL_LOAD);
-
- // Don't include any aborts that resulted in a new navigation, as the chain
- // length will be included in the aborter PageLoadTracker.
- if (page_end_reason_ != END_RELOAD &&
- page_end_reason_ != END_FORWARD_BACK &&
- page_end_reason_ != END_NEW_NAVIGATION) {
- LogAbortChainHistograms(nullptr);
- }
} else if (page_load_metrics::IsEmpty(metrics_update_dispatcher_.timing())) {
RecordInternalError(ERR_NO_IPCS_RECEIVED);
}
@@ -318,57 +281,6 @@ PageLoadTracker::~PageLoadTracker() {
}
}
-void PageLoadTracker::LogAbortChainHistograms(
- content::NavigationHandle* final_navigation) {
- if (aborted_chain_size_ == 0)
- return;
- // Note that this could be broken out by this navigation's abort type, if more
- // granularity is needed. Add one to the chain size to count the current
- // navigation. In the other cases, the current navigation is the final
- // navigation (which commits).
- if (!final_navigation) {
- UMA_HISTOGRAM_COUNTS_1M(internal::kAbortChainSizeNoCommit,
- aborted_chain_size_ + 1);
- LogAbortChainSameURLHistogram(aborted_chain_size_same_url_ + 1);
- return;
- }
-
- // The following is only executed for committing trackers.
- DCHECK(did_commit_);
-
- // Note that histograms could be separated out by this commit's transition
- // type, but for simplicity they will all be bucketed together.
- LogAbortChainSameURLHistogram(aborted_chain_size_same_url_);
-
- ui::PageTransition committed_transition =
- final_navigation->GetPageTransition();
- switch (EndReasonForPageTransition(committed_transition)) {
- case END_RELOAD:
- UMA_HISTOGRAM_COUNTS_1M(internal::kAbortChainSizeReload,
- aborted_chain_size_);
- return;
- case END_FORWARD_BACK:
- UMA_HISTOGRAM_COUNTS_1M(internal::kAbortChainSizeForwardBack,
- aborted_chain_size_);
- return;
- // TODO(csharrison): Refactor this code so it is based on the WillStart*
- // code path instead of the committed load code path. Then, for every abort
- // chain, log a histogram of the counts of each of these metrics. For now,
- // merge client redirects with new navigations, which was (basically) the
- // previous behavior.
- case END_CLIENT_REDIRECT:
- case END_NEW_NAVIGATION:
- UMA_HISTOGRAM_COUNTS_1M(internal::kAbortChainSizeNewNavigation,
- aborted_chain_size_);
- return;
- default:
- NOTREACHED()
- << "LogAbortChainHistograms received unexpected ui::PageTransition: "
- << committed_transition;
- return;
- }
-}
-
void PageLoadTracker::PageHidden() {
// Only log the first time we background in a given page load.
if (!first_background_time_.has_value() ||
@@ -459,7 +371,6 @@ void PageLoadTracker::Commit(content::NavigationHandle* navigation_handle) {
INVOKE_AND_PRUNE_OBSERVERS(observers_, ShouldObserveMimeType, mime_type);
INVOKE_AND_PRUNE_OBSERVERS(observers_, OnCommit, navigation_handle,
source_id_);
- LogAbortChainHistograms(navigation_handle);
}
void PageLoadTracker::DidActivatePrerenderedPage(
@@ -544,23 +455,6 @@ void PageLoadTracker::FlushMetricsOnAppEnterBackground() {
metrics_update_dispatcher_.timing());
}
-void PageLoadTracker::NotifyClientRedirectTo(
- content::NavigationHandle* destination) {
- if (metrics_update_dispatcher_.timing().paint_timing->first_paint) {
- base::TimeTicks first_paint_time =
- navigation_start() +
- metrics_update_dispatcher_.timing().paint_timing->first_paint.value();
- base::TimeDelta first_paint_to_navigation;
- if (destination->NavigationStart() > first_paint_time)
- first_paint_to_navigation =
- destination->NavigationStart() - first_paint_time;
- PAGE_LOAD_HISTOGRAM(internal::kClientRedirectFirstPaintToNavigation,
- first_paint_to_navigation);
- } else {
- UMA_HISTOGRAM_BOOLEAN(internal::kClientRedirectWithoutPaint, true);
- }
-}
-
void PageLoadTracker::OnLoadedResource(
const ExtraRequestCompleteInfo& extra_request_complete_info) {
for (const auto& observer : observers_) {
@@ -704,14 +598,6 @@ bool PageLoadTracker::IsLikelyProvisionalAbort(
(abort_cause_time - page_end_time_).InMilliseconds() < 100;
}
-bool PageLoadTracker::MatchesOriginalNavigation(
- content::NavigationHandle* navigation_handle) {
- // Neither navigation should have committed.
- DCHECK(!navigation_handle->HasCommitted());
- DCHECK(!did_commit_);
- return navigation_handle->GetURL() == start_url_;
-}
-
void PageLoadTracker::UpdatePageEndInternal(
PageEndReason page_end_reason,
UserInitiatedInfo user_initiated_info,
diff --git a/chromium/components/page_load_metrics/browser/page_load_tracker.h b/chromium/components/page_load_metrics/browser/page_load_tracker.h
index 41921e1f21e..267421d994e 100644
--- a/chromium/components/page_load_metrics/browser/page_load_tracker.h
+++ b/chromium/components/page_load_metrics/browser/page_load_tracker.h
@@ -52,11 +52,6 @@ enum class PageLoadPrerenderEvent {
};
extern const char kErrorEvents[];
-extern const char kAbortChainSizeReload[];
-extern const char kAbortChainSizeForwardBack[];
-extern const char kAbortChainSizeNewNavigation[];
-extern const char kAbortChainSizeNoCommit[];
-extern const char kAbortChainSizeSameURL[];
extern const char kPageLoadCompletedAfterAppBackground[];
extern const char kPageLoadStartedInForeground[];
extern const char kPageLoadPrerender2Event[];
@@ -166,7 +161,6 @@ enum InternalErrorLoadEvent {
// to access them.
void RecordInternalError(InternalErrorLoadEvent event);
PageEndReason EndReasonForPageTransition(ui::PageTransition transition);
-void LogAbortChainSameURLHistogram(int aborted_chain_size_same_url);
bool IsNavigationUserInitiated(content::NavigationHandle* handle);
// This class tracks a given page load, starting from navigation start /
@@ -185,9 +179,7 @@ class PageLoadTracker : public PageLoadMetricsUpdateDispatcher::Client,
const GURL& currently_committed_url,
bool is_first_navigation_in_web_contents,
content::NavigationHandle* navigation_handle,
- UserInitiatedInfo user_initiated_info,
- int aborted_chain_size,
- int aborted_chain_size_same_url);
+ UserInitiatedInfo user_initiated_info);
PageLoadTracker(const PageLoadTracker&) = delete;
PageLoadTracker& operator=(const PageLoadTracker&) = delete;
@@ -293,8 +285,6 @@ class PageLoadTracker : public PageLoadMetricsUpdateDispatcher::Client,
visibility_tracker_ = tracker;
}
- void NotifyClientRedirectTo(content::NavigationHandle* destination);
-
void OnLoadedResource(
const ExtraRequestCompleteInfo& extra_request_complete_info);
@@ -324,11 +314,6 @@ class PageLoadTracker : public PageLoadMetricsUpdateDispatcher::Client,
// tracking metrics in DidFinishNavigation.
void StopTracking();
- int aborted_chain_size() const { return aborted_chain_size_; }
- int aborted_chain_size_same_url() const {
- return aborted_chain_size_same_url_;
- }
-
PageEndReason page_end_reason() const { return page_end_reason_; }
base::TimeTicks page_end_time() const { return page_end_time_; }
@@ -357,8 +342,6 @@ class PageLoadTracker : public PageLoadMetricsUpdateDispatcher::Client,
// and is simpler than other feasible methods. See https://goo.gl/WKRG98.
bool IsLikelyProvisionalAbort(base::TimeTicks abort_cause_time) const;
- bool MatchesOriginalNavigation(content::NavigationHandle* navigation_handle);
-
bool did_commit() const { return did_commit_; }
const GURL& url() const { return url_; }
@@ -412,10 +395,6 @@ class PageLoadTracker : public PageLoadMetricsUpdateDispatcher::Client,
UserInitiatedInfo user_initiated_info,
base::TimeTicks timestamp,
bool is_certainly_browser_timestamp);
- // If |final_navigation| is null, then this is an "unparented" abort chain,
- // and represents a sequence of provisional aborts that never ends with a
- // committed load.
- void LogAbortChainHistograms(content::NavigationHandle* final_navigation);
// Given a |time|, returns the duration between |navigation_start_| and
// |time|. |time| must be greater than or equal to |navigation_start_|.
@@ -482,18 +461,6 @@ class PageLoadTracker : public PageLoadMetricsUpdateDispatcher::Client,
// Whether this page load was user initiated.
UserInitiatedInfo user_initiated_info_;
- // This is a subtle member. If a provisional load A gets aborted by
- // provisional load B, which gets aborted by C that eventually commits, then
- // there exists an abort chain of length 2, starting at A's navigation_start.
- // This is useful because it allows histograming abort chain lengths based on
- // what the last load's transition type is. i.e. holding down F-5 to spam
- // reload will produce a long chain with the RELOAD transition.
- const int aborted_chain_size_;
-
- // This member counts consecutive provisional aborts that share a url. It will
- // always be less than or equal to |aborted_chain_size_|.
- const int aborted_chain_size_same_url_;
-
// Keeps track of actively loading resources on the page.
ResourceTracker resource_tracker_;
diff --git a/chromium/components/page_load_metrics/browser/responsiveness_metrics_normalization.h b/chromium/components/page_load_metrics/browser/responsiveness_metrics_normalization.h
index 949afad8517..a59dbd870c1 100644
--- a/chromium/components/page_load_metrics/browser/responsiveness_metrics_normalization.h
+++ b/chromium/components/page_load_metrics/browser/responsiveness_metrics_normalization.h
@@ -5,6 +5,8 @@
#ifndef COMPONENTS_PAGE_LOAD_METRICS_BROWSER_RESPONSIVENESS_METRICS_NORMALIZATION_H_
#define COMPONENTS_PAGE_LOAD_METRICS_BROWSER_RESPONSIVENESS_METRICS_NORMALIZATION_H_
+#include <queue>
+
#include "base/time/time.h"
#include "components/page_load_metrics/common/page_load_metrics.mojom.h"
#include "third_party/blink/public/common/features.h"
diff --git a/chromium/components/page_load_metrics/browser/responsiveness_metrics_normalization_unittest.cc b/chromium/components/page_load_metrics/browser/responsiveness_metrics_normalization_unittest.cc
index 87736715930..7cca9bfcf02 100644
--- a/chromium/components/page_load_metrics/browser/responsiveness_metrics_normalization_unittest.cc
+++ b/chromium/components/page_load_metrics/browser/responsiveness_metrics_normalization_unittest.cc
@@ -36,59 +36,6 @@ class ResponsivenessMetricsNormalizationTest : public testing::Test {
responsiveness_metrics_normalization_;
};
-TEST_F(ResponsivenessMetricsNormalizationTest, OnlySendWorstInteractions) {
- UserInteractionLatenciesPtr max_event_duration1 =
- UserInteractionLatencies::NewWorstInteractionLatency(
- base::Milliseconds(120));
- UserInteractionLatenciesPtr total_event_durations1 =
- UserInteractionLatencies::NewWorstInteractionLatency(
- base::Milliseconds(140));
- AddNewUserInteractions(1, *max_event_duration1, *total_event_durations1);
-
- UserInteractionLatenciesPtr max_event_duration2 =
- UserInteractionLatencies::NewWorstInteractionLatency(
- base::Milliseconds(200));
- UserInteractionLatenciesPtr total_event_durations2 =
- UserInteractionLatencies::NewWorstInteractionLatency(
- base::Milliseconds(250));
- AddNewUserInteractions(2, *max_event_duration2, *total_event_durations2);
-
- UserInteractionLatenciesPtr max_event_duration3 =
- UserInteractionLatencies::NewWorstInteractionLatency(
- base::Milliseconds(70));
- UserInteractionLatenciesPtr total_event_durations3 =
- UserInteractionLatencies::NewWorstInteractionLatency(
- base::Milliseconds(70));
- AddNewUserInteractions(3, *max_event_duration3, *total_event_durations3);
-
- EXPECT_EQ(normalized_responsiveness_metrics().num_user_interactions, 6u);
- // When the flag is disabled, only worst_latency has a meaningful value and
- // other metrics should have default values.
- auto& normalized_max_event_durations =
- normalized_responsiveness_metrics().normalized_max_event_durations;
- EXPECT_EQ(normalized_max_event_durations.worst_latency,
- base::Milliseconds(200));
- EXPECT_EQ(normalized_max_event_durations.worst_latency_over_budget,
- base::Milliseconds(0));
- EXPECT_EQ(normalized_max_event_durations.sum_of_latency_over_budget,
- base::Milliseconds(0));
- EXPECT_EQ(
- normalized_max_event_durations.pseudo_second_worst_latency_over_budget,
- base::Milliseconds(0));
-
- auto& normalized_total_event_durations =
- normalized_responsiveness_metrics().normalized_total_event_durations;
- EXPECT_EQ(normalized_total_event_durations.worst_latency,
- base::Milliseconds(250));
- EXPECT_EQ(normalized_total_event_durations.worst_latency_over_budget,
- base::Milliseconds(0));
- EXPECT_EQ(normalized_total_event_durations.sum_of_latency_over_budget,
- base::Milliseconds(0));
- EXPECT_EQ(
- normalized_total_event_durations.pseudo_second_worst_latency_over_budget,
- base::Milliseconds(0));
-}
-
TEST_F(ResponsivenessMetricsNormalizationTest, SendAllInteractions) {
// Flip the flag to send all user interaction latencies to browser.
base::test::ScopedFeatureList feature_list;
diff --git a/chromium/components/page_load_metrics/browser/test_metrics_web_contents_observer_embedder.cc b/chromium/components/page_load_metrics/browser/test_metrics_web_contents_observer_embedder.cc
index 59be76a05e3..d9852d70c85 100644
--- a/chromium/components/page_load_metrics/browser/test_metrics_web_contents_observer_embedder.cc
+++ b/chromium/components/page_load_metrics/browser/test_metrics_web_contents_observer_embedder.cc
@@ -184,6 +184,11 @@ bool TestMetricsWebContentsObserverEmbedder::IsExtensionUrl(const GURL& url) {
return false;
}
+bool TestMetricsWebContentsObserverEmbedder::IsSidePanel(
+ content::WebContents* web_contents) {
+ return false;
+}
+
PageLoadMetricsMemoryTracker*
TestMetricsWebContentsObserverEmbedder::GetMemoryTrackerForBrowserContext(
content::BrowserContext* browser_context) {
diff --git a/chromium/components/page_load_metrics/browser/test_metrics_web_contents_observer_embedder.h b/chromium/components/page_load_metrics/browser/test_metrics_web_contents_observer_embedder.h
index 3d5d546ae00..5b51cc68b8c 100644
--- a/chromium/components/page_load_metrics/browser/test_metrics_web_contents_observer_embedder.h
+++ b/chromium/components/page_load_metrics/browser/test_metrics_web_contents_observer_embedder.h
@@ -31,6 +31,7 @@ class TestMetricsWebContentsObserverEmbedder
std::unique_ptr<base::OneShotTimer> CreateTimer() override;
bool IsNoStatePrefetch(content::WebContents* web_contents) override;
bool IsExtensionUrl(const GURL& url) override;
+ bool IsSidePanel(content::WebContents* web_contents) override;
PageLoadMetricsMemoryTracker* GetMemoryTrackerForBrowserContext(
content::BrowserContext* browser_context) override;
diff --git a/chromium/components/page_load_metrics/common/page_load_metrics.mojom b/chromium/components/page_load_metrics/common/page_load_metrics.mojom
index dc5f7e3e406..7f2f30f3d5c 100644
--- a/chromium/components/page_load_metrics/common/page_load_metrics.mojom
+++ b/chromium/components/page_load_metrics/common/page_load_metrics.mojom
@@ -40,6 +40,10 @@ struct LargestContentfulPaintTiming {
// These are packed blink::LargestContentfulPaintType enums, indicating
// the largest LCP candidate's type characteristics.
uint32 type;
+
+ // Computed entropy of the page's largest image, calculated as the image file
+ // size, in bits, divided by the image's rendered size, in pixels.
+ double image_bpp;
};
// TimeDeltas below relative to navigation start.
@@ -233,10 +237,6 @@ struct ResourceDataUpdate {
// Whether this resource load has completed.
bool is_complete;
- // Compression ratio estimated from the response headers if data saver was
- // used.
- double data_reduction_proxy_compression_ratio_estimate;
-
// Whether this resource was tagged as an ad in the renderer. This flag can
// be set to true at any point during a resource load. A more recent
// ResourceDataUpdate can have a different flag than the previous update.
@@ -300,12 +300,6 @@ struct FrameRenderDataUpdate {
// How many times LayoutNG-based LayoutObject::UpdateLayout() is called.
uint32 ng_layout_call_count_delta;
- // How many LayoutNGFlexbox instances were created.
- uint32 flexbox_ng_layout_block_count_delta;
-
- // How many LayoutNGGrid instances were created.
- uint32 grid_ng_layout_block_count_delta;
-
// New layout shifts with timestamps.
array<LayoutShift> new_layout_shifts;
};
diff --git a/chromium/components/page_load_metrics/renderer/metrics_render_frame_observer.cc b/chromium/components/page_load_metrics/renderer/metrics_render_frame_observer.cc
index 323a0f9cb31..0156bfa23d2 100644
--- a/chromium/components/page_load_metrics/renderer/metrics_render_frame_observer.cc
+++ b/chromium/components/page_load_metrics/renderer/metrics_render_frame_observer.cc
@@ -150,17 +150,13 @@ void MetricsRenderFrameObserver::DidObserveLayoutShift(
after_input_or_scroll);
}
-void MetricsRenderFrameObserver::DidObserveLayoutNg(
- uint32_t all_block_count,
- uint32_t ng_block_count,
- uint32_t all_call_count,
- uint32_t ng_call_count,
- uint32_t flexbox_ng_block_count,
- uint32_t grid_ng_block_count) {
+void MetricsRenderFrameObserver::DidObserveLayoutNg(uint32_t all_block_count,
+ uint32_t ng_block_count,
+ uint32_t all_call_count,
+ uint32_t ng_call_count) {
if (page_timing_metrics_sender_)
page_timing_metrics_sender_->DidObserveLayoutNg(
- all_block_count, ng_block_count, all_call_count, ng_call_count,
- flexbox_ng_block_count, grid_ng_block_count);
+ all_block_count, ng_block_count, all_call_count, ng_call_count);
}
void MetricsRenderFrameObserver::DidObserveLazyLoadBehavior(
@@ -173,8 +169,7 @@ void MetricsRenderFrameObserver::DidStartResponse(
const GURL& response_url,
int request_id,
const network::mojom::URLResponseHead& response_head,
- network::mojom::RequestDestination request_destination,
- blink::PreviewsState previews_state) {
+ network::mojom::RequestDestination request_destination) {
if (provisional_frame_resource_data_use_ &&
blink::IsRequestDestinationFrame(request_destination)) {
// TODO(rajendrant): This frame request might start before the provisional
@@ -595,6 +590,8 @@ MetricsRenderFrameObserver::Timing MetricsRenderFrameObserver::GetTiming()
: ClampDelta(perf.LargestImagePaint(), start);
timing->paint_timing->largest_contentful_paint->type =
perf.LargestContentfulPaintType();
+ timing->paint_timing->largest_contentful_paint->image_bpp =
+ perf.LargestContentfulPaintImageBPP();
}
if (perf.LargestTextPaintSize() > 0) {
// LargestTextPaint and LargestTextPaintSize should be available at the
diff --git a/chromium/components/page_load_metrics/renderer/metrics_render_frame_observer.h b/chromium/components/page_load_metrics/renderer/metrics_render_frame_observer.h
index c478cfd2c26..dc5644bc799 100644
--- a/chromium/components/page_load_metrics/renderer/metrics_render_frame_observer.h
+++ b/chromium/components/page_load_metrics/renderer/metrics_render_frame_observer.h
@@ -62,16 +62,14 @@ class MetricsRenderFrameObserver
void DidObserveLayoutNg(uint32_t all_block_count,
uint32_t ng_block_count,
uint32_t all_call_count,
- uint32_t ng_call_count,
- uint32_t flexbox_ng_block_count,
- uint32_t grid_ng_block_count) override;
+ uint32_t ng_call_count) override;
void DidObserveLazyLoadBehavior(
blink::WebLocalFrameClient::LazyLoadBehavior lazy_load_behavior) override;
- void DidStartResponse(const GURL& response_url,
- int request_id,
- const network::mojom::URLResponseHead& response_head,
- network::mojom::RequestDestination request_destination,
- blink::PreviewsState previews_state) override;
+ void DidStartResponse(
+ const GURL& response_url,
+ int request_id,
+ const network::mojom::URLResponseHead& response_head,
+ network::mojom::RequestDestination request_destination) override;
void DidReceiveTransferSizeUpdate(int request_id,
int received_data_length) override;
void DidCompleteResponse(
diff --git a/chromium/components/page_load_metrics/renderer/page_resource_data_use.cc b/chromium/components/page_load_metrics/renderer/page_resource_data_use.cc
index 53a47e983c8..8d30de0f202 100644
--- a/chromium/components/page_load_metrics/renderer/page_resource_data_use.cc
+++ b/chromium/components/page_load_metrics/renderer/page_resource_data_use.cc
@@ -4,7 +4,6 @@
#include "components/page_load_metrics/renderer/page_resource_data_use.h"
-#include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h"
#include "services/network/public/cpp/url_loader_completion_status.h"
#include "services/network/public/mojom/url_response_head.mojom.h"
#include "third_party/blink/public/common/loader/resource_type_util.h"
@@ -14,7 +13,6 @@ namespace page_load_metrics {
PageResourceDataUse::PageResourceDataUse()
: resource_id_(-1),
- data_reduction_proxy_compression_ratio_estimate_(1.0),
total_received_bytes_(0),
last_update_bytes_(0),
is_complete_(false),
@@ -37,8 +35,6 @@ void PageResourceDataUse::DidStartResponse(
const network::mojom::URLResponseHead& response_head,
network::mojom::RequestDestination request_destination) {
resource_id_ = resource_id;
- data_reduction_proxy_compression_ratio_estimate_ =
- data_reduction_proxy::EstimateCompressionRatioFromHeaders(&response_head);
proxy_used_ = !response_head.proxy_server.is_direct();
mime_type_ = response_head.mime_type;
@@ -121,8 +117,6 @@ mojom::ResourceDataUpdatePtr PageResourceDataUse::GetResourceDataUpdate() {
resource_data_update->received_data_length = total_received_bytes_;
resource_data_update->delta_bytes = CalculateNewlyReceivedBytes();
resource_data_update->is_complete = is_complete_;
- resource_data_update->data_reduction_proxy_compression_ratio_estimate =
- data_reduction_proxy_compression_ratio_estimate_;
resource_data_update->reported_as_ad_resource = reported_as_ad_resource_;
resource_data_update->is_main_frame_resource = is_main_frame_resource_;
resource_data_update->mime_type = mime_type_;
diff --git a/chromium/components/page_load_metrics/renderer/page_resource_data_use.h b/chromium/components/page_load_metrics/renderer/page_resource_data_use.h
index 0146dee94bb..5b873ed5c80 100644
--- a/chromium/components/page_load_metrics/renderer/page_resource_data_use.h
+++ b/chromium/components/page_load_metrics/renderer/page_resource_data_use.h
@@ -7,7 +7,6 @@
#include "components/page_load_metrics/common/page_load_metrics.mojom.h"
#include "services/network/public/mojom/url_response_head.mojom-forward.h"
-#include "third_party/blink/public/common/loader/previews_state.h"
#include "third_party/blink/public/mojom/loader/resource_load_info.mojom-shared.h"
#include "url/origin.h"
@@ -74,10 +73,6 @@ class PageResourceDataUse {
int resource_id_;
- // Compression ratio estimated from the response headers if data saver was
- // used.
- double data_reduction_proxy_compression_ratio_estimate_;
-
uint64_t total_received_bytes_ = 0;
uint64_t last_update_bytes_ = 0;
uint64_t encoded_body_length_ = 0;
diff --git a/chromium/components/page_load_metrics/renderer/page_timing_metrics_sender.cc b/chromium/components/page_load_metrics/renderer/page_timing_metrics_sender.cc
index e0bb59cf327..1c9f5bf5a5c 100644
--- a/chromium/components/page_load_metrics/renderer/page_timing_metrics_sender.cc
+++ b/chromium/components/page_load_metrics/renderer/page_timing_metrics_sender.cc
@@ -24,10 +24,6 @@
namespace page_load_metrics {
-const base::Feature kLayoutShiftNormalizationEmitShiftsForKeyMetrics{
- "LayoutShiftNormalizationEmitShiftsForKeyMetrics",
- base::FEATURE_ENABLED_BY_DEFAULT};
-
namespace {
const int kInitialTimerDelayMillis = 50;
const int64_t kInputDelayAdjustmentMillis = int64_t(50);
@@ -105,29 +101,21 @@ void PageTimingMetricsSender::DidObserveLayoutShift(
bool after_input_or_scroll) {
DCHECK(score > 0);
render_data_.layout_shift_delta += score;
- if (base::FeatureList::IsEnabled(
- kLayoutShiftNormalizationEmitShiftsForKeyMetrics)) {
- render_data_.new_layout_shifts.push_back(
- mojom::LayoutShift::New(base::TimeTicks::Now(), score));
- }
+ render_data_.new_layout_shifts.push_back(
+ mojom::LayoutShift::New(base::TimeTicks::Now(), score));
if (!after_input_or_scroll)
render_data_.layout_shift_delta_before_input_or_scroll += score;
EnsureSendTimer();
}
-void PageTimingMetricsSender::DidObserveLayoutNg(
- uint32_t all_block_count,
- uint32_t ng_block_count,
- uint32_t all_call_count,
- uint32_t ng_call_count,
- uint32_t flexbox_ng_block_count,
- uint32_t grid_ng_block_count) {
+void PageTimingMetricsSender::DidObserveLayoutNg(uint32_t all_block_count,
+ uint32_t ng_block_count,
+ uint32_t all_call_count,
+ uint32_t ng_call_count) {
render_data_.all_layout_block_count_delta += all_block_count;
render_data_.ng_layout_block_count_delta += ng_block_count;
render_data_.all_layout_call_count_delta += all_call_count;
render_data_.ng_layout_call_count_delta += ng_call_count;
- render_data_.flexbox_ng_layout_block_count_delta += flexbox_ng_block_count;
- render_data_.grid_ng_layout_block_count_delta += grid_ng_block_count;
EnsureSendTimer();
}
diff --git a/chromium/components/page_load_metrics/renderer/page_timing_metrics_sender.h b/chromium/components/page_load_metrics/renderer/page_timing_metrics_sender.h
index 19168bde8ad..7631b38013c 100644
--- a/chromium/components/page_load_metrics/renderer/page_timing_metrics_sender.h
+++ b/chromium/components/page_load_metrics/renderer/page_timing_metrics_sender.h
@@ -14,7 +14,6 @@
#include "components/page_load_metrics/renderer/page_timing_metadata_recorder.h"
#include "services/network/public/mojom/url_response_head.mojom-forward.h"
#include "third_party/blink/public/common/loader/loading_behavior_flag.h"
-#include "third_party/blink/public/common/loader/previews_state.h"
#include "third_party/blink/public/common/responsiveness_metrics/user_interaction_latency.h"
#include "third_party/blink/public/common/use_counter/use_counter_feature_tracker.h"
#include "third_party/blink/public/web/web_local_frame_client.h"
@@ -56,9 +55,7 @@ class PageTimingMetricsSender {
void DidObserveLayoutNg(uint32_t all_block_count,
uint32_t ng_block_count,
uint32_t all_call_count,
- uint32_t ng_call_count,
- uint32_t flexbox_ng_block_count,
- uint32_t grid_ng_block_count);
+ uint32_t ng_call_count);
void DidObserveLazyLoadBehavior(
blink::WebLocalFrameClient::LazyLoadBehavior lazy_load_behavior);
void DidObserveMobileFriendlinessChanged(const blink::MobileFriendliness&);
diff --git a/chromium/components/page_load_metrics/renderer/page_timing_metrics_sender_unittest.cc b/chromium/components/page_load_metrics/renderer/page_timing_metrics_sender_unittest.cc
index 0c59de40474..8cc6cf4dcf6 100644
--- a/chromium/components/page_load_metrics/renderer/page_timing_metrics_sender_unittest.cc
+++ b/chromium/components/page_load_metrics/renderer/page_timing_metrics_sender_unittest.cc
@@ -307,11 +307,11 @@ TEST_F(PageTimingMetricsSenderTest, SendPageRenderData) {
metrics_sender_->DidObserveLayoutShift(0.5, false);
metrics_sender_->DidObserveLayoutShift(0.5, false);
- metrics_sender_->DidObserveLayoutNg(3, 2, 10, 4, 9, 11);
- metrics_sender_->DidObserveLayoutNg(2, 0, 7, 5, 13, 15);
+ metrics_sender_->DidObserveLayoutNg(3, 2, 10, 4);
+ metrics_sender_->DidObserveLayoutNg(2, 0, 7, 5);
metrics_sender_->DidObserveLayoutShift(0.5, true);
- mojom::FrameRenderDataUpdate render_data(1.5, 1.0, 5, 2, 17, 9, 21, 26, {});
+ mojom::FrameRenderDataUpdate render_data(1.5, 1.0, 5, 2, 17, 9, {});
validator_.UpdateExpectFrameRenderDataUpdate(render_data);
metrics_sender_->mock_timer()->Fire();
diff --git a/chromium/components/paint_preview/browser/paint_preview_base_service_unittest.cc b/chromium/components/paint_preview/browser/paint_preview_base_service_unittest.cc
index 29d2b46033c..49061acdc55 100644
--- a/chromium/components/paint_preview/browser/paint_preview_base_service_unittest.cc
+++ b/chromium/components/paint_preview/browser/paint_preview_base_service_unittest.cc
@@ -8,7 +8,6 @@
#include <utility>
#include "base/files/scoped_temp_dir.h"
-#include "base/no_destructor.h"
#include "base/strings/strcat.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
@@ -245,7 +244,7 @@ TEST_P(PaintPreviewBaseServiceTest, CaptureMainFrame) {
result->proto.root_frame().embedding_token_low());
switch (GetParam()) {
case RecordingPersistence::kFileSystem: {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
base::FilePath path = base::FilePath(
base::UTF8ToWide(result->proto.root_frame().file_path()));
base::FilePath name(
diff --git a/chromium/components/paint_preview/browser/paint_preview_client_unittest.cc b/chromium/components/paint_preview/browser/paint_preview_client_unittest.cc
index e05602cefb3..2875e69fd91 100644
--- a/chromium/components/paint_preview/browser/paint_preview_client_unittest.cc
+++ b/chromium/components/paint_preview/browser/paint_preview_client_unittest.cc
@@ -214,7 +214,7 @@ TEST_P(PaintPreviewClientRenderViewHostTest, CaptureMainFrameMock) {
switch (GetParam()) {
case RecordingPersistence::kFileSystem: {
base::ScopedAllowBlockingForTesting scope;
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
base::FilePath path = base::FilePath(
base::UTF8ToWide(result->proto.root_frame().file_path()));
#else
diff --git a/chromium/components/paint_preview/common/glyph_usage.cc b/chromium/components/paint_preview/common/glyph_usage.cc
index 5a20f801ecd..0021595b653 100644
--- a/chromium/components/paint_preview/common/glyph_usage.cc
+++ b/chromium/components/paint_preview/common/glyph_usage.cc
@@ -16,7 +16,7 @@ GlyphUsage::GlyphUsage(uint16_t first, uint16_t last)
}
GlyphUsage::~GlyphUsage() = default;
-DenseGlyphUsage::DenseGlyphUsage() : GlyphUsage(), bitset_(0, 0) {}
+DenseGlyphUsage::DenseGlyphUsage() : GlyphUsage(), bitset_(0, false) {}
DenseGlyphUsage::DenseGlyphUsage(uint16_t num_glyphs)
: GlyphUsage(1, num_glyphs), bitset_(num_glyphs + 1, false) {}
DenseGlyphUsage::~DenseGlyphUsage() = default;
diff --git a/chromium/components/paint_preview/common/recording_map.cc b/chromium/components/paint_preview/common/recording_map.cc
index aa3073e8726..0da234fa911 100644
--- a/chromium/components/paint_preview/common/recording_map.cc
+++ b/chromium/components/paint_preview/common/recording_map.cc
@@ -14,7 +14,7 @@ namespace paint_preview {
namespace {
base::FilePath ToFilePath(base::StringPiece path_str) {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
return base::FilePath(base::UTF8ToWide(path_str));
#else
return base::FilePath(path_str);
diff --git a/chromium/components/paint_preview/common/serial_utils.cc b/chromium/components/paint_preview/common/serial_utils.cc
index 3f4834c91fa..bb733835dbd 100644
--- a/chromium/components/paint_preview/common/serial_utils.cc
+++ b/chromium/components/paint_preview/common/serial_utils.cc
@@ -70,7 +70,7 @@ sk_sp<SkData> SerializeTypeface(SkTypeface* typeface, void* ctx) {
return typeface->serialize(SkTypeface::SerializeBehavior::kDontIncludeData);
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
{
SkString familyName;
typeface->getFamilyName(&familyName);
diff --git a/chromium/components/paint_preview/common/serial_utils_unittest.cc b/chromium/components/paint_preview/common/serial_utils_unittest.cc
index a8b993cff0a..cce518d0d81 100644
--- a/chromium/components/paint_preview/common/serial_utils_unittest.cc
+++ b/chromium/components/paint_preview/common/serial_utils_unittest.cc
@@ -87,7 +87,7 @@ TEST(PaintPreviewSerialUtils, TestSerialPictureNotInMap) {
// Skip this on Android as we only have system fonts in this test and Android
// doesn't serialize those.
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
TEST(PaintPreviewSerialUtils, TestSerialTypeface) {
PictureSerializationContext picture_ctx;
@@ -119,7 +119,7 @@ TEST(PaintPreviewSerialUtils, TestSerialTypeface) {
}
#endif
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
TEST(PaintPreviewSerialUtils, TestSerialAndroidSystemTypeface) {
PictureSerializationContext picture_ctx;
diff --git a/chromium/components/paint_preview/common/subset_font_unittest.cc b/chromium/components/paint_preview/common/subset_font_unittest.cc
index b6f0e37e900..e38e5e7d535 100644
--- a/chromium/components/paint_preview/common/subset_font_unittest.cc
+++ b/chromium/components/paint_preview/common/subset_font_unittest.cc
@@ -47,7 +47,7 @@ TEST(PaintPreviewSubsetFontTest, TestBasicSubset) {
// TODO(crbug/1250606): Investigate removing the early exits for unsupported
// variation fonts on at least Linux/Android.
-#if defined(OS_LINUX) || defined(OS_ANDROID)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_ANDROID)
namespace {
diff --git a/chromium/components/paint_preview/player/android/javatests/src/org/chromium/components/paintpreview/player/PaintPreviewPlayerTest.java b/chromium/components/paint_preview/player/android/javatests/src/org/chromium/components/paintpreview/player/PaintPreviewPlayerTest.java
index 2b16f6d41ed..2dec1c4d714 100644
--- a/chromium/components/paint_preview/player/android/javatests/src/org/chromium/components/paintpreview/player/PaintPreviewPlayerTest.java
+++ b/chromium/components/paint_preview/player/android/javatests/src/org/chromium/components/paintpreview/player/PaintPreviewPlayerTest.java
@@ -31,7 +31,7 @@ import org.chromium.base.test.util.Criteria;
import org.chromium.base.test.util.CriteriaHelper;
import org.chromium.base.test.util.DisableIf;
import org.chromium.content_public.browser.UiThreadTaskTraits;
-import org.chromium.ui.test.util.DummyUiActivityTestCase;
+import org.chromium.ui.test.util.BlankUiTestActivityTestCase;
import org.chromium.url.GURL;
import java.util.List;
@@ -40,7 +40,7 @@ import java.util.List;
* Instrumentation tests for the Paint Preview player.
*/
@RunWith(BaseJUnit4ClassRunner.class)
-public class PaintPreviewPlayerTest extends DummyUiActivityTestCase {
+public class PaintPreviewPlayerTest extends BlankUiTestActivityTestCase {
private static final long TIMEOUT_MS = 5000;
private static final String TEST_DIRECTORY_KEY = "test_dir";
diff --git a/chromium/components/paint_preview/renderer/paint_preview_recorder_browsertest.cc b/chromium/components/paint_preview/renderer/paint_preview_recorder_browsertest.cc
index abda4f3742d..5e26ad09270 100644
--- a/chromium/components/paint_preview/renderer/paint_preview_recorder_browsertest.cc
+++ b/chromium/components/paint_preview/renderer/paint_preview_recorder_browsertest.cc
@@ -21,6 +21,7 @@
#include "third_party/blink/public/platform/web_runtime_features.h"
#include "third_party/blink/public/web/web_local_frame.h"
#include "third_party/blink/public/web/web_testing_support.h"
+#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkPicture.h"
#include "ui/native_theme/native_theme_features.h"
@@ -725,7 +726,7 @@ TEST_P(PaintPreviewRecorderRenderViewTest, CaptureWithTranslateThenRotate) {
EXPECT_EQ(out_response->links[0]->url, GURL("http://www.example.com"));
EXPECT_NEAR(out_response->links[0]->rect.x(), 141, 5);
EXPECT_NEAR(out_response->links[0]->rect.y(), 18, 5);
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
EXPECT_NEAR(out_response->links[0]->rect.width(), 58, 10);
EXPECT_NEAR(out_response->links[0]->rect.height(), 58, 10);
#endif
@@ -767,7 +768,7 @@ TEST_P(PaintPreviewRecorderRenderViewTest, CaptureWithRotateThenTranslate) {
EXPECT_EQ(out_response->links[0]->url, GURL("http://www.example.com"));
EXPECT_NEAR(out_response->links[0]->rect.x(), 111, 5);
EXPECT_NEAR(out_response->links[0]->rect.y(), 88, 5);
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
EXPECT_NEAR(out_response->links[0]->rect.width(), 58, 10);
EXPECT_NEAR(out_response->links[0]->rect.height(), 58, 10);
#endif
diff --git a/chromium/components/password_manager/OWNERS b/chromium/components/password_manager/OWNERS
index 73bb5977843..978cf9ac8b0 100644
--- a/chromium/components/password_manager/OWNERS
+++ b/chromium/components/password_manager/OWNERS
@@ -1,5 +1,3 @@
-dvadym@chromium.org
-jdoerrie@chromium.org
kolos@chromium.org
mamir@chromium.org
vasilii@chromium.org
diff --git a/chromium/components/password_manager/content/browser/content_password_manager_driver.cc b/chromium/components/password_manager/content/browser/content_password_manager_driver.cc
index fd2331e9150..449c2dc325c 100644
--- a/chromium/components/password_manager/content/browser/content_password_manager_driver.cc
+++ b/chromium/components/password_manager/content/browser/content_password_manager_driver.cc
@@ -160,11 +160,6 @@ void ContentPasswordManagerDriver::GeneratedPasswordAccepted(
generation_element_id, password);
}
-void ContentPasswordManagerDriver::TouchToFillClosed(
- ShowVirtualKeyboard show_virtual_keyboard) {
- GetPasswordAutofillAgent()->TouchToFillClosed(show_virtual_keyboard.value());
-}
-
void ContentPasswordManagerDriver::FillSuggestion(
const std::u16string& username,
const std::u16string& password) {
@@ -177,6 +172,17 @@ void ContentPasswordManagerDriver::FillIntoFocusedField(
GetPasswordAutofillAgent()->FillIntoFocusedField(is_password, credential);
}
+#if BUILDFLAG(IS_ANDROID)
+void ContentPasswordManagerDriver::TouchToFillClosed(
+ ShowVirtualKeyboard show_virtual_keyboard) {
+ GetPasswordAutofillAgent()->TouchToFillClosed(show_virtual_keyboard.value());
+}
+
+void ContentPasswordManagerDriver::TriggerFormSubmission() {
+ GetPasswordAutofillAgent()->TriggerFormSubmission();
+}
+#endif
+
void ContentPasswordManagerDriver::PreviewSuggestion(
const std::u16string& username,
const std::u16string& password) {
@@ -402,11 +408,6 @@ void ContentPasswordManagerDriver::CheckSafeBrowsingReputation(
if (!password_manager::bad_message::CheckFrameNotPrerendering(
render_frame_host_))
return;
- // Despite the name, this method is only called on password fields.
- // (See PasswordAutofillAgent::MaybeCheckSafeBrowsingReputation())
- if (client_->GetMetricsRecorder()) {
- client_->GetMetricsRecorder()->RecordUserFocusedPasswordField();
- }
#if defined(ON_FOCUS_PING_ENABLED)
client_->CheckSafeBrowsingReputation(form_action, frame_url);
#endif
diff --git a/chromium/components/password_manager/content/browser/content_password_manager_driver.h b/chromium/components/password_manager/content/browser/content_password_manager_driver.h
index 018856416ce..1b3bc7f9b52 100644
--- a/chromium/components/password_manager/content/browser/content_password_manager_driver.h
+++ b/chromium/components/password_manager/content/browser/content_password_manager_driver.h
@@ -68,11 +68,14 @@ class ContentPasswordManagerDriver
const autofill::FormData& form_data,
autofill::FieldRendererId generation_element_id,
const std::u16string& password) override;
- void TouchToFillClosed(ShowVirtualKeyboard show_virtual_keyboard) override;
void FillSuggestion(const std::u16string& username,
const std::u16string& password) override;
void FillIntoFocusedField(bool is_password,
const std::u16string& credential) override;
+#if BUILDFLAG(IS_ANDROID)
+ void TouchToFillClosed(ShowVirtualKeyboard show_virtual_keyboard) override;
+ void TriggerFormSubmission() override;
+#endif
void PreviewSuggestion(const std::u16string& username,
const std::u16string& password) override;
void ClearPreviewedForm() override;
diff --git a/chromium/components/password_manager/content/browser/content_password_manager_driver_factory.cc b/chromium/components/password_manager/content/browser/content_password_manager_driver_factory.cc
index a8680172b50..c826da7695f 100644
--- a/chromium/components/password_manager/content/browser/content_password_manager_driver_factory.cc
+++ b/chromium/components/password_manager/content/browser/content_password_manager_driver_factory.cc
@@ -7,7 +7,6 @@
#include <utility>
#include "base/memory/ptr_util.h"
-#include "base/stl_util.h"
#include "components/autofill/content/browser/content_autofill_driver.h"
#include "components/autofill/content/browser/content_autofill_driver_factory.h"
#include "components/autofill/core/common/form_data.h"
@@ -82,15 +81,16 @@ ContentPasswordManagerDriverFactory::GetDriverForFrame(
if (!render_frame_host->IsRenderFrameLive())
return nullptr;
- // TryEmplace() will return an iterator to the driver corresponding to
- // `render_frame_host`. It creates a new one if required.
- return &base::TryEmplace(frame_driver_map_, render_frame_host,
- // Args passed to the ContentPasswordManagerDriver
- // constructor if none exists for `render_frame_host`
- // yet.
- render_frame_host, password_client_,
- autofill_client_)
- .first->second;
+ // try_emplace() will return an iterator to the driver corresponding to
+ // `render_frame_host`, creating a new one if `render_frame_host` is not
+ // already a key in the map.
+ auto [it, inserted] = frame_driver_map_.try_emplace(
+ render_frame_host,
+ // Args passed to the ContentPasswordManagerDriver
+ // constructor if none exists for `render_frame_host`
+ // yet.
+ render_frame_host, password_client_, autofill_client_);
+ return &it->second;
}
void ContentPasswordManagerDriverFactory::RenderFrameDeleted(
diff --git a/chromium/components/password_manager/content/browser/content_password_manager_driver_unittest.cc b/chromium/components/password_manager/content/browser/content_password_manager_driver_unittest.cc
index e47067fdb9d..14b3605a63a 100644
--- a/chromium/components/password_manager/content/browser/content_password_manager_driver_unittest.cc
+++ b/chromium/components/password_manager/content/browser/content_password_manager_driver_unittest.cc
@@ -10,6 +10,7 @@
#include "base/bind.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_feature_list.h"
#include "components/autofill/content/common/mojom/autofill_agent.mojom.h"
#include "components/autofill/core/browser/logging/stub_log_manager.h"
#include "components/autofill/core/browser/test_autofill_client.h"
@@ -20,6 +21,7 @@
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/ssl_status.h"
#include "content/public/browser/web_contents.h"
+#include "content/public/test/navigation_simulator.h"
#include "content/public/test/test_renderer_host.h"
#include "content/public/test/web_contents_tester.h"
#include "mojo/public/cpp/bindings/associated_receiver.h"
@@ -27,6 +29,7 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
+#include "third_party/blink/public/common/features.h"
using autofill::ParsingResult;
using autofill::PasswordFormFillData;
@@ -91,7 +94,10 @@ class FakePasswordAutofillAgent
FillIntoFocusedField,
(bool, const std::u16string&),
(override));
+#if BUILDFLAG(IS_ANDROID)
MOCK_METHOD(void, TouchToFillClosed, (bool), (override));
+ MOCK_METHOD(void, TriggerFormSubmission, (), (override));
+#endif
MOCK_METHOD(void,
AnnotateFieldsWithParsingResult,
(const ParsingResult&),
@@ -374,4 +380,57 @@ TEST_F(ContentPasswordManagerDriverURLTest, PasswordFormCleared) {
driver()->PasswordFormCleared(form);
}
+class ContentPasswordManagerDriverFencedFramesTest
+ : public ContentPasswordManagerDriverTest {
+ public:
+ ContentPasswordManagerDriverFencedFramesTest() {
+ scoped_feature_list_.InitAndEnableFeatureWithParameters(
+ blink::features::kFencedFrames, {{"implementation_type", "mparch"}});
+ }
+ ~ContentPasswordManagerDriverFencedFramesTest() override = default;
+
+ private:
+ base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+TEST_F(ContentPasswordManagerDriverFencedFramesTest,
+ SetFrameAndFormMetaDataOfForm) {
+ NavigateAndCommit(GURL("https://test.org"));
+
+ std::unique_ptr<ContentPasswordManagerDriver> driver(
+ new ContentPasswordManagerDriver(main_rfh(), &password_manager_client_,
+ &autofill_client_));
+
+ content::RenderFrameHost* fenced_frame_root =
+ content::RenderFrameHostTester::For(main_rfh())->AppendFencedFrame();
+
+ // Navigate a fenced frame.
+ GURL fenced_frame_url =
+ GURL("https://username:password@hostname/path?query#hash");
+ std::unique_ptr<content::NavigationSimulator> navigation_simulator =
+ content::NavigationSimulator::CreateForFencedFrame(fenced_frame_url,
+ fenced_frame_root);
+ navigation_simulator->Commit();
+
+ autofill::FormData initial_form;
+ autofill::FormData form_in_fenced_frame =
+ GetFormWithFrameAndFormMetaData(fenced_frame_root, initial_form);
+
+ // Verify all form data that are filled from a fenced frame's render frame
+ // host, not from the primary main frame.
+ EXPECT_EQ(
+ form_in_fenced_frame.host_frame,
+ autofill::LocalFrameToken(fenced_frame_root->GetFrameToken().value()));
+ EXPECT_EQ(form_in_fenced_frame.url, GURL("https://hostname/path"));
+ EXPECT_EQ(form_in_fenced_frame.full_url,
+ GURL("https://hostname/path?query#hash"));
+
+ EXPECT_EQ(form_in_fenced_frame.main_frame_origin,
+ fenced_frame_root->GetLastCommittedOrigin());
+ EXPECT_NE(form_in_fenced_frame.main_frame_origin,
+ web_contents()->GetMainFrame()->GetLastCommittedOrigin());
+ EXPECT_EQ(form_in_fenced_frame.main_frame_origin,
+ url::Origin::CreateFromNormalizedTuple("https", "hostname", 443));
+}
+
} // namespace password_manager
diff --git a/chromium/components/password_manager/content/common/credential_manager_mojom_traits.cc b/chromium/components/password_manager/content/common/credential_manager_mojom_traits.cc
index e6ea9b44f52..5fb69f1b191 100644
--- a/chromium/components/password_manager/content/common/credential_manager_mojom_traits.cc
+++ b/chromium/components/password_manager/content/common/credential_manager_mojom_traits.cc
@@ -78,35 +78,12 @@ bool EnumTraits<blink::mojom::CredentialManagerError,
*output = password_manager::CredentialManagerError::SUCCESS;
return true;
case blink::mojom::CredentialManagerError::PENDING_REQUEST:
- case blink::mojom::CredentialManagerError::PENDING_REQUEST_WEBAUTHN:
*output = password_manager::CredentialManagerError::PENDING_REQUEST;
return true;
case blink::mojom::CredentialManagerError::PASSWORD_STORE_UNAVAILABLE:
*output =
password_manager::CredentialManagerError::PASSWORDSTOREUNAVAILABLE;
return true;
- case blink::mojom::CredentialManagerError::NOT_ALLOWED:
- case blink::mojom::CredentialManagerError::ANDROID_NOT_SUPPORTED_ERROR:
- case blink::mojom::CredentialManagerError::ANDROID_ALGORITHM_UNSUPPORTED:
- case blink::mojom::CredentialManagerError::ANDROID_EMPTY_ALLOW_CREDENTIALS:
- case blink::mojom::CredentialManagerError::
- ANDROID_USER_VERIFICATION_UNSUPPORTED:
- case blink::mojom::CredentialManagerError::INVALID_DOMAIN:
- case blink::mojom::CredentialManagerError::INVALID_ICON_URL:
- case blink::mojom::CredentialManagerError::CREDENTIAL_EXCLUDED:
- case blink::mojom::CredentialManagerError::NOT_IMPLEMENTED:
- case blink::mojom::CredentialManagerError::NOT_FOCUSED:
- case blink::mojom::CredentialManagerError::RESIDENT_CREDENTIALS_UNSUPPORTED:
- case blink::mojom::CredentialManagerError::PROTECTION_POLICY_INCONSISTENT:
- case blink::mojom::CredentialManagerError::ABORT:
- case blink::mojom::CredentialManagerError::OPAQUE_DOMAIN:
- case blink::mojom::CredentialManagerError::INVALID_PROTOCOL:
- case blink::mojom::CredentialManagerError::BAD_RELYING_PARTY_ID:
- case blink::mojom::CredentialManagerError::CANNOT_READ_AND_WRITE_LARGE_BLOB:
- case blink::mojom::CredentialManagerError::
- INVALID_ALLOW_CREDENTIALS_FOR_LARGE_BLOB:
- case blink::mojom::CredentialManagerError::
- FAILED_TO_SAVE_CREDENTIAL_ID_FOR_PAYMENT_EXTENSION:
case blink::mojom::CredentialManagerError::UNKNOWN:
*output = password_manager::CredentialManagerError::UNKNOWN;
return true;
diff --git a/chromium/components/password_manager/core/browser/BUILD.gn b/chromium/components/password_manager/core/browser/BUILD.gn
index d0216b48c40..748805bc886 100644
--- a/chromium/components/password_manager/core/browser/BUILD.gn
+++ b/chromium/components/password_manager/core/browser/BUILD.gn
@@ -108,6 +108,8 @@ static_library("browser") {
"leak_detection_dialog_utils.h",
"login_database.cc",
"login_database.h",
+ "login_database_async_helper.cc",
+ "login_database_async_helper.h",
"manage_passwords_referrer.h",
"move_password_to_account_store_helper.cc",
"move_password_to_account_store_helper.h",
@@ -123,6 +125,9 @@ static_library("browser") {
"password_autofill_manager.h",
"password_bubble_experiment.cc",
"password_bubble_experiment.h",
+ "password_change_success_tracker.h",
+ "password_change_success_tracker_impl.cc",
+ "password_change_success_tracker_impl.h",
"password_feature_manager.h",
"password_feature_manager_impl.cc",
"password_feature_manager_impl.h",
@@ -135,6 +140,8 @@ static_library("browser") {
"password_form_manager_for_ui.h",
"password_form_metrics_recorder.cc",
"password_form_metrics_recorder.h",
+ "password_form_prediction_waiter.cc",
+ "password_form_prediction_waiter.h",
"password_generation_frame_helper.cc",
"password_generation_frame_helper.h",
"password_generation_manager.cc",
@@ -274,6 +281,7 @@ static_library("browser") {
"//components/autofill/core/browser",
"//components/autofill/core/browser/proto",
"//components/autofill/core/common",
+ "//components/autofill/core/common:features",
"//components/autofill/core/common/mojom:mojo_types",
"//components/device_reauth",
"//components/favicon/core",
@@ -283,6 +291,7 @@ static_library("browser") {
"//components/password_manager/core/browser/leak_detection:leak_detection",
"//components/password_manager/core/browser/leak_detection:leak_detection_interface_headers",
"//components/password_manager/core/common",
+ "//components/password_manager/core/common:features",
"//components/pref_registry",
"//components/prefs",
"//components/profile_metrics",
@@ -318,6 +327,9 @@ static_library("browser") {
sources += [
"built_in_backend_to_android_backend_migrator.cc",
"built_in_backend_to_android_backend_migrator.h",
+ "capabilities_service.h",
+ "capabilities_service_impl.cc",
+ "capabilities_service_impl.h",
"password_scripts_fetcher.h",
"password_scripts_fetcher_impl.cc",
"password_scripts_fetcher_impl.h",
@@ -325,7 +337,10 @@ static_library("browser") {
"password_store_backend_migration_decorator.h",
"password_store_proxy_backend.cc",
"password_store_proxy_backend.h",
+ "saved_passwords_capabilities_fetcher.cc",
+ "saved_passwords_capabilities_fetcher.h",
]
+ deps += [ "//components/autofill_assistant/browser/public" ]
}
if (!is_ios) {
@@ -505,6 +520,8 @@ static_library("test_support") {
"mock_bulk_leak_check_service.h",
"mock_field_info_store.cc",
"mock_field_info_store.h",
+ "mock_password_change_success_tracker.cc",
+ "mock_password_change_success_tracker.h",
"mock_password_feature_manager.cc",
"mock_password_feature_manager.h",
"mock_password_form_manager_for_ui.cc",
@@ -519,6 +536,8 @@ static_library("test_support") {
"mock_password_sync_metadata_store.h",
"mock_smart_bubble_stats_store.cc",
"mock_smart_bubble_stats_store.h",
+ "mock_webauthn_credentials_delegate.cc",
+ "mock_webauthn_credentials_delegate.h",
"password_manager_test_utils.cc",
"password_manager_test_utils.h",
"site_affiliation/fake_affiliation_service.cc",
@@ -602,6 +621,7 @@ bundle_data("unit_tests_bundle_data") {
"//components/test/data/password_manager/login_db_v3.sql",
"//components/test/data/password_manager/login_db_v30.sql",
"//components/test/data/password_manager/login_db_v31.sql",
+ "//components/test/data/password_manager/login_db_v32.sql",
"//components/test/data/password_manager/login_db_v3_broken.sql",
"//components/test/data/password_manager/login_db_v4.sql",
"//components/test/data/password_manager/login_db_v5.sql",
@@ -664,6 +684,7 @@ source_set("unit_tests") {
"password_form_filling_unittest.cc",
"password_form_manager_unittest.cc",
"password_form_metrics_recorder_unittest.cc",
+ "password_form_prediction_waiter_unittest.cc",
"password_generation_frame_helper_unittest.cc",
"password_generation_manager_unittest.cc",
"password_hash_data_unittest.cc",
@@ -706,9 +727,11 @@ source_set("unit_tests") {
if (is_android) {
sources += [
"built_in_backend_to_android_backend_migrator_unittest.cc",
+ "capabilities_service_impl_unittest.cc",
"password_scripts_fetcher_impl_unittests.cc",
"password_store_backend_migration_decorator_unittest.cc",
"password_store_proxy_backend_unittest.cc",
+ "saved_passwords_capabilities_fetcher_unittest.cc",
]
}
if (is_ios) {
@@ -758,6 +781,7 @@ source_set("unit_tests") {
"//components/password_manager/core/browser/leak_detection:test_support",
"//components/password_manager/core/browser/leak_detection:unit_tests",
"//components/password_manager/core/common",
+ "//components/password_manager/core/common:features",
"//components/prefs:test_support",
"//components/safe_browsing/core/common",
"//components/safe_browsing/core/common:safe_browsing_prefs",
@@ -784,6 +808,10 @@ source_set("unit_tests") {
"//ui/gfx:test_support",
"//url",
]
+
+ if (is_android) {
+ deps += [ "//components/autofill_assistant/browser/public" ]
+ }
}
fuzzer_test("csv_reader_fuzzer") {
diff --git a/chromium/components/password_manager/core/browser/DEPS b/chromium/components/password_manager/core/browser/DEPS
index 54ebd78eb38..923f54eba17 100644
--- a/chromium/components/password_manager/core/browser/DEPS
+++ b/chromium/components/password_manager/core/browser/DEPS
@@ -1,5 +1,6 @@
include_rules = [
"+components/autofill/core/browser",
+ "+components/autofill_assistant/browser/public",
"+components/device_reauth",
"+components/favicon/core",
"+components/keyed_service/core",
diff --git a/chromium/components/password_manager/core/browser/android_affiliation/fake_affiliation_api.cc b/chromium/components/password_manager/core/browser/android_affiliation/fake_affiliation_api.cc
index 659c343b93e..5a84ce22c07 100644
--- a/chromium/components/password_manager/core/browser/android_affiliation/fake_affiliation_api.cc
+++ b/chromium/components/password_manager/core/browser/android_affiliation/fake_affiliation_api.cc
@@ -6,9 +6,9 @@
#include <algorithm>
#include <memory>
+#include <tuple>
#include <utility>
-#include "base/ignore_result.h"
#include "base/ranges/algorithm.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -62,7 +62,7 @@ void FakeAffiliationAPI::FailNextRequest() {
void FakeAffiliationAPI::IgnoreNextRequest() {
if (!fake_fetcher_factory_->has_pending_fetchers())
return;
- ignore_result(fake_fetcher_factory_->PopNextFetcher());
+ std::ignore = fake_fetcher_factory_->PopNextFetcher();
}
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/android_affiliation/lookup_affiliation_response_parser.cc b/chromium/components/password_manager/core/browser/android_affiliation/lookup_affiliation_response_parser.cc
index 907b7eca825..9211a0920e7 100644
--- a/chromium/components/password_manager/core/browser/android_affiliation/lookup_affiliation_response_parser.cc
+++ b/chromium/components/password_manager/core/browser/android_affiliation/lookup_affiliation_response_parser.cc
@@ -74,11 +74,12 @@ bool ParseFacets(const std::vector<FacetURI>& requested_facet_uris,
bool ParseLookupAffiliationResponse(
const std::vector<FacetURI>& requested_facet_uris,
- const affiliation_pb::LookupAffiliationResponse& response,
+ const affiliation_pb::LookupAffiliationByHashPrefixResponse& response,
AffiliationFetcherDelegate::Result* result) {
- return ParseFacets(requested_facet_uris, response.affiliation(),
+ return ParseFacets(requested_facet_uris, response.affiliations(),
result->affiliations) &&
- ParseFacets(requested_facet_uris, response.group(), result->groupings);
+ ParseFacets(requested_facet_uris, response.groups(),
+ result->groupings);
}
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/android_affiliation/lookup_affiliation_response_parser.h b/chromium/components/password_manager/core/browser/android_affiliation/lookup_affiliation_response_parser.h
index 4efaed9a7f2..98126640bd2 100644
--- a/chromium/components/password_manager/core/browser/android_affiliation/lookup_affiliation_response_parser.h
+++ b/chromium/components/password_manager/core/browser/android_affiliation/lookup_affiliation_response_parser.h
@@ -18,7 +18,7 @@ namespace password_manager {
bool ParseLookupAffiliationResponse(
const std::vector<FacetURI>& requested_facet_uris,
- const affiliation_pb::LookupAffiliationResponse& response,
+ const affiliation_pb::LookupAffiliationByHashPrefixResponse& response,
AffiliationFetcherDelegate::Result* result);
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/android_affiliation/lookup_affiliation_response_parser_fuzzer.cc b/chromium/components/password_manager/core/browser/android_affiliation/lookup_affiliation_response_parser_fuzzer.cc
index a76405a5d24..8cbe9d5ea27 100644
--- a/chromium/components/password_manager/core/browser/android_affiliation/lookup_affiliation_response_parser_fuzzer.cc
+++ b/chromium/components/password_manager/core/browser/android_affiliation/lookup_affiliation_response_parser_fuzzer.cc
@@ -24,7 +24,7 @@ struct IcuEnvironment {
// See more details about the fuzzer extending at
// https://crrev.com/c/1131185/1/components/password_manager/core/browser/android_affiliation/lookup_affiliation_response_parser_fuzzer.cc#25
DEFINE_BINARY_PROTO_FUZZER(
- const affiliation_pb::LookupAffiliationResponse& response) {
+ const affiliation_pb::LookupAffiliationByHashPrefixResponse& response) {
static IcuEnvironment env;
AffiliationFetcherDelegate::Result result;
diff --git a/chromium/components/password_manager/core/browser/built_in_backend_to_android_backend_migrator.cc b/chromium/components/password_manager/core/browser/built_in_backend_to_android_backend_migrator.cc
index 22cfbf6c1e2..9190266e56e 100644
--- a/chromium/components/password_manager/core/browser/built_in_backend_to_android_backend_migrator.cc
+++ b/chromium/components/password_manager/core/browser/built_in_backend_to_android_backend_migrator.cc
@@ -10,7 +10,9 @@
#include "base/callback.h"
#include "base/containers/flat_set.h"
#include "base/memory/scoped_refptr.h"
+#include "base/metrics/histogram_functions.h"
#include "base/ranges/algorithm.h"
+#include "base/strings/strcat.h"
#include "components/password_manager/core/common/password_manager_features.h"
#include "components/password_manager/core/common/password_manager_pref_names.h"
#include "components/prefs/pref_service.h"
@@ -19,23 +21,10 @@ namespace password_manager {
namespace {
+// Threshold for the next migration attempt. This is needed in order to prevent
+// clients from spamming GMS Core API.
constexpr base::TimeDelta kMigrationThreshold = base::Days(1);
-struct IsPasswordLess {
- bool operator()(const PasswordForm* lhs, const PasswordForm* rhs) const {
- return PasswordFormUniqueKey(*lhs) < PasswordFormUniqueKey(*rhs);
- }
-};
-
-base::OnceCallback<void(PasswordStoreChangeList)>
-IgnoreChangeListAndRunCallback(base::OnceClosure callback) {
- return base::BindOnce(
- [](base::OnceClosure callback, PasswordStoreChangeList) {
- std::move(callback).Run();
- },
- std::move(callback));
-}
-
bool IsInitialMigrationNeeded(PrefService* prefs) {
return features::kMigrationVersion.Get() >
prefs->GetInteger(
@@ -44,6 +33,12 @@ bool IsInitialMigrationNeeded(PrefService* prefs) {
} // namespace
+struct BuiltInBackendToAndroidBackendMigrator::IsPasswordLess {
+ bool operator()(const PasswordForm* lhs, const PasswordForm* rhs) const {
+ return PasswordFormUniqueKey(*lhs) < PasswordFormUniqueKey(*rhs);
+ }
+};
+
struct BuiltInBackendToAndroidBackendMigrator::BackendAndLoginsResults {
raw_ptr<PasswordStoreBackend> backend;
LoginsResultOrError logins_result;
@@ -73,28 +68,54 @@ struct BuiltInBackendToAndroidBackendMigrator::BackendAndLoginsResults {
~BackendAndLoginsResults() = default;
};
+class BuiltInBackendToAndroidBackendMigrator::MigrationMetricsReporter {
+ public:
+ explicit MigrationMetricsReporter(base::StringPiece metric_infix)
+ : metric_infix_(metric_infix) {}
+ ~MigrationMetricsReporter() = default;
+
+ void ReportMetrics(bool migration_succeeded) {
+ auto BuildMetricName = [this](base::StringPiece suffix) {
+ return base::StrCat({"PasswordManager.UnifiedPasswordManager.",
+ metric_infix_, ".", suffix});
+ };
+ base::TimeDelta duration = base::Time::Now() - start_;
+ base::UmaHistogramMediumTimes(BuildMetricName("Latency"), duration);
+ base::UmaHistogramBoolean(BuildMetricName("Success"), migration_succeeded);
+ }
+
+ private:
+ base::Time start_ = base::Time::Now();
+ base::StringPiece metric_infix_;
+};
+
BuiltInBackendToAndroidBackendMigrator::BuiltInBackendToAndroidBackendMigrator(
PasswordStoreBackend* built_in_backend,
PasswordStoreBackend* android_backend,
PrefService* prefs,
- base::RepeatingCallback<bool()> is_syncing_passwords_callback)
+ PasswordStoreBackend::SyncDelegate* sync_delegate)
: built_in_backend_(built_in_backend),
android_backend_(android_backend),
prefs_(prefs),
- is_syncing_passwords_callback_(std::move(is_syncing_passwords_callback)) {
+ sync_delegate_(sync_delegate) {
DCHECK(built_in_backend_);
DCHECK(android_backend_);
+ base::UmaHistogramBoolean(
+ "PasswordManager.UnifiedPasswordManager.WasMigrationDone",
+ !IsInitialMigrationNeeded(prefs_));
}
BuiltInBackendToAndroidBackendMigrator::
~BuiltInBackendToAndroidBackendMigrator() = default;
void BuiltInBackendToAndroidBackendMigrator::StartMigrationIfNecessary() {
+ bool is_initial_migration_needed = IsInitialMigrationNeeded(prefs_);
+
// For syncing users, we don't need to move passwords between the built-in
// and the Android backends, since both backends should be able to
// retrieve the same passwords from the sync server.
- if (is_syncing_passwords_callback_.Run() &&
- IsInitialMigrationNeeded(prefs_)) {
+ if (sync_delegate_->IsSyncingPasswordsEnabled() &&
+ is_initial_migration_needed) {
// TODO:(crbug.com/1252443) Drop metadata and only then update pref.
UpdateMigrationVersionInPref();
return;
@@ -111,8 +132,10 @@ void BuiltInBackendToAndroidBackendMigrator::StartMigrationIfNecessary() {
// Manually migrate passwords between backends if initial or rolling migration
// is needed. Even for syncing users we still should do rolling migration to
// ensure deletions aren’t resurrected.
- if (IsInitialMigrationNeeded(prefs_) ||
+ if (is_initial_migration_needed ||
base::FeatureList::IsEnabled(features::kUnifiedPasswordManagerAndroid)) {
+ metrics_reporter_ = std::make_unique<MigrationMetricsReporter>(
+ is_initial_migration_needed ? "InitialMigration" : "RollingMigration");
PrepareForMigration();
}
}
@@ -148,11 +171,13 @@ void BuiltInBackendToAndroidBackendMigrator::PrepareForMigration() {
void BuiltInBackendToAndroidBackendMigrator::
MigratePasswordsBetweenAndroidAndBuiltInBackends(
std::vector<BackendAndLoginsResults> results) {
+ DCHECK(metrics_reporter_);
DCHECK_EQ(2u, results.size());
- // TODO:(crbug.com/1252443) Record that migration was canceled due to an
- // error.
- if (results[0].HasError() || results[1].HasError())
+
+ if (results[0].HasError() || results[1].HasError()) {
+ MigrationFinished(/*is_success=*/false);
return;
+ }
base::flat_set<const PasswordForm*, IsPasswordLess> built_in_backend_logins =
(results[0].backend == built_in_backend_) ? results[0].GetLogins()
@@ -162,52 +187,54 @@ void BuiltInBackendToAndroidBackendMigrator::
(results[0].backend == android_backend_) ? results[0].GetLogins()
: results[1].GetLogins();
- bool is_initial_migration = IsInitialMigrationNeeded(prefs_);
+ if (IsInitialMigrationNeeded(prefs_)) {
+ MergeAndroidBackendAndBuiltInBackend(std::move(built_in_backend_logins),
+ std::move(android_logins));
+ } else {
+ MirrorAndroidBackendToBuiltInBackend(std::move(built_in_backend_logins),
+ std::move(android_logins));
+ }
+}
+void BuiltInBackendToAndroidBackendMigrator::
+ MergeAndroidBackendAndBuiltInBackend(
+ PasswordFormPtrFlatSet built_in_backend_logins,
+ PasswordFormPtrFlatSet android_logins) {
// For a form |F|, there are three cases to handle:
- // 1. |F| exists only in the |built_in_backend_|
- // 2. |F| exists only in the |android_backend_|
- // 3. |F| exists in both |built_in_backend_| and |android_backend_|.
- //
- // In initial migration is required:
- // 1. |F| should be added to the |android_backend_|.
- // 2. |F| should be added to the |built_in_backend_|.
- // 3. Both versions should be merged by accepting the most recently created
+ // 1. If |F| exists only in the |built_in_backend_|, then |F| should be added
+ // to the |android_backend_|.
+ // 2. If |F| exists only in the |android_backend_|, then |F| should be added
+ // to
+ // the |built_in_backend_|
+ // 3. If |F| exists in both |built_in_backend_| and |android_backend_|, then
+ // both versions should be merged by accepting the most recently created
// one*, and update either |built_in_backend_| and |android_backend_|
// accordingly.
// * it should happen only if password values differs between backends.
- // Otherwise:
- // 1. |F| should be removed from the |built_in_backend_|.
- // 2. |F| should be added to the |built_in_backend_|.
- // 3. version from |built_in_backend_| should be updated with version from the
- // |android_backend_|.
- // Callbacks are chained in a LIFO way by passing 'callback_chain' as a
- // completion for the next operation. If it is initial migration - update pref
- // to mark successful completion.
+ // Callbacks are chained like in a stack way by passing 'callback_chain' as a
+ // completion for the next operation. At the end, update pref to mark
+ // successful completion.
base::OnceClosure callbacks_chain =
- is_initial_migration
- ? base::BindOnce(&BuiltInBackendToAndroidBackendMigrator::
- UpdateMigrationVersionInPref,
- weak_ptr_factory_.GetWeakPtr())
- : base::DoNothing();
+ base::BindOnce(&BuiltInBackendToAndroidBackendMigrator::MigrationFinished,
+ weak_ptr_factory_.GetWeakPtr(), /*is_success=*/true);
+
+ callbacks_chain =
+ base::BindOnce(
+ &BuiltInBackendToAndroidBackendMigrator::UpdateMigrationVersionInPref,
+ weak_ptr_factory_.GetWeakPtr())
+ .Then(std::move(callbacks_chain));
+
for (auto* const login : built_in_backend_logins) {
auto android_login_iter = android_logins.find(login);
if (android_login_iter == android_logins.end()) {
// Password from the |built_in_backend_| doesn't exist in the
// |android_backend_|.
- if (is_initial_migration) {
- callbacks_chain = base::BindOnce(
- &PasswordStoreBackend::AddLoginAsync,
- android_backend_->GetWeakPtr(), *login,
- IgnoreChangeListAndRunCallback(std::move(callbacks_chain)));
- } else {
- callbacks_chain = base::BindOnce(
- &PasswordStoreBackend::RemoveLoginAsync,
- built_in_backend_->GetWeakPtr(), *login,
- IgnoreChangeListAndRunCallback(std::move(callbacks_chain)));
- }
+ callbacks_chain = base::BindOnce(
+ &BuiltInBackendToAndroidBackendMigrator::AddLoginToBackend,
+ weak_ptr_factory_.GetWeakPtr(), android_backend_, *login,
+ std::move(callbacks_chain));
continue;
}
@@ -220,22 +247,18 @@ void BuiltInBackendToAndroidBackendMigrator::
continue;
}
- // Passwords aren't identical.
- if (is_initial_migration &&
- login->date_created > android_login->date_created) {
- // // During initial migration, pick the most recently created one. This
- // is aligned with the merge sync logic in PasswordSyncBridge.
+ // Passwords aren't identical. Pick the most recently created one. This
+ // is aligned with the merge sync logic in PasswordSyncBridge.
+ if (login->date_created > android_login->date_created) {
callbacks_chain = base::BindOnce(
- &PasswordStoreBackend::UpdateLoginAsync,
- android_backend_->GetWeakPtr(), *login,
- IgnoreChangeListAndRunCallback(std::move(callbacks_chain)));
+ &BuiltInBackendToAndroidBackendMigrator::UpdateLoginInBackend,
+ weak_ptr_factory_.GetWeakPtr(), android_backend_, *login,
+ std::move(callbacks_chain));
} else {
- // During rolling migration, update the built-in version to match the
- // Android version.
callbacks_chain = base::BindOnce(
- &PasswordStoreBackend::UpdateLoginAsync,
- built_in_backend_->GetWeakPtr(), *android_login,
- IgnoreChangeListAndRunCallback(std::move(callbacks_chain)));
+ &BuiltInBackendToAndroidBackendMigrator::UpdateLoginInBackend,
+ weak_ptr_factory_.GetWeakPtr(), built_in_backend_, *android_login,
+ std::move(callbacks_chain));
}
}
@@ -252,12 +275,133 @@ void BuiltInBackendToAndroidBackendMigrator::
// Add to the |built_in_backend_| any passwords from the |android_backend_|
// that doesn't exist in the |built_in_backend_|.
callbacks_chain = base::BindOnce(
- &PasswordStoreBackend::AddLoginAsync, built_in_backend_->GetWeakPtr(),
- *android_login,
- IgnoreChangeListAndRunCallback(std::move(callbacks_chain)));
+ &BuiltInBackendToAndroidBackendMigrator::AddLoginToBackend,
+ weak_ptr_factory_.GetWeakPtr(), built_in_backend_, *android_login,
+ std::move(callbacks_chain));
}
std::move(callbacks_chain).Run();
}
+void BuiltInBackendToAndroidBackendMigrator::
+ MirrorAndroidBackendToBuiltInBackend(
+ PasswordFormPtrFlatSet built_in_backend_logins,
+ PasswordFormPtrFlatSet android_logins) {
+ // For a form |F|, there are three cases to handle:
+ // 1. If |F| exists only in the |built_in_backend_|, then |F| should be
+ // removed from the |built_in_backend_|.
+ // 2. |F| exists only in the |android_backend_|, then |F| should be added to
+ // the |built_in_backend_|.
+ // 3. |F| exists in both |built_in_backend_| and |android_backend_|, then
+ // version from |built_in_backend_| should be updated with version from the
+ // |android_backend_|.
+
+ // Callbacks are chained like in a stack way by passing 'callback_chain' as a
+ // completion for the next operation.
+ base::OnceClosure callbacks_chain =
+ base::BindOnce(&BuiltInBackendToAndroidBackendMigrator::MigrationFinished,
+ weak_ptr_factory_.GetWeakPtr(), /*is_success=*/true);
+
+ for (auto* const login : built_in_backend_logins) {
+ auto android_login_iter = android_logins.find(login);
+
+ if (android_login_iter == android_logins.end()) {
+ // Password from the |built_in_backend_| doesn't exist in the
+ // |android_backend_|.
+ callbacks_chain = base::BindOnce(
+ &BuiltInBackendToAndroidBackendMigrator::RemoveLoginFromBackend,
+ weak_ptr_factory_.GetWeakPtr(), built_in_backend_, *login,
+ std::move(callbacks_chain));
+ continue;
+ }
+
+ // Password from the |built_in_backend_| exists in the |android_backend_|.
+ auto* const android_login = (*android_login_iter);
+
+ if (login->password_value == android_login->password_value) {
+ // Passwords are identical, nothing else to do.
+ continue;
+ }
+
+ // Passwords aren't identical, update the built-in version to match the
+ // Android version.
+ callbacks_chain = base::BindOnce(
+ &BuiltInBackendToAndroidBackendMigrator::UpdateLoginInBackend,
+ weak_ptr_factory_.GetWeakPtr(), built_in_backend_, *android_login,
+ std::move(callbacks_chain));
+ }
+
+ // At this point, we have processed all passwords from the |built_in_backend_|
+ // In addition, we also have processed all passwords from the
+ // |android_backend_| which exist in the |built_in_backend_|. What's remaining
+ // is to process passwords from |android_backend_| that don't exist in the
+ // |built_in_backend_|.
+ for (auto* const android_login : android_logins) {
+ if (built_in_backend_logins.contains(android_login)) {
+ continue;
+ }
+
+ // Add to the |built_in_backend_| any passwords from the |android_backend_|
+ // that doesn't exist in the |built_in_backend_|.
+ callbacks_chain = base::BindOnce(
+ &BuiltInBackendToAndroidBackendMigrator::AddLoginToBackend,
+ weak_ptr_factory_.GetWeakPtr(), built_in_backend_, *android_login,
+ std::move(callbacks_chain));
+ }
+
+ std::move(callbacks_chain).Run();
+}
+
+void BuiltInBackendToAndroidBackendMigrator::AddLoginToBackend(
+ PasswordStoreBackend* backend,
+ const PasswordForm& form,
+ base::OnceClosure callback) {
+ backend->AddLoginAsync(
+ form,
+ base::BindOnce(
+ &BuiltInBackendToAndroidBackendMigrator::RunCallbackOrAbortMigration,
+ weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+}
+
+void BuiltInBackendToAndroidBackendMigrator::UpdateLoginInBackend(
+ PasswordStoreBackend* backend,
+ const PasswordForm& form,
+ base::OnceClosure callback) {
+ backend->UpdateLoginAsync(
+ form,
+ base::BindOnce(
+ &BuiltInBackendToAndroidBackendMigrator::RunCallbackOrAbortMigration,
+ weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+}
+
+void BuiltInBackendToAndroidBackendMigrator::RemoveLoginFromBackend(
+ PasswordStoreBackend* backend,
+ const PasswordForm& form,
+ base::OnceClosure callback) {
+ backend->RemoveLoginAsync(
+ form,
+ base::BindOnce(
+ &BuiltInBackendToAndroidBackendMigrator::RunCallbackOrAbortMigration,
+ weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+}
+
+void BuiltInBackendToAndroidBackendMigrator::RunCallbackOrAbortMigration(
+ base::OnceClosure callback,
+ absl::optional<PasswordStoreChangeList> changelist) {
+ if (!changelist.has_value() || !changelist.value().empty()) {
+ // The step was successful, continue the migration.
+ std::move(callback).Run();
+ return;
+ }
+ // Migration failed.
+ MigrationFinished(/*is_success=*/false);
+}
+
+void BuiltInBackendToAndroidBackendMigrator::MigrationFinished(
+ bool is_success) {
+ DCHECK(metrics_reporter_);
+ metrics_reporter_->ReportMetrics(is_success);
+ metrics_reporter_.reset();
+}
+
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/built_in_backend_to_android_backend_migrator.h b/chromium/components/password_manager/core/browser/built_in_backend_to_android_backend_migrator.h
index 3962e9922b4..979a475dd4e 100644
--- a/chromium/components/password_manager/core/browser/built_in_backend_to_android_backend_migrator.h
+++ b/chromium/components/password_manager/core/browser/built_in_backend_to_android_backend_migrator.h
@@ -12,8 +12,6 @@ class PrefService;
namespace password_manager {
-class PasswordStoreBackend;
-
// Instantiate this object to migrate all password stored in the built-in
// backend to the Android backend. Migration is potentially an expensive
// operation and shouldn't start during the hot phase of Chrome start.
@@ -25,7 +23,7 @@ class BuiltInBackendToAndroidBackendMigrator {
PasswordStoreBackend* built_in_backend,
PasswordStoreBackend* android_backend,
PrefService* prefs,
- base::RepeatingCallback<bool()> is_syncing_passwords_callback);
+ PasswordStoreBackend::SyncDelegate* sync_delegate);
BuiltInBackendToAndroidBackendMigrator(
const BuiltInBackendToAndroidBackendMigrator&) = delete;
@@ -40,7 +38,12 @@ class BuiltInBackendToAndroidBackendMigrator {
void StartMigrationIfNecessary();
private:
+ struct IsPasswordLess;
struct BackendAndLoginsResults;
+ class MigrationMetricsReporter;
+
+ using PasswordFormPtrFlatSet =
+ base::flat_set<const PasswordForm*, IsPasswordLess>;
// Saves current migration version in |prefs_|.
void UpdateMigrationVersionInPref();
@@ -56,12 +59,50 @@ class BuiltInBackendToAndroidBackendMigrator {
void MigratePasswordsBetweenAndroidAndBuiltInBackends(
std::vector<BackendAndLoginsResults> result);
+ // Updates both |built_in_backend_| and |android_backend_| such that both
+ // contain the same set of passwords without deleting any password. In
+ // addition, it marks the initial migration as completed.
+ void MergeAndroidBackendAndBuiltInBackend(
+ PasswordFormPtrFlatSet built_in_backend_logins,
+ PasswordFormPtrFlatSet android_logins);
+
+ // Updates |built_in_backend_| such that it contains the same set of passwords
+ // as in |android_backend_|.
+ void MirrorAndroidBackendToBuiltInBackend(
+ PasswordFormPtrFlatSet built_in_backend_logins,
+ PasswordFormPtrFlatSet android_logins);
+
+ // Helper methods to {Add,Update,Remove} |form| in |backend|. This is used to
+ // ensure that all the operations are happening inside
+ // BuiltInBackendToAndroidBackendMigrator life-scope.
+ void AddLoginToBackend(PasswordStoreBackend* backend,
+ const PasswordForm& form,
+ base::OnceClosure callback);
+ void UpdateLoginInBackend(PasswordStoreBackend* backend,
+ const PasswordForm& form,
+ base::OnceClosure callback);
+ void RemoveLoginFromBackend(PasswordStoreBackend* backend,
+ const PasswordForm& form,
+ base::OnceClosure callback);
+
+ // If |changelist| is an empty changelist, migration is aborted by calling
+ // MigrationFinished() indicating the migration is *not* successful.
+ // Otherwise, |callback| is invoked.
+ void RunCallbackOrAbortMigration(
+ base::OnceClosure callback,
+ absl::optional<PasswordStoreChangeList> changelist);
+
+ // Reports metrics and deletes |metrics_reporter_|
+ void MigrationFinished(bool is_success);
+
const raw_ptr<PasswordStoreBackend> built_in_backend_;
const raw_ptr<PasswordStoreBackend> android_backend_;
const raw_ptr<PrefService> prefs_ = nullptr;
- base::RepeatingCallback<bool()> is_syncing_passwords_callback_;
+ std::unique_ptr<MigrationMetricsReporter> metrics_reporter_;
+
+ const raw_ptr<PasswordStoreBackend::SyncDelegate> sync_delegate_;
base::WeakPtrFactory<BuiltInBackendToAndroidBackendMigrator>
weak_ptr_factory_{this};
diff --git a/chromium/components/password_manager/core/browser/built_in_backend_to_android_backend_migrator_unittest.cc b/chromium/components/password_manager/core/browser/built_in_backend_to_android_backend_migrator_unittest.cc
index 96100489379..0523d9a6c52 100644
--- a/chromium/components/password_manager/core/browser/built_in_backend_to_android_backend_migrator_unittest.cc
+++ b/chromium/components/password_manager/core/browser/built_in_backend_to_android_backend_migrator_unittest.cc
@@ -6,10 +6,12 @@
#include "base/feature_list.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/test/metrics/histogram_tester.h"
#include "base/test/mock_callback.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "components/password_manager/core/browser/fake_password_store_backend.h"
+#include "components/password_manager/core/browser/mock_password_store_backend.h"
#include "components/password_manager/core/browser/password_manager_test_utils.h"
#include "components/password_manager/core/common/password_manager_features.h"
#include "components/password_manager/core/common/password_manager_pref_names.h"
@@ -21,13 +23,18 @@
#include "testing/gtest/include/gtest/gtest.h"
using ::testing::Eq;
+using ::testing::Invoke;
using ::testing::Pointee;
+using ::testing::Return;
using ::testing::UnorderedElementsAreArray;
+using ::testing::WithArg;
namespace password_manager {
namespace {
+constexpr base::TimeDelta kLatencyDelta = base::Milliseconds(123u);
+
PasswordForm CreateTestPasswordForm(int index = 0) {
PasswordForm form;
form.url = GURL("https://test" + base::NumberToString(index) + ".com");
@@ -40,45 +47,47 @@ PasswordForm CreateTestPasswordForm(int index = 0) {
} // namespace
+// Checks that initial/rolling migration is started only when all the conditions
+// are satisfied. It also check that migration result is properly recorded in
+// prefs.
class BuiltInBackendToAndroidBackendMigratorTest : public testing::Test {
protected:
- BuiltInBackendToAndroidBackendMigratorTest() {
- prefs_ = std::make_unique<TestingPrefServiceSimple>();
- prefs_->registry()->RegisterIntegerPref(
+ BuiltInBackendToAndroidBackendMigratorTest() = default;
+ ~BuiltInBackendToAndroidBackendMigratorTest() override = default;
+
+ void Init(int current_migration_version = 0) {
+ prefs_.registry()->RegisterIntegerPref(
prefs::kCurrentMigrationVersionToGoogleMobileServices, 0);
- prefs_->registry()->RegisterDoublePref(prefs::kTimeOfLastMigrationAttempt,
- 0.0);
+ prefs_.SetInteger(prefs::kCurrentMigrationVersionToGoogleMobileServices,
+ current_migration_version);
+ prefs_.registry()->RegisterDoublePref(prefs::kTimeOfLastMigrationAttempt,
+ 0.0);
migrator_ = std::make_unique<BuiltInBackendToAndroidBackendMigrator>(
- &built_in_backend_, &android_backend_, prefs_.get(),
- /*is_syncing_passwords_callback=*/is_sync_enabled_callback_.Get());
+ &built_in_backend_, &android_backend_, &prefs_, &sync_delegate_);
}
- ~BuiltInBackendToAndroidBackendMigratorTest() override = default;
-
+ MockPasswordBackendSyncDelegate& sync_delegate() { return sync_delegate_; }
PasswordStoreBackend& built_in_backend() { return built_in_backend_; }
PasswordStoreBackend& android_backend() { return android_backend_; }
base::test::ScopedFeatureList& feature_list() { return feature_list_; }
- TestingPrefServiceSimple* prefs() { return prefs_.get(); }
+ TestingPrefServiceSimple* prefs() { return &prefs_; }
BuiltInBackendToAndroidBackendMigrator* migrator() { return migrator_.get(); }
void RunUntilIdle() { task_env_.RunUntilIdle(); }
+ void FastForwardBy(base::TimeDelta delta) { task_env_.FastForwardBy(delta); }
- void ExpectSyncCallbackAndSetResult(bool enabled) {
- EXPECT_CALL(is_sync_enabled_callback_, Run())
- .WillOnce(testing::Return(enabled));
- }
+ protected:
+ testing::StrictMock<MockPasswordBackendSyncDelegate> sync_delegate_;
private:
base::test::SingleThreadTaskEnvironment task_env_{
base::test::TaskEnvironment::TimeSource::MOCK_TIME};
base::test::ScopedFeatureList feature_list_;
- std::unique_ptr<TestingPrefServiceSimple> prefs_;
+ TestingPrefServiceSimple prefs_;
FakePasswordStoreBackend built_in_backend_;
FakePasswordStoreBackend android_backend_;
std::unique_ptr<BuiltInBackendToAndroidBackendMigrator> migrator_;
- base::MockCallback<base::RepeatingCallback<bool(void)>>
- is_sync_enabled_callback_;
};
TEST_F(BuiltInBackendToAndroidBackendMigratorTest,
@@ -86,7 +95,9 @@ TEST_F(BuiltInBackendToAndroidBackendMigratorTest,
feature_list().InitAndEnableFeatureWithParameters(
/*enabled_feature=*/features::kUnifiedPasswordManagerMigration,
{{"migration_version", "1"}});
- ExpectSyncCallbackAndSetResult(true);
+ Init();
+ EXPECT_CALL(sync_delegate(), IsSyncingPasswordsEnabled)
+ .WillOnce(Return(true));
migrator()->StartMigrationIfNecessary();
RunUntilIdle();
@@ -104,7 +115,10 @@ TEST_F(BuiltInBackendToAndroidBackendMigratorTest,
feature_list().InitAndEnableFeatureWithParameters(
/*enabled_feature=*/features::kUnifiedPasswordManagerMigration,
{{"migration_version", "1"}});
- ExpectSyncCallbackAndSetResult(false);
+ Init();
+
+ EXPECT_CALL(sync_delegate(), IsSyncingPasswordsEnabled)
+ .WillOnce(Return(false));
migrator()->StartMigrationIfNecessary();
RunUntilIdle();
@@ -120,9 +134,12 @@ TEST_F(BuiltInBackendToAndroidBackendMigratorTest,
PrefsUnchangedWhenAttemptedMigrationEarlierToday) {
feature_list().InitAndEnableFeatureWithParameters(
features::kUnifiedPasswordManagerMigration, {{"migration_version", "1"}});
+ Init();
+
prefs()->SetDouble(password_manager::prefs::kTimeOfLastMigrationAttempt,
(base::Time::Now() - base::Hours(2)).ToDoubleT());
- ExpectSyncCallbackAndSetResult(false);
+ EXPECT_CALL(sync_delegate(), IsSyncingPasswordsEnabled)
+ .WillOnce(Return(false));
migrator()->StartMigrationIfNecessary();
RunUntilIdle();
@@ -141,9 +158,10 @@ TEST_F(BuiltInBackendToAndroidBackendMigratorTest,
/*enabled_features=*/{{features::kUnifiedPasswordManagerMigration,
{{"migration_version", "1"}}}},
/*disabled_features=*/{features::kUnifiedPasswordManagerAndroid});
- prefs()->SetInteger(prefs::kCurrentMigrationVersionToGoogleMobileServices, 1);
+ Init(/*current_migration_version=*/1);
- ExpectSyncCallbackAndSetResult(false);
+ EXPECT_CALL(sync_delegate(), IsSyncingPasswordsEnabled)
+ .WillOnce(Return(false));
migrator()->StartMigrationIfNecessary();
RunUntilIdle();
@@ -162,9 +180,10 @@ TEST_F(BuiltInBackendToAndroidBackendMigratorTest,
{{"migration_version", "1"}}},
{features::kUnifiedPasswordManagerAndroid, {{}}}},
/*disabled_features=*/{});
- prefs()->SetInteger(prefs::kCurrentMigrationVersionToGoogleMobileServices, 1);
+ Init(/*current_migration_version=*/1);
- ExpectSyncCallbackAndSetResult(false);
+ EXPECT_CALL(sync_delegate(), IsSyncingPasswordsEnabled)
+ .WillOnce(Return(false));
migrator()->StartMigrationIfNecessary();
RunUntilIdle();
@@ -176,6 +195,52 @@ TEST_F(BuiltInBackendToAndroidBackendMigratorTest,
prefs()->GetDouble(password_manager::prefs::kTimeOfLastMigrationAttempt));
}
+TEST_F(BuiltInBackendToAndroidBackendMigratorTest,
+ InitialMigrationNeverStartedMetrics) {
+ base::HistogramTester histogram_tester;
+ const char kMigrationFinishedMetric[] =
+ "PasswordManager.UnifiedPasswordManager.WasMigrationDone";
+
+ feature_list().InitAndEnableFeatureWithParameters(
+ /*enabled_feature=*/features::kUnifiedPasswordManagerMigration,
+ {{"migration_version", "1"}});
+ Init();
+
+ histogram_tester.ExpectTotalCount(kMigrationFinishedMetric, 1);
+ histogram_tester.ExpectBucketCount(kMigrationFinishedMetric, false, 1);
+}
+
+TEST_F(BuiltInBackendToAndroidBackendMigratorTest,
+ InitialMigrationFinishedMetrics) {
+ base::HistogramTester histogram_tester;
+ const char kMigrationFinishedMetric[] =
+ "PasswordManager.UnifiedPasswordManager.WasMigrationDone";
+
+ feature_list().InitAndEnableFeatureWithParameters(
+ /*enabled_feature=*/features::kUnifiedPasswordManagerMigration,
+ {{"migration_version", "1"}});
+ Init(/*current_migration_version=*/1);
+
+ histogram_tester.ExpectTotalCount(kMigrationFinishedMetric, 1);
+ histogram_tester.ExpectBucketCount(kMigrationFinishedMetric, true, 1);
+}
+
+TEST_F(BuiltInBackendToAndroidBackendMigratorTest,
+ InitialMigrationNeedsRestartMetrics) {
+ base::HistogramTester histogram_tester;
+ const char kMigrationFinishedMetric[] =
+ "PasswordManager.UnifiedPasswordManager.WasMigrationDone";
+
+ feature_list().InitAndEnableFeatureWithParameters(
+ /*enabled_feature=*/features::kUnifiedPasswordManagerMigration,
+ {{"migration_version", "2"}});
+
+ Init(/*current_migration_version=*/1);
+
+ histogram_tester.ExpectTotalCount(kMigrationFinishedMetric, 1);
+ histogram_tester.ExpectBucketCount(kMigrationFinishedMetric, false, 1);
+}
+
// Holds the built in and android backend's logins and the expected result after
// the migration.
struct MigrationParam {
@@ -222,6 +287,8 @@ struct MigrationParam {
std::vector<Entry> merged_logins;
};
+// Tests that initial and rolling migration actually works by comparing
+// passwords in built-in/android backend before and after migration.
class BuiltInBackendToAndroidBackendMigratorTestWithMigrationParams
: public BuiltInBackendToAndroidBackendMigratorTest,
public testing::WithParamInterface<MigrationParam> {};
@@ -229,7 +296,10 @@ class BuiltInBackendToAndroidBackendMigratorTestWithMigrationParams
// Tests the initial migration result.
TEST_P(BuiltInBackendToAndroidBackendMigratorTestWithMigrationParams,
InitialMigration) {
- ExpectSyncCallbackAndSetResult(false);
+ BuiltInBackendToAndroidBackendMigratorTest::Init();
+
+ EXPECT_CALL(sync_delegate(), IsSyncingPasswordsEnabled)
+ .WillOnce(Return(false));
feature_list().InitAndEnableFeatureWithParameters(
/*enabled_feature=*/features::kUnifiedPasswordManagerMigration,
@@ -266,9 +336,11 @@ TEST_P(BuiltInBackendToAndroidBackendMigratorTestWithMigrationParams,
{{"migration_version", "1"}}},
{features::kUnifiedPasswordManagerAndroid, {{}}}},
/*disabled_features=*/{});
- prefs()->SetDouble(password_manager::prefs::kTimeOfLastMigrationAttempt,
- (base::Time::Now() - base::Days(2)).ToDoubleT());
- prefs()->SetInteger(prefs::kCurrentMigrationVersionToGoogleMobileServices, 1);
+ BuiltInBackendToAndroidBackendMigratorTest::Init(
+ /*current_migration_version=*/1);
+
+ EXPECT_CALL(sync_delegate(), IsSyncingPasswordsEnabled)
+ .WillOnce(Return(true));
const MigrationParam& p = GetParam();
@@ -320,4 +392,168 @@ INSTANTIATE_TEST_SUITE_P(
.android_logins = {{1, "old_password", base::Days(1)}, {3}},
.merged_logins = {{1, "new_password", base::Days(2)}, {2}, {3}}}));
+struct MigrationParamForMetrics {
+ // Whether this is initial or rolling migration.
+ bool is_initial_migration;
+ // Whether migration was completed successfully or not.
+ bool is_successful_migration;
+};
+
+class BuiltInBackendToAndroidBackendMigratorTestMetrics
+ : public BuiltInBackendToAndroidBackendMigratorTest,
+ public testing::WithParamInterface<MigrationParamForMetrics> {
+ protected:
+ BuiltInBackendToAndroidBackendMigratorTestMetrics() {
+ prefs()->registry()->RegisterIntegerPref(
+ prefs::kCurrentMigrationVersionToGoogleMobileServices, 0);
+ prefs()->registry()->RegisterDoublePref(prefs::kTimeOfLastMigrationAttempt,
+ 0.0);
+ if (GetParam().is_initial_migration) {
+ feature_list().InitAndEnableFeatureWithParameters(
+ /*enabled_feature=*/features::kUnifiedPasswordManagerMigration,
+ {{"migration_version", "1"}});
+ latency_metric_ =
+ "PasswordManager.UnifiedPasswordManager.InitialMigration.Latency";
+ success_metric_ =
+ "PasswordManager.UnifiedPasswordManager.InitialMigration.Success";
+ } else {
+ feature_list().InitWithFeaturesAndParameters(
+ /*enabled_features=*/{{features::kUnifiedPasswordManagerMigration,
+ {{"migration_version", "1"}}},
+ {features::kUnifiedPasswordManagerAndroid,
+ {{}}}},
+ /*disabled_features=*/{});
+ // Setup the pref to indicate that the initial migration has happened
+ // already.
+ prefs()->SetInteger(prefs::kCurrentMigrationVersionToGoogleMobileServices,
+ 1);
+ latency_metric_ =
+ "PasswordManager.UnifiedPasswordManager.RollingMigration.Latency";
+ success_metric_ =
+ "PasswordManager.UnifiedPasswordManager.RollingMigration.Success";
+ }
+
+ migrator_ = std::make_unique<BuiltInBackendToAndroidBackendMigrator>(
+ &built_in_backend_, &android_backend_, prefs(), &sync_delegate());
+ }
+
+ std::string latency_metric_;
+ std::string success_metric_;
+ ::testing::StrictMock<MockPasswordStoreBackend> built_in_backend_;
+ ::testing::StrictMock<MockPasswordStoreBackend> android_backend_;
+ std::unique_ptr<BuiltInBackendToAndroidBackendMigrator> migrator_;
+};
+
+TEST_P(BuiltInBackendToAndroidBackendMigratorTestMetrics,
+ MigrationMetricsTest) {
+ base::HistogramTester histogram_tester;
+
+ EXPECT_CALL(sync_delegate(), IsSyncingPasswordsEnabled)
+ .WillOnce(Return(false));
+
+ EXPECT_CALL(built_in_backend_, GetAllLoginsAsync)
+ .WillOnce(WithArg<0>(Invoke([](LoginsOrErrorReply reply) -> void {
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(std::move(reply), LoginsResult()));
+ })));
+ EXPECT_CALL(android_backend_, GetAllLoginsAsync)
+ .WillOnce(WithArg<0>(Invoke([](LoginsOrErrorReply reply) -> void {
+ LoginsResultOrError result =
+ GetParam().is_successful_migration
+ ? LoginsResultOrError(LoginsResult())
+ : LoginsResultOrError(PasswordStoreBackendError::kUnspecified);
+ base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, base::BindOnce(std::move(reply), std::move(result)),
+ kLatencyDelta);
+ })));
+
+ migrator_->StartMigrationIfNecessary();
+ FastForwardBy(kLatencyDelta);
+
+ histogram_tester.ExpectTotalCount(latency_metric_, 1);
+ histogram_tester.ExpectTimeBucketCount(latency_metric_, kLatencyDelta, 1);
+ histogram_tester.ExpectTotalCount(success_metric_, 1);
+ histogram_tester.ExpectBucketCount(success_metric_, true,
+ GetParam().is_successful_migration);
+ histogram_tester.ExpectBucketCount(success_metric_, false,
+ !GetParam().is_successful_migration);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ BuiltInBackendToAndroidBackendMigratorTest,
+ BuiltInBackendToAndroidBackendMigratorTestMetrics,
+ testing::Values(MigrationParamForMetrics{.is_initial_migration = true,
+ .is_successful_migration = true},
+ MigrationParamForMetrics{.is_initial_migration = true,
+ .is_successful_migration = false},
+ MigrationParamForMetrics{.is_initial_migration = false,
+ .is_successful_migration = true},
+ MigrationParamForMetrics{
+ .is_initial_migration = false,
+ .is_successful_migration = false}));
+
+class BuiltInBackendToAndroidBackendMigratorWithMockAndroidBackendTest
+ : public BuiltInBackendToAndroidBackendMigratorTest {
+ protected:
+ BuiltInBackendToAndroidBackendMigratorWithMockAndroidBackendTest() {
+ prefs()->registry()->RegisterIntegerPref(
+ prefs::kCurrentMigrationVersionToGoogleMobileServices, 0);
+ prefs()->registry()->RegisterDoublePref(prefs::kTimeOfLastMigrationAttempt,
+ 0.0);
+ feature_list().InitAndEnableFeatureWithParameters(
+ /*enabled_feature=*/features::kUnifiedPasswordManagerMigration,
+ {{"migration_version", "1"}});
+
+ migrator_ = std::make_unique<BuiltInBackendToAndroidBackendMigrator>(
+ &built_in_backend_, &android_backend_, prefs(), &sync_delegate_);
+ }
+
+ PasswordStoreBackend& built_in_backend() { return built_in_backend_; }
+
+ ::testing::NiceMock<MockPasswordStoreBackend> android_backend_;
+ std::unique_ptr<BuiltInBackendToAndroidBackendMigrator> migrator_;
+
+ private:
+ FakePasswordStoreBackend built_in_backend_;
+};
+
+TEST_F(BuiltInBackendToAndroidBackendMigratorWithMockAndroidBackendTest,
+ ShouldNotCompleteMigrationWhenWritingToAndroidBackendFails) {
+ EXPECT_CALL(sync_delegate(), IsSyncingPasswordsEnabled)
+ .WillOnce(Return(false));
+ // Add two credentials to the built-in backend.
+ built_in_backend().AddLoginAsync(CreateTestPasswordForm(/*index=*/1),
+ base::DoNothing());
+ built_in_backend().AddLoginAsync(CreateTestPasswordForm(/*index=*/2),
+ base::DoNothing());
+
+ // Simulate an empty Android backend.
+ EXPECT_CALL(android_backend_, GetAllLoginsAsync)
+ .WillOnce(WithArg<0>(Invoke([](LoginsOrErrorReply reply) -> void {
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(std::move(reply), LoginsResult()));
+ })));
+
+ // Simulate an Android backend that fails to write by returning an empty
+ // changelist.
+ ON_CALL(android_backend_, AddLoginAsync)
+ .WillByDefault(
+ WithArg<1>(Invoke([](PasswordStoreChangeListReply callback) -> void {
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::BindOnce(std::move(callback), PasswordStoreChangeList()));
+ })));
+
+ // Once one AddLoginAsync() call fails, all consecutive ones will not be
+ // executed. Check that exactly ont AddLoginAsync() is called.
+ EXPECT_CALL(android_backend_, AddLoginAsync).Times(1);
+
+ migrator_->StartMigrationIfNecessary();
+
+ // Migration version is still 0 since migration didn't complete.
+ EXPECT_EQ(0, prefs()->GetInteger(
+ prefs::kCurrentMigrationVersionToGoogleMobileServices));
+ RunUntilIdle();
+}
+
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/capabilities_service.h b/chromium/components/password_manager/core/browser/capabilities_service.h
new file mode 100644
index 00000000000..d80bd4d64eb
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/capabilities_service.h
@@ -0,0 +1,35 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_CAPABILITIES_SERVICE_H_
+#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_CAPABILITIES_SERVICE_H_
+
+#include <set>
+#include <vector>
+
+#include "base/callback.h"
+#include "url/origin.h"
+
+namespace password_manager {
+
+// The class fetches capabilities (e.g. availability of a script for automated
+// password changes) for different origins.
+class CapabilitiesService {
+ public:
+ using ResponseCallback =
+ base::OnceCallback<void(const std::set<url::Origin>&)>;
+
+ virtual ~CapabilitiesService() = default;
+
+ // Returns the subset of provided |origins| for which a password change script
+ // is available. In case of a network error while fetching capabilities, the
+ // result list will be empty.
+ virtual void QueryPasswordChangeScriptAvailability(
+ const std::vector<url::Origin>& origins,
+ ResponseCallback callback) = 0;
+};
+
+} // namespace password_manager
+
+#endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_CAPABILITIES_SERVICE_H_
diff --git a/chromium/components/password_manager/core/browser/capabilities_service_impl.cc b/chromium/components/password_manager/core/browser/capabilities_service_impl.cc
new file mode 100644
index 00000000000..20b3c1471cf
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/capabilities_service_impl.cc
@@ -0,0 +1,109 @@
+// Copyright 2022 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.
+
+#include "components/password_manager/core/browser/capabilities_service_impl.h"
+
+#include "base/containers/flat_set.h"
+#include "base/hash/legacy_hash.h"
+#include "base/logging.h"
+#include "base/metrics/histogram_functions.h"
+#include "base/ranges/algorithm.h"
+#include "base/stl_util.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "components/password_manager/core/common/password_manager_features.h"
+#include "net/http/http_status_code.h"
+#include "url/gurl.h"
+
+namespace {
+
+// Number of leading bits of the domain url hashes to send to the server.
+constexpr uint32_t kHashPrefixSize = 15;
+
+constexpr char kRequestIntent[] = "PASSWORD_CHANGE";
+// Parameter that specifies the script's experiments.
+const char kExperimentsParameterName[] = "EXPERIMENT_IDS";
+// Server side experiment id that specifies when a script has only been released
+// to a small subset of clients.
+const char kScriptLiveExperiment[] = "3345172";
+
+bool ScriptInLiveExperiment(
+ const base::flat_map<std::string, std::string>& script_parameters) {
+ auto params_iter = script_parameters.find(kExperimentsParameterName);
+ if (params_iter == script_parameters.end()) {
+ return false;
+ }
+
+ const std::vector<std::string> experiments = base::SplitString(
+ params_iter->second, ",", base::WhitespaceHandling::TRIM_WHITESPACE,
+ base::SplitResult::SPLIT_WANT_NONEMPTY);
+
+ return base::ranges::count(experiments, kScriptLiveExperiment) > 0;
+}
+
+std::string CanonicalizeOrigin(const url::Origin& origin) {
+ std::string url_str = origin.GetURL().spec();
+ // Remove trailing '/' if exist.
+ base::TrimString(url_str, "/", &url_str);
+ return url_str;
+}
+
+uint64_t GetHashPrefix(const url::Origin& origin) {
+ const std::string& canonicalized_url = CanonicalizeOrigin(origin);
+ uint64_t hash = base::legacy::CityHash64(
+ base::as_bytes(base::make_span(canonicalized_url)));
+ return hash >> (64 - kHashPrefixSize);
+}
+} // namespace
+
+CapabilitiesServiceImpl::CapabilitiesServiceImpl(
+ std::unique_ptr<autofill_assistant::AutofillAssistant> autofill_assistant)
+ : autofill_assistant_(std::move(autofill_assistant)) {}
+
+CapabilitiesServiceImpl::~CapabilitiesServiceImpl() = default;
+
+void CapabilitiesServiceImpl::QueryPasswordChangeScriptAvailability(
+ const std::vector<url::Origin>& origins,
+ ResponseCallback callback) {
+ if (origins.empty()) {
+ std::move(callback).Run(std::set<url::Origin>());
+ return;
+ }
+
+ std::vector<uint64_t> hash_prefixes;
+ base::ranges::transform(origins, std::back_inserter(hash_prefixes),
+ GetHashPrefix);
+
+ autofill_assistant_->GetCapabilitiesByHashPrefix(
+ kHashPrefixSize, hash_prefixes, kRequestIntent,
+ base::BindOnce(&CapabilitiesServiceImpl::OnGetCapabilitiesResult,
+ base::Unretained(this), origins, std::move(callback)));
+}
+
+void CapabilitiesServiceImpl::OnGetCapabilitiesResult(
+ const std::vector<url::Origin>& origins,
+ ResponseCallback callback,
+ int http_status,
+ const std::vector<CapabilitiesInfo>& infos) {
+ base::UmaHistogramSparse(
+ "PasswordManager.CapabilitiesService.HttpResponseCode", http_status);
+ if (http_status != net::HTTP_OK) {
+ std::move(callback).Run(std::set<url::Origin>());
+ return;
+ }
+
+ std::set<url::Origin> infos_origin_set;
+ for (const CapabilitiesInfo& info : infos) {
+ // Checks if the script is visible to the client.
+ if (password_manager::features::kPasswordChangeLiveExperimentParam.Get() ||
+ !ScriptInLiveExperiment(info.script_parameters)) {
+ infos_origin_set.insert(url::Origin::Create(GURL(info.url)));
+ }
+ }
+ std::set<url::Origin> origins_set(origins.begin(), origins.end());
+ std::set<url::Origin> response =
+ base::STLSetIntersection<std::set<url::Origin>>(origins_set,
+ infos_origin_set);
+ std::move(callback).Run(response);
+}
diff --git a/chromium/components/password_manager/core/browser/capabilities_service_impl.h b/chromium/components/password_manager/core/browser/capabilities_service_impl.h
new file mode 100644
index 00000000000..ed3c622f927
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/capabilities_service_impl.h
@@ -0,0 +1,41 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_CAPABILITIES_SERVICE_IMPL_H_
+#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_CAPABILITIES_SERVICE_IMPL_H_
+
+#include "components/autofill_assistant/browser/public/autofill_assistant.h"
+#include "components/password_manager/core/browser/capabilities_service.h"
+
+class CapabilitiesServiceImpl : public password_manager::CapabilitiesService {
+ public:
+ explicit CapabilitiesServiceImpl(
+ std::unique_ptr<autofill_assistant::AutofillAssistant>
+ autofill_assistant);
+ CapabilitiesServiceImpl(const CapabilitiesServiceImpl&) = delete;
+ CapabilitiesServiceImpl& operator=(const CapabilitiesServiceImpl&) = delete;
+
+ ~CapabilitiesServiceImpl() override;
+
+ // CapabilitiesService:
+ void QueryPasswordChangeScriptAvailability(
+ const std::vector<url::Origin>& origins,
+ ResponseCallback callback) override;
+
+ private:
+ using CapabilitiesInfo =
+ autofill_assistant::AutofillAssistant::CapabilitiesInfo;
+
+ void OnGetCapabilitiesResult(
+ const std::vector<url::Origin>& origins,
+ ResponseCallback callback,
+ int http_status,
+ const std::vector<
+ autofill_assistant::AutofillAssistant::CapabilitiesInfo>& infos);
+
+ // Used for capabilities requests.
+ std::unique_ptr<autofill_assistant::AutofillAssistant> autofill_assistant_;
+};
+
+#endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_CAPABILITIES_SERVICE_IMPL_H_
diff --git a/chromium/components/password_manager/core/browser/capabilities_service_impl_unittest.cc b/chromium/components/password_manager/core/browser/capabilities_service_impl_unittest.cc
new file mode 100644
index 00000000000..7562401162b
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/capabilities_service_impl_unittest.cc
@@ -0,0 +1,215 @@
+// Copyright 2022 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.
+
+#include "components/password_manager/core/browser/capabilities_service_impl.h"
+
+#include <set>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/memory/raw_ptr.h"
+#include "base/test/gmock_callback_support.h"
+#include "base/test/metrics/histogram_tester.h"
+#include "base/test/mock_callback.h"
+#include "base/test/scoped_feature_list.h"
+#include "components/autofill_assistant/browser/public/autofill_assistant.h"
+#include "components/password_manager/core/common/password_manager_features.h"
+#include "net/http/http_status_code.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace password_manager {
+namespace {
+
+using ::base::test::RunOnceCallback;
+using ::testing::_;
+using ::testing::NiceMock;
+using CapabilitiesInfo =
+ autofill_assistant::AutofillAssistant::CapabilitiesInfo;
+
+constexpr uint32_t kHashPrefixSize = 15;
+constexpr uint64_t kExampleDotComHash = 2170UL;
+constexpr uint64_t kTestDotComHash = 17534UL;
+constexpr uint64_t kDummyurlDotComHash = 15654UL;
+
+constexpr char kPasswordChangeIntent[] = "PASSWORD_CHANGE";
+
+class MockAutofillAssistant : public autofill_assistant::AutofillAssistant {
+ public:
+ MockAutofillAssistant() = default;
+ ~MockAutofillAssistant() override = default;
+
+ MOCK_METHOD4(GetCapabilitiesByHashPrefix,
+ void(uint32_t hash_prefix_length,
+ const std::vector<uint64_t>& hash_prefix,
+ const std::string& intent,
+ GetCapabilitiesResponseCallback callback));
+};
+
+class CapabilitiesServiceImplTest : public ::testing::Test {
+ public:
+ CapabilitiesServiceImplTest() {
+ auto autofill_assistant =
+ std::make_unique<NiceMock<MockAutofillAssistant>>();
+ mock_autofill_assistant_ = autofill_assistant.get();
+
+ service_ = std::make_unique<CapabilitiesServiceImpl>(
+ std::move(autofill_assistant));
+ }
+ ~CapabilitiesServiceImplTest() override = default;
+
+ protected:
+ raw_ptr<NiceMock<MockAutofillAssistant>> mock_autofill_assistant_;
+ std::unique_ptr<CapabilitiesServiceImpl> service_;
+};
+
+TEST_F(CapabilitiesServiceImplTest, FetchCapabilitiesEmptyResponse) {
+ base::HistogramTester histogram_tester;
+ std::vector<url::Origin> origins = {
+ url::Origin::Create(GURL("https://example.com")),
+ url::Origin::Create(GURL("https://test.com"))};
+
+ EXPECT_CALL(*mock_autofill_assistant_,
+ GetCapabilitiesByHashPrefix(
+ kHashPrefixSize,
+ std::vector<uint64_t>{kExampleDotComHash, kTestDotComHash},
+ kPasswordChangeIntent, _))
+ .WillOnce(
+ RunOnceCallback<3>(net::HTTP_OK, std::vector<CapabilitiesInfo>()));
+
+ base::MockCallback<password_manager::CapabilitiesService::ResponseCallback>
+ mock_response_callback;
+ EXPECT_CALL(mock_response_callback, Run(std::set<url::Origin>()));
+
+ service_->QueryPasswordChangeScriptAvailability(origins,
+ mock_response_callback.Get());
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.CapabilitiesService.HttpResponseCode",
+ net::HttpStatusCode::HTTP_OK, 1u);
+}
+
+TEST_F(CapabilitiesServiceImplTest, FetchCapabilitiesEmptyRequest) {
+ base::HistogramTester histogram_tester;
+ EXPECT_CALL(*mock_autofill_assistant_, GetCapabilitiesByHashPrefix).Times(0);
+ base::MockCallback<password_manager::CapabilitiesService::ResponseCallback>
+ mock_response_callback;
+ EXPECT_CALL(mock_response_callback, Run(std::set<url::Origin>()));
+
+ service_->QueryPasswordChangeScriptAvailability({},
+ mock_response_callback.Get());
+ histogram_tester.ExpectTotalCount(
+ "PasswordManager.CapabilitiesService.HttpResponseCode", 0u);
+}
+
+TEST_F(CapabilitiesServiceImplTest, BackendRequestFailed) {
+ base::HistogramTester histogram_tester;
+ EXPECT_CALL(*mock_autofill_assistant_, GetCapabilitiesByHashPrefix)
+ .WillOnce(RunOnceCallback<3>(net::HTTP_FORBIDDEN,
+ std::vector<CapabilitiesInfo>()));
+
+ base::MockCallback<password_manager::CapabilitiesService::ResponseCallback>
+ mock_response_callback;
+ EXPECT_CALL(mock_response_callback, Run(std::set<url::Origin>()));
+
+ std::vector<url::Origin> origins = {
+ url::Origin::Create(GURL("https://example.com")),
+ url::Origin::Create(GURL("https://test.com"))};
+
+ service_->QueryPasswordChangeScriptAvailability(origins,
+ mock_response_callback.Get());
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.CapabilitiesService.HttpResponseCode",
+ net::HTTP_FORBIDDEN, 1u);
+}
+
+TEST_F(CapabilitiesServiceImplTest, FetchCapabilitiesSuccess) {
+ base::HistogramTester histogram_tester;
+ std::vector<CapabilitiesInfo> capabilities_reponse = {
+ CapabilitiesInfo{"https://foo.test.com", {}},
+ CapabilitiesInfo{"https://bar.test.com", {}},
+ CapabilitiesInfo{"https://example.com", {}},
+ CapabilitiesInfo{"https://test.com", {}},
+ CapabilitiesInfo{"https://dummyurl.com",
+ {{{"EXPERIMENT_IDS", "3345172"}}}},
+ };
+
+ EXPECT_CALL(*mock_autofill_assistant_,
+ GetCapabilitiesByHashPrefix(
+ kHashPrefixSize,
+ std::vector<uint64_t>{kExampleDotComHash, kTestDotComHash,
+ kDummyurlDotComHash},
+ kPasswordChangeIntent, _))
+ .WillOnce(RunOnceCallback<3>(net::HTTP_OK, capabilities_reponse));
+
+ base::MockCallback<password_manager::CapabilitiesService::ResponseCallback>
+ mock_response_callback;
+
+ EXPECT_CALL(mock_response_callback,
+ Run(std::set<url::Origin>{
+ url::Origin::Create(GURL("https://example.com")),
+ url::Origin::Create(GURL("https://test.com")),
+ }));
+
+ std::vector<url::Origin> origins = {
+ url::Origin::Create(GURL("https://example.com")),
+ url::Origin::Create(GURL("https://test.com")),
+ url::Origin::Create(GURL("https://dummyurl.com")),
+ };
+
+ service_->QueryPasswordChangeScriptAvailability(origins,
+ mock_response_callback.Get());
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.CapabilitiesService.HttpResponseCode",
+ net::HttpStatusCode::HTTP_OK, 1u);
+}
+
+TEST_F(CapabilitiesServiceImplTest, FetchCapabilitiesClientInLiveExperiment) {
+ base::HistogramTester histogram_tester;
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeatureWithParameters(
+ password_manager::features::kPasswordDomainCapabilitiesFetching,
+ {{"live_experiment", "true"}});
+
+ std::vector<CapabilitiesInfo> capabilities_reponse = {
+ CapabilitiesInfo{"https://foo.test.com", {}},
+ CapabilitiesInfo{"https://bar.test.com", {}},
+ CapabilitiesInfo{"https://example.com", {}},
+ CapabilitiesInfo{"https://test.com", {}},
+ CapabilitiesInfo{"https://dummyurl.com",
+ {{{"EXPERIMENT_IDS", "3345172"}}}},
+ };
+
+ EXPECT_CALL(*mock_autofill_assistant_,
+ GetCapabilitiesByHashPrefix(
+ kHashPrefixSize,
+ std::vector<uint64_t>{kExampleDotComHash, kTestDotComHash,
+ kDummyurlDotComHash},
+ kPasswordChangeIntent, _))
+ .WillOnce(RunOnceCallback<3>(net::HTTP_OK, capabilities_reponse));
+
+ base::MockCallback<password_manager::CapabilitiesService::ResponseCallback>
+ mock_response_callback;
+ EXPECT_CALL(mock_response_callback,
+ Run(std::set<url::Origin>{
+ url::Origin::Create(GURL("https://example.com")),
+ url::Origin::Create(GURL("https://test.com")),
+ url::Origin::Create(GURL("https://dummyurl.com")),
+ }));
+
+ std::vector<url::Origin> origins = {
+ url::Origin::Create(GURL("https://example.com")),
+ url::Origin::Create(GURL("https://test.com")),
+ url::Origin::Create(GURL("https://dummyurl.com")),
+ };
+
+ service_->QueryPasswordChangeScriptAvailability(origins,
+ mock_response_callback.Get());
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.CapabilitiesService.HttpResponseCode",
+ net::HttpStatusCode::HTTP_OK, 1u);
+}
+
+} // namespace
+} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/credential_manager_impl.cc b/chromium/components/password_manager/core/browser/credential_manager_impl.cc
index 676aa807b82..e52e4776da1 100644
--- a/chromium/components/password_manager/core/browser/credential_manager_impl.cc
+++ b/chromium/components/password_manager/core/browser/credential_manager_impl.cc
@@ -57,8 +57,10 @@ void CredentialManagerImpl::Store(const CredentialInfo& credential,
CreatePasswordFormFromCredentialInfo(credential, origin));
// Check whether a stored password credential was leaked.
- if (credential.type == CredentialType::CREDENTIAL_TYPE_PASSWORD)
- leak_delegate_.StartLeakCheck(*form);
+ if (credential.type == CredentialType::CREDENTIAL_TYPE_PASSWORD) {
+ leak_delegate_.StartLeakCheck(
+ *form, /*submitted_form_was_likely_signup_form=*/false);
+ }
std::string signon_realm = origin.GetURL().spec();
PasswordFormDigest observed_digest(PasswordForm::Scheme::kHtml, signon_realm,
diff --git a/chromium/components/password_manager/core/browser/export/csv_writer.cc b/chromium/components/password_manager/core/browser/export/csv_writer.cc
index dfc0ad798f9..3610ed568ed 100644
--- a/chromium/components/password_manager/core/browser/export/csv_writer.cc
+++ b/chromium/components/password_manager/core/browser/export/csv_writer.cc
@@ -52,7 +52,7 @@ void CSVFormatter::AppendValue(const std::string& raw_value) {
}
void CSVFormatter::EndLine() {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
const char kLineEnding[] = "\r\n";
#else
const char kLineEnding[] = "\n";
diff --git a/chromium/components/password_manager/core/browser/export/csv_writer_unittest.cc b/chromium/components/password_manager/core/browser/export/csv_writer_unittest.cc
index 137f6ebb5c6..c5928acaf1d 100644
--- a/chromium/components/password_manager/core/browser/export/csv_writer_unittest.cc
+++ b/chromium/components/password_manager/core/browser/export/csv_writer_unittest.cc
@@ -7,7 +7,7 @@
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#define CSV_EOL_SEQUENCE "\r\n"
#else
#define CSV_EOL_SEQUENCE "\n"
diff --git a/chromium/components/password_manager/core/browser/export/password_manager_exporter.cc b/chromium/components/password_manager/core/browser/export/password_manager_exporter.cc
index c394f10209b..60e6fd3af80 100644
--- a/chromium/components/password_manager/core/browser/export/password_manager_exporter.cc
+++ b/chromium/components/password_manager/core/browser/export/password_manager_exporter.cc
@@ -82,7 +82,7 @@ PasswordManagerExporter::PasswordManagerExporter(
last_progress_status_(ExportProgressStatus::NOT_STARTED),
write_function_(base::BindRepeating(&DefaultWriteFunction)),
delete_function_(base::BindRepeating(&DefaultDeleteFunction)),
-#if defined(OS_POSIX)
+#if BUILDFLAG(IS_POSIX)
set_permissions_function_(
base::BindRepeating(base::SetPosixFilePermissions)),
#else
diff --git a/chromium/components/password_manager/core/browser/export/password_manager_exporter_unittest.cc b/chromium/components/password_manager/core/browser/export/password_manager_exporter_unittest.cc
index 0553723181e..c2e610604ce 100644
--- a/chromium/components/password_manager/core/browser/export/password_manager_exporter_unittest.cc
+++ b/chromium/components/password_manager/core/browser/export/password_manager_exporter_unittest.cc
@@ -44,7 +44,7 @@ using DeleteCallback = PasswordManagerExporter::DeleteCallback;
using SetPosixFilePermissionsCallback =
PasswordManagerExporter::SetPosixFilePermissionsCallback;
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
const base::FilePath::CharType kNullFileName[] = FILE_PATH_LITERAL("/nul");
#else
const base::FilePath::CharType kNullFileName[] = FILE_PATH_LITERAL("/dev/null");
@@ -255,7 +255,7 @@ TEST_F(PasswordManagerExporterTest, CancelAfterExporting) {
task_environment_.RunUntilIdle();
}
-#if defined(OS_POSIX)
+#if BUILDFLAG(IS_POSIX)
// Chrome creates files using the broadest permissions allowed. Passwords are
// sensitive and should be explicitly limited to the owner.
TEST_F(PasswordManagerExporterTest, OutputHasRestrictedPermissions) {
diff --git a/chromium/components/password_manager/core/browser/fake_password_store_backend.cc b/chromium/components/password_manager/core/browser/fake_password_store_backend.cc
index b0f55816612..d6e86b38af3 100644
--- a/chromium/components/password_manager/core/browser/fake_password_store_backend.cc
+++ b/chromium/components/password_manager/core/browser/fake_password_store_backend.cc
@@ -16,10 +16,6 @@ namespace password_manager {
FakePasswordStoreBackend::FakePasswordStoreBackend() = default;
FakePasswordStoreBackend::~FakePasswordStoreBackend() = default;
-base::WeakPtr<PasswordStoreBackend> FakePasswordStoreBackend::GetWeakPtr() {
- return weak_ptr_factory_.GetWeakPtr();
-}
-
void FakePasswordStoreBackend::InitBackend(
RemoteChangesReceived remote_form_changes_received,
base::RepeatingClosure sync_enabled_or_disabled_cb,
@@ -131,6 +127,10 @@ FakePasswordStoreBackend::CreateSyncControllerDelegate() {
return nullptr;
}
+void FakePasswordStoreBackend::ClearAllLocalPasswords() {
+ NOTIMPLEMENTED();
+}
+
LoginsResult FakePasswordStoreBackend::GetAllLoginsInternal() {
LoginsResult result;
for (const auto& elements : stored_passwords_) {
diff --git a/chromium/components/password_manager/core/browser/fake_password_store_backend.h b/chromium/components/password_manager/core/browser/fake_password_store_backend.h
index 5a545608272..7a2d4b6a159 100644
--- a/chromium/components/password_manager/core/browser/fake_password_store_backend.h
+++ b/chromium/components/password_manager/core/browser/fake_password_store_backend.h
@@ -29,7 +29,6 @@ class FakePasswordStoreBackend : public PasswordStoreBackend {
private:
// Implements PasswordStoreBackend interface.
- base::WeakPtr<PasswordStoreBackend> GetWeakPtr() override;
void InitBackend(RemoteChangesReceived remote_form_changes_received,
base::RepeatingClosure sync_enabled_or_disabled_cb,
base::OnceCallback<void(bool)> completion) override;
@@ -63,6 +62,7 @@ class FakePasswordStoreBackend : public PasswordStoreBackend {
FieldInfoStore* GetFieldInfoStore() override;
std::unique_ptr<syncer::ProxyModelTypeControllerDelegate>
CreateSyncControllerDelegate() override;
+ void ClearAllLocalPasswords() override;
LoginsResult GetAllLoginsInternal();
LoginsResult GetAutofillableLoginsInternal();
@@ -78,7 +78,6 @@ class FakePasswordStoreBackend : public PasswordStoreBackend {
PasswordStoreChangeList RemoveLoginInternal(const PasswordForm& form);
PasswordMap stored_passwords_;
- base::WeakPtrFactory<FakePasswordStoreBackend> weak_ptr_factory_{this};
};
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/field_info_manager.cc b/chromium/components/password_manager/core/browser/field_info_manager.cc
index 334718e3123..3f08c3ef205 100644
--- a/chromium/components/password_manager/core/browser/field_info_manager.cc
+++ b/chromium/components/password_manager/core/browser/field_info_manager.cc
@@ -28,7 +28,7 @@ void FieldInfoManagerImpl::AddFieldType(
autofill::FormSignature form_signature,
autofill::FieldSignature field_signature,
autofill::ServerFieldType field_type) {
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
// TODO(https://crbug.com/1051914): Enable on Android after making local
// heuristics reliable.
field_types_[std::make_pair(form_signature, field_signature)] = field_type;
@@ -37,7 +37,7 @@ void FieldInfoManagerImpl::AddFieldType(
info_store->AddFieldInfo(
{form_signature, field_signature, field_type, base::Time::Now()});
}
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
}
autofill::ServerFieldType FieldInfoManagerImpl::GetFieldType(
diff --git a/chromium/components/password_manager/core/browser/field_info_manager_unittest.cc b/chromium/components/password_manager/core/browser/field_info_manager_unittest.cc
index 0adccbb23fd..d0f984d2841 100644
--- a/chromium/components/password_manager/core/browser/field_info_manager_unittest.cc
+++ b/chromium/components/password_manager/core/browser/field_info_manager_unittest.cc
@@ -47,7 +47,7 @@ class FieldInfoManagerTest : public testing::Test {
Time::FromTimeT(10)});
store_ = new testing::StrictMock<MockPasswordStoreInterface>();
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
EXPECT_CALL(*store_, GetFieldInfoStore)
.WillRepeatedly(testing::Return(&mock_field_store_));
EXPECT_CALL(mock_field_store_, GetAllFieldInfo);
@@ -75,18 +75,18 @@ TEST_F(FieldInfoManagerTest, AddFieldType) {
field_info_manager_->GetFieldType(autofill::FormSignature(101u),
autofill::FieldSignature(1u)));
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
EXPECT_CALL(mock_field_store_, AddFieldInfo).Times(0);
#else
EXPECT_CALL(mock_field_store_, AddFieldInfo(FieldInfoHasData(
autofill::FormSignature(101u),
autofill::FieldSignature(1u), PASSWORD)));
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
field_info_manager_->AddFieldType(autofill::FormSignature(101u),
autofill::FieldSignature(1u), PASSWORD);
task_environment_.RunUntilIdle();
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
EXPECT_EQ(UNKNOWN_TYPE,
field_info_manager_->GetFieldType(autofill::FormSignature(101u),
autofill::FieldSignature(1u)));
@@ -94,7 +94,7 @@ TEST_F(FieldInfoManagerTest, AddFieldType) {
EXPECT_EQ(PASSWORD,
field_info_manager_->GetFieldType(autofill::FormSignature(101u),
autofill::FieldSignature(1u)));
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
}
TEST_F(FieldInfoManagerTest, OnGetAllFieldInfo) {
diff --git a/chromium/components/password_manager/core/browser/field_info_table.cc b/chromium/components/password_manager/core/browser/field_info_table.cc
index 9915ab9650e..afc05cf47d6 100644
--- a/chromium/components/password_manager/core/browser/field_info_table.cc
+++ b/chromium/components/password_manager/core/browser/field_info_table.cc
@@ -16,7 +16,7 @@ namespace {
constexpr char kFieldInfoTableName[] = "field_info";
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
// Represents columns of the FieldInfoTable. Used with SQL queries that use all
// the columns.
enum class FieldInfoTableColumn {
@@ -71,16 +71,16 @@ bool operator==(const FieldInfo& lhs, const FieldInfo& rhs) {
void FieldInfoTable::Init(sql::Database* db) {
db_ = db;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Local predictions on Android are not reliable, so they are not used now.
// Remove the table which might have created in the old versions.
// TODO(https://crbug.com/1051914): remove this after M-83.
DropTableIfExists();
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
}
bool FieldInfoTable::CreateTableIfNecessary() {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
return true;
#else
if (db_->DoesTableExist(kFieldInfoTableName))
@@ -88,7 +88,7 @@ bool FieldInfoTable::CreateTableIfNecessary() {
SQLTableBuilder builder(kFieldInfoTableName);
InitializeFieldInfoBuilder(&builder);
return builder.CreateTable(db_);
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
}
bool FieldInfoTable::DropTableIfExists() {
@@ -98,7 +98,7 @@ bool FieldInfoTable::DropTableIfExists() {
}
bool FieldInfoTable::AddRow(const FieldInfo& field) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
return false;
#else
sql::Statement s(db_->GetCachedStatement(
@@ -115,12 +115,12 @@ bool FieldInfoTable::AddRow(const FieldInfo& field) {
s.BindInt64(GetColumnNumber(FieldInfoTableColumn::kCreateTime),
field.create_time.ToDeltaSinceWindowsEpoch().InMicroseconds());
return s.Run();
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
}
bool FieldInfoTable::RemoveRowsByTime(base::Time remove_begin,
base::Time remove_end) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
return false;
#else
sql::Statement s(
@@ -130,11 +130,11 @@ bool FieldInfoTable::RemoveRowsByTime(base::Time remove_begin,
s.BindInt64(0, remove_begin.ToDeltaSinceWindowsEpoch().InMicroseconds());
s.BindInt64(1, remove_end.ToDeltaSinceWindowsEpoch().InMicroseconds());
return s.Run();
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
}
std::vector<FieldInfo> FieldInfoTable::GetAllRows() {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
return std::vector<FieldInfo>();
#else
sql::Statement s(db_->GetCachedStatement(
@@ -142,13 +142,13 @@ std::vector<FieldInfo> FieldInfoTable::GetAllRows() {
"SELECT form_signature, field_signature, field_type, create_time FROM "
"field_info"));
return StatementToFieldInfo(&s);
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
}
// Returns all FieldInfo from the database which have |form_signature|.
std::vector<FieldInfo> FieldInfoTable::GetAllRowsForFormSignature(
uint64_t form_signature) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
return std::vector<FieldInfo>();
#else
sql::Statement s(
@@ -158,7 +158,7 @@ std::vector<FieldInfo> FieldInfoTable::GetAllRowsForFormSignature(
"WHERE form_signature = ?"));
s.BindInt64(0, form_signature);
return StatementToFieldInfo(&s);
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
}
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/field_info_table_unittest.cc b/chromium/components/password_manager/core/browser/field_info_table_unittest.cc
index 1dafc2c3037..97967092f8e 100644
--- a/chromium/components/password_manager/core/browser/field_info_table_unittest.cc
+++ b/chromium/components/password_manager/core/browser/field_info_table_unittest.cc
@@ -56,7 +56,7 @@ class FieldInfoTableTest : public testing::Test {
std::vector<FieldInfo> test_data_;
};
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
TEST_F(FieldInfoTableTest, AddRow) {
EXPECT_TRUE(field_info_table_->AddRow(test_data_[0]));
EXPECT_EQ(test_data_[0], field_info_table_->GetAllRows()[0]);
@@ -120,7 +120,7 @@ TEST_F(FieldInfoTableTest, AddRowNoOp) {
EXPECT_TRUE(field_info_table_->GetAllRows().empty());
}
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
} // namespace
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/form_fetcher_impl.cc b/chromium/components/password_manager/core/browser/form_fetcher_impl.cc
index 82d624de7cb..98e29e47922 100644
--- a/chromium/components/password_manager/core/browser/form_fetcher_impl.cc
+++ b/chromium/components/password_manager/core/browser/form_fetcher_impl.cc
@@ -127,7 +127,7 @@ void FormFetcherImpl::Fetch() {
// The statistics isn't needed on mobile, only on desktop. Let's save some
// processor cycles.
-#if !defined(OS_IOS) && !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_IOS) && !BUILDFLAG(IS_ANDROID)
// The statistics is needed for the "Save password?" bubble.
password_manager::SmartBubbleStatsStore* stats_store =
profile_password_store->GetSmartBubbleStatsStore();
diff --git a/chromium/components/password_manager/core/browser/form_fetcher_impl_unittest.cc b/chromium/components/password_manager/core/browser/form_fetcher_impl_unittest.cc
index a7aa3d6d465..0a4167f741f 100644
--- a/chromium/components/password_manager/core/browser/form_fetcher_impl_unittest.cc
+++ b/chromium/components/password_manager/core/browser/form_fetcher_impl_unittest.cc
@@ -567,7 +567,7 @@ TEST_P(FormFetcherImplTest, Update_Reentrance) {
UnorderedElementsAre(Pointee(form_b), Pointee(form_c)));
}
-#if !defined(OS_IOS) && !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_IOS) && !BUILDFLAG(IS_ANDROID)
TEST_P(FormFetcherImplTest, FetchStatistics) {
InteractionsStats stats;
stats.origin_domain = form_digest_.url.DeprecatedGetOriginAsURL();
diff --git a/chromium/components/password_manager/core/browser/form_parsing/BUILD.gn b/chromium/components/password_manager/core/browser/form_parsing/BUILD.gn
index c0029368b24..12f6f225411 100644
--- a/chromium/components/password_manager/core/browser/form_parsing/BUILD.gn
+++ b/chromium/components/password_manager/core/browser/form_parsing/BUILD.gn
@@ -20,7 +20,7 @@ static_library("form_parsing") {
deps = [
"//components/autofill/core/browser",
"//components/autofill/core/common",
- "//components/password_manager/core/common",
+ "//components/password_manager/core/common:features",
]
}
@@ -36,7 +36,7 @@ source_set("unit_tests") {
"//base/test:test_support",
"//components/autofill/core/browser",
"//components/autofill/core/common",
- "//components/password_manager/core/common",
+ "//components/password_manager/core/common:features",
"//testing/gmock",
"//testing/gtest",
"//url",
diff --git a/chromium/components/password_manager/core/browser/form_parsing/form_parser.cc b/chromium/components/password_manager/core/browser/form_parsing/form_parser.cc
index 07263d146d1..fbcecbe895a 100644
--- a/chromium/components/password_manager/core/browser/form_parsing/form_parser.cc
+++ b/chromium/components/password_manager/core/browser/form_parsing/form_parser.cc
@@ -818,7 +818,7 @@ void ParseUsingBaseHeuristics(
// the iOS specific parts of PasswordForm are also built on fuzzer enabled
// platforms. See http://crbug.com/896594
std::u16string GetPlatformSpecificIdentifier(const FormFieldData& field) {
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
return field.unique_id;
#else
return field.name;
diff --git a/chromium/components/password_manager/core/browser/form_parsing/form_parser_unittest.cc b/chromium/components/password_manager/core/browser/form_parsing/form_parser_unittest.cc
index dbca6f0eef7..fec5f8a4348 100644
--- a/chromium/components/password_manager/core/browser/form_parsing/form_parser_unittest.cc
+++ b/chromium/components/password_manager/core/browser/form_parsing/form_parser_unittest.cc
@@ -183,7 +183,7 @@ FormData GetFormDataAndExpectation(const FormParsingTestCase& test_case,
field.name = std::u16string(field_description.name);
}
field.name_attribute = field.name;
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
field.unique_id = StampUniqueSuffix(u"unique_id");
#endif
field.form_control_type = field_description.form_control_type;
@@ -215,7 +215,7 @@ FormData GetFormDataAndExpectation(const FormParsingTestCase& test_case,
if (field_description.prediction.type != autofill::MAX_VALID_FIELD_TYPE) {
predictions->fields.push_back(field_description.prediction);
predictions->fields.back().renderer_id = renderer_id;
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
predictions->fields.back().unique_id = field.unique_id;
#endif
}
@@ -267,7 +267,7 @@ void CheckField(const std::vector<FormFieldData>& fields,
// On iOS |unique_id| is used for identifying DOM elements, so the parser should
// return it. See crbug.com/896594
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
EXPECT_EQ(element_name, field_it->unique_id);
#else
EXPECT_EQ(element_name, field_it->name);
diff --git a/chromium/components/password_manager/core/browser/form_parsing/password_field_prediction.cc b/chromium/components/password_manager/core/browser/form_parsing/password_field_prediction.cc
index d8e2f03c18b..f0345693c2e 100644
--- a/chromium/components/password_manager/core/browser/form_parsing/password_field_prediction.cc
+++ b/chromium/components/password_manager/core/browser/form_parsing/password_field_prediction.cc
@@ -5,6 +5,7 @@
#include "components/password_manager/core/browser/form_parsing/password_field_prediction.h"
#include "base/feature_list.h"
+#include "build/build_config.h"
#include "components/autofill/core/browser/form_structure.h"
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/signatures.h"
@@ -128,7 +129,7 @@ FormPredictions ConvertToFormPredictions(int driver_id,
field_predictions.back().type = server_type;
field_predictions.back().may_use_prefilled_placeholder =
field->may_use_prefilled_placeholder();
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
field_predictions.back().unique_id = field->unique_id;
#endif
}
diff --git a/chromium/components/password_manager/core/browser/form_parsing/password_field_prediction.h b/chromium/components/password_manager/core/browser/form_parsing/password_field_prediction.h
index 812842c9c34..3f39cdb54ac 100644
--- a/chromium/components/password_manager/core/browser/form_parsing/password_field_prediction.h
+++ b/chromium/components/password_manager/core/browser/form_parsing/password_field_prediction.h
@@ -36,7 +36,7 @@ CredentialFieldType DeriveFromServerFieldType(autofill::ServerFieldType type);
struct PasswordFieldPrediction {
// Field identifier generated in Blink on non-iOS platforms.
autofill::FieldRendererId renderer_id;
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
std::u16string unique_id;
#endif
autofill::FieldSignature signature;
diff --git a/chromium/components/password_manager/core/browser/hash_password_manager.cc b/chromium/components/password_manager/core/browser/hash_password_manager.cc
index 4f3b2683ebe..1cd6039100a 100644
--- a/chromium/components/password_manager/core/browser/hash_password_manager.cc
+++ b/chromium/components/password_manager/core/browser/hash_password_manager.cc
@@ -136,7 +136,7 @@ bool HashPasswordManager::SavePasswordHash(const std::string username,
// unchanged, no need to save password hash again. Instead we update the last
// sign in timestamp.
ListPrefUpdate update(prefs_, prefs::kPasswordHashDataList);
- for (base::Value& password_hash_data : update.Get()->GetList()) {
+ for (base::Value& password_hash_data : update.Get()->GetListDeprecated()) {
if (AreUsernamesSame(
GetAndDecryptField(password_hash_data, kUsernameFieldKey),
IsGaiaPassword(password_hash_data), username, is_gaia_password)) {
@@ -222,10 +222,9 @@ std::vector<PasswordHashData> HashPasswordManager::RetrieveAllPasswordHashes() {
if (!prefs_ || !prefs_->HasPrefPath(prefs::kPasswordHashDataList))
return result;
- const base::ListValue* hash_list =
- prefs_->GetList(prefs::kPasswordHashDataList);
+ const base::Value* hash_list = prefs_->GetList(prefs::kPasswordHashDataList);
- for (const base::Value& entry : hash_list->GetList()) {
+ for (const base::Value& entry : hash_list->GetListDeprecated()) {
absl::optional<PasswordHashData> password_hash_data =
ConvertToPasswordHashData(entry);
if (password_hash_data)
@@ -243,7 +242,7 @@ absl::optional<PasswordHashData> HashPasswordManager::RetrievePasswordHash(
}
for (const base::Value& entry :
- prefs_->GetList(prefs::kPasswordHashDataList)->GetList()) {
+ prefs_->GetList(prefs::kPasswordHashDataList)->GetListDeprecated()) {
if (AreUsernamesSame(GetAndDecryptField(entry, kUsernameFieldKey),
IsGaiaPassword(entry), username, is_gaia_password)) {
return ConvertToPasswordHashData(entry);
@@ -261,7 +260,7 @@ bool HashPasswordManager::HasPasswordHash(const std::string& username,
}
for (const base::Value& entry :
- prefs_->GetList(prefs::kPasswordHashDataList)->GetList()) {
+ prefs_->GetList(prefs::kPasswordHashDataList)->GetListDeprecated()) {
if (AreUsernamesSame(GetAndDecryptField(entry, kUsernameFieldKey),
IsGaiaPassword(entry), username, is_gaia_password)) {
return true;
@@ -322,10 +321,10 @@ bool HashPasswordManager::EncryptAndSave(
});
if (num_erased == 0 &&
- update->GetList().size() >= kMaxPasswordHashDataDictSize) {
+ update->GetListDeprecated().size() >= kMaxPasswordHashDataDictSize) {
// Erase the oldest sign-in password hash data.
update->EraseListIter(std::min_element(
- update->GetList().begin(), update->GetList().end(),
+ update->GetListDeprecated().begin(), update->GetListDeprecated().end(),
[](const auto& lhs, const auto& rhs) {
return lhs.FindKey(kLastSignInTimeFieldKey)->GetDouble() <
rhs.FindKey(kLastSignInTimeFieldKey)->GetDouble();
diff --git a/chromium/components/password_manager/core/browser/hash_password_manager_unittest.cc b/chromium/components/password_manager/core/browser/hash_password_manager_unittest.cc
index 8c351e44f32..ee468c6b0b9 100644
--- a/chromium/components/password_manager/core/browser/hash_password_manager_unittest.cc
+++ b/chromium/components/password_manager/core/browser/hash_password_manager_unittest.cc
@@ -90,7 +90,9 @@ TEST_F(HashPasswordManagerTest, SavingPasswordHashDataNotCanonicalized) {
hash_password_manager.SavePasswordHash(canonical_username, password,
/*is_gaia_password=*/true);
ASSERT_TRUE(prefs_.HasPrefPath(prefs::kPasswordHashDataList));
- EXPECT_EQ(1u, prefs_.GetList(prefs::kPasswordHashDataList)->GetList().size());
+ EXPECT_EQ(
+ 1u,
+ prefs_.GetList(prefs::kPasswordHashDataList)->GetListDeprecated().size());
EXPECT_EQ(
canonical_username,
hash_password_manager
@@ -108,7 +110,9 @@ TEST_F(HashPasswordManagerTest, SavingPasswordHashDataNotCanonicalized) {
hash_password_manager.RetrievePasswordHash(username,
/*is_gaia_password=*/true);
EXPECT_EQ(current_password_hash_data->hash, existing_password_data->hash);
- EXPECT_EQ(1u, prefs_.GetList(prefs::kPasswordHashDataList)->GetList().size());
+ EXPECT_EQ(
+ 1u,
+ prefs_.GetList(prefs::kPasswordHashDataList)->GetListDeprecated().size());
EXPECT_EQ(canonical_username,
hash_password_manager
.RetrievePasswordHash(username, /*is_gaia_password=*/true)
@@ -120,7 +124,9 @@ TEST_F(HashPasswordManagerTest, SavingPasswordHashDataNotCanonicalized) {
.RetrievePasswordHash(gmail_prefix,
/*is_gaia_password=*/true)
->hash);
- EXPECT_EQ(1u, prefs_.GetList(prefs::kPasswordHashDataList)->GetList().size());
+ EXPECT_EQ(
+ 1u,
+ prefs_.GetList(prefs::kPasswordHashDataList)->GetListDeprecated().size());
EXPECT_EQ(canonical_username,
hash_password_manager
.RetrievePasswordHash(gmail_prefix, /*is_gaia_password=*/true)
@@ -130,7 +136,9 @@ TEST_F(HashPasswordManagerTest, SavingPasswordHashDataNotCanonicalized) {
// full gmail user name.
hash_password_manager.SavePasswordHash("user.name", password,
/*is_gaia_password=*/true);
- EXPECT_EQ(2u, prefs_.GetList(prefs::kPasswordHashDataList)->GetList().size());
+ EXPECT_EQ(
+ 2u,
+ prefs_.GetList(prefs::kPasswordHashDataList)->GetListDeprecated().size());
EXPECT_EQ("username@gmail.com",
hash_password_manager
.RetrievePasswordHash("user.name", /*is_gaia_password=*/true)
diff --git a/chromium/components/password_manager/core/browser/leak_detection/BUILD.gn b/chromium/components/password_manager/core/browser/leak_detection/BUILD.gn
index b39c0d01230..dc8a4c9da97 100644
--- a/chromium/components/password_manager/core/browser/leak_detection/BUILD.gn
+++ b/chromium/components/password_manager/core/browser/leak_detection/BUILD.gn
@@ -51,7 +51,7 @@ source_set("leak_detection") {
deps = [
":proto",
"//base",
- "//components/password_manager/core/common",
+ "//components/password_manager/core/common:features",
"//components/signin/public/identity_manager",
"//components/version_info:channel",
"//third_party/private-join-and-compute/src:ec_commutative_cipher",
@@ -93,7 +93,7 @@ source_set("unit_tests") {
":proto",
":test_support",
"//base/test:test_support",
- "//components/password_manager/core/common",
+ "//components/password_manager/core/common:features",
"//components/signin/public/identity_manager:test_support",
"//components/version_info:channel",
"//services/network:test_support",
diff --git a/chromium/components/password_manager/core/browser/leak_detection/encryption_utils.cc b/chromium/components/password_manager/core/browser/leak_detection/encryption_utils.cc
index 4b91fb0941a..e0ab2b6fa1e 100644
--- a/chromium/components/password_manager/core/browser/leak_detection/encryption_utils.cc
+++ b/chromium/components/password_manager/core/browser/leak_detection/encryption_utils.cc
@@ -131,10 +131,10 @@ absl::optional<std::string> CipherEncrypt(const std::string& plaintext,
auto cipher = ECCommutativeCipher::CreateWithNewKey(
NID_X9_62_prime256v1, ECCommutativeCipher::SHA256);
if (cipher.ok()) {
- auto result = cipher.ValueOrDie()->Encrypt(plaintext);
+ auto result = cipher.value()->Encrypt(plaintext);
if (result.ok()) {
- *key = cipher.ValueOrDie()->GetPrivateKeyBytes();
- return std::move(result).ValueOrDie();
+ *key = cipher.value()->GetPrivateKeyBytes();
+ return std::move(result).value();
}
}
return absl::nullopt;
@@ -146,9 +146,9 @@ absl::optional<std::string> CipherEncryptWithKey(const std::string& plaintext,
auto cipher = ECCommutativeCipher::CreateFromKey(NID_X9_62_prime256v1, key,
ECCommutativeCipher::SHA256);
if (cipher.ok()) {
- auto result = cipher.ValueOrDie()->Encrypt(plaintext);
+ auto result = cipher.value()->Encrypt(plaintext);
if (result.ok())
- return std::move(result).ValueOrDie();
+ return std::move(result).value();
}
return absl::nullopt;
}
@@ -160,10 +160,10 @@ absl::optional<std::string> CipherReEncrypt(
auto cipher = ECCommutativeCipher::CreateWithNewKey(
NID_X9_62_prime256v1, ECCommutativeCipher::SHA256);
if (cipher.ok()) {
- auto result = cipher.ValueOrDie()->ReEncrypt(already_encrypted);
+ auto result = cipher.value()->ReEncrypt(already_encrypted);
if (result.ok()) {
- *key = cipher.ValueOrDie()->GetPrivateKeyBytes();
- return std::move(result).ValueOrDie();
+ *key = cipher.value()->GetPrivateKeyBytes();
+ return std::move(result).value();
}
}
return absl::nullopt;
@@ -175,9 +175,9 @@ absl::optional<std::string> CipherDecrypt(const std::string& ciphertext,
auto cipher = ECCommutativeCipher::CreateFromKey(NID_X9_62_prime256v1, key,
ECCommutativeCipher::SHA256);
if (cipher.ok()) {
- auto result = cipher.ValueOrDie()->Decrypt(ciphertext);
+ auto result = cipher.value()->Decrypt(ciphertext);
if (result.ok())
- return std::move(result).ValueOrDie();
+ return std::move(result).value();
}
return absl::nullopt;
}
@@ -187,7 +187,7 @@ absl::optional<std::string> CreateNewKey() {
auto cipher = ECCommutativeCipher::CreateWithNewKey(
NID_X9_62_prime256v1, ECCommutativeCipher::SHA256);
if (cipher.ok())
- return cipher.ValueOrDie()->GetPrivateKeyBytes();
+ return cipher.value()->GetPrivateKeyBytes();
return absl::nullopt;
}
diff --git a/chromium/components/password_manager/core/browser/leak_detection/encryption_utils_unittest.cc b/chromium/components/password_manager/core/browser/leak_detection/encryption_utils_unittest.cc
index e8b8baea7c0..e19899832b9 100644
--- a/chromium/components/password_manager/core/browser/leak_detection/encryption_utils_unittest.cc
+++ b/chromium/components/password_manager/core/browser/leak_detection/encryption_utils_unittest.cc
@@ -26,8 +26,8 @@ std::string CalculateECCurveHash(const std::string& plaintext) {
std::unique_ptr<Context> context(new Context);
auto group = ECGroup::Create(NID_X9_62_prime256v1, context.get());
- auto point = group.ValueOrDie().GetPointByHashingToCurveSha256(plaintext);
- return point.ValueOrDie().ToBytesCompressed().ValueOrDie();
+ auto point = group.value().GetPointByHashingToCurveSha256(plaintext);
+ return point.value().ToBytesCompressed().value();
}
// Converts a string to an array for printing.
diff --git a/chromium/components/password_manager/core/browser/leak_detection/leak_detection_request_utils.h b/chromium/components/password_manager/core/browser/leak_detection/leak_detection_request_utils.h
index b17c4e63c48..65b591fa50a 100644
--- a/chromium/components/password_manager/core/browser/leak_detection/leak_detection_request_utils.h
+++ b/chromium/components/password_manager/core/browser/leak_detection/leak_detection_request_utils.h
@@ -6,7 +6,6 @@
#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_LEAK_DETECTION_LEAK_DETECTION_REQUEST_UTILS_H_
#include "base/callback.h"
-#include "base/compiler_specific.h"
#include "base/strings/string_piece_forward.h"
#include "base/task/cancelable_task_tracker.h"
#include "base/task/task_runner.h"
@@ -82,9 +81,9 @@ void AnalyzeResponse(std::unique_ptr<SingleLookupResponse> response,
// Requests an access token for the API. |callback| is to be called with the
// result. The caller should keep the returned fetcher alive.
-std::unique_ptr<signin::AccessTokenFetcher> RequestAccessToken(
+[[nodiscard]] std::unique_ptr<signin::AccessTokenFetcher> RequestAccessToken(
signin::IdentityManager* identity_manager,
- signin::AccessTokenFetcher::TokenCallback callback) WARN_UNUSED_RESULT;
+ signin::AccessTokenFetcher::TokenCallback callback);
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/leak_detection_delegate.cc b/chromium/components/password_manager/core/browser/leak_detection_delegate.cc
index 4e71f5a4f8d..1fab881cf36 100644
--- a/chromium/components/password_manager/core/browser/leak_detection_delegate.cc
+++ b/chromium/components/password_manager/core/browser/leak_detection_delegate.cc
@@ -47,17 +47,22 @@ LeakDetectionDelegate::LeakDetectionDelegate(PasswordManagerClient* client)
LeakDetectionDelegate::~LeakDetectionDelegate() = default;
-void LeakDetectionDelegate::StartLeakCheck(const PasswordForm& form) {
+void LeakDetectionDelegate::StartLeakCheck(
+ const PasswordForm& credentials,
+ bool submitted_form_was_likely_signup_form) {
if (client_->IsIncognito())
return;
if (!CanStartLeakCheck(*client_->GetPrefs(), client_))
return;
- if (form.username_value.empty())
+ if (credentials.username_value.empty())
return;
- DCHECK(!form.password_value.empty());
+ DCHECK(!credentials.password_value.empty());
+
+ is_likely_signup_form_ = submitted_form_was_likely_signup_form;
+
leak_check_ = leak_factory_->TryCreateLeakCheck(
this, client_->GetIdentityManager(), client_->GetURLLoaderFactory(),
client_->GetChannel());
@@ -65,7 +70,8 @@ void LeakDetectionDelegate::StartLeakCheck(const PasswordForm& form) {
helper_.reset();
if (leak_check_) {
is_leaked_timer_ = std::make_unique<base::ElapsedTimer>();
- leak_check_->Start(form.url, form.username_value, form.password_value);
+ leak_check_->Start(credentials.url, credentials.username_value,
+ credentials.password_value);
}
}
@@ -86,9 +92,13 @@ void LeakDetectionDelegate::OnLeakDetectionDone(bool is_leaked,
false);
if (is_leaked || force_dialog_for_testing) {
PasswordScriptsFetcher* scripts_fetcher = nullptr;
+ // Password change scripts require password generation, so only bother
+ // querying for script availability if generation is available.
+ // Similarly, password change scripts should only be offered during sign-in
+ // (not during sign-up), so don't query if this was a new-password form.
if (client_->GetPasswordFeatureManager()->IsGenerationEnabled() &&
- base::FeatureList::IsEnabled(
- password_manager::features::kPasswordScriptsFetching) &&
+ !is_likely_signup_form_ &&
+ password_manager::features::IsPasswordScriptsFetchingEnabled() &&
base::FeatureList::IsEnabled(
password_manager::features::kPasswordChange)) {
scripts_fetcher = client_->GetPasswordScriptsFetcher();
diff --git a/chromium/components/password_manager/core/browser/leak_detection_delegate.h b/chromium/components/password_manager/core/browser/leak_detection_delegate.h
index 79624ca36af..ca87eb178ce 100644
--- a/chromium/components/password_manager/core/browser/leak_detection_delegate.h
+++ b/chromium/components/password_manager/core/browser/leak_detection_delegate.h
@@ -43,7 +43,11 @@ class LeakDetectionDelegate : public LeakDetectionDelegateInterface {
LeakDetectionCheck* leak_check() const { return leak_check_.get(); }
#endif // defined(UNIT_TEST)
- void StartLeakCheck(const PasswordForm& form);
+ // Starts a leak check for `credentials`. Note that
+ // `submitted_form_was_likely_signup_form` is typically derived from a
+ // different PasswordForm instance!
+ void StartLeakCheck(const PasswordForm& credentials,
+ bool submitted_form_was_likely_signup_form);
private:
// LeakDetectionDelegateInterface:
@@ -74,6 +78,9 @@ class LeakDetectionDelegate : public LeakDetectionDelegateInterface {
// Current leak check-up being performed in the background.
std::unique_ptr<LeakDetectionCheck> leak_check_;
+ // Whether the form that was submitted was (likely) a signup form.
+ bool is_likely_signup_form_ = false;
+
// Timer measuring the time it takes from StartLeakCheck() until a call to
// OnLeakDetectionDone() with is_leaked = true.
std::unique_ptr<base::ElapsedTimer> is_leaked_timer_;
diff --git a/chromium/components/password_manager/core/browser/leak_detection_delegate_helper.cc b/chromium/components/password_manager/core/browser/leak_detection_delegate_helper.cc
index d382f86a2e7..818311df2d0 100644
--- a/chromium/components/password_manager/core/browser/leak_detection_delegate_helper.cc
+++ b/chromium/components/password_manager/core/browser/leak_detection_delegate_helper.cc
@@ -92,7 +92,8 @@ void LeakDetectionDelegateHelper::ProcessResults() {
IsSaved is_saved(
base::ranges::any_of(partial_results_, [this](const auto& form) {
- return form->url == url_ && form->username_value == username_;
+ return form->url == url_ && form->username_value == username_ &&
+ form->password_value == password_;
}));
IsReused is_reused(partial_results_.size() > (is_saved ? 1 : 0));
HasChangeScript has_change_script(script_is_available_);
diff --git a/chromium/components/password_manager/core/browser/leak_detection_delegate_unittest.cc b/chromium/components/password_manager/core/browser/leak_detection_delegate_unittest.cc
index cd247109726..f06c1d55ceb 100644
--- a/chromium/components/password_manager/core/browser/leak_detection_delegate_unittest.cc
+++ b/chromium/components/password_manager/core/browser/leak_detection_delegate_unittest.cc
@@ -68,6 +68,10 @@ class MockPasswordManagerClient : public StubPasswordManagerClient {
GetProfilePasswordStore,
(),
(const override));
+ MOCK_METHOD(PasswordScriptsFetcher*,
+ GetPasswordScriptsFetcher,
+ (),
+ (override));
MOCK_METHOD(version_info::Channel, GetChannel, (), (const override));
};
@@ -83,7 +87,10 @@ class MockLeakDetectionCheck : public LeakDetectionCheck {
class LeakDetectionDelegateTest : public testing::Test {
public:
- LeakDetectionDelegateTest() {
+ explicit LeakDetectionDelegateTest(
+ const std::vector<base::Feature>& enabled_features) {
+ features_.InitWithFeatures(enabled_features, {});
+
auto mock_factory =
std::make_unique<testing::StrictMock<MockLeakDetectionCheckFactory>>();
mock_factory_ = mock_factory.get();
@@ -97,6 +104,9 @@ class LeakDetectionDelegateTest : public testing::Test {
ON_CALL(client_, GetPrefs()).WillByDefault(Return(pref_service()));
}
+ LeakDetectionDelegateTest()
+ : LeakDetectionDelegateTest(std::vector<base::Feature>()) {}
+
~LeakDetectionDelegateTest() override = default;
MockPasswordManagerClient& client() { return client_; }
@@ -148,6 +158,7 @@ class LeakDetectionDelegateTest : public testing::Test {
}
private:
+ base::test::ScopedFeatureList features_;
base::test::TaskEnvironment task_environment_{
base::test::TaskEnvironment::TimeSource::MOCK_TIME};
testing::NiceMock<MockPasswordManagerClient> client_;
@@ -163,7 +174,8 @@ TEST_F(LeakDetectionDelegateTest, InIncognito) {
const PasswordForm form = CreateTestForm();
EXPECT_CALL(client(), IsIncognito).WillOnce(Return(true));
EXPECT_CALL(factory(), TryCreateLeakCheck).Times(0);
- delegate().StartLeakCheck(form);
+ delegate().StartLeakCheck(form,
+ /*submitted_form_was_likely_signup_form=*/false);
EXPECT_FALSE(delegate().leak_check());
}
@@ -172,7 +184,9 @@ TEST_F(LeakDetectionDelegateTest, SafeBrowsingOff) {
pref_service()->SetBoolean(::prefs::kSafeBrowsingEnabled, false);
EXPECT_CALL(factory(), TryCreateLeakCheck).Times(0);
- delegate().StartLeakCheck(CreateTestForm());
+ const PasswordForm form = CreateTestForm();
+ delegate().StartLeakCheck(form,
+ /*submitted_form_was_likely_signup_form=*/false);
EXPECT_FALSE(delegate().leak_check());
}
@@ -182,7 +196,8 @@ TEST_F(LeakDetectionDelegateTest, UsernameIsEmpty) {
form.username_value.clear();
EXPECT_CALL(factory(), TryCreateLeakCheck).Times(0);
- delegate().StartLeakCheck(form);
+ delegate().StartLeakCheck(form,
+ /*submitted_form_was_likely_signup_form=*/false);
EXPECT_FALSE(delegate().leak_check());
}
@@ -196,7 +211,8 @@ TEST_F(LeakDetectionDelegateTest, StartCheck) {
Start(form.url, form.username_value, form.password_value));
EXPECT_CALL(factory(), TryCreateLeakCheck(&delegate(), _, _, _))
.WillOnce(Return(ByMove(std::move(check_instance))));
- delegate().StartLeakCheck(form);
+ delegate().StartLeakCheck(form,
+ /*submitted_form_was_likely_signup_form=*/false);
EXPECT_TRUE(delegate().leak_check());
}
@@ -207,7 +223,8 @@ TEST_F(LeakDetectionDelegateTest, DoNotStartCheck) {
EXPECT_CALL(client(), IsIncognito).WillOnce(Return(false));
auto check_instance = std::make_unique<MockLeakDetectionCheck>();
EXPECT_CALL(factory(), TryCreateLeakCheck).Times(0);
- delegate().StartLeakCheck(form);
+ delegate().StartLeakCheck(form,
+ /*submitted_form_was_likely_signup_form=*/false);
EXPECT_FALSE(delegate().leak_check());
}
@@ -222,13 +239,18 @@ TEST_F(LeakDetectionDelegateTest, StartCheckWithStandardProtection) {
Start(form.url, form.username_value, form.password_value));
EXPECT_CALL(factory(), TryCreateLeakCheck(&delegate(), _, _, _))
.WillOnce(Return(ByMove(std::move(check_instance))));
- delegate().StartLeakCheck(form);
+ delegate().StartLeakCheck(form,
+ /*submitted_form_was_likely_signup_form=*/false);
EXPECT_TRUE(delegate().leak_check());
EXPECT_TRUE(CanStartLeakCheck(*pref_service()));
}
TEST_F(LeakDetectionDelegateTest, StartCheckWithEnhancedProtection) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitWithFeatures(
+ /* enabled_features */ {safe_browsing::kEnhancedProtection},
+ /* disabled_features */ {});
SetSBState(safe_browsing::SafeBrowsingState::ENHANCED_PROTECTION);
SetLeakDetectionEnabled(false);
const PasswordForm form = CreateTestForm();
@@ -238,7 +260,8 @@ TEST_F(LeakDetectionDelegateTest, StartCheckWithEnhancedProtection) {
Start(form.url, form.username_value, form.password_value));
EXPECT_CALL(factory(), TryCreateLeakCheck(&delegate(), _, _, _))
.WillOnce(Return(ByMove(std::move(check_instance))));
- delegate().StartLeakCheck(form);
+ delegate().StartLeakCheck(form,
+ /*submitted_form_was_likely_signup_form=*/false);
EXPECT_TRUE(delegate().leak_check());
EXPECT_TRUE(CanStartLeakCheck(*pref_service()));
@@ -251,7 +274,8 @@ TEST_F(LeakDetectionDelegateTest, DoNotStartCheckWithoutSafeBrowsing) {
EXPECT_CALL(client(), IsIncognito).WillOnce(Return(false));
auto check_instance = std::make_unique<MockLeakDetectionCheck>();
EXPECT_CALL(factory(), TryCreateLeakCheck).Times(0);
- delegate().StartLeakCheck(form);
+ delegate().StartLeakCheck(form,
+ /*submitted_form_was_likely_signup_form=*/false);
EXPECT_FALSE(delegate().leak_check());
EXPECT_FALSE(CanStartLeakCheck(*pref_service()));
@@ -264,7 +288,8 @@ TEST_F(LeakDetectionDelegateTest, DoNotStartLeakCheckIfLeakCheckIsOff) {
EXPECT_CALL(client(), IsIncognito).WillOnce(Return(false));
EXPECT_CALL(factory(), TryCreateLeakCheck).Times(0);
auto check_instance = std::make_unique<MockLeakDetectionCheck>();
- delegate().StartLeakCheck(form);
+ delegate().StartLeakCheck(form,
+ /*submitted_form_was_likely_signup_form=*/false);
EXPECT_FALSE(delegate().leak_check());
EXPECT_FALSE(CanStartLeakCheck(*pref_service()));
@@ -278,7 +303,8 @@ TEST_F(LeakDetectionDelegateTest, LeakDetectionDoneWithFalseResult) {
EXPECT_CALL(factory(), TryCreateLeakCheck)
.WillOnce(
Return(ByMove(std::make_unique<NiceMock<MockLeakDetectionCheck>>())));
- delegate().StartLeakCheck(form);
+ delegate().StartLeakCheck(form,
+ /*submitted_form_was_likely_signup_form=*/false);
EXPECT_CALL(client(), NotifyUserCredentialsWereLeaked).Times(0);
delegate_interface->OnLeakDetectionDone(
@@ -310,7 +336,8 @@ TEST_F(LeakDetectionDelegateTest,
EXPECT_CALL(factory(), TryCreateLeakCheck)
.WillOnce(
Return(ByMove(std::make_unique<NiceMock<MockLeakDetectionCheck>>())));
- delegate().StartLeakCheck(form);
+ delegate().StartLeakCheck(form,
+ /*submitted_form_was_likely_signup_form=*/false);
EXPECT_CALL(client(), NotifyUserCredentialsWereLeaked(
password_manager::CreateLeakType(
@@ -334,7 +361,8 @@ TEST_F(LeakDetectionDelegateTest, LeakDetectionDoneWithTrueResult) {
EXPECT_CALL(factory(), TryCreateLeakCheck)
.WillOnce(
Return(ByMove(std::make_unique<NiceMock<MockLeakDetectionCheck>>())));
- delegate().StartLeakCheck(form);
+ delegate().StartLeakCheck(form,
+ /*submitted_form_was_likely_signup_form=*/false);
EXPECT_CALL(client(), NotifyUserCredentialsWereLeaked(
password_manager::CreateLeakType(
@@ -358,7 +386,8 @@ TEST_F(LeakDetectionDelegateTest, LeakHistoryAddCredentials) {
EXPECT_CALL(factory(), TryCreateLeakCheck)
.WillOnce(
Return(ByMove(std::make_unique<NiceMock<MockLeakDetectionCheck>>())));
- delegate().StartLeakCheck(form);
+ delegate().StartLeakCheck(form,
+ /*submitted_form_was_likely_signup_form=*/false);
EXPECT_CALL(client(), NotifyUserCredentialsWereLeaked(_, form.url,
form.username_value));
@@ -382,7 +411,8 @@ TEST_F(LeakDetectionDelegateTest, CallStartTwice) {
EXPECT_CALL(factory(), TryCreateLeakCheck(&delegate(), _, _, _))
.WillOnce(Return(ByMove(std::move(check_instance))));
PasswordForm form = CreateTestForm();
- delegate().StartLeakCheck(form);
+ delegate().StartLeakCheck(form,
+ /*submitted_form_was_likely_signup_form=*/false);
ASSERT_TRUE(delegate().leak_check());
// The delegate analyses the password store after this call.
@@ -397,7 +427,8 @@ TEST_F(LeakDetectionDelegateTest, CallStartTwice) {
.WillOnce(Return(ByMove(std::move(check_instance))));
form.username_value = u"username";
form.password_value = u"password";
- delegate().StartLeakCheck(form);
+ delegate().StartLeakCheck(form,
+ /*submitted_form_was_likely_signup_form=*/false);
ASSERT_TRUE(delegate().leak_check());
// Simulate the previous check is complete now.
@@ -421,9 +452,79 @@ TEST_F(LeakDetectionDelegateTest, PassesChromeChannel) {
EXPECT_CALL(client(), GetChannel).WillOnce(Return(channel));
EXPECT_CALL(factory(), TryCreateLeakCheck(&delegate(), _, _, channel))
.WillOnce(Return(ByMove(std::move(check_instance))));
- delegate().StartLeakCheck(form);
+ delegate().StartLeakCheck(form,
+ /*submitted_form_was_likely_signup_form=*/false);
EXPECT_TRUE(delegate().leak_check());
}
+class LeakDetectionDelegateWithPasswordChangeTest
+ : public LeakDetectionDelegateTest {
+ public:
+ LeakDetectionDelegateWithPasswordChangeTest()
+ : LeakDetectionDelegateTest(
+ {password_manager::features::kPasswordChange,
+ password_manager::features::kPasswordScriptsFetching,
+ password_manager::features::kPasswordDomainCapabilitiesFetching}) {
+ }
+};
+
+TEST_F(LeakDetectionDelegateWithPasswordChangeTest,
+ ChecksForScriptsOnSigninForm) {
+ ON_CALL(*client().GetPasswordFeatureManager(), IsGenerationEnabled())
+ .WillByDefault(Return(true));
+
+ const PasswordForm form = CreateTestForm();
+
+ EXPECT_CALL(client(), GetProfilePasswordStore())
+ .WillRepeatedly(testing::Return(store()));
+ ExpectPasswords({});
+ EXPECT_CALL(factory(), TryCreateLeakCheck)
+ .WillOnce(
+ Return(ByMove(std::make_unique<NiceMock<MockLeakDetectionCheck>>())));
+ delegate().StartLeakCheck(form,
+ /*submitted_form_was_likely_signup_form=*/false);
+
+ // All the prerequisites are fulfilled, so the delegate should try to get a
+ // PasswordScriptsFetcher. For simplicity, we don't actually return one here
+ // (interactions with the fetcher are tested in
+ // LeakDetectionDelegateHelperTest).
+ EXPECT_CALL(client(), GetPasswordScriptsFetcher()).WillOnce(Return(nullptr));
+
+ EXPECT_CALL(client(), NotifyUserCredentialsWereLeaked(_, form.url,
+ form.username_value));
+ LeakDetectionDelegateInterface* delegate_interface = &delegate();
+ delegate_interface->OnLeakDetectionDone(
+ /*is_leaked=*/true, form.url, form.username_value, form.password_value);
+ WaitForPasswordStore();
+}
+
+TEST_F(LeakDetectionDelegateWithPasswordChangeTest,
+ DoesNotCheckForScriptsOnSignupForm) {
+ ON_CALL(*client().GetPasswordFeatureManager(), IsGenerationEnabled())
+ .WillByDefault(Return(true));
+
+ const PasswordForm form = CreateTestForm();
+
+ EXPECT_CALL(client(), GetProfilePasswordStore())
+ .WillRepeatedly(testing::Return(store()));
+ ExpectPasswords({});
+ EXPECT_CALL(factory(), TryCreateLeakCheck)
+ .WillOnce(
+ Return(ByMove(std::make_unique<NiceMock<MockLeakDetectionCheck>>())));
+ delegate().StartLeakCheck(form,
+ /*submitted_form_was_likely_signup_form=*/true);
+
+ // The given form is a sign-*up* form, so the delegate should NOT try to get a
+ // PasswordScriptsFetcher.
+ EXPECT_CALL(client(), GetPasswordScriptsFetcher()).Times(0);
+
+ EXPECT_CALL(client(), NotifyUserCredentialsWereLeaked(_, form.url,
+ form.username_value));
+ LeakDetectionDelegateInterface* delegate_interface = &delegate();
+ delegate_interface->OnLeakDetectionDone(
+ /*is_leaked=*/true, form.url, form.username_value, form.password_value);
+ WaitForPasswordStore();
+}
+
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/leak_detection_dialog_utils.cc b/chromium/components/password_manager/core/browser/leak_detection_dialog_utils.cc
index eb2f49e9df7..91c1f895584 100644
--- a/chromium/components/password_manager/core/browser/leak_detection_dialog_utils.cc
+++ b/chromium/components/password_manager/core/browser/leak_detection_dialog_utils.cc
@@ -194,9 +194,9 @@ GURL GetPasswordCheckupURL(PasswordCheckupReferrer referrer) {
GURL url(kPasswordCheckupURL);
url = net::AppendQueryParameter(url, "utm_source", "chrome");
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
const char* const medium = "android";
-#elif defined(OS_IOS)
+#elif BUILDFLAG(IS_IOS)
const char* const medium = "ios";
#else
const char* const medium = "desktop";
diff --git a/chromium/components/password_manager/core/browser/leak_detection_dialog_utils_unittest.cc b/chromium/components/password_manager/core/browser/leak_detection_dialog_utils_unittest.cc
index 9773c71f2b1..022dfc81226 100644
--- a/chromium/components/password_manager/core/browser/leak_detection_dialog_utils_unittest.cc
+++ b/chromium/components/password_manager/core/browser/leak_detection_dialog_utils_unittest.cc
@@ -27,7 +27,6 @@ using password_manager::IsSyncing;
namespace password_manager {
namespace {
-
// Contains information that should be displayed on the leak dialog for
// specified |leak_type|.
const struct {
@@ -45,40 +44,72 @@ const struct {
IsReused(false),
IsSyncing(false),
HasChangeScript(false)),
- IDS_OK, IDS_CLOSE, IDS_CREDENTIAL_LEAK_CHANGE_PASSWORD_MESSAGE,
+ IDS_OK, IDS_CLOSE,
+#if BUILDFLAG(IS_IOS)
+ IDS_CREDENTIAL_LEAK_CHANGE_PASSWORD_MESSAGE_BRANDED,
+#else
+ IDS_CREDENTIAL_LEAK_CHANGE_PASSWORD_MESSAGE,
+#endif
IDS_CREDENTIAL_LEAK_TITLE_CHANGE, false, false},
{CreateLeakType(IsSaved(false),
IsReused(false),
IsSyncing(true),
HasChangeScript(false)),
- IDS_OK, IDS_CLOSE, IDS_CREDENTIAL_LEAK_CHANGE_PASSWORD_MESSAGE,
+ IDS_OK, IDS_CLOSE,
+#if BUILDFLAG(IS_IOS)
+ IDS_CREDENTIAL_LEAK_CHANGE_PASSWORD_MESSAGE_BRANDED,
+#else
+ IDS_CREDENTIAL_LEAK_CHANGE_PASSWORD_MESSAGE,
+#endif
IDS_CREDENTIAL_LEAK_TITLE_CHANGE, false, false},
{CreateLeakType(IsSaved(false),
IsReused(true),
IsSyncing(true),
HasChangeScript(false)),
IDS_LEAK_CHECK_CREDENTIALS, IDS_CLOSE,
+#if BUILDFLAG(IS_IOS)
+ IDS_CREDENTIAL_LEAK_CHANGE_AND_CHECK_PASSWORDS_MESSAGE_BRANDED,
+ IDS_CREDENTIAL_LEAK_TITLE_CHECK_BRANDED,
+#else
IDS_CREDENTIAL_LEAK_CHANGE_AND_CHECK_PASSWORDS_MESSAGE,
- IDS_CREDENTIAL_LEAK_TITLE_CHECK, true, true},
+ IDS_CREDENTIAL_LEAK_TITLE_CHECK,
+#endif
+ true, true},
{CreateLeakType(IsSaved(false),
IsReused(false),
IsSyncing(true),
HasChangeScript(true)),
- IDS_OK, IDS_CLOSE, IDS_CREDENTIAL_LEAK_CHANGE_PASSWORD_MESSAGE,
+ IDS_OK, IDS_CLOSE,
+#if BUILDFLAG(IS_IOS)
+ IDS_CREDENTIAL_LEAK_CHANGE_PASSWORD_MESSAGE_BRANDED,
+#else
+ IDS_CREDENTIAL_LEAK_CHANGE_PASSWORD_MESSAGE,
+#endif
IDS_CREDENTIAL_LEAK_TITLE_CHANGE, false, false},
{CreateLeakType(IsSaved(true),
IsReused(false),
IsSyncing(true),
HasChangeScript(false)),
- IDS_OK, IDS_CLOSE, IDS_CREDENTIAL_LEAK_CHANGE_PASSWORD_MESSAGE,
+ IDS_OK, IDS_CLOSE,
+#if BUILDFLAG(IS_IOS)
+ IDS_CREDENTIAL_LEAK_CHANGE_PASSWORD_MESSAGE_BRANDED,
+#else
+ IDS_CREDENTIAL_LEAK_CHANGE_PASSWORD_MESSAGE,
+#endif
IDS_CREDENTIAL_LEAK_TITLE_CHANGE, false, false},
{CreateLeakType(IsSaved(true),
IsReused(true),
IsSyncing(true),
HasChangeScript(false)),
IDS_LEAK_CHECK_CREDENTIALS, IDS_CLOSE,
+#if BUILDFLAG(IS_IOS)
+ IDS_CREDENTIAL_LEAK_CHECK_PASSWORDS_MESSAGE_BRANDED,
+ IDS_CREDENTIAL_LEAK_TITLE_CHECK_BRANDED,
+#else
IDS_CREDENTIAL_LEAK_CHECK_PASSWORDS_MESSAGE,
- IDS_CREDENTIAL_LEAK_TITLE_CHECK, true, true},
+ IDS_CREDENTIAL_LEAK_TITLE_CHECK,
+#endif
+ true, true},
};
struct BulkCheckParams {
@@ -112,7 +143,20 @@ struct BulkCheckParams {
true}};
} // namespace
-TEST(CredentialLeakDialogUtilsTest, GetAcceptButtonLabel) {
+class CredentialLeakDialogUtilsTest : public testing::Test {
+ public:
+ CredentialLeakDialogUtilsTest() {
+#if BUILDFLAG(IS_IOS)
+ feature_list_.InitAndEnableFeature(
+ features::kIOSEnablePasswordManagerBrandingUpdate);
+#endif
+ }
+
+ private:
+ base::test::ScopedFeatureList feature_list_;
+};
+
+TEST_F(CredentialLeakDialogUtilsTest, GetAcceptButtonLabel) {
for (size_t i = 0; i < base::size(kLeakTypesTestCases); ++i) {
SCOPED_TRACE(testing::Message() << i);
EXPECT_EQ(
@@ -121,7 +165,7 @@ TEST(CredentialLeakDialogUtilsTest, GetAcceptButtonLabel) {
}
}
-TEST(CredentialLeakDialogUtilsTest, GetCancelButtonLabel) {
+TEST_F(CredentialLeakDialogUtilsTest, GetCancelButtonLabel) {
for (size_t i = 0; i < base::size(kLeakTypesTestCases); ++i) {
SCOPED_TRACE(testing::Message() << i);
EXPECT_EQ(
@@ -130,7 +174,7 @@ TEST(CredentialLeakDialogUtilsTest, GetCancelButtonLabel) {
}
}
-TEST(CredentialLeakDialogUtilsTest, GetDescription) {
+TEST_F(CredentialLeakDialogUtilsTest, GetDescription) {
for (size_t i = 0; i < base::size(kLeakTypesTestCases); ++i) {
SCOPED_TRACE(testing::Message() << i);
std::u16string expected_message =
@@ -140,7 +184,7 @@ TEST(CredentialLeakDialogUtilsTest, GetDescription) {
}
}
-TEST(CredentialLeakDialogUtilsTest, GetTitle) {
+TEST_F(CredentialLeakDialogUtilsTest, GetTitle) {
for (size_t i = 0; i < base::size(kLeakTypesTestCases); ++i) {
SCOPED_TRACE(testing::Message() << i);
EXPECT_EQ(l10n_util::GetStringUTF16(kLeakTypesTestCases[i].leak_title_id),
@@ -148,7 +192,7 @@ TEST(CredentialLeakDialogUtilsTest, GetTitle) {
}
}
-TEST(CredentialLeakDialogUtilsTest, ShouldCheckPasswords) {
+TEST_F(CredentialLeakDialogUtilsTest, ShouldCheckPasswords) {
for (size_t i = 0; i < base::size(kLeakTypesTestCases); ++i) {
SCOPED_TRACE(testing::Message() << i);
EXPECT_EQ(kLeakTypesTestCases[i].should_check_passwords,
@@ -156,7 +200,7 @@ TEST(CredentialLeakDialogUtilsTest, ShouldCheckPasswords) {
}
}
-TEST(CredentialLeakDialogUtilsTest, ShouldShowCancelButton) {
+TEST_F(CredentialLeakDialogUtilsTest, ShouldShowCancelButton) {
for (size_t i = 0; i < base::size(kLeakTypesTestCases); ++i) {
SCOPED_TRACE(testing::Message() << i);
EXPECT_EQ(kLeakTypesTestCases[i].should_show_cancel_button,
@@ -166,6 +210,16 @@ TEST(CredentialLeakDialogUtilsTest, ShouldShowCancelButton) {
class BulkCheckCredentialLeakDialogUtilsTest
: public testing::TestWithParam<BulkCheckParams> {
+ public:
+ BulkCheckCredentialLeakDialogUtilsTest() {
+#if BUILDFLAG(IS_IOS)
+ feature_list_.InitAndEnableFeature(
+ features::kIOSEnablePasswordManagerBrandingUpdate);
+#endif
+ }
+
+ private:
+ base::test::ScopedFeatureList feature_list_;
};
TEST_P(BulkCheckCredentialLeakDialogUtilsTest, ShouldCheckPasswords) {
@@ -188,8 +242,15 @@ TEST_P(BulkCheckCredentialLeakDialogUtilsTest, Buttons) {
TEST_P(BulkCheckCredentialLeakDialogUtilsTest, Title) {
SCOPED_TRACE(testing::Message() << GetParam().leak_type);
+ int leak_title_id;
+#if BUILDFLAG(IS_IOS)
+ leak_title_id = IDS_CREDENTIAL_LEAK_TITLE_CHECK_BRANDED;
+#else
+ leak_title_id = IDS_CREDENTIAL_LEAK_TITLE_CHECK;
+#endif
+
EXPECT_EQ(l10n_util::GetStringUTF16(GetParam().should_check_passwords
- ? IDS_CREDENTIAL_LEAK_TITLE_CHECK
+ ? leak_title_id
: IDS_CREDENTIAL_LEAK_TITLE_CHANGE),
GetTitle(GetParam().leak_type));
}
@@ -198,7 +259,7 @@ INSTANTIATE_TEST_SUITE_P(InstantiationName,
BulkCheckCredentialLeakDialogUtilsTest,
testing::ValuesIn(kBulkCheckTestCases));
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
struct PasswordChangeParams {
// Specifies the test case. Note that the HasChangeScript(false) cases are
// covered in a separate test.
diff --git a/chromium/components/password_manager/core/browser/login_database.cc b/chromium/components/password_manager/core/browser/login_database.cc
index 65e8a3df56b..87bc02ea001 100644
--- a/chromium/components/password_manager/core/browser/login_database.cc
+++ b/chromium/components/password_manager/core/browser/login_database.cc
@@ -42,6 +42,7 @@
#include "components/password_manager/core/browser/password_store_change.h"
#include "components/password_manager/core/browser/psl_matching_helper.h"
#include "components/password_manager/core/browser/sql_table_builder.h"
+#include "components/password_manager/core/common/password_manager_features.h"
#include "components/sync/protocol/entity_metadata.pb.h"
#include "components/sync/protocol/model_type_state.pb.h"
#include "google_apis/gaia/gaia_auth_util.h"
@@ -58,7 +59,7 @@ using autofill::GaiaIdHash;
namespace password_manager {
// The current version number of the login database schema.
-constexpr int kCurrentVersionNumber = 31;
+constexpr int kCurrentVersionNumber = 32;
// The oldest version of the schema such that a legacy Chrome client using that
// version can still read/write the current database.
constexpr int kCompatibleVersionNumber = 31;
@@ -241,6 +242,25 @@ void AddCallback(int* output_err, int err, sql::Statement* /*stmt*/) {
DLOG(WARNING) << "LoginDatabase::AddLogin updated an existing form";
}
+class ScopedDbErrorHandler {
+ public:
+ explicit ScopedDbErrorHandler(sql::Database* db) : db_(db) {
+ db_->set_error_callback(
+ base::BindRepeating(AddCallback, &sqlite_error_code_));
+ }
+ ScopedDbErrorHandler(const ScopedDbErrorHandler&) = delete;
+ ScopedDbErrorHandler& operator=(const ScopedDbErrorHandler&) = delete;
+
+ ~ScopedDbErrorHandler() { db_->reset_error_callback(); }
+
+ void reset_error_code() { sqlite_error_code_ = 0; }
+ int get_error_code() const { return sqlite_error_code_; }
+
+ private:
+ raw_ptr<sql::Database> db_;
+ int sqlite_error_code_{0};
+};
+
bool DoesMatchConstraints(const PasswordForm& form) {
if (!IsValidAndroidFacetURI(form.signon_realm) && form.url.is_empty()) {
DLOG(ERROR) << "Constraint violation: form.origin is empty";
@@ -437,6 +457,10 @@ void InitializeBuilders(SQLTableBuilders builders) {
builders.logins->DropColumn("date_synced");
SealVersion(builders, /*expected_version=*/31u);
+ // Version 32. Set timestamps of uninitialized timestamps in
+ // 'insecure_credentials' table.
+ SealVersion(builders, /*expected_version=*/32u);
+
DCHECK_EQ(static_cast<size_t>(COLUMN_NUM), builders.logins->NumberOfColumns())
<< "Adjust LoginDatabaseTableColumns if you change column definitions "
"here.";
@@ -579,6 +603,18 @@ bool MigrateDatabase(unsigned current_version,
return false;
}
+ // Set the create_time value when uninitialized for 'insecure_credentials'.
+ if (current_version >= 29 && current_version < 32) {
+ sql::Statement set_timestamp;
+ set_timestamp.Assign(
+ db->GetUniqueStatement("UPDATE insecure_credentials SET create_time = "
+ "? WHERE create_time = 0"));
+ set_timestamp.BindInt64(
+ 0, base::Time::Now().ToDeltaSinceWindowsEpoch().InMicroseconds());
+ if (!set_timestamp.Run())
+ return false;
+ }
+
return true;
}
@@ -628,7 +664,7 @@ std::string GeneratePlaceholders(size_t count) {
return result;
}
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
// Fills |form| with necessary data required to be removed from the database
// and returns it.
PasswordForm GetFormForRemoval(sql::Statement& statement) {
@@ -642,6 +678,16 @@ PasswordForm GetFormForRemoval(sql::Statement& statement) {
}
#endif
+// Whether we should try to return the decryptable passwords while the
+// encryption service fails for some passwords.
+bool ShouldReturnPartialPasswords() {
+#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
+ return base::FeatureList::IsEnabled(features::kSkipUndecryptablePasswords);
+#else
+ return false;
+#endif
+}
+
} // namespace
struct LoginDatabase::PrimaryKeyAndPassword {
@@ -820,11 +866,11 @@ bool LoginDatabase::Init() {
}
void LoginDatabase::ReportBubbleSuppressionMetrics() {
-#if !defined(OS_IOS) && !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_IOS) && !BUILDFLAG(IS_ANDROID)
base::UmaHistogramCustomCounts(
"PasswordManager.BubbleSuppression.AccountsInStatisticsTable",
stats_table_.GetNumAccounts(), 0, 1000, 100);
-#endif // !defined(OS_IOS) && !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_IOS) && !BUILDFLAG(IS_ANDROID)
}
void LoginDatabase::ReportInaccessiblePasswordsMetrics() {
@@ -885,7 +931,7 @@ PasswordStoreChangeList LoginDatabase::AddLogin(const PasswordForm& form,
if (DecryptedString(form.encrypted_password, &decrypted_password) !=
ENCRYPTION_RESULT_SUCCESS) {
if (error) {
- *error = AddLoginError::kEncrytionServiceFailure;
+ *error = AddLoginError::kEncryptionServiceFailure;
}
return list;
}
@@ -895,7 +941,7 @@ PasswordStoreChangeList LoginDatabase::AddLogin(const PasswordForm& form,
if (EncryptedString(form.password_value, &encrypted_password) !=
ENCRYPTION_RESULT_SUCCESS) {
if (error) {
- *error = AddLoginError::kEncrytionServiceFailure;
+ *error = AddLoginError::kEncryptionServiceFailure;
}
return list;
}
@@ -906,8 +952,7 @@ PasswordStoreChangeList LoginDatabase::AddLogin(const PasswordForm& form,
sql::Statement s(
db_.GetCachedStatement(SQL_FROM_HERE, add_statement_.c_str()));
BindAddStatement(form_with_encrypted_password, &s);
- int sqlite_error_code;
- db_.set_error_callback(base::BindRepeating(&AddCallback, &sqlite_error_code));
+ ScopedDbErrorHandler db_error_handler(&db_);
const bool success = s.Run();
if (success) {
// If success, the row never existed so password was not changed.
@@ -922,9 +967,8 @@ PasswordStoreChangeList LoginDatabase::AddLogin(const PasswordForm& form,
/*password_changed=*/false);
return list;
}
-
// Repeat the same statement but with REPLACE semantic.
- sqlite_error_code = 0;
+ db_error_handler.reset_error_code();
DCHECK(!add_replace_statement_.empty());
PrimaryKeyAndPassword old_primary_key_password =
GetPrimaryKeyAndPassword(form);
@@ -951,13 +995,12 @@ PasswordStoreChangeList LoginDatabase::AddLogin(const PasswordForm& form,
FormPrimaryKey(db_.GetLastInsertRowId()),
password_changed, insecure_changed);
} else if (error) {
- if (sqlite_error_code == 19 /*SQLITE_CONSTRAINT*/) {
+ if (db_error_handler.get_error_code() == 19 /*SQLITE_CONSTRAINT*/) {
*error = AddLoginError::kConstraintViolation;
} else {
*error = AddLoginError::kDbError;
}
}
- db_.reset_error_callback();
return list;
}
@@ -971,7 +1014,7 @@ PasswordStoreChangeList LoginDatabase::UpdateLogin(const PasswordForm& form,
if (EncryptedString(form.password_value, &encrypted_password) !=
ENCRYPTION_RESULT_SUCCESS) {
if (error) {
- *error = UpdateLoginError::kEncrytionServiceFailure;
+ *error = UpdateLoginError::kEncryptionServiceFailure;
}
return PasswordStoreChangeList();
}
@@ -979,7 +1022,7 @@ PasswordStoreChangeList LoginDatabase::UpdateLogin(const PasswordForm& form,
const PrimaryKeyAndPassword old_primary_key_password =
GetPrimaryKeyAndPassword(form);
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
DeleteEncryptedPasswordFromKeychain(
old_primary_key_password.encrypted_password);
#endif
@@ -1081,7 +1124,7 @@ bool LoginDatabase::RemoveLogin(const PasswordForm& form,
}
const PrimaryKeyAndPassword old_primary_key_password =
GetPrimaryKeyAndPassword(form);
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
DeleteEncryptedPasswordFromKeychain(
old_primary_key_password.encrypted_password);
#endif
@@ -1127,7 +1170,7 @@ bool LoginDatabase::RemoveLoginByPrimaryKey(FormPrimaryKey primary_key,
DCHECK_EQ(db_primary_key, primary_key.value());
}
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
DeleteEncryptedPasswordById(primary_key.value());
#endif
DCHECK(!delete_by_id_statement_.empty());
@@ -1160,7 +1203,7 @@ bool LoginDatabase::RemoveLoginsCreatedBetween(
return false;
}
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
for (const auto& pair : key_to_form_map) {
DeleteEncryptedPasswordById(pair.first.value());
}
@@ -1197,7 +1240,9 @@ bool LoginDatabase::GetAutoSignInLogins(PrimaryKeyToFormMap* key_to_form_map) {
sql::Statement s(
db_.GetCachedStatement(SQL_FROM_HERE, autosignin_statement_.c_str()));
FormRetrievalResult result = StatementToForms(&s, nullptr, key_to_form_map);
- return result == FormRetrievalResult::kSuccess;
+ return (result == FormRetrievalResult::kSuccess ||
+ result ==
+ FormRetrievalResult::kEncryptionServiceFailureWithPartialData);
}
bool LoginDatabase::DisableAutoSignInForOrigin(const GURL& origin) {
@@ -1337,7 +1382,8 @@ bool LoginDatabase::GetLogins(
FormRetrievalResult result = StatementToForms(
&s, should_PSL_matching_apply || should_federated_apply ? &form : nullptr,
&key_to_form_map);
- if (result != FormRetrievalResult::kSuccess) {
+ if (result != FormRetrievalResult::kSuccess &&
+ result != FormRetrievalResult::kEncryptionServiceFailureWithPartialData) {
return false;
}
for (auto& pair : key_to_form_map) {
@@ -1415,10 +1461,10 @@ bool LoginDatabase::GetAllLoginsWithBlocklistSetting(
PrimaryKeyToFormMap key_to_form_map;
- if (StatementToForms(&s, nullptr, &key_to_form_map) !=
- FormRetrievalResult::kSuccess) {
+ FormRetrievalResult result = StatementToForms(&s, nullptr, &key_to_form_map);
+ if (result != FormRetrievalResult::kSuccess &&
+ result != FormRetrievalResult::kEncryptionServiceFailureWithPartialData)
return false;
- }
for (auto& pair : key_to_form_map) {
forms->push_back(std::move(pair.second));
@@ -1442,9 +1488,10 @@ bool LoginDatabase::DeleteAndRecreateDatabaseFile() {
}
DatabaseCleanupResult LoginDatabase::DeleteUndecryptableLogins() {
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
TRACE_EVENT0("passwords", "LoginDatabase::DeleteUndecryptableLogins");
- // If the Keychain is unavailable, don't delete any logins.
+ // If the Keychain in MacOS or the real secret key in Linux is unavailable,
+ // don't delete any logins.
if (!OSCrypt::IsEncryptionAvailable()) {
metrics_util::LogDeleteUndecryptableLoginsReturnValue(
metrics_util::DeleteCorruptedPasswordsResult::kEncryptionUnavailable);
@@ -1734,6 +1781,7 @@ FormRetrievalResult LoginDatabase::StatementToForms(
const PasswordFormDigest* matched_form,
PrimaryKeyToFormMap* key_to_form_map) {
key_to_form_map->clear();
+ bool has_service_failure = false;
while (statement->Step()) {
auto new_form = std::make_unique<PasswordForm>();
FillFormInStore(new_form.get());
@@ -1743,7 +1791,8 @@ FormRetrievalResult LoginDatabase::StatementToForms(
*statement, /*decrypt_and_fill_password_value=*/true, &primary_key,
new_form.get());
if (result == ENCRYPTION_RESULT_SERVICE_FAILURE) {
- return FormRetrievalResult::kEncrytionServiceFailure;
+ has_service_failure = true;
+ continue;
}
if (result == ENCRYPTION_RESULT_ITEM_FAILURE) {
continue;
@@ -1770,6 +1819,13 @@ FormRetrievalResult LoginDatabase::StatementToForms(
if (!statement->Succeeded()) {
return FormRetrievalResult::kDbError;
}
+ if (has_service_failure &&
+ (key_to_form_map->empty() || !ShouldReturnPartialPasswords())) {
+ return FormRetrievalResult::kEncryptionServiceFailure;
+ }
+ if (has_service_failure) {
+ return FormRetrievalResult::kEncryptionServiceFailureWithPartialData;
+ }
return FormRetrievalResult::kSuccess;
}
diff --git a/chromium/components/password_manager/core/browser/login_database.h b/chromium/components/password_manager/core/browser/login_database.h
index ef151b3f88e..3546a2e5786 100644
--- a/chromium/components/password_manager/core/browser/login_database.h
+++ b/chromium/components/password_manager/core/browser/login_database.h
@@ -10,7 +10,6 @@
#include <vector>
#include "base/callback.h"
-#include "base/compiler_specific.h"
#include "base/files/file_path.h"
#include "base/pickle.h"
#include "build/build_config.h"
@@ -27,7 +26,7 @@
#include "sql/database.h"
#include "sql/meta_table.h"
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
#include "base/gtest_prod_util.h"
#endif
@@ -69,31 +68,30 @@ class LoginDatabase : public PasswordStoreSync::MetadataStore {
// then the REMOVE is associated with the form that was added. Thus only the
// primary key columns contain the values associated with the removed form. In
// case of error, it sets |error| if |error| isn't null.
- PasswordStoreChangeList AddLogin(const PasswordForm& form,
- AddLoginError* error = nullptr)
- WARN_UNUSED_RESULT;
+ [[nodiscard]] PasswordStoreChangeList AddLogin(
+ const PasswordForm& form,
+ AddLoginError* error = nullptr);
// Updates existing password form. Returns the list of applied changes ({},
// {UPDATE}). The password is looked up by the tuple {origin,
// username_element, username_value, password_element, signon_realm}. These
// columns stay intact. In case of error, it sets |error| if |error| isn't
// null.
- PasswordStoreChangeList UpdateLogin(const PasswordForm& form,
- UpdateLoginError* error = nullptr)
- WARN_UNUSED_RESULT;
+ [[nodiscard]] PasswordStoreChangeList UpdateLogin(
+ const PasswordForm& form,
+ UpdateLoginError* error = nullptr);
// Removes |form| from the list of remembered password forms. Returns true if
// |form| was successfully removed from the database. If |changes| is not be
// null, it will be used to populate the change list of the removed forms if
// any.
- bool RemoveLogin(const PasswordForm& form,
- PasswordStoreChangeList* changes) WARN_UNUSED_RESULT;
+ [[nodiscard]] bool RemoveLogin(const PasswordForm& form,
+ PasswordStoreChangeList* changes);
// Removes the form with |primary_key| from the list of remembered password
// forms. Returns true if the form was successfully removed from the database.
- bool RemoveLoginByPrimaryKey(FormPrimaryKey primary_key,
- PasswordStoreChangeList* changes)
- WARN_UNUSED_RESULT;
+ [[nodiscard]] bool RemoveLoginByPrimaryKey(FormPrimaryKey primary_key,
+ PasswordStoreChangeList* changes);
// Removes all logins created from |delete_begin| onwards (inclusive) and
// before |delete_end|. You may use a null Time value to do an unbounded
@@ -113,41 +111,40 @@ class LoginDatabase : public PasswordStoreSync::MetadataStore {
// and federated credentials.
// |should_PSL_matching_apply| controls if the PSL matches are included or
// only the exact matches.
- bool GetLogins(const PasswordFormDigest& form,
- bool should_PSL_matching_apply,
- std::vector<std::unique_ptr<PasswordForm>>* forms)
- WARN_UNUSED_RESULT;
+ [[nodiscard]] bool GetLogins(
+ const PasswordFormDigest& form,
+ bool should_PSL_matching_apply,
+ std::vector<std::unique_ptr<PasswordForm>>* forms);
// Gets all logins created from |begin| onwards (inclusive) and before |end|.
// You may use a null Time value to do an unbounded search in either
// direction. |key_to_form_map| must not be null and will be used to return
// the results. The key of the map is the DB primary key.
- bool GetLoginsCreatedBetween(base::Time begin,
- base::Time end,
- PrimaryKeyToFormMap* key_to_form_map)
- WARN_UNUSED_RESULT;
+ [[nodiscard]] bool GetLoginsCreatedBetween(
+ base::Time begin,
+ base::Time end,
+ PrimaryKeyToFormMap* key_to_form_map);
// Gets the complete list of all credentials.
- FormRetrievalResult GetAllLogins(PrimaryKeyToFormMap* key_to_form_map)
- WARN_UNUSED_RESULT;
+ [[nodiscard]] FormRetrievalResult GetAllLogins(
+ PrimaryKeyToFormMap* key_to_form_map);
// Gets list of logins which match |signon_realm| and |username|.
- FormRetrievalResult GetLoginsBySignonRealmAndUsername(
+ [[nodiscard]] FormRetrievalResult GetLoginsBySignonRealmAndUsername(
const std::string& signon_realm,
const std::u16string& username,
- PrimaryKeyToFormMap& key_to_form_map) WARN_UNUSED_RESULT;
+ PrimaryKeyToFormMap& key_to_form_map);
// Gets the complete list of not blocklisted credentials.
- bool GetAutofillableLogins(std::vector<std::unique_ptr<PasswordForm>>* forms)
- WARN_UNUSED_RESULT;
+ [[nodiscard]] bool GetAutofillableLogins(
+ std::vector<std::unique_ptr<PasswordForm>>* forms);
// Gets the complete list of blocklisted credentials.
- bool GetBlocklistLogins(std::vector<std::unique_ptr<PasswordForm>>* forms)
- WARN_UNUSED_RESULT;
+ [[nodiscard]] bool GetBlocklistLogins(
+ std::vector<std::unique_ptr<PasswordForm>>* forms);
// Gets the list of auto-sign-inable credentials.
- bool GetAutoSignInLogins(PrimaryKeyToFormMap* key_to_form_map)
- WARN_UNUSED_RESULT;
+ [[nodiscard]] bool GetAutoSignInLogins(PrimaryKeyToFormMap* key_to_form_map);
// Deletes the login database file on disk, and creates a new, empty database.
// This can be used after migrating passwords to some other store, to ensure
@@ -204,7 +201,7 @@ class LoginDatabase : public PasswordStoreSync::MetadataStore {
FRIEND_TEST_ALL_PREFIXES(LoginDatabaseTest,
AddLoginWithEncryptedPasswordAndValue);
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
friend class LoginDatabaseIOSTest;
FRIEND_TEST_ALL_PREFIXES(LoginDatabaseIOSTest, KeychainStorage);
@@ -249,17 +246,17 @@ class LoginDatabase : public PasswordStoreSync::MetadataStore {
// successful, or returning false and leaving cipher_text unchanged if
// encryption fails (e.g., if the underlying OS encryption system is
// temporarily unavailable).
- EncryptionResult EncryptedString(const std::u16string& plain_text,
- std::string* cipher_text) const
- WARN_UNUSED_RESULT;
+ [[nodiscard]] EncryptionResult EncryptedString(
+ const std::u16string& plain_text,
+ std::string* cipher_text) const;
// Decrypts cipher_text, setting the value of plain_text and returning true if
// successful, or returning false and leaving plain_text unchanged if
// decryption fails (e.g., if the underlying OS encryption system is
// temporarily unavailable).
- EncryptionResult DecryptedString(const std::string& cipher_text,
- std::u16string* plain_text) const
- WARN_UNUSED_RESULT;
+ [[nodiscard]] EncryptionResult DecryptedString(
+ const std::string& cipher_text,
+ std::u16string* plain_text) const;
// Fills |form| from the values in the given statement (which is assumed to be
// of the form used by the Get*Logins methods). Fills the corresponding DB
@@ -269,11 +266,11 @@ class LoginDatabase : public PasswordStoreSync::MetadataStore {
// ENCRYPTION_RESULT_SUCCESS, |form| is not filled. If
// |decrypt_and_fill_password_value| is set to false, it always returns
// ENCRYPTION_RESULT_SUCCESS.
- EncryptionResult InitPasswordFormFromStatement(
+ [[nodiscard]] EncryptionResult InitPasswordFormFromStatement(
sql::Statement& s,
bool decrypt_and_fill_password_value,
int* primary_key,
- PasswordForm* form) const WARN_UNUSED_RESULT;
+ PasswordForm* form) const;
// Gets all blocklisted or all non-blocklisted (depending on |blocklisted|)
// credentials. On success returns true and overwrites |forms| with the
@@ -302,10 +299,10 @@ class LoginDatabase : public PasswordStoreSync::MetadataStore {
// returns true.
// |key_to_form_map| must not be null and will be used to return the results.
// The key of the map is the DB primary key.
- FormRetrievalResult StatementToForms(sql::Statement* statement,
- const PasswordFormDigest* matched_form,
- PrimaryKeyToFormMap* key_to_form_map)
- WARN_UNUSED_RESULT;
+ [[nodiscard]] FormRetrievalResult StatementToForms(
+ sql::Statement* statement,
+ const PasswordFormDigest* matched_form,
+ PrimaryKeyToFormMap* key_to_form_map);
// Initializes all the *_statement_ data members with appropriate SQL
// fragments based on |builder|.
diff --git a/chromium/components/password_manager/core/browser/login_database_async_helper.cc b/chromium/components/password_manager/core/browser/login_database_async_helper.cc
new file mode 100644
index 00000000000..e19293e3828
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/login_database_async_helper.cc
@@ -0,0 +1,453 @@
+// Copyright 2022 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.
+
+#include "components/password_manager/core/browser/login_database_async_helper.h"
+
+#include "base/bind.h"
+#include "base/task/sequenced_task_runner.h"
+#include "components/password_manager/core/browser/login_database.h"
+#include "components/password_manager/core/browser/sync/password_sync_bridge.h"
+#include "components/sync/model/client_tag_based_model_type_processor.h"
+#include "components/sync/model/model_type_controller_delegate.h"
+
+namespace password_manager {
+
+namespace {
+
+constexpr base::TimeDelta kSyncTaskTimeout = base::Seconds(30);
+
+} // namespace
+
+LoginDatabaseAsyncHelper::LoginDatabaseAsyncHelper(
+ std::unique_ptr<LoginDatabase> login_db,
+ std::unique_ptr<UnsyncedCredentialsDeletionNotifier> notifier,
+ scoped_refptr<base::SequencedTaskRunner> main_task_runner)
+ : login_db_(std::move(login_db)),
+ deletion_notifier_(std::move(notifier)),
+ main_task_runner_(std::move(main_task_runner)) {
+ DETACH_FROM_SEQUENCE(sequence_checker_);
+ DCHECK(login_db_);
+ DCHECK(main_task_runner_);
+}
+
+LoginDatabaseAsyncHelper::~LoginDatabaseAsyncHelper() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+}
+
+bool LoginDatabaseAsyncHelper::Initialize(
+ PasswordStoreBackend::RemoteChangesReceived remote_form_changes_received,
+ base::RepeatingClosure sync_enabled_or_disabled_cb) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ remote_forms_changes_received_callback_ =
+ std::move(remote_form_changes_received);
+
+ bool success = true;
+ if (!login_db_->Init()) {
+ login_db_.reset();
+ // The initialization should be continued, because PasswordSyncBridge
+ // has to be initialized even if database initialization failed.
+ success = false;
+ LOG(ERROR) << "Could not create/open login database.";
+ }
+ if (success) {
+ login_db_->SetDeletionsHaveSyncedCallback(base::BindRepeating(
+ &LoginDatabaseAsyncHelper::NotifyDeletionsHaveSynced,
+ weak_ptr_factory_.GetWeakPtr()));
+
+ // Delay the actual reporting by 30 seconds, to ensure it doesn't happen
+ // during the "hot phase" of Chrome startup.
+ base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE,
+ base::BindOnce(&LoginDatabaseAsyncHelper::ReportMetrics,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Seconds(30));
+ }
+
+ sync_bridge_ = std::make_unique<PasswordSyncBridge>(
+ std::make_unique<syncer::ClientTagBasedModelTypeProcessor>(
+ syncer::PASSWORDS, base::DoNothing()),
+ static_cast<PasswordStoreSync*>(this),
+ std::move(sync_enabled_or_disabled_cb));
+
+ return success;
+}
+
+LoginsResult LoginDatabaseAsyncHelper::GetAllLogins() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ PrimaryKeyToFormMap key_to_form_map;
+
+ if (!login_db_)
+ return {};
+ FormRetrievalResult result = login_db_->GetAllLogins(&key_to_form_map);
+ if (result != FormRetrievalResult::kSuccess &&
+ result != FormRetrievalResult::kEncryptionServiceFailureWithPartialData)
+ return {};
+
+ std::vector<std::unique_ptr<PasswordForm>> obtained_forms;
+ obtained_forms.reserve(key_to_form_map.size());
+ for (auto& pair : key_to_form_map) {
+ obtained_forms.push_back(std::move(pair.second));
+ }
+ return obtained_forms;
+}
+
+LoginsResult LoginDatabaseAsyncHelper::GetAutofillableLogins() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ std::vector<std::unique_ptr<PasswordForm>> results;
+ if (!login_db_ || !login_db_->GetAutofillableLogins(&results))
+ return {};
+ return results;
+}
+
+LoginsResult LoginDatabaseAsyncHelper::FillMatchingLogins(
+ const std::vector<PasswordFormDigest>& forms,
+ bool include_psl) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ std::vector<std::unique_ptr<PasswordForm>> results;
+ for (const auto& form : forms) {
+ std::vector<std::unique_ptr<PasswordForm>> matched_forms;
+ if (login_db_ && !login_db_->GetLogins(form, include_psl, &matched_forms))
+ continue;
+ results.insert(results.end(),
+ std::make_move_iterator(matched_forms.begin()),
+ std::make_move_iterator(matched_forms.end()));
+ }
+ return results;
+}
+
+PasswordStoreChangeList LoginDatabaseAsyncHelper::AddLogin(
+ const PasswordForm& form) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ BeginTransaction();
+ PasswordStoreChangeList changes = AddLoginSync(form, /*error=*/nullptr);
+ if (sync_bridge_ && !changes.empty())
+ sync_bridge_->ActOnPasswordStoreChanges(changes);
+ // Sync metadata get updated in ActOnPasswordStoreChanges(). Therefore,
+ // CommitTransaction() must be called after ActOnPasswordStoreChanges(),
+ // because sync codebase needs to update metadata atomically together with
+ // the login data.
+ CommitTransaction();
+ return changes;
+}
+
+PasswordStoreChangeList LoginDatabaseAsyncHelper::UpdateLogin(
+ const PasswordForm& form) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ BeginTransaction();
+ PasswordStoreChangeList changes = UpdateLoginSync(form, /*error=*/nullptr);
+ if (sync_bridge_ && !changes.empty())
+ sync_bridge_->ActOnPasswordStoreChanges(changes);
+ // Sync metadata get updated in ActOnPasswordStoreChanges(). Therefore,
+ // CommitTransaction() must be called after ActOnPasswordStoreChanges(),
+ // because sync codebase needs to update metadata atomically together with
+ // the login data.
+ CommitTransaction();
+ return changes;
+}
+
+PasswordStoreChangeList LoginDatabaseAsyncHelper::RemoveLogin(
+ const PasswordForm& form) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ BeginTransaction();
+ PasswordStoreChangeList changes;
+ if (login_db_ && login_db_->RemoveLogin(form, &changes)) {
+ if (sync_bridge_ && !changes.empty())
+ sync_bridge_->ActOnPasswordStoreChanges(changes);
+ }
+ // Sync metadata get updated in ActOnPasswordStoreChanges(). Therefore,
+ // CommitTransaction() must be called after ActOnPasswordStoreChanges(),
+ // because sync codebase needs to update metadata atomically together with
+ // the login data.
+ CommitTransaction();
+ return changes;
+}
+
+PasswordStoreChangeList LoginDatabaseAsyncHelper::RemoveLoginsCreatedBetween(
+ base::Time delete_begin,
+ base::Time delete_end) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ BeginTransaction();
+ PasswordStoreChangeList changes;
+ if (login_db_ && login_db_->RemoveLoginsCreatedBetween(
+ delete_begin, delete_end, &changes)) {
+ if (sync_bridge_ && !changes.empty())
+ sync_bridge_->ActOnPasswordStoreChanges(changes);
+ }
+ // Sync metadata get updated in ActOnPasswordStoreChanges(). Therefore,
+ // CommitTransaction() must be called after ActOnPasswordStoreChanges(),
+ // because sync codebase needs to update metadata atomically together with
+ // the login data.
+ CommitTransaction();
+ return changes;
+}
+
+PasswordStoreChangeList LoginDatabaseAsyncHelper::RemoveLoginsByURLAndTime(
+ const base::RepeatingCallback<bool(const GURL&)>& url_filter,
+ base::Time delete_begin,
+ base::Time delete_end,
+ base::OnceCallback<void(bool)> sync_completion) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ BeginTransaction();
+ PrimaryKeyToFormMap key_to_form_map;
+ PasswordStoreChangeList changes;
+ if (login_db_ && login_db_->GetLoginsCreatedBetween(delete_begin, delete_end,
+ &key_to_form_map)) {
+ for (const auto& pair : key_to_form_map) {
+ PasswordForm* form = pair.second.get();
+ PasswordStoreChangeList remove_changes;
+ if (url_filter.Run(form->url) &&
+ login_db_->RemoveLogin(*form, &remove_changes)) {
+ std::move(remove_changes.begin(), remove_changes.end(),
+ std::back_inserter(changes));
+ }
+ }
+ }
+ if (sync_bridge_ && !changes.empty())
+ sync_bridge_->ActOnPasswordStoreChanges(changes);
+ // Sync metadata get updated in ActOnPasswordStoreChanges(). Therefore,
+ // CommitTransaction() must be called after ActOnPasswordStoreChanges(),
+ // because sync codebase needs to update metadata atomically together with
+ // the login data.
+ CommitTransaction();
+
+ if (sync_completion) {
+ deletions_have_synced_callbacks_.push_back(std::move(sync_completion));
+ // Start a timeout for sync, or restart it if it was already running.
+ deletions_have_synced_timeout_.Reset(
+ base::BindOnce(&LoginDatabaseAsyncHelper::NotifyDeletionsHaveSynced,
+ weak_ptr_factory_.GetWeakPtr(),
+ /*success=*/false));
+ base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, deletions_have_synced_timeout_.callback(), kSyncTaskTimeout);
+
+ // Do an immediate check for the case where there are already no unsynced
+ // deletions.
+ if (!GetMetadataStore()->HasUnsyncedDeletions())
+ NotifyDeletionsHaveSynced(/*success=*/true);
+ }
+ return changes;
+}
+
+PasswordStoreChangeList LoginDatabaseAsyncHelper::DisableAutoSignInForOrigins(
+ const base::RepeatingCallback<bool(const GURL&)>& origin_filter) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ PrimaryKeyToFormMap key_to_form_map;
+ PasswordStoreChangeList changes;
+ if (!login_db_ || !login_db_->GetAutoSignInLogins(&key_to_form_map))
+ return changes;
+
+ std::set<GURL> origins_to_update;
+ for (const auto& pair : key_to_form_map) {
+ if (origin_filter.Run(pair.second->url))
+ origins_to_update.insert(pair.second->url);
+ }
+
+ std::set<GURL> origins_updated;
+ for (const GURL& origin : origins_to_update) {
+ if (login_db_->DisableAutoSignInForOrigin(origin))
+ origins_updated.insert(origin);
+ }
+
+ for (const auto& pair : key_to_form_map) {
+ if (origins_updated.count(pair.second->url)) {
+ changes.emplace_back(PasswordStoreChange::UPDATE, *pair.second,
+ FormPrimaryKey(pair.first));
+ }
+ }
+ return changes;
+}
+
+// Synchronous implementation for manipulating with statistics.
+void LoginDatabaseAsyncHelper::AddSiteStats(const InteractionsStats& stats) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ if (login_db_)
+ login_db_->stats_table().AddRow(stats);
+}
+
+void LoginDatabaseAsyncHelper::RemoveSiteStats(const GURL& origin_domain) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ if (login_db_)
+ login_db_->stats_table().RemoveRow(origin_domain);
+}
+
+std::vector<InteractionsStats> LoginDatabaseAsyncHelper::GetSiteStats(
+ const GURL& origin_domain) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ return login_db_ ? login_db_->stats_table().GetRows(origin_domain)
+ : std::vector<InteractionsStats>();
+}
+
+void LoginDatabaseAsyncHelper::RemoveStatisticsByOriginAndTime(
+ const base::RepeatingCallback<bool(const GURL&)>& origin_filter,
+ base::Time delete_begin,
+ base::Time delete_end) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ if (login_db_) {
+ login_db_->stats_table().RemoveStatsByOriginAndTime(
+ origin_filter, delete_begin, delete_end);
+ }
+}
+
+// Synchronous implementation for manipulating with field info.
+void LoginDatabaseAsyncHelper::AddFieldInfo(const FieldInfo& field_info) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ if (login_db_)
+ login_db_->field_info_table().AddRow(field_info);
+}
+
+std::vector<FieldInfo> LoginDatabaseAsyncHelper::GetAllFieldInfo() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ return login_db_ ? login_db_->field_info_table().GetAllRows()
+ : std::vector<FieldInfo>();
+}
+
+void LoginDatabaseAsyncHelper::RemoveFieldInfoByTime(base::Time remove_begin,
+ base::Time remove_end) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ if (login_db_)
+ login_db_->field_info_table().RemoveRowsByTime(remove_begin, remove_end);
+}
+
+base::WeakPtr<syncer::ModelTypeControllerDelegate>
+LoginDatabaseAsyncHelper::GetSyncControllerDelegate() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ return sync_bridge_->change_processor()->GetControllerDelegate();
+}
+
+PasswordStoreChangeList LoginDatabaseAsyncHelper::AddLoginSync(
+ const PasswordForm& form,
+ AddLoginError* error) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ if (!login_db_) {
+ if (error) {
+ *error = AddLoginError::kDbNotAvailable;
+ }
+ return PasswordStoreChangeList();
+ }
+ return login_db_->AddLogin(form, error);
+}
+
+PasswordStoreChangeList LoginDatabaseAsyncHelper::UpdateLoginSync(
+ const PasswordForm& form,
+ UpdateLoginError* error) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ if (!login_db_) {
+ if (error) {
+ *error = UpdateLoginError::kDbNotAvailable;
+ }
+ return PasswordStoreChangeList();
+ }
+ return login_db_->UpdateLogin(form, error);
+}
+
+void LoginDatabaseAsyncHelper::NotifyLoginsChanged(
+ const PasswordStoreChangeList& changes) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ if (!remote_forms_changes_received_callback_)
+ return;
+ main_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(remote_forms_changes_received_callback_, changes));
+}
+
+void LoginDatabaseAsyncHelper::NotifyDeletionsHaveSynced(bool success) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ // Either all deletions have been committed to the Sync server, or Sync is
+ // telling us that it won't commit them (because Sync was turned off
+ // permanently). In either case, run the corresponding callbacks now (on the
+ // main task runner).
+ DCHECK(!success || !GetMetadataStore()->HasUnsyncedDeletions());
+ for (auto& callback : deletions_have_synced_callbacks_) {
+ main_task_runner_->PostTask(FROM_HERE,
+ base::BindOnce(std::move(callback), success));
+ }
+ deletions_have_synced_timeout_.Cancel();
+ deletions_have_synced_callbacks_.clear();
+}
+
+void LoginDatabaseAsyncHelper::NotifyUnsyncedCredentialsWillBeDeleted(
+ std::vector<PasswordForm> unsynced_credentials) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(IsAccountStore());
+ // |deletion_notifier_| only gets set for desktop.
+ if (deletion_notifier_) {
+ main_task_runner_->PostTask(
+ FROM_HERE, base::BindOnce(&UnsyncedCredentialsDeletionNotifier::Notify,
+ deletion_notifier_->GetWeakPtr(),
+ std::move(unsynced_credentials)));
+ }
+}
+
+bool LoginDatabaseAsyncHelper::BeginTransaction() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ if (login_db_)
+ return login_db_->BeginTransaction();
+ return false;
+}
+
+void LoginDatabaseAsyncHelper::RollbackTransaction() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ if (login_db_)
+ login_db_->RollbackTransaction();
+}
+
+bool LoginDatabaseAsyncHelper::CommitTransaction() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ if (login_db_)
+ return login_db_->CommitTransaction();
+ return false;
+}
+
+FormRetrievalResult LoginDatabaseAsyncHelper::ReadAllLogins(
+ PrimaryKeyToFormMap* key_to_form_map) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ if (!login_db_)
+ return FormRetrievalResult::kDbError;
+ return login_db_->GetAllLogins(key_to_form_map);
+}
+
+PasswordStoreChangeList LoginDatabaseAsyncHelper::RemoveLoginByPrimaryKeySync(
+ FormPrimaryKey primary_key) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ PasswordStoreChangeList changes;
+ if (login_db_ && login_db_->RemoveLoginByPrimaryKey(primary_key, &changes)) {
+ return changes;
+ }
+ return PasswordStoreChangeList();
+}
+
+PasswordStoreSync::MetadataStore* LoginDatabaseAsyncHelper::GetMetadataStore() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ return login_db_.get();
+}
+
+bool LoginDatabaseAsyncHelper::IsAccountStore() const {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ return login_db_ && login_db_->is_account_store();
+}
+
+bool LoginDatabaseAsyncHelper::DeleteAndRecreateDatabaseFile() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ return login_db_ && login_db_->DeleteAndRecreateDatabaseFile();
+}
+
+DatabaseCleanupResult LoginDatabaseAsyncHelper::DeleteUndecryptableLogins() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ if (!login_db_)
+ return DatabaseCleanupResult::kDatabaseUnavailable;
+ return login_db_->DeleteUndecryptableLogins();
+}
+
+// Reports password store metrics that aren't reported by the
+// StoreMetricsReporter. Namely, metrics related to inaccessible passwords,
+// and bubble statistics.
+void LoginDatabaseAsyncHelper::ReportMetrics() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ if (!login_db_)
+ return;
+ login_db_->ReportMetrics();
+}
+
+} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/login_database_async_helper.h b/chromium/components/password_manager/core/browser/login_database_async_helper.h
new file mode 100644
index 00000000000..9843e57f53f
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/login_database_async_helper.h
@@ -0,0 +1,149 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_LOGIN_DATABASE_ASYNC_HELPER_H_
+#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_LOGIN_DATABASE_ASYNC_HELPER_H_
+
+#include "base/cancelable_callback.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/memory/weak_ptr.h"
+#include "components/password_manager/core/browser/password_store_backend.h"
+#include "components/password_manager/core/browser/password_store_sync.h"
+
+namespace syncer {
+class ModelTypeControllerDelegate;
+} // namespace syncer
+
+namespace password_manager {
+
+class LoginDatabase;
+class PasswordSyncBridge;
+class UnsyncedCredentialsDeletionNotifier;
+
+struct FieldInfo;
+struct InteractionsStats;
+
+// Class which interacts directly with LoginDatabase. It is also responsible to
+// sync passwords. Works only on background sequence.
+class LoginDatabaseAsyncHelper : private PasswordStoreSync {
+ public:
+ LoginDatabaseAsyncHelper(
+ std::unique_ptr<LoginDatabase> login_db,
+ std::unique_ptr<UnsyncedCredentialsDeletionNotifier> notifier,
+ scoped_refptr<base::SequencedTaskRunner> main_task_runner);
+
+ ~LoginDatabaseAsyncHelper() override;
+
+ // Opens |login_db_| and creates |sync_bridge_|.
+ bool Initialize(
+ PasswordStoreBackend::RemoteChangesReceived remote_form_changes_received,
+ base::RepeatingClosure sync_enabled_or_disabled_cb);
+
+ // Synchronous implementation of PasswordStoreBackend interface.
+ LoginsResult GetAllLogins();
+ LoginsResult GetAutofillableLogins();
+ LoginsResult FillMatchingLogins(const std::vector<PasswordFormDigest>& forms,
+ bool include_psl);
+ PasswordStoreChangeList AddLogin(const PasswordForm& form);
+ PasswordStoreChangeList UpdateLogin(const PasswordForm& form);
+ PasswordStoreChangeList RemoveLogin(const PasswordForm& form);
+ PasswordStoreChangeList RemoveLoginsCreatedBetween(base::Time delete_begin,
+ base::Time delete_end);
+ PasswordStoreChangeList RemoveLoginsByURLAndTime(
+ const base::RepeatingCallback<bool(const GURL&)>& url_filter,
+ base::Time delete_begin,
+ base::Time delete_end,
+ base::OnceCallback<void(bool)> sync_completion);
+ PasswordStoreChangeList DisableAutoSignInForOrigins(
+ const base::RepeatingCallback<bool(const GURL&)>& origin_filter);
+
+ // Synchronous implementation of SmartBubbleStatsStore interface.
+ void AddSiteStats(const InteractionsStats& stats);
+ void RemoveSiteStats(const GURL& origin_domain);
+ std::vector<InteractionsStats> GetSiteStats(const GURL& origin_domain);
+ void RemoveStatisticsByOriginAndTime(
+ const base::RepeatingCallback<bool(const GURL&)>& origin_filter,
+ base::Time delete_begin,
+ base::Time delete_end);
+
+ // Synchronous implementation of FieldInfoStore.
+ void AddFieldInfo(const FieldInfo& field_info);
+ std::vector<FieldInfo> GetAllFieldInfo();
+ void RemoveFieldInfoByTime(base::Time remove_begin, base::Time remove_end);
+
+ // Instantiates a proxy controller delegate to react to sync events.
+ base::WeakPtr<syncer::ModelTypeControllerDelegate>
+ GetSyncControllerDelegate();
+
+ private:
+ // Implements PasswordStoreSync interface.
+ PasswordStoreChangeList AddLoginSync(const PasswordForm& form,
+ AddLoginError* error) override;
+ PasswordStoreChangeList UpdateLoginSync(const PasswordForm& form,
+ UpdateLoginError* error) override;
+ void NotifyLoginsChanged(const PasswordStoreChangeList& changes) override;
+ void NotifyDeletionsHaveSynced(bool success) override;
+ void NotifyUnsyncedCredentialsWillBeDeleted(
+ std::vector<PasswordForm> unsynced_credentials) override;
+ bool BeginTransaction() override;
+ void RollbackTransaction() override;
+ bool CommitTransaction() override;
+ FormRetrievalResult ReadAllLogins(
+ PrimaryKeyToFormMap* key_to_form_map) override;
+ PasswordStoreChangeList RemoveLoginByPrimaryKeySync(
+ FormPrimaryKey primary_key) override;
+ PasswordStoreSync::MetadataStore* GetMetadataStore() override;
+ bool IsAccountStore() const override;
+ bool DeleteAndRecreateDatabaseFile() override;
+ DatabaseCleanupResult DeleteUndecryptableLogins() override;
+
+ // Reports password store metrics that aren't reported by the
+ // StoreMetricsReporter. Namely, metrics related to inaccessible passwords,
+ // and bubble statistics.
+ void ReportMetrics();
+
+ // Ensures that all methods, excluding construction, are called on the same
+ // sequence.
+ SEQUENCE_CHECKER(sequence_checker_);
+
+ // The login SQL database. The LoginDatabase instance is received via the
+ // constructor. It is passed in an uninitialized state, to allow injecting
+ // mocks. It will be initilaized by calling Initialize. If opening the DB
+ // fails, |login_db_| will be reset and stay NULL for the lifetime of |this|.
+ std::unique_ptr<LoginDatabase> login_db_
+ GUARDED_BY_CONTEXT(sequence_checker_);
+
+ std::unique_ptr<PasswordSyncBridge> sync_bridge_
+ GUARDED_BY_CONTEXT(sequence_checker_);
+
+ // Whenever 'sync_bridge_'receive remote changes this callback is used to
+ // notify PasswordStore observers about them. Called on a main sequence from
+ // the 'NotifyLoginsChanged'.
+ PasswordStoreBackend::RemoteChangesReceived
+ remote_forms_changes_received_callback_
+ GUARDED_BY_CONTEXT(sequence_checker_);
+
+ std::unique_ptr<UnsyncedCredentialsDeletionNotifier> deletion_notifier_
+ GUARDED_BY_CONTEXT(sequence_checker_);
+
+ // A list of callbacks that should be run once all pending deletions have been
+ // sent to the Sync server. Note that the vector itself lives on the
+ // background thread, but the callbacks must be run on the main thread!
+ std::vector<base::OnceCallback<void(bool)>> deletions_have_synced_callbacks_
+ GUARDED_BY_CONTEXT(sequence_checker_);
+
+ // Timeout closure that runs if sync takes too long to propagate deletions.
+ base::CancelableOnceClosure deletions_have_synced_timeout_
+ GUARDED_BY_CONTEXT(sequence_checker_);
+
+ scoped_refptr<base::SequencedTaskRunner> main_task_runner_
+ GUARDED_BY_CONTEXT(sequence_checker_);
+
+ base::WeakPtrFactory<LoginDatabaseAsyncHelper> weak_ptr_factory_
+ GUARDED_BY_CONTEXT(sequence_checker_){this};
+};
+
+} // namespace password_manager
+
+#endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_LOGIN_DATABASE_ASYNC_HELPER_H_
diff --git a/chromium/components/password_manager/core/browser/login_database_ios_unittest.cc b/chromium/components/password_manager/core/browser/login_database_ios_unittest.cc
index e8ed6a90aaf..0305aa527fa 100644
--- a/chromium/components/password_manager/core/browser/login_database_ios_unittest.cc
+++ b/chromium/components/password_manager/core/browser/login_database_ios_unittest.cc
@@ -7,9 +7,10 @@
#include <Security/Security.h>
#include <stddef.h>
+#include <tuple>
+
#include "base/cxx17_backports.h"
#include "base/files/scoped_temp_dir.h"
-#include "base/ignore_result.h"
#include "base/mac/scoped_cftyperef.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/task_environment.h"
@@ -144,7 +145,7 @@ TEST_F(LoginDatabaseIOSTest, UpdateLogin) {
form.password_element = u"pwd";
form.password_value = u"example";
- ignore_result(login_db_->AddLogin(form));
+ std::ignore = login_db_->AddLogin(form);
form.password_value = u"secret";
@@ -169,7 +170,7 @@ TEST_F(LoginDatabaseIOSTest, RemoveLogin) {
ASSERT_THAT(login_db_->AddLogin(form), testing::SizeIs(1));
- ignore_result(login_db_->RemoveLogin(form, /*changes=*/nullptr));
+ std::ignore = login_db_->RemoveLogin(form, /*changes=*/nullptr);
std::vector<std::unique_ptr<PasswordForm>> forms;
EXPECT_TRUE(login_db_->GetLogins(PasswordFormDigest(form), true, &forms));
@@ -199,7 +200,7 @@ TEST_F(LoginDatabaseIOSTest, RemoveLoginsCreatedBetween) {
forms[2].password_value = u"pass2";
for (size_t i = 0; i < base::size(forms); i++) {
- ignore_result(login_db_->AddLogin(forms[i]));
+ std::ignore = login_db_->AddLogin(forms[i]);
}
login_db_->RemoveLoginsCreatedBetween(base::Time::FromDoubleT(150),
diff --git a/chromium/components/password_manager/core/browser/login_database_posix.cc b/chromium/components/password_manager/core/browser/login_database_posix.cc
index 8f5f8272e34..dafb565b372 100644
--- a/chromium/components/password_manager/core/browser/login_database_posix.cc
+++ b/chromium/components/password_manager/core/browser/login_database_posix.cc
@@ -38,8 +38,8 @@ LoginDatabase::EncryptionResult LoginDatabase::EncryptedString(
LoginDatabase::EncryptionResult LoginDatabase::DecryptedString(
const std::string& cipher_text,
std::u16string* plain_text) const {
-#if !defined(OS_FUCHSIA)
-#if defined(OS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH)
+#if !BUILDFLAG(IS_FUCHSIA)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH)
// On Android and ChromeOS, we have a mix of obfuscated and plain-text
// passwords. Obfuscated passwords always start with "v10", therefore anything
// else is plain-text.
@@ -56,10 +56,10 @@ LoginDatabase::EncryptionResult LoginDatabase::DecryptedString(
PasswordDecryptionResult::kSucceededBySkipping);
return ENCRYPTION_RESULT_SUCCESS;
}
-#endif // !defined(OS_FUCHSIA)
+#endif // !BUILDFLAG(IS_FUCHSIA)
bool decryption_success = OSCrypt::DecryptString16(cipher_text, plain_text);
-#if defined(OS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH)
// If decryption failed, we assume it was because the value was actually a
// plain-text password which started with "v10".
// TODO(crbug.com/960322): Remove this when there isn't a mix of plain-text
diff --git a/chromium/components/password_manager/core/browser/login_database_unittest.cc b/chromium/components/password_manager/core/browser/login_database_unittest.cc
index d9c340867ed..ad2885689c7 100644
--- a/chromium/components/password_manager/core/browser/login_database_unittest.cc
+++ b/chromium/components/password_manager/core/browser/login_database_unittest.cc
@@ -8,18 +8,18 @@
#include <stdint.h>
#include <memory>
+#include <tuple>
#include <utility>
-#include "base/compiler_specific.h"
#include "base/containers/flat_map.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
-#include "base/ignore_result.h"
#include "base/path_service.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/metrics/histogram_tester.h"
+#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
@@ -129,7 +129,7 @@ int64_t GetFirstColumn(sql::Statement& s) {
}
template <>
-ALLOW_UNUSED_TYPE std::string GetFirstColumn(sql::Statement& s) {
+[[maybe_unused]] std::string GetFirstColumn(sql::Statement& s) {
return s.ColumnString(0);
}
@@ -155,7 +155,7 @@ std::vector<T> GetColumnValuesFromDatabase(const base::FilePath& database_path,
return results;
}
-#if defined(OS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH)
// Set the new password value for all the rows with the specified username.
void UpdatePasswordValueForUsername(const base::FilePath& database_path,
const std::u16string& username,
@@ -172,7 +172,7 @@ void UpdatePasswordValueForUsername(const base::FilePath& database_path,
CHECK(s.Run());
}
-#endif // defined(OS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH)
+#endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH)
bool AddZeroClickableLogin(LoginDatabase* db,
const std::string& unique_string,
@@ -1551,10 +1551,10 @@ TEST_F(LoginDatabaseTest, ReportMetricsTest) {
histogram_tester.ExpectUniqueSample("PasswordManager.InaccessiblePasswords",
0, 1);
-#if !defined(OS_IOS) && !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_IOS) && !BUILDFLAG(IS_ANDROID)
histogram_tester.ExpectUniqueSample(
"PasswordManager.BubbleSuppression.AccountsInStatisticsTable", 4, 1);
-#endif // !defined(OS_IOS) && !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_IOS) && !BUILDFLAG(IS_ANDROID)
}
// This test is mostly a copy of ReportMetricsTest, but covering the account
@@ -1698,7 +1698,7 @@ TEST_F(LoginDatabaseTest, WriteThenDeleteSyncMetadata) {
metadata_batch->GetModelTypeState().SerializeAsString());
}
-#if defined(OS_POSIX)
+#if BUILDFLAG(IS_POSIX)
// Only the current user has permission to read the database.
//
// Only POSIX because GetPosixFilePermissions() only exists on POSIX.
@@ -1709,9 +1709,9 @@ TEST_F(LoginDatabaseTest, FilePermissions) {
EXPECT_TRUE(base::GetPosixFilePermissions(file_, &mode));
EXPECT_EQ((mode & base::FILE_PERMISSION_USER_MASK), mode);
}
-#endif // defined(OS_POSIX)
+#endif // BUILDFLAG(IS_POSIX)
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
// Test that LoginDatabase encrypts the password values that it stores.
TEST_F(LoginDatabaseTest, EncryptionEnabled) {
PasswordForm password_form = GenerateExamplePasswordForm();
@@ -1727,9 +1727,9 @@ TEST_F(LoginDatabaseTest, EncryptionEnabled) {
&decrypted_pw));
EXPECT_EQ(decrypted_pw, password_form.password_value);
}
-#endif // !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_IOS)
-#if defined(OS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH)
// On Android and ChromeOS there is a mix of plain-text and obfuscated
// passwords. Verify that they can both be accessed. Obfuscated passwords start
// with "v10". Some password values also start with "v10". Test that both are
@@ -1777,7 +1777,7 @@ TEST_F(LoginDatabaseTest, HandleObfuscationMix) {
EXPECT_EQ(k_plain_text_pw116, forms[1]->password_value);
EXPECT_EQ(k_plain_text_pw216, forms[2]->password_value);
}
-#endif // defined(OS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH)
+#endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH)
// If the database initialisation fails, the initialisation transaction should
// roll back without crashing.
@@ -1919,6 +1919,18 @@ void LoginDatabaseMigrationTest::MigrationToVCurrent(
ASSERT_EQ(1U, result.size());
EXPECT_EQ(form, *result[0]);
EXPECT_TRUE(db.RemoveLogin(form, /*changes=*/nullptr));
+
+ if (version() == 31) {
+ // Check that unset values of 'insecure_credentials.create_time' are set
+ // to current time.
+ std::vector<InsecureCredential> insecure_credentials(
+ db.insecure_credentials_table().GetRows(FormPrimaryKey(1)));
+ ASSERT_EQ(2U, insecure_credentials.size());
+ base::Time time_now = base::Time::Now();
+ base::Time time_slightly_before = time_now - base::Seconds(2);
+ EXPECT_LE(insecure_credentials[0].create_time, time_now);
+ EXPECT_GE(insecure_credentials[0].create_time, time_slightly_before);
+ }
}
// Added 07/21. Safe to remove in a year.
if (version() <= 29) {
@@ -2078,8 +2090,9 @@ TEST_F(LoginDatabaseUndecryptableLoginsTest, DeleteUndecryptableLoginsTest) {
base::HistogramTester histogram_tester;
ASSERT_TRUE(db.Init());
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC) || (BUILDFLAG(IS_LINUX) && !BUILDFLAG(IS_CHROMECAST))
// Make sure that we can't get any logins when database is corrupted.
+ // Disabling the checks in chromecast because encryption is unavailable.
std::vector<std::unique_ptr<PasswordForm>> result;
EXPECT_FALSE(db.GetAutofillableLogins(&result));
EXPECT_TRUE(result.empty());
@@ -2095,12 +2108,15 @@ TEST_F(LoginDatabaseUndecryptableLoginsTest, DeleteUndecryptableLoginsTest) {
EXPECT_THAT(result, IsEmpty());
RunUntilIdle();
+#elif (BUILDFLAG(IS_LINUX) && BUILDFLAG(IS_CHROMECAST))
+ EXPECT_EQ(DatabaseCleanupResult::kEncryptionUnavailable,
+ db.DeleteUndecryptableLogins());
#else
EXPECT_EQ(DatabaseCleanupResult::kSuccess, db.DeleteUndecryptableLogins());
#endif
// Check histograms.
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC) || (BUILDFLAG(IS_LINUX) && !BUILDFLAG(IS_CHROMECAST))
histogram_tester.ExpectUniqueSample("PasswordManager.CleanedUpPasswords", 2,
1);
histogram_tester.ExpectUniqueSample(
@@ -2114,7 +2130,7 @@ TEST_F(LoginDatabaseUndecryptableLoginsTest, DeleteUndecryptableLoginsTest) {
#endif
}
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
TEST_F(LoginDatabaseUndecryptableLoginsTest,
PasswordRecoveryDisabledGetLogins) {
AddDummyLogin("foo1", GURL("https://foo1.com/"), false,
@@ -2150,7 +2166,87 @@ TEST_F(LoginDatabaseUndecryptableLoginsTest, KeychainLockedTest) {
"PasswordManager.DeleteUndecryptableLoginsReturnValue",
metrics_util::DeleteCorruptedPasswordsResult::kEncryptionUnavailable, 1);
}
-#endif // defined(OS_MAC)
+#endif // BUILDFLAG(IS_MAC)
+
+#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
+// Test getting auto sign in logins when there are undecryptable ones
+TEST_F(LoginDatabaseUndecryptableLoginsTest, GetAutoSignInLogins) {
+ PrimaryKeyToFormMap key_to_form_map;
+
+ auto form1 =
+ AddDummyLogin("foo1", GURL("https://foo1.com/"),
+ /*should_be_corrupted=*/false, /*blocklisted=*/false);
+ auto form2 =
+ AddDummyLogin("foo2", GURL("https://foo2.com/"),
+ /*should_be_corrupted=*/true, /*blocklisted=*/false);
+ auto form3 =
+ AddDummyLogin("foo3", GURL("https://foo3.com/"),
+ /*should_be_corrupted=*/false, /*blocklisted=*/false);
+
+ LoginDatabase db(database_path(), IsAccountStore(false));
+ ASSERT_TRUE(db.Init());
+
+ EXPECT_FALSE(db.GetAutoSignInLogins(&key_to_form_map));
+
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeature(features::kSkipUndecryptablePasswords);
+
+ EXPECT_TRUE(db.GetAutoSignInLogins(&key_to_form_map));
+ EXPECT_THAT(key_to_form_map, UnorderedElementsAre(Pair(_, Pointee(form1)),
+ Pair(_, Pointee(form3))));
+}
+
+// Test getting logins when there are undecryptable ones
+TEST_F(LoginDatabaseUndecryptableLoginsTest, GetLogins) {
+ auto form1 =
+ AddDummyLogin("user1", GURL("http://www.google.com/"),
+ /*should_be_corrupted=*/false, /*blocklisted=*/false);
+ auto form2 =
+ AddDummyLogin("user2", GURL("http://www.google.com/"),
+ /*should_be_corrupted=*/true, /*blocklisted=*/false);
+ LoginDatabase db(database_path(), IsAccountStore(false));
+ ASSERT_TRUE(db.Init());
+ std::vector<std::unique_ptr<PasswordForm>> result;
+
+ PasswordForm form = GenerateExamplePasswordForm();
+ EXPECT_FALSE(db.GetLogins(PasswordFormDigest(form),
+ /*should_PSL_matching_apply=*/false, &result));
+
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeature(features::kSkipUndecryptablePasswords);
+ result.clear();
+
+ EXPECT_TRUE(db.GetLogins(PasswordFormDigest(form),
+ /*should_PSL_matching_apply=*/false, &result));
+ EXPECT_THAT(result, ElementsAre(Pointee(form1)));
+}
+
+// Test getting auto fillable logins when there are undecryptable ones
+TEST_F(LoginDatabaseUndecryptableLoginsTest, GetAutofillableLogins) {
+ std::vector<std::unique_ptr<PasswordForm>> result;
+
+ auto form1 =
+ AddDummyLogin("foo1", GURL("https://foo1.com/"),
+ /*should_be_corrupted=*/false, /*blocklisted=*/false);
+ auto form2 =
+ AddDummyLogin("foo2", GURL("https://foo2.com/"),
+ /*should_be_corrupted=*/true, /*blocklisted=*/false);
+ auto form3 =
+ AddDummyLogin("foo3", GURL("https://foo3.com/"),
+ /*should_be_corrupted=*/false, /*blocklisted=*/true);
+
+ LoginDatabase db(database_path(), IsAccountStore(false));
+ ASSERT_TRUE(db.Init());
+
+ EXPECT_FALSE(db.GetAutofillableLogins(&result));
+
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeature(features::kSkipUndecryptablePasswords);
+
+ EXPECT_TRUE(db.GetAutofillableLogins(&result));
+ EXPECT_THAT(result, ElementsAre(Pointee(form1)));
+}
+#endif
// Test encrypted passwords are present in add change lists.
TEST_F(LoginDatabaseTest, EncryptedPasswordAdd) {
@@ -2175,7 +2271,7 @@ TEST_F(LoginDatabaseTest, EncryptedPasswordAddWithReplaceSemantics) {
form.password_element = u"pwd";
form.password_value = u"example";
- ignore_result(db().AddLogin(form));
+ std::ignore = db().AddLogin(form);
form.password_value = u"secret";
@@ -2195,7 +2291,7 @@ TEST_F(LoginDatabaseTest, EncryptedPasswordUpdate) {
form.password_element = u"pwd";
form.password_value = u"example";
- ignore_result(db().AddLogin(form));
+ std::ignore = db().AddLogin(form);
form.password_value = u"secret";
@@ -2226,8 +2322,7 @@ TEST_F(LoginDatabaseTest, GetLoginsEncryptedPassword) {
TEST_F(LoginDatabaseTest, RetrievesInsecureDataWithLogins) {
PasswordForm form = GenerateExamplePasswordForm();
- ignore_result(db().AddLogin(form));
-
+ std::ignore = db().AddLogin(form);
base::flat_map<InsecureType, InsecurityMetadata> issues;
issues[InsecureType::kLeaked] =
@@ -2252,7 +2347,7 @@ TEST_F(LoginDatabaseTest, RetrievesInsecureDataWithLogins) {
TEST_F(LoginDatabaseTest, RemovingLoginRemovesInsecureCredentials) {
PasswordForm form = GenerateExamplePasswordForm();
- ignore_result(db().AddLogin(form));
+ std::ignore = db().AddLogin(form);
InsecureCredential credential1{form.signon_realm, form.username_value,
base::Time(), InsecureType::kLeaked,
IsMuted(false)};
@@ -2318,7 +2413,7 @@ TEST_F(LoginDatabaseTest, GetLoginsBySignonRealmAndUsername) {
TEST_F(LoginDatabaseTest, UpdateLoginWithAddedInsecureCredential) {
PasswordForm form = GenerateExamplePasswordForm();
- ignore_result(db().AddLogin(form));
+ std::ignore = db().AddLogin(form);
InsecureCredential insecure_credential{form.signon_realm, form.username_value,
base::Time(), InsecureType::kLeaked,
IsMuted(false)};
@@ -2336,7 +2431,7 @@ TEST_F(LoginDatabaseTest, UpdateLoginWithAddedInsecureCredential) {
TEST_F(LoginDatabaseTest, UpdateLoginWithUpdatedInsecureCredential) {
PasswordForm form = GenerateExamplePasswordForm();
- ignore_result(db().AddLogin(form));
+ std::ignore = db().AddLogin(form);
InsecureCredential insecure_credential{form.signon_realm, form.username_value,
base::Time(), InsecureType::kLeaked,
IsMuted(false)};
@@ -2362,7 +2457,7 @@ TEST_F(LoginDatabaseTest, UpdateLoginWithUpdatedInsecureCredential) {
TEST_F(LoginDatabaseTest, UpdateLoginWithRemovedInsecureCredentialEntry) {
PasswordForm form = GenerateExamplePasswordForm();
- ignore_result(db().AddLogin(form));
+ std::ignore = db().AddLogin(form);
InsecureCredential leaked{form.signon_realm, form.username_value,
base::Time(), InsecureType::kLeaked,
IsMuted(false)};
@@ -2398,7 +2493,7 @@ TEST_F(LoginDatabaseTest,
AddLoginWithDifferentPasswordRemovesInsecureCredentials) {
PasswordForm form = GenerateExamplePasswordForm();
- ignore_result(db().AddLogin(form));
+ std::ignore = db().AddLogin(form);
InsecureCredential credential1{form.signon_realm, form.username_value,
base::Time(), InsecureType::kLeaked,
IsMuted(false)};
@@ -2452,7 +2547,7 @@ TEST_F(LoginDatabaseTest, RemoveLoginRemovesInsecureCredentials) {
form.password_issues = {
{InsecureType::kLeaked,
InsecurityMetadata(base::Time::FromTimeT(1), IsMuted(false))}};
- ignore_result(db().AddLogin(form));
+ std::ignore = db().AddLogin(form);
InsecureCredential leaked{form.signon_realm, form.username_value,
base::Time::FromTimeT(1), InsecureType::kLeaked,
diff --git a/chromium/components/password_manager/core/browser/mock_password_change_success_tracker.cc b/chromium/components/password_manager/core/browser/mock_password_change_success_tracker.cc
new file mode 100644
index 00000000000..95f87393046
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/mock_password_change_success_tracker.cc
@@ -0,0 +1,13 @@
+// Copyright 2022 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.
+
+#include "components/password_manager/core/browser/mock_password_change_success_tracker.h"
+
+namespace password_manager {
+
+MockPasswordChangeSuccessTracker::MockPasswordChangeSuccessTracker() = default;
+
+MockPasswordChangeSuccessTracker::~MockPasswordChangeSuccessTracker() = default;
+
+} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/mock_password_change_success_tracker.h b/chromium/components/password_manager/core/browser/mock_password_change_success_tracker.h
new file mode 100644
index 00000000000..43ff34fd2cc
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/mock_password_change_success_tracker.h
@@ -0,0 +1,31 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_MOCK_PASSWORD_CHANGE_SUCCESS_TRACKER_H_
+#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_MOCK_PASSWORD_CHANGE_SUCCESS_TRACKER_H_
+
+#include "components/password_manager/core/browser/password_change_success_tracker.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace password_manager {
+
+// Mocked PasswordChangeSuccessTracker used by unit tests.
+class MockPasswordChangeSuccessTracker : public PasswordChangeSuccessTracker {
+ public:
+ MockPasswordChangeSuccessTracker();
+ ~MockPasswordChangeSuccessTracker() override;
+
+ MOCK_METHOD3(OnChangePasswordFlowStarted,
+ void(const GURL& url,
+ const std::string& username,
+ StartEvent event_type));
+ MOCK_METHOD3(OnChangePasswordFlowCompleted,
+ void(const GURL& url,
+ const std::string& username,
+ EndEvent event_type));
+};
+
+} // namespace password_manager
+
+#endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_MOCK_PASSWORD_CHANGE_SUCCESS_TRACKER_H_
diff --git a/chromium/components/password_manager/core/browser/mock_password_store_backend.cc b/chromium/components/password_manager/core/browser/mock_password_store_backend.cc
index 86faa6f1f40..4a5abb3f134 100644
--- a/chromium/components/password_manager/core/browser/mock_password_store_backend.cc
+++ b/chromium/components/password_manager/core/browser/mock_password_store_backend.cc
@@ -6,6 +6,9 @@
namespace password_manager {
+MockPasswordBackendSyncDelegate::MockPasswordBackendSyncDelegate() = default;
+MockPasswordBackendSyncDelegate::~MockPasswordBackendSyncDelegate() = default;
+
MockPasswordStoreBackend::MockPasswordStoreBackend() = default;
MockPasswordStoreBackend::~MockPasswordStoreBackend() = default;
diff --git a/chromium/components/password_manager/core/browser/mock_password_store_backend.h b/chromium/components/password_manager/core/browser/mock_password_store_backend.h
index df756d8b90c..5b9bf3ea74b 100644
--- a/chromium/components/password_manager/core/browser/mock_password_store_backend.h
+++ b/chromium/components/password_manager/core/browser/mock_password_store_backend.h
@@ -19,15 +19,22 @@
namespace password_manager {
+class MockPasswordBackendSyncDelegate
+ : public PasswordStoreBackend::SyncDelegate {
+ public:
+ MockPasswordBackendSyncDelegate();
+ ~MockPasswordBackendSyncDelegate() override;
+
+ MOCK_METHOD(bool, IsSyncingPasswordsEnabled, (), (override));
+
+ MOCK_METHOD(absl::optional<std::string>, GetSyncingAccount, (), (override));
+};
+
class MockPasswordStoreBackend : public PasswordStoreBackend {
public:
MockPasswordStoreBackend();
~MockPasswordStoreBackend() override;
- base::WeakPtr<PasswordStoreBackend> GetWeakPtr() override {
- return weak_ptr_factory_.GetWeakPtr();
- }
-
MOCK_METHOD(void,
InitBackend,
(RemoteChangesReceived remote_form_changes_received,
@@ -87,9 +94,7 @@ class MockPasswordStoreBackend : public PasswordStoreBackend {
CreateSyncControllerDelegate,
(),
(override));
-
- private:
- base::WeakPtrFactory<MockPasswordStoreBackend> weak_ptr_factory_{this};
+ MOCK_METHOD(void, ClearAllLocalPasswords, (), (override));
};
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/mock_webauthn_credentials_delegate.cc b/chromium/components/password_manager/core/browser/mock_webauthn_credentials_delegate.cc
new file mode 100644
index 00000000000..ccdfe81855b
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/mock_webauthn_credentials_delegate.cc
@@ -0,0 +1,13 @@
+// Copyright 2022 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.
+
+#include "components/password_manager/core/browser/mock_webauthn_credentials_delegate.h"
+
+namespace password_manager {
+
+MockWebAuthnCredentialsDelegate::MockWebAuthnCredentialsDelegate() = default;
+
+MockWebAuthnCredentialsDelegate::~MockWebAuthnCredentialsDelegate() = default;
+
+} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/mock_webauthn_credentials_delegate.h b/chromium/components/password_manager/core/browser/mock_webauthn_credentials_delegate.h
new file mode 100644
index 00000000000..f9e1abfdb0c
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/mock_webauthn_credentials_delegate.h
@@ -0,0 +1,41 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_MOCK_WEBAUTHN_CREDENTIALS_DELEGATE_H_
+#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_MOCK_WEBAUTHN_CREDENTIALS_DELEGATE_H_
+
+#include "components/password_manager/core/browser/webauthn_credentials_delegate.h"
+
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace password_manager {
+
+class MockWebAuthnCredentialsDelegate : public WebAuthnCredentialsDelegate {
+ public:
+ MockWebAuthnCredentialsDelegate();
+ ~MockWebAuthnCredentialsDelegate() override;
+
+ MockWebAuthnCredentialsDelegate(const MockWebAuthnCredentialsDelegate&) =
+ delete;
+ MockWebAuthnCredentialsDelegate& operator=(
+ const MockWebAuthnCredentialsDelegate&) = delete;
+
+ MOCK_METHOD(bool, IsWebAuthnAutofillEnabled, (), (const, override));
+ MOCK_METHOD(void,
+ SelectWebAuthnCredential,
+ (std::string backend_id),
+ (override));
+ MOCK_METHOD(const std::vector<autofill::Suggestion>&,
+ GetWebAuthnSuggestions,
+ (),
+ (const override));
+ MOCK_METHOD(void,
+ RetrieveWebAuthnSuggestions,
+ (base::OnceClosure),
+ (override));
+};
+
+} // namespace password_manager
+
+#endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_MOCK_WEBAUTHN_CREDENTIALS_DELEGATE_H_ \ No newline at end of file
diff --git a/chromium/components/password_manager/core/browser/password_autofill_manager.cc b/chromium/components/password_manager/core/browser/password_autofill_manager.cc
index 76bf7357471..52fd554d6a8 100644
--- a/chromium/components/password_manager/core/browser/password_autofill_manager.cc
+++ b/chromium/components/password_manager/core/browser/password_autofill_manager.cc
@@ -128,6 +128,8 @@ void AppendSuggestionIfMatching(
suggestion.label = GetHumanReadableRealm(signon_realm);
suggestion.additional_label =
std::u16string(password_length, kPasswordReplacementChar);
+ suggestion.voice_over = l10n_util::GetStringFUTF16(
+ IDS_PASSWORD_MANAGER_PASSWORD_FOR_ACCOUNT, suggestion.label);
if (from_account_store) {
suggestion.frontend_id =
is_password_field
@@ -365,8 +367,10 @@ void PasswordAutofillManager::OnPopupHidden() {}
void PasswordAutofillManager::OnPopupSuppressed() {}
-void PasswordAutofillManager::DidSelectSuggestion(const std::u16string& value,
- int frontend_id) {
+void PasswordAutofillManager::DidSelectSuggestion(
+ const std::u16string& value,
+ int frontend_id,
+ const std::string& backend_id) {
ClearPreviewedForm();
if (frontend_id == autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY ||
frontend_id == autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_EMPTY ||
diff --git a/chromium/components/password_manager/core/browser/password_autofill_manager.h b/chromium/components/password_manager/core/browser/password_autofill_manager.h
index 4095da6d4c6..c4599c8f928 100644
--- a/chromium/components/password_manager/core/browser/password_autofill_manager.h
+++ b/chromium/components/password_manager/core/browser/password_autofill_manager.h
@@ -54,7 +54,8 @@ class PasswordAutofillManager : public autofill::AutofillPopupDelegate {
void OnPopupHidden() override;
void OnPopupSuppressed() override;
void DidSelectSuggestion(const std::u16string& value,
- int frontend_id) override;
+ int frontend_id,
+ const std::string& backend_id) override;
void DidAcceptSuggestion(const std::u16string& value,
int frontend_id,
const std::string& backend_id,
diff --git a/chromium/components/password_manager/core/browser/password_autofill_manager_unittest.cc b/chromium/components/password_manager/core/browser/password_autofill_manager_unittest.cc
index 0bf3d5e5372..e4387544bed 100644
--- a/chromium/components/password_manager/core/browser/password_autofill_manager_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_autofill_manager_unittest.cc
@@ -33,6 +33,7 @@
#include "components/device_reauth/mock_biometric_authenticator.h"
#include "components/favicon/core/test/mock_favicon_service.h"
#include "components/password_manager/core/browser/mock_password_feature_manager.h"
+#include "components/password_manager/core/browser/mock_webauthn_credentials_delegate.h"
#include "components/password_manager/core/browser/password_manager.h"
#include "components/password_manager/core/browser/password_manager_metrics_util.h"
#include "components/password_manager/core/browser/stub_password_manager_client.h"
@@ -51,7 +52,7 @@
#include "ui/gfx/image/image.h"
#include "ui/gfx/image/image_unittest_util.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "base/android/build_info.h"
#endif
@@ -84,6 +85,7 @@ using testing::Field;
using testing::Invoke;
using testing::NiceMock;
using testing::Return;
+using testing::ReturnRef;
using testing::SizeIs;
using testing::Unused;
@@ -108,19 +110,6 @@ constexpr char kCredentialsCountFromAccountStoreAfterUnlockHistogram[] =
"PasswordManager.CredentialsCountFromAccountStoreAfterUnlock";
const gfx::Image kTestFavicon = gfx::test::CreateImage(16, 16);
-class MockWebAuthnCredentialsDelegate : public WebAuthnCredentialsDelegate {
- public:
- MOCK_METHOD(bool, IsWebAuthnAutofillEnabled, (), (const, override));
- MOCK_METHOD(void,
- SelectWebAuthnCredential,
- (std::string backend_id),
- (override));
- MOCK_METHOD(std::vector<autofill::Suggestion>,
- GetWebAuthnSuggestions,
- (),
- (const override));
-};
-
class MockPasswordManagerDriver : public StubPasswordManagerDriver {
public:
MOCK_METHOD(void,
@@ -323,6 +312,13 @@ class PasswordAutofillManagerTest : public testing::Test {
testing::Mock::VerifyAndClearExpectations(client);
// Suppress the warnings in the tests.
EXPECT_CALL(*client, GetFaviconService()).WillRepeatedly(Return(nullptr));
+
+ webauthn_credentials_delegate_ =
+ std::make_unique<MockWebAuthnCredentialsDelegate>();
+ ON_CALL(*client, GetWebAuthnCredentialsDelegate)
+ .WillByDefault(Return(webauthn_credentials_delegate_.get()));
+ ON_CALL(*webauthn_credentials_delegate_, IsWebAuthnAutofillEnabled)
+ .WillByDefault(Return(false));
}
autofill::PasswordFormFillData CreateTestFormFillData() {
@@ -356,6 +352,9 @@ class PasswordAutofillManagerTest : public testing::Test {
scoped_refptr<device_reauth::MockBiometricAuthenticator> authenticator_ =
base::MakeRefCounted<device_reauth::MockBiometricAuthenticator>();
+ std::unique_ptr<MockWebAuthnCredentialsDelegate>
+ webauthn_credentials_delegate_;
+
std::u16string test_username_;
std::u16string test_password_;
@@ -1227,8 +1226,8 @@ TEST_F(PasswordAutofillManagerTest, PreviewAndFillEmptyUsernameSuggestion) {
// Check that preview of the empty username works.
EXPECT_CALL(*client.mock_driver(),
PreviewSuggestion(std::u16string(), test_password_));
- password_autofill_manager_->DidSelectSuggestion(no_username_string,
- 0 /*not used*/);
+ password_autofill_manager_->DidSelectSuggestion(
+ no_username_string, 0 /*not used*/, std::string() /*not used*/);
testing::Mock::VerifyAndClearExpectations(client.mock_driver());
// Check that fill of the empty username works.
@@ -1803,8 +1802,10 @@ TEST_F(PasswordAutofillManagerTest, ShowsWebAuthnSuggestions) {
.WillByDefault(Return(true));
EXPECT_CALL(client, GetWebAuthnCredentialsDelegate)
.WillRepeatedly(Return(&webauthn_credentials_delegate));
+ auto webauthn_credential_list =
+ std::vector<autofill::Suggestion>{webauthn_credential};
EXPECT_CALL(webauthn_credentials_delegate, GetWebAuthnSuggestions)
- .WillOnce(Return(std::vector<autofill::Suggestion>{webauthn_credential}));
+ .WillOnce(ReturnRef(webauthn_credential_list));
// Show password suggestions including WebAuthn credentials.
autofill::AutofillClient::PopupOpenArgs open_args;
@@ -1831,7 +1832,8 @@ TEST_F(PasswordAutofillManagerTest, ShowsWebAuthnSuggestions) {
EXPECT_CALL(*client.mock_driver(),
PreviewSuggestion(kName, /*password=*/std::u16string(u"")));
password_autofill_manager_->DidSelectSuggestion(
- kName, autofill::POPUP_ITEM_ID_WEBAUTHN_CREDENTIAL);
+ kName, autofill::POPUP_ITEM_ID_WEBAUTHN_CREDENTIAL,
+ std::string() /*not used*/);
testing::Mock::VerifyAndClearExpectations(client.mock_driver());
// Check that selecting the credential reports back to the client.
diff --git a/chromium/components/password_manager/core/browser/password_change_success_tracker.h b/chromium/components/password_manager/core/browser/password_change_success_tracker.h
new file mode 100644
index 00000000000..03a54947da5
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/password_change_success_tracker.h
@@ -0,0 +1,78 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_CHANGE_SUCCESS_TRACKER_H_
+#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_CHANGE_SUCCESS_TRACKER_H_
+
+#include <string>
+
+#include "components/keyed_service/core/keyed_service.h"
+
+class GURL;
+
+namespace password_manager {
+
+// Abstract interface to track whether a change password flow leads to a
+// successful password update.
+// Usage notes:
+// - |OnChangePasswordFlowStarted| is supposed to be called when a change flow
+// starts.
+// - |OnChangePasswordFlowSucceeded| is supposed to be called when a compromised
+// password is updated or at the end of kAutomatedResetLinkRequestFlow when
+// the email with the reset link or code was requested.
+// - |url| param is the url of the current page. The tracker is supposed to
+// normalize it to eTLD+1 for matching.
+class PasswordChangeSuccessTracker : public KeyedService {
+ public:
+ // Start and end events for automated (i.e. Autofill Assistant-driven) and
+ // manual flows (i.e. Chrome opens a CCT and a user updates a password on
+ // their own).
+ enum class StartEvent {
+ // Some automated flow started. A specific type will be known only at the
+ // end.
+ kAutomatedFlow = 0,
+
+ // Flow started with opening an origin of a stored credential (which is
+ // supposed to be the homepage).
+ kManualHomepageFlow = 1,
+ // Flow started with opening the .well-known/change-password path.
+ KManualWellKnownUrlFlow = 2,
+ // Flow started with opening a domain-specific URL.
+ kManualChangePasswordUrlFlow = 3,
+
+ // Flow started as an automated flow that requested a reset link, now a user
+ // is supposed to open the link and update the password manually. Should be
+ // used only internally when kAutomatedResetLinkRequestFlow ends.
+ kManualResetLinkOpenningFlow = 4,
+ };
+ enum class EndEvent {
+ // Fully automated flow completed.
+ kAutomatedGeneratedPasswordFlow = 0,
+ // Flow started as an automated flow, but a user chose to create their own
+ // password.
+ kAutomatedOwnPasswordFlow = 1,
+ // Password-reset link was requested. Autofill Assistant's part is done and
+ // a user is supposed to continue the flow on their own.
+ kAutomatedResetLinkRequestFlow = 2,
+
+ // Some manual flow completed. A specific type is known only at the start.
+ kManualFlow = 3,
+ };
+
+ // Called when a change flow starts. Emits a report that a flow has started
+ // and stores an entry to wait for a matching FlowSucceeded call. If there is
+ // no matching call for a while, the entry will expire.
+ virtual void OnChangePasswordFlowStarted(const GURL& url,
+ const std::string& username,
+ StartEvent event_type) = 0;
+
+ // Called when a change flow succeeds. If there is a recent matching
+ // FlowStarted call, it emits a report about a successful password change.
+ virtual void OnChangePasswordFlowCompleted(const GURL& url,
+ const std::string& username,
+ EndEvent event_type) = 0;
+};
+} // namespace password_manager
+
+#endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_CHANGE_SUCCESS_TRACKER_H_
diff --git a/chromium/components/password_manager/core/browser/password_change_success_tracker_impl.cc b/chromium/components/password_manager/core/browser/password_change_success_tracker_impl.cc
new file mode 100644
index 00000000000..e082438766a
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/password_change_success_tracker_impl.cc
@@ -0,0 +1,29 @@
+// Copyright 2022 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.
+
+#include "components/password_manager/core/browser/password_change_success_tracker_impl.h"
+
+#include "url/gurl.h"
+
+namespace password_manager {
+
+PasswordChangeSuccessTrackerImpl::PasswordChangeSuccessTrackerImpl() = default;
+
+PasswordChangeSuccessTrackerImpl::~PasswordChangeSuccessTrackerImpl() = default;
+
+void PasswordChangeSuccessTrackerImpl::OnChangePasswordFlowStarted(
+ const GURL& url,
+ const std::string& username,
+ StartEvent event_type) {
+ // TODO(crbug.com/1281844): Implement metrics recoding.
+}
+
+void PasswordChangeSuccessTrackerImpl::OnChangePasswordFlowCompleted(
+ const GURL& url,
+ const std::string& username,
+ EndEvent event_type) {
+ // TODO(crbug.com/1281844): Implement metrics recoding.
+}
+
+} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/password_change_success_tracker_impl.h b/chromium/components/password_manager/core/browser/password_change_success_tracker_impl.h
new file mode 100644
index 00000000000..e3d835a33c2
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/password_change_success_tracker_impl.h
@@ -0,0 +1,31 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_CHANGE_SUCCESS_TRACKER_IMPL_H_
+#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_CHANGE_SUCCESS_TRACKER_IMPL_H_
+
+#include "components/password_manager/core/browser/password_change_success_tracker.h"
+
+class GURL;
+
+namespace password_manager {
+
+class PasswordChangeSuccessTrackerImpl
+ : public password_manager::PasswordChangeSuccessTracker {
+ public:
+ PasswordChangeSuccessTrackerImpl();
+
+ ~PasswordChangeSuccessTrackerImpl() override;
+
+ void OnChangePasswordFlowStarted(const GURL& url,
+ const std::string& username,
+ StartEvent event_type) override;
+
+ void OnChangePasswordFlowCompleted(const GURL& url,
+ const std::string& username,
+ EndEvent event_type) override;
+};
+
+} // namespace password_manager
+#endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_CHANGE_SUCCESS_TRACKER_IMPL_H_
diff --git a/chromium/components/password_manager/core/browser/password_form.cc b/chromium/components/password_manager/core/browser/password_form.cc
index f067362ce71..3cfffdf8ef7 100644
--- a/chromium/components/password_manager/core/browser/password_form.cc
+++ b/chromium/components/password_manager/core/browser/password_form.cc
@@ -214,9 +214,14 @@ PasswordForm& PasswordForm::operator=(const PasswordForm& form) = default;
PasswordForm& PasswordForm::operator=(PasswordForm&& form) = default;
+bool PasswordForm::IsLikelySignupForm() const {
+ return HasNewPasswordElement() && HasUsernameElement() &&
+ !HasPasswordElement();
+}
+
bool PasswordForm::IsLikelyChangePasswordForm() const {
- return HasNewPasswordElement() && (username_element_renderer_id.is_null() ||
- !password_element_renderer_id.is_null());
+ return HasNewPasswordElement() &&
+ (!HasUsernameElement() || HasPasswordElement());
}
bool PasswordForm::HasUsernameElement() const {
diff --git a/chromium/components/password_manager/core/browser/password_form.h b/chromium/components/password_manager/core/browser/password_form.h
index 4121a2064b8..6af5af285a4 100644
--- a/chromium/components/password_manager/core/browser/password_form.h
+++ b/chromium/components/password_manager/core/browser/password_form.h
@@ -377,6 +377,10 @@ struct PasswordForm {
// to its metadata (e.g. time it was discovered, whether alerts are muted).
base::flat_map<InsecureType, InsecurityMetadata> password_issues;
+ // Return true if we consider this form to be a signup form. It's based on
+ // local heuristics and may be inaccurate.
+ bool IsLikelySignupForm() const;
+
// Return true if we consider this form to be a change password form and not
// a signup form. It's based on local heuristics and may be inaccurate.
bool IsLikelyChangePasswordForm() const;
diff --git a/chromium/components/password_manager/core/browser/password_form_filling.cc b/chromium/components/password_manager/core/browser/password_form_filling.cc
index 4baa12954c2..ccecb39f6e2 100644
--- a/chromium/components/password_manager/core/browser/password_form_filling.cc
+++ b/chromium/components/password_manager/core/browser/password_form_filling.cc
@@ -58,7 +58,7 @@ bool ContainsAndroidCredentials(const PasswordFormFillData& fill_data) {
return PreferredRealmIsFromAndroid(fill_data);
}
-#if !defined(OS_IOS) && !defined(ANDROID)
+#if !BUILDFLAG(IS_IOS) && !defined(ANDROID)
bool IsFillOnAccountSelectFeatureEnabled() {
return base::FeatureList::IsEnabled(
password_manager::features::kFillOnAccountSelect);
@@ -177,7 +177,7 @@ LikelyFormFilling SendFillInformationToRenderer(
// This metric will always record kReauthRequired on iOS and Android. So we can
// drop it there.
-#if !defined(OS_IOS) && !defined(ANDROID)
+#if !BUILDFLAG(IS_IOS) && !defined(ANDROID)
// Proceed to autofill.
// Note that we provide the choices but don't actually prefill a value if:
// (1) we are in Incognito mode, or
@@ -227,7 +227,7 @@ LikelyFormFilling SendFillInformationToRenderer(
wait_for_username_reason != WaitForUsernameReason::kDontWait;
#else
bool wait_for_username = true;
-#endif // !defined(OS_IOS) && !defined(ANDROID)
+#endif // !BUILDFLAG(IS_IOS) && !defined(ANDROID)
if (wait_for_username) {
metrics_recorder->SetManagerAction(
@@ -290,7 +290,7 @@ PasswordFormFillData CreatePasswordFormFillData(
result.password_field.form_control_type = "password";
// On iOS, use the unique_id field to refer to elements.
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
result.username_field.unique_id = form_on_page.username_element;
result.password_field.unique_id = form_on_page.password_element;
#endif
diff --git a/chromium/components/password_manager/core/browser/password_form_filling_unittest.cc b/chromium/components/password_manager/core/browser/password_form_filling_unittest.cc
index 1c3fe9bcf98..d8e3131523e 100644
--- a/chromium/components/password_manager/core/browser/password_form_filling_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_form_filling_unittest.cc
@@ -17,11 +17,11 @@
#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/password_form_fill_data.h"
#include "components/autofill/core/common/unique_ids.h"
+#include "components/password_manager/core/browser/mock_webauthn_credentials_delegate.h"
#include "components/password_manager/core/browser/password_form.h"
#include "components/password_manager/core/browser/password_form_metrics_recorder.h"
#include "components/password_manager/core/browser/stub_password_manager_client.h"
#include "components/password_manager/core/browser/stub_password_manager_driver.h"
-#include "components/password_manager/core/browser/webauthn_credentials_delegate.h"
#include "components/password_manager/core/common/password_manager_features.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -52,19 +52,6 @@ class MockPasswordManagerDriver : public StubPasswordManagerDriver {
MOCK_METHOD(void, InformNoSavedCredentials, (bool), (override));
};
-class MockWebAuthnCredentialsDelegate : public WebAuthnCredentialsDelegate {
- public:
- MOCK_METHOD(bool, IsWebAuthnAutofillEnabled, (), (const, override));
- MOCK_METHOD(void,
- SelectWebAuthnCredential,
- (std::string backend_id),
- (override));
- MOCK_METHOD(std::vector<autofill::Suggestion>,
- GetWebAuthnSuggestions,
- (),
- (const override));
-};
-
class MockPasswordManagerClient : public StubPasswordManagerClient {
public:
MOCK_METHOD(void,
@@ -133,6 +120,11 @@ class PasswordFormFillingTest : public testing::Test {
metrics_recorder_ = base::MakeRefCounted<PasswordFormMetricsRecorder>(
true, client_.GetUkmSourceId(), /*pref_service=*/nullptr);
+
+ ON_CALL(client_, GetWebAuthnCredentialsDelegate)
+ .WillByDefault(Return(&webauthn_credentials_delegate_));
+ ON_CALL(webauthn_credentials_delegate_, IsWebAuthnAutofillEnabled)
+ .WillByDefault(Return(false));
}
protected:
@@ -143,6 +135,7 @@ class PasswordFormFillingTest : public testing::Test {
PasswordForm psl_saved_match_;
scoped_refptr<PasswordFormMetricsRecorder> metrics_recorder_;
std::vector<const PasswordForm*> federated_matches_;
+ MockWebAuthnCredentialsDelegate webauthn_credentials_delegate_;
};
TEST_F(PasswordFormFillingTest, NoSavedCredentials) {
@@ -176,7 +169,7 @@ TEST_F(PasswordFormFillingTest, Autofill) {
// On Android Touch To Fill will prevent autofilling credentials on page load.
// On iOS Reauth is always required.
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
EXPECT_EQ(LikelyFormFilling::kFillOnAccountSelect, likely_form_filling);
EXPECT_TRUE(fill_data.wait_for_username);
#else
@@ -253,7 +246,7 @@ TEST_F(PasswordFormFillingTest, TestFillOnLoadSuggestion) {
if (test_case.current_password_present) {
// On Android Touch To Fill will prevent autofilling credentials on page
// load. On iOS Reauth is always required.
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
EXPECT_EQ(LikelyFormFilling::kFillOnAccountSelect, likely_form_filling);
#else
EXPECT_EQ(LikelyFormFilling::kFillOnPageLoad, likely_form_filling);
@@ -264,7 +257,7 @@ TEST_F(PasswordFormFillingTest, TestFillOnLoadSuggestion) {
}
}
-#if !defined(ANDROID) && !defined(OS_IOS)
+#if !defined(ANDROID) && !BUILDFLAG(IS_IOS)
TEST_F(PasswordFormFillingTest, DontFillOnLoadWebAuthnCredentials) {
MockWebAuthnCredentialsDelegate webauthn_credentials_delegate;
observed_form_.accepts_webauthn_credentials = true;
@@ -294,7 +287,7 @@ TEST_F(PasswordFormFillingTest, DontFillOnLoadWebAuthnCredentials) {
// placeholder.
// Skip for Android and iOS since it uses touch to fill, meaning placeholders
// will never be overwritten.
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
TEST_F(PasswordFormFillingTest, TestFillOnLoadSuggestionWithPrefill) {
const struct {
const char* description;
@@ -387,7 +380,7 @@ TEST_F(PasswordFormFillingTest, NoAutofillOnHttp) {
ASSERT_FALSE(GURL(saved_http_match.signon_realm).SchemeIsCryptographic());
std::vector<const PasswordForm*> best_matches = {&saved_http_match};
-#if !defined(OS_IOS) && !defined(ANDROID)
+#if !BUILDFLAG(IS_IOS) && !defined(ANDROID)
EXPECT_CALL(client_, IsCommittedMainFrameSecure).WillOnce(Return(false));
#endif
LikelyFormFilling likely_form_filling = SendFillInformationToRenderer(
@@ -396,7 +389,7 @@ TEST_F(PasswordFormFillingTest, NoAutofillOnHttp) {
EXPECT_EQ(LikelyFormFilling::kFillOnAccountSelect, likely_form_filling);
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
TEST_F(PasswordFormFillingTest, TouchToFill) {
std::vector<const PasswordForm*> best_matches = {&saved_match_};
diff --git a/chromium/components/password_manager/core/browser/password_form_manager.cc b/chromium/components/password_manager/core/browser/password_form_manager.cc
index dc18d25d73d..a2ca7159a88 100644
--- a/chromium/components/password_manager/core/browser/password_form_manager.cc
+++ b/chromium/components/password_manager/core/browser/password_form_manager.cc
@@ -10,7 +10,6 @@
#include <string>
#include <utility>
-#include "base/bind.h"
#include "base/feature_list.h"
#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_functions.h"
@@ -18,6 +17,7 @@
#include "base/metrics/user_metrics.h"
#include "base/metrics/user_metrics_action.h"
#include "base/ranges/algorithm.h"
+#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/password_form_generation_data.h"
@@ -26,6 +26,7 @@
#include "components/password_manager/core/browser/browser_save_password_progress_logger.h"
#include "components/password_manager/core/browser/field_info_manager.h"
#include "components/password_manager/core/browser/form_fetcher_impl.h"
+#include "components/password_manager/core/browser/password_change_success_tracker_impl.h"
#include "components/password_manager/core/browser/password_feature_manager.h"
#include "components/password_manager/core/browser/password_form.h"
#include "components/password_manager/core/browser/password_form_filling.h"
@@ -146,6 +147,21 @@ PasswordFormManager::PasswordFormManager(
if (owned_form_fetcher_ &&
!observed_form()->is_gaia_with_skip_save_password_form) {
owned_form_fetcher_->Fetch();
+
+ WebAuthnCredentialsDelegate* delegate =
+ client_->GetWebAuthnCredentialsDelegate();
+ bool is_webauthn_autofill_enabled =
+ delegate && delegate->IsWebAuthnAutofillEnabled();
+
+ // The barrier closure is invoked by the WebAuthnCredentialsDelegate,
+ // if enabled, and by ProcessServerPredictions. A fill will trigger
+ // when both requests are satisfied.
+ async_predictions_waiter_.InitializeClosure(
+ is_webauthn_autofill_enabled ? 2 : 1);
+ if (is_webauthn_autofill_enabled) {
+ delegate->RetrieveWebAuthnSuggestions(
+ async_predictions_waiter_.closure());
+ }
}
votes_uploader_.StoreInitialFieldValues(*observed_form());
}
@@ -285,12 +301,26 @@ void PasswordFormManager::Save() {
newly_blocklisted_ = false;
}
+ // This is potentially the conclusion of a password change flow. It might also
+ // not be related to such a flow at all, but the tracker will figure it out.
+ client_->GetPasswordChangeSuccessTracker()->OnChangePasswordFlowCompleted(
+ parsed_submitted_form_->url,
+ base::UTF16ToUTF8(GetPendingCredentials().username_value),
+ PasswordChangeSuccessTracker::EndEvent::kManualFlow);
+
password_save_manager_->Save(observed_form(), *parsed_submitted_form_);
client_->UpdateFormManagers();
}
void PasswordFormManager::Update(const PasswordForm& credentials_to_update) {
+ // This is potentially the conclusion of a password change flow. It might also
+ // not be related to such a flow at all, but the tracker will figure it out.
+ client_->GetPasswordChangeSuccessTracker()->OnChangePasswordFlowCompleted(
+ parsed_submitted_form_->url,
+ base::UTF16ToUTF8(GetPendingCredentials().username_value),
+ PasswordChangeSuccessTracker::EndEvent::kManualFlow);
+
password_save_manager_->Update(credentials_to_update, observed_form(),
*parsed_submitted_form_);
@@ -492,7 +522,7 @@ const PasswordForm* PasswordFormManager::GetSubmittedForm() const {
return parsed_submitted_form_.get();
}
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
void PasswordFormManager::PresaveGeneratedPassword(
PasswordManagerDriver* driver,
const FormData& form,
@@ -563,7 +593,7 @@ void PasswordFormManager::ProvisionallySaveFieldDataManagerInfo(
if (data_found)
ProvisionallySave(*observed_form(), driver, nullptr);
}
-#endif // defined(OS_IOS)
+#endif // BUILDFLAG(IS_IOS)
void PasswordFormManager::SaveSuggestedUsernameValueToVotesUploader() {
votes_uploader_.set_suggested_username(
@@ -627,13 +657,7 @@ PasswordFormManager::PasswordFormManager(
void PasswordFormManager::DelayFillForServerSidePredictions() {
waiting_for_server_predictions_ = true;
-
- weak_ptr_factory_.InvalidateWeakPtrs();
- base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
- FROM_HERE,
- base::BindOnce(&PasswordFormManager::Fill,
- weak_ptr_factory_.GetWeakPtr()),
- kMaxFillingDelayForServerPredictions);
+ async_predictions_waiter_.StartTimer();
}
void PasswordFormManager::OnFetchCompleted() {
@@ -667,6 +691,10 @@ void PasswordFormManager::OnFetchCompleted() {
}
}
+void PasswordFormManager::OnWaitCompleted() {
+ Fill();
+}
+
void PasswordFormManager::CreatePendingCredentials() {
DCHECK(is_submitted_);
if (!parsed_submitted_form_)
@@ -781,8 +809,15 @@ void PasswordFormManager::ProcessServerPredictions(
return;
}
UpdatePredictionsForObservedForm(predictions);
- if (parser_.predictions())
- Fill();
+ if (parser_.predictions()) {
+ if (!async_predictions_waiter_.closure().is_null()) {
+ // Signals the availability of server predictions, but there might be
+ // other callbacks still outstanding.
+ async_predictions_waiter_.closure().Run();
+ } else {
+ Fill();
+ }
+ }
}
void PasswordFormManager::Fill() {
@@ -810,7 +845,7 @@ void PasswordFormManager::Fill() {
if (observed_password_form->is_new_password_reliable && !IsBlocklisted()) {
driver_->FormEligibleForGenerationFound({
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
.form_renderer_id = observed_password_form->form_data.unique_renderer_id,
#endif
.new_password_renderer_id =
@@ -820,7 +855,7 @@ void PasswordFormManager::Fill() {
});
}
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
// Filling on username first flow is not supported on iOS.
if (observed_password_form->IsSingleUsername())
return;
@@ -904,7 +939,8 @@ PasswordFormManager::PasswordFormManager(
password_save_manager_(std::move(password_save_manager)),
// TODO(https://crbug.com/831123): set correctly
// |is_possible_change_password_form| in |votes_uploader_| constructor
- votes_uploader_(client, false /* is_possible_change_password_form */) {
+ votes_uploader_(client, false /* is_possible_change_password_form */),
+ async_predictions_waiter_(this) {
form_fetcher_->AddConsumer(this);
if (!metrics_recorder_) {
metrics_recorder_ = base::MakeRefCounted<PasswordFormMetricsRecorder>(
diff --git a/chromium/components/password_manager/core/browser/password_form_manager.h b/chromium/components/password_manager/core/browser/password_form_manager.h
index caeb0f23ad5..62c596ea454 100644
--- a/chromium/components/password_manager/core/browser/password_form_manager.h
+++ b/chromium/components/password_manager/core/browser/password_form_manager.h
@@ -26,16 +26,13 @@
#include "components/password_manager/core/browser/password_form_digest.h"
#include "components/password_manager/core/browser/password_form_manager_for_ui.h"
#include "components/password_manager/core/browser/password_form_metrics_recorder.h"
+#include "components/password_manager/core/browser/password_form_prediction_waiter.h"
#include "components/password_manager/core/browser/password_save_manager.h"
#include "components/password_manager/core/browser/votes_uploader.h"
#include "third_party/abseil-cpp/absl/types/variant.h"
namespace password_manager {
-// Filling timeout for waiting server predictions
-constexpr base::TimeDelta kMaxFillingDelayForServerPredictions =
- base::Milliseconds(500);
-
class PasswordFormMetricsRecorder;
class PasswordManagerClient;
class PasswordManagerDriver;
@@ -44,6 +41,7 @@ struct PossibleUsernameData;
// This class helps with filling the observed form and with saving/updating the
// stored information about it.
class PasswordFormManager : public PasswordFormManagerForUI,
+ public PasswordFormPredictionWaiter::Client,
public FormFetcher::Consumer {
public:
// TODO(crbug.com/621355): So far, |form_fetcher| can be null. In that case
@@ -190,7 +188,7 @@ class PasswordFormManager : public PasswordFormManagerForUI,
int driver_id() { return driver_id_; }
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
// Presaves the form with |generated_password|. This function is called once
// when the user accepts the generated password. The password was generated in
// the field with identifier |generation_element|. |driver| corresponds to the
@@ -215,7 +213,7 @@ class PasswordFormManager : public PasswordFormManagerForUI,
void ProvisionallySaveFieldDataManagerInfo(
const autofill::FieldDataManager& field_data_manager,
const PasswordManagerDriver* driver);
-#endif // defined(OS_IOS)
+#endif // BUILDFLAG(IS_IOS)
// Create a copy of |*this| which can be passed to the code handling
// save-password related UI. This omits some parts of the internal data, so
@@ -261,6 +259,9 @@ class PasswordFormManager : public PasswordFormManagerForUI,
// FormFetcher::Consumer:
void OnFetchCompleted() override;
+ // PasswordFormPredictionWaiter::Client:
+ void OnWaitCompleted() override;
+
// Create pending credentials from |parsed_submitted_form_| and forms received
// from the password store.
void CreatePendingCredentials();
@@ -337,8 +338,8 @@ class PasswordFormManager : public PasswordFormManagerForUI,
const autofill::FormData& observed_form_data,
const std::map<autofill::FormSignature, FormPredictions>& predictions);
- // Delays form filling by |kMaxFillingDelayForServerPredictions| while waiting
- // for server-side predictions.
+ // Sets the timer on |async_predictions_waiter_| while waiting for
+ // server-side predictions.
void DelayFillForServerSidePredictions();
// The client which implements embedder-specific PasswordManager operations.
@@ -399,10 +400,10 @@ class PasswordFormManager : public PasswordFormManagerForUI,
// Time when stored credentials are received from the store. Used for metrics.
base::TimeTicks received_stored_credentials_time_;
+ PasswordFormPredictionWaiter async_predictions_waiter_;
+
// Used to transform FormData into PasswordForms.
FormDataParser parser_;
-
- base::WeakPtrFactory<PasswordFormManager> weak_ptr_factory_{this};
};
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/password_form_manager_unittest.cc b/chromium/components/password_manager/core/browser/password_form_manager_unittest.cc
index 6ed2520b1d6..1a82c0862b8 100644
--- a/chromium/components/password_manager/core/browser/password_form_manager_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_form_manager_unittest.cc
@@ -31,6 +31,8 @@
#include "components/autofill/core/common/unique_ids.h"
#include "components/password_manager/core/browser/fake_form_fetcher.h"
#include "components/password_manager/core/browser/field_info_manager.h"
+#include "components/password_manager/core/browser/mock_password_change_success_tracker.h"
+#include "components/password_manager/core/browser/mock_webauthn_credentials_delegate.h"
#include "components/password_manager/core/browser/password_form.h"
#include "components/password_manager/core/browser/password_form_manager_for_ui.h"
#include "components/password_manager/core/browser/password_manager_metrics_util.h"
@@ -170,6 +172,10 @@ class MockPasswordManagerClient : public StubPasswordManagerClient {
MOCK_METHOD(FieldInfoManager*, GetFieldInfoManager, (), (const, override));
MOCK_METHOD(signin::IdentityManager*, GetIdentityManager, (), (override));
MOCK_METHOD(PrefService*, GetPrefs, (), (const, override));
+ MOCK_METHOD(WebAuthnCredentialsDelegate*,
+ GetWebAuthnCredentialsDelegate,
+ (),
+ (override));
};
void CheckPendingCredentials(const PasswordForm& expected,
@@ -380,7 +386,7 @@ class PasswordFormManagerTest : public testing::Test,
// current navigation.
// TODO(crbug.com/896689): Expand the logic/application of this to other
// platforms and/or merge this concept with |unique_renderer_id|.
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
for (auto& f : observed_form_.fields) {
f.unique_id = f.id_attribute;
}
@@ -440,6 +446,11 @@ class PasswordFormManagerTest : public testing::Test,
ON_CALL(*client_.GetPasswordFeatureManager(), GetDefaultPasswordStore)
.WillByDefault(Return(PasswordForm::Store::kProfileStore));
+ ON_CALL(client_, GetWebAuthnCredentialsDelegate)
+ .WillByDefault(Return(&webauthn_credentials_delegate_));
+ ON_CALL(webauthn_credentials_delegate_, IsWebAuthnAutofillEnabled)
+ .WillByDefault(Return(false));
+
fetcher_ = std::make_unique<FakeFormFetcher>();
fetcher_->Fetch();
}
@@ -463,6 +474,7 @@ class PasswordFormManagerTest : public testing::Test,
TestingPrefServiceSimple pref_service_;
MockPasswordManagerClient client_;
MockPasswordManagerDriver driver_;
+ MockWebAuthnCredentialsDelegate webauthn_credentials_delegate_;
// Define |fetcher_| before |form_manager_|, because the former needs to
// outlive the latter.
@@ -553,7 +565,7 @@ TEST_P(PasswordFormManagerTest, Autofill) {
// On Android Touch To Fill will prevent autofilling credentials on page load.
// On iOS bio-metric reauth will prevent autofilling as well.
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
EXPECT_TRUE(fill_data.wait_for_username);
#else
EXPECT_FALSE(fill_data.wait_for_username);
@@ -605,7 +617,7 @@ TEST_P(PasswordFormManagerTest, AutofillSignUpForm) {
task_environment_.FastForwardUntilNoTasksRemain();
EXPECT_TRUE(fill_data.password_field.unique_renderer_id.is_null());
EXPECT_EQ(saved_match_.password_value, fill_data.password_field.value);
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
EXPECT_EQ(observed_form_.unique_renderer_id,
generation_data.form_renderer_id);
#else
@@ -639,7 +651,7 @@ TEST_P(PasswordFormManagerTest, GenerationOnNewAndConfirmPasswordFields) {
fetcher_->NotifyFetchCompleted();
task_environment_.FastForwardUntilNoTasksRemain();
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
EXPECT_EQ(observed_form_.unique_renderer_id,
generation_data.form_renderer_id);
#else
@@ -671,7 +683,7 @@ TEST_P(PasswordFormManagerTest, SetSubmitted) {
FormData another_form = submitted_form_;
another_form.name += u"1";
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
// |another_form| is managed because the same |unique_renderer_id| as
// |observed_form_|.
EXPECT_TRUE(
@@ -816,7 +828,7 @@ TEST_P(PasswordFormManagerTest, CreatePendingCredentialsAlreadySaved) {
// Tests that depending on whether we fill on page load or account select that
// correct user action is recorded. Fill on account select is simulated by
// pretending we are in incognito mode.
-#if !defined(OS_IOS) && !defined(ANDROID)
+#if !BUILDFLAG(IS_IOS) && !defined(ANDROID)
for (bool is_incognito : {false, true}) {
EXPECT_CALL(client_, IsIncognito).WillOnce(Return(is_incognito));
#endif
@@ -825,7 +837,7 @@ TEST_P(PasswordFormManagerTest, CreatePendingCredentialsAlreadySaved) {
form_manager_->ProvisionallySave(submitted_form_, &driver_, nullptr));
CheckPendingCredentials(/* expected */ saved_match_,
form_manager_->GetPendingCredentials());
-#if !defined(OS_IOS) && !defined(ANDROID)
+#if !BUILDFLAG(IS_IOS) && !defined(ANDROID)
}
#endif
}
@@ -1106,6 +1118,11 @@ TEST_P(PasswordFormManagerTest, UpdatePasswordOnChangePasswordForm) {
Pointee(saved_match_another_username)),
saved_match_.password_value))
.WillOnce(SaveArg<0>(&updated_form));
+ EXPECT_CALL(
+ *client_.GetPasswordChangeSuccessTracker(),
+ OnChangePasswordFlowCompleted(
+ submitted_form.url, base::UTF16ToUTF8(saved_match_.username_value),
+ PasswordChangeSuccessTracker::EndEvent::kManualFlow));
form_manager_->Save();
@@ -1736,7 +1753,7 @@ TEST_P(PasswordFormManagerTest, FillForm) {
form.fields[kUsernameFieldIndex].unique_renderer_id.value() += 1000;
form.fields[kUsernameFieldIndex].name += u"1";
form.fields[kUsernameFieldIndex].id_attribute += u"1";
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
form.fields[kUsernameFieldIndex].unique_id += u"1";
#endif
form.fields[kPasswordFieldIndex].unique_renderer_id.value() += 1000;
@@ -1815,14 +1832,14 @@ TEST_P(PasswordFormManagerTest, UpdateFormWaitForServerPredictions) {
EXPECT_CALL(driver_, FillPasswordForm).Times(0);
// Wait half-delay time before updating form
- task_environment_.FastForwardBy(kMaxFillingDelayForServerPredictions / 2);
+ task_environment_.FastForwardBy(kMaxFillingDelayForAsyncPredictions / 2);
// Updating form should cancel previous task for fill and start a new delayed
// fill task for waiting server-side predictions
form_manager_->FillForm(changed_form, {});
// Fire the cancelled fill task should do nothing
- task_environment_.FastForwardBy(kMaxFillingDelayForServerPredictions / 2);
+ task_environment_.FastForwardBy(kMaxFillingDelayForAsyncPredictions / 2);
PasswordFormFillData fill_data;
EXPECT_CALL(driver_, FillPasswordForm(_)).WillOnce(SaveArg<0>(&fill_data));
@@ -1859,6 +1876,10 @@ TEST_P(PasswordFormManagerTest, Update) {
Pointee(saved_match_another_username)),
saved_match_.password_value))
.WillOnce(SaveArg<0>(&updated_form));
+ EXPECT_CALL(*client_.GetPasswordChangeSuccessTracker(),
+ OnChangePasswordFlowCompleted(
+ submitted_form.url, base::UTF16ToUTF8(username),
+ PasswordChangeSuccessTracker::EndEvent::kManualFlow));
EXPECT_CALL(client_, UpdateFormManagers());
const base::Time kNow = base::Time::Now();
@@ -2076,7 +2097,7 @@ TEST_P(PasswordFormManagerTest, BlocklistHttpAuthCredentials) {
form_manager_->OnNeverClicked();
}
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
TEST_P(PasswordFormManagerTest, iOSPresavedGeneratedPassword) {
fetcher_->NotifyFetchCompleted();
MockFormSaver& form_saver = MockFormSaver::Get(form_manager_.get());
@@ -2156,7 +2177,7 @@ TEST_P(PasswordFormManagerTest, iOSUsingFieldDataManagerData) {
FieldPropertiesFlags::kAutofilledOnUserTrigger);
}
-#endif // defined(OS_IOS)
+#endif // BUILDFLAG(IS_IOS)
// Tests provisional saving of credentials during username first flow.
TEST_P(PasswordFormManagerTest, UsernameFirstFlowProvisionalSave) {
@@ -2305,12 +2326,12 @@ TEST_P(PasswordFormManagerTest, UsernameFirstFlow) {
testing::InSequence in_sequence;
// Upload username first flow votes on the username form.
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
EXPECT_CALL(mock_autofill_download_manager_,
StartUploadRequest(SignatureIs(kSingleUsernameFormSignature),
false, ServerFieldTypeSet{SINGLE_USERNAME},
_, true, nullptr));
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
// Upload username first flow votes on the password form.
autofill::AutofillUploadContents::SingleUsernameData
@@ -2325,13 +2346,13 @@ TEST_P(PasswordFormManagerTest, UsernameFirstFlow) {
: autofill::AutofillUploadContents::USERNAME_LIKE);
// As Android does not allow username editing, |NO_INFORMATION| about prompt
// edits is uploaded.
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
expected_single_username_data.set_prompt_edit(
autofill::AutofillUploadContents::EDITED_POSITIVE);
#else
expected_single_username_data.set_prompt_edit(
autofill::AutofillUploadContents::EDIT_UNSPECIFIED);
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
EXPECT_CALL(
mock_autofill_download_manager_,
StartUploadRequest(
@@ -2413,14 +2434,14 @@ TEST_P(PasswordFormManagerTest, NegativeUsernameFirstFlowVotes) {
// Upload for the username form. Ensure that we send `NOT_USERNAME` for the
// username field.
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
EXPECT_CALL(
mock_autofill_download_manager_,
StartUploadRequest(SignatureIs(kUsernameFormSignature), false,
ServerFieldTypeSet{NOT_USERNAME}, _, true, nullptr));
#else
EXPECT_CALL(mock_autofill_download_manager_, StartUploadRequest).Times(0);
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
// Upload for the password form.
autofill::AutofillUploadContents::SingleUsernameData
@@ -2433,13 +2454,13 @@ TEST_P(PasswordFormManagerTest, NegativeUsernameFirstFlowVotes) {
autofill::AutofillUploadContents::USERNAME_LIKE);
// As Android does not allow username editing, |NO_INFORMATION| about prompt
// edits is uploaded.
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
expected_single_username_data.set_prompt_edit(
autofill::AutofillUploadContents::EDITED_NEGATIVE);
#else
expected_single_username_data.set_prompt_edit(
autofill::AutofillUploadContents::EDIT_UNSPECIFIED);
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
EXPECT_CALL(
mock_autofill_download_manager_,
StartUploadRequest(
@@ -2729,6 +2750,11 @@ class PasswordFormManagerTestWithMockedSaver : public PasswordFormManagerTest {
std::make_unique<NiceMock<MockPasswordSaveManager>>();
mock_password_save_manager_ = mock_password_save_manager.get();
EXPECT_CALL(*mock_password_save_manager_, Init(_, _, _, _));
+ // The PasswordFormManagerTestWithMockedSaver tests don't rely on the
+ // return value of GetPendingCredentials. So, it is fine to return an
+ // arbitrary form.
+ ON_CALL(*mock_password_save_manager_, GetPendingCredentials)
+ .WillByDefault(ReturnRef(saved_match_));
form_manager_ = std::make_unique<PasswordFormManager>(
&client_, driver_.AsWeakPtr(), observed_form, fetcher_.get(),
std::move(mock_password_save_manager), nullptr);
@@ -2743,6 +2769,11 @@ class PasswordFormManagerTestWithMockedSaver : public PasswordFormManagerTest {
std::make_unique<NiceMock<MockPasswordSaveManager>>();
mock_password_save_manager_ = mock_password_save_manager.get();
EXPECT_CALL(*mock_password_save_manager_, Init(_, _, _, _));
+ // The PasswordFormManagerTestWithMockedSaver tests don't rely on the
+ // return value of GetPendingCredentials. So, it is fine to return an
+ // arbitrary form.
+ ON_CALL(*mock_password_save_manager_, GetPendingCredentials)
+ .WillByDefault(ReturnRef(saved_match_));
form_manager_ = std::make_unique<PasswordFormManager>(
&client_, PasswordFormDigest(base_auth_observed_form), fetcher_.get(),
std::move(mock_password_save_manager));
@@ -3075,7 +3106,6 @@ TEST_F(PasswordFormManagerTestWithMockedSaver, SaveHttpAuthNoHttpAuthStored) {
EXPECT_CALL(*mock_password_save_manager(),
CreatePendingCredentials(http_auth_form, _, _, true, _));
ASSERT_TRUE(form_manager_->ProvisionallySaveHttpAuthForm(http_auth_form));
- PasswordForm updated_form;
// Check that the password save manager is invoked.
EXPECT_CALL(*mock_password_save_manager(), Save(_, http_auth_form));
form_manager_->Save();
diff --git a/chromium/components/password_manager/core/browser/password_form_metrics_recorder.cc b/chromium/components/password_manager/core/browser/password_form_metrics_recorder.cc
index e96e56faff5..c2dfadad495 100644
--- a/chromium/components/password_manager/core/browser/password_form_metrics_recorder.cc
+++ b/chromium/components/password_manager/core/browser/password_form_metrics_recorder.cc
@@ -518,7 +518,7 @@ void PasswordFormMetricsRecorder::CalculateFillingAssistanceMetric(
is_mixed_content_form_ = true;
}
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
filling_source_ = FillingSource::kNotFilled;
#endif
account_storage_usage_level_ = account_storage_usage_level;
@@ -557,7 +557,7 @@ void PasswordFormMetricsRecorder::CalculateFillingAssistanceMetric(
return;
}
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
// At this point, the password was filled from at least one of the two stores,
// so compute the filling source now.
filling_source_ = ComputeFillingSource(
diff --git a/chromium/components/password_manager/core/browser/password_form_metrics_recorder_unittest.cc b/chromium/components/password_manager/core/browser/password_form_metrics_recorder_unittest.cc
index 50a2bd11ae4..12ba9dfdf6d 100644
--- a/chromium/components/password_manager/core/browser/password_form_metrics_recorder_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_form_metrics_recorder_unittest.cc
@@ -1103,7 +1103,7 @@ TEST(PasswordFormMetricsRecorder, FilledValueMatchesSavedUsernameAndPassword) {
PasswordFormMetricsRecorder::FillingAssistance::kAutomatic});
}
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
struct FillingSourceTestCase {
std::vector<TestCaseFieldInfo> fields;
diff --git a/chromium/components/password_manager/core/browser/password_form_prediction_waiter.cc b/chromium/components/password_manager/core/browser/password_form_prediction_waiter.cc
new file mode 100644
index 00000000000..ecb8307fa0d
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/password_form_prediction_waiter.cc
@@ -0,0 +1,49 @@
+// Copyright 2022 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.
+
+#include "components/password_manager/core/browser/password_form_prediction_waiter.h"
+
+#include "base/barrier_closure.h"
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/logging.h"
+
+namespace password_manager {
+
+PasswordFormPredictionWaiter::PasswordFormPredictionWaiter(Client* client)
+ : client_(client) {}
+
+PasswordFormPredictionWaiter::~PasswordFormPredictionWaiter() = default;
+
+void PasswordFormPredictionWaiter::StartTimer() {
+ // Unretained |this| is safe because the timer will be destroyed on
+ // destruction of this object.
+ timer_.Start(FROM_HERE, kMaxFillingDelayForAsyncPredictions, this,
+ &PasswordFormPredictionWaiter::OnTimeout);
+}
+
+void PasswordFormPredictionWaiter::InitializeClosure(size_t callback_count) {
+ // Invalidating the weak pointers serves to cancel outstanding callbacks
+ // on the BarrierClosure.
+ weak_ptr_factory_.InvalidateWeakPtrs();
+ barrier_closure_ = base::BarrierClosure(
+ callback_count,
+ base::BindOnce(&PasswordFormPredictionWaiter::OnClosureComplete,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void PasswordFormPredictionWaiter::OnTimeout() {
+ weak_ptr_factory_.InvalidateWeakPtrs();
+ barrier_closure_ = base::RepeatingClosure();
+ client_->OnWaitCompleted();
+}
+
+void PasswordFormPredictionWaiter::OnClosureComplete() {
+ weak_ptr_factory_.InvalidateWeakPtrs();
+ barrier_closure_ = base::RepeatingClosure();
+ timer_.Stop();
+ client_->OnWaitCompleted();
+}
+
+} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/password_form_prediction_waiter.h b/chromium/components/password_manager/core/browser/password_form_prediction_waiter.h
new file mode 100644
index 00000000000..0d1332d7361
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/password_form_prediction_waiter.h
@@ -0,0 +1,67 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_FORM_PREDICTION_WAITER_H_
+#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_FORM_PREDICTION_WAITER_H_
+
+#include "base/callback_forward.h"
+#include "base/memory/weak_ptr.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
+
+namespace base {
+class OneShotTimer;
+}
+
+namespace password_manager {
+
+// Filling timeout for waiting for asynchronous predictions.
+constexpr base::TimeDelta kMaxFillingDelayForAsyncPredictions =
+ base::Milliseconds(500);
+
+// Helper class for PasswordFormManager to manage outstanding asynchronous
+// prediction fetches. This uses a barrier callback to wait on multiple
+// asynchronous events, signalling when all are complete, and also a timer
+// that will cause cause Client::OnWaitCompleted() to be called even if there
+// are still outstanding callbacks.
+class PasswordFormPredictionWaiter {
+ public:
+ class Client {
+ public:
+ virtual void OnWaitCompleted() = 0;
+ };
+
+ explicit PasswordFormPredictionWaiter(Client* client);
+
+ PasswordFormPredictionWaiter(const PasswordFormPredictionWaiter&) = delete;
+ PasswordFormPredictionWaiter& operator=(const PasswordFormPredictionWaiter&) =
+ delete;
+
+ ~PasswordFormPredictionWaiter();
+
+ void StartTimer();
+
+ void InitializeClosure(size_t callback_count);
+ const base::RepeatingClosure& closure() const { return barrier_closure_; }
+
+ private:
+ void OnTimeout();
+ void OnClosureComplete();
+
+ // The client owns the waiter so this pointer will survive this object's
+ // lifetime.
+ Client* client_;
+
+ base::OneShotTimer timer_;
+
+ // BarrierClosure is used to wait until predictions are obtained from
+ // all asynchronous sources.
+ base::RepeatingClosure barrier_closure_;
+
+ base::WeakPtrFactory<PasswordFormPredictionWaiter> weak_ptr_factory_{this};
+};
+
+} // namespace password_manager
+
+#endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_FORM_PREDICTION_WAITER_H_
diff --git a/chromium/components/password_manager/core/browser/password_form_prediction_waiter_unittest.cc b/chromium/components/password_manager/core/browser/password_form_prediction_waiter_unittest.cc
new file mode 100644
index 00000000000..1e86b9f6587
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/password_form_prediction_waiter_unittest.cc
@@ -0,0 +1,81 @@
+// Copyright 2022 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.
+
+#include "components/password_manager/core/browser/password_form_prediction_waiter.h"
+
+#include "base/test/task_environment.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace password_manager {
+
+namespace {
+
+class WaiterClient : public PasswordFormPredictionWaiter::Client {
+ public:
+ WaiterClient() = default;
+ ~WaiterClient() = default;
+
+ WaiterClient(const WaiterClient&) = delete;
+ WaiterClient& operator=(const WaiterClient&) = delete;
+
+ bool wait_completed() const { return wait_completed_; }
+ void Reset() { wait_completed_ = false; }
+
+ protected:
+ void OnWaitCompleted() override { wait_completed_ = true; }
+
+ bool wait_completed_ = false;
+};
+
+class PasswordFormPredictionWaiterTest : public testing::Test {
+ public:
+ PasswordFormPredictionWaiterTest() : prediction_waiter_(&client_) {}
+
+ protected:
+ WaiterClient client_;
+ PasswordFormPredictionWaiter prediction_waiter_;
+
+ base::test::TaskEnvironment task_environment_{
+ base::test::TaskEnvironment::TimeSource::MOCK_TIME};
+};
+
+TEST_F(PasswordFormPredictionWaiterTest, WaitCompletedOnTimeout) {
+ prediction_waiter_.StartTimer();
+ task_environment_.FastForwardBy(kMaxFillingDelayForAsyncPredictions);
+ EXPECT_TRUE(client_.wait_completed());
+}
+
+TEST_F(PasswordFormPredictionWaiterTest,
+ WaitCompletedOnTimeoutWithOutstandingCallback) {
+ prediction_waiter_.StartTimer();
+ prediction_waiter_.InitializeClosure(2);
+ prediction_waiter_.closure().Run();
+ EXPECT_FALSE(client_.wait_completed());
+
+ task_environment_.FastForwardBy(kMaxFillingDelayForAsyncPredictions);
+ EXPECT_TRUE(client_.wait_completed());
+}
+
+TEST_F(PasswordFormPredictionWaiterTest, WaitCompletedOnSingleBarrierCallback) {
+ prediction_waiter_.InitializeClosure(1);
+ prediction_waiter_.closure().Run();
+
+ EXPECT_TRUE(prediction_waiter_.closure().is_null());
+ EXPECT_TRUE(client_.wait_completed());
+}
+
+TEST_F(PasswordFormPredictionWaiterTest,
+ WaitCompletedOnMultipleBarrierCallbacks) {
+ prediction_waiter_.InitializeClosure(3);
+ for (int i = 0; i < 3; ++i) {
+ prediction_waiter_.closure().Run();
+ }
+
+ EXPECT_TRUE(prediction_waiter_.closure().is_null());
+ EXPECT_TRUE(client_.wait_completed());
+}
+
+} // namespace
+
+} // namespace password_manager \ No newline at end of file
diff --git a/chromium/components/password_manager/core/browser/password_list_sorter.cc b/chromium/components/password_manager/core/browser/password_list_sorter.cc
index 5b61a2e3c0f..0c477251396 100644
--- a/chromium/components/password_manager/core/browser/password_list_sorter.cc
+++ b/chromium/components/password_manager/core/browser/password_list_sorter.cc
@@ -5,7 +5,6 @@
#include "components/password_manager/core/browser/password_list_sorter.h"
#include <algorithm>
-#include <tuple>
#include "base/strings/utf_string_conversions.h"
#include "components/password_manager/core/browser/android_affiliation/affiliation_utils.h"
@@ -28,9 +27,7 @@ constexpr char kSortKeyNoFederationSymbol = '-';
} // namespace
std::string CreateSortKey(const PasswordForm& form, IgnoreStore ignore_store) {
- std::string shown_origin;
- GURL link_url;
- std::tie(shown_origin, link_url) = GetShownOriginAndLinkUrl(form);
+ auto [shown_origin, link_url] = GetShownOriginAndLinkUrl(form);
const auto facet_uri =
FacetURI::FromPotentiallyInvalidSpec(form.signon_realm);
diff --git a/chromium/components/password_manager/core/browser/password_manager.cc b/chromium/components/password_manager/core/browser/password_manager.cc
index fb2fb49a898..ecb974a6e1b 100644
--- a/chromium/components/password_manager/core/browser/password_manager.cc
+++ b/chromium/components/password_manager/core/browser/password_manager.cc
@@ -50,7 +50,7 @@
#include "google_apis/gaia/gaia_auth_util.h"
#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include "components/prefs/pref_registry_simple.h"
#endif
@@ -118,7 +118,7 @@ bool ShouldPromptUserToSavePassword(const PasswordFormManager& manager) {
return manager.IsNewLogin();
}
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
// Finds the matched form manager with id |form_renderer_id| in
// |form_managers|.
PasswordFormManager* FindMatchedManagerByRendererId(
@@ -131,7 +131,7 @@ PasswordFormManager* FindMatchedManagerByRendererId(
}
return nullptr;
}
-#endif // !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_IOS)
bool HasSingleUsernameVote(const FormPredictions& form) {
for (const auto& field : form.fields) {
@@ -220,6 +220,8 @@ void PasswordManager::RegisterProfilePrefs(
registry->RegisterDoublePref(prefs::kLastTimeObsoleteHttpCredentialsRemoved,
0.0);
registry->RegisterDoublePref(prefs::kLastTimePasswordCheckCompleted, 0.0);
+ registry->RegisterDoublePref(prefs::kLastTimePasswordStoreMetricsReported,
+ 0.0);
registry->RegisterTimePref(
prefs::kSyncedLastTimePasswordCheckCompleted, base::Time(),
user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF);
@@ -232,7 +234,7 @@ void PasswordManager::RegisterProfilePrefs(
base::Time());
registry->RegisterBooleanPref(prefs::kWereOldGoogleLoginsRemoved, false);
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
registry->RegisterIntegerPref(prefs::kKeychainMigrationStatus,
4 /* MIGRATED_DELETED */);
#endif
@@ -241,7 +243,10 @@ void PasswordManager::RegisterProfilePrefs(
registry->RegisterBooleanPref(
prefs::kPasswordLeakDetectionEnabled, true,
user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
-#if defined(OS_ANDROID)
+ registry->RegisterBooleanPref(
+ prefs::kPasswordDismissCompromisedAlertEnabled, true,
+ user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+#if BUILDFLAG(IS_ANDROID)
registry->RegisterIntegerPref(
prefs::kCurrentMigrationVersionToGoogleMobileServices, 0);
registry->RegisterDoublePref(prefs::kTimeOfLastMigrationAttempt, 0.0);
@@ -250,7 +255,7 @@ void PasswordManager::RegisterProfilePrefs(
// static
void PasswordManager::RegisterLocalPrefs(PrefRegistrySimple* registry) {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
registry->RegisterInt64Pref(prefs::kOsPasswordLastChanged, 0);
registry->RegisterBooleanPref(prefs::kOsPasswordBlank, false);
#endif
@@ -496,7 +501,7 @@ void PasswordManager::OnPasswordFormCleared(
}
}
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
void PasswordManager::OnSubframeFormSubmission(PasswordManagerDriver* driver,
const FormData& form_data) {
if (password_manager_util::IsLoggingActive(client_)) {
@@ -708,7 +713,7 @@ PasswordFormManager* PasswordManager::ProvisionallySaveForm(
return matched_manager;
}
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
void PasswordManager::LogFirstFillingResult(
PasswordManagerDriver* driver,
autofill::FormRendererId form_renderer_id,
@@ -719,14 +724,14 @@ void PasswordManager::LogFirstFillingResult(
return;
matching_manager->GetMetricsRecorder()->RecordFirstFillingResult(result);
}
-#endif // !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_IOS)
void PasswordManager::NotifyStorePasswordCalled() {
store_password_called_ = true;
DropFormManagers();
}
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
void PasswordManager::PresaveGeneratedPassword(
PasswordManagerDriver* driver,
const FormData& form,
@@ -970,7 +975,8 @@ void PasswordManager::OnLoginSuccessful() {
if (!HasMutedCredentials(
submitted_manager->GetInsecureCredentials(),
submitted_manager->GetSubmittedForm()->username_value)) {
- leak_delegate_.StartLeakCheck(submitted_manager->GetPendingCredentials());
+ leak_delegate_.StartLeakCheck(submitted_manager->GetPendingCredentials(),
+ submitted_form->IsLikelySignupForm());
}
auto submission_event =
@@ -1148,6 +1154,12 @@ void PasswordManager::ProcessAutofillPredictions(
for (auto& manager : form_managers_)
manager->ProcessServerPredictions(predictions_);
+
+ PasswordGenerationFrameHelper* password_generation_manager =
+ driver ? driver->GetPasswordGenerationHelper() : nullptr;
+ if (password_generation_manager) {
+ password_generation_manager->ProcessPasswordRequirements(forms);
+ }
}
PasswordFormManager* PasswordManager::GetSubmittedManager() const {
@@ -1162,6 +1174,10 @@ PasswordFormManager* PasswordManager::GetSubmittedManager() const {
return nullptr;
}
+bool PasswordManager::HasSubmittedManager() const {
+ return GetSubmittedManager() != nullptr;
+}
+
void PasswordManager::SaveSubmittedManager() {
PasswordFormManager* submitted_manager = GetSubmittedManager();
DCHECK(submitted_manager);
@@ -1220,7 +1236,7 @@ PasswordFormManager* PasswordManager::GetMatchedManager(
for (auto& form_manager : form_managers_) {
// Until support of cross-origin iframes is implemented, there is only one
// driver on iOS. It needs to be set in order for filling to work.
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
if (driver && !form_manager->GetDriver())
form_manager->SetDriver(driver->AsWeakPtr());
#endif
@@ -1324,7 +1340,7 @@ bool PasswordManager::IsFormManagerPendingPasswordUpdate() const {
owned_submitted_form_manager_->IsPasswordUpdate();
}
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
bool PasswordManager::DetectPotentialSubmission(
PasswordFormManager* form_manager,
const FieldDataManager& field_data_manager,
diff --git a/chromium/components/password_manager/core/browser/password_manager.h b/chromium/components/password_manager/core/browser/password_manager.h
index e616f2d0499..7455da4813c 100644
--- a/chromium/components/password_manager/core/browser/password_manager.h
+++ b/chromium/components/password_manager/core/browser/password_manager.h
@@ -88,7 +88,7 @@ class PasswordManager : public PasswordManagerInterface {
autofill::FormRendererId form_id,
autofill::FieldRendererId generation_element,
autofill::password_generation::PasswordGenerationType type) override;
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
void OnSubframeFormSubmission(PasswordManagerDriver* driver,
const autofill::FormData& form_data) override;
void PresaveGeneratedPassword(
@@ -195,14 +195,14 @@ class PasswordManager : public PasswordManagerInterface {
}
#endif // defined(UNIT_TEST)
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
// Reports the success from the renderer's PasswordAutofillAgent to fill
// credentials into a site. This may be called multiple times, but only
// the first result will be recorded for each PasswordFormManager.
void LogFirstFillingResult(PasswordManagerDriver* driver,
autofill::FormRendererId form_renderer_id,
int32_t result);
-#endif // !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_IOS)
// Notifies that Credential Management API function store() is called.
void NotifyStorePasswordCalled();
@@ -213,6 +213,9 @@ class PasswordManager : public PasswordManagerInterface {
// Returns true if a form manager is processing a password update.
bool IsFormManagerPendingPasswordUpdate() const;
+ // Returns true if password manager has recorded a submitted manager.
+ bool HasSubmittedManager() const;
+
// Saves the current submitted password to the disk. Password manager must
// have a submitted manager.
void SaveSubmittedManager();
@@ -320,7 +323,7 @@ class PasswordManager : public PasswordManagerInterface {
// Returns the timeout for the disabling Password Manager's prompts.
base::TimeDelta GetTimeoutForDisablingPrompts();
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
// Even though the formal submission might not happen, the manager
// could still be provisionally saved on user input or have autofilled data,
// in this case submission might be considered successful and a save prompt
diff --git a/chromium/components/password_manager/core/browser/password_manager_client.h b/chromium/components/password_manager/core/browser/password_manager_client.h
index b3d3c8fdb1c..c15c4edffad 100644
--- a/chromium/components/password_manager/core/browser/password_manager_client.h
+++ b/chromium/components/password_manager/core/browser/password_manager_client.h
@@ -81,6 +81,7 @@ class PasswordFormManagerForUI;
class PasswordManagerDriver;
class PasswordManagerMetricsRecorder;
class HttpAuthManager;
+class PasswordChangeSuccessTracker;
class PasswordRequirementsService;
class PasswordReuseManager;
class PasswordScriptsFetcher;
@@ -283,6 +284,9 @@ class PasswordManagerClient {
// Returns the PasswordScriptsFetcher associated with this instance.
virtual PasswordScriptsFetcher* GetPasswordScriptsFetcher() = 0;
+ // Returns the PasswordChangeSuccessTracker associated with this instance.
+ virtual PasswordChangeSuccessTracker* GetPasswordChangeSuccessTracker() = 0;
+
// Reports whether and how passwords are synced in the embedder. The default
// implementation always returns kNotSyncing.
virtual SyncState GetPasswordSyncState() const;
diff --git a/chromium/components/password_manager/core/browser/password_manager_driver.h b/chromium/components/password_manager/core/browser/password_manager_driver.h
index 7024de887a8..11e242adad9 100644
--- a/chromium/components/password_manager/core/browser/password_manager_driver.h
+++ b/chromium/components/password_manager/core/browser/password_manager_driver.h
@@ -34,8 +34,10 @@ class PasswordManager;
class PasswordManagerDriver
: public base::SupportsWeakPtr<PasswordManagerDriver> {
public:
+#if BUILDFLAG(IS_ANDROID)
using ShowVirtualKeyboard =
base::StrongAlias<class ShowVirtualKeyboardTag, bool>;
+#endif
PasswordManagerDriver() = default;
@@ -78,8 +80,6 @@ class PasswordManagerDriver
autofill::FieldRendererId generation_element_id,
const std::u16string& password) {}
- virtual void TouchToFillClosed(ShowVirtualKeyboard show_virtual_keyboard) {}
-
// Tells the driver to fill the form with the |username| and |password|.
virtual void FillSuggestion(const std::u16string& username,
const std::u16string& password) = 0;
@@ -90,6 +90,15 @@ class PasswordManagerDriver
bool is_password,
const std::u16string& user_provided_credential) {}
+#if BUILDFLAG(IS_ANDROID)
+ // Informs the renderer that the Touch To Fill sheet has been closed.
+ // Indicates whether the virtual keyboard should be shown instead.
+ virtual void TouchToFillClosed(ShowVirtualKeyboard show_virtual_keyboard) {}
+
+ // Triggers form submission on the last interacted web input element.
+ virtual void TriggerFormSubmission() {}
+#endif
+
// Tells the driver to preview filling form with the |username| and
// |password|.
virtual void PreviewSuggestion(const std::u16string& username,
diff --git a/chromium/components/password_manager/core/browser/password_manager_features_util.cc b/chromium/components/password_manager/core/browser/password_manager_features_util.cc
index 3bc8b890ecf..eed2bef8966 100644
--- a/chromium/components/password_manager/core/browser/password_manager_features_util.cc
+++ b/chromium/components/password_manager/core/browser/password_manager_features_util.cc
@@ -85,7 +85,7 @@ const char kMoveToAccountStoreOfferedCountKey[] =
// Returns the total number of accounts for which an opt-in to the account
// storage exists. Used for metrics.
int GetNumberOfOptedInAccounts(const PrefService* pref_service) {
- const base::DictionaryValue* global_pref =
+ const base::Value* global_pref =
pref_service->GetDictionary(prefs::kAccountStoragePerAccountSettings);
int count = 0;
for (auto entry : global_pref->DictItems()) {
@@ -100,7 +100,7 @@ class AccountStorageSettingsReader {
public:
AccountStorageSettingsReader(const PrefService* prefs,
const GaiaIdHash& gaia_id_hash) {
- const base::DictionaryValue* global_pref =
+ const base::Value* global_pref =
prefs->GetDictionary(prefs::kAccountStoragePerAccountSettings);
if (global_pref)
account_settings_ = global_pref->FindDictKey(gaia_id_hash.ToBase64());
@@ -148,8 +148,8 @@ class ScopedAccountStorageSettingsUpdate {
base::Value* GetOrCreateAccountSettings() {
base::Value* account_settings = update_->FindDictKey(account_hash_);
if (!account_settings) {
- account_settings =
- update_->SetKey(account_hash_, base::DictionaryValue());
+ account_settings = update_->SetKey(
+ account_hash_, base::Value(base::Value::Type::DICTIONARY));
}
DCHECK(account_settings);
return account_settings;
diff --git a/chromium/components/password_manager/core/browser/password_manager_interface.h b/chromium/components/password_manager/core/browser/password_manager_interface.h
index f4ab7dbce7f..729b9e59b17 100644
--- a/chromium/components/password_manager/core/browser/password_manager_interface.h
+++ b/chromium/components/password_manager/core/browser/password_manager_interface.h
@@ -54,7 +54,7 @@ class PasswordManagerInterface : public FormSubmissionObserver {
autofill::FieldRendererId generation_element,
autofill::password_generation::PasswordGenerationType type) = 0;
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
// Handles a subframe form submission. In contrast to OnPasswordFormSubmitted
// this method does not wait for OnPasswordFormsRendered before invoking
// OnLoginSuccessful), but rather invokes ProvisionallySave immediately and
diff --git a/chromium/components/password_manager/core/browser/password_manager_metrics_recorder.cc b/chromium/components/password_manager/core/browser/password_manager_metrics_recorder.cc
index dec7702e3a5..b07d7eb7284 100644
--- a/chromium/components/password_manager/core/browser/password_manager_metrics_recorder.cc
+++ b/chromium/components/password_manager/core/browser/password_manager_metrics_recorder.cc
@@ -19,12 +19,9 @@ typedef autofill::SavePasswordProgressLogger Logger;
namespace password_manager {
PasswordManagerMetricsRecorder::PasswordManagerMetricsRecorder(
- ukm::SourceId source_id,
- std::unique_ptr<NavigationMetricRecorderDelegate>
- navigation_metric_recorder)
+ ukm::SourceId source_id)
: ukm_entry_builder_(
- std::make_unique<ukm::builders::PageWithPassword>(source_id)),
- navigation_metric_recorder_(std::move(navigation_metric_recorder)) {}
+ std::make_unique<ukm::builders::PageWithPassword>(source_id)) {}
PasswordManagerMetricsRecorder::PasswordManagerMetricsRecorder(
PasswordManagerMetricsRecorder&& that) noexcept = default;
@@ -42,19 +39,9 @@ PasswordManagerMetricsRecorder& PasswordManagerMetricsRecorder::operator=(
PasswordManagerMetricsRecorder&& that) = default;
void PasswordManagerMetricsRecorder::RecordUserModifiedPasswordField() {
- if (!user_modified_password_field_ && navigation_metric_recorder_) {
- navigation_metric_recorder_->OnUserModifiedPasswordFieldFirstTime();
- }
user_modified_password_field_ = true;
}
-void PasswordManagerMetricsRecorder::RecordUserFocusedPasswordField() {
- if (!user_focused_password_field_ && navigation_metric_recorder_) {
- navigation_metric_recorder_->OnUserFocusedPasswordFieldFirstTime();
- }
- user_focused_password_field_ = true;
-}
-
void PasswordManagerMetricsRecorder::RecordProvisionalSaveFailure(
ProvisionalSaveFailure failure,
const GURL& main_frame_url,
diff --git a/chromium/components/password_manager/core/browser/password_manager_metrics_recorder.h b/chromium/components/password_manager/core/browser/password_manager_metrics_recorder.h
index 91a931b8040..d4da077c1f1 100644
--- a/chromium/components/password_manager/core/browser/password_manager_metrics_recorder.h
+++ b/chromium/components/password_manager/core/browser/password_manager_metrics_recorder.h
@@ -78,22 +78,8 @@ class PasswordManagerMetricsRecorder {
kObsoleteShowAllPasswordsWhileNoneAreSuggested = 2,
};
- // This purpose of this interface is to allow browser to record metrics
- // about the current navigation.
- class NavigationMetricRecorderDelegate {
- public:
- virtual ~NavigationMetricRecorderDelegate() = default;
- // Called the first time the user focuses on a password field.
- virtual void OnUserFocusedPasswordFieldFirstTime() = 0;
- // Called the first time the user types into a password field.
- virtual void OnUserModifiedPasswordFieldFirstTime() = 0;
- };
-
// Records UKM metrics and reports them on destruction.
- PasswordManagerMetricsRecorder(
- ukm::SourceId source_id,
- std::unique_ptr<NavigationMetricRecorderDelegate>
- navigation_metric_recorder);
+ explicit PasswordManagerMetricsRecorder(ukm::SourceId source_id);
PasswordManagerMetricsRecorder(
PasswordManagerMetricsRecorder&& that) noexcept;
@@ -111,9 +97,6 @@ class PasswordManagerMetricsRecorder {
// Records that the user has modified a password field on a page. This may be
// called multiple times but a single metric will be reported.
void RecordUserModifiedPasswordField();
- // Records that the user has focused a password field on a page. This may be
- // called multiple times but a single metric will be reported.
- void RecordUserFocusedPasswordField();
// Log failure to provisionally save a password to in the PasswordManager to
// UMA and the |logger|.
@@ -133,13 +116,10 @@ class PasswordManagerMetricsRecorder {
std::unique_ptr<ukm::builders::PageWithPassword> ukm_entry_builder_;
bool user_modified_password_field_ = false;
- bool user_focused_password_field_ = false;
// Stores the value most recently reported via RecordFormManagerAvailable.
FormManagerAvailable form_manager_availability_ =
FormManagerAvailable::kNotSet;
-
- std::unique_ptr<NavigationMetricRecorderDelegate> navigation_metric_recorder_;
};
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/password_manager_metrics_recorder_unittest.cc b/chromium/components/password_manager/core/browser/password_manager_metrics_recorder_unittest.cc
index eaa179a8fd7..17b28209fd2 100644
--- a/chromium/components/password_manager/core/browser/password_manager_metrics_recorder_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_manager_metrics_recorder_unittest.cc
@@ -26,7 +26,7 @@ constexpr ukm::SourceId kTestSourceId = 0x1234;
using UkmEntry = ukm::builders::PageWithPassword;
PasswordManagerMetricsRecorder CreateMetricsRecorder() {
- return PasswordManagerMetricsRecorder(kTestSourceId, nullptr);
+ return PasswordManagerMetricsRecorder(kTestSourceId);
}
} // namespace
diff --git a/chromium/components/password_manager/core/browser/password_manager_metrics_util.h b/chromium/components/password_manager/core/browser/password_manager_metrics_util.h
index 45a8b7305ca..585cc5602f2 100644
--- a/chromium/components/password_manager/core/browser/password_manager_metrics_util.h
+++ b/chromium/components/password_manager/core/browser/password_manager_metrics_util.h
@@ -447,8 +447,10 @@ enum class PasswordCheckInteraction {
kEditPassword = 4,
kRemovePassword = 5,
kShowPassword = 6,
+ kMutePassword = 7,
+ kUnmutePassword = 8,
// Must be last.
- kMaxValue = kShowPassword,
+ kMaxValue = kUnmutePassword,
};
// Represents different user interactions related to adding credential from the
diff --git a/chromium/components/password_manager/core/browser/password_manager_unittest.cc b/chromium/components/password_manager/core/browser/password_manager_unittest.cc
index 3c5370b9d78..2ea37442ef5 100644
--- a/chromium/components/password_manager/core/browser/password_manager_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_manager_unittest.cc
@@ -34,6 +34,7 @@
#include "components/password_manager/core/browser/mock_password_reuse_manager.h"
#include "components/password_manager/core/browser/mock_password_store_interface.h"
#include "components/password_manager/core/browser/mock_smart_bubble_stats_store.h"
+#include "components/password_manager/core/browser/mock_webauthn_credentials_delegate.h"
#include "components/password_manager/core/browser/password_autofill_manager.h"
#include "components/password_manager/core/browser/password_bubble_experiment.h"
#include "components/password_manager/core/browser/password_form_manager.h"
@@ -150,6 +151,11 @@ class MockPasswordManagerClient : public StubPasswordManagerClient {
ON_CALL(filter_, IsSyncAccountEmail(_)).WillByDefault(Return(false));
ON_CALL(*this, IsNewTabPage()).WillByDefault(Return(false));
ON_CALL(*this, IsAutofillAssistantUIVisible()).WillByDefault(Return(false));
+
+ ON_CALL(*this, GetWebAuthnCredentialsDelegate)
+ .WillByDefault(Return(&webauthn_credentials_delegate_));
+ ON_CALL(webauthn_credentials_delegate_, IsWebAuthnAutofillEnabled)
+ .WillByDefault(Return(false));
}
MOCK_METHOD(bool,
@@ -210,6 +216,10 @@ class MockPasswordManagerClient : public StubPasswordManagerClient {
(),
(const, override));
MOCK_METHOD(version_info::Channel, GetChannel, (), (const override));
+ MOCK_METHOD(WebAuthnCredentialsDelegate*,
+ GetWebAuthnCredentialsDelegate,
+ (),
+ (override));
// Workaround for std::unique_ptr<> lacking a copy constructor.
bool PromptUserToSaveOrUpdatePassword(
@@ -240,6 +250,7 @@ class MockPasswordManagerClient : public StubPasswordManagerClient {
private:
mutable FakeNetworkContext network_context_;
testing::NiceMock<MockStoreResultFilter> filter_;
+ MockWebAuthnCredentialsDelegate webauthn_credentials_delegate_;
};
class MockPasswordManagerDriver : public StubPasswordManagerDriver {
@@ -302,7 +313,7 @@ void SanitizeFormData(FormData* form) {
}
void SetFieldName(const std::u16string& name, FormFieldData* field) {
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
field->unique_id = name;
#else
field->name = name;
@@ -341,7 +352,7 @@ void SetUniqueIdIfNeeded(FormData* form) {
// current navigation.
// TODO(crbug.com/896689): Expand the logic/application of this to other
// platforms and/or merge this concept with |unique_renderer_id|.
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
for (auto& f : form->fields)
f.unique_id = f.id_attribute;
#endif
@@ -736,7 +747,7 @@ TEST_P(PasswordManagerTest, GeneratedPasswordFormSubmitEmptyStore) {
EXPECT_EQ(form_data.fields[1].value, form_to_save.password_value);
}
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
TEST_P(PasswordManagerTest, EditingGeneratedPasswordOnIOS) {
EXPECT_CALL(client_, IsSavingAndFillingEnabled(_))
.WillRepeatedly(Return(true));
@@ -883,7 +894,7 @@ TEST_P(PasswordManagerTest, ShowHideManualFallbackOnIOS) {
manager()->UpdateStateOnUserInput(&driver_, form_data.unique_renderer_id,
password_element, std::u16string());
}
-#endif // defined(OS_IOS)
+#endif // BUILDFLAG(IS_IOS)
TEST_P(PasswordManagerTest, FormSubmitNoGoodMatch) {
// When the password store already contains credentials for a given form, new
@@ -2307,7 +2318,7 @@ TEST_P(PasswordManagerTest, AutofillingOfAffiliatedCredentials) {
EXPECT_EQ(android_form.username_value, form_data.username_field.value);
EXPECT_EQ(android_form.password_value, form_data.password_field.value);
// On Android Touch To Fill will prevent autofilling credentials on page load.
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
EXPECT_TRUE(form_data.wait_for_username);
#else
EXPECT_FALSE(form_data.wait_for_username);
@@ -3016,7 +3027,7 @@ TEST_P(PasswordManagerTest, AutofillPredictionBeforeFormParsed) {
FieldPrediction prediction;
prediction.set_type(autofill::PASSWORD);
form_structure.field(1)->set_server_predictions({prediction});
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
manager()->ProcessAutofillPredictions(&driver_, {&form_structure});
#else // On iOS predictions are propagated with nullptr driver.
manager()->ProcessAutofillPredictions(nullptr, {&form_structure});
@@ -3059,7 +3070,7 @@ TEST_P(PasswordManagerTest, AutofillPredictionBeforeMultipleFormsParsed) {
prediction.set_type(autofill::PASSWORD);
form_structure2.field(1)->set_server_predictions({prediction});
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
manager()->ProcessAutofillPredictions(&driver_,
{&form_structure1, &form_structure2});
// Both forms should be filled.
@@ -3134,7 +3145,7 @@ TEST_P(PasswordManagerTest, ProvisionallySaveFailure) {
base::HistogramTester histogram_tester;
ukm::TestAutoSetUkmRecorder test_ukm_recorder;
auto metrics_recorder =
- std::make_unique<PasswordManagerMetricsRecorder>(1234, nullptr);
+ std::make_unique<PasswordManagerMetricsRecorder>(1234);
EXPECT_CALL(client_, GetMetricsRecorder())
.WillRepeatedly(Return(metrics_recorder.get()));
@@ -3268,7 +3279,7 @@ TEST_P(PasswordManagerTest, ReportMissingFormManager) {
ukm::TestAutoSetUkmRecorder test_ukm_recorder;
auto metrics_recorder =
- std::make_unique<PasswordManagerMetricsRecorder>(1234, nullptr);
+ std::make_unique<PasswordManagerMetricsRecorder>(1234);
EXPECT_CALL(client_, GetMetricsRecorder())
.WillRepeatedly(Return(metrics_recorder.get()));
@@ -3400,7 +3411,7 @@ TEST_P(PasswordManagerTest, FillingAndSavingFallbacksOnNonPasswordForm) {
manager()->OnPasswordFormsRendered(&driver_, {}, true);
}
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
// Check that on successful login the credentials are checked for leak.
TEST_P(PasswordManagerTest, StartLeakDetection) {
auto mock_factory =
@@ -3432,7 +3443,7 @@ TEST_P(PasswordManagerTest, StartLeakDetection) {
manager()->OnPasswordFormsParsed(&driver_, observed);
manager()->OnPasswordFormsRendered(&driver_, observed, true);
}
-#endif // !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_IOS)
// Check that a non-password form with SINGLE_USERNAME prediction is filled.
TEST_P(PasswordManagerTest, FillSingleUsername) {
@@ -3462,7 +3473,7 @@ TEST_P(PasswordManagerTest, FillSingleUsername) {
prediction.set_type(autofill::SINGLE_USERNAME);
form_structure.field(0)->set_server_predictions({prediction});
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
PasswordFormFillData fill_data;
EXPECT_CALL(driver_, FillPasswordForm(_)).WillOnce(SaveArg<0>(&fill_data));
manager()->ProcessAutofillPredictions(&driver_, {&form_structure});
@@ -3471,9 +3482,9 @@ TEST_P(PasswordManagerTest, FillSingleUsername) {
EXPECT_EQ(field_id, fill_data.username_field.unique_renderer_id);
EXPECT_EQ(saved_match.password_value, fill_data.password_field.value);
EXPECT_TRUE(fill_data.password_field.unique_renderer_id.is_null());
-#else // defined(OS_IOS)
+#else // BUILDFLAG(IS_IOS)
EXPECT_CALL(driver_, FillPasswordForm(_)).Times(0);
-#endif // !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_IOS)
}
// Checks that a password form with a clear-text account creation field results
@@ -3676,7 +3687,7 @@ TEST_P(PasswordManagerTest, UsernameFirstFlowWithNavigationInTheMiddle) {
submitted_form_manager->GetPendingCredentials().username_value.empty());
}
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
// Checks that username is filled on username first flow based on server and
// local predictions.
TEST_P(PasswordManagerTest, UsernameFirstFlowFilling) {
@@ -3880,7 +3891,9 @@ TEST_P(PasswordManagerTest,
EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr);
EXPECT_CALL(client_, IsSavingAndFillingEnabled)
.WillRepeatedly(Return(true));
+
manager()->OnPasswordFormsParsed(&driver_, {form2.form_data});
+
OnPasswordFormSubmitted(form2.form_data);
manager()->OnPasswordFormsRendered(&driver_, {} /* observed */,
true /* did stop loading */);
@@ -4043,7 +4056,7 @@ TEST_P(PasswordManagerTest, SubmissionDetectedOnClearedNamelessForm) {
manager()->OnPasswordFormCleared(&driver_, form_data);
}
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
TEST_P(PasswordManagerTest, SubmissionDetectedOnClearedFormlessFields) {
base::test::ScopedFeatureList feature_list;
feature_list.InitAndEnableFeature(features::kDetectFormSubmissionOnFormClear);
@@ -4163,7 +4176,7 @@ TEST_P(PasswordManagerTest, SubmissionDetectedOnClearedNameAndFormlessFields) {
manager()->OnPasswordFormCleared(&driver_, form_data);
}
}
-#endif // !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_IOS)
TEST_P(PasswordManagerTest, IsFormManagerPendingPasswordUpdate) {
PasswordForm form(MakeSimpleForm());
diff --git a/chromium/components/password_manager/core/browser/password_manager_util.cc b/chromium/components/password_manager/core/browser/password_manager_util.cc
index ae545074294..e169666c93c 100644
--- a/chromium/components/password_manager/core/browser/password_manager_util.cc
+++ b/chromium/components/password_manager/core/browser/password_manager_util.cc
@@ -19,6 +19,7 @@
#include "base/strings/strcat.h"
#include "base/time/time.h"
#include "build/build_config.h"
+#include "components/autofill/core/browser/autofill_client.h"
#include "components/autofill/core/browser/logging/log_manager.h"
#include "components/autofill/core/browser/ui/popup_item_ids.h"
#include "components/autofill/core/common/password_generation_util.h"
@@ -150,7 +151,12 @@ bool ShowAllSavedPasswordsContextMenuEnabled(
}
void UserTriggeredManualGenerationFromContextMenu(
- password_manager::PasswordManagerClient* password_manager_client) {
+ password_manager::PasswordManagerClient* password_manager_client,
+ autofill::AutofillClient* autofill_client) {
+ if (autofill_client) {
+ autofill_client->HideAutofillPopup(
+ autofill::PopupHidingReason::kOverlappingWithAnotherPrompt);
+ }
if (!password_manager_client->GetPasswordFeatureManager()
->ShouldShowAccountStorageOptIn()) {
password_manager_client->GeneratePassword(PasswordGenerationType::kManual);
@@ -187,14 +193,14 @@ void RemoveUselessCredentials(
network_context_getter) {
DCHECK(cleaning_tasks_runner);
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
// Can be null for some unittests.
if (!network_context_getter.is_null()) {
cleaning_tasks_runner->MaybeAddCleaningTask(
std::make_unique<password_manager::HttpCredentialCleaner>(
store, network_context_getter, prefs));
}
-#endif // !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_IOS)
// TODO(crbug.com/450621): Remove this when enough number of clients switch
// to the new version of Chrome.
diff --git a/chromium/components/password_manager/core/browser/password_manager_util.h b/chromium/components/password_manager/core/browser/password_manager_util.h
index 5322ae68145..497936109d6 100644
--- a/chromium/components/password_manager/core/browser/password_manager_util.h
+++ b/chromium/components/password_manager/core/browser/password_manager_util.h
@@ -29,6 +29,10 @@ class PasswordManagerDriver;
class PasswordManagerClient;
} // namespace password_manager
+namespace autofill {
+class AutofillClient;
+} // namespace autofill
+
namespace syncer {
class SyncService;
}
@@ -83,7 +87,8 @@ bool ShowAllSavedPasswordsContextMenuEnabled(
// be asked to opt in to account storage, will trigger a reauth flow first and
// generation will only happen on success.
void UserTriggeredManualGenerationFromContextMenu(
- password_manager::PasswordManagerClient* password_manager_client);
+ password_manager::PasswordManagerClient* password_manager_client,
+ autofill::AutofillClient* autofill_client);
// This function handles the following clean-ups of credentials:
// (1) Removing blocklisted duplicates: if two blocklisted credentials have the
diff --git a/chromium/components/password_manager/core/browser/password_manager_util_unittest.cc b/chromium/components/password_manager/core/browser/password_manager_util_unittest.cc
index a66b8f47456..6ef721a6fd6 100644
--- a/chromium/components/password_manager/core/browser/password_manager_util_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_manager_util_unittest.cc
@@ -12,6 +12,10 @@
#include "base/callback_helpers.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
+#include "build/build_config.h"
+#include "components/autofill/core/browser/autofill_client.h"
+#include "components/autofill/core/browser/payments/local_card_migration_manager.h"
+#include "components/autofill/core/browser/ui/popup_types.h"
#include "components/autofill/core/common/password_generation_util.h"
#include "components/password_manager/core/browser/mock_password_feature_manager.h"
#include "components/password_manager/core/browser/password_form.h"
@@ -53,6 +57,198 @@ class MockPasswordManagerClient
MOCK_METHOD(void, GeneratePassword, (PasswordGenerationType), (override));
};
+class MockAutofillClient : public autofill::AutofillClient {
+ public:
+ MockAutofillClient() = default;
+ MockAutofillClient(const MockAutofillClient&) = delete;
+ MockAutofillClient& operator=(const MockAutofillClient&) = delete;
+ ~MockAutofillClient() override = default;
+
+ MOCK_METHOD(version_info::Channel, GetChannel, (), (const, override));
+ MOCK_METHOD(autofill::PersonalDataManager*,
+ GetPersonalDataManager,
+ (),
+ (override));
+ MOCK_METHOD(autofill::AutocompleteHistoryManager*,
+ GetAutocompleteHistoryManager,
+ (),
+ (override));
+ MOCK_METHOD(PrefService*, GetPrefs, (), (override));
+ MOCK_METHOD(const PrefService*, GetPrefs, (), (const, override));
+ MOCK_METHOD(syncer::SyncService*, GetSyncService, (), (override));
+ MOCK_METHOD(signin::IdentityManager*, GetIdentityManager, (), (override));
+ MOCK_METHOD(autofill::FormDataImporter*, GetFormDataImporter, (), (override));
+ MOCK_METHOD(autofill::payments::PaymentsClient*,
+ GetPaymentsClient,
+ (),
+ (override));
+ MOCK_METHOD(autofill::StrikeDatabase*, GetStrikeDatabase, (), (override));
+ MOCK_METHOD(ukm::UkmRecorder*, GetUkmRecorder, (), (override));
+ MOCK_METHOD(ukm::SourceId, GetUkmSourceId, (), (override));
+ MOCK_METHOD(autofill::AddressNormalizer*,
+ GetAddressNormalizer,
+ (),
+ (override));
+ MOCK_METHOD(const GURL&, GetLastCommittedURL, (), (const, override));
+ MOCK_METHOD(security_state::SecurityLevel,
+ GetSecurityLevelForUmaHistograms,
+ (),
+ (override));
+ MOCK_METHOD(const translate::LanguageState*,
+ GetLanguageState,
+ (),
+ (override));
+ MOCK_METHOD(translate::TranslateDriver*, GetTranslateDriver, (), (override));
+ MOCK_METHOD(void, ShowAutofillSettings, (bool), (override));
+ MOCK_METHOD(void,
+ ShowUnmaskPrompt,
+ (const autofill::CreditCard&,
+ UnmaskCardReason,
+ base::WeakPtr<autofill::CardUnmaskDelegate>),
+ (override));
+ MOCK_METHOD(void,
+ OnUnmaskVerificationResult,
+ (PaymentsRpcResult),
+ (override));
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
+ MOCK_METHOD(std::vector<std::string>,
+ GetAllowedMerchantsForVirtualCards,
+ (),
+ (override));
+ MOCK_METHOD(std::vector<std::string>,
+ GetAllowedBinRangesForVirtualCards,
+ (),
+ (override));
+ MOCK_METHOD(void,
+ ShowLocalCardMigrationDialog,
+ (base::OnceClosure),
+ (override));
+ MOCK_METHOD(void,
+ ConfirmMigrateLocalCardToCloud,
+ (const autofill::LegalMessageLines&,
+ const std::string&,
+ const std::vector<autofill::MigratableCreditCard>&,
+ LocalCardMigrationCallback),
+ (override));
+ MOCK_METHOD(void,
+ ShowLocalCardMigrationResults,
+ (const bool,
+ const std::u16string&,
+ const std::vector<autofill::MigratableCreditCard>&,
+ MigrationDeleteCardCallback),
+ (override));
+ MOCK_METHOD(void,
+ ShowWebauthnOfferDialog,
+ (WebauthnDialogCallback),
+ (override));
+ MOCK_METHOD(void,
+ ShowWebauthnVerifyPendingDialog,
+ (WebauthnDialogCallback),
+ (override));
+ MOCK_METHOD(void, UpdateWebauthnOfferDialogWithError, (), (override));
+ MOCK_METHOD(bool, CloseWebauthnDialog, (), (override));
+ MOCK_METHOD(void,
+ ConfirmSaveUpiIdLocally,
+ (const std::string&,
+ base::OnceCallback<void(bool user_decision)>),
+ (override));
+ MOCK_METHOD(void,
+ OfferVirtualCardOptions,
+ (const std::vector<autofill::CreditCard*>&,
+ base::OnceCallback<void(const std::string&)>),
+ (override));
+#else // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
+ MOCK_METHOD(void,
+ ConfirmAccountNameFixFlow,
+ (base::OnceCallback<void(const std::u16string&)>),
+ (override));
+ MOCK_METHOD(
+ void,
+ ConfirmExpirationDateFixFlow,
+ (const autofill::CreditCard&,
+ base::OnceCallback<void(const std::u16string&, const std::u16string&)>),
+ (override));
+#endif
+ MOCK_METHOD(void,
+ ConfirmSaveCreditCardLocally,
+ (const autofill::CreditCard&,
+ autofill::AutofillClient::SaveCreditCardOptions,
+ LocalSaveCardPromptCallback),
+ (override));
+ MOCK_METHOD(void,
+ ConfirmSaveCreditCardToCloud,
+ (const autofill::CreditCard&,
+ const autofill::LegalMessageLines&,
+ SaveCreditCardOptions,
+ UploadSaveCardPromptCallback),
+ (override));
+ MOCK_METHOD(void, CreditCardUploadCompleted, (bool), (override));
+ MOCK_METHOD(void,
+ ConfirmCreditCardFillAssist,
+ (const autofill::CreditCard&, base::OnceClosure),
+ (override));
+ MOCK_METHOD(void,
+ ConfirmSaveAddressProfile,
+ (const autofill::AutofillProfile&,
+ const autofill::AutofillProfile*,
+ SaveAddressProfilePromptOptions,
+ AddressProfileSavePromptCallback),
+ (override));
+ MOCK_METHOD(bool, HasCreditCardScanFeature, (), (override));
+ MOCK_METHOD(void, ScanCreditCard, (CreditCardScanCallback), (override));
+ MOCK_METHOD(void,
+ ShowAutofillPopup,
+ (const PopupOpenArgs&,
+ base::WeakPtr<autofill::AutofillPopupDelegate>),
+ (override));
+ MOCK_METHOD(void,
+ UpdateAutofillPopupDataListValues,
+ (const std::vector<std::u16string>&,
+ const std::vector<std::u16string>&),
+ (override));
+ MOCK_METHOD(void, PinPopupView, (), (override));
+ MOCK_METHOD(PopupOpenArgs, GetReopenPopupArgs, (), (const, override));
+ MOCK_METHOD(base::span<const autofill::Suggestion>,
+ GetPopupSuggestions,
+ (),
+ (const, override));
+ MOCK_METHOD(void,
+ UpdatePopup,
+ (const std::vector<autofill::Suggestion>&, autofill::PopupType),
+ (override));
+ MOCK_METHOD(void,
+ HideAutofillPopup,
+ (autofill::PopupHidingReason),
+ (override));
+ MOCK_METHOD(bool, IsAutocompleteEnabled, (), (override));
+ MOCK_METHOD(bool, IsPasswordManagerEnabled, (), (override));
+ MOCK_METHOD(void,
+ PropagateAutofillPredictions,
+ (content::RenderFrameHost*,
+ const std::vector<autofill::FormStructure*>&),
+ (override));
+ MOCK_METHOD(void,
+ DidFillOrPreviewField,
+ (const std::u16string&, const std::u16string&),
+ (override));
+ MOCK_METHOD(bool, IsContextSecure, (), (const, override));
+ MOCK_METHOD(bool, ShouldShowSigninPromo, (), (override));
+ MOCK_METHOD(bool, AreServerCardsSupported, (), (const, override));
+ MOCK_METHOD(void, ExecuteCommand, (int), (override));
+ MOCK_METHOD(autofill::LogManager*, GetLogManager, (), (const, override));
+ MOCK_METHOD(const autofill::AutofillAblationStudy&,
+ GetAblationStudy,
+ (),
+ (const, override));
+#if BUILDFLAG(IS_IOS)
+ MOCK_METHOD(bool, IsQueryIDRelevant, (int), (override));
+#endif
+ MOCK_METHOD(void,
+ LoadRiskData,
+ (base::OnceCallback<void(const std::string&)>),
+ (override));
+};
+
PasswordForm GetTestAndroidCredential() {
PasswordForm form;
form.scheme = PasswordForm::Scheme::kHtml;
@@ -475,7 +671,7 @@ TEST(PasswordManagerUtil, ManualGenerationShouldNotReauthIfNotNeeded) {
EXPECT_CALL(mock_client, TriggerReauthForPrimaryAccount).Times(0);
EXPECT_CALL(mock_client, GeneratePassword(PasswordGenerationType::kManual));
- UserTriggeredManualGenerationFromContextMenu(&mock_client);
+ UserTriggeredManualGenerationFromContextMenu(&mock_client, nullptr);
}
TEST(PasswordManagerUtil,
@@ -499,7 +695,7 @@ TEST(PasswordManagerUtil,
});
EXPECT_CALL(mock_client, GeneratePassword(PasswordGenerationType::kManual));
- UserTriggeredManualGenerationFromContextMenu(&mock_client);
+ UserTriggeredManualGenerationFromContextMenu(&mock_client, nullptr);
}
TEST(PasswordManagerUtil,
@@ -524,7 +720,19 @@ TEST(PasswordManagerUtil,
});
EXPECT_CALL(mock_client, GeneratePassword).Times(0);
- UserTriggeredManualGenerationFromContextMenu(&mock_client);
+ UserTriggeredManualGenerationFromContextMenu(&mock_client, nullptr);
+}
+
+TEST(PasswordManagerUtil, AvoidOverlappingAutofillMenuAndManualGeneration) {
+ password_manager::StubPasswordManagerClient stub_password_client;
+ MockAutofillClient mock_autofill_client;
+
+ EXPECT_CALL(mock_autofill_client,
+ HideAutofillPopup(
+ autofill::PopupHidingReason::kOverlappingWithAnotherPrompt));
+
+ UserTriggeredManualGenerationFromContextMenu(&stub_password_client,
+ &mock_autofill_client);
}
TEST(PasswordManagerUtil, StripAuthAndParams) {
diff --git a/chromium/components/password_manager/core/browser/password_reuse_detection_manager.cc b/chromium/components/password_manager/core/browser/password_reuse_detection_manager.cc
index 76333b24726..3e7bba5c3ee 100644
--- a/chromium/components/password_manager/core/browser/password_reuse_detection_manager.cc
+++ b/chromium/components/password_manager/core/browser/password_reuse_detection_manager.cc
@@ -45,7 +45,7 @@ void PasswordReuseDetectionManager::OnKeyPressedCommitted(
OnKeyPressed(text, /*is_committed*/ true);
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
void PasswordReuseDetectionManager::OnKeyPressedUncommitted(
const std::u16string& text) {
OnKeyPressed(text, /*is_committed*/ false);
diff --git a/chromium/components/password_manager/core/browser/password_reuse_detection_manager.h b/chromium/components/password_manager/core/browser/password_reuse_detection_manager.h
index 13589509600..fd987cc316f 100644
--- a/chromium/components/password_manager/core/browser/password_reuse_detection_manager.h
+++ b/chromium/components/password_manager/core/browser/password_reuse_detection_manager.h
@@ -38,7 +38,7 @@ class PasswordReuseDetectionManager : public PasswordReuseDetectorConsumer {
~PasswordReuseDetectionManager() override;
void DidNavigateMainFrame(const GURL& main_frame_url);
void OnKeyPressedCommitted(const std::u16string& text);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
void OnKeyPressedUncommitted(const std::u16string& text);
#endif
void OnPaste(const std::u16string text);
diff --git a/chromium/components/password_manager/core/browser/password_reuse_detection_manager_unittest.cc b/chromium/components/password_manager/core/browser/password_reuse_detection_manager_unittest.cc
index 19a89fbbbc4..816c836f734 100644
--- a/chromium/components/password_manager/core/browser/password_reuse_detection_manager_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_reuse_detection_manager_unittest.cc
@@ -238,7 +238,7 @@ TEST_F(PasswordReuseDetectionManagerTest,
reused_credentials, /*saved_passwords=*/1);
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
TEST_F(PasswordReuseDetectionManagerTest,
CheckReusedCalledWithUncommittedText) {
EXPECT_CALL(client_, GetPasswordReuseManager())
diff --git a/chromium/components/password_manager/core/browser/password_reuse_manager_impl_unittest.cc b/chromium/components/password_manager/core/browser/password_reuse_manager_impl_unittest.cc
index 460ba671f41..dcac2bbe85e 100644
--- a/chromium/components/password_manager/core/browser/password_reuse_manager_impl_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_reuse_manager_impl_unittest.cc
@@ -222,8 +222,10 @@ TEST_F(PasswordReuseManagerImplTest, ClearGaiaPasswordHash) {
// Check that no sync password reuse is found after clearing the password
// hash.
reuse_manager()->ClearGaiaPasswordHash("sync_username");
- EXPECT_EQ(0u,
- prefs().GetList(prefs::kPasswordHashDataList)->GetList().size());
+ EXPECT_EQ(0u, prefs()
+ .GetList(prefs::kPasswordHashDataList)
+ ->GetListDeprecated()
+ .size());
MockPasswordReuseDetectorConsumer mock_consumer;
EXPECT_CALL(mock_consumer, OnReuseCheckDone(false, _, _, _, _));
reuse_manager()->CheckReuse(input, "https://facebook.com", &mock_consumer);
@@ -249,8 +251,10 @@ TEST_F(PasswordReuseManagerImplTest, ClearAllGaiaPasswordHash) {
// Check that no Gaia password reuse is found after clearing all Gaia
// password hash.
MockPasswordReuseDetectorConsumer mock_consumer;
- EXPECT_EQ(0u,
- prefs().GetList(prefs::kPasswordHashDataList)->GetList().size());
+ EXPECT_EQ(0u, prefs()
+ .GetList(prefs::kPasswordHashDataList)
+ ->GetListDeprecated()
+ .size());
EXPECT_CALL(mock_consumer, OnReuseCheckDone(false, _, _, _, _));
reuse_manager()->CheckReuse(input, "https://example.com", &mock_consumer);
RunUntilIdle();
@@ -292,8 +296,10 @@ TEST_F(PasswordReuseManagerImplTest, ClearAllEnterprisePasswordHash) {
// Check that no enterprise password reuse is found after clearing the
// password hash.
reuse_manager()->ClearAllEnterprisePasswordHash();
- EXPECT_EQ(0u,
- prefs().GetList(prefs::kPasswordHashDataList)->GetList().size());
+ EXPECT_EQ(0u, prefs()
+ .GetList(prefs::kPasswordHashDataList)
+ ->GetListDeprecated()
+ .size());
MockPasswordReuseDetectorConsumer mock_consumer;
EXPECT_CALL(mock_consumer, OnReuseCheckDone(false, _, _, _, _));
reuse_manager()->CheckReuse(input, "https://example.com", &mock_consumer);
@@ -325,15 +331,19 @@ TEST_F(PasswordReuseManagerImplTest, ClearAllNonGmailPasswordHash) {
"username@gmail.com", /*is_gaia_password=*/true, prefs());
ASSERT_TRUE(gmail_password_hash.has_value());
- EXPECT_EQ(2u,
- prefs().GetList(prefs::kPasswordHashDataList)->GetList().size());
+ EXPECT_EQ(2u, prefs()
+ .GetList(prefs::kPasswordHashDataList)
+ ->GetListDeprecated()
+ .size());
// Check that no non-gmail password reuse is found after clearing the
// password hash.
reuse_manager()->ClearAllNonGmailPasswordHash();
MockPasswordReuseDetectorConsumer mock_consumer;
- EXPECT_EQ(1u,
- prefs().GetList(prefs::kPasswordHashDataList)->GetList().size());
+ EXPECT_EQ(1u, prefs()
+ .GetList(prefs::kPasswordHashDataList)
+ ->GetListDeprecated()
+ .size());
EXPECT_CALL(mock_consumer, OnReuseCheckDone(false, _, _, _, _));
reuse_manager()->CheckReuse(non_sync_gaia_password, "https://example.com",
&mock_consumer);
diff --git a/chromium/components/password_manager/core/browser/password_save_manager_impl.cc b/chromium/components/password_manager/core/browser/password_save_manager_impl.cc
index 1980ae53e82..3ba61982370 100644
--- a/chromium/components/password_manager/core/browser/password_save_manager_impl.cc
+++ b/chromium/components/password_manager/core/browser/password_save_manager_impl.cc
@@ -66,7 +66,7 @@ PasswordForm PendingCredentialsForNewCredentials(
// Helper to get the platform specific identifier by which autofill and password
// manager refer to a field. See http://crbug.com/896594
std::u16string GetPlatformSpecificIdentifier(const FormFieldData& field) {
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
return field.unique_id;
#else
return field.name;
@@ -767,10 +767,10 @@ void PasswordSaveManagerImpl::UploadVotesAndMetrics(
// It's not possible to edit username in a save/update prompt on Android.
// TODO(crbug.com/959776): Get rid of this method, by passing
// |pending_credentials_| directly to MaybeSendSingleUsernameVote.
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
votes_uploader_->CalculateUsernamePromptEditState(
/*saved_username=*/pending_credentials_.username_value);
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
if (IsNewLogin()) {
metrics_util::LogNewlySavedPasswordIsGenerated(
diff --git a/chromium/components/password_manager/core/browser/password_save_manager_impl_unittest.cc b/chromium/components/password_manager/core/browser/password_save_manager_impl_unittest.cc
index 38f18e99898..ab64f03732b 100644
--- a/chromium/components/password_manager/core/browser/password_save_manager_impl_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_save_manager_impl_unittest.cc
@@ -250,7 +250,7 @@ class PasswordSaveManagerImplTestBase : public testing::Test {
// current navigation.
// TODO(crbug.com/896689): Expand the logic/application of this to other
// platforms and/or merge this concept with |unique_renderer_id|.
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
for (auto& f : observed_form_.fields) {
f.unique_id = f.id_attribute;
}
@@ -1926,8 +1926,7 @@ class MultiStorePasswordSaveManagerGenerationConflictTest
// The test parameters determine which of the conflicts should be included.
std::vector<PasswordForm> CreateProfileStoreMatchesForTestParameters(
const std::u16string& username) const {
- bool add_same_username_match, add_empty_username_match;
- std::tie(add_same_username_match, add_empty_username_match) = GetParam();
+ auto [add_same_username_match, add_empty_username_match] = GetParam();
std::vector<PasswordForm> profile_store_matches;
if (add_same_username_match) {
diff --git a/chromium/components/password_manager/core/browser/password_scripts_fetcher.h b/chromium/components/password_manager/core/browser/password_scripts_fetcher.h
index 0922a6da2a7..8a16d3bf9e8 100644
--- a/chromium/components/password_manager/core/browser/password_scripts_fetcher.h
+++ b/chromium/components/password_manager/core/browser/password_scripts_fetcher.h
@@ -18,6 +18,19 @@ namespace password_manager {
class PasswordScriptsFetcher : public KeyedService {
public:
using ResponseCallback = base::OnceCallback<void(bool)>;
+ // These values are persisted to logs. Entries should not be renumbered and
+ // numeric values should never be reused.
+ enum class CacheState {
+ // Cache is ready.
+ kReady = 0,
+ // Cache was set but it is stale. Re-fetch needed.
+ kStale = 1,
+ // Cache was never set,
+ kNeverSet = 2,
+ // Cache is waiting for an in-flight request.
+ kWaiting = 3,
+ kMaxValue = kWaiting,
+ };
// Triggers pre-fetching the list of scripts. Should be called from UI
// preceding Bulk Check.
virtual void PrewarmCache() = 0;
diff --git a/chromium/components/password_manager/core/browser/password_scripts_fetcher_impl.cc b/chromium/components/password_manager/core/browser/password_scripts_fetcher_impl.cc
index fb1b64c769c..4ad6464b3fe 100644
--- a/chromium/components/password_manager/core/browser/password_scripts_fetcher_impl.cc
+++ b/chromium/components/password_manager/core/browser/password_scripts_fetcher_impl.cc
@@ -67,7 +67,8 @@ base::flat_set<ParsingResult> ParseDomainSpecificParamaters(
}
}
- for (const base::Value& domain : supported_domains_list->GetList()) {
+ for (const base::Value& domain :
+ supported_domains_list->GetListDeprecated()) {
if (!domain.is_string()) {
warnings.insert(ParsingResult::kInvalidJson);
continue;
diff --git a/chromium/components/password_manager/core/browser/password_scripts_fetcher_impl.h b/chromium/components/password_manager/core/browser/password_scripts_fetcher_impl.h
index 292ff1c7215..80d1d03bcfa 100644
--- a/chromium/components/password_manager/core/browser/password_scripts_fetcher_impl.h
+++ b/chromium/components/password_manager/core/browser/password_scripts_fetcher_impl.h
@@ -34,18 +34,6 @@ extern const char kDefaultChangePasswordScriptsListUrl[];
class PasswordScriptsFetcherImpl
: public password_manager::PasswordScriptsFetcher {
public:
- // These enums are used in histograms. Do not change or reuse values.
- enum class CacheState {
- // Cache is ready.
- kReady = 0,
- // Cache was set but it is stale. Re-fetch needed.
- kStale = 1,
- // Cache was never set,
- kNeverSet = 2,
- // Cache is waiting for an in-flight request.
- kWaiting = 3,
- kMaxValue = kWaiting,
- };
enum class ParsingResult {
// No response from the server.
kNoResponse = 0,
@@ -87,6 +75,7 @@ class PasswordScriptsFetcherImpl
#endif
private:
+ using CacheState = PasswordScriptsFetcher::CacheState;
// Sends new request to gstatic.
void StartFetch();
// Callback for the request to gstatic.
diff --git a/chromium/components/password_manager/core/browser/password_scripts_fetcher_impl_unittests.cc b/chromium/components/password_manager/core/browser/password_scripts_fetcher_impl_unittests.cc
index dd89377ef37..d4ea2929c78 100644
--- a/chromium/components/password_manager/core/browser/password_scripts_fetcher_impl_unittests.cc
+++ b/chromium/components/password_manager/core/browser/password_scripts_fetcher_impl_unittests.cc
@@ -173,7 +173,7 @@ TEST_F(PasswordScriptsFetcherImplTest, PrewarmCache) {
EXPECT_EQ(0, GetNumberOfPendingRequests());
histogram_tester->ExpectUniqueSample(
"PasswordManager.PasswordScriptsFetcher.CacheState",
- PasswordScriptsFetcherImpl::CacheState::kReady, 1u);
+ PasswordScriptsFetcher::CacheState::kReady, 1u);
// Make cache stale and re-fetch the map.
histogram_tester = std::make_unique<base::HistogramTester>();
@@ -201,7 +201,7 @@ TEST_F(PasswordScriptsFetcherImplTest, PrewarmCache) {
EXPECT_EQ(0, GetNumberOfPendingRequests());
histogram_tester->ExpectUniqueSample(
"PasswordManager.PasswordScriptsFetcher.CacheState",
- PasswordScriptsFetcherImpl::CacheState::kStale, 1u);
+ PasswordScriptsFetcher::CacheState::kStale, 1u);
}
TEST_F(PasswordScriptsFetcherImplTest, SlowResponse) {
@@ -214,7 +214,7 @@ TEST_F(PasswordScriptsFetcherImplTest, SlowResponse) {
histogram_tester.ExpectUniqueSample(
"PasswordManager.PasswordScriptsFetcher.CacheState",
- PasswordScriptsFetcherImpl::CacheState::kWaiting, 1u);
+ PasswordScriptsFetcher::CacheState::kWaiting, 1u);
}
TEST_F(PasswordScriptsFetcherImplTest, NoPrewarmCache) {
@@ -233,7 +233,7 @@ TEST_F(PasswordScriptsFetcherImplTest, NoPrewarmCache) {
histogram_tester.ExpectUniqueSample(
"PasswordManager.PasswordScriptsFetcher.CacheState",
- PasswordScriptsFetcherImpl::CacheState::kNeverSet, 1u);
+ PasswordScriptsFetcher::CacheState::kNeverSet, 1u);
histogram_tester.ExpectUniqueSample(
"PasswordManager.PasswordScriptsFetcher.ParsingResult",
PasswordScriptsFetcherImpl::ParsingResult::kOk, 1u);
diff --git a/chromium/components/password_manager/core/browser/password_store.cc b/chromium/components/password_manager/core/browser/password_store.cc
index 9a532f1e3cf..7a29d1cdd03 100644
--- a/chromium/components/password_manager/core/browser/password_store.cc
+++ b/chromium/components/password_manager/core/browser/password_store.cc
@@ -18,6 +18,7 @@
#include "base/metrics/histogram_functions.h"
#include "base/notreached.h"
#include "base/ranges/algorithm.h"
+#include "base/task/bind_post_task.h"
#include "base/task/post_task.h"
#include "base/task/task_runner_util.h"
#include "base/task/thread_pool.h"
@@ -53,23 +54,23 @@ bool FormSupportsPSL(const PasswordFormDigest& digest) {
// Helper function which invokes |notifying_callback| and |completion_callback|
// when changes are received.
-void InvokeCallbackOnChanges(
- base::OnceCallback<void(PasswordStoreChangeList changes)>
- notifying_callback,
+void InvokeCallbacksForSuspectedChanges(
+ PasswordStoreChangeListReply notifying_callback,
base::OnceCallback<void(bool)> completion_callback,
- PasswordStoreChangeList changes) {
+ absl::optional<PasswordStoreChangeList> changes) {
DCHECK(notifying_callback);
- bool is_change_empty = changes.empty();
+ // Two cases *presumably* have changes that need to be reported:
+ // 1. `changes` contains a non-empty PasswordStoreChangeList.
+ // 2. `changes` contains no PasswordStoreChangeList at all because the
+ // backend can't compute it. A full list will be requested instead.
+ // Only if `changes` contains an empty PasswordStoreChangeList, Chrome knows
+ // for certain that no changes have happened:
+ bool completed = !changes.has_value() || !changes->empty();
+
+ // In any case, we want to indicate the completed operation:
std::move(notifying_callback).Run(std::move(changes));
if (completion_callback)
- std::move(completion_callback).Run(!is_change_empty);
-}
-
-LoginsResult GetLoginsOrEmptyListOnFailure(LoginsResultOrError result) {
- if (absl::holds_alternative<PasswordStoreBackendError>(result)) {
- return {};
- }
- return std::move(absl::get<LoginsResult>(result));
+ std::move(completion_callback).Run(completed);
}
} // namespace
@@ -87,16 +88,21 @@ bool PasswordStore::Init(
DCHECK(main_task_runner_);
prefs_ = prefs;
affiliated_match_helper_ = std::move(affiliated_match_helper);
+ sync_enabled_or_disabled_cb_ = std::move(sync_enabled_or_disabled_cb);
- // TODO(crbug.bom/1226042): Backend might be null in tests, remove this after
+ // TODO(crbug.com/1226042): Backend might be null in tests, remove this after
// tests switch to MockPasswordStoreInterface.
if (backend_) {
TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(
"passwords", "PasswordStore::InitOnBackgroundSequence", this);
backend_->InitBackend(
base::BindRepeating(&PasswordStore::NotifyLoginsChangedOnMainSequence,
- this),
- std::move(sync_enabled_or_disabled_cb),
+ this, LoginsChangedTrigger::ExternalUpdate),
+ base::BindPostTask(
+ main_task_runner_,
+ base::BindRepeating(
+ &PasswordStore::NotifySyncEnabledOrDisabledOnMainSequence,
+ this)),
base::BindOnce(&PasswordStore::OnInitCompleted, this));
}
return true;
@@ -107,8 +113,8 @@ void PasswordStore::AddLogin(const PasswordForm& form) {
if (!backend_)
return; // Once the shutdown started, ignore new requests.
backend_->AddLoginAsync(
- form,
- base::BindOnce(&PasswordStore::NotifyLoginsChangedOnMainSequence, this));
+ form, base::BindOnce(&PasswordStore::NotifyLoginsChangedOnMainSequence,
+ this, LoginsChangedTrigger::Addition));
}
void PasswordStore::UpdateLogin(const PasswordForm& form) {
@@ -116,8 +122,8 @@ void PasswordStore::UpdateLogin(const PasswordForm& form) {
if (!backend_)
return; // Once the shutdown started, ignore new requests.
backend_->UpdateLoginAsync(
- form,
- base::BindOnce(&PasswordStore::NotifyLoginsChangedOnMainSequence, this));
+ form, base::BindOnce(&PasswordStore::NotifyLoginsChangedOnMainSequence,
+ this, LoginsChangedTrigger::Update));
}
void PasswordStore::UpdateLoginWithPrimaryKey(
@@ -138,10 +144,12 @@ void PasswordStore::UpdateLoginWithPrimaryKey(
base::flat_map<InsecureType, InsecurityMetadata>();
}
- auto barrier_callback = base::BarrierCallback<PasswordStoreChangeList>(
- 2, base::BindOnce(&JoinPasswordStoreChanges)
- .Then(base::BindOnce(
- &PasswordStore::NotifyLoginsChangedOnMainSequence, this)));
+ auto barrier_callback =
+ base::BarrierCallback<absl::optional<PasswordStoreChangeList>>(
+ 2, base::BindOnce(&JoinPasswordStoreChanges)
+ .Then(base::BindOnce(
+ &PasswordStore::NotifyLoginsChangedOnMainSequence, this,
+ LoginsChangedTrigger::Update)));
backend_->RemoveLoginAsync(old_primary_key, barrier_callback);
backend_->AddLoginAsync(new_form_with_correct_password_issues,
@@ -153,8 +161,8 @@ void PasswordStore::RemoveLogin(const PasswordForm& form) {
if (!backend_)
return; // Once the shutdown started, ignore new requests.
backend_->RemoveLoginAsync(
- form,
- base::BindOnce(&PasswordStore::NotifyLoginsChangedOnMainSequence, this));
+ form, base::BindOnce(&PasswordStore::NotifyLoginsChangedOnMainSequence,
+ this, LoginsChangedTrigger::Deletion));
}
void PasswordStore::RemoveLoginsByURLAndTime(
@@ -170,7 +178,8 @@ void PasswordStore::RemoveLoginsByURLAndTime(
}
backend_->RemoveLoginsByURLAndTimeAsync(
url_filter, delete_begin, delete_end, std::move(sync_completion),
- base::BindOnce(&PasswordStore::NotifyLoginsChangedOnMainSequence, this)
+ base::BindOnce(&PasswordStore::NotifyLoginsChangedOnMainSequence, this,
+ LoginsChangedTrigger::BatchDeletion)
.Then(std::move(completion)));
}
@@ -184,10 +193,11 @@ void PasswordStore::RemoveLoginsCreatedBetween(
return; // Once the shutdown started, ignore new requests.
}
auto callback =
- base::BindOnce(&PasswordStore::NotifyLoginsChangedOnMainSequence, this);
+ base::BindOnce(&PasswordStore::NotifyLoginsChangedOnMainSequence, this,
+ LoginsChangedTrigger::BatchDeletion);
backend_->RemoveLoginsCreatedBetweenAsync(
delete_begin, delete_end,
- base::BindOnce(&InvokeCallbackOnChanges, std::move(callback),
+ base::BindOnce(&InvokeCallbacksForSuspectedChanges, std::move(callback),
std::move(completion)));
}
@@ -314,6 +324,11 @@ bool PasswordStore::IsAbleToSavePasswords() const {
void PasswordStore::ShutdownOnUIThread() {
DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
+
+ // Prevent in-flight tasks posted from the backend to invoke the callback
+ // after shutdown.
+ sync_enabled_or_disabled_cb_ = base::DoNothing();
+
// The AffiliationService must be destroyed from the main sequence.
affiliated_match_helper_.reset();
if (backend_) {
@@ -350,22 +365,71 @@ void PasswordStore::OnInitCompleted(bool success) {
}
void PasswordStore::NotifyLoginsChangedOnMainSequence(
- PasswordStoreChangeList changes) {
+ LoginsChangedTrigger logins_changed_trigger,
+ absl::optional<PasswordStoreChangeList> changes) {
DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
- if (changes.empty())
+ // Don't propagate reference to this store after its shutdown. No caller
+ // should expect any notifications from a shut down store in any case.
+ if (!backend_)
+ return;
+
+#if BUILDFLAG(IS_ANDROID)
+ // Record that an OnLoginsRetained call may be required here already since
+ // issuing the list call seems to be the most relevant and expensive step.
+ base::UmaHistogramEnumeration(
+ "PasswordManager.PasswordStore.OnLoginsRetained", logins_changed_trigger);
+ if (!changes.has_value()) {
+ // If the changes aren't provided, the store propagates the latest logins.
+ backend_->GetAllLoginsAsync(base::BindOnce(
+ &PasswordStore::NotifyLoginsRetainedOnMainSequence, this));
return;
+ }
+#else
+ DCHECK(changes.has_value())
+ << "Non-Android platforms can always compute changes!";
+#endif
+ if (changes->empty())
+ return;
+
+ for (auto& observer : observers_) {
+ observer.OnLoginsChanged(this, changes.value());
+ }
+
+ base::UmaHistogramBoolean("PasswordManager.PasswordStore.OnLoginsChanged",
+ true);
+}
+
+void PasswordStore::NotifyLoginsRetainedOnMainSequence(
+ LoginsResultOrError result) {
+ DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
// Don't propagate reference to this store after its shutdown. No caller
// should expect any notifications from a shut down store in any case.
if (!backend_)
return;
+ // Clients don't expect errors yet, so just wait for the next notification.
+ if (absl::holds_alternative<PasswordStoreBackendError>(result)) {
+ return;
+ }
+
+ std::vector<PasswordForm> retained_logins;
+ retained_logins.reserve(absl::get<LoginsResult>(result).size());
+ for (auto& login : absl::get<LoginsResult>(result)) {
+ retained_logins.push_back(std::move(*login));
+ }
+
for (auto& observer : observers_) {
- observer.OnLoginsChanged(this, changes);
+ observer.OnLoginsRetained(this, retained_logins);
}
}
+void PasswordStore::NotifySyncEnabledOrDisabledOnMainSequence() {
+ DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
+ sync_enabled_or_disabled_cb_.Run();
+}
+
void PasswordStore::UnblocklistInternal(
base::OnceClosure completion,
std::vector<std::unique_ptr<PasswordForm>> forms) {
@@ -388,13 +452,15 @@ void PasswordStore::UnblocklistInternal(
}
auto notify_callback =
- base::BindOnce(&PasswordStore::NotifyLoginsChangedOnMainSequence, this);
+ base::BindOnce(&PasswordStore::NotifyLoginsChangedOnMainSequence, this,
+ LoginsChangedTrigger::Unblocklisting);
if (completion)
notify_callback = std::move(notify_callback).Then(std::move(completion));
- auto barrier_callback = base::BarrierCallback<PasswordStoreChangeList>(
- forms_to_remove.size(), base::BindOnce(&JoinPasswordStoreChanges)
- .Then(std::move(notify_callback)));
+ auto barrier_callback =
+ base::BarrierCallback<absl::optional<PasswordStoreChangeList>>(
+ forms_to_remove.size(), base::BindOnce(&JoinPasswordStoreChanges)
+ .Then(std::move(notify_callback)));
for (const auto& form : forms_to_remove) {
backend_->RemoveLoginAsync(form, barrier_callback);
diff --git a/chromium/components/password_manager/core/browser/password_store.h b/chromium/components/password_manager/core/browser/password_store.h
index 02ed3fb79fe..7607c63f549 100644
--- a/chromium/components/password_manager/core/browser/password_store.h
+++ b/chromium/components/password_manager/core/browser/password_store.h
@@ -50,6 +50,15 @@ using metrics_util::GaiaPasswordHashChange;
class PasswordStoreConsumer;
+// Used to notify that unsynced credentials are about to be deleted.
+class UnsyncedCredentialsDeletionNotifier {
+ public:
+ // Should be called from the UI thread.
+ virtual void Notify(std::vector<PasswordForm>) = 0;
+ virtual ~UnsyncedCredentialsDeletionNotifier() = default;
+ virtual base::WeakPtr<UnsyncedCredentialsDeletionNotifier> GetWeakPtr() = 0;
+};
+
// Partial, cross-platform implementation for storing form passwords.
// The login request/manipulation API is not threadsafe and must be used
// from the UI thread.
@@ -57,22 +66,15 @@ class PasswordStoreConsumer;
// needs to access these methods.
class PasswordStore : public PasswordStoreInterface {
public:
- // Used to notify that unsynced credentials are about to be deleted.
- class UnsyncedCredentialsDeletionNotifier {
- public:
- // Should be called from the UI thread.
- virtual void Notify(std::vector<PasswordForm>) = 0;
- virtual ~UnsyncedCredentialsDeletionNotifier() = default;
- virtual base::WeakPtr<UnsyncedCredentialsDeletionNotifier> GetWeakPtr() = 0;
- };
-
explicit PasswordStore(std::unique_ptr<PasswordStoreBackend> backend);
PasswordStore(const PasswordStore&) = delete;
PasswordStore& operator=(const PasswordStore&) = delete;
- // Always call this too on the UI thread.
- // TODO(crbug.bom/1218413): Move initialization into the core interface, too.
+ // Always call this too on the UI thread. |sync_enabled_or_disabled_cb| is
+ // invoked in UI thread (or sequence used to invoke Init()) when sync is
+ // enabled or disabled. It is no longer invoked after ShutdownOnUIThread().
+ // TODO(crbug.com/1218413): Move initialization into the core interface, too.
bool Init(
PrefService* prefs,
std::unique_ptr<AffiliatedMatchHelper> affiliated_match_helper,
@@ -146,13 +148,38 @@ class PasswordStore : public PasswordStoreInterface {
using InsecureCredentialsTask =
base::OnceCallback<std::vector<InsecureCredential>()>;
+ // Represents different triggers that may require requesting all logins from
+ // the password store. Entries should not be renumbered and numeric values
+ // should never be reused. Always keep this enum in sync with the
+ // corresponding LoginsChangedTrigger in enums.xml.
+ enum class LoginsChangedTrigger {
+ ExternalUpdate = 0,
+ Addition = 1,
+ Update = 2,
+ Deletion = 3,
+ BatchDeletion = 4,
+ Unblocklisting = 5,
+ // Must be last.
+ kMaxValue = Unblocklisting,
+ };
+
// Called on the main thread after initialization is completed.
// |success| is true if initialization was successful. Sets the
// |init_status_|.
void OnInitCompleted(bool success);
- // Notifies observers that password store data may have been changed.
- void NotifyLoginsChangedOnMainSequence(PasswordStoreChangeList changes);
+ // Notifies observers that password store data may have been changed. If
+ // available, it forwards the changes to observers. Otherwise, all logins are
+ // requested and forwarded to `NotifyLoginsRetainedOnMainSequence`.
+ void NotifyLoginsChangedOnMainSequence(
+ LoginsChangedTrigger change_event,
+ absl::optional<PasswordStoreChangeList> changes);
+
+ // Notifies observers with all logins remaining after a modifying operation.
+ void NotifyLoginsRetainedOnMainSequence(LoginsResultOrError result);
+
+ // Called when the backend reports that sync has been enabled or disabled.
+ void NotifySyncEnabledOrDisabledOnMainSequence();
// The following methods notify observers that the password store may have
// been modified via NotifyLoginsChangedOnMainSequence(). Note that there is
@@ -179,6 +206,9 @@ class PasswordStore : public PasswordStoreInterface {
// TODO(crbug.com/1217071): Move into backend_.
scoped_refptr<base::SequencedTaskRunner> main_task_runner_;
+ // Closure passed during Init().
+ base::RepeatingClosure sync_enabled_or_disabled_cb_ = base::DoNothing();
+
// The observers.
base::ObserverList<Observer, /*check_empty=*/true> observers_;
diff --git a/chromium/components/password_manager/core/browser/password_store_backend.h b/chromium/components/password_manager/core/browser/password_store_backend.h
index 0ae1109e8d3..117f06011e0 100644
--- a/chromium/components/password_manager/core/browser/password_store_backend.h
+++ b/chromium/components/password_manager/core/browser/password_store_backend.h
@@ -20,8 +20,6 @@ class PrefService;
namespace password_manager {
-class LoginDatabase;
-
struct PasswordForm;
class FieldInfoStore;
@@ -40,7 +38,7 @@ enum class PasswordStoreBackendError {
using LoginsResult = std::vector<std::unique_ptr<PasswordForm>>;
using LoginsReply = base::OnceCallback<void(LoginsResult)>;
using PasswordStoreChangeListReply =
- base::OnceCallback<void(PasswordStoreChangeList)>;
+ base::OnceCallback<void(absl::optional<PasswordStoreChangeList>)>;
using LoginsResultOrError =
absl::variant<LoginsResult, PasswordStoreBackendError>;
@@ -53,8 +51,26 @@ using LoginsOrErrorReply = base::OnceCallback<void(LoginsResultOrError)>;
// IO operation from possibly blocking the main thread.
class PasswordStoreBackend {
public:
+ // Delegate which provides information about current sync status and an
+ // account used for syncing.
+ class SyncDelegate {
+ public:
+ SyncDelegate() = default;
+ SyncDelegate(const SyncDelegate&) = delete;
+ SyncDelegate(SyncDelegate&&) = delete;
+ SyncDelegate& operator=(const SyncDelegate&) = delete;
+ SyncDelegate& operator=(SyncDelegate&&) = delete;
+ virtual ~SyncDelegate() = default;
+
+ // Tells whether sync enabled or not.
+ virtual bool IsSyncingPasswordsEnabled() = 0;
+
+ // Active syncing account if one exist.
+ virtual absl::optional<std::string> GetSyncingAccount() = 0;
+ };
+
using RemoteChangesReceived =
- base::RepeatingCallback<void(PasswordStoreChangeList)>;
+ base::RepeatingCallback<void(absl::optional<PasswordStoreChangeList>)>;
PasswordStoreBackend() = default;
PasswordStoreBackend(const PasswordStoreBackend&) = delete;
@@ -63,8 +79,6 @@ class PasswordStoreBackend {
PasswordStoreBackend& operator=(PasswordStoreBackend&&) = delete;
virtual ~PasswordStoreBackend() = default;
- virtual base::WeakPtr<PasswordStoreBackend> GetWeakPtr() = 0;
-
// TODO(crbug.bom/1226042): Rename this to Init after PasswordStoreImpl no
// longer inherits PasswordStore.
virtual void InitBackend(RemoteChangesReceived remote_form_changes_received,
@@ -100,6 +114,13 @@ class PasswordStoreBackend {
// TODO(crbug.com/1217071): Delete corresponding Impl method from
// PasswordStore and the async method on backend_ instead.
+ // The completion callback in each of the write operations below receive an
+ // optional PasswordStoreChangeList. In case of success that the changelist
+ // will be populated with the executed changes. An empty changelist indicates
+ // that some error has occurred during the execution. The absence of the
+ // changelist indicates that the used backend (e.g. on Android) cannot
+ // confirm of the execution and a re-fetch is required to know the current
+ // state of the backend.
virtual void AddLoginAsync(const PasswordForm& form,
PasswordStoreChangeListReply callback) = 0;
virtual void UpdateLoginAsync(const PasswordForm& form,
@@ -128,12 +149,16 @@ class PasswordStoreBackend {
virtual std::unique_ptr<syncer::ProxyModelTypeControllerDelegate>
CreateSyncControllerDelegate() = 0;
+ // Clears all the passwords from the local storage.
+ virtual void ClearAllLocalPasswords() = 0;
+
// Factory function for creating the backend. The Local backend requires the
- // provided `login_db` for storage and Android backend for migration purposes.
+ // provided `login_db_path` for storage and Android backend for migration
+ // purposes. |sync_delegate| is also required for migration purposes.
static std::unique_ptr<PasswordStoreBackend> Create(
- std::unique_ptr<LoginDatabase> login_db,
+ const base::FilePath& login_db_path,
PrefService* prefs,
- base::RepeatingCallback<bool()> is_syncing_passwords_callback);
+ std::unique_ptr<SyncDelegate> sync_delegate);
};
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/password_store_backend_migration_decorator.cc b/chromium/components/password_manager/core/browser/password_store_backend_migration_decorator.cc
index f95f8c36803..8434628c92a 100644
--- a/chromium/components/password_manager/core/browser/password_store_backend_migration_decorator.cc
+++ b/chromium/components/password_manager/core/browser/password_store_backend_migration_decorator.cc
@@ -5,10 +5,12 @@
#include "components/password_manager/core/browser/password_store_backend_migration_decorator.h"
#include "base/bind.h"
+#include "base/task/sequenced_task_runner.h"
#include "components/password_manager/core/browser/built_in_backend_to_android_backend_migrator.h"
#include "components/password_manager/core/browser/field_info_table.h"
#include "components/password_manager/core/browser/password_store_proxy_backend.h"
#include "components/password_manager/core/common/password_manager_features.h"
+#include "components/password_manager/core/common/password_manager_pref_names.h"
#include "components/prefs/pref_service.h"
#include "components/sync/model/proxy_model_type_controller_delegate.h"
@@ -26,35 +28,51 @@ PasswordStoreBackendMigrationDecorator::PasswordStoreBackendMigrationDecorator(
std::unique_ptr<PasswordStoreBackend> built_in_backend,
std::unique_ptr<PasswordStoreBackend> android_backend,
PrefService* prefs,
- base::RepeatingCallback<bool()> is_syncing_passwords_callback)
+ std::unique_ptr<SyncDelegate> sync_delegate)
: built_in_backend_(std::move(built_in_backend)),
android_backend_(std::move(android_backend)),
prefs_(prefs),
- is_syncing_passwords_callback_(std::move(is_syncing_passwords_callback)) {
+ sync_delegate_(std::move(sync_delegate)) {
DCHECK(built_in_backend_);
DCHECK(android_backend_);
active_backend_ = std::make_unique<PasswordStoreProxyBackend>(
- built_in_backend_.get(), android_backend_.get(),
- is_syncing_passwords_callback_);
+ built_in_backend_.get(), android_backend_.get(), prefs_,
+ sync_delegate_.get());
}
PasswordStoreBackendMigrationDecorator::
~PasswordStoreBackendMigrationDecorator() = default;
-base::WeakPtr<PasswordStoreBackend>
-PasswordStoreBackendMigrationDecorator::GetWeakPtr() {
- return weak_ptr_factory_.GetWeakPtr();
-}
-
void PasswordStoreBackendMigrationDecorator::InitBackend(
RemoteChangesReceived remote_form_changes_received,
base::RepeatingClosure sync_enabled_or_disabled_cb,
base::OnceCallback<void(bool)> completion) {
+ base::RepeatingClosure handle_sync_status_change = base::BindRepeating(
+ &PasswordStoreBackendMigrationDecorator::SyncStatusChanged,
+ weak_ptr_factory_.GetWeakPtr());
+
+ // |sync_enabled_or_disabled_cb| is called on a background sequence so it
+ // should be posted to the main sequence before invoking
+ // PasswordStoreBackendMigrationDecorator::SyncStatusChanged().
+ base::RepeatingClosure handle_sync_status_change_on_main_thread =
+ base::BindRepeating(
+ base::IgnoreResult(&base::SequencedTaskRunner::PostTask),
+ base::SequencedTaskRunnerHandle::Get(), FROM_HERE,
+ std::move(handle_sync_status_change));
+
+ // Inject nested callback to listen for sync status changes.
+ sync_enabled_or_disabled_cb =
+ std::move(handle_sync_status_change_on_main_thread)
+ .Then(std::move(sync_enabled_or_disabled_cb));
+
active_backend_->InitBackend(std::move(remote_form_changes_received),
std::move(sync_enabled_or_disabled_cb),
std::move(completion));
if (base::FeatureList::IsEnabled(
features::kUnifiedPasswordManagerMigration)) {
+ migrator_ = std::make_unique<BuiltInBackendToAndroidBackendMigrator>(
+ built_in_backend_.get(), android_backend_.get(), prefs_,
+ sync_delegate_.get());
base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::BindOnce(&PasswordStoreBackendMigrationDecorator::StartMigration,
@@ -168,11 +186,28 @@ PasswordStoreBackendMigrationDecorator::CreateSyncControllerDelegate() {
return built_in_backend_->CreateSyncControllerDelegate();
}
+void PasswordStoreBackendMigrationDecorator::ClearAllLocalPasswords() {
+ NOTIMPLEMENTED();
+}
+
void PasswordStoreBackendMigrationDecorator::StartMigration() {
- migrator_ = std::make_unique<BuiltInBackendToAndroidBackendMigrator>(
- built_in_backend_.get(), android_backend_.get(), prefs_,
- is_syncing_passwords_callback_);
+ DCHECK(migrator_);
migrator_->StartMigrationIfNecessary();
}
+void PasswordStoreBackendMigrationDecorator::SyncStatusChanged() {
+ if (!base::FeatureList::IsEnabled(features::kUnifiedPasswordManagerMigration))
+ return;
+
+ if (sync_delegate_->IsSyncingPasswordsEnabled()) {
+ // Sync was enabled. Delete all the passwords from GMS Core local storage.
+ android_backend_->ClearAllLocalPasswords();
+ } else {
+ // Clear migration pref to force rerun of initial migration of passwords
+ // from Chrome to GMS Core local storage.
+ prefs_->SetInteger(prefs::kCurrentMigrationVersionToGoogleMobileServices,
+ 0);
+ }
+}
+
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/password_store_backend_migration_decorator.h b/chromium/components/password_manager/core/browser/password_store_backend_migration_decorator.h
index 9353be1f145..4646d9c5c1d 100644
--- a/chromium/components/password_manager/core/browser/password_store_backend_migration_decorator.h
+++ b/chromium/components/password_manager/core/browser/password_store_backend_migration_decorator.h
@@ -30,7 +30,7 @@ class PasswordStoreBackendMigrationDecorator : public PasswordStoreBackend {
std::unique_ptr<PasswordStoreBackend> built_in_backend,
std::unique_ptr<PasswordStoreBackend> android_backend,
PrefService* prefs,
- base::RepeatingCallback<bool()> is_syncing_passwords_callback);
+ std::unique_ptr<SyncDelegate> sync_delegate);
PasswordStoreBackendMigrationDecorator(
const PasswordStoreBackendMigrationDecorator&) = delete;
PasswordStoreBackendMigrationDecorator(
@@ -43,7 +43,6 @@ class PasswordStoreBackendMigrationDecorator : public PasswordStoreBackend {
private:
// Implements PasswordStoreBackend interface.
- base::WeakPtr<PasswordStoreBackend> GetWeakPtr() override;
void InitBackend(RemoteChangesReceived remote_form_changes_received,
base::RepeatingClosure sync_enabled_or_disabled_cb,
base::OnceCallback<void(bool)> completion) override;
@@ -77,10 +76,15 @@ class PasswordStoreBackendMigrationDecorator : public PasswordStoreBackend {
FieldInfoStore* GetFieldInfoStore() override;
std::unique_ptr<syncer::ProxyModelTypeControllerDelegate>
CreateSyncControllerDelegate() override;
+ void ClearAllLocalPasswords() override;
// Creates 'migrator_' and starts migration process.
void StartMigration();
+ // React on sync changes to keep GMS Core local storage up-to-date.
+ // TODO(https://crbug.com/) Remove this method when no longer needed.
+ void SyncStatusChanged();
+
std::unique_ptr<PasswordStoreBackend> built_in_backend_;
std::unique_ptr<PasswordStoreBackend> android_backend_;
@@ -89,7 +93,7 @@ class PasswordStoreBackendMigrationDecorator : public PasswordStoreBackend {
raw_ptr<PrefService> prefs_ = nullptr;
- base::RepeatingCallback<bool()> is_syncing_passwords_callback_;
+ std::unique_ptr<SyncDelegate> sync_delegate_;
std::unique_ptr<BuiltInBackendToAndroidBackendMigrator> migrator_;
diff --git a/chromium/components/password_manager/core/browser/password_store_backend_migration_decorator_unittest.cc b/chromium/components/password_manager/core/browser/password_store_backend_migration_decorator_unittest.cc
index 3c0f0fed7d5..713e79e4d84 100644
--- a/chromium/components/password_manager/core/browser/password_store_backend_migration_decorator_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_store_backend_migration_decorator_unittest.cc
@@ -4,98 +4,167 @@
#include "components/password_manager/core/browser/password_store_backend_migration_decorator.h"
+#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "base/memory/raw_ptr.h"
#include "base/test/mock_callback.h"
+#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
-#include "components/password_manager/core/browser/fake_password_store_backend.h"
+#include "components/password_manager/core/browser/mock_password_store_backend.h"
#include "components/password_manager/core/browser/password_manager_test_utils.h"
+#include "components/password_manager/core/common/password_manager_features.h"
+#include "components/password_manager/core/common/password_manager_pref_names.h"
+#include "components/prefs/pref_registry.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/testing_pref_service.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace password_manager {
namespace {
-using ::testing::_;
-using ::testing::Invoke;
+using ::testing::Return;
using ::testing::WithArg;
-
-std::vector<std::unique_ptr<PasswordForm>> CreateTestLogins() {
- std::vector<std::unique_ptr<PasswordForm>> forms;
- forms.push_back(CreateEntry("Todd Tester", "S3cr3t",
- GURL(u"https://example.com"),
- /*is_psl_match=*/false,
- /*is_affiliation_based_match=*/false));
- forms.push_back(CreateEntry("Marcus McSpartanGregor", "S0m3th1ngCr34t1v3",
- GURL(u"https://m.example.com"),
- /*is_psl_match=*/true,
- /*is_affiliation_based_match=*/false));
- forms[0]->in_store = PasswordForm::Store::kProfileStore;
- forms[1]->in_store = PasswordForm::Store::kProfileStore;
- return forms;
-}
+using ::testing::WithArgs;
} // namespace
class PasswordStoreBackendMigrationDecoratorTest : public testing::Test {
protected:
PasswordStoreBackendMigrationDecoratorTest() {
+ prefs_.registry()->RegisterIntegerPref(
+ prefs::kCurrentMigrationVersionToGoogleMobileServices, 0);
+
+ feature_list_.InitAndEnableFeatureWithParameters(
+ /*enabled_feature=*/features::kUnifiedPasswordManagerMigration,
+ {{"migration_version", "1"}});
+
backend_migration_decorator_ =
std::make_unique<PasswordStoreBackendMigrationDecorator>(
- CreateBuiltInBackend(), CreateAndroidBackend(), /*prefs=*/nullptr,
- /*is_syncing_passwords_callback=*/base::BindRepeating([]() {
- return false;
- }));
+ CreateBuiltInBackend(), CreateAndroidBackend(), &prefs_,
+ CreateSyncDelegate());
}
~PasswordStoreBackendMigrationDecoratorTest() override {
backend_migration_decorator()->Shutdown(base::DoNothing());
}
+ MockPasswordBackendSyncDelegate* sync_delegate() { return sync_delegate_; }
PasswordStoreBackend* backend_migration_decorator() {
return backend_migration_decorator_.get();
}
- PasswordStoreBackend* built_in_backend() { return built_in_backend_; }
- PasswordStoreBackend* android_backend() { return android_backend_; }
-
- void AddTestLogins() {
- for (const auto& login : CreateTestLogins()) {
- built_in_backend()->AddLoginAsync(*login, base::DoNothing());
- android_backend()->AddLoginAsync(*login, base::DoNothing());
- }
- RunUntilIdle();
- }
+ MockPasswordStoreBackend* built_in_backend() { return built_in_backend_; }
+ MockPasswordStoreBackend* android_backend() { return android_backend_; }
+
+ TestingPrefServiceSimple& prefs() { return prefs_; }
void RunUntilIdle() { task_env_.RunUntilIdle(); }
private:
std::unique_ptr<PasswordStoreBackend> CreateBuiltInBackend() {
- auto unique_backend = std::make_unique<FakePasswordStoreBackend>();
+ auto unique_backend = std::make_unique<MockPasswordStoreBackend>();
built_in_backend_ = unique_backend.get();
return unique_backend;
}
std::unique_ptr<PasswordStoreBackend> CreateAndroidBackend() {
- auto unique_backend = std::make_unique<FakePasswordStoreBackend>();
+ auto unique_backend = std::make_unique<MockPasswordStoreBackend>();
android_backend_ = unique_backend.get();
return unique_backend;
}
+ std::unique_ptr<MockPasswordBackendSyncDelegate> CreateSyncDelegate() {
+ auto unique_delegate = std::make_unique<MockPasswordBackendSyncDelegate>();
+ sync_delegate_ = unique_delegate.get();
+ return unique_delegate;
+ }
+
base::test::SingleThreadTaskEnvironment task_env_;
- raw_ptr<FakePasswordStoreBackend> built_in_backend_;
- raw_ptr<FakePasswordStoreBackend> android_backend_;
+ base::test::ScopedFeatureList feature_list_;
+ TestingPrefServiceSimple prefs_;
+ raw_ptr<MockPasswordBackendSyncDelegate> sync_delegate_;
+ raw_ptr<MockPasswordStoreBackend> built_in_backend_;
+ raw_ptr<MockPasswordStoreBackend> android_backend_;
std::unique_ptr<PasswordStoreBackendMigrationDecorator>
backend_migration_decorator_;
};
TEST_F(PasswordStoreBackendMigrationDecoratorTest,
- UseBuiltInBackendToGetAllLoginsAsync) {
- base::MockCallback<LoginsOrErrorReply> mock_reply;
- std::vector<std::unique_ptr<PasswordForm>> expected_logins =
- CreateTestLogins();
- AddTestLogins();
- EXPECT_CALL(mock_reply, Run(LoginsResultsOrErrorAre(&expected_logins)));
- backend_migration_decorator()->GetAllLoginsAsync(mock_reply.Get());
+ MigrationPreferenceClearedWhenSyncDisabled) {
+ base::MockCallback<base::OnceCallback<void(bool)>> mock_completion_callback;
+ base::RepeatingClosure sync_status_changed_closure;
+
+ // Set up pref to indicate that initial migration is finished.
+ prefs().SetInteger(prefs::kCurrentMigrationVersionToGoogleMobileServices, 2);
+
+ EXPECT_CALL(mock_completion_callback, Run(/*success=*/true));
+
+ EXPECT_CALL(*built_in_backend(), InitBackend)
+ .WillOnce(WithArgs<1, 2>(
+ [&sync_status_changed_closure](auto sync_status_changed,
+ auto completion_callback) {
+ std::move(completion_callback).Run(/*success=*/true);
+ // Capture |sync_enabled_or_disabled_cb| passed to the
+ // build_in_backend.
+ sync_status_changed_closure = std::move(sync_status_changed);
+ }));
+ EXPECT_CALL(*android_backend(), InitBackend)
+ .WillOnce(WithArg<2>([](auto completion_callback) {
+ std::move(completion_callback).Run(/*success=*/true);
+ }));
+
+ backend_migration_decorator()->InitBackend(
+ /*remote_form_changes_received=*/base::DoNothing(),
+ /*sync_enabled_or_disabled_cb=*/base::DoNothing(),
+ /*completion=*/mock_completion_callback.Get());
+
+ // Invoke sync callback to simulate a change in sync status. Set expectation
+ // for sync to be turned off.
+ EXPECT_CALL(*sync_delegate(), IsSyncingPasswordsEnabled)
+ .WillOnce(Return(false));
+ sync_status_changed_closure.Run();
+
+ RunUntilIdle();
+
+ // Since sync was disabled pref value for migration version should be reset.
+ EXPECT_EQ(0, prefs().GetInteger(
+ prefs::kCurrentMigrationVersionToGoogleMobileServices));
+}
+
+TEST_F(PasswordStoreBackendMigrationDecoratorTest,
+ LocalAndroidPasswordsClearedWhenSyncEnabled) {
+ base::MockCallback<base::OnceCallback<void(bool)>> mock_completion_callback;
+ base::RepeatingClosure sync_status_changed_closure;
+
+ EXPECT_CALL(mock_completion_callback, Run(/*success=*/true));
+
+ EXPECT_CALL(*built_in_backend(), InitBackend)
+ .WillOnce(WithArgs<1, 2>(
+ [&sync_status_changed_closure](auto sync_status_changed,
+ auto completion_callback) {
+ std::move(completion_callback).Run(/*success=*/true);
+ // Capture |sync_enabled_or_disabled_cb| passed to the
+ // build_in_backend.
+ sync_status_changed_closure = std::move(sync_status_changed);
+ }));
+ EXPECT_CALL(*android_backend(), InitBackend)
+ .WillOnce(WithArg<2>([](auto completion_callback) {
+ std::move(completion_callback).Run(/*success=*/true);
+ }));
+
+ backend_migration_decorator()->InitBackend(
+ /*remote_form_changes_received=*/base::DoNothing(),
+ /*sync_enabled_or_disabled_cb=*/base::DoNothing(),
+ /*completion=*/mock_completion_callback.Get());
+
+ // Invoke sync callback to simulate a change in sync status. Set expectation
+ // for sync to be turned off.
+ EXPECT_CALL(*sync_delegate(), IsSyncingPasswordsEnabled)
+ .WillOnce(Return(true));
+ EXPECT_CALL(*android_backend(), ClearAllLocalPasswords);
+ sync_status_changed_closure.Run();
+
RunUntilIdle();
}
diff --git a/chromium/components/password_manager/core/browser/password_store_built_in_backend.cc b/chromium/components/password_manager/core/browser/password_store_built_in_backend.cc
index a27228018a7..6f652d89ca7 100644
--- a/chromium/components/password_manager/core/browser/password_store_built_in_backend.cc
+++ b/chromium/components/password_manager/core/browser/password_store_built_in_backend.cc
@@ -4,303 +4,77 @@
#include "components/password_manager/core/browser/password_store_built_in_backend.h"
-#include <iterator>
-#include <memory>
-#include <set>
-#include <utility>
-
#include "base/bind.h"
-#include "base/location.h"
-#include "base/logging.h"
-#include "base/memory/scoped_refptr.h"
-#include "base/memory/weak_ptr.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
-#include "build/build_config.h"
-#include "components/password_manager/core/browser/field_info_table.h"
#include "components/password_manager/core/browser/login_database.h"
-#include "components/password_manager/core/browser/password_store_backend.h"
-#include "components/password_manager/core/browser/password_store_change.h"
-#include "components/password_manager/core/browser/password_store_consumer.h"
-#include "components/password_manager/core/browser/sync/password_sync_bridge.h"
-#include "components/prefs/pref_service.h"
-#include "components/sync/model/client_tag_based_model_type_processor.h"
-#include "components/sync/model/model_type_controller_delegate.h"
+#include "components/password_manager/core/browser/login_database_async_helper.h"
#include "components/sync/model/proxy_model_type_controller_delegate.h"
namespace password_manager {
-namespace {
-
-constexpr base::TimeDelta kSyncTaskTimeout = base::Seconds(30);
-
-} // namespace
-
PasswordStoreBuiltInBackend::PasswordStoreBuiltInBackend(
- std::unique_ptr<LoginDatabase> login_db)
- : login_db_(std::move(login_db)) {
- main_task_runner_ = base::SequencedTaskRunnerHandle::Get();
- DCHECK(main_task_runner_);
+ std::unique_ptr<LoginDatabase> login_db,
+ std::unique_ptr<UnsyncedCredentialsDeletionNotifier> notifier) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
background_task_runner_ = base::ThreadPool::CreateSequencedTaskRunner(
{base::MayBlock(), base::TaskPriority::USER_VISIBLE});
DCHECK(background_task_runner_);
+ helper_ = std::make_unique<LoginDatabaseAsyncHelper>(
+ std::move(login_db), std::move(notifier),
+ base::SequencedTaskRunnerHandle::Get());
}
-PasswordStoreBuiltInBackend::PasswordStoreBuiltInBackend(
- std::unique_ptr<LoginDatabase> login_db,
- std::unique_ptr<PasswordStore::UnsyncedCredentialsDeletionNotifier>
- notifier)
- : PasswordStoreBuiltInBackend(std::move(login_db)) {
- DCHECK(notifier);
- deletion_notifier_ = std::move(notifier);
+PasswordStoreBuiltInBackend::~PasswordStoreBuiltInBackend() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
-PasswordStoreBuiltInBackend::~PasswordStoreBuiltInBackend() = default;
-
void PasswordStoreBuiltInBackend::Shutdown(
base::OnceClosure shutdown_completed) {
- DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
- was_shutdown_ = true;
- background_task_runner_->PostTaskAndReply(
- FROM_HERE,
- base::BindOnce(&PasswordStoreBuiltInBackend::DestroyOnBackgroundSequence,
- weak_ptr_factory_.GetWeakPtr()),
- std::move(shutdown_completed));
-}
-
-PasswordStoreChangeList
-PasswordStoreBuiltInBackend::DisableAutoSignInForOriginsImpl(
- const base::RepeatingCallback<bool(const GURL&)>& origin_filter) {
- PrimaryKeyToFormMap key_to_form_map;
- PasswordStoreChangeList changes;
- if (!login_db_ || !login_db_->GetAutoSignInLogins(&key_to_form_map))
- return changes;
-
- std::set<GURL> origins_to_update;
- for (const auto& pair : key_to_form_map) {
- if (origin_filter.Run(pair.second->url))
- origins_to_update.insert(pair.second->url);
- }
-
- std::set<GURL> origins_updated;
- for (const GURL& origin : origins_to_update) {
- if (login_db_->DisableAutoSignInForOrigin(origin))
- origins_updated.insert(origin);
- }
-
- for (const auto& pair : key_to_form_map) {
- if (origins_updated.count(pair.second->url)) {
- changes.emplace_back(PasswordStoreChange::UPDATE, *pair.second,
- FormPrimaryKey(pair.first));
- }
- }
-
- return changes;
-}
-
-DatabaseCleanupResult PasswordStoreBuiltInBackend::DeleteUndecryptableLogins() {
- DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
- if (!login_db_)
- return DatabaseCleanupResult::kDatabaseUnavailable;
- return login_db_->DeleteUndecryptableLogins();
-}
-
-void PasswordStoreBuiltInBackend::AddSiteStatsInternal(
- const InteractionsStats& stats) {
- DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
- if (login_db_)
- login_db_->stats_table().AddRow(stats);
-}
-
-void PasswordStoreBuiltInBackend::RemoveSiteStatsInternal(
- const GURL& origin_domain) {
- DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
- if (login_db_)
- login_db_->stats_table().RemoveRow(origin_domain);
-}
-
-std::vector<InteractionsStats>
-PasswordStoreBuiltInBackend::GetSiteStatsInternal(const GURL& origin_domain) {
- DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
- return login_db_ ? login_db_->stats_table().GetRows(origin_domain)
- : std::vector<InteractionsStats>();
-}
-
-void PasswordStoreBuiltInBackend::RemoveStatisticsByOriginAndTimeInternal(
- const base::RepeatingCallback<bool(const GURL&)>& origin_filter,
- base::Time delete_begin,
- base::Time delete_end) {
- if (login_db_) {
- login_db_->stats_table().RemoveStatsByOriginAndTime(
- origin_filter, delete_begin, delete_end);
- }
-}
-
-base::WeakPtr<syncer::ModelTypeControllerDelegate>
-PasswordStoreBuiltInBackend::GetSyncControllerDelegateOnBackgroundSequence() {
- DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
- DCHECK(sync_bridge_);
- return sync_bridge_->change_processor()->GetControllerDelegate();
-}
-
-void PasswordStoreBuiltInBackend::ReportMetrics() {
- DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
- if (!login_db_)
- return;
- login_db_->ReportMetrics();
-}
-
-PasswordStoreChangeList PasswordStoreBuiltInBackend::AddLoginSync(
- const PasswordForm& form,
- AddLoginError* error) {
- if (!login_db_) {
- if (error) {
- *error = AddLoginError::kDbNotAvailable;
- }
- return PasswordStoreChangeList();
- }
- return login_db_->AddLogin(form, error);
-}
-
-PasswordStoreChangeList PasswordStoreBuiltInBackend::UpdateLoginSync(
- const PasswordForm& form,
- UpdateLoginError* error) {
- if (!login_db_) {
- if (error) {
- *error = UpdateLoginError::kDbNotAvailable;
- }
- return PasswordStoreChangeList();
- }
- return login_db_->UpdateLogin(form, error);
-}
-
-void PasswordStoreBuiltInBackend::NotifyLoginsChanged(
- const PasswordStoreChangeList& changes) {
- if (!remote_forms_changes_received_callback_)
- return;
- main_task_runner_->PostTask(
- FROM_HERE,
- base::BindOnce(remote_forms_changes_received_callback_, changes));
-}
-
-void PasswordStoreBuiltInBackend::NotifyDeletionsHaveSynced(bool success) {
- DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
- // Either all deletions have been committed to the Sync server, or Sync is
- // telling us that it won't commit them (because Sync was turned off
- // permanently). In either case, run the corresponding callbacks now (on the
- // main task runner).
- DCHECK(!success || !GetMetadataStore()->HasUnsyncedDeletions());
- for (auto& callback : deletions_have_synced_callbacks_) {
- main_task_runner_->PostTask(FROM_HERE,
- base::BindOnce(std::move(callback), success));
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ if (helper_) {
+ background_task_runner_->DeleteSoon(FROM_HERE, std::move(helper_));
}
- deletions_have_synced_timeout_.Cancel();
- deletions_have_synced_callbacks_.clear();
-}
-
-void PasswordStoreBuiltInBackend::NotifyUnsyncedCredentialsWillBeDeleted(
- std::vector<PasswordForm> unsynced_credentials) {
- DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
- DCHECK(IsAccountStore());
- // |deletion_notifier_| only gets set for desktop.
- if (deletion_notifier_) {
- main_task_runner_->PostTask(
- FROM_HERE,
- base::BindOnce(
- &PasswordStore::UnsyncedCredentialsDeletionNotifier::Notify,
- deletion_notifier_->GetWeakPtr(), std::move(unsynced_credentials)));
- }
-}
-
-bool PasswordStoreBuiltInBackend::BeginTransaction() {
- if (login_db_)
- return login_db_->BeginTransaction();
- return false;
-}
-
-void PasswordStoreBuiltInBackend::RollbackTransaction() {
- if (login_db_)
- login_db_->RollbackTransaction();
-}
-
-bool PasswordStoreBuiltInBackend::CommitTransaction() {
- if (login_db_)
- return login_db_->CommitTransaction();
- return false;
-}
-
-FormRetrievalResult PasswordStoreBuiltInBackend::ReadAllLogins(
- PrimaryKeyToFormMap* key_to_form_map) {
- DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
- if (!login_db_)
- return FormRetrievalResult::kDbError;
- return login_db_->GetAllLogins(key_to_form_map);
-}
-
-PasswordStoreChangeList
-PasswordStoreBuiltInBackend::RemoveLoginByPrimaryKeySync(
- FormPrimaryKey primary_key) {
- DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
- PasswordStoreChangeList changes;
- if (login_db_ && login_db_->RemoveLoginByPrimaryKey(primary_key, &changes)) {
- return changes;
- }
- return PasswordStoreChangeList();
-}
-
-PasswordStoreSync::MetadataStore*
-PasswordStoreBuiltInBackend::GetMetadataStore() {
- return login_db_.get();
-}
-
-bool PasswordStoreBuiltInBackend::IsAccountStore() const {
- return login_db_ && login_db_->is_account_store();
-}
-
-bool PasswordStoreBuiltInBackend::DeleteAndRecreateDatabaseFile() {
- return login_db_ && login_db_->DeleteAndRecreateDatabaseFile();
-}
-
-base::WeakPtr<PasswordStoreBackend> PasswordStoreBuiltInBackend::GetWeakPtr() {
- return weak_ptr_factory_.GetWeakPtr();
}
void PasswordStoreBuiltInBackend::InitBackend(
RemoteChangesReceived remote_form_changes_received,
base::RepeatingClosure sync_enabled_or_disabled_cb,
base::OnceCallback<void(bool)> completion) {
- DCHECK(!was_shutdown_);
- DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(helper_);
background_task_runner_->PostTaskAndReplyWithResult(
FROM_HERE,
- base::BindOnce(&PasswordStoreBuiltInBackend::InitOnBackgroundSequence,
- base::Unretained(this), // Safe until `Shutdown()`.
- std::move(remote_form_changes_received),
- std::move(sync_enabled_or_disabled_cb)),
+ base::BindOnce(
+ &LoginDatabaseAsyncHelper::Initialize,
+ base::Unretained(helper_.get()), // Safe until `Shutdown()`.
+ std::move(remote_form_changes_received),
+ std::move(sync_enabled_or_disabled_cb)),
std::move(completion));
}
void PasswordStoreBuiltInBackend::GetAllLoginsAsync(
LoginsOrErrorReply callback) {
- DCHECK(!was_shutdown_);
- DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(helper_);
background_task_runner_->PostTaskAndReplyWithResult(
FROM_HERE,
- base::BindOnce(&PasswordStoreBuiltInBackend::GetAllLoginsInternal,
- base::Unretained(this)), // Safe until `Shutdown()`.
+ base::BindOnce(
+ &LoginDatabaseAsyncHelper::GetAllLogins,
+ base::Unretained(helper_.get())), // Safe until `Shutdown()`.
std::move(callback));
}
void PasswordStoreBuiltInBackend::GetAutofillableLoginsAsync(
LoginsOrErrorReply callback) {
- DCHECK(!was_shutdown_);
- DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(helper_);
background_task_runner_->PostTaskAndReplyWithResult(
FROM_HERE,
base::BindOnce(
- &PasswordStoreBuiltInBackend::GetAutofillableLoginsInternal,
- base::Unretained(this)), // Safe until `Shutdown()`.
+ &LoginDatabaseAsyncHelper::GetAutofillableLogins,
+ base::Unretained(helper_.get())), // Safe until `Shutdown()`.
std::move(callback));
}
@@ -308,8 +82,8 @@ void PasswordStoreBuiltInBackend::FillMatchingLoginsAsync(
LoginsReply callback,
bool include_psl,
const std::vector<PasswordFormDigest>& forms) {
- DCHECK(!was_shutdown_);
- DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(helper_);
if (forms.empty()) {
std::move(callback).Run({});
return;
@@ -317,48 +91,48 @@ void PasswordStoreBuiltInBackend::FillMatchingLoginsAsync(
background_task_runner_->PostTaskAndReplyWithResult(
FROM_HERE,
- base::BindOnce(&PasswordStoreBuiltInBackend::FillMatchingLoginsInternal,
- base::Unretained(this), // Safe until `Shutdown()`.
- forms, include_psl),
+ base::BindOnce(
+ &LoginDatabaseAsyncHelper::FillMatchingLogins,
+ base::Unretained(helper_.get()), // Safe until `Shutdown()`.
+ forms, include_psl),
std::move(callback));
}
void PasswordStoreBuiltInBackend::AddLoginAsync(
const PasswordForm& form,
PasswordStoreChangeListReply callback) {
- DCHECK(!was_shutdown_);
- DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(helper_);
background_task_runner_->PostTaskAndReplyWithResult(
FROM_HERE,
- base::BindOnce(&PasswordStoreBuiltInBackend::AddLoginInternal,
- base::Unretained(this), // Safe until `Shutdown()`.
- form),
+ base::BindOnce(&LoginDatabaseAsyncHelper::AddLogin,
+ base::Unretained(helper_.get()), form),
std::move(callback));
}
void PasswordStoreBuiltInBackend::UpdateLoginAsync(
const PasswordForm& form,
PasswordStoreChangeListReply callback) {
- DCHECK(!was_shutdown_);
- DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(helper_);
background_task_runner_->PostTaskAndReplyWithResult(
FROM_HERE,
- base::BindOnce(&PasswordStoreBuiltInBackend::UpdateLoginInternal,
- base::Unretained(this), // Safe until `Shutdown()`.
- form),
+ base::BindOnce(&LoginDatabaseAsyncHelper::UpdateLogin,
+ base::Unretained(helper_.get()), form),
std::move(callback));
}
void PasswordStoreBuiltInBackend::RemoveLoginAsync(
const PasswordForm& form,
PasswordStoreChangeListReply callback) {
- DCHECK(!was_shutdown_);
- DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(helper_);
background_task_runner_->PostTaskAndReplyWithResult(
FROM_HERE,
- base::BindOnce(&PasswordStoreBuiltInBackend::RemoveLoginInternal,
- base::Unretained(this), // Safe until `Shutdown()`.
- form),
+ base::BindOnce(
+ &LoginDatabaseAsyncHelper::RemoveLogin,
+ base::Unretained(helper_.get()), // Safe until `Shutdown()`.
+ form),
std::move(callback));
}
@@ -366,13 +140,13 @@ void PasswordStoreBuiltInBackend::RemoveLoginsCreatedBetweenAsync(
base::Time delete_begin,
base::Time delete_end,
PasswordStoreChangeListReply callback) {
- DCHECK(!was_shutdown_);
- DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(helper_);
background_task_runner_->PostTaskAndReplyWithResult(
FROM_HERE,
base::BindOnce(
- &PasswordStoreBuiltInBackend::RemoveLoginsCreatedBetweenInternal,
- base::Unretained(this), // Safe until `Shutdown()`.
+ &LoginDatabaseAsyncHelper::RemoveLoginsCreatedBetween,
+ base::Unretained(helper_.get()), // Safe until `Shutdown()`.
delete_begin, delete_end),
std::move(callback));
}
@@ -383,13 +157,13 @@ void PasswordStoreBuiltInBackend::RemoveLoginsByURLAndTimeAsync(
base::Time delete_end,
base::OnceCallback<void(bool)> sync_completion,
PasswordStoreChangeListReply callback) {
- DCHECK(!was_shutdown_);
- DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(helper_);
background_task_runner_->PostTaskAndReplyWithResult(
FROM_HERE,
base::BindOnce(
- &PasswordStoreBuiltInBackend::RemoveLoginsByURLAndTimeInternal,
- base::Unretained(this), // Safe until `Shutdown()`.
+ &LoginDatabaseAsyncHelper::RemoveLoginsByURLAndTime,
+ base::Unretained(helper_.get()), // Safe until `Shutdown()`.
url_filter, delete_begin, delete_end, std::move(sync_completion)),
std::move(callback));
}
@@ -397,14 +171,14 @@ void PasswordStoreBuiltInBackend::RemoveLoginsByURLAndTimeAsync(
void PasswordStoreBuiltInBackend::DisableAutoSignInForOriginsAsync(
const base::RepeatingCallback<bool(const GURL&)>& origin_filter,
base::OnceClosure completion) {
- DCHECK(!was_shutdown_);
- DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(helper_);
background_task_runner_->PostTaskAndReply(
FROM_HERE,
base::BindOnce(
base::IgnoreResult(
- &PasswordStoreBuiltInBackend::DisableAutoSignInForOriginsImpl),
- base::Unretained(this), // Safe until `Shutdown()`.
+ &LoginDatabaseAsyncHelper::DisableAutoSignInForOrigins),
+ base::Unretained(helper_.get()), // Safe until `Shutdown()`.
origin_filter),
std::move(completion));
}
@@ -419,54 +193,52 @@ FieldInfoStore* PasswordStoreBuiltInBackend::GetFieldInfoStore() {
std::unique_ptr<syncer::ProxyModelTypeControllerDelegate>
PasswordStoreBuiltInBackend::CreateSyncControllerDelegate() {
- DCHECK(!was_shutdown_);
- DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(helper_);
// Note that a callback is bound for
- // GetSyncControllerDelegateOnBackgroundSequence() because this getter itself
+ // GetSyncControllerDelegate() because this getter itself
// must also run in the backend sequence, and the proxy object below will take
// care of that.
// Since the controller delegate can (only in theory) invoke the factory after
// `Shutdown` was called, it only returns nullptr then to prevent a UAF.
return std::make_unique<syncer::ProxyModelTypeControllerDelegate>(
background_task_runner_,
- base::BindRepeating(
- [](base::WeakPtr<PasswordStoreBuiltInBackend> backend) {
- if (!backend)
- return base::WeakPtr<syncer::ModelTypeControllerDelegate>(
- nullptr);
- return backend->GetSyncControllerDelegateOnBackgroundSequence();
- },
- weak_ptr_factory_.GetWeakPtr()));
+ base::BindRepeating(&LoginDatabaseAsyncHelper::GetSyncControllerDelegate,
+ base::Unretained(helper_.get())));
+}
+
+void PasswordStoreBuiltInBackend::ClearAllLocalPasswords() {
+ NOTREACHED();
}
void PasswordStoreBuiltInBackend::AddSiteStats(const InteractionsStats& stats) {
- DCHECK(!was_shutdown_);
- DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(helper_);
background_task_runner_->PostTask(
- FROM_HERE,
- base::BindOnce(&PasswordStoreBuiltInBackend::AddSiteStatsInternal,
- weak_ptr_factory_.GetWeakPtr(), stats));
+ FROM_HERE, base::BindOnce(&LoginDatabaseAsyncHelper::AddSiteStats,
+ base::Unretained(helper_.get()), stats));
}
void PasswordStoreBuiltInBackend::RemoveSiteStats(const GURL& origin_domain) {
- DCHECK(!was_shutdown_);
- DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(helper_);
background_task_runner_->PostTask(
FROM_HERE,
- base::BindOnce(&PasswordStoreBuiltInBackend::RemoveSiteStatsInternal,
- weak_ptr_factory_.GetWeakPtr(), origin_domain));
+ base::BindOnce(&LoginDatabaseAsyncHelper::RemoveSiteStats,
+ base::Unretained(helper_.get()), origin_domain));
}
void PasswordStoreBuiltInBackend::GetSiteStats(
const GURL& origin_domain,
base::WeakPtr<PasswordStoreConsumer> consumer) {
- DCHECK(!was_shutdown_);
- DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(helper_);
consumer->cancelable_task_tracker()->PostTaskAndReplyWithResult(
background_task_runner_.get(), FROM_HERE,
- base::BindOnce(&PasswordStoreBuiltInBackend::GetSiteStatsInternal,
- base::Unretained(this), // Safe until `Shutdown()`.
- origin_domain),
+ base::BindOnce(
+ &LoginDatabaseAsyncHelper::GetSiteStats,
+ base::Unretained(helper_.get()), // Safe until `Shutdown()`.
+ origin_domain),
base::BindOnce(&PasswordStoreConsumer::OnGetSiteStatistics, consumer));
}
@@ -475,34 +247,33 @@ void PasswordStoreBuiltInBackend::RemoveStatisticsByOriginAndTime(
base::Time delete_begin,
base::Time delete_end,
base::OnceClosure completion) {
- DCHECK(!was_shutdown_);
- DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(helper_);
background_task_runner_->PostTaskAndReply(
FROM_HERE,
- base::BindOnce(
- &PasswordStoreBuiltInBackend::RemoveStatisticsByOriginAndTimeInternal,
- weak_ptr_factory_.GetWeakPtr(), origin_filter, delete_begin,
- delete_end),
+ base::BindOnce(&LoginDatabaseAsyncHelper::RemoveStatisticsByOriginAndTime,
+ base::Unretained(helper_.get()), origin_filter,
+ delete_begin, delete_end),
std::move(completion));
}
void PasswordStoreBuiltInBackend::AddFieldInfo(const FieldInfo& field_info) {
- DCHECK(!was_shutdown_);
- DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(helper_);
background_task_runner_->PostTask(
- FROM_HERE,
- base::BindOnce(&PasswordStoreBuiltInBackend::AddFieldInfoInternal,
- weak_ptr_factory_.GetWeakPtr(), field_info));
+ FROM_HERE, base::BindOnce(&LoginDatabaseAsyncHelper::AddFieldInfo,
+ base::Unretained(helper_.get()), field_info));
}
void PasswordStoreBuiltInBackend::GetAllFieldInfo(
base::WeakPtr<PasswordStoreConsumer> consumer) {
- DCHECK(!was_shutdown_);
- DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(helper_);
consumer->cancelable_task_tracker()->PostTaskAndReplyWithResult(
background_task_runner_.get(), FROM_HERE,
- base::BindOnce(&PasswordStoreBuiltInBackend::GetAllFieldInfoInternal,
- base::Unretained(this)), // Safe until `Shutdown()`.
+ base::BindOnce(
+ &LoginDatabaseAsyncHelper::GetAllFieldInfo,
+ base::Unretained(helper_.get())), // Safe until `Shutdown()`.
base::BindOnce(&PasswordStoreConsumer::OnGetAllFieldInfo, consumer));
}
@@ -510,235 +281,13 @@ void PasswordStoreBuiltInBackend::RemoveFieldInfoByTime(
base::Time remove_begin,
base::Time remove_end,
base::OnceClosure completion) {
- DCHECK(!was_shutdown_);
- DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(helper_);
background_task_runner_->PostTaskAndReply(
FROM_HERE,
- base::BindOnce(
- &PasswordStoreBuiltInBackend::RemoveFieldInfoByTimeInternal,
- weak_ptr_factory_.GetWeakPtr(), remove_begin, remove_end),
+ base::BindOnce(&LoginDatabaseAsyncHelper::RemoveFieldInfoByTime,
+ base::Unretained(helper_.get()), remove_begin, remove_end),
std::move(completion));
}
-bool PasswordStoreBuiltInBackend::InitOnBackgroundSequence(
- RemoteChangesReceived remote_form_changes_received,
- base::RepeatingClosure sync_enabled_or_disabled_cb) {
- DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
-
- remote_forms_changes_received_callback_ =
- std::move(remote_form_changes_received);
-
- DCHECK(login_db_);
- bool success = true;
- if (!login_db_->Init()) {
- login_db_.reset();
- // The initialization should be continued, because PasswordSyncBridge
- // has to be initialized even if database initialization failed.
- success = false;
- LOG(ERROR) << "Could not create/open login database.";
- }
- if (success) {
- login_db_->SetDeletionsHaveSyncedCallback(base::BindRepeating(
- &PasswordStoreBuiltInBackend::NotifyDeletionsHaveSynced,
- weak_ptr_factory_.GetWeakPtr()));
-
- // Delay the actual reporting by 30 seconds, to ensure it doesn't happen
- // during the "hot phase" of Chrome startup.
- background_task_runner_->PostDelayedTask(
- FROM_HERE,
- base::BindOnce(&PasswordStoreBuiltInBackend::ReportMetrics,
- weak_ptr_factory_.GetWeakPtr()),
- base::Seconds(30));
- }
-
- sync_bridge_ = base::WrapUnique(new PasswordSyncBridge(
- std::make_unique<syncer::ClientTagBasedModelTypeProcessor>(
- syncer::PASSWORDS, base::DoNothing()),
- /*password_store_sync=*/this, sync_enabled_or_disabled_cb));
-
- return success;
-}
-
-void PasswordStoreBuiltInBackend::DestroyOnBackgroundSequence() {
- DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
- remote_forms_changes_received_callback_.Reset();
- weak_ptr_factory_.InvalidateWeakPtrs();
- login_db_.reset();
- sync_bridge_.reset();
- // No task should be running on (or send to) the background runner.
- background_task_runner_.reset();
- main_task_runner_.reset();
-}
-
-LoginsResult PasswordStoreBuiltInBackend::GetAllLoginsInternal() {
- DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
- PrimaryKeyToFormMap key_to_form_map;
-
- if (!login_db_ || login_db_->GetAllLogins(&key_to_form_map) !=
- FormRetrievalResult::kSuccess)
- return {};
-
- std::vector<std::unique_ptr<PasswordForm>> obtained_forms;
- for (auto& pair : key_to_form_map) {
- obtained_forms.push_back(std::move(pair.second));
- }
- return obtained_forms;
-}
-
-LoginsResult PasswordStoreBuiltInBackend::GetAutofillableLoginsInternal() {
- std::vector<std::unique_ptr<PasswordForm>> results;
- if (!login_db_ || !login_db_->GetAutofillableLogins(&results))
- return {};
- return results;
-}
-
-LoginsResult PasswordStoreBuiltInBackend::FillMatchingLoginsInternal(
- const std::vector<PasswordFormDigest>& forms,
- bool include_psl) {
- DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
-
- std::vector<std::unique_ptr<PasswordForm>> results;
- for (const auto& form : forms) {
- std::vector<std::unique_ptr<PasswordForm>> matched_forms;
- if (login_db_ && !login_db_->GetLogins(form, include_psl, &matched_forms))
- continue;
- results.insert(results.end(),
- std::make_move_iterator(matched_forms.begin()),
- std::make_move_iterator(matched_forms.end()));
- }
- return results;
-}
-
-PasswordStoreChangeList PasswordStoreBuiltInBackend::AddLoginInternal(
- const PasswordForm& form) {
- DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
- BeginTransaction();
- PasswordStoreChangeList changes = AddLoginSync(form, /*error=*/nullptr);
- if (sync_bridge_ && !changes.empty())
- sync_bridge_->ActOnPasswordStoreChanges(changes);
- // Sync metadata get updated in ActOnPasswordStoreChanges(). Therefore,
- // CommitTransaction() must be called after ActOnPasswordStoreChanges(),
- // because sync codebase needs to update metadata atomically together with the
- // login data.
- CommitTransaction();
- return changes;
-}
-
-PasswordStoreChangeList PasswordStoreBuiltInBackend::UpdateLoginInternal(
- const PasswordForm& form) {
- DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
- BeginTransaction();
- PasswordStoreChangeList changes = UpdateLoginSync(form, /*error=*/nullptr);
- if (sync_bridge_ && !changes.empty())
- sync_bridge_->ActOnPasswordStoreChanges(changes);
- // Sync metadata get updated in ActOnPasswordStoreChanges(). Therefore,
- // CommitTransaction() must be called after ActOnPasswordStoreChanges(),
- // because sync codebase needs to update metadata atomically together with the
- // login data.
- CommitTransaction();
- return changes;
-}
-
-PasswordStoreChangeList PasswordStoreBuiltInBackend::RemoveLoginInternal(
- const PasswordForm& form) {
- DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
- BeginTransaction();
- PasswordStoreChangeList changes;
- if (login_db_ && login_db_->RemoveLogin(form, &changes)) {
- if (sync_bridge_ && !changes.empty())
- sync_bridge_->ActOnPasswordStoreChanges(changes);
- }
- // Sync metadata get updated in ActOnPasswordStoreChanges(). Therefore,
- // CommitTransaction() must be called after ActOnPasswordStoreChanges(),
- // because sync codebase needs to update metadata atomically together with the
- // login data.
- CommitTransaction();
- return changes;
-}
-
-PasswordStoreChangeList
-PasswordStoreBuiltInBackend::RemoveLoginsCreatedBetweenInternal(
- base::Time delete_begin,
- base::Time delete_end) {
- DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
- BeginTransaction();
- PasswordStoreChangeList changes;
- if (login_db_ && login_db_->RemoveLoginsCreatedBetween(
- delete_begin, delete_end, &changes)) {
- if (sync_bridge_ && !changes.empty())
- sync_bridge_->ActOnPasswordStoreChanges(changes);
- }
- // Sync metadata get updated in ActOnPasswordStoreChanges(). Therefore,
- // CommitTransaction() must be called after ActOnPasswordStoreChanges(),
- // because sync codebase needs to update metadata atomically together with the
- // login data.
- CommitTransaction();
- return changes;
-}
-
-PasswordStoreChangeList
-PasswordStoreBuiltInBackend::RemoveLoginsByURLAndTimeInternal(
- const base::RepeatingCallback<bool(const GURL&)>& url_filter,
- base::Time delete_begin,
- base::Time delete_end,
- base::OnceCallback<void(bool)> sync_completion) {
- BeginTransaction();
- PrimaryKeyToFormMap key_to_form_map;
- PasswordStoreChangeList changes;
- if (login_db_ && login_db_->GetLoginsCreatedBetween(delete_begin, delete_end,
- &key_to_form_map)) {
- for (const auto& pair : key_to_form_map) {
- PasswordForm* form = pair.second.get();
- PasswordStoreChangeList remove_changes;
- if (url_filter.Run(form->url) &&
- login_db_->RemoveLogin(*form, &remove_changes)) {
- std::move(remove_changes.begin(), remove_changes.end(),
- std::back_inserter(changes));
- }
- }
- }
- if (sync_bridge_ && !changes.empty())
- sync_bridge_->ActOnPasswordStoreChanges(changes);
- // Sync metadata get updated in ActOnPasswordStoreChanges(). Therefore,
- // CommitTransaction() must be called after ActOnPasswordStoreChanges(),
- // because sync codebase needs to update metadata atomically together with the
- // login data.
- CommitTransaction();
-
- if (sync_completion) {
- deletions_have_synced_callbacks_.push_back(std::move(sync_completion));
- // Start a timeout for sync, or restart it if it was already running.
- deletions_have_synced_timeout_.Reset(
- base::BindOnce(&PasswordStoreBuiltInBackend::NotifyDeletionsHaveSynced,
- weak_ptr_factory_.GetWeakPtr(),
- /*success=*/false));
- background_task_runner_->PostDelayedTask(
- FROM_HERE, deletions_have_synced_timeout_.callback(), kSyncTaskTimeout);
-
- // Do an immediate check for the case where there are already no unsynced
- // deletions.
- if (!GetMetadataStore()->HasUnsyncedDeletions())
- NotifyDeletionsHaveSynced(/*success=*/true);
- }
- return changes;
-}
-
-void PasswordStoreBuiltInBackend::AddFieldInfoInternal(
- const FieldInfo& field_info) {
- if (login_db_)
- login_db_->field_info_table().AddRow(field_info);
-}
-
-std::vector<FieldInfo> PasswordStoreBuiltInBackend::GetAllFieldInfoInternal() {
- return login_db_ ? login_db_->field_info_table().GetAllRows()
- : std::vector<FieldInfo>();
-}
-
-void PasswordStoreBuiltInBackend::RemoveFieldInfoByTimeInternal(
- base::Time remove_begin,
- base::Time remove_end) {
- if (login_db_)
- login_db_->field_info_table().RemoveRowsByTime(remove_begin, remove_end);
-}
-
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/password_store_built_in_backend.h b/chromium/components/password_manager/core/browser/password_store_built_in_backend.h
index ba237488529..335cdee0b2a 100644
--- a/chromium/components/password_manager/core/browser/password_store_built_in_backend.h
+++ b/chromium/components/password_manager/core/browser/password_store_built_in_backend.h
@@ -12,13 +12,9 @@
#include "base/gtest_prod_util.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
-#include "components/password_manager/core/browser/insecure_credentials_table.h"
-#include "components/password_manager/core/browser/login_database.h"
-#include "components/password_manager/core/browser/password_store.h"
-
-namespace syncer {
-class ModelTypeControllerDelegate;
-} // namespace syncer
+#include "components/password_manager/core/browser/field_info_store.h"
+#include "components/password_manager/core/browser/password_store_backend.h"
+#include "components/password_manager/core/browser/smart_bubble_stats_store.h"
namespace base {
class SequencedTaskRunner;
@@ -26,60 +22,28 @@ class SequencedTaskRunner;
namespace password_manager {
-class PasswordSyncBridge;
+class LoginDatabase;
+class LoginDatabaseAsyncHelper;
+class UnsyncedCredentialsDeletionNotifier;
struct FieldInfo;
// Simple password store implementation that delegates everything to
-// the LoginDatabase.
-class PasswordStoreBuiltInBackend : protected PasswordStoreSync,
- public PasswordStoreBackend,
+// the LoginDatabaseAsyncHelper. Works only on the main sequence.
+class PasswordStoreBuiltInBackend : public PasswordStoreBackend,
public SmartBubbleStatsStore,
protected FieldInfoStore {
public:
// The |login_db| must not have been Init()-ed yet. It will be initialized in
// a deferred manner on the background sequence.
- explicit PasswordStoreBuiltInBackend(std::unique_ptr<LoginDatabase> login_db);
-
PasswordStoreBuiltInBackend(
std::unique_ptr<LoginDatabase> login_db,
- std::unique_ptr<PasswordStore::UnsyncedCredentialsDeletionNotifier>
- notifier);
+ std::unique_ptr<UnsyncedCredentialsDeletionNotifier> notifier = nullptr);
~PasswordStoreBuiltInBackend() override;
- protected:
- // Implements PasswordStore interface.
- PasswordStoreChangeList DisableAutoSignInForOriginsImpl(
- const base::RepeatingCallback<bool(const GURL&)>& origin_filter);
- DatabaseCleanupResult DeleteUndecryptableLogins() override;
-
- // Implements PasswordStoreSync interface.
- PasswordStoreChangeList AddLoginSync(const PasswordForm& form,
- AddLoginError* error) override;
- PasswordStoreChangeList UpdateLoginSync(const PasswordForm& form,
- UpdateLoginError* error) override;
- void NotifyLoginsChanged(const PasswordStoreChangeList& changes) override;
- void NotifyDeletionsHaveSynced(bool success) override;
- void NotifyUnsyncedCredentialsWillBeDeleted(
- std::vector<PasswordForm> unsynced_credentials) override;
- bool BeginTransaction() override;
- void RollbackTransaction() override;
- bool CommitTransaction() override;
- FormRetrievalResult ReadAllLogins(
- PrimaryKeyToFormMap* key_to_form_map) override;
- PasswordStoreChangeList RemoveLoginByPrimaryKeySync(
- FormPrimaryKey primary_key) override;
- PasswordStoreSync::MetadataStore* GetMetadataStore() override;
- bool IsAccountStore() const override;
- bool DeleteAndRecreateDatabaseFile() override;
-
private:
- FRIEND_TEST_ALL_PREFIXES(PasswordStoreTest,
- UpdatePasswordsStoredForAffiliatedWebsites);
-
// Implements PasswordStoreBackend interface.
- base::WeakPtr<PasswordStoreBackend> GetWeakPtr() override;
void InitBackend(RemoteChangesReceived remote_form_changes_received,
base::RepeatingClosure sync_enabled_or_disabled_cb,
base::OnceCallback<void(bool)> completion) override;
@@ -113,6 +77,7 @@ class PasswordStoreBuiltInBackend : protected PasswordStoreSync,
FieldInfoStore* GetFieldInfoStore() override;
std::unique_ptr<syncer::ProxyModelTypeControllerDelegate>
CreateSyncControllerDelegate() override;
+ void ClearAllLocalPasswords() override;
// SmartBubbleStatsStore:
void AddSiteStats(const InteractionsStats& stats) override;
@@ -132,96 +97,19 @@ class PasswordStoreBuiltInBackend : protected PasswordStoreSync,
base::Time remove_end,
base::OnceClosure completion) override;
- // Opens |login_db_| and creates |sync_bridge_| on the background sequence.
- bool InitOnBackgroundSequence(
- RemoteChangesReceived remote_form_changes_received,
- base::RepeatingClosure sync_enabled_or_disabled_cb);
-
- // Resets all members on the background sequence but ensures that the
- // backend deletion is happening on the given `main_task_runner` after the
- // backend work is concluded.
- void DestroyOnBackgroundSequence();
-
- // Synchronous implementation of GetAllLoginsAsync.
- LoginsResult GetAllLoginsInternal();
-
- // Synchronous implementation of GetAutofillableLoginsAsync.
- LoginsResult GetAutofillableLoginsInternal();
+ // Ensures that all methods are called on the main sequence.
+ SEQUENCE_CHECKER(sequence_checker_);
- // Synchronous implementation of FillMatchingLoginsAsync.
- LoginsResult FillMatchingLoginsInternal(
- const std::vector<PasswordFormDigest>& forms,
- bool include_psl);
-
- PasswordStoreChangeList AddLoginInternal(const PasswordForm& form);
- PasswordStoreChangeList UpdateLoginInternal(const PasswordForm& form);
- PasswordStoreChangeList RemoveLoginInternal(const PasswordForm& form);
- PasswordStoreChangeList RemoveLoginsCreatedBetweenInternal(
- base::Time delete_begin,
- base::Time delete_end);
- PasswordStoreChangeList RemoveLoginsByURLAndTimeInternal(
- const base::RepeatingCallback<bool(const GURL&)>& url_filter,
- base::Time delete_begin,
- base::Time delete_end,
- base::OnceCallback<void(bool)> sync_completion);
-
- // Synchronous implementation for manipulating with statistics.
- void AddSiteStatsInternal(const InteractionsStats& stats);
- void RemoveSiteStatsInternal(const GURL& origin_domain);
- std::vector<InteractionsStats> GetSiteStatsInternal(
- const GURL& origin_domain);
- void RemoveStatisticsByOriginAndTimeInternal(
- const base::RepeatingCallback<bool(const GURL&)>& origin_filter,
- base::Time delete_begin,
- base::Time delete_end);
-
- // Synchronous implementation for manipulating with field info.
- void AddFieldInfoInternal(const FieldInfo& field_info);
- std::vector<FieldInfo> GetAllFieldInfoInternal();
- void RemoveFieldInfoByTimeInternal(base::Time remove_begin,
- base::Time remove_end);
-
- base::WeakPtr<syncer::ModelTypeControllerDelegate>
- GetSyncControllerDelegateOnBackgroundSequence();
-
- // Reports password store metrics that aren't reported by the
- // StoreMetricsReporter. Namely, metrics related to inaccessible passwords,
- // and bubble statistics.
- void ReportMetrics();
-
- // Used to trigger DCHECKs if tasks are posted after shut down.
- bool was_shutdown_{false};
-
- // The login SQL database. The LoginDatabase instance is received via the
- // in an uninitialized state, so as to allow injecting mocks, then Init() is
- // called on the background sequence in a deferred manner. If opening the DB
- // fails, |login_db_| will be reset and stay NULL for the lifetime of |this|.
- std::unique_ptr<LoginDatabase> login_db_;
-
- std::unique_ptr<PasswordSyncBridge> sync_bridge_;
-
- // Whenever 'sync_bridge_'receive remote changes this callback is used to
- // notify PasswordStore observers about them. Called on a main sequence from
- // the 'NotifyLoginsChanged'.
- RemoteChangesReceived remote_forms_changes_received_callback_;
-
- std::unique_ptr<PasswordStore::UnsyncedCredentialsDeletionNotifier>
- deletion_notifier_;
-
- // A list of callbacks that should be run once all pending deletions have been
- // sent to the Sync server. Note that the vector itself lives on the
- // background thread, but the callbacks must be run on the main thread!
- std::vector<base::OnceCallback<void(bool)>> deletions_have_synced_callbacks_;
- // Timeout closure that runs if sync takes too long to propagate deletions.
- base::CancelableOnceClosure deletions_have_synced_timeout_;
-
- // TaskRunner for tasks that run on the main sequence (usually the UI thread).
- scoped_refptr<base::SequencedTaskRunner> main_task_runner_;
+ // The helper, owned by this backend instance, but
+ // living on the |background_task_runner_|. It will be deleted asynchronously
+ // during shutdown on the |background_task_runner_|, so it will outlive |this|
+ // along with all its in-flight tasks.
+ std::unique_ptr<LoginDatabaseAsyncHelper> helper_
+ GUARDED_BY_CONTEXT(sequence_checker_);
// TaskRunner for all the background operations.
- scoped_refptr<base::SequencedTaskRunner> background_task_runner_;
-
- base::WeakPtrFactory<PasswordStoreBuiltInBackend> weak_ptr_factory_{this};
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner_
+ GUARDED_BY_CONTEXT(sequence_checker_);
};
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/password_store_built_in_backend_unittest.cc b/chromium/components/password_manager/core/browser/password_store_built_in_backend_unittest.cc
index ce2e50a36e9..e54e95fbc5f 100644
--- a/chromium/components/password_manager/core/browser/password_store_built_in_backend_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_store_built_in_backend_unittest.cc
@@ -30,6 +30,7 @@ using testing::_;
using testing::ElementsAre;
using testing::ElementsAreArray;
using testing::IsEmpty;
+using testing::Optional;
namespace password_manager {
@@ -58,7 +59,7 @@ class MockPasswordStoreConsumer : public PasswordStoreConsumer {
class MockPasswordStoreBackendTester {
public:
- MOCK_METHOD(void, HandleChanges, (PasswordStoreChangeList));
+ MOCK_METHOD(void, HandleChanges, (absl::optional<PasswordStoreChangeList>));
MOCK_METHOD(void,
LoginsReceivedConstRef,
(const std::vector<std::unique_ptr<PasswordForm>>&));
@@ -202,7 +203,7 @@ TEST_F(PasswordStoreBuiltInBackendTest, TestAddLoginAsync) {
PasswordStoreChange(PasswordStoreChange::ADD, form);
testing::StrictMock<MockPasswordStoreBackendTester> tester;
- EXPECT_CALL(tester, HandleChanges(ElementsAre(add_change)));
+ EXPECT_CALL(tester, HandleChanges(Optional(ElementsAre(add_change))));
backend->AddLoginAsync(
form, base::BindOnce(&MockPasswordStoreBackendTester::HandleChanges,
base::Unretained(&tester)));
@@ -221,7 +222,7 @@ TEST_F(PasswordStoreBuiltInBackendTest, TestUpdateLoginAsync) {
PasswordStoreChange(PasswordStoreChange::UPDATE, form);
testing::StrictMock<MockPasswordStoreBackendTester> tester;
- EXPECT_CALL(tester, HandleChanges(ElementsAre(update_change)));
+ EXPECT_CALL(tester, HandleChanges(Optional(ElementsAre(update_change))));
backend->UpdateLoginAsync(
form, base::BindOnce(&MockPasswordStoreBackendTester::HandleChanges,
base::Unretained(&tester)));
@@ -239,7 +240,7 @@ TEST_F(PasswordStoreBuiltInBackendTest, TestRemoveLoginAsync) {
PasswordStoreChange(PasswordStoreChange::REMOVE, form);
testing::StrictMock<MockPasswordStoreBackendTester> tester;
- EXPECT_CALL(tester, HandleChanges(ElementsAre(remove_change)));
+ EXPECT_CALL(tester, HandleChanges(Optional(ElementsAre(remove_change))));
backend->RemoveLoginAsync(
form, base::BindOnce(&MockPasswordStoreBackendTester::HandleChanges,
base::Unretained(&tester)));
@@ -265,9 +266,10 @@ TEST_F(PasswordStoreBuiltInBackendTest, OperationsOnABadDatabaseSilentlyFail) {
blocked_form->action = GURL("http://foo.example.com/action");
blocked_form->blocked_by_user = true;
- base::RepeatingCallback<void(PasswordStoreChangeList)> handle_changes =
- base::BindRepeating(&MockPasswordStoreBackendTester::HandleChanges,
- base::Unretained(&tester));
+ base::RepeatingCallback<void(absl::optional<PasswordStoreChangeList>)>
+ handle_changes =
+ base::BindRepeating(&MockPasswordStoreBackendTester::HandleChanges,
+ base::Unretained(&tester));
base::RepeatingCallback<void(LoginsResult)> handle_logins =
base::BindRepeating(&MockPasswordStoreBackendTester::HandleLogins,
base::Unretained(&tester));
@@ -275,12 +277,12 @@ TEST_F(PasswordStoreBuiltInBackendTest, OperationsOnABadDatabaseSilentlyFail) {
base::BindRepeating(&MockPasswordStoreBackendTester::HandleLoginsOrError,
base::Unretained(&tester));
- EXPECT_CALL(tester, HandleChanges(IsEmpty()));
+ EXPECT_CALL(tester, HandleChanges(Optional(IsEmpty())));
bad_backend->AddLoginAsync(*form, handle_changes);
RunUntilIdle();
testing::Mock::VerifyAndClearExpectations(&tester);
- EXPECT_CALL(tester, HandleChanges(IsEmpty()));
+ EXPECT_CALL(tester, HandleChanges(Optional(IsEmpty())));
bad_backend->AddLoginAsync(*blocked_form, handle_changes);
RunUntilIdle();
testing::Mock::VerifyAndClearExpectations(&tester);
@@ -305,7 +307,7 @@ TEST_F(PasswordStoreBuiltInBackendTest, OperationsOnABadDatabaseSilentlyFail) {
testing::Mock::VerifyAndClearExpectations(&tester);
- EXPECT_CALL(tester, HandleChanges(IsEmpty()));
+ EXPECT_CALL(tester, HandleChanges(Optional(IsEmpty())));
bad_backend->RemoveLoginAsync(*form, handle_changes);
RunUntilIdle();
}
diff --git a/chromium/components/password_manager/core/browser/password_store_proxy_backend.cc b/chromium/components/password_manager/core/browser/password_store_proxy_backend.cc
index 436253678a3..5a453aa61af 100644
--- a/chromium/components/password_manager/core/browser/password_store_proxy_backend.cc
+++ b/chromium/components/password_manager/core/browser/password_store_proxy_backend.cc
@@ -18,25 +18,122 @@
#include "base/strings/strcat.h"
#include "components/password_manager/core/browser/field_info_table.h"
#include "components/password_manager/core/common/password_manager_features.h"
+#include "components/password_manager/core/common/password_manager_pref_names.h"
+#include "components/prefs/pref_service.h"
#include "components/sync/model/proxy_model_type_controller_delegate.h"
namespace password_manager {
namespace {
-using MethodName = base::StrongAlias<struct MethodNameTag, std::string>;
-
-bool IsPasswordUniquePtrLess(const std::unique_ptr<PasswordForm>& lhs,
- const std::unique_ptr<PasswordForm>& rhs) {
- return PasswordFormUniqueKey(*lhs) < PasswordFormUniqueKey(*rhs);
+bool ShouldExecuteModifyOperationsOnShadowBackend(PrefService* prefs,
+ bool is_syncing) {
+ if (!base::FeatureList::IsEnabled(
+ features::kUnifiedPasswordManagerShadowWriteOperationsAndroid)) {
+ return false;
+ }
+ if (is_syncing)
+ return false;
+ if (features::kMigrationVersion.Get() >
+ prefs->GetInteger(
+ prefs::kCurrentMigrationVersionToGoogleMobileServices)) {
+ // If initial migration isn't completed yet, we shouldn't modify the shadow
+ // backend.
+ return false;
+ }
+ return true;
}
-bool IsPasswordUniquePtrWithSameKeyInconsistent(
- const std::unique_ptr<PasswordForm>& lhs,
- const std::unique_ptr<PasswordForm>& rhs) {
- return lhs->password_value != rhs->password_value;
+bool ShouldExecuteReadOperationsOnShadowBackend(PrefService* prefs,
+ bool is_syncing) {
+ if (ShouldExecuteModifyOperationsOnShadowBackend(prefs, is_syncing)) {
+ // Read operations are always allowed whenever modifications are allowed.
+ // i.e. necessary migrations have happened and appropriate flags are set.
+ return true;
+ }
+ return is_syncing && base::FeatureList::IsEnabled(
+ features::kUnifiedPasswordManagerShadowAndroid);
}
+using MethodName = base::StrongAlias<struct MethodNameTag, std::string>;
+
+struct LoginsResultImpl {
+ using ResultType = LoginsResult;
+ using ElementsType = LoginsResult;
+
+ static LoginsResult* GetElements(LoginsResult& logins) { return &logins; }
+
+ static std::unique_ptr<PasswordForm> Clone(
+ const std::unique_ptr<PasswordForm>& login) {
+ return std::make_unique<PasswordForm>(*login);
+ }
+
+ static bool IsLess(const std::unique_ptr<PasswordForm>& lhs,
+ const std::unique_ptr<PasswordForm>& rhs) {
+ return PasswordFormUniqueKey(*lhs) < PasswordFormUniqueKey(*rhs);
+ }
+
+ static bool HaveInconsistentPasswords(
+ const std::unique_ptr<PasswordForm>& lhs,
+ const std::unique_ptr<PasswordForm>& rhs) {
+ return lhs->password_value != rhs->password_value;
+ }
+};
+
+struct LoginsResultOrErrorImpl {
+ using ResultType = LoginsResultOrError;
+ using ElementsType = LoginsResult;
+
+ static LoginsResult* GetElements(LoginsResultOrError& logins_or_error) {
+ return absl::holds_alternative<PasswordStoreBackendError>(logins_or_error)
+ ? nullptr
+ : &absl::get<LoginsResult>(logins_or_error);
+ }
+
+ static std::unique_ptr<PasswordForm> Clone(
+ const std::unique_ptr<PasswordForm>& login) {
+ return std::make_unique<PasswordForm>(*login);
+ }
+
+ static bool IsLess(const std::unique_ptr<PasswordForm>& lhs,
+ const std::unique_ptr<PasswordForm>& rhs) {
+ return PasswordFormUniqueKey(*lhs) < PasswordFormUniqueKey(*rhs);
+ }
+
+ static bool HaveInconsistentPasswords(
+ const std::unique_ptr<PasswordForm>& lhs,
+ const std::unique_ptr<PasswordForm>& rhs) {
+ return lhs->password_value != rhs->password_value;
+ }
+};
+
+struct PasswordStoreChangeListImpl {
+ using ResultType = absl::optional<PasswordStoreChangeList>;
+ using ElementsType = PasswordStoreChangeList;
+
+ static PasswordStoreChangeList* GetElements(
+ absl::optional<PasswordStoreChangeList>& changelist) {
+ return changelist.has_value() ? &changelist.value() : nullptr;
+ }
+
+ static PasswordStoreChange Clone(const PasswordStoreChange& change) {
+ return change;
+ }
+
+ static bool IsLess(const PasswordStoreChange& lhs,
+ const PasswordStoreChange& rhs) {
+ return std::forward_as_tuple(PasswordFormUniqueKey(lhs.form()),
+ lhs.type()) <
+ std::forward_as_tuple(PasswordFormUniqueKey(rhs.form()), rhs.type());
+ }
+
+ static bool HaveInconsistentPasswords(const PasswordStoreChange& lhs,
+ const PasswordStoreChange& rhs) {
+ // We never consider PasswordStoreChange having inconsistent passwords.
+ return false;
+ }
+};
+
void InvokeCallbackWithCombinedStatus(base::OnceCallback<void(bool)> completion,
std::vector<bool> statuses) {
std::move(completion).Run(base::ranges::all_of(statuses, base::identity()));
@@ -110,59 +207,63 @@ void RecordMetrics(const MethodName& method_name,
}
// Records the metrics of a pair of MethodName calls to the main and
-// the shadow backends once both calls are finished.
+// the shadow backends once both calls are finished. MethodName() is expected to
+// return an std::vector<ApiMethodImpl::ResultType>. ApiMethodImpl classes need
+// to provide 4 methods:
+// - GetElements(): returns the elements to be compared
+// - Clone(): Returns a copy of an element, used to cache the main results.
+// - IsLess(): to compare elements.
+// - HaveInconsistentPasswords(): Whether elements have inconsistent passwords
//
// The class is ref-counted because it is equally owned by the two parallel
// method calls : it must outlive the first returning one and shall be
// destroyed after the second one returns.
+template <typename ApiMethodImpl>
class ShadowTrafficMetricsRecorder
- : public base::RefCounted<ShadowTrafficMetricsRecorder> {
+ : public base::RefCounted<ShadowTrafficMetricsRecorder<ApiMethodImpl>> {
public:
explicit ShadowTrafficMetricsRecorder(MethodName method_name)
: method_name_(std::move(method_name)) {}
// Returns the unchanged |result| so it can be passed to the main handler.
- LoginsResultOrError RecordMainLoginsResultOrError(
- LoginsResultOrError logins_or_error) {
- if (absl::holds_alternative<PasswordStoreBackendError>(logins_or_error)) {
- return logins_or_error;
- }
-
- LoginsResult logins = std::move(absl::get<LoginsResult>(logins_or_error));
- if (!first_result_) {
- first_result_ = absl::make_optional<LoginsResult>();
- first_result_->reserve(logins.size());
- for (const auto& login : logins)
- first_result_->push_back(std::make_unique<PasswordForm>(*login));
- } else {
- RecordMetrics(method_name_, /*main_result=*/logins,
- /*shadow_result=*/*first_result_, &IsPasswordUniquePtrLess,
- &IsPasswordUniquePtrWithSameKeyInconsistent);
+ typename ApiMethodImpl::ResultType RecordMainResult(
+ typename ApiMethodImpl::ResultType result) {
+ if (auto* elements = ApiMethodImpl::GetElements(result)) {
+ if (!first_result_) {
+ first_result_ =
+ absl::make_optional<typename ApiMethodImpl::ElementsType>();
+ first_result_->reserve(elements->size());
+ for (const auto& e : *elements)
+ first_result_->push_back(ApiMethodImpl::Clone(e));
+ } else {
+ RecordMetrics(method_name_, /*main_result=*/*elements,
+ /*shadow_result=*/*first_result_, &ApiMethodImpl::IsLess,
+ &ApiMethodImpl::HaveInconsistentPasswords);
+ }
}
- return logins;
+ return result;
}
- void RecordShadowLoginsResultOrError(LoginsResultOrError logins_or_error) {
- if (absl::holds_alternative<PasswordStoreBackendError>(logins_or_error)) {
- return;
+ void RecordShadowResult(typename ApiMethodImpl::ResultType result) {
+ if (auto* elements = ApiMethodImpl::GetElements(result)) {
+ if (!first_result_) {
+ first_result_ = std::move(*elements);
+ } else {
+ RecordMetrics(method_name_,
+ /*main_result=*/*first_result_,
+ /*shadow_result=*/*elements, &ApiMethodImpl::IsLess,
+ &ApiMethodImpl::HaveInconsistentPasswords);
+ }
}
-
- LoginsResult logins = std::move(absl::get<LoginsResult>(logins_or_error));
- if (!first_result_)
- first_result_ = std::move(logins);
- else
- RecordMetrics(method_name_, /*main_result=*/*first_result_,
- /*shadow_result=*/logins, &IsPasswordUniquePtrLess,
- &IsPasswordUniquePtrWithSameKeyInconsistent);
}
private:
- friend class RefCounted<ShadowTrafficMetricsRecorder>;
+ friend class base::RefCounted<ShadowTrafficMetricsRecorder<ApiMethodImpl>>;
~ShadowTrafficMetricsRecorder() = default;
// Stores the result of the backend that returns first.
- absl::optional<LoginsResult> first_result_;
+ absl::optional<typename ApiMethodImpl::ElementsType> first_result_;
const MethodName method_name_;
};
@@ -171,18 +272,15 @@ class ShadowTrafficMetricsRecorder
PasswordStoreProxyBackend::PasswordStoreProxyBackend(
PasswordStoreBackend* main_backend,
PasswordStoreBackend* shadow_backend,
- base::RepeatingCallback<bool()> is_syncing_passwords_callback)
+ PrefService* prefs,
+ SyncDelegate* sync_delegate)
: main_backend_(main_backend),
shadow_backend_(shadow_backend),
- is_syncing_passwords_callback_(std::move(is_syncing_passwords_callback)) {
-}
+ prefs_(prefs),
+ sync_delegate_(sync_delegate) {}
PasswordStoreProxyBackend::~PasswordStoreProxyBackend() = default;
-base::WeakPtr<PasswordStoreBackend> PasswordStoreProxyBackend::GetWeakPtr() {
- return weak_ptr_factory_.GetWeakPtr();
-}
-
void PasswordStoreProxyBackend::InitBackend(
RemoteChangesReceived remote_form_changes_received,
base::RepeatingClosure sync_enabled_or_disabled_cb,
@@ -207,57 +305,132 @@ void PasswordStoreProxyBackend::Shutdown(base::OnceClosure shutdown_completed) {
}
void PasswordStoreProxyBackend::GetAllLoginsAsync(LoginsOrErrorReply callback) {
- scoped_refptr<ShadowTrafficMetricsRecorder> handler =
- base::MakeRefCounted<ShadowTrafficMetricsRecorder>(
- MethodName("GetAllLoginsAsync"));
+ auto handler = base::MakeRefCounted<
+ ShadowTrafficMetricsRecorder<LoginsResultOrErrorImpl>>(
+ MethodName("GetAllLoginsAsync"));
main_backend_->GetAllLoginsAsync(
- base::BindOnce(
- &ShadowTrafficMetricsRecorder::RecordMainLoginsResultOrError, handler)
+ base::BindOnce(&ShadowTrafficMetricsRecorder<
+ LoginsResultOrErrorImpl>::RecordMainResult,
+ handler)
.Then(std::move(callback)));
- if (is_syncing_passwords_callback_.Run() &&
- base::FeatureList::IsEnabled(
- features::kUnifiedPasswordManagerShadowAndroid)) {
- shadow_backend_->GetAllLoginsAsync(base::BindOnce(
- &ShadowTrafficMetricsRecorder::RecordShadowLoginsResultOrError,
- handler));
+ if (ShouldExecuteReadOperationsOnShadowBackend(
+ prefs_, sync_delegate_->IsSyncingPasswordsEnabled())) {
+ shadow_backend_->GetAllLoginsAsync(
+ base::BindOnce(&ShadowTrafficMetricsRecorder<
+ LoginsResultOrErrorImpl>::RecordShadowResult,
+ handler));
}
}
void PasswordStoreProxyBackend::GetAutofillableLoginsAsync(
LoginsOrErrorReply callback) {
- main_backend_->GetAutofillableLoginsAsync(std::move(callback));
- // TODO(crbug.com/1229655): Request shadow_backend_ and compare results.
+ auto handler = base::MakeRefCounted<
+ ShadowTrafficMetricsRecorder<LoginsResultOrErrorImpl>>(
+ MethodName("GetAutofillableLoginsAsync"));
+ main_backend_->GetAutofillableLoginsAsync(
+ base::BindOnce(&ShadowTrafficMetricsRecorder<
+ LoginsResultOrErrorImpl>::RecordMainResult,
+ handler)
+ .Then(std::move(callback)));
+
+ if (ShouldExecuteReadOperationsOnShadowBackend(
+ prefs_, sync_delegate_->IsSyncingPasswordsEnabled())) {
+ shadow_backend_->GetAutofillableLoginsAsync(
+ base::BindOnce(&ShadowTrafficMetricsRecorder<
+ LoginsResultOrErrorImpl>::RecordShadowResult,
+ handler));
+ }
}
void PasswordStoreProxyBackend::FillMatchingLoginsAsync(
LoginsReply callback,
bool include_psl,
const std::vector<PasswordFormDigest>& forms) {
- main_backend_->FillMatchingLoginsAsync(std::move(callback), include_psl,
- forms);
- // TODO(crbug.com/1229655): Request shadow_backend_ and compare results.
+ auto handler =
+ base::MakeRefCounted<ShadowTrafficMetricsRecorder<LoginsResultImpl>>(
+ MethodName("FillMatchingLoginsAsync"));
+ main_backend_->FillMatchingLoginsAsync(
+ base::BindOnce(
+ &ShadowTrafficMetricsRecorder<LoginsResultImpl>::RecordMainResult,
+ handler)
+ .Then(std::move(callback)),
+ include_psl, forms);
+
+ if (ShouldExecuteReadOperationsOnShadowBackend(
+ prefs_, sync_delegate_->IsSyncingPasswordsEnabled())) {
+ shadow_backend_->FillMatchingLoginsAsync(
+ base::BindOnce(
+ &ShadowTrafficMetricsRecorder<LoginsResultImpl>::RecordShadowResult,
+ handler),
+ include_psl, forms);
+ }
}
void PasswordStoreProxyBackend::AddLoginAsync(
const PasswordForm& form,
PasswordStoreChangeListReply callback) {
- main_backend_->AddLoginAsync(form, std::move(callback));
- // TODO(crbug.com/1229655): Request shadow_backend_ and compare results.
+ auto handler = base::MakeRefCounted<
+ ShadowTrafficMetricsRecorder<PasswordStoreChangeListImpl>>(
+ MethodName("AddLoginAsync"));
+
+ main_backend_->AddLoginAsync(
+ form, base::BindOnce(&ShadowTrafficMetricsRecorder<
+ PasswordStoreChangeListImpl>::RecordMainResult,
+ handler)
+ .Then(std::move(callback)));
+ if (ShouldExecuteModifyOperationsOnShadowBackend(
+ prefs_, sync_delegate_->IsSyncingPasswordsEnabled())) {
+ shadow_backend_->AddLoginAsync(
+ form,
+ base::BindOnce(&ShadowTrafficMetricsRecorder<
+ PasswordStoreChangeListImpl>::RecordShadowResult,
+ handler));
+ }
}
void PasswordStoreProxyBackend::UpdateLoginAsync(
const PasswordForm& form,
PasswordStoreChangeListReply callback) {
- main_backend_->UpdateLoginAsync(form, std::move(callback));
- // TODO(crbug.com/1229655): Request shadow_backend_ and compare results.
+ auto handler = base::MakeRefCounted<
+ ShadowTrafficMetricsRecorder<PasswordStoreChangeListImpl>>(
+ MethodName("UpdateLoginAsync"));
+
+ main_backend_->UpdateLoginAsync(
+ form, base::BindOnce(&ShadowTrafficMetricsRecorder<
+ PasswordStoreChangeListImpl>::RecordMainResult,
+ handler)
+ .Then(std::move(callback)));
+ if (ShouldExecuteModifyOperationsOnShadowBackend(
+ prefs_, sync_delegate_->IsSyncingPasswordsEnabled())) {
+ shadow_backend_->UpdateLoginAsync(
+ form,
+ base::BindOnce(&ShadowTrafficMetricsRecorder<
+ PasswordStoreChangeListImpl>::RecordShadowResult,
+ handler));
+ }
}
void PasswordStoreProxyBackend::RemoveLoginAsync(
const PasswordForm& form,
PasswordStoreChangeListReply callback) {
- main_backend_->RemoveLoginAsync(form, std::move(callback));
- // TODO(crbug.com/1229655): Request shadow_backend_ and compare results.
+ auto handler = base::MakeRefCounted<
+ ShadowTrafficMetricsRecorder<PasswordStoreChangeListImpl>>(
+ MethodName("RemoveLoginAsync"));
+
+ main_backend_->RemoveLoginAsync(
+ form, base::BindOnce(&ShadowTrafficMetricsRecorder<
+ PasswordStoreChangeListImpl>::RecordMainResult,
+ handler)
+ .Then(std::move(callback)));
+ if (ShouldExecuteModifyOperationsOnShadowBackend(
+ prefs_, sync_delegate_->IsSyncingPasswordsEnabled())) {
+ shadow_backend_->RemoveLoginAsync(
+ form,
+ base::BindOnce(&ShadowTrafficMetricsRecorder<
+ PasswordStoreChangeListImpl>::RecordShadowResult,
+ handler));
+ }
}
void PasswordStoreProxyBackend::RemoveLoginsByURLAndTimeAsync(
@@ -266,19 +439,49 @@ void PasswordStoreProxyBackend::RemoveLoginsByURLAndTimeAsync(
base::Time delete_end,
base::OnceCallback<void(bool)> sync_completion,
PasswordStoreChangeListReply callback) {
+ auto handler = base::MakeRefCounted<
+ ShadowTrafficMetricsRecorder<PasswordStoreChangeListImpl>>(
+ MethodName("RemoveLoginsByURLAndTimeAsync"));
+
main_backend_->RemoveLoginsByURLAndTimeAsync(
- url_filter, std::move(delete_begin), std::move(delete_end),
- std::move(sync_completion), std::move(callback));
- // TODO(crbug.com/1229655): Request shadow_backend_ and compare results.
+ url_filter, delete_begin, delete_end, std::move(sync_completion),
+ base::BindOnce(&ShadowTrafficMetricsRecorder<
+ PasswordStoreChangeListImpl>::RecordMainResult,
+ handler)
+ .Then(std::move(callback)));
+ if (ShouldExecuteModifyOperationsOnShadowBackend(
+ prefs_, sync_delegate_->IsSyncingPasswordsEnabled())) {
+ shadow_backend_->RemoveLoginsByURLAndTimeAsync(
+ url_filter, std::move(delete_begin), std::move(delete_end),
+ base::OnceCallback<void(bool)>(),
+ base::BindOnce(&ShadowTrafficMetricsRecorder<
+ PasswordStoreChangeListImpl>::RecordShadowResult,
+ handler));
+ }
}
void PasswordStoreProxyBackend::RemoveLoginsCreatedBetweenAsync(
base::Time delete_begin,
base::Time delete_end,
PasswordStoreChangeListReply callback) {
+ auto handler = base::MakeRefCounted<
+ ShadowTrafficMetricsRecorder<PasswordStoreChangeListImpl>>(
+ MethodName("RemoveLoginsCreatedBetweenAsync"));
+
main_backend_->RemoveLoginsCreatedBetweenAsync(
- std::move(delete_begin), std::move(delete_end), std::move(callback));
- // TODO(crbug.com/1229655): Request shadow_backend_ and compare results.
+ delete_begin, delete_end,
+ base::BindOnce(&ShadowTrafficMetricsRecorder<
+ PasswordStoreChangeListImpl>::RecordMainResult,
+ handler)
+ .Then(std::move(callback)));
+ if (ShouldExecuteModifyOperationsOnShadowBackend(
+ prefs_, sync_delegate_->IsSyncingPasswordsEnabled())) {
+ shadow_backend_->RemoveLoginsCreatedBetweenAsync(
+ std::move(delete_begin), std::move(delete_end),
+ base::BindOnce(&ShadowTrafficMetricsRecorder<
+ PasswordStoreChangeListImpl>::RecordShadowResult,
+ handler));
+ }
}
void PasswordStoreProxyBackend::DisableAutoSignInForOriginsAsync(
@@ -286,7 +489,12 @@ void PasswordStoreProxyBackend::DisableAutoSignInForOriginsAsync(
base::OnceClosure completion) {
main_backend_->DisableAutoSignInForOriginsAsync(origin_filter,
std::move(completion));
- // TODO(crbug.com/1229655): Request shadow_backend_ and compare results.
+ if (ShouldExecuteModifyOperationsOnShadowBackend(
+ prefs_, sync_delegate_->IsSyncingPasswordsEnabled())) {
+ shadow_backend_->DisableAutoSignInForOriginsAsync(
+ origin_filter,
+ /*completion=*/base::DoNothing());
+ }
}
SmartBubbleStatsStore* PasswordStoreProxyBackend::GetSmartBubbleStatsStore() {
@@ -302,4 +510,8 @@ PasswordStoreProxyBackend::CreateSyncControllerDelegate() {
return main_backend_->CreateSyncControllerDelegate();
}
+void PasswordStoreProxyBackend::ClearAllLocalPasswords() {
+ NOTIMPLEMENTED();
+}
+
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/password_store_proxy_backend.h b/chromium/components/password_manager/core/browser/password_store_proxy_backend.h
index 0724074ebe5..ab46ed8920d 100644
--- a/chromium/components/password_manager/core/browser/password_store_proxy_backend.h
+++ b/chromium/components/password_manager/core/browser/password_store_proxy_backend.h
@@ -12,6 +12,8 @@
#include "base/memory/weak_ptr.h"
#include "components/password_manager/core/browser/password_store_backend.h"
+class PrefService;
+
namespace password_manager {
// This backend forwards requests to two backends in order to compare and record
@@ -21,10 +23,10 @@ class PasswordStoreProxyBackend : public PasswordStoreBackend {
public:
// `main_backend` and `shadow_backend` must not be null and must outlive this
// object as long as Shutdown() is not called.
- PasswordStoreProxyBackend(
- PasswordStoreBackend* main_backend,
- PasswordStoreBackend* shadow_backend,
- base::RepeatingCallback<bool()> is_syncing_passwords_callback);
+ PasswordStoreProxyBackend(PasswordStoreBackend* main_backend,
+ PasswordStoreBackend* shadow_backend,
+ PrefService* prefs,
+ SyncDelegate* sync_delegate);
PasswordStoreProxyBackend(const PasswordStoreProxyBackend&) = delete;
PasswordStoreProxyBackend(PasswordStoreProxyBackend&&) = delete;
PasswordStoreProxyBackend& operator=(const PasswordStoreProxyBackend&) =
@@ -34,7 +36,6 @@ class PasswordStoreProxyBackend : public PasswordStoreBackend {
private:
// Implements PasswordStoreBackend interface.
- base::WeakPtr<PasswordStoreBackend> GetWeakPtr() override;
void InitBackend(RemoteChangesReceived remote_form_changes_received,
base::RepeatingClosure sync_enabled_or_disabled_cb,
base::OnceCallback<void(bool)> completion) override;
@@ -68,11 +69,12 @@ class PasswordStoreProxyBackend : public PasswordStoreBackend {
FieldInfoStore* GetFieldInfoStore() override;
std::unique_ptr<syncer::ProxyModelTypeControllerDelegate>
CreateSyncControllerDelegate() override;
+ void ClearAllLocalPasswords() override;
const raw_ptr<PasswordStoreBackend> main_backend_;
const raw_ptr<PasswordStoreBackend> shadow_backend_;
- base::RepeatingCallback<bool()> is_syncing_passwords_callback_;
- base::WeakPtrFactory<PasswordStoreProxyBackend> weak_ptr_factory_{this};
+ raw_ptr<PrefService> const prefs_ = nullptr;
+ const raw_ptr<SyncDelegate> sync_delegate_;
};
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/password_store_proxy_backend_unittest.cc b/chromium/components/password_manager/core/browser/password_store_proxy_backend_unittest.cc
index cd6e7fbb2e0..471be6529bc 100644
--- a/chromium/components/password_manager/core/browser/password_store_proxy_backend_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_store_proxy_backend_unittest.cc
@@ -18,6 +18,9 @@
#include "components/password_manager/core/browser/password_manager_test_utils.h"
#include "components/password_manager/core/browser/password_store_change.h"
#include "components/password_manager/core/common/password_manager_features.h"
+#include "components/password_manager/core/common/password_manager_pref_names.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/testing_pref_service.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
@@ -26,6 +29,7 @@ namespace password_manager {
namespace {
using ::testing::_;
+using ::testing::AnyNumber;
using ::testing::AtMost;
using ::testing::Eq;
using ::testing::Invoke;
@@ -68,10 +72,16 @@ class PasswordStoreProxyBackendTest : public testing::Test {
protected:
PasswordStoreProxyBackendTest() {
proxy_backend_ = std::make_unique<PasswordStoreProxyBackend>(
- &main_backend_, &shadow_backend_, is_syncing_passwords_callback_.Get());
+ &main_backend_, &shadow_backend_, &prefs_, &sync_delegate_);
- feature_list_.InitAndEnableFeature(
- features::kUnifiedPasswordManagerShadowAndroid);
+ feature_list_.InitWithFeatures(
+ /*enabled_features=*/
+ {features::kUnifiedPasswordManagerShadowAndroid,
+ features::kUnifiedPasswordManagerShadowWriteOperationsAndroid},
+ /*disabled_features=*/{});
+
+ prefs_.registry()->RegisterIntegerPref(
+ prefs::kCurrentMigrationVersionToGoogleMobileServices, 0);
}
void TearDown() override {
@@ -82,16 +92,17 @@ class PasswordStoreProxyBackendTest : public testing::Test {
proxy_backend_.reset();
}
+ MockPasswordBackendSyncDelegate& sync_delegate() { return sync_delegate_; }
PasswordStoreBackend& proxy_backend() { return *proxy_backend_; }
MockPasswordStoreBackend& main_backend() { return main_backend_; }
MockPasswordStoreBackend& shadow_backend() { return shadow_backend_; }
-
- base::MockCallback<base::RepeatingCallback<bool(void)>>
- is_syncing_passwords_callback_;
+ TestingPrefServiceSimple* prefs() { return &prefs_; }
private:
base::test::ScopedFeatureList feature_list_;
+ TestingPrefServiceSimple prefs_;
std::unique_ptr<PasswordStoreProxyBackend> proxy_backend_;
+ testing::NiceMock<MockPasswordBackendSyncDelegate> sync_delegate_;
StrictMock<MockPasswordStoreBackend> main_backend_;
StrictMock<MockPasswordStoreBackend> shadow_backend_;
};
@@ -144,11 +155,9 @@ TEST_F(PasswordStoreProxyBackendTest, UseMainBackendToGetAllLoginsAsync) {
.WillOnce(WithArg<0>(Invoke([](LoginsOrErrorReply reply) -> void {
std::move(reply).Run(CreateTestLogins());
})));
- EXPECT_CALL(is_syncing_passwords_callback_, Run).WillRepeatedly(Return(true));
- EXPECT_CALL(shadow_backend(), GetAllLoginsAsync)
- .WillOnce(WithArg<0>(Invoke([](LoginsOrErrorReply reply) -> void {
- std::move(reply).Run(CreateTestLogins());
- })));
+ EXPECT_CALL(sync_delegate(), IsSyncingPasswordsEnabled)
+ .WillRepeatedly(Return(true));
+ EXPECT_CALL(shadow_backend(), GetAllLoginsAsync);
proxy_backend().GetAllLoginsAsync(mock_reply.Get());
}
@@ -162,6 +171,9 @@ TEST_F(PasswordStoreProxyBackendTest,
.WillOnce(WithArg<0>(Invoke([](LoginsOrErrorReply reply) -> void {
std::move(reply).Run(CreateTestLogins());
})));
+ EXPECT_CALL(sync_delegate(), IsSyncingPasswordsEnabled)
+ .WillRepeatedly(Return(true));
+ EXPECT_CALL(shadow_backend(), GetAutofillableLoginsAsync);
proxy_backend().GetAutofillableLoginsAsync(mock_reply.Get());
}
@@ -175,6 +187,9 @@ TEST_F(PasswordStoreProxyBackendTest, UseMainBackendToFillMatchingLoginsAsync) {
.WillOnce(WithArg<0>(Invoke([](LoginsReply reply) -> void {
std::move(reply).Run(CreateTestLogins());
})));
+ EXPECT_CALL(sync_delegate(), IsSyncingPasswordsEnabled)
+ .WillRepeatedly(Return(true));
+ EXPECT_CALL(shadow_backend(), FillMatchingLoginsAsync);
proxy_backend().FillMatchingLoginsAsync(mock_reply.Get(),
/*include_psl=*/false,
std::vector<PasswordFormDigest>());
@@ -186,6 +201,8 @@ TEST_F(PasswordStoreProxyBackendTest, UseMainBackendToAddLoginAsync) {
PasswordStoreChangeList change_list;
change_list.push_back(PasswordStoreChange(Type::ADD, form));
EXPECT_CALL(mock_reply, Run(Eq(change_list)));
+ // This test doesn't care about the shadow backend.
+ EXPECT_CALL(shadow_backend(), AddLoginAsync).Times(AnyNumber());
EXPECT_CALL(main_backend(), AddLoginAsync(Eq(form), _))
.WillOnce(WithArg<1>(
Invoke([&change_list](PasswordStoreChangeListReply reply) -> void {
@@ -200,6 +217,8 @@ TEST_F(PasswordStoreProxyBackendTest, UseMainBackendToUpdateLoginAsync) {
PasswordStoreChangeList change_list;
change_list.push_back(PasswordStoreChange(Type::UPDATE, form));
EXPECT_CALL(mock_reply, Run(Eq(change_list)));
+ // This test doesn't care about the shadow backend.
+ EXPECT_CALL(shadow_backend(), UpdateLoginAsync).Times(AnyNumber());
EXPECT_CALL(main_backend(), UpdateLoginAsync(Eq(form), _))
.WillOnce(WithArg<1>(
Invoke([&change_list](PasswordStoreChangeListReply reply) -> void {
@@ -214,6 +233,8 @@ TEST_F(PasswordStoreProxyBackendTest, UseMainBackendToRemoveLoginAsync) {
PasswordStoreChangeList change_list;
change_list.push_back(PasswordStoreChange(Type::REMOVE, form));
EXPECT_CALL(mock_reply, Run(Eq(change_list)));
+ // This test doesn't care about the shadow backend.
+ EXPECT_CALL(shadow_backend(), RemoveLoginAsync).Times(AnyNumber());
EXPECT_CALL(main_backend(), RemoveLoginAsync(Eq(form), _))
.WillOnce(WithArg<1>(
Invoke([&change_list](PasswordStoreChangeListReply reply) -> void {
@@ -230,6 +251,9 @@ TEST_F(PasswordStoreProxyBackendTest,
PasswordStoreChangeList change_list;
change_list.push_back(PasswordStoreChange(Type::REMOVE, CreateTestForm()));
EXPECT_CALL(mock_reply, Run(Eq(change_list)));
+ // This test doesn't care about the shadow backend.
+ EXPECT_CALL(shadow_backend(), RemoveLoginsByURLAndTimeAsync)
+ .Times(AnyNumber());
EXPECT_CALL(main_backend(),
RemoveLoginsByURLAndTimeAsync(_, Eq(kStart), Eq(kEnd), _, _))
.WillOnce(WithArg<4>(
@@ -249,6 +273,9 @@ TEST_F(PasswordStoreProxyBackendTest,
PasswordStoreChangeList change_list;
change_list.push_back(PasswordStoreChange(Type::REMOVE, CreateTestForm()));
EXPECT_CALL(mock_reply, Run(Eq(change_list)));
+ // This test doesn't care about the shadow backend.
+ EXPECT_CALL(shadow_backend(), RemoveLoginsCreatedBetweenAsync)
+ .Times(AnyNumber());
EXPECT_CALL(main_backend(),
RemoveLoginsCreatedBetweenAsync(Eq(kStart), Eq(kEnd), _))
.WillOnce(WithArg<2>(
@@ -263,6 +290,9 @@ TEST_F(PasswordStoreProxyBackendTest,
UseMainBackendToDisableAutoSignInForOriginsAsync) {
base::MockCallback<base::OnceClosure> mock_reply;
EXPECT_CALL(mock_reply, Run);
+ // This test doesn't care about the shadow backend.
+ EXPECT_CALL(shadow_backend(), DisableAutoSignInForOriginsAsync)
+ .Times(AnyNumber());
EXPECT_CALL(main_backend(), DisableAutoSignInForOriginsAsync)
.WillOnce(WithArg<1>(
Invoke([](base::OnceClosure reply) { std::move(reply).Run(); })));
@@ -287,7 +317,15 @@ TEST_F(PasswordStoreProxyBackendTest,
proxy_backend().CreateSyncControllerDelegate();
}
-TEST_F(PasswordStoreProxyBackendTest, NoShadowGetAllLoginsWhenSyncDisabled) {
+TEST_F(PasswordStoreProxyBackendTest,
+ NoShadowGetAllLoginsAsyncWithoutSyncOrMigration) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitWithFeaturesAndParameters(
+ /*enabled_features=*/{{features::kUnifiedPasswordManagerMigration,
+ {{"migration_version", "2"}}}},
+ /*disabled_features=*/{});
+ prefs()->SetInteger(prefs::kCurrentMigrationVersionToGoogleMobileServices, 1);
+
base::HistogramTester histogram_tester;
base::MockCallback<LoginsOrErrorReply> mock_reply;
std::vector<std::unique_ptr<PasswordForm>> expected_logins =
@@ -297,7 +335,7 @@ TEST_F(PasswordStoreProxyBackendTest, NoShadowGetAllLoginsWhenSyncDisabled) {
.WillOnce(WithArg<0>(Invoke([](LoginsOrErrorReply reply) -> void {
std::move(reply).Run(CreateTestLogins());
})));
- EXPECT_CALL(is_syncing_passwords_callback_, Run)
+ EXPECT_CALL(sync_delegate(), IsSyncingPasswordsEnabled)
.WillRepeatedly(Return(false));
EXPECT_CALL(shadow_backend(), GetAllLoginsAsync).Times(0);
proxy_backend().GetAllLoginsAsync(mock_reply.Get());
@@ -315,6 +353,428 @@ TEST_F(PasswordStoreProxyBackendTest, NoShadowGetAllLoginsWhenSyncDisabled) {
histogram_tester.ExpectTotalCount(prefix + "InconsistentPasswords.Rel", 0);
}
+TEST_F(PasswordStoreProxyBackendTest,
+ NoShadowGetAutofillableLoginsAsyncWithoutSyncOrMigration) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitWithFeaturesAndParameters(
+ /*enabled_features=*/{{features::kUnifiedPasswordManagerMigration,
+ {{"migration_version", "2"}}}},
+ /*disabled_features=*/{});
+ prefs()->SetInteger(prefs::kCurrentMigrationVersionToGoogleMobileServices, 1);
+ EXPECT_CALL(sync_delegate(), IsSyncingPasswordsEnabled)
+ .WillRepeatedly(Return(false));
+
+ EXPECT_CALL(main_backend(), GetAutofillableLoginsAsync);
+ EXPECT_CALL(shadow_backend(), GetAutofillableLoginsAsync).Times(0);
+ proxy_backend().GetAutofillableLoginsAsync(/*callback=*/base::DoNothing());
+}
+
+TEST_F(PasswordStoreProxyBackendTest,
+ NoShadowFillMatchingLoginsAsyncWithoutSyncOrMigration) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitWithFeaturesAndParameters(
+ /*enabled_features=*/{{features::kUnifiedPasswordManagerMigration,
+ {{"migration_version", "2"}}}},
+ /*disabled_features=*/{});
+ prefs()->SetInteger(prefs::kCurrentMigrationVersionToGoogleMobileServices, 1);
+ EXPECT_CALL(sync_delegate(), IsSyncingPasswordsEnabled)
+ .WillRepeatedly(Return(false));
+
+ EXPECT_CALL(main_backend(), FillMatchingLoginsAsync);
+ EXPECT_CALL(shadow_backend(), FillMatchingLoginsAsync).Times(0);
+ proxy_backend().FillMatchingLoginsAsync(/*callback=*/base::DoNothing(),
+ /*include_psl=*/false,
+ std::vector<PasswordFormDigest>());
+}
+
+TEST_F(PasswordStoreProxyBackendTest, NoShadowAddLoginAsyncWhenSyncEnabled) {
+ EXPECT_CALL(sync_delegate(), IsSyncingPasswordsEnabled)
+ .WillRepeatedly(Return(true));
+
+ EXPECT_CALL(main_backend(), AddLoginAsync);
+ EXPECT_CALL(shadow_backend(), AddLoginAsync).Times(0);
+ proxy_backend().AddLoginAsync(CreateTestForm(),
+ /*callback=*/base::DoNothing());
+}
+
+TEST_F(PasswordStoreProxyBackendTest,
+ NoShadowAddLoginAsyncWhenSyncDisabledAndInitialMigrationIncomplete) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitWithFeaturesAndParameters(
+ /*enabled_features=*/{{features::kUnifiedPasswordManagerMigration,
+ {{"migration_version", "2"}}}},
+ /*disabled_features=*/{});
+ prefs()->SetInteger(prefs::kCurrentMigrationVersionToGoogleMobileServices, 1);
+
+ EXPECT_CALL(sync_delegate(), IsSyncingPasswordsEnabled)
+ .WillRepeatedly(Return(false));
+
+ EXPECT_CALL(main_backend(), AddLoginAsync);
+ EXPECT_CALL(shadow_backend(), AddLoginAsync).Times(0);
+ proxy_backend().AddLoginAsync(CreateTestForm(),
+ /*callback=*/base::DoNothing());
+}
+
+TEST_F(PasswordStoreProxyBackendTest,
+ ShadowAddLoginAsyncWhenSyncDisabledAndInitialMigrationComplete) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitWithFeaturesAndParameters(
+ /*enabled_features=*/{{features::kUnifiedPasswordManagerMigration,
+ {{"migration_version", "2"}}}},
+ /*disabled_features=*/{});
+ prefs()->SetInteger(prefs::kCurrentMigrationVersionToGoogleMobileServices, 2);
+
+ EXPECT_CALL(sync_delegate(), IsSyncingPasswordsEnabled)
+ .WillRepeatedly(Return(false));
+
+ EXPECT_CALL(main_backend(), AddLoginAsync);
+ EXPECT_CALL(shadow_backend(), AddLoginAsync);
+ proxy_backend().AddLoginAsync(CreateTestForm(),
+ /*callback=*/base::DoNothing());
+}
+
+TEST_F(PasswordStoreProxyBackendTest, ShadowAddLoginAsyncBasicMetricsTesting) {
+ base::HistogramTester histogram_tester;
+ // Set the prefs such that no initial migration is required to allow shadow
+ // write operations.
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitWithFeaturesAndParameters(
+ /*enabled_features=*/{{features::kUnifiedPasswordManagerMigration,
+ {{"migration_version", "2"}}}},
+ /*disabled_features=*/{});
+ prefs()->SetInteger(prefs::kCurrentMigrationVersionToGoogleMobileServices, 2);
+ // Shadow write operations run only for non-syncing users.
+ EXPECT_CALL(sync_delegate(), IsSyncingPasswordsEnabled)
+ .WillRepeatedly(Return(false));
+
+ PasswordForm test_form = CreateTestForm();
+
+ PasswordStoreChangeList main_backend_changelist;
+ main_backend_changelist.emplace_back(PasswordStoreChange::ADD, test_form);
+
+ PasswordStoreChangeList shadow_backend_changelist;
+ shadow_backend_changelist.emplace_back(PasswordStoreChange::UPDATE,
+ test_form);
+
+ EXPECT_CALL(main_backend(), AddLoginAsync)
+ .WillOnce(WithArg<1>(Invoke(
+ [&main_backend_changelist](PasswordStoreChangeListReply reply)
+ -> void { std::move(reply).Run(main_backend_changelist); })));
+
+ EXPECT_CALL(shadow_backend(), AddLoginAsync)
+ .WillOnce(WithArg<1>(Invoke(
+ [&shadow_backend_changelist](PasswordStoreChangeListReply reply)
+ -> void { std::move(reply).Run(shadow_backend_changelist); })));
+
+ proxy_backend().AddLoginAsync(test_form,
+ /*callback=*/base::DoNothing());
+
+ std::string prefix =
+ "PasswordManager.PasswordStoreProxyBackend.AddLoginAsync.";
+
+ histogram_tester.ExpectUniqueSample(prefix + "Diff.Abs", 2, 1);
+ histogram_tester.ExpectUniqueSample(prefix + "MainMinusShadow.Abs", 1, 1);
+ histogram_tester.ExpectUniqueSample(prefix + "ShadowMinusMain.Abs", 1, 1);
+ histogram_tester.ExpectUniqueSample(prefix + "InconsistentPasswords.Abs", 0,
+ 1);
+}
+
+TEST_F(PasswordStoreProxyBackendTest, NoShadowUpdateLoginAsyncWhenSyncEnabled) {
+ EXPECT_CALL(sync_delegate(), IsSyncingPasswordsEnabled)
+ .WillRepeatedly(Return(true));
+
+ EXPECT_CALL(main_backend(), UpdateLoginAsync);
+ EXPECT_CALL(shadow_backend(), UpdateLoginAsync).Times(0);
+ proxy_backend().UpdateLoginAsync(CreateTestForm(),
+ /*callback=*/base::DoNothing());
+}
+
+TEST_F(PasswordStoreProxyBackendTest,
+ NoShadowUpdateLoginAsyncWhenSyncDisabledAndInitialMigrationIncomplete) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitWithFeaturesAndParameters(
+ /*enabled_features=*/{{features::kUnifiedPasswordManagerMigration,
+ {{"migration_version", "2"}}}},
+ /*disabled_features=*/{});
+ prefs()->SetInteger(prefs::kCurrentMigrationVersionToGoogleMobileServices, 1);
+
+ EXPECT_CALL(sync_delegate(), IsSyncingPasswordsEnabled)
+ .WillRepeatedly(Return(false));
+
+ EXPECT_CALL(main_backend(), UpdateLoginAsync);
+ EXPECT_CALL(shadow_backend(), UpdateLoginAsync).Times(0);
+ proxy_backend().UpdateLoginAsync(CreateTestForm(),
+ /*callback=*/base::DoNothing());
+}
+
+TEST_F(PasswordStoreProxyBackendTest,
+ ShadowGetAllLoginsAsyncWhenSyncDisabledAndInitialMigrationComplete) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitWithFeaturesAndParameters(
+ /*enabled_features=*/{{features::kUnifiedPasswordManagerMigration,
+ {{"migration_version", "2"}}}},
+ /*disabled_features=*/{});
+ prefs()->SetInteger(prefs::kCurrentMigrationVersionToGoogleMobileServices, 2);
+ EXPECT_CALL(sync_delegate(), IsSyncingPasswordsEnabled)
+ .WillRepeatedly(Return(false));
+
+ base::HistogramTester histogram_tester;
+ base::MockCallback<LoginsOrErrorReply> mock_reply;
+ std::vector<std::unique_ptr<PasswordForm>> expected_logins =
+ CreateTestLogins();
+ EXPECT_CALL(mock_reply, Run(LoginsResultsOrErrorAre(&expected_logins)));
+ EXPECT_CALL(main_backend(), GetAllLoginsAsync)
+ .WillOnce(WithArg<0>(Invoke([](LoginsOrErrorReply reply) -> void {
+ std::move(reply).Run(CreateTestLogins());
+ })));
+ EXPECT_CALL(shadow_backend(), GetAllLoginsAsync)
+ .WillOnce(WithArg<0>(Invoke([](LoginsOrErrorReply reply) -> void {
+ std::move(reply).Run(CreateTestLogins());
+ })));
+ proxy_backend().GetAllLoginsAsync(mock_reply.Get());
+
+ std::string prefix =
+ "PasswordManager.PasswordStoreProxyBackend.GetAllLoginsAsync.";
+
+ histogram_tester.ExpectTotalCount(prefix + "Diff.Abs", 1);
+ histogram_tester.ExpectTotalCount(prefix + "MainMinusShadow.Abs", 1);
+ histogram_tester.ExpectTotalCount(prefix + "ShadowMinusMain.Abs", 1);
+ histogram_tester.ExpectTotalCount(prefix + "InconsistentPasswords.Abs", 1);
+ histogram_tester.ExpectTotalCount(prefix + "Diff.Rel", 1);
+ histogram_tester.ExpectTotalCount(prefix + "MainMinusShadow.Rel", 1);
+ histogram_tester.ExpectTotalCount(prefix + "ShadowMinusMain.Rel", 1);
+ histogram_tester.ExpectTotalCount(prefix + "InconsistentPasswords.Rel", 1);
+}
+
+TEST_F(PasswordStoreProxyBackendTest,
+ ShadowUpdateLoginAsyncWhenSyncDisabledAndInitialMigrationComplete) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitWithFeaturesAndParameters(
+ /*enabled_features=*/{{features::kUnifiedPasswordManagerMigration,
+ {{"migration_version", "2"}}}},
+ /*disabled_features=*/{});
+ prefs()->SetInteger(prefs::kCurrentMigrationVersionToGoogleMobileServices, 2);
+
+ EXPECT_CALL(sync_delegate(), IsSyncingPasswordsEnabled)
+ .WillRepeatedly(Return(false));
+
+ EXPECT_CALL(main_backend(), UpdateLoginAsync);
+ EXPECT_CALL(shadow_backend(), UpdateLoginAsync);
+ proxy_backend().UpdateLoginAsync(CreateTestForm(),
+ /*callback=*/base::DoNothing());
+}
+
+TEST_F(PasswordStoreProxyBackendTest, NoShadowRemoveLoginAsyncWhenSyncEnabled) {
+ EXPECT_CALL(sync_delegate(), IsSyncingPasswordsEnabled)
+ .WillRepeatedly(Return(true));
+
+ EXPECT_CALL(main_backend(), RemoveLoginAsync);
+ EXPECT_CALL(shadow_backend(), RemoveLoginAsync).Times(0);
+ proxy_backend().RemoveLoginAsync(CreateTestForm(),
+ /*callback=*/base::DoNothing());
+}
+
+TEST_F(PasswordStoreProxyBackendTest,
+ NoShadowRemoveLoginAsyncWhenSyncDisabledAndInitialMigrationIncomplete) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitWithFeaturesAndParameters(
+ /*enabled_features=*/{{features::kUnifiedPasswordManagerMigration,
+ {{"migration_version", "2"}}}},
+ /*disabled_features=*/{});
+ prefs()->SetInteger(prefs::kCurrentMigrationVersionToGoogleMobileServices, 1);
+
+ EXPECT_CALL(sync_delegate(), IsSyncingPasswordsEnabled)
+ .WillRepeatedly(Return(false));
+
+ EXPECT_CALL(main_backend(), RemoveLoginAsync);
+ EXPECT_CALL(shadow_backend(), RemoveLoginAsync).Times(0);
+ proxy_backend().RemoveLoginAsync(CreateTestForm(),
+ /*callback=*/base::DoNothing());
+}
+
+TEST_F(PasswordStoreProxyBackendTest,
+ ShadowRemoveLoginAsyncWhenSyncDisabledAndInitialMigrationComplete) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitWithFeaturesAndParameters(
+ /*enabled_features=*/{{features::kUnifiedPasswordManagerMigration,
+ {{"migration_version", "2"}}}},
+ /*disabled_features=*/{});
+ prefs()->SetInteger(prefs::kCurrentMigrationVersionToGoogleMobileServices, 2);
+
+ EXPECT_CALL(sync_delegate(), IsSyncingPasswordsEnabled)
+ .WillRepeatedly(Return(false));
+
+ EXPECT_CALL(main_backend(), RemoveLoginAsync);
+ EXPECT_CALL(shadow_backend(), RemoveLoginAsync);
+ proxy_backend().RemoveLoginAsync(CreateTestForm(),
+ /*callback=*/base::DoNothing());
+}
+
+TEST_F(PasswordStoreProxyBackendTest,
+ NoShadowRemoveLoginsByURLAndTimeAsyncWhenSyncEnabled) {
+ EXPECT_CALL(sync_delegate(), IsSyncingPasswordsEnabled)
+ .WillRepeatedly(Return(true));
+
+ EXPECT_CALL(main_backend(), RemoveLoginsByURLAndTimeAsync);
+ EXPECT_CALL(shadow_backend(), RemoveLoginsByURLAndTimeAsync).Times(0);
+ proxy_backend().RemoveLoginsByURLAndTimeAsync(
+ base::BindRepeating(&FilterNoUrl),
+ /*delete_begin=*/base::Time::FromTimeT(111111),
+ /*delete_end=*/base::Time::FromTimeT(22222222),
+ /*sync_completion=*/base::OnceCallback<void(bool)>(),
+ /*callback=*/base::DoNothing());
+}
+
+TEST_F(
+ PasswordStoreProxyBackendTest,
+ NoShadowRemoveLoginsByURLAndTimeAsyncWhenSyncDisabledAndInitialMigrationIncomplete) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitWithFeaturesAndParameters(
+ /*enabled_features=*/{{features::kUnifiedPasswordManagerMigration,
+ {{"migration_version", "2"}}}},
+ /*disabled_features=*/{});
+ prefs()->SetInteger(prefs::kCurrentMigrationVersionToGoogleMobileServices, 1);
+
+ EXPECT_CALL(sync_delegate(), IsSyncingPasswordsEnabled)
+ .WillRepeatedly(Return(false));
+
+ EXPECT_CALL(main_backend(), RemoveLoginsByURLAndTimeAsync);
+ EXPECT_CALL(shadow_backend(), RemoveLoginsByURLAndTimeAsync).Times(0);
+ proxy_backend().RemoveLoginsByURLAndTimeAsync(
+ base::BindRepeating(&FilterNoUrl),
+ /*delete_begin=*/base::Time::FromTimeT(111111),
+ /*delete_end=*/base::Time::FromTimeT(22222222),
+ /*sync_completion=*/base::OnceCallback<void(bool)>(),
+ /*callback=*/base::DoNothing());
+}
+
+TEST_F(
+ PasswordStoreProxyBackendTest,
+ ShadowRemoveLoginsByURLAndTimeAsyncWhenSyncDisabledAndInitialMigrationComplete) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitWithFeaturesAndParameters(
+ /*enabled_features=*/{{features::kUnifiedPasswordManagerMigration,
+ {{"migration_version", "2"}}}},
+ /*disabled_features=*/{});
+ prefs()->SetInteger(prefs::kCurrentMigrationVersionToGoogleMobileServices, 2);
+
+ EXPECT_CALL(sync_delegate(), IsSyncingPasswordsEnabled)
+ .WillRepeatedly(Return(false));
+
+ EXPECT_CALL(main_backend(), RemoveLoginsByURLAndTimeAsync);
+ EXPECT_CALL(shadow_backend(), RemoveLoginsByURLAndTimeAsync);
+ proxy_backend().RemoveLoginsByURLAndTimeAsync(
+ base::BindRepeating(&FilterNoUrl),
+ /*delete_begin=*/base::Time::FromTimeT(111111),
+ /*delete_end=*/base::Time::FromTimeT(22222222),
+ /*sync_completion=*/base::OnceCallback<void(bool)>(),
+ /*callback=*/base::DoNothing());
+}
+
+TEST_F(PasswordStoreProxyBackendTest,
+ NoShadowRemoveLoginsCreatedBetweenAsyncWhenSyncEnabled) {
+ EXPECT_CALL(sync_delegate(), IsSyncingPasswordsEnabled)
+ .WillRepeatedly(Return(true));
+
+ EXPECT_CALL(main_backend(), RemoveLoginsCreatedBetweenAsync);
+ EXPECT_CALL(shadow_backend(), RemoveLoginsCreatedBetweenAsync).Times(0);
+ proxy_backend().RemoveLoginsCreatedBetweenAsync(
+ /*delete_begin=*/base::Time::FromTimeT(111111),
+ /*delete_end=*/base::Time::FromTimeT(22222222),
+ /*callback=*/base::DoNothing());
+}
+
+TEST_F(
+ PasswordStoreProxyBackendTest,
+ NoShadowRemoveLoginsCreatedBetweenAsyncWhenSyncDisabledAndInitialMigrationIncomplete) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitWithFeaturesAndParameters(
+ /*enabled_features=*/{{features::kUnifiedPasswordManagerMigration,
+ {{"migration_version", "2"}}}},
+ /*disabled_features=*/{});
+ prefs()->SetInteger(prefs::kCurrentMigrationVersionToGoogleMobileServices, 1);
+
+ EXPECT_CALL(sync_delegate(), IsSyncingPasswordsEnabled)
+ .WillRepeatedly(Return(false));
+
+ EXPECT_CALL(main_backend(), RemoveLoginsCreatedBetweenAsync);
+ EXPECT_CALL(shadow_backend(), RemoveLoginsCreatedBetweenAsync).Times(0);
+ proxy_backend().RemoveLoginsCreatedBetweenAsync(
+ /*delete_begin=*/base::Time::FromTimeT(111111),
+ /*delete_end=*/base::Time::FromTimeT(22222222),
+ /*callback=*/base::DoNothing());
+}
+
+TEST_F(
+ PasswordStoreProxyBackendTest,
+ ShadowRemoveLoginsCreatedBetweenAsyncWhenSyncDisabledAndInitialMigrationComplete) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitWithFeaturesAndParameters(
+ /*enabled_features=*/{{features::kUnifiedPasswordManagerMigration,
+ {{"migration_version", "2"}}}},
+ /*disabled_features=*/{});
+ prefs()->SetInteger(prefs::kCurrentMigrationVersionToGoogleMobileServices, 2);
+
+ EXPECT_CALL(sync_delegate(), IsSyncingPasswordsEnabled)
+ .WillRepeatedly(Return(false));
+
+ EXPECT_CALL(main_backend(), RemoveLoginsCreatedBetweenAsync);
+ EXPECT_CALL(shadow_backend(), RemoveLoginsCreatedBetweenAsync);
+ proxy_backend().RemoveLoginsCreatedBetweenAsync(
+ /*delete_begin=*/base::Time::FromTimeT(111111),
+ /*delete_end=*/base::Time::FromTimeT(22222222),
+ /*callback=*/base::DoNothing());
+}
+
+TEST_F(PasswordStoreProxyBackendTest,
+ NoShadowDisableAutoSignInForOriginsAsyncWhenSyncEnabled) {
+ EXPECT_CALL(sync_delegate(), IsSyncingPasswordsEnabled)
+ .WillRepeatedly(Return(true));
+
+ EXPECT_CALL(main_backend(), DisableAutoSignInForOriginsAsync);
+ EXPECT_CALL(shadow_backend(), DisableAutoSignInForOriginsAsync).Times(0);
+ proxy_backend().DisableAutoSignInForOriginsAsync(
+ base::BindRepeating(&FilterNoUrl), /*completion=*/base::DoNothing());
+}
+
+TEST_F(
+ PasswordStoreProxyBackendTest,
+ NoShadowDisableAutoSignInForOriginsAsyncWhenSyncDisabledAndInitialMigrationIncomplete) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitWithFeaturesAndParameters(
+ /*enabled_features=*/{{features::kUnifiedPasswordManagerMigration,
+ {{"migration_version", "2"}}}},
+ /*disabled_features=*/{});
+ prefs()->SetInteger(prefs::kCurrentMigrationVersionToGoogleMobileServices, 1);
+
+ EXPECT_CALL(sync_delegate(), IsSyncingPasswordsEnabled)
+ .WillRepeatedly(Return(false));
+
+ EXPECT_CALL(main_backend(), DisableAutoSignInForOriginsAsync);
+ EXPECT_CALL(shadow_backend(), DisableAutoSignInForOriginsAsync).Times(0);
+ proxy_backend().DisableAutoSignInForOriginsAsync(
+ base::BindRepeating(&FilterNoUrl), /*completion=*/base::DoNothing());
+}
+
+TEST_F(
+ PasswordStoreProxyBackendTest,
+ ShadowDisableAutoSignInForOriginsAsyncWhenSyncDisabledAndInitialMigrationComplete) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitWithFeaturesAndParameters(
+ /*enabled_features=*/{{features::kUnifiedPasswordManagerMigration,
+ {{"migration_version", "2"}}}},
+ /*disabled_features=*/{});
+ prefs()->SetInteger(prefs::kCurrentMigrationVersionToGoogleMobileServices, 2);
+
+ EXPECT_CALL(sync_delegate(), IsSyncingPasswordsEnabled)
+ .WillRepeatedly(Return(false));
+
+ EXPECT_CALL(main_backend(), DisableAutoSignInForOriginsAsync);
+ EXPECT_CALL(shadow_backend(), DisableAutoSignInForOriginsAsync);
+ proxy_backend().DisableAutoSignInForOriginsAsync(
+ base::BindRepeating(&FilterNoUrl), /*completion=*/base::DoNothing());
+}
+
// Holds the main and shadow backend's logins and the expected number of common
// and different logins.
struct LoginsMetricsParam {
@@ -368,7 +828,7 @@ TEST_P(PasswordStoreProxyBackendTestWithLoginsParams,
.WillOnce(WithArg<0>(Invoke([&p](LoginsOrErrorReply reply) -> void {
std::move(reply).Run(p.GetMainLogins());
})));
- EXPECT_CALL(is_syncing_passwords_callback_, Run)
+ EXPECT_CALL(sync_delegate(), IsSyncingPasswordsEnabled)
.WillRepeatedly(Return(true));
EXPECT_CALL(shadow_backend(), GetAllLoginsAsync)
.WillOnce(WithArg<0>(Invoke([&p](LoginsOrErrorReply reply) -> void {
diff --git a/chromium/components/password_manager/core/browser/password_store_signin_notifier_impl_unittest.cc b/chromium/components/password_manager/core/browser/password_store_signin_notifier_impl_unittest.cc
index d4ff4237faa..a9b3b90ebcd 100644
--- a/chromium/components/password_manager/core/browser/password_store_signin_notifier_impl_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_store_signin_notifier_impl_unittest.cc
@@ -61,7 +61,7 @@ TEST_F(PasswordStoreSigninNotifierImplTest, Unsubscribed) {
identity_test_env()->ClearPrimaryAccount();
}
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
// This test is excluded from iOS since iOS does not support multiple Google
// accounts. Checks that ClearGaiaPasswordHash() is called when a secondary
// account is removed.
@@ -92,7 +92,7 @@ TEST_F(PasswordStoreSigninNotifierImplTest, SignOutContentArea) {
identity_test_env()->ClearPrimaryAccount();
notifier.UnsubscribeFromSigninEvents();
}
-#endif // !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_IOS)
} // namespace
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/password_store_sync.h b/chromium/components/password_manager/core/browser/password_store_sync.h
index 6779498b9dc..8b9cbbb122f 100644
--- a/chromium/components/password_manager/core/browser/password_store_sync.h
+++ b/chromium/components/password_manager/core/browser/password_store_sync.h
@@ -9,7 +9,6 @@
#include <memory>
#include <vector>
-#include "base/compiler_specific.h"
#include "components/password_manager/core/browser/password_store_change.h"
#include "components/sync/model/sync_metadata_store.h"
@@ -41,7 +40,9 @@ enum class FormRetrievalResult {
kDbError,
// A service-level failure (e.g., on a platform using a keyring, the keyring
// is temporarily unavailable).
- kEncrytionServiceFailure,
+ kEncryptionServiceFailure,
+ // A service-level failure, but some forms can be retrieved successfully.
+ kEncryptionServiceFailureWithPartialData,
};
// Error values for adding a login to the store.
@@ -58,7 +59,7 @@ enum class AddLoginError {
kConstraintViolation = 2,
// A service-level failure (e.g., on a platform using a keyring, the keyring
// is temporarily unavailable).
- kEncrytionServiceFailure = 3,
+ kEncryptionServiceFailure = 3,
// Database error.
kDbError = 4,
@@ -79,7 +80,7 @@ enum class UpdateLoginError {
kNoUpdatedRecords = 2,
// A service-level failure (e.g., on a platform using a keyring, the keyring
// is temporarily unavailable).
- kEncrytionServiceFailure = 3,
+ kEncryptionServiceFailure = 3,
// Database error.
kDbError = 4,
@@ -122,8 +123,8 @@ class PasswordStoreSync {
// Overwrites |key_to_form_map| with a map from the DB primary key to the
// corresponding form for all stored credentials. Returns true on success.
- virtual FormRetrievalResult ReadAllLogins(
- PrimaryKeyToFormMap* key_to_form_map) WARN_UNUSED_RESULT = 0;
+ [[nodiscard]] virtual FormRetrievalResult ReadAllLogins(
+ PrimaryKeyToFormMap* key_to_form_map) = 0;
// Deletes logins that cannot be decrypted.
virtual DatabaseCleanupResult DeleteUndecryptableLogins() = 0;
diff --git a/chromium/components/password_manager/core/browser/password_store_unittest.cc b/chromium/components/password_manager/core/browser/password_store_unittest.cc
index 8ef91ede335..fec082da5d9 100644
--- a/chromium/components/password_manager/core/browser/password_store_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_store_unittest.cc
@@ -15,6 +15,7 @@
#include "base/strings/utf_string_conversions.h"
#include "base/synchronization/waitable_event.h"
#include "base/test/bind.h"
+#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "base/time/time.h"
@@ -24,6 +25,7 @@
#include "components/password_manager/core/browser/android_affiliation/mock_affiliated_match_helper.h"
#include "components/password_manager/core/browser/fake_password_store_backend.h"
#include "components/password_manager/core/browser/form_parsing/form_parser.h"
+#include "components/password_manager/core/browser/login_database.h"
#include "components/password_manager/core/browser/mock_password_store_backend.h"
#include "components/password_manager/core/browser/password_form.h"
#include "components/password_manager/core/browser/password_manager_test_utils.h"
@@ -49,8 +51,11 @@ using testing::_;
using testing::DoAll;
using testing::ElementsAre;
using testing::ElementsAreArray;
+using testing::Eq;
+using testing::Invoke;
using testing::IsEmpty;
using testing::Pointee;
+using testing::SizeIs;
using testing::UnorderedElementsAre;
using testing::WithArg;
@@ -121,64 +126,6 @@ class MockPasswordStoreConsumer : public PasswordStoreConsumer {
base::WeakPtrFactory<MockPasswordStoreConsumer> weak_ptr_factory_{this};
};
-class MockPasswordStoreSigninNotifier : public PasswordStoreSigninNotifier {
- public:
- MOCK_METHOD(void,
- SubscribeToSigninEvents,
- (PasswordReuseManager * manager),
- (override));
- MOCK_METHOD(void, UnsubscribeFromSigninEvents, (), (override));
-};
-
-class MockMetadataStore : public PasswordStoreSync::MetadataStore {
- public:
- MOCK_METHOD(void, DeleteAllSyncMetadata, (), (override));
- MOCK_METHOD(void,
- SetDeletionsHaveSyncedCallback,
- (base::RepeatingCallback<void(bool)> callback),
- (override));
- MOCK_METHOD(bool, HasUnsyncedDeletions, (), (override));
-
- std::unique_ptr<syncer::MetadataBatch> GetAllSyncMetadata() override {
- return std::make_unique<syncer::MetadataBatch>();
- }
-
- bool UpdateSyncMetadata(syncer::ModelType model_type,
- const std::string& storage_key,
- const sync_pb::EntityMetadata& metadata) override {
- return true;
- }
-
- bool ClearSyncMetadata(syncer::ModelType model_type,
- const std::string& storage_key) override {
- return true;
- }
-
- bool UpdateModelTypeState(
- syncer::ModelType model_type,
- const sync_pb::ModelTypeState& model_type_state) override {
- return true;
- }
-
- bool ClearModelTypeState(syncer::ModelType model_type) override {
- return true;
- }
-};
-
-class BackendImplWithMockedMetadataStore : public PasswordStoreBuiltInBackend {
- public:
- explicit BackendImplWithMockedMetadataStore(
- std::unique_ptr<LoginDatabase> login_database)
- : PasswordStoreBuiltInBackend(std::move(login_database)) {}
-
- PasswordStoreSync::MetadataStore* GetMetadataStore() override {
- return &metadata_store_;
- }
-
- private:
- MockMetadataStore metadata_store_;
-};
-
PasswordForm MakePasswordForm(const std::string& signon_realm) {
PasswordForm form;
form.url = GURL("http://www.origin.com");
@@ -193,6 +140,14 @@ bool MatchesOrigin(const GURL& origin, const GURL& url) {
return origin.DeprecatedGetOriginAsURL() == url.DeprecatedGetOriginAsURL();
}
+std::tuple<scoped_refptr<PasswordStore>, MockPasswordStoreBackend*>
+CreateUnownedStoreWithOwnedMockBackend() {
+ auto backend = std::make_unique<MockPasswordStoreBackend>();
+ MockPasswordStoreBackend* mock_backend = backend.get();
+ return std::make_tuple(
+ base::MakeRefCounted<PasswordStore>(std::move(backend)), mock_backend);
+}
+
PasswordFormData CreateTestPasswordFormDataByOrigin(const char* origin_url) {
PasswordFormData data = {PasswordForm::Scheme::kHtml,
origin_url,
@@ -208,6 +163,37 @@ PasswordFormData CreateTestPasswordFormDataByOrigin(const char* origin_url) {
return data;
}
+PasswordStoreChangeList CreateChangeList(PasswordStoreChange::Type type,
+ PasswordForm form) {
+ PasswordStoreChangeList changes;
+ changes.emplace_back(type, std::move(form));
+ return changes;
+}
+
+auto HasChangeType(PasswordStoreChange::Type type) {
+ return testing::Property(&PasswordStoreChange::type, Eq(type));
+}
+
+auto HasForm(const PasswordForm& form) {
+ return testing::Property(&PasswordStoreChange::form, Eq(form));
+}
+
+auto EqChange(PasswordStoreChange::Type type, const PasswordForm& form) {
+ return AllOf(HasChangeType(type), HasForm(form));
+}
+
+auto EqRemoval(const PasswordForm& form) {
+ return EqChange(PasswordStoreChange::REMOVE, form);
+}
+
+auto EqAddition(const PasswordForm& form) {
+ return EqChange(PasswordStoreChange::ADD, form);
+}
+
+auto EqUpdate(const PasswordForm& form) {
+ return EqChange(PasswordStoreChange::UPDATE, form);
+}
+
} // namespace
class PasswordStoreTest : public testing::Test {
@@ -245,14 +231,6 @@ class PasswordStoreTest : public testing::Test {
password_manager::IsAccountStore(false))));
}
- scoped_refptr<PasswordStore> CreatePasswordStoreWithMockedMetaData() {
- return base::MakeRefCounted<PasswordStore>(
- std::make_unique<BackendImplWithMockedMetadataStore>(
- std::make_unique<LoginDatabase>(
- test_login_db_file_path(),
- password_manager::IsAccountStore(false))));
- }
-
TestingPrefServiceSimple* pref_service() { return &pref_service_; }
protected:
@@ -1017,13 +995,7 @@ INSTANTIATE_TEST_SUITE_P(Federation,
testing::Bool());
TEST_F(PasswordStoreTest, DelegatesGetAllLoginsToBackend) {
- scoped_refptr<PasswordStore> store;
- MockPasswordStoreBackend* mock_backend;
- { // This scope ensures nobody tries to use `backend` after its move.
- auto backend = std::make_unique<MockPasswordStoreBackend>();
- mock_backend = backend.get();
- store = new PasswordStore(std::move(backend));
- }
+ auto [store, mock_backend] = CreateUnownedStoreWithOwnedMockBackend();
store->Init(/*prefs=*/nullptr, /*affiliated_match_helper=*/nullptr);
MockPasswordStoreConsumer mock_consumer;
@@ -1034,13 +1006,7 @@ TEST_F(PasswordStoreTest, DelegatesGetAllLoginsToBackend) {
}
TEST_F(PasswordStoreTest, DelegatesGetAutofillableLoginsToBackend) {
- scoped_refptr<PasswordStore> store;
- MockPasswordStoreBackend* mock_backend;
- { // This scope ensures nobody tries to use `backend` after its move.
- auto backend = std::make_unique<MockPasswordStoreBackend>();
- mock_backend = backend.get();
- store = new PasswordStore(std::move(backend));
- }
+ auto [store, mock_backend] = CreateUnownedStoreWithOwnedMockBackend();
store->Init(/*prefs=*/nullptr, /*affiliated_match_helper=*/nullptr);
MockPasswordStoreConsumer mock_consumer;
@@ -1050,6 +1016,161 @@ TEST_F(PasswordStoreTest, DelegatesGetAutofillableLoginsToBackend) {
store->ShutdownOnUIThread();
}
+TEST_F(PasswordStoreTest, CallOnLoginsChangedIfRemovalProvidesChanges) {
+ base::HistogramTester histogram_tester;
+ const char kOnLoginsChangedMetric[] =
+ "PasswordManager.PasswordStore.OnLoginsChanged";
+ const PasswordForm kTestForm = MakePasswordForm(kTestWebRealm1);
+ MockPasswordStoreObserver mock_observer;
+ auto [store, mock_backend] = CreateUnownedStoreWithOwnedMockBackend();
+ store->Init(/*prefs=*/nullptr, /*affiliated_match_helper=*/nullptr);
+ store->AddObserver(&mock_observer);
+
+ // Expect that observers receive the removal when the backend invokes the
+ // reply with a `PasswordStoreChangeList`.
+ EXPECT_CALL(*mock_backend, RemoveLoginAsync(Eq(kTestForm), _))
+ .WillOnce(
+ WithArg<1>(Invoke([&](PasswordStoreChangeListReply reply) -> void {
+ std::move(reply).Run(
+ CreateChangeList(PasswordStoreChange::REMOVE, kTestForm));
+ })));
+ EXPECT_CALL(mock_observer, OnLoginsRetained).Times(0);
+ EXPECT_CALL(mock_observer,
+ OnLoginsChanged(store.get(), ElementsAre(EqRemoval(kTestForm))));
+ store->RemoveLogin(kTestForm);
+ WaitForPasswordStore();
+ histogram_tester.ExpectTotalCount(kOnLoginsChangedMetric, 1);
+
+ store->RemoveObserver(&mock_observer);
+ store->ShutdownOnUIThread();
+}
+
+TEST_F(PasswordStoreTest, CallOnLoginsChangedIfAdditionProvidesChanges) {
+ const PasswordForm kTestForm = MakePasswordForm(kTestWebRealm1);
+ MockPasswordStoreObserver mock_observer;
+ auto [store, mock_backend] = CreateUnownedStoreWithOwnedMockBackend();
+ store->Init(/*prefs=*/nullptr, /*affiliated_match_helper=*/nullptr);
+ store->AddObserver(&mock_observer);
+
+ // Expect that observers receive the addition when the backend invokes the
+ // reply with a `PasswordStoreChangeList`.
+ EXPECT_CALL(*mock_backend, AddLoginAsync(Eq(kTestForm), _))
+ .WillOnce(
+ WithArg<1>(Invoke([&](PasswordStoreChangeListReply reply) -> void {
+ std::move(reply).Run(
+ CreateChangeList(PasswordStoreChange::ADD, kTestForm));
+ })));
+ EXPECT_CALL(mock_observer, OnLoginsRetained).Times(0);
+ EXPECT_CALL(mock_observer,
+ OnLoginsChanged(store.get(), ElementsAre(EqAddition(kTestForm))));
+ store->AddLogin(kTestForm);
+ WaitForPasswordStore();
+
+ store->RemoveObserver(&mock_observer);
+ store->ShutdownOnUIThread();
+}
+
+TEST_F(PasswordStoreTest, CallOnLoginsChangedIfUpdateProvidesChanges) {
+ const PasswordForm kTestForm = MakePasswordForm(kTestWebRealm1);
+ MockPasswordStoreObserver mock_observer;
+ auto [store, mock_backend] = CreateUnownedStoreWithOwnedMockBackend();
+ store->Init(/*prefs=*/nullptr, /*affiliated_match_helper=*/nullptr);
+ store->AddObserver(&mock_observer);
+
+ // Expect that observers receive the update when the backend invokes the
+ // reply with a `PasswordStoreChangeList`.
+ EXPECT_CALL(*mock_backend, UpdateLoginAsync(Eq(kTestForm), _))
+ .WillOnce(
+ WithArg<1>(Invoke([&](PasswordStoreChangeListReply reply) -> void {
+ std::move(reply).Run(
+ CreateChangeList(PasswordStoreChange::UPDATE, kTestForm));
+ })));
+ EXPECT_CALL(mock_observer, OnLoginsRetained).Times(0);
+ EXPECT_CALL(mock_observer,
+ OnLoginsChanged(store.get(), ElementsAre(EqUpdate(kTestForm))));
+ store->UpdateLogin(kTestForm);
+ WaitForPasswordStore();
+
+ store->RemoveObserver(&mock_observer);
+ store->ShutdownOnUIThread();
+}
+
+#if BUILDFLAG(IS_ANDROID)
+TEST_F(PasswordStoreTest, CallOnLoginsRetainedIfUpdateProvidesNoChanges) {
+ base::HistogramTester histogram_tester;
+ const char kOnLoginRetainedMetric[] =
+ "PasswordManager.PasswordStore.OnLoginsRetained";
+ std::vector<std::unique_ptr<PasswordForm>> all_credentials;
+ all_credentials.push_back(FillPasswordFormWithData(
+ CreateTestPasswordFormDataByOrigin(kTestWebRealm1)));
+ all_credentials.push_back(FillPasswordFormWithData(
+ CreateTestPasswordFormDataByOrigin(kTestAndroidRealm1)));
+ const PasswordForm kTestForm = *all_credentials[0];
+ const PasswordForm kOtherForm = *all_credentials[1];
+ MockPasswordStoreObserver mock_observer;
+ auto [store, mock_backend] = CreateUnownedStoreWithOwnedMockBackend();
+ store->Init(/*prefs=*/nullptr, /*affiliated_match_helper=*/nullptr);
+ store->AddObserver(&mock_observer);
+
+ // Expect that observers receive the full list if the backend invokes the
+ // reply with a nullopt.
+ EXPECT_CALL(*mock_backend, UpdateLoginAsync(Eq(kTestForm), _))
+ .WillOnce(
+ WithArg<1>(Invoke([](PasswordStoreChangeListReply reply) -> void {
+ std::move(reply).Run(absl::nullopt);
+ })));
+ EXPECT_CALL(*mock_backend, GetAllLoginsAsync(_))
+ .WillOnce(WithArg<0>(
+ Invoke([&all_credentials](LoginsOrErrorReply reply) -> void {
+ std::move(reply).Run(std::move(all_credentials));
+ })));
+ EXPECT_CALL(mock_observer, OnLoginsChanged).Times(0);
+ EXPECT_CALL(mock_observer,
+ OnLoginsRetained(store.get(),
+ UnorderedElementsAre(kTestForm, kOtherForm)));
+ store->UpdateLogin(kTestForm);
+ WaitForPasswordStore();
+
+ store->RemoveObserver(&mock_observer);
+ store->ShutdownOnUIThread();
+ histogram_tester.ExpectUniqueSample(kOnLoginRetainedMetric, /*Update*/ 2, 1);
+ histogram_tester.ExpectTotalCount(kOnLoginRetainedMetric, 1);
+}
+#endif // BUILDFLAG(IS_ANDROID)
+
+#if BUILDFLAG(IS_ANDROID)
+TEST_F(PasswordStoreTest, RecordsPotentialOnLoginsRetainedInvokations) {
+ base::HistogramTester histogram_tester;
+ const PasswordForm kTestForm = MakePasswordForm(kTestWebRealm1);
+ MockPasswordStoreObserver mock_observer;
+ auto [store, mock_backend] = CreateUnownedStoreWithOwnedMockBackend();
+ store->Init(/*prefs=*/nullptr, /*affiliated_match_helper=*/nullptr);
+ store->AddObserver(&mock_observer);
+
+ // A changelist will be returned, so `OnLoginsRetained` call is not issued.
+ // But the changelist is empty, so `OnLoginsChanged` is not issued either.
+ // Regardless, this is a case where `OnLoginsRetained` would be called if the
+ // GMS backend was active — therefore record the potential call.
+ EXPECT_CALL(*mock_backend, UpdateLoginAsync(Eq(kTestForm), _))
+ .WillOnce(
+ WithArg<1>(Invoke([](PasswordStoreChangeListReply reply) -> void {
+ std::move(reply).Run(PasswordStoreChangeList());
+ })));
+ EXPECT_CALL(mock_observer, OnLoginsRetained).Times(0);
+ EXPECT_CALL(mock_observer, OnLoginsChanged).Times(0);
+ store->UpdateLogin(kTestForm);
+ WaitForPasswordStore();
+
+ const char kOnLoginRetainedMetric[] =
+ "PasswordManager.PasswordStore.OnLoginsRetained";
+ histogram_tester.ExpectUniqueSample(kOnLoginRetainedMetric, /*Update*/ 2, 1);
+ histogram_tester.ExpectTotalCount(kOnLoginRetainedMetric, 1);
+
+ store->RemoveObserver(&mock_observer);
+ store->ShutdownOnUIThread();
+}
+#endif // BUILDFLAG(IS_ANDROID)
+
TEST_F(PasswordStoreTest, GetAllLogins) {
static constexpr PasswordFormData kTestCredentials[] = {
{PasswordForm::Scheme::kHtml, kTestAndroidRealm1, "", "", u"", u"", u"",
@@ -1090,13 +1211,7 @@ TEST_F(PasswordStoreTest, GetAllLogins) {
}
TEST_F(PasswordStoreTest, GetAllLoginsWithAffiliationAndBrandingInformation) {
- scoped_refptr<PasswordStore> store;
- MockPasswordStoreBackend* mock_backend;
- { // This scope ensures nobody tries to use `backend` after its move.
- auto backend = std::make_unique<MockPasswordStoreBackend>();
- mock_backend = backend.get();
- store = new PasswordStore(std::move(backend));
- }
+ auto [store, mock_backend] = CreateUnownedStoreWithOwnedMockBackend();
// Invoke the store initialization callback to initialize
// AffiliatedMatchHelper.
EXPECT_CALL(*mock_backend, InitBackend)
@@ -1160,7 +1275,6 @@ TEST_F(PasswordStoreTest, GetAllLoginsWithAffiliationAndBrandingInformation) {
EXPECT_CALL(mock_consumer,
OnGetPasswordStoreResultsConstRef(
UnorderedPasswordFormElementsAre(&expected_results)));
- LoginsOrErrorReply callback;
EXPECT_CALL(*mock_backend, GetAllLoginsAsync)
.WillOnce([&all_credentials](LoginsOrErrorReply callback) {
std::move(callback).Run(std::move(all_credentials));
@@ -1288,7 +1402,7 @@ TEST_F(PasswordStoreTest, RemoveInsecureCredentialsSyncOnUpdate) {
store->ShutdownOnUIThread();
}
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
// TODO(https://crbug.com/1051914): Enable on Android after making local
// heuristics reliable.
TEST_F(PasswordStoreTest, GetAllFieldInfo) {
@@ -1353,7 +1467,7 @@ TEST_F(PasswordStoreTest, RemoveFieldInfo) {
store->ShutdownOnUIThread();
}
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
TEST_F(PasswordStoreTest, TestGetLoginRequestCancelable) {
scoped_refptr<PasswordStore> store = CreatePasswordStore();
@@ -1384,7 +1498,7 @@ TEST_F(PasswordStoreTest, TestGetLoginRequestCancelable) {
}
TEST_F(PasswordStoreTest, TestUnblockListEmptyStore) {
- scoped_refptr<PasswordStore> store = CreatePasswordStoreWithMockedMetaData();
+ scoped_refptr<PasswordStore> store = CreatePasswordStore();
store->Init(/*prefs=*/nullptr, /*affiliated_match_helper=*/nullptr);
WaitForPasswordStore();
diff --git a/chromium/components/password_manager/core/browser/password_store_util.cc b/chromium/components/password_manager/core/browser/password_store_util.cc
index 186f56397a3..78a021b8c96 100644
--- a/chromium/components/password_manager/core/browser/password_store_util.cc
+++ b/chromium/components/password_manager/core/browser/password_store_util.cc
@@ -6,14 +6,32 @@
namespace password_manager {
-PasswordStoreChangeList JoinPasswordStoreChanges(
- std::vector<PasswordStoreChangeList> changes) {
+absl::optional<PasswordStoreChangeList> JoinPasswordStoreChanges(
+ std::vector<absl::optional<PasswordStoreChangeList>> changes) {
PasswordStoreChangeList joined_changes;
for (auto changes_list : changes) {
- std::move(changes_list.begin(), changes_list.end(),
+ if (!changes_list.has_value())
+ return absl::nullopt;
+ std::move(changes_list->begin(), changes_list->end(),
std::back_inserter(joined_changes));
}
return joined_changes;
}
+LoginsResult GetLoginsOrEmptyListOnFailure(LoginsResultOrError result) {
+ if (absl::holds_alternative<PasswordStoreBackendError>(result)) {
+ return {};
+ }
+ return std::move(absl::get<LoginsResult>(result));
+}
+
+PasswordStoreChangeListReply IgnoreChangeListAndRunCallback(
+ base::OnceClosure callback) {
+ return base::BindOnce(
+ [](base::OnceClosure callback, absl::optional<PasswordStoreChangeList>) {
+ std::move(callback).Run();
+ },
+ std::move(callback));
+}
+
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/password_store_util.h b/chromium/components/password_manager/core/browser/password_store_util.h
index 11a44f5e18a..346f08989db 100644
--- a/chromium/components/password_manager/core/browser/password_store_util.h
+++ b/chromium/components/password_manager/core/browser/password_store_util.h
@@ -7,15 +7,26 @@
#include <vector>
+#include "components/password_manager/core/browser/password_store_backend.h"
#include "components/password_manager/core/browser/password_store_change.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
namespace password_manager {
// Aggregates a vector of PasswordStoreChangeLists into a single
// PasswordStoreChangeList. Does not check for duplicate values.
-PasswordStoreChangeList JoinPasswordStoreChanges(
- std::vector<PasswordStoreChangeList> changes);
+absl::optional<PasswordStoreChangeList> JoinPasswordStoreChanges(
+ std::vector<absl::optional<PasswordStoreChangeList>> changes);
+
+// Returns logins if |result| holds them, or an empty list if |result|
+// holds an error.
+LoginsResult GetLoginsOrEmptyListOnFailure(LoginsResultOrError result);
+
+// Helper function allowing to bind base::OnceClosure to
+// PasswordStoreChangeListReply.
+PasswordStoreChangeListReply IgnoreChangeListAndRunCallback(
+ base::OnceClosure callback);
} // namespace password_manager
-#endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_STORE_UTIL_H_ \ No newline at end of file
+#endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_STORE_UTIL_H_
diff --git a/chromium/components/password_manager/core/browser/password_ui_utils_unittest.cc b/chromium/components/password_manager/core/browser/password_ui_utils_unittest.cc
index 78e5afc84e8..fb80f2b59d3 100644
--- a/chromium/components/password_manager/core/browser/password_ui_utils_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_ui_utils_unittest.cc
@@ -44,9 +44,7 @@ TEST(GetShownOriginAndLinkUrlTest, OriginFromAndroidForm_NoAppDisplayName) {
android_form.signon_realm = "android://hash@com.example.android";
android_form.app_display_name.clear();
- std::string shown_origin;
- GURL link_url;
- std::tie(shown_origin, link_url) = GetShownOriginAndLinkUrl(android_form);
+ auto [shown_origin, link_url] = GetShownOriginAndLinkUrl(android_form);
EXPECT_EQ("android.example.com", shown_origin);
EXPECT_EQ("https://play.google.com/store/apps/details?id=com.example.android",
@@ -58,9 +56,7 @@ TEST(GetShownOriginAndLinkUrlTest, OriginFromAndroidForm_WithAppDisplayName) {
android_form.signon_realm = "android://hash@com.example.android";
android_form.app_display_name = "Example Android App";
- std::string shown_origin;
- GURL link_url;
- std::tie(shown_origin, link_url) = GetShownOriginAndLinkUrl(android_form);
+ auto [shown_origin, link_url] = GetShownOriginAndLinkUrl(android_form);
EXPECT_EQ("Example Android App", shown_origin);
EXPECT_EQ("https://play.google.com/store/apps/details?id=com.example.android",
@@ -72,9 +68,7 @@ TEST(GetShownOriginAndLinkUrlTest, OriginFromNonAndroidForm) {
form.signon_realm = "https://example.com/";
form.url = GURL("https://example.com/login?ref=1");
- std::string shown_origin;
- GURL link_url;
- std::tie(shown_origin, link_url) = GetShownOriginAndLinkUrl(form);
+ auto [shown_origin, link_url] = GetShownOriginAndLinkUrl(form);
EXPECT_EQ("example.com", shown_origin);
EXPECT_EQ(GURL("https://example.com/login?ref=1"), link_url);
diff --git a/chromium/components/password_manager/core/browser/saved_passwords_capabilities_fetcher.cc b/chromium/components/password_manager/core/browser/saved_passwords_capabilities_fetcher.cc
new file mode 100644
index 00000000000..031c18cf32f
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/saved_passwords_capabilities_fetcher.cc
@@ -0,0 +1,284 @@
+// Copyright 2022 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.
+
+#include "components/password_manager/core/browser/saved_passwords_capabilities_fetcher.h"
+
+#include <algorithm>
+#include <iterator>
+#include <map>
+#include <memory>
+#include <vector>
+
+#include "base/containers/cxx20_erase.h"
+#include "base/logging.h"
+#include "base/metrics/histogram_functions.h"
+#include "base/scoped_observation.h"
+#include "base/stl_util.h"
+#include "components/password_manager/core/browser/password_store_interface.h"
+#include "components/password_manager/core/browser/ui/saved_passwords_presenter.h"
+#include "url/gurl.h"
+
+namespace password_manager {
+
+SavedPasswordsCapabilitiesFetcher::SavedPasswordsCapabilitiesFetcher(
+ std::unique_ptr<CapabilitiesService> fetcher,
+ scoped_refptr<password_manager::PasswordStoreInterface> password_store)
+ : fetcher_(std::move(fetcher)), saved_passwords_presenter_(password_store) {
+ observed_saved_password_presenter_.Observe(&saved_passwords_presenter_);
+ saved_passwords_presenter_.Init();
+}
+
+SavedPasswordsCapabilitiesFetcher::~SavedPasswordsCapabilitiesFetcher() =
+ default;
+
+void SavedPasswordsCapabilitiesFetcher::PrewarmCache() {
+ if (!is_cache_initialized_) {
+ should_refresh_cache_ = true;
+ return;
+ }
+
+ if (GetCacheState() == CacheState::kStale) {
+ FetchCapababilitiesForAllStoredOrigins();
+ }
+}
+
+void SavedPasswordsCapabilitiesFetcher::RefreshScriptsIfNecessary(
+ base::OnceClosure fetch_finished_callback) {
+ CacheState state = GetCacheState();
+
+ base::UmaHistogramEnumeration(
+ "PasswordManager.SavedPasswordsCapabilitiesFetcher.CacheState", state);
+
+ if (state == CacheState::kReady) {
+ std::move(fetch_finished_callback).Run();
+ return;
+ }
+
+ all_origins_callbacks_.emplace_back(std::move(fetch_finished_callback));
+
+ switch (state) {
+ case CacheState::kNeverSet:
+ should_refresh_cache_ = true;
+ break;
+ case CacheState::kWaiting:
+ // No new fetching.
+ break;
+ case CacheState::kStale:
+ FetchCapababilitiesForAllStoredOrigins();
+ break;
+ case CacheState::kReady:
+ NOTREACHED();
+ break;
+ }
+}
+
+void SavedPasswordsCapabilitiesFetcher::FetchScriptAvailability(
+ const url::Origin& origin,
+ ResponseCallback callback) {
+ if (!is_cache_initialized_ || refresh_in_process_) {
+ single_origin_callbacks_.emplace_back(origin, std::move(callback));
+ return;
+ }
+
+ auto domains_it = cache_.find(origin);
+ // Domain is present in the cache but stale.
+ if (domains_it != cache_.end() && domains_it->second.IsResultStale()) {
+ FetchCapababilitiesForSingleOrigin(origin, std::move(callback));
+ return;
+ }
+
+ std::move(callback).Run(IsScriptAvailable(origin));
+}
+
+bool SavedPasswordsCapabilitiesFetcher::IsScriptAvailable(
+ const url::Origin& origin) const {
+ auto domains_it = cache_.find(origin);
+ // Domain not present.
+ if (domains_it == cache_.end() || domains_it->second.IsResultStale()) {
+ return false;
+ }
+
+ return domains_it->second.has_script;
+}
+
+void SavedPasswordsCapabilitiesFetcher::OnEdited(const PasswordForm& form) {
+ // OnEdited() only gets called if a the password was edited via
+ // |saved_passwords_presenter_|, so even if the password gets edited
+ // elsewhere, we wouldn't end up here.
+ NOTREACHED();
+}
+
+void SavedPasswordsCapabilitiesFetcher::OnSavedPasswordsChanged(
+ SavedPasswordsPresenter::SavedPasswordsView passwords) {
+ if (is_cache_initialized_) {
+ // Request an update only if the updated set of passwords origins differ
+ // from the ones in cache.
+ std::vector<url::Origin> new_origins = GetOriginsOfStoredPasswords();
+ std::vector<url::Origin> cached_origins;
+ base::ranges::transform(cache_, std::back_inserter(cached_origins),
+ [](const auto& record) { return record.first; });
+
+ DCHECK(std::is_sorted(new_origins.begin(), new_origins.end()));
+ DCHECK(std::is_sorted(cached_origins.begin(), cached_origins.end()));
+ if (!base::ranges::equal(new_origins, cached_origins)) {
+ ReinitializeCache();
+ should_refresh_cache_ = true;
+ }
+ return;
+ }
+
+ ReinitializeCache();
+ is_cache_initialized_ = true;
+
+ if (should_refresh_cache_) {
+ // Fetch capabilities for all origins if refresh was requested. Once
+ // refresh is finished, any pending callbacks will be resolved.
+ FetchCapababilitiesForAllStoredOrigins();
+ } else {
+ // Answer any single-origin requests that might have come during
+ // initialization.
+ for (auto& [origin, callback] :
+ std::exchange(single_origin_callbacks_, {})) {
+ FetchCapababilitiesForSingleOrigin(std::move(origin),
+ std::move(callback));
+ }
+ }
+}
+
+void SavedPasswordsCapabilitiesFetcher::
+ FetchCapababilitiesForAllStoredOrigins() {
+ DCHECK(!refresh_in_process_);
+ // The request is being handled, so reset the boolean.
+ should_refresh_cache_ = false;
+ refresh_in_process_ = true;
+
+ ReinitializeCache();
+
+ fetcher_->QueryPasswordChangeScriptAvailability(
+ GetOriginsOfStoredPasswords(),
+ base::BindOnce(&SavedPasswordsCapabilitiesFetcher::
+ FetchCapababilitiesForAllStoredOriginsDone,
+ base::Unretained(this), base::TimeTicks::Now()));
+}
+
+void SavedPasswordsCapabilitiesFetcher::
+ FetchCapababilitiesForAllStoredOriginsDone(
+ base::TimeTicks request_start_timestamp,
+ const std::set<url::Origin>& capabilities) {
+ // Update |has_script| and |last_fetch_timestamp| for all origins.
+ base::TimeTicks now = base::TimeTicks::Now();
+ base::UmaHistogramMediumTimes(
+ "PasswordManager.SavedPasswordsCapabilitiesFetcher."
+ "AllOriginsResponseTime",
+ now - request_start_timestamp);
+ for (auto& [origin, c_result] : cache_) {
+ c_result.last_fetch_timestamp = now;
+ c_result.has_script = capabilities.find(origin) != capabilities.end();
+ }
+
+ refresh_in_process_ = false;
+
+ if (should_refresh_cache_) {
+ // If a new refresh request has come in the meantime, this starts another
+ // refresh here instead of running all the callbacks.
+ FetchCapababilitiesForAllStoredOrigins();
+ return;
+ }
+
+ for (auto& callback : std::exchange(all_origins_callbacks_, {})) {
+ std::move(callback).Run();
+ }
+ for (auto& [origin, callback] : std::exchange(single_origin_callbacks_, {})) {
+ std::move(callback).Run(IsScriptAvailable(origin));
+ }
+}
+
+void SavedPasswordsCapabilitiesFetcher::FetchCapababilitiesForSingleOrigin(
+ const url::Origin& origin,
+ ResponseCallback callback) {
+ // Domain not present. Fetching is only supported for origins of stored
+ // passwords.
+ if (cache_.find(origin) == cache_.end()) {
+ std::move(callback).Run(IsScriptAvailable(origin));
+ return;
+ }
+
+ fetcher_->QueryPasswordChangeScriptAvailability(
+ {origin}, base::BindOnce(&SavedPasswordsCapabilitiesFetcher::
+ FetchCapababilitiesForSingleOriginDone,
+ base::Unretained(this), origin,
+ std::move(callback), base::TimeTicks::Now()));
+}
+
+void SavedPasswordsCapabilitiesFetcher::FetchCapababilitiesForSingleOriginDone(
+ const url::Origin& origin,
+ ResponseCallback callback,
+ base::TimeTicks request_start_timestamp,
+ const std::set<url::Origin>& capabilities) {
+ base::UmaHistogramMediumTimes(
+ "PasswordManager.SavedPasswordsCapabilitiesFetcher."
+ "SingleOriginResponseTime",
+ base::TimeTicks::Now() - request_start_timestamp);
+ // Domain not present. The password might have gotten deleted since the fetch
+ // was started.
+ if (cache_.find(origin) == cache_.end()) {
+ std::move(callback).Run(IsScriptAvailable(origin));
+ return;
+ }
+ SavedPasswordsCapabilitiesFetcher::CapabilitiesFetchResult& c_result =
+ cache_.find(origin)->second;
+ c_result.last_fetch_timestamp = base::TimeTicks::Now();
+ c_result.has_script = capabilities.find(origin) != capabilities.end();
+ std::move(callback).Run(IsScriptAvailable(origin));
+}
+
+std::vector<url::Origin>
+SavedPasswordsCapabilitiesFetcher::GetOriginsOfStoredPasswords() const {
+ std::vector<url::Origin> origins;
+ for (const auto& form : saved_passwords_presenter_.GetSavedPasswords()) {
+ url::Origin origin = url::Origin::Create(form.url);
+ if (!origin.opaque()) {
+ origins.push_back(origin);
+ }
+ }
+ std::sort(origins.begin(), origins.end());
+ origins.erase(std::unique(origins.begin(), origins.end()), origins.end());
+ return origins;
+}
+
+void SavedPasswordsCapabilitiesFetcher::ReinitializeCache() {
+ // Restart the cache.
+ cache_.clear();
+ for (const auto& origin : GetOriginsOfStoredPasswords()) {
+ cache_[origin] = CapabilitiesFetchResult();
+ }
+}
+
+SavedPasswordsCapabilitiesFetcher::CacheState
+SavedPasswordsCapabilitiesFetcher::GetCacheState() const {
+ if (!is_cache_initialized_) {
+ return CacheState::kNeverSet;
+ }
+ bool need_refresh = should_refresh_cache_ ||
+ base::ranges::any_of(cache_, [](const auto& record) {
+ return record.second.IsResultStale();
+ });
+ return need_refresh
+ ? (refresh_in_process_ ? CacheState::kWaiting : CacheState::kStale)
+ : CacheState::kReady;
+}
+
+SavedPasswordsCapabilitiesFetcher::CapabilitiesFetchResult::
+ CapabilitiesFetchResult() = default;
+SavedPasswordsCapabilitiesFetcher::CapabilitiesFetchResult::
+ ~CapabilitiesFetchResult() = default;
+
+bool SavedPasswordsCapabilitiesFetcher::CapabilitiesFetchResult::IsResultStale()
+ const {
+ static const base::TimeDelta kCacheTimeout = base::Minutes(5);
+ return last_fetch_timestamp.is_null() ||
+ base::TimeTicks::Now() - last_fetch_timestamp >= kCacheTimeout;
+}
+
+} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/saved_passwords_capabilities_fetcher.h b/chromium/components/password_manager/core/browser/saved_passwords_capabilities_fetcher.h
new file mode 100644
index 00000000000..119bc6b4fda
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/saved_passwords_capabilities_fetcher.h
@@ -0,0 +1,114 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_SAVED_PASSWORDS_CAPABILITIES_FETCHER_H_
+#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_SAVED_PASSWORDS_CAPABILITIES_FETCHER_H_
+
+#include <memory>
+#include <set>
+
+#include "base/scoped_observation.h"
+#include "base/time/time.h"
+#include "components/password_manager/core/browser/capabilities_service.h"
+#include "components/password_manager/core/browser/password_scripts_fetcher.h"
+#include "components/password_manager/core/browser/ui/saved_passwords_presenter.h"
+
+namespace password_manager {
+
+class SavedPasswordsCapabilitiesFetcher
+ : public PasswordScriptsFetcher,
+ public SavedPasswordsPresenter::Observer {
+ public:
+ struct CapabilitiesFetchResult {
+ CapabilitiesFetchResult();
+ ~CapabilitiesFetchResult();
+
+ bool has_script = false;
+ base::TimeTicks last_fetch_timestamp;
+
+ bool IsResultStale() const;
+ };
+
+ SavedPasswordsCapabilitiesFetcher(
+ std::unique_ptr<CapabilitiesService> fetcher,
+ scoped_refptr<password_manager::PasswordStoreInterface> password_store);
+
+ SavedPasswordsCapabilitiesFetcher(const SavedPasswordsCapabilitiesFetcher&) =
+ delete;
+ SavedPasswordsCapabilitiesFetcher& operator=(
+ const SavedPasswordsCapabilitiesFetcher&) = delete;
+
+ ~SavedPasswordsCapabilitiesFetcher() override;
+
+ // PasswordScriptsFetcher:
+ void PrewarmCache() override;
+ void RefreshScriptsIfNecessary(
+ base::OnceClosure fetch_finished_callback) override;
+ void FetchScriptAvailability(const url::Origin& origin,
+ ResponseCallback callback) override;
+ bool IsScriptAvailable(const url::Origin& origin) const override;
+
+ private:
+ using CacheState = PasswordScriptsFetcher::CacheState;
+ // SavedPasswordsPresenter::Observer:
+ void OnEdited(const PasswordForm& form) override;
+ void OnSavedPasswordsChanged(
+ SavedPasswordsPresenter::SavedPasswordsView passwords) override;
+
+ // Fetches capabilities for all origins in cache.
+ void FetchCapababilitiesForAllStoredOrigins();
+ // Callback to process refresh capabilities request.
+ void FetchCapababilitiesForAllStoredOriginsDone(
+ base::TimeTicks request_start_timestamp,
+ const std::set<url::Origin>& capabilities);
+ // Fetches capabilities info for a single origin.
+ void FetchCapababilitiesForSingleOrigin(const url::Origin& origin,
+ ResponseCallback callback);
+ // Callback to process FetchCapababilitiesForSingleOrigin request.
+ void FetchCapababilitiesForSingleOriginDone(
+ const url::Origin& origin,
+ ResponseCallback callback,
+ base::TimeTicks request_start_timestamp,
+ const std::set<url::Origin>& capabilities);
+ // Returns a sorted list of unique origins of all stored credentials.
+ std::vector<url::Origin> GetOriginsOfStoredPasswords() const;
+ // Resets the |cache_| with the current list of origins from stored
+ // credentials.
+ void ReinitializeCache();
+
+ CacheState GetCacheState() const;
+
+ std::unique_ptr<CapabilitiesService> fetcher_;
+ // Manages the list of saved passwords, including updates.
+ password_manager::SavedPasswordsPresenter saved_passwords_presenter_;
+ // Stores the callbacks that are waiting for the refresh capabilities request
+ // to finish.
+ std::vector<base::OnceClosure> all_origins_callbacks_;
+ // Stores the single origin callbacks that are waiting for the capabilities
+ // refresh request to finish.
+ std::vector<std::pair<url::Origin, ResponseCallback>>
+ single_origin_callbacks_;
+ // Stores script capabilities and last request timestamp per origin.
+ std::map<url::Origin, CapabilitiesFetchResult> cache_;
+
+ // Boolean that remembers whether |cache_| is initialized. This is set to
+ // true when the delegate obtains the list of saved passwords for the first
+ // time.
+ bool is_cache_initialized_ = false;
+ // Boolean that remembers whether there is a refresh capabilities request in
+ // process.
+ bool refresh_in_process_ = false;
+ // Boolean that remembers whether cache should be refreshed (e.g due to an new
+ // password added to the store or a prewarming request before initialization).
+ bool should_refresh_cache_ = false;
+
+ // A scoped observer for `saved_passwords_presenter_`.
+ base::ScopedObservation<password_manager::SavedPasswordsPresenter,
+ password_manager::SavedPasswordsPresenter::Observer>
+ observed_saved_password_presenter_{this};
+};
+
+} // namespace password_manager
+
+#endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_SAVED_PASSWORDS_CAPABILITIES_FETCHER_H_
diff --git a/chromium/components/password_manager/core/browser/saved_passwords_capabilities_fetcher_unittest.cc b/chromium/components/password_manager/core/browser/saved_passwords_capabilities_fetcher_unittest.cc
new file mode 100644
index 00000000000..36194ba55b6
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/saved_passwords_capabilities_fetcher_unittest.cc
@@ -0,0 +1,512 @@
+// Copyright 2022 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.
+
+#include "components/password_manager/core/browser/saved_passwords_capabilities_fetcher.h"
+
+#include "base/callback.h"
+#include "base/test/gmock_callback_support.h"
+#include "base/test/gmock_move_support.h"
+#include "base/test/metrics/histogram_tester.h"
+#include "base/test/mock_callback.h"
+#include "base/test/task_environment.h"
+#include "components/password_manager/core/browser/capabilities_service.h"
+#include "components/password_manager/core/browser/password_form.h"
+#include "components/password_manager/core/browser/test_password_store.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace password_manager {
+namespace {
+
+using ::base::test::RunOnceCallback;
+using ::testing::_;
+using ::testing::ElementsAreArray;
+using ::testing::NiceMock;
+using ::testing::Pair;
+using ::testing::SaveArg;
+using ::testing::SaveArgPointee;
+using ::testing::UnorderedElementsAre;
+using testing::WithArgs;
+
+constexpr char kOriginWithScript1[] = "https://example.com";
+constexpr char kOriginWithScript2[] = "https://mobile.example.com";
+constexpr char kOriginWithScript3[] = "https://test.com";
+constexpr char kOriginWithoutScript[] = "https://no-script.com";
+constexpr char kExampleApp[] = "android://hash@com.example.app";
+
+constexpr char16_t kUsername1[] = u"alice";
+constexpr char16_t kUsername2[] = u"bob";
+
+constexpr char16_t kPassword1[] = u"f00b4r";
+constexpr char16_t kPassword2[] = u"s3cr3t";
+constexpr char16_t kPassword3[] = u"skpr2t";
+constexpr char16_t kPassword4[] = u"484her";
+
+url::Origin GetOriginWithScript1() {
+ return url::Origin::Create(GURL(kOriginWithScript1));
+}
+
+url::Origin GetOriginWithScript2() {
+ return url::Origin::Create(GURL(kOriginWithScript2));
+}
+
+url::Origin GetOriginWithScript3() {
+ return url::Origin::Create(GURL(kOriginWithScript3));
+}
+
+url::Origin GetOriginWithoutScript() {
+ return url::Origin::Create(GURL(kOriginWithoutScript));
+}
+
+PasswordForm MakeSavedPassword(base::StringPiece signon_realm,
+ base::StringPiece16 username,
+ base::StringPiece16 password,
+ base::StringPiece16 username_element = u"") {
+ PasswordForm form;
+ form.signon_realm = std::string(signon_realm);
+ form.url = GURL(signon_realm);
+ form.username_value = std::u16string(username);
+ form.password_value = std::u16string(password);
+ form.username_element = std::u16string(username_element);
+ return form;
+}
+
+PasswordForm MakeSavedAndroidPassword(
+ std::string package_name,
+ base::StringPiece16 username,
+ base::StringPiece app_display_name = "",
+ base::StringPiece affiliated_web_realm = "",
+ base::StringPiece16 password = kPassword1) {
+ PasswordForm form;
+ form.signon_realm = package_name;
+ form.username_value = std::u16string(username);
+ form.app_display_name = std::string(app_display_name);
+ form.affiliated_web_realm = std::string(affiliated_web_realm);
+ form.password_value = std::u16string(password);
+ return form;
+}
+
+class MockCapabilitiesService : public password_manager::CapabilitiesService {
+ public:
+ MockCapabilitiesService() = default;
+ ~MockCapabilitiesService() override = default;
+
+ MOCK_METHOD(void,
+ QueryPasswordChangeScriptAvailability,
+ (const std::vector<url::Origin>& origins,
+ ResponseCallback callback),
+ (override));
+};
+
+} // namespace
+
+class SavedPasswordsCapabilitiesFetcherTest : public ::testing::Test {
+ public:
+ SavedPasswordsCapabilitiesFetcherTest() {
+ store_->Init(/*prefs=*/nullptr, /*affiliated_match_helper=*/nullptr);
+ auto capabilities_service =
+ std::make_unique<NiceMock<MockCapabilitiesService>>();
+ mock_capabilities_service_ = capabilities_service.get();
+
+ fetcher_ = std::make_unique<SavedPasswordsCapabilitiesFetcher>(
+ std::move(capabilities_service), store_);
+ }
+ ~SavedPasswordsCapabilitiesFetcherTest() override {
+ store_->ShutdownOnUIThread();
+ task_env_.RunUntilIdle();
+ }
+
+ void FillPasswordStore() {
+ store_->AddLogin(
+ MakeSavedPassword(kOriginWithScript1, kUsername1, kPassword1));
+ store_->AddLogin(
+ MakeSavedPassword(kOriginWithScript2, kUsername1, kPassword2));
+ store_->AddLogin(
+ MakeSavedPassword(kOriginWithScript3, kUsername2, kPassword3));
+ store_->AddLogin(
+ MakeSavedPassword(kOriginWithoutScript, kUsername2, kPassword4));
+ store_->AddLogin(MakeSavedAndroidPassword(kExampleApp, kUsername2,
+ "Example App", kOriginWithScript1,
+ kPassword1));
+ RunUntilIdle();
+ }
+
+ void RunUntilIdle() { task_env_.RunUntilIdle(); }
+
+ void CheckScriptAvailabilityDefaultResults() {
+ EXPECT_TRUE(fetcher_->IsScriptAvailable(GetOriginWithScript1()));
+ EXPECT_TRUE(fetcher_->IsScriptAvailable(GetOriginWithScript2()));
+ EXPECT_TRUE(fetcher_->IsScriptAvailable(GetOriginWithScript3()));
+ EXPECT_FALSE(fetcher_->IsScriptAvailable(GetOriginWithoutScript()));
+ }
+
+ void RequestSingleScriptAvailability(const url::Origin& origin) {
+ fetcher_->FetchScriptAvailability(
+ origin,
+ base::BindOnce(&SavedPasswordsCapabilitiesFetcherTest::RecordResponse,
+ base::Unretained(this), origin));
+ }
+
+ void RecordResponse(url::Origin origin, bool has_script) {
+ const auto& it = recorded_responses_.find(origin);
+ if (it != recorded_responses_.end()) {
+ DCHECK(recorded_responses_[origin] == has_script)
+ << "Responses for " << origin << " differ";
+ } else {
+ recorded_responses_[origin] = has_script;
+ }
+ }
+
+ void ExpectCacheRefresh() {
+ EXPECT_CALL(*mock_capabilities_service_,
+ QueryPasswordChangeScriptAvailability(
+ UnorderedElementsAre(
+ GetOriginWithScript1(), GetOriginWithScript2(),
+ GetOriginWithScript3(), GetOriginWithoutScript()),
+ _))
+ .WillOnce(RunOnceCallback<1>(std::set<url::Origin>{
+ GetOriginWithScript1(), GetOriginWithScript2(),
+ GetOriginWithScript3()}));
+ }
+
+ protected:
+ base::test::SingleThreadTaskEnvironment task_env_{
+ base::test::TaskEnvironment::TimeSource::MOCK_TIME};
+ base::flat_map<url::Origin, bool> recorded_responses_;
+ raw_ptr<NiceMock<MockCapabilitiesService>> mock_capabilities_service_;
+ scoped_refptr<TestPasswordStore> store_ =
+ base::MakeRefCounted<TestPasswordStore>();
+ std::unique_ptr<SavedPasswordsCapabilitiesFetcher> fetcher_;
+};
+
+TEST_F(SavedPasswordsCapabilitiesFetcherTest, ServerError) {
+ FillPasswordStore();
+ // Simulate server error empty response.
+ EXPECT_CALL(*mock_capabilities_service_,
+ QueryPasswordChangeScriptAvailability)
+ .WillOnce(RunOnceCallback<1>(std::set<url::Origin>()));
+ fetcher_->RefreshScriptsIfNecessary(base::DoNothing());
+ EXPECT_FALSE(fetcher_->IsScriptAvailable(GetOriginWithScript1()));
+ EXPECT_FALSE(fetcher_->IsScriptAvailable(GetOriginWithScript2()));
+ EXPECT_FALSE(fetcher_->IsScriptAvailable(GetOriginWithScript3()));
+ EXPECT_FALSE(fetcher_->IsScriptAvailable(GetOriginWithoutScript()));
+}
+
+TEST_F(SavedPasswordsCapabilitiesFetcherTest, PrewarmCache) {
+ FillPasswordStore();
+
+ base::HistogramTester histogram_tester;
+ ExpectCacheRefresh();
+ fetcher_->PrewarmCache();
+
+ // The cache is not stale yet. No new request is expected.
+ EXPECT_CALL(*mock_capabilities_service_,
+ QueryPasswordChangeScriptAvailability)
+ .Times(0);
+
+ fetcher_->RefreshScriptsIfNecessary(base::DoNothing());
+ CheckScriptAvailabilityDefaultResults();
+
+ // Make cache stale again.
+ RunUntilIdle();
+ task_env_.AdvanceClock(base::Minutes(10));
+ EXPECT_CALL(*mock_capabilities_service_,
+ QueryPasswordChangeScriptAvailability(
+ UnorderedElementsAre(
+ GetOriginWithScript1(), GetOriginWithScript2(),
+ GetOriginWithScript3(), GetOriginWithoutScript()),
+ _))
+ .WillOnce(RunOnceCallback<1>(std::set<url::Origin>()));
+ fetcher_->PrewarmCache();
+
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.SavedPasswordsCapabilitiesFetcher.CacheState",
+ PasswordScriptsFetcher::CacheState::kReady, 1u);
+ histogram_tester.ExpectTotalCount(
+ "PasswordManager.SavedPasswordsCapabilitiesFetcher."
+ "AllOriginsResponseTime",
+ 2u);
+}
+
+TEST_F(SavedPasswordsCapabilitiesFetcherTest, NoPrewarmCache) {
+ FillPasswordStore();
+
+ base::HistogramTester histogram_tester;
+ // Run bulk check with no cache prewarming. Expect necessary full refresh.
+ ExpectCacheRefresh();
+ fetcher_->RefreshScriptsIfNecessary(base::DoNothing());
+ CheckScriptAvailabilityDefaultResults();
+
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.SavedPasswordsCapabilitiesFetcher.CacheState",
+ PasswordScriptsFetcher::CacheState::kStale, 1u);
+ histogram_tester.ExpectTotalCount(
+ "PasswordManager.SavedPasswordsCapabilitiesFetcher."
+ "AllOriginsResponseTime",
+ 1u);
+}
+
+TEST_F(SavedPasswordsCapabilitiesFetcherTest,
+ StartBulkCheckBeforePrewarmingResponse) {
+ FillPasswordStore();
+ base::HistogramTester histogram_tester;
+
+ CapabilitiesService::ResponseCallback callback;
+ EXPECT_CALL(*mock_capabilities_service_,
+ QueryPasswordChangeScriptAvailability(
+ UnorderedElementsAre(
+ GetOriginWithScript1(), GetOriginWithScript2(),
+ GetOriginWithScript3(), GetOriginWithoutScript()),
+ _))
+ .WillOnce(MoveArg<1>(&callback));
+
+ fetcher_->PrewarmCache();
+
+ // Bulk check started before server's prewarming response. No new request
+ // should be triggered if the cache is |kWaiting|.
+ EXPECT_CALL(*mock_capabilities_service_,
+ QueryPasswordChangeScriptAvailability)
+ .Times(0);
+ fetcher_->RefreshScriptsIfNecessary(base::DoNothing());
+
+ // Resolve prewarming callback.
+ std::move(callback).Run(std::set<url::Origin>{
+ GetOriginWithScript1(), GetOriginWithScript2(), GetOriginWithScript3()});
+ CheckScriptAvailabilityDefaultResults();
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.SavedPasswordsCapabilitiesFetcher.CacheState",
+ PasswordScriptsFetcher::CacheState::kWaiting, 1u);
+ histogram_tester.ExpectTotalCount(
+ "PasswordManager.SavedPasswordsCapabilitiesFetcher."
+ "AllOriginsResponseTime",
+ 1u);
+}
+
+TEST_F(SavedPasswordsCapabilitiesFetcherTest, IsScriptAvailable) {
+ FillPasswordStore();
+ base::HistogramTester histogram_tester;
+ EXPECT_CALL(*mock_capabilities_service_,
+ QueryPasswordChangeScriptAvailability)
+ .Times(0);
+ // |IsScriptAvailable| does not trigger any network requests and returns the
+ // default value (false).
+ EXPECT_FALSE(fetcher_->IsScriptAvailable(GetOriginWithScript1()));
+ EXPECT_FALSE(fetcher_->IsScriptAvailable(GetOriginWithScript2()));
+ EXPECT_FALSE(fetcher_->IsScriptAvailable(GetOriginWithScript3()));
+ EXPECT_FALSE(fetcher_->IsScriptAvailable(GetOriginWithoutScript()));
+
+ ExpectCacheRefresh();
+ fetcher_->RefreshScriptsIfNecessary(base::DoNothing());
+
+ // Cache is ready.
+ CheckScriptAvailabilityDefaultResults();
+
+ EXPECT_CALL(*mock_capabilities_service_,
+ QueryPasswordChangeScriptAvailability)
+ .Times(0);
+
+ // Make cache stale again.
+ task_env_.AdvanceClock(base::Minutes(10));
+ // |IsScriptAvailable| does not trigger refetching and returns false.
+ EXPECT_FALSE(fetcher_->IsScriptAvailable(GetOriginWithScript1()));
+ EXPECT_FALSE(fetcher_->IsScriptAvailable(GetOriginWithScript2()));
+ EXPECT_FALSE(fetcher_->IsScriptAvailable(GetOriginWithScript3()));
+ EXPECT_FALSE(fetcher_->IsScriptAvailable(GetOriginWithoutScript()));
+
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.SavedPasswordsCapabilitiesFetcher.CacheState",
+ PasswordScriptsFetcher::CacheState::kStale, 1u);
+ histogram_tester.ExpectTotalCount(
+ "PasswordManager.SavedPasswordsCapabilitiesFetcher."
+ "AllOriginsResponseTime",
+ 1u);
+}
+
+TEST_F(SavedPasswordsCapabilitiesFetcherTest, PasswordStoreUpdate) {
+ FillPasswordStore();
+
+ ExpectCacheRefresh();
+ fetcher_->PrewarmCache();
+
+ // Add a new login to the store. Cache should go stale.
+ PasswordForm password_form =
+ MakeSavedPassword("https://foo.com", kUsername1, kPassword1);
+ store_->AddLogin(password_form);
+ RunUntilIdle();
+
+ // Expect refresh of stored creentials including the new one.
+ EXPECT_CALL(
+ *mock_capabilities_service_,
+ QueryPasswordChangeScriptAvailability(
+ UnorderedElementsAre(GetOriginWithScript1(), GetOriginWithScript2(),
+ GetOriginWithScript3(), GetOriginWithoutScript(),
+ url::Origin::Create(GURL("https://foo.com"))),
+ _))
+ .WillOnce(RunOnceCallback<1>(std::set<url::Origin>()));
+ fetcher_->PrewarmCache();
+
+ // Updated a credential, cache should *not* go stale.
+ password_form.password_value = kPassword2;
+ store_->UpdateLogin(password_form);
+ RunUntilIdle();
+
+ EXPECT_CALL(*mock_capabilities_service_,
+ QueryPasswordChangeScriptAvailability)
+ .Times(0);
+ fetcher_->PrewarmCache();
+}
+
+TEST_F(SavedPasswordsCapabilitiesFetcherTest,
+ FetchScriptAvailabilityDuringRequest) {
+ FillPasswordStore();
+ base::HistogramTester histogram_tester;
+
+ CapabilitiesService::ResponseCallback callback;
+ EXPECT_CALL(*mock_capabilities_service_,
+ QueryPasswordChangeScriptAvailability(
+ UnorderedElementsAre(
+ GetOriginWithScript1(), GetOriginWithScript2(),
+ GetOriginWithScript3(), GetOriginWithoutScript()),
+ _))
+ .WillOnce(MoveArg<1>(&callback));
+
+ fetcher_->PrewarmCache();
+
+ // FetchScriptAvailability before server's prewarming response. No new request
+ // should be triggered if the cache is |kWaiting|. Requests should be answered
+ // after refresh is finished.
+ EXPECT_CALL(*mock_capabilities_service_,
+ QueryPasswordChangeScriptAvailability)
+ .Times(0);
+ RequestSingleScriptAvailability(GetOriginWithScript1());
+ RequestSingleScriptAvailability(GetOriginWithoutScript());
+
+ // Resolve prewarming callback.
+ std::move(callback).Run(std::set<url::Origin>{
+ GetOriginWithScript1(), GetOriginWithScript2(), GetOriginWithScript3()});
+ EXPECT_THAT(recorded_responses_,
+ UnorderedElementsAre(Pair(GetOriginWithScript1(), true),
+ Pair(GetOriginWithoutScript(), false)));
+ histogram_tester.ExpectTotalCount(
+ "PasswordManager.SavedPasswordsCapabilitiesFetcher.CacheState", 0u);
+ histogram_tester.ExpectTotalCount(
+ "PasswordManager.SavedPasswordsCapabilitiesFetcher."
+ "AllOriginsResponseTime",
+ 1u);
+ histogram_tester.ExpectTotalCount(
+ "PasswordManager.SavedPasswordsCapabilitiesFetcher."
+ "SingleOriginResponseTime",
+ 0u);
+}
+
+TEST_F(SavedPasswordsCapabilitiesFetcherTest,
+ FetchScriptAvailabilityAfterRefreshRequest) {
+ FillPasswordStore();
+ base::HistogramTester histogram_tester;
+
+ ExpectCacheRefresh();
+ fetcher_->PrewarmCache();
+
+ // Add a new login to the store. Cache should go stale and
+ // FetchScriptAvailability should trigger single origin requests.
+ PasswordForm password_form =
+ MakeSavedPassword("https://foo.com", kUsername1, kPassword1);
+ store_->AddLogin(password_form);
+ RunUntilIdle();
+
+ url::Origin foo_origin = url::Origin::Create(GURL("https://foo.com"));
+ EXPECT_CALL(
+ *mock_capabilities_service_,
+ QueryPasswordChangeScriptAvailability(ElementsAreArray({foo_origin}), _))
+ .WillOnce(RunOnceCallback<1>(std::set<url::Origin>{foo_origin}));
+
+ EXPECT_CALL(*mock_capabilities_service_,
+ QueryPasswordChangeScriptAvailability(
+ ElementsAreArray({GetOriginWithoutScript()}), _))
+ .WillOnce(RunOnceCallback<1>(std::set<url::Origin>()));
+
+ // Origin got added to the cache, record should be stale and therefore
+ // trigger a single origin request.
+ RequestSingleScriptAvailability(foo_origin);
+ RequestSingleScriptAvailability(GetOriginWithoutScript());
+
+ EXPECT_THAT(recorded_responses_,
+ UnorderedElementsAre(Pair(foo_origin, true),
+ Pair(GetOriginWithoutScript(), false)));
+
+ histogram_tester.ExpectTotalCount(
+ "PasswordManager.SavedPasswordsCapabilitiesFetcher.CacheState", 0u);
+ histogram_tester.ExpectTotalCount(
+ "PasswordManager.SavedPasswordsCapabilitiesFetcher."
+ "AllOriginsResponseTime",
+ 1u);
+ histogram_tester.ExpectTotalCount(
+ "PasswordManager.SavedPasswordsCapabilitiesFetcher."
+ "SingleOriginResponseTime",
+ 2u);
+}
+
+TEST_F(SavedPasswordsCapabilitiesFetcherTest,
+ FetchScriptAvailabilityAfterStaleCache) {
+ FillPasswordStore();
+ base::HistogramTester histogram_tester;
+
+ // FetchScriptAvailability without any refresh should trigger single origin
+ // request.
+ EXPECT_CALL(*mock_capabilities_service_,
+ QueryPasswordChangeScriptAvailability(
+ ElementsAreArray({GetOriginWithScript1()}), _))
+ .WillOnce(
+ RunOnceCallback<1>(std::set<url::Origin>{GetOriginWithScript1()}));
+
+ RequestSingleScriptAvailability(GetOriginWithScript1());
+ EXPECT_THAT(recorded_responses_,
+ ElementsAreArray({Pair(GetOriginWithScript1(), true)}));
+
+ // Refresh full cache.
+ ExpectCacheRefresh();
+ fetcher_->PrewarmCache();
+
+ // The cache is not stale. No new request is expected.
+ EXPECT_CALL(*mock_capabilities_service_,
+ QueryPasswordChangeScriptAvailability)
+ .Times(0);
+ RequestSingleScriptAvailability(GetOriginWithScript1());
+ EXPECT_THAT(recorded_responses_,
+ ElementsAreArray({Pair(GetOriginWithScript1(), true)}));
+
+ // Cache goes stale. Single origin request is expected.
+ task_env_.AdvanceClock(base::Minutes(10));
+ recorded_responses_.clear();
+
+ EXPECT_CALL(*mock_capabilities_service_,
+ QueryPasswordChangeScriptAvailability(
+ ElementsAreArray({GetOriginWithScript2()}), _))
+ .WillOnce(
+ RunOnceCallback<1>(std::set<url::Origin>{GetOriginWithScript2()}));
+
+ EXPECT_CALL(*mock_capabilities_service_,
+ QueryPasswordChangeScriptAvailability(
+ ElementsAreArray({GetOriginWithoutScript()}), _))
+ .WillOnce(RunOnceCallback<1>(std::set<url::Origin>()));
+
+ RequestSingleScriptAvailability(GetOriginWithScript2());
+ RequestSingleScriptAvailability(GetOriginWithoutScript());
+
+ EXPECT_THAT(recorded_responses_,
+ UnorderedElementsAre(Pair(GetOriginWithScript2(), true),
+ Pair(GetOriginWithoutScript(), false)));
+ histogram_tester.ExpectTotalCount(
+ "PasswordManager.SavedPasswordsCapabilitiesFetcher.CacheState", 0u);
+ histogram_tester.ExpectTotalCount(
+ "PasswordManager.SavedPasswordsCapabilitiesFetcher."
+ "AllOriginsResponseTime",
+ 1u);
+ histogram_tester.ExpectTotalCount(
+ "PasswordManager.SavedPasswordsCapabilitiesFetcher."
+ "SingleOriginResponseTime",
+ 3u);
+}
+
+} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/site_affiliation/affiliation_fetcher_base.cc b/chromium/components/password_manager/core/browser/site_affiliation/affiliation_fetcher_base.cc
index 9ecf66fd997..61d831ac09b 100644
--- a/chromium/components/password_manager/core/browser/site_affiliation/affiliation_fetcher_base.cc
+++ b/chromium/components/password_manager/core/browser/site_affiliation/affiliation_fetcher_base.cc
@@ -102,9 +102,12 @@ bool AffiliationFetcherBase::ParseResponse(
// case so the caller can be notified and it can act accordingly.
// * The |result| will be free of duplicate or empty equivalence classes.
- affiliation_pb::LookupAffiliationResponse response;
- if (!response.ParseFromString(serialized_response))
+ affiliation_pb::LookupAffiliationByHashPrefixResponse response;
+ if (!response.ParseFromString(serialized_response)) {
+ base::UmaHistogramBoolean(
+ "PasswordManager.AffiliationFetcher.FailedToParseResponse", true);
return false;
+ }
return ParseLookupAffiliationResponse(GetRequestedFacetURIs(), response,
result);
diff --git a/chromium/components/password_manager/core/browser/site_affiliation/affiliation_service_impl.cc b/chromium/components/password_manager/core/browser/site_affiliation/affiliation_service_impl.cc
index 6a9ef8544cc..f0d32217009 100644
--- a/chromium/components/password_manager/core/browser/site_affiliation/affiliation_service_impl.cc
+++ b/chromium/components/password_manager/core/browser/site_affiliation/affiliation_service_impl.cc
@@ -12,7 +12,6 @@
#include "base/files/file_path.h"
#include "base/location.h"
#include "base/metrics/histogram_functions.h"
-#include "base/no_destructor.h"
#include "base/ranges/algorithm.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/thread_pool.h"
diff --git a/chromium/components/password_manager/core/browser/site_affiliation/asset_link_data.cc b/chromium/components/password_manager/core/browser/site_affiliation/asset_link_data.cc
index bc057677445..1f2fac4aa47 100644
--- a/chromium/components/password_manager/core/browser/site_affiliation/asset_link_data.cc
+++ b/chromium/components/password_manager/core/browser/site_affiliation/asset_link_data.cc
@@ -58,7 +58,7 @@ bool AssetLinkData::Parse(const std::string& data) {
if (!value || !value->is_list())
return false;
base::JSONValueConverter<Statement> converter;
- for (const auto& item : value->GetList()) {
+ for (const auto& item : value->GetListDeprecated()) {
Statement statement;
if (converter.Convert(item, &statement)) {
if (!statement.include.empty()) {
diff --git a/chromium/components/password_manager/core/browser/store_metrics_reporter.cc b/chromium/components/password_manager/core/browser/store_metrics_reporter.cc
index 7522d8c018d..eb05f454997 100644
--- a/chromium/components/password_manager/core/browser/store_metrics_reporter.cc
+++ b/chromium/components/password_manager/core/browser/store_metrics_reporter.cc
@@ -6,7 +6,6 @@
#include <memory>
#include "base/metrics/histogram_functions.h"
-#include "base/metrics/histogram_macros.h"
#include "base/strings/strcat.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/sequenced_task_runner.h"
@@ -27,15 +26,20 @@ namespace password_manager {
namespace {
+// Minimum time between two metrics reporting trigger for the same profile. This
+// is needed in order to avoid unnecessarily reporting password store metrics on
+// every profile creation (which is very frequent on Android for example).
+constexpr base::TimeDelta kMetricsReportingThreshold = base::Days(1);
+
// Common prefix for all histograms.
constexpr char kPasswordManager[] = "PasswordManager";
-// Need to stay in sync with the PasswordGenerated suffix in histograms.xml.
+// Need to stay in sync with the PasswordType variant in histograms.xml.
constexpr char kAutoGeneratedSuffix[] = ".AutoGenerated";
constexpr char kUserCreatedSuffix[] = ".UserCreated";
constexpr char kOverallSuffix[] = ".Overall";
-// Need to stay in sync with the PasswordCustomPassphrase suffix in
+// Need to stay in sync with the CustomPassphraseStatus variant in
// histograms.xml.
constexpr char kWithCustomPassphraseSuffix[] = ".WithCustomPassphrase";
constexpr char kWithoutCustomPassphraseSuffix[] = ".WithoutCustomPassphrase";
@@ -47,13 +51,22 @@ base::StringPiece GetCustomPassphraseSuffix(
}
// Returns a suffix (infix, really) to be used in histogram names to
-// differentiate the profile store from the account store.
+// differentiate the profile store from the account store. Need to stay in sync
+// with the Store variant in histograms.xml.
base::StringPiece GetMetricsSuffixForStore(bool is_account_store) {
- // Note: For historic reasons, the profile store does not use a suffix, only
- // the account store does.
- return is_account_store ? ".AccountStore" : "";
+ return is_account_store ? ".AccountStore" : ".ProfileStore";
}
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
+enum class SyncingAccountState {
+ kSyncingAndSyncPasswordNotSaved = 0,
+ kSyncingAndSyncPasswordSaved = 1,
+ kNotSyncingAndSyncPasswordNotSaved = 2,
+ kNotSyncingAndSyncPasswordSaved = 3,
+ kMaxValue = kNotSyncingAndSyncPasswordSaved,
+};
+
void LogAccountStatHiRes(const std::string& name, int sample) {
base::UmaHistogramCustomCounts(name, sample, 0, 1000, 100);
}
@@ -63,7 +76,7 @@ void LogNumberOfAccountsForScheme(base::StringPiece suffix_for_store,
int sample) {
base::UmaHistogramCustomCounts(
base::StrCat({kPasswordManager, suffix_for_store,
- ".TotalAccountsHiRes.WithScheme.", scheme}),
+ ".TotalAccountsHiRes2.WithScheme.", scheme}),
sample, 1, 1000, 100);
}
@@ -100,7 +113,7 @@ void ReportNumberOfAccountsMetrics(
}
constexpr base::StringPiece kAccountsPerSiteSuffix =
- ".AccountsPerSiteHiRes";
+ ".AccountsPerSiteHiRes2";
if (password_type == PasswordForm::Type::kGenerated) {
total_generated_accounts += accounts_per_site;
@@ -123,7 +136,7 @@ void ReportNumberOfAccountsMetrics(
}
static constexpr base::StringPiece kTotalAccountsByTypeSuffix =
- ".TotalAccountsHiRes.ByType";
+ ".TotalAccountsHiRes2.ByType";
LogAccountStatHiRes(
base::StrCat({kPasswordManager, store_suffix, kTotalAccountsByTypeSuffix,
@@ -141,7 +154,7 @@ void ReportNumberOfAccountsMetrics(
total_user_created_accounts + total_generated_accounts);
LogAccountStatHiRes(
- base::StrCat({kPasswordManager, store_suffix, ".BlacklistedSitesHiRes",
+ base::StrCat({kPasswordManager, store_suffix, ".BlacklistedSitesHiRes2",
custom_passphrase_suffix}),
blocklisted_sites);
}
@@ -195,7 +208,7 @@ void ReportTimesPasswordUsedMetrics(
const int times_used = form->times_used;
static constexpr base::StringPiece kTimesPasswordUsedSuffix =
- ".TimesPasswordUsed";
+ ".TimesPasswordUsed2";
if (type == PasswordForm::Type::kGenerated) {
LogTimesUsedStat(
@@ -228,10 +241,17 @@ void ReportSyncingAccountStateMetrics(
gaia::AreEmailsSame(sync_username,
base::UTF16ToUTF8(form->username_value));
});
-
- UMA_HISTOGRAM_ENUMERATION("PasswordManager.SyncingAccountState",
- 2 * sync_username.empty() + syncing_account_saved,
- 4);
+ SyncingAccountState sync_account_state =
+ sync_username.empty()
+ ? (syncing_account_saved
+ ? SyncingAccountState::kNotSyncingAndSyncPasswordSaved
+ : SyncingAccountState::kNotSyncingAndSyncPasswordNotSaved)
+ : (syncing_account_saved
+ ? SyncingAccountState::kSyncingAndSyncPasswordSaved
+ : SyncingAccountState::kSyncingAndSyncPasswordNotSaved);
+ base::UmaHistogramEnumeration(
+ base::StrCat({kPasswordManager, ".SyncingAccountState2"}),
+ sync_account_state);
}
void ReportDuplicateCredentialsMetrics(
@@ -266,10 +286,11 @@ void ReportDuplicateCredentialsMetrics(
credentials_with_mismatched_duplicates++;
}
- base::UmaHistogramCustomCounts("PasswordManager.CredentialsWithDuplicates",
- credentials_with_duplicates, 0, 32, 6);
base::UmaHistogramCustomCounts(
- "PasswordManager.CredentialsWithMismatchedDuplicates",
+ base::StrCat({kPasswordManager, ".CredentialsWithDuplicates2"}),
+ credentials_with_duplicates, 0, 32, 6);
+ base::UmaHistogramCustomCounts(
+ base::StrCat({kPasswordManager, ".CredentialsWithMismatchedDuplicates2"}),
credentials_with_mismatched_duplicates, 0, 32, 6);
}
@@ -280,10 +301,12 @@ void ReportPasswordIssuesMetrics(
return !form->password_issues.contains(InsecureType::kLeaked);
});
base::UmaHistogramCounts100(
- "PasswordManager.CompromisedCredentials.CountLeaked", count_leaked);
+ base::StrCat({kPasswordManager, ".CompromisedCredentials2.CountLeaked"}),
+ count_leaked);
if (bulk_check_done) {
base::UmaHistogramCounts100(
- "PasswordManager.CompromisedCredentials.CountLeakedAfterBulkCheck",
+ base::StrCat({kPasswordManager,
+ ".CompromisedCredentials2.CountLeakedAfterBulkCheck"}),
count_leaked);
}
@@ -291,7 +314,8 @@ void ReportPasswordIssuesMetrics(
return !form->password_issues.contains(InsecureType::kPhished);
});
base::UmaHistogramCounts100(
- "PasswordManager.CompromisedCredentials.CountPhished", count_phished);
+ base::StrCat({kPasswordManager, ".CompromisedCredentials2.CountPhished"}),
+ count_phished);
}
void ReportMultiStoreMetrics(
@@ -354,13 +378,21 @@ void ReportMultiStoreMetrics(
if (is_opted_in) {
base::UmaHistogramCounts100(
- "PasswordManager.AccountStoreVsProfileStore2.Additional", additional);
+ base::StrCat(
+ {kPasswordManager, ".AccountStoreVsProfileStore3.Additional"}),
+ additional);
base::UmaHistogramCounts100(
- "PasswordManager.AccountStoreVsProfileStore2.Missing", missing);
+ base::StrCat(
+ {kPasswordManager, ".AccountStoreVsProfileStore3.Missing"}),
+ missing);
base::UmaHistogramCounts100(
- "PasswordManager.AccountStoreVsProfileStore2.Identical", identical);
+ base::StrCat(
+ {kPasswordManager, ".AccountStoreVsProfileStore3.Identical"}),
+ identical);
base::UmaHistogramCounts100(
- "PasswordManager.AccountStoreVsProfileStore2.Conflicting", conflicting);
+ base::StrCat(
+ {kPasswordManager, ".AccountStoreVsProfileStore3.Conflicting"}),
+ conflicting);
}
}
@@ -381,6 +413,25 @@ StoreMetricsReporter::StoreMetricsReporter(
done_callback_(std::move(done_callback)) {
DCHECK(prefs);
+ base::TimeDelta time_since_last_metrics_reporting =
+ base::Time::Now() -
+ base::Time::FromTimeT(prefs->GetDouble(
+ password_manager::prefs::kLastTimePasswordStoreMetricsReported));
+ if (time_since_last_metrics_reporting < kMetricsReportingThreshold) {
+ // Upon constructing StoreMetricsReporter, it's moved into member variable
+ // in StoreMetricReporterHelper. `done_callback_` effectively destroys
+ // StoreMetricReporterHelper. Therefore, `done_callback_` must be called
+ // asynchronously to avoid moving the StoreMetricsReporter pointer to a
+ // destroyed unique_ptr.
+ base::SequencedTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+ std::move(done_callback_));
+ return;
+ }
+
+ prefs->SetDouble(
+ password_manager::prefs::kLastTimePasswordStoreMetricsReported,
+ base::Time::Now().ToDoubleT());
+
sync_username_ =
password_manager::sync_util::GetSyncUsernameIfSyncingPasswords(
sync_service, identity_manager);
@@ -395,7 +446,7 @@ StoreMetricsReporter::StoreMetricsReporter(
is_opted_in_ = features_util::IsOptedInForAccountStorage(prefs, sync_service);
base::UmaHistogramBoolean(
- "PasswordManager.Enabled2",
+ base::StrCat({kPasswordManager, ".Enabled3"}),
prefs->GetBoolean(password_manager::prefs::kCredentialsEnableService));
// May be null in tests.
@@ -411,6 +462,12 @@ StoreMetricsReporter::StoreMetricsReporter(
if (account_store_)
account_store_->GetAllLogins(weak_ptr_factory_.GetWeakPtr());
+
+ if (!profile_store_ && !account_store_) {
+ // There is nothing else to report.
+ base::SequencedTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+ std::move(done_callback_));
+ }
}
void StoreMetricsReporter::OnGetPasswordStoreResults(
@@ -457,6 +514,7 @@ void StoreMetricsReporter::OnGetPasswordStoreResultsFrom(
ReportMultiStoreMetrics(std::move(profile_store_results_),
std::move(account_store_results_), is_opted_in_);
}
+ DCHECK(done_callback_);
std::move(done_callback_).Run();
}
@@ -470,7 +528,8 @@ void StoreMetricsReporter::ReportStoreMetrics(
custom_passphrase_sync_enabled_, results);
// The remaining metrics are not recorded for the account store:
- // - SyncingAccountState just doesn't make sense, since syncing users only use
+ // - SyncingAccountState2 just doesn't make sense, since syncing users only
+ // use
// the profile store.
// - DuplicateCredentials *could* be recorded for the account store, but are
// not very critical.
diff --git a/chromium/components/password_manager/core/browser/store_metrics_reporter_unittest.cc b/chromium/components/password_manager/core/browser/store_metrics_reporter_unittest.cc
index 452baa5419c..63bc8a372a2 100644
--- a/chromium/components/password_manager/core/browser/store_metrics_reporter_unittest.cc
+++ b/chromium/components/password_manager/core/browser/store_metrics_reporter_unittest.cc
@@ -8,6 +8,7 @@
#include "base/memory/scoped_refptr.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/metrics/histogram_tester.h"
+#include "base/test/mock_callback.h"
#include "base/test/scoped_feature_list.h"
#include "components/os_crypt/os_crypt_mocker.h"
#include "components/password_manager/core/browser/mock_password_reuse_manager.h"
@@ -140,6 +141,8 @@ class StoreMetricsReporterTest : public SyncUsernameTestBase {
password_manager::prefs::kWasAutoSignInFirstRunExperienceShown, false);
prefs_.registry()->RegisterBooleanPref(prefs::kWereOldGoogleLoginsRemoved,
false);
+ prefs_.registry()->RegisterDoublePref(
+ prefs::kLastTimePasswordStoreMetricsReported, 0.0);
}
void TearDown() override { OSCryptMocker::TearDown(); }
@@ -171,10 +174,44 @@ TEST_P(StoreMetricsReporterTestWithParams, StoreIndependentMetrics) {
/*is_under_advanced_protection=*/false,
/*done_callback*/ base::DoNothing());
- histogram_tester.ExpectUniqueSample("PasswordManager.Enabled2",
+ histogram_tester.ExpectUniqueSample("PasswordManager.Enabled3",
password_manager_enabled, 1);
}
+TEST_F(StoreMetricsReporterTest, ReportMetricsAtMostOncePerDay) {
+ auto profile_store =
+ base::MakeRefCounted<TestPasswordStore>(IsAccountStore(false));
+ profile_store->Init(&prefs_, /*affiliated_match_helper=*/nullptr);
+
+ base::HistogramTester histogram_tester;
+ base::MockCallback<base::OnceClosure> done_callback;
+ StoreMetricsReporter reporter(
+ profile_store.get(), /*account_store=*/nullptr, sync_service(),
+ identity_manager(), &prefs_, /*password_reuse_manager=*/nullptr,
+ /*is_under_advanced_protection=*/false, done_callback.Get());
+ histogram_tester.ExpectTotalCount("PasswordManager.Enabled3", 1);
+ EXPECT_CALL(done_callback, Run());
+ RunUntilIdle();
+
+ // Immediately try to report metrics again, no metrics should be reported
+ // since not enough time has passwed, but the done_callback should be invoked
+ // nevertheless.
+ base::HistogramTester histogram_tester2;
+ base::MockCallback<base::OnceClosure> done_callback2;
+ StoreMetricsReporter reporter2(
+ profile_store.get(), /*account_store=*/nullptr, sync_service(),
+ identity_manager(), &prefs_, /*password_reuse_manager=*/nullptr,
+ /*is_under_advanced_protection=*/false, done_callback2.Get());
+ histogram_tester2.ExpectTotalCount("PasswordManager.Enabled3", 0);
+ EXPECT_CALL(done_callback2, Run());
+ RunUntilIdle();
+
+ profile_store->ShutdownOnUIThread();
+ // Make sure the PasswordStore destruction parts on the background sequence
+ // finish, otherwise we get memory leak reports.
+ RunUntilIdle();
+}
+
TEST_F(StoreMetricsReporterTest, ReportAccountsPerSiteHiResMetricsTest) {
auto profile_store =
base::MakeRefCounted<TestPasswordStore>(IsAccountStore(false));
@@ -200,25 +237,32 @@ TEST_F(StoreMetricsReporterTest, ReportAccountsPerSiteHiResMetricsTest) {
RunUntilIdle();
histogram_tester.ExpectUniqueSample(
- "PasswordManager.AccountsPerSiteHiRes.AutoGenerated."
+ "PasswordManager.ProfileStore.AccountsPerSiteHiRes2."
+ "AutoGenerated."
"WithoutCustomPassphrase",
1, 2);
histogram_tester.ExpectBucketCount(
- "PasswordManager.AccountsPerSiteHiRes.UserCreated."
+ "PasswordManager.ProfileStore.AccountsPerSiteHiRes2."
+ "UserCreated."
"WithoutCustomPassphrase",
1, 3);
histogram_tester.ExpectBucketCount(
- "PasswordManager.AccountsPerSiteHiRes.UserCreated."
+ "PasswordManager.ProfileStore.AccountsPerSiteHiRes2."
+ "UserCreated."
"WithoutCustomPassphrase",
2, 2);
histogram_tester.ExpectBucketCount(
- "PasswordManager.AccountsPerSiteHiRes.Overall.WithoutCustomPassphrase", 1,
- 5);
+ "PasswordManager.ProfileStore.AccountsPerSiteHiRes2."
+ "Overall."
+ "WithoutCustomPassphrase",
+ 1, 5);
histogram_tester.ExpectBucketCount(
- "PasswordManager.AccountsPerSiteHiRes.Overall.WithoutCustomPassphrase", 2,
- 2);
+ "PasswordManager.ProfileStore.AccountsPerSiteHiRes2."
+ "Overall."
+ "WithoutCustomPassphrase",
+ 2, 2);
account_store->ShutdownOnUIThread();
profile_store->ShutdownOnUIThread();
@@ -253,30 +297,46 @@ TEST_F(StoreMetricsReporterTest, ReportTotalAccountsHiResMetricsTest) {
RunUntilIdle();
histogram_tester.ExpectUniqueSample(
- "PasswordManager.TotalAccountsHiRes.ByType.AutoGenerated."
+ "PasswordManager.ProfileStore.TotalAccountsHiRes2."
+ "ByType."
+ "AutoGenerated."
"WithoutCustomPassphrase",
2, 1);
histogram_tester.ExpectUniqueSample(
- "PasswordManager.TotalAccountsHiRes.ByType.UserCreated."
+ "PasswordManager.ProfileStore.TotalAccountsHiRes2."
+ "ByType."
+ "UserCreated."
"WithoutCustomPassphrase",
7, 1);
histogram_tester.ExpectUniqueSample(
- "PasswordManager.TotalAccountsHiRes.ByType.Overall."
+ "PasswordManager.ProfileStore.TotalAccountsHiRes2."
+ "ByType.Overall."
"WithoutCustomPassphrase",
9, 1);
histogram_tester.ExpectUniqueSample(
- "PasswordManager.TotalAccountsHiRes.WithScheme.Android", 2, 1);
+ "PasswordManager.ProfileStore.TotalAccountsHiRes2."
+ "WithScheme."
+ "Android",
+ 2, 1);
histogram_tester.ExpectUniqueSample(
- "PasswordManager.TotalAccountsHiRes.WithScheme.Ftp", 1, 1);
+ "PasswordManager.ProfileStore.TotalAccountsHiRes2."
+ "WithScheme.Ftp",
+ 1, 1);
histogram_tester.ExpectUniqueSample(
- "PasswordManager.TotalAccountsHiRes.WithScheme.Http", 5, 1);
+ "PasswordManager.ProfileStore.TotalAccountsHiRes2."
+ "WithScheme.Http",
+ 5, 1);
histogram_tester.ExpectUniqueSample(
- "PasswordManager.TotalAccountsHiRes.WithScheme.Https", 1, 1);
+ "PasswordManager.ProfileStore.TotalAccountsHiRes2."
+ "WithScheme.Https",
+ 1, 1);
histogram_tester.ExpectUniqueSample(
- "PasswordManager.TotalAccountsHiRes.WithScheme.Other", 0, 1);
+ "PasswordManager.ProfileStore.TotalAccountsHiRes2."
+ "WithScheme.Other",
+ 0, 1);
account_store->ShutdownOnUIThread();
profile_store->ShutdownOnUIThread();
@@ -311,35 +371,53 @@ TEST_F(StoreMetricsReporterTest, ReportTimesPasswordUsedMetricsTest) {
RunUntilIdle();
histogram_tester.ExpectBucketCount(
- "PasswordManager.TimesPasswordUsed.AutoGenerated.WithoutCustomPassphrase",
+ "PasswordManager.ProfileStore.TimesPasswordUsed2."
+ "AutoGenerated."
+ "WithoutCustomPassphrase",
2, 1);
histogram_tester.ExpectBucketCount(
- "PasswordManager.TimesPasswordUsed.AutoGenerated.WithoutCustomPassphrase",
+ "PasswordManager.ProfileStore.TimesPasswordUsed2."
+ "AutoGenerated."
+ "WithoutCustomPassphrase",
4, 1);
histogram_tester.ExpectBucketCount(
- "PasswordManager.TimesPasswordUsed.UserCreated.WithoutCustomPassphrase",
+ "PasswordManager.ProfileStore.TimesPasswordUsed2."
+ "UserCreated."
+ "WithoutCustomPassphrase",
0, 1);
histogram_tester.ExpectBucketCount(
- "PasswordManager.TimesPasswordUsed.UserCreated.WithoutCustomPassphrase",
+ "PasswordManager.ProfileStore.TimesPasswordUsed2."
+ "UserCreated."
+ "WithoutCustomPassphrase",
1, 1);
histogram_tester.ExpectBucketCount(
- "PasswordManager.TimesPasswordUsed.UserCreated.WithoutCustomPassphrase",
+ "PasswordManager.ProfileStore.TimesPasswordUsed2."
+ "UserCreated."
+ "WithoutCustomPassphrase",
3, 1);
histogram_tester.ExpectBucketCount(
- "PasswordManager.TimesPasswordUsed.Overall.WithoutCustomPassphrase", 0,
- 1);
+ "PasswordManager.ProfileStore.TimesPasswordUsed2."
+ "Overall."
+ "WithoutCustomPassphrase",
+ 0, 1);
histogram_tester.ExpectBucketCount(
- "PasswordManager.TimesPasswordUsed.Overall.WithoutCustomPassphrase", 1,
- 1);
+ "PasswordManager.ProfileStore.TimesPasswordUsed2."
+ "Overall."
+ "WithoutCustomPassphrase",
+ 1, 1);
histogram_tester.ExpectBucketCount(
- "PasswordManager.TimesPasswordUsed.Overall.WithoutCustomPassphrase", 2,
- 1);
+ "PasswordManager.ProfileStore.TimesPasswordUsed2."
+ "Overall."
+ "WithoutCustomPassphrase",
+ 2, 1);
// The bucket for 3 and 4 is the same. Thus we expect two samples here.
histogram_tester.ExpectBucketCount(
- "PasswordManager.TimesPasswordUsed.Overall.WithoutCustomPassphrase", 3,
- 2);
+ "PasswordManager.ProfileStore.TimesPasswordUsed2."
+ "Overall."
+ "WithoutCustomPassphrase",
+ 3, 2);
account_store->ShutdownOnUIThread();
profile_store->ShutdownOnUIThread();
@@ -384,25 +462,30 @@ TEST_F(StoreMetricsReporterTest,
RunUntilIdle();
histogram_tester.ExpectUniqueSample(
- "PasswordManager.AccountStore.AccountsPerSiteHiRes.AutoGenerated."
+ "PasswordManager.AccountStore.AccountsPerSiteHiRes2."
+ "AutoGenerated."
"WithoutCustomPassphrase",
1, 2);
histogram_tester.ExpectBucketCount(
- "PasswordManager.AccountStore.AccountsPerSiteHiRes.UserCreated."
+ "PasswordManager.AccountStore.AccountsPerSiteHiRes2."
+ "UserCreated."
"WithoutCustomPassphrase",
1, 3);
histogram_tester.ExpectBucketCount(
- "PasswordManager.AccountStore.AccountsPerSiteHiRes.UserCreated."
+ "PasswordManager.AccountStore.AccountsPerSiteHiRes2."
+ "UserCreated."
"WithoutCustomPassphrase",
2, 2);
histogram_tester.ExpectBucketCount(
- "PasswordManager.AccountStore.AccountsPerSiteHiRes.Overall."
+ "PasswordManager.AccountStore.AccountsPerSiteHiRes2."
+ "Overall."
"WithoutCustomPassphrase",
1, 5);
histogram_tester.ExpectBucketCount(
- "PasswordManager.AccountStore.AccountsPerSiteHiRes.Overall."
+ "PasswordManager.AccountStore.AccountsPerSiteHiRes2."
+ "Overall."
"WithoutCustomPassphrase",
2, 2);
@@ -445,31 +528,43 @@ TEST_F(StoreMetricsReporterTest,
RunUntilIdle();
histogram_tester.ExpectUniqueSample(
- "PasswordManager.AccountStore.TotalAccountsHiRes.ByType.AutoGenerated."
+ "PasswordManager.AccountStore.TotalAccountsHiRes2."
+ "ByType.AutoGenerated."
"WithoutCustomPassphrase",
2, 1);
histogram_tester.ExpectUniqueSample(
- "PasswordManager.AccountStore.TotalAccountsHiRes.ByType.UserCreated."
+ "PasswordManager.AccountStore.TotalAccountsHiRes2."
+ "ByType.UserCreated."
"WithoutCustomPassphrase",
7, 1);
histogram_tester.ExpectUniqueSample(
- "PasswordManager.AccountStore.TotalAccountsHiRes.ByType.Overall."
+ "PasswordManager.AccountStore.TotalAccountsHiRes2."
+ "ByType.Overall."
"WithoutCustomPassphrase",
9, 1);
histogram_tester.ExpectUniqueSample(
- "PasswordManager.AccountStore.TotalAccountsHiRes.WithScheme.Android", 2,
- 1);
+ "PasswordManager.AccountStore.TotalAccountsHiRes2."
+ "WithScheme.Android",
+ 2, 1);
histogram_tester.ExpectUniqueSample(
- "PasswordManager.AccountStore.TotalAccountsHiRes.WithScheme.Ftp", 1, 1);
+ "PasswordManager.AccountStore.TotalAccountsHiRes2."
+ "WithScheme.Ftp",
+ 1, 1);
histogram_tester.ExpectUniqueSample(
- "PasswordManager.AccountStore.TotalAccountsHiRes.WithScheme.Http", 5, 1);
+ "PasswordManager.AccountStore.TotalAccountsHiRes2."
+ "WithScheme.Http",
+ 5, 1);
histogram_tester.ExpectUniqueSample(
- "PasswordManager.AccountStore.TotalAccountsHiRes.WithScheme.Https", 1, 1);
+ "PasswordManager.AccountStore.TotalAccountsHiRes2."
+ "WithScheme.Https",
+ 1, 1);
histogram_tester.ExpectUniqueSample(
- "PasswordManager.AccountStore.TotalAccountsHiRes.WithScheme.Other", 0, 1);
+ "PasswordManager.AccountStore.TotalAccountsHiRes2."
+ "WithScheme.Other",
+ 0, 1);
account_store->ShutdownOnUIThread();
profile_store->ShutdownOnUIThread();
@@ -510,42 +605,51 @@ TEST_F(StoreMetricsReporterTest,
RunUntilIdle();
histogram_tester.ExpectBucketCount(
- "PasswordManager.AccountStore.TimesPasswordUsed.AutoGenerated."
+ "PasswordManager.AccountStore.TimesPasswordUsed2."
+ "AutoGenerated."
"WithoutCustomPassphrase",
2, 1);
histogram_tester.ExpectBucketCount(
- "PasswordManager.AccountStore.TimesPasswordUsed.AutoGenerated."
+ "PasswordManager.AccountStore.TimesPasswordUsed2."
+ "AutoGenerated."
"WithoutCustomPassphrase",
4, 1);
histogram_tester.ExpectBucketCount(
- "PasswordManager.AccountStore.TimesPasswordUsed.UserCreated."
+ "PasswordManager.AccountStore.TimesPasswordUsed2."
+ "UserCreated."
"WithoutCustomPassphrase",
0, 1);
histogram_tester.ExpectBucketCount(
- "PasswordManager.AccountStore.TimesPasswordUsed.UserCreated."
+ "PasswordManager.AccountStore.TimesPasswordUsed2."
+ "UserCreated."
"WithoutCustomPassphrase",
1, 1);
histogram_tester.ExpectBucketCount(
- "PasswordManager.AccountStore.TimesPasswordUsed.UserCreated."
+ "PasswordManager.AccountStore.TimesPasswordUsed2."
+ "UserCreated."
"WithoutCustomPassphrase",
3, 1);
histogram_tester.ExpectBucketCount(
- "PasswordManager.AccountStore.TimesPasswordUsed.Overall."
+ "PasswordManager.AccountStore.TimesPasswordUsed2."
+ "Overall."
"WithoutCustomPassphrase",
0, 1);
histogram_tester.ExpectBucketCount(
- "PasswordManager.AccountStore.TimesPasswordUsed.Overall."
+ "PasswordManager.AccountStore.TimesPasswordUsed2."
+ "Overall."
"WithoutCustomPassphrase",
1, 1);
histogram_tester.ExpectBucketCount(
- "PasswordManager.AccountStore.TimesPasswordUsed.Overall."
+ "PasswordManager.AccountStore.TimesPasswordUsed2."
+ "Overall."
"WithoutCustomPassphrase",
2, 1);
// The bucket for 3 and 4 is the same. Thus we expect two samples here.
histogram_tester.ExpectBucketCount(
- "PasswordManager.AccountStore.TimesPasswordUsed.Overall."
+ "PasswordManager.AccountStore.TimesPasswordUsed2."
+ "Overall."
"WithoutCustomPassphrase",
3, 2);
@@ -602,11 +706,12 @@ TEST_F(StoreMetricsReporterTest, DuplicatesMetrics_NoDuplicates) {
RunUntilIdle();
EXPECT_THAT(histogram_tester.GetAllSamples(
- "PasswordManager.CredentialsWithDuplicates"),
- testing::ElementsAre(base::Bucket(0, 1)));
- EXPECT_THAT(histogram_tester.GetAllSamples(
- "PasswordManager.CredentialsWithMismatchedDuplicates"),
+ "PasswordManager.CredentialsWithDuplicates2"),
testing::ElementsAre(base::Bucket(0, 1)));
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples("PasswordManager."
+ "CredentialsWithMismatchedDuplicates2"),
+ testing::ElementsAre(base::Bucket(0, 1)));
profile_store->ShutdownOnUIThread();
// Make sure the PasswordStore destruction parts on the background sequence
@@ -654,11 +759,12 @@ TEST_F(StoreMetricsReporterTest, DuplicatesMetrics_ExactDuplicates) {
// There should be 2 groups of "exact" duplicates.
EXPECT_THAT(histogram_tester.GetAllSamples(
- "PasswordManager.CredentialsWithDuplicates"),
+ "PasswordManager.CredentialsWithDuplicates2"),
testing::ElementsAre(base::Bucket(2, 1)));
- EXPECT_THAT(histogram_tester.GetAllSamples(
- "PasswordManager.CredentialsWithMismatchedDuplicates"),
- testing::ElementsAre(base::Bucket(0, 1)));
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples("PasswordManager."
+ "CredentialsWithMismatchedDuplicates2"),
+ testing::ElementsAre(base::Bucket(0, 1)));
profile_store->ShutdownOnUIThread();
// Make sure the PasswordStore destruction parts on the background sequence
@@ -703,11 +809,12 @@ TEST_F(StoreMetricsReporterTest, DuplicatesMetrics_MismatchedDuplicates) {
RunUntilIdle();
EXPECT_THAT(histogram_tester.GetAllSamples(
- "PasswordManager.CredentialsWithDuplicates"),
+ "PasswordManager.CredentialsWithDuplicates2"),
testing::ElementsAre(base::Bucket(0, 1)));
- EXPECT_THAT(histogram_tester.GetAllSamples(
- "PasswordManager.CredentialsWithMismatchedDuplicates"),
- testing::ElementsAre(base::Bucket(1, 1)));
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples("PasswordManager."
+ "CredentialsWithMismatchedDuplicates2"),
+ testing::ElementsAre(base::Bucket(1, 1)));
profile_store->ShutdownOnUIThread();
// Make sure the PasswordStore destruction parts on the background sequence
@@ -791,6 +898,12 @@ TEST_F(StoreMetricsReporterTest, MultiStoreMetrics) {
sync_service());
}
+ // In every pass in the loop, StoreMetricsReporter uses the same pref
+ // service. Set the kLastTimePasswordStoreMetricsReported to make sure
+ // metrics will be reported in the second pass too.
+ prefs_.SetDouble(
+ password_manager::prefs::kLastTimePasswordStoreMetricsReported, 0.0);
+
base::HistogramTester histogram_tester;
StoreMetricsReporter reporter(profile_store.get(), account_store.get(),
@@ -805,22 +918,38 @@ TEST_F(StoreMetricsReporterTest, MultiStoreMetrics) {
if (opted_in) {
histogram_tester.ExpectUniqueSample(
- "PasswordManager.AccountStoreVsProfileStore2.Additional", 2, 1);
+ "PasswordManager.AccountStoreVsProfileStore3."
+ "Additional",
+ 2, 1);
histogram_tester.ExpectUniqueSample(
- "PasswordManager.AccountStoreVsProfileStore2.Missing", 4, 1);
+ "PasswordManager.AccountStoreVsProfileStore3."
+ "Missing",
+ 4, 1);
histogram_tester.ExpectUniqueSample(
- "PasswordManager.AccountStoreVsProfileStore2.Identical", 2, 1);
+ "PasswordManager.AccountStoreVsProfileStore3."
+ "Identical",
+ 2, 1);
histogram_tester.ExpectUniqueSample(
- "PasswordManager.AccountStoreVsProfileStore2.Conflicting", 1, 1);
+ "PasswordManager.AccountStoreVsProfileStore3."
+ "Conflicting",
+ 1, 1);
} else {
histogram_tester.ExpectTotalCount(
- "PasswordManager.AccountStoreVsProfileStore2.Additional", 0);
+ "PasswordManager.AccountStoreVsProfileStore3."
+ "Additional",
+ 0);
histogram_tester.ExpectTotalCount(
- "PasswordManager.AccountStoreVsProfileStore2.Missing", 0);
+ "PasswordManager.AccountStoreVsProfileStore3."
+ "Missing",
+ 0);
histogram_tester.ExpectTotalCount(
- "PasswordManager.AccountStoreVsProfileStore2.Identical", 0);
+ "PasswordManager.AccountStoreVsProfileStore3."
+ "Identical",
+ 0);
histogram_tester.ExpectTotalCount(
- "PasswordManager.AccountStoreVsProfileStore2.Conflicting", 0);
+ "PasswordManager.AccountStoreVsProfileStore3."
+ "Conflicting",
+ 0);
}
}
diff --git a/chromium/components/password_manager/core/browser/stub_password_manager_client.cc b/chromium/components/password_manager/core/browser/stub_password_manager_client.cc
index 553860c1d37..af829d6a13f 100644
--- a/chromium/components/password_manager/core/browser/stub_password_manager_client.cc
+++ b/chromium/components/password_manager/core/browser/stub_password_manager_client.cc
@@ -85,6 +85,11 @@ PasswordScriptsFetcher* StubPasswordManagerClient::GetPasswordScriptsFetcher() {
return nullptr;
}
+MockPasswordChangeSuccessTracker*
+StubPasswordManagerClient::GetPasswordChangeSuccessTracker() {
+ return &password_change_success_tracker_;
+}
+
const GURL& StubPasswordManagerClient::GetLastCommittedURL() const {
return GURL::EmptyGURL();
}
@@ -138,7 +143,7 @@ ukm::SourceId StubPasswordManagerClient::GetUkmSourceId() {
PasswordManagerMetricsRecorder*
StubPasswordManagerClient::GetMetricsRecorder() {
if (!metrics_recorder_) {
- metrics_recorder_.emplace(GetUkmSourceId(), nullptr);
+ metrics_recorder_.emplace(GetUkmSourceId());
}
return base::OptionalOrNullptr(metrics_recorder_);
}
diff --git a/chromium/components/password_manager/core/browser/stub_password_manager_client.h b/chromium/components/password_manager/core/browser/stub_password_manager_client.h
index 83d05019ad4..1290fc7cbc8 100644
--- a/chromium/components/password_manager/core/browser/stub_password_manager_client.h
+++ b/chromium/components/password_manager/core/browser/stub_password_manager_client.h
@@ -6,6 +6,7 @@
#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_STUB_PASSWORD_MANAGER_CLIENT_H_
#include "components/autofill/core/browser/logging/stub_log_manager.h"
+#include "components/password_manager/core/browser/mock_password_change_success_tracker.h"
#include "components/password_manager/core/browser/mock_password_feature_manager.h"
#include "components/password_manager/core/browser/password_manager_client.h"
#include "components/password_manager/core/browser/password_manager_metrics_recorder.h"
@@ -63,6 +64,7 @@ class StubPasswordManagerClient : public PasswordManagerClient {
PasswordStoreInterface* GetAccountPasswordStore() const override;
PasswordReuseManager* GetPasswordReuseManager() const override;
PasswordScriptsFetcher* GetPasswordScriptsFetcher() override;
+ MockPasswordChangeSuccessTracker* GetPasswordChangeSuccessTracker() override;
const GURL& GetLastCommittedURL() const override;
url::Origin GetLastCommittedOrigin() const override;
const CredentialsFilter* GetStoreResultFilter() const override;
@@ -103,6 +105,8 @@ class StubPasswordManagerClient : public PasswordManagerClient {
autofill::StubLogManager log_manager_;
ukm::SourceId ukm_source_id_;
absl::optional<PasswordManagerMetricsRecorder> metrics_recorder_;
+ testing::NiceMock<MockPasswordChangeSuccessTracker>
+ password_change_success_tracker_;
};
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/stub_password_manager_driver.cc b/chromium/components/password_manager/core/browser/stub_password_manager_driver.cc
index 4c26ede7c21..f91c367b00e 100644
--- a/chromium/components/password_manager/core/browser/stub_password_manager_driver.cc
+++ b/chromium/components/password_manager/core/browser/stub_password_manager_driver.cc
@@ -26,6 +26,10 @@ void StubPasswordManagerDriver::FillSuggestion(const std::u16string& username,
const std::u16string& password) {
}
+#if BUILDFLAG(IS_ANDROID)
+void StubPasswordManagerDriver::TriggerFormSubmission() {}
+#endif
+
void StubPasswordManagerDriver::PreviewSuggestion(
const std::u16string& username,
const std::u16string& password) {}
diff --git a/chromium/components/password_manager/core/browser/stub_password_manager_driver.h b/chromium/components/password_manager/core/browser/stub_password_manager_driver.h
index ea4f7f15fcc..802661f6dc4 100644
--- a/chromium/components/password_manager/core/browser/stub_password_manager_driver.h
+++ b/chromium/components/password_manager/core/browser/stub_password_manager_driver.h
@@ -29,6 +29,9 @@ class StubPasswordManagerDriver : public PasswordManagerDriver {
void GeneratedPasswordAccepted(const std::u16string& password) override;
void FillSuggestion(const std::u16string& username,
const std::u16string& password) override;
+#if BUILDFLAG(IS_ANDROID)
+ void TriggerFormSubmission() override;
+#endif
void PreviewSuggestion(const std::u16string& username,
const std::u16string& password) override;
void ClearPreviewedForm() override;
diff --git a/chromium/components/password_manager/core/browser/sync/password_proto_utils.cc b/chromium/components/password_manager/core/browser/sync/password_proto_utils.cc
index 900fb88abb5..add243a2672 100644
--- a/chromium/components/password_manager/core/browser/sync/password_proto_utils.cc
+++ b/chromium/components/password_manager/core/browser/sync/password_proto_utils.cc
@@ -28,13 +28,13 @@ sync_pb::PasswordSpecificsData_PasswordIssues PasswordIssuesMapToProto(
const base::flat_map<InsecureType, InsecurityMetadata>&
form_password_issues) {
sync_pb::PasswordSpecificsData::PasswordIssues password_issues;
- for (const auto& form_issue : form_password_issues) {
+ for (const auto& [insecure_type, insecure_metadata] : form_password_issues) {
sync_pb::PasswordSpecificsData::PasswordIssues::PasswordIssue issue;
issue.set_date_first_detection_microseconds(
- form_issue.second.create_time.ToDeltaSinceWindowsEpoch()
+ insecure_metadata.create_time.ToDeltaSinceWindowsEpoch()
.InMicroseconds());
- issue.set_is_muted(form_issue.second.is_muted.value());
- switch (form_issue.first) {
+ issue.set_is_muted(insecure_metadata.is_muted.value());
+ switch (insecure_type) {
case InsecureType::kLeaked:
DCHECK(!password_issues.has_leaked_password_issue());
*password_issues.mutable_leaked_password_issue() = std::move(issue);
diff --git a/chromium/components/password_manager/core/browser/sync/password_sync_bridge.cc b/chromium/components/password_manager/core/browser/sync/password_sync_bridge.cc
index 69e634ddb96..ea76ccf59bd 100644
--- a/chromium/components/password_manager/core/browser/sync/password_sync_bridge.cc
+++ b/chromium/components/password_manager/core/browser/sync/password_sync_bridge.cc
@@ -11,6 +11,7 @@
#include "base/callback.h"
#include "base/check_op.h"
#include "base/containers/flat_map.h"
+#include "base/feature_list.h"
#include "base/memory/raw_ptr.h"
#include "base/metrics/histogram_functions.h"
#include "base/notreached.h"
@@ -21,6 +22,7 @@
#include "components/password_manager/core/browser/password_form.h"
#include "components/password_manager/core/browser/password_manager_metrics_util.h"
#include "components/password_manager/core/browser/password_store_change.h"
+#include "components/password_manager/core/browser/password_store_sync.h"
#include "components/password_manager/core/browser/sync/password_proto_utils.h"
#include "components/password_manager/core/common/password_manager_features.h"
#include "components/sync/model/in_memory_metadata_change_list.h"
@@ -48,8 +50,11 @@ enum class SyncMetadataReadError {
kDbNotAvailable = 1,
// Reading failure.
kReadFailed = 2,
+ // Reading successful but cleaning initiated in order to force initial sync.
+ // This will clean undecryptable passwords.
+ kReadSuccessButCleared = 3,
- kMaxValue = kReadFailed,
+ kMaxValue = kReadSuccessButCleared,
};
std::string ComputeClientTag(
@@ -178,13 +183,38 @@ bool AreLocalAndRemotePasswordsEqual(
// merge.
bool ShouldRecoverPasswordsDuringMerge() {
// Delete the local undecryptable copy when this is MacOS only.
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
return true;
+#elif BUILDFLAG(IS_LINUX)
+ return base::FeatureList::IsEnabled(
+ features::kSyncUndecryptablePasswordsLinux);
#else
return false;
#endif
}
+bool ShouldCleanSyncMetadataDuringStartupWhenDecryptionFails() {
+#if BUILDFLAG(IS_LINUX)
+ return ShouldRecoverPasswordsDuringMerge() &&
+ base::FeatureList::IsEnabled(
+ features::kForceInitialSyncWhenDecryptionFails);
+#else
+ return false;
+#endif
+}
+
+bool DoesPasswordStoreHaveEncryptionServiceFailures(
+ PasswordStoreSync* password_store_sync) {
+ PrimaryKeyToFormMap key_to_form_map;
+ FormRetrievalResult result =
+ password_store_sync->ReadAllLogins(&key_to_form_map);
+ if (result == FormRetrievalResult::kEncryptionServiceFailure ||
+ result == FormRetrievalResult::kEncryptionServiceFailureWithPartialData) {
+ return true;
+ }
+ return false;
+}
+
// A simple class for scoping a password store sync transaction. If the
// transaction hasn't been committed, it will be rolled back when it goes out of
// scope.
@@ -244,6 +274,14 @@ PasswordSyncBridge::PasswordSyncBridge(
password_store_sync_->GetMetadataStore()->DeleteAllSyncMetadata();
batch = std::make_unique<syncer::MetadataBatch>();
sync_metadata_read_error = SyncMetadataReadError::kReadFailed;
+ } else if (ShouldCleanSyncMetadataDuringStartupWhenDecryptionFails() &&
+ DoesPasswordStoreHaveEncryptionServiceFailures(
+ password_store_sync_)) {
+ // Some logins in the passwords store cannot be read, force initial sync
+ // by dropping the metadata.
+ password_store_sync_->GetMetadataStore()->DeleteAllSyncMetadata();
+ batch = std::make_unique<syncer::MetadataBatch>();
+ sync_metadata_read_error = SyncMetadataReadError::kReadSuccessButCleared;
}
}
base::UmaHistogramEnumeration("PasswordManager.SyncMetadataReadError",
@@ -314,7 +352,6 @@ absl::optional<syncer::ModelError> PasswordSyncBridge::MergeSyncData(
// 3. |F| exists in both the local and the remote models --> both versions
// should be merged by accepting the most recently created one, and update
// local and remote models accordingly.
-
base::AutoReset<bool> processing_changes(&is_processing_remote_sync_changes_,
true);
@@ -328,7 +365,9 @@ absl::optional<syncer::ModelError> PasswordSyncBridge::MergeSyncData(
return syncer::ModelError(FROM_HERE,
"Failed to load entries from password store.");
}
- if (read_result == FormRetrievalResult::kEncrytionServiceFailure) {
+ if (read_result == FormRetrievalResult::kEncryptionServiceFailure ||
+ read_result ==
+ FormRetrievalResult::kEncryptionServiceFailureWithPartialData) {
if (!ShouldRecoverPasswordsDuringMerge()) {
metrics_util::LogPasswordSyncState(
metrics_util::NOT_SYNCING_FAILED_DECRYPTION);
@@ -376,12 +415,10 @@ absl::optional<syncer::ModelError> PasswordSyncBridge::MergeSyncData(
// created version. Password comparison is done by comparing the client
// tags. In addition, collect the client tags of local passwords.
std::unordered_set<std::string> client_tags_of_local_passwords;
- for (const auto& pair : key_to_local_form_map) {
- const FormPrimaryKey primary_key = pair.first;
- const PasswordForm& local_password_form = *pair.second;
-
+ for (const auto& [primary_key, local_password_form] :
+ key_to_local_form_map) {
std::unique_ptr<syncer::EntityData> local_form_entity_data =
- CreateEntityData(local_password_form);
+ CreateEntityData(*local_password_form);
const std::string client_tag_of_local_password =
GetClientTag(*local_form_entity_data);
client_tags_of_local_passwords.insert(client_tag_of_local_password);
@@ -412,17 +449,17 @@ absl::optional<syncer::ModelError> PasswordSyncBridge::MergeSyncData(
metadata_change_list.get());
if (AreLocalAndRemotePasswordsEqual(remote_password_specifics,
- local_password_form)) {
+ *local_password_form)) {
// Passwords are identical, nothing else to do.
continue;
}
// Passwords or insecure credentials aren't identical.
if (ConvertToBaseTime(remote_password_specifics.date_created()) <
- local_password_form.date_created ||
+ local_password_form->date_created ||
(AreLocalAndRemotePasswordsEqualExcludingIssues(
- remote_password_specifics, local_password_form) &&
- local_password_form.IsInsecureCredential(InsecureType::kPhished))) {
+ remote_password_specifics, *local_password_form) &&
+ local_password_form->IsInsecureCredential(InsecureType::kPhished))) {
// Either the local password is more recent, or they are equal but the
// local password has been marked as phished. While all other types of
// issues are easy to recompute (e.g. via Password Check) phished
@@ -760,11 +797,10 @@ void PasswordSyncBridge::GetAllDataForDebugging(DataCallback callback) {
}
auto batch = std::make_unique<syncer::MutableDataBatch>();
- for (const auto& pair : key_to_form_map) {
- PasswordForm form = *pair.second;
- form.password_value = u"<redacted>";
- batch->Put(base::NumberToString(pair.first.value()),
- CreateEntityData(form));
+ for (const auto& [primary_key, form] : key_to_form_map) {
+ form->password_value = u"<redacted>";
+ batch->Put(base::NumberToString(primary_key.value()),
+ CreateEntityData(*form));
}
std::move(callback).Run(std::move(batch));
}
@@ -795,6 +831,7 @@ void PasswordSyncBridge::ApplyStopSyncChanges(
}
if (!password_store_sync_->IsAccountStore()) {
password_store_sync_->GetMetadataStore()->DeleteAllSyncMetadata();
+ sync_enabled_or_disabled_cb_.Run();
return;
}
// For the account store, the data should be deleted too. So do the following:
@@ -815,14 +852,12 @@ void PasswordSyncBridge::ApplyStopSyncChanges(
if (result == FormRetrievalResult::kSuccess) {
std::set<FormPrimaryKey> unsynced_passwords_storage_keys =
GetUnsyncedPasswordsStorageKeys();
- for (const auto& primary_key_and_form : logins) {
- FormPrimaryKey primary_key = primary_key_and_form.first;
- const PasswordForm& form = *primary_key_and_form.second;
- password_store_changes.emplace_back(PasswordStoreChange::REMOVE, form,
+ for (const auto& [primary_key, form] : logins) {
+ password_store_changes.emplace_back(PasswordStoreChange::REMOVE, *form,
primary_key);
if (unsynced_passwords_storage_keys.count(primary_key) != 0 &&
- !form.blocked_by_user) {
- unsynced_logins_being_deleted.push_back(form);
+ !form->blocked_by_user) {
+ unsynced_logins_being_deleted.push_back(*form);
}
}
}
@@ -854,11 +889,11 @@ std::set<FormPrimaryKey> PasswordSyncBridge::GetUnsyncedPasswordsStorageKeys() {
}
std::unique_ptr<syncer::MetadataBatch> batch =
metadata_store->GetAllSyncMetadata();
- for (const auto& metadata_entry : batch->GetAllMetadata()) {
+ for (const auto& [storage_key, metadata] : batch->GetAllMetadata()) {
// Ignore unsynced deletions.
- if (!metadata_entry.second->is_deleted() &&
- change_processor()->IsEntityUnsynced(metadata_entry.first)) {
- storage_keys.insert(ParsePrimaryKey(metadata_entry.first));
+ if (!metadata->is_deleted() &&
+ change_processor()->IsEntityUnsynced(storage_key)) {
+ storage_keys.insert(ParsePrimaryKey(storage_key));
}
}
return storage_keys;
diff --git a/chromium/components/password_manager/core/browser/sync/password_sync_bridge.h b/chromium/components/password_manager/core/browser/sync/password_sync_bridge.h
index e6e88403d2b..b549e958799 100644
--- a/chromium/components/password_manager/core/browser/sync/password_sync_bridge.h
+++ b/chromium/components/password_manager/core/browser/sync/password_sync_bridge.h
@@ -68,11 +68,11 @@ class PasswordSyncBridge : public syncer::ModelTypeSyncBridge {
const sync_pb::PasswordSpecificsData& password_data);
private:
- // On MacOS it may happen that some passwords cannot be decrypted due to
- // modification of encryption key in Keychain (https://crbug.com/730625). This
- // method deletes those logins from the store. So during merge, the data in
- // sync will be added to the password store. This should be called during
- // MergeSyncData().
+ // On MacOS or Linux it may happen that some passwords cannot be decrypted due
+ // to modification of encryption key in Keychain or Keyring
+ // (https://crbug.com/730625). This method deletes those logins from the
+ // store. So during merge, the data in sync will be added to the password
+ // store. This should be called during MergeSyncData().
absl::optional<syncer::ModelError> CleanupPasswordStore();
// Retrieves the storage keys of all unsynced passwords in the store.
diff --git a/chromium/components/password_manager/core/browser/sync/password_sync_bridge_unittest.cc b/chromium/components/password_manager/core/browser/sync/password_sync_bridge_unittest.cc
index e664f0a83f4..57c45d47af4 100644
--- a/chromium/components/password_manager/core/browser/sync/password_sync_bridge_unittest.cc
+++ b/chromium/components/password_manager/core/browser/sync/password_sync_bridge_unittest.cc
@@ -11,14 +11,17 @@
#include "base/bind.h"
#include "base/callback_helpers.h"
+#include "base/feature_list.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/mock_callback.h"
+#include "base/test/scoped_feature_list.h"
#include "build/build_config.h"
#include "components/password_manager/core/browser/insecure_credentials_table.h"
#include "components/password_manager/core/browser/password_form.h"
#include "components/password_manager/core/browser/password_store_sync.h"
+#include "components/password_manager/core/common/password_manager_features.h"
#include "components/sync/base/client_tag_hash.h"
#include "components/sync/model/data_batch.h"
#include "components/sync/model/entity_change.h"
@@ -214,8 +217,8 @@ class FakeDatabase {
FormRetrievalResult ReadAllLogins(PrimaryKeyToFormMap* map) {
map->clear();
- for (const auto& pair : data_) {
- map->emplace(pair.first, std::make_unique<PasswordForm>(*pair.second));
+ for (const auto& [primary_key, form] : data_) {
+ map->emplace(primary_key, std::make_unique<PasswordForm>(*form));
}
return FormRetrievalResult::kSuccess;
}
@@ -274,9 +277,9 @@ class FakeDatabase {
private:
FormPrimaryKey GetPrimaryKey(const PasswordForm& form) const {
- for (const auto& pair : data_) {
- if (ArePasswordFormUniqueKeysEqual(*pair.second, form)) {
- return pair.first;
+ for (const auto& [primary_key, other_form] : data_) {
+ if (ArePasswordFormUniqueKeysEqual(*other_form, form)) {
+ return primary_key;
}
}
return FormPrimaryKey(-1);
@@ -418,10 +421,10 @@ class PasswordSyncBridgeTest : public testing::Test {
if (!batch || !batch->HasNext()) {
return absl::nullopt;
}
- const syncer::KeyAndData& data_pair = batch->Next();
- EXPECT_THAT(data_pair.first, Eq(storage_key));
+ auto [other_storage_key, entity_data] = batch->Next();
+ EXPECT_THAT(other_storage_key, Eq(storage_key));
EXPECT_FALSE(batch->HasNext());
- return data_pair.second->specifics.password();
+ return entity_data->specifics.password();
}
FakeDatabase* fake_db() { return &fake_db_; }
@@ -854,6 +857,54 @@ TEST_F(PasswordSyncBridgeTest,
EXPECT_TRUE(error);
}
+#if BUILDFLAG(IS_LINUX)
+TEST_F(PasswordSyncBridgeTest, ShouldRemoveSyncMetadataWhenReadAllLoginsFails) {
+ base::HistogramTester histogram_tester;
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitWithFeatures(
+ {
+ features::kForceInitialSyncWhenDecryptionFails,
+ features::kSyncUndecryptablePasswordsLinux,
+ },
+ {});
+ ON_CALL(*mock_password_store_sync(), ReadAllLogins)
+ .WillByDefault(
+ testing::Return(FormRetrievalResult::kEncryptionServiceFailure));
+
+ EXPECT_CALL(*mock_sync_metadata_store_sync(), GetAllSyncMetadata());
+ EXPECT_CALL(*mock_password_store_sync(), ReadAllLogins)
+ .WillOnce(Return(FormRetrievalResult::kEncryptionServiceFailure));
+ EXPECT_CALL(*mock_sync_metadata_store_sync(), DeleteAllSyncMetadata());
+
+ auto bridge =
+ PasswordSyncBridge(mock_processor().CreateForwardingProcessor(),
+ mock_password_store_sync(), base::DoNothing());
+
+ histogram_tester.ExpectUniqueSample("PasswordManager.SyncMetadataReadError",
+ 3, 1);
+}
+
+TEST_F(PasswordSyncBridgeTest,
+ ShouldNotRemoveSyncMetadataWhenReadAllLoginsSucceeds) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitWithFeatures(
+ {
+ features::kForceInitialSyncWhenDecryptionFails,
+ features::kSyncUndecryptablePasswordsLinux,
+ },
+ {});
+
+ EXPECT_CALL(*mock_sync_metadata_store_sync(), GetAllSyncMetadata());
+ EXPECT_CALL(*mock_password_store_sync(), ReadAllLogins)
+ .WillOnce(Return(FormRetrievalResult::kSuccess));
+ EXPECT_CALL(*mock_sync_metadata_store_sync(), DeleteAllSyncMetadata())
+ .Times(0);
+
+ PasswordSyncBridge(mock_processor().CreateForwardingProcessor(),
+ mock_password_store_sync(), base::DoNothing());
+}
+#endif
+
// This tests that if adding logins to the store fails,
// ShouldMergeSync() would return an error without crashing.
TEST_F(PasswordSyncBridgeTest,
@@ -932,8 +983,8 @@ TEST_F(PasswordSyncBridgeTest,
ASSERT_THAT(batch, NotNull());
EXPECT_TRUE(batch->HasNext());
while (batch->HasNext()) {
- const syncer::KeyAndData& data_pair = batch->Next();
- EXPECT_EQ("<redacted>", data_pair.second->specifics.password()
+ auto [key, data] = batch->Next();
+ EXPECT_EQ("<redacted>", data->specifics.password()
.client_only_encrypted_data()
.password_value());
}
@@ -960,24 +1011,48 @@ TEST_F(PasswordSyncBridgeTest,
mock_password_store_sync(), base::DoNothing());
}
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
// Tests that in case ReadAllLogins() during initial merge returns encryption
// service failure, the bridge would try to do a DB clean up.
-TEST_F(PasswordSyncBridgeTest, ShouldDeleteUndecryptableLoginsDuringMerge) {
- ON_CALL(*mock_password_store_sync(), DeleteUndecryptableLogins())
- .WillByDefault(Return(DatabaseCleanupResult::kSuccess));
-
- // We should try to read first, and simulate an encryption failure. Then,
- // cleanup the database and try to read again which should be successful now.
- EXPECT_CALL(*mock_password_store_sync(), ReadAllLogins)
- .WillOnce(Return(FormRetrievalResult::kEncrytionServiceFailure))
- .WillOnce(Return(FormRetrievalResult::kSuccess));
- EXPECT_CALL(*mock_password_store_sync(), DeleteUndecryptableLogins());
+class PasswordSyncBridgeMergeTest
+ : public PasswordSyncBridgeTest,
+ public testing::WithParamInterface<FormRetrievalResult> {
+ protected:
+ void ShouldDeleteUndecryptableLoginsDuringMerge() {
+#if BUILDFLAG(IS_LINUX)
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeature(
+ features::kSyncUndecryptablePasswordsLinux);
+#endif
+ ON_CALL(*mock_password_store_sync(), DeleteUndecryptableLogins())
+ .WillByDefault(Return(DatabaseCleanupResult::kSuccess));
+
+ // We should try to read first, and simulate an encryption failure. Then,
+ // cleanup the database and try to read again which should be successful
+ // now.
+ testing::InSequence in_sequence;
+ EXPECT_CALL(*mock_password_store_sync(), ReadAllLogins)
+ .WillOnce(Return(GetParam()));
+ EXPECT_CALL(*mock_password_store_sync(), DeleteUndecryptableLogins());
+ EXPECT_CALL(*mock_password_store_sync(), ReadAllLogins)
+ .WillOnce(Return(FormRetrievalResult::kSuccess));
+
+ absl::optional<syncer::ModelError> error =
+ bridge()->MergeSyncData(bridge()->CreateMetadataChangeList(), {});
+ EXPECT_FALSE(error);
+ }
+};
- absl::optional<syncer::ModelError> error =
- bridge()->MergeSyncData(bridge()->CreateMetadataChangeList(), {});
- EXPECT_FALSE(error);
+TEST_P(PasswordSyncBridgeMergeTest, ShouldFixWhenDatabaseEncryptionFails) {
+ ShouldDeleteUndecryptableLoginsDuringMerge();
}
+
+INSTANTIATE_TEST_SUITE_P(
+ PasswordSyncBridgeTest,
+ PasswordSyncBridgeMergeTest,
+ testing::Values(
+ FormRetrievalResult::kEncryptionServiceFailure,
+ FormRetrievalResult::kEncryptionServiceFailureWithPartialData));
#endif
TEST_F(PasswordSyncBridgeTest,
@@ -1035,13 +1110,11 @@ TEST_F(PasswordSyncBridgeTest, ShouldNotifyOnSyncDisableIfAccountStore) {
bridge()->ApplyStopSyncChanges(bridge()->CreateMetadataChangeList());
}
-TEST_F(PasswordSyncBridgeTest, ShouldNotNotifyOnSyncDisableIfProfileStore) {
+TEST_F(PasswordSyncBridgeTest, ShouldNotifyOnSyncDisableIfProfileStore) {
ON_CALL(*mock_password_store_sync(), IsAccountStore())
.WillByDefault(Return(false));
- // The profile password store does *not* get cleared when sync is disabled, so
- // this should *not* trigger the callback.
- EXPECT_CALL(*mock_sync_enabled_or_disabled_cb(), Run()).Times(0);
+ EXPECT_CALL(*mock_sync_enabled_or_disabled_cb(), Run());
bridge()->ApplyStopSyncChanges(bridge()->CreateMetadataChangeList());
}
diff --git a/chromium/components/password_manager/core/browser/sync_credentials_filter_unittest.cc b/chromium/components/password_manager/core/browser/sync_credentials_filter_unittest.cc
index db3be06979c..4e4c29ebb9c 100644
--- a/chromium/components/password_manager/core/browser/sync_credentials_filter_unittest.cc
+++ b/chromium/components/password_manager/core/browser/sync_credentials_filter_unittest.cc
@@ -18,6 +18,7 @@
#include "base/test/scoped_feature_list.h"
#include "components/password_manager/core/browser/fake_form_fetcher.h"
#include "components/password_manager/core/browser/mock_password_store_interface.h"
+#include "components/password_manager/core/browser/mock_webauthn_credentials_delegate.h"
#include "components/password_manager/core/browser/password_form.h"
#include "components/password_manager/core/browser/password_form_manager.h"
#include "components/password_manager/core/browser/password_manager_test_utils.h"
@@ -56,6 +57,9 @@ class FakePasswordManagerClient : public StubPasswordManagerClient {
prefs_->registry()->RegisterListPref(prefs::kPasswordProtectionLoginURLs);
prefs_->SetString(prefs::kPasswordProtectionChangePasswordURL,
kEnterpriseURL);
+
+ ON_CALL(webauthn_credentials_delegate_, IsWebAuthnAutofillEnabled)
+ .WillByDefault(testing::Return(false));
}
FakePasswordManagerClient(const FakePasswordManagerClient&) = delete;
@@ -76,6 +80,9 @@ class FakePasswordManagerClient : public StubPasswordManagerClient {
signin::IdentityManager* GetIdentityManager() override {
return identity_manager_;
}
+ MockWebAuthnCredentialsDelegate* GetWebAuthnCredentialsDelegate() override {
+ return &webauthn_credentials_delegate_;
+ }
void set_last_committed_entry_url(base::StringPiece url_spec) {
last_committed_origin_ = url::Origin::Create(GURL(url_spec));
@@ -91,6 +98,7 @@ class FakePasswordManagerClient : public StubPasswordManagerClient {
url::Origin last_committed_origin_;
scoped_refptr<testing::NiceMock<MockPasswordStoreInterface>> password_store_ =
new testing::NiceMock<MockPasswordStoreInterface>;
+ MockWebAuthnCredentialsDelegate webauthn_credentials_delegate_;
bool is_incognito_ = false;
raw_ptr<signin::IdentityManager> identity_manager_;
std::unique_ptr<TestingPrefServiceSimple> prefs_;
diff --git a/chromium/components/password_manager/core/browser/test_password_store.cc b/chromium/components/password_manager/core/browser/test_password_store.cc
index 28a6675c49f..f6441154009 100644
--- a/chromium/components/password_manager/core/browser/test_password_store.cc
+++ b/chromium/components/password_manager/core/browser/test_password_store.cc
@@ -145,10 +145,6 @@ bool TestPasswordStore::IsEmpty() const {
TestPasswordStore::~TestPasswordStore() = default;
-base::WeakPtr<PasswordStoreBackend> TestPasswordStore::GetWeakPtr() {
- return weak_ptr_factory_.GetWeakPtr();
-}
-
void TestPasswordStore::InitBackend(
RemoteChangesReceived remote_form_changes_received,
base::RepeatingClosure sync_enabled_or_disabled_cb,
@@ -258,6 +254,10 @@ TestPasswordStore::CreateSyncControllerDelegate() {
return nullptr;
}
+void TestPasswordStore::ClearAllLocalPasswords() {
+ NOTIMPLEMENTED();
+}
+
bool TestPasswordStore::IsAccountStore() const {
return is_account_store_.value();
}
diff --git a/chromium/components/password_manager/core/browser/test_password_store.h b/chromium/components/password_manager/core/browser/test_password_store.h
index da5b07129a4..12e185ba105 100644
--- a/chromium/components/password_manager/core/browser/test_password_store.h
+++ b/chromium/components/password_manager/core/browser/test_password_store.h
@@ -65,7 +65,6 @@ class TestPasswordStore : public PasswordStore, public PasswordStoreBackend {
~TestPasswordStore() override;
// PasswordStoreBackend interface
- base::WeakPtr<PasswordStoreBackend> GetWeakPtr() override;
void InitBackend(RemoteChangesReceived remote_form_changes_received,
base::RepeatingClosure sync_enabled_or_disabled_cb,
base::OnceCallback<void(bool)> completion) override;
@@ -99,6 +98,7 @@ class TestPasswordStore : public PasswordStore, public PasswordStoreBackend {
FieldInfoStore* GetFieldInfoStore() override;
std::unique_ptr<syncer::ProxyModelTypeControllerDelegate>
CreateSyncControllerDelegate() override;
+ void ClearAllLocalPasswords() override;
private:
LoginsResult GetAllLoginsInternal();
@@ -126,8 +126,6 @@ class TestPasswordStore : public PasswordStore, public PasswordStoreBackend {
// Number of calls of FillMatchingLogins() method.
int fill_matching_logins_calls_ = 0;
-
- base::WeakPtrFactory<TestPasswordStore> weak_ptr_factory_{this};
};
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/ui/insecure_credentials_manager.cc b/chromium/components/password_manager/core/browser/ui/insecure_credentials_manager.cc
index 826dec7ca76..fb1727e21b2 100644
--- a/chromium/components/password_manager/core/browser/ui/insecure_credentials_manager.cc
+++ b/chromium/components/password_manager/core/browser/ui/insecure_credentials_manager.cc
@@ -27,7 +27,7 @@
#include "components/password_manager/core/browser/ui/saved_passwords_presenter.h"
#include "components/password_manager/core/common/password_manager_features.h"
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
#include "components/password_manager/core/browser/ui/weak_check_utility.h"
#endif
@@ -38,6 +38,7 @@ struct CredentialMetadata {
std::vector<PasswordForm> forms;
InsecureCredentialTypeFlags type = InsecureCredentialTypeFlags::kSecure;
base::Time latest_time;
+ IsMuted is_muted;
};
namespace {
@@ -123,6 +124,7 @@ CredentialPasswordsMap GetInsecureCredentialsFromPasswords(
credential_to_form.type |= ConvertInsecureType(pair.first);
credential_to_form.latest_time =
std::max(credential_to_form.latest_time, pair.second.create_time);
+ credential_to_form.is_muted = pair.second.is_muted;
}
// Populate the map. The values are vectors, because it is
// possible that multiple saved passwords match to the same
@@ -155,6 +157,7 @@ std::vector<CredentialWithPassword> ExtractInsecureCredentials(
CredentialWithPassword credential(credential_to_forms.first);
credential.insecure_type = credential_to_forms.second.type;
credential.create_time = credential_to_forms.second.latest_time;
+ credential.is_muted = credential_to_forms.second.is_muted;
credentials.push_back(std::move(credential));
}
}
@@ -162,13 +165,13 @@ std::vector<CredentialWithPassword> ExtractInsecureCredentials(
}
// The function is only used by the weak check.
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
base::flat_set<std::u16string> ExtractPasswords(
SavedPasswordsPresenter::SavedPasswordsView password_forms) {
return base::MakeFlatSet<std::u16string>(password_forms, {},
&PasswordForm::password_value);
}
-#endif // !defined(OS_ANDROID) && !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
} // namespace
@@ -214,7 +217,8 @@ CredentialWithPassword::CredentialWithPassword(
/*password=*/{},
/*last_used_time=*/base::Time()),
create_time(credential.create_time),
- insecure_type(ConvertInsecureType(credential.insecure_type)) {}
+ insecure_type(ConvertInsecureType(credential.insecure_type)),
+ is_muted(credential.is_muted) {}
CredentialWithPassword& CredentialWithPassword::operator=(
const CredentialWithPassword& other) = default;
@@ -235,7 +239,7 @@ InsecureCredentialsManager::~InsecureCredentialsManager() = default;
void InsecureCredentialsManager::Init() {}
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
void InsecureCredentialsManager::StartWeakCheck(
base::OnceClosure on_check_done) {
base::ThreadPool::PostTaskAndReplyWithResult(
@@ -246,7 +250,7 @@ void InsecureCredentialsManager::StartWeakCheck(
weak_ptr_factory_.GetWeakPtr(), base::ElapsedTimer())
.Then(std::move(on_check_done)));
}
-#endif // !defined(OS_ANDROID) && !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
void InsecureCredentialsManager::SaveInsecureCredential(
const LeakCheckCredential& credential) {
@@ -257,7 +261,8 @@ void InsecureCredentialsManager::SaveInsecureCredential(
for (const PasswordForm& saved_password : presenter_->GetSavedPasswords()) {
if (saved_password.password_value == credential.password() &&
CanonicalizeUsername(saved_password.username_value) ==
- canonicalized_username) {
+ canonicalized_username &&
+ !saved_password.password_issues.contains(InsecureType::kLeaked)) {
PasswordForm form_to_update = saved_password;
form_to_update.password_issues.insert_or_assign(
InsecureType::kLeaked,
@@ -267,6 +272,69 @@ void InsecureCredentialsManager::SaveInsecureCredential(
}
}
+bool InsecureCredentialsManager::MuteCredential(
+ const CredentialView& credential) {
+ auto it = credentials_to_forms_.find(credential);
+ if (it == credentials_to_forms_.end())
+ return false;
+
+ // Mute all matching compromised credentials from the store.
+ // For a match, all insecureity types saved in the store are muted.
+ // Return whether any credentials were muted.
+ const auto& saved_passwords = it->second.forms;
+ bool muted = false;
+ for (const PasswordForm& saved_password : saved_passwords) {
+ PasswordForm form_to_update = saved_password;
+ bool form_changed = false;
+ for (const auto& password_issue : saved_password.password_issues) {
+ if (!password_issue.second.is_muted.value()) {
+ form_to_update.password_issues.insert_or_assign(
+ password_issue.first,
+ InsecurityMetadata(password_issue.second.create_time,
+ IsMuted(true)));
+ form_changed = true;
+ }
+ }
+ if (form_changed) {
+ GetStoreFor(saved_password).UpdateLogin(form_to_update);
+ muted = true;
+ }
+ }
+ return muted;
+}
+
+bool InsecureCredentialsManager::UnmuteCredential(
+ const CredentialView& credential) {
+ auto it = credentials_to_forms_.find(credential);
+ if (it == credentials_to_forms_.end())
+ return false;
+
+ // Unmute all matching compromised credentials from the store.
+ // For a match, all insecureity types saved in the store are unmuted.
+ // Return whether any credentials were unmuted.
+ const auto& saved_passwords = it->second.forms;
+ bool unmuted = false;
+
+ for (const PasswordForm& saved_password : saved_passwords) {
+ PasswordForm form_to_update = saved_password;
+ bool form_changed = false;
+ for (const auto& password_issue : saved_password.password_issues) {
+ if (password_issue.second.is_muted.value()) {
+ form_to_update.password_issues.insert_or_assign(
+ password_issue.first,
+ InsecurityMetadata(password_issue.second.create_time,
+ IsMuted(false)));
+ form_changed = true;
+ }
+ }
+ if (form_changed) {
+ GetStoreFor(saved_password).UpdateLogin(form_to_update);
+ unmuted = true;
+ }
+ }
+ return unmuted;
+}
+
bool InsecureCredentialsManager::UpdateCredential(
const CredentialView& credential,
const base::StringPiece password) {
@@ -356,7 +424,7 @@ void InsecureCredentialsManager::OnWeakCheckDone(
void InsecureCredentialsManager::OnEdited(const PasswordForm& form) {
// The WeakCheck is a Desktop only feature for now. Disable on Mobile to avoid
// pulling in a big dependency on zxcvbn.
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
const std::u16string& password = form.password_value;
if (weak_passwords_.contains(password) || !IsWeak(password)) {
// Either the password is already known to be weak, or it is not weak at
diff --git a/chromium/components/password_manager/core/browser/ui/insecure_credentials_manager.h b/chromium/components/password_manager/core/browser/ui/insecure_credentials_manager.h
index 68a8fcb8193..bbb06fc23c2 100644
--- a/chromium/components/password_manager/core/browser/ui/insecure_credentials_manager.h
+++ b/chromium/components/password_manager/core/browser/ui/insecure_credentials_manager.h
@@ -115,7 +115,6 @@ struct CredentialView {
struct CredentialWithPassword : CredentialView {
explicit CredentialWithPassword(const CredentialView& credential);
explicit CredentialWithPassword(const InsecureCredential& credential);
-
CredentialWithPassword(const CredentialWithPassword& other);
CredentialWithPassword(CredentialWithPassword&& other);
~CredentialWithPassword();
@@ -125,6 +124,7 @@ struct CredentialWithPassword : CredentialView {
base::Time create_time;
InsecureCredentialTypeFlags insecure_type =
InsecureCredentialTypeFlags::kSecure;
+ IsMuted is_muted{false};
};
// Comparator that can compare CredentialView or CredentialsWithPasswords.
@@ -139,10 +139,10 @@ struct PasswordCredentialLess {
struct CredentialMetadata;
// This class provides clients with saved insecure credentials and possibility
-// to save new LeakedCredentials, edit/delete insecure credentials and match
-// insecure credentials with corresponding autofill::PasswordForms. It supports
-// an observer interface, and clients can register themselves to get notified
-// about changes to the list.
+// to save new LeakedCredentials, edit/delete/[un]mute insecure credentials and
+// match insecure credentials with corresponding autofill::PasswordForms. It
+// supports an observer interface, and clients can register themselves to get
+// notified about changes to the list.
class InsecureCredentialsManager : public SavedPasswordsPresenter::Observer {
public:
using CredentialsView = base::span<const CredentialWithPassword>;
@@ -165,7 +165,7 @@ class InsecureCredentialsManager : public SavedPasswordsPresenter::Observer {
void Init();
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
// Computes weak credentials in a separate thread and then passes the result
// to OnWeakCheckDone.
void StartWeakCheck(base::OnceClosure on_check_done = base::DoNothing());
@@ -184,6 +184,14 @@ class InsecureCredentialsManager : public SavedPasswordsPresenter::Observer {
// the remove succeeded.
bool RemoveCredential(const CredentialView& credential);
+ // Attempts to mute |credential| from the password store.
+ // Returns whether the mute succeeded.
+ bool MuteCredential(const CredentialView& credential);
+
+ // Attempts to unmute |credential| from the password store.
+ // Returns whether the unmute succeeded.
+ bool UnmuteCredential(const CredentialView& credential);
+
// Returns a vector of currently insecure credentials.
std::vector<CredentialWithPassword> GetInsecureCredentials() const;
diff --git a/chromium/components/password_manager/core/browser/ui/insecure_credentials_manager_unittest.cc b/chromium/components/password_manager/core/browser/ui/insecure_credentials_manager_unittest.cc
index 9644846e4b0..177bbb43d93 100644
--- a/chromium/components/password_manager/core/browser/ui/insecure_credentials_manager_unittest.cc
+++ b/chromium/components/password_manager/core/browser/ui/insecure_credentials_manager_unittest.cc
@@ -34,7 +34,7 @@ constexpr char kPassword2[] = "s3cr3t";
constexpr char16_t kPassword216[] = u"s3cr3t";
constexpr char16_t kPassword3[] = u"484her";
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
constexpr char16_t kWeakPassword1[] = u"123456";
constexpr char kWeakPassword2[] = "abcdabcdabcdabcdabcdabcdabcdabcdabcdabcda";
constexpr char16_t kWeakPassword216[] =
@@ -45,7 +45,7 @@ constexpr char16_t kStrongPassword2[] =
u"pmsFlsnoab4nsl#losb@skpfnsbkjb^klsnbs!cns";
// Delay in milliseconds.
constexpr int kDelay = 2;
-#endif // !defined(OS_ANDROID) && !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
using ::testing::ElementsAre;
using ::testing::ElementsAreArray;
@@ -84,14 +84,16 @@ LeakCheckCredential MakeLeakCredential(base::StringPiece16 username,
CredentialWithPassword MakeCompromisedCredential(
const PasswordForm& form,
- InsecureCredentialTypeFlags type =
- InsecureCredentialTypeFlags::kCredentialLeaked) {
+ const InsecureCredentialTypeFlags type =
+ InsecureCredentialTypeFlags::kCredentialLeaked,
+ const bool is_muted = false) {
CredentialWithPassword credential_with_password((CredentialView(form)));
credential_with_password.insecure_type = type;
+ credential_with_password.is_muted = IsMuted(is_muted);
return credential_with_password;
}
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
CredentialWithPassword MakeWeakCredential(const PasswordForm& form) {
CredentialWithPassword weak_credential{CredentialView(form)};
weak_credential.insecure_type = InsecureCredentialTypeFlags::kWeakCredential;
@@ -106,7 +108,7 @@ CredentialWithPassword MakeWeakAndCompromisedCredential(
InsecureCredentialTypeFlags::kWeakCredential;
return credential_with_password;
}
-#endif // !defined(OS_ANDROID) && !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
class InsecureCredentialsManagerTest : public ::testing::Test {
protected:
@@ -159,7 +161,7 @@ class InsecureCredentialsManagerTest : public ::testing::Test {
bool operator==(const CredentialWithPassword& lhs,
const CredentialWithPassword& rhs) {
return lhs.signon_realm == rhs.signon_realm && lhs.username == rhs.username &&
- lhs.create_time == rhs.create_time &&
+ lhs.create_time == rhs.create_time && lhs.is_muted == rhs.is_muted &&
lhs.insecure_type == rhs.insecure_type && lhs.password == rhs.password;
}
@@ -168,7 +170,7 @@ std::ostream& operator<<(std::ostream& out,
return out << "{ signon_realm: " << credential.signon_realm
<< ", username: " << credential.username
<< ", create_time: " << credential.create_time
- << ", insecure_type: "
+ << ", is_muted: " << credential.is_muted << ", insecure_type: "
<< static_cast<int>(credential.insecure_type)
<< ", password: " << credential.password << " }";
}
@@ -405,7 +407,7 @@ TEST_F(InsecureCredentialsManagerTest, MapCompromisedPasswordsToPasswords) {
ElementsAreArray(store().stored_passwords().at(kExampleOrg)));
}
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
TEST_F(InsecureCredentialsManagerTest, StartWeakCheckNotifiesOnCompletion) {
base::MockOnceClosure closure;
provider().StartWeakCheck(closure.Get());
@@ -645,7 +647,7 @@ TEST_F(InsecureCredentialsManagerTest, SingleCredentialIsWeakAndCompromised) {
histogram_tester().ExpectUniqueSample(
"PasswordManager.WeakCheck.PasswordScore", 0, 1);
}
-#endif // !defined(OS_ANDROID) && !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
// Test verifies that saving LeakCheckCredential via provider adds expected
// compromised credential.
@@ -666,6 +668,217 @@ TEST_F(InsecureCredentialsManagerTest, SaveCompromisedPassword) {
EXPECT_THAT(provider().GetInsecureCredentials(), ElementsAre(expected));
}
+// Test verifies that saving LeakCheckCredential doesn't occur for already
+// leaked passwords.
+TEST_F(InsecureCredentialsManagerTest, SaveCompromisedPasswordForExistingLeak) {
+ PasswordForm password_form =
+ MakeSavedPassword(kExampleCom, kUsername1, kPassword1);
+ LeakCheckCredential credential = MakeLeakCredential(kUsername1, kPassword1);
+
+ InsecurityMetadata insecurity_metadata(base::Time::Now() - base::Days(3),
+ IsMuted(true));
+ password_form.password_issues.insert(
+ {InsecureType::kLeaked, insecurity_metadata});
+
+ store().AddLogin(password_form);
+ RunUntilIdle();
+
+ provider().SaveInsecureCredential(credential);
+ RunUntilIdle();
+
+ EXPECT_EQ(insecurity_metadata,
+ store()
+ .stored_passwords()
+ .at(kExampleCom)
+ .back()
+ .password_issues.at(InsecureType::kLeaked));
+}
+
+TEST_F(InsecureCredentialsManagerTest, MuteCompromisedCredential) {
+ PasswordForm password =
+ MakeSavedPassword(kExampleCom, kUsername1, kPassword1);
+ password.password_issues.insert(
+ {InsecureType::kLeaked, InsecurityMetadata()});
+
+ store().AddLogin(password);
+ RunUntilIdle();
+
+ CredentialWithPassword expected = MakeCompromisedCredential(password);
+
+ EXPECT_THAT(provider().GetInsecureCredentials(), ElementsAre(expected));
+ EXPECT_FALSE(provider().GetInsecureCredentials()[0].is_muted);
+
+ EXPECT_TRUE(provider().MuteCredential(expected));
+ RunUntilIdle();
+ EXPECT_TRUE(provider().GetInsecureCredentials()[0].is_muted);
+ EXPECT_TRUE(store()
+ .stored_passwords()
+ .at(kExampleCom)
+ .back()
+ .password_issues.at(InsecureType::kLeaked)
+ .is_muted.value());
+}
+
+TEST_F(InsecureCredentialsManagerTest, UnmuteCompromisedMutedCredential) {
+ PasswordForm password =
+ MakeSavedPassword(kExampleCom, kUsername1, kPassword1);
+ password.password_issues.insert(
+ {InsecureType::kLeaked, InsecurityMetadata(base::Time(), IsMuted(true))});
+
+ store().AddLogin(password);
+ RunUntilIdle();
+
+ CredentialWithPassword expected = MakeCompromisedCredential(
+ password, InsecureCredentialTypeFlags::kCredentialLeaked, true);
+
+ EXPECT_THAT(provider().GetInsecureCredentials(), ElementsAre(expected));
+ EXPECT_TRUE(provider().GetInsecureCredentials()[0].is_muted);
+
+ EXPECT_TRUE(provider().UnmuteCredential(expected));
+ RunUntilIdle();
+ EXPECT_FALSE(provider().GetInsecureCredentials()[0].is_muted);
+ EXPECT_FALSE(store()
+ .stored_passwords()
+ .at(kExampleCom)
+ .back()
+ .password_issues.at(InsecureType::kLeaked)
+ .is_muted.value());
+}
+
+TEST_F(InsecureCredentialsManagerTest, UnmuteCompromisedNotMutedCredential) {
+ PasswordForm password =
+ MakeSavedPassword(kExampleCom, kUsername1, kPassword1);
+ password.password_issues.insert(
+ {InsecureType::kLeaked,
+ InsecurityMetadata(base::Time(), IsMuted(false))});
+
+ store().AddLogin(password);
+ RunUntilIdle();
+
+ CredentialWithPassword expected = MakeCompromisedCredential(
+ password, InsecureCredentialTypeFlags::kCredentialLeaked, false);
+
+ EXPECT_THAT(provider().GetInsecureCredentials(), ElementsAre(expected));
+ EXPECT_FALSE(provider().GetInsecureCredentials()[0].is_muted);
+
+ EXPECT_FALSE(provider().UnmuteCredential(expected));
+ RunUntilIdle();
+ EXPECT_FALSE(provider().GetInsecureCredentials()[0].is_muted);
+ EXPECT_FALSE(store()
+ .stored_passwords()
+ .at(kExampleCom)
+ .back()
+ .password_issues.at(InsecureType::kLeaked)
+ .is_muted.value());
+}
+
+TEST_F(InsecureCredentialsManagerTest,
+ UnmuteCompromisedMutedCredentialWithMultipleInsecurityTypes) {
+ PasswordForm password =
+ MakeSavedPassword(kExampleCom, kUsername1, kPassword1);
+ password.password_issues.insert(
+ {InsecureType::kLeaked, InsecurityMetadata(base::Time(), IsMuted(true))});
+ password.password_issues.insert(
+ {InsecureType::kPhished,
+ InsecurityMetadata(base::Time(), IsMuted(true))});
+
+ store().AddLogin(password);
+ RunUntilIdle();
+
+ CredentialWithPassword expected = MakeCompromisedCredential(
+ password,
+ InsecureCredentialTypeFlags::kCredentialLeaked |
+ InsecureCredentialTypeFlags::kCredentialPhished,
+ true);
+
+ EXPECT_THAT(provider().GetInsecureCredentials(), ElementsAre(expected));
+
+ EXPECT_TRUE(provider().GetInsecureCredentials()[0].is_muted);
+
+ EXPECT_TRUE(provider().UnmuteCredential(expected));
+ RunUntilIdle();
+ EXPECT_FALSE(provider().GetInsecureCredentials()[0].is_muted);
+ EXPECT_FALSE(store()
+ .stored_passwords()
+ .at(kExampleCom)
+ .back()
+ .password_issues.at(InsecureType::kLeaked)
+ .is_muted.value());
+ EXPECT_FALSE(store()
+ .stored_passwords()
+ .at(kExampleCom)
+ .back()
+ .password_issues.at(InsecureType::kPhished)
+ .is_muted.value());
+}
+
+TEST_F(InsecureCredentialsManagerTest, MuteCompromisedCredentialOnMutedIsNoOp) {
+ PasswordForm password =
+ MakeSavedPassword(kExampleCom, kUsername1, kPassword1);
+ password.password_issues.insert(
+ {InsecureType::kLeaked, InsecurityMetadata(base::Time(), IsMuted(true))});
+
+ store().AddLogin(password);
+ RunUntilIdle();
+
+ CredentialWithPassword expected = MakeCompromisedCredential(
+ password, InsecureCredentialTypeFlags::kCredentialLeaked, true);
+
+ EXPECT_THAT(provider().GetInsecureCredentials(), ElementsAre(expected));
+ EXPECT_TRUE(provider().GetInsecureCredentials()[0].is_muted);
+
+ EXPECT_FALSE(provider().MuteCredential(expected));
+ RunUntilIdle();
+ EXPECT_TRUE(provider().GetInsecureCredentials()[0].is_muted);
+ EXPECT_TRUE(store()
+ .stored_passwords()
+ .at(kExampleCom)
+ .back()
+ .password_issues.at(InsecureType::kLeaked)
+ .is_muted.value());
+}
+
+TEST_F(InsecureCredentialsManagerTest,
+ MuteCompromisedCredentialLeakedMutesMultipleInsecurityTypes) {
+ PasswordForm password =
+ MakeSavedPassword(kExampleCom, kUsername1, kPassword1);
+ password.password_issues.insert(
+ {InsecureType::kLeaked,
+ InsecurityMetadata(base::Time(), IsMuted(false))});
+ password.password_issues.insert(
+ {InsecureType::kPhished,
+ InsecurityMetadata(base::Time(), IsMuted(false))});
+
+ store().AddLogin(password);
+ RunUntilIdle();
+
+ CredentialWithPassword expected = MakeCompromisedCredential(
+ password,
+ InsecureCredentialTypeFlags::kCredentialLeaked |
+ InsecureCredentialTypeFlags::kCredentialPhished,
+ false);
+
+ EXPECT_THAT(provider().GetInsecureCredentials(), ElementsAre(expected));
+
+ EXPECT_FALSE(provider().GetInsecureCredentials()[0].is_muted);
+
+ EXPECT_TRUE(provider().MuteCredential(expected));
+ RunUntilIdle();
+ EXPECT_TRUE(provider().GetInsecureCredentials()[0].is_muted);
+ EXPECT_TRUE(store()
+ .stored_passwords()
+ .at(kExampleCom)
+ .back()
+ .password_issues.at(InsecureType::kLeaked)
+ .is_muted.value());
+ EXPECT_TRUE(store()
+ .stored_passwords()
+ .at(kExampleCom)
+ .back()
+ .password_issues.at(InsecureType::kPhished)
+ .is_muted.value());
+}
+
// Test verifies that editing Compromised Credential via provider change the
// original password form.
TEST_F(InsecureCredentialsManagerTest, UpdateCompromisedPassword) {
@@ -678,7 +891,7 @@ TEST_F(InsecureCredentialsManagerTest, UpdateCompromisedPassword) {
RunUntilIdle();
CredentialWithPassword expected =
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
MakeWeakAndCompromisedCredential(password_form);
#else
MakeCompromisedCredential(password_form);
@@ -691,7 +904,7 @@ TEST_F(InsecureCredentialsManagerTest, UpdateCompromisedPassword) {
EXPECT_TRUE(provider().GetInsecureCredentials().empty());
}
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
// Test verifies that editing weak credential via provider has affect on weak
// credentials and updates password in the store.
TEST_F(InsecureCredentialsManagerTest, UpdateWeakPassword) {
@@ -759,7 +972,7 @@ TEST_F(InsecureCredentialsManagerTest, UpdateInsecurePassword) {
EXPECT_EQ(GetSavedPasswordForUsername(kExampleCom, kUsername1),
kStrongPassword116);
}
-#endif // !defined(OS_ANDROID) && !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
TEST_F(InsecureCredentialsManagerTest, RemoveCompromisedCredential) {
PasswordForm password =
@@ -780,7 +993,7 @@ TEST_F(InsecureCredentialsManagerTest, RemoveCompromisedCredential) {
EXPECT_THAT(provider().GetInsecureCredentials(), IsEmpty());
}
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
TEST_F(InsecureCredentialsManagerTest, RemoveWeakCredential) {
PasswordForm password =
MakeSavedPassword(kExampleCom, kUsername1, kWeakPassword1);
@@ -840,7 +1053,7 @@ TEST_F(InsecureCredentialsManagerTest, GetWeakCredentialsReturnsSortedData) {
MakeWeakCredential(password_forms[2]),
MakeWeakCredential(password_forms[3])));
}
-#endif // !defined(OS_ANDROID) && !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
namespace {
class InsecureCredentialsManagerWithTwoStoresTest : public ::testing::Test {
@@ -1016,7 +1229,7 @@ TEST_F(InsecureCredentialsManagerWithTwoStoresTest,
EXPECT_TRUE(account_store().stored_passwords().at(kExampleCom).empty());
}
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
TEST_F(InsecureCredentialsManagerWithTwoStoresTest, RemoveWeakCredential) {
// Add `kUsername1`,`kPassword1` to both stores.
profile_store().AddLogin(
@@ -1036,6 +1249,6 @@ TEST_F(InsecureCredentialsManagerWithTwoStoresTest, RemoveWeakCredential) {
EXPECT_THAT(profile_store().stored_passwords().at(kExampleCom), IsEmpty());
EXPECT_THAT(account_store().stored_passwords().at(kExampleCom), IsEmpty());
}
-#endif // !defined(OS_ANDROID) && !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/votes_uploader.cc b/chromium/components/password_manager/core/browser/votes_uploader.cc
index eba26153217..e945749ae29 100644
--- a/chromium/components/password_manager/core/browser/votes_uploader.cc
+++ b/chromium/components/password_manager/core/browser/votes_uploader.cc
@@ -621,7 +621,7 @@ void VotesUploader::MaybeSendSingleUsernameVote() {
}
}
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
void VotesUploader::CalculateUsernamePromptEditState(
const std::u16string& saved_username) {
if (!single_username_vote_data_ ||
@@ -662,7 +662,7 @@ void VotesUploader::CalculateUsernamePromptEditState(
}
single_username_vote_data_->prompt_edit = prompt_edit;
}
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
void VotesUploader::AddGeneratedVote(FormStructure* form_structure) {
DCHECK(form_structure);
@@ -882,7 +882,7 @@ bool VotesUploader::SetSingleUsernameVoteOnUsernameForm(
} else {
// It's not possible to edit username in the save prompt on Android, thus it's
// not possible to rely on this heuristic.
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
const auto& prompt_edit = single_username_vote_data_->prompt_edit;
// There is no meaningful data on prompt edit, the vote should not be sent.
if (prompt_edit == AutofillUploadContents::EDIT_UNSPECIFIED)
@@ -897,7 +897,7 @@ bool VotesUploader::SetSingleUsernameVoteOnUsernameForm(
: AutofillUploadContents::Field::WEAK;
#else
return false;
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
}
available_field_types->insert(type);
SaveFieldVote(form_signature, field->GetFieldSignature(), type);
diff --git a/chromium/components/password_manager/core/browser/votes_uploader.h b/chromium/components/password_manager/core/browser/votes_uploader.h
index 12e52c88d75..f3250139d53 100644
--- a/chromium/components/password_manager/core/browser/votes_uploader.h
+++ b/chromium/components/password_manager/core/browser/votes_uploader.h
@@ -152,12 +152,12 @@ class VotesUploader {
// Not calculated on Android, because it's not possible to edit credentials in
// prompts on Android.
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
// Calculate whether the username value was edited in a prompt based on
// suggested and saved username values and whether it confirms or
// contradicts |single_username_vote_data_|.
void CalculateUsernamePromptEditState(const std::u16string& saved_username);
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
void set_generation_popup_was_shown(bool generation_popup_was_shown) {
generation_popup_was_shown_ = generation_popup_was_shown;
diff --git a/chromium/components/password_manager/core/browser/votes_uploader_unittest.cc b/chromium/components/password_manager/core/browser/votes_uploader_unittest.cc
index 771d1976f33..a5b757f2274 100644
--- a/chromium/components/password_manager/core/browser/votes_uploader_unittest.cc
+++ b/chromium/components/password_manager/core/browser/votes_uploader_unittest.cc
@@ -508,12 +508,12 @@ TEST_F(VotesUploaderTest, UploadSingleUsernameMultipleFieldsInUsernameForm) {
form_predictions,
/*stored_credentials=*/{});
votes_uploader.set_suggested_username(single_username_candidate_value);
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
votes_uploader.CalculateUsernamePromptEditState(
/*saved_username=*/single_username_candidate_value);
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
// Upload on the username form.
ServerFieldTypeSet expected_types = {SINGLE_USERNAME};
EXPECT_CALL(mock_autofill_download_manager_,
@@ -525,7 +525,7 @@ TEST_F(VotesUploaderTest, UploadSingleUsernameMultipleFieldsInUsernameForm) {
/* pref_service= */ nullptr));
#else
EXPECT_CALL(mock_autofill_download_manager_, StartUploadRequest).Times(0);
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
votes_uploader.MaybeSendSingleUsernameVote();
}
@@ -550,10 +550,10 @@ TEST_F(VotesUploaderTest, UploadNotSingleUsernameForWhitespaces) {
/*username_candidate_value=*/u"some search query",
MakeSimpleSingleUsernamePredictions(),
/*stored_credentials=*/{});
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
votes_uploader.CalculateUsernamePromptEditState(
/*saved_username=*/u"saved_value");
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
// Upload on the username form.
ServerFieldTypeSet expected_types = {NOT_USERNAME};
@@ -572,13 +572,13 @@ TEST_F(VotesUploaderTest, UploadNotSingleUsernameForWhitespaces) {
expected_single_username_data = MakeSimpleSingleUsernameData();
expected_single_username_data.set_value_type(
autofill::AutofillUploadContents::VALUE_WITH_WHITESPACE);
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
expected_single_username_data.set_prompt_edit(
autofill::AutofillUploadContents::EDITED_NEGATIVE);
#else
expected_single_username_data.set_prompt_edit(
autofill::AutofillUploadContents::EDIT_UNSPECIFIED);
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
EXPECT_CALL(
mock_autofill_download_manager_,
StartUploadRequest(
@@ -608,12 +608,12 @@ TEST_F(VotesUploaderTest, SingleUsernameValueSuggestedAndAccepted) {
kSingleUsernameRendererId, single_username_candidate_value,
MakeSimpleSingleUsernamePredictions(), /*stored_credentials=*/{});
votes_uploader.set_suggested_username(single_username_candidate_value);
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
votes_uploader.CalculateUsernamePromptEditState(
/*saved_username=*/single_username_candidate_value);
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
// Upload on the username form.
ServerFieldTypeSet expected_types = {SINGLE_USERNAME};
EXPECT_CALL(mock_autofill_download_manager_,
@@ -627,20 +627,20 @@ TEST_F(VotesUploaderTest, SingleUsernameValueSuggestedAndAccepted) {
/*pref_service=*/nullptr));
#else
EXPECT_CALL(mock_autofill_download_manager_, StartUploadRequest).Times(0);
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
votes_uploader.MaybeSendSingleUsernameVote();
// Upload on the password form for the fallback classifier.
autofill::AutofillUploadContents::SingleUsernameData
expected_single_username_data = MakeSimpleSingleUsernameData();
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
expected_single_username_data.set_prompt_edit(
autofill::AutofillUploadContents::NOT_EDITED_POSITIVE);
#else
expected_single_username_data.set_prompt_edit(
autofill::AutofillUploadContents::EDIT_UNSPECIFIED);
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
EXPECT_CALL(
mock_autofill_download_manager_,
StartUploadRequest(
@@ -672,12 +672,12 @@ TEST_F(VotesUploaderTest, SingleUsernameOtherValueSuggestedAndAccepted) {
MakeSimpleSingleUsernamePredictions(), /*stored_credentials=*/{});
std::u16string suggested_value = u"other_value";
votes_uploader.set_suggested_username(suggested_value);
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
votes_uploader.CalculateUsernamePromptEditState(
/*saved_username=*/suggested_value);
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
// Upload on the username form.
ServerFieldTypeSet expected_types = {NOT_USERNAME};
EXPECT_CALL(mock_autofill_download_manager_,
@@ -691,20 +691,20 @@ TEST_F(VotesUploaderTest, SingleUsernameOtherValueSuggestedAndAccepted) {
/*pref_service=*/nullptr));
#else
EXPECT_CALL(mock_autofill_download_manager_, StartUploadRequest).Times(0);
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
votes_uploader.MaybeSendSingleUsernameVote();
// Upload on the password form for the fallback classifier.
autofill::AutofillUploadContents::SingleUsernameData
expected_single_username_data = MakeSimpleSingleUsernameData();
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
expected_single_username_data.set_prompt_edit(
autofill::AutofillUploadContents::NOT_EDITED_NEGATIVE);
#else
expected_single_username_data.set_prompt_edit(
autofill::AutofillUploadContents::EDIT_UNSPECIFIED);
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
EXPECT_CALL(
mock_autofill_download_manager_,
StartUploadRequest(
@@ -735,12 +735,12 @@ TEST_F(VotesUploaderTest, SingleUsernameValueSetInPrompt) {
MakeSimpleSingleUsernamePredictions(), /*stored_credentials=*/{});
std::u16string suggested_value = u"other_value";
votes_uploader.set_suggested_username(suggested_value);
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
votes_uploader.CalculateUsernamePromptEditState(
/*saved_username=*/single_username_candidate_value);
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
ServerFieldTypeSet expected_types = {SINGLE_USERNAME};
EXPECT_CALL(mock_autofill_download_manager_,
StartUploadRequest(
@@ -753,20 +753,20 @@ TEST_F(VotesUploaderTest, SingleUsernameValueSetInPrompt) {
/*pref_service=*/nullptr));
#else
EXPECT_CALL(mock_autofill_download_manager_, StartUploadRequest).Times(0);
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
votes_uploader.MaybeSendSingleUsernameVote();
// Upload on the password form for the fallback classifier.
autofill::AutofillUploadContents::SingleUsernameData
expected_single_username_data = MakeSimpleSingleUsernameData();
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
expected_single_username_data.set_prompt_edit(
autofill::AutofillUploadContents::EDITED_POSITIVE);
#else
expected_single_username_data.set_prompt_edit(
autofill::AutofillUploadContents::EDIT_UNSPECIFIED);
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
EXPECT_CALL(
mock_autofill_download_manager_,
StartUploadRequest(
@@ -796,11 +796,11 @@ TEST_F(VotesUploaderTest, SingleUsernameValueDeletedInPrompt) {
kSingleUsernameRendererId, single_username_candidate_value,
MakeSimpleSingleUsernamePredictions(), /*stored_credentials=*/{});
votes_uploader.set_suggested_username(single_username_candidate_value);
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
votes_uploader.CalculateUsernamePromptEditState(/*saved_username=*/u"");
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
// Upload on the username form.
ServerFieldTypeSet expected_types = {NOT_USERNAME};
EXPECT_CALL(mock_autofill_download_manager_,
@@ -814,20 +814,20 @@ TEST_F(VotesUploaderTest, SingleUsernameValueDeletedInPrompt) {
/*pref_service=*/nullptr));
#else
EXPECT_CALL(mock_autofill_download_manager_, StartUploadRequest).Times(0);
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
votes_uploader.MaybeSendSingleUsernameVote();
// Expect upload for the password form for the fallback classifier.
autofill::AutofillUploadContents::SingleUsernameData
expected_single_username_data = MakeSimpleSingleUsernameData();
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
expected_single_username_data.set_prompt_edit(
autofill::AutofillUploadContents::EDITED_NEGATIVE);
#else
expected_single_username_data.set_prompt_edit(
autofill::AutofillUploadContents::EDIT_UNSPECIFIED);
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
EXPECT_CALL(
mock_autofill_download_manager_,
StartUploadRequest(
@@ -858,9 +858,9 @@ TEST_F(VotesUploaderTest, NotSingleUsernameValueDeletedInPrompt) {
MakeSimpleSingleUsernamePredictions(), /*stored_credentials=*/{});
std::u16string other_value = u"other_value";
votes_uploader.set_suggested_username(other_value);
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
votes_uploader.CalculateUsernamePromptEditState(/*saved_username=*/u"");
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
// Expect no upload on username form, as th signal is not informative to us.
EXPECT_CALL(mock_autofill_download_manager_,
@@ -901,9 +901,9 @@ TEST_F(VotesUploaderTest, SingleUsernameNoUsernameCandidate) {
FieldRendererId(), std::u16string(), FormPredictions(),
/*stored_credentials=*/{});
votes_uploader.set_suggested_username(u"");
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
votes_uploader.CalculateUsernamePromptEditState(/*saved_username=*/u"");
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
votes_uploader.MaybeSendSingleUsernameVote();
@@ -932,16 +932,16 @@ TEST_F(VotesUploaderTest, SaveSingleUsernameVote) {
votes_uploader.set_single_username_vote_data(
kSingleUsernameRendererId, single_username_candidate_value,
MakeSimpleSingleUsernamePredictions(), /*stored_credentials=*/{});
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
votes_uploader.CalculateUsernamePromptEditState(
/*saved_username=*/single_username_candidate_value);
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
// Init store and expect that adding field info is called.
scoped_refptr<MockPasswordStoreInterface> store =
new testing::StrictMock<MockPasswordStoreInterface>();
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
EXPECT_CALL(*store, GetFieldInfoStore)
.WillRepeatedly(testing::Return(nullptr));
#else
@@ -952,7 +952,7 @@ TEST_F(VotesUploaderTest, SaveSingleUsernameVote) {
AddFieldInfo(FieldInfoHasData(kSingleUsernameFormSignature,
kSingleUsernameFieldSignature,
SINGLE_USERNAME)));
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
// Init FieldInfoManager.
FieldInfoManagerImpl field_info_manager(store);
diff --git a/chromium/components/password_manager/core/browser/webauthn_credentials_delegate.h b/chromium/components/password_manager/core/browser/webauthn_credentials_delegate.h
index 23aa024c9c5..ebd27d65c5a 100644
--- a/chromium/components/password_manager/core/browser/webauthn_credentials_delegate.h
+++ b/chromium/components/password_manager/core/browser/webauthn_credentials_delegate.h
@@ -8,6 +8,7 @@
#include <string>
#include <vector>
+#include "base/callback.h"
#include "components/autofill/core/browser/ui/suggestion.h"
namespace password_manager {
@@ -27,7 +28,13 @@ class WebAuthnCredentialsDelegate {
// Returns the list of eligible WebAuthn credentials to fulfill an ongoing
// WebAuthn request.
- virtual std::vector<autofill::Suggestion> GetWebAuthnSuggestions() const = 0;
+ virtual const std::vector<autofill::Suggestion>& GetWebAuthnSuggestions()
+ const = 0;
+
+ // Initiates retrieval of discoverable WebAuthn credentials from the platform
+ // authenticator. |callback| is invoked upon completion.
+ virtual void RetrieveWebAuthnSuggestions(
+ base::OnceCallback<void()> callback) = 0;
};
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/common/BUILD.gn b/chromium/components/password_manager/core/common/BUILD.gn
index 3f5c1f739dd..21b66a3d792 100644
--- a/chromium/components/password_manager/core/common/BUILD.gn
+++ b/chromium/components/password_manager/core/common/BUILD.gn
@@ -2,15 +2,10 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-import("//build/buildflag_header.gni")
-import("//components/password_manager/core/common/features.gni")
-
static_library("common") {
sources = [
"credential_manager_types.cc",
"credential_manager_types.h",
- "password_manager_features.cc",
- "password_manager_features.h",
"password_manager_pref_names.cc",
"password_manager_pref_names.h",
"password_manager_ui.h",
@@ -25,12 +20,20 @@ static_library("common") {
deps = [
"//base",
- "//components/autofill/core/common",
"//sql",
"//url",
]
- public_deps = [ ":password_manager_buildflags" ]
+ public_deps = [ ":features" ]
+}
+
+source_set("features") {
+ sources = [
+ "password_manager_features.cc",
+ "password_manager_features.h",
+ ]
+
+ deps = [ "//base" ]
}
if (is_ios) {
@@ -49,9 +52,3 @@ if (is_ios) {
]
}
}
-
-buildflag_header("password_manager_buildflags") {
- header = "password_manager_buildflags.h"
- flags =
- [ "USE_LEGACY_PASSWORD_STORE_BACKEND=$use_legacy_password_store_backend" ]
-}
diff --git a/chromium/components/password_manager/core/common/features.gni b/chromium/components/password_manager/core/common/features.gni
deleted file mode 100644
index a75c1168a16..00000000000
--- a/chromium/components/password_manager/core/common/features.gni
+++ /dev/null
@@ -1,10 +0,0 @@
-# Copyright 2021 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.
-
-import("//build/config/android/config.gni")
-
-# The legacy password store backend is supported on android but usually disabled
-# in favor of a downstream implementation.
-use_legacy_password_store_backend =
- !is_android || !enable_chrome_android_internal
diff --git a/chromium/components/password_manager/core/common/password_manager_features.cc b/chromium/components/password_manager/core/common/password_manager_features.cc
index cd5b413a6b1..e9dc08e1e7f 100644
--- a/chromium/components/password_manager/core/common/password_manager_features.cc
+++ b/chromium/components/password_manager/core/common/password_manager_features.cc
@@ -20,17 +20,13 @@ const base::Feature kBiometricTouchToFill = {"BiometricTouchToFill",
// from the page.
const base::Feature kDetectFormSubmissionOnFormClear = {
"DetectFormSubmissionOnFormClear",
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
base::FEATURE_DISABLED_BY_DEFAULT
#else
base::FEATURE_ENABLED_BY_DEFAULT
#endif
};
-// Enables the editing of passwords in Chrome settings.
-const base::Feature kEditPasswordsInSettings = {
- "EditPasswordsInSettings", base::FEATURE_ENABLED_BY_DEFAULT};
-
// Enables UI that allows the user to create a strong password even if the field
// wasn't parsed as a new password field.
// TODO(crbug/1181254): Remove once it's launched.
@@ -46,7 +42,7 @@ const base::Feature kEnableOverwritingPlaceholderUsernames{
// in but not syncing.
const base::Feature kEnablePasswordsAccountStorage = {
"EnablePasswordsAccountStorage",
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
base::FEATURE_DISABLED_BY_DEFAULT
#else
base::FEATURE_ENABLED_BY_DEFAULT
@@ -67,6 +63,13 @@ const base::Feature kFillingAcrossAffiliatedWebsites{
const base::Feature kFillOnAccountSelect = {"fill-on-account-select",
base::FEATURE_DISABLED_BY_DEFAULT};
+#if BUILDFLAG(IS_LINUX)
+// When enabled, initial sync will be forced during startup if the password
+// store has encryption service failures.
+const base::Feature kForceInitialSyncWhenDecryptionFails = {
+ "ForceInitialSyncWhenDecryptionFails", base::FEATURE_DISABLED_BY_DEFAULT};
+#endif
+
// Enables finding a confirmation password field during saving by inspecting the
// values of the fields. Used as a kill switch.
// TODO(crbug.com/1164861): Remove once confirmed to be safe (around M92 or so).
@@ -79,6 +82,14 @@ const base::Feature kIOSEnablePasswordManagerBrandingUpdate{
"IOSEnablePasswordManagerBrandingUpdate",
base::FEATURE_DISABLED_BY_DEFAULT};
+// Enables (un)muting compromised passwords from bulk leak check in settings.
+const base::Feature kMuteCompromisedPasswords{
+ "MuteCompromisedPasswords", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Enables adding, displaying and modifying extra notes to stored credentials.
+const base::Feature kPasswordNotes{"PasswordNotes",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
// Enables password leak detection for unauthenticated users.
const base::Feature kLeakDetectionUnauthenticated = {
"LeakDetectionUnauthenticated", base::FEATURE_DISABLED_BY_DEFAULT};
@@ -97,6 +108,11 @@ const base::Feature kPasswordChangeOnlyRecentCredentials = {
const base::Feature kPasswordChangeInSettings = {
"PasswordChangeInSettings", base::FEATURE_DISABLED_BY_DEFAULT};
+// Enables fetching credentials capabilities from server for the
+// |PasswordChangeInSettings| and |PasswordChange| features.
+const base::Feature kPasswordDomainCapabilitiesFetching = {
+ "PasswordDomainCapabilitiesFetching", base::FEATURE_DISABLED_BY_DEFAULT};
+
// Controls the ability to import passwords from Chrome's settings page.
const base::Feature kPasswordImport = {"PasswordImport",
base::FEATURE_DISABLED_BY_DEFAULT};
@@ -129,17 +145,38 @@ const base::Feature kReparseServerPredictionsFollowingFormChange = {
const base::Feature kSecondaryServerFieldPredictions = {
"SecondaryServerFieldPredictions", base::FEATURE_ENABLED_BY_DEFAULT};
+#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
+// Displays at least the decryptable and never saved logins in the password
+// manager
+const base::Feature kSkipUndecryptablePasswords = {
+ "SkipUndecryptablePasswords", base::FEATURE_DISABLED_BY_DEFAULT};
+#endif
+
// Enables the addition of passwords in Chrome Settings.
// TODO(crbug/1226008): Remove once it's launched.
const base::Feature kSupportForAddPasswordsInSettings = {
"SupportForAddPasswordsInSettings", base::FEATURE_DISABLED_BY_DEFAULT};
+#if BUILDFLAG(IS_LINUX)
+// When enabled, all undecryptable passwords are deleted from the local database
+// during initial sync flow.
+const base::Feature kSyncUndecryptablePasswordsLinux = {
+ "SyncUndecryptablePasswordsLinux", base::FEATURE_DISABLED_BY_DEFAULT};
+#endif
+
+#if BUILDFLAG(IS_ANDROID)
+// Enables the experiment to automatically submit a form after filling by
+// TouchToFill
+const base::Feature kTouchToFillPasswordSubmission = {
+ "TouchToFillPasswordSubmission", base::FEATURE_DISABLED_BY_DEFAULT};
+#endif
+
// Treat heuritistics to find new password fields as reliable. This enables
// password generation on more forms, but could lead to false positives.
const base::Feature kTreatNewPasswordHeuristicsAsReliable = {
"TreatNewPasswordHeuristicsAsReliable", base::FEATURE_DISABLED_BY_DEFAULT};
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Enables the intent fetching for the credential manager in Google Mobile
// Services. It does not enable launching the credential manager.
const base::Feature kUnifiedCredentialManagerDryRun = {
@@ -161,6 +198,12 @@ const base::Feature kUnifiedPasswordManagerMigration{
const base::Feature kUnifiedPasswordManagerShadowAndroid{
"UnifiedPasswordManagerShadowAndroid", base::FEATURE_DISABLED_BY_DEFAULT};
+// Similar to kUnifiedPasswordManagerShadowAndroid but send modify operations
+// instead of read operations.Relevant only for non-sync'ing users.
+const base::Feature kUnifiedPasswordManagerShadowWriteOperationsAndroid{
+ "UnifiedPasswordManagerShadowWriteOperationsAndroid",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
// If enabled, the built-in sync functionality in PasswordSyncBridge becomes
// unused, meaning that SyncService/SyncEngine will no longer download or
// upload changes to/from the Sync server. Instead, an external Android-specific
@@ -187,11 +230,17 @@ const base::Feature kUsernameFirstFlowFallbackCrowdsourcing = {
"UsernameFirstFlowFallbackCrowdsourcing",
base::FEATURE_DISABLED_BY_DEFAULT};
-#if defined(OS_ANDROID)
+// Returns true if the client is part of the live_experiment group for
+// |kPasswordDomainCapabilitiesFetching|, otherwise, the client is assumed to be
+// in the regular launch group.
+extern const base::FeatureParam<bool> kPasswordChangeLiveExperimentParam = {
+ &kPasswordDomainCapabilitiesFetching, "live_experiment", false};
+
+#if BUILDFLAG(IS_ANDROID)
// Current migration version to Google Mobile Services. If version saved in pref
// is lower than 'kMigrationVersion' passwords will be re-uploaded.
extern const base::FeatureParam<int> kMigrationVersion = {
- &kUnifiedPasswordManagerMigration, "migration_version", 0};
+ &kUnifiedPasswordManagerMigration, "migration_version", 1};
#endif
// Field trial identifier for password generation requirements.
@@ -223,6 +272,11 @@ const char kPasswordChangeWithForcedDialogAfterEverySuccessfulSubmission[] =
const char kPasswordChangeInSettingsWithForcedWarningForEverySite[] =
"should_force_warning_for_every_site_in_settings";
+bool IsPasswordScriptsFetchingEnabled() {
+ return base::FeatureList::IsEnabled(kPasswordScriptsFetching) ||
+ base::FeatureList::IsEnabled(kPasswordDomainCapabilitiesFetching);
+}
+
} // namespace features
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/common/password_manager_features.h b/chromium/components/password_manager/core/common/password_manager_features.h
index 8d183d8e794..820c286a048 100644
--- a/chromium/components/password_manager/core/common/password_manager_features.h
+++ b/chromium/components/password_manager/core/common/password_manager_features.h
@@ -9,6 +9,7 @@
// module.
#include "base/feature_list.h"
+#include "base/metrics/field_trial_params.h"
#include "build/build_config.h"
namespace password_manager {
@@ -19,7 +20,6 @@ namespace features {
// alongside the definition of their values in the .cc file.
extern const base::Feature kBiometricTouchToFill;
-extern const base::Feature kEditPasswordsInSettings;
extern const base::Feature kDetectFormSubmissionOnFormClear;
extern const base::Feature kEnableManualPasswordGeneration;
extern const base::Feature kEnableOverwritingPlaceholderUsernames;
@@ -27,12 +27,18 @@ extern const base::Feature kEnablePasswordsAccountStorage;
extern const base::Feature KEnablePasswordGenerationForClearTextFields;
extern const base::Feature kFillingAcrossAffiliatedWebsites;
extern const base::Feature kFillOnAccountSelect;
+#if BUILDFLAG(IS_LINUX)
+extern const base::Feature kForceInitialSyncWhenDecryptionFails;
+#endif
extern const base::Feature kInferConfirmationPasswordField;
extern const base::Feature kIOSEnablePasswordManagerBrandingUpdate;
+extern const base::Feature kMuteCompromisedPasswords;
+extern const base::Feature kPasswordNotes;
extern const base::Feature kLeakDetectionUnauthenticated;
extern const base::Feature kPasswordChange;
extern const base::Feature kPasswordChangeOnlyRecentCredentials;
extern const base::Feature kPasswordChangeInSettings;
+extern const base::Feature kPasswordDomainCapabilitiesFetching;
extern const base::Feature kPasswordImport;
extern const base::Feature kPasswordReuseDetectionEnabled;
extern const base::Feature kPasswordsAccountStorageRevisedOptInFlow;
@@ -40,23 +46,32 @@ extern const base::Feature kPasswordScriptsFetching;
extern const base::Feature kRecoverFromNeverSaveAndroid;
extern const base::Feature kReparseServerPredictionsFollowingFormChange;
extern const base::Feature kSecondaryServerFieldPredictions;
+#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
+extern const base::Feature kSkipUndecryptablePasswords;
+#endif
extern const base::Feature kSupportForAddPasswordsInSettings;
+#if BUILDFLAG(IS_LINUX)
+extern const base::Feature kSyncUndecryptablePasswordsLinux;
+#endif
+#if BUILDFLAG(IS_ANDROID)
+extern const base::Feature kTouchToFillPasswordSubmission;
+#endif
extern const base::Feature kTreatNewPasswordHeuristicsAsReliable;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
extern const base::Feature kUnifiedCredentialManagerDryRun;
extern const base::Feature kUnifiedPasswordManagerAndroid;
extern const base::Feature kUnifiedPasswordManagerMigration;
extern const base::Feature kUnifiedPasswordManagerShadowAndroid;
+extern const base::Feature kUnifiedPasswordManagerShadowWriteOperationsAndroid;
extern const base::Feature kUnifiedPasswordManagerSyncUsingAndroidBackendOnly;
-
#endif
extern const base::Feature kUsernameFirstFlow;
extern const base::Feature kUsernameFirstFlowFilling;
extern const base::Feature kUsernameFirstFlowFallbackCrowdsourcing;
// All features parameters are in alphabetical order.
-
-#if defined(OS_ANDROID)
+extern const base::FeatureParam<bool> kPasswordChangeLiveExperimentParam;
+#if BUILDFLAG(IS_ANDROID)
extern const base::FeatureParam<int> kMigrationVersion;
#endif
@@ -77,6 +92,10 @@ extern const char
kPasswordChangeWithForcedDialogAfterEverySuccessfulSubmission[];
extern const char kPasswordChangeInSettingsWithForcedWarningForEverySite[];
+// Returns true if any of the password script fetching related flags are
+// enabled.
+bool IsPasswordScriptsFetchingEnabled();
+
} // namespace features
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/common/password_manager_pref_names.cc b/chromium/components/password_manager/core/common/password_manager_pref_names.cc
index f11ac3e9bc8..be87af9a907 100644
--- a/chromium/components/password_manager/core/common/password_manager_pref_names.cc
+++ b/chromium/components/password_manager/core/common/password_manager_pref_names.cc
@@ -12,20 +12,20 @@ namespace prefs {
const char kCredentialsEnableAutosignin[] = "credentials_enable_autosignin";
const char kCredentialsEnableService[] = "credentials_enable_service";
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
const char kCurrentMigrationVersionToGoogleMobileServices[] =
"current_migration_version_to_google_mobile_services";
const char kTimeOfLastMigrationAttempt[] = "time_of_last_migration_attempt";
#endif
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
const char kOsPasswordBlank[] = "password_manager.os_password_blank";
const char kOsPasswordLastChanged[] =
"password_manager.os_password_last_changed";
#endif
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
const char kKeychainMigrationStatus[] = "password_manager.keychain_migration";
#endif
@@ -49,6 +49,9 @@ const char kLastTimeObsoleteHttpCredentialsRemoved[] =
const char kLastTimePasswordCheckCompleted[] =
"profile.last_time_password_check_completed";
+const char kLastTimePasswordStoreMetricsReported[] =
+ "profile.last_time_password_store_metrics_reported";
+
const char kSyncedLastTimePasswordCheckCompleted[] =
"profile.credentials_last_password_checkup_time";
@@ -57,6 +60,9 @@ const char kPasswordHashDataList[] = "profile.password_hash_data_list";
const char kPasswordLeakDetectionEnabled[] =
"profile.password_manager_leak_detection";
+const char kPasswordDismissCompromisedAlertEnabled[] =
+ "profile.password_dismiss_compromised_alert";
+
const char kProfileStoreDateLastUsedForFilling[] =
"password_manager.profile_store_date_last_used_for_filling";
const char kAccountStoreDateLastUsedForFilling[] =
diff --git a/chromium/components/password_manager/core/common/password_manager_pref_names.h b/chromium/components/password_manager/core/common/password_manager_pref_names.h
index 1a2e86414ef..63581f9c0f7 100644
--- a/chromium/components/password_manager/core/common/password_manager_pref_names.h
+++ b/chromium/components/password_manager/core/common/password_manager_pref_names.h
@@ -24,7 +24,7 @@ extern const char kCredentialsEnableAutosignin[];
// passwords.
extern const char kCredentialsEnableService[];
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Integer value which indicates the version used to migrate passwords from
// built in storage to Google Mobile Services.
extern const char kCurrentMigrationVersionToGoogleMobileServices[];
@@ -34,7 +34,7 @@ extern const char kCurrentMigrationVersionToGoogleMobileServices[];
extern const char kTimeOfLastMigrationAttempt[];
#endif
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// Whether the password was blank, only valid if OS password was last changed
// on or before the value contained in kOsPasswordLastChanged.
extern const char kOsPasswordBlank[];
@@ -43,7 +43,7 @@ extern const char kOsPasswordBlank[];
extern const char kOsPasswordLastChanged[];
#endif
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
// The current status of migrating the passwords from the Keychain to the
// database. Stores a value from MigrationStatus.
extern const char kKeychainMigrationStatus[];
@@ -77,6 +77,10 @@ extern const char kLastTimeObsoleteHttpCredentialsRemoved[];
// The last time the password check has run to completion.
extern const char kLastTimePasswordCheckCompleted[];
+// Timestamps of when password store metrics where last reported, in
+// microseconds since Windows epoch.
+extern const char kLastTimePasswordStoreMetricsReported[];
+
// The last time the password check has run to completion synced across devices.
// It's used on passwords.google.com and not in Chrome.
extern const char kSyncedLastTimePasswordCheckCompleted[];
@@ -88,6 +92,10 @@ extern const char kPasswordHashDataList[];
// submitted by the user were part of a leak.
extern const char kPasswordLeakDetectionEnabled[];
+// Boolean indicating whether users can mute (aka dismiss) alerts resulting from
+// compromised credentials that were submitted by the user.
+extern const char kPasswordDismissCompromisedAlertEnabled[];
+
// Timestamps of when credentials from the profile / account store were last
// used to fill a form, in microseconds since Windows epoch.
extern const char kProfileStoreDateLastUsedForFilling[];
diff --git a/chromium/components/password_manager/ios/BUILD.gn b/chromium/components/password_manager/ios/BUILD.gn
index 4aceeb7d7c0..9ebf405e156 100644
--- a/chromium/components/password_manager/ios/BUILD.gn
+++ b/chromium/components/password_manager/ios/BUILD.gn
@@ -122,6 +122,7 @@ source_set("unit_tests") {
"//components/password_manager/ios:password_manager_feature",
"//ios/web/public/js_messaging",
"//ios/web/public/test",
+ "//ios/web/public/test:test_fixture",
"//ios/web/public/test/fakes",
"//testing/gmock",
"//testing/gtest",
diff --git a/chromium/components/password_manager/ios/password_manager_java_script_feature.mm b/chromium/components/password_manager/ios/password_manager_java_script_feature.mm
index 521b2cf71e8..41b6fa1f90d 100644
--- a/chromium/components/password_manager/ios/password_manager_java_script_feature.mm
+++ b/chromium/components/password_manager/ios/password_manager_java_script_feature.mm
@@ -4,6 +4,7 @@
#import "components/password_manager/ios/password_manager_java_script_feature.h"
+#include "base/no_destructor.h"
#include "base/strings/sys_string_conversions.h"
#include "base/values.h"
#include "components/autofill/core/common/password_form_fill_data.h"
diff --git a/chromium/components/password_manager_strings.grdp b/chromium/components/password_manager_strings.grdp
index 7cede9146e2..c3c12abaa49 100644
--- a/chromium/components/password_manager_strings.grdp
+++ b/chromium/components/password_manager_strings.grdp
@@ -100,4 +100,7 @@
<message name="IDS_PASSWORD_MANAGER_DEFAULT_EXPORT_FILENAME" desc="Chrome suggests this file name when user chooses to export their passwords saved with Chrome.">
Chrome Passwords
</message>
+ <message name="IDS_PASSWORD_MANAGER_PASSWORD_FOR_ACCOUNT" desc="Voice over text read if the user focuses a drop down entry to fill a password for a given account.">
+ Password for <ph name="username">$1<ex>chef@google.com</ex></ph>
+ </message>
</grit-part>
diff --git a/chromium/components/password_manager_strings_grdp/IDS_PASSWORD_MANAGER_PASSWORD_FOR_ACCOUNT.png.sha1 b/chromium/components/password_manager_strings_grdp/IDS_PASSWORD_MANAGER_PASSWORD_FOR_ACCOUNT.png.sha1
new file mode 100644
index 00000000000..661cafd1af1
--- /dev/null
+++ b/chromium/components/password_manager_strings_grdp/IDS_PASSWORD_MANAGER_PASSWORD_FOR_ACCOUNT.png.sha1
@@ -0,0 +1 @@
+84e591dd00200eac4f46e43493a13039be622434 \ No newline at end of file
diff --git a/chromium/components/payments/content/android/BUILD.gn b/chromium/components/payments/content/android/BUILD.gn
index 7a0b856c475..fcd5e1be5ed 100644
--- a/chromium/components/payments/content/android/BUILD.gn
+++ b/chromium/components/payments/content/android/BUILD.gn
@@ -196,6 +196,7 @@ android_library("full_java") {
"//base:base_java",
"//components/autofill/android:autofill_java",
"//components/browser_ui/bottomsheet/android:java",
+ "//components/browser_ui/widget/android:java_resources",
"//components/embedder_support/android:util_java",
"//components/page_info/android:java",
"//components/payments/mojom:mojom_java",
diff --git a/chromium/components/payments/content/android/minimal_java_res/drawable/google_pay.xml b/chromium/components/payments/content/android/minimal_java_res/drawable/google_pay.xml
index 7076701a9ec..b48dc4aaf6f 100644
--- a/chromium/components/payments/content/android/minimal_java_res/drawable/google_pay.xml
+++ b/chromium/components/payments/content/android/minimal_java_res/drawable/google_pay.xml
@@ -4,8 +4,6 @@
found in the LICENSE file. -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- tools:targetApi="21"
android:viewportWidth="49"
android:viewportHeight="20"
android:width="49dp"
diff --git a/chromium/components/payments/content/android/payment_app_service_bridge.cc b/chromium/components/payments/content/android/payment_app_service_bridge.cc
index a2df0a2d9c5..d7d7ebef134 100644
--- a/chromium/components/payments/content/android/payment_app_service_bridge.cc
+++ b/chromium/components/payments/content/android/payment_app_service_bridge.cc
@@ -92,6 +92,7 @@ void JNI_PaymentAppServiceBridge_Create(
const JavaParamRef<jobject>& jpayment_request_spec,
const JavaParamRef<jstring>& jtwa_package_name,
jboolean jmay_crawl_for_installable_payment_apps,
+ jboolean jis_off_the_record,
const JavaParamRef<jobject>& jcallback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
@@ -117,6 +118,7 @@ void JNI_PaymentAppServiceBridge_Create(
env, jpayment_request_spec),
jtwa_package_name ? ConvertJavaStringToUTF8(env, jtwa_package_name) : "",
web_data_service, jmay_crawl_for_installable_payment_apps,
+ jis_off_the_record,
base::BindOnce(&OnCanMakePaymentCalculated,
ScopedJavaGlobalRef<jobject>(env, jcallback)),
base::BindRepeating(&OnPaymentAppCreated,
@@ -174,6 +176,7 @@ PaymentAppServiceBridge* PaymentAppServiceBridge::Create(
const std::string& twa_package_name,
scoped_refptr<PaymentManifestWebDataService> web_data_service,
bool may_crawl_for_installable_payment_apps,
+ bool is_off_the_record,
CanMakePaymentCalculatedCallback can_make_payment_calculated_callback,
PaymentAppCreatedCallback payment_app_created_callback,
PaymentAppCreationErrorCallback payment_app_creation_error_callback,
@@ -184,7 +187,7 @@ PaymentAppServiceBridge* PaymentAppServiceBridge::Create(
std::unique_ptr<PaymentAppServiceBridge> bridge(new PaymentAppServiceBridge(
number_of_factories, render_frame_host, top_origin, spec,
twa_package_name, std::move(web_data_service),
- may_crawl_for_installable_payment_apps,
+ may_crawl_for_installable_payment_apps, is_off_the_record,
std::move(can_make_payment_calculated_callback),
std::move(payment_app_created_callback),
std::move(payment_app_creation_error_callback),
@@ -201,6 +204,7 @@ PaymentAppServiceBridge::PaymentAppServiceBridge(
const std::string& twa_package_name,
scoped_refptr<PaymentManifestWebDataService> web_data_service,
bool may_crawl_for_installable_payment_apps,
+ bool is_off_the_record,
CanMakePaymentCalculatedCallback can_make_payment_calculated_callback,
PaymentAppCreatedCallback payment_app_created_callback,
PaymentAppCreationErrorCallback payment_app_creation_error_callback,
@@ -217,6 +221,7 @@ PaymentAppServiceBridge::PaymentAppServiceBridge(
payment_manifest_web_data_service_(web_data_service),
may_crawl_for_installable_payment_apps_(
may_crawl_for_installable_payment_apps),
+ is_off_the_record_(is_off_the_record),
can_make_payment_calculated_callback_(
std::move(can_make_payment_calculated_callback)),
payment_app_created_callback_(std::move(payment_app_created_callback)),
@@ -294,9 +299,7 @@ bool PaymentAppServiceBridge::MayCrawlForInstallablePaymentApps() {
}
bool PaymentAppServiceBridge::IsOffTheRecord() const {
- auto* rfh = content::RenderFrameHost::FromID(frame_routing_id_);
- return rfh && rfh->GetBrowserContext() &&
- rfh->GetBrowserContext()->IsOffTheRecord();
+ return is_off_the_record_;
}
const std::vector<autofill::AutofillProfile*>&
diff --git a/chromium/components/payments/content/android/payment_app_service_bridge.h b/chromium/components/payments/content/android/payment_app_service_bridge.h
index 34e11b7d17b..8d73bb457fd 100644
--- a/chromium/components/payments/content/android/payment_app_service_bridge.h
+++ b/chromium/components/payments/content/android/payment_app_service_bridge.h
@@ -49,6 +49,7 @@ class PaymentAppServiceBridge : public PaymentAppFactory::Delegate {
const std::string& twa_package_name,
scoped_refptr<PaymentManifestWebDataService> web_data_service,
bool may_crawl_for_installable_payment_apps,
+ bool is_off_the_record,
CanMakePaymentCalculatedCallback can_make_payment_calculated_callback,
PaymentAppCreatedCallback payment_app_created_callback,
PaymentAppCreationErrorCallback payment_app_creation_error_callback,
@@ -105,6 +106,7 @@ class PaymentAppServiceBridge : public PaymentAppFactory::Delegate {
const std::string& twa_package_name,
scoped_refptr<PaymentManifestWebDataService> web_data_service,
bool may_crawl_for_installable_payment_apps,
+ bool is_off_the_record,
CanMakePaymentCalculatedCallback can_make_payment_calculated_callback,
PaymentAppCreatedCallback payment_app_created_callback,
PaymentAppCreationErrorCallback payment_app_creation_error_callback,
@@ -121,6 +123,7 @@ class PaymentAppServiceBridge : public PaymentAppFactory::Delegate {
scoped_refptr<PaymentManifestWebDataService>
payment_manifest_web_data_service_;
bool may_crawl_for_installable_payment_apps_;
+ bool is_off_the_record_;
std::vector<autofill::AutofillProfile*> dummy_profiles_;
CanMakePaymentCalculatedCallback can_make_payment_calculated_callback_;
diff --git a/chromium/components/payments/content/manifest_verifier.cc b/chromium/components/payments/content/manifest_verifier.cc
index 300fd9e01e6..69c975438a9 100644
--- a/chromium/components/payments/content/manifest_verifier.cc
+++ b/chromium/components/payments/content/manifest_verifier.cc
@@ -104,10 +104,7 @@ void ManifestVerifier::Verify(
}
// Same origin payment methods are always allowed.
- url::Origin app_origin =
- url::Origin::Create(app.second->scope.DeprecatedGetOriginAsURL());
- if (url::Origin::Create(method_manifest_url.DeprecatedGetOriginAsURL())
- .IsSameOriginWith(app_origin)) {
+ if (url::IsSameOriginWith(app.second->scope, method_manifest_url)) {
verified_method_names.emplace_back(method);
app.second->has_explicitly_verified_methods = true;
continue;
diff --git a/chromium/components/payments/content/payment_app_service.cc b/chromium/components/payments/content/payment_app_service.cc
index cdc90c0eba8..f094b8cbf1c 100644
--- a/chromium/components/payments/content/payment_app_service.cc
+++ b/chromium/components/payments/content/payment_app_service.cc
@@ -4,6 +4,8 @@
#include "components/payments/content/payment_app_service.h"
+#include <utility>
+
#include "base/feature_list.h"
#include "components/payments/content/android_app_communication.h"
#include "components/payments/content/android_payment_app_factory.h"
@@ -59,4 +61,9 @@ void PaymentAppService::Shutdown() {
factories_.clear();
}
+void PaymentAppService::AddFactoryForTesting(
+ std::unique_ptr<PaymentAppFactory> factory) {
+ factories_.push_back(std::move(factory));
+}
+
} // namespace payments
diff --git a/chromium/components/payments/content/payment_app_service.h b/chromium/components/payments/content/payment_app_service.h
index affd4034baa..f9bb81d5bc8 100644
--- a/chromium/components/payments/content/payment_app_service.h
+++ b/chromium/components/payments/content/payment_app_service.h
@@ -41,6 +41,8 @@ class PaymentAppService : public KeyedService {
// KeyedService implementation:
void Shutdown() override;
+ void AddFactoryForTesting(std::unique_ptr<PaymentAppFactory> factory);
+
private:
std::vector<std::unique_ptr<PaymentAppFactory>> factories_;
};
diff --git a/chromium/components/payments/content/payment_request.h b/chromium/components/payments/content/payment_request.h
index e6137dba096..5162545b4b1 100644
--- a/chromium/components/payments/content/payment_request.h
+++ b/chromium/components/payments/content/payment_request.h
@@ -128,10 +128,6 @@ class PaymentRequest : public content::DocumentService<mojom::PaymentRequest>,
// object and close any related connections.
void OnUserCancelled();
- // Called when the main frame attached to this PaymentRequest is navigating
- // to another document, but before the PaymentRequest is destroyed.
- void DidStartMainFrameNavigationToDifferentDocument(bool is_user_initiated);
-
// Called when the PaymentRequest is about to be destroyed. This reports
// the reason for destruction.
void WillBeDestroyed(content::DocumentServiceDestructionReason reason) final;
diff --git a/chromium/components/payments/content/payment_request_dialog.h b/chromium/components/payments/content/payment_request_dialog.h
index 4a6d02bcf5b..552cd821ba9 100644
--- a/chromium/components/payments/content/payment_request_dialog.h
+++ b/chromium/components/payments/content/payment_request_dialog.h
@@ -9,10 +9,6 @@
#include "components/autofill/core/browser/payments/full_card_request.h"
#include "components/payments/content/payment_request_display_manager.h"
-namespace content {
-class WebContents;
-}
-
namespace payments {
// Used to interact with a cross-platform Payment Request dialog.
@@ -40,7 +36,7 @@ class PaymentRequestDialog {
const autofill::CreditCard& credit_card,
base::WeakPtr<autofill::payments::FullCardRequest::ResultDelegate>
result_delegate,
- content::WebContents* web_contents) = 0;
+ content::RenderFrameHost* render_frame_host) = 0;
// Display |url| in a new screen and run |callback| after navigation is
// completed, passing true/false to indicate success/failure.
diff --git a/chromium/components/payments/content/payment_request_spec_unittest.cc b/chromium/components/payments/content/payment_request_spec_unittest.cc
index 654d7c1586d..dd75449091a 100644
--- a/chromium/components/payments/content/payment_request_spec_unittest.cc
+++ b/chromium/components/payments/content/payment_request_spec_unittest.cc
@@ -9,7 +9,9 @@
#include "base/memory/weak_ptr.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_feature_list.h"
#include "components/strings/grit/components_strings.h"
+#include "content/public/common/content_features.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/mojom/payments/payment_request.mojom.h"
@@ -20,10 +22,10 @@ namespace payments {
using ::testing::ElementsAre;
using ::testing::UnorderedElementsAre;
-class PaymentRequestSpecTest : public testing::Test,
- public PaymentRequestSpec::Observer {
+class PaymentRequestSpecTestBase : public testing::Test,
+ public PaymentRequestSpec::Observer {
protected:
- ~PaymentRequestSpecTest() override {}
+ ~PaymentRequestSpecTestBase() override = default;
void OnSpecUpdated() override { on_spec_updated_called_ = true; }
@@ -49,11 +51,28 @@ class PaymentRequestSpecTest : public testing::Test,
private:
std::unique_ptr<PaymentRequestSpec> spec_;
bool on_spec_updated_called_ = false;
- base::WeakPtrFactory<PaymentRequestSpecTest> weak_ptr_factory_{this};
+ base::WeakPtrFactory<PaymentRequestSpecTestBase> weak_ptr_factory_{this};
+};
+
+class PaymentRequestSpecBasiCardEnabledTest
+ : public PaymentRequestSpecTestBase {
+ public:
+ PaymentRequestSpecBasiCardEnabledTest(
+ const PaymentRequestSpecBasiCardEnabledTest&) = delete;
+ PaymentRequestSpecBasiCardEnabledTest& operator=(
+ const PaymentRequestSpecBasiCardEnabledTest&) = delete;
+
+ protected:
+ PaymentRequestSpecBasiCardEnabledTest() {
+ feature_list_.InitAndEnableFeature(::features::kPaymentRequestBasicCard);
+ }
+
+ private:
+ base::test::ScopedFeatureList feature_list_;
};
// Test that empty method data is parsed correctly.
-TEST_F(PaymentRequestSpecTest, EmptyMethodData) {
+TEST_F(PaymentRequestSpecBasiCardEnabledTest, EmptyMethodData) {
std::vector<mojom::PaymentMethodDataPtr> method_data;
RecreateSpecWithMethodData(std::move(method_data));
@@ -61,7 +80,8 @@ TEST_F(PaymentRequestSpecTest, EmptyMethodData) {
EXPECT_EQ(0u, spec()->supported_card_networks().size());
}
-TEST_F(PaymentRequestSpecTest, IsMethodSupportedThroughBasicCard) {
+TEST_F(PaymentRequestSpecBasiCardEnabledTest,
+ IsMethodSupportedThroughBasicCard) {
mojom::PaymentMethodDataPtr entry1 = mojom::PaymentMethodData::New();
entry1->supported_method = "visa";
mojom::PaymentMethodDataPtr entry2 = mojom::PaymentMethodData::New();
@@ -97,7 +117,7 @@ TEST_F(PaymentRequestSpecTest, IsMethodSupportedThroughBasicCard) {
}
// Order matters when parsing the supportedMethods and basic card networks.
-TEST_F(PaymentRequestSpecTest,
+TEST_F(PaymentRequestSpecBasiCardEnabledTest,
IsMethodSupportedThroughBasicCard_DifferentOrder) {
mojom::PaymentMethodDataPtr entry1 = mojom::PaymentMethodData::New();
entry1->supported_method = "basic-card";
@@ -129,7 +149,7 @@ TEST_F(PaymentRequestSpecTest,
// Test that parsing supported methods (with invalid values and duplicates)
// works as expected.
-TEST_F(PaymentRequestSpecTest, SupportedMethods) {
+TEST_F(PaymentRequestSpecBasiCardEnabledTest, SupportedMethods) {
mojom::PaymentMethodDataPtr entry1 = mojom::PaymentMethodData::New();
entry1->supported_method = "basic-card";
entry1->supported_networks.push_back(mojom::BasicCardNetwork::VISA);
@@ -157,7 +177,8 @@ TEST_F(PaymentRequestSpecTest, SupportedMethods) {
// Test that parsing supported methods in different method data entries fails as
// soon as one entry doesn't specify anything in supported_methods.
-TEST_F(PaymentRequestSpecTest, SupportedMethods_MultipleEntries_OneEmpty) {
+TEST_F(PaymentRequestSpecBasiCardEnabledTest,
+ SupportedMethods_MultipleEntries_OneEmpty) {
// First entry is valid.
mojom::PaymentMethodDataPtr entry = mojom::PaymentMethodData::New();
entry->supported_method = "basic-card";
@@ -181,7 +202,7 @@ TEST_F(PaymentRequestSpecTest, SupportedMethods_MultipleEntries_OneEmpty) {
}
// Test that only specifying basic-card means that all are supported.
-TEST_F(PaymentRequestSpecTest, SupportedMethods_OnlyBasicCard) {
+TEST_F(PaymentRequestSpecBasiCardEnabledTest, SupportedMethods_OnlyBasicCard) {
mojom::PaymentMethodDataPtr entry = mojom::PaymentMethodData::New();
entry->supported_method = "basic-card";
std::vector<mojom::PaymentMethodDataPtr> method_data;
@@ -203,7 +224,8 @@ TEST_F(PaymentRequestSpecTest, SupportedMethods_OnlyBasicCard) {
// Test that specifying a method AND basic-card means that all are supported,
// but with the method as first.
-TEST_F(PaymentRequestSpecTest, SupportedMethods_BasicCard_WithSpecificMethod) {
+TEST_F(PaymentRequestSpecBasiCardEnabledTest,
+ SupportedMethods_BasicCard_WithSpecificMethod) {
mojom::PaymentMethodDataPtr entry1 = mojom::PaymentMethodData::New();
entry1->supported_method = "jcb";
mojom::PaymentMethodDataPtr entry2 = mojom::PaymentMethodData::New();
@@ -224,7 +246,8 @@ TEST_F(PaymentRequestSpecTest, SupportedMethods_BasicCard_WithSpecificMethod) {
// Test that specifying basic-card with a supported network (with previous
// supported methods) will work as expected
-TEST_F(PaymentRequestSpecTest, SupportedMethods_BasicCard_Overlap) {
+TEST_F(PaymentRequestSpecBasiCardEnabledTest,
+ SupportedMethods_BasicCard_Overlap) {
mojom::PaymentMethodDataPtr entry1 = mojom::PaymentMethodData::New();
entry1->supported_method = "mastercard";
mojom::PaymentMethodDataPtr entry2 = mojom::PaymentMethodData::New();
@@ -249,7 +272,7 @@ TEST_F(PaymentRequestSpecTest, SupportedMethods_BasicCard_Overlap) {
// Test that specifying basic-card with supported networks after specifying
// some methods
-TEST_F(PaymentRequestSpecTest,
+TEST_F(PaymentRequestSpecBasiCardEnabledTest,
SupportedMethods_BasicCard_WithSupportedNetworks) {
mojom::PaymentMethodDataPtr entry = mojom::PaymentMethodData::New();
entry->supported_method = "basic-card";
@@ -268,7 +291,7 @@ TEST_F(PaymentRequestSpecTest,
// Test that the last shipping option is selected, even in the case of
// updateWith.
-TEST_F(PaymentRequestSpecTest, ShippingOptionsSelection) {
+TEST_F(PaymentRequestSpecBasiCardEnabledTest, ShippingOptionsSelection) {
std::vector<mojom::PaymentShippingOptionPtr> shipping_options;
mojom::PaymentShippingOptionPtr option = mojom::PaymentShippingOption::New();
option->id = "option:1";
@@ -311,7 +334,8 @@ TEST_F(PaymentRequestSpecTest, ShippingOptionsSelection) {
// Test that the last shipping option is selected, even in the case of
// updateWith.
-TEST_F(PaymentRequestSpecTest, ShippingOptionsSelection_NoOptionsAtAll) {
+TEST_F(PaymentRequestSpecBasiCardEnabledTest,
+ ShippingOptionsSelection_NoOptionsAtAll) {
// No options are provided at first.
mojom::PaymentOptionsPtr options = mojom::PaymentOptions::New();
options->request_shipping = true;
@@ -350,7 +374,7 @@ TEST_F(PaymentRequestSpecTest, ShippingOptionsSelection_NoOptionsAtAll) {
// Test that the last shipping option is selected, even in the case of
// updateWith.
-TEST_F(PaymentRequestSpecTest, UpdateWithNoShippingOptions) {
+TEST_F(PaymentRequestSpecBasiCardEnabledTest, UpdateWithNoShippingOptions) {
std::vector<mojom::PaymentShippingOptionPtr> shipping_options;
mojom::PaymentShippingOptionPtr option = mojom::PaymentShippingOption::New();
option->id = "option:1";
@@ -377,7 +401,8 @@ TEST_F(PaymentRequestSpecTest, UpdateWithNoShippingOptions) {
EXPECT_TRUE(spec()->selected_shipping_option_error().empty());
}
-TEST_F(PaymentRequestSpecTest, SingleCurrencyWithoutDisplayItems) {
+TEST_F(PaymentRequestSpecBasiCardEnabledTest,
+ SingleCurrencyWithoutDisplayItems) {
mojom::PaymentDetailsPtr details = mojom::PaymentDetails::New();
mojom::PaymentItemPtr total = mojom::PaymentItem::New();
mojom::PaymentCurrencyAmountPtr amount = mojom::PaymentCurrencyAmount::New();
@@ -391,7 +416,7 @@ TEST_F(PaymentRequestSpecTest, SingleCurrencyWithoutDisplayItems) {
EXPECT_FALSE(spec()->IsMixedCurrency());
}
-TEST_F(PaymentRequestSpecTest, SingleCurrencyWithDisplayItems) {
+TEST_F(PaymentRequestSpecBasiCardEnabledTest, SingleCurrencyWithDisplayItems) {
mojom::PaymentDetailsPtr details = mojom::PaymentDetails::New();
mojom::PaymentItemPtr total = mojom::PaymentItem::New();
mojom::PaymentCurrencyAmountPtr amount = mojom::PaymentCurrencyAmount::New();
@@ -414,7 +439,8 @@ TEST_F(PaymentRequestSpecTest, SingleCurrencyWithDisplayItems) {
EXPECT_FALSE(spec()->IsMixedCurrency());
}
-TEST_F(PaymentRequestSpecTest, MultipleCurrenciesWithOneDisplayItem) {
+TEST_F(PaymentRequestSpecBasiCardEnabledTest,
+ MultipleCurrenciesWithOneDisplayItem) {
mojom::PaymentDetailsPtr details = mojom::PaymentDetails::New();
mojom::PaymentItemPtr total = mojom::PaymentItem::New();
mojom::PaymentCurrencyAmountPtr amount = mojom::PaymentCurrencyAmount::New();
@@ -438,7 +464,8 @@ TEST_F(PaymentRequestSpecTest, MultipleCurrenciesWithOneDisplayItem) {
EXPECT_TRUE(spec()->IsMixedCurrency());
}
-TEST_F(PaymentRequestSpecTest, MultipleCurrenciesWithTwoDisplayItem) {
+TEST_F(PaymentRequestSpecBasiCardEnabledTest,
+ MultipleCurrenciesWithTwoDisplayItem) {
mojom::PaymentDetailsPtr details = mojom::PaymentDetails::New();
mojom::PaymentItemPtr total = mojom::PaymentItem::New();
mojom::PaymentCurrencyAmountPtr amount = mojom::PaymentCurrencyAmount::New();
@@ -469,7 +496,7 @@ TEST_F(PaymentRequestSpecTest, MultipleCurrenciesWithTwoDisplayItem) {
EXPECT_TRUE(spec()->IsMixedCurrency());
}
-TEST_F(PaymentRequestSpecTest, RetryWithShippingAddressErrors) {
+TEST_F(PaymentRequestSpecBasiCardEnabledTest, RetryWithShippingAddressErrors) {
mojom::PaymentOptionsPtr options = mojom::PaymentOptions::New();
options->request_shipping = true;
RecreateSpecWithOptionsAndDetails(std::move(options),
@@ -496,7 +523,7 @@ TEST_F(PaymentRequestSpecTest, RetryWithShippingAddressErrors) {
EXPECT_TRUE(spec()->has_shipping_address_error());
}
-TEST_F(PaymentRequestSpecTest, RetryWithPayerErrors) {
+TEST_F(PaymentRequestSpecBasiCardEnabledTest, RetryWithPayerErrors) {
mojom::PaymentOptionsPtr options = mojom::PaymentOptions::New();
options->request_payer_email = true;
options->request_payer_name = true;
@@ -524,5 +551,4 @@ TEST_F(PaymentRequestSpecTest, RetryWithPayerErrors) {
EXPECT_TRUE(spec()->has_payer_error());
}
-
} // namespace payments
diff --git a/chromium/components/payments/content/payment_request_state_unittest.cc b/chromium/components/payments/content/payment_request_state_unittest.cc
index 620fd16a5eb..b499886ee98 100644
--- a/chromium/components/payments/content/payment_request_state_unittest.cc
+++ b/chromium/components/payments/content/payment_request_state_unittest.cc
@@ -4,6 +4,7 @@
#include "components/payments/content/payment_request_state.h"
+#include <string>
#include <utility>
#include "base/bind.h"
@@ -16,6 +17,7 @@
#include "components/autofill/core/browser/data_model/autofill_profile.h"
#include "components/autofill/core/browser/data_model/credit_card.h"
#include "components/autofill/core/browser/test_personal_data_manager.h"
+#include "components/payments/content/payment_app_factory.h"
#include "components/payments/content/payment_app_service.h"
#include "components/payments/content/payment_app_service_factory.h"
#include "components/payments/content/payment_request_spec.h"
@@ -31,34 +33,91 @@
#include "third_party/blink/public/mojom/payments/payment_request.mojom.h"
namespace payments {
+namespace {
+
+class TestApp : public PaymentApp {
+ public:
+ explicit TestApp(const std::string& method)
+ : PaymentApp(/*icon_resource_id=*/0,
+ PaymentApp::Type::SERVICE_WORKER_APP),
+ method_(method) {}
+
+ TestApp(const TestApp& other) = delete;
+ TestApp& operator=(const TestApp& other) = delete;
+
+ // PaymentApp:
+ void InvokePaymentApp(base::WeakPtr<Delegate> delegate) override {}
+ bool IsCompleteForPayment() const override { return true; }
+ uint32_t GetCompletenessScore() const override { return 0; }
+ bool CanPreselect() const override { return true; }
+ std::u16string GetMissingInfoLabel() const override {
+ return std::u16string();
+ }
+ bool HasEnrolledInstrument() const override { return true; }
+ void RecordUse() override {}
+ bool NeedsInstallation() const override { return false; }
+ std::string GetId() const override { return method_; }
+ std::u16string GetLabel() const override { return std::u16string(); }
+ std::u16string GetSublabel() const override { return std::u16string(); }
+ bool IsValidForModifier(
+ const std::string& method,
+ bool supported_networks_specified,
+ const std::set<std::string>& supported_networks) const override {
+ return false;
+ }
+ base::WeakPtr<PaymentApp> AsWeakPtr() override {
+ return weak_ptr_factory_.GetWeakPtr();
+ }
+ bool HandlesShippingAddress() const override { return false; }
+ bool HandlesPayerName() const override { return false; }
+ bool HandlesPayerEmail() const override { return false; }
+ bool HandlesPayerPhone() const override { return false; }
-class PaymentRequestStateTest : public testing::Test,
- public PaymentRequestState::Observer,
- public PaymentRequestState::Delegate {
+ private:
+ const std::string method_;
+ base::WeakPtrFactory<TestApp> weak_ptr_factory_{this};
+};
+
+class TestAppFactory : public PaymentAppFactory {
+ public:
+ explicit TestAppFactory(const std::string& method)
+ : PaymentAppFactory(PaymentApp::Type::SERVICE_WORKER_APP),
+ method_(method) {}
+
+ TestAppFactory(const TestAppFactory& other) = delete;
+ TestAppFactory& operator=(const TestAppFactory& other) = delete;
+
+ void Create(base::WeakPtr<Delegate> delegate) override {
+ auto requested_methods =
+ delegate->GetSpec()->payment_method_identifiers_set();
+ if (requested_methods.find(method_) != requested_methods.end())
+ delegate->OnPaymentAppCreated(std::make_unique<TestApp>(method_));
+ delegate->OnDoneCreatingPaymentApps();
+ }
+
+ private:
+ const std::string method_;
+};
+
+class PaymentRequestStateTestBase : public testing::Test,
+ public PaymentRequestState::Observer,
+ public PaymentRequestState::Delegate {
protected:
- PaymentRequestStateTest()
+ PaymentRequestStateTestBase()
: num_on_selected_information_changed_called_(0),
test_payment_request_delegate_(/*task_executor=*/nullptr,
&test_personal_data_manager_),
journey_logger_(test_payment_request_delegate_.IsOffTheRecord(),
ukm::UkmRecorder::GetNewSourceID()),
- address_(autofill::test::GetFullProfile()),
- credit_card_visa_(autofill::test::GetCreditCard()) {
- scoped_feature_list_.InitAndDisableFeature(
- features::kServiceWorkerPaymentApps);
-
+ address_(autofill::test::GetFullProfile()) {
// Must be initialized after scoped_feature_list_ (crbug.com/1172599)
web_contents_ = web_contents_factory_.CreateWebContents(&context_);
- test_personal_data_manager_.SetAutofillCreditCardEnabled(true);
test_personal_data_manager_.SetAutofillProfileEnabled(true);
test_personal_data_manager_.SetAutofillWalletImportEnabled(true);
test_personal_data_manager_.AddProfile(address_);
- credit_card_visa_.set_billing_address_id(address_.guid());
- credit_card_visa_.set_use_count(5u);
- test_personal_data_manager_.AddCreditCard(credit_card_visa_);
}
- ~PaymentRequestStateTest() override {}
+ ~PaymentRequestStateTestBase() override = default;
// PaymentRequestState::Observer:
void OnGetAllPaymentAppsFinished() override {}
@@ -77,10 +136,10 @@ class PaymentRequestStateTest : public testing::Test,
}
void OnPayerInfoSelected(mojom::PayerDetailPtr payer_info) override {}
- void RecreateStateWithOptionsAndDetails(
- mojom::PaymentOptionsPtr options,
- mojom::PaymentDetailsPtr details,
- std::vector<mojom::PaymentMethodDataPtr> method_data) {
+ void RecreateState(mojom::PaymentOptionsPtr options,
+ mojom::PaymentDetailsPtr details,
+ std::vector<mojom::PaymentMethodDataPtr> method_data,
+ std::unique_ptr<PaymentAppService> app_service) {
if (!details->total)
details->total = mojom::PaymentItem::New();
details->id = "test_id";
@@ -88,8 +147,7 @@ class PaymentRequestStateTest : public testing::Test,
spec_ = std::make_unique<PaymentRequestSpec>(
std::move(options), std::move(details), std::move(method_data),
/*observer=*/nullptr, "en-US");
- PaymentAppServiceFactory::SetForTesting(
- std::make_unique<PaymentAppService>(&context_));
+ PaymentAppServiceFactory::SetForTesting(std::move(app_service));
state_ = std::make_unique<PaymentRequestState>(
web_contents_->GetMainFrame(), GURL("https://example.com"),
GURL("https://example.com/pay"),
@@ -100,13 +158,6 @@ class PaymentRequestStateTest : public testing::Test,
state_->AddObserver(this);
}
- // Convenience method to create a PaymentRequestState with default details
- // (one shipping option) and method data (only supports visa).
- void RecreateStateWithOptions(mojom::PaymentOptionsPtr options) {
- RecreateStateWithOptionsAndDetails(
- std::move(options), CreateDefaultDetails(), GetMethodDataForVisa());
- }
-
// Convenience method that returns a dummy PaymentDetails with a single
// shipping option.
mojom::PaymentDetailsPtr CreateDefaultDetails() {
@@ -121,16 +172,6 @@ class PaymentRequestStateTest : public testing::Test,
return details;
}
- // Convenience method that returns MethodData that supports Visa.
- std::vector<mojom::PaymentMethodDataPtr> GetMethodDataForVisa() {
- std::vector<mojom::PaymentMethodDataPtr> method_data;
- mojom::PaymentMethodDataPtr entry = mojom::PaymentMethodData::New();
- entry->supported_method = "basic-card";
- entry->supported_networks.push_back(mojom::BasicCardNetwork::VISA);
- method_data.push_back(std::move(entry));
- return method_data;
- }
-
PaymentRequestState* state() { return state_.get(); }
PaymentRequestSpec* spec() { return spec_.get(); }
const mojom::PaymentResponsePtr& response() { return payment_response_; }
@@ -146,8 +187,6 @@ class PaymentRequestStateTest : public testing::Test,
return &test_payment_request_delegate_;
}
- private:
- base::test::ScopedFeatureList scoped_feature_list_;
content::BrowserTaskEnvironment task_environment_;
content::TestBrowserContext context_;
content::TestWebContentsFactory web_contents_factory_;
@@ -164,8 +203,49 @@ class PaymentRequestStateTest : public testing::Test,
// Test data.
autofill::AutofillProfile address_;
+ base::WeakPtrFactory<PaymentRequestStateTestBase> weak_ptr_factory_{this};
+};
+
+class PaymentRequestStateTest : public PaymentRequestStateTestBase {
+ protected:
+ PaymentRequestStateTest()
+ : credit_card_visa_(autofill::test::GetCreditCard()) {
+ scoped_feature_list_.InitWithFeatures(
+ {::features::kPaymentRequestBasicCard},
+ {features::kServiceWorkerPaymentApps});
+
+ // Must be initialized after scoped_feature_list_ (crbug.com/1172599)
+ web_contents_ = web_contents_factory_.CreateWebContents(&context_);
+
+ test_personal_data_manager_.SetAutofillCreditCardEnabled(true);
+ credit_card_visa_.set_billing_address_id(address_.guid());
+ credit_card_visa_.set_use_count(5u);
+ test_personal_data_manager_.AddCreditCard(credit_card_visa_);
+ }
+ ~PaymentRequestStateTest() override = default;
+
+ // Convenience method to create a PaymentRequestState with default details
+ // (one shipping option) and method data (only supports visa).
+ void RecreateStateWithOptions(mojom::PaymentOptionsPtr options) {
+ RecreateState(std::move(options), CreateDefaultDetails(),
+ GetMethodDataForVisa(),
+ std::make_unique<PaymentAppService>(&context_));
+ }
+
+ // Convenience method that returns MethodData that supports Visa.
+ std::vector<mojom::PaymentMethodDataPtr> GetMethodDataForVisa() {
+ std::vector<mojom::PaymentMethodDataPtr> method_data;
+ mojom::PaymentMethodDataPtr entry = mojom::PaymentMethodData::New();
+ entry->supported_method = "basic-card";
+ entry->supported_networks.push_back(mojom::BasicCardNetwork::VISA);
+ method_data.push_back(std::move(entry));
+ return method_data;
+ }
+
+ private:
+ base::test::ScopedFeatureList scoped_feature_list_;
+ // Test data.
autofill::CreditCard credit_card_visa_;
- base::WeakPtrFactory<PaymentRequestStateTest> weak_ptr_factory_{this};
};
TEST_F(PaymentRequestStateTest, CanMakePayment) {
@@ -189,9 +269,9 @@ TEST_F(PaymentRequestStateTest, CanMakePayment_NoEnrolledInstrument) {
entry->supported_method = "basic-card";
entry->supported_networks.push_back(mojom::BasicCardNetwork::MASTERCARD);
method_data.push_back(std::move(entry));
- RecreateStateWithOptionsAndDetails(mojom::PaymentOptions::New(),
- mojom::PaymentDetails::New(),
- std::move(method_data));
+ RecreateState(mojom::PaymentOptions::New(), mojom::PaymentDetails::New(),
+ std::move(method_data),
+ std::make_unique<PaymentAppService>(&context_));
state()->HasEnrolledInstrument(
base::BindOnce([](bool has_enrolled_instrument) {
@@ -209,9 +289,9 @@ TEST_F(PaymentRequestStateTest, CanMakePayment_UnsupportedPaymentMethod) {
mojom::PaymentMethodDataPtr entry = mojom::PaymentMethodData::New();
entry->supported_method = "unsupported_method";
method_data.push_back(std::move(entry));
- RecreateStateWithOptionsAndDetails(mojom::PaymentOptions::New(),
- mojom::PaymentDetails::New(),
- std::move(method_data));
+ RecreateState(mojom::PaymentOptions::New(), mojom::PaymentDetails::New(),
+ std::move(method_data),
+ std::make_unique<PaymentAppService>(&context_));
state()->HasEnrolledInstrument(
base::BindOnce([](bool has_enrolled_instrument) {
@@ -230,9 +310,9 @@ TEST_F(PaymentRequestStateTest, CanMakePayment_OnlyBasicCard) {
entry->supported_method = "basic-card";
std::vector<mojom::PaymentMethodDataPtr> method_data;
method_data.push_back(std::move(entry));
- RecreateStateWithOptionsAndDetails(mojom::PaymentOptions::New(),
- mojom::PaymentDetails::New(),
- std::move(method_data));
+ RecreateState(mojom::PaymentOptions::New(), mojom::PaymentDetails::New(),
+ std::move(method_data),
+ std::make_unique<PaymentAppService>(&context_));
state()->HasEnrolledInstrument(
base::BindOnce([](bool has_enrolled_instrument) {
@@ -251,9 +331,9 @@ TEST_F(PaymentRequestStateTest, CanMakePayment_BasicCard_SpecificAvailable) {
entry->supported_networks.push_back(mojom::BasicCardNetwork::VISA);
std::vector<mojom::PaymentMethodDataPtr> method_data;
method_data.push_back(std::move(entry));
- RecreateStateWithOptionsAndDetails(mojom::PaymentOptions::New(),
- mojom::PaymentDetails::New(),
- std::move(method_data));
+ RecreateState(mojom::PaymentOptions::New(), mojom::PaymentDetails::New(),
+ std::move(method_data),
+ std::make_unique<PaymentAppService>(&context_));
state()->HasEnrolledInstrument(
base::BindOnce([](bool has_enrolled_instrument) {
@@ -273,9 +353,9 @@ TEST_F(PaymentRequestStateTest,
entry->supported_networks.push_back(mojom::BasicCardNetwork::JCB);
std::vector<mojom::PaymentMethodDataPtr> method_data;
method_data.push_back(std::move(entry));
- RecreateStateWithOptionsAndDetails(mojom::PaymentOptions::New(),
- mojom::PaymentDetails::New(),
- std::move(method_data));
+ RecreateState(mojom::PaymentOptions::New(), mojom::PaymentDetails::New(),
+ std::move(method_data),
+ std::make_unique<PaymentAppService>(&context_));
state()->HasEnrolledInstrument(
base::BindOnce([](bool has_enrolled_instrument) {
@@ -295,9 +375,9 @@ TEST_F(PaymentRequestStateTest, CanMakePayment_BasicCard_SpecificUnavailable) {
entry->supported_networks.push_back(mojom::BasicCardNetwork::MASTERCARD);
std::vector<mojom::PaymentMethodDataPtr> method_data;
method_data.push_back(std::move(entry));
- RecreateStateWithOptionsAndDetails(mojom::PaymentOptions::New(),
- mojom::PaymentDetails::New(),
- std::move(method_data));
+ RecreateState(mojom::PaymentOptions::New(), mojom::PaymentDetails::New(),
+ std::move(method_data),
+ std::make_unique<PaymentAppService>(&context_));
state()->HasEnrolledInstrument(
base::BindOnce([](bool has_enrolled_instrument) {
@@ -341,7 +421,7 @@ TEST_F(PaymentRequestStateTest, ReadyToPay_DefaultSelections) {
EXPECT_TRUE(state()->is_ready_to_pay());
}
-// Testing that only supported intruments are shown. In this test the merchant
+// Testing that only supported instruments are shown. In this test the merchant
// only supports Visa.
TEST_F(PaymentRequestStateTest, UnsupportedCardAreNotAvailable) {
// Default options.
@@ -551,4 +631,280 @@ TEST_F(PaymentRequestStateTest, RetryWithPayerErrors) {
EXPECT_TRUE(state()->invalid_contact_profile());
}
+// The tests in this class correspond to the tests of the same name in
+// PaymentRequestStateTest, with the basic-card being disabled. Parameterized
+// tests are not used because the test setup for both tests are too different.
+class PaymentRequestStateBasicCardDisabledTest
+ : public PaymentRequestStateTestBase {
+ protected:
+ static constexpr char kMethodName[] = "https://www.chromium.org";
+
+ PaymentRequestStateBasicCardDisabledTest() {
+ scoped_feature_list_.InitAndDisableFeature(
+ ::features::kPaymentRequestBasicCard);
+ // Must be initialized after scoped_feature_list_ (crbug.com/1172599)
+ web_contents_ = web_contents_factory_.CreateWebContents(&context_);
+
+ test_personal_data_manager_.SetAutofillProfileEnabled(true);
+ test_personal_data_manager_.SetAutofillWalletImportEnabled(true);
+ test_personal_data_manager_.AddProfile(address_);
+ }
+ ~PaymentRequestStateBasicCardDisabledTest() override = default;
+
+ // Convenience method to create a PaymentRequestState with default details
+ // (one shipping option) and method data (only supports a url method).
+ void RecreateStateWithOptions(mojom::PaymentOptionsPtr options) {
+ RecreateStateWithRequestedMethodAndOptions(
+ /*requested_method==*/installed_app_method_, std::move(options));
+ }
+
+ void RecreateStateWithRequestedMethodAndOptions(
+ const std::string& requested_method,
+ mojom::PaymentOptionsPtr options) {
+ auto app_service = std::make_unique<PaymentAppService>(&context_);
+ app_service->AddFactoryForTesting(
+ std::make_unique<TestAppFactory>(installed_app_method_));
+ RecreateState(std::move(options), CreateDefaultDetails(),
+ GetMethodDataForUrlMethod(requested_method),
+ std::move(app_service));
+ base::RunLoop run_loop;
+ state()->AreRequestedMethodsSupported(
+ base::BindOnce(&OnMethodSupportResult, run_loop.QuitClosure()));
+ run_loop.Run();
+ }
+
+ // Convenience method that returns MethodData that supports a url method.
+ std::vector<mojom::PaymentMethodDataPtr> GetMethodDataForUrlMethod(
+ const std::string& requested_method = kMethodName) {
+ std::vector<mojom::PaymentMethodDataPtr> method_data;
+ mojom::PaymentMethodDataPtr entry = mojom::PaymentMethodData::New();
+ entry->supported_method = requested_method;
+ method_data.push_back(std::move(entry));
+ return method_data;
+ }
+
+ const std::string& installed_app_method() const {
+ return installed_app_method_;
+ }
+
+ private:
+ static void OnMethodSupportResult(base::RepeatingClosure quit_closure,
+ bool methods_supported,
+ const std::string& error_message,
+ AppCreationFailureReason error_reason) {
+ quit_closure.Run();
+ }
+
+ base::test::ScopedFeatureList scoped_feature_list_;
+ const std::string installed_app_method_ = kMethodName;
+};
+
+TEST_F(PaymentRequestStateBasicCardDisabledTest, CanMakePayment) {
+ // Default options.
+ RecreateStateWithOptions(mojom::PaymentOptions::New());
+
+ state()->HasEnrolledInstrument(
+ base::BindOnce([](bool has_enrolled_instrument) {
+ EXPECT_TRUE(has_enrolled_instrument);
+ }));
+
+ // CanMakePayment returns true because the requested method is supported.
+ state()->CanMakePayment(base::BindOnce(
+ [](bool can_make_payment) { EXPECT_TRUE(can_make_payment); }));
+}
+
+TEST_F(PaymentRequestStateBasicCardDisabledTest,
+ CanMakePayment_NoEnrolledInstrument) {
+ std::vector<mojom::PaymentMethodDataPtr> method_data;
+ mojom::PaymentMethodDataPtr entry = mojom::PaymentMethodData::New();
+ entry->supported_method = installed_app_method();
+ method_data.push_back(std::move(entry));
+ auto app_service = std::make_unique<PaymentAppService>(&context_);
+ app_service->AddFactoryForTesting(
+ std::make_unique<TestAppFactory>(installed_app_method()));
+ RecreateState(mojom::PaymentOptions::New(), mojom::PaymentDetails::New(),
+ std::move(method_data), std::move(app_service));
+
+ state()->HasEnrolledInstrument(
+ base::BindOnce([](bool has_enrolled_instrument) {
+ EXPECT_FALSE(has_enrolled_instrument);
+ }));
+
+ // CanMakePayment returns true because the requested method is supported, even
+ // though the payment app is not ready to pay.
+ state()->CanMakePayment(base::BindOnce(
+ [](bool can_make_payment) { EXPECT_TRUE(can_make_payment); }));
+}
+
+TEST_F(PaymentRequestStateBasicCardDisabledTest,
+ CanMakePayment_UnsupportedPaymentMethod) {
+ std::vector<mojom::PaymentMethodDataPtr> method_data;
+ mojom::PaymentMethodDataPtr entry = mojom::PaymentMethodData::New();
+ entry->supported_method = "unsupported_method";
+ method_data.push_back(std::move(entry));
+ RecreateState(mojom::PaymentOptions::New(), mojom::PaymentDetails::New(),
+ std::move(method_data),
+ std::make_unique<PaymentAppService>(&context_));
+
+ state()->HasEnrolledInstrument(
+ base::BindOnce([](bool has_enrolled_instrument) {
+ EXPECT_FALSE(has_enrolled_instrument);
+ }));
+
+ // CanMakePayment returns true because the requested method is supported, even
+ // though the payment app is not ready to pay.
+ state()->CanMakePayment(base::BindOnce(
+ [](bool can_make_payment) { EXPECT_FALSE(can_make_payment); }));
+}
+
+// Test selecting a contact info profile will make the user ready to pay.
+TEST_F(PaymentRequestStateBasicCardDisabledTest, ReadyToPay_ContactInfo) {
+ mojom::PaymentOptionsPtr options = mojom::PaymentOptions::New();
+ options->request_payer_name = true;
+ options->request_payer_phone = true;
+ options->request_payer_email = true;
+ RecreateStateWithOptions(std::move(options));
+ int expected_changes = 2;
+ EXPECT_EQ(expected_changes, num_on_selected_information_changed_called());
+
+ // Ready to pay because of default selections.
+ EXPECT_TRUE(state()->is_ready_to_pay());
+
+ // Unselecting contact profile.
+ state()->SetSelectedContactProfile(/*profile=*/nullptr);
+ EXPECT_EQ(++expected_changes, num_on_selected_information_changed_called());
+
+ EXPECT_FALSE(state()->is_ready_to_pay());
+
+ state()->SetSelectedContactProfile(test_address());
+ EXPECT_EQ(++expected_changes, num_on_selected_information_changed_called());
+
+ // Ready to pay!
+ EXPECT_TRUE(state()->is_ready_to_pay());
+}
+
+TEST_F(PaymentRequestStateBasicCardDisabledTest, ReadyToPay_DefaultSelections) {
+ mojom::PaymentOptionsPtr options = mojom::PaymentOptions::New();
+ options->request_shipping = true;
+ options->request_payer_name = true;
+ options->request_payer_phone = true;
+ options->request_payer_email = true;
+ RecreateStateWithOptions(std::move(options));
+ int expected_changes = 2;
+ EXPECT_EQ(expected_changes, num_on_selected_information_changed_called());
+
+ // Because there are shipping options, no address is selected by default.
+ // Therefore we are not ready to pay.
+ EXPECT_FALSE(state()->is_ready_to_pay());
+
+ state()->SetSelectedShippingProfile(test_address());
+ EXPECT_EQ(expected_changes, num_on_selected_information_changed_called());
+
+ // Simulate that the merchant has validated the shipping address change.
+ spec()->UpdateWith(CreateDefaultDetails());
+ EXPECT_EQ(++expected_changes, num_on_selected_information_changed_called());
+
+ // Not ready to pay since there's no selected shipping option.
+ EXPECT_FALSE(state()->is_ready_to_pay());
+
+ // Simulate that the website validates the shipping option.
+ state()->SetSelectedShippingOption("option:1");
+ auto details = CreateDefaultDetails();
+ (*details->shipping_options)[0]->selected = true;
+ spec()->UpdateWith(std::move(details));
+ EXPECT_EQ(++expected_changes, num_on_selected_information_changed_called());
+ EXPECT_TRUE(state()->is_ready_to_pay());
+}
+
+TEST_F(PaymentRequestStateBasicCardDisabledTest, RetryWithPayerErrors) {
+ mojom::PaymentOptionsPtr options = mojom::PaymentOptions::New();
+ options->request_payer_name = true;
+ options->request_payer_phone = true;
+ options->request_payer_email = true;
+ RecreateStateWithOptions(std::move(options));
+ int expected_changes = 2;
+ EXPECT_EQ(expected_changes, num_on_selected_information_changed_called());
+
+ state()->SetSelectedContactProfile(test_address());
+ EXPECT_EQ(++expected_changes, num_on_selected_information_changed_called());
+ EXPECT_TRUE(state()->is_ready_to_pay());
+
+ EXPECT_TRUE(state()->selected_contact_profile());
+ EXPECT_FALSE(state()->invalid_contact_profile());
+
+ mojom::PayerErrorsPtr payer_errors = mojom::PayerErrors::New();
+ payer_errors->email = "Invalid email";
+ payer_errors->name = "Invalid name";
+ payer_errors->phone = "Invalid phone";
+
+ mojom::PaymentValidationErrorsPtr errors =
+ mojom::PaymentValidationErrors::New();
+ errors->payer = std::move(payer_errors);
+ spec()->Retry(std::move(errors));
+ EXPECT_EQ(++expected_changes, num_on_selected_information_changed_called());
+ EXPECT_FALSE(state()->is_ready_to_pay());
+
+ EXPECT_FALSE(state()->selected_contact_profile());
+ EXPECT_TRUE(state()->invalid_contact_profile());
+}
+
+TEST_F(PaymentRequestStateBasicCardDisabledTest,
+ RetryWithShippingAddressErrors) {
+ mojom::PaymentOptionsPtr options = mojom::PaymentOptions::New();
+ options->request_shipping = true;
+ RecreateStateWithOptions(std::move(options));
+ int expected_changes = 2;
+ EXPECT_EQ(expected_changes, num_on_selected_information_changed_called());
+
+ // Because there are shipping options, no address is selected by default.
+ // Therefore we are not ready to pay.
+ EXPECT_FALSE(state()->is_ready_to_pay());
+
+ state()->SetSelectedShippingProfile(test_address());
+ EXPECT_EQ(expected_changes, num_on_selected_information_changed_called());
+
+ // Simulate that the merchant has validated the shipping address change.
+ spec()->UpdateWith(CreateDefaultDetails());
+ EXPECT_EQ(++expected_changes, num_on_selected_information_changed_called());
+
+ // Not ready to pay since there's no selected shipping option.
+ EXPECT_FALSE(state()->is_ready_to_pay());
+
+ // Simulate that the website validates the shipping option.
+ state()->SetSelectedShippingOption("option:1");
+ auto details = CreateDefaultDetails();
+ (*details->shipping_options)[0]->selected = true;
+ spec()->UpdateWith(std::move(details));
+ EXPECT_EQ(++expected_changes, num_on_selected_information_changed_called());
+ EXPECT_TRUE(state()->is_ready_to_pay());
+
+ EXPECT_TRUE(state()->selected_shipping_profile());
+ EXPECT_FALSE(state()->invalid_shipping_profile());
+
+ mojom::AddressErrorsPtr shipping_address_errors = mojom::AddressErrors::New();
+ shipping_address_errors->address_line = "Invalid address line";
+ shipping_address_errors->city = "Invalid city";
+
+ mojom::PaymentValidationErrorsPtr errors =
+ mojom::PaymentValidationErrors::New();
+ errors->shipping_address = std::move(shipping_address_errors);
+ spec()->Retry(std::move(errors));
+ EXPECT_EQ(++expected_changes, num_on_selected_information_changed_called());
+ EXPECT_FALSE(state()->is_ready_to_pay());
+
+ EXPECT_FALSE(state()->selected_shipping_profile());
+ EXPECT_TRUE(state()->invalid_shipping_profile());
+}
+
+// Testing that only supported instruments are shown. In this test the merchant
+// requests https://payments.example payment method, which is not supported.
+TEST_F(PaymentRequestStateBasicCardDisabledTest, UnsupportedMethod) {
+ RecreateStateWithRequestedMethodAndOptions(
+ /*requested_method=*/"https://payments.example",
+ mojom::PaymentOptions::New());
+ EXPECT_FALSE(state()->is_ready_to_pay());
+ EXPECT_EQ(0u, state()->available_apps().size());
+}
+
+} // namespace
} // namespace payments
diff --git a/chromium/components/payments/content/payment_response_helper_unittest.cc b/chromium/components/payments/content/payment_response_helper_unittest.cc
index a70abc2cea2..7f3d799d4f1 100644
--- a/chromium/components/payments/content/payment_response_helper_unittest.cc
+++ b/chromium/components/payments/content/payment_response_helper_unittest.cc
@@ -13,6 +13,7 @@
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/single_thread_task_executor.h"
+#include "base/test/scoped_feature_list.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
#include "components/autofill/core/browser/data_model/autofill_profile.h"
#include "components/autofill/core/browser/data_model/credit_card.h"
@@ -20,6 +21,7 @@
#include "components/payments/content/autofill_payment_app.h"
#include "components/payments/content/payment_request_spec.h"
#include "components/payments/core/test_payment_request_delegate.h"
+#include "content/public/common/content_features.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/mojom/payments/payment_request.mojom.h"
@@ -155,49 +157,6 @@ TEST_F(PaymentResponseHelperTest, GeneratePaymentResponse_SupportedMethod) {
response()->stringified_details);
}
-// Test generating a PaymentResponse when the method is specified through
-// "basic-card".
-TEST_F(PaymentResponseHelperTest, GeneratePaymentResponse_BasicCard) {
- // The method data supports visa through basic-card.
- mojom::PaymentMethodDataPtr entry = mojom::PaymentMethodData::New();
- entry->supported_method = "basic-card";
- entry->supported_networks.push_back(mojom::BasicCardNetwork::VISA);
- std::vector<mojom::PaymentMethodDataPtr> method_data;
- method_data.push_back(std::move(entry));
- RecreateSpecWithOptionsAndDetails(mojom::PaymentOptions::New(),
- mojom::PaymentDetails::New(),
- std::move(method_data));
-
- // "basic-card" is specified so it is returned as the method name.
- PaymentResponseHelper helper("en-US", spec(), test_app(),
- test_payment_request_delegate(), test_address(),
- test_address(), GetWeakPtr());
- EXPECT_EQ("basic-card", response()->method_name);
- EXPECT_EQ(
- base::StringPrintf(
- "{\"billingAddress\":"
- "{\"addressLine\":[\"666 Erebus St.\",\"Apt 8\"],"
- "\"city\":\"Elysium\","
- "\"country\":\"US\","
- "\"dependentLocality\":\"\","
- "\"organization\":\"Underworld\","
- "\"phone\":\"16502111111\","
- "\"postalCode\":\"91111\","
- "\"recipient\":\"John H. Doe\","
- "\"region\":\"CA\","
- "\"sortingCode\":\"\"},"
- "\"cardNumber\":\"4111111111111111\","
- "\"cardSecurityCode\":\"123\","
- "\"cardholderName\":\"Test User\","
- "\"expiryMonth\":\"%s\","
- "\"expiryYear\":\"%s\"}",
- base::UTF16ToUTF8(test_credit_card().Expiration2DigitMonthAsString())
- .c_str(),
- base::UTF16ToUTF8(test_credit_card().Expiration4DigitYearAsString())
- .c_str()),
- response()->stringified_details);
-}
-
// Tests the the generated PaymentResponse has the correct values for the
// shipping address.
TEST_F(PaymentResponseHelperTest, GeneratePaymentResponse_ShippingAddress) {
@@ -308,4 +267,65 @@ TEST_F(PaymentResponseHelperTest,
EXPECT_EQ("5151231234", response()->payer->phone.value());
}
+class PaymentResponseHelperBasicCardEnabledTest
+ : public PaymentResponseHelperTest {
+ public:
+ PaymentResponseHelperBasicCardEnabledTest(
+ const PaymentResponseHelperBasicCardEnabledTest&) = delete;
+ PaymentResponseHelperBasicCardEnabledTest& operator=(
+ const PaymentResponseHelperBasicCardEnabledTest&) = delete;
+
+ protected:
+ PaymentResponseHelperBasicCardEnabledTest() {
+ feature_list_.InitAndEnableFeature(::features::kPaymentRequestBasicCard);
+ }
+
+ private:
+ base::test::ScopedFeatureList feature_list_;
+};
+
+// Test generating a PaymentResponse when the method is specified through
+// "basic-card".
+TEST_F(PaymentResponseHelperBasicCardEnabledTest,
+ GeneratePaymentResponse_BasicCard) {
+ // The method data supports visa through basic-card.
+ mojom::PaymentMethodDataPtr entry = mojom::PaymentMethodData::New();
+ entry->supported_method = "basic-card";
+ entry->supported_networks.push_back(mojom::BasicCardNetwork::VISA);
+ std::vector<mojom::PaymentMethodDataPtr> method_data;
+ method_data.push_back(std::move(entry));
+ RecreateSpecWithOptionsAndDetails(mojom::PaymentOptions::New(),
+ mojom::PaymentDetails::New(),
+ std::move(method_data));
+
+ // "basic-card" is specified so it is returned as the method name.
+ PaymentResponseHelper helper("en-US", spec(), test_app(),
+ test_payment_request_delegate(), test_address(),
+ test_address(), GetWeakPtr());
+ EXPECT_EQ("basic-card", response()->method_name);
+ EXPECT_EQ(
+ base::StringPrintf(
+ "{\"billingAddress\":"
+ "{\"addressLine\":[\"666 Erebus St.\",\"Apt 8\"],"
+ "\"city\":\"Elysium\","
+ "\"country\":\"US\","
+ "\"dependentLocality\":\"\","
+ "\"organization\":\"Underworld\","
+ "\"phone\":\"16502111111\","
+ "\"postalCode\":\"91111\","
+ "\"recipient\":\"John H. Doe\","
+ "\"region\":\"CA\","
+ "\"sortingCode\":\"\"},"
+ "\"cardNumber\":\"4111111111111111\","
+ "\"cardSecurityCode\":\"123\","
+ "\"cardholderName\":\"Test User\","
+ "\"expiryMonth\":\"%s\","
+ "\"expiryYear\":\"%s\"}",
+ base::UTF16ToUTF8(test_credit_card().Expiration2DigitMonthAsString())
+ .c_str(),
+ base::UTF16ToUTF8(test_credit_card().Expiration4DigitYearAsString())
+ .c_str()),
+ response()->stringified_details);
+}
+
} // namespace payments
diff --git a/chromium/components/payments/content/secure_payment_confirmation_app.cc b/chromium/components/payments/content/secure_payment_confirmation_app.cc
index 239801e21d7..8e488591396 100644
--- a/chromium/components/payments/content/secure_payment_confirmation_app.cc
+++ b/chromium/components/payments/content/secure_payment_confirmation_app.cc
@@ -218,8 +218,7 @@ SecurePaymentConfirmationApp::SetAppSpecificResponseFields(
response->secure_payment_confirmation =
mojom::SecurePaymentConfirmationResponse::New(
response_->info.Clone(), response_->signature,
- response_->has_transport, response_->transport,
- response_->user_handle);
+ response_->authenticator_attachment, response_->user_handle);
return response;
}
@@ -235,7 +234,8 @@ void SecurePaymentConfirmationApp::RenderFrameDeleted(
void SecurePaymentConfirmationApp::OnGetAssertion(
base::WeakPtr<Delegate> delegate,
blink::mojom::AuthenticatorStatus status,
- blink::mojom::GetAssertionAuthenticatorResponsePtr response) {
+ blink::mojom::GetAssertionAuthenticatorResponsePtr response,
+ blink::mojom::WebAuthnDOMExceptionDetailsPtr dom_exception_details) {
if (!delegate)
return;
diff --git a/chromium/components/payments/content/secure_payment_confirmation_app.h b/chromium/components/payments/content/secure_payment_confirmation_app.h
index dbcf28cbf6c..e4d028c3ffa 100644
--- a/chromium/components/payments/content/secure_payment_confirmation_app.h
+++ b/chromium/components/payments/content/secure_payment_confirmation_app.h
@@ -103,7 +103,8 @@ class SecurePaymentConfirmationApp : public PaymentApp,
void OnGetAssertion(
base::WeakPtr<Delegate> delegate,
blink::mojom::AuthenticatorStatus status,
- blink::mojom::GetAssertionAuthenticatorResponsePtr response);
+ blink::mojom::GetAssertionAuthenticatorResponsePtr response,
+ blink::mojom::WebAuthnDOMExceptionDetailsPtr dom_exception_details);
// Used only for comparison with the RenderFrameHost pointer in
// RenderFrameDeleted() method.
diff --git a/chromium/components/payments/content/secure_payment_confirmation_app_unittest.cc b/chromium/components/payments/content/secure_payment_confirmation_app_unittest.cc
index ebf4dfbcc57..2b0c53a0709 100644
--- a/chromium/components/payments/content/secure_payment_confirmation_app_unittest.cc
+++ b/chromium/components/payments/content/secure_payment_confirmation_app_unittest.cc
@@ -68,7 +68,8 @@ class MockAuthenticator : public webauthn::InternalAuthenticator {
std::move(callback).Run(
should_succeed_ ? blink::mojom::AuthenticatorStatus::SUCCESS
: blink::mojom::AuthenticatorStatus::NOT_ALLOWED_ERROR,
- blink::mojom::GetAssertionAuthenticatorResponse::New());
+ blink::mojom::GetAssertionAuthenticatorResponse::New(),
+ /*dom_exception_details=*/nullptr);
}
content::WebContents* web_contents() { return web_contents_; }
diff --git a/chromium/components/payments/content/secure_payment_confirmation_controller.cc b/chromium/components/payments/content/secure_payment_confirmation_controller.cc
index 304db984aad..db80367a8c2 100644
--- a/chromium/components/payments/content/secure_payment_confirmation_controller.cc
+++ b/chromium/components/payments/content/secure_payment_confirmation_controller.cc
@@ -32,9 +32,9 @@ SecurePaymentConfirmationController::~SecurePaymentConfirmationController() =
default;
void SecurePaymentConfirmationController::ShowDialog() {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
NOTREACHED();
-#endif // OS_ANDROID
+#endif // BUILDFLAG(IS_ANDROID)
if (!request_ || !request_->spec())
return;
@@ -178,7 +178,7 @@ void SecurePaymentConfirmationController::ShowCvcUnmaskPrompt(
const autofill::CreditCard& credit_card,
base::WeakPtr<autofill::payments::FullCardRequest::ResultDelegate>
result_delegate,
- content::WebContents* web_contents) {
+ content::RenderFrameHost* render_frame_host) {
// CVC unmasking is nut supported.
NOTREACHED();
}
diff --git a/chromium/components/payments/content/secure_payment_confirmation_controller.h b/chromium/components/payments/content/secure_payment_confirmation_controller.h
index 4917544d606..d2530fc861d 100644
--- a/chromium/components/payments/content/secure_payment_confirmation_controller.h
+++ b/chromium/components/payments/content/secure_payment_confirmation_controller.h
@@ -40,7 +40,7 @@ class SecurePaymentConfirmationController
const autofill::CreditCard& credit_card,
base::WeakPtr<autofill::payments::FullCardRequest::ResultDelegate>
result_delegate,
- content::WebContents* web_contents) override;
+ content::RenderFrameHost* render_frame_host) override;
void ShowPaymentHandlerScreen(
const GURL& url,
PaymentHandlerOpenWindowCallback callback) override;
diff --git a/chromium/components/payments/content/secure_payment_confirmation_no_creds.cc b/chromium/components/payments/content/secure_payment_confirmation_no_creds.cc
index b2f584a5fa2..bcdfec48146 100644
--- a/chromium/components/payments/content/secure_payment_confirmation_no_creds.cc
+++ b/chromium/components/payments/content/secure_payment_confirmation_no_creds.cc
@@ -30,9 +30,9 @@ void SecurePaymentConfirmationNoCreds::ShowDialog(
content::WebContents* web_contents,
const std::u16string& merchant_name,
ResponseCallback response_callback) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
NOTREACHED();
-#endif // OS_ANDROID
+#endif // BUILDFLAG(IS_ANDROID)
DCHECK(!view_);
view_ = SecurePaymentConfirmationNoCredsView::Create();
diff --git a/chromium/components/payments/content/service_worker_payment_app.cc b/chromium/components/payments/content/service_worker_payment_app.cc
index 56c224a6c35..4e3f323fde6 100644
--- a/chromium/components/payments/content/service_worker_payment_app.cc
+++ b/chromium/components/payments/content/service_worker_payment_app.cc
@@ -12,6 +12,7 @@
#include "base/callback_helpers.h"
#include "base/containers/contains.h"
#include "base/feature_list.h"
+#include "base/metrics/histogram_functions.h"
#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
#include "components/payments/content/payment_event_response_util.h"
@@ -204,6 +205,8 @@ void ServiceWorkerPaymentApp::OnCanMakePaymentEventResponded(
// |can_make_payment| is true as long as there is a matching payment handler.
can_make_payment_result_ = true;
has_enrolled_instrument_result_ = response->can_make_payment;
+ base::UmaHistogramBoolean("PaymentRequest.EventResponse.CanMakePayment",
+ response->can_make_payment);
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(std::move(callback), this, can_make_payment_result_));
@@ -448,7 +451,7 @@ bool ServiceWorkerPaymentApp::IsValidForModifier(
return true;
if (!base::FeatureList::IsEnabled(::features::kPaymentRequestBasicCard))
- return true;
+ return false;
// Checking the capabilities of this app against the modifier.
// Return true if card networks are not specified in the modifier.
diff --git a/chromium/components/payments/content/service_worker_payment_app_finder_unittest.cc b/chromium/components/payments/content/service_worker_payment_app_finder_unittest.cc
index feb18459886..ee2d71a8816 100644
--- a/chromium/components/payments/content/service_worker_payment_app_finder_unittest.cc
+++ b/chromium/components/payments/content/service_worker_payment_app_finder_unittest.cc
@@ -4,6 +4,8 @@
#include "components/payments/content/service_worker_payment_app_finder.h"
+#include "base/test/scoped_feature_list.h"
+#include "content/public/common/content_features.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/mojom/payments/payment_request.mojom.h"
@@ -89,41 +91,6 @@ TEST_F(ServiceWorkerPaymentAppFinderTest,
}
TEST_F(ServiceWorkerPaymentAppFinderTest,
- RemoveAppsWithoutMatchingMethodData_NoNetworkCapabilities) {
- std::vector<mojom::PaymentMethodDataPtr> requested_methods;
- requested_methods.emplace_back(mojom::PaymentMethodData::New());
- requested_methods.back()->supported_method = "basic-card";
- requested_methods.back()->supported_networks = {
- mojom::BasicCardNetwork::AMEX};
- content::InstalledPaymentAppsFinder::PaymentApps apps;
- apps[0] = std::make_unique<content::StoredPaymentApp>();
- apps[0]->enabled_methods = {"basic-card"};
-
- RemoveAppsWithoutMatchingMethodData(requested_methods, &apps);
-
- EXPECT_TRUE(apps.empty());
-}
-
-TEST_F(ServiceWorkerPaymentAppFinderTest,
- RemoveAppsWithoutMatchingMethodData_NoMatchingNetworkCapabilities) {
- std::vector<mojom::PaymentMethodDataPtr> requested_methods;
- requested_methods.emplace_back(mojom::PaymentMethodData::New());
- requested_methods.back()->supported_method = "basic-card";
- requested_methods.back()->supported_networks = {
- mojom::BasicCardNetwork::AMEX};
- content::InstalledPaymentAppsFinder::PaymentApps apps;
- apps[0] = std::make_unique<content::StoredPaymentApp>();
- apps[0]->enabled_methods = {"basic-card"};
- apps[0]->capabilities.emplace_back();
- apps[0]->capabilities.back().supported_card_networks = {
- static_cast<int32_t>(mojom::BasicCardNetwork::VISA)};
-
- RemoveAppsWithoutMatchingMethodData(requested_methods, &apps);
-
- EXPECT_TRUE(apps.empty());
-}
-
-TEST_F(ServiceWorkerPaymentAppFinderTest,
RemoveAppsWithoutMatchingMethodData_NoRequestedNetwork) {
std::vector<mojom::PaymentMethodDataPtr> requested_methods;
requested_methods.emplace_back(mojom::PaymentMethodData::New());
@@ -195,4 +162,56 @@ TEST_F(ServiceWorkerPaymentAppFinderTest,
apps.find(0)->second->enabled_methods);
}
+class ServiceWorkerPaymentAppFinderBasicCardEnabledTest
+ : public ServiceWorkerPaymentAppFinderTest {
+ public:
+ ServiceWorkerPaymentAppFinderBasicCardEnabledTest(
+ const ServiceWorkerPaymentAppFinderBasicCardEnabledTest&) = delete;
+ ServiceWorkerPaymentAppFinderBasicCardEnabledTest& operator=(
+ const ServiceWorkerPaymentAppFinderBasicCardEnabledTest&) = delete;
+
+ protected:
+ ServiceWorkerPaymentAppFinderBasicCardEnabledTest() {
+ feature_list_.InitAndEnableFeature(::features::kPaymentRequestBasicCard);
+ }
+
+ private:
+ base::test::ScopedFeatureList feature_list_;
+};
+
+TEST_F(ServiceWorkerPaymentAppFinderBasicCardEnabledTest,
+ RemoveAppsWithoutMatchingMethodData_NoNetworkCapabilities) {
+ std::vector<mojom::PaymentMethodDataPtr> requested_methods;
+ requested_methods.emplace_back(mojom::PaymentMethodData::New());
+ requested_methods.back()->supported_method = "basic-card";
+ requested_methods.back()->supported_networks = {
+ mojom::BasicCardNetwork::AMEX};
+ content::InstalledPaymentAppsFinder::PaymentApps apps;
+ apps[0] = std::make_unique<content::StoredPaymentApp>();
+ apps[0]->enabled_methods = {"basic-card"};
+
+ RemoveAppsWithoutMatchingMethodData(requested_methods, &apps);
+
+ EXPECT_TRUE(apps.empty());
+}
+
+TEST_F(ServiceWorkerPaymentAppFinderBasicCardEnabledTest,
+ RemoveAppsWithoutMatchingMethodData_NoMatchingNetworkCapabilities) {
+ std::vector<mojom::PaymentMethodDataPtr> requested_methods;
+ requested_methods.emplace_back(mojom::PaymentMethodData::New());
+ requested_methods.back()->supported_method = "basic-card";
+ requested_methods.back()->supported_networks = {
+ mojom::BasicCardNetwork::AMEX};
+ content::InstalledPaymentAppsFinder::PaymentApps apps;
+ apps[0] = std::make_unique<content::StoredPaymentApp>();
+ apps[0]->enabled_methods = {"basic-card"};
+ apps[0]->capabilities.emplace_back();
+ apps[0]->capabilities.back().supported_card_networks = {
+ static_cast<int32_t>(mojom::BasicCardNetwork::VISA)};
+
+ RemoveAppsWithoutMatchingMethodData(requested_methods, &apps);
+
+ EXPECT_TRUE(apps.empty());
+}
+
} // namespace payments
diff --git a/chromium/components/payments/content/service_worker_payment_app_unittest.cc b/chromium/components/payments/content/service_worker_payment_app_unittest.cc
index 415d767909d..a4696c0c017 100644
--- a/chromium/components/payments/content/service_worker_payment_app_unittest.cc
+++ b/chromium/components/payments/content/service_worker_payment_app_unittest.cc
@@ -9,7 +9,9 @@
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_feature_list.h"
#include "content/public/browser/stored_payment_app.h"
+#include "content/public/common/content_features.h"
#include "content/public/test/browser_task_environment.h"
#include "content/public/test/test_browser_context.h"
#include "content/public/test/test_web_contents_factory.h"
@@ -233,8 +235,63 @@ TEST_F(ServiceWorkerPaymentAppTest, ValidateCanMakePayment) {
EXPECT_FALSE(GetApp()->HasEnrolledInstrument());
}
+class ServiceWorkerPaymentAppBasicCardDisabledTest
+ : public ServiceWorkerPaymentAppTest {
+ public:
+ ServiceWorkerPaymentAppBasicCardDisabledTest(
+ const ServiceWorkerPaymentAppBasicCardDisabledTest&) = delete;
+ ServiceWorkerPaymentAppBasicCardDisabledTest& operator=(
+ const ServiceWorkerPaymentAppBasicCardDisabledTest&) = delete;
+
+ protected:
+ ServiceWorkerPaymentAppBasicCardDisabledTest() {
+ feature_list_.InitAndDisableFeature(::features::kPaymentRequestBasicCard);
+ }
+
+ private:
+ base::test::ScopedFeatureList feature_list_;
+};
+
+// Test modifiers can be matched based on capabilities.
+TEST_F(ServiceWorkerPaymentAppBasicCardDisabledTest, IsValidForModifier) {
+ CreateServiceWorkerPaymentApp(true);
+
+ EXPECT_FALSE(GetApp()->IsValidForModifier(
+ /*method=*/"basic-card", /*supported_networks_specified=*/false,
+ /*supported_networks=*/{}));
+
+ EXPECT_TRUE(GetApp()->IsValidForModifier(
+ /*method=*/"https://bobpay.com", /*supported_networks_specified=*/true,
+ /*supported_networks=*/{}));
+
+ EXPECT_FALSE(GetApp()->IsValidForModifier(
+ /*method=*/"basic-card", /*supported_networks_specified=*/true,
+ /*supported_networks=*/{"mastercard"}));
+
+ EXPECT_FALSE(GetApp()->IsValidForModifier(
+ /*method=*/"basic-card", /*supported_networks_specified=*/true,
+ /*supported_networks=*/{"unionpay"}));
+}
+
+class ServiceWorkerPaymentAppBasicCardEnabledTest
+ : public ServiceWorkerPaymentAppTest {
+ public:
+ ServiceWorkerPaymentAppBasicCardEnabledTest(
+ const ServiceWorkerPaymentAppBasicCardEnabledTest&) = delete;
+ ServiceWorkerPaymentAppBasicCardEnabledTest& operator=(
+ const ServiceWorkerPaymentAppBasicCardEnabledTest&) = delete;
+
+ protected:
+ ServiceWorkerPaymentAppBasicCardEnabledTest() {
+ feature_list_.InitAndEnableFeature(::features::kPaymentRequestBasicCard);
+ }
+
+ private:
+ base::test::ScopedFeatureList feature_list_;
+};
+
// Test modifiers can be matched based on capabilities.
-TEST_F(ServiceWorkerPaymentAppTest, IsValidForModifier) {
+TEST_F(ServiceWorkerPaymentAppBasicCardEnabledTest, IsValidForModifier) {
CreateServiceWorkerPaymentApp(true);
EXPECT_TRUE(GetApp()->IsValidForModifier(
diff --git a/chromium/components/payments/content/utility/payment_manifest_parser.cc b/chromium/components/payments/content/utility/payment_manifest_parser.cc
index 16bd0f28761..e50db4cdd81 100644
--- a/chromium/components/payments/content/utility/payment_manifest_parser.cc
+++ b/chromium/components/payments/content/utility/payment_manifest_parser.cc
@@ -85,7 +85,7 @@ bool ParseDefaultApplications(const GURL& manifest_url,
base::StringPrintf("\"%s\" must be a list.", kDefaultApplications));
return false;
}
- base::Value::ConstListView list_view = list->GetList();
+ base::Value::ConstListView list_view = list->GetListDeprecated();
size_t apps_number = list_view.size();
if (apps_number > kMaximumNumberOfItems) {
@@ -139,7 +139,7 @@ bool ParseSupportedOrigins(base::DictionaryValue* dict,
kSupportedOrigins));
return false;
}
- base::Value::ConstListView list_view = list->GetList();
+ base::Value::ConstListView list_view = list->GetListDeprecated();
size_t supported_origins_number = list_view.size();
if (supported_origins_number > kMaximumNumberOfSupportedOrigins) {
@@ -193,7 +193,7 @@ void ParseIcons(const base::DictionaryValue& dict,
return;
}
- for (const auto& icon : icons_list->GetList()) {
+ for (const auto& icon : icons_list->GetListDeprecated()) {
if (!icon.is_dict()) {
log.Warn(base::StringPrintf(
"Each item in the list \"%s\" should be a dictionary.",
@@ -248,7 +248,7 @@ void ParsePreferredRelatedApplicationIdentifiers(
std::vector<std::string>* ids) {
DCHECK(ids);
- if (!dict.HasKey(kPreferRelatedApplications))
+ if (!dict.FindKey(kPreferRelatedApplications))
return;
absl::optional<bool> prefer_related_applications =
@@ -270,7 +270,7 @@ void ParsePreferredRelatedApplicationIdentifiers(
return;
}
- size_t size = related_applications->GetList().size();
+ size_t size = related_applications->GetListDeprecated().size();
if (size == 0) {
log.Warn(base::StringPrintf(
"Did not find any entries in \"%s\", even though \"%s\" is true.",
@@ -280,7 +280,7 @@ void ParsePreferredRelatedApplicationIdentifiers(
for (size_t i = 0; i < size; ++i) {
const base::Value& related_application_value =
- related_applications->GetList()[i];
+ related_applications->GetListDeprecated()[i];
if (!related_application_value.is_dict()) {
log.Warn(
base::StringPrintf("Element #%zu in \"%s\" should be a dictionary.",
@@ -290,9 +290,8 @@ void ParsePreferredRelatedApplicationIdentifiers(
const base::DictionaryValue& related_application =
base::Value::AsDictionaryValue(related_application_value);
- std::string platform;
- if (!related_application.GetString(kPlatform, &platform) ||
- platform != kPlay) {
+ const std::string* platform = related_application.FindStringKey(kPlatform);
+ if (!platform || *platform != kPlay) {
continue;
}
@@ -304,25 +303,36 @@ void ParsePreferredRelatedApplicationIdentifiers(
break;
}
- std::string id;
- if (!related_application.GetString(kId, &id)) {
+ const std::string* id = related_application.FindStringKey(kId);
+ if (!id) {
log.Warn(base::StringPrintf(
"Elements in \"%s\" with \"%s\":\"%s\" should have \"%s\" field.",
kRelatedApplications, kPlatform, kPlay, kId));
continue;
}
- if (id.empty() || !base::IsStringASCII(id)) {
+ if (id->empty() || !base::IsStringASCII(*id)) {
log.Warn(base::StringPrintf(
"\"%s\".\"%s\" should be a non-empty ASCII string.",
kRelatedApplications, kId));
continue;
}
- ids->emplace_back(id);
+ ids->emplace_back(*id);
}
}
+bool GetString(const base::Value* dict,
+ base::StringPiece key,
+ std::string& result) {
+ DCHECK(dict);
+ const std::string* value = dict->FindStringKey(key);
+ if (value) {
+ result = *value;
+ }
+ return value;
+}
+
} // namespace
PaymentManifestParser::WebAppIcon::WebAppIcon() = default;
@@ -385,13 +395,13 @@ void PaymentManifestParser::ParsePaymentMethodManifestIntoVectors(
return;
}
- if (dict->HasKey(kDefaultApplications) &&
+ if (dict->FindKey(kDefaultApplications) &&
!ParseDefaultApplications(manifest_url, dict.get(), web_app_manifest_urls,
log)) {
return;
}
- if (dict->HasKey(kSupportedOrigins) &&
+ if (dict->FindKey(kSupportedOrigins) &&
!ParseSupportedOrigins(dict.get(), supported_origins, log)) {
web_app_manifest_urls->clear();
}
@@ -416,7 +426,8 @@ bool PaymentManifestParser::ParseWebAppManifestIntoVector(
return false;
}
- for (const base::Value& related_application_value : list->GetList()) {
+ for (const base::Value& related_application_value :
+ list->GetListDeprecated()) {
if (!related_application_value.is_dict()) {
log.Error(base::StringPrintf("\"%s\" must be a list of dictionaries.",
kRelatedApplications));
@@ -427,9 +438,8 @@ bool PaymentManifestParser::ParseWebAppManifestIntoVector(
const base::DictionaryValue& related_application =
base::Value::AsDictionaryValue(related_application_value);
- std::string platform;
- if (!related_application.GetString(kPlatform, &platform) ||
- platform != kPlay) {
+ const std::string* platform = related_application.FindStringKey(kPlatform);
+ if (!platform || *platform != kPlay) {
continue;
}
@@ -441,9 +451,9 @@ bool PaymentManifestParser::ParseWebAppManifestIntoVector(
return false;
}
- if (!related_application.HasKey(kId) ||
- !related_application.HasKey(kMinVersion) ||
- !related_application.HasKey(kFingerprints)) {
+ if (!related_application.FindKey(kId) ||
+ !related_application.FindKey(kMinVersion) ||
+ !related_application.FindKey(kFingerprints)) {
log.Error(
base::StringPrintf("Each \"%s\": \"%s\" entry in \"%s\" must contain "
"\"%s\", \"%s\", and \"%s\".",
@@ -455,18 +465,21 @@ bool PaymentManifestParser::ParseWebAppManifestIntoVector(
WebAppManifestSection section;
section.min_version = 0;
- if (!related_application.GetString(kId, &section.id) ||
- section.id.empty() || !base::IsStringASCII(section.id)) {
+ const std::string* section_id = related_application.FindStringKey(kId);
+ if (!section_id || section_id->empty() ||
+ !base::IsStringASCII(*section_id)) {
log.Error(
base::StringPrintf("\"%s\" must be a non-empty ASCII string.", kId));
output->clear();
return false;
}
+ section.id = *section_id;
- std::string min_version;
- if (!related_application.GetString(kMinVersion, &min_version) ||
- min_version.empty() || !base::IsStringASCII(min_version) ||
- !base::StringToInt64(min_version, &section.min_version)) {
+ const std::string* min_version =
+ related_application.FindStringKey(kMinVersion);
+ if (!min_version || min_version->empty() ||
+ !base::IsStringASCII(*min_version) ||
+ !base::StringToInt64(*min_version, &section.min_version)) {
log.Error(base::StringPrintf(
"\"%s\" must be a string convertible into a number.", kMinVersion));
output->clear();
@@ -475,8 +488,8 @@ bool PaymentManifestParser::ParseWebAppManifestIntoVector(
const base::ListValue* fingerprints_list = nullptr;
if (!related_application.GetList(kFingerprints, &fingerprints_list) ||
- fingerprints_list->GetList().empty() ||
- fingerprints_list->GetList().size() > kMaximumNumberOfItems) {
+ fingerprints_list->GetListDeprecated().empty() ||
+ fingerprints_list->GetListDeprecated().size() > kMaximumNumberOfItems) {
log.Error(base::StringPrintf(
"\"%s\" must be a non-empty list of at most %zu items.",
kFingerprints, kMaximumNumberOfItems));
@@ -485,7 +498,7 @@ bool PaymentManifestParser::ParseWebAppManifestIntoVector(
}
for (const base::Value& fingerprint_dict_value :
- fingerprints_list->GetList()) {
+ fingerprints_list->GetListDeprecated()) {
const base::DictionaryValue* fingerprint_dict = nullptr;
if (fingerprint_dict_value.is_dict()) {
fingerprint_dict =
@@ -494,9 +507,9 @@ bool PaymentManifestParser::ParseWebAppManifestIntoVector(
std::string fingerprint_type;
std::string fingerprint_value;
if (!fingerprint_dict ||
- !fingerprint_dict->GetString("type", &fingerprint_type) ||
+ !GetString(fingerprint_dict, "type", fingerprint_type) ||
fingerprint_type != "sha256_cert" ||
- !fingerprint_dict->GetString("value", &fingerprint_value) ||
+ !GetString(fingerprint_dict, "value", fingerprint_value) ||
fingerprint_value.empty() ||
!base::IsStringASCII(fingerprint_value)) {
log.Error(base::StringPrintf(
@@ -548,18 +561,21 @@ bool PaymentManifestParser::ParseWebAppInstallationInfoIntoStructs(
return false;
}
- if (!service_worker_dict->GetString(kServiceWorkerSrc,
- &installation_info->sw_js_url) ||
- installation_info->sw_js_url.empty() ||
- !base::IsStringUTF8(installation_info->sw_js_url)) {
+ const std::string* sw_js_url =
+ service_worker_dict->FindStringKey(kServiceWorkerSrc);
+ if (!sw_js_url || sw_js_url->empty() || !base::IsStringUTF8(*sw_js_url)) {
log.Error(
base::StringPrintf("\"%s\".\"%s\" must be a non-empty UTF8 string.",
kServiceWorker, kServiceWorkerSrc));
return false;
}
+ installation_info->sw_js_url = *sw_js_url;
- service_worker_dict->GetString(kServiceWorkerScope,
- &installation_info->sw_scope);
+ const std::string* sw_scope =
+ service_worker_dict->FindStringKey(kServiceWorkerScope);
+ if (sw_scope) {
+ installation_info->sw_scope = *sw_scope;
+ }
absl::optional<bool> use_cache =
service_worker_dict->FindBoolKey(kServiceWorkerUseCache);
@@ -568,7 +584,10 @@ bool PaymentManifestParser::ParseWebAppInstallationInfoIntoStructs(
}
}
- dict->GetString(kWebAppName, &installation_info->name);
+ const std::string* name = dict->FindStringKey(kWebAppName);
+ if (name) {
+ installation_info->name = *name;
+ }
if (installation_info->name.empty()) {
log.Warn(
base::StringPrintf("No \"%s\" string in the manifest.", kWebAppName));
@@ -582,8 +601,8 @@ bool PaymentManifestParser::ParseWebAppInstallationInfoIntoStructs(
if (dict->GetDictionary(kPayment, &payment_dict)) {
const base::ListValue* delegation_list = nullptr;
if (payment_dict->GetList(kSupportedDelegations, &delegation_list)) {
- if (delegation_list->GetList().empty() ||
- delegation_list->GetList().size() >
+ if (delegation_list->GetListDeprecated().empty() ||
+ delegation_list->GetListDeprecated().size() >
kMaximumNumberOfSupportedDelegations) {
log.Error(base::StringPrintf(
"\"%s.%s\" must be a non-empty list of at most %zu entries.",
@@ -591,7 +610,7 @@ bool PaymentManifestParser::ParseWebAppInstallationInfoIntoStructs(
kMaximumNumberOfSupportedDelegations));
return false;
}
- for (const auto& delegation_item : delegation_list->GetList()) {
+ for (const auto& delegation_item : delegation_list->GetListDeprecated()) {
std::string delegation_name = delegation_item.GetString();
if (delegation_name == "shippingAddress") {
installation_info->supported_delegations.shipping_address = true;
@@ -620,7 +639,7 @@ bool PaymentManifestParser::ParseWebAppInstallationInfoIntoStructs(
kPayment, kSupportedDelegations));
return false;
}
- } else if (dict->HasKey(kPayment)) {
+ } else if (dict->FindKey(kPayment)) {
log.Error(
base::StringPrintf("\"%s\" member must be a dictionary", kPayment));
return false;
diff --git a/chromium/components/payments/core/error_strings.cc b/chromium/components/payments/core/error_strings.cc
index 8b531b2b4e2..aaccb971bd5 100644
--- a/chromium/components/payments/core/error_strings.cc
+++ b/chromium/components/payments/core/error_strings.cc
@@ -13,7 +13,7 @@ namespace errors {
const char kAnotherUiShowing[] = "Another PaymentRequest UI is already showing in a different tab or window.";
const char kAppStoreMethodOnlySupportedInTwa[] = "Payment method https://play.google.com/billing is only supported in Trusted Web Activity.";
const char kAttemptedInitializationTwice[] = "Attempted initialization twice.";
-const char kCannotShowInBackgroundTab[] = "Cannot show PaymentRequest UI in a background tab.";
+const char kCannotShowInBackgroundTab[] = "Cannot show PaymentRequest UI in a preview page or a background tab.";
const char kCannotShowTwice[] = "Attempted show twice.";
const char kCannotShowWithoutInit[] = "Attempted show without initialization.";
const char kCannotUpdateWithoutInit[] = "Attempted updateWith without initialization.";
diff --git a/chromium/components/payments/core/features.cc b/chromium/components/payments/core/features.cc
index fee41063d81..5945bed418d 100644
--- a/chromium/components/payments/core/features.cc
+++ b/chromium/components/payments/core/features.cc
@@ -13,7 +13,7 @@ namespace features {
const base::Feature kWebPaymentsExperimentalFeatures{
"WebPaymentsExperimentalFeatures", base::FEATURE_DISABLED_BY_DEFAULT};
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
const base::Feature kWebPaymentsNativeApps{"WebPaymentsNativeApps",
base::FEATURE_DISABLED_BY_DEFAULT};
#endif
@@ -39,11 +39,11 @@ const base::Feature kWebPaymentsRedactShippingAddress{
const base::Feature kAppStoreBilling {
"AppStoreBilling",
-#if defined(OS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH)
base::FEATURE_ENABLED_BY_DEFAULT
#else
base::FEATURE_DISABLED_BY_DEFAULT
-#endif // OS_ANDROID || BUILDFLAG(IS_CHROMEOS_ASH)
+#endif
};
const base::Feature kAppStoreBillingDebug{"AppStoreBillingDebug",
diff --git a/chromium/components/payments/core/features.h b/chromium/components/payments/core/features.h
index 4e33b94492c..1ccd6fe3a06 100644
--- a/chromium/components/payments/core/features.h
+++ b/chromium/components/payments/core/features.h
@@ -15,7 +15,7 @@ namespace features {
// release.
extern const base::Feature kWebPaymentsExperimentalFeatures;
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
// Used to control the support for iOS third party apps as payment methods.
extern const base::Feature kWebPaymentsNativeApps;
#endif
diff --git a/chromium/components/payments/core/payment_details.cc b/chromium/components/payments/core/payment_details.cc
index 625908c6c32..15a51e1f54b 100644
--- a/chromium/components/payments/core/payment_details.cc
+++ b/chromium/components/payments/core/payment_details.cc
@@ -6,6 +6,7 @@
#include <algorithm>
+#include "base/memory/values_equivalent.h"
#include "base/values.h"
namespace payments {
@@ -51,9 +52,7 @@ PaymentDetails& PaymentDetails::operator=(const PaymentDetails& other) {
}
bool PaymentDetails::operator==(const PaymentDetails& other) const {
- return id == other.id &&
- ((!total && !other.total) ||
- (total && other.total && *total == *other.total)) &&
+ return id == other.id && base::ValuesEquivalent(total, other.total) &&
display_items == other.display_items &&
shipping_options == other.shipping_options &&
modifiers == other.modifiers && error == other.error;
@@ -92,7 +91,8 @@ bool PaymentDetails::FromValue(const base::Value& value, bool requires_total) {
const base::Value* display_items_list =
value.FindListKey(kPaymentDetailsDisplayItems);
if (display_items_list) {
- for (const base::Value& payment_item_dict : display_items_list->GetList()) {
+ for (const base::Value& payment_item_dict :
+ display_items_list->GetListDeprecated()) {
PaymentItem payment_item;
if (!payment_item.FromValue(payment_item_dict)) {
return false;
@@ -105,7 +105,7 @@ bool PaymentDetails::FromValue(const base::Value& value, bool requires_total) {
value.FindListKey(kPaymentDetailsShippingOptions);
if (shipping_options_list) {
for (const base::Value& shipping_option_dict :
- shipping_options_list->GetList()) {
+ shipping_options_list->GetListDeprecated()) {
PaymentShippingOption shipping_option;
if (!shipping_option.FromValue(shipping_option_dict)) {
return false;
@@ -117,7 +117,8 @@ bool PaymentDetails::FromValue(const base::Value& value, bool requires_total) {
const base::Value* modifiers_list =
value.FindListKey(kPaymentDetailsModifiers);
if (modifiers_list) {
- for (const base::Value& modifier_dict : modifiers_list->GetList()) {
+ for (const base::Value& modifier_dict :
+ modifiers_list->GetListDeprecated()) {
PaymentDetailsModifier modifier;
if (!modifier.method_data.FromValue(modifier_dict)) {
return false;
@@ -133,7 +134,7 @@ bool PaymentDetails::FromValue(const base::Value& value, bool requires_total) {
modifier_dict.FindListKey(kPaymentDetailsAdditionalDisplayItems);
if (additional_display_items_list) {
for (const base::Value& additional_display_item_dict :
- additional_display_items_list->GetList()) {
+ additional_display_items_list->GetListDeprecated()) {
PaymentItem additional_display_item;
if (!additional_display_item.FromValue(
additional_display_item_dict)) {
diff --git a/chromium/components/payments/core/payment_details_modifier.cc b/chromium/components/payments/core/payment_details_modifier.cc
index 3d1105e3026..e7527a0616f 100644
--- a/chromium/components/payments/core/payment_details_modifier.cc
+++ b/chromium/components/payments/core/payment_details_modifier.cc
@@ -4,6 +4,7 @@
#include "components/payments/core/payment_details_modifier.h"
+#include "base/memory/values_equivalent.h"
#include "base/values.h"
namespace payments {
@@ -44,8 +45,7 @@ PaymentDetailsModifier& PaymentDetailsModifier::operator=(
bool PaymentDetailsModifier::operator==(
const PaymentDetailsModifier& other) const {
return method_data == other.method_data &&
- ((!total && !other.total) ||
- (total && other.total && *total == *other.total)) &&
+ base::ValuesEquivalent(total, other.total) &&
additional_display_items == other.additional_display_items;
}
diff --git a/chromium/components/payments/core/payment_details_unittest.cc b/chromium/components/payments/core/payment_details_unittest.cc
index 3cc11e6cbf3..3398c81dba3 100644
--- a/chromium/components/payments/core/payment_details_unittest.cc
+++ b/chromium/components/payments/core/payment_details_unittest.cc
@@ -128,13 +128,13 @@ TEST(PaymentRequestTest, PaymentDetailsFromValueFailure) {
payment_method.SetKey("total", std::move(invalid_total_dict));
details_dict.FindKey("modifiers")->Append(std::move(payment_method));
EXPECT_FALSE(actual.FromValue(details_dict, /*requires_total=*/false));
- details_dict.FindKey("modifiers")->GetList()[0].RemoveKey("total");
+ details_dict.FindKey("modifiers")->GetListDeprecated()[0].RemoveKey("total");
// Invalid additional_display_item in modifiers.
base::Value additional_display_items_list(base::Value::Type::LIST);
additional_display_items_list.Append("not a payment item");
details_dict.FindKey("modifiers")
- ->GetList()[0]
+ ->GetListDeprecated()[0]
.SetKey("additionalDisplayItems",
std::move(additional_display_items_list));
EXPECT_FALSE(actual.FromValue(details_dict, /*requires_total=*/false));
diff --git a/chromium/components/payments/core/payment_method_data.cc b/chromium/components/payments/core/payment_method_data.cc
index f19de2c3d7f..efb777f75ff 100644
--- a/chromium/components/payments/core/payment_method_data.cc
+++ b/chromium/components/payments/core/payment_method_data.cc
@@ -60,7 +60,7 @@ bool PaymentMethodData::FromValue(const base::Value& value) {
data_dict->FindListKey(kSupportedNetworks);
if (supported_networks_list) {
for (const base::Value& supported_network :
- supported_networks_list->GetList()) {
+ supported_networks_list->GetListDeprecated()) {
if (!supported_network.is_string() ||
!base::IsStringASCII(supported_network.GetString())) {
return false;
diff --git a/chromium/components/payments/core/payment_method_data_unittest.cc b/chromium/components/payments/core/payment_method_data_unittest.cc
index 9f8d18bcef5..399c532930c 100644
--- a/chromium/components/payments/core/payment_method_data_unittest.cc
+++ b/chromium/components/payments/core/payment_method_data_unittest.cc
@@ -74,7 +74,9 @@ TEST(PaymentMethodData, FromValueFailure) {
method_data_dict.SetKey("data", std::move(data_dict));
EXPECT_FALSE(actual.FromValue(method_data_dict));
- method_data_dict.FindKey("data")->FindKey("supportedNetworks")->GetList()[0] =
+ method_data_dict.FindKey("data")
+ ->FindKey("supportedNetworks")
+ ->GetListDeprecated()[0] =
base::Value("\xD0\xA2\xD0\xB5\xD1\x81\xD1\x82");
EXPECT_FALSE(actual.FromValue(method_data_dict));
}
diff --git a/chromium/components/payments/core/payment_request_data_util_unittest.cc b/chromium/components/payments/core/payment_request_data_util_unittest.cc
index fadad10aff8..d86240fc79b 100644
--- a/chromium/components/payments/core/payment_request_data_util_unittest.cc
+++ b/chromium/components/payments/core/payment_request_data_util_unittest.cc
@@ -133,12 +133,12 @@ INSTANTIATE_TEST_SUITE_P(
// A test fixture to check ParseSupportedMethods() correctly returns the card
// networks for the "basic-card" payment method.
typedef ::testing::TestWithParam<const char*> SupportedNetworksTest;
-#if defined(OS_IOS) && !TARGET_OS_SIMULATOR
+#if BUILDFLAG(IS_IOS) && !TARGET_OS_SIMULATOR
// TODO(crbug.com/1008023): Enable this test on iOS devices.
#define MAYBE_SupportedNetworks DISABLED_SupportedNetworks
#else
#define MAYBE_SupportedNetworks SupportedNetworks
-#endif // defined(OS_IOS) && !TARGET_OS_SIMULATOR
+#endif // BUILDFLAG(IS_IOS) && !TARGET_OS_SIMULATOR
TEST_P(SupportedNetworksTest, MAYBE_SupportedNetworks) {
PaymentMethodData method_data;
method_data.supported_method = kBasicCardMethodName;
diff --git a/chromium/components/pdf/browser/BUILD.gn b/chromium/components/pdf/browser/BUILD.gn
index 5a9998a5fd7..efb41083a23 100644
--- a/chromium/components/pdf/browser/BUILD.gn
+++ b/chromium/components/pdf/browser/BUILD.gn
@@ -17,7 +17,6 @@ static_library("browser") {
deps = [
"//base",
"//content/public/browser",
- "//pdf:features",
"//ui/base",
"//ui/touch_selection",
]
diff --git a/chromium/components/pdf/browser/mock_url_loader_client.h b/chromium/components/pdf/browser/mock_url_loader_client.h
index 554b1b4817e..6d2f8ad17de 100644
--- a/chromium/components/pdf/browser/mock_url_loader_client.h
+++ b/chromium/components/pdf/browser/mock_url_loader_client.h
@@ -25,7 +25,8 @@ class MockURLLoaderClient : public network::mojom::URLLoaderClient {
(override));
MOCK_METHOD(void,
OnReceiveResponse,
- (network::mojom::URLResponseHeadPtr head),
+ (network::mojom::URLResponseHeadPtr head,
+ mojo::ScopedDataPipeConsumerHandle body),
(override));
MOCK_METHOD(void,
OnReceiveRedirect,
diff --git a/chromium/components/pdf/browser/pdf_web_contents_helper.cc b/chromium/components/pdf/browser/pdf_web_contents_helper.cc
index 4c21f244032..26a4f75cb3d 100644
--- a/chromium/components/pdf/browser/pdf_web_contents_helper.cc
+++ b/chromium/components/pdf/browser/pdf_web_contents_helper.cc
@@ -6,15 +6,12 @@
#include <utility>
-#include "base/feature_list.h"
#include "base/memory/ptr_util.h"
#include "base/notreached.h"
#include "components/pdf/browser/pdf_web_contents_helper_client.h"
#include "content/public/browser/render_widget_host.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/common/referrer_type_converters.h"
-#include "pdf/pdf_features.h"
-#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
#include "ui/base/pointer/touch_editing_controller.h"
#include "ui/base/ui_base_types.h"
#include "ui/gfx/geometry/point_conversions.h"
@@ -54,6 +51,9 @@ PDFWebContentsHelper::PDFWebContentsHelper(
client_(std::move(client)) {}
PDFWebContentsHelper::~PDFWebContentsHelper() {
+ if (pdf_rwh_)
+ pdf_rwh_->RemoveObserver(this);
+
if (!touch_selection_controller_client_manager_)
return;
@@ -73,19 +73,27 @@ void PDFWebContentsHelper::SetListener(
mojo::PendingRemote<mojom::PdfListener> listener) {
remote_pdf_client_.reset();
remote_pdf_client_.Bind(std::move(listener));
+
+ if (pdf_rwh_)
+ pdf_rwh_->RemoveObserver(this);
+ pdf_rwh_ = client_->FindPdfFrame(&GetWebContents())->GetRenderWidgetHost();
+ pdf_rwh_->AddObserver(this);
}
gfx::PointF PDFWebContentsHelper::ConvertHelper(const gfx::PointF& point_f,
float scale) {
- gfx::PointF origin_f;
- content::RenderWidgetHostView* view =
- GetWebContents().GetRenderWidgetHostView();
- if (view) {
- origin_f = view->TransformPointToRootCoordSpaceF(gfx::PointF());
- origin_f.Scale(scale);
- }
+ if (!pdf_rwh_)
+ return point_f;
+
+ content::RenderWidgetHostView* view = pdf_rwh_->GetView();
+ if (!view)
+ return point_f;
+
+ gfx::Vector2dF offset =
+ view->TransformPointToRootCoordSpaceF(gfx::PointF()).OffsetFromOrigin();
+ offset.Scale(scale);
- return gfx::PointF(point_f.x() + origin_f.x(), point_f.y() + origin_f.y());
+ return point_f + offset;
}
gfx::PointF PDFWebContentsHelper::ConvertFromRoot(const gfx::PointF& point_f) {
@@ -112,21 +120,6 @@ void PDFWebContentsHelper::SetPluginCanSave(bool can_save) {
client_->SetPluginCanSave(&GetWebContents(), can_save);
}
-void PDFWebContentsHelper::GetPdfFindInPage(GetPdfFindInPageCallback callback) {
- if (!base::FeatureList::IsEnabled(chrome_pdf::features::kPdfUnseasoned)) {
- NOTREACHED();
- return;
- }
-
- if (!find_factory_remote_) {
- GetWebContents()
- .GetMainFrame()
- ->GetRemoteAssociatedInterfaces()
- ->GetInterface(&find_factory_remote_);
- }
- find_factory_remote_->GetPdfFindInPage(std::move(callback));
-}
-
void PDFWebContentsHelper::DidScroll() {
if (!touch_selection_controller_client_manager_)
InitTouchSelectionClientManager();
@@ -163,6 +156,12 @@ void PDFWebContentsHelper::DidScroll() {
}
}
+void PDFWebContentsHelper::RenderWidgetHostDestroyed(
+ content::RenderWidgetHost* widget_host) {
+ if (pdf_rwh_ == widget_host)
+ pdf_rwh_ = nullptr;
+}
+
bool PDFWebContentsHelper::SupportsAnimation() const {
return false;
}
diff --git a/chromium/components/pdf/browser/pdf_web_contents_helper.h b/chromium/components/pdf/browser/pdf_web_contents_helper.h
index 73e1c8e29fe..a799667a1ae 100644
--- a/chromium/components/pdf/browser/pdf_web_contents_helper.h
+++ b/chromium/components/pdf/browser/pdf_web_contents_helper.h
@@ -9,9 +9,9 @@
#include "base/memory/raw_ptr.h"
#include "content/public/browser/render_frame_host_receiver_set.h"
+#include "content/public/browser/render_widget_host_observer.h"
#include "content/public/browser/touch_selection_controller_client_manager.h"
#include "content/public/browser/web_contents_user_data.h"
-#include "mojo/public/cpp/bindings/associated_remote.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "pdf/mojom/pdf.mojom.h"
@@ -20,6 +20,7 @@
#include "ui/touch_selection/touch_selection_menu_runner.h"
namespace content {
+class RenderWidgetHost;
class WebContents;
}
@@ -31,6 +32,7 @@ class PDFWebContentsHelperTest;
// Per-WebContents class to handle PDF messages.
class PDFWebContentsHelper
: public content::WebContentsUserData<PDFWebContentsHelper>,
+ public content::RenderWidgetHostObserver,
public mojom::PdfService,
public ui::TouchSelectionControllerClient,
public ui::TouchSelectionMenuClient,
@@ -48,7 +50,11 @@ class PDFWebContentsHelper
mojo::PendingAssociatedReceiver<mojom::PdfService> pdf_service,
content::RenderFrameHost* rfh);
- // ui::TouchSelectionControllerClient :
+ // content::RenderWidgetHostObserver:
+ void RenderWidgetHostDestroyed(
+ content::RenderWidgetHost* widget_host) override;
+
+ // ui::TouchSelectionControllerClient:
bool SupportsAnimation() const override;
void SetNeedsAnimate() override {}
void MoveCaret(const gfx::PointF& position) override;
@@ -72,6 +78,18 @@ class PDFWebContentsHelper
void OnManagerWillDestroy(
content::TouchSelectionControllerClientManager* manager) override;
+ // pdf::mojom::PdfService:
+ void SetListener(mojo::PendingRemote<mojom::PdfListener> listener) override;
+ void HasUnsupportedFeature() override;
+ void SaveUrlAs(const GURL& url,
+ network::mojom::ReferrerPolicy policy) override;
+ void UpdateContentRestrictions(int32_t content_restrictions) override;
+ void SelectionChanged(const gfx::PointF& left,
+ int32_t left_height,
+ const gfx::PointF& right,
+ int32_t right_height) override;
+ void SetPluginCanSave(bool can_save) override;
+
private:
friend class content::WebContentsUserData<PDFWebContentsHelper>;
friend class PDFWebContentsHelperTest;
@@ -84,24 +102,16 @@ class PDFWebContentsHelper
gfx::PointF ConvertToRoot(const gfx::PointF& point_f);
gfx::PointF ConvertHelper(const gfx::PointF& point_f, float scale);
- // mojom::PdfService:
- void SetListener(mojo::PendingRemote<mojom::PdfListener> listener) override;
- void HasUnsupportedFeature() override;
- void SaveUrlAs(const GURL& url,
- network::mojom::ReferrerPolicy policy) override;
- void UpdateContentRestrictions(int32_t content_restrictions) override;
- void SelectionChanged(const gfx::PointF& left,
- int32_t left_height,
- const gfx::PointF& right,
- int32_t right_height) override;
- void SetPluginCanSave(bool can_save) override;
- void GetPdfFindInPage(GetPdfFindInPageCallback callback) override;
-
content::RenderFrameHostReceiverSet<mojom::PdfService> pdf_service_receivers_;
std::unique_ptr<PDFWebContentsHelperClient> const client_;
raw_ptr<content::TouchSelectionControllerClientManager>
touch_selection_controller_client_manager_ = nullptr;
+ // The `RenderWidgetHost` associated to the frame containing the PDF plugin.
+ // This should be null until the plugin is known to have been created; the
+ // signal comes from `SetListener()`.
+ raw_ptr<content::RenderWidgetHost> pdf_rwh_ = nullptr;
+
// Latest selection bounds received from PDFium.
gfx::PointF selection_left_;
int32_t selection_left_height_ = 0;
@@ -111,8 +121,6 @@ class PDFWebContentsHelper
mojo::Remote<mojom::PdfListener> remote_pdf_client_;
- mojo::AssociatedRemote<mojom::PdfFindInPageFactory> find_factory_remote_;
-
WEB_CONTENTS_USER_DATA_KEY_DECL();
};
diff --git a/chromium/components/pdf/browser/pdf_web_contents_helper_browsertest.cc b/chromium/components/pdf/browser/pdf_web_contents_helper_browsertest.cc
index ecb8fc5f222..02f603b6bfa 100644
--- a/chromium/components/pdf/browser/pdf_web_contents_helper_browsertest.cc
+++ b/chromium/components/pdf/browser/pdf_web_contents_helper_browsertest.cc
@@ -10,10 +10,35 @@
#include "content/public/test/browser_test.h"
#include "content/public/test/content_browser_test.h"
#include "content/shell/browser/shell.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "pdf/mojom/pdf.mojom.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/selection_bound.h"
namespace pdf {
+namespace {
+
+using ::testing::NiceMock;
+
+class FakePdfListener : public pdf::mojom::PdfListener {
+ public:
+ FakePdfListener() = default;
+ FakePdfListener(const FakePdfListener&) = delete;
+ FakePdfListener& operator=(const FakePdfListener&) = delete;
+ ~FakePdfListener() override = default;
+
+ MOCK_METHOD(void, SetCaretPosition, (const gfx::PointF&), (override));
+ MOCK_METHOD(void, MoveRangeSelectionExtent, (const gfx::PointF&), (override));
+ MOCK_METHOD(void,
+ SetSelectionBounds,
+ (const gfx::PointF&, const gfx::PointF&),
+ (override));
+};
+
+} // namespace
+
// A mock PDFWebContentsHelperClient.
class TestPDFWebContentsHelperClient : public PDFWebContentsHelperClient {
public:
@@ -26,6 +51,11 @@ class TestPDFWebContentsHelperClient : public PDFWebContentsHelperClient {
private:
// PDFWebContentsHelperClient:
+ content::RenderFrameHost* FindPdfFrame(
+ content::WebContents* contents) override {
+ return contents->GetMainFrame();
+ }
+
void UpdateContentRestrictions(content::WebContents* contents,
int content_restrictions) override {}
void OnPDFHasUnsupportedFeature(content::WebContents* contents) override {}
@@ -122,6 +152,20 @@ class PDFWebContentsHelperTest : public content::ContentBrowserTest {
touch_selection_controller_client_manager_;
};
+IN_PROC_BROWSER_TEST_F(PDFWebContentsHelperTest, SetListenerTwice) {
+ NiceMock<FakePdfListener> listener;
+
+ {
+ mojo::Receiver<pdf::mojom::PdfListener> receiver(&listener);
+ pdf_web_contents_helper()->SetListener(receiver.BindNewPipeAndPassRemote());
+ }
+
+ {
+ mojo::Receiver<pdf::mojom::PdfListener> receiver(&listener);
+ pdf_web_contents_helper()->SetListener(receiver.BindNewPipeAndPassRemote());
+ }
+}
+
// Tests that select-changed on a pdf text brings up selection handles and the
// quick menu in the reasonable position.
IN_PROC_BROWSER_TEST_F(PDFWebContentsHelperTest, SelectionChanged) {
diff --git a/chromium/components/pdf/browser/pdf_web_contents_helper_client.h b/chromium/components/pdf/browser/pdf_web_contents_helper_client.h
index fcf515e3c44..2af85f9ed40 100644
--- a/chromium/components/pdf/browser/pdf_web_contents_helper_client.h
+++ b/chromium/components/pdf/browser/pdf_web_contents_helper_client.h
@@ -6,6 +6,7 @@
#define COMPONENTS_PDF_BROWSER_PDF_WEB_CONTENTS_HELPER_CLIENT_H_
namespace content {
+class RenderFrameHost;
class WebContents;
}
@@ -13,7 +14,10 @@ namespace pdf {
class PDFWebContentsHelperClient {
public:
- virtual ~PDFWebContentsHelperClient() {}
+ virtual ~PDFWebContentsHelperClient() = default;
+
+ virtual content::RenderFrameHost* FindPdfFrame(
+ content::WebContents* contents) = 0;
virtual void UpdateContentRestrictions(content::WebContents* contents,
int content_restrictions) = 0;
diff --git a/chromium/components/pdf/browser/plugin_response_writer.cc b/chromium/components/pdf/browser/plugin_response_writer.cc
index 9ca8573fdd3..44ea938ad64 100644
--- a/chromium/components/pdf/browser/plugin_response_writer.cc
+++ b/chromium/components/pdf/browser/plugin_response_writer.cc
@@ -57,6 +57,11 @@ embed {
position: fixed;
top: 0;
}
+
+/* Hide scrollbars when in Presentation mode. */
+.fullscreen {
+ overflow: hidden;
+}
</style>
<div id="sizer"></div>
<embed type="application/x-google-chrome-pdf" src="$1" original-url="$2"
@@ -69,7 +74,7 @@ $3
// TODO(crbug.com/1252096): We should load the injected scripts as network
// resources instead. Until then, feel free to raise this limit as necessary.
if (stream_info.injected_script)
- DCHECK_LE(stream_info.injected_script->size(), 8'192u);
+ DCHECK_LE(stream_info.injected_script->size(), 16'384u);
return base::ReplaceStringPlaceholders(
kResponseTemplate,
@@ -95,7 +100,8 @@ void PluginResponseWriter::Start(base::OnceClosure done_callback) {
response->headers =
base::MakeRefCounted<net::HttpResponseHeaders>("HTTP/1.1 200 OK");
response->mime_type = "text/html";
- client_->OnReceiveResponse(std::move(response));
+ client_->OnReceiveResponse(std::move(response),
+ mojo::ScopedDataPipeConsumerHandle());
mojo::ScopedDataPipeProducerHandle producer;
mojo::ScopedDataPipeConsumerHandle consumer;
diff --git a/chromium/components/pdf/browser/plugin_response_writer_unittest.cc b/chromium/components/pdf/browser/plugin_response_writer_unittest.cc
index de2ad3c1594..19f59446d2b 100644
--- a/chromium/components/pdf/browser/plugin_response_writer_unittest.cc
+++ b/chromium/components/pdf/browser/plugin_response_writer_unittest.cc
@@ -139,7 +139,8 @@ TEST_F(PluginResponseWriterTest, Start) {
testing::InSequence in_sequence;
EXPECT_CALL(mock_client_, OnReceiveResponse)
- .WillOnce([](network::mojom::URLResponseHeadPtr head) {
+ .WillOnce([](network::mojom::URLResponseHeadPtr head,
+ mojo::ScopedDataPipeConsumerHandle body) {
EXPECT_EQ(200, head->headers->response_code());
EXPECT_EQ("text/html", head->mime_type);
});
diff --git a/chromium/components/pdf/renderer/BUILD.gn b/chromium/components/pdf/renderer/BUILD.gn
index b43840e4029..d61e395a8a9 100644
--- a/chromium/components/pdf/renderer/BUILD.gn
+++ b/chromium/components/pdf/renderer/BUILD.gn
@@ -14,7 +14,6 @@ static_library("renderer") {
"internal_plugin_renderer_helpers.h",
"pdf_accessibility_tree.h",
"pdf_ax_action_target.h",
- "pdf_find_in_page.h",
"pdf_internal_plugin_delegate.h",
"pepper_pdf_host.h",
]
@@ -23,7 +22,6 @@ static_library("renderer") {
"internal_plugin_renderer_helpers.cc",
"pdf_accessibility_tree.cc",
"pdf_ax_action_target.cc",
- "pdf_find_in_page.cc",
"pdf_internal_plugin_delegate.cc",
"pdf_view_web_plugin_client.cc",
"pdf_view_web_plugin_client.h",
@@ -48,7 +46,7 @@ static_library("renderer") {
"//ppapi/shared_impl",
"//printing/buildflags",
"//third_party/blink/public:blink",
- "//third_party/blink/public/strings:strings_grit",
+ "//third_party/blink/public/strings:accessibility_strings",
"//third_party/icu",
"//url",
"//v8",
diff --git a/chromium/components/pdf/renderer/internal_plugin_renderer_helpers.cc b/chromium/components/pdf/renderer/internal_plugin_renderer_helpers.cc
index 5ceed0ce692..3334ea4598c 100644
--- a/chromium/components/pdf/renderer/internal_plugin_renderer_helpers.cc
+++ b/chromium/components/pdf/renderer/internal_plugin_renderer_helpers.cc
@@ -8,9 +8,11 @@
#include <utility>
#include "base/check.h"
+#include "base/command_line.h"
#include "base/feature_list.h"
#include "components/pdf/renderer/pdf_internal_plugin_delegate.h"
#include "components/pdf/renderer/pdf_view_web_plugin_client.h"
+#include "content/public/common/content_switches.h"
#include "content/public/renderer/render_frame.h"
#include "mojo/public/cpp/bindings/associated_remote.h"
#include "pdf/mojom/pdf.mojom.h"
@@ -27,6 +29,12 @@
namespace pdf {
+bool IsPdfRenderer() {
+ static const bool has_switch =
+ base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kPdfRenderer);
+ return has_switch;
+}
+
blink::WebPlugin* CreateInternalPlugin(
const content::WebPluginInfo& info,
blink::WebPluginParams params,
@@ -56,6 +64,9 @@ blink::WebPlugin* CreateInternalPlugin(
return nullptr;
}
+ // Only create the in-process plugin within a PDF renderer.
+ CHECK(IsPdfRenderer());
+
// Origins allowed to embed the internal plugin are trusted (the PDF viewer
// and Print Preview), and should never directly create the in-process plugin.
// Likewise, they should not share a process with this frame.
diff --git a/chromium/components/pdf/renderer/internal_plugin_renderer_helpers.h b/chromium/components/pdf/renderer/internal_plugin_renderer_helpers.h
index 4ee7df5fb0b..64a48acb15f 100644
--- a/chromium/components/pdf/renderer/internal_plugin_renderer_helpers.h
+++ b/chromium/components/pdf/renderer/internal_plugin_renderer_helpers.h
@@ -21,6 +21,9 @@ namespace pdf {
class PdfInternalPluginDelegate;
+// Returns `true` if the current process is a PDF renderer.
+bool IsPdfRenderer();
+
// Tries to create an instance of the internal PDF plugin, returning `nullptr`
// if the plugin cannot be created. This function handles both the Pepper and
// Pepper-free implementations, delegating to `content::RenderFrame` when
diff --git a/chromium/components/pdf/renderer/pdf_accessibility_tree.cc b/chromium/components/pdf/renderer/pdf_accessibility_tree.cc
index d23fcd2c16e..da26cbc0350 100644
--- a/chromium/components/pdf/renderer/pdf_accessibility_tree.cc
+++ b/chromium/components/pdf/renderer/pdf_accessibility_tree.cc
@@ -9,6 +9,7 @@
#include "base/i18n/break_iterator.h"
#include "base/memory/ptr_util.h"
+#include "base/metrics/histogram_functions.h"
#include "base/notreached.h"
#include "base/strings/utf_string_conversion_utils.h"
#include "components/pdf/renderer/pdf_ax_action_target.h"
@@ -20,7 +21,7 @@
#include "pdf/accessibility_structs.h"
#include "pdf/pdf_accessibility_action_handler.h"
#include "pdf/pdf_features.h"
-#include "third_party/blink/public/strings/grit/blink_strings.h"
+#include "third_party/blink/public/strings/grit/blink_accessibility_strings.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/null_ax_action_target.h"
#include "ui/base/l10n/l10n_util.h"
@@ -1384,6 +1385,8 @@ void PdfAccessibilityTree::SetAccessibilityPageInfo(
AddPageContent(page_node, page_bounds, page_index, text_runs, chars,
page_objects);
+ did_get_a_text_run_ |= !text_runs.empty();
+
if (page_index == page_count_ - 1)
Finish();
}
@@ -1423,6 +1426,9 @@ void PdfAccessibilityTree::Finish() {
GetRenderAccessibilityIfEnabled();
if (render_accessibility)
render_accessibility->SetPluginTreeSource(this);
+
+ base::UmaHistogramBoolean("Accessibility.PDF.HasAccessibleText",
+ did_get_a_text_run_);
}
void PdfAccessibilityTree::UpdateAXTreeDataFromSelection() {
diff --git a/chromium/components/pdf/renderer/pdf_accessibility_tree.h b/chromium/components/pdf/renderer/pdf_accessibility_tree.h
index 2747de14f12..18a5e81578a 100644
--- a/chromium/components/pdf/renderer/pdf_accessibility_tree.h
+++ b/chromium/components/pdf/renderer/pdf_accessibility_tree.h
@@ -198,6 +198,8 @@ class PdfAccessibilityTree : public content::PluginAXTreeSource,
// outdated calls of SetAccessibilityPageInfo().
uint32_t next_page_index_ = 0;
+ bool did_get_a_text_run_ = false;
+
base::WeakPtrFactory<PdfAccessibilityTree> weak_ptr_factory_{this};
};
diff --git a/chromium/components/pdf/renderer/pdf_accessibility_tree_browsertest.cc b/chromium/components/pdf/renderer/pdf_accessibility_tree_browsertest.cc
index 9f54431a682..51d8a99c142 100644
--- a/chromium/components/pdf/renderer/pdf_accessibility_tree_browsertest.cc
+++ b/chromium/components/pdf/renderer/pdf_accessibility_tree_browsertest.cc
@@ -15,7 +15,7 @@
#include "pdf/accessibility_structs.h"
#include "pdf/pdf_accessibility_action_handler.h"
#include "pdf/pdf_features.h"
-#include "third_party/blink/public/strings/grit/blink_strings.h"
+#include "third_party/blink/public/strings/grit/blink_accessibility_strings.h"
#include "third_party/blink/public/web/web_local_frame.h"
#include "third_party/blink/public/web/web_settings.h"
#include "third_party/blink/public/web/web_view.h"
diff --git a/chromium/components/pdf/renderer/pdf_find_in_page.cc b/chromium/components/pdf/renderer/pdf_find_in_page.cc
deleted file mode 100644
index 174e75cad36..00000000000
--- a/chromium/components/pdf/renderer/pdf_find_in_page.cc
+++ /dev/null
@@ -1,106 +0,0 @@
-// Copyright 2021 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.
-
-#include "components/pdf/renderer/pdf_find_in_page.h"
-
-#include <memory>
-#include <utility>
-
-#include "base/check.h"
-#include "base/feature_list.h"
-#include "content/public/renderer/render_frame.h"
-#include "content/public/renderer/render_frame_observer.h"
-#include "mojo/public/cpp/bindings/pending_receiver.h"
-#include "mojo/public/cpp/bindings/receiver.h"
-#include "pdf/pdf_features.h"
-#include "third_party/blink/public/platform/web_vector.h"
-#include "third_party/blink/public/web/web_document.h"
-#include "third_party/blink/public/web/web_element.h"
-#include "third_party/blink/public/web/web_local_frame.h"
-#include "third_party/blink/public/web/web_node.h"
-
-namespace {
-
-blink::WebElement FindPdfViewerScroller(const blink::WebLocalFrame* frame) {
- blink::WebElement viewer = frame->GetDocument().GetElementById("viewer");
- if (viewer.IsNull())
- return blink::WebElement();
-
- blink::WebNode shadow_root = viewer.ShadowRoot();
- if (shadow_root.IsNull())
- return blink::WebElement();
-
- blink::WebElement plugin = shadow_root.QuerySelector("#plugin");
- if (plugin.IsNull() || !plugin.HasAttribute("pdf-viewer-update-enabled"))
- return blink::WebElement();
-
- return shadow_root.QuerySelector("#scroller");
-}
-
-} // namespace
-
-namespace pdf {
-
-// static
-void PdfFindInPageFactory::BindReceiver(
- int32_t routing_id,
- mojo::PendingAssociatedReceiver<pdf::mojom::PdfFindInPageFactory>
- receiver) {
- DCHECK(base::FeatureList::IsEnabled(chrome_pdf::features::kPdfUnseasoned));
-
- auto* render_frame = content::RenderFrame::FromRoutingID(routing_id);
- if (!render_frame)
- return;
-
- // PdfFindInPageFactory is self deleting.
- new PdfFindInPageFactory(render_frame, std::move(receiver));
-}
-
-void PdfFindInPageFactory::OnDestruct() {
- delete this;
-}
-
-void PdfFindInPageFactory::GetPdfFindInPage(GetPdfFindInPageCallback callback) {
- mojo::PendingReceiver<pdf::mojom::PdfFindInPage> pending_receiver;
- auto pending_remote = pending_receiver.InitWithNewPipeAndPassRemote();
- find_in_page_ = std::make_unique<FindInPageImpl>(render_frame(),
- std::move(pending_receiver));
- std::move(callback).Run(std::move(pending_remote));
-}
-
-PdfFindInPageFactory::PdfFindInPageFactory(
- content::RenderFrame* render_frame,
- mojo::PendingAssociatedReceiver<pdf::mojom::PdfFindInPageFactory> receiver)
- : content::RenderFrameObserver(render_frame),
- receiver_(this, std::move(receiver)) {}
-
-PdfFindInPageFactory::~PdfFindInPageFactory() = default;
-
-class PdfFindInPageFactory::FindInPageImpl : public pdf::mojom::PdfFindInPage {
- public:
- FindInPageImpl(
- content::RenderFrame* render_frame,
- mojo::PendingReceiver<pdf::mojom::PdfFindInPage> pending_receiver)
- : render_frame_(render_frame),
- receiver_(this, std::move(pending_receiver)) {}
-
- FindInPageImpl(const FindInPageImpl&) = delete;
- FindInPageImpl& operator=(const FindInPageImpl&) = delete;
-
- ~FindInPageImpl() override = default;
-
- // pdf::mojom::PdfFindInPage:
- void SetTickmarks(const std::vector<gfx::Rect>& tickmarks) override {
- blink::WebVector<gfx::Rect> tickmarks_converted(tickmarks);
- blink::WebLocalFrame* frame = render_frame_->GetWebFrame();
- blink::WebElement target = FindPdfViewerScroller(frame);
- frame->SetTickmarks(target, tickmarks_converted);
- }
-
- private:
- content::RenderFrame* const render_frame_;
- mojo::Receiver<pdf::mojom::PdfFindInPage> receiver_;
-};
-
-} // namespace pdf
diff --git a/chromium/components/pdf/renderer/pdf_find_in_page.h b/chromium/components/pdf/renderer/pdf_find_in_page.h
deleted file mode 100644
index 12fb253dbe9..00000000000
--- a/chromium/components/pdf/renderer/pdf_find_in_page.h
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright 2021 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.
-
-#ifndef COMPONENTS_PDF_RENDERER_PDF_FIND_IN_PAGE_H_
-#define COMPONENTS_PDF_RENDERER_PDF_FIND_IN_PAGE_H_
-
-#include <stdint.h>
-
-#include <memory>
-
-#include "content/public/renderer/render_frame_observer.h"
-#include "mojo/public/cpp/bindings/associated_receiver.h"
-#include "mojo/public/cpp/bindings/pending_associated_receiver.h"
-#include "pdf/mojom/pdf.mojom.h"
-
-namespace content {
-class RenderFrame;
-}
-
-namespace pdf {
-
-// Facilitates find-in-page IPCs from PDF renderer to PDF extension.
-// Has the same lifetime as the RenderFrame it is associated with.
-class PdfFindInPageFactory : public content::RenderFrameObserver,
- public pdf::mojom::PdfFindInPageFactory {
- public:
- static void BindReceiver(
- int32_t routing_id,
- mojo::PendingAssociatedReceiver<pdf::mojom::PdfFindInPageFactory>
- receiver);
-
- PdfFindInPageFactory(const PdfFindInPageFactory&) = delete;
- PdfFindInPageFactory& operator=(const PdfFindInPageFactory&) = delete;
-
- // content::RenderFrameObserver:
- void OnDestruct() override;
-
- // pdf::mojom::PdfFindInPageFactory:
- void GetPdfFindInPage(GetPdfFindInPageCallback callback) override;
-
- private:
- class FindInPageImpl;
-
- // Self deleting.
- PdfFindInPageFactory(
- content::RenderFrame* render_frame,
- mojo::PendingAssociatedReceiver<pdf::mojom::PdfFindInPageFactory>
- receiver);
- ~PdfFindInPageFactory() override;
-
- std::unique_ptr<FindInPageImpl> find_in_page_;
- mojo::AssociatedReceiver<pdf::mojom::PdfFindInPageFactory> receiver_;
-};
-
-} // namespace pdf
-
-#endif // COMPONENTS_PDF_RENDERER_PDF_FIND_IN_PAGE_H_
diff --git a/chromium/components/performance_manager/decorators/page_load_tracker_decorator.cc b/chromium/components/performance_manager/decorators/page_load_tracker_decorator.cc
index c077b21a51b..1d297ce131f 100644
--- a/chromium/components/performance_manager/decorators/page_load_tracker_decorator.cc
+++ b/chromium/components/performance_manager/decorators/page_load_tracker_decorator.cc
@@ -229,7 +229,7 @@ void PageLoadTrackerDecorator::UpdateLoadIdleStatePage(
LoadIdleState::kWaitingForNavigationTimedOut);
}
- FALLTHROUGH;
+ [[fallthrough]];
}
case LoadIdleState::kWaitingForNavigationTimedOut: {
@@ -268,7 +268,7 @@ void PageLoadTrackerDecorator::UpdateLoadIdleStatePage(
data->loading_stopped_ = now;
// Let the kLoadedNotIdling state transition evaluate, allowing an
// immediate transition to kLoadedAndIdling if the page is already idling.
- FALLTHROUGH;
+ [[fallthrough]];
}
case LoadIdleState::kLoadedNotIdling: {
@@ -282,7 +282,7 @@ void PageLoadTrackerDecorator::UpdateLoadIdleStatePage(
data->SetLoadIdleState(page_node, LoadIdleState::kLoadedAndIdling);
data->idling_started_ = now;
- FALLTHROUGH;
+ [[fallthrough]];
}
case LoadIdleState::kLoadedAndIdling: {
diff --git a/chromium/components/performance_manager/decorators/process_metrics_decorator.cc b/chromium/components/performance_manager/decorators/process_metrics_decorator.cc
index 7b7a527a238..d86ab1e27c6 100644
--- a/chromium/components/performance_manager/decorators/process_metrics_decorator.cc
+++ b/chromium/components/performance_manager/decorators/process_metrics_decorator.cc
@@ -24,7 +24,7 @@ namespace {
// The default process metrics refresh interval.
constexpr base::TimeDelta kDefaultRefreshTimerPeriod = base::Minutes(2);
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
// The fast process metrics refresh interval. Used in certain situations, see
// the comment in ProcessMetricsDecorator::StartTimer for more details.
constexpr base::TimeDelta kFastRefreshTimerPeriod = base::Seconds(20);
@@ -107,7 +107,7 @@ void ProcessMetricsDecorator::StartTimer() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
base::TimeDelta refresh_period = kDefaultRefreshTimerPeriod;
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
// Bump the refresh frequency when urgent discarding is done from the graph or
// when discarding tabs on high PMF as these features relies on relatively
// fresh data.
diff --git a/chromium/components/performance_manager/features.cc b/chromium/components/performance_manager/features.cc
index 981670d916e..193c27e851b 100644
--- a/chromium/components/performance_manager/features.cc
+++ b/chromium/components/performance_manager/features.cc
@@ -11,18 +11,17 @@
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
-namespace performance_manager {
-namespace features {
+namespace performance_manager::features {
const base::Feature kRunOnMainThread{"RunOnMainThread",
base::FEATURE_DISABLED_BY_DEFAULT};
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
const base::Feature kUrgentDiscardingFromPerformanceManager {
"UrgentDiscardingFromPerformanceManager",
// Ash Chrome uses memory pressure evaluator instead of performance manager to
// discard tabs.
-#if BUILDFLAG(IS_CHROMEOS_ASH) || defined(OS_LINUX)
+#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_LINUX)
base::FEATURE_DISABLED_BY_DEFAULT
#else
base::FEATURE_ENABLED_BY_DEFAULT
@@ -55,23 +54,4 @@ const base::Feature kHighPMFDiscardPolicy{"HighPMFDiscardPolicy",
const base::Feature kBFCachePerformanceManagerPolicy{
"BFCachePerformanceManagerPolicy", base::FEATURE_DISABLED_BY_DEFAULT};
-constexpr base::FeatureParam<bool>
- BFCachePerformanceManagerPolicyParams::kFlushOnModeratePressure;
-
-constexpr base::FeatureParam<int>
- BFCachePerformanceManagerPolicyParams::kDelayToFlushBackgroundTabInSeconds;
-
-// static
-BFCachePerformanceManagerPolicyParams
-BFCachePerformanceManagerPolicyParams::GetParams() {
- BFCachePerformanceManagerPolicyParams params;
- params.flush_on_moderate_pressure_ =
- BFCachePerformanceManagerPolicyParams::kFlushOnModeratePressure.Get();
- params.delay_to_flush_background_tab_ = base::Seconds(
- BFCachePerformanceManagerPolicyParams::kDelayToFlushBackgroundTabInSeconds
- .Get());
- return params;
-}
-
-} // namespace features
-} // namespace performance_manager
+} // namespace performance_manager::features
diff --git a/chromium/components/performance_manager/graph/graph_impl_unittest.cc b/chromium/components/performance_manager/graph/graph_impl_unittest.cc
index 75f98ddc0f7..80caab73b4a 100644
--- a/chromium/components/performance_manager/graph/graph_impl_unittest.cc
+++ b/chromium/components/performance_manager/graph/graph_impl_unittest.cc
@@ -252,7 +252,7 @@ void AssertDictValueContainsListKey(const base::Value& descr,
const base::Value* v = descr.FindListKey(key);
ASSERT_NE(nullptr, v);
- const auto list = v->GetList();
+ const auto list = v->GetListDeprecated();
ASSERT_EQ(2u, list.size());
ASSERT_EQ(list[0], base::Value(s1));
ASSERT_EQ(list[1], base::Value(s2));
diff --git a/chromium/components/performance_manager/graph/policies/bfcache_policy.cc b/chromium/components/performance_manager/graph/policies/bfcache_policy.cc
index 0428b49a7bb..7181680a502 100644
--- a/chromium/components/performance_manager/graph/policies/bfcache_policy.cc
+++ b/chromium/components/performance_manager/graph/policies/bfcache_policy.cc
@@ -6,6 +6,7 @@
#include "base/bind.h"
#include "base/memory/memory_pressure_listener.h"
+#include "base/notreached.h"
#include "base/task/task_traits.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
@@ -18,11 +19,50 @@
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/web_contents.h"
-namespace performance_manager {
-namespace policies {
+namespace performance_manager::policies {
namespace {
+// The foregrounded tab's cache limit on moderate memory pressure. The negative
+// value means no limit.
+int ForegroundCacheSizeOnModeratePressure() {
+ static constexpr base::FeatureParam<int>
+ foreground_cache_size_on_moderate_pressure{
+ &features::kBFCachePerformanceManagerPolicy,
+ "foreground_cache_size_on_moderate_pressure", 3};
+ return foreground_cache_size_on_moderate_pressure.Get();
+}
+
+// The backgrounded tab's cache limit on moderate memory pressure. The negative
+// value means no limit.
+int BackgroundCacheSizeOnModeratePressure() {
+ static constexpr base::FeatureParam<int>
+ background_cache_size_on_moderate_pressure{
+ &features::kBFCachePerformanceManagerPolicy,
+ "background_cache_size_on_moderate_pressure", 1};
+ return background_cache_size_on_moderate_pressure.Get();
+}
+
+// The foregrounded tab's cache limit on critical memory pressure. The negative
+// value means no limit.
+int ForegroundCacheSizeOnCriticalPressure() {
+ static constexpr base::FeatureParam<int>
+ foreground_cache_size_on_critical_pressure{
+ &features::kBFCachePerformanceManagerPolicy,
+ "foreground_cache_size_on_critical_pressure", 0};
+ return foreground_cache_size_on_critical_pressure.Get();
+}
+
+// The backgrounded tab's cache limit on critical memory pressure. The negative
+// value means no limit.
+int BackgroundCacheSizeOnCriticalPressure() {
+ static constexpr base::FeatureParam<int>
+ background_cache_size_on_critical_pressure{
+ &features::kBFCachePerformanceManagerPolicy,
+ "background_cache_size_on_critical_pressure", 0};
+ return background_cache_size_on_critical_pressure.Get();
+}
+
bool PageMightHaveFramesInBFCache(const PageNode* page_node) {
// TODO(crbug.com/1211368): Use PageState when that actually works.
auto main_frame_nodes = page_node->GetMainFrameNodes();
@@ -35,124 +75,78 @@ bool PageMightHaveFramesInBFCache(const PageNode* page_node) {
return false;
}
-void MaybeFlushBFCacheOnUIThread(const WebContentsProxy& contents_proxy) {
+using MemoryPressureLevel = base::MemoryPressureListener::MemoryPressureLevel;
+
+void MaybeFlushBFCacheOnUIThread(const WebContentsProxy& contents_proxy,
+ MemoryPressureLevel memory_pressure_level) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
content::WebContents* const content = contents_proxy.Get();
if (!content)
return;
+ int cache_size = -1;
+ bool foregrounded =
+ (content->GetVisibility() == content::Visibility::VISIBLE);
+ switch (memory_pressure_level) {
+ case MemoryPressureLevel::MEMORY_PRESSURE_LEVEL_MODERATE:
+ cache_size = foregrounded ? ForegroundCacheSizeOnModeratePressure()
+ : BackgroundCacheSizeOnModeratePressure();
+ break;
+ case MemoryPressureLevel::MEMORY_PRESSURE_LEVEL_CRITICAL:
+ cache_size = foregrounded ? ForegroundCacheSizeOnCriticalPressure()
+ : BackgroundCacheSizeOnCriticalPressure();
+ break;
+ default:
+ NOTREACHED();
+ }
+ // Do not flush BFCache if cache_size is negative (such as -1).
+ if (cache_size < 0)
+ return;
+
// Do not flush the BFCache if there's a pending navigation as this could stop
// it.
// TODO(sebmarchand): Check if this is really needed.
auto& navigation_controller = content->GetController();
if (!navigation_controller.GetPendingEntry())
- navigation_controller.GetBackForwardCache().Flush();
+ navigation_controller.GetBackForwardCache().Prune(cache_size);
}
} // namespace
-BFCachePolicy::BFCachePolicy()
- : flush_on_moderate_pressure_{features::
- BFCachePerformanceManagerPolicyParams::
- GetParams()
- .flush_on_moderate_pressure()},
- delay_to_flush_background_tab_{
- features::BFCachePerformanceManagerPolicyParams::GetParams()
- .delay_to_flush_background_tab()} {}
-
-BFCachePolicy::~BFCachePolicy() = default;
-
-void BFCachePolicy::MaybeFlushBFCache(const PageNode* page_node) {
+void BFCachePolicy::MaybeFlushBFCache(
+ const PageNode* page_node,
+ MemoryPressureLevel memory_pressure_level) {
DCHECK(page_node);
content::GetUIThreadTaskRunner({})->PostTask(
- FROM_HERE, base::BindOnce(&MaybeFlushBFCacheOnUIThread,
- page_node->GetContentsProxy()));
-}
-
-void BFCachePolicy::MaybeFlushBFCacheLater(const PageNode* page_node) {
- // If |MaybeFlushBFCacheLater| is called while waiting for the timer,
- // |MaybeFlushBFCacheLater| will reset the timer.
- // The use of base::Unretained(this) is safe here because |this| owns the
- // timer.
- page_to_flush_timer_[page_node].Start(
- FROM_HERE, delay_to_flush_background_tab_,
- base::BindOnce(&BFCachePolicy::MaybeFlushBFCache, base::Unretained(this),
- page_node));
+ FROM_HERE,
+ base::BindOnce(&MaybeFlushBFCacheOnUIThread,
+ page_node->GetContentsProxy(), memory_pressure_level));
}
void BFCachePolicy::OnPassedToGraph(Graph* graph) {
DCHECK(graph->HasOnlySystemNode());
graph_ = graph;
- graph_->AddPageNodeObserver(this);
graph_->AddSystemNodeObserver(this);
}
void BFCachePolicy::OnTakenFromGraph(Graph* graph) {
- graph_->RemovePageNodeObserver(this);
graph_->RemoveSystemNodeObserver(this);
graph_ = nullptr;
}
-void BFCachePolicy::OnIsVisibleChanged(const PageNode* page_node) {
- if (delay_to_flush_background_tab_.InSeconds() < 0)
- return;
-
- // Try to flush the BFCache of pages when they become non-visible. This could
- // fail if the page still has a pending navigation.
- if (page_node->GetPageState() == PageState::kActive &&
- !page_node->IsVisible() && PageMightHaveFramesInBFCache(page_node)) {
- MaybeFlushBFCacheLater(page_node);
- } else if (page_node->IsVisible()) {
- // Remove the timer associated with |page_node| if one exists.
- page_to_flush_timer_.erase(page_node);
- }
-}
-
-void BFCachePolicy::OnLoadingStateChanged(
- const PageNode* page_node,
- PageNode::LoadingState previous_state) {
- if (delay_to_flush_background_tab_.InSeconds() < 0)
- return;
-
- // Flush the BFCache of pages that finish a navigation while in background.
- // TODO(sebmarchand): Check if this is really needed.
- if (!page_node->IsVisible() &&
- page_node->GetLoadingState() >= PageNode::LoadingState::kLoadedBusy &&
- PageMightHaveFramesInBFCache(page_node)) {
- MaybeFlushBFCacheLater(page_node);
- } else if (page_node->IsVisible()) {
- // Remove the timer associated with |page_node| if one exists.
- page_to_flush_timer_.erase(page_node);
- }
-}
-
-void BFCachePolicy::OnBeforePageNodeRemoved(const PageNode* page_node) {
- // Remove the timer associated with |page_node| if one exists.
- page_to_flush_timer_.erase(page_node);
-}
-
-void BFCachePolicy::OnMemoryPressure(
- base::MemoryPressureListener::MemoryPressureLevel new_level) {
+void BFCachePolicy::OnMemoryPressure(MemoryPressureLevel new_level) {
// This shouldn't happen but add the check anyway in case the API changes.
- if (new_level == base::MemoryPressureListener::MemoryPressureLevel::
- MEMORY_PRESSURE_LEVEL_NONE) {
- return;
- }
-
- if (new_level == base::MemoryPressureListener::MemoryPressureLevel::
- MEMORY_PRESSURE_LEVEL_MODERATE &&
- !flush_on_moderate_pressure_) {
+ if (new_level == MemoryPressureLevel::MEMORY_PRESSURE_LEVEL_NONE) {
return;
}
- // Flush the cache of all pages.
+ // Apply the cache limit to all pages.
for (auto* page_node : graph_->GetAllPageNodes()) {
- if (page_node->GetPageState() == PageState::kActive &&
+ if (page_node->GetPageState() == PageNode::PageState::kActive &&
PageMightHaveFramesInBFCache(page_node)) {
- MaybeFlushBFCache(page_node);
+ MaybeFlushBFCache(page_node, new_level);
}
}
}
-} // namespace policies
-} // namespace performance_manager
+} // namespace performance_manager::policies
diff --git a/chromium/components/performance_manager/graph/policies/bfcache_policy.h b/chromium/components/performance_manager/graph/policies/bfcache_policy.h
index c214693bb00..a731ebbc2f2 100644
--- a/chromium/components/performance_manager/graph/policies/bfcache_policy.h
+++ b/chromium/components/performance_manager/graph/policies/bfcache_policy.h
@@ -5,66 +5,45 @@
#ifndef COMPONENTS_PERFORMANCE_MANAGER_GRAPH_POLICIES_BFCACHE_POLICY_H_
#define COMPONENTS_PERFORMANCE_MANAGER_GRAPH_POLICIES_BFCACHE_POLICY_H_
-#include <map>
-
#include "base/memory/raw_ptr.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "components/performance_manager/public/graph/graph.h"
-#include "components/performance_manager/public/graph/page_node.h"
#include "components/performance_manager/public/graph/system_node.h"
-namespace performance_manager {
-
-namespace policies {
+namespace performance_manager::policies {
-// Policies that automatically flush the BFCache of pages that become non
-// visible or when the system is under memory pressure.
+// Policies that automatically flush the BFCache of pages when the system is
+// under memory pressure.
class BFCachePolicy : public GraphOwned,
- public PageNode::ObserverDefaultImpl,
public SystemNode::ObserverDefaultImpl {
public:
- BFCachePolicy();
+ BFCachePolicy() = default;
BFCachePolicy(const BFCachePolicy&) = delete;
BFCachePolicy(BFCachePolicy&&) = delete;
BFCachePolicy& operator=(const BFCachePolicy&) = delete;
BFCachePolicy& operator=(BFCachePolicy&&) = delete;
- ~BFCachePolicy() override;
+ ~BFCachePolicy() override = default;
protected:
+ using MemoryPressureLevel = base::MemoryPressureListener::MemoryPressureLevel;
+
// Try to flush the BFCache associated with |page_node|. This will be a no-op
// if there's a pending navigation.
- virtual void MaybeFlushBFCache(const PageNode* page_node);
-
- bool flush_on_moderate_pressure_;
- base::TimeDelta delay_to_flush_background_tab_;
+ virtual void MaybeFlushBFCache(const PageNode* page_node,
+ MemoryPressureLevel memory_pressure_level);
private:
// GraphOwned implementation:
void OnPassedToGraph(Graph* graph) override;
void OnTakenFromGraph(Graph* graph) override;
- // PageNodeObserver:
- void OnIsVisibleChanged(const PageNode* page_node) override;
- void OnLoadingStateChanged(const PageNode* page_node,
- PageNode::LoadingState previous_state) override;
- void OnBeforePageNodeRemoved(const PageNode* page_node) override;
-
// SystemNodeObserver:
- void OnMemoryPressure(
- base::MemoryPressureListener::MemoryPressureLevel new_level) override;
-
- void MaybeFlushBFCacheLater(const PageNode* page_node);
-
- // PageNodes that become non visible will have their BFcache after a small
- // amount of time spent in that state, this map stores the timers for that
- // logic.
- std::map<const PageNode*, base::OneShotTimer> page_to_flush_timer_;
+ void OnMemoryPressure(MemoryPressureLevel new_level) override;
raw_ptr<Graph> graph_;
};
-} // namespace policies
-} // namespace performance_manager
+} // namespace performance_manager::policies
#endif // COMPONENTS_PERFORMANCE_MANAGER_GRAPH_POLICIES_BFCACHE_POLICY_H_
diff --git a/chromium/components/performance_manager/graph/policies/bfcache_policy_unittest.cc b/chromium/components/performance_manager/graph/policies/bfcache_policy_unittest.cc
index f03c78a864d..af02206bcf8 100644
--- a/chromium/components/performance_manager/graph/policies/bfcache_policy_unittest.cc
+++ b/chromium/components/performance_manager/graph/policies/bfcache_policy_unittest.cc
@@ -13,26 +13,22 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-namespace performance_manager {
-namespace policies {
+namespace performance_manager::policies {
namespace {
// Mock version of a performance_manager::BFCachePolicy.
class LenientMockBFCachePolicy : public BFCachePolicy {
public:
- LenientMockBFCachePolicy() {
- flush_on_moderate_pressure_ = true;
- delay_to_flush_background_tab_ = base::Seconds(5);
- }
+ LenientMockBFCachePolicy() = default;
~LenientMockBFCachePolicy() override = default;
LenientMockBFCachePolicy(const LenientMockBFCachePolicy& other) = delete;
LenientMockBFCachePolicy& operator=(const LenientMockBFCachePolicy&) = delete;
- base::TimeDelta delay_to_flush_background_tab() {
- return delay_to_flush_background_tab_;
- }
- MOCK_METHOD1(MaybeFlushBFCache, void(const PageNode* page_node));
+ MOCK_METHOD2(MaybeFlushBFCache,
+ void(const PageNode* page_node,
+ MemoryPressureLevel memory_pressure_level));
};
+using MemoryPressureLevel = base::MemoryPressureListener::MemoryPressureLevel;
using MockBFCachePolicy = ::testing::StrictMock<LenientMockBFCachePolicy>;
} // namespace
@@ -75,43 +71,26 @@ class BFCachePolicyTest : public GraphTestHarness {
raw_ptr<MockBFCachePolicy> policy_;
};
-TEST_F(BFCachePolicyTest, BFCacheFlushedWhenPageBecomesNonVisible) {
- page_node_->SetIsVisible(true);
- page_node_->SetLoadingState(PageNode::LoadingState::kLoadedBusy);
- ::testing::Mock::VerifyAndClearExpectations(policy_);
-
- page_node_->SetIsVisible(false);
- // There should be no immediate call to MaybeFlushBFCache.
- ::testing::Mock::VerifyAndClearExpectations(policy_);
- task_env().FastForwardBy(policy_->delay_to_flush_background_tab() / 2);
-
- // There should be no call to MaybeFlushBFCache if not enough time has passed.
- page_node_->SetIsVisible(true);
- ::testing::Mock::VerifyAndClearExpectations(policy_);
-
- page_node_->SetIsVisible(false);
- EXPECT_CALL(*policy_, MaybeFlushBFCache(page_node_.get()));
- task_env().FastForwardBy(policy_->delay_to_flush_background_tab());
- ::testing::Mock::VerifyAndClearExpectations(policy_);
-}
-
TEST_F(BFCachePolicyTest, BFCacheFlushedOnMemoryPressure) {
page_node_->SetIsVisible(true);
page_node_->SetLoadingState(PageNode::LoadingState::kLoadedBusy);
::testing::Mock::VerifyAndClearExpectations(policy_);
- EXPECT_CALL(*policy_, MaybeFlushBFCache(page_node_.get()));
+ EXPECT_CALL(
+ *policy_,
+ MaybeFlushBFCache(page_node_.get(),
+ MemoryPressureLevel::MEMORY_PRESSURE_LEVEL_MODERATE));
GetSystemNode()->OnMemoryPressureForTesting(
- base::MemoryPressureListener::MemoryPressureLevel::
- MEMORY_PRESSURE_LEVEL_MODERATE);
+ MemoryPressureLevel::MEMORY_PRESSURE_LEVEL_MODERATE);
::testing::Mock::VerifyAndClearExpectations(policy_);
- EXPECT_CALL(*policy_, MaybeFlushBFCache(page_node_.get()));
+ EXPECT_CALL(
+ *policy_,
+ MaybeFlushBFCache(page_node_.get(),
+ MemoryPressureLevel::MEMORY_PRESSURE_LEVEL_CRITICAL));
GetSystemNode()->OnMemoryPressureForTesting(
- base::MemoryPressureListener::MemoryPressureLevel::
- MEMORY_PRESSURE_LEVEL_CRITICAL);
+ MemoryPressureLevel::MEMORY_PRESSURE_LEVEL_CRITICAL);
::testing::Mock::VerifyAndClearExpectations(policy_);
}
-} // namespace policies
-} // namespace performance_manager
+} // namespace performance_manager::policies
diff --git a/chromium/components/performance_manager/graph/process_node_impl_describer.cc b/chromium/components/performance_manager/graph/process_node_impl_describer.cc
index e31ee2c213a..18c10eaf9b3 100644
--- a/chromium/components/performance_manager/graph/process_node_impl_describer.cc
+++ b/chromium/components/performance_manager/graph/process_node_impl_describer.cc
@@ -17,7 +17,7 @@
#include "components/performance_manager/public/graph/node_data_describer_registry.h"
#include "content/public/common/child_process_host.h"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include "base/win/win_util.h"
#endif
@@ -57,9 +57,9 @@ base::Value GetProcessValueDict(const base::Process& process) {
// On Windows, handle is a void *. On Fuchsia it's an int. On other platforms
// it is equal to the pid, so don't bother to record it.
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
ret.SetIntKey("handle", base::win::HandleToUint32(process.Handle()));
-#elif defined(OS_FUCHSIA)
+#elif BUILDFLAG(IS_FUCHSIA)
ret.SetIntKey("handle", process.Handle());
#endif
@@ -74,7 +74,7 @@ base::Value GetProcessValueDict(const base::Process& process) {
}
#endif
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// Creation time is always available on Windows, even for dead processes.
// On other platforms it is available only for valid processes (see below).
ret.SetStringKey("creation_time", base::TimeFormatTimeOfDayWithMilliseconds(
@@ -84,14 +84,14 @@ base::Value GetProcessValueDict(const base::Process& process) {
if (process.IsValid()) {
// These properties can only be accessed for valid processes.
ret.SetIntKey("os_priority", process.GetPriority());
-#if !defined(OS_APPLE)
+#if !BUILDFLAG(IS_APPLE)
ret.SetBoolKey("is_backgrounded", process.IsProcessBackgrounded());
#endif
-#if !defined(OS_ANDROID) && !defined(OS_WIN)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_WIN)
ret.SetStringKey("creation_time", base::TimeFormatTimeOfDayWithMilliseconds(
process.CreationTime()));
#endif
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// Most processes are running, so only show the outliers.
if (!process.IsRunning()) {
ret.SetBoolKey("is_running", false);
diff --git a/chromium/components/performance_manager/graph_features.cc b/chromium/components/performance_manager/graph_features.cc
index 9b2b4843351..0194c989097 100644
--- a/chromium/components/performance_manager/graph_features.cc
+++ b/chromium/components/performance_manager/graph_features.cc
@@ -24,7 +24,7 @@
#include "components/performance_manager/v8_memory/v8_context_tracker.h"
#include "components/performance_manager/v8_memory/web_memory_stress_tester.h"
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
#include "components/performance_manager/public/decorators/site_data_recorder.h"
#endif
@@ -65,7 +65,7 @@ void GraphFeatures::ConfigureGraph(Graph* graph) const {
if (flags_.worker_node_impl_describer)
Install<WorkerNodeImplDescriber>(graph);
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
if (flags_.site_data_recorder)
Install<SiteDataRecorder>(graph);
#endif
diff --git a/chromium/components/performance_manager/graph_features_unittest.cc b/chromium/components/performance_manager/graph_features_unittest.cc
index ebf134f4369..00776c7262f 100644
--- a/chromium/components/performance_manager/graph_features_unittest.cc
+++ b/chromium/components/performance_manager/graph_features_unittest.cc
@@ -54,7 +54,7 @@ TEST(GraphFeaturesTest, EnableDefault) {
EXPECT_FALSE(v8_memory::V8ContextTracker::GetFromGraph(&graph));
size_t graph_owned_count = 13;
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
// The SiteDataRecorder is not available on Android.
graph_owned_count++;
#endif
diff --git a/chromium/components/performance_manager/metrics/metrics_collector_unittest.cc b/chromium/components/performance_manager/metrics/metrics_collector_unittest.cc
index db54b3bcb9e..f6d99ac0e34 100644
--- a/chromium/components/performance_manager/metrics/metrics_collector_unittest.cc
+++ b/chromium/components/performance_manager/metrics/metrics_collector_unittest.cc
@@ -22,7 +22,7 @@ const base::TimeDelta kTestMetricsReportDelayTimeout =
const char kHtmlMimeType[] = "text/html";
// TODO(crbug.com/759905) Enable on Windows once this bug is fixed.
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#define MAYBE_MetricsCollectorTest DISABLED_MetricsCollectorTest
#else
#define MAYBE_MetricsCollectorTest MetricsCollectorTest
diff --git a/chromium/components/performance_manager/persistence/site_data/leveldb_site_data_store.cc b/chromium/components/performance_manager/persistence/site_data/leveldb_site_data_store.cc
index a4763e8bea1..d5ed52b831c 100644
--- a/chromium/components/performance_manager/persistence/site_data/leveldb_site_data_store.cc
+++ b/chromium/components/performance_manager/persistence/site_data/leveldb_site_data_store.cc
@@ -351,7 +351,7 @@ DatabaseSizeResult LevelDBSiteDataStore::AsyncHelper::GetDatabaseSize() {
base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
base::BlockingType::MAY_BLOCK);
DatabaseSizeResult ret;
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// Windows has an annoying mis-feature that the size of an open file is not
// written to the parent directory until the file is closed. Since this is a
// diagnostic interface that should be rarely called, go to the trouble of
@@ -360,7 +360,7 @@ DatabaseSizeResult LevelDBSiteDataStore::AsyncHelper::GetDatabaseSize() {
db_.reset();
#endif
ret.on_disk_size_kb = base::ComputeDirectorySize(db_path_) / 1024;
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
OpenOrCreateDatabase();
if (!db_)
return DatabaseSizeResult();
diff --git a/chromium/components/performance_manager/persistence/site_data/leveldb_site_data_store_unittest.cc b/chromium/components/performance_manager/persistence/site_data/leveldb_site_data_store_unittest.cc
index df283fb9628..69a57041c05 100644
--- a/chromium/components/performance_manager/persistence/site_data/leveldb_site_data_store_unittest.cc
+++ b/chromium/components/performance_manager/persistence/site_data/leveldb_site_data_store_unittest.cc
@@ -48,9 +48,9 @@ ScopedReadOnlyDirectory::ScopedReadOnlyDirectory(
root_dir, FILE_PATH_LITERAL("read_only_path"), &read_only_path_));
permission_restorer_ =
std::make_unique<base::FilePermissionRestorer>(read_only_path_);
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
base::DenyFilePermission(read_only_path_, GENERIC_WRITE);
-#else // defined(OS_WIN)
+#else // BUILDFLAG(IS_WIN)
EXPECT_TRUE(base::MakeFileUnwritable(read_only_path_));
#endif
EXPECT_FALSE(base::PathIsWritable(read_only_path_));
diff --git a/chromium/components/performance_manager/persistence/site_data/site_data_cache_factory.h b/chromium/components/performance_manager/persistence/site_data/site_data_cache_factory.h
index 24e47d8b0d8..df27c4831bc 100644
--- a/chromium/components/performance_manager/persistence/site_data/site_data_cache_factory.h
+++ b/chromium/components/performance_manager/persistence/site_data/site_data_cache_factory.h
@@ -11,7 +11,6 @@
#include "base/callback.h"
#include "base/containers/flat_map.h"
#include "base/files/file_path.h"
-#include "base/location.h"
#include "base/sequence_checker.h"
#include "base/task/sequenced_task_runner.h"
#include "components/performance_manager/persistence/site_data/site_data_cache.h"
diff --git a/chromium/components/performance_manager/persistence/site_data/site_data_cache_impl.cc b/chromium/components/performance_manager/persistence/site_data/site_data_cache_impl.cc
index 547de3ca48a..0c8aeaa1072 100644
--- a/chromium/components/performance_manager/persistence/site_data/site_data_cache_impl.cc
+++ b/chromium/components/performance_manager/persistence/site_data/site_data_cache_impl.cc
@@ -49,7 +49,7 @@ std::unique_ptr<SiteDataReader> SiteDataCacheImpl::GetReaderForOrigin(
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
internal::SiteDataImpl* impl = GetOrCreateFeatureImpl(origin);
DCHECK(impl);
- SiteDataReader* data_reader = new SiteDataReader(impl);
+ SiteDataReader* data_reader = new SiteDataReaderImpl(impl);
return base::WrapUnique(data_reader);
}
diff --git a/chromium/components/performance_manager/persistence/site_data/site_data_reader.cc b/chromium/components/performance_manager/persistence/site_data/site_data_reader.cc
index 080d6645c84..6e53528d05b 100644
--- a/chromium/components/performance_manager/persistence/site_data/site_data_reader.cc
+++ b/chromium/components/performance_manager/persistence/site_data/site_data_reader.cc
@@ -12,41 +12,46 @@
namespace performance_manager {
-SiteDataReader::SiteDataReader(scoped_refptr<internal::SiteDataImpl> impl)
+SiteDataReader::SiteDataReader() = default;
+SiteDataReader::~SiteDataReader() = default;
+
+SiteDataReaderImpl::SiteDataReaderImpl(
+ scoped_refptr<internal::SiteDataImpl> impl)
: impl_(std::move(impl)) {}
-SiteDataReader::~SiteDataReader() {}
+SiteDataReaderImpl::~SiteDataReaderImpl() = default;
performance_manager::SiteFeatureUsage
-SiteDataReader::UpdatesFaviconInBackground() const {
+SiteDataReaderImpl::UpdatesFaviconInBackground() const {
return impl_->UpdatesFaviconInBackground();
}
-performance_manager::SiteFeatureUsage SiteDataReader::UpdatesTitleInBackground()
- const {
+performance_manager::SiteFeatureUsage
+SiteDataReaderImpl::UpdatesTitleInBackground() const {
return impl_->UpdatesTitleInBackground();
}
-performance_manager::SiteFeatureUsage SiteDataReader::UsesAudioInBackground()
- const {
+performance_manager::SiteFeatureUsage
+SiteDataReaderImpl::UsesAudioInBackground() const {
return impl_->UsesAudioInBackground();
}
-bool SiteDataReader::DataLoaded() const {
+bool SiteDataReaderImpl::DataLoaded() const {
return impl_->DataLoaded();
}
-void SiteDataReader::RegisterDataLoadedCallback(base::OnceClosure&& callback) {
+void SiteDataReaderImpl::RegisterDataLoadedCallback(
+ base::OnceClosure&& callback) {
// Register a closure that is bound using a weak pointer to this instance.
// In that way it won't be invoked by the underlying |impl_| after this
// reader is destroyed.
- base::OnceClosure closure(base::BindOnce(&SiteDataReader::RunClosure,
+ base::OnceClosure closure(base::BindOnce(&SiteDataReaderImpl::RunClosure,
weak_factory_.GetWeakPtr(),
std::move(callback)));
impl_->RegisterDataLoadedCallback(std::move(closure));
}
-void SiteDataReader::RunClosure(base::OnceClosure&& closure) {
+void SiteDataReaderImpl::RunClosure(base::OnceClosure&& closure) {
std::move(closure).Run();
}
diff --git a/chromium/components/performance_manager/persistence/site_data/site_data_reader_unittest.cc b/chromium/components/performance_manager/persistence/site_data/site_data_reader_unittest.cc
index fcfe02be257..652e112a060 100644
--- a/chromium/components/performance_manager/persistence/site_data/site_data_reader_unittest.cc
+++ b/chromium/components/performance_manager/persistence/site_data/site_data_reader_unittest.cc
@@ -80,7 +80,7 @@ class SiteDataReaderTest : public ::testing::Test {
delegate_.GetWeakPtr(), &data_store_));
test_impl_->NotifySiteLoaded();
test_impl_->NotifyLoadedSiteBackgrounded();
- SiteDataReader* reader = new SiteDataReader(test_impl_.get());
+ SiteDataReader* reader = new SiteDataReaderImpl(test_impl_.get());
reader_ = base::WrapUnique(reader);
}
@@ -156,12 +156,14 @@ TEST_F(SiteDataReaderTest, FreeingReaderDoesntCauseWriteOperation) {
::testing::_))
.WillOnce(::testing::Invoke(read_from_store_mock_impl));
- std::unique_ptr<SiteDataReader> reader = base::WrapUnique(
- new SiteDataReader(base::WrapRefCounted(new internal::SiteDataImpl(
- kOrigin, delegate_.GetWeakPtr(), &data_store))));
+ scoped_refptr<internal::SiteDataImpl> impl(
+ base::WrapRefCounted(new internal::SiteDataImpl(
+ kOrigin, delegate_.GetWeakPtr(), &data_store)));
+ std::unique_ptr<SiteDataReader> reader =
+ base::WrapUnique(new SiteDataReaderImpl(impl));
::testing::Mock::VerifyAndClear(&data_store);
- EXPECT_TRUE(reader->impl_for_testing()->fully_initialized_for_testing());
+ EXPECT_TRUE(impl->fully_initialized_for_testing());
// Resetting the reader shouldn't cause any write operation to the data store.
EXPECT_CALL(data_store, WriteSiteDataIntoStore(::testing::_, ::testing::_))
@@ -184,7 +186,7 @@ TEST_F(SiteDataReaderTest, OnDataLoadedCallbackInvoked) {
// Create the reader.
std::unique_ptr<SiteDataReader> reader =
- base::WrapUnique(new SiteDataReader(impl));
+ base::WrapUnique(new SiteDataReaderImpl(impl));
EXPECT_FALSE(reader->DataLoaded());
// Register a data ready closure.
@@ -215,7 +217,7 @@ TEST_F(SiteDataReaderTest, DestroyingReaderCancelsPendingCallbacks) {
// Create the reader.
std::unique_ptr<SiteDataReader> reader =
- base::WrapUnique(new SiteDataReader(impl));
+ base::WrapUnique(new SiteDataReaderImpl(impl));
EXPECT_FALSE(reader->DataLoaded());
// Register a data ready closure.
diff --git a/chromium/components/performance_manager/prerendering_browsertest.cc b/chromium/components/performance_manager/prerendering_browsertest.cc
index a26d3464c7f..eb61056f058 100644
--- a/chromium/components/performance_manager/prerendering_browsertest.cc
+++ b/chromium/components/performance_manager/prerendering_browsertest.cc
@@ -58,7 +58,7 @@ class PerformanceManagerPrerenderingBrowserTest
// and wait for the old RenderFrameHost to be deleted after we navigate away
// from it.
content::DisableBackForwardCacheForTesting(
- web_contents(), content::BackForwardCache::TEST_ASSUMES_NO_CACHING);
+ web_contents(), content::BackForwardCache::TEST_REQUIRES_NO_CACHING);
}
void TearDownOnMainThread() override {
diff --git a/chromium/components/performance_manager/public/features.h b/chromium/components/performance_manager/public/features.h
index b877c8ee60a..5e9402f2ec4 100644
--- a/chromium/components/performance_manager/public/features.h
+++ b/chromium/components/performance_manager/public/features.h
@@ -13,13 +13,12 @@
#include "base/time/time.h"
#include "build/build_config.h"
-namespace performance_manager {
-namespace features {
+namespace performance_manager::features {
// The feature that gates whether or not the PM runs on the main (UI) thread.
extern const base::Feature kRunOnMainThread;
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
// Enables urgent discarding of pages directly from PerformanceManager rather
// than via TabManager.
extern const base::Feature kUrgentDiscardingFromPerformanceManager;
@@ -67,52 +66,6 @@ extern const base::Feature kBackgroundTabLoadingFromPerformanceManager;
// BFCache of all pages when the system is under memory pressure.
extern const base::Feature kBFCachePerformanceManagerPolicy;
-// Parameters allowing to control some aspects of the
-// |kBFCachePerformanceManagerPolicy|.
-class BFCachePerformanceManagerPolicyParams {
- public:
- BFCachePerformanceManagerPolicyParams(
- BFCachePerformanceManagerPolicyParams&&) = default;
- BFCachePerformanceManagerPolicyParams& operator=(
- BFCachePerformanceManagerPolicyParams&&) = default;
- BFCachePerformanceManagerPolicyParams(
- const BFCachePerformanceManagerPolicyParams&) = delete;
- BFCachePerformanceManagerPolicyParams& operator=(
- const BFCachePerformanceManagerPolicyParams&) = delete;
- ~BFCachePerformanceManagerPolicyParams() = default;
-
- static BFCachePerformanceManagerPolicyParams GetParams();
-
- // Whether or not the BFCache of all pages should be flushed when the system
- // is under *moderate* memory pressure. The policy always flushes the bfcache
- // under critical pressure.
- bool flush_on_moderate_pressure() const {
- return flush_on_moderate_pressure_;
- }
-
- base::TimeDelta delay_to_flush_background_tab() const {
- return delay_to_flush_background_tab_;
- }
-
- static constexpr base::FeatureParam<bool> kFlushOnModeratePressure{
- &features::kBFCachePerformanceManagerPolicy, "flush_on_moderate_pressure",
- false};
-
- // The back forward cache should be flushed after the tab goes to background
- // and elapses this delay. If the value is negative (such as -1), the back
- // forward cache in the background tabs will not be flushed.
- static constexpr base::FeatureParam<int> kDelayToFlushBackgroundTabInSeconds{
- &features::kBFCachePerformanceManagerPolicy,
- "delay_to_flush_background_tab_in_seconds", -1};
-
- private:
- BFCachePerformanceManagerPolicyParams() = default;
-
- bool flush_on_moderate_pressure_;
- base::TimeDelta delay_to_flush_background_tab_;
-};
-
-} // namespace features
-} // namespace performance_manager
+} // namespace performance_manager::features
#endif // COMPONENTS_PERFORMANCE_MANAGER_PUBLIC_FEATURES_H_
diff --git a/chromium/components/performance_manager/public/graph/node_attached_data.h b/chromium/components/performance_manager/public/graph/node_attached_data.h
index 79a97a0aaa2..67a5f6af267 100644
--- a/chromium/components/performance_manager/public/graph/node_attached_data.h
+++ b/chromium/components/performance_manager/public/graph/node_attached_data.h
@@ -67,7 +67,7 @@ class ExternalNodeAttachedDataImpl : public NodeAttachedData {
static bool Destroy(const NodeType* node);
private:
- static constexpr int kUserDataKey = 0;
+ static const int kUserDataKey = 0;
static const void* UserDataKey() { return &kUserDataKey; }
};
diff --git a/chromium/components/performance_manager/public/persistence/site_data/site_data_reader.h b/chromium/components/performance_manager/public/persistence/site_data/site_data_reader.h
index 2a24a781448..56aa92fba73 100644
--- a/chromium/components/performance_manager/public/persistence/site_data/site_data_reader.h
+++ b/chromium/components/performance_manager/public/persistence/site_data/site_data_reader.h
@@ -22,28 +22,39 @@ class SiteDataImpl;
class SiteDataReader {
public:
- SiteDataReader(const SiteDataReader&) = delete;
- SiteDataReader& operator=(const SiteDataReader&) = delete;
-
- ~SiteDataReader();
+ SiteDataReader();
+ virtual ~SiteDataReader();
// Accessors for the site characteristics usage.
- performance_manager::SiteFeatureUsage UpdatesFaviconInBackground() const;
- performance_manager::SiteFeatureUsage UpdatesTitleInBackground() const;
- performance_manager::SiteFeatureUsage UsesAudioInBackground() const;
+ virtual SiteFeatureUsage UpdatesFaviconInBackground() const = 0;
+ virtual SiteFeatureUsage UpdatesTitleInBackground() const = 0;
+ virtual SiteFeatureUsage UsesAudioInBackground() const = 0;
// Returns true if this reader is fully initialized and serving the most
// authoritative data. This can initially return false as the backing store is
// loaded asynchronously.
- bool DataLoaded() const;
+ virtual bool DataLoaded() const = 0;
// Registers a callback that will be invoked when the data backing this object
// has been loaded. Note that if "DataLoaded" is true at the time this is
// called it may immediately invoke the callback. The callback will not be
// invoked after this object has been destroyed.
- void RegisterDataLoadedCallback(base::OnceClosure&& callback);
+ virtual void RegisterDataLoadedCallback(base::OnceClosure&& callback) = 0;
+};
+
+class SiteDataReaderImpl : public SiteDataReader {
+ public:
+ SiteDataReaderImpl(const SiteDataReaderImpl&) = delete;
+ SiteDataReaderImpl& operator=(const SiteDataReaderImpl&) = delete;
+
+ ~SiteDataReaderImpl() override;
- const internal::SiteDataImpl* impl_for_testing() const { return impl_.get(); }
+ // SiteDataReader:
+ SiteFeatureUsage UpdatesFaviconInBackground() const override;
+ SiteFeatureUsage UpdatesTitleInBackground() const override;
+ SiteFeatureUsage UsesAudioInBackground() const override;
+ bool DataLoaded() const override;
+ void RegisterDataLoadedCallback(base::OnceClosure&& callback) override;
private:
friend class SiteDataCacheImpl;
@@ -57,7 +68,7 @@ class SiteDataReader {
// Private constructor, these objects are meant to be created by a site data
// store.
- explicit SiteDataReader(scoped_refptr<internal::SiteDataImpl> impl);
+ explicit SiteDataReaderImpl(scoped_refptr<internal::SiteDataImpl> impl);
// Runs the provided closure. This is used as a wrapper so that callbacks
// registered with the |impl_| by this reader are invalidated when the
@@ -68,7 +79,7 @@ class SiteDataReader {
const scoped_refptr<internal::SiteDataImpl> impl_;
// Used for invalidating callbacks.
- base::WeakPtrFactory<SiteDataReader> weak_factory_{this};
+ base::WeakPtrFactory<SiteDataReaderImpl> weak_factory_{this};
};
} // namespace performance_manager
diff --git a/chromium/components/performance_manager/render_process_user_data.cc b/chromium/components/performance_manager/render_process_user_data.cc
index e22d887e46f..640ef3a0c65 100644
--- a/chromium/components/performance_manager/render_process_user_data.cc
+++ b/chromium/components/performance_manager/render_process_user_data.cc
@@ -77,7 +77,7 @@ RenderProcessUserData* RenderProcessUserData::CreateForRenderProcessHost(
void RenderProcessUserData::RenderProcessReady(
content::RenderProcessHost* host) {
const base::Time launch_time =
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Process::CreationTime() is not available on Android. Since this
// method is called immediately after the process is launched, the
// process launch time can be approximated with the current time.
diff --git a/chromium/components/performance_manager/service_worker_context_adapter.cc b/chromium/components/performance_manager/service_worker_context_adapter.cc
index 960a489ceb0..91fb3621309 100644
--- a/chromium/components/performance_manager/service_worker_context_adapter.cc
+++ b/chromium/components/performance_manager/service_worker_context_adapter.cc
@@ -121,6 +121,7 @@ void ServiceWorkerContextAdapter::UnregisterServiceWorker(
content::ServiceWorkerExternalRequestResult
ServiceWorkerContextAdapter::StartingExternalRequest(
int64_t service_worker_version_id,
+ content::ServiceWorkerExternalRequestTimeoutType timeout_type,
const std::string& request_uuid) {
NOTIMPLEMENTED();
return content::ServiceWorkerExternalRequestResult::kOk;
@@ -140,6 +141,14 @@ size_t ServiceWorkerContextAdapter::CountExternalRequestsForTest(
return 0u;
}
+bool ServiceWorkerContextAdapter::ExecuteScriptForTest(
+ const std::string& script,
+ int64_t version_id,
+ content::ServiceWorkerScriptExecutionCallback callback) {
+ NOTIMPLEMENTED();
+ return false;
+}
+
bool ServiceWorkerContextAdapter::MaybeHasRegistrationForStorageKey(
const blink::StorageKey& key) {
NOTIMPLEMENTED();
diff --git a/chromium/components/performance_manager/service_worker_context_adapter.h b/chromium/components/performance_manager/service_worker_context_adapter.h
index e46c41b9caa..b65457560e4 100644
--- a/chromium/components/performance_manager/service_worker_context_adapter.h
+++ b/chromium/components/performance_manager/service_worker_context_adapter.h
@@ -60,11 +60,16 @@ class ServiceWorkerContextAdapter
ResultCallback callback) override;
content::ServiceWorkerExternalRequestResult StartingExternalRequest(
int64_t service_worker_version_id,
+ content::ServiceWorkerExternalRequestTimeoutType timeout_type,
const std::string& request_uuid) override;
content::ServiceWorkerExternalRequestResult FinishedExternalRequest(
int64_t service_worker_version_id,
const std::string& request_uuid) override;
size_t CountExternalRequestsForTest(const blink::StorageKey& key) override;
+ bool ExecuteScriptForTest(
+ const std::string& script,
+ int64_t service_worker_version_id,
+ content::ServiceWorkerScriptExecutionCallback callback) override;
bool MaybeHasRegistrationForStorageKey(const blink::StorageKey& key) override;
void GetAllOriginsInfo(GetUsageInfoCallback callback) override;
void DeleteForStorageKey(const blink::StorageKey& key,
diff --git a/chromium/components/performance_manager/v8_memory/v8_context_tracker_helpers.h b/chromium/components/performance_manager/v8_memory/v8_context_tracker_helpers.h
index cab1e8915be..b7944a280ef 100644
--- a/chromium/components/performance_manager/v8_memory/v8_context_tracker_helpers.h
+++ b/chromium/components/performance_manager/v8_memory/v8_context_tracker_helpers.h
@@ -7,7 +7,6 @@
#include <string>
-#include "base/compiler_specific.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/blink/public/common/tokens/tokens.h"
@@ -29,31 +28,29 @@ namespace v8_memory {
// Helper function to convert a WorkerToken to an ExecutionContext token.
// TODO(crbug.com/1126285): There should be automatic type conversion for this
// added to MultiToken<>.
-blink::ExecutionContextToken ToExecutionContextToken(
- const blink::WorkerToken& token) WARN_UNUSED_RESULT;
+[[nodiscard]] blink::ExecutionContextToken ToExecutionContextToken(
+ const blink::WorkerToken& token);
// Determines if the provided frame has a cross-process parent frame.
-bool HasCrossProcessParent(const FrameNode* frame_node) WARN_UNUSED_RESULT;
+[[nodiscard]] bool HasCrossProcessParent(const FrameNode* frame_node);
// Determines if a string is a valid extension ID.
// TODO(crbug.com/1096617): The extension ID should be strongly typed, with
// built-in validation, mojo type-mapping, etc. Ideally this would be done
// directly in extensions/common/extension_id.h.
-bool IsValidExtensionId(const std::string& s) WARN_UNUSED_RESULT;
+[[nodiscard]] bool IsValidExtensionId(const std::string& s);
// Returns true if an ExecutionContextToken corresponds to a worklet.
-bool IsWorkletToken(const blink::ExecutionContextToken& token)
- WARN_UNUSED_RESULT;
+[[nodiscard]] bool IsWorkletToken(const blink::ExecutionContextToken& token);
// Returns true if an ExecutionContextToken corresponds to a worker.
-bool IsWorkerToken(const blink::ExecutionContextToken& token)
- WARN_UNUSED_RESULT;
+[[nodiscard]] bool IsWorkerToken(const blink::ExecutionContextToken& token);
// Looks up the execution context corresponding to the given token. Note that
// the ExecutionContextRegistry must be installed on the graph.
-const execution_context::ExecutionContext* GetExecutionContext(
+[[nodiscard]] const execution_context::ExecutionContext* GetExecutionContext(
const blink::ExecutionContextToken& token,
- Graph* graph) WARN_UNUSED_RESULT;
+ Graph* graph);
// Return type for V8ContextDescription validation.
enum class V8ContextDescriptionStatus {
@@ -73,16 +70,17 @@ enum class V8ContextDescriptionStatus {
};
// Validates the given V8ContextDescription.
-V8ContextDescriptionStatus ValidateV8ContextDescription(
- const mojom::V8ContextDescription& description) WARN_UNUSED_RESULT;
+[[nodiscard]] V8ContextDescriptionStatus ValidateV8ContextDescription(
+ const mojom::V8ContextDescription& description);
// Determines whether or not IframeAttributionData is expected to accompany the
// provided V8ContextDescription. This is not always able to be determined, in
// which case absl::nullopt will be returned. It is assumed that the
// |description| has previously been validated.
-absl::optional<bool> ExpectIframeAttributionDataForV8ContextDescription(
+[[nodiscard]] absl::optional<bool>
+ExpectIframeAttributionDataForV8ContextDescription(
const mojom::V8ContextDescription& description,
- Graph* graph) WARN_UNUSED_RESULT;
+ Graph* graph);
// Small helper class for maintaining a count of objects that are optionally
// "marked".
diff --git a/chromium/components/performance_manager/v8_memory/v8_context_tracker_internal.h b/chromium/components/performance_manager/v8_memory/v8_context_tracker_internal.h
index 3787e3644dd..43f757d1ab8 100644
--- a/chromium/components/performance_manager/v8_memory/v8_context_tracker_internal.h
+++ b/chromium/components/performance_manager/v8_memory/v8_context_tracker_internal.h
@@ -13,7 +13,6 @@
#include <memory>
#include <set>
-#include "base/compiler_specific.h"
#include "base/containers/linked_list.h"
#include "base/memory/raw_ptr.h"
#include "base/types/pass_key.h"
@@ -86,33 +85,33 @@ class ExecutionContextData : public base::LinkNode<ExecutionContextData>,
// Returns true if this object is currently being tracked (it is in
// ProcessData::execution_context_datas_, and
// V8ContextTrackerDataStore::global_execution_context_datas_).
- WARN_UNUSED_RESULT bool IsTracked() const;
+ [[nodiscard]] bool IsTracked() const;
// Returns true if this object *should* be destroyed (there are no references
// to it keeping it alive).
- WARN_UNUSED_RESULT bool ShouldDestroy() const;
+ [[nodiscard]] bool ShouldDestroy() const;
// Manages remote frame data associated with this ExecutionContextData.
void SetRemoteFrameData(base::PassKey<RemoteFrameData>,
RemoteFrameData* remote_frame_data);
- WARN_UNUSED_RESULT bool ClearRemoteFrameData(base::PassKey<RemoteFrameData>);
+ [[nodiscard]] bool ClearRemoteFrameData(base::PassKey<RemoteFrameData>);
// Increments |v8_context_count_|.
void IncrementV8ContextCount(base::PassKey<V8ContextData>);
// Decrements |v8_context_count_|, and returns true if the object has
// transitioned to "ShouldDestroy".
- WARN_UNUSED_RESULT bool DecrementV8ContextCount(base::PassKey<V8ContextData>);
+ [[nodiscard]] bool DecrementV8ContextCount(base::PassKey<V8ContextData>);
// Marks this context as destroyed. Returns true if the state changed, false
// if it was already destroyed.
- WARN_UNUSED_RESULT bool MarkDestroyed(base::PassKey<ProcessData>);
+ [[nodiscard]] bool MarkDestroyed(base::PassKey<ProcessData>);
// Used for tracking the total number of non-detached "main" V8Contexts
// associated with this ExecutionContext. This should always be no more than
// 1. A new context may become the main context during a same-document
// navigation of a frame.
- WARN_UNUSED_RESULT bool MarkMainV8ContextCreated(
+ [[nodiscard]] bool MarkMainV8ContextCreated(
base::PassKey<V8ContextTrackerDataStore>);
void MarkMainV8ContextDetached(base::PassKey<V8ContextData>);
@@ -162,7 +161,7 @@ class RemoteFrameData : public base::LinkNode<RemoteFrameData> {
// Returns true if this object is currently being tracked (it is in
// ProcessData::remote_frame_datas_, and
// V8ContextTrackerDataStore::global_remote_frame_datas_).
- WARN_UNUSED_RESULT bool IsTracked() const;
+ [[nodiscard]] bool IsTracked() const;
private:
const raw_ptr<ProcessData> process_data_;
@@ -198,7 +197,7 @@ class V8ContextData : public base::LinkNode<V8ContextData>,
// Returns true if this object is currently being tracked (its in
// ProcessData::v8_context_datas_, and
// V8ContextTrackerDataStore::global_v8_context_datas_).
- WARN_UNUSED_RESULT bool IsTracked() const;
+ [[nodiscard]] bool IsTracked() const;
// Returns the ExecutionContextData associated with this V8ContextData.
ExecutionContextData* GetExecutionContextData() const;
@@ -208,7 +207,7 @@ class V8ContextData : public base::LinkNode<V8ContextData>,
// Marks this context as detached. Returns true if the state changed, false
// if it was already detached.
- WARN_UNUSED_RESULT bool MarkDetached(base::PassKey<ProcessData>);
+ [[nodiscard]] bool MarkDetached(base::PassKey<ProcessData>);
// Returns true if this is the "main" V8Context for an ExecutionContext.
// This will return true if |GetExecutionContextData()| is a frame and
@@ -260,11 +259,10 @@ class ProcessData : public NodeAttachedDataImpl<ProcessData> {
// For marking objects detached/destroyed. Returns true if the state
// actually changed, false otherwise.
- WARN_UNUSED_RESULT bool MarkDestroyed(
- base::PassKey<V8ContextTrackerDataStore>,
- ExecutionContextData* ec_data);
- WARN_UNUSED_RESULT bool MarkDetached(base::PassKey<V8ContextTrackerDataStore>,
- V8ContextData* v8_data);
+ [[nodiscard]] bool MarkDestroyed(base::PassKey<V8ContextTrackerDataStore>,
+ ExecutionContextData* ec_data);
+ [[nodiscard]] bool MarkDetached(base::PassKey<V8ContextTrackerDataStore>,
+ V8ContextData* v8_data);
size_t GetExecutionContextDataCount() const {
return counts_.GetExecutionContextDataCount();
@@ -320,7 +318,7 @@ class V8ContextTrackerDataStore {
// |ec_data| to the impl that "ShouldDestroy" should return false.
void Pass(std::unique_ptr<ExecutionContextData> ec_data);
void Pass(std::unique_ptr<RemoteFrameData> rf_data);
- WARN_UNUSED_RESULT bool Pass(std::unique_ptr<V8ContextData> v8_data);
+ [[nodiscard]] bool Pass(std::unique_ptr<V8ContextData> v8_data);
// Looks up owned objects by token.
ExecutionContextData* Get(const blink::ExecutionContextToken& token);
@@ -330,7 +328,7 @@ class V8ContextTrackerDataStore {
// For marking objects as detached/destroyed. "MarkDetached" returns true if
// the object was not previously detached, false otherwise.
void MarkDestroyed(ExecutionContextData* ec_data);
- WARN_UNUSED_RESULT bool MarkDetached(V8ContextData* v8_data);
+ [[nodiscard]] bool MarkDetached(V8ContextData* v8_data);
// Destroys objects by token. They must exist ("Get" should return non
// nullptr).
diff --git a/chromium/components/performance_manager/v8_memory/v8_detailed_memory_unittest.cc b/chromium/components/performance_manager/v8_memory/v8_detailed_memory_unittest.cc
index c2cd5be1b18..a3e8aa2ad7e 100644
--- a/chromium/components/performance_manager/v8_memory/v8_detailed_memory_unittest.cc
+++ b/chromium/components/performance_manager/v8_memory/v8_detailed_memory_unittest.cc
@@ -1556,7 +1556,7 @@ TEST_F(V8DetailedMemoryDecoratorDeathTest, EnforceObserversRemoved) {
});
}
-TEST_F(V8DetailedMemoryDecoratorDeathTest, InvalidParameters) {
+TEST_F(V8DetailedMemoryDecoratorDeathTest, InvalidEagerModeConfig) {
// Not allowed to use kEagerForTesting mode without calling
// SetEagerMemoryMeasurementEnabledForTesting.
EXPECT_DCHECK_DEATH({
@@ -1567,19 +1567,26 @@ TEST_F(V8DetailedMemoryDecoratorDeathTest, InvalidParameters) {
V8DetailedMemoryRequestAnySeq memory_request(
kMinTimeBetweenRequests, MeasurementMode::kEagerForTesting);
});
- // Zero, negative and infinite TimeDelta's are disallowed.
+}
+
+TEST_F(V8DetailedMemoryDecoratorDeathTest, NonPositiveTimeDeltas) {
+ // Zero and negative.
EXPECT_DCHECK_DEATH({
base::TimeDelta zero;
V8DetailedMemoryRequestAnySeq memory_request(zero);
});
EXPECT_DCHECK_DEATH({
- V8DetailedMemoryRequestAnySeq memory_request(base::TimeDelta::Min());
+ V8DetailedMemoryRequestAnySeq memory_request(kMinTimeBetweenRequests * -1);
});
+}
+
+TEST_F(V8DetailedMemoryDecoratorDeathTest, ExtremeTImeDeltas) {
+ // Infinite TimeDelta's are disallowed.
EXPECT_DCHECK_DEATH({
- V8DetailedMemoryRequestAnySeq memory_request(base::TimeDelta::Max());
+ V8DetailedMemoryRequestAnySeq memory_request(base::TimeDelta::Min());
});
EXPECT_DCHECK_DEATH({
- V8DetailedMemoryRequestAnySeq memory_request(kMinTimeBetweenRequests * -1);
+ V8DetailedMemoryRequestAnySeq memory_request(base::TimeDelta::Max());
});
}
@@ -1687,7 +1694,7 @@ TEST_F(V8DetailedMemoryRequestAnySeqTest, RequestIsSequenceSafe) {
}
// TODO(crbug.com/1203439) Sometimes timing out on Windows.
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#define MAYBE_SingleProcessRequest DISABLED_SingleProcessRequest
#else
#define MAYBE_SingleProcessRequest SingleProcessRequest
diff --git a/chromium/components/permissions/BUILD.gn b/chromium/components/permissions/BUILD.gn
index e1f33848f20..8cbc3d9fbf8 100644
--- a/chromium/components/permissions/BUILD.gn
+++ b/chromium/components/permissions/BUILD.gn
@@ -55,6 +55,8 @@ source_set("permissions") {
"contexts/wake_lock_permission_context.h",
"contexts/webxr_permission_context.cc",
"contexts/webxr_permission_context.h",
+ "contexts/window_placement_permission_context.cc",
+ "contexts/window_placement_permission_context.h",
"object_permission_context_base.cc",
"object_permission_context_base.h",
"permission_actions_history.cc",
@@ -232,6 +234,7 @@ source_set("test_support") {
source_set("unit_tests") {
testonly = true
sources = [
+ "chooser_title_util_unittest.cc",
"contexts/camera_pan_tilt_zoom_permission_context_unittest.cc",
"contexts/geolocation_permission_context_unittest.cc",
"contexts/midi_permission_context_unittest.cc",
@@ -268,6 +271,7 @@ source_set("unit_tests") {
"//components/content_settings/core/browser",
"//components/keyed_service/content",
"//components/prefs:test_support",
+ "//components/strings:components_strings_grit",
"//components/ukm:test_support",
"//components/ukm/content",
"//components/variations",
diff --git a/chromium/components/permissions/README.md b/chromium/components/permissions/README.md
index 87749681d17..bc567894372 100644
--- a/chromium/components/permissions/README.md
+++ b/chromium/components/permissions/README.md
@@ -62,13 +62,6 @@ saved and retrieved using a key consisting of a 3-tuple of values:
[ContentSettingsType](https://cs.chromium.org/chromium/src/components/content_settings/core/common/content_settings_types.h)
that specifies which setting this operation refers to.
-> NOTE: While the code contains a `ResourceIdentifier` this is deprecated and
-> should never be used.
-
-See [go/otjvl](go/otjvl) for a breakdown of primary/secondary pattern meanings
-based on
-[ContentSettingsType](https://cs.chromium.org/chromium/src/components/content_settings/core/common/content_settings_types.h)
-
A
[ContentSettingsPattern](https://cs.chromium.org/chromium/src/components/content_settings/core/common/content_settings_pattern.h)
is basically a URL where every part (scheme, host port, path) is allowed to be
@@ -182,27 +175,14 @@ to present to the user based on information about the request.
For specific permission prompt requests a decision could be made to enforce a
quiet UI version of the permission prompt. Currently this only applies to
-NOTIFICATION permission requests.
+NOTIFICATIONS permission requests.
A quiet UI prompt can be triggered if any of these conditions are met:
* The user has enabled quiet prompts in settings.
-* The user's denial behavior has caused quiet prompts to be enabled
- automatically. See below for more details on this.
* The site requesting the permissions is marked by Safe Browsing as having a
bad reputation.
-In order for the user's behavior to automatically enable quiet notification
-prompts, the feature variation of
-"[kQuietNotificationPromptsWithAdaptiveActivation](https://cs.chromium.org/chromium/src/chrome/browser/about_flags.cc?g=0&l=1444)"
-needs to the enabled variation for the
-"[quiet-notification-prompts](https://cs.chromium.org/chromium/src/chrome/browser/about_flags.cc?g=0&l=4626)"
-feature to enable adaptively activating quiet notifications based on user
-behavior. If adaptive activation is enabled, when the user has decided to deny 3
-notification prompts in a row (regardless if on the same site or entirely
-different sites), they will automatically start receiving only quiet
-notification permission prompts.
-
The
[AdaptiveQuietNotificationPermissionUiEnabler](https://cs.chromium.org/chromium/src/chrome/browser/permissions/adaptive_quiet_notification_permission_ui_enabler.h)
is responsible for recording the permission prompts outcomes and, if needed,
@@ -213,3 +193,36 @@ the appropriate UI flavor.
A quiet UI prompt will use a right-side omnibox indicator on desktop or a
mini-infobar on Android.
+
+## [PermissionsSecurityModelInteractiveUITest](https://cs.chromium.org/chromium/src/chrome/browser/permissions/permissions_security_model_interactive_uitest.cc)
+
+### Testing
+
+Requesting and verification of permissions does not feature unified behavior in
+different environments. In other words, based on the preconditions, a permission
+request could be shown or automatically declined. To make sure that all cases
+work as intended, we introduced [PermissionsSecurityModelInteractiveUITest](https://cs.chromium.org/chromium/src/chrome/browser/permissions/permissions_security_model_interactive_uitest.cc).
+
+### Add your own test
+
+If you're adding a new environment that requires non-default behavior for
+permissions, then you need to add a test in
+[PermissionsSecurityModelInteractiveUITest](https://cs.chromium.org/chromium/src/chrome/browser/permissions/permissions_security_model_interactive_uitest.cc).
+
+Steps to follow:
+
+* Create a new test fixture and activate your environment and get a
+ [WebContents](https://source.chromium.org/chromium/chromium/src/+/main:content/public/browser/web_contents.h)
+ or a [RenderFrameHost](https://source.chromium.org/chromium/chromium/src/+/main:content/public/browser/render_frame_host.h).
+* Create a method `VerifyPermissionForXYZ`, where `XYZ` is the name of your
+ environment. You can use the already defined `VerifyPermission` method if you
+ expect to have default behavior for permissions. In `VerifyPermissionForXYZ`
+ define a new behavior you expect to have.
+* Call `VerifyPermissionForXYZ` from your newly created test fixture.
+
+> EXAMPLE:
+> [PermissionRequestWithPortalTest](https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/permissions/permissions_security_model_interactive_uitest.cc;drc=c662f11e160976c04682f41941aaeccad92ace48;bpv=0;bpt=1;l=1063)
+> enables the [Portals](https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/common/features.cc;l=179;drc=c662f11e160976c04682f41941aaeccad92ace48).
+> The [PortalActivation] test verifies that permissions are disabled in Portals.
+> [VerifyPermissionsDeniedForPortal](https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/permissions/permissions_security_model_interactive_uitest.cc;drc=c662f11e160976c04682f41941aaeccad92ace48;l=429) incapsulates all logic
+> needed for a particular permission verification.
diff --git a/chromium/components/permissions/android/BUILD.gn b/chromium/components/permissions/android/BUILD.gn
index 958cacdd47e..13ecd738384 100644
--- a/chromium/components/permissions/android/BUILD.gn
+++ b/chromium/components/permissions/android/BUILD.gn
@@ -55,27 +55,16 @@ android_resources("java_resources") {
"res/drawable-xxxhdpi/infobar_protected_media_identifier.png",
"res/drawable-xxxhdpi/infobar_warning.png",
"res/drawable-xxxhdpi/permission_cookie.png",
- "res/drawable/gm_filled_bluetooth_searching_20.xml",
"res/drawable/gm_filled_bluetooth_searching_24.xml",
- "res/drawable/gm_filled_cardboard_20.xml",
"res/drawable/gm_filled_cardboard_24.xml",
- "res/drawable/gm_filled_content_paste_20.xml",
"res/drawable/gm_filled_content_paste_24.xml",
- "res/drawable/gm_filled_devices_20.xml",
"res/drawable/gm_filled_devices_24.xml",
- "res/drawable/gm_filled_location_on_20.xml",
"res/drawable/gm_filled_location_on_24.xml",
- "res/drawable/gm_filled_mic_20.xml",
"res/drawable/gm_filled_mic_24.xml",
- "res/drawable/gm_filled_nfc_20.xml",
"res/drawable/gm_filled_nfc_24.xml",
- "res/drawable/gm_filled_notifications_20.xml",
"res/drawable/gm_filled_notifications_24.xml",
- "res/drawable/gm_filled_piano_20.xml",
"res/drawable/gm_filled_piano_24.xml",
- "res/drawable/gm_filled_usb_20.xml",
"res/drawable/gm_filled_usb_24.xml",
- "res/drawable/gm_filled_videocam_20.xml",
"res/drawable/gm_filled_videocam_24.xml",
"res/drawable/ic_bluetooth_connected.xml",
"res/drawable/ic_signal_cellular_0_bar.xml",
diff --git a/chromium/components/permissions/android/permission_prompt_android.cc b/chromium/components/permissions/android/permission_prompt_android.cc
index 4befe27d27b..0486024f375 100644
--- a/chromium/components/permissions/android/permission_prompt_android.cc
+++ b/chromium/components/permissions/android/permission_prompt_android.cc
@@ -43,13 +43,10 @@ PermissionPromptAndroid::PermissionPromptAndroid(
permissions::PermissionPromptDisposition::MODAL_DIALOG;
PermissionDialogDelegate::Create(web_contents_, this);
}
-
- prompt_disposition_ = permissions::PermissionPromptDisposition::MINI_INFOBAR;
}
PermissionPromptAndroid::~PermissionPromptAndroid() {
if (message_delegate_) {
- message_delegate_.reset();
return;
}
infobars::InfoBarManager* infobar_manager =
@@ -90,10 +87,23 @@ void PermissionPromptAndroid::Deny() {
delegate_->Deny();
}
+void PermissionPromptAndroid::SetManageClicked() {
+ delegate_->SetManageClicked();
+}
+
+void PermissionPromptAndroid::SetLearnMoreClicked() {
+ delegate_->SetLearnMoreClicked();
+}
+
bool PermissionPromptAndroid::ShouldCurrentRequestUseQuietUI() {
return delegate_->ShouldCurrentRequestUseQuietUI();
}
+absl::optional<PermissionUiSelector::QuietUiReason>
+PermissionPromptAndroid::ReasonForUsingQuietUi() const {
+ return delegate_->ReasonForUsingQuietUi();
+}
+
size_t PermissionPromptAndroid::PermissionCount() const {
return delegate_->Requests().size();
}
diff --git a/chromium/components/permissions/android/permission_prompt_android.h b/chromium/components/permissions/android/permission_prompt_android.h
index 12ebbce8079..375817ab4c8 100644
--- a/chromium/components/permissions/android/permission_prompt_android.h
+++ b/chromium/components/permissions/android/permission_prompt_android.h
@@ -12,7 +12,6 @@
#include "base/memory/weak_ptr.h"
#include "components/content_settings/core/common/content_settings_types.h"
#include "components/infobars/core/infobar_manager.h"
-#include "components/messages/android/message_wrapper.h"
#include "components/permissions/permission_prompt.h"
#include "components/permissions/permission_uma_util.h"
#include "components/permissions/permissions_client.h"
@@ -52,7 +51,11 @@ class PermissionPromptAndroid : public permissions::PermissionPrompt,
void Closing();
void Accept();
void Deny();
+ void SetManageClicked();
+ void SetLearnMoreClicked();
bool ShouldCurrentRequestUseQuietUI();
+ absl::optional<PermissionUiSelector::QuietUiReason> ReasonForUsingQuietUi()
+ const;
// We show one permission at a time except for grouped mic+camera, for which
// we still have a single icon and message text.
diff --git a/chromium/components/permissions/android/permissions_android_feature_list.cc b/chromium/components/permissions/android/permissions_android_feature_list.cc
index 3712456c433..cab4a433f3f 100644
--- a/chromium/components/permissions/android/permissions_android_feature_list.cc
+++ b/chromium/components/permissions/android/permissions_android_feature_list.cc
@@ -4,6 +4,7 @@
#include "components/permissions/android/permissions_android_feature_list.h"
#include "base/android/jni_string.h"
+#include "base/notreached.h"
#include "components/permissions/android/jni_headers/PermissionsAndroidFeatureList_jni.h"
using base::android::ConvertJavaStringToUTF8;
diff --git a/chromium/components/permissions/android/res/color/item_chooser_row_icon_color.xml b/chromium/components/permissions/android/res/color/item_chooser_row_icon_color.xml
index d29d0b80e92..d27af03917f 100644
--- a/chromium/components/permissions/android/res/color/item_chooser_row_icon_color.xml
+++ b/chromium/components/permissions/android/res/color/item_chooser_row_icon_color.xml
@@ -4,7 +4,7 @@
found in the LICENSE file.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:color="@color/default_icon_color_inverse" android:state_selected="true"/>
+ <item android:color="@macro/default_icon_color_inverse" android:state_selected="true"/>
<item android:alpha="@dimen/default_disabled_alpha"
android:state_enabled="false" android:color="@macro/default_icon_color" />
<item android:color="@macro/default_icon_color"/>
diff --git a/chromium/components/permissions/android/res/drawable/gm_filled_bluetooth_searching_20.xml b/chromium/components/permissions/android/res/drawable/gm_filled_bluetooth_searching_20.xml
deleted file mode 100644
index 0aafb0f8ebb..00000000000
--- a/chromium/components/permissions/android/res/drawable/gm_filled_bluetooth_searching_20.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--Copyright 2021 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.-->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="20dp"
- android:height="20dp"
- android:viewportWidth="20"
- android:viewportHeight="20"
- android:tint="?attr/colorControlNormal"
- android:autoMirrored="true">
- <path
- android:fillColor="@android:color/white"
- android:pathData="M13.13,6.5L8.63,2L7.5,2l0,5.87L3.93,4.31L2.87,5.37L7.5,10V10l-4.63,4.63l1.06,1.06l3.57,-3.57l0,5.88l1.12,0l4.5,-4.5L9.63,10L13.13,6.5zM11,6.5l-2,2L9,4.5L11,6.5zM11,13.5l-2,2l0,-4.01L11,13.5z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M15.95,6.05l-1.11,1.11C15.26,8.02 15.5,8.98 15.5,10s-0.24,1.98 -0.66,2.84l1.11,1.11C16.62,12.78 17,11.44 17,10S16.62,7.22 15.95,6.05z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M12,10l1.69,1.69C13.88,11.16 14,10.6 14,10s-0.12,-1.16 -0.31,-1.69L12,10z"/>
-</vector>
diff --git a/chromium/components/permissions/android/res/drawable/gm_filled_cardboard_20.xml b/chromium/components/permissions/android/res/drawable/gm_filled_cardboard_20.xml
deleted file mode 100644
index 47ef07cf679..00000000000
--- a/chromium/components/permissions/android/res/drawable/gm_filled_cardboard_20.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--Copyright 2021 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.-->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="20dp"
- android:height="20dp"
- android:viewportWidth="20"
- android:viewportHeight="20"
- android:tint="?attr/colorControlNormal">
- <path
- android:fillColor="@android:color/white"
- android:pathData="M15.5,5.5h-11C3.67,5.5 3,6.18 3,7v6c0,0.82 0.67,1.5 1.5,1.5h3.19c0.56,0 1.08,-0.31 1.33,-0.81l0.62,-1.21c0.15,-0.28 0.54,-0.31 0.71,0l0.63,1.21c0.26,0.5 0.77,0.81 1.33,0.81h3.19c0.83,0 1.5,-0.68 1.5,-1.5V7C17,6.18 16.33,5.5 15.5,5.5zM6.5,11.5C5.67,11.5 5,10.82 5,10s0.67,-1.5 1.5,-1.5C7.32,8.5 8,9.18 8,10S7.32,11.5 6.5,11.5zM13.5,11.5c-0.83,0 -1.5,-0.68 -1.5,-1.5s0.67,-1.5 1.5,-1.5c0.82,0 1.5,0.68 1.5,1.5S14.32,11.5 13.5,11.5z"/>
-</vector>
diff --git a/chromium/components/permissions/android/res/drawable/gm_filled_content_paste_20.xml b/chromium/components/permissions/android/res/drawable/gm_filled_content_paste_20.xml
deleted file mode 100644
index 9107ea7b58e..00000000000
--- a/chromium/components/permissions/android/res/drawable/gm_filled_content_paste_20.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--Copyright 2021 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.-->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="20dp"
- android:height="20dp"
- android:viewportWidth="20"
- android:viewportHeight="20"
- android:tint="?attr/colorControlNormal">
- <path
- android:fillColor="@android:color/white"
- android:pathData="M15.5,3h-3.57c-0.22,-0.86 -1,-1.5 -1.93,-1.5C9.07,1.5 8.29,2.14 8.07,3H4.5C3.67,3 3,3.67 3,4.5v11C3,16.33 3.67,17 4.5,17h11c0.83,0 1.5,-0.67 1.5,-1.5v-11C17,3.67 16.33,3 15.5,3zM10.75,3.75c0,0.41 -0.34,0.75 -0.75,0.75S9.25,4.16 9.25,3.75C9.25,3.34 9.59,3 10,3S10.75,3.34 10.75,3.75zM15.5,15.5h-11v-11H6V7h8V4.5h1.5V15.5z"/>
-</vector>
diff --git a/chromium/components/permissions/android/res/drawable/gm_filled_devices_20.xml b/chromium/components/permissions/android/res/drawable/gm_filled_devices_20.xml
deleted file mode 100644
index 7186ad350b6..00000000000
--- a/chromium/components/permissions/android/res/drawable/gm_filled_devices_20.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--Copyright 2021 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.-->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="20dp"
- android:height="20dp"
- android:viewportWidth="20"
- android:viewportHeight="20"
- android:tint="?attr/colorControlNormal">
- <path
- android:fillColor="@android:color/white"
- android:pathData="M5.5,5.5H17V4H5.5C4.67,4 4,4.67 4,5.5V14H2v2h8v-2H5.5V5.5z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M17,7h-4c-0.55,0 -1,0.45 -1,1v7c0,0.55 0.45,1 1,1h4c0.55,0 1,-0.45 1,-1V8C18,7.45 17.55,7 17,7zM16.5,14h-3V8.5h3V14z"/>
-</vector>
diff --git a/chromium/components/permissions/android/res/drawable/gm_filled_location_on_20.xml b/chromium/components/permissions/android/res/drawable/gm_filled_location_on_20.xml
deleted file mode 100644
index ec2b90db9c9..00000000000
--- a/chromium/components/permissions/android/res/drawable/gm_filled_location_on_20.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--Copyright 2021 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.-->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="20dp"
- android:height="20dp"
- android:viewportWidth="20"
- android:viewportHeight="20"
- android:tint="?attr/colorControlNormal">
- <path
- android:fillColor="@android:color/white"
- android:pathData="M10,2C6.91,2 4.4,4.51 4.4,7.6c0,4.27 3.37,5.43 4.83,9.83C9.34,17.76 9.64,18 10,18s0.66,-0.24 0.77,-0.57c1.46,-4.4 4.83,-5.56 4.83,-9.83C15.6,4.51 13.09,2 10,2zM10,9.6c-1.1,0 -2,-0.9 -2,-2c0,-1.1 0.9,-2 2,-2s2,0.9 2,2C12,8.7 11.1,9.6 10,9.6z"/>
-</vector>
diff --git a/chromium/components/permissions/android/res/drawable/gm_filled_mic_20.xml b/chromium/components/permissions/android/res/drawable/gm_filled_mic_20.xml
deleted file mode 100644
index 844121644a2..00000000000
--- a/chromium/components/permissions/android/res/drawable/gm_filled_mic_20.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--Copyright 2021 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.-->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="20dp"
- android:height="20dp"
- android:viewportWidth="20"
- android:viewportHeight="20"
- android:tint="?attr/colorControlNormal">
- <path
- android:fillColor="@android:color/white"
- android:pathData="M15.5,9.5H14c0,2.21 -1.79,4 -4,4s-4,-1.79 -4,-4H4.5c0,2.78 2.07,5.08 4.75,5.44V17h1.5v-2.06C13.43,14.58 15.5,12.28 15.5,9.5z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M10,12c1.38,0 2.5,-1.12 2.5,-2.5v-5C12.5,3.12 11.38,2 10,2S7.5,3.12 7.5,4.5v5C7.5,10.88 8.62,12 10,12z"/>
-</vector>
diff --git a/chromium/components/permissions/android/res/drawable/gm_filled_nfc_20.xml b/chromium/components/permissions/android/res/drawable/gm_filled_nfc_20.xml
deleted file mode 100644
index 07361634312..00000000000
--- a/chromium/components/permissions/android/res/drawable/gm_filled_nfc_20.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--Copyright 2021 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.-->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="20dp"
- android:height="20dp"
- android:viewportWidth="20"
- android:viewportHeight="20"
- android:tint="?attr/colorControlNormal">
- <path
- android:fillColor="@android:color/white"
- android:pathData="M3,4.5v11C3,16.33 3.67,17 4.5,17h11c0.83,0 1.5,-0.67 1.5,-1.5v-11C17,3.67 16.33,3 15.5,3h-11C3.67,3 3,3.67 3,4.5zM15.5,15.5h-11v-11h11V15.5z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M14,6h-3.75c-0.55,0 -1,0.45 -1,1v0.5v1.21C8.8,8.97 8.5,9.45 8.5,10c0,0.83 0.67,1.5 1.5,1.5s1.5,-0.67 1.5,-1.5c0,-0.55 -0.3,-1.03 -0.75,-1.29V7.5h1.75v5h-5v-5h0.75V6H6v8h8V6z"/>
-</vector>
diff --git a/chromium/components/permissions/android/res/drawable/gm_filled_notifications_20.xml b/chromium/components/permissions/android/res/drawable/gm_filled_notifications_20.xml
deleted file mode 100644
index b697cdaf64c..00000000000
--- a/chromium/components/permissions/android/res/drawable/gm_filled_notifications_20.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--Copyright 2021 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.-->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="20dp"
- android:height="20dp"
- android:viewportWidth="20"
- android:viewportHeight="20"
- android:tint="?attr/colorControlNormal">
- <path
- android:fillColor="@android:color/white"
- android:pathData="M15,14V9c0,-2.42 -1.72,-4.44 -4,-4.9V3c0,-0.55 -0.45,-1 -1,-1S9,2.45 9,3v1.1C6.72,4.56 5,6.58 5,9v5H4v1.5h12V14H15z"/>
- <path
- android:fillColor="@android:color/white"
- android:pathData="M10,18c0.83,0 1.5,-0.67 1.5,-1.5h-3C8.5,17.33 9.17,18 10,18z"/>
-</vector>
diff --git a/chromium/components/permissions/android/res/drawable/gm_filled_piano_20.xml b/chromium/components/permissions/android/res/drawable/gm_filled_piano_20.xml
deleted file mode 100644
index b1696f030ef..00000000000
--- a/chromium/components/permissions/android/res/drawable/gm_filled_piano_20.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--Copyright 2021 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.-->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="20dp"
- android:height="20dp"
- android:viewportWidth="20"
- android:viewportHeight="20"
- android:tint="?attr/colorControlNormal">
- <path
- android:fillColor="@android:color/white"
- android:pathData="M15.5,3h-11C3.67,3 3,3.67 3,4.5v11C3,16.33 3.67,17 4.5,17h11c0.83,0 1.5,-0.67 1.5,-1.5v-11C17,3.67 16.33,3 15.5,3zM7,15.5H4.5v-11H6v7C6,11.78 6.22,12 6.5,12H7V15.5zM12,15.5H8V12h0.5C8.78,12 9,11.78 9,11.5v-7h2v7c0,0.28 0.22,0.5 0.5,0.5H12V15.5zM15.5,15.5H13V12h0.5c0.28,0 0.5,-0.22 0.5,-0.5v-7h1.5V15.5z"/>
-</vector>
diff --git a/chromium/components/permissions/android/res/drawable/gm_filled_usb_20.xml b/chromium/components/permissions/android/res/drawable/gm_filled_usb_20.xml
deleted file mode 100644
index cadc91a243e..00000000000
--- a/chromium/components/permissions/android/res/drawable/gm_filled_usb_20.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--Copyright 2021 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.-->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="20dp"
- android:height="20dp"
- android:viewportWidth="20"
- android:viewportHeight="20"
- android:tint="?attr/colorControlNormal">
- <path
- android:fillColor="@android:color/white"
- android:pathData="M15.5,7h-3v3h0.75v1.5h-2.5V5h1.75L10,2L7.5,5h1.75v6.5h-2.5V9.79C7.2,9.53 7.5,9.05 7.5,8.5C7.5,7.67 6.83,7 6,7S4.5,7.67 4.5,8.5c0,0.55 0.3,1.03 0.75,1.29v1.71c0,0.83 0.67,1.5 1.5,1.5h2.5v2.21C8.8,15.47 8.5,15.95 8.5,16.5c0,0.83 0.67,1.5 1.5,1.5s1.5,-0.67 1.5,-1.5c0,-0.55 -0.3,-1.03 -0.75,-1.29V13h2.5c0.83,0 1.5,-0.67 1.5,-1.5V10h0.75V7z"/>
-</vector>
diff --git a/chromium/components/permissions/android/res/drawable/gm_filled_videocam_20.xml b/chromium/components/permissions/android/res/drawable/gm_filled_videocam_20.xml
deleted file mode 100644
index 113af32f3b5..00000000000
--- a/chromium/components/permissions/android/res/drawable/gm_filled_videocam_20.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--Copyright 2021 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.-->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="20dp"
- android:height="20dp"
- android:viewportWidth="20"
- android:viewportHeight="20"
- android:tint="?attr/colorControlNormal">
- <path
- android:fillColor="@android:color/white"
- android:pathData="M15,9V5.5C15,4.67 14.33,4 13.5,4h-9C3.67,4 3,4.67 3,5.5v9C3,15.33 3.67,16 4.5,16h9c0.83,0 1.5,-0.67 1.5,-1.5V11l3,3V6L15,9z"/>
-</vector>
diff --git a/chromium/components/permissions/android/res/layout/bluetooth_scanning_permission_dialog.xml b/chromium/components/permissions/android/res/layout/bluetooth_scanning_permission_dialog.xml
index 778e2e10c08..d104fbe1683 100644
--- a/chromium/components/permissions/android/res/layout/bluetooth_scanning_permission_dialog.xml
+++ b/chromium/components/permissions/android/res/layout/bluetooth_scanning_permission_dialog.xml
@@ -11,7 +11,7 @@
android:orientation="vertical"
android:paddingBottom="12dp"
android:paddingTop="20dp"
- android:background="@color/sheet_bg_color">
+ android:background="@drawable/sheet_background">
<include layout="@layout/device_item_list" />
diff --git a/chromium/components/permissions/android/res/layout/item_chooser_dialog.xml b/chromium/components/permissions/android/res/layout/item_chooser_dialog.xml
index 78e581984c7..a63af7bc16d 100644
--- a/chromium/components/permissions/android/res/layout/item_chooser_dialog.xml
+++ b/chromium/components/permissions/android/res/layout/item_chooser_dialog.xml
@@ -10,7 +10,7 @@
android:orientation="vertical"
android:paddingBottom="12dp"
android:paddingTop="20dp"
- android:background="@color/sheet_bg_color">
+ android:background="@drawable/sheet_background">
<include layout="@layout/device_item_list" />
diff --git a/chromium/components/permissions/android/translations/permissions_android_strings_as.xtb b/chromium/components/permissions/android/translations/permissions_android_strings_as.xtb
index 13acb22aab7..d8888a61491 100644
--- a/chromium/components/permissions/android/translations/permissions_android_strings_as.xtb
+++ b/chromium/components/permissions/android/translations/permissions_android_strings_as.xtb
@@ -3,7 +3,7 @@
<translationbundle lang="as">
<translation id="1569387923882100876">সংযোজিত ডিভাইচ</translation>
<translation id="1612196535745283361">ডিভাইচ সà§à¦•à§‡à¦¨ কৰিবলৈ Chromeঠঅৱসà§à¦¥à¦¾à¦¨ à¦à¦•à§à¦¸à§‡à¦› কৰাটো পà§à§°à¦¯à¦¼à§‹à¦œà¦¨à§€à¦¯à¦¼à¥¤ à¦à¦‡ ডিভাইচটোৰ বাবে <ph name="BEGIN_LINK" />অৱসà§à¦¥à¦¾à¦¨ à¦à¦•à§à¦¸à§‡à¦› অফ কৰা আছে৷<ph name="END_LINK" /></translation>
-<translation id="1993768208584545658"><ph name="SITE" />ঠযোৰা লগাব বিচাৰে</translation>
+<translation id="1993768208584545658"><ph name="SITE" />ঠপেয়াৰ কৰিব বিচাৰে</translation>
<translation id="2077832278056815832">অনà§à¦¯ à¦à¦ªà§° যিকোনো বাবল অথবা অ’ভাৰলে’ বনà§à¦§ কৰক। তাৰ পাছত পà§à¦¨à§° চেষà§à¦Ÿà¦¾ কৰক।</translation>
<translation id="230115972905494466">খাপ খোৱা কোনো ডিভাইচ বিচাৰি পোৱা নগ’ল</translation>
<translation id="2359808026110333948">অবà§à¦¯à¦¾à¦¹à¦¤ ৰাখক</translation>
@@ -15,7 +15,7 @@
<translation id="5230560987958996918"><ph name="SITE" />ঠনিকটৱৰà§à¦¤à§€ বà§à¦²à§à¦Ÿà§à¦¥ ডিভাইচবোৰ বিচাৰি সà§à¦•à§‡à¦¨ কৰিব বিচাৰে। à¦à¦‡ ডিভাইচকেইটা বিচাৰি পোৱা গৈছে:</translation>
<translation id="5527082711130173040">ডিভাইচ সà§à¦•à§‡à¦¨ কৰিবলৈ Chromeঠঅৱসà§à¦¥à¦¾à¦¨ à¦à¦•à§à¦¸à§‡à¦› কৰাটো পà§à§°à¦¯à¦¼à§‹à¦œà¦¨à§€à¦¯à¦¼à¥¤ <ph name="BEGIN_LINK1" />অনà§à¦®à¦¤à¦¿ আপডে’ট কৰক<ph name="END_LINK1" />। অৱসà§à¦¥à¦¾à¦¨ ইতিহাস <ph name="BEGIN_LINK2" />à¦à¦‡ ডিভাইচটোৰ বাবেও অফ কৰি থোৱা হৈছে<ph name="END_LINK2" />।</translation>
<translation id="557283862590186398">Chromeক à¦à¦‡ ছাইটৰ বাবে আপোনাৰ মাইকà§à§°â€™à¦«â€™à¦¨ বà§à¦¯à§±à¦¹à¦¾à§° কৰিবলৈ অনà§à¦®à¦¤à¦¿à§° আৱশà§à¦¯à¦•à¥¤</translation>
-<translation id="5817918615728894473">যোৰা লগাওক</translation>
+<translation id="5817918615728894473">পেয়াৰ কৰক</translation>
<translation id="5858741533101922242">Chromeঠবà§à¦²à§à¦Ÿà§à¦¥ à¦à¦¡à¦¾à¦ªà§à¦Ÿà§°à¦Ÿà§‹ অন কৰিবলৈ সকà§à¦·à¦® নহ’ল</translation>
<translation id="5860491529813859533">অন কৰক</translation>
<translation id="6092062101542170135">অবà§à¦¯à¦¾à¦¹à¦¤ ৰাখিবলৈ Android ছেটিংসমূহত NFC অন কৰক</translation>
diff --git a/chromium/components/permissions/android/translations/permissions_android_strings_de.xtb b/chromium/components/permissions/android/translations/permissions_android_strings_de.xtb
index 64df4eb7b03..89d111cd74b 100644
--- a/chromium/components/permissions/android/translations/permissions_android_strings_de.xtb
+++ b/chromium/components/permissions/android/translations/permissions_android_strings_de.xtb
@@ -4,25 +4,25 @@
<translation id="1569387923882100876">Verbundenes Gerät</translation>
<translation id="1612196535745283361">Chrome benötigt Zugriff auf den Standort, um nach Geräten suchen zu können. Der Standortzugriff ist <ph name="BEGIN_LINK" />für dieses Gerät deaktiviert<ph name="END_LINK" />.</translation>
<translation id="1993768208584545658"><ph name="SITE" /> möchte eine Kopplung durchführen</translation>
-<translation id="2077832278056815832">Schließen Sie alle Infofelder und Einblendungen anderer Apps. Versuchen Sie es anschließend noch einmal.</translation>
+<translation id="2077832278056815832">Schließe alle Infofelder und Einblendungen anderer Apps. Versuche es anschließend noch einmal.</translation>
<translation id="230115972905494466">Keine kompatiblen Geräte gefunden</translation>
<translation id="2359808026110333948">Weiter</translation>
-<translation id="2416359993254398973">Chrome benötigt für diese Website die Berechtigung, auf Ihre Kamera zuzugreifen.</translation>
-<translation id="2987449669841041897">Diese Website darf nicht nach Ihrer Berechtigung fragen</translation>
+<translation id="2416359993254398973">Chrome benötigt für diese Website die Berechtigung, auf deine Kamera zuzugreifen.</translation>
+<translation id="2987449669841041897">Diese Website darf nicht nach deiner Berechtigung fragen</translation>
<translation id="3036750288708366620"><ph name="BEGIN_LINK" />Hilfe aufrufen<ph name="END_LINK" /></translation>
-<translation id="3773755127849930740"><ph name="BEGIN_LINK" />Aktivieren Sie Bluetooth<ph name="END_LINK" />, um die Kopplung zu ermöglichen</translation>
+<translation id="3773755127849930740"><ph name="BEGIN_LINK" />Aktiviere Bluetooth<ph name="END_LINK" />, um die Kopplung zu ermöglichen</translation>
<translation id="4915549754973153784"><ph name="BEGIN_LINK" />Hilfe aufrufen<ph name="END_LINK" />, während nach Geräten gesucht wird…</translation>
<translation id="5230560987958996918"><ph name="SITE" /> möchte nach Bluetooth-Geräten in der Nähe suchen. Die folgenden Geräte wurden gefunden:</translation>
<translation id="5527082711130173040">Chrome benötigt Zugriff auf den Standort, um nach Geräten suchen zu können. <ph name="BEGIN_LINK1" />Berechtigungen aktualisieren.<ph name="END_LINK1" /> Außerdem ist der Standortzugriff <ph name="BEGIN_LINK2" />für dieses Gerät deaktiviert<ph name="END_LINK2" />.</translation>
-<translation id="557283862590186398">Chrome benötigt für diese Website die Berechtigung, auf Ihr Mikrofon zuzugreifen.</translation>
+<translation id="557283862590186398">Chrome benötigt für diese Website die Berechtigung, auf dein Mikrofon zuzugreifen.</translation>
<translation id="5817918615728894473">Koppeln</translation>
<translation id="5858741533101922242">Chrome kann den Bluetooth-Adapter nicht aktivieren</translation>
<translation id="5860491529813859533">Aktivieren</translation>
-<translation id="6092062101542170135">Aktivieren Sie zum Fortfahren NFC in den Android-Einstellungen</translation>
-<translation id="6393863479814692971">Chrome benötigt für diese Website die Berechtigung, auf Ihre Kamera und Ihr Mikrofon zuzugreifen.</translation>
+<translation id="6092062101542170135">Aktiviere zum Fortfahren NFC in den Android-Einstellungen</translation>
+<translation id="6393863479814692971">Chrome benötigt für diese Website die Berechtigung, auf deine Kamera und dein Mikrofon zuzugreifen.</translation>
<translation id="6656545060687952787">Chrome benötigt Zugriff auf den Standort, um nach Geräten suchen zu können. <ph name="BEGIN_LINK" />Berechtigungen aktualisieren<ph name="END_LINK" /></translation>
-<translation id="6697947395630195233">Chrome benötigt Zugriff auf Ihren Standort, um ihn mit dieser Website zu teilen.</translation>
-<translation id="7134415045456331657">Chrome benötigt Zugriff auf die Kamera, um eine 3D-Karte Ihrer Umgebung zu erstellen.</translation>
+<translation id="6697947395630195233">Chrome benötigt Zugriff auf deinen Standort, um ihn mit dieser Website zu teilen.</translation>
+<translation id="7134415045456331657">Chrome benötigt Zugriff auf die Kamera, um eine 3D-Karte deiner Umgebung zu erstellen.</translation>
<translation id="7624880197989616768"><ph name="BEGIN_LINK1" />Hilfe aufrufen<ph name="END_LINK1" /> oder <ph name="BEGIN_LINK2" />noch einmal suchen<ph name="END_LINK2" /></translation>
<translation id="7884346424584885269">Chrome benötigt die Berechtigung, nach Geräten in der Nähe zu suchen. <ph name="BEGIN_LINK" />Berechtigungen aktualisieren<ph name="END_LINK" /></translation>
<translation id="8368027906805972958">Unbekanntes oder nicht unterstütztes Gerät (<ph name="DEVICE_ID" />)</translation>
diff --git a/chromium/components/permissions/android/translations/permissions_android_strings_it.xtb b/chromium/components/permissions/android/translations/permissions_android_strings_it.xtb
index 24c56f463b8..0bf64cd4f90 100644
--- a/chromium/components/permissions/android/translations/permissions_android_strings_it.xtb
+++ b/chromium/components/permissions/android/translations/permissions_android_strings_it.xtb
@@ -26,6 +26,6 @@
<translation id="7624880197989616768"><ph name="BEGIN_LINK1" />Richiedi assistenza<ph name="END_LINK1" /> o <ph name="BEGIN_LINK2" />ripeti la ricerca<ph name="END_LINK2" /></translation>
<translation id="7884346424584885269">Chrome ha bisogno dell'autorizzazione per cercare dispositivi nelle vicinanze. <ph name="BEGIN_LINK" />Aggiorna autorizzazioni<ph name="END_LINK" />.</translation>
<translation id="8368027906805972958">Dispositivo sconosciuto o non supportato (<ph name="DEVICE_ID" />)</translation>
-<translation id="8687353297350450808">{N_BARS,plural, =1{Intensità del segnale: # barra}one{Signal Strength Level: # bars}other{Intensità del segnale: # barre}}</translation>
+<translation id="8687353297350450808">{N_BARS,plural, =1{Intensità del segnale: # barra}other{Intensità del segnale: # barre}}</translation>
<translation id="9133703968756164531"><ph name="ITEM_NAME" /> (<ph name="ITEM_ID" />)</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/permissions/android/translations/permissions_android_strings_ne.xtb b/chromium/components/permissions/android/translations/permissions_android_strings_ne.xtb
index 1bbc344f9bb..4977a198102 100644
--- a/chromium/components/permissions/android/translations/permissions_android_strings_ne.xtb
+++ b/chromium/components/permissions/android/translations/permissions_android_strings_ne.xtb
@@ -10,15 +10,15 @@
<translation id="2416359993254398973">यो साइटका लागि Chrome लाई तपाईंको कà¥à¤¯à¤®à¥‡à¤°à¤¾à¤®à¤¾à¤¥à¤¿ पहà¥à¤à¤š राखà¥à¤¨ अनà¥à¤®à¤¤à¤¿ आवशà¥à¤¯à¤• हà¥à¤¨à¥à¤›à¥¤</translation>
<translation id="2987449669841041897">यो साइट तपाईंको अनà¥à¤®à¤¤à¤¿ मागà¥à¤¨ सकà¥à¤¦à¥ˆà¤¨</translation>
<translation id="3036750288708366620"><ph name="BEGIN_LINK" />मदà¥à¤¦à¤¤ पà¥à¤°à¤¾à¤ªà¥à¤¤ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥<ph name="END_LINK" /></translation>
-<translation id="3773755127849930740">जोडा बनाउने पà¥à¤°à¤•à¥à¤°à¤¿à¤¯à¤¾à¤²à¤¾à¤ˆ अनà¥à¤®à¤¤à¤¿ दिन <ph name="BEGIN_LINK" />बà¥à¤²à¥à¤Ÿà¥à¤¥<ph name="END_LINK" /> लाई सकà¥à¤°à¤¿à¤¯ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
+<translation id="3773755127849930740">जोडा बनाउने पà¥à¤°à¤•à¥à¤°à¤¿à¤¯à¤¾à¤²à¤¾à¤ˆ अनà¥à¤®à¤¤à¤¿ दिन <ph name="BEGIN_LINK" />बà¥à¤²à¥à¤Ÿà¥à¤¥<ph name="END_LINK" /> लाई अन गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="4915549754973153784">अनà¥à¤¯ यनà¥à¤¤à¥à¤°à¤¹à¤°à¥‚लाई सà¥à¤•à¥à¤¯à¤¾à¤¨ गरà¥à¤¦à¤¾ <ph name="BEGIN_LINK" />मदà¥à¤¦à¤¤ पà¥à¤°à¤¾à¤ªà¥à¤¤ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥<ph name="END_LINK" />…</translation>
<translation id="5230560987958996918"><ph name="SITE" /> वरपरका बà¥à¤²à¥à¤Ÿà¥à¤¥ यनà¥à¤¤à¥à¤°à¤¹à¤°à¥‚ खोजà¥à¤¨ सà¥à¤•à¥à¤¯à¤¾à¤¨ गरà¥à¤¨ चाहनà¥à¤›à¥¤ निमà¥à¤¨ यनà¥à¤¤à¥à¤°à¤¹à¤°à¥‚ फेला परेका छनà¥:</translation>
<translation id="5527082711130173040">यनà¥à¤¤à¥à¤°à¤¹à¤°à¥‚ सà¥à¤•à¥à¤¯à¤¾à¤¨ गरà¥à¤¨ Chrome लाई सà¥à¤¥à¤¾à¤¨ माथिको पहà¥à¤à¤š चाहिनà¥à¤›à¥¤ <ph name="BEGIN_LINK1" />अनà¥à¤®à¤¤à¤¿à¤¹à¤°à¥‚लाई अपडेट गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥<ph name="END_LINK1" />। यो डिभाइसमा सà¥à¤¥à¤¾à¤¨ माथिको पहà¥à¤à¤šà¤²à¤¾à¤ˆ पनि <ph name="BEGIN_LINK2" />निषà¥à¤•à¥à¤°à¤¿à¤¯ पारिà¤à¤•à¥‹ छ<ph name="END_LINK2" />।</translation>
<translation id="557283862590186398">यो साइटका लागि Chrome लाई तपाईंको माइकà¥à¤°à¥‹à¤«à¥‹à¤¨à¤®à¤¾à¤¥à¤¿ पहà¥à¤à¤š राखà¥à¤¨ अनà¥à¤®à¤¤à¤¿ आवशà¥à¤¯à¤• हà¥à¤¨à¥à¤›à¥¤</translation>
<translation id="5817918615728894473">जोडा बनाउनà¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="5858741533101922242">Chrome ले बà¥à¤²à¥à¤Ÿà¥à¤¥ à¤à¤¡à¤¾à¤ªà¥à¤Ÿà¤°à¤²à¤¾à¤ˆ सकà¥à¤°à¤¿à¤¯ गरà¥à¤¨ सकेन</translation>
-<translation id="5860491529813859533">सकà¥à¤°à¤¿à¤¯ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
-<translation id="6092062101542170135">अगाडि बढà¥à¤¨ Android समà¥à¤¬à¤¨à¥à¤§à¥€ सेटिङमा गई NFC सकà¥à¤°à¤¿à¤¯ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
+<translation id="5860491529813859533">अन गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
+<translation id="6092062101542170135">अगाडि बढà¥à¤¨ Android समà¥à¤¬à¤¨à¥à¤§à¥€ सेटिङमा गई NFC अन गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="6393863479814692971">यो साइटका लागि Chrome लाई तपाईंको कà¥à¤¯à¤¾à¤®à¥‡à¤°à¤¾ र माइकà¥à¤°à¥‹à¤«à¥‹à¤¨à¤®à¤¾à¤¥à¤¿ पहà¥à¤à¤š राखà¥à¤¨ अनà¥à¤®à¤¤à¤¿ आवशà¥à¤¯à¤• हà¥à¤¨à¥à¤›à¥¤</translation>
<translation id="6656545060687952787">Chrome डिभाइसहरूको लागि सà¥à¤•à¥à¤¯à¤¾à¤¨ गरà¥à¤¨ सà¥à¤¥à¤¾à¤¨ पहà¥à¤à¤š आवशà¥à¤¯à¤• छ। <ph name="BEGIN_LINK" /> अनà¥à¤®à¤¤à¤¿à¤¹à¤°à¥‚ अपडेट गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥<ph name="END_LINK" /></translation>
<translation id="6697947395630195233">यो साइटसà¤à¤— तपाईंको सà¥à¤¥à¤¾à¤¨à¤¸à¤®à¥à¤¬à¤¨à¥à¤§à¥€ जानकारी आदान पà¥à¤°à¤¦à¤¾à¤¨ गरà¥à¤¨ Chrome लाई तपाईंको सà¥à¤¥à¤¾à¤¨à¤®à¤¾à¤¥à¤¿à¤•à¥‹ पहà¥à¤à¤š आवशà¥à¤¯à¤• हà¥à¤¨à¥à¤›à¥¤</translation>
diff --git a/chromium/components/permissions/android/translations/permissions_android_strings_pt-PT.xtb b/chromium/components/permissions/android/translations/permissions_android_strings_pt-PT.xtb
index 617bf3dc813..976ecdeb0cd 100644
--- a/chromium/components/permissions/android/translations/permissions_android_strings_pt-PT.xtb
+++ b/chromium/components/permissions/android/translations/permissions_android_strings_pt-PT.xtb
@@ -26,6 +26,6 @@
<translation id="7624880197989616768"><ph name="BEGIN_LINK1" />Obter ajuda<ph name="END_LINK1" /> ou <ph name="BEGIN_LINK2" />voltar a procurar<ph name="END_LINK2" /></translation>
<translation id="7884346424584885269">O Chrome precisa de autorização para procurar dispositivos próximos. <ph name="BEGIN_LINK" />Atualize as autorizações<ph name="END_LINK" /></translation>
<translation id="8368027906805972958">Dispositivo desconhecido ou não suportado (<ph name="DEVICE_ID" />)</translation>
-<translation id="8687353297350450808">{N_BARS,plural, =1{Nível de intensidade do sinal: # barra}one{Nível de intensidade do sinal: # barras}other{Nível de intensidade do sinal: # barras}}</translation>
+<translation id="8687353297350450808">{N_BARS,plural, =1{Nível de intensidade do sinal: # barra}other{Nível de intensidade do sinal: # barras}}</translation>
<translation id="9133703968756164531"><ph name="ITEM_NAME" /> (<ph name="ITEM_ID" />)</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/permissions/android/translations/permissions_android_strings_te.xtb b/chromium/components/permissions/android/translations/permissions_android_strings_te.xtb
index added11fc81..c68317bf417 100644
--- a/chromium/components/permissions/android/translations/permissions_android_strings_te.xtb
+++ b/chromium/components/permissions/android/translations/permissions_android_strings_te.xtb
@@ -22,7 +22,7 @@
<translation id="6393863479814692971">à°ˆ సైటౠకోసం మీ కెమెరా మరియౠమైకà±à°°à±‹à°«à±‹à°¨à±â€Œà°¨à± యాకà±à°¸à±†à°¸à± చేయడానికి Chromeà°•à± à°…à°¨à±à°®à°¤à°¿ అవసరం.</translation>
<translation id="6656545060687952787">పరికరాల కోసం à°¸à±à°•à°¾à°¨à± చేయడానికి Chromeà°•à± à°¸à±à°¥à°¾à°¨ యాకà±à°¸à±†à°¸à± అవసరం. <ph name="BEGIN_LINK" />à°…à°¨à±à°®à°¤à±à°²à°¨à± à°…à°ªà±â€Œà°¡à±‡à°Ÿà± చేయండి<ph name="END_LINK" /></translation>
<translation id="6697947395630195233">à°ˆ సైటà±â€Œà°¤à±‹ మీ à°¸à±à°¥à°¾à°¨à°¾à°¨à±à°¨à°¿ షేరౠచేయడానికి Chromeకౠమీ à°¸à±à°¥à°¾à°¨ యాకà±à°¸à±†à°¸à± అవసరం.</translation>
-<translation id="7134415045456331657">మీ పరిసరాల 3D à°®à±à°¯à°¾à°ªà±â€Œà°¨à± సృషà±à°Ÿà°¿à°‚చడానికి Chromeకౠమీ కెమెరానౠయాకà±à°¸à±†à°¸à± చేసే à°…à°¨à±à°®à°¤à°¿ కావాలి.</translation>
+<translation id="7134415045456331657">మీ పరిసరాల 3D à°®à±à°¯à°¾à°ªà±â€Œà°¨à± à°•à±à°°à°¿à°¯à±‡à°Ÿà± చేయడానికి Chromeకౠమీ కెమెరానౠయాకà±à°¸à±†à°¸à± చేసే à°…à°¨à±à°®à°¤à°¿ కావాలి.</translation>
<translation id="7624880197989616768"><ph name="BEGIN_LINK1" />సహాయం పొందండి<ph name="END_LINK1" /> లేదా <ph name="BEGIN_LINK2" />మళà±à°²à±€ à°¸à±à°•à°¾à°¨à± చేయండి<ph name="END_LINK2" /></translation>
<translation id="7884346424584885269">సమీపంలోని పరికరాల కోసం à°¸à±à°•à°¾à°¨à± చేయడానికి Chromeà°•à± à°…à°¨à±à°®à°¤à°¿ అవసరం. <ph name="BEGIN_LINK" />à°…à°¨à±à°®à°¤à±à°²à°¨à± à°…à°ªà±â€Œà°¡à±‡à°Ÿà± చేయండి<ph name="END_LINK" />.</translation>
<translation id="8368027906805972958">తెలియని లేదా మదà±à°¦à°¤à± లేని పరికరం (<ph name="DEVICE_ID" />)</translation>
diff --git a/chromium/components/permissions/bluetooth_chooser_controller.cc b/chromium/components/permissions/bluetooth_chooser_controller.cc
index 3590bd510ac..91bbc94d957 100644
--- a/chromium/components/permissions/bluetooth_chooser_controller.cc
+++ b/chromium/components/permissions/bluetooth_chooser_controller.cc
@@ -7,6 +7,7 @@
#include <algorithm>
#include "base/check_op.h"
+#include "base/debug/dump_without_crashing.h"
#include "base/metrics/histogram_macros.h"
#include "base/notreached.h"
#include "base/strings/utf_string_conversions.h"
@@ -79,12 +80,16 @@ bool BluetoothChooserController::IsPaired(size_t index) const {
}
std::u16string BluetoothChooserController::GetOption(size_t index) const {
- DCHECK_LT(index, devices_.size());
+ // Change these back to DCHECKs once https://crbug.com/1292234 is resolved.
+ if (index >= devices_.size())
+ base::debug::DumpWithoutCrashing();
const std::string& device_id = devices_[index].id;
const auto& device_name_it = device_id_to_name_map_.find(device_id);
- DCHECK(device_name_it != device_id_to_name_map_.end());
+ if (device_name_it == device_id_to_name_map_.end())
+ base::debug::DumpWithoutCrashing();
const auto& it = device_name_counts_.find(device_name_it->second);
- DCHECK(it != device_name_counts_.end());
+ if (it == device_name_counts_.end())
+ base::debug::DumpWithoutCrashing();
return it->second == 1
? device_name_it->second
: l10n_util::GetStringFUTF16(
diff --git a/chromium/components/permissions/chooser_title_util.cc b/chromium/components/permissions/chooser_title_util.cc
index fdce3bc108f..4c2fb4e1399 100644
--- a/chromium/components/permissions/chooser_title_util.cc
+++ b/chromium/components/permissions/chooser_title_util.cc
@@ -15,11 +15,10 @@ std::u16string CreateChooserTitle(content::RenderFrameHost* render_frame_host,
int title_string_id_origin) {
if (!render_frame_host)
return u"";
-
return l10n_util::GetStringFUTF16(
title_string_id_origin,
url_formatter::FormatOriginForSecurityDisplay(
- render_frame_host->GetLastCommittedOrigin(),
+ render_frame_host->GetMainFrame()->GetLastCommittedOrigin(),
url_formatter::SchemeDisplay::OMIT_CRYPTOGRAPHIC));
}
diff --git a/chromium/components/permissions/chooser_title_util.h b/chromium/components/permissions/chooser_title_util.h
index 2ec034245f4..a0b694f2e66 100644
--- a/chromium/components/permissions/chooser_title_util.h
+++ b/chromium/components/permissions/chooser_title_util.h
@@ -13,8 +13,9 @@ class RenderFrameHost;
namespace permissions {
-// Creates a title for a chooser using the origin of the frame. Returns the
-// empty string if |render_frame_host| is null.
+// Creates a title for a chooser using the origin of the main frame
+// containing `render_frame_host`. Returns the empty string if
+// `render_frame_host` is null.
std::u16string CreateChooserTitle(content::RenderFrameHost* render_frame_host,
int title_string_id_origin);
diff --git a/chromium/components/permissions/chooser_title_util_unittest.cc b/chromium/components/permissions/chooser_title_util_unittest.cc
new file mode 100644
index 00000000000..ae66385b2ad
--- /dev/null
+++ b/chromium/components/permissions/chooser_title_util_unittest.cc
@@ -0,0 +1,41 @@
+// Copyright 2022 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.
+
+#include "components/permissions/chooser_title_util.h"
+
+#include "components/strings/grit/components_strings.h"
+#include "content/public/test/navigation_simulator.h"
+#include "content/public/test/test_renderer_host.h"
+#include "url/gurl.h"
+#include "url/origin.h"
+
+namespace permissions {
+namespace {
+
+constexpr int kTitleResourceId = IDS_USB_DEVICE_CHOOSER_PROMPT_ORIGIN;
+
+using ChooserTitleTest = content::RenderViewHostTestHarness;
+
+TEST_F(ChooserTitleTest, NoFrame) {
+ EXPECT_EQ(u"", CreateChooserTitle(nullptr, kTitleResourceId));
+}
+
+TEST_F(ChooserTitleTest, FrameTree) {
+ NavigateAndCommit(GURL("https://main-frame.com"));
+ content::RenderFrameHost* subframe =
+ content::NavigationSimulator::NavigateAndCommitFromDocument(
+ GURL("https://sub-frame.com"),
+ content::RenderFrameHostTester::For(main_rfh())
+ ->AppendChild("subframe"));
+
+ EXPECT_EQ("main-frame.com", main_rfh()->GetLastCommittedOrigin().host());
+ EXPECT_EQ(u"main-frame.com wants to connect",
+ CreateChooserTitle(main_rfh(), kTitleResourceId));
+ EXPECT_EQ("sub-frame.com", subframe->GetLastCommittedOrigin().host());
+ EXPECT_EQ(u"main-frame.com wants to connect",
+ CreateChooserTitle(subframe, kTitleResourceId));
+}
+
+} // namespace
+} // namespace permissions
diff --git a/chromium/components/permissions/contexts/DEPS b/chromium/components/permissions/contexts/DEPS
index 4507688348f..74e6149bfa0 100644
--- a/chromium/components/permissions/contexts/DEPS
+++ b/chromium/components/permissions/contexts/DEPS
@@ -10,3 +10,9 @@ include_rules = [
"+third_party/blink/public/mojom",
"+services/device/public/cpp/geolocation",
]
+
+specific_include_rules = {
+ "window_placement_permission_context\.cc": [
+ "+content/public/browser",
+ ],
+}
diff --git a/chromium/components/permissions/contexts/bluetooth_chooser_context.cc b/chromium/components/permissions/contexts/bluetooth_chooser_context.cc
index f8a839899bd..a2b84457453 100644
--- a/chromium/components/permissions/contexts/bluetooth_chooser_context.cc
+++ b/chromium/components/permissions/contexts/bluetooth_chooser_context.cc
@@ -94,7 +94,7 @@ void AddManufacturerDataTo(
auto& manufacturer_data_list =
*permission_object->FindListKey(kManufacturerDataKey);
for (const auto& manufacturer_data_permission :
- manufacturer_data_list.GetList()) {
+ manufacturer_data_list.GetListDeprecated()) {
manufacturer_data_set.insert(
static_cast<uint16_t>(manufacturer_data_permission.GetInt()));
}
@@ -289,7 +289,8 @@ bool BluetoothChooserContext::IsAllowedToAccessManufacturerData(
if (!manufacturer_data_list)
return false;
- for (const auto& manufacturer_data : manufacturer_data_list->GetList()) {
+ for (const auto& manufacturer_data :
+ manufacturer_data_list->GetListDeprecated()) {
if (manufacturer_code == manufacturer_data.GetInt())
return true;
}
diff --git a/chromium/components/permissions/contexts/geolocation_permission_context.h b/chromium/components/permissions/contexts/geolocation_permission_context.h
index b79d0425774..7463e472071 100644
--- a/chromium/components/permissions/contexts/geolocation_permission_context.h
+++ b/chromium/components/permissions/contexts/geolocation_permission_context.h
@@ -40,7 +40,7 @@ class GeolocationPermissionContext : public PermissionContextBase {
BrowserPermissionCallback* callback,
GeolocationPermissionContext* context) = 0;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Returns whether or not this |web_contents| is interactable.
virtual bool IsInteractable(content::WebContents* web_contents) = 0;
@@ -50,11 +50,6 @@ class GeolocationPermissionContext : public PermissionContextBase {
// Returns whether |requesting_origin| is the default search engine.
virtual bool IsRequestingOriginDSE(content::BrowserContext* browser_context,
const GURL& requesting_origin) = 0;
-
- // Called after NotifyPermissionSet() has been called from this context.
- virtual void FinishNotifyPermissionSet(const PermissionRequestID& id,
- const GURL& requesting_origin,
- const GURL& embedding_origin) = 0;
#endif
};
diff --git a/chromium/components/permissions/contexts/geolocation_permission_context_android.cc b/chromium/components/permissions/contexts/geolocation_permission_context_android.cc
index bad41e68f3a..42d8f072991 100644
--- a/chromium/components/permissions/contexts/geolocation_permission_context_android.cc
+++ b/chromium/components/permissions/contexts/geolocation_permission_context_android.cc
@@ -307,7 +307,7 @@ void GeolocationPermissionContextAndroid::UpdateLocationSettingsBackOff(
break;
case LocationSettingsDialogBackOff::kOneMonth:
backoff_level = LocationSettingsDialogBackOff::kThreeMonths;
- FALLTHROUGH;
+ [[fallthrough]];
case LocationSettingsDialogBackOff::kThreeMonths:
next_show += base::Days(90);
break;
@@ -427,8 +427,6 @@ void GeolocationPermissionContextAndroid::FinishNotifyPermissionSet(
GeolocationPermissionContext::NotifyPermissionSet(
id, requesting_origin, embedding_origin, std::move(callback), persist,
content_setting, /*is_one_time=*/false);
-
- delegate_->FinishNotifyPermissionSet(id, requesting_origin, embedding_origin);
}
void GeolocationPermissionContextAndroid::SetLocationSettingsForTesting(
diff --git a/chromium/components/permissions/contexts/geolocation_permission_context_unittest.cc b/chromium/components/permissions/contexts/geolocation_permission_context_unittest.cc
index 6664fb1fbea..6241238006e 100644
--- a/chromium/components/permissions/contexts/geolocation_permission_context_unittest.cc
+++ b/chromium/components/permissions/contexts/geolocation_permission_context_unittest.cc
@@ -56,7 +56,7 @@
#include "content/public/test/web_contents_tester.h"
#include "testing/gtest/include/gtest/gtest.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "components/location/android/location_settings_dialog_outcome.h"
#include "components/location/android/mock_location_settings.h"
#include "components/permissions/contexts/geolocation_permission_context_android.h"
@@ -64,7 +64,7 @@
#include "content/public/browser/permission_type.h"
#endif
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
#include "components/permissions/contexts/geolocation_permission_context_mac.h"
#include "services/device/public/cpp/test/fake_geolocation_manager.h"
#endif
@@ -81,7 +81,7 @@ class TestGeolocationPermissionContextDelegate
public:
explicit TestGeolocationPermissionContextDelegate(
content::BrowserContext* browser_context) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
GeolocationPermissionContextAndroid::RegisterProfilePrefs(
prefs_.registry());
#endif
@@ -96,7 +96,7 @@ class TestGeolocationPermissionContextDelegate
return false;
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
bool IsInteractable(content::WebContents* web_contents) override {
return true;
}
@@ -110,10 +110,6 @@ class TestGeolocationPermissionContextDelegate
return dse_origin_ &&
dse_origin_.value() == url::Origin::Create(requesting_origin);
}
-
- void FinishNotifyPermissionSet(const PermissionRequestID& id,
- const GURL& requesting_origin,
- const GURL& embedding_origin) override {}
#endif
void SetDSEOriginForTesting(const url::Origin& dse_origin) {
@@ -161,7 +157,7 @@ class GeolocationPermissionContextTests
const ContentSettingsPattern& secondary_pattern,
ContentSettingsTypeSet content_type_set) override;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
bool RequestPermissionIsLSDShown(const GURL& origin);
bool RequestPermissionIsLSDShownWithPermissionPrompt(const GURL& origin);
void AddDayOffsetForTesting(int days);
@@ -191,7 +187,7 @@ class GeolocationPermissionContextTests
mock_permission_prompt_factories_;
std::unique_ptr<PermissionManager> manager_;
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
std::unique_ptr<device::FakeGeolocationManager> fake_geolocation_manager_;
#endif
@@ -315,7 +311,7 @@ void GeolocationPermissionContextTests::SetUp() {
browser_context());
delegate_ = delegate.get();
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
auto context = std::make_unique<GeolocationPermissionContextAndroid>(
browser_context(), std::move(delegate));
context->SetLocationSettingsForTesting(
@@ -325,7 +321,7 @@ void GeolocationPermissionContextTests::SetUp() {
MockLocationSettings::SetLocationSettingsDialogStatus(false /* enabled */,
GRANTED);
MockLocationSettings::ClearHasShownLocationSettingsDialog();
-#elif defined(OS_MAC)
+#elif BUILDFLAG(IS_MAC)
fake_geolocation_manager_ =
std::make_unique<device::FakeGeolocationManager>();
fake_geolocation_manager_->SetSystemPermission(
@@ -368,7 +364,7 @@ void GeolocationPermissionContextTests::SetupRequestManager(
permission_request_manager));
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
bool GeolocationPermissionContextTests::RequestPermissionIsLSDShown(
const GURL& origin) {
@@ -406,7 +402,7 @@ void GeolocationPermissionContextTests::RequestManagerDocumentLoadCompleted() {
void GeolocationPermissionContextTests::RequestManagerDocumentLoadCompleted(
content::WebContents* web_contents) {
PermissionRequestManager::FromWebContents(web_contents)
- ->DocumentOnLoadCompletedInMainFrame(main_rfh());
+ ->DocumentOnLoadCompletedInPrimaryMainFrame();
}
ContentSetting GeolocationPermissionContextTests::GetGeolocationContentSetting(
@@ -468,7 +464,7 @@ std::u16string GeolocationPermissionContextTests::GetPromptText() {
PermissionRequestManager* manager =
PermissionRequestManager::FromWebContents(web_contents());
PermissionRequest* request = manager->Requests().front();
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
return request->GetDialogMessageText();
#else
return base::ASCIIToUTF16(request->requesting_origin().spec()) +
@@ -501,7 +497,7 @@ TEST_F(GeolocationPermissionContextTests,
ASSERT_FALSE(HasActivePrompt());
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Tests concerning Android location settings permission
TEST_F(GeolocationPermissionContextTests, GeolocationEnabledDisabled) {
GURL requesting_frame("https://www.example.com/geolocation");
@@ -1033,7 +1029,7 @@ TEST_F(GeolocationPermissionContextTests, TabDestroyed) {
GetGeolocationContentSetting(requesting_frame, requesting_frame));
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
TEST_F(GeolocationPermissionContextTests, GeolocationStatusAndroidDisabled) {
GURL requesting_frame("https://www.example.com/geolocation");
@@ -1110,9 +1106,9 @@ TEST_F(GeolocationPermissionContextTests, GeolocationStatusSystemDisabled) {
manager_->GetPermissionStatus(content::PermissionType::GEOLOCATION,
requesting_frame, requesting_frame));
}
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
TEST_F(GeolocationPermissionContextTests,
AllSystemAndSitePermissionCombinations) {
GURL requesting_frame("https://www.example.com/geolocation");
diff --git a/chromium/components/permissions/contexts/nfc_permission_context.cc b/chromium/components/permissions/contexts/nfc_permission_context.cc
index f46cadb07e8..efda9258313 100644
--- a/chromium/components/permissions/contexts/nfc_permission_context.cc
+++ b/chromium/components/permissions/contexts/nfc_permission_context.cc
@@ -4,6 +4,7 @@
#include "components/permissions/contexts/nfc_permission_context.h"
+#include "build/build_config.h"
#include "components/content_settings/browser/page_specific_content_settings.h"
#include "components/permissions/permission_request_id.h"
#include "third_party/blink/public/mojom/permissions_policy/permissions_policy_feature.mojom.h"
@@ -20,7 +21,7 @@ NfcPermissionContext::NfcPermissionContext(
NfcPermissionContext::~NfcPermissionContext() = default;
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
ContentSetting NfcPermissionContext::GetPermissionStatusInternal(
content::RenderFrameHost* render_frame_host,
const GURL& requesting_origin,
diff --git a/chromium/components/permissions/contexts/nfc_permission_context.h b/chromium/components/permissions/contexts/nfc_permission_context.h
index e3fa626862a..8c52b53d915 100644
--- a/chromium/components/permissions/contexts/nfc_permission_context.h
+++ b/chromium/components/permissions/contexts/nfc_permission_context.h
@@ -17,7 +17,7 @@ class NfcPermissionContext : public PermissionContextBase {
public:
virtual ~Delegate() = default;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Returns whether or not this |web_contents| is interactable.
virtual bool IsInteractable(content::WebContents* web_contents) = 0;
#endif
@@ -36,7 +36,7 @@ class NfcPermissionContext : public PermissionContextBase {
private:
// PermissionContextBase:
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
ContentSetting GetPermissionStatusInternal(
content::RenderFrameHost* render_frame_host,
const GURL& requesting_origin,
diff --git a/chromium/components/permissions/contexts/nfc_permission_context_unittest.cc b/chromium/components/permissions/contexts/nfc_permission_context_unittest.cc
index 03c50e576b0..e5762016a87 100644
--- a/chromium/components/permissions/contexts/nfc_permission_context_unittest.cc
+++ b/chromium/components/permissions/contexts/nfc_permission_context_unittest.cc
@@ -17,7 +17,7 @@
#include "content/public/test/test_renderer_host.h"
#include "content/public/test/test_utils.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "components/permissions/android/nfc/mock_nfc_system_level_setting.h"
#include "components/permissions/contexts/nfc_permission_context_android.h"
#endif
@@ -28,7 +28,7 @@ namespace permissions {
namespace {
class TestNfcPermissionContextDelegate : public NfcPermissionContext::Delegate {
public:
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
bool IsInteractable(content::WebContents* web_contents) override {
return true;
}
@@ -138,7 +138,7 @@ void NfcPermissionContextTests::SetUp() {
auto delegate = std::make_unique<TestNfcPermissionContextDelegate>();
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
auto context = std::make_unique<NfcPermissionContextAndroid>(
browser_context(), std::move(delegate));
context->set_nfc_system_level_setting_for_testing(
@@ -183,7 +183,7 @@ void NfcPermissionContextTests::SetupRequestManager(
void NfcPermissionContextTests::RequestManagerDocumentLoadCompleted() {
PermissionRequestManager::FromWebContents(web_contents())
- ->DocumentOnLoadCompletedInMainFrame(web_contents()->GetMainFrame());
+ ->DocumentOnLoadCompletedInPrimaryMainFrame();
}
ContentSetting NfcPermissionContextTests::GetNfcContentSetting(GURL frame_0,
@@ -234,7 +234,7 @@ TEST_F(NfcPermissionContextTests, SinglePermissionPrompt) {
RequestNfcPermission(web_contents(), RequestID(0), requesting_frame,
true /* user_gesture */);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
ASSERT_TRUE(HasActivePrompt());
#else
ASSERT_FALSE(HasActivePrompt());
@@ -251,7 +251,7 @@ TEST_F(NfcPermissionContextTests, SinglePermissionPromptFailsOnInsecureOrigin) {
ASSERT_FALSE(HasActivePrompt());
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Tests concerning Android NFC setting
TEST_F(NfcPermissionContextTests,
SystemNfcSettingDisabledWhenNfcPermissionGetsGranted) {
diff --git a/chromium/components/permissions/contexts/webxr_permission_context.cc b/chromium/components/permissions/contexts/webxr_permission_context.cc
index 4e675d0df93..4dee1e961bf 100644
--- a/chromium/components/permissions/contexts/webxr_permission_context.cc
+++ b/chromium/components/permissions/contexts/webxr_permission_context.cc
@@ -5,9 +5,10 @@
#include "components/permissions/contexts/webxr_permission_context.h"
#include "base/check.h"
+#include "build/build_config.h"
#include "third_party/blink/public/mojom/permissions_policy/permissions_policy.mojom.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "components/permissions/android/android_permission_util.h"
#include "components/permissions/permission_request_id.h"
#include "components/permissions/permissions_client.h"
@@ -32,7 +33,7 @@ bool WebXrPermissionContext::IsRestrictedToSecureOrigins() const {
return true;
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// There are two other permissions that need to check corresponding OS-level
// permissions, and they take two different approaches to this. Geolocation only
// stores the permission ContentSetting if both requests are granted (or if the
@@ -134,5 +135,5 @@ void WebXrPermissionContext::OnAndroidPermissionDecided(
id, requesting_origin, embedding_origin, std::move(callback),
false /*persist*/, setting, /*is_one_time=*/false);
}
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
} // namespace permissions
diff --git a/chromium/components/permissions/contexts/webxr_permission_context.h b/chromium/components/permissions/contexts/webxr_permission_context.h
index 303e5094a3e..596b2ef72f7 100644
--- a/chromium/components/permissions/contexts/webxr_permission_context.h
+++ b/chromium/components/permissions/contexts/webxr_permission_context.h
@@ -23,7 +23,7 @@ class WebXrPermissionContext : public PermissionContextBase {
// PermissionContextBase:
bool IsRestrictedToSecureOrigins() const override;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// On Android we need to do some additional checking for OS level permissions,
// which do not need to happen on Desktop. Note that NotifyPermissionSet is
// only called after a "RequestPermission" call (and not if we are just
diff --git a/chromium/components/permissions/contexts/window_placement_permission_context.cc b/chromium/components/permissions/contexts/window_placement_permission_context.cc
new file mode 100644
index 00000000000..34a7914400e
--- /dev/null
+++ b/chromium/components/permissions/contexts/window_placement_permission_context.cc
@@ -0,0 +1,49 @@
+// Copyright 2020 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.
+
+#include "components/permissions/contexts/window_placement_permission_context.h"
+
+#include "components/content_settings/core/common/content_settings_types.h"
+#include "components/permissions/permission_request_id.h"
+#include "content/public/browser/render_frame_host.h"
+#include "third_party/blink/public/mojom/frame/user_activation_notification_type.mojom.h"
+#include "third_party/blink/public/mojom/permissions_policy/permissions_policy.mojom.h"
+
+namespace permissions {
+
+WindowPlacementPermissionContext::WindowPlacementPermissionContext(
+ content::BrowserContext* browser_context)
+ : PermissionContextBase(
+ browser_context,
+ ContentSettingsType::WINDOW_PLACEMENT,
+ blink::mojom::PermissionsPolicyFeature::kWindowPlacement) {}
+
+WindowPlacementPermissionContext::~WindowPlacementPermissionContext() = default;
+
+bool WindowPlacementPermissionContext::IsRestrictedToSecureOrigins() const {
+ return true;
+}
+
+void WindowPlacementPermissionContext::UserMadePermissionDecision(
+ const PermissionRequestID& id,
+ const GURL& requesting_origin,
+ const GURL& embedding_origin,
+ ContentSetting content_setting) {
+ // Notify user activation on the requesting frame if permission was granted,
+ // as transient activation may have expired while the user was responding.
+ // This enables sites to prompt for permission to access multi-screen info and
+ // then immediately request fullscreen or place a window using granted info.
+ if (content_setting == CONTENT_SETTING_ALLOW) {
+ if (auto* render_frame_host = content::RenderFrameHost::FromID(
+ id.render_process_id(), id.render_frame_id())) {
+ render_frame_host->NotifyUserActivation(
+ blink::mojom::UserActivationNotificationType::kInteraction);
+ }
+ }
+
+ PermissionContextBase::UserMadePermissionDecision(
+ id, requesting_origin, embedding_origin, content_setting);
+}
+
+} // namespace permissions
diff --git a/chromium/components/permissions/contexts/window_placement_permission_context.h b/chromium/components/permissions/contexts/window_placement_permission_context.h
new file mode 100644
index 00000000000..7c13ae1afba
--- /dev/null
+++ b/chromium/components/permissions/contexts/window_placement_permission_context.h
@@ -0,0 +1,34 @@
+// Copyright 2020 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.
+
+#ifndef COMPONENTS_PERMISSIONS_CONTEXTS_WINDOW_PLACEMENT_PERMISSION_CONTEXT_H_
+#define COMPONENTS_PERMISSIONS_CONTEXTS_WINDOW_PLACEMENT_PERMISSION_CONTEXT_H_
+
+#include "components/permissions/permission_context_base.h"
+
+namespace permissions {
+
+class WindowPlacementPermissionContext : public PermissionContextBase {
+ public:
+ explicit WindowPlacementPermissionContext(
+ content::BrowserContext* browser_context);
+ ~WindowPlacementPermissionContext() override;
+
+ WindowPlacementPermissionContext(const WindowPlacementPermissionContext&) =
+ delete;
+ WindowPlacementPermissionContext& operator=(
+ const WindowPlacementPermissionContext&) = delete;
+
+ protected:
+ // PermissionContextBase:
+ bool IsRestrictedToSecureOrigins() const override;
+ void UserMadePermissionDecision(const PermissionRequestID& id,
+ const GURL& requesting_origin,
+ const GURL& embedding_origin,
+ ContentSetting content_setting) override;
+};
+
+} // namespace permissions
+
+#endif // COMPONENTS_PERMISSIONS_CONTEXTS_WINDOW_PLACEMENT_PERMISSION_CONTEXT_H_
diff --git a/chromium/components/permissions/features.cc b/chromium/components/permissions/features.cc
index 50b190bbb99..928fea1b49d 100644
--- a/chromium/components/permissions/features.cc
+++ b/chromium/components/permissions/features.cc
@@ -67,12 +67,9 @@ const base::Feature kPermissionPredictionServiceUseUrlOverride{
"kPermissionPredictionServiceUseUrlOverride",
base::FEATURE_DISABLED_BY_DEFAULT};
-#if defined(OS_ANDROID)
-// When enabled, the Default Search Engine does not automatically receive the
-// "geolocation" and "notifications" permissions. DSE only applies to Android.
-const base::Feature kRevertDSEAutomaticPermissions{
- "RevertDSEAutomaticPermissions", base::FEATURE_ENABLED_BY_DEFAULT};
-#endif // defined(OS_ANDROID)
+const base::Feature kPermissionOnDeviceNotificationPredictions{
+ "PermissionOnDeviceNotificationPredictions",
+ base::FEATURE_DISABLED_BY_DEFAULT};
} // namespace features
namespace feature_params {
@@ -90,5 +87,11 @@ const base::FeatureParam<bool> kPermissionPredictionServiceUseJson{
&permissions::features::kPermissionPredictionServiceUseUrlOverride,
"service_use_json", false};
+const base::FeatureParam<double>
+ kPermissionOnDeviceNotificationPredictionsHoldbackChance(
+ &features::kPermissionOnDeviceNotificationPredictions,
+ "holdback_chance",
+ 0.0);
+
} // namespace feature_params
} // namespace permissions
diff --git a/chromium/components/permissions/features.h b/chromium/components/permissions/features.h
index 21b08c177bf..f3eb68bda6d 100644
--- a/chromium/components/permissions/features.h
+++ b/chromium/components/permissions/features.h
@@ -49,10 +49,8 @@ extern const base::Feature kPermissionChipIsProminentStyle;
COMPONENT_EXPORT(PERMISSIONS_COMMON)
extern const base::Feature kPermissionPredictionServiceUseUrlOverride;
-#if defined(OS_ANDROID)
COMPONENT_EXPORT(PERMISSIONS_COMMON)
-extern const base::Feature kRevertDSEAutomaticPermissions;
-#endif // defined(OS_ANDROID)
+extern const base::Feature kPermissionOnDeviceNotificationPredictions;
} // namespace features
namespace feature_params {
@@ -67,6 +65,10 @@ extern const base::FeatureParam<std::string>
COMPONENT_EXPORT(PERMISSIONS_COMMON)
extern const base::FeatureParam<bool> kPermissionPredictionServiceUseJson;
+COMPONENT_EXPORT(PERMISSIONS_COMMON)
+extern const base::FeatureParam<double>
+ kPermissionOnDeviceNotificationPredictionsHoldbackChance;
+
} // namespace feature_params
} // namespace permissions
diff --git a/chromium/components/permissions/object_permission_context_base.cc b/chromium/components/permissions/object_permission_context_base.cc
index eaef35f6f5a..6a9262de1b4 100644
--- a/chromium/components/permissions/object_permission_context_base.cc
+++ b/chromium/components/permissions/object_permission_context_base.cc
@@ -238,12 +238,11 @@ void ObjectPermissionContextBase::NotifyPermissionRevoked(
base::Value ObjectPermissionContextBase::GetWebsiteSetting(
const url::Origin& origin,
content_settings::SettingInfo* info) {
- std::unique_ptr<base::Value> value =
- host_content_settings_map_->GetWebsiteSetting(
- origin.GetURL(), GURL(), data_content_settings_type_, info);
- if (value)
- return base::Value::FromUniquePtrValue(std::move(value));
- return base::Value(base::Value::Type::DICTIONARY);
+ base::Value value = host_content_settings_map_->GetWebsiteSetting(
+ origin.GetURL(), GURL(), data_content_settings_type_, info);
+ if (value.is_none())
+ return base::Value(base::Value::Type::DICTIONARY);
+ return value;
}
void ObjectPermissionContextBase::SaveWebsiteSetting(
@@ -261,7 +260,7 @@ void ObjectPermissionContextBase::SaveWebsiteSetting(
if (origin_objects_it == objects().end()) {
host_content_settings_map_->SetWebsiteSettingDefaultScope(
- origin.GetURL(), GURL(), data_content_settings_type_, nullptr);
+ origin.GetURL(), GURL(), data_content_settings_type_, base::Value());
return;
}
@@ -273,7 +272,7 @@ void ObjectPermissionContextBase::SaveWebsiteSetting(
website_setting_value.SetKey(kObjectListKey, std::move(objects_list));
host_content_settings_map_->SetWebsiteSettingDefaultScope(
origin.GetURL(), GURL(), data_content_settings_type_,
- base::Value::ToUniquePtrValue(std::move(website_setting_value)));
+ std::move(website_setting_value));
}
void ObjectPermissionContextBase::ScheduleSaveWebsiteSetting(
@@ -320,7 +319,7 @@ ObjectPermissionContextBase::GetWebsiteSettingObjects() {
if (!objects)
continue;
- for (auto& object : objects->GetList()) {
+ for (auto& object : objects->GetListDeprecated()) {
if (!IsValidObject(object)) {
continue;
}
diff --git a/chromium/components/permissions/permission_actions_history.cc b/chromium/components/permissions/permission_actions_history.cc
index 27cb7a8e3e9..ae5be88c14c 100644
--- a/chromium/components/permissions/permission_actions_history.cc
+++ b/chromium/components/permissions/permission_actions_history.cc
@@ -5,7 +5,6 @@
#include "base/containers/adapters.h"
#include "base/json/values_util.h"
-#include "base/no_destructor.h"
#include "base/ranges/algorithm.h"
#include "base/strings/string_piece.h"
#include "base/values.h"
@@ -52,7 +51,7 @@ constexpr base::TimeDelta kPermissionActionMaxAge = base::Days(90);
std::vector<PermissionActionsHistory::Entry>
PermissionActionsHistory::GetHistory(const base::Time& begin,
EntryFilter entry_filter) {
- const base::DictionaryValue* dictionary =
+ const base::Value* dictionary =
pref_service_->GetDictionary(prefs::kPermissionActions);
if (!dictionary)
return {};
@@ -89,7 +88,7 @@ void PermissionActionsHistory::RecordAction(
const base::StringPiece permission_path(PermissionKeyForRequestType(type));
if (!update->FindPathOfType(permission_path, base::Value::Type::LIST)) {
- update->SetPath(permission_path, base::ListValue());
+ update->SetPath(permission_path, base::Value(base::Value::Type::LIST));
}
base::Value* permission_actions =
@@ -151,7 +150,7 @@ PermissionActionsHistory::GetHistoryInternal(const base::Time& begin,
std::vector<Entry> matching_actions;
- for (const auto& entry : permission_actions->GetList()) {
+ for (const auto& entry : permission_actions->GetListDeprecated()) {
const absl::optional<base::Time> timestamp =
base::ValueToTime(entry.FindKey(kPermissionActionEntryTimestampKey));
diff --git a/chromium/components/permissions/permission_context_base.cc b/chromium/components/permissions/permission_context_base.cc
index 42d648e000c..db1ab614505 100644
--- a/chromium/components/permissions/permission_context_base.cc
+++ b/chromium/components/permissions/permission_context_base.cc
@@ -45,7 +45,7 @@ namespace {
const char kPermissionBlockedKillSwitchMessage[] =
"%s permission has been blocked.";
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
const char kPermissionBlockedRepeatedDismissalsMessage[] =
"%s permission has been blocked as the user has dismissed the permission "
"prompt several times. This can be reset in Site Settings. See "
@@ -85,10 +85,10 @@ const char kPermissionBlockedFencedFrameMessage[] =
"%s permission has been blocked because it was requested inside a fenced "
"frame. Fenced frames don't currently support permission requests.";
-void LogPermissionBlockedMessage(content::WebContents* web_contents,
+void LogPermissionBlockedMessage(content::RenderFrameHost* rfh,
const char* message,
ContentSettingsType type) {
- web_contents->GetMainFrame()->AddMessageToConsole(
+ rfh->GetOutermostMainFrame()->AddMessageToConsole(
blink::mojom::ConsoleMessageLevel::kWarning,
base::StringPrintf(message,
PermissionUtil::GetPermissionString(type).c_str()));
@@ -156,34 +156,31 @@ void PermissionContextBase::RequestPermission(
switch (result.source) {
case PermissionStatusSource::KILL_SWITCH:
// Block the request and log to the developer console.
- LogPermissionBlockedMessage(web_contents,
- kPermissionBlockedKillSwitchMessage,
+ LogPermissionBlockedMessage(rfh, kPermissionBlockedKillSwitchMessage,
content_settings_type_);
std::move(callback).Run(CONTENT_SETTING_BLOCK);
return;
case PermissionStatusSource::MULTIPLE_DISMISSALS:
- LogPermissionBlockedMessage(web_contents,
+ LogPermissionBlockedMessage(rfh,
kPermissionBlockedRepeatedDismissalsMessage,
content_settings_type_);
break;
case PermissionStatusSource::MULTIPLE_IGNORES:
- LogPermissionBlockedMessage(web_contents,
+ LogPermissionBlockedMessage(rfh,
kPermissionBlockedRepeatedIgnoresMessage,
content_settings_type_);
break;
case PermissionStatusSource::FEATURE_POLICY:
- LogPermissionBlockedMessage(web_contents,
+ LogPermissionBlockedMessage(rfh,
kPermissionBlockedPermissionsPolicyMessage,
content_settings_type_);
break;
case PermissionStatusSource::PORTAL:
- LogPermissionBlockedMessage(web_contents,
- kPermissionBlockedPortalsMessage,
+ LogPermissionBlockedMessage(rfh, kPermissionBlockedPortalsMessage,
content_settings_type_);
break;
case PermissionStatusSource::FENCED_FRAME:
- LogPermissionBlockedMessage(web_contents,
- kPermissionBlockedFencedFrameMessage,
+ LogPermissionBlockedMessage(rfh, kPermissionBlockedFencedFrameMessage,
content_settings_type_);
break;
case PermissionStatusSource::INSECURE_ORIGIN:
@@ -296,8 +293,7 @@ PermissionResult PermissionContextBase::GetPermissionStatus(
const GURL loaded_url = entry->GetURL();
if (virtual_url.SchemeIsHTTPOrHTTPS() &&
loaded_url.SchemeIsHTTPOrHTTPS() &&
- !url::Origin::Create(virtual_url)
- .IsSameOriginWith(url::Origin::Create(loaded_url))) {
+ !url::IsSameOriginWith(virtual_url, loaded_url)) {
return PermissionResult(
CONTENT_SETTING_BLOCK,
PermissionStatusSource::VIRTUAL_URL_DIFFERENT_ORIGIN);
diff --git a/chromium/components/permissions/permission_context_base_unittest.cc b/chromium/components/permissions/permission_context_base_unittest.cc
index 2358bbe073a..07a61d16653 100644
--- a/chromium/components/permissions/permission_context_base_unittest.cc
+++ b/chromium/components/permissions/permission_context_base_unittest.cc
@@ -267,7 +267,7 @@ class PermissionContextBaseTests : public content::RenderViewHostTestHarness {
"Permissions.Prompt." + decision_string + ".PriorIgnoreCount2." +
PermissionUtil::GetPermissionString(content_settings_type),
0, 1);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
histograms.ExpectUniqueSample(
"Permissions.Action.WithDisposition.ModalDialog",
static_cast<int>(action.value()), 1);
@@ -307,7 +307,7 @@ class PermissionContextBaseTests : public content::RenderViewHostTestHarness {
EXPECT_EQ(*ukm_recorder.GetEntryMetric(entry, "Action"),
static_cast<int64_t>(action.value()));
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
EXPECT_EQ(
*ukm_recorder.GetEntryMetric(entry, "PromptDisposition"),
static_cast<int64_t>(PermissionPromptDisposition::MODAL_DIALOG));
@@ -721,7 +721,7 @@ class PermissionContextBaseTests : public content::RenderViewHostTestHarness {
void SetUpUrl(const GURL& url) {
NavigateAndCommit(url);
- prompt_factory_->DocumentOnLoadCompletedInMainFrame(main_rfh());
+ prompt_factory_->DocumentOnLoadCompletedInPrimaryMainFrame();
}
private:
@@ -772,13 +772,7 @@ TEST_F(PermissionContextBaseTests, TestDismissUntilBlocked) {
}
// Test setting a custom number of dismissals before block via variations.
-// TODO(crbug.com/1278842): Fix flaky test on Linux TSan.
-#if defined(OS_LINUX) && defined(THREAD_SANITIZER)
-#define MAYBE_TestDismissVariations DISABLED_TestDismissVariations
-#else
-#define MAYBE_TestDismissVariations TestDismissVariations
-#endif
-TEST_F(PermissionContextBaseTests, MAYBE_TestDismissVariations) {
+TEST_F(PermissionContextBaseTests, TestDismissVariations) {
TestVariationBlockOnSeveralDismissals_TestContent();
}
@@ -796,7 +790,7 @@ TEST_F(PermissionContextBaseTests, TestGrantAndRevoke) {
CONTENT_SETTING_ASK);
TestGrantAndRevoke_TestContent(ContentSettingsType::MIDI_SYSEX,
CONTENT_SETTING_ASK);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
TestGrantAndRevoke_TestContent(
ContentSettingsType::PROTECTED_MEDIA_IDENTIFIER, CONTENT_SETTING_ASK);
// TODO(timvolodine): currently no test for
@@ -809,18 +803,12 @@ TEST_F(PermissionContextBaseTests, TestGrantAndRevoke) {
}
// Tests the global kill switch by enabling/disabling the Field Trials.
-// TODO(crbug.com/1278842): Fix flaky test on Linux TSan.
-#if defined(OS_LINUX) && defined(THREAD_SANITIZER)
-#define MAYBE_TestGlobalKillSwitch DISABLED_TestGlobalKillSwitch
-#else
-#define MAYBE_TestGlobalKillSwitch TestGlobalKillSwitch
-#endif
-TEST_F(PermissionContextBaseTests, MAYBE_TestGlobalKillSwitch) {
+TEST_F(PermissionContextBaseTests, TestGlobalKillSwitch) {
TestGlobalPermissionsKillSwitch(ContentSettingsType::GEOLOCATION);
TestGlobalPermissionsKillSwitch(ContentSettingsType::NOTIFICATIONS);
TestGlobalPermissionsKillSwitch(ContentSettingsType::MIDI_SYSEX);
TestGlobalPermissionsKillSwitch(ContentSettingsType::DURABLE_STORAGE);
-#if defined(OS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH)
TestGlobalPermissionsKillSwitch(
ContentSettingsType::PROTECTED_MEDIA_IDENTIFIER);
#endif
diff --git a/chromium/components/permissions/permission_decision_auto_blocker.cc b/chromium/components/permissions/permission_decision_auto_blocker.cc
index 614d46c747c..bcd1210bd66 100644
--- a/chromium/components/permissions/permission_decision_auto_blocker.cc
+++ b/chromium/components/permissions/permission_decision_auto_blocker.cc
@@ -56,13 +56,13 @@ int g_ignore_embargo_days = kDefaultEmbargoDays;
std::unique_ptr<base::Value> GetOriginAutoBlockerData(
HostContentSettingsMap* settings,
const GURL& origin_url) {
- std::unique_ptr<base::Value> website_setting = settings->GetWebsiteSetting(
+ base::Value website_setting = settings->GetWebsiteSetting(
origin_url, GURL(), ContentSettingsType::PERMISSION_AUTOBLOCKER_DATA,
nullptr);
- if (!website_setting || !website_setting->is_dict())
+ if (!website_setting.is_dict())
return std::make_unique<base::Value>(base::Value::Type::DICTIONARY);
- return website_setting;
+ return base::Value::ToUniquePtrValue(std::move(website_setting));
}
base::Value* GetOrCreatePermissionDict(base::Value* origin_dict,
@@ -92,7 +92,7 @@ int RecordActionInWebsiteSettings(const GURL& url,
settings_map->SetWebsiteSettingDefaultScope(
url, GURL(), ContentSettingsType::PERMISSION_AUTOBLOCKER_DATA,
- std::move(dict));
+ base::Value::FromUniquePtrValue(std::move(dict)));
return current_count;
}
@@ -403,7 +403,7 @@ void PermissionDecisionAutoBlocker::RemoveEmbargoAndResetCounts(
settings_map_->SetWebsiteSettingDefaultScope(
url, GURL(), ContentSettingsType::PERMISSION_AUTOBLOCKER_DATA,
- std::move(dict));
+ base::Value::FromUniquePtrValue(std::move(dict)));
}
void PermissionDecisionAutoBlocker::RemoveEmbargoAndResetCounts(
@@ -419,7 +419,7 @@ void PermissionDecisionAutoBlocker::RemoveEmbargoAndResetCounts(
if (origin.is_valid() && filter.Run(origin)) {
settings_map_->SetWebsiteSettingDefaultScope(
origin, GURL(), ContentSettingsType::PERMISSION_AUTOBLOCKER_DATA,
- nullptr);
+ base::Value());
}
}
}
@@ -448,7 +448,7 @@ void PermissionDecisionAutoBlocker::PlaceUnderEmbargo(
key, base::Value(static_cast<double>(clock_->Now().ToInternalValue())));
settings_map_->SetWebsiteSettingDefaultScope(
request_origin, GURL(), ContentSettingsType::PERMISSION_AUTOBLOCKER_DATA,
- std::move(dict));
+ base::Value::FromUniquePtrValue(std::move(dict)));
}
void PermissionDecisionAutoBlocker::SetClockForTesting(base::Clock* clock) {
diff --git a/chromium/components/permissions/permission_manager.cc b/chromium/components/permissions/permission_manager.cc
index a34e52a2f49..72bf09f01e9 100644
--- a/chromium/components/permissions/permission_manager.cc
+++ b/chromium/components/permissions/permission_manager.cc
@@ -83,7 +83,7 @@ ContentSettingsType PermissionTypeToContentSettingSafe(
case PermissionType::GEOLOCATION:
return ContentSettingsType::GEOLOCATION;
case PermissionType::PROTECTED_MEDIA_IDENTIFIER:
-#if defined(OS_ANDROID) || defined(OS_CHROMEOS) || defined(OS_WIN)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN)
return ContentSettingsType::PROTECTED_MEDIA_IDENTIFIER;
#else
break;
diff --git a/chromium/components/permissions/permission_manager_unittest.cc b/chromium/components/permissions/permission_manager_unittest.cc
index 576bccdb44d..ba27fbd8d65 100644
--- a/chromium/components/permissions/permission_manager_unittest.cc
+++ b/chromium/components/permissions/permission_manager_unittest.cc
@@ -26,9 +26,9 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/mojom/permissions_policy/permissions_policy.mojom.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "base/android/build_info.h"
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
using blink::mojom::PermissionStatus;
using content::PermissionType;
@@ -92,7 +92,7 @@ PermissionManager::PermissionContextMap CreatePermissionContexts(
std::make_unique<FakePermissionContextAlwaysAllow>(
browser_context, ContentSettingsType::STORAGE_ACCESS,
blink::mojom::PermissionsPolicyFeature::kStorageAccessAPI);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
permission_contexts[ContentSettingsType::PROTECTED_MEDIA_IDENTIFIER] =
std::make_unique<FakePermissionContext>(
browser_context, ContentSettingsType::PROTECTED_MEDIA_IDENTIFIER,
@@ -101,7 +101,7 @@ PermissionManager::PermissionContextMap CreatePermissionContexts(
return permission_contexts;
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// See https://crbug.com/904883.
auto GetDefaultProtectedMediaIdentifierPermissionStatus() {
return base::android::BuildInfo::GetInstance()->sdk_int() >=
@@ -116,7 +116,7 @@ auto GetDefaultProtectedMediaIdentifierContentSetting() {
? CONTENT_SETTING_ALLOW
: CONTENT_SETTING_ASK;
}
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
} // namespace
@@ -273,7 +273,7 @@ TEST_F(PermissionManagerTest, GetPermissionStatusDefault) {
CheckPermissionStatus(PermissionType::MIDI_SYSEX, PermissionStatus::ASK);
CheckPermissionStatus(PermissionType::NOTIFICATIONS, PermissionStatus::ASK);
CheckPermissionStatus(PermissionType::GEOLOCATION, PermissionStatus::ASK);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
CheckPermissionStatus(PermissionType::PROTECTED_MEDIA_IDENTIFIER,
GetDefaultProtectedMediaIdentifierPermissionStatus());
#endif
@@ -290,7 +290,7 @@ TEST_F(PermissionManagerTest, GetPermissionStatusAfterSet) {
SetPermission(ContentSettingsType::MIDI_SYSEX, CONTENT_SETTING_ALLOW);
CheckPermissionStatus(PermissionType::MIDI_SYSEX, PermissionStatus::GRANTED);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
SetPermission(ContentSettingsType::PROTECTED_MEDIA_IDENTIFIER,
CONTENT_SETTING_ALLOW);
CheckPermissionStatus(PermissionType::PROTECTED_MEDIA_IDENTIFIER,
@@ -305,7 +305,7 @@ TEST_F(PermissionManagerTest, CheckPermissionResultDefault) {
PermissionStatusSource::UNSPECIFIED);
CheckPermissionResult(ContentSettingsType::GEOLOCATION, CONTENT_SETTING_ASK,
PermissionStatusSource::UNSPECIFIED);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
CheckPermissionResult(ContentSettingsType::PROTECTED_MEDIA_IDENTIFIER,
GetDefaultProtectedMediaIdentifierContentSetting(),
PermissionStatusSource::UNSPECIFIED);
@@ -326,7 +326,7 @@ TEST_F(PermissionManagerTest, CheckPermissionResultAfterSet) {
CheckPermissionResult(ContentSettingsType::MIDI_SYSEX, CONTENT_SETTING_ALLOW,
PermissionStatusSource::UNSPECIFIED);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
SetPermission(ContentSettingsType::PROTECTED_MEDIA_IDENTIFIER,
CONTENT_SETTING_ALLOW);
CheckPermissionResult(ContentSettingsType::PROTECTED_MEDIA_IDENTIFIER,
@@ -684,7 +684,7 @@ TEST_F(PermissionManagerTest, InsecureOriginIsNotOverridable) {
TEST_F(PermissionManagerTest, MissingContextIsNotOverridable) {
// Permissions that are not implemented should be denied overridability.
-#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_CHROMEOS) && !BUILDFLAG(IS_ANDROID)
EXPECT_FALSE(
GetPermissionControllerDelegate()->IsPermissionOverridableByDevTools(
PermissionType::PROTECTED_MEDIA_IDENTIFIER,
@@ -756,7 +756,7 @@ TEST_F(PermissionManagerTest, GetPermissionStatusDelegation) {
PermissionRequestManager::FromWebContents(web_contents());
auto prompt_factory = std::make_unique<MockPermissionPromptFactory>(manager);
prompt_factory->set_response_type(PermissionRequestManager::ACCEPT_ALL);
- prompt_factory->DocumentOnLoadCompletedInMainFrame(main_rfh());
+ prompt_factory->DocumentOnLoadCompletedInPrimaryMainFrame();
RequestPermission(PermissionType::GEOLOCATION, child, GURL(kOrigin2));
diff --git a/chromium/components/permissions/permission_prompt.h b/chromium/components/permissions/permission_prompt.h
index 0ab07f922af..e657a069928 100644
--- a/chromium/components/permissions/permission_prompt.h
+++ b/chromium/components/permissions/permission_prompt.h
@@ -93,6 +93,12 @@ class PermissionPrompt {
// Set when the user made any decision for the currentrequest.
virtual void SetDecisionTime() = 0;
+
+ // Set when the user made any decision for manage settings.
+ virtual void SetManageClicked() = 0;
+
+ // Set when the user made any decision for clicking on learn more link.
+ virtual void SetLearnMoreClicked() = 0;
};
typedef base::RepeatingCallback<
diff --git a/chromium/components/permissions/permission_request.cc b/chromium/components/permissions/permission_request.cc
index 978b5e6d73d..d154e01d32a 100644
--- a/chromium/components/permissions/permission_request.cc
+++ b/chromium/components/permissions/permission_request.cc
@@ -12,7 +12,7 @@
#include "components/url_formatter/elide_url.h"
#include "ui/base/l10n/l10n_util.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "media/base/android/media_drm_bridge.h"
#endif
@@ -39,7 +39,7 @@ bool PermissionRequest::IsDuplicateOf(PermissionRequest* other_request) const {
requesting_origin() == other_request->requesting_origin();
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
std::u16string PermissionRequest::GetDialogMessageText() const {
int message_id = 0;
switch (request_type_) {
@@ -102,7 +102,7 @@ std::u16string PermissionRequest::GetDialogMessageText() const {
}
#endif
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
IconId PermissionRequest::GetIconForChip() {
return permissions::GetIconId(request_type_);
}
@@ -207,7 +207,7 @@ std::u16string PermissionRequest::GetMessageTextFragment() const {
case RequestType::kNotifications:
message_id = IDS_NOTIFICATION_PERMISSIONS_FRAGMENT;
break;
-#if defined(OS_CHROMEOS) || defined(OS_WIN)
+#if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN)
case RequestType::kProtectedMediaIdentifier:
message_id = IDS_PROTECTED_MEDIA_IDENTIFIER_PERMISSION_FRAGMENT;
break;
diff --git a/chromium/components/permissions/permission_request.h b/chromium/components/permissions/permission_request.h
index 6bd135b5ec6..94264968af0 100644
--- a/chromium/components/permissions/permission_request.h
+++ b/chromium/components/permissions/permission_request.h
@@ -66,12 +66,12 @@ class PermissionRequest {
// need to be shown in the UI.
virtual bool IsDuplicateOf(PermissionRequest* other_request) const;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Returns prompt text appropriate for displaying in an Android dialog.
virtual std::u16string GetDialogMessageText() const;
#endif
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
// Returns prompt icon appropriate for displaying on the chip button in the
// location bar.
IconId GetIconForChip();
diff --git a/chromium/components/permissions/permission_request_manager.cc b/chromium/components/permissions/permission_request_manager.cc
index 7c2d6ad6d3f..30d020a934f 100644
--- a/chromium/components/permissions/permission_request_manager.cc
+++ b/chromium/components/permissions/permission_request_manager.cc
@@ -99,7 +99,7 @@ bool ShouldShowQuietRequestAgainIfPreempted(
}
bool IsMediaRequest(RequestType type) {
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
if (type == RequestType::kCameraPanTiltZoom)
return true;
#endif
@@ -203,8 +203,7 @@ void PermissionRequestManager::AddRequest(
const GURL& main_frame_origin =
PermissionUtil::GetLastCommittedOriginAsURL(web_contents());
bool is_main_frame =
- url::Origin::Create(main_frame_origin)
- .IsSameOriginWith(url::Origin::Create(request->requesting_origin()));
+ url::IsSameOriginWith(main_frame_origin, request->requesting_origin());
absl::optional<url::Origin> auto_approval_origin =
PermissionsClient::Get()->GetAutoApprovalOrigin();
@@ -375,8 +374,7 @@ void PermissionRequestManager::DidFinishNavigation(
CleanUpRequests();
}
-void PermissionRequestManager::DocumentOnLoadCompletedInMainFrame(
- content::RenderFrameHost* render_frame_host) {
+void PermissionRequestManager::DocumentOnLoadCompletedInPrimaryMainFrame() {
// This is scheduled because while all calls to the browser have been
// issued at DOMContentLoaded, they may be bouncing around in scheduled
// callbacks finding the UI thread still. This makes sure we allow those
@@ -428,7 +426,7 @@ void PermissionRequestManager::OnVisibilityChanged(
return;
}
- if (!web_contents()->IsDocumentOnLoadCompletedInMainFrame())
+ if (!web_contents()->IsDocumentOnLoadCompletedInPrimaryMainFrame())
return;
if (!IsRequestInProgress()) {
@@ -556,6 +554,14 @@ void PermissionRequestManager::SetDecisionTime() {
current_request_decision_time_ = base::Time::Now();
}
+void PermissionRequestManager::SetManageClicked() {
+ set_manage_clicked();
+}
+
+void PermissionRequestManager::SetLearnMoreClicked() {
+ set_learn_more_clicked();
+}
+
PermissionRequestManager::PermissionRequestManager(
content::WebContents* web_contents)
: content::WebContentsObserver(web_contents),
@@ -584,7 +590,7 @@ void PermissionRequestManager::DequeueRequestIfNeeded() {
// PermissionBubbleMediaAccessHandler and UserMediaClient. We probably don't
// need two permission queues, so resolve the duplication.
- if (!web_contents()->IsDocumentOnLoadCompletedInMainFrame() || view_ ||
+ if (!web_contents()->IsDocumentOnLoadCompletedInPrimaryMainFrame() || view_ ||
IsRequestInProgress()) {
return;
}
@@ -665,7 +671,7 @@ void PermissionRequestManager::ShowBubble() {
if (!IsRequestInProgress() || view_)
return;
- DCHECK(web_contents()->IsDocumentOnLoadCompletedInMainFrame());
+ DCHECK(web_contents()->IsDocumentOnLoadCompletedInPrimaryMainFrame());
DCHECK(current_request_ui_to_use_);
if (tab_is_hidden_)
@@ -732,7 +738,7 @@ void PermissionRequestManager::ResetViewStateForCurrentRequest() {
selector_decisions_.clear();
should_dismiss_current_request_ = false;
did_show_bubble_ = false;
- did_click_managed_ = false;
+ did_click_manage_ = false;
did_click_learn_more_ = false;
if (view_)
@@ -761,7 +767,7 @@ void PermissionRequestManager::FinalizeCurrentRequests(
requests_, web_contents(), permission_action, time_to_decision,
DetermineCurrentRequestUIDisposition(),
DetermineCurrentRequestUIDispositionReasonForUMA(),
- prediction_grant_likelihood_, did_show_bubble_, did_click_managed_,
+ prediction_grant_likelihood_, did_show_bubble_, did_click_manage_,
did_click_learn_more_);
content::BrowserContext* browser_context =
diff --git a/chromium/components/permissions/permission_request_manager.h b/chromium/components/permissions/permission_request_manager.h
index 4ef281544d9..ecff13fc0af 100644
--- a/chromium/components/permissions/permission_request_manager.h
+++ b/chromium/components/permissions/permission_request_manager.h
@@ -126,8 +126,7 @@ class PermissionRequestManager
content::NavigationHandle* navigation_handle) override;
void DidFinishNavigation(
content::NavigationHandle* navigation_handle) override;
- void DocumentOnLoadCompletedInMainFrame(
- content::RenderFrameHost* render_frame_host) override;
+ void DocumentOnLoadCompletedInPrimaryMainFrame() override;
void DOMContentLoaded(content::RenderFrameHost* render_frame_host) override;
void WebContentsDestroyed() override;
void OnVisibilityChanged(content::Visibility visibility) override;
@@ -149,8 +148,10 @@ class PermissionRequestManager
void SetDismissOnTabClose() override;
void SetBubbleShown() override;
void SetDecisionTime() override;
+ void SetManageClicked() override;
+ void SetLearnMoreClicked() override;
- void set_managed_clicked() { did_click_managed_ = true; }
+ void set_manage_clicked() { did_click_manage_ = true; }
void set_learn_more_clicked() { did_click_learn_more_ = true; }
void set_web_contents_supports_permission_requests(
@@ -399,7 +400,7 @@ class PermissionRequestManager
// at all.
base::Time current_request_decision_time_;
- bool did_click_managed_ = false;
+ bool did_click_manage_ = false;
bool did_click_learn_more_ = false;
diff --git a/chromium/components/permissions/permission_request_manager_unittest.cc b/chromium/components/permissions/permission_request_manager_unittest.cc
index 79aa0f2347a..217ce22c44d 100644
--- a/chromium/components/permissions/permission_request_manager_unittest.cc
+++ b/chromium/components/permissions/permission_request_manager_unittest.cc
@@ -46,7 +46,7 @@ class PermissionRequestManagerTest
PermissionRequestGestureType::NO_GESTURE),
request_camera_(RequestType::kCameraStream,
PermissionRequestGestureType::NO_GESTURE),
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
request_ptz_(RequestType::kCameraPanTiltZoom,
PermissionRequestGestureType::NO_GESTURE),
#endif
@@ -99,7 +99,7 @@ class PermissionRequestManagerTest
}
void WaitForBubbleToBeShown() {
- manager_->DocumentOnLoadCompletedInMainFrame(main_rfh());
+ manager_->DocumentOnLoadCompletedInPrimaryMainFrame();
base::RunLoop().RunUntilIdle();
}
@@ -151,7 +151,7 @@ class PermissionRequestManagerTest
MockPermissionRequest request2_;
MockPermissionRequest request_mic_;
MockPermissionRequest request_camera_;
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
MockPermissionRequest request_ptz_;
#endif
MockPermissionRequest iframe_request_same_domain_;
@@ -364,7 +364,7 @@ TEST_P(PermissionRequestManagerTest, MicCameraDifferentOrigins) {
ASSERT_EQ(prompt_factory_->request_count(), 1);
}
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
// Only camera/ptz requests from the same origin should be grouped.
TEST_P(PermissionRequestManagerTest, CameraPtzGrouped) {
manager_->AddRequest(web_contents()->GetMainFrame(), &request_camera_);
@@ -426,7 +426,7 @@ TEST_P(PermissionRequestManagerTest, MicCameraPtzDifferentOrigins) {
EXPECT_TRUE(prompt_factory_->is_visible());
ASSERT_LT(prompt_factory_->request_count(), 3);
}
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
// Tests mix of grouped media requests and non-groupable request.
TEST_P(PermissionRequestManagerTest, MixOfMediaAndNotMediaRequests) {
@@ -461,7 +461,7 @@ TEST_P(PermissionRequestManagerTest, TwoRequestsTabSwitch) {
ASSERT_EQ(prompt_factory_->request_count(), 2);
MockTabSwitchAway();
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
EXPECT_TRUE(prompt_factory_->is_visible());
#else
EXPECT_FALSE(prompt_factory_->is_visible());
diff --git a/chromium/components/permissions/permission_uma_util.cc b/chromium/components/permissions/permission_uma_util.cc
index ab4860693ea..32992dcf7aa 100644
--- a/chromium/components/permissions/permission_uma_util.cc
+++ b/chromium/components/permissions/permission_uma_util.cc
@@ -17,8 +17,8 @@
#include "components/permissions/permission_request.h"
#include "components/permissions/permission_util.h"
#include "components/permissions/permissions_client.h"
+#include "components/permissions/prediction_service/prediction_common.h"
#include "components/permissions/prediction_service/prediction_request_features.h"
-#include "components/permissions/prediction_service/prediction_service.h"
#include "components/permissions/request_type.h"
#include "components/ukm/content/source_url_recorder.h"
#include "content/public/browser/permission_type.h"
@@ -29,7 +29,7 @@
#include "services/network/public/cpp/is_potentially_trustworthy.h"
#include "url/gurl.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "base/android/jni_string.h"
#include "components/permissions/android/jni_headers/PermissionUmaUtil_jni.h"
#endif
@@ -60,7 +60,7 @@ RequestTypeForUma GetUmaValueForRequestType(RequestType request_type) {
return RequestTypeForUma::PERMISSION_ACCESSIBILITY_EVENTS;
case RequestType::kArSession:
return RequestTypeForUma::PERMISSION_AR;
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
case RequestType::kCameraPanTiltZoom:
return RequestTypeForUma::PERMISSION_CAMERA_PAN_TILT_ZOOM;
#endif
@@ -70,7 +70,7 @@ RequestTypeForUma GetUmaValueForRequestType(RequestType request_type) {
return RequestTypeForUma::PERMISSION_CLIPBOARD_READ_WRITE;
case RequestType::kDiskQuota:
return RequestTypeForUma::QUOTA;
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
case RequestType::kFontAccess:
return RequestTypeForUma::PERMISSION_FONT_ACCESS;
#endif
@@ -84,17 +84,17 @@ RequestTypeForUma GetUmaValueForRequestType(RequestType request_type) {
return RequestTypeForUma::PERMISSION_MIDI_SYSEX;
case RequestType::kMultipleDownloads:
return RequestTypeForUma::DOWNLOAD;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
case RequestType::kNfcDevice:
return RequestTypeForUma::PERMISSION_NFC;
#endif
case RequestType::kNotifications:
return RequestTypeForUma::PERMISSION_NOTIFICATIONS;
-#if defined(OS_ANDROID) || defined(OS_CHROMEOS) || defined(OS_WIN)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN)
case RequestType::kProtectedMediaIdentifier:
return RequestTypeForUma::PERMISSION_PROTECTED_MEDIA_IDENTIFIER;
#endif
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
case RequestType::kRegisterProtocolHandler:
return RequestTypeForUma::REGISTER_PROTOCOL_HANDLER;
case RequestType::kSecurityAttestation:
@@ -106,7 +106,7 @@ RequestTypeForUma GetUmaValueForRequestType(RequestType request_type) {
return RequestTypeForUma::PERMISSION_STORAGE_ACCESS;
case RequestType::kVrSession:
return RequestTypeForUma::PERMISSION_VR;
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
case RequestType::kWindowPlacement:
return RequestTypeForUma::PERMISSION_WINDOW_PLACEMENT;
#endif
@@ -243,68 +243,57 @@ void RecordPermissionActionUkm(
builder
.SetStats_LoudPromptsOfType_DenyRate(
- PredictionService::GetRoundedRatioForUkm(
- loud_ui_actions_counts_for_request_type.denies,
- loud_ui_prompts_count_for_request_type))
- .SetStats_LoudPromptsOfType_DismissRate(
- PredictionService::GetRoundedRatioForUkm(
- loud_ui_actions_counts_for_request_type.dismissals,
- loud_ui_prompts_count_for_request_type))
+ GetRoundedRatioForUkm(loud_ui_actions_counts_for_request_type.denies,
+ loud_ui_prompts_count_for_request_type))
+ .SetStats_LoudPromptsOfType_DismissRate(GetRoundedRatioForUkm(
+ loud_ui_actions_counts_for_request_type.dismissals,
+ loud_ui_prompts_count_for_request_type))
.SetStats_LoudPromptsOfType_GrantRate(
- PredictionService::GetRoundedRatioForUkm(
- loud_ui_actions_counts_for_request_type.grants,
- loud_ui_prompts_count_for_request_type))
+ GetRoundedRatioForUkm(loud_ui_actions_counts_for_request_type.grants,
+ loud_ui_prompts_count_for_request_type))
.SetStats_LoudPromptsOfType_IgnoreRate(
- PredictionService::GetRoundedRatioForUkm(
- loud_ui_actions_counts_for_request_type.ignores,
- loud_ui_prompts_count_for_request_type))
- .SetStats_LoudPromptsOfType_Count(PredictionService::BucketizeValue(
- loud_ui_prompts_count_for_request_type));
+ GetRoundedRatioForUkm(loud_ui_actions_counts_for_request_type.ignores,
+ loud_ui_prompts_count_for_request_type))
+ .SetStats_LoudPromptsOfType_Count(
+ BucketizeValue(loud_ui_prompts_count_for_request_type));
builder
- .SetStats_LoudPrompts_DenyRate(PredictionService::GetRoundedRatioForUkm(
+ .SetStats_LoudPrompts_DenyRate(GetRoundedRatioForUkm(
loud_ui_actions_counts.denies, loud_ui_prompts_count))
- .SetStats_LoudPrompts_DismissRate(
- PredictionService::GetRoundedRatioForUkm(
- loud_ui_actions_counts.dismissals, loud_ui_prompts_count))
- .SetStats_LoudPrompts_GrantRate(PredictionService::GetRoundedRatioForUkm(
+ .SetStats_LoudPrompts_DismissRate(GetRoundedRatioForUkm(
+ loud_ui_actions_counts.dismissals, loud_ui_prompts_count))
+ .SetStats_LoudPrompts_GrantRate(GetRoundedRatioForUkm(
loud_ui_actions_counts.grants, loud_ui_prompts_count))
- .SetStats_LoudPrompts_IgnoreRate(PredictionService::GetRoundedRatioForUkm(
+ .SetStats_LoudPrompts_IgnoreRate(GetRoundedRatioForUkm(
loud_ui_actions_counts.ignores, loud_ui_prompts_count))
- .SetStats_LoudPrompts_Count(
- PredictionService::BucketizeValue(loud_ui_prompts_count));
+ .SetStats_LoudPrompts_Count(BucketizeValue(loud_ui_prompts_count));
builder
.SetStats_AllPromptsOfType_DenyRate(
- PredictionService::GetRoundedRatioForUkm(
- actions_counts_for_request_type.denies,
- prompts_count_for_request_type))
+ GetRoundedRatioForUkm(actions_counts_for_request_type.denies,
+ prompts_count_for_request_type))
.SetStats_AllPromptsOfType_DismissRate(
- PredictionService::GetRoundedRatioForUkm(
- actions_counts_for_request_type.dismissals,
- prompts_count_for_request_type))
+ GetRoundedRatioForUkm(actions_counts_for_request_type.dismissals,
+ prompts_count_for_request_type))
.SetStats_AllPromptsOfType_GrantRate(
- PredictionService::GetRoundedRatioForUkm(
- actions_counts_for_request_type.grants,
- prompts_count_for_request_type))
+ GetRoundedRatioForUkm(actions_counts_for_request_type.grants,
+ prompts_count_for_request_type))
.SetStats_AllPromptsOfType_IgnoreRate(
- PredictionService::GetRoundedRatioForUkm(
- actions_counts_for_request_type.ignores,
- prompts_count_for_request_type))
+ GetRoundedRatioForUkm(actions_counts_for_request_type.ignores,
+ prompts_count_for_request_type))
.SetStats_AllPromptsOfType_Count(
- PredictionService::BucketizeValue(prompts_count_for_request_type));
+ BucketizeValue(prompts_count_for_request_type));
builder
- .SetStats_AllPrompts_DenyRate(PredictionService::GetRoundedRatioForUkm(
- actions_counts.denies, prompts_count))
- .SetStats_AllPrompts_DismissRate(PredictionService::GetRoundedRatioForUkm(
- actions_counts.dismissals, prompts_count))
- .SetStats_AllPrompts_GrantRate(PredictionService::GetRoundedRatioForUkm(
- actions_counts.grants, prompts_count))
- .SetStats_AllPrompts_IgnoreRate(PredictionService::GetRoundedRatioForUkm(
- actions_counts.ignores, prompts_count))
- .SetStats_AllPrompts_Count(
- PredictionService::BucketizeValue(prompts_count));
+ .SetStats_AllPrompts_DenyRate(
+ GetRoundedRatioForUkm(actions_counts.denies, prompts_count))
+ .SetStats_AllPrompts_DismissRate(
+ GetRoundedRatioForUkm(actions_counts.dismissals, prompts_count))
+ .SetStats_AllPrompts_GrantRate(
+ GetRoundedRatioForUkm(actions_counts.grants, prompts_count))
+ .SetStats_AllPrompts_IgnoreRate(
+ GetRoundedRatioForUkm(actions_counts.ignores, prompts_count))
+ .SetStats_AllPrompts_Count(BucketizeValue(prompts_count));
if (ui_reason.has_value())
builder.SetPromptDispositionReason(static_cast<int64_t>(ui_reason.value()));
@@ -615,7 +604,7 @@ void PermissionUmaUtil::PermissionPromptResolved(
RecordPermissionPromptPriorCount(
permission, priorIgnorePrefix,
autoblocker->GetIgnoreCount(requesting_origin, permission));
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
if (permission == ContentSettingsType::GEOLOCATION &&
permission_action != PermissionAction::IGNORED) {
RecordWithBatteryBucket("Permissions.BatteryLevel." + action_string +
@@ -650,25 +639,33 @@ void PermissionUmaUtil::PermissionPromptResolved(
if (permission_action == PermissionAction::IGNORED &&
ui_disposition !=
- PermissionPromptDisposition::LOCATION_BAR_LEFT_CHIP_AUTO_BUBBLE) {
+ PermissionPromptDisposition::LOCATION_BAR_LEFT_CHIP_AUTO_BUBBLE &&
+ ui_disposition != PermissionPromptDisposition::ANCHORED_BUBBLE) {
base::UmaHistogramBoolean("Permissions.Prompt." + permission_type + "." +
permission_disposition +
".Ignored.DidShowBubble",
did_show_prompt);
}
- if (ui_disposition ==
- PermissionPromptDisposition::LOCATION_BAR_LEFT_QUIET_CHIP) {
- base::UmaHistogramBoolean("Permissions.Prompt." + permission_type + "." +
- permission_disposition + "." + action_string +
- ".DidClickManage",
- did_click_managed);
- } else if (ui_disposition == PermissionPromptDisposition::
- LOCATION_BAR_LEFT_QUIET_ABUSIVE_CHIP) {
- base::UmaHistogramBoolean("Permissions.Prompt." + permission_type + "." +
- permission_disposition + "." + action_string +
- ".DidClickLearnMore",
- did_click_learn_more);
+ if (requests[0]->request_type() == RequestType::kGeolocation ||
+ requests[0]->request_type() == RequestType::kNotifications) {
+ if (ui_disposition ==
+ PermissionPromptDisposition::LOCATION_BAR_LEFT_QUIET_CHIP ||
+ ui_disposition == PermissionPromptDisposition::MESSAGE_UI ||
+ ui_disposition == PermissionPromptDisposition::MINI_INFOBAR) {
+ base::UmaHistogramBoolean("Permissions.Prompt." + permission_type + "." +
+ permission_disposition + "." +
+ action_string + ".DidClickManage",
+ did_click_managed);
+ } else if (ui_disposition == PermissionPromptDisposition::
+ LOCATION_BAR_LEFT_QUIET_ABUSIVE_CHIP ||
+ ui_disposition == PermissionPromptDisposition::MESSAGE_UI ||
+ ui_disposition == PermissionPromptDisposition::MINI_INFOBAR) {
+ base::UmaHistogramBoolean("Permissions.Prompt." + permission_type + "." +
+ permission_disposition + "." +
+ action_string + ".DidClickLearnMore",
+ did_click_learn_more);
+ }
}
} // namespace permissions
@@ -688,7 +685,7 @@ void PermissionUmaUtil::RecordPermissionPromptPriorCount(
->Add(count);
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
void PermissionUmaUtil::RecordWithBatteryBucket(const std::string& histogram) {
JNIEnv* env = base::android::AttachCurrentThread();
Java_PermissionUmaUtil_recordWithBatteryBucket(
@@ -1060,6 +1057,31 @@ void PermissionUmaUtil::RecordDSEEffectiveSetting(
CONTENT_SETTING_NUM_SETTINGS);
}
+// static
+void PermissionUmaUtil::RecordPermissionPredictionSource(
+ PermissionPredictionSource prediction_source) {
+ base::UmaHistogramEnumeration(
+ "Permissions.PredictionService.PredictionSource", prediction_source);
+}
+
+// static
+void PermissionUmaUtil::RecordPermissionPredictionServiceHoldback(
+ RequestType request_type,
+ bool is_on_device,
+ bool is_heldback) {
+ if (is_on_device) {
+ base::UmaHistogramBoolean(
+ "Permissions.OnDevicePredictionService.Response." +
+ GetPermissionRequestString(GetUmaValueForRequestType(request_type)),
+ is_heldback);
+ } else {
+ base::UmaHistogramBoolean(
+ "Permissions.PredictionService.Response." +
+ GetPermissionRequestString(GetUmaValueForRequestType(request_type)),
+ is_heldback);
+ }
+}
+
std::string PermissionUmaUtil::GetPermissionActionString(
PermissionAction permission_action) {
switch (permission_action) {
diff --git a/chromium/components/permissions/permission_uma_util.h b/chromium/components/permissions/permission_uma_util.h
index a88bec186d6..4da8d5d835a 100644
--- a/chromium/components/permissions/permission_uma_util.h
+++ b/chromium/components/permissions/permission_uma_util.h
@@ -241,6 +241,17 @@ enum class AutoDSEPermissionRevertTransition {
kMaxValue = INVALID_END_STATE,
};
+// This enum backs up the 'PermissionPredictionSource` histogram enum. It
+// indicates whether the permission prediction was done by the local on device
+// model or by the server side model.
+enum class PermissionPredictionSource {
+ ON_DEVICE = 0,
+ SERVER_SIDE = 1,
+
+ // Always keep at the end.
+ kMaxValue = SERVER_SIDE,
+};
+
// Provides a convenient way of logging UMA for permission related operations.
class PermissionUmaUtil {
public:
@@ -344,6 +355,14 @@ class PermissionUmaUtil {
static void RecordDSEEffectiveSetting(ContentSettingsType permission_type,
ContentSetting setting);
+ static void RecordPermissionPredictionSource(
+ PermissionPredictionSource prediction_type);
+
+ static void RecordPermissionPredictionServiceHoldback(
+ RequestType request_type,
+ bool is_on_device,
+ bool is_heldback);
+
static std::string GetPermissionActionString(
PermissionAction permission_action);
diff --git a/chromium/components/permissions/permission_util.cc b/chromium/components/permissions/permission_util.cc
index 1bf0b460b1a..71b90e5bae9 100644
--- a/chromium/components/permissions/permission_util.cc
+++ b/chromium/components/permissions/permission_util.cc
@@ -116,7 +116,7 @@ bool PermissionUtil::GetPermissionType(ContentSettingsType type,
case ContentSettingsType::BACKGROUND_SYNC:
*out = PermissionType::BACKGROUND_SYNC;
break;
-#if defined(OS_ANDROID) || defined(OS_CHROMEOS) || defined(OS_WIN)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN)
case ContentSettingsType::PROTECTED_MEDIA_IDENTIFIER:
*out = PermissionType::PROTECTED_MEDIA_IDENTIFIER;
break;
@@ -188,7 +188,7 @@ bool PermissionUtil::IsPermission(ContentSettingsType type) {
case ContentSettingsType::MEDIASTREAM_CAMERA:
case ContentSettingsType::MEDIASTREAM_MIC:
case ContentSettingsType::BACKGROUND_SYNC:
-#if defined(OS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH) || defined(OS_WIN)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_WIN)
case ContentSettingsType::PROTECTED_MEDIA_IDENTIFIER:
#endif
case ContentSettingsType::SENSORS:
diff --git a/chromium/components/permissions/permissions_client.cc b/chromium/components/permissions/permissions_client.cc
index 7b4319806fe..78552246beb 100644
--- a/chromium/components/permissions/permissions_client.cc
+++ b/chromium/components/permissions/permissions_client.cc
@@ -5,10 +5,11 @@
#include "components/permissions/permissions_client.h"
#include "base/callback.h"
+#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "components/permissions/permission_uma_util.h"
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
#include "ui/gfx/paint_vector_icon.h"
#endif
@@ -45,7 +46,7 @@ void PermissionsClient::AreSitesImportant(
entry.second = false;
}
-#if defined(OS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH)
bool PermissionsClient::IsCookieDeletionDisabled(
content::BrowserContext* browser_context,
const GURL& origin) {
@@ -61,7 +62,7 @@ void PermissionsClient::GetUkmSourceId(content::BrowserContext* browser_context,
}
IconId PermissionsClient::GetOverrideIconId(RequestType request_type) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
return 0;
#else
return gfx::kNoneIcon;
@@ -116,26 +117,12 @@ bool PermissionsClient::DoOriginsMatchNewTabPage(const GURL& requesting_origin,
return false;
}
-#if defined(OS_ANDROID)
-bool PermissionsClient::IsPermissionControlledByDse(
- content::BrowserContext* browser_context,
- ContentSettingsType type,
- const url::Origin& origin) {
- return false;
-}
-
+#if BUILDFLAG(IS_ANDROID)
bool PermissionsClient::IsDseOrigin(content::BrowserContext* browser_context,
const url::Origin& origin) {
return false;
}
-bool PermissionsClient::ResetPermissionIfControlledByDse(
- content::BrowserContext* browser_context,
- ContentSettingsType type,
- const url::Origin& origin) {
- return false;
-}
-
infobars::InfoBarManager* PermissionsClient::GetInfoBarManager(
content::WebContents* web_contents) {
return nullptr;
@@ -148,7 +135,7 @@ infobars::InfoBar* PermissionsClient::MaybeCreateInfoBar(
return nullptr;
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
std::unique_ptr<PermissionsClient::PermissionMessageDelegate>
PermissionsClient::MaybeCreateMessageUI(
content::WebContents* web_contents,
diff --git a/chromium/components/permissions/permissions_client.h b/chromium/components/permissions/permissions_client.h
index cc1a48f813e..ce16d8601c4 100644
--- a/chromium/components/permissions/permissions_client.h
+++ b/chromium/components/permissions/permissions_client.h
@@ -19,7 +19,7 @@
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "url/origin.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "components/messages/android/message_wrapper.h"
#endif
@@ -51,7 +51,7 @@ class PermissionPromptAndroid;
// specific logic.
class PermissionsClient {
public:
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
class PermissionMessageDelegate {
public:
virtual ~PermissionMessageDelegate() = default;
@@ -113,7 +113,7 @@ class PermissionsClient {
content::BrowserContext* browser_context,
std::vector<std::pair<url::Origin, bool>>* origins);
-#if defined(OS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH)
// Returns whether cookie deletion is allowed for |browser_context| and
// |origin|.
// TODO(crbug.com/1081944): Remove this method and all code depending on it
@@ -196,27 +196,12 @@ class PermissionsClient {
virtual bool DoOriginsMatchNewTabPage(const GURL& requesting_origin,
const GURL& embedding_origin);
-#if defined(OS_ANDROID)
- // Returns whether the permission is controlled by the default search
- // engine (DSE). For example, in Chrome, making a search engine default
- // automatically grants notification permissions for the associated origin.
- virtual bool IsPermissionControlledByDse(
- content::BrowserContext* browser_context,
- ContentSettingsType type,
- const url::Origin& origin);
-
+#if BUILDFLAG(IS_ANDROID)
// Returns whether the given origin matches the default search engine (DSE)
// origin.
virtual bool IsDseOrigin(content::BrowserContext* browser_context,
const url::Origin& origin);
- // Resets the permission if it's controlled by the default search
- // engine (DSE). The return value is true if the permission was reset.
- virtual bool ResetPermissionIfControlledByDse(
- content::BrowserContext* browser_context,
- ContentSettingsType type,
- const url::Origin& origin);
-
// Retrieves the InfoBarManager for the web contents. The returned
// pointer has the same lifetime as |web_contents|.
virtual infobars::InfoBarManager* GetInfoBarManager(
diff --git a/chromium/components/permissions/prediction_service/BUILD.gn b/chromium/components/permissions/prediction_service/BUILD.gn
index 0a8f8ca22c7..dabb2a020ad 100644
--- a/chromium/components/permissions/prediction_service/BUILD.gn
+++ b/chromium/components/permissions/prediction_service/BUILD.gn
@@ -2,6 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//components/optimization_guide/features.gni")
import("//third_party/protobuf/proto_library.gni")
proto_library("prediction_service_messages_proto") {
@@ -10,21 +11,41 @@ proto_library("prediction_service_messages_proto") {
source_set("prediction_service") {
sources = [
+ "prediction_common.cc",
+ "prediction_common.h",
"prediction_request_features.h",
"prediction_service.cc",
"prediction_service.h",
"prediction_service_base.h",
- "prediction_service_common.cc",
- "prediction_service_common.h",
]
deps = [
"//build:chromeos_buildflags",
"//components/keyed_service/content",
"//components/permissions:permissions_common",
+ "//content/public/browser",
"//services/network/public/cpp:cpp",
"//third_party/protobuf:protobuf_lite",
]
- public_deps = [ ":prediction_service_messages_proto" ]
+ public_deps = [
+ ":prediction_service_messages_proto",
+ "//components/optimization_guide/core",
+ "//components/optimization_guide/proto:optimization_guide_proto",
+ ]
+
+ if (build_with_tflite_lib) {
+ sources += [
+ "prediction_model_executor.cc",
+ "prediction_model_executor.h",
+ "prediction_model_handler.cc",
+ "prediction_model_handler.h",
+ ]
+
+ deps += [
+ "//third_party/tflite:tflite_public_headers",
+ "//third_party/tflite_support",
+ "//third_party/tflite_support:tflite_support_proto",
+ ]
+ }
}
source_set("unit_tests") {
diff --git a/chromium/components/permissions/prediction_service/DEPS b/chromium/components/permissions/prediction_service/DEPS
index e1fbc94db6e..57af075d74f 100644
--- a/chromium/components/permissions/prediction_service/DEPS
+++ b/chromium/components/permissions/prediction_service/DEPS
@@ -1,7 +1,9 @@
include_rules = [
"+google/protobuf",
"+net",
+ "+components/optimization_guide",
"+services/network/public",
"+services/network/test",
"+third_party/googletest",
+ "+third_party/tflite_support",
]
diff --git a/chromium/components/permissions/prediction_service/prediction_service_common.cc b/chromium/components/permissions/prediction_service/prediction_common.cc
index c295aaa22aa..fe7c5788268 100644
--- a/chromium/components/permissions/prediction_service/prediction_service_common.cc
+++ b/chromium/components/permissions/prediction_service/prediction_common.cc
@@ -2,28 +2,142 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/permissions/prediction_service/prediction_service_common.h"
+#include "components/permissions/prediction_service/prediction_common.h"
+
+#include <cmath>
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
+#include "base/notreached.h"
#include "base/values.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
namespace permissions {
+
+float GetRoundedRatio(int numerator, int denominator) {
+ if (denominator == 0)
+ return 0;
+ return roundf(numerator / kRoundToMultiplesOf / denominator) *
+ kRoundToMultiplesOf;
+}
+
+int GetRoundedRatioForUkm(int numerator, int denominator) {
+ return GetRoundedRatio(numerator, denominator) * 100;
+}
+
+int BucketizeValue(int count) {
+ for (const int bucket : kCountBuckets) {
+ if (count >= bucket)
+ return bucket;
+ }
+ return 0;
+}
+
ClientFeatures_Platform GetCurrentPlatformProto() {
-#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_CHROMEOS) || \
- defined(OS_MAC)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || \
+ BUILDFLAG(IS_MAC)
return permissions::ClientFeatures_Platform_PLATFORM_DESKTOP;
-#elif defined(OS_ANDROID) || defined(OS_FUCHSIA)
+#elif BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_FUCHSIA)
return permissions::ClientFeatures_Platform_PLATFORM_MOBILE;
#else
return permissions::ClientFeatures_Platform_PLATFORM_UNSPECIFIED;
#endif
}
+ClientFeatures_PlatformEnum GetCurrentPlatformEnumProto() {
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || \
+ BUILDFLAG(IS_MAC)
+ return permissions::ClientFeatures_PlatformEnum_PLATFORM_DESKTOP_V2;
+#elif BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_FUCHSIA)
+ return permissions::ClientFeatures_PlatformEnum_PLATFORM_MOBILE_V2;
+#else
+ return permissions::ClientFeatures_PlatformEnum_PLATFORM_UNSPECIFIED_V2;
+#endif
+}
+
+ClientFeatures_Gesture ConvertToProtoGesture(
+ const permissions::PermissionRequestGestureType type) {
+ switch (type) {
+ case permissions::PermissionRequestGestureType::GESTURE:
+ return permissions::ClientFeatures_Gesture_GESTURE;
+ case permissions::PermissionRequestGestureType::NO_GESTURE:
+ return permissions::ClientFeatures_Gesture_NO_GESTURE;
+ case permissions::PermissionRequestGestureType::UNKNOWN:
+ return permissions::ClientFeatures_Gesture_GESTURE_UNSPECIFIED;
+ case permissions::PermissionRequestGestureType::NUM:
+ break;
+ }
+
+ NOTREACHED();
+ return permissions::ClientFeatures_Gesture_GESTURE_UNSPECIFIED;
+}
+
+ClientFeatures_GestureEnum ConvertToProtoGestureEnum(
+ const permissions::PermissionRequestGestureType type) {
+ switch (type) {
+ case permissions::PermissionRequestGestureType::GESTURE:
+ return permissions::ClientFeatures_GestureEnum_GESTURE_V2;
+ case permissions::PermissionRequestGestureType::NO_GESTURE:
+ case permissions::PermissionRequestGestureType::UNKNOWN:
+ return permissions::ClientFeatures_GestureEnum_GESTURE_UNSPECIFIED_V2;
+ case permissions::PermissionRequestGestureType::NUM:
+ break;
+ }
+
+ NOTREACHED();
+ return permissions::ClientFeatures_GestureEnum_GESTURE_UNSPECIFIED_V2;
+}
+
+void FillInStatsFeatures(const PredictionRequestFeatures::ActionCounts& counts,
+ StatsFeatures* features) {
+ int total_counts = counts.total();
+
+ // Round to only 2 decimal places to help prevent fingerprinting.
+ features->set_avg_deny_rate(GetRoundedRatio(counts.denies, total_counts));
+ features->set_avg_dismiss_rate(
+ GetRoundedRatio(counts.dismissals, total_counts));
+ features->set_avg_grant_rate(GetRoundedRatio(counts.grants, total_counts));
+ features->set_avg_ignore_rate(GetRoundedRatio(counts.ignores, total_counts));
+ features->set_prompts_count(BucketizeValue(total_counts));
+}
+
+std::unique_ptr<GeneratePredictionsRequest> GetPredictionRequestProto(
+ const PredictionRequestFeatures& entity) {
+ auto proto_request = std::make_unique<GeneratePredictionsRequest>();
+
+ ClientFeatures* client_features = proto_request->mutable_client_features();
+ client_features->set_platform(GetCurrentPlatformProto());
+ client_features->set_gesture(ConvertToProtoGesture(entity.gesture));
+ client_features->set_platform_enum(GetCurrentPlatformEnumProto());
+ client_features->set_gesture_enum(ConvertToProtoGestureEnum(entity.gesture));
+ FillInStatsFeatures(entity.all_permission_counts,
+ client_features->mutable_client_stats());
+
+ PermissionFeatures* permission_features =
+ proto_request->mutable_permission_features()->Add();
+ FillInStatsFeatures(entity.requested_permission_counts,
+ permission_features->mutable_permission_stats());
+
+ switch (entity.type) {
+ case RequestType::kNotifications:
+ permission_features->mutable_notification_permission()->Clear();
+ break;
+ case RequestType::kGeolocation:
+ permission_features->mutable_geolocation_permission()->Clear();
+ break;
+ default:
+ NOTREACHED()
+ << "CPSS only supports notifications and geolocation at the moment.";
+ }
+
+ return proto_request;
+}
+
constexpr char kPlatform[] = "platform";
constexpr char kGesture[] = "gesture";
+constexpr char kPlatformEnum[] = "platformEnum";
+constexpr char kGestureEnum[] = "gestureEnum";
constexpr char kAvgDenyRate[] = "avgDenyRate";
constexpr char kAvgGrantRate[] = "avgGrantRate";
constexpr char kAvgDismissRate[] = "avgDismissRate";
@@ -47,6 +161,12 @@ std::string GeneratePredictionsRequestMessageToJson(
message.client_features().platform())));
client_features.SetKey(kGesture, base::Value(ClientFeatures_Gesture_Name(
message.client_features().gesture())));
+ client_features.SetKey(kPlatformEnum,
+ base::Value(ClientFeatures_PlatformEnum_Name(
+ message.client_features().platform_enum())));
+ client_features.SetKey(kGestureEnum,
+ base::Value(ClientFeatures_GestureEnum_Name(
+ message.client_features().gesture_enum())));
base::Value client_stats(base::Value::Type::DICTIONARY);
client_stats.SetKey(
kAvgDenyRate,
@@ -115,13 +235,13 @@ GeneratePredictionsResponseJsonToMessage(std::string input) {
return message;
auto* prediction_list = parsed_message->FindListKey(kPrediction);
- if (!prediction_list || prediction_list->GetList().empty() ||
- !prediction_list->GetList()[0].is_dict()) {
+ if (!prediction_list || prediction_list->GetListDeprecated().empty() ||
+ !prediction_list->GetListDeprecated()[0].is_dict()) {
return message;
}
auto* likelihood_dict =
- prediction_list->GetList()[0].FindDictKey(kGrantLikelihood);
+ prediction_list->GetListDeprecated()[0].FindDictKey(kGrantLikelihood);
if (!likelihood_dict)
return message;
diff --git a/chromium/components/permissions/prediction_service/prediction_common.h b/chromium/components/permissions/prediction_service/prediction_common.h
new file mode 100644
index 00000000000..fdd557dd77e
--- /dev/null
+++ b/chromium/components/permissions/prediction_service/prediction_common.h
@@ -0,0 +1,73 @@
+// Copyright 2020 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.
+
+#ifndef COMPONENTS_PERMISSIONS_PREDICTION_SERVICE_PREDICTION_COMMON_H_
+#define COMPONENTS_PERMISSIONS_PREDICTION_SERVICE_PREDICTION_COMMON_H_
+
+#include "components/permissions/prediction_service/prediction_request_features.h"
+#include "components/permissions/prediction_service/prediction_service_messages.pb.h"
+
+namespace permissions {
+
+constexpr char kDefaultPredictionServiceUrl[] =
+ "https://webpermissionpredictions.googleapis.com/v1:generatePredictions";
+
+// A command line switch to override the default service url.
+constexpr char kDefaultPredictionServiceUrlSwitchKey[] =
+ "permission-predictions-service-url";
+
+constexpr float kRoundToMultiplesOf = 0.1f;
+
+constexpr int kCountBuckets[] = {20, 15, 12, 10, 9, 8, 7, 6, 5, 4};
+
+// Thresholds of the likelihood that triggers the CPSS prompts.
+constexpr float kNotificationPredictionsThreshold = 0.83;
+constexpr float kGeolocationPredictionsThreshold = 0.87;
+
+// Returns the ratio rounded to the nearest 10%. It returns a value between 0
+// and 1 in steps of 0.1
+float GetRoundedRatio(int numerator, int denominator);
+
+// This method normalises the value returned by GetRoundedRatio(int, int) for
+// sending it to ukm. It returns a value between 0 and 100 in steps of 10.
+int GetRoundedRatioForUkm(int numerator, int denominator);
+
+// Returns the appropriate bucket for `count`.
+int BucketizeValue(int count);
+
+// Get the current platform for proto message purposes.
+ClientFeatures_Platform GetCurrentPlatformProto();
+
+// Get the current platform for proto message purposes.
+ClientFeatures_PlatformEnum GetCurrentPlatformEnumProto();
+
+// Convert PermissionRequestGestureType to ClientFeatures_Gesture.
+ClientFeatures_Gesture ConvertToProtoGesture(
+ const permissions::PermissionRequestGestureType type);
+
+// Convert PermissionRequestGestureType to ClientFeatures_GestureEnum.
+ClientFeatures_GestureEnum ConvertToProtoGestureEnum(
+ const permissions::PermissionRequestGestureType type);
+
+// Fill in the values in StatsFeature using the values in
+// PredictionRequestFeatures::ActionCounts
+void FillInStatsFeatures(const PredictionRequestFeatures::ActionCounts& counts,
+ StatsFeatures* features);
+
+std::unique_ptr<GeneratePredictionsRequest> GetPredictionRequestProto(
+ const PredictionRequestFeatures& entity);
+
+// Convert a GeneratePredictionsRequest from Message to Json String.
+// Returns empty string if the conversion is unsuccessful.
+std::string GeneratePredictionsRequestMessageToJson(
+ const GeneratePredictionsRequest&);
+
+// Convert a GeneratePredictionsResponse from Json String to Message.
+// Returns nullptr if the conversion is unsuccessful.
+std::unique_ptr<GeneratePredictionsResponse>
+ GeneratePredictionsResponseJsonToMessage(std::string);
+
+} // namespace permissions
+
+#endif // COMPONENTS_PERMISSIONS_PREDICTION_SERVICE_PREDICTION_COMMON_H_
diff --git a/chromium/components/permissions/prediction_service/prediction_model_executor.cc b/chromium/components/permissions/prediction_service/prediction_model_executor.cc
new file mode 100644
index 00000000000..1eaa2500446
--- /dev/null
+++ b/chromium/components/permissions/prediction_service/prediction_model_executor.cc
@@ -0,0 +1,147 @@
+// Copyright 2021 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.
+
+#include "components/permissions/prediction_service/prediction_model_executor.h"
+
+#include "base/notreached.h"
+#include "components/permissions/prediction_service/prediction_common.h"
+#include "components/permissions/prediction_service/prediction_request_features.h"
+#include "third_party/tflite_support/src/tensorflow_lite_support/cc/task/core/task_utils.h"
+
+namespace permissions {
+
+PredictionModelExecutor::PredictionModelExecutor() = default;
+PredictionModelExecutor::~PredictionModelExecutor() = default;
+
+bool PredictionModelExecutor::Preprocess(
+ const std::vector<TfLiteTensor*>& input_tensors,
+ const GeneratePredictionsRequest& input) {
+ switch (input.permission_features()[0].permission_type_case()) {
+ case PermissionFeatures::kNotificationPermission:
+ request_type_ = RequestType::kNotifications;
+ break;
+ case PermissionFeatures::kGeolocationPermission:
+ request_type_ = RequestType::kGeolocation;
+ break;
+ default:
+ NOTREACHED();
+ }
+
+ if (!tflite::task::core::PopulateTensor<float>(
+ input.client_features().client_stats().avg_deny_rate(),
+ input_tensors[0])
+ .ok()) {
+ return false;
+ }
+
+ if (!tflite::task::core::PopulateTensor<float>(
+ input.client_features().client_stats().avg_dismiss_rate(),
+ input_tensors[1])
+ .ok()) {
+ return false;
+ }
+
+ if (!tflite::task::core::PopulateTensor<float>(
+ input.client_features().client_stats().avg_grant_rate(),
+ input_tensors[2])
+ .ok()) {
+ return false;
+ }
+
+ if (!tflite::task::core::PopulateTensor<float>(
+ input.client_features().client_stats().avg_ignore_rate(),
+ input_tensors[3])
+ .ok()) {
+ return false;
+ }
+
+ if (!tflite::task::core::PopulateTensor<float>(
+ input.permission_features()[0].permission_stats().avg_deny_rate(),
+ input_tensors[4])
+ .ok()) {
+ return false;
+ }
+
+ if (!tflite::task::core::PopulateTensor<float>(
+ input.permission_features()[0].permission_stats().avg_dismiss_rate(),
+ input_tensors[5])
+ .ok()) {
+ return false;
+ }
+
+ if (!tflite::task::core::PopulateTensor<float>(
+ input.permission_features()[0].permission_stats().avg_grant_rate(),
+ input_tensors[6])
+ .ok()) {
+ return false;
+ }
+
+ if (!tflite::task::core::PopulateTensor<float>(
+ input.permission_features()[0].permission_stats().avg_ignore_rate(),
+ input_tensors[7])
+ .ok()) {
+ return false;
+ }
+
+ if (!tflite::task::core::PopulateTensor<int64_t>(
+ static_cast<int64_t>(input.permission_features()[0]
+ .permission_stats()
+ .prompts_count()),
+ input_tensors[8])
+ .ok()) {
+ return false;
+ }
+
+ if (!tflite::task::core::PopulateTensor<int64_t>(
+ static_cast<int64_t>(
+ input.client_features().client_stats().prompts_count()),
+ input_tensors[9])
+ .ok()) {
+ return false;
+ }
+
+ if (!tflite::task::core::PopulateTensor<int64_t>(
+ static_cast<int64_t>(input.client_features().gesture_enum()),
+ input_tensors[10])
+ .ok()) {
+ return false;
+ }
+
+ if (!tflite::task::core::PopulateTensor<int64_t>(
+ static_cast<int64_t>(input.client_features().platform_enum()),
+ input_tensors[11])
+ .ok()) {
+ return false;
+ }
+
+ return true;
+}
+
+absl::optional<GeneratePredictionsResponse>
+PredictionModelExecutor::Postprocess(
+ const std::vector<const TfLiteTensor*>& output_tensors) {
+ DCHECK(request_type_ == RequestType::kNotifications ||
+ request_type_ == RequestType::kGeolocation);
+ std::vector<float> data;
+ if (!tflite::task::core::PopulateVector<float>(output_tensors[0], &data)
+ .ok()) {
+ return absl::nullopt;
+ }
+
+ GeneratePredictionsResponse response;
+ float threshold = request_type_ == RequestType::kNotifications
+ ? kNotificationPredictionsThreshold
+ : kGeolocationPredictionsThreshold;
+ response.mutable_prediction()
+ ->Add()
+ ->mutable_grant_likelihood()
+ ->set_discretized_likelihood(
+ data[1] >= threshold
+ ? PermissionPrediction_Likelihood_DiscretizedLikelihood_VERY_UNLIKELY
+ : PermissionPrediction_Likelihood_DiscretizedLikelihood_DISCRETIZED_LIKELIHOOD_UNSPECIFIED);
+
+ return response;
+}
+
+} // namespace permissions
diff --git a/chromium/components/permissions/prediction_service/prediction_model_executor.h b/chromium/components/permissions/prediction_service/prediction_model_executor.h
new file mode 100644
index 00000000000..f3f84a91f2a
--- /dev/null
+++ b/chromium/components/permissions/prediction_service/prediction_model_executor.h
@@ -0,0 +1,39 @@
+// Copyright 2021 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.
+
+#ifndef COMPONENTS_PERMISSIONS_PREDICTION_SERVICE_PREDICTION_MODEL_EXECUTOR_H_
+#define COMPONENTS_PERMISSIONS_PREDICTION_SERVICE_PREDICTION_MODEL_EXECUTOR_H_
+
+#include <vector>
+
+#include "components/optimization_guide/core/base_model_executor.h"
+#include "components/permissions/prediction_service/prediction_request_features.h"
+#include "components/permissions/prediction_service/prediction_service_messages.pb.h"
+
+namespace permissions {
+
+class PredictionModelExecutor : public optimization_guide::BaseModelExecutor<
+ GeneratePredictionsResponse,
+ const GeneratePredictionsRequest&> {
+ public:
+ PredictionModelExecutor();
+ ~PredictionModelExecutor() override;
+
+ PredictionModelExecutor(const PredictionModelExecutor&) = delete;
+ PredictionModelExecutor& operator=(const PredictionModelExecutor&) = delete;
+
+ protected:
+ // optimization_guide::BaseModelExecutor:
+ bool Preprocess(const std::vector<TfLiteTensor*>& input_tensors,
+ const GeneratePredictionsRequest& input) override;
+
+ absl::optional<GeneratePredictionsResponse> Postprocess(
+ const std::vector<const TfLiteTensor*>& output_tensors) override;
+
+ private:
+ RequestType request_type_;
+};
+
+} // namespace permissions
+#endif // COMPONENTS_PERMISSIONS_PREDICTION_SERVICE_PREDICTION_MODEL_EXECUTOR_H_
diff --git a/chromium/components/permissions/prediction_service/prediction_model_handler.cc b/chromium/components/permissions/prediction_service/prediction_model_handler.cc
new file mode 100644
index 00000000000..0dbbc3f7acd
--- /dev/null
+++ b/chromium/components/permissions/prediction_service/prediction_model_handler.cc
@@ -0,0 +1,35 @@
+// Copyright 2021 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.
+
+#include "components/permissions/prediction_service/prediction_model_handler.h"
+
+#include <memory>
+
+#include "base/task/sequenced_task_runner.h"
+#include "base/task/task_traits.h"
+#include "base/task/thread_pool.h"
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "components/optimization_guide/core/optimization_guide_model_provider.h"
+#include "components/optimization_guide/proto/models.pb.h"
+#include "components/permissions/prediction_service/prediction_model_executor.h"
+#include "components/permissions/prediction_service/prediction_request_features.h"
+#include "content/public/browser/browser_context.h"
+
+namespace permissions {
+
+PredictionModelHandler::PredictionModelHandler(
+ optimization_guide::OptimizationGuideModelProvider* model_provider,
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner)
+ : ModelHandler<GeneratePredictionsResponse,
+ const GeneratePredictionsRequest&>(
+ model_provider,
+ background_task_runner,
+ std::make_unique<PredictionModelExecutor>(),
+ optimization_guide::proto::OptimizationTarget::
+ OPTIMIZATION_TARGET_NOTIFICATION_PERMISSION_PREDICTIONS,
+ absl::nullopt) {}
+
+} // namespace permissions
diff --git a/chromium/components/permissions/prediction_service/prediction_model_handler.h b/chromium/components/permissions/prediction_service/prediction_model_handler.h
new file mode 100644
index 00000000000..ad57b6a3866
--- /dev/null
+++ b/chromium/components/permissions/prediction_service/prediction_model_handler.h
@@ -0,0 +1,29 @@
+// Copyright 2021 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.
+
+#ifndef COMPONENTS_PERMISSIONS_PREDICTION_SERVICE_PREDICTION_MODEL_HANDLER_H_
+#define COMPONENTS_PERMISSIONS_PREDICTION_SERVICE_PREDICTION_MODEL_HANDLER_H_
+
+#include "components/keyed_service/core/keyed_service.h"
+#include "components/optimization_guide/core/model_handler.h"
+#include "components/permissions/prediction_service/prediction_model_executor.h"
+#include "components/permissions/prediction_service/prediction_service_messages.pb.h"
+
+namespace permissions {
+class PredictionModelHandler : public KeyedService,
+ public optimization_guide::ModelHandler<
+ GeneratePredictionsResponse,
+ const GeneratePredictionsRequest&> {
+ public:
+ explicit PredictionModelHandler(
+ optimization_guide::OptimizationGuideModelProvider* model_provider,
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner);
+
+ ~PredictionModelHandler() override = default;
+ PredictionModelHandler(const PredictionModelHandler&) = delete;
+ PredictionModelHandler& operator=(const PredictionModelHandler&) = delete;
+};
+
+} // namespace permissions
+#endif // COMPONENTS_PERMISSIONS_PREDICTION_SERVICE_PREDICTION_MODEL_HANDLER_H_
diff --git a/chromium/components/permissions/prediction_service/prediction_service.cc b/chromium/components/permissions/prediction_service/prediction_service.cc
index 4bd63e970e1..96d36e1c06e 100644
--- a/chromium/components/permissions/prediction_service/prediction_service.cc
+++ b/chromium/components/permissions/prediction_service/prediction_service.cc
@@ -13,8 +13,8 @@
#include "base/no_destructor.h"
#include "base/notreached.h"
#include "components/permissions/features.h"
+#include "components/permissions/prediction_service/prediction_common.h"
#include "components/permissions/prediction_service/prediction_request_features.h"
-#include "components/permissions/prediction_service/prediction_service_common.h"
#include "components/permissions/prediction_service/prediction_service_messages.pb.h"
#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
@@ -30,45 +30,6 @@ namespace {
constexpr base::TimeDelta kURLLookupTimeout = base::Seconds(2);
-constexpr float kRoundToMultiplesOf = 0.1f;
-
-constexpr int kCountBuckets[] = {20, 15, 12, 10, 9, 8, 7, 6, 5, 4};
-
-permissions::ClientFeatures_Gesture ConvertToProtoGesture(
- const permissions::PermissionRequestGestureType type) {
- switch (type) {
- case permissions::PermissionRequestGestureType::GESTURE:
- return permissions::ClientFeatures_Gesture_GESTURE;
- case permissions::PermissionRequestGestureType::NO_GESTURE:
- return permissions::ClientFeatures_Gesture_NO_GESTURE;
- case permissions::PermissionRequestGestureType::UNKNOWN:
- return permissions::ClientFeatures_Gesture_GESTURE_UNSPECIFIED;
- case permissions::PermissionRequestGestureType::NUM:
- break;
- }
-
- NOTREACHED();
- return permissions::ClientFeatures_Gesture_GESTURE_UNSPECIFIED;
-}
-
-void FillInStatsFeatures(
- const permissions::PredictionRequestFeatures::ActionCounts& counts,
- permissions::StatsFeatures* features) {
- using PredictionService = permissions::PredictionService;
- int total_counts = counts.total();
-
- // Round to only 2 decimal places to help prevent fingerprinting.
- features->set_avg_deny_rate(
- PredictionService::GetRoundedRatio(counts.denies, total_counts));
- features->set_avg_dismiss_rate(
- PredictionService::GetRoundedRatio(counts.dismissals, total_counts));
- features->set_avg_grant_rate(
- PredictionService::GetRoundedRatio(counts.grants, total_counts));
- features->set_avg_ignore_rate(
- PredictionService::GetRoundedRatio(counts.ignores, total_counts));
- features->set_prompts_count(PredictionService::BucketizeValue(total_counts));
-}
-
net::NetworkTrafficAnnotationTag GetTrafficAnnotationTag() {
return net::DefineNetworkTrafficAnnotation("permission_predictions", R"(
semantics {
@@ -180,37 +141,6 @@ PredictionService::GetResourceRequest() {
return request;
}
-std::unique_ptr<GeneratePredictionsRequest>
-PredictionService::GetPredictionRequestProto(
- const PredictionRequestFeatures& entity) {
- auto proto_request = std::make_unique<GeneratePredictionsRequest>();
-
- ClientFeatures* client_features = proto_request->mutable_client_features();
- client_features->set_platform(GetCurrentPlatformProto());
- client_features->set_gesture(ConvertToProtoGesture(entity.gesture));
- FillInStatsFeatures(entity.all_permission_counts,
- client_features->mutable_client_stats());
-
- PermissionFeatures* permission_features =
- proto_request->mutable_permission_features()->Add();
- FillInStatsFeatures(entity.requested_permission_counts,
- permission_features->mutable_permission_stats());
-
- switch (entity.type) {
- case RequestType::kNotifications:
- permission_features->mutable_notification_permission()->Clear();
- break;
- case RequestType::kGeolocation:
- permission_features->mutable_geolocation_permission()->Clear();
- break;
- default:
- NOTREACHED()
- << "CPSS only supports notifications and geolocation at the moment.";
- }
-
- return proto_request;
-}
-
void PredictionService::SendRequestInternal(
std::unique_ptr<network::ResourceRequest> request,
const std::string& request_data,
@@ -245,10 +175,15 @@ void PredictionService::OnURLLoaderComplete(
CreatePredictionsResponse(loader, response_body.get());
if (request.second) {
+ absl::optional<GeneratePredictionsResponse> response;
+ if (prediction_response == nullptr) {
+ response = absl::nullopt;
+ } else {
+ response = *prediction_response;
+ }
bool lookup_success = prediction_response != nullptr;
std::move(request.second)
- .Run(lookup_success, false /* Response from cache */,
- std::move(prediction_response));
+ .Run(lookup_success, /*Response from cache=*/false, response);
}
pending_requests_.erase(request.first);
@@ -281,26 +216,4 @@ PredictionService::CreatePredictionsResponse(network::SimpleURLLoader* loader,
return predictions_response;
}
-// static
-float PredictionService::GetRoundedRatio(int numerator, int denominator) {
- if (denominator == 0)
- return 0;
- return roundf(numerator / kRoundToMultiplesOf / denominator) *
- kRoundToMultiplesOf;
-}
-
-// static
-int PredictionService::GetRoundedRatioForUkm(int numerator, int denominator) {
- return GetRoundedRatio(numerator, denominator) * 100;
-}
-
-// static
-int PredictionService::BucketizeValue(int count) {
- for (const int bucket : kCountBuckets) {
- if (count >= bucket)
- return bucket;
- }
- return 0;
-}
-
} // namespace permissions
diff --git a/chromium/components/permissions/prediction_service/prediction_service.h b/chromium/components/permissions/prediction_service/prediction_service.h
index c8a40588053..8717805fb74 100644
--- a/chromium/components/permissions/prediction_service/prediction_service.h
+++ b/chromium/components/permissions/prediction_service/prediction_service.h
@@ -11,7 +11,6 @@
#include "base/callback.h"
#include "components/keyed_service/core/keyed_service.h"
#include "components/permissions/permission_request_enums.h"
-#include "components/permissions/prediction_service/prediction_request_features.h"
#include "components/permissions/prediction_service/prediction_service_base.h"
#include "components/permissions/prediction_service/prediction_service_messages.pb.h"
#include "services/network/public/cpp/resource_request.h"
@@ -51,22 +50,10 @@ class PredictionService : public PredictionServiceBase {
recalculate_service_url_every_time = true;
}
- // Returns the ratio rounded to the nearest 10%. It returns a value between 0
- // and 1 in steps of 0.1
- static float GetRoundedRatio(int numerator, int denominator);
-
- // This method normalises the value returned by GetRoundedRatio(int, int) for
- // sending it to ukm. It returns a value between 0 and 100 in steps of 10.
- static int GetRoundedRatioForUkm(int numerator, int denominator);
-
- // Returns the appropriate bucket for `count`.
- static int BucketizeValue(int count);
-
private:
static const GURL GetPredictionServiceUrl(bool recalculate_for_testing);
std::unique_ptr<network::ResourceRequest> GetResourceRequest();
- std::unique_ptr<GeneratePredictionsRequest> GetPredictionRequestProto(
- const PredictionRequestFeatures& entity);
+
void SendRequestInternal(std::unique_ptr<network::ResourceRequest> request,
const std::string& request_data,
const PredictionRequestFeatures& entity,
diff --git a/chromium/components/permissions/prediction_service/prediction_service_base.h b/chromium/components/permissions/prediction_service/prediction_service_base.h
index 42572412063..4c28b6b77de 100644
--- a/chromium/components/permissions/prediction_service/prediction_service_base.h
+++ b/chromium/components/permissions/prediction_service/prediction_service_base.h
@@ -28,10 +28,10 @@ class PredictionServiceBase : public KeyedService {
base::OnceCallback<void(std::unique_ptr<GeneratePredictionsRequest>,
std::string)>; // Access token.
- using LookupResponseCallback =
- base::OnceCallback<void(bool, // Lookup successful.
- bool, // Response from cache.
- std::unique_ptr<GeneratePredictionsResponse>)>;
+ using LookupResponseCallback = base::OnceCallback<void(
+ bool, // Lookup successful.
+ bool, // Response from cache.
+ const absl::optional<GeneratePredictionsResponse>&)>;
virtual void StartLookup(const PredictionRequestFeatures& entity,
LookupRequestCallback request_callback,
diff --git a/chromium/components/permissions/prediction_service/prediction_service_common.h b/chromium/components/permissions/prediction_service/prediction_service_common.h
deleted file mode 100644
index 5e7453dc179..00000000000
--- a/chromium/components/permissions/prediction_service/prediction_service_common.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2020 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.
-
-#ifndef COMPONENTS_PERMISSIONS_PREDICTION_SERVICE_PREDICTION_SERVICE_COMMON_H_
-#define COMPONENTS_PERMISSIONS_PREDICTION_SERVICE_PREDICTION_SERVICE_COMMON_H_
-
-#include "components/permissions/prediction_service/prediction_service_messages.pb.h"
-
-namespace permissions {
-
-// TODO(andypaicu): when available, replace with actual URL.
-constexpr char kDefaultPredictionServiceUrl[] =
- "https://webpermissionpredictions.googleapis.com/v1:generatePredictions";
-
-// A command line switch to override the default service url.
-constexpr char kDefaultPredictionServiceUrlSwitchKey[] =
- "permission-predictions-service-url";
-
-// Get the current platform for proto message purposes.
-ClientFeatures_Platform GetCurrentPlatformProto();
-
-// Convert a GeneratePredictionsRequest from Message to Json String.
-// Returns empty string if the conversion is unsuccessful.
-std::string GeneratePredictionsRequestMessageToJson(
- const GeneratePredictionsRequest&);
-
-// Convert a GeneratePredictionsResponse from Json String to Message.
-// Returns nullptr if the conversion is unsuccessful.
-std::unique_ptr<GeneratePredictionsResponse>
- GeneratePredictionsResponseJsonToMessage(std::string);
-
-} // namespace permissions
-
-#endif // COMPONENTS_PERMISSIONS_PREDICTION_SERVICE_PREDICTION_SERVICE_COMMON_H_
diff --git a/chromium/components/permissions/prediction_service/prediction_service_messages.proto b/chromium/components/permissions/prediction_service/prediction_service_messages.proto
index 22ebe6741c2..6c0178aea80 100644
--- a/chromium/components/permissions/prediction_service/prediction_service_messages.proto
+++ b/chromium/components/permissions/prediction_service/prediction_service_messages.proto
@@ -55,6 +55,21 @@ message ClientFeatures {
// The type of gesture performed by the user on the page before the permission
// prompt was shown.
optional Gesture gesture = 3;
+
+ enum GestureEnum {
+ GESTURE_V2 = 0;
+ GESTURE_UNSPECIFIED_V2 = 1;
+ }
+
+ optional GestureEnum gesture_enum = 4;
+
+ enum PlatformEnum {
+ PLATFORM_MOBILE_V2 = 0;
+ PLATFORM_DESKTOP_V2 = 1;
+ PLATFORM_UNSPECIFIED_V2 = 3;
+ }
+
+ optional PlatformEnum platform_enum = 5;
}
// Features related to a specific permission type.
diff --git a/chromium/components/permissions/prediction_service/prediction_service_unittest.cc b/chromium/components/permissions/prediction_service/prediction_service_unittest.cc
index 0b296d510ad..94f49a12251 100644
--- a/chromium/components/permissions/prediction_service/prediction_service_unittest.cc
+++ b/chromium/components/permissions/prediction_service/prediction_service_unittest.cc
@@ -16,8 +16,8 @@
#include "base/time/time.h"
#include "components/permissions/features.h"
#include "components/permissions/permission_request_enums.h"
+#include "components/permissions/prediction_service/prediction_common.h"
#include "components/permissions/prediction_service/prediction_request_features.h"
-#include "components/permissions/prediction_service/prediction_service_common.h"
#include "components/permissions/prediction_service/prediction_service_messages.pb.h"
#include "components/permissions/request_type.h"
#include "google/protobuf/message_lite.h"
@@ -103,8 +103,12 @@ void InitializeProtoHelperObjects() {
->set_prompts_count(0);
kRequestAllCountsZero.mutable_client_features()->set_platform(
permissions::GetCurrentPlatformProto());
+ kRequestAllCountsZero.mutable_client_features()->set_platform_enum(
+ permissions::GetCurrentPlatformEnumProto());
kRequestAllCountsZero.mutable_client_features()->set_gesture(
permissions::ClientFeatures_Gesture_GESTURE);
+ kRequestAllCountsZero.mutable_client_features()->set_gesture_enum(
+ permissions::ClientFeatures_GestureEnum_GESTURE_V2);
kRequestAllCountsZero.mutable_permission_features()->Clear();
auto* permission_feature =
kRequestAllCountsZero.mutable_permission_features()->Add();
@@ -132,8 +136,12 @@ void InitializeProtoHelperObjects() {
->set_prompts_count(20);
kRequestRoundedCounts.mutable_client_features()->set_platform(
permissions::GetCurrentPlatformProto());
+ kRequestRoundedCounts.mutable_client_features()->set_platform_enum(
+ permissions::GetCurrentPlatformEnumProto());
kRequestRoundedCounts.mutable_client_features()->set_gesture(
permissions::ClientFeatures_Gesture_NO_GESTURE);
+ kRequestRoundedCounts.mutable_client_features()->set_gesture_enum(
+ permissions::ClientFeatures_GestureEnum_GESTURE_UNSPECIFIED_V2);
kRequestRoundedCounts.mutable_permission_features()->Clear();
permission_feature =
kRequestRoundedCounts.mutable_permission_features()->Add();
@@ -161,8 +169,12 @@ void InitializeProtoHelperObjects() {
->set_prompts_count(20);
kRequestEqualCountsTotal20.mutable_client_features()->set_platform(
permissions::GetCurrentPlatformProto());
+ kRequestEqualCountsTotal20.mutable_client_features()->set_platform_enum(
+ permissions::GetCurrentPlatformEnumProto());
kRequestEqualCountsTotal20.mutable_client_features()->set_gesture(
permissions::ClientFeatures_Gesture_GESTURE);
+ kRequestEqualCountsTotal20.mutable_client_features()->set_gesture_enum(
+ permissions::ClientFeatures_GestureEnum_GESTURE_V2);
kRequestEqualCountsTotal20.mutable_permission_features()->Clear();
permission_feature =
kRequestEqualCountsTotal20.mutable_permission_features()->Add();
@@ -190,8 +202,12 @@ void InitializeProtoHelperObjects() {
->set_prompts_count(20);
kRequestDifferentCounts.mutable_client_features()->set_platform(
permissions::GetCurrentPlatformProto());
+ kRequestDifferentCounts.mutable_client_features()->set_platform_enum(
+ permissions::GetCurrentPlatformEnumProto());
kRequestDifferentCounts.mutable_client_features()->set_gesture(
permissions::ClientFeatures_Gesture_NO_GESTURE);
+ kRequestDifferentCounts.mutable_client_features()->set_gesture_enum(
+ permissions::ClientFeatures_GestureEnum_GESTURE_UNSPECIFIED_V2);
kRequestDifferentCounts.mutable_permission_features()->Clear();
permission_feature =
kRequestDifferentCounts.mutable_permission_features()->Add();
@@ -277,11 +293,12 @@ class PredictionServiceTest : public testing::Test {
EXPECT_EQ(std::string(), access_token);
}
- void ResponseCallback(base::RunLoop* response_loop,
- bool lookup_successful,
- bool response_from_cache,
- std::unique_ptr<GeneratePredictionsResponse> response) {
- received_responses_.emplace_back(std::move(response));
+ void ResponseCallback(
+ base::RunLoop* response_loop,
+ bool lookup_successful,
+ bool response_from_cache,
+ const absl::optional<GeneratePredictionsResponse>& response) {
+ received_responses_.emplace_back(response);
if (response_loop)
response_loop->Quit();
@@ -291,7 +308,7 @@ class PredictionServiceTest : public testing::Test {
protected:
std::vector<std::unique_ptr<GeneratePredictionsRequest>> received_requests_;
- std::vector<std::unique_ptr<GeneratePredictionsResponse>> received_responses_;
+ std::vector<absl::optional<GeneratePredictionsResponse>> received_responses_;
std::unique_ptr<PredictionService> prediction_service_;
// Different paths to simulate different server behaviours.
@@ -497,7 +514,7 @@ TEST_F(PredictionServiceTest, HandleSimultaneousRequests) {
response_loop.Run();
EXPECT_EQ(2u, received_responses_.size());
- EXPECT_TRUE(received_responses_[1].get() != nullptr);
+ EXPECT_TRUE(received_responses_[1]);
EXPECT_EQ(kResponseLikely.SerializeAsString(),
received_responses_[1]->SerializeAsString());
EXPECT_EQ(0u, prediction_service_->pending_requests_for_testing().size());
@@ -524,13 +541,16 @@ TEST_F(PredictionServiceTest, TestJsonConversions) {
std::string kPlatformName =
ClientFeatures_Platform_Name(permissions::GetCurrentPlatformProto());
+ std::string kPlatformEnumName = ClientFeatures_PlatformEnum_Name(
+ permissions::GetCurrentPlatformEnumProto());
+
std::string expected_round_counts =
"{\"clientFeatures\":{\"clientStats\":{\"avgDenyRate\":0."
"20000000298023224,\"avgDismissRate\":0.20000000298023224,"
"\"avgGrantRate\":0.30000001192092896,\"avgIgnoreRate\":0."
"20000000298023224,\"promptsCount\":20},\"gesture\":\"NO_GESTURE\","
- "\"platform\":\"" +
- kPlatformName +
+ "\"gestureEnum\":\"GESTURE_UNSPECIFIED_V2\",\"platform\":\"" +
+ kPlatformName + "\",\"platformEnum\":\"" + kPlatformEnumName +
"\"},\"permissionFeatures\":[{\"notificationPermission\":{},"
"\"permissionStats\":{\"avgDenyRate\":0.20000000298023224,"
"\"avgDismissRate\":0.20000000298023224,\"avgGrantRate\":0."
@@ -542,8 +562,8 @@ TEST_F(PredictionServiceTest, TestJsonConversions) {
"30000001192092896,\"avgDismissRate\":0.30000001192092896,"
"\"avgGrantRate\":0.30000001192092896,\"avgIgnoreRate\":0."
"30000001192092896,\"promptsCount\":20},\"gesture\":\"GESTURE\","
- "\"platform\":\"" +
- kPlatformName +
+ "\"gestureEnum\":\"GESTURE_V2\",\"platform\":\"" +
+ kPlatformName + "\",\"platformEnum\":\"" + kPlatformEnumName +
"\"},\"permissionFeatures\":[{\"notificationPermission\":{},"
"\"permissionStats\":{\"avgDenyRate\":0.30000001192092896,"
"\"avgDismissRate\":0.30000001192092896,\"avgGrantRate\":0."
@@ -555,8 +575,8 @@ TEST_F(PredictionServiceTest, TestJsonConversions) {
"30000001192092896,\"avgDismissRate\":0.30000001192092896,"
"\"avgGrantRate\":0.30000001192092896,\"avgIgnoreRate\":0."
"30000001192092896,\"promptsCount\":20},\"gesture\":\"NO_GESTURE\","
- "\"platform\":\"" +
- kPlatformName +
+ "\"gestureEnum\":\"GESTURE_UNSPECIFIED_V2\",\"platform\":\"" +
+ kPlatformName + "\",\"platformEnum\":\"" + kPlatformEnumName +
"\"},\"permissionFeatures\":[{\"notificationPermission\":{},"
"\"permissionStats\":{\"avgDenyRate\":0.0,\"avgDismissRate\":0.0,"
"\"avgGrantRate\":0.0,\"avgIgnoreRate\":0.0,\"promptsCount\":0}}]}";
@@ -564,8 +584,9 @@ TEST_F(PredictionServiceTest, TestJsonConversions) {
std::string expected_zero_counts =
"{\"clientFeatures\":{\"clientStats\":{\"avgDenyRate\":0.0,"
"\"avgDismissRate\":0.0,\"avgGrantRate\":0.0,\"avgIgnoreRate\":0.0,"
- "\"promptsCount\":0},\"gesture\":\"GESTURE\",\"platform\":\"" +
- kPlatformName +
+ "\"promptsCount\":0},\"gesture\":\"GESTURE\","
+ "\"gestureEnum\":\"GESTURE_V2\",\"platform\":\"" +
+ kPlatformName + "\",\"platformEnum\":\"" + kPlatformEnumName +
"\"},\"permissionFeatures\":[{\"notificationPermission\":{},"
"\"permissionStats\":{\"avgDenyRate\":0.0,\"avgDismissRate\":0.0,"
"\"avgGrantRate\":0.0,\"avgIgnoreRate\":0.0,\"promptsCount\":0}}]}";
diff --git a/chromium/components/permissions/pref_names.cc b/chromium/components/permissions/pref_names.cc
index 7b6f4ce6421..e3e408da703 100644
--- a/chromium/components/permissions/pref_names.cc
+++ b/chromium/components/permissions/pref_names.cc
@@ -4,6 +4,8 @@
#include "components/permissions/pref_names.h"
+#include "build/build_config.h"
+
namespace permissions {
namespace prefs {
@@ -11,7 +13,7 @@ namespace prefs {
// types.
const char kPermissionActions[] = "profile.content_settings.permission_actions";
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// The current level of backoff for showing the location settings dialog for the
// default search engine.
const char kLocationSettingsBackoffLevelDSE[] =
diff --git a/chromium/components/permissions/pref_names.h b/chromium/components/permissions/pref_names.h
index c0b798259ff..c588ade8d82 100644
--- a/chromium/components/permissions/pref_names.h
+++ b/chromium/components/permissions/pref_names.h
@@ -11,7 +11,7 @@ namespace permissions {
namespace prefs {
extern const char kPermissionActions[];
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
extern const char kLocationSettingsBackoffLevelDSE[];
extern const char kLocationSettingsBackoffLevelDefault[];
extern const char kLocationSettingsNextShowDSE[];
diff --git a/chromium/components/permissions/quota_permission_context_impl.cc b/chromium/components/permissions/quota_permission_context_impl.cc
index 3b8b4718c88..2b58608f90b 100644
--- a/chromium/components/permissions/quota_permission_context_impl.cc
+++ b/chromium/components/permissions/quota_permission_context_impl.cc
@@ -25,7 +25,7 @@
#include "ui/base/l10n/l10n_util.h"
#include "url/gurl.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "components/resources/android/theme_resources.h"
#else
#include "components/vector_icons/vector_icons.h"
@@ -55,7 +55,7 @@ class QuotaPermissionRequest : public PermissionRequest {
// PermissionRequest:
bool IsDuplicateOf(PermissionRequest* other_request) const override;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
std::u16string GetDialogMessageText() const override;
#endif
@@ -97,7 +97,7 @@ bool QuotaPermissionRequest::IsDuplicateOf(
->is_large_quota_request_;
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
std::u16string QuotaPermissionRequest::GetDialogMessageText() const {
// If the site requested larger quota than this threshold, show a different
// message to the user.
@@ -106,7 +106,7 @@ std::u16string QuotaPermissionRequest::GetDialogMessageText() const {
: IDS_REQUEST_QUOTA_INFOBAR_TEXT),
url_formatter::FormatUrlForSecurityDisplay(requesting_origin()));
}
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
void QuotaPermissionRequest::PermissionDecided(ContentSetting result,
bool is_one_time) {
diff --git a/chromium/components/permissions/request_type.cc b/chromium/components/permissions/request_type.cc
index cbefa8fb1c5..0fd73f5e338 100644
--- a/chromium/components/permissions/request_type.cc
+++ b/chromium/components/permissions/request_type.cc
@@ -6,23 +6,24 @@
#include "base/check.h"
#include "base/notreached.h"
+#include "build/build_config.h"
#include "components/content_settings/core/common/content_settings_types.h"
#include "components/permissions/permissions_client.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "components/resources/android/theme_resources.h"
#else
#include "components/permissions/vector_icons/vector_icons.h"
#include "components/vector_icons/vector_icons.h"
#include "ui/gfx/paint_vector_icon.h"
#include "ui/gfx/vector_icon_types.h"
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
namespace permissions {
namespace {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
int GetIconIdAndroid(RequestType type) {
switch (type) {
case RequestType::kAccessibilityEvents:
@@ -58,9 +59,9 @@ int GetIconIdAndroid(RequestType type) {
NOTREACHED();
return 0;
}
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
const gfx::VectorIcon& GetIconIdDesktop(RequestType type) {
switch (type) {
case RequestType::kAccessibilityEvents:
@@ -89,7 +90,7 @@ const gfx::VectorIcon& GetIconIdDesktop(RequestType type) {
return vector_icons::kFileDownloadIcon;
case RequestType::kNotifications:
return vector_icons::kNotificationsIcon;
-#if defined(OS_CHROMEOS) || defined(OS_WIN)
+#if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN)
case RequestType::kProtectedMediaIdentifier:
// This icon is provided by ChromePermissionsClient::GetOverrideIconId.
NOTREACHED();
@@ -135,7 +136,7 @@ const gfx::VectorIcon& GetBlockedIconIdDesktop(RequestType type) {
NOTREACHED();
return gfx::kNoneIcon;
}
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
absl::optional<RequestType> ContentSettingsTypeToRequestTypeIfExists(
ContentSettingsType content_settings_type) {
@@ -144,7 +145,7 @@ absl::optional<RequestType> ContentSettingsTypeToRequestTypeIfExists(
return RequestType::kAccessibilityEvents;
case ContentSettingsType::AR:
return RequestType::kArSession;
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
case ContentSettingsType::CAMERA_PAN_TILT_ZOOM:
return RequestType::kCameraPanTiltZoom;
#endif
@@ -152,7 +153,7 @@ absl::optional<RequestType> ContentSettingsTypeToRequestTypeIfExists(
return RequestType::kCameraStream;
case ContentSettingsType::CLIPBOARD_READ_WRITE:
return RequestType::kClipboard;
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
case ContentSettingsType::FONT_ACCESS:
return RequestType::kFontAccess;
#endif
@@ -166,11 +167,11 @@ absl::optional<RequestType> ContentSettingsTypeToRequestTypeIfExists(
return RequestType::kMidiSysex;
case ContentSettingsType::NOTIFICATIONS:
return RequestType::kNotifications;
-#if defined(OS_ANDROID) || defined(OS_CHROMEOS) || defined(OS_WIN)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN)
case ContentSettingsType::PROTECTED_MEDIA_IDENTIFIER:
return RequestType::kProtectedMediaIdentifier;
#endif
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
case ContentSettingsType::NFC:
return RequestType::kNfcDevice;
#endif
@@ -178,7 +179,7 @@ absl::optional<RequestType> ContentSettingsTypeToRequestTypeIfExists(
return RequestType::kStorageAccess;
case ContentSettingsType::VR:
return RequestType::kVrSession;
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
case ContentSettingsType::WINDOW_PLACEMENT:
return RequestType::kWindowPlacement;
#endif
@@ -208,7 +209,7 @@ absl::optional<ContentSettingsType> RequestTypeToContentSettingsType(
return ContentSettingsType::ACCESSIBILITY_EVENTS;
case RequestType::kArSession:
return ContentSettingsType::AR;
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
case RequestType::kCameraPanTiltZoom:
return ContentSettingsType::CAMERA_PAN_TILT_ZOOM;
#endif
@@ -216,7 +217,7 @@ absl::optional<ContentSettingsType> RequestTypeToContentSettingsType(
return ContentSettingsType::MEDIASTREAM_CAMERA;
case RequestType::kClipboard:
return ContentSettingsType::CLIPBOARD_READ_WRITE;
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
case RequestType::kFontAccess:
return ContentSettingsType::FONT_ACCESS;
#endif
@@ -228,13 +229,13 @@ absl::optional<ContentSettingsType> RequestTypeToContentSettingsType(
return ContentSettingsType::MEDIASTREAM_MIC;
case RequestType::kMidiSysex:
return ContentSettingsType::MIDI_SYSEX;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
case RequestType::kNfcDevice:
return ContentSettingsType::NFC;
#endif
case RequestType::kNotifications:
return ContentSettingsType::NOTIFICATIONS;
-#if defined(OS_ANDROID) || defined(OS_CHROMEOS) || defined(OS_WIN)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN)
case RequestType::kProtectedMediaIdentifier:
return ContentSettingsType::PROTECTED_MEDIA_IDENTIFIER;
#endif
@@ -242,7 +243,7 @@ absl::optional<ContentSettingsType> RequestTypeToContentSettingsType(
return ContentSettingsType::STORAGE_ACCESS;
case RequestType::kVrSession:
return ContentSettingsType::VR;
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
case RequestType::kWindowPlacement:
return ContentSettingsType::WINDOW_PLACEMENT;
#endif
@@ -254,7 +255,7 @@ absl::optional<ContentSettingsType> RequestTypeToContentSettingsType(
IconId GetIconId(RequestType type) {
IconId override_id = PermissionsClient::Get()->GetOverrideIconId(type);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
if (override_id)
return override_id;
return GetIconIdAndroid(type);
@@ -265,7 +266,7 @@ IconId GetIconId(RequestType type) {
#endif
}
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
IconId GetBlockedIconId(RequestType type) {
return GetBlockedIconIdDesktop(type);
}
@@ -277,7 +278,7 @@ const char* PermissionKeyForRequestType(permissions::RequestType request_type) {
return "accessibility_events";
case permissions::RequestType::kArSession:
return "ar_session";
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
case permissions::RequestType::kCameraPanTiltZoom:
return "camera_pan_tilt_zoom";
#endif
@@ -287,7 +288,7 @@ const char* PermissionKeyForRequestType(permissions::RequestType request_type) {
return "clipboard";
case permissions::RequestType::kDiskQuota:
return "disk_quota";
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
case permissions::RequestType::kFontAccess:
return "font_access";
#endif
@@ -301,17 +302,17 @@ const char* PermissionKeyForRequestType(permissions::RequestType request_type) {
return "midi_sysex";
case permissions::RequestType::kMultipleDownloads:
return "multiple_downloads";
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
case permissions::RequestType::kNfcDevice:
return "nfc_device";
#endif
case permissions::RequestType::kNotifications:
return "notifications";
-#if defined(OS_ANDROID) || defined(OS_CHROMEOS) || defined(OS_WIN)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN)
case permissions::RequestType::kProtectedMediaIdentifier:
return "protected_media_identifier";
#endif
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
case permissions::RequestType::kRegisterProtocolHandler:
return "register_protocol_handler";
case permissions::RequestType::kSecurityAttestation:
@@ -319,13 +320,13 @@ const char* PermissionKeyForRequestType(permissions::RequestType request_type) {
#endif
case permissions::RequestType::kStorageAccess:
return "storage_access";
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
case permissions::RequestType::kU2fApiRequest:
return "u2f_api_request";
#endif
case permissions::RequestType::kVrSession:
return "vr_session";
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
case permissions::RequestType::kWindowPlacement:
return "window_placement";
#endif
diff --git a/chromium/components/permissions/request_type.h b/chromium/components/permissions/request_type.h
index 361af1b3f42..736f5fc3b30 100644
--- a/chromium/components/permissions/request_type.h
+++ b/chromium/components/permissions/request_type.h
@@ -22,13 +22,13 @@ namespace permissions {
enum class RequestType {
kAccessibilityEvents,
kArSession,
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
kCameraPanTiltZoom,
#endif
kCameraStream,
kClipboard,
kDiskQuota,
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
kFontAccess,
#endif
kGeolocation,
@@ -36,23 +36,23 @@ enum class RequestType {
kMicStream,
kMidiSysex,
kMultipleDownloads,
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
kNfcDevice,
#endif
kNotifications,
-#if defined(OS_ANDROID) || defined(OS_CHROMEOS) || defined(OS_WIN)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN)
kProtectedMediaIdentifier,
#endif
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
kRegisterProtocolHandler,
kSecurityAttestation,
#endif
kStorageAccess,
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
kU2fApiRequest,
#endif
kVrSession,
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
kWindowPlacement,
kMaxValue = kWindowPlacement
#else
@@ -60,7 +60,7 @@ enum class RequestType {
#endif
};
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// On Android, icons are represented with an IDR_ identifier.
using IconId = int;
#else
@@ -79,7 +79,7 @@ absl::optional<ContentSettingsType> RequestTypeToContentSettingsType(
// Returns the icon to display.
IconId GetIconId(RequestType type);
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
// Returns the blocked icon to display.
IconId GetBlockedIconId(RequestType type);
#endif
diff --git a/chromium/components/permissions_strings.grdp b/chromium/components/permissions_strings.grdp
index a0ccba06ea6..ae25a6a47b1 100644
--- a/chromium/components/permissions_strings.grdp
+++ b/chromium/components/permissions_strings.grdp
@@ -16,7 +16,7 @@
<ph name="URL">$1<ex>maps.google.com</ex></ph> wants to see text and images copied to the clipboard
</message>
<message name="IDS_NFC_INFOBAR_TEXT" desc="Text requesting permission for a site to use NFC">
- <ph name="URL">$1<ex>google.com</ex></ph> wants to send and receive info when you tap your phone on an NFC device
+ <ph name="URL">$1<ex>google.com</ex></ph> wants to see and change information on NFC devices that you tap with your phone
</message>
<message name="IDS_VR_INFOBAR_TEXT" desc="Text requesting permission for a site to use VR">
<ph name="URL">$1<ex>google.com</ex></ph> wants to use your virtual reality device and data
@@ -83,7 +83,7 @@
Allow 2 permissions?
</message>
</if>
- <if expr="is_android or chromeos or lacros or is_win">
+ <if expr="is_android or chromeos_ash or chromeos_lacros or is_win">
<message name="IDS_PROTECTED_MEDIA_IDENTIFIER_PERMISSION_FRAGMENT" desc="Permission fragment shown in the permissions bubble when a web page requests access to the computer's protected media identifier.">
Know your unique device identifier
</message>
@@ -133,7 +133,7 @@ Do you want to allow <ph name="EMBEDDED_URL">$1<ex>news.site</ex></ph> to use co
This will otherwise be blocked by your privacy settings. This will allow the content you interacted with to work correctly, but may allow <ph name="EMBEDDED_URL">$1<ex>news.site</ex></ph> to track your activity.
</message>
<message name="IDS_WINDOW_PLACEMENT_PERMISSION_FRAGMENT" desc="Permission request shown if the user is visiting a site that wants to place windows. Follows a prompt: 'This site would like to:'">
- Open and place windows on your screens
+ Use info about your screens to open and place windows
</message>
<message name="IDS_FONT_ACCESS_PERMISSION_FRAGMENT" desc="Permission request shown if the user is visiting a site that wants to access locally installed font data. Follows a prompt: 'This site would like to:'">
Use the fonts on your computer so you can create high-fidelity content
diff --git a/chromium/components/permissions_strings_grdp/IDS_NFC_INFOBAR_TEXT.png.sha1 b/chromium/components/permissions_strings_grdp/IDS_NFC_INFOBAR_TEXT.png.sha1
index 263d71b43e8..5b701be6d0b 100644
--- a/chromium/components/permissions_strings_grdp/IDS_NFC_INFOBAR_TEXT.png.sha1
+++ b/chromium/components/permissions_strings_grdp/IDS_NFC_INFOBAR_TEXT.png.sha1
@@ -1 +1 @@
-b5f8e3ae2ad49bc64df66144f4ed070c4e9b0899 \ No newline at end of file
+438c2bbfae46872850f5242cd0ad61a097d21dc7 \ No newline at end of file
diff --git a/chromium/components/permissions_strings_grdp/IDS_WINDOW_PLACEMENT_PERMISSION_FRAGMENT.png.sha1 b/chromium/components/permissions_strings_grdp/IDS_WINDOW_PLACEMENT_PERMISSION_FRAGMENT.png.sha1
index cd2ace223dc..766865d5595 100644
--- a/chromium/components/permissions_strings_grdp/IDS_WINDOW_PLACEMENT_PERMISSION_FRAGMENT.png.sha1
+++ b/chromium/components/permissions_strings_grdp/IDS_WINDOW_PLACEMENT_PERMISSION_FRAGMENT.png.sha1
@@ -1 +1 @@
-81a78351acc34e6f8413a82488253e97c0b907fc \ No newline at end of file
+84dc3e5387507dd3904aa9c365683f1d5bd7450a \ No newline at end of file
diff --git a/chromium/components/plugins/renderer/plugin_placeholder.cc b/chromium/components/plugins/renderer/plugin_placeholder.cc
index 53f1726c98b..ff67198c46c 100644
--- a/chromium/components/plugins/renderer/plugin_placeholder.cc
+++ b/chromium/components/plugins/renderer/plugin_placeholder.cc
@@ -100,7 +100,7 @@ void PluginPlaceholderBase::HidePlugin() {
parent = parent.ParentNode();
if (!parent.IsElementNode())
continue;
- element = parent.ToConst<blink::WebElement>();
+ element = parent.To<blink::WebElement>();
if (element.HasAttribute("style")) {
std::string style_str = element.GetAttribute("style").Utf8();
if (RE2::PartialMatch(style_str, width_str) &&
diff --git a/chromium/components/plugins/renderer/webview_plugin.cc b/chromium/components/plugins/renderer/webview_plugin.cc
index b87c2b1f7be..94d9fa4e1ce 100644
--- a/chromium/components/plugins/renderer/webview_plugin.cc
+++ b/chromium/components/plugins/renderer/webview_plugin.cc
@@ -438,7 +438,6 @@ void WebViewPlugin::UpdatePluginForNewGeometry(
// The delegate may instantiate a new plugin.
delegate_->OnUnobscuredRectUpdate(gfx::Rect(unobscured_rect));
// The delegate may have dirtied style and layout of the WebView.
- // See for example the resizePoster function in plugin_poster.html.
// Run the lifecycle now so that it is clean.
DCHECK(web_view()->MainFrameWidget());
web_view()->MainFrameWidget()->UpdateAllLifecyclePhases(
diff --git a/chromium/components/policy/content/BUILD.gn b/chromium/components/policy/content/BUILD.gn
index 2709062c39b..2d2ef937b5a 100644
--- a/chromium/components/policy/content/BUILD.gn
+++ b/chromium/components/policy/content/BUILD.gn
@@ -20,6 +20,7 @@ source_set("safe_sites_navigation_throttle") {
"//components/policy/core/browser",
"//components/safe_search_api",
"//components/safe_search_api:safe_search_client",
+ "//components/url_matcher",
"//content/public/browser",
"//net",
]
diff --git a/chromium/components/policy/core/browser/BUILD.gn b/chromium/components/policy/core/browser/BUILD.gn
index 73efbdb6b1a..d5c7b9d294a 100644
--- a/chromium/components/policy/core/browser/BUILD.gn
+++ b/chromium/components/policy/core/browser/BUILD.gn
@@ -42,8 +42,8 @@ source_set("internal") {
"url_blocklist_manager.h",
"url_blocklist_policy_handler.cc",
"url_blocklist_policy_handler.h",
- "url_util.cc",
- "url_util.h",
+ "url_scheme_list_policy_handler.cc",
+ "url_scheme_list_policy_handler.h",
"webui/json_generation.cc",
"webui/json_generation.h",
"webui/machine_level_user_cloud_policy_status_provider.cc",
@@ -102,15 +102,10 @@ static_library("test_support") {
sources = [
"configuration_policy_pref_store_test.cc",
"configuration_policy_pref_store_test.h",
+ "policy_pref_mapping_test.cc",
+ "policy_pref_mapping_test.h",
]
- if (!is_fuchsia) {
- sources += [
- "policy_pref_mapping_test.cc",
- "policy_pref_mapping_test.h",
- ]
- }
-
public_deps = [
":browser",
"//base",
@@ -142,7 +137,7 @@ source_set("unit_tests") {
"url_allowlist_policy_handler_unittest.cc",
"url_blocklist_manager_unittest.cc",
"url_blocklist_policy_handler_unittest.cc",
- "url_util_unittest.cc",
+ "url_scheme_list_policy_handler_unittest.cc",
]
deps = [
":browser",
@@ -153,6 +148,7 @@ source_set("unit_tests") {
"//components/signin/public/identity_manager:identity_manager",
"//components/signin/public/identity_manager:test_support",
"//components/url_formatter",
+ "//components/url_matcher",
"//google_apis",
"//net",
"//services/network:test_support",
diff --git a/chromium/components/policy/core/common/BUILD.gn b/chromium/components/policy/core/common/BUILD.gn
index 1b97421fcc4..9aa66afafdd 100644
--- a/chromium/components/policy/core/common/BUILD.gn
+++ b/chromium/components/policy/core/common/BUILD.gn
@@ -280,6 +280,8 @@ source_set("internal") {
if (is_chromeos_ash) {
deps += [ "//chromeos/system" ]
sources += [
+ "default_chrome_apps_migrator.cc",
+ "default_chrome_apps_migrator.h",
"policy_scheduler.cc",
"policy_scheduler.h",
]
@@ -356,7 +358,6 @@ static_library("test_support") {
"mock_policy_service.h",
"policy_test_utils.cc",
"policy_test_utils.h",
- "remote_commands/test_support/blocking_queue.h",
"remote_commands/test_support/echo_remote_command_job.cc",
"remote_commands/test_support/echo_remote_command_job.h",
"remote_commands/test_support/testing_remote_commands_server.cc",
@@ -447,6 +448,7 @@ source_set("unit_tests") {
"policy_bundle_unittest.cc",
"policy_loader_command_line_unittest.cc",
"policy_map_unittest.cc",
+ "policy_proto_decoders_unittest.cc",
"policy_service_impl_unittest.cc",
"policy_statistics_collector_unittest.cc",
"remote_commands/remote_commands_queue_unittest.cc",
@@ -474,6 +476,7 @@ source_set("unit_tests") {
}
if (is_chromeos_ash) {
sources += [
+ "default_chrome_apps_migrator_unittest.cc",
"policy_scheduler_unittest.cc",
"proxy_policy_provider_unittest.cc",
]
diff --git a/chromium/components/policy/test_support/BUILD.gn b/chromium/components/policy/test_support/BUILD.gn
index b8d78602f04..e0d88bd0881 100644
--- a/chromium/components/policy/test_support/BUILD.gn
+++ b/chromium/components/policy/test_support/BUILD.gn
@@ -5,38 +5,53 @@
static_library("test_support") {
testonly = true
- data = [ "policy_testserver.py" ]
-
sources = [
"client_storage.cc",
"client_storage.h",
"embedded_policy_test_server.cc",
"embedded_policy_test_server.h",
+ "failing_request_handler.cc",
+ "failing_request_handler.h",
"policy_storage.cc",
"policy_storage.h",
"request_handler_for_api_authorization.cc",
"request_handler_for_api_authorization.h",
+ "request_handler_for_auto_enrollment.cc",
+ "request_handler_for_auto_enrollment.h",
+ "request_handler_for_check_android_management.cc",
+ "request_handler_for_check_android_management.h",
"request_handler_for_chrome_desktop_report.cc",
"request_handler_for_chrome_desktop_report.h",
+ "request_handler_for_device_attribute_update.cc",
+ "request_handler_for_device_attribute_update.h",
+ "request_handler_for_device_attribute_update_permission.cc",
+ "request_handler_for_device_attribute_update_permission.h",
+ "request_handler_for_device_initial_enrollment_state.cc",
+ "request_handler_for_device_initial_enrollment_state.h",
+ "request_handler_for_device_state_retrieval.cc",
+ "request_handler_for_device_state_retrieval.h",
"request_handler_for_policy.cc",
"request_handler_for_policy.h",
+ "request_handler_for_psm_auto_enrollment.cc",
+ "request_handler_for_psm_auto_enrollment.h",
"request_handler_for_register_browser.cc",
"request_handler_for_register_browser.h",
+ "request_handler_for_register_cert_based.cc",
+ "request_handler_for_register_cert_based.h",
"request_handler_for_register_device_and_user.cc",
"request_handler_for_register_device_and_user.h",
+ "request_handler_for_remote_commands.cc",
+ "request_handler_for_remote_commands.h",
+ "request_handler_for_status_upload.cc",
+ "request_handler_for_status_upload.h",
+ "request_handler_for_unregister.cc",
+ "request_handler_for_unregister.h",
"signature_provider.cc",
"signature_provider.h",
"test_server_helpers.cc",
"test_server_helpers.h",
]
- if (!is_android) {
- sources += [
- "local_policy_test_server.cc",
- "local_policy_test_server.h",
- ]
- }
-
public_deps = [ "//net:test_support" ]
deps = [
"//base",
@@ -46,6 +61,7 @@ static_library("test_support") {
"//google_apis:google_apis",
"//net",
"//net:test_support",
+ "//third_party/private_membership:private_membership_proto",
"//third_party/re2:re2",
]
}
@@ -54,14 +70,28 @@ source_set("unittests") {
testonly = true
sources = [
+ "client_storage_unittest.cc",
"embedded_policy_test_server_test_base.cc",
"embedded_policy_test_server_test_base.h",
"embedded_policy_test_server_unittest.cc",
+ "failing_request_handler_unittest.cc",
+ "policy_storage_unittest.cc",
"request_handler_for_api_authorization_unittest.cc",
+ "request_handler_for_auto_enrollment_unittest.cc",
+ "request_handler_for_check_android_management_unittest.cc",
"request_handler_for_chrome_desktop_report_unittest.cc",
+ "request_handler_for_device_attribute_update_permission_unittest.cc",
+ "request_handler_for_device_attribute_update_unittest.cc",
+ "request_handler_for_device_initial_enrollment_state_unittest.cc",
+ "request_handler_for_device_state_retrieval_unittest.cc",
"request_handler_for_policy_unittest.cc",
+ "request_handler_for_psm_auto_enrollment_unittest.cc",
"request_handler_for_register_browser_unittest.cc",
+ "request_handler_for_register_cert_based_unittest.cc",
"request_handler_for_register_device_and_user_unittest.cc",
+ "request_handler_for_remote_commands_unittest.cc",
+ "request_handler_for_status_upload_unittest.cc",
+ "request_handler_for_unregister_unittest.cc",
"signature_provider_unittest.cc",
]
diff --git a/chromium/components/policy_strings.grdp b/chromium/components/policy_strings.grdp
index 6dae5625025..9f5e16c7504 100644
--- a/chromium/components/policy_strings.grdp
+++ b/chromium/components/policy_strings.grdp
@@ -163,6 +163,9 @@
<message name="IDS_POLICY_CLOUD_SOURCE_ONLY_ERROR" desc="The text displayed in the status column when a policy that should only be set in the cloud is set from another source.">
Ignored because the policy is not set by a cloud source.
</message>
+ <message name="IDS_POLICY_CLOUD_USER_ONLY_ERROR" desc="The text displayed in the status column when a policy should only be set from cloud user is set from another source.">
+ Ignored because the policy can only be set as a cloud user policy.
+ </message>
<message name="IDS_POLICY_CLOUD_MANAGEMENT_ENROLLMENT_ONLY_ERROR" desc="The text displayed in the status column when a policy that is effective only when the machine is enrolled with the Chrome Browser Cloud Management.">
Ignored because the machine is not enrolled with Chrome Browser Cloud Management.
</message>
@@ -271,7 +274,7 @@ Additional details:
<ph name="DEBUG_INFO">$1<ex>ERROR: Field name 'SomeRandomField' is unknown. (at toplevel)</ex></ph>
</message>
</if>
- <if expr="chromeos or lacros">
+ <if expr="chromeos_ash or chromeos_lacros">
<message name="IDS_POLICY_SCOPE_ERROR" desc="Text displayed in the status column when a policy is set in an unsupported scope.">
Policy scope is not supported.
</message>
@@ -752,5 +755,27 @@ Additional details:
<message name="IDS_POLICY_DLP_CLIPBOARD_BUBBLE_MESSAGE" desc="Text for a bubble that informs the user that their copy and paste action has been blocked/warned with a link to a help center article about Data Leak Prevention.">
<ph name="BUBBLE_MESSAGE">$1<ex>Pasting from corp.google.com to this location is blocked by administrator policy</ex></ph>. <ph name="LEARN_MORE_TEXT">$2<ex>Learn more</ex></ph>
</message>
-
+ <message name="IDS_POLICY_DEVICE_SCHEDULED_REBOOT_TITLE" desc="The title for notification informing the user that the device will restart soon.">
+ Device will restart very soon
+ </message>
+ <message name="IDS_POLICY_DEVICE_SCHEDULED_REBOOT_MESSAGE" desc="The message for notification informing the user that the device will restart soon.">
+ Your administrator will restart your device at <ph name="TIME">$1<ex>3:20 PM</ex></ph> on <ph name="DATE">$2<ex>Nov 29, 2021</ex></ph>
+ </message>
+ <message name="IDS_POLICY_REBOOT_BUTTON" desc="Notification button label for restarting the device.">
+ Restart now
+ </message>
+ <message name="IDS_POLICY_DEVICE_SCHEDULED_REBOOT_DIALOG_MESSAGE" desc="The message of the dialog informing the user that the device will restart soon.">
+ Your administrator will restart your device automatically at <ph name="TIME">$1<ex>3:20 PM</ex></ph> on <ph name="DATE">$2<ex>Nov 29, 2021</ex></ph>. Save any open items before your device restarts.
+ </message>
+ <message name="IDS_REBOOT_SCHEDULED_TITLE_MINUTES" desc="The title of a dialog that tells users the device will be restarted within one or more minutes.">
+ {0, plural,
+ =1 {Your device will restart in 1 minute}
+ other {Your device will restart in # minutes}}
+ </message>
+ <message name="IDS_REBOOT_SCHEDULED_TITLE_SECONDS" desc="The title of a dialog that tells users the device will be restarted within some number of seconds.">
+ {0, plural,
+ =0 {Your device will restart now}
+ =1 {Your device will restart in 1 second}
+ other {Your device will restart in # seconds}}
+ </message>
</grit-part>
diff --git a/chromium/components/policy_strings_grdp/IDS_POLICY_CLOUD_USER_ONLY_ERROR.png.sha1 b/chromium/components/policy_strings_grdp/IDS_POLICY_CLOUD_USER_ONLY_ERROR.png.sha1
new file mode 100644
index 00000000000..fdc777540e6
--- /dev/null
+++ b/chromium/components/policy_strings_grdp/IDS_POLICY_CLOUD_USER_ONLY_ERROR.png.sha1
@@ -0,0 +1 @@
+251ff32b46173c5495f8e2a4e08430da7b8d08f8 \ No newline at end of file
diff --git a/chromium/components/policy_strings_grdp/IDS_POLICY_DEVICE_SCHEDULED_REBOOT_DIALOG_MESSAGE.png.sha1 b/chromium/components/policy_strings_grdp/IDS_POLICY_DEVICE_SCHEDULED_REBOOT_DIALOG_MESSAGE.png.sha1
new file mode 100644
index 00000000000..5944e23c762
--- /dev/null
+++ b/chromium/components/policy_strings_grdp/IDS_POLICY_DEVICE_SCHEDULED_REBOOT_DIALOG_MESSAGE.png.sha1
@@ -0,0 +1 @@
+198b15998c56e1653647f80f6c8aadfd1124d606 \ No newline at end of file
diff --git a/chromium/components/policy_strings_grdp/IDS_POLICY_DEVICE_SCHEDULED_REBOOT_MESSAGE.png.sha1 b/chromium/components/policy_strings_grdp/IDS_POLICY_DEVICE_SCHEDULED_REBOOT_MESSAGE.png.sha1
new file mode 100644
index 00000000000..64deab79840
--- /dev/null
+++ b/chromium/components/policy_strings_grdp/IDS_POLICY_DEVICE_SCHEDULED_REBOOT_MESSAGE.png.sha1
@@ -0,0 +1 @@
+a3d9900e23d053e9d9d39b70ef736a8ec02330af \ No newline at end of file
diff --git a/chromium/components/policy_strings_grdp/IDS_POLICY_DEVICE_SCHEDULED_REBOOT_TITLE.png.sha1 b/chromium/components/policy_strings_grdp/IDS_POLICY_DEVICE_SCHEDULED_REBOOT_TITLE.png.sha1
new file mode 100644
index 00000000000..d906a5ab004
--- /dev/null
+++ b/chromium/components/policy_strings_grdp/IDS_POLICY_DEVICE_SCHEDULED_REBOOT_TITLE.png.sha1
@@ -0,0 +1 @@
+a0d64adcdeb183d5b488afaefc71b58c7ba40200 \ No newline at end of file
diff --git a/chromium/components/policy_strings_grdp/IDS_POLICY_REBOOT_BUTTON.png.sha1 b/chromium/components/policy_strings_grdp/IDS_POLICY_REBOOT_BUTTON.png.sha1
new file mode 100644
index 00000000000..7c06e5dd987
--- /dev/null
+++ b/chromium/components/policy_strings_grdp/IDS_POLICY_REBOOT_BUTTON.png.sha1
@@ -0,0 +1 @@
+7bb4ca07694e4d2645db4e6e1721ef886022984f \ No newline at end of file
diff --git a/chromium/components/policy_strings_grdp/IDS_REBOOT_SCHEDULED_TITLE_MINUTES.png.sha1 b/chromium/components/policy_strings_grdp/IDS_REBOOT_SCHEDULED_TITLE_MINUTES.png.sha1
new file mode 100644
index 00000000000..e3e24ca066a
--- /dev/null
+++ b/chromium/components/policy_strings_grdp/IDS_REBOOT_SCHEDULED_TITLE_MINUTES.png.sha1
@@ -0,0 +1 @@
+6426159ba1e831a9805993cf66811220a6f4a1c5 \ No newline at end of file
diff --git a/chromium/components/policy_strings_grdp/IDS_REBOOT_SCHEDULED_TITLE_SECONDS.png.sha1 b/chromium/components/policy_strings_grdp/IDS_REBOOT_SCHEDULED_TITLE_SECONDS.png.sha1
new file mode 100644
index 00000000000..658ae9a8470
--- /dev/null
+++ b/chromium/components/policy_strings_grdp/IDS_REBOOT_SCHEDULED_TITLE_SECONDS.png.sha1
@@ -0,0 +1 @@
+7152006b5e45b1d96876c7e8e3e799b33a70e228 \ No newline at end of file
diff --git a/chromium/components/power_metrics/BUILD.gn b/chromium/components/power_metrics/BUILD.gn
index 96a878623f9..ecc0c9be021 100644
--- a/chromium/components/power_metrics/BUILD.gn
+++ b/chromium/components/power_metrics/BUILD.gn
@@ -9,6 +9,9 @@ if (is_mac) {
"energy_impact_mac.mm",
"iopm_power_source_sampling_event_source.cc",
"iopm_power_source_sampling_event_source.h",
+ "m1_sensors_internal_types_mac.h",
+ "m1_sensors_mac.h",
+ "m1_sensors_mac.mm",
"mach_time_mac.h",
"mach_time_mac.mm",
"resource_coalition_internal_types_mac.h",
diff --git a/chromium/components/power_metrics/iopm_power_source_sampling_event_source.cc b/chromium/components/power_metrics/iopm_power_source_sampling_event_source.cc
index ca1b10d7b64..321d66e2dc3 100644
--- a/chromium/components/power_metrics/iopm_power_source_sampling_event_source.cc
+++ b/chromium/components/power_metrics/iopm_power_source_sampling_event_source.cc
@@ -10,7 +10,7 @@
#include "base/check.h"
#include "base/logging.h"
-namespace power_sampler {
+namespace power_metrics {
IOPMPowerSourceSamplingEventSource::IOPMPowerSourceSamplingEventSource() =
default;
@@ -64,4 +64,4 @@ void IOPMPowerSourceSamplingEventSource::OnNotification(
self->callback_.Run();
}
-} // namespace power_sampler
+} // namespace power_metrics
diff --git a/chromium/components/power_metrics/iopm_power_source_sampling_event_source.h b/chromium/components/power_metrics/iopm_power_source_sampling_event_source.h
index 9b294a2b939..9b0b59359b5 100644
--- a/chromium/components/power_metrics/iopm_power_source_sampling_event_source.h
+++ b/chromium/components/power_metrics/iopm_power_source_sampling_event_source.h
@@ -10,7 +10,7 @@
#include "base/mac/scoped_ioobject.h"
#include "components/power_metrics/sampling_event_source.h"
-namespace power_sampler {
+namespace power_metrics {
// Generates a sampling event when a state change notification is dispatched by
// the IOPMPowerSource service.
@@ -35,6 +35,6 @@ class IOPMPowerSourceSamplingEventSource : public SamplingEventSource {
SamplingEventCallback callback_;
};
-} // namespace power_sampler
+} // namespace power_metrics
#endif // COMPONENTS_POWER_METRICS_IOPM_POWER_SOURCE_SAMPLING_EVENT_SOURCE_H_
diff --git a/chromium/components/power_metrics/m1_sensors_internal_types_mac.h b/chromium/components/power_metrics/m1_sensors_internal_types_mac.h
new file mode 100644
index 00000000000..039d84c33dd
--- /dev/null
+++ b/chromium/components/power_metrics/m1_sensors_internal_types_mac.h
@@ -0,0 +1,26 @@
+// Copyright 2021 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.
+
+#ifndef COMPONENTS_POWER_METRICS_M1_SENSORS_INTERNAL_TYPES_MAC_H_
+#define COMPONENTS_POWER_METRICS_M1_SENSORS_INTERNAL_TYPES_MAC_H_
+
+#include <stdint.h>
+
+// From:
+// https://opensource.apple.com/source/IOHIDFamily/IOHIDFamily-421.6/IOHIDFamily/IOHIDEventTypes.h.auto.html
+
+#define IOHIDEventFieldBase(type) (type << 16)
+
+constexpr int64_t kIOHIDEventTypeTemperature = 15;
+
+// From:
+// https://opensource.apple.com/source/IOHIDFamily/IOHIDFamily-421.6/IOHIDFamily/AppleHIDUsageTables.h
+
+// Usage pages
+constexpr int kHIDPage_AppleVendor = 0xff00;
+
+// Usage keys for `kHIDPage_AppleVendor`
+constexpr int kHIDUsage_AppleVendor_TemperatureSensor = 0x0005;
+
+#endif // COMPONENTS_POWER_METRICS_M1_SENSORS_INTERNAL_TYPES_MAC_H_
diff --git a/chromium/components/power_metrics/m1_sensors_mac.h b/chromium/components/power_metrics/m1_sensors_mac.h
new file mode 100644
index 00000000000..45703ada492
--- /dev/null
+++ b/chromium/components/power_metrics/m1_sensors_mac.h
@@ -0,0 +1,48 @@
+// Copyright 2021 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.
+
+// The Apple M1 chip has sensors to monitor its power consumption and
+// temperature. This file defines a class to retrieve data from these sensors.
+
+#ifndef COMPONENTS_POWER_METRICS_M1_SENSORS_MAC_H_
+#define COMPONENTS_POWER_METRICS_M1_SENSORS_MAC_H_
+
+#include <memory>
+
+#include <IOKit/hidsystem/IOHIDEventSystemClient.h>
+
+#include "base/mac/scoped_cftyperef.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace power_metrics {
+
+class M1SensorsReader {
+ public:
+ struct TemperaturesCelsius {
+ TemperaturesCelsius();
+ TemperaturesCelsius(const TemperaturesCelsius&) noexcept;
+ ~TemperaturesCelsius();
+
+ absl::optional<double> p_cores;
+ absl::optional<double> e_cores;
+ };
+
+ virtual ~M1SensorsReader();
+
+ // Creates an M1SensorsReader. Returns nullptr on failure.
+ static std::unique_ptr<M1SensorsReader> Create();
+
+ // Reads temperature sensors. Virtual for testing.
+ virtual TemperaturesCelsius ReadTemperatures();
+
+ protected:
+ M1SensorsReader(base::ScopedCFTypeRef<IOHIDEventSystemClientRef> system);
+
+ private:
+ base::ScopedCFTypeRef<IOHIDEventSystemClientRef> system_;
+};
+
+} // namespace power_metrics
+
+#endif // COMPONENTS_POWER_METRICS_M1_SENSORS_MAC_H_
diff --git a/chromium/components/power_metrics/m1_sensors_mac.mm b/chromium/components/power_metrics/m1_sensors_mac.mm
new file mode 100644
index 00000000000..0477e776746
--- /dev/null
+++ b/chromium/components/power_metrics/m1_sensors_mac.mm
@@ -0,0 +1,123 @@
+// Copyright 2021 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.
+
+#include "components/power_metrics/m1_sensors_mac.h"
+
+#import <Foundation/Foundation.h>
+#import <IOKit/hid/IOHIDDeviceKeys.h>
+#import <IOKit/hidsystem/IOHIDServiceClient.h>
+
+#include <utility>
+
+#include "base/mac/foundation_util.h"
+#include "base/memory/ptr_util.h"
+#include "components/power_metrics/m1_sensors_internal_types_mac.h"
+
+extern "C" {
+
+extern IOHIDEventSystemClientRef IOHIDEventSystemClientCreate(CFAllocatorRef);
+extern int IOHIDEventSystemClientSetMatching(IOHIDEventSystemClientRef client,
+ CFDictionaryRef match);
+extern CFTypeRef IOHIDServiceClientCopyEvent(IOHIDServiceClientRef,
+ int64_t,
+ int32_t,
+ int64_t);
+extern double IOHIDEventGetFloatValue(CFTypeRef, int32_t);
+}
+
+namespace power_metrics {
+
+namespace {
+
+absl::optional<double> GetEventFloatValue(IOHIDServiceClientRef service,
+ int64_t event_type) {
+ base::ScopedCFTypeRef<CFTypeRef> event(
+ IOHIDServiceClientCopyEvent(service, event_type, 0, 0));
+ if (!event)
+ return absl::nullopt;
+ return IOHIDEventGetFloatValue(event, IOHIDEventFieldBase(event_type));
+}
+
+} // namespace
+
+M1SensorsReader::TemperaturesCelsius::TemperaturesCelsius() = default;
+M1SensorsReader::TemperaturesCelsius::TemperaturesCelsius(
+ const TemperaturesCelsius&) noexcept = default;
+M1SensorsReader::TemperaturesCelsius::~TemperaturesCelsius() = default;
+
+M1SensorsReader::~M1SensorsReader() = default;
+
+// static
+std::unique_ptr<M1SensorsReader> M1SensorsReader::Create() {
+ base::ScopedCFTypeRef<IOHIDEventSystemClientRef> system(
+ IOHIDEventSystemClientCreate(kCFAllocatorDefault));
+
+ if (system == nil)
+ return nullptr;
+
+ NSDictionary* filter = @{
+ @kIOHIDPrimaryUsagePageKey : [NSNumber numberWithInt:kHIDPage_AppleVendor],
+ @kIOHIDPrimaryUsageKey :
+ [NSNumber numberWithInt:kHIDUsage_AppleVendor_TemperatureSensor],
+ };
+ IOHIDEventSystemClientSetMatching(system, base::mac::NSToCFCast(filter));
+
+ return base::WrapUnique(new M1SensorsReader(std::move(system)));
+}
+
+M1SensorsReader::TemperaturesCelsius M1SensorsReader::ReadTemperatures() {
+ base::ScopedCFTypeRef<CFArrayRef> services(
+ IOHIDEventSystemClientCopyServices(system_.get()));
+
+ // There are multiple temperature sensors on P-Cores and E-Cores. Count and
+ // sum values to compute average later.
+ int num_p_core_temp = 0;
+ int num_e_core_temp = 0;
+ double sum_p_core_temp = 0;
+ double sum_e_core_temp = 0;
+
+ for (id service_obj in base::mac::CFToNSCast(services.get())) {
+ IOHIDServiceClientRef service = (IOHIDServiceClientRef)service_obj;
+
+ base::ScopedCFTypeRef<CFStringRef> product_cf(
+ base::mac::CFCast<CFStringRef>(
+ IOHIDServiceClientCopyProperty(service, CFSTR(kIOHIDProductKey))));
+ if (product_cf == nil)
+ continue;
+
+ if ([base::mac::CFToNSCast(product_cf.get())
+ hasPrefix:@"pACC MTR Temp Sensor"]) {
+ absl::optional<double> temp =
+ GetEventFloatValue(service, kIOHIDEventTypeTemperature);
+ if (temp.has_value()) {
+ num_p_core_temp += 1;
+ sum_p_core_temp += temp.value();
+ }
+ }
+
+ if ([base::mac::CFToNSCast(product_cf.get())
+ hasPrefix:@"eACC MTR Temp Sensor"]) {
+ absl::optional<double> temp =
+ GetEventFloatValue(service, kIOHIDEventTypeTemperature);
+ if (temp.has_value()) {
+ num_e_core_temp += 1;
+ sum_e_core_temp += temp.value();
+ }
+ }
+ }
+
+ TemperaturesCelsius temperatures;
+ if (num_p_core_temp > 0)
+ temperatures.p_cores = sum_p_core_temp / num_p_core_temp;
+ if (num_e_core_temp > 0)
+ temperatures.e_cores = sum_e_core_temp / num_e_core_temp;
+
+ return temperatures;
+}
+
+M1SensorsReader::M1SensorsReader(
+ base::ScopedCFTypeRef<IOHIDEventSystemClientRef> system)
+ : system_(std::move(system)) {}
+
+} // namespace power_metrics
diff --git a/chromium/components/power_metrics/resource_coalition_internal_types_mac.h b/chromium/components/power_metrics/resource_coalition_internal_types_mac.h
index cad2ffd4b17..d08a30b6982 100644
--- a/chromium/components/power_metrics/resource_coalition_internal_types_mac.h
+++ b/chromium/components/power_metrics/resource_coalition_internal_types_mac.h
@@ -60,6 +60,7 @@ struct coalition_resource_usage {
uint64_t cpu_ptime;
uint64_t cpu_time_eqos_len; /* Stores the number of thread QoS types */
uint64_t cpu_time_eqos[COALITION_NUM_THREAD_QOS_TYPES];
+ // `cpu_instructions` and `cpu_cycles` are only populated on macOS 10.15+
uint64_t cpu_instructions;
uint64_t cpu_cycles;
uint64_t fs_metadata_writes;
diff --git a/chromium/components/power_metrics/resource_coalition_mac.h b/chromium/components/power_metrics/resource_coalition_mac.h
index 6cdcaee704c..b74da57ced2 100644
--- a/chromium/components/power_metrics/resource_coalition_mac.h
+++ b/chromium/components/power_metrics/resource_coalition_mac.h
@@ -14,18 +14,24 @@
#include <stdint.h>
#include <memory>
+#include <mach/mach_time.h>
+
#include "base/process/process_handle.h"
+#include "base/time/time.h"
#include "components/power_metrics/resource_coalition_internal_types_mac.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
namespace power_metrics {
+struct EnergyImpactCoefficients;
+
// Returns the coalition id for the process identified by |pid| or nullopt if
// not available.
absl::optional<uint64_t> GetProcessCoalitionId(base::ProcessId pid);
// Returns resource usage data for the coalition identified by |coalition_id|,
-// or nullptr if not available.
+// or nullptr if not available (e.g. if `coalition_id` is invalid or if the
+// kernel can't allocate memory).
std::unique_ptr<coalition_resource_usage> GetCoalitionResourceUsage(
int64_t coalition_id);
@@ -35,6 +41,31 @@ coalition_resource_usage GetCoalitionResourceUsageDifference(
const coalition_resource_usage& left,
const coalition_resource_usage& right);
+// Struct that contains the rate of resource usage for a coalition.
+struct CoalitionResourceUsageRate {
+ double cpu_time_per_second;
+ double interrupt_wakeups_per_second;
+ double platform_idle_wakeups_per_second;
+ double bytesread_per_second;
+ double byteswritten_per_second;
+ double gpu_time_per_second;
+ // Only makes sense on Intel macs, not computed on M1 macs.
+ absl::optional<double> energy_impact_per_second;
+ // Only available on M1 macs as of September 2021.
+ double power_nw;
+
+ double qos_time_per_second[THREAD_QOS_LAST];
+};
+
+// Returns rate of resource usage for a coalition, given the usage at
+// the beginning and end of an interval and the duration of the interval.
+absl::optional<CoalitionResourceUsageRate> GetCoalitionResourceUsageRate(
+ const coalition_resource_usage& begin,
+ const coalition_resource_usage& end,
+ base::TimeDelta interval_duration,
+ mach_timebase_info_data_t timebase,
+ absl::optional<EnergyImpactCoefficients> energy_impact_coefficients);
+
} // namespace power_metrics
#endif // COMPONENTS_PPOWER_METRICS_RESOURCE_COALITION_MAC_H_
diff --git a/chromium/components/power_metrics/resource_coalition_mac.mm b/chromium/components/power_metrics/resource_coalition_mac.mm
index fcea8998c29..2fc6e9c7af8 100644
--- a/chromium/components/power_metrics/resource_coalition_mac.mm
+++ b/chromium/components/power_metrics/resource_coalition_mac.mm
@@ -7,6 +7,8 @@
#include <libproc.h>
#include "base/check_op.h"
+#include "components/power_metrics/energy_impact_mac.h"
+#include "components/power_metrics/mach_time_mac.h"
extern "C" int coalition_info_resource_usage(
uint64_t cid,
@@ -133,4 +135,75 @@ coalition_resource_usage GetCoalitionResourceUsageDifference(
return ret;
}
+absl::optional<CoalitionResourceUsageRate> GetCoalitionResourceUsageRate(
+ const coalition_resource_usage& begin,
+ const coalition_resource_usage& end,
+ base::TimeDelta interval_duration,
+ mach_timebase_info_data_t timebase,
+ absl::optional<EnergyImpactCoefficients> energy_impact_coefficients) {
+ // Validate that |end| >= |begin|.
+ bool end_greater_or_equal_begin =
+ std::tie(end.cpu_time, end.interrupt_wakeups, end.platform_idle_wakeups,
+ end.bytesread, end.byteswritten, end.gpu_time, end.energy) >=
+ std::tie(begin.cpu_time, begin.interrupt_wakeups,
+ begin.platform_idle_wakeups, begin.bytesread, begin.byteswritten,
+ begin.gpu_time, begin.energy);
+ for (int i = 0; i < COALITION_NUM_THREAD_QOS_TYPES; ++i) {
+ if (end.cpu_time_eqos[i] < begin.cpu_time_eqos[i])
+ end_greater_or_equal_begin = false;
+ }
+ if (!end_greater_or_equal_begin)
+ return absl::nullopt;
+
+ auto get_rate_per_second = [&interval_duration](uint64_t begin,
+ uint64_t end) -> double {
+ DCHECK_GE(end, begin);
+ uint64_t diff = end - begin;
+ return diff / interval_duration.InSecondsF();
+ };
+
+ auto get_time_rate_per_second = [&interval_duration, &timebase](
+ uint64_t begin, uint64_t end) -> double {
+ DCHECK_GE(end, begin);
+ // Compute the delta in s, being careful to avoid truncation due to integral
+ // division.
+ double delta_sample_s =
+ power_metrics::MachTimeToNs(end - begin, timebase) /
+ static_cast<double>(base::Time::kNanosecondsPerSecond);
+ return delta_sample_s / interval_duration.InSecondsF();
+ };
+
+ CoalitionResourceUsageRate result;
+
+ result.cpu_time_per_second =
+ get_time_rate_per_second(begin.cpu_time, end.cpu_time);
+ result.interrupt_wakeups_per_second =
+ get_rate_per_second(begin.interrupt_wakeups, end.interrupt_wakeups);
+ result.platform_idle_wakeups_per_second = get_rate_per_second(
+ begin.platform_idle_wakeups, end.platform_idle_wakeups);
+ result.bytesread_per_second =
+ get_rate_per_second(begin.bytesread, end.bytesread);
+ result.byteswritten_per_second =
+ get_rate_per_second(begin.byteswritten, end.byteswritten);
+ result.gpu_time_per_second =
+ get_time_rate_per_second(begin.gpu_time, end.gpu_time);
+ result.power_nw = get_rate_per_second(begin.energy, end.energy);
+
+ for (int i = 0; i < COALITION_NUM_THREAD_QOS_TYPES; ++i) {
+ result.qos_time_per_second[i] =
+ get_time_rate_per_second(begin.cpu_time_eqos[i], end.cpu_time_eqos[i]);
+ }
+
+ if (energy_impact_coefficients.has_value()) {
+ result.energy_impact_per_second =
+ (ComputeEnergyImpactForResourceUsage(
+ end, energy_impact_coefficients.value(), timebase) -
+ ComputeEnergyImpactForResourceUsage(
+ begin, energy_impact_coefficients.value(), timebase)) /
+ interval_duration.InSecondsF();
+ }
+
+ return result;
+}
+
} // power_metrics
diff --git a/chromium/components/power_metrics/resource_coalition_mac_unittest.mm b/chromium/components/power_metrics/resource_coalition_mac_unittest.mm
index 3b5187824ea..ee113cd7d6b 100644
--- a/chromium/components/power_metrics/resource_coalition_mac_unittest.mm
+++ b/chromium/components/power_metrics/resource_coalition_mac_unittest.mm
@@ -4,12 +4,29 @@
#include "components/power_metrics/resource_coalition_mac.h"
+#include "base/rand_util.h"
+#include "components/power_metrics/energy_impact_mac.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
namespace power_metrics {
namespace {
+constexpr mach_timebase_info_data_t kIntelTimebase = {1, 1};
+constexpr mach_timebase_info_data_t kM1Timebase = {125, 3};
+
+constexpr EnergyImpactCoefficients kEnergyImpactCoefficients{
+ .kcpu_wakeups = base::Microseconds(200).InSecondsF(),
+ .kqos_default = 1.0,
+ .kqos_background = 0.8,
+ .kqos_utility = 1.0,
+ .kqos_legacy = 1.0,
+ .kqos_user_initiated = 1.0,
+ .kqos_user_interactive = 1.0,
+ .kgpu_time = 2.5,
+};
+
coalition_resource_usage GetTestCoalitionResourceUsage(uint32_t increment) {
coalition_resource_usage ret{
.tasks_started = 1 + increment,
@@ -53,8 +70,46 @@ coalition_resource_usage GetTestCoalitionResourceUsage(uint32_t increment) {
return ret;
}
+void BurnCPU() {
+ base::TimeTicks begin = base::TimeTicks::Now();
+ constexpr base::TimeDelta busy_time = base::Seconds(1);
+ [[maybe_unused]] volatile double number = 1;
+ while (base::TimeTicks::Now() < (begin + busy_time)) {
+ for (int i = 0; i < 10000; ++i)
+ number *= base::RandDouble();
+ }
+}
+
} // namespace
+TEST(ResourceCoalitionMacTest, Busy) {
+ absl::optional<uint64_t> coalition_id =
+ GetProcessCoalitionId(base::GetCurrentProcId());
+ ASSERT_TRUE(coalition_id.has_value());
+
+ std::unique_ptr<coalition_resource_usage> begin =
+ GetCoalitionResourceUsage(coalition_id.value());
+ BurnCPU();
+ std::unique_ptr<coalition_resource_usage> end =
+ GetCoalitionResourceUsage(coalition_id.value());
+
+ ASSERT_TRUE(begin);
+ ASSERT_TRUE(end);
+
+ // Waterfall suggests that `cpu_instructions` and `cpu_cycles` are not
+ // populated prior to macOS 10.15.
+ if (@available(macOS 10.15, *)) {
+ EXPECT_GT(end->cpu_instructions, begin->cpu_instructions);
+ EXPECT_GT(end->cpu_cycles, begin->cpu_cycles);
+ } else {
+ EXPECT_EQ(0u, begin->cpu_instructions);
+ EXPECT_EQ(0u, begin->cpu_cycles);
+ EXPECT_EQ(0u, end->cpu_instructions);
+ EXPECT_EQ(0u, end->cpu_cycles);
+ }
+ EXPECT_GT(end->cpu_time, begin->cpu_time);
+}
+
TEST(ResourceCoalitionMacTest, Difference) {
coalition_resource_usage left =
GetTestCoalitionResourceUsage(/* increment= */ 1);
@@ -98,4 +153,282 @@ TEST(ResourceCoalitionMacTest, Difference) {
EXPECT_EQ(diff.pm_writes, 1U);
}
+namespace {
+
+constexpr base::TimeDelta kIntervalDuration = base::Seconds(2.5);
+
+constexpr double kExpectedCPUUsagePerSecondPercent = 0.7;
+constexpr double kExpectedGPUUsagePerSecondPercent = 0.3;
+// Note: The following counters must have an integral value once multiplied by
+// the interval length in seconds (2.5).
+constexpr double kExpectedInterruptWakeUpPerSecond = 0.4;
+constexpr double kExpectedPlatformIdleWakeUpPerSecond = 10;
+constexpr double kExpectedBytesReadPerSecond = 0.8;
+constexpr double kExpectedBytesWrittenPerSecond = 1.6;
+constexpr double kExpectedPowerNW = 10000.0;
+// This number will be multiplied by the int value associated with a QoS level
+// to compute the expected time spent in this QoS level. E.g.
+// |QoSLevels::kUtility == 3| so the time spent in the utility QoS state will
+// be set to 3 * 0.1 = 30%.
+constexpr double kExpectedQoSTimeBucketIdMultiplier = 0.1;
+
+// Scales a time given in ns to mach_time in |timebase|.
+uint64_t NsScaleToTimebase(const mach_timebase_info_data_t& timebase,
+ int64_t time_ns) {
+ return time_ns * timebase.denom / timebase.numer;
+}
+
+// Returns test data with all time quantities scaled to the given time base.
+std::unique_ptr<coalition_resource_usage> GetCoalitionResourceUsageRateTestData(
+ const mach_timebase_info_data_t& timebase) {
+ std::unique_ptr<coalition_resource_usage> test_data =
+ std::make_unique<coalition_resource_usage>();
+
+ // Scales a time given in ns to mach_time in |timebase|.
+ auto scale_to_timebase = [&timebase](double time_ns) -> int64_t {
+ return NsScaleToTimebase(timebase, time_ns);
+ };
+
+ test_data->cpu_time = scale_to_timebase(kExpectedCPUUsagePerSecondPercent *
+ kIntervalDuration.InNanoseconds());
+ test_data->interrupt_wakeups =
+ kExpectedInterruptWakeUpPerSecond * kIntervalDuration.InSecondsF();
+ test_data->platform_idle_wakeups =
+ kExpectedPlatformIdleWakeUpPerSecond * kIntervalDuration.InSecondsF();
+ test_data->bytesread =
+ kExpectedBytesReadPerSecond * kIntervalDuration.InSecondsF();
+ test_data->byteswritten =
+ kExpectedBytesWrittenPerSecond * kIntervalDuration.InSecondsF();
+ test_data->gpu_time = scale_to_timebase(kExpectedGPUUsagePerSecondPercent *
+ kIntervalDuration.InNanoseconds());
+ test_data->energy = kExpectedPowerNW * kIntervalDuration.InSecondsF();
+ for (int i = 0; i < COALITION_NUM_THREAD_QOS_TYPES; ++i) {
+ test_data->cpu_time_eqos[i] =
+ scale_to_timebase(i * kExpectedQoSTimeBucketIdMultiplier *
+ kIntervalDuration.InNanoseconds());
+ }
+ test_data->cpu_time_eqos_len = COALITION_NUM_THREAD_QOS_TYPES;
+
+ return test_data;
+}
+
+} // namespace
+
+TEST(ResourceCoalitionMacTest, GetDataRate_NoEnergyImpact_Intel) {
+ // Keep the initial data zero initialized.
+ std::unique_ptr<coalition_resource_usage> t0_data =
+ std::make_unique<coalition_resource_usage>();
+ std::unique_ptr<coalition_resource_usage> t1_data =
+ GetCoalitionResourceUsageRateTestData(kIntelTimebase);
+
+ auto rate = GetCoalitionResourceUsageRate(
+ *t0_data, *t1_data, kIntervalDuration, kIntelTimebase, absl::nullopt);
+ ASSERT_TRUE(rate);
+ EXPECT_EQ(kExpectedCPUUsagePerSecondPercent, rate->cpu_time_per_second);
+ EXPECT_EQ(kExpectedInterruptWakeUpPerSecond,
+ rate->interrupt_wakeups_per_second);
+ EXPECT_EQ(kExpectedPlatformIdleWakeUpPerSecond,
+ rate->platform_idle_wakeups_per_second);
+ EXPECT_EQ(kExpectedBytesReadPerSecond, rate->bytesread_per_second);
+ EXPECT_EQ(kExpectedBytesWrittenPerSecond, rate->byteswritten_per_second);
+ EXPECT_EQ(kExpectedGPUUsagePerSecondPercent, rate->gpu_time_per_second);
+ EXPECT_FALSE(rate->energy_impact_per_second.has_value());
+ EXPECT_EQ(kExpectedPowerNW, rate->power_nw);
+
+ for (int i = 0; i < COALITION_NUM_THREAD_QOS_TYPES; ++i) {
+ EXPECT_DOUBLE_EQ(i * kExpectedQoSTimeBucketIdMultiplier,
+ rate->qos_time_per_second[i]);
+ }
+}
+
+TEST(ResourceCoalitionMacTest, GetDataRate_NoEnergyImpact_M1) {
+ // Keep the initial data zero initialized.
+ std::unique_ptr<coalition_resource_usage> t0_data =
+ std::make_unique<coalition_resource_usage>();
+ std::unique_ptr<coalition_resource_usage> t1_data =
+ GetCoalitionResourceUsageRateTestData(kM1Timebase);
+
+ auto rate = GetCoalitionResourceUsageRate(
+ *t0_data, *t1_data, kIntervalDuration, kM1Timebase, absl::nullopt);
+ ASSERT_TRUE(rate);
+ EXPECT_DOUBLE_EQ(kExpectedCPUUsagePerSecondPercent,
+ rate->cpu_time_per_second);
+ EXPECT_DOUBLE_EQ(kExpectedInterruptWakeUpPerSecond,
+ rate->interrupt_wakeups_per_second);
+ EXPECT_DOUBLE_EQ(kExpectedPlatformIdleWakeUpPerSecond,
+ rate->platform_idle_wakeups_per_second);
+ EXPECT_DOUBLE_EQ(kExpectedBytesReadPerSecond, rate->bytesread_per_second);
+ EXPECT_DOUBLE_EQ(kExpectedBytesWrittenPerSecond,
+ rate->byteswritten_per_second);
+ EXPECT_DOUBLE_EQ(kExpectedGPUUsagePerSecondPercent,
+ rate->gpu_time_per_second);
+ EXPECT_FALSE(rate->energy_impact_per_second.has_value());
+ EXPECT_DOUBLE_EQ(kExpectedPowerNW, rate->power_nw);
+
+ for (int i = 0; i < COALITION_NUM_THREAD_QOS_TYPES; ++i) {
+ EXPECT_DOUBLE_EQ(i * kExpectedQoSTimeBucketIdMultiplier,
+ rate->qos_time_per_second[i]);
+ }
+}
+
+TEST(ResourceCoalitionMacTest, GetDataRate_WithEnergyImpact_Intel) {
+ std::unique_ptr<coalition_resource_usage> t0_data =
+ std::make_unique<coalition_resource_usage>();
+ std::unique_ptr<coalition_resource_usage> t1_data =
+ GetCoalitionResourceUsageRateTestData(kIntelTimebase);
+
+ auto rate =
+ GetCoalitionResourceUsageRate(*t0_data, *t1_data, kIntervalDuration,
+ kIntelTimebase, kEnergyImpactCoefficients);
+ ASSERT_TRUE(rate);
+ EXPECT_EQ(kExpectedCPUUsagePerSecondPercent, rate->cpu_time_per_second);
+ EXPECT_EQ(kExpectedInterruptWakeUpPerSecond,
+ rate->interrupt_wakeups_per_second);
+ EXPECT_EQ(kExpectedPlatformIdleWakeUpPerSecond,
+ rate->platform_idle_wakeups_per_second);
+ EXPECT_EQ(kExpectedBytesReadPerSecond, rate->bytesread_per_second);
+ EXPECT_EQ(kExpectedBytesWrittenPerSecond, rate->byteswritten_per_second);
+ EXPECT_EQ(kExpectedGPUUsagePerSecondPercent, rate->gpu_time_per_second);
+ ASSERT_TRUE(rate->energy_impact_per_second.has_value());
+ EXPECT_EQ(271.2, rate->energy_impact_per_second.value());
+ EXPECT_FLOAT_EQ(kExpectedPowerNW, rate->power_nw);
+
+ for (int i = 0; i < COALITION_NUM_THREAD_QOS_TYPES; ++i) {
+ EXPECT_DOUBLE_EQ(i * kExpectedQoSTimeBucketIdMultiplier,
+ rate->qos_time_per_second[i]);
+ }
+}
+
+TEST(ResourceCoalitionMacTest, GetDataRate_WithEnergyImpact_M1) {
+ std::unique_ptr<coalition_resource_usage> t0_data =
+ std::make_unique<coalition_resource_usage>();
+ std::unique_ptr<coalition_resource_usage> t1_data =
+ GetCoalitionResourceUsageRateTestData(kM1Timebase);
+
+ auto rate =
+ GetCoalitionResourceUsageRate(*t0_data, *t1_data, kIntervalDuration,
+ kM1Timebase, kEnergyImpactCoefficients);
+ ASSERT_TRUE(rate);
+ EXPECT_EQ(kExpectedCPUUsagePerSecondPercent, rate->cpu_time_per_second);
+ EXPECT_EQ(kExpectedInterruptWakeUpPerSecond,
+ rate->interrupt_wakeups_per_second);
+ EXPECT_EQ(kExpectedPlatformIdleWakeUpPerSecond,
+ rate->platform_idle_wakeups_per_second);
+ EXPECT_EQ(kExpectedBytesReadPerSecond, rate->bytesread_per_second);
+ EXPECT_EQ(kExpectedBytesWrittenPerSecond, rate->byteswritten_per_second);
+ EXPECT_EQ(kExpectedGPUUsagePerSecondPercent, rate->gpu_time_per_second);
+ ASSERT_TRUE(rate->energy_impact_per_second.has_value());
+ EXPECT_EQ(271.2, rate->energy_impact_per_second.value());
+ EXPECT_FLOAT_EQ(kExpectedPowerNW, rate->power_nw);
+
+ for (int i = 0; i < COALITION_NUM_THREAD_QOS_TYPES; ++i) {
+ EXPECT_DOUBLE_EQ(i * kExpectedQoSTimeBucketIdMultiplier,
+ rate->qos_time_per_second[i]);
+ }
+}
+
+namespace {
+
+bool DataOverflowInvalidatesDiffImpl(
+ std::unique_ptr<coalition_resource_usage> t0,
+ std::unique_ptr<coalition_resource_usage> t1,
+ uint64_t* field_to_overflow) {
+ // Initialize all fields to a non zero value.
+ ::memset(t0.get(), 1000, sizeof(coalition_resource_usage));
+ ::memset(t1.get(), 1000, sizeof(coalition_resource_usage));
+ *field_to_overflow = 0;
+ t1->cpu_time_eqos_len = COALITION_NUM_THREAD_QOS_TYPES;
+ return !GetCoalitionResourceUsageRate(*t0, *t1, kIntervalDuration,
+ kIntelTimebase, absl::nullopt)
+ .has_value();
+}
+
+bool DataOverflowInvalidatesDiff(
+ uint64_t coalition_resource_usage::*member_ptr) {
+ std::unique_ptr<coalition_resource_usage> t0_data =
+ std::make_unique<coalition_resource_usage>();
+ std::unique_ptr<coalition_resource_usage> t1_data =
+ std::make_unique<coalition_resource_usage>();
+ auto* ptr = &(t1_data.get()->*member_ptr);
+ return DataOverflowInvalidatesDiffImpl(std::move(t0_data), std::move(t1_data),
+ ptr);
+}
+
+bool DataOverflowInvalidatesDiff(
+ uint64_t (
+ coalition_resource_usage::*member_ptr)[COALITION_NUM_THREAD_QOS_TYPES],
+ int index_to_check) {
+ std::unique_ptr<coalition_resource_usage> t0_data =
+ std::make_unique<coalition_resource_usage>();
+ std::unique_ptr<coalition_resource_usage> t1_data =
+ std::make_unique<coalition_resource_usage>();
+ auto* ptr = &(t1_data.get()->*member_ptr)[index_to_check];
+ return DataOverflowInvalidatesDiffImpl(std::move(t0_data), std::move(t1_data),
+ ptr);
+}
+
+} // namespace
+
+// If one of these tests fails then it means that overflows on a newly tracked
+// coalition field aren't tracked properly in GetCoalitionResourceUsageRate().
+TEST(ResourceCoalitionTests, Overflows) {
+ EXPECT_FALSE(DataOverflowInvalidatesDiff(
+ &coalition_resource_usage::energy_billed_to_me));
+ EXPECT_FALSE(
+ DataOverflowInvalidatesDiff(&coalition_resource_usage::tasks_started));
+ EXPECT_FALSE(
+ DataOverflowInvalidatesDiff(&coalition_resource_usage::tasks_exited));
+ EXPECT_FALSE(
+ DataOverflowInvalidatesDiff(&coalition_resource_usage::time_nonempty));
+ EXPECT_TRUE(DataOverflowInvalidatesDiff(&coalition_resource_usage::cpu_time));
+ EXPECT_TRUE(DataOverflowInvalidatesDiff(
+ &coalition_resource_usage::interrupt_wakeups));
+ EXPECT_TRUE(DataOverflowInvalidatesDiff(
+ &coalition_resource_usage::platform_idle_wakeups));
+ EXPECT_TRUE(
+ DataOverflowInvalidatesDiff(&coalition_resource_usage::bytesread));
+ EXPECT_TRUE(
+ DataOverflowInvalidatesDiff(&coalition_resource_usage::byteswritten));
+ EXPECT_TRUE(DataOverflowInvalidatesDiff(&coalition_resource_usage::gpu_time));
+ EXPECT_FALSE(DataOverflowInvalidatesDiff(
+ &coalition_resource_usage::cpu_time_billed_to_me));
+ EXPECT_FALSE(DataOverflowInvalidatesDiff(
+ &coalition_resource_usage::cpu_time_billed_to_others));
+ EXPECT_TRUE(DataOverflowInvalidatesDiff(&coalition_resource_usage::energy));
+ EXPECT_FALSE(DataOverflowInvalidatesDiff(
+ &coalition_resource_usage::logical_immediate_writes));
+ EXPECT_FALSE(DataOverflowInvalidatesDiff(
+ &coalition_resource_usage::logical_deferred_writes));
+ EXPECT_FALSE(DataOverflowInvalidatesDiff(
+ &coalition_resource_usage::logical_invalidated_writes));
+ EXPECT_FALSE(DataOverflowInvalidatesDiff(
+ &coalition_resource_usage::logical_metadata_writes));
+ EXPECT_FALSE(DataOverflowInvalidatesDiff(
+ &coalition_resource_usage::logical_immediate_writes_to_external));
+ EXPECT_FALSE(DataOverflowInvalidatesDiff(
+ &coalition_resource_usage::logical_deferred_writes_to_external));
+ EXPECT_FALSE(DataOverflowInvalidatesDiff(
+ &coalition_resource_usage::logical_invalidated_writes_to_external));
+ EXPECT_FALSE(DataOverflowInvalidatesDiff(
+ &coalition_resource_usage::logical_metadata_writes_to_external));
+ EXPECT_FALSE(DataOverflowInvalidatesDiff(
+ &coalition_resource_usage::energy_billed_to_me));
+ EXPECT_FALSE(DataOverflowInvalidatesDiff(
+ &coalition_resource_usage::energy_billed_to_others));
+ EXPECT_FALSE(
+ DataOverflowInvalidatesDiff(&coalition_resource_usage::cpu_ptime));
+ for (int i = 0; i < COALITION_NUM_THREAD_QOS_TYPES; ++i) {
+ EXPECT_TRUE(DataOverflowInvalidatesDiff(
+ &coalition_resource_usage::cpu_time_eqos, i));
+ }
+ EXPECT_FALSE(
+ DataOverflowInvalidatesDiff(&coalition_resource_usage::cpu_instructions));
+ EXPECT_FALSE(
+ DataOverflowInvalidatesDiff(&coalition_resource_usage::cpu_cycles));
+ EXPECT_FALSE(DataOverflowInvalidatesDiff(
+ &coalition_resource_usage::fs_metadata_writes));
+ EXPECT_FALSE(
+ DataOverflowInvalidatesDiff(&coalition_resource_usage::pm_writes));
+}
+
} // namespace power_metrics
diff --git a/chromium/components/power_metrics/sampling_event_source.cc b/chromium/components/power_metrics/sampling_event_source.cc
index 41d2ee7beb8..3a5caa2674e 100644
--- a/chromium/components/power_metrics/sampling_event_source.cc
+++ b/chromium/components/power_metrics/sampling_event_source.cc
@@ -4,8 +4,8 @@
#include "components/power_metrics/sampling_event_source.h"
-namespace power_sampler {
+namespace power_metrics {
SamplingEventSource::~SamplingEventSource() = default;
-} // namespace power_sampler
+} // namespace power_metrics
diff --git a/chromium/components/power_metrics/sampling_event_source.h b/chromium/components/power_metrics/sampling_event_source.h
index 61743b66f3d..20797a60e67 100644
--- a/chromium/components/power_metrics/sampling_event_source.h
+++ b/chromium/components/power_metrics/sampling_event_source.h
@@ -7,7 +7,7 @@
#include "base/callback_forward.h"
-namespace power_sampler {
+namespace power_metrics {
// Invokes a callback when a Sample should be requested from all Samplers.
class SamplingEventSource {
@@ -21,6 +21,6 @@ class SamplingEventSource {
virtual bool Start(SamplingEventCallback callback) = 0;
};
-} // namespace power_sampler
+} // namespace power_metrics
#endif // COMPONENTS_POWER_METRICS_SAMPLING_EVENT_SOURCE_H_
diff --git a/chromium/components/power_metrics/timer_sampling_event_source.cc b/chromium/components/power_metrics/timer_sampling_event_source.cc
index 3d6f058bfdb..eef92f2b872 100644
--- a/chromium/components/power_metrics/timer_sampling_event_source.cc
+++ b/chromium/components/power_metrics/timer_sampling_event_source.cc
@@ -6,7 +6,7 @@
#include "base/check.h"
-namespace power_sampler {
+namespace power_metrics {
TimerSamplingEventSource::TimerSamplingEventSource(base::TimeDelta interval)
: interval_(interval) {}
@@ -19,4 +19,4 @@ bool TimerSamplingEventSource::Start(SamplingEventCallback callback) {
return true;
}
-} // namespace power_sampler
+} // namespace power_metrics
diff --git a/chromium/components/power_metrics/timer_sampling_event_source.h b/chromium/components/power_metrics/timer_sampling_event_source.h
index e350d6735ba..a7115d17a24 100644
--- a/chromium/components/power_metrics/timer_sampling_event_source.h
+++ b/chromium/components/power_metrics/timer_sampling_event_source.h
@@ -9,7 +9,7 @@
#include "base/timer/timer.h"
#include "components/power_metrics/sampling_event_source.h"
-namespace power_sampler {
+namespace power_metrics {
// Generates a sampling event at regular time intervals.
class TimerSamplingEventSource : public SamplingEventSource {
@@ -27,6 +27,6 @@ class TimerSamplingEventSource : public SamplingEventSource {
base::RepeatingTimer timer_;
};
-} // namespace power_sampler
+} // namespace power_metrics
#endif // COMPONENTS_POWER_METRICS_TIMER_SAMPLING_EVENT_SOURCE_H_
diff --git a/chromium/components/power_metrics/timer_sampling_event_source_unittest.cc b/chromium/components/power_metrics/timer_sampling_event_source_unittest.cc
index 3c2d1dc10ee..6d89e098424 100644
--- a/chromium/components/power_metrics/timer_sampling_event_source_unittest.cc
+++ b/chromium/components/power_metrics/timer_sampling_event_source_unittest.cc
@@ -8,7 +8,7 @@
#include "base/test/task_environment.h"
#include "testing/gtest/include/gtest/gtest.h"
-namespace power_sampler {
+namespace power_metrics {
TEST(TimerSamplingEventSourceTest, Basic) {
constexpr base::TimeDelta kDelay = base::Seconds(1);
@@ -28,4 +28,4 @@ TEST(TimerSamplingEventSourceTest, Basic) {
EXPECT_EQ(11, num_callbacks);
}
-} // namespace power_sampler
+} // namespace power_metrics
diff --git a/chromium/components/power_scheduler/power_scheduler.cc b/chromium/components/power_scheduler/power_scheduler.cc
index 0c2dcb032e9..8b5c8d9de33 100644
--- a/chromium/components/power_scheduler/power_scheduler.cc
+++ b/chromium/components/power_scheduler/power_scheduler.cc
@@ -10,6 +10,7 @@
#include "base/cpu_affinity_posix.h"
#include "base/feature_list.h"
#include "base/lazy_instance.h"
+#include "base/metrics/field_trial_params.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/no_destructor.h"
diff --git a/chromium/components/power_scheduler/power_scheduler.h b/chromium/components/power_scheduler/power_scheduler.h
index fea177e2662..a1dfdb50798 100644
--- a/chromium/components/power_scheduler/power_scheduler.h
+++ b/chromium/components/power_scheduler/power_scheduler.h
@@ -8,6 +8,7 @@
#include "base/component_export.h"
#include "base/cpu_affinity_posix.h"
#include "base/memory/raw_ptr.h"
+#include "base/no_destructor.h"
#include "base/process/process_metrics.h"
#include "base/task/task_observer.h"
#include "components/power_scheduler/power_mode_arbiter.h"
diff --git a/chromium/components/prefs/BUILD.gn b/chromium/components/prefs/BUILD.gn
index 0dd1a50a396..c1828d1027e 100644
--- a/chromium/components/prefs/BUILD.gn
+++ b/chromium/components/prefs/BUILD.gn
@@ -2,6 +2,8 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//build/config/chromeos/ui_mode.gni")
+
component("prefs") {
sources = [
"command_line_pref_store.cc",
diff --git a/chromium/components/prefs/in_memory_pref_store_unittest.cc b/chromium/components/prefs/in_memory_pref_store_unittest.cc
index 4ad18640562..81fcf83b9e4 100644
--- a/chromium/components/prefs/in_memory_pref_store_unittest.cc
+++ b/chromium/components/prefs/in_memory_pref_store_unittest.cc
@@ -36,9 +36,9 @@ TEST_F(InMemoryPrefStoreTest, SetGetValue) {
store_->SetValue(kTestPref, std::make_unique<base::Value>(42),
WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
EXPECT_TRUE(store_->GetValue(kTestPref, &value));
- EXPECT_TRUE(base::Value(42).Equals(value));
+ EXPECT_EQ(base::Value(42), *value);
EXPECT_TRUE(store_->GetMutableValue(kTestPref, &mutable_value));
- EXPECT_TRUE(base::Value(42).Equals(mutable_value));
+ EXPECT_EQ(base::Value(42), *mutable_value);
store_->RemoveValue(kTestPref, WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
EXPECT_FALSE(store_->GetValue(kTestPref, &value));
diff --git a/chromium/components/prefs/json_pref_store.cc b/chromium/components/prefs/json_pref_store.cc
index d4f68c8b687..f84b6625d24 100644
--- a/chromium/components/prefs/json_pref_store.cc
+++ b/chromium/components/prefs/json_pref_store.cc
@@ -169,8 +169,8 @@ bool JsonPrefStore::GetValue(const std::string& key,
const base::Value** result) const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- base::Value* tmp = nullptr;
- if (!prefs_->Get(key, &tmp))
+ base::Value* tmp = prefs_->FindPath(key);
+ if (!tmp)
return false;
if (result)
@@ -209,7 +209,13 @@ bool JsonPrefStore::GetMutableValue(const std::string& key,
base::Value** result) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- return prefs_->Get(key, result);
+ base::Value* tmp = prefs_->FindPath(key);
+ if (!tmp)
+ return false;
+
+ if (result)
+ *result = tmp;
+ return true;
}
void JsonPrefStore::SetValue(const std::string& key,
@@ -218,8 +224,7 @@ void JsonPrefStore::SetValue(const std::string& key,
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(value);
- base::Value* old_value = nullptr;
- prefs_->Get(key, &old_value);
+ base::Value* old_value = prefs_->FindPath(key);
if (!old_value || *value != *old_value) {
prefs_->SetPath(key, std::move(*value));
ReportValueChanged(key, flags);
@@ -232,8 +237,7 @@ void JsonPrefStore::SetValueSilently(const std::string& key,
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(value);
- base::Value* old_value = nullptr;
- prefs_->Get(key, &old_value);
+ base::Value* old_value = prefs_->FindPath(key);
if (!old_value || *value != *old_value) {
prefs_->SetPath(key, std::move(*value));
ScheduleWrite(flags);
diff --git a/chromium/components/prefs/json_pref_store_unittest.cc b/chromium/components/prefs/json_pref_store_unittest.cc
index acce087f2e1..6deeb68010e 100644
--- a/chromium/components/prefs/json_pref_store_unittest.cc
+++ b/chromium/components/prefs/json_pref_store_unittest.cc
@@ -140,7 +140,7 @@ base::test::TaskEnvironment::ThreadPoolExecutionMode GetExecutionMode(
CommitPendingWriteMode commit_mode) {
switch (commit_mode) {
case CommitPendingWriteMode::WITHOUT_CALLBACK:
- FALLTHROUGH;
+ [[fallthrough]];
case CommitPendingWriteMode::WITH_CALLBACK:
return base::test::TaskEnvironment::ThreadPoolExecutionMode::QUEUED;
case CommitPendingWriteMode::WITH_SYNCHRONOUS_CALLBACK:
@@ -388,9 +388,9 @@ TEST_P(JsonPrefStoreTest, PreserveEmptyValues) {
// Check values.
const Value* result = nullptr;
EXPECT_TRUE(pref_store->GetValue("list", &result));
- EXPECT_TRUE(ListValue().Equals(result));
+ EXPECT_EQ(ListValue(), *result);
EXPECT_TRUE(pref_store->GetValue("dict", &result));
- EXPECT_TRUE(DictionaryValue().Equals(result));
+ EXPECT_EQ(DictionaryValue(), *result);
}
// This test is just documenting some potentially non-obvious behavior. It
diff --git a/chromium/components/prefs/mock_pref_change_callback.h b/chromium/components/prefs/mock_pref_change_callback.h
index 8541ee9e180..6227f8a1acf 100644
--- a/chromium/components/prefs/mock_pref_change_callback.h
+++ b/chromium/components/prefs/mock_pref_change_callback.h
@@ -8,6 +8,7 @@
#include <string>
#include "base/memory/raw_ptr.h"
+#include "base/memory/values_equivalent.h"
#include "components/prefs/pref_change_registrar.h"
#include "components/prefs/pref_service.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -24,12 +25,7 @@ MATCHER_P3(PrefValueMatches, prefs, pref_name, value, "") {
if (!pref)
return false;
- const base::Value* actual_value = pref->GetValue();
- if (!actual_value)
- return value == NULL;
- if (!value)
- return actual_value == NULL;
- return *value == *actual_value;
+ return base::ValuesEquivalent(value, pref->GetValue());
}
// A mock for testing preference notifications and easy setup of expectations.
diff --git a/chromium/components/prefs/overlay_user_pref_store_unittest.cc b/chromium/components/prefs/overlay_user_pref_store_unittest.cc
index d8be47e61b0..067188d9653 100644
--- a/chromium/components/prefs/overlay_user_pref_store_unittest.cc
+++ b/chromium/components/prefs/overlay_user_pref_store_unittest.cc
@@ -105,29 +105,29 @@ TEST_F(OverlayUserPrefStoreTest, GetAndSet) {
// Value shines through:
EXPECT_TRUE(overlay_->GetValue(regular_key, &value));
- EXPECT_TRUE(base::Value(42).Equals(value));
+ EXPECT_EQ(base::Value(42), *value);
EXPECT_TRUE(underlay_->GetValue(regular_key, &value));
- EXPECT_TRUE(base::Value(42).Equals(value));
+ EXPECT_EQ(base::Value(42), *value);
overlay_->SetValue(regular_key, std::make_unique<Value>(43),
WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
EXPECT_TRUE(overlay_->GetValue(regular_key, &value));
- EXPECT_TRUE(base::Value(43).Equals(value));
+ EXPECT_EQ(base::Value(43), *value);
EXPECT_TRUE(underlay_->GetValue(regular_key, &value));
- EXPECT_TRUE(base::Value(42).Equals(value));
+ EXPECT_EQ(base::Value(42), *value);
overlay_->RemoveValue(regular_key,
WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
// Value shines through:
EXPECT_TRUE(overlay_->GetValue(regular_key, &value));
- EXPECT_TRUE(base::Value(42).Equals(value));
+ EXPECT_EQ(base::Value(42), *value);
EXPECT_TRUE(underlay_->GetValue(regular_key, &value));
- EXPECT_TRUE(base::Value(42).Equals(value));
+ EXPECT_EQ(base::Value(42), *value);
}
// Check that GetMutableValue does not return the dictionary of the underlay.
@@ -173,7 +173,7 @@ TEST_F(OverlayUserPrefStoreTest, GlobalPref) {
// Check that we get this value from the overlay
EXPECT_TRUE(overlay_->GetValue(persistent_key, &value));
- EXPECT_TRUE(base::Value(43).Equals(value));
+ EXPECT_EQ(base::Value(43), *value);
// Check that overwriting change in overlay is reported.
overlay_->SetValue(persistent_key, std::make_unique<Value>(44),
@@ -182,9 +182,9 @@ TEST_F(OverlayUserPrefStoreTest, GlobalPref) {
// Check that we get this value from the overlay and the underlay.
EXPECT_TRUE(overlay_->GetValue(persistent_key, &value));
- EXPECT_TRUE(base::Value(44).Equals(value));
+ EXPECT_EQ(base::Value(44), *value);
EXPECT_TRUE(underlay_->GetValue(persistent_key, &value));
- EXPECT_TRUE(base::Value(44).Equals(value));
+ EXPECT_EQ(base::Value(44), *value);
// Check that overlay remove is reported.
overlay_->RemoveValue(persistent_key,
@@ -221,12 +221,12 @@ TEST_F(OverlayUserPrefStoreTest, ClearMutableValues) {
const Value* value = nullptr;
// Check that an overlay preference is returned.
EXPECT_TRUE(overlay_->GetValue(regular_key, &value));
- EXPECT_TRUE(base::Value(43).Equals(value));
+ EXPECT_EQ(base::Value(43), *value);
overlay_->ClearMutableValues();
// Check that an underlay preference is returned.
EXPECT_TRUE(overlay_->GetValue(regular_key, &value));
- EXPECT_TRUE(base::Value(42).Equals(value));
+ EXPECT_EQ(base::Value(42), *value);
}
// Check that mutable values are removed correctly when using a silent set.
@@ -240,12 +240,12 @@ TEST_F(OverlayUserPrefStoreTest, ClearMutableValues_Silently) {
const Value* value = nullptr;
// Check that an overlay preference is returned.
EXPECT_TRUE(overlay_->GetValue(regular_key, &value));
- EXPECT_TRUE(base::Value(43).Equals(value));
+ EXPECT_EQ(base::Value(43), *value);
overlay_->ClearMutableValues();
// Check that an underlay preference is returned.
EXPECT_TRUE(overlay_->GetValue(regular_key, &value));
- EXPECT_TRUE(base::Value(42).Equals(value));
+ EXPECT_EQ(base::Value(42), *value);
}
TEST_F(OverlayUserPrefStoreTest, GetValues) {
@@ -264,15 +264,15 @@ TEST_F(OverlayUserPrefStoreTest, GetValues) {
const Value* value = nullptr;
// Check that an overlay preference is returned.
ASSERT_TRUE(values->Get(persistent_key, &value));
- EXPECT_TRUE(base::Value(42).Equals(value));
+ EXPECT_EQ(base::Value(42), *value);
// Check that an underlay preference is returned.
ASSERT_TRUE(values->Get(regular_key, &value));
- EXPECT_TRUE(base::Value(43).Equals(value));
+ EXPECT_EQ(base::Value(43), *value);
// Check that the overlay is preferred.
ASSERT_TRUE(values->Get(shared_key, &value));
- EXPECT_TRUE(base::Value(43).Equals(value));
+ EXPECT_EQ(base::Value(43), *value);
}
TEST_F(OverlayUserPrefStoreTest, CommitPendingWriteWithCallback) {
diff --git a/chromium/components/prefs/pref_member.cc b/chromium/components/prefs/pref_member.cc
index f5340ab1fd0..8ee5e7d4ec8 100644
--- a/chromium/components/prefs/pref_member.cc
+++ b/chromium/components/prefs/pref_member.cc
@@ -134,7 +134,7 @@ bool PrefMemberVectorStringUpdate(const base::Value& value,
return false;
std::vector<std::string> local_vector;
- for (const auto& item : value.GetList()) {
+ for (const auto& item : value.GetListDeprecated()) {
if (!item.is_string())
return false;
local_vector.push_back(item.GetString());
diff --git a/chromium/components/prefs/pref_member_unittest.cc b/chromium/components/prefs/pref_member_unittest.cc
index 291b043a876..ca1bbe35f5f 100644
--- a/chromium/components/prefs/pref_member_unittest.cc
+++ b/chromium/components/prefs/pref_member_unittest.cc
@@ -214,7 +214,7 @@ TEST_F(PrefMemberTest, BasicGetAndSet) {
string_list.Init(kStringListPref, &prefs);
// Check the defaults
- EXPECT_TRUE(expected_list.Equals(prefs.GetList(kStringListPref)));
+ EXPECT_EQ(expected_list, *prefs.GetList(kStringListPref));
EXPECT_EQ(expected_vector, string_list.GetValue());
EXPECT_EQ(expected_vector, *string_list);
EXPECT_TRUE(string_list.IsDefaultValue());
@@ -224,7 +224,7 @@ TEST_F(PrefMemberTest, BasicGetAndSet) {
expected_vector.push_back("foo");
string_list.SetValue(expected_vector);
- EXPECT_TRUE(expected_list.Equals(prefs.GetList(kStringListPref)));
+ EXPECT_EQ(expected_list, *prefs.GetList(kStringListPref));
EXPECT_EQ(expected_vector, string_list.GetValue());
EXPECT_EQ(expected_vector, *string_list);
EXPECT_FALSE(string_list.IsDefaultValue());
@@ -234,17 +234,18 @@ TEST_F(PrefMemberTest, BasicGetAndSet) {
expected_vector.push_back("bar");
prefs.Set(kStringListPref, expected_list);
- EXPECT_TRUE(expected_list.Equals(prefs.GetList(kStringListPref)));
+ EXPECT_EQ(expected_list, *prefs.GetList(kStringListPref));
EXPECT_EQ(expected_vector, string_list.GetValue());
EXPECT_EQ(expected_vector, *string_list);
EXPECT_FALSE(string_list.IsDefaultValue());
// Try removing through the pref.
- EXPECT_TRUE(expected_list.EraseListIter(expected_list.GetList().begin()));
+ EXPECT_TRUE(
+ expected_list.EraseListIter(expected_list.GetListDeprecated().begin()));
expected_vector.erase(expected_vector.begin());
prefs.Set(kStringListPref, expected_list);
- EXPECT_TRUE(expected_list.Equals(prefs.GetList(kStringListPref)));
+ EXPECT_EQ(expected_list, *prefs.GetList(kStringListPref));
EXPECT_EQ(expected_vector, string_list.GetValue());
EXPECT_EQ(expected_vector, *string_list);
EXPECT_FALSE(string_list.IsDefaultValue());
diff --git a/chromium/components/prefs/pref_service.cc b/chromium/components/prefs/pref_service.cc
index ae6cdad1aae..f7f709787d7 100644
--- a/chromium/components/prefs/pref_service.cc
+++ b/chromium/components/prefs/pref_service.cc
@@ -28,7 +28,7 @@
#include "components/prefs/pref_notifier_impl.h"
#include "components/prefs/pref_registry.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "components/prefs/android/pref_service_android.h"
#endif
@@ -89,10 +89,22 @@ void CheckForNewPrefChangesInPrefStore(
} // namespace
+PrefService::PersistentPrefStoreLoadingObserver::
+ PersistentPrefStoreLoadingObserver(PrefService* pref_service)
+ : pref_service_(pref_service) {
+ DCHECK(pref_service_);
+}
+
+void PrefService::PersistentPrefStoreLoadingObserver::OnInitializationCompleted(
+ bool succeeded) {
+ pref_service_->CheckPrefsLoaded();
+}
+
PrefService::PrefService(
std::unique_ptr<PrefNotifierImpl> pref_notifier,
std::unique_ptr<PrefValueStore> pref_value_store,
scoped_refptr<PersistentPrefStore> user_prefs,
+ scoped_refptr<PersistentPrefStore> standalone_browser_prefs,
scoped_refptr<PrefRegistry> pref_registry,
base::RepeatingCallback<void(PersistentPrefStore::PrefReadError)>
read_error_callback,
@@ -100,8 +112,12 @@ PrefService::PrefService(
: pref_notifier_(std::move(pref_notifier)),
pref_value_store_(std::move(pref_value_store)),
user_pref_store_(std::move(user_prefs)),
+ standalone_browser_pref_store_(std::move(standalone_browser_prefs)),
read_error_callback_(std::move(read_error_callback)),
- pref_registry_(std::move(pref_registry)) {
+ pref_registry_(std::move(pref_registry)),
+ pref_store_observer_(
+ std::make_unique<PrefService::PersistentPrefStoreLoadingObserver>(
+ this)) {
pref_notifier_->SetPrefService(this);
DCHECK(pref_registry_);
@@ -113,6 +129,13 @@ PrefService::PrefService(
PrefService::~PrefService() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ // Remove observers. This could be necessary if this service is destroyed
+ // before the prefs are fully loaded.
+ user_pref_store_->RemoveObserver(pref_store_observer_.get());
+ if (standalone_browser_pref_store_) {
+ standalone_browser_pref_store_->RemoveObserver(pref_store_observer_.get());
+ }
+
// TODO(crbug.com/942491, 946668, 945772) The following code collects
// augments stack dumps created by ~PrefNotifierImpl() with information
// whether the profile owning the PrefService is an incognito profile.
@@ -129,16 +152,71 @@ PrefService::~PrefService() {
}
void PrefService::InitFromStorage(bool async) {
- if (user_pref_store_->IsInitializationComplete()) {
- read_error_callback_.Run(user_pref_store_->GetReadError());
- } else if (!async) {
- read_error_callback_.Run(user_pref_store_->ReadPrefs());
+ if (!async) {
+ if (!user_pref_store_->IsInitializationComplete()) {
+ user_pref_store_->ReadPrefs();
+ }
+ if (standalone_browser_pref_store_ &&
+ !standalone_browser_pref_store_->IsInitializationComplete()) {
+ standalone_browser_pref_store_->ReadPrefs();
+ }
+ CheckPrefsLoaded();
+ return;
+ }
+
+ CheckPrefsLoaded();
+
+ if (!user_pref_store_->IsInitializationComplete()) {
+ user_pref_store_->AddObserver(pref_store_observer_.get());
+ user_pref_store_->ReadPrefsAsync(nullptr);
+ }
+
+ if (standalone_browser_pref_store_ &&
+ !standalone_browser_pref_store_->IsInitializationComplete()) {
+ standalone_browser_pref_store_->AddObserver(pref_store_observer_.get());
+ standalone_browser_pref_store_->ReadPrefsAsync(nullptr);
+ }
+}
+
+void PrefService::CheckPrefsLoaded() {
+ if (!(user_pref_store_->IsInitializationComplete() &&
+ (!standalone_browser_pref_store_ ||
+ standalone_browser_pref_store_->IsInitializationComplete()))) {
+ // Not done initializing both prefstores.
+ return;
+ }
+
+ user_pref_store_->RemoveObserver(pref_store_observer_.get());
+ if (standalone_browser_pref_store_) {
+ standalone_browser_pref_store_->RemoveObserver(pref_store_observer_.get());
+ }
+
+ // Both prefstores are initialized, get the read errors.
+ PersistentPrefStore::PrefReadError user_store_error =
+ user_pref_store_->GetReadError();
+ if (!standalone_browser_pref_store_) {
+ read_error_callback_.Run(user_store_error);
+ return;
+ }
+ PersistentPrefStore::PrefReadError standalone_browser_store_error =
+ standalone_browser_pref_store_->GetReadError();
+
+ // If both stores have the same error (or no error), run the callback with
+ // either one. This avoids double-reporting (either way prefs weren't
+ // successfully fully loaded)
+ if (user_store_error == standalone_browser_store_error) {
+ read_error_callback_.Run(user_store_error);
+ } else if (user_store_error == PersistentPrefStore::PREF_READ_ERROR_NONE ||
+ user_store_error == PersistentPrefStore::PREF_READ_ERROR_NO_FILE) {
+ // Prefer to report the standalone_browser_pref_store error if the
+ // user_pref_store error is not significant.
+ read_error_callback_.Run(standalone_browser_store_error);
} else {
- // Guarantee that initialization happens after this function returned.
- base::SequencedTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::BindOnce(&PersistentPrefStore::ReadPrefsAsync, user_pref_store_,
- new ReadErrorHandler(read_error_callback_)));
+ // Either the user_pref_store error is significant, or
+ // both stores failed to load but for different reasons.
+ // The user_store error is more significant in essentially all cases,
+ // so prefer to report that.
+ read_error_callback_.Run(user_store_error);
}
}
@@ -298,8 +376,7 @@ const base::Value* PrefService::Get(const std::string& path) const {
return GetPreferenceValueChecked(path);
}
-const base::DictionaryValue* PrefService::GetDictionary(
- const std::string& path) const {
+const base::Value* PrefService::GetDictionary(const std::string& path) const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
const base::Value* value = GetPreferenceValueChecked(path);
@@ -309,7 +386,7 @@ const base::DictionaryValue* PrefService::GetDictionary(
NOTREACHED();
return nullptr;
}
- return static_cast<const base::DictionaryValue*>(value);
+ return value;
}
const base::Value* PrefService::GetUserPrefValue(
@@ -352,7 +429,7 @@ const base::Value* PrefService::GetDefaultPrefValue(
return value;
}
-const base::ListValue* PrefService::GetList(const std::string& path) const {
+const base::Value* PrefService::GetList(const std::string& path) const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
const base::Value* value = GetPreferenceValueChecked(path);
@@ -362,7 +439,7 @@ const base::ListValue* PrefService::GetList(const std::string& path) const {
NOTREACHED();
return nullptr;
}
- return static_cast<const base::ListValue*>(value);
+ return value;
}
void PrefService::AddPrefObserver(const std::string& path, PrefObserver* obs) {
@@ -435,8 +512,8 @@ void PrefService::ChangePrefValueStore(
pref_value_store_ = pref_value_store_->CloneAndSpecialize(
managed_prefs, supervised_user_prefs, extension_prefs,
nullptr /* command_line_prefs */, nullptr /* user_prefs */,
- recommended_prefs, nullptr /* default_prefs */, pref_notifier_.get(),
- std::move(delegate));
+ nullptr /* standalone_browser_prefs */, recommended_prefs,
+ nullptr /* default_prefs */, pref_notifier_.get(), std::move(delegate));
// Notify |pref_notifier_| on all changed values.
for (const auto& kv : pref_changed_map) {
@@ -453,7 +530,7 @@ void PrefService::RemovePrefObserverAllPrefs(PrefObserver* obs) {
pref_notifier_->RemovePrefObserverAllPrefs(obs);
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
base::android::ScopedJavaLocalRef<jobject> PrefService::GetJavaObject() {
if (!pref_service_android_) {
pref_service_android_ = std::make_unique<PrefServiceAndroid>(this);
diff --git a/chromium/components/prefs/pref_service.h b/chromium/components/prefs/pref_service.h
index 24b5820bdb7..1e9af591770 100644
--- a/chromium/components/prefs/pref_service.h
+++ b/chromium/components/prefs/pref_service.h
@@ -31,7 +31,7 @@
#include "components/prefs/pref_value_store.h"
#include "components/prefs/prefs_export.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "base/android/scoped_java_ref.h"
#endif
@@ -40,7 +40,7 @@ class PrefNotifierImpl;
class PrefObserver;
class PrefRegistry;
class PrefStore;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
class PrefServiceAndroid;
#endif
@@ -176,6 +176,7 @@ class COMPONENTS_PREFS_EXPORT PrefService {
PrefService(std::unique_ptr<PrefNotifierImpl> pref_notifier,
std::unique_ptr<PrefValueStore> pref_value_store,
scoped_refptr<PersistentPrefStore> user_prefs,
+ scoped_refptr<PersistentPrefStore> standalone_browser_prefs,
scoped_refptr<PrefRegistry> pref_registry,
base::RepeatingCallback<void(PersistentPrefStore::PrefReadError)>
read_error_callback,
@@ -233,8 +234,8 @@ class COMPONENTS_PREFS_EXPORT PrefService {
// Note that |path| must point to a registered preference. In that case, these
// functions will never return NULL.
const base::Value* Get(const std::string& path) const;
- const base::DictionaryValue* GetDictionary(const std::string& path) const;
- const base::ListValue* GetList(const std::string& path) const;
+ const base::Value* GetDictionary(const std::string& path) const;
+ const base::Value* GetList(const std::string& path) const;
// Removes a user pref and restores the pref to its default value.
void ClearPref(const std::string& path);
@@ -380,7 +381,7 @@ class COMPONENTS_PREFS_EXPORT PrefService {
void AddPrefObserverAllPrefs(PrefObserver* obs);
void RemovePrefObserverAllPrefs(PrefObserver* obs);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
base::android::ScopedJavaLocalRef<jobject> GetJavaObject();
#endif
@@ -396,6 +397,7 @@ class COMPONENTS_PREFS_EXPORT PrefService {
// Pref Stores and profile that we passed to the PrefValueStore.
const scoped_refptr<PersistentPrefStore> user_pref_store_;
+ const scoped_refptr<PersistentPrefStore> standalone_browser_pref_store_;
// Callback to call when a read error occurs. Always invoked on the sequence
// this PrefService was created own.
@@ -435,6 +437,22 @@ class COMPONENTS_PREFS_EXPORT PrefService {
virtual void AddPrefObserver(const std::string& path, PrefObserver* obs);
virtual void RemovePrefObserver(const std::string& path, PrefObserver* obs);
+ // A PrefStore::Observer which reports loading errors from
+ // PersistentPrefStores after they are loaded. Usually this is only user_prefs
+ // however in ash it additionally includes standalone_browser_prefs. Errors
+ // are only reported once even though multiple files may be loaded.
+ class PersistentPrefStoreLoadingObserver : public PrefStore::Observer {
+ public:
+ explicit PersistentPrefStoreLoadingObserver(PrefService* pref_service_);
+
+ // PrefStore::Observer implementation
+ void OnPrefValueChanged(const std::string& key) override {}
+ void OnInitializationCompleted(bool succeeded) override;
+
+ private:
+ PrefService* pref_service_ = nullptr;
+ };
+
// Sends notification of a changed preference. This needs to be called by
// a ScopedUserPrefUpdate or ScopedDictionaryPrefUpdate if a DictionaryValue
// or ListValue is changed.
@@ -451,6 +469,11 @@ class COMPONENTS_PREFS_EXPORT PrefService {
// This should only be called from the constructor.
void InitFromStorage(bool async);
+ // Verifies that prefs are fully loaded from disk, handling errors. This
+ // method may be called multiple times, but no more than once after all prefs
+ // are loaded.
+ void CheckPrefsLoaded();
+
// Used to set the value of dictionary or list values in the user pref store.
// This will create a dictionary or list if one does not exist in the user
// pref store. This method returns NULL only if you're requesting an
@@ -471,12 +494,15 @@ class COMPONENTS_PREFS_EXPORT PrefService {
const scoped_refptr<PrefRegistry> pref_registry_;
+ std::unique_ptr<PrefService::PersistentPrefStoreLoadingObserver>
+ pref_store_observer_;
+
// Local cache of registered Preference objects. The pref_registry_
// is authoritative with respect to what the types and default values
// of registered preferences are.
mutable PreferenceMap prefs_map_;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Manage and fetch the java object that wraps this PrefService on
// android.
std::unique_ptr<PrefServiceAndroid> pref_service_android_;
diff --git a/chromium/components/prefs/pref_service_factory.cc b/chromium/components/prefs/pref_service_factory.cc
index 2d4cad04124..8030482fc23 100644
--- a/chromium/components/prefs/pref_service_factory.cc
+++ b/chromium/components/prefs/pref_service_factory.cc
@@ -34,12 +34,14 @@ std::unique_ptr<PrefService> PrefServiceFactory::Create(
auto pref_notifier = std::make_unique<PrefNotifierImpl>();
auto pref_value_store = std::make_unique<PrefValueStore>(
managed_prefs_.get(), supervised_user_prefs_.get(),
- extension_prefs_.get(), command_line_prefs_.get(), user_prefs_.get(),
- recommended_prefs_.get(), pref_registry->defaults().get(),
- pref_notifier.get(), std::move(delegate));
+ extension_prefs_.get(), standalone_browser_prefs_.get(),
+ command_line_prefs_.get(), user_prefs_.get(), recommended_prefs_.get(),
+ pref_registry->defaults().get(), pref_notifier.get(),
+ std::move(delegate));
return std::make_unique<PrefService>(
std::move(pref_notifier), std::move(pref_value_store), user_prefs_.get(),
- std::move(pref_registry), read_error_callback_, async_);
+ standalone_browser_prefs_.get(), std::move(pref_registry),
+ read_error_callback_, async_);
}
void PrefServiceFactory::ChangePrefValueStore(
diff --git a/chromium/components/prefs/pref_service_factory.h b/chromium/components/prefs/pref_service_factory.h
index 2683d365f93..ce5b3e6cd48 100644
--- a/chromium/components/prefs/pref_service_factory.h
+++ b/chromium/components/prefs/pref_service_factory.h
@@ -43,6 +43,10 @@ class COMPONENTS_PREFS_EXPORT PrefServiceFactory {
extension_prefs_.swap(prefs);
}
+ void set_standalone_browser_prefs(scoped_refptr<PersistentPrefStore> prefs) {
+ standalone_browser_prefs_.swap(prefs);
+ }
+
void set_command_line_prefs(scoped_refptr<PrefStore> prefs) {
command_line_prefs_.swap(prefs);
}
@@ -87,6 +91,7 @@ class COMPONENTS_PREFS_EXPORT PrefServiceFactory {
scoped_refptr<PrefStore> managed_prefs_;
scoped_refptr<PrefStore> supervised_user_prefs_;
scoped_refptr<PrefStore> extension_prefs_;
+ scoped_refptr<PersistentPrefStore> standalone_browser_prefs_;
scoped_refptr<PrefStore> command_line_prefs_;
scoped_refptr<PersistentPrefStore> user_prefs_;
scoped_refptr<PrefStore> recommended_prefs_;
diff --git a/chromium/components/prefs/pref_service_unittest.cc b/chromium/components/prefs/pref_service_unittest.cc
index b31ed70240a..8ba3c88c395 100644
--- a/chromium/components/prefs/pref_service_unittest.cc
+++ b/chromium/components/prefs/pref_service_unittest.cc
@@ -32,6 +32,7 @@ const char kPrefName[] = "pref.name";
const char kManagedPref[] = "managed_pref";
const char kRecommendedPref[] = "recommended_pref";
const char kSupervisedPref[] = "supervised_pref";
+const char kStandaloneBrowserPref[] = "standalone_browser_pref";
} // namespace
@@ -130,7 +131,7 @@ TEST(PrefServiceTest, Observers) {
obs2.Expect(pref_name, &expected_new_pref_value2);
// This should fire the checks in obs and obs2 but with an unchanged value
// as the recommended value is being overridden by the user-set value.
- prefs.SetRecommendedPref(pref_name, recommended_pref_value.CreateDeepCopy());
+ prefs.SetRecommendedPref(pref_name, recommended_pref_value.Clone());
Mock::VerifyAndClearExpectations(&obs);
Mock::VerifyAndClearExpectations(&obs2);
@@ -499,12 +500,13 @@ class PrefValueStoreChangeTest : public testing::Test {
auto pref_notifier = std::make_unique<PrefNotifierImpl>();
auto pref_value_store = std::make_unique<PrefValueStore>(
nullptr /* managed_prefs */, nullptr /* supervised_user_prefs */,
- nullptr /* extension_prefs */, new TestingPrefStore(),
- user_pref_store_.get(), nullptr /* recommended_prefs */,
- pref_registry_->defaults().get(), pref_notifier.get());
+ nullptr /* extension_prefs */, nullptr /* standalone_browser_prefs */,
+ new TestingPrefStore(), user_pref_store_.get(),
+ nullptr /* recommended_prefs */, pref_registry_->defaults().get(),
+ pref_notifier.get());
pref_service_ = std::make_unique<PrefService>(
std::move(pref_notifier), std::move(pref_value_store), user_pref_store_,
- pref_registry_, base::DoNothing(), false);
+ nullptr, pref_registry_, base::DoNothing(), false);
pref_registry_->RegisterIntegerPref(kManagedPref, 1);
pref_registry_->RegisterIntegerPref(kRecommendedPref, 2);
pref_registry_->RegisterIntegerPref(kSupervisedPref, 3);
@@ -614,3 +616,57 @@ TEST_F(PrefValueStoreChangeTest, PrefChangeRegistrar) {
supervised_pref_store->SetInteger(kSupervisedPref, 31);
Mock::VerifyAndClearExpectations(&obs);
}
+
+class PrefStandaloneBrowserPrefsTest : public testing::Test {
+ protected:
+ PrefStandaloneBrowserPrefsTest()
+ : user_pref_store_(base::MakeRefCounted<TestingPrefStore>()),
+ standalone_browser_pref_store_(
+ base::MakeRefCounted<TestingPrefStore>()),
+ pref_registry_(base::MakeRefCounted<PrefRegistrySimple>()) {}
+
+ ~PrefStandaloneBrowserPrefsTest() override = default;
+
+ void SetUp() override {
+ auto pref_notifier = std::make_unique<PrefNotifierImpl>();
+ auto pref_value_store = std::make_unique<PrefValueStore>(
+ nullptr /* managed_prefs */, nullptr /* supervised_user_prefs */,
+ nullptr /* extension_prefs */, standalone_browser_pref_store_.get(),
+ new TestingPrefStore(), user_pref_store_.get(),
+ nullptr /* recommended_prefs */, pref_registry_->defaults().get(),
+ pref_notifier.get());
+ pref_service_ = std::make_unique<PrefService>(
+ std::move(pref_notifier), std::move(pref_value_store), user_pref_store_,
+ standalone_browser_pref_store_, pref_registry_, base::DoNothing(),
+ false);
+ pref_registry_->RegisterIntegerPref(kStandaloneBrowserPref, 4);
+ }
+
+ std::unique_ptr<PrefService> pref_service_;
+ scoped_refptr<TestingPrefStore> user_pref_store_;
+ scoped_refptr<TestingPrefStore> standalone_browser_pref_store_;
+ scoped_refptr<PrefRegistrySimple> pref_registry_;
+};
+
+// Check that the standalone browser pref store is correctly initialized,
+// written to, read, and has correct precedence.
+TEST_F(PrefStandaloneBrowserPrefsTest, CheckStandaloneBrowserPref) {
+ const PrefService::Preference* preference =
+ pref_service_->FindPreference(kStandaloneBrowserPref);
+ EXPECT_TRUE(preference->IsDefaultValue());
+ EXPECT_EQ(base::Value(4), *(preference->GetValue()));
+ user_pref_store_->SetInteger(kStandaloneBrowserPref, 11);
+ EXPECT_EQ(base::Value(11), *(preference->GetValue()));
+ // The standalone_browser_pref_store has higher precedence.
+ standalone_browser_pref_store_->SetInteger(kStandaloneBrowserPref, 10);
+ ASSERT_EQ(base::Value(10), *(preference->GetValue()));
+ // Removing user_pref_store value shouldn't change the pref value.
+ user_pref_store_->RemoveValue(kStandaloneBrowserPref,
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+ ASSERT_EQ(base::Value(10), *(preference->GetValue()));
+ // Now removing the standalone_browser_pref_store value should revert the
+ // value to default.
+ standalone_browser_pref_store_->RemoveValue(
+ kStandaloneBrowserPref, WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+ EXPECT_EQ(base::Value(4), *(preference->GetValue()));
+}
diff --git a/chromium/components/prefs/pref_value_store.cc b/chromium/components/prefs/pref_value_store.cc
index 4a238d06b16..efa40276caa 100644
--- a/chromium/components/prefs/pref_value_store.cc
+++ b/chromium/components/prefs/pref_value_store.cc
@@ -49,6 +49,7 @@ void PrefValueStore::PrefStoreKeeper::OnInitializationCompleted(
PrefValueStore::PrefValueStore(PrefStore* managed_prefs,
PrefStore* supervised_user_prefs,
PrefStore* extension_prefs,
+ PrefStore* standalone_browser_prefs,
PrefStore* command_line_prefs,
PrefStore* user_prefs,
PrefStore* recommended_prefs,
@@ -61,6 +62,7 @@ PrefValueStore::PrefValueStore(PrefStore* managed_prefs,
InitPrefStore(MANAGED_STORE, managed_prefs);
InitPrefStore(SUPERVISED_USER_STORE, supervised_user_prefs);
InitPrefStore(EXTENSION_STORE, extension_prefs);
+ InitPrefStore(STANDALONE_BROWSER_STORE, standalone_browser_prefs);
InitPrefStore(COMMAND_LINE_STORE, command_line_prefs);
InitPrefStore(USER_STORE, user_prefs);
InitPrefStore(RECOMMENDED_STORE, recommended_prefs);
@@ -69,8 +71,8 @@ PrefValueStore::PrefValueStore(PrefStore* managed_prefs,
CheckInitializationCompleted();
if (delegate_) {
delegate_->Init(managed_prefs, supervised_user_prefs, extension_prefs,
- command_line_prefs, user_prefs, recommended_prefs,
- default_prefs, pref_notifier);
+ standalone_browser_prefs, command_line_prefs, user_prefs,
+ recommended_prefs, default_prefs, pref_notifier);
}
}
@@ -80,6 +82,7 @@ std::unique_ptr<PrefValueStore> PrefValueStore::CloneAndSpecialize(
PrefStore* managed_prefs,
PrefStore* supervised_user_prefs,
PrefStore* extension_prefs,
+ PrefStore* standalone_browser_prefs,
PrefStore* command_line_prefs,
PrefStore* user_prefs,
PrefStore* recommended_prefs,
@@ -93,6 +96,8 @@ std::unique_ptr<PrefValueStore> PrefValueStore::CloneAndSpecialize(
supervised_user_prefs = GetPrefStore(SUPERVISED_USER_STORE);
if (!extension_prefs)
extension_prefs = GetPrefStore(EXTENSION_STORE);
+ if (!standalone_browser_prefs)
+ standalone_browser_prefs = GetPrefStore(STANDALONE_BROWSER_STORE);
if (!command_line_prefs)
command_line_prefs = GetPrefStore(COMMAND_LINE_STORE);
if (!user_prefs)
@@ -103,9 +108,9 @@ std::unique_ptr<PrefValueStore> PrefValueStore::CloneAndSpecialize(
default_prefs = GetPrefStore(DEFAULT_STORE);
return std::make_unique<PrefValueStore>(
- managed_prefs, supervised_user_prefs, extension_prefs, command_line_prefs,
- user_prefs, recommended_prefs, default_prefs, pref_notifier,
- std::move(delegate));
+ managed_prefs, supervised_user_prefs, extension_prefs,
+ standalone_browser_prefs, command_line_prefs, user_prefs,
+ recommended_prefs, default_prefs, pref_notifier, std::move(delegate));
}
bool PrefValueStore::GetValue(const std::string& name,
diff --git a/chromium/components/prefs/pref_value_store.h b/chromium/components/prefs/pref_value_store.h
index 9808056b6af..ea483807600 100644
--- a/chromium/components/prefs/pref_value_store.h
+++ b/chromium/components/prefs/pref_value_store.h
@@ -45,6 +45,7 @@ class COMPONENTS_PREFS_EXPORT PrefValueStore {
virtual void Init(PrefStore* managed_prefs,
PrefStore* supervised_user_prefs,
PrefStore* extension_prefs,
+ PrefStore* standalone_browser_prefs,
PrefStore* command_line_prefs,
PrefStore* user_prefs,
PrefStore* recommended_prefs,
@@ -64,15 +65,19 @@ class COMPONENTS_PREFS_EXPORT PrefValueStore {
};
// PrefStores must be listed here in order from highest to lowest priority.
- // MANAGED contains all managed preference values that are provided by
+ // MANAGED contains all managed preferences that are provided by
// mandatory policies (e.g. Windows Group Policy or cloud policy).
// SUPERVISED_USER contains preferences that are valid for supervised users.
- // EXTENSION contains preference values set by extensions.
- // COMMAND_LINE contains preference values set by command-line switches.
- // USER contains all user-set preference values.
+ // EXTENSION contains preferences set by extensions.
+ // STANDALONE_BROWSER contains system preferences inherited from a separate
+ // Chrome instance. One relevant source is extension prefs in lacros
+ // passed to ash, so these prefs have similar precedence to extension
+ // prefs.
+ // COMMAND_LINE contains preferences set by command-line switches.
+ // USER contains all user-set preferences.
// RECOMMENDED contains all preferences that are provided by recommended
// policies.
- // DEFAULT contains all application default preference values.
+ // DEFAULT contains all application default preferences.
enum PrefStoreType {
// INVALID_STORE is not associated with an actual PrefStore but used as
// an invalid marker, e.g. as a return value.
@@ -80,6 +85,7 @@ class COMPONENTS_PREFS_EXPORT PrefValueStore {
MANAGED_STORE = 0,
SUPERVISED_USER_STORE,
EXTENSION_STORE,
+ STANDALONE_BROWSER_STORE,
COMMAND_LINE_STORE,
USER_STORE,
RECOMMENDED_STORE,
@@ -105,6 +111,7 @@ class COMPONENTS_PREFS_EXPORT PrefValueStore {
PrefValueStore(PrefStore* managed_prefs,
PrefStore* supervised_user_prefs,
PrefStore* extension_prefs,
+ PrefStore* standalone_browser_prefs,
PrefStore* command_line_prefs,
PrefStore* user_prefs,
PrefStore* recommended_prefs,
@@ -125,6 +132,7 @@ class COMPONENTS_PREFS_EXPORT PrefValueStore {
PrefStore* managed_prefs,
PrefStore* supervised_user_prefs,
PrefStore* extension_prefs,
+ PrefStore* standalone_browser_prefs,
PrefStore* command_line_prefs,
PrefStore* user_prefs,
PrefStore* recommended_prefs,
diff --git a/chromium/components/prefs/pref_value_store_unittest.cc b/chromium/components/prefs/pref_value_store_unittest.cc
index 39648139c4f..287196461fb 100644
--- a/chromium/components/prefs/pref_value_store_unittest.cc
+++ b/chromium/components/prefs/pref_value_store_unittest.cc
@@ -41,6 +41,7 @@ const char kManagedPref[] = "this.pref.managed";
const char kSupervisedUserPref[] = "this.pref.supervised_user";
const char kCommandLinePref[] = "this.pref.command_line";
const char kExtensionPref[] = "this.pref.extension";
+const char kStandaloneBrowserPref[] = "this.pref.standalone_browser";
const char kUserPref[] = "this.pref.user";
const char kRecommendedPref[] = "this.pref.recommended";
const char kDefaultPref[] = "this.pref.default";
@@ -63,10 +64,18 @@ const char kSupervisedUserValue[] = "extension:supervised_user";
const char kExtensionValue[] = "extension:extension";
}
+namespace standalone_browser_pref {
+const char kManagedValue[] = "standalone_browser:managed";
+const char kSupervisedUserValue[] = "standalone_browser:supervised_user";
+const char kExtensionValue[] = "standalone_browser:extension";
+const char kStandaloneBrowserValue[] = "standalone_browser:standalone_browser";
+} // namespace standalone_browser_pref
+
namespace command_line_pref {
const char kManagedValue[] = "command_line:managed";
const char kSupervisedUserValue[] = "command_line:supervised_user";
const char kExtensionValue[] = "command_line:extension";
+const char kStandaloneBrowserValue[] = "command_line:standalone_browser";
const char kCommandLineValue[] = "command_line:command_line";
}
@@ -74,6 +83,7 @@ namespace user_pref {
const char kManagedValue[] = "user:managed";
const char kSupervisedUserValue[] = "supervised_user:supervised_user";
const char kExtensionValue[] = "user:extension";
+const char kStandaloneBrowserValue[] = "user:standalone_browser";
const char kCommandLineValue[] = "user:command_line";
const char kUserValue[] = "user:user";
}
@@ -82,6 +92,7 @@ namespace recommended_pref {
const char kManagedValue[] = "recommended:managed";
const char kSupervisedUserValue[] = "recommended:supervised_user";
const char kExtensionValue[] = "recommended:extension";
+const char kStandaloneBrowserValue[] = "recommended:standalone_browser";
const char kCommandLineValue[] = "recommended:command_line";
const char kUserValue[] = "recommended:user";
const char kRecommendedValue[] = "recommended:recommended";
@@ -91,6 +102,7 @@ namespace default_pref {
const char kManagedValue[] = "default:managed";
const char kSupervisedUserValue[] = "default:supervised_user";
const char kExtensionValue[] = "default:extension";
+const char kStandaloneBrowserValue[] = "default:standalone_browser";
const char kCommandLineValue[] = "default:command_line";
const char kUserValue[] = "default:user";
const char kRecommendedValue[] = "default:recommended";
@@ -104,6 +116,7 @@ class PrefValueStoreTest : public testing::Test {
CreateManagedPrefs();
CreateSupervisedUserPrefs();
CreateExtensionPrefs();
+ CreateStandaloneBrowserPrefs();
CreateCommandLinePrefs();
CreateUserPrefs();
CreateRecommendedPrefs();
@@ -113,9 +126,10 @@ class PrefValueStoreTest : public testing::Test {
// Create a fresh PrefValueStore.
pref_value_store_ = std::make_unique<PrefValueStore>(
managed_pref_store_.get(), supervised_user_pref_store_.get(),
- extension_pref_store_.get(), command_line_pref_store_.get(),
- user_pref_store_.get(), recommended_pref_store_.get(),
- default_pref_store_.get(), &pref_notifier_);
+ extension_pref_store_.get(), standalone_browser_pref_store_.get(),
+ command_line_pref_store_.get(), user_pref_store_.get(),
+ recommended_pref_store_.get(), default_pref_store_.get(),
+ &pref_notifier_);
pref_value_store_->set_callback(
base::BindRepeating(&MockPrefModelAssociator::ProcessPrefChange,
@@ -152,6 +166,20 @@ class PrefValueStoreTest : public testing::Test {
extension_pref::kExtensionValue);
}
+ void CreateStandaloneBrowserPrefs() {
+ standalone_browser_pref_store_ = new TestingPrefStore;
+ standalone_browser_pref_store_->SetString(
+ prefs::kManagedPref, standalone_browser_pref::kManagedValue);
+ standalone_browser_pref_store_->SetString(
+ prefs::kSupervisedUserPref,
+ standalone_browser_pref::kSupervisedUserValue);
+ standalone_browser_pref_store_->SetString(
+ prefs::kExtensionPref, standalone_browser_pref::kExtensionValue);
+ standalone_browser_pref_store_->SetString(
+ prefs::kStandaloneBrowserPref,
+ standalone_browser_pref::kStandaloneBrowserValue);
+ }
+
void CreateCommandLinePrefs() {
command_line_pref_store_ = new TestingPrefStore;
command_line_pref_store_->SetString(
@@ -164,6 +192,9 @@ class PrefValueStoreTest : public testing::Test {
prefs::kExtensionPref,
command_line_pref::kExtensionValue);
command_line_pref_store_->SetString(
+ prefs::kStandaloneBrowserPref,
+ command_line_pref::kStandaloneBrowserValue);
+ command_line_pref_store_->SetString(
prefs::kCommandLinePref,
command_line_pref::kCommandLineValue);
}
@@ -182,6 +213,8 @@ class PrefValueStoreTest : public testing::Test {
user_pref_store_->SetString(
prefs::kExtensionPref,
user_pref::kExtensionValue);
+ user_pref_store_->SetString(prefs::kStandaloneBrowserPref,
+ user_pref::kStandaloneBrowserValue);
user_pref_store_->SetString(
prefs::kUserPref,
user_pref::kUserValue);
@@ -202,6 +235,9 @@ class PrefValueStoreTest : public testing::Test {
prefs::kExtensionPref,
recommended_pref::kExtensionValue);
recommended_pref_store_->SetString(
+ prefs::kStandaloneBrowserPref,
+ recommended_pref::kStandaloneBrowserValue);
+ recommended_pref_store_->SetString(
prefs::kUserPref,
recommended_pref::kUserValue);
recommended_pref_store_->SetString(
@@ -223,6 +259,8 @@ class PrefValueStoreTest : public testing::Test {
default_pref_store_->SetString(
prefs::kExtensionPref,
default_pref::kExtensionValue);
+ default_pref_store_->SetString(prefs::kStandaloneBrowserPref,
+ default_pref::kStandaloneBrowserValue);
default_pref_store_->SetString(
prefs::kUserPref,
default_pref::kUserValue);
@@ -251,6 +289,7 @@ class PrefValueStoreTest : public testing::Test {
scoped_refptr<TestingPrefStore> managed_pref_store_;
scoped_refptr<TestingPrefStore> supervised_user_pref_store_;
scoped_refptr<TestingPrefStore> extension_pref_store_;
+ scoped_refptr<TestingPrefStore> standalone_browser_pref_store_;
scoped_refptr<TestingPrefStore> command_line_pref_store_;
scoped_refptr<TestingPrefStore> user_pref_store_;
scoped_refptr<TestingPrefStore> recommended_pref_store_;
@@ -480,6 +519,7 @@ TEST_F(PrefValueStoreTest, OnInitializationCompleted) {
managed_pref_store_->SetInitializationCompleted();
supervised_user_pref_store_->SetInitializationCompleted();
extension_pref_store_->SetInitializationCompleted();
+ standalone_browser_pref_store_->SetInitializationCompleted();
command_line_pref_store_->SetInitializationCompleted();
recommended_pref_store_->SetInitializationCompleted();
default_pref_store_->SetInitializationCompleted();
@@ -499,6 +539,8 @@ TEST_F(PrefValueStoreTest, PrefValueInManagedStore) {
EXPECT_FALSE(pref_value_store_->PrefValueInManagedStore(
prefs::kExtensionPref));
EXPECT_FALSE(pref_value_store_->PrefValueInManagedStore(
+ prefs::kStandaloneBrowserPref));
+ EXPECT_FALSE(pref_value_store_->PrefValueInManagedStore(
prefs::kCommandLinePref));
EXPECT_FALSE(pref_value_store_->PrefValueInManagedStore(
prefs::kUserPref));
@@ -518,6 +560,8 @@ TEST_F(PrefValueStoreTest, PrefValueInExtensionStore) {
EXPECT_TRUE(pref_value_store_->PrefValueInExtensionStore(
prefs::kExtensionPref));
EXPECT_FALSE(pref_value_store_->PrefValueInExtensionStore(
+ prefs::kStandaloneBrowserPref));
+ EXPECT_FALSE(pref_value_store_->PrefValueInExtensionStore(
prefs::kCommandLinePref));
EXPECT_FALSE(pref_value_store_->PrefValueInExtensionStore(
prefs::kUserPref));
@@ -536,6 +580,8 @@ TEST_F(PrefValueStoreTest, PrefValueInUserStore) {
prefs::kSupervisedUserPref));
EXPECT_TRUE(pref_value_store_->PrefValueInUserStore(
prefs::kExtensionPref));
+ EXPECT_TRUE(
+ pref_value_store_->PrefValueInUserStore(prefs::kStandaloneBrowserPref));
EXPECT_TRUE(pref_value_store_->PrefValueInUserStore(
prefs::kCommandLinePref));
EXPECT_TRUE(pref_value_store_->PrefValueInUserStore(
@@ -556,6 +602,8 @@ TEST_F(PrefValueStoreTest, PrefValueFromExtensionStore) {
EXPECT_TRUE(pref_value_store_->PrefValueFromExtensionStore(
prefs::kExtensionPref));
EXPECT_FALSE(pref_value_store_->PrefValueFromExtensionStore(
+ prefs::kStandaloneBrowserPref));
+ EXPECT_FALSE(pref_value_store_->PrefValueFromExtensionStore(
prefs::kCommandLinePref));
EXPECT_FALSE(pref_value_store_->PrefValueFromExtensionStore(
prefs::kUserPref));
@@ -574,6 +622,8 @@ TEST_F(PrefValueStoreTest, PrefValueFromUserStore) {
prefs::kSupervisedUserPref));
EXPECT_FALSE(pref_value_store_->PrefValueFromUserStore(
prefs::kExtensionPref));
+ EXPECT_FALSE(
+ pref_value_store_->PrefValueFromUserStore(prefs::kStandaloneBrowserPref));
EXPECT_FALSE(pref_value_store_->PrefValueFromUserStore(
prefs::kCommandLinePref));
EXPECT_TRUE(pref_value_store_->PrefValueFromUserStore(
@@ -594,6 +644,8 @@ TEST_F(PrefValueStoreTest, PrefValueFromRecommendedStore) {
EXPECT_FALSE(pref_value_store_->PrefValueFromRecommendedStore(
prefs::kExtensionPref));
EXPECT_FALSE(pref_value_store_->PrefValueFromRecommendedStore(
+ prefs::kStandaloneBrowserPref));
+ EXPECT_FALSE(pref_value_store_->PrefValueFromRecommendedStore(
prefs::kCommandLinePref));
EXPECT_FALSE(pref_value_store_->PrefValueFromRecommendedStore(
prefs::kUserPref));
@@ -613,6 +665,8 @@ TEST_F(PrefValueStoreTest, PrefValueFromDefaultStore) {
EXPECT_FALSE(pref_value_store_->PrefValueFromDefaultStore(
prefs::kExtensionPref));
EXPECT_FALSE(pref_value_store_->PrefValueFromDefaultStore(
+ prefs::kStandaloneBrowserPref));
+ EXPECT_FALSE(pref_value_store_->PrefValueFromDefaultStore(
prefs::kCommandLinePref));
EXPECT_FALSE(pref_value_store_->PrefValueFromDefaultStore(
prefs::kUserPref));
@@ -632,6 +686,8 @@ TEST_F(PrefValueStoreTest, PrefValueUserModifiable) {
EXPECT_FALSE(pref_value_store_->PrefValueUserModifiable(
prefs::kExtensionPref));
EXPECT_FALSE(pref_value_store_->PrefValueUserModifiable(
+ prefs::kStandaloneBrowserPref));
+ EXPECT_FALSE(pref_value_store_->PrefValueUserModifiable(
prefs::kCommandLinePref));
EXPECT_TRUE(pref_value_store_->PrefValueUserModifiable(
prefs::kUserPref));
@@ -651,6 +707,8 @@ TEST_F(PrefValueStoreTest, PrefValueExtensionModifiable) {
EXPECT_TRUE(pref_value_store_->PrefValueExtensionModifiable(
prefs::kExtensionPref));
EXPECT_TRUE(pref_value_store_->PrefValueExtensionModifiable(
+ prefs::kStandaloneBrowserPref));
+ EXPECT_TRUE(pref_value_store_->PrefValueExtensionModifiable(
prefs::kCommandLinePref));
EXPECT_TRUE(pref_value_store_->PrefValueExtensionModifiable(
prefs::kUserPref));
diff --git a/chromium/components/prefs/scoped_user_pref_update.h b/chromium/components/prefs/scoped_user_pref_update.h
index e2d894ff8d0..7f34c9465fe 100644
--- a/chromium/components/prefs/scoped_user_pref_update.h
+++ b/chromium/components/prefs/scoped_user_pref_update.h
@@ -18,11 +18,6 @@
class PrefService;
-namespace base {
-class DictionaryValue;
-class ListValue;
-}
-
namespace subtle {
// Base class for ScopedUserPrefUpdateTemplate that contains the parts
@@ -62,12 +57,12 @@ class COMPONENTS_PREFS_EXPORT ScopedUserPrefUpdateBase {
} // namespace subtle
-// Class to support modifications to DictionaryValues and ListValues while
+// Class to support modifications to dictionary and list base::Values while
// guaranteeing that PrefObservers are notified of changed values.
//
// This class may only be used on the UI thread as it requires access to the
// PrefService.
-template <typename T, base::Value::Type type_enum_value>
+template <base::Value::Type type_enum_value>
class ScopedUserPrefUpdate : public subtle::ScopedUserPrefUpdateBase {
public:
ScopedUserPrefUpdate(PrefService* service, const std::string& path)
@@ -79,7 +74,7 @@ class ScopedUserPrefUpdate : public subtle::ScopedUserPrefUpdateBase {
// Triggers an update notification if Get() was called.
virtual ~ScopedUserPrefUpdate() {}
- // Returns a mutable |T| instance that
+ // Returns a mutable |base::Value| instance that
// - is already in the user pref store, or
// - is (silently) created and written to the user pref store if none existed
// before.
@@ -90,23 +85,15 @@ class ScopedUserPrefUpdate : public subtle::ScopedUserPrefUpdateBase {
// The ownership of the return value remains with the user pref store.
// Virtual so it can be overriden in subclasses that transform the value
// before returning it (for example to return a subelement of a dictionary).
- virtual T* Get() {
- return static_cast<T*>(GetValueOfType(type_enum_value));
- }
+ virtual base::Value* Get() { return GetValueOfType(type_enum_value); }
- T& operator*() {
- return *Get();
- }
+ base::Value& operator*() { return *Get(); }
- T* operator->() {
- return Get();
- }
+ base::Value* operator->() { return Get(); }
};
-typedef ScopedUserPrefUpdate<base::DictionaryValue,
- base::Value::Type::DICTIONARY>
+typedef ScopedUserPrefUpdate<base::Value::Type::DICTIONARY>
DictionaryPrefUpdate;
-typedef ScopedUserPrefUpdate<base::ListValue, base::Value::Type::LIST>
- ListPrefUpdate;
+typedef ScopedUserPrefUpdate<base::Value::Type::LIST> ListPrefUpdate;
#endif // COMPONENTS_PREFS_SCOPED_USER_PREF_UPDATE_H_
diff --git a/chromium/components/prefs/scoped_user_pref_update_unittest.cc b/chromium/components/prefs/scoped_user_pref_update_unittest.cc
index 3c1bee21c20..18eaa5114e6 100644
--- a/chromium/components/prefs/scoped_user_pref_update_unittest.cc
+++ b/chromium/components/prefs/scoped_user_pref_update_unittest.cc
@@ -40,42 +40,40 @@ const char ScopedUserPrefUpdateTest::kValue[] = "value";
TEST_F(ScopedUserPrefUpdateTest, RegularUse) {
// Dictionary that will be expected to be set at the end.
- base::DictionaryValue expected_dictionary;
- expected_dictionary.SetString(kKey, kValue);
+ base::Value expected_dictionary(base::Value::Type::DICTIONARY);
+ expected_dictionary.SetStringKey(kKey, kValue);
{
EXPECT_CALL(observer_, OnPreferenceChanged(_)).Times(0);
DictionaryPrefUpdate update(&prefs_, kPref);
- base::DictionaryValue* value = update.Get();
+ base::Value* value = update.Get();
ASSERT_TRUE(value);
- value->SetString(kKey, kValue);
+ value->SetStringKey(kKey, kValue);
// The dictionary was created for us but the creation should have happened
// silently without notifications.
Mock::VerifyAndClearExpectations(&observer_);
// Modifications happen online and are instantly visible, though.
- const base::DictionaryValue* current_value = prefs_.GetDictionary(kPref);
+ const base::Value* current_value = prefs_.GetDictionary(kPref);
ASSERT_TRUE(current_value);
- EXPECT_TRUE(expected_dictionary.Equals(current_value));
+ EXPECT_EQ(expected_dictionary, *current_value);
// Now we are leaving the scope of the update so we should be notified.
observer_.Expect(kPref, &expected_dictionary);
}
Mock::VerifyAndClearExpectations(&observer_);
- const base::DictionaryValue* current_value = prefs_.GetDictionary(kPref);
+ const base::Value* current_value = prefs_.GetDictionary(kPref);
ASSERT_TRUE(current_value);
- EXPECT_TRUE(expected_dictionary.Equals(current_value));
+ EXPECT_EQ(expected_dictionary, *current_value);
}
TEST_F(ScopedUserPrefUpdateTest, NeverTouchAnything) {
- const base::DictionaryValue* old_value = prefs_.GetDictionary(kPref);
+ const base::Value* old_value = prefs_.GetDictionary(kPref);
EXPECT_CALL(observer_, OnPreferenceChanged(_)).Times(0);
- {
- DictionaryPrefUpdate update(&prefs_, kPref);
- }
- const base::DictionaryValue* new_value = prefs_.GetDictionary(kPref);
+ { DictionaryPrefUpdate update(&prefs_, kPref); }
+ const base::Value* new_value = prefs_.GetDictionary(kPref);
EXPECT_EQ(old_value, new_value);
Mock::VerifyAndClearExpectations(&observer_);
}
@@ -88,23 +86,23 @@ TEST_F(ScopedUserPrefUpdateTest, UpdatingListPrefWithDefaults) {
std::string pref_name = "mypref";
prefs_.registry()->RegisterListPref(pref_name,
base::Value(std::move(defaults)));
- EXPECT_EQ(2u, prefs_.GetList(pref_name)->GetList().size());
+ EXPECT_EQ(2u, prefs_.GetList(pref_name)->GetListDeprecated().size());
ListPrefUpdate update(&prefs_, pref_name);
update->Append("thirdvalue");
- EXPECT_EQ(3u, prefs_.GetList(pref_name)->GetList().size());
+ EXPECT_EQ(3u, prefs_.GetList(pref_name)->GetListDeprecated().size());
}
TEST_F(ScopedUserPrefUpdateTest, UpdatingDictionaryPrefWithDefaults) {
base::Value defaults(base::Value::Type::DICTIONARY);
- defaults.SetKey("firstkey", base::Value("value"));
- defaults.SetKey("secondkey", base::Value("value"));
+ defaults.SetStringKey("firstkey", "value");
+ defaults.SetStringKey("secondkey", "value");
std::string pref_name = "mypref";
prefs_.registry()->RegisterDictionaryPref(pref_name, std::move(defaults));
EXPECT_EQ(2u, prefs_.GetDictionary(pref_name)->DictSize());
DictionaryPrefUpdate update(&prefs_, pref_name);
- update->SetKey("thirdkey", base::Value("value"));
+ update->SetStringKey("thirdkey", "value");
EXPECT_EQ(3u, prefs_.GetDictionary(pref_name)->DictSize());
}
diff --git a/chromium/components/prefs/segregated_pref_store.cc b/chromium/components/prefs/segregated_pref_store.cc
index 1f3ccc52fcb..d27ada8a5b6 100644
--- a/chromium/components/prefs/segregated_pref_store.cc
+++ b/chromium/components/prefs/segregated_pref_store.cc
@@ -92,8 +92,7 @@ std::unique_ptr<base::DictionaryValue> SegregatedPrefStore::GetValues() const {
auto values = default_pref_store_->GetValues();
auto selected_pref_store_values = selected_pref_store_->GetValues();
for (const auto& key : selected_preference_names_) {
- const base::Value* value = nullptr;
- if (selected_pref_store_values->Get(key, &value)) {
+ if (const base::Value* value = selected_pref_store_values->FindPath(key)) {
values->SetPath(key, value->Clone());
} else {
values->RemoveKey(key);
diff --git a/chromium/components/prefs/segregated_pref_store_unittest.cc b/chromium/components/prefs/segregated_pref_store_unittest.cc
index fb43dd294b1..4014acd8eff 100644
--- a/chromium/components/prefs/segregated_pref_store_unittest.cc
+++ b/chromium/components/prefs/segregated_pref_store_unittest.cc
@@ -381,15 +381,15 @@ TEST_F(SegregatedPrefStoreTest, GetValues) {
const base::Value* value = nullptr;
// Check that a selected preference is returned.
ASSERT_TRUE(values->Get(kSelectedPref, &value));
- EXPECT_TRUE(base::Value(kValue1).Equals(value));
+ EXPECT_EQ(base::Value(kValue1), *value);
// Check that a a default preference is returned.
ASSERT_TRUE(values->Get(kUnselectedPref, &value));
- EXPECT_TRUE(base::Value(kValue2).Equals(value));
+ EXPECT_EQ(base::Value(kValue2), *value);
// Check that the selected preference is preferred.
ASSERT_TRUE(values->Get(kSharedPref, &value));
- EXPECT_TRUE(base::Value(kValue1).Equals(value));
+ EXPECT_EQ(base::Value(kValue1), *value);
}
INSTANTIATE_TEST_SUITE_P(
diff --git a/chromium/components/prefs/testing_pref_service.cc b/chromium/components/prefs/testing_pref_service.cc
index fb0679075b0..07d3400daa3 100644
--- a/chromium/components/prefs/testing_pref_service.cc
+++ b/chromium/components/prefs/testing_pref_service.cc
@@ -19,6 +19,7 @@ TestingPrefServiceBase<PrefService, PrefRegistry>::TestingPrefServiceBase(
TestingPrefStore* managed_prefs,
TestingPrefStore* supervised_user_prefs,
TestingPrefStore* extension_prefs,
+ TestingPrefStore* standalone_browser_prefs,
TestingPrefStore* user_prefs,
TestingPrefStore* recommended_prefs,
PrefRegistry* pref_registry,
@@ -28,12 +29,14 @@ TestingPrefServiceBase<PrefService, PrefRegistry>::TestingPrefServiceBase(
std::make_unique<PrefValueStore>(managed_prefs,
supervised_user_prefs,
extension_prefs,
+ standalone_browser_prefs,
/*command_line_prefs=*/nullptr,
user_prefs,
recommended_prefs,
pref_registry->defaults().get(),
pref_notifier),
user_prefs,
+ standalone_browser_prefs,
pref_registry,
base::BindRepeating(
&TestingPrefServiceBase<PrefService,
@@ -42,6 +45,7 @@ TestingPrefServiceBase<PrefService, PrefRegistry>::TestingPrefServiceBase(
managed_prefs_(managed_prefs),
supervised_user_prefs_(supervised_user_prefs),
extension_prefs_(extension_prefs),
+ standalone_browser_prefs_(standalone_browser_prefs),
user_prefs_(user_prefs),
recommended_prefs_(recommended_prefs) {}
@@ -50,6 +54,7 @@ TestingPrefServiceSimple::TestingPrefServiceSimple()
/*managed_prefs=*/new TestingPrefStore(),
/*supervised_user_prefs=*/new TestingPrefStore(),
/*extension_prefs=*/new TestingPrefStore(),
+ /*standalone_browser_prefs=*/new TestingPrefStore(),
/*user_prefs=*/new TestingPrefStore(),
/*recommended_prefs=*/new TestingPrefStore(),
new PrefRegistrySimple(),
diff --git a/chromium/components/prefs/testing_pref_service.h b/chromium/components/prefs/testing_pref_service.h
index 7ec1954d687..429a11c5969 100644
--- a/chromium/components/prefs/testing_pref_service.h
+++ b/chromium/components/prefs/testing_pref_service.h
@@ -38,6 +38,7 @@ class TestingPrefServiceBase : public SuperPrefService {
// preference changed.
void SetManagedPref(const std::string& path,
std::unique_ptr<base::Value> value);
+ void SetManagedPref(const std::string& path, base::Value value);
// Clears the preference on the managed layer and fire observers if the
// preference has been defined previously.
@@ -61,12 +62,14 @@ class TestingPrefServiceBase : public SuperPrefService {
// Similar to the above, but for user preferences.
const base::Value* GetUserPref(const std::string& path) const;
void SetUserPref(const std::string& path, std::unique_ptr<base::Value> value);
+ void SetUserPref(const std::string& path, base::Value value);
void RemoveUserPref(const std::string& path);
// Similar to the above, but for recommended policy preferences.
const base::Value* GetRecommendedPref(const std::string& path) const;
void SetRecommendedPref(const std::string& path,
std::unique_ptr<base::Value> value);
+ void SetRecommendedPref(const std::string& path, base::Value value);
void RemoveRecommendedPref(const std::string& path);
// Do-nothing implementation for TestingPrefService.
@@ -75,10 +78,13 @@ class TestingPrefServiceBase : public SuperPrefService {
// Set initialization status of pref stores.
void SetInitializationCompleted();
+ scoped_refptr<TestingPrefStore> user_prefs_store() { return user_prefs_; }
+
protected:
TestingPrefServiceBase(TestingPrefStore* managed_prefs,
TestingPrefStore* supervised_user_prefs,
TestingPrefStore* extension_prefs,
+ TestingPrefStore* standalone_browser_prefs,
TestingPrefStore* user_prefs,
TestingPrefStore* recommended_prefs,
ConstructionPrefRegistry* pref_registry,
@@ -102,6 +108,7 @@ class TestingPrefServiceBase : public SuperPrefService {
scoped_refptr<TestingPrefStore> managed_prefs_;
scoped_refptr<TestingPrefStore> supervised_user_prefs_;
scoped_refptr<TestingPrefStore> extension_prefs_;
+ scoped_refptr<TestingPrefStore> standalone_browser_prefs_;
scoped_refptr<TestingPrefStore> user_prefs_;
scoped_refptr<TestingPrefStore> recommended_prefs_;
};
@@ -130,6 +137,7 @@ TestingPrefServiceBase<PrefService, PrefRegistry>::TestingPrefServiceBase(
TestingPrefStore* managed_prefs,
TestingPrefStore* supervised_user_prefs,
TestingPrefStore* extension_prefs,
+ TestingPrefStore* standalone_browser_prefs,
TestingPrefStore* user_prefs,
TestingPrefStore* recommended_prefs,
PrefRegistry* pref_registry,
@@ -156,6 +164,12 @@ void TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>::
template <class SuperPrefService, class ConstructionPrefRegistry>
void TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>::
+ SetManagedPref(const std::string& path, base::Value value) {
+ SetManagedPref(path, base::Value::ToUniquePtrValue(std::move(value)));
+}
+
+template <class SuperPrefService, class ConstructionPrefRegistry>
+void TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>::
RemoveManagedPref(const std::string& path) {
RemovePref(managed_prefs_.get(), path);
}
@@ -215,6 +229,12 @@ void TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>::
template <class SuperPrefService, class ConstructionPrefRegistry>
void TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>::
+ SetUserPref(const std::string& path, base::Value value) {
+ SetUserPref(path, base::Value::ToUniquePtrValue(std::move(value)));
+}
+
+template <class SuperPrefService, class ConstructionPrefRegistry>
+void TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>::
RemoveUserPref(const std::string& path) {
RemovePref(user_prefs_.get(), path);
}
@@ -235,6 +255,13 @@ void TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>::
template <class SuperPrefService, class ConstructionPrefRegistry>
void TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>::
+ SetRecommendedPref(const std::string& path, base::Value value) {
+ SetPref(recommended_prefs_.get(), path,
+ base::Value::ToUniquePtrValue(std::move(value)));
+}
+
+template <class SuperPrefService, class ConstructionPrefRegistry>
+void TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>::
RemoveRecommendedPref(const std::string& path) {
RemovePref(recommended_prefs_.get(), path);
}
@@ -270,8 +297,8 @@ void TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>::
supervised_user_prefs_->SetInitializationCompleted();
extension_prefs_->SetInitializationCompleted();
recommended_prefs_->SetInitializationCompleted();
- // |user_prefs_| is initialized in PrefService constructor so no need to
- // set initialization status again.
+ // |user_prefs_| and |standalone_browser_prefs_| are initialized in
+ // PrefService constructor so no need to set initialization status again.
}
#endif // COMPONENTS_PREFS_TESTING_PREF_SERVICE_H_
diff --git a/chromium/components/previous_session_info/previous_session_info.h b/chromium/components/previous_session_info/previous_session_info.h
index 3ffac885e2f..0af1c3a105d 100644
--- a/chromium/components/previous_session_info/previous_session_info.h
+++ b/chromium/components/previous_session_info/previous_session_info.h
@@ -107,14 +107,6 @@ enum class DeviceBatteryState {
// session.
@property(nonatomic, assign, readonly) BOOL OSRestartedAfterPreviousSession;
-// Whether the previous session was on Multi Window enabled version of the
-// application. A previous session doesn't have to be from a previous run, in
-// the case of single window to multiple windows migration, after the first
-// session created/restored the flag value should be updated to |YES|.
-// TODO(crbug.com/1109280): Remove after the migration to Multi-Window sessions
-// is done.
-@property(nonatomic, assign, readonly) BOOL isMultiWindowEnabledSession;
-
// The OS version during the previous session or nil if no previous session data
// is available.
@property(nonatomic, strong, readonly) NSString* OSVersion;
@@ -201,11 +193,6 @@ enum class DeviceBatteryState {
// Empties the list of connected session.
- (void)resetConnectedSceneSessionIDs;
-// Updates the local and the saved Multi Window support status.
-// TODO(crbug.com/1109280): Remove after the migration to Multi-Window
-// sessions is done.
-- (void)updateMultiWindowSupportStatus;
-
// Must be called when Chrome starts session restoration. The returned closure
// runner will clear up the flag when destroyed. Can be used on different
// threads.
diff --git a/chromium/components/previous_session_info/previous_session_info.mm b/chromium/components/previous_session_info/previous_session_info.mm
index f8724a6186c..003af073389 100644
--- a/chromium/components/previous_session_info/previous_session_info.mm
+++ b/chromium/components/previous_session_info/previous_session_info.mm
@@ -94,6 +94,7 @@ NSString* const kPreviousSessionInfoThermalState =
// - A (boolean) describing whether or not low power mode is enabled.
NSString* const kPreviousSessionInfoLowPowerMode =
@"PreviousSessionInfoLowPowerMode";
+// TODO(crbug.com/1295763): Remove key for no longer used state.
// - A (boolean) describing whether the last session was on Multi-Window enabled
// version of the application.
NSString* const kPreviousSessionInfoMultiWindowEnabled =
@@ -142,7 +143,6 @@ NSString* const kPreviousSessionInfoOTRTabCount =
@property(nonatomic, assign) BOOL didSeeMemoryWarningShortlyBeforeTerminating;
@property(nonatomic, assign) BOOL isFirstSessionAfterUpgrade;
@property(nonatomic, assign) BOOL isFirstSessionAfterLanguageChange;
-@property(nonatomic, assign) BOOL isMultiWindowEnabledSession;
@property(nonatomic, assign) BOOL OSRestartedAfterPreviousSession;
@property(nonatomic, strong) NSString* OSVersion;
@property(nonatomic, strong) NSDate* sessionStartTime;
@@ -210,10 +210,11 @@ static PreviousSessionInfo* gSharedInstance = nil;
gSharedInstance.isFirstSessionAfterUpgrade =
![lastRanVersion isEqualToString:currentVersion];
- // TODO(crbug.com/1109280): Remove after the migration to Multi-Window
- // sessions is done.
- gSharedInstance.isMultiWindowEnabledSession =
- [defaults boolForKey:kPreviousSessionInfoMultiWindowEnabled];
+ // This key is no longer being used so we remove it here,
+ // but this should be cleaned-up in many milestones.
+ // TODO(crbug.com/1295763): Remove this line.
+ [[NSUserDefaults standardUserDefaults]
+ removeObjectForKey:kPreviousSessionInfoMultiWindowEnabled];
gSharedInstance.connectedSceneSessionsIDs = [NSMutableSet
setWithArray:[defaults
@@ -543,15 +544,6 @@ static PreviousSessionInfo* gSharedInstance = nil;
[self synchronizeSceneSessionIDs];
}
-- (void)updateMultiWindowSupportStatus {
- gSharedInstance.isMultiWindowEnabledSession =
- base::ios::IsMultiwindowSupported();
- NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
- [defaults setBool:gSharedInstance.isMultiWindowEnabledSession
- forKey:kPreviousSessionInfoMultiWindowEnabled];
- [defaults synchronize];
-}
-
- (base::ScopedClosureRunner)startSessionRestoration {
if (self.numberOfSessionsBeingRestored == 0) {
[NSUserDefaults.standardUserDefaults
diff --git a/chromium/components/printing/browser/print_manager.cc b/chromium/components/printing/browser/print_manager.cc
index 0bc4c1217ed..37e4db4235e 100644
--- a/chromium/components/printing/browser/print_manager.cc
+++ b/chromium/components/printing/browser/print_manager.cc
@@ -50,7 +50,7 @@ void PrintManager::PrintingFailed(int32_t cookie) {
if (!IsValidCookie(cookie))
return;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
PdfWritingDone(0);
#endif
}
@@ -93,7 +93,7 @@ content::RenderFrameHost* PrintManager::GetCurrentTargetFrame() {
}
void PrintManager::PrintingRenderFrameDeleted() {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
PdfWritingDone(0);
#endif
}
diff --git a/chromium/components/printing/browser/print_manager.h b/chromium/components/printing/browser/print_manager.h
index 732ffc4c1d0..f9db604a724 100644
--- a/chromium/components/printing/browser/print_manager.h
+++ b/chromium/components/printing/browser/print_manager.h
@@ -15,7 +15,7 @@
#include "mojo/public/cpp/bindings/associated_remote.h"
#include "printing/buildflags/buildflags.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include <utility>
#include "base/callback.h"
@@ -34,7 +34,7 @@ class PrintManager : public content::WebContentsObserver,
mojo::PendingAssociatedReceiver<mojom::PrintManagerHost> receiver,
content::RenderFrameHost* rfh);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// TODO(timvolodine): consider introducing PrintManagerAndroid (crbug/500960)
using PdfWritingDoneCallback =
base::RepeatingCallback<void(int /* page count */)>;
@@ -77,7 +77,7 @@ class PrintManager : public content::WebContentsObserver,
int cookie() const { return cookie_; }
void set_cookie(int cookie) { cookie_ = cookie; }
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
PdfWritingDoneCallback pdf_writing_done_callback() const {
return pdf_writing_done_callback_;
}
@@ -94,7 +94,7 @@ class PrintManager : public content::WebContentsObserver,
content::RenderFrameHostReceiverSet<printing::mojom::PrintManagerHost>
print_manager_host_receivers_;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Callback to execute when done writing pdf.
PdfWritingDoneCallback pdf_writing_done_callback_;
#endif
diff --git a/chromium/components/printing/browser/print_to_pdf/pdf_print_manager.cc b/chromium/components/printing/browser/print_to_pdf/pdf_print_manager.cc
index 44421c66146..66810a2a5f0 100644
--- a/chromium/components/printing/browser/print_to_pdf/pdf_print_manager.cc
+++ b/chromium/components/printing/browser/print_to_pdf/pdf_print_manager.cc
@@ -6,6 +6,7 @@
#include <utility>
+#include "build/build_config.h"
#include "components/printing/browser/print_to_pdf/pdf_print_utils.h"
#include "printing/mojom/print.mojom.h"
#include "printing/page_range.h"
@@ -229,7 +230,7 @@ void PdfPrintManager::SetAccessibilityTree(
}
#endif
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
void PdfPrintManager::PdfWritingDone(int page_count) {}
#endif
diff --git a/chromium/components/printing/browser/print_to_pdf/pdf_print_manager.h b/chromium/components/printing/browser/print_to_pdf/pdf_print_manager.h
index 193a1cc443b..3326eea1fd8 100644
--- a/chromium/components/printing/browser/print_to_pdf/pdf_print_manager.h
+++ b/chromium/components/printing/browser/print_to_pdf/pdf_print_manager.h
@@ -93,7 +93,7 @@ class PdfPrintManager : public printing::PrintManager,
int32_t cookie,
const ui::AXTreeUpdate& accessibility_tree) override;
#endif
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
void PdfWritingDone(int page_count) override;
#endif
diff --git a/chromium/components/printing/common/cloud_print_cdd_conversion.cc b/chromium/components/printing/common/cloud_print_cdd_conversion.cc
index 0b7a9bd95fb..1605b472e48 100644
--- a/chromium/components/printing/common/cloud_print_cdd_conversion.cc
+++ b/chromium/components/printing/common/cloud_print_cdd_conversion.cc
@@ -13,6 +13,7 @@
#include "base/memory/ptr_util.h"
#include "base/notreached.h"
#include "base/strings/string_number_conversions.h"
+#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "components/cloud_devices/common/printer_description.h"
#include "printing/backend/print_backend.h"
@@ -38,7 +39,7 @@ printer::DuplexType ToCloudDuplexType(printing::mojom::DuplexMode mode) {
return printer::DuplexType::NO_DUPLEX;
}
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS)
printer::TypedValueVendorCapability::ValueType ToCloudValueType(
printing::AdvancedCapability::Type type) {
switch (type) {
@@ -55,7 +56,7 @@ printer::TypedValueVendorCapability::ValueType ToCloudValueType(
}
return printer::TypedValueVendorCapability::ValueType::STRING;
}
-#endif // defined(OS_CHROMEOS)
+#endif // BUILDFLAG(IS_CHROMEOS)
printer::Media ConvertPaperToMedia(
const printing::PrinterSemanticCapsAndDefaults::Paper& paper) {
@@ -134,7 +135,7 @@ printer::DpiCapability GetDpiCapabilities(
return dpi_capabilities;
}
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS)
printer::VendorCapabilities GetVendorCapabilities(
const printing::PrinterSemanticCapsAndDefaults& semantic_info) {
printer::VendorCapabilities vendor_capabilities;
@@ -164,7 +165,7 @@ printer::VendorCapabilities GetVendorCapabilities(
return vendor_capabilities;
}
-#endif // defined(OS_CHROMEOS)
+#endif // BUILDFLAG(IS_CHROMEOS)
} // namespace
@@ -231,7 +232,7 @@ base::Value PrinterSemanticCapsAndDefaultsToCdd(
orientation.AddOption(printer::OrientationType::AUTO_ORIENTATION);
orientation.SaveTo(&description);
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS)
printer::PinCapability pin;
pin.set_value(semantic_info.pin_supported);
pin.SaveTo(&description);
@@ -241,7 +242,7 @@ base::Value PrinterSemanticCapsAndDefaultsToCdd(
GetVendorCapabilities(semantic_info);
vendor_capabilities.SaveTo(&description);
}
-#endif // defined(OS_CHROMEOS)
+#endif // BUILDFLAG(IS_CHROMEOS)
return std::move(description).ToValue();
}
diff --git a/chromium/components/printing/renderer/print_render_frame_helper.cc b/chromium/components/printing/renderer/print_render_frame_helper.cc
index 650b5550f98..0d5c467e59c 100644
--- a/chromium/components/printing/renderer/print_render_frame_helper.cc
+++ b/chromium/components/printing/renderer/print_render_frame_helper.cc
@@ -10,12 +10,12 @@
#include <algorithm>
#include <memory>
#include <string>
+#include <tuple>
#include <utility>
#include "base/auto_reset.h"
#include "base/bind.h"
#include "base/i18n/rtl.h"
-#include "base/ignore_result.h"
#include "base/json/json_writer.h"
#include "base/location.h"
#include "base/logging.h"
@@ -23,6 +23,7 @@
#include "base/metrics/histogram_functions.h"
#include "base/numerics/safe_conversions.h"
#include "base/process/process_handle.h"
+#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/task/single_thread_task_runner.h"
@@ -52,7 +53,6 @@
#include "third_party/blink/public/platform/scheduler/web_agent_group_scheduler.h"
#include "third_party/blink/public/platform/scheduler/web_thread_scheduler.h"
#include "third_party/blink/public/platform/web_data.h"
-#include "third_party/blink/public/platform/web_double_size.h"
#include "third_party/blink/public/platform/web_url.h"
#include "third_party/blink/public/platform/web_url_request.h"
#include "third_party/blink/public/web/web_console_message.h"
@@ -129,7 +129,7 @@ void ExecuteScript(blink::WebLocalFrame* frame,
}
int GetDPI(const mojom::PrintParams& print_params) {
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
// On Mac, the printable area is in points, don't do any scaling based on DPI.
return kPointsPerInch;
#else
@@ -137,7 +137,7 @@ int GetDPI(const mojom::PrintParams& print_params) {
// prevent bad quality print jobs on rectantular DPI printers.
return static_cast<int>(
std::max(print_params.dpi.width(), print_params.dpi.height()));
-#endif // defined(OS_APPLE)
+#endif // BUILDFLAG(IS_APPLE)
}
bool PrintMsg_Print_Params_IsValid(const mojom::PrintParams& params) {
@@ -172,9 +172,9 @@ mojom::PrintParamsPtr GetCssPrintParams(blink::WebLocalFrame* frame,
int dpi = GetDPI(page_params);
blink::WebPrintPageDescription description;
- description.size = blink::WebDoubleSize(
- ConvertUnitDouble(page_params.page_size.width(), dpi, kPixelsPerInch),
- ConvertUnitDouble(page_params.page_size.height(), dpi, kPixelsPerInch));
+ description.size.SetSize(
+ ConvertUnitFloat(page_params.page_size.width(), dpi, kPixelsPerInch),
+ ConvertUnitFloat(page_params.page_size.height(), dpi, kPixelsPerInch));
description.margin_top =
ConvertUnit(page_params.margin_top, dpi, kPixelsPerInch);
description.margin_right = ConvertUnit(page_params.page_size.width() -
@@ -191,11 +191,10 @@ mojom::PrintParamsPtr GetCssPrintParams(blink::WebLocalFrame* frame,
if (frame)
frame->GetPageDescription(page_index, &description);
- double new_content_width = description.size.Width() -
- description.margin_left - description.margin_right;
- double new_content_height = description.size.Height() -
- description.margin_top -
- description.margin_bottom;
+ float new_content_width = description.size.width() - description.margin_left -
+ description.margin_right;
+ float new_content_height = description.size.height() -
+ description.margin_top - description.margin_bottom;
// Invalid page size and/or margins. We just use the default setting.
if (new_content_width < 1 || new_content_height < 1) {
@@ -208,8 +207,8 @@ mojom::PrintParamsPtr GetCssPrintParams(blink::WebLocalFrame* frame,
FromBlinkPageOrientation(description.orientation);
page_css_params->page_size =
- gfx::Size(ConvertUnit(description.size.Width(), kPixelsPerInch, dpi),
- ConvertUnit(description.size.Height(), kPixelsPerInch, dpi));
+ gfx::Size(ConvertUnit(description.size.width(), kPixelsPerInch, dpi),
+ ConvertUnit(description.size.height(), kPixelsPerInch, dpi));
page_css_params->content_size =
gfx::Size(ConvertUnit(new_content_width, kPixelsPerInch, dpi),
ConvertUnit(new_content_height, kPixelsPerInch, dpi));
@@ -327,7 +326,7 @@ void ComputeWebKitPrintParamsInDesiredDpi(
webkit_print_params->scale_factor =
static_cast<int>(print_params.scale_factor * 100);
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
// For Mac, GetDPI() returns a value that avoids DPI-based scaling. This is
// correct except when rastering PDFs, which uses |printer_dpi|, and the
// value for |printer_dpi| is too low. Adjust that here.
@@ -743,14 +742,14 @@ void PrintRenderFrameHelper::PrintHeaderAndFooter(
frame_widget.BindNewEndpointAndPassDedicatedReceiver();
mojo::AssociatedRemote<blink::mojom::FrameWidgetHost> frame_widget_host;
- ignore_result(frame_widget_host.BindNewEndpointAndPassDedicatedReceiver());
+ std::ignore = frame_widget_host.BindNewEndpointAndPassDedicatedReceiver();
mojo::AssociatedRemote<blink::mojom::Widget> widget_remote;
mojo::PendingAssociatedReceiver<blink::mojom::Widget> widget_receiver =
widget_remote.BindNewEndpointAndPassDedicatedReceiver();
mojo::AssociatedRemote<blink::mojom::WidgetHost> widget_host_remote;
- ignore_result(widget_host_remote.BindNewEndpointAndPassDedicatedReceiver());
+ std::ignore = widget_host_remote.BindNewEndpointAndPassDedicatedReceiver();
blink::WebNonCompositedWidgetClient client;
blink::WebFrameWidget* web_frame_widget = frame->InitializeFrameWidget(
@@ -869,12 +868,19 @@ class PrepareFrameAndViewForPrint : public blink::WebViewClient,
void ResizeForPrinting();
void RestoreSize();
void CopySelection(const WebPreferences& preferences);
+ void ComputeScalingAndPrintParams(blink::WebLocalFrame* frame,
+ mojom::PrintParamsPtr& print_params,
+ std::string* selection,
+ bool is_pdf,
+ bool ignore_css_margins,
+ bool fit_to_page);
FrameReference frame_;
FrameReference original_frame_;
blink::WebNavigationControl* navigation_control_ = nullptr;
blink::WebNode node_to_print_;
bool owns_web_view_ = false;
+ mojom::PrintParamsPtr selection_only_print_params_;
blink::WebPrintParams web_print_params_;
gfx::Size prev_view_size_;
uint32_t expected_pages_count_ = 0;
@@ -902,21 +908,19 @@ PrepareFrameAndViewForPrint::PrepareFrameAndViewForPrint(
mojom::PrintParamsPtr print_params = params.Clone();
bool source_is_pdf = IsPrintingNodeOrPdfFrame(frame, node_to_print_);
- if (!should_print_selection_only_) {
+ if (should_print_selection_only_) {
+ // Save the parameters for use in `CopySelection()`.
+ selection_only_print_params_ = std::move(print_params);
+
+ // Printing selection not an option for PDF.
+ DCHECK(!source_is_pdf);
+ } else {
bool fit_to_page =
ignore_css_margins && IsPrintScalingOptionFitToPage(*print_params);
- ComputeWebKitPrintParamsInDesiredDpi(params, source_is_pdf,
- &web_print_params_);
- frame->PrintBegin(web_print_params_, node_to_print_);
- double scale_factor = PrintRenderFrameHelper::GetScaleFactor(
- print_params->scale_factor, source_is_pdf);
- print_params =
- CalculatePrintParamsForCss(frame, 0, *print_params, ignore_css_margins,
- fit_to_page, &scale_factor);
- frame->PrintEnd();
+ ComputeScalingAndPrintParams(frame, print_params, /*selection=*/nullptr,
+ source_is_pdf, ignore_css_margins,
+ fit_to_page);
}
- ComputeWebKitPrintParamsInDesiredDpi(*print_params, source_is_pdf,
- &web_print_params_);
}
PrepareFrameAndViewForPrint::~PrepareFrameAndViewForPrint() {
@@ -975,9 +979,11 @@ void PrepareFrameAndViewForPrint::CopySelectionIfNeeded(
void PrepareFrameAndViewForPrint::CopySelection(
const WebPreferences& preferences) {
ResizeForPrinting();
- frame()->PrintBegin(web_print_params_, node_to_print_);
- std::string html = frame()->SelectionAsMarkup().Utf8();
- frame()->PrintEnd();
+ std::string html;
+ ComputeScalingAndPrintParams(frame(), selection_only_print_params_, &html,
+ /*is_pdf=*/false,
+ /*ignore_css_margins=*/false,
+ /*fit_to_page=*/false);
RestoreSize();
// Create a new WebView with the same settings as the current display one.
@@ -1008,14 +1014,14 @@ void PrepareFrameAndViewForPrint::CopySelection(
frame_widget.BindNewEndpointAndPassDedicatedReceiver();
mojo::AssociatedRemote<blink::mojom::FrameWidgetHost> frame_widget_host;
- ignore_result(frame_widget_host.BindNewEndpointAndPassDedicatedReceiver());
+ std::ignore = frame_widget_host.BindNewEndpointAndPassDedicatedReceiver();
mojo::AssociatedRemote<blink::mojom::Widget> widget_remote;
mojo::PendingAssociatedReceiver<blink::mojom::Widget> widget_receiver =
widget_remote.BindNewEndpointAndPassDedicatedReceiver();
mojo::AssociatedRemote<blink::mojom::WidgetHost> widget_host_remote;
- ignore_result(widget_host_remote.BindNewEndpointAndPassDedicatedReceiver());
+ std::ignore = widget_host_remote.BindNewEndpointAndPassDedicatedReceiver();
blink::WebFrameWidget* main_frame_widget = main_frame->InitializeFrameWidget(
frame_widget_host.Unbind(), std::move(frame_widget_receiver),
@@ -1038,6 +1044,28 @@ void PrepareFrameAndViewForPrint::CopySelection(
/*extra_data=*/nullptr);
}
+void PrepareFrameAndViewForPrint::ComputeScalingAndPrintParams(
+ blink::WebLocalFrame* frame,
+ mojom::PrintParamsPtr& print_params,
+ std::string* selection,
+ bool is_pdf,
+ bool ignore_css_margins,
+ bool fit_to_page) {
+ ComputeWebKitPrintParamsInDesiredDpi(*print_params, is_pdf,
+ &web_print_params_);
+ frame->PrintBegin(web_print_params_, node_to_print_);
+ double scale_factor = PrintRenderFrameHelper::GetScaleFactor(
+ print_params->scale_factor, is_pdf);
+ print_params = CalculatePrintParamsForCss(frame, /*page_index=*/0,
+ *print_params, ignore_css_margins,
+ fit_to_page, &scale_factor);
+ if (selection)
+ *selection = frame->SelectionAsMarkup().Utf8();
+ frame->PrintEnd();
+ ComputeWebKitPrintParamsInDesiredDpi(*print_params, is_pdf,
+ &web_print_params_);
+}
+
void PrepareFrameAndViewForPrint::DidStopLoading() {
DCHECK(!on_ready_.is_null());
// Don't call callback here, because it can delete |this| and WebView that is
@@ -1199,6 +1227,10 @@ void PrintRenderFrameHelper::DidFinishLoad() {
std::move(on_stop_loading_closure_).Run();
}
+void PrintRenderFrameHelper::DidFinishLoadForPrinting() {
+ DidFinishLoad();
+}
+
void PrintRenderFrameHelper::ScriptedPrint(bool user_initiated) {
blink::WebLocalFrame* web_frame = render_frame()->GetWebFrame();
if (!IsScriptInitiatedPrintAllowed(web_frame, user_initiated))
@@ -1219,7 +1251,8 @@ void PrintRenderFrameHelper::ScriptedPrint(bool user_initiated) {
if (g_is_preview_enabled) {
#if BUILDFLAG(ENABLE_PRINT_PREVIEW)
print_preview_context_.InitWithFrame(web_frame);
- RequestPrintPreview(PRINT_PREVIEW_SCRIPTED);
+ RequestPrintPreview(PRINT_PREVIEW_SCRIPTED,
+ /*already_notified_frame=*/false);
#endif
} else {
web_frame->DispatchBeforePrintEvent(/*print_client=*/nullptr);
@@ -1340,9 +1373,9 @@ void PrintRenderFrameHelper::InitiatePrintPreview(
return;
}
print_preview_context_.InitWithFrame(frame);
- RequestPrintPreview(has_selection
- ? PRINT_PREVIEW_USER_INITIATED_SELECTION
- : PRINT_PREVIEW_USER_INITIATED_ENTIRE_FRAME);
+ RequestPrintPreview(has_selection ? PRINT_PREVIEW_USER_INITIATED_SELECTION
+ : PRINT_PREVIEW_USER_INITIATED_ENTIRE_FRAME,
+ /*already_notified_frame=*/false);
}
void PrintRenderFrameHelper::PrintPreview(base::Value settings) {
@@ -1869,7 +1902,8 @@ void PrintRenderFrameHelper::PrintNode(const blink::WebNode& node) {
if (g_is_preview_enabled) {
#if BUILDFLAG(ENABLE_PRINT_PREVIEW)
print_preview_context_.InitWithNode(node);
- RequestPrintPreview(PRINT_PREVIEW_USER_INITIATED_CONTEXT_NODE);
+ RequestPrintPreview(PRINT_PREVIEW_USER_INITIATED_CONTEXT_NODE,
+ /*already_notified_frame=*/false);
#endif
} else {
// Make a copy of the node, in case RenderView::OnContextMenuClosed() resets
@@ -2085,7 +2119,7 @@ bool PrintRenderFrameHelper::PrintPagesNative(blink::WebLocalFrame* frame,
page_params->content = mojom::DidPrintContentParams::New();
gfx::Size* page_size_in_dpi;
gfx::Rect* content_area_in_dpi;
-#if defined(OS_APPLE) || defined(OS_WIN)
+#if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_WIN)
page_size_in_dpi = &page_params->page_size;
content_area_in_dpi = &page_params->content_area;
#else
@@ -2112,7 +2146,7 @@ bool PrintRenderFrameHelper::PrintPagesNative(blink::WebLocalFrame* frame,
}
page_params->document_cookie = print_params.document_cookie;
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
page_params->physical_offsets = printer_printable_area_.origin();
#endif
bool completed = false;
@@ -2284,25 +2318,26 @@ bool PrintRenderFrameHelper::UpdatePrintSettings(
return false;
}
- // TODO(dhoss): Replace deprecated base::DictionaryValue::Get<Type>() calls
- if (!job_settings->GetInteger(kPreviewUIID,
- &settings->params->preview_ui_id)) {
+ absl::optional<int> preview_ui_id = job_settings->FindIntKey(kPreviewUIID);
+ if (!preview_ui_id) {
NOTREACHED();
print_preview_context_.set_error(PREVIEW_ERROR_BAD_SETTING);
return false;
}
+ settings->params->preview_ui_id = *preview_ui_id;
// Validate expected print preview settings.
absl::optional<bool> is_first_request =
job_settings->FindBoolKey(kIsFirstRequest);
- if (!job_settings->GetInteger(kPreviewRequestID,
- &settings->params->preview_request_id) ||
- !is_first_request.has_value()) {
+ absl::optional<int> preview_request_id =
+ job_settings->FindIntKey(kPreviewRequestID);
+ if (!preview_request_id.has_value() || !is_first_request.has_value()) {
NOTREACHED();
print_preview_context_.set_error(PREVIEW_ERROR_BAD_SETTING);
return false;
}
settings->params->is_first_request = is_first_request.value();
+ settings->params->preview_request_id = preview_request_id.value();
settings->params->print_to_pdf = IsPrintToPdfRequested(*job_settings);
UpdateFrameMarginsCssInfo(*job_settings);
@@ -2383,7 +2418,7 @@ bool PrintRenderFrameHelper::RenderPagesForPrint(blink::WebLocalFrame* frame,
return true;
}
-#if !defined(OS_APPLE)
+#if !BUILDFLAG(IS_APPLE)
void PrintRenderFrameHelper::PrintPageInternal(const mojom::PrintParams& params,
uint32_t page_number,
uint32_t page_count,
@@ -2422,7 +2457,7 @@ void PrintRenderFrameHelper::PrintPageInternal(const mojom::PrintParams& params,
params.display_header_footer ? gfx::Rect(page_size) : content_area;
// TODO(thestig): Figure out why Linux is different.
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
float webkit_page_shrink_factor = frame->GetPrintPageShrink(page_number);
float final_scale_factor = css_scale_factor * webkit_page_shrink_factor;
#else
@@ -2437,7 +2472,7 @@ void PrintRenderFrameHelper::PrintPageInternal(const mojom::PrintParams& params,
canvas->SetPrintingMetafile(metafile);
if (params.display_header_footer) {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
const float fudge_factor = 1;
#else
// TODO(thestig): Figure out why Linux needs this. It is almost certainly
@@ -2459,7 +2494,7 @@ void PrintRenderFrameHelper::PrintPageInternal(const mojom::PrintParams& params,
bool ret = metafile->FinishPage();
DCHECK(ret);
}
-#endif // !defined(OS_APPLE)
+#endif // !BUILDFLAG(IS_APPLE)
#if BUILDFLAG(ENABLE_PRINT_PREVIEW)
void PrintRenderFrameHelper::ShowScriptedPrintPreview() {
@@ -2470,12 +2505,32 @@ void PrintRenderFrameHelper::ShowScriptedPrintPreview() {
}
}
-void PrintRenderFrameHelper::RequestPrintPreview(PrintPreviewRequestType type) {
+void PrintRenderFrameHelper::WaitForLoad(PrintPreviewRequestType type) {
+ static constexpr base::TimeDelta kLoadEventTimeout = base::Seconds(2);
+
+ on_stop_loading_closure_ =
+ base::BindOnce(&PrintRenderFrameHelper::RequestPrintPreview,
+ weak_ptr_factory_.GetWeakPtr(), type, true);
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE,
+ base::BindOnce(&PrintRenderFrameHelper::DidFinishLoadForPrinting,
+ weak_ptr_factory_.GetWeakPtr()),
+ kLoadEventTimeout);
+}
+
+void PrintRenderFrameHelper::RequestPrintPreview(PrintPreviewRequestType type,
+ bool already_notified_frame) {
auto weak_this = weak_ptr_factory_.GetWeakPtr();
- print_preview_context_.DispatchBeforePrintEvent(weak_this);
+ if (!already_notified_frame) {
+ print_preview_context_.DispatchBeforePrintEvent(weak_this);
+ }
if (!weak_this)
return;
+ if (!already_notified_frame) {
+ is_loading_ = print_preview_context_.source_frame()->WillPrintSoon();
+ }
+
const bool is_from_arc = print_preview_context_.IsForArc();
const bool is_modifiable = print_preview_context_.IsModifiable();
const bool has_selection = print_preview_context_.HasSelection();
@@ -2499,19 +2554,20 @@ void PrintRenderFrameHelper::RequestPrintPreview(PrintPreviewRequestType type) {
// 2. ShowScriptedPrintPreview() shows preview once the document has been
// loaded.
is_scripted_preview_delayed_ = true;
- if (is_loading_ && print_preview_context_.IsPlugin()) {
- // Wait for DidStopLoading. Plugins may not know the correct
- // |is_modifiable| value until they are fully loaded, which occurs when
- // DidStopLoading() is called. Defer showing the preview until then.
- on_stop_loading_closure_ =
- base::BindOnce(&PrintRenderFrameHelper::ShowScriptedPrintPreview,
- weak_ptr_factory_.GetWeakPtr());
- } else {
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::BindOnce(&PrintRenderFrameHelper::ShowScriptedPrintPreview,
- weak_ptr_factory_.GetWeakPtr()));
+ if (is_loading_) {
+ // Wait for DidStopLoading, for two reasons:
+ // * To give the document time to finish loading any pending resources
+ /// that are desired for printing.
+ // * Plugins may not know the correct|is_modifiable| value until they
+ // are fully loaded, which occurs when DidStopLoading() is called.
+ // Defer showing the preview until then.
+ WaitForLoad(type);
+ return;
}
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::BindOnce(&PrintRenderFrameHelper::ShowScriptedPrintPreview,
+ weak_ptr_factory_.GetWeakPtr()));
base::RunLoop loop{base::RunLoop::Type::kNestableTasksAllowed};
closures_for_mojo_responses_->SetScriptedPrintPreviewQuitClosure(
loop.QuitClosure());
@@ -2536,13 +2592,9 @@ void PrintRenderFrameHelper::RequestPrintPreview(PrintPreviewRequestType type) {
return;
}
case PRINT_PREVIEW_USER_INITIATED_ENTIRE_FRAME: {
- // Wait for DidStopLoading. Continuing with this function while
- // |is_loading_| is true will cause print preview to hang when try to
- // print a PDF document.
- if (is_loading_ && print_preview_context_.IsPlugin()) {
- on_stop_loading_closure_ =
- base::BindOnce(&PrintRenderFrameHelper::RequestPrintPreview,
- weak_ptr_factory_.GetWeakPtr(), type);
+ // See comment under PRINT_PREVIEW_SCRIPTED.
+ if (is_loading_) {
+ WaitForLoad(type);
return;
}
@@ -2555,10 +2607,9 @@ void PrintRenderFrameHelper::RequestPrintPreview(PrintPreviewRequestType type) {
break;
}
case PRINT_PREVIEW_USER_INITIATED_CONTEXT_NODE: {
- if (is_loading_ && print_preview_context_.IsPlugin()) {
- on_stop_loading_closure_ =
- base::BindOnce(&PrintRenderFrameHelper::RequestPrintPreview,
- weak_ptr_factory_.GetWeakPtr(), type);
+ // See comment under PRINT_PREVIEW_SCRIPTED.
+ if (is_loading_) {
+ WaitForLoad(type);
return;
}
diff --git a/chromium/components/printing/renderer/print_render_frame_helper.h b/chromium/components/printing/renderer/print_render_frame_helper.h
index 90236920457..2b703118bf9 100644
--- a/chromium/components/printing/renderer/print_render_frame_helper.h
+++ b/chromium/components/printing/renderer/print_render_frame_helper.h
@@ -34,15 +34,11 @@
// RenderViewTest-based tests crash on Android
// http://crbug.com/187500
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#define MAYBE_PrintRenderFrameHelperTest DISABLED_PrintRenderFrameHelperTest
-#define MAYBE_PrintRenderFrameHelperPreviewTest \
- DISABLED_PrintRenderFrameHelperPreviewTest
#else
#define MAYBE_PrintRenderFrameHelperTest PrintRenderFrameHelperTest
-#define MAYBE_PrintRenderFrameHelperPreviewTest \
- PrintRenderFrameHelperPreviewTest
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
namespace base {
class DictionaryValue;
@@ -167,8 +163,9 @@ class PrintRenderFrameHelper
const mojo::AssociatedRemote<mojom::PrintManagerHost>& GetPrintManagerHost();
private:
+ friend class PrintRenderFrameHelperPreviewTest;
friend class PrintRenderFrameHelperTestBase;
- FRIEND_TEST_ALL_PREFIXES(MAYBE_PrintRenderFrameHelperPreviewTest,
+ FRIEND_TEST_ALL_PREFIXES(PrintRenderFrameHelperPreviewTest,
BlockScriptInitiatedPrinting);
FRIEND_TEST_ALL_PREFIXES(MAYBE_PrintRenderFrameHelperTest,
PrintRequestedPages);
@@ -176,10 +173,10 @@ class PrintRenderFrameHelper
BlockScriptInitiatedPrinting);
FRIEND_TEST_ALL_PREFIXES(MAYBE_PrintRenderFrameHelperTest,
BlockScriptInitiatedPrintingFromPopup);
-#if defined(OS_WIN) || defined(OS_APPLE)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE)
FRIEND_TEST_ALL_PREFIXES(MAYBE_PrintRenderFrameHelperTest, PrintLayoutTest);
FRIEND_TEST_ALL_PREFIXES(MAYBE_PrintRenderFrameHelperTest, PrintWithIframe);
-#endif // defined(OS_WIN) || defined(OS_APPLE)
+#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE)
// CREATE_IN_PROGRESS signifies that the preview document is being rendered
// asynchronously by a PrintRenderer.
@@ -250,6 +247,7 @@ class PrintRenderFrameHelper
absl::optional<blink::WebNavigationType> navigation_type) override;
void DidFailProvisionalLoad() override;
void DidFinishLoad() override;
+ void DidFinishLoadForPrinting() override;
void ScriptedPrint(bool user_initiated) override;
void BindPrintRenderFrameReceiver(
@@ -439,7 +437,8 @@ class PrintRenderFrameHelper
// WARNING: |this| may be gone after this method returns when |type| is
// PRINT_PREVIEW_SCRIPTED.
- void RequestPrintPreview(PrintPreviewRequestType type);
+ void RequestPrintPreview(PrintPreviewRequestType type,
+ bool already_notified_frame);
// Checks whether print preview should continue or not.
// Returns true if canceling, false if continuing.
@@ -658,6 +657,8 @@ class PrintRenderFrameHelper
int count_ = 0;
};
+ void WaitForLoad(PrintPreviewRequestType type);
+
ScriptingThrottler scripting_throttler_;
bool print_node_in_progress_ = false;
@@ -676,10 +677,13 @@ class PrintRenderFrameHelper
// is enabled.
std::unique_ptr<content::AXTreeSnapshotter> snapshotter_;
- // Used to fix a race condition where the source is a PDF and print preview
- // hangs because RequestPrintPreview is called before DidStopLoading() is
- // called. This is a store for the RequestPrintPreview() call and its
- // parameters so that it can be invoked after DidStopLoading.
+ // Used for two reasons:
+ // * To give the document time to finish loading any pending resources that
+ // are desired for printing.
+ // * To fix a race condition where the source is a PDF and print preview
+ // hangs because RequestPrintPreview is called before DidStopLoading() is
+ // called. This is a store for the RequestPrintPreview() call and its
+ // parameters so that it can be invoked after DidStopLoading.
base::OnceClosure on_stop_loading_closure_;
// Stores the quit closures of Mojo responses.
diff --git a/chromium/components/printing_component_strings.grdp b/chromium/components/printing_component_strings.grdp
index 0e36b124478..f1ad867bff9 100644
--- a/chromium/components/printing_component_strings.grdp
+++ b/chromium/components/printing_component_strings.grdp
@@ -12,7 +12,7 @@
Print Compositor Service
</message>
- <if expr="chromeos or lacros">
+ <if expr="chromeos_ash or chromeos_lacros">
<message name="IDS_PRINT_CHAMBER_HUMIDITY" desc="PWG5100.21 (8.1.1) chamber-humidity">
Chamber humidity
</message>
diff --git a/chromium/components/privacy_sandbox/BUILD.gn b/chromium/components/privacy_sandbox/BUILD.gn
index 524bfb6ae78..e095c42f06c 100644
--- a/chromium/components/privacy_sandbox/BUILD.gn
+++ b/chromium/components/privacy_sandbox/BUILD.gn
@@ -15,3 +15,69 @@ static_library("privacy_sandbox_prefs") {
public_deps = [ "//base" ]
}
+
+source_set("privacy_sandbox") {
+ sources = [
+ "canonical_topic.cc",
+ "canonical_topic.h",
+ "privacy_sandbox_features.cc",
+ "privacy_sandbox_features.h",
+ "privacy_sandbox_settings.cc",
+ "privacy_sandbox_settings.h",
+ ]
+
+ deps = [
+ ":privacy_sandbox_prefs",
+ "//components/content_settings/core/browser",
+ "//components/content_settings/core/common",
+ "//components/keyed_service/core:core",
+ "//components/pref_registry:pref_registry",
+ "//components/prefs",
+ "//components/strings:components_strings_grit",
+ "//net:net",
+ "//ui/base:base",
+ "//url:url",
+ ]
+
+ public_deps = [ "//base" ]
+}
+
+source_set("unit_tests") {
+ testonly = true
+ sources = [
+ "canonical_topic_unittest.cc",
+ "privacy_sandbox_settings_unittest.cc",
+ ]
+
+ deps = [
+ ":privacy_sandbox",
+ ":privacy_sandbox_prefs",
+ ":test_support",
+ "//components/content_settings/core/browser:browser",
+ "//components/content_settings/core/test:test_support",
+ "//components/prefs:test_support",
+ "//components/strings:components_strings_grit",
+ "//components/sync_preferences:test_support",
+ "//content/test:test_support",
+ "//net",
+ "//testing/gtest",
+ ]
+}
+
+source_set("test_support") {
+ testonly = true
+ sources = [
+ "privacy_sandbox_test_util.cc",
+ "privacy_sandbox_test_util.h",
+ ]
+ deps = [
+ ":privacy_sandbox",
+ ":privacy_sandbox_prefs",
+ "//components/content_settings/core/browser:browser",
+ "//components/content_settings/core/common:common",
+ "//components/content_settings/core/test:test_support",
+ "//components/prefs:test_support",
+ "//components/sync_preferences:test_support",
+ "//testing/gmock",
+ ]
+}
diff --git a/chromium/components/privacy_sandbox/DEPS b/chromium/components/privacy_sandbox/DEPS
index 4876dc706da..2478fd75ee7 100644
--- a/chromium/components/privacy_sandbox/DEPS
+++ b/chromium/components/privacy_sandbox/DEPS
@@ -1,4 +1,12 @@
include_rules = [
+ "+components/content_settings/core",
+ "+components/keyed_service/core",
"+components/pref_registry",
"+components/prefs",
+ "+components/strings/grit/components_strings.h",
+ "+components/sync_preferences/testing_pref_service_syncable.h",
+ "+net/base",
+ "+net/cookies/site_for_cookies.h",
+ "+content/public/test",
+ "+ui/base",
]
diff --git a/chromium/components/privacy_sandbox/canonical_topic.cc b/chromium/components/privacy_sandbox/canonical_topic.cc
new file mode 100644
index 00000000000..8d7ed31b030
--- /dev/null
+++ b/chromium/components/privacy_sandbox/canonical_topic.cc
@@ -0,0 +1,412 @@
+// Copyright 2022 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.
+
+#include "components/privacy_sandbox/canonical_topic.h"
+
+#include "base/check_op.h"
+#include "base/metrics/histogram_functions.h"
+#include "components/strings/grit/components_strings.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace {
+
+std::u16string GetLocalizedRepresentationInternal(int topic_id,
+ int taxonomy_version) {
+ // The available Taxonomy versions are included in the Chrome binary, and
+ // so can be CHECK'd against here.
+ CHECK_EQ(privacy_sandbox::CanonicalTopic::AVAILABLE_TAXONOMY,
+ taxonomy_version);
+
+ // Topic IDs are sequentially indexed from 1. They are provided by a
+ // categorization model shipped over the network, which could technically
+ // provide Topic IDs outside the expected range, e.g. due to server issues.
+ // The case of an out-of-bounds |topic_id| must thus be gracefully handled. To
+ // ensure we are made aware of any issues, UMA metrics are logged in this
+ // failure case.
+ constexpr int kTaxonomyV1Size = 349;
+ if (topic_id < 1 || topic_id > kTaxonomyV1Size) {
+ base::UmaHistogramSparse("Settings.PrivacySandbox.InvalidTopicIdLocalized",
+ topic_id);
+ return l10n_util::GetStringUTF16(IDS_PRIVACY_SANDBOX_TOPICS_INVALID_TOPIC);
+ }
+
+ static constexpr int kLocalizedTaxononmyV1[kTaxonomyV1Size] = {
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_1,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_2,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_3,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_4,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_5,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_6,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_7,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_8,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_9,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_10,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_11,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_12,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_13,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_14,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_15,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_16,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_17,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_18,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_19,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_20,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_21,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_22,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_23,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_24,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_25,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_26,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_27,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_28,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_29,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_30,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_31,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_32,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_33,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_34,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_35,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_36,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_37,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_38,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_39,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_40,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_41,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_42,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_43,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_44,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_45,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_46,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_47,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_48,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_49,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_50,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_51,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_52,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_53,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_54,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_55,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_56,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_57,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_58,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_59,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_60,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_61,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_62,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_63,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_64,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_65,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_66,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_67,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_68,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_69,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_70,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_71,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_72,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_73,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_74,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_75,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_76,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_77,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_78,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_79,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_80,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_81,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_82,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_83,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_84,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_85,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_86,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_87,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_88,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_89,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_90,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_91,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_92,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_93,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_94,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_95,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_96,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_97,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_98,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_99,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_100,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_101,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_102,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_103,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_104,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_105,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_106,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_107,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_108,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_109,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_110,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_111,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_112,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_113,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_114,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_115,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_116,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_117,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_118,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_119,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_120,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_121,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_122,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_123,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_124,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_125,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_126,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_127,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_128,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_129,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_130,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_131,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_132,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_133,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_134,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_135,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_136,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_137,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_138,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_139,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_140,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_141,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_142,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_143,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_144,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_145,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_146,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_147,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_148,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_149,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_150,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_151,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_152,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_153,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_154,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_155,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_156,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_157,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_158,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_159,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_160,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_161,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_162,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_163,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_164,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_165,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_166,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_167,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_168,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_169,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_170,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_171,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_172,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_173,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_174,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_175,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_176,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_177,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_178,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_179,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_180,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_181,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_182,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_183,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_184,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_185,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_186,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_187,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_188,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_189,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_190,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_191,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_192,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_193,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_194,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_195,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_196,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_197,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_198,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_199,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_200,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_201,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_202,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_203,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_204,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_205,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_206,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_207,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_208,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_209,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_210,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_211,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_212,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_213,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_214,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_215,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_216,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_217,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_218,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_219,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_220,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_221,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_222,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_223,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_224,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_225,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_226,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_227,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_228,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_229,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_230,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_231,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_232,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_233,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_234,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_235,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_236,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_237,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_238,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_239,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_240,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_241,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_242,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_243,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_244,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_245,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_246,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_247,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_248,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_249,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_250,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_251,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_252,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_253,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_254,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_255,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_256,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_257,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_258,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_259,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_260,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_261,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_262,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_263,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_264,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_265,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_266,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_267,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_268,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_269,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_270,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_271,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_272,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_273,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_274,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_275,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_276,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_277,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_278,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_279,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_280,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_281,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_282,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_283,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_284,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_285,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_286,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_287,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_288,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_289,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_290,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_291,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_292,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_293,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_294,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_295,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_296,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_297,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_298,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_299,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_300,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_301,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_302,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_303,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_304,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_305,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_306,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_307,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_308,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_309,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_310,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_311,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_312,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_313,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_314,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_315,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_316,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_317,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_318,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_319,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_320,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_321,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_322,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_323,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_324,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_325,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_326,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_327,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_328,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_329,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_330,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_331,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_332,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_333,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_334,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_335,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_336,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_337,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_338,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_339,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_340,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_341,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_342,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_343,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_344,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_345,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_346,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_347,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_348,
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_349,
+ };
+
+ return l10n_util::GetStringUTF16(kLocalizedTaxononmyV1[topic_id - 1]);
+}
+
+} // namespace
+
+namespace privacy_sandbox {
+
+CanonicalTopic::CanonicalTopic(int topic_id, int taxonomy_version)
+ : topic_id_(topic_id), taxonomy_version_(taxonomy_version) {}
+
+std::u16string CanonicalTopic::GetLocalizedRepresentation() const {
+ return GetLocalizedRepresentationInternal(topic_id_, taxonomy_version_);
+}
+
+bool CanonicalTopic::operator<(const CanonicalTopic& other) const {
+ if (taxonomy_version_ != other.taxonomy_version_)
+ return taxonomy_version_ < other.taxonomy_version_;
+ return topic_id_ < other.topic_id_;
+}
+
+bool CanonicalTopic::operator==(const CanonicalTopic& other) const {
+ if (taxonomy_version_ != other.taxonomy_version_)
+ return false;
+ return topic_id_ == other.topic_id_;
+}
+
+} // namespace privacy_sandbox
diff --git a/chromium/components/privacy_sandbox/canonical_topic.h b/chromium/components/privacy_sandbox/canonical_topic.h
new file mode 100644
index 00000000000..ceb48aa4a45
--- /dev/null
+++ b/chromium/components/privacy_sandbox/canonical_topic.h
@@ -0,0 +1,47 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_PRIVACY_SANDBOX_CANONICAL_TOPIC_H_
+#define COMPONENTS_PRIVACY_SANDBOX_CANONICAL_TOPIC_H_
+
+#include <string>
+
+namespace browsing_topics {
+using Topic = int;
+}
+
+namespace privacy_sandbox {
+// Contains a topic and a name in the current locale.
+class CanonicalTopic {
+ public:
+ // TODO(crbug.com/1286276): Correctly retrieve the set of available
+ // taxononmies.
+ static const int AVAILABLE_TAXONOMY = 1;
+
+ CanonicalTopic(browsing_topics::Topic topic_id, int taxonomy_version);
+
+ // The ID of this topic. A Canonical Topic's ID uniquely identifies it
+ // within a specific taxonomy version.
+ browsing_topics::Topic topic_id() const { return topic_id_; }
+
+ // The taxonomy version of the Canonical Topic. Topics with the same topic
+ // ID, but different taxonomy versions are never equivalent. Even if their
+ // localized representations are identical.
+ int taxonomy_version() const { return taxonomy_version_; }
+
+ // Returns the localized string representation of the Canonical Topic, this
+ // is suitable for direct display to the user.
+ std::u16string GetLocalizedRepresentation() const;
+
+ bool operator<(const CanonicalTopic& other) const;
+ bool operator==(const CanonicalTopic& other) const;
+
+ private:
+ browsing_topics::Topic topic_id_;
+ int taxonomy_version_;
+};
+
+} // namespace privacy_sandbox
+
+#endif // COMPONENTS_PRIVACY_SANDBOX_CANONICAL_TOPIC_H_
diff --git a/chromium/components/privacy_sandbox/canonical_topic_unittest.cc b/chromium/components/privacy_sandbox/canonical_topic_unittest.cc
new file mode 100644
index 00000000000..98c6ed6b26d
--- /dev/null
+++ b/chromium/components/privacy_sandbox/canonical_topic_unittest.cc
@@ -0,0 +1,93 @@
+// Copyright 2022 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.
+
+#include "components/privacy_sandbox/canonical_topic.h"
+
+#include "base/test/gtest_util.h"
+#include "base/test/metrics/histogram_tester.h"
+#include "components/strings/grit/components_strings.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace privacy_sandbox {
+
+namespace {
+
+// Constraints around the currently checked in topics and taxonomy. Changes to
+// the taxononmy version or number of topics will fail these tests unless these
+// are also updated.
+constexpr int kAvailableTaxononmyVersion = 1;
+constexpr int kLowestTopicID = 1;
+constexpr int kHighestTopicID = 349;
+
+constexpr char kInvalidTopicLocalizedHistogramName[] =
+ "Settings.PrivacySandbox.InvalidTopicIdLocalized";
+
+} // namespace
+
+using CanonicalTopicTest = testing::Test;
+
+TEST_F(CanonicalTopicTest, LocalizedRepresentation) {
+ // Confirm that topics at the boundaries convert to strings appropriately.
+ base::HistogramTester histogram_tester;
+ CanonicalTopic first_topic(
+ kLowestTopicID, privacy_sandbox::CanonicalTopic::AVAILABLE_TAXONOMY);
+ CanonicalTopic last_topic(
+ kHighestTopicID, privacy_sandbox::CanonicalTopic::AVAILABLE_TAXONOMY);
+ EXPECT_EQ(l10n_util::GetStringUTF16(
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_1),
+ first_topic.GetLocalizedRepresentation());
+ EXPECT_EQ(l10n_util::GetStringUTF16(
+ IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_349),
+ last_topic.GetLocalizedRepresentation());
+
+ // Successful localizations should not result in any metrics being recorded.
+ histogram_tester.ExpectTotalCount(kInvalidTopicLocalizedHistogramName, 0);
+}
+
+TEST_F(CanonicalTopicTest, InvalidTopicIdLocalized) {
+ // Confirm that an attempt to localize an invalid Topic ID returns the correct
+ // error string and logs to UMA.
+ base::HistogramTester histogram_tester;
+ CanonicalTopic too_low_id(kLowestTopicID - 1, kAvailableTaxononmyVersion);
+ CanonicalTopic negative_id(-1, kAvailableTaxononmyVersion);
+ CanonicalTopic too_high_id(kHighestTopicID + 1, kAvailableTaxononmyVersion);
+
+ std::vector<CanonicalTopic> test_bad_topics = {too_low_id, negative_id,
+ too_high_id};
+
+ for (const auto& topic : test_bad_topics) {
+ EXPECT_EQ(
+ l10n_util::GetStringUTF16(IDS_PRIVACY_SANDBOX_TOPICS_INVALID_TOPIC),
+ topic.GetLocalizedRepresentation());
+ }
+
+ histogram_tester.ExpectTotalCount(kInvalidTopicLocalizedHistogramName, 3);
+ histogram_tester.ExpectBucketCount(kInvalidTopicLocalizedHistogramName,
+ too_low_id.topic_id(), 1);
+ histogram_tester.ExpectBucketCount(kInvalidTopicLocalizedHistogramName,
+ negative_id.topic_id(), 1);
+ histogram_tester.ExpectBucketCount(kInvalidTopicLocalizedHistogramName,
+ too_high_id.topic_id(), 1);
+}
+
+using CanonicalTopicDeathTest = testing::Test;
+
+TEST_F(CanonicalTopicDeathTest, OutOfBoundsDeath) {
+ // Confirm that requesting a topics with invalid Taxononmy results in a
+ // CHECK failure.
+ CanonicalTopic too_low_taxonomy(kLowestTopicID,
+ kAvailableTaxononmyVersion - 1);
+ CanonicalTopic negative_taxonomy(kLowestTopicID, -1);
+ CanonicalTopic too_high_taxonomy(kLowestTopicID,
+ kAvailableTaxononmyVersion + 1);
+
+ std::vector<CanonicalTopic> test_bad_topics = {
+ too_low_taxonomy, negative_taxonomy, too_high_taxonomy};
+
+ for (const auto& topic : test_bad_topics)
+ EXPECT_CHECK_DEATH(topic.GetLocalizedRepresentation());
+}
+
+} // namespace privacy_sandbox
diff --git a/chromium/components/privacy_sandbox/privacy_sandbox_features.cc b/chromium/components/privacy_sandbox/privacy_sandbox_features.cc
new file mode 100644
index 00000000000..5a274e78c3b
--- /dev/null
+++ b/chromium/components/privacy_sandbox/privacy_sandbox_features.cc
@@ -0,0 +1,22 @@
+// Copyright 2022 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.
+
+#include "components/privacy_sandbox/privacy_sandbox_features.h"
+
+namespace privacy_sandbox {
+
+const base::Feature kPrivacySandboxSettings3{"PrivacySandboxSettings3",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+const base::FeatureParam<bool> kPrivacySandboxSettings3ConsentRequired{
+ &kPrivacySandboxSettings3, "consent-required", false};
+const base::FeatureParam<bool> kPrivacySandboxSettings3DisableDialogForTesting{
+ &kPrivacySandboxSettings3, "disable-dialog-for-testing", false};
+const base::FeatureParam<bool>
+ kPrivacySandboxSettings3ForceShowConsentForTesting{
+ &kPrivacySandboxSettings3, "force-show-consent-for-testing", false};
+const base::FeatureParam<bool>
+ kPrivacySandboxSettings3ForceShowNoticeForTesting{
+ &kPrivacySandboxSettings3, "force-show-notice-for-testing", false};
+
+} // namespace privacy_sandbox
diff --git a/chromium/components/privacy_sandbox/privacy_sandbox_features.h b/chromium/components/privacy_sandbox/privacy_sandbox_features.h
new file mode 100644
index 00000000000..225acc7edbf
--- /dev/null
+++ b/chromium/components/privacy_sandbox/privacy_sandbox_features.h
@@ -0,0 +1,30 @@
+// Copyright 2022 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.
+
+#include "base/feature_list.h"
+#include "base/metrics/field_trial_params.h"
+
+#ifndef COMPONENTS_PRIVACY_SANDBOX_PRIVACY_SANDBOX_FEATURES_H_
+#define COMPONENTS_PRIVACY_SANDBOX_PRIVACY_SANDBOX_FEATURES_H_
+
+namespace privacy_sandbox {
+
+// Enables the third release of the Privacy Sandbox settings.
+extern const base::Feature kPrivacySandboxSettings3;
+extern const base::FeatureParam<bool> kPrivacySandboxSettings3ConsentRequired;
+
+// Feature parameters which should exclusively be used for testing purposes.
+// Enabling any of these parameters may result in the Privacy Sandbox prefs
+// (unsynced) entering an unexpected state, requiring profile deletion to
+// resolve.
+extern const base::FeatureParam<bool>
+ kPrivacySandboxSettings3DisableDialogForTesting;
+extern const base::FeatureParam<bool>
+ kPrivacySandboxSettings3ForceShowConsentForTesting;
+extern const base::FeatureParam<bool>
+ kPrivacySandboxSettings3ForceShowNoticeForTesting;
+
+} // namespace privacy_sandbox
+
+#endif // COMPONENTS_PRIVACY_SANDBOX_PRIVACY_SANDBOX_FEATURES_H_
diff --git a/chromium/components/privacy_sandbox/privacy_sandbox_prefs.cc b/chromium/components/privacy_sandbox/privacy_sandbox_prefs.cc
index f6094c3d700..ef5155700fb 100644
--- a/chromium/components/privacy_sandbox/privacy_sandbox_prefs.cc
+++ b/chromium/components/privacy_sandbox/privacy_sandbox_prefs.cc
@@ -12,6 +12,8 @@ namespace prefs {
const char kPrivacySandboxApisEnabled[] = "privacy_sandbox.apis_enabled";
+const char kPrivacySandboxApisEnabledV2[] = "privacy_sandbox.apis_enabled_v2";
+
const char kPrivacySandboxManuallyControlled[] =
"privacy_sandbox.manually_controlled";
@@ -25,6 +27,21 @@ const char kPrivacySandboxFlocDataAccessibleSince[] =
extern const char kPrivacySandboxFlocEnabled[] = "privacy_sandbox.floc_enabled";
+extern const char kPrivacySandboxFledgeJoinBlocked[] =
+ "privacy_sandbox.fledge_join_blocked";
+
+extern const char kPrivacySandboxNoticeDisplayed[] =
+ "privacy_sandbox.notice_displayed";
+
+extern const char kPrivacySandboxConsentDecisionMade[] =
+ "privacy_sandbox.consent_decision_made";
+
+extern const char kPrivacySandboxNoConfirmationSandboxDisabled[] =
+ "privacy_sandbox.no_confirmation_sandbox_disabled";
+
+extern const char kPrivacySandboxDisabledInsufficientConfirmation[] =
+ "privacy_sandbox.disabled_insufficient_confirmation";
+
} // namespace prefs
namespace privacy_sandbox {
@@ -33,6 +50,7 @@ void RegisterProfilePrefs(PrefRegistrySimple* registry) {
registry->RegisterBooleanPref(
prefs::kPrivacySandboxApisEnabled, true,
user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+ registry->RegisterBooleanPref(prefs::kPrivacySandboxApisEnabledV2, false);
registry->RegisterBooleanPref(
prefs::kPrivacySandboxManuallyControlled, false,
user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
@@ -44,6 +62,14 @@ void RegisterProfilePrefs(PrefRegistrySimple* registry) {
registry->RegisterBooleanPref(
prefs::kPrivacySandboxFlocEnabled, true,
user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+ registry->RegisterDictionaryPref(prefs::kPrivacySandboxFledgeJoinBlocked);
+ registry->RegisterBooleanPref(prefs::kPrivacySandboxNoticeDisplayed, false);
+ registry->RegisterBooleanPref(prefs::kPrivacySandboxConsentDecisionMade,
+ false);
+ registry->RegisterBooleanPref(
+ prefs::kPrivacySandboxNoConfirmationSandboxDisabled, false);
+ registry->RegisterBooleanPref(
+ prefs::kPrivacySandboxDisabledInsufficientConfirmation, false);
}
} // namespace privacy_sandbox
diff --git a/chromium/components/privacy_sandbox/privacy_sandbox_prefs.h b/chromium/components/privacy_sandbox/privacy_sandbox_prefs.h
index 22f6bf7e4e1..cf980b345c3 100644
--- a/chromium/components/privacy_sandbox/privacy_sandbox_prefs.h
+++ b/chromium/components/privacy_sandbox/privacy_sandbox_prefs.h
@@ -12,8 +12,16 @@ namespace prefs {
// Synced boolean pref. Privacy Sandbox APIs may only be enabled when this is
// enabled, but each API will respect its own enabling logic if this pref is
// true. When this pref is false ALL Privacy Sandbox APIs are disabled.
+// TODO(crbug.com/1292898): Deprecate this preference once all users have been
+// migrated to the V2 pref.
extern const char kPrivacySandboxApisEnabled[];
+// Un-synced boolean pref. This is a replacement for the synced preference
+// above. It performs the exact same functionality, but is unsynced. This
+// preference is only consulted when the kPrivacySandboxSettings3 feature is
+// enabled.
+extern const char kPrivacySandboxApisEnabledV2[];
+
// Synced boolean that indicates if a user has manually toggled the settings
// associated with the PrivacySandboxSettings feature.
extern const char kPrivacySandboxManuallyControlled[];
@@ -35,6 +43,27 @@ extern const char kPrivacySandboxFlocDataAccessibleSince[];
// kPrivacySandboxApisEnabled preference be enabled to take effect.
extern const char kPrivacySandboxFlocEnabled[];
+// Dictionary of entries representing top frame origins on which the profile
+// cannot be joined to an interest group. Keys are the blocked origins, and
+// values are the time the setting was applied.
+extern const char kPrivacySandboxFledgeJoinBlocked[];
+
+// Boolean that indicates that the Privacy Sandbox notice was shown to the
+// profile.
+extern const char kPrivacySandboxNoticeDisplayed[];
+
+// Boolean that indicates that this profile has made a decision on the Privacy
+// Sandbox consent.
+extern const char kPrivacySandboxConsentDecisionMade[];
+
+// Boolean that indicates a Privacy Sandbox confirmation was not shown to the
+// profile because the profile had already disabled the Privacy Sandbox.
+extern const char kPrivacySandboxNoConfirmationSandboxDisabled[];
+
+// Boolean that indicates the user's Privacy Sandbox setting was disabled
+// automatically because they do not have the correct level of confirmation.
+extern const char kPrivacySandboxDisabledInsufficientConfirmation[];
+
} // namespace prefs
namespace privacy_sandbox {
diff --git a/chromium/components/privacy_sandbox/privacy_sandbox_settings.cc b/chromium/components/privacy_sandbox/privacy_sandbox_settings.cc
new file mode 100644
index 00000000000..3830e60c7e7
--- /dev/null
+++ b/chromium/components/privacy_sandbox/privacy_sandbox_settings.cc
@@ -0,0 +1,364 @@
+// Copyright 2020 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.
+
+#include "components/privacy_sandbox/privacy_sandbox_settings.h"
+
+#include "base/feature_list.h"
+#include "base/json/values_util.h"
+#include "base/ranges/algorithm.h"
+#include "base/time/time.h"
+#include "components/content_settings/core/browser/cookie_settings.h"
+#include "components/content_settings/core/browser/host_content_settings_map.h"
+#include "components/content_settings/core/common/pref_names.h"
+#include "components/prefs/pref_service.h"
+#include "components/prefs/scoped_user_pref_update.h"
+#include "components/privacy_sandbox/privacy_sandbox_features.h"
+#include "components/privacy_sandbox/privacy_sandbox_prefs.h"
+#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
+#include "net/cookies/site_for_cookies.h"
+#include "url/gurl.h"
+#include "url/origin.h"
+
+namespace {
+
+bool IsCookiesClearOnExitEnabled(HostContentSettingsMap* map) {
+ return map->GetDefaultContentSetting(ContentSettingsType::COOKIES,
+ /*provider_id=*/nullptr) ==
+ ContentSetting::CONTENT_SETTING_SESSION_ONLY;
+}
+
+bool HasNonDefaultBlockSetting(const ContentSettingsForOneType& cookie_settings,
+ const GURL& url,
+ const GURL& top_frame_origin) {
+ // APIs are allowed unless there is an effective non-default cookie content
+ // setting block exception. A default cookie content setting is one that has a
+ // wildcard pattern for both primary and secondary patterns. Content
+ // settings are listed in descending order of priority such that the first
+ // that matches is the effective content setting. A default setting can appear
+ // anywhere in the list. Content settings which appear after a default content
+ // setting are completely superseded by that content setting and are thus not
+ // consulted. Default settings which appear before other settings are applied
+ // from higher precedence sources, such as policy. The value of a default
+ // content setting applied by a higher precedence provider is not consulted
+ // here. For managed policies, the state will be reflected directly in the
+ // privacy sandbox preference. Other providers (such as extensions) will have
+ // been considered for the initial value of the privacy sandbox preference.
+ for (const auto& setting : cookie_settings) {
+ if (setting.primary_pattern == ContentSettingsPattern::Wildcard() &&
+ setting.secondary_pattern == ContentSettingsPattern::Wildcard()) {
+ return false;
+ }
+ if (setting.primary_pattern.Matches(url) &&
+ setting.secondary_pattern.Matches(top_frame_origin)) {
+ return setting.GetContentSetting() ==
+ ContentSetting::CONTENT_SETTING_BLOCK;
+ }
+ }
+ // ContentSettingsForOneType should always end with a default content setting
+ // from the default provider.
+ NOTREACHED();
+ return false;
+}
+
+// Convert a stored FLEDGE block eTLD+1 into applicable content settings
+// patterns. This ensures that if Public Suffix List membership changes, the
+// stored item continues to match as when it was set. Multiple patterns are set
+// to support IP address fallbacks, which do not support [*.] prefixes.
+// TODO (crbug.com/1287153): This is somewhat hacky and can be removed when
+// FLEDGE is controlled by a content setting directly.
+std::vector<ContentSettingsPattern> FledgeBlockToContentSettingsPatterns(
+ const std::string& entry) {
+ return {ContentSettingsPattern::FromString("[*.]" + entry),
+ ContentSettingsPattern::FromString(entry)};
+}
+
+} // namespace
+
+PrivacySandboxSettings::PrivacySandboxSettings(
+ HostContentSettingsMap* host_content_settings_map,
+ scoped_refptr<content_settings::CookieSettings> cookie_settings,
+ PrefService* pref_service,
+ bool incognito_profile)
+ : host_content_settings_map_(host_content_settings_map),
+ cookie_settings_(cookie_settings),
+ pref_service_(pref_service),
+ incognito_profile_(incognito_profile) {
+ DCHECK(pref_service_);
+ DCHECK(host_content_settings_map_);
+ DCHECK(cookie_settings_);
+ // "Clear on exit" causes a cookie deletion on shutdown. But for practical
+ // purposes, we're notifying the observers on startup (which should be
+ // equivalent, as no cookie operations could have happened while the profile
+ // was shut down).
+ if (IsCookiesClearOnExitEnabled(host_content_settings_map_))
+ OnCookiesCleared();
+
+ pref_change_registrar_.Init(pref_service_);
+ pref_change_registrar_.Add(
+ prefs::kPrivacySandboxApisEnabledV2,
+ base::BindRepeating(&PrivacySandboxSettings::OnPrivacySandboxPrefChanged,
+ base::Unretained(this)));
+}
+
+PrivacySandboxSettings::~PrivacySandboxSettings() = default;
+
+bool PrivacySandboxSettings::IsFlocAllowed() const {
+ return pref_service_->GetBoolean(prefs::kPrivacySandboxFlocEnabled) &&
+ IsPrivacySandboxEnabled();
+}
+
+bool PrivacySandboxSettings::IsFlocAllowedForContext(
+ const GURL& url,
+ const absl::optional<url::Origin>& top_frame_origin) const {
+ // If FLoC is disabled completely, it is not available in any context.
+ if (!IsFlocAllowed())
+ return false;
+
+ ContentSettingsForOneType cookie_settings;
+ cookie_settings_->GetCookieSettings(&cookie_settings);
+
+ return IsPrivacySandboxEnabledForContext(url, top_frame_origin,
+ cookie_settings);
+}
+
+base::Time PrivacySandboxSettings::FlocDataAccessibleSince() const {
+ return pref_service_->GetTime(prefs::kPrivacySandboxFlocDataAccessibleSince);
+}
+
+void PrivacySandboxSettings::SetFlocDataAccessibleFromNow(
+ bool reset_calculate_timer) const {
+ pref_service_->SetTime(prefs::kPrivacySandboxFlocDataAccessibleSince,
+ base::Time::Now());
+
+ for (auto& observer : observers_)
+ observer.OnFlocDataAccessibleSinceUpdated(reset_calculate_timer);
+}
+
+bool PrivacySandboxSettings::IsConversionMeasurementAllowed(
+ const url::Origin& top_frame_origin,
+ const url::Origin& reporting_origin) const {
+ ContentSettingsForOneType cookie_settings;
+ cookie_settings_->GetCookieSettings(&cookie_settings);
+
+ return IsPrivacySandboxEnabledForContext(reporting_origin.GetURL(),
+ top_frame_origin, cookie_settings);
+}
+
+bool PrivacySandboxSettings::ShouldSendConversionReport(
+ const url::Origin& impression_origin,
+ const url::Origin& conversion_origin,
+ const url::Origin& reporting_origin) const {
+ // Re-using the |cookie_settings| allows this function to be faster
+ // than simply calling IsConversionMeasurementAllowed() twice
+ ContentSettingsForOneType cookie_settings;
+ cookie_settings_->GetCookieSettings(&cookie_settings);
+
+ // The |reporting_origin| needs to have been accessible in both impression
+ // and conversion contexts. These are both checked when they occur, but
+ // user settings may have changed between then and when the conversion report
+ // is sent.
+ return IsPrivacySandboxEnabledForContext(
+ reporting_origin.GetURL(), impression_origin, cookie_settings) &&
+ IsPrivacySandboxEnabledForContext(reporting_origin.GetURL(),
+ conversion_origin, cookie_settings);
+}
+
+void PrivacySandboxSettings::SetFledgeJoiningAllowed(
+ const std::string& top_frame_etld_plus1,
+ bool allowed) {
+ DictionaryPrefUpdate scoped_pref_update(
+ pref_service_, prefs::kPrivacySandboxFledgeJoinBlocked);
+ auto* pref_data = scoped_pref_update.Get();
+ DCHECK(pref_data);
+ DCHECK(pref_data->is_dict());
+
+ // Ensure that the provided etld_plus1 actually is an etld+1.
+ auto effective_top_frame_etld_plus1 =
+ net::registry_controlled_domains::GetDomainAndRegistry(
+ top_frame_etld_plus1,
+ net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
+
+ // Hosts are also accepted as a fallback. This may occur if the private
+ // registry has changed, and what the caller may be assuming is an eTLD+1 no
+ // longer is. Simply ignoring non-eTLD+1's may thus result in unexpected
+ // access.
+ if (effective_top_frame_etld_plus1 != top_frame_etld_plus1) {
+ // Add a dummy scheme and use GURL to confirm the provided string is a valid
+ // host.
+ const GURL url("https://" + top_frame_etld_plus1);
+ effective_top_frame_etld_plus1 = url.host();
+ }
+
+ // Ignore attempts to configure an empty etld+1. This will also catch the
+ // case where the eTLD+1 was not even a host, as GURL will have canonicalised
+ // it to empty.
+ if (effective_top_frame_etld_plus1.length() == 0) {
+ NOTREACHED() << "Cannot control FLEDGE joining for empty eTLD+1";
+ return;
+ }
+
+ if (allowed) {
+ // Existence of the key implies blocking, so simply removing the key is
+ // sufficient. If the key wasn't already present, the following is a no-op.
+ pref_data->RemoveKey(effective_top_frame_etld_plus1);
+ } else {
+ // Overriding the creation date for keys which already exist is acceptable.
+ // Time range based deletions are typically started from the current time,
+ // and so this will be more aggressively removed. This decreases the chance
+ // a potentially sensitive website remains in preferences.
+ pref_data->SetKey(effective_top_frame_etld_plus1,
+ base::TimeToValue(base::Time::Now()));
+ }
+}
+
+void PrivacySandboxSettings::ClearFledgeJoiningAllowedSettings(
+ base::Time start_time,
+ base::Time end_time) {
+ DictionaryPrefUpdate scoped_pref_update(
+ pref_service_, prefs::kPrivacySandboxFledgeJoinBlocked);
+ auto* pref_data = scoped_pref_update.Get();
+ DCHECK(pref_data);
+ DCHECK(pref_data->is_dict());
+
+ // Shortcut for maximum time range deletion
+ if (start_time == base::Time() && end_time == base::Time::Max()) {
+ pref_data->DictClear();
+ return;
+ }
+
+ std::vector<std::string> keys_to_remove;
+ for (auto entry : pref_data->DictItems()) {
+ absl::optional<base::Time> created_time = base::ValueToTime(entry.second);
+ if (created_time.has_value() && start_time <= created_time &&
+ created_time <= end_time) {
+ keys_to_remove.push_back(entry.first);
+ }
+ }
+
+ for (const auto& key : keys_to_remove)
+ pref_data->RemoveKey(key);
+}
+
+bool PrivacySandboxSettings::IsFledgeJoiningAllowed(
+ const url::Origin& top_frame_origin) const {
+ DictionaryPrefUpdate scoped_pref_update(
+ pref_service_, prefs::kPrivacySandboxFledgeJoinBlocked);
+ auto* pref_data = scoped_pref_update.Get();
+ DCHECK(pref_data);
+ DCHECK(pref_data->is_dict());
+ for (auto entry : pref_data->DictItems()) {
+ if (base::ranges::any_of(FledgeBlockToContentSettingsPatterns(entry.first),
+ [&](const auto& pattern) {
+ return pattern.Matches(
+ top_frame_origin.GetURL());
+ })) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool PrivacySandboxSettings::IsFledgeAllowed(
+ const url::Origin& top_frame_origin,
+ const url::Origin& auction_party) {
+ // If the sandbox is disabled, then FLEDGE is never allowed.
+ if (!IsPrivacySandboxEnabled())
+ return false;
+
+ // Third party cookies must also be available for this context. An empty site
+ // for cookies is provided so the context is always treated as a third party.
+ return cookie_settings_->IsFullCookieAccessAllowed(
+ auction_party.GetURL(), net::SiteForCookies(), top_frame_origin);
+}
+
+std::vector<GURL> PrivacySandboxSettings::FilterFledgeAllowedParties(
+ const url::Origin& top_frame_origin,
+ const std::vector<GURL>& auction_parties) {
+ // If the sandbox is disabled, then no parties are allowed.
+ if (!IsPrivacySandboxEnabled())
+ return {};
+
+ std::vector<GURL> allowed_parties;
+ for (const auto& party : auction_parties) {
+ if (cookie_settings_->IsFullCookieAccessAllowed(
+ party, net::SiteForCookies(), top_frame_origin)) {
+ allowed_parties.push_back(party);
+ }
+ }
+ return allowed_parties;
+}
+
+bool PrivacySandboxSettings::IsPrivacySandboxEnabled() const {
+ // Which preference is consulted is dependent on whether release 3 of the
+ // settings is available.
+ if (base::FeatureList::IsEnabled(privacy_sandbox::kPrivacySandboxSettings3)) {
+ // For Privacy Sandbox Settings 3, APIs are disabled in incognito.
+ if (incognito_profile_)
+ return false;
+
+ // The V2 pref was introduced with the 3rd Privacy Sandbox release.
+ return pref_service_->GetBoolean(prefs::kPrivacySandboxApisEnabledV2);
+ }
+
+ return pref_service_->GetBoolean(prefs::kPrivacySandboxApisEnabled);
+}
+
+void PrivacySandboxSettings::SetPrivacySandboxEnabled(bool enabled) {
+ pref_service_->SetBoolean(prefs::kPrivacySandboxManuallyControlled, true);
+
+ // Only apply the decision to the appropriate preference. Confirmation logic
+ // DCHECKS that the user has not been able to enable the V2 preference
+ // without seeing a dialog.
+ if (base::FeatureList::IsEnabled(privacy_sandbox::kPrivacySandboxSettings3)) {
+ pref_service_->SetBoolean(prefs::kPrivacySandboxApisEnabledV2, enabled);
+ } else {
+ pref_service_->SetBoolean(prefs::kPrivacySandboxApisEnabled, enabled);
+ }
+}
+
+bool PrivacySandboxSettings::IsTrustTokensAllowed() {
+ // The PrivacySandboxSettings is only involved in Trust Token access
+ // decisions when the Release 3 flag is enabled.
+ if (!base::FeatureList::IsEnabled(privacy_sandbox::kPrivacySandboxSettings3))
+ return true;
+
+ return IsPrivacySandboxEnabled();
+}
+
+void PrivacySandboxSettings::OnCookiesCleared() {
+ SetFlocDataAccessibleFromNow(/*reset_calculate_timer=*/false);
+}
+
+void PrivacySandboxSettings::OnPrivacySandboxPrefChanged() {
+ // The PrivacySandboxSettings is only involved in Trust Token access
+ // decisions when the Release 3 flag is enabled.
+ if (!base::FeatureList::IsEnabled(privacy_sandbox::kPrivacySandboxSettings3))
+ return;
+
+ for (auto& observer : observers_)
+ observer.OnTrustTokenBlockingChanged(!IsTrustTokensAllowed());
+}
+
+void PrivacySandboxSettings::AddObserver(Observer* observer) {
+ observers_.AddObserver(observer);
+}
+
+void PrivacySandboxSettings::RemoveObserver(Observer* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+bool PrivacySandboxSettings::IsPrivacySandboxEnabledForContext(
+ const GURL& url,
+ const absl::optional<url::Origin>& top_frame_origin,
+ const ContentSettingsForOneType& cookie_settings) const {
+ if (!IsPrivacySandboxEnabled())
+ return false;
+
+ // TODO (crbug.com/1155504): Bypassing the CookieSettings class to access
+ // content settings directly ignores allowlisted schemes and the storage
+ // access API. These should be taken into account here.
+ return !HasNonDefaultBlockSetting(
+ cookie_settings, url,
+ top_frame_origin ? top_frame_origin->GetURL() : GURL());
+}
diff --git a/chromium/components/privacy_sandbox/privacy_sandbox_settings.h b/chromium/components/privacy_sandbox/privacy_sandbox_settings.h
new file mode 100644
index 00000000000..deb99522802
--- /dev/null
+++ b/chromium/components/privacy_sandbox/privacy_sandbox_settings.h
@@ -0,0 +1,169 @@
+// Copyright 2020 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.
+
+#ifndef COMPONENTS_PRIVACY_SANDBOX_PRIVACY_SANDBOX_SETTINGS_H_
+#define COMPONENTS_PRIVACY_SANDBOX_PRIVACY_SANDBOX_SETTINGS_H_
+
+#include "base/gtest_prod_util.h"
+#include "base/memory/raw_ptr.h"
+#include "base/observer_list.h"
+#include "base/time/time.h"
+#include "components/content_settings/core/common/content_settings.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "components/prefs/pref_change_registrar.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+class HostContentSettingsMap;
+class PrefService;
+
+namespace content_settings {
+class CookieSettings;
+}
+
+namespace url {
+class Origin;
+}
+
+// A service which acts as a intermediary between Privacy Sandbox APIs and the
+// preferences and content settings which define when they are allowed to be
+// accessed. Privacy Sandbox APIs, regardless of where they live (renderer,
+// browser, network etc), must consult this service to determine when
+// they are allowed to run. While a basic on/off control is provided by this
+// service, embedders are expected to achieve fine-grained control though
+// the underlying preferences and content settings separately.
+class PrivacySandboxSettings : public KeyedService {
+ public:
+ class Observer {
+ public:
+ virtual void OnFlocDataAccessibleSinceUpdated(bool reset_compute_timer) {}
+
+ virtual void OnTrustTokenBlockingChanged(bool blocked) {}
+ };
+
+ PrivacySandboxSettings(
+ HostContentSettingsMap* host_content_settings_map,
+ scoped_refptr<content_settings::CookieSettings> cookie_settings,
+ PrefService* pref_service,
+ bool incognito_profile);
+ ~PrivacySandboxSettings() override;
+
+ // Returns whether FLoC is allowed at all. If false, FLoC calculations should
+ // not occur. If true, the more specific function, IsFlocAllowedForContext(),
+ // should be consulted for the relevant context.
+ bool IsFlocAllowed() const;
+
+ // Determines whether FLoC is allowable in a particular context.
+ // |top_frame_origin| is used to check for content settings which could both
+ // affect 1P and 3P contexts.
+ bool IsFlocAllowedForContext(
+ const GURL& url,
+ const absl::optional<url::Origin>& top_frame_origin) const;
+
+ // Returns the point in time from which history is eligible to be used when
+ // calculating a user's FLoC ID. Reset when a user clears all cookies, or
+ // when the browser restarts with "Clear on exit" enabled. The returned time
+ // will have been fuzzed for local privacy, and so may be in the future, in
+ // which case no history is eligible.
+ base::Time FlocDataAccessibleSince() const;
+
+ // Sets the time when history is accessible for FLoC calculation to the
+ // current time, optionally resetting the time to the next FLoC id calculation
+ // if |reset_calculate_timer| is true.
+ void SetFlocDataAccessibleFromNow(bool reset_calculate_timer) const;
+
+ // Determines whether Conversion Measurement is allowable in a particular
+ // context. Should be called at both impression & conversion. At each of these
+ // points |top_frame_origin| is the same as either the impression origin or
+ // the conversion origin respectively.
+ bool IsConversionMeasurementAllowed(
+ const url::Origin& top_frame_origin,
+ const url::Origin& reporting_origin) const;
+
+ // Called before sending the associated conversion report to
+ // |reporting_origin|. Re-checks that |reporting_origin| is allowable as a 3P
+ // on both |impression_origin| and |conversion_origin|.
+ bool ShouldSendConversionReport(const url::Origin& impression_origin,
+ const url::Origin& conversion_origin,
+ const url::Origin& reporting_origin) const;
+
+ // Sets the ability for |top_frame_etld_plus1| to join the profile to interest
+ // groups to |allowed|. This information is stored in preferences, and is made
+ // available to the API via IsFledgeJoiningAllowed(). |top_frame_etld_plus1|
+ // should in most circumstances be a valid eTLD+1, but hosts are accepted to
+ // allow for shifts in private registries. Entries are converted into wildcard
+ // subdomain ContentSettingsPattern before comparison.
+ void SetFledgeJoiningAllowed(const std::string& top_frame_etld_plus1,
+ bool allowed);
+
+ // Clears any FLEDGE joining block settings with creation times between
+ // |start_time| and |end_time|.
+ void ClearFledgeJoiningAllowedSettings(base::Time start_time,
+ base::Time end_time);
+
+ // Determines whether the user may be joined to FLEDGE interest groups on, or
+ // by, |top_frame_origin|. This is an additional check that must be
+ // combined with the more generic IsFledgeAllowed().
+ bool IsFledgeJoiningAllowed(const url::Origin& top_frame_origin) const;
+
+ // Determine whether |auction_party| can register an interest group, or sell /
+ // buy in an auction, on |top_frame_origin|.
+ bool IsFledgeAllowed(const url::Origin& top_frame_origin,
+ const url::Origin& auction_party);
+
+ // Filter |auction_parties| down to those that may participate as a buyer for
+ // auctions run on |top_frame_origin|. Logically equivalent to calling
+ // IsFledgeAllowed() for each element of |auction_parties|.
+ std::vector<GURL> FilterFledgeAllowedParties(
+ const url::Origin& top_frame_origin,
+ const std::vector<GURL>& auction_parties);
+
+ // Returns whether the Privacy Sandbox is "generally" available. A return
+ // value of false indicates that the sandbox is completely disabled. A return
+ // value of true *must* be followed up by the appropriate context specific
+ // check.
+ bool IsPrivacySandboxEnabled() const;
+
+ // Disables the Privacy Sandbox completely if |enabled| is false, if |enabled|
+ // is true, more granular checks will still be performed to determine if
+ // specific APIs are available in specific contexts.
+ void SetPrivacySandboxEnabled(bool enabled);
+
+ // Returns whether Trust Tokens are "generally" available. A return value of
+ // false is authoritative, while a value of true must be followed by the
+ // appropriate context specific check.
+ bool IsTrustTokensAllowed();
+
+ // Called when there's a broad cookies clearing action. For example, this
+ // should be called on "Clear browsing data", but shouldn't be called on the
+ // Clear-Site-Data header, as it's restricted to a specific site.
+ void OnCookiesCleared();
+
+ // Called when the main privacy sandbox preference is changed.
+ void OnPrivacySandboxPrefChanged();
+
+ void AddObserver(Observer* observer);
+ void RemoveObserver(Observer* observer);
+
+ protected:
+ // Determines based on the current features, preferences and provided
+ // |cookie_settings| whether Privacy Sandbox APIs are generally allowable for
+ // |url| on |top_frame_origin|. Individual APIs may perform additional checks
+ // for allowability (such as incognito) ontop of this. |cookie_settings| is
+ // provided as a parameter to allow callers to cache it between calls.
+ bool IsPrivacySandboxEnabledForContext(
+ const GURL& url,
+ const absl::optional<url::Origin>& top_frame_origin,
+ const ContentSettingsForOneType& cookie_settings) const;
+
+ private:
+ base::ObserverList<Observer>::Unchecked observers_;
+
+ raw_ptr<HostContentSettingsMap> host_content_settings_map_;
+ scoped_refptr<content_settings::CookieSettings> cookie_settings_;
+ raw_ptr<PrefService> pref_service_;
+ PrefChangeRegistrar pref_change_registrar_;
+ bool incognito_profile_;
+};
+
+#endif // COMPONENTS_PRIVACY_SANDBOX_PRIVACY_SANDBOX_SETTINGS_H_
diff --git a/chromium/components/privacy_sandbox/privacy_sandbox_settings_unittest.cc b/chromium/components/privacy_sandbox/privacy_sandbox_settings_unittest.cc
new file mode 100644
index 00000000000..9d976177859
--- /dev/null
+++ b/chromium/components/privacy_sandbox/privacy_sandbox_settings_unittest.cc
@@ -0,0 +1,783 @@
+// Copyright 2020 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.
+
+#include "components/privacy_sandbox/privacy_sandbox_settings.h"
+
+#include "base/json/values_util.h"
+#include "base/test/gtest_util.h"
+#include "base/test/scoped_feature_list.h"
+#include "components/content_settings/core/browser/cookie_settings.h"
+#include "components/content_settings/core/browser/host_content_settings_map.h"
+#include "components/content_settings/core/common/pref_names.h"
+#include "components/content_settings/core/test/content_settings_mock_provider.h"
+#include "components/content_settings/core/test/content_settings_test_utils.h"
+#include "components/privacy_sandbox/privacy_sandbox_features.h"
+#include "components/privacy_sandbox/privacy_sandbox_prefs.h"
+#include "components/privacy_sandbox/privacy_sandbox_test_util.h"
+#include "components/sync_preferences/testing_pref_service_syncable.h"
+#include "content/public/test/browser_task_environment.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/origin.h"
+
+class PrivacySandboxSettingsTest : public testing::TestWithParam<bool> {
+ public:
+ PrivacySandboxSettingsTest()
+ : browser_task_environment_(
+ base::test::TaskEnvironment::TimeSource::MOCK_TIME) {
+ content_settings::CookieSettings::RegisterProfilePrefs(prefs()->registry());
+ HostContentSettingsMap::RegisterProfilePrefs(prefs()->registry());
+ privacy_sandbox::RegisterProfilePrefs(prefs()->registry());
+
+ host_content_settings_map_ = new HostContentSettingsMap(
+ &prefs_, false /* is_off_the_record */, false /* store_last_modified */,
+ false /* restore_session */);
+ cookie_settings_ = new content_settings::CookieSettings(
+ host_content_settings_map_.get(), &prefs_, false, "chrome-extension");
+ }
+ ~PrivacySandboxSettingsTest() override {
+ host_content_settings_map()->ShutdownOnUIThread();
+ }
+
+ void SetUp() override {
+ InitializePrefsBeforeStart();
+ InitializeFeaturesBeforeStart();
+
+ privacy_sandbox_settings_ = std::make_unique<PrivacySandboxSettings>(
+ host_content_settings_map(), cookie_settings_, prefs(),
+ IsIncognitoProfile());
+ }
+
+ virtual void InitializePrefsBeforeStart() {}
+
+ virtual void InitializeFeaturesBeforeStart() {
+ if (GetParam()) {
+ feature_list_.InitAndEnableFeature(
+ privacy_sandbox::kPrivacySandboxSettings3);
+ } else {
+ feature_list_.InitAndDisableFeature(
+ privacy_sandbox::kPrivacySandboxSettings3);
+ }
+ }
+
+ virtual bool IsIncognitoProfile() { return false; }
+
+ sync_preferences::TestingPrefServiceSyncable* prefs() { return &prefs_; }
+ HostContentSettingsMap* host_content_settings_map() {
+ return host_content_settings_map_.get();
+ }
+ content_settings::CookieSettings* cookie_settings() {
+ return cookie_settings_.get();
+ }
+
+ PrivacySandboxSettings* privacy_sandbox_settings() {
+ return privacy_sandbox_settings_.get();
+ }
+
+ content::BrowserTaskEnvironment* task_environment() {
+ return &browser_task_environment_;
+ }
+
+ private:
+ content::BrowserTaskEnvironment browser_task_environment_;
+ base::test::ScopedFeatureList feature_list_;
+ sync_preferences::TestingPrefServiceSyncable prefs_;
+ scoped_refptr<HostContentSettingsMap> host_content_settings_map_;
+ scoped_refptr<content_settings::CookieSettings> cookie_settings_;
+
+ std::unique_ptr<PrivacySandboxSettings> privacy_sandbox_settings_;
+};
+
+TEST_P(PrivacySandboxSettingsTest, PreferenceOverridesDefaultContentSetting) {
+ // When the Privacy Sandbox UI is available, the sandbox preference should
+ // override the default cookie content setting.
+ privacy_sandbox_test_util::SetupTestState(
+ prefs(), host_content_settings_map(),
+ /*privacy_sandbox_enabled=*/true,
+ /*block_third_party_cookies=*/false,
+ /*default_cookie_setting=*/ContentSetting::CONTENT_SETTING_BLOCK,
+ /*user_cookie_exceptions=*/{},
+ /*managed_cookie_setting=*/privacy_sandbox_test_util::kNoSetting,
+ /*managed_cookie_exceptions=*/{});
+
+ EXPECT_TRUE(privacy_sandbox_settings()->IsFlocAllowedForContext(
+ GURL("https://embedded.com"),
+ url::Origin::Create(GURL("https://test.com"))));
+
+ EXPECT_TRUE(privacy_sandbox_settings()->IsConversionMeasurementAllowed(
+ url::Origin::Create(GURL("https://test.com")),
+ url::Origin::Create(GURL("https://embedded.com"))));
+ EXPECT_TRUE(privacy_sandbox_settings()->ShouldSendConversionReport(
+ url::Origin::Create(GURL("https://test.com")),
+ url::Origin::Create(GURL("https://another-test.com")),
+ url::Origin::Create(GURL("https://embedded.com"))));
+
+ EXPECT_FALSE(privacy_sandbox_settings()->IsFledgeAllowed(
+ url::Origin::Create(GURL("https://test.com")),
+ url::Origin::Create(GURL("https://embedded.com"))));
+ EXPECT_EQ(std::vector<GURL>{},
+ privacy_sandbox_settings()->FilterFledgeAllowedParties(
+ url::Origin::Create(GURL("https://test.com")),
+ {GURL("https://embedded.com"),
+ GURL("https://another-embedded.com")}));
+
+ // An allow exception should not override the preference value.
+ privacy_sandbox_test_util::SetupTestState(
+ prefs(), host_content_settings_map(),
+ /*privacy_sandbox_enabled=*/false,
+ /*block_third_party_cookies=*/false,
+ /*default_cookie_setting=*/ContentSetting::CONTENT_SETTING_ALLOW,
+ /*user_cookie_exceptions=*/
+ {{"https://embedded.com", "https://test.com",
+ ContentSetting::CONTENT_SETTING_ALLOW},
+ {"https://another-embedded.com", "https://test.com",
+ ContentSetting::CONTENT_SETTING_ALLOW},
+ {"https://embedded.com", "https://another-test.com",
+ ContentSetting::CONTENT_SETTING_ALLOW}},
+ /*managed_cookie_setting=*/privacy_sandbox_test_util::kNoSetting,
+ /*managed_cookie_exceptions=*/{});
+
+ EXPECT_FALSE(privacy_sandbox_settings()->IsFlocAllowedForContext(
+ GURL("https://embedded.com"),
+ url::Origin::Create(GURL("https://test.com"))));
+
+ EXPECT_FALSE(privacy_sandbox_settings()->IsConversionMeasurementAllowed(
+ url::Origin::Create(GURL("https://test.com")),
+ url::Origin::Create(GURL("https://embedded.com"))));
+ EXPECT_FALSE(privacy_sandbox_settings()->ShouldSendConversionReport(
+ url::Origin::Create(GURL("https://test.com")),
+ url::Origin::Create(GURL("https://another-test.com")),
+ url::Origin::Create(GURL("https://embedded.com"))));
+
+ EXPECT_FALSE(privacy_sandbox_settings()->IsFledgeAllowed(
+ url::Origin::Create(GURL("https://test.com")),
+ url::Origin::Create(GURL("https://embedded.com"))));
+ EXPECT_EQ(std::vector<GURL>{},
+ privacy_sandbox_settings()->FilterFledgeAllowedParties(
+ url::Origin::Create(GURL("https://test.com")),
+ {GURL("https://embedded.com"),
+ GURL("https://another-embedded.com")}));
+}
+
+TEST_P(PrivacySandboxSettingsTest, CookieBlockExceptionsApply) {
+ // When the Privacy Sandbox preference is enabled, targeted cookie block
+ // exceptions should still apply.
+ privacy_sandbox_test_util::SetupTestState(
+ prefs(), host_content_settings_map(),
+ /*privacy_sandbox_enabled=*/true,
+ /*block_third_party_cookies=*/false,
+ /*default_cookie_setting=*/ContentSetting::CONTENT_SETTING_ALLOW,
+ /*user_cookie_exceptions=*/
+ {{"https://embedded.com", "https://test.com",
+ ContentSetting::CONTENT_SETTING_BLOCK},
+ {"https://another-embedded.com", "*",
+ ContentSetting::CONTENT_SETTING_BLOCK}},
+ /*managed_cookie_setting=*/privacy_sandbox_test_util::kNoSetting,
+ /*managed_cookie_exceptions=*/{});
+
+ EXPECT_FALSE(privacy_sandbox_settings()->IsFlocAllowedForContext(
+ GURL("https://embedded.com"),
+ url::Origin::Create(GURL("https://test.com"))));
+
+ EXPECT_FALSE(privacy_sandbox_settings()->IsConversionMeasurementAllowed(
+ url::Origin::Create(GURL("https://test.com")),
+ url::Origin::Create(GURL("https://embedded.com"))));
+ EXPECT_FALSE(privacy_sandbox_settings()->ShouldSendConversionReport(
+ url::Origin::Create(GURL("https://test.com")),
+ url::Origin::Create(GURL("https://another-test.com")),
+ url::Origin::Create(GURL("https://embedded.com"))));
+
+ EXPECT_FALSE(privacy_sandbox_settings()->IsFledgeAllowed(
+ url::Origin::Create(GURL("https://test.com")),
+ url::Origin::Create(GURL("https://embedded.com"))));
+ EXPECT_EQ(std::vector<GURL>{},
+ privacy_sandbox_settings()->FilterFledgeAllowedParties(
+ url::Origin::Create(GURL("https://test.com")),
+ {GURL("https://embedded.com"),
+ GURL("https://another-embedded.com")}));
+
+ // User created exceptions should not apply if a managed default coookie
+ // setting exists. What the managed default setting actually is should *not*
+ // affect whether APIs are enabled. The cookie managed state is reflected in
+ // the privacy sandbox preferences directly.
+ privacy_sandbox_test_util::SetupTestState(
+ prefs(), host_content_settings_map(),
+ /*privacy_sandbox_enabled=*/true,
+ /*block_third_party_cookies=*/false,
+ /*default_cookie_setting=*/ContentSetting::CONTENT_SETTING_ALLOW,
+ /*user_cookie_exceptions=*/
+ {{"https://embedded.com", "https://test.com",
+ ContentSetting::CONTENT_SETTING_BLOCK},
+ {"https://another-embedded.com", "https://test.com",
+ ContentSetting::CONTENT_SETTING_BLOCK},
+ {"https://embedded.com", "https://another-test.com",
+ ContentSetting::CONTENT_SETTING_BLOCK}},
+ /*managed_cookie_setting=*/ContentSetting::CONTENT_SETTING_BLOCK,
+ /*managed_cookie_exceptions=*/{});
+
+ EXPECT_TRUE(privacy_sandbox_settings()->IsFlocAllowedForContext(
+ GURL("https://embedded.com"),
+ url::Origin::Create(GURL("https://test.com"))));
+ EXPECT_TRUE(privacy_sandbox_settings()->IsConversionMeasurementAllowed(
+ url::Origin::Create(GURL("https://test.com")),
+ url::Origin::Create(GURL("https://embedded.com"))));
+ EXPECT_TRUE(privacy_sandbox_settings()->ShouldSendConversionReport(
+ url::Origin::Create(GURL("https://test.com")),
+ url::Origin::Create(GURL("https://another-test.com")),
+ url::Origin::Create(GURL("https://embedded.com"))));
+
+ EXPECT_FALSE(privacy_sandbox_settings()->IsFledgeAllowed(
+ url::Origin::Create(GURL("https://test.com")),
+ url::Origin::Create(GURL("https://embedded.com"))));
+ EXPECT_EQ(std::vector<GURL>{},
+ privacy_sandbox_settings()->FilterFledgeAllowedParties(
+ url::Origin::Create(GURL("https://test.com")),
+ {GURL("https://embedded.com"),
+ GURL("https://another-embedded.com")}));
+
+ // Managed content setting exceptions should override both the privacy
+ // sandbox pref and any user settings.
+ privacy_sandbox_test_util::SetupTestState(
+ prefs(), host_content_settings_map(),
+ /*privacy_sandbox_enabled=*/true,
+ /*block_third_party_cookies=*/false,
+ /*default_cookie_setting=*/ContentSetting::CONTENT_SETTING_ALLOW,
+ /*user_cookie_exceptions=*/
+ {{"https://embedded.com", "https://test.com",
+ ContentSetting::CONTENT_SETTING_ALLOW},
+ {"https://another-embedded.com", "https://test.com",
+ ContentSetting::CONTENT_SETTING_ALLOW},
+ {"https://embedded.com", "https://another-test.com",
+ ContentSetting::CONTENT_SETTING_ALLOW}},
+ /*managed_cookie_setting=*/ContentSetting::CONTENT_SETTING_ALLOW,
+ {{"https://embedded.com", "https://test.com",
+ ContentSetting::CONTENT_SETTING_BLOCK}});
+
+ EXPECT_FALSE(privacy_sandbox_settings()->IsFlocAllowedForContext(
+ GURL("https://embedded.com"),
+ url::Origin::Create(GURL("https://test.com"))));
+ EXPECT_TRUE(privacy_sandbox_settings()->IsFlocAllowedForContext(
+ GURL("https://unrelated.com"),
+ url::Origin::Create(GURL("https://unrelated.com"))));
+
+ EXPECT_FALSE(privacy_sandbox_settings()->IsConversionMeasurementAllowed(
+ url::Origin::Create(GURL("https://test.com")),
+ url::Origin::Create(GURL("https://embedded.com"))));
+ EXPECT_FALSE(privacy_sandbox_settings()->ShouldSendConversionReport(
+ url::Origin::Create(GURL("https://test.com")),
+ url::Origin::Create(GURL("https://another-test.com")),
+ url::Origin::Create(GURL("https://embedded.com"))));
+ EXPECT_TRUE(privacy_sandbox_settings()->IsConversionMeasurementAllowed(
+ url::Origin::Create(GURL("https://unrelated-a.com")),
+ url::Origin::Create(GURL("https://unrelated-b.com"))));
+ EXPECT_TRUE(privacy_sandbox_settings()->ShouldSendConversionReport(
+ url::Origin::Create(GURL("https://unrelated-c.com")),
+ url::Origin::Create(GURL("https://unrelated-d.com")),
+ url::Origin::Create(GURL("https://unrelated-e.com"))));
+
+ EXPECT_FALSE(privacy_sandbox_settings()->IsFledgeAllowed(
+ url::Origin::Create(GURL("https://test.com")),
+ url::Origin::Create(GURL("https://embedded.com"))));
+ EXPECT_EQ(std::vector<GURL>{GURL("https://another-embedded.com")},
+ privacy_sandbox_settings()->FilterFledgeAllowedParties(
+ url::Origin::Create(GURL("https://test.com")),
+ {GURL("https://embedded.com"),
+ GURL("https://another-embedded.com")}));
+
+ // A less specific block exception should not override a more specific allow
+ // exception. The effective content setting in this scenario is still allow,
+ // even though a block exception exists.
+ privacy_sandbox_test_util::SetupTestState(
+ prefs(), host_content_settings_map(),
+ /*privacy_sandbox_enabled=*/true,
+ /*block_third_party_cookies=*/false,
+ /*default_cookie_setting=*/ContentSetting::CONTENT_SETTING_ALLOW,
+ /*user_cookie_exceptions=*/
+ {{"https://embedded.com", "https://test.com",
+ ContentSetting::CONTENT_SETTING_ALLOW},
+ {"https://embedded.com", "https://another-test.com",
+ ContentSetting::CONTENT_SETTING_ALLOW},
+ {"https://[*.]embedded.com", "https://[*.]test.com",
+ ContentSetting::CONTENT_SETTING_BLOCK},
+ {"https://[*.]embedded.com", "https://[*.]another-test.com",
+ ContentSetting::CONTENT_SETTING_BLOCK}},
+ /*managed_cookie_setting=*/privacy_sandbox_test_util::kNoSetting,
+ /*managed_cookie_exceptions=*/{});
+ EXPECT_TRUE(privacy_sandbox_settings()->IsFlocAllowedForContext(
+ GURL("https://embedded.com"),
+ url::Origin::Create(GURL("https://test.com"))));
+
+ EXPECT_TRUE(privacy_sandbox_settings()->IsFledgeAllowed(
+ url::Origin::Create(GURL("https://test.com")),
+ url::Origin::Create(GURL("https://embedded.com"))));
+
+ // Exceptions which specify a top frame origin should not match against other
+ // top frame origins, or an empty origin.
+ privacy_sandbox_test_util::SetupTestState(
+ prefs(), host_content_settings_map(),
+ /*privacy_sandbox_enabled=*/true,
+ /*block_third_party_cookies=*/false,
+ /*default_cookie_setting=*/ContentSetting::CONTENT_SETTING_BLOCK,
+ /*user_cookie_exceptions=*/
+ {{"https://embedded.com", "https://test.com",
+ ContentSetting::CONTENT_SETTING_BLOCK}},
+ /*managed_cookie_setting=*/privacy_sandbox_test_util::kNoSetting,
+ /*managed_cookie_exceptions=*/
+ {{"https://embedded.com", "https://test.com",
+ ContentSetting::CONTENT_SETTING_BLOCK}});
+
+ EXPECT_TRUE(privacy_sandbox_settings()->IsFlocAllowedForContext(
+ GURL("https://embedded.com"), absl::nullopt));
+
+ EXPECT_TRUE(privacy_sandbox_settings()->IsConversionMeasurementAllowed(
+ url::Origin::Create(GURL("https://another-test.com")),
+ url::Origin::Create(GURL("https://embedded.com"))));
+ EXPECT_TRUE(privacy_sandbox_settings()->ShouldSendConversionReport(
+ url::Origin::Create(GURL("https://another-test.com")),
+ url::Origin::Create(GURL("https://yet-another-test.com")),
+ url::Origin::Create(GURL("https://embedded.com"))));
+
+ EXPECT_FALSE(privacy_sandbox_settings()->IsFledgeAllowed(
+ url::Origin::Create(GURL("https://another-test.com")),
+ url::Origin::Create(GURL("https://embedded.com"))));
+ EXPECT_EQ(std::vector<GURL>{},
+ privacy_sandbox_settings()->FilterFledgeAllowedParties(
+ url::Origin::Create(GURL("https://test.com")),
+ {GURL("https://embedded.com"),
+ GURL("https://another-embedded.com")}));
+
+ // Exceptions which specify a wildcard top frame origin should match both
+ // empty top frames and non empty top frames.
+ privacy_sandbox_test_util::SetupTestState(
+ prefs(), host_content_settings_map(),
+ /*privacy_sandbox_enabled=*/true,
+ /*block_third_party_cookies=*/false,
+ /*default_cookie_setting=*/ContentSetting::CONTENT_SETTING_ALLOW,
+ /*user_cookie_exceptions=*/
+ {{"https://embedded.com", "*", ContentSetting::CONTENT_SETTING_BLOCK}},
+ /*managed_cookie_setting=*/privacy_sandbox_test_util::kNoSetting,
+ /*managed_cookie_exceptions=*/{});
+
+ EXPECT_FALSE(privacy_sandbox_settings()->IsFlocAllowedForContext(
+ GURL("https://embedded.com"), absl::nullopt));
+ EXPECT_FALSE(privacy_sandbox_settings()->IsFlocAllowedForContext(
+ GURL("https://embedded.com"),
+ url::Origin::Create(GURL("https://test.com"))));
+
+ EXPECT_FALSE(privacy_sandbox_settings()->IsConversionMeasurementAllowed(
+ url::Origin::Create(GURL("https://test.com")),
+ url::Origin::Create(GURL("https://embedded.com"))));
+ EXPECT_FALSE(privacy_sandbox_settings()->ShouldSendConversionReport(
+ url::Origin::Create(GURL("https://test.com")),
+ url::Origin::Create(GURL("https://another-test.com")),
+ url::Origin::Create(GURL("https://embedded.com"))));
+
+ EXPECT_FALSE(privacy_sandbox_settings()->IsFledgeAllowed(
+ url::Origin::Create(GURL("https://test.com")),
+ url::Origin::Create(GURL("https://embedded.com"))));
+ EXPECT_EQ(std::vector<GURL>{GURL("https://another-embedded.com")},
+ privacy_sandbox_settings()->FilterFledgeAllowedParties(
+ url::Origin::Create(GURL("https://test.com")),
+ {GURL("https://embedded.com"),
+ GURL("https://another-embedded.com")}));
+}
+
+TEST_P(PrivacySandboxSettingsTest, IsFledgeAllowed) {
+ // FLEDGE should be disabled if 3P cookies are blocked.
+ privacy_sandbox_test_util::SetupTestState(
+ prefs(), host_content_settings_map(),
+ /*privacy_sandbox_enabled=*/true,
+ /*block_third_party_cookies=*/true,
+ /*default_cookie_setting=*/ContentSetting::CONTENT_SETTING_ALLOW,
+ /*user_cookie_exceptions=*/{},
+ /*managed_cookie_setting=*/privacy_sandbox_test_util::kNoSetting,
+ /*managed_cookie_exceptions=*/{});
+
+ EXPECT_FALSE(privacy_sandbox_settings()->IsFledgeAllowed(
+ url::Origin::Create(GURL("https://test.com")),
+ url::Origin::Create(GURL("https://embedded.com"))));
+ EXPECT_EQ(std::vector<GURL>{},
+ privacy_sandbox_settings()->FilterFledgeAllowedParties(
+ url::Origin::Create(GURL("https://test.com")),
+ {GURL("https://embedded.com")}));
+
+ // FLEDGE should be disabled if all cookies are blocked.
+ privacy_sandbox_test_util::SetupTestState(
+ prefs(), host_content_settings_map(),
+ /*privacy_sandbox_enabled=*/true,
+ /*block_third_party_cookies=*/false,
+ /*default_cookie_setting=*/ContentSetting::CONTENT_SETTING_BLOCK,
+ /*user_cookie_exceptions=*/{},
+ /*managed_cookie_setting=*/privacy_sandbox_test_util::kNoSetting,
+ /*managed_cookie_exceptions=*/{});
+
+ EXPECT_FALSE(privacy_sandbox_settings()->IsFledgeAllowed(
+ url::Origin::Create(GURL("https://test.com")),
+ url::Origin::Create(GURL("https://embedded.com"))));
+ EXPECT_EQ(std::vector<GURL>{},
+ privacy_sandbox_settings()->FilterFledgeAllowedParties(
+ url::Origin::Create(GURL("https://test.com")),
+ {GURL("https://embedded.com")}));
+
+ // FLEDGE should be disabled if the privacy sandbox is disabled, regardless
+ // of other cookie settings.
+ privacy_sandbox_test_util::SetupTestState(
+ prefs(), host_content_settings_map(),
+ /*privacy_sandbox_enabled=*/false,
+ /*block_third_party_cookies=*/false,
+ /*default_cookie_setting=*/ContentSetting::CONTENT_SETTING_ALLOW,
+ /*user_cookie_exceptions=*/
+ {{"https://embedded.com", "https://test.com",
+ ContentSetting::CONTENT_SETTING_ALLOW}},
+ /*managed_cookie_setting=*/ContentSetting::CONTENT_SETTING_ALLOW,
+ /*managed_cookie_exceptions=*/
+ {{"https://embedded.com", "https://test.com",
+ ContentSetting::CONTENT_SETTING_ALLOW}});
+
+ EXPECT_FALSE(privacy_sandbox_settings()->IsFledgeAllowed(
+ url::Origin::Create(GURL("https://test.com")),
+ url::Origin::Create(GURL("https://embedded.com"))));
+ EXPECT_EQ(std::vector<GURL>{},
+ privacy_sandbox_settings()->FilterFledgeAllowedParties(
+ url::Origin::Create(GURL("https://test.com")),
+ {GURL("https://embedded.com")}));
+
+ // The managed cookie content setting should not override a disabled privacy
+ // sandbox setting.
+ privacy_sandbox_test_util::SetupTestState(
+ prefs(), host_content_settings_map(),
+ /*privacy_sandbox_enabled=*/false,
+ /*block_third_party_cookies=*/false,
+ /*default_cookie_setting=*/ContentSetting::CONTENT_SETTING_ALLOW,
+ /*user_cookie_exceptions=*/{},
+ /*managed_cookie_setting=*/ContentSetting::CONTENT_SETTING_ALLOW,
+ /*managed_cookie_exceptions=*/{});
+
+ EXPECT_FALSE(privacy_sandbox_settings()->IsFledgeAllowed(
+ url::Origin::Create(GURL("https://test.com")),
+ url::Origin::Create(GURL("https://embedded.com"))));
+ EXPECT_EQ(std::vector<GURL>{},
+ privacy_sandbox_settings()->FilterFledgeAllowedParties(
+ url::Origin::Create(GURL("https://test.com")),
+ {GURL("https://embedded.com")}));
+}
+
+TEST_P(PrivacySandboxSettingsTest, IsPrivacySandboxEnabled) {
+ privacy_sandbox_test_util::SetupTestState(
+ prefs(), host_content_settings_map(),
+ /*privacy_sandbox_enabled=*/false,
+ /*block_third_party_cookies=*/false,
+ /*default_cookie_setting=*/ContentSetting::CONTENT_SETTING_ALLOW,
+ /*user_cookie_exceptions=*/{},
+ /*managed_cookie_setting=*/privacy_sandbox_test_util::kNoSetting,
+ /*managed_cookie_exceptions=*/{});
+ EXPECT_FALSE(privacy_sandbox_settings()->IsPrivacySandboxEnabled());
+
+ privacy_sandbox_test_util::SetupTestState(
+ prefs(), host_content_settings_map(),
+ /*privacy_sandbox_enabled=*/false,
+ /*block_third_party_cookies=*/true,
+ /*default_cookie_setting=*/ContentSetting::CONTENT_SETTING_ALLOW,
+ /*user_cookie_exceptions=*/{},
+ /*managed_cookie_setting=*/privacy_sandbox_test_util::kNoSetting,
+ /*managed_cookie_exceptions=*/{});
+ EXPECT_FALSE(privacy_sandbox_settings()->IsPrivacySandboxEnabled());
+
+ privacy_sandbox_test_util::SetupTestState(
+ prefs(), host_content_settings_map(),
+ /*privacy_sandbox_enabled=*/true,
+ /*block_third_party_cookies=*/false,
+ /*default_cookie_setting=*/ContentSetting::CONTENT_SETTING_ALLOW,
+ /*user_cookie_exceptions=*/{},
+ /*managed_cookie_setting=*/privacy_sandbox_test_util::kNoSetting,
+ /*managed_cookie_exceptions=*/{});
+ EXPECT_TRUE(privacy_sandbox_settings()->IsPrivacySandboxEnabled());
+}
+
+TEST_P(PrivacySandboxSettingsTest, IsFlocAllowed) {
+ privacy_sandbox_test_util::SetupTestState(
+ prefs(), host_content_settings_map(),
+ /*privacy_sandbox_enabled=*/true,
+ /*block_third_party_cookies=*/true,
+ /*default_cookie_setting=*/ContentSetting::CONTENT_SETTING_BLOCK,
+ /*user_cookie_exceptions=*/{},
+ /*managed_cookie_setting=*/privacy_sandbox_test_util::kNoSetting,
+ /*managed_cookie_exceptions=*/{});
+ prefs()->SetBoolean(prefs::kPrivacySandboxFlocEnabled, true);
+ EXPECT_TRUE(privacy_sandbox_settings()->IsFlocAllowed());
+
+ privacy_sandbox_test_util::SetupTestState(
+ prefs(), host_content_settings_map(),
+ /*privacy_sandbox_enabled=*/false,
+ /*block_third_party_cookies=*/false,
+ /*default_cookie_setting=*/ContentSetting::CONTENT_SETTING_BLOCK,
+ /*user_cookie_exceptions=*/{},
+ /*managed_cookie_setting=*/privacy_sandbox_test_util::kNoSetting,
+ /*managed_cookie_exceptions=*/{});
+ prefs()->SetBoolean(prefs::kPrivacySandboxFlocEnabled, true);
+ EXPECT_FALSE(privacy_sandbox_settings()->IsFlocAllowed());
+
+ privacy_sandbox_test_util::SetupTestState(
+ prefs(), host_content_settings_map(),
+ /*privacy_sandbox_enabled=*/true,
+ /*block_third_party_cookies=*/false,
+ /*default_cookie_setting=*/ContentSetting::CONTENT_SETTING_ALLOW,
+ /*user_cookie_exceptions=*/{},
+ /*managed_cookie_setting=*/privacy_sandbox_test_util::kNoSetting,
+ /*managed_cookie_exceptions=*/{});
+ prefs()->SetBoolean(prefs::kPrivacySandboxFlocEnabled, false);
+ EXPECT_FALSE(privacy_sandbox_settings()->IsFlocAllowed());
+
+ privacy_sandbox_test_util::SetupTestState(
+ prefs(), host_content_settings_map(),
+ /*privacy_sandbox_enabled=*/false,
+ /*block_third_party_cookies=*/false,
+ /*default_cookie_setting=*/ContentSetting::CONTENT_SETTING_ALLOW,
+ /*user_cookie_exceptions=*/{},
+ /*managed_cookie_setting=*/privacy_sandbox_test_util::kNoSetting,
+ /*managed_cookie_exceptions=*/{});
+ prefs()->SetBoolean(prefs::kPrivacySandboxFlocEnabled, true);
+ EXPECT_FALSE(privacy_sandbox_settings()->IsFlocAllowed());
+}
+
+TEST_P(PrivacySandboxSettingsTest, FlocDataAccessibleSince) {
+ ASSERT_NE(base::Time(), base::Time::Now());
+
+ EXPECT_EQ(base::Time(),
+ privacy_sandbox_settings()->FlocDataAccessibleSince());
+
+ privacy_sandbox_settings()->OnCookiesCleared();
+
+ EXPECT_EQ(base::Time::Now(),
+ privacy_sandbox_settings()->FlocDataAccessibleSince());
+}
+
+TEST_P(PrivacySandboxSettingsTest, FledgeJoiningAllowed) {
+ // Whether or not a site can join a user to an interest group is independent
+ // of any other profile state.
+ privacy_sandbox_test_util::SetupTestState(
+ prefs(), host_content_settings_map(),
+ /*privacy_sandbox_enabled=*/false,
+ /*block_third_party_cookies=*/true,
+ /*default_cookie_setting=*/ContentSetting::CONTENT_SETTING_BLOCK,
+ /*user_cookie_exceptions=*/
+ {{"https://example.com", "*", ContentSetting::CONTENT_SETTING_BLOCK}},
+ /*managed_cookie_setting=*/ContentSetting::CONTENT_SETTING_BLOCK,
+ /*managed_cookie_exceptions=*/
+ {{"https://example.com", "*", ContentSetting::CONTENT_SETTING_BLOCK}});
+ EXPECT_TRUE(privacy_sandbox_settings()->IsFledgeJoiningAllowed(
+ url::Origin::Create(GURL("https://example.com"))));
+
+ // Settings should match at the eTLD + 1 level.
+ privacy_sandbox_settings()->SetFledgeJoiningAllowed("example.com", false);
+
+ EXPECT_FALSE(privacy_sandbox_settings()->IsFledgeJoiningAllowed(
+ url::Origin::Create(GURL("https://subsite.example.com"))));
+ EXPECT_FALSE(privacy_sandbox_settings()->IsFledgeJoiningAllowed(
+ url::Origin::Create(GURL("http://example.com"))));
+ EXPECT_FALSE(privacy_sandbox_settings()->IsFledgeJoiningAllowed(
+ url::Origin::Create(GURL("https://example.com:888"))));
+ EXPECT_FALSE(privacy_sandbox_settings()->IsFledgeJoiningAllowed(
+ url::Origin::Create(GURL("https://example.com"))));
+ EXPECT_TRUE(privacy_sandbox_settings()->IsFledgeJoiningAllowed(
+ url::Origin::Create(GURL("https://example.com.au"))));
+
+ privacy_sandbox_settings()->SetFledgeJoiningAllowed("example.com", true);
+
+ EXPECT_TRUE(privacy_sandbox_settings()->IsFledgeJoiningAllowed(
+ url::Origin::Create(GURL("https://example.com"))));
+ EXPECT_TRUE(privacy_sandbox_settings()->IsFledgeJoiningAllowed(
+ url::Origin::Create(GURL("https://subsite.example.com"))));
+ EXPECT_TRUE(privacy_sandbox_settings()->IsFledgeJoiningAllowed(
+ url::Origin::Create(GURL("http://example.com"))));
+ EXPECT_TRUE(privacy_sandbox_settings()->IsFledgeJoiningAllowed(
+ url::Origin::Create(GURL("https://example.com:888"))));
+ EXPECT_TRUE(privacy_sandbox_settings()->IsFledgeJoiningAllowed(
+ url::Origin::Create(GURL("https://example.com"))));
+ EXPECT_TRUE(privacy_sandbox_settings()->IsFledgeJoiningAllowed(
+ url::Origin::Create(GURL("https://example.com.au"))));
+}
+
+TEST_P(PrivacySandboxSettingsTest, NonEtldPlusOneBlocked) {
+ // Confirm that, as a fallback, hosts are accepted by SetFledgeJoiningAllowed.
+ privacy_sandbox_settings()->SetFledgeJoiningAllowed("subsite.example.com",
+ false);
+
+ // Applied setting should affect subdomaings.
+ EXPECT_FALSE(privacy_sandbox_settings()->IsFledgeJoiningAllowed(
+ url::Origin::Create(GURL("https://subsite.example.com"))));
+ EXPECT_FALSE(privacy_sandbox_settings()->IsFledgeJoiningAllowed(
+ url::Origin::Create(GURL("http://another.subsite.example.com"))));
+ EXPECT_TRUE(privacy_sandbox_settings()->IsFledgeJoiningAllowed(
+ url::Origin::Create(GURL("https://example.com"))));
+
+ // When removing the setting, only an exact match, and not the associated
+ // eTLD+1, should remove a setting.
+ privacy_sandbox_settings()->SetFledgeJoiningAllowed("example.com", true);
+ EXPECT_FALSE(privacy_sandbox_settings()->IsFledgeJoiningAllowed(
+ url::Origin::Create(GURL("https://subsite.example.com"))));
+ EXPECT_FALSE(privacy_sandbox_settings()->IsFledgeJoiningAllowed(
+ url::Origin::Create(GURL("http://another.subsite.example.com"))));
+ EXPECT_TRUE(privacy_sandbox_settings()->IsFledgeJoiningAllowed(
+ url::Origin::Create(GURL("https://example.com"))));
+
+ privacy_sandbox_settings()->SetFledgeJoiningAllowed("subsite.example.com",
+ true);
+ EXPECT_TRUE(privacy_sandbox_settings()->IsFledgeJoiningAllowed(
+ url::Origin::Create(GURL("https://subsite.example.com"))));
+ EXPECT_TRUE(privacy_sandbox_settings()->IsFledgeJoiningAllowed(
+ url::Origin::Create(GURL("http://another.subsite.example.com"))));
+ EXPECT_TRUE(privacy_sandbox_settings()->IsFledgeJoiningAllowed(
+ url::Origin::Create(GURL("https://example.com"))));
+
+ // IP addresses should also be accepted as a fallback.
+ privacy_sandbox_settings()->SetFledgeJoiningAllowed("10.1.1.100", false);
+ EXPECT_FALSE(privacy_sandbox_settings()->IsFledgeJoiningAllowed(
+ url::Origin::Create(GURL("https://10.1.1.100"))));
+ EXPECT_FALSE(privacy_sandbox_settings()->IsFledgeJoiningAllowed(
+ url::Origin::Create(GURL("http://10.1.1.100:8080"))));
+ EXPECT_TRUE(privacy_sandbox_settings()->IsFledgeJoiningAllowed(
+ url::Origin::Create(GURL("https://10.2.2.200"))));
+}
+
+TEST_P(PrivacySandboxSettingsTest, FledgeJoinSettingTimeRangeDeletion) {
+ // Confirm that time range deletions work appropriately for FLEDGE join
+ // settings.
+ privacy_sandbox_settings()->SetFledgeJoiningAllowed("first.com", false);
+ task_environment()->AdvanceClock(base::Hours(1));
+
+ const base::Time kSecondSettingTime = base::Time::Now();
+ privacy_sandbox_settings()->SetFledgeJoiningAllowed("second.com", false);
+
+ task_environment()->AdvanceClock(base::Hours(1));
+ privacy_sandbox_settings()->SetFledgeJoiningAllowed("third.com", false);
+
+ EXPECT_FALSE(privacy_sandbox_settings()->IsFledgeJoiningAllowed(
+ url::Origin::Create(GURL("https://first.com"))));
+ EXPECT_FALSE(privacy_sandbox_settings()->IsFledgeJoiningAllowed(
+ url::Origin::Create(GURL("https://second.com"))));
+ EXPECT_FALSE(privacy_sandbox_settings()->IsFledgeJoiningAllowed(
+ url::Origin::Create(GURL("https://third.com"))));
+
+ // Construct a deletion which only targets the second setting.
+ privacy_sandbox_settings()->ClearFledgeJoiningAllowedSettings(
+ kSecondSettingTime - base::Seconds(1),
+ kSecondSettingTime + base::Seconds(1));
+ EXPECT_FALSE(privacy_sandbox_settings()->IsFledgeJoiningAllowed(
+ url::Origin::Create(GURL("https://first.com"))));
+ EXPECT_TRUE(privacy_sandbox_settings()->IsFledgeJoiningAllowed(
+ url::Origin::Create(GURL("https://second.com"))));
+ EXPECT_FALSE(privacy_sandbox_settings()->IsFledgeJoiningAllowed(
+ url::Origin::Create(GURL("https://third.com"))));
+
+ // Perform a maximmal time range deletion, which should remove the two
+ // remaining settings.
+ privacy_sandbox_settings()->ClearFledgeJoiningAllowedSettings(
+ base::Time(), base::Time::Max());
+ EXPECT_TRUE(privacy_sandbox_settings()->IsFledgeJoiningAllowed(
+ url::Origin::Create(GURL("https://first.com"))));
+ EXPECT_TRUE(privacy_sandbox_settings()->IsFledgeJoiningAllowed(
+ url::Origin::Create(GURL("https://second.com"))));
+ EXPECT_TRUE(privacy_sandbox_settings()->IsFledgeJoiningAllowed(
+ url::Origin::Create(GURL("https://third.com"))));
+}
+
+TEST_P(PrivacySandboxSettingsTest, TrustTokensAllowed) {
+ // IsTrustTokensAllowed() should follow the top level privacy sandbox setting
+ // as long as the release 3 feature is enabled, always returning true
+ // otherwise
+ base::test::ScopedFeatureList feature_list_;
+ feature_list_.InitAndEnableFeature(privacy_sandbox::kPrivacySandboxSettings3);
+ privacy_sandbox_test_util::MockPrivacySandboxObserver observer;
+ privacy_sandbox_settings()->AddObserver(&observer);
+ EXPECT_CALL(observer, OnTrustTokenBlockingChanged(/*blocked=*/true));
+
+ privacy_sandbox_settings()->SetPrivacySandboxEnabled(false);
+ EXPECT_FALSE(privacy_sandbox_settings()->IsTrustTokensAllowed());
+ testing::Mock::VerifyAndClearExpectations(&observer);
+
+ EXPECT_CALL(observer, OnTrustTokenBlockingChanged(/*blocked=*/false));
+ privacy_sandbox_settings()->SetPrivacySandboxEnabled(true);
+ EXPECT_TRUE(privacy_sandbox_settings()->IsTrustTokensAllowed());
+ testing::Mock::VerifyAndClearExpectations(&observer);
+
+ feature_list_.Reset();
+ feature_list_.InitAndDisableFeature(
+ privacy_sandbox::kPrivacySandboxSettings3);
+ EXPECT_CALL(observer, OnTrustTokenBlockingChanged(testing::_)).Times(0);
+
+ privacy_sandbox_settings()->SetPrivacySandboxEnabled(false);
+ EXPECT_TRUE(privacy_sandbox_settings()->IsTrustTokensAllowed());
+
+ privacy_sandbox_settings()->SetPrivacySandboxEnabled(true);
+ EXPECT_TRUE(privacy_sandbox_settings()->IsTrustTokensAllowed());
+}
+
+INSTANTIATE_TEST_SUITE_P(PrivacySandboxSettingsTestInstance,
+ PrivacySandboxSettingsTest,
+ testing::Bool());
+
+class PrivacySandboxSettingsTestCookiesClearOnExitTurnedOff
+ : public PrivacySandboxSettingsTest {
+ public:
+ void InitializePrefsBeforeStart() override {
+ prefs()->SetUserPref(prefs::kPrivacySandboxFlocDataAccessibleSince,
+ std::make_unique<base::Value>(::base::TimeToValue(
+ base::Time::FromTimeT(12345))));
+ }
+ void InitializeFeaturesBeforeStart() override {}
+};
+
+TEST_P(PrivacySandboxSettingsTestCookiesClearOnExitTurnedOff,
+ UseLastFlocDataAccessibleSince) {
+ EXPECT_EQ(base::Time::FromTimeT(12345),
+ privacy_sandbox_settings()->FlocDataAccessibleSince());
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ PrivacySandboxSettingsTestCookiesClearOnExitTurnedOffInstance,
+ PrivacySandboxSettingsTestCookiesClearOnExitTurnedOff,
+ testing::Bool());
+
+class PrivacySandboxSettingsTestCookiesClearOnExitTurnedOn
+ : public PrivacySandboxSettingsTest {
+ public:
+ void InitializePrefsBeforeStart() override {
+ host_content_settings_map()->SetDefaultContentSetting(
+ ContentSettingsType::COOKIES,
+ ContentSetting::CONTENT_SETTING_SESSION_ONLY);
+
+ prefs()->SetUserPref(prefs::kPrivacySandboxFlocDataAccessibleSince,
+ std::make_unique<base::Value>(::base::TimeToValue(
+ base::Time::FromTimeT(12345))));
+ }
+};
+
+TEST_P(PrivacySandboxSettingsTestCookiesClearOnExitTurnedOn,
+ UpdateFlocDataAccessibleSince) {
+ EXPECT_EQ(base::Time::Now(),
+ privacy_sandbox_settings()->FlocDataAccessibleSince());
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ PrivacySandboxSettingsTestCookiesClearOnExitTurnedOnInstance,
+ PrivacySandboxSettingsTestCookiesClearOnExitTurnedOn,
+ testing::Bool());
+
+class PrivacySandboxSettingsIncognitoTest : public PrivacySandboxSettingsTest {
+ bool IsIncognitoProfile() override { return true; }
+};
+
+TEST_P(PrivacySandboxSettingsIncognitoTest, DisabledInIncognito) {
+ // When the Release 3 flag is enabled, APIs should always be disabled in
+ // incognito. The Release 3 flag is set based on the test param.
+ privacy_sandbox_settings()->SetPrivacySandboxEnabled(true);
+ if (GetParam())
+ EXPECT_FALSE(privacy_sandbox_settings()->IsPrivacySandboxEnabled());
+ else
+ EXPECT_TRUE(privacy_sandbox_settings()->IsPrivacySandboxEnabled());
+}
+
+INSTANTIATE_TEST_SUITE_P(PrivacySandboxSettingsIncognitoTestInstance,
+ PrivacySandboxSettingsIncognitoTest,
+ testing::Bool());
diff --git a/chromium/components/privacy_sandbox/privacy_sandbox_test_util.cc b/chromium/components/privacy_sandbox/privacy_sandbox_test_util.cc
new file mode 100644
index 00000000000..663d05964df
--- /dev/null
+++ b/chromium/components/privacy_sandbox/privacy_sandbox_test_util.cc
@@ -0,0 +1,89 @@
+// Copyright 2021 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.
+
+#include "components/privacy_sandbox/privacy_sandbox_test_util.h"
+
+#include "base/feature_list.h"
+#include "components/content_settings/core/browser/cookie_settings.h"
+#include "components/content_settings/core/browser/host_content_settings_map.h"
+#include "components/content_settings/core/common/pref_names.h"
+#include "components/content_settings/core/test/content_settings_mock_provider.h"
+#include "components/content_settings/core/test/content_settings_test_utils.h"
+#include "components/privacy_sandbox/privacy_sandbox_features.h"
+#include "components/privacy_sandbox/privacy_sandbox_prefs.h"
+#include "components/sync_preferences/testing_pref_service_syncable.h"
+
+namespace privacy_sandbox_test_util {
+
+MockPrivacySandboxObserver::MockPrivacySandboxObserver() = default;
+MockPrivacySandboxObserver::~MockPrivacySandboxObserver() = default;
+
+void SetupTestState(
+ sync_preferences::TestingPrefServiceSyncable* testing_pref_service,
+ HostContentSettingsMap* map,
+ bool privacy_sandbox_enabled,
+ bool block_third_party_cookies,
+ ContentSetting default_cookie_setting,
+ const std::vector<CookieContentSettingException>& user_cookie_exceptions,
+ ContentSetting managed_cookie_setting,
+ const std::vector<CookieContentSettingException>&
+ managed_cookie_exceptions) {
+ // Setup block-third-party-cookies settings.
+ testing_pref_service->SetUserPref(
+ prefs::kCookieControlsMode,
+ std::make_unique<base::Value>(static_cast<int>(
+ block_third_party_cookies
+ ? content_settings::CookieControlsMode::kBlockThirdParty
+ : content_settings::CookieControlsMode::kOff)));
+
+ // Setup cookie content settings.
+ auto user_provider = std::make_unique<content_settings::MockProvider>();
+ auto managed_provider = std::make_unique<content_settings::MockProvider>();
+
+ if (default_cookie_setting != kNoSetting) {
+ user_provider->SetWebsiteSetting(
+ ContentSettingsPattern::Wildcard(), ContentSettingsPattern::Wildcard(),
+ ContentSettingsType::COOKIES, base::Value(default_cookie_setting));
+ }
+
+ for (const auto& exception : user_cookie_exceptions) {
+ user_provider->SetWebsiteSetting(
+ ContentSettingsPattern::FromString(exception.primary_pattern),
+ ContentSettingsPattern::FromString(exception.secondary_pattern),
+ ContentSettingsType::COOKIES, base::Value(exception.content_setting));
+ }
+
+ if (managed_cookie_setting != kNoSetting) {
+ managed_provider->SetWebsiteSetting(
+ ContentSettingsPattern::Wildcard(), ContentSettingsPattern::Wildcard(),
+ ContentSettingsType::COOKIES, base::Value(managed_cookie_setting));
+ }
+
+ for (const auto& exception : managed_cookie_exceptions) {
+ managed_provider->SetWebsiteSetting(
+ ContentSettingsPattern::FromString(exception.primary_pattern),
+ ContentSettingsPattern::FromString(exception.secondary_pattern),
+ ContentSettingsType::COOKIES, base::Value(exception.content_setting));
+ }
+
+ content_settings::TestUtils::OverrideProvider(
+ map, std::move(user_provider), HostContentSettingsMap::DEFAULT_PROVIDER);
+ content_settings::TestUtils::OverrideProvider(
+ map, std::move(managed_provider),
+ HostContentSettingsMap::POLICY_PROVIDER);
+
+ // Only adjust the Privacy Sandbox preference which should be being consulted
+ // based on feature state.
+ if (base::FeatureList::IsEnabled(privacy_sandbox::kPrivacySandboxSettings3)) {
+ testing_pref_service->SetUserPref(
+ prefs::kPrivacySandboxApisEnabledV2,
+ std::make_unique<base::Value>(privacy_sandbox_enabled));
+ } else {
+ testing_pref_service->SetUserPref(
+ prefs::kPrivacySandboxApisEnabled,
+ std::make_unique<base::Value>(privacy_sandbox_enabled));
+ }
+}
+
+} // namespace privacy_sandbox_test_util
diff --git a/chromium/components/privacy_sandbox/privacy_sandbox_test_util.h b/chromium/components/privacy_sandbox/privacy_sandbox_test_util.h
new file mode 100644
index 00000000000..1b5c692cbd0
--- /dev/null
+++ b/chromium/components/privacy_sandbox/privacy_sandbox_test_util.h
@@ -0,0 +1,54 @@
+// Copyright 2021 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.
+
+#ifndef COMPONENTS_PRIVACY_SANDBOX_PRIVACY_SANDBOX_TEST_UTIL_H_
+#define COMPONENTS_PRIVACY_SANDBOX_PRIVACY_SANDBOX_TEST_UTIL_H_
+
+#include <string>
+
+#include "components/content_settings/core/common/content_settings.h"
+#include "components/privacy_sandbox/privacy_sandbox_settings.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace sync_preferences {
+class TestingPrefServiceSyncable;
+}
+
+class HostContentSettingsMap;
+
+namespace privacy_sandbox_test_util {
+
+class MockPrivacySandboxObserver : public PrivacySandboxSettings::Observer {
+ public:
+ MockPrivacySandboxObserver();
+ ~MockPrivacySandboxObserver();
+ MOCK_METHOD1(OnFlocDataAccessibleSinceUpdated, void(bool));
+ MOCK_METHOD1(OnTrustTokenBlockingChanged, void(bool));
+};
+
+// Define an additional content setting value to simulate an unmanaged default
+// content setting.
+const ContentSetting kNoSetting = static_cast<ContentSetting>(-1);
+
+struct CookieContentSettingException {
+ std::string primary_pattern;
+ std::string secondary_pattern;
+ ContentSetting content_setting;
+};
+
+// Sets up preferences and content settings based on provided parameters.
+void SetupTestState(
+ sync_preferences::TestingPrefServiceSyncable* testing_pref_service,
+ HostContentSettingsMap* map,
+ bool privacy_sandbox_enabled,
+ bool block_third_party_cookies,
+ ContentSetting default_cookie_setting,
+ const std::vector<CookieContentSettingException>& user_cookie_exceptions,
+ ContentSetting managed_cookie_setting,
+ const std::vector<CookieContentSettingException>&
+ managed_cookie_exceptions);
+
+} // namespace privacy_sandbox_test_util
+
+#endif // COMPONENTS_PRIVACY_SANDBOX_PRIVACY_SANDBOX_TEST_UTIL_H_
diff --git a/chromium/components/privacy_sandbox_strings.grdp b/chromium/components/privacy_sandbox_strings.grdp
index 4953b15aa84..3ffe20f920b 100644
--- a/chromium/components/privacy_sandbox_strings.grdp
+++ b/chromium/components/privacy_sandbox_strings.grdp
@@ -33,4 +33,1058 @@
<message name="IDS_PRIVACY_SANDBOX_FLOC_STATUS_NOT_ACTIVE" desc="Description of the user's FLoC status when FLoC is not operational, either because the user does not have the FLoC setting enabled, or the user was not placed in the origin trial, or both.">
Off
</message>
+
+ <!-- Topics API Taxonomy -->
+ <!-- These entries have been script generated to ensure consistent mappings. If you are editing these directly, you are likely doing something wrong -->
+ <!-- TODO(crbug.com/1286276) These strings are not final and hence marked as no translate -->
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_INVALID_TOPIC" translateable="false" desc="Shown when an unknown Topic has been provided by the categorization service. This is indicative of an error state that is not expected to occur">
+ Unknown
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_1" translateable="false" desc="Taxonomy Member. Meaning: [Umbrella category that encompasses: pop culture, entertainment and celebrity media; music, film, radio, tv, animation, humor; performing and visual arts; miscellaneous online &quot;fun.&quot;] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/2968097980703095441">
+ Arts &amp; entertainment
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_2" translateable="false" desc="Taxonomy Member. Meaning: [acting, dramaturgy, theatrical productions and stagecraft; dramatic performance before a live audience] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/2860407149739760502">
+ Acting &amp; theater
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_3" translateable="false" desc="Taxonomy Member. Meaning: [comic books, comic strips and graphic novels; both print comics and web comics] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/8681047362902928146">
+ Comics
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_4" translateable="false" desc="Taxonomy Member. Meaning: [live performances of music; festivals that gather together multiple artists and performers for live musical performances] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/8049728585295014965">
+ Concerts &amp; music festivals
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_5" translateable="false" desc="Taxonomy Member. Meaning: [all manner of recreational dancing, from ballroom to break-dancing; also, all manner of dance as spectacle and performance, from ballet, butoh and folk dancing to other spectator dances] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/5257399864132148397">
+ Dance
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_6" translateable="false" desc="Taxonomy Member. Meaning: [the business and industry of creating entertainment media: filmmaking, music and tv production, etc.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/16372513248706452">
+ Entertainment industry
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_7" translateable="false" desc="Taxonomy Member. Meaning: [jokes, gags, pranks, bloopers, parodies, political satire and other funny stuff] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/54550779249595828">
+ Humor
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_8" translateable="false" desc="Taxonomy Member. Meaning: [the performing art of comedy, traditionally in a live setting; the comedians that perform it and those that write it; in other words: improv, stand-up and sketch comedy] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/2872368234977873982">
+ Live comedy
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_9" translateable="false" desc="Taxonomy Member. Meaning: [sports events as live entertainment; sports event ticketing and related sporting venues such as stadiums and athletic arenas] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/6894920366209049234">
+ Live sporting events
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_10" translateable="false" desc="Taxonomy Member. Meaning: [magic (sometimes referred to as stage magic to distinguish it from paranormal or ritual magic) is a performing art that entertains audiences by staging tricks or creating illusions of seemingly impossible or supernatural feats using natural means; one who performs such illusions is called a magician or an illusionist; some performers may also be referred to by names reflecting the type of magical effects they present, such as prestidigitators, conjurors, mentalists, or escape artists (source: Wikipedia)] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/7028249567539345753">
+ Magic
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_11" translateable="false" desc="Taxonomy Member. Meaning: [content related to movie theaters and film showings, including film listings, short reviews and showtimes] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/5922147370861736784">
+ Movie listings &amp; theater showtimes
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_12" translateable="false" desc="Taxonomy Member. Meaning: [cinema, motion pictures, films; their public exhibition in theaters, their recorded formats (videos, DVDs, etc), and related merchandise] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/8174211814203073114">
+ Movies
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_13" translateable="false" desc="Taxonomy Member. Meaning: [A film that has action (fights, shootouts, explosions, car chases) or adventure (discovery of new worlds, fighting outlaws) as a major theme; includes spy films, action-oriented war films, and historical action films.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/3759809365624147506">
+ Action &amp; adventure films
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_14" translateable="false" desc="Taxonomy Member. Meaning: [Films that are created by animators or using animated techniques: cartoon, stop-motion, computer animation, etc.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/2307119915510248122">
+ Animated films
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_15" translateable="false" desc="Taxonomy Member. Meaning: [A film which uses humor as its main emphasis; includes black comedies, spoof films, romantic comedies, screwball comedies.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/7930191045766714923">
+ Comedy films
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_16" translateable="false" desc="Taxonomy Member. Meaning: [Movies that have either developed a cult following or that have been produced independently; includes b-movies, midnight movies, Sundance films. Also includes experimental, avant-garde and art films.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/1250439441563990896">
+ Cult &amp; indie films
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_17" translateable="false" desc="Taxonomy Member. Meaning: [a non-fiction film intended to document some aspect of reality (source: Wikipedia)] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/8530848477777371672">
+ Documentary films
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_18" translateable="false" desc="Taxonomy Member. Meaning: [Drama film is a film genre that has as its hallmark realistic psychological, emotional and in-depth characters and themes. Includes bio-pics, epics, historical dramas, dramatic literary adaptations, costume dramas, dramatic war films, family sagas, legal dramas and generational films.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/8974218169454235423">
+ Drama films
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_19" translateable="false" desc="Taxonomy Member. Meaning: [often called &quot;family films&quot; or &quot;family-oriented&quot; films, this is the genre of cinema oriented toward children, teens and families] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/6543693795090723901">
+ Family films
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_20" translateable="false" desc="Taxonomy Member. Meaning: [Horror films often deal with viewers&#x27; nightmares, fears, revulsions and terror of the unknown. Prevalent elements include ghosts, extraterrestrials, vampires, werewolves, demons, gore, torture, vicious animals, evil witches, monsters, zombies, cannibals, psychopaths, and serial killers (source: Wikipedia).] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/3683253599582226273">
+ Horror films
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_21" translateable="false" desc="Taxonomy Member. Meaning: [Films with a romantic theme, or which emphasize the personal relationships between the film&#x27;s protagonists; includes romantic comedies (&quot;rom-coms&quot;)] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/6642844646231849461">
+ Romance films
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_22" translateable="false" desc="Taxonomy Member. Meaning: [Films with plots that involve crime or suspense; includes mystery films, suspense films, crime films, thrillers, films noir, and gangster films.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/1028517354047369491">
+ Thriller, crime &amp; mystery films
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_23" translateable="false" desc="Taxonomy Member. Meaning: [Umbrella category encompassing music in recorded formats or as a performance; musical instruction, instrumentation and technology; audio content, chiefly for entertainment or informational purposes.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/1942344463604084284">
+ Music &amp; audio
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_24" translateable="false" desc="Taxonomy Member. Meaning: [a style of music originally based on African-American field shouts and secular songs; it is a vocal genre, often performed by singing guitarists; sometimes called a subgenre of jazz, blues music has its own identity in artists such as Buddy Guy and Ruth Brown; typical artists in blues-rock, a related style, are Stevie Ray Vaughan and Eric Clapton (Source: DMOZ)] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/5818298131139717934">
+ Blues
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_25" translateable="false" desc="Taxonomy Member. Meaning: [Music encompassing a broad period from roughly the 9th century to present times (Source: Wikipedia); it is epitomized by forms such as the symphony, concerto, and sonata, and composers such as Mozart, Beethoven, Vivaldi, Bach, etc.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/7794536354774135472">
+ Classical music
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_26" translateable="false" desc="Taxonomy Member. Meaning: [a blend of popular musical forms originally found in the Southern United States and the Appalachian Mountains; includes hillbilly, bluegrass, Western swing music, honky-tonk, and both pop and alternative country genres; not limited to the USA, variants of country music are also popular in Australia, Canada, Poland, and areas of Latin America (Source: Wikipedia)] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/1003758414042879701">
+ Country music
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_27" translateable="false" desc="Taxonomy Member. Meaning: [the broad genre of electronic-based music, including techno, house, ambient, drum and bass, jungle, trip-hop, trap, trance, dubstep, electronic disco, etc. The term electronica has been used to describe electronic music styles intended not just for dancing but also concentrated listening (source: Wikipedia).] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/5701637830475686882">
+ Dance &amp; electronic music
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_28" translateable="false" desc="Taxonomy Member. Meaning: [folk and traditional music, including folk revival movements that have produced a kind of popular music that is based on traditional music; sub-genres include folk rock, electric folk and progressive folk music; not limited to North America, folk music includes other forms of traditional music using traditional instruments such as Celtic folk music, Balkan and Eastern European folk traditions, Japanese taiko, etc (Source: Wikipedia)] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/3153944137796314763">
+ Folk &amp; traditional music
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_29" translateable="false" desc="Taxonomy Member. Meaning: [a style of music that often involves improvisation and group interaction; the style is also known for use of blue notes, syncopation, swing, call and response, and polyrhythms (Source: Wikipedia)] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/7267890742105038471">
+ Jazz
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_30" translateable="false" desc="Taxonomy Member. Meaning: [musical instruments and accessories] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/3651825076054204255">
+ Musical instruments
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_31" translateable="false" desc="Taxonomy Member. Meaning: [Chart-toppers and music that has received wide radio or public airplay; music that is accessible to the general public and disseminated by one or more of the mass media; the term &quot;pop music&quot; was first used in the sense of &quot;having popular appeal&quot;, but since the 1950s it has been used in the sense of a musical genre, originally characterized as a lighter alternative to rock and roll (source: Wikipedia). Includes artists like Michael Jackson, Madonna, Taylor Swift, Justin Bieber.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/7828293148434841954">
+ Pop music
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_32" translateable="false" desc="Taxonomy Member. Meaning: [The term hip hop music is sometimes used synonymously with the term rap music, though rapping is not a required component of hip hop music; the genre may also incorporate other elements of hip hop culture, including DJing, turntablism, and scratching, beatboxing, and instrumental tracks (source: Wikipedia).] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/2413099954889237037">
+ Rap &amp; hip-hop
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_33" translateable="false" desc="Taxonomy Member. Meaning: [rock and roll and its many sub-genres; a loosely defined genre of popular music that entered the mainstream in the mid 1950s, in the 1970s, rock developed a number of subgenres, such as soft rock, glam rock, heavy metal, hard rock, progressive rock, and punk rock (Source: Wikipedia)] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/6070916516256100445">
+ Rock music
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_34" translateable="false" desc="Taxonomy Member. Meaning: [Classic Rock and Oldies feature a large playlist of songs ranging from the 1960s, 1970s, 1980s and early 1990s; Oldies has some overlap with the classic rock format, which concentrates on the rock music of the late-1960s and 1970s and sometimes plays newer material made in the same style as the older songs. Traditionally, classic rock focuses on the heavier rock music of the era while oldies focuses on the lighter pop music (source: Wikipedia).] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/7984451814414788618">
+ Classic rock &amp; oldies
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_35" translateable="false" desc="Taxonomy Member. Meaning: [Hard rock is a sub-genre of rock music which is considerably harder than conventional rock music, but not as extreme as heavy metal; it includes examples like Kiss, Def Leppard, Led Zeppelin. Progressive rock focuses on technical musicianship in a rock context, and pushes rock&#x27;s technical and compositional boundaries by going beyond the standard verse-chorus-based song structures; the term was applied to the music of bands such as Pink Floyd, King Crimson, Yes, Genesis, Jethro Tull, Soft Machine, and Emerson, Lake &amp; Palmer, and reached its peak of popularity in the mid 1970s (source: Wikipedia).] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/6335121931020200010">
+ Hard rock &amp; progressive
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_36" translateable="false" desc="Taxonomy Member. Meaning: [A sub-genre of rock music that emerged in the 1980s and became widely popular in the 1990s, alternative rock consists of various subgenres that have emerged from the independent music scene since the 1980s, such as grunge, Britpop, gothic rock, and indie pop; featuring artists often associated with independent record labels. (Source: Wikipedia). Includes artists such as Radiohead, Nirvana, The Smiths.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/5538794458052201021">
+ Indie &amp; alternative music
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_37" translateable="false" desc="Taxonomy Member. Meaning: [Soul combines elements of African-American gospel music, rhythm and blues, and jazz. Contemporary R&amp;B features a distinctive record production style, drum machine-backed rhythms, an occasional saxophone-laced beat to give a jazz feel (in contemporary R&amp;B songs prior to the year 1995) and a smooth, lush style of vocal arrangement. Funk typically consists of a complex groove with rhythm instruments such as electric guitar, electric bass, Hammond organ, and drums playing interlocking rhythms (source: Wikipedia).] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/5425329252191278611">
+ Soul &amp; r&amp;b
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_38" translateable="false" desc="Taxonomy Member. Meaning: [film, television or video game music and themes; film, tv, and video game music composers] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/1271305976669033594">
+ Soundtracks
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_39" translateable="false" desc="Taxonomy Member. Meaning: [Radio programs in which people talk about politics, sports, current affairs, etc., and listeners can make phone calls to give their opinions; talk radio shows, networks and personalities.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/2579922399234486228">
+ Talk radio
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_40" translateable="false" desc="Taxonomy Member. Meaning: [Regional and ethnic music of various genres, specifically non-Western popular and traditional music; also, a catch-all marketing term for popularized folk traditions and ethnic music, or pop from outside of the Anglo traditions of the United States, Canada, Australia, New Zealand and the United Kingdom; the world music section in a record store might include albums of Hawaiian slack-key guitar, Cajun zydeco, Dominican merengue and Algerian ra?, among others (source: Wikipedia).] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/3402857732233686445">
+ World music
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_41" translateable="false" desc="Taxonomy Member. Meaning: [The music of the Caribbean; some of the styles to gain wide popularity outside of the Caribbean include reggae, zouk, calypso, and punta; Reggae more properly denotes a particular music style that originated following on the development of ska and rocksteady (source: Wikipedia).] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/2346297341997046685">
+ Reggae &amp; caribbean music
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_42" translateable="false" desc="Taxonomy Member. Meaning: [online image-based content; online galleries of images and photos with minimal text; collections of images or photos of famous people, places and events, or items of interest; typically, static hosted image content, not necessarily user-uploaded or shared content] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/6886302747700347831">
+ Online image galleries
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_43" translateable="false" desc="Taxonomy Member. Meaning: [online digital video content] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/5096385157103445048">
+ Online video
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_44" translateable="false" desc="Taxonomy Member. Meaning: [an art form in which singers and musicians perform a dramatic work (called an opera) which combines a text (called a libretto) and a musical score (Source: Wikipedia); opera works, composers, performances, singers and performers] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/1385754809560116050">
+ Opera
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_45" translateable="false" desc="Taxonomy Member. Meaning: [A television program is a segment of content intended for broadcast on over-the-air, cable television, or internet television; it doesn&#x27;t include commercials, trailers, or any other segments of content not serving as attraction for TV viewership (source: Wikipedia).] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/8250092644935921963">
+ TV shows &amp; programs
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_46" translateable="false" desc="Taxonomy Member. Meaning: [television programs with a focus on humor; includes sitcoms, sketch comedy shows, and animated series with a particular emphasis on jokes] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/5813986711525484638">
+ TV comedies
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_47" translateable="false" desc="Taxonomy Member. Meaning: [televised programming such as tv films, programs and miniseries, that focus on real-life events, in the past or present; can include science, biography, travel, and other types of programming intended to inform or educate] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/8983069057849763877">
+ TV documentary &amp; nonfiction
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_48" translateable="false" desc="Taxonomy Member. Meaning: [dramatic TV programs and series; series that have realistic psychological, emotional and in-depth characters and themes] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/2984681966454881659">
+ TV dramas
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_49" translateable="false" desc="Taxonomy Member. Meaning: [serial TV dramas dealing typically with daily events in the lives of the same group of characters; chiefly characterized by tangled interpersonal situations and melodramatic or sentimental treatment] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/2318091960487053429">
+ TV soap operas
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_50" translateable="false" desc="Taxonomy Member. Meaning: [family-oriented television shows that are made for, and whose primary audiences are, parents, teens and children] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/544990757699326442">
+ TV familly-oriented shows
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_51" translateable="false" desc="Taxonomy Member. Meaning: [a genre of (generally episodic) television programming that presents purportedly unscripted dramatic or humorous situations, documents actual events, and usually features ordinary people instead of professional actors (Source: Wikipedia)] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/2228280087691900252">
+ TV reality shows
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_52" translateable="false" desc="Taxonomy Member. Meaning: [TV sci-fi shows featuring futuristic elements such as spacecraft, robots, cyborgs, interstellar space travel or other technologies; fantasy shows featuring magic, supernatural events, mythology, folklore, or exotic fantasy worlds (source: Wikipedia).] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/1831820498314087291">
+ TV sci-fi &amp; fantasy shows
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_53" translateable="false" desc="Taxonomy Member. Meaning: [all manner of visual art works, including painting, sculpture, drawing, collage, installation art, artistic (as opposed to business) printmaking, murals, etc; also, design; artistic photography may fall into this category, as well as video and film art] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/4258098659051509326">
+ Visual art &amp; design
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_54" translateable="false" desc="Taxonomy Member. Meaning: [the act of working out the form of something (making a sketch or outline or plan): product design, furniture design, home design, graphic design, etc] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/5921667170692323372">
+ Design
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_55" translateable="false" desc="Taxonomy Member. Meaning: [the practice of applying paint, pigment, color or other medium to a surface to create a work of art; the term describes both the act and the result, which is called a painting (source: Wikipedia)] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/646231684975825817">
+ Painting
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_56" translateable="false" desc="Taxonomy Member. Meaning: [photography as an artistic practice or hobby, extended to the field of digital image production and videography; artistic photography, video and digital art] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/6094865097262177264">
+ Photographic &amp; digital arts
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_57" translateable="false" desc="Taxonomy Member. Meaning: [Umbrella category that encompasses motor vehicles of all kinds, including cars, bicycles, personal aircraft and watercraft; consumer products and services related to moving vehicles.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/3265681195405732661">
+ Autos &amp; vehicles
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_58" translateable="false" desc="Taxonomy Member. Meaning: [Motor vehicles and trailers designed to transport cargo for commercial purposes; commonly known as lorries, tractor-trailers, semi-trucks, and 18 wheelers. They also serve as platforms for specialized equipment such as fire trucks, cement mixers, and garbage trucks.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/2127651263889384706">
+ Cargo trucks &amp; trailers
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_59" translateable="false" desc="Taxonomy Member. Meaning: [older cars, trucks, and motorcycles with enough historical interest to be collectible and worth preserving or restoring (source: Wikipedia)] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/4651839125153921319">
+ Classic vehicles
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_60" translateable="false" desc="Taxonomy Member. Meaning: [this category includes modified vehicles, such as lowered trucks, hot rods, souped-up racers; concept vehicles; and exclusive, ultra high-performance, or otherwise &quot;exotic&quot; supercars, often manufactured by elite automakers such as Ferrari, Lotus, Koenigsegg, and Bugatti] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/9074459087593201370">
+ Custom &amp; performance vehicles
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_61" translateable="false" desc="Taxonomy Member. Meaning: [vehicle fueling stations and services; consumer gas price resources and comparisons; fuel economy, fuel efficiency, and fuel taxation] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/8329984535343109075">
+ Gas prices &amp; vehicle fueling
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_62" translateable="false" desc="Taxonomy Member. Meaning: [a category to group consumer motor vehicles by vehicle class, (e.g. compact cars, trucks, motorcycles, mopeds etc.), body type (e.g. sedan, coupe, wagon), and consumer segment (e.g. luxury)] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/8872061343727741247">
+ Motor vehicles (by type)
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_63" translateable="false" desc="Taxonomy Member. Meaning: [A self-driving car, also known as an autonomous vehicle, driverless car, or robo-car is a vehicle that is capable of sensing its environment and moving safely with little or no human input. (Source: Wikipedia)] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/4944651545077644524">
+ Autonomous vehicles
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_64" translateable="false" desc="Taxonomy Member. Meaning: [Vehicles that can convert from an enclosed to an open-air vehicle. Common names and styles include hard top convertibles, soft tops, targa tops, spyders, cabriolets, and roadsters.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/4829581144633699619">
+ Convertibles
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_65" translateable="false" desc="Taxonomy Member. Meaning: [two-door family cars, typically with a hard top and sloping back; passenger vehicles in the compact to midsize size range, with two doors and four seats, or two front seats and room for two or three passengers in back] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/4233627725223682907">
+ Coupes
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_66" translateable="false" desc="Taxonomy Member. Meaning: [Cars featuring a shared passenger and cargo space (no separate trunk compartment), usually with a top-hinged liftgate &quot;hatch&quot; in the rear acting as the third or fifth door, and shorter in length than a station wagon (3 pillars vs. 4). Examples include the Volkswagen Golf, Mini Hardtop, and Citro?n C4 Hatchback.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/2652871435928048950">
+ Hatchbacks
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_67" translateable="false" desc="Taxonomy Member. Meaning: [vehicles with an alternative fuel engine (such as ethanol, hydrogen, and biodiesel) and fuel-electric hybrids, full electric vehicles, etc.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/7964577762873181206">
+ Hybrid &amp; alternative vehicles
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_68" translateable="false" desc="Taxonomy Member. Meaning: [luxury vehicle is a marketing term for a vehicle that provides luxury ? pleasant or desirable features beyond strict necessity ? at increased expense (Source: Wikipedia); luxury vehicles are often identified by brand (eg, BMW, Jaguar, Lexus, Mercedes-Benz) and price point, and many automotive manufacturers have dedicated luxury lines of vehicles] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/6918438858307498936">
+ Luxury vehicles
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_69" translateable="false" desc="Taxonomy Member. Meaning: [the smallest classes of motor vehicles in the USA and Europe; smaller than compact cars, they are typically two-door vehicles intended primarily for transportation in urban areas; this includes the microcar, bubble car, city car and supermini car segments in Europe, and overlaps with the micro and subcompact segments in USA; popular examples include the Smart and Mini brand vehicles, as well as the &quot;kei car&quot; segment in Japan] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/1054097891495782845">
+ Microcars &amp; subcompacts
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_70" translateable="false" desc="Taxonomy Member. Meaning: [a motorcycle (also called a motorbike, bike, moto or cycle) is a two or three wheeled motor vehicle; includes motorcycle retailers, manufacturers, gear, etc.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/4047422247042666379">
+ Motorcycles
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_71" translateable="false" desc="Taxonomy Member. Meaning: [motorized vehicles capable of driving on and off paved or gravel surface, water, sand, snow, ice, marsh, swampland, or other terrain, they generally characterized by having large tires with deep, open treads, a flexible suspension, or even caterpillar tracks; examples include ATVs, dune buggies, dirt bikes, snowmobiles, side-by-sides, 4x4s and all-wheel-drive vehicles, etc.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/3805566893887872965">
+ Off-road vehicles
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_72" translateable="false" desc="Taxonomy Member. Meaning: [light-duty trucks with an enclosed cab and an open cargo area in the back (source: Wikipedia), examples include the Ford F-Series, Chevrolet Silverado, and Nissan Titan.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/934837161003377655">
+ Pickup trucks
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_73" translateable="false" desc="Taxonomy Member. Meaning: [this category includes both scooters, which are motorcycles with step-through frames such as Vespas; and mopeds, which are slower-moving, pedal and engine-propelled motorcycles sometimes called &quot;motorized bicycles&quot;] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/4203987010453301525">
+ Scooters &amp; mopeds
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_74" translateable="false" desc="Taxonomy Member. Meaning: [cars with four doors, a separate trunk compartment, and enough space in the rear to comfortably accommodate adults; also known as saloon cars] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/4611181233197207721">
+ Sedans
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_75" translateable="false" desc="Taxonomy Member. Meaning: [Cars with a body style variant of a sedan/saloon with its roof extended rearward over a shared passenger/cargo volume with access at the back via a third or fifth door (the liftgate or tailgate), instead of a trunk lid (Source: Wikipedia). Longer than hatchbacks (4 pillars instead of 3), examples include the Volkswagen Golf SportWagen, Toyota Prius V, Mazda6 Estate, and Volvo V60.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/4970210882918683612">
+ Station wagons
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_76" translateable="false" desc="Taxonomy Member. Meaning: [Sport utility vehicles (SUVs) are vehicles built on a light-truck chassis that feature large passenger, cargo, and towing capacities, high ground clearance, and an upright, boxy design; often referred to as an \&#x27;off-roader\&#x27; in Europe. Examples include the Chevrolet Tahoe, Ford Expedition, Toyota 4Runner, and Mercedes G-Class.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/2340701835461601376">
+ SUVs &amp; crossovers
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_77" translateable="false" desc="Taxonomy Member. Meaning: [Vehicles built on a car platform that combine features from sport utility vehicles (SUVs) and hatchbacks or station wagons. Built on a unibody chassis rather than the truck-based body-on-frame platform of standard SUVs, crossovers feature car-like fuel economy and handling, and SUV-like cargo room, ground clearance, and towing capacity. Examples included the Toyota RAV4, Honda Pilot, Ford Escape, Audi Q7, and Mercedes GL.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/7913753013863451951">
+ Crossovers
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_78" translateable="false" desc="Taxonomy Member. Meaning: [vehicles that feature a short hood and a box-shaped body enclosing a large cargo or passenger area] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/3165356599697789364">
+ Vans &amp; minivans
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_79" translateable="false" desc="Taxonomy Member. Meaning: [Services that assist motorists, or bicyclists, whose vehicles have suffered a mechanical failure that leaves the operator stranded (Source: Wikipedia). Includes vehicle towing, tire changes, battery service, etc.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/2892996270723975724">
+ Towing &amp; roadside assistance
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_80" translateable="false" desc="Taxonomy Member. Meaning: [Products, services, and information related to driver, passenger and vehicle safety. Includes vehicle and traffic codes, traffic signage and related equipment (e.g. traffic lights), traffic safety campaigns etc.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/4337451575162195176">
+ Vehicle &amp; traffic safety
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_81" translateable="false" desc="Taxonomy Member. Meaning: [vehicle parts and accessories, including auto body and interior, engine components, electronics, etc] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/5105021423436289531">
+ Vehicle parts &amp; accessories
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_82" translateable="false" desc="Taxonomy Member. Meaning: [Vehicle repair and maintenance, including auto mechanics, body shops and garages; excludes roadside assistance.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/1327343024944705365">
+ Vehicle repair &amp; maintenance
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_83" translateable="false" desc="Taxonomy Member. Meaning: [vehicle shopping services and information, including both online and offline sales and classsifieds] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/1570908993266729935">
+ Vehicle shopping
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_84" translateable="false" desc="Taxonomy Member. Meaning: [pre-owned vehicle listings, automotive classifieds and used vehicle dealers] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/6039885784743740565">
+ Used vehicles
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_85" translateable="false" desc="Taxonomy Member. Meaning: [vehicles shows, expos, and conferences for manufacturers and other people in the industry, the specialized press, and/or enthusiasts] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/7339196590922475651">
+ Vehicle shows
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_86" translateable="false" desc="Taxonomy Member. Meaning: [beauty, style, fashion and fitness; self-care, hygiene, body-image and wellness] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/4884736190847523854">
+ Beauty &amp; fitness
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_87" translateable="false" desc="Taxonomy Member. Meaning: [tattoos, piercings, body art, body painting] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/6890484398428245875">
+ Body art
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_88" translateable="false" desc="Taxonomy Member. Meaning: [products and services meant to care for the face and body] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/2128681789762099558">
+ Face &amp; body care
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_89" translateable="false" desc="Taxonomy Member. Meaning: [Products that are designed to reduce perspiration or conceal unpleasant bodily odors.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/7677786914242125225">
+ Antiperspirants, deodorants &amp; body sprays
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_90" translateable="false" desc="Taxonomy Member. Meaning: [body lotions, body creams, body oils, body butters; body washes and scrubs; hand and feet care; bubble bath products, bath salts and body deodorants] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/3430584136022164066">
+ Bath &amp; body products
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_91" translateable="false" desc="Taxonomy Member. Meaning: [Clean beauty, also known as &quot;green&quot; or &quot;natural&quot;, includes any beauty product that self describes as ethically sourced, natural, non toxic, and/or organic ingredients.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/3706293287309434572">
+ Clean beauty
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_92" translateable="false" desc="Taxonomy Member. Meaning: [all types of makeup and cosmetics] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/20502649613022378">
+ Make-up &amp; cosmetics
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_93" translateable="false" desc="Taxonomy Member. Meaning: [nail polish, gel manicure products, nail appliques and nail art products, nail care tools, nail polish removers, etc.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/6743998850604648325">
+ Nail care products
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_94" translateable="false" desc="Taxonomy Member. Meaning: [perfumes, colognes and other fragrances meant for the body] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/7261881654549299715">
+ Perfumes &amp; fragrances
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_95" translateable="false" desc="Taxonomy Member. Meaning: [Instruments with a sharp blade, or combination of blades, used to remove or trim unwanted hair from the face or body; can be manual or electric.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/1837367248073548846">
+ Razors &amp; shavers
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_96" translateable="false" desc="Taxonomy Member. Meaning: [fashion media and publications, fashion design, style trends and advice] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/1220764295986807342">
+ Fashion &amp; style
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_97" translateable="false" desc="Taxonomy Member. Meaning: [personal fitness, calisthenic and cardiovascular exercising, aerobics, fitness as a lifestyle] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/3163088267288624590">
+ Fitness
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_98" translateable="false" desc="Taxonomy Member. Meaning: [weight lifting, free weights and use of mechanical weight to increase and exhibit muscle mass] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/8372304202830723542">
+ Bodybuilding
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_99" translateable="false" desc="Taxonomy Member. Meaning: [hair products; shampoos, conditioners, hair sprays, gels; also barbers and hair stylists] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/8521800725470611514">
+ Hair care
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_100" translateable="false" desc="Taxonomy Member. Meaning: [Umbrella category that encompasses books and magazines, either as printed matter or in online reproductions; book retailers and resellers; the literary arts in general, including authors, book-collecting, specific genres and types of literature, literary programs and journals.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/7203586559176706238">
+ Books &amp; literature
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_101" translateable="false" desc="Taxonomy Member. Meaning: [Books &amp; literature written for children.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/3549709581836871503">
+ Children&#x27;s literature
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_102" translateable="false" desc="Taxonomy Member. Meaning: [poetry, either or an amateur or professional nature; poetic works, discussion of these] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/8485083971562288882">
+ Poetry
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_103" translateable="false" desc="Taxonomy Member. Meaning: [Business services and industrial markets related to specific trades or specialized industries] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/1139636249987410701">
+ Business &amp; industrial
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_104" translateable="false" desc="Taxonomy Member. Meaning: [advertising, direct marketing, market research, public relations, etc.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/7743376233860216996">
+ Advertising &amp; marketing
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_105" translateable="false" desc="Taxonomy Member. Meaning: [the professional field of sales; salespersons, methods of selling, sales agents and agencies, sales management, etc] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/512193652870293151">
+ Sales
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_106" translateable="false" desc="Taxonomy Member. Meaning: [growth and management of flora and fauna as a business, including farming, ranching, horticulture and forestry] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/8652443110139521550">
+ Agriculture &amp; forestry
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_107" translateable="false" desc="Taxonomy Member. Meaning: [food manufacture, processing, production, packaging and distribution on an industrial scale; &quot;the food industry&quot;] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/1469567909605461312">
+ Food production
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_108" translateable="false" desc="Taxonomy Member. Meaning: [the design, engineering, manufacture, marketing and distribution of motor vehicles; news and media related to the auto industry itself, distinct from media and retailers oriented to a consumer audience] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/7558774116019975260">
+ Automotive industry
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_109" translateable="false" desc="Taxonomy Member. Meaning: [development, design, manufacture and operation of aircraft (not passenger flights in a travel context, or air cargo in a transportation context)] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/8310676113847687078">
+ Aviation industry
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_110" translateable="false" desc="Taxonomy Member. Meaning: [ongoing recurring activities involved in the running of a business for the purpose of producing value for the stakeholders; includes business processes and strategies, workforce and executive management, and business modeling] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/8504100719552366526">
+ Business operations
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_111" translateable="false" desc="Taxonomy Member. Meaning: [Flexible work arrangements empower an employee to choose what time they begin to work, where to work, and when they will stop work. The idea is to help manage work-life balance and benefits of FWA can include reduced employee stress and increased overall job satisfaction. (Source:Wikipedia)] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/4175404957300857059">
+ Flexible work arrangements
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_112" translateable="false" desc="Taxonomy Member. Meaning: [The &quot;people&quot; aspects of running a business; the professional activity of hiring and developing an organization&#x27;s staff, as well as the department of that organization that deals with human resources management (HRM).] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/4385620857212940765">
+ Human resources
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_113" translateable="false" desc="Taxonomy Member. Meaning: [lending funds to corporate bodies, local authorities and governments; commercial lenders offer loans backed by hard collateral; in most cases this is real estate, but it can also include factoring and other sources of collateral (source: Wikipedia)] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/5014141623827278146">
+ Commercial lending
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_114" translateable="false" desc="Taxonomy Member. Meaning: [construction of buildings and other structures, heavy construction (e.g. such as highways, power plants, and pipelines), additions, alterations, reconstruction, installation, and maintenance and repairs] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/7532452534944861030">
+ Construction &amp; maintenance
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_115" translateable="false" desc="Taxonomy Member. Meaning: [A professional engineering discipline that deals with the design, construction, and maintenance of the physical and naturally built environment, including works such as bridges, roads, canals, dams and buildings (source: Wikipedia); includes activities such as land surveying, structural engineering, geotechnical evaluation, etc.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/6864982936777789322">
+ Civil engineering
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_116" translateable="false" desc="Taxonomy Member. Meaning: [comprises government and commercial industry involved in research, development, production, and service of military material, equipment and facilities (source: Wikipedia)] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/1964667475519868379">
+ Defense industry
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_117" translateable="false" desc="Taxonomy Member. Meaning: [energy generation and development; technologies and the companies that are involved in energy production and distribution; private and public utilities] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/4707317595881518891">
+ Energy &amp; utilities
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_118" translateable="false" desc="Taxonomy Member. Meaning: [water industry and utilities; content related to public or commercial water supply, water quality, water management and water treatment; can include systems for water distribution, sanitation, and usage; also covers issues of water pollution and scarcity] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/238348257107156765">
+ Water supply &amp; treatment
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_119" translateable="false" desc="Taxonomy Member. Meaning: [public hospitality services industries including, but not limited to, hotels, food service, casinos, and tourism] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/7805678306890284096">
+ Hospitality industry
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_120" translateable="false" desc="Taxonomy Member. Meaning: [industrial production, in which raw materials are transformed into finished goods on a large scale] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/7545704483923797515">
+ Manufacturing
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_121" translateable="false" desc="Taxonomy Member. Meaning: [metals, minerals and ores; mining industry content] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/7055969384991602250">
+ Metals &amp; mining
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_122" translateable="false" desc="Taxonomy Member. Meaning: [Pharmaceuticals industry refers to drug discovery, development and manufacturing, and related medical research; biotechnology or biotech refers to the application of technology to biological materials for industrial or commercial use (for example, in biologically engineered food production)] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/681287532573248832">
+ Pharmaceuticals &amp; biotech
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_123" translateable="false" desc="Taxonomy Member. Meaning: [the printing and publishing industries; entities engaged in publishing and distributing newspapers, magazines, other periodicals, and books, as well as electronic materials; establishments involved in the manufacture, production, and distribution of print products, such as newspapers, books, periodicals, business forms, greeting cards, and other materials; includes companies that perform perform support activities, such as bookbinding, platemaking services, and data imaging (Source: ODP)] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/2613813704616662413">
+ Printing &amp; publishing
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_124" translateable="false" desc="Taxonomy Member. Meaning: [industries and establishments that focus primarily on providing products and services to retailers; the B2B aspect of retailing and merchandising; not meant for online shops, but rather associations and services servicing the retail industry] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/7797616431239921382">
+ Retail trade
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_125" translateable="false" desc="Taxonomy Member. Meaning: [private equity capital typically provided by professional, outside investors to new, high-potential-growth companies (startups) in exchange for equity, with an eye to profit from the company&#x27;s growth] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/7488525250137982815">
+ Venture capital
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_126" translateable="false" desc="Taxonomy Member. Meaning: [Umbrella category that encompasses computing hardware and software, consumer and non-consumer electronics, computing for business or personal use.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/8375584628751083797">
+ Computers &amp; electronics
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_127" translateable="false" desc="Taxonomy Member. Meaning: [software or tools to fight spyware, adware, trojan horses, viruses, worms, etc] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/3628161500907690952">
+ Antivirus &amp; malware
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_128" translateable="false" desc="Taxonomy Member. Meaning: [computer devices that are not part of the essential computer (the processor, memory, and data paths) but are situated relatively close by; typically, input and output devices to a host computer, expanding the host&#x27;s capabilities, but not forming part of the core computer architecture (Source: Wikipedia)] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/1309547678103520411">
+ Computer peripherals
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_129" translateable="false" desc="Taxonomy Member. Meaning: [electronic equipment intended for use by everyday people, not including computers] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/3831373972074857037">
+ Consumer electronics
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_130" translateable="false" desc="Taxonomy Member. Meaning: [cameras and camcorders, including retailers, related information, etc.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/4178771562445010882">
+ Cameras &amp; camcorders
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_131" translateable="false" desc="Taxonomy Member. Meaning: [Devices and software that allow users to control home lighting, sound systems, monitor or control appliances, operate home security systems, etc., typically remotely.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/7697871506067940404">
+ Home automation
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_132" translateable="false" desc="Taxonomy Member. Meaning: [television and video equipment designed to reproduce at home the experience of being in a movie theater; includes home entertainment systems and related equipment] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/4678594450183827584">
+ Home theater systems
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_133" translateable="false" desc="Taxonomy Member. Meaning: [Wearable products and devices that incorporate computer and advanced electronic technologies.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/5536255386518952322">
+ Wearable technology
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_134" translateable="false" desc="Taxonomy Member. Meaning: [a desktop computer is a personal computer (PC) in a hardware configuration that makes it suitable for regular use at a fixed location, as opposed to a laptop or other mobile devices (source: Wikipedia); includes mini PCs] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/6925354490648875732">
+ Desktop computers
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_135" translateable="false" desc="Taxonomy Member. Meaning: [personal computers designed for mobile use such as laptops, notebooks, and ultraportable PCs; includes 2-in-1 laptops, and Chromebooks] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/4367973428696769541">
+ Laptops &amp; notebooks
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_136" translateable="false" desc="Taxonomy Member. Meaning: [computing network security solutions, services, tools: firewalls, intrusion detection systems, denial of service prevention, etc] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/1806105062543621981">
+ Network security
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_137" translateable="false" desc="Taxonomy Member. Meaning: [the engineering discipline concerned with the communication between computer systems or devices; a computer network is any set of computers or devices connected to each other with the ability to exchange data (source: Wikipedia)] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/3957825689644527533">
+ Networking
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_138" translateable="false" desc="Taxonomy Member. Meaning: [The practice of using a network of remote servers hosted on the Internet to store, manage, and process data, rather than a local server or a personal computer; the study and production of distributed systems, consisting of multiple autonomous computers that communicate through a computer network; includes concepts such as parallel, cluster and grid computing; high-performance computing which uses supercomputers and computer clusters to solve advanced computation problems (source: Wikipedia).] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/3248986129510004039">
+ Distributed &amp; cloud computing
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_139" translateable="false" desc="Taxonomy Member. Meaning: [the process of writing, testing, debugging/troubleshooting, and maintaining software] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/7282364022001656702">
+ Programming
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_140" translateable="false" desc="Taxonomy Member. Meaning: [software refers to the programs and other operating information used by a computer; includes software applications and utilities, operating systems, etc.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/7409717756718834230">
+ Software
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_141" translateable="false" desc="Taxonomy Member. Meaning: [software for use in sound production, recording, editing, and playback; also includes audio player software, digital audio workstation software, music composition and notation software, instrument simulation software, virtual synthesizer and studio software etc.; popular examples include Audacity, GarageBand, and Pro Tools] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/2121682951166241388">
+ Audio &amp; music software
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_142" translateable="false" desc="Taxonomy Member. Meaning: [desktop publishing is the creation of documents and publications that are properly formatted for print or electronic distribution; desktop publishing software can generate layouts and produce typographic quality text and images comparable to traditional typography and printing (source: Wikipedia); popular examples include Adobe InDesign, Microsoft Publisher, QuarkXPress, Serif PagePlus, and Scribus] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/1855224727519238778">
+ Desktop publishing
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_143" translateable="false" desc="Taxonomy Member. Meaning: [freely available software, for general public use, typically available by download at no cost to the user or for an optional fee; this category is intended primarily for software content that advertises itself explicitly as free; includes web properties that aggregate free software content] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/7474871584167254699">
+ Freeware &amp; shareware
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_144" translateable="false" desc="Taxonomy Member. Meaning: [software for creating or manipulating visual images, graphics and/or animations; popular examples include CorelDraw, SketchBook, Adobe Illustrator, Inkscape, and Autodesk Maya] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/2050639293586889823">
+ Graphics &amp; animation software
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_145" translateable="false" desc="Taxonomy Member. Meaning: [An operating system (OS) is software, consisting of programs and data, that runs on computers to manage the computer&#x27;s hardware and provide common services for efficient execution of various application software (Source: WIkipedia). Includes content related to various operating systems, various OS architectures and subcomponents, process management, etc.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/5212139084339403436">
+ Operating systems
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_146" translateable="false" desc="Taxonomy Member. Meaning: [software used to manage or organize photo collections; software used to edit or retouch digital photos; popular examples include iPhoto, Adobe Photoshop, and Corel PaintShop Pro; includes related utilities and plug-ins] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/89992876854779967">
+ Photo software
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_147" translateable="false" desc="Taxonomy Member. Meaning: [software for use in video production, recording, editing, and playback; also includes video player software, digital video workstation software; examples include Windows Movie Maker, iMovie, and Adobe After Effects] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/8159620650642307448">
+ Video software
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_148" translateable="false" desc="Taxonomy Member. Meaning: [Applications designed for browsing the web/internet. Web browsers enable users to access, navigate and interact with text, images, video and other media and information found on a web page located on the internet. Popular examples include Google Chrome, Internet Explorer, and Mozilla Firefox.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/5184464415905481973">
+ Web browsers
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_149" translateable="false" desc="Taxonomy Member. Meaning: [Umbrella category that encompasses consumer and business financial services, such as banking, loans, credit, investing, insurance, etc.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/2844460539416377578">
+ Finance
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_150" translateable="false" desc="Taxonomy Member. Meaning: [services that combine various kinds of bookkeeping and accounting activities; products and services aiming at tracking business income and expenses and answer specific questions about the financial and tax status of an individual or business] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/956251474921720097">
+ Accounting &amp; auditing
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_151" translateable="false" desc="Taxonomy Member. Meaning: [services that provide tax preparation or prepare taxes for people; includes advice and tips for both tax preparation.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/4760464649248515637">
+ Tax preparation &amp; planning
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_152" translateable="false" desc="Taxonomy Member. Meaning: [credit and debit card companies, offers and reviews] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/3200267103650246507">
+ Credit cards
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_153" translateable="false" desc="Taxonomy Member. Meaning: [broadly, investment services and financial planning services; includes portfolio management planning and services; professional financial services oriented toward wealth management, estate planning or asset protection; professional money managers often carry the CFP (Certified Financial Planner) designation] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/5880850679805616279">
+ Financial planning &amp; management
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_154" translateable="false" desc="Taxonomy Member. Meaning: [planning for retirement, pension plans, annuities, individual retirement accounts, 401k, pensions, social security, etc.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/8609879096232646964">
+ Retirement &amp; pension
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_155" translateable="false" desc="Taxonomy Member. Meaning: [public and private grants, fellowships, and other sources of public funding or financial assistance for special projects and/or business, educational or organizational pursuits] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/34160357033579408">
+ Grants, scholarships &amp; financial aid
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_156" translateable="false" desc="Taxonomy Member. Meaning: [financial support and other grants, both private and governmental, that are awarded to support academic study; unlike student loans, there is no expectation of eventual debt repayment; includes information, such as advice from users and experts and reviews of financial programs] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/1870017364785985714">
+ Study grants &amp; scholarships
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_157" translateable="false" desc="Taxonomy Member. Meaning: [mortgages and mortgage companies; home loans and lenders; the process of procuring financing to purchase a home or other residential real estate] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/5118652265814965911">
+ Home financing
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_158" translateable="false" desc="Taxonomy Member. Meaning: [insurance agents, carriers and claims; actuarial science &amp; services; financial guaranty; risk management] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/3741900859008836651">
+ Insurance
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_159" translateable="false" desc="Taxonomy Member. Meaning: [motor vehicle insurance; insurance for cars and trucks] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/4604321306087491479">
+ Auto insurance
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_160" translateable="false" desc="Taxonomy Member. Meaning: [insurance coverage for medical expenses, health insurance providers who either directly reimburse the insured party or pay the medical care providers for any financial liability incurred from illness or injury] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/1117176005604181710">
+ Health insurance
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_161" translateable="false" desc="Taxonomy Member. Meaning: [the type of property insurance that covers private homes; fire insurance, burglary insurance, earthquake insurance, flood insurance, acts of god insurance, tornado insurance, weather-related insurance, hurricane insurance, breaking and entry insurance, b &amp; e insurance, property insurance, renters insurance] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/9147523895969579006">
+ Home insurance
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_162" translateable="false" desc="Taxonomy Member. Meaning: [a contract between an insurance policy holder and an insurer, where the insurer promises to pay a designated beneficiary a sum of money (the &quot;benefits&quot;) upon the death of the insured person (Source: Wikipedia)] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/8531475784994978055">
+ Life insurance
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_163" translateable="false" desc="Taxonomy Member. Meaning: [insurance that is intended to cover medical expenses, financial default of travel suppliers, and other losses incurred while traveling, either within one&#x27;s own country, or internationally (Source: Wikipedia)] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/637641992572614367">
+ Travel insurance
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_164" translateable="false" desc="Taxonomy Member. Meaning: [products, information and services centered around securities (like stocks, bonds, or mutual funds), commodities, derivative, or real-estate trusts] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/8494705151771539693">
+ Investing
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_165" translateable="false" desc="Taxonomy Member. Meaning: [content about commodities, futures, derivatives, and options on futures; also, investing and trading in precious metals (distinct from industrial extraction services: see &quot;Metals &amp; Mining&quot;)] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/3111774353950510496">
+ Commodities &amp; futures trading
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_166" translateable="false" desc="Taxonomy Member. Meaning: [currency conversion and exchange; FOREX brokerages, guides, research and analysis] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/6961181346456305845">
+ Currencies &amp; foreign exchange
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_167" translateable="false" desc="Taxonomy Member. Meaning: [investment funds that can undertake a wider range of investment and trading activities than other funds, but which is only open for investment from particular types of investors specified by regulators; these investors are typically institutions, such as pension funds, university endowments and foundations, or high net worth individuals; hedge funds invest in a diverse range of assets, but they most commonly trade liquid securities on public markets; they also employ a wide variety of investment strategies, and make use of techniques such as short selling and leverage (Source: WIkipedia)] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/7606689751494500303">
+ Hedge funds
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_168" translateable="false" desc="Taxonomy Member. Meaning: [mutual funds are professionally managed types of collective investment schemes that pool money from many investors to buy stocks, bonds, short-term money market instruments, and/or other securities (Source: Wikipedia)] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/8368907615403624994">
+ Mutual funds
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_169" translateable="false" desc="Taxonomy Member. Meaning: [content related to stocks, bonds, and other securities; news, research and resources about securities and exchanges, equities and bond markets] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/2272646388087840746">
+ Stocks &amp; bonds
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_170" translateable="false" desc="Taxonomy Member. Meaning: [personal loans commonly refers to unsecured consumer lending, signature loans or unsecured loans; these loans are often used by borrowers for small purchases such as computers, home improvements, vacations or unexpected expenses, like medical bills (Source: Wikipedia)] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/7274332815460521387">
+ Personal loans
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_171" translateable="false" desc="Taxonomy Member. Meaning: [loans designed to help students pay for post-secondary education and the associated fees, such as tuition, books and supplies, and living expenses (source: Wikipedia)] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/779541846953867896">
+ Student loans &amp; college financing
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_172" translateable="false" desc="Taxonomy Member. Meaning: [Umbrella category that encompasses food and beverages, including cooking, dining, shopping for and serving food.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/2872488089978390528">
+ Food &amp; drink
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_173" translateable="false" desc="Taxonomy Member. Meaning: [content related to cooking, recipes, and various world cuisines] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/8247360513054075859">
+ Cooking &amp; recipes
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_174" translateable="false" desc="Taxonomy Member. Meaning: [barbecue or barbeque (abbreviated BBQ, Bar-B-Q and Barbie); methods and recipes for firing, smoking and grilling meat and other foods with the heat and hot smoke of a fire, smoking wood, hot coals of charcoal, or liquefied petroleum gas; a popular American, Canadian, and Australian cooking method and cuisine (Source: Wikipedia)] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/1019199934861093311">
+ BBQ &amp; grilling
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_175" translateable="false" desc="Taxonomy Member. Meaning: [content about global, ethnic and regional cuisines; recipes and dishes originating from a distinct world region or culture; a set of cooking traditions and dishes centered around certain regional staples and cooking ingredients] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/2546001021118496817">
+ Cuisines
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_176" translateable="false" desc="Taxonomy Member. Meaning: [vegetarian cuisine, food, and recipes; meatless diets and meat substitutes] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/2591240715795040171">
+ Vegetarian cuisine
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_177" translateable="false" desc="Taxonomy Member. Meaning: [vegan cuisine, food, and recipes; diets avoiding not only meat but also egg and dairy products and other animal-derived foodstuffs] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/1273341416820374939">
+ Vegan cuisine
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_178" translateable="false" desc="Taxonomy Member. Meaning: [recipes, menus, resources and tips for healthy cooking, eating and diet; cooking and eating with a mind to improving health and nutrition] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/8449517581244298760">
+ Healthy eating
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_179" translateable="false" desc="Taxonomy Member. Meaning: [grocery stores, grocers, supermarkets, food markets and other food retailers; includes major food retail chains] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/1431338466612002800">
+ Food &amp; grocery retailers
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_180" translateable="false" desc="Taxonomy Member. Meaning: [Any activity commonly referred to as a game (except sports). This includes computer and video games, board games, roleplaying games, and card games.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/8091337557500824334">
+ Games
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_181" translateable="false" desc="Taxonomy Member. Meaning: [Games played with a cue stick and various numbers of balls on a cloth-covered table. Examples include pool, snooker, and carom billiards.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/8987183253095541102">
+ Billiards
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_182" translateable="false" desc="Taxonomy Member. Meaning: [any game which uses cards (of any sort) as its primary gameplay device] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/3594644188208961363">
+ Card games
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_183" translateable="false" desc="Taxonomy Member. Meaning: [any electronic game that uses a video screen to display gameplay, whether through a computer, game console, or portable device such as a tablet or phone] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/352068353645394673">
+ Computer &amp; video games
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_184" translateable="false" desc="Taxonomy Member. Meaning: [Games that emphasize physical challenges, including hand-eye coordination and reaction-time; platform games are an important sub-genre of action games characterized by jumping to and from suspended platforms or over obstacles (Source: Wikipedia). Popular franchises that incorporate the action genre are Grand Theft Auto, Fallout, League of Legends, and Batman: Arkham. Popular platformers include: Super Mario, Portal, Mega Man, and Temple Run.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/1257305188757693991">
+ Action &amp; platform games
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_185" translateable="false" desc="Taxonomy Member. Meaning: [Games with an interactive story that emphasize exploration and puzzle-solving. Examples include classic text adventures (e.g. the Zork trilogy), graphical adventure games (e.g. Myst), point-and-click adventures, room escape games, and visual novels. The action-adventure genre is a common hybrid, and includes games such as The Legend of Zelda and Assassin&#x27;s Creed.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/2982814953690299324">
+ Adventure games
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_186" translateable="false" desc="Taxonomy Member. Meaning: [Games with extremely simple gameplay that are targeted to a mass audience and typically playable over short sessions. These include Tetris, Bejeweled, Angry Birds, Candy Crush Saga, Pac-Man, and Diner Dash.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/376563557744501929">
+ Casual games
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_187" translateable="false" desc="Taxonomy Member. Meaning: [Organized competitions between professional or amateur computer and video game players, also known as eSports (source: Wikipedia).] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/8171522680026276978">
+ Competitive video gaming
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_188" translateable="false" desc="Taxonomy Member. Meaning: [Games which support thousands or more players simultaneously in the same, often persistent, game world. Examples include World of Warcraft, Clash of Clans, Roblox, and Club Penguin. Does not include online games that support relatively few simulatenous players such as League of Legends and Defense of the Ancients 2.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/7491951684925589000">
+ Massively multiplayer games
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_189" translateable="false" desc="Taxonomy Member. Meaning: [music and dance related games, in which gameplay typically requires keeping time with musical rhythm; signature game series include Guitar Hero, Dance Dance Revolution, Bust a Groove, etc.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/7279671314928001151">
+ Music &amp; dance games
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_190" translateable="false" desc="Taxonomy Member. Meaning: [A simulation video game describes a diverse super-category of video games, generally designed to closely simulate real world activities.(source: Wikipedia)] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/1026664265024410095">
+ Simulation games
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_191" translateable="false" desc="Taxonomy Member. Meaning: [simulated video games depicting an indoor or outdoor sports game or activity according to rules] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/3944988229755250972">
+ Sports games
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_192" translateable="false" desc="Taxonomy Member. Meaning: [Games that focus on skillful thinking and planning, often featuring a god-like view of the game world where the player controls units under their command. Overlaps with multiplayer online battle arenas (MOBAs) and tactics-based games. Examples include Civilization, Worms, Warcraft, League of Legends, Defense of the Ancients (DotA), and Fire Emblem.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/1922669055530508308">
+ Strategy games
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_193" translateable="false" desc="Taxonomy Member. Meaning: [games and activities that feature painting, drawing, or coloring] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/4129327327046722216">
+ Drawing &amp; coloring
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_194" translateable="false" desc="Taxonomy Member. Meaning: [games in which players assume the roles of fictional characters and collaboratively create or follow stories; also known as RPGs] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/5381848811946741579">
+ Roleplaying games
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_195" translateable="false" desc="Taxonomy Member. Meaning: [a sport in which two or four players hit a lightweight, hollow ball back and forth to each other with paddles over a hard table divided by a net; often called &quot;ping pong&quot;] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/2947570596592037239">
+ Table tennis
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_196" translateable="false" desc="Taxonomy Member. Meaning: [Umbrella category that encompasses recreational, leisure and lifestyle pastimes and hobbies] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/8047450332599359680">
+ Hobbies &amp; leisure
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_197" translateable="false" desc="Taxonomy Member. Meaning: [the commemorative day that celebrates a past wedding, engagement or beginning of a romantic relationship; gifts and activities related to these anniversaries; does not include other anniversaries of personal of historical importance] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/4384284280905147881">
+ Anniversaries
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_198" translateable="false" desc="Taxonomy Member. Meaning: [the anniversary of one&#x27;s birth or a particular day of the year associated with one&#x27;s given name; birthday and name day gifts, celebrations, events and occasions] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/1900888872496185732">
+ Birthdays &amp; name days
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_199" translateable="false" desc="Taxonomy Member. Meaning: [underwater activities including diving, scuba, snorkeling, finswimming, etc] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/3865005762986696510">
+ Diving &amp; underwater activities
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_200" translateable="false" desc="Taxonomy Member. Meaning: [those arts and crafts that use plant, animal, or synthetic fibers to construct practical or decorative objects; also, a style of fine art which uses textiles such as fabric, yarn, and natural and synthetic fibers; includes needlework, quilting, and other fabric arts (Source: Wikipedia)] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/7320750072644192681">
+ Fiber &amp; textile arts
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_201" translateable="false" desc="Taxonomy Member. Meaning: [outdoor recreation; not generally to include athletic or recreational fitness activities like running, cycling, swimming, etc.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/152463061722515936">
+ Outdoors
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_202" translateable="false" desc="Taxonomy Member. Meaning: [fishing as sports or recreation] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/2939899117911867601">
+ Fishing
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_203" translateable="false" desc="Taxonomy Member. Meaning: [all types of hunting for sport, both in competition and for recreation; also, recreation shooting, to include archery, target and skeet shooting] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/166910095049954514">
+ Hunting &amp; shooting
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_204" translateable="false" desc="Taxonomy Member. Meaning: [paintball and airsoft (games in which players eliminate opponents by hitting them with dye-filled paintballs or other non-metallic pellets)] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/6981728230205859504">
+ Paintball
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_205" translateable="false" desc="Taxonomy Member. Meaning: [remotely controlled model cars, boats, airplanes, etc.; hobby model building and other miniature and to-scale models] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/3363466958969091079">
+ Radio control &amp; modeling
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_206" translateable="false" desc="Taxonomy Member. Meaning: [weddings and marriage ceremonies; wedding planning, wedding ceremonies, wedding apparel, wedding gifts, etc.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/7365440755144867425">
+ Weddings
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_207" translateable="false" desc="Taxonomy Member. Meaning: [Umbrella category that encompasses products and services for the home, yard, garden and outdoor environs.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/2066460565081379253">
+ Home &amp; garden
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_208" translateable="false" desc="Taxonomy Member. Meaning: [Gardening resources, supplies and equipment (e.g. pruning shears, gardening gloves, etc.)] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/8054463204383392781">
+ Gardening
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_209" translateable="false" desc="Taxonomy Member. Meaning: [decorations for the home and residential interior; household organization and do-it-yourself projects for the home; examples: Good Housekeeping and Martha Stewart] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/8420059947372759747">
+ Home &amp; interior decor
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_210" translateable="false" desc="Taxonomy Member. Meaning: [electrical or mechanical appliances which accomplish some household functions, such as cooking, cleaning, washing, etc] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/4409326960448405254">
+ Home appliances
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_211" translateable="false" desc="Taxonomy Member. Meaning: [products, services and resources related to home repair, remodeling and renovation] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/4935350966824227117">
+ Home improvement
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_212" translateable="false" desc="Taxonomy Member. Meaning: [content related to products and services to secure the home in event of crime, disaster or emergency; to include smoke detectors and alarms, fire extinguishers, home safes, etc.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/7593630526179557624">
+ Home safety &amp; security
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_213" translateable="false" desc="Taxonomy Member. Meaning: [Consumable items for the home, including products for food storage, laundry, house cleaning, and waste disposal.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/7677533781953817028">
+ Household supplies
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_214" translateable="false" desc="Taxonomy Member. Meaning: [Landscape design, landscape architecture and site enhancement, i.e. the improvement of the aesthetic appearance of outdoor areas, landmarks, and structures by changing its contours, adding ornamental features, or planting trees and shrubs. (Source: Wikipedia.)] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/7629152298955251873">
+ Landscape design
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_215" translateable="false" desc="Taxonomy Member. Meaning: [products and services that allow users to communicate through internet, telephony, cable, and radio; access providers and other services that enable or supplement web navigation, web publishing, web monetization, or web communication] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/2440988220307383672">
+ Internet &amp; telecom
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_216" translateable="false" desc="Taxonomy Member. Meaning: [An email service provider, mailbox provider, or mail service provider is a provider of email hosting. It implements email servers to send, receive, accept, and store email for other organizations or end users, on their behalf. (Source: Wikipedia)] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/1987431586656129541">
+ Email
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_217" translateable="false" desc="Taxonomy Member. Meaning: [Internet access plans, including dial-up, DSL, cable modem, wireless or dedicated high-speed access, and the companies that provide users with them.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/4822825857214982005">
+ ISPs
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_218" translateable="false" desc="Taxonomy Member. Meaning: [Plans and services for phones, whether landline or mobile. Companies that facilitate landline telephone service and provide long distance or local calling plans, as well as wireless carriers. Also includes mobile broadband providers.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/8095959427480563136">
+ Phone service providers
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_219" translateable="false" desc="Taxonomy Member. Meaning: [a system that allows users to search for information on the internet such as Google, Bing, Yahoo! Search, etc.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/1055826165163308557">
+ Search engines
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_220" translateable="false" desc="Taxonomy Member. Meaning: [a mobile phone offering advanced capabilities beyond calling and texting, such as music playback, cameras, internet connection, etc.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/4069828937326256925">
+ Smart phones
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_221" translateable="false" desc="Taxonomy Member. Meaning: [a conference with participants in different locations linked by telecommunications devices; teleconferencing or videoconferencing can happen over the phone, internet, video, etc; includes teleconferencing and videoconferencing equipment, services and technologies] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/5386101597996462971">
+ Teleconferencing
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_222" translateable="false" desc="Taxonomy Member. Meaning: [mobile and web-based text, image, and multimedia messaging technology (i.e. texting, instant messaging, SMS, and MMS); includes apps and services such as WhatsApp, Facebook Messenger, WeChat, etc.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/4406295034200984908">
+ Text &amp; instant messaging
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_223" translateable="false" desc="Taxonomy Member. Meaning: [applications that are accessed via web browser; also, computer software applications that are coded in a browser-supported language (such as HTML, JavaScript, Java, etc.) and reliant on a common web browser to render the applications executable (source: Wikipedia)] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/8151692501266701245">
+ Web apps &amp; online tools
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_224" translateable="false" desc="Taxonomy Member. Meaning: [The creation and development of websites, which encompass aspects such as page layout, typography, content development, user experience design, graphic design, etc.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/3824728791744408878">
+ Web design &amp; development
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_225" translateable="false" desc="Taxonomy Member. Meaning: [services that allow users to set up their own website and make it accessible via the World Wide Web, usually by providing storage space on a server] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/4300487829870464543">
+ Web hosting
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_226" translateable="false" desc="Taxonomy Member. Meaning: [Umbrella category that encompasses all content about education, jobs, careers, or vocational training.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/4517581546201111862">
+ Jobs &amp; education
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_227" translateable="false" desc="Taxonomy Member. Meaning: [educational institutions, process and practice] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/4419501367263333275">
+ Education
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_228" translateable="false" desc="Taxonomy Member. Meaning: [Conferences and related events for researchers and academics to present and discuss their work; academic or scientific journals (academic work published in journal article, book or thesis form); also, the subfield of publishing which distributes academic research and scholarship (source: Wikipedia).] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/8052702820668451885">
+ Academic conferences &amp; publications
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_229" translateable="false" desc="Taxonomy Member. Meaning: [Public and private colleges and universities; educational institutions at the tertiary level and beyond. Includes community and junior colleges, as well as graduate programs.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/6351926515676847103">
+ Colleges &amp; universities
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_230" translateable="false" desc="Taxonomy Member. Meaning: [Educational opportunities and resources available for students who are not physically present at a school, typically for the purpose of completing a degree. Distance learning is often conducted online or by mail: using correspondence, audio and video media, software, study guides, online discussion groups, e-mail, etc. Does not include micro-courses and massive online courses (MOOCs) that cannot be taken towards a university degree.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/1866911147020514155">
+ Distance learning
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_231" translateable="false" desc="Taxonomy Member. Meaning: [Pre-school and kindergarten; training, curriculum, sites and organizations for the education for very young children] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/1010499748215693913">
+ Early childhood education
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_232" translateable="false" desc="Taxonomy Member. Meaning: [The education of children between the ages of 0-5 years old, prior to the commencement of compulsory education at primary school. In the United Kingdom it is called nursery school. In the United States the terms &#x27;preschool&#x27; and &#x27;Pre-K&#x27; (pre-Kindergarten) are used (source: Wikipedia).] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/3090218931101237041">
+ Preschool
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_233" translateable="false" desc="Taxonomy Member. Meaning: [the education of children at home and in the community (typically by parents, co-ops or professional tutors), as opposed to in a public or private school] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/2544571709434028206">
+ Homeschooling
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_234" translateable="false" desc="Taxonomy Member. Meaning: [standardized testing, including admissions testing, skills evaluation testing and other professional evaluations; products and services relating to the preparation for standardized examinations] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/9085661686341876683">
+ Standardized &amp; admissions tests
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_235" translateable="false" desc="Taxonomy Member. Meaning: [trade schools, vocational training, refresher courses, continuing education, adult education, extension courses, community enrichment courses] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/6766705594535058513">
+ Vocational &amp; continuing education
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_236" translateable="false" desc="Taxonomy Member. Meaning: [general umbrella category for employment services and job listings, career and vocational information] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/7834393844464998277">
+ Jobs
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_237" translateable="false" desc="Taxonomy Member. Meaning: [advice and resources for career enhancement, career selection and exploration of career choices] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/1446641408166840112">
+ Career resources &amp; planning
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_238" translateable="false" desc="Taxonomy Member. Meaning: [listings of employment opportunities, job portals, and content which provides job seekers with information which specifically relates to finding a job, as opposed to career related information or resumes] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/5816374402436936189">
+ Job listings
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_239" translateable="false" desc="Taxonomy Member. Meaning: [umbrella category that covers legal, government, military, public safety, and social institutions and services] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/2081116017671486756">
+ Law &amp; government
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_240" translateable="false" desc="Taxonomy Member. Meaning: [crime and punishment: penal code and prison system, judicial sentencing, criminal activities, etc.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/6921091197595128322">
+ Crime &amp; justice
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_241" translateable="false" desc="Taxonomy Member. Meaning: [law-related content, to include: law firms, legal information, primary legal materials, paralegal services, legal publications and technology, expert witnesses, litigation consultants, and other legal service providers] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/2207448743982657883">
+ Legal
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_242" translateable="false" desc="Taxonomy Member. Meaning: [specific lawyers and law firms; also, legal consultants and legal service providers providing services to legal professionals] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/7714825855460112240">
+ Legal services
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_243" translateable="false" desc="Taxonomy Member. Meaning: [Coverage of current developments in local and world affairs, politics, sports, business and finance, technology and gossip.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/8973913434480581401">
+ News
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_244" translateable="false" desc="Taxonomy Member. Meaning: [news on the state of national and global economies; economic trends, official statistics and indicators; consumer and employment reports] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/2709641167996618879">
+ Economy news
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_245" translateable="false" desc="Taxonomy Member. Meaning: [news coverage of interest to a smaller geographic area, town, city, region or state; newspapers or broadcast news outlets that focus a significant amount of coverage on the city, metro, county or local level] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/5789359360876243217">
+ Local news
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_246" translateable="false" desc="Taxonomy Member. Meaning: [the aspect of corporate strategy, corporate finance and management dealing with the buying, selling and combining of different companies that can finance a company in a given industry or help it grow rapidly without having to create another business entity\r\n\r\n(Source: Wikipedia.)] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/5017727352413071511">
+ Mergers &amp; acquisitions
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_247" translateable="false" desc="Taxonomy Member. Meaning: [political news and media; discussions of social, governmental and public policy] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/4917746638767225325">
+ Politics
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_248" translateable="false" desc="Taxonomy Member. Meaning: [weather forecasting and prediction in a news context; weather reports and related news] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/2014352108522339782">
+ Weather
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_249" translateable="false" desc="Taxonomy Member. Meaning: [news content roughly corresponding to the &quot;world news&quot; sections of major news outlets like the BBC, New York Times, and CNN; news stories related to events that involve multiple nations or representatives of multiple nations, or that have a global impact] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/1205620894610060765">
+ World news
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_250" translateable="false" desc="Taxonomy Member. Meaning: [Groups of people, usually with common interests, whose members interact with each other primarily via the internet. Online communities can act as information systems where members can post, comment on discussions, give advice or collaborate. Commonly, people communicate through social networking sites, chat rooms, forums, email lists and discussion boards. People may also join online communities through video games, blogs and virtual worlds.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/6671943044295819214">
+ Online communities
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_251" translateable="false" desc="Taxonomy Member. Meaning: [services and networks that help people find partners; dating chats, personal ads, photo rating, matchmaking services] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/467538341939407273">
+ Dating &amp; personals
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_252" translateable="false" desc="Taxonomy Member. Meaning: [A space for holding discussions and posting user-generated content. Providers of message board and chat services; not to be confused with single-topic forums.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/8377469718949969520">
+ Forum &amp; chat providers
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_253" translateable="false" desc="Taxonomy Member. Meaning: [A dedicated website or application built around a network of linked user profiles; users communicate with each other by posting information, comments, messages, images, etc. Well-known examples include Facebook, VKontakte, LinkedIn etc.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/2936561296339527677">
+ Social networks
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_254" translateable="false" desc="Taxonomy Member. Meaning: [Umbrella category that encompasses social groups and social issues based on personal identity, cultural traditions, family, faith and personal beliefs; &quot;special interest&quot; groups and communities; communities based on age, gender, ethnicity, religion, political affiliation or lifestyle choice; the scientific study of people and social groups in the &quot;social sciences&quot;.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/5098251294806643822">
+ People &amp; society
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_255" translateable="false" desc="Taxonomy Member. Meaning: [interpersonal relationships, including family, friendship and romance] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/1748891129952062597">
+ Family &amp; relationships
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_256" translateable="false" desc="Taxonomy Member. Meaning: [the study of family histories, including specific family surnames, genealogy products and services, etc.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/2218134745113599491">
+ Ancestry &amp; genealogy
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_257" translateable="false" desc="Taxonomy Member. Meaning: [the institution of marriage; includes marital issues and lifestyle, getting married and staying married, etc.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/3824857850796360612">
+ Marriage
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_258" translateable="false" desc="Taxonomy Member. Meaning: [pregnancy and maternity; baby and child care; parenting and child rearing] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/1488150639148112584">
+ Parenting
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_259" translateable="false" desc="Taxonomy Member. Meaning: [agencies, organizations, facilitators and other resources that deal with child adoption and fostering] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/3454817014379856183">
+ Adoption
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_260" translateable="false" desc="Taxonomy Member. Meaning: [products and services for newborns, babies, and children between the ages of one and three; content related to care and nurture of children in the first years of their life] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/4781411966627663176">
+ Babies &amp; toddlers
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_261" translateable="false" desc="Taxonomy Member. Meaning: [Content about making the internet a safe place for children and young people. Includes parental controls, monitoring services, educational resources, etc.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/5965261215029338496">
+ Child internet safety
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_262" translateable="false" desc="Taxonomy Member. Meaning: [content appealing to science fiction and fantasy fans] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/279327516333715085">
+ Science fiction &amp; fantasy
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_263" translateable="false" desc="Taxonomy Member. Meaning: [Umbrella category that encompasses pets, wildlife, and associated resources and services; does not apply in zoological or agricultural contexts (e.g., does not apply to scientific literature about primate behavior; commercial pig farming content, etc.)] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/1341220933436852053">
+ Pets &amp; animals
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_264" translateable="false" desc="Taxonomy Member. Meaning: [products used to feed, house, train, entertain, or care for pets including mammals, fish, insects, reptiles and birds] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/5726544825531472420">
+ Pet food &amp; pet care supplies
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_265" translateable="false" desc="Taxonomy Member. Meaning: [pets; domesticated and companion animals] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/4459727713618527003">
+ Pets
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_266" translateable="false" desc="Taxonomy Member. Meaning: [birds kept as pets; care of birds; bird breeding and bird enthusiasts] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/863515016486438782">
+ Birds
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_267" translateable="false" desc="Taxonomy Member. Meaning: [cats kept as pets; care of cats; cat breeding and cat enthusiasts] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/5655262829025444474">
+ Cats
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_268" translateable="false" desc="Taxonomy Member. Meaning: [dogs kept as pets; care of dogs; dog breeding and dog enthusiasts] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/1561957233914013210">
+ Dogs
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_269" translateable="false" desc="Taxonomy Member. Meaning: [fish kept as pets; freshwater and saltwater aquatic animals kept in aquaria; fishkeeping and aquarium hobbyists] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/4279675338672759481">
+ Fish &amp; aquaria
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_270" translateable="false" desc="Taxonomy Member. Meaning: [reptiles and amphibians kept as pets; to include pet snakes, lizards, turtles, frogs, etc; herpetology and reptile husbandry] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/3251873092249745541">
+ Reptiles &amp; amphibians
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_271" translateable="false" desc="Taxonomy Member. Meaning: [veterinarians and veterinary science; professionals and professional services involved in the prevention and treatment of animal disease and all the health issues of animals; the improvement of animal husbandry] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/8243386205257498259">
+ Veterinarians
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_272" translateable="false" desc="Taxonomy Member. Meaning: [Umbrella category that encompasses any products or services related to real estate, such as real estate agencies, listings, appraisals, inspections, etc.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/8519643931661372774">
+ Real estate
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_273" translateable="false" desc="Taxonomy Member. Meaning: [listings and content related to undeveloped land, lots and acreage; includes farmland, hunting properties, building parcels] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/1719753255024203063">
+ Lots &amp; land
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_274" translateable="false" desc="Taxonomy Member. Meaning: [vacation property for sale, timeshare properties, second homes, etc.; excludes vacation property rentals] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/883294268497665400">
+ Timeshares &amp; vacation properties
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_275" translateable="false" desc="Taxonomy Member. Meaning: [Umbrella category that encompasses reference material such as dictionaries, thesauruses, encyclopedias, directories, language and grammar resources, faqs, tutorials; also, educational materials relevant to specific disciplines like the humanities, sciences and social sciences.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/2827195501070385944">
+ Reference
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_276" translateable="false" desc="Taxonomy Member. Meaning: [Materials whose primary purpose is to facilitate learning (e.g. textbooks, educational videos, etc); collections of information intended to educate. Does not include content related to lesson planning, classroom management, thematic units, or resources for teachers to prepare lectures and classes.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/8343639099956376061">
+ Educational resources
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_277" translateable="false" desc="Taxonomy Member. Meaning: [foreign language education; education resources for non-native speakers of a second (or third, etc) language; specifically, foreign language courses, tutoring, and self-teaching education software] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/11328112605926338">
+ Foreign language study
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_278" translateable="false" desc="Taxonomy Member. Meaning: [FAQs, help content, tutorials, expert content, do-it-yourself content, how-to content] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/6600033035270447997">
+ How-to, DIY &amp; expert content
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_279" translateable="false" desc="Taxonomy Member. Meaning: [Umbrella category that encompasses the natural sciences, e.g. physics, life sciences, earth sciences, mathematics, engineering, and technology. It excludes the study of human society and behavior such as social sciences, economics, psychology.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/8912141049970223361">
+ Science
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_280" translateable="false" desc="Taxonomy Member. Meaning: [Virtual reality is an immersive, computer-simulated technology with many applications in entertainment, training, design, and therapy. Augmented reality blends virtual technology with elements from the real-world environment to enhance the user&#x27;s perception of reality with images, sounds, or other generated information. (Source: Wikipedia)] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/2897011691058278039">
+ Augmented &amp; virtual reality
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_281" translateable="false" desc="Taxonomy Member. Meaning: [the life sciences, to include botany, zoology, microbiology, biochemistry, and genetics] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/7168766670076538552">
+ Biological sciences
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_282" translateable="false" desc="Taxonomy Member. Meaning: [the science of heredity and variation in living organisms; the study of genes] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/7975147582536260852">
+ Genetics
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_283" translateable="false" desc="Taxonomy Member. Meaning: [The physical science related to studies of various atoms, molecules, crystals and other aggregates of matter whether in isolation or combination, which incorporates the concepts of energy and entropy in relation to the spontaneity of chemical processes.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/3864615371872269415">
+ Chemistry
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_284" translateable="false" desc="Taxonomy Member. Meaning: [ecology and environmental sciences; the study of ecosystems and species interaction] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/7521728702803249166">
+ Ecology &amp; environment
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_285" translateable="false" desc="Taxonomy Member. Meaning: [the field encompassing the study of the composition, structure, physical properties, dynamics, and history of Earth materials, and the processes by which they are formed, moved, and changed (Source: Wikipedia)] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/4714007324363906459">
+ Geology
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_286" translateable="false" desc="Taxonomy Member. Meaning: [the branch of computer science which aims to create intelligent machines, or model human cognition, language and knowledge; includes subfields such as machine learning, intelligent systems design, cybernetics and computational neuroscience] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/4024369817630603608">
+ Machine learning &amp; artificial intelligence
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_287" translateable="false" desc="Taxonomy Member. Meaning: [the science of matter and its motion, as well as space and time] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/4110708376238087773">
+ Physics
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_288" translateable="false" desc="Taxonomy Member. Meaning: [the science and technology of robots, and their design, manufacture, and application (Source: Wikipedia)] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/8370266446203965877">
+ Robotics
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_289" translateable="false" desc="Taxonomy Member. Meaning: [Umbrella category that encompasses consumer-oriented content, such as online retailers, brick and mortar shops, product comparisons, and customer services; excludes business-to-business purchasing and procurement.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/4366652724945803153">
+ Shopping
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_290" translateable="false" desc="Taxonomy Member. Meaning: [a collectible object such as a piece of furniture or work of art that has a high value because of its age and quality; vintage items and collectible merchandise (items valued and sought by collectors)] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/3157196244168765800">
+ Antiques &amp; collectibles
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_291" translateable="false" desc="Taxonomy Member. Meaning: [apparel for infants, boys and girls, to include retailers that specialize in this apparel] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/1013801664713141760">
+ Children&#x27;s clothing
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_292" translateable="false" desc="Taxonomy Member. Meaning: [resources for shoppers before and after a purchase; includes product and service information so that consumers can make informed purchasing decisions; customer services that protect consumers from fraud or abuse, reward loyalty, or guarantee the life or functionality of a product or service] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/3496872838858082501">
+ Consumer resources
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_293" translateable="false" desc="Taxonomy Member. Meaning: [coupons, coupon codes, rebates, and vouchers; deal aggregators; and significant discount events such as Black Friday and holiday sales] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/6034955000931327113">
+ Coupons &amp; discount offers
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_294" translateable="false" desc="Taxonomy Member. Meaning: [outfits or disguises worn for holidays, festivals, theme parties, or similar occasions] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/640872172634141037">
+ Costumes
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_295" translateable="false" desc="Taxonomy Member. Meaning: [retail flowers, floral arrangements and flower-based gifts, including flower delivery services] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/4459254689584399041">
+ Flowers
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_296" translateable="false" desc="Taxonomy Member. Meaning: [apparel and clothing accessories for men, to include brands and retails that specialize in menswear] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/3272155990104831869">
+ Men&#x27;s clothing
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_297" translateable="false" desc="Taxonomy Member. Meaning: [products related to holiday celebrations, parties and other special occasions] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/3334915833986293768">
+ Party &amp; holiday supplies
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_298" translateable="false" desc="Taxonomy Member. Meaning: [apparel and clothing accessories for women, to include brands and retails that specialize in women&#x27;s apparel] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/3562830092129675869">
+ Women&#x27;s clothing
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_299" translateable="false" desc="Taxonomy Member. Meaning: [Umbrella category that encompasses all team and individual sports, at both professional and amateur level; includes products and services associated with sport.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/7688311912769068093">
+ Sports
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_300" translateable="false" desc="Taxonomy Member. Meaning: [American football, Canadian football, and arena football] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/383417521473450887">
+ American football
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_301" translateable="false" desc="Taxonomy Member. Meaning: [Australian rules football, officially known as Australian football, also called football, footy or Aussie rules (and in some regions called ? erroneously ? AFL, after the Australian Football League, the only fully professional Australian rules football league ; a sport played between two teams of 22 players (18 on the field, and four interchanges) on either an Australian rules football ground, a modified cricket field or another modified sports venue (Source: Wikipedia)] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/3488831683927398268">
+ Australian football
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_302" translateable="false" desc="Taxonomy Member. Meaning: [a motorsport involving the racing of cars for competition. Includes formula one, off-road, stock car, among other types of auto racing.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/7580055674058533868">
+ Auto racing
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_303" translateable="false" desc="Taxonomy Member. Meaning: [baseball &amp; softball] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/5846183276439397724">
+ Baseball
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_304" translateable="false" desc="Taxonomy Member. Meaning: [indoor basketball, streetball (street basketball), etc.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/8164083822794853176">
+ Basketball
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_305" translateable="false" desc="Taxonomy Member. Meaning: [the sport of bowling, with particular emphasis on ten-pin bowling] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/312182251545064223">
+ Bowling
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_306" translateable="false" desc="Taxonomy Member. Meaning: [a combat sport in which two people throw punches at each other] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/8111928385046363700">
+ Boxing
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_307" translateable="false" desc="Taxonomy Member. Meaning: [cheerleading organizations and competitions] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/7463080506922507397">
+ Cheerleading
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_308" translateable="false" desc="Taxonomy Member. Meaning: [collegiate athletics, sports teams, sports events] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/4925586985884604647">
+ College sports
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_309" translateable="false" desc="Taxonomy Member. Meaning: [an open-air game played on a large grass field with ball, bats, and two wickets, between teams of eleven players, the object of the game being to score more runs than the opposition] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/8462040086381074472">
+ Cricket
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_310" translateable="false" desc="Taxonomy Member. Meaning: [cycling as a competitive sport or as a recreational or fitness activity] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/5103019602023096180">
+ Cycling
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_311" translateable="false" desc="Taxonomy Member. Meaning: [horse riding and breeding as a sport and for show; show jumping, dressage, endurance riding, vaulting, polo, etc] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/1067319762809747789">
+ Equestrian
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_312" translateable="false" desc="Taxonomy Member. Meaning: [Any sport or activity with an extraordinarily high perceived level of inherent danger and risk for serious physical harm, sometimes performed primarily for thrill] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/333816567700263326">
+ Extreme sports
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_313" translateable="false" desc="Taxonomy Member. Meaning: [climbing for recreation, exercise, sport or challenge; includes bouldering, rock climbing, mountaineering, ice climbing, canyoning, etc] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/502272895784682665">
+ Climbing &amp; mountaineering
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_314" translateable="false" desc="Taxonomy Member. Meaning: [a fantasy sport (also known as rotisserie, roto, or owner simulation), a game where participants act as owners to build a team that competes against other fantasy owners based on the statistics generated by the real individual players or teams of a professional sport (Source: Wikipedia); not exclusively computer-based, fantasy sports typically involve multiple players engaged a season-long simulation in real-time] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/1960681730662566492">
+ Fantasy sports
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_315" translateable="false" desc="Taxonomy Member. Meaning: [golf, mini golf, disc golf, etc.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/4099279999161330956">
+ Golf
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_316" translateable="false" desc="Taxonomy Member. Meaning: [artistic gymnastics, rhythmic gymnastics, acrobatics, vaulting, trampoline, etc.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/539663162575982626">
+ Gymnastics
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_317" translateable="false" desc="Taxonomy Member. Meaning: [ice hockey, field hockey, roller hockey, etc.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/4964073484737149944">
+ Hockey
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_318" translateable="false" desc="Taxonomy Member. Meaning: [outdoor and indoor ice skating, both for recreation and competitive or professional sport] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/8543385062822290830">
+ Ice skating
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_319" translateable="false" desc="Taxonomy Member. Meaning: [Martial arts are codified systems and traditions of combat practices, which are practiced for a number of reasons: as self-defense, military and law enforcement applications, mental and spiritual development; as well as entertainment and the preservation of a nation&#x27;s intangible cultural heritage (source: Wikipedia)] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/1827162993061037345">
+ Martial arts
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_320" translateable="false" desc="Taxonomy Member. Meaning: [motorcycle races of all varieties, both on and off road, as well as hill climbs and land speed record trials] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/2678678615741797272">
+ Motorcycle racing
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_321" translateable="false" desc="Taxonomy Member. Meaning: [content about the Summer and Winter Olympic Games, including the general content related to the history of the Games] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/2336949114801585764">
+ Olympics
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_322" translateable="false" desc="Taxonomy Member. Meaning: [a style of football named after Rugby School in the United Kingdom, it is seen most prominently in two current sports, rugby league and rugby union (Source: Wikipedia)] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/5448547304107738833">
+ Rugby
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_323" translateable="false" desc="Taxonomy Member. Meaning: [running and walking as a recreational activity, for fitness or pleasure; also, running and walking sports, including freestyle walking, racewalking, cross country, marathons, road running, trail running, etc] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/47392603994513150">
+ Running &amp; walking
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_324" translateable="false" desc="Taxonomy Member. Meaning: [a group of sports or recreational activities, primarily conducted in winter climates and environments, using skis or snowboards as primary equipment] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/7439014877870789073">
+ Skiing &amp; snowboarding
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_325" translateable="false" desc="Taxonomy Member. Meaning: [association football (a.k.a. soccer)] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/2227399069328296048">
+ Soccer
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_326" translateable="false" desc="Taxonomy Member. Meaning: [surfing is a surface water sport in which the surfer rides a surfboard on the crest and face of a wave which is carrying the surfer towards the shore; three major subdivisions within stand-up surfing are longboarding, shortboarding, and stand up paddle surfing; bodysurfing involves riding the wave without a board, and is considered by some to be the purest form of surfing (source: Wikipedia)] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/5437790103348544442">
+ Surfing
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_327" translateable="false" desc="Taxonomy Member. Meaning: [the aquatic sport of swimming involves competition amongst participants to be the fastest over a given distance under self propulsion; different distances are swum in different levels of competition (Source: Wikipedia)] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/6978968426342204396">
+ Swimming
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_328" translateable="false" desc="Taxonomy Member. Meaning: [tennis players, matches, competitions, and related media; tennis is a sport usually played between two players (singles) or between two teams of two players each (doubles); each player uses a racket that is strung to strike a hollow rubber ball covered with felt over a net into the opponent&#x27;s court (Source: Wikipedia)] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/5911104555345590858">
+ Tennis
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_329" translateable="false" desc="Taxonomy Member. Meaning: [various athletic contests based on the skills of running, jumping, and throwing (source: Wikipedia); examples include sprints, hurdles, race walks, and distance runs on a track, and jumps, vaults, and throwing events on a field] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/1172848219017882195">
+ Track &amp; field
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_330" translateable="false" desc="Taxonomy Member. Meaning: [indoor volleyball, beach volleyball, etc.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/6257460393849946294">
+ Volleyball
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_331" translateable="false" desc="Taxonomy Member. Meaning: [grappling-based combat sports, such as arm wrestling, greco-roman wrestiling, american wrestling, sumo wrestling, lucha libre, etc.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/5041682049381135476">
+ Wrestling
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_332" translateable="false" desc="Taxonomy Member. Meaning: [Umbrella category that encompasses travel and tourism, to include travel products and services, tourist destinations, and all modes of (non industrial) transportation.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/3544337312994447546">
+ Travel &amp; transportation
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_333" translateable="false" desc="Taxonomy Member. Meaning: [adventure travel and tours; strenuous travel for vigorous travelers off the typical tourism circuit; to include jungle expeditions, safaris, whitewater rafting tours, extreme backpacking tours, etc] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/5173047300100980905">
+ Adventure travel
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_334" translateable="false" desc="Taxonomy Member. Meaning: [airlines, airfare, budget airfares, frequent flyer programs, charters, airports etc] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/203867448899179230">
+ Air travel
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_335" translateable="false" desc="Taxonomy Member. Meaning: [Travel undertaken for work or business purposes, as opposed to other types of travel, such as for leisure purposes or regularly commuting between one&#x27;s home and workplace. Common reasons for business travel include attending meetings, conferences, exhibitions, and incentive trips. (Source: Wikipedia)] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/8026738780137821201">
+ Business travel
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_336" translateable="false" desc="Taxonomy Member. Meaning: [car rental, hire car, or car hire agency are companies that rent automobiles for short periods of time, generally ranging from a few hours to a few weeks. includes peer to peer car rentals. (source: Wikipedia)] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/8401988302167662697">
+ Car rentals
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_337" translateable="false" desc="Taxonomy Member. Meaning: [pleasure cruises, chartered boats and yachts, ferry service and water transport] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/3808986732150625564">
+ Cruises &amp; charters
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_338" translateable="false" desc="Taxonomy Member. Meaning: [Travel focused on families traveling with children.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/662299721322582259">
+ Family travel
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_339" translateable="false" desc="Taxonomy Member. Meaning: [Romantic travel - e.g. honeymoons, anniversaries, weekend getaways for couples, etc.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/4792515542726292732">
+ Honeymoons &amp; romantic getaways
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_340" translateable="false" desc="Taxonomy Member. Meaning: [hotels, motels, inns, resorts, bed &amp; breakfasts, hostels, etc] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/1593901441731372065">
+ Hotels &amp; accommodations
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_341" translateable="false" desc="Taxonomy Member. Meaning: [land-based public transportation services like buses and railways that cover longer distances than city transit systems] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/7179861189647095673">
+ Long distance bus &amp; rail
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_342" translateable="false" desc="Taxonomy Member. Meaning: [All types of low cost travel carriers and last minute travel deals, including flights, hotel bookings, cruises, vacation packages, etc.] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/8412352521613865661">
+ Low cost &amp; last minute travel
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_343" translateable="false" desc="Taxonomy Member. Meaning: [travel products and personal items such as luggage, travel bags, suitcase tags and other accessories that facilitate long-distance travel] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/5980171530827030093">
+ Luggage &amp; travel accessories
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_344" translateable="false" desc="Taxonomy Member. Meaning: [content specific to individual tourist destinations; popular attractions and sites of interest; specialized destination guides for distinct travel locales; also, individual boards of tourism] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/7923352816810946078">
+ Tourist destinations
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_345" translateable="false" desc="Taxonomy Member. Meaning: [seaside resort and popular beach or island vacation destinations] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/3968628705007948901">
+ Beaches &amp; islands
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_346" translateable="false" desc="Taxonomy Member. Meaning: [state and national parks and forests; city parks and botanical gardens] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/5861060413004625161">
+ Regional parks &amp; gardens
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_347" translateable="false" desc="Taxonomy Member. Meaning: [amusement or theme parks: a collection of rides and other entertainment attractions assembled for the purpose of entertaining a large group of people] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/2774404912928084263">
+ Theme parks
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_348" translateable="false" desc="Taxonomy Member. Meaning: [parks, aquariums and sanctuaries dedicated to the collection and display of wildlife (including sea life) to a public audience] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/2945765054327967005">
+ Zoos, aquariums &amp; preserves
+ </message>
+ <message name="IDS_PRIVACY_SANDBOX_TOPICS_TAXONOMY_V1_TOPIC_ID_349" translateable="false" desc="Taxonomy Member. Meaning: [amateur and professional publications, directories and portals related to traveling and tourism; travel guides, travel blogs, travel periodicals, etc] Existing Ref: http://tc-message/message/FatCatTaxonomy_Verticals4/2340477805275742936">
+ Travel guides &amp; travelogues
+ </message>
</grit-part>
diff --git a/chromium/components/protocol_handler_strings.grdp b/chromium/components/protocol_handler_strings.grdp
new file mode 100644
index 00000000000..71a3eaf67a0
--- /dev/null
+++ b/chromium/components/protocol_handler_strings.grdp
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<grit-part>
+ <!-- Protocol Handler -->
+ <message name="IDS_REGISTER_PROTOCOL_HANDLER_TOOLTIP" desc="Location bar icon tooltip text when a page wants to use registerProtocolHandler.">
+ page wants to install a service handler.
+ </message>
+ <!-- Register Protocol Handler Strings -->
+ <message name="IDS_REGISTER_PROTOCOL_HANDLER_MAILTO_NAME" desc="A more user friendly way of describing mailto: links.">
+ email
+ </message>
+ <message name="IDS_REGISTER_PROTOCOL_HANDLER_WEBCAL_NAME" desc="A more user friendly way of describing webcal: links.">
+ web calendar
+ </message>
+ <message name="IDS_REGISTER_PROTOCOL_HANDLER_CONFIRM" desc="The message to display when asking a user to confirm the registration of a protocol handler.">
+ Allow <ph name="HANDLER_HOSTNAME">$1<ex>google.com</ex></ph> to open all <ph name="PROTOCOL">$2<ex>search</ex></ph> links?
+ </message>
+ <message name="IDS_REGISTER_PROTOCOL_HANDLER_CONFIRM_REPLACE" desc="The message to display when asking a user to confirm the registration of a protocol handler.">
+ Allow <ph name="HANDLER_HOSTNAME">$1<ex>google.com</ex></ph> to open all <ph name="PROTOCOL">$2<ex>search</ex></ph> links instead of <ph name="REPLACED_HANDLER_TITLE">$3<ex>Elgoog Search</ex></ph>?
+ </message>
+ <message name="IDS_REGISTER_PROTOCOL_HANDLER_CONFIRM_FRAGMENT" desc="The permission fragment to display when asking a user to confirm the registration of a protocol handler in a permission bubble. Follows a prompt 'This site would like to:'.">
+ Open <ph name="PROTOCOL">$1<ex>search</ex></ph> links
+ </message>
+ <message name="IDS_REGISTER_PROTOCOL_HANDLER_CONFIRM_REPLACE_FRAGMENT" desc="The permission fragment to display when asking a user to confirm the registration of a protocol handler. Follows a prompt 'This site would like to:'.">
+ Open <ph name="PROTOCOL">$1<ex>search</ex></ph> links instead of <ph name="REPLACED_HANDLER_TITLE">$2<ex>Elgoog Search</ex></ph>
+ </message>
+ <message name="IDS_REGISTER_PROTOCOL_HANDLER_ACCEPT" desc="Text to show for the accept button for the register protocol handler request infobar.">
+ Allow
+ </message>
+ <message name="IDS_REGISTER_PROTOCOL_HANDLER_DENY" desc="Text to show for the deny button for the register protocol handler request infobar.">
+ Deny
+ </message>
+ <message name="IDS_REGISTER_PROTOCOL_HANDLER_IGNORE" desc="Text to show for an ignore prompt for a register protocol handler registration request.">
+ Ignore
+ </message>
+ <!-- Protocol Handling intent prompt -->
+ <if expr="not is_android">
+ <message name="IDS_PROTOCOL_HANDLER_INTENT_PICKER_QUESTION" desc="Label on the protocol handler intent picker.">
+ Allow app to open <ph name="PROTOCOL_SCHEME">$1<ex>mailto</ex></ph> links?
+ </message>
+ </if>
+</grit-part>
diff --git a/chromium/components/protocol_handler_strings_grdp/IDS_PROTOCOL_HANDLER_INTENT_PICKER_QUESTION.png.sha1 b/chromium/components/protocol_handler_strings_grdp/IDS_PROTOCOL_HANDLER_INTENT_PICKER_QUESTION.png.sha1
new file mode 100644
index 00000000000..8775ef89874
--- /dev/null
+++ b/chromium/components/protocol_handler_strings_grdp/IDS_PROTOCOL_HANDLER_INTENT_PICKER_QUESTION.png.sha1
@@ -0,0 +1 @@
+97a95bf3413a8b26200bab5f3c320ea089e44e02 \ No newline at end of file
diff --git a/chromium/components/proxy_config/pref_proxy_config_tracker_impl.cc b/chromium/components/proxy_config/pref_proxy_config_tracker_impl.cc
index 17e984eda1e..a3fa01bf88e 100644
--- a/chromium/components/proxy_config/pref_proxy_config_tracker_impl.cc
+++ b/chromium/components/proxy_config/pref_proxy_config_tracker_impl.cc
@@ -262,7 +262,7 @@ ProxyPrefs::ConfigState PrefProxyConfigTrackerImpl::ReadPrefConfig(
pref_service->FindPreference(proxy_config::prefs::kProxy);
DCHECK(pref);
- const base::DictionaryValue* dict =
+ const base::Value* dict =
pref_service->GetDictionary(proxy_config::prefs::kProxy);
DCHECK(dict);
ProxyConfigDictionary proxy_dict(dict->Clone());
diff --git a/chromium/components/proxy_config/proxy_policy_handler.cc b/chromium/components/proxy_config/proxy_policy_handler.cc
index 54650735454..233a89c55d4 100644
--- a/chromium/components/proxy_config/proxy_policy_handler.cc
+++ b/chromium/components/proxy_config/proxy_policy_handler.cc
@@ -279,8 +279,8 @@ const base::Value* ProxyPolicyHandler::GetProxyPolicyValue(
if (!value || !value->GetAsDictionary(&settings))
return nullptr;
- const base::Value* policy_value = nullptr;
- if (!settings->Get(policy_name, &policy_value) || policy_value->is_none())
+ const base::Value* policy_value = settings->FindPath(policy_name);
+ if (!policy_value || policy_value->is_none())
return nullptr;
const std::string* tmp = policy_value->GetIfString();
if (tmp && tmp->empty())
diff --git a/chromium/components/query_tiles/BUILD.gn b/chromium/components/query_tiles/BUILD.gn
index d6ac8ae7da6..3eb0305e059 100644
--- a/chromium/components/query_tiles/BUILD.gn
+++ b/chromium/components/query_tiles/BUILD.gn
@@ -54,7 +54,10 @@ source_set("public") {
"android/tile_provider_bridge.h",
]
- deps += [ ":jni_headers" ]
+ deps += [
+ ":jni_headers",
+ "//url:gurl_android",
+ ]
}
}
@@ -82,6 +85,7 @@ if (is_android) {
deps = [
"//components/browser_ui/widget/android:java",
"//third_party/androidx:androidx_annotation_annotation_java",
+ "//url:gurl_java",
]
}
@@ -100,6 +104,7 @@ if (is_android) {
"//components/browser_ui/widget/android:java",
"//third_party/androidx:androidx_annotation_annotation_java",
"//ui/android:ui_java",
+ "//url:gurl_java",
]
annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
@@ -115,11 +120,14 @@ if (is_android) {
}
android_library("test_support_java") {
+ testonly = true
sources = [ "android/java/src/org/chromium/components/query_tiles/TestTileProvider.java" ]
deps = [
":java",
"//base:base_java",
+ "//url:gurl_java",
+ "//url:gurl_junit_test_support",
]
}
diff --git a/chromium/components/query_tiles/android/tile_conversion_bridge.cc b/chromium/components/query_tiles/android/tile_conversion_bridge.cc
index 9b31f43202d..89419e796ae 100644
--- a/chromium/components/query_tiles/android/tile_conversion_bridge.cc
+++ b/chromium/components/query_tiles/android/tile_conversion_bridge.cc
@@ -10,6 +10,7 @@
#include "base/android/jni_array.h"
#include "base/android/jni_string.h"
#include "components/query_tiles/jni_headers/TileConversionBridge_jni.h"
+#include "url/android/gurl_android.h"
namespace query_tiles {
@@ -26,16 +27,16 @@ ScopedJavaLocalRef<jobject> CreateJavaTileAndMaybeAddToList(
for (const auto& subtile : tile.sub_tiles)
CreateJavaTileAndMaybeAddToList(env, jchildren, *subtile.get());
- std::vector<std::string> urls;
+ std::vector<ScopedJavaLocalRef<jobject>> urls;
for (const ImageMetadata& image : tile.image_metadatas)
- urls.push_back(image.url.spec());
+ urls.push_back(url::GURLAndroid::FromNativeGURL(env, image.url));
return Java_TileConversionBridge_createTileAndMaybeAddToList(
env, jlist, ConvertUTF8ToJavaString(env, tile.id),
ConvertUTF8ToJavaString(env, tile.display_text),
ConvertUTF8ToJavaString(env, tile.accessibility_text),
ConvertUTF8ToJavaString(env, tile.query_text),
- ToJavaArrayOfStrings(env, urls),
+ url::GURLAndroid::ToJavaArrayOfGURLs(env, urls),
ToJavaArrayOfStrings(env, tile.search_params), jchildren);
}
diff --git a/chromium/components/query_tiles/internal/tile_service_scheduler_impl.cc b/chromium/components/query_tiles/internal/tile_service_scheduler_impl.cc
index badee9aae30..2a937042f03 100644
--- a/chromium/components/query_tiles/internal/tile_service_scheduler_impl.cc
+++ b/chromium/components/query_tiles/internal/tile_service_scheduler_impl.cc
@@ -145,7 +145,7 @@ TileGroup* TileServiceSchedulerImpl::GetTileGroup() {
std::unique_ptr<net::BackoffEntry> TileServiceSchedulerImpl::GetBackoff() {
std::unique_ptr<net::BackoffEntry> result;
- const base::ListValue* value = prefs_->GetList(kBackoffEntryKey);
+ const base::Value* value = prefs_->GetList(kBackoffEntryKey);
if (value) {
result = net::BackoffEntrySerializer::DeserializeFromValue(
*value, backoff_policy_.get(), tick_clock_, clock_->Now());
diff --git a/chromium/components/query_tiles/internal/tile_service_scheduler_unittest.cc b/chromium/components/query_tiles/internal/tile_service_scheduler_unittest.cc
index 2cbb0b95241..8d207ef3e91 100644
--- a/chromium/components/query_tiles/internal/tile_service_scheduler_unittest.cc
+++ b/chromium/components/query_tiles/internal/tile_service_scheduler_unittest.cc
@@ -88,7 +88,7 @@ class TileServiceSchedulerTest : public testing::Test {
std::unique_ptr<net::BackoffEntry> GetBackoffPolicy() {
std::unique_ptr<net::BackoffEntry> result;
- const base::ListValue* value = prefs()->GetList(kBackoffEntryKey);
+ const base::Value* value = prefs()->GetList(kBackoffEntryKey);
if (value) {
result = net::BackoffEntrySerializer::DeserializeFromValue(
*value, &kTestPolicy, tick_clock(), clock()->Now());
diff --git a/chromium/components/quirks/quirks_manager.cc b/chromium/components/quirks/quirks_manager.cc
index f3601d8c7cc..027cc7fe63b 100644
--- a/chromium/components/quirks/quirks_manager.cc
+++ b/chromium/components/quirks/quirks_manager.cc
@@ -207,7 +207,7 @@ void QuirksManager::SetLastServerCheck(int64_t product_id,
const base::Time& last_check) {
DCHECK(thread_checker_.CalledOnValidThread());
DictionaryPrefUpdate dict(local_state_, prefs::kQuirksClientLastServerCheck);
- dict->SetDouble(IdToHexString(product_id), last_check.ToDoubleT());
+ dict->SetDoubleKey(IdToHexString(product_id), last_check.ToDoubleT());
}
} // namespace quirks
diff --git a/chromium/components/reading_list/core/reading_list_model.h b/chromium/components/reading_list/core/reading_list_model.h
index cfddaea2e27..e9c6b357968 100644
--- a/chromium/components/reading_list/core/reading_list_model.h
+++ b/chromium/components/reading_list/core/reading_list_model.h
@@ -13,6 +13,7 @@
#include "base/memory/raw_ptr.h"
#include "base/observer_list.h"
#include "base/sequence_checker.h"
+#include "components/keyed_service/core/keyed_service.h"
#include "components/reading_list/core/reading_list_entry.h"
#include "components/reading_list/core/reading_list_model_observer.h"
@@ -28,7 +29,7 @@ class ModelTypeSyncBridge;
// other of read ones. This object should only be accessed from one thread
// (Usually the main thread). The observers callbacks are also sent on the main
// thread.
-class ReadingListModel {
+class ReadingListModel : public KeyedService {
public:
class ScopedReadingListBatchUpdate;
@@ -173,7 +174,7 @@ class ReadingListModel {
protected:
ReadingListModel();
- virtual ~ReadingListModel();
+ ~ReadingListModel() override;
// The observers.
base::ObserverList<ReadingListModelObserver>::Unchecked observers_;
diff --git a/chromium/components/reading_list/core/reading_list_model_impl.h b/chromium/components/reading_list/core/reading_list_model_impl.h
index 5fc20c2c57b..ea2ee526f60 100644
--- a/chromium/components/reading_list/core/reading_list_model_impl.h
+++ b/chromium/components/reading_list/core/reading_list_model_impl.h
@@ -9,7 +9,6 @@
#include <memory>
#include "base/memory/raw_ptr.h"
-#include "components/keyed_service/core/keyed_service.h"
#include "components/reading_list/core/reading_list_entry.h"
#include "components/reading_list/core/reading_list_model.h"
#include "components/reading_list/core/reading_list_model_storage.h"
@@ -23,8 +22,7 @@ class PrefService;
// Concrete implementation of a reading list model using in memory lists.
class ReadingListModelImpl : public ReadingListModel,
- public ReadingListStoreDelegate,
- public KeyedService {
+ public ReadingListStoreDelegate {
public:
using ReadingListEntries = std::map<GURL, ReadingListEntry>;
@@ -37,8 +35,6 @@ class ReadingListModelImpl : public ReadingListModel,
PrefService* pref_service,
base::Clock* clock_);
- ReadingListModelImpl();
-
syncer::ModelTypeSyncBridge* GetModelTypeSyncBridge() override;
ReadingListModelImpl(const ReadingListModelImpl&) = delete;
diff --git a/chromium/components/reading_list/core/reading_list_pref_names.cc b/chromium/components/reading_list/core/reading_list_pref_names.cc
index 08da77f09ec..58c5c89a511 100644
--- a/chromium/components/reading_list/core/reading_list_pref_names.cc
+++ b/chromium/components/reading_list/core/reading_list_pref_names.cc
@@ -4,6 +4,8 @@
#include "components/reading_list/core/reading_list_pref_names.h"
+#include "build/build_config.h"
+
namespace reading_list {
namespace prefs {
@@ -11,11 +13,11 @@ namespace prefs {
// device. Not synced.
const char kReadingListHasUnseenEntries[] = "reading_list.has_unseen_entries";
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
// Boolean to track if the first-use experience has been shown on desktop.
const char kReadingListDesktopFirstUseExperienceShown[] =
"reading_list.desktop_first_use_experience_shown";
-#endif // !defined(OS_ANDROID) && !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
} // namespace prefs
} // namespace reading_list
diff --git a/chromium/components/reading_list/core/reading_list_pref_names.h b/chromium/components/reading_list/core/reading_list_pref_names.h
index 76a8f76a941..99fc9d267f7 100644
--- a/chromium/components/reading_list/core/reading_list_pref_names.h
+++ b/chromium/components/reading_list/core/reading_list_pref_names.h
@@ -14,9 +14,9 @@ namespace prefs {
extern const char kReadingListHasUnseenEntries[];
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
extern const char kReadingListDesktopFirstUseExperienceShown[];
-#endif // !defined(OS_ANDROID) && !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
} // namespace prefs
} // namespace reading_list
diff --git a/chromium/components/reading_list/features/reading_list_switches.cc b/chromium/components/reading_list/features/reading_list_switches.cc
index fa44390f022..b5b032aeba5 100644
--- a/chromium/components/reading_list/features/reading_list_switches.cc
+++ b/chromium/components/reading_list/features/reading_list_switches.cc
@@ -9,28 +9,27 @@
#include "build/build_config.h"
#include "components/reading_list/features/reading_list_buildflags.h"
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
namespace features {
// Hosts some content in a side panel. https://crbug.com/1149995
const base::Feature kSidePanel{"SidePanel", base::FEATURE_DISABLED_BY_DEFAULT};
} // namespace features
-#endif // !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_IOS)
namespace reading_list {
namespace switches {
// Allow users to save tabs for later. Enables a new button and menu for
-// accessing tabs saved for later. https://crbug.com/1109316
-#if defined(OS_ANDROID)
-const base::Feature kReadLater{"ReadLater", base::FEATURE_DISABLED_BY_DEFAULT};
-#else
+// accessing tabs saved for later.
+// android: https://crbug.com/1123087
+// desktop: https://crbug.com/1109316
+// ios: https://crbug.com/577659
const base::Feature kReadLater{"ReadLater", base::FEATURE_ENABLED_BY_DEFAULT};
-#endif
bool IsReadingListEnabled() {
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
return BUILDFLAG(ENABLE_READING_LIST);
-#elif defined(OS_ANDROID)
+#elif BUILDFLAG(IS_ANDROID)
return base::FeatureList::IsEnabled(kReadLater);
#else
return base::FeatureList::IsEnabled(kReadLater) ||
@@ -41,7 +40,7 @@ bool IsReadingListEnabled() {
const base::Feature kReadLaterBackendMigration{
"ReadLaterBackendMigration", base::FEATURE_DISABLED_BY_DEFAULT};
-#ifdef OS_ANDROID
+#if BUILDFLAG(IS_ANDROID)
// Feature flag used for enabling read later reminder notification.
const base::Feature kReadLaterReminderNotification{
"ReadLaterReminderNotification", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/chromium/components/reading_list/features/reading_list_switches.h b/chromium/components/reading_list/features/reading_list_switches.h
index 1192f2555bc..bd8dcf9d056 100644
--- a/chromium/components/reading_list/features/reading_list_switches.h
+++ b/chromium/components/reading_list/features/reading_list_switches.h
@@ -8,7 +8,7 @@
#include "base/feature_list.h"
#include "build/build_config.h"
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
// Feature flag used for enabling side panel on desktop.
// TODO(crbug.com/1225279): Move this back to chrome/browser/ui/ui_features.h
// after kReadLater is cleaned up (and IsReadingListEnabled() returns true on
@@ -17,7 +17,7 @@
namespace features {
extern const base::Feature kSidePanel;
} // namespace features
-#endif // !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_IOS)
namespace reading_list {
namespace switches {
@@ -39,7 +39,7 @@ bool IsReadingListEnabled();
// details.
extern const base::Feature kReadLaterBackendMigration;
-#ifdef OS_ANDROID
+#if BUILDFLAG(IS_ANDROID)
// Feature flag used for enabling read later reminder notification.
extern const base::Feature kReadLaterReminderNotification;
#endif
diff --git a/chromium/components/remote_cocoa/app_shim/application_bridge.mm b/chromium/components/remote_cocoa/app_shim/application_bridge.mm
index c8ba6f3da89..9734fb620a9 100644
--- a/chromium/components/remote_cocoa/app_shim/application_bridge.mm
+++ b/chromium/components/remote_cocoa/app_shim/application_bridge.mm
@@ -4,8 +4,9 @@
#include "components/remote_cocoa/app_shim/application_bridge.h"
+#include <tuple>
+
#include "base/bind.h"
-#include "base/ignore_result.h"
#include "base/no_destructor.h"
#include "components/remote_cocoa/app_shim/alert.h"
#include "components/remote_cocoa/app_shim/color_panel_bridge.h"
@@ -126,7 +127,7 @@ void ApplicationBridge::SetContentNSViewCreateCallbacks(
void ApplicationBridge::CreateAlert(
mojo::PendingReceiver<mojom::AlertBridge> bridge_receiver) {
// The resulting object manages its own lifetime.
- ignore_result(new AlertBridge(std::move(bridge_receiver)));
+ std::ignore = new AlertBridge(std::move(bridge_receiver));
}
void ApplicationBridge::ShowColorPanel(
@@ -143,9 +144,9 @@ void ApplicationBridge::CreateNativeWidgetNSWindow(
mojo::PendingAssociatedRemote<mojom::NativeWidgetNSWindowHost> host,
mojo::PendingAssociatedRemote<mojom::TextInputHost> text_input_host) {
// The resulting object will be destroyed when its message pipe is closed.
- ignore_result(
+ std::ignore =
new NativeWidgetBridgeOwner(bridge_id, std::move(bridge_receiver),
- std::move(host), std::move(text_input_host)));
+ std::move(host), std::move(text_input_host));
}
void ApplicationBridge::CreateRenderWidgetHostNSView(
diff --git a/chromium/components/remote_cocoa/app_shim/bridged_content_view.mm b/chromium/components/remote_cocoa/app_shim/bridged_content_view.mm
index 747f789789b..b5d505af82c 100644
--- a/chromium/components/remote_cocoa/app_shim/bridged_content_view.mm
+++ b/chromium/components/remote_cocoa/app_shim/bridged_content_view.mm
@@ -26,12 +26,10 @@
#include "ui/events/keycodes/dom/dom_code.h"
#import "ui/events/keycodes/keyboard_code_conversion_mac.h"
#include "ui/events/platform/platform_event_source.h"
-#include "ui/gfx/canvas_paint_mac.h"
#include "ui/gfx/decorated_text.h"
#import "ui/gfx/decorated_text_mac.h"
#include "ui/gfx/geometry/rect.h"
#import "ui/gfx/mac/coordinate_conversion.h"
-#import "ui/gfx/path_mac.h"
#include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
namespace {
diff --git a/chromium/components/remote_cocoa/app_shim/color_panel_bridge.mm b/chromium/components/remote_cocoa/app_shim/color_panel_bridge.mm
index 1ad75ab1c8c..f7f0de0bac8 100644
--- a/chromium/components/remote_cocoa/app_shim/color_panel_bridge.mm
+++ b/chromium/components/remote_cocoa/app_shim/color_panel_bridge.mm
@@ -42,11 +42,15 @@ remote_cocoa::ColorPanelBridge* g_current_panel_bridge = nullptr;
- (instancetype)init {
if ((self = [super init])) {
NSColorPanel* panel = [NSColorPanel sharedColorPanel];
- [[NSNotificationCenter defaultCenter]
- addObserver:self
+ NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
+ [nc addObserver:self
selector:@selector(windowWillClose:)
name:NSWindowWillCloseNotification
object:panel];
+ [nc addObserver:self
+ selector:@selector(windowDidResignKey:)
+ name:NSWindowDidResignKeyNotification
+ object:panel];
}
return self;
}
@@ -63,6 +67,12 @@ remote_cocoa::ColorPanelBridge* g_current_panel_bridge = nullptr;
_nonUserChange = NO;
}
+- (void)windowDidResignKey:(NSNotification*)notification {
+ // Close the color panel when the user clicks away.
+ [self windowWillClose:notification];
+ [[NSColorPanel sharedColorPanel] close];
+}
+
- (void)didChooseColor:(NSColorPanel*)panel {
if (_nonUserChange) {
_nonUserChange = NO;
diff --git a/chromium/components/remote_cocoa/app_shim/mouse_capture.h b/chromium/components/remote_cocoa/app_shim/mouse_capture.h
index 426404d3e9c..59bdc58a539 100644
--- a/chromium/components/remote_cocoa/app_shim/mouse_capture.h
+++ b/chromium/components/remote_cocoa/app_shim/mouse_capture.h
@@ -9,7 +9,11 @@
#include "components/remote_cocoa/app_shim/remote_cocoa_app_shim_export.h"
+#if defined(__OBJC__)
@class NSWindow;
+#else
+class NSWindow;
+#endif
namespace remote_cocoa {
diff --git a/chromium/components/remote_cocoa/app_shim/mouse_capture.mm b/chromium/components/remote_cocoa/app_shim/mouse_capture.mm
index f597435ba32..aca6d6a0365 100644
--- a/chromium/components/remote_cocoa/app_shim/mouse_capture.mm
+++ b/chromium/components/remote_cocoa/app_shim/mouse_capture.mm
@@ -88,9 +88,10 @@ void CocoaMouseCapture::ActiveEventTap::Init() {
auto local_block = ^NSEvent*(NSEvent* event) {
CocoaMouseCapture* owner =
ui::WeakPtrNSObjectFactory<CocoaMouseCapture>::Get(handle);
- if (owner)
- owner->delegate_->PostCapturedEvent(event);
- return nil; // Swallow all local events.
+ if (!owner)
+ return event;
+ bool handled = owner->delegate_->PostCapturedEvent(event);
+ return handled ? nil : event;
};
auto global_block = ^void(NSEvent* event) {
CocoaMouseCapture* owner =
diff --git a/chromium/components/remote_cocoa/app_shim/mouse_capture_delegate.h b/chromium/components/remote_cocoa/app_shim/mouse_capture_delegate.h
index d85570b2ded..2a018ddc2d1 100644
--- a/chromium/components/remote_cocoa/app_shim/mouse_capture_delegate.h
+++ b/chromium/components/remote_cocoa/app_shim/mouse_capture_delegate.h
@@ -5,18 +5,27 @@
#ifndef COMPONENTS_REMOTE_COCOA_APP_SHIM_MOUSE_CAPTURE_DELEGATE_H_
#define COMPONENTS_REMOTE_COCOA_APP_SHIM_MOUSE_CAPTURE_DELEGATE_H_
+#if defined(__OBJC__)
@class NSEvent;
@class NSWindow;
+#else
+class NSEvent;
+class NSWindow;
+#endif
namespace remote_cocoa {
// Delegate for receiving captured events from a CocoaMouseCapture.
class CocoaMouseCaptureDelegate {
public:
+ virtual ~CocoaMouseCaptureDelegate() = default;
+
// Called when an event has been captured. This may be an event local to the
// application, or a global event (sent to another application). If it is a
- // local event, regular event handling will be suppressed.
- virtual void PostCapturedEvent(NSEvent* event) = 0;
+ // local event and this function returns true, the event will be swallowed
+ // instead of propagated normally. The function return value is ignored for
+ // global events.
+ virtual bool PostCapturedEvent(NSEvent* event) = 0;
// Called once. When another window acquires capture, or when the
// CocoaMouseCapture is destroyed.
diff --git a/chromium/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.h b/chromium/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.h
index 35e78412a26..a101b191688 100644
--- a/chromium/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.h
+++ b/chromium/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.h
@@ -22,6 +22,7 @@
#include "ui/accelerated_widget_mac/ca_transaction_observer.h"
#include "ui/accelerated_widget_mac/display_ca_layer_tree.h"
#include "ui/base/cocoa/command_dispatcher.h"
+#include "ui/base/cocoa/weak_ptr_nsobject.h"
#include "ui/base/ime/text_input_client.h"
#include "ui/display/display_observer.h"
@@ -253,6 +254,7 @@ class REMOTE_COCOA_APP_SHIM_EXPORT NativeWidgetNSWindowBridge
void ReleaseCapture() override;
void RedispatchKeyEvent(
const std::vector<uint8_t>& native_event_data) override;
+ void SetLocalEventMonitorEnabled(bool enable) override;
void CreateWindowControlsOverlayNSView(
const mojom::WindowControlsOverlayNSViewType overlay_type) override;
void UpdateWindowControlsOverlayNSView(
@@ -303,7 +305,7 @@ class REMOTE_COCOA_APP_SHIM_EXPORT NativeWidgetNSWindowBridge
bool HasWindowRestorationData();
// CocoaMouseCaptureDelegate:
- void PostCapturedEvent(NSEvent* event) override;
+ bool PostCapturedEvent(NSEvent* event) override;
void OnMouseCaptureLost() override;
NSWindow* GetWindow() const override;
@@ -326,6 +328,8 @@ class REMOTE_COCOA_APP_SHIM_EXPORT NativeWidgetNSWindowBridge
std::unique_ptr<CocoaWindowMoveLoop> window_move_loop_;
ui::ModalType modal_type_ = ui::MODAL_TYPE_NONE;
bool is_translucent_window_ = false;
+ bool is_headless_mode_window_ = false;
+ id key_down_event_monitor_ = nil;
// Intended for PWAs with window controls overlay display override. These two
// NSViews are added on top of the non client area to route events to the
@@ -399,6 +403,8 @@ class REMOTE_COCOA_APP_SHIM_EXPORT NativeWidgetNSWindowBridge
mojo::AssociatedReceiver<remote_cocoa::mojom::NativeWidgetNSWindow>
bridge_mojo_receiver_{this};
+
+ ui::WeakPtrNSObjectFactory<NativeWidgetNSWindowBridge> ns_weak_factory_;
};
} // namespace remote_cocoa
diff --git a/chromium/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm b/chromium/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm
index 2cb46846d9c..cb82b91eb2e 100644
--- a/chromium/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm
+++ b/chromium/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm
@@ -313,12 +313,15 @@ NativeWidgetNSWindowBridge::NativeWidgetNSWindowBridge(
: id_(bridged_native_widget_id),
host_(host),
host_helper_(host_helper),
- text_input_host_(text_input_host) {
+ text_input_host_(text_input_host),
+ ns_weak_factory_(this) {
DCHECK(GetIdToWidgetImplMap().find(id_) == GetIdToWidgetImplMap().end());
GetIdToWidgetImplMap().insert(std::make_pair(id_, this));
}
NativeWidgetNSWindowBridge::~NativeWidgetNSWindowBridge() {
+ SetLocalEventMonitorEnabled(false);
+ DCHECK(!key_down_event_monitor_);
GetPendingWindowTitleMap().erase(window_.get());
// The delegate should be cleared already. Note this enforces the precondition
// that -[NSWindow close] is invoked on the hosted window before the
@@ -429,6 +432,7 @@ void NativeWidgetNSWindowBridge::InitWindow(
mojom::NativeWidgetNSWindowInitParamsPtr params) {
modal_type_ = params->modal_type;
is_translucent_window_ = params->is_translucent;
+ is_headless_mode_window_ = params->is_headless_mode_window;
pending_restoration_data_ = params->state_restoration_data;
// Register for application hide notifications so that visibility can be
@@ -652,6 +656,10 @@ void NativeWidgetNSWindowBridge::CloseWindowNow() {
void NativeWidgetNSWindowBridge::SetVisibilityState(
WindowVisibilityState new_state) {
+ // Avoid changing headless mode window visibility state.
+ if (is_headless_mode_window_)
+ return;
+
// During session restore this method gets called from RestoreTabsToBrowser()
// with new_state = kShowAndActivateWindow. We consume restoration data on our
// first time through this method so we can use its existence as an
@@ -796,6 +804,38 @@ bool NativeWidgetNSWindowBridge::HasCapture() {
return mouse_capture_ && mouse_capture_->IsActive();
}
+void NativeWidgetNSWindowBridge::SetLocalEventMonitorEnabled(bool enabled) {
+ if (enabled) {
+ // Create the event montitor if it does not exist yet.
+ if (key_down_event_monitor_)
+ return;
+
+ // Capture a WeakPtr via NSObject. This allows the block to detect another
+ // event monitor for the same event deleting `this`.
+ WeakPtrNSObject* handle = ns_weak_factory_.handle();
+ auto block = ^NSEvent*(NSEvent* event) {
+ auto* bridge =
+ ui::WeakPtrNSObjectFactory<NativeWidgetNSWindowBridge>::Get(handle);
+ if (!bridge)
+ return event;
+ std::unique_ptr<ui::Event> ui_event = ui::EventFromNative(event);
+ bool event_handled = false;
+ bridge->host_->DispatchMonitorEvent(std::move(ui_event), &event_handled);
+ return event_handled ? nil : event;
+ };
+ key_down_event_monitor_ =
+ [NSEvent addLocalMonitorForEventsMatchingMask:NSKeyDownMask
+ handler:block];
+ } else {
+ // Destroy the event monitor if it exists.
+ if (!key_down_event_monitor_)
+ return;
+
+ [NSEvent removeMonitor:key_down_event_monitor_];
+ key_down_event_monitor_ = nil;
+ }
+}
+
bool NativeWidgetNSWindowBridge::HasWindowRestorationData() {
return !pending_restoration_data_.empty();
}
@@ -1232,8 +1272,9 @@ base::TimeDelta NativeWidgetNSWindowBridge::PreCommitTimeout() {
////////////////////////////////////////////////////////////////////////////////
// NativeWidgetNSWindowBridge, CocoaMouseCaptureDelegate:
-void NativeWidgetNSWindowBridge::PostCapturedEvent(NSEvent* event) {
+bool NativeWidgetNSWindowBridge::PostCapturedEvent(NSEvent* event) {
[bridged_view_ processCapturedMouseEvent:event];
+ return true;
}
void NativeWidgetNSWindowBridge::OnMouseCaptureLost() {
diff --git a/chromium/components/remote_cocoa/common/native_widget_ns_window.mojom b/chromium/components/remote_cocoa/common/native_widget_ns_window.mojom
index b82f559fb4c..1c02511cd1c 100644
--- a/chromium/components/remote_cocoa/common/native_widget_ns_window.mojom
+++ b/chromium/components/remote_cocoa/common/native_widget_ns_window.mojom
@@ -8,6 +8,7 @@ import "components/remote_cocoa/common/select_file_dialog.mojom";
import "mojo/public/mojom/base/string16.mojom";
import "services/network/public/mojom/network_param.mojom";
import "ui/base/mojom/ui_base_types.mojom";
+import "ui/events/mojom/event_constants.mojom";
import "ui/gfx/geometry/mojom/geometry.mojom";
import "ui/gfx/mojom/ca_layer_params.mojom";
@@ -73,6 +74,8 @@ struct NativeWidgetNSWindowInitParams {
// NSWindowCollectionBehaviorParticipatesInCycle (this is not the
// default for NSWindows with NSBorderlessWindowMask).
bool force_into_collection_cycle;
+ // If true, the window was created in headless mode.
+ bool is_headless_mode_window;
// An opaque blob of AppKit data which includes, among other things, a
// window's workspace and fullscreen state, and can be retrieved from or
// applied to a window.
@@ -226,6 +229,9 @@ interface NativeWidgetNSWindow {
// Redispatch a keyboard event using the widget's window's CommandDispatcher.
RedispatchKeyEvent(array<uint8> native_event_data);
+ // Enable or disable this widget's local event monitor.
+ SetLocalEventMonitorEnabled(bool enabled);
+
// Add the overlay NSView for a PWA with window controls overlay
// display override given a |overlay_type|.
CreateWindowControlsOverlayNSView(
diff --git a/chromium/components/remote_cocoa/common/native_widget_ns_window_host.mojom b/chromium/components/remote_cocoa/common/native_widget_ns_window_host.mojom
index 50daf00ce50..e7d68ead8cb 100644
--- a/chromium/components/remote_cocoa/common/native_widget_ns_window_host.mojom
+++ b/chromium/components/remote_cocoa/common/native_widget_ns_window_host.mojom
@@ -89,6 +89,11 @@ interface NativeWidgetNSWindowHost {
DispatchKeyEventToMenuControllerRemote(ui.mojom.Event event) =>
(bool event_swallowed, bool event_handled);
+ // Called when the NSEvent monitor observes an event. If `event_handled` is
+ // true, then do not continue dispatching the event.
+ [Sync]
+ DispatchMonitorEvent(ui.mojom.Event event) => (bool event_handled);
+
// Synchronously return in |has_menu_controller| whether or not a menu
// controller exists for this widget.
[Sync]
diff --git a/chromium/components/renderer_context_menu/render_view_context_menu_base.cc b/chromium/components/renderer_context_menu/render_view_context_menu_base.cc
index eb360c97768..3dfc21fddd9 100644
--- a/chromium/components/renderer_context_menu/render_view_context_menu_base.cc
+++ b/chromium/components/renderer_context_menu/render_view_context_menu_base.cc
@@ -254,7 +254,7 @@ void RenderViewContextMenuBase::UpdateMenuItem(int command_id,
menu_model_.SetEnabledAt(index, enabled);
menu_model_.SetVisibleAt(index, !hidden);
if (toolkit_delegate_) {
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
toolkit_delegate_->UpdateMenuItem(command_id, enabled, hidden, label);
#else
toolkit_delegate_->RebuildMenu();
diff --git a/chromium/components/reporting/DIR_METADATA b/chromium/components/reporting/DIR_METADATA
new file mode 100644
index 00000000000..f332abae154
--- /dev/null
+++ b/chromium/components/reporting/DIR_METADATA
@@ -0,0 +1 @@
+mixins: "//ash/components/policy/COMMON_METADATA"
diff --git a/chromium/components/reporting/client/empty_dm_token_retriever.cc b/chromium/components/reporting/client/empty_dm_token_retriever.cc
index 72a4d525839..6cd1b1b1a1c 100644
--- a/chromium/components/reporting/client/empty_dm_token_retriever.cc
+++ b/chromium/components/reporting/client/empty_dm_token_retriever.cc
@@ -4,6 +4,8 @@
#include "components/reporting/client/empty_dm_token_retriever.h"
+#include <utility>
+
#include "base/callback.h"
namespace reporting {
diff --git a/chromium/components/reporting/client/empty_dm_token_retriever.h b/chromium/components/reporting/client/empty_dm_token_retriever.h
index 2f1556a4c22..8090ee6b266 100644
--- a/chromium/components/reporting/client/empty_dm_token_retriever.h
+++ b/chromium/components/reporting/client/empty_dm_token_retriever.h
@@ -6,7 +6,6 @@
#define COMPONENTS_REPORTING_CLIENT_EMPTY_DM_TOKEN_RETRIEVER_H_
#include "components/reporting/client/dm_token_retriever.h"
-#include "components/reporting/util/statusor.h"
namespace reporting {
diff --git a/chromium/components/reporting/client/empty_dm_token_retriever_unittest.cc b/chromium/components/reporting/client/empty_dm_token_retriever_unittest.cc
index 89f3e670192..5a4de2413e6 100644
--- a/chromium/components/reporting/client/empty_dm_token_retriever_unittest.cc
+++ b/chromium/components/reporting/client/empty_dm_token_retriever_unittest.cc
@@ -4,6 +4,8 @@
#include "components/reporting/client/empty_dm_token_retriever.h"
+#include <string>
+
#include "base/bind.h"
#include "base/test/task_environment.h"
#include "components/reporting/util/statusor.h"
diff --git a/chromium/components/reporting/client/mock_dm_token_retriever.cc b/chromium/components/reporting/client/mock_dm_token_retriever.cc
index 9f91e2d9db6..e7c849544d1 100644
--- a/chromium/components/reporting/client/mock_dm_token_retriever.cc
+++ b/chromium/components/reporting/client/mock_dm_token_retriever.cc
@@ -4,8 +4,12 @@
#include "components/reporting/client/mock_dm_token_retriever.h"
+#include <string>
+#include <utility>
+
#include "base/test/gmock_callback_support.h"
#include "components/reporting/client/dm_token_retriever.h"
+#include "components/reporting/util/statusor.h"
namespace reporting {
diff --git a/chromium/components/reporting/client/mock_dm_token_retriever.h b/chromium/components/reporting/client/mock_dm_token_retriever.h
index 88e622b4d3b..9b6618cea18 100644
--- a/chromium/components/reporting/client/mock_dm_token_retriever.h
+++ b/chromium/components/reporting/client/mock_dm_token_retriever.h
@@ -5,7 +5,8 @@
#ifndef COMPONENTS_REPORTING_CLIENT_MOCK_DM_TOKEN_RETRIEVER_H_
#define COMPONENTS_REPORTING_CLIENT_MOCK_DM_TOKEN_RETRIEVER_H_
-#include "base/strings/string_piece_forward.h"
+#include <string>
+
#include "components/reporting/client/dm_token_retriever.h"
#include "testing/gmock/include/gmock/gmock.h"
diff --git a/chromium/components/reporting/client/mock_report_queue.h b/chromium/components/reporting/client/mock_report_queue.h
index e12c9fa902b..89bda0f6b6d 100644
--- a/chromium/components/reporting/client/mock_report_queue.h
+++ b/chromium/components/reporting/client/mock_report_queue.h
@@ -5,6 +5,8 @@
#ifndef COMPONENTS_REPORTING_CLIENT_MOCK_REPORT_QUEUE_H_
#define COMPONENTS_REPORTING_CLIENT_MOCK_REPORT_QUEUE_H_
+#include <memory>
+
#include "base/callback.h"
#include "components/reporting/client/report_queue.h"
#include "components/reporting/proto/synced/record.pb.h"
diff --git a/chromium/components/reporting/client/mock_report_queue_provider.cc b/chromium/components/reporting/client/mock_report_queue_provider.cc
index 837c7eb0d1a..bb4d59380f1 100644
--- a/chromium/components/reporting/client/mock_report_queue_provider.cc
+++ b/chromium/components/reporting/client/mock_report_queue_provider.cc
@@ -5,19 +5,18 @@
#include "components/reporting/client/mock_report_queue_provider.h"
#include <memory>
+#include <utility>
#include "base/bind.h"
#include "base/callback_helpers.h"
-#include "base/no_destructor.h"
#include "base/task/sequenced_task_runner.h"
#include "base/test/gmock_callback_support.h"
-#include "base/threading/sequenced_task_runner_handle.h"
+#include "base/threading/thread_task_runner_handle.h"
#include "components/reporting/client/mock_report_queue.h"
#include "components/reporting/client/report_queue.h"
#include "components/reporting/client/report_queue_configuration.h"
#include "components/reporting/client/report_queue_provider.h"
#include "components/reporting/storage/test_storage_module.h"
-#include "report_queue_provider.h"
#include "testing/gmock/include/gmock/gmock.h"
using ::base::test::RunOnceCallback;
@@ -32,12 +31,16 @@ MockReportQueueProvider::MockReportQueueProvider()
[](OnStorageModuleCreatedCallback storage_created_cb) {
std::move(storage_created_cb)
.Run(base::MakeRefCounted<test::TestStorageModule>());
- })) {}
+ })),
+ test_sequenced_task_runner_(base::ThreadTaskRunnerHandle::Get()) {}
+
MockReportQueueProvider::~MockReportQueueProvider() = default;
void MockReportQueueProvider::ExpectCreateNewQueueAndReturnNewMockQueue(
size_t times) {
- EXPECT_CALL(*this, CreateNewQueue(_, _))
+ CheckOnThread();
+
+ EXPECT_CALL(*this, CreateNewQueueMock(_, _))
.Times(times)
.WillRepeatedly([](std::unique_ptr<ReportQueueConfiguration> config,
CreateReportQueueCallback cb) {
@@ -47,13 +50,15 @@ void MockReportQueueProvider::ExpectCreateNewQueueAndReturnNewMockQueue(
void MockReportQueueProvider::
ExpectCreateNewSpeculativeQueueAndReturnNewMockQueue(size_t times) {
+ CheckOnThread();
+
// Mock internals so we do not unnecessarily create a new report queue.
- EXPECT_CALL(*this, CreateNewQueue(_, _))
+ EXPECT_CALL(*this, CreateNewQueueMock(_, _))
.Times(times)
.WillRepeatedly(
RunOnceCallback<1>(std::unique_ptr<ReportQueue>(nullptr)));
- EXPECT_CALL(*this, CreateNewSpeculativeQueue())
+ EXPECT_CALL(*this, CreateNewSpeculativeQueueMock())
.Times(times)
.WillRepeatedly([]() {
auto report_queue =
@@ -72,4 +77,47 @@ void MockReportQueueProvider::
});
}
+void MockReportQueueProvider::OnInitCompleted() {
+ // OnInitCompleted is called on a thread pool, so in order to make potential
+ // EXPECT_CALLs happen sequentially, we assign Mock to the test's main thread
+ // task runner.
+ test_sequenced_task_runner_->PostTask(
+ FROM_HERE, base::BindOnce(&MockReportQueueProvider::OnInitCompletedMock,
+ base::Unretained(this)));
+}
+
+void MockReportQueueProvider::CreateNewQueue(
+ std::unique_ptr<ReportQueueConfiguration> config,
+ CreateReportQueueCallback cb) {
+ // CreateNewQueue is called on a thread pool, so in order to make potential
+ // EXPECT_CALLs happen sequentially, we assign Mock to the test's main thread
+ // task runner.
+ test_sequenced_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(&MockReportQueueProvider::CreateNewQueueMock,
+ base::Unretained(this), std::move(config), std::move(cb)));
+}
+
+StatusOr<std::unique_ptr<ReportQueue, base::OnTaskRunnerDeleter>>
+MockReportQueueProvider::CreateNewSpeculativeQueue() {
+ CheckOnThread();
+ return CreateNewSpeculativeQueueMock();
+}
+
+void MockReportQueueProvider::ConfigureReportQueue(
+ std::unique_ptr<ReportQueueConfiguration> report_queue_config,
+ ReportQueueConfiguredCallback completion_cb) {
+ // ConfigureReportQueue is called on a thread pool, so in order to make
+ // potential EXPECT_CALLs happen sequentially, we assign Mock to the test's
+ // main thread task runner.
+ test_sequenced_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(&MockReportQueueProvider::ConfigureReportQueueMock,
+ base::Unretained(this), std::move(report_queue_config),
+ std::move(completion_cb)));
+}
+
+void MockReportQueueProvider::CheckOnThread() const {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(test_sequence_checker_);
+}
} // namespace reporting
diff --git a/chromium/components/reporting/client/mock_report_queue_provider.h b/chromium/components/reporting/client/mock_report_queue_provider.h
index f0fc1b5b471..bcfbbe7ab79 100644
--- a/chromium/components/reporting/client/mock_report_queue_provider.h
+++ b/chromium/components/reporting/client/mock_report_queue_provider.h
@@ -7,6 +7,7 @@
#include <memory>
+#include "base/sequence_checker.h"
#include "base/task/sequenced_task_runner.h"
#include "components/reporting/client/report_queue.h"
#include "components/reporting/client/report_queue_configuration.h"
@@ -35,28 +36,44 @@ class MockReportQueueProvider : public ReportQueueProvider {
// know how often you expect this method to be called.
void ExpectCreateNewSpeculativeQueueAndReturnNewMockQueue(size_t times);
+ // The following mocks will be invoked on the same thread
+ // MockReportQueueProvider was constructed on.
MOCK_METHOD(void,
- CreateNewQueue,
+ CreateNewQueueMock,
(std::unique_ptr<ReportQueueConfiguration> config,
CreateReportQueueCallback cb),
- (override));
+ ());
MOCK_METHOD(
(StatusOr<std::unique_ptr<ReportQueue, base::OnTaskRunnerDeleter>>),
- CreateNewSpeculativeQueue,
+ CreateNewSpeculativeQueueMock,
(),
- (override));
+ ());
- MOCK_METHOD(void, OnInitCompleted, (), ());
+ MOCK_METHOD(void, OnInitCompletedMock, (), ());
MOCK_METHOD(void,
- ConfigureReportQueue,
+ ConfigureReportQueueMock,
(std::unique_ptr<ReportQueueConfiguration> configuration,
ReportQueueProvider::ReportQueueConfiguredCallback callback),
- (override));
+ ());
+
+ void CheckOnThread() const;
private:
+ // Implementations of ReportQueueProvider virtual methods.
+ void OnInitCompleted() override;
+ void CreateNewQueue(std::unique_ptr<ReportQueueConfiguration> config,
+ CreateReportQueueCallback cb) override;
+ StatusOr<std::unique_ptr<ReportQueue, base::OnTaskRunnerDeleter>>
+ CreateNewSpeculativeQueue() override;
+ void ConfigureReportQueue(
+ std::unique_ptr<ReportQueueConfiguration> report_queue_config,
+ ReportQueueConfiguredCallback completion_cb) override;
+
scoped_refptr<StorageModuleInterface> storage_;
+ const scoped_refptr<base::SequencedTaskRunner> test_sequenced_task_runner_;
+ SEQUENCE_CHECKER(test_sequence_checker_);
};
} // namespace reporting
diff --git a/chromium/components/reporting/client/report_queue_configuration.cc b/chromium/components/reporting/client/report_queue_configuration.cc
index c4c75b299ff..3545ed203a7 100644
--- a/chromium/components/reporting/client/report_queue_configuration.cc
+++ b/chromium/components/reporting/client/report_queue_configuration.cc
@@ -4,6 +4,7 @@
#include "components/reporting/client/report_queue_configuration.h"
+#include <string>
#include <utility>
#include "base/bind.h"
diff --git a/chromium/components/reporting/client/report_queue_configuration.h b/chromium/components/reporting/client/report_queue_configuration.h
index c6b5786654d..d00bb0f451b 100644
--- a/chromium/components/reporting/client/report_queue_configuration.h
+++ b/chromium/components/reporting/client/report_queue_configuration.h
@@ -6,6 +6,7 @@
#define COMPONENTS_REPORTING_CLIENT_REPORT_QUEUE_CONFIGURATION_H_
#include <memory>
+#include <string>
#include <utility>
#include "base/callback.h"
@@ -21,11 +22,13 @@ enum class EventType { kDevice, kUser };
// ReportQueueConfiguration configures a report queue.
// |dm_token| if set will be attached to all records generated with this queue.
-// |event_type| describes the event type being reported and is indirectly used
-// to retrieve DM tokens for downstream processing. |destination| indicates what
-// server side handler will be handling the records that are generated by the
-// ReportQueueImpl. |policy_check_callback_| is a RepeatingCallback that
-// verifies the specific report queue is allowed.
+// Pass user DM tokens where applicable so the server can associate these events
+// with the user. |event_type| describes the event type being reported and is
+// indirectly used to retrieve DM tokens for downstream processing. Please use
+// |EventType::kUser| for events that need to be associated with the current
+// user. |destination| indicates what server side handler will be handling the
+// records that are generated by the ReportQueueImpl. |policy_check_callback_|
+// is a RepeatingCallback that verifies the specific report queue is allowed.
class ReportQueueConfiguration {
public:
// PolicyCheckCallbacks should return error::UNAUTHENTICATED if a policy check
@@ -38,6 +41,8 @@ class ReportQueueConfiguration {
ReportQueueConfiguration& operator=(const ReportQueueConfiguration& other) =
delete;
+ // Deprecated and should not be used.
+ //
// Factory for generating a ReportQueueConfiguration.
// If any of the parameters are invalid, will return error::INVALID_ARGUMENT.
// |dm_token| is valid when dm_token.is_valid() is true.
@@ -51,10 +56,11 @@ class ReportQueueConfiguration {
// Factory for generating a ReportQueueConfiguration.
// |event_type| is the type of event being reported, and is indirectly used to
// retrieve DM tokens for downstream processing when building the report
- // queue. Using |EventType::kDevice| will skip DM token retrieval. If
- // any of the parameters are invalid, will return error::INVALID_ARGUMENT.
- // |destination| is valid when it is any value other than
- // Destination::UNDEFINED_DESTINATION.
+ // queue. Using |EventType::kDevice| will skip DM token retrieval, so please
+ // use |EventType::kUser| for events that need to be associated with the
+ // current user. If any of the parameters are invalid, will return
+ // error::INVALID_ARGUMENT. |destination| is valid when it is any value other
+ // than Destination::UNDEFINED_DESTINATION.
static StatusOr<std::unique_ptr<ReportQueueConfiguration>> Create(
EventType event_type,
Destination destination,
diff --git a/chromium/components/reporting/client/report_queue_factory.cc b/chromium/components/reporting/client/report_queue_factory.cc
index e5e62470a8d..7e9d7a198af 100644
--- a/chromium/components/reporting/client/report_queue_factory.cc
+++ b/chromium/components/reporting/client/report_queue_factory.cc
@@ -4,12 +4,13 @@
#include "components/reporting/client/report_queue_factory.h"
+#include <utility>
+
#include "base/bind.h"
#include "base/callback.h"
#include "base/strings/string_piece.h"
#include "base/task/bind_post_task.h"
#include "base/threading/thread_task_runner_handle.h"
-#include "build/build_config.h"
#include "components/reporting/client/report_queue_configuration.h"
#include "components/reporting/client/report_queue_provider.h"
#include "components/reporting/util/backoff_settings.h"
@@ -90,7 +91,8 @@ ReportQueueFactory::CreateSpeculativeReportQueue(
::reporting::ReportQueueProvider::CreateSpeculativeQueue(
std::move(config_result.ValueOrDie()));
if (!speculative_queue_result.ok()) {
- DVLOG(1) << "Failed to create speculative queue";
+ DVLOG(1) << "Failed to create speculative queue: "
+ << speculative_queue_result.status();
return std::unique_ptr<::reporting::ReportQueue, base::OnTaskRunnerDeleter>(
nullptr,
base::OnTaskRunnerDeleter(base::SequencedTaskRunnerHandle::Get()));
@@ -122,7 +124,8 @@ ReportQueueFactory::CreateSpeculativeReportQueue(EventType event_type,
::reporting::ReportQueueProvider::CreateSpeculativeQueue(
std::move(config_result.ValueOrDie()));
if (!speculative_queue_result.ok()) {
- DVLOG(1) << "Failed to create speculative queue";
+ DVLOG(1) << "Failed to create speculative queue: "
+ << speculative_queue_result.status();
return std::unique_ptr<::reporting::ReportQueue, base::OnTaskRunnerDeleter>(
nullptr,
base::OnTaskRunnerDeleter(base::SequencedTaskRunnerHandle::Get()));
diff --git a/chromium/components/reporting/client/report_queue_factory_unittest.cc b/chromium/components/reporting/client/report_queue_factory_unittest.cc
index 95922b8bebc..7f3707af31f 100644
--- a/chromium/components/reporting/client/report_queue_factory_unittest.cc
+++ b/chromium/components/reporting/client/report_queue_factory_unittest.cc
@@ -6,6 +6,7 @@
#include <memory>
#include <string>
+#include <utility>
#include "base/logging.h"
#include "base/memory/weak_ptr.h"
@@ -14,6 +15,7 @@
#include "components/reporting/client/mock_report_queue_provider.h"
#include "components/reporting/client/report_queue.h"
#include "components/reporting/client/report_queue_provider_test_helper.h"
+#include "components/reporting/util/test_support_callbacks.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -29,13 +31,17 @@ namespace reporting {
class MockReportQueueConsumer {
public:
MockReportQueueConsumer() = default;
- void SetReportQueue(std::unique_ptr<ReportQueue> report_queue) {
+ void SetReportQueue(test::TestCallbackWaiter* waiter,
+ std::unique_ptr<ReportQueue> report_queue) {
report_queue_ = std::move(report_queue);
+ if (waiter) {
+ waiter->Signal();
+ }
}
base::OnceCallback<void(std::unique_ptr<reporting::ReportQueue>)>
- GetReportQueueSetter() {
+ GetReportQueueSetter(test::TestCallbackWaiter* waiter) {
return base::BindOnce(&MockReportQueueConsumer::SetReportQueue,
- weak_factory_.GetWeakPtr());
+ weak_factory_.GetWeakPtr(), base::Unretained(waiter));
}
ReportQueue* GetReportQueue() const { return report_queue_.get(); }
@@ -55,6 +61,7 @@ class ReportQueueFactoryTest : public ::testing::Test {
}
void TearDown() override {
+ task_environment_.RunUntilIdle(); // Drain remaining scheduled tasks.
report_queue_provider_test_helper::SetForTesting(nullptr);
}
@@ -70,12 +77,14 @@ class ReportQueueFactoryTest : public ::testing::Test {
TEST_F(ReportQueueFactoryTest, CreateAndGetQueueUsingDMToken) {
// Initially the queue must be an uninitialized unique_ptr
EXPECT_FALSE(consumer_->GetReportQueue());
- reporting::ReportQueueFactory::Create(/*dm_token_value=*/"TOKEN",
- destination_,
- consumer_->GetReportQueueSetter());
- EXPECT_CALL(*provider_.get(), OnInitCompleted()).Times(1);
- provider_->ExpectCreateNewQueueAndReturnNewMockQueue(1);
- task_environment_.RunUntilIdle();
+ {
+ test::TestCallbackAutoWaiter set_waiter;
+ reporting::ReportQueueFactory::Create(
+ /*dm_token_value=*/"TOKEN", destination_,
+ consumer_->GetReportQueueSetter(&set_waiter));
+ EXPECT_CALL(*provider_.get(), OnInitCompletedMock()).Times(1);
+ provider_->ExpectCreateNewQueueAndReturnNewMockQueue(1);
+ }
// We expect the report queue to be existing in the consumer.
EXPECT_TRUE(consumer_->GetReportQueue());
}
@@ -83,11 +92,14 @@ TEST_F(ReportQueueFactoryTest, CreateAndGetQueueUsingDMToken) {
TEST_F(ReportQueueFactoryTest, CreateAndGetQueue) {
// Initially the queue must be an uninitialized unique_ptr
EXPECT_FALSE(consumer_->GetReportQueue());
- reporting::ReportQueueFactory::Create(EventType::kDevice, destination_,
- consumer_->GetReportQueueSetter());
- EXPECT_CALL(*provider_.get(), OnInitCompleted()).Times(1);
- provider_->ExpectCreateNewQueueAndReturnNewMockQueue(1);
- task_environment_.RunUntilIdle();
+ {
+ test::TestCallbackAutoWaiter set_waiter;
+ reporting::ReportQueueFactory::Create(
+ EventType::kDevice, destination_,
+ consumer_->GetReportQueueSetter(&set_waiter));
+ EXPECT_CALL(*provider_.get(), OnInitCompletedMock()).Times(1);
+ provider_->ExpectCreateNewQueueAndReturnNewMockQueue(1);
+ }
// We expect the report queue to be existing in the consumer.
EXPECT_TRUE(consumer_->GetReportQueue());
}
@@ -95,12 +107,11 @@ TEST_F(ReportQueueFactoryTest, CreateAndGetQueue) {
TEST_F(ReportQueueFactoryTest, CreateQueueWithInvalidConfig) {
// Initially the queue must be an uninitialized unique_ptr
EXPECT_FALSE(consumer_->GetReportQueue());
- reporting::ReportQueueFactory::Create(EventType::kDevice,
- Destination::UNDEFINED_DESTINATION,
- consumer_->GetReportQueueSetter());
+ reporting::ReportQueueFactory::Create(
+ EventType::kDevice, Destination::UNDEFINED_DESTINATION,
+ consumer_->GetReportQueueSetter(nullptr));
// Expect failure before it gets to the report queue provider
- EXPECT_CALL(*provider_.get(), OnInitCompleted()).Times(0);
- task_environment_.RunUntilIdle();
+ EXPECT_CALL(*provider_.get(), OnInitCompletedMock()).Times(0);
// We do not expect the report queue to be existing in the consumer.
EXPECT_FALSE(consumer_->GetReportQueue());
}
@@ -111,7 +122,6 @@ TEST_F(ReportQueueFactoryTest, CreateSpeculativeQueue) {
const auto report_queue =
reporting::ReportQueueFactory::CreateSpeculativeReportQueue(
EventType::kDevice, destination_);
- task_environment_.RunUntilIdle();
EXPECT_THAT(report_queue, NotNull());
}
@@ -119,18 +129,19 @@ TEST_F(ReportQueueFactoryTest, CreateSpeculativeQueueWithInvalidConfig) {
const auto report_queue =
reporting::ReportQueueFactory::CreateSpeculativeReportQueue(
EventType::kDevice, Destination::UNDEFINED_DESTINATION);
- task_environment_.RunUntilIdle();
EXPECT_THAT(report_queue, IsNull());
}
TEST_F(ReportQueueFactoryTest, EmptyDmToken) {
// Initially the queue must be an uninitialized unique_ptr
EXPECT_FALSE(consumer_->GetReportQueue());
- reporting::ReportQueueFactory::Create("", destination_,
- consumer_->GetReportQueueSetter());
- EXPECT_CALL(*provider_.get(), OnInitCompleted()).Times(1);
- provider_->ExpectCreateNewQueueAndReturnNewMockQueue(1);
- task_environment_.RunUntilIdle();
+ {
+ test::TestCallbackAutoWaiter set_waiter;
+ reporting::ReportQueueFactory::Create(
+ "", destination_, consumer_->GetReportQueueSetter(&set_waiter));
+ EXPECT_CALL(*provider_.get(), OnInitCompletedMock()).Times(1);
+ provider_->ExpectCreateNewQueueAndReturnNewMockQueue(1);
+ }
// We expect the report queue to be existing in the consumer.
EXPECT_TRUE(consumer_->GetReportQueue());
}
@@ -140,13 +151,18 @@ TEST_F(ReportQueueFactoryTest, SameProviderForMultipleThreads) {
auto consumer2 = std::make_unique<MockReportQueueConsumer>();
EXPECT_FALSE(consumer_->GetReportQueue());
EXPECT_FALSE(consumer2->GetReportQueue());
- reporting::ReportQueueFactory::Create(EventType::kDevice, destination_,
- consumer_->GetReportQueueSetter());
- reporting::ReportQueueFactory::Create(EventType::kUser, destination_,
- consumer2->GetReportQueueSetter());
- EXPECT_CALL(*provider_.get(), OnInitCompleted()).Times(1);
- provider_->ExpectCreateNewQueueAndReturnNewMockQueue(2);
- task_environment_.RunUntilIdle();
+ {
+ test::TestCallbackAutoWaiter set_waiter;
+ set_waiter.Attach();
+ reporting::ReportQueueFactory::Create(
+ EventType::kDevice, destination_,
+ consumer_->GetReportQueueSetter(&set_waiter));
+ reporting::ReportQueueFactory::Create(
+ EventType::kUser, destination_,
+ consumer2->GetReportQueueSetter(&set_waiter));
+ EXPECT_CALL(*provider_.get(), OnInitCompletedMock()).Times(1);
+ provider_->ExpectCreateNewQueueAndReturnNewMockQueue(2);
+ }
// We expect the report queue to be existing in the consumer.
EXPECT_TRUE(consumer_->GetReportQueue());
// And for the 2nd consumer
diff --git a/chromium/components/reporting/client/report_queue_impl.cc b/chromium/components/reporting/client/report_queue_impl.cc
index 86387416ad5..1c6a81d580f 100644
--- a/chromium/components/reporting/client/report_queue_impl.cc
+++ b/chromium/components/reporting/client/report_queue_impl.cc
@@ -5,6 +5,7 @@
#include "components/reporting/client/report_queue_impl.h"
#include <memory>
+#include <queue>
#include <string>
#include <utility>
@@ -23,7 +24,6 @@
#include "base/time/time.h"
#include "base/values.h"
#include "components/reporting/client/report_queue_configuration.h"
-#include "components/reporting/encryption/encryption_module.h"
#include "components/reporting/proto/synced/record.pb.h"
#include "components/reporting/proto/synced/record_constants.pb.h"
#include "components/reporting/storage/storage_module_interface.h"
diff --git a/chromium/components/reporting/client/report_queue_impl.h b/chromium/components/reporting/client/report_queue_impl.h
index 64e3e9edbab..2b603c99174 100644
--- a/chromium/components/reporting/client/report_queue_impl.h
+++ b/chromium/components/reporting/client/report_queue_impl.h
@@ -6,6 +6,7 @@
#define COMPONENTS_REPORTING_CLIENT_REPORT_QUEUE_IMPL_H_
#include <memory>
+#include <queue>
#include <string>
#include <utility>
diff --git a/chromium/components/reporting/client/report_queue_provider.cc b/chromium/components/reporting/client/report_queue_provider.cc
index 8ba2d75d85d..53b1c7af782 100644
--- a/chromium/components/reporting/client/report_queue_provider.cc
+++ b/chromium/components/reporting/client/report_queue_provider.cc
@@ -5,6 +5,7 @@
#include "components/reporting/client/report_queue_provider.h"
#include <memory>
+#include <string>
#include "base/bind.h"
#include "base/callback.h"
@@ -22,7 +23,6 @@
#include "components/reporting/client/report_queue_impl.h"
#include "components/reporting/proto/synced/record_constants.pb.h"
#include "components/reporting/storage/storage_module_interface.h"
-#include "components/reporting/storage_selector/storage_selector.h"
#include "components/reporting/util/shared_queue.h"
#include "components/reporting/util/status.h"
#include "components/reporting/util/statusor.h"
diff --git a/chromium/components/reporting/client/report_queue_provider_test_helper.cc b/chromium/components/reporting/client/report_queue_provider_test_helper.cc
index 58f19fdfc57..a8b2a9e1347 100644
--- a/chromium/components/reporting/client/report_queue_provider_test_helper.cc
+++ b/chromium/components/reporting/client/report_queue_provider_test_helper.cc
@@ -19,7 +19,7 @@ void SetForTesting(MockReportQueueProvider* provider) {
} // namespace report_queue_provider_test_helper
-// Implementation of the mock report provider for this test.
+// Implementation of the mock report provider for this test helper.
ReportQueueProvider* ReportQueueProvider::GetInstance() {
return report_queue_provider_test_helper::g_mock_report_queue_provider;
}
diff --git a/chromium/components/reporting/client/report_queue_provider_unittest.cc b/chromium/components/reporting/client/report_queue_provider_unittest.cc
index 554e480db02..51c66c991d5 100644
--- a/chromium/components/reporting/client/report_queue_provider_unittest.cc
+++ b/chromium/components/reporting/client/report_queue_provider_unittest.cc
@@ -3,7 +3,9 @@
// found in the LICENSE file.
#include "components/reporting/client/report_queue_provider.h"
+
#include <memory>
+#include <string>
#include "base/bind.h"
#include "base/task/thread_pool.h"
@@ -50,7 +52,7 @@ TEST_F(ReportQueueProviderTest, CreateAndGetQueue) {
auto config_result = ReportQueueConfiguration::Create(
EventType::kDevice, destination_, policy_checker_callback_);
ASSERT_OK(config_result);
- EXPECT_CALL(*provider.get(), OnInitCompleted()).Times(1);
+ EXPECT_CALL(*provider.get(), OnInitCompletedMock()).Times(1);
provider->ExpectCreateNewQueueAndReturnNewMockQueue(1);
// Use it to asynchronously create ReportingQueue and then asynchronously
// send the message.
diff --git a/chromium/components/reporting/encryption/encryption_module.cc b/chromium/components/reporting/encryption/encryption_module.cc
index 49a43af944a..6cba25bd6b1 100644
--- a/chromium/components/reporting/encryption/encryption_module.cc
+++ b/chromium/components/reporting/encryption/encryption_module.cc
@@ -4,7 +4,6 @@
#include "components/reporting/encryption/encryption_module.h"
-#include <atomic>
#include <string>
#include <utility>
diff --git a/chromium/components/reporting/encryption/encryption_module.h b/chromium/components/reporting/encryption/encryption_module.h
index 46894b122e3..653f04d466f 100644
--- a/chromium/components/reporting/encryption/encryption_module.h
+++ b/chromium/components/reporting/encryption/encryption_module.h
@@ -5,8 +5,6 @@
#ifndef COMPONENTS_REPORTING_ENCRYPTION_ENCRYPTION_MODULE_H_
#define COMPONENTS_REPORTING_ENCRYPTION_ENCRYPTION_MODULE_H_
-#include <atomic>
-
#include "base/callback.h"
#include "base/memory/ref_counted.h"
#include "base/strings/string_piece.h"
diff --git a/chromium/components/reporting/encryption/encryption_module_interface.cc b/chromium/components/reporting/encryption/encryption_module_interface.cc
index 1ca9997d6c3..49b5585c7ed 100644
--- a/chromium/components/reporting/encryption/encryption_module_interface.cc
+++ b/chromium/components/reporting/encryption/encryption_module_interface.cc
@@ -4,8 +4,6 @@
#include "components/reporting/encryption/encryption_module_interface.h"
-#include <atomic>
-
#include "base/callback.h"
#include "base/feature_list.h"
#include "base/strings/string_piece.h"
diff --git a/chromium/components/reporting/metrics/fake_metric_report_queue.h b/chromium/components/reporting/metrics/fake_metric_report_queue.h
index 9c81145ed7a..beee1d1bd53 100644
--- a/chromium/components/reporting/metrics/fake_metric_report_queue.h
+++ b/chromium/components/reporting/metrics/fake_metric_report_queue.h
@@ -32,13 +32,13 @@ class FakeMetricReportQueue : public MetricReportQueue {
void Enqueue(const MetricData& metric_data,
ReportQueue::EnqueueCallback callback) override;
- void Flush() override;
-
std::vector<MetricData> GetMetricDataReported() const;
int GetNumFlush() const;
private:
+ void Flush() override;
+
std::vector<MetricData> reported_data_;
int num_flush_ = 0;
diff --git a/chromium/components/reporting/metrics/fake_reporting_settings.cc b/chromium/components/reporting/metrics/fake_reporting_settings.cc
index 0ad9d822b19..ce249439241 100644
--- a/chromium/components/reporting/metrics/fake_reporting_settings.cc
+++ b/chromium/components/reporting/metrics/fake_reporting_settings.cc
@@ -9,6 +9,8 @@
#include "base/threading/sequenced_task_runner_handle.h"
namespace reporting {
+namespace test {
+
FakeReportingSettings::FakeReportingSettings() = default;
FakeReportingSettings::~FakeReportingSettings() = default;
@@ -74,4 +76,5 @@ void FakeReportingSettings::SetIsTrusted(bool is_trusted) {
run_loop.QuitClosure());
run_loop.Run();
}
+} // namespace test
} // namespace reporting
diff --git a/chromium/components/reporting/metrics/fake_reporting_settings.h b/chromium/components/reporting/metrics/fake_reporting_settings.h
index 0a32049b124..3927f69a467 100644
--- a/chromium/components/reporting/metrics/fake_reporting_settings.h
+++ b/chromium/components/reporting/metrics/fake_reporting_settings.h
@@ -15,6 +15,7 @@
#include "components/reporting/metrics/reporting_settings.h"
namespace reporting {
+namespace test {
// Fake reporting settings for testing.
class FakeReportingSettings : public ReportingSettings {
@@ -52,6 +53,7 @@ class FakeReportingSettings : public ReportingSettings {
bool is_trusted_ = true;
};
+} // namespace test
} // namespace reporting
#endif // COMPONENTS_REPORTING_METRICS_FAKE_REPORTING_SETTINGS_H_
diff --git a/chromium/components/reporting/metrics/fake_sampler.cc b/chromium/components/reporting/metrics/fake_sampler.cc
index 125a49c2a4d..d92ada76c48 100644
--- a/chromium/components/reporting/metrics/fake_sampler.cc
+++ b/chromium/components/reporting/metrics/fake_sampler.cc
@@ -16,7 +16,7 @@ namespace test {
void FakeSampler::Collect(MetricCallback cb) {
num_calls_++;
- std::move(cb).Run(std::move(metric_data_));
+ std::move(cb).Run(metric_data_);
}
void FakeSampler::SetMetricData(MetricData metric_data) {
diff --git a/chromium/components/reporting/metrics/metric_data_collector.cc b/chromium/components/reporting/metrics/metric_data_collector.cc
index d1cc4bf39e9..98580070636 100644
--- a/chromium/components/reporting/metrics/metric_data_collector.cc
+++ b/chromium/components/reporting/metrics/metric_data_collector.cc
@@ -53,11 +53,12 @@ OneShotCollector::OneShotCollector(Sampler* sampler,
MetricReportQueue* metric_report_queue,
ReportingSettings* reporting_settings,
const std::string& setting_path,
+ bool setting_enabled_default_value,
base::OnceClosure on_data_reported)
: CollectorBase(sampler, metric_report_queue),
on_data_reported_(std::move(on_data_reported)) {
reporting_controller_ = std::make_unique<MetricReportingController>(
- reporting_settings, setting_path,
+ reporting_settings, setting_path, setting_enabled_default_value,
base::BindRepeating(&OneShotCollector::Collect, base::Unretained(this)));
}
@@ -86,6 +87,7 @@ PeriodicCollector::PeriodicCollector(Sampler* sampler,
MetricReportQueue* metric_report_queue,
ReportingSettings* reporting_settings,
const std::string& enable_setting_path,
+ bool setting_enabled_default_value,
const std::string& rate_setting_path,
base::TimeDelta default_rate,
int rate_unit_to_ms)
@@ -100,6 +102,7 @@ PeriodicCollector::PeriodicCollector(Sampler* sampler,
reporting_controller_(std::make_unique<MetricReportingController>(
reporting_settings,
enable_setting_path,
+ setting_enabled_default_value,
base::BindRepeating(&PeriodicEventCollector::StartPeriodicCollection,
base::Unretained(this)),
base::BindRepeating(&PeriodicEventCollector::StopPeriodicCollection,
@@ -116,6 +119,8 @@ void PeriodicCollector::OnMetricDataCollected(MetricData metric_data) {
void PeriodicCollector::StartPeriodicCollection() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ // Do initial collection at startup.
+ Collect();
rate_controller_->Start();
}
@@ -171,6 +176,7 @@ PeriodicEventCollector::PeriodicEventCollector(
MetricReportQueue* metric_report_queue,
ReportingSettings* reporting_settings,
const std::string& enable_setting_path,
+ bool setting_enabled_default_value,
const std::string& rate_setting_path,
base::TimeDelta default_rate,
int rate_unit_to_ms)
@@ -178,6 +184,7 @@ PeriodicEventCollector::PeriodicEventCollector(
metric_report_queue,
reporting_settings,
enable_setting_path,
+ setting_enabled_default_value,
rate_setting_path,
default_rate,
rate_unit_to_ms),
diff --git a/chromium/components/reporting/metrics/metric_data_collector.h b/chromium/components/reporting/metrics/metric_data_collector.h
index 9c5aa879ad8..7b7253fb382 100644
--- a/chromium/components/reporting/metrics/metric_data_collector.h
+++ b/chromium/components/reporting/metrics/metric_data_collector.h
@@ -63,6 +63,7 @@ class OneShotCollector : public CollectorBase {
MetricReportQueue* metric_report_queue,
ReportingSettings* reporting_settings,
const std::string& setting_path,
+ bool setting_enabled_default_value,
base::OnceClosure on_data_reported = base::DoNothing());
OneShotCollector(const OneShotCollector& other) = delete;
@@ -91,6 +92,7 @@ class PeriodicCollector : public CollectorBase {
MetricReportQueue* metric_report_queue,
ReportingSettings* reporting_settings,
const std::string& enable_setting_path,
+ bool setting_enabled_default_value,
const std::string& rate_setting_path,
base::TimeDelta default_rate,
int rate_unit_to_ms = 1);
@@ -163,6 +165,7 @@ class PeriodicEventCollector : public PeriodicCollector {
MetricReportQueue* metric_report_queue,
ReportingSettings* reporting_settings,
const std::string& enable_setting_path,
+ bool setting_enabled_default_value,
const std::string& rate_setting_path,
base::TimeDelta default_rate,
int rate_unit_to_ms = 1);
diff --git a/chromium/components/reporting/metrics/metric_data_collector_unittest.cc b/chromium/components/reporting/metrics/metric_data_collector_unittest.cc
index d8857b10e79..9d1ab6f73de 100644
--- a/chromium/components/reporting/metrics/metric_data_collector_unittest.cc
+++ b/chromium/components/reporting/metrics/metric_data_collector_unittest.cc
@@ -56,22 +56,30 @@ class FakeEventDetector : public EventDetector {
};
} // namespace test
+namespace {
+
class MetricDataCollectorTest : public ::testing::Test {
- public:
+ protected:
void SetUp() override {
- settings_ = std::make_unique<FakeReportingSettings>();
+ settings_ = std::make_unique<test::FakeReportingSettings>();
sampler_ = std::make_unique<test::FakeSampler>();
metric_report_queue_ = std::make_unique<test::FakeMetricReportQueue>();
}
- protected:
+ void FlushTasks() {
+ base::RunLoop run_loop;
+ task_environment_.GetMainThreadTaskRunner()->PostTask(
+ FROM_HERE, run_loop.QuitClosure());
+ run_loop.Run();
+ }
+
base::test::SingleThreadTaskEnvironment task_environment_{
base::test::TaskEnvironment::TimeSource::MOCK_TIME};
const std::string kEnableSettingPath = "enable_path";
const std::string kRateSettingPath = "rate_path";
- std::unique_ptr<FakeReportingSettings> settings_;
+ std::unique_ptr<test::FakeReportingSettings> settings_;
std::unique_ptr<test::FakeSampler> sampler_;
std::unique_ptr<test::FakeMetricReportQueue> metric_report_queue_;
};
@@ -86,6 +94,7 @@ TEST_F(MetricDataCollectorTest, OneShotCollector_InitiallyEnabled) {
OneShotCollector collector(sampler_.get(), metric_report_queue_.get(),
settings_.get(), kEnableSettingPath,
+ /*setting_enabled_default_value=*/false,
base::BindLambdaForTesting([&callback_called]() {
callback_called = true;
}));
@@ -100,10 +109,7 @@ TEST_F(MetricDataCollectorTest, OneShotCollector_InitiallyEnabled) {
// re-enabled.
EXPECT_EQ(sampler_->GetNumCollectCalls(), 1);
- base::RunLoop run_loop;
- task_environment_.GetMainThreadTaskRunner()->PostTask(FROM_HERE,
- run_loop.QuitClosure());
- run_loop.Run();
+ FlushTasks();
auto metric_data_reported = metric_report_queue_->GetMetricDataReported();
ASSERT_EQ(metric_data_reported.size(), 1ul);
@@ -120,7 +126,8 @@ TEST_F(MetricDataCollectorTest, OneShotCollector_InitiallyDisabled) {
sampler_->SetMetricData(std::move(metric_data));
OneShotCollector collector(sampler_.get(), metric_report_queue_.get(),
- settings_.get(), kEnableSettingPath);
+ settings_.get(), kEnableSettingPath,
+ /*setting_enabled_default_value=*/false);
// Setting is initially disabled, no data is collected.
EXPECT_EQ(sampler_->GetNumCollectCalls(), 0);
@@ -137,36 +144,82 @@ TEST_F(MetricDataCollectorTest, OneShotCollector_InitiallyDisabled) {
// re-enabled.
EXPECT_EQ(sampler_->GetNumCollectCalls(), 1);
- base::RunLoop run_loop;
- task_environment_.GetMainThreadTaskRunner()->PostTask(FROM_HERE,
- run_loop.QuitClosure());
- run_loop.Run();
+ FlushTasks();
+ auto metric_data_reported = metric_report_queue_->GetMetricDataReported();
+
+ ASSERT_EQ(metric_data_reported.size(), 1ul);
+ EXPECT_TRUE(metric_data_reported[0].has_timestamp_ms());
+ EXPECT_TRUE(metric_data_reported[0].has_info_data());
+}
+
+TEST_F(MetricDataCollectorTest, OneShotCollector_DefaultEnabled) {
+ MetricData metric_data;
+ metric_data.mutable_info_data();
+ sampler_->SetMetricData(std::move(metric_data));
+ bool callback_called = false;
+
+ OneShotCollector collector(sampler_.get(), metric_report_queue_.get(),
+ settings_.get(), "invalid/path",
+ /*setting_enabled_default_value=*/true,
+ base::BindLambdaForTesting([&callback_called]() {
+ callback_called = true;
+ }));
+
+ // Setting is enabled by default, data is being collected.
+ EXPECT_EQ(sampler_->GetNumCollectCalls(), 1);
+
+ FlushTasks();
auto metric_data_reported = metric_report_queue_->GetMetricDataReported();
ASSERT_EQ(metric_data_reported.size(), 1ul);
+ EXPECT_TRUE(callback_called);
EXPECT_TRUE(metric_data_reported[0].has_timestamp_ms());
EXPECT_TRUE(metric_data_reported[0].has_info_data());
}
+TEST_F(MetricDataCollectorTest, OneShotCollector_DefaultDisabled) {
+ MetricData metric_data;
+ metric_data.mutable_info_data();
+ sampler_->SetMetricData(std::move(metric_data));
+
+ OneShotCollector collector(sampler_.get(), metric_report_queue_.get(),
+ settings_.get(), kEnableSettingPath,
+ /*setting_enabled_default_value=*/false);
+ FlushTasks();
+
+ // Setting is disabled by default, no data is collected.
+ EXPECT_EQ(sampler_->GetNumCollectCalls(), 0);
+ EXPECT_TRUE(metric_report_queue_->GetMetricDataReported().empty());
+}
+
TEST_F(MetricDataCollectorTest, PeriodicCollector_InitiallyEnabled) {
constexpr int interval = 10000;
settings_->SetBoolean(kEnableSettingPath, true);
settings_->SetInteger(kRateSettingPath, interval);
- MetricData metric_data[3];
+ MetricData metric_data[5];
metric_data[0].mutable_telemetry_data();
metric_data[1].mutable_info_data();
metric_data[2].mutable_event_data();
+ metric_data[3].mutable_telemetry_data();
+ metric_data[3].mutable_event_data();
+ metric_data[4].mutable_info_data();
+ metric_data[4].mutable_event_data();
+ sampler_->SetMetricData(metric_data[0]);
PeriodicCollector collector(
sampler_.get(), metric_report_queue_.get(), settings_.get(),
- kEnableSettingPath, kRateSettingPath, base::Milliseconds(interval / 2));
+ kEnableSettingPath, /*setting_enabled_default_value=*/false,
+ kRateSettingPath, base::Milliseconds(interval / 2));
- EXPECT_EQ(sampler_->GetNumCollectCalls(), 0);
+ // One initial collection at startup.
+ EXPECT_EQ(sampler_->GetNumCollectCalls(), 1);
+ FlushTasks();
- int expected_collect_calls = 0;
+ // Expected calls count initialized to 1 to reflect the initial collection.
+ int expected_collect_calls = 1;
for (int i = 0; i < 2; ++i) {
- sampler_->SetMetricData(metric_data[i]);
+ sampler_->SetMetricData(metric_data[i + 1]);
// 5 secs elapsed, no new data collected.
task_environment_.FastForwardBy(base::Milliseconds(interval / 2));
EXPECT_EQ(sampler_->GetNumCollectCalls(), expected_collect_calls);
@@ -175,15 +228,23 @@ TEST_F(MetricDataCollectorTest, PeriodicCollector_InitiallyEnabled) {
// 10 secs elapsed, data should be collected.
task_environment_.FastForwardBy(base::Milliseconds(interval / 2));
EXPECT_EQ(sampler_->GetNumCollectCalls(), expected_collect_calls);
+ FlushTasks();
}
- sampler_->SetMetricData(metric_data[2]);
+ sampler_->SetMetricData(metric_data[3]);
settings_->SetBoolean(kEnableSettingPath, false);
// Setting disabled, no data should be collected.
task_environment_.FastForwardBy(base::Milliseconds(interval));
EXPECT_EQ(sampler_->GetNumCollectCalls(), expected_collect_calls);
+ FlushTasks();
settings_->SetBoolean(kEnableSettingPath, true);
+ // Initial collection at policy enablement.
+ ++expected_collect_calls;
+ EXPECT_EQ(sampler_->GetNumCollectCalls(), expected_collect_calls);
+ FlushTasks();
+
+ sampler_->SetMetricData(metric_data[4]);
// Setting enabled, data should be collected after interval.
task_environment_.FastForwardBy(base::Milliseconds(interval / 2));
EXPECT_EQ(sampler_->GetNumCollectCalls(), expected_collect_calls);
@@ -191,14 +252,11 @@ TEST_F(MetricDataCollectorTest, PeriodicCollector_InitiallyEnabled) {
task_environment_.FastForwardBy(base::Milliseconds(interval / 2));
EXPECT_EQ(sampler_->GetNumCollectCalls(), expected_collect_calls);
- base::RunLoop run_loop;
- task_environment_.GetMainThreadTaskRunner()->PostTask(FROM_HERE,
- run_loop.QuitClosure());
- run_loop.Run();
+ FlushTasks();
auto metric_data_reported = metric_report_queue_->GetMetricDataReported();
- ASSERT_EQ(metric_data_reported.size(), 3ul);
- for (int i = 0; i < 3; ++i) {
+ ASSERT_EQ(metric_data_reported.size(), 5ul);
+ for (int i = 0; i < 5; ++i) {
EXPECT_TRUE(metric_data_reported[i].has_timestamp_ms());
EXPECT_EQ(metric_data_reported[i].has_telemetry_data(),
metric_data[i].has_telemetry_data());
@@ -217,28 +275,91 @@ TEST_F(MetricDataCollectorTest, PeriodicCollector_InitiallyDisabled) {
MetricData metric_data;
metric_data.mutable_telemetry_data();
+ sampler_->SetMetricData(std::move(metric_data));
+
PeriodicCollector collector(
sampler_.get(), metric_report_queue_.get(), settings_.get(),
- kEnableSettingPath, kRateSettingPath, base::Milliseconds(interval / 2));
+ kEnableSettingPath, /*setting_enabled_default_value=*/false,
+ kRateSettingPath, base::Milliseconds(interval / 2));
- sampler_->SetMetricData(metric_data);
task_environment_.FastForwardBy(base::Milliseconds(interval));
// Setting is disabled, no data collected.
EXPECT_EQ(sampler_->GetNumCollectCalls(), 0);
settings_->SetBoolean(kEnableSettingPath, true);
+ // One initial collection at policy enablement.
+ EXPECT_EQ(sampler_->GetNumCollectCalls(), 1);
+ FlushTasks();
+
task_environment_.FastForwardBy(base::Milliseconds(interval));
+ // 1 collection at policy enablement + 1 collection after interval.
+ EXPECT_EQ(sampler_->GetNumCollectCalls(), 2);
+
+ FlushTasks();
+ auto metric_data_reported = metric_report_queue_->GetMetricDataReported();
+
+ ASSERT_EQ(metric_data_reported.size(), 2ul);
+ EXPECT_TRUE(metric_data_reported[0].has_timestamp_ms());
+ EXPECT_TRUE(metric_data_reported[0].has_telemetry_data());
+ EXPECT_TRUE(metric_data_reported[1].has_timestamp_ms());
+ EXPECT_TRUE(metric_data_reported[1].has_telemetry_data());
+}
+
+TEST_F(MetricDataCollectorTest, PeriodicCollector_DefaultEnabled) {
+ constexpr int interval = 10000;
+ settings_->SetInteger(kRateSettingPath, interval);
+
+ MetricData metric_data;
+ metric_data.mutable_telemetry_data();
+
+ sampler_->SetMetricData(std::move(metric_data));
+ PeriodicCollector collector(
+ sampler_.get(), metric_report_queue_.get(), settings_.get(),
+ "invalid/path", /*setting_enabled_default_value=*/true, kRateSettingPath,
+ base::Milliseconds(interval / 2));
+
+ // One initial collection at startup.
EXPECT_EQ(sampler_->GetNumCollectCalls(), 1);
+ FlushTasks();
+
+ metric_data.Clear();
+ metric_data.mutable_event_data();
+ sampler_->SetMetricData(std::move(metric_data));
+ // 10 secs elapsed, data should be collected.
+ task_environment_.FastForwardBy(base::Milliseconds(interval));
+ // 1 collection at startup + 1 collection after interval.
+ EXPECT_EQ(sampler_->GetNumCollectCalls(), 2);
- base::RunLoop run_loop;
- task_environment_.GetMainThreadTaskRunner()->PostTask(FROM_HERE,
- run_loop.QuitClosure());
- run_loop.Run();
+ FlushTasks();
auto metric_data_reported = metric_report_queue_->GetMetricDataReported();
- ASSERT_EQ(metric_data_reported.size(), 1ul);
+ ASSERT_EQ(metric_data_reported.size(), 2ul);
EXPECT_TRUE(metric_data_reported[0].has_timestamp_ms());
EXPECT_TRUE(metric_data_reported[0].has_telemetry_data());
+ EXPECT_TRUE(metric_data_reported[1].has_timestamp_ms());
+ EXPECT_FALSE(metric_data_reported[1].has_telemetry_data());
+ EXPECT_TRUE(metric_data_reported[1].has_event_data());
+}
+
+TEST_F(MetricDataCollectorTest, PeriodicCollector_DefaultDisabled) {
+ constexpr int interval = 10000;
+ settings_->SetInteger(kRateSettingPath, interval);
+
+ MetricData metric_data;
+ metric_data.mutable_telemetry_data();
+
+ PeriodicCollector collector(
+ sampler_.get(), metric_report_queue_.get(), settings_.get(),
+ "invalid/path", /*setting_enabled_default_value=*/false, kRateSettingPath,
+ base::Milliseconds(interval / 2));
+
+ sampler_->SetMetricData(std::move(metric_data));
+ task_environment_.FastForwardBy(base::Milliseconds(interval));
+ FlushTasks();
+
+ // Setting is disabled by default, no data collected.
+ EXPECT_EQ(sampler_->GetNumCollectCalls(), 0);
+ EXPECT_TRUE(metric_report_queue_->GetMetricDataReported().empty());
}
TEST_F(MetricDataCollectorTest, PeriodicEventCollector_NoAdditionalSamplers) {
@@ -246,36 +367,41 @@ TEST_F(MetricDataCollectorTest, PeriodicEventCollector_NoAdditionalSamplers) {
settings_->SetBoolean(kEnableSettingPath, true);
settings_->SetInteger(kRateSettingPath, interval);
- MetricData metric_data[2];
+ MetricData metric_data[3];
metric_data[0].mutable_info_data();
metric_data[1].mutable_telemetry_data();
+ metric_data[2].mutable_info_data();
auto event_detector = std::make_unique<test::FakeEventDetector>();
auto* event_detector_ptr = event_detector.get();
+ sampler_->SetMetricData(metric_data[0]);
PeriodicEventCollector collector(sampler_.get(), std::move(event_detector),
{}, metric_report_queue_.get(),
settings_.get(), kEnableSettingPath,
+ /*setting_enabled_default_value=*/false,
kRateSettingPath, base::Milliseconds(15000));
- sampler_->SetMetricData(metric_data[0]);
- task_environment_.FastForwardBy(base::Milliseconds(interval));
- // Data collected but should not be reported.
+ // One initial collection at startup, data collected but not reported.
EXPECT_EQ(sampler_->GetNumCollectCalls(), 1);
+ FlushTasks();
- sampler_->SetMetricData(metric_data[1]);
+ sampler_->SetMetricData(std::move(metric_data[1]));
event_detector_ptr->SetHasEvent(true);
task_environment_.FastForwardBy(base::Milliseconds(interval));
// Data collected and reported.
EXPECT_EQ(sampler_->GetNumCollectCalls(), 2);
+ FlushTasks();
- base::RunLoop run_loop;
- task_environment_.GetMainThreadTaskRunner()->PostTask(FROM_HERE,
- run_loop.QuitClosure());
- run_loop.Run();
+ sampler_->SetMetricData(std::move(metric_data[2]));
+ event_detector_ptr->SetHasEvent(false);
+ task_environment_.FastForwardBy(base::Milliseconds(interval));
+ // Data collected but not reported.
+ EXPECT_EQ(sampler_->GetNumCollectCalls(), 3);
+ FlushTasks();
auto previous_metric_list = event_detector_ptr->GetPreviousMetricList();
- ASSERT_EQ(previous_metric_list.size(), 2ul);
+ ASSERT_EQ(previous_metric_list.size(), 3ul);
EXPECT_FALSE(previous_metric_list[0].has_timestamp_ms());
EXPECT_FALSE(previous_metric_list[0].has_info_data());
@@ -287,6 +413,11 @@ TEST_F(MetricDataCollectorTest, PeriodicEventCollector_NoAdditionalSamplers) {
EXPECT_FALSE(previous_metric_list[1].has_telemetry_data());
EXPECT_FALSE(previous_metric_list[1].has_event_data());
+ EXPECT_TRUE(previous_metric_list[2].has_timestamp_ms());
+ EXPECT_FALSE(previous_metric_list[2].has_info_data());
+ EXPECT_TRUE(previous_metric_list[2].has_telemetry_data());
+ EXPECT_TRUE(previous_metric_list[2].has_event_data());
+
auto metric_data_reported = metric_report_queue_->GetMetricDataReported();
ASSERT_EQ(metric_data_reported.size(), 1ul);
@@ -297,9 +428,7 @@ TEST_F(MetricDataCollectorTest, PeriodicEventCollector_NoAdditionalSamplers) {
}
TEST_F(MetricDataCollectorTest, PeriodicEventCollector_WithAdditionalSamplers) {
- constexpr int interval = 10000;
settings_->SetBoolean(kEnableSettingPath, true);
- settings_->SetInteger(kRateSettingPath, interval);
MetricData metric_data;
metric_data.mutable_telemetry_data();
@@ -329,24 +458,20 @@ TEST_F(MetricDataCollectorTest, PeriodicEventCollector_WithAdditionalSamplers) {
}
auto event_detector = std::make_unique<test::FakeEventDetector>();
- auto* event_detector_ptr = event_detector.get();
+ sampler_->SetMetricData(std::move(metric_data));
+ event_detector->SetHasEvent(true);
PeriodicEventCollector collector(sampler_.get(), std::move(event_detector),
std::move(additional_sampler_ptrs),
metric_report_queue_.get(), settings_.get(),
- kEnableSettingPath, kRateSettingPath,
- base::Milliseconds(15000));
+ kEnableSettingPath,
+ /*setting_enabled_default_value=*/false,
+ kRateSettingPath, base::Milliseconds(15000));
- sampler_->SetMetricData(metric_data);
- event_detector_ptr->SetHasEvent(true);
- task_environment_.FastForwardBy(base::Milliseconds(interval));
// Data collected and reported.
EXPECT_EQ(sampler_->GetNumCollectCalls(), 1);
- base::RunLoop run_loop;
- task_environment_.GetMainThreadTaskRunner()->PostTask(FROM_HERE,
- run_loop.QuitClosure());
- run_loop.Run();
+ task_environment_.RunUntilIdle();
auto metric_data_reported = metric_report_queue_->GetMetricDataReported();
ASSERT_EQ(metric_data_reported.size(), 1ul);
@@ -380,4 +505,5 @@ TEST_F(MetricDataCollectorTest, PeriodicEventCollector_WithAdditionalSamplers) {
.https_latency_data()
.latency_ms());
}
+} // namespace
} // namespace reporting
diff --git a/chromium/components/reporting/metrics/metric_event_observer_manager.cc b/chromium/components/reporting/metrics/metric_event_observer_manager.cc
index 3e03c7babb4..301b9675c27 100644
--- a/chromium/components/reporting/metrics/metric_event_observer_manager.cc
+++ b/chromium/components/reporting/metrics/metric_event_observer_manager.cc
@@ -23,6 +23,7 @@ MetricEventObserverManager::MetricEventObserverManager(
MetricReportQueue* metric_report_queue,
ReportingSettings* reporting_settings,
const std::string& enable_setting_path,
+ bool setting_enabled_default_value,
std::vector<Sampler*> additional_samplers)
: event_observer_(std::move(event_observer)),
metric_report_queue_(metric_report_queue),
@@ -39,7 +40,7 @@ MetricEventObserverManager::MetricEventObserverManager(
base::SequencedTaskRunnerHandle::Get(), std::move(on_event_observed_cb)));
reporting_controller_ = std::make_unique<MetricReportingController>(
- reporting_settings, enable_setting_path,
+ reporting_settings, enable_setting_path, setting_enabled_default_value,
base::BindRepeating(&MetricEventObserverManager::SetReportingEnabled,
base::Unretained(this),
/*is_enabled=*/true),
diff --git a/chromium/components/reporting/metrics/metric_event_observer_manager.h b/chromium/components/reporting/metrics/metric_event_observer_manager.h
index ecd40414650..e11b9a11254 100644
--- a/chromium/components/reporting/metrics/metric_event_observer_manager.h
+++ b/chromium/components/reporting/metrics/metric_event_observer_manager.h
@@ -32,13 +32,14 @@ class MetricEventObserverManager {
MetricReportQueue* metric_report_queue,
ReportingSettings* reporting_settings,
const std::string& enable_setting_path,
+ bool setting_enabled_default_value,
std::vector<Sampler*> additional_samplers = {});
MetricEventObserverManager(const MetricEventObserverManager& other) = delete;
MetricEventObserverManager& operator=(
const MetricEventObserverManager& other) = delete;
- ~MetricEventObserverManager();
+ virtual ~MetricEventObserverManager();
private:
void SetReportingEnabled(bool is_enabled);
diff --git a/chromium/components/reporting/metrics/metric_event_observer_manager_unittest.cc b/chromium/components/reporting/metrics/metric_event_observer_manager_unittest.cc
index e2ba97b9527..c1e6eb55316 100644
--- a/chromium/components/reporting/metrics/metric_event_observer_manager_unittest.cc
+++ b/chromium/components/reporting/metrics/metric_event_observer_manager_unittest.cc
@@ -20,11 +20,12 @@
#include "testing/gtest/include/gtest/gtest.h"
namespace reporting {
+namespace {
class MetricEventObserverManagerTest : public ::testing::Test {
public:
void SetUp() override {
- settings_ = std::make_unique<FakeReportingSettings>();
+ settings_ = std::make_unique<test::FakeReportingSettings>();
event_observer_ = std::make_unique<test::FakeMetricEventObserver>();
metric_report_queue_ = std::make_unique<test::FakeMetricReportQueue>();
}
@@ -34,7 +35,7 @@ class MetricEventObserverManagerTest : public ::testing::Test {
const std::string kEnableSettingPath = "enable_path";
- std::unique_ptr<FakeReportingSettings> settings_;
+ std::unique_ptr<test::FakeReportingSettings> settings_;
std::unique_ptr<test::FakeMetricEventObserver> event_observer_;
std::unique_ptr<test::FakeMetricReportQueue> metric_report_queue_;
};
@@ -43,9 +44,9 @@ TEST_F(MetricEventObserverManagerTest, InitiallyEnabled) {
settings_->SetBoolean(kEnableSettingPath, true);
auto* event_observer_ptr = event_observer_.get();
- MetricEventObserverManager event_manager(std::move(event_observer_),
- metric_report_queue_.get(),
- settings_.get(), kEnableSettingPath);
+ MetricEventObserverManager event_manager(
+ std::move(event_observer_), metric_report_queue_.get(), settings_.get(),
+ kEnableSettingPath, /*setting_enabled_default_value=*/false);
MetricData metric_data;
metric_data.mutable_event_data();
@@ -76,9 +77,9 @@ TEST_F(MetricEventObserverManagerTest, InitiallyDisabled) {
settings_->SetBoolean(kEnableSettingPath, false);
auto* event_observer_ptr = event_observer_.get();
- MetricEventObserverManager event_manager(std::move(event_observer_),
- metric_report_queue_.get(),
- settings_.get(), kEnableSettingPath);
+ MetricEventObserverManager event_manager(
+ std::move(event_observer_), metric_report_queue_.get(), settings_.get(),
+ kEnableSettingPath, /*setting_enabled_default_value=*/false);
MetricData metric_data;
metric_data.mutable_event_data();
@@ -98,6 +99,41 @@ TEST_F(MetricEventObserverManagerTest, InitiallyDisabled) {
EXPECT_TRUE(metric_data_reported[0].has_event_data());
}
+TEST_F(MetricEventObserverManagerTest, DefaultEnabled) {
+ auto* event_observer_ptr = event_observer_.get();
+
+ MetricEventObserverManager event_manager(
+ std::move(event_observer_), metric_report_queue_.get(), settings_.get(),
+ "invalid/path", /*setting_enabled_default_value=*/true);
+
+ MetricData metric_data;
+ metric_data.mutable_event_data();
+
+ ASSERT_TRUE(event_observer_ptr->GetReportingEnabled());
+ event_observer_ptr->RunCallback(metric_data);
+
+ auto metric_data_reported = metric_report_queue_->GetMetricDataReported();
+ ASSERT_EQ(metric_data_reported.size(), 1ul);
+ EXPECT_TRUE(metric_data_reported[0].has_timestamp_ms());
+ EXPECT_TRUE(metric_data_reported[0].has_event_data());
+}
+
+TEST_F(MetricEventObserverManagerTest, DefaultDisabled) {
+ auto* event_observer_ptr = event_observer_.get();
+
+ MetricEventObserverManager event_manager(
+ std::move(event_observer_), metric_report_queue_.get(), settings_.get(),
+ "invalid/path", /*setting_enabled_default_value=*/false);
+
+ MetricData metric_data;
+ metric_data.mutable_event_data();
+
+ event_observer_ptr->RunCallback(metric_data);
+
+ ASSERT_FALSE(event_observer_ptr->GetReportingEnabled());
+ EXPECT_TRUE(metric_report_queue_->GetMetricDataReported().empty());
+}
+
TEST_F(MetricEventObserverManagerTest, AdditionalSamplers) {
settings_->SetBoolean(kEnableSettingPath, true);
auto* event_observer_ptr = event_observer_.get();
@@ -109,7 +145,8 @@ TEST_F(MetricEventObserverManagerTest, AdditionalSamplers) {
MetricEventObserverManager event_manager(
std::move(event_observer_), metric_report_queue_.get(), settings_.get(),
- kEnableSettingPath, {&additional_sampler});
+ kEnableSettingPath, /*setting_enabled_default_value=*/false,
+ {&additional_sampler});
MetricData metric_data;
metric_data.mutable_event_data();
@@ -130,4 +167,6 @@ TEST_F(MetricEventObserverManagerTest, AdditionalSamplers) {
EXPECT_TRUE(metric_data_reported[i].has_telemetry_data());
}
}
+
+} // namespace
} // namespace reporting
diff --git a/chromium/components/reporting/metrics/metric_rate_controller_unittest.cc b/chromium/components/reporting/metrics/metric_rate_controller_unittest.cc
index 0d0bc9ac4cf..edbe9119487 100644
--- a/chromium/components/reporting/metrics/metric_rate_controller_unittest.cc
+++ b/chromium/components/reporting/metrics/metric_rate_controller_unittest.cc
@@ -14,11 +14,12 @@
#include "testing/gtest/include/gtest/gtest.h"
namespace reporting {
+namespace {
class MetricRateControllerTest : public ::testing::Test {
public:
void SetUp() override {
- settings_ = std::make_unique<FakeReportingSettings>();
+ settings_ = std::make_unique<test::FakeReportingSettings>();
run_count_ = 0;
run_cb_ = base::BindLambdaForTesting([this]() { ++run_count_; });
}
@@ -26,7 +27,7 @@ class MetricRateControllerTest : public ::testing::Test {
protected:
const std::string rate_setting_path_ = "rate_path";
- std::unique_ptr<FakeReportingSettings> settings_;
+ std::unique_ptr<test::FakeReportingSettings> settings_;
int run_count_ = 0;
base::RepeatingClosure run_cb_;
@@ -144,4 +145,5 @@ TEST_F(MetricRateControllerTest, RateSettingZero) {
task_environment_.FastForwardBy(base::Milliseconds(5000));
EXPECT_EQ(run_count_, 1);
}
+} // namespace
} // namespace reporting
diff --git a/chromium/components/reporting/metrics/metric_report_queue.cc b/chromium/components/reporting/metrics/metric_report_queue.cc
index a0dbfa745e8..d571648f5fb 100644
--- a/chromium/components/reporting/metrics/metric_report_queue.cc
+++ b/chromium/components/reporting/metrics/metric_report_queue.cc
@@ -39,6 +39,15 @@ void MetricReportQueue::Enqueue(const MetricData& metric_data,
report_queue_->Enqueue(&metric_data, priority_, std::move(callback));
}
+void MetricReportQueue::Upload() {
+ Flush();
+ // Restart timer if the metric report queue flush is rate controlled.
+ if (rate_controller_) {
+ rate_controller_->Stop();
+ rate_controller_->Start();
+ }
+}
+
void MetricReportQueue::Flush() {
report_queue_->Flush(
priority_, base::BindOnce([](Status status) {
diff --git a/chromium/components/reporting/metrics/metric_report_queue.h b/chromium/components/reporting/metrics/metric_report_queue.h
index b279fc8fde8..ec4583319a4 100644
--- a/chromium/components/reporting/metrics/metric_report_queue.h
+++ b/chromium/components/reporting/metrics/metric_report_queue.h
@@ -46,10 +46,14 @@ class MetricReportQueue {
virtual void Enqueue(const MetricData& metric_data,
ReportQueue::EnqueueCallback callback);
+ // Initiate manual upload of records with `priority_` and restart timer if
+ // exists.
+ void Upload();
+
+ private:
// Initiate upload of records with `priority_`.
virtual void Flush();
- private:
const std::unique_ptr<ReportQueue, base::OnTaskRunnerDeleter> report_queue_;
const Priority priority_;
diff --git a/chromium/components/reporting/metrics/metric_report_queue_unittest.cc b/chromium/components/reporting/metrics/metric_report_queue_unittest.cc
index 94ed245995f..7a9a94d3140 100644
--- a/chromium/components/reporting/metrics/metric_report_queue_unittest.cc
+++ b/chromium/components/reporting/metrics/metric_report_queue_unittest.cc
@@ -21,21 +21,24 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using ::testing::_;
+
namespace reporting {
+namespace {
-using ::testing::_;
+constexpr char kRateSettingPath[] = "rate_path";
+constexpr int kRateMs = 10000;
+constexpr base::TimeDelta kDefaultRate = base::Milliseconds(100);
class MetricReportQueueTest : public ::testing::Test {
public:
void SetUp() override {
priority_ = Priority::SLOW_BATCH;
- settings_ = std::make_unique<FakeReportingSettings>();
+ settings_ = std::make_unique<test::FakeReportingSettings>();
}
protected:
- const std::string kRateSettingPath = "rate_path";
-
- std::unique_ptr<FakeReportingSettings> settings_;
+ std::unique_ptr<test::FakeReportingSettings> settings_;
Priority priority_;
@@ -43,7 +46,7 @@ class MetricReportQueueTest : public ::testing::Test {
base::test::TaskEnvironment::TimeSource::MOCK_TIME};
};
-TEST_F(MetricReportQueueTest, ManualFlush) {
+TEST_F(MetricReportQueueTest, ManualUpload) {
auto mock_queue =
std::unique_ptr<::reporting::MockReportQueue, base::OnTaskRunnerDeleter>(
new testing::StrictMock<::reporting::MockReportQueue>(),
@@ -74,12 +77,63 @@ TEST_F(MetricReportQueueTest, ManualFlush) {
EXPECT_TRUE(callback_called);
EXPECT_CALL(*mock_queue_ptr, Flush(priority_, _)).Times(1);
- metric_report_queue.Flush();
+ metric_report_queue.Upload();
+}
+
+TEST_F(MetricReportQueueTest, ManualUploadWithTimer) {
+ settings_->SetInteger(kRateSettingPath, kRateMs);
+
+ int upload_count = 0;
+ auto mock_queue =
+ std::unique_ptr<::reporting::MockReportQueue, base::OnTaskRunnerDeleter>(
+ new testing::NiceMock<::reporting::MockReportQueue>(),
+ base::OnTaskRunnerDeleter(
+ base::ThreadPool::CreateSequencedTaskRunner({})));
+ auto* mock_queue_ptr = mock_queue.get();
+ MetricData record;
+ record.set_timestamp_ms(123456);
+
+ MetricReportQueue metric_report_queue(std::move(mock_queue), priority_,
+ settings_.get(), kRateSettingPath,
+ kDefaultRate);
+
+ EXPECT_CALL(*mock_queue_ptr, AddRecord(_, _, _))
+ .WillOnce([&record, this](base::StringPiece record_string,
+ Priority actual_priority,
+ ReportQueue::EnqueueCallback cb) {
+ std::move(cb).Run(Status());
+ MetricData actual_record;
+
+ EXPECT_TRUE(actual_record.ParseFromArray(record_string.data(),
+ record_string.size()));
+ EXPECT_EQ(actual_record.timestamp_ms(), record.timestamp_ms());
+ EXPECT_EQ(actual_priority, priority_);
+ });
+ bool callback_called = false;
+ metric_report_queue.Enqueue(
+ record, base::BindLambdaForTesting(
+ [&callback_called](Status) { callback_called = true; }));
+ EXPECT_TRUE(callback_called);
+
+ ON_CALL(*mock_queue_ptr, Flush(priority_, _)).WillByDefault([&]() {
+ ++upload_count;
+ });
+ task_environment_.FastForwardBy(base::Milliseconds(kRateMs / 2));
+ metric_report_queue.Upload();
+ ASSERT_EQ(upload_count, 1);
+
+ // Manual upload should have reset the timer so no upload should be expected
+ // after the time is elapsed.
+ task_environment_.FastForwardBy(base::Milliseconds(kRateMs / 2));
+ ASSERT_EQ(upload_count, 1);
+
+ // Full time elapsed after manual upload, new upload should be initiated.
+ task_environment_.FastForwardBy(base::Milliseconds(kRateMs / 2));
+ ASSERT_EQ(upload_count, 2);
}
TEST_F(MetricReportQueueTest, RateControlledFlush_TimeNotElapsed) {
- constexpr int rate_ms = 10000;
- settings_->SetInteger(kRateSettingPath, rate_ms);
+ settings_->SetInteger(kRateSettingPath, kRateMs);
auto mock_queue =
std::unique_ptr<::reporting::MockReportQueue, base::OnTaskRunnerDeleter>(
new testing::StrictMock<::reporting::MockReportQueue>(),
@@ -91,7 +145,7 @@ TEST_F(MetricReportQueueTest, RateControlledFlush_TimeNotElapsed) {
MetricReportQueue metric_report_queue(std::move(mock_queue), priority_,
settings_.get(), kRateSettingPath,
- /*default_rate=*/base::Milliseconds(1));
+ kDefaultRate);
EXPECT_CALL(*mock_queue_ptr, AddRecord(_, _, _))
.WillOnce([&record, this](base::StringPiece record_string,
@@ -112,12 +166,11 @@ TEST_F(MetricReportQueueTest, RateControlledFlush_TimeNotElapsed) {
EXPECT_TRUE(callback_called);
EXPECT_CALL(*mock_queue_ptr, Flush).Times(0);
- task_environment_.FastForwardBy(base::Milliseconds(rate_ms - 1));
+ task_environment_.FastForwardBy(base::Milliseconds(kRateMs - 1));
}
TEST_F(MetricReportQueueTest, RateControlledFlush_TimeElapsed) {
- constexpr int rate_ms = 10000;
- settings_->SetInteger(kRateSettingPath, rate_ms);
+ settings_->SetInteger(kRateSettingPath, kRateMs);
auto mock_queue =
std::unique_ptr<::reporting::MockReportQueue, base::OnTaskRunnerDeleter>(
new testing::StrictMock<::reporting::MockReportQueue>(),
@@ -129,7 +182,7 @@ TEST_F(MetricReportQueueTest, RateControlledFlush_TimeElapsed) {
MetricReportQueue metric_report_queue(std::move(mock_queue), priority_,
settings_.get(), kRateSettingPath,
- /*default_rate=*/base::Milliseconds(1));
+ kDefaultRate);
EXPECT_CALL(*mock_queue_ptr, AddRecord(_, _, _))
.WillOnce([&record, this](base::StringPiece record_string,
@@ -150,6 +203,7 @@ TEST_F(MetricReportQueueTest, RateControlledFlush_TimeElapsed) {
EXPECT_TRUE(callback_called);
EXPECT_CALL(*mock_queue_ptr, Flush(priority_, _)).Times(1);
- task_environment_.FastForwardBy(base::Milliseconds(rate_ms));
+ task_environment_.FastForwardBy(base::Milliseconds(kRateMs));
}
+} // namespace
} // namespace reporting
diff --git a/chromium/components/reporting/metrics/metric_reporting_controller.cc b/chromium/components/reporting/metrics/metric_reporting_controller.cc
index f77283bd5f5..3c870005a01 100644
--- a/chromium/components/reporting/metrics/metric_reporting_controller.cc
+++ b/chromium/components/reporting/metrics/metric_reporting_controller.cc
@@ -14,10 +14,12 @@ namespace reporting {
MetricReportingController::MetricReportingController(
ReportingSettings* reporting_settings,
const std::string& setting_path,
+ bool setting_enabled_default_value,
base::RepeatingClosure on_setting_enabled,
base::RepeatingClosure on_setting_disabled)
: reporting_settings_(reporting_settings),
setting_path_(setting_path),
+ setting_enabled_default_value_(setting_enabled_default_value),
on_setting_enabled_(std::move(on_setting_enabled)),
on_setting_disabled_(std::move(on_setting_disabled)) {
UpdateSetting();
@@ -44,7 +46,7 @@ void MetricReportingController::UpdateSetting() {
return;
}
- bool new_setting_enabled = false;
+ bool new_setting_enabled = setting_enabled_default_value_;
reporting_settings_->GetBoolean(setting_path_, &new_setting_enabled);
if (setting_enabled_ != new_setting_enabled) {
diff --git a/chromium/components/reporting/metrics/metric_reporting_controller.h b/chromium/components/reporting/metrics/metric_reporting_controller.h
index adebe4b5dc9..2438659a322 100644
--- a/chromium/components/reporting/metrics/metric_reporting_controller.h
+++ b/chromium/components/reporting/metrics/metric_reporting_controller.h
@@ -25,6 +25,7 @@ class MetricReportingController {
MetricReportingController(
ReportingSettings* reporting_settings,
const std::string& setting_path,
+ bool setting_enabled_default_value,
base::RepeatingClosure on_setting_enabled,
base::RepeatingClosure on_setting_disabled = base::DoNothing());
@@ -39,6 +40,7 @@ class MetricReportingController {
const raw_ptr<ReportingSettings> reporting_settings_;
const std::string setting_path_;
+ const bool setting_enabled_default_value_;
const base::RepeatingClosure on_setting_enabled_;
const base::RepeatingClosure on_setting_disabled_;
diff --git a/chromium/components/reporting/metrics/metric_reporting_controller_unittest.cc b/chromium/components/reporting/metrics/metric_reporting_controller_unittest.cc
index 7964a1a6751..bcad021d460 100644
--- a/chromium/components/reporting/metrics/metric_reporting_controller_unittest.cc
+++ b/chromium/components/reporting/metrics/metric_reporting_controller_unittest.cc
@@ -14,11 +14,14 @@
#include "testing/gtest/include/gtest/gtest.h"
namespace reporting {
+namespace {
+
+constexpr char kSettingPath[] = "path";
class MetricReportingControllerTest : public ::testing::Test {
public:
void SetUp() override {
- settings_ = std::make_unique<FakeReportingSettings>();
+ settings_ = std::make_unique<test::FakeReportingSettings>();
enable_count_ = 0;
disable_count_ = 0;
enable_cb_ = base::BindLambdaForTesting([this]() { ++enable_count_; });
@@ -31,26 +34,36 @@ class MetricReportingControllerTest : public ::testing::Test {
base::RepeatingClosure enable_cb_;
base::RepeatingClosure disable_cb_;
- std::unique_ptr<FakeReportingSettings> settings_;
+ std::unique_ptr<test::FakeReportingSettings> settings_;
base::test::SingleThreadTaskEnvironment task_environment_;
};
-TEST_F(MetricReportingControllerTest, InvalidPath) {
- MetricReportingController controller(settings_.get(), "invalid_path",
+TEST_F(MetricReportingControllerTest, InvalidPath_DefaultDisabled) {
+ MetricReportingController controller(settings_.get(), "invalid/path",
+ /*setting_enabled_default_value=*/false,
enable_cb_, disable_cb_);
EXPECT_EQ(enable_count_, 0);
EXPECT_EQ(disable_count_, 0);
}
+TEST_F(MetricReportingControllerTest, InvalidPath_DefaultEnabled) {
+ MetricReportingController controller(settings_.get(), "invalid/path",
+ /*setting_enabled_default_value=*/true,
+ enable_cb_, disable_cb_);
+
+ EXPECT_EQ(enable_count_, 1);
+ EXPECT_EQ(disable_count_, 0);
+}
+
TEST_F(MetricReportingControllerTest, TrustedCheck) {
- const std::string path = "path";
- settings_->SetBoolean(path, true);
+ settings_->SetBoolean(kSettingPath, true);
settings_->SetIsTrusted(false);
- MetricReportingController controller(settings_.get(), path, enable_cb_,
- disable_cb_);
+ MetricReportingController controller(settings_.get(), kSettingPath,
+ /*setting_enabled_default_value=*/false,
+ enable_cb_, disable_cb_);
EXPECT_EQ(enable_count_, 0);
EXPECT_EQ(disable_count_, 0);
@@ -61,55 +74,57 @@ TEST_F(MetricReportingControllerTest, TrustedCheck) {
EXPECT_EQ(disable_count_, 0);
}
-TEST_F(MetricReportingControllerTest, DefaultEnable) {
- const std::string path = "path";
- settings_->SetBoolean(path, true);
+TEST_F(MetricReportingControllerTest, InitiallyEnabled) {
+ settings_->SetBoolean(kSettingPath, true);
- MetricReportingController controller(settings_.get(), path, enable_cb_,
- disable_cb_);
+ MetricReportingController controller(settings_.get(), kSettingPath,
+ /*setting_enabled_default_value=*/false,
+ enable_cb_, disable_cb_);
// Only enable_cb_ is called.
EXPECT_EQ(enable_count_, 1);
EXPECT_EQ(disable_count_, 0);
// Change to disable.
- settings_->SetBoolean(path, false);
+ settings_->SetBoolean(kSettingPath, false);
// Only disable_cb_ is called.
EXPECT_EQ(enable_count_, 1);
EXPECT_EQ(disable_count_, 1);
// Change to enable.
- settings_->SetBoolean(path, true);
+ settings_->SetBoolean(kSettingPath, true);
// Only enable_cb_ is called.
EXPECT_EQ(enable_count_, 2);
EXPECT_EQ(disable_count_, 1);
}
-TEST_F(MetricReportingControllerTest, DefaultDisable) {
- const std::string path = "path";
- settings_->SetBoolean(path, false);
+TEST_F(MetricReportingControllerTest, InitiallyDisabled) {
+ settings_->SetBoolean(kSettingPath, false);
- MetricReportingController controller(settings_.get(), path, enable_cb_,
- disable_cb_);
+ MetricReportingController controller(settings_.get(), kSettingPath,
+ /*setting_enabled_default_value=*/false,
+ enable_cb_, disable_cb_);
// No callbacks are called.
EXPECT_EQ(enable_count_, 0);
EXPECT_EQ(disable_count_, 0);
// Change to enable.
- settings_->SetBoolean(path, true);
+ settings_->SetBoolean(kSettingPath, true);
// Only enable_cb_ is called.
EXPECT_EQ(enable_count_, 1);
EXPECT_EQ(disable_count_, 0);
// Change to disable.
- settings_->SetBoolean(path, false);
+ settings_->SetBoolean(kSettingPath, false);
// Only disable_cb_ is called.
EXPECT_EQ(enable_count_, 1);
EXPECT_EQ(disable_count_, 1);
}
+
+} // namespace
} // namespace reporting
diff --git a/chromium/components/reporting/proto/synced/metric_data.proto b/chromium/components/reporting/proto/synced/metric_data.proto
index 8daf7124233..0f9df806b6e 100644
--- a/chromium/components/reporting/proto/synced/metric_data.proto
+++ b/chromium/components/reporting/proto/synced/metric_data.proto
@@ -87,6 +87,21 @@ message NetworkTelemetry {
optional string gateway = 6;
// Network connection type.
optional NetworkType type = 7;
+
+ reserved 8;
+
+ // Transmission bit rate measured in Mbps.
+ optional int64 tx_bit_rate_mbps = 9;
+ // Receiving bit rate measured in Mbps.
+ optional int64 rx_bit_rate_mbps = 10;
+ // Transmission power measured in dBm.
+ optional int32 tx_power_dbm = 11;
+ // Is wifi encryption key on or not.
+ optional bool encryption_on = 12;
+ // Wifi link quality.
+ optional int64 link_quality = 13;
+ // Wifi power management enabled
+ optional bool power_management_enabled = 14;
}
// Configured networks telemetry data.
@@ -116,7 +131,7 @@ enum ThunderboltSecurityLevel {
THUNDERBOLT_SECURITY_USB_ONLY_LEVEL = 5;
// PCIE tunneling is disabled.
THUNDERBOLT_SECURITY_NO_PCIE_LEVEL = 6;
-};
+}
message ThunderboltInfo {
optional ThunderboltSecurityLevel security_level = 1;
@@ -156,9 +171,9 @@ message TotalMemoryEncryptionInfo {
// The state of memory encryption on the device.
optional MemoryEncryptionState encryption_state = 1;
// The maximum number of keys that can be used for encryption.
- optional uint32 max_keys = 2;
+ optional int64 max_keys = 2;
// The length of the encryption keys.
- optional uint32 key_length = 3;
+ optional int64 key_length = 3;
// The encryption algorithm being used on the device.
optional MemoryEncryptionAlgorithm encryption_algorithm = 4;
}
@@ -168,6 +183,50 @@ message MemoryInfo {
optional TotalMemoryEncryptionInfo tme_info = 1;
}
+enum NetworkDeviceType {
+ NETWORK_DEVICE_TYPE_UNSPECIFIED = 0;
+ CELLULAR_DEVICE = 1;
+ ETHERNET_DEVICE = 2;
+ WIFI_DEVICE = 5;
+}
+
+// Info details about network interface.
+message NetworkInterface {
+ // Network device type.
+ optional NetworkDeviceType type = 1;
+
+ // MAC address (if applicable) of the corresponding network device. This is
+ // formatted as an ASCII string with 12 hex digits. Example: A0B1C2D3E4F5.
+ optional string mac_address = 2;
+
+ // MEID (if applicable) of the corresponding network device. Formatted as
+ // ASCII string composed of 14 hex digits. Example: A10000009296F2.
+ optional string meid = 3;
+
+ // IMEI (if applicable) of the corresponding network device. 15-16 decimal
+ // digits encoded as ASCII string. Example: 355402040158759.
+ optional string imei = 4;
+
+ // The device path associated with this network interface.
+ optional string device_path = 5;
+
+ // The integrated circuit card ID associated with the device's sim card.
+ optional string iccid = 6;
+
+ // The mobile directory number associated with the device's sim card.
+ optional string mdn = 7;
+
+ // List of EID (EUICC Identifier) of all cellular EUICCs
+ // (Embedded Universal Integrated Circuit Cards) on the device.
+ // 32 decimal digits encoded as ASCII string.
+ repeated string eids = 8;
+}
+
+// Networks info data.
+message NetworksInfo {
+ repeated NetworkInterface network_interfaces = 1;
+}
+
// Information about keylocker. This is supported on Intel CPUs.
message KeylockerInfo {
// If keylocker is supported on the devices CPUs.
@@ -190,6 +249,8 @@ message InfoData {
optional BusDeviceInfo bus_device_info = 2;
// Memory info for the device.
optional MemoryInfo memory_info = 3;
+ // Network interfaces info.
+ optional NetworksInfo networks_info = 4;
}
// Audio telemetry data recorded intermittently
@@ -208,6 +269,20 @@ message AudioTelemetry {
optional string input_device_name = 6;
}
+// Boot Performance telemetry data
+message BootPerformanceTelemetry {
+ // Total time when to boot up.
+ optional int64 boot_up_seconds = 1;
+ // The Timestamp when power came on.
+ optional int64 boot_up_timestamp_seconds = 2;
+ // Total time since shutdown start to power off.
+ optional int64 shutdown_seconds = 3;
+ // Timestamp when shutdown.
+ optional int64 shutdown_timestamp_seconds = 4;
+ // Shutdown reason.
+ optional string shutdown_reason = 5;
+}
+
// Data that can change over time, collected and reported every specific period
// of time or when an event occur.
message TelemetryData {
@@ -217,6 +292,10 @@ message TelemetryData {
optional NetworksTelemetry networks_telemetry = 1;
// Audio telemetry data.
optional AudioTelemetry audio_telemetry = 2;
+ // Peripherals telemetry data
+ optional PeripheralsTelemetry peripherals_telemetry = 3;
+ // Boot Performance telemetry data.
+ optional BootPerformanceTelemetry boot_performance_telemetry = 4;
}
enum MetricEventType {
@@ -225,6 +304,32 @@ enum MetricEventType {
NETWORK_CONNECTION_STATE_CHANGE = 2;
NETWORK_SIGNAL_STRENGTH_CHANGE = 3;
AUDIO_SEVERE_UNDERRUN = 4;
+ USB_ADDED = 5;
+ USB_REMOVED = 6;
+}
+
+message PeripheralsTelemetry {
+ repeated UsbTelemetry usb_telemetry = 1;
+}
+
+message UsbTelemetry {
+ // Vendor name
+ optional string vendor = 1;
+ // Device name, model name, or product name
+ optional string name = 2;
+ // Vendor ID
+ optional int32 vid = 3;
+ // Product ID
+ optional int32 pid = 4;
+ // Categories the device belongs to
+ // https://www.usb.org/defined-class-codes
+ repeated string categories = 5;
+ // Class ID
+ // https://www.usb.org/defined-class-codes
+ optional int32 class_id = 6;
+ // Subclass ID
+ // https://www.usb.org/defined-class-codes
+ optional int32 subclass_id = 7;
}
// Indicates one of the following conditions occurred on the device, data
diff --git a/chromium/components/reporting/proto/synced/record_constants.proto b/chromium/components/reporting/proto/synced/record_constants.proto
index 6feab168ee2..d1ac2a81452 100644
--- a/chromium/components/reporting/proto/synced/record_constants.proto
+++ b/chromium/components/reporting/proto/synced/record_constants.proto
@@ -71,6 +71,10 @@ enum Destination {
// |CRD_EVENTS| are sent for Chrome remote desktop connect and disconnect.
CRD_EVENTS = 18;
+
+ // |PERIPHERAL_EVENTS| is for both event and telemetry data from peripherals
+ // connected to ChromeOS devices.
+ PERIPHERAL_EVENTS = 19;
}
// |Priority| is used to determine when items from the queue should be rate
diff --git a/chromium/components/reporting/storage/BUILD.gn b/chromium/components/reporting/storage/BUILD.gn
index 0f201eda340..18c0ed1746b 100644
--- a/chromium/components/reporting/storage/BUILD.gn
+++ b/chromium/components/reporting/storage/BUILD.gn
@@ -44,6 +44,7 @@ static_library("storage_queue") {
"//components/reporting/proto:record_constants",
"//components/reporting/proto:record_proto",
"//components/reporting/resources:resource_interface",
+ "//components/reporting/util:file",
"//components/reporting/util:status",
"//components/reporting/util:status_macros",
"//components/reporting/util:task_runner_context",
@@ -71,6 +72,7 @@ static_library("storage") {
"//components/reporting/encryption:verification",
"//components/reporting/proto:record_constants",
"//components/reporting/proto:record_proto",
+ "//components/reporting/util:file",
"//components/reporting/util:status",
"//components/reporting/util:status_macros",
"//components/reporting/util:task_runner_context",
@@ -187,6 +189,7 @@ source_set("unit_tests") {
"//components/reporting/encryption:testing_primitives",
"//components/reporting/proto:record_proto",
"//components/reporting/resources:resource_interface",
+ "//components/reporting/util:file",
"//components/reporting/util:status",
"//components/reporting/util:status_macros",
"//components/reporting/util:test_callbacks_support",
diff --git a/chromium/components/reporting/storage/storage.cc b/chromium/components/reporting/storage/storage.cc
index a09426a463c..2f27e917f20 100644
--- a/chromium/components/reporting/storage/storage.cc
+++ b/chromium/components/reporting/storage/storage.cc
@@ -11,6 +11,7 @@
#include "base/bind.h"
#include "base/callback.h"
#include "base/callback_list.h"
+#include "base/containers/adapters.h"
#include "base/containers/flat_set.h"
#include "base/files/file.h"
#include "base/files/file_enumerator.h"
@@ -32,6 +33,7 @@
#include "components/reporting/storage/storage_configuration.h"
#include "components/reporting/storage/storage_queue.h"
#include "components/reporting/storage/storage_uploader_interface.h"
+#include "components/reporting/util/file.h"
#include "components/reporting/util/status.h"
#include "components/reporting/util/status_macros.h"
#include "components/reporting/util/statusor.h"
@@ -344,7 +346,7 @@ class Storage::KeyInStorage {
if (full_name == signed_encryption_key_result.value().first) {
continue; // This file is used.
}
- base::DeleteFile(full_name); // Ignore errors, if any.
+ DeleteFileWarnIfFailed(full_name); // Ignore errors, if any.
}
// Return the key.
@@ -412,40 +414,32 @@ class Storage::KeyInStorage {
// Enumerates key files and deletes those with index lower than
// |new_file_index|. Called during key upload.
void RemoveKeyFilesWithLowerIndexes(uint64_t new_file_index) {
- base::flat_set<base::FilePath> key_files_to_remove;
base::FileEnumerator dir_enum(
directory_,
/*recursive=*/false, base::FileEnumerator::FILES,
base::StrCat({kEncryptionKeyFilePrefix, FILE_PATH_LITERAL("*")}));
- base::FilePath full_name;
- while (full_name = dir_enum.Next(), !full_name.empty()) {
- const auto result = key_files_to_remove.emplace(full_name);
- if (!result.second) {
- // Duplicate file name. Should not happen.
- continue;
- }
- const auto extension = full_name.Extension();
- if (extension.empty()) {
- // Should not happen, will remove this file.
- continue;
- }
- uint64_t file_index = 0;
- if (!base::StringToUint64(extension.substr(1), &file_index)) {
- // Bad extension - not a number. Should not happen, will remove this
- // file.
- continue;
- }
- if (file_index < new_file_index) {
- // Lower index file, will remove it.
- continue;
- }
- // Keep this file - drop it from erase list.
- key_files_to_remove.erase(result.first);
- }
- // Delete all files assigned for deletion.
- for (const auto& file_to_remove : key_files_to_remove) {
- base::DeleteFile(file_to_remove); // Ignore errors, if any.
- }
+ DeleteFilesWarnIfFailed(
+ dir_enum,
+ base::BindRepeating(
+ [](uint64_t new_file_index, const base::FilePath& full_name) {
+ const auto extension = full_name.Extension();
+ if (extension.empty()) {
+ // Should not happen, will remove this file.
+ return true;
+ }
+ uint64_t file_index = 0;
+ if (!base::StringToUint64(extension.substr(1), &file_index)) {
+ // Bad extension - not a number. Should not happen, will remove
+ // this file.
+ return true;
+ }
+ if (file_index < new_file_index) {
+ // Lower index file, will remove it.
+ return true;
+ }
+ return false;
+ },
+ new_file_index));
}
// Enumerates possible key files, collects the ones that have valid name,
@@ -494,9 +488,8 @@ class Storage::KeyInStorage {
LocateValidKeyAndParse(
const base::flat_map<uint64_t, base::FilePath>& found_key_files) {
// Try to unserialize the key from each found file (latest first).
- for (auto key_file_it = found_key_files.rbegin();
- key_file_it != found_key_files.rend(); ++key_file_it) {
- base::File key_file(key_file_it->second,
+ for (const auto& [index, file_path] : base::Reversed(found_key_files)) {
+ base::File key_file(file_path,
base::File::FLAG_OPEN | base::File::FLAG_READ);
if (!key_file.IsValid()) {
continue; // Could not open.
@@ -511,7 +504,7 @@ class Storage::KeyInStorage {
if (read_result < 0) {
LOG(WARNING) << "File read error="
<< key_file.ErrorToString(key_file.GetLastFileError())
- << " " << key_file_it->second.MaybeAsASCII();
+ << " " << file_path.MaybeAsASCII();
continue; // File read error.
}
if (read_result == 0 || read_result >= kEncryptionKeyMaxFileSize) {
@@ -521,7 +514,7 @@ class Storage::KeyInStorage {
key_file_buffer.get(), read_result);
if (!signed_encryption_key.ParseFromZeroCopyStream(&key_stream)) {
LOG(WARNING) << "Failed to parse key file, full_name='"
- << key_file_it->second.MaybeAsASCII() << "'";
+ << file_path.MaybeAsASCII() << "'";
continue;
}
}
@@ -532,12 +525,12 @@ class Storage::KeyInStorage {
if (!signature_verification_status.ok()) {
LOG(WARNING) << "Loaded key failed verification, status="
<< signature_verification_status << ", full_name='"
- << key_file_it->second.MaybeAsASCII() << "'";
+ << file_path.MaybeAsASCII() << "'";
continue;
}
// Validated successfully. Return file name and signed key proto.
- return std::make_pair(key_file_it->second, signed_encryption_key);
+ return std::make_pair(file_path, signed_encryption_key);
}
// Not found, return error.
diff --git a/chromium/components/reporting/storage/storage_queue.cc b/chromium/components/reporting/storage/storage_queue.cc
index 3cca65de818..f3cdc0470e1 100644
--- a/chromium/components/reporting/storage/storage_queue.cc
+++ b/chromium/components/reporting/storage/storage_queue.cc
@@ -17,6 +17,7 @@
#include "base/bind.h"
#include "base/callback.h"
+#include "base/containers/adapters.h"
#include "base/containers/flat_set.h"
#include "base/files/file.h"
#include "base/files/file_enumerator.h"
@@ -41,6 +42,7 @@
#include "components/reporting/resources/resource_interface.h"
#include "components/reporting/storage/storage_configuration.h"
#include "components/reporting/storage/storage_uploader_interface.h"
+#include "components/reporting/util/file.h"
#include "components/reporting/util/status.h"
#include "components/reporting/util/status_macros.h"
#include "components/reporting/util/statusor.h"
@@ -727,10 +729,10 @@ Status StorageQueue::RestoreMetadata(
// No match or failed to load. Let's locate any valid metadata file (from
// latest to earilest) and use generation from there (last record digest is
// useless in that case).
- for (auto rit = meta_files.rbegin(); rit != meta_files.rend(); ++rit) {
- const auto status = ReadMetadata(
- /*meta_file_path=*/rit->second.first, /*size=*/rit->second.second,
- /*sequencing_id=*/rit->first, used_files_set);
+ for (const auto& [sequencing_id, path_and_size] :
+ base::Reversed(meta_files)) {
+ const auto& [path, size] = path_and_size;
+ const auto status = ReadMetadata(path, size, sequencing_id, used_files_set);
if (status.ok()) {
return status;
}
@@ -742,51 +744,53 @@ Status StorageQueue::RestoreMetadata(
} // namespace reporting
void StorageQueue::DeleteUnusedFiles(
- const base::flat_set<base::FilePath>& used_files_setused_files_set) {
+ const base::flat_set<base::FilePath>& used_files_set) const {
// Note, that these files were not reserved against disk allowance and do not
// need to be discarded.
+ // If the deletion of a file fails, the file will be naturally handled next
+ // time.
base::FileEnumerator dir_enum(options_.directory(),
/*recursive=*/true,
base::FileEnumerator::FILES);
- base::FilePath full_name;
- while (full_name = dir_enum.Next(), !full_name.empty()) {
- if (used_files_setused_files_set.count(full_name) > 0) {
- continue; // File is used, keep it.
- }
- base::DeleteFile(full_name);
- }
+ DeleteFilesWarnIfFailed(
+ dir_enum, base::BindRepeating(
+ [](const base::flat_set<base::FilePath>* used_files_set,
+ const base::FilePath& full_name) {
+ return !used_files_set->contains(full_name);
+ },
+ &used_files_set));
}
void StorageQueue::DeleteOutdatedMetadata(int64_t sequencing_id_to_keep) {
- std::vector<std::pair<base::FilePath, uint64_t>> files_to_delete;
+ // Delete file on disk. Note: disk space has already been released when the
+ // metafile was destructed, and so we don't need to do that here.
+ // If the deletion of a file fails, the file will be naturally handled next
+ // time.
base::FileEnumerator dir_enum(
options_.directory(),
/*recursive=*/false, base::FileEnumerator::FILES,
base::StrCat({METADATA_NAME, FILE_PATH_LITERAL(".*")}));
- base::FilePath full_name;
- while (full_name = dir_enum.Next(), !full_name.empty()) {
- const auto extension = dir_enum.GetInfo().GetName().FinalExtension();
- if (extension.empty()) {
- continue;
- }
- int64_t sequencing_id = 0;
- bool success = base::StringToInt64(
- dir_enum.GetInfo().GetName().FinalExtension().substr(1),
- &sequencing_id);
- if (!success) {
- continue;
- }
- if (sequencing_id >= sequencing_id_to_keep) {
- continue;
- }
- files_to_delete.emplace_back(
- std::make_pair(full_name, dir_enum.GetInfo().GetSize()));
- }
- for (const auto& file_to_delete : files_to_delete) {
- // Delete file on disk. Note: disk space has already been released when the
- // metafile was destructed, and so we don't need to do that here.
- base::DeleteFile(file_to_delete.first); // ignore result
- }
+
+ DeleteFilesWarnIfFailed(
+ dir_enum,
+ base::BindRepeating(
+ [](int64_t sequencing_id_to_keep, const base::FilePath& full_name) {
+ const auto extension = full_name.FinalExtension();
+ if (extension.empty()) {
+ return false;
+ }
+ int64_t sequencing_id = 0;
+ bool success =
+ base::StringToInt64(extension.substr(1), &sequencing_id);
+ if (!success) {
+ return false;
+ }
+ if (sequencing_id >= sequencing_id_to_keep) {
+ return false;
+ }
+ return true;
+ },
+ sequencing_id_to_keep));
}
// Context for uploading data from the queue in proper sequence.
@@ -1527,13 +1531,13 @@ Status StorageQueue::SwitchLastFileIfNotEmpty() {
std::map<int64_t, scoped_refptr<StorageQueue::SingleFile>>
StorageQueue::CollectFilesForUpload(int64_t sequencing_id) const {
DCHECK_CALLED_ON_VALID_SEQUENCE(storage_queue_sequence_checker_);
- // Locate the first file based on sequencing id.
- auto file_it = files_.find(sequencing_id);
- if (file_it == files_.end()) {
- file_it = files_.upper_bound(sequencing_id);
- if (file_it != files_.begin()) {
- --file_it;
- }
+ // Locate the last file that contains a sequencing ID <= sequencing_id. This
+ // is to ensure that we do not miss an event that hasn't been uploaded (i.e.,
+ // an event that has a sequencing ID >= sequencing_id). If no such file
+ // exists, use files_.begin().
+ auto file_it = files_.upper_bound(sequencing_id);
+ if (file_it != files_.begin()) {
+ --file_it;
}
// Create references to the files that will be uploaded.
@@ -1616,8 +1620,7 @@ Status StorageQueue::RemoveConfirmedData(int64_t sequencing_id) {
// file for writing).
for (;;) {
DCHECK(!files_.empty()) << "Empty storage queue";
- auto next_it = files_.begin();
- ++next_it; // Need to consider the next file.
+ auto next_it = std::next(files_.begin()); // Need to consider the next file
if (next_it == files_.end()) {
// We are on the last file, keep it.
break;
@@ -1630,9 +1633,8 @@ Status StorageQueue::RemoveConfirmedData(int64_t sequencing_id) {
// Current file holds only ids <= sequencing_id.
// Delete it.
files_.begin()->second->Close();
- if (files_.begin()->second->Delete().ok()) {
- files_.erase(files_.begin());
- }
+ files_.begin()->second->DeleteWarnIfFailed();
+ files_.erase(files_.begin());
}
// Even if there were errors, ignore them.
return Status::StatusOK();
@@ -1743,15 +1745,11 @@ void StorageQueue::SingleFile::Close() {
}
}
-Status StorageQueue::SingleFile::Delete() {
+void StorageQueue::SingleFile::DeleteWarnIfFailed() {
DCHECK(!handle_);
GetDiskResource()->Discard(size_);
size_ = 0;
- if (!base::DeleteFile(filename_)) {
- return Status(error::DATA_LOSS,
- base::StrCat({"Cannot delete file=", name()}));
- }
- return Status::StatusOK();
+ DeleteFileWarnIfFailed(filename_);
}
StatusOr<base::StringPiece> StorageQueue::SingleFile::Read(
diff --git a/chromium/components/reporting/storage/storage_queue.h b/chromium/components/reporting/storage/storage_queue.h
index 8c2b2ac48a9..88619b38aff 100644
--- a/chromium/components/reporting/storage/storage_queue.h
+++ b/chromium/components/reporting/storage/storage_queue.h
@@ -151,7 +151,7 @@ class StorageQueue : public base::RefCountedDeleteOnSequence<StorageQueue> {
Status Open(bool read_only); // No-op if already opened.
void Close(); // No-op if not opened.
- Status Delete();
+ void DeleteWarnIfFailed();
// Attempts to read |size| bytes from position |pos| and returns
// reference to the data that were actually read (no more than |size|).
@@ -279,9 +279,9 @@ class StorageQueue : public base::RefCountedDeleteOnSequence<StorageQueue> {
// Adds used metadata file to the set.
Status RestoreMetadata(base::flat_set<base::FilePath>* used_files_set);
- // Delete all files except those listed in the set.
+ // Delete all files except those listed in |used_file_set|.
void DeleteUnusedFiles(
- const base::flat_set<base::FilePath>& used_files_setused_files_set);
+ const base::flat_set<base::FilePath>& used_files_set) const;
// Helper method for Write(): deletes meta files up to, but not including
// |sequencing_id_to_keep|. Any errors are ignored.
diff --git a/chromium/components/reporting/storage/storage_queue_unittest.cc b/chromium/components/reporting/storage/storage_queue_unittest.cc
index b8097a04af8..079a0c2ee51 100644
--- a/chromium/components/reporting/storage/storage_queue_unittest.cc
+++ b/chromium/components/reporting/storage/storage_queue_unittest.cc
@@ -22,15 +22,16 @@
#include "base/task/thread_pool.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
+#include "base/threading/sequence_bound.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "components/reporting/compression/compression_module.h"
#include "components/reporting/compression/decompression.h"
-#include "components/reporting/compression/test_compression_module.h"
#include "components/reporting/encryption/test_encryption_module.h"
#include "components/reporting/proto/synced/record.pb.h"
#include "components/reporting/resources/resource_interface.h"
#include "components/reporting/storage/storage_configuration.h"
+#include "components/reporting/util/file.h"
#include "components/reporting/util/status.h"
#include "components/reporting/util/statusor.h"
#include "components/reporting/util/test_support_callbacks.h"
@@ -65,7 +66,7 @@ const base::FilePath::CharType METADATA_NAME[] = FILE_PATH_LITERAL("META");
// Forbidden file/folder names
const base::FilePath::StringType kInvalidFilePrefix = FILE_PATH_LITERAL("..");
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
const base::FilePath::StringPieceType kInvalidDirectoryPath =
FILE_PATH_LITERAL("o:\\some\\inaccessible\\dir");
#else
@@ -73,6 +74,19 @@ const base::FilePath::StringPieceType kInvalidDirectoryPath =
FILE_PATH_LITERAL("////////////");
#endif
+// Ensure files as specified by the parameters are deleted. Take the same
+// parameters as base::FileEnumerator().
+template <typename... FileEnumeratorParams>
+void EnsureDeletingFiles(FileEnumeratorParams... file_enum_params) {
+ base::FileEnumerator dir_enum(file_enum_params...);
+ ASSERT_TRUE(DeleteFilesWarnIfFailed(dir_enum));
+ // Ensure that the files have been deleted
+ ASSERT_TRUE(base::FileEnumerator(
+ std::forward<FileEnumeratorParams>(file_enum_params)...)
+ .Next()
+ .empty());
+}
+
class StorageQueueTest
: public ::testing::TestWithParam<
testing::tuple<size_t /*file_size*/, std::string /*dm_token*/>> {
@@ -80,10 +94,11 @@ class StorageQueueTest
void SetUp() override {
ASSERT_TRUE(location_.CreateUniqueTempDir());
dm_token_ = testing::get<1>(GetParam());
- options_.set_directory(base::FilePath(location_.GetPath()));
+ options_.set_directory(location_.GetPath());
+ // Disallow uploads unless other expectation is set (any later EXPECT_CALL
+ // will take precedence over this one).
EXPECT_CALL(set_mock_uploader_expectations_, Call(_))
- .WillRepeatedly(Invoke([](UploaderInterface::UploadReason reason)
- -> StatusOr<std::unique_ptr<TestUploader>> {
+ .WillRepeatedly(Invoke([](UploaderInterface::UploadReason reason) {
return Status(
error::UNAVAILABLE,
base::StrCat({"Test uploader not provided by the test, reason=",
@@ -102,102 +117,123 @@ class StorageQueueTest
LOG(ERROR) << "Next uploader id=" << next_uploader_id.load();
}
- class MockUpload : public base::RefCountedDeleteOnSequence<
- ::testing::NiceMock<MockUpload>> {
+ // Mock class used for setting upload expectations on it.
+ class MockUpload {
public:
- explicit MockUpload(
- scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner)
- : base::RefCountedDeleteOnSequence<::testing::NiceMock<MockUpload>>(
- sequenced_task_runner) {
- DETACH_FROM_SEQUENCE(mock_uploader_checker_);
+ MockUpload() = default;
+ virtual ~MockUpload() = default;
+ MOCK_METHOD(void,
+ EncounterSeqId,
+ (int64_t /*uploader_id*/, int64_t),
+ (const));
+ MOCK_METHOD(bool,
+ UploadRecord,
+ (int64_t /*uploader_id*/, int64_t, base::StringPiece),
+ (const));
+ MOCK_METHOD(bool,
+ UploadRecordFailure,
+ (int64_t /*uploader_id*/, int64_t, Status),
+ (const));
+ MOCK_METHOD(bool,
+ UploadGap,
+ (int64_t /*uploader_id*/, int64_t, uint64_t),
+ (const));
+ MOCK_METHOD(void,
+ UploadComplete,
+ (int64_t /*uploader_id*/, Status),
+ (const));
+ };
+
+ // Helper class to be wrapped in SequenceBound<..>, in order to make sure
+ // all its methods are run on a main sequential task wrapper. As a result,
+ // collected information and EXPECT_CALLs to MockUpload are safe - executed on
+ // the main test thread.
+ class SequenceBoundUpload {
+ public:
+ explicit SequenceBoundUpload(const MockUpload* mock_upload)
+ : mock_upload_(mock_upload) {
+ DETACH_FROM_SEQUENCE(scoped_checker_);
upload_progress_.assign("\nStart\n");
}
- MockUpload(const MockUpload& other) = delete;
- MockUpload& operator=(const MockUpload& other) = delete;
+ SequenceBoundUpload(const SequenceBoundUpload& other) = delete;
+ SequenceBoundUpload& operator=(const SequenceBoundUpload& other) = delete;
+ ~SequenceBoundUpload() { DCHECK_CALLED_ON_VALID_SEQUENCE(scoped_checker_); }
- void DoEncounterSeqId(int64_t uploader_id, int64_t sequence_id) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(mock_uploader_checker_);
+ void DoEncounterSeqId(int64_t uploader_id, int64_t sequencing_id) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(scoped_checker_);
upload_progress_.append("SeqId: ")
- .append(base::NumberToString(sequence_id))
+ .append(base::NumberToString(sequencing_id))
.append("\n");
- EncounterSeqId(uploader_id, sequence_id);
+ mock_upload_->EncounterSeqId(uploader_id, sequencing_id);
}
- bool DoUploadRecord(int64_t uploader_id,
- int64_t sequence_id,
- base::StringPiece data) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(mock_uploader_checker_);
+
+ void DoUploadRecord(int64_t uploader_id,
+ int64_t sequencing_id,
+ base::StringPiece data,
+ base::OnceCallback<void(bool)> processed_cb) {
+ DoEncounterSeqId(uploader_id, sequencing_id);
+ DCHECK_CALLED_ON_VALID_SEQUENCE(scoped_checker_);
upload_progress_.append("Record: ")
- .append(base::NumberToString(sequence_id))
+ .append(base::NumberToString(sequencing_id))
.append(" '")
.append(data.data(), data.size())
.append("'\n");
- return UploadRecord(uploader_id, sequence_id, data);
+ std::move(processed_cb)
+ .Run(mock_upload_->UploadRecord(uploader_id, sequencing_id, data));
}
- bool DoUploadRecordFailure(int64_t uploader_id,
- int64_t sequence_id,
- Status status) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(mock_uploader_checker_);
+
+ void DoUploadRecordFailure(int64_t uploader_id,
+ int64_t sequencing_id,
+ Status status,
+ base::OnceCallback<void(bool)> processed_cb) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(scoped_checker_);
upload_progress_.append("Failure: ")
- .append(base::NumberToString(sequence_id))
+ .append(base::NumberToString(sequencing_id))
.append(" '")
.append(status.ToString())
.append("'\n");
- return UploadRecordFailure(uploader_id, sequence_id, status);
+ std::move(processed_cb)
+ .Run(mock_upload_->UploadRecordFailure(uploader_id, sequencing_id,
+ status));
}
- bool DoUploadGap(int64_t uploader_id, int64_t sequence_id, uint64_t count) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(mock_uploader_checker_);
+
+ void DoUploadGap(int64_t uploader_id,
+ int64_t sequencing_id,
+ uint64_t count,
+ base::OnceCallback<void(bool)> processed_cb) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(scoped_checker_);
+ for (uint64_t c = 0; c < count; ++c) {
+ DoEncounterSeqId(uploader_id, sequencing_id + static_cast<int64_t>(c));
+ }
upload_progress_.append("Gap: ")
- .append(base::NumberToString(sequence_id))
+ .append(base::NumberToString(sequencing_id))
.append("(")
.append(base::NumberToString(count))
.append(")\n");
- return UploadGap(uploader_id, sequence_id, count);
+ std::move(processed_cb)
+ .Run(mock_upload_->UploadGap(uploader_id, sequencing_id, count));
}
void DoUploadComplete(int64_t uploader_id, Status status) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(mock_uploader_checker_);
+ DCHECK_CALLED_ON_VALID_SEQUENCE(scoped_checker_);
upload_progress_.append("Complete: ")
.append(status.ToString())
.append("\n");
LOG(ERROR) << "TestUploader: " << upload_progress_ << "End\n";
- UploadComplete(uploader_id, status);
- }
-
- MOCK_METHOD(void,
- EncounterSeqId,
- (int64_t /*uploader_id*/, int64_t),
- (const));
- MOCK_METHOD(bool,
- UploadRecord,
- (int64_t /*uploader_id*/, int64_t, base::StringPiece),
- (const));
- MOCK_METHOD(bool,
- UploadRecordFailure,
- (int64_t /*uploader_id*/, int64_t, Status),
- (const));
- MOCK_METHOD(bool,
- UploadGap,
- (int64_t /*uploader_id*/, int64_t, uint64_t),
- (const));
- MOCK_METHOD(void,
- UploadComplete,
- (int64_t /*uploader_id*/, Status),
- (const));
-
- protected:
- virtual ~MockUpload() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(mock_uploader_checker_);
+ mock_upload_->UploadComplete(uploader_id, status);
}
private:
- friend class base::RefCountedDeleteOnSequence<
- ::testing::NiceMock<MockUpload>>;
+ const raw_ptr<const MockUpload> mock_upload_;
- SEQUENCE_CHECKER(mock_uploader_checker_);
+ SEQUENCE_CHECKER(scoped_checker_);
// Snapshot of data received in this upload (for debug purposes).
std::string upload_progress_;
};
+ // Uploader interface implementation to be assigned to tests.
+ // Note that Storage guarantees that all APIs are executed on the same
+ // sequenced task runner (not the main test thread!).
class TestUploader : public UploaderInterface {
public:
// Mapping of <generation id, sequencing id> to matching record digest.
@@ -209,117 +245,6 @@ class StorageQueueTest
std::pair<int64_t /*generation id */, int64_t /*sequencing id*/>,
absl::optional<std::string /*digest*/>>;
- explicit TestUploader(StorageQueueTest* self)
- : uploader_id_(next_uploader_id.fetch_add(1)),
- last_record_digest_map_(&self->last_record_digest_map_),
- main_thread_task_runner_(self->main_thread_task_runner_),
- mock_upload_(base::MakeRefCounted<::testing::NiceMock<MockUpload>>(
- main_thread_task_runner_)) {
- DETACH_FROM_SEQUENCE(test_uploader_checker_);
- }
-
- ~TestUploader() override {
- DCHECK_CALLED_ON_VALID_SEQUENCE(test_uploader_checker_);
- DCHECK(!mock_upload_);
- }
-
- void ProcessRecord(EncryptedRecord encrypted_record,
- base::OnceCallback<void(bool)> processed_cb) override {
- DCHECK_CALLED_ON_VALID_SEQUENCE(test_uploader_checker_);
- DCHECK(mock_upload_);
- auto sequence_information = encrypted_record.sequence_information();
- // Decompress encrypted_wrapped_record if is was compressed.
- WrappedRecord wrapped_record;
- if (encrypted_record.has_compression_information()) {
- std::string decompressed_record = Decompression::DecompressRecord(
- encrypted_record.encrypted_wrapped_record(),
- encrypted_record.compression_information());
- encrypted_record.set_encrypted_wrapped_record(decompressed_record);
- }
- ASSERT_TRUE(wrapped_record.ParseFromString(
- encrypted_record.encrypted_wrapped_record()));
-
- // Verify compression information is enabled or disabled.
- if (CompressionModule::is_enabled()) {
- EXPECT_TRUE(encrypted_record.has_compression_information());
- } else {
- EXPECT_FALSE(encrypted_record.has_compression_information());
- }
-
- ScheduleVerifyRecord(std::move(sequence_information),
- std::move(wrapped_record), std::move(processed_cb));
- }
-
- void ProcessGap(SequenceInformation sequence_information,
- uint64_t count,
- base::OnceCallback<void(bool)> processed_cb) override {
- DCHECK_CALLED_ON_VALID_SEQUENCE(test_uploader_checker_);
- DCHECK(mock_upload_);
- // Verify generation match.
- if (generation_id_.has_value() &&
- generation_id_.value() != sequence_information.generation_id()) {
- main_thread_task_runner_->PostTask(
- FROM_HERE,
- base::BindOnce(
- [](SequenceInformation sequence_information,
- int64_t uploader_id, int64_t generation_id,
- scoped_refptr<MockUpload> mock_upload,
- base::OnceCallback<void(bool)> processed_cb) {
- std::move(processed_cb)
- .Run(mock_upload->DoUploadRecordFailure(
- uploader_id, sequence_information.sequencing_id(),
- Status(
- error::DATA_LOSS,
- base::StrCat({"Generation id mismatch, expected=",
- base::NumberToString(generation_id),
- " actual=",
- base::NumberToString(
- sequence_information
- .generation_id())}))));
- },
- std::move(sequence_information), uploader_id_,
- generation_id_.value(), mock_upload_, std::move(processed_cb)));
- return;
- }
- if (!generation_id_.has_value()) {
- generation_id_ = sequence_information.generation_id();
- }
-
- last_record_digest_map_->emplace(
- std::make_pair(sequence_information.sequencing_id(),
- sequence_information.generation_id()),
- absl::nullopt);
-
- main_thread_task_runner_->PostTask(
- FROM_HERE,
- base::BindOnce(
- [](uint64_t count, SequenceInformation sequence_information,
- int64_t uploader_id, scoped_refptr<MockUpload> mock_upload,
- base::OnceCallback<void(bool)> processed_cb) {
- for (uint64_t c = 0; c < count; ++c) {
- mock_upload->DoEncounterSeqId(
- uploader_id, sequence_information.sequencing_id() +
- static_cast<int64_t>(c));
- }
- std::move(processed_cb)
- .Run(mock_upload->DoUploadGap(
- uploader_id, sequence_information.sequencing_id(),
- count));
- },
- count, std::move(sequence_information), uploader_id_,
- mock_upload_, std::move(processed_cb)));
- }
-
- void Completed(Status status) override {
- DCHECK_CALLED_ON_VALID_SEQUENCE(test_uploader_checker_);
- DCHECK(mock_upload_);
- main_thread_task_runner_->PostTask(
- FROM_HERE,
- base::BindOnce(&MockUpload::DoUploadComplete,
- std::move(mock_upload_), // No longer needed.
- uploader_id_, status));
- }
-
// Helper class for setting up mock uploader expectations of a successful
// completion.
class SetUp {
@@ -330,10 +255,11 @@ class StorageQueueTest
waiter_(waiter) {}
SetUp(const SetUp& other) = delete;
SetUp& operator=(const SetUp& other) = delete;
- ~SetUp() = default;
+ ~SetUp() { CHECK(!uploader_) << "Missed 'Complete' call"; }
std::unique_ptr<TestUploader> Complete(
Status status = Status::StatusOK()) {
+ CHECK(uploader_) << "'Complete' already called";
EXPECT_CALL(*uploader_->mock_upload_,
UploadComplete(Eq(uploader_id_), Eq(status)))
.InSequence(uploader_->test_upload_sequence_,
@@ -346,18 +272,20 @@ class StorageQueueTest
return std::move(uploader_);
}
- SetUp& Required(int64_t sequence_number, base::StringPiece value) {
+ SetUp& Required(int64_t sequencing_id, base::StringPiece value) {
+ CHECK(uploader_) << "'Complete' already called";
EXPECT_CALL(*uploader_->mock_upload_,
- UploadRecord(Eq(uploader_id_), Eq(sequence_number),
+ UploadRecord(Eq(uploader_id_), Eq(sequencing_id),
StrEq(std::string(value))))
.InSequence(uploader_->test_upload_sequence_)
.WillOnce(Return(true));
return *this;
}
- SetUp& Possible(int64_t sequence_number, base::StringPiece value) {
+ SetUp& Possible(int64_t sequencing_id, base::StringPiece value) {
+ CHECK(uploader_) << "'Complete' already called";
EXPECT_CALL(*uploader_->mock_upload_,
- UploadRecord(Eq(uploader_id_), Eq(sequence_number),
+ UploadRecord(Eq(uploader_id_), Eq(sequencing_id),
StrEq(std::string(value))))
.Times(Between(0, 1))
.InSequence(uploader_->test_upload_sequence_)
@@ -365,27 +293,30 @@ class StorageQueueTest
return *this;
}
- SetUp& RequiredGap(int64_t sequence_number, uint64_t count) {
+ SetUp& RequiredGap(int64_t sequencing_id, uint64_t count) {
+ CHECK(uploader_) << "'Complete' already called";
EXPECT_CALL(*uploader_->mock_upload_,
- UploadGap(Eq(uploader_id_), Eq(sequence_number), Eq(count)))
+ UploadGap(Eq(uploader_id_), Eq(sequencing_id), Eq(count)))
.InSequence(uploader_->test_upload_sequence_)
.WillOnce(Return(true));
return *this;
}
- SetUp& PossibleGap(int64_t sequence_number, uint64_t count) {
+ SetUp& PossibleGap(int64_t sequencing_id, uint64_t count) {
+ CHECK(uploader_) << "'Complete' already called";
EXPECT_CALL(*uploader_->mock_upload_,
- UploadGap(Eq(uploader_id_), Eq(sequence_number), Eq(count)))
+ UploadGap(Eq(uploader_id_), Eq(sequencing_id), Eq(count)))
.Times(Between(0, 1))
.InSequence(uploader_->test_upload_sequence_)
.WillRepeatedly(Return(true));
return *this;
}
- SetUp& Failure(int64_t sequence_number, Status error) {
- EXPECT_CALL(*uploader_->mock_upload_,
- UploadRecordFailure(Eq(uploader_id_), Eq(sequence_number),
- Eq(error)))
+ SetUp& Failure(int64_t sequencing_id, Status error) {
+ CHECK(uploader_) << "'Complete' already called";
+ EXPECT_CALL(
+ *uploader_->mock_upload_,
+ UploadRecordFailure(Eq(uploader_id_), Eq(sequencing_id), Eq(error)))
.InSequence(uploader_->test_upload_sequence_)
.WillOnce(Return(true));
return *this;
@@ -395,17 +326,19 @@ class StorageQueueTest
// sequencing ids have been encountered, regardless of whether they
// belonged to records or gaps. The expectations are set on a separate
// test sequence.
- SetUp& RequiredSeqId(int64_t sequence_number) {
+ SetUp& RequiredSeqId(int64_t sequencing_id) {
+ CHECK(uploader_) << "'Complete' already called";
EXPECT_CALL(*uploader_->mock_upload_,
- EncounterSeqId(Eq(uploader_id_), Eq(sequence_number)))
+ EncounterSeqId(Eq(uploader_id_), Eq(sequencing_id)))
.Times(1)
.InSequence(uploader_->test_encounter_sequence_);
return *this;
}
- SetUp& PossibleSeqId(int64_t sequence_number) {
+ SetUp& PossibleSeqId(int64_t sequencing_id) {
+ CHECK(uploader_) << "'Complete' already called";
EXPECT_CALL(*uploader_->mock_upload_,
- EncounterSeqId(Eq(uploader_id_), Eq(sequence_number)))
+ EncounterSeqId(Eq(uploader_id_), Eq(sequencing_id)))
.Times(Between(0, 1))
.InSequence(uploader_->test_encounter_sequence_);
return *this;
@@ -417,33 +350,104 @@ class StorageQueueTest
const raw_ptr<test::TestCallbackWaiter> waiter_;
};
- private:
- void ScheduleVerifyRecord(SequenceInformation sequence_information,
- WrappedRecord wrapped_record,
- base::OnceCallback<void(bool)> processed_cb) {
- main_thread_task_runner_->PostTask(
- FROM_HERE,
- base::BindOnce(&TestUploader::VerifyRecord, base::Unretained(this),
- std::move(sequence_information),
- std::move(wrapped_record), std::move(processed_cb)));
+ explicit TestUploader(StorageQueueTest* self)
+ : uploader_id_(next_uploader_id.fetch_add(1)),
+ last_record_digest_map_(&self->last_record_digest_map_),
+ mock_upload_(&self->mock_upload_),
+ sequence_bound_upload_(self->main_thread_task_runner_,
+ &self->mock_upload_) {
+ DETACH_FROM_SEQUENCE(test_uploader_checker_);
+ }
+
+ ~TestUploader() override {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(test_uploader_checker_);
}
+ void ProcessRecord(EncryptedRecord encrypted_record,
+ base::OnceCallback<void(bool)> processed_cb) override {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(test_uploader_checker_);
+ auto sequence_information = encrypted_record.sequence_information();
+ // Decompress encrypted_wrapped_record if is was compressed.
+ WrappedRecord wrapped_record;
+ if (encrypted_record.has_compression_information()) {
+ std::string decompressed_record = Decompression::DecompressRecord(
+ encrypted_record.encrypted_wrapped_record(),
+ encrypted_record.compression_information());
+ encrypted_record.set_encrypted_wrapped_record(decompressed_record);
+ }
+ ASSERT_TRUE(wrapped_record.ParseFromString(
+ encrypted_record.encrypted_wrapped_record()));
+
+ // Verify compression information is enabled or disabled.
+ if (CompressionModule::is_enabled()) {
+ EXPECT_TRUE(encrypted_record.has_compression_information());
+ } else {
+ EXPECT_FALSE(encrypted_record.has_compression_information());
+ }
+
+ VerifyRecord(std::move(sequence_information), std::move(wrapped_record),
+ std::move(processed_cb));
+ }
+
+ void ProcessGap(SequenceInformation sequence_information,
+ uint64_t count,
+ base::OnceCallback<void(bool)> processed_cb) override {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(test_uploader_checker_);
+ // Verify generation match.
+ if (generation_id_.has_value() &&
+ generation_id_.value() != sequence_information.generation_id()) {
+ sequence_bound_upload_
+ .AsyncCall(&SequenceBoundUpload::DoUploadRecordFailure)
+ .WithArgs(uploader_id_, sequence_information.sequencing_id(),
+ Status(error::DATA_LOSS,
+ base::StrCat(
+ {"Generation id mismatch, expected=",
+ base::NumberToString(generation_id_.value()),
+ " actual=",
+ base::NumberToString(
+ sequence_information.generation_id())})),
+ std::move(processed_cb));
+ return;
+ }
+ if (!generation_id_.has_value()) {
+ generation_id_ = sequence_information.generation_id();
+ }
+
+ last_record_digest_map_->emplace(
+ std::make_pair(sequence_information.sequencing_id(),
+ sequence_information.generation_id()),
+ absl::nullopt);
+
+ sequence_bound_upload_.AsyncCall(&SequenceBoundUpload::DoUploadGap)
+ .WithArgs(uploader_id_, sequence_information.sequencing_id(), count,
+ std::move(processed_cb));
+ }
+
+ void Completed(Status status) override {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(test_uploader_checker_);
+ sequence_bound_upload_.AsyncCall(&SequenceBoundUpload::DoUploadComplete)
+ .WithArgs(uploader_id_, status);
+ }
+
+ private:
void VerifyRecord(SequenceInformation sequence_information,
WrappedRecord wrapped_record,
base::OnceCallback<void(bool)> processed_cb) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(test_uploader_checker_);
// Verify generation match.
if (generation_id_.has_value() &&
generation_id_.value() != sequence_information.generation_id()) {
- std::move(processed_cb)
- .Run(mock_upload_->DoUploadRecordFailure(
- uploader_id_, sequence_information.sequencing_id(),
- Status(error::DATA_LOSS,
- base::StrCat(
- {"Generation id mismatch, expected=",
- base::NumberToString(generation_id_.value()),
- " actual=",
- base::NumberToString(
- sequence_information.generation_id())}))));
+ sequence_bound_upload_
+ .AsyncCall(&SequenceBoundUpload::DoUploadRecordFailure)
+ .WithArgs(uploader_id_, sequence_information.sequencing_id(),
+ Status(error::DATA_LOSS,
+ base::StrCat(
+ {"Generation id mismatch, expected=",
+ base::NumberToString(generation_id_.value()),
+ " actual=",
+ base::NumberToString(
+ sequence_information.generation_id())})),
+ std::move(processed_cb));
return;
}
if (!generation_id_.has_value()) {
@@ -457,10 +461,11 @@ class StorageQueueTest
const auto record_digest = crypto::SHA256HashString(serialized_record);
DCHECK_EQ(record_digest.size(), crypto::kSHA256Length);
if (record_digest != wrapped_record.record_digest()) {
- std::move(processed_cb)
- .Run(mock_upload_->DoUploadRecordFailure(
- uploader_id_, sequence_information.sequencing_id(),
- Status(error::DATA_LOSS, "Record digest mismatch")));
+ sequence_bound_upload_
+ .AsyncCall(&SequenceBoundUpload::DoUploadRecordFailure)
+ .WithArgs(uploader_id_, sequence_information.sequencing_id(),
+ Status(error::DATA_LOSS, "Record digest mismatch"),
+ std::move(processed_cb));
return;
}
// Store record digest for the next record in sequence to
@@ -478,21 +483,20 @@ class StorageQueueTest
if (it == last_record_digest_map_->end() ||
(it->second.has_value() &&
it->second.value() != wrapped_record.last_record_digest())) {
- std::move(processed_cb)
- .Run(mock_upload_->DoUploadRecordFailure(
+ sequence_bound_upload_
+ .AsyncCall(&SequenceBoundUpload::DoUploadRecordFailure)
+ .WithArgs(
uploader_id_, sequence_information.sequencing_id(),
- Status(error::DATA_LOSS, "Last record digest mismatch")));
+ Status(error::DATA_LOSS, "Last record digest mismatch"),
+ std::move(processed_cb));
return;
}
}
}
- mock_upload_->DoEncounterSeqId(uploader_id_,
- sequence_information.sequencing_id());
- std::move(processed_cb)
- .Run(mock_upload_->DoUploadRecord(
- uploader_id_, sequence_information.sequencing_id(),
- wrapped_record.record().data()));
+ sequence_bound_upload_.AsyncCall(&SequenceBoundUpload::DoUploadRecord)
+ .WithArgs(uploader_id_, sequence_information.sequencing_id(),
+ wrapped_record.record().data(), std::move(processed_cb));
}
SEQUENCE_CHECKER(test_uploader_checker_);
@@ -506,10 +510,9 @@ class StorageQueueTest
absl::optional<int64_t> generation_id_;
const raw_ptr<LastRecordDigestMap> last_record_digest_map_;
- // Single task runner where all EXPECTs will happen.
- const scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_;
+ const raw_ptr<const MockUpload> mock_upload_;
- scoped_refptr<::testing::NiceMock<MockUpload>> mock_upload_;
+ base::SequenceBound<SequenceBoundUpload> sequence_bound_upload_;
Sequence test_encounter_sequence_;
Sequence test_upload_sequence_;
@@ -660,8 +663,10 @@ class StorageQueueTest
// digest. Serves all TestUploaders created by test fixture.
TestUploader::LastRecordDigestMap last_record_digest_map_;
+ const ::testing::NiceMock<const MockUpload> mock_upload_;
+
::testing::MockFunction<StatusOr<std::unique_ptr<TestUploader>>(
- UploaderInterface::UploadReason)>
+ UploaderInterface::UploadReason /*reason*/)>
set_mock_uploader_expectations_;
};
@@ -790,14 +795,9 @@ TEST_P(StorageQueueTest,
ResetTestStorageQueue();
// Delete all metadata files.
- base::FileEnumerator dir_enum(
- options.directory(),
- /*recursive=*/false, base::FileEnumerator::FILES,
- base::StrCat({METADATA_NAME, FILE_PATH_LITERAL(".*")}));
- base::FilePath full_name;
- while (full_name = dir_enum.Next(), !full_name.empty()) {
- base::DeleteFile(full_name);
- }
+ EnsureDeletingFiles(options.directory(),
+ /*recursive=*/false, base::FileEnumerator::FILES,
+ base::StrCat({METADATA_NAME, FILE_PATH_LITERAL(".*")}));
// Reopen, starting a new generation.
CreateTestStorageQueueOrDie(BuildStorageQueueOptionsPeriodic());
@@ -838,15 +838,23 @@ TEST_P(
ResetTestStorageQueue();
- // Delete all metadata files.
- base::FileEnumerator dir_enum(
- options.directory(),
- /*recursive=*/false, base::FileEnumerator::FILES,
- base::StrCat({METADATA_NAME, FILE_PATH_LITERAL(".2")}));
- base::FilePath full_name = dir_enum.Next();
- ASSERT_FALSE(full_name.empty());
- base::DeleteFile(full_name);
- ASSERT_TRUE(dir_enum.Next().empty());
+ // Delete the last metadata file.
+ { // scoping this block so that dir_enum is not used later.
+ const auto last_metadata_file_pattern =
+ base::StrCat({METADATA_NAME, FILE_PATH_LITERAL(".2")});
+ base::FileEnumerator dir_enum(options.directory(),
+ /*recursive=*/false,
+ base::FileEnumerator::FILES,
+ last_metadata_file_pattern);
+ base::FilePath full_name = dir_enum.Next();
+ ASSERT_FALSE(full_name.empty())
+ << "No file matches " << last_metadata_file_pattern;
+ ASSERT_TRUE(dir_enum.Next().empty())
+ << full_name << " is not the last metadata file in "
+ << options.directory();
+ ASSERT_TRUE(base::DeleteFile(full_name))
+ << "Failed to delete " << full_name;
+ }
// Reopen, starting a new generation.
CreateTestStorageQueueOrDie(BuildStorageQueueOptionsPeriodic());
@@ -889,17 +897,11 @@ TEST_P(StorageQueueTest,
// Reopen with the same generation and sequencing information.
CreateTestStorageQueueOrDie(BuildStorageQueueOptionsPeriodic());
- // Delete the data file *.generation.0
- {
- base::FileEnumerator dir_enum(
- options.directory(),
- /*recursive=*/false, base::FileEnumerator::FILES,
- base::StrCat({options.file_prefix(), FILE_PATH_LITERAL(".*.0")}));
- base::FilePath full_name;
- while (full_name = dir_enum.Next(), !full_name.empty()) {
- base::DeleteFile(full_name);
- }
- }
+ // Delete the data files *.generation.0
+ EnsureDeletingFiles(
+ options.directory(),
+ /*recursive=*/false, base::FileEnumerator::FILES,
+ base::StrCat({options.file_prefix(), FILE_PATH_LITERAL(".*.0")}));
// Write more data.
WriteStringOrDie(kMoreData[0]);
diff --git a/chromium/components/reporting/storage/storage_unittest.cc b/chromium/components/reporting/storage/storage_unittest.cc
index 94cfeb1b4d4..2d400935609 100644
--- a/chromium/components/reporting/storage/storage_unittest.cc
+++ b/chromium/components/reporting/storage/storage_unittest.cc
@@ -19,6 +19,7 @@
#include "base/task/thread_pool.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
+#include "base/threading/sequence_bound.h"
#include "components/reporting/compression/compression_module.h"
#include "components/reporting/compression/test_compression_module.h"
#include "components/reporting/encryption/decryption.h"
@@ -228,114 +229,132 @@ class StorageTest
LOG(ERROR) << "Next uploader id=" << next_uploader_id.load();
}
- class MockUpload : public base::RefCountedDeleteOnSequence<
- ::testing::NiceMock<MockUpload>> {
+ // Mock class used for setting upload expectations on it.
+ class MockUpload {
public:
- MockUpload(scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner,
- base::OnceClosure key_generation)
- : base::RefCountedDeleteOnSequence<::testing::NiceMock<MockUpload>>(
- sequenced_task_runner),
- key_generation_(std::move(key_generation)) {
- DETACH_FROM_SEQUENCE(mock_uploader_checker_);
+ MockUpload() = default;
+ virtual ~MockUpload() = default;
+ MOCK_METHOD(void,
+ EncounterSeqId,
+ (int64_t /*uploader_id*/, Priority, int64_t),
+ (const));
+ MOCK_METHOD(bool,
+ UploadRecord,
+ (int64_t /*uploader_id*/, Priority, int64_t, base::StringPiece),
+ (const));
+ MOCK_METHOD(bool,
+ UploadRecordFailure,
+ (int64_t /*uploader_id*/, Priority, int64_t, Status),
+ (const));
+ MOCK_METHOD(bool,
+ UploadGap,
+ (int64_t /*uploader_id*/, Priority, int64_t, uint64_t),
+ (const));
+ MOCK_METHOD(void,
+ UploadComplete,
+ (int64_t /*uploader_id*/, Status),
+ (const));
+ };
+
+ // Helper class to be wrapped in SequenceBound<..>, in order to make sure
+ // all its methods are run on a main sequential task wrapper. As a result,
+ // collected information and EXPECT_CALLs to MockUpload are safe - executed on
+ // the main test thread.
+ class SequenceBoundUpload {
+ public:
+ explicit SequenceBoundUpload(const MockUpload* mock_upload)
+ : mock_upload_(mock_upload) {
+ DETACH_FROM_SEQUENCE(scoped_checker_);
upload_progress_.assign("\nStart\n");
}
- MockUpload(const MockUpload& other) = delete;
- MockUpload& operator=(const MockUpload& other) = delete;
-
- void KeyGeneration() { std::move(key_generation_).Run(); }
+ SequenceBoundUpload(const SequenceBoundUpload& other) = delete;
+ SequenceBoundUpload& operator=(const SequenceBoundUpload& other) = delete;
+ ~SequenceBoundUpload() { DCHECK_CALLED_ON_VALID_SEQUENCE(scoped_checker_); }
void DoEncounterSeqId(int64_t uploader_id,
Priority priority,
- int64_t sequence_id) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(mock_uploader_checker_);
+ int64_t sequencing_id) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(scoped_checker_);
upload_progress_.append("SeqId: ")
- .append(base::NumberToString(sequence_id))
+ .append(base::NumberToString(sequencing_id))
.append("\n");
- EncounterSeqId(uploader_id, priority, sequence_id);
+ mock_upload_->EncounterSeqId(uploader_id, priority, sequencing_id);
}
- bool DoUploadRecord(int64_t uploader_id,
+
+ void DoUploadRecord(int64_t uploader_id,
Priority priority,
- int64_t sequence_id,
- base::StringPiece data) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(mock_uploader_checker_);
+ int64_t sequencing_id,
+ base::StringPiece data,
+ base::OnceCallback<void(bool)> processed_cb) {
+ DoEncounterSeqId(uploader_id, priority, sequencing_id);
+ DCHECK_CALLED_ON_VALID_SEQUENCE(scoped_checker_);
upload_progress_.append("Record: ")
- .append(base::NumberToString(sequence_id))
+ .append(base::NumberToString(sequencing_id))
.append(" '")
.append(data.data(), data.size())
.append("'\n");
- return UploadRecord(uploader_id, priority, sequence_id, data);
+ std::move(processed_cb)
+ .Run(mock_upload_->UploadRecord(uploader_id, priority, sequencing_id,
+ data));
}
- bool DoUploadRecordFailure(int64_t uploader_id,
+
+ void DoUploadRecordFailure(int64_t uploader_id,
Priority priority,
- int64_t sequence_id,
- Status status) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(mock_uploader_checker_);
+ int64_t sequencing_id,
+ Status status,
+ base::OnceCallback<void(bool)> processed_cb) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(scoped_checker_);
upload_progress_.append("Failure: ")
- .append(base::NumberToString(sequence_id))
+ .append(base::NumberToString(sequencing_id))
.append(" '")
.append(status.ToString())
.append("'\n");
- return UploadRecordFailure(uploader_id, priority, sequence_id, status);
+ std::move(processed_cb)
+ .Run(mock_upload_->UploadRecordFailure(uploader_id, priority,
+ sequencing_id, status));
}
- bool DoUploadGap(int64_t uploader_id,
+
+ void DoUploadGap(int64_t uploader_id,
Priority priority,
- int64_t sequence_id,
- uint64_t count) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(mock_uploader_checker_);
+ int64_t sequencing_id,
+ uint64_t count,
+ base::OnceCallback<void(bool)> processed_cb) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(scoped_checker_);
+ for (uint64_t c = 0; c < count; ++c) {
+ DoEncounterSeqId(uploader_id, priority,
+ sequencing_id + static_cast<int64_t>(c));
+ }
upload_progress_.append("Gap: ")
- .append(base::NumberToString(sequence_id))
+ .append(base::NumberToString(sequencing_id))
.append("(")
.append(base::NumberToString(count))
.append(")\n");
- return UploadGap(uploader_id, priority, sequence_id, count);
+ std::move(processed_cb)
+ .Run(mock_upload_->UploadGap(uploader_id, priority, sequencing_id,
+ count));
}
+
void DoUploadComplete(int64_t uploader_id, Status status) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(mock_uploader_checker_);
+ DCHECK_CALLED_ON_VALID_SEQUENCE(scoped_checker_);
upload_progress_.append("Complete: ")
.append(status.ToString())
.append("\n");
LOG(ERROR) << "TestUploader: " << upload_progress_ << "End\n";
- UploadComplete(uploader_id, status);
- }
-
- MOCK_METHOD(void,
- EncounterSeqId,
- (int64_t /*uploader_id*/, Priority, int64_t),
- (const));
- MOCK_METHOD(bool,
- UploadRecord,
- (int64_t /*uploader_id*/, Priority, int64_t, base::StringPiece),
- (const));
- MOCK_METHOD(bool,
- UploadRecordFailure,
- (int64_t /*uploader_id*/, Priority, int64_t, Status),
- (const));
- MOCK_METHOD(bool,
- UploadGap,
- (int64_t /*uploader_id*/, Priority, int64_t, uint64_t),
- (const));
- MOCK_METHOD(void,
- UploadComplete,
- (int64_t /*uploader_id*/, Status),
- (const));
-
- protected:
- virtual ~MockUpload() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(mock_uploader_checker_);
+ mock_upload_->UploadComplete(uploader_id, status);
}
private:
- friend class base::RefCountedDeleteOnSequence<
- ::testing::NiceMock<MockUpload>>;
-
- base::OnceClosure key_generation_;
+ const raw_ptr<const MockUpload> mock_upload_;
- SEQUENCE_CHECKER(mock_uploader_checker_);
+ SEQUENCE_CHECKER(scoped_checker_);
// Snapshot of data received in this upload (for debug purposes).
std::string upload_progress_;
};
+ // Uploader interface implementation to be assigned to tests.
+ // Note that Storage guarantees that all APIs are executed on the same
+ // sequenced task runner (not the main test thread!).
class TestUploader : public UploaderInterface {
public:
// Mapping of <generation id, sequencing id> to matching record digest.
@@ -348,133 +367,6 @@ class StorageTest
int64_t /*sequencing id*/>,
absl::optional<std::string /*digest*/>>;
- explicit TestUploader(StorageTest* self)
- : uploader_id_(next_uploader_id.fetch_add(1)),
- last_record_digest_map_(&self->last_record_digest_map_),
- main_thread_task_runner_(self->main_thread_task_runner_),
- mock_upload_(base::MakeRefCounted<::testing::NiceMock<MockUpload>>(
- main_thread_task_runner_,
- base::BindOnce(&Storage::UpdateEncryptionKey,
- base::Unretained(self->storage_.get()),
- self->signed_encryption_key_))),
- decryptor_(self->decryptor_) {
- DETACH_FROM_SEQUENCE(test_uploader_checker_);
- }
-
- ~TestUploader() override {
- DCHECK(!mock_upload_);
- DCHECK_CALLED_ON_VALID_SEQUENCE(test_uploader_checker_);
- }
-
- void ProcessRecord(EncryptedRecord encrypted_record,
- base::OnceCallback<void(bool)> processed_cb) override {
- DCHECK_CALLED_ON_VALID_SEQUENCE(test_uploader_checker_);
- DCHECK(mock_upload_);
- auto sequence_information = encrypted_record.sequence_information();
- if (!encrypted_record.has_encryption_info()) {
- // Wrapped record is not encrypted.
- WrappedRecord wrapped_record;
- ASSERT_TRUE(wrapped_record.ParseFromString(
- encrypted_record.encrypted_wrapped_record()));
- ScheduleVerifyRecord(std::move(sequence_information),
- std::move(wrapped_record),
- std::move(processed_cb));
- return;
- }
- // Decrypt encrypted_record.
- (new SingleDecryptionContext(
- encrypted_record, decryptor_,
- base::BindOnce(
- [](SequenceInformation sequence_information,
- base::OnceCallback<void(bool)> processed_cb,
- TestUploader* uploader, StatusOr<base::StringPiece> result) {
- ASSERT_OK(result.status());
- WrappedRecord wrapped_record;
- ASSERT_TRUE(wrapped_record.ParseFromArray(
- result.ValueOrDie().data(), result.ValueOrDie().size()));
- // Verify wrapped record once decrypted.
- uploader->ScheduleVerifyRecord(std::move(sequence_information),
- std::move(wrapped_record),
- std::move(processed_cb));
- },
- std::move(sequence_information), std::move(processed_cb),
- base::Unretained(this))))
- ->Start();
- }
-
- void ProcessGap(SequenceInformation sequence_information,
- uint64_t count,
- base::OnceCallback<void(bool)> processed_cb) override {
- DCHECK_CALLED_ON_VALID_SEQUENCE(test_uploader_checker_);
- DCHECK(mock_upload_);
- // Verify generation match.
- if (generation_id_.has_value() &&
- generation_id_.value() != sequence_information.generation_id()) {
- main_thread_task_runner_->PostTask(
- FROM_HERE,
- base::BindOnce(
- [](SequenceInformation sequence_information,
- int64_t uploader_id, int64_t generation_id,
- scoped_refptr<MockUpload> mock_upload,
- base::OnceCallback<void(bool)> processed_cb) {
- std::move(processed_cb)
- .Run(mock_upload->DoUploadRecordFailure(
- uploader_id, sequence_information.priority(),
- sequence_information.sequencing_id(),
- Status(
- error::DATA_LOSS,
- base::StrCat({"Generation id mismatch, expected=",
- base::NumberToString(generation_id),
- " actual=",
- base::NumberToString(
- sequence_information
- .generation_id())}))));
- },
- std::move(sequence_information), uploader_id_,
- generation_id_.value(), mock_upload_, std::move(processed_cb)));
- return;
- }
- if (!generation_id_.has_value()) {
- generation_id_ = sequence_information.generation_id();
- }
-
- last_record_digest_map_->emplace(
- std::make_tuple(sequence_information.priority(),
- sequence_information.sequencing_id(),
- sequence_information.generation_id()),
- absl::nullopt);
-
- main_thread_task_runner_->PostTask(
- FROM_HERE,
- base::BindOnce(
- [](uint64_t count, SequenceInformation sequence_information,
- int64_t uploader_id, scoped_refptr<MockUpload> mock_upload,
- base::OnceCallback<void(bool)> processed_cb) {
- for (uint64_t c = 0; c < count; ++c) {
- mock_upload->DoEncounterSeqId(
- uploader_id, sequence_information.priority(),
- sequence_information.sequencing_id() +
- static_cast<int64_t>(c));
- }
- std::move(processed_cb)
- .Run(mock_upload->DoUploadGap(
- uploader_id, sequence_information.priority(),
- sequence_information.sequencing_id(), count));
- },
- count, std::move(sequence_information), uploader_id_,
- mock_upload_, std::move(processed_cb)));
- }
-
- void Completed(Status status) override {
- DCHECK_CALLED_ON_VALID_SEQUENCE(test_uploader_checker_);
- DCHECK(mock_upload_);
- main_thread_task_runner_->PostTask(
- FROM_HERE,
- base::BindOnce(&MockUpload::DoUploadComplete,
- std::move(mock_upload_), // No longer needed.
- uploader_id_, status));
- }
-
// Helper class for setting up mock uploader expectations of a successful
// completion.
class SetUp {
@@ -530,11 +422,11 @@ class StorageTest
return *this;
}
- SetUp& PossibleGap(int64_t sequence_number, uint64_t count) {
+ SetUp& PossibleGap(int64_t sequencing_id, uint64_t count) {
CHECK(uploader_) << "'Complete' already called";
EXPECT_CALL(*uploader_->mock_upload_,
UploadGap(Eq(uploader_id_), Eq(priority_),
- Eq(sequence_number), Eq(count)))
+ Eq(sequencing_id), Eq(count)))
.Times(Between(0, 1))
.InSequence(uploader_->test_upload_sequence_)
.WillRepeatedly(Return(true));
@@ -545,21 +437,21 @@ class StorageTest
// sequencing ids have been encountered, regardless of whether they
// belonged to records or gaps. The expectations are set on a separate
// test sequence.
- SetUp& RequiredSeqId(int64_t sequence_number) {
+ SetUp& RequiredSeqId(int64_t sequencing_id) {
CHECK(uploader_) << "'Complete' already called";
- EXPECT_CALL(*uploader_->mock_upload_,
- EncounterSeqId(Eq(uploader_id_), Eq(priority_),
- Eq(sequence_number)))
+ EXPECT_CALL(
+ *uploader_->mock_upload_,
+ EncounterSeqId(Eq(uploader_id_), Eq(priority_), Eq(sequencing_id)))
.Times(1)
.InSequence(uploader_->test_encounter_sequence_);
return *this;
}
- SetUp& PossibleSeqId(int64_t sequence_number) {
+ SetUp& PossibleSeqId(int64_t sequencing_id) {
CHECK(uploader_) << "'Complete' already called";
- EXPECT_CALL(*uploader_->mock_upload_,
- EncounterSeqId(Eq(uploader_id_), Eq(priority_),
- Eq(sequence_number)))
+ EXPECT_CALL(
+ *uploader_->mock_upload_,
+ EncounterSeqId(Eq(uploader_id_), Eq(priority_), Eq(sequencing_id)))
.Times(Between(0, 1))
.InSequence(uploader_->test_encounter_sequence_);
return *this;
@@ -604,7 +496,7 @@ class StorageTest
class SetKeyDelivery {
public:
explicit SetKeyDelivery(StorageTest* self)
- : uploader_(std::make_unique<TestUploader>(self)) {}
+ : self_(self), uploader_(std::make_unique<TestUploader>(self)) {}
SetKeyDelivery(const SetKeyDelivery& other) = delete;
SetKeyDelivery& operator=(const SetKeyDelivery& other) = delete;
~SetKeyDelivery() { CHECK(!uploader_) << "Missed 'Complete' call"; }
@@ -620,44 +512,134 @@ class StorageTest
EXPECT_CALL(
*uploader_->mock_upload_,
UploadComplete(Eq(uploader_->uploader_id_), Eq(Status::StatusOK())))
- .WillOnce(WithoutArgs(Invoke(uploader_->mock_upload_.get(),
- &MockUpload::KeyGeneration)))
+ .WillOnce(
+ WithoutArgs(Invoke(self_.get(), &StorageTest::DeliverKey)))
.RetiresOnSaturation();
return std::move(uploader_);
}
private:
+ const raw_ptr<StorageTest> self_;
std::unique_ptr<TestUploader> uploader_;
};
- private:
- void ScheduleVerifyRecord(SequenceInformation sequence_information,
- WrappedRecord wrapped_record,
- base::OnceCallback<void(bool)> processed_cb) {
- main_thread_task_runner_->PostTask(
- FROM_HERE,
- base::BindOnce(&TestUploader::VerifyRecord, base::Unretained(this),
- std::move(sequence_information),
- std::move(wrapped_record), std::move(processed_cb)));
+ explicit TestUploader(StorageTest* self)
+ : uploader_id_(next_uploader_id.fetch_add(1)),
+ last_record_digest_map_(&self->last_record_digest_map_),
+ mock_upload_(&self->mock_upload_),
+ sequence_bound_upload_(self->main_thread_task_runner_,
+ &self->mock_upload_),
+ decryptor_(self->decryptor_) {
+ DETACH_FROM_SEQUENCE(test_uploader_checker_);
+ }
+
+ ~TestUploader() override {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(test_uploader_checker_);
+ }
+
+ void ProcessRecord(EncryptedRecord encrypted_record,
+ base::OnceCallback<void(bool)> processed_cb) override {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(test_uploader_checker_);
+ auto sequence_information = encrypted_record.sequence_information();
+ if (!encrypted_record.has_encryption_info()) {
+ // Wrapped record is not encrypted.
+ WrappedRecord wrapped_record;
+ ASSERT_TRUE(wrapped_record.ParseFromString(
+ encrypted_record.encrypted_wrapped_record()));
+ VerifyRecord(std::move(sequence_information), std::move(wrapped_record),
+ std::move(processed_cb));
+ return;
+ }
+ // Decrypt encrypted_record asynhcronously, then resume on the current
+ // sequence.
+ (new SingleDecryptionContext(
+ encrypted_record, decryptor_,
+ base::BindOnce(
+ [](SequenceInformation sequence_information,
+ base::OnceCallback<void(bool)> processed_cb,
+ scoped_refptr<base::SequencedTaskRunner> task_runner,
+ TestUploader* uploader, StatusOr<base::StringPiece> result) {
+ ASSERT_OK(result.status());
+ WrappedRecord wrapped_record;
+ ASSERT_TRUE(wrapped_record.ParseFromArray(
+ result.ValueOrDie().data(), result.ValueOrDie().size()));
+ // Schedule on the same runner to verify wrapped record once
+ // decrypted.
+ task_runner->PostTask(
+ FROM_HERE, base::BindOnce(&TestUploader::VerifyRecord,
+ base::Unretained(uploader),
+ std::move(sequence_information),
+ std::move(wrapped_record),
+ std::move(processed_cb)));
+ },
+ std::move(sequence_information), std::move(processed_cb),
+ base::SequencedTaskRunnerHandle::Get(), base::Unretained(this))))
+ ->Start();
+ }
+
+ void ProcessGap(SequenceInformation sequence_information,
+ uint64_t count,
+ base::OnceCallback<void(bool)> processed_cb) override {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(test_uploader_checker_);
+ // Verify generation match.
+ if (generation_id_.has_value() &&
+ generation_id_.value() != sequence_information.generation_id()) {
+ sequence_bound_upload_
+ .AsyncCall(&SequenceBoundUpload::DoUploadRecordFailure)
+ .WithArgs(uploader_id_, sequence_information.priority(),
+ sequence_information.sequencing_id(),
+ Status(error::DATA_LOSS,
+ base::StrCat(
+ {"Generation id mismatch, expected=",
+ base::NumberToString(generation_id_.value()),
+ " actual=",
+ base::NumberToString(
+ sequence_information.generation_id())})),
+ std::move(processed_cb));
+ return;
+ }
+ if (!generation_id_.has_value()) {
+ generation_id_ = sequence_information.generation_id();
+ }
+
+ last_record_digest_map_->emplace(
+ std::make_tuple(sequence_information.priority(),
+ sequence_information.sequencing_id(),
+ sequence_information.generation_id()),
+ absl::nullopt);
+
+ sequence_bound_upload_.AsyncCall(&SequenceBoundUpload::DoUploadGap)
+ .WithArgs(uploader_id_, sequence_information.priority(),
+ sequence_information.sequencing_id(), count,
+ std::move(processed_cb));
+ }
+
+ void Completed(Status status) override {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(test_uploader_checker_);
+ sequence_bound_upload_.AsyncCall(&SequenceBoundUpload::DoUploadComplete)
+ .WithArgs(uploader_id_, status);
}
+ private:
void VerifyRecord(SequenceInformation sequence_information,
WrappedRecord wrapped_record,
base::OnceCallback<void(bool)> processed_cb) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(test_uploader_checker_);
// Verify generation match.
if (generation_id_.has_value() &&
generation_id_.value() != sequence_information.generation_id()) {
- std::move(processed_cb)
- .Run(mock_upload_->DoUploadRecordFailure(
- uploader_id_, sequence_information.priority(),
- sequence_information.sequencing_id(),
- Status(error::DATA_LOSS,
- base::StrCat(
- {"Generation id mismatch, expected=",
- base::NumberToString(generation_id_.value()),
- " actual=",
- base::NumberToString(
- sequence_information.generation_id())}))));
+ sequence_bound_upload_
+ .AsyncCall(&SequenceBoundUpload::DoUploadRecordFailure)
+ .WithArgs(uploader_id_, sequence_information.priority(),
+ sequence_information.sequencing_id(),
+ Status(error::DATA_LOSS,
+ base::StrCat(
+ {"Generation id mismatch, expected=",
+ base::NumberToString(generation_id_.value()),
+ " actual=",
+ base::NumberToString(
+ sequence_information.generation_id())})),
+ std::move(processed_cb));
return;
}
if (!generation_id_.has_value()) {
@@ -671,11 +653,12 @@ class StorageTest
const auto record_digest = crypto::SHA256HashString(serialized_record);
DCHECK_EQ(record_digest.size(), crypto::kSHA256Length);
if (record_digest != wrapped_record.record_digest()) {
- std::move(processed_cb)
- .Run(mock_upload_->DoUploadRecordFailure(
- uploader_id_, sequence_information.priority(),
- sequence_information.sequencing_id(),
- Status(error::DATA_LOSS, "Record digest mismatch")));
+ sequence_bound_upload_
+ .AsyncCall(&SequenceBoundUpload::DoUploadRecordFailure)
+ .WithArgs(uploader_id_, sequence_information.priority(),
+ sequence_information.sequencing_id(),
+ Status(error::DATA_LOSS, "Record digest mismatch"),
+ std::move(processed_cb));
return;
}
if (wrapped_record.has_last_record_digest()) {
@@ -683,29 +666,16 @@ class StorageTest
std::make_tuple(sequence_information.priority(),
sequence_information.sequencing_id() - 1,
sequence_information.generation_id()));
- if (it == last_record_digest_map_->end()) {
- // Previous record has not been seen yet, reschedule. This can
- // happen because decryption is done asynchronously and only sets on
- // main_thread_task_runner_ after it. As a result, later record may
- // get decrypted early and be posted to main_thread_task_runner_ for
- // verification before its predecessor. Rescheduling will move it
- // back in the sequence. Rescheduling may happen multiple times, but
- // once the earlier record is decrypted, it will be also posted to
- // main_thread_task_runner_ and get its digest recorded, making it
- // ready for the current one. This is not an efficient method, but
- // is simple and good enough for the test.
- ScheduleVerifyRecord(std::move(sequence_information),
- std::move(wrapped_record),
- std::move(processed_cb));
- return;
- }
+ ASSERT_TRUE(it != last_record_digest_map_->end());
// Previous record has been seen, last record digest must match it.
if (it->second != wrapped_record.last_record_digest()) {
- std::move(processed_cb)
- .Run(mock_upload_->DoUploadRecordFailure(
+ sequence_bound_upload_
+ .AsyncCall(&SequenceBoundUpload::DoUploadRecordFailure)
+ .WithArgs(
uploader_id_, sequence_information.priority(),
sequence_information.sequencing_id(),
- Status(error::DATA_LOSS, "Last record digest mismatch")));
+ Status(error::DATA_LOSS, "Last record digest mismatch"),
+ std::move(processed_cb));
return;
}
}
@@ -716,14 +686,10 @@ class StorageTest
record_digest);
}
- mock_upload_->DoEncounterSeqId(uploader_id_,
- sequence_information.priority(),
- sequence_information.sequencing_id());
- std::move(processed_cb)
- .Run(mock_upload_->DoUploadRecord(
- uploader_id_, sequence_information.priority(),
- sequence_information.sequencing_id(),
- wrapped_record.record().data()));
+ sequence_bound_upload_.AsyncCall(&SequenceBoundUpload::DoUploadRecord)
+ .WithArgs(uploader_id_, sequence_information.priority(),
+ sequence_information.sequencing_id(),
+ wrapped_record.record().data(), std::move(processed_cb));
}
SEQUENCE_CHECKER(test_uploader_checker_);
@@ -737,12 +703,10 @@ class StorageTest
absl::optional<int64_t> generation_id_;
const raw_ptr<LastRecordDigestMap> last_record_digest_map_;
- // Single task runner where all EXPECTs will happen.
- const scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_;
+ const raw_ptr<const MockUpload> mock_upload_;
- scoped_refptr<::testing::NiceMock<MockUpload>> mock_upload_;
+ base::SequenceBound<SequenceBoundUpload> sequence_bound_upload_;
- base::OnceClosure key_generation_;
const scoped_refptr<test::Decryptor> decryptor_;
Sequence test_encounter_sequence_;
@@ -817,8 +781,7 @@ class StorageTest
}
StorageOptions BuildTestStorageOptions() const {
- auto options = StorageOptions()
- .set_directory(base::FilePath(location_.GetPath()));
+ auto options = StorageOptions().set_directory(location_.GetPath());
if (is_encryption_enabled()) {
// Encryption enabled.
options.set_signature_verification_public_key(std::string(
@@ -937,6 +900,12 @@ class StorageTest
return signed_encryption_key;
}
+ void DeliverKey() const {
+ ASSERT_TRUE(is_encryption_enabled())
+ << "Key can be delivered only when encryption is enabled";
+ storage_->UpdateEncryptionKey(signed_encryption_key_);
+ }
+
bool is_encryption_enabled() const { return ::testing::get<0>(GetParam()); }
size_t single_file_size_limit() const {
return ::testing::get<1>(GetParam());
@@ -965,6 +934,8 @@ class StorageTest
// digest. Serves all TestUploaders created by test fixture.
TestUploader::LastRecordDigestMap last_record_digest_map_;
+ const ::testing::NiceMock<const MockUpload> mock_upload_;
+
::testing::MockFunction<StatusOr<std::unique_ptr<TestUploader>>(
UploaderInterface::UploadReason /*reason*/)>
set_mock_uploader_expectations_;
@@ -1039,16 +1010,6 @@ TEST_P(StorageTest, WriteIntoNewStorageAndUploadWithKeyUpdate) {
{
test::TestCallbackAutoWaiter waiter;
EXPECT_CALL(set_mock_uploader_expectations_,
- Call(Eq(UploaderInterface::UploadReason::KEY_DELIVERY)))
- // Called once with empty queue.
- .WillOnce(Invoke([this](UploaderInterface::UploadReason reason) {
- return TestUploader::SetEmpty(this).Complete();
- }))
- // Can be called later again, reject it.
- .WillRepeatedly(Invoke([](UploaderInterface::UploadReason reason) {
- return Status(error::CANCELLED, "Repeated key delivery rejected");
- }));
- EXPECT_CALL(set_mock_uploader_expectations_,
Call(Eq(UploaderInterface::UploadReason::MANUAL)))
.WillOnce(
Invoke([&waiter, this](UploaderInterface::UploadReason reason) {
@@ -1072,7 +1033,7 @@ TEST_P(StorageTest, WriteIntoNewStorageAndUploadWithKeyUpdate) {
WriteStringOrDie(MANUAL_BATCH, kMoreData[1]);
WriteStringOrDie(MANUAL_BATCH, kMoreData[2]);
- // Wait to trigger encryption key request on the next upload
+ // Wait to trigger encryption key request on the next upload.
task_environment_.FastForwardBy(kKeyRenewalTime + base::Seconds(1));
// Set uploader expectations with encryption key request.
diff --git a/chromium/components/reporting/util/BUILD.gn b/chromium/components/reporting/util/BUILD.gn
index a5cacd7059c..8aa7fe30758 100644
--- a/chromium/components/reporting/util/BUILD.gn
+++ b/chromium/components/reporting/util/BUILD.gn
@@ -15,6 +15,14 @@ static_library("backoff_settings") {
deps = [ "//net" ]
}
+static_library("file") {
+ sources = [
+ "file.cc",
+ "file.h",
+ ]
+ deps = [ "//base" ]
+}
+
source_set("shared_vector") {
sources = [ "shared_vector.h" ]
deps = [
@@ -68,11 +76,25 @@ source_set("test_callbacks_support") {
deps = [ "//base" ]
}
+source_set("disconnectable_client") {
+ sources = [
+ "disconnectable_client.cc",
+ "disconnectable_client.h",
+ ]
+
+ deps = [
+ ":status",
+ "//base",
+ ]
+}
+
# All unit tests are built as part of the //components:components_unittests
# target.
source_set("unit_tests") {
testonly = true
sources = [
+ "disconnectable_client_unittest.cc",
+ "file_unittest.cc",
"shared_queue_unittest.cc",
"shared_vector_unittest.cc",
"status_macros_unittest.cc",
@@ -80,6 +102,8 @@ source_set("unit_tests") {
"statusor_unittest.cc",
]
deps = [
+ ":disconnectable_client",
+ ":file",
":shared_queue",
":shared_vector",
":status",
diff --git a/chromium/components/reporting/util/disconnectable_client.cc b/chromium/components/reporting/util/disconnectable_client.cc
new file mode 100644
index 00000000000..091fe834366
--- /dev/null
+++ b/chromium/components/reporting/util/disconnectable_client.cc
@@ -0,0 +1,77 @@
+// Copyright 2022 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.
+
+#include "components/reporting/util/disconnectable_client.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/callback.h"
+#include "base/containers/fixed_flat_map.h"
+#include "base/logging.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/rand_util.h"
+#include "base/sequence_checker.h"
+#include "base/task/sequenced_task_runner.h"
+#include "components/reporting/util/status.h"
+
+namespace reporting {
+
+DisconnectableClient::DisconnectableClient(
+ scoped_refptr<base::SequencedTaskRunner> task_runner)
+ : task_runner_(task_runner) {}
+
+DisconnectableClient::~DisconnectableClient() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ SetAvailability(/*is_available=*/false);
+}
+
+void DisconnectableClient::MaybeMakeCall(std::unique_ptr<Delegate> delegate) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ // Bail out, if missive daemon is not available over dBus.
+ if (!is_available_) {
+ delegate->Respond(
+ Status(reporting::error::UNAVAILABLE, "Service is unavailable"));
+ return;
+ }
+ // Add the delegate to the map.
+ const auto id = base::RandUint64();
+ auto res = outstanding_delegates_.emplace(id, std::move(delegate));
+ DCHECK(res.second) << "Duplicate call id " << id;
+ // Make a call, resume on CallResponded, when response is received.
+ res.first->second->DoCall(base::BindOnce(&DisconnectableClient::CallResponded,
+ weak_ptr_factory_.GetWeakPtr(), id));
+}
+
+void DisconnectableClient::CallResponded(uint64_t id) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ auto it = outstanding_delegates_.find(id);
+ if (it == outstanding_delegates_.end()) {
+ // Callback has already been removed, no action needed.
+ return;
+ }
+ // Respond through the |delegate|.
+ auto delegate = std::move(it->second);
+ outstanding_delegates_.erase(it);
+ // Respond.
+ delegate->Respond(Status::StatusOK());
+}
+
+void DisconnectableClient::SetAvailability(bool is_available) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ is_available_ = is_available;
+ LOG(WARNING) << "Service became " << (is_available_ ? "" : "un")
+ << "available";
+ if (!is_available_) {
+ // Cancel all pending calls.
+ for (auto& p : outstanding_delegates_) {
+ std::move(p.second)->Respond(
+ Status(reporting::error::UNAVAILABLE, "Service is unavailable"));
+ }
+ outstanding_delegates_.clear();
+ }
+}
+
+} // namespace reporting
diff --git a/chromium/components/reporting/util/disconnectable_client.h b/chromium/components/reporting/util/disconnectable_client.h
new file mode 100644
index 00000000000..eb3af246885
--- /dev/null
+++ b/chromium/components/reporting/util/disconnectable_client.h
@@ -0,0 +1,73 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_REPORTING_UTIL_DISCONNECTABLE_CLIENT_H_
+#define COMPONENTS_REPORTING_UTIL_DISCONNECTABLE_CLIENT_H_
+
+#include <memory>
+
+#include "base/callback.h"
+#include "base/containers/fixed_flat_map.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/sequence_checker.h"
+#include "base/task/sequenced_task_runner.h"
+#include "base/thread_annotations.h"
+#include "components/reporting/util/status.h"
+
+namespace reporting {
+
+// Client connection class that handles possible disconnections.
+// When the service is not available, calls are immediately responded with
+// failure, including those started beforewhen the connection was available.
+class DisconnectableClient {
+ public:
+ // Interface to actual connection call.
+ class Delegate {
+ public:
+ virtual ~Delegate() = default;
+
+ // Makes actual call to the service.
+ virtual void DoCall(base::OnceClosure cb) = 0;
+ // Processes response received from the service (OK is successful).
+ virtual void Respond(Status status) = 0;
+ };
+
+ explicit DisconnectableClient(
+ scoped_refptr<base::SequencedTaskRunner> task_runner);
+ DisconnectableClient(const DisconnectableClient& other) = delete;
+ DisconnectableClient& operator=(const DisconnectableClient& other) = delete;
+ ~DisconnectableClient();
+
+ // Makes a call. Must be executed on task_runner_.
+ void MaybeMakeCall(std::unique_ptr<Delegate> delegate);
+
+ // Sets availability flag of the service.
+ void SetAvailability(bool is_available);
+
+ // Returns sequenced task runner for all operations.
+ scoped_refptr<base::SequencedTaskRunner> task_runner() const;
+
+ private:
+ void CallResponded(uint64_t id);
+
+ // Sequenced task runner - must be first member of the class.
+ const scoped_refptr<base::SequencedTaskRunner> task_runner_;
+ SEQUENCE_CHECKER(sequence_checker_);
+
+ // Availability flag.
+ bool is_available_ GUARDED_BY_CONTEXT(sequence_checker_){false};
+
+ // Map of delegates indexed by unique ids (all delegates will fail with error
+ // Status if service disconnects).
+ base::flat_map<uint64_t, std::unique_ptr<Delegate>> outstanding_delegates_
+ GUARDED_BY_CONTEXT(sequence_checker_);
+
+ // Weak pointer factory - must be last member of the class.
+ base::WeakPtrFactory<DisconnectableClient> weak_ptr_factory_{this};
+};
+
+} // namespace reporting
+
+#endif // COMPONENTS_REPORTING_UTIL_DISCONNECTABLE_CLIENT_H_
diff --git a/chromium/components/reporting/util/disconnectable_client_unittest.cc b/chromium/components/reporting/util/disconnectable_client_unittest.cc
new file mode 100644
index 00000000000..36f653a7397
--- /dev/null
+++ b/chromium/components/reporting/util/disconnectable_client_unittest.cc
@@ -0,0 +1,249 @@
+// Copyright 2022 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.
+
+#include "components/reporting/util/disconnectable_client.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/test/task_environment.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "base/time/time.h"
+#include "components/reporting/util/status.h"
+#include "components/reporting/util/statusor.h"
+#include "components/reporting/util/test_support_callbacks.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::Eq;
+
+namespace reporting {
+
+class MockDelegate : public DisconnectableClient::Delegate {
+ public:
+ MockDelegate(int64_t input,
+ base::TimeDelta delay,
+ base::OnceCallback<void(StatusOr<int64_t>)> completion_cb)
+ : input_(input),
+ delay_(delay),
+ completion_cb_(std::move(completion_cb)) {}
+ MockDelegate(const MockDelegate& other) = delete;
+ MockDelegate& operator=(const MockDelegate& other) = delete;
+ ~MockDelegate() override = default;
+
+ void DoCall(base::OnceClosure cb) override {
+ base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, std::move(cb), delay_);
+ }
+
+ void Respond(Status status) override {
+ DCHECK(completion_cb_);
+ if (!status.ok()) {
+ std::move(completion_cb_).Run(status);
+ return;
+ }
+ std::move(completion_cb_).Run(input_ * 2);
+ }
+
+ private:
+ const int64_t input_;
+ const base::TimeDelta delay_;
+ base::OnceCallback<void(StatusOr<int64_t>)> completion_cb_;
+};
+
+class FailDelegate : public DisconnectableClient::Delegate {
+ public:
+ FailDelegate(base::TimeDelta delay,
+ base::OnceCallback<void(StatusOr<int64_t>)> completion_cb)
+ : delay_(delay), completion_cb_(std::move(completion_cb)) {}
+ FailDelegate(const FailDelegate& other) = delete;
+ FailDelegate& operator=(const FailDelegate& other) = delete;
+ ~FailDelegate() override = default;
+
+ void DoCall(base::OnceClosure cb) override {
+ base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, std::move(cb), delay_);
+ }
+
+ void Respond(Status status) override {
+ DCHECK(completion_cb_);
+ if (!status.ok()) {
+ std::move(completion_cb_).Run(status);
+ return;
+ }
+ std::move(completion_cb_).Run(Status(error::CANCELLED, "Failed in test"));
+ }
+
+ private:
+ const base::TimeDelta delay_;
+ base::OnceCallback<void(StatusOr<int64_t>)> completion_cb_;
+};
+
+class DisconnectableClientTest : public ::testing::Test {
+ protected:
+ base::test::TaskEnvironment task_environment_{
+ base::test::TaskEnvironment::TimeSource::MOCK_TIME};
+
+ DisconnectableClient client_{base::SequencedTaskRunnerHandle::Get()};
+};
+
+TEST_F(DisconnectableClientTest, NormalConnection) {
+ client_.SetAvailability(/*is_available=*/true);
+
+ test::TestEvent<StatusOr<int64_t>> res1;
+ test::TestEvent<StatusOr<int64_t>> res2;
+ client_.MaybeMakeCall(
+ std::make_unique<MockDelegate>(111, base::TimeDelta(), res1.cb()));
+ client_.MaybeMakeCall(
+ std::make_unique<MockDelegate>(222, base::TimeDelta(), res2.cb()));
+
+ auto result = res1.result();
+ ASSERT_OK(result) << result.status();
+ EXPECT_THAT(result.ValueOrDie(), Eq(222));
+ result = res2.result();
+ ASSERT_OK(result) << result.status();
+ EXPECT_THAT(result.ValueOrDie(), Eq(444));
+}
+
+TEST_F(DisconnectableClientTest, NoConnection) {
+ test::TestEvent<StatusOr<int64_t>> res;
+ client_.MaybeMakeCall(
+ std::make_unique<MockDelegate>(111, base::TimeDelta(), res.cb()));
+
+ auto result = res.result();
+ ASSERT_FALSE(result.ok());
+ ASSERT_THAT(result.status().error_code(), Eq(error::UNAVAILABLE))
+ << result.status();
+}
+
+TEST_F(DisconnectableClientTest, FailedCallOnNormalConnection) {
+ client_.SetAvailability(/*is_available=*/true);
+
+ test::TestEvent<StatusOr<int64_t>> res1;
+ test::TestEvent<StatusOr<int64_t>> res2;
+ test::TestEvent<StatusOr<int64_t>> res3;
+ client_.MaybeMakeCall(
+ std::make_unique<MockDelegate>(111, base::Seconds(1), res1.cb()));
+ client_.MaybeMakeCall(
+ std::make_unique<FailDelegate>(base::Seconds(2), res2.cb()));
+ client_.MaybeMakeCall(
+ std::make_unique<MockDelegate>(222, base::Seconds(3), res3.cb()));
+
+ task_environment_.FastForwardBy(base::Seconds(1));
+
+ auto result = res1.result();
+ ASSERT_OK(result) << result.status();
+ EXPECT_THAT(result.ValueOrDie(), Eq(222));
+
+ task_environment_.FastForwardBy(base::Seconds(1));
+
+ result = res2.result();
+ ASSERT_FALSE(result.ok());
+ ASSERT_THAT(result.status().error_code(), Eq(error::CANCELLED))
+ << result.status();
+
+ task_environment_.FastForwardBy(base::Seconds(1));
+
+ result = res3.result();
+ ASSERT_OK(result) << result.status();
+ EXPECT_THAT(result.ValueOrDie(), Eq(444));
+}
+
+TEST_F(DisconnectableClientTest, DroppedConnection) {
+ client_.SetAvailability(/*is_available=*/true);
+
+ test::TestEvent<StatusOr<int64_t>> res1;
+ test::TestEvent<StatusOr<int64_t>> res2;
+ client_.MaybeMakeCall(
+ std::make_unique<MockDelegate>(111, base::Seconds(1), res1.cb()));
+ client_.MaybeMakeCall(
+ std::make_unique<MockDelegate>(222, base::Seconds(2), res2.cb()));
+
+ task_environment_.FastForwardBy(base::Seconds(1));
+
+ auto result = res1.result();
+ ASSERT_OK(result) << result.status();
+ EXPECT_THAT(result.ValueOrDie(), Eq(222));
+
+ client_.SetAvailability(/*is_available=*/false);
+
+ result = res2.result();
+ ASSERT_FALSE(result.ok());
+ ASSERT_THAT(result.status().error_code(), Eq(error::UNAVAILABLE))
+ << result.status();
+}
+
+TEST_F(DisconnectableClientTest, FailedCallOnDroppedConnection) {
+ client_.SetAvailability(/*is_available=*/true);
+
+ test::TestEvent<StatusOr<int64_t>> res1;
+ test::TestEvent<StatusOr<int64_t>> res2;
+ test::TestEvent<StatusOr<int64_t>> res3;
+ client_.MaybeMakeCall(
+ std::make_unique<MockDelegate>(111, base::Seconds(1), res1.cb()));
+ client_.MaybeMakeCall(
+ std::make_unique<FailDelegate>(base::Seconds(2), res2.cb()));
+ client_.MaybeMakeCall(
+ std::make_unique<MockDelegate>(222, base::Seconds(3), res3.cb()));
+
+ task_environment_.FastForwardBy(base::Seconds(1));
+
+ auto result = res1.result();
+ ASSERT_OK(result) << result.status();
+ EXPECT_THAT(result.ValueOrDie(), Eq(222));
+
+ client_.SetAvailability(/*is_available=*/false);
+
+ task_environment_.FastForwardBy(base::Seconds(1));
+
+ result = res2.result();
+ ASSERT_FALSE(result.ok());
+ ASSERT_THAT(result.status().error_code(), Eq(error::UNAVAILABLE))
+ << result.status();
+
+ result = res3.result();
+ ASSERT_FALSE(result.ok());
+ ASSERT_THAT(result.status().error_code(), Eq(error::UNAVAILABLE))
+ << result.status();
+}
+
+TEST_F(DisconnectableClientTest, ConnectionDroppedThenRestored) {
+ client_.SetAvailability(/*is_available=*/true);
+
+ test::TestEvent<StatusOr<int64_t>> res1;
+ test::TestEvent<StatusOr<int64_t>> res2;
+ test::TestEvent<StatusOr<int64_t>> res3;
+ client_.MaybeMakeCall(
+ std::make_unique<MockDelegate>(111, base::Seconds(1), res1.cb()));
+ client_.MaybeMakeCall(
+ std::make_unique<MockDelegate>(222, base::Seconds(2), res2.cb()));
+
+ task_environment_.FastForwardBy(base::Seconds(1));
+
+ auto result = res1.result();
+ ASSERT_OK(result) << result.status();
+ EXPECT_THAT(result.ValueOrDie(), Eq(222));
+
+ client_.SetAvailability(/*is_available=*/false);
+
+ task_environment_.FastForwardBy(base::Seconds(1));
+
+ result = res2.result();
+ ASSERT_FALSE(result.ok());
+ ASSERT_THAT(result.status().error_code(), Eq(error::UNAVAILABLE))
+ << result.status();
+
+ client_.SetAvailability(/*is_available=*/true);
+
+ client_.MaybeMakeCall(
+ std::make_unique<MockDelegate>(333, base::Seconds(1), res3.cb()));
+
+ task_environment_.FastForwardBy(base::Seconds(1));
+
+ result = res3.result();
+ ASSERT_OK(result) << result.status();
+ EXPECT_THAT(result.ValueOrDie(), Eq(666));
+}
+
+} // namespace reporting
diff --git a/chromium/components/reporting/util/file.cc b/chromium/components/reporting/util/file.cc
new file mode 100644
index 00000000000..3243c280450
--- /dev/null
+++ b/chromium/components/reporting/util/file.cc
@@ -0,0 +1,43 @@
+// Copyright 2022 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.
+
+#include "components/reporting/util/file.h"
+
+#include <utility>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/files/file_enumerator.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+
+namespace reporting {
+
+bool DeleteFileWarnIfFailed(const base::FilePath& path) {
+ const auto delete_result = base::DeleteFile(path);
+ if (!delete_result) {
+ LOG(WARNING) << "Failed to delete " << path.MaybeAsASCII();
+ }
+ return delete_result;
+}
+
+bool DeleteFilesWarnIfFailed(
+ base::FileEnumerator& dir_enum,
+ base::RepeatingCallback<bool(const base::FilePath&)> pred) {
+ std::vector<base::FilePath> files_to_delete;
+ for (auto full_name = dir_enum.Next(); !full_name.empty();
+ full_name = dir_enum.Next()) {
+ if (pred.Run(full_name)) {
+ files_to_delete.push_back(std::move(full_name));
+ }
+ }
+ bool success = true;
+ for (const auto& file_to_delete : files_to_delete) {
+ if (!DeleteFileWarnIfFailed(file_to_delete)) {
+ success = false;
+ }
+ }
+ return success;
+}
+} // namespace reporting
diff --git a/chromium/components/reporting/util/file.h b/chromium/components/reporting/util/file.h
new file mode 100644
index 00000000000..02c213e26cc
--- /dev/null
+++ b/chromium/components/reporting/util/file.h
@@ -0,0 +1,34 @@
+// Copyright 2022 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.
+
+// Utilities for file operations.
+
+#ifndef COMPONENTS_REPORTING_UTIL_FILE_H_
+#define COMPONENTS_REPORTING_UTIL_FILE_H_
+
+#include "base/callback.h"
+#include "base/files/file_enumerator.h"
+#include "base/files/file_util.h"
+
+namespace reporting {
+
+// Deletes the given path, whether it's a file or a directory.
+// This function is identical to base::DeleteFile() except that it issues a
+// warning if the deletion fails. Useful when we do not care about whether the
+// deletion succeeds or not.
+bool DeleteFileWarnIfFailed(const base::FilePath& path);
+
+// Enumerates over |dir_enum|, and deletes the file if pred.Run(file) returns
+// true. If |pred| is unspecified, all files enumerated are deleted. It deletes
+// each individual file with DeleteFileWarnIfFailed(). Refer to
+// DeleteFileWarnIfFailed() for the effect of the deletion.
+// Returns true if all files are deleted successfully, otherwise returns false.
+bool DeleteFilesWarnIfFailed(
+ base::FileEnumerator& dir_enum,
+ base::RepeatingCallback<bool(const base::FilePath&)> pred =
+ base::BindRepeating([](const base::FilePath&) { return true; }));
+
+} // namespace reporting
+
+#endif // COMPONENTS_REPORTING_UTIL_FILE_H_
diff --git a/chromium/components/reporting/util/file_unittest.cc b/chromium/components/reporting/util/file_unittest.cc
new file mode 100644
index 00000000000..b896967a448
--- /dev/null
+++ b/chromium/components/reporting/util/file_unittest.cc
@@ -0,0 +1,88 @@
+// Copyright 2022 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.
+
+#include "components/reporting/util/file.h"
+
+#include "base/files/file.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/test/test_file_util.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace reporting {
+namespace {
+
+TEST(FileTest, DeleteFileWarnIfFailed) {
+ // This test briefly tests DeleteFileWarnIfFailed, as it mostly calls
+ // DeleteFile(), which should be more extensively tested in base.
+ base::ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ const auto dir_path = temp_dir.GetPath();
+ ASSERT_TRUE(base::DirectoryExists(dir_path));
+
+ base::FilePath file_path;
+ ASSERT_TRUE(base::CreateTemporaryFileInDir(dir_path, &file_path));
+
+ // Delete an existing file with no permission.
+ // Don't test on Fuchsia: No file permission support. See
+ // base/files/file_util_unittest.cc for some similar tests being skipped.
+#if !BUILDFLAG(IS_FUCHSIA)
+ {
+ // On Windows, we open the file to prevent it from being deleted. Otherwise,
+ // we modify the directory permission to prevent it from being deleted.
+#if BUILDFLAG(IS_WIN)
+ base::File file(file_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
+ ASSERT_TRUE(file.IsValid());
+#else // BUILDFLAG(IS_WIN)
+ base::FilePermissionRestorer restore_permissions_for(dir_path);
+ // Get rid of the write permission from temp_dir
+ ASSERT_TRUE(base::MakeFileUnwritable(dir_path));
+ // Ensure no deletion permission
+ ASSERT_FALSE(base::PathIsWritable(dir_path));
+#endif // BUILDFLAG(IS_WIN)
+ ASSERT_TRUE(base::PathExists(file_path));
+ ASSERT_FALSE(DeleteFileWarnIfFailed(file_path))
+ << "Deletion of an existing file without permission should fail";
+ }
+#endif // !BUILDFLAG(IS_FUCHSIA)
+
+ {
+ // Delete with permission
+ ASSERT_TRUE(base::PathIsWritable(dir_path)); // Ensure deletion permission
+ ASSERT_TRUE(base::PathExists(file_path));
+ ASSERT_TRUE(DeleteFileWarnIfFailed(file_path))
+ << "Deletion of an existing file should succeed";
+ ASSERT_FALSE(base::PathExists(file_path)) << "File failed to be deleted";
+ }
+
+ // Delete a non-existing file
+ {
+ ASSERT_FALSE(base::PathExists(file_path));
+ ASSERT_TRUE(DeleteFileWarnIfFailed(file_path))
+ << "Deletion of a nonexisting file should succeed";
+ }
+}
+
+TEST(FileTest, DeleteFilesWarnIfFailed) {
+ base::ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ const auto dir_path = temp_dir.GetPath();
+ ASSERT_TRUE(base::DirectoryExists(dir_path));
+
+ base::FilePath file_path;
+ ASSERT_TRUE(base::CreateTemporaryFileInDir(dir_path, &file_path));
+
+ // empty the directory
+ base::FileEnumerator dir_enum(dir_path, /*recursive=*/false,
+ base::FileEnumerator::FILES,
+ FILE_PATH_LITERAL("*"));
+ ASSERT_TRUE(DeleteFilesWarnIfFailed(dir_enum))
+ << "Failed to delete " << file_path.MaybeAsASCII();
+ ASSERT_FALSE(base::PathExists(file_path))
+ << "Deletion succeeds but " << file_path.MaybeAsASCII()
+ << " still exists.";
+}
+
+} // namespace
+} // namespace reporting
diff --git a/chromium/components/reporting/util/status.h b/chromium/components/reporting/util/status.h
index d432941d1b5..30b182f5354 100644
--- a/chromium/components/reporting/util/status.h
+++ b/chromium/components/reporting/util/status.h
@@ -9,7 +9,6 @@
#include <iosfwd>
#include <string>
-#include "base/compiler_specific.h"
#include "base/strings/string_piece.h"
#include "components/reporting/util/status.pb.h"
@@ -44,7 +43,7 @@ enum Code : int32_t {
};
} // namespace error
-class WARN_UNUSED_RESULT Status {
+class Status {
public:
// Creates a "successful" status.
Status();
diff --git a/chromium/components/reporting/util/statusor.h b/chromium/components/reporting/util/statusor.h
index 2c0806178fc..10035061b74 100644
--- a/chromium/components/reporting/util/statusor.h
+++ b/chromium/components/reporting/util/statusor.h
@@ -60,7 +60,6 @@
#include <type_traits>
#include <utility>
-#include "base/compiler_specific.h"
#include "base/logging.h"
#include "base/memory/raw_ptr.h"
#include "components/reporting/util/status.h"
@@ -81,7 +80,7 @@ class StatusOrHelper {
} // namespace internal
template <typename T>
-class WARN_UNUSED_RESULT StatusOr {
+class StatusOr {
template <typename U>
friend class StatusOr;
@@ -216,7 +215,7 @@ class WARN_UNUSED_RESULT StatusOr {
//
// This method should only be called if this StatusOr object's status is OK
// (i.e. a call to ok() returns true), otherwise this call will abort.
- const T& WARN_UNUSED_RESULT ValueOrDie() const& {
+ [[nodiscard]] const T& ValueOrDie() const& {
if (!ok()) {
internal::StatusOrHelper::Crash(status_);
}
@@ -227,7 +226,7 @@ class WARN_UNUSED_RESULT StatusOr {
//
// This method should only be called if this StatusOr object's status is OK
// (i.e. a call to ok() returns true), otherwise this call will abort.
- T& WARN_UNUSED_RESULT ValueOrDie() & {
+ [[nodiscard]] T& ValueOrDie() & {
if (!ok()) {
internal::StatusOrHelper::Crash(status_);
}
@@ -240,7 +239,7 @@ class WARN_UNUSED_RESULT StatusOr {
// (i.e. a call to ok() returns true), otherwise this call will abort. The
// StatusOr object is invalidated after this call and will be updated to
// contain a non-OK status with a |error::UNKNOWN| error code.
- T WARN_UNUSED_RESULT ValueOrDie() && {
+ [[nodiscard]] T ValueOrDie() && {
if (!ok()) {
internal::StatusOrHelper::Crash(status_);
}
diff --git a/chromium/components/reputation/core/safety_tip_test_utils.cc b/chromium/components/reputation/core/safety_tip_test_utils.cc
index 1b45d901a85..bf2983dfc15 100644
--- a/chromium/components/reputation/core/safety_tip_test_utils.cc
+++ b/chromium/components/reputation/core/safety_tip_test_utils.cc
@@ -82,4 +82,15 @@ void InitializeBlankLookalikeAllowlistForTesting() {
SetSafetyTipAllowlistPatterns({}, {}, {});
}
+void AddSafetyTipHeuristicLaunchConfigForTesting(
+ reputation::HeuristicLaunchConfig::Heuristic heuristic,
+ int launch_percentage) {
+ auto config_proto = GetConfig();
+ reputation::HeuristicLaunchConfig* launch_config =
+ config_proto->add_launch_config();
+ launch_config->set_heuristic(heuristic);
+ launch_config->set_launch_percentage(launch_percentage);
+ SetSafetyTipsRemoteConfigProto(std::move(config_proto));
+}
+
} // namespace reputation
diff --git a/chromium/components/reputation/core/safety_tip_test_utils.h b/chromium/components/reputation/core/safety_tip_test_utils.h
index 58b8065aec4..30e1e202932 100644
--- a/chromium/components/reputation/core/safety_tip_test_utils.h
+++ b/chromium/components/reputation/core/safety_tip_test_utils.h
@@ -34,6 +34,12 @@ void SetSafetyTipAllowlistPatterns(std::vector<std::string> patterns,
std::vector<std::string> target_patterns,
std::vector<std::string> common_words);
+// Adds a launch config for the given heuristic with the given percentage. See
+// the proto definition for the meaning of various launch percentage values.
+void AddSafetyTipHeuristicLaunchConfigForTesting(
+ reputation::HeuristicLaunchConfig::Heuristic heuristic,
+ int launch_percentage);
+
// Ensure that the allowlist has been initialized. This is important as some
// code (e.g. the elision policy) is fail-open (i.e. it won't elide without an
// initialized allowlist). This is convenience wrapper around
diff --git a/chromium/components/reputation/core/safety_tips.proto b/chromium/components/reputation/core/safety_tips.proto
index 44b5b5204d7..0c771a466c3 100644
--- a/chromium/components/reputation/core/safety_tips.proto
+++ b/chromium/components/reputation/core/safety_tips.proto
@@ -34,6 +34,35 @@ message HostPattern {
optional string regex = 1;
}
+message HeuristicLaunchConfig {
+ // The heuristic to be launched with a warning UI.
+ // Important: Changes to heuristics MUST be added as a NEW heuristic (e.g.
+ // by adding a new enum value with "_V2" at the end).
+ // Otherwise, rolling out the new version will also enable the buggy version
+ // of the heuristic on older versions of Chrome.
+ //
+ // The values in this enum are intended to be temporary and used only for
+ // new heuristic launches. Do not reuse this enum for any other purpose,
+ // use the existing LookalikeHeuristic enum in this file.
+ enum Heuristic {
+ HEURISTIC_UNKNOWN = 0;
+ HEURISTIC_CHARACTER_SWAP_ENGAGED_SITES = 1;
+ HEURISTIC_CHARACTER_SWAP_TOP_SITES = 2;
+ }
+ optional Heuristic heuristic = 1;
+
+ // Percentage of all sites this heuristic should be enabled on the Stable
+ // Channel. The determination of which sites are enabled is based on hash
+ // prefixes of the sites.
+ // A value of 0 means the heuristic isn't enabled on any site on Stable.
+ // A value of 100 means the heuristic is enabled on all sites on Stable.
+ //
+ // If a launch config is found for a heuristic, the heuristic is enabled for
+ // 90% of sites on Canary/Dev and 50% on Beta, regardless of the value of this
+ // field.
+ optional uint32 launch_percentage = 2;
+}
+
// Configuration for the safety tips component. A binary version of this proto
// will be distributed to Chrome clients via component updater. The binary will
// contain a single instance of this message.
@@ -70,4 +99,8 @@ message SafetyTipsConfig {
// components/url_formatter/spoof_checks/common_words. The combined list is
// used in some lookalike heuristics to prevent common false positives.
repeated string common_word = 5;
+
+ // Launch configurations for new heuristics. Each new heuristic being launched
+ // gets its own config. Multiple heuristics can be enabled at the same time.
+ repeated HeuristicLaunchConfig launch_config = 6;
}
diff --git a/chromium/components/resources/about_ui_resources.grdp b/chromium/components/resources/about_ui_resources.grdp
index 236e09f2e51..cd38bcc6e68 100644
--- a/chromium/components/resources/about_ui_resources.grdp
+++ b/chromium/components/resources/about_ui_resources.grdp
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<grit-part>
+ <include name="IDR_ABOUT_UI_CREDITS_CSS" file="../about_ui/resources/about_credits.css" preprocess="true" type="BINDATA" compress="brotli" />
<include name="IDR_ABOUT_UI_CREDITS_HTML" file="${about_credits_file}" compress="brotli" use_base_dir="false" type="BINDATA" />
<include name="IDR_ABOUT_UI_CREDITS_JS" file="../about_ui/resources/about_credits.js" preprocess="true" type="BINDATA" compress="brotli" />
</grit-part>
diff --git a/chromium/components/resources/autofill_and_password_manager_internals_resources.grdp b/chromium/components/resources/autofill_and_password_manager_internals_resources.grdp
index 04be13c9e83..a1941782deb 100644
--- a/chromium/components/resources/autofill_and_password_manager_internals_resources.grdp
+++ b/chromium/components/resources/autofill_and_password_manager_internals_resources.grdp
@@ -1,11 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<grit-part>
- <if expr="not is_ios">
- <include name="IDR_AUTOFILL_AND_PASSWORD_MANAGER_INTERNALS_HTML" file="../autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.html" type="BINDATA" />
- </if>
- <if expr="is_ios">
- <include name="IDR_AUTOFILL_AND_PASSWORD_MANAGER_INTERNALS_HTML" file="../autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals_ios.html" type="BINDATA" />
- </if>
+ <include name="IDR_AUTOFILL_AND_PASSWORD_MANAGER_INTERNALS_HTML" file="../autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.html" type="BINDATA" />
<include name="IDR_AUTOFILL_AND_PASSWORD_MANAGER_INTERNALS_JS" file="../autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.js" preprocess="true" type="BINDATA" />
- <include name="IDR_AUTOFILL_AND_PASSWORD_MANAGER_INTERNALS_CSS" file="../autofill/core/browser/autofill_and_password_manager_internals/autofill_and_password_manager_internals.css" type="BINDATA" />
</grit-part>
diff --git a/chromium/components/resources/autofill_scaled_resources.grdp b/chromium/components/resources/autofill_scaled_resources.grdp
index ea4f82e860f..7706b257433 100644
--- a/chromium/components/resources/autofill_scaled_resources.grdp
+++ b/chromium/components/resources/autofill_scaled_resources.grdp
@@ -11,6 +11,8 @@
<structure type="chrome_scaled_image" name="IDR_AUTOFILL_CC_UNIONPAY" file="autofill/unionpay.png" />
<structure type="chrome_scaled_image" name="IDR_AUTOFILL_CC_VISA" file="autofill/visa.png" />
<structure type="chrome_scaled_image" name="IDR_AUTOFILL_CC_TROY" file="autofill/troy.png" />
+ <structure type="chrome_scaled_image" name="IDR_AUTOFILL_VIRTUAL_CARD_ENROLL_DIALOG" file="autofill/virtual_card_enroll.png" />
+ <structure type="chrome_scaled_image" name="IDR_AUTOFILL_VIRTUAL_CARD_ENROLL_DIALOG_DARK" file="autofill/virtual_card_enroll_dark.png" />
<if expr="_google_chrome">
<then>
<structure type="chrome_scaled_image" name="IDR_AUTOFILL_GOOGLE_ISSUED_CARD" file="google_chrome/autofill/googlepay_plex.png" />
diff --git a/chromium/components/resources/components_resources.grd b/chromium/components/resources/components_resources.grd
index be607c11752..60f6613c51a 100644
--- a/chromium/components/resources/components_resources.grd
+++ b/chromium/components/resources/components_resources.grd
@@ -26,6 +26,7 @@ dev_ui_components_resources.grd.
<part file="security_interstitials_resources.grdp" />
<part file="translate_resources.grdp" />
<part file="version_ui_resources.grdp" />
+ <part file="web_app_default_offline.grdp" />
<if expr="is_android">
<part file="android_system_error_page_resources.grdp" />
diff --git a/chromium/components/resources/default_100_percent/autofill/virtual_card_enroll.png b/chromium/components/resources/default_100_percent/autofill/virtual_card_enroll.png
new file mode 100644
index 00000000000..660bb83abf9
--- /dev/null
+++ b/chromium/components/resources/default_100_percent/autofill/virtual_card_enroll.png
Binary files differ
diff --git a/chromium/components/resources/default_100_percent/autofill/virtual_card_enroll_dark.png b/chromium/components/resources/default_100_percent/autofill/virtual_card_enroll_dark.png
new file mode 100644
index 00000000000..ad82791446c
--- /dev/null
+++ b/chromium/components/resources/default_100_percent/autofill/virtual_card_enroll_dark.png
Binary files differ
diff --git a/chromium/components/resources/default_200_percent/autofill/virtual_card_enroll.png b/chromium/components/resources/default_200_percent/autofill/virtual_card_enroll.png
new file mode 100644
index 00000000000..b41324914e0
--- /dev/null
+++ b/chromium/components/resources/default_200_percent/autofill/virtual_card_enroll.png
Binary files differ
diff --git a/chromium/components/resources/default_200_percent/autofill/virtual_card_enroll_dark.png b/chromium/components/resources/default_200_percent/autofill/virtual_card_enroll_dark.png
new file mode 100644
index 00000000000..aa6fdb72d42
--- /dev/null
+++ b/chromium/components/resources/default_200_percent/autofill/virtual_card_enroll_dark.png
Binary files differ
diff --git a/chromium/components/resources/default_300_percent/autofill/virtual_card_enroll.png b/chromium/components/resources/default_300_percent/autofill/virtual_card_enroll.png
new file mode 100644
index 00000000000..1a18b1e56a0
--- /dev/null
+++ b/chromium/components/resources/default_300_percent/autofill/virtual_card_enroll.png
Binary files differ
diff --git a/chromium/components/resources/default_300_percent/autofill/virtual_card_enroll_dark.png b/chromium/components/resources/default_300_percent/autofill/virtual_card_enroll_dark.png
new file mode 100644
index 00000000000..d393ec1d20f
--- /dev/null
+++ b/chromium/components/resources/default_300_percent/autofill/virtual_card_enroll_dark.png
Binary files differ
diff --git a/chromium/components/resources/web_app_default_offline.grdp b/chromium/components/resources/web_app_default_offline.grdp
new file mode 100644
index 00000000000..2b6de95a617
--- /dev/null
+++ b/chromium/components/resources/web_app_default_offline.grdp
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<grit-part>
+ <include name="IDR_WEBAPP_DEFAULT_OFFLINE_HTML" file="../web_app_resources/web_app_default_offline.html" flattenhtml="true" type="BINDATA"/>
+</grit-part> \ No newline at end of file
diff --git a/chromium/components/safe_browsing/DEPS b/chromium/components/safe_browsing/DEPS
index 6e9b4ba3d95..f4d1cf27330 100644
--- a/chromium/components/safe_browsing/DEPS
+++ b/chromium/components/safe_browsing/DEPS
@@ -7,10 +7,12 @@ include_rules = [
"+components/history/core/browser",
"+components/keyed_service/core",
"+components/password_manager/core/browser/password_manager_metrics_util.h",
+ "+components/policy/core/browser",
"+components/prefs",
"+components/security_interstitials/core",
"+components/sync_preferences/testing_pref_service_syncable.h",
"+components/unified_consent",
+ "+components/url_matcher",
"+components/user_prefs/user_prefs.h",
"+components/variations",
"+google_apis",
diff --git a/chromium/components/safe_browsing/android/safe_browsing_api_handler_util.cc b/chromium/components/safe_browsing/android/safe_browsing_api_handler_util.cc
index 39d6c4855e9..6bc5553ec26 100644
--- a/chromium/components/safe_browsing/android/safe_browsing_api_handler_util.cc
+++ b/chromium/components/safe_browsing/android/safe_browsing_api_handler_util.cc
@@ -149,7 +149,7 @@ UmaRemoteCallResult ParseJsonFromGMSCore(const std::string& metadata_str,
// Go through each matched threat type and pick the most severe.
JavaThreatTypes worst_threat_type = JAVA_THREAT_TYPE_MAX_VALUE;
const base::DictionaryValue* worst_match = nullptr;
- for (const base::Value& match_value : matches->GetList()) {
+ for (const base::Value& match_value : matches->GetListDeprecated()) {
// Get the threat number
const base::DictionaryValue* match = nullptr;
if (match_value.is_dict())
diff --git a/chromium/components/safe_browsing/content/browser/BUILD.gn b/chromium/components/safe_browsing/content/browser/BUILD.gn
index 9e7762f662f..9f53dc8dd0c 100644
--- a/chromium/components/safe_browsing/content/browser/BUILD.gn
+++ b/chromium/components/safe_browsing/content/browser/BUILD.gn
@@ -52,6 +52,7 @@ if (safe_browsing_mode > 0) {
"//components/safe_browsing/core/browser:safe_browsing_metrics_collector",
"//components/safe_browsing/core/common",
"//components/safe_browsing/core/common:safe_browsing_prefs",
+ "//components/safe_browsing/core/common/proto:csd_proto",
"//components/security_interstitials/content:security_interstitial_page",
"//components/security_interstitials/core",
"//components/security_interstitials/core:unsafe_resource",
diff --git a/chromium/components/safe_browsing/content/browser/base_ui_manager.cc b/chromium/components/safe_browsing/content/browser/base_ui_manager.cc
index ab07df49ece..c81f75938d6 100644
--- a/chromium/components/safe_browsing/content/browser/base_ui_manager.cc
+++ b/chromium/components/safe_browsing/content/browser/base_ui_manager.cc
@@ -11,7 +11,6 @@
#include "base/feature_list.h"
#include "base/i18n/rtl.h"
#include "base/memory/ptr_util.h"
-#include "base/supports_user_data.h"
#include "components/safe_browsing/content/browser/base_blocking_page.h"
#include "components/safe_browsing/core/common/features.h"
#include "components/security_interstitials/content/security_interstitial_tab_helper.h"
@@ -21,6 +20,7 @@
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_user_data.h"
using content::BrowserThread;
using content::NavigationEntry;
@@ -30,18 +30,15 @@ using safe_browsing::SBThreatType;
namespace {
-const void* const kAllowlistKey = &kAllowlistKey;
-
// A AllowlistUrlSet holds the set of URLs that have been allowlisted
// for a specific WebContents, along with pending entries that are still
// undecided. Each URL is associated with the first SBThreatType that
// was seen for that URL. The URLs in this set should come from
// GetAllowlistUrl() or GetMainFrameAllowlistUrlForResource() (in
// SafeBrowsingUIManager)
-class AllowlistUrlSet : public base::SupportsUserData::Data {
+class AllowlistUrlSet : public content::WebContentsUserData<AllowlistUrlSet> {
public:
- AllowlistUrlSet() {}
-
+ ~AllowlistUrlSet() override = default;
AllowlistUrlSet(const AllowlistUrlSet&) = delete;
AllowlistUrlSet& operator=(const AllowlistUrlSet&) = delete;
@@ -82,12 +79,17 @@ class AllowlistUrlSet : public base::SupportsUserData::Data {
pending_[url] = {threat_type, 1};
}
- protected:
+ private:
+ friend class content::WebContentsUserData<AllowlistUrlSet>;
+ WEB_CONTENTS_USER_DATA_KEY_DECL();
+
+ explicit AllowlistUrlSet(content::WebContents* web_contents)
+ : content::WebContentsUserData<AllowlistUrlSet>(*web_contents) {}
+
// Method to remove all the instances of a website in the pending list
// disregarding the count. Used when adding a site to the permanent list.
void RemoveAllPending(const GURL& url) { pending_.erase(url); }
- private:
std::map<GURL, SBThreatType> map_;
// Keep a count of how many times a site has been added to the pending list
// in order to solve a problem where upon reloading an interstitial, a site
@@ -95,6 +97,8 @@ class AllowlistUrlSet : public base::SupportsUserData::Data {
std::map<GURL, std::pair<SBThreatType, int>> pending_;
};
+WEB_CONTENTS_USER_DATA_KEY_IMPL(AllowlistUrlSet);
+
// Returns the URL that should be used in a AllowlistUrlSet for the
// resource loaded from |url| on a navigation |entry|.
GURL GetAllowlistUrl(const GURL& url,
@@ -108,23 +112,13 @@ GURL GetAllowlistUrl(const GURL& url,
return url.GetWithEmptyPath();
}
-AllowlistUrlSet* GetOrCreateAllowlist(WebContents* web_contents) {
- AllowlistUrlSet* site_list =
- static_cast<AllowlistUrlSet*>(web_contents->GetUserData(kAllowlistKey));
- if (!site_list) {
- site_list = new AllowlistUrlSet;
- web_contents->SetUserData(kAllowlistKey, base::WrapUnique(site_list));
- }
- return site_list;
-}
-
} // namespace
namespace safe_browsing {
-BaseUIManager::BaseUIManager() {}
+BaseUIManager::BaseUIManager() = default;
-BaseUIManager::~BaseUIManager() {}
+BaseUIManager::~BaseUIManager() = default;
bool BaseUIManager::IsAllowlisted(const UnsafeResource& resource) {
NavigationEntry* entry = nullptr;
@@ -159,8 +153,7 @@ bool BaseUIManager::IsUrlAllowlistedOrPendingForWebContents(
if (lookup_url.is_empty())
return false;
- AllowlistUrlSet* site_list =
- static_cast<AllowlistUrlSet*>(web_contents->GetUserData(kAllowlistKey));
+ AllowlistUrlSet* site_list = AllowlistUrlSet::FromWebContents(web_contents);
if (!site_list)
return false;
@@ -335,7 +328,7 @@ void BaseUIManager::DisplayBlockingPage(const UnsafeResource& resource) {
}
void BaseUIManager::EnsureAllowlistCreated(WebContents* web_contents) {
- GetOrCreateAllowlist(web_contents);
+ AllowlistUrlSet::CreateForWebContents(web_contents);
}
void BaseUIManager::CreateAndSendHitReport(const UnsafeResource& resource) {}
@@ -384,7 +377,8 @@ void BaseUIManager::AddToAllowlistUrlSet(const GURL& allowlist_url,
if (!web_contents)
return;
- AllowlistUrlSet* site_list = GetOrCreateAllowlist(web_contents);
+ AllowlistUrlSet::CreateForWebContents(web_contents);
+ AllowlistUrlSet* site_list = AllowlistUrlSet::FromWebContents(web_contents);
if (allowlist_url.is_empty())
return;
@@ -445,8 +439,7 @@ void BaseUIManager::RemoveAllowlistUrlSet(const GURL& allowlist_url,
// here. By this point, a "Back" navigation could have already been
// committed, so the page loading |resource| might be gone and
// |web_contents_getter| may no longer be valid.
- AllowlistUrlSet* site_list =
- static_cast<AllowlistUrlSet*>(web_contents->GetUserData(kAllowlistKey));
+ AllowlistUrlSet* site_list = AllowlistUrlSet::FromWebContents(web_contents);
if (allowlist_url.is_empty())
return;
@@ -478,13 +471,10 @@ void BaseUIManager::RemoveAllowlistUrlSet(const GURL& allowlist_url,
// static
GURL BaseUIManager::GetMainFrameAllowlistUrlForResource(
const security_interstitials::UnsafeResource& resource) {
- if (resource.is_subresource) {
- NavigationEntry* entry = GetNavigationEntryForResource(resource);
- if (!entry)
- return GURL();
- return entry->GetURL().GetWithEmptyPath();
- }
- return resource.url.GetWithEmptyPath();
+ return GetAllowlistUrl(resource.url, resource.is_subresource,
+ resource.is_subresource
+ ? GetNavigationEntryForResource(resource)
+ : nullptr);
}
} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing/content/browser/client_side_detection_service.cc b/chromium/components/safe_browsing/content/browser/client_side_detection_service.cc
index 8d80336cafe..124c3c4cbe1 100644
--- a/chromium/components/safe_browsing/content/browser/client_side_detection_service.cc
+++ b/chromium/components/safe_browsing/content/browser/client_side_detection_service.cc
@@ -106,6 +106,8 @@ ClientSideDetectionService::~ClientSideDetectionService() {
void ClientSideDetectionService::Shutdown() {
url_loader_factory_.reset();
+ delegate_.reset();
+ enabled_ = false;
}
void ClientSideDetectionService::OnPrefsUpdated() {
@@ -416,7 +418,7 @@ void ClientSideDetectionService::LoadPhishingReportTimesFromPrefs() {
for (const base::Value& timestamp :
delegate_->GetPrefs()
->GetList(prefs::kSafeBrowsingCsdPingTimestamps)
- ->GetList()) {
+ ->GetListDeprecated()) {
phishing_report_times_.push_back(
base::Time::FromDoubleT(timestamp.GetDouble()));
}
diff --git a/chromium/components/safe_browsing/content/browser/client_side_phishing_model_unittest.cc b/chromium/components/safe_browsing/content/browser/client_side_phishing_model_unittest.cc
index 1b181895b4e..e91f3f7b991 100644
--- a/chromium/components/safe_browsing/content/browser/client_side_phishing_model_unittest.cc
+++ b/chromium/components/safe_browsing/content/browser/client_side_phishing_model_unittest.cc
@@ -391,8 +391,8 @@ TEST(ClientSidePhishingModelTest, FlatbufferonFollowingUpdate) {
// See https://crbug.com/815537 and base/test/gtest_util.h.
// Can remove this if flaky.
// Windows ASAN flake: crbug.com/1234652
-#if defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID) && \
- !(defined(OS_WIN) && defined(ADDRESS_SANITIZER))
+#if defined(GTEST_HAS_DEATH_TEST) && !BUILDFLAG(IS_ANDROID) && \
+ !(BUILDFLAG(IS_WIN) && defined(ADDRESS_SANITIZER))
EXPECT_DEATH_IF_SUPPORTED(memset(memory_addr, 'G', 1), "");
#endif
}
diff --git a/chromium/components/safe_browsing/content/browser/password_protection/BUILD.gn b/chromium/components/safe_browsing/content/browser/password_protection/BUILD.gn
index 6b986fd67bb..3a5f0756a23 100644
--- a/chromium/components/safe_browsing/content/browser/password_protection/BUILD.gn
+++ b/chromium/components/safe_browsing/content/browser/password_protection/BUILD.gn
@@ -8,8 +8,8 @@ import("//extensions/buildflags/buildflags.gni")
source_set("password_protection") {
if (safe_browsing_mode == 1 || safe_browsing_mode == 2) {
sources = [
- "password_protection_navigation_throttle.cc",
- "password_protection_navigation_throttle.h",
+ "password_protection_commit_deferring_condition.cc",
+ "password_protection_commit_deferring_condition.h",
"password_protection_request_content.cc",
"password_protection_request_content.h",
"password_protection_service.cc",
@@ -65,7 +65,7 @@ source_set("password_protection_unittest") {
testonly = true
if (safe_browsing_mode > 0) {
sources = [
- "password_protection_navigation_throttle_unittest.cc",
+ "password_protection_commit_deferring_condition_unittest.cc",
"password_protection_service_unittest.cc",
]
diff --git a/chromium/components/safe_browsing/content/browser/password_protection/password_protection_commit_deferring_condition.cc b/chromium/components/safe_browsing/content/browser/password_protection/password_protection_commit_deferring_condition.cc
new file mode 100644
index 00000000000..e6abe4309b0
--- /dev/null
+++ b/chromium/components/safe_browsing/content/browser/password_protection/password_protection_commit_deferring_condition.cc
@@ -0,0 +1,51 @@
+// Copyright 2022 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.
+
+#include "components/safe_browsing/content/browser/password_protection/password_protection_commit_deferring_condition.h"
+
+#include "components/safe_browsing/content/browser/password_protection/password_protection_request_content.h"
+#include "content/public/browser/navigation_handle.h"
+
+namespace safe_browsing {
+
+PasswordProtectionCommitDeferringCondition::
+ PasswordProtectionCommitDeferringCondition(
+ content::NavigationHandle& navigation_handle,
+ scoped_refptr<PasswordProtectionRequestContent> request)
+ : content::CommitDeferringCondition(navigation_handle), request_(request) {
+ DCHECK(request_);
+ request_->AddDeferredNavigation(*this);
+}
+
+PasswordProtectionCommitDeferringCondition::
+ ~PasswordProtectionCommitDeferringCondition() {
+ // It's ok we won't call RemoveDeferredNavigation if !navigation_was_resumed
+ // since `request_` will clean up all conditions after calling
+ // ResumeNavigation.
+ if (!navigation_was_resumed_)
+ request_->RemoveDeferredNavigation(*this);
+}
+
+content::CommitDeferringCondition::Result
+PasswordProtectionCommitDeferringCondition::WillCommitNavigation(
+ base::OnceClosure resume) {
+ // The request may have asked for a resumption before this condition was
+ // executed. In that case, proceed without deferring.
+ if (navigation_was_resumed_)
+ return Result::kProceed;
+
+ resume_ = std::move(resume);
+ return Result::kDefer;
+}
+
+void PasswordProtectionCommitDeferringCondition::ResumeNavigation() {
+ navigation_was_resumed_ = true;
+
+ if (resume_)
+ std::move(resume_).Run();
+
+ // Warning: Run() may have deleted `self`.
+}
+
+} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing/content/browser/password_protection/password_protection_commit_deferring_condition.h b/chromium/components/safe_browsing/content/browser/password_protection/password_protection_commit_deferring_condition.h
new file mode 100644
index 00000000000..52a086f80da
--- /dev/null
+++ b/chromium/components/safe_browsing/content/browser/password_protection/password_protection_commit_deferring_condition.h
@@ -0,0 +1,81 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_SAFE_BROWSING_CONTENT_BROWSER_PASSWORD_PROTECTION_PASSWORD_PROTECTION_COMMIT_DEFERRING_CONDITION_H_
+#define COMPONENTS_SAFE_BROWSING_CONTENT_BROWSER_PASSWORD_PROTECTION_PASSWORD_PROTECTION_COMMIT_DEFERRING_CONDITION_H_
+
+#include "base/memory/ref_counted.h"
+#include "content/public/browser/commit_deferring_condition.h"
+
+namespace content {
+class NavigationHandle;
+} // namespace content
+
+namespace safe_browsing {
+class PasswordProtectionRequestContent;
+
+// PasswordProtectionCommitDeferringCondition defers navigations under the
+// following conditions:
+// (1) The navigation starts while there is a on-going sync password
+// reuse ping. When the verdict comes back, if the verdict results in
+// showing a modal warning dialog, the navigation continues to be deferred;
+// otherwise, the deferred navigation will be resumed.
+// (2) The navigation starts while there is a modal warning showing.
+//
+// If a modal warning is showing, the navigation will continue to be deferred
+// until the user takes an action and dismisses the dialog, at which point the
+// navigation will resume.
+class PasswordProtectionCommitDeferringCondition
+ : public content::CommitDeferringCondition {
+ public:
+ PasswordProtectionCommitDeferringCondition(
+ content::NavigationHandle& navigation_handle,
+ scoped_refptr<PasswordProtectionRequestContent> request);
+
+ PasswordProtectionCommitDeferringCondition(
+ const PasswordProtectionCommitDeferringCondition&) = delete;
+ PasswordProtectionCommitDeferringCondition& operator=(
+ const PasswordProtectionCommitDeferringCondition&) = delete;
+
+ ~PasswordProtectionCommitDeferringCondition() override;
+
+ // Overrides content::CommitDeferringCondition
+ //
+ // Called from a NavigationHandle when a navigation is ready and about to
+ // commit. Unless ResumeNavigation() was already called, this will return
+ // kDefer which will defer the navigation from committing until `resume` is
+ // invoked (via `ResumeNavigation()`).
+ Result WillCommitNavigation(base::OnceClosure resume) override;
+
+ // Called by the PasswordProtectionService when it decides this navigation no
+ // longer needs to be deferred (e.g. because a ping resulted in not showing a
+ // modal, or a shown modal was dismissed by the user). If called after this
+ // navigation tried to commit, this invokes the `resume` closure passed to
+ // WillCommitNavigation. If called before WillCommitNavigation,
+ // WillCommitNavigation will not defer the commit.
+ void ResumeNavigation();
+
+ // Returns whether the NavigationHandle tried to commit but was deferred from
+ // doing so by this condition.
+ bool is_deferred_for_testing() const { return !resume_.is_null(); }
+
+ private:
+ // A pointer to the PasswordProtectionRequestContent on whose behalf this
+ // condition is deferring navigations.
+ // TODO(bokan): Replace with a WeakPtr.
+ scoped_refptr<PasswordProtectionRequestContent> request_;
+
+ // The resume closure used to resume the navigation past this
+ // CommitDeferringCondition.
+ base::OnceClosure resume_;
+
+ // Set to true to indicate the request has asked to resume the navigation,
+ // i.e. the request result didn't result in a modal being shown, or the user
+ // has dismissed the modal.
+ bool navigation_was_resumed_ = false;
+};
+
+} // namespace safe_browsing
+
+#endif // COMPONENTS_SAFE_BROWSING_CONTENT_BROWSER_PASSWORD_PROTECTION_PASSWORD_PROTECTION_COMMIT_DEFERRING_CONDITION_H_
diff --git a/chromium/components/safe_browsing/content/browser/password_protection/password_protection_commit_deferring_condition_unittest.cc b/chromium/components/safe_browsing/content/browser/password_protection/password_protection_commit_deferring_condition_unittest.cc
new file mode 100644
index 00000000000..fc07987ae6e
--- /dev/null
+++ b/chromium/components/safe_browsing/content/browser/password_protection/password_protection_commit_deferring_condition_unittest.cc
@@ -0,0 +1,106 @@
+// Copyright 2020 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.
+
+#include "components/safe_browsing/content/browser/password_protection/password_protection_commit_deferring_condition.h"
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "base/test/bind.h"
+#include "components/safe_browsing/content/browser/password_protection/mock_password_protection_service.h"
+#include "components/safe_browsing/content/browser/password_protection/password_protection_request_content.h"
+#include "content/public/browser/commit_deferring_condition.h"
+#include "content/public/browser/navigation_handle.h"
+#include "content/public/test/mock_navigation_handle.h"
+#include "content/public/test/navigation_simulator.h"
+#include "content/public/test/test_renderer_host.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace safe_browsing {
+
+using content::CommitDeferringCondition;
+using content::MockNavigationHandle;
+using content::NavigationHandle;
+using content::NavigationSimulator;
+using content::RenderViewHostTestHarness;
+using testing::NiceMock;
+
+class PasswordProtectionCommitDeferringConditionTest
+ : public RenderViewHostTestHarness {
+ public:
+ PasswordProtectionCommitDeferringConditionTest() = default;
+ PasswordProtectionCommitDeferringConditionTest(
+ const PasswordProtectionCommitDeferringConditionTest&) = delete;
+ PasswordProtectionCommitDeferringConditionTest& operator=(
+ const PasswordProtectionCommitDeferringConditionTest&) = delete;
+ ~PasswordProtectionCommitDeferringConditionTest() override = default;
+
+ // RenderViewHostTestHarness:
+ void SetUp() override {
+ RenderViewHostTestHarness::SetUp();
+
+ std::vector<password_manager::MatchingReusedCredential> credentials = {
+ {"http://example.test"}, {"http://2.example.com"}};
+
+ scoped_refptr<PasswordProtectionRequestContent> request =
+ new PasswordProtectionRequestContent(
+ RenderViewHostTestHarness::web_contents(), GURL(), GURL(), GURL(),
+ RenderViewHostTestHarness::web_contents()->GetContentsMimeType(),
+ "username", PasswordType::PASSWORD_TYPE_UNKNOWN, credentials,
+ LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
+ /* password_field_exists*/ true, &service_,
+ /*request_timeout_in_ms=*/0);
+
+ condition_ = std::make_unique<PasswordProtectionCommitDeferringCondition>(
+ mock_navigation_, request);
+ }
+
+ void TearDown() override {
+ condition_.reset();
+ RenderViewHostTestHarness::TearDown();
+ }
+
+ protected:
+ std::unique_ptr<PasswordProtectionCommitDeferringCondition> condition_;
+
+ MockNavigationHandle mock_navigation_;
+ NiceMock<safe_browsing::MockPasswordProtectionService> service_;
+};
+
+// If created, and while not resumed, a condition must return kDefer to defer
+// the navigation until safe browsing determines it should be resumed.
+TEST_F(PasswordProtectionCommitDeferringConditionTest, DeferWhenCreated) {
+ EXPECT_EQ(content::CommitDeferringCondition::Result::kDefer,
+ condition_->WillCommitNavigation(base::DoNothing()));
+}
+
+// If the password protection request is resolved before the navigation reaches
+// commit, the condition shouldn't defer the navigation.
+TEST_F(PasswordProtectionCommitDeferringConditionTest,
+ ResumedBeforeCommitProceeds) {
+ condition_->ResumeNavigation();
+
+ bool was_invoked = false;
+ EXPECT_EQ(CommitDeferringCondition::Result::kProceed,
+ condition_->WillCommitNavigation(
+ base::BindLambdaForTesting([&]() { was_invoked = true; })));
+ EXPECT_FALSE(was_invoked);
+}
+
+// Calling ResumeNavigation on a deferred condition should invoke the callback.
+TEST_F(PasswordProtectionCommitDeferringConditionTest,
+ InvokeCallbackFromResume) {
+ bool was_invoked = false;
+ ASSERT_EQ(CommitDeferringCondition::Result::kDefer,
+ condition_->WillCommitNavigation(
+ base::BindLambdaForTesting([&]() { was_invoked = true; })));
+ ASSERT_FALSE(was_invoked);
+
+ condition_->ResumeNavigation();
+ EXPECT_TRUE(was_invoked);
+}
+
+} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing/content/browser/password_protection/password_protection_navigation_throttle.cc b/chromium/components/safe_browsing/content/browser/password_protection/password_protection_navigation_throttle.cc
deleted file mode 100644
index bb2b90f5b13..00000000000
--- a/chromium/components/safe_browsing/content/browser/password_protection/password_protection_navigation_throttle.cc
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright 2017 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.
-
-#include "components/safe_browsing/content/browser/password_protection/password_protection_navigation_throttle.h"
-
-#include "components/safe_browsing/content/browser/password_protection/password_protection_request_content.h"
-#include "content/public/browser/navigation_handle.h"
-
-namespace safe_browsing {
-PasswordProtectionNavigationThrottle::PasswordProtectionNavigationThrottle(
- content::NavigationHandle* navigation_handle,
- scoped_refptr<PasswordProtectionRequestContent> request,
- bool is_warning_showing)
- : content::NavigationThrottle(navigation_handle),
- request_(request),
- is_warning_showing_(is_warning_showing) {
- // Only call AddThrottle() if there is no modal warning showing. If there's a
- // modal dialog, PPNavigationThrottle will simply cancel this navigation
- // immediately, therefore no need to keep track of it.
- if (!is_warning_showing_)
- request_->AddThrottle(this);
-}
-
-PasswordProtectionNavigationThrottle::~PasswordProtectionNavigationThrottle() {
- if (request_)
- request_->RemoveThrottle(this);
-}
-
-content::NavigationThrottle::ThrottleCheckResult
-PasswordProtectionNavigationThrottle::WillStartRequest() {
- // If a modal warning is being shown right now, we don't
- // want to continue navigation. Otherwise, we assume that
- // the PasswordProtectionRequestContent is still waiting for a
- // verdict and so we defer the navigation.
- if (is_warning_showing_)
- return content::NavigationThrottle::CANCEL;
- return content::NavigationThrottle::DEFER;
-}
-
-content::NavigationThrottle::ThrottleCheckResult
-PasswordProtectionNavigationThrottle::WillRedirectRequest() {
- // If a modal warning is being shown right now, we don't
- // want to redirect navigation. Otherwise, if the
- // PasswordProtectionRequestContent still exists, we assume that the
- // request is still waiting for a verdict and so we defer the
- // navigation, otherwise we proceed navigation.
- if (is_warning_showing_)
- return content::NavigationThrottle::CANCEL;
- return request_ ? content::NavigationThrottle::DEFER
- : content::NavigationThrottle::PROCEED;
-}
-
-const char* PasswordProtectionNavigationThrottle::GetNameForLogging() {
- return "PasswordProtectionNavigationThrottle";
-}
-
-void PasswordProtectionNavigationThrottle::ResumeNavigation() {
- Resume();
- // When navigation is resumed, we do not need to keep track of the
- // PasswordProtectionRequestContent because this method is only called
- // after the request received a verdict and has finished.
- request_.reset();
-}
-
-void PasswordProtectionNavigationThrottle::CancelNavigation(
- content::NavigationThrottle::ThrottleCheckResult result) {
- // When navigation is resumed, we do not need to keep track of the
- // PasswordProtectionRequestContent because this method is only called
- // after the request received a verdict, showing a modal warning and has
- // finished.
- CancelDeferredNavigation(result);
- request_.reset();
-}
-
-} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing/content/browser/password_protection/password_protection_navigation_throttle.h b/chromium/components/safe_browsing/content/browser/password_protection/password_protection_navigation_throttle.h
deleted file mode 100644
index aae977887c2..00000000000
--- a/chromium/components/safe_browsing/content/browser/password_protection/password_protection_navigation_throttle.h
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright 2017 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.
-
-#ifndef COMPONENTS_SAFE_BROWSING_CONTENT_BROWSER_PASSWORD_PROTECTION_PASSWORD_PROTECTION_NAVIGATION_THROTTLE_H_
-#define COMPONENTS_SAFE_BROWSING_CONTENT_BROWSER_PASSWORD_PROTECTION_PASSWORD_PROTECTION_NAVIGATION_THROTTLE_H_
-
-#include "base/memory/ref_counted.h"
-#include "content/public/browser/navigation_throttle.h"
-
-namespace content {
-class NavigationHandle;
-} // namespace content
-
-namespace safe_browsing {
-class PasswordProtectionRequestContent;
-
-// PasswordProtectionNavigationThrottle defers or cancel navigation under the
-// following condition:
-// (1) if a navigation starts when there is a on-going sync password reuse ping,
-// this throttle defers this navigation. When the verdict comes back, if the
-// verdict results in showing a modal warning dialog, the deferred
-// navigation will be canceled; otherwise, the deferred navigation will be
-// resumed.
-// (2) if a navigation starts when there is a modal warning showing, this
-// throttle simply cancels this navigation.
-class PasswordProtectionNavigationThrottle
- : public content::NavigationThrottle {
- public:
- PasswordProtectionNavigationThrottle(
- content::NavigationHandle* navigation_handle,
- scoped_refptr<PasswordProtectionRequestContent> request,
- bool is_warning_showing);
-
- PasswordProtectionNavigationThrottle(
- const PasswordProtectionNavigationThrottle&) = delete;
- PasswordProtectionNavigationThrottle& operator=(
- const PasswordProtectionNavigationThrottle&) = delete;
-
- ~PasswordProtectionNavigationThrottle() override;
-
- // content::NavigationThrottle:
- content::NavigationThrottle::ThrottleCheckResult WillStartRequest() override;
- content::NavigationThrottle::ThrottleCheckResult WillRedirectRequest()
- override;
- const char* GetNameForLogging() override;
-
- // Called to resume a deferred navigation once the
- // PasswordProtectionRequestContent has received a verdict and there is no
- // modal warning shown.
- void ResumeNavigation();
- // Called when the PasswordProtectionRequestContent has received a verdict and
- // there is a modal warning shown.
- void CancelNavigation(
- content::NavigationThrottle::ThrottleCheckResult result);
-
- private:
- scoped_refptr<PasswordProtectionRequestContent> request_;
- bool is_warning_showing_;
-};
-
-} // namespace safe_browsing
-
-#endif // COMPONENTS_SAFE_BROWSING_CONTENT_BROWSER_PASSWORD_PROTECTION_PASSWORD_PROTECTION_NAVIGATION_THROTTLE_H_
diff --git a/chromium/components/safe_browsing/content/browser/password_protection/password_protection_navigation_throttle_unittest.cc b/chromium/components/safe_browsing/content/browser/password_protection/password_protection_navigation_throttle_unittest.cc
deleted file mode 100644
index 31d1d43c710..00000000000
--- a/chromium/components/safe_browsing/content/browser/password_protection/password_protection_navigation_throttle_unittest.cc
+++ /dev/null
@@ -1,150 +0,0 @@
-// Copyright 2020 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.
-
-#include "components/safe_browsing/content/browser/password_protection/password_protection_navigation_throttle.h"
-
-#include <memory>
-#include <utility>
-#include <vector>
-
-#include "base/test/bind.h"
-#include "components/safe_browsing/content/browser/password_protection/mock_password_protection_service.h"
-#include "components/safe_browsing/content/browser/password_protection/password_protection_request_content.h"
-#include "content/public/browser/navigation_handle.h"
-#include "content/public/browser/navigation_throttle.h"
-#include "content/public/browser/web_contents_observer.h"
-#include "content/public/test/navigation_simulator.h"
-#include "content/public/test/test_renderer_host.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "url/gurl.h"
-
-namespace safe_browsing {
-
-using testing::NiceMock;
-
-class PasswordProtectionNavigationThrottleTest
- : public content::RenderViewHostTestHarness,
- public content::WebContentsObserver {
- public:
- PasswordProtectionNavigationThrottleTest() = default;
- PasswordProtectionNavigationThrottleTest(
- const PasswordProtectionNavigationThrottleTest&) = delete;
- PasswordProtectionNavigationThrottleTest& operator=(
- const PasswordProtectionNavigationThrottleTest&) = delete;
- ~PasswordProtectionNavigationThrottleTest() override = default;
-
- // content::RenderViewHostTestHarness:
- void SetUp() override {
- content::RenderViewHostTestHarness::SetUp();
-
- // Observe the WebContents to add the throttle.
- Observe(RenderViewHostTestHarness::web_contents());
- }
-
- void TearDown() override {
- content::RenderViewHostTestHarness::TearDown();
- throttle_.release();
- }
-
- void SetIsWarningShown(bool is_warning_shown) {
- is_warning_shown_ = is_warning_shown;
- }
-
- // content::WebContentsObserver:
- void DidStartNavigation(
- content::NavigationHandle* navigation_handle) override {
- std::vector<password_manager::MatchingReusedCredential> credentials = {
- {"http://example.test"}, {"http://2.example.com"}};
- std::unique_ptr<safe_browsing::MockPasswordProtectionService>
- password_protection_service = std::make_unique<
- NiceMock<safe_browsing::MockPasswordProtectionService>>();
-
- scoped_refptr<PasswordProtectionRequestContent> request =
- new PasswordProtectionRequestContent(
- RenderViewHostTestHarness::web_contents(), GURL(), GURL(), GURL(),
- RenderViewHostTestHarness::web_contents()->GetContentsMimeType(),
- "username", PasswordType::PASSWORD_TYPE_UNKNOWN, credentials,
- LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
- /* password_field_exists*/ true, password_protection_service.get(),
- /*request_timeout_in_ms=*/0);
- std::unique_ptr<PasswordProtectionNavigationThrottle> throttle =
- std::make_unique<PasswordProtectionNavigationThrottle>(
- navigation_handle, request, is_warning_shown_);
- throttle_ = std::move(throttle);
- }
-
- std::unique_ptr<PasswordProtectionNavigationThrottle> throttle() {
- return std::move(throttle_);
- }
-
- protected:
- std::unique_ptr<content::NavigationSimulator> StartNavigation(
- const GURL& first_url) {
- auto navigation_simulator =
- content::NavigationSimulator::CreateRendererInitiated(first_url,
- main_rfh());
- navigation_simulator->SetAutoAdvance(false);
- navigation_simulator->Start();
- return navigation_simulator;
- }
-
- bool is_warning_shown_ = false;
- std::unique_ptr<PasswordProtectionNavigationThrottle> throttle_;
-};
-
-TEST_F(PasswordProtectionNavigationThrottleTest, DeferOnNavigation) {
- auto navigation_simulator = StartNavigation(GURL("http://www.example.com/"));
- EXPECT_EQ(content::NavigationThrottle::DEFER, throttle()->WillStartRequest());
-}
-
-TEST_F(PasswordProtectionNavigationThrottleTest,
- CancelNavigationOnWarningShown) {
- SetIsWarningShown(true);
-
- auto navigation_simulator = StartNavigation(GURL("http://www.example.com/"));
- EXPECT_EQ(content::NavigationThrottle::CANCEL,
- throttle()->WillStartRequest());
-}
-
-TEST_F(PasswordProtectionNavigationThrottleTest, WillDeferRedirectRequest) {
- auto navigation_simulator = StartNavigation(GURL("http://www.example.com/"));
-
- std::unique_ptr<PasswordProtectionNavigationThrottle> throttle_copy =
- std::move(throttle_);
- throttle_copy->set_resume_callback_for_testing(
- base::BindLambdaForTesting([&]() {}));
- EXPECT_EQ(content::NavigationThrottle::DEFER,
- throttle_copy->WillRedirectRequest());
-
- // Release request.
- throttle_copy->ResumeNavigation();
- EXPECT_EQ(content::NavigationThrottle::PROCEED,
- throttle_copy->WillRedirectRequest());
-}
-
-TEST_F(PasswordProtectionNavigationThrottleTest, WillCancelRedirectRequest) {
- auto navigation_simulator = StartNavigation(GURL("http://www.example.com/"));
-
- // Release request.
- std::unique_ptr<PasswordProtectionNavigationThrottle> throttle_copy =
- std::move(throttle_);
- throttle_copy->set_cancel_deferred_navigation_callback_for_testing(
- base::BindRepeating(
- [](content::NavigationThrottle::ThrottleCheckResult result) {}));
- throttle_copy->CancelNavigation(content::NavigationThrottle::DEFER);
-
- EXPECT_EQ(content::NavigationThrottle::PROCEED,
- throttle_copy->WillRedirectRequest());
-}
-
-TEST_F(PasswordProtectionNavigationThrottleTest,
- WillCancelRedirectRequestOnWarningShown) {
- SetIsWarningShown(true);
-
- auto navigation_simulator = StartNavigation(GURL("http://www.example.com/"));
- EXPECT_EQ(content::NavigationThrottle::CANCEL,
- throttle()->WillRedirectRequest());
-}
-
-} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing/content/browser/password_protection/password_protection_request_content.cc b/chromium/components/safe_browsing/content/browser/password_protection/password_protection_request_content.cc
index 853c5c15b64..507e5282dbf 100644
--- a/chromium/components/safe_browsing/content/browser/password_protection/password_protection_request_content.cc
+++ b/chromium/components/safe_browsing/content/browser/password_protection/password_protection_request_content.cc
@@ -8,7 +8,7 @@
#include "base/metrics/histogram_macros.h"
#include "base/task/thread_pool.h"
#include "build/build_config.h"
-#include "components/safe_browsing/content/browser/password_protection/password_protection_navigation_throttle.h"
+#include "components/safe_browsing/content/browser/password_protection/password_protection_commit_deferring_condition.h"
#include "components/safe_browsing/content/browser/password_protection/password_protection_service.h"
#include "components/safe_browsing/content/browser/web_ui/safe_browsing_ui.h"
#include "components/safe_browsing/core/browser/password_protection/request_canceler.h"
@@ -24,7 +24,7 @@
#include "content/public/browser/web_contents.h"
#endif // BUILDFLAG(SAFE_BROWSING_AVAILABLE)
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "ui/android/view_android.h"
#endif
@@ -37,7 +37,7 @@ namespace {
const int kDomFeatureTimeoutMs = 3000;
// Parameters chosen to ensure privacy is preserved by visual features.
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
const int kMinWidthForVisualFeatures = 258;
const int kMinHeightForVisualFeatures = 258;
#else
@@ -122,19 +122,18 @@ void PasswordProtectionRequestContent::Cancel(bool timed_out) {
// If request is canceled because |password_protection_service_| is shutting
// down, ignore all these deferred navigations.
if (!timed_out) {
- throttles_.clear();
+ deferred_navigations_.clear();
}
PasswordProtectionRequest::Cancel(timed_out);
}
-void PasswordProtectionRequestContent::HandleDeferredNavigations() {
- for (auto* throttle : throttles_) {
- if (is_modal_warning_showing())
- throttle->CancelNavigation(content::NavigationThrottle::CANCEL);
- else
- throttle->ResumeNavigation();
+void PasswordProtectionRequestContent::ResumeDeferredNavigations() {
+ for (PasswordProtectionCommitDeferringCondition* condition :
+ deferred_navigations_) {
+ condition->ResumeNavigation();
}
- throttles_.clear();
+
+ deferred_navigations_.clear();
}
void PasswordProtectionRequestContent::MaybeLogPasswordReuseLookupEvent(
@@ -257,7 +256,7 @@ void PasswordProtectionRequestContent::OnGetDomFeatureTimeout() {
void PasswordProtectionRequestContent::MaybeCollectVisualFeatures() {
// TODO(drubery): Unify this with the code to populate content_area_width and
// content_area_height on desktop.
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
if (password_protection_service()->IsExtendedReporting() &&
!password_protection_service()->IsIncognito()) {
content::RenderWidgetHostView* view =
@@ -276,7 +275,7 @@ void PasswordProtectionRequestContent::MaybeCollectVisualFeatures() {
!password_protection_service()->IsIncognito() &&
request_proto_->content_area_width() >= GetMinWidthForVisualFeatures() &&
request_proto_->content_area_height() >= GetMinHeightForVisualFeatures();
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
can_collect_visual_features &=
zoom::ZoomController::GetZoomLevelForWebContents(web_contents_) <=
kMaxZoomForVisualFeatures;
@@ -334,7 +333,7 @@ void PasswordProtectionRequestContent::OnVisualFeatureCollectionDone(
SendRequest();
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
void PasswordProtectionRequestContent::SetReferringAppInfo() {
PasswordProtectionService* service =
static_cast<PasswordProtectionService*>(password_protection_service());
@@ -347,6 +346,6 @@ void PasswordProtectionRequestContent::SetReferringAppInfo() {
1);
*request_proto_->mutable_referring_app_info() = std::move(referring_app_info);
}
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing/content/browser/password_protection/password_protection_request_content.h b/chromium/components/safe_browsing/content/browser/password_protection/password_protection_request_content.h
index d857b4cef42..9f33fe2c4d1 100644
--- a/chromium/components/safe_browsing/content/browser/password_protection/password_protection_request_content.h
+++ b/chromium/components/safe_browsing/content/browser/password_protection/password_protection_request_content.h
@@ -36,7 +36,7 @@ class WebContents;
namespace safe_browsing {
-class PasswordProtectionNavigationThrottle;
+class PasswordProtectionCommitDeferringCondition;
using password_manager::metrics_util::PasswordType;
@@ -66,17 +66,25 @@ class PasswordProtectionRequestContent : public PasswordProtectionRequest {
return base::AsWeakPtr(this);
}
- // Keeps track of created navigation throttle.
- void AddThrottle(PasswordProtectionNavigationThrottle* throttle) {
- throttles_.insert(throttle);
+ // Keeps track of deferred navigations.
+ void AddDeferredNavigation(
+ PasswordProtectionCommitDeferringCondition& condition) {
+ deferred_navigations_.insert(&condition);
}
- void RemoveThrottle(PasswordProtectionNavigationThrottle* throttle) {
- throttles_.erase(throttle);
+ void RemoveDeferredNavigation(
+ PasswordProtectionCommitDeferringCondition& condition) {
+ deferred_navigations_.erase(&condition);
}
- // Cancels navigation if there is modal warning showing, resumes it otherwise.
- void HandleDeferredNavigations();
+ // Resumes any navigations that were deferred waiting on this request or any
+ // associated modal warning dialog.
+ void ResumeDeferredNavigations();
+
+ std::set<PasswordProtectionCommitDeferringCondition*>&
+ get_deferred_navigations_for_testing() {
+ return deferred_navigations_;
+ }
private:
friend class PasswordProtectionServiceTest;
@@ -122,9 +130,9 @@ class PasswordProtectionRequestContent : public PasswordProtectionRequest {
std::unique_ptr<VisualFeatures> visual_features);
#endif // BUILDFLAG(SAFE_BROWSING_AVAILABLE)
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
void SetReferringAppInfo() override;
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
// WebContents of the password protection event.
raw_ptr<content::WebContents> web_contents_;
@@ -132,10 +140,9 @@ class PasswordProtectionRequestContent : public PasswordProtectionRequest {
// Cancels the request when it is no longer valid.
std::unique_ptr<RequestCanceler> request_canceler_;
- // Navigation throttles created for this |web_contents_| during |this|'s
- // lifetime. These throttles are owned by their corresponding
- // NavigationHandler instances.
- std::set<PasswordProtectionNavigationThrottle*> throttles_;
+ // Tracks navigations that are deferred on this request and any associated
+ // modal dialog.
+ std::set<PasswordProtectionCommitDeferringCondition*> deferred_navigations_;
// If a request is sent, this is the token returned by the WebUI.
int web_ui_token_;
diff --git a/chromium/components/safe_browsing/content/browser/password_protection/password_protection_service.cc b/chromium/components/safe_browsing/content/browser/password_protection/password_protection_service.cc
index 1a76cc8ad17..6f63cb114b8 100644
--- a/chromium/components/safe_browsing/content/browser/password_protection/password_protection_service.cc
+++ b/chromium/components/safe_browsing/content/browser/password_protection/password_protection_service.cc
@@ -13,7 +13,7 @@
#include "base/metrics/histogram_macros.h"
#include "components/password_manager/core/browser/password_manager_metrics_util.h"
#include "components/password_manager/core/browser/password_reuse_detector.h"
-#include "components/safe_browsing/content/browser/password_protection/password_protection_navigation_throttle.h"
+#include "components/safe_browsing/content/browser/password_protection/password_protection_commit_deferring_condition.h"
#include "components/safe_browsing/content/browser/password_protection/password_protection_request_content.h"
#include "components/safe_browsing/core/common/features.h"
#include "components/safe_browsing/core/common/utils.h"
@@ -122,6 +122,10 @@ void PasswordProtectionService::StartRequest(
password_field_exists, this, GetRequestTimeoutInMS()));
request->Start();
+ // TODO(bokan): Now that the throttle has been changed to a
+ // CommitDeferringCondition, a followup CL will remove this and make
+ // activations defer like other navigations. https://crbug.com/1234857
+ //
// PasswordProtectionService defers all navigations in the WebContents while
// there is a pending request triggered by a password reuse. However it does
// this via NavigationThrottles, which are not able to throttle navigations
@@ -143,10 +147,6 @@ void PasswordProtectionService::StartRequest(
//
// If we were to disallow for other trigger types, we may disable prerendering
// more than required.
- //
- // TODO(https://crbug.com/1234857): Change the throttle to a
- // CommitDeferringCondition, so the activation navigation can be deferred like
- // other navigations.
if (request->trigger_type() ==
safe_browsing::LoginReputationClientRequest::PASSWORD_REUSE_EVENT) {
web_contents->DisallowActivationNavigationsForBug1234857();
@@ -155,13 +155,13 @@ void PasswordProtectionService::StartRequest(
pending_requests_.insert(std::move(request));
}
-std::unique_ptr<PasswordProtectionNavigationThrottle>
-PasswordProtectionService::MaybeCreateNavigationThrottle(
- content::NavigationHandle* navigation_handle) {
- if (!navigation_handle->IsRendererInitiated())
+std::unique_ptr<PasswordProtectionCommitDeferringCondition>
+PasswordProtectionService::MaybeCreateCommitDeferringCondition(
+ content::NavigationHandle& navigation_handle) {
+ if (!navigation_handle.IsRendererInitiated())
return nullptr;
- content::WebContents* web_contents = navigation_handle->GetWebContents();
+ content::WebContents* web_contents = navigation_handle.GetWebContents();
for (scoped_refptr<PasswordProtectionRequest> request : pending_requests_) {
PasswordProtectionRequestContent* request_content =
static_cast<PasswordProtectionRequestContent*>(request.get());
@@ -171,8 +171,8 @@ PasswordProtectionService::MaybeCreateNavigationThrottle(
IsSupportedPasswordTypeForModalWarning(
GetPasswordProtectionReusedPasswordAccountType(
request->password_type(), username_for_last_shown_warning()))) {
- return std::make_unique<PasswordProtectionNavigationThrottle>(
- navigation_handle, request_content, /*is_warning_showing=*/false);
+ return std::make_unique<PasswordProtectionCommitDeferringCondition>(
+ navigation_handle, request_content);
}
}
@@ -180,8 +180,8 @@ PasswordProtectionService::MaybeCreateNavigationThrottle(
PasswordProtectionRequestContent* request_content =
static_cast<PasswordProtectionRequestContent*>(request.get());
if (request_content->web_contents() == web_contents) {
- return std::make_unique<PasswordProtectionNavigationThrottle>(
- navigation_handle, request_content, /*is_warning_showing=*/true);
+ return std::make_unique<PasswordProtectionCommitDeferringCondition>(
+ navigation_handle, request_content);
}
}
return nullptr;
@@ -200,10 +200,12 @@ void PasswordProtectionService::RemoveWarningRequestsByWebContents(
for (auto it = warning_requests_.begin(); it != warning_requests_.end();) {
PasswordProtectionRequestContent* request_content =
static_cast<PasswordProtectionRequestContent*>(it->get());
- if (request_content->web_contents() == web_contents)
+ if (request_content->web_contents() == web_contents) {
+ request_content->ResumeDeferredNavigations();
it = warning_requests_.erase(it);
- else
+ } else {
++it;
+ }
}
}
@@ -218,11 +220,14 @@ bool PasswordProtectionService::IsModalWarningShowingInWebContents(
return false;
}
-void PasswordProtectionService::MaybeHandleDeferredNavigations(
+void PasswordProtectionService::ResumeDeferredNavigationsIfNeeded(
PasswordProtectionRequest* request) {
+ if (request->is_modal_warning_showing())
+ return;
+
PasswordProtectionRequestContent* request_content =
static_cast<PasswordProtectionRequestContent*>(request);
- request_content->HandleDeferredNavigations();
+ request_content->ResumeDeferredNavigations();
}
} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing/content/browser/password_protection/password_protection_service.h b/chromium/components/safe_browsing/content/browser/password_protection/password_protection_service.h
index 5399024cc4f..7623d64d5a4 100644
--- a/chromium/components/safe_browsing/content/browser/password_protection/password_protection_service.h
+++ b/chromium/components/safe_browsing/content/browser/password_protection/password_protection_service.h
@@ -13,6 +13,7 @@
#include "components/safe_browsing/core/browser/password_protection/metrics_util.h"
#include "components/safe_browsing/core/browser/password_protection/password_protection_service_base.h"
#include "components/safe_browsing/core/common/proto/csd.pb.h"
+#include "content/public/browser/commit_deferring_condition.h"
#include "mojo/public/cpp/bindings/remote.h"
namespace content {
@@ -24,7 +25,7 @@ class GURL;
namespace safe_browsing {
-class PasswordProtectionNavigationThrottle;
+class PasswordProtectionCommitDeferringCondition;
class PasswordProtectionRequest;
using ReusedPasswordAccountType =
@@ -88,7 +89,7 @@ class PasswordProtectionService : public PasswordProtectionServiceBase {
ReusedPasswordAccountType password_type,
content::WebContents* web_contents) = 0;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Returns the referring app info that starts the activity.
virtual LoginReputationClientRequest::ReferringAppInfo GetReferringAppInfo(
content::WebContents* web_contents) = 0;
@@ -102,18 +103,19 @@ class PasswordProtectionService : public PasswordProtectionServiceBase {
mojo::Remote<mojom::PhishingDetector>* phishing_detector);
#endif
- // Called when a new navigation is starting. Create throttle if there is a
- // pending sync password reuse ping or if there is a modal warning dialog
- // showing in the corresponding web contents.
- std::unique_ptr<PasswordProtectionNavigationThrottle>
- MaybeCreateNavigationThrottle(content::NavigationHandle* navigation_handle);
+ // Called when a new navigation is starting to create a deferring condition
+ // if there is a pending sync password reuse ping or if there is a modal
+ // warning dialog showing in the corresponding web contents.
+ std::unique_ptr<PasswordProtectionCommitDeferringCondition>
+ MaybeCreateCommitDeferringCondition(
+ content::NavigationHandle& navigation_handle);
protected:
void RemoveWarningRequestsByWebContents(content::WebContents* web_contents);
bool IsModalWarningShowingInWebContents(content::WebContents* web_contents);
- void MaybeHandleDeferredNavigations(
+ void ResumeDeferredNavigationsIfNeeded(
PasswordProtectionRequest* request) override;
};
diff --git a/chromium/components/safe_browsing/content/browser/password_protection/password_protection_service_unittest.cc b/chromium/components/safe_browsing/content/browser/password_protection/password_protection_service_unittest.cc
index 383c37f66f4..23b0ffed5b0 100644
--- a/chromium/components/safe_browsing/content/browser/password_protection/password_protection_service_unittest.cc
+++ b/chromium/components/safe_browsing/content/browser/password_protection/password_protection_service_unittest.cc
@@ -24,12 +24,14 @@
#include "base/test/scoped_feature_list.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
+#include "base/values.h"
#include "build/build_config.h"
#include "components/content_settings/core/browser/host_content_settings_map.h"
+#include "components/content_settings/core/common/content_settings_utils.h"
#include "components/password_manager/core/browser/password_manager_metrics_util.h"
#include "components/password_manager/core/browser/password_reuse_detector.h"
#include "components/safe_browsing/content/browser/password_protection/mock_password_protection_service.h"
-#include "components/safe_browsing/content/browser/password_protection/password_protection_navigation_throttle.h"
+#include "components/safe_browsing/content/browser/password_protection/password_protection_commit_deferring_condition.h"
#include "components/safe_browsing/content/browser/password_protection/password_protection_request_content.h"
#include "components/safe_browsing/content/common/safe_browsing.mojom-forward.h"
#include "components/safe_browsing/content/common/safe_browsing.mojom.h"
@@ -48,6 +50,7 @@
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_task_environment.h"
+#include "content/public/test/mock_navigation_handle.h"
#include "content/public/test/test_browser_context.h"
#include "content/public/test/test_renderer_host.h"
#include "content/public/test/web_contents_tester.h"
@@ -314,8 +317,8 @@ class PasswordProtectionServiceTest : public ::testing::Test {
content_setting_map_->ShutdownOnUIThread();
}
- size_t GetNumberOfNavigationThrottles() {
- return request_ ? request_->throttles_.size() : 0u;
+ size_t GetNumberOfDeferredNavigations() {
+ return request_ ? request_->deferred_navigations_.size() : 0u;
}
// |task_environment_| is needed here because this test involves both UI and
@@ -333,23 +336,38 @@ class PasswordProtectionServiceTest : public ::testing::Test {
};
TEST_F(PasswordProtectionServiceTest,
- VerifyNavigationThrottleNotRemovedWhenCanceledOnTimeout) {
+ VerifyCommitDeferringConditionNotRemovedWhenCanceledOnTimeout) {
request_->Start();
- auto throttle = std::make_unique<PasswordProtectionNavigationThrottle>(
- nullptr, request_, false);
- EXPECT_EQ(1U, GetNumberOfNavigationThrottles());
+ content::MockNavigationHandle mock_handle;
+ auto condition = std::make_unique<PasswordProtectionCommitDeferringCondition>(
+ mock_handle, request_);
+ EXPECT_EQ(1U, GetNumberOfDeferredNavigations());
request_->Cancel(/*timed_out=*/true);
- EXPECT_EQ(1U, GetNumberOfNavigationThrottles());
+ EXPECT_EQ(1U, GetNumberOfDeferredNavigations());
}
TEST_F(PasswordProtectionServiceTest,
- VerifyNavigationThrottleRemovedWhenCanceledNotOnTimeout) {
+ VerifyCommitDeferringConditionRemovedWhenCanceledNotOnTimeout) {
request_->Start();
- auto throttle = std::make_unique<PasswordProtectionNavigationThrottle>(
- nullptr, request_, false);
- EXPECT_EQ(1U, GetNumberOfNavigationThrottles());
+ content::MockNavigationHandle mock_handle;
+ auto condition = std::make_unique<PasswordProtectionCommitDeferringCondition>(
+ mock_handle, request_);
+ EXPECT_EQ(1U, GetNumberOfDeferredNavigations());
request_->Cancel(/*timed_out=*/false);
- EXPECT_EQ(0U, GetNumberOfNavigationThrottles());
+ EXPECT_EQ(0U, GetNumberOfDeferredNavigations());
+}
+
+TEST_F(PasswordProtectionServiceTest, NoSendPingPrivateIpHostname) {
+ EXPECT_CALL(*password_protection_service_, IsPingingEnabled(_, _))
+ .WillRepeatedly(Return(true));
+ ReusedPasswordAccountType reused_password_type;
+ reused_password_type.set_account_type(ReusedPasswordAccountType::GMAIL);
+ EXPECT_FALSE(password_protection_service_->CanSendPing(
+ LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
+ GURL("http://127.0.0.1"), reused_password_type));
+ EXPECT_FALSE(password_protection_service_->CanSendPing(
+ LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
+ GURL("http://192.168.1.1"), reused_password_type));
}
class PasswordProtectionServiceBaseTest
@@ -463,30 +481,25 @@ class PasswordProtectionServiceBaseTest
void CacheInvalidVerdict(ReusedPasswordAccountType password_type) {
GURL invalid_hostname("http://invalid.com");
- std::unique_ptr<base::DictionaryValue> verdict_dictionary =
- base::DictionaryValue::From(content_setting_map_->GetWebsiteSetting(
- invalid_hostname, GURL(), ContentSettingsType::PASSWORD_PROTECTION,
- nullptr));
-
- if (!verdict_dictionary)
- verdict_dictionary = std::make_unique<base::DictionaryValue>();
-
- std::unique_ptr<base::DictionaryValue> invalid_verdict_entry =
- std::make_unique<base::DictionaryValue>();
- invalid_verdict_entry->SetString("invalid", "invalid_string");
-
- std::unique_ptr<base::DictionaryValue> invalid_cache_expression_entry =
- std::make_unique<base::DictionaryValue>();
- invalid_cache_expression_entry->SetKey(
- "invalid_cache_expression",
- base::Value::FromUniquePtrValue(std::move(invalid_verdict_entry)));
- verdict_dictionary->SetKey(
+ base::Value verdict_dictionary = content_setting_map_->GetWebsiteSetting(
+ invalid_hostname, GURL(), ContentSettingsType::PASSWORD_PROTECTION,
+ nullptr);
+
+ if (!verdict_dictionary.is_dict())
+ verdict_dictionary = base::Value(base::Value::Type::DICTIONARY);
+
+ base::Value invalid_verdict_entry(base::Value::Type::DICTIONARY);
+ invalid_verdict_entry.SetStringKey("invalid", "invalid_string");
+
+ base::Value invalid_cache_expression_entry(base::Value::Type::DICTIONARY);
+ invalid_cache_expression_entry.SetKey("invalid_cache_expression",
+ std::move(invalid_verdict_entry));
+ verdict_dictionary.SetKey(
base::NumberToString(static_cast<std::underlying_type_t<PasswordType>>(
password_protection_service_
->ConvertReusedPasswordAccountTypeToPasswordType(
password_type))),
- base::Value::FromUniquePtrValue(
- std::move(invalid_cache_expression_entry)));
+ std::move(invalid_cache_expression_entry));
content_setting_map_->SetWebsiteSettingDefaultScope(
invalid_hostname, GURL(), ContentSettingsType::PASSWORD_PROTECTION,
std::move(verdict_dictionary));
@@ -512,7 +525,7 @@ class PasswordProtectionServiceBaseTest
}
// Visual features are not supported on Android.
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
void VerifyContentAreaSizeCollection(
const LoginReputationClientRequest& request) {
bool should_report_content_size =
@@ -934,7 +947,7 @@ TEST_P(PasswordProtectionServiceBaseTest, TestNoRequestSentForAllowlistedURL) {
}
// crbug.com/1010007: crashes on win
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#define MAYBE_TestNoRequestSentIfVerdictAlreadyCached \
DISABLED_TestNoRequestSentIfVerdictAlreadyCached
#else
@@ -1235,7 +1248,7 @@ TEST_P(PasswordProtectionServiceBaseTest, VerifyPasswordOnFocusRequestProto) {
EXPECT_EQ(true, actual_request->frames(1).has_password_field());
ASSERT_EQ(1, actual_request->frames(1).forms_size());
EXPECT_EQ(kFormActionUrl, actual_request->frames(1).forms(0).action_url());
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
VerifyContentAreaSizeCollection(*actual_request);
#endif
}
@@ -1292,7 +1305,7 @@ TEST_P(PasswordProtectionServiceBaseTest,
const auto& reuse_event = actual_request->password_reuse_event();
EXPECT_TRUE(reuse_event.is_chrome_signin_password());
EXPECT_EQ(0, reuse_event.domains_matching_password_size());
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
VerifyContentAreaSizeCollection(*actual_request);
#endif
}
@@ -1332,7 +1345,7 @@ TEST_P(PasswordProtectionServiceBaseTest,
} else {
EXPECT_EQ(0, reuse_event.domains_matching_password_size());
}
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
VerifyContentAreaSizeCollection(*actual_request);
#endif
}
@@ -1389,9 +1402,9 @@ TEST_P(PasswordProtectionServiceBaseTest, VerifyShouldShowModalWarning) {
reused_password_account_type.set_account_type(
ReusedPasswordAccountType::GMAIL);
reused_password_account_type.set_is_account_syncing(false);
-// Currently password reuse warnings are only supported for saved passwords on
-// Android.
-#if defined(OS_ANDROID)
+// Currently password reuse warnings are not supported for non-sync gaia
+// passwords on Android.
+#if BUILDFLAG(IS_ANDROID)
EXPECT_FALSE(password_protection_service_->ShouldShowModalWarning(
#else
EXPECT_TRUE(password_protection_service_->ShouldShowModalWarning(
@@ -1424,18 +1437,23 @@ TEST_P(PasswordProtectionServiceBaseTest, VerifyShouldShowModalWarning) {
}
{
+ // TODO(crbug.com/1237388): Remove it once the flag is completed removed.
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndDisableFeature(
+ safe_browsing::kPasswordProtectionForSignedInUsers);
+
reused_password_account_type.set_account_type(
ReusedPasswordAccountType::GMAIL);
reused_password_account_type.set_is_account_syncing(true);
// If kPasswordProtectionForSignedInUsers is disabled, then GMAIL password
// reuse warnings are only supported on desktop platforms.
-#if defined(OS_ANDROID)
- EXPECT_FALSE(password_protection_service_->ShouldShowModalWarning(
+#if BUILDFLAG(IS_ANDROID)
+ EXPECT_FALSE(password_protection_service_->ShouldShowModalWarning(
#else
EXPECT_TRUE(password_protection_service_->ShouldShowModalWarning(
#endif
- LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
- reused_password_account_type, LoginReputationClientResponse::PHISHING));
+ LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
+ reused_password_account_type, LoginReputationClientResponse::PHISHING));
}
// For a GSUITE account, don't show warning if password protection is set to
@@ -1458,9 +1476,9 @@ TEST_P(PasswordProtectionServiceBaseTest, VerifyShouldShowModalWarning) {
PHISHING_REUSE,
password_protection_service_->GetPasswordProtectionWarningTriggerPref(
reused_password_account_type));
-// Currently password reuse warnings are only supported for saved passwords on
+// Currently password reuse warnings are not supported for GSUITE passwords on
// Android.
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
EXPECT_FALSE(password_protection_service_->ShouldShowModalWarning(
#else
EXPECT_TRUE(password_protection_service_->ShouldShowModalWarning(
@@ -1469,9 +1487,9 @@ TEST_P(PasswordProtectionServiceBaseTest, VerifyShouldShowModalWarning) {
reused_password_account_type, LoginReputationClientResponse::PHISHING));
// Modal dialog warning is also shown on LOW_REPUTATION verdict.
-// Currently password reuse warnings are only supported for saved passwords on
+// Currently password reuse warnings are not supported for GSUITE passwords on
// Android.
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
EXPECT_FALSE(password_protection_service_->ShouldShowModalWarning(
#else
EXPECT_TRUE(password_protection_service_->ShouldShowModalWarning(
@@ -1496,9 +1514,9 @@ TEST_P(PasswordProtectionServiceBaseTest, VerifyShouldShowModalWarning) {
EXPECT_CALL(*password_protection_service_,
GetPasswordProtectionWarningTriggerPref(_))
.WillRepeatedly(Return(PHISHING_REUSE));
-// Currently password reuse warnings are only supported for saved passwords on
-// Android.
-#if defined(OS_ANDROID)
+// Currently password reuse warnings are not supported for enterprise passwords
+// on Android.
+#if BUILDFLAG(IS_ANDROID)
EXPECT_FALSE(password_protection_service_->ShouldShowModalWarning(
#else
EXPECT_TRUE(password_protection_service_->ShouldShowModalWarning(
@@ -1543,13 +1561,8 @@ TEST_P(PasswordProtectionServiceBaseTest,
EXPECT_TRUE(password_protection_service_->IsSupportedPasswordTypeForPinging(
PasswordType::PRIMARY_ACCOUNT_PASSWORD));
-#if defined(OS_ANDROID)
- EXPECT_FALSE(password_protection_service_->IsSupportedPasswordTypeForPinging(
- PasswordType::OTHER_GAIA_PASSWORD));
-#else
EXPECT_TRUE(password_protection_service_->IsSupportedPasswordTypeForPinging(
PasswordType::OTHER_GAIA_PASSWORD));
-#endif
EXPECT_TRUE(password_protection_service_->IsSupportedPasswordTypeForPinging(
PasswordType::ENTERPRISE_PASSWORD));
EXPECT_TRUE(password_protection_service_->IsSupportedPasswordTypeForPinging(
@@ -1581,7 +1594,7 @@ TEST_P(PasswordProtectionServiceBaseTest, TestPingsForAboutBlank) {
}
// DOM features and visual features are not supported on Android.
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
TEST_P(PasswordProtectionServiceBaseTest,
TestVisualFeaturesPopulatedInOnFocusPing) {
LoginReputationClientResponse expected_response =
diff --git a/chromium/components/safe_browsing/content/browser/safe_browsing_blocking_page.cc b/chromium/components/safe_browsing/content/browser/safe_browsing_blocking_page.cc
index 48b340fc0c9..1d4c5f0e1ec 100644
--- a/chromium/components/safe_browsing/content/browser/safe_browsing_blocking_page.cc
+++ b/chromium/components/safe_browsing/content/browser/safe_browsing_blocking_page.cc
@@ -37,29 +37,6 @@ using security_interstitials::SecurityInterstitialControllerClient;
namespace safe_browsing {
-namespace {
-
-SafeBrowsingMetricsCollector::EventType GetEventTypeFromThreatSource(
- ThreatSource threat_source) {
- switch (threat_source) {
- case ThreatSource::LOCAL_PVER4:
- case ThreatSource::REMOTE:
- return SafeBrowsingMetricsCollector::EventType::
- DATABASE_INTERSTITIAL_BYPASS;
- case ThreatSource::CLIENT_SIDE_DETECTION:
- return SafeBrowsingMetricsCollector::EventType::CSD_INTERSTITIAL_BYPASS;
- case ThreatSource::REAL_TIME_CHECK:
- return SafeBrowsingMetricsCollector::EventType::
- REAL_TIME_INTERSTITIAL_BYPASS;
- default:
- NOTREACHED() << "Unexpected threat source.";
- return SafeBrowsingMetricsCollector::EventType::
- DATABASE_INTERSTITIAL_BYPASS;
- }
-}
-
-} // namespace
-
// static
const security_interstitials::SecurityInterstitialPage::TypeID
SafeBrowsingBlockingPage::kTypeForTesting =
@@ -76,6 +53,8 @@ SafeBrowsingBlockingPage::SafeBrowsingBlockingPage(
const BaseSafeBrowsingErrorUI::SBErrorDisplayOptions& display_options,
bool should_trigger_reporting,
history::HistoryService* history_service,
+ base::RepeatingCallback<ChromeUserPopulation()>
+ get_user_population_callback,
SafeBrowsingNavigationObserverManager* navigation_observer_manager,
SafeBrowsingMetricsCollector* metrics_collector,
TriggerManager* trigger_manager,
@@ -89,6 +68,7 @@ SafeBrowsingBlockingPage::SafeBrowsingBlockingPage(
threat_details_in_progress_(false),
threat_source_(unsafe_resources[0].threat_source),
history_service_(history_service),
+ get_user_population_callback_(get_user_population_callback),
navigation_observer_manager_(navigation_observer_manager),
metrics_collector_(metrics_collector),
trigger_manager_(trigger_manager) {
@@ -123,7 +103,7 @@ SafeBrowsingBlockingPage::SafeBrowsingBlockingPage(
trigger_manager_->StartCollectingThreatDetails(
TriggerType::SECURITY_INTERSTITIAL, web_contents,
unsafe_resources[0], url_loader_factory, history_service_,
- navigation_observer_manager_,
+ get_user_population_callback_, navigation_observer_manager_,
sb_error_ui()->get_error_display_options());
}
}
@@ -147,8 +127,7 @@ void SafeBrowsingBlockingPage::OnInterstitialClosing() {
OnDontProceedDone();
} else {
if (metrics_collector_) {
- metrics_collector_->AddSafeBrowsingEventToPref(
- GetEventTypeFromThreatSource(threat_source_));
+ metrics_collector_->AddBypassEventToPref(threat_source_);
}
}
BaseBlockingPage::OnInterstitialClosing();
diff --git a/chromium/components/safe_browsing/content/browser/safe_browsing_blocking_page.h b/chromium/components/safe_browsing/content/browser/safe_browsing_blocking_page.h
index 644b7bb79fb..e9732302626 100644
--- a/chromium/components/safe_browsing/content/browser/safe_browsing_blocking_page.h
+++ b/chromium/components/safe_browsing/content/browser/safe_browsing_blocking_page.h
@@ -34,6 +34,7 @@
#include "base/memory/raw_ptr.h"
#include "components/safe_browsing/content/browser/base_blocking_page.h"
#include "components/safe_browsing/content/browser/base_ui_manager.h"
+#include "components/safe_browsing/core/common/proto/csd.pb.h"
namespace history {
class HistoryService;
@@ -111,6 +112,8 @@ class SafeBrowsingBlockingPage : public BaseBlockingPage {
const BaseSafeBrowsingErrorUI::SBErrorDisplayOptions& display_options,
bool should_trigger_reporting,
history::HistoryService* history_service,
+ base::RepeatingCallback<ChromeUserPopulation()>
+ get_user_population_callback,
SafeBrowsingNavigationObserverManager* navigation_observer_manager,
SafeBrowsingMetricsCollector* metrics_collector,
TriggerManager* trigger_manager,
@@ -137,6 +140,7 @@ class SafeBrowsingBlockingPage : public BaseBlockingPage {
private:
raw_ptr<history::HistoryService> history_service_ = nullptr;
+ base::RepeatingCallback<ChromeUserPopulation()> get_user_population_callback_;
raw_ptr<SafeBrowsingNavigationObserverManager> navigation_observer_manager_ =
nullptr;
raw_ptr<SafeBrowsingMetricsCollector> metrics_collector_ = nullptr;
diff --git a/chromium/components/safe_browsing/content/browser/safe_browsing_navigation_observer.cc b/chromium/components/safe_browsing/content/browser/safe_browsing_navigation_observer.cc
index 4720f42b21d..82c56c25f30 100644
--- a/chromium/components/safe_browsing/content/browser/safe_browsing_navigation_observer.cc
+++ b/chromium/components/safe_browsing/content/browser/safe_browsing_navigation_observer.cc
@@ -35,7 +35,6 @@ NavigationEvent::NavigationEvent()
original_request_url(),
source_tab_id(SessionID::InvalidValue()),
target_tab_id(SessionID::InvalidValue()),
- frame_id(content::RenderFrameHost::kNoFrameTreeNodeId),
last_updated(base::Time::Now()),
navigation_initiation(ReferrerChainEntry::UNDEFINED),
has_committed(false),
@@ -48,7 +47,6 @@ NavigationEvent::NavigationEvent(NavigationEvent&& nav_event)
server_redirect_urls(std::move(nav_event.server_redirect_urls)),
source_tab_id(std::move(nav_event.source_tab_id)),
target_tab_id(std::move(nav_event.target_tab_id)),
- frame_id(nav_event.frame_id),
last_updated(nav_event.last_updated),
navigation_initiation(nav_event.navigation_initiation),
has_committed(nav_event.has_committed),
@@ -63,7 +61,6 @@ NavigationEvent& NavigationEvent::operator=(NavigationEvent&& nav_event) {
original_request_url = std::move(nav_event.original_request_url);
source_tab_id = nav_event.source_tab_id;
target_tab_id = nav_event.target_tab_id;
- frame_id = nav_event.frame_id;
last_updated = nav_event.last_updated;
navigation_initiation = nav_event.navigation_initiation;
has_committed = nav_event.has_committed;
@@ -147,7 +144,6 @@ void SafeBrowsingNavigationObserver::DidStartNavigation(
nav_event.get());
// All the other fields are reconstructed based on current content of
// navigation_handle.
- nav_event->frame_id = navigation_handle->GetFrameTreeNodeId();
SetNavigationSourceUrl(navigation_handle, nav_event.get());
nav_event->original_request_url =
SafeBrowsingNavigationObserverManager::ClearURLRef(
diff --git a/chromium/components/safe_browsing/content/browser/safe_browsing_navigation_observer.h b/chromium/components/safe_browsing/content/browser/safe_browsing_navigation_observer.h
index 061e3603476..0a3a2662293 100644
--- a/chromium/components/safe_browsing/content/browser/safe_browsing_navigation_observer.h
+++ b/chromium/components/safe_browsing/content/browser/safe_browsing_navigation_observer.h
@@ -58,9 +58,6 @@ struct NavigationEvent {
// Which tab this request url is targeting to.
SessionID target_tab_id;
- // Frame tree node ID of the frame where this navigation takes place.
- int frame_id;
-
// When this NavigationEvent was last updated.
base::Time last_updated;
diff --git a/chromium/components/safe_browsing/content/browser/safe_browsing_navigation_observer_manager.cc b/chromium/components/safe_browsing/content/browser/safe_browsing_navigation_observer_manager.cc
index 58abad5e11d..07fc2089f2a 100644
--- a/chromium/components/safe_browsing/content/browser/safe_browsing_navigation_observer_manager.cc
+++ b/chromium/components/safe_browsing/content/browser/safe_browsing_navigation_observer_manager.cc
@@ -633,9 +633,6 @@ void SafeBrowsingNavigationObserverManager::RecordNewWebContents(
nav_event->original_request_url = cleaned_target_url;
nav_event->target_tab_id =
sessions::SessionTabHelper::IdForTab(target_web_contents);
- nav_event->frame_id = source_render_frame_host
- ? source_render_frame_host->GetFrameTreeNodeId()
- : content::RenderFrameHost::kNoFrameTreeNodeId;
nav_event->maybe_launched_by_external_application =
ui::PageTransitionCoreTypeIs(page_transition,
ui::PAGE_TRANSITION_AUTO_TOPLEVEL);
diff --git a/chromium/components/safe_browsing/content/browser/safe_browsing_navigation_observer_unittest.cc b/chromium/components/safe_browsing/content/browser/safe_browsing_navigation_observer_unittest.cc
index 0cca03e98df..f6b0ebaf983 100644
--- a/chromium/components/safe_browsing/content/browser/safe_browsing_navigation_observer_unittest.cc
+++ b/chromium/components/safe_browsing/content/browser/safe_browsing_navigation_observer_unittest.cc
@@ -9,7 +9,6 @@
#include "base/memory/raw_ptr.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
-#include "build/build_config.h"
#include "components/content_settings/core/browser/content_settings_observer.h"
#include "components/content_settings/core/browser/host_content_settings_map.h"
#include "components/safe_browsing/content/browser/safe_browsing_navigation_observer_manager.h"
@@ -30,7 +29,10 @@ namespace safe_browsing {
class SBNavigationObserverTest : public content::RenderViewHostTestHarness {
public:
- SBNavigationObserverTest() {}
+ SBNavigationObserverTest() {
+ scoped_feature_list_.InitAndEnableFeature(
+ kOmitNonUserGesturesFromReferrerChain);
+ }
SBNavigationObserverTest(const SBNavigationObserverTest&) = delete;
SBNavigationObserverTest& operator=(const SBNavigationObserverTest&) = delete;
@@ -50,9 +52,6 @@ class SBNavigationObserverTest : public content::RenderViewHostTestHarness {
navigation_observer_ =
new SafeBrowsingNavigationObserver(web_contents(), settings_map_.get(),
navigation_observer_manager_.get());
-
- scoped_feature_list_.InitAndEnableFeature(
- kOmitNonUserGesturesFromReferrerChain);
}
void TearDown() override {
delete navigation_observer_;
@@ -185,6 +184,8 @@ class SBNavigationObserverTest : public content::RenderViewHostTestHarness {
std::unique_ptr<SafeBrowsingNavigationObserverManager>
navigation_observer_manager_;
raw_ptr<SafeBrowsingNavigationObserver> navigation_observer_;
+
+ private:
base::test::ScopedFeatureList scoped_feature_list_;
};
@@ -449,13 +450,7 @@ TEST_F(SBNavigationObserverTest, TestCleanUpStaleUserGestures) {
EXPECT_EQ(now, (*user_gesture_map())[content0]);
}
-// TODO(crbug.com/1278500): Flaky on Linux TSAN
-#if defined(OS_LINUX) && defined(THREAD_SANITIZER)
-#define MAYBE_TestCleanUpStaleIPAddresses DISABLED_TestCleanUpStaleIPAddresses
-#else
-#define MAYBE_TestCleanUpStaleIPAddresses TestCleanUpStaleIPAddresses
-#endif
-TEST_F(SBNavigationObserverTest, MAYBE_TestCleanUpStaleIPAddresses) {
+TEST_F(SBNavigationObserverTest, TestCleanUpStaleIPAddresses) {
// Sets up host_to_ip_map() such that it includes fresh, stale and invalid
// user gestures.
base::Time now = base::Time::Now(); // Fresh
@@ -486,13 +481,7 @@ TEST_F(SBNavigationObserverTest, MAYBE_TestCleanUpStaleIPAddresses) {
EXPECT_EQ(now, (*host_to_ip_map())[host_0].front().timestamp);
}
-// TODO(crbug.com/1278500): Flaky on Linux TSAN
-#if defined(OS_LINUX) && defined(THREAD_SANITIZER)
-#define MAYBE_TestRecordHostToIpMapping DISABLED_TestRecordHostToIpMapping
-#else
-#define MAYBE_TestRecordHostToIpMapping TestRecordHostToIpMapping
-#endif
-TEST_F(SBNavigationObserverTest, MAYBE_TestRecordHostToIpMapping) {
+TEST_F(SBNavigationObserverTest, TestRecordHostToIpMapping) {
// Setup host_to_ip_map().
base::Time now = base::Time::Now(); // Fresh
base::Time one_hour_ago =
@@ -642,16 +631,8 @@ TEST_F(SBNavigationObserverTest,
EXPECT_EQ(GURL("http://A.com"), referrer_chain[11].referrer_url());
}
-// TODO(crbug.com/1278500): Flaky on Linux TSAN
-#if defined(OS_LINUX) && defined(THREAD_SANITIZER)
-#define MAYBE_RemoveNonUserGestureEntriesWithExcessiveUserGestureEvents \
- DISABLED_RemoveNonUserGestureEntriesWithExcessiveUserGestureEvents
-#else
-#define MAYBE_RemoveNonUserGestureEntriesWithExcessiveUserGestureEvents \
- RemoveNonUserGestureEntriesWithExcessiveUserGestureEvents
-#endif
TEST_F(SBNavigationObserverTest,
- MAYBE_RemoveNonUserGestureEntriesWithExcessiveUserGestureEvents) {
+ RemoveNonUserGestureEntriesWithExcessiveUserGestureEvents) {
GURL url = GURL("http://A.com");
base::Time half_hour_ago =
base::Time::FromDoubleT(base::Time::Now().ToDoubleT() - 30.0 * 60.0);
@@ -708,13 +689,7 @@ TEST_F(SBNavigationObserverTest, RemoveMiddleReferrerChains) {
EXPECT_EQ(GURL("http://A.com"), referrer_chain[11].referrer_url());
}
-// TODO(crbug.com/1278500): Flaky on Linux TSAN
-#if defined(OS_LINUX) && defined(THREAD_SANITIZER)
-#define MAYBE_ChainWorksThroughNewTab DISABLED_ChainWorksThroughNewTab
-#else
-#define MAYBE_ChainWorksThroughNewTab ChainWorksThroughNewTab
-#endif
-TEST_F(SBNavigationObserverTest, MAYBE_ChainWorksThroughNewTab) {
+TEST_F(SBNavigationObserverTest, ChainWorksThroughNewTab) {
base::Time now = base::Time::Now();
base::Time one_hour_ago =
base::Time::FromDoubleT(now.ToDoubleT() - 60.0 * 60.0);
@@ -831,15 +806,7 @@ TEST_F(SBNavigationObserverTest,
EXPECT_TRUE(referrer_chain[0].is_retargeting());
}
-// TODO(crbug.com/1278500): Flaky on Linux TSAN
-#if defined(OS_LINUX) && defined(THREAD_SANITIZER)
-#define MAYBE_TestGetLatestPendingNavigationEvent \
- DISABLED_TestGetLatestPendingNavigationEvent
-#else
-#define MAYBE_TestGetLatestPendingNavigationEvent \
- TestGetLatestPendingNavigationEvent
-#endif
-TEST_F(SBNavigationObserverTest, MAYBE_TestGetLatestPendingNavigationEvent) {
+TEST_F(SBNavigationObserverTest, TestGetLatestPendingNavigationEvent) {
base::Time now = base::Time::Now();
base::Time one_minute_ago = base::Time::FromDoubleT(now.ToDoubleT() - 60.0);
base::Time two_minute_ago = base::Time::FromDoubleT(now.ToDoubleT() - 120.0);
diff --git a/chromium/components/safe_browsing/content/browser/safe_browsing_service_interface.h b/chromium/components/safe_browsing/content/browser/safe_browsing_service_interface.h
index 16e3cae5480..0dcbb2f0d2c 100644
--- a/chromium/components/safe_browsing/content/browser/safe_browsing_service_interface.h
+++ b/chromium/components/safe_browsing/content/browser/safe_browsing_service_interface.h
@@ -46,7 +46,7 @@ class SafeBrowsingServiceInterface
virtual ReferrerChainProvider* GetReferrerChainProviderFromBrowserContext(
content::BrowserContext* browser_context) = 0;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
virtual LoginReputationClientRequest::ReferringAppInfo GetReferringAppInfo(
content::WebContents* web_contents) = 0;
#endif
diff --git a/chromium/components/safe_browsing/content/browser/threat_details.cc b/chromium/components/safe_browsing/content/browser/threat_details.cc
index 5ccc75cc2f5..e25299110b9 100644
--- a/chromium/components/safe_browsing/content/browser/threat_details.cc
+++ b/chromium/components/safe_browsing/content/browser/threat_details.cc
@@ -330,6 +330,8 @@ class ThreatDetailsFactoryImpl : public ThreatDetailsFactory {
const security_interstitials::UnsafeResource& unsafe_resource,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
history::HistoryService* history_service,
+ base::RepeatingCallback<ChromeUserPopulation()>
+ get_user_population_callback,
ReferrerChainProvider* referrer_chain_provider,
bool trim_to_ad_tags,
ThreatDetailsDoneCallback done_callback) override {
@@ -338,8 +340,8 @@ class ThreatDetailsFactoryImpl : public ThreatDetailsFactory {
// used.
auto threat_details = base::WrapUnique(new ThreatDetails(
ui_manager, web_contents, unsafe_resource, url_loader_factory,
- history_service, referrer_chain_provider, trim_to_ad_tags,
- std::move(done_callback)));
+ history_service, get_user_population_callback, referrer_chain_provider,
+ trim_to_ad_tags, std::move(done_callback)));
threat_details->StartCollection();
return threat_details;
}
@@ -361,6 +363,8 @@ std::unique_ptr<ThreatDetails> ThreatDetails::NewThreatDetails(
const UnsafeResource& resource,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
history::HistoryService* history_service,
+ base::RepeatingCallback<ChromeUserPopulation()>
+ get_user_population_callback,
ReferrerChainProvider* referrer_chain_provider,
bool trim_to_ad_tags,
ThreatDetailsDoneCallback done_callback) {
@@ -370,7 +374,8 @@ std::unique_ptr<ThreatDetails> ThreatDetails::NewThreatDetails(
factory_ = g_threat_details_factory_impl.Pointer();
return factory_->CreateThreatDetails(
ui_manager, web_contents, resource, url_loader_factory, history_service,
- referrer_chain_provider, trim_to_ad_tags, std::move(done_callback));
+ get_user_population_callback, referrer_chain_provider, trim_to_ad_tags,
+ std::move(done_callback));
}
// Create a ThreatDetails for the given tab. Runs in the UI thread.
@@ -380,6 +385,8 @@ ThreatDetails::ThreatDetails(
const UnsafeResource& resource,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
history::HistoryService* history_service,
+ base::RepeatingCallback<ChromeUserPopulation()>
+ get_user_population_callback,
ReferrerChainProvider* referrer_chain_provider,
bool trim_to_ad_tags,
ThreatDetailsDoneCallback done_callback)
@@ -388,16 +395,17 @@ ThreatDetails::ThreatDetails(
ui_manager_(ui_manager),
browser_context_(web_contents->GetBrowserContext()),
resource_(resource),
+ get_user_population_callback_(get_user_population_callback),
referrer_chain_provider_(referrer_chain_provider),
cache_result_(false),
did_proceed_(false),
num_visits_(0),
trim_to_ad_tags_(trim_to_ad_tags),
- cache_collector_(new ThreatDetailsCacheCollector),
+ cache_collector_(std::make_unique<ThreatDetailsCacheCollector>()),
done_callback_(std::move(done_callback)),
all_done_expected_(false),
is_all_done_(false) {
- redirects_collector_ = new ThreatDetailsRedirectsCollector(
+ redirects_collector_ = std::make_unique<ThreatDetailsRedirectsCollector>(
history_service ? history_service->AsWeakPtr()
: base::WeakPtr<history::HistoryService>());
}
@@ -412,9 +420,7 @@ ThreatDetails::ThreatDetails()
all_done_expected_(false),
is_all_done_(false) {}
-ThreatDetails::~ThreatDetails() {
- DCHECK_EQ(all_done_expected_, is_all_done_);
-}
+ThreatDetails::~ThreatDetails() = default;
bool ThreatDetails::IsReportableUrl(const GURL& url) const {
// TODO(panayiotis): also skip internal urls.
@@ -855,6 +861,10 @@ void ThreatDetails::OnCacheCollectionReady() {
report_->mutable_client_properties()->set_url_api_type(
GetUrlApiTypeForThreatSource(resource_.threat_source));
+ if (!get_user_population_callback_.is_null()) {
+ *report_->mutable_population() = get_user_population_callback_.Run();
+ }
+
// Fill the referrer chain if applicable.
MaybeFillReferrerChain();
diff --git a/chromium/components/safe_browsing/content/browser/threat_details.h b/chromium/components/safe_browsing/content/browser/threat_details.h
index 316bbecdba6..29932811d9e 100644
--- a/chromium/components/safe_browsing/content/browser/threat_details.h
+++ b/chromium/components/safe_browsing/content/browser/threat_details.h
@@ -87,6 +87,8 @@ class ThreatDetails : public content::WebContentsObserver {
const UnsafeResource& resource,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
history::HistoryService* history_service,
+ base::RepeatingCallback<ChromeUserPopulation()>
+ get_user_population_callback,
ReferrerChainProvider* referrer_chain_provider,
bool trim_to_ad_tags,
ThreatDetailsDoneCallback done_callback);
@@ -107,7 +109,8 @@ class ThreatDetails : public content::WebContentsObserver {
void OnCacheCollectionReady();
- void OnRedirectionCollectionReady();
+ // Overridden during tests
+ virtual void OnRedirectionCollectionReady();
// WebContentsObserver implementation:
void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) override;
@@ -127,6 +130,8 @@ class ThreatDetails : public content::WebContentsObserver {
const UnsafeResource& resource,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
history::HistoryService* history_service,
+ base::RepeatingCallback<ChromeUserPopulation()>
+ get_user_population_callback,
ReferrerChainProvider* referrer_chain_provider,
bool trim_to_ad_tags,
ThreatDetailsDoneCallback done_callback);
@@ -207,6 +212,8 @@ class ThreatDetails : public content::WebContentsObserver {
const UnsafeResource resource_;
+ base::RepeatingCallback<ChromeUserPopulation()> get_user_population_callback_;
+
raw_ptr<ReferrerChainProvider> referrer_chain_provider_;
// For every Url we collect we create a Resource message. We keep
@@ -256,10 +263,10 @@ class ThreatDetails : public content::WebContentsObserver {
static ThreatDetailsFactory* factory_;
// Used to collect details from the HTTP Cache.
- scoped_refptr<ThreatDetailsCacheCollector> cache_collector_;
+ std::unique_ptr<ThreatDetailsCacheCollector> cache_collector_;
// Used to collect redirect urls from the history service
- scoped_refptr<ThreatDetailsRedirectsCollector> redirects_collector_;
+ std::unique_ptr<ThreatDetailsRedirectsCollector> redirects_collector_;
// Callback to run when the report is finished.
ThreatDetailsDoneCallback done_callback_;
@@ -288,6 +295,7 @@ class ThreatDetails : public content::WebContentsObserver {
FRIEND_TEST_ALL_PREFIXES(ThreatDetailsTest, ThreatDOMDetails_MultipleFrames);
FRIEND_TEST_ALL_PREFIXES(ThreatDetailsTest, ThreatDOMDetails_TrimToAdTags);
FRIEND_TEST_ALL_PREFIXES(ThreatDetailsTest, ThreatDOMDetails);
+ FRIEND_TEST_ALL_PREFIXES(ThreatDetailsTest, CanCancelDuringCollection);
};
// Factory for creating ThreatDetails. Useful for tests.
@@ -301,6 +309,8 @@ class ThreatDetailsFactory {
const security_interstitials::UnsafeResource& unsafe_resource,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
history::HistoryService* history_service,
+ base::RepeatingCallback<ChromeUserPopulation()>
+ get_user_population_callback,
ReferrerChainProvider* referrer_chain_provider,
bool trim_to_ad_tags,
ThreatDetailsDoneCallback done_callback) = 0;
diff --git a/chromium/components/safe_browsing/content/browser/threat_details_cache.cc b/chromium/components/safe_browsing/content/browser/threat_details_cache.cc
index 8219b0bea85..1f0a5b14ba2 100644
--- a/chromium/components/safe_browsing/content/browser/threat_details_cache.cc
+++ b/chromium/components/safe_browsing/content/browser/threat_details_cache.cc
@@ -54,7 +54,8 @@ void ThreatDetailsCacheCollector::StartCacheCollection(
// Post a task in the message loop, so the callers don't need to
// check if we call their callback immediately.
content::GetUIThreadTaskRunner({})->PostTask(
- FROM_HERE, base::BindOnce(&ThreatDetailsCacheCollector::OpenEntry, this));
+ FROM_HERE, base::BindOnce(&ThreatDetailsCacheCollector::OpenEntry,
+ weak_factory_.GetWeakPtr()));
}
bool ThreatDetailsCacheCollector::HasStarted() {
@@ -120,6 +121,7 @@ void ThreatDetailsCacheCollector::OpenEntry() {
current_load_->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
url_loader_factory_.get(),
base::BindOnce(&ThreatDetailsCacheCollector::OnURLLoaderComplete,
+ // This is safe because `current_load_` is owned by `this`.
base::Unretained(this)));
}
@@ -229,7 +231,8 @@ void ThreatDetailsCacheCollector::AdvanceEntry() {
// Create a task so we don't take over the UI thread for too long.
content::GetUIThreadTaskRunner({})->PostTask(
- FROM_HERE, base::BindOnce(&ThreatDetailsCacheCollector::OpenEntry, this));
+ FROM_HERE, base::BindOnce(&ThreatDetailsCacheCollector::OpenEntry,
+ weak_factory_.GetWeakPtr()));
}
void ThreatDetailsCacheCollector::AllDone(bool success) {
diff --git a/chromium/components/safe_browsing/content/browser/threat_details_cache.h b/chromium/components/safe_browsing/content/browser/threat_details_cache.h
index 51cb5c7eece..b2ea6795959 100644
--- a/chromium/components/safe_browsing/content/browser/threat_details_cache.h
+++ b/chromium/components/safe_browsing/content/browser/threat_details_cache.h
@@ -31,10 +31,10 @@ typedef std::unordered_map<
std::unique_ptr<ClientSafeBrowsingReportRequest::Resource>>
ResourceMap;
-class ThreatDetailsCacheCollector
- : public base::RefCounted<ThreatDetailsCacheCollector> {
+class ThreatDetailsCacheCollector {
public:
ThreatDetailsCacheCollector();
+ ~ThreatDetailsCacheCollector();
// We use |request_context_getter|, we modify |resources| and
// |result|, and we call |callback|, so they must all remain alive
@@ -55,8 +55,6 @@ class ThreatDetailsCacheCollector
private:
friend class base::RefCounted<ThreatDetailsCacheCollector>;
- ~ThreatDetailsCacheCollector();
-
// Points to the url for which we are fetching the HTTP cache entry or
// redirect chain.
ResourceMap::iterator resources_it_;
@@ -80,6 +78,8 @@ class ThreatDetailsCacheCollector
// The current SimpleURLLoader.
std::unique_ptr<network::SimpleURLLoader> current_load_;
+ base::WeakPtrFactory<ThreatDetailsCacheCollector> weak_factory_{this};
+
// Returns the resource from resources_ that corresponds to |url|
ClientSafeBrowsingReportRequest::Resource* GetResource(const GURL& url);
diff --git a/chromium/components/safe_browsing/content/browser/threat_details_history.cc b/chromium/components/safe_browsing/content/browser/threat_details_history.cc
index 3a36327a341..c71d1555f0c 100644
--- a/chromium/components/safe_browsing/content/browser/threat_details_history.cc
+++ b/chromium/components/safe_browsing/content/browser/threat_details_history.cc
@@ -42,8 +42,8 @@ void ThreatDetailsRedirectsCollector::StartHistoryCollection(
content::GetUIThreadTaskRunner({})->PostTask(
FROM_HERE,
- base::BindOnce(&ThreatDetailsRedirectsCollector::StartGetRedirects, this,
- urls));
+ base::BindOnce(&ThreatDetailsRedirectsCollector::StartGetRedirects,
+ weak_factory_.GetWeakPtr(), urls));
}
bool ThreatDetailsRedirectsCollector::HasStarted() const {
@@ -79,7 +79,7 @@ void ThreatDetailsRedirectsCollector::GetRedirects(const GURL& url) {
history_service_->QueryRedirectsTo(
url,
base::BindOnce(&ThreatDetailsRedirectsCollector::OnGotQueryRedirectsTo,
- base::Unretained(this), url),
+ weak_factory_.GetWeakPtr(), url),
&request_tracker_);
}
diff --git a/chromium/components/safe_browsing/content/browser/threat_details_history.h b/chromium/components/safe_browsing/content/browser/threat_details_history.h
index bddeee82935..670d1b5d74c 100644
--- a/chromium/components/safe_browsing/content/browser/threat_details_history.h
+++ b/chromium/components/safe_browsing/content/browser/threat_details_history.h
@@ -22,12 +22,11 @@ namespace safe_browsing {
typedef std::vector<GURL> RedirectChain;
-class ThreatDetailsRedirectsCollector
- : public base::RefCounted<ThreatDetailsRedirectsCollector>,
- public history::HistoryServiceObserver {
+class ThreatDetailsRedirectsCollector : public history::HistoryServiceObserver {
public:
explicit ThreatDetailsRedirectsCollector(
const base::WeakPtr<history::HistoryService>& history_service);
+ ~ThreatDetailsRedirectsCollector() override;
ThreatDetailsRedirectsCollector(const ThreatDetailsRedirectsCollector&) =
delete;
@@ -52,8 +51,6 @@ class ThreatDetailsRedirectsCollector
private:
friend class base::RefCounted<ThreatDetailsRedirectsCollector>;
- ~ThreatDetailsRedirectsCollector() override;
-
void StartGetRedirects(const std::vector<GURL>& urls);
void GetRedirects(const GURL& url);
void OnGotQueryRedirectsTo(const GURL& url,
@@ -82,6 +79,8 @@ class ThreatDetailsRedirectsCollector
base::ScopedObservation<history::HistoryService,
history::HistoryServiceObserver>
history_service_observation_{this};
+
+ base::WeakPtrFactory<ThreatDetailsRedirectsCollector> weak_factory_{this};
};
} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing/content/browser/triggers/BUILD.gn b/chromium/components/safe_browsing/content/browser/triggers/BUILD.gn
index b7cef3ac77d..d1447798444 100644
--- a/chromium/components/safe_browsing/content/browser/triggers/BUILD.gn
+++ b/chromium/components/safe_browsing/content/browser/triggers/BUILD.gn
@@ -63,6 +63,7 @@ source_set("ad_sampler_trigger") {
"//base:base",
"//components/safe_browsing/core/browser:referrer_chain_provider",
"//components/safe_browsing/core/common",
+ "//components/safe_browsing/core/common/proto:csd_proto",
"//content/public/browser",
]
}
@@ -80,6 +81,7 @@ source_set("suspicious_site_trigger") {
"//components/prefs:prefs",
"//components/safe_browsing/core/browser:referrer_chain_provider",
"//components/safe_browsing/core/common",
+ "//components/safe_browsing/core/common/proto:csd_proto",
"//content/public/browser",
"//net:net",
]
diff --git a/chromium/components/safe_browsing/content/browser/triggers/ad_sampler_trigger.cc b/chromium/components/safe_browsing/content/browser/triggers/ad_sampler_trigger.cc
index e2df179b189..e7b6d9b6932 100644
--- a/chromium/components/safe_browsing/content/browser/triggers/ad_sampler_trigger.cc
+++ b/chromium/components/safe_browsing/content/browser/triggers/ad_sampler_trigger.cc
@@ -85,6 +85,8 @@ AdSamplerTrigger::AdSamplerTrigger(
PrefService* prefs,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
history::HistoryService* history_service,
+ base::RepeatingCallback<ChromeUserPopulation()>
+ get_user_population_callback,
ReferrerChainProvider* referrer_chain_provider)
: content::WebContentsObserver(web_contents),
content::WebContentsUserData<AdSamplerTrigger>(*web_contents),
@@ -97,6 +99,7 @@ AdSamplerTrigger::AdSamplerTrigger(
prefs_(prefs),
url_loader_factory_(url_loader_factory),
history_service_(history_service),
+ get_user_population_callback_(get_user_population_callback),
referrer_chain_provider_(referrer_chain_provider),
task_runner_(content::GetUIThreadTaskRunner({})) {}
@@ -143,7 +146,8 @@ void AdSamplerTrigger::CreateAdSampleReport() {
if (!trigger_manager_->StartCollectingThreatDetails(
TriggerType::AD_SAMPLE, web_contents(), resource, url_loader_factory_,
- history_service_, referrer_chain_provider_, error_options)) {
+ history_service_, get_user_population_callback_,
+ referrer_chain_provider_, error_options)) {
UMA_HISTOGRAM_ENUMERATION(kAdSamplerTriggerActionMetricName,
NO_SAMPLE_COULD_NOT_START_REPORT, MAX_ACTIONS);
return;
diff --git a/chromium/components/safe_browsing/content/browser/triggers/ad_sampler_trigger.h b/chromium/components/safe_browsing/content/browser/triggers/ad_sampler_trigger.h
index b6336dab7d7..59af2aadc94 100644
--- a/chromium/components/safe_browsing/content/browser/triggers/ad_sampler_trigger.h
+++ b/chromium/components/safe_browsing/content/browser/triggers/ad_sampler_trigger.h
@@ -8,6 +8,7 @@
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
+#include "components/safe_browsing/core/common/proto/csd.pb.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_contents_user_data.h"
@@ -82,6 +83,8 @@ class AdSamplerTrigger : public content::WebContentsObserver,
PrefService* prefs,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
history::HistoryService* history_service,
+ base::RepeatingCallback<ChromeUserPopulation()>
+ get_user_population_callback,
ReferrerChainProvider* referrer_chain_provider);
// Called to create an ad sample report.
@@ -113,6 +116,7 @@ class AdSamplerTrigger : public content::WebContentsObserver,
raw_ptr<PrefService> prefs_;
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
raw_ptr<history::HistoryService> history_service_;
+ base::RepeatingCallback<ChromeUserPopulation()> get_user_population_callback_;
raw_ptr<ReferrerChainProvider> referrer_chain_provider_;
// Task runner for posting delayed tasks. Normally set to the runner for the
diff --git a/chromium/components/safe_browsing/content/browser/triggers/ad_sampler_trigger_unittest.cc b/chromium/components/safe_browsing/content/browser/triggers/ad_sampler_trigger_unittest.cc
index 9204c559307..85c8017866a 100644
--- a/chromium/components/safe_browsing/content/browser/triggers/ad_sampler_trigger_unittest.cc
+++ b/chromium/components/safe_browsing/content/browser/triggers/ad_sampler_trigger_unittest.cc
@@ -50,7 +50,8 @@ class AdSamplerTriggerTest : public content::RenderViewHostTestHarness {
void CreateTriggerWithFrequency(const size_t denominator) {
safe_browsing::AdSamplerTrigger::CreateForWebContents(
- web_contents(), &trigger_manager_, &prefs_, nullptr, nullptr, nullptr);
+ web_contents(), &trigger_manager_, &prefs_, nullptr, nullptr,
+ base::NullCallback(), nullptr);
safe_browsing::AdSamplerTrigger* ad_sampler =
safe_browsing::AdSamplerTrigger::FromWebContents(web_contents());
@@ -100,7 +101,7 @@ TEST_F(AdSamplerTriggerTest, TriggerDisabledBySamplingFrequency) {
// zero, which disables the trigger.
CreateTriggerWithFrequency(kAdSamplerFrequencyDisabled);
EXPECT_CALL(*get_trigger_manager(),
- StartCollectingThreatDetails(_, _, _, _, _, _, _))
+ StartCollectingThreatDetails(_, _, _, _, _, _, _, _))
.Times(0);
EXPECT_CALL(*get_trigger_manager(),
FinishCollectingThreatDetails(_, _, _, _, _, _))
@@ -127,7 +128,7 @@ TEST_F(AdSamplerTriggerTest, DISABLED_PageWithNoAds) {
CreateTriggerWithFrequency(/*denominator=*/1);
EXPECT_CALL(*get_trigger_manager(),
- StartCollectingThreatDetails(_, _, _, _, _, _, _))
+ StartCollectingThreatDetails(_, _, _, _, _, _, _, _))
.Times(0);
EXPECT_CALL(*get_trigger_manager(),
FinishCollectingThreatDetails(_, _, _, _, _, _))
@@ -150,7 +151,7 @@ TEST_F(AdSamplerTriggerTest, PageWithMultipleAds) {
CreateTriggerWithFrequency(/*denominator=*/1);
EXPECT_CALL(*get_trigger_manager(),
StartCollectingThreatDetails(TriggerType::AD_SAMPLE,
- web_contents(), _, _, _, _, _))
+ web_contents(), _, _, _, _, _, _))
.Times(2)
.WillRepeatedly(Return(true));
EXPECT_CALL(*get_trigger_manager(),
@@ -183,7 +184,7 @@ TEST_F(AdSamplerTriggerTest, ReportRejectedByTriggerManager) {
CreateTriggerWithFrequency(/*denominator=*/1);
EXPECT_CALL(*get_trigger_manager(),
StartCollectingThreatDetails(TriggerType::AD_SAMPLE,
- web_contents(), _, _, _, _, _))
+ web_contents(), _, _, _, _, _, _))
.Times(1)
.WillOnce(Return(false));
EXPECT_CALL(*get_trigger_manager(),
@@ -215,7 +216,8 @@ TEST(AdSamplerTriggerTestFinch, FrequencyDenominatorFeature) {
// given.
content::BrowserTaskEnvironment task_environment;
AdSamplerTrigger trigger_default(nullptr, nullptr, nullptr, nullptr, nullptr,
- nullptr);
+ base::NullCallback(), nullptr);
+
EXPECT_EQ(kAdSamplerDefaultFrequency,
trigger_default.sampler_frequency_denominator_);
@@ -230,7 +232,7 @@ TEST(AdSamplerTriggerTestFinch, FrequencyDenominatorFeature) {
safe_browsing::kAdSamplerTriggerFeature, feature_params);
AdSamplerTrigger trigger_finch(nullptr, nullptr, nullptr, nullptr, nullptr,
- nullptr);
+ base::NullCallback(), nullptr);
EXPECT_EQ(kDenominatorInt, trigger_finch.sampler_frequency_denominator_);
}
} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing/content/browser/triggers/mock_trigger_manager.h b/chromium/components/safe_browsing/content/browser/triggers/mock_trigger_manager.h
index 46833c4cee5..13a05caab21 100644
--- a/chromium/components/safe_browsing/content/browser/triggers/mock_trigger_manager.h
+++ b/chromium/components/safe_browsing/content/browser/triggers/mock_trigger_manager.h
@@ -21,22 +21,26 @@ class MockTriggerManager : public TriggerManager {
~MockTriggerManager() override;
- MOCK_METHOD7(
+ MOCK_METHOD8(
StartCollectingThreatDetails,
bool(TriggerType trigger_type,
content::WebContents* web_contents,
const security_interstitials::UnsafeResource& resource,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
history::HistoryService* history_service,
+ base::RepeatingCallback<ChromeUserPopulation()>
+ get_user_population_callback,
ReferrerChainProvider* referrer_chain_provider,
const SBErrorOptions& error_display_options));
- MOCK_METHOD8(
+ MOCK_METHOD9(
StartCollectingThreatDetailsWithReason,
bool(TriggerType trigger_type,
content::WebContents* web_contents,
const security_interstitials::UnsafeResource& resource,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
history::HistoryService* history_service,
+ base::RepeatingCallback<ChromeUserPopulation()>
+ get_user_population_callback,
ReferrerChainProvider* referrer_chain_provider,
const SBErrorOptions& error_display_options,
TriggerManagerReason* out_reason));
diff --git a/chromium/components/safe_browsing/content/browser/triggers/suspicious_site_trigger.cc b/chromium/components/safe_browsing/content/browser/triggers/suspicious_site_trigger.cc
index eb0bc72d40f..d4d092faeb6 100644
--- a/chromium/components/safe_browsing/content/browser/triggers/suspicious_site_trigger.cc
+++ b/chromium/components/safe_browsing/content/browser/triggers/suspicious_site_trigger.cc
@@ -61,6 +61,8 @@ SuspiciousSiteTrigger::SuspiciousSiteTrigger(
PrefService* prefs,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
history::HistoryService* history_service,
+ base::RepeatingCallback<ChromeUserPopulation()>
+ get_user_population_callback,
ReferrerChainProvider* referrer_chain_provider,
bool monitor_mode)
: content::WebContentsObserver(web_contents),
@@ -72,6 +74,7 @@ SuspiciousSiteTrigger::SuspiciousSiteTrigger(
prefs_(prefs),
url_loader_factory_(url_loader_factory),
history_service_(history_service),
+ get_user_population_callback_(get_user_population_callback),
referrer_chain_provider_(referrer_chain_provider),
task_runner_(content::GetUIThreadTaskRunner({})) {}
@@ -99,8 +102,8 @@ bool SuspiciousSiteTrigger::MaybeStartReport() {
TriggerManagerReason reason;
if (!trigger_manager_->StartCollectingThreatDetailsWithReason(
TriggerType::SUSPICIOUS_SITE, web_contents(), resource,
- url_loader_factory_, history_service_, referrer_chain_provider_,
- error_options, &reason)) {
+ url_loader_factory_, history_service_, get_user_population_callback_,
+ referrer_chain_provider_, error_options, &reason)) {
UMA_HISTOGRAM_ENUMERATION(kSuspiciousSiteTriggerEventMetricName,
SuspiciousSiteTriggerEvent::REPORT_START_FAILED);
LOCAL_HISTOGRAM_ENUMERATION(
diff --git a/chromium/components/safe_browsing/content/browser/triggers/suspicious_site_trigger.h b/chromium/components/safe_browsing/content/browser/triggers/suspicious_site_trigger.h
index 88c9f90d30c..fc225e43e1c 100644
--- a/chromium/components/safe_browsing/content/browser/triggers/suspicious_site_trigger.h
+++ b/chromium/components/safe_browsing/content/browser/triggers/suspicious_site_trigger.h
@@ -7,6 +7,7 @@
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
+#include "components/safe_browsing/core/common/proto/csd.pb.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_contents_user_data.h"
@@ -131,6 +132,8 @@ class SuspiciousSiteTrigger
PrefService* prefs,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
history::HistoryService* history_service,
+ base::RepeatingCallback<ChromeUserPopulation()>
+ get_user_population_callback,
ReferrerChainProvider* referrer_chain_provider,
bool monitor_mode);
@@ -171,6 +174,7 @@ class SuspiciousSiteTrigger
raw_ptr<PrefService> prefs_;
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
raw_ptr<history::HistoryService> history_service_;
+ base::RepeatingCallback<ChromeUserPopulation()> get_user_population_callback_;
raw_ptr<ReferrerChainProvider> referrer_chain_provider_;
// Task runner for posting delayed tasks. Normally set to the runner for the
diff --git a/chromium/components/safe_browsing/content/browser/triggers/suspicious_site_trigger_unittest.cc b/chromium/components/safe_browsing/content/browser/triggers/suspicious_site_trigger_unittest.cc
index 01c047608a8..db7beb2a06b 100644
--- a/chromium/components/safe_browsing/content/browser/triggers/suspicious_site_trigger_unittest.cc
+++ b/chromium/components/safe_browsing/content/browser/triggers/suspicious_site_trigger_unittest.cc
@@ -55,8 +55,8 @@ class SuspiciousSiteTriggerTest : public content::RenderViewHostTestHarness {
void CreateTrigger(bool monitor_mode) {
safe_browsing::SuspiciousSiteTrigger::CreateForWebContents(
- web_contents(), &trigger_manager_, &prefs_, nullptr, nullptr, nullptr,
- monitor_mode);
+ web_contents(), &trigger_manager_, &prefs_, nullptr, nullptr,
+ base::NullCallback(), nullptr, monitor_mode);
safe_browsing::SuspiciousSiteTrigger* trigger =
safe_browsing::SuspiciousSiteTrigger::FromWebContents(web_contents());
// Give the trigger a test task runner that we can synchronize on.
@@ -172,7 +172,7 @@ TEST_F(SuspiciousSiteTriggerTest, RegularPageNonSuspicious) {
CreateTrigger(/*monitor_mode=*/false);
EXPECT_CALL(*get_trigger_manager(),
- StartCollectingThreatDetailsWithReason(_, _, _, _, _, _, _, _))
+ StartCollectingThreatDetailsWithReason(_, _, _, _, _, _, _, _, _))
.Times(0);
EXPECT_CALL(*get_trigger_manager(),
FinishCollectingThreatDetails(_, _, _, _, _, _))
@@ -193,7 +193,7 @@ TEST_F(SuspiciousSiteTriggerTest, RegularPageNonSuspicious) {
}
// crbug.com/1010037: fails on win.
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#define MAYBE_SuspiciousHitDuringLoad DISABLED_SuspiciousHitDuringLoad
#else
#define MAYBE_SuspiciousHitDuringLoad SuspiciousHitDuringLoad
@@ -204,7 +204,7 @@ TEST_F(SuspiciousSiteTriggerTest, MAYBE_SuspiciousHitDuringLoad) {
CreateTrigger(/*monitor_mode=*/false);
EXPECT_CALL(*get_trigger_manager(),
- StartCollectingThreatDetailsWithReason(_, _, _, _, _, _, _, _))
+ StartCollectingThreatDetailsWithReason(_, _, _, _, _, _, _, _, _))
.Times(1)
.WillOnce(Return(true));
EXPECT_CALL(*get_trigger_manager(),
@@ -242,7 +242,7 @@ TEST_F(SuspiciousSiteTriggerTest, SuspiciousHitAfterLoad) {
CreateTrigger(/*monitor_mode=*/false);
EXPECT_CALL(*get_trigger_manager(),
- StartCollectingThreatDetailsWithReason(_, _, _, _, _, _, _, _))
+ StartCollectingThreatDetailsWithReason(_, _, _, _, _, _, _, _, _))
.Times(1)
.WillOnce(Return(true));
EXPECT_CALL(*get_trigger_manager(),
@@ -279,10 +279,10 @@ TEST_F(SuspiciousSiteTriggerTest, DISABLED_ReportRejectedByTriggerManager) {
CreateTrigger(/*monitor_mode=*/false);
EXPECT_CALL(*get_trigger_manager(),
- StartCollectingThreatDetailsWithReason(_, _, _, _, _, _, _, _))
+ StartCollectingThreatDetailsWithReason(_, _, _, _, _, _, _, _, _))
.Times(1)
.WillOnce(
- DoAll(SetArgPointee<7>(TriggerManagerReason::DAILY_QUOTA_EXCEEDED),
+ DoAll(SetArgPointee<8>(TriggerManagerReason::DAILY_QUOTA_EXCEEDED),
Return(false)));
EXPECT_CALL(*get_trigger_manager(),
FinishCollectingThreatDetails(_, _, _, _, _, _))
@@ -321,7 +321,7 @@ TEST_F(SuspiciousSiteTriggerTest, NewNavigationMidLoad_NotSuspicious) {
CreateTrigger(/*monitor_mode=*/false);
EXPECT_CALL(*get_trigger_manager(),
- StartCollectingThreatDetailsWithReason(_, _, _, _, _, _, _, _))
+ StartCollectingThreatDetailsWithReason(_, _, _, _, _, _, _, _, _))
.Times(0);
EXPECT_CALL(*get_trigger_manager(),
FinishCollectingThreatDetails(_, _, _, _, _, _))
@@ -353,7 +353,7 @@ TEST_F(SuspiciousSiteTriggerTest, DISABLED_NewNavigationMidLoad_Suspicious) {
CreateTrigger(/*monitor_mode=*/false);
EXPECT_CALL(*get_trigger_manager(),
- StartCollectingThreatDetailsWithReason(_, _, _, _, _, _, _, _))
+ StartCollectingThreatDetailsWithReason(_, _, _, _, _, _, _, _, _))
.Times(0);
EXPECT_CALL(*get_trigger_manager(),
FinishCollectingThreatDetails(_, _, _, _, _, _))
@@ -391,7 +391,7 @@ TEST_F(SuspiciousSiteTriggerTest, MonitorMode_NotSuspicious) {
CreateTrigger(/*monitor_mode=*/true);
EXPECT_CALL(*get_trigger_manager(),
- StartCollectingThreatDetailsWithReason(_, _, _, _, _, _, _, _))
+ StartCollectingThreatDetailsWithReason(_, _, _, _, _, _, _, _, _))
.Times(0);
EXPECT_CALL(*get_trigger_manager(),
FinishCollectingThreatDetails(_, _, _, _, _, _))
@@ -418,7 +418,7 @@ TEST_F(SuspiciousSiteTriggerTest, MonitorMode_SuspiciousHitDuringLoad) {
CreateTrigger(/*monitor_mode=*/true);
EXPECT_CALL(*get_trigger_manager(),
- StartCollectingThreatDetailsWithReason(_, _, _, _, _, _, _, _))
+ StartCollectingThreatDetailsWithReason(_, _, _, _, _, _, _, _, _))
.Times(0);
EXPECT_CALL(*get_trigger_manager(),
FinishCollectingThreatDetails(_, _, _, _, _, _))
@@ -454,7 +454,7 @@ TEST_F(SuspiciousSiteTriggerTest, VisibleURLChangeMidLoad_NotSuspicious) {
CreateTrigger(/*monitor_mode=*/false);
EXPECT_CALL(*get_trigger_manager(),
- StartCollectingThreatDetailsWithReason(_, _, _, _, _, _, _, _))
+ StartCollectingThreatDetailsWithReason(_, _, _, _, _, _, _, _, _))
.Times(0);
EXPECT_CALL(*get_trigger_manager(),
FinishCollectingThreatDetails(_, _, _, _, _, _))
@@ -491,7 +491,7 @@ TEST_F(SuspiciousSiteTriggerTest, VisibleURLChangeMidLoad_Suspicious) {
GURL suspicious_url(kSuspiciousUrl);
EXPECT_CALL(*get_trigger_manager(),
StartCollectingThreatDetailsWithReason(
- _, _, ResourceHasUrl(suspicious_url), _, _, _, _, _))
+ _, _, ResourceHasUrl(suspicious_url), _, _, _, _, _, _))
.Times(1)
.WillOnce(Return(true));
EXPECT_CALL(*get_trigger_manager(),
diff --git a/chromium/components/safe_browsing/content/browser/triggers/trigger_manager.cc b/chromium/components/safe_browsing/content/browser/triggers/trigger_manager.cc
index 23197e1ebee..9fe3d39a75e 100644
--- a/chromium/components/safe_browsing/content/browser/triggers/trigger_manager.cc
+++ b/chromium/components/safe_browsing/content/browser/triggers/trigger_manager.cc
@@ -147,12 +147,15 @@ bool TriggerManager::StartCollectingThreatDetails(
const security_interstitials::UnsafeResource& resource,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
history::HistoryService* history_service,
+ base::RepeatingCallback<ChromeUserPopulation()>
+ get_user_population_callback,
ReferrerChainProvider* referrer_chain_provider,
const SBErrorOptions& error_display_options) {
TriggerManagerReason unused_reason;
return StartCollectingThreatDetailsWithReason(
trigger_type, web_contents, resource, url_loader_factory, history_service,
- referrer_chain_provider, error_display_options, &unused_reason);
+ get_user_population_callback, referrer_chain_provider,
+ error_display_options, &unused_reason);
}
bool TriggerManager::StartCollectingThreatDetailsWithReason(
@@ -161,6 +164,8 @@ bool TriggerManager::StartCollectingThreatDetailsWithReason(
const security_interstitials::UnsafeResource& resource,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
history::HistoryService* history_service,
+ base::RepeatingCallback<ChromeUserPopulation()>
+ get_user_population_callback,
ReferrerChainProvider* referrer_chain_provider,
const SBErrorOptions& error_display_options,
TriggerManagerReason* reason) {
@@ -178,7 +183,8 @@ bool TriggerManager::StartCollectingThreatDetailsWithReason(
bool should_trim_threat_details = trigger_type == TriggerType::AD_SAMPLE;
collectors->threat_details = ThreatDetails::NewThreatDetails(
ui_manager_, web_contents, resource, url_loader_factory, history_service,
- referrer_chain_provider, should_trim_threat_details,
+ get_user_population_callback, referrer_chain_provider,
+ should_trim_threat_details,
base::BindOnce(&TriggerManager::ThreatDetailsDone,
weak_factory_.GetWeakPtr()));
return true;
diff --git a/chromium/components/safe_browsing/content/browser/triggers/trigger_manager.h b/chromium/components/safe_browsing/content/browser/triggers/trigger_manager.h
index edb23b7b4d4..d191758b4d4 100644
--- a/chromium/components/safe_browsing/content/browser/triggers/trigger_manager.h
+++ b/chromium/components/safe_browsing/content/browser/triggers/trigger_manager.h
@@ -132,6 +132,8 @@ class TriggerManager {
const security_interstitials::UnsafeResource& resource,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
history::HistoryService* history_service,
+ base::RepeatingCallback<ChromeUserPopulation()>
+ get_user_population_callback,
ReferrerChainProvider* referrer_chain_provider,
const SBErrorOptions& error_display_options,
TriggerManagerReason* out_reason);
@@ -144,6 +146,8 @@ class TriggerManager {
const security_interstitials::UnsafeResource& resource,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
history::HistoryService* history_service,
+ base::RepeatingCallback<ChromeUserPopulation()>
+ get_user_population_callback,
ReferrerChainProvider* referrer_chain_provider,
const SBErrorOptions& error_display_options);
diff --git a/chromium/components/safe_browsing/content/browser/triggers/trigger_manager_unittest.cc b/chromium/components/safe_browsing/content/browser/triggers/trigger_manager_unittest.cc
index 584e35d2f10..a84455b3868 100644
--- a/chromium/components/safe_browsing/content/browser/triggers/trigger_manager_unittest.cc
+++ b/chromium/components/safe_browsing/content/browser/triggers/trigger_manager_unittest.cc
@@ -47,6 +47,8 @@ class MockThreatDetailsFactory : public ThreatDetailsFactory {
const security_interstitials::UnsafeResource& unsafe_resource,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
history::HistoryService* history_service,
+ base::RepeatingCallback<ChromeUserPopulation()>
+ get_user_population_callback,
ReferrerChainProvider* referrer_chain_provider,
bool trim_to_ad_tags,
ThreatDetailsDoneCallback done_callback) override {
@@ -121,7 +123,7 @@ class TriggerManagerTest : public ::testing::Test {
TriggerManager::GetSBErrorDisplayOptions(pref_service_, web_contents);
return trigger_manager_.StartCollectingThreatDetails(
trigger_type, web_contents, security_interstitials::UnsafeResource(),
- nullptr, nullptr, nullptr, options);
+ nullptr, nullptr, base::NullCallback(), nullptr, options);
}
bool FinishCollectingThreatDetails(const TriggerType trigger_type,
diff --git a/chromium/components/safe_browsing/content/browser/triggers/trigger_throttler.cc b/chromium/components/safe_browsing/content/browser/triggers/trigger_throttler.cc
index 2e9741905ac..b203cee28a2 100644
--- a/chromium/components/safe_browsing/content/browser/triggers/trigger_throttler.cc
+++ b/chromium/components/safe_browsing/content/browser/triggers/trigger_throttler.cc
@@ -198,7 +198,7 @@ void TriggerThrottler::LoadTriggerEventsFromPref() {
if (!local_state_prefs_)
return;
- const base::DictionaryValue* event_dict = local_state_prefs_->GetDictionary(
+ const base::Value* event_dict = local_state_prefs_->GetDictionary(
prefs::kSafeBrowsingTriggerEventTimestamps);
for (auto trigger_pair : event_dict->DictItems()) {
// Check that the first item in the pair is convertible to a trigger type
@@ -213,7 +213,7 @@ void TriggerThrottler::LoadTriggerEventsFromPref() {
continue;
const TriggerType trigger_type = static_cast<TriggerType>(trigger_type_int);
- for (const auto& timestamp : trigger_pair.second.GetList()) {
+ for (const auto& timestamp : trigger_pair.second.GetListDeprecated()) {
if (timestamp.is_double())
trigger_events_[trigger_type].push_back(
base::Time::FromDoubleT(timestamp.GetDouble()));
diff --git a/chromium/components/safe_browsing/content/browser/triggers/trigger_throttler_unittest.cc b/chromium/components/safe_browsing/content/browser/triggers/trigger_throttler_unittest.cc
index b4c7ba61cdd..b760b99f777 100644
--- a/chromium/components/safe_browsing/content/browser/triggers/trigger_throttler_unittest.cc
+++ b/chromium/components/safe_browsing/content/browser/triggers/trigger_throttler_unittest.cc
@@ -180,17 +180,17 @@ TEST_F(TriggerThrottlerTest, TriggerQuotaPersistence) {
// Check the pref directly, it should reflect the events for each trigger.
PrefService* prefs = get_pref_service();
- const base::DictionaryValue* event_dict =
+ const base::Value* event_dict =
prefs->GetDictionary(prefs::kSafeBrowsingTriggerEventTimestamps);
const std::string kAdSampleKey = "2";
const base::Value* ad_sample_events = event_dict->FindKey(kAdSampleKey);
- EXPECT_EQ(3u, ad_sample_events->GetList().size());
+ EXPECT_EQ(3u, ad_sample_events->GetListDeprecated().size());
const std::string kSuspiciousSiteKey = "4";
const base::Value* suspicious_site_events =
event_dict->FindKey(kSuspiciousSiteKey);
- EXPECT_EQ(2u, suspicious_site_events->GetList().size());
+ EXPECT_EQ(2u, suspicious_site_events->GetListDeprecated().size());
// To simulate a new startup of the browser, we can create another throttler
// using the same quota configuration and pref store. It should read the
diff --git a/chromium/components/safe_browsing/content/browser/ui_manager.cc b/chromium/components/safe_browsing/content/browser/ui_manager.cc
index 882f1fe0751..b25158c3ffe 100644
--- a/chromium/components/safe_browsing/content/browser/ui_manager.cc
+++ b/chromium/components/safe_browsing/content/browser/ui_manager.cc
@@ -161,7 +161,7 @@ void SafeBrowsingUIManager::StartDisplayingBlockingPage(
// destroyed once the request is failed.
if (resource.IsMainPageLoadBlocked()) {
content::NavigationEntry* entry =
- web_contents->GetController().GetPendingEntry();
+ security_interstitials::GetNavigationEntryForResource(resource);
if (entry) {
security_interstitials::UnsafeResource resource_copy(resource);
resource_copy.navigation_url = entry->GetURL();
@@ -194,17 +194,14 @@ void SafeBrowsingUIManager::MaybeReportSafeBrowsingHit(
if (!ShouldSendHitReport(hit_report, web_contents))
return;
- // The service may delete the ping manager (i.e. when user disabling service,
- // etc). This happens on the IO thread.
- if (shut_down_ || !delegate_->GetPingManagerIfExists())
+ if (shut_down_)
return;
DVLOG(1) << "ReportSafeBrowsingHit: " << hit_report.malicious_url << " "
<< hit_report.page_url << " " << hit_report.referrer_url << " "
<< hit_report.is_subresource << " " << hit_report.threat_type;
- delegate_->GetPingManagerIfExists()->ReportSafeBrowsingHit(
- delegate_->GetURLLoaderFactory(web_contents->GetBrowserContext()),
- hit_report);
+ delegate_->GetPingManager(web_contents->GetBrowserContext())
+ ->ReportSafeBrowsingHit(hit_report);
}
// Static.
@@ -286,15 +283,12 @@ void SafeBrowsingUIManager::SendSerializedThreatDetails(
const std::string& serialized) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- // The service may delete the ping manager (i.e. when user disabling service,
- // etc). This happens on the IO thread.
- if (shut_down_ || !delegate_->GetPingManagerIfExists())
+ if (shut_down_)
return;
if (!serialized.empty()) {
DVLOG(1) << "Sending serialized threat details.";
- delegate_->GetPingManagerIfExists()->ReportThreatDetails(
- delegate_->GetURLLoaderFactory(browser_context), serialized);
+ delegate_->GetPingManager(browser_context)->ReportThreatDetails(serialized);
}
}
diff --git a/chromium/components/safe_browsing/content/browser/ui_manager.h b/chromium/components/safe_browsing/content/browser/ui_manager.h
index 1e859f76b57..bc37f984b99 100644
--- a/chromium/components/safe_browsing/content/browser/ui_manager.h
+++ b/chromium/components/safe_browsing/content/browser/ui_manager.h
@@ -107,12 +107,8 @@ class SafeBrowsingUIManager : public BaseUIManager {
virtual history::HistoryService* GetHistoryService(
content::BrowserContext* browser_context) = 0;
- // Gets the PingManager. This may be null.
- virtual PingManager* GetPingManagerIfExists() = 0;
-
- // Gets the URLLoaderFactory attached to |browser_context|. Guaranteed to be
- // non-null if GetPingManagerIfExists() is non-null.
- virtual scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory(
+ // Gets the PingManager.
+ virtual PingManager* GetPingManager(
content::BrowserContext* browser_context) = 0;
// Returns true if metrics reporting is enabled.
diff --git a/chromium/components/safe_browsing/content/browser/ui_manager_unittest.cc b/chromium/components/safe_browsing/content/browser/ui_manager_unittest.cc
index 12ea2f8756c..a4e16e329f4 100644
--- a/chromium/components/safe_browsing/content/browser/ui_manager_unittest.cc
+++ b/chromium/components/safe_browsing/content/browser/ui_manager_unittest.cc
@@ -122,6 +122,7 @@ class TestSafeBrowsingBlockingPage : public SafeBrowsingBlockingPage {
"cpn_safe_browsing"), // help_center_article_link
true, // should_trigger_reporting
/*history_service=*/nullptr,
+ /*get_user_population_callback=*/base::NullCallback(),
/*navigation_observer_manager=*/nullptr,
/*metrics_collector=*/nullptr,
/*trigger_manager=*/nullptr) {
@@ -184,8 +185,7 @@ class TestSafeBrowsingUIManagerDelegate
content::BrowserContext* browser_context) override {
return nullptr;
}
- PingManager* GetPingManagerIfExists() override { return nullptr; }
- scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory(
+ PingManager* GetPingManager(
content::BrowserContext* browser_context) override {
return nullptr;
}
diff --git a/chromium/components/safe_browsing/content/browser/web_ui/safe_browsing_ui.cc b/chromium/components/safe_browsing/content/browser/web_ui/safe_browsing_ui.cc
index ad32a53cc30..1a5829544ca 100644
--- a/chromium/components/safe_browsing/content/browser/web_ui/safe_browsing_ui.cc
+++ b/chromium/components/safe_browsing/content/browser/web_ui/safe_browsing_ui.cc
@@ -295,14 +295,14 @@ void WebUIInfoSingleton::ClearLogMessages() {
webui_listener->NotifyLogMessageJsListener(timestamp, message);
}
-void WebUIInfoSingleton::AddToReportingEvents(const base::Value& event) {
+void WebUIInfoSingleton::AddToReportingEvents(const base::Value::Dict& event) {
if (!HasListener())
return;
for (auto* webui_listener : webui_instances_)
webui_listener->NotifyReportingEventJsListener(event);
- reporting_events_.push_back(event.Clone());
+ reporting_events_.emplace_back(event.Clone());
}
void WebUIInfoSingleton::ClearReportingEvents() {
@@ -383,7 +383,7 @@ ReferrerChainProvider* WebUIInfoSingleton::GetReferrerChainProvider(
browser_context);
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
LoginReputationClientRequest::ReferringAppInfo
WebUIInfoSingleton::GetReferringAppInfo(content::WebContents* web_contents) {
return sb_service_ ? sb_service_->GetReferringAppInfo(web_contents)
@@ -1150,6 +1150,10 @@ std::string SerializeCSBRR(const ClientSafeBrowsingReportRequest& report) {
report_request.SetBoolean("show_download_in_folder",
report.show_download_in_folder());
}
+ if (report.has_population()) {
+ report_request.SetKey("population",
+ SerializeChromeUserPopulation(report.population()));
+ }
std::string serialized;
if (report.SerializeToString(&serialized)) {
std::string base64_encoded;
@@ -1777,7 +1781,7 @@ base::Value SerializeLogMessage(const base::Time& timestamp,
return std::move(result);
}
-base::Value SerializeReportingEvent(const base::Value& event) {
+base::Value SerializeReportingEvent(const base::Value::Dict& event) {
base::DictionaryValue result;
std::string event_serialized;
@@ -2027,34 +2031,35 @@ void SafeBrowsingUIHandler::OnJavascriptDisallowed() {
WebUIInfoSingleton::GetInstance()->UnregisterWebUIInstance(this);
}
-void SafeBrowsingUIHandler::GetExperiments(const base::ListValue* args) {
+void SafeBrowsingUIHandler::GetExperiments(
+ const base::Value::ConstListView args) {
AllowJavascript();
- DCHECK(!args->GetList().empty());
- std::string callback_id = args->GetList()[0].GetString();
+ DCHECK(!args.empty());
+ std::string callback_id = args[0].GetString();
ResolveJavascriptCallback(base::Value(callback_id), GetFeatureStatusList());
}
-void SafeBrowsingUIHandler::GetPrefs(const base::ListValue* args) {
+void SafeBrowsingUIHandler::GetPrefs(const base::Value::ConstListView args) {
AllowJavascript();
- DCHECK(!args->GetList().empty());
- std::string callback_id = args->GetList()[0].GetString();
+ DCHECK(!args.empty());
+ std::string callback_id = args[0].GetString();
ResolveJavascriptCallback(base::Value(callback_id),
safe_browsing::GetSafeBrowsingPreferencesList(
user_prefs::UserPrefs::Get(browser_context_)));
}
-void SafeBrowsingUIHandler::GetPolicies(const base::ListValue* args) {
+void SafeBrowsingUIHandler::GetPolicies(const base::Value::ConstListView args) {
AllowJavascript();
- DCHECK(!args->GetList().empty());
- std::string callback_id = args->GetList()[0].GetString();
+ DCHECK(!args.empty());
+ std::string callback_id = args[0].GetString();
ResolveJavascriptCallback(base::Value(callback_id),
safe_browsing::GetSafeBrowsingPoliciesList(
user_prefs::UserPrefs::Get(browser_context_)));
}
-void SafeBrowsingUIHandler::GetCookie(const base::ListValue* args) {
- DCHECK(!args->GetList().empty());
- std::string callback_id = args->GetList()[0].GetString();
+void SafeBrowsingUIHandler::GetCookie(const base::Value::ConstListView args) {
+ DCHECK(!args.empty());
+ std::string callback_id = args[0].GetString();
cookie_manager_remote_ =
WebUIInfoSingleton::GetInstance()->GetCookieManager(browser_context_);
@@ -2084,7 +2089,8 @@ void SafeBrowsingUIHandler::OnGetCookie(
base::Value(std::move(response)));
}
-void SafeBrowsingUIHandler::GetSavedPasswords(const base::ListValue* args) {
+void SafeBrowsingUIHandler::GetSavedPasswords(
+ const base::Value::ConstListView args) {
password_manager::HashPasswordManager hash_manager(
user_prefs::UserPrefs::Get(browser_context_));
@@ -2096,13 +2102,13 @@ void SafeBrowsingUIHandler::GetSavedPasswords(const base::ListValue* args) {
}
AllowJavascript();
- DCHECK(!args->GetList().empty());
- std::string callback_id = args->GetList()[0].GetString();
+ DCHECK(!args.empty());
+ std::string callback_id = args[0].GetString();
ResolveJavascriptCallback(base::Value(callback_id), saved_passwords);
}
void SafeBrowsingUIHandler::GetDatabaseManagerInfo(
- const base::ListValue* args) {
+ const base::Value::ConstListView args) {
base::ListValue database_manager_info;
#if BUILDFLAG(SAFE_BROWSING_DB_LOCAL)
@@ -2130,8 +2136,8 @@ void SafeBrowsingUIHandler::GetDatabaseManagerInfo(
#endif
AllowJavascript();
- DCHECK(!args->GetList().empty());
- std::string callback_id = args->GetList()[0].GetString();
+ DCHECK(!args.empty());
+ std::string callback_id = args[0].GetString();
ResolveJavascriptCallback(base::Value(callback_id), database_manager_info);
}
@@ -2204,7 +2210,7 @@ std::string SerializeDownloadUrlChecked(const std::vector<GURL>& urls,
}
void SafeBrowsingUIHandler::GetDownloadUrlsChecked(
- const base::ListValue* args) {
+ const base::Value::ConstListView args) {
const std::vector<std::pair<std::vector<GURL>, DownloadCheckResult>>&
urls_checked = WebUIInfoSingleton::GetInstance()->download_urls_checked();
@@ -2216,13 +2222,13 @@ void SafeBrowsingUIHandler::GetDownloadUrlsChecked(
}
AllowJavascript();
- DCHECK(!args->GetList().empty());
- std::string callback_id = args->GetList()[0].GetString();
+ DCHECK(!args.empty());
+ std::string callback_id = args[0].GetString();
ResolveJavascriptCallback(base::Value(callback_id), urls_checked_value);
}
void SafeBrowsingUIHandler::GetSentClientDownloadRequests(
- const base::ListValue* args) {
+ const base::Value::ConstListView args) {
const std::vector<std::unique_ptr<ClientDownloadRequest>>& cdrs =
WebUIInfoSingleton::GetInstance()->client_download_requests_sent();
@@ -2233,13 +2239,13 @@ void SafeBrowsingUIHandler::GetSentClientDownloadRequests(
}
AllowJavascript();
- DCHECK(!args->GetList().empty());
- std::string callback_id = args->GetList()[0].GetString();
+ DCHECK(!args.empty());
+ std::string callback_id = args[0].GetString();
ResolveJavascriptCallback(base::Value(callback_id), cdrs_sent);
}
void SafeBrowsingUIHandler::GetReceivedClientDownloadResponses(
- const base::ListValue* args) {
+ const base::Value::ConstListView args) {
const std::vector<std::unique_ptr<ClientDownloadResponse>>& cdrs =
WebUIInfoSingleton::GetInstance()->client_download_responses_received();
@@ -2250,13 +2256,13 @@ void SafeBrowsingUIHandler::GetReceivedClientDownloadResponses(
}
AllowJavascript();
- DCHECK(!args->GetList().empty());
- std::string callback_id = args->GetList()[0].GetString();
+ DCHECK(!args.empty());
+ std::string callback_id = args[0].GetString();
ResolveJavascriptCallback(base::Value(callback_id), cdrs_received);
}
void SafeBrowsingUIHandler::GetSentClientPhishingRequests(
- const base::ListValue* args) {
+ const base::Value::ConstListView args) {
const std::vector<ClientPhishingRequestAndToken>& cprs =
WebUIInfoSingleton::GetInstance()->client_phishing_requests_sent();
@@ -2267,13 +2273,13 @@ void SafeBrowsingUIHandler::GetSentClientPhishingRequests(
}
AllowJavascript();
- DCHECK(!args->GetList().empty());
- std::string callback_id = args->GetList()[0].GetString();
+ DCHECK(!args.empty());
+ std::string callback_id = args[0].GetString();
ResolveJavascriptCallback(base::Value(callback_id), cprs_sent);
}
void SafeBrowsingUIHandler::GetReceivedClientPhishingResponses(
- const base::ListValue* args) {
+ const base::Value::ConstListView args) {
const std::vector<std::unique_ptr<ClientPhishingResponse>>& cprs =
WebUIInfoSingleton::GetInstance()->client_phishing_responses_received();
@@ -2284,12 +2290,13 @@ void SafeBrowsingUIHandler::GetReceivedClientPhishingResponses(
}
AllowJavascript();
- DCHECK(!args->GetList().empty());
- std::string callback_id = args->GetList()[0].GetString();
+ DCHECK(!args.empty());
+ std::string callback_id = args[0].GetString();
ResolveJavascriptCallback(base::Value(callback_id), cprs_received);
}
-void SafeBrowsingUIHandler::GetSentCSBRRs(const base::ListValue* args) {
+void SafeBrowsingUIHandler::GetSentCSBRRs(
+ const base::Value::ConstListView args) {
const std::vector<std::unique_ptr<ClientSafeBrowsingReportRequest>>& reports =
WebUIInfoSingleton::GetInstance()->csbrrs_sent();
@@ -2300,12 +2307,12 @@ void SafeBrowsingUIHandler::GetSentCSBRRs(const base::ListValue* args) {
}
AllowJavascript();
- DCHECK(!args->GetList().empty());
- std::string callback_id = args->GetList()[0].GetString();
+ DCHECK(!args.empty());
+ std::string callback_id = args[0].GetString();
ResolveJavascriptCallback(base::Value(callback_id), sent_reports);
}
-void SafeBrowsingUIHandler::GetPGEvents(const base::ListValue* args) {
+void SafeBrowsingUIHandler::GetPGEvents(const base::Value::ConstListView args) {
const std::vector<sync_pb::UserEventSpecifics>& events =
WebUIInfoSingleton::GetInstance()->pg_event_log();
@@ -2315,12 +2322,13 @@ void SafeBrowsingUIHandler::GetPGEvents(const base::ListValue* args) {
events_sent.Append(SerializePGEvent(event));
AllowJavascript();
- DCHECK(!args->GetList().empty());
- std::string callback_id = args->GetList()[0].GetString();
+ DCHECK(!args.empty());
+ std::string callback_id = args[0].GetString();
ResolveJavascriptCallback(base::Value(callback_id), events_sent);
}
-void SafeBrowsingUIHandler::GetSecurityEvents(const base::ListValue* args) {
+void SafeBrowsingUIHandler::GetSecurityEvents(
+ const base::Value::ConstListView args) {
const std::vector<sync_pb::GaiaPasswordReuse>& events =
WebUIInfoSingleton::GetInstance()->security_event_log();
@@ -2330,12 +2338,12 @@ void SafeBrowsingUIHandler::GetSecurityEvents(const base::ListValue* args) {
events_sent.Append(SerializeSecurityEvent(event));
AllowJavascript();
- DCHECK(!args->GetList().empty());
- std::string callback_id = args->GetList()[0].GetString();
+ DCHECK(!args.empty());
+ std::string callback_id = args[0].GetString();
ResolveJavascriptCallback(base::Value(callback_id), events_sent);
}
-void SafeBrowsingUIHandler::GetPGPings(const base::ListValue* args) {
+void SafeBrowsingUIHandler::GetPGPings(const base::Value::ConstListView args) {
const std::vector<LoginReputationClientRequestAndToken> requests =
WebUIInfoSingleton::GetInstance()->pg_pings();
@@ -2349,12 +2357,13 @@ void SafeBrowsingUIHandler::GetPGPings(const base::ListValue* args) {
}
AllowJavascript();
- DCHECK(!args->GetList().empty());
- std::string callback_id = args->GetList()[0].GetString();
+ DCHECK(!args.empty());
+ std::string callback_id = args[0].GetString();
ResolveJavascriptCallback(base::Value(callback_id), pings_sent);
}
-void SafeBrowsingUIHandler::GetPGResponses(const base::ListValue* args) {
+void SafeBrowsingUIHandler::GetPGResponses(
+ const base::Value::ConstListView args) {
const std::map<int, LoginReputationClientResponse> responses =
WebUIInfoSingleton::GetInstance()->pg_responses();
@@ -2368,12 +2377,13 @@ void SafeBrowsingUIHandler::GetPGResponses(const base::ListValue* args) {
}
AllowJavascript();
- DCHECK(!args->GetList().empty());
- std::string callback_id = args->GetList()[0].GetString();
+ DCHECK(!args.empty());
+ std::string callback_id = args[0].GetString();
ResolveJavascriptCallback(base::Value(callback_id), responses_sent);
}
-void SafeBrowsingUIHandler::GetRTLookupPings(const base::ListValue* args) {
+void SafeBrowsingUIHandler::GetRTLookupPings(
+ const base::Value::ConstListView args) {
const std::vector<RTLookupRequestAndToken> requests =
WebUIInfoSingleton::GetInstance()->rt_lookup_pings();
@@ -2388,12 +2398,13 @@ void SafeBrowsingUIHandler::GetRTLookupPings(const base::ListValue* args) {
}
AllowJavascript();
- DCHECK(!args->GetList().empty());
- std::string callback_id = args->GetList()[0].GetString();
+ DCHECK(!args.empty());
+ std::string callback_id = args[0].GetString();
ResolveJavascriptCallback(base::Value(callback_id), pings_sent);
}
-void SafeBrowsingUIHandler::GetRTLookupResponses(const base::ListValue* args) {
+void SafeBrowsingUIHandler::GetRTLookupResponses(
+ const base::Value::ConstListView args) {
const std::map<int, RTLookupResponse> responses =
WebUIInfoSingleton::GetInstance()->rt_lookup_responses();
@@ -2407,20 +2418,21 @@ void SafeBrowsingUIHandler::GetRTLookupResponses(const base::ListValue* args) {
}
AllowJavascript();
- DCHECK(!args->GetList().empty());
- std::string callback_id = args->GetList()[0].GetString();
+ DCHECK(!args.empty());
+ std::string callback_id = args[0].GetString();
ResolveJavascriptCallback(base::Value(callback_id), responses_sent);
}
-void SafeBrowsingUIHandler::GetReferrerChain(const base::ListValue* args) {
- DCHECK_GE(args->GetList().size(), 2U);
- std::string url_string = args->GetList()[1].GetString();
+void SafeBrowsingUIHandler::GetReferrerChain(
+ const base::Value::ConstListView args) {
+ DCHECK_GE(args.size(), 2U);
+ std::string url_string = args[1].GetString();
ReferrerChainProvider* provider =
WebUIInfoSingleton::GetInstance()->GetReferrerChainProvider(
browser_context_);
- std::string callback_id = args->GetList()[0].GetString();
+ std::string callback_id = args[0].GetString();
if (!provider) {
AllowJavascript();
@@ -2447,9 +2459,10 @@ void SafeBrowsingUIHandler::GetReferrerChain(const base::ListValue* args) {
base::Value(referrer_chain_serialized));
}
-void SafeBrowsingUIHandler::GetReferringAppInfo(const base::ListValue* args) {
+void SafeBrowsingUIHandler::GetReferringAppInfo(
+ const base::Value::ConstListView args) {
base::Value referring_app_value;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
LoginReputationClientRequest::ReferringAppInfo info =
WebUIInfoSingleton::GetInstance()->GetReferringAppInfo(
web_ui()->GetWebContents());
@@ -2461,13 +2474,14 @@ void SafeBrowsingUIHandler::GetReferringAppInfo(const base::ListValue* args) {
serializer.Serialize(referring_app_value);
AllowJavascript();
- DCHECK(!args->GetList().empty());
- std::string callback_id = args->GetList()[0].GetString();
+ DCHECK(!args.empty());
+ std::string callback_id = args[0].GetString();
ResolveJavascriptCallback(base::Value(callback_id),
base::Value(referring_app_serialized));
}
-void SafeBrowsingUIHandler::GetReportingEvents(const base::ListValue* args) {
+void SafeBrowsingUIHandler::GetReportingEvents(
+ const base::Value::ConstListView args) {
base::ListValue reporting_events;
for (const auto& reporting_event :
WebUIInfoSingleton::GetInstance()->reporting_events()) {
@@ -2475,12 +2489,13 @@ void SafeBrowsingUIHandler::GetReportingEvents(const base::ListValue* args) {
}
AllowJavascript();
- DCHECK(!args->GetList().empty());
- std::string callback_id = args->GetList()[0].GetString();
+ DCHECK(!args.empty());
+ std::string callback_id = args[0].GetString();
ResolveJavascriptCallback(base::Value(callback_id), reporting_events);
}
-void SafeBrowsingUIHandler::GetLogMessages(const base::ListValue* args) {
+void SafeBrowsingUIHandler::GetLogMessages(
+ const base::Value::ConstListView args) {
const std::vector<std::pair<base::Time, std::string>>& log_messages =
WebUIInfoSingleton::GetInstance()->log_messages();
@@ -2491,12 +2506,13 @@ void SafeBrowsingUIHandler::GetLogMessages(const base::ListValue* args) {
}
AllowJavascript();
- DCHECK(!args->GetList().empty());
- std::string callback_id = args->GetList()[0].GetString();
+ DCHECK(!args.empty());
+ std::string callback_id = args[0].GetString();
ResolveJavascriptCallback(base::Value(callback_id), messages_received);
}
-void SafeBrowsingUIHandler::GetDeepScans(const base::ListValue* args) {
+void SafeBrowsingUIHandler::GetDeepScans(
+ const base::Value::ConstListView args) {
base::ListValue pings_sent;
#if BUILDFLAG(FULL_SAFE_BROWSING)
for (const auto& token_and_data :
@@ -2507,8 +2523,8 @@ void SafeBrowsingUIHandler::GetDeepScans(const base::ListValue* args) {
#endif
AllowJavascript();
- DCHECK(!args->GetList().empty());
- std::string callback_id = args->GetList()[0].GetString();
+ DCHECK(!args.empty());
+ std::string callback_id = args[0].GetString();
ResolveJavascriptCallback(base::Value(callback_id), pings_sent);
}
@@ -2623,7 +2639,7 @@ void SafeBrowsingUIHandler::NotifyLogMessageJsListener(
}
void SafeBrowsingUIHandler::NotifyReportingEventJsListener(
- const base::Value& event) {
+ const base::Value::Dict& event) {
AllowJavascript();
FireWebUIListener("reporting-events-update", SerializeReportingEvent(event));
}
@@ -2639,92 +2655,92 @@ void SafeBrowsingUIHandler::NotifyDeepScanJsListener(
#endif
void SafeBrowsingUIHandler::RegisterMessages() {
- web_ui()->RegisterDeprecatedMessageCallback(
+ web_ui()->RegisterMessageCallback(
"getExperiments",
base::BindRepeating(&SafeBrowsingUIHandler::GetExperiments,
base::Unretained(this)));
- web_ui()->RegisterDeprecatedMessageCallback(
+ web_ui()->RegisterMessageCallback(
"getPolicies", base::BindRepeating(&SafeBrowsingUIHandler::GetPolicies,
base::Unretained(this)));
- web_ui()->RegisterDeprecatedMessageCallback(
+ web_ui()->RegisterMessageCallback(
"getPrefs", base::BindRepeating(&SafeBrowsingUIHandler::GetPrefs,
base::Unretained(this)));
- web_ui()->RegisterDeprecatedMessageCallback(
+ web_ui()->RegisterMessageCallback(
"getCookie", base::BindRepeating(&SafeBrowsingUIHandler::GetCookie,
base::Unretained(this)));
- web_ui()->RegisterDeprecatedMessageCallback(
+ web_ui()->RegisterMessageCallback(
"getSavedPasswords",
base::BindRepeating(&SafeBrowsingUIHandler::GetSavedPasswords,
base::Unretained(this)));
- web_ui()->RegisterDeprecatedMessageCallback(
+ web_ui()->RegisterMessageCallback(
"getDatabaseManagerInfo",
base::BindRepeating(&SafeBrowsingUIHandler::GetDatabaseManagerInfo,
base::Unretained(this)));
- web_ui()->RegisterDeprecatedMessageCallback(
+ web_ui()->RegisterMessageCallback(
"getDownloadUrlsChecked",
base::BindRepeating(&SafeBrowsingUIHandler::GetDownloadUrlsChecked,
base::Unretained(this)));
- web_ui()->RegisterDeprecatedMessageCallback(
+ web_ui()->RegisterMessageCallback(
"getSentClientDownloadRequests",
base::BindRepeating(&SafeBrowsingUIHandler::GetSentClientDownloadRequests,
base::Unretained(this)));
- web_ui()->RegisterDeprecatedMessageCallback(
+ web_ui()->RegisterMessageCallback(
"getReceivedClientDownloadResponses",
base::BindRepeating(
&SafeBrowsingUIHandler::GetReceivedClientDownloadResponses,
base::Unretained(this)));
- web_ui()->RegisterDeprecatedMessageCallback(
+ web_ui()->RegisterMessageCallback(
"getSentClientPhishingRequests",
base::BindRepeating(&SafeBrowsingUIHandler::GetSentClientPhishingRequests,
base::Unretained(this)));
- web_ui()->RegisterDeprecatedMessageCallback(
+ web_ui()->RegisterMessageCallback(
"getReceivedClientPhishingResponses",
base::BindRepeating(
&SafeBrowsingUIHandler::GetReceivedClientPhishingResponses,
base::Unretained(this)));
- web_ui()->RegisterDeprecatedMessageCallback(
+ web_ui()->RegisterMessageCallback(
"getSentCSBRRs",
base::BindRepeating(&SafeBrowsingUIHandler::GetSentCSBRRs,
base::Unretained(this)));
- web_ui()->RegisterDeprecatedMessageCallback(
+ web_ui()->RegisterMessageCallback(
"getPGEvents", base::BindRepeating(&SafeBrowsingUIHandler::GetPGEvents,
base::Unretained(this)));
- web_ui()->RegisterDeprecatedMessageCallback(
+ web_ui()->RegisterMessageCallback(
"getSecurityEvents",
base::BindRepeating(&SafeBrowsingUIHandler::GetSecurityEvents,
base::Unretained(this)));
- web_ui()->RegisterDeprecatedMessageCallback(
+ web_ui()->RegisterMessageCallback(
"getPGPings", base::BindRepeating(&SafeBrowsingUIHandler::GetPGPings,
base::Unretained(this)));
- web_ui()->RegisterDeprecatedMessageCallback(
+ web_ui()->RegisterMessageCallback(
"getPGResponses",
base::BindRepeating(&SafeBrowsingUIHandler::GetPGResponses,
base::Unretained(this)));
- web_ui()->RegisterDeprecatedMessageCallback(
+ web_ui()->RegisterMessageCallback(
"getRTLookupPings",
base::BindRepeating(&SafeBrowsingUIHandler::GetRTLookupPings,
base::Unretained(this)));
- web_ui()->RegisterDeprecatedMessageCallback(
+ web_ui()->RegisterMessageCallback(
"getRTLookupResponses",
base::BindRepeating(&SafeBrowsingUIHandler::GetRTLookupResponses,
base::Unretained(this)));
- web_ui()->RegisterDeprecatedMessageCallback(
+ web_ui()->RegisterMessageCallback(
"getLogMessages",
base::BindRepeating(&SafeBrowsingUIHandler::GetLogMessages,
base::Unretained(this)));
- web_ui()->RegisterDeprecatedMessageCallback(
+ web_ui()->RegisterMessageCallback(
"getReferrerChain",
base::BindRepeating(&SafeBrowsingUIHandler::GetReferrerChain,
base::Unretained(this)));
- web_ui()->RegisterDeprecatedMessageCallback(
+ web_ui()->RegisterMessageCallback(
"getReferringAppInfo",
base::BindRepeating(&SafeBrowsingUIHandler::GetReferringAppInfo,
base::Unretained(this)));
- web_ui()->RegisterDeprecatedMessageCallback(
+ web_ui()->RegisterMessageCallback(
"getReportingEvents",
base::BindRepeating(&SafeBrowsingUIHandler::GetReportingEvents,
base::Unretained(this)));
- web_ui()->RegisterDeprecatedMessageCallback(
+ web_ui()->RegisterMessageCallback(
"getDeepScans", base::BindRepeating(&SafeBrowsingUIHandler::GetDeepScans,
base::Unretained(this)));
}
diff --git a/chromium/components/safe_browsing/content/browser/web_ui/safe_browsing_ui.h b/chromium/components/safe_browsing/content/browser/web_ui/safe_browsing_ui.h
index 86931f2b642..78bb31b8592 100644
--- a/chromium/components/safe_browsing/content/browser/web_ui/safe_browsing_ui.h
+++ b/chromium/components/safe_browsing/content/browser/web_ui/safe_browsing_ui.h
@@ -97,90 +97,92 @@ class SafeBrowsingUIHandler : public content::WebUIMessageHandler {
void OnJavascriptDisallowed() override;
// Get the experiments that are currently enabled per Chrome instance.
- void GetExperiments(const base::ListValue* args);
+ void GetExperiments(const base::Value::ConstListView args);
// Get the Safe Browsing related preferences for the current user.
- void GetPrefs(const base::ListValue* args);
+ void GetPrefs(const base::Value::ConstListView args);
// Get the Safe Browsing related policies for the current user.
- void GetPolicies(const base::ListValue* args);
+ void GetPolicies(const base::Value::ConstListView args);
// Get the Safe Browsing cookie.
- void GetCookie(const base::ListValue* args);
+ void GetCookie(const base::Value::ConstListView args);
// Get the current captured passwords.
- void GetSavedPasswords(const base::ListValue* args);
+ void GetSavedPasswords(const base::Value::ConstListView args);
// Get the information related to the Safe Browsing database and full hash
// cache.
- void GetDatabaseManagerInfo(const base::ListValue* args);
+ void GetDatabaseManagerInfo(const base::Value::ConstListView args);
// Get the download URLs that have been checked since the oldest currently
// open chrome://safe-browsing tab was opened.
- void GetDownloadUrlsChecked(const base::ListValue* args);
+ void GetDownloadUrlsChecked(const base::Value::ConstListView args);
// Get the ClientDownloadRequests that have been collected since the oldest
// currently open chrome://safe-browsing tab was opened.
- void GetSentClientDownloadRequests(const base::ListValue* args);
+ void GetSentClientDownloadRequests(const base::Value::ConstListView args);
// Get the ClientDownloadReponses that have been collected since the oldest
// currently open chrome://safe-browsing tab was opened.
- void GetReceivedClientDownloadResponses(const base::ListValue* args);
+ void GetReceivedClientDownloadResponses(
+ const base::Value::ConstListView args);
// Get the ClientPhishingRequests that have been collected since the oldest
// currently open chrome://safe-browsing tab was opened.
- void GetSentClientPhishingRequests(const base::ListValue* args);
+ void GetSentClientPhishingRequests(const base::Value::ConstListView args);
// Get the ClientPhishingResponses that have been collected since the oldest
// currently open chrome://safe-browsing tab was opened.
- void GetReceivedClientPhishingResponses(const base::ListValue* args);
+ void GetReceivedClientPhishingResponses(
+ const base::Value::ConstListView args);
// Get the ThreatDetails that have been collected since the oldest currently
// open chrome://safe-browsing tab was opened.
- void GetSentCSBRRs(const base::ListValue* args);
+ void GetSentCSBRRs(const base::Value::ConstListView args);
// Get the PhishGuard events that have been collected since the oldest
// currently open chrome://safe-browsing tab was opened.
- void GetPGEvents(const base::ListValue* args);
+ void GetPGEvents(const base::Value::ConstListView args);
// Get the Security events that have been collected since the oldest
// currently open chrome://safe-browsing tab was opened.
- void GetSecurityEvents(const base::ListValue* args);
+ void GetSecurityEvents(const base::Value::ConstListView args);
// Get the PhishGuard pings that have been sent since the oldest currently
// open chrome://safe-browsing tab was opened.
- void GetPGPings(const base::ListValue* args);
+ void GetPGPings(const base::Value::ConstListView args);
// Get the PhishGuard responses that have been received since the oldest
// currently open chrome://safe-browsing tab was opened.
- void GetPGResponses(const base::ListValue* args);
+ void GetPGResponses(const base::Value::ConstListView args);
// Get the real time lookup pings that have been sent since the oldest
// currently open chrome://safe-browsing tab was opened.
- void GetRTLookupPings(const base::ListValue* args);
+ void GetRTLookupPings(const base::Value::ConstListView args);
// Get the real time lookup responses that have been received since the oldest
// currently open chrome://safe-browsing tab was opened.
- void GetRTLookupResponses(const base::ListValue* args);
+ void GetRTLookupResponses(const base::Value::ConstListView args);
// Get the current referrer chain for a given URL.
- void GetReferrerChain(const base::ListValue* args);
+ void GetReferrerChain(const base::Value::ConstListView args);
// Get the referring app info that launches Chrome on Android. Always set to
// null if it's called from platforms other than Android.
- void GetReferringAppInfo(const base::ListValue* args);
+ void GetReferringAppInfo(const base::Value::ConstListView args);
// Get the list of log messages that have been received since the oldest
// currently open chrome://safe-browsing tab was opened.
- void GetLogMessages(const base::ListValue* args);
+ void GetLogMessages(const base::Value::ConstListView args);
// Get the reporting events that have been collected since the oldest
// currently open chrome://safe-browsing tab was opened.
- void GetReportingEvents(const base::ListValue* args);
+ void GetReportingEvents(const base::Value::ConstListView args);
// Get the deep scanning requests that have been collected since the oldest
// currently open chrome://safe-browsing tab was opened.
- void GetDeepScans(const base::ListValue* args);
+ void GetDeepScans(const base::Value::ConstListView args);
// Register callbacks for WebUI messages.
void RegisterMessages() override;
@@ -257,7 +259,7 @@ class SafeBrowsingUIHandler : public content::WebUIMessageHandler {
// Called when any new reporting events are sent while one or more WebUI tabs
// are open.
- void NotifyReportingEventJsListener(const base::Value& event);
+ void NotifyReportingEventJsListener(const base::Value::Dict& event);
#if BUILDFLAG(FULL_SAFE_BROWSING)
// Called when any deep scans are updated while one or more WebUI
@@ -399,7 +401,7 @@ class WebUIInfoSingleton : public SafeBrowsingUrlCheckerImpl::WebUIDelegate {
// Add the reporting event to |reporting_events_| and send it to all the open
// chrome://safe-browsing tabs.
- void AddToReportingEvents(const base::Value& event);
+ void AddToReportingEvents(const base::Value::Dict& event);
// Clear |reporting_events_|.
void ClearReportingEvents();
@@ -539,7 +541,7 @@ class WebUIInfoSingleton : public SafeBrowsingUrlCheckerImpl::WebUIDelegate {
ReferrerChainProvider* GetReferrerChainProvider(
content::BrowserContext* browser_context);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
LoginReputationClientRequest::ReferringAppInfo GetReferringAppInfo(
content::WebContents* web_contents);
#endif
@@ -633,6 +635,8 @@ class WebUIInfoSingleton : public SafeBrowsingUrlCheckerImpl::WebUIDelegate {
// List of reporting events logged since the oldest currently open
// chrome://safe-browsing tab was opened.
+ // TODO(https://crbug.com/1297256): This can only store base::Value::Dicts, so
+ // update this type to reflect that.
std::vector<base::Value> reporting_events_;
#if BUILDFLAG(FULL_SAFE_BROWSING)
diff --git a/chromium/components/safe_browsing/content/common/BUILD.gn b/chromium/components/safe_browsing/content/common/BUILD.gn
index b2982f99b35..6094b2bfb27 100644
--- a/chromium/components/safe_browsing/content/common/BUILD.gn
+++ b/chromium/components/safe_browsing/content/common/BUILD.gn
@@ -26,15 +26,23 @@ if (safe_browsing_mode != 0) {
sources = [
"file_type_policies.cc",
"file_type_policies.h",
+ "file_type_policies_policy_util.cc",
+ "file_type_policies_policy_util.h",
+ "file_type_policies_prefs.cc",
+ "file_type_policies_prefs.h",
]
public_deps = [
"//base",
"//components/safe_browsing/content/common/proto:download_file_types_proto",
+ "//url:url",
]
deps = [
+ "//components/policy/core/browser",
+ "//components/prefs",
"//components/resources:components_resources",
+ "//components/url_matcher:url_matcher",
"//ui/base",
]
}
@@ -49,6 +57,20 @@ if (safe_browsing_mode != 0) {
deps = [ ":file_type_policies" ]
}
+ source_set("file_type_policies_policy_util_unittest") {
+ testonly = true
+ sources = [ "file_type_policies_policy_util_unittest.cc" ]
+
+ deps = [
+ ":file_type_policies",
+ "//base:base",
+ "//components/policy/core/browser:test_support",
+ "//components/prefs:test_support",
+ "//testing/gmock:gmock",
+ "//testing/gtest:gtest",
+ ]
+ }
+
source_set("file_type_policies_unittest") {
testonly = true
sources = [ "file_type_policies_unittest.cc" ]
diff --git a/chromium/components/safe_browsing/content/common/file_type_policies.cc b/chromium/components/safe_browsing/content/common/file_type_policies.cc
index 677241e450a..b8736714cbf 100644
--- a/chromium/components/safe_browsing/content/common/file_type_policies.cc
+++ b/chromium/components/safe_browsing/content/common/file_type_policies.cc
@@ -7,12 +7,50 @@
#include "base/check_op.h"
#include "base/memory/singleton.h"
#include "base/metrics/histogram_functions.h"
+#include "base/no_destructor.h"
#include "base/strings/string_util.h"
#include "components/grit/components_resources.h"
+#include "components/safe_browsing/content/common/file_type_policies_policy_util.h"
#include "ui/base/resource/resource_bundle.h"
+#include "url/gurl.h"
namespace safe_browsing {
+namespace policy {
+
+using ExtensionToPolicyMap = std::map<std::string, const DownloadFileType>;
+
+ExtensionToPolicyMap& GetExtensionToPolicyMap() {
+ static base::NoDestructor<ExtensionToPolicyMap> ext_map;
+ return *ext_map;
+}
+
+const DownloadFileType& GetOrCreatePolicyForExtensionOverrideNotDangerous(
+ const std::string& extension,
+ const DownloadFileType& base_policy) {
+ ExtensionToPolicyMap& ext_map = GetExtensionToPolicyMap();
+ auto it = ext_map.find(extension);
+ // Cache hit, don't bother recreating a duplicate policy structure.
+ if (it != ext_map.end())
+ return it->second;
+
+ // Create copy of existing settings.
+ const DownloadFileType::PlatformSettings& base_settings =
+ base_policy.platform_settings(0);
+ DownloadFileType override_policy = base_policy;
+
+ // Override only the danger level.
+ override_policy.clear_platform_settings();
+ auto* override_settings = override_policy.add_platform_settings();
+ *override_settings = base_settings;
+ override_settings->set_danger_level(DownloadFileType::NOT_DANGEROUS);
+
+ // Add element to our map so we can hand out a valid reference.
+ return ext_map.insert({extension, override_policy}).first->second;
+}
+
+} // namespace policy
+
using base::AutoLock;
// Our Singleton needs to populate itself when first constructed.
@@ -143,6 +181,10 @@ void FileTypePolicies::SwapConfigLocked(
// If there are dups, first one wins.
file_type_by_ext_.insert(std::make_pair(file_type.extension(), &file_type));
}
+
+ // |ext_map| is now stale since |file_type_by_ext_| has been cleared
+ // and recreated, so clear it.
+ policy::GetExtensionToPolicyMap().clear();
}
// static
@@ -177,7 +219,9 @@ float FileTypePolicies::SampledPingProbability() const {
}
const DownloadFileType& FileTypePolicies::PolicyForExtension(
- const std::string& ascii_ext) const {
+ const std::string& ascii_ext,
+ const GURL& source_url,
+ const PrefService* prefs) const {
lock_.AssertAcquired();
// This could happen if the ResourceBundle is corrupted.
if (!config_) {
@@ -185,6 +229,16 @@ const DownloadFileType& FileTypePolicies::PolicyForExtension(
return last_resort_default_;
}
auto itr = file_type_by_ext_.find(ascii_ext);
+
+ if (safe_browsing::IsInNotDangerousOverrideList(ascii_ext, source_url,
+ prefs)) {
+ if (itr != file_type_by_ext_.find(ascii_ext))
+ return policy::GetOrCreatePolicyForExtensionOverrideNotDangerous(
+ ascii_ext, *itr->second);
+ return policy::GetOrCreatePolicyForExtensionOverrideNotDangerous(
+ ascii_ext, config_->default_file_type());
+ }
+
if (itr != file_type_by_ext_.end())
return *itr->second;
else
@@ -192,30 +246,35 @@ const DownloadFileType& FileTypePolicies::PolicyForExtension(
}
DownloadFileType FileTypePolicies::PolicyForFile(
- const base::FilePath& file) const {
+ const base::FilePath& file,
+ const GURL& source_url,
+ const PrefService* prefs) const {
const std::string ext = CanonicalizedExtension(file);
AutoLock lock(lock_);
- return PolicyForExtension(ext);
+ return PolicyForExtension(ext, source_url, prefs);
}
DownloadFileType::PlatformSettings FileTypePolicies::SettingsForFile(
- const base::FilePath& file) const {
+ const base::FilePath& file,
+ const GURL& source_url,
+ const PrefService* prefs) const {
const std::string ext = CanonicalizedExtension(file);
AutoLock lock(lock_);
- DCHECK_EQ(1, PolicyForExtension(ext).platform_settings().size());
- return PolicyForExtension(ext).platform_settings(0);
+ DCHECK_EQ(
+ 1, PolicyForExtension(ext, source_url, prefs).platform_settings().size());
+ return PolicyForExtension(ext, source_url, prefs).platform_settings(0);
}
int64_t FileTypePolicies::UmaValueForFile(const base::FilePath& file) const {
const std::string ext = CanonicalizedExtension(file);
AutoLock lock(lock_);
- return PolicyForExtension(ext).uma_value();
+ return PolicyForExtension(ext, GURL{}, nullptr).uma_value();
}
bool FileTypePolicies::IsArchiveFile(const base::FilePath& file) const {
const std::string ext = CanonicalizedExtension(file);
AutoLock lock(lock_);
- return PolicyForExtension(ext).is_archive();
+ return PolicyForExtension(ext, GURL{}, nullptr).is_archive();
}
// TODO(nparker): Add unit tests for these accessors.
@@ -226,15 +285,16 @@ bool FileTypePolicies::IsAllowedToOpenAutomatically(
if (ext.empty())
return false;
AutoLock lock(lock_);
- return PolicyForExtension(ext).platform_settings(0).auto_open_hint() ==
- DownloadFileType::ALLOW_AUTO_OPEN;
+ return PolicyForExtension(ext, GURL{}, nullptr)
+ .platform_settings(0)
+ .auto_open_hint() == DownloadFileType::ALLOW_AUTO_OPEN;
}
DownloadFileType::PingSetting FileTypePolicies::PingSettingForFile(
const base::FilePath& file) const {
const std::string ext = CanonicalizedExtension(file);
AutoLock lock(lock_);
- return PolicyForExtension(ext).ping_setting();
+ return PolicyForExtension(ext, GURL{}, nullptr).ping_setting();
}
bool FileTypePolicies::IsCheckedBinaryFile(const base::FilePath& file) const {
@@ -242,16 +302,20 @@ bool FileTypePolicies::IsCheckedBinaryFile(const base::FilePath& file) const {
}
DownloadFileType::DangerLevel FileTypePolicies::GetFileDangerLevel(
- const base::FilePath& file) const {
+ const base::FilePath& file,
+ const GURL& source_url,
+ const PrefService* prefs) const {
const std::string ext = CanonicalizedExtension(file);
AutoLock lock(lock_);
- return PolicyForExtension(ext).platform_settings(0).danger_level();
+ return PolicyForExtension(ext, source_url, prefs)
+ .platform_settings(0)
+ .danger_level();
}
uint64_t FileTypePolicies::GetMaxFileSizeToAnalyze(
const std::string& ascii_ext) const {
AutoLock lock(lock_);
- return PolicyForExtension(ascii_ext)
+ return PolicyForExtension(ascii_ext, GURL{}, nullptr)
.platform_settings(0)
.max_file_size_to_analyze();
}
diff --git a/chromium/components/safe_browsing/content/common/file_type_policies.h b/chromium/components/safe_browsing/content/common/file_type_policies.h
index 2740a510f54..bd149d45f9a 100644
--- a/chromium/components/safe_browsing/content/common/file_type_policies.h
+++ b/chromium/components/safe_browsing/content/common/file_type_policies.h
@@ -13,6 +13,9 @@
#include "base/synchronization/lock.h"
#include "components/safe_browsing/content/common/proto/download_file_types.pb.h"
+class GURL;
+class PrefService;
+
namespace safe_browsing {
struct FileTypePoliciesSingletonTrait;
@@ -68,7 +71,9 @@ class FileTypePolicies {
// Return the danger level of this file type.
DownloadFileType::DangerLevel GetFileDangerLevel(
- const base::FilePath& file) const;
+ const base::FilePath& file,
+ const GURL& source_url,
+ const PrefService* prefs) const;
// Return the type of ping we should send for this file
DownloadFileType::PingSetting PingSettingForFile(
@@ -76,9 +81,13 @@ class FileTypePolicies {
float SampledPingProbability() const;
- DownloadFileType PolicyForFile(const base::FilePath& file) const;
+ DownloadFileType PolicyForFile(const base::FilePath& file,
+ const GURL& source_url,
+ const PrefService* prefs) const;
DownloadFileType::PlatformSettings SettingsForFile(
- const base::FilePath& file) const;
+ const base::FilePath& file,
+ const GURL& source_url,
+ const PrefService* prefs) const;
// Return max size for which unpacking and/or binary feature extration is
// supported for the given file extension.
@@ -119,7 +128,9 @@ class FileTypePolicies {
// Look up the policy for a given ASCII ext.
virtual const DownloadFileType& PolicyForExtension(
- const std::string& ext) const;
+ const std::string& ext,
+ const GURL& source_url,
+ const PrefService* prefs) const;
private:
// Swap in a different config. This will rebuild file_type_by_ext_ index.
diff --git a/chromium/components/safe_browsing/content/common/file_type_policies_policy_util.cc b/chromium/components/safe_browsing/content/common/file_type_policies_policy_util.cc
new file mode 100644
index 00000000000..8a787c6327a
--- /dev/null
+++ b/chromium/components/safe_browsing/content/common/file_type_policies_policy_util.cc
@@ -0,0 +1,77 @@
+// Copyright 2021 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.
+
+#include "components/safe_browsing/content/common/file_type_policies_policy_util.h"
+
+#include "base/strings/string_util.h"
+#include "components/policy/core/browser/url_blocklist_manager.h"
+#include "components/prefs/pref_service.h"
+#include "components/safe_browsing/content/common/file_type_policies_prefs.h"
+#include "components/url_matcher/url_matcher.h"
+#include "components/url_matcher/url_util.h"
+#include "url/gurl.h"
+#include "url/origin.h"
+
+namespace safe_browsing {
+
+namespace {
+
+constexpr char kFileExtensionNameKey[] = "file_extension";
+constexpr char kDomainListKey[] = "domains";
+
+} // namespace
+
+bool IsInNotDangerousOverrideList(const std::string& extension,
+ const GURL& url,
+ const PrefService* prefs) {
+ GURL normalized_url = url;
+ if (normalized_url.SchemeIsBlob()) {
+ normalized_url = url::Origin::Create(normalized_url).GetURL();
+ }
+
+ // no overrides if we don't have this policy set or the url is invalid.
+ if (!prefs || !normalized_url.is_valid() ||
+ !prefs->HasPrefPath(
+ file_type::prefs::
+ kExemptDomainFileTypePairsFromFileTypeDownloadWarnings)) {
+ return false;
+ }
+ const base::Value* heuristic_overrides = prefs->GetList(
+ file_type::prefs::kExemptDomainFileTypePairsFromFileTypeDownloadWarnings);
+
+ const std::string lower_extension = base::ToLowerASCII(extension);
+
+ if (heuristic_overrides) {
+ base::ListValue domains_for_extension;
+ for (const base::Value& entry : heuristic_overrides->GetListDeprecated()) {
+ const base::DictionaryValue& extension_domain_patterns_dict =
+ base::Value::AsDictionaryValue(entry);
+ const std::string* extension_for_this_entry =
+ extension_domain_patterns_dict.FindStringKey(kFileExtensionNameKey);
+ if (extension_for_this_entry &&
+ base::ToLowerASCII(*extension_for_this_entry) == lower_extension) {
+ const base::Value* domains_for_this_entry =
+ extension_domain_patterns_dict.FindListKey(kDomainListKey);
+ if (domains_for_this_entry) {
+ for (const base::Value& domain :
+ domains_for_this_entry->GetListDeprecated()) {
+ domains_for_extension.Append(domain.Clone());
+ }
+ }
+ }
+ }
+
+ if (!domains_for_extension.GetListDeprecated().empty()) {
+ url_matcher::URLMatcher matcher;
+ url_matcher::URLMatcherConditionSet::ID id(0);
+ url_matcher::util::AddFilters(&matcher, true, &id,
+ &domains_for_extension);
+ auto matching_set_size = matcher.MatchURL(normalized_url).size();
+ return matching_set_size > 0;
+ }
+ }
+ return false;
+}
+
+} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing/content/common/file_type_policies_policy_util.h b/chromium/components/safe_browsing/content/common/file_type_policies_policy_util.h
new file mode 100644
index 00000000000..3841f8db549
--- /dev/null
+++ b/chromium/components/safe_browsing/content/common/file_type_policies_policy_util.h
@@ -0,0 +1,21 @@
+// Copyright 2021 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.
+
+#ifndef COMPONENTS_SAFE_BROWSING_CONTENT_COMMON_FILE_TYPE_POLICIES_POLICY_UTIL_H_
+#define COMPONENTS_SAFE_BROWSING_CONTENT_COMMON_FILE_TYPE_POLICIES_POLICY_UTIL_H_
+
+#include <string>
+
+class GURL;
+class PrefService;
+
+namespace safe_browsing {
+
+bool IsInNotDangerousOverrideList(const std::string& extension,
+ const GURL& url,
+ const PrefService* pref_service);
+
+} // namespace safe_browsing
+
+#endif // COMPONENTS_SAFE_BROWSING_CONTENT_COMMON_FILE_TYPE_POLICIES_POLICY_UTIL_H_ \ No newline at end of file
diff --git a/chromium/components/safe_browsing/content/common/file_type_policies_policy_util_unittest.cc b/chromium/components/safe_browsing/content/common/file_type_policies_policy_util_unittest.cc
new file mode 100644
index 00000000000..aa87f627964
--- /dev/null
+++ b/chromium/components/safe_browsing/content/common/file_type_policies_policy_util_unittest.cc
@@ -0,0 +1,161 @@
+// Copyright 2021 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.
+
+#include "components/safe_browsing/content/common/file_type_policies_policy_util.h"
+
+#include "components/policy/core/browser/configuration_policy_pref_store_test.h"
+#include "components/prefs/testing_pref_service.h"
+#include "components/safe_browsing/content/common/file_type_policies_prefs.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace {
+
+base::ListValue CreateStringListValueForTest(
+ const std::vector<std::string>& items) {
+ base::ListValue list;
+ for (const auto& item : items) {
+ list.Append(item);
+ }
+ return list;
+}
+
+base::DictionaryValue CreatePolicyEntry(
+ const std::string& extension,
+ const std::vector<std::string>& domains) {
+ base::DictionaryValue out;
+ out.SetKey("file_extension", base::Value{extension});
+ out.SetKey("domains", CreateStringListValueForTest(domains));
+ return out;
+}
+
+} // namespace
+
+namespace safe_browsing::file_type {
+class FileTypePoliciesPolicyUtilTest
+ : public policy::ConfigurationPolicyPrefStoreTest {
+ public:
+ FileTypePoliciesPolicyUtilTest() = default;
+ FileTypePoliciesPolicyUtilTest(FileTypePoliciesPolicyUtilTest& other) =
+ delete;
+ FileTypePoliciesPolicyUtilTest& operator=(
+ const FileTypePoliciesPolicyUtilTest&) = delete;
+ void SetUp() override { RegisterProfilePrefs(pref_service_.registry()); }
+
+ protected:
+ TestingPrefServiceSimple pref_service_;
+};
+
+TEST_F(FileTypePoliciesPolicyUtilTest, OverrideListIsIgnoredIfNotConfigured) {
+ EXPECT_FALSE(IsInNotDangerousOverrideList(
+ "exe", GURL{"http://www.example.com"}, &pref_service_));
+}
+
+TEST_F(FileTypePoliciesPolicyUtilTest, OverrideListIsIgnoredIfNoValuesSet) {
+ base::ListValue list;
+ pref_service_.Set(
+ prefs::kExemptDomainFileTypePairsFromFileTypeDownloadWarnings, list);
+ EXPECT_FALSE(IsInNotDangerousOverrideList(
+ "exe", GURL{"http://www.example.com"}, &pref_service_));
+}
+
+TEST_F(FileTypePoliciesPolicyUtilTest,
+ OverrideListIsIgnoredIfNoDomainsSetForExtension) {
+ base::ListValue list;
+ list.Append(CreatePolicyEntry("txt", {/* empty vector */}));
+ pref_service_.Set(
+ prefs::kExemptDomainFileTypePairsFromFileTypeDownloadWarnings, list);
+ EXPECT_FALSE(IsInNotDangerousOverrideList(
+ "txt", GURL{"http://www.example.com"}, &pref_service_));
+}
+
+TEST_F(FileTypePoliciesPolicyUtilTest, OverrideListCanUseWildcards) {
+ base::ListValue list;
+ list.Append(CreatePolicyEntry("txt", {"example.com"}));
+ list.Append(CreatePolicyEntry("exe", {"http://*"}));
+ list.Append(CreatePolicyEntry("jpg", {"*"}));
+ pref_service_.Set(
+ prefs::kExemptDomainFileTypePairsFromFileTypeDownloadWarnings, list);
+ EXPECT_TRUE(IsInNotDangerousOverrideList(
+ "exe", GURL{"http://www.example.com"}, &pref_service_));
+ EXPECT_TRUE(IsInNotDangerousOverrideList(
+ "jpg", GURL{"http://www.example.com"}, &pref_service_));
+ EXPECT_TRUE(IsInNotDangerousOverrideList(
+ "exe", GURL{"http://www.example1.com"}, &pref_service_));
+ EXPECT_TRUE(IsInNotDangerousOverrideList(
+ "txt", GURL{"http://foo.example.com"}, &pref_service_));
+ EXPECT_FALSE(IsInNotDangerousOverrideList(
+ "txt", GURL{"http://www.example1.com"}, &pref_service_));
+}
+
+TEST_F(FileTypePoliciesPolicyUtilTest, OverrideListCanMatchExactly) {
+ base::ListValue list;
+ list.Append(CreatePolicyEntry("txt", {"http://www.example.com"}));
+ pref_service_.Set(
+ prefs::kExemptDomainFileTypePairsFromFileTypeDownloadWarnings, list);
+ EXPECT_TRUE(IsInNotDangerousOverrideList(
+ "txt", GURL{"http://www.example.com"}, &pref_service_));
+ EXPECT_FALSE(IsInNotDangerousOverrideList(
+ "txt", GURL{"http://foo.example.com"}, &pref_service_));
+}
+
+TEST_F(FileTypePoliciesPolicyUtilTest, OverrideListCanMatchSubPaths) {
+ base::ListValue list;
+ list.Append(CreatePolicyEntry("txt", {"http://www.example.com"}));
+ pref_service_.Set(
+ prefs::kExemptDomainFileTypePairsFromFileTypeDownloadWarnings, list);
+ EXPECT_TRUE(IsInNotDangerousOverrideList(
+ "txt", GURL{"http://www.example.com/some/path/file.html"},
+ &pref_service_));
+}
+
+TEST_F(FileTypePoliciesPolicyUtilTest, CanLimitToHTTPS) {
+ base::ListValue list;
+ list.Append(CreatePolicyEntry("txt", {"https://example.com"}));
+ pref_service_.Set(
+ prefs::kExemptDomainFileTypePairsFromFileTypeDownloadWarnings, list);
+ EXPECT_TRUE(IsInNotDangerousOverrideList(
+ "txt", GURL{"https://www.example.com"}, &pref_service_));
+ EXPECT_TRUE(IsInNotDangerousOverrideList(
+ "txt", GURL{"https://foo.example.com"}, &pref_service_));
+ EXPECT_FALSE(IsInNotDangerousOverrideList(
+ "txt", GURL{"http://www.example.com"}, &pref_service_));
+}
+
+TEST_F(FileTypePoliciesPolicyUtilTest,
+ OverrideListOnlyWorksForListedExtension) {
+ base::ListValue list;
+ list.Append(CreatePolicyEntry("txt", {"www.example.com"}));
+ pref_service_.Set(
+ prefs::kExemptDomainFileTypePairsFromFileTypeDownloadWarnings, list);
+ EXPECT_TRUE(IsInNotDangerousOverrideList(
+ "txt", GURL{"http://www.example.com"}, &pref_service_));
+ EXPECT_FALSE(IsInNotDangerousOverrideList(
+ "exe", GURL{"http://www.example.com"}, &pref_service_));
+}
+
+TEST_F(FileTypePoliciesPolicyUtilTest, ValuesAreNotCaseSensitive) {
+ base::ListValue list;
+ list.Append(CreatePolicyEntry("TxT", {"www.example.com"}));
+ pref_service_.Set(
+ prefs::kExemptDomainFileTypePairsFromFileTypeDownloadWarnings, list);
+ EXPECT_TRUE(IsInNotDangerousOverrideList(
+ "tXt", GURL{"hTTp://wWw.example.cOM"}, &pref_service_));
+ EXPECT_FALSE(IsInNotDangerousOverrideList(
+ "exe", GURL{"hTTp://wWw.example.cOM"}, &pref_service_));
+}
+
+TEST_F(FileTypePoliciesPolicyUtilTest, NormalizesBlobURLs) {
+ base::ListValue list;
+ list.Append(CreatePolicyEntry("txt", {"https://example.com"}));
+ pref_service_.Set(
+ prefs::kExemptDomainFileTypePairsFromFileTypeDownloadWarnings, list);
+ ASSERT_TRUE(IsInNotDangerousOverrideList(
+ "txt", GURL{"https://www.example.com"}, &pref_service_));
+ // The blob: version of this URL should also be allowed.
+ EXPECT_TRUE(IsInNotDangerousOverrideList(
+ "txt", GURL{"blob:https://www.example.com"}, &pref_service_));
+}
+
+} // namespace safe_browsing::file_type \ No newline at end of file
diff --git a/chromium/components/safe_browsing/content/common/file_type_policies_prefs.cc b/chromium/components/safe_browsing/content/common/file_type_policies_prefs.cc
new file mode 100644
index 00000000000..94eaee83b41
--- /dev/null
+++ b/chromium/components/safe_browsing/content/common/file_type_policies_prefs.cc
@@ -0,0 +1,26 @@
+// Copyright 2021 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.
+
+#include "components/safe_browsing/content/common/file_type_policies_prefs.h"
+
+#include "components/prefs/pref_registry_simple.h"
+
+namespace safe_browsing::file_type {
+
+namespace prefs {
+
+// A list of file type and domains pairs that overrides the heuristics checks
+// performed when downloading the specified file types from the specified
+// domains.
+const char kExemptDomainFileTypePairsFromFileTypeDownloadWarnings[] =
+ "downloads.exempt_domain_filetype_pair_from_file_type_downloads_warnings";
+
+} // namespace prefs
+
+void RegisterProfilePrefs(PrefRegistrySimple* registry) {
+ registry->RegisterListPref(
+ prefs::kExemptDomainFileTypePairsFromFileTypeDownloadWarnings);
+}
+
+} // namespace safe_browsing::file_type \ No newline at end of file
diff --git a/chromium/components/safe_browsing/content/common/file_type_policies_prefs.h b/chromium/components/safe_browsing/content/common/file_type_policies_prefs.h
new file mode 100644
index 00000000000..6f1058ca0fe
--- /dev/null
+++ b/chromium/components/safe_browsing/content/common/file_type_policies_prefs.h
@@ -0,0 +1,21 @@
+// Copyright 2021 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.
+
+#ifndef COMPONENTS_SAFE_BROWSING_CONTENT_COMMON_FILE_TYPE_POLICIES_PREFS_H_
+#define COMPONENTS_SAFE_BROWSING_CONTENT_COMMON_FILE_TYPE_POLICIES_PREFS_H_
+
+class PrefRegistrySimple;
+
+namespace safe_browsing::file_type {
+namespace prefs {
+
+extern const char kExemptDomainFileTypePairsFromFileTypeDownloadWarnings[];
+
+} // namespace prefs
+
+void RegisterProfilePrefs(PrefRegistrySimple* registry);
+
+} // namespace safe_browsing::file_type
+
+#endif // COMPONENTS_SAFE_BROWSING_CONTENT_COMMON_FILE_TYPE_POLICIES_PREFS_H_ \ No newline at end of file
diff --git a/chromium/components/safe_browsing/content/common/file_type_policies_unittest.cc b/chromium/components/safe_browsing/content/common/file_type_policies_unittest.cc
index 96fec0bee9d..7928062fa54 100644
--- a/chromium/components/safe_browsing/content/common/file_type_policies_unittest.cc
+++ b/chromium/components/safe_browsing/content/common/file_type_policies_unittest.cc
@@ -12,6 +12,7 @@
#include "build/build_config.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
using testing::NiceMock;
@@ -53,12 +54,13 @@ TEST_F(FileTypePoliciesTest, UnpackResourceBundle) {
// Lookup .exe that varies on OS_WIN.
base::FilePath exe_file(FILE_PATH_LITERAL("a/foo.exe"));
- DownloadFileType file_type = policies_.PolicyForFile(exe_file);
+ DownloadFileType file_type =
+ policies_.PolicyForFile(exe_file, GURL{}, nullptr);
EXPECT_EQ("exe", file_type.extension());
EXPECT_EQ(0l, file_type.uma_value());
EXPECT_FALSE(file_type.is_archive());
EXPECT_EQ(DownloadFileType::FULL_PING, file_type.ping_setting());
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
EXPECT_EQ(DownloadFileType::ALLOW_ON_USER_GESTURE,
file_type.platform_settings(0).danger_level());
EXPECT_EQ(DownloadFileType::DISALLOW_AUTO_OPEN,
@@ -73,12 +75,12 @@ TEST_F(FileTypePoliciesTest, UnpackResourceBundle) {
// Lookup .class that varies on OS_CHROMEOS, and also has a
// default setting set.
base::FilePath class_file(FILE_PATH_LITERAL("foo.class"));
- file_type = policies_.PolicyForFile(class_file);
+ file_type = policies_.PolicyForFile(class_file, GURL{}, nullptr);
EXPECT_EQ("class", file_type.extension());
EXPECT_EQ(13l, file_type.uma_value());
EXPECT_FALSE(file_type.is_archive());
EXPECT_EQ(DownloadFileType::FULL_PING, file_type.ping_setting());
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS)
EXPECT_EQ(DownloadFileType::NOT_DANGEROUS,
file_type.platform_settings(0).danger_level());
EXPECT_EQ(DownloadFileType::ALLOW_AUTO_OPEN,
@@ -92,12 +94,12 @@ TEST_F(FileTypePoliciesTest, UnpackResourceBundle) {
// Lookup .dmg that varies on OS_MACOS
base::FilePath dmg_file(FILE_PATH_LITERAL("foo.dmg"));
- file_type = policies_.PolicyForFile(dmg_file);
+ file_type = policies_.PolicyForFile(dmg_file, GURL{}, nullptr);
EXPECT_EQ("dmg", file_type.extension());
EXPECT_EQ(21, file_type.uma_value());
EXPECT_FALSE(file_type.is_archive());
EXPECT_EQ(DownloadFileType::FULL_PING, file_type.ping_setting());
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
EXPECT_EQ(DownloadFileType::ALLOW_ON_USER_GESTURE,
file_type.platform_settings(0).danger_level());
EXPECT_EQ(DownloadFileType::DISALLOW_AUTO_OPEN,
@@ -111,12 +113,12 @@ TEST_F(FileTypePoliciesTest, UnpackResourceBundle) {
// Lookup .dex that varies on OS_ANDROID and OS_CHROMEOS
base::FilePath dex_file(FILE_PATH_LITERAL("foo.dex"));
- file_type = policies_.PolicyForFile(dex_file);
+ file_type = policies_.PolicyForFile(dex_file, GURL{}, nullptr);
EXPECT_EQ("dex", file_type.extension());
EXPECT_EQ(143, file_type.uma_value());
EXPECT_FALSE(file_type.is_archive());
EXPECT_EQ(DownloadFileType::FULL_PING, file_type.ping_setting());
-#if defined(OS_ANDROID) || defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS)
EXPECT_EQ(DownloadFileType::ALLOW_ON_USER_GESTURE,
file_type.platform_settings(0).danger_level());
EXPECT_EQ(DownloadFileType::DISALLOW_AUTO_OPEN,
@@ -130,14 +132,14 @@ TEST_F(FileTypePoliciesTest, UnpackResourceBundle) {
// Lookup .rpm that varies on OS_LINUX
base::FilePath rpm_file(FILE_PATH_LITERAL("foo.rpm"));
- file_type = policies_.PolicyForFile(rpm_file);
+ file_type = policies_.PolicyForFile(rpm_file, GURL{}, nullptr);
EXPECT_EQ("rpm", file_type.extension());
EXPECT_EQ(142, file_type.uma_value());
EXPECT_FALSE(file_type.is_archive());
EXPECT_EQ(DownloadFileType::FULL_PING, file_type.ping_setting());
// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
// of lacros-chrome is complete.
-#if defined(OS_LINUX)
+#if BUILDFLAG(IS_LINUX)
EXPECT_EQ(DownloadFileType::ALLOW_ON_USER_GESTURE,
file_type.platform_settings(0).danger_level());
EXPECT_EQ(DownloadFileType::DISALLOW_AUTO_OPEN,
@@ -151,7 +153,7 @@ TEST_F(FileTypePoliciesTest, UnpackResourceBundle) {
// Look .zip, an archive. The same on all platforms.
base::FilePath zip_file(FILE_PATH_LITERAL("b/bar.txt.zip"));
- file_type = policies_.PolicyForFile(zip_file);
+ file_type = policies_.PolicyForFile(zip_file, GURL{}, nullptr);
EXPECT_EQ("zip", file_type.extension());
EXPECT_EQ(7l, file_type.uma_value());
EXPECT_TRUE(file_type.is_archive());
@@ -166,7 +168,7 @@ TEST_F(FileTypePoliciesTest, UnpackResourceBundle) {
// Verify settings on the default type.
file_type = policies_.PolicyForFile(
- base::FilePath(FILE_PATH_LITERAL("a/foo.fooobar")));
+ base::FilePath(FILE_PATH_LITERAL("a/foo.fooobar")), GURL{}, nullptr);
EXPECT_EQ("", file_type.extension());
EXPECT_EQ(18l, file_type.uma_value());
EXPECT_FALSE(file_type.is_archive());
diff --git a/chromium/components/safe_browsing/content/renderer/phishing_classifier/flatbuffer_scorer.cc b/chromium/components/safe_browsing/content/renderer/phishing_classifier/flatbuffer_scorer.cc
index 46fa6d37199..9ccd343116b 100644
--- a/chromium/components/safe_browsing/content/renderer/phishing_classifier/flatbuffer_scorer.cc
+++ b/chromium/components/safe_browsing/content/renderer/phishing_classifier/flatbuffer_scorer.cc
@@ -15,6 +15,7 @@
#include "base/strings/string_piece.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
+#include "build/build_config.h"
#include "components/safe_browsing/content/renderer/phishing_classifier/features.h"
#include "components/safe_browsing/core/common/proto/client_model.pb.h"
#include "components/safe_browsing/core/common/proto/csd.pb.h"
@@ -124,7 +125,8 @@ FlatBufferModelScorer* FlatBufferModelScorer::Create(
// Only do this part if the visual model file exists
if (visual_tflite_model.IsValid()) {
- if (!scorer->visual_tflite_model_.Initialize(
+ scorer->visual_tflite_model_ = std::make_unique<base::MemoryMappedFile>();
+ if (!scorer->visual_tflite_model_->Initialize(
std::move(visual_tflite_model))) {
RecordScorerCreationStatus(SCORER_FAIL_MAP_VISUAL_TFLITE_MODEL);
return nullptr;
@@ -183,13 +185,13 @@ void FlatBufferModelScorer::GetMatchingVisualTargets(
NOTIMPLEMENTED();
}
-#if BUILDFLAG(BUILD_WITH_TFLITE_LIB) && !defined(OS_CHROMEOS) && \
+#if BUILDFLAG(BUILD_WITH_TFLITE_LIB) && !BUILDFLAG(IS_CHROMEOS) && \
!BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_CHROMEOS_LACROS)
void FlatBufferModelScorer::ApplyVisualTfLiteModel(
const SkBitmap& bitmap,
- base::OnceCallback<void(std::vector<double>)> callback) const {
+ base::OnceCallback<void(std::vector<double>)> callback) {
DCHECK(content::RenderThread::IsMainThread());
- if (visual_tflite_model_.IsValid()) {
+ if (visual_tflite_model_ && visual_tflite_model_->IsValid()) {
base::Time start_post_task_time = base::Time::Now();
base::ThreadPool::PostTaskAndReplyWithResult(
FROM_HERE,
@@ -197,10 +199,9 @@ void FlatBufferModelScorer::ApplyVisualTfLiteModel(
base::BindOnce(&ApplyVisualTfLiteModelHelper, bitmap,
flatbuffer_model_->tflite_metadata()->input_width(),
flatbuffer_model_->tflite_metadata()->input_height(),
- std::string(reinterpret_cast<const char*>(
- visual_tflite_model_.data()),
- visual_tflite_model_.length())),
- std::move(callback));
+ std::move(visual_tflite_model_)),
+ base::BindOnce(&FlatBufferModelScorer::OnVisualTfLiteModelComplete,
+ weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
base::UmaHistogramTimes(
"SBClientPhishing.TfLiteModelLoadTime.FlatbufferScorer",
base::Time::Now() - start_post_task_time);
diff --git a/chromium/components/safe_browsing/content/renderer/phishing_classifier/flatbuffer_scorer.h b/chromium/components/safe_browsing/content/renderer/phishing_classifier/flatbuffer_scorer.h
index d25d221e710..22027c696a6 100644
--- a/chromium/components/safe_browsing/content/renderer/phishing_classifier/flatbuffer_scorer.h
+++ b/chromium/components/safe_browsing/content/renderer/phishing_classifier/flatbuffer_scorer.h
@@ -55,11 +55,11 @@ class FlatBufferModelScorer : public Scorer {
const override;
// TODO(crbug/1278502): This is disabled as a temporary measure due to crashes.
-#if BUILDFLAG(BUILD_WITH_TFLITE_LIB) && !defined(OS_CHROMEOS) && \
+#if BUILDFLAG(BUILD_WITH_TFLITE_LIB) && !BUILDFLAG(IS_CHROMEOS) && \
!BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_CHROMEOS_LACROS)
void ApplyVisualTfLiteModel(
const SkBitmap& bitmap,
- base::OnceCallback<void(std::vector<double>)> callback) const override;
+ base::OnceCallback<void(std::vector<double>)> callback) override;
#endif
int model_version() const override;
diff --git a/chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier.cc b/chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier.cc
index d4de25da7dc..9249aa4ff21 100644
--- a/chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier.cc
+++ b/chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier.cc
@@ -20,6 +20,7 @@
#include "base/task/thread_pool.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/trace_event/trace_event.h"
+#include "build/build_config.h"
#include "cc/paint/paint_recorder.h"
#include "cc/paint/skia_paint_canvas.h"
#include "components/paint_preview/common/paint_preview_tracker.h"
@@ -83,7 +84,7 @@ PhishingClassifier::~PhishingClassifier() {
DCHECK(!page_text_);
}
-void PhishingClassifier::set_phishing_scorer(const Scorer* scorer) {
+void PhishingClassifier::set_phishing_scorer(Scorer* scorer) {
DCHECK(done_callback_.is_null());
DCHECK(!page_text_);
scorer_ = scorer;
@@ -289,7 +290,7 @@ void PhishingClassifier::VisualExtractionFinished(bool success) {
base::BindOnce(&PhishingClassifier::OnVisualTargetsMatched,
weak_factory_.GetWeakPtr()));
// TODO(crbug/1278502): This is disabled as a temporary measure due to crashes.
-#elif BUILDFLAG(BUILD_WITH_TFLITE_LIB) && !defined(OS_CHROMEOS) && \
+#elif BUILDFLAG(BUILD_WITH_TFLITE_LIB) && !BUILDFLAG(IS_CHROMEOS) && \
!BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_CHROMEOS_LACROS)
scorer_->ApplyVisualTfLiteModel(
*bitmap_, base::BindOnce(&PhishingClassifier::OnVisualTfLiteModelDone,
@@ -309,7 +310,7 @@ void PhishingClassifier::OnVisualTargetsMatched(
base::TimeTicks::Now() - visual_matching_start_);
// TODO(crbug/1278502): This is disabled as a temporary measure due to crashes.
-#if BUILDFLAG(BUILD_WITH_TFLITE_LIB) && !defined(OS_CHROMEOS) && \
+#if BUILDFLAG(BUILD_WITH_TFLITE_LIB) && !BUILDFLAG(IS_CHROMEOS) && \
!BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_CHROMEOS_LACROS)
scorer_->ApplyVisualTfLiteModel(
*bitmap_, base::BindOnce(&PhishingClassifier::OnVisualTfLiteModelDone,
diff --git a/chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier.h b/chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier.h
index 783d4c4eb29..be2f1789a7c 100644
--- a/chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier.h
+++ b/chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier.h
@@ -69,7 +69,7 @@ class PhishingClassifier {
// This must live at least as long as the PhishingClassifier. The caller is
// expected to cancel any pending classification before setting a phishing
// scorer.
- void set_phishing_scorer(const Scorer* scorer);
+ void set_phishing_scorer(Scorer* scorer);
// Returns true if the classifier is ready to classify pages, i.e. it
// has had a scorer set via set_phishing_scorer().
@@ -151,7 +151,7 @@ class PhishingClassifier {
void Clear();
content::RenderFrame* render_frame_; // owns us
- const Scorer* scorer_; // owned by the caller
+ Scorer* scorer_; // owned by the caller
std::unique_ptr<PhishingUrlFeatureExtractor> url_extractor_;
std::unique_ptr<PhishingDOMFeatureExtractor> dom_extractor_;
std::unique_ptr<PhishingTermFeatureExtractor> term_extractor_;
diff --git a/chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier_delegate.cc b/chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier_delegate.cc
index 9297b5506d0..5f423be061b 100644
--- a/chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier_delegate.cc
+++ b/chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier_delegate.cc
@@ -48,8 +48,8 @@ std::set<PhishingClassifierDelegate*>& PhishingClassifierDelegates() {
return *s;
}
-base::LazyInstance<std::unique_ptr<const safe_browsing::Scorer>>::
- DestructorAtExit g_phishing_scorer = LAZY_INSTANCE_INITIALIZER;
+base::LazyInstance<std::unique_ptr<safe_browsing::Scorer>>::DestructorAtExit
+ g_phishing_scorer = LAZY_INSTANCE_INITIALIZER;
} // namespace
@@ -123,7 +123,7 @@ PhishingClassifierDelegate* PhishingClassifierDelegate::Create(
}
void PhishingClassifierDelegate::SetPhishingScorer(
- const safe_browsing::Scorer* scorer) {
+ safe_browsing::Scorer* scorer) {
if (is_classifying_) {
// If there is a classification going on right now it means we're
// actually replacing an existing scorer with a new model. In
diff --git a/chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier_delegate.h b/chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier_delegate.h
index 02a315a2ca2..4bf53916e35 100644
--- a/chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier_delegate.h
+++ b/chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_classifier_delegate.h
@@ -64,7 +64,7 @@ class PhishingClassifierDelegate : public content::RenderFrameObserver,
// Called by the RenderFrame once there is a phishing scorer available.
// The scorer is passed on to the classifier.
- void SetPhishingScorer(const safe_browsing::Scorer* scorer);
+ void SetPhishingScorer(safe_browsing::Scorer* scorer);
// Called by the RenderFrame once a page has finished loading. Updates the
// last-loaded URL and page text, then starts classification if all other
diff --git a/chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_term_feature_extractor_unittest.cc b/chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_term_feature_extractor_unittest.cc
index 011976fd7ec..ce6e7426dd0 100644
--- a/chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_term_feature_extractor_unittest.cc
+++ b/chromium/components/safe_browsing/content/renderer/phishing_classifier/phishing_term_feature_extractor_unittest.cc
@@ -268,7 +268,7 @@ TEST_F(PhishingTermFeatureExtractorTest, ExtractFeatures) {
ExpectFeatureMapsAreEqual(features, expected_features);
EXPECT_THAT(expected_shingle_hashes, testing::ContainerEq(shingle_hashes));
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
// The test code is disabled due to http://crbug.com/392234
// The client-side detection feature is not enabled on Android yet.
// If we decided to enable the feature, we need to fix the bug first.
diff --git a/chromium/components/safe_browsing/content/renderer/phishing_classifier/protobuf_scorer.cc b/chromium/components/safe_browsing/content/renderer/phishing_classifier/protobuf_scorer.cc
index af7927d437d..44f69f9b4ba 100644
--- a/chromium/components/safe_browsing/content/renderer/phishing_classifier/protobuf_scorer.cc
+++ b/chromium/components/safe_browsing/content/renderer/phishing_classifier/protobuf_scorer.cc
@@ -17,6 +17,7 @@
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "base/trace_event/trace_event.h"
+#include "build/build_config.h"
#include "components/safe_browsing/content/renderer/phishing_classifier/features.h"
#include "components/safe_browsing/core/common/proto/client_model.pb.h"
#include "components/safe_browsing/core/common/proto/csd.pb.h"
@@ -116,10 +117,13 @@ ProtobufModelScorer* ProtobufModelScorer::Create(
}
// Only do this part if the visual model file exists
- if (visual_tflite_model.IsValid() && !scorer->visual_tflite_model_.Initialize(
- std::move(visual_tflite_model))) {
- RecordScorerCreationStatus(SCORER_FAIL_MAP_VISUAL_TFLITE_MODEL);
- return nullptr;
+ if (visual_tflite_model.IsValid()) {
+ scorer->visual_tflite_model_ = std::make_unique<base::MemoryMappedFile>();
+ if (!scorer->visual_tflite_model_->Initialize(
+ std::move(visual_tflite_model))) {
+ RecordScorerCreationStatus(SCORER_FAIL_MAP_VISUAL_TFLITE_MODEL);
+ return nullptr;
+ }
}
RecordScorerCreationStatus(SCORER_SUCCESS);
@@ -149,13 +153,13 @@ void ProtobufModelScorer::GetMatchingVisualTargets(
std::move(callback));
}
-#if BUILDFLAG(BUILD_WITH_TFLITE_LIB) && !defined(OS_CHROMEOS) && \
+#if BUILDFLAG(BUILD_WITH_TFLITE_LIB) && !BUILDFLAG(IS_CHROMEOS) && \
!BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_CHROMEOS_LACROS)
void ProtobufModelScorer::ApplyVisualTfLiteModel(
const SkBitmap& bitmap,
- base::OnceCallback<void(std::vector<double>)> callback) const {
+ base::OnceCallback<void(std::vector<double>)> callback) {
DCHECK(content::RenderThread::IsMainThread());
- if (visual_tflite_model_.IsValid()) {
+ if (visual_tflite_model_ && visual_tflite_model_->IsValid()) {
base::Time start_post_task_time = base::Time::Now();
base::ThreadPool::PostTaskAndReplyWithResult(
FROM_HERE,
@@ -163,10 +167,9 @@ void ProtobufModelScorer::ApplyVisualTfLiteModel(
base::BindOnce(&ApplyVisualTfLiteModelHelper, bitmap,
model_.tflite_metadata().input_width(),
model_.tflite_metadata().input_height(),
- std::string(reinterpret_cast<const char*>(
- visual_tflite_model_.data()),
- visual_tflite_model_.length())),
- std::move(callback));
+ std::move(visual_tflite_model_)),
+ base::BindOnce(&ProtobufModelScorer::OnVisualTfLiteModelComplete,
+ weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
base::UmaHistogramTimes(
"SBClientPhishing.TfLiteModelLoadTime.ProtobufScorer",
base::Time::Now() - start_post_task_time);
@@ -181,7 +184,7 @@ int ProtobufModelScorer::model_version() const {
}
bool Scorer::HasVisualTfLiteModel() const {
- return visual_tflite_model_.IsValid();
+ return visual_tflite_model_ && visual_tflite_model_->IsValid();
}
const std::unordered_set<std::string>&
diff --git a/chromium/components/safe_browsing/content/renderer/phishing_classifier/protobuf_scorer.h b/chromium/components/safe_browsing/content/renderer/phishing_classifier/protobuf_scorer.h
index e6607956348..11fc051da07 100644
--- a/chromium/components/safe_browsing/content/renderer/phishing_classifier/protobuf_scorer.h
+++ b/chromium/components/safe_browsing/content/renderer/phishing_classifier/protobuf_scorer.h
@@ -53,11 +53,11 @@ class ProtobufModelScorer : public Scorer {
const override;
// TODO(crbug/1278502): This is disabled as a temporary measure due to crashes.
-#if BUILDFLAG(BUILD_WITH_TFLITE_LIB) && !defined(OS_CHROMEOS) && \
+#if BUILDFLAG(BUILD_WITH_TFLITE_LIB) && !BUILDFLAG(IS_CHROMEOS) && \
!BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_CHROMEOS_LACROS)
void ApplyVisualTfLiteModel(
const SkBitmap& bitmap,
- base::OnceCallback<void(std::vector<double>)> callback) const override;
+ base::OnceCallback<void(std::vector<double>)> callback) override;
#endif
int model_version() const override;
diff --git a/chromium/components/safe_browsing/content/renderer/phishing_classifier/scorer.cc b/chromium/components/safe_browsing/content/renderer/phishing_classifier/scorer.cc
index f1334313c74..a66a8f8c5fa 100644
--- a/chromium/components/safe_browsing/content/renderer/phishing_classifier/scorer.cc
+++ b/chromium/components/safe_browsing/content/renderer/phishing_classifier/scorer.cc
@@ -12,6 +12,7 @@
#include "base/memory/read_only_shared_memory_region.h"
#include "base/memory/shared_memory_mapping.h"
+#include "base/metrics/histogram_functions.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
#include "base/task/task_traits.h"
@@ -60,10 +61,11 @@ std::unique_ptr<tflite::MutableOpResolver> CreateOpResolver() {
}
std::unique_ptr<tflite::task::vision::ImageClassifier> CreateClassifier(
- const std::string& model_data) {
+ std::string model_data) {
TRACE_EVENT0("safe_browsing", "CreateTfLiteClassifier");
tflite::task::vision::ImageClassifierOptions options;
- options.mutable_model_file_with_metadata()->set_file_content(model_data);
+ options.mutable_model_file_with_metadata()->set_file_content(
+ std::move(model_data));
auto statusor_classifier =
tflite::task::vision::ImageClassifier::CreateFromOptions(
options, CreateOpResolver());
@@ -109,21 +111,37 @@ std::string GetModelInput(const SkBitmap& bitmap, int width, int height) {
} // namespace
#if BUILDFLAG(BUILD_WITH_TFLITE_LIB)
-std::vector<double> Scorer::ApplyVisualTfLiteModelHelper(
+Scorer::VisualTfliteModelHelperResult Scorer::ApplyVisualTfLiteModelHelper(
const SkBitmap& bitmap,
int input_width,
int input_height,
- const std::string& model_data) {
+ std::unique_ptr<base::MemoryMappedFile> visual_tflite_model) {
+ VisualTfliteModelHelperResult result;
+ result.visual_tflite_model = std::move(visual_tflite_model);
+
TRACE_EVENT0("safe_browsing", "ApplyVisualTfLiteModel");
+ base::Time before_operation = base::Time::Now();
+ std::string model_data = std::string(
+ reinterpret_cast<const char*>(result.visual_tflite_model->data()),
+ result.visual_tflite_model->length());
+ base::UmaHistogramTimes("SBClientPhishing.ApplyTfliteTime.ModelCopy",
+ base::Time::Now() - before_operation);
+ before_operation = base::Time::Now();
std::unique_ptr<tflite::task::vision::ImageClassifier> classifier =
- CreateClassifier(model_data);
+ CreateClassifier(std::move(model_data));
+ base::UmaHistogramTimes("SBClientPhishing.ApplyTfliteTime.CreateClassifier",
+ base::Time::Now() - before_operation);
if (!classifier)
- return std::vector<double>();
+ return result;
+ before_operation = base::Time::Now();
std::string model_input = GetModelInput(bitmap, input_width, input_height);
if (model_input.empty())
- return std::vector<double>();
+ return result;
+ base::UmaHistogramTimes("SBClientPhishing.ApplyTfliteTime.GetModelInput",
+ base::Time::Now() - before_operation);
+ before_operation = base::Time::Now();
tflite::task::vision::FrameBuffer::Plane plane{
reinterpret_cast<const tflite::uint8*>(model_input.data()),
{3 * input_width, 3}};
@@ -132,9 +150,11 @@ std::vector<double> Scorer::ApplyVisualTfLiteModelHelper(
tflite::task::vision::FrameBuffer::Format::kRGB,
tflite::task::vision::FrameBuffer::Orientation::kTopLeft);
auto statusor_result = classifier->Classify(*frame_buffer);
+ base::UmaHistogramTimes("SBClientPhishing.ApplyTfliteTime.Classify",
+ base::Time::Now() - before_operation);
if (!statusor_result.ok()) {
VLOG(1) << statusor_result.status().ToString();
- return std::vector<double>();
+ return result;
} else {
std::vector<double> scores(
statusor_result->classifications(0).classes().size());
@@ -142,9 +162,17 @@ std::vector<double> Scorer::ApplyVisualTfLiteModelHelper(
statusor_result->classifications(0).classes()) {
scores[clas.index()] = clas.score();
}
- return scores;
+ result.scores = std::move(scores);
+ return result;
}
}
+
+void Scorer::OnVisualTfLiteModelComplete(
+ base::OnceCallback<void(std::vector<double>)> callback,
+ VisualTfliteModelHelperResult result) {
+ visual_tflite_model_ = std::move(result.visual_tflite_model);
+ std::move(callback).Run(result.scores);
+}
#endif
double Scorer::LogOdds2Prob(double log_odds) {
@@ -161,4 +189,14 @@ double Scorer::LogOdds2Prob(double log_odds) {
Scorer::Scorer() = default;
Scorer::~Scorer() = default;
+Scorer::VisualTfliteModelHelperResult::VisualTfliteModelHelperResult() =
+ default;
+Scorer::VisualTfliteModelHelperResult::~VisualTfliteModelHelperResult() =
+ default;
+Scorer::VisualTfliteModelHelperResult::VisualTfliteModelHelperResult(
+ VisualTfliteModelHelperResult&&) = default;
+Scorer::VisualTfliteModelHelperResult&
+Scorer::VisualTfliteModelHelperResult::operator=(
+ VisualTfliteModelHelperResult&&) = default;
+
} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing/content/renderer/phishing_classifier/scorer.h b/chromium/components/safe_browsing/content/renderer/phishing_classifier/scorer.h
index 208993af2fe..110edf6aa55 100644
--- a/chromium/components/safe_browsing/content/renderer/phishing_classifier/scorer.h
+++ b/chromium/components/safe_browsing/content/renderer/phishing_classifier/scorer.h
@@ -27,6 +27,7 @@
#include "base/memory/weak_ptr.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/string_piece.h"
+#include "build/build_config.h"
#include "components/optimization_guide/machine_learning_tflite_buildflags.h"
#include "components/safe_browsing/core/common/proto/client_model.pb.h"
#include "components/safe_browsing/core/common/proto/csd.pb.h"
@@ -78,14 +79,14 @@ class Scorer {
const = 0;
// TODO(crbug/1278502): This is disabled as a temporary measure due to crashes.
-#if BUILDFLAG(BUILD_WITH_TFLITE_LIB) && !defined(OS_CHROMEOS) && \
+#if BUILDFLAG(BUILD_WITH_TFLITE_LIB) && !BUILDFLAG(IS_CHROMEOS) && \
!BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_CHROMEOS_LACROS)
// This method applies the TfLite visual model to the given bitmap. It
// asynchronously returns the list of scores for each category, in the same
// order as `tflite_thresholds()`.
virtual void ApplyVisualTfLiteModel(
const SkBitmap& bitmap,
- base::OnceCallback<void(std::vector<double>)> callback) const = 0;
+ base::OnceCallback<void(std::vector<double>)> callback) = 0;
#endif
// Returns the version number of the loaded client model.
@@ -135,14 +136,33 @@ class Scorer {
// [0.0,1.0].
static double LogOdds2Prob(double log_odds);
+ // Helper struct used to return the scores and the memory mapped file
+ // containing the model back to the main thread.
+ struct VisualTfliteModelHelperResult {
+ VisualTfliteModelHelperResult();
+ ~VisualTfliteModelHelperResult();
+ VisualTfliteModelHelperResult(const VisualTfliteModelHelperResult&) =
+ delete;
+ VisualTfliteModelHelperResult& operator=(
+ const VisualTfliteModelHelperResult&) = delete;
+ VisualTfliteModelHelperResult(VisualTfliteModelHelperResult&&);
+ VisualTfliteModelHelperResult& operator=(VisualTfliteModelHelperResult&&);
+
+ std::vector<double> scores;
+ std::unique_ptr<base::MemoryMappedFile> visual_tflite_model;
+ };
+
// Apply the tflite model to the bitmap, and return scores.
- static std::vector<double> ApplyVisualTfLiteModelHelper(
+ static VisualTfliteModelHelperResult ApplyVisualTfLiteModelHelper(
const SkBitmap& bitmap,
int input_width,
int input_height,
- const std::string& model_data);
+ std::unique_ptr<base::MemoryMappedFile> visual_tflite_model);
+ void OnVisualTfLiteModelComplete(
+ base::OnceCallback<void(std::vector<double>)> callback,
+ VisualTfliteModelHelperResult result);
- base::MemoryMappedFile visual_tflite_model_;
+ std::unique_ptr<base::MemoryMappedFile> visual_tflite_model_;
base::WeakPtrFactory<Scorer> weak_ptr_factory_{this};
private:
diff --git a/chromium/components/safe_browsing/content/resources/download_file_types.asciipb b/chromium/components/safe_browsing/content/resources/download_file_types.asciipb
index f93154422e1..928e55b9d1c 100644
--- a/chromium/components/safe_browsing/content/resources/download_file_types.asciipb
+++ b/chromium/components/safe_browsing/content/resources/download_file_types.asciipb
@@ -8,7 +8,7 @@
##
## Top level settings
##
-version_id: 47
+version_id: 48
sampled_ping_probability: 0.01
max_archived_binaries_to_report: 10
default_file_type {
@@ -1525,9 +1525,15 @@ file_types {
ping_setting: FULL_PING
}
file_types {
+ # DLL files built for excel.
extension: "xll"
uma_value: 350
ping_setting: FULL_PING
+ platform_settings {
+ platform: PLATFORM_WINDOWS
+ danger_level: ALLOW_ON_USER_GESTURE
+ auto_open_hint: DISALLOW_AUTO_OPEN
+ }
}
file_types {
extension: "xlm"
diff --git a/chromium/components/safe_browsing/content/resources/download_file_types_experiment.asciipb b/chromium/components/safe_browsing/content/resources/download_file_types_experiment.asciipb
index 0630edb2bcc..fc461cbd5c7 100644
--- a/chromium/components/safe_browsing/content/resources/download_file_types_experiment.asciipb
+++ b/chromium/components/safe_browsing/content/resources/download_file_types_experiment.asciipb
@@ -12,7 +12,7 @@
## version id is larger than the version id in download_file_types.asciipb. If
## there isn't an ongoing experiment, this version id is equal to the version id
## in download_file_types.asciipb.
-version_id: 47
+version_id: 48
sampled_ping_probability: 0.01
max_archived_binaries_to_report: 10
default_file_type {
@@ -1529,9 +1529,15 @@ file_types {
ping_setting: FULL_PING
}
file_types {
+ # DLL files built for excel.
extension: "xll"
uma_value: 350
ping_setting: FULL_PING
+ platform_settings {
+ platform: PLATFORM_WINDOWS
+ danger_level: ALLOW_ON_USER_GESTURE
+ auto_open_hint: DISALLOW_AUTO_OPEN
+ }
}
file_types {
extension: "xlm"
diff --git a/chromium/components/safe_browsing/core/browser/BUILD.gn b/chromium/components/safe_browsing/core/browser/BUILD.gn
index 9ee8f36f632..88064ff95c1 100644
--- a/chromium/components/safe_browsing/core/browser/BUILD.gn
+++ b/chromium/components/safe_browsing/core/browser/BUILD.gn
@@ -19,7 +19,9 @@ source_set("browser") {
deps = [
"//base",
+ "//components/keyed_service/core",
"//components/prefs",
+ "//components/safe_browsing/core/browser:token_fetcher",
"//components/safe_browsing/core/browser/db:database_manager",
"//components/safe_browsing/core/browser/db:hit_report",
"//components/safe_browsing/core/browser/db:util",
@@ -153,6 +155,7 @@ source_set("safe_browsing_metrics_collector") {
"//base",
"//components/keyed_service/core",
"//components/prefs",
+ "//components/safe_browsing/core/browser/db:hit_report",
"//components/safe_browsing/core/common:safe_browsing_prefs",
]
}
@@ -166,6 +169,7 @@ source_set("safe_browsing_metrics_collector_unittest") {
"//base/test:test_support",
"//components/prefs",
"//components/prefs:test_support",
+ "//components/safe_browsing/core/common",
"//components/safe_browsing/core/common:safe_browsing_prefs",
"//testing/gtest",
]
diff --git a/chromium/components/safe_browsing/core/browser/DEPS b/chromium/components/safe_browsing/core/browser/DEPS
index 810704b76c3..1b8bc5e1e6f 100644
--- a/chromium/components/safe_browsing/core/browser/DEPS
+++ b/chromium/components/safe_browsing/core/browser/DEPS
@@ -1,5 +1,6 @@
include_rules = [
"+components/history/core/browser",
+ "+components/content_settings/core",
"+components/sessions/core/session_id.h",
"+components/version_info",
"+ipc/ipc_message.h",
diff --git a/chromium/components/safe_browsing/core/browser/db/v4_database.cc b/chromium/components/safe_browsing/core/browser/db/v4_database.cc
index 2184ae2a25a..f2f7d33acb9 100644
--- a/chromium/components/safe_browsing/core/browser/db/v4_database.cc
+++ b/chromium/components/safe_browsing/core/browser/db/v4_database.cc
@@ -18,7 +18,7 @@
#include "build/build_config.h"
#include "components/safe_browsing/core/common/proto/webui.pb.h"
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
#include "base/mac/backup_util.h"
#endif
@@ -92,7 +92,7 @@ void V4Database::CreateOnTaskRunner(
if (!base::CreateDirectory(base_path))
NOTREACHED();
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
base::mac::SetBackupExclusion(base_path);
#endif
diff --git a/chromium/components/safe_browsing/core/browser/db/v4_get_hash_protocol_manager_unittest.cc b/chromium/components/safe_browsing/core/browser/db/v4_get_hash_protocol_manager_unittest.cc
index ac320f4cc1e..13ed4fd888d 100644
--- a/chromium/components/safe_browsing/core/browser/db/v4_get_hash_protocol_manager_unittest.cc
+++ b/chromium/components/safe_browsing/core/browser/db/v4_get_hash_protocol_manager_unittest.cc
@@ -672,7 +672,7 @@ TEST_F(V4GetHashProtocolManagerTest,
m->set_threat_type(API_ABUSE);
// TODO(crbug.com/1030487): This special case for Android will no longer be
// needed once GetCurrentPlatformType() returns ANDROID_PLATFORM on Android.
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
m->set_platform_type(ANDROID_PLATFORM);
#else
m->set_platform_type(GetCurrentPlatformType());
diff --git a/chromium/components/safe_browsing/core/browser/db/v4_local_database_manager.cc b/chromium/components/safe_browsing/core/browser/db/v4_local_database_manager.cc
index b7ea7472d50..786aaeebe32 100644
--- a/chromium/components/safe_browsing/core/browser/db/v4_local_database_manager.cc
+++ b/chromium/components/safe_browsing/core/browser/db/v4_local_database_manager.cc
@@ -67,7 +67,7 @@ ListInfos GetListInfos() {
// - The list doesn't have hash prefixes to match. All requests lead to full
// hash checks. For instance: GetChromeUrlApiId()
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
const bool kSyncOnIos = true;
#else
const bool kSyncOnIos = false;
diff --git a/chromium/components/safe_browsing/core/browser/db/v4_local_database_manager_unittest.cc b/chromium/components/safe_browsing/core/browser/db/v4_local_database_manager_unittest.cc
index 889010fd301..7f28936bacf 100644
--- a/chromium/components/safe_browsing/core/browser/db/v4_local_database_manager_unittest.cc
+++ b/chromium/components/safe_browsing/core/browser/db/v4_local_database_manager_unittest.cc
@@ -1436,7 +1436,7 @@ TEST_F(V4LocalDatabaseManagerTest, FlagMultipleUrls) {
TEST_F(V4LocalDatabaseManagerTest, SyncedLists) {
WaitForTasksOnTaskRunner();
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
std::vector<ListIdentifier> expected_lists{
GetUrlSocEngId(), GetUrlMalwareId(), GetUrlBillingId(),
GetUrlCsdAllowlistId(), GetUrlHighConfidenceAllowlistId()};
diff --git a/chromium/components/safe_browsing/core/browser/db/v4_protocol_manager_util.cc b/chromium/components/safe_browsing/core/browser/db/v4_protocol_manager_util.cc
index cca73b537ed..9fb5472abda 100644
--- a/chromium/components/safe_browsing/core/browser/db/v4_protocol_manager_util.cc
+++ b/chromium/components/safe_browsing/core/browser/db/v4_protocol_manager_util.cc
@@ -113,13 +113,13 @@ std::ostream& operator<<(std::ostream& os, const ListIdentifier& id) {
}
PlatformType GetCurrentPlatformType() {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
return WINDOWS_PLATFORM;
-#elif defined(OS_LINUX) || defined(OS_CHROMEOS)
+#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
return LINUX_PLATFORM;
-#elif defined(OS_IOS)
+#elif BUILDFLAG(IS_IOS)
return IOS_PLATFORM;
-#elif defined(OS_MAC)
+#elif BUILDFLAG(IS_MAC)
return OSX_PLATFORM;
#else
return ANDROID_PLATFORM;
diff --git a/chromium/components/safe_browsing/core/browser/db/v4_rice.cc b/chromium/components/safe_browsing/core/browser/db/v4_rice.cc
index 6b17e71352c..1fc02f19f61 100644
--- a/chromium/components/safe_browsing/core/browser/db/v4_rice.cc
+++ b/chromium/components/safe_browsing/core/browser/db/v4_rice.cc
@@ -12,9 +12,9 @@
#include "build/build_config.h"
#include "components/safe_browsing/core/browser/db/v4_rice.h"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include <winsock2.h>
-#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
#include <arpa/inet.h>
#endif
diff --git a/chromium/components/safe_browsing/core/browser/db/v4_store.h b/chromium/components/safe_browsing/core/browser/db/v4_store.h
index 8e050617631..9b2cdb2957e 100644
--- a/chromium/components/safe_browsing/core/browser/db/v4_store.h
+++ b/chromium/components/safe_browsing/core/browser/db/v4_store.h
@@ -15,6 +15,7 @@
#include "base/gtest_prod_util.h"
#include "base/memory/ref_counted.h"
#include "base/task/sequenced_task_runner.h"
+#include "base/time/time.h"
#include "components/safe_browsing/core/browser/db/v4_protocol_manager_util.h"
#include "components/safe_browsing/core/common/proto/webui.pb.h"
diff --git a/chromium/components/safe_browsing/core/browser/password_protection/password_protection_request.cc b/chromium/components/safe_browsing/core/browser/password_protection/password_protection_request.cc
index 6879beea7fa..3ceedd3cb32 100644
--- a/chromium/components/safe_browsing/core/browser/password_protection/password_protection_request.cc
+++ b/chromium/components/safe_browsing/core/browser/password_protection/password_protection_request.cc
@@ -10,6 +10,7 @@
#include "base/metrics/histogram_functions.h"
#include "base/strings/strcat.h"
#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
#include "components/safe_browsing/core/browser/db/allowlist_checker_client.h"
#include "components/safe_browsing/core/browser/db/database_manager.h"
#include "components/safe_browsing/core/browser/password_protection/password_protection_service_base.h"
@@ -110,17 +111,6 @@ PasswordProtectionRequest::~PasswordProtectionRequest() = default;
void PasswordProtectionRequest::Start() {
DCHECK(ui_task_runner()->RunsTasksInCurrentSequence());
- if (trigger_type_ == LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE) {
- base::UmaHistogramExactLinear(
- "PasswordProtection.OnFocus.UserPopulationStart",
- password_protection_service_->GetUserPopulationPref(),
- ChromeUserPopulation::UserPopulation_MAX + 1);
- } else {
- base::UmaHistogramExactLinear(
- "PasswordProtection.PasswordEntry.UserPopulationStart",
- password_protection_service_->GetUserPopulationPref(),
- ChromeUserPopulation::UserPopulation_MAX + 1);
- }
CheckAllowlist();
}
@@ -248,9 +238,9 @@ void PasswordProtectionRequest::FillRequestProto(bool is_sampled_ping) {
}
#endif // BUILDFLAG(FULL_SAFE_BROWSING)
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
SetReferringAppInfo();
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
switch (trigger_type_) {
case LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE: {
@@ -333,19 +323,6 @@ bool PasswordProtectionRequest::IsVisualFeaturesEnabled() {
void PasswordProtectionRequest::SendRequest() {
DCHECK(ui_task_runner()->RunsTasksInCurrentSequence());
-
- if (trigger_type_ == LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE) {
- base::UmaHistogramExactLinear(
- "PasswordProtection.OnFocus.UserPopulationOnPing",
- password_protection_service_->GetUserPopulationPref(),
- ChromeUserPopulation::UserPopulation_MAX + 1);
- } else {
- base::UmaHistogramExactLinear(
- "PasswordProtection.PasswordEntry.UserPopulationOnPing",
- password_protection_service_->GetUserPopulationPref(),
- ChromeUserPopulation::UserPopulation_MAX + 1);
- }
-
if (password_protection_service_->CanGetAccessToken() &&
password_protection_service_->token_fetcher()) {
password_protection_service_->token_fetcher()->Start(
diff --git a/chromium/components/safe_browsing/core/browser/password_protection/password_protection_request.h b/chromium/components/safe_browsing/core/browser/password_protection/password_protection_request.h
index 435077bdcf4..7fe32c3e12b 100644
--- a/chromium/components/safe_browsing/core/browser/password_protection/password_protection_request.h
+++ b/chromium/components/safe_browsing/core/browser/password_protection/password_protection_request.h
@@ -107,6 +107,12 @@ class PasswordProtectionRequest
request_outcome_ = request_outcome;
}
+ void finish_for_testing(
+ RequestOutcome outcome,
+ std::unique_ptr<LoginReputationClientResponse> response) {
+ Finish(outcome, std::move(response));
+ }
+
protected:
friend class base::RefCountedThreadSafe<PasswordProtectionRequest>;
@@ -193,10 +199,10 @@ class PasswordProtectionRequest
virtual void MaybeCollectVisualFeatures() = 0;
#endif // BUILDFLAG(SAFE_BROWSING_AVAILABLE)
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Sets the referring app info.
virtual void SetReferringAppInfo() = 0;
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
// Start a timer to cancel the request if it takes too long.
void StartTimeout();
diff --git a/chromium/components/safe_browsing/core/browser/password_protection/password_protection_service_base.cc b/chromium/components/safe_browsing/core/browser/password_protection/password_protection_service_base.cc
index f988534f9e1..708a064ba51 100644
--- a/chromium/components/safe_browsing/core/browser/password_protection/password_protection_service_base.cc
+++ b/chromium/components/safe_browsing/core/browser/password_protection/password_protection_service_base.cc
@@ -16,6 +16,7 @@
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/threading/sequenced_task_runner_handle.h"
+#include "build/build_config.h"
#include "components/password_manager/core/browser/password_manager_metrics_util.h"
#include "components/password_manager/core/browser/password_reuse_detector.h"
#include "components/safe_browsing/core/browser/db/database_manager.h"
@@ -141,7 +142,12 @@ bool PasswordProtectionServiceBase::CanSendPing(
ReusedPasswordAccountType password_type) {
return IsPingingEnabled(trigger_type, password_type) &&
!IsURLAllowlistedForPasswordEntry(main_frame_url) &&
- !IsInExcludedCountry();
+ !IsInExcludedCountry() &&
+ // Although we can't get the reputation of the main frame URL for
+ // password reuse on about:blank, the referrer chain still provides
+ // enough useful information that we should send the ping.
+ (main_frame_url == GURL("about:blank") ||
+ CanGetReputationOfURL(main_frame_url));
}
bool PasswordProtectionServiceBase::
@@ -195,7 +201,7 @@ void PasswordProtectionServiceBase::RequestFinished(
}
}
- MaybeHandleDeferredNavigations(request);
+ ResumeDeferredNavigationsIfNeeded(request);
// If the request is canceled, the PasswordProtectionServiceBase is already
// partially destroyed, and we won't be able to log accurate metrics.
@@ -208,7 +214,7 @@ void PasswordProtectionServiceBase::RequestFinished(
MaybeRecordSecuritySensitiveEvent(metrics_collector_, verdict);
// Disabled on Android, because enterprise reporting extension is not supported.
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
MaybeReportPasswordReuseDetected(
request, request->username(), request->password_type(),
verdict == LoginReputationClientResponse::PHISHING);
@@ -415,7 +421,7 @@ bool PasswordProtectionServiceBase::IsSupportedPasswordTypeForModalWarning(
// Currently password reuse warnings are only supported for saved passwords
// and GAIA passwords on Android.
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
return IsSyncingGMAILPasswordWithSignedInProtectionEnabled(password_type);
#else
if (password_type.account_type() ==
diff --git a/chromium/components/safe_browsing/core/browser/password_protection/password_protection_service_base.h b/chromium/components/safe_browsing/core/browser/password_protection/password_protection_service_base.h
index 46523c252da..27f4b7a0c5d 100644
--- a/chromium/components/safe_browsing/core/browser/password_protection/password_protection_service_base.h
+++ b/chromium/components/safe_browsing/core/browser/password_protection/password_protection_service_base.h
@@ -117,7 +117,7 @@ class PasswordProtectionServiceBase : public history::HistoryServiceObserver {
// The following functions are disabled on Android, because enterprise reporting
// extension is not supported.
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
// Triggers the safeBrowsingPrivate.OnPolicySpecifiedPasswordReuseDetected.
virtual void MaybeReportPasswordReuseDetected(
PasswordProtectionRequest* request,
@@ -249,6 +249,11 @@ class PasswordProtectionServiceBase : public history::HistoryServiceObserver {
virtual ChromeUserPopulation::UserPopulation GetUserPopulationPref()
const = 0;
+ std::set<scoped_refptr<PasswordProtectionRequest>>&
+ get_pending_requests_for_testing() {
+ return pending_requests_;
+ }
+
protected:
friend class PasswordProtectionRequest;
friend class PasswordProtectionRequestContent;
@@ -361,9 +366,9 @@ class PasswordProtectionServiceBase : public history::HistoryServiceObserver {
const GURL& url,
ReusedPasswordAccountType password_type) = 0;
- // Subclasses may override this method to either cancel or resume deferred
- // navigations. By default, deferred navigations are not handled.
- virtual void MaybeHandleDeferredNavigations(
+ // Subclasses may override this method to resume deferred navigations when a
+ // request finishes. By default, deferred navigations are not handled.
+ virtual void ResumeDeferredNavigationsIfNeeded(
PasswordProtectionRequest* request) {}
bool CanGetAccessToken();
@@ -403,6 +408,8 @@ class PasswordProtectionServiceBase : public history::HistoryServiceObserver {
TestRemoveCachedVerdictOnURLsDeleted);
FRIEND_TEST_ALL_PREFIXES(PasswordProtectionServiceTest,
TestCleanUpExpiredVerdict);
+ FRIEND_TEST_ALL_PREFIXES(PasswordProtectionServiceTest,
+ NoSendPingPrivateIpHostname);
// Overridden from history::HistoryServiceObserver.
void OnURLsDeleted(history::HistoryService* history_service,
diff --git a/chromium/components/safe_browsing/core/browser/ping_manager.cc b/chromium/components/safe_browsing/core/browser/ping_manager.cc
index 2fb9fb6b945..c3c8283e4e3 100644
--- a/chromium/components/safe_browsing/core/browser/ping_manager.cc
+++ b/chromium/components/safe_browsing/core/browser/ping_manager.cc
@@ -9,10 +9,12 @@
#include "base/bind.h"
#include "base/check.h"
#include "base/memory/ptr_util.h"
+#include "base/metrics/histogram_functions.h"
#include "base/notreached.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "components/safe_browsing/core/browser/db/v4_protocol_manager_util.h"
+#include "components/safe_browsing/core/common/utils.h"
#include "google_apis/google_api_keys.h"
#include "net/base/escape.h"
#include "net/base/load_flags.h"
@@ -67,12 +69,24 @@ namespace safe_browsing {
// SafeBrowsingPingManager implementation ----------------------------------
// static
-std::unique_ptr<PingManager> PingManager::Create(
- const V4ProtocolConfig& config) {
- return base::WrapUnique(new PingManager(config));
+PingManager* PingManager::Create(
+ const V4ProtocolConfig& config,
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+ std::unique_ptr<SafeBrowsingTokenFetcher> token_fetcher,
+ base::RepeatingCallback<bool()> get_should_fetch_access_token) {
+ return new PingManager(config, url_loader_factory, std::move(token_fetcher),
+ get_should_fetch_access_token);
}
-PingManager::PingManager(const V4ProtocolConfig& config) : config_(config) {}
+PingManager::PingManager(
+ const V4ProtocolConfig& config,
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+ std::unique_ptr<SafeBrowsingTokenFetcher> token_fetcher,
+ base::RepeatingCallback<bool()> get_should_fetch_access_token)
+ : config_(config),
+ url_loader_factory_(url_loader_factory),
+ token_fetcher_(std::move(token_fetcher)),
+ get_should_fetch_access_token_(get_should_fetch_access_token) {}
PingManager::~PingManager() {}
@@ -87,7 +101,6 @@ void PingManager::OnURLLoaderComplete(
// Sends a SafeBrowsing "hit" report.
void PingManager::ReportSafeBrowsingHit(
- scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
const safe_browsing::HitReport& hit_report) {
auto resource_request = std::make_unique<network::ResourceRequest>();
GURL report_url = SafeBrowsingHitUrl(hit_report);
@@ -103,16 +116,27 @@ void PingManager::ReportSafeBrowsingHit(
report_ptr->AttachStringForUpload(hit_report.post_data, "text/plain");
report_ptr->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
- url_loader_factory.get(),
+ url_loader_factory_.get(),
base::BindOnce(&PingManager::OnURLLoaderComplete, base::Unretained(this),
report_ptr.get()));
safebrowsing_reports_.insert(std::move(report_ptr));
}
// Sends threat details for users who opt-in.
-void PingManager::ReportThreatDetails(
- scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
- const std::string& report) {
+void PingManager::ReportThreatDetails(const std::string& report) {
+ if (get_should_fetch_access_token_.Run()) {
+ token_fetcher_->Start(
+ base::BindOnce(&PingManager::ReportThreatDetailsOnGotAccessToken,
+ weak_factory_.GetWeakPtr(), report));
+ } else {
+ std::string empty_access_token;
+ ReportThreatDetailsOnGotAccessToken(report, empty_access_token);
+ }
+}
+
+void PingManager::ReportThreatDetailsOnGotAccessToken(
+ const std::string& report,
+ const std::string& access_token) {
GURL report_url = ThreatDetailsUrl();
auto resource_request = std::make_unique<network::ResourceRequest>();
@@ -120,13 +144,21 @@ void PingManager::ReportThreatDetails(
resource_request->load_flags = net::LOAD_DISABLE_CACHE;
resource_request->method = "POST";
+ if (!access_token.empty()) {
+ SetAccessTokenAndClearCookieInResourceRequest(resource_request.get(),
+ access_token);
+ }
+ base::UmaHistogramBoolean(
+ "SafeBrowsing.ClientSafeBrowsingReport.RequestHasToken",
+ !access_token.empty());
+
auto loader = network::SimpleURLLoader::Create(std::move(resource_request),
kTrafficAnnotation);
loader->AttachStringForUpload(report, "application/octet-stream");
loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
- url_loader_factory.get(),
+ url_loader_factory_.get(),
base::BindOnce(&PingManager::OnURLLoaderComplete, base::Unretained(this),
loader.get()));
safebrowsing_reports_.insert(std::move(loader));
@@ -215,4 +247,14 @@ GURL PingManager::ThreatDetailsUrl() const {
return GURL(url);
}
+void PingManager::SetURLLoaderFactoryForTesting(
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) {
+ url_loader_factory_ = url_loader_factory;
+}
+
+void PingManager::SetTokenFetcherForTesting(
+ std::unique_ptr<SafeBrowsingTokenFetcher> token_fetcher) {
+ token_fetcher_ = std::move(token_fetcher);
+}
+
} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing/core/browser/ping_manager.h b/chromium/components/safe_browsing/core/browser/ping_manager.h
index 0575d9f77c7..0210b144a96 100644
--- a/chromium/components/safe_browsing/core/browser/ping_manager.h
+++ b/chromium/components/safe_browsing/core/browser/ping_manager.h
@@ -14,8 +14,10 @@
#include "base/containers/unique_ptr_adapters.h"
#include "base/gtest_prod_util.h"
#include "base/memory/ref_counted.h"
+#include "components/keyed_service/core/keyed_service.h"
#include "components/safe_browsing/core/browser/db/hit_report.h"
#include "components/safe_browsing/core/browser/db/util.h"
+#include "components/safe_browsing/core/browser/safe_browsing_token_fetcher.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "url/gurl.h"
@@ -25,37 +27,47 @@ class SimpleURLLoader;
namespace safe_browsing {
-class PingManager {
+class PingManager : public KeyedService {
public:
PingManager(const PingManager&) = delete;
PingManager& operator=(const PingManager&) = delete;
- virtual ~PingManager();
+ ~PingManager() override;
// Create an instance of the safe browsing ping manager.
- static std::unique_ptr<PingManager> Create(const V4ProtocolConfig& config);
+ static PingManager* Create(
+ const V4ProtocolConfig& config,
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+ std::unique_ptr<SafeBrowsingTokenFetcher> token_fetcher,
+ base::RepeatingCallback<bool()> get_should_fetch_access_token);
void OnURLLoaderComplete(network::SimpleURLLoader* source,
std::unique_ptr<std::string> response_body);
// Report to Google when a SafeBrowsing warning is shown to the user.
// |hit_report.threat_type| should be one of the types known by
- // SafeBrowsingtHitUrl. Uses the given |url_loader_factory| to get the network
- // context.
- void ReportSafeBrowsingHit(
- scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
- const safe_browsing::HitReport& hit_report);
+ // SafeBrowsingtHitUrl.
+ void ReportSafeBrowsingHit(const safe_browsing::HitReport& hit_report);
// Users can opt-in on the SafeBrowsing interstitial to send detailed
// threat reports. |report| is the serialized report.
- void ReportThreatDetails(
- scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
- const std::string& report);
+ void ReportThreatDetails(const std::string& report);
+
+ // Only used for tests
+ void SetURLLoaderFactoryForTesting(
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory);
+ void SetTokenFetcherForTesting(
+ std::unique_ptr<SafeBrowsingTokenFetcher> token_fetcher);
protected:
friend class PingManagerTest;
- // Constructs a PingManager with the given |config|.
- explicit PingManager(const V4ProtocolConfig& config);
+ // Constructs a PingManager with the given |config|, |url_loader_factory|, and
+ // access token fetching information.
+ explicit PingManager(
+ const V4ProtocolConfig& config,
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+ std::unique_ptr<SafeBrowsingTokenFetcher> token_fetcher,
+ base::RepeatingCallback<bool()> get_should_fetch_access_token);
private:
FRIEND_TEST_ALL_PREFIXES(PingManagerTest, TestSafeBrowsingHitUrl);
@@ -74,9 +86,26 @@ class PingManager {
// Generates URL for reporting threat details for users who opt-in.
GURL ThreatDetailsUrl() const;
+ // Once the user's access_token has been fetched by ReportThreatDetails (or
+ // intentionally not fetched), attaches the token and sends the report.
+ void ReportThreatDetailsOnGotAccessToken(const std::string& report,
+ const std::string& access_token);
+
// Track outstanding SafeBrowsing report fetchers for clean up.
// We add both "hit" and "detail" fetchers in this set.
Reports safebrowsing_reports_;
+
+ // Used to issue network requests.
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
+
+ // The token fetcher used for getting access token.
+ std::unique_ptr<SafeBrowsingTokenFetcher> token_fetcher_;
+
+ // Determines whether it's relevant to fetch the access token for the user
+ // based on whether they're a signed-in ESB user.
+ base::RepeatingCallback<bool()> get_should_fetch_access_token_;
+
+ base::WeakPtrFactory<PingManager> weak_factory_{this};
};
} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing/core/browser/ping_manager_unittest.cc b/chromium/components/safe_browsing/core/browser/ping_manager_unittest.cc
index 5580026a44c..d5a81d64059 100644
--- a/chromium/components/safe_browsing/core/browser/ping_manager_unittest.cc
+++ b/chromium/components/safe_browsing/core/browser/ping_manager_unittest.cc
@@ -33,7 +33,8 @@ class PingManagerTest : public testing::Test {
}
ping_manager_.reset(
- new PingManager(safe_browsing::GetTestV4ProtocolConfig()));
+ new PingManager(safe_browsing::GetTestV4ProtocolConfig(), nullptr,
+ nullptr, base::BindRepeating([]() { return false; })));
}
PingManager* ping_manager() { return ping_manager_.get(); }
diff --git a/chromium/components/safe_browsing/core/browser/realtime/policy_engine.cc b/chromium/components/safe_browsing/core/browser/realtime/policy_engine.cc
index 132b770408a..0b2f00bbfe1 100644
--- a/chromium/components/safe_browsing/core/browser/realtime/policy_engine.cc
+++ b/chromium/components/safe_browsing/core/browser/realtime/policy_engine.cc
@@ -15,7 +15,7 @@
#include "components/variations/service/variations_service.h"
#include "services/network/public/cpp/request_destination.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "base/metrics/field_trial_params.h"
#include "base/system/sys_info.h"
#endif
diff --git a/chromium/components/safe_browsing/core/browser/realtime/policy_engine_unittest.cc b/chromium/components/safe_browsing/core/browser/realtime/policy_engine_unittest.cc
index 6d882ad154a..daa565827ae 100644
--- a/chromium/components/safe_browsing/core/browser/realtime/policy_engine_unittest.cc
+++ b/chromium/components/safe_browsing/core/browser/realtime/policy_engine_unittest.cc
@@ -4,7 +4,9 @@
#include "components/safe_browsing/core/browser/realtime/policy_engine.h"
+#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
+#include "components/safe_browsing/core/common/features.h"
#include "components/safe_browsing/core/common/safe_browsing_prefs.h"
#include "components/safe_browsing/core/common/safebrowsing_constants.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
@@ -86,12 +88,24 @@ TEST_F(RealTimePolicyEngineTest, TestCanPerformFullURLLookup_EnabledUserOptin) {
TEST_F(RealTimePolicyEngineTest,
TestCanPerformFullURLLookup_EnhancedProtection) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeature(kEnhancedProtection);
pref_service_.SetBoolean(prefs::kSafeBrowsingEnhanced, true);
ASSERT_TRUE(CanPerformFullURLLookup(/* is_off_the_record */ false));
}
TEST_F(RealTimePolicyEngineTest,
+ TestCanPerformFullURLLookup_DisabledEnhancedProtection) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndDisableFeature(kEnhancedProtection);
+ pref_service_.SetBoolean(prefs::kSafeBrowsingEnhanced, true);
+ ASSERT_FALSE(CanPerformFullURLLookup(/* is_off_the_record */ false));
+}
+
+TEST_F(RealTimePolicyEngineTest,
TestCanPerformFullURLLookup_RTLookupForEpEnabled_WithTokenDisabled) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeature(kEnhancedProtection);
pref_service_.SetBoolean(prefs::kSafeBrowsingEnhanced, true);
EXPECT_TRUE(CanPerformFullURLLookup(/* is_off_the_record */ false));
EXPECT_TRUE(CanPerformFullURLLookupWithToken(
@@ -126,6 +140,8 @@ TEST_F(
TEST_F(
RealTimePolicyEngineTest,
TestCanPerformFullURLLookupWithToken_ClientControlledWithEnhancedProtection) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeature(kEnhancedProtection);
// Enhanced protection is disabled: token fetches should be disallowed whether
// or not they are configured in the client.
EXPECT_FALSE(CanPerformFullURLLookupWithToken(
diff --git a/chromium/components/safe_browsing/core/browser/realtime/url_lookup_service.cc b/chromium/components/safe_browsing/core/browser/realtime/url_lookup_service.cc
index 1a2c3091088..4ac929c1fe4 100644
--- a/chromium/components/safe_browsing/core/browser/realtime/url_lookup_service.cc
+++ b/chromium/components/safe_browsing/core/browser/realtime/url_lookup_service.cc
@@ -8,6 +8,7 @@
#include "base/metrics/field_trial_params.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
+#include "base/rand_util.h"
#include "base/strings/strcat.h"
#include "base/strings/string_piece.h"
#include "base/task/post_task.h"
@@ -33,6 +34,9 @@ namespace {
constexpr int kDefaultRealTimeUrlLookupReferrerLength = 2;
+// Probability for sending protego requests for urls on the allowlist
+const float kProbabilityForSendingSampledRequests = 0.01;
+
} // namespace
namespace safe_browsing {
@@ -106,7 +110,7 @@ void RealTimeUrlLookupService::OnGetAccessToken(
!access_token.empty());
SendRequest(url, last_committed_url, is_mainframe, access_token,
std::move(request_callback), std::move(response_callback),
- std::move(callback_task_runner));
+ std::move(callback_task_runner), /* is_sampled_report */ false);
}
void RealTimeUrlLookupService::OnResponseUnauthorized(
@@ -127,10 +131,6 @@ bool RealTimeUrlLookupService::CanPerformFullURLLookupWithToken() const {
variations_);
}
-bool RealTimeUrlLookupService::CanAttachReferrerChain() const {
- return true;
-}
-
int RealTimeUrlLookupService::GetReferrerUserGestureLimit() const {
return kDefaultRealTimeUrlLookupReferrerLength;
}
@@ -149,6 +149,14 @@ bool RealTimeUrlLookupService::CanCheckSafeBrowsingDb() const {
return true;
}
+bool RealTimeUrlLookupService::CanSendRTSampleRequest() const {
+ return IsExtendedReportingEnabled(*pref_service_) &&
+ base::FeatureList::IsEnabled(
+ safe_browsing::kSendSampledPingsForProtegoAllowlistDomains) &&
+ (bypass_protego_probability_for_tests_ ||
+ base::RandDouble() <= kProbabilityForSendingSampledRequests);
+}
+
void RealTimeUrlLookupService::Shutdown() {
shutting_down_ = true;
diff --git a/chromium/components/safe_browsing/core/browser/realtime/url_lookup_service.h b/chromium/components/safe_browsing/core/browser/realtime/url_lookup_service.h
index 6d12225ba37..ad4d30c7957 100644
--- a/chromium/components/safe_browsing/core/browser/realtime/url_lookup_service.h
+++ b/chromium/components/safe_browsing/core/browser/realtime/url_lookup_service.h
@@ -77,13 +77,21 @@ class RealTimeUrlLookupService : public RealTimeUrlLookupServiceBase {
bool CanCheckSubresourceURL() const override;
bool CanCheckSafeBrowsingDb() const override;
void Shutdown() override;
+ bool CanSendRTSampleRequest() const override;
+
+#if defined(UNIT_TEST)
+ void set_bypass_probability_for_tests(
+ bool bypass_protego_probability_for_tests) {
+ bypass_protego_probability_for_tests_ =
+ bypass_protego_probability_for_tests;
+ }
+#endif
private:
// RealTimeUrlLookupServiceBase:
GURL GetRealTimeLookupUrl() const override;
net::NetworkTrafficAnnotationTag GetTrafficAnnotationTag() const override;
bool CanPerformFullURLLookupWithToken() const override;
- bool CanAttachReferrerChain() const override;
int GetReferrerUserGestureLimit() const override;
bool CanSendPageLoadToken() const override;
void GetAccessToken(
@@ -138,6 +146,10 @@ class RealTimeUrlLookupService : public RealTimeUrlLookupServiceBase {
// location.
raw_ptr<variations::VariationsService> variations_;
+ // Bypasses the check for probability when sending Protego sample pings.
+ // Only for unit tests.
+ bool bypass_protego_probability_for_tests_ = false;
+
// True if Shutdown() has already been called, or started running. This allows
// us to skip unnecessary calls to SendRequest().
bool shutting_down_ = false;
diff --git a/chromium/components/safe_browsing/core/browser/realtime/url_lookup_service_base.cc b/chromium/components/safe_browsing/core/browser/realtime/url_lookup_service_base.cc
index 582abe6631c..a5af234feeb 100644
--- a/chromium/components/safe_browsing/core/browser/realtime/url_lookup_service_base.cc
+++ b/chromium/components/safe_browsing/core/browser/realtime/url_lookup_service_base.cc
@@ -7,6 +7,7 @@
#include "base/base64url.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
+#include "base/rand_util.h"
#include "base/strings/strcat.h"
#include "base/strings/string_piece.h"
#include "base/threading/sequenced_task_runner_handle.h"
@@ -15,6 +16,7 @@
#include "components/prefs/pref_service.h"
#include "components/safe_browsing/core/browser/referrer_chain_provider.h"
#include "components/safe_browsing/core/browser/verdict_cache_manager.h"
+#include "components/safe_browsing/core/common/features.h"
#include "components/safe_browsing/core/common/safe_browsing_prefs.h"
#include "components/safe_browsing/core/common/safebrowsing_constants.h"
#include "components/safe_browsing/core/common/utils.h"
@@ -41,7 +43,7 @@ const size_t kMaxBackOffResetDurationInSeconds = 30 * 60; // 30 minutes.
const size_t kURLLookupTimeoutDurationInSeconds = 3;
// Represents the value stored in the |version| field of |RTLookupRequest|.
-const int kRTLookupRequestVersion = 2;
+const int kRTLookupRequestVersion = 3;
// UMA helper functions.
void RecordBooleanWithAndWithoutSuffix(const std::string& metric,
@@ -99,19 +101,19 @@ void RecordNetworkResultWithAndWithoutSuffix(const std::string& metric,
}
RTLookupRequest::OSType GetRTLookupRequestOSType() {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
return RTLookupRequest::OS_TYPE_ANDROID;
-#elif defined(OS_CHROMEOS)
+#elif BUILDFLAG(IS_CHROMEOS)
return RTLookupRequest::OS_TYPE_CHROME_OS;
-#elif defined(OS_FUCHSIA)
+#elif BUILDFLAG(IS_FUCHSIA)
return RTLookupRequest::OS_TYPE_FUCHSIA;
-#elif defined(OS_IOS)
+#elif BUILDFLAG(IS_IOS)
return RTLookupRequest::OS_TYPE_IOS;
-#elif defined(OS_LINUX)
+#elif BUILDFLAG(IS_LINUX)
return RTLookupRequest::OS_TYPE_LINUX;
-#elif defined(OS_MAC)
+#elif BUILDFLAG(IS_MAC)
return RTLookupRequest::OS_TYPE_MAC;
-#elif defined(OS_WIN)
+#elif BUILDFLAG(IS_WIN)
return RTLookupRequest::OS_TYPE_WINDOWS;
#else
return RTLookupRequest::OS_TYPE_UNSPECIFIED;
@@ -318,6 +320,22 @@ void RealTimeUrlLookupServiceBase::MayBeCacheRealTimeUrlVerdict(
}
}
+void RealTimeUrlLookupServiceBase::SendSampledRequest(
+ const GURL& url,
+ const GURL& last_committed_url,
+ bool is_mainframe,
+ RTLookupRequestCallback request_callback,
+ scoped_refptr<base::SequencedTaskRunner> callback_task_runner) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(url.is_valid());
+
+ SendRequest(url, last_committed_url, is_mainframe,
+ /* access_token_string */ absl::nullopt,
+ std::move(request_callback),
+ /* response_callback */ base::NullCallback(),
+ std::move(callback_task_runner), /* is_sampled_report */ true);
+}
+
void RealTimeUrlLookupServiceBase::StartLookup(
const GURL& url,
const GURL& last_committed_url,
@@ -348,7 +366,7 @@ void RealTimeUrlLookupServiceBase::StartLookup(
SendRequest(url, last_committed_url, is_mainframe,
/* access_token_string */ absl::nullopt,
std::move(request_callback), std::move(response_callback),
- std::move(callback_task_runner));
+ std::move(callback_task_runner), /* is_sampled_report */ false);
}
}
@@ -359,16 +377,20 @@ void RealTimeUrlLookupServiceBase::SendRequest(
absl::optional<std::string> access_token_string,
RTLookupRequestCallback request_callback,
RTLookupResponseCallback response_callback,
- scoped_refptr<base::SequencedTaskRunner> callback_task_runner) {
+ scoped_refptr<base::SequencedTaskRunner> callback_task_runner,
+ bool is_sampled_report) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- std::unique_ptr<RTLookupRequest> request =
- FillRequestProto(url, last_committed_url, is_mainframe);
+ std::unique_ptr<RTLookupRequest> request = FillRequestProto(
+ url, last_committed_url, is_mainframe, is_sampled_report);
RecordRequestPopulationWithAndWithoutSuffix(
"SafeBrowsing.RT.Request.UserPopulation", GetMetricSuffix(),
request->population().user_population());
RecordCount100WithAndWithoutSuffix(
"SafeBrowsing.RT.Request.ReferrerChainLength", GetMetricSuffix(),
request->referrer_chain().size());
+ // Track sampled and full report
+ base::UmaHistogramBoolean("SafeBrowsing.RT.SampledRequestSent",
+ is_sampled_report);
std::string req_data;
request->SerializeToString(&req_data);
@@ -482,11 +504,14 @@ void RealTimeUrlLookupServiceBase::OnURLLoaderComplete(
"SafeBrowsing.RT.Response.VerdictType." + enhanced_protection_suffix,
response->threat_info(0).verdict_type());
}
-
- response_callback_task_runner->PostTask(
- FROM_HERE,
- base::BindOnce(std::move(it->second), is_rt_lookup_successful,
- /* is_cached_response */ false, std::move(response)));
+ // response_callback (it->second) could be null when
+ // it is a sampled report.
+ if (!it->second.is_null()) {
+ response_callback_task_runner->PostTask(
+ FROM_HERE,
+ base::BindOnce(std::move(it->second), is_rt_lookup_successful,
+ /* is_cached_response */ false, std::move(response)));
+ }
delete it->first;
pending_requests_.erase(it);
@@ -506,12 +531,17 @@ RealTimeUrlLookupServiceBase::GetResourceRequest() {
std::unique_ptr<RTLookupRequest> RealTimeUrlLookupServiceBase::FillRequestProto(
const GURL& url,
const GURL& last_committed_url,
- bool is_mainframe) {
+ bool is_mainframe,
+ bool is_sampled_report) {
auto request = std::make_unique<RTLookupRequest>();
request->set_url(SanitizeURL(url).spec());
request->set_lookup_type(RTLookupRequest::NAVIGATION);
request->set_version(kRTLookupRequestVersion);
request->set_os_type(GetRTLookupRequestOSType());
+ request->set_report_type(is_sampled_report ? RTLookupRequest::SAMPLED_REPORT
+ : RTLookupRequest::FULL_REPORT);
+ request->set_frame_type(is_mainframe ? RTLookupRequest::MAIN_FRAME
+ : RTLookupRequest::SUB_FRAME);
absl::optional<std::string> dm_token_string = GetDMTokenString();
if (dm_token_string.has_value()) {
request->set_dm_token(dm_token_string.value());
@@ -524,7 +554,7 @@ std::unique_ptr<RTLookupRequest> RealTimeUrlLookupServiceBase::FillRequestProto(
request->population().user_population() ==
ChromeUserPopulation::ENHANCED_PROTECTION);
- if (CanAttachReferrerChain() && referrer_chain_provider_) {
+ if (referrer_chain_provider_) {
referrer_chain_provider_->IdentifyReferrerChainByPendingEventURL(
SanitizeURL(url), GetReferrerUserGestureLimit(),
request->mutable_referrer_chain());
diff --git a/chromium/components/safe_browsing/core/browser/realtime/url_lookup_service_base.h b/chromium/components/safe_browsing/core/browser/realtime/url_lookup_service_base.h
index 20c68d204d7..141c4fc2f8c 100644
--- a/chromium/components/safe_browsing/core/browser/realtime/url_lookup_service_base.h
+++ b/chromium/components/safe_browsing/core/browser/realtime/url_lookup_service_base.h
@@ -92,6 +92,15 @@ class RealTimeUrlLookupServiceBase : public KeyedService {
RTLookupResponseCallback response_callback,
scoped_refptr<base::SequencedTaskRunner> callback_task_runner);
+ // Similar to the function StartLookup above,
+ // but to send Protego sampled request specifically.
+ virtual void SendSampledRequest(
+ const GURL& url,
+ const GURL& last_committed_url,
+ bool is_mainframe,
+ RTLookupRequestCallback request_callback,
+ scoped_refptr<base::SequencedTaskRunner> callback_task_runner);
+
// Helper function to return a weak pointer.
base::WeakPtr<RealTimeUrlLookupServiceBase> GetWeakPtr();
@@ -107,6 +116,9 @@ class RealTimeUrlLookupServiceBase : public KeyedService {
// check is enabled.
virtual bool CanCheckSafeBrowsingDb() const = 0;
+ // Checks if a sample ping can be sent to Safe Browsing.
+ virtual bool CanSendRTSampleRequest() const = 0;
+
// KeyedService:
// Called before the actual deletion of the object.
void Shutdown() override;
@@ -126,7 +138,8 @@ class RealTimeUrlLookupServiceBase : public KeyedService {
absl::optional<std::string> access_token_string,
RTLookupRequestCallback request_callback,
RTLookupResponseCallback response_callback,
- scoped_refptr<base::SequencedTaskRunner> callback_task_runner);
+ scoped_refptr<base::SequencedTaskRunner> callback_task_runner,
+ bool is_sampled_report);
private:
using PendingRTLookupRequests =
@@ -148,9 +161,6 @@ class RealTimeUrlLookupServiceBase : public KeyedService {
// Returns true if real time URL lookup with GAIA token is enabled.
virtual bool CanPerformFullURLLookupWithToken() const = 0;
- // Returns true if referrer chain should be attached to requests.
- virtual bool CanAttachReferrerChain() const = 0;
-
// Returns the user gesture limit of the referrer chain.
virtual int GetReferrerUserGestureLimit() const = 0;
@@ -240,7 +250,8 @@ class RealTimeUrlLookupServiceBase : public KeyedService {
std::unique_ptr<RTLookupRequest> FillRequestProto(
const GURL& url,
const GURL& last_committed_url,
- bool is_mainframe);
+ bool is_mainframe,
+ bool is_sampled_report);
SEQUENCE_CHECKER(sequence_checker_);
diff --git a/chromium/components/safe_browsing/core/browser/realtime/url_lookup_service_unittest.cc b/chromium/components/safe_browsing/core/browser/realtime/url_lookup_service_unittest.cc
index 580896dd11c..51f745f18f7 100644
--- a/chromium/components/safe_browsing/core/browser/realtime/url_lookup_service_unittest.cc
+++ b/chromium/components/safe_browsing/core/browser/realtime/url_lookup_service_unittest.cc
@@ -146,11 +146,16 @@ class RealTimeUrlLookupServiceTest : public PlatformTest {
void HandleLookupError() { rt_service_->HandleLookupError(); }
void HandleLookupSuccess() { rt_service_->HandleLookupSuccess(); }
bool IsInBackoffMode() { return rt_service_->IsInBackoffMode(); }
+ bool CanSendRTSampleRequest() {
+ return rt_service_->CanSendRTSampleRequest();
+ }
std::unique_ptr<RTLookupRequest> FillRequestProto(
const GURL& url,
const GURL& last_committed_url,
- bool is_mainframe) {
- return rt_service_->FillRequestProto(url, last_committed_url, is_mainframe);
+ bool is_mainframe,
+ bool is_sampled_report) {
+ return rt_service_->FillRequestProto(url, last_committed_url, is_mainframe,
+ is_sampled_report);
}
std::unique_ptr<RTLookupResponse> GetCachedRealTimeUrlVerdict(
const GURL& url) {
@@ -212,6 +217,14 @@ class RealTimeUrlLookupServiceTest : public PlatformTest {
std::make_unique<base::Value>(true));
}
+ void EnableExtendedReporting() {
+ EnableMbb();
+ test_pref_service_.SetUserPref(prefs::kSafeBrowsingEnabled,
+ std::make_unique<base::Value>(true));
+ test_pref_service_.SetUserPref(prefs::kSafeBrowsingScoutReportingEnabled,
+ std::make_unique<base::Value>(true));
+ }
+
void EnableRealTimeUrlLookup(
const std::vector<base::Feature>& enabled_features,
const std::vector<base::Feature>& disabled_features) {
@@ -303,11 +316,18 @@ TEST_F(RealTimeUrlLookupServiceTest, TestFillRequestProto) {
{"http://example.com/abc#123", "http://example.com/abc#123"}};
for (size_t i = 0; i < base::size(sanitize_url_cases); i++) {
GURL url(sanitize_url_cases[i].url);
- auto result = FillRequestProto(url, last_committed_url_, is_mainframe_);
+ auto result = FillRequestProto(url, last_committed_url_, is_mainframe_,
+ /*is_sampled_report=*/i % 2 == 0);
+ if (i % 2 == 0) {
+ EXPECT_EQ(/* sampled report */ 2, result->report_type());
+ } else {
+ EXPECT_EQ(/* full report */ 1, result->report_type());
+ }
EXPECT_EQ(sanitize_url_cases[i].expected_url, result->url());
EXPECT_EQ(RTLookupRequest::NAVIGATION, result->lookup_type());
EXPECT_EQ(ChromeUserPopulation::SAFE_BROWSING,
result->population().user_population());
+ EXPECT_EQ(1, result->frame_type());
// The value of is_history_sync_enabled() should reflect that of the
// callback passed in by the client, which in this case is true.
@@ -322,8 +342,8 @@ TEST_F(RealTimeUrlLookupServiceTest, TestFillRequestProto) {
TEST_F(RealTimeUrlLookupServiceTest, TestFillPageLoadToken_FeatureDisabled) {
feature_list_.InitAndDisableFeature(kSafeBrowsingPageLoadToken);
- auto request =
- FillRequestProto(GURL(kTestUrl), GURL(), /*is_mainframe=*/true);
+ auto request = FillRequestProto(GURL(kTestUrl), GURL(), /*is_mainframe=*/true,
+ /*is_sampled_report=*/false);
// Page load tokens should not be attached because the feature flag is
// disabled.
ASSERT_EQ(0, request->population().page_load_tokens_size());
@@ -338,7 +358,8 @@ TEST_F(RealTimeUrlLookupServiceTest, TestFillPageLoadToken_FeatureEnabled) {
{
cache_manager_->SetPageLoadTokenForTesting(
url, CreatePageLoadToken("url_page_load_token"));
- auto request = FillRequestProto(url, GURL(), /*is_mainframe=*/true);
+ auto request = FillRequestProto(url, GURL(), /*is_mainframe=*/true,
+ /*is_sampled_report=*/false);
ASSERT_EQ(1, request->population().page_load_tokens_size());
// The token should be re-generated for the mainframe URL.
EXPECT_NE("url_page_load_token",
@@ -351,7 +372,8 @@ TEST_F(RealTimeUrlLookupServiceTest, TestFillPageLoadToken_FeatureEnabled) {
{
ChromeUserPopulation::PageLoadToken empty_token;
cache_manager_->SetPageLoadTokenForTesting(url, empty_token);
- auto request = FillRequestProto(subframe_url, url, /*is_mainframe=*/false);
+ auto request = FillRequestProto(subframe_url, url, /*is_mainframe=*/false,
+ /*is_sampled_report=*/false);
ASSERT_EQ(1, request->population().page_load_tokens_size());
// The token should be generated for the mainframe URL.
std::string token_value =
@@ -365,7 +387,8 @@ TEST_F(RealTimeUrlLookupServiceTest, TestFillPageLoadToken_FeatureEnabled) {
{
cache_manager_->SetPageLoadTokenForTesting(
url, CreatePageLoadToken("url_page_load_token"));
- auto request = FillRequestProto(subframe_url, url, /*is_mainframe=*/false);
+ auto request = FillRequestProto(subframe_url, url, /*is_mainframe=*/false,
+ /*is_sampled_report=*/false);
ASSERT_EQ(1, request->population().page_load_tokens_size());
// The token for the mainframe URL should be reused.
EXPECT_EQ("url_page_load_token",
@@ -897,7 +920,7 @@ TEST_F(RealTimeUrlLookupServiceTest, TestReferrerChain_ReferrerChainAttached) {
url, last_committed_url_, is_mainframe_,
base::BindOnce(
[](std::unique_ptr<RTLookupRequest> request, std::string token) {
- EXPECT_EQ(2, request->version());
+ EXPECT_EQ(3, request->version());
// Check referrer chain is attached.
EXPECT_EQ(2, request->referrer_chain().size());
EXPECT_EQ(kTestUrl, request->referrer_chain().Get(0).url());
@@ -939,7 +962,7 @@ TEST_F(RealTimeUrlLookupServiceTest,
url, last_committed_url_, is_mainframe_,
base::BindOnce([](std::unique_ptr<RTLookupRequest> request,
std::string token) {
- EXPECT_EQ(2, request->version());
+ EXPECT_EQ(3, request->version());
EXPECT_EQ(2, request->referrer_chain().size());
// The first entry is sanitized because it is triggered in a
// subframe.
@@ -973,6 +996,8 @@ TEST_F(RealTimeUrlLookupServiceTest,
TEST_F(RealTimeUrlLookupServiceTest,
TestReferrerChain_NotSanitizedIfSubresourceAllowed) {
EnableMbb();
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeature(kEnhancedProtection);
// Subresource is allowed when enhanced protection is enabled.
SetSafeBrowsingState(&test_pref_service_,
SafeBrowsingState::ENHANCED_PROTECTION);
@@ -1004,7 +1029,7 @@ TEST_F(RealTimeUrlLookupServiceTest,
url, last_committed_url_, is_mainframe_,
base::BindOnce([](std::unique_ptr<RTLookupRequest> request,
std::string token) {
- EXPECT_EQ(2, request->version());
+ EXPECT_EQ(3, request->version());
EXPECT_EQ(2, request->referrer_chain().size());
// Check referrer chain is not sanitized.
EXPECT_EQ(kTestSubframeUrl, request->referrer_chain().Get(0).url());
@@ -1067,7 +1092,7 @@ TEST_F(RealTimeUrlLookupServiceTest,
url, last_committed_url_, is_mainframe_,
base::BindOnce([](std::unique_ptr<RTLookupRequest> request,
std::string token) {
- EXPECT_EQ(2, request->version());
+ EXPECT_EQ(3, request->version());
EXPECT_EQ(2, request->referrer_chain().size());
// Check the first referrer chain is sanitized because it's logged
// before real time URL lookup is enabled.
@@ -1138,4 +1163,51 @@ TEST_F(RealTimeUrlLookupServiceTest,
task_environment_.RunUntilIdle();
}
+TEST_F(RealTimeUrlLookupServiceTest, TestSendSampledRequest) {
+ EnableMbb();
+ // Enabling access token does not affect sending sampled ping.
+ EnableTokenFetchesInClient();
+ GURL url(kTestUrl);
+
+ rt_service()->SendSampledRequest(
+ url, last_committed_url_, is_mainframe_,
+ base::BindOnce(
+ [](std::unique_ptr<RTLookupRequest> request, std::string token) {
+ EXPECT_EQ(3, request->version());
+ EXPECT_EQ(2, request->report_type());
+ EXPECT_EQ(1, request->frame_type());
+ }),
+ base::SequencedTaskRunnerHandle::Get());
+ rt_service()->Shutdown();
+
+ task_environment_.RunUntilIdle();
+}
+
+TEST_F(RealTimeUrlLookupServiceTest,
+ TestCanSendRTSampleRequest_FeatureEnabled) {
+ // When extended reporting is not enabled,
+ // sample request will not be sent.
+ EXPECT_FALSE(CanSendRTSampleRequest());
+ // Enable extended reporting.
+ EnableExtendedReporting();
+ rt_service()->set_bypass_probability_for_tests(true);
+ feature_list_.InitAndEnableFeature(
+ safe_browsing::kSendSampledPingsForProtegoAllowlistDomains);
+ // After enabling the feature, a sampled ping should be sent.
+ EXPECT_TRUE(CanSendRTSampleRequest());
+}
+
+TEST_F(RealTimeUrlLookupServiceTest,
+ TestCanSendRTSampleRequest_FeatureDisabled) {
+ // Enable extended reporting.
+ EnableExtendedReporting();
+ rt_service()->set_bypass_probability_for_tests(true);
+ // When feature is not enabled, a sampled ping should not be sent.
+ EXPECT_FALSE(CanSendRTSampleRequest());
+ feature_list_.InitAndDisableFeature(
+ safe_browsing::kSendSampledPingsForProtegoAllowlistDomains);
+ // After enabling the feature, a sampled ping should be sent.
+ EXPECT_FALSE(CanSendRTSampleRequest());
+}
+
} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing/core/browser/safe_browsing_metrics_collector.cc b/chromium/components/safe_browsing/core/browser/safe_browsing_metrics_collector.cc
index 73104b01174..c061236808a 100644
--- a/chromium/components/safe_browsing/core/browser/safe_browsing_metrics_collector.cc
+++ b/chromium/components/safe_browsing/core/browser/safe_browsing_metrics_collector.cc
@@ -11,6 +11,7 @@
#include "base/time/time.h"
#include "components/prefs/pref_service.h"
#include "components/prefs/scoped_user_pref_update.h"
+#include "components/safe_browsing/core/browser/db/hit_report.h"
#include "components/safe_browsing/core/common/safe_browsing_prefs.h"
namespace {
@@ -156,7 +157,7 @@ void SafeBrowsingMetricsCollector::LogDailyEventMetrics() {
void SafeBrowsingMetricsCollector::RemoveOldEventsFromPref() {
DictionaryPrefUpdate update(pref_service_,
prefs::kSafeBrowsingEventTimestamps);
- base::DictionaryValue* mutable_state_dict = update.Get();
+ base::Value* mutable_state_dict = update.Get();
bool is_pref_valid = mutable_state_dict->is_dict();
base::UmaHistogramBoolean("SafeBrowsing.MetricsCollector.IsPrefValid",
is_pref_valid);
@@ -185,6 +186,27 @@ void SafeBrowsingMetricsCollector::AddSafeBrowsingEventToPref(
AddSafeBrowsingEventAndUserStateToPref(GetUserState(), event_type);
}
+void SafeBrowsingMetricsCollector::AddBypassEventToPref(
+ ThreatSource threat_source) {
+ EventType event;
+ switch (threat_source) {
+ case ThreatSource::LOCAL_PVER4:
+ case ThreatSource::REMOTE:
+ event = EventType::DATABASE_INTERSTITIAL_BYPASS;
+ break;
+ case ThreatSource::CLIENT_SIDE_DETECTION:
+ event = EventType::CSD_INTERSTITIAL_BYPASS;
+ break;
+ case ThreatSource::REAL_TIME_CHECK:
+ event = EventType::REAL_TIME_INTERSTITIAL_BYPASS;
+ break;
+ default:
+ NOTREACHED() << "Unexpected threat source.";
+ event = EventType::DATABASE_INTERSTITIAL_BYPASS;
+ }
+ AddSafeBrowsingEventToPref(event);
+}
+
absl::optional<base::Time>
SafeBrowsingMetricsCollector::GetLatestEventTimestamp(EventType event_type) {
return GetLatestEventTimestamp(base::BindRepeating(
@@ -220,7 +242,7 @@ void SafeBrowsingMetricsCollector::AddSafeBrowsingEventAndUserStateToPref(
EventType event_type) {
DictionaryPrefUpdate update(pref_service_,
prefs::kSafeBrowsingEventTimestamps);
- base::DictionaryValue* mutable_state_dict = update.Get();
+ base::Value* mutable_state_dict = update.Get();
base::Value* event_dict =
mutable_state_dict->FindDictKey(UserStateToPrefKey(user_state));
@@ -238,8 +260,8 @@ void SafeBrowsingMetricsCollector::AddSafeBrowsingEventAndUserStateToPref(
}
// Remove the oldest timestamp if the length of the timestamps hits the limit.
- while (timestamps->GetList().size() >= kTimestampsMaxLength) {
- timestamps->EraseListIter(timestamps->GetList().begin());
+ while (timestamps->GetListDeprecated().size() >= kTimestampsMaxLength) {
+ timestamps->EraseListIter(timestamps->GetListDeprecated().begin());
}
timestamps->Append(TimeToPrefValue(base::Time::Now()));
@@ -263,7 +285,7 @@ void SafeBrowsingMetricsCollector::OnEnhancedProtectionPrefChanged() {
const base::Value* SafeBrowsingMetricsCollector::GetSafeBrowsingEventDictionary(
UserState user_state) {
- const base::DictionaryValue* state_dict =
+ const base::Value* state_dict =
pref_service_->GetDictionary(prefs::kSafeBrowsingEventTimestamps);
return state_dict->FindDictKey(UserStateToPrefKey(user_state));
@@ -282,8 +304,8 @@ SafeBrowsingMetricsCollector::GetLatestEventFromEventType(
const base::Value* timestamps =
event_dict->FindListKey(EventTypeToPrefKey(event_type));
- if (timestamps && timestamps->GetList().size() > 0) {
- base::Time time = PrefValueToTime(timestamps->GetList().back());
+ if (timestamps && timestamps->GetListDeprecated().size() > 0) {
+ base::Time time = PrefValueToTime(timestamps->GetListDeprecated().back());
return Event(event_type, time);
}
@@ -419,8 +441,8 @@ int SafeBrowsingMetricsCollector::GetEventCountSince(UserState user_state,
return 0;
}
- return std::count_if(timestamps->GetList().begin(),
- timestamps->GetList().end(),
+ return std::count_if(timestamps->GetListDeprecated().begin(),
+ timestamps->GetListDeprecated().end(),
[&](const base::Value& timestamp) {
return PrefValueToTime(timestamp) > since_time;
});
@@ -534,8 +556,10 @@ std::string SafeBrowsingMetricsCollector::GetTimesDisabledSuffix() {
EventType::USER_STATE_ENABLED);
if (!latest_enabled_event) {
- // this code path could be possible if ESB was enabled via policy but
- // later disabled by the user, since policy enables/disables are not tracked
+ // This code path could be possible if ESB was enabled via policy but
+ // later disabled by the user, since policy enables/disables are not
+ // tracked. It's also possible if it's been longer than kEventMaxDurationDay
+ // days since the latest enabled event.
return "NeverEnabled";
}
const auto hours_since_enabled =
diff --git a/chromium/components/safe_browsing/core/browser/safe_browsing_metrics_collector.h b/chromium/components/safe_browsing/core/browser/safe_browsing_metrics_collector.h
index c35e481b393..02bf49dc1b1 100644
--- a/chromium/components/safe_browsing/core/browser/safe_browsing_metrics_collector.h
+++ b/chromium/components/safe_browsing/core/browser/safe_browsing_metrics_collector.h
@@ -11,6 +11,7 @@
#include "base/timer/timer.h"
#include "components/keyed_service/core/keyed_service.h"
#include "components/prefs/pref_change_registrar.h"
+#include "components/safe_browsing/core/browser/db/hit_report.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
class PrefService;
@@ -115,6 +116,10 @@ class SafeBrowsingMetricsCollector : public KeyedService {
// Adds |event_type| and the current timestamp to pref.
void AddSafeBrowsingEventToPref(EventType event_type);
+ // Uses |threat_source| to choose which EventType should be passed into
+ // AddSafeBrowsingEventToPref
+ void AddBypassEventToPref(ThreatSource threat_source);
+
// Gets the latest event timestamp of the |event_type|. Returns nullopt if
// the |event_type| didn't happen in the past.
absl::optional<base::Time> GetLatestEventTimestamp(EventType event_type);
diff --git a/chromium/components/safe_browsing/core/browser/safe_browsing_metrics_collector_unittest.cc b/chromium/components/safe_browsing/core/browser/safe_browsing_metrics_collector_unittest.cc
index a79fd99350d..79da9582771 100644
--- a/chromium/components/safe_browsing/core/browser/safe_browsing_metrics_collector_unittest.cc
+++ b/chromium/components/safe_browsing/core/browser/safe_browsing_metrics_collector_unittest.cc
@@ -11,9 +11,11 @@
#include "base/memory/scoped_refptr.h"
#include "base/strings/string_number_conversions.h"
#include "base/test/metrics/histogram_tester.h"
+#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/testing_pref_service.h"
+#include "components/safe_browsing/core/common/features.h"
#include "components/safe_browsing/core/common/safe_browsing_prefs.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -44,7 +46,7 @@ class SafeBrowsingMetricsCollectorTest : public ::testing::Test {
const base::Value* GetTsFromUserStateAndEventType(UserState state,
EventType event_type) {
- const base::DictionaryValue* state_dict =
+ const base::Value* state_dict =
pref_service_.GetDictionary(prefs::kSafeBrowsingEventTimestamps);
const base::Value* event_dict =
state_dict->FindDictKey(base::NumberToString(static_cast<int>(state)));
@@ -58,7 +60,8 @@ class SafeBrowsingMetricsCollectorTest : public ::testing::Test {
}
bool IsSortedInChronologicalOrder(const base::Value* ts) {
- return std::is_sorted(ts->GetList().begin(), ts->GetList().end(),
+ return std::is_sorted(ts->GetListDeprecated().begin(),
+ ts->GetListDeprecated().end(),
[](const base::Value& ts_a, const base::Value& ts_b) {
return base::ValueToInt64(ts_a).value_or(0) <
base::ValueToInt64(ts_b).value_or(0);
@@ -198,6 +201,8 @@ TEST_F(SafeBrowsingMetricsCollectorTest,
TEST_F(SafeBrowsingMetricsCollectorTest,
AddSafeBrowsingEventToPref_OldestTsRemoved) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeature(kEnhancedProtection);
SetSafeBrowsingState(&pref_service_, SafeBrowsingState::ENHANCED_PROTECTION);
metrics_collector_->AddSafeBrowsingEventToPref(
EventType::DATABASE_INTERSTITIAL_BYPASS);
@@ -210,23 +215,27 @@ TEST_F(SafeBrowsingMetricsCollectorTest,
const base::Value* timestamps = GetTsFromUserStateAndEventType(
UserState::kEnhancedProtection, EventType::DATABASE_INTERSTITIAL_BYPASS);
- EXPECT_EQ(30u, timestamps->GetList().size());
+ EXPECT_EQ(30u, timestamps->GetListDeprecated().size());
EXPECT_TRUE(IsSortedInChronologicalOrder(timestamps));
task_environment_.FastForwardBy(base::Days(1));
metrics_collector_->AddSafeBrowsingEventToPref(
EventType::DATABASE_INTERSTITIAL_BYPASS);
- EXPECT_EQ(30u, timestamps->GetList().size());
+ EXPECT_EQ(30u, timestamps->GetListDeprecated().size());
EXPECT_TRUE(IsSortedInChronologicalOrder(timestamps));
// The oldest timestamp should be removed.
- EXPECT_EQ(timestamps->GetList()[0], timestamps->GetList()[1]);
+ EXPECT_EQ(timestamps->GetListDeprecated()[0],
+ timestamps->GetListDeprecated()[1]);
// The newest timestamp should be added as the last element.
- EXPECT_NE(timestamps->GetList()[28], timestamps->GetList()[29]);
+ EXPECT_NE(timestamps->GetListDeprecated()[28],
+ timestamps->GetListDeprecated()[29]);
}
TEST_F(SafeBrowsingMetricsCollectorTest,
AddSafeBrowsingEventToPref_SafeBrowsingManaged) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeature(kEnhancedProtection);
SetSafeBrowsingState(&pref_service_, SafeBrowsingState::ENHANCED_PROTECTION);
metrics_collector_->AddSafeBrowsingEventToPref(
EventType::DATABASE_INTERSTITIAL_BYPASS);
@@ -239,15 +248,17 @@ TEST_F(SafeBrowsingMetricsCollectorTest,
const base::Value* enhanced_timestamps = GetTsFromUserStateAndEventType(
UserState::kEnhancedProtection, EventType::DATABASE_INTERSTITIAL_BYPASS);
- EXPECT_EQ(1u, enhanced_timestamps->GetList().size());
+ EXPECT_EQ(1u, enhanced_timestamps->GetListDeprecated().size());
const base::Value* managed_timestamps = GetTsFromUserStateAndEventType(
UserState::kManaged, EventType::DATABASE_INTERSTITIAL_BYPASS);
- EXPECT_EQ(2u, managed_timestamps->GetList().size());
+ EXPECT_EQ(2u, managed_timestamps->GetListDeprecated().size());
}
TEST_F(SafeBrowsingMetricsCollectorTest,
LogEnhancedProtectionDisabledMetrics_GetLastBypassEventType) {
base::HistogramTester histograms;
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeature(kEnhancedProtection);
SetSafeBrowsingState(&pref_service_, SafeBrowsingState::ENHANCED_PROTECTION);
FastForwardAndAddEvent(base::Hours(1),
@@ -331,6 +342,8 @@ TEST_F(SafeBrowsingMetricsCollectorTest,
TEST_F(SafeBrowsingMetricsCollectorTest,
LogEnhancedProtectionDisabledMetrics_GetLastSecuritySensitiveEventType) {
base::HistogramTester histograms;
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeature(kEnhancedProtection);
SetSafeBrowsingState(&pref_service_, SafeBrowsingState::ENHANCED_PROTECTION);
FastForwardAndAddEvent(
@@ -561,6 +574,8 @@ TEST_F(SafeBrowsingMetricsCollectorTest,
TEST_F(SafeBrowsingMetricsCollectorTest,
LogEnhancedProtectionDisabledMetrics_NotLoggedIfHitQuotaLimit) {
base::HistogramTester histograms;
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeature(kEnhancedProtection);
SetSafeBrowsingState(&pref_service_, SafeBrowsingState::ENHANCED_PROTECTION);
FastForwardAndAddEvent(base::Hours(1),
@@ -614,6 +629,8 @@ TEST_F(SafeBrowsingMetricsCollectorTest,
TEST_F(SafeBrowsingMetricsCollectorTest, LogDailyEventMetrics_LoggedDaily) {
base::HistogramTester histograms;
SetSafeBrowsingMetricsLastLogTime(base::Time::Now());
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeature(kEnhancedProtection);
SetSafeBrowsingState(&pref_service_, SafeBrowsingState::ENHANCED_PROTECTION);
metrics_collector_->StartLogging();
FastForwardAndAddEvent(base::Hours(1),
@@ -700,6 +717,8 @@ TEST_F(SafeBrowsingMetricsCollectorTest,
LogDailyEventMetrics_DoesNotCountOldEvent) {
base::HistogramTester histograms;
SetSafeBrowsingMetricsLastLogTime(base::Time::Now());
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeature(kEnhancedProtection);
SetSafeBrowsingState(&pref_service_, SafeBrowsingState::ENHANCED_PROTECTION);
metrics_collector_->StartLogging();
FastForwardAndAddEvent(base::Hours(1),
@@ -742,6 +761,8 @@ TEST_F(SafeBrowsingMetricsCollectorTest,
LogDailyEventMetrics_SwitchBetweenDifferentUserState) {
base::HistogramTester histograms;
SetSafeBrowsingMetricsLastLogTime(base::Time::Now());
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeature(kEnhancedProtection);
SetSafeBrowsingState(&pref_service_, SafeBrowsingState::ENHANCED_PROTECTION);
metrics_collector_->StartLogging();
FastForwardAndAddEvent(base::Hours(1),
@@ -780,15 +801,15 @@ TEST_F(SafeBrowsingMetricsCollectorTest,
const base::Value* db_timestamps = GetTsFromUserStateAndEventType(
UserState::kStandardProtection, EventType::DATABASE_INTERSTITIAL_BYPASS);
// The event is removed from pref because it was logged more than 30 days.
- EXPECT_EQ(0u, db_timestamps->GetList().size());
+ EXPECT_EQ(0u, db_timestamps->GetListDeprecated().size());
const base::Value* csd_timestamps = GetTsFromUserStateAndEventType(
UserState::kStandardProtection, EventType::CSD_INTERSTITIAL_BYPASS);
// The CSD event is still in pref because it was logged less than 30 days.
- EXPECT_EQ(1u, csd_timestamps->GetList().size());
+ EXPECT_EQ(1u, csd_timestamps->GetListDeprecated().size());
task_environment_.FastForwardBy(base::Days(1));
// The CSD event is also removed because it was logged more than 30 days now.
- EXPECT_EQ(0u, csd_timestamps->GetList().size());
+ EXPECT_EQ(0u, csd_timestamps->GetListDeprecated().size());
histograms.ExpectUniqueSample("SafeBrowsing.MetricsCollector.IsPrefValid",
/* sample */ 1,
@@ -796,6 +817,8 @@ TEST_F(SafeBrowsingMetricsCollectorTest,
}
TEST_F(SafeBrowsingMetricsCollectorTest, GetUserState) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeature(kEnhancedProtection);
SetSafeBrowsingState(&pref_service_, SafeBrowsingState::ENHANCED_PROTECTION);
EXPECT_EQ(UserState::kEnhancedProtection, metrics_collector_->GetUserState());
diff --git a/chromium/components/safe_browsing/core/browser/safe_browsing_token_fetch_tracker.h b/chromium/components/safe_browsing/core/browser/safe_browsing_token_fetch_tracker.h
index 8927c89af5a..7fabb3e782c 100644
--- a/chromium/components/safe_browsing/core/browser/safe_browsing_token_fetch_tracker.h
+++ b/chromium/components/safe_browsing/core/browser/safe_browsing_token_fetch_tracker.h
@@ -17,7 +17,7 @@
namespace safe_browsing {
// Exposed for unittests.
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
constexpr int kTokenFetchTimeoutDelayFromMilliseconds = 50;
#else
constexpr int kTokenFetchTimeoutDelayFromMilliseconds = 1000;
diff --git a/chromium/components/safe_browsing/core/browser/safe_browsing_url_checker_impl.cc b/chromium/components/safe_browsing/core/browser/safe_browsing_url_checker_impl.cc
index 603302c79df..f829830671b 100644
--- a/chromium/components/safe_browsing/core/browser/safe_browsing_url_checker_impl.cc
+++ b/chromium/components/safe_browsing/core/browser/safe_browsing_url_checker_impl.cc
@@ -570,6 +570,14 @@ void SafeBrowsingUrlCheckerImpl::OnCheckUrlForHighConfidenceAllowlist(
const GURL& url = urls_[next_index_].url;
if (did_match_allowlist) {
+ ui_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(&SafeBrowsingUrlCheckerImpl::MaybeSendSampleRequest,
+ weak_factory_.GetWeakPtr(), url, last_committed_url_,
+ /*is_mainframe=*/request_destination_ ==
+ network::mojom::RequestDestination::kDocument,
+ url_lookup_service_on_ui_, database_manager_,
+ base::SequencedTaskRunnerHandle::Get()));
// If the URL matches the high-confidence allowlist, still do the hash based
// checks.
PerformHashBasedCheck(url);
@@ -590,6 +598,32 @@ void SafeBrowsingUrlCheckerImpl::SetWebUIToken(int token) {
url_web_ui_token_ = token;
}
+void SafeBrowsingUrlCheckerImpl::MaybeSendSampleRequest(
+ base::WeakPtr<SafeBrowsingUrlCheckerImpl> weak_checker_on_io,
+ const GURL& url,
+ const GURL& last_committed_url,
+ bool is_mainframe,
+ base::WeakPtr<RealTimeUrlLookupServiceBase> url_lookup_service_on_ui,
+ scoped_refptr<SafeBrowsingDatabaseManager> database_manager,
+ scoped_refptr<base::SequencedTaskRunner> io_task_runner) {
+ bool can_send_protego_sampled_ping =
+ url_lookup_service_on_ui &&
+ url_lookup_service_on_ui->CanSendRTSampleRequest();
+
+ if (!can_send_protego_sampled_ping) {
+ return;
+ }
+ bool is_lookup_service_available =
+ !url_lookup_service_on_ui->IsInBackoffMode();
+ if (is_lookup_service_available) {
+ RTLookupRequestCallback request_callback = base::BindOnce(
+ &SafeBrowsingUrlCheckerImpl::OnRTLookupRequest, weak_checker_on_io);
+ url_lookup_service_on_ui->SendSampledRequest(
+ url, last_committed_url, is_mainframe, std::move(request_callback),
+ std::move(io_task_runner));
+ }
+}
+
// static
void SafeBrowsingUrlCheckerImpl::StartLookupOnUIThread(
base::WeakPtr<SafeBrowsingUrlCheckerImpl> weak_checker_on_io,
diff --git a/chromium/components/safe_browsing/core/browser/safe_browsing_url_checker_impl.h b/chromium/components/safe_browsing/core/browser/safe_browsing_url_checker_impl.h
index 42647580c16..98b33401435 100644
--- a/chromium/components/safe_browsing/core/browser/safe_browsing_url_checker_impl.h
+++ b/chromium/components/safe_browsing/core/browser/safe_browsing_url_checker_impl.h
@@ -208,6 +208,17 @@ class SafeBrowsingUrlCheckerImpl : public mojom::SafeBrowsingUrlChecker,
// Perform the hash based check for the url.
void PerformHashBasedCheck(const GURL& url);
+ // Checks the eligibility of sending a sampled ping first;
+ // Send a sampled report if one should be sent, otherwise, exit.
+ static void MaybeSendSampleRequest(
+ base::WeakPtr<SafeBrowsingUrlCheckerImpl> weak_checker_on_io,
+ const GURL& url,
+ const GURL& last_committed_url,
+ bool is_mainframe,
+ base::WeakPtr<RealTimeUrlLookupServiceBase> url_lookup_service_on_ui,
+ scoped_refptr<SafeBrowsingDatabaseManager> database_manager,
+ scoped_refptr<base::SequencedTaskRunner> io_task_runner);
+
// This function has to be static because it is called in UI thread.
// This function starts a real time url check if |url_lookup_service_on_ui| is
// available and is not in backoff mode. Otherwise, hop back to IO thread and
diff --git a/chromium/components/safe_browsing/core/browser/safe_browsing_url_checker_impl_unittest.cc b/chromium/components/safe_browsing/core/browser/safe_browsing_url_checker_impl_unittest.cc
index 06a3b9b9189..722b6f9afea 100644
--- a/chromium/components/safe_browsing/core/browser/safe_browsing_url_checker_impl_unittest.cc
+++ b/chromium/components/safe_browsing/core/browser/safe_browsing_url_checker_impl_unittest.cc
@@ -222,6 +222,13 @@ class MockRealTimeUrlLookupService : public RealTimeUrlLookupServiceBase {
std::move(response)));
}
+ void SendSampledRequest(
+ const GURL& gurl,
+ const GURL& last_committed_url,
+ bool is_mainframe,
+ RTLookupRequestCallback request_callback,
+ scoped_refptr<base::SequencedTaskRunner> callback_task_runner) override {}
+
void SetThreatTypeForUrl(const GURL& gurl, SBThreatType threat_type) {
urls_threat_type_[gurl.spec()] = threat_type;
}
@@ -234,6 +241,7 @@ class MockRealTimeUrlLookupService : public RealTimeUrlLookupServiceBase {
bool CanPerformFullURLLookup() const override { return true; }
bool CanCheckSubresourceURL() const override { return false; }
bool CanCheckSafeBrowsingDb() const override { return true; }
+ bool CanSendRTSampleRequest() const override { return true; }
private:
// RealTimeUrlLookupServiceBase:
@@ -242,7 +250,6 @@ class MockRealTimeUrlLookupService : public RealTimeUrlLookupServiceBase {
return TRAFFIC_ANNOTATION_FOR_TESTS;
}
bool CanPerformFullURLLookupWithToken() const override { return false; }
- bool CanAttachReferrerChain() const override { return false; }
int GetReferrerUserGestureLimit() const override { return 0; }
bool CanSendPageLoadToken() const override { return false; }
void GetAccessToken(
diff --git a/chromium/components/safe_browsing/core/browser/tailored_security_service/tailored_security_service.cc b/chromium/components/safe_browsing/core/browser/tailored_security_service/tailored_security_service.cc
index 1381cc2c428..8fee6ea9143 100644
--- a/chromium/components/safe_browsing/core/browser/tailored_security_service/tailored_security_service.cc
+++ b/chromium/components/safe_browsing/core/browser/tailored_security_service/tailored_security_service.cc
@@ -280,13 +280,23 @@ void TailoredSecurityService::AddQueryRequest() {
DCHECK(!is_shut_down_);
active_query_request_++;
if (active_query_request_ == 1) {
- // Query now and register a repeating timer to get the tailored security bit
- // every `kRepeatingCheckTailoredSecurityBitDelayInMinutes` minutes.
- QueryTailoredSecurityBit();
- timer_.Start(
- FROM_HERE,
- base::Minutes(kRepeatingCheckTailoredSecurityBitDelayInMinutes), this,
- &TailoredSecurityService::QueryTailoredSecurityBit);
+ if (base::Time::Now() - last_updated_ <=
+ base::Minutes(kRepeatingCheckTailoredSecurityBitDelayInMinutes)) {
+ // Since we queried recently, start the timer with a shorter delay.
+ base::TimeDelta delay =
+ base::Minutes(kRepeatingCheckTailoredSecurityBitDelayInMinutes) -
+ (base::Time::Now() - last_updated_);
+ timer_.Start(FROM_HERE, delay, this,
+ &TailoredSecurityService::QueryTailoredSecurityBit);
+ } else {
+ // Query now and register a timer to get the tailored security bit
+ // every `kRepeatingCheckTailoredSecurityBitDelayInMinutes` minutes.
+ QueryTailoredSecurityBit();
+ timer_.Start(
+ FROM_HERE,
+ base::Minutes(kRepeatingCheckTailoredSecurityBitDelayInMinutes), this,
+ &TailoredSecurityService::QueryTailoredSecurityBit);
+ }
}
}
@@ -362,6 +372,12 @@ void TailoredSecurityService::OnTailoredSecurityBitRetrieved(
}
is_tailored_security_enabled_ = is_enabled;
last_updated_ = base::Time::Now();
+ if (active_query_request_ > 0) {
+ timer_.Start(
+ FROM_HERE,
+ base::Minutes(kRepeatingCheckTailoredSecurityBitDelayInMinutes), this,
+ &TailoredSecurityService::QueryTailoredSecurityBit);
+ }
}
void TailoredSecurityService::QueryTailoredSecurityBitCompletionCallback(
@@ -400,8 +416,8 @@ void TailoredSecurityService::SetTailoredSecurityBitForTesting(
std::unique_ptr<Request> request =
CreateRequest(url, std::move(completion_callback), traffic_annotation);
- base::DictionaryValue enable_tailored_security_service;
- enable_tailored_security_service.SetBoolean("history_recording_enabled",
+ base::Value enable_tailored_security_service(base::Value::Type::DICTIONARY);
+ enable_tailored_security_service.SetBoolKey("history_recording_enabled",
is_enabled);
std::string post_data;
base::JSONWriter::Write(enable_tailored_security_service, &post_data);
diff --git a/chromium/components/safe_browsing/core/browser/tailored_security_service/tailored_security_service.h b/chromium/components/safe_browsing/core/browser/tailored_security_service/tailored_security_service.h
index 7f5b17b7e75..1ac110db37a 100644
--- a/chromium/components/safe_browsing/core/browser/tailored_security_service/tailored_security_service.h
+++ b/chromium/components/safe_browsing/core/browser/tailored_security_service/tailored_security_service.h
@@ -174,7 +174,7 @@ class TailoredSecurityService : public KeyedService {
size_t active_query_request_ = 0;
// Timer to periodically check tailored security bit.
- base::RepeatingTimer timer_;
+ base::OneShotTimer timer_;
bool is_tailored_security_enabled_ = false;
base::Time last_updated_;
diff --git a/chromium/components/safe_browsing/core/browser/tailored_security_service/tailored_security_service_unittest.cc b/chromium/components/safe_browsing/core/browser/tailored_security_service/tailored_security_service_unittest.cc
index 8b302360186..4b1a670a3bf 100644
--- a/chromium/components/safe_browsing/core/browser/tailored_security_service/tailored_security_service_unittest.cc
+++ b/chromium/components/safe_browsing/core/browser/tailored_security_service/tailored_security_service_unittest.cc
@@ -259,10 +259,6 @@ void TestingTailoredSecurityService::MaybeNotifySyncUser(
} // namespace
// A test class used for testing the TailoredSecurityService class.
-// In order for TailoredSecurityService to be valid, we must have a valid
-// ProfileSyncService. Using the ProfileSyncServiceMock class allows to
-// assign specific return values as needed to make sure the tailored security
-// service is available.
class TailoredSecurityServiceTest : public testing::Test {
public:
TailoredSecurityServiceTest()
diff --git a/chromium/components/safe_browsing/core/browser/user_population_unittest.cc b/chromium/components/safe_browsing/core/browser/user_population_unittest.cc
index 9c1a359d587..af99d63a083 100644
--- a/chromium/components/safe_browsing/core/browser/user_population_unittest.cc
+++ b/chromium/components/safe_browsing/core/browser/user_population_unittest.cc
@@ -35,6 +35,10 @@ std::unique_ptr<PrefService> CreatePrefService() {
TEST(GetUserPopulationTest, PopulatesPopulation) {
base::test::TaskEnvironment task_environment;
auto pref_service = CreatePrefService();
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitWithFeatures(
+ /* enabled_features */ {safe_browsing::kEnhancedProtection},
+ /* disabled_features */ {});
SetSafeBrowsingState(pref_service.get(),
SafeBrowsingState::STANDARD_PROTECTION);
@@ -50,6 +54,7 @@ TEST(GetUserPopulationTest, PopulatesPopulation) {
GetUserPopulation(pref_service.get(), false, false, false, nullptr,
absl::optional<size_t>(), absl::optional<size_t>(),
absl::optional<size_t>());
+
EXPECT_EQ(population.user_population(),
ChromeUserPopulation::ENHANCED_PROTECTION);
diff --git a/chromium/components/safe_browsing/core/browser/verdict_cache_manager.cc b/chromium/components/safe_browsing/core/browser/verdict_cache_manager.cc
index 2535217b03f..90bbe1dd191 100644
--- a/chromium/components/safe_browsing/core/browser/verdict_cache_manager.cc
+++ b/chromium/components/safe_browsing/core/browser/verdict_cache_manager.cc
@@ -14,6 +14,8 @@
#include "base/strings/string_split.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "base/time/time.h"
+#include "components/content_settings/core/browser/host_content_settings_map.h"
+#include "components/content_settings/core/common/content_settings_utils.h"
#include "components/history/core/browser/history_service_observer.h"
#include "components/safe_browsing/core/browser/db/v4_protocol_manager_util.h"
#include "components/safe_browsing/core/common/proto/csd.pb.h"
@@ -281,8 +283,9 @@ typename T::VerdictType GetMostMatchingCachedVerdictWithPathMatching(
GURL hostname = GetHostNameWithHTTPScheme(url);
std::unique_ptr<base::DictionaryValue> cache_dictionary =
- base::DictionaryValue::From(content_settings->GetWebsiteSetting(
- hostname, GURL(), contents_setting_type, nullptr));
+ base::DictionaryValue::From(content_settings::ToNullableUniquePtrValue(
+ content_settings->GetWebsiteSetting(hostname, GURL(),
+ contents_setting_type, nullptr)));
if (!cache_dictionary || cache_dictionary->DictEmpty())
return T::VERDICT_TYPE_UNSPECIFIED;
@@ -417,8 +420,10 @@ void VerdictCacheManager::CachePhishGuardVerdict(
GURL hostname = GetHostNameFromCacheExpression(GetCacheExpression(verdict));
std::unique_ptr<base::DictionaryValue> cache_dictionary =
- base::DictionaryValue::From(content_settings_->GetWebsiteSetting(
- hostname, GURL(), ContentSettingsType::PASSWORD_PROTECTION, nullptr));
+ base::DictionaryValue::From(content_settings::ToNullableUniquePtrValue(
+ content_settings_->GetWebsiteSetting(
+ hostname, GURL(), ContentSettingsType::PASSWORD_PROTECTION,
+ nullptr)));
if (!cache_dictionary)
cache_dictionary = std::make_unique<base::DictionaryValue>();
@@ -453,7 +458,7 @@ void VerdictCacheManager::CachePhishGuardVerdict(
base::Value::FromUniquePtrValue(std::move(verdict_entry)));
content_settings_->SetWebsiteSettingDefaultScope(
hostname, GURL(), ContentSettingsType::PASSWORD_PROTECTION,
- std::move(cache_dictionary));
+ base::Value::FromUniquePtrValue(std::move(cache_dictionary)));
}
LoginReputationClientResponse::VerdictType
@@ -544,9 +549,10 @@ void VerdictCacheManager::CacheRealTimeUrlVerdict(
GURL hostname = GetHostNameFromCacheExpression(cache_expression);
std::unique_ptr<base::DictionaryValue> cache_dictionary =
- base::DictionaryValue::From(content_settings_->GetWebsiteSetting(
- hostname, GURL(), ContentSettingsType::SAFE_BROWSING_URL_CHECK_DATA,
- nullptr));
+ base::DictionaryValue::From(content_settings::ToNullableUniquePtrValue(
+ content_settings_->GetWebsiteSetting(
+ hostname, GURL(),
+ ContentSettingsType::SAFE_BROWSING_URL_CHECK_DATA, nullptr)));
if (!cache_dictionary)
cache_dictionary = std::make_unique<base::DictionaryValue>();
@@ -575,7 +581,7 @@ void VerdictCacheManager::CacheRealTimeUrlVerdict(
content_settings_->SetWebsiteSettingDefaultScope(
hostname, GURL(), ContentSettingsType::SAFE_BROWSING_URL_CHECK_DATA,
- std::move(cache_dictionary));
+ base::Value::FromUniquePtrValue(std::move(cache_dictionary)));
}
base::UmaHistogramCounts10000(
"SafeBrowsing.RT.CacheManager.RealTimeVerdictCount",
@@ -650,17 +656,13 @@ void VerdictCacheManager::CleanUpExpiredPhishGuardVerdicts() {
int removed_count = 0;
for (ContentSettingPatternSource& source : password_protection_settings) {
// Find all verdicts associated with this origin.
- std::unique_ptr<base::Value> cache_dictionary =
- base::Value::ToUniquePtrValue(std::move(source.setting_value));
+ base::Value cache_dictionary = std::move(source.setting_value);
bool has_expired_password_on_focus_entry = RemoveExpiredPhishGuardVerdicts(
- LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
- cache_dictionary.get());
+ LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE, &cache_dictionary);
bool has_expired_password_reuse_entry = RemoveExpiredPhishGuardVerdicts(
- LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
- cache_dictionary.get());
+ LoginReputationClientRequest::PASSWORD_REUSE_EVENT, &cache_dictionary);
- if (!cache_dictionary->DictEmpty() &&
- !has_expired_password_on_focus_entry &&
+ if (!cache_dictionary.DictEmpty() && !has_expired_password_on_focus_entry &&
!has_expired_password_reuse_entry) {
continue;
}
@@ -670,7 +672,8 @@ void VerdictCacheManager::CleanUpExpiredPhishGuardVerdicts() {
content_settings_->SetWebsiteSettingCustomScope(
source.primary_pattern, source.secondary_pattern,
ContentSettingsType::PASSWORD_PROTECTION,
- cache_dictionary->DictEmpty() ? nullptr : std::move(cache_dictionary));
+ cache_dictionary.DictEmpty() ? base::Value()
+ : std::move(cache_dictionary));
if ((++removed_count) == kMaxRemovedEntriesCount) {
return;
@@ -691,12 +694,11 @@ void VerdictCacheManager::CleanUpExpiredRealTimeUrlCheckVerdicts() {
for (ContentSettingPatternSource& source :
safe_browsing_url_check_data_settings) {
// Find all verdicts associated with this origin.
- std::unique_ptr<base::Value> cache_dictionary =
- base::Value::ToUniquePtrValue(std::move(source.setting_value));
+ base::Value cache_dictionary = std::move(source.setting_value);
bool has_expired_entry =
- RemoveExpiredRealTimeUrlCheckVerdicts(cache_dictionary.get());
+ RemoveExpiredRealTimeUrlCheckVerdicts(&cache_dictionary);
- if (!cache_dictionary->DictEmpty() && !has_expired_entry) {
+ if (!cache_dictionary.DictEmpty() && !has_expired_entry) {
continue;
}
@@ -705,7 +707,8 @@ void VerdictCacheManager::CleanUpExpiredRealTimeUrlCheckVerdicts() {
content_settings_->SetWebsiteSettingCustomScope(
source.primary_pattern, source.secondary_pattern,
ContentSettingsType::SAFE_BROWSING_URL_CHECK_DATA,
- cache_dictionary->DictEmpty() ? nullptr : std::move(cache_dictionary));
+ cache_dictionary.DictEmpty() ? base::Value()
+ : std::move(cache_dictionary));
if ((++removed_count) == kMaxRemovedEntriesCount) {
return;
@@ -836,10 +839,11 @@ void VerdictCacheManager::RemoveContentSettingsOnURLsDeleted(
GetStoredRealTimeUrlCheckVerdictCount() -
GetRealTimeUrlCheckVerdictCountForURL(url_key);
content_settings_->SetWebsiteSettingDefaultScope(
- url_key, GURL(), ContentSettingsType::PASSWORD_PROTECTION, nullptr);
+ url_key, GURL(), ContentSettingsType::PASSWORD_PROTECTION,
+ base::Value());
content_settings_->SetWebsiteSettingDefaultScope(
url_key, GURL(), ContentSettingsType::SAFE_BROWSING_URL_CHECK_DATA,
- nullptr);
+ base::Value());
}
}
@@ -849,8 +853,9 @@ size_t VerdictCacheManager::GetPhishGuardVerdictCountForURL(
DCHECK(trigger_type == LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE ||
trigger_type == LoginReputationClientRequest::PASSWORD_REUSE_EVENT);
std::unique_ptr<base::DictionaryValue> cache_dictionary =
- base::DictionaryValue::From(content_settings_->GetWebsiteSetting(
- url, GURL(), ContentSettingsType::PASSWORD_PROTECTION, nullptr));
+ base::DictionaryValue::From(content_settings::ToNullableUniquePtrValue(
+ content_settings_->GetWebsiteSetting(
+ url, GURL(), ContentSettingsType::PASSWORD_PROTECTION, nullptr)));
if (!cache_dictionary || cache_dictionary->DictEmpty())
return 0;
@@ -874,9 +879,10 @@ size_t VerdictCacheManager::GetPhishGuardVerdictCountForURL(
size_t VerdictCacheManager::GetRealTimeUrlCheckVerdictCountForURL(
const GURL& url) {
std::unique_ptr<base::DictionaryValue> cache_dictionary =
- base::DictionaryValue::From(content_settings_->GetWebsiteSetting(
- url, GURL(), ContentSettingsType::SAFE_BROWSING_URL_CHECK_DATA,
- nullptr));
+ base::DictionaryValue::From(content_settings::ToNullableUniquePtrValue(
+ content_settings_->GetWebsiteSetting(
+ url, GURL(), ContentSettingsType::SAFE_BROWSING_URL_CHECK_DATA,
+ nullptr)));
if (!cache_dictionary || cache_dictionary->DictEmpty())
return 0;
base::Value* verdict_dictionary =
diff --git a/chromium/components/safe_browsing/core/browser/verdict_cache_manager_unittest.cc b/chromium/components/safe_browsing/core/browser/verdict_cache_manager_unittest.cc
index de93b907169..67feadb5280 100644
--- a/chromium/components/safe_browsing/core/browser/verdict_cache_manager_unittest.cc
+++ b/chromium/components/safe_browsing/core/browser/verdict_cache_manager_unittest.cc
@@ -209,7 +209,8 @@ TEST_F(VerdictCacheManagerTest, TestParseInvalidVerdictEntry) {
content_setting_map_->SetWebsiteSettingDefaultScope(
GURL("http://www.google.com/"), GURL(),
- ContentSettingsType::PASSWORD_PROTECTION, std::move(cache_dictionary));
+ ContentSettingsType::PASSWORD_PROTECTION,
+ base::Value::FromUniquePtrValue(std::move(cache_dictionary)));
ReusedPasswordAccountType password_type;
password_type.set_account_type(ReusedPasswordAccountType::GSUITE);
@@ -459,7 +460,8 @@ TEST_F(VerdictCacheManagerTest, TestCleanUpExpiredVerdictWithInvalidEntry) {
content_setting_map_->SetWebsiteSettingDefaultScope(
GURL("http://www.google.com/"), GURL(),
- ContentSettingsType::PASSWORD_PROTECTION, std::move(cache_dictionary));
+ ContentSettingsType::PASSWORD_PROTECTION,
+ base::Value::FromUniquePtrValue(std::move(cache_dictionary)));
ReusedPasswordAccountType password_type;
password_type.set_account_type(ReusedPasswordAccountType::GSUITE);
@@ -473,7 +475,7 @@ TEST_F(VerdictCacheManagerTest, TestCleanUpExpiredVerdictWithInvalidEntry) {
->GetWebsiteSetting(
GURL("http://www.google.com/"), GURL(),
ContentSettingsType::PASSWORD_PROTECTION, nullptr)
- ->FindDictKey("1")
+ .FindDictKey("1")
->DictSize());
cache_manager_->CleanUpExpiredVerdicts();
@@ -483,7 +485,7 @@ TEST_F(VerdictCacheManagerTest, TestCleanUpExpiredVerdictWithInvalidEntry) {
->GetWebsiteSetting(
GURL("http://www.google.com/"), GURL(),
ContentSettingsType::PASSWORD_PROTECTION, nullptr)
- ->FindDictKey("1")
+ .FindDictKey("1")
->DictSize());
}
diff --git a/chromium/components/safe_browsing/core/common/features.cc b/chromium/components/safe_browsing/core/common/features.cc
index 2b93f3394d5..7eb745450bf 100644
--- a/chromium/components/safe_browsing/core/common/features.cc
+++ b/chromium/components/safe_browsing/core/common/features.cc
@@ -31,13 +31,13 @@ const base::Feature kBetterTelemetryAcrossReports{
base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kClientSideDetectionDocumentScanning{
- "ClientSideDetectionDocumentScanning", base::FEATURE_DISABLED_BY_DEFAULT};
+ "ClientSideDetectionDocumentScanning", base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kClientSideDetectionForAndroid{
"ClientSideDetectionModelOnAndroid", base::FEATURE_ENABLED_BY_DEFAULT};
// Enable only for Android
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
const base::Feature kClientSideDetectionModelIsFlatBuffer{
"ClientSideDetectionModelIsFlatBuffer", base::FEATURE_ENABLED_BY_DEFAULT};
#else
@@ -58,13 +58,10 @@ const base::Feature kClientSideDetectionReferrerChain{
"ClientSideDetectionReferrerChain", base::FEATURE_ENABLED_BY_DEFAULT};
// TODO(b/197749390): Add tests for this feature being enabled when it's
-// finalied.
+// finalized.
const base::Feature kConnectorsScanningReportOnlyUI{
"ConnectorsScanningReportOnlyUI", base::FEATURE_DISABLED_BY_DEFAULT};
-const base::Feature kFileTypePoliciesTag{"FileTypePoliciesTag",
- base::FEATURE_ENABLED_BY_DEFAULT};
-
const base::Feature kDelayedWarnings{"SafeBrowsingDelayedWarnings",
base::FEATURE_DISABLED_BY_DEFAULT};
@@ -75,6 +72,18 @@ const base::FeatureParam<bool> kDelayedWarningsEnableMouseClicks{
&kDelayedWarnings, "mouse",
/*default_value=*/false};
+const base::Feature kDownloadBubble{"DownloadBubble",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+const base::Feature kEnhancedProtection {
+ "SafeBrowsingEnhancedProtection",
+#if BUILDFLAG(IS_IOS)
+ base::FEATURE_DISABLED_BY_DEFAULT
+#else
+ base::FEATURE_ENABLED_BY_DEFAULT
+#endif
+};
+
const base::Feature kExtensionTelemetry{"SafeBrowsingExtensionTelemetry",
base::FEATURE_DISABLED_BY_DEFAULT};
@@ -82,6 +91,9 @@ const base::FeatureParam<int> kExtensionTelemetryUploadIntervalSeconds{
&kExtensionTelemetry, "UploadIntervalSeconds",
/*default_value=*/3600};
+const base::Feature kFileTypePoliciesTag{"FileTypePoliciesTag",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+
const base::Feature kSimplifiedUrlDisplay{"SimplifiedUrlDisplay",
base::FEATURE_DISABLED_BY_DEFAULT};
@@ -90,20 +102,18 @@ const base::Feature kTailoredSecurityIntegration{
const base::Feature kOmitNonUserGesturesFromReferrerChain{
"SafeBrowsingOmitNonUserGesturesFromReferrerChain",
- base::FEATURE_DISABLED_BY_DEFAULT};
+ base::FEATURE_ENABLED_BY_DEFAULT};
-const base::Feature kPasswordProtectionForSignedInUsers {
- "SafeBrowsingPasswordProtectionForSignedInUsers",
-#if BUILDFLAG(FULL_SAFE_BROWSING)
- base::FEATURE_ENABLED_BY_DEFAULT
-#else
- base::FEATURE_DISABLED_BY_DEFAULT
-#endif
-};
+const base::Feature kPasswordProtectionForSignedInUsers{
+ "SafeBrowsingPasswordProtectionForSignedInUsers",
+ base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kPromptEsbForDeepScanning{
"SafeBrowsingPromptEsbForDeepScanning", base::FEATURE_ENABLED_BY_DEFAULT};
+const base::Feature kSafeBrowsingCsbrrWithToken{
+ "SafeBrowsingCsbrrWithToken", base::FEATURE_DISABLED_BY_DEFAULT};
+
const base::Feature kSafeBrowsingCTDownloadWarning{
"SafeBrowsingCTDownloadWarning", base::FEATURE_DISABLED_BY_DEFAULT};
@@ -114,12 +124,8 @@ const base::Feature kSafeBrowsingDisableConsumerCsdForEnterprise{
"SafeBrowsingDisableConsumerCsdForEnterprise",
base::FEATURE_ENABLED_BY_DEFAULT};
-const base::Feature kRealTimeUrlLookupReferrerChainForEnterprise{
- "SafeBrowsingRealTimeUrlLookupReferrerChainForEnterprise",
- base::FEATURE_ENABLED_BY_DEFAULT};
-
const base::Feature kSafeBrowsingPageLoadToken{
- "SafeBrowsingPageLoadToken", base::FEATURE_DISABLED_BY_DEFAULT};
+ "SafeBrowsingPageLoadToken", base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature
kSafeBrowsingPasswordCheckIntegrationForSavedPasswordsAndroid{
@@ -130,6 +136,10 @@ const base::Feature kSafeBrowsingRemoveCookiesInAuthRequests{
"SafeBrowsingRemoveCookiesInAuthRequests",
base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kSendSampledPingsForProtegoAllowlistDomains{
+ "SafeBrowsingSendSampledPingsForProtegoAllowlistDomains",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
constexpr base::FeatureParam<bool> kShouldFillOldPhishGuardProto{
&kPasswordProtectionForSignedInUsers, "DeprecateOldProto", false};
@@ -168,15 +178,19 @@ constexpr struct {
{&kClientSideDetectionModelIsFlatBuffer, true},
{&kClientSideDetectionModelVersion, true},
{&kClientSideDetectionReferrerChain, true},
+ {&kConnectorsScanningReportOnlyUI, true},
{&kDelayedWarnings, true},
+ {&kDownloadBubble, true},
+ {&kEnhancedProtection, true},
{&kExtensionTelemetry, true},
{&kFileTypePoliciesTag, true},
{&kOmitNonUserGesturesFromReferrerChain, true},
{&kPasswordProtectionForSignedInUsers, true},
- {&kRealTimeUrlLookupReferrerChainForEnterprise, true},
+ {&kSafeBrowsingCsbrrWithToken, true},
{&kSafeBrowsingPageLoadToken, true},
{&kSafeBrowsingPasswordCheckIntegrationForSavedPasswordsAndroid, true},
{&kSafeBrowsingRemoveCookiesInAuthRequests, true},
+ {&kSendSampledPingsForProtegoAllowlistDomains, true},
{&kSuspiciousSiteTriggerQuotaFeature, true},
{&kThreatDomDetailsTagAndAttributeFeature, false},
{&kTriggerThrottlerDailyQuotaFeature, false},
diff --git a/chromium/components/safe_browsing/core/common/features.h b/chromium/components/safe_browsing/core/common/features.h
index c53463b3a98..2d6c7fb21ca 100644
--- a/chromium/components/safe_browsing/core/common/features.h
+++ b/chromium/components/safe_browsing/core/common/features.h
@@ -70,6 +70,12 @@ extern const base::Feature kDelayedWarnings;
// warnings feature is enabled.
extern const base::FeatureParam<bool> kDelayedWarningsEnableMouseClicks;
+// Whether to use download bubble instead of download shelf.
+extern const base::Feature kDownloadBubble;
+
+// Enables Enhanced Safe Browsing.
+extern const base::Feature kEnhancedProtection;
+
// Enables collection of signals related to extension activity and uploads
// of telemetry reports to SB servers.
extern const base::Feature kExtensionTelemetry;
@@ -93,6 +99,10 @@ extern const base::Feature kPasswordProtectionForSignedInUsers;
// scanning.
extern const base::Feature kPromptEsbForDeepScanning;
+// Controls whether Client Safe Browsing Reports are sent with a GAIA-tied token
+// for Enhanced Safe Browsing users
+extern const base::Feature kSafeBrowsingCsbrrWithToken;
+
// Controls whether users will see an account compromise specific warning
// when Safe Browsing determines a file is associated with stealing cookies.
extern const base::Feature kSafeBrowsingCTDownloadWarning;
@@ -119,9 +129,9 @@ extern const base::Feature kSafeBrowsingRemoveCookiesInAuthRequests;
// Controls the daily quota for the suspicious site trigger.
extern const base::Feature kSuspiciousSiteTriggerQuotaFeature;
-// Controls whether the referrer chain is attached to real time requests for
-// enterprise.
-extern const base::Feature kRealTimeUrlLookupReferrerChainForEnterprise;
+// Controls whether to send sample pings of Protego allowlist domains on
+// the allowlist to Safe Browsing.
+extern const base::Feature kSendSampledPingsForProtegoAllowlistDomains;
// Status of the SimplifiedUrlDisplay experiments. This does not control the
// individual experiments, those are controlled by their own feature flags.
diff --git a/chromium/components/safe_browsing/core/common/proto/csd.proto b/chromium/components/safe_browsing/core/common/proto/csd.proto
index 9152f7efd3c..e2339cee173 100644
--- a/chromium/components/safe_browsing/core/common/proto/csd.proto
+++ b/chromium/components/safe_browsing/core/common/proto/csd.proto
@@ -1384,7 +1384,7 @@ message DownloadMetadata {
// A Detailed Safebrowsing Report from clients. Chrome safebrowsing reports are
// only sent by Chrome users who have opted into extended Safe Browsing.
// This proto is replacing ClientMalwareReportRequest.
-// Next tag: 26
+// Next tag: 27
message ClientSafeBrowsingReportRequest {
// Note: A lot of the "optional" fields would make sense to be
// "required" instead. However, having them as optional allows the
@@ -1560,6 +1560,8 @@ message ClientSafeBrowsingReportRequest {
// The SafetyNet ID of the Android device.
// Deprecated, not launched.
optional string safety_net_id = 25 [deprecated = true];
+
+ optional ChromeUserPopulation population = 26;
}
// An HTML Element on the page (eg: iframe, div, script, etc).
@@ -1619,11 +1621,15 @@ message ExtensionTelemetryReportRequest {
message TabsExecuteScriptInfo {
message ScriptInfo {
optional bytes hash = 1;
- // number of times script has been executed since
- // last report/browser start
+ // Number of times this script has been executed since
+ // last report/browser start. This number is limited to
+ // a configurable maximum (default max is 100).
optional uint32 execution_count = 2;
}
repeated ScriptInfo scripts = 1;
+ // The number of scripts that were not recorded because the max count was
+ // exceeded.
+ optional uint32 max_exceeded_script_count = 2;
}
optional TabsExecuteScriptInfo tabs_execute_script_info = 1;
diff --git a/chromium/components/safe_browsing/core/common/proto/realtimeapi.proto b/chromium/components/safe_browsing/core/common/proto/realtimeapi.proto
index f6e05fc9845..53e00dfda7f 100644
--- a/chromium/components/safe_browsing/core/common/proto/realtimeapi.proto
+++ b/chromium/components/safe_browsing/core/common/proto/realtimeapi.proto
@@ -47,6 +47,8 @@ message RTLookupRequest {
// cache.
// Version 2:
// * Client supports referrer chains.
+ // Version 3:
+ // * Client support the |report_type| and |frame_type| fields.
optional int32 version = 6 [default = 0];
// The operating system of the client.
@@ -67,6 +69,25 @@ message RTLookupRequest {
// chronological order, i.e. current URL comes first in this list, and landing
// referrer comes last.
repeated ReferrerChainEntry referrer_chain = 8;
+
+ // Type of report sent.
+ enum ReportType {
+ REPORT_TYPE_UNSPECIFIED = 0;
+ FULL_REPORT = 1;
+ SAMPLED_REPORT = 2;
+ }
+ // Whether the ping sent to Safe Browsing is a normal (full request) ping or a
+ // sample ping for URLs on the allow-list.
+ optional ReportType report_type = 9;
+
+ // Type of URL frame.
+ enum FrameType {
+ FRAME_TYPE_UNSPECIFIED = 0;
+ MAIN_FRAME = 1;
+ SUB_FRAME = 2;
+ }
+ // Whether the URL sent to Safe Browsing is mainframe URL or subframe URL.
+ optional FrameType frame_type = 10;
}
message RTLookupResponse {
diff --git a/chromium/components/safe_browsing/core/common/safe_browsing_prefs.cc b/chromium/components/safe_browsing/core/common/safe_browsing_prefs.cc
index bacfcd99cfa..efc273d4c24 100644
--- a/chromium/components/safe_browsing/core/common/safe_browsing_prefs.cc
+++ b/chromium/components/safe_browsing/core/common/safe_browsing_prefs.cc
@@ -150,7 +150,8 @@ bool IsSafeBrowsingEnabled(const PrefService& prefs) {
bool IsEnhancedProtectionEnabled(const PrefService& prefs) {
// SafeBrowsingEnabled is checked too due to devices being out
// of sync or not on a version that includes SafeBrowsingEnhanced pref.
- return prefs.GetBoolean(prefs::kSafeBrowsingEnhanced) &&
+ return base::FeatureList::IsEnabled(kEnhancedProtection) &&
+ prefs.GetBoolean(prefs::kSafeBrowsingEnhanced) &&
IsSafeBrowsingEnabled(prefs);
}
@@ -288,7 +289,7 @@ base::ListValue GetSafeBrowsingPreferencesList(PrefService* prefs) {
base::ListValue GetSafeBrowsingPoliciesList(PrefService* prefs) {
base::ListValue preferences_list;
- const base::ListValue* allowlist_domains =
+ const base::Value* allowlist_domains =
prefs->GetList(prefs::kSafeBrowsingAllowlistDomains);
std::vector<std::string> domain_list;
CanonicalizeDomainList(*allowlist_domains, &domain_list);
@@ -321,17 +322,17 @@ base::ListValue GetSafeBrowsingPoliciesList(PrefService* prefs) {
void GetSafeBrowsingAllowlistDomainsPref(
const PrefService& prefs,
std::vector<std::string>* out_canonicalized_domain_list) {
- const base::ListValue* pref_value =
+ const base::Value* pref_value =
prefs.GetList(prefs::kSafeBrowsingAllowlistDomains);
CanonicalizeDomainList(*pref_value, out_canonicalized_domain_list);
}
void CanonicalizeDomainList(
- const base::ListValue& raw_domain_list,
+ const base::Value& raw_domain_list,
std::vector<std::string>* out_canonicalized_domain_list) {
out_canonicalized_domain_list->clear();
- for (auto it = raw_domain_list.GetList().begin();
- it != raw_domain_list.GetList().end(); it++) {
+ for (auto it = raw_domain_list.GetListDeprecated().begin();
+ it != raw_domain_list.GetListDeprecated().end(); it++) {
// Verify if it is valid domain string.
url::CanonHostInfo host_info;
std::string canonical_host =
@@ -344,9 +345,9 @@ void CanonicalizeDomainList(
bool IsURLAllowlistedByPolicy(const GURL& url, const PrefService& pref) {
if (!pref.HasPrefPath(prefs::kSafeBrowsingAllowlistDomains))
return false;
- const base::ListValue* allowlist =
+ const base::Value* allowlist =
pref.GetList(prefs::kSafeBrowsingAllowlistDomains);
- for (const base::Value& value : allowlist->GetList()) {
+ for (const base::Value& value : allowlist->GetListDeprecated()) {
if (url.DomainIs(value.GetString()))
return true;
}
@@ -355,9 +356,9 @@ bool IsURLAllowlistedByPolicy(const GURL& url, const PrefService& pref) {
std::vector<std::string> GetURLAllowlistByPolicy(PrefService* pref_service) {
std::vector<std::string> allowlist_domains;
- const base::ListValue* allowlist =
+ const base::Value* allowlist =
pref_service->GetList(prefs::kSafeBrowsingAllowlistDomains);
- for (const base::Value& value : allowlist->GetList()) {
+ for (const base::Value& value : allowlist->GetListDeprecated()) {
allowlist_domains.push_back(value.GetString());
}
return allowlist_domains;
@@ -374,10 +375,10 @@ bool MatchesEnterpriseAllowlist(const PrefService& pref,
void GetPasswordProtectionLoginURLsPref(const PrefService& prefs,
std::vector<GURL>* out_login_url_list) {
- const base::ListValue* pref_value =
+ const base::Value* pref_value =
prefs.GetList(prefs::kPasswordProtectionLoginURLs);
out_login_url_list->clear();
- for (const base::Value& value : pref_value->GetList()) {
+ for (const base::Value& value : pref_value->GetListDeprecated()) {
GURL login_url(value.GetString());
// Skip invalid or none-http/https login URLs.
if (login_url.is_valid() && login_url.SchemeIsHTTPOrHTTPS())
diff --git a/chromium/components/safe_browsing/core/common/safe_browsing_prefs.h b/chromium/components/safe_browsing/core/common/safe_browsing_prefs.h
index c72b92ad774..05136ba29e4 100644
--- a/chromium/components/safe_browsing/core/common/safe_browsing_prefs.h
+++ b/chromium/components/safe_browsing/core/common/safe_browsing_prefs.h
@@ -291,7 +291,7 @@ void GetSafeBrowsingAllowlistDomainsPref(
// Helper function to validate and canonicalize a list of domain strings.
void CanonicalizeDomainList(
- const base::ListValue& raw_domain_list,
+ const base::Value& raw_domain_list,
std::vector<std::string>* out_canonicalized_domain_list);
// Helper function to determine if |url| matches Safe Browsing allowlist domains
diff --git a/chromium/components/safe_browsing/core/common/safe_browsing_prefs_unittest.cc b/chromium/components/safe_browsing/core/common/safe_browsing_prefs_unittest.cc
index ca51a13fe8a..ec3a286d996 100644
--- a/chromium/components/safe_browsing/core/common/safe_browsing_prefs_unittest.cc
+++ b/chromium/components/safe_browsing/core/common/safe_browsing_prefs_unittest.cc
@@ -54,15 +54,7 @@ class SafeBrowsingPrefsTest : public ::testing::Test {
TestingPrefServiceSimple prefs_;
};
-// TODO(crbug.com/881476) disabled for flaky crashes.
-#if defined(OS_WIN)
-#define MAYBE_GetSafeBrowsingExtendedReportingLevel \
- DISABLED_GetSafeBrowsingExtendedReportingLevel
-#else
-#define MAYBE_GetSafeBrowsingExtendedReportingLevel \
- GetSafeBrowsingExtendedReportingLevel
-#endif
-TEST_F(SafeBrowsingPrefsTest, MAYBE_GetSafeBrowsingExtendedReportingLevel) {
+TEST_F(SafeBrowsingPrefsTest, GetSafeBrowsingExtendedReportingLevel) {
// By Default, extended reporting is off.
EXPECT_EQ(SBER_LEVEL_OFF, GetExtendedReportingLevel(prefs_));
@@ -74,15 +66,7 @@ TEST_F(SafeBrowsingPrefsTest, MAYBE_GetSafeBrowsingExtendedReportingLevel) {
EXPECT_EQ(SBER_LEVEL_OFF, GetExtendedReportingLevel(prefs_));
}
-// TODO(crbug.com/881476) disabled for flaky crashes.
-#if defined(OS_WIN)
-#define MAYBE_VerifyMatchesPasswordProtectionLoginURL \
- DISABLED_VerifyMatchesPasswordProtectionLoginURL
-#else
-#define MAYBE_VerifyMatchesPasswordProtectionLoginURL \
- VerifyMatchesPasswordProtectionLoginURL
-#endif
-TEST_F(SafeBrowsingPrefsTest, MAYBE_VerifyMatchesPasswordProtectionLoginURL) {
+TEST_F(SafeBrowsingPrefsTest, VerifyMatchesPasswordProtectionLoginURL) {
GURL url("https://mydomain.com/login.html#ref?username=alice");
EXPECT_FALSE(prefs_.HasPrefPath(prefs::kPasswordProtectionLoginURLs));
EXPECT_FALSE(MatchesPasswordProtectionLoginURL(url, prefs_));
@@ -123,10 +107,14 @@ TEST_F(SafeBrowsingPrefsTest, EnhancedProtection) {
SetEnhancedProtectionPrefForTests(&prefs_, true);
{
base::test::ScopedFeatureList scoped_feature_list;
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeature(kEnhancedProtection);
EXPECT_TRUE(IsEnhancedProtectionEnabled(prefs_));
}
{
base::test::ScopedFeatureList scoped_feature_list;
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndDisableFeature(kEnhancedProtection);
prefs_.SetBoolean(prefs::kSafeBrowsingEnabled, false);
EXPECT_FALSE(IsEnhancedProtectionEnabled(prefs_));
}
diff --git a/chromium/components/safe_browsing/core/common/utils.cc b/chromium/components/safe_browsing/core/common/utils.cc
index a29141ddade..e9f7c2984a5 100644
--- a/chromium/components/safe_browsing/core/common/utils.cc
+++ b/chromium/components/safe_browsing/core/common/utils.cc
@@ -21,7 +21,7 @@
#include "net/http/http_request_headers.h"
#include "services/network/public/cpp/resource_request.h"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include "base/enterprise_util.h"
#endif
@@ -50,18 +50,18 @@ std::string ShortURLForReporting(const GURL& url) {
ChromeUserPopulation::ProfileManagementStatus GetProfileManagementStatus(
const policy::BrowserPolicyConnector* bpc) {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
if (base::IsMachineExternallyManaged())
return ChromeUserPopulation::ENTERPRISE_MANAGED;
else
return ChromeUserPopulation::NOT_MANAGED;
-#elif defined(OS_CHROMEOS)
+#elif BUILDFLAG(IS_CHROMEOS)
if (!bpc || !bpc->IsDeviceEnterpriseManaged())
return ChromeUserPopulation::NOT_MANAGED;
return ChromeUserPopulation::ENTERPRISE_MANAGED;
#else
return ChromeUserPopulation::UNAVAILABLE;
-#endif // #if defined(OS_WIN) || defined(OS_CHROMEOS)
+#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_CHROMEOS)
}
void SetDelayInPref(PrefService* prefs,
diff --git a/chromium/components/safe_browsing/core/common/visual_utils.cc b/chromium/components/safe_browsing/core/common/visual_utils.cc
index 4b1d789fcdc..bf472a9a59e 100644
--- a/chromium/components/safe_browsing/core/common/visual_utils.cc
+++ b/chromium/components/safe_browsing/core/common/visual_utils.cc
@@ -29,7 +29,7 @@ namespace {
// WARNING: The following parameters are highly privacy and performance
// sensitive. These should not be changed without thorough review.
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
const int kPHashDownsampleWidth = 108;
const int kPHashDownsampleHeight = 192;
#else
diff --git a/chromium/components/safe_search_api/safe_search/safe_search_url_checker_client.cc b/chromium/components/safe_search_api/safe_search/safe_search_url_checker_client.cc
index 2a246b7446e..bce77656f52 100644
--- a/chromium/components/safe_search_api/safe_search/safe_search_url_checker_client.cc
+++ b/chromium/components/safe_search_api/safe_search/safe_search_url_checker_client.cc
@@ -52,11 +52,12 @@ bool ParseResponse(const std::string& response, bool* is_porn) {
DLOG(WARNING) << "ParseResponse failed to parse classifications list";
return false;
}
- if (classifications_list->GetList().size() != 1) {
+ if (classifications_list->GetListDeprecated().size() != 1) {
DLOG(WARNING) << "ParseResponse expected exactly one result";
return false;
}
- const base::Value& classification_value = classifications_list->GetList()[0];
+ const base::Value& classification_value =
+ classifications_list->GetListDeprecated()[0];
if (!classification_value.is_dict()) {
DLOG(WARNING) << "ParseResponse failed to parse classification dict";
return false;
diff --git a/chromium/components/scheduling_metrics/total_duration_metric_reporter.cc b/chromium/components/scheduling_metrics/total_duration_metric_reporter.cc
index 768c29fcc4a..5f5f2040773 100644
--- a/chromium/components/scheduling_metrics/total_duration_metric_reporter.cc
+++ b/chromium/components/scheduling_metrics/total_duration_metric_reporter.cc
@@ -4,6 +4,8 @@
#include "components/scheduling_metrics/total_duration_metric_reporter.h"
+#include "base/cpu_reduction_experiment.h"
+
namespace scheduling_metrics {
namespace {
@@ -34,6 +36,9 @@ TotalDurationMetricReporter::~TotalDurationMetricReporter() = default;
void TotalDurationMetricReporter::RecordAdditionalDuration(
base::TimeDelta duration) {
+ static base::CpuReductionExperimentFilter filter;
+ if (!filter.ShouldLogHistograms())
+ return;
if (reported_value_)
negative_histogram_->Add(reported_value_->InSeconds());
reported_value_ = reported_value_.value_or(base::TimeDelta()) + duration;
diff --git a/chromium/components/search/BUILD.gn b/chromium/components/search/BUILD.gn
index df271d33321..ae69d747d7c 100644
--- a/chromium/components/search/BUILD.gn
+++ b/chromium/components/search/BUILD.gn
@@ -14,6 +14,7 @@ static_library("search") {
deps = [
"//base",
+ "//components/commerce/core:feature_list",
"//components/google/core/common",
"//components/history/core/browser",
"//components/keyed_service/core",
diff --git a/chromium/components/search/DEPS b/chromium/components/search/DEPS
index 41868402988..45c457aaa82 100644
--- a/chromium/components/search/DEPS
+++ b/chromium/components/search/DEPS
@@ -1,6 +1,7 @@
include_rules = [
"+components/bookmarks/browser",
"+components/bookmarks/test",
+ "+components/commerce",
"+components/google/core",
"+components/history/core",
"+components/keyed_service/core",
diff --git a/chromium/components/search/ntp_features.cc b/chromium/components/search/ntp_features.cc
index 5506ac536bf..560ec91ed7e 100644
--- a/chromium/components/search/ntp_features.cc
+++ b/chromium/components/search/ntp_features.cc
@@ -7,8 +7,10 @@
#include "base/feature_list.h"
#include "base/metrics/field_trial_params.h"
#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
#include "base/time/time.h"
#include "build/build_config.h"
+#include "components/commerce/core/commerce_feature_list.h"
namespace ntp_features {
@@ -31,11 +33,16 @@ const base::Feature kDismissPromos{"DismissNtpPromos",
const base::Feature kNtpRepeatableQueries{"NtpRepeatableQueries",
base::FEATURE_DISABLED_BY_DEFAULT};
-// Depends on kRealbox being enabled. If enabled, the NTP "realbox" will be
-// themed like the omnibox (same background/text/selected/hover colors).
+// If enabled, the NTP "realbox" will be themed like the omnibox
+// (same background/text/selected/hover colors).
const base::Feature kRealboxMatchOmniboxTheme{
"NtpRealboxMatchOmniboxTheme", base::FEATURE_DISABLED_BY_DEFAULT};
+// If enabled, the NTP "realbox" will be themed like the searchbox (same border/
+// drop shadow on hover state/rounded corners).
+const base::Feature kRealboxMatchSearchboxTheme{
+ "NtpRealboxMatchSearchboxTheme", base::FEATURE_DISABLED_BY_DEFAULT};
+
// If enabled, the real search box ("realbox") on the New Tab page will show a
// Google (g) icon instead of the typical magnifying glass (aka loupe).
const base::Feature kRealboxUseGoogleGIcon{"NtpRealboxUseGoogleGIcon",
@@ -84,6 +91,11 @@ const base::Feature kNtpShoppingTasksModule{"NtpShoppingTasksModule",
// If enabled, chrome cart module will be shown.
const base::Feature kNtpChromeCartModule{"NtpChromeCartModule",
base::FEATURE_DISABLED_BY_DEFAULT};
+#if !defined(OFFICIAL_BUILD)
+// If enabled, dummy modules will be shown.
+const base::Feature kNtpDummyModules{"NtpDummyModules",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+#endif
// If enabled, redesigned modules will be shown.
const base::Feature kNtpModulesRedesigned{"NtpModulesRedesigned",
@@ -102,6 +114,19 @@ const base::Feature kNtpDriveModule{"NtpDriveModule",
const base::Feature kNtpPhotosModule{"NtpPhotosModule",
base::FEATURE_DISABLED_BY_DEFAULT};
+// If enabled, a customized title will be shown on the opt-in card.
+const base::Feature kNtpPhotosModuleCustomizedOptInTitle{
+ "NtpPhotosModuleCustomizedOptInTitle", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// If enabled, a customized art work will be shown on the opt-in card.
+const base::Feature kNtpPhotosModuleCustomizedOptInArtWork{
+ "NtpPhotosModuleCustomizedOptInArtWork", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// If enabled, Google Photos opt-in card will show a button to soft opt-out.
+const base::Feature kNtpPhotosModuleSoftOptOut(
+ "NtpPhotosModuleSoftOptOut",
+ base::FEATURE_DISABLED_BY_DEFAULT);
+
// If enabled, SafeBrowsing module will be shown to a target user.
const base::Feature kNtpSafeBrowsingModule{"NtpSafeBrowsingModule",
base::FEATURE_DISABLED_BY_DEFAULT};
@@ -112,6 +137,7 @@ const base::Feature kNtpModulesDragAndDrop{"NtpModulesDragAndDrop",
const char kNtpModulesLoadTimeoutMillisecondsParam[] =
"NtpModulesLoadTimeoutMillisecondsParam";
+const char kNtpModulesOrderParam[] = "NtpModulesOrderParam";
const char kNtpShoppingTasksModuleDataParam[] =
"NtpShoppingTasksModuleDataParam";
const char kNtpRecipeTasksModuleDataParam[] = "NtpRecipeTasksModuleDataParam";
@@ -119,6 +145,10 @@ const char kNtpShoppingTasksModuleCacheMaxAgeSParam[] =
"NtpShoppingTasksModuleCacheMaxAgeSParam";
const char kNtpRecipeTasksModuleCacheMaxAgeSParam[] =
"NtpRecipeTasksModuleCacheMaxAgeSParam";
+const char kNtpShoppingTasksModuleExperimentGroupParam[] =
+ "NtpShoppingTasksModuleExperimentGroupParam";
+const char kNtpRecipeTasksModuleExperimentGroupParam[] =
+ "NtpRecipeTasksModuleExperimentGroupParam";
const char kNtpChromeCartModuleDataParam[] = "NtpChromeCartModuleDataParam";
const char kNtpChromeCartModuleAbandonedCartDiscountParam[] =
"NtpChromeCartModuleAbandonedCartDiscountParam";
@@ -135,10 +165,109 @@ const char kNtpDriveModuleCacheMaxAgeSParam[] =
const char kNtpDriveModuleExperimentGroupParam[] =
"NtpDriveModuleExperimentGroupParam";
const char kNtpPhotosModuleDataParam[] = "NtpPhotosModuleDataParam";
+const char kNtpPhotosModuleOptInTitleParam[] = "NtpPhotosModuleOptInTitleParam";
+const char kNtpPhotosModuleOptInArtWorkParam[] =
+ "NtpPhotosModuleOptInArtWorkParam";
const char kNtpSafeBrowsingModuleCooldownPeriodDaysParam[] =
"NtpSafeBrowsingModuleCooldownPeriodDaysParam";
const char kNtpSafeBrowsingModuleCountMaxParam[] =
"NtpSafeBrowsingModuleCountMaxParam";
+const char kRealboxMatchOmniboxThemeVariantParam[] =
+ "RealboxMatchOmniboxThemeVariantParam";
+const char kRealboxMatchSearchboxThemeParam[] =
+ "RealboxMatchSearchboxThemeParam";
+
+// Params for Discount Consent V2 in the NTP Cart module.
+const char kNtpChromeCartModuleDiscountConsentNtpVariationParam[] =
+ "discount-consent-ntp-variation";
+const base::FeatureParam<int> kNtpChromeCartModuleDiscountConsentNtpVariation{
+ &commerce::kDiscountConsentV2,
+ kNtpChromeCartModuleDiscountConsentNtpVariationParam, 0};
+const char kNtpChromeCartModuleDiscountConsentReshowTimeParam[] =
+ "discount-consent-ntp-reshow-time";
+const base::FeatureParam<base::TimeDelta>
+ kNtpChromeCartModuleDiscountConsentReshowTime{
+ &commerce::kDiscountConsentV2,
+ kNtpChromeCartModuleDiscountConsentReshowTimeParam, base::Days(28)};
+const char kNtpChromeCartModuleDiscountConsentMaxDismissalCountParam[] =
+ "discount-consent-ntp-max-dismiss-count";
+const base::FeatureParam<int>
+ kNtpChromeCartModuleDiscountConsentMaxDismissalCount{
+ &commerce::kDiscountConsentV2,
+ kNtpChromeCartModuleDiscountConsentMaxDismissalCountParam, 1};
+
+// String change variation params.
+const char kNtpChromeCartModuleDiscountConsentStringChangeContentParam[] =
+ "string-change-content";
+const base::FeatureParam<std::string>
+ kNtpChromeCartModuleDiscountConsentStringChangeContent{
+ &commerce::kDiscountConsentV2,
+ kNtpChromeCartModuleDiscountConsentStringChangeContentParam, ""};
+
+const char kNtpChromeCartModuleDiscountConsentInlineShowCloseButtonParam[] =
+ "inline-card-show-button";
+const base::FeatureParam<bool>
+ kNtpChromeCartModuleDiscountConsentInlineShowCloseButton{
+ &commerce::kDiscountConsentV2,
+ kNtpChromeCartModuleDiscountConsentStringChangeContentParam, true};
+
+// Discount consent v2 step 1 params.
+const char
+ kNtpChromeCartModuleDiscountConsentNtpStepOneUseStaticContentParam[] =
+ "step-one-use-static-content";
+const base::FeatureParam<bool>
+ kNtpChromeCartModuleDiscountConsentNtpStepOneUseStaticContent{
+ &commerce::kDiscountConsentV2,
+ kNtpChromeCartModuleDiscountConsentNtpStepOneUseStaticContentParam,
+ false};
+const char kNtpChromeCartModuleDiscountConsentNtpStepOneStaticContentParam[] =
+ "step-one-static-content";
+const base::FeatureParam<std::string>
+ kNtpChromeCartModuleDiscountConsentNtpStepOneStaticContent{
+ &commerce::kDiscountConsentV2,
+ kNtpChromeCartModuleDiscountConsentNtpStepOneStaticContentParam, ""};
+const char kNtpChromeCartModuleDiscountConsentNtpStepOneContentOneCartParam[] =
+ "step-one-one-cart-content";
+const base::FeatureParam<std::string>
+ kNtpChromeCartModuleDiscountConsentNtpStepOneContentOneCart{
+ &commerce::kDiscountConsentV2,
+ kNtpChromeCartModuleDiscountConsentNtpStepOneContentOneCartParam, ""};
+const char kNtpChromeCartModuleDiscountConsentNtpStepOneContentTwoCartsParam[] =
+ "step-one-two-carts-content";
+const base::FeatureParam<std::string>
+ kNtpChromeCartModuleDiscountConsentNtpStepOneContentTwoCarts{
+ &commerce::kDiscountConsentV2,
+ kNtpChromeCartModuleDiscountConsentNtpStepOneContentTwoCartsParam, ""};
+const char
+ kNtpChromeCartModuleDiscountConsentNtpStepOneContentThreeCartsParam[] =
+ "step-one-three-carts-content";
+const base::FeatureParam<std::string>
+ kNtpChromeCartModuleDiscountConsentNtpStepOneContentThreeCarts{
+ &commerce::kDiscountConsentV2,
+ kNtpChromeCartModuleDiscountConsentNtpStepOneContentThreeCartsParam,
+ ""};
+
+// Discount consent v2 step 2 params.
+const char kNtpChromeCartModuleDiscountConsentNtpStepTwoContentParam[] =
+ "step-two-content";
+const base::FeatureParam<std::string>
+ kNtpChromeCartModuleDiscountConsentNtpStepTwoContent{
+ &commerce::kDiscountConsentV2,
+ kNtpChromeCartModuleDiscountConsentNtpStepTwoContentParam, ""};
+const char
+ kNtpChromeCartModuleDiscountConsentInlineStepTwoDifferentColorParam[] =
+ "step-two-different-color";
+const base::FeatureParam<bool>
+ kNtpChromeCartModuleDiscountConsentInlineStepTwoDifferentColor{
+ &commerce::kDiscountConsentV2,
+ kNtpChromeCartModuleDiscountConsentInlineStepTwoDifferentColorParam,
+ false};
+const char kNtpChromeCartModuleDiscountConsentNtpDialogContentTitleParam[] =
+ "dialog-content-title";
+const base::FeatureParam<std::string>
+ kNtpChromeCartModuleDiscountConsentNtpDialogContentTitle{
+ &commerce::kDiscountConsentV2,
+ kNtpChromeCartModuleDiscountConsentNtpDialogContentTitleParam, ""};
base::TimeDelta GetModulesLoadTimeout() {
std::string param_value = base::GetFieldTrialParamValueByFeature(
@@ -152,4 +281,11 @@ base::TimeDelta GetModulesLoadTimeout() {
return base::Milliseconds(param_value_as_int);
}
+std::vector<std::string> GetModulesOrder() {
+ return base::SplitString(
+ base::GetFieldTrialParamValueByFeature(kModules, kNtpModulesOrderParam),
+ ",:;", base::WhitespaceHandling::TRIM_WHITESPACE,
+ base::SplitResult::SPLIT_WANT_NONEMPTY);
+}
+
} // namespace ntp_features
diff --git a/chromium/components/search/ntp_features.h b/chromium/components/search/ntp_features.h
index badfcce30db..15183d1ebd9 100644
--- a/chromium/components/search/ntp_features.h
+++ b/chromium/components/search/ntp_features.h
@@ -5,7 +5,11 @@
#ifndef COMPONENTS_SEARCH_NTP_FEATURES_H_
#define COMPONENTS_SEARCH_NTP_FEATURES_H_
+#include <string>
+#include <vector>
+
#include "base/feature_list.h"
+#include "base/metrics/field_trial_params.h"
namespace base {
class TimeDelta;
@@ -23,6 +27,7 @@ extern const base::Feature kIframeOneGoogleBar;
extern const base::Feature kNtpRepeatableQueries;
extern const base::Feature kOneGoogleBarModalOverlays;
extern const base::Feature kRealboxMatchOmniboxTheme;
+extern const base::Feature kRealboxMatchSearchboxTheme;
extern const base::Feature kRealboxUseGoogleGIcon;
extern const base::Feature kNtpOneGoogleBar;
extern const base::Feature kNtpLogo;
@@ -36,7 +41,14 @@ extern const base::Feature kNtpChromeCartModule;
extern const base::Feature kNtpModulesRedesigned;
extern const base::Feature kNtpModulesRedesignedLayout;
extern const base::Feature kNtpDriveModule;
+#if !defined(OFFICIAL_BUILD)
+extern const base::Feature kNtpDummyModules;
+#endif
extern const base::Feature kNtpPhotosModule;
+extern const base::Feature kNtpPhotosModuleSoftOptOut;
+
+extern const base::Feature kNtpPhotosModuleCustomizedOptInTitle;
+extern const base::Feature kNtpPhotosModuleCustomizedOptInArtWork;
extern const base::Feature kNtpSafeBrowsingModule;
extern const base::Feature kNtpModulesDragAndDrop;
@@ -44,6 +56,8 @@ extern const base::Feature kNtpHandleMostVisitedNavigationExplicitly;
// Parameter determining the module load timeout.
extern const char kNtpModulesLoadTimeoutMillisecondsParam[];
+// Parameter determining the module order.
+extern const char kNtpModulesOrderParam[];
// Parameter determining the type of shopping data to request.
extern const char kNtpShoppingTasksModuleDataParam[];
// Parameter determining the type of recipe data to request.
@@ -54,6 +68,12 @@ extern const char kNtpShoppingTasksModuleCacheMaxAgeSParam[];
// Parameter determining the max age in seconds of the cache for recipe tasks
// data.
extern const char kNtpRecipeTasksModuleCacheMaxAgeSParam[];
+// Parameter for communicating the experiment group of the shopping tasks module
+// experiment.
+extern const char kNtpShoppingTasksModuleExperimentGroupParam[];
+// Parameter for communicating the experiment group of the recipe tasks module
+// experiment.
+extern const char kNtpRecipeTasksModuleExperimentGroupParam[];
// Parameter determining the type of cart data used to render module.
extern const char kNtpChromeCartModuleDataParam[];
// Parameter for enabling the abandoned cart discount.
@@ -76,14 +96,112 @@ extern const char kNtpDriveModuleCacheMaxAgeSParam[];
extern const char kNtpDriveModuleExperimentGroupParam[];
// Parameter determining the type of Photos data to render.
extern const char kNtpPhotosModuleDataParam[];
+// Parameter determining the art work in opt-in card.
+extern const char kNtpPhotosModuleOptInArtWorkParam[];
+// Parameter determining the title for the opt-in card.
+extern const char kNtpPhotosModuleOptInTitleParam[];
// Parameter determining the number of times a module is shown to a user
// before cooldown starts.
extern const char kNtpSafeBrowsingModuleCountMaxParam[];
// Parameter determining the cooldown period (in days) for a target user.
extern const char kNtpSafeBrowsingModuleCooldownPeriodDaysParam[];
+// Parameter determining the variation of the omnibox theme matching.
+extern const char kRealboxMatchOmniboxThemeVariantParam[];
+// Parameter determining the variations of searchbox theme matching.
+extern const char kRealboxMatchSearchboxThemeParam[];
+
+// The following are Feature params for Discount user consent v2.
+// This indicates the Discount Consent v2 variation on the NTP Cart module.
+enum class DiscountConsentNtpVariation {
+ // These values are persisted to logs. Entries should not be renumbered and
+ // numeric values should never be reused.
+ kDefault = 0,
+ kStringChange = 1,
+ kInline = 2,
+ kDialog = 3,
+ kMaxValue = kDialog
+};
+
+// Param indicates the ConsentV2 variation. See DiscountConsentNtpVariation
+// enum.
+extern const char kNtpChromeCartModuleDiscountConsentNtpVariationParam[];
+extern const base::FeatureParam<int>
+ kNtpChromeCartModuleDiscountConsentNtpVariation;
+// The time interval, after the last dismissal, before reshowing the consent.
+extern const char kNtpChromeCartModuleDiscountConsentReshowTimeParam[];
+extern const base::FeatureParam<base::TimeDelta>
+ kNtpChromeCartModuleDiscountConsentReshowTime;
+// The max number of dismisses allowed.
+extern const char kNtpChromeCartModuleDiscountConsentMaxDismissalCountParam[];
+extern const base::FeatureParam<int>
+ kNtpChromeCartModuleDiscountConsentMaxDismissalCount;
+
+// String change variation params. This string is replacing the content string
+// of the v1 consent.
+extern const char kNtpChromeCartModuleDiscountConsentStringChangeContentParam[];
+extern const base::FeatureParam<std::string>
+ kNtpChromeCartModuleDiscountConsentStringChangeContent;
+
+// DiscountConsentNtpVariation::kInline and DiscountConsentNtpVariation::kDialog
+// params. This indicate whether the 'x' button should show.
+extern const char
+ kNtpChromeCartModuleDiscountConsentInlineShowCloseButtonParam[];
+extern const base::FeatureParam<bool>
+ kNtpChromeCartModuleDiscountConsentInlineShowCloseButton;
+
+// The following are discount consent step 1 params.
+// This indicates whether the content in step 1 is a static string that does not
+// contain any merchant names.
+extern const char
+ kNtpChromeCartModuleDiscountConsentNtpStepOneUseStaticContentParam[];
+extern const base::FeatureParam<bool>
+ kNtpChromeCartModuleDiscountConsentNtpStepOneUseStaticContent;
+// This the content string use in step 1 if
+// kNtpChromeCartModuleDiscountConsentNtpStepOneUseStaticContent.Get() is true.
+extern const char
+ kNtpChromeCartModuleDiscountConsentNtpStepOneStaticContentParam[];
+extern const base::FeatureParam<std::string>
+ kNtpChromeCartModuleDiscountConsentNtpStepOneStaticContent;
+// This is a string template that takes in one merchant name, and it's used when
+// there is only 1 Chrome Cart.
+extern const char
+ kNtpChromeCartModuleDiscountConsentNtpStepOneContentOneCartParam[];
+extern const base::FeatureParam<std::string>
+ kNtpChromeCartModuleDiscountConsentNtpStepOneContentOneCart;
+// This is a string template that takes in two merchant names, and it's used
+// when there are only 2 Chrome Carts.
+extern const char
+ kNtpChromeCartModuleDiscountConsentNtpStepOneContentTwoCartsParam[];
+extern const base::FeatureParam<std::string>
+ kNtpChromeCartModuleDiscountConsentNtpStepOneContentTwoCarts;
+// This is a string template that takes in two merchant names, and it's used
+// when there are 3 or more Chrome Carts.
+extern const char
+ kNtpChromeCartModuleDiscountConsentNtpStepOneContentThreeCartsParam[];
+extern const base::FeatureParam<std::string>
+ kNtpChromeCartModuleDiscountConsentNtpStepOneContentThreeCarts;
+
+// The following are discount consent step 2 params.
+// This is the content string used in step 2. This is the actual consent string.
+extern const char kNtpChromeCartModuleDiscountConsentNtpStepTwoContentParam[];
+extern const base::FeatureParam<std::string>
+ kNtpChromeCartModuleDiscountConsentNtpStepTwoContent;
+// This is used to indicate whether the backgound-color of step 2 should change.
+extern const char
+ kNtpChromeCartModuleDiscountConsentInlineStepTwoDifferentColorParam[];
+extern const base::FeatureParam<bool>
+ kNtpChromeCartModuleDiscountConsentInlineStepTwoDifferentColor;
+// This is the content title use in the dialog consent.
+extern const char
+ kNtpChromeCartModuleDiscountConsentNtpDialogContentTitleParam[];
+extern const base::FeatureParam<std::string>
+ kNtpChromeCartModuleDiscountConsentNtpDialogContentTitle;
// Returns the timeout after which the load of a module should be aborted.
base::TimeDelta GetModulesLoadTimeout();
+
+// Returns a list of module IDs ordered by how they should appear on the NTP.
+std::vector<std::string> GetModulesOrder();
} // namespace ntp_features
#endif // COMPONENTS_SEARCH_NTP_FEATURES_H_
diff --git a/chromium/components/search/search.cc b/chromium/components/search/search.cc
index 8347619c680..43e8dd8d8c4 100644
--- a/chromium/components/search/search.cc
+++ b/chromium/components/search/search.cc
@@ -13,7 +13,7 @@
namespace search {
bool IsInstantExtendedAPIEnabled() {
-#if defined(OS_IOS) || defined(OS_ANDROID)
+#if BUILDFLAG(IS_IOS) || BUILDFLAG(IS_ANDROID)
return false;
#else
return true;
diff --git a/chromium/components/search/search_unittest.cc b/chromium/components/search/search_unittest.cc
index 6d5cf8f2589..d5cac427029 100644
--- a/chromium/components/search/search_unittest.cc
+++ b/chromium/components/search/search_unittest.cc
@@ -9,12 +9,12 @@
namespace search {
-#if !defined(OS_IOS) && !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_IOS) && !BUILDFLAG(IS_ANDROID)
TEST(SearchTest, InstantExtendedAPIEnabled) {
EXPECT_TRUE(IsInstantExtendedAPIEnabled());
}
-#endif // !defined(OS_IOS) && !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_IOS) && !BUILDFLAG(IS_ANDROID)
} // namespace search
diff --git a/chromium/components/search_engines/BUILD.gn b/chromium/components/search_engines/BUILD.gn
index 936d193d15a..88bf47aaea0 100644
--- a/chromium/components/search_engines/BUILD.gn
+++ b/chromium/components/search_engines/BUILD.gn
@@ -69,6 +69,7 @@ static_library("search_engines") {
"//components/history/core/browser",
"//components/infobars/core",
"//components/lens:lens",
+ "//components/omnibox/common",
"//components/policy:generated",
"//components/policy/core/browser",
"//components/pref_registry",
@@ -167,6 +168,7 @@ source_set("unit_tests") {
"//base/test:test_support",
"//components/country_codes",
"//components/google/core/common",
+ "//components/omnibox/common",
"//components/pref_registry:pref_registry",
"//components/prefs",
"//components/sync:test_support",
diff --git a/chromium/components/search_engines/DEPS b/chromium/components/search_engines/DEPS
index 68a433c82e9..aebf926f741 100644
--- a/chromium/components/search_engines/DEPS
+++ b/chromium/components/search_engines/DEPS
@@ -6,6 +6,7 @@ include_rules = [
"+components/infobars/core",
"+components/keyed_service/core",
"+components/lens",
+ "+components/omnibox/common",
"+components/policy",
"+components/pref_registry",
"+components/prefs",
@@ -22,7 +23,7 @@ include_rules = [
"+services/network/public/mojom",
"+services/network/test",
"+sql",
+ "+third_party/metrics_proto",
"+ui/base",
"+ui/gfx",
- "+third_party/metrics_proto",
]
diff --git a/chromium/components/search_engines/android/template_url_service_android.cc b/chromium/components/search_engines/android/template_url_service_android.cc
index f4d2f728354..51f0072fd23 100644
--- a/chromium/components/search_engines/android/template_url_service_android.cc
+++ b/chromium/components/search_engines/android/template_url_service_android.cc
@@ -129,11 +129,7 @@ jboolean TemplateUrlServiceAndroid::DoesDefaultSearchEngineHaveLogo(
jboolean TemplateUrlServiceAndroid::IsDefaultSearchEngineGoogle(
JNIEnv* env,
const JavaParamRef<jobject>& obj) {
- const TemplateURL* default_search_provider =
- template_url_service_->GetDefaultSearchProvider();
- return default_search_provider &&
- default_search_provider->url_ref().HasGoogleBaseURLs(
- template_url_service_->search_terms_data());
+ return IsDefaultSearchEngineGoogle();
}
jboolean
@@ -146,6 +142,14 @@ TemplateUrlServiceAndroid::IsSearchResultsPageFromDefaultSearchProvider(
*url);
}
+bool TemplateUrlServiceAndroid::IsDefaultSearchEngineGoogle() {
+ const TemplateURL* default_search_provider =
+ template_url_service_->GetDefaultSearchProvider();
+ return default_search_provider &&
+ default_search_provider->url_ref().HasGoogleBaseURLs(
+ template_url_service_->search_terms_data());
+}
+
void TemplateUrlServiceAndroid::OnTemplateURLServiceLoaded() {
template_url_subscription_ = {};
JNIEnv* env = base::android::AttachCurrentThread();
@@ -226,7 +230,7 @@ TemplateUrlServiceAndroid::GetUrlForVoiceSearchQuery(
if (!query.empty()) {
GURL gurl(GetDefaultSearchURLForSearchTerms(template_url_service_, query));
- if (google_util::IsGoogleSearchUrl(gurl))
+ if (IsDefaultSearchEngineGoogle())
gurl = net::AppendQueryParameter(gurl, "inm", "vs");
return url::GURLAndroid::FromNativeGURL(env, gurl);
}
@@ -246,7 +250,7 @@ TemplateUrlServiceAndroid::GetUrlForContextualSearchQuery(
if (!query.empty()) {
GURL gurl(GetDefaultSearchURLForSearchTerms(template_url_service_, query));
- if (google_util::IsGoogleSearchUrl(gurl)) {
+ if (IsDefaultSearchEngineGoogle()) {
std::string protocol_version(
base::android::ConvertJavaStringToUTF8(env, jprotocol_version));
gurl = net::AppendQueryParameter(gurl, "ctxs", protocol_version);
diff --git a/chromium/components/search_engines/android/template_url_service_android.h b/chromium/components/search_engines/android/template_url_service_android.h
index e130787574c..b81612d4d52 100644
--- a/chromium/components/search_engines/android/template_url_service_android.h
+++ b/chromium/components/search_engines/android/template_url_service_android.h
@@ -118,6 +118,8 @@ class TemplateUrlServiceAndroid : public TemplateURLServiceObserver {
const base::android::JavaParamRef<jobject>& obj);
private:
+ bool IsDefaultSearchEngineGoogle();
+
void OnTemplateURLServiceLoaded();
// TemplateUrlServiceObserver:
diff --git a/chromium/components/search_engines/default_search_manager.cc b/chromium/components/search_engines/default_search_manager.cc
index 9a7f8b6047a..60211626d6e 100644
--- a/chromium/components/search_engines/default_search_manager.cc
+++ b/chromium/components/search_engines/default_search_manager.cc
@@ -165,10 +165,7 @@ DefaultSearchManager::GetDefaultSearchEngineIgnoringExtensions() const {
const base::Value* user_value =
pref_service_->GetUserPrefValue(kDefaultSearchProviderDataPrefName);
if (user_value && user_value->is_dict()) {
- const base::DictionaryValue* dict_value = nullptr;
- user_value->GetAsDictionary(&dict_value);
- DCHECK(dict_value);
- auto turl_data = TemplateURLDataFromDictionary(*dict_value);
+ auto turl_data = TemplateURLDataFromDictionary(*user_value);
if (turl_data)
return turl_data;
}
@@ -290,7 +287,7 @@ void DefaultSearchManager::LoadDefaultSearchEngineFromPrefs() {
DCHECK(pref);
default_search_controlled_by_policy_ = pref->IsManaged();
- const base::DictionaryValue* url_dict =
+ const base::Value* url_dict =
pref_service_->GetDictionary(kDefaultSearchProviderDataPrefName);
if (url_dict->DictEmpty())
return;
diff --git a/chromium/components/search_engines/default_search_manager_unittest.cc b/chromium/components/search_engines/default_search_manager_unittest.cc
index 5bd571c4a6e..1ead3b8a617 100644
--- a/chromium/components/search_engines/default_search_manager_unittest.cc
+++ b/chromium/components/search_engines/default_search_manager_unittest.cc
@@ -33,30 +33,30 @@ void SetOverrides(sync_preferences::TestingPrefServiceSyncable* prefs,
prefs->SetUserPref(prefs::kSearchProviderOverridesVersion,
std::make_unique<base::Value>(1));
auto overrides = std::make_unique<base::ListValue>();
- auto entry = std::make_unique<base::DictionaryValue>();
-
- entry->SetString("name", update ? "new_foo" : "foo");
- entry->SetString("keyword", update ? "new_fook" : "fook");
- entry->SetString("search_url", "http://foo.com/s?q={searchTerms}");
- entry->SetString("favicon_url", "http://foi.com/favicon.ico");
- entry->SetString("encoding", "UTF-8");
- entry->SetInteger("id", 1001);
- entry->SetString("suggest_url", "http://foo.com/suggest?q={searchTerms}");
+ auto entry = std::make_unique<base::Value>(base::Value::Type::DICTIONARY);
+
+ entry->SetStringKey("name", update ? "new_foo" : "foo");
+ entry->SetStringKey("keyword", update ? "new_fook" : "fook");
+ entry->SetStringKey("search_url", "http://foo.com/s?q={searchTerms}");
+ entry->SetStringKey("favicon_url", "http://foi.com/favicon.ico");
+ entry->SetStringKey("encoding", "UTF-8");
+ entry->SetIntKey("id", 1001);
+ entry->SetStringKey("suggest_url", "http://foo.com/suggest?q={searchTerms}");
base::ListValue alternate_urls;
alternate_urls.Append("http://foo.com/alternate?q={searchTerms}");
entry->SetKey("alternate_urls", std::move(alternate_urls));
overrides->Append(std::move(entry));
- entry = std::make_unique<base::DictionaryValue>();
- entry->SetInteger("id", 1002);
- entry->SetString("name", update ? "new_bar" : "bar");
- entry->SetString("keyword", update ? "new_bark" : "bark");
- entry->SetString("encoding", std::string());
+ entry = std::make_unique<base::Value>(base::Value::Type::DICTIONARY);
+ entry->SetIntKey("id", 1002);
+ entry->SetStringKey("name", update ? "new_bar" : "bar");
+ entry->SetStringKey("keyword", update ? "new_bark" : "bark");
+ entry->SetStringKey("encoding", std::string());
overrides->Append(std::make_unique<base::Value>(entry->Clone()));
- entry->SetInteger("id", 1003);
- entry->SetString("name", "baz");
- entry->SetString("keyword", "bazk");
- entry->SetString("encoding", "UTF-8");
+ entry->SetIntKey("id", 1003);
+ entry->SetStringKey("name", "baz");
+ entry->SetStringKey("keyword", "bazk");
+ entry->SetStringKey("encoding", "UTF-8");
overrides->Append(std::move(entry));
prefs->SetUserPref(prefs::kSearchProviderOverrides, std::move(overrides));
}
@@ -68,9 +68,8 @@ void SetPolicy(sync_preferences::TestingPrefServiceSyncable* prefs,
EXPECT_FALSE(data->keyword().empty());
EXPECT_FALSE(data->url().empty());
}
- std::unique_ptr<base::DictionaryValue> entry(
- TemplateURLDataToDictionary(*data));
- entry->SetBoolean(DefaultSearchManager::kDisabledByPolicy, !enabled);
+ std::unique_ptr<base::Value> entry = TemplateURLDataToDictionary(*data);
+ entry->SetBoolKey(DefaultSearchManager::kDisabledByPolicy, !enabled);
prefs->SetManagedPref(
DefaultSearchManager::kDefaultSearchProviderDataPrefName,
std::move(entry));
diff --git a/chromium/components/search_engines/default_search_policy_handler_unittest.cc b/chromium/components/search_engines/default_search_policy_handler_unittest.cc
index ccc583c957d..a091591ec98 100644
--- a/chromium/components/search_engines/default_search_policy_handler_unittest.cc
+++ b/chromium/components/search_engines/default_search_policy_handler_unittest.cc
@@ -219,11 +219,11 @@ TEST_F(DefaultSearchPolicyHandlerTest, FullyDefined) {
EXPECT_TRUE(
dictionary->GetList(DefaultSearchManager::kInputEncodings, &list_value));
- EXPECT_TRUE(encodings.Equals(list_value));
+ EXPECT_EQ(encodings, *list_value);
EXPECT_TRUE(
dictionary->GetList(DefaultSearchManager::kAlternateURLs, &list_value));
- EXPECT_TRUE(default_alternate_urls_.Equals(list_value));
+ EXPECT_EQ(default_alternate_urls_, *list_value);
EXPECT_TRUE(dictionary->GetString(DefaultSearchManager::kImageURL, &value));
EXPECT_EQ(kImageURL, value);
@@ -316,10 +316,10 @@ TEST_F(DefaultSearchPolicyHandlerTest, MinimallyDefined) {
EXPECT_EQ(std::string(), value);
EXPECT_TRUE(
dictionary->GetList(DefaultSearchManager::kInputEncodings, &list_value));
- EXPECT_TRUE(base::ListValue().Equals(list_value));
+ EXPECT_EQ(base::ListValue(), *list_value);
EXPECT_TRUE(
dictionary->GetList(DefaultSearchManager::kAlternateURLs, &list_value));
- EXPECT_TRUE(base::ListValue().Equals(list_value));
+ EXPECT_EQ(base::ListValue(), *list_value);
EXPECT_TRUE(dictionary->GetString(DefaultSearchManager::kImageURL, &value));
EXPECT_EQ(std::string(), value);
EXPECT_TRUE(
diff --git a/chromium/components/search_engines/keyword_table.cc b/chromium/components/search_engines/keyword_table.cc
index e5aee86d48c..e607ebf8ce3 100644
--- a/chromium/components/search_engines/keyword_table.cc
+++ b/chromium/components/search_engines/keyword_table.cc
@@ -504,7 +504,7 @@ bool KeywordTable::GetKeywordDataFromStatement(sql::Statement& s,
data->alternate_urls.clear();
absl::optional<base::Value> value(base::JSONReader::Read(s.ColumnString(15)));
if (value && value->is_list()) {
- for (const base::Value& alternate_url : value->GetList()) {
+ for (const base::Value& alternate_url : value->GetListDeprecated()) {
if (alternate_url.is_string()) {
data->alternate_urls.push_back(alternate_url.GetString());
}
diff --git a/chromium/components/search_engines/keyword_web_data_service.cc b/chromium/components/search_engines/keyword_web_data_service.cc
index c9e19c394ae..19bed6b750a 100644
--- a/chromium/components/search_engines/keyword_web_data_service.cc
+++ b/chromium/components/search_engines/keyword_web_data_service.cc
@@ -156,7 +156,7 @@ void KeywordWebDataService::AdjustBatchModeLevel(bool entering_batch_mode) {
// When killing an app on Android/iOS, shutdown isn't guaranteed to be
// called. Finishing this task immediately ensures the table is fully
// populated even if the app is killed before the timer expires.
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
CommitQueuedOperations();
#else
timer_.Reset();
diff --git a/chromium/components/search_engines/search_terms_data.cc b/chromium/components/search_engines/search_terms_data.cc
index 52eca7441d8..17224159bdb 100644
--- a/chromium/components/search_engines/search_terms_data.cc
+++ b/chromium/components/search_engines/search_terms_data.cc
@@ -3,12 +3,105 @@
// found in the LICENSE file.
#include "components/search_engines/search_terms_data.h"
+#include <memory>
#include "base/check.h"
+#include "base/trace_event/memory_usage_estimator.h"
+#include "base/trace_event/trace_event.h"
+#include "build/build_config.h"
#include "components/google/core/common/google_util.h"
#include "components/lens/lens_features.h"
#include "url/gurl.h"
+namespace {
+
+// -----------------------------------------------------------------
+// SearchTermsDataSnapshot
+
+// Implementation of SearchTermsData that takes a snapshot of another
+// SearchTermsData by copying all the responses to the different getters into
+// member strings, then returning those strings when its own getters are called.
+// This will typically be constructed on the UI thread from
+// UIThreadSearchTermsData but is subsequently safe to use on any thread.
+class SearchTermsDataSnapshot : public SearchTermsData {
+ public:
+ explicit SearchTermsDataSnapshot(const SearchTermsData* search_terms_data);
+ ~SearchTermsDataSnapshot() override;
+ SearchTermsDataSnapshot(const SearchTermsDataSnapshot&) = delete;
+ SearchTermsDataSnapshot& operator=(const SearchTermsDataSnapshot&) = delete;
+
+ std::string GoogleBaseURLValue() const override;
+ std::string GetApplicationLocale() const override;
+ std::u16string GetRlzParameterValue(bool from_app_list) const override;
+ std::string GetSearchClient() const override;
+ std::string GoogleImageSearchSource() const override;
+
+ // Estimates dynamic memory usage.
+ // See base/trace_event/memory_usage_estimator.h for more info.
+ size_t EstimateMemoryUsage() const override;
+
+ private:
+ std::string google_base_url_value_;
+ std::string application_locale_;
+ std::u16string rlz_parameter_value_;
+ std::string search_client_;
+ std::string google_image_search_source_;
+};
+
+SearchTermsDataSnapshot::SearchTermsDataSnapshot(
+ const SearchTermsData* search_terms_data) {
+ if (search_terms_data) {
+ google_base_url_value_ = search_terms_data->GoogleBaseURLValue();
+ application_locale_ = search_terms_data->GetApplicationLocale();
+ rlz_parameter_value_ = search_terms_data->GetRlzParameterValue(false);
+ search_client_ = search_terms_data->GetSearchClient();
+ google_image_search_source_ = search_terms_data->GoogleImageSearchSource();
+ }
+}
+
+SearchTermsDataSnapshot::~SearchTermsDataSnapshot() = default;
+
+std::string SearchTermsDataSnapshot::GoogleBaseURLValue() const {
+ return google_base_url_value_;
+}
+
+std::string SearchTermsDataSnapshot::GetApplicationLocale() const {
+ return application_locale_;
+}
+
+std::u16string SearchTermsDataSnapshot::GetRlzParameterValue(
+ bool from_app_list) const {
+ return rlz_parameter_value_;
+}
+
+std::string SearchTermsDataSnapshot::GetSearchClient() const {
+ return search_client_;
+}
+
+std::string SearchTermsDataSnapshot::GoogleImageSearchSource() const {
+ return google_image_search_source_;
+}
+
+size_t SearchTermsDataSnapshot::EstimateMemoryUsage() const {
+ size_t res = 0;
+
+ res += base::trace_event::EstimateMemoryUsage(google_base_url_value_);
+ res += base::trace_event::EstimateMemoryUsage(application_locale_);
+ res += base::trace_event::EstimateMemoryUsage(rlz_parameter_value_);
+ res += base::trace_event::EstimateMemoryUsage(search_client_);
+ res += base::trace_event::EstimateMemoryUsage(google_image_search_source_);
+
+ return res;
+}
+
+} // namespace
+
+// static
+std::unique_ptr<SearchTermsData> SearchTermsData::MakeSnapshot(
+ const SearchTermsData* original_data) {
+ return std::make_unique<SearchTermsDataSnapshot>(original_data);
+}
+
SearchTermsData::SearchTermsData() = default;
SearchTermsData::~SearchTermsData() = default;
@@ -20,13 +113,12 @@ std::string SearchTermsData::GoogleBaseURLValue() const {
std::string SearchTermsData::GoogleBaseSearchByImageURLValue() const {
const std::string kGoogleHomepageURLPath = std::string("searchbyimage/");
- // If both LensStandalone and LensRegionSearch features are enabled,
- // LensStandalone parameters will take precedence even if the values differ.
+#if !BUILDFLAG(IS_IOS) && !BUILDFLAG(IS_ANDROID)
if (base::FeatureList::IsEnabled(lens::features::kLensStandalone)) {
- return lens::features::GetHomepageURLForImageSearch();
- } else if (base::FeatureList::IsEnabled(lens::features::kLensRegionSearch)) {
- return lens::features::GetHomepageURLForRegionSearch();
+ return lens::features::GetHomepageURLForLens();
}
+#endif // !BUILDFLAG(IS_IOS) && !BUILDFLAG(IS_ANDROID)
+
return google_util::kGoogleHomepageURL + kGoogleHomepageURLPath;
}
diff --git a/chromium/components/search_engines/search_terms_data.h b/chromium/components/search_engines/search_terms_data.h
index d28687e4232..fe1cdd69246 100644
--- a/chromium/components/search_engines/search_terms_data.h
+++ b/chromium/components/search_engines/search_terms_data.h
@@ -5,6 +5,7 @@
#ifndef COMPONENTS_SEARCH_ENGINES_SEARCH_TERMS_DATA_H_
#define COMPONENTS_SEARCH_ENGINES_SEARCH_TERMS_DATA_H_
+#include <memory>
#include <string>
#include "base/compiler_specific.h"
@@ -13,6 +14,12 @@
// only be accessed on the UI thread.
class SearchTermsData {
public:
+ // Utility function that takes a snapshot of a different SearchTermsData
+ // instance. This is used to access SearchTermsData off the UI thread, or to
+ // copy the SearchTermsData for lifetime reasons.
+ static std::unique_ptr<SearchTermsData> MakeSnapshot(
+ const SearchTermsData* original_data);
+
SearchTermsData();
SearchTermsData(const SearchTermsData&) = delete;
diff --git a/chromium/components/search_engines/template_url.cc b/chromium/components/search_engines/template_url.cc
index 36e25919ace..567dc1b8dff 100644
--- a/chromium/components/search_engines/template_url.cc
+++ b/chromium/components/search_engines/template_url.cc
@@ -11,7 +11,9 @@
#include "base/base64.h"
#include "base/check_op.h"
#include "base/command_line.h"
+#include "base/containers/adapters.h"
#include "base/containers/contains.h"
+#include "base/feature_list.h"
#include "base/format_macros.h"
#include "base/i18n/case_conversion.h"
#include "base/i18n/icu_string_conversions.h"
@@ -27,6 +29,7 @@
#include "base/trace_event/memory_usage_estimator.h"
#include "build/build_config.h"
#include "components/google/core/common/google_util.h"
+#include "components/omnibox/common/omnibox_features.h"
#include "components/search_engines/search_engine_utils.h"
#include "components/search_engines/search_engines_switches.h"
#include "components/search_engines/search_terms_data.h"
@@ -734,7 +737,7 @@ bool TemplateURLRef::ParseParameter(size_t start,
} else if (parameter == "google:sessionToken") {
replacements->push_back(Replacement(GOOGLE_SESSION_TOKEN, start));
} else if (parameter == "google:sourceId") {
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
url->insert(start, "sourceid=chrome-mobile&");
#else
url->insert(start, "sourceid=chrome&");
@@ -990,10 +993,10 @@ std::string TemplateURLRef::HandleReplacements(
// replacements_ is ordered in ascending order, as such we need to iterate
// from the back.
- for (auto i = replacements_.rbegin(); i != replacements_.rend(); ++i) {
- switch (i->type) {
+ for (const Replacement& replacement : base::Reversed(replacements_)) {
+ switch (replacement.type) {
case ENCODING:
- HandleReplacement(std::string(), input_encoding, *i, &url);
+ HandleReplacement(std::string(), input_encoding, replacement, &url);
break;
case GOOGLE_CONTEXTUAL_SEARCH_VERSION:
@@ -1002,12 +1005,12 @@ std::string TemplateURLRef::HandleReplacements(
"ctxs",
base::NumberToString(
search_terms_args.contextual_search_params.version),
- *i, &url);
+ replacement, &url);
}
break;
case GOOGLE_CONTEXTUAL_SEARCH_CONTEXT_DATA: {
- DCHECK(!i->is_post_param);
+ DCHECK(!replacement.is_post_param);
const SearchTermsArgs::ContextualSearchParams& params =
search_terms_args.contextual_search_params;
@@ -1038,12 +1041,13 @@ std::string TemplateURLRef::HandleReplacements(
if (!params.related_searches_stamp.empty())
args.push_back("ctxsl_rs=" + params.related_searches_stamp);
- HandleReplacement(std::string(), base::JoinString(args, "&"), *i, &url);
+ HandleReplacement(std::string(), base::JoinString(args, "&"),
+ replacement, &url);
break;
}
case GOOGLE_ASSISTED_QUERY_STATS:
- DCHECK(!i->is_post_param);
+ DCHECK(!replacement.is_post_param);
if (!search_terms_args.assisted_query_stats.empty()) {
// Get the base URL without substituting AQS to avoid infinite
// recursion. We need the URL to find out if it meets all
@@ -1054,85 +1058,85 @@ std::string TemplateURLRef::HandleReplacements(
GURL base_url(ReplaceSearchTerms(search_terms_args_without_aqs,
search_terms_data, nullptr));
if (base_url.SchemeIsCryptographic()) {
- HandleReplacement(
- "aqs", search_terms_args.assisted_query_stats, *i, &url);
+ HandleReplacement("aqs", search_terms_args.assisted_query_stats,
+ replacement, &url);
}
}
break;
case GOOGLE_BASE_URL:
- DCHECK(!i->is_post_param);
- HandleReplacement(
- std::string(), search_terms_data.GoogleBaseURLValue(), *i, &url);
+ DCHECK(!replacement.is_post_param);
+ HandleReplacement(std::string(), search_terms_data.GoogleBaseURLValue(),
+ replacement, &url);
break;
case GOOGLE_BASE_SEARCH_BY_IMAGE_URL:
- DCHECK(!i->is_post_param);
+ DCHECK(!replacement.is_post_param);
HandleReplacement(std::string(),
search_terms_data.GoogleBaseSearchByImageURLValue(),
- *i, &url);
+ replacement, &url);
break;
case GOOGLE_BASE_SUGGEST_URL:
- DCHECK(!i->is_post_param);
- HandleReplacement(
- std::string(), search_terms_data.GoogleBaseSuggestURLValue(), *i,
- &url);
+ DCHECK(!replacement.is_post_param);
+ HandleReplacement(std::string(),
+ search_terms_data.GoogleBaseSuggestURLValue(),
+ replacement, &url);
break;
case GOOGLE_CURRENT_PAGE_URL:
- DCHECK(!i->is_post_param);
+ DCHECK(!replacement.is_post_param);
if (!search_terms_args.current_page_url.empty()) {
const std::string& escaped_current_page_url =
net::EscapeQueryParamValue(search_terms_args.current_page_url,
true);
- HandleReplacement("url", escaped_current_page_url, *i, &url);
+ HandleReplacement("url", escaped_current_page_url, replacement, &url);
}
break;
case GOOGLE_CURSOR_POSITION:
- DCHECK(!i->is_post_param);
+ DCHECK(!replacement.is_post_param);
if (search_terms_args.cursor_position != std::u16string::npos)
HandleReplacement(
"cp",
base::StringPrintf("%" PRIuS, search_terms_args.cursor_position),
- *i,
- &url);
+ replacement, &url);
break;
case GOOGLE_INPUT_TYPE:
- DCHECK(!i->is_post_param);
+ DCHECK(!replacement.is_post_param);
HandleReplacement("oit",
base::NumberToString(search_terms_args.input_type),
- *i, &url);
+ replacement, &url);
break;
case GOOGLE_OMNIBOX_FOCUS_TYPE:
- DCHECK(!i->is_post_param);
+ DCHECK(!replacement.is_post_param);
if (search_terms_args.focus_type != OmniboxFocusType::DEFAULT) {
HandleReplacement("oft",
base::NumberToString(
static_cast<int>(search_terms_args.focus_type)),
- *i, &url);
+ replacement, &url);
}
break;
case GOOGLE_ORIGINAL_QUERY_FOR_SUGGESTION:
- DCHECK(!i->is_post_param);
+ DCHECK(!replacement.is_post_param);
if (search_terms_args.accepted_suggestion >= 0 ||
!search_terms_args.assisted_query_stats.empty()) {
- HandleReplacement(
- "oq", base::UTF16ToUTF8(encoded_original_query), *i, &url);
+ HandleReplacement("oq", base::UTF16ToUTF8(encoded_original_query),
+ replacement, &url);
}
break;
case GOOGLE_PAGE_CLASSIFICATION:
if (search_terms_args.page_classification !=
- metrics::OmniboxEventProto::INVALID_SPEC) {
+ metrics::OmniboxEventProto::INVALID_SPEC &&
+ !base::FeatureList::IsEnabled(omnibox::kZeroSuggestPrefetching)) {
HandleReplacement(
"pgcl",
- base::NumberToString(search_terms_args.page_classification), *i,
- &url);
+ base::NumberToString(search_terms_args.page_classification),
+ replacement, &url);
}
break;
@@ -1143,7 +1147,7 @@ std::string TemplateURLRef::HandleReplacements(
"ccttl",
base::NumberToString(
search_terms_args.zero_suggest_cache_duration_sec),
- *i, &url);
+ replacement, &url);
}
break;
@@ -1151,8 +1155,9 @@ std::string TemplateURLRef::HandleReplacements(
const std::string& query = search_terms_args.prefetch_query;
const std::string& type = search_terms_args.prefetch_query_type;
if (!query.empty() && !type.empty()) {
- HandleReplacement(
- std::string(), "pfq=" + query + "&qha=" + type + "&", *i, &url);
+ HandleReplacement(std::string(),
+ "pfq=" + query + "&qha=" + type + "&", replacement,
+ &url);
}
break;
}
@@ -1165,13 +1170,13 @@ std::string TemplateURLRef::HandleReplacements(
// prefetch to allow the search server to treat the requests based on
// source. "cs" represents Chrome Suggestions as the source. Adding a
// new source should be supported by the Search engine.
- HandleReplacement("pf", "cs", *i, &url);
+ HandleReplacement("pf", "cs", replacement, &url);
}
break;
}
case GOOGLE_RLZ: {
- DCHECK(!i->is_post_param);
+ DCHECK(!replacement.is_post_param);
// On platforms that don't have RLZ, we still want this branch
// to happen so that we replace the RLZ template with the
// empty string. (If we don't handle this case, we hit a
@@ -1179,45 +1184,46 @@ std::string TemplateURLRef::HandleReplacements(
std::u16string rlz_string = search_terms_data.GetRlzParameterValue(
search_terms_args.request_source == CROS_APP_LIST);
if (!rlz_string.empty()) {
- HandleReplacement("rlz", base::UTF16ToUTF8(rlz_string), *i, &url);
+ HandleReplacement("rlz", base::UTF16ToUTF8(rlz_string), replacement,
+ &url);
}
break;
}
case GOOGLE_SEARCH_CLIENT: {
- DCHECK(!i->is_post_param);
+ DCHECK(!replacement.is_post_param);
std::string client = search_terms_data.GetSearchClient();
if (!client.empty())
- HandleReplacement("client", client, *i, &url);
+ HandleReplacement("client", client, replacement, &url);
break;
}
case GOOGLE_SEARCH_FIELDTRIAL_GROUP:
// We are not currently running any fieldtrials that modulate the search
// url. If we do, then we'd have some conditional insert such as:
- // url.insert(i->index, used_www ? "gcx=w&" : "gcx=c&");
+ // url.insert(replacement.index, used_www ? "gcx=w&" : "gcx=c&");
break;
case GOOGLE_SEARCH_VERSION:
- HandleReplacement("gs_rn", "42", *i, &url);
+ HandleReplacement("gs_rn", "42", replacement, &url);
break;
case GOOGLE_SESSION_TOKEN: {
std::string token = search_terms_args.session_token;
if (!token.empty())
- HandleReplacement("psi", token, *i, &url);
+ HandleReplacement("psi", token, replacement, &url);
break;
}
case GOOGLE_SUGGEST_CLIENT:
HandleReplacement(std::string(), search_terms_data.GetSuggestClient(),
- *i, &url);
+ replacement, &url);
break;
case GOOGLE_SUGGEST_REQUEST_ID:
- HandleReplacement(
- std::string(), search_terms_data.GetSuggestRequestIdentifier(), *i,
- &url);
+ HandleReplacement(std::string(),
+ search_terms_data.GetSuggestRequestIdentifier(),
+ replacement, &url);
break;
case GOOGLE_UNESCAPED_SEARCH_TERMS: {
@@ -1226,41 +1232,44 @@ std::string TemplateURLRef::HandleReplacements(
input_encoding.c_str(),
base::OnStringConversionError::SKIP,
&unescaped_terms);
- HandleReplacement(std::string(), unescaped_terms, *i, &url);
+ HandleReplacement(std::string(), unescaped_terms, replacement, &url);
break;
}
case LANGUAGE:
- HandleReplacement(
- std::string(), search_terms_data.GetApplicationLocale(), *i, &url);
+ HandleReplacement(std::string(),
+ search_terms_data.GetApplicationLocale(), replacement,
+ &url);
break;
case SEARCH_TERMS:
- HandleReplacement(
- std::string(), base::UTF16ToUTF8(encoded_terms), *i, &url);
+ HandleReplacement(std::string(), base::UTF16ToUTF8(encoded_terms),
+ replacement, &url);
break;
case GOOGLE_IMAGE_THUMBNAIL:
- HandleReplacement(
- std::string(), search_terms_args.image_thumbnail_content, *i, &url);
- if (i->is_post_param)
- post_params_[i->index].content_type = "image/jpeg";
+ HandleReplacement(std::string(),
+ search_terms_args.image_thumbnail_content,
+ replacement, &url);
+ if (replacement.is_post_param)
+ post_params_[replacement.index].content_type = "image/jpeg";
break;
case GOOGLE_IMAGE_THUMBNAIL_BASE64: {
std::string base64_thumbnail_content;
base::Base64Encode(search_terms_args.image_thumbnail_content,
&base64_thumbnail_content);
- HandleReplacement(std::string(), base64_thumbnail_content, *i, &url);
- if (i->is_post_param)
- post_params_[i->index].content_type = "image/jpeg";
+ HandleReplacement(std::string(), base64_thumbnail_content, replacement,
+ &url);
+ if (replacement.is_post_param)
+ post_params_[replacement.index].content_type = "image/jpeg";
break;
}
case GOOGLE_IMAGE_URL:
if (search_terms_args.image_url.is_valid()) {
- HandleReplacement(
- std::string(), search_terms_args.image_url.spec(), *i, &url);
+ HandleReplacement(std::string(), search_terms_args.image_url.spec(),
+ replacement, &url);
}
break;
@@ -1269,7 +1278,7 @@ std::string TemplateURLRef::HandleReplacements(
HandleReplacement(std::string(),
base::NumberToString(
search_terms_args.image_original_size.width()),
- *i, &url);
+ replacement, &url);
}
break;
@@ -1278,34 +1287,34 @@ std::string TemplateURLRef::HandleReplacements(
HandleReplacement(std::string(),
base::NumberToString(
search_terms_args.image_original_size.height()),
- *i, &url);
+ replacement, &url);
}
break;
case GOOGLE_IMAGE_SEARCH_SOURCE:
- HandleReplacement(
- std::string(), search_terms_data.GoogleImageSearchSource(), *i,
- &url);
+ HandleReplacement(std::string(),
+ search_terms_data.GoogleImageSearchSource(),
+ replacement, &url);
break;
case GOOGLE_IOS_SEARCH_LANGUAGE:
-#if defined(OS_IOS)
- HandleReplacement("hl", search_terms_data.GetApplicationLocale(), *i,
- &url);
+#if BUILDFLAG(IS_IOS)
+ HandleReplacement("hl", search_terms_data.GetApplicationLocale(),
+ replacement, &url);
#endif
break;
case YANDEX_REFERRAL_ID: {
std::string referral_id = search_terms_data.GetYandexReferralID();
if (!referral_id.empty())
- HandleReplacement("clid", referral_id, *i, &url);
+ HandleReplacement("clid", referral_id, replacement, &url);
break;
}
case MAIL_RU_REFERRAL_ID: {
std::string referral_id = search_terms_data.GetMailRUReferralID();
if (!referral_id.empty())
- HandleReplacement("gp", referral_id, *i, &url);
+ HandleReplacement("gp", referral_id, replacement, &url);
break;
}
diff --git a/chromium/components/search_engines/template_url.h b/chromium/components/search_engines/template_url.h
index f2cd0aef7dc..d501cf9e440 100644
--- a/chromium/components/search_engines/template_url.h
+++ b/chromium/components/search_engines/template_url.h
@@ -257,6 +257,10 @@ class TemplateURLRef {
// The cache duration to be sent as a query string parameter in the zero
// suggest requests, if non-zero.
uint32_t zero_suggest_cache_duration_sec = 0;
+
+ // Whether the request should bypass the HTTP cache, i.e., a "shift-reload".
+ // If true, the net::LOAD_BYPASS_CACHE load flag will be set on the request.
+ bool bypass_cache = false;
};
TemplateURLRef(const TemplateURL* owner, Type type);
diff --git a/chromium/components/search_engines/template_url_data.cc b/chromium/components/search_engines/template_url_data.cc
index f0f131ff84e..4d10e7ab765 100644
--- a/chromium/components/search_engines/template_url_data.cc
+++ b/chromium/components/search_engines/template_url_data.cc
@@ -95,7 +95,7 @@ TemplateURLData::TemplateURLData(const std::u16string& name,
SetURL(std::string(search_url));
input_encodings.push_back(std::string(encoding));
if (alternate_urls_list.is_list()) {
- auto alternate_urls_list_view = alternate_urls_list.GetList();
+ auto alternate_urls_list_view = alternate_urls_list.GetListDeprecated();
for (size_t i = 0; i < alternate_urls_list_view.size(); ++i) {
const std::string* alternate_url =
alternate_urls_list_view[i].GetIfString();
diff --git a/chromium/components/search_engines/template_url_data_util.cc b/chromium/components/search_engines/template_url_data_util.cc
index 7373dedf290..d8f2177d9ff 100644
--- a/chromium/components/search_engines/template_url_data_util.cc
+++ b/chromium/components/search_engines/template_url_data_util.cc
@@ -26,7 +26,7 @@ base::StringPiece ToStringPiece(const char* str) {
} // namespace
std::unique_ptr<TemplateURLData> TemplateURLDataFromDictionary(
- const base::DictionaryValue& dict) {
+ const base::Value& dict) {
const std::string* search_url =
dict.FindStringKey(DefaultSearchManager::kURL);
const std::string* keyword =
@@ -144,17 +144,19 @@ std::unique_ptr<TemplateURLData> TemplateURLDataFromDictionary(
result->usage_count = dict.FindIntKey(DefaultSearchManager::kUsageCount)
.value_or(result->usage_count);
- const base::ListValue* alternate_urls = nullptr;
- if (dict.GetList(DefaultSearchManager::kAlternateURLs, &alternate_urls)) {
- for (const auto& it : alternate_urls->GetList()) {
+ const base::Value* alternate_urls =
+ dict.FindListKey(DefaultSearchManager::kAlternateURLs);
+ if (alternate_urls) {
+ for (const auto& it : alternate_urls->GetListDeprecated()) {
if (it.is_string())
result->alternate_urls.push_back(it.GetString());
}
}
- const base::ListValue* encodings = nullptr;
- if (dict.GetList(DefaultSearchManager::kInputEncodings, &encodings)) {
- for (const auto& it : encodings->GetList()) {
+ const base::Value* encodings =
+ dict.FindListKey(DefaultSearchManager::kInputEncodings);
+ if (encodings) {
+ for (const auto& it : encodings->GetListDeprecated()) {
std::string encoding;
if (it.is_string())
result->input_encodings.push_back(it.GetString());
diff --git a/chromium/components/search_engines/template_url_data_util.h b/chromium/components/search_engines/template_url_data_util.h
index 50a098c5522..ca1016612e6 100644
--- a/chromium/components/search_engines/template_url_data_util.h
+++ b/chromium/components/search_engines/template_url_data_util.h
@@ -20,7 +20,7 @@ struct TemplateURLData;
// Deserializes a TemplateURLData from |dict|.
std::unique_ptr<TemplateURLData> TemplateURLDataFromDictionary(
- const base::DictionaryValue& dict);
+ const base::Value& dict);
// Serializes a TemplateURLData to |dict|.
std::unique_ptr<base::DictionaryValue> TemplateURLDataToDictionary(
diff --git a/chromium/components/search_engines/template_url_parser.cc b/chromium/components/search_engines/template_url_parser.cc
index 8829a7016c3..8d38add1aa9 100644
--- a/chromium/components/search_engines/template_url_parser.cc
+++ b/chromium/components/search_engines/template_url_parser.cc
@@ -11,7 +11,6 @@
#include "base/bind.h"
#include "base/logging.h"
-#include "base/memory/raw_ptr.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
@@ -111,7 +110,7 @@ class SafeTemplateURLParser {
const SearchTermsData* search_terms_data,
const TemplateURLParser::ParameterFilter& parameter_filter,
TemplateURLParser::ParseCallback callback)
- : search_terms_data_(search_terms_data),
+ : search_terms_data_(SearchTermsData::MakeSnapshot(search_terms_data)),
parameter_filter_(parameter_filter),
callback_(std::move(callback)) {}
@@ -158,7 +157,10 @@ class SafeTemplateURLParser {
// at least one element, if only the empty string.
std::vector<std::string> namespaces_;
- raw_ptr<const SearchTermsData> search_terms_data_;
+ // We have to own our own snapshot, because the parse request may outlive the
+ // originally provided SearchTermsData lifetime.
+ std::unique_ptr<SearchTermsData> search_terms_data_;
+
TemplateURLParser::ParameterFilter parameter_filter_;
TemplateURLParser::ParseCallback callback_;
};
@@ -432,8 +434,9 @@ void TemplateURLParser::Parse(const SearchTermsData* search_terms_data,
auto safe_parser = std::make_unique<SafeTemplateURLParser>(
search_terms_data, parameter_filter, std::move(completion_callback));
data_decoder::DataDecoder::ParseXmlIsolated(
- data, base::BindOnce(&SafeTemplateURLParser::OnXmlParseComplete,
- std::move(safe_parser)));
+ data, data_decoder::mojom::XmlParser::WhitespaceBehavior::kIgnore,
+ base::BindOnce(&SafeTemplateURLParser::OnXmlParseComplete,
+ std::move(safe_parser)));
}
// static
@@ -446,6 +449,7 @@ void TemplateURLParser::ParseWithDataDecoder(
auto safe_parser = std::make_unique<SafeTemplateURLParser>(
search_terms_data, parameter_filter, std::move(completion_callback));
data_decoder->ParseXml(
- data, base::BindOnce(&SafeTemplateURLParser::OnXmlParseComplete,
- std::move(safe_parser)));
+ data, data_decoder::mojom::XmlParser::WhitespaceBehavior::kIgnore,
+ base::BindOnce(&SafeTemplateURLParser::OnXmlParseComplete,
+ std::move(safe_parser)));
}
diff --git a/chromium/components/search_engines/template_url_prepopulate_data.cc b/chromium/components/search_engines/template_url_prepopulate_data.cc
index c9c393401e5..2fc0c051271 100644
--- a/chromium/components/search_engines/template_url_prepopulate_data.cc
+++ b/chromium/components/search_engines/template_url_prepopulate_data.cc
@@ -1165,7 +1165,7 @@ std::vector<std::unique_ptr<TemplateURLData>> GetPrepopulationSetFromCountryID(
UNHANDLED_COUNTRY(G, N) // Guinea
UNHANDLED_COUNTRY(G, P) // Guadeloupe
UNHANDLED_COUNTRY(H, T) // Haiti
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
UNHANDLED_COUNTRY(I, P) // Clipperton Island ('IP' is an WinXP-ism; ISO
// includes it with France)
#endif
@@ -1340,11 +1340,11 @@ std::vector<std::unique_ptr<TemplateURLData>> GetPrepopulatedTemplateURLData(
if (!prefs)
return t_urls;
- const base::ListValue* list = prefs->GetList(prefs::kSearchProviderOverrides);
+ const base::Value* list = prefs->GetList(prefs::kSearchProviderOverrides);
if (!list)
return t_urls;
- for (const base::Value& engine : list->GetList()) {
+ for (const base::Value& engine : list->GetListDeprecated()) {
if (engine.is_dict()) {
auto t_url = TemplateURLDataFromOverrideDictionary(engine);
if (t_url)
@@ -1403,7 +1403,7 @@ std::unique_ptr<TemplateURLData> GetPrepopulatedEngine(PrefService* prefs,
return nullptr;
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
std::vector<std::unique_ptr<TemplateURLData>> GetLocalPrepopulatedEngines(
const std::string& locale) {
diff --git a/chromium/components/search_engines/template_url_prepopulate_data.h b/chromium/components/search_engines/template_url_prepopulate_data.h
index 74c3404d2b6..a5ee3f871bf 100644
--- a/chromium/components/search_engines/template_url_prepopulate_data.h
+++ b/chromium/components/search_engines/template_url_prepopulate_data.h
@@ -44,7 +44,7 @@ std::vector<std::unique_ptr<TemplateURLData>> GetPrepopulatedEngines(
std::unique_ptr<TemplateURLData> GetPrepopulatedEngine(PrefService* prefs,
int prepopulated_id);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Returns the prepopulated URLs associated with |locale|. |locale| should be a
// two-character uppercase ISO 3166-1 country code.
std::vector<std::unique_ptr<TemplateURLData>> GetLocalPrepopulatedEngines(
diff --git a/chromium/components/search_engines/template_url_service.cc b/chromium/components/search_engines/template_url_service.cc
index a31f2b81349..18bf8acac4c 100644
--- a/chromium/components/search_engines/template_url_service.cc
+++ b/chromium/components/search_engines/template_url_service.cc
@@ -22,6 +22,7 @@
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/pref_service.h"
#include "components/search_engines/search_engines_pref_names.h"
@@ -40,7 +41,7 @@
#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
#include "url/gurl.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "components/search_engines/android/template_url_service_android.h"
#endif
@@ -319,7 +320,7 @@ void TemplateURLService::LogSearchTemplateURLEvent(
// static
void TemplateURLService::RegisterProfilePrefs(
user_prefs::PrefRegistrySyncable* registry) {
-#if defined(OS_IOS) || defined(OS_ANDROID)
+#if BUILDFLAG(IS_IOS) || BUILDFLAG(IS_ANDROID)
uint32_t flags = PrefRegistry::NO_REGISTRATION_FLAGS;
#else
uint32_t flags = user_prefs::PrefRegistrySyncable::SYNCABLE_PREF;
@@ -332,7 +333,7 @@ void TemplateURLService::RegisterProfilePrefs(
prefs::kDefaultSearchProviderContextMenuAccessAllowed, true);
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
base::android::ScopedJavaLocalRef<jobject> TemplateURLService::GetJavaObject() {
if (!template_url_service_android_) {
template_url_service_android_ =
diff --git a/chromium/components/search_engines/template_url_service.h b/chromium/components/search_engines/template_url_service.h
index 10d0543ab91..7f67b9ff5be 100644
--- a/chromium/components/search_engines/template_url_service.h
+++ b/chromium/components/search_engines/template_url_service.h
@@ -33,7 +33,7 @@
#include "components/sync/model/syncable_service.h"
#include "components/sync/protocol/search_engine_specifics.pb.h"
#include "components/webdata/common/web_data_service_consumer.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "base/android/scoped_java_ref.h"
#endif
@@ -42,7 +42,7 @@ class PrefService;
class TemplateURLServiceClient;
class TemplateURLServiceObserver;
struct TemplateURLData;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
class TemplateUrlServiceAndroid;
#endif
@@ -139,7 +139,7 @@ class TemplateURLService : public WebDataServiceConsumer,
// Register Profile preferences in |registry|.
static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
base::android::ScopedJavaLocalRef<jobject> GetJavaObject();
#endif
@@ -830,7 +830,7 @@ class TemplateURLService : public WebDataServiceConsumer,
std::string current_token_;
base::TimeTicks token_expiration_time_;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Manage and fetch the java object that wraps this TemplateURLService on
// android.
std::unique_ptr<TemplateUrlServiceAndroid> template_url_service_android_;
diff --git a/chromium/components/search_engines/template_url_service_unittest.cc b/chromium/components/search_engines/template_url_service_unittest.cc
index d9252a2df17..8cb8da33e9b 100644
--- a/chromium/components/search_engines/template_url_service_unittest.cc
+++ b/chromium/components/search_engines/template_url_service_unittest.cc
@@ -2,11 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "components/search_engines/template_url_service.h"
+
#include <stddef.h>
#include <memory>
-#include "components/search_engines/template_url_service.h"
+#include "base/threading/platform_thread.h"
#include "testing/gtest/include/gtest/gtest.h"
class TemplateURLServiceUnitTest : public testing::Test {
diff --git a/chromium/components/search_engines/template_url_unittest.cc b/chromium/components/search_engines/template_url_unittest.cc
index 109f13f5cc5..89f642524d5 100644
--- a/chromium/components/search_engines/template_url_unittest.cc
+++ b/chromium/components/search_engines/template_url_unittest.cc
@@ -8,11 +8,13 @@
#include "base/base_paths.h"
#include "base/command_line.h"
#include "base/cxx17_backports.h"
+#include "base/feature_list.h"
#include "base/i18n/case_conversion.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "components/google/core/common/google_util.h"
+#include "components/omnibox/common/omnibox_features.h"
#include "components/search_engines/search_engines_switches.h"
#include "components/search_engines/search_terms_data.h"
#include "components/search_engines/template_url.h"
@@ -1719,13 +1721,19 @@ TEST_F(TemplateURLTest, ReplacePageClassification) {
search_terms_args.page_classification = metrics::OmniboxEventProto::NTP;
result = url.url_ref().ReplaceSearchTerms(search_terms_args,
search_terms_data_);
- EXPECT_EQ("http://www.google.com/?pgcl=1&q=foo", result);
+ EXPECT_EQ(base::FeatureList::IsEnabled(omnibox::kZeroSuggestPrefetching)
+ ? "http://www.google.com/?q=foo"
+ : "http://www.google.com/?pgcl=1&q=foo",
+ result);
search_terms_args.page_classification =
metrics::OmniboxEventProto::HOME_PAGE;
result = url.url_ref().ReplaceSearchTerms(search_terms_args,
search_terms_data_);
- EXPECT_EQ("http://www.google.com/?pgcl=3&q=foo", result);
+ EXPECT_EQ(base::FeatureList::IsEnabled(omnibox::kZeroSuggestPrefetching)
+ ? "http://www.google.com/?q=foo"
+ : "http://www.google.com/?pgcl=3&q=foo",
+ result);
}
// Test the IsSearchResults function.
diff --git a/chromium/components/search_provider_logos/google_logo_api.cc b/chromium/components/search_provider_logos/google_logo_api.cc
index f9d61c94e57..8e2cee5a42a 100644
--- a/chromium/components/search_provider_logos/google_logo_api.cc
+++ b/chromium/components/search_provider_logos/google_logo_api.cc
@@ -12,6 +12,7 @@
#include "base/base64.h"
#include "base/bind.h"
#include "base/callback.h"
+#include "base/check.h"
#include "base/command_line.h"
#include "base/feature_list.h"
#include "base/json/json_reader.h"
@@ -76,14 +77,15 @@ GURL AppendPreliminaryParamsToDoodleURL(bool gray_background,
namespace {
const char kResponsePreamble[] = ")]}'";
-GURL ParseUrl(const base::DictionaryValue& parent_dict,
+GURL ParseUrl(const base::Value& parent_dict,
const std::string& key,
const GURL& base_url) {
- std::string url_str;
- if (!parent_dict.GetString(key, &url_str) || url_str.empty()) {
+ DCHECK(parent_dict.is_dict());
+ const std::string* url_str = parent_dict.FindStringKey(key);
+ if (!url_str || url_str->empty()) {
return GURL();
}
- GURL result = base_url.Resolve(url_str);
+ GURL result = base_url.Resolve(*url_str);
// If the base URL is https:// (which should almost always be the case, see
// above), then we require all other URLs to be https:// too.
if (base_url.SchemeIs(url::kHttpsScheme) &&
@@ -159,13 +161,11 @@ std::unique_ptr<EncodedLogo> ParseDoodleLogoResponse(
return nullptr;
}
- std::unique_ptr<base::DictionaryValue> config = base::DictionaryValue::From(
- base::Value::ToUniquePtrValue(std::move(*parsed_json.value)));
- if (!config)
+ if (!parsed_json.value->is_dict())
return nullptr;
- const base::DictionaryValue* ddljson = nullptr;
- if (!config->GetDictionary("ddljson", &ddljson))
+ const base::Value* ddljson = parsed_json.value->FindDictKey("ddljson");
+ if (!ddljson)
return nullptr;
// If there is no logo today, the "ddljson" dictionary will be empty.
@@ -176,14 +176,14 @@ std::unique_ptr<EncodedLogo> ParseDoodleLogoResponse(
auto logo = std::make_unique<EncodedLogo>();
- std::string doodle_type;
+ const std::string* doodle_type = ddljson->FindStringKey("doodle_type");
logo->metadata.type = LogoType::SIMPLE;
- if (ddljson->GetString("doodle_type", &doodle_type)) {
- if (doodle_type == "ANIMATED") {
+ if (doodle_type) {
+ if (*doodle_type == "ANIMATED") {
logo->metadata.type = LogoType::ANIMATED;
- } else if (doodle_type == "INTERACTIVE") {
+ } else if (*doodle_type == "INTERACTIVE") {
logo->metadata.type = LogoType::INTERACTIVE;
- } else if (doodle_type == "VIDEO") {
+ } else if (*doodle_type == "VIDEO") {
logo->metadata.type = LogoType::INTERACTIVE;
}
}
@@ -195,30 +195,37 @@ std::unique_ptr<EncodedLogo> ParseDoodleLogoResponse(
// Check if the main image is animated.
if (is_animated) {
// If animated, get the URL for the animated image.
- const base::DictionaryValue* image = nullptr;
- if (!ddljson->GetDictionary("large_image", &image))
+ const base::Value* image = ddljson->FindDictKey("large_image");
+ if (!image)
return nullptr;
logo->metadata.animated_url = ParseUrl(*image, "url", base_url);
if (!logo->metadata.animated_url.is_valid())
return nullptr;
- const base::DictionaryValue* dark_image = nullptr;
- if (ddljson->GetDictionary("dark_large_image", &dark_image))
+ const base::Value* dark_image = ddljson->FindDictKey("dark_large_image");
+ if (dark_image)
logo->metadata.dark_animated_url = ParseUrl(*dark_image, "url", base_url);
}
if (is_simple || is_animated) {
- const base::DictionaryValue* image = nullptr;
- if (ddljson->GetDictionary("large_image", &image)) {
- image->GetInteger("width", &logo->metadata.width_px);
- image->GetInteger("height", &logo->metadata.height_px);
+ const base::Value* image = ddljson->FindDictKey("large_image");
+ if (image) {
+ if (absl::optional<int> width_px = image->FindIntKey("width"))
+ logo->metadata.width_px = *width_px;
+ if (absl::optional<int> height_px = image->FindIntKey("height"))
+ logo->metadata.height_px = *height_px;
}
- const base::DictionaryValue* dark_image = nullptr;
- if (ddljson->GetDictionary("dark_large_image", &dark_image)) {
- dark_image->GetString("background_color",
- &logo->metadata.dark_background_color);
- dark_image->GetInteger("width", &logo->metadata.dark_width_px);
- dark_image->GetInteger("height", &logo->metadata.dark_height_px);
+
+ const base::Value* dark_image = ddljson->FindDictKey("dark_large_image");
+ if (dark_image) {
+ if (const std::string* background_color =
+ dark_image->FindStringKey("background_color")) {
+ logo->metadata.dark_background_color = *background_color;
+ }
+ if (absl::optional<int> width_px = dark_image->FindIntKey("width"))
+ logo->metadata.dark_width_px = *width_px;
+ if (absl::optional<int> height_px = dark_image->FindIntKey("height"))
+ logo->metadata.dark_height_px = *height_px;
}
}
@@ -227,44 +234,56 @@ std::unique_ptr<EncodedLogo> ParseDoodleLogoResponse(
logo->metadata.type == LogoType::SIMPLE);
if (is_eligible_for_share_button) {
- const base::DictionaryValue* share_button = nullptr;
- std::string short_link_str;
+ const base::Value* share_button = ddljson->FindDictKey("share_button");
+ const std::string* short_link_ptr = ddljson->FindStringKey("short_link");
// The short link in the doodle proto is an incomplete URL with the format
// //g.co/*, //doodle.gle/* or //google.com?doodle=*.
// Complete the URL if possible.
- if (ddljson->GetDictionary("share_button", &share_button) &&
- ddljson->GetString("short_link", &short_link_str) &&
- short_link_str.find("//") == 0) {
+ if (share_button && short_link_ptr && short_link_ptr->find("//") == 0) {
+ std::string short_link_str = *short_link_ptr;
short_link_str.insert(0, "https:");
- logo->metadata.short_link = GURL(short_link_str);
+ logo->metadata.short_link = GURL(std::move(short_link_str));
if (logo->metadata.short_link.is_valid()) {
- share_button->GetInteger("offset_x", &logo->metadata.share_button_x);
- share_button->GetInteger("offset_y", &logo->metadata.share_button_y);
+ if (absl::optional<int> offset_x = share_button->FindIntKey("offset_x"))
+ logo->metadata.share_button_x = *offset_x;
+ if (absl::optional<int> offset_y = share_button->FindIntKey("offset_y"))
+ logo->metadata.share_button_y = *offset_y;
if (absl::optional<double> opacity =
share_button->FindDoubleKey("opacity")) {
logo->metadata.share_button_opacity = *opacity;
}
- share_button->GetString("icon_image",
- &logo->metadata.share_button_icon);
- share_button->GetString("background_color",
- &logo->metadata.share_button_bg);
+ if (const std::string* icon = share_button->FindStringKey("icon_image"))
+ logo->metadata.share_button_icon = *icon;
+ if (const std::string* bg_color =
+ share_button->FindStringKey("background_color")) {
+ logo->metadata.share_button_bg = *bg_color;
+ }
}
}
- const base::DictionaryValue* dark_share_button = nullptr;
- if (ddljson->GetDictionary("dark_share_button", &dark_share_button)) {
+ const base::Value* dark_share_button =
+ ddljson->FindDictKey("dark_share_button");
+ if (dark_share_button) {
if (logo->metadata.short_link.is_valid()) {
- dark_share_button->GetInteger("offset_x",
- &logo->metadata.dark_share_button_x);
- dark_share_button->GetInteger("offset_y",
- &logo->metadata.dark_share_button_y);
+ if (absl::optional<int> offset_x =
+ dark_share_button->FindIntKey("offset_x")) {
+ logo->metadata.dark_share_button_x = *offset_x;
+ }
+ if (absl::optional<int> offset_y =
+ dark_share_button->FindIntKey("offset_y")) {
+ logo->metadata.dark_share_button_y = *offset_y;
+ }
if (absl::optional<double> opacity =
dark_share_button->FindDoubleKey("opacity")) {
logo->metadata.dark_share_button_opacity = *opacity;
}
- dark_share_button->GetString("icon_image",
- &logo->metadata.dark_share_button_icon);
- dark_share_button->GetString("background_color",
- &logo->metadata.dark_share_button_bg);
+ if (const std::string* icon =
+ dark_share_button->FindStringKey("icon_image")) {
+ logo->metadata.dark_share_button_icon = *icon;
+ }
+ if (const std::string* bg_color =
+ dark_share_button->FindStringKey("background_color")) {
+ logo->metadata.dark_share_button_bg = *bg_color;
+ }
}
}
}
@@ -274,24 +293,24 @@ std::unique_ptr<EncodedLogo> ParseDoodleLogoResponse(
// Data is optional, since we may be revalidating a cached logo.
// If there is a CTA image, get that; otherwise use the regular image.
- std::string encoded_image_data;
- if (ddljson->GetString("cta_data_uri", &encoded_image_data) ||
- ddljson->GetString("data_uri", &encoded_image_data)) {
- std::string mime_type;
- scoped_refptr<base::RefCountedString> data;
- std::tie(mime_type, data) = ParseEncodedImageData(encoded_image_data);
+ const std::string* encoded_image_data =
+ ddljson->FindStringKey("cta_data_uri");
+ if (!encoded_image_data)
+ encoded_image_data = ddljson->FindStringKey("data_uri");
+ if (encoded_image_data) {
+ auto [mime_type, data] = ParseEncodedImageData(*encoded_image_data);
if (!data)
return nullptr;
logo->metadata.mime_type = mime_type;
logo->encoded_image = data;
}
- std::string dark_encoded_image_data;
- if (ddljson->GetString("dark_cta_data_uri", &dark_encoded_image_data) ||
- ddljson->GetString("dark_data_uri", &dark_encoded_image_data)) {
- std::string mime_type;
- scoped_refptr<base::RefCountedString> data;
- std::tie(mime_type, data) = ParseEncodedImageData(dark_encoded_image_data);
+ const std::string* dark_encoded_image_data =
+ ddljson->FindStringKey("dark_cta_data_uri");
+ if (!dark_encoded_image_data)
+ dark_encoded_image_data = ddljson->FindStringKey("dark_data_uri");
+ if (dark_encoded_image_data) {
+ auto [mime_type, data] = ParseEncodedImageData(*dark_encoded_image_data);
if (data)
logo->metadata.dark_mime_type = mime_type;
@@ -299,7 +318,8 @@ std::unique_ptr<EncodedLogo> ParseDoodleLogoResponse(
}
logo->metadata.on_click_url = ParseUrl(*ddljson, "target_url", base_url);
- ddljson->GetString("alt_text", &logo->metadata.alt_text);
+ if (const std::string* alt_text = ddljson->FindStringKey("alt_text"))
+ logo->metadata.alt_text = *alt_text;
logo->metadata.cta_log_url = ParseUrl(*ddljson, "cta_log_url", base_url);
logo->metadata.dark_cta_log_url =
@@ -307,12 +327,13 @@ std::unique_ptr<EncodedLogo> ParseDoodleLogoResponse(
logo->metadata.log_url = ParseUrl(*ddljson, "log_url", base_url);
logo->metadata.dark_log_url = ParseUrl(*ddljson, "dark_log_url", base_url);
- ddljson->GetString("fingerprint", &logo->metadata.fingerprint);
+ if (const std::string* fingerprint = ddljson->FindStringKey("fingerprint"))
+ logo->metadata.fingerprint = *fingerprint;
if (is_interactive) {
- std::string behavior;
- if (ddljson->GetString("launch_interactive_behavior", &behavior) &&
- (behavior == "NEW_WINDOW")) {
+ const std::string* behavior =
+ ddljson->FindStringKey("launch_interactive_behavior");
+ if (behavior && (*behavior == "NEW_WINDOW")) {
logo->metadata.type = LogoType::SIMPLE;
logo->metadata.on_click_url = logo->metadata.full_page_url;
is_interactive = false;
@@ -322,12 +343,10 @@ std::unique_ptr<EncodedLogo> ParseDoodleLogoResponse(
logo->metadata.iframe_width_px = 0;
logo->metadata.iframe_height_px = 0;
if (is_interactive) {
- if (!ddljson->GetInteger("iframe_width_px",
- &logo->metadata.iframe_width_px))
- logo->metadata.iframe_width_px = kDefaultIframeWidthPx;
- if (!ddljson->GetInteger("iframe_height_px",
- &logo->metadata.iframe_height_px))
- logo->metadata.iframe_height_px = kDefaultIframeHeightPx;
+ logo->metadata.iframe_width_px =
+ ddljson->FindIntKey("iframe_width_px").value_or(kDefaultIframeWidthPx);
+ logo->metadata.iframe_height_px = ddljson->FindIntKey("iframe_height_px")
+ .value_or(kDefaultIframeHeightPx);
}
base::TimeDelta time_to_live;
diff --git a/chromium/components/search_provider_logos/logo_service_impl.cc b/chromium/components/search_provider_logos/logo_service_impl.cc
index 9a5dc785765..d229db180ce 100644
--- a/chromium/components/search_provider_logos/logo_service_impl.cc
+++ b/chromium/components/search_provider_logos/logo_service_impl.cc
@@ -242,7 +242,7 @@ void LogoServiceImpl::GetLogo(LogoCallbacks callbacks, bool for_webui_ntp) {
logo_url = GURL(
command_line->GetSwitchValueASCII(switches::kSearchProviderLogoURL));
} else {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Non-Google default search engine logos are currently enabled only on
// Android (https://crbug.com/737283).
logo_url = template_url->logo_url();
@@ -602,7 +602,7 @@ void LogoServiceImpl::OnFreshLogoAvailable(
} else if (encoded_logo && !encoded_logo->encoded_image &&
encoded_logo->metadata.type != LogoType::INTERACTIVE) {
download_outcome = DOWNLOAD_OUTCOME_MISSING_REQUIRED_IMAGE;
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
} else if (encoded_logo && !encoded_logo->encoded_image) {
// On Mobile interactive doodles require a static CTA image, on Desktop the
// static image is not required as it's handled by the iframed page.
diff --git a/chromium/components/security_interstitials/content/android/BUILD.gn b/chromium/components/security_interstitials/content/android/BUILD.gn
index dc87ddcf274..99edd0d7952 100644
--- a/chromium/components/security_interstitials/content/android/BUILD.gn
+++ b/chromium/components/security_interstitials/content/android/BUILD.gn
@@ -18,5 +18,8 @@ android_library("java") {
"java/src/org/chromium/components/security_interstitials/CaptivePortalHelper.java",
"java/src/org/chromium/components/security_interstitials/DateAndTimeSettingsHelper.java",
]
- deps = [ "//base:base_java" ]
+ deps = [
+ "//base:base_java",
+ "//third_party/androidx:androidx_annotation_annotation_java",
+ ]
}
diff --git a/chromium/components/security_interstitials/content/captive_portal_blocking_page.cc b/chromium/components/security_interstitials/content/captive_portal_blocking_page.cc
index ce75af7cf9a..4e737c574c4 100644
--- a/chromium/components/security_interstitials/content/captive_portal_blocking_page.cc
+++ b/chromium/components/security_interstitials/content/captive_portal_blocking_page.cc
@@ -32,7 +32,7 @@
#include "net/ssl/ssl_info.h"
#include "ui/base/l10n/l10n_util.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "net/android/network_library.h"
#endif
@@ -101,16 +101,16 @@ std::string CaptivePortalBlockingPage::GetWiFiSSID() const {
// currently associated WiFi access point. |WiFiService| isn't available on
// Linux so |net::GetWifiSSID| is used instead.
std::string ssid;
-#if defined(OS_WIN) || defined(OS_APPLE)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE)
std::unique_ptr<wifi::WiFiService> wifi_service(wifi::WiFiService::Create());
wifi_service->Initialize(nullptr);
std::string error;
wifi_service->GetConnectedNetworkSSID(&ssid, &error);
if (!error.empty())
return std::string();
-#elif defined(OS_LINUX) || defined(OS_CHROMEOS)
+#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
ssid = net::GetWifiSSID();
-#elif defined(OS_ANDROID)
+#elif BUILDFLAG(IS_ANDROID)
ssid = net::android::GetWifiSSID();
#endif
// TODO(meacer): Handle non UTF8 SSIDs.
diff --git a/chromium/components/security_interstitials/content/certificate_error_report.cc b/chromium/components/security_interstitials/content/certificate_error_report.cc
index 7e23a5fd235..d52129b7a99 100644
--- a/chromium/components/security_interstitials/content/certificate_error_report.cc
+++ b/chromium/components/security_interstitials/content/certificate_error_report.cc
@@ -16,11 +16,11 @@
#include "net/cert/x509_certificate.h"
#include "net/ssl/ssl_info.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "net/cert/cert_verify_proc_android.h"
#endif
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
#include "net/cert/internal/trust_store_mac.h"
#endif
@@ -105,7 +105,7 @@ void AddVerifyFlagsToReport(
}
}
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
void AddMacTrustFlagsToReport(
int mac_trust_flags,
::google::protobuf::RepeatedField<int>* report_flags) {
@@ -167,9 +167,9 @@ TrustImplTypeFromMojom(
MAC_TRUST_IMPL_MRU_CACHE;
}
}
-#endif // defined(OS_APPLE)
+#endif // BUILDFLAG(IS_APPLE)
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
void AddWinPlatformDebugInfoToReport(
const cert_verifier::mojom::WinPlatformVerifierDebugInfoPtr&
win_platform_debug_info,
@@ -185,7 +185,7 @@ void AddWinPlatformDebugInfoToReport(
std::begin(win_platform_debug_info->authroot_sequence_number),
std::end(win_platform_debug_info->authroot_sequence_number));
}
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
#endif // BUILDFLAG(TRIAL_COMPARISON_CERT_VERIFIER_SUPPORTED)
@@ -256,7 +256,7 @@ CertificateErrorReport::CertificateErrorReport(
if (!sct_list.empty())
trial_report->set_sct_list(sct_list);
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
AddMacPlatformDebugInfoToReport(debug_info->mac_platform_debug_info,
trial_report);
AddMacTrustFlagsToReport(
@@ -265,7 +265,7 @@ CertificateErrorReport::CertificateErrorReport(
trial_report->set_mac_trust_impl(
TrustImplTypeFromMojom(debug_info->mac_trust_impl));
#endif
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
AddWinPlatformDebugInfoToReport(debug_info->win_platform_debug_info,
trial_report);
#endif
@@ -459,7 +459,7 @@ CertificateErrorReport::CertificateErrorReport(
AddCertStatusToReportErrors(cert_status, cert_report_->mutable_cert_error());
AddCertStatusToReportStatus(cert_status, cert_report_->mutable_cert_status());
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
chrome_browser_ssl::CertLoggerFeaturesInfo* features_info =
cert_report_->mutable_features_info();
features_info->set_android_aia_fetching_status(
diff --git a/chromium/components/security_interstitials/content/certificate_error_report_unittest.cc b/chromium/components/security_interstitials/content/certificate_error_report_unittest.cc
index bc67bcf8c12..3da4dae3398 100644
--- a/chromium/components/security_interstitials/content/certificate_error_report_unittest.cc
+++ b/chromium/components/security_interstitials/content/certificate_error_report_unittest.cc
@@ -30,11 +30,11 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "net/cert/cert_verify_proc_android.h"
#endif
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
#include "net/cert/internal/trust_store_mac.h"
#endif
@@ -305,7 +305,7 @@ TEST(ErrorReportTest, TestChromeChannelIncluded) {
}
}
-#if defined(OS_WIN) || BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_CHROMEOS_ASH)
// Tests that the SetIsEnterpriseManaged() function populates
// is_enterprise_managed correctly on Windows, and that value is correctly
// extracted from the parsed report.
@@ -327,7 +327,7 @@ TEST(ErrorReportTest, TestIsEnterpriseManagedPopulatedOnWindows) {
}
#endif
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Tests that information about the Android AIA fetching feature is included in
// the report.
TEST(ErrorReportTest, AndroidAIAFetchingFeatureEnabled) {
@@ -364,7 +364,7 @@ TEST(ErrorReportTest, TrialDebugInfo) {
cert_verifier::mojom::CertVerifierDebugInfoPtr debug_info =
cert_verifier::mojom::CertVerifierDebugInfo::New();
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
debug_info->mac_platform_debug_info =
cert_verifier::mojom::MacPlatformVerifierDebugInfo::New();
debug_info->mac_platform_debug_info->trust_result = 1;
@@ -389,7 +389,7 @@ TEST(ErrorReportTest, TrialDebugInfo) {
debug_info->mac_trust_impl =
cert_verifier::mojom::CertVerifierDebugInfo::MacTrustImplType::kLruCache;
#endif
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
debug_info->win_platform_debug_info =
cert_verifier::mojom::WinPlatformVerifierDebugInfo::New();
debug_info->win_platform_debug_info->authroot_this_update =
@@ -419,7 +419,7 @@ TEST(ErrorReportTest, TrialDebugInfo) {
VerifyDeserializedReportSystemInfo(parsed);
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
ASSERT_TRUE(trial_info.has_mac_platform_debug_info());
EXPECT_EQ(1U, trial_info.mac_platform_debug_info().trust_result());
EXPECT_EQ(20, trial_info.mac_platform_debug_info().result_code());
@@ -466,7 +466,7 @@ TEST(ErrorReportTest, TrialDebugInfo) {
EXPECT_FALSE(trial_info.has_mac_trust_impl());
#endif
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
ASSERT_TRUE(trial_info.has_win_platform_debug_info());
EXPECT_EQ(
8675309,
diff --git a/chromium/components/security_interstitials/content/connection_help_ui.cc b/chromium/components/security_interstitials/content/connection_help_ui.cc
index 084a683c412..9a77d57078c 100644
--- a/chromium/components/security_interstitials/content/connection_help_ui.cc
+++ b/chromium/components/security_interstitials/content/connection_help_ui.cc
@@ -58,7 +58,7 @@ ConnectionHelpUI::ConnectionHelpUI(content::WebUI* web_ui)
IDS_CONNECTION_HELP_INCORRECT_CLOCK_DETAILS);
// The superfish section should only be added on Windows.
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
html_source->AddBoolean("isWindows", true);
html_source->AddLocalizedString("connectionHelpMitmSoftwareTitle",
IDS_CONNECTION_HELP_MITM_SOFTWARE_TITLE);
diff --git a/chromium/components/security_interstitials/content/security_interstitial_tab_helper.cc b/chromium/components/security_interstitials/content/security_interstitial_tab_helper.cc
index a3518954469..a996c61e636 100644
--- a/chromium/components/security_interstitials/content/security_interstitial_tab_helper.cc
+++ b/chromium/components/security_interstitials/content/security_interstitial_tab_helper.cc
@@ -54,9 +54,9 @@ void SecurityInterstitialTabHelper::AssociateBlockingPage(
content::NavigationHandle* navigation_handle,
std::unique_ptr<security_interstitials::SecurityInterstitialPage>
blocking_page) {
- // Security interstitials are not supported with prerendered pages.
- if (!navigation_handle->IsInPrimaryMainFrame())
- return;
+ // An interstitial should not be shown in a prerendered page. The prerender
+ // should just be canceled.
+ DCHECK(navigation_handle->IsInPrimaryMainFrame());
// CreateForWebContents() creates a tab helper if it doesn't yet exist for the
// WebContents provided by |navigation_handle|.
diff --git a/chromium/components/security_interstitials/content/security_interstitial_tab_helper_unittest.cc b/chromium/components/security_interstitials/content/security_interstitial_tab_helper_unittest.cc
index 1eada58b27b..c6db9a0c0d4 100644
--- a/chromium/components/security_interstitials/content/security_interstitial_tab_helper_unittest.cc
+++ b/chromium/components/security_interstitials/content/security_interstitial_tab_helper_unittest.cc
@@ -215,17 +215,4 @@ TEST_F(SecurityInterstitialTabHelperTest, NavigationDoesNotCommit) {
EXPECT_TRUE(committed_blocking_page_destroyed);
}
-// Tests that a security interstital created for a non-primary main frame
-// navigation is immediately discarded.
-TEST_F(SecurityInterstitialTabHelperTest, DiscardedOnNonPrimaryMainFrame) {
- std::unique_ptr<content::MockNavigationHandle> blocking_page_handle =
- CreateHandle(true, false);
- blocking_page_handle->set_is_in_primary_main_frame(false);
- bool blocking_page_destroyed = false;
- CreateAssociatedBlockingPage(blocking_page_handle.get(),
- &blocking_page_destroyed);
- // Interstitial should be discarded immediately.
- EXPECT_TRUE(blocking_page_destroyed);
-}
-
} // namespace security_interstitials
diff --git a/chromium/components/security_interstitials/content/ssl_error_handler.cc b/chromium/components/security_interstitials/content/ssl_error_handler.cc
index 656cc13fa1f..97071314bc6 100644
--- a/chromium/components/security_interstitials/content/ssl_error_handler.cc
+++ b/chromium/components/security_interstitials/content/ssl_error_handler.cc
@@ -53,7 +53,7 @@
#include "components/captive_portal/content/captive_portal_tab_helper.h"
#endif
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "base/android/jni_android.h"
#include "components/security_interstitials/content/captive_portal_helper_android.h"
#endif
@@ -429,7 +429,7 @@ void SSLErrorHandlerDelegateImpl::CheckForCaptivePortal() {
}
bool SSLErrorHandlerDelegateImpl::DoesOSReportCaptivePortal() {
-#if defined(OS_ANDROID) || defined(OS_WIN)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_WIN)
return security_interstitials::IsBehindCaptivePortal();
#else
return false;
@@ -510,7 +510,7 @@ void SSLErrorHandlerDelegateImpl::ShowBlockedInterceptionInterstitial() {
void SSLErrorHandlerDelegateImpl::ReportNetworkConnectivity(
base::OnceClosure callback) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
security_interstitials::ReportNetworkConnectivity(
base::android::AttachCurrentThread());
#else
diff --git a/chromium/components/security_interstitials/content/ssl_error_handler_unittest.cc b/chromium/components/security_interstitials/content/ssl_error_handler_unittest.cc
index 12174de7c59..4e85285271d 100644
--- a/chromium/components/security_interstitials/content/ssl_error_handler_unittest.cc
+++ b/chromium/components/security_interstitials/content/ssl_error_handler_unittest.cc
@@ -457,7 +457,7 @@ class SSLErrorAssistantProtoTest : public content::RenderViewHostTestHarness {
RunCaptivePortalTest();
-#if !defined(OS_ANDROID) && !BUILDFLAG(IS_CHROMECAST)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMECAST)
// On platforms where captive portal detection is enabled, timer should
// start for captive portal detection.
EXPECT_TRUE(error_handler()->IsTimerRunningForTesting());
@@ -1138,7 +1138,7 @@ TEST_F(SSLErrorHandlerNameMismatchTest,
}
// Flakily fails on linux_chromium_tsan_rel_ng. http://crbug.com/989128
-#if (defined(OS_LINUX) || defined(OS_CHROMEOS)) && defined(THREAD_SANITIZER)
+#if (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)) && defined(THREAD_SANITIZER)
#define MAYBE_TimeQueryStarted DISABLED_TimeQueryStarted
#else
#define MAYBE_TimeQueryStarted TimeQueryStarted
@@ -1173,7 +1173,7 @@ TEST_F(SSLErrorHandlerDateInvalidTest, MAYBE_TimeQueryStarted) {
// clock can't be determined because network time is unavailable.
// Flakily fails on linux_chromium_tsan_rel_ng. http://crbug.com/989225
-#if (defined(OS_LINUX) || defined(OS_CHROMEOS)) && defined(THREAD_SANITIZER)
+#if (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)) && defined(THREAD_SANITIZER)
#define MAYBE_NoTimeQueries DISABLED_NoTimeQueries
#else
#define MAYBE_NoTimeQueries NoTimeQueries
@@ -1198,7 +1198,7 @@ TEST_F(SSLErrorHandlerDateInvalidTest, MAYBE_NoTimeQueries) {
// the system clock times out (e.g. because a network time query hangs).
// Flakily fails on linux_chromium_tsan_rel_ng. http://crbug.com/989289
-#if (defined(OS_LINUX) || defined(OS_CHROMEOS)) && defined(THREAD_SANITIZER)
+#if (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)) && defined(THREAD_SANITIZER)
#define MAYBE_TimeQueryHangs DISABLED_TimeQueryHangs
#else
#define MAYBE_TimeQueryHangs TimeQueryHangs
diff --git a/chromium/components/security_interstitials/content/ssl_error_navigation_throttle.cc b/chromium/components/security_interstitials/content/ssl_error_navigation_throttle.cc
index 0e8933640eb..4aa3e24e5d4 100644
--- a/chromium/components/security_interstitials/content/ssl_error_navigation_throttle.cc
+++ b/chromium/components/security_interstitials/content/ssl_error_navigation_throttle.cc
@@ -45,9 +45,10 @@ SSLErrorNavigationThrottle::WillFailRequest() {
return content::NavigationThrottle::PROCEED;
}
- // Do not set special error page HTML for subframes; those are handled as
- // normal network errors.
- if (!handle->IsInMainFrame() || handle->GetWebContents()->IsPortal()) {
+ // Do not set special error page HTML for non-primary pages (e.g. regular
+ // subframe, prerendering, fenced-frame, portal). Those are handled as normal
+ // network errors.
+ if (!handle->IsInPrimaryMainFrame() || handle->GetWebContents()->IsPortal()) {
return content::NavigationThrottle::PROCEED;
}
@@ -81,9 +82,10 @@ SSLErrorNavigationThrottle::WillProcessResponse() {
return content::NavigationThrottle::PROCEED;
}
- // Do not set special error page HTML for subframes; those are handled as
- // normal network errors.
- if (!handle->IsInMainFrame() || handle->GetWebContents()->IsPortal()) {
+ // Do not set special error page HTML for non-primary pages (e.g. regular
+ // subframe, prerendering, fenced-frame, portal). Those are handled as normal
+ // network errors.
+ if (!handle->IsInPrimaryMainFrame() || handle->GetWebContents()->IsPortal()) {
return content::NavigationThrottle::PROCEED;
}
@@ -93,12 +95,6 @@ SSLErrorNavigationThrottle::WillProcessResponse() {
// through the interstitial will continue the navigation in a regular browser
// window.
if (std::move(is_in_hosted_app_callback_).Run(handle->GetWebContents())) {
- // Non-primary pages (e.g. prerendering, fenced-frame, portal) should not
- // be handled as a hosted app since they are associated with the non-app
- // WebContents. For prerendering specifically, we should already have
- // canceled the prerender from OnSSLCertificateError before the throttle
- // runs WillProcessResponse.
- DCHECK(navigation_handle()->IsInPrimaryMainFrame());
QueueShowInterstitial(
std::move(handle_ssl_error_callback_), handle->GetWebContents(),
// The navigation handle's net error code will be
@@ -145,8 +141,10 @@ void SSLErrorNavigationThrottle::ShowInterstitial(
content::NavigationHandle* handle = navigation_handle();
- // For non-primary pages (e.g. prerendering) we should already have canceled
- // the prerender from OnSSLCertificateError before the throttle failure.
+ // Do not display insterstitials for SSL errors from non-primary pages (e.g.
+ // prerendering, fenced-frame, portal). For prerendering specifically, we
+ // should already have canceled the prerender from OnSSLCertificateError
+ // before the throttle runs.
DCHECK(handle->IsInPrimaryMainFrame());
security_interstitials::SecurityInterstitialTabHelper::AssociateBlockingPage(
diff --git a/chromium/components/security_interstitials/content/stateful_ssl_host_state_delegate.cc b/chromium/components/security_interstitials/content/stateful_ssl_host_state_delegate.cc
index 186363ed08f..efd772bc180 100644
--- a/chromium/components/security_interstitials/content/stateful_ssl_host_state_delegate.cc
+++ b/chromium/components/security_interstitials/content/stateful_ssl_host_state_delegate.cc
@@ -50,7 +50,7 @@
namespace {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
StatefulSSLHostStateDelegate::RecurrentInterstitialMode
kRecurrentInterstitialDefaultMode =
StatefulSSLHostStateDelegate::RecurrentInterstitialMode::PREF;
@@ -107,7 +107,7 @@ void UpdateRecurrentInterstitialPref(PrefService* pref_service,
// Check that the values are in increasing order and wipe out the list if
// not (presumably because the clock changed).
double previous = 0;
- for (const auto& error_instance : list_value->GetList()) {
+ for (const auto& error_instance : list_value->GetListDeprecated()) {
double error_time = error_instance.GetDouble();
if (error_time < previous) {
list_value = nullptr;
@@ -130,8 +130,9 @@ void UpdateRecurrentInterstitialPref(PrefService* pref_service,
// Only up to |threshold| values need to be stored. If the list already
// contains |threshold| values, pop one off the front and append the new one
// at the end; otherwise just append the new one.
- while (base::MakeStrictNum(list_value->GetList().size()) >= threshold) {
- list_value->EraseListIter(list_value->GetList().begin());
+ while (base::MakeStrictNum(list_value->GetListDeprecated().size()) >=
+ threshold) {
+ list_value->EraseListIter(list_value->GetListDeprecated().begin());
}
list_value->Append(now);
}
@@ -155,7 +156,7 @@ bool DoesRecurrentInterstitialPrefMeetThreshold(PrefService* pref_service,
// Assume that the values in the list are in increasing order;
// UpdateRecurrentInterstitialPref() maintains this ordering. Check if there
// are more than |threshold| values after the cutoff time.
- base::Value::ConstListView error_list = list_value->GetList();
+ base::Value::ConstListView error_list = list_value->GetListDeprecated();
for (size_t i = 0; i < error_list.size(); i++) {
if (base::Time::FromJsTime(error_list[i].GetDouble()) >= cutoff_time)
return base::MakeStrictNum(error_list.size() - i) >= threshold;
@@ -241,23 +242,22 @@ void StatefulSSLHostStateDelegate::AllowCert(
}
GURL url = GetSecureGURLForHost(host);
- std::unique_ptr<base::Value> value(
- host_content_settings_map_->GetWebsiteSetting(
- url, url, ContentSettingsType::SSL_CERT_DECISIONS, nullptr));
+ base::Value value(host_content_settings_map_->GetWebsiteSetting(
+ url, url, ContentSettingsType::SSL_CERT_DECISIONS, nullptr));
- if (!value.get() || !value->is_dict())
- value = std::make_unique<base::Value>(base::Value::Type::DICTIONARY);
+ if (!value.is_dict())
+ value = base::Value(base::Value::Type::DICTIONARY);
base::Value* cert_dict =
- GetValidCertDecisionsDict(value.get(), CREATE_DICTIONARY_ENTRIES);
+ GetValidCertDecisionsDict(CREATE_DICTIONARY_ENTRIES, value);
// If a a valid certificate dictionary cannot be extracted from the content
// setting, that means it's in an unknown format. Unfortunately, there's
// nothing to be done in that case, so a silent fail is the only option.
if (!cert_dict)
return;
- value->SetKey(kSSLCertDecisionVersionKey,
- base::Value(kDefaultSSLCertDecisionVersion));
+ value.SetKey(kSSLCertDecisionVersionKey,
+ base::Value(kDefaultSSLCertDecisionVersion));
cert_dict->SetKey(GetKey(cert, error), base::Value(ALLOWED));
// The map takes ownership of the value, so it is released in the call to
@@ -312,15 +312,14 @@ StatefulSSLHostStateDelegate::QueryPolicy(const std::string& host,
}
GURL url = GetSecureGURLForHost(host);
- std::unique_ptr<base::Value> value(
- host_content_settings_map_->GetWebsiteSetting(
- url, url, ContentSettingsType::SSL_CERT_DECISIONS, nullptr));
+ base::Value value(host_content_settings_map_->GetWebsiteSetting(
+ url, url, ContentSettingsType::SSL_CERT_DECISIONS, nullptr));
- if (!value.get() || !value->is_dict())
+ if (!value.is_dict())
return DENIED;
base::Value* cert_error_dict =
- GetValidCertDecisionsDict(value.get(), DO_NOT_CREATE_DICTIONARY_ENTRIES);
+ GetValidCertDecisionsDict(DO_NOT_CREATE_DICTIONARY_ENTRIES, value);
if (!cert_error_dict) {
// This revoke is necessary to clear any old expired setting that may be
// lingering in the case that an old decision expried.
@@ -395,7 +394,8 @@ void StatefulSSLHostStateDelegate::AllowHttpForHost(
dict->SetKey(kHTTPAllowlistExpirationTimeKey,
base::TimeToValue(expiration_time));
host_content_settings_map_->SetWebsiteSettingDefaultScope(
- url, GURL(), ContentSettingsType::HTTP_ALLOWED, std::move(dict));
+ url, GURL(), ContentSettingsType::HTTP_ALLOWED,
+ base::Value::FromUniquePtrValue(std::move(dict)));
}
bool StatefulSSLHostStateDelegate::IsHttpAllowedForHost(
@@ -415,14 +415,14 @@ bool StatefulSSLHostStateDelegate::IsHttpAllowedForHost(
const ContentSettingsPattern pattern =
ContentSettingsPattern::FromURLNoWildcard(url);
- auto value = host_content_settings_map_->GetWebsiteSetting(
+ const base::Value value = host_content_settings_map_->GetWebsiteSetting(
url, url, ContentSettingsType::HTTP_ALLOWED, nullptr);
- if (!value || !value->is_dict()) {
+ if (!value.is_dict()) {
return false;
}
auto* decision_expiration_value =
- value->FindKey(kHTTPAllowlistExpirationTimeKey);
+ value.FindKey(kHTTPAllowlistExpirationTimeKey);
auto decision_expiration = base::ValueToTime(decision_expiration_value);
if (decision_expiration <= clock_->Now()) {
// Allowlist entry has expired.
@@ -437,9 +437,9 @@ void StatefulSSLHostStateDelegate::RevokeUserAllowExceptions(
GURL url = GetSecureGURLForHost(host);
host_content_settings_map_->SetWebsiteSettingDefaultScope(
- url, GURL(), ContentSettingsType::SSL_CERT_DECISIONS, nullptr);
+ url, GURL(), ContentSettingsType::SSL_CERT_DECISIONS, base::Value());
host_content_settings_map_->SetWebsiteSettingDefaultScope(
- url, GURL(), ContentSettingsType::HTTP_ALLOWED, nullptr);
+ url, GURL(), ContentSettingsType::HTTP_ALLOWED, base::Value());
// Decisions for non-default storage partitions are stored separately in
// memory; delete those as well.
@@ -592,14 +592,13 @@ bool StatefulSSLHostStateDelegate::HasCertAllowException(
const ContentSettingsPattern pattern =
ContentSettingsPattern::FromURLNoWildcard(url);
- std::unique_ptr<base::Value> value(
- host_content_settings_map_->GetWebsiteSetting(
- url, url, ContentSettingsType::SSL_CERT_DECISIONS, nullptr));
+ const base::Value value(host_content_settings_map_->GetWebsiteSetting(
+ url, url, ContentSettingsType::SSL_CERT_DECISIONS, nullptr));
- if (!value.get() || !value->is_dict())
+ if (!value.is_dict())
return false;
- for (auto pair : value->DictItems()) {
+ for (const auto pair : value.DictItems()) {
if (!pair.second.is_int())
continue;
@@ -622,16 +621,16 @@ bool StatefulSSLHostStateDelegate::HasCertAllowException(
// is set to |CREATE_DICTIONARY_ENTRIES|, if no dictionary is found or the
// decisions are expired, a new dictionary will be created.
base::Value* StatefulSSLHostStateDelegate::GetValidCertDecisionsDict(
- base::Value* dict,
- CreateDictionaryEntriesDisposition create_entries) {
+ CreateDictionaryEntriesDisposition create_entries,
+ base::Value& dict) {
// Extract the version of the certificate decision structure from the content
// setting.
- absl::optional<int> version = dict->FindIntKey(kSSLCertDecisionVersionKey);
+ absl::optional<int> version = dict.FindIntKey(kSSLCertDecisionVersionKey);
if (!version) {
if (create_entries == DO_NOT_CREATE_DICTIONARY_ENTRIES)
return nullptr;
- dict->SetIntKey(kSSLCertDecisionVersionKey, kDefaultSSLCertDecisionVersion);
+ dict.SetIntKey(kSSLCertDecisionVersionKey, kDefaultSSLCertDecisionVersion);
version = absl::make_optional<int>(kDefaultSSLCertDecisionVersion);
}
@@ -652,7 +651,7 @@ base::Value* StatefulSSLHostStateDelegate::GetValidCertDecisionsDict(
bool expired = false;
base::Time now = clock_->Now();
auto* decision_expiration_value =
- dict->FindKey(kSSLCertDecisionExpirationTimeKey);
+ dict.FindKey(kSSLCertDecisionExpirationTimeKey);
auto decision_expiration = base::ValueToTime(decision_expiration_value);
// Check to see if the user's certificate decision has expired.
@@ -670,19 +669,19 @@ base::Value* StatefulSSLHostStateDelegate::GetValidCertDecisionsDict(
// Unfortunately, JSON (and thus content settings) doesn't support int64_t
// values, only doubles. Since this mildly depends on precision, it is
// better to store the value as a string.
- dict->SetKey(kSSLCertDecisionExpirationTimeKey,
- base::TimeToValue(expiration_time));
+ dict.SetKey(kSSLCertDecisionExpirationTimeKey,
+ base::TimeToValue(expiration_time));
}
// Extract the map of certificate fingerprints to errors from the setting.
base::Value* cert_error_dict =
- dict->FindDictKey(kSSLCertDecisionCertErrorMapKey);
+ dict.FindDictKey(kSSLCertDecisionCertErrorMapKey);
if (expired || !cert_error_dict) {
if (create_entries == DO_NOT_CREATE_DICTIONARY_ENTRIES)
return nullptr;
- cert_error_dict = dict->SetKey(kSSLCertDecisionCertErrorMapKey,
- base::Value(base::Value::Type::DICTIONARY));
+ cert_error_dict = dict.SetKey(kSSLCertDecisionCertErrorMapKey,
+ base::Value(base::Value::Type::DICTIONARY));
}
return cert_error_dict;
diff --git a/chromium/components/security_interstitials/content/stateful_ssl_host_state_delegate.h b/chromium/components/security_interstitials/content/stateful_ssl_host_state_delegate.h
index 68c376aefeb..a7e8ea7c841 100644
--- a/chromium/components/security_interstitials/content/stateful_ssl_host_state_delegate.h
+++ b/chromium/components/security_interstitials/content/stateful_ssl_host_state_delegate.h
@@ -135,8 +135,8 @@ class StatefulSSLHostStateDelegate : public content::SSLHostStateDelegate,
// dictionary if they do not already exist. Otherwise will fail and return if
// NULL if they do not exist.
base::Value* GetValidCertDecisionsDict(
- base::Value* dict,
- CreateDictionaryEntriesDisposition create_entries);
+ CreateDictionaryEntriesDisposition create_entries,
+ base::Value& dict);
std::unique_ptr<base::Clock> clock_;
raw_ptr<content::BrowserContext> browser_context_;
diff --git a/chromium/components/security_interstitials/content/utils.cc b/chromium/components/security_interstitials/content/utils.cc
index 1a96fdb6c80..2954aef077b 100644
--- a/chromium/components/security_interstitials/content/utils.cc
+++ b/chromium/components/security_interstitials/content/utils.cc
@@ -13,14 +13,14 @@
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
#include "base/android/scoped_java_ref.h"
#include "components/security_interstitials/content/android/jni_headers/DateAndTimeSettingsHelper_jni.h"
#endif
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include "base/base_paths_win.h"
#include "base/path_service.h"
#endif
@@ -31,10 +31,10 @@ namespace security_interstitials {
void LaunchDateAndTimeSettings() {
// The code for each OS is completely separate, in order to avoid bugs like
// https://crbug.com/430877 .
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
JNIEnv* env = base::android::AttachCurrentThread();
Java_DateAndTimeSettingsHelper_openDateAndTimeSettings(env);
-#elif defined(OS_LINUX) || defined(OS_CHROMEOS)
+#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
struct ClockCommand {
const char* const pathname;
const char* const argument;
@@ -74,7 +74,7 @@ void LaunchDateAndTimeSettings() {
options.allow_new_privs = true;
base::LaunchProcess(command, options);
-#elif defined(OS_APPLE)
+#elif BUILDFLAG(IS_APPLE)
base::CommandLine command(base::FilePath("/usr/bin/open"));
command.AppendArg("/System/Library/PreferencePanes/DateAndTime.prefPane");
@@ -82,7 +82,7 @@ void LaunchDateAndTimeSettings() {
options.wait = false;
base::LaunchProcess(command, options);
-#elif defined(OS_WIN)
+#elif BUILDFLAG(IS_WIN)
base::FilePath path;
base::PathService::Get(base::DIR_SYSTEM, &path);
static const wchar_t kControlPanelExe[] = L"control.exe";
@@ -95,7 +95,7 @@ void LaunchDateAndTimeSettings() {
options.wait = false;
base::LaunchProcess(command, options);
-#elif defined(OS_FUCHSIA)
+#elif BUILDFLAG(IS_FUCHSIA)
// TODO(crbug.com/1233494): Send to the platform settings.
NOTIMPLEMENTED_LOG_ONCE();
#else
diff --git a/chromium/components/security_interstitials/core/safe_browsing_loud_error_ui.cc b/chromium/components/security_interstitials/core/safe_browsing_loud_error_ui.cc
index 2e462a38a71..eae06a31dca 100644
--- a/chromium/components/security_interstitials/core/safe_browsing_loud_error_ui.cc
+++ b/chromium/components/security_interstitials/core/safe_browsing_loud_error_ui.cc
@@ -140,7 +140,7 @@ void SafeBrowsingLoudErrorUI::HandleCommand(
break;
}
// If the user can't proceed, fall through to CMD_DONT_PROCEED.
- FALLTHROUGH;
+ [[fallthrough]];
}
case CMD_DONT_PROCEED: {
// User pressed on the button to return to safety.
diff --git a/chromium/components/security_interstitials/core/ssl_error_ui.cc b/chromium/components/security_interstitials/core/ssl_error_ui.cc
index 0d7cd203afa..c8485f0b84e 100644
--- a/chromium/components/security_interstitials/core/ssl_error_ui.cc
+++ b/chromium/components/security_interstitials/core/ssl_error_ui.cc
@@ -128,7 +128,7 @@ void SSLErrorUI::PopulateOverridableStrings(base::Value* load_time_data) {
// On iOS, offer to close the page instead of navigating to NTP when unable to
// go back. See crbug.com/1058476 for discussion.
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
if (!controller()->CanGoBack()) {
load_time_data->SetStringKey(
"primaryButtonText",
diff --git a/chromium/components/security_state/core/security_state.cc b/chromium/components/security_state/core/security_state.cc
index 143f294140e..db8be156f6d 100644
--- a/chromium/components/security_state/core/security_state.cc
+++ b/chromium/components/security_state/core/security_state.cc
@@ -160,7 +160,7 @@ SecurityLevel GetSecurityLevel(
if (!visible_security_state.is_error_page &&
!network::IsUrlPotentiallyTrustworthy(url) &&
(url.IsStandard() || url.SchemeIs(url::kBlobScheme))) {
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
// On Desktop, Reader Mode pages have their own visible security state in
// the omnibox. Display ReaderMode pages as neutral even if the original
// URL was secure, because Chrome has modified the content so we don't
@@ -172,7 +172,7 @@ SecurityLevel GetSecurityLevel(
if (visible_security_state.is_reader_mode) {
return NONE;
}
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
return WARNING;
}
return NONE;
diff --git a/chromium/components/security_state/ios/BUILD.gn b/chromium/components/security_state/ios/BUILD.gn
index 22149a2ad14..2c36d3cef66 100644
--- a/chromium/components/security_state/ios/BUILD.gn
+++ b/chromium/components/security_state/ios/BUILD.gn
@@ -29,5 +29,6 @@ source_set("unit_tests") {
"//components/security_state/core",
"//ios/web/public/security",
"//ios/web/public/test",
+ "//ios/web/public/test:test_fixture",
]
}
diff --git a/chromium/components/segmentation_platform/OWNERS b/chromium/components/segmentation_platform/OWNERS
index 2c364517d42..932eb9b06b5 100644
--- a/chromium/components/segmentation_platform/OWNERS
+++ b/chromium/components/segmentation_platform/OWNERS
@@ -1,2 +1,4 @@
nyquist@chromium.org
+qinmin@chromium.org
shaktisahu@chromium.org
+ssid@chromium.org
diff --git a/chromium/components/segmentation_platform/README.md b/chromium/components/segmentation_platform/README.md
index 08415064a13..687eeaf6fae 100644
--- a/chromium/components/segmentation_platform/README.md
+++ b/chromium/components/segmentation_platform/README.md
@@ -38,3 +38,10 @@ target and give the `segmentation_platform` filter file as an argument:
```
./out/Default/components_unittests --test-launcher-filter-file=components/segmentation_platform/components_unittests.filter
```
+
+To update the list of tests, you can run the following command:
+```
+for test in $(git grep -E '^TEST(_F)?\(' -- components/segmentation_platform | \
+ cut -d"(" -f 2 | cut -d"," -f 1 | sort | uniq); do echo ${test}.* ; done > \
+ components/segmentation_platform/components_unittests.filter
+```
diff --git a/chromium/components/segmentation_platform/components_unittests.filter b/chromium/components/segmentation_platform/components_unittests.filter
index 64f2d828b16..78c233197b4 100644
--- a/chromium/components/segmentation_platform/components_unittests.filter
+++ b/chromium/components/segmentation_platform/components_unittests.filter
@@ -2,20 +2,22 @@ DatabaseMaintenanceImplTest.*
DummyModelExecutionManagerTest.*
DummySegmentationPlatformServiceTest.*
FeatureAggregatorImplTest.*
+FeatureListQueryProcessorTest.*
HistogramSignalHandlerTest.*
MetadataUtilsTest.*
ModelExecutionManagerFactoryTest.*
ModelExecutionManagerTest.*
ModelExecutionSchedulerTest.*
SegmentationModelExecutorTest.*
-SegmentationPlatformFeaturesTest.*
-SegmentationPlatformServiceImplTest.*
SegmentationPlatformServiceImplEmptyConfigTest.*
SegmentationPlatformServiceImplMultiClientTest.*
+SegmentationPlatformServiceImplTest.*
SegmentationResultPrefsTest.*
+SegmentationUkmHelperTest.*
SegmentInfoDatabaseTest.*
SegmentScoreProviderTest.*
SegmentSelectorTest.*
+ServiceProxyImplTest.*
SignalDatabaseImplTest.*
SignalFilterProcessorTest.*
SignalKeyInternalTest.*
diff --git a/chromium/components/segmentation_platform/internal/BUILD.gn b/chromium/components/segmentation_platform/internal/BUILD.gn
index 1a03b897ccc..d06820e40b5 100644
--- a/chromium/components/segmentation_platform/internal/BUILD.gn
+++ b/chromium/components/segmentation_platform/internal/BUILD.gn
@@ -17,6 +17,8 @@ static_library("internal") {
sources = [
"constants.cc",
"constants.h",
+ "data_collection/training_data_collector.cc",
+ "data_collection/training_data_collector.h",
"database/database_maintenance.h",
"database/database_maintenance_impl.cc",
"database/database_maintenance_impl.h",
@@ -35,15 +37,23 @@ static_library("internal") {
"database/signal_storage_config.h",
"dummy_segmentation_platform_service.cc",
"dummy_segmentation_platform_service.h",
+ "execution/custom_input_processor.cc",
+ "execution/custom_input_processor.h",
"execution/dummy_model_execution_manager.cc",
"execution/dummy_model_execution_manager.h",
"execution/feature_aggregator.h",
"execution/feature_aggregator_impl.cc",
"execution/feature_aggregator_impl.h",
+ "execution/feature_list_query_processor.cc",
+ "execution/feature_list_query_processor.h",
+ "execution/feature_processor_state.cc",
+ "execution/feature_processor_state.h",
"execution/model_execution_manager.h",
"execution/model_execution_manager_factory.cc",
"execution/model_execution_manager_factory.h",
"execution/model_execution_status.h",
+ "execution/uma_feature_processor.cc",
+ "execution/uma_feature_processor.h",
"platform_options.cc",
"platform_options.h",
"scheduler/model_execution_scheduler.h",
@@ -51,6 +61,8 @@ static_library("internal") {
"scheduler/model_execution_scheduler_impl.h",
"segmentation_platform_service_impl.cc",
"segmentation_platform_service_impl.h",
+ "segmentation_ukm_helper.cc",
+ "segmentation_ukm_helper.h",
"selection/segment_score_provider.cc",
"selection/segment_score_provider.h",
"selection/segment_selector.h",
@@ -68,6 +80,8 @@ static_library("internal") {
"signals/user_action_signal_handler.h",
"stats.cc",
"stats.h",
+ "ukm_data_manager.cc",
+ "ukm_data_manager.h",
]
deps = [
@@ -77,6 +91,8 @@ static_library("internal") {
"//components/prefs",
"//components/segmentation_platform/internal/proto",
"//components/segmentation_platform/public",
+ "//services/metrics/public/cpp:metrics_cpp",
+ "//services/metrics/public/cpp:ukm_builders",
]
public_deps = [
@@ -134,9 +150,13 @@ source_set("unit_tests") {
"dummy_segmentation_platform_service_unittest.cc",
"execution/dummy_model_execution_manager_unittest.cc",
"execution/feature_aggregator_impl_unittest.cc",
+ "execution/feature_list_query_processor_unittest.cc",
+ "execution/mock_feature_aggregator.cc",
+ "execution/mock_feature_aggregator.h",
"execution/model_execution_manager_factory_unittest.cc",
"scheduler/model_execution_scheduler_unittest.cc",
"segmentation_platform_service_impl_unittest.cc",
+ "segmentation_ukm_helper_unittest.cc",
"selection/segment_score_provider_unittest.cc",
"selection/segment_selector_unittest.cc",
"selection/segmentation_result_prefs_unittest.cc",
@@ -157,6 +177,8 @@ source_set("unit_tests") {
"//components/prefs:test_support",
"//components/segmentation_platform/internal/proto",
"//components/segmentation_platform/public",
+ "//components/ukm:test_support",
+ "//services/metrics/public/cpp:ukm_builders",
"//testing/gmock",
"//testing/gtest",
]
diff --git a/chromium/components/segmentation_platform/internal/DEPS b/chromium/components/segmentation_platform/internal/DEPS
new file mode 100644
index 00000000000..b0131012718
--- /dev/null
+++ b/chromium/components/segmentation_platform/internal/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+ "+components/ukm/test_ukm_recorder.h",
+ "+services/metrics/public/cpp",
+]
diff --git a/chromium/components/segmentation_platform/internal/android/segmentation_platform_service_android.cc b/chromium/components/segmentation_platform/internal/android/segmentation_platform_service_android.cc
index 738d40fcecf..d580aa7d579 100644
--- a/chromium/components/segmentation_platform/internal/android/segmentation_platform_service_android.cc
+++ b/chromium/components/segmentation_platform/internal/android/segmentation_platform_service_android.cc
@@ -85,6 +85,16 @@ void SegmentationPlatformServiceAndroid::GetSelectedSegment(
}
ScopedJavaLocalRef<jobject>
+SegmentationPlatformServiceAndroid::GetCachedSegmentResult(
+ JNIEnv* env,
+ const JavaParamRef<jobject>& jcaller,
+ const JavaParamRef<jstring>& j_segmentation_key) {
+ return CreateJavaSegmentSelectionResult(
+ env, segmentation_platform_service_->GetCachedSegmentResult(
+ ConvertJavaStringToUTF8(env, j_segmentation_key)));
+}
+
+ScopedJavaLocalRef<jobject>
SegmentationPlatformServiceAndroid::GetJavaObject() {
return ScopedJavaLocalRef<jobject>(java_obj_);
}
diff --git a/chromium/components/segmentation_platform/internal/android/segmentation_platform_service_android.h b/chromium/components/segmentation_platform/internal/android/segmentation_platform_service_android.h
index c9225b01cdd..86ad117a3e0 100644
--- a/chromium/components/segmentation_platform/internal/android/segmentation_platform_service_android.h
+++ b/chromium/components/segmentation_platform/internal/android/segmentation_platform_service_android.h
@@ -30,6 +30,11 @@ class SegmentationPlatformServiceAndroid : public base::SupportsUserData::Data {
const JavaParamRef<jstring>& j_segmentation_key,
const JavaParamRef<jobject>& j_callback);
+ ScopedJavaLocalRef<jobject> GetCachedSegmentResult(
+ JNIEnv* env,
+ const JavaParamRef<jobject>& jcaller,
+ const JavaParamRef<jstring>& j_segmentation_key);
+
ScopedJavaLocalRef<jobject> GetJavaObject();
private:
diff --git a/chromium/components/segmentation_platform/internal/data_collection/training_data_collector.cc b/chromium/components/segmentation_platform/internal/data_collection/training_data_collector.cc
new file mode 100644
index 00000000000..27822a21322
--- /dev/null
+++ b/chromium/components/segmentation_platform/internal/data_collection/training_data_collector.cc
@@ -0,0 +1,26 @@
+// Copyright 2022 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.
+
+#include "components/segmentation_platform/internal/data_collection/training_data_collector.h"
+
+#include "base/notreached.h"
+#include "components/segmentation_platform/internal/execution/feature_list_query_processor.h"
+
+namespace segmentation_platform {
+
+TrainingDataCollector::TrainingDataCollector(
+ FeatureListQueryProcessor* processor)
+ : feature_list_query_processor_(processor) {}
+
+TrainingDataCollector::~TrainingDataCollector() = default;
+
+void TrainingDataCollector::OnModelMetadataUpdated() {
+ NOTIMPLEMENTED();
+}
+
+void TrainingDataCollector::OnServiceInitialized() {
+ NOTIMPLEMENTED();
+}
+
+} // namespace segmentation_platform
diff --git a/chromium/components/segmentation_platform/internal/data_collection/training_data_collector.h b/chromium/components/segmentation_platform/internal/data_collection/training_data_collector.h
new file mode 100644
index 00000000000..30d0260cc78
--- /dev/null
+++ b/chromium/components/segmentation_platform/internal/data_collection/training_data_collector.h
@@ -0,0 +1,40 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_DATA_COLLECTION_TRAINING_DATA_COLLECTOR_H_
+#define COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_DATA_COLLECTION_TRAINING_DATA_COLLECTOR_H_
+
+#include "base/memory/raw_ptr.h"
+
+namespace segmentation_platform {
+
+class FeatureListQueryProcessor;
+
+// Collect training data and report as Ukm message. Live on main thread.
+// TODO(xingliu): Make a new class that owns the training data collector and
+// model execution collector.
+class TrainingDataCollector {
+ public:
+ explicit TrainingDataCollector(FeatureListQueryProcessor* processor);
+ ~TrainingDataCollector();
+
+ // Disallow copy/assign.
+ TrainingDataCollector(const TrainingDataCollector&) = delete;
+ TrainingDataCollector& operator=(const TrainingDataCollector&) = delete;
+
+ // Called when model metadata is updated. May result in training data
+ // collection behavior change.
+ void OnModelMetadataUpdated();
+
+ // Called after segmentation platform is initialized. May report training data
+ // to Ukm that has a non-zero |duration| field in |UMAOutput|.
+ void OnServiceInitialized();
+
+ private:
+ raw_ptr<FeatureListQueryProcessor> feature_list_query_processor_;
+};
+
+} // namespace segmentation_platform
+
+#endif // COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_DATABASE_DATABASE_MAINTENANCE_IMPL_H_
diff --git a/chromium/components/segmentation_platform/internal/database/database_maintenance_impl.cc b/chromium/components/segmentation_platform/internal/database/database_maintenance_impl.cc
index 65b28057bf2..d749d728e91 100644
--- a/chromium/components/segmentation_platform/internal/database/database_maintenance_impl.cc
+++ b/chromium/components/segmentation_platform/internal/database/database_maintenance_impl.cc
@@ -15,10 +15,12 @@
#include "base/callback.h"
#include "base/callback_forward.h"
#include "base/callback_helpers.h"
+#include "base/containers/adapters.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/clock.h"
#include "base/time/time.h"
#include "base/trace_event/typed_macros.h"
+#include "components/segmentation_platform/internal/database/metadata_utils.h"
#include "components/segmentation_platform/internal/database/segment_info_database.h"
#include "components/segmentation_platform/internal/database/signal_database.h"
#include "components/segmentation_platform/internal/database/signal_storage_config.h"
@@ -37,14 +39,13 @@ using CleanupItem = DatabaseMaintenanceImpl::CleanupItem;
namespace {
std::set<SignalIdentifier> CollectAllSignalIdentifiers(
- std::vector<std::pair<OptimizationTarget, proto::SegmentInfo>>
- segment_infos) {
+ const SegmentInfoDatabase::SegmentInfoList& segment_infos) {
std::set<SignalIdentifier> signal_ids;
for (const auto& pair : segment_infos) {
const proto::SegmentInfo& segment_info = pair.second;
const auto& metadata = segment_info.model_metadata();
- for (int i = 0; i < metadata.features_size(); i++) {
- const auto& feature = metadata.features(i);
+ auto features = metadata_utils::GetAllUmaFeatures(metadata);
+ for (auto const& feature : features) {
if (feature.name_hash() != 0 &&
feature.type() != proto::SignalType::UNKNOWN_SIGNAL_TYPE) {
signal_ids.insert(std::make_pair(feature.name_hash(), feature.type()));
@@ -63,11 +64,11 @@ base::OnceClosure LinkTasks(
// of linked list, where the last task refers to a callback that does
// nothing.
base::OnceClosure first_task = base::DoNothing();
- for (auto curr_task = tasks.rbegin(); curr_task != tasks.rend();
- ++curr_task) {
+ for (base::OnceCallback<void(base::OnceClosure)>& curr_task :
+ base::Reversed(tasks)) {
// We need to first perform the current task, and then move on to the next
// task which was previously stored in first_task.
- first_task = base::BindOnce(std::move(*curr_task), std::move(first_task));
+ first_task = base::BindOnce(std::move(curr_task), std::move(first_task));
}
// All tasks can now be found following from the first task.
return first_task;
@@ -110,10 +111,9 @@ void DatabaseMaintenanceImpl::ExecuteMaintenanceTasks() {
}
void DatabaseMaintenanceImpl::OnSegmentInfoCallback(
- std::vector<std::pair<OptimizationTarget, proto::SegmentInfo>>
- segment_infos) {
+ std::unique_ptr<SegmentInfoDatabase::SegmentInfoList> segment_infos) {
std::set<SignalIdentifier> signal_ids =
- CollectAllSignalIdentifiers(segment_infos);
+ CollectAllSignalIdentifiers(*segment_infos);
stats::RecordMaintenanceSignalIdentifierCount(signal_ids.size());
auto all_tasks = GetAllTasks(signal_ids);
diff --git a/chromium/components/segmentation_platform/internal/database/database_maintenance_impl.h b/chromium/components/segmentation_platform/internal/database/database_maintenance_impl.h
index 6b87e377bee..14317a579f7 100644
--- a/chromium/components/segmentation_platform/internal/database/database_maintenance_impl.h
+++ b/chromium/components/segmentation_platform/internal/database/database_maintenance_impl.h
@@ -16,6 +16,7 @@
#include "base/memory/weak_ptr.h"
#include "components/optimization_guide/proto/models.pb.h"
#include "components/segmentation_platform/internal/database/database_maintenance.h"
+#include "components/segmentation_platform/internal/database/segment_info_database.h"
#include "components/segmentation_platform/internal/proto/types.pb.h"
namespace base {
@@ -26,11 +27,7 @@ class Time;
using optimization_guide::proto::OptimizationTarget;
namespace segmentation_platform {
-namespace proto {
-class SegmentInfo;
-} // namespace proto
class SignalDatabase;
-class SegmentInfoDatabase;
class SignalStorageConfig;
// DatabaseMaintenanceImpl is the main implementation of the DatabaseMaintenance
@@ -59,8 +56,7 @@ class DatabaseMaintenanceImpl : public DatabaseMaintenance {
// All tasks currently need information about various segments, so this is
// the callback after the initial database lookup for this data.
void OnSegmentInfoCallback(
- std::vector<std::pair<OptimizationTarget, proto::SegmentInfo>>
- segment_infos);
+ std::unique_ptr<SegmentInfoDatabase::SegmentInfoList> segment_infos);
// Returns an ordered vector of all the tasks we are supposed to perform.
// These are unfinished and also need to be linked to the next task to be
diff --git a/chromium/components/segmentation_platform/internal/database/metadata_utils.cc b/chromium/components/segmentation_platform/internal/database/metadata_utils.cc
index 0ba1fe92496..692a1f38858 100644
--- a/chromium/components/segmentation_platform/internal/database/metadata_utils.cc
+++ b/chromium/components/segmentation_platform/internal/database/metadata_utils.cc
@@ -4,8 +4,12 @@
#include "components/segmentation_platform/internal/database/metadata_utils.h"
+#include <inttypes.h>
+
#include "base/metrics/metrics_hashes.h"
#include "base/notreached.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
#include "base/time/time.h"
#include "components/optimization_guide/proto/models.pb.h"
#include "components/segmentation_platform/internal/database/signal_key.h"
@@ -19,7 +23,7 @@ namespace segmentation_platform {
namespace metadata_utils {
namespace {
-uint64_t GetExpectedTensorLength(const proto::Feature& feature) {
+uint64_t GetExpectedTensorLength(const proto::UMAFeature& feature) {
switch (feature.aggregation()) {
case proto::Aggregation::COUNT:
case proto::Aggregation::COUNT_BOOLEAN:
@@ -40,6 +44,36 @@ uint64_t GetExpectedTensorLength(const proto::Feature& feature) {
return 0;
}
}
+
+std::string FeatureToString(const proto::UMAFeature& feature) {
+ std::string result;
+ if (feature.has_type()) {
+ result = "type:" + proto::SignalType_Name(feature.type()) + ", ";
+ }
+ if (feature.has_name()) {
+ result.append("name:" + feature.name() + ", ");
+ }
+ if (feature.has_name_hash()) {
+ result.append(
+ base::StringPrintf("name_hash:0x%" PRIx64 ", ", feature.name_hash()));
+ }
+ if (feature.has_bucket_count()) {
+ result.append(base::StringPrintf("bucket_count:%" PRIu64 ", ",
+ feature.bucket_count()));
+ }
+ if (feature.has_tensor_length()) {
+ result.append(base::StringPrintf("tensor_length:%" PRIu64 ", ",
+ feature.tensor_length()));
+ }
+ if (feature.has_aggregation()) {
+ result.append("aggregation:" +
+ proto::Aggregation_Name(feature.aggregation()));
+ }
+ if (base::EndsWith(result, ", "))
+ result.resize(result.size() - 2);
+ return result;
+}
+
} // namespace
ValidationResult ValidateSegmentInfo(const proto::SegmentInfo& segment_info) {
@@ -56,13 +90,23 @@ ValidationResult ValidateSegmentInfo(const proto::SegmentInfo& segment_info) {
ValidationResult ValidateMetadata(
const proto::SegmentationModelMetadata& model_metadata) {
+ if (proto::CurrentVersion::METADATA_VERSION <
+ model_metadata.version_info().metadata_min_version()) {
+ return ValidationResult::kVersionNotSupported;
+ }
+
if (model_metadata.time_unit() == proto::TimeUnit::UNKNOWN_TIME_UNIT)
return ValidationResult::kTimeUnitInvald;
+ if (model_metadata.features_size() != 0 &&
+ model_metadata.input_features_size() != 0) {
+ return ValidationResult::kFeatureListInvalid;
+ }
+
return ValidationResult::kValidationSuccess;
}
-ValidationResult ValidateMetadataFeature(const proto::Feature& feature) {
+ValidationResult ValidateMetadataUmaFeature(const proto::UMAFeature& feature) {
if (feature.type() == proto::SignalType::UNKNOWN_SIGNAL_TYPE)
return ValidationResult::kSignalTypeInvalid;
@@ -89,6 +133,26 @@ ValidationResult ValidateMetadataFeature(const proto::Feature& feature) {
return ValidationResult::kValidationSuccess;
}
+ValidationResult ValidateMetadataCustomInput(
+ const proto::CustomInput& custom_input) {
+ if (custom_input.fill_policy() == proto::CustomInput::UNKNOWN_FILL_POLICY) {
+ // If the current fill policy is not supported or not filled, we must use
+ // the given default value list, therefore the default value list must
+ // provide enough input values as specified by tensor length.
+ if (custom_input.tensor_length() > custom_input.default_value_size()) {
+ return ValidationResult::kCustomInputInvalid;
+ }
+ } else if (custom_input.fill_policy() ==
+ proto::CustomInput::FILL_PREDICTION_TIME) {
+ // Current time can only provide up to one input tensor value, so column
+ // weight must not exceed 1.
+ if (custom_input.tensor_length() > 1) {
+ return ValidationResult::kCustomInputInvalid;
+ }
+ }
+ return ValidationResult::kValidationSuccess;
+}
+
ValidationResult ValidateMetadataAndFeatures(
const proto::SegmentationModelMetadata& model_metadata) {
auto metadata_result = ValidateMetadata(model_metadata);
@@ -97,11 +161,26 @@ ValidationResult ValidateMetadataAndFeatures(
for (int i = 0; i < model_metadata.features_size(); ++i) {
auto feature = model_metadata.features(i);
- auto feature_result = ValidateMetadataFeature(feature);
+ auto feature_result = ValidateMetadataUmaFeature(feature);
if (feature_result != ValidationResult::kValidationSuccess)
return feature_result;
}
+ for (int i = 0; i < model_metadata.input_features_size(); ++i) {
+ auto feature = model_metadata.input_features(i);
+ if (feature.has_uma_feature()) {
+ auto feature_result = ValidateMetadataUmaFeature(feature.uma_feature());
+ if (feature_result != ValidationResult::kValidationSuccess)
+ return feature_result;
+ } else if (feature.has_custom_input()) {
+ auto feature_result = ValidateMetadataCustomInput(feature.custom_input());
+ if (feature_result != ValidationResult::kValidationSuccess)
+ return feature_result;
+ } else {
+ return ValidationResult::kFeatureListInvalid;
+ }
+ }
+
return ValidationResult::kValidationSuccess;
}
@@ -117,7 +196,7 @@ ValidationResult ValidateSegmentInfoMetadataAndFeatures(
void SetFeatureNameHashesFromName(
proto::SegmentationModelMetadata* model_metadata) {
for (int i = 0; i < model_metadata->features_size(); ++i) {
- proto::Feature* feature = model_metadata->mutable_features(i);
+ proto::UMAFeature* feature = model_metadata->mutable_features(i);
feature->set_name_hash(base::HashMetricName(feature->name()));
}
}
@@ -172,7 +251,7 @@ base::TimeDelta GetTimeUnit(
case proto::TimeUnit::SECOND:
return base::Seconds(1);
case proto::TimeUnit::UNKNOWN_TIME_UNIT:
- FALLTHROUGH;
+ [[fallthrough]];
default:
NOTREACHED();
return base::TimeDelta();
@@ -222,5 +301,55 @@ int ConvertToDiscreteScore(const std::string& mapping_key,
return discrete_result;
}
+std::string SegmetationModelMetadataToString(
+ const proto::SegmentationModelMetadata& model_metadata) {
+ std::string result;
+ for (const auto& feature : model_metadata.features()) {
+ result.append("feature:{" + FeatureToString(feature) + "}, ");
+ }
+ if (model_metadata.has_time_unit()) {
+ result.append(
+ "time_unit:" + proto::TimeUnit_Name(model_metadata.time_unit()) + ", ");
+ }
+ if (model_metadata.has_bucket_duration()) {
+ result.append(base::StringPrintf("bucket_duration:%" PRIu64 ", ",
+ model_metadata.bucket_duration()));
+ }
+ if (model_metadata.has_signal_storage_length()) {
+ result.append(base::StringPrintf("signal_storage_length:%" PRId64 ", ",
+ model_metadata.signal_storage_length()));
+ }
+ if (model_metadata.has_min_signal_collection_length()) {
+ result.append(
+ base::StringPrintf("min_signal_collection_length:%" PRId64 ", ",
+ model_metadata.min_signal_collection_length()));
+ }
+ if (model_metadata.has_result_time_to_live()) {
+ result.append(base::StringPrintf("result_time_to_live:%" PRId64,
+ model_metadata.result_time_to_live()));
+ }
+
+ if (base::EndsWith(result, ", "))
+ result.resize(result.size() - 2);
+ return result;
+}
+
+std::vector<proto::UMAFeature> GetAllUmaFeatures(
+ const proto::SegmentationModelMetadata& model_metadata) {
+ std::vector<proto::UMAFeature> features;
+ for (int i = 0; i < model_metadata.features_size(); ++i) {
+ features.push_back(model_metadata.features(i));
+ }
+
+ for (int i = 0; i < model_metadata.input_features_size(); ++i) {
+ auto feature = model_metadata.input_features(i);
+ if (feature.has_uma_feature()) {
+ features.push_back(feature.uma_feature());
+ }
+ }
+
+ return features;
+}
+
} // namespace metadata_utils
} // namespace segmentation_platform
diff --git a/chromium/components/segmentation_platform/internal/database/metadata_utils.h b/chromium/components/segmentation_platform/internal/database/metadata_utils.h
index fde92581a4e..56023e1de57 100644
--- a/chromium/components/segmentation_platform/internal/database/metadata_utils.h
+++ b/chromium/components/segmentation_platform/internal/database/metadata_utils.h
@@ -31,7 +31,10 @@ enum class ValidationResult {
kFeatureAggregationNotFound = 7,
kFeatureTensorLengthInvalid = 8,
kFeatureNameHashDoesNotMatchName = 9,
- kMaxValue = kFeatureNameHashDoesNotMatchName,
+ kVersionNotSupported = 10,
+ kFeatureListInvalid = 11,
+ kCustomInputInvalid = 12,
+ kMaxValue = kCustomInputInvalid,
};
// Whether the given SegmentInfo and its metadata is valid to be used for the
@@ -45,7 +48,12 @@ ValidationResult ValidateMetadata(
// Whether the given feature metadata is valid to be used for the current
// segmentation platform.
-ValidationResult ValidateMetadataFeature(const proto::Feature& feature);
+ValidationResult ValidateMetadataUmaFeature(const proto::UMAFeature& feature);
+
+// Whether the given custom input metadata is valid to be used for the current
+// segmentation platform.
+ValidationResult ValidateMetadataCustomInput(
+ const proto::CustomInput& custom_input);
// Whether the given metadata and feature metadata is valid to be used for the
// current segmentation platform.
@@ -84,6 +92,13 @@ int ConvertToDiscreteScore(const std::string& mapping_key,
float input_score,
const proto::SegmentationModelMetadata& metadata);
+std::string SegmetationModelMetadataToString(
+ const proto::SegmentationModelMetadata& model_metadata);
+
+// Helper method to get all UMAFeatures from a segmentation model's metadata.
+std::vector<proto::UMAFeature> GetAllUmaFeatures(
+ const proto::SegmentationModelMetadata& model_metadata);
+
} // namespace metadata_utils
} // namespace segmentation_platform
diff --git a/chromium/components/segmentation_platform/internal/database/metadata_utils_unittest.cc b/chromium/components/segmentation_platform/internal/database/metadata_utils_unittest.cc
index 2692ffd7898..cb0a5140551 100644
--- a/chromium/components/segmentation_platform/internal/database/metadata_utils_unittest.cc
+++ b/chromium/components/segmentation_platform/internal/database/metadata_utils_unittest.cc
@@ -71,51 +71,57 @@ TEST_F(MetadataUtilsTest, MetadataValidation) {
metadata.set_time_unit(proto::DAY);
EXPECT_EQ(metadata_utils::ValidationResult::kValidationSuccess,
metadata_utils::ValidateMetadata(metadata));
+
+ proto::VersionInfo* version_info = metadata.mutable_version_info();
+ version_info->set_metadata_min_version(
+ proto::CurrentVersion::METADATA_VERSION + 1);
+ EXPECT_EQ(metadata_utils::ValidationResult::kVersionNotSupported,
+ metadata_utils::ValidateMetadata(metadata));
}
-TEST_F(MetadataUtilsTest, MetadataFeatureValidation) {
- proto::Feature feature;
+TEST_F(MetadataUtilsTest, MetadataUmaFeatureValidation) {
+ proto::UMAFeature feature;
EXPECT_EQ(metadata_utils::ValidationResult::kSignalTypeInvalid,
- metadata_utils::ValidateMetadataFeature(feature));
+ metadata_utils::ValidateMetadataUmaFeature(feature));
feature.set_type(proto::SignalType::UNKNOWN_SIGNAL_TYPE);
EXPECT_EQ(metadata_utils::ValidationResult::kSignalTypeInvalid,
- metadata_utils::ValidateMetadataFeature(feature));
+ metadata_utils::ValidateMetadataUmaFeature(feature));
// name not required for USER_ACTION.
feature.set_type(proto::SignalType::USER_ACTION);
EXPECT_EQ(metadata_utils::ValidationResult::kFeatureNameHashNotFound,
- metadata_utils::ValidateMetadataFeature(feature));
+ metadata_utils::ValidateMetadataUmaFeature(feature));
feature.set_type(proto::SignalType::HISTOGRAM_ENUM);
EXPECT_EQ(metadata_utils::ValidationResult::kFeatureNameNotFound,
- metadata_utils::ValidateMetadataFeature(feature));
+ metadata_utils::ValidateMetadataUmaFeature(feature));
feature.set_type(proto::SignalType::HISTOGRAM_VALUE);
EXPECT_EQ(metadata_utils::ValidationResult::kFeatureNameNotFound,
- metadata_utils::ValidateMetadataFeature(feature));
+ metadata_utils::ValidateMetadataUmaFeature(feature));
feature.set_name("test name");
EXPECT_EQ(metadata_utils::ValidationResult::kFeatureNameHashNotFound,
- metadata_utils::ValidateMetadataFeature(feature));
+ metadata_utils::ValidateMetadataUmaFeature(feature));
feature.set_name_hash(base::HashMetricName("not the correct name"));
EXPECT_EQ(metadata_utils::ValidationResult::kFeatureNameHashDoesNotMatchName,
- metadata_utils::ValidateMetadataFeature(feature));
+ metadata_utils::ValidateMetadataUmaFeature(feature));
feature.set_name_hash(base::HashMetricName("test name"));
EXPECT_EQ(metadata_utils::ValidationResult::kFeatureAggregationNotFound,
- metadata_utils::ValidateMetadataFeature(feature));
+ metadata_utils::ValidateMetadataUmaFeature(feature));
feature.set_aggregation(proto::Aggregation::COUNT);
// No bucket_count or tensor_length is valid.
EXPECT_EQ(metadata_utils::ValidationResult::kValidationSuccess,
- metadata_utils::ValidateMetadataFeature(feature));
+ metadata_utils::ValidateMetadataUmaFeature(feature));
feature.set_bucket_count(456);
// Aggregation=COUNT requires tensor length = 1.
EXPECT_EQ(metadata_utils::ValidationResult::kFeatureTensorLengthInvalid,
- metadata_utils::ValidateMetadataFeature(feature));
+ metadata_utils::ValidateMetadataUmaFeature(feature));
std::vector<proto::Aggregation> tensor_length_1 = {
proto::Aggregation::COUNT,
@@ -142,21 +148,21 @@ TEST_F(MetadataUtilsTest, MetadataFeatureValidation) {
feature.set_bucket_count(0);
feature.set_tensor_length(1);
EXPECT_EQ(metadata_utils::ValidationResult::kFeatureTensorLengthInvalid,
- metadata_utils::ValidateMetadataFeature(feature));
+ metadata_utils::ValidateMetadataUmaFeature(feature));
feature.set_tensor_length(0);
EXPECT_EQ(metadata_utils::ValidationResult::kValidationSuccess,
- metadata_utils::ValidateMetadataFeature(feature));
+ metadata_utils::ValidateMetadataUmaFeature(feature));
// Tensor length should otherwise always be 1 for this aggregation type.
feature.set_bucket_count(456);
feature.set_tensor_length(10);
EXPECT_EQ(metadata_utils::ValidationResult::kFeatureTensorLengthInvalid,
- metadata_utils::ValidateMetadataFeature(feature));
+ metadata_utils::ValidateMetadataUmaFeature(feature));
feature.set_bucket_count(456);
feature.set_tensor_length(1);
EXPECT_EQ(metadata_utils::ValidationResult::kValidationSuccess,
- metadata_utils::ValidateMetadataFeature(feature));
+ metadata_utils::ValidateMetadataUmaFeature(feature));
}
for (auto aggregation : tensor_length_bucket_count) {
@@ -167,25 +173,54 @@ TEST_F(MetadataUtilsTest, MetadataFeatureValidation) {
feature.set_bucket_count(0);
feature.set_tensor_length(1);
EXPECT_EQ(metadata_utils::ValidationResult::kFeatureTensorLengthInvalid,
- metadata_utils::ValidateMetadataFeature(feature));
+ metadata_utils::ValidateMetadataUmaFeature(feature));
feature.set_tensor_length(0);
EXPECT_EQ(metadata_utils::ValidationResult::kValidationSuccess,
- metadata_utils::ValidateMetadataFeature(feature));
+ metadata_utils::ValidateMetadataUmaFeature(feature));
// Tensor length should otherwise always be equal to bucket_count for this
// aggregation type.
feature.set_bucket_count(456);
feature.set_tensor_length(1);
EXPECT_EQ(metadata_utils::ValidationResult::kFeatureTensorLengthInvalid,
- metadata_utils::ValidateMetadataFeature(feature));
+ metadata_utils::ValidateMetadataUmaFeature(feature));
feature.set_bucket_count(456);
feature.set_tensor_length(456);
EXPECT_EQ(metadata_utils::ValidationResult::kValidationSuccess,
- metadata_utils::ValidateMetadataFeature(feature));
+ metadata_utils::ValidateMetadataUmaFeature(feature));
}
}
+TEST_F(MetadataUtilsTest, MetadataCustomInputValidation) {
+ // Empty custom input has tensor length of 0 and result in a valid input
+ // tensor of length 0.
+ proto::CustomInput custom_input;
+ EXPECT_EQ(metadata_utils::ValidationResult::kValidationSuccess,
+ metadata_utils::ValidateMetadataCustomInput(custom_input));
+
+ // When fill policy is unknown, the custom input is invalid if the default
+ // value list size is smaller than the input tensor length.
+ custom_input.set_tensor_length(1);
+ EXPECT_EQ(metadata_utils::ValidationResult::kCustomInputInvalid,
+ metadata_utils::ValidateMetadataCustomInput(custom_input));
+
+ custom_input.add_default_value(0);
+ EXPECT_EQ(metadata_utils::ValidationResult::kValidationSuccess,
+ metadata_utils::ValidateMetadataCustomInput(custom_input));
+
+ // When fill policy is current time, the custom input is invalid if the tensor
+ // length is bigger than 1.
+ custom_input.set_fill_policy(proto::CustomInput::FILL_PREDICTION_TIME);
+ custom_input.set_tensor_length(2);
+ EXPECT_EQ(metadata_utils::ValidationResult::kCustomInputInvalid,
+ metadata_utils::ValidateMetadataCustomInput(custom_input));
+
+ custom_input.set_tensor_length(1);
+ EXPECT_EQ(metadata_utils::ValidationResult::kValidationSuccess,
+ metadata_utils::ValidateMetadataCustomInput(custom_input));
+}
+
TEST_F(MetadataUtilsTest, ValidateMetadataAndFeatures) {
proto::SegmentationModelMetadata metadata;
metadata.set_time_unit(proto::UNKNOWN_TIME_UNIT);
@@ -228,6 +263,63 @@ TEST_F(MetadataUtilsTest, ValidateMetadataAndFeatures) {
metadata_utils::ValidateMetadataAndFeatures(metadata));
}
+TEST_F(MetadataUtilsTest, ValidateMetadataAndInputFeatures) {
+ proto::SegmentationModelMetadata metadata;
+ metadata.set_time_unit(proto::DAY);
+ EXPECT_EQ(metadata_utils::ValidationResult::kValidationSuccess,
+ metadata_utils::ValidateMetadataAndFeatures(metadata));
+
+ // Verify adding a single input feature adds new requirements.
+ auto* input1 = metadata.add_input_features();
+ EXPECT_EQ(metadata_utils::ValidationResult::kFeatureListInvalid,
+ metadata_utils::ValidateMetadataAndFeatures(metadata));
+
+ proto::UMAFeature* feature1 = input1->mutable_uma_feature();
+ EXPECT_EQ(metadata_utils::ValidationResult::kSignalTypeInvalid,
+ metadata_utils::ValidateMetadataAndFeatures(metadata));
+
+ // Fully flesh out an example input feature and verify validation starts
+ // working again.
+ feature1->set_type(proto::SignalType::USER_ACTION);
+ feature1->set_name_hash(base::HashMetricName("some user action"));
+ feature1->set_aggregation(proto::Aggregation::COUNT);
+ feature1->set_bucket_count(1);
+ feature1->set_tensor_length(1);
+ EXPECT_EQ(metadata_utils::ValidationResult::kValidationSuccess,
+ metadata_utils::ValidateMetadataAndFeatures(metadata));
+
+ // Verify adding another feature adds new requirements again.
+ auto* input2 = metadata.add_input_features();
+ EXPECT_EQ(metadata_utils::ValidationResult::kFeatureListInvalid,
+ metadata_utils::ValidateMetadataAndFeatures(metadata));
+
+ proto::UMAFeature* feature2 = input2->mutable_uma_feature();
+ EXPECT_EQ(metadata_utils::ValidationResult::kSignalTypeInvalid,
+ metadata_utils::ValidateMetadataAndFeatures(metadata));
+
+ // Fully flesh out the second feature and verify validation starts working
+ // again.
+ feature2->set_type(proto::SignalType::HISTOGRAM_VALUE);
+ feature2->set_name("some histogram");
+ feature2->set_name_hash(base::HashMetricName("some histogram"));
+ feature2->set_aggregation(proto::Aggregation::BUCKETED_COUNT);
+ feature2->set_bucket_count(2);
+ feature2->set_tensor_length(2);
+ EXPECT_EQ(metadata_utils::ValidationResult::kValidationSuccess,
+ metadata_utils::ValidateMetadataAndFeatures(metadata));
+
+ // Verify that setting both features and input_features list is invalid.
+ auto* feature3 = metadata.add_features();
+ feature3->set_type(proto::SignalType::HISTOGRAM_VALUE);
+ feature3->set_name("some other histogram");
+ feature3->set_name_hash(base::HashMetricName("some other histogram"));
+ feature3->set_aggregation(proto::Aggregation::BUCKETED_COUNT);
+ feature3->set_bucket_count(2);
+ feature3->set_tensor_length(2);
+ EXPECT_EQ(metadata_utils::ValidationResult::kFeatureListInvalid,
+ metadata_utils::ValidateMetadataAndFeatures(metadata));
+}
+
TEST_F(MetadataUtilsTest, ValidateSegementInfoMetadataAndFeatures) {
proto::SegmentInfo segment_info;
EXPECT_EQ(
@@ -506,4 +598,73 @@ TEST_F(MetadataUtilsTest, CheckMissingDefaultDiscreteMapping) {
metadata));
}
+TEST_F(MetadataUtilsTest, SegmetationModelMetadataToString) {
+ proto::SegmentationModelMetadata metadata;
+ ASSERT_TRUE(
+ metadata_utils::SegmetationModelMetadataToString(metadata).empty());
+
+ proto::UMAFeature feature;
+ feature.set_type(proto::SignalType::UNKNOWN_SIGNAL_TYPE);
+ feature.set_name("test name");
+ feature.set_aggregation(proto::Aggregation::COUNT);
+ feature.set_bucket_count(456);
+ *metadata.add_features() = feature;
+
+ std::string expected =
+ "feature:{type:UNKNOWN_SIGNAL_TYPE, name:test name, bucket_count:456, "
+ "aggregation:COUNT}";
+ ASSERT_EQ(metadata_utils::SegmetationModelMetadataToString(metadata),
+ expected);
+
+ metadata.set_bucket_duration(10);
+ metadata.set_min_signal_collection_length(7);
+ ASSERT_EQ(metadata_utils::SegmetationModelMetadataToString(metadata),
+ expected + ", bucket_duration:10, min_signal_collection_length:7");
+}
+
+TEST_F(MetadataUtilsTest, GetAllUmaFeatures) {
+ proto::SegmentationModelMetadata model_metadata;
+
+ proto::UMAFeature feature1;
+ feature1.set_name("feature1");
+ *model_metadata.add_features() = feature1;
+
+ proto::UMAFeature feature2;
+ feature2.set_name("feature2");
+ *model_metadata.add_features() = feature2;
+
+ std::vector<proto::UMAFeature> expected =
+ metadata_utils::GetAllUmaFeatures(model_metadata);
+
+ ASSERT_EQ(model_metadata.features_size(), (int)expected.size());
+
+ for (int i = 0; i < model_metadata.features_size(); ++i) {
+ ASSERT_EQ(model_metadata.features(i).name(), expected[i].name());
+ }
+}
+
+TEST_F(MetadataUtilsTest, GetAllUmaFeaturesWithInputFeatures) {
+ proto::SegmentationModelMetadata model_metadata;
+
+ auto* input1 = model_metadata.add_input_features();
+ proto::UMAFeature* feature1 = input1->mutable_uma_feature();
+ feature1->set_name("feature1");
+
+ auto* input2 = model_metadata.add_input_features();
+ proto::UMAFeature* feature2 = input2->mutable_uma_feature();
+ feature2->set_name("feature2");
+
+ std::vector<proto::UMAFeature> expected =
+ metadata_utils::GetAllUmaFeatures(model_metadata);
+
+ ASSERT_EQ(model_metadata.input_features_size(), (int)expected.size());
+
+ for (int i = 0; i < model_metadata.input_features_size(); ++i) {
+ if (model_metadata.input_features(i).has_uma_feature()) {
+ ASSERT_EQ(model_metadata.input_features(i).uma_feature().name(),
+ expected[i].name());
+ }
+ }
+}
+
} // namespace segmentation_platform
diff --git a/chromium/components/segmentation_platform/internal/database/segment_info_database.cc b/chromium/components/segmentation_platform/internal/database/segment_info_database.cc
index f35e35cd87a..12a3f46a83d 100644
--- a/chromium/components/segmentation_platform/internal/database/segment_info_database.cc
+++ b/chromium/components/segmentation_platform/internal/database/segment_info_database.cc
@@ -42,14 +42,14 @@ void SegmentInfoDatabase::OnMultipleSegmentInfoLoaded(
MultipleSegmentInfoCallback callback,
bool success,
std::unique_ptr<std::vector<proto::SegmentInfo>> all_infos) {
- std::vector<std::pair<OptimizationTarget, proto::SegmentInfo>> pairs;
+ auto pairs = std::make_unique<SegmentInfoList>();
if (success && all_infos) {
for (auto& info : *all_infos.get()) {
- pairs.emplace_back(std::make_pair(info.segment_id(), std::move(info)));
+ pairs->emplace_back(std::make_pair(info.segment_id(), std::move(info)));
}
}
- std::move(callback).Run(pairs);
+ std::move(callback).Run(std::move(pairs));
}
void SegmentInfoDatabase::GetSegmentInfoForSegments(
diff --git a/chromium/components/segmentation_platform/internal/database/segment_info_database.h b/chromium/components/segmentation_platform/internal/database/segment_info_database.h
index 9687c021895..2c4ab127714 100644
--- a/chromium/components/segmentation_platform/internal/database/segment_info_database.h
+++ b/chromium/components/segmentation_platform/internal/database/segment_info_database.h
@@ -5,6 +5,7 @@
#ifndef COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_DATABASE_SEGMENT_INFO_DATABASE_H_
#define COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_DATABASE_SEGMENT_INFO_DATABASE_H_
+#include <memory>
#include <vector>
#include "base/callback.h"
@@ -28,8 +29,10 @@ class PredictionResult;
class SegmentInfoDatabase {
public:
using SuccessCallback = base::OnceCallback<void(bool)>;
- using MultipleSegmentInfoCallback = base::OnceCallback<void(
- std::vector<std::pair<OptimizationTarget, proto::SegmentInfo>>)>;
+ using SegmentInfoList =
+ std::vector<std::pair<OptimizationTarget, proto::SegmentInfo>>;
+ using MultipleSegmentInfoCallback =
+ base::OnceCallback<void(std::unique_ptr<SegmentInfoList>)>;
using SegmentInfoCallback =
base::OnceCallback<void(absl::optional<proto::SegmentInfo>)>;
using SegmentInfoProtoDb = leveldb_proto::ProtoDatabase<proto::SegmentInfo>;
diff --git a/chromium/components/segmentation_platform/internal/database/segment_info_database_unittest.cc b/chromium/components/segmentation_platform/internal/database/segment_info_database_unittest.cc
index 4f9591071c0..9d49234546f 100644
--- a/chromium/components/segmentation_platform/internal/database/segment_info_database_unittest.cc
+++ b/chromium/components/segmentation_platform/internal/database/segment_info_database_unittest.cc
@@ -46,8 +46,8 @@ class SegmentInfoDatabaseTest : public testing::Test {
~SegmentInfoDatabaseTest() override = default;
void OnGetAllSegments(
- std::vector<std::pair<OptimizationTarget, proto::SegmentInfo>> entries) {
- get_all_segment_result_ = entries;
+ std::unique_ptr<SegmentInfoDatabase::SegmentInfoList> entries) {
+ get_all_segment_result_.swap(entries);
}
void OnGetSegment(absl::optional<proto::SegmentInfo> result) {
@@ -107,9 +107,12 @@ class SegmentInfoDatabaseTest : public testing::Test {
}
}
+ const SegmentInfoDatabase::SegmentInfoList& get_all_segment_result() const {
+ return *get_all_segment_result_;
+ }
+
base::test::TaskEnvironment task_environment_;
- std::vector<std::pair<OptimizationTarget, proto::SegmentInfo>>
- get_all_segment_result_;
+ std::unique_ptr<SegmentInfoDatabase::SegmentInfoList> get_all_segment_result_;
absl::optional<proto::SegmentInfo> get_segment_result_;
std::map<std::string, proto::SegmentInfo> db_entries_;
raw_ptr<leveldb_proto::test::FakeDB<proto::SegmentInfo>> db_{nullptr};
@@ -130,7 +133,7 @@ TEST_F(SegmentInfoDatabaseTest, Get) {
segment_db_->GetAllSegmentInfo(base::BindOnce(
&SegmentInfoDatabaseTest::OnGetAllSegments, base::Unretained(this)));
db_->LoadCallback(true);
- EXPECT_EQ(1u, get_all_segment_result_.size());
+ EXPECT_EQ(1u, get_all_segment_result().size());
// Get a single segment.
segment_db_->GetSegmentInfo(
@@ -172,24 +175,24 @@ TEST_F(SegmentInfoDatabaseTest, Update) {
{kSegmentId2}, base::BindOnce(&SegmentInfoDatabaseTest::OnGetAllSegments,
base::Unretained(this)));
db_->LoadCallback(true);
- EXPECT_EQ(1u, get_all_segment_result_.size());
- EXPECT_EQ(kSegmentId2, get_all_segment_result_[0].first);
+ EXPECT_EQ(1u, get_all_segment_result().size());
+ EXPECT_EQ(kSegmentId2, get_all_segment_result()[0].first);
segment_db_->GetSegmentInfoForSegments(
{kSegmentId}, base::BindOnce(&SegmentInfoDatabaseTest::OnGetAllSegments,
base::Unretained(this)));
db_->LoadCallback(true);
- EXPECT_EQ(1u, get_all_segment_result_.size());
- EXPECT_EQ(kSegmentId, get_all_segment_result_[0].first);
+ EXPECT_EQ(1u, get_all_segment_result().size());
+ EXPECT_EQ(kSegmentId, get_all_segment_result()[0].first);
segment_db_->GetSegmentInfoForSegments(
{kSegmentId, kSegmentId2},
base::BindOnce(&SegmentInfoDatabaseTest::OnGetAllSegments,
base::Unretained(this)));
db_->LoadCallback(true);
- EXPECT_EQ(2u, get_all_segment_result_.size());
- EXPECT_EQ(kSegmentId, get_all_segment_result_[0].first);
- EXPECT_EQ(kSegmentId2, get_all_segment_result_[1].first);
+ EXPECT_EQ(2u, get_all_segment_result().size());
+ EXPECT_EQ(kSegmentId, get_all_segment_result()[0].first);
+ EXPECT_EQ(kSegmentId2, get_all_segment_result()[1].first);
}
TEST_F(SegmentInfoDatabaseTest, WriteResult) {
diff --git a/chromium/components/segmentation_platform/internal/database/signal_key.h b/chromium/components/segmentation_platform/internal/database/signal_key.h
index 19b418c0972..d72fc850a15 100644
--- a/chromium/components/segmentation_platform/internal/database/signal_key.h
+++ b/chromium/components/segmentation_platform/internal/database/signal_key.h
@@ -9,7 +9,6 @@
#include <ostream>
#include <string>
-#include "base/compiler_specific.h"
#include "base/time/time.h"
namespace segmentation_platform {
@@ -70,8 +69,8 @@ class SignalKey {
std::string ToBinary() const;
// Parses a machine readable representation of a SignalKeyInternal into
// a SignalKey. Returns whether the conversion succeeded.
- static bool FromBinary(const std::string& input,
- SignalKey* output) WARN_UNUSED_RESULT;
+ [[nodiscard]] static bool FromBinary(const std::string& input,
+ SignalKey* output);
// The SignalKey prefix in binary format.
std::string GetPrefixInBinary() const;
// Returns a human readable representation of the SignalKey.
diff --git a/chromium/components/segmentation_platform/internal/database/signal_key_internal.h b/chromium/components/segmentation_platform/internal/database/signal_key_internal.h
index fc9b07824c5..e775877bdb0 100644
--- a/chromium/components/segmentation_platform/internal/database/signal_key_internal.h
+++ b/chromium/components/segmentation_platform/internal/database/signal_key_internal.h
@@ -10,8 +10,6 @@
#include <string>
#include <type_traits>
-#include "base/compiler_specific.h"
-
namespace segmentation_platform {
// The SignalKeyInternal is used for identifying a particular record in the
@@ -101,8 +99,8 @@ static_assert(sizeof(SignalKeyInternal) ==
std::string SignalKeyInternalToBinary(const SignalKeyInternal& input);
// Parses a machine readable representation of a SignalKeyInternal into
// a SignalKeyInternal. Returns whether the conversion succeeded.
-bool SignalKeyInternalFromBinary(const std::string& input,
- SignalKeyInternal* output) WARN_UNUSED_RESULT;
+[[nodiscard]] bool SignalKeyInternalFromBinary(const std::string& input,
+ SignalKeyInternal* output);
// Returns a human readable representation of the SignalKeyInternal.
std::string SignalKeyInternalToDebugString(const SignalKeyInternal& input);
@@ -113,9 +111,9 @@ std::string SignalKeyInternalPrefixToBinary(
const SignalKeyInternal::Prefix& input);
// Parses a machine readable representation of a SignalKeyInternal::Prefix into
// a SignalKeyInternal::Prefix. Returns whether the conversion succeeded.
-bool SignalKeyInternalPrefixFromBinary(const std::string& input,
- SignalKeyInternal::Prefix* output)
- WARN_UNUSED_RESULT;
+[[nodiscard]] bool SignalKeyInternalPrefixFromBinary(
+ const std::string& input,
+ SignalKeyInternal::Prefix* output);
// Returns a human readable representation of the SignalKeyInternal::Prefix.
std::string SignalKeyInternalPrefixToDebugString(
const SignalKeyInternal::Prefix& input);
diff --git a/chromium/components/segmentation_platform/internal/database/signal_storage_config.cc b/chromium/components/segmentation_platform/internal/database/signal_storage_config.cc
index f228a602132..bd9c2743626 100644
--- a/chromium/components/segmentation_platform/internal/database/signal_storage_config.cc
+++ b/chromium/components/segmentation_platform/internal/database/signal_storage_config.cc
@@ -83,14 +83,14 @@ bool SignalStorageConfig::MeetsSignalCollectionRequirement(
// Loop through all the signals specified in the model, and check if they have
// been collected long enough.
- for (int i = 0; i < model_metadata.features_size(); ++i) {
- const proto::Feature& feature = model_metadata.features(i);
+ auto features = metadata_utils::GetAllUmaFeatures(model_metadata);
+ for (auto const& feature : features) {
// Skip the signals that has bucket_count set to 0. These ones are only for
// collection purposes and hence don't get used in model evaluation.
if (feature.bucket_count() == 0)
continue;
- if (metadata_utils::ValidateMetadataFeature(feature) !=
+ if (metadata_utils::ValidateMetadataUmaFeature(feature) !=
metadata_utils::ValidationResult::kValidationSuccess) {
continue;
}
@@ -117,9 +117,9 @@ void SignalStorageConfig::OnSignalCollectionStarted(
// Run through the model and calculate for each signal.
bool is_dirty = false;
- for (int i = 0; i < model_metadata.features_size(); ++i) {
- const proto::Feature& feature = model_metadata.features(i);
- if (metadata_utils::ValidateMetadataFeature(feature) !=
+ auto features = metadata_utils::GetAllUmaFeatures(model_metadata);
+ for (auto const& feature : features) {
+ if (metadata_utils::ValidateMetadataUmaFeature(feature) !=
metadata_utils::ValidationResult::kValidationSuccess) {
continue;
}
diff --git a/chromium/components/segmentation_platform/internal/database/signal_storage_config_unittest.cc b/chromium/components/segmentation_platform/internal/database/signal_storage_config_unittest.cc
index 43880fa2a02..92222ace076 100644
--- a/chromium/components/segmentation_platform/internal/database/signal_storage_config_unittest.cc
+++ b/chromium/components/segmentation_platform/internal/database/signal_storage_config_unittest.cc
@@ -80,14 +80,14 @@ TEST_F(SignalStorageConfigTest,
metadata2.set_min_signal_collection_length(4);
// Add a user action feature to the both models.
- proto::Feature* feature = metadata.add_features();
+ proto::UMAFeature* feature = metadata.add_features();
uint64_t name_hash = base::HashMetricName("some user action");
feature->set_type(proto::SignalType::USER_ACTION);
feature->set_name_hash(name_hash);
feature->set_bucket_count(1);
feature->set_tensor_length(1);
feature->set_aggregation(proto::Aggregation::COUNT);
- proto::Feature* feature2 = metadata2.add_features();
+ proto::UMAFeature* feature2 = metadata2.add_features();
feature2->set_type(proto::SignalType::USER_ACTION);
feature2->set_name_hash(name_hash);
feature2->set_bucket_count(1);
diff --git a/chromium/components/segmentation_platform/internal/database/test_segment_info_database.cc b/chromium/components/segmentation_platform/internal/database/test_segment_info_database.cc
index f460c110900..394e3103534 100644
--- a/chromium/components/segmentation_platform/internal/database/test_segment_info_database.cc
+++ b/chromium/components/segmentation_platform/internal/database/test_segment_info_database.cc
@@ -29,7 +29,7 @@ void AddFeature(proto::SegmentInfo* segment_info,
const std::vector<int32_t>& accepted_enum_ids) {
proto::SegmentationModelMetadata* metadata =
segment_info->mutable_model_metadata();
- proto::Feature* feature = metadata->add_features();
+ proto::UMAFeature* feature = metadata->add_features();
feature->set_type(signal_type);
feature->set_name(name);
feature->set_name_hash(base::HashMetricName(name));
@@ -53,18 +53,19 @@ void TestSegmentInfoDatabase::Initialize(SuccessCallback callback) {
void TestSegmentInfoDatabase::GetAllSegmentInfo(
MultipleSegmentInfoCallback callback) {
- std::move(callback).Run(segment_infos_);
+ std::move(callback).Run(
+ std::make_unique<SegmentInfoDatabase::SegmentInfoList>(segment_infos_));
}
void TestSegmentInfoDatabase::GetSegmentInfoForSegments(
const std::vector<OptimizationTarget>& segment_ids,
MultipleSegmentInfoCallback callback) {
- std::vector<std::pair<OptimizationTarget, proto::SegmentInfo>> result;
+ auto result = std::make_unique<SegmentInfoDatabase::SegmentInfoList>();
for (const auto& pair : segment_infos_) {
if (base::Contains(segment_ids, pair.first))
- result.emplace_back(pair);
+ result->emplace_back(pair);
}
- std::move(callback).Run(result);
+ std::move(callback).Run(std::move(result));
}
void TestSegmentInfoDatabase::GetSegmentInfo(OptimizationTarget segment_id,
diff --git a/chromium/components/segmentation_platform/internal/dummy_segmentation_platform_service.cc b/chromium/components/segmentation_platform/internal/dummy_segmentation_platform_service.cc
index 3e7c2a5aaaf..f43f095a64c 100644
--- a/chromium/components/segmentation_platform/internal/dummy_segmentation_platform_service.cc
+++ b/chromium/components/segmentation_platform/internal/dummy_segmentation_platform_service.cc
@@ -7,6 +7,7 @@
#include <string>
#include "base/threading/sequenced_task_runner_handle.h"
+#include "components/segmentation_platform/internal/stats.h"
#include "components/segmentation_platform/public/segment_selection_result.h"
namespace segmentation_platform {
@@ -18,10 +19,17 @@ DummySegmentationPlatformService::~DummySegmentationPlatformService() = default;
void DummySegmentationPlatformService::GetSelectedSegment(
const std::string& segmentation_key,
SegmentSelectionCallback callback) {
+ stats::RecordSegmentSelectionFailure(
+ stats::SegmentationSelectionFailureReason::kPlatformDisabled);
base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), SegmentSelectionResult()));
}
+SegmentSelectionResult DummySegmentationPlatformService::GetCachedSegmentResult(
+ const std::string& segmentation_key) {
+ return SegmentSelectionResult();
+}
+
void DummySegmentationPlatformService::EnableMetrics(
bool signal_collection_allowed) {}
} // namespace segmentation_platform
diff --git a/chromium/components/segmentation_platform/internal/dummy_segmentation_platform_service.h b/chromium/components/segmentation_platform/internal/dummy_segmentation_platform_service.h
index 7102adc7322..67df2fdcf59 100644
--- a/chromium/components/segmentation_platform/internal/dummy_segmentation_platform_service.h
+++ b/chromium/components/segmentation_platform/internal/dummy_segmentation_platform_service.h
@@ -27,6 +27,8 @@ class DummySegmentationPlatformService : public SegmentationPlatformService {
// SegmentationPlatformService overrides.
void GetSelectedSegment(const std::string& segmentation_key,
SegmentSelectionCallback callback) override;
+ SegmentSelectionResult GetCachedSegmentResult(
+ const std::string& segmentation_key) override;
void EnableMetrics(bool signal_collection_allowed) override;
};
diff --git a/chromium/components/segmentation_platform/internal/dummy_segmentation_platform_service_unittest.cc b/chromium/components/segmentation_platform/internal/dummy_segmentation_platform_service_unittest.cc
index accf532976c..645967d8e62 100644
--- a/chromium/components/segmentation_platform/internal/dummy_segmentation_platform_service_unittest.cc
+++ b/chromium/components/segmentation_platform/internal/dummy_segmentation_platform_service_unittest.cc
@@ -47,6 +47,8 @@ TEST_F(DummySegmentationPlatformServiceTest, GetSelectedSegment) {
&DummySegmentationPlatformServiceTest::OnGetSelectedSegment,
base::Unretained(this), loop.QuitClosure(), expected));
loop.Run();
+ ASSERT_EQ(expected,
+ segmentation_platform_service_->GetCachedSegmentResult("some_key"));
}
} // namespace segmentation_platform
diff --git a/chromium/components/segmentation_platform/internal/execution/custom_input_processor.cc b/chromium/components/segmentation_platform/internal/execution/custom_input_processor.cc
new file mode 100644
index 00000000000..6ed98f7aefc
--- /dev/null
+++ b/chromium/components/segmentation_platform/internal/execution/custom_input_processor.cc
@@ -0,0 +1,60 @@
+// Copyright 2022 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.
+
+#include "components/segmentation_platform/internal/execution/custom_input_processor.h"
+
+#include "components/segmentation_platform/internal/database/metadata_utils.h"
+#include "components/segmentation_platform/internal/execution/feature_processor_state.h"
+
+namespace segmentation_platform {
+
+CustomInputProcessor::CustomInputProcessor() = default;
+
+CustomInputProcessor::~CustomInputProcessor() = default;
+
+void CustomInputProcessor::ProcessCustomInput(
+ const proto::CustomInput& custom_input,
+ std::unique_ptr<FeatureProcessorState> feature_processor_state,
+ FeatureListQueryProcessorCallback callback) {
+ // Skip custom input with tensor length of 0.
+ if (custom_input.tensor_length() == 0) {
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(std::move(callback),
+ std::move(feature_processor_state)));
+ return;
+ }
+
+ // Validate the proto::CustomInput metadata.
+ if (metadata_utils::ValidateMetadataCustomInput(custom_input) !=
+ metadata_utils::ValidationResult::kValidationSuccess) {
+ feature_processor_state->SetError();
+ feature_processor_state->RunCallback();
+ return;
+ }
+
+ // TODO(haileywang): Fail validation when the output of custom function is
+ // not float.
+ if (custom_input.fill_policy() == proto::CustomInput::UNKNOWN_FILL_POLICY) {
+ // When prasing a CustomInput object, if the fill policy is not supported by
+ // the current version of the client, the fill policy field will not be
+ // filled. When this happens, the custom input processor will either use
+ // the default values to generate an input tensor or fail the model
+ // execution.
+ feature_processor_state->AppendInputTensor(
+ std::vector<float>(custom_input.default_value().begin(),
+ custom_input.default_value().end()));
+ } else if (custom_input.fill_policy() ==
+ proto::CustomInput::FILL_PREDICTION_TIME) {
+ feature_processor_state->AppendInputTensor(
+ std::vector<float>(1, feature_processor_state->prediction_time()
+ .ToDeltaSinceWindowsEpoch()
+ .InMicroseconds()));
+ }
+
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::BindOnce(std::move(callback), std::move(feature_processor_state)));
+}
+
+} // namespace segmentation_platform
diff --git a/chromium/components/segmentation_platform/internal/execution/custom_input_processor.h b/chromium/components/segmentation_platform/internal/execution/custom_input_processor.h
new file mode 100644
index 00000000000..01952a1e3b6
--- /dev/null
+++ b/chromium/components/segmentation_platform/internal/execution/custom_input_processor.h
@@ -0,0 +1,43 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_EXECUTION_CUSTOM_INPUT_PROCESSOR_H_
+#define COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_EXECUTION_CUSTOM_INPUT_PROCESSOR_H_
+
+#include <vector>
+
+#include "base/callback.h"
+#include "components/segmentation_platform/internal/proto/model_metadata.pb.h"
+
+namespace segmentation_platform {
+class FeatureProcessorState;
+
+// CustomInputProcessor adds support to a larger variety of data type
+// (timestamps, strings mapped to enums, etc), transforming them into valid
+// input tensor to use when executing the ML model.
+class CustomInputProcessor {
+ public:
+ explicit CustomInputProcessor();
+ virtual ~CustomInputProcessor();
+
+ // Disallow copy/assign.
+ CustomInputProcessor(const CustomInputProcessor&) = delete;
+ CustomInputProcessor& operator=(const CustomInputProcessor&) = delete;
+
+ using FeatureListQueryProcessorCallback =
+ base::OnceCallback<void(std::unique_ptr<FeatureProcessorState>)>;
+
+ // Function for processing the next CustomInput type of input for ML model.
+ // When the processing is successful, the feature processor state's input
+ // tensor is updated accordingly, else if an error occurred, the feature
+ // processor state's error flag is set.
+ void ProcessCustomInput(
+ const proto::CustomInput& custom_input,
+ std::unique_ptr<FeatureProcessorState> feature_processor_state,
+ FeatureListQueryProcessorCallback callback);
+};
+
+} // namespace segmentation_platform
+
+#endif // COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_EXECUTION_CUSTOM_INPUT_PROCESSOR_H_
diff --git a/chromium/components/segmentation_platform/internal/execution/feature_list_query_processor.cc b/chromium/components/segmentation_platform/internal/execution/feature_list_query_processor.cc
new file mode 100644
index 00000000000..515e408250b
--- /dev/null
+++ b/chromium/components/segmentation_platform/internal/execution/feature_list_query_processor.cc
@@ -0,0 +1,84 @@
+// Copyright 2022 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.
+
+#include "components/segmentation_platform/internal/execution/feature_list_query_processor.h"
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/memory/weak_ptr.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "base/time/clock.h"
+#include "components/segmentation_platform/internal/database/metadata_utils.h"
+#include "components/segmentation_platform/internal/execution/custom_input_processor.h"
+#include "components/segmentation_platform/internal/execution/feature_processor_state.h"
+#include "components/segmentation_platform/internal/execution/uma_feature_processor.h"
+#include "components/segmentation_platform/internal/proto/model_metadata.pb.h"
+#include "components/segmentation_platform/internal/stats.h"
+
+namespace segmentation_platform {
+
+FeatureListQueryProcessor::FeatureListQueryProcessor(
+ SignalDatabase* signal_database,
+ std::unique_ptr<FeatureAggregator> feature_aggregator)
+ : uma_feature_processor_(signal_database, std::move(feature_aggregator)) {}
+
+FeatureListQueryProcessor::~FeatureListQueryProcessor() = default;
+
+void FeatureListQueryProcessor::ProcessFeatureList(
+ const proto::SegmentationModelMetadata& model_metadata,
+ OptimizationTarget segment_id,
+ base::Time prediction_time,
+ FeatureProcessorCallback callback) {
+ // The total bucket duration is defined by product of the bucket_duration
+ // value and the length of related time_unit field, e.g. 28 * length(DAY).
+ base::TimeDelta time_unit_len = metadata_utils::GetTimeUnit(model_metadata);
+ base::TimeDelta bucket_duration =
+ model_metadata.bucket_duration() * time_unit_len;
+
+ // Grab the metadata for all the features, which will be processed one at a
+ // time, before executing the model.
+ auto input_features = std::make_unique<std::deque<proto::InputFeature>>();
+ for (int i = 0; i < model_metadata.features_size(); ++i) {
+ proto::InputFeature input_feature;
+ input_feature.mutable_uma_feature()->CopyFrom(model_metadata.features(i));
+ input_features->emplace_back(input_feature);
+ }
+ for (int i = 0; i < model_metadata.input_features_size(); ++i)
+ input_features->emplace_back(model_metadata.input_features(i));
+
+ // Capture all the relevant metadata information into a FeatureProcessorState.
+ auto feature_processor_state = std::make_unique<FeatureProcessorState>(
+ prediction_time, bucket_duration, segment_id, std::move(input_features),
+ std::move(callback));
+
+ ProcessNextInputFeature(std::move(feature_processor_state));
+}
+
+void FeatureListQueryProcessor::ProcessNextInputFeature(
+ std::unique_ptr<FeatureProcessorState> feature_processor_state) {
+ // Finished processing all input features.
+ if (feature_processor_state->IsFeatureListEmpty()) {
+ feature_processor_state->RunCallback();
+ return;
+ }
+
+ // Get next input feature to process.
+ proto::InputFeature input_feature =
+ feature_processor_state->PopNextInputFeature();
+
+ if (input_feature.has_uma_feature()) {
+ // Process all the features in-order, starting with the first feature.
+ uma_feature_processor_.ProcessUmaFeature(
+ input_feature.uma_feature(), std::move(feature_processor_state),
+ base::BindOnce(&FeatureListQueryProcessor::ProcessNextInputFeature,
+ weak_ptr_factory_.GetWeakPtr()));
+ } else if (input_feature.has_custom_input()) {
+ custom_input_processor_.ProcessCustomInput(
+ input_feature.custom_input(), std::move(feature_processor_state),
+ base::BindOnce(&FeatureListQueryProcessor::ProcessNextInputFeature,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
+}
+
+} // namespace segmentation_platform
diff --git a/chromium/components/segmentation_platform/internal/execution/feature_list_query_processor.h b/chromium/components/segmentation_platform/internal/execution/feature_list_query_processor.h
new file mode 100644
index 00000000000..1606552b4a9
--- /dev/null
+++ b/chromium/components/segmentation_platform/internal/execution/feature_list_query_processor.h
@@ -0,0 +1,71 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_EXECUTION_FEATURE_LIST_QUERY_PROCESSOR_H_
+#define COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_EXECUTION_FEATURE_LIST_QUERY_PROCESSOR_H_
+
+#include <deque>
+#include <vector>
+
+#include "base/memory/weak_ptr.h"
+#include "components/optimization_guide/proto/models.pb.h"
+#include "components/segmentation_platform/internal/execution/custom_input_processor.h"
+#include "components/segmentation_platform/internal/execution/model_execution_manager_impl.h"
+#include "components/segmentation_platform/internal/execution/uma_feature_processor.h"
+#include "components/segmentation_platform/internal/proto/model_metadata.pb.h"
+
+namespace segmentation_platform {
+class FeatureAggregator;
+class FeatureProcessorState;
+class SignalDatabase;
+
+// FeatureListQueryProcessor takes a segmentation model's metadata, processes
+// each feature in the metadata's feature list in order and computes an input
+// tensor to use when executing the ML model.
+class FeatureListQueryProcessor {
+ public:
+ FeatureListQueryProcessor(
+ SignalDatabase* signal_database,
+ std::unique_ptr<FeatureAggregator> feature_aggregator);
+ virtual ~FeatureListQueryProcessor();
+
+ // Disallow copy/assign.
+ FeatureListQueryProcessor(const FeatureListQueryProcessor&) = delete;
+ FeatureListQueryProcessor& operator=(const FeatureListQueryProcessor&) =
+ delete;
+
+ using FeatureProcessorCallback =
+ base::OnceCallback<void(bool, const std::vector<float>&)>;
+
+ // Given a model's metadata, processes the feature list from the metadata and
+ // computes the input tensor for the ML model. Result is returned through a
+ // callback.
+ // |segment_id| is only used for recording performance metrics. This class
+ // does not need to know about the segment itself. |prediction_time| is the
+ // time at which we predict the model execution should happen.
+ void ProcessFeatureList(
+ const proto::SegmentationModelMetadata& model_metadata,
+ OptimizationTarget segment_id,
+ base::Time prediction_time,
+ FeatureProcessorCallback callback);
+
+ private:
+ // Called by ProcessFeatureList to process the next input feature in the list.
+ // It then delegates the processing to the correct feature processor class
+ // until the feature list is empty.
+ void ProcessNextInputFeature(
+ std::unique_ptr<FeatureProcessorState> feature_processor_state);
+
+ // Feature processor for uma type of input features.
+ UmaFeatureProcessor uma_feature_processor_;
+
+ // Feature processor for uma type of input features.
+ CustomInputProcessor custom_input_processor_;
+
+ base::WeakPtrFactory<FeatureListQueryProcessor> weak_ptr_factory_{this};
+};
+
+} // namespace segmentation_platform
+
+#endif // COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_EXECUTION_FEATURE_LIST_QUERY_PROCESSOR_H_
diff --git a/chromium/components/segmentation_platform/internal/execution/feature_list_query_processor_unittest.cc b/chromium/components/segmentation_platform/internal/execution/feature_list_query_processor_unittest.cc
new file mode 100644
index 00000000000..17201900cb2
--- /dev/null
+++ b/chromium/components/segmentation_platform/internal/execution/feature_list_query_processor_unittest.cc
@@ -0,0 +1,561 @@
+// Copyright 2022 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.
+
+#include "components/segmentation_platform/internal/execution/feature_list_query_processor.h"
+
+#include <memory>
+
+#include "base/bind.h"
+#include "base/metrics/metrics_hashes.h"
+#include "base/run_loop.h"
+#include "base/test/gmock_callback_support.h"
+#include "base/test/simple_test_clock.h"
+#include "base/test/task_environment.h"
+#include "components/segmentation_platform/internal/database/mock_signal_database.h"
+#include "components/segmentation_platform/internal/execution/mock_feature_aggregator.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::test::RunOnceCallback;
+using SignalDatabaseSample = segmentation_platform::SignalDatabase::Sample;
+using testing::_;
+using testing::Return;
+using testing::SetArgReferee;
+
+namespace segmentation_platform {
+
+namespace {
+constexpr base::TimeDelta kOneSecond = base::Seconds(1);
+constexpr base::TimeDelta kTwoSeconds = base::Seconds(2);
+} // namespace
+
+class FeatureListQueryProcessorTest : public testing::Test {
+ public:
+ FeatureListQueryProcessorTest() = default;
+ ~FeatureListQueryProcessorTest() override = default;
+
+ void SetUp() override {
+ signal_database_ = std::make_unique<MockSignalDatabase>();
+ clock_.SetNow(base::Time::Now());
+ segment_id_ = OptimizationTarget::OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB;
+ }
+
+ void TearDown() override {
+ feature_list_query_processor_.reset();
+ // Allow for the background class to be destroyed.
+ RunUntilIdle();
+ }
+
+ void RunUntilIdle() { task_environment_.RunUntilIdle(); }
+
+ void CreateFeatureListQueryProcessor() {
+ auto feature_aggregator = std::make_unique<MockFeatureAggregator>();
+ feature_aggregator_ = feature_aggregator.get();
+ feature_list_query_processor_ = std::make_unique<FeatureListQueryProcessor>(
+ signal_database_.get(), std::move(feature_aggregator));
+ }
+
+ void SetBucketDuration(uint64_t bucket_duration, proto::TimeUnit time_unit) {
+ model_metadata.set_bucket_duration(bucket_duration);
+ model_metadata.set_time_unit(time_unit);
+ }
+
+ base::Time StartTime(base::TimeDelta bucket_duration, int64_t bucket_count) {
+ return clock_.Now() - bucket_duration * bucket_count;
+ }
+
+ void AddUmaFeature(proto::SignalType signal_type,
+ const std::string& name,
+ uint64_t bucket_count,
+ uint64_t tensor_length,
+ proto::Aggregation aggregation,
+ const std::vector<int32_t>& accepted_enum_ids) {
+ auto* input_feature = model_metadata.add_input_features();
+ proto::UMAFeature* uma_feature = input_feature->mutable_uma_feature();
+ uma_feature->set_type(signal_type);
+ uma_feature->set_name(name);
+ uma_feature->set_name_hash(base::HashMetricName(name));
+ uma_feature->set_bucket_count(bucket_count);
+ uma_feature->set_tensor_length(tensor_length);
+ uma_feature->set_aggregation(aggregation);
+
+ for (int32_t accepted_enum_id : accepted_enum_ids)
+ uma_feature->add_enum_ids(accepted_enum_id);
+ }
+
+ void AddUserActionWithProcessingSetup(base::TimeDelta bucket_duration) {
+ // Set up a single user action feature.
+ std::string user_action_name = "some_action";
+ AddUmaFeature(proto::SignalType::USER_ACTION, user_action_name, 2, 1,
+ proto::Aggregation::COUNT, {});
+
+ // When the particular user action is looked up with the correct start time,
+ // end time, and aggregation type, return 3 samples.
+ std::vector<SignalDatabaseSample> samples{
+ {clock_.Now(), 0},
+ {clock_.Now(), 0},
+ {clock_.Now(), 0},
+ };
+
+ EXPECT_CALL(*signal_database_,
+ GetSamples(proto::SignalType::USER_ACTION,
+ base::HashMetricName(user_action_name),
+ StartTime(bucket_duration, 2), clock_.Now(), _))
+ .WillOnce(RunOnceCallback<4>(samples));
+
+ // After retrieving the samples, they should be processed and aggregated.
+ EXPECT_CALL(
+ *feature_aggregator_,
+ Process(proto::SignalType::USER_ACTION, proto::Aggregation::COUNT, 2,
+ clock_.Now(), bucket_duration, samples))
+ .WillOnce(Return(std::vector<float>{3}));
+ }
+
+ void AddCustomInput(int tensor_length,
+ proto::CustomInput::FillPolicy fill_policy,
+ const std::vector<float>& default_values) {
+ auto* input_feature = model_metadata.add_input_features();
+ proto::CustomInput* custom_input = input_feature->mutable_custom_input();
+ custom_input->set_fill_policy(fill_policy);
+ custom_input->set_tensor_length(tensor_length);
+ for (float default_value : default_values)
+ custom_input->add_default_value(default_value);
+ }
+
+ void ExpectProcessedFeatureList(
+ bool expected_error,
+ const std::vector<float>& expected_input_tensor,
+ base::Time prediction_time) {
+ base::RunLoop loop;
+ feature_list_query_processor_->ProcessFeatureList(
+ model_metadata, segment_id_, prediction_time,
+ base::BindOnce(
+ &FeatureListQueryProcessorTest::OnProcessingFinishedCallback,
+ base::Unretained(this), loop.QuitClosure(), expected_error,
+ expected_input_tensor));
+ loop.Run();
+ }
+
+ void ExpectProcessedFeatureList(
+ bool expected_error,
+ const std::vector<float>& expected_input_tensor) {
+ ExpectProcessedFeatureList(expected_error, expected_input_tensor,
+ clock_.Now());
+ }
+
+ void OnProcessingFinishedCallback(
+ base::RepeatingClosure closure,
+ bool expected_error,
+ const std::vector<float>& expected_input_tensor,
+ bool error,
+ const std::vector<float>& input_tensor) {
+ EXPECT_EQ(expected_error, error);
+ EXPECT_EQ(expected_input_tensor, input_tensor);
+ std::move(closure).Run();
+ }
+
+ base::SimpleTestClock clock_;
+ base::test::TaskEnvironment task_environment_;
+ OptimizationTarget segment_id_;
+ proto::SegmentationModelMetadata model_metadata;
+ std::unique_ptr<MockSignalDatabase> signal_database_;
+ raw_ptr<MockFeatureAggregator> feature_aggregator_;
+
+ std::unique_ptr<FeatureListQueryProcessor> feature_list_query_processor_;
+};
+
+TEST_F(FeatureListQueryProcessorTest, InvalidMetadata) {
+ CreateFeatureListQueryProcessor();
+
+ // Initialize with required metadata.
+ SetBucketDuration(3, proto::TimeUnit::HOUR);
+
+ // Set up a single invalid feature.
+ std::string invalid_uma_feature = "invalid_uma_feature";
+ AddUmaFeature(proto::SignalType::UNKNOWN_SIGNAL_TYPE, invalid_uma_feature, 2,
+ 1, proto::Aggregation::COUNT, {});
+
+ // The next step should be to run the feature processor.
+ ExpectProcessedFeatureList(true, std::vector<float>{});
+}
+
+TEST_F(FeatureListQueryProcessorTest, SingleCustomInput) {
+ CreateFeatureListQueryProcessor();
+
+ // Initialize with required metadata.
+ SetBucketDuration(3, proto::TimeUnit::HOUR);
+
+ // Set up a custom input.
+ AddCustomInput(1, proto::CustomInput::FILL_PREDICTION_TIME, {});
+
+ // The next step should be to run the feature processor, the input tensor
+ // should contain the current time.
+ base::Time prediction_time = clock_.Now();
+ ExpectProcessedFeatureList(
+ false,
+ std::vector<float>{static_cast<float>(
+ prediction_time.ToDeltaSinceWindowsEpoch().InMicroseconds())},
+ prediction_time);
+}
+
+TEST_F(FeatureListQueryProcessorTest, DefaultValueCustomInput) {
+ CreateFeatureListQueryProcessor();
+
+ // Initialize with required metadata.
+ SetBucketDuration(3, proto::TimeUnit::HOUR);
+
+ // Set up a custom input.
+ AddCustomInput(2, proto::CustomInput::UNKNOWN_FILL_POLICY, {1, 2});
+
+ // The next step should be to run the feature processor, the input tensor
+ // should contain the default values 1 and 2.
+ ExpectProcessedFeatureList(false, std::vector<float>{1, 2});
+}
+
+TEST_F(FeatureListQueryProcessorTest, SingleUserAction) {
+ CreateFeatureListQueryProcessor();
+
+ // Initialize with required metadata.
+ SetBucketDuration(3, proto::TimeUnit::HOUR);
+ base::TimeDelta bucket_duration = base::Hours(3);
+
+ // Set up a single user action feature.
+ std::string user_action_name_1 = "some_action_1";
+ AddUmaFeature(proto::SignalType::USER_ACTION, user_action_name_1, 2, 1,
+ proto::Aggregation::COUNT, {});
+
+ // When the particular user action is looked up with the correct start time,
+ // end time, and aggregation type, return 3 samples.
+ std::vector<SignalDatabaseSample> samples{
+ {clock_.Now(), 0},
+ {clock_.Now(), 0},
+ {clock_.Now(), 0},
+ };
+ EXPECT_CALL(*signal_database_,
+ GetSamples(proto::SignalType::USER_ACTION,
+ base::HashMetricName(user_action_name_1),
+ StartTime(bucket_duration, 2), clock_.Now(), _))
+ .WillOnce(RunOnceCallback<4>(samples));
+
+ // After retrieving the samples, they should be processed and aggregated.
+ EXPECT_CALL(*feature_aggregator_,
+ Process(proto::SignalType::USER_ACTION, proto::Aggregation::COUNT,
+ 2, clock_.Now(), bucket_duration, samples))
+ .WillOnce(Return(std::vector<float>{3}));
+
+ // The next step should be to run the feature processor.
+ ExpectProcessedFeatureList(false, std::vector<float>{3});
+}
+
+TEST_F(FeatureListQueryProcessorTest, UmaFeaturesAndCustomInputs) {
+ CreateFeatureListQueryProcessor();
+
+ // Initialize with required metadata.
+ SetBucketDuration(3, proto::TimeUnit::HOUR);
+ base::TimeDelta bucket_duration = base::Hours(3);
+
+ // Set up a user action feature.
+ AddUserActionWithProcessingSetup(bucket_duration);
+
+ // Set up a custom input.
+ AddCustomInput(1, proto::CustomInput::FILL_PREDICTION_TIME, {});
+
+ // The next step should be to run the feature processor, the input tensor
+ // should contain 3 and current time.
+ base::Time prediction_time = clock_.Now();
+ ExpectProcessedFeatureList(
+ false,
+ std::vector<float>{
+ 3, static_cast<float>(
+ prediction_time.ToDeltaSinceWindowsEpoch().InMicroseconds())},
+ prediction_time);
+}
+
+TEST_F(FeatureListQueryProcessorTest, UmaFeaturesAndCustomInputsInvalid) {
+ CreateFeatureListQueryProcessor();
+
+ // Initialize with required metadata.
+ SetBucketDuration(3, proto::TimeUnit::HOUR);
+ base::TimeDelta bucket_duration = base::Hours(3);
+
+ // Set up a user action feature.
+ AddUserActionWithProcessingSetup(bucket_duration);
+
+ // Set up an invalid custom input.
+ AddCustomInput(1, proto::CustomInput::UNKNOWN_FILL_POLICY, {});
+
+ // The next step should be to run the feature processor.
+ ExpectProcessedFeatureList(true, std::vector<float>{});
+}
+
+TEST_F(FeatureListQueryProcessorTest, MultipleUmaFeatures) {
+ CreateFeatureListQueryProcessor();
+
+ // Initialize with required metadata.
+ SetBucketDuration(3, proto::TimeUnit::HOUR);
+ base::TimeDelta bucket_duration = base::Hours(3);
+
+ // Set up 3 metadata feature, one of each signal type.
+ std::string user_action_name = "some_user_action";
+ AddUmaFeature(proto::SignalType::USER_ACTION, user_action_name, 2, 1,
+ proto::Aggregation::COUNT, {});
+ std::string histogram_value_name = "some_histogram_value";
+ AddUmaFeature(proto::SignalType::HISTOGRAM_VALUE, histogram_value_name, 3, 1,
+ proto::Aggregation::SUM, {});
+ std::string histogram_enum_name = "some_histogram_enum";
+ AddUmaFeature(proto::SignalType::HISTOGRAM_ENUM, histogram_enum_name, 4, 1,
+ proto::Aggregation::COUNT, {});
+
+ // First uma feature should be the user action.
+ std::vector<SignalDatabaseSample> user_action_samples{
+ {clock_.Now(), 0},
+ {clock_.Now(), 0},
+ {clock_.Now(), 0},
+ };
+ EXPECT_CALL(*signal_database_,
+ GetSamples(proto::SignalType::USER_ACTION,
+ base::HashMetricName(user_action_name),
+ StartTime(bucket_duration, 2), clock_.Now(), _))
+ .WillOnce(RunOnceCallback<4>(user_action_samples));
+ EXPECT_CALL(*feature_aggregator_,
+ Process(proto::SignalType::USER_ACTION, proto::Aggregation::COUNT,
+ 2, clock_.Now(), bucket_duration, user_action_samples))
+ .WillOnce(Return(std::vector<float>{3}));
+
+ // Second uma feature should be the value histogram.
+ std::vector<SignalDatabaseSample> histogram_value_samples{
+ {clock_.Now(), 1},
+ {clock_.Now(), 2},
+ {clock_.Now(), 3},
+ };
+ EXPECT_CALL(*signal_database_,
+ GetSamples(proto::SignalType::HISTOGRAM_VALUE,
+ base::HashMetricName(histogram_value_name),
+ StartTime(bucket_duration, 3), clock_.Now(), _))
+ .WillOnce(RunOnceCallback<4>(histogram_value_samples));
+ EXPECT_CALL(
+ *feature_aggregator_,
+ Process(proto::SignalType::HISTOGRAM_VALUE, proto::Aggregation::SUM, 3,
+ clock_.Now(), bucket_duration, histogram_value_samples))
+ .WillOnce(Return(std::vector<float>{6}));
+
+ // Third uma feature should be the enum histogram.
+ std::vector<SignalDatabaseSample> histogram_enum_samples{
+ {clock_.Now(), 1},
+ {clock_.Now(), 2},
+ {clock_.Now(), 3},
+ {clock_.Now(), 4},
+ };
+ EXPECT_CALL(*signal_database_,
+ GetSamples(proto::SignalType::HISTOGRAM_ENUM,
+ base::HashMetricName(histogram_enum_name),
+ StartTime(bucket_duration, 4), clock_.Now(), _))
+ .WillOnce(RunOnceCallback<4>(histogram_enum_samples));
+ EXPECT_CALL(
+ *feature_aggregator_,
+ Process(proto::SignalType::HISTOGRAM_ENUM, proto::Aggregation::COUNT, 4,
+ clock_.Now(), bucket_duration, histogram_enum_samples))
+ .WillOnce(Return(std::vector<float>{4}));
+
+ // The input tensor should contain all three values: 3, 6, and 4.
+ ExpectProcessedFeatureList(false, std::vector<float>{3, 6, 4});
+}
+
+TEST_F(FeatureListQueryProcessorTest, SkipCollectionOnlyUmaFeatures) {
+ CreateFeatureListQueryProcessor();
+
+ // Initialize with required metadata.
+ SetBucketDuration(3, proto::TimeUnit::HOUR);
+ base::TimeDelta bucket_duration = base::Hours(3);
+
+ // Set up 3 metadata feature, one of each signal type.
+ std::string collected_user_action = "some_user_action";
+ AddUmaFeature(proto::SignalType::USER_ACTION, collected_user_action, 1, 1,
+ proto::Aggregation::COUNT, {});
+ std::string no_collection_user_action = "no_collection_user_action";
+ AddUmaFeature(proto::SignalType::USER_ACTION, no_collection_user_action, 0, 0,
+ proto::Aggregation::SUM, {});
+ std::string no_collection_histogram_value = "no_collection_histogram_value";
+ AddUmaFeature(proto::SignalType::HISTOGRAM_VALUE,
+ no_collection_histogram_value, 0, 0, proto::Aggregation::SUM,
+ {});
+ std::string no_collection_histogram_enum = "no_collection_histogram_enum";
+ AddUmaFeature(proto::SignalType::HISTOGRAM_ENUM, no_collection_histogram_enum,
+ 0, 0, proto::Aggregation::SUM, {});
+ std::string collected_histogram_value = "collected_histogram_value";
+ AddUmaFeature(proto::SignalType::HISTOGRAM_VALUE, collected_histogram_value,
+ 1, 1, proto::Aggregation::SUM, {});
+
+ // The first uma feature in use should be the very first uma feature.
+ std::vector<SignalDatabaseSample> user_action_samples{
+ {clock_.Now(), 0},
+ {clock_.Now(), 0},
+ {clock_.Now(), 0},
+ };
+ EXPECT_CALL(*signal_database_,
+ GetSamples(proto::SignalType::USER_ACTION,
+ base::HashMetricName(collected_user_action),
+ StartTime(bucket_duration, 1), clock_.Now(), _))
+ .WillOnce(RunOnceCallback<4>(user_action_samples));
+ EXPECT_CALL(*feature_aggregator_,
+ Process(proto::SignalType::USER_ACTION, proto::Aggregation::COUNT,
+ 1, clock_.Now(), bucket_duration, user_action_samples))
+ .WillOnce(Return(std::vector<float>{3}));
+
+ // The three uma features in the middle should all be ignored, so the next one
+ // should be the last uma feature.
+ std::vector<SignalDatabaseSample> histogram_value_samples{
+ {clock_.Now(), 1},
+ {clock_.Now(), 2},
+ {clock_.Now(), 3},
+ };
+ EXPECT_CALL(*signal_database_,
+ GetSamples(proto::SignalType::HISTOGRAM_VALUE,
+ base::HashMetricName(collected_histogram_value),
+ StartTime(bucket_duration, 1), clock_.Now(), _))
+ .WillOnce(RunOnceCallback<4>(histogram_value_samples));
+ EXPECT_CALL(
+ *feature_aggregator_,
+ Process(proto::SignalType::HISTOGRAM_VALUE, proto::Aggregation::SUM, 1,
+ clock_.Now(), bucket_duration, histogram_value_samples))
+ .WillOnce(Return(std::vector<float>{6}));
+
+ // The input tensor should contain only the first and last uma feature.
+ ExpectProcessedFeatureList(false, std::vector<float>{3, 6});
+}
+
+TEST_F(FeatureListQueryProcessorTest, SkipNoColumnWeightCustomInput) {
+ CreateFeatureListQueryProcessor();
+
+ // Initialize with required metadata.
+ SetBucketDuration(3, proto::TimeUnit::HOUR);
+
+ // Set up a custom input.
+ AddCustomInput(1, proto::CustomInput::UNKNOWN_FILL_POLICY, {1});
+
+ // Set up a few custom input with tensor length of 0.
+ AddCustomInput(0, proto::CustomInput::UNKNOWN_FILL_POLICY, {2});
+ AddCustomInput(0, proto::CustomInput::UNKNOWN_FILL_POLICY, {3});
+
+ // Set up another custom input with tensor length.
+ AddCustomInput(1, proto::CustomInput::UNKNOWN_FILL_POLICY, {4});
+
+ // The next step should be to run the feature processor, the input tensor
+ // should contain the first and last custom input of 1 and 4.
+ ExpectProcessedFeatureList(false, std::vector<float>{1, 4});
+}
+
+TEST_F(FeatureListQueryProcessorTest, FilteredEnumSamples) {
+ CreateFeatureListQueryProcessor();
+
+ // Initialize with required metadata.
+ SetBucketDuration(3, proto::TimeUnit::HOUR);
+ base::TimeDelta bucket_duration = base::Hours(3);
+
+ // Set up a single enum histogram feature.
+ std::string histogram_enum_name = "some_histogram_enum";
+ std::vector<int32_t> accepted_enum_ids = {2, 4};
+ AddUmaFeature(proto::SignalType::HISTOGRAM_ENUM, histogram_enum_name, 4, 1,
+ proto::Aggregation::COUNT, accepted_enum_ids);
+
+ // When the particular enum histogram is looked up with the correct start
+ // time, end time, and aggregation type, return all 5 samples.
+ std::vector<SignalDatabaseSample> histogram_enum_samples{
+ {clock_.Now(), 1}, {clock_.Now(), 2}, {clock_.Now(), 3},
+ {clock_.Now(), 4}, {clock_.Now(), 5},
+ };
+ EXPECT_CALL(*signal_database_,
+ GetSamples(proto::SignalType::HISTOGRAM_ENUM,
+ base::HashMetricName(histogram_enum_name),
+ StartTime(bucket_duration, 4), clock_.Now(), _))
+ .WillOnce(RunOnceCallback<4>(histogram_enum_samples));
+ // The executor must first filter the enum samples.
+ std::vector<SignalDatabaseSample> filtered_enum_samples{
+ {clock_.Now(), 2},
+ {clock_.Now(), 4},
+ };
+ EXPECT_CALL(*feature_aggregator_,
+ FilterEnumSamples(accepted_enum_ids, histogram_enum_samples))
+ .WillOnce(SetArgReferee<1>(filtered_enum_samples));
+ // Only filtered_enum_samples should be processed.
+ EXPECT_CALL(
+ *feature_aggregator_,
+ Process(proto::SignalType::HISTOGRAM_ENUM, proto::Aggregation::COUNT, 4,
+ clock_.Now(), bucket_duration, filtered_enum_samples))
+ .WillOnce(Return(std::vector<float>{2}));
+
+ // The input tensor should contain a single value.
+ ExpectProcessedFeatureList(false, std::vector<float>{2});
+}
+
+TEST_F(FeatureListQueryProcessorTest, MultipleUmaFeaturesWithMultipleBuckets) {
+ CreateFeatureListQueryProcessor();
+
+ // Initialize with required metadata.
+ SetBucketDuration(3, proto::TimeUnit::HOUR);
+ base::TimeDelta bucket_duration = base::Hours(3);
+
+ // Set up metadata uma features where bucket_count is not equal to 1.
+ std::string user_action_name = "some_user_action";
+ // 3 buckets
+ AddUmaFeature(proto::SignalType::USER_ACTION, user_action_name, 3, 3,
+ proto::Aggregation::BUCKETED_COUNT, {});
+ std::string histogram_value_name = "some_histogram_value";
+ // 4 buckets
+ AddUmaFeature(proto::SignalType::HISTOGRAM_VALUE, histogram_value_name, 4, 4,
+ proto::Aggregation::BUCKETED_COUNT_BOOLEAN, {});
+
+ // First uma feature should be the user action. The timestamp is set to three
+ // different buckets.
+ std::vector<SignalDatabaseSample> user_action_samples{
+ {clock_.Now(), 0},
+ {clock_.Now() - kOneSecond, 0},
+ {clock_.Now() - bucket_duration, 0},
+ {clock_.Now() - bucket_duration - kOneSecond, 0},
+ {clock_.Now() - bucket_duration - kTwoSeconds, 0},
+ {clock_.Now() - bucket_duration * 2, 0},
+ {clock_.Now() - bucket_duration * 2 - kOneSecond, 0},
+ {clock_.Now() - bucket_duration * 2 - kTwoSeconds, 0},
+ };
+ EXPECT_CALL(*signal_database_,
+ GetSamples(proto::SignalType::USER_ACTION,
+ base::HashMetricName(user_action_name),
+ StartTime(bucket_duration, 3), clock_.Now(), _))
+ .WillOnce(RunOnceCallback<4>(user_action_samples));
+ EXPECT_CALL(*feature_aggregator_,
+ Process(proto::SignalType::USER_ACTION,
+ proto::Aggregation::BUCKETED_COUNT, 3, clock_.Now(),
+ bucket_duration, user_action_samples))
+ .WillOnce(Return(std::vector<float>{1, 2, 3}));
+
+ // Second uma feature should be the value histogram. The timestamp is set to
+ // four different buckets.
+ std::vector<SignalDatabaseSample> histogram_value_samples{
+ {clock_.Now(), 1},
+ {clock_.Now() - kOneSecond, 2},
+ {clock_.Now() - bucket_duration, 3},
+ {clock_.Now() - bucket_duration - kOneSecond, 4},
+ {clock_.Now() - bucket_duration - kTwoSeconds, 5},
+ {clock_.Now() - bucket_duration * 2, 6},
+ {clock_.Now() - bucket_duration * 2 - kOneSecond, 7},
+ {clock_.Now() - bucket_duration * 2 - kTwoSeconds, 8},
+ {clock_.Now() - bucket_duration * 3, 9},
+ {clock_.Now() - bucket_duration * 3 - kOneSecond, 10},
+ {clock_.Now() - bucket_duration * 3 - kTwoSeconds, 11},
+ };
+ EXPECT_CALL(*signal_database_,
+ GetSamples(proto::SignalType::HISTOGRAM_VALUE,
+ base::HashMetricName(histogram_value_name),
+ StartTime(bucket_duration, 4), clock_.Now(), _))
+ .WillOnce(RunOnceCallback<4>(histogram_value_samples));
+ EXPECT_CALL(*feature_aggregator_,
+ Process(proto::SignalType::HISTOGRAM_VALUE,
+ proto::Aggregation::BUCKETED_COUNT_BOOLEAN, 4,
+ clock_.Now(), bucket_duration, histogram_value_samples))
+ .WillOnce(Return(std::vector<float>{4, 5, 6, 7}));
+
+ // The input tensor should contain all values flattened to a single vector.
+ ExpectProcessedFeatureList(false, std::vector<float>{1, 2, 3, 4, 5, 6, 7});
+}
+
+} // namespace segmentation_platform
diff --git a/chromium/components/segmentation_platform/internal/execution/feature_processor_state.cc b/chromium/components/segmentation_platform/internal/execution/feature_processor_state.cc
new file mode 100644
index 00000000000..e8c4cba29bc
--- /dev/null
+++ b/chromium/components/segmentation_platform/internal/execution/feature_processor_state.cc
@@ -0,0 +1,47 @@
+// Copyright 2022 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.
+
+#include "components/segmentation_platform/internal/execution/feature_processor_state.h"
+
+namespace segmentation_platform {
+
+FeatureProcessorState::FeatureProcessorState(
+ base::Time prediction_time,
+ base::TimeDelta bucket_duration,
+ OptimizationTarget segment_id,
+ std::unique_ptr<std::deque<proto::InputFeature>> input_features,
+ FeatureListQueryProcessor::FeatureProcessorCallback callback)
+ : prediction_time_(prediction_time),
+ bucket_duration_(bucket_duration),
+ segment_id_(segment_id),
+ input_features_(std::move(input_features)),
+ callback_(std::move(callback)) {}
+
+FeatureProcessorState::~FeatureProcessorState() = default;
+
+void FeatureProcessorState::SetError() {
+ error_ = true;
+ input_tensor_.clear();
+}
+
+proto::InputFeature FeatureProcessorState::PopNextInputFeature() {
+ proto::InputFeature input_feature = std::move(input_features_->front());
+ input_features_->pop_front();
+ return input_feature;
+}
+
+bool FeatureProcessorState::IsFeatureListEmpty() const {
+ return input_features_->empty();
+}
+
+void FeatureProcessorState::RunCallback() {
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(std::move(callback_), error_, input_tensor_));
+}
+
+void FeatureProcessorState::AppendInputTensor(const std::vector<float>& data) {
+ input_tensor_.insert(input_tensor_.end(), data.begin(), data.end());
+}
+
+} // namespace segmentation_platform
diff --git a/chromium/components/segmentation_platform/internal/execution/feature_processor_state.h b/chromium/components/segmentation_platform/internal/execution/feature_processor_state.h
new file mode 100644
index 00000000000..bfc498663f0
--- /dev/null
+++ b/chromium/components/segmentation_platform/internal/execution/feature_processor_state.h
@@ -0,0 +1,73 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_EXECUTION_FEATURE_PROCESSOR_STATE_H_
+#define COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_EXECUTION_FEATURE_PROCESSOR_STATE_H_
+
+#include <deque>
+#include <vector>
+
+#include "base/time/clock.h"
+#include "components/optimization_guide/proto/models.pb.h"
+#include "components/segmentation_platform/internal/execution/feature_list_query_processor.h"
+#include "components/segmentation_platform/internal/proto/model_metadata.pb.h"
+
+namespace segmentation_platform {
+
+// FeatureProcessorState is responsible for storing all necessary state during
+// the processing of a model's metadata.
+class FeatureProcessorState {
+ public:
+ FeatureProcessorState(
+ base::Time prediction_time,
+ base::TimeDelta bucket_duration,
+ OptimizationTarget segment_id,
+ std::unique_ptr<std::deque<proto::InputFeature>> input_features,
+ FeatureListQueryProcessor::FeatureProcessorCallback callback);
+ virtual ~FeatureProcessorState();
+
+ // Disallow copy/assign.
+ FeatureProcessorState(const FeatureProcessorState&) = delete;
+ FeatureProcessorState& operator=(const FeatureProcessorState&) = delete;
+
+ // Getters.
+ base::TimeDelta bucket_duration() const { return bucket_duration_; }
+
+ base::Time prediction_time() const { return prediction_time_; }
+
+ OptimizationTarget segment_id() const { return segment_id_; }
+
+ // Returns and pops the next input feature in the feature list.
+ proto::InputFeature PopNextInputFeature();
+
+ // Sets an error to the current feature processor state.
+ void SetError();
+
+ // Returns whether the input feature list is empty.
+ bool IsFeatureListEmpty() const;
+
+ // Run the callback stored in the current feature processor state.
+ void RunCallback();
+
+ // Update the input tensor vector.
+ void AppendInputTensor(const std::vector<float>& data);
+ void AppendInputTensor(float data);
+
+ private:
+ const base::Time prediction_time_;
+ const base::TimeDelta bucket_duration_;
+ const OptimizationTarget segment_id_;
+ std::unique_ptr<std::deque<proto::InputFeature>> input_features_;
+
+ // Feature processing results.
+ std::vector<float> input_tensor_;
+ bool error_{false};
+
+ // Callback to return feature processing results to model execution manager.
+ FeatureListQueryProcessor::FeatureProcessorCallback callback_;
+};
+
+} // namespace segmentation_platform
+
+#endif // COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_EXECUTION_FEATURE_PROCESSOR_STATE_H_
diff --git a/chromium/components/segmentation_platform/internal/execution/mock_feature_aggregator.cc b/chromium/components/segmentation_platform/internal/execution/mock_feature_aggregator.cc
new file mode 100644
index 00000000000..1aa1ab859ae
--- /dev/null
+++ b/chromium/components/segmentation_platform/internal/execution/mock_feature_aggregator.cc
@@ -0,0 +1,12 @@
+// Copyright 2022 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.
+
+#include "components/segmentation_platform/internal/execution/mock_feature_aggregator.h"
+
+namespace segmentation_platform {
+
+MockFeatureAggregator::MockFeatureAggregator() = default;
+MockFeatureAggregator::~MockFeatureAggregator() = default;
+
+} // namespace segmentation_platform \ No newline at end of file
diff --git a/chromium/components/segmentation_platform/internal/execution/mock_feature_aggregator.h b/chromium/components/segmentation_platform/internal/execution/mock_feature_aggregator.h
new file mode 100644
index 00000000000..29bb25675ec
--- /dev/null
+++ b/chromium/components/segmentation_platform/internal/execution/mock_feature_aggregator.h
@@ -0,0 +1,38 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_EXECUTION_MOCK_FEATURE_AGGREGATOR_H_
+#define COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_EXECUTION_MOCK_FEATURE_AGGREGATOR_H_
+
+#include <vector>
+
+#include "components/segmentation_platform/internal/execution/feature_aggregator.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace segmentation_platform {
+
+// Mock of feature aggregator class. Used for testing.
+class MockFeatureAggregator : public FeatureAggregator {
+ public:
+ MockFeatureAggregator();
+ ~MockFeatureAggregator() override;
+ MOCK_METHOD(std::vector<float>,
+ Process,
+ (proto::SignalType signal_type,
+ proto::Aggregation aggregation,
+ uint64_t bucket_count,
+ const base::Time& end_time,
+ const base::TimeDelta& bucket_duration,
+ const std::vector<SignalDatabase::Sample>& samples),
+ (const override));
+ MOCK_METHOD(void,
+ FilterEnumSamples,
+ (const std::vector<int32_t>& accepted_enum_ids,
+ std::vector<SignalDatabase::Sample>& samples),
+ (const override));
+};
+
+} // namespace segmentation_platform
+
+#endif // COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_EXECUTION_MOCK_FEATURE_AGGREGATOR_H_ \ No newline at end of file
diff --git a/chromium/components/segmentation_platform/internal/execution/model_execution_manager_factory.cc b/chromium/components/segmentation_platform/internal/execution/model_execution_manager_factory.cc
index d6d8e28a1f3..17979f06d81 100644
--- a/chromium/components/segmentation_platform/internal/execution/model_execution_manager_factory.cc
+++ b/chromium/components/segmentation_platform/internal/execution/model_execution_manager_factory.cc
@@ -11,7 +11,7 @@
#include "base/task/sequenced_task_runner.h"
#include "components/optimization_guide/machine_learning_tflite_buildflags.h"
#include "components/optimization_guide/proto/models.pb.h"
-#include "components/segmentation_platform/internal/execution/feature_aggregator.h"
+#include "components/segmentation_platform/internal/execution/feature_list_query_processor.h"
#include "components/segmentation_platform/internal/execution/model_execution_manager.h"
#if BUILDFLAG(BUILD_WITH_TFLITE_LIB)
@@ -30,11 +30,15 @@ class OptimizationGuideModelProvider;
} // namespace optimization_guide
namespace segmentation_platform {
-class FeatureAggregator;
class SegmentInfoDatabase;
class SignalDatabase;
#if BUILDFLAG(BUILD_WITH_TFLITE_LIB)
+
+const char kSegmentationModelMetadataTypeUrl[] =
+ "type.googleapis.com/"
+ "google.internal.chrome.optimizationguide.v1.SegmentationModelMetadata";
+
// CreateModelHandler makes it possible to pass in any creator of the
// SegmentationModelHandler, which makes it possible to create mock versions.
std::unique_ptr<SegmentationModelHandler> CreateModelHandler(
@@ -43,9 +47,18 @@ std::unique_ptr<SegmentationModelHandler> CreateModelHandler(
optimization_guide::proto::OptimizationTarget optimization_target,
const SegmentationModelHandler::ModelUpdatedCallback&
model_updated_callback) {
+ // Preparing the version data to be sent to server along with the request to
+ // download the model.
+ optimization_guide::proto::Any any_metadata;
+ any_metadata.set_type_url(kSegmentationModelMetadataTypeUrl);
+ proto::SegmentationModelMetadata model_metadata;
+ proto::VersionInfo* version_info = model_metadata.mutable_version_info();
+ version_info->set_metadata_cur_version(
+ proto::CurrentVersion::METADATA_VERSION);
+ model_metadata.SerializeToString(any_metadata.mutable_value());
return std::make_unique<SegmentationModelHandler>(
model_provider, background_task_runner, optimization_target,
- model_updated_callback);
+ model_updated_callback, std::move(any_metadata));
}
#endif // BUILDFLAG(BUILD_WITH_TFLITE_LIB)
@@ -56,7 +69,7 @@ std::unique_ptr<ModelExecutionManager> CreateModelExecutionManager(
base::Clock* clock,
SegmentInfoDatabase* segment_database,
SignalDatabase* signal_database,
- std::unique_ptr<FeatureAggregator> feature_aggregator,
+ FeatureListQueryProcessor* feature_list_query_processor,
const ModelExecutionManager::SegmentationModelUpdatedCallback&
model_updated_callback) {
#if BUILDFLAG(BUILD_WITH_TFLITE_LIB)
@@ -64,7 +77,7 @@ std::unique_ptr<ModelExecutionManager> CreateModelExecutionManager(
segment_ids,
base::BindRepeating(&CreateModelHandler, model_provider,
background_task_runner),
- clock, segment_database, signal_database, std::move(feature_aggregator),
+ clock, segment_database, signal_database, feature_list_query_processor,
model_updated_callback);
#else
return std::make_unique<DummyModelExecutionManager>();
diff --git a/chromium/components/segmentation_platform/internal/execution/model_execution_manager_factory.h b/chromium/components/segmentation_platform/internal/execution/model_execution_manager_factory.h
index 3f4ee4f88cd..1000adc084d 100644
--- a/chromium/components/segmentation_platform/internal/execution/model_execution_manager_factory.h
+++ b/chromium/components/segmentation_platform/internal/execution/model_execution_manager_factory.h
@@ -22,7 +22,7 @@ class OptimizationGuideModelProvider;
} // namespace optimization_guide
namespace segmentation_platform {
-class FeatureAggregator;
+class FeatureListQueryProcessor;
class SegmentInfoDatabase;
class SignalDatabase;
@@ -37,7 +37,7 @@ std::unique_ptr<ModelExecutionManager> CreateModelExecutionManager(
base::Clock* clock,
SegmentInfoDatabase* segment_database,
SignalDatabase* signal_database,
- std::unique_ptr<FeatureAggregator> feature_aggregator,
+ FeatureListQueryProcessor* feature_list_query_processor,
const ModelExecutionManager::SegmentationModelUpdatedCallback&
model_updated_callback);
diff --git a/chromium/components/segmentation_platform/internal/execution/model_execution_manager_factory_unittest.cc b/chromium/components/segmentation_platform/internal/execution/model_execution_manager_factory_unittest.cc
index 120486e14c6..e2ed3251955 100644
--- a/chromium/components/segmentation_platform/internal/execution/model_execution_manager_factory_unittest.cc
+++ b/chromium/components/segmentation_platform/internal/execution/model_execution_manager_factory_unittest.cc
@@ -15,9 +15,11 @@
#include "base/time/time.h"
#include "components/optimization_guide/core/test_optimization_guide_model_provider.h"
#include "components/optimization_guide/proto/models.pb.h"
+#include "components/segmentation_platform/internal/database/mock_signal_database.h"
#include "components/segmentation_platform/internal/database/signal_database.h"
#include "components/segmentation_platform/internal/database/test_segment_info_database.h"
#include "components/segmentation_platform/internal/execution/feature_aggregator_impl.h"
+#include "components/segmentation_platform/internal/execution/feature_list_query_processor.h"
#include "components/segmentation_platform/internal/execution/model_execution_status.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -31,7 +33,8 @@ class ModelExecutionManagerFactoryTest : public testing::Test {
optimization_guide_model_provider_ = std::make_unique<
optimization_guide::TestOptimizationGuideModelProvider>();
segment_database_ = std::make_unique<test::TestSegmentInfoDatabase>();
- feature_aggregator_ = std::make_unique<FeatureAggregatorImpl>();
+ feature_list_query_processor_ = std::make_unique<FeatureListQueryProcessor>(
+ &mock_signal_database_, std::make_unique<FeatureAggregatorImpl>());
test_clock_.SetNow(base::Time::Now());
}
@@ -46,8 +49,8 @@ class ModelExecutionManagerFactoryTest : public testing::Test {
optimization_guide_model_provider_;
base::SimpleTestClock test_clock_;
std::unique_ptr<test::TestSegmentInfoDatabase> segment_database_;
- std::unique_ptr<SignalDatabase> signal_database_;
- std::unique_ptr<FeatureAggregatorImpl> feature_aggregator_;
+ MockSignalDatabase mock_signal_database_;
+ std::unique_ptr<FeatureListQueryProcessor> feature_list_query_processor_;
};
TEST_F(ModelExecutionManagerFactoryTest, CreateModelExecutionManager) {
@@ -55,8 +58,8 @@ TEST_F(ModelExecutionManagerFactoryTest, CreateModelExecutionManager) {
optimization_guide_model_provider_.get(),
task_environment_.GetMainThreadTaskRunner(),
{OptimizationTarget::OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB},
- &test_clock_, segment_database_.get(), signal_database_.get(),
- std::move(feature_aggregator_), base::DoNothing());
+ &test_clock_, segment_database_.get(), &mock_signal_database_,
+ feature_list_query_processor_.get(), base::DoNothing());
// This should work regardless of whether a DummyModelExecutionManager or
// ModelExecutionManagerImpl is returned.
CHECK(model_execution_manager);
diff --git a/chromium/components/segmentation_platform/internal/execution/model_execution_manager_impl.cc b/chromium/components/segmentation_platform/internal/execution/model_execution_manager_impl.cc
index ab3fbf38619..04f06f24498 100644
--- a/chromium/components/segmentation_platform/internal/execution/model_execution_manager_impl.cc
+++ b/chromium/components/segmentation_platform/internal/execution/model_execution_manager_impl.cc
@@ -21,7 +21,7 @@
#include "components/optimization_guide/proto/models.pb.h"
#include "components/segmentation_platform/internal/database/metadata_utils.h"
#include "components/segmentation_platform/internal/database/signal_database.h"
-#include "components/segmentation_platform/internal/execution/feature_aggregator.h"
+#include "components/segmentation_platform/internal/execution/feature_list_query_processor.h"
#include "components/segmentation_platform/internal/execution/model_execution_manager.h"
#include "components/segmentation_platform/internal/execution/model_execution_status.h"
#include "components/segmentation_platform/internal/execution/segmentation_model_handler.h"
@@ -29,6 +29,7 @@
#include "components/segmentation_platform/internal/proto/model_metadata.pb.h"
#include "components/segmentation_platform/internal/proto/model_prediction.pb.h"
#include "components/segmentation_platform/internal/proto/types.pb.h"
+#include "components/segmentation_platform/internal/segmentation_ukm_helper.h"
#include "components/segmentation_platform/internal/stats.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/perfetto/include/perfetto/tracing/track.h"
@@ -75,10 +76,7 @@ struct ModelExecutionManagerImpl::ExecutionState {
OptimizationTarget segment_id;
raw_ptr<SegmentationModelHandler> model_handler = nullptr;
ModelExecutionCallback callback;
- base::TimeDelta bucket_duration;
- std::deque<proto::Feature> features;
std::vector<float> input_tensor;
- base::Time end_time;
base::Time total_execution_start_time;
base::Time model_execution_start_time;
};
@@ -97,34 +95,19 @@ ModelExecutionManagerImpl::ModelExecutionTraceEvent::
perfetto::Track::FromPointer(&state));
}
-struct ModelExecutionManagerImpl::FeatureState {
- FeatureState() = default;
- ~FeatureState() = default;
-
- // Disallow copy/assign.
- FeatureState(const FeatureState&) = delete;
- FeatureState& operator=(const FeatureState&) = delete;
-
- proto::SignalType signal_type;
- proto::Aggregation aggregation;
- absl::optional<std::vector<int32_t>> accepted_enum_ids;
- uint64_t bucket_count;
- uint64_t tensor_length;
-};
-
ModelExecutionManagerImpl::ModelExecutionManagerImpl(
const base::flat_set<OptimizationTarget>& segment_ids,
ModelHandlerCreator model_handler_creator,
base::Clock* clock,
SegmentInfoDatabase* segment_database,
SignalDatabase* signal_database,
- std::unique_ptr<FeatureAggregator> feature_aggregator,
+ FeatureListQueryProcessor* feature_list_query_processor,
const SegmentationModelUpdatedCallback& model_updated_callback)
: clock_(clock),
segment_database_(segment_database),
signal_database_(signal_database),
- feature_aggregator_(std::move(feature_aggregator)),
model_updated_callback_(model_updated_callback) {
+ feature_list_query_processor_ = feature_list_query_processor;
for (OptimizationTarget segment_id : segment_ids) {
model_handlers_.emplace(std::make_pair(
segment_id,
@@ -177,135 +160,28 @@ void ModelExecutionManagerImpl::OnSegmentInfoFetchedForExecution(
return;
}
- // The total bucket duration is defined by product of the bucket_duration
- // value and the length of related time_unit field, e.g. 28 * length(DAY).
- const auto& model_metadata = segment_info->model_metadata();
- uint64_t bucket_duration = model_metadata.bucket_duration();
- base::TimeDelta time_unit_len = metadata_utils::GetTimeUnit(model_metadata);
- state->bucket_duration = bucket_duration * time_unit_len;
-
- // Now that we have just fetched the metadata, set the end_time to be shared
- // across all features, so we get a consistent picture.
- state->end_time = clock_->Now();
-
- // Grab the metadata for all the features, which will be processed one at a
- // time, before executing the model.
- for (int i = 0; i < model_metadata.features_size(); ++i)
- state->features.emplace_back(model_metadata.features(i));
-
- // Process all the features in-order, starting with the first feature.
- ProcessFeatures(std::move(state));
-}
-
-void ModelExecutionManagerImpl::ProcessFeatures(
- std::unique_ptr<ExecutionState> state) {
- ModelExecutionTraceEvent trace_event(
- "ModelExecutionManagerImpl::ProcessFeatures", *state);
- // When there are no more features to process, we are done, so we execute the
- // model.
- if (state->features.empty()) {
- ExecuteModel(std::move(state));
- return;
- }
-
- proto::Feature feature;
- do {
- // Copy and pop the next feature.
- feature = state->features.front();
- state->features.pop_front();
-
- // Validate the proto::Feature metadata.
- if (metadata_utils::ValidateMetadataFeature(feature) !=
- metadata_utils::ValidationResult::kValidationSuccess) {
- RunModelExecutionCallback(std::move(state), 0,
- ModelExecutionStatus::kInvalidMetadata);
- return;
- }
- } while (feature.bucket_count() == 0); // Skip collection-only features.
-
- // Capture all relevant metadata for the current proto::Feature into the
- // FeatureState.
- auto feature_state = std::make_unique<FeatureState>();
- feature_state->signal_type = feature.type();
- feature_state->aggregation = feature.aggregation();
- feature_state->bucket_count = feature.bucket_count();
- feature_state->tensor_length = feature.tensor_length();
-
- auto name_hash = feature.name_hash();
-
- // Enum histograms can optionally only accept some of the enum values.
- // While the proto::Feature is available, capture a vector of the accepted
- // enum values. An empty vector is ignored (all values are considered
- // accepted).
- if (feature_state->signal_type == proto::SignalType::HISTOGRAM_ENUM) {
- std::vector<int32_t> accepted_enum_ids{};
- for (int i = 0; i < feature.enum_ids_size(); ++i)
- accepted_enum_ids.emplace_back(feature.enum_ids(i));
-
- feature_state->accepted_enum_ids = absl::make_optional(accepted_enum_ids);
- }
-
- // Only fetch data that is relevant for the current proto::Feature, since
- // the FeatureAggregator assumes that only relevant data is given to it.
- base::TimeDelta duration =
- state->bucket_duration * feature_state->bucket_count;
- base::Time start_time = state->end_time - duration;
-
- // Fetch the relevant samples for the current proto::Feature. Once the result
- // has come back, it will be processed and inserted into the
- // ExecutorState::input_tensor and will then invoke ProcessFeatures(...)
- // again to ensure we continue until all features have been processed.
- // Note: All parameters from the ExecutorState need to be captured locally
- // before invoking GetSamples, because the state is moved with the callback,
- // and the order of the move and accessing the members while invoking
- // GetSamples is not guaranteed.
- auto signal_type = feature_state->signal_type;
- auto end_time = state->end_time;
- signal_database_->GetSamples(
- signal_type, name_hash, start_time, end_time,
- base::BindOnce(&ModelExecutionManagerImpl::OnGetSamplesForFeature,
- weak_ptr_factory_.GetWeakPtr(), std::move(state),
- std::move(feature_state)));
+ OptimizationTarget segment_id = state->segment_id;
+ feature_list_query_processor_->ProcessFeatureList(
+ segment_info->model_metadata(), segment_id, clock_->Now(),
+ base::BindOnce(
+ &ModelExecutionManagerImpl::OnProcessingFeatureListComplete,
+ weak_ptr_factory_.GetWeakPtr(), std::move(state)));
}
-void ModelExecutionManagerImpl::OnGetSamplesForFeature(
+void ModelExecutionManagerImpl::OnProcessingFeatureListComplete(
std::unique_ptr<ExecutionState> state,
- std::unique_ptr<FeatureState> feature_state,
- std::vector<SignalDatabase::Sample> samples) {
- ModelExecutionTraceEvent trace_event(
- "ModelExecutionManagerImpl::OnGetSamplesForFeature", *state);
- base::Time process_start_time = clock_->Now();
- // HISTOGRAM_ENUM features might require us to filter out the result to only
- // keep enum values that match the accepted list. If the accepted list is'
- // empty, all histogram enum values are kept.
- // The SignalDatabase does not currently support this type of data filter,
- // so instead we are doing this here.
- if (feature_state->signal_type == proto::SignalType::HISTOGRAM_ENUM) {
- DCHECK(feature_state->accepted_enum_ids.has_value());
- feature_aggregator_->FilterEnumSamples(*feature_state->accepted_enum_ids,
- samples);
+ bool error,
+ const std::vector<float>& input_tensor) {
+ if (error) {
+ // Validation error occurred on model's metadata.
+ RunModelExecutionCallback(std::move(state), 0,
+ ModelExecutionStatus::kInvalidMetadata);
+ return;
}
+ state->input_tensor.insert(state->input_tensor.end(), input_tensor.begin(),
+ input_tensor.end());
- // We now have all the data required to process a single feature, so we can
- // process it synchronously, and insert it into the
- // ExecutorState::input_tensor so we can later pass it to the ML model
- // executor.
- std::vector<float> feature_data = feature_aggregator_->Process(
- feature_state->signal_type, feature_state->aggregation,
- feature_state->bucket_count, state->end_time, state->bucket_duration,
- samples);
- DCHECK_EQ(feature_state->tensor_length, feature_data.size());
- state->input_tensor.insert(state->input_tensor.end(), feature_data.begin(),
- feature_data.end());
-
- stats::RecordModelExecutionDurationFeatureProcessing(
- state->segment_id, clock_->Now() - process_start_time);
-
- // Continue with the rest of the features.
- base::SequencedTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::BindOnce(&ModelExecutionManagerImpl::ProcessFeatures,
- weak_ptr_factory_.GetWeakPtr(), std::move(state)));
+ ExecuteModel(std::move(state));
}
void ModelExecutionManagerImpl::ExecuteModel(
@@ -349,6 +225,11 @@ void ModelExecutionManagerImpl::OnModelExecutionComplete(
if (result.has_value()) {
VLOG(1) << "Segmentation model result: " << *result;
stats::RecordModelExecutionResult(state->segment_id, result.value());
+ if (state->model_handler->GetModelInfo()) {
+ SegmentationUkmHelper::GetInstance()->RecordModelExecutionResult(
+ state->segment_id, state->model_handler->GetModelInfo()->GetVersion(),
+ state->input_tensor, result.value());
+ }
RunModelExecutionCallback(std::move(state), *result,
ModelExecutionStatus::kSuccess);
} else {
@@ -380,7 +261,8 @@ void ModelExecutionManagerImpl::OnSegmentationModelUpdated(
return;
}
- // Set or overwrite name hashes for metadata features based on the name field.
+ // Set or overwrite name hashes for metadata features based on the name
+ // field.
metadata_utils::SetFeatureNameHashesFromName(&metadata);
auto validation = metadata_utils::ValidateMetadataAndFeatures(metadata);
@@ -442,8 +324,8 @@ void ModelExecutionManagerImpl::OnSegmentInfoFetchedForModelUpdate(
stats::RecordModelDeliveryMetadataFeatureCount(
segment_id, new_segment_info.model_metadata().features_size());
- // Now that we've merged the old and the new SegmentInfo, we want to store the
- // new version in the database.
+ // Now that we've merged the old and the new SegmentInfo, we want to store
+ // the new version in the database.
segment_database_->UpdateSegment(
segment_id, absl::make_optional(new_segment_info),
base::BindOnce(&ModelExecutionManagerImpl::OnUpdatedSegmentInfoStored,
@@ -459,7 +341,8 @@ void ModelExecutionManagerImpl::OnUpdatedSegmentInfoStored(
if (!success)
return;
- // We are now ready to receive requests for execution, so invoke the callback.
+ // We are now ready to receive requests for execution, so invoke the
+ // callback.
model_updated_callback_.Run(std::move(segment_info));
}
diff --git a/chromium/components/segmentation_platform/internal/execution/model_execution_manager_impl.h b/chromium/components/segmentation_platform/internal/execution/model_execution_manager_impl.h
index 271ac601388..5ad78b2e39a 100644
--- a/chromium/components/segmentation_platform/internal/execution/model_execution_manager_impl.h
+++ b/chromium/components/segmentation_platform/internal/execution/model_execution_manager_impl.h
@@ -29,7 +29,7 @@ class Clock;
} // namespace base
namespace segmentation_platform {
-class FeatureAggregator;
+class FeatureListQueryProcessor;
class SignalDatabase;
namespace proto {
@@ -62,7 +62,7 @@ class ModelExecutionManagerImpl : public ModelExecutionManager {
base::Clock* clock,
SegmentInfoDatabase* segment_database,
SignalDatabase* signal_database,
- std::unique_ptr<FeatureAggregator> feature_aggregator,
+ FeatureListQueryProcessor* feature_list_query_processor,
const SegmentationModelUpdatedCallback& model_updated_callback);
~ModelExecutionManagerImpl() override;
@@ -79,7 +79,6 @@ class ModelExecutionManagerImpl : public ModelExecutionManager {
FRIEND_TEST_ALL_PREFIXES(SegmentationPlatformServiceImplTest,
InitializationFlow);
struct ExecutionState;
- struct FeatureState;
struct ModelExecutionTraceEvent;
// Callback method for when the SegmentInfo (segment metadata) has been
@@ -88,25 +87,19 @@ class ModelExecutionManagerImpl : public ModelExecutionManager {
std::unique_ptr<ExecutionState> state,
absl::optional<proto::SegmentInfo> segment_info);
- // ProcessFeatures is the core function for processing all the required ML
- // features in the correct order. It fetches samples for one feature at a
- // time, makes sure the data is processed, and then is invoked again to
- // process the next feature.
- void ProcessFeatures(std::unique_ptr<ExecutionState> state);
-
- // Callback method for when all relevant samples for a particular feature has
- // been loaded. Processes the samples, and inserts them into the input tensor
- // that is later given to the ML execution.
- void OnGetSamplesForFeature(std::unique_ptr<ExecutionState> state,
- std::unique_ptr<FeatureState> feature_state,
- std::vector<SignalDatabase::Sample> samples);
-
- // ExecuteModel takes the current input tensor and passes it to the ML model
- // for execution.
+ // Callback method for when the processing of the model metadata's feature
+ // list has completed, which either result in an error or a valid input tensor
+ // for executing the model.
+ void OnProcessingFeatureListComplete(std::unique_ptr<ExecutionState> state,
+ bool error,
+ const std::vector<float>& input_tensor);
+
+ // ExecuteModel takes the current input tensor and passes it to the ML
+ // model for execution.
void ExecuteModel(std::unique_ptr<ExecutionState> state);
- // Callback method for when the model execution has completed which gives the
- // end result to the initial ModelExecutionCallback passed to
+ // Callback method for when the model execution has completed which gives
+ // the end result to the initial ModelExecutionCallback passed to
// ExecuteModel(...).
void OnModelExecutionComplete(std::unique_ptr<ExecutionState> state,
const absl::optional<float>& result);
@@ -127,15 +120,15 @@ class ModelExecutionManagerImpl : public ModelExecutionManager {
// Callback after fetching the current SegmentInfo from the
// SegmentInfoDatabase. This is part of the flow for informing the
// SegmentationModelUpdatedCallback about a changed model.
- // Merges the PredictionResult from the previously stored SegmentInfo with the
- // newly updated one, and stores the new version in the DB.
+ // Merges the PredictionResult from the previously stored SegmentInfo with
+ // the newly updated one, and stores the new version in the DB.
void OnSegmentInfoFetchedForModelUpdate(
optimization_guide::proto::OptimizationTarget segment_id,
proto::SegmentationModelMetadata metadata,
absl::optional<proto::SegmentInfo> segment_info);
- // Callback after storing the updated version of the SegmentInfo. Responsible
- // for invoking the SegmentationModelUpdatedCallback.
+ // Callback after storing the updated version of the SegmentInfo.
+ // Responsible for invoking the SegmentationModelUpdatedCallback.
void OnUpdatedSegmentInfoStored(proto::SegmentInfo segment_info,
bool success);
@@ -152,8 +145,8 @@ class ModelExecutionManagerImpl : public ModelExecutionManager {
// Main signal database for user actions and histograms.
raw_ptr<SignalDatabase> signal_database_;
- // The FeatureAggregator aggregates all the data based on metadata and input.
- std::unique_ptr<FeatureAggregator> feature_aggregator_;
+ // Feature list processor for processing a model metadata's feature list.
+ raw_ptr<FeatureListQueryProcessor> feature_list_query_processor_;
// Invoked whenever there is an update to any of the relevant ML models.
SegmentationModelUpdatedCallback model_updated_callback_;
diff --git a/chromium/components/segmentation_platform/internal/execution/model_execution_manager_impl_unittest.cc b/chromium/components/segmentation_platform/internal/execution/model_execution_manager_impl_unittest.cc
index c1ebaf017aa..54f4b290f5a 100644
--- a/chromium/components/segmentation_platform/internal/execution/model_execution_manager_impl_unittest.cc
+++ b/chromium/components/segmentation_platform/internal/execution/model_execution_manager_impl_unittest.cc
@@ -25,6 +25,8 @@
#include "components/segmentation_platform/internal/database/signal_database.h"
#include "components/segmentation_platform/internal/database/test_segment_info_database.h"
#include "components/segmentation_platform/internal/execution/feature_aggregator.h"
+#include "components/segmentation_platform/internal/execution/feature_list_query_processor.h"
+#include "components/segmentation_platform/internal/execution/mock_feature_aggregator.h"
#include "components/segmentation_platform/internal/execution/model_execution_manager.h"
#include "components/segmentation_platform/internal/execution/model_execution_status.h"
#include "components/segmentation_platform/internal/execution/segmentation_model_handler.h"
@@ -43,11 +45,6 @@ using testing::SetArgReferee;
namespace segmentation_platform {
using Sample = SignalDatabase::Sample;
-namespace {
-constexpr base::TimeDelta kOneSecond = base::Seconds(1);
-constexpr base::TimeDelta kTwoSeconds = base::Seconds(2);
-} // namespace
-
class MockSegmentInfoDatabase : public test::TestSegmentInfoDatabase {
public:
MOCK_METHOD(void, Initialize, (SuccessCallback callback), (override));
@@ -89,7 +86,8 @@ class MockSegmentationModelHandler : public SegmentationModelHandler {
: SegmentationModelHandler(model_provider,
background_task_runner,
optimization_target,
- model_updated_callback) {}
+ model_updated_callback,
+ absl::nullopt) {}
MOCK_METHOD(void,
ExecuteModelWithInput,
@@ -100,25 +98,6 @@ class MockSegmentationModelHandler : public SegmentationModelHandler {
MOCK_METHOD(bool, ModelAvailable, (), (const override));
};
-class MockFeatureAggregator : public FeatureAggregator {
- public:
- MockFeatureAggregator() = default;
- MOCK_METHOD(std::vector<float>,
- Process,
- (proto::SignalType signal_type,
- proto::Aggregation aggregation,
- uint64_t bucket_count,
- const base::Time& end_time,
- const base::TimeDelta& bucket_duration,
- const std::vector<Sample>& samples),
- (const override));
- MOCK_METHOD(void,
- FilterEnumSamples,
- (const std::vector<int32_t>& accepted_enum_ids,
- std::vector<Sample>& samples),
- (const override));
-};
-
class ModelExecutionManagerTest : public testing::Test {
public:
ModelExecutionManagerTest() = default;
@@ -144,13 +123,14 @@ class ModelExecutionManagerTest : public testing::Test {
const ModelExecutionManager::SegmentationModelUpdatedCallback& callback) {
auto feature_aggregator = std::make_unique<MockFeatureAggregator>();
feature_aggregator_ = feature_aggregator.get();
-
+ feature_list_query_processor_ = std::make_unique<FeatureListQueryProcessor>(
+ signal_database_.get(), std::move(feature_aggregator));
model_execution_manager_ = std::make_unique<ModelExecutionManagerImpl>(
segment_ids,
base::BindRepeating(&ModelExecutionManagerTest::CreateModelHandler,
base::Unretained(this)),
&clock_, segment_database_.get(), signal_database_.get(),
- std::move(feature_aggregator), callback);
+ feature_list_query_processor_.get(), callback);
}
std::unique_ptr<SegmentationModelHandler> CreateModelHandler(
@@ -208,6 +188,7 @@ class ModelExecutionManagerTest : public testing::Test {
std::unique_ptr<MockSignalDatabase> signal_database_;
raw_ptr<MockFeatureAggregator> feature_aggregator_;
+ std::unique_ptr<FeatureListQueryProcessor> feature_list_query_processor_;
std::unique_ptr<ModelExecutionManagerImpl> model_execution_manager_;
};
@@ -228,52 +209,6 @@ TEST_F(ModelExecutionManagerTest, MetadataTests) {
ExecuteModel(std::make_pair(0, ModelExecutionStatus::kInvalidMetadata));
}
-TEST_F(ModelExecutionManagerTest, SingleUserAction) {
- auto segment_id =
- OptimizationTarget::OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB;
- auto unrelated_segment_id =
- optimization_guide::proto::OPTIMIZATION_TARGET_SEGMENTATION_SHARE;
- CreateModelExecutionManager({segment_id, unrelated_segment_id},
- base::DoNothing());
-
- // Initialize with required metadata.
- segment_database_->SetBucketDuration(segment_id, 3, proto::TimeUnit::HOUR);
- base::TimeDelta bucket_duration = base::Hours(3);
-
- // Set up a single user action feature.
- std::string user_action_name_1 = "some_action_1";
- segment_database_->AddUserActionFeature(segment_id, user_action_name_1, 2, 1,
- proto::Aggregation::COUNT);
-
- // When the particular user action is looked up with the correct start time,
- // end time, and aggregation type, return 3 samples.
- std::vector<Sample> samples{
- {clock_.Now(), 0},
- {clock_.Now(), 0},
- {clock_.Now(), 0},
- };
- EXPECT_CALL(*signal_database_,
- GetSamples(proto::SignalType::USER_ACTION,
- base::HashMetricName(user_action_name_1),
- StartTime(bucket_duration, 2), clock_.Now(), _))
- .WillOnce(RunOnceCallback<4>(samples));
-
- // After retrieving the samples, they should be processed and aggregated.
- EXPECT_CALL(*feature_aggregator_,
- Process(proto::SignalType::USER_ACTION, proto::Aggregation::COUNT,
- 2, clock_.Now(), bucket_duration, samples))
- .WillOnce(Return(std::vector<float>{3}));
-
- // The next step should be to execute the model.
- EXPECT_CALL(FindHandler(segment_id), ModelAvailable())
- .WillRepeatedly(Return(true));
- EXPECT_CALL(FindHandler(segment_id),
- ExecuteModelWithInput(_, std::vector<float>{3}))
- .WillOnce(RunOnceCallback<0>(absl::make_optional(0.8)));
-
- ExecuteModel(std::make_pair(0.8, ModelExecutionStatus::kSuccess));
-}
-
TEST_F(ModelExecutionManagerTest, ModelNotReady) {
auto segment_id =
OptimizationTarget::OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB;
@@ -288,289 +223,6 @@ TEST_F(ModelExecutionManagerTest, ModelNotReady) {
ExecuteModel(std::make_pair(0, ModelExecutionStatus::kExecutionError));
}
-TEST_F(ModelExecutionManagerTest, MultipleFeatures) {
- auto segment_id =
- OptimizationTarget::OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB;
- CreateModelExecutionManager({segment_id}, base::DoNothing());
-
- // Initialize with required metadata.
- segment_database_->SetBucketDuration(segment_id, 3, proto::TimeUnit::HOUR);
- base::TimeDelta bucket_duration = base::Hours(3);
-
- // Set up 3 metadata feature, one of each signal type.
- std::string user_action_name = "some_user_action";
- segment_database_->AddUserActionFeature(segment_id, user_action_name, 2, 1,
- proto::Aggregation::COUNT);
- std::string histogram_value_name = "some_histogram_value";
- segment_database_->AddHistogramValueFeature(segment_id, histogram_value_name,
- 3, 1, proto::Aggregation::SUM);
- std::string histogram_enum_name = "some_histogram_enum";
- segment_database_->AddHistogramEnumFeature(segment_id, histogram_enum_name, 4,
- 1, proto::Aggregation::COUNT, {});
-
- // First feature should be the user action.
- std::vector<Sample> user_action_samples{
- {clock_.Now(), 0},
- {clock_.Now(), 0},
- {clock_.Now(), 0},
- };
- EXPECT_CALL(*signal_database_,
- GetSamples(proto::SignalType::USER_ACTION,
- base::HashMetricName(user_action_name),
- StartTime(bucket_duration, 2), clock_.Now(), _))
- .WillOnce(RunOnceCallback<4>(user_action_samples));
- EXPECT_CALL(*feature_aggregator_,
- Process(proto::SignalType::USER_ACTION, proto::Aggregation::COUNT,
- 2, clock_.Now(), bucket_duration, user_action_samples))
- .WillOnce(Return(std::vector<float>{3}));
-
- // Second feature should be the value histogram.
- std::vector<Sample> histogram_value_samples{
- {clock_.Now(), 1},
- {clock_.Now(), 2},
- {clock_.Now(), 3},
- };
- EXPECT_CALL(*signal_database_,
- GetSamples(proto::SignalType::HISTOGRAM_VALUE,
- base::HashMetricName(histogram_value_name),
- StartTime(bucket_duration, 3), clock_.Now(), _))
- .WillOnce(RunOnceCallback<4>(histogram_value_samples));
- EXPECT_CALL(
- *feature_aggregator_,
- Process(proto::SignalType::HISTOGRAM_VALUE, proto::Aggregation::SUM, 3,
- clock_.Now(), bucket_duration, histogram_value_samples))
- .WillOnce(Return(std::vector<float>{6}));
-
- // Third feature should be the value histogram.
- std::vector<Sample> histogram_enum_samples{
- {clock_.Now(), 1},
- {clock_.Now(), 2},
- {clock_.Now(), 3},
- {clock_.Now(), 4},
- };
- EXPECT_CALL(*signal_database_,
- GetSamples(proto::SignalType::HISTOGRAM_ENUM,
- base::HashMetricName(histogram_enum_name),
- StartTime(bucket_duration, 4), clock_.Now(), _))
- .WillOnce(RunOnceCallback<4>(histogram_enum_samples));
- EXPECT_CALL(
- *feature_aggregator_,
- Process(proto::SignalType::HISTOGRAM_ENUM, proto::Aggregation::COUNT, 4,
- clock_.Now(), bucket_duration, histogram_enum_samples))
- .WillOnce(Return(std::vector<float>{4}));
-
- // The input tensor should contain all three values: 3, 6, and 4.
- EXPECT_CALL(FindHandler(segment_id), ModelAvailable())
- .WillRepeatedly(Return(true));
- EXPECT_CALL(FindHandler(segment_id),
- ExecuteModelWithInput(_, std::vector<float>{3, 6, 4}))
- .WillOnce(RunOnceCallback<0>(absl::make_optional(0.8)));
-
- ExecuteModel(std::make_pair(0.8, ModelExecutionStatus::kSuccess));
-}
-
-TEST_F(ModelExecutionManagerTest, SkipCollectionOnlyFeatures) {
- auto segment_id =
- OptimizationTarget::OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB;
- CreateModelExecutionManager({segment_id}, base::DoNothing());
-
- // Initialize with required metadata.
- segment_database_->SetBucketDuration(segment_id, 3, proto::TimeUnit::HOUR);
- base::TimeDelta bucket_duration = base::Hours(3);
-
- // Set up 3 metadata feature, one of each signal type.
- std::string collected_user_action = "some_user_action";
- segment_database_->AddUserActionFeature(segment_id, collected_user_action, 1,
- 1, proto::Aggregation::COUNT);
- std::string no_collection_user_action = "no_collection_user_action";
- segment_database_->AddUserActionFeature(segment_id, no_collection_user_action,
- 0, 0, proto::Aggregation::SUM);
- std::string no_collection_histogram_value = "no_collection_histogram_value";
- segment_database_->AddHistogramValueFeature(
- segment_id, no_collection_histogram_value, 0, 0, proto::Aggregation::SUM);
- std::string no_collection_histogram_enum = "no_collection_histogram_enum";
- segment_database_->AddHistogramEnumFeature(segment_id,
- no_collection_histogram_enum, 0, 0,
- proto::Aggregation::SUM, {});
- std::string collected_histogram_value = "collected_histogram_value";
- segment_database_->AddHistogramValueFeature(
- segment_id, collected_histogram_value, 1, 1, proto::Aggregation::SUM);
-
- // The first feature in use should be the very first feature.
- std::vector<Sample> user_action_samples{
- {clock_.Now(), 0},
- {clock_.Now(), 0},
- {clock_.Now(), 0},
- };
- EXPECT_CALL(*signal_database_,
- GetSamples(proto::SignalType::USER_ACTION,
- base::HashMetricName(collected_user_action),
- StartTime(bucket_duration, 1), clock_.Now(), _))
- .WillOnce(RunOnceCallback<4>(user_action_samples));
- EXPECT_CALL(*feature_aggregator_,
- Process(proto::SignalType::USER_ACTION, proto::Aggregation::COUNT,
- 1, clock_.Now(), bucket_duration, user_action_samples))
- .WillOnce(Return(std::vector<float>{3}));
-
- // The three features in the middle should all be ignored, so the next one
- // should be the last feature.
- std::vector<Sample> histogram_value_samples{
- {clock_.Now(), 1},
- {clock_.Now(), 2},
- {clock_.Now(), 3},
- };
- EXPECT_CALL(*signal_database_,
- GetSamples(proto::SignalType::HISTOGRAM_VALUE,
- base::HashMetricName(collected_histogram_value),
- StartTime(bucket_duration, 1), clock_.Now(), _))
- .WillOnce(RunOnceCallback<4>(histogram_value_samples));
- EXPECT_CALL(
- *feature_aggregator_,
- Process(proto::SignalType::HISTOGRAM_VALUE, proto::Aggregation::SUM, 1,
- clock_.Now(), bucket_duration, histogram_value_samples))
- .WillOnce(Return(std::vector<float>{6}));
-
- // The input tensor should contain only the first and last feature.
- EXPECT_CALL(FindHandler(segment_id), ModelAvailable())
- .WillRepeatedly(Return(true));
- EXPECT_CALL(FindHandler(segment_id),
- ExecuteModelWithInput(_, std::vector<float>{3, 6}))
- .WillOnce(RunOnceCallback<0>(absl::make_optional(0.8)));
-
- ExecuteModel(std::make_pair(0.8, ModelExecutionStatus::kSuccess));
-}
-
-TEST_F(ModelExecutionManagerTest, FilteredEnumSamples) {
- auto segment_id =
- OptimizationTarget::OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB;
- CreateModelExecutionManager({segment_id}, base::DoNothing());
-
- // Initialize with required metadata.
- segment_database_->SetBucketDuration(segment_id, 3, proto::TimeUnit::HOUR);
- base::TimeDelta bucket_duration = base::Hours(3);
-
- // Set up a single enum histogram feature.
- std::string histogram_enum_name = "some_histogram_enum";
- std::vector<int32_t> accepted_enum_ids = {2, 4};
- segment_database_->AddHistogramEnumFeature(segment_id, histogram_enum_name, 4,
- 1, proto::Aggregation::COUNT,
- accepted_enum_ids);
-
- // When the particular enum histogram is looked up with the correct start
- // time, end time, and aggregation type, return all 5 samples.
- std::vector<Sample> histogram_enum_samples{
- {clock_.Now(), 1}, {clock_.Now(), 2}, {clock_.Now(), 3},
- {clock_.Now(), 4}, {clock_.Now(), 5},
- };
- EXPECT_CALL(*signal_database_,
- GetSamples(proto::SignalType::HISTOGRAM_ENUM,
- base::HashMetricName(histogram_enum_name),
- StartTime(bucket_duration, 4), clock_.Now(), _))
- .WillOnce(RunOnceCallback<4>(histogram_enum_samples));
- // The executor must first filter the enum samples.
- std::vector<Sample> filtered_enum_samples{
- {clock_.Now(), 2},
- {clock_.Now(), 4},
- };
- EXPECT_CALL(*feature_aggregator_,
- FilterEnumSamples(accepted_enum_ids, histogram_enum_samples))
- .WillOnce(SetArgReferee<1>(filtered_enum_samples));
- // Only filtered_enum_samples should be processed.
- EXPECT_CALL(
- *feature_aggregator_,
- Process(proto::SignalType::HISTOGRAM_ENUM, proto::Aggregation::COUNT, 4,
- clock_.Now(), bucket_duration, filtered_enum_samples))
- .WillOnce(Return(std::vector<float>{2}));
-
- // The input tensor should contain a single value.
- EXPECT_CALL(FindHandler(segment_id), ModelAvailable())
- .WillRepeatedly(Return(true));
- EXPECT_CALL(FindHandler(segment_id),
- ExecuteModelWithInput(_, std::vector<float>{2}))
- .WillOnce(RunOnceCallback<0>(absl::make_optional(0.8)));
-
- ExecuteModel(std::make_pair(0.8, ModelExecutionStatus::kSuccess));
-}
-
-TEST_F(ModelExecutionManagerTest, MultipleFeaturesWithMultipleBuckets) {
- auto segment_id =
- OptimizationTarget::OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB;
- CreateModelExecutionManager({segment_id}, base::DoNothing());
-
- // Initialize with required metadata.
- segment_database_->SetBucketDuration(segment_id, 3, proto::TimeUnit::HOUR);
- base::TimeDelta bucket_duration = base::Hours(3);
-
- // Set up metadata features where bucket_count is not equal to 1.
- std::string user_action_name = "some_user_action";
- // 3 buckets
- segment_database_->AddUserActionFeature(segment_id, user_action_name, 3, 3,
- proto::Aggregation::BUCKETED_COUNT);
- std::string histogram_value_name = "some_histogram_value";
- // 4 buckets
- segment_database_->AddHistogramValueFeature(
- segment_id, histogram_value_name, 4, 4,
- proto::Aggregation::BUCKETED_COUNT_BOOLEAN);
-
- // First feature should be the user action. The timestamp is set to three
- // different buckets.
- std::vector<Sample> user_action_samples{
- {clock_.Now(), 0},
- {clock_.Now() - kOneSecond, 0},
- {clock_.Now() - bucket_duration, 0},
- {clock_.Now() - bucket_duration - kOneSecond, 0},
- {clock_.Now() - bucket_duration - kTwoSeconds, 0},
- {clock_.Now() - bucket_duration * 2, 0},
- {clock_.Now() - bucket_duration * 2 - kOneSecond, 0},
- {clock_.Now() - bucket_duration * 2 - kTwoSeconds, 0},
- };
- EXPECT_CALL(*signal_database_,
- GetSamples(proto::SignalType::USER_ACTION,
- base::HashMetricName(user_action_name),
- StartTime(bucket_duration, 3), clock_.Now(), _))
- .WillOnce(RunOnceCallback<4>(user_action_samples));
- EXPECT_CALL(*feature_aggregator_,
- Process(proto::SignalType::USER_ACTION,
- proto::Aggregation::BUCKETED_COUNT, 3, clock_.Now(),
- bucket_duration, user_action_samples))
- .WillOnce(Return(std::vector<float>{1, 2, 3}));
-
- // Second feature should be the value histogram. The timestamp is set to four
- // different buckets.
- std::vector<Sample> histogram_value_samples{
- {clock_.Now(), 1},
- {clock_.Now() - kOneSecond, 2},
- {clock_.Now() - bucket_duration, 3},
- {clock_.Now() - bucket_duration - kOneSecond, 4},
- {clock_.Now() - bucket_duration - kTwoSeconds, 5},
- {clock_.Now() - bucket_duration * 2, 6},
- {clock_.Now() - bucket_duration * 2 - kOneSecond, 7},
- {clock_.Now() - bucket_duration * 2 - kTwoSeconds, 8},
- {clock_.Now() - bucket_duration * 3, 9},
- {clock_.Now() - bucket_duration * 3 - kOneSecond, 10},
- {clock_.Now() - bucket_duration * 3 - kTwoSeconds, 11},
- };
- EXPECT_CALL(*signal_database_,
- GetSamples(proto::SignalType::HISTOGRAM_VALUE,
- base::HashMetricName(histogram_value_name),
- StartTime(bucket_duration, 4), clock_.Now(), _))
- .WillOnce(RunOnceCallback<4>(histogram_value_samples));
- EXPECT_CALL(*feature_aggregator_,
- Process(proto::SignalType::HISTOGRAM_VALUE,
- proto::Aggregation::BUCKETED_COUNT_BOOLEAN, 4,
- clock_.Now(), bucket_duration, histogram_value_samples))
- .WillOnce(Return(std::vector<float>{4, 5, 6, 7}));
-
- // The input tensor should contain all values flattened to a single vector.
- EXPECT_CALL(FindHandler(segment_id), ModelAvailable())
- .WillRepeatedly(Return(true));
- EXPECT_CALL(FindHandler(segment_id),
- ExecuteModelWithInput(_, std::vector<float>{1, 2, 3, 4, 5, 6, 7}))
- .WillOnce(RunOnceCallback<0>(absl::make_optional(0.8)));
-
- ExecuteModel(std::make_pair(0.8, ModelExecutionStatus::kSuccess));
-}
-
TEST_F(ModelExecutionManagerTest, OnSegmentationModelUpdatedInvalidMetadata) {
// Use a MockSegmentInfoDatabase for this test in particular, to verify that
// it is never used.
diff --git a/chromium/components/segmentation_platform/internal/execution/segmentation_model_executor.cc b/chromium/components/segmentation_platform/internal/execution/segmentation_model_executor.cc
index e03fd07ec88..3b7396da906 100644
--- a/chromium/components/segmentation_platform/internal/execution/segmentation_model_executor.cc
+++ b/chromium/components/segmentation_platform/internal/execution/segmentation_model_executor.cc
@@ -16,26 +16,31 @@ SegmentationModelExecutor::SegmentationModelExecutor() = default;
SegmentationModelExecutor::~SegmentationModelExecutor() = default;
-absl::Status SegmentationModelExecutor::Preprocess(
+bool SegmentationModelExecutor::Preprocess(
const std::vector<TfLiteTensor*>& input_tensors,
const std::vector<float>& input) {
// The model must have a single float input tensor, and the length of the
// input data must match the length of the tensor.
- if (input_tensors.size() != 1u)
- return absl::InvalidArgumentError("input tensor size not 1");
- if (kTfLiteFloat32 != input_tensors[0]->type)
- return absl::InvalidArgumentError("input tensor type is not float");
+ if (input_tensors.size() != 1u) {
+ LOG(ERROR) << "input tensor size not 1";
+ return false;
+ }
+ if (kTfLiteFloat32 != input_tensors[0]->type) {
+ LOG(ERROR) << "input tensor type is not float";
+ return false;
+ }
if (input_tensors[0]->bytes / sizeof(input_tensors[0]->type) !=
input.size()) {
- return absl::InvalidArgumentError(
- "length of input data does not match length of tensor");
+ LOG(ERROR) << "length of input data does not match length of tensor";
+ return false;
}
- tflite::task::core::PopulateTensor<float>(input, input_tensors[0]);
- return absl::OkStatus();
+ absl::Status status =
+ tflite::task::core::PopulateTensor<float>(input, input_tensors[0]);
+ return status.ok();
}
-float SegmentationModelExecutor::Postprocess(
+absl::optional<float> SegmentationModelExecutor::Postprocess(
const std::vector<const TfLiteTensor*>& output_tensors) {
// The output must be a single tensor with a single float element.
DCHECK_EQ(1u, output_tensors.size());
@@ -43,7 +48,12 @@ float SegmentationModelExecutor::Postprocess(
DCHECK_EQ(1u, output_tensors[0]->bytes / sizeof(output_tensors[0]->type));
std::vector<float> data;
- tflite::task::core::PopulateVector<float>(output_tensors[0], &data);
+ absl::Status status =
+ tflite::task::core::PopulateVector<float>(output_tensors[0], &data);
+ if (!status.ok()) {
+ NOTREACHED();
+ return absl::nullopt;
+ }
DCHECK_EQ(1u, data.size());
return data[0];
}
diff --git a/chromium/components/segmentation_platform/internal/execution/segmentation_model_executor.h b/chromium/components/segmentation_platform/internal/execution/segmentation_model_executor.h
index fa578e95870..33e885e8f31 100644
--- a/chromium/components/segmentation_platform/internal/execution/segmentation_model_executor.h
+++ b/chromium/components/segmentation_platform/internal/execution/segmentation_model_executor.h
@@ -37,9 +37,9 @@ class SegmentationModelExecutor
protected:
// optimization_guide::BaseModelExecutor overrides.
- absl::Status Preprocess(const std::vector<TfLiteTensor*>& input_tensors,
- const std::vector<float>& input) override;
- float Postprocess(
+ bool Preprocess(const std::vector<TfLiteTensor*>& input_tensors,
+ const std::vector<float>& input) override;
+ absl::optional<float> Postprocess(
const std::vector<const TfLiteTensor*>& output_tensors) override;
};
diff --git a/chromium/components/segmentation_platform/internal/execution/segmentation_model_executor_unittest.cc b/chromium/components/segmentation_platform/internal/execution/segmentation_model_executor_unittest.cc
index a7aa8f2ae6c..2276510a0ab 100644
--- a/chromium/components/segmentation_platform/internal/execution/segmentation_model_executor_unittest.cc
+++ b/chromium/components/segmentation_platform/internal/execution/segmentation_model_executor_unittest.cc
@@ -73,7 +73,7 @@ class SegmentationModelExecutorTest : public testing::Test {
model_executor_handle_ = std::make_unique<SegmentationModelHandler>(
optimization_guide_model_provider_.get(),
task_environment_.GetMainThreadTaskRunner(), kOptimizationTarget,
- callback);
+ callback, absl::nullopt);
}
void ResetModelExecutor() {
diff --git a/chromium/components/segmentation_platform/internal/execution/segmentation_model_handler.cc b/chromium/components/segmentation_platform/internal/execution/segmentation_model_handler.cc
index 70a26fd56bc..23a1e0d374f 100644
--- a/chromium/components/segmentation_platform/internal/execution/segmentation_model_handler.cc
+++ b/chromium/components/segmentation_platform/internal/execution/segmentation_model_handler.cc
@@ -20,14 +20,19 @@ SegmentationModelHandler::SegmentationModelHandler(
optimization_guide::OptimizationGuideModelProvider* model_provider,
scoped_refptr<base::SequencedTaskRunner> background_task_runner,
optimization_guide::proto::OptimizationTarget optimization_target,
- const ModelUpdatedCallback& model_updated_callback)
+ const ModelUpdatedCallback& model_updated_callback,
+ absl::optional<optimization_guide::proto::Any>&& model_metadata)
: optimization_guide::ModelHandler<float, const std::vector<float>&>(
model_provider,
background_task_runner,
std::make_unique<SegmentationModelExecutor>(),
optimization_target,
- /*model_metadata=*/absl::nullopt),
- model_updated_callback_(model_updated_callback) {}
+ model_metadata),
+ model_updated_callback_(model_updated_callback) {
+ stats::RecordModelAvailability(
+ optimization_target,
+ stats::SegmentationModelAvailability::kModelHandlerCreated);
+}
SegmentationModelHandler::~SegmentationModelHandler() = default;
@@ -53,8 +58,14 @@ void SegmentationModelHandler::OnModelUpdated(
// expected to pass this along. Either something failed horribly on the way,
// we failed to read the metadata, or the server side configuration is
// wrong.
+ stats::RecordModelAvailability(
+ optimization_target,
+ stats::SegmentationModelAvailability::kMetadataInvalid);
return;
}
+ stats::RecordModelAvailability(
+ optimization_target,
+ stats::SegmentationModelAvailability::kModelAvailable);
model_updated_callback_.Run(optimization_target,
std::move(*segmentation_model_metadata));
diff --git a/chromium/components/segmentation_platform/internal/execution/segmentation_model_handler.h b/chromium/components/segmentation_platform/internal/execution/segmentation_model_handler.h
index 27dc66097c2..725ca861127 100644
--- a/chromium/components/segmentation_platform/internal/execution/segmentation_model_handler.h
+++ b/chromium/components/segmentation_platform/internal/execution/segmentation_model_handler.h
@@ -37,7 +37,9 @@ class SegmentationModelHandler
optimization_guide::OptimizationGuideModelProvider* model_provider,
scoped_refptr<base::SequencedTaskRunner> background_task_runner,
optimization_guide::proto::OptimizationTarget optimization_target,
- const ModelUpdatedCallback& model_updated_callback);
+ const ModelUpdatedCallback& model_updated_callback,
+ absl::optional<optimization_guide::proto::Any>&& model_metadata);
+
~SegmentationModelHandler() override;
// Disallow copy/assign.
diff --git a/chromium/components/segmentation_platform/internal/execution/uma_feature_processor.cc b/chromium/components/segmentation_platform/internal/execution/uma_feature_processor.cc
new file mode 100644
index 00000000000..dfdf143727c
--- /dev/null
+++ b/chromium/components/segmentation_platform/internal/execution/uma_feature_processor.cc
@@ -0,0 +1,118 @@
+// Copyright 2022 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.
+
+#include "components/segmentation_platform/internal/execution/uma_feature_processor.h"
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/memory/weak_ptr.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "base/timer/elapsed_timer.h"
+#include "components/segmentation_platform/internal/database/metadata_utils.h"
+#include "components/segmentation_platform/internal/execution/feature_processor_state.h"
+#include "components/segmentation_platform/internal/proto/model_metadata.pb.h"
+#include "components/segmentation_platform/internal/stats.h"
+
+namespace segmentation_platform {
+
+UmaFeatureProcessor::UmaFeatureProcessor(
+ SignalDatabase* signal_database,
+ std::unique_ptr<FeatureAggregator> feature_aggregator)
+ : signal_database_(signal_database),
+ feature_aggregator_(std::move(feature_aggregator)) {}
+
+UmaFeatureProcessor::~UmaFeatureProcessor() = default;
+
+void UmaFeatureProcessor::ProcessUmaFeature(
+ const proto::UMAFeature& feature,
+ std::unique_ptr<FeatureProcessorState> feature_processor_state,
+ FeatureListQueryProcessorCallback callback) {
+ // Skip collection-only features.
+ if (feature.bucket_count() == 0) {
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(std::move(callback),
+ std::move(feature_processor_state)));
+ return;
+ }
+
+ // Validate the proto::UMAFeature metadata.
+ if (metadata_utils::ValidateMetadataUmaFeature(feature) !=
+ metadata_utils::ValidationResult::kValidationSuccess) {
+ feature_processor_state->SetError();
+ feature_processor_state->RunCallback();
+ return;
+ }
+
+ auto name_hash = feature.name_hash();
+
+ // Enum histograms can optionally only accept some of the enum values.
+ // While the proto::UMAFeature is available, capture a vector of the
+ // accepted enum values. An empty vector is ignored (all values are
+ // considered accepted).
+ std::vector<int32_t> accepted_enum_ids{};
+ if (feature.type() == proto::SignalType::HISTOGRAM_ENUM) {
+ for (int i = 0; i < feature.enum_ids_size(); ++i)
+ accepted_enum_ids.emplace_back(feature.enum_ids(i));
+ }
+
+ // Only fetch data that is relevant for the current proto::UMAFeature, since
+ // the FeatureAggregator assumes that only relevant data is given to it.
+ base::TimeDelta duration =
+ feature_processor_state->bucket_duration() * feature.bucket_count();
+ base::Time start_time = feature_processor_state->prediction_time() - duration;
+
+ // Fetch the relevant samples for the current proto::UMAFeature. Once the
+ // result has come back, it will be processed and inserted into the
+ // FeatureProcessorState::input_tensor and will then invoke
+ // ProcessInputFeatures(...) again to ensure we continue until all features
+ // have been processed. Note: All parameters from the FeatureProcessorState
+ // need to be captured locally before invoking GetSamples, because the state
+ // is moved with the callback, and the order of the move and accessing the
+ // members while invoking GetSamples is not guaranteed.
+ auto signal_type = feature.type();
+ auto prediction_time = feature_processor_state->prediction_time();
+ signal_database_->GetSamples(
+ signal_type, name_hash, start_time, prediction_time,
+ base::BindOnce(&UmaFeatureProcessor::OnGetSamplesForUmaFeature,
+ weak_ptr_factory_.GetWeakPtr(), std::move(callback),
+ std::move(feature_processor_state), feature,
+ accepted_enum_ids));
+}
+
+void UmaFeatureProcessor::OnGetSamplesForUmaFeature(
+ FeatureListQueryProcessorCallback callback,
+ std::unique_ptr<FeatureProcessorState> feature_processor_state,
+ const proto::UMAFeature& feature,
+ const std::vector<int32_t>& accepted_enum_ids,
+ std::vector<SignalDatabase::Sample> samples) {
+ base::ElapsedTimer timer;
+ // HISTOGRAM_ENUM features might require us to filter out the result to only
+ // keep enum values that match the accepted list. If the accepted list is'
+ // empty, all histogram enum values are kept.
+ // The SignalDatabase does not currently support this type of data filter,
+ // so instead we are doing this here.
+ if (feature.type() == proto::SignalType::HISTOGRAM_ENUM) {
+ feature_aggregator_->FilterEnumSamples(accepted_enum_ids, samples);
+ }
+
+ // We now have all the data required to process a single feature, so we can
+ // process it synchronously, and insert it into the
+ // FeatureProcessorState::input_tensor so we can later pass it to the ML model
+ // executor.
+ std::vector<float> feature_data = feature_aggregator_->Process(
+ feature.type(), feature.aggregation(), feature.bucket_count(),
+ feature_processor_state->prediction_time(),
+ feature_processor_state->bucket_duration(), samples);
+
+ DCHECK_EQ(feature.tensor_length(), feature_data.size());
+ feature_processor_state->AppendInputTensor(feature_data);
+
+ stats::RecordModelExecutionDurationFeatureProcessing(
+ feature_processor_state->segment_id(), timer.Elapsed());
+
+ // Continue with the rest of the features.
+ std::move(callback).Run(std::move(feature_processor_state));
+}
+
+} // namespace segmentation_platform
diff --git a/chromium/components/segmentation_platform/internal/execution/uma_feature_processor.h b/chromium/components/segmentation_platform/internal/execution/uma_feature_processor.h
new file mode 100644
index 00000000000..74152f2a5e5
--- /dev/null
+++ b/chromium/components/segmentation_platform/internal/execution/uma_feature_processor.h
@@ -0,0 +1,65 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_EXECUTION_UMA_FEATURE_PROCESSOR_H_
+#define COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_EXECUTION_UMA_FEATURE_PROCESSOR_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/memory/raw_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "components/optimization_guide/proto/models.pb.h"
+#include "components/segmentation_platform/internal/database/signal_database.h"
+#include "components/segmentation_platform/internal/execution/feature_aggregator.h"
+#include "components/segmentation_platform/internal/proto/model_metadata.pb.h"
+
+namespace segmentation_platform {
+class FeatureProcessorState;
+
+// UmaFeatureProcessor takes an UMAFeature type of input, fetches samples from
+// the SignalDatabase (raw signals) databases, and computes an input tensor to
+// use when executing the ML model.
+class UmaFeatureProcessor {
+ public:
+ UmaFeatureProcessor(SignalDatabase* signal_database,
+ std::unique_ptr<FeatureAggregator> feature_aggregator);
+ virtual ~UmaFeatureProcessor();
+
+ // Disallow copy/assign.
+ UmaFeatureProcessor(const UmaFeatureProcessor&) = delete;
+ UmaFeatureProcessor& operator=(const UmaFeatureProcessor&) = delete;
+
+ using FeatureListQueryProcessorCallback =
+ base::OnceCallback<void(std::unique_ptr<FeatureProcessorState>)>;
+
+ // Function for processing the next UMAFeature type of input for ML model.
+ void ProcessUmaFeature(
+ const proto::UMAFeature& feature,
+ std::unique_ptr<FeatureProcessorState> feature_processor_state,
+ FeatureListQueryProcessorCallback callback);
+
+ private:
+ // Callback method for when all relevant samples for a particular feature has
+ // been loaded. Processes the samples, and inserts them into the input tensor
+ // that is later given to the ML execution.
+ void OnGetSamplesForUmaFeature(
+ FeatureListQueryProcessorCallback callback,
+ std::unique_ptr<FeatureProcessorState> feature_processor_state,
+ const proto::UMAFeature& feature,
+ const std::vector<int32_t>& accepted_enum_ids,
+ std::vector<SignalDatabase::Sample> samples);
+
+ // Main signal database for user actions and histograms.
+ raw_ptr<SignalDatabase> signal_database_;
+
+ // The FeatureAggregator aggregates all the data based on metadata and input.
+ std::unique_ptr<FeatureAggregator> feature_aggregator_;
+
+ base::WeakPtrFactory<UmaFeatureProcessor> weak_ptr_factory_{this};
+};
+
+} // namespace segmentation_platform
+
+#endif // COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_EXECUTION_UMA_FEATURE_PROCESSOR_H_
diff --git a/chromium/components/segmentation_platform/internal/proto/PRESUBMIT.py b/chromium/components/segmentation_platform/internal/proto/PRESUBMIT.py
new file mode 100644
index 00000000000..e4183d8e5c7
--- /dev/null
+++ b/chromium/components/segmentation_platform/internal/proto/PRESUBMIT.py
@@ -0,0 +1,30 @@
+# Copyright 2022 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.
+
+"""
+See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
+for more details on the presubmit API built into depot_tools.
+"""
+
+USE_PYTHON3 = True
+
+def CheckChange(input_api, output_api):
+ cwd = input_api.PresubmitLocalPath()
+ for f in input_api.AffectedFiles():
+ p = f.AbsoluteLocalPath()
+
+ # Only do PRESUBMIT checks when |p| is under |cwd| and is a proto file.
+ if input_api.os_path.commonprefix([p, cwd]) == cwd \
+ and p.endswith('.proto'):
+ return [output_api.PresubmitPromptWarning(
+ 'Segmentation platform proto files were updated, consider ' +
+ 'updating the VERSION field in components/' +
+ 'segmentation_platform/internal/proto/model_metadata.proto.')]
+ return []
+
+def CheckChangeOnUpload(input_api, output_api):
+ return CheckChange(input_api, output_api)
+
+def CheckChangeOnCommit(input_api, output_api):
+ return CheckChange(input_api, output_api)
diff --git a/chromium/components/segmentation_platform/internal/proto/model_metadata.proto b/chromium/components/segmentation_platform/internal/proto/model_metadata.proto
index 1eb33de546e..9924dbb1348 100644
--- a/chromium/components/segmentation_platform/internal/proto/model_metadata.proto
+++ b/chromium/components/segmentation_platform/internal/proto/model_metadata.proto
@@ -10,6 +10,29 @@ package segmentation_platform.proto;
import "components/segmentation_platform/internal/proto/aggregation.proto";
import "components/segmentation_platform/internal/proto/types.proto";
+// The version is used to verify if the metadata provided by the server is
+// supported in current version of the code. Update the version number for any
+// new feature added to metadata proto, and add a log of the new changes in the
+// current version in this file.
+// Version 0 supports UMA features and aggregation in |features| field.
+// Version 1 supports UMA features and custom inputs in |input_features| field.
+// Version 2 supports training data output collection in |training_outputs|
+// field.
+enum CurrentVersion { METADATA_VERSION = 0; }
+
+// Version information for segmentation models.
+message VersionInfo {
+ // Minimum model metadata version that is supported. Some newer
+ // features/fields might not be available before this version. This field is
+ // set on the server and read by the client to verify if model is valid.
+ optional int32 metadata_min_version = 1;
+
+ // Current model metadata version. This field is set by the client while
+ // sending a model download request to optimization guide server so that the
+ // server knows the capabilities of the client.
+ optional int32 metadata_cur_version = 2;
+}
+
// Used as time unit for rest of this proto.
enum TimeUnit {
UNKNOWN_TIME_UNIT = 0;
@@ -22,7 +45,7 @@ enum TimeUnit {
SECOND = 7;
}
-message Feature {
+message UMAFeature {
// The type of signal this feature refers to.
optional SignalType type = 1;
@@ -51,11 +74,146 @@ message Feature {
repeated int32 enum_ids = 7;
}
+message CustomInput {
+ // If the param is directly used as the input tensor field to the model, then
+ // this specifies the number of columns to fill in the tensor. In this case
+ // the value should be float.
+ optional int32 tensor_length = 1;
+
+ // Used to distinguish between different types of custom inputs.
+ enum FillPolicy {
+ // Custom functions provided by the engine that fills in the input feature
+ // to the model.
+ UNKNOWN_FILL_POLICY = 0;
+ // Output is the time at which model prediction is needed. Can be used to
+ // bind TIME type param to queries.
+ FILL_PREDICTION_TIME = 1;
+ }
+
+ // The fill type of the custom input.
+ optional FillPolicy fill_policy = 2;
+
+ // If the current chrome version does not support this fill type, use this
+ // value. If this is not specified and the function is unavailable, the model
+ // will not run due to missing input. The number of entries should be equal to
+ // the |tensor_length|.
+ repeated float default_value = 3;
+}
+
+// Configuration for storing signals in the SQL database.
+message SignalFilterConfig {
+ // Defines a single UKM event that should be stored.
+ message UkmEvent {
+ // Event hash of the UKM event.
+ optional uint64 event_hash = 1;
+ // List of metric hashes for the event, to store in the database. If
+ // empty, the database will store all the metrics for the UKM event. It is
+ // is recommended to provide list of necessary metrics, unless it is clear
+ // that the list of metrics of the event is easily trackable and doesn't
+ // grow over time.
+ repeated uint64 metric_hash_filter = 2;
+ }
+ // List of UKM events to store in the database.
+ repeated UkmEvent ukm_events = 1;
+}
+
+message SqlFeature {
+ // The query should select a single float column. The query can contain '?'
+ // which can be used to bind values using |bind_values| list.
+ // TODO(ssid): Consider expanding this to return multiple input tensor
+ // features.
+ optional string sql = 1;
+
+ // List of signals needed in the storage for the query.
+ optional SignalFilterConfig signal_filter = 2;
+
+ // Used to bind value for the SQL query.
+ message BindValue {
+ // The bind field numbers, in range of 0 to n-1, for n question marks in the
+ // SQL query.
+ repeated int32 bind_field_index = 1;
+
+ // Used to call Bind*() in sql::Statement.
+ enum ParamType {
+ UNKNOWN = 0;
+ NULL = 1;
+ BOOL = 2;
+ INT = 3;
+ INT64 = 4;
+ DOUBLE = 5;
+ STRING = 6;
+ TIME = 7;
+ }
+ optional ParamType param_type = 2;
+
+ // Value of the input to bind the query. The custom function should return
+ // the specified param type. The |tensor_length| should be 0 since these
+ // inputs can only be used for SQL bind values.
+ optional CustomInput value = 3;
+ }
+ repeated BindValue bind_values = 3;
+}
+
+// Contains a feature used as an input to the ML model.
+message InputFeature {
+ oneof Feature {
+ // An UMAFeature type of input feature.
+ UMAFeature uma_feature = 1;
+
+ // A custom input type of input feature.
+ CustomInput custom_input = 2;
+
+ // Input feature computed using SQL query.
+ SqlFeature sql_feature = 3;
+ }
+}
+
+// Contains a list of training output generators. The ML model pipeline can
+// iterate on different output candidates and select the final output generator.
+message TrainingOutputs {
+ repeated TrainingOutput outputs = 1;
+}
+
+// Generic type to define how to generate the training data output.
+// TODO(xingliu): Add more implementation details about how output training data
+// is generated.
+message TrainingOutput {
+ oneof output {
+ // Training data output is generated from UMA metrics.
+ UMAOutput uma_output = 1;
+ }
+}
+
+// Contains the information to generate the output for training data based on a
+// particular UMA metric.
+message UMAOutput {
+ // The UMA metric to generate the training data output.
+ optional UMAFeature uma_feature = 1;
+
+ // The duration to trigger a training data collection, unit in TimeUnit. If
+ // not specified or 0, the training data will be generated immediately after
+ // certain UMA is recorded.
+ optional uint64 duration = 2;
+}
+
// Metadata about a segmentation model for a given segment. Contains information
// on how to use the model such as collecting signals, interpreting results etc.
+// Next tag: 12
message SegmentationModelMetadata {
- // An ordered list of required features.
- repeated Feature features = 1;
+ // The version information needed to validate segmentation models.
+ optional VersionInfo version_info = 9;
+
+ // DEPRECATED: Use |input_features.uma_feature| instead. Only one of
+ // |features| or |input_features| can be used in the config, not both. An
+ // ordered list of required features.
+ repeated UMAFeature features = 1;
+
+ // An ordered list of required features and custom inputs. Only one of
+ // |features| or |input_features| can be used in the config, not both.
+ repeated InputFeature input_features = 10;
+
+ // A list of training data output definitions.
+ optional TrainingOutputs training_outputs = 11;
// The time unit to be used for the rest of this proto.
optional TimeUnit time_unit = 2;
diff --git a/chromium/components/segmentation_platform/internal/scheduler/model_execution_scheduler_impl.cc b/chromium/components/segmentation_platform/internal/scheduler/model_execution_scheduler_impl.cc
index fc7c97d4a8f..7e5b0048468 100644
--- a/chromium/components/segmentation_platform/internal/scheduler/model_execution_scheduler_impl.cc
+++ b/chromium/components/segmentation_platform/internal/scheduler/model_execution_scheduler_impl.cc
@@ -86,6 +86,10 @@ void ModelExecutionSchedulerImpl::OnModelExecutionCompleted(
segment_result.set_timestamp_us(
clock_->Now().ToDeltaSinceWindowsEpoch().InMicroseconds());
stats::RecordModelScore(segment_id, result.first);
+ } else {
+ stats::RecordSegmentSelectionFailure(
+ stats::SegmentationSelectionFailureReason::
+ kAtLeastOneModelFailedExecution);
}
segment_database_->SaveSegmentResult(
@@ -96,10 +100,9 @@ void ModelExecutionSchedulerImpl::OnModelExecutionCompleted(
void ModelExecutionSchedulerImpl::FilterEligibleSegments(
bool expired_only,
- std::vector<std::pair<OptimizationTarget, proto::SegmentInfo>>
- all_segments) {
+ std::unique_ptr<SegmentInfoDatabase::SegmentInfoList> all_segments) {
std::vector<OptimizationTarget> models_to_run;
- for (const auto& pair : all_segments) {
+ for (const auto& pair : *all_segments) {
OptimizationTarget segment_id = pair.first;
const proto::SegmentInfo& segment_info = pair.second;
if (!ShouldExecuteSegment(expired_only, segment_info)) {
@@ -137,6 +140,9 @@ bool ModelExecutionSchedulerImpl::ShouldExecuteSegment(
// Filter out segments that don't match signal collection min length.
if (!signal_storage_config_->MeetsSignalCollectionRequirement(
segment_info.model_metadata())) {
+ stats::RecordSegmentSelectionFailure(
+ stats::SegmentationSelectionFailureReason::
+ kAtLeastOneModelNeedsMoreSignals);
VLOG(1) << "Segmentation model not executed since metadata requirements "
"not met.";
return false;
@@ -157,8 +163,11 @@ void ModelExecutionSchedulerImpl::CancelOutstandingExecutionRequests(
void ModelExecutionSchedulerImpl::OnResultSaved(OptimizationTarget segment_id,
bool success) {
stats::RecordModelExecutionSaveResult(segment_id, success);
- if (!success)
+ if (!success) {
+ stats::RecordSegmentSelectionFailure(
+ stats::SegmentationSelectionFailureReason::kFailedToSaveModelResult);
return;
+ }
for (Observer* observer : observers_)
observer->OnModelExecutionCompleted(segment_id);
diff --git a/chromium/components/segmentation_platform/internal/scheduler/model_execution_scheduler_impl.h b/chromium/components/segmentation_platform/internal/scheduler/model_execution_scheduler_impl.h
index 36898affca7..7d441f917a3 100644
--- a/chromium/components/segmentation_platform/internal/scheduler/model_execution_scheduler_impl.h
+++ b/chromium/components/segmentation_platform/internal/scheduler/model_execution_scheduler_impl.h
@@ -12,6 +12,7 @@
#include "base/containers/flat_set.h"
#include "base/memory/weak_ptr.h"
#include "components/optimization_guide/proto/models.pb.h"
+#include "components/segmentation_platform/internal/database/segment_info_database.h"
#include "components/segmentation_platform/internal/execution/model_execution_manager.h"
#include "components/segmentation_platform/internal/execution/model_execution_status.h"
#include "components/segmentation_platform/internal/platform_options.h"
@@ -26,7 +27,6 @@ namespace proto {
class SegmentInfo;
} // namespace proto
-class SegmentInfoDatabase;
class SignalStorageConfig;
class ModelExecutionSchedulerImpl : public ModelExecutionScheduler {
@@ -57,8 +57,7 @@ class ModelExecutionSchedulerImpl : public ModelExecutionScheduler {
private:
void FilterEligibleSegments(
bool expired_only,
- std::vector<std::pair<OptimizationTarget, proto::SegmentInfo>>
- all_segments);
+ std::unique_ptr<SegmentInfoDatabase::SegmentInfoList> all_segments);
bool ShouldExecuteSegment(bool expired_only,
const proto::SegmentInfo& segment_info);
void CancelOutstandingExecutionRequests(OptimizationTarget segment_id);
diff --git a/chromium/components/segmentation_platform/internal/segmentation_platform_service_impl.cc b/chromium/components/segmentation_platform/internal/segmentation_platform_service_impl.cc
index c76de96a666..9c873935a9b 100644
--- a/chromium/components/segmentation_platform/internal/segmentation_platform_service_impl.cc
+++ b/chromium/components/segmentation_platform/internal/segmentation_platform_service_impl.cc
@@ -18,12 +18,14 @@
#include "components/leveldb_proto/public/shared_proto_database_client_list.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/segmentation_platform/internal/constants.h"
+#include "components/segmentation_platform/internal/data_collection/training_data_collector.h"
#include "components/segmentation_platform/internal/database/database_maintenance_impl.h"
#include "components/segmentation_platform/internal/database/metadata_utils.h"
#include "components/segmentation_platform/internal/database/segment_info_database.h"
#include "components/segmentation_platform/internal/database/signal_database_impl.h"
#include "components/segmentation_platform/internal/database/signal_storage_config.h"
#include "components/segmentation_platform/internal/execution/feature_aggregator_impl.h"
+#include "components/segmentation_platform/internal/execution/feature_list_query_processor.h"
#include "components/segmentation_platform/internal/execution/model_execution_manager.h"
#include "components/segmentation_platform/internal/execution/model_execution_manager_factory.h"
#include "components/segmentation_platform/internal/platform_options.h"
@@ -37,6 +39,8 @@
#include "components/segmentation_platform/internal/signals/histogram_signal_handler.h"
#include "components/segmentation_platform/internal/signals/signal_filter_processor.h"
#include "components/segmentation_platform/internal/signals/user_action_signal_handler.h"
+#include "components/segmentation_platform/internal/stats.h"
+#include "components/segmentation_platform/internal/ukm_data_manager.h"
#include "components/segmentation_platform/public/config.h"
using optimization_guide::proto::OptimizationTarget;
@@ -55,6 +59,7 @@ SegmentationPlatformServiceImpl::SegmentationPlatformServiceImpl(
optimization_guide::OptimizationGuideModelProvider* model_provider,
leveldb_proto::ProtoDatabaseProvider* db_provider,
const base::FilePath& storage_dir,
+ UkmDataManager* ukm_data_manager,
PrefService* pref_service,
const scoped_refptr<base::SequencedTaskRunner>& task_runner,
base::Clock* clock,
@@ -72,6 +77,7 @@ SegmentationPlatformServiceImpl::SegmentationPlatformServiceImpl(
leveldb_proto::ProtoDbType::SIGNAL_STORAGE_CONFIG_DATABASE,
storage_dir.Append(kSignalStorageConfigDBName),
task_runner),
+ ukm_data_manager,
model_provider,
pref_service,
task_runner,
@@ -84,6 +90,7 @@ SegmentationPlatformServiceImpl::SegmentationPlatformServiceImpl(
std::unique_ptr<leveldb_proto::ProtoDatabase<proto::SignalData>> signal_db,
std::unique_ptr<leveldb_proto::ProtoDatabase<proto::SignalStorageConfigs>>
signal_storage_config_db,
+ UkmDataManager* ukm_data_manager,
optimization_guide::OptimizationGuideModelProvider* model_provider,
PrefService* pref_service,
const scoped_refptr<base::SequencedTaskRunner>& task_runner,
@@ -93,7 +100,9 @@ SegmentationPlatformServiceImpl::SegmentationPlatformServiceImpl(
task_runner_(task_runner),
clock_(clock),
platform_options_(PlatformOptions::CreateDefault()),
- configs_(std::move(configs)) {
+ configs_(std::move(configs)),
+ ukm_data_manager_(ukm_data_manager) {
+ ukm_data_manager_->AddRef();
// Construct databases.
segment_info_database_ =
std::make_unique<SegmentInfoDatabase>(std::move(segment_db));
@@ -103,8 +112,6 @@ SegmentationPlatformServiceImpl::SegmentationPlatformServiceImpl(
std::move(signal_storage_config_db), clock);
segmentation_result_prefs_ =
std::make_unique<SegmentationResultPrefs>(pref_service);
- proxy_ =
- std::make_unique<ServiceProxyImpl>(this, segment_info_database_.get());
// Construct signal processors.
user_action_signal_handler_ =
@@ -123,6 +130,9 @@ SegmentationPlatformServiceImpl::SegmentationPlatformServiceImpl(
platform_options_);
}
+ proxy_ = std::make_unique<ServiceProxyImpl>(segment_info_database_.get(),
+ signal_storage_config_.get(),
+ &configs_, &segment_selectors_);
for (const auto& config : configs_) {
for (const auto& segment_id : config->segment_ids)
all_segment_ids_.insert(segment_id);
@@ -148,7 +158,9 @@ SegmentationPlatformServiceImpl::SegmentationPlatformServiceImpl(
weak_ptr_factory_.GetWeakPtr()));
}
-SegmentationPlatformServiceImpl::~SegmentationPlatformServiceImpl() = default;
+SegmentationPlatformServiceImpl::~SegmentationPlatformServiceImpl() {
+ ukm_data_manager_->RemoveRef();
+}
void SegmentationPlatformServiceImpl::GetSelectedSegment(
const std::string& segmentation_key,
@@ -158,6 +170,13 @@ void SegmentationPlatformServiceImpl::GetSelectedSegment(
selector->GetSelectedSegment(std::move(callback));
}
+SegmentSelectionResult SegmentationPlatformServiceImpl::GetCachedSegmentResult(
+ const std::string& segmentation_key) {
+ CHECK(segment_selectors_.find(segmentation_key) != segment_selectors_.end());
+ auto& selector = segment_selectors_.at(segmentation_key);
+ return selector->GetCachedSegmentResult();
+}
+
void SegmentationPlatformServiceImpl::EnableMetrics(
bool signal_collection_allowed) {
signal_filter_processor_->EnableMetrics(signal_collection_allowed);
@@ -201,13 +220,22 @@ void SegmentationPlatformServiceImpl::MaybeRunPostInitializationRoutines() {
signal_storage_config_initialized_;
OnServiceStatusChanged();
- if (!init_success)
+ if (!init_success) {
+ stats::RecordSegmentSelectionFailure(
+ stats::SegmentationSelectionFailureReason::kDBInitFailure);
return;
+ }
+
+ feature_list_query_processor_ = std::make_unique<FeatureListQueryProcessor>(
+ signal_database_.get(), std::make_unique<FeatureAggregatorImpl>());
+
+ training_data_collector_ = std::make_unique<TrainingDataCollector>(
+ feature_list_query_processor_.get());
model_execution_manager_ = CreateModelExecutionManager(
model_provider_, task_runner_, all_segment_ids_, clock_,
segment_info_database_.get(), signal_database_.get(),
- std::make_unique<FeatureAggregatorImpl>(),
+ feature_list_query_processor_.get(),
base::BindRepeating(
&SegmentationPlatformServiceImpl::OnSegmentationModelUpdated,
weak_ptr_factory_.GetWeakPtr()));
@@ -231,6 +259,8 @@ void SegmentationPlatformServiceImpl::MaybeRunPostInitializationRoutines() {
&SegmentationPlatformServiceImpl::OnExecuteDatabaseMaintenanceTasks,
weak_ptr_factory_.GetWeakPtr()),
kDatabaseMaintenanceDelay);
+
+ proxy_->SetModelExecutionScheduler(model_execution_scheduler_.get());
}
void SegmentationPlatformServiceImpl::OnSegmentationModelUpdated(
@@ -243,6 +273,12 @@ void SegmentationPlatformServiceImpl::OnSegmentationModelUpdated(
signal_filter_processor_->OnSignalListUpdated();
model_execution_scheduler_->OnNewModelInfoReady(segment_info);
+
+ // Update the service status for proxy.
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::BindOnce(&SegmentationPlatformServiceImpl::OnServiceStatusChanged,
+ weak_ptr_factory_.GetWeakPtr()));
}
void SegmentationPlatformServiceImpl::OnExecuteDatabaseMaintenanceTasks() {
@@ -251,15 +287,12 @@ void SegmentationPlatformServiceImpl::OnExecuteDatabaseMaintenanceTasks() {
void SegmentationPlatformServiceImpl::OnServiceStatusChanged() {
int status = static_cast<int>(ServiceStatus::kUninitialized);
- if (IsInitializationFinished()) {
- if (segment_info_database_initialized_)
- status |= static_cast<int>(ServiceStatus::kSegmentationInfoDbInitialized);
- if (signal_database_initialized_)
- status |= static_cast<int>(ServiceStatus::kSignalDbInitialized);
- if (signal_storage_config_initialized_) {
- status |=
- static_cast<int>(ServiceStatus::kSignalStorageConfigInitialized);
- }
+ if (segment_info_database_initialized_)
+ status |= static_cast<int>(ServiceStatus::kSegmentationInfoDbInitialized);
+ if (signal_database_initialized_)
+ status |= static_cast<int>(ServiceStatus::kSignalDbInitialized);
+ if (signal_storage_config_initialized_) {
+ status |= static_cast<int>(ServiceStatus::kSignalStorageConfigInitialized);
}
proxy_->OnServiceStatusChanged(IsInitializationFinished(), status);
diff --git a/chromium/components/segmentation_platform/internal/segmentation_platform_service_impl.h b/chromium/components/segmentation_platform/internal/segmentation_platform_service_impl.h
index fca4bd55c14..fc529f8163c 100644
--- a/chromium/components/segmentation_platform/internal/segmentation_platform_service_impl.h
+++ b/chromium/components/segmentation_platform/internal/segmentation_platform_service_impl.h
@@ -47,6 +47,7 @@ class SignalStorageConfigs;
struct Config;
class DatabaseMaintenanceImpl;
+class FeatureListQueryProcessor;
class HistogramSignalHandler;
class ModelExecutionManager;
class ModelExecutionSchedulerImpl;
@@ -57,6 +58,8 @@ class SignalDatabaseImpl;
class SignalFilterProcessor;
class SignalStorageConfig;
class SegmentScoreProvider;
+class TrainingDataCollector;
+class UkmDataManager;
class UserActionSignalHandler;
// Qualifiers used to indicate service status. One or more qualifiers can
@@ -82,6 +85,7 @@ class SegmentationPlatformServiceImpl : public SegmentationPlatformService {
optimization_guide::OptimizationGuideModelProvider* model_provider,
leveldb_proto::ProtoDatabaseProvider* db_provider,
const base::FilePath& storage_dir,
+ UkmDataManager* ukm_data_manager,
PrefService* pref_service,
const scoped_refptr<base::SequencedTaskRunner>& task_runner,
base::Clock* clock,
@@ -95,6 +99,7 @@ class SegmentationPlatformServiceImpl : public SegmentationPlatformService {
signal_db,
std::unique_ptr<leveldb_proto::ProtoDatabase<proto::SignalStorageConfigs>>
signal_storage_config_db,
+ UkmDataManager* ukm_data_manager,
optimization_guide::OptimizationGuideModelProvider* model_provider,
PrefService* pref_service,
const scoped_refptr<base::SequencedTaskRunner>& task_runner,
@@ -112,6 +117,8 @@ class SegmentationPlatformServiceImpl : public SegmentationPlatformService {
// SegmentationPlatformService overrides.
void GetSelectedSegment(const std::string& segmentation_key,
SegmentSelectionCallback callback) override;
+ SegmentSelectionResult GetCachedSegmentResult(
+ const std::string& segmentation_key) override;
void EnableMetrics(bool signal_collection_allowed) override;
ServiceProxy* GetServiceProxy() override;
@@ -150,11 +157,20 @@ class SegmentationPlatformServiceImpl : public SegmentationPlatformService {
std::unique_ptr<SignalStorageConfig> signal_storage_config_;
std::unique_ptr<SegmentationResultPrefs> segmentation_result_prefs_;
+ // The data manager is owned by the database client and is guaranteed to be
+ // kept alive until all profiles (keyed services) are destroyed. Refer to the
+ // description of UkmDataManager to know the lifetime of the objects usable
+ // from the manager.
+ raw_ptr<UkmDataManager> ukm_data_manager_;
+
// Signal processing.
std::unique_ptr<UserActionSignalHandler> user_action_signal_handler_;
std::unique_ptr<HistogramSignalHandler> histogram_signal_handler_;
std::unique_ptr<SignalFilterProcessor> signal_filter_processor_;
+ // Training/inference input data generation.
+ std::unique_ptr<FeatureListQueryProcessor> feature_list_query_processor_;
+
// Segment selection.
// TODO(shaktisahu): Determine safe destruction ordering between
// SegmentSelectorImpl and ModelExecutionSchedulerImpl.
@@ -164,6 +180,9 @@ class SegmentationPlatformServiceImpl : public SegmentationPlatformService {
// Segment results.
std::unique_ptr<SegmentScoreProvider> segment_score_provider_;
+ // Traing data collection logic.
+ std::unique_ptr<TrainingDataCollector> training_data_collector_;
+
// Model execution scheduling logic.
std::unique_ptr<ModelExecutionSchedulerImpl> model_execution_scheduler_;
diff --git a/chromium/components/segmentation_platform/internal/segmentation_platform_service_impl_unittest.cc b/chromium/components/segmentation_platform/internal/segmentation_platform_service_impl_unittest.cc
index 6e0f7f98ca6..33f089c9b51 100644
--- a/chromium/components/segmentation_platform/internal/segmentation_platform_service_impl_unittest.cc
+++ b/chromium/components/segmentation_platform/internal/segmentation_platform_service_impl_unittest.cc
@@ -5,6 +5,7 @@
#include "components/segmentation_platform/internal/segmentation_platform_service_impl.h"
#include <string>
+#include <utility>
#include "base/bind.h"
#include "base/files/file_path.h"
@@ -41,13 +42,17 @@
#include "components/segmentation_platform/internal/signals/histogram_signal_handler.h"
#include "components/segmentation_platform/internal/signals/signal_filter_processor.h"
#include "components/segmentation_platform/internal/signals/user_action_signal_handler.h"
+#include "components/segmentation_platform/internal/ukm_data_manager.h"
#include "components/segmentation_platform/public/config.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#if BUILDFLAG(BUILD_WITH_TFLITE_LIB)
#include "components/segmentation_platform/internal/execution/model_execution_manager_impl.h"
#endif // BUILDFLAG(BUILD_WITH_TFLITE_LIB
+using ::testing::_;
+
namespace segmentation_platform {
namespace {
@@ -94,6 +99,19 @@ std::vector<std::unique_ptr<Config>> CreateTestConfigs() {
} // namespace
+// A mock of the ServiceProxy::Observer.
+class MockServiceProxyObserver : public ServiceProxy::Observer {
+ public:
+ MockServiceProxyObserver() = default;
+ ~MockServiceProxyObserver() override = default;
+
+ MOCK_METHOD(void, OnServiceStatusChanged, (bool, int), (override));
+ MOCK_METHOD(void,
+ OnClientInfoAvailable,
+ (const std::vector<ServiceProxy::ClientInfo>& client_info),
+ (override));
+};
+
class SegmentationPlatformServiceImplTest : public testing::Test {
public:
SegmentationPlatformServiceImplTest() = default;
@@ -124,8 +142,11 @@ class SegmentationPlatformServiceImplTest : public testing::Test {
segmentation_platform_service_impl_ =
std::make_unique<SegmentationPlatformServiceImpl>(
std::move(segment_db), std::move(signal_db),
- std::move(segment_storage_config_db), &model_provider_,
- &pref_service_, task_runner_, &test_clock_, std::move(configs));
+ std::move(segment_storage_config_db), &ukm_data_manager_,
+ &model_provider_, &pref_service_, task_runner_, &test_clock_,
+ std::move(configs));
+ segmentation_platform_service_impl_->GetServiceProxy()->AddObserver(
+ &observer_);
}
void TearDown() override {
@@ -137,7 +158,7 @@ class SegmentationPlatformServiceImplTest : public testing::Test {
virtual void SetUpPrefs() {
DictionaryPrefUpdate update(&pref_service_, kSegmentationResultPref);
- base::DictionaryValue* dictionary = update.Get();
+ base::Value* dictionary = update.Get();
base::Value segmentation_result(base::Value::Type::DICTIONARY);
segmentation_result.SetIntKey(
@@ -175,6 +196,20 @@ class SegmentationPlatformServiceImplTest : public testing::Test {
loop.Run();
}
+ void AssertCachedSegment(
+ const std::string& segmentation_key,
+ bool is_ready,
+ OptimizationTarget expected =
+ OptimizationTarget::OPTIMIZATION_TARGET_UNKNOWN) {
+ SegmentSelectionResult result;
+ result.is_ready = is_ready;
+ if (is_ready)
+ result.segment = expected;
+ ASSERT_EQ(result,
+ segmentation_platform_service_impl_->GetCachedSegmentResult(
+ segmentation_key));
+ }
+
protected:
base::test::TaskEnvironment task_environment_{
base::test::TaskEnvironment::TimeSource::MOCK_TIME};
@@ -190,12 +225,15 @@ class SegmentationPlatformServiceImplTest : public testing::Test {
optimization_guide::TestOptimizationGuideModelProvider model_provider_;
TestingPrefServiceSimple pref_service_;
base::SimpleTestClock test_clock_;
+ UkmDataManager ukm_data_manager_;
std::unique_ptr<SegmentationPlatformServiceImpl>
segmentation_platform_service_impl_;
+ MockServiceProxyObserver observer_;
};
TEST_F(SegmentationPlatformServiceImplTest, InitializationFlow) {
// Let the DB loading complete successfully.
+ EXPECT_CALL(observer_, OnServiceStatusChanged(true, 7));
segment_db_->InitStatusCallback(leveldb_proto::Enums::InitStatus::kOK);
signal_db_->InitStatusCallback(leveldb_proto::Enums::InitStatus::kOK);
segment_storage_config_db_->InitStatusCallback(
@@ -253,6 +291,16 @@ TEST_F(SegmentationPlatformServiceImplTest, InitializationFlow) {
OptimizationTarget::OPTIMIZATION_TARGET_SEGMENTATION_SHARE);
AssertSelectedSegment(kTestSegmentationKey2, false);
AssertSelectedSegment(kTestSegmentationKey3, false);
+ AssertCachedSegment(
+ kTestSegmentationKey1, true,
+ OptimizationTarget::OPTIMIZATION_TARGET_SEGMENTATION_SHARE);
+ AssertCachedSegment(kTestSegmentationKey2, false);
+ AssertCachedSegment(kTestSegmentationKey3, false);
+
+ // ServiceProxy will load new segment info from the DB.
+ EXPECT_CALL(observer_, OnClientInfoAvailable(_));
+ task_environment_.RunUntilIdle();
+ segment_db_->LoadCallback(true);
mem_impl->OnSegmentationModelUpdated(
OptimizationTarget::OPTIMIZATION_TARGET_SEGMENTATION_VOICE, metadata);
@@ -266,6 +314,11 @@ TEST_F(SegmentationPlatformServiceImplTest, InitializationFlow) {
EXPECT_EQ(
2, histogram_tester.GetBucketCount(
"SegmentationPlatform.Signals.ListeningCount.HistogramValue", 1));
+
+ // ServiceProxy will load new segment info from the DB.
+ EXPECT_CALL(observer_, OnClientInfoAvailable(_));
+ task_environment_.RunUntilIdle();
+ segment_db_->LoadCallback(true);
#endif // BUILDFLAG(BUILD_WITH_TFLITE_LIB)
// Database maintenance tasks should try to cleanup the signals after a short
@@ -278,6 +331,11 @@ TEST_F(SegmentationPlatformServiceImplTest, InitializationFlow) {
OptimizationTarget::OPTIMIZATION_TARGET_SEGMENTATION_SHARE);
AssertSelectedSegment(kTestSegmentationKey2, false);
AssertSelectedSegment(kTestSegmentationKey3, false);
+ AssertCachedSegment(
+ kTestSegmentationKey1, true,
+ OptimizationTarget::OPTIMIZATION_TARGET_SEGMENTATION_SHARE);
+ AssertCachedSegment(kTestSegmentationKey2, false);
+ AssertCachedSegment(kTestSegmentationKey3, false);
}
TEST_F(SegmentationPlatformServiceImplTest,
@@ -302,6 +360,7 @@ class SegmentationPlatformServiceImplEmptyConfigTest
TEST_F(SegmentationPlatformServiceImplEmptyConfigTest, InitializationFlow) {
// Let the DB loading complete successfully.
+ EXPECT_CALL(observer_, OnServiceStatusChanged(true, 7));
segment_db_->InitStatusCallback(leveldb_proto::Enums::InitStatus::kOK);
signal_db_->InitStatusCallback(leveldb_proto::Enums::InitStatus::kOK);
segment_storage_config_db_->InitStatusCallback(
@@ -317,7 +376,7 @@ class SegmentationPlatformServiceImplMultiClientTest
: public SegmentationPlatformServiceImplTest {
void SetUpPrefs() override {
DictionaryPrefUpdate update(&pref_service_, kSegmentationResultPref);
- base::DictionaryValue* dictionary = update.Get();
+ base::Value* dictionary = update.Get();
base::Value segmentation_result(base::Value::Type::DICTIONARY);
segmentation_result.SetIntKey(
@@ -335,6 +394,7 @@ class SegmentationPlatformServiceImplMultiClientTest
TEST_F(SegmentationPlatformServiceImplMultiClientTest, InitializationFlow) {
// Let the DB loading complete successfully.
+ EXPECT_CALL(observer_, OnServiceStatusChanged(true, 7));
segment_db_->InitStatusCallback(leveldb_proto::Enums::InitStatus::kOK);
signal_db_->InitStatusCallback(leveldb_proto::Enums::InitStatus::kOK);
segment_storage_config_db_->InitStatusCallback(
@@ -352,6 +412,13 @@ TEST_F(SegmentationPlatformServiceImplMultiClientTest, InitializationFlow) {
kTestSegmentationKey2, true,
OptimizationTarget::OPTIMIZATION_TARGET_SEGMENTATION_VOICE);
AssertSelectedSegment(kTestSegmentationKey3, false);
+ AssertCachedSegment(
+ kTestSegmentationKey1, true,
+ OptimizationTarget::OPTIMIZATION_TARGET_SEGMENTATION_SHARE);
+ AssertCachedSegment(
+ kTestSegmentationKey2, true,
+ OptimizationTarget::OPTIMIZATION_TARGET_SEGMENTATION_VOICE);
+ AssertCachedSegment(kTestSegmentationKey3, false);
}
} // namespace segmentation_platform
diff --git a/chromium/components/segmentation_platform/internal/segmentation_ukm_helper.cc b/chromium/components/segmentation_platform/internal/segmentation_ukm_helper.cc
new file mode 100644
index 00000000000..c1c43449380
--- /dev/null
+++ b/chromium/components/segmentation_platform/internal/segmentation_ukm_helper.cc
@@ -0,0 +1,131 @@
+// Copyright 2022 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.
+
+#include "components/segmentation_platform/internal/segmentation_ukm_helper.h"
+
+#include "base/bit_cast.h"
+#include "base/metrics/field_trial_params.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "components/segmentation_platform/internal/stats.h"
+#include "components/segmentation_platform/public/config.h"
+#include "components/segmentation_platform/public/features.h"
+#include "services/metrics/public/cpp/ukm_builders.h"
+#include "services/metrics/public/cpp/ukm_recorder.h"
+
+#define CALL_MEMBER_FN(obj, func) ((obj).*(func))
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x)[0])
+
+using ukm::builders::Segmentation_ModelExecution;
+
+namespace {
+using UkmMemberFn =
+ Segmentation_ModelExecution& (Segmentation_ModelExecution::*)(int64_t);
+
+const UkmMemberFn kSegmentationUkmMethods[] = {
+ &Segmentation_ModelExecution::SetInput0,
+ &Segmentation_ModelExecution::SetInput1,
+ &Segmentation_ModelExecution::SetInput2,
+ &Segmentation_ModelExecution::SetInput3,
+ &Segmentation_ModelExecution::SetInput4,
+ &Segmentation_ModelExecution::SetInput5,
+ &Segmentation_ModelExecution::SetInput6,
+ &Segmentation_ModelExecution::SetInput7,
+ &Segmentation_ModelExecution::SetInput8,
+ &Segmentation_ModelExecution::SetInput9,
+ &Segmentation_ModelExecution::SetInput10,
+ &Segmentation_ModelExecution::SetInput11,
+ &Segmentation_ModelExecution::SetInput12,
+ &Segmentation_ModelExecution::SetInput13,
+ &Segmentation_ModelExecution::SetInput14,
+ &Segmentation_ModelExecution::SetInput15,
+ &Segmentation_ModelExecution::SetInput16,
+ &Segmentation_ModelExecution::SetInput17,
+ &Segmentation_ModelExecution::SetInput18,
+ &Segmentation_ModelExecution::SetInput19,
+ &Segmentation_ModelExecution::SetInput20,
+ &Segmentation_ModelExecution::SetInput21,
+ &Segmentation_ModelExecution::SetInput22,
+ &Segmentation_ModelExecution::SetInput23,
+ &Segmentation_ModelExecution::SetInput24,
+ &Segmentation_ModelExecution::SetInput25,
+ &Segmentation_ModelExecution::SetInput26,
+ &Segmentation_ModelExecution::SetInput27,
+ &Segmentation_ModelExecution::SetInput28,
+ &Segmentation_ModelExecution::SetInput29};
+
+// Gets a set of segment IDs that are allowed to upload metrics.
+base::flat_set<int> GetSegmentIdsAllowedForReporting() {
+ std::vector<std::string> segment_ids = base::SplitString(
+ base::GetFieldTrialParamValueByFeature(
+ segmentation_platform::features::
+ kSegmentationStructuredMetricsFeature,
+ segmentation_platform::kSegmentIdsAllowedForReportingKey),
+ ",;", base::WhitespaceHandling::TRIM_WHITESPACE,
+ base::SplitResult::SPLIT_WANT_NONEMPTY);
+ base::flat_set<int> result;
+ for (const auto& id : segment_ids) {
+ int segment_id;
+ if (base::StringToInt(id, &segment_id))
+ result.emplace(segment_id);
+ }
+ return result;
+}
+
+} // namespace
+
+namespace segmentation_platform {
+
+SegmentationUkmHelper::SegmentationUkmHelper() {
+ Initialize();
+}
+
+SegmentationUkmHelper::~SegmentationUkmHelper() = default;
+
+void SegmentationUkmHelper::Initialize() {
+ allowed_segment_ids_ = GetSegmentIdsAllowedForReporting();
+}
+
+// static
+SegmentationUkmHelper* SegmentationUkmHelper::GetInstance() {
+ static base::NoDestructor<SegmentationUkmHelper> helper;
+ return helper.get();
+}
+
+ukm::SourceId SegmentationUkmHelper::RecordModelExecutionResult(
+ OptimizationTarget segment_id,
+ int64_t model_version,
+ const std::vector<float>& input_tensor,
+ float result) {
+ // Check if the |segment_id| is allowed to record metrics.
+ if (!allowed_segment_ids_.contains(static_cast<int>(segment_id)))
+ return ukm::kInvalidSourceId;
+
+ ukm::SourceId source_id = ukm::NoURLSourceId();
+ // Don't record UKM if there are too many tensors.
+ if (input_tensor.size() > ARRAY_SIZE(kSegmentationUkmMethods)) {
+ stats::RecordTooManyInputTensors(input_tensor.size());
+ return ukm::kInvalidSourceId;
+ }
+ ukm::builders::Segmentation_ModelExecution execution_result(source_id);
+
+ execution_result.SetOptimizationTarget(segment_id)
+ .SetModelVersion(model_version);
+
+ for (size_t i = 0; i < input_tensor.size(); ++i) {
+ CALL_MEMBER_FN(execution_result, kSegmentationUkmMethods[i])
+ (FloatToInt64(input_tensor[i]));
+ }
+ execution_result.SetPredictionResult(FloatToInt64(result))
+ .Record(ukm::UkmRecorder::Get());
+ return source_id;
+}
+
+// static
+int64_t SegmentationUkmHelper::FloatToInt64(float f) {
+ // Encode the float number in IEEE754 double precision.
+ return bit_cast<int64_t>(static_cast<double>(f));
+}
+
+} // namespace segmentation_platform
diff --git a/chromium/components/segmentation_platform/internal/segmentation_ukm_helper.h b/chromium/components/segmentation_platform/internal/segmentation_ukm_helper.h
new file mode 100644
index 00000000000..3df93385f54
--- /dev/null
+++ b/chromium/components/segmentation_platform/internal/segmentation_ukm_helper.h
@@ -0,0 +1,48 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_SEGMENTATION_UKM_HELPER_H_
+#define COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_SEGMENTATION_UKM_HELPER_H_
+
+#include "base/containers/flat_set.h"
+#include "base/no_destructor.h"
+#include "components/optimization_guide/proto/models.pb.h"
+#include "services/metrics/public/cpp/ukm_source_id.h"
+
+using optimization_guide::proto::OptimizationTarget;
+
+namespace segmentation_platform {
+
+// A helper class to record segmentation model execution results in UKM.
+class SegmentationUkmHelper {
+ public:
+ static SegmentationUkmHelper* GetInstance();
+ SegmentationUkmHelper(const SegmentationUkmHelper&) = delete;
+ SegmentationUkmHelper& operator=(const SegmentationUkmHelper&) = delete;
+
+ // Record segmentation model information and input/output after the
+ // executing the model, and return the UKM source ID.
+ ukm::SourceId RecordModelExecutionResult(
+ OptimizationTarget segment_id,
+ int64_t model_version,
+ const std::vector<float>& input_tensor,
+ float result);
+
+ // Helper method to encode a float number into int64.
+ static int64_t FloatToInt64(float f);
+
+ private:
+ friend class base::NoDestructor<SegmentationUkmHelper>;
+ friend class SegmentationUkmHelperTest;
+ SegmentationUkmHelper();
+ ~SegmentationUkmHelper();
+
+ void Initialize();
+
+ base::flat_set<int> allowed_segment_ids_;
+};
+
+} // namespace segmentation_platform
+
+#endif // COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_SEGMENTATION_UKM_HELPER_H_
diff --git a/chromium/components/segmentation_platform/internal/segmentation_ukm_helper_unittest.cc b/chromium/components/segmentation_platform/internal/segmentation_ukm_helper_unittest.cc
new file mode 100644
index 00000000000..d88fcd44a2d
--- /dev/null
+++ b/chromium/components/segmentation_platform/internal/segmentation_ukm_helper_unittest.cc
@@ -0,0 +1,180 @@
+// Copyright 2022 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.
+
+#include "components/segmentation_platform/internal/segmentation_ukm_helper.h"
+
+#include <cmath>
+
+#include "base/bit_cast.h"
+#include "base/test/metrics/histogram_tester.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/test/task_environment.h"
+#include "components/segmentation_platform/public/config.h"
+#include "components/segmentation_platform/public/features.h"
+#include "components/ukm/test_ukm_recorder.h"
+#include "services/metrics/public/cpp/ukm_builders.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using Segmentation_ModelExecution = ukm::builders::Segmentation_ModelExecution;
+
+namespace {
+
+// Round errors allowed during conversion.
+static const double kRoundingError = 1E-5;
+
+float Int64ToFloat(int64_t encoded) {
+ return static_cast<float>(bit_cast<double>(encoded));
+}
+
+void CompareEncodeDecodeDifference(float tensor) {
+ ASSERT_LT(
+ std::abs(tensor -
+ Int64ToFloat(
+ segmentation_platform::SegmentationUkmHelper::FloatToInt64(
+ tensor))),
+ kRoundingError);
+}
+
+} // namespace
+
+namespace segmentation_platform {
+
+class SegmentationUkmHelperTest : public testing::Test {
+ public:
+ SegmentationUkmHelperTest() = default;
+
+ SegmentationUkmHelperTest(const SegmentationUkmHelperTest&) = delete;
+ SegmentationUkmHelperTest& operator=(const SegmentationUkmHelperTest&) =
+ delete;
+
+ ~SegmentationUkmHelperTest() override = default;
+
+ void SetUp() override { test_recorder_.Purge(); }
+
+ void ExpectUkmMetrics(const base::StringPiece entry_name,
+ const std::vector<base::StringPiece>& keys,
+ const std::vector<int64_t>& values) {
+ const auto& entries = test_recorder_.GetEntriesByName(entry_name);
+ EXPECT_EQ(1u, entries.size());
+ for (const auto* entry : entries) {
+ const size_t keys_size = keys.size();
+ EXPECT_EQ(keys_size, values.size());
+ for (size_t i = 0; i < keys_size; ++i) {
+ test_recorder_.ExpectEntryMetric(entry, keys[i], values[i]);
+ }
+ }
+ }
+
+ void ExpectEmptyUkmMetrics(const base::StringPiece entry_name) {
+ EXPECT_EQ(0u, test_recorder_.GetEntriesByName(entry_name).size());
+ }
+
+ void InitializeAllowedSegmentIds(const std::string& allowed_ids) {
+ std::map<std::string, std::string> params = {
+ {kSegmentIdsAllowedForReportingKey, allowed_ids}};
+ feature_list_.InitAndEnableFeatureWithParameters(
+ features::kSegmentationStructuredMetricsFeature, params);
+ SegmentationUkmHelper::GetInstance()->Initialize();
+ }
+
+ void DisableStructureMetrics() {
+ feature_list_.InitAndDisableFeature(
+ features::kSegmentationStructuredMetricsFeature);
+ SegmentationUkmHelper::GetInstance()->Initialize();
+ }
+
+ protected:
+ base::test::TaskEnvironment task_environment_;
+ ukm::TestAutoSetUkmRecorder test_recorder_;
+ base::test::ScopedFeatureList feature_list_;
+};
+
+// Tests that basic recording works properly.
+TEST_F(SegmentationUkmHelperTest, TestBasicReporting) {
+ // Allow results for OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB to be recorded.
+ InitializeAllowedSegmentIds("4");
+ std::vector<float> input_tensors = {0.1, 0.7, 0.8, 0.5};
+ SegmentationUkmHelper::GetInstance()->RecordModelExecutionResult(
+ optimization_guide::proto::OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB, 101,
+ input_tensors, 0.6);
+ ExpectUkmMetrics(
+ Segmentation_ModelExecution::kEntryName,
+ {Segmentation_ModelExecution::kOptimizationTargetName,
+ Segmentation_ModelExecution::kModelVersionName,
+ Segmentation_ModelExecution::kInput0Name,
+ Segmentation_ModelExecution::kInput1Name,
+ Segmentation_ModelExecution::kInput2Name,
+ Segmentation_ModelExecution::kInput3Name,
+ Segmentation_ModelExecution::kPredictionResultName},
+ {
+ optimization_guide::proto::OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB,
+ 101,
+ SegmentationUkmHelper::FloatToInt64(0.1),
+ SegmentationUkmHelper::FloatToInt64(0.7),
+ SegmentationUkmHelper::FloatToInt64(0.8),
+ SegmentationUkmHelper::FloatToInt64(0.5),
+ SegmentationUkmHelper::FloatToInt64(0.6),
+ });
+}
+
+// Tests that recording is disabled if kSegmentationStructuredMetricsFeature
+// is disabled.
+TEST_F(SegmentationUkmHelperTest, TestDisabledStructuredMetrics) {
+ DisableStructureMetrics();
+ std::vector<float> input_tensors = {0.1, 0.7, 0.8, 0.5};
+ SegmentationUkmHelper::GetInstance()->RecordModelExecutionResult(
+ optimization_guide::proto::OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB, 101,
+ input_tensors, 0.6);
+ ExpectEmptyUkmMetrics(Segmentation_ModelExecution::kEntryName);
+}
+
+// Tests that recording is disabled for segment IDs that are not in the allowed
+// list.
+TEST_F(SegmentationUkmHelperTest, TestNotAllowedSegmentId) {
+ InitializeAllowedSegmentIds("7, 8");
+ std::vector<float> input_tensors = {0.1, 0.7, 0.8, 0.5};
+ SegmentationUkmHelper::GetInstance()->RecordModelExecutionResult(
+ optimization_guide::proto::OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB, 101,
+ input_tensors, 0.6);
+ ExpectEmptyUkmMetrics(Segmentation_ModelExecution::kEntryName);
+}
+
+// Tests that float encoding works properly.
+TEST_F(SegmentationUkmHelperTest, TestFloatEncoding) {
+ // Compare the numbers with their IEEE754 binary representations in double.
+ ASSERT_EQ(SegmentationUkmHelper::FloatToInt64(0.5), 0x3FE0000000000000);
+ ASSERT_EQ(SegmentationUkmHelper::FloatToInt64(0.25), 0x3FD0000000000000);
+ ASSERT_EQ(SegmentationUkmHelper::FloatToInt64(0.125), 0x3FC0000000000000);
+ ASSERT_EQ(SegmentationUkmHelper::FloatToInt64(0.75), 0x3FE8000000000000);
+ ASSERT_EQ(SegmentationUkmHelper::FloatToInt64(1), 0x3FF0000000000000);
+ ASSERT_EQ(SegmentationUkmHelper::FloatToInt64(0), 0);
+ ASSERT_EQ(SegmentationUkmHelper::FloatToInt64(10), 0x4024000000000000);
+}
+
+// Tests that floats encoded can be properly decoded later.
+TEST_F(SegmentationUkmHelperTest, FloatEncodeDeocode) {
+ CompareEncodeDecodeDifference(0.1);
+ CompareEncodeDecodeDifference(0.5);
+ CompareEncodeDecodeDifference(0.88);
+ CompareEncodeDecodeDifference(0.01);
+ ASSERT_EQ(0, Int64ToFloat(SegmentationUkmHelper::FloatToInt64(0)));
+ ASSERT_EQ(1, Int64ToFloat(SegmentationUkmHelper::FloatToInt64(1)));
+}
+
+// Tests that there are too many input tensors to record.
+TEST_F(SegmentationUkmHelperTest, TooManyInputTensors) {
+ base::HistogramTester tester;
+ std::string histogram_name(
+ "SegmentationPlatform.StructuredMetrics.TooManyTensors.Count");
+ InitializeAllowedSegmentIds("4");
+ std::vector<float> input_tensors(100, 0.1);
+ ukm::SourceId source_id =
+ SegmentationUkmHelper::GetInstance()->RecordModelExecutionResult(
+ optimization_guide::proto::OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB,
+ 101, input_tensors, 0.6);
+ ASSERT_EQ(source_id, ukm::kInvalidSourceId);
+ tester.ExpectTotalCount(histogram_name, 1);
+ ASSERT_EQ(tester.GetTotalSum(histogram_name), 100);
+}
+} // namespace segmentation_platform
diff --git a/chromium/components/segmentation_platform/internal/selection/segment_score_provider.cc b/chromium/components/segmentation_platform/internal/selection/segment_score_provider.cc
index 756914cf36e..eda9084bea0 100644
--- a/chromium/components/segmentation_platform/internal/selection/segment_score_provider.cc
+++ b/chromium/components/segmentation_platform/internal/selection/segment_score_provider.cc
@@ -46,10 +46,9 @@ class SegmentScoreProviderImpl : public SegmentScoreProvider {
private:
void ReadScoresFromLastSession(
base::OnceClosure callback,
- std::vector<std::pair<OptimizationTarget, proto::SegmentInfo>>
- all_segments) {
+ std::unique_ptr<SegmentInfoDatabase::SegmentInfoList> all_segments) {
// Read results from last session to memory.
- for (const auto& pair : all_segments) {
+ for (const auto& pair : *all_segments) {
OptimizationTarget id = pair.first;
const proto::SegmentInfo& info = pair.second;
if (!info.has_prediction_result())
diff --git a/chromium/components/segmentation_platform/internal/selection/segment_selector.h b/chromium/components/segmentation_platform/internal/selection/segment_selector.h
index e86615cba4f..af20d2ab023 100644
--- a/chromium/components/segmentation_platform/internal/selection/segment_selector.h
+++ b/chromium/components/segmentation_platform/internal/selection/segment_selector.h
@@ -28,9 +28,13 @@ class SegmentSelector : public ModelExecutionScheduler::Observer {
using SegmentSelectionCallback =
base::OnceCallback<void(const SegmentSelectionResult&)>;
- // Client API. Returns the selected segment from the last session. If none,
- // returns empty result.
+ // Client API. Returns the selected segment from the last session
+ // asynchronously. If none, returns empty result.
virtual void GetSelectedSegment(SegmentSelectionCallback callback) = 0;
+
+ // Client API. Returns the cached selected segment from the last session
+ // synchronously.
+ virtual SegmentSelectionResult GetCachedSegmentResult() = 0;
};
} // namespace segmentation_platform
diff --git a/chromium/components/segmentation_platform/internal/selection/segment_selector_impl.cc b/chromium/components/segmentation_platform/internal/selection/segment_selector_impl.cc
index d444276a595..4024baa60e0 100644
--- a/chromium/components/segmentation_platform/internal/selection/segment_selector_impl.cc
+++ b/chromium/components/segmentation_platform/internal/selection/segment_selector_impl.cc
@@ -42,6 +42,12 @@ SegmentSelectorImpl::SegmentSelectorImpl(
if (selected_segment.has_value()) {
selected_segment_last_session_.segment = selected_segment->segment_id;
selected_segment_last_session_.is_ready = true;
+ stats::RecordSegmentSelectionFailure(
+ stats::SegmentationSelectionFailureReason::kSelectionAvailableInPrefs);
+ } else {
+ stats::RecordSegmentSelectionFailure(
+ stats::SegmentationSelectionFailureReason::
+ kInvalidSelectionResultInPrefs);
}
}
@@ -54,6 +60,10 @@ void SegmentSelectorImpl::GetSelectedSegment(
base::BindOnce(std::move(callback), selected_segment_last_session_));
}
+SegmentSelectionResult SegmentSelectorImpl::GetCachedSegmentResult() {
+ return selected_segment_last_session_;
+}
+
void SegmentSelectorImpl::OnModelExecutionCompleted(
OptimizationTarget segment_id) {
// If the |segment_id| is not in config, then skip any updates early.
@@ -67,18 +77,16 @@ void SegmentSelectorImpl::OnModelExecutionCompleted(
}
void SegmentSelectorImpl::RunSegmentSelection(
- std::vector<std::pair<OptimizationTarget, proto::SegmentInfo>>
- all_segments) {
- if (!CanComputeSegmentSelection(all_segments))
+ std::unique_ptr<SegmentInfoDatabase::SegmentInfoList> all_segments) {
+ if (!CanComputeSegmentSelection(*all_segments))
return;
- OptimizationTarget selected_segment = FindBestSegment(all_segments);
+ OptimizationTarget selected_segment = FindBestSegment(*all_segments);
UpdateSelectedSegment(selected_segment);
}
bool SegmentSelectorImpl::CanComputeSegmentSelection(
- const std::vector<std::pair<OptimizationTarget, proto::SegmentInfo>>&
- all_segments) {
+ const SegmentInfoDatabase::SegmentInfoList& all_segments) {
VLOG(1) << __func__ << ": all_segments.size()=" << all_segments.size();
// Don't compute results if we don't have enough signals, or don't have
// valid unexpired results for any of the segments.
@@ -90,6 +98,9 @@ bool SegmentSelectorImpl::CanComputeSegmentSelection(
VLOG(1) << __func__ << ": segment="
<< OptimizationTarget_Name(segment_info.segment_id())
<< " does not meet signal collection requirements.";
+ stats::RecordSegmentSelectionFailure(
+ stats::SegmentationSelectionFailureReason::
+ kAtLeastOneSegmentSignalsNotCollected);
return false;
}
@@ -98,6 +109,9 @@ bool SegmentSelectorImpl::CanComputeSegmentSelection(
VLOG(1) << __func__ << ": segment="
<< OptimizationTarget_Name(segment_info.segment_id())
<< " has expired or unavailable result.";
+ stats::RecordSegmentSelectionFailure(
+ stats::SegmentationSelectionFailureReason::
+ kAtLeastOneSegmentNotReady);
return false;
}
}
@@ -113,6 +127,8 @@ bool SegmentSelectorImpl::CanComputeSegmentSelection(
: config_->segment_selection_ttl;
if (!platform_options_.force_refresh_results &&
previous_selection->selection_time + ttl_to_use > clock_->Now()) {
+ stats::RecordSegmentSelectionFailure(
+ stats::SegmentationSelectionFailureReason::kSelectionTtlNotExpired);
VLOG(1) << __func__ << ": previous selection of segment="
<< OptimizationTarget_Name(previous_selection->segment_id)
<< " has not yet expired.";
@@ -124,8 +140,7 @@ bool SegmentSelectorImpl::CanComputeSegmentSelection(
}
OptimizationTarget SegmentSelectorImpl::FindBestSegment(
- const std::vector<std::pair<OptimizationTarget, proto::SegmentInfo>>&
- all_segments) {
+ const SegmentInfoDatabase::SegmentInfoList& all_segments) {
int max_score = 0;
OptimizationTarget max_score_id =
OptimizationTarget::OPTIMIZATION_TARGET_UNKNOWN;
diff --git a/chromium/components/segmentation_platform/internal/selection/segment_selector_impl.h b/chromium/components/segmentation_platform/internal/selection/segment_selector_impl.h
index d48bd834f42..4a2c984575f 100644
--- a/chromium/components/segmentation_platform/internal/selection/segment_selector_impl.h
+++ b/chromium/components/segmentation_platform/internal/selection/segment_selector_impl.h
@@ -9,6 +9,7 @@
#include "components/segmentation_platform/internal/selection/segment_selector.h"
#include "base/callback_helpers.h"
+#include "components/segmentation_platform/internal/database/segment_info_database.h"
#include "components/segmentation_platform/internal/platform_options.h"
#include "components/segmentation_platform/public/segment_selection_result.h"
@@ -21,13 +22,8 @@ namespace segmentation_platform {
struct Config;
class ModelExecutionScheduler;
class SegmentationResultPrefs;
-class SegmentInfoDatabase;
class SignalStorageConfig;
-namespace proto {
-class SegmentInfo;
-} // namespace proto
-
class SegmentSelectorImpl : public SegmentSelector {
public:
SegmentSelectorImpl(SegmentInfoDatabase* segment_database,
@@ -41,6 +37,11 @@ class SegmentSelectorImpl : public SegmentSelector {
// SegmentSelector overrides.
void GetSelectedSegment(SegmentSelectionCallback callback) override;
+ SegmentSelectionResult GetCachedSegmentResult() override;
+
+ // Helper function to update the selected segment in the prefs. Auto-extends
+ // the selection if the new result is unknown.
+ virtual void UpdateSelectedSegment(OptimizationTarget new_selection);
// ModelExecutionScheduler::Observer overrides.
@@ -54,26 +55,19 @@ class SegmentSelectorImpl : public SegmentSelector {
// Helper method to run segment selection if possible.
void RunSegmentSelection(
- std::vector<std::pair<OptimizationTarget, proto::SegmentInfo>>
- all_segments);
+ std::unique_ptr<SegmentInfoDatabase::SegmentInfoList> all_segments);
// Determines whether segment selection can be run based on whether all
// segments have met signal collection requirement, have valid results, and
// segment selection TTL has expired.
bool CanComputeSegmentSelection(
- const std::vector<std::pair<OptimizationTarget, proto::SegmentInfo>>&
- all_segments);
+ const SegmentInfoDatabase::SegmentInfoList& all_segments);
// Loops through all segments, performs discrete mapping, honors finch
// supplied tie-breakers, TTL, inertia etc, and finds the highest score.
// Ignores the segments that have no results.
OptimizationTarget FindBestSegment(
- const std::vector<std::pair<OptimizationTarget, proto::SegmentInfo>>&
- all_segments);
-
- // Helper function to update the selected segment in the prefs. Auto-extends
- // the selection if the new result is unknown.
- void UpdateSelectedSegment(OptimizationTarget new_selection);
+ const SegmentInfoDatabase::SegmentInfoList& all_segments);
// The database storing metadata and results.
raw_ptr<SegmentInfoDatabase> segment_database_;
diff --git a/chromium/components/segmentation_platform/internal/selection/segment_selector_unittest.cc b/chromium/components/segmentation_platform/internal/selection/segment_selector_unittest.cc
index 63bf8d35340..e02af0ef66a 100644
--- a/chromium/components/segmentation_platform/internal/selection/segment_selector_unittest.cc
+++ b/chromium/components/segmentation_platform/internal/selection/segment_selector_unittest.cc
@@ -301,6 +301,7 @@ TEST_F(SegmentSelectorTest,
result.segment = segment_id0;
result.is_ready = true;
GetSelectedSegment(result);
+ ASSERT_EQ(result, segment_selector_->GetCachedSegmentResult());
// Add results for a new segment.
base::Time result_timestamp = base::Time::Now();
@@ -312,6 +313,37 @@ TEST_F(SegmentSelectorTest,
// GetSelectedSegment should still return value from previous session.
GetSelectedSegment(result);
+ ASSERT_EQ(result, segment_selector_->GetCachedSegmentResult());
+}
+
+// Tests that prefs are properly updated after calling UpdateSelectedSegment().
+TEST_F(SegmentSelectorTest, UpdateSelectedSegment) {
+ SetUpWithConfig(CreateTestConfig());
+ EXPECT_CALL(signal_storage_config_, MeetsSignalCollectionRequirement(_))
+ .WillRepeatedly(Return(true));
+
+ OptimizationTarget segment_id =
+ OptimizationTarget::OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB;
+ float mapping[][2] = {{0.2, 1}, {0.5, 3}, {0.7, 4}};
+ InitializeMetadataForSegment(segment_id, mapping, 3);
+
+ OptimizationTarget segment_id2 =
+ OptimizationTarget::OPTIMIZATION_TARGET_SEGMENTATION_SHARE;
+ float mapping2[][2] = {{0.3, 1}, {0.4, 4}};
+ InitializeMetadataForSegment(segment_id2, mapping2, 2);
+
+ segment_database_->AddPredictionResult(segment_id, 0.6, clock_.Now());
+ segment_database_->AddPredictionResult(segment_id2, 0.5, clock_.Now());
+
+ clock_.Advance(base::Days(1));
+ segment_selector_->OnModelExecutionCompleted(segment_id);
+ ASSERT_TRUE(prefs_->selection.has_value());
+ ASSERT_EQ(segment_id2, prefs_->selection->segment_id);
+
+ // Update the selected segment to |segment_id|.
+ segment_selector_->UpdateSelectedSegment(segment_id);
+ ASSERT_TRUE(prefs_->selection.has_value());
+ ASSERT_EQ(segment_id, prefs_->selection->segment_id);
}
} // namespace segmentation_platform
diff --git a/chromium/components/segmentation_platform/internal/selection/segmentation_result_prefs.cc b/chromium/components/segmentation_platform/internal/selection/segmentation_result_prefs.cc
index 82ae63311c1..e5f87e2963c 100644
--- a/chromium/components/segmentation_platform/internal/selection/segmentation_result_prefs.cc
+++ b/chromium/components/segmentation_platform/internal/selection/segmentation_result_prefs.cc
@@ -24,7 +24,7 @@ void SegmentationResultPrefs::SaveSegmentationResultToPref(
const std::string& result_key,
const absl::optional<SelectedSegment>& selected_segment) {
DictionaryPrefUpdate update(prefs_, kSegmentationResultPref);
- base::DictionaryValue* dictionary = update.Get();
+ base::Value* dictionary = update.Get();
if (!selected_segment.has_value()) {
dictionary->RemoveKey(result_key);
return;
@@ -41,7 +41,7 @@ void SegmentationResultPrefs::SaveSegmentationResultToPref(
absl::optional<SelectedSegment>
SegmentationResultPrefs::ReadSegmentationResultFromPref(
const std::string& result_key) {
- const base::DictionaryValue* dictionary =
+ const base::Value* dictionary =
prefs_->GetDictionary(kSegmentationResultPref);
DCHECK(dictionary);
diff --git a/chromium/components/segmentation_platform/internal/service_proxy_impl.cc b/chromium/components/segmentation_platform/internal/service_proxy_impl.cc
index c399021babe..8d7852e86ef 100644
--- a/chromium/components/segmentation_platform/internal/service_proxy_impl.cc
+++ b/chromium/components/segmentation_platform/internal/service_proxy_impl.cc
@@ -5,41 +5,62 @@
#include "components/segmentation_platform/internal/service_proxy_impl.h"
#include <inttypes.h>
+#include <sstream>
+#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
+#include "base/time/time.h"
+#include "components/optimization_guide/core/model_util.h"
#include "components/optimization_guide/core/optimization_guide_util.h"
+#include "components/segmentation_platform/internal/database/metadata_utils.h"
+#include "components/segmentation_platform/internal/database/signal_storage_config.h"
+#include "components/segmentation_platform/internal/scheduler/model_execution_scheduler_impl.h"
#include "components/segmentation_platform/internal/segmentation_platform_service_impl.h"
+#include "components/segmentation_platform/internal/selection/segment_selector_impl.h"
+#include "components/segmentation_platform/public/config.h"
+#include "base/logging.h"
namespace segmentation_platform {
-// static
-std::string ServiceProxyImpl::SegmentInfoToString(
- const proto::SegmentInfo& segment_info) {
- std::string result;
- if (segment_info.has_segment_id()) {
- result = "segment_id: " +
- optimization_guide::GetStringNameForOptimizationTarget(
- segment_info.segment_id()) +
- "\n";
- }
- if (segment_info.has_prediction_result()) {
- const auto prediction_result = segment_info.prediction_result();
- std::string prediction_result_str = base::StringPrintf(
- "prediction_result: { result: %f, timestamp_us: %" PRId64 " }\n",
- prediction_result.has_result() ? prediction_result.result() : 0,
- prediction_result.has_timestamp_us() ? prediction_result.timestamp_us()
- : 0);
- result.append(prediction_result_str);
- }
- return result;
+namespace {
+std::string SegmentMetadataToString(const proto::SegmentInfo& segment_info) {
+ if (!segment_info.has_model_metadata())
+ return std::string();
+
+ return "model_metadata: { " +
+ metadata_utils::SegmetationModelMetadataToString(
+ segment_info.model_metadata()) +
+ " }";
}
-ServiceProxyImpl::ServiceProxyImpl(SegmentationPlatformService* service,
- SegmentInfoDatabase* segment_db)
- : is_service_initialized_(false),
- service_status_flag_(0),
- service_(service),
- segment_db_(segment_db) {}
+std::string PredictionResultToString(const proto::SegmentInfo& segment_info) {
+ if (!segment_info.has_prediction_result())
+ return std::string();
+ const auto prediction_result = segment_info.prediction_result();
+ base::Time time;
+ if (prediction_result.has_timestamp_us()) {
+ time = base::Time::FromDeltaSinceWindowsEpoch(
+ base::Microseconds(prediction_result.timestamp_us()));
+ }
+ std::ostringstream time_string;
+ time_string << time;
+ return base::StringPrintf(
+ "result: %f, time: %s",
+ prediction_result.has_result() ? prediction_result.result() : 0,
+ time_string.str().c_str());
+}
+} // namespace
+
+ServiceProxyImpl::ServiceProxyImpl(
+ SegmentInfoDatabase* segment_db,
+ SignalStorageConfig* signal_storage_config,
+ std::vector<std::unique_ptr<Config>>* configs,
+ base::flat_map<std::string, std::unique_ptr<SegmentSelectorImpl>>*
+ segment_selectors)
+ : segment_db_(segment_db),
+ signal_storage_config_(signal_storage_config),
+ configs_(configs),
+ segment_selectors_(segment_selectors) {}
ServiceProxyImpl::~ServiceProxyImpl() = default;
@@ -53,41 +74,114 @@ void ServiceProxyImpl::RemoveObserver(ServiceProxy::Observer* observer) {
void ServiceProxyImpl::OnServiceStatusChanged(bool is_initialized,
int status_flag) {
+ bool changed = (is_service_initialized_ != is_initialized) ||
+ (service_status_flag_ != status_flag);
is_service_initialized_ = is_initialized;
service_status_flag_ = status_flag;
- for (Observer& obs : observers_)
- obs.OnServiceStatusChanged(is_initialized, status_flag);
+ UpdateObservers(changed);
+}
+
+void ServiceProxyImpl::UpdateObservers(bool update_service_status) {
+ if (update_service_status) {
+ for (Observer& obs : observers_)
+ obs.OnServiceStatusChanged(is_service_initialized_, service_status_flag_);
+ }
if (segment_db_ &&
(static_cast<int>(ServiceStatus::kSegmentationInfoDbInitialized) &
- status_flag)) {
+ service_status_flag_)) {
segment_db_->GetAllSegmentInfo(
base::BindOnce(&ServiceProxyImpl::OnGetAllSegmentationInfo,
weak_ptr_factory_.GetWeakPtr()));
}
}
+void ServiceProxyImpl::SetModelExecutionScheduler(
+ ModelExecutionScheduler* model_execution_scheduler) {
+ model_execution_scheduler_ = model_execution_scheduler;
+}
+
void ServiceProxyImpl::GetServiceStatus() {
- OnServiceStatusChanged(is_service_initialized_, service_status_flag_);
+ UpdateObservers(true /* update_service_status */);
}
-void ServiceProxyImpl::GetSelectedSegment(
- const std::string& segmentation_key,
- SegmentationPlatformService::SegmentSelectionCallback callback) {
- service_->GetSelectedSegment(segmentation_key, std::move(callback));
+void ServiceProxyImpl::ExecuteModel(OptimizationTarget segment_id) {
+ if (!model_execution_scheduler_)
+ return;
+ if (segment_id != OptimizationTarget::OPTIMIZATION_TARGET_UNKNOWN) {
+ model_execution_scheduler_->RequestModelExecution(segment_id);
+ }
+}
+
+void ServiceProxyImpl::OverwriteResult(OptimizationTarget segment_id,
+ float result) {
+ if (!model_execution_scheduler_)
+ return;
+
+ if (result < 0 || result > 1)
+ return;
+
+ if (segment_id != OptimizationTarget::OPTIMIZATION_TARGET_UNKNOWN) {
+ model_execution_scheduler_->OnModelExecutionCompleted(
+ segment_id, std::make_pair(result, ModelExecutionStatus::kSuccess));
+ }
+}
+
+void ServiceProxyImpl::SetSelectedSegment(const std::string& segmentation_key,
+ OptimizationTarget segment_id) {
+ if (!segment_selectors_ ||
+ segment_selectors_->find(segmentation_key) == segment_selectors_->end()) {
+ return;
+ }
+ if (segment_id != OptimizationTarget::OPTIMIZATION_TARGET_UNKNOWN) {
+ auto& selector = segment_selectors_->at(segmentation_key);
+ selector->UpdateSelectedSegment(segment_id);
+ }
}
-// Called after retrieving all the segmentation info from the DB.
void ServiceProxyImpl::OnGetAllSegmentationInfo(
- std::vector<std::pair<OptimizationTarget, proto::SegmentInfo>>
- segment_infos) {
- std::vector<std::string> result;
- for (const auto& segment_info : segment_infos) {
- result.emplace_back(SegmentInfoToString(segment_info.second));
+ std::unique_ptr<SegmentInfoDatabase::SegmentInfoList> segment_info) {
+ if (!configs_)
+ return;
+
+ // Convert the |segment_info| vector to a map for quick lookup.
+ base::flat_map<OptimizationTarget, proto::SegmentInfo> optimization_targets;
+ for (const auto& info : *segment_info) {
+ optimization_targets[info.first] = info.second;
+ }
+
+ std::vector<ServiceProxy::ClientInfo> result;
+ for (const auto& config : *configs_) {
+ OptimizationTarget selected =
+ OptimizationTarget::OPTIMIZATION_TARGET_UNKNOWN;
+ if (segment_selectors_ &&
+ segment_selectors_->find(config->segmentation_key) !=
+ segment_selectors_->end()) {
+ absl::optional<optimization_guide::proto::OptimizationTarget> target =
+ segment_selectors_->at(config->segmentation_key)
+ ->GetCachedSegmentResult()
+ .segment;
+ if (target.has_value()) {
+ selected = target.value();
+ }
+ }
+ result.emplace_back(config->segmentation_key, selected);
+ for (const auto& segment_id : config->segment_ids) {
+ if (!optimization_targets.contains(segment_id))
+ continue;
+ const auto& info = optimization_targets[segment_id];
+ result.back().segment_status.emplace_back(
+ segment_id, SegmentMetadataToString(info),
+ PredictionResultToString(info),
+ signal_storage_config_
+ ? signal_storage_config_->MeetsSignalCollectionRequirement(
+ info.model_metadata())
+ : false);
+ }
}
for (Observer& obs : observers_)
- obs.OnSegmentInfoAvailable(result);
+ obs.OnClientInfoAvailable(result);
}
} // namespace segmentation_platform
diff --git a/chromium/components/segmentation_platform/internal/service_proxy_impl.h b/chromium/components/segmentation_platform/internal/service_proxy_impl.h
index d9d83bf24c7..86601f1a379 100644
--- a/chromium/components/segmentation_platform/internal/service_proxy_impl.h
+++ b/chromium/components/segmentation_platform/internal/service_proxy_impl.h
@@ -5,8 +5,11 @@
#ifndef COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_SERVICE_PROXY_IMPL_H_
#define COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_SERVICE_PROXY_IMPL_H_
+#include <memory>
#include <vector>
+#include "base/containers/flat_map.h"
+#include "base/memory/raw_ptr.h"
#include "base/observer_list.h"
#include "components/leveldb_proto/public/proto_database.h"
#include "components/optimization_guide/proto/models.pb.h"
@@ -16,46 +19,61 @@
using optimization_guide::proto::OptimizationTarget;
namespace segmentation_platform {
+struct Config;
+class SignalStorageConfig;
+class ModelExecutionScheduler;
+class SegmentSelectorImpl;
// A helper class to expose internals of the segmentationss service to a logging
// component and/or debug UI.
class ServiceProxyImpl : public ServiceProxy {
public:
- ServiceProxyImpl(SegmentationPlatformService* service,
- SegmentInfoDatabase* segment_db);
+ ServiceProxyImpl(
+ SegmentInfoDatabase* segment_db,
+ SignalStorageConfig* signal_storage_config,
+ std::vector<std::unique_ptr<Config>>* configs,
+ base::flat_map<std::string, std::unique_ptr<SegmentSelectorImpl>>*
+ segment_selectors);
~ServiceProxyImpl() override;
- // Helper method to convert |segment_info| to string.
- // TODO(qinmin): move this to a common utility class.
- static std::string SegmentInfoToString(
- const proto::SegmentInfo& segment_info);
-
void AddObserver(ServiceProxy::Observer* observer) override;
void RemoveObserver(ServiceProxy::Observer* observer) override;
ServiceProxyImpl(const ServiceProxyImpl& other) = delete;
ServiceProxyImpl& operator=(const ServiceProxyImpl& other) = delete;
- // Returns the current status of the segmentation service.
+ void SetModelExecutionScheduler(
+ ModelExecutionScheduler* model_execution_scheduler);
+
+ // ServiceProxy impl.
void GetServiceStatus() override;
- void GetSelectedSegment(
- const std::string& segmentation_key,
- SegmentationPlatformService::SegmentSelectionCallback callback) override;
+ void ExecuteModel(OptimizationTarget segment_id) override;
+ void OverwriteResult(OptimizationTarget segment_id, float result) override;
+ void SetSelectedSegment(const std::string& segmentation_key,
+ OptimizationTarget segment_id) override;
// Called when segmentation service status changed.
void OnServiceStatusChanged(bool is_initialized, int status_flag);
private:
+ // Called to update observers with new segmentation info. If
+ // |update_service_status| is true, status about the segmentation service will
+ // be sent.
+ void UpdateObservers(bool update_service_status);
+
// Called after retrieving all the segmentation info from the DB.
void OnGetAllSegmentationInfo(
- std::vector<std::pair<OptimizationTarget, proto::SegmentInfo>>
- segment_infos);
+ std::unique_ptr<SegmentInfoDatabase::SegmentInfoList> segment_info);
- bool is_service_initialized_;
- int service_status_flag_;
- SegmentationPlatformService* service_;
- SegmentInfoDatabase* segment_db_;
+ bool is_service_initialized_ = false;
+ int service_status_flag_ = 0;
+ raw_ptr<SegmentInfoDatabase> segment_db_;
+ raw_ptr<SignalStorageConfig> signal_storage_config_;
+ raw_ptr<std::vector<std::unique_ptr<Config>>> configs_;
base::ObserverList<ServiceProxy::Observer> observers_;
+ raw_ptr<ModelExecutionScheduler> model_execution_scheduler_{nullptr};
+ raw_ptr<base::flat_map<std::string, std::unique_ptr<SegmentSelectorImpl>>>
+ segment_selectors_;
base::WeakPtrFactory<ServiceProxyImpl> weak_ptr_factory_{this};
};
diff --git a/chromium/components/segmentation_platform/internal/service_proxy_impl_unittest.cc b/chromium/components/segmentation_platform/internal/service_proxy_impl_unittest.cc
index 02ca55a49e6..d6e200f166b 100644
--- a/chromium/components/segmentation_platform/internal/service_proxy_impl_unittest.cc
+++ b/chromium/components/segmentation_platform/internal/service_proxy_impl_unittest.cc
@@ -7,40 +7,100 @@
#include "base/strings/string_number_conversions.h"
#include "components/leveldb_proto/public/proto_database.h"
#include "components/leveldb_proto/testing/fake_db.h"
+#include "components/optimization_guide/core/model_util.h"
+#include "components/optimization_guide/core/optimization_guide_util.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/testing_pref_service.h"
+#include "components/segmentation_platform/internal/constants.h"
+#include "components/segmentation_platform/internal/platform_options.h"
+#include "components/segmentation_platform/internal/scheduler/model_execution_scheduler.h"
+#include "components/segmentation_platform/internal/selection/segment_selector_impl.h"
+#include "components/segmentation_platform/internal/selection/segmentation_result_prefs.h"
+#include "components/segmentation_platform/public/config.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using testing::_;
+
namespace segmentation_platform {
namespace {
// Adds a segment info into a map, and return a copy of it.
proto::SegmentInfo AddSegmentInfo(
std::map<std::string, proto::SegmentInfo>* db_entries,
+ Config* config,
OptimizationTarget segment_id) {
proto::SegmentInfo info;
info.set_segment_id(segment_id);
db_entries->insert(
std::make_pair(base::NumberToString(static_cast<int>(segment_id)), info));
+ config->segment_ids.emplace_back(segment_id);
return info;
}
+class MockModelExecutionScheduler : public ModelExecutionScheduler {
+ public:
+ MockModelExecutionScheduler() = default;
+ MOCK_METHOD(void, RequestModelExecution, (OptimizationTarget));
+ MOCK_METHOD(void, OnNewModelInfoReady, (const proto::SegmentInfo&));
+ MOCK_METHOD(void, RequestModelExecutionForEligibleSegments, (bool));
+ MOCK_METHOD(void,
+ OnModelExecutionCompleted,
+ (OptimizationTarget,
+ (const std::pair<float, ModelExecutionStatus>&)));
+};
+
} // namespace
+class FakeSegmentSelectorImpl : public SegmentSelectorImpl {
+ public:
+ FakeSegmentSelectorImpl(SegmentationResultPrefs* result_prefs,
+ const Config* config)
+ : SegmentSelectorImpl(nullptr,
+ nullptr,
+ result_prefs,
+ config,
+ nullptr,
+ PlatformOptions::CreateDefault()) {}
+ ~FakeSegmentSelectorImpl() override = default;
+
+ void UpdateSelectedSegment(OptimizationTarget new_selection) override {
+ new_selection_ = new_selection;
+ }
+
+ OptimizationTarget new_selection() const { return new_selection_; }
+
+ private:
+ OptimizationTarget new_selection_;
+};
+
class ServiceProxyImplTest : public testing::Test,
public ServiceProxy::Observer {
public:
ServiceProxyImplTest() = default;
~ServiceProxyImplTest() override = default;
+ void SetUp() override {
+ auto config = std::make_unique<Config>();
+ config->segmentation_key = "test";
+ configs_.emplace_back(std::move(config));
+ pref_service_.registry()->RegisterDictionaryPref(kSegmentationResultPref);
+ }
+
void SetUpProxy() {
DCHECK(!db_);
DCHECK(!segment_db_);
+
auto db = std::make_unique<leveldb_proto::test::FakeDB<proto::SegmentInfo>>(
&db_entries_);
db_ = db.get();
segment_db_ = std::make_unique<SegmentInfoDatabase>(std::move(db));
- service_proxy_impl_ =
- std::make_unique<ServiceProxyImpl>(nullptr, segment_db_.get());
+ result_prefs_ = std::make_unique<SegmentationResultPrefs>(&pref_service_);
+ segment_selectors_["test"] = std::make_unique<FakeSegmentSelectorImpl>(
+ result_prefs_.get(), configs_.at(0).get());
+ service_proxy_impl_ = std::make_unique<ServiceProxyImpl>(
+ segment_db_.get(), nullptr, &configs_, &segment_selectors_);
service_proxy_impl_->AddObserver(this);
}
@@ -48,6 +108,8 @@ class ServiceProxyImplTest : public testing::Test,
db_entries_.clear();
db_ = nullptr;
segment_db_.reset();
+ configs_.clear();
+ client_info_.clear();
}
void OnServiceStatusChanged(bool is_initialized, int status_flag) override {
@@ -55,9 +117,9 @@ class ServiceProxyImplTest : public testing::Test,
status_flag_ = status_flag;
}
- void OnSegmentInfoAvailable(
- const std::vector<std::string>& segment_info) override {
- segment_info_ = segment_info;
+ void OnClientInfoAvailable(
+ const std::vector<ServiceProxy::ClientInfo>& client_info) override {
+ client_info_ = client_info;
}
protected:
@@ -68,7 +130,12 @@ class ServiceProxyImplTest : public testing::Test,
raw_ptr<leveldb_proto::test::FakeDB<proto::SegmentInfo>> db_{nullptr};
std::unique_ptr<SegmentInfoDatabase> segment_db_;
std::unique_ptr<ServiceProxyImpl> service_proxy_impl_;
- std::vector<std::string> segment_info_;
+ std::vector<ServiceProxy::ClientInfo> client_info_;
+ std::vector<std::unique_ptr<Config>> configs_;
+ base::flat_map<std::string, std::unique_ptr<SegmentSelectorImpl>>
+ segment_selectors_;
+ TestingPrefServiceSimple pref_service_;
+ std::unique_ptr<SegmentationResultPrefs> result_prefs_;
};
TEST_F(ServiceProxyImplTest, GetServiceStatus) {
@@ -86,19 +153,108 @@ TEST_F(ServiceProxyImplTest, GetServiceStatus) {
ASSERT_EQ(status_flag_, 7);
db_->LoadCallback(true);
- ASSERT_TRUE(segment_info_.empty());
+ ASSERT_FALSE(client_info_.empty());
+ ASSERT_EQ(client_info_.size(), 1u);
}
TEST_F(ServiceProxyImplTest, GetSegmentationInfoFromDB) {
proto::SegmentInfo info = AddSegmentInfo(
- &db_entries_,
+ &db_entries_, configs_.at(0).get(),
+ OptimizationTarget::OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB);
+ SetUpProxy();
+
+ service_proxy_impl_->OnServiceStatusChanged(true, 7);
+ db_->LoadCallback(true);
+ ASSERT_EQ(client_info_.size(), 1u);
+ ASSERT_EQ(client_info_.at(0).segmentation_key, "test");
+ ASSERT_EQ(client_info_.at(0).segment_status.size(), 1u);
+ ServiceProxy::SegmentStatus status = client_info_.at(0).segment_status.at(0);
+ ASSERT_EQ(status.segment_id,
+ OptimizationTarget::OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB);
+ ASSERT_EQ(status.can_execute_segment, false);
+ ASSERT_TRUE(status.segment_metadata.empty());
+ ASSERT_TRUE(status.prediction_result.empty());
+}
+
+TEST_F(ServiceProxyImplTest, ExecuteModel) {
+ proto::SegmentInfo info = AddSegmentInfo(
+ &db_entries_, configs_.at(0).get(),
+ OptimizationTarget::OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB);
+ SetUpProxy();
+
+ service_proxy_impl_->OnServiceStatusChanged(true, 7);
+ db_->LoadCallback(true);
+
+ MockModelExecutionScheduler scheduler;
+ // Scheduler is not set, ExecuteModel() will do nothing.
+ EXPECT_CALL(scheduler, RequestModelExecution(_)).Times(0);
+ service_proxy_impl_->ExecuteModel(
+ OptimizationTarget::OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB);
+
+ service_proxy_impl_->SetModelExecutionScheduler(&scheduler);
+ EXPECT_CALL(scheduler,
+ RequestModelExecution(
+ OptimizationTarget::OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB))
+ .Times(1);
+ service_proxy_impl_->ExecuteModel(
+ OptimizationTarget::OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB);
+
+ EXPECT_CALL(scheduler, RequestModelExecution(_)).Times(0);
+ service_proxy_impl_->ExecuteModel(
+ OptimizationTarget::OPTIMIZATION_TARGET_UNKNOWN);
+}
+
+TEST_F(ServiceProxyImplTest, OverwriteResult) {
+ proto::SegmentInfo info = AddSegmentInfo(
+ &db_entries_, configs_.at(0).get(),
OptimizationTarget::OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB);
SetUpProxy();
service_proxy_impl_->OnServiceStatusChanged(true, 7);
db_->LoadCallback(true);
- ASSERT_EQ(segment_info_.size(), 1u);
- ASSERT_EQ(segment_info_.at(0), ServiceProxyImpl::SegmentInfoToString(info));
+
+ MockModelExecutionScheduler scheduler;
+
+ // Scheduler is not set, OverwriteValue() will do nothing.
+ EXPECT_CALL(scheduler, OnModelExecutionCompleted(_, _)).Times(0);
+ service_proxy_impl_->OverwriteResult(
+ OptimizationTarget::OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB, 0.7);
+
+ // Test with invalid values.
+ service_proxy_impl_->SetModelExecutionScheduler(&scheduler);
+ EXPECT_CALL(scheduler, OnModelExecutionCompleted(_, _)).Times(0);
+ service_proxy_impl_->OverwriteResult(
+ OptimizationTarget::OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB, 1.1);
+ service_proxy_impl_->OverwriteResult(
+ OptimizationTarget::OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB, -0.1);
+
+ EXPECT_CALL(
+ scheduler,
+ OnModelExecutionCompleted(
+ OptimizationTarget::OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB, _))
+ .Times(1);
+ service_proxy_impl_->OverwriteResult(
+ OptimizationTarget::OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB, 0.7);
+
+ EXPECT_CALL(scheduler, OnModelExecutionCompleted(_, _)).Times(0);
+ service_proxy_impl_->OverwriteResult(
+ OptimizationTarget::OPTIMIZATION_TARGET_UNKNOWN, 0.7);
}
+TEST_F(ServiceProxyImplTest, SetSelectSegment) {
+ proto::SegmentInfo info = AddSegmentInfo(
+ &db_entries_, configs_.at(0).get(),
+ OptimizationTarget::OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB);
+ SetUpProxy();
+
+ service_proxy_impl_->OnServiceStatusChanged(true, 7);
+ db_->LoadCallback(true);
+
+ service_proxy_impl_->SetSelectedSegment(
+ "test", OptimizationTarget::OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB);
+ ASSERT_EQ(
+ OptimizationTarget::OPTIMIZATION_TARGET_SEGMENTATION_NEW_TAB,
+ static_cast<FakeSegmentSelectorImpl*>(segment_selectors_["test"].get())
+ ->new_selection());
+}
} // namespace segmentation_platform
diff --git a/chromium/components/segmentation_platform/internal/signals/histogram_signal_handler.cc b/chromium/components/segmentation_platform/internal/signals/histogram_signal_handler.cc
index 933794cc593..f2adb381a15 100644
--- a/chromium/components/segmentation_platform/internal/signals/histogram_signal_handler.cc
+++ b/chromium/components/segmentation_platform/internal/signals/histogram_signal_handler.cc
@@ -4,6 +4,7 @@
#include "components/segmentation_platform/internal/signals/histogram_signal_handler.h"
+#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/metrics/metrics_hashes.h"
#include "components/segmentation_platform/internal/database/signal_database.h"
@@ -45,7 +46,27 @@ void HistogramSignalHandler::OnHistogramSample(
if (!metrics_enabled_)
return;
- db_->WriteSample(signal_type, name_hash, sample, base::DoNothing());
+ db_->WriteSample(signal_type, name_hash, sample,
+ base::BindOnce(&HistogramSignalHandler::OnSampleWritten,
+ weak_ptr_factory_.GetWeakPtr(),
+ std::string(histogram_name)));
+}
+
+void HistogramSignalHandler::AddObserver(Observer* observer) {
+ observers_.AddObserver(observer);
+}
+
+void HistogramSignalHandler::RemoveObserver(Observer* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+void HistogramSignalHandler::OnSampleWritten(const std::string& histogram_name,
+ bool success) {
+ if (!success)
+ return;
+
+ for (Observer& ob : observers_)
+ ob.OnHistogramSignalUpdated(histogram_name);
}
} // namespace segmentation_platform
diff --git a/chromium/components/segmentation_platform/internal/signals/histogram_signal_handler.h b/chromium/components/segmentation_platform/internal/signals/histogram_signal_handler.h
index 61449921e8f..a7049906f72 100644
--- a/chromium/components/segmentation_platform/internal/signals/histogram_signal_handler.h
+++ b/chromium/components/segmentation_platform/internal/signals/histogram_signal_handler.h
@@ -16,6 +16,7 @@
#include "base/memory/weak_ptr.h"
#include "base/metrics/histogram_base.h"
#include "base/metrics/statistics_recorder.h"
+#include "base/observer_list.h"
#include "components/segmentation_platform/internal/proto/types.pb.h"
namespace segmentation_platform {
@@ -26,6 +27,18 @@ class SignalDatabase;
// persisting them to the internal database for future processing.
class HistogramSignalHandler {
public:
+ class Observer : public base::CheckedObserver {
+ public:
+ // Called when a histogram signal tracked by segmentation platform is
+ // updated and written to database.
+ virtual void OnHistogramSignalUpdated(
+ const std::string& histogram_name) = 0;
+ ~Observer() override = default;
+
+ protected:
+ Observer() = default;
+ };
+
explicit HistogramSignalHandler(SignalDatabase* signal_database);
virtual ~HistogramSignalHandler();
@@ -41,12 +54,18 @@ class HistogramSignalHandler {
// Called to enable or disable metrics collection for segmentation platform.
virtual void EnableMetrics(bool enable_metrics);
+ // Add/Remove observer for histogram update events.
+ virtual void AddObserver(Observer* observer);
+ virtual void RemoveObserver(Observer* observer);
+
private:
void OnHistogramSample(proto::SignalType signal_type,
const char* histogram_name,
uint64_t name_hash,
base::HistogramBase::Sample sample);
+ void OnSampleWritten(const std::string& histogram_name, bool success);
+
// The database storing relevant histogram samples.
raw_ptr<SignalDatabase> db_;
@@ -60,6 +79,8 @@ class HistogramSignalHandler {
std::unique_ptr<base::StatisticsRecorder::ScopedHistogramSampleObserver>>
histogram_observers_;
+ base::ObserverList<Observer> observers_;
+
base::WeakPtrFactory<HistogramSignalHandler> weak_ptr_factory_{this};
};
diff --git a/chromium/components/segmentation_platform/internal/signals/histogram_signal_handler_unittest.cc b/chromium/components/segmentation_platform/internal/signals/histogram_signal_handler_unittest.cc
index 28a06f65b23..a6bc8aea56d 100644
--- a/chromium/components/segmentation_platform/internal/signals/histogram_signal_handler_unittest.cc
+++ b/chromium/components/segmentation_platform/internal/signals/histogram_signal_handler_unittest.cc
@@ -12,8 +12,10 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-using testing::_;
-using testing::Eq;
+using ::testing::_;
+using ::testing::Eq;
+using ::testing::Invoke;
+using ::testing::WithArgs;
namespace segmentation_platform {
@@ -22,7 +24,12 @@ namespace {
constexpr char kExpectedHistogram[] = "some_histogram";
const uint64_t kExpectedHash = base::HashMetricName(kExpectedHistogram);
-} // namespace
+class MockObserver : public HistogramSignalHandler::Observer {
+ public:
+ MockObserver() = default;
+ ~MockObserver() override = default;
+ MOCK_METHOD(void, OnHistogramSignalUpdated, (const std::string&), (override));
+};
class HistogramSignalHandlerTest : public testing::Test {
public:
@@ -45,6 +52,7 @@ class HistogramSignalHandlerTest : public testing::Test {
base::test::TaskEnvironment task_environment_;
std::unique_ptr<MockSignalDatabase> signal_database_;
std::unique_ptr<HistogramSignalHandler> histogram_signal_handler_;
+ MockObserver observer_;
};
TEST_F(HistogramSignalHandlerTest, HistogramsAreRecorded) {
@@ -104,4 +112,26 @@ TEST_F(HistogramSignalHandlerTest, DisableMetrics) {
task_environment_.RunUntilIdle();
}
+TEST_F(HistogramSignalHandlerTest, ObserversNotified) {
+ histogram_signal_handler_->EnableMetrics(true);
+ SetupHistograms();
+ histogram_signal_handler_->AddObserver(&observer_);
+
+ EXPECT_CALL(*signal_database_, WriteSample(proto::SignalType::HISTOGRAM_ENUM,
+ kExpectedHash, Eq(1), _))
+ .WillOnce(
+ WithArgs<3>(Invoke([](MockSignalDatabase::SuccessCallback callback) {
+ std::move(callback).Run(true);
+ })));
+ EXPECT_CALL(observer_,
+ OnHistogramSignalUpdated(std::string(kExpectedHistogram)));
+
+ // Record a registered histogram sample. |observer_| should be notified.
+ UMA_HISTOGRAM_BOOLEAN(kExpectedHistogram, true);
+ task_environment_.RunUntilIdle();
+
+ histogram_signal_handler_->RemoveObserver(&observer_);
+}
+
+} // namespace
} // namespace segmentation_platform
diff --git a/chromium/components/segmentation_platform/internal/signals/signal_filter_processor.cc b/chromium/components/segmentation_platform/internal/signals/signal_filter_processor.cc
index 0244adab255..3a6790a284b 100644
--- a/chromium/components/segmentation_platform/internal/signals/signal_filter_processor.cc
+++ b/chromium/components/segmentation_platform/internal/signals/signal_filter_processor.cc
@@ -7,6 +7,7 @@
#include <set>
#include "base/logging.h"
+#include "components/segmentation_platform/internal/database/metadata_utils.h"
#include "components/segmentation_platform/internal/database/segment_info_database.h"
#include "components/segmentation_platform/internal/proto/model_prediction.pb.h"
#include "components/segmentation_platform/internal/proto/types.pb.h"
@@ -32,15 +33,14 @@ void SignalFilterProcessor::OnSignalListUpdated() {
}
void SignalFilterProcessor::FilterSignals(
- std::vector<std::pair<OptimizationTarget, proto::SegmentInfo>>
- segment_infos) {
+ std::unique_ptr<SegmentInfoDatabase::SegmentInfoList> segment_infos) {
std::set<uint64_t> user_actions;
std::set<std::pair<std::string, proto::SignalType>> histograms;
- for (const auto& pair : segment_infos) {
+ for (const auto& pair : *segment_infos) {
const proto::SegmentInfo& segment_info = pair.second;
const auto& metadata = segment_info.model_metadata();
- for (int i = 0; i < metadata.features_size(); i++) {
- const auto& feature = metadata.features(i);
+ auto features = metadata_utils::GetAllUmaFeatures(metadata);
+ for (auto const& feature : features) {
if (feature.type() == proto::SignalType::USER_ACTION &&
feature.name_hash() != 0) {
user_actions.insert(feature.name_hash());
diff --git a/chromium/components/segmentation_platform/internal/signals/signal_filter_processor.h b/chromium/components/segmentation_platform/internal/signals/signal_filter_processor.h
index 1535a442c34..213bc4cbaa3 100644
--- a/chromium/components/segmentation_platform/internal/signals/signal_filter_processor.h
+++ b/chromium/components/segmentation_platform/internal/signals/signal_filter_processor.h
@@ -8,17 +8,13 @@
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "components/optimization_guide/proto/models.pb.h"
+#include "components/segmentation_platform/internal/database/segment_info_database.h"
using optimization_guide::proto::OptimizationTarget;
namespace segmentation_platform {
-namespace proto {
-class SegmentInfo;
-} // namespace proto
-
class HistogramSignalHandler;
-class SegmentInfoDatabase;
class UserActionSignalHandler;
// Responsible for listening to the metadata updates for the models and
@@ -48,8 +44,7 @@ class SignalFilterProcessor {
private:
void FilterSignals(
- std::vector<std::pair<OptimizationTarget, proto::SegmentInfo>>
- segment_infos);
+ std::unique_ptr<SegmentInfoDatabase::SegmentInfoList> segment_infos);
raw_ptr<SegmentInfoDatabase> segment_database_;
raw_ptr<UserActionSignalHandler> user_action_signal_handler_;
diff --git a/chromium/components/segmentation_platform/internal/stats.cc b/chromium/components/segmentation_platform/internal/stats.cc
index 7cf506acd00..2503e7ec834 100644
--- a/chromium/components/segmentation_platform/internal/stats.cc
+++ b/chromium/components/segmentation_platform/internal/stats.cc
@@ -34,6 +34,9 @@ std::string OptimizationTargetToHistogramVariant(
return "ChromeStartAndroid";
case OptimizationTarget::OPTIMIZATION_TARGET_SEGMENTATION_QUERY_TILES:
return "QueryTiles";
+ case OptimizationTarget::
+ OPTIMIZATION_TARGET_SEGMENTATION_CHROME_LOW_USER_ENGAGEMENT:
+ return "ChromeLowUserEngagement";
default:
NOTREACHED();
return "Unknown";
@@ -64,7 +67,8 @@ enum class SegmentationModel {
kDummy = 10,
kChromeStartAndroid = 11,
kQueryTiles = 12,
- kMaxValue = kQueryTiles,
+ kChromeLowUserEngagement = 16,
+ kMaxValue = kChromeLowUserEngagement,
};
AdaptiveToolbarButtonVariant OptimizationTargetToAdaptiveToolbarButtonVariant(
@@ -84,8 +88,11 @@ AdaptiveToolbarButtonVariant OptimizationTargetToAdaptiveToolbarButtonVariant(
}
bool IsBooleanSegment(const std::string& segmentation_key) {
+ // Please keep in sync with BooleanModel variant in
+ // //tools/metrics/histograms/metadata/segmentation_platform/histograms.xml.
return segmentation_key == kChromeStartAndroidSegmentationKey ||
- segmentation_key == kQueryTilesSegmentationKey;
+ segmentation_key == kQueryTilesSegmentationKey ||
+ segmentation_key == kChromeLowUserEngagementSegmentationKey;
}
BooleanSegmentSwitch GetBooleanSegmentSwitch(
@@ -180,6 +187,9 @@ SegmentationModel OptimizationTargetToSegmentationModel(
return SegmentationModel::kChromeStartAndroid;
case OptimizationTarget::OPTIMIZATION_TARGET_SEGMENTATION_QUERY_TILES:
return SegmentationModel::kQueryTiles;
+ case OptimizationTarget::
+ OPTIMIZATION_TARGET_SEGMENTATION_CHROME_LOW_USER_ENGAGEMENT:
+ return SegmentationModel::kChromeLowUserEngagement;
default:
return SegmentationModel::kUnknown;
}
@@ -231,6 +241,8 @@ float ZeroValueFraction(const std::vector<float>& tensor) {
}
const char* SegmentationKeyToUmaName(const std::string& segmentation_key) {
+ // Please keep in sync with SegmentationKey variant in
+ // //tools/metrics/histograms/metadata/segmentation_platform/histograms.xml.
if (segmentation_key == kAdaptiveToolbarSegmentationKey) {
return "AdaptiveToolbar";
} else if (segmentation_key == kDummySegmentationKey) {
@@ -239,6 +251,8 @@ const char* SegmentationKeyToUmaName(const std::string& segmentation_key) {
return "ChromeStartAndroid";
} else if (segmentation_key == kQueryTilesSegmentationKey) {
return "QueryTiles";
+ } else if (segmentation_key == kChromeLowUserEngagementSegmentationKey) {
+ return "ChromeLowUserEngagement";
} else if (base::StartsWith(segmentation_key, "test_key")) {
return "TestKey";
}
@@ -272,6 +286,8 @@ void RecordModelScore(OptimizationTarget segment_id, float score) {
case OptimizationTarget::
OPTIMIZATION_TARGET_SEGMENTATION_CHROME_START_ANDROID:
case OptimizationTarget::OPTIMIZATION_TARGET_SEGMENTATION_QUERY_TILES:
+ case OptimizationTarget::
+ OPTIMIZATION_TARGET_SEGMENTATION_CHROME_LOW_USER_ENGAGEMENT:
// Assumes all models return score between 0 and 1. This is true for all
// the models we have currently.
base::UmaHistogramPercentage(
@@ -498,5 +514,24 @@ void RecordSignalsListeningCount(
histogram_value_count);
}
+void RecordSegmentSelectionFailure(SegmentationSelectionFailureReason reason) {
+ base::UmaHistogramEnumeration("SegmentationPlatform.SelectionFailedReason",
+ reason);
+}
+
+void RecordModelAvailability(OptimizationTarget segment_id,
+ SegmentationModelAvailability availability) {
+ base::UmaHistogramEnumeration(
+ "SegmentationPlatform.ModelAvailability." +
+ OptimizationTargetToHistogramVariant(segment_id),
+ availability);
+}
+
+void RecordTooManyInputTensors(int tensor_size) {
+ UMA_HISTOGRAM_COUNTS_100(
+ "SegmentationPlatform.StructuredMetrics.TooManyTensors.Count",
+ tensor_size);
+}
+
} // namespace stats
} // namespace segmentation_platform
diff --git a/chromium/components/segmentation_platform/internal/stats.h b/chromium/components/segmentation_platform/internal/stats.h
index ce96c5b5e42..fb63787b950 100644
--- a/chromium/components/segmentation_platform/internal/stats.h
+++ b/chromium/components/segmentation_platform/internal/stats.h
@@ -9,6 +9,7 @@
#include "components/segmentation_platform/internal/database/metadata_utils.h"
#include "components/segmentation_platform/internal/execution/model_execution_status.h"
#include "components/segmentation_platform/internal/proto/types.pb.h"
+#include "components/segmentation_platform/public/segment_selection_result.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
using optimization_guide::proto::OptimizationTarget;
@@ -143,6 +144,45 @@ void RecordSignalsListeningCount(
const std::set<uint64_t>& user_actions,
const std::set<std::pair<std::string, proto::SignalType>>& histograms);
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused. Please keep in sync with
+// "SegmentationSelectionFailureReason" in
+// //tools/metrics/histograms/enums.xml.
+enum class SegmentationSelectionFailureReason {
+ kPlatformDisabled = 0,
+ kSelectionAvailableInPrefs = 1,
+ kAtLeastOneSegmentNotReady = 2,
+ kAtLeastOneSegmentSignalsNotCollected = 3,
+ kSelectionTtlNotExpired = 4,
+ kAtLeastOneModelFailedExecution = 5,
+ kAtLeastOneModelNeedsMoreSignals = 6,
+ kAtLeastOneModelWithInvalidMetadata = 7,
+ kFailedToSaveModelResult = 8,
+ kInvalidSelectionResultInPrefs = 9,
+ kDBInitFailure = 10,
+ kMaxValue = kDBInitFailure
+};
+
+// Records the reason for failure or success to compute a segment selection.
+void RecordSegmentSelectionFailure(SegmentationSelectionFailureReason reason);
+
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused. Please keep in sync with
+// "SegmentationModelAvailability" in //tools/metrics/histograms/enums.xml.
+enum class SegmentationModelAvailability {
+ kModelHandlerCreated = 0,
+ kModelAvailable = 1,
+ kMetadataInvalid = 2,
+ kMaxValue = kMetadataInvalid
+};
+// Records the availability of segmentation models for each target needed.
+void RecordModelAvailability(OptimizationTarget segment_id,
+ SegmentationModelAvailability availability);
+
+// Records the number of input tensor that's causing a failure to upload
+// structured metrics.
+void RecordTooManyInputTensors(int tensor_size);
+
} // namespace stats
} // namespace segmentation_platform
diff --git a/chromium/components/segmentation_platform/internal/ukm_data_manager.cc b/chromium/components/segmentation_platform/internal/ukm_data_manager.cc
new file mode 100644
index 00000000000..a4969ae672e
--- /dev/null
+++ b/chromium/components/segmentation_platform/internal/ukm_data_manager.cc
@@ -0,0 +1,44 @@
+// Copyright 2022 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.
+
+#include "components/segmentation_platform/internal/ukm_data_manager.h"
+
+#include "base/check_op.h"
+
+namespace segmentation_platform {
+
+UkmDataManager::UkmDataManager() = default;
+
+UkmDataManager::~UkmDataManager() {
+ DCHECK_EQ(ref_count_, 0);
+ // TODO(ssid): Destroy signal handler and database here.
+}
+
+void UkmDataManager::Initialize(const base::FilePath& database_path) {
+ // TODO(ssid): Create database here.
+}
+
+UrlSignalHandler* UkmDataManager::GetOrCreateUrlHandler() {
+ // TODO(ssid): Return signal handler here.
+ return nullptr;
+}
+
+void UkmDataManager::CanObserveUkm(ukm::UkmRecorderImpl* ukm_recorder) {
+ // TODO(ssid): Create observer here.
+}
+
+void UkmDataManager::StopObservingUkm() {
+ // TODO(ssid): Destroy observer here.
+}
+
+void UkmDataManager::AddRef() {
+ ref_count_++;
+}
+
+void UkmDataManager::RemoveRef() {
+ DCHECK_GT(ref_count_, 0);
+ ref_count_--;
+}
+
+} // namespace segmentation_platform
diff --git a/chromium/components/segmentation_platform/internal/ukm_data_manager.h b/chromium/components/segmentation_platform/internal/ukm_data_manager.h
new file mode 100644
index 00000000000..c366420e2f4
--- /dev/null
+++ b/chromium/components/segmentation_platform/internal/ukm_data_manager.h
@@ -0,0 +1,59 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_UKM_DATA_MANAGER_H_
+#define COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_UKM_DATA_MANAGER_H_
+
+#include "base/files/file_path.h"
+
+namespace ukm {
+class UkmRecorderImpl;
+}
+
+namespace segmentation_platform {
+
+class UkmDatabase;
+class UrlSignalHandler;
+
+// Manages ownership and lifetime of all UKM related classes, like database and
+// observer. There is only one manager per browser process. Created before
+// profile initialization and destroyed after all profiles are destroyed. The
+// database, observer and signal handler can have different lifetimes, see
+// comments below.
+class UkmDataManager {
+ public:
+ UkmDataManager();
+ ~UkmDataManager();
+
+ UkmDataManager(UkmDataManager&) = delete;
+ UkmDataManager& operator=(UkmDataManager&) = delete;
+
+ // Initializes UKM database.
+ void Initialize(const base::FilePath& database_path);
+
+ // Must be called when UKM service is available to start observing metrics.
+ void CanObserveUkm(ukm::UkmRecorderImpl* ukm_recorder);
+ // Must be called before UKM service is destroyed, to remove observers.
+ void StopObservingUkm();
+
+ // Get URL signal handler. The signal handler is safe to use as long as data
+ // manager is alive, so until after all profiles are destroyed.
+ UrlSignalHandler* GetOrCreateUrlHandler();
+
+ // Get UKM database. The database is safe to use as long as data manager is
+ // alive, so until after all profiles are destroyed.
+ UkmDatabase* GetUkmDatabase();
+
+ // Keep track of all the segmentation services that hold reference to this
+ // object.
+ void AddRef();
+ void RemoveRef();
+
+ private:
+ int ref_count_{0};
+};
+
+} // namespace segmentation_platform
+
+#endif // COMPONENTS_SEGMENTATION_PLATFORM_INTERNAL_UKM_DATA_MANAGER_H_
diff --git a/chromium/components/segmentation_platform/public/BUILD.gn b/chromium/components/segmentation_platform/public/BUILD.gn
index 3862db29030..4f3255229ae 100644
--- a/chromium/components/segmentation_platform/public/BUILD.gn
+++ b/chromium/components/segmentation_platform/public/BUILD.gn
@@ -17,6 +17,7 @@ source_set("public") {
"segment_selection_result.h",
"segmentation_platform_service.cc",
"segmentation_platform_service.h",
+ "service_proxy.cc",
"service_proxy.h",
]
diff --git a/chromium/components/segmentation_platform/public/config.h b/chromium/components/segmentation_platform/public/config.h
index 558d31700cd..13a98f59fe2 100644
--- a/chromium/components/segmentation_platform/public/config.h
+++ b/chromium/components/segmentation_platform/public/config.h
@@ -25,6 +25,19 @@ const char kChromeStartAndroidSegmentationKey[] = "chrome_start_android";
// The key is used to decide whether to show query tiles.
const char kQueryTilesSegmentationKey[] = "query_tiles";
+// The key is used to decide whether a user has low user engagement with chrome.
+// This is a generic model that can be used by multiple features targeting
+// low-engaged users. Typically low engaged users are active in chrome below a
+// certain threshold number of days over a time period. This is computed using
+// Session.TotalDuration histogram.
+const char kChromeLowUserEngagementSegmentationKey[] =
+ "chrome_low_user_engagement";
+
+// The key provide a list of segment IDs, separated by commas, whose ML model
+// execution results are allowed to be uploaded through UKM.
+const char kSegmentIdsAllowedForReportingKey[] =
+ "segment_ids_allowed_for_reporting";
+
// Contains various finch configuration params used by the segmentation
// platform.
struct Config {
diff --git a/chromium/components/segmentation_platform/public/features.cc b/chromium/components/segmentation_platform/public/features.cc
index 2c94eadfbc5..105bceae7b2 100644
--- a/chromium/components/segmentation_platform/public/features.cc
+++ b/chromium/components/segmentation_platform/public/features.cc
@@ -11,7 +11,7 @@ namespace features {
const base::Feature kSegmentationPlatformFeature {
"SegmentationPlatform",
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
base::FEATURE_ENABLED_BY_DEFAULT
#else
base::FEATURE_DISABLED_BY_DEFAULT
@@ -21,8 +21,7 @@ const base::Feature kSegmentationPlatformFeature {
const base::Feature kSegmentationPlatformDummyFeature{
"SegmentationPlatformDummyFeature", base::FEATURE_DISABLED_BY_DEFAULT};
-const base::Feature kSegmentationPlatformQueryTilesFeature{
- "SegmentationPlatformQueryTiles", base::FEATURE_DISABLED_BY_DEFAULT};
-
+const base::Feature kSegmentationStructuredMetricsFeature{
+ "SegmentationStructuredMetrics", base::FEATURE_DISABLED_BY_DEFAULT};
} // namespace features
} // namespace segmentation_platform
diff --git a/chromium/components/segmentation_platform/public/features.h b/chromium/components/segmentation_platform/public/features.h
index 870046da39e..30411db0c47 100644
--- a/chromium/components/segmentation_platform/public/features.h
+++ b/chromium/components/segmentation_platform/public/features.h
@@ -17,10 +17,8 @@ extern const base::Feature kSegmentationPlatformFeature;
// experimental models and data collection.
extern const base::Feature kSegmentationPlatformDummyFeature;
-// Feature flag for using a segmentation based model for query tiles to decide
-// whether or not to show query tiles.
-extern const base::Feature kSegmentationPlatformQueryTilesFeature;
-
+// Feature flag for allowing structured metrics to be collected.
+extern const base::Feature kSegmentationStructuredMetricsFeature;
} // namespace features
} // namespace segmentation_platform
diff --git a/chromium/components/segmentation_platform/public/segmentation_platform_service.h b/chromium/components/segmentation_platform/public/segmentation_platform_service.h
index cb74dbc4bba..e7ab9ec28bd 100644
--- a/chromium/components/segmentation_platform/public/segmentation_platform_service.h
+++ b/chromium/components/segmentation_platform/public/segmentation_platform_service.h
@@ -13,9 +13,9 @@
#include "build/build_config.h"
#include "components/keyed_service/core/keyed_service.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "base/android/jni_android.h"
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
class PrefRegistrySimple;
@@ -28,12 +28,12 @@ struct SegmentSelectionResult;
class SegmentationPlatformService : public KeyedService,
public base::SupportsUserData {
public:
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Returns a Java object of the type SegmentationPlatformService for the given
// SegmentationPlatformService.
static base::android::ScopedJavaLocalRef<jobject> GetJavaObject(
SegmentationPlatformService* segmentation_platform_service);
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
SegmentationPlatformService() = default;
~SegmentationPlatformService() override = default;
@@ -50,10 +50,16 @@ class SegmentationPlatformService : public KeyedService,
using SegmentSelectionCallback =
base::OnceCallback<void(const SegmentSelectionResult&)>;
- // Called to get the selected segment. If none, returns empty result.
+ // Called to get the selected segment asynchronously. If none, returns empty
+ // result.
virtual void GetSelectedSegment(const std::string& segmentation_key,
SegmentSelectionCallback callback) = 0;
+ // Called to get the selected segment synchronously. If none, returns empty
+ // result.
+ virtual SegmentSelectionResult GetCachedSegmentResult(
+ const std::string& segmentation_key) = 0;
+
// Called to enable or disable metrics collection. Must be explicitly called
// on startup.
virtual void EnableMetrics(bool signal_collection_allowed) = 0;
diff --git a/chromium/components/segmentation_platform/public/service_proxy.cc b/chromium/components/segmentation_platform/public/service_proxy.cc
new file mode 100644
index 00000000000..616fbe3cfc1
--- /dev/null
+++ b/chromium/components/segmentation_platform/public/service_proxy.cc
@@ -0,0 +1,26 @@
+// Copyright 2021 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.
+
+#include "components/segmentation_platform/public/service_proxy.h"
+
+namespace segmentation_platform {
+
+ServiceProxy::SegmentStatus::SegmentStatus(OptimizationTarget segment_id,
+ const std::string& segment_metadata,
+ const std::string& prediction_result,
+ bool can_execute_segment)
+ : segment_id(segment_id),
+ segment_metadata(segment_metadata),
+ prediction_result(prediction_result),
+ can_execute_segment(can_execute_segment) {}
+
+ServiceProxy::ClientInfo::ClientInfo(const std::string& segmentation_key,
+ OptimizationTarget selected_segment)
+ : segmentation_key(segmentation_key), selected_segment(selected_segment) {}
+
+ServiceProxy::ClientInfo::~ClientInfo() = default;
+
+ServiceProxy::ClientInfo::ClientInfo(const ClientInfo& other) = default;
+
+} // namespace segmentation_platform \ No newline at end of file
diff --git a/chromium/components/segmentation_platform/public/service_proxy.h b/chromium/components/segmentation_platform/public/service_proxy.h
index 8b1f9146359..10f96e4e33c 100644
--- a/chromium/components/segmentation_platform/public/service_proxy.h
+++ b/chromium/components/segmentation_platform/public/service_proxy.h
@@ -5,10 +5,13 @@
#ifndef COMPONENTS_SEGMENTATION_PLATFORM_PUBLIC_SERVICE_PROXY_H_
#define COMPONENTS_SEGMENTATION_PLATFORM_PUBLIC_SERVICE_PROXY_H_
+#include <string>
#include <vector>
#include "base/observer_list_types.h"
-#include "components/segmentation_platform/public/segmentation_platform_service.h"
+#include "components/optimization_guide/proto/models.pb.h"
+
+using optimization_guide::proto::OptimizationTarget;
namespace segmentation_platform {
@@ -16,12 +19,36 @@ namespace segmentation_platform {
// component and/or debug UI.
class ServiceProxy {
public:
+ // Status about a segment.
+ struct SegmentStatus {
+ SegmentStatus(OptimizationTarget segment_id,
+ const std::string& segment_metadata,
+ const std::string& prediction_result,
+ bool can_execute_segment);
+ OptimizationTarget segment_id;
+ std::string segment_metadata;
+ std::string prediction_result;
+ bool can_execute_segment;
+ };
+
+ // Information about a client to the segmentation platform.
+ struct ClientInfo {
+ ClientInfo(const std::string& segmentation_key,
+ OptimizationTarget selected_segment);
+ ~ClientInfo();
+ ClientInfo(const ClientInfo& other);
+
+ std::string segmentation_key;
+ OptimizationTarget selected_segment;
+ std::vector<SegmentStatus> segment_status;
+ };
+
class Observer : public base::CheckedObserver {
public:
// Called whenever the servoice status changes.
virtual void OnServiceStatusChanged(bool is_initialized, int status_flag) {}
- virtual void OnSegmentInfoAvailable(
- const std::vector<std::string>& segment_info) {}
+ virtual void OnClientInfoAvailable(
+ const std::vector<ClientInfo>& config_info) {}
};
virtual ~ServiceProxy() = default;
@@ -35,10 +62,17 @@ class ServiceProxy {
// Returns the current status of the segmentation service.
virtual void GetServiceStatus() = 0;
- // Called to get the selected segment. If none, returns empty result.
- virtual void GetSelectedSegment(
- const std::string& segmentation_key,
- SegmentationPlatformService::SegmentSelectionCallback callback) = 0;
+ // Executes the given segment identified by |segment_id|.
+ virtual void ExecuteModel(OptimizationTarget segment_id) = 0;
+
+ // Overwrites the result for the given segment identified by |segment_id|.
+ // This will trigger a new round of segment selection and update the existing
+ // result in Prefs.
+ virtual void OverwriteResult(OptimizationTarget segment_id, float result) = 0;
+
+ // Sets the selected segment for the config identified by |segment_id|.
+ virtual void SetSelectedSegment(const std::string& segmentation_key,
+ OptimizationTarget segment_id) = 0;
protected:
ServiceProxy() = default;
diff --git a/chromium/components/send_tab_to_self/BUILD.gn b/chromium/components/send_tab_to_self/BUILD.gn
index fed338526d6..6fba4c0f8d9 100644
--- a/chromium/components/send_tab_to_self/BUILD.gn
+++ b/chromium/components/send_tab_to_self/BUILD.gn
@@ -26,7 +26,6 @@ static_library("send_tab_to_self") {
]
deps = [
"//base",
- "//build:chromeos_buildflags",
"//components/history/core/browser",
"//components/keyed_service/core",
"//components/send_tab_to_self/proto:send_tab_to_self_proto",
diff --git a/chromium/components/send_tab_to_self/features.cc b/chromium/components/send_tab_to_self/features.cc
index 8c9c2277f11..2bc791e45d7 100644
--- a/chromium/components/send_tab_to_self/features.cc
+++ b/chromium/components/send_tab_to_self/features.cc
@@ -7,38 +7,18 @@
#include "base/feature_list.h"
#include "build/build_config.h"
#include "build/buildflag.h"
-#include "build/chromeos_buildflags.h"
#include "components/sync/base/sync_prefs.h"
#include "components/sync/base/user_selectable_type.h"
namespace send_tab_to_self {
-const base::Feature kSendTabToSelfWhenSignedIn{
- "SendTabToSelfWhenSignedIn",
-#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
- base::FEATURE_DISABLED_BY_DEFAULT
-#else
- base::FEATURE_ENABLED_BY_DEFAULT
-#endif
-};
-
-const base::Feature kSendTabToSelfManageDevicesLink{
- "SendTabToSelfManageDevicesLink",
-#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
- base::FEATURE_DISABLED_BY_DEFAULT
-#else
- base::FEATURE_ENABLED_BY_DEFAULT
-#endif
-};
+const base::Feature kSendTabToSelfSigninPromo{
+ "SendTabToSelfSigninPromo", base::FEATURE_DISABLED_BY_DEFAULT};
-const base::Feature kSendTabToSelfV2{
- "SendTabToSelfV2",
-#if defined(OS_ANDROID) || defined(OS_IOS)
- base::FEATURE_DISABLED_BY_DEFAULT
-#else
- base::FEATURE_ENABLED_BY_DEFAULT
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
+const base::Feature kSendTabToSelfV2{"SendTabToSelfV2",
+ base::FEATURE_DISABLED_BY_DEFAULT};
#endif
-};
bool IsReceivingEnabledByUserOnThisDevice(PrefService* prefs) {
// TODO(crbug.com/1015322): SyncPrefs is used directly instead of methods in
@@ -47,21 +27,18 @@ bool IsReceivingEnabledByUserOnThisDevice(PrefService* prefs) {
// used by DeviceInfoSyncClient which is owned by DeviceInfoSyncService.
syncer::SyncPrefs sync_prefs(prefs);
- if (sync_prefs.IsFirstSetupComplete()) {
- // Sync-the-feature was fully setup. Regardless of
- // kSendTabToSelfWhenSignedIn, the user-configurable bits should be
- // respected in this state.
- return sync_prefs.IsSyncRequested() &&
- sync_prefs.GetSelectedTypes().Has(syncer::UserSelectableType::kTabs);
- }
-
- // Sync-the-feature is disabled or the consent is missing (e.g. sync setup in
- // progress). If kSendTabToSelfWhenSignedIn is disabled, receiving shouldn't
- // be allowed in this state. If kSendTabToSelfWhenSignedIn is enabled, the
- // method can return true without actually checking whether the user is
- // signed-in: if they are not, sync-the-transport won't run and receiving tabs
- // would be impossible anyway.
- return base::FeatureList::IsEnabled(kSendTabToSelfWhenSignedIn);
+ // IsFirstSetupComplete() false means sync-the-feature is disabled or the
+ // consent is missing (e.g. sync setup in progress). The method can return
+ // true without actually checking whether the user is signed-in: if they are
+ // not, sync-the-transport won't run and receiving tabs would be impossible
+ // anyway.
+ if (!sync_prefs.IsFirstSetupComplete())
+ return true;
+
+ // Sync-the-feature was fully setup. The user-configurable bits should be
+ // respected in this state.
+ return sync_prefs.IsSyncRequested() &&
+ sync_prefs.GetSelectedTypes().Has(syncer::UserSelectableType::kTabs);
}
} // namespace send_tab_to_self
diff --git a/chromium/components/send_tab_to_self/features.h b/chromium/components/send_tab_to_self/features.h
index aedaf032432..2b10474de42 100644
--- a/chromium/components/send_tab_to_self/features.h
+++ b/chromium/components/send_tab_to_self/features.h
@@ -6,23 +6,24 @@
#define COMPONENTS_SEND_TAB_TO_SELF_FEATURES_H_
#include "base/feature_list.h"
+#include "build/build_config.h"
class PrefService;
namespace send_tab_to_self {
-// If this feature is enabled, we will use signed-in, ephemeral data rather than
-// persistent sync data. Users who are signed in can use the feature regardless
-// of whether they have the sync feature enabled.
-extern const base::Feature kSendTabToSelfWhenSignedIn;
-
-// If this feature is enabled, a link to manage the user's devices will be shown
-// below the device list when sharing.
-extern const base::Feature kSendTabToSelfManageDevicesLink;
+// If this feature is enabled and a signed-out user attempts to share a tab,
+// they will see a promo to sign-in.
+extern const base::Feature kSendTabToSelfSigninPromo;
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
// If this feature is enabled, show received tabs in a new UI next to the
// profile icon rather than in a system notification.
+//
+// V2 is the default on desktop and the V1 code path has been deleted there, so
+// this base::Feature no longer exists on desktop platforms.
extern const base::Feature kSendTabToSelfV2;
+#endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
// Returns whether the receiving components of the feature is enabled on this
// device. This doesn't rely on the SendTabToSelfSyncService to be actively up
diff --git a/chromium/components/send_tab_to_self/features_unittest.cc b/chromium/components/send_tab_to_self/features_unittest.cc
index a2924400763..c59003af2e5 100644
--- a/chromium/components/send_tab_to_self/features_unittest.cc
+++ b/chromium/components/send_tab_to_self/features_unittest.cc
@@ -7,7 +7,6 @@
#include <memory>
#include "base/test/task_environment.h"
-#include "base/test/scoped_feature_list.h"
#include "components/sync/base/sync_prefs.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -27,7 +26,6 @@ class SendTabToSelfFeaturesTest : public testing::Test {
sync_preferences::TestingPrefServiceSyncable prefs_;
std::unique_ptr<syncer::SyncPrefs> sync_prefs_;
base::test::TaskEnvironment task_environment_;
- base::test::ScopedFeatureList features_;
};
TEST_F(SendTabToSelfFeaturesTest, ReceivingEnabledIfSyncTheFeatureEnabled) {
@@ -65,36 +63,8 @@ TEST_F(SendTabToSelfFeaturesTest,
EXPECT_FALSE(IsReceivingEnabledByUserOnThisDevice(&prefs_));
}
-TEST_F(SendTabToSelfFeaturesTest, ReceivingDisabledIfSyncTheFeatureDisabled) {
- features_.InitAndDisableFeature(kSendTabToSelfWhenSignedIn);
- sync_prefs_->SetSelectedTypes(
- /*keep_everything_synced=*/false,
- /*registered_types=*/syncer::UserSelectableTypeSet::All(),
- /*selected_types=*/{});
-
- EXPECT_FALSE(IsReceivingEnabledByUserOnThisDevice(&prefs_));
-}
-
-TEST_F(
- SendTabToSelfFeaturesTest,
- ReceivingDisabledIfSyncSetupIncomplete__SendTabToSelfWhenSignedInEnabled) {
- features_.InitAndDisableFeature(kSendTabToSelfWhenSignedIn);
-
- sync_prefs_->SetSyncRequested(true);
- // Skip setting FirstSetupComplete.
- sync_prefs_->SetSelectedTypes(
- /*keep_everything_synced=*/false,
- /*registered_types=*/syncer::UserSelectableTypeSet::All(),
- /*selected_types=*/{syncer::UserSelectableType::kTabs});
-
- // Should wait for the setup to complete.
- EXPECT_FALSE(IsReceivingEnabledByUserOnThisDevice(&prefs_));
-}
-
TEST_F(SendTabToSelfFeaturesTest,
ReceivingEnabledIfSyncSetupIncomplete_SendTabToSelfWhenSignedInEnabled) {
- features_.InitAndEnableFeature(kSendTabToSelfWhenSignedIn);
-
sync_prefs_->SetSyncRequested(true);
// Skip setting FirstSetupComplete.
sync_prefs_->SetSelectedTypes(
@@ -110,7 +80,6 @@ TEST_F(SendTabToSelfFeaturesTest,
TEST_F(
SendTabToSelfFeaturesTest,
ReceivingEnabledIfSyncTheFeatureDisabled_SendTabToSelfWhenSignedInEnabled) {
- features_.InitAndEnableFeature(kSendTabToSelfWhenSignedIn);
sync_prefs_->SetSelectedTypes(
/*keep_everything_synced=*/false,
/*registered_types=*/syncer::UserSelectableTypeSet::All(),
diff --git a/chromium/components/send_tab_to_self/metrics_util.cc b/chromium/components/send_tab_to_self/metrics_util.cc
index 2bce8a20278..a6d81b4b314 100644
--- a/chromium/components/send_tab_to_self/metrics_util.cc
+++ b/chromium/components/send_tab_to_self/metrics_util.cc
@@ -32,7 +32,8 @@ enum class NotificationStatus {
kTimedOut = 3,
kSent = 4,
kDismissReasonUnknown = 5,
- kMaxValue = kDismissReasonUnknown,
+ kThrottled = 6,
+ kMaxValue = kThrottled,
};
std::string GetEntryPointHistogramString(ShareEntryPoint entry_point) {
@@ -96,4 +97,9 @@ void RecordNotificationDismissReasonUnknown() {
NotificationStatus::kDismissReasonUnknown);
}
+void RecordNotificationThrottled() {
+ base::UmaHistogramEnumeration("Sharing.SendTabToSelf.NotificationStatus",
+ NotificationStatus::kThrottled);
+}
+
} // namespace send_tab_to_self
diff --git a/chromium/components/send_tab_to_self/metrics_util.h b/chromium/components/send_tab_to_self/metrics_util.h
index 607855184f5..3043a31c644 100644
--- a/chromium/components/send_tab_to_self/metrics_util.h
+++ b/chromium/components/send_tab_to_self/metrics_util.h
@@ -38,6 +38,9 @@ void RecordNotificationTimedOut();
// Records when a received STTS notification is dismissed for an unknown reason.
void RecordNotificationDismissReasonUnknown();
+// Records when a received STTS notification is throttled from being sent.
+void RecordNotificationThrottled();
+
} // namespace send_tab_to_self
#endif // COMPONENTS_SEND_TAB_TO_SELF_METRICS_UTIL_H_
diff --git a/chromium/components/send_tab_to_self/send_tab_to_self_bridge.cc b/chromium/components/send_tab_to_self/send_tab_to_self_bridge.cc
index f6e170457b3..6d574d72007 100644
--- a/chromium/components/send_tab_to_self/send_tab_to_self_bridge.cc
+++ b/chromium/components/send_tab_to_self/send_tab_to_self_bridge.cc
@@ -17,6 +17,7 @@
#include "base/time/time.h"
#include "components/history/core/browser/history_service.h"
#include "components/send_tab_to_self/features.h"
+#include "components/send_tab_to_self/metrics_util.h"
#include "components/send_tab_to_self/proto/send_tab_to_self.pb.h"
#include "components/send_tab_to_self/target_device_info.h"
#include "components/sync/model/entity_change.h"
@@ -312,6 +313,7 @@ const SendTabToSelfEntry* SendTabToSelfBridge::AddEntry(
if (mru_entry_ && url == mru_entry_->GetURL() &&
navigation_time == mru_entry_->GetOriginalNavigationTime() &&
shared_time - mru_entry_->GetSharedTime() < kDedupeTime) {
+ send_tab_to_self::RecordNotificationThrottled();
return mru_entry_;
}
diff --git a/chromium/components/send_tab_to_self/send_tab_to_self_bridge_unittest.cc b/chromium/components/send_tab_to_self/send_tab_to_self_bridge_unittest.cc
index f75ffe44dd4..e4b84ef3033 100644
--- a/chromium/components/send_tab_to_self/send_tab_to_self_bridge_unittest.cc
+++ b/chromium/components/send_tab_to_self/send_tab_to_self_bridge_unittest.cc
@@ -17,10 +17,10 @@
#include "components/send_tab_to_self/features.h"
#include "components/send_tab_to_self/proto/send_tab_to_self.pb.h"
#include "components/send_tab_to_self/target_device_info.h"
-#include "components/sync/engine/entity_data.h"
#include "components/sync/model/entity_change.h"
#include "components/sync/model/in_memory_metadata_change_list.h"
#include "components/sync/model/metadata_batch.h"
+#include "components/sync/protocol/entity_data.h"
#include "components/sync/protocol/model_type_state.pb.h"
#include "components/sync/test/model/mock_model_type_change_processor.h"
#include "components/sync/test/model/model_type_store_test_util.h"
diff --git a/chromium/components/send_tab_to_self/send_tab_to_self_model_type_controller.cc b/chromium/components/send_tab_to_self/send_tab_to_self_model_type_controller.cc
index b5fc1cd2d97..428aab9aeea 100644
--- a/chromium/components/send_tab_to_self/send_tab_to_self_model_type_controller.cc
+++ b/chromium/components/send_tab_to_self/send_tab_to_self_model_type_controller.cc
@@ -19,9 +19,7 @@ SendTabToSelfModelTypeController::SendTabToSelfModelTypeController(
: ModelTypeController(syncer::SEND_TAB_TO_SELF,
std::move(delegate_for_full_sync_mode),
std::move(delegate_for_transport_mode)) {
- DCHECK_EQ(base::FeatureList::IsEnabled(
- send_tab_to_self::kSendTabToSelfWhenSignedIn),
- ShouldRunInTransportOnlyMode());
+ DCHECK(ShouldRunInTransportOnlyMode());
}
SendTabToSelfModelTypeController::~SendTabToSelfModelTypeController() = default;
diff --git a/chromium/components/services/app_service/BUILD.gn b/chromium/components/services/app_service/BUILD.gn
index a860306ee5b..d6e390233a2 100644
--- a/chromium/components/services/app_service/BUILD.gn
+++ b/chromium/components/services/app_service/BUILD.gn
@@ -35,6 +35,7 @@ source_set("unit_tests") {
"//components/services/app_service/public/cpp:intents",
"//components/services/app_service/public/cpp:preferred_apps",
"//components/services/app_service/public/cpp:publisher",
+ "//components/services/app_service/public/cpp:run_on_os_login",
"//components/services/app_service/public/cpp:test_support",
"//content/test:test_support",
"//testing/gtest",
diff --git a/chromium/components/services/app_service/app_service_mojom_impl.cc b/chromium/components/services/app_service/app_service_mojom_impl.cc
index dab153dcd2f..23623e84c2b 100644
--- a/chromium/components/services/app_service/app_service_mojom_impl.cc
+++ b/chromium/components/services/app_service/app_service_mojom_impl.cc
@@ -539,6 +539,17 @@ void AppServiceMojomImpl::SetWindowMode(apps::mojom::AppType app_type,
iter->second->SetWindowMode(app_id, window_mode);
}
+void AppServiceMojomImpl::SetRunOnOsLoginMode(
+ apps::mojom::AppType app_type,
+ const std::string& app_id,
+ apps::mojom::RunOnOsLoginMode run_on_os_login_mode) {
+ auto iter = publishers_.find(app_type);
+ if (iter == publishers_.end()) {
+ return;
+ }
+ iter->second->SetRunOnOsLoginMode(app_id, run_on_os_login_mode);
+}
+
PreferredAppsList& AppServiceMojomImpl::GetPreferredAppsForTesting() {
return preferred_apps_;
}
diff --git a/chromium/components/services/app_service/app_service_mojom_impl.h b/chromium/components/services/app_service/app_service_mojom_impl.h
index 32a402deb8e..c58a2ea5d4d 100644
--- a/chromium/components/services/app_service/app_service_mojom_impl.h
+++ b/chromium/components/services/app_service/app_service_mojom_impl.h
@@ -121,6 +121,10 @@ class AppServiceMojomImpl : public apps::mojom::AppService {
void SetWindowMode(apps::mojom::AppType app_type,
const std::string& app_id,
apps::mojom::WindowMode window_mode) override;
+ void SetRunOnOsLoginMode(
+ apps::mojom::AppType app_type,
+ const std::string& app_id,
+ apps::mojom::RunOnOsLoginMode run_on_os_login_mode) override;
// Retern the preferred_apps_ for testing.
PreferredAppsList& GetPreferredAppsForTesting();
diff --git a/chromium/components/services/app_service/public/cpp/BUILD.gn b/chromium/components/services/app_service/public/cpp/BUILD.gn
index 504e7576c47..b461dd8b633 100644
--- a/chromium/components/services/app_service/public/cpp/BUILD.gn
+++ b/chromium/components/services/app_service/public/cpp/BUILD.gn
@@ -49,13 +49,20 @@ component("app_types") {
sources = [
"app_types.cc",
"app_types.h",
+ "intent_filter.cc",
+ "intent_filter.h",
+ "permission.cc",
+ "permission.h",
]
defines = [ "IS_APP_TYPES_IMPL" ]
public_deps = [ "//components/services/app_service/public/mojom" ]
- deps = [ ":icon_types" ]
+ deps = [
+ ":icon_types",
+ ":run_on_os_login",
+ ]
}
component("app_update") {
@@ -73,6 +80,9 @@ component("app_update") {
"app_update.h",
"capability_access_update.cc",
"capability_access_update.h",
+ "features.cc",
+ "features.h",
+ "macros.h",
]
defines = [ "IS_APP_UPDATE_IMPL" ]
@@ -86,6 +96,7 @@ component("app_update") {
":app_types",
":icon_types",
":intents",
+ ":run_on_os_login",
"//ui/gfx",
]
}
@@ -173,6 +184,18 @@ component("icon_types") {
deps = [ "//ui/gfx" ]
}
+component("run_on_os_login") {
+ output_name = "LOGIN_MODE"
+ sources = [
+ "run_on_os_login_types.cc",
+ "run_on_os_login_types.h",
+ ]
+
+ defines = [ "IS_LOGIN_MODE_IMPL" ]
+
+ public_deps = [ "//components/services/app_service/public/mojom" ]
+}
+
source_set("intents") {
sources = [
"intent_constants.cc",
@@ -184,6 +207,7 @@ source_set("intents") {
]
deps = [
+ ":app_types",
"//base",
"//components/services/app_service/public/mojom",
"//third_party/blink/public/common",
@@ -295,6 +319,7 @@ source_set("unit_tests") {
":intents",
":preferred_apps",
":publisher",
+ ":run_on_os_login",
":test_support",
":types",
"//content/test:test_support",
diff --git a/chromium/components/services/app_service/public/cpp/app_registry_cache.cc b/chromium/components/services/app_service/public/cpp/app_registry_cache.cc
index c0effb42c76..ef505a87806 100644
--- a/chromium/components/services/app_service/public/cpp/app_registry_cache.cc
+++ b/chromium/components/services/app_service/public/cpp/app_registry_cache.cc
@@ -5,17 +5,12 @@
#include "components/services/app_service/public/cpp/app_registry_cache.h"
#include "base/containers/contains.h"
+#include "components/services/app_service/public/cpp/features.h"
#include <utility>
namespace apps {
-namespace {
-
-constexpr uint32_t kUAFSentinelInitial = 0xabcd1234;
-
-} // namespace
-
AppRegistryCache::Observer::Observer(AppRegistryCache* cache) {
Observe(cache);
}
@@ -42,15 +37,13 @@ void AppRegistryCache::Observer::Observe(AppRegistryCache* cache) {
}
}
-AppRegistryCache::AppRegistryCache()
- : account_id_(EmptyAccountId()), uaf_sentinel_(kUAFSentinelInitial) {}
+AppRegistryCache::AppRegistryCache() : account_id_(EmptyAccountId()) {}
AppRegistryCache::~AppRegistryCache() {
for (auto& obs : observers_) {
obs.OnAppRegistryCacheWillBeDestroyed(this);
}
DCHECK(observers_.empty());
- uaf_sentinel_ = 0;
}
void AppRegistryCache::AddObserver(Observer* observer) {
@@ -69,8 +62,8 @@ void AppRegistryCache::OnApps(std::vector<apps::mojom::AppPtr> deltas,
if (should_notify_initialized) {
DCHECK_NE(apps::mojom::AppType::kUnknown, app_type);
- if (initialized_app_types_.find(app_type) == initialized_app_types_.end()) {
- in_progress_initialized_app_types_.insert(app_type);
+ if (!IsAppTypeInitialized(ConvertMojomAppTypToAppType(app_type))) {
+ in_progress_initialized_mojom_app_types_.insert(app_type);
}
}
@@ -90,15 +83,17 @@ void AppRegistryCache::OnApps(std::vector<apps::mojom::AppPtr> deltas,
OnAppTypeInitialized();
}
-void AppRegistryCache::OnApps(std::vector<std::unique_ptr<App>> deltas,
+void AppRegistryCache::OnApps(std::vector<AppPtr> deltas,
apps::AppType app_type,
bool should_notify_initialized) {
DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker_);
- // TODO(crbug.com/1253250): Modify in_progress_initialized_app_types_ based on
- // the `App` struct when the `App` struct replaces the mojom `App` struct for
- // all publishers, to prevent OnAppTypeInitialized to be called twice for both
- // the mojom struct and non-mojom struct.
+ if (should_notify_initialized) {
+ DCHECK_NE(apps::AppType::kUnknown, app_type);
+ if (!IsAppTypeInitialized(app_type)) {
+ in_progress_initialized_app_types_.insert(app_type);
+ }
+ }
if (!deltas_in_progress_.empty()) {
std::move(deltas.begin(), deltas.end(),
@@ -108,15 +103,15 @@ void AppRegistryCache::OnApps(std::vector<std::unique_ptr<App>> deltas,
DoOnApps(std::move(deltas));
while (!deltas_pending_.empty()) {
- std::vector<std::unique_ptr<App>> pending;
+ std::vector<AppPtr> pending;
pending.swap(deltas_pending_);
DoOnApps(std::move(pending));
}
- // TODO(crbug.com/1253250): Modify and add OnAppTypeInitialized for the `App`
- // struct when the `App` struct replaces the mojom `App` struct for all
- // publishers, to prevent OnAppTypeInitialized to be called twice for both the
- // mojom struct and non-mojom struct.
+ if (base::FeatureList::IsEnabled(
+ kAppServiceOnAppTypeInitializedWithoutMojom)) {
+ OnAppTypeInitialized();
+ }
}
void AppRegistryCache::DoOnApps(std::vector<apps::mojom::AppPtr> deltas) {
@@ -179,7 +174,7 @@ void AppRegistryCache::DoOnApps(std::vector<apps::mojom::AppPtr> deltas) {
mojom_deltas_in_progress_.clear();
}
-void AppRegistryCache::DoOnApps(std::vector<std::unique_ptr<App>> deltas) {
+void AppRegistryCache::DoOnApps(std::vector<AppPtr> deltas) {
// Merge any deltas elements that have the same app_id. If an observer's
// OnAppUpdate calls back into this AppRegistryCache then we can therefore
// present a single delta for any given app_id.
@@ -242,30 +237,68 @@ void AppRegistryCache::SetAccountId(const AccountId& account_id) {
account_id_ = account_id;
}
-const std::set<apps::mojom::AppType>& AppRegistryCache::GetInitializedAppTypes()
- const {
+const std::set<AppType>& AppRegistryCache::InitializedAppTypes() const {
return initialized_app_types_;
}
-bool AppRegistryCache::IsAppTypeInitialized(
- apps::mojom::AppType app_type) const {
+bool AppRegistryCache::IsAppTypeInitialized(apps::AppType app_type) const {
return base::Contains(initialized_app_types_, app_type);
}
+void AppRegistryCache::OnMojomAppTypeInitialized() {
+ if (in_progress_initialized_mojom_app_types_.empty()) {
+ return;
+ }
+
+ auto in_progress_initialized_app_types =
+ in_progress_initialized_mojom_app_types_;
+ in_progress_initialized_mojom_app_types_.clear();
+
+ for (auto app_type : in_progress_initialized_app_types) {
+ for (auto& obs : observers_) {
+ obs.OnAppTypeInitialized(ConvertMojomAppTypToAppType(app_type));
+ }
+ initialized_app_types_.insert(ConvertMojomAppTypToAppType(app_type));
+ }
+}
+
void AppRegistryCache::OnAppTypeInitialized() {
- CHECK_EQ(kUAFSentinelInitial, uaf_sentinel_);
- if (in_progress_initialized_app_types_.empty()) {
+ if (!base::FeatureList::IsEnabled(
+ kAppServiceOnAppTypeInitializedWithoutMojom)) {
+ OnMojomAppTypeInitialized();
+ return;
+ }
+
+ // Check both the non mojom and mojom initialized status. Only when they are
+ // not initialized, call OnAppTypeInitialized to notify observers, because
+ // observers might use the non mojom or mojom App struct.
+ //
+ // TODO(crbug.com/1253250): Remove the mojom initialized checking when all
+ // observers use the non mojom App struct only.
+ if (in_progress_initialized_mojom_app_types_.empty() ||
+ in_progress_initialized_app_types_.empty()) {
return;
}
- auto in_progress_initialized_app_types = in_progress_initialized_app_types_;
- in_progress_initialized_app_types_.clear();
+ // In observer's OnAppTypeInitialized callback, `OnApp` might be call to
+ // update the app, then this OnAppTypeInitialized might be called again. So we
+ // need to check the initialized `app_type` first, and remove it from
+ // `in_progress_initialized_app_types_` to prevent the dead loop.
+ std::set<AppType> in_progress_initialized_app_types;
+ for (auto app_type : in_progress_initialized_app_types_) {
+ if (base::Contains(in_progress_initialized_mojom_app_types_,
+ ConvertAppTypeToMojomAppType(app_type))) {
+ in_progress_initialized_app_types.insert(app_type);
+ }
+ }
for (auto app_type : in_progress_initialized_app_types) {
+ auto mojom_app_type = ConvertAppTypeToMojomAppType(app_type);
+ in_progress_initialized_app_types_.erase(app_type);
+ in_progress_initialized_mojom_app_types_.erase(mojom_app_type);
for (auto& obs : observers_) {
obs.OnAppTypeInitialized(app_type);
}
- CHECK_EQ(kUAFSentinelInitial, uaf_sentinel_);
initialized_app_types_.insert(app_type);
}
}
diff --git a/chromium/components/services/app_service/public/cpp/app_registry_cache.h b/chromium/components/services/app_service/public/cpp/app_registry_cache.h
index 799a93a8af1..14f52557977 100644
--- a/chromium/components/services/app_service/public/cpp/app_registry_cache.h
+++ b/chromium/components/services/app_service/public/cpp/app_registry_cache.h
@@ -53,9 +53,9 @@ class COMPONENT_EXPORT(APP_UPDATE) AppRegistryCache {
// Called when the publisher for |app_type| has finished initiating apps.
// Note that this will not be called for app types initialized prior to this
// observer being registered. Observers should call
- // AppRegistryCache::GetInitializedAppTypes() at the time of starting
+ // AppRegistryCache::InitializedAppTypes() at the time of starting
// observation to get a set of the app types which have been initialized.
- virtual void OnAppTypeInitialized(apps::mojom::AppType app_type) {}
+ virtual void OnAppTypeInitialized(apps::AppType app_type) {}
// Called when the AppRegistryCache object (the thing that this observer
// observes) will be destroyed. In response, the observer, |this|, should
@@ -115,7 +115,7 @@ class COMPONENT_EXPORT(APP_UPDATE) AppRegistryCache {
void OnApps(std::vector<apps::mojom::AppPtr> deltas,
apps::mojom::AppType app_type,
bool should_notify_initialized);
- void OnApps(std::vector<std::unique_ptr<App>> deltas,
+ void OnApps(std::vector<AppPtr> deltas,
apps::AppType app_type,
bool should_notify_initialized);
@@ -240,26 +240,26 @@ class COMPONENT_EXPORT(APP_UPDATE) AppRegistryCache {
}
// Returns the set of app types that have so far been initialized.
- const std::set<apps::mojom::AppType>& GetInitializedAppTypes() const;
+ const std::set<AppType>& InitializedAppTypes() const;
- bool IsAppTypeInitialized(apps::mojom::AppType app_type) const;
+ bool IsAppTypeInitialized(AppType app_type) const;
private:
friend class AppRegistryCacheTest;
friend class PublisherTest;
void DoOnApps(std::vector<apps::mojom::AppPtr> deltas);
- void DoOnApps(std::vector<std::unique_ptr<App>> deltas);
+ void DoOnApps(std::vector<AppPtr> deltas);
- // NOINLINE should force this function to appear on the stack in crash dumps.
- // https://crbug.com/1237267.
- void NOINLINE OnAppTypeInitialized();
+ void OnMojomAppTypeInitialized();
+
+ void OnAppTypeInitialized();
base::ObserverList<Observer> observers_;
// Maps from app_id to the latest state: the "sum" of all previous deltas.
std::map<std::string, apps::mojom::AppPtr> mojom_states_;
- std::map<std::string, std::unique_ptr<App>> states_;
+ std::map<std::string, AppPtr> states_;
// Track the deltas being processed or are about to be processed by OnApps.
// They are separate to manage the "notification and merging might be delayed
@@ -280,23 +280,20 @@ class COMPONENT_EXPORT(APP_UPDATE) AppRegistryCache {
std::map<std::string, apps::mojom::App*> mojom_deltas_in_progress_;
std::vector<apps::mojom::AppPtr> mojom_deltas_pending_;
std::map<std::string, App*> deltas_in_progress_;
- std::vector<std::unique_ptr<App>> deltas_pending_;
+ std::vector<AppPtr> deltas_pending_;
// Saves app types which will finish initialization, and OnAppTypeInitialized
// will be called to notify observers.
- std::set<apps::mojom::AppType> in_progress_initialized_app_types_;
+ std::set<apps::mojom::AppType> in_progress_initialized_mojom_app_types_;
+ std::set<AppType> in_progress_initialized_app_types_;
// Saves app types which have finished initialization, and
// OnAppTypeInitialized has be called to notify observers.
- std::set<apps::mojom::AppType> initialized_app_types_;
+ std::set<AppType> initialized_app_types_;
AccountId account_id_;
SEQUENCE_CHECKER(my_sequence_checker_);
-
- // A sentinel value checking for a UAF in https://crbug.com/1237267. Should be
- // removed after https://crbug.com/1237267 is fixed.
- uint32_t uaf_sentinel_;
};
} // namespace apps
diff --git a/chromium/components/services/app_service/public/cpp/app_registry_cache_mojom_unittest.cc b/chromium/components/services/app_service/public/cpp/app_registry_cache_mojom_unittest.cc
index 1e52d6ad846..04612f78995 100644
--- a/chromium/components/services/app_service/public/cpp/app_registry_cache_mojom_unittest.cc
+++ b/chromium/components/services/app_service/public/cpp/app_registry_cache_mojom_unittest.cc
@@ -5,7 +5,10 @@
#include <map>
#include "base/memory/raw_ptr.h"
+#include "base/test/scoped_feature_list.h"
#include "components/services/app_service/public/cpp/app_registry_cache.h"
+#include "components/services/app_service/public/cpp/app_types.h"
+#include "components/services/app_service/public/cpp/features.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -30,6 +33,11 @@ MATCHER_P(HasAppId, app_id, "Has the correct app id") {
class AppRegistryCacheMojomTest : public testing::Test,
public apps::AppRegistryCache::Observer {
protected:
+ AppRegistryCacheMojomTest() {
+ scoped_feature_list_.InitAndDisableFeature(
+ apps::kAppServiceOnAppTypeInitializedWithoutMojom);
+ }
+
static apps::mojom::AppPtr MakeApp(
const char* app_id,
const char* name,
@@ -68,7 +76,7 @@ class AppRegistryCacheMojomTest : public testing::Test,
updated_names_.insert(update.Name());
}
- void OnAppTypeInitialized(apps::mojom::AppType app_type) override {
+ void OnAppTypeInitialized(apps::AppType app_type) override {
app_type_ = app_type;
}
@@ -78,17 +86,18 @@ class AppRegistryCacheMojomTest : public testing::Test,
NOTREACHED();
}
- void SetAppType(apps::mojom::AppType app_type) { app_type_ = app_type; }
+ void SetAppType(apps::AppType app_type) { app_type_ = app_type; }
const AccountId& account_id() const { return account_id_; }
- apps::mojom::AppType app_type() const { return app_type_; }
+ apps::AppType app_type() const { return app_type_; }
int num_freshly_installed_ = 0;
std::set<std::string> updated_ids_;
std::set<std::string> updated_names_;
AccountId account_id_ = AccountId::FromUserEmail("test@gmail.com");
- apps::mojom::AppType app_type_ = apps::mojom::AppType::kUnknown;
+ apps::AppType app_type_ = apps::AppType::kUnknown;
+ base::test::ScopedFeatureList scoped_feature_list_;
};
// Responds to a cache's OnAppUpdate to call back into the cache, checking that
@@ -126,7 +135,7 @@ class RecursiveObserver : public apps::AppRegistryCache::Observer {
int NumAppsSeenOnAppUpdate() { return num_apps_seen_on_app_update_; }
- apps::mojom::AppType app_type() const { return app_type_; }
+ apps::AppType app_type() const { return app_type_; }
protected:
// apps::AppRegistryCache::Observer overrides.
@@ -199,7 +208,7 @@ class RecursiveObserver : public apps::AppRegistryCache::Observer {
num_apps_seen_on_app_update_++;
}
- void OnAppTypeInitialized(apps::mojom::AppType app_type) override {
+ void OnAppTypeInitialized(apps::AppType app_type) override {
app_type_ = app_type;
}
@@ -222,7 +231,7 @@ class RecursiveObserver : public apps::AppRegistryCache::Observer {
int expected_num_apps_;
int num_apps_seen_on_app_update_;
AccountId account_id_ = AccountId::FromUserEmail("test@gmail.com");
- apps::mojom::AppType app_type_ = apps::mojom::AppType::kUnknown;
+ apps::AppType app_type_ = apps::AppType::kUnknown;
// Records previously seen app names, keyed by app_id's, so we can check
// that, for these tests, a given app's name is always increasing (in string
@@ -261,7 +270,7 @@ class InitializedObserver : public apps::AppRegistryCache::Observer {
updated_ids_.insert(update.AppId());
}
- void OnAppTypeInitialized(apps::mojom::AppType app_type) override {
+ void OnAppTypeInitialized(apps::AppType app_type) override {
app_type_ = app_type;
++count_;
app_count_ = updated_ids_.size();
@@ -272,9 +281,9 @@ class InitializedObserver : public apps::AppRegistryCache::Observer {
Observe(nullptr);
}
- void SetAppType(apps::mojom::AppType app_type) { app_type_ = app_type; }
+ void SetAppType(apps::AppType app_type) { app_type_ = app_type; }
- apps::mojom::AppType app_type() const { return app_type_; }
+ apps::AppType app_type() const { return app_type_; }
int count() const { return count_; }
@@ -282,7 +291,7 @@ class InitializedObserver : public apps::AppRegistryCache::Observer {
private:
std::set<std::string> updated_ids_;
- apps::mojom::AppType app_type_ = apps::mojom::AppType::kUnknown;
+ apps::AppType app_type_ = apps::AppType::kUnknown;
int count_ = 0;
int app_count_ = 0;
};
@@ -410,10 +419,10 @@ TEST_F(AppRegistryCacheMojomTest, Observer) {
EXPECT_NE(updated_ids_.end(), updated_ids_.find("a"));
EXPECT_NE(updated_ids_.end(), updated_ids_.find("c"));
EXPECT_NE(updated_ids_.end(), updated_ids_.find("e"));
- EXPECT_EQ(apps::mojom::AppType::kArc, app_type());
- EXPECT_TRUE(cache.IsAppTypeInitialized(apps::mojom::AppType::kArc));
+ EXPECT_EQ(apps::AppType::kArc, app_type());
+ EXPECT_TRUE(cache.IsAppTypeInitialized(apps::AppType::kArc));
- SetAppType(apps::mojom::AppType::kUnknown);
+ SetAppType(apps::AppType::kUnknown);
num_freshly_installed_ = 0;
updated_ids_.clear();
deltas.clear();
@@ -426,7 +435,7 @@ TEST_F(AppRegistryCacheMojomTest, Observer) {
EXPECT_EQ(2u, updated_ids_.size());
EXPECT_NE(updated_ids_.end(), updated_ids_.find("b"));
EXPECT_NE(updated_ids_.end(), updated_ids_.find("c"));
- EXPECT_EQ(apps::mojom::AppType::kUnknown, app_type());
+ EXPECT_EQ(apps::AppType::kUnknown, app_type());
cache.RemoveObserver(this);
@@ -439,8 +448,8 @@ TEST_F(AppRegistryCacheMojomTest, Observer) {
EXPECT_EQ(0, num_freshly_installed_);
EXPECT_EQ(0u, updated_ids_.size());
- EXPECT_EQ(apps::mojom::AppType::kUnknown, app_type());
- EXPECT_TRUE(cache.IsAppTypeInitialized(apps::mojom::AppType::kArc));
+ EXPECT_EQ(apps::AppType::kUnknown, app_type());
+ EXPECT_TRUE(cache.IsAppTypeInitialized(apps::AppType::kArc));
}
TEST_F(AppRegistryCacheMojomTest, Recursive) {
@@ -473,8 +482,8 @@ TEST_F(AppRegistryCacheMojomTest, Recursive) {
cache.OnApps(std::move(deltas), apps::mojom::AppType::kUnknown,
false /* should_notify_initialized */);
EXPECT_EQ(1, observer.NumAppsSeenOnAppUpdate());
- EXPECT_EQ(apps::mojom::AppType::kArc, observer.app_type());
- EXPECT_TRUE(cache.IsAppTypeInitialized(apps::mojom::AppType::kArc));
+ EXPECT_EQ(apps::AppType::kArc, observer.app_type());
+ EXPECT_TRUE(cache.IsAppTypeInitialized(apps::AppType::kArc));
}
TEST_F(AppRegistryCacheMojomTest, SuperRecursive) {
@@ -521,8 +530,8 @@ TEST_F(AppRegistryCacheMojomTest, SuperRecursive) {
EXPECT_EQ("avocado", GetName(cache, "a"));
EXPECT_EQ("boysenberry", GetName(cache, "b"));
EXPECT_EQ("coconut", GetName(cache, "c"));
- EXPECT_EQ(apps::mojom::AppType::kArc, observer.app_type());
- EXPECT_TRUE(cache.IsAppTypeInitialized(apps::mojom::AppType::kArc));
+ EXPECT_EQ(apps::AppType::kArc, observer.app_type());
+ EXPECT_TRUE(cache.IsAppTypeInitialized(apps::AppType::kArc));
}
TEST_F(AppRegistryCacheMojomTest, OnAppTypeInitialized) {
@@ -541,16 +550,16 @@ TEST_F(AppRegistryCacheMojomTest, OnAppTypeInitialized) {
cache.OnApps(std::move(deltas), apps::mojom::AppType::kArc,
true /* should_notify_initialized */);
- EXPECT_EQ(apps::mojom::AppType::kArc, observer1.app_type());
+ EXPECT_EQ(apps::AppType::kArc, observer1.app_type());
EXPECT_EQ(1, observer1.count());
EXPECT_EQ(3, observer1.app_count());
- EXPECT_EQ(1u, cache.GetInitializedAppTypes().size());
- EXPECT_TRUE(cache.IsAppTypeInitialized(apps::mojom::AppType::kArc));
+ EXPECT_EQ(1u, cache.InitializedAppTypes().size());
+ EXPECT_TRUE(cache.IsAppTypeInitialized(apps::AppType::kArc));
// New observers should not have OnAppTypeInitialized called.
InitializedObserver observer2(&cache);
- EXPECT_EQ(apps::mojom::AppType::kUnknown, observer2.app_type());
+ EXPECT_EQ(apps::AppType::kUnknown, observer2.app_type());
EXPECT_EQ(0, observer2.count());
- EXPECT_EQ(1u, cache.GetInitializedAppTypes().size());
- EXPECT_TRUE(cache.IsAppTypeInitialized(apps::mojom::AppType::kArc));
+ EXPECT_EQ(1u, cache.InitializedAppTypes().size());
+ EXPECT_TRUE(cache.IsAppTypeInitialized(apps::AppType::kArc));
}
diff --git a/chromium/components/services/app_service/public/cpp/app_registry_cache_unittest.cc b/chromium/components/services/app_service/public/cpp/app_registry_cache_unittest.cc
index c6c81461ff4..ebaa29ce7fb 100644
--- a/chromium/components/services/app_service/public/cpp/app_registry_cache_unittest.cc
+++ b/chromium/components/services/app_service/public/cpp/app_registry_cache_unittest.cc
@@ -2,29 +2,112 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "components/services/app_service/public/cpp/app_registry_cache.h"
+
#include <map>
+#include <set>
#include <utility>
#include <vector>
-#include "components/services/app_service/public/cpp/app_registry_cache.h"
+#include "base/containers/contains.h"
+#include "base/test/scoped_feature_list.h"
+#include "components/services/app_service/public/cpp/app_types.h"
+#include "components/services/app_service/public/cpp/features.h"
#include "components/services/app_service/public/cpp/types_util.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace apps {
-class AppRegistryCacheTest : public testing::Test {
+namespace {
+
+apps::AppPtr MakeApp(const char* app_id,
+ const char* name,
+ apps::AppType app_type = apps::AppType::kArc,
+ apps::Readiness readiness = apps::Readiness::kUnknown,
+ uint64_t timeline = 0) {
+ auto app = std::make_unique<apps::App>(app_type, app_id);
+ app->readiness = readiness;
+ app->name = name;
+ app->icon_key =
+ apps::IconKey(timeline, /*resource_id=*/0, /*icon_effects=*/0);
+ return app;
+}
+
+apps::mojom::AppPtr MakeMojomApp(
+ const char* app_id,
+ const char* name,
+ apps::mojom::AppType app_type = apps::mojom::AppType::kArc) {
+ apps::mojom::AppPtr app = apps::mojom::App::New();
+ app->app_type = app_type;
+ app->app_id = app_id;
+ app->name = name;
+ return app;
+}
+
+// InitializedObserver is used to test the OnAppTypeInitialized interface for
+// AppRegistryCache::Observer.
+class InitializedObserver : public apps::AppRegistryCache::Observer {
public:
- std::unique_ptr<App> MakeApp(const char* app_id,
- const char* name,
- Readiness readiness = Readiness::kUnknown,
- uint64_t timeline = 0) {
- std::unique_ptr<App> app = std::make_unique<App>(AppType::kArc, app_id);
- app->readiness = readiness;
- app->name = name;
- app->icon_key = IconKey(timeline, /*resource_id=*/0, /*icon_effects=*/0);
- return app;
+ explicit InitializedObserver(apps::AppRegistryCache* cache) {
+ cache_ = cache;
+ Observe(cache);
+ }
+
+ ~InitializedObserver() override = default;
+
+ // apps::AppRegistryCache::Observer overrides.
+ void OnAppUpdate(const apps::AppUpdate& update) override {
+ updated_ids_.insert(update.AppId());
+ }
+
+ void UpdateApps() {
+ std::vector<AppPtr> deltas;
+ deltas.push_back(MakeApp("n", "noodle", AppType::kArc));
+ deltas.push_back(MakeApp("s", "salmon", AppType::kChromeApp));
+ cache_->OnApps(std::move(deltas), AppType::kUnknown,
+ false /* should_notify_initialized */);
+
+ std::vector<apps::mojom::AppPtr> mojom_deltas;
+ mojom_deltas.push_back(
+ MakeMojomApp("n", "noodle", apps::mojom::AppType::kArc));
+ mojom_deltas.push_back(
+ MakeMojomApp("s", "salmon", apps::mojom::AppType::kChromeApp));
+ cache_->OnApps(std::move(mojom_deltas), apps::mojom::AppType::kUnknown,
+ false /* should_notify_initialized */);
+ }
+
+ void OnAppTypeInitialized(apps::AppType app_type) override {
+ app_types_.insert(app_type);
+ ++initialized_app_type_count_;
+ app_count_at_initialization_ = updated_ids_.size();
+ UpdateApps();
+ }
+
+ void OnAppRegistryCacheWillBeDestroyed(
+ apps::AppRegistryCache* cache) override {
+ Observe(nullptr);
+ }
+
+ std::set<apps::AppType> app_types() const { return app_types_; }
+
+ int initialized_app_type_count() const { return initialized_app_type_count_; }
+
+ int app_count_at_initialization() const {
+ return app_count_at_initialization_;
}
+ private:
+ std::set<std::string> updated_ids_;
+ std::set<apps::AppType> app_types_;
+ int initialized_app_type_count_ = 0;
+ int app_count_at_initialization_ = 0;
+ apps::AppRegistryCache* cache_ = nullptr;
+};
+
+} // namespace
+
+class AppRegistryCacheTest : public testing::Test {
+ public:
void CallForAllApps(AppRegistryCache& cache) {
cache.ForAllApps([this](const AppUpdate& update) { OnAppUpdate(update); });
}
@@ -68,16 +151,30 @@ class AppRegistryCacheTest : public testing::Test {
updated_names_.clear();
}
+ void DisableOnAppTypeInitializedFlag() {
+ scoped_feature_list_.InitAndDisableFeature(
+ kAppServiceOnAppTypeInitializedWithoutMojom);
+ }
+
+ void EnableOnAppTypeInitializedFlag() {
+ scoped_feature_list_.InitAndEnableFeature(
+ kAppServiceOnAppTypeInitializedWithoutMojom);
+ }
+
std::set<std::string> updated_ids_;
std::set<std::string> updated_names_;
+
+ private:
+ base::test::ScopedFeatureList scoped_feature_list_;
};
TEST_F(AppRegistryCacheTest, OnApps) {
AppRegistryCache cache;
- std::vector<std::unique_ptr<App>> deltas;
+ std::vector<AppPtr> deltas;
deltas.push_back(MakeApp("a", "apple"));
- deltas.push_back(MakeApp("b", "banana", Readiness::kReady));
- deltas.push_back(MakeApp("c", "cherry", Readiness::kDisabledByPolicy,
+ deltas.push_back(MakeApp("b", "banana", AppType::kArc, Readiness::kReady));
+ deltas.push_back(MakeApp("c", "cherry", AppType::kArc,
+ Readiness::kDisabledByPolicy,
/*timeline=*/10));
cache.OnApps(std::move(deltas), AppType::kUnknown,
false /* should_notify_initialized */);
@@ -98,7 +195,7 @@ TEST_F(AppRegistryCacheTest, OnApps) {
Clear();
deltas.clear();
- deltas.push_back(MakeApp("a", "apricot", Readiness::kReady));
+ deltas.push_back(MakeApp("a", "apricot", AppType::kArc, Readiness::kReady));
deltas.push_back(MakeApp("d", "durian"));
cache.OnApps(std::move(deltas), AppType::kUnknown,
false /* should_notify_initialized */);
@@ -121,8 +218,8 @@ TEST_F(AppRegistryCacheTest, OnApps) {
TEST_F(AppRegistryCacheTest, Removed) {
AppRegistryCache cache;
- std::vector<std::unique_ptr<App>> apps;
- apps.push_back(MakeApp("app", "app", Readiness::kReady));
+ std::vector<AppPtr> apps;
+ apps.push_back(MakeApp("app", "app", AppType::kArc, Readiness::kReady));
cache.OnApps(std::move(apps), AppType::kUnknown,
false /* should_notify_initialized */);
@@ -135,8 +232,9 @@ TEST_F(AppRegistryCacheTest, Removed) {
// Uninstall the app, then remove it.
apps.clear();
- apps.push_back(MakeApp("app", "app", Readiness::kUninstalledByUser));
- apps.push_back(MakeApp("app", "app", Readiness::kRemoved));
+ apps.push_back(
+ MakeApp("app", "app", AppType::kArc, Readiness::kUninstalledByUser));
+ apps.push_back(MakeApp("app", "app", AppType::kArc, Readiness::kRemoved));
cache.OnApps(std::move(apps), AppType::kUnknown,
false /* should_notify_initialized */);
@@ -148,4 +246,549 @@ TEST_F(AppRegistryCacheTest, Removed) {
Clear();
}
+// Verify the OnAppTypeInitialized callback when OnApps is called for the non
+// mojom App type first, with the disabled flag.
+TEST_F(AppRegistryCacheTest,
+ OnAppTypeInitializedWithDisableFlagNonMojomUpdateFirst) {
+ DisableOnAppTypeInitializedFlag();
+
+ AppRegistryCache cache;
+ InitializedObserver observer1(&cache);
+
+ std::vector<AppPtr> deltas1;
+ deltas1.push_back(MakeApp("a", "avocado"));
+ deltas1.push_back(MakeApp("c", "cucumber"));
+ cache.OnApps(std::move(deltas1), AppType::kArc,
+ true /* should_notify_initialized */);
+
+ // Verify OnAppTypeInitialized is not called when the non mojom Apps are
+ // added.
+ EXPECT_TRUE(observer1.app_types().empty());
+ EXPECT_EQ(0, observer1.initialized_app_type_count());
+ EXPECT_EQ(0, observer1.app_count_at_initialization());
+ EXPECT_TRUE(cache.InitializedAppTypes().empty());
+ EXPECT_FALSE(cache.IsAppTypeInitialized(AppType::kArc));
+
+ std::vector<apps::mojom::AppPtr> mojom_deltas1;
+ mojom_deltas1.push_back(MakeMojomApp("a", "avocado"));
+ mojom_deltas1.push_back(MakeMojomApp("c", "cucumber"));
+ cache.OnApps(std::move(mojom_deltas1), apps::mojom::AppType::kArc,
+ true /* should_notify_initialized */);
+
+ // Verify OnAppTypeInitialized is called when the mojom Apps are added.
+ EXPECT_TRUE(base::Contains(observer1.app_types(), apps::AppType::kArc));
+ EXPECT_EQ(1, observer1.initialized_app_type_count());
+ EXPECT_EQ(2, observer1.app_count_at_initialization());
+ EXPECT_EQ(1u, cache.InitializedAppTypes().size());
+ EXPECT_TRUE(cache.IsAppTypeInitialized(AppType::kArc));
+
+ std::vector<AppPtr> deltas2;
+ deltas2.push_back(MakeApp("d", "durian"));
+ cache.OnApps(std::move(deltas2), AppType::kArc,
+ true /* should_notify_initialized */);
+
+ // Verify OnAppTypeInitialized is not called when the non mojom Apps are
+ // added.
+ EXPECT_EQ(1, observer1.initialized_app_type_count());
+ EXPECT_EQ(2, observer1.app_count_at_initialization());
+ EXPECT_EQ(1u, cache.InitializedAppTypes().size());
+
+ std::vector<apps::mojom::AppPtr> mojom_deltas2;
+ mojom_deltas2.push_back(MakeMojomApp("d", "durian"));
+ cache.OnApps(std::move(mojom_deltas2), apps::mojom::AppType::kArc,
+ true /* should_notify_initialized */);
+
+ // Verify OnAppTypeInitialized is not called when the mojom Apps are
+ // initialized again.
+ EXPECT_EQ(1, observer1.initialized_app_type_count());
+ EXPECT_EQ(2, observer1.app_count_at_initialization());
+ EXPECT_EQ(1u, cache.InitializedAppTypes().size());
+
+ // Verify the new observers should not have OnAppTypeInitialized called.
+ InitializedObserver observer2(&cache);
+ EXPECT_TRUE(observer2.app_types().empty());
+ EXPECT_EQ(0, observer2.initialized_app_type_count());
+ EXPECT_EQ(0, observer2.app_count_at_initialization());
+}
+
+// Verify the OnAppTypeInitialized callback when OnApps is called for the mojom
+// App type first, with the disabled flag.
+TEST_F(AppRegistryCacheTest,
+ OnAppTypeInitializedWithDisableFlagMojomUpdateFirst) {
+ DisableOnAppTypeInitializedFlag();
+
+ AppRegistryCache cache;
+ InitializedObserver observer1(&cache);
+
+ std::vector<apps::mojom::AppPtr> mojom_deltas1;
+ mojom_deltas1.push_back(MakeMojomApp("a", "avocado"));
+ mojom_deltas1.push_back(MakeMojomApp("c", "cucumber"));
+ cache.OnApps(std::move(mojom_deltas1), apps::mojom::AppType::kArc,
+ true /* should_notify_initialized */);
+
+ // Verify OnAppTypeInitialized is called when the mojom Apps are added.
+ EXPECT_TRUE(base::Contains(observer1.app_types(), apps::AppType::kArc));
+ EXPECT_EQ(1, observer1.initialized_app_type_count());
+ EXPECT_EQ(2, observer1.app_count_at_initialization());
+ EXPECT_EQ(1u, cache.InitializedAppTypes().size());
+ EXPECT_TRUE(cache.IsAppTypeInitialized(AppType::kArc));
+
+ std::vector<AppPtr> deltas1;
+ deltas1.push_back(MakeApp("a", "avocado"));
+ deltas1.push_back(MakeApp("c", "cucumber"));
+ cache.OnApps(std::move(deltas1), AppType::kArc,
+ true /* should_notify_initialized */);
+
+ // Verify OnAppTypeInitialized is not called when the non mojom Apps are
+ // added.
+ EXPECT_EQ(1, observer1.initialized_app_type_count());
+ EXPECT_EQ(2, observer1.app_count_at_initialization());
+
+ std::vector<apps::mojom::AppPtr> mojom_deltas2;
+ mojom_deltas2.push_back(MakeMojomApp("d", "durian"));
+ cache.OnApps(std::move(mojom_deltas2), apps::mojom::AppType::kArc,
+ true /* should_notify_initialized */);
+
+ std::vector<AppPtr> deltas2;
+ deltas2.push_back(MakeApp("d", "durian"));
+ cache.OnApps(std::move(deltas2), AppType::kArc,
+ true /* should_notify_initialized */);
+
+ // Verify OnAppTypeInitialized is not called when the Apps are added.
+ EXPECT_EQ(1, observer1.initialized_app_type_count());
+ EXPECT_EQ(2, observer1.app_count_at_initialization());
+ EXPECT_EQ(1u, cache.InitializedAppTypes().size());
+
+ // Verify the new observers should not have OnAppTypeInitialized called.
+ InitializedObserver observer2(&cache);
+ EXPECT_TRUE(observer2.app_types().empty());
+ EXPECT_EQ(0, observer2.initialized_app_type_count());
+ EXPECT_EQ(0, observer2.app_count_at_initialization());
+}
+
+// Verify the OnAppTypeInitialized callback when OnApps is called for multiple
+// App types, with the disabled flag.
+TEST_F(AppRegistryCacheTest,
+ OnAppTypeInitializedWithDisableFlagMultipleAppTypes) {
+ DisableOnAppTypeInitializedFlag();
+
+ AppRegistryCache cache;
+ InitializedObserver observer1(&cache);
+
+ std::vector<AppPtr> deltas1;
+ deltas1.push_back(MakeApp("a", "avocado"));
+ deltas1.push_back(MakeApp("c", "cucumber"));
+ cache.OnApps(std::move(deltas1), AppType::kArc,
+ true /* should_notify_initialized */);
+
+ // Verify OnAppTypeInitialized is not called when the non mojom Apps are
+ // added.
+ EXPECT_TRUE(observer1.app_types().empty());
+ EXPECT_EQ(0, observer1.initialized_app_type_count());
+ EXPECT_EQ(0, observer1.app_count_at_initialization());
+ EXPECT_TRUE(cache.InitializedAppTypes().empty());
+
+ std::vector<apps::mojom::AppPtr> mojom_deltas1;
+ mojom_deltas1.push_back(MakeMojomApp("a", "avocado"));
+ mojom_deltas1.push_back(MakeMojomApp("c", "cucumber"));
+ cache.OnApps(std::move(mojom_deltas1), apps::mojom::AppType::kArc,
+ true /* should_notify_initialized */);
+
+ // Verify OnAppTypeInitialized is called when the mojom Apps are added.
+ EXPECT_TRUE(base::Contains(observer1.app_types(), apps::AppType::kArc));
+ EXPECT_EQ(1, observer1.initialized_app_type_count());
+ EXPECT_EQ(2, observer1.app_count_at_initialization());
+ EXPECT_EQ(1u, cache.InitializedAppTypes().size());
+ EXPECT_TRUE(cache.IsAppTypeInitialized(AppType::kArc));
+
+ std::vector<apps::mojom::AppPtr> mojom_deltas2;
+ mojom_deltas2.push_back(
+ MakeMojomApp("d", "durian", apps::mojom::AppType::kChromeApp));
+ cache.OnApps(std::move(mojom_deltas2), apps::mojom::AppType::kChromeApp,
+ true /* should_notify_initialized */);
+
+ // Verify OnAppTypeInitialized is called when the mojom Apps are added.
+ EXPECT_EQ(2u, observer1.app_types().size());
+ EXPECT_TRUE(base::Contains(observer1.app_types(), apps::AppType::kChromeApp));
+ EXPECT_EQ(2, observer1.initialized_app_type_count());
+ EXPECT_EQ(5, observer1.app_count_at_initialization());
+ EXPECT_EQ(2u, cache.InitializedAppTypes().size());
+ EXPECT_TRUE(cache.IsAppTypeInitialized(AppType::kChromeApp));
+
+ std::vector<AppPtr> deltas2;
+ deltas2.push_back(MakeApp("d", "durian", AppType::kChromeApp));
+ cache.OnApps(std::move(deltas2), AppType::kChromeApp,
+ true /* should_notify_initialized */);
+
+ // Verify OnAppTypeInitialized is not called when the non mojom Apps are
+ // added.
+ EXPECT_EQ(2, observer1.initialized_app_type_count());
+ EXPECT_EQ(5, observer1.app_count_at_initialization());
+ EXPECT_EQ(2u, cache.InitializedAppTypes().size());
+
+ // Verify the new observers should not have OnAppTypeInitialized called.
+ InitializedObserver observer2(&cache);
+ EXPECT_TRUE(observer2.app_types().empty());
+ EXPECT_EQ(0, observer2.initialized_app_type_count());
+ EXPECT_EQ(0, observer2.app_count_at_initialization());
+}
+
+// Verify the OnAppTypeInitialized callback when OnApps is called for empty apps
+// vector, with the disabled flag.
+TEST_F(AppRegistryCacheTest, OnAppTypeInitializedWithDisableFlagEmptyUpdate) {
+ DisableOnAppTypeInitializedFlag();
+
+ AppRegistryCache cache;
+ InitializedObserver observer1(&cache);
+
+ std::vector<AppPtr> deltas1;
+ cache.OnApps(std::move(deltas1), AppType::kStandaloneBrowserChromeApp,
+ true /* should_notify_initialized */);
+
+ // Verify OnAppTypeInitialized is not called when the non mojom Apps are
+ // initialized.
+ EXPECT_TRUE(observer1.app_types().empty());
+ EXPECT_EQ(0, observer1.initialized_app_type_count());
+ EXPECT_EQ(0, observer1.app_count_at_initialization());
+ EXPECT_TRUE(cache.InitializedAppTypes().empty());
+ EXPECT_FALSE(
+ cache.IsAppTypeInitialized(AppType::kStandaloneBrowserChromeApp));
+
+ std::vector<apps::mojom::AppPtr> mojom_deltas1;
+ cache.OnApps(std::move(mojom_deltas1),
+ apps::mojom::AppType::kStandaloneBrowserChromeApp,
+ true /* should_notify_initialized */);
+
+ // Verify OnAppTypeInitialized is called when the mojom Apps are initialized.
+ EXPECT_TRUE(base::Contains(observer1.app_types(),
+ apps::AppType::kStandaloneBrowserChromeApp));
+ EXPECT_EQ(1, observer1.initialized_app_type_count());
+ EXPECT_EQ(0, observer1.app_count_at_initialization());
+ EXPECT_EQ(1u, cache.InitializedAppTypes().size());
+ EXPECT_TRUE(cache.IsAppTypeInitialized(AppType::kStandaloneBrowserChromeApp));
+
+ std::vector<AppPtr> deltas2;
+ deltas2.push_back(MakeApp("d", "durian"));
+ cache.OnApps(std::move(deltas2), AppType::kStandaloneBrowserChromeApp,
+ true /* should_notify_initialized */);
+
+ // Verify OnAppTypeInitialized is not called when the non mojom Apps are
+ // initialized again.
+ EXPECT_EQ(1, observer1.initialized_app_type_count());
+ EXPECT_EQ(0, observer1.app_count_at_initialization());
+ EXPECT_EQ(1u, cache.InitializedAppTypes().size());
+
+ std::vector<apps::mojom::AppPtr> mojom_deltas2;
+ mojom_deltas2.push_back(MakeMojomApp("d", "durian"));
+ cache.OnApps(std::move(mojom_deltas2),
+ apps::mojom::AppType::kStandaloneBrowserChromeApp,
+ true /* should_notify_initialized */);
+
+ // Verify OnAppTypeInitialized is not called when the mojom Apps are
+ // initialized again.
+ EXPECT_EQ(1, observer1.initialized_app_type_count());
+ EXPECT_EQ(0, observer1.app_count_at_initialization());
+ EXPECT_EQ(1u, cache.InitializedAppTypes().size());
+
+ std::vector<apps::mojom::AppPtr> mojom_deltas3;
+ cache.OnApps(std::move(mojom_deltas3), apps::mojom::AppType::kRemote,
+ true /* should_notify_initialized */);
+
+ // Verify OnAppTypeInitialized is called when the mojom Apps are initialized.
+ EXPECT_EQ(2u, observer1.app_types().size());
+ EXPECT_TRUE(base::Contains(observer1.app_types(), apps::AppType::kRemote));
+ EXPECT_EQ(2, observer1.initialized_app_type_count());
+ EXPECT_EQ(2u, cache.InitializedAppTypes().size());
+ EXPECT_TRUE(cache.IsAppTypeInitialized(AppType::kRemote));
+
+ std::vector<AppPtr> deltas3;
+ cache.OnApps(std::move(deltas3), AppType::kRemote,
+ true /* should_notify_initialized */);
+
+ // Verify OnAppTypeInitialized is not called when the non mojom Apps are
+ // initialized.
+ EXPECT_EQ(2, observer1.initialized_app_type_count());
+ EXPECT_EQ(2u, cache.InitializedAppTypes().size());
+
+ // Verify the new observers should not have OnAppTypeInitialized called.
+ InitializedObserver observer2(&cache);
+ EXPECT_TRUE(observer2.app_types().empty());
+ EXPECT_EQ(0, observer2.initialized_app_type_count());
+ EXPECT_EQ(0, observer2.app_count_at_initialization());
+}
+
+// Verify the OnAppTypeInitialized callback when OnApps is called for the non
+// mojom App type first, with the enabled flag.
+TEST_F(AppRegistryCacheTest,
+ OnAppTypeInitializedWithEnableFlagNonMojomUpdateFirst) {
+ EnableOnAppTypeInitializedFlag();
+
+ AppRegistryCache cache;
+ InitializedObserver observer1(&cache);
+
+ std::vector<AppPtr> deltas1;
+ deltas1.push_back(MakeApp("a", "avocado"));
+ deltas1.push_back(MakeApp("c", "cucumber"));
+ cache.OnApps(std::move(deltas1), AppType::kArc,
+ true /* should_notify_initialized */);
+
+ // Verify OnAppTypeInitialized is not called when the non mojom Apps are
+ // added.
+ EXPECT_TRUE(observer1.app_types().empty());
+ EXPECT_EQ(0, observer1.initialized_app_type_count());
+ EXPECT_EQ(0, observer1.app_count_at_initialization());
+ EXPECT_EQ(0u, cache.InitializedAppTypes().size());
+ EXPECT_FALSE(cache.IsAppTypeInitialized(AppType::kArc));
+
+ std::vector<apps::mojom::AppPtr> mojom_deltas1;
+ mojom_deltas1.push_back(MakeMojomApp("a", "avocado"));
+ mojom_deltas1.push_back(MakeMojomApp("c", "cucumber"));
+ cache.OnApps(std::move(mojom_deltas1), apps::mojom::AppType::kArc,
+ true /* should_notify_initialized */);
+
+ // Verify OnAppTypeInitialized is called when both the non mojom and mojom
+ // Apps are added.
+ EXPECT_TRUE(base::Contains(observer1.app_types(), AppType::kArc));
+ EXPECT_EQ(1, observer1.initialized_app_type_count());
+ EXPECT_EQ(2, observer1.app_count_at_initialization());
+ EXPECT_EQ(1u, cache.InitializedAppTypes().size());
+ EXPECT_TRUE(cache.IsAppTypeInitialized(AppType::kArc));
+
+ std::vector<AppPtr> deltas2;
+ deltas2.push_back(MakeApp("d", "durian"));
+ cache.OnApps(std::move(deltas2), AppType::kArc,
+ true /* should_notify_initialized */);
+
+ std::vector<apps::mojom::AppPtr> mojom_deltas2;
+ mojom_deltas2.push_back(MakeMojomApp("d", "durian"));
+ cache.OnApps(std::move(mojom_deltas2), apps::mojom::AppType::kArc,
+ true /* should_notify_initialized */);
+
+ // Verify OnAppTypeInitialized is not called when more Apps are
+ // added.
+ EXPECT_TRUE(base::Contains(observer1.app_types(), AppType::kArc));
+ EXPECT_EQ(1, observer1.initialized_app_type_count());
+ EXPECT_EQ(2, observer1.app_count_at_initialization());
+ EXPECT_EQ(1u, cache.InitializedAppTypes().size());
+
+ // Verify the new observers should not have OnAppTypeInitialized called.
+ InitializedObserver observer2(&cache);
+ EXPECT_TRUE(observer2.app_types().empty());
+ EXPECT_EQ(0, observer2.initialized_app_type_count());
+ EXPECT_EQ(0, observer2.app_count_at_initialization());
+}
+
+// Verify the OnAppTypeInitialized callback when OnApps is called for the mojom
+// App type first, with the enabled flag.
+TEST_F(AppRegistryCacheTest,
+ OnAppTypeInitializedWithEnableFlagMojomUpdateFirst) {
+ EnableOnAppTypeInitializedFlag();
+
+ AppRegistryCache cache;
+ InitializedObserver observer1(&cache);
+
+ std::vector<apps::mojom::AppPtr> mojom_deltas1;
+ mojom_deltas1.push_back(MakeMojomApp("a", "avocado"));
+ mojom_deltas1.push_back(MakeMojomApp("c", "cucumber"));
+ cache.OnApps(std::move(mojom_deltas1), apps::mojom::AppType::kArc,
+ true /* should_notify_initialized */);
+
+ // Verify OnAppTypeInitialized is not called when the mojom Apps are added.
+ EXPECT_TRUE(observer1.app_types().empty());
+ EXPECT_EQ(0, observer1.initialized_app_type_count());
+ EXPECT_EQ(0, observer1.app_count_at_initialization());
+ EXPECT_EQ(0u, cache.InitializedAppTypes().size());
+ EXPECT_FALSE(cache.IsAppTypeInitialized(AppType::kArc));
+
+ std::vector<AppPtr> deltas1;
+ deltas1.push_back(MakeApp("a", "avocado"));
+ deltas1.push_back(MakeApp("c", "cucumber"));
+ cache.OnApps(std::move(deltas1), AppType::kArc,
+ true /* should_notify_initialized */);
+
+ // Verify OnAppTypeInitialized is called when both the non mojom and mojom
+ // Apps are added.
+ EXPECT_TRUE(base::Contains(observer1.app_types(), AppType::kArc));
+ EXPECT_EQ(1, observer1.initialized_app_type_count());
+ EXPECT_EQ(2, observer1.app_count_at_initialization());
+ EXPECT_EQ(1u, cache.InitializedAppTypes().size());
+ EXPECT_TRUE(cache.IsAppTypeInitialized(AppType::kArc));
+
+ std::vector<apps::mojom::AppPtr> mojom_deltas2;
+ mojom_deltas2.push_back(MakeMojomApp("d", "durian"));
+ cache.OnApps(std::move(mojom_deltas2), apps::mojom::AppType::kArc,
+ true /* should_notify_initialized */);
+
+ std::vector<AppPtr> deltas2;
+ deltas2.push_back(MakeApp("d", "durian"));
+ cache.OnApps(std::move(deltas2), AppType::kArc,
+ true /* should_notify_initialized */);
+
+ // Verify OnAppTypeInitialized is not called when the Apps are added.
+ EXPECT_EQ(1, observer1.initialized_app_type_count());
+ EXPECT_EQ(2, observer1.app_count_at_initialization());
+ EXPECT_EQ(1u, cache.InitializedAppTypes().size());
+
+ // Verify the new observers should not have OnAppTypeInitialized called.
+ InitializedObserver observer2(&cache);
+ EXPECT_TRUE(observer2.app_types().empty());
+ EXPECT_EQ(0, observer2.initialized_app_type_count());
+ EXPECT_EQ(0, observer2.app_count_at_initialization());
+}
+
+// Verify the OnAppTypeInitialized callback when OnApps is called for multiple
+// App types, with the enabled flag.
+TEST_F(AppRegistryCacheTest,
+ OnAppTypeInitializedWithEnableFlagMultipleAppTypes) {
+ EnableOnAppTypeInitializedFlag();
+
+ AppRegistryCache cache;
+ InitializedObserver observer1(&cache);
+
+ std::vector<AppPtr> deltas1;
+ deltas1.push_back(MakeApp("a", "avocado"));
+ deltas1.push_back(MakeApp("c", "cucumber"));
+ cache.OnApps(std::move(deltas1), AppType::kArc,
+ true /* should_notify_initialized */);
+
+ // Verify OnAppTypeInitialized is not called when the non mojom Apps are
+ // added.
+ EXPECT_TRUE(observer1.app_types().empty());
+ EXPECT_EQ(0, observer1.initialized_app_type_count());
+ EXPECT_EQ(0, observer1.app_count_at_initialization());
+ EXPECT_TRUE(cache.InitializedAppTypes().empty());
+
+ std::vector<apps::mojom::AppPtr> mojom_deltas1;
+ mojom_deltas1.push_back(MakeMojomApp("a", "avocado"));
+ mojom_deltas1.push_back(MakeMojomApp("c", "cucumber"));
+ cache.OnApps(std::move(mojom_deltas1), apps::mojom::AppType::kArc,
+ true /* should_notify_initialized */);
+
+ // Verify OnAppTypeInitialized is called when both the non mojom and mojom
+ // Apps are added.
+ EXPECT_TRUE(base::Contains(observer1.app_types(), AppType::kArc));
+ EXPECT_EQ(1, observer1.initialized_app_type_count());
+ EXPECT_EQ(2, observer1.app_count_at_initialization());
+ EXPECT_EQ(1u, cache.InitializedAppTypes().size());
+ EXPECT_TRUE(cache.IsAppTypeInitialized(AppType::kArc));
+
+ std::vector<apps::mojom::AppPtr> mojom_deltas2;
+ mojom_deltas2.push_back(
+ MakeMojomApp("d", "durian", apps::mojom::AppType::kChromeApp));
+ cache.OnApps(std::move(mojom_deltas2), apps::mojom::AppType::kChromeApp,
+ true /* should_notify_initialized */);
+
+ // Verify OnAppTypeInitialized is not called when the mojom Apps are added.
+ EXPECT_EQ(1u, observer1.app_types().size());
+ EXPECT_FALSE(base::Contains(observer1.app_types(), AppType::kChromeApp));
+ EXPECT_EQ(1, observer1.initialized_app_type_count());
+ EXPECT_EQ(2, observer1.app_count_at_initialization());
+ EXPECT_EQ(1u, cache.InitializedAppTypes().size());
+ EXPECT_FALSE(cache.IsAppTypeInitialized(AppType::kChromeApp));
+
+ std::vector<AppPtr> deltas2;
+ deltas2.push_back(MakeApp("d", "durian", AppType::kChromeApp));
+ cache.OnApps(std::move(deltas2), AppType::kChromeApp,
+ true /* should_notify_initialized */);
+
+ // Verify OnAppTypeInitialized is called when both the non mojom and mojom
+ // Apps are added.
+ EXPECT_EQ(2u, observer1.app_types().size());
+ EXPECT_TRUE(base::Contains(observer1.app_types(), AppType::kChromeApp));
+ EXPECT_EQ(2, observer1.initialized_app_type_count());
+ EXPECT_EQ(5, observer1.app_count_at_initialization());
+ EXPECT_EQ(2u, cache.InitializedAppTypes().size());
+ EXPECT_TRUE(cache.IsAppTypeInitialized(AppType::kChromeApp));
+
+ // Verify the new observers should not have OnAppTypeInitialized called.
+ InitializedObserver observer2(&cache);
+ EXPECT_TRUE(observer2.app_types().empty());
+ EXPECT_EQ(0, observer2.initialized_app_type_count());
+ EXPECT_EQ(0, observer2.app_count_at_initialization());
+}
+
+// Verify the OnAppTypeInitialized callback when OnApps is called for empty apps
+// vector, with the enabled flag.
+TEST_F(AppRegistryCacheTest, OnAppTypeInitializedWithEnableFlagEmptyUpdate) {
+ EnableOnAppTypeInitializedFlag();
+
+ AppRegistryCache cache;
+ InitializedObserver observer1(&cache);
+
+ std::vector<AppPtr> deltas1;
+ cache.OnApps(std::move(deltas1), AppType::kStandaloneBrowserChromeApp,
+ true /* should_notify_initialized */);
+
+ // Verify OnAppTypeInitialized is not called when the non mojom Apps are
+ // initialized.
+ EXPECT_TRUE(observer1.app_types().empty());
+ EXPECT_EQ(0, observer1.initialized_app_type_count());
+ EXPECT_EQ(0, observer1.app_count_at_initialization());
+ EXPECT_TRUE(cache.InitializedAppTypes().empty());
+
+ std::vector<apps::mojom::AppPtr> mojom_deltas1;
+ cache.OnApps(std::move(mojom_deltas1),
+ apps::mojom::AppType::kStandaloneBrowserChromeApp,
+ true /* should_notify_initialized */);
+
+ // Verify OnAppTypeInitialized is called when both the mojom and non mojom
+ // Apps are initialized.
+ EXPECT_TRUE(base::Contains(observer1.app_types(),
+ AppType::kStandaloneBrowserChromeApp));
+ EXPECT_EQ(1, observer1.initialized_app_type_count());
+ EXPECT_EQ(0, observer1.app_count_at_initialization());
+ EXPECT_EQ(1u, cache.InitializedAppTypes().size());
+ EXPECT_TRUE(cache.IsAppTypeInitialized(AppType::kStandaloneBrowserChromeApp));
+
+ std::vector<AppPtr> deltas2;
+ deltas2.push_back(MakeApp("d", "durian"));
+ cache.OnApps(std::move(deltas2), AppType::kStandaloneBrowserChromeApp,
+ true /* should_notify_initialized */);
+
+ // Verify OnAppTypeInitialized is not called when the non mojom Apps are
+ // initialized again.
+ EXPECT_EQ(1, observer1.initialized_app_type_count());
+ EXPECT_EQ(0, observer1.app_count_at_initialization());
+ EXPECT_EQ(1u, cache.InitializedAppTypes().size());
+
+ std::vector<apps::mojom::AppPtr> mojom_deltas2;
+ mojom_deltas2.push_back(MakeMojomApp("d", "durian"));
+ cache.OnApps(std::move(mojom_deltas2),
+ apps::mojom::AppType::kStandaloneBrowserChromeApp,
+ true /* should_notify_initialized */);
+
+ // Verify OnAppTypeInitialized is not called when the mojom Apps are
+ // initialized again.
+ EXPECT_EQ(1, observer1.initialized_app_type_count());
+ EXPECT_EQ(0, observer1.app_count_at_initialization());
+ EXPECT_EQ(1u, cache.InitializedAppTypes().size());
+
+ std::vector<apps::mojom::AppPtr> mojom_deltas3;
+ cache.OnApps(std::move(mojom_deltas3), apps::mojom::AppType::kRemote,
+ true /* should_notify_initialized */);
+
+ // Verify OnAppTypeInitialized is not called when the mojom Apps are
+ // initialized.
+ EXPECT_EQ(1u, observer1.app_types().size());
+ EXPECT_EQ(1u, cache.InitializedAppTypes().size());
+
+ std::vector<AppPtr> deltas3;
+ cache.OnApps(std::move(deltas3), AppType::kRemote,
+ true /* should_notify_initialized */);
+
+ // Verify OnAppTypeInitialized is called when both the mojom and non mojom
+ // Apps are initialized.
+ EXPECT_EQ(2u, observer1.app_types().size());
+ EXPECT_TRUE(base::Contains(observer1.app_types(), AppType::kRemote));
+ EXPECT_EQ(2, observer1.initialized_app_type_count());
+ EXPECT_EQ(2u, cache.InitializedAppTypes().size());
+ EXPECT_TRUE(cache.IsAppTypeInitialized(AppType::kRemote));
+
+ // Verify the new observers should not have OnAppTypeInitialized called.
+ InitializedObserver observer2(&cache);
+ EXPECT_TRUE(observer2.app_types().empty());
+ EXPECT_EQ(0, observer2.initialized_app_type_count());
+ EXPECT_EQ(0, observer2.app_count_at_initialization());
+}
+
} // namespace apps
diff --git a/chromium/components/services/app_service/public/cpp/app_types.cc b/chromium/components/services/app_service/public/cpp/app_types.cc
index 4a6d3ed29c9..abacfc3c8a1 100644
--- a/chromium/components/services/app_service/public/cpp/app_types.cc
+++ b/chromium/components/services/app_service/public/cpp/app_types.cc
@@ -11,8 +11,8 @@ App::App(AppType app_type, const std::string& app_id)
App::~App() = default;
-std::unique_ptr<App> App::Clone() const {
- std::unique_ptr<App> app = std::make_unique<App>(app_type, app_id);
+AppPtr App::Clone() const {
+ auto app = std::make_unique<App>(app_type, app_id);
app->readiness = readiness;
app->name = name;
@@ -20,11 +20,39 @@ std::unique_ptr<App> App::Clone() const {
app->publisher_id = publisher_id;
app->description = description;
app->version = version;
+ app->additional_search_terms = additional_search_terms;
if (icon_key.has_value()) {
app->icon_key = apps::IconKey(icon_key->timeline, icon_key->resource_id,
icon_key->icon_effects);
}
+
+ app->last_launch_time = last_launch_time;
+ app->install_time = install_time;
+ app->permissions = ClonePermissions(permissions);
+ app->install_reason = install_reason;
+ app->install_source = install_source;
+ app->policy_id = policy_id;
+ app->is_platform_app = is_platform_app;
+ app->recommendable = recommendable;
+ app->searchable = searchable;
+ app->show_in_launcher = show_in_launcher;
+ app->show_in_shelf = show_in_shelf;
+ app->show_in_search = show_in_search;
+ app->show_in_management = show_in_management;
+ app->handles_intents = handles_intents;
+ app->allow_uninstall = allow_uninstall;
+ app->has_badge = has_badge;
+ app->paused = paused;
+ app->intent_filters = CloneIntentFilters(intent_filters);
+ app->resize_locked = resize_locked;
+ app->window_mode = window_mode;
+
+ if (run_on_os_login.has_value()) {
+ app->run_on_os_login = apps::RunOnOsLogin(run_on_os_login->login_mode,
+ run_on_os_login->is_managed);
+ }
+
return app;
}
@@ -61,6 +89,39 @@ AppType ConvertMojomAppTypToAppType(apps::mojom::AppType mojom_app_type) {
}
}
+mojom::AppType ConvertAppTypeToMojomAppType(AppType app_type) {
+ switch (app_type) {
+ case AppType::kUnknown:
+ return apps::mojom::AppType::kUnknown;
+ case AppType::kArc:
+ return apps::mojom::AppType::kArc;
+ case AppType::kBuiltIn:
+ return apps::mojom::AppType::kBuiltIn;
+ case AppType::kCrostini:
+ return apps::mojom::AppType::kCrostini;
+ case AppType::kChromeApp:
+ return apps::mojom::AppType::kChromeApp;
+ case AppType::kWeb:
+ return apps::mojom::AppType::kWeb;
+ case AppType::kMacOs:
+ return apps::mojom::AppType::kMacOs;
+ case AppType::kPluginVm:
+ return apps::mojom::AppType::kPluginVm;
+ case AppType::kStandaloneBrowser:
+ return apps::mojom::AppType::kStandaloneBrowser;
+ case AppType::kRemote:
+ return apps::mojom::AppType::kRemote;
+ case AppType::kBorealis:
+ return apps::mojom::AppType::kBorealis;
+ case AppType::kSystemWeb:
+ return apps::mojom::AppType::kSystemWeb;
+ case AppType::kStandaloneBrowserChromeApp:
+ return apps::mojom::AppType::kStandaloneBrowserChromeApp;
+ case AppType::kExtension:
+ return apps::mojom::AppType::kExtension;
+ }
+}
+
Readiness ConvertMojomReadinessToReadiness(
apps::mojom::Readiness mojom_readiness) {
switch (mojom_readiness) {
@@ -85,10 +146,157 @@ Readiness ConvertMojomReadinessToReadiness(
}
}
-std::unique_ptr<App> ConvertMojomAppToApp(
- const apps::mojom::AppPtr& mojom_app) {
+apps::mojom::Readiness ConvertReadinessToMojomReadiness(Readiness readiness) {
+ switch (readiness) {
+ case Readiness::kUnknown:
+ return apps::mojom::Readiness::kUnknown;
+ case Readiness::kReady:
+ return apps::mojom::Readiness::kReady;
+ case Readiness::kDisabledByBlocklist:
+ return apps::mojom::Readiness::kDisabledByBlocklist;
+ case Readiness::kDisabledByPolicy:
+ return apps::mojom::Readiness::kDisabledByPolicy;
+ case Readiness::kDisabledByUser:
+ return apps::mojom::Readiness::kDisabledByUser;
+ case Readiness::kTerminated:
+ return apps::mojom::Readiness::kTerminated;
+ case Readiness::kUninstalledByUser:
+ return apps::mojom::Readiness::kUninstalledByUser;
+ case Readiness::kRemoved:
+ return apps::mojom::Readiness::kRemoved;
+ case Readiness::kUninstalledByMigration:
+ return apps::mojom::Readiness::kUninstalledByMigration;
+ }
+}
+
+InstallReason ConvertMojomInstallReasonToInstallReason(
+ apps::mojom::InstallReason mojom_install_reason) {
+ switch (mojom_install_reason) {
+ case apps::mojom::InstallReason::kUnknown:
+ return InstallReason::kUnknown;
+ case apps::mojom::InstallReason::kSystem:
+ return InstallReason::kSystem;
+ case apps::mojom::InstallReason::kPolicy:
+ return InstallReason::kPolicy;
+ case apps::mojom::InstallReason::kOem:
+ return InstallReason::kOem;
+ case apps::mojom::InstallReason::kDefault:
+ return InstallReason::kDefault;
+ case apps::mojom::InstallReason::kSync:
+ return InstallReason::kSync;
+ case apps::mojom::InstallReason::kUser:
+ return InstallReason::kUser;
+ case apps::mojom::InstallReason::kSubApp:
+ return InstallReason::kSubApp;
+ }
+}
+
+apps::mojom::InstallReason ConvertInstallReasonToMojomInstallReason(
+ InstallReason install_reason) {
+ switch (install_reason) {
+ case InstallReason::kUnknown:
+ return apps::mojom::InstallReason::kUnknown;
+ case InstallReason::kSystem:
+ return apps::mojom::InstallReason::kSystem;
+ case InstallReason::kPolicy:
+ return apps::mojom::InstallReason::kPolicy;
+ case InstallReason::kOem:
+ return apps::mojom::InstallReason::kOem;
+ case InstallReason::kDefault:
+ return apps::mojom::InstallReason::kDefault;
+ case InstallReason::kSync:
+ return apps::mojom::InstallReason::kSync;
+ case InstallReason::kUser:
+ return apps::mojom::InstallReason::kUser;
+ case InstallReason::kSubApp:
+ return apps::mojom::InstallReason::kSubApp;
+ }
+}
+
+InstallSource ConvertMojomInstallSourceToInstallSource(
+ apps::mojom::InstallSource mojom_install_source) {
+ switch (mojom_install_source) {
+ case apps::mojom::InstallSource::kUnknown:
+ return InstallSource::kUnknown;
+ case apps::mojom::InstallSource::kSystem:
+ return InstallSource::kSystem;
+ case apps::mojom::InstallSource::kSync:
+ return InstallSource::kSync;
+ case apps::mojom::InstallSource::kPlayStore:
+ return InstallSource::kPlayStore;
+ case apps::mojom::InstallSource::kChromeWebStore:
+ return InstallSource::kChromeWebStore;
+ case apps::mojom::InstallSource::kBrowser:
+ return InstallSource::kBrowser;
+ }
+}
+
+apps::mojom::InstallSource ConvertInstallSourceToMojomInstallSource(
+ InstallSource install_source) {
+ switch (install_source) {
+ case InstallSource::kUnknown:
+ return apps::mojom::InstallSource::kUnknown;
+ case InstallSource::kSystem:
+ return apps::mojom::InstallSource::kSystem;
+ case InstallSource::kSync:
+ return apps::mojom::InstallSource::kSync;
+ case InstallSource::kPlayStore:
+ return apps::mojom::InstallSource::kPlayStore;
+ case InstallSource::kChromeWebStore:
+ return apps::mojom::InstallSource::kChromeWebStore;
+ case InstallSource::kBrowser:
+ return apps::mojom::InstallSource::kBrowser;
+ }
+}
+
+WindowMode ConvertMojomWindowModeToWindowMode(
+ apps::mojom::WindowMode mojom_window_mode) {
+ switch (mojom_window_mode) {
+ case apps::mojom::WindowMode::kUnknown:
+ return WindowMode::kUnknown;
+ case apps::mojom::WindowMode::kWindow:
+ return WindowMode::kWindow;
+ case apps::mojom::WindowMode::kBrowser:
+ return WindowMode::kBrowser;
+ case apps::mojom::WindowMode::kTabbedWindow:
+ return WindowMode::kTabbedWindow;
+ }
+}
+
+apps::mojom::WindowMode ConvertWindowModeToMojomWindowMode(
+ WindowMode window_mode) {
+ switch (window_mode) {
+ case WindowMode::kUnknown:
+ return apps::mojom::WindowMode::kUnknown;
+ case WindowMode::kWindow:
+ return apps::mojom::WindowMode::kWindow;
+ case WindowMode::kBrowser:
+ return apps::mojom::WindowMode::kBrowser;
+ case WindowMode::kTabbedWindow:
+ return apps::mojom::WindowMode::kTabbedWindow;
+ }
+}
+
+absl::optional<bool> GetOptionalBool(
+ const apps::mojom::OptionalBool& mojom_optional_bool) {
+ absl::optional<bool> optional_bool;
+ if (mojom_optional_bool != apps::mojom::OptionalBool::kUnknown) {
+ optional_bool = mojom_optional_bool == apps::mojom::OptionalBool::kTrue;
+ }
+ return optional_bool;
+}
+
+apps::mojom::OptionalBool GetMojomOptionalBool(
+ const absl::optional<bool>& optional_bool) {
+ return optional_bool.has_value()
+ ? (optional_bool.value() ? apps::mojom::OptionalBool::kTrue
+ : apps::mojom::OptionalBool::kFalse)
+ : apps::mojom::OptionalBool::kUnknown;
+}
+
+AppPtr ConvertMojomAppToApp(const apps::mojom::AppPtr& mojom_app) {
DCHECK(mojom_app);
- std::unique_ptr<App> app = std::make_unique<App>(
+ auto app = std::make_unique<App>(
ConvertMojomAppTypToAppType(mojom_app->app_type), mojom_app->app_id);
app->readiness = ConvertMojomReadinessToReadiness(mojom_app->readiness);
@@ -97,13 +305,121 @@ std::unique_ptr<App> ConvertMojomAppToApp(
app->publisher_id = mojom_app->publisher_id;
app->description = mojom_app->description;
app->version = mojom_app->version;
+ app->additional_search_terms = mojom_app->additional_search_terms;
if (mojom_app->icon_key) {
app->icon_key = apps::IconKey(mojom_app->icon_key->timeline,
mojom_app->icon_key->resource_id,
mojom_app->icon_key->icon_effects);
}
+
+ app->last_launch_time = mojom_app->last_launch_time;
+ app->install_time = mojom_app->install_time;
+
+ for (const auto& mojom_permission : mojom_app->permissions) {
+ auto permission = ConvertMojomPermissionToPermission(mojom_permission);
+ if (permission) {
+ app->permissions.push_back(std::move(permission));
+ }
+ }
+
+ app->install_reason =
+ ConvertMojomInstallReasonToInstallReason(mojom_app->install_reason);
+ app->install_source =
+ ConvertMojomInstallSourceToInstallSource(mojom_app->install_source);
+
+ app->policy_id = mojom_app->policy_id;
+
+ app->is_platform_app = GetOptionalBool(mojom_app->is_platform_app);
+ app->recommendable = GetOptionalBool(mojom_app->recommendable);
+ app->searchable = GetOptionalBool(mojom_app->searchable);
+ app->show_in_launcher = GetOptionalBool(mojom_app->show_in_launcher);
+ app->show_in_shelf = GetOptionalBool(mojom_app->show_in_shelf);
+ app->show_in_search = GetOptionalBool(mojom_app->show_in_search);
+ app->show_in_management = GetOptionalBool(mojom_app->show_in_management);
+ app->handles_intents = GetOptionalBool(mojom_app->handles_intents);
+ app->allow_uninstall = GetOptionalBool(mojom_app->allow_uninstall);
+ app->has_badge = GetOptionalBool(mojom_app->has_badge);
+ app->paused = GetOptionalBool(mojom_app->paused);
+
+ for (const auto& mojom_intent_filter : mojom_app->intent_filters) {
+ auto intent_filter =
+ ConvertMojomIntentFilterToIntentFilter(mojom_intent_filter);
+ if (intent_filter) {
+ app->intent_filters.push_back(std::move(intent_filter));
+ }
+ }
+
+ app->resize_locked = GetOptionalBool(mojom_app->resize_locked);
+ app->window_mode = ConvertMojomWindowModeToWindowMode(mojom_app->window_mode);
+ if (mojom_app->run_on_os_login) {
+ app->run_on_os_login =
+ apps::RunOnOsLogin(ConvertMojomRunOnOsLoginModeToRunOnOsLoginMode(
+ mojom_app->run_on_os_login->login_mode),
+ mojom_app->run_on_os_login->is_managed);
+ }
+
return app;
}
+apps::mojom::AppPtr ConvertAppToMojomApp(const AppPtr& app) {
+ auto mojom_app = apps::mojom::App::New();
+ mojom_app->app_type = ConvertAppTypeToMojomAppType(app->app_type);
+ mojom_app->app_id = app->app_id;
+ mojom_app->readiness = ConvertReadinessToMojomReadiness(app->readiness);
+ mojom_app->name = app->name;
+ mojom_app->short_name = app->short_name;
+ mojom_app->publisher_id = app->publisher_id;
+ mojom_app->description = app->description;
+ mojom_app->version = app->version;
+ mojom_app->additional_search_terms = app->additional_search_terms;
+
+ if (app->icon_key.has_value()) {
+ mojom_app->icon_key = ConvertIconKeyToMojomIconKey(app->icon_key.value());
+ }
+
+ mojom_app->last_launch_time = app->last_launch_time;
+ mojom_app->install_time = app->install_time;
+
+ for (const auto& permission : app->permissions) {
+ if (permission) {
+ mojom_app->permissions.push_back(
+ ConvertPermissionToMojomPermission(permission));
+ }
+ }
+
+ mojom_app->install_reason =
+ ConvertInstallReasonToMojomInstallReason(app->install_reason);
+ mojom_app->install_source =
+ ConvertInstallSourceToMojomInstallSource(app->install_source);
+ mojom_app->policy_id = app->policy_id;
+ mojom_app->is_platform_app = GetMojomOptionalBool(app->is_platform_app);
+ mojom_app->recommendable = GetMojomOptionalBool(app->recommendable);
+ mojom_app->searchable = GetMojomOptionalBool(app->searchable);
+ mojom_app->show_in_launcher = GetMojomOptionalBool(app->show_in_launcher);
+ mojom_app->show_in_shelf = GetMojomOptionalBool(app->show_in_shelf);
+ mojom_app->show_in_search = GetMojomOptionalBool(app->show_in_search);
+ mojom_app->show_in_management = GetMojomOptionalBool(app->show_in_management);
+ mojom_app->handles_intents = GetMojomOptionalBool(app->handles_intents);
+ mojom_app->allow_uninstall = GetMojomOptionalBool(app->allow_uninstall);
+ mojom_app->has_badge = GetMojomOptionalBool(app->has_badge);
+ mojom_app->paused = GetMojomOptionalBool(app->paused);
+
+ for (const auto& intent_filter : app->intent_filters) {
+ if (intent_filter) {
+ mojom_app->intent_filters.push_back(
+ ConvertIntentFilterToMojomIntentFilter(intent_filter));
+ }
+ }
+
+ mojom_app->resize_locked = GetMojomOptionalBool(app->resize_locked);
+ mojom_app->window_mode = ConvertWindowModeToMojomWindowMode(app->window_mode);
+
+ if (app->run_on_os_login.has_value()) {
+ mojom_app->run_on_os_login =
+ ConvertRunOnOsLoginToMojomRunOnOsLogin(app->run_on_os_login.value());
+ }
+ return mojom_app;
+}
+
} // namespace apps
diff --git a/chromium/components/services/app_service/public/cpp/app_types.h b/chromium/components/services/app_service/public/cpp/app_types.h
index d22de50352a..0e7fdc2ac43 100644
--- a/chromium/components/services/app_service/public/cpp/app_types.h
+++ b/chromium/components/services/app_service/public/cpp/app_types.h
@@ -7,8 +7,14 @@
#include <string>
#include <utility>
+#include <vector>
+#include "base/component_export.h"
+#include "base/time/time.h"
#include "components/services/app_service/public/cpp/icon_types.h"
+#include "components/services/app_service/public/cpp/intent_filter.h"
+#include "components/services/app_service/public/cpp/permission.h"
+#include "components/services/app_service/public/cpp/run_on_os_login_types.h"
#include "components/services/app_service/public/mojom/types.mojom.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
@@ -54,6 +60,55 @@ enum class Readiness {
kMaxValue = kUninstalledByMigration,
};
+// How the app was installed.
+// This should be kept in sync with histograms.xml, and InstallReason in
+// enums.xml.
+// Note the enumeration is used in UMA histogram so entries should not be
+// re-ordered or removed. New entries should be added at the bottom.
+enum class InstallReason {
+ kUnknown = 0,
+ kSystem, // Installed with the system and is considered a part of the OS.
+ kPolicy, // Installed by policy.
+ kOem, // Installed by an OEM.
+ kDefault, // Preinstalled by default, but is not considered a system app.
+ kSync, // Installed by sync.
+ kUser, // Installed by user action.
+ kSubApp, // Installed by the SubApp API call.
+
+ // Add any new values above this one, and update kMaxValue to the highest
+ // enumerator value.
+ kMaxValue = kSubApp,
+};
+
+// Where the app was installed from.
+// This should be kept in sync with histograms.xml, and InstallSource in
+// enums.xml.
+// Note the enumeration is used in UMA histogram so entries should not be
+// re-ordered or removed. New entries should be added at the bottom.
+enum class InstallSource {
+ kUnknown = 0,
+ kSystem, // Installed as part of Chrome OS.
+ kSync, // Installed from sync.
+ kPlayStore, // Installed from Play store.
+ kChromeWebStore, // Installed from Chrome web store.
+ kBrowser, // Installed from browser.
+
+ // Add any new values above this one, and update kMaxValue to the highest
+ // enumerator value.
+ kMaxValue = kBrowser,
+};
+
+// The window mode that each app will open in.
+enum class WindowMode {
+ kUnknown = 0,
+ // Opens in a standalone window
+ kWindow,
+ // Opens in the default web browser
+ kBrowser,
+ // Opens in a tabbed app window
+ kTabbedWindow,
+};
+
struct COMPONENT_EXPORT(APP_TYPES) App {
App(AppType app_type, const std::string& app_id);
@@ -78,26 +133,130 @@ struct COMPONENT_EXPORT(APP_TYPES) App {
absl::optional<std::string> description;
absl::optional<std::string> version;
+ std::vector<std::string> additional_search_terms;
absl::optional<IconKey> icon_key;
- // TODO(crbug.com/1253250): Add other App struct fields.
+ absl::optional<base::Time> last_launch_time;
+ absl::optional<base::Time> install_time;
+
+ // This vector must be treated atomically, if there is a permission
+ // change, the publisher must send through the entire list of permissions.
+ // Should contain no duplicate IDs.
+ // If empty during updates, Subscriber can assume no changes.
+ // There is no guarantee that this is sorted by any criteria.
+ Permissions permissions;
+
+ // Whether the app was installed by sync, policy or as a default app.
+ InstallReason install_reason = InstallReason::kUnknown;
+
+ // Where the app was installed from, e.g. from Play Store, from Chrome Web
+ // Store, etc.
+ InstallSource install_source = InstallSource::kUnknown;
+
+ // An optional ID used for policy to identify the app.
+ // For web apps, it contains the install URL.
+ absl::optional<std::string> policy_id;
+
+ // Whether the app is an extensions::Extensions where is_platform_app()
+ // returns true.
+ absl::optional<bool> is_platform_app;
+
+ absl::optional<bool> recommendable;
+ absl::optional<bool> searchable;
+ absl::optional<bool> show_in_launcher;
+ absl::optional<bool> show_in_shelf;
+ absl::optional<bool> show_in_search;
+ absl::optional<bool> show_in_management;
+
+ // True if the app is able to handle intents and should be shown in intent
+ // surfaces.
+ absl::optional<bool> handles_intents;
+
+ // Whether the app publisher allows the app to be uninstalled.
+ absl::optional<bool> allow_uninstall;
+
+ // Whether the app icon should add the notification badging.
+ absl::optional<bool> has_badge;
+
+ // Paused apps cannot be launched, and any running apps that become paused
+ // will be stopped. This is independent of whether or not the app is ready to
+ // be launched (defined by the Readiness field).
+ absl::optional<bool> paused;
+
+ // This vector stores all the intent filters defined in this app. Each
+ // intent filter defines a matching criteria for whether an intent can
+ // be handled by this app. One app can have multiple intent filters.
+ IntentFilters intent_filters;
+
+ // Whether the app can be free resized. If this is true, various resizing
+ // operations will be restricted.
+ absl::optional<bool> resize_locked;
+
+ // Whether the app's display mode is in the browser or otherwise.
+ WindowMode window_mode = WindowMode::kUnknown;
+
+ // Whether the app runs on os login in a new window or not.
+ absl::optional<RunOnOsLogin> run_on_os_login;
// When adding new fields to the App type, the `Clone` function and the
// `AppUpdate` class should also be updated.
};
+using AppPtr = std::unique_ptr<App>;
+
// TODO(crbug.com/1253250): Remove these functions after migrating to non-mojo
// AppService.
COMPONENT_EXPORT(APP_TYPES)
AppType ConvertMojomAppTypToAppType(apps::mojom::AppType mojom_app_type);
COMPONENT_EXPORT(APP_TYPES)
+mojom::AppType ConvertAppTypeToMojomAppType(AppType mojom_app_type);
+
+COMPONENT_EXPORT(APP_TYPES)
Readiness ConvertMojomReadinessToReadiness(
apps::mojom::Readiness mojom_readiness);
COMPONENT_EXPORT(APP_TYPES)
-std::unique_ptr<App> ConvertMojomAppToApp(const apps::mojom::AppPtr& mojom_app);
+apps::mojom::Readiness ConvertReadinessToMojomReadiness(Readiness readiness);
+
+COMPONENT_EXPORT(APP_TYPES)
+InstallReason ConvertMojomInstallReasonToInstallReason(
+ apps::mojom::InstallReason mojom_install_reason);
+
+COMPONENT_EXPORT(APP_TYPES)
+apps::mojom::InstallReason ConvertInstallReasonToMojomInstallReason(
+ InstallReason install_reason);
+
+COMPONENT_EXPORT(APP_TYPES)
+InstallSource ConvertMojomInstallSourceToInstallSource(
+ apps::mojom::InstallSource mojom_install_source);
+
+COMPONENT_EXPORT(APP_TYPES)
+apps::mojom::InstallSource ConvertInstallSourceToMojomInstallSource(
+ InstallSource install_source);
+
+COMPONENT_EXPORT(APP_TYPES)
+WindowMode ConvertMojomWindowModeToWindowMode(
+ apps::mojom::WindowMode mojom_window_mode);
+
+COMPONENT_EXPORT(APP_TYPES)
+apps::mojom::WindowMode ConvertWindowModeToMojomWindowMode(
+ WindowMode mojom_window_mode);
+
+COMPONENT_EXPORT(APP_TYPES)
+absl::optional<bool> GetOptionalBool(
+ const apps::mojom::OptionalBool& mojom_optional_bool);
+
+COMPONENT_EXPORT(APP_TYPES)
+absl::optional<bool> GetMojomOptionalBool(
+ const apps::mojom::OptionalBool& mojom_optional_bool);
+
+COMPONENT_EXPORT(APP_TYPES)
+AppPtr ConvertMojomAppToApp(const apps::mojom::AppPtr& mojom_app);
+
+COMPONENT_EXPORT(APP_TYPES)
+apps::mojom::AppPtr ConvertAppToMojomApp(const AppPtr& app);
} // namespace apps
diff --git a/chromium/components/services/app_service/public/cpp/app_update.cc b/chromium/components/services/app_service/public/cpp/app_update.cc
index 71a696f89cf..2950815e592 100644
--- a/chromium/components/services/app_service/public/cpp/app_update.cc
+++ b/chromium/components/services/app_service/public/cpp/app_update.cc
@@ -9,6 +9,7 @@
#include "base/time/time.h"
#include "components/services/app_service/public/cpp/icon_types.h"
#include "components/services/app_service/public/cpp/intent_filter_util.h"
+#include "components/services/app_service/public/cpp/macros.h"
namespace {
@@ -39,6 +40,11 @@ absl::optional<apps::IconKey> CloneIconKey(const apps::IconKey& icon_key) {
icon_key.icon_effects);
}
+absl::optional<apps::RunOnOsLogin> CloneRunOnOsLogin(
+ const apps::RunOnOsLogin& login_data) {
+ return apps::RunOnOsLogin(login_data.login_mode, login_data.is_managed);
+}
+
} // namespace
namespace apps {
@@ -99,7 +105,7 @@ void AppUpdate::Merge(apps::mojom::App* state, const apps::mojom::App* delta) {
DCHECK(state->permissions.empty() ||
(delta->permissions.size() == state->permissions.size()));
state->permissions.clear();
- ClonePermissions(delta->permissions, &state->permissions);
+ ::ClonePermissions(delta->permissions, &state->permissions);
}
if (delta->install_reason != apps::mojom::InstallReason::kUnknown) {
state->install_reason = delta->install_reason;
@@ -145,7 +151,7 @@ void AppUpdate::Merge(apps::mojom::App* state, const apps::mojom::App* delta) {
}
if (!delta->intent_filters.empty()) {
state->intent_filters.clear();
- CloneIntentFilters(delta->intent_filters, &state->intent_filters);
+ ::CloneIntentFilters(delta->intent_filters, &state->intent_filters);
}
if (delta->resize_locked != apps::mojom::OptionalBool::kUnknown) {
state->resize_locked = delta->resize_locked;
@@ -153,6 +159,9 @@ void AppUpdate::Merge(apps::mojom::App* state, const apps::mojom::App* delta) {
if (delta->window_mode != apps::mojom::WindowMode::kUnknown) {
state->window_mode = delta->window_mode;
}
+ if (!delta->run_on_os_login.is_null()) {
+ state->run_on_os_login = delta->run_on_os_login.Clone();
+ }
// When adding new fields to the App Mojo type, this function should also be
// updated.
@@ -175,28 +184,59 @@ void AppUpdate::Merge(App* state, const App* delta) {
DCHECK_NE(state->readiness, Readiness::kRemoved);
DCHECK_NE(delta->readiness, Readiness::kRemoved);
- if (delta->readiness != apps::Readiness::kUnknown) {
- state->readiness = delta->readiness;
- }
- if (delta->name.has_value()) {
- state->name = delta->name;
- }
- if (delta->short_name.has_value()) {
- state->short_name = delta->short_name;
- }
- if (delta->publisher_id.has_value()) {
- state->publisher_id = delta->publisher_id;
- }
- if (delta->description.has_value()) {
- state->description = delta->description;
- }
- if (delta->version.has_value()) {
- state->version = delta->version;
+ SET_ENUM_VALUE(readiness, apps::Readiness::kUnknown);
+ SET_OPTIONAL_VALUE(name)
+ SET_OPTIONAL_VALUE(short_name)
+ SET_OPTIONAL_VALUE(publisher_id)
+ SET_OPTIONAL_VALUE(description)
+ SET_OPTIONAL_VALUE(version)
+
+ if (!delta->additional_search_terms.empty()) {
+ state->additional_search_terms.clear();
+ state->additional_search_terms = delta->additional_search_terms;
}
+
if (delta->icon_key.has_value()) {
state->icon_key = CloneIconKey(delta->icon_key.value());
}
+ SET_OPTIONAL_VALUE(last_launch_time);
+ SET_OPTIONAL_VALUE(install_time);
+
+ if (!delta->permissions.empty()) {
+ DCHECK(state->permissions.empty() ||
+ (delta->permissions.size() == state->permissions.size()));
+ state->permissions.clear();
+ state->permissions = ClonePermissions(delta->permissions);
+ }
+
+ SET_ENUM_VALUE(install_reason, InstallReason::kUnknown);
+ SET_ENUM_VALUE(install_source, InstallSource::kUnknown);
+ SET_OPTIONAL_VALUE(policy_id);
+ SET_OPTIONAL_VALUE(is_platform_app);
+ SET_OPTIONAL_VALUE(recommendable);
+ SET_OPTIONAL_VALUE(searchable);
+ SET_OPTIONAL_VALUE(show_in_launcher);
+ SET_OPTIONAL_VALUE(show_in_shelf);
+ SET_OPTIONAL_VALUE(show_in_search);
+ SET_OPTIONAL_VALUE(show_in_management);
+ SET_OPTIONAL_VALUE(handles_intents);
+ SET_OPTIONAL_VALUE(allow_uninstall);
+ SET_OPTIONAL_VALUE(has_badge);
+ SET_OPTIONAL_VALUE(paused);
+
+ if (!delta->intent_filters.empty()) {
+ state->intent_filters.clear();
+ state->intent_filters = CloneIntentFilters(delta->intent_filters);
+ }
+
+ SET_OPTIONAL_VALUE(resize_locked)
+ SET_ENUM_VALUE(window_mode, WindowMode::kUnknown)
+
+ if (delta->run_on_os_login.has_value()) {
+ state->run_on_os_login = CloneRunOnOsLogin(delta->run_on_os_login.value());
+ }
+
// When adding new fields to the App type, this function should also be
// updated.
}
@@ -260,14 +300,7 @@ apps::mojom::Readiness AppUpdate::PriorReadiness() const {
}
apps::Readiness AppUpdate::GetReadiness() const {
- if (delta_ && (delta_->readiness != apps::Readiness::kUnknown)) {
- return delta_->readiness;
- }
- if (state_) {
- return state_->readiness;
- }
- return apps::Readiness::kUnknown;
-}
+ GET_VALUE_WITH_DEFAULT_VALUE(readiness, apps::Readiness::kUnknown)}
apps::Readiness AppUpdate::GetPriorReadiness() const {
return state_ ? state_->readiness : apps::Readiness::kUnknown;
@@ -291,13 +324,7 @@ const std::string& AppUpdate::Name() const {
}
const std::string& AppUpdate::GetName() const {
- if (delta_ && delta_->name.has_value()) {
- return delta_->name.value();
- }
- if (state_ && state_->name.has_value()) {
- return state_->name.value();
- }
- return base::EmptyString();
+ GET_VALUE_WITH_FALLBACK(name, base::EmptyString())
}
bool AppUpdate::NameChanged() const {
@@ -316,13 +343,7 @@ const std::string& AppUpdate::ShortName() const {
}
const std::string& AppUpdate::GetShortName() const {
- if (delta_ && delta_->short_name.has_value()) {
- return delta_->short_name.value();
- }
- if (state_ && state_->short_name.has_value()) {
- return state_->short_name.value();
- }
- return base::EmptyString();
+ GET_VALUE_WITH_FALLBACK(short_name, base::EmptyString())
}
bool AppUpdate::ShortNameChanged() const {
@@ -342,13 +363,7 @@ const std::string& AppUpdate::PublisherId() const {
}
const std::string& AppUpdate::GetPublisherId() const {
- if (delta_ && delta_->publisher_id.has_value()) {
- return delta_->publisher_id.value();
- }
- if (state_ && state_->publisher_id.has_value()) {
- return state_->publisher_id.value();
- }
- return base::EmptyString();
+ GET_VALUE_WITH_FALLBACK(publisher_id, base::EmptyString())
}
bool AppUpdate::PublisherIdChanged() const {
@@ -368,13 +383,7 @@ const std::string& AppUpdate::Description() const {
}
const std::string& AppUpdate::GetDescription() const {
- if (delta_ && delta_->description.has_value()) {
- return delta_->description.value();
- }
- if (state_ && state_->description.has_value()) {
- return state_->description.value();
- }
- return base::EmptyString();
+ GET_VALUE_WITH_FALLBACK(description, base::EmptyString())
}
bool AppUpdate::DescriptionChanged() const {
@@ -394,13 +403,7 @@ const std::string& AppUpdate::Version() const {
}
const std::string& AppUpdate::GetVersion() const {
- if (delta_ && delta_->version.has_value()) {
- return delta_->version.value();
- }
- if (state_ && state_->version.has_value()) {
- return state_->version.value();
- }
- return base::EmptyString();
+ GET_VALUE_WITH_FALLBACK(version, base::EmptyString())
}
bool AppUpdate::VersionChanged() const {
@@ -422,6 +425,11 @@ std::vector<std::string> AppUpdate::AdditionalSearchTerms() const {
return additional_search_terms;
}
+std::vector<std::string> AppUpdate::GetAdditionalSearchTerms() const {
+ GET_VALUE_WITH_CHECK_AND_DEFAULT_RETURN(additional_search_terms, empty,
+ std::vector<std::string>{})
+}
+
bool AppUpdate::AdditionalSearchTermsChanged() const {
return mojom_delta_ && !mojom_delta_->additional_search_terms.empty() &&
(!mojom_state_ || (mojom_delta_->additional_search_terms !=
@@ -464,6 +472,10 @@ base::Time AppUpdate::LastLaunchTime() const {
return base::Time();
}
+base::Time AppUpdate::GetLastLaunchTime() const {
+ GET_VALUE_WITH_FALLBACK(last_launch_time, base::Time())
+}
+
bool AppUpdate::LastLaunchTimeChanged() const {
return mojom_delta_ && mojom_delta_->last_launch_time.has_value() &&
(!mojom_state_ ||
@@ -480,6 +492,10 @@ base::Time AppUpdate::InstallTime() const {
return base::Time();
}
+base::Time AppUpdate::GetInstallTime() const {
+ GET_VALUE_WITH_FALLBACK(install_time, base::Time())
+}
+
bool AppUpdate::InstallTimeChanged() const {
return mojom_delta_ && mojom_delta_->install_time.has_value() &&
(!mojom_state_ ||
@@ -490,9 +506,21 @@ std::vector<apps::mojom::PermissionPtr> AppUpdate::Permissions() const {
std::vector<apps::mojom::PermissionPtr> permissions;
if (mojom_delta_ && !mojom_delta_->permissions.empty()) {
- ClonePermissions(mojom_delta_->permissions, &permissions);
+ ::ClonePermissions(mojom_delta_->permissions, &permissions);
} else if (mojom_state_ && !mojom_state_->permissions.empty()) {
- ClonePermissions(mojom_state_->permissions, &permissions);
+ ::ClonePermissions(mojom_state_->permissions, &permissions);
+ }
+
+ return permissions;
+}
+
+apps::Permissions AppUpdate::GetPermissions() const {
+ apps::Permissions permissions;
+
+ if (delta_ && !delta_->permissions.empty()) {
+ permissions = ClonePermissions(delta_->permissions);
+ } else if (state_ && !state_->permissions.empty()) {
+ permissions = ClonePermissions(state_->permissions);
}
return permissions;
@@ -515,6 +543,10 @@ apps::mojom::InstallReason AppUpdate::InstallReason() const {
return apps::mojom::InstallReason::kUnknown;
}
+apps::InstallReason AppUpdate::GetInstallReason() const {
+ GET_VALUE_WITH_DEFAULT_VALUE(install_reason, InstallReason::kUnknown)
+}
+
bool AppUpdate::InstallReasonChanged() const {
return mojom_delta_ &&
(mojom_delta_->install_reason !=
@@ -534,6 +566,10 @@ apps::mojom::InstallSource AppUpdate::InstallSource() const {
return apps::mojom::InstallSource::kUnknown;
}
+apps::InstallSource AppUpdate::GetInstallSource() const {
+ GET_VALUE_WITH_DEFAULT_VALUE(install_source, InstallSource::kUnknown)
+}
+
bool AppUpdate::InstallSourceChanged() const {
return mojom_delta_ &&
(mojom_delta_->install_source !=
@@ -552,6 +588,10 @@ const std::string& AppUpdate::PolicyId() const {
return base::EmptyString();
}
+const std::string& AppUpdate::GetPolicyId() const {
+ GET_VALUE_WITH_FALLBACK(policy_id, base::EmptyString())
+}
+
bool AppUpdate::PolicyIdChanged() const {
return mojom_delta_ && mojom_delta_->policy_id.has_value() &&
(!mojom_state_ ||
@@ -583,6 +623,10 @@ apps::mojom::OptionalBool AppUpdate::IsPlatformApp() const {
return apps::mojom::OptionalBool::kUnknown;
}
+absl::optional<bool> AppUpdate::GetIsPlatformApp() const {
+ GET_VALUE_WITH_FALLBACK(is_platform_app, absl::nullopt)
+}
+
bool AppUpdate::IsPlatformAppChanged() const {
return mojom_delta_ &&
(mojom_delta_->is_platform_app !=
@@ -602,6 +646,10 @@ apps::mojom::OptionalBool AppUpdate::Recommendable() const {
return apps::mojom::OptionalBool::kUnknown;
}
+absl::optional<bool> AppUpdate::GetRecommendable() const {
+ GET_VALUE_WITH_FALLBACK(recommendable, absl::nullopt)
+}
+
bool AppUpdate::RecommendableChanged() const {
return mojom_delta_ &&
(mojom_delta_->recommendable != apps::mojom::OptionalBool::kUnknown) &&
@@ -620,6 +668,10 @@ apps::mojom::OptionalBool AppUpdate::Searchable() const {
return apps::mojom::OptionalBool::kUnknown;
}
+absl::optional<bool> AppUpdate::GetSearchable() const {
+ GET_VALUE_WITH_FALLBACK(searchable, absl::nullopt)
+}
+
bool AppUpdate::SearchableChanged() const {
return mojom_delta_ &&
(mojom_delta_->searchable != apps::mojom::OptionalBool::kUnknown) &&
@@ -638,6 +690,10 @@ apps::mojom::OptionalBool AppUpdate::ShowInLauncher() const {
return apps::mojom::OptionalBool::kUnknown;
}
+absl::optional<bool> AppUpdate::GetShowInLauncher() const {
+ GET_VALUE_WITH_FALLBACK(show_in_launcher, absl::nullopt)
+}
+
bool AppUpdate::ShowInLauncherChanged() const {
return mojom_delta_ &&
(mojom_delta_->show_in_launcher !=
@@ -657,6 +713,10 @@ apps::mojom::OptionalBool AppUpdate::ShowInShelf() const {
return apps::mojom::OptionalBool::kUnknown;
}
+absl::optional<bool> AppUpdate::GetShowInShelf() const {
+ GET_VALUE_WITH_FALLBACK(show_in_shelf, absl::nullopt)
+}
+
bool AppUpdate::ShowInShelfChanged() const {
return mojom_delta_ &&
(mojom_delta_->show_in_shelf != apps::mojom::OptionalBool::kUnknown) &&
@@ -675,6 +735,10 @@ apps::mojom::OptionalBool AppUpdate::ShowInSearch() const {
return apps::mojom::OptionalBool::kUnknown;
}
+absl::optional<bool> AppUpdate::GetShowInSearch() const {
+ GET_VALUE_WITH_FALLBACK(show_in_search, absl::nullopt)
+}
+
bool AppUpdate::ShowInSearchChanged() const {
return mojom_delta_ &&
(mojom_delta_->show_in_search !=
@@ -694,6 +758,10 @@ apps::mojom::OptionalBool AppUpdate::ShowInManagement() const {
return apps::mojom::OptionalBool::kUnknown;
}
+absl::optional<bool> AppUpdate::GetShowInManagement() const {
+ GET_VALUE_WITH_FALLBACK(show_in_management, absl::nullopt)
+}
+
bool AppUpdate::ShowInManagementChanged() const {
return mojom_delta_ &&
(mojom_delta_->show_in_management !=
@@ -713,6 +781,10 @@ apps::mojom::OptionalBool AppUpdate::HandlesIntents() const {
return apps::mojom::OptionalBool::kUnknown;
}
+absl::optional<bool> AppUpdate::GetHandlesIntents() const {
+ GET_VALUE_WITH_FALLBACK(handles_intents, absl::nullopt)
+}
+
bool AppUpdate::HandlesIntentsChanged() const {
return mojom_delta_ &&
(mojom_delta_->handles_intents !=
@@ -732,6 +804,10 @@ apps::mojom::OptionalBool AppUpdate::AllowUninstall() const {
return apps::mojom::OptionalBool::kUnknown;
}
+absl::optional<bool> AppUpdate::GetAllowUninstall() const {
+ GET_VALUE_WITH_FALLBACK(allow_uninstall, absl::nullopt)
+}
+
bool AppUpdate::AllowUninstallChanged() const {
return mojom_delta_ &&
(mojom_delta_->allow_uninstall !=
@@ -751,6 +827,10 @@ apps::mojom::OptionalBool AppUpdate::HasBadge() const {
return apps::mojom::OptionalBool::kUnknown;
}
+absl::optional<bool> AppUpdate::GetHasBadge() const {
+ GET_VALUE_WITH_FALLBACK(has_badge, absl::nullopt);
+}
+
bool AppUpdate::HasBadgeChanged() const {
return mojom_delta_ &&
(mojom_delta_->has_badge != apps::mojom::OptionalBool::kUnknown) &&
@@ -769,6 +849,10 @@ apps::mojom::OptionalBool AppUpdate::Paused() const {
return apps::mojom::OptionalBool::kUnknown;
}
+absl::optional<bool> AppUpdate::GetPaused() const {
+ GET_VALUE_WITH_FALLBACK(paused, absl::nullopt);
+}
+
bool AppUpdate::PausedChanged() const {
return mojom_delta_ &&
(mojom_delta_->paused != apps::mojom::OptionalBool::kUnknown) &&
@@ -779,9 +863,21 @@ std::vector<apps::mojom::IntentFilterPtr> AppUpdate::IntentFilters() const {
std::vector<apps::mojom::IntentFilterPtr> intent_filters;
if (mojom_delta_ && !mojom_delta_->intent_filters.empty()) {
- CloneIntentFilters(mojom_delta_->intent_filters, &intent_filters);
+ ::CloneIntentFilters(mojom_delta_->intent_filters, &intent_filters);
} else if (mojom_state_ && !mojom_state_->intent_filters.empty()) {
- CloneIntentFilters(mojom_state_->intent_filters, &intent_filters);
+ ::CloneIntentFilters(mojom_state_->intent_filters, &intent_filters);
+ }
+
+ return intent_filters;
+}
+
+apps::IntentFilters AppUpdate::GetIntentFilters() const {
+ apps::IntentFilters intent_filters;
+
+ if (delta_ && !delta_->intent_filters.empty()) {
+ intent_filters = CloneIntentFilters(delta_->intent_filters);
+ } else if (state_ && !state_->intent_filters.empty()) {
+ intent_filters = CloneIntentFilters(state_->intent_filters);
}
return intent_filters;
@@ -803,6 +899,10 @@ apps::mojom::OptionalBool AppUpdate::ResizeLocked() const {
return apps::mojom::OptionalBool::kUnknown;
}
+absl::optional<bool> AppUpdate::GetResizeLocked() const {
+ GET_VALUE_WITH_FALLBACK(resize_locked, absl::nullopt);
+}
+
bool AppUpdate::ResizeLockedChanged() const {
return mojom_delta_ &&
(mojom_delta_->resize_locked != apps::mojom::OptionalBool::kUnknown) &&
@@ -821,6 +921,10 @@ apps::mojom::WindowMode AppUpdate::WindowMode() const {
return apps::mojom::WindowMode::kUnknown;
}
+apps::WindowMode AppUpdate::GetWindowMode() const {
+ GET_VALUE_WITH_DEFAULT_VALUE(window_mode, WindowMode::kUnknown)
+}
+
bool AppUpdate::WindowModeChanged() const {
return mojom_delta_ &&
(mojom_delta_->window_mode != apps::mojom::WindowMode::kUnknown) &&
@@ -828,6 +932,32 @@ bool AppUpdate::WindowModeChanged() const {
(mojom_delta_->window_mode != mojom_state_->window_mode));
}
+apps::mojom::RunOnOsLoginPtr AppUpdate::RunOnOsLogin() const {
+ if (mojom_delta_ && !mojom_delta_->run_on_os_login.is_null()) {
+ return mojom_delta_->run_on_os_login.Clone();
+ }
+ if (mojom_state_ && !mojom_state_->run_on_os_login.is_null()) {
+ return mojom_state_->run_on_os_login.Clone();
+ }
+ return apps::mojom::RunOnOsLoginPtr();
+}
+
+absl::optional<apps::RunOnOsLogin> AppUpdate::GetRunOnOsLogin() const {
+ if (delta_ && delta_->run_on_os_login.has_value()) {
+ return CloneRunOnOsLogin(delta_->run_on_os_login.value());
+ }
+ if (state_ && state_->run_on_os_login.has_value()) {
+ return CloneRunOnOsLogin(state_->run_on_os_login.value());
+ }
+ return absl::nullopt;
+}
+
+bool AppUpdate::RunOnOsLoginChanged() const {
+ return mojom_delta_ && !mojom_delta_->run_on_os_login.is_null() &&
+ (!mojom_state_ ||
+ !mojom_delta_->run_on_os_login.Equals(mojom_state_->run_on_os_login));
+}
+
const ::AccountId& AppUpdate::AccountId() const {
return account_id_;
}
@@ -885,6 +1015,9 @@ std::ostream& operator<<(std::ostream& out, const AppUpdate& app) {
out << "ResizeLocked: " << app.ResizeLocked() << std::endl;
out << "WindowMode: " << app.WindowMode() << std::endl;
+ if (app.RunOnOsLogin()) {
+ out << "RunOnOsLoginMode: " << app.RunOnOsLogin()->login_mode << std::endl;
+ }
return out;
}
diff --git a/chromium/components/services/app_service/public/cpp/app_update.h b/chromium/components/services/app_service/public/cpp/app_update.h
index 9070c6b3aca..4c6ccc87bc6 100644
--- a/chromium/components/services/app_service/public/cpp/app_update.h
+++ b/chromium/components/services/app_service/public/cpp/app_update.h
@@ -13,12 +13,15 @@
#include "base/memory/raw_ptr.h"
#include "components/account_id/account_id.h"
#include "components/services/app_service/public/cpp/app_types.h"
+#include "components/services/app_service/public/cpp/intent_filter.h"
+#include "components/services/app_service/public/cpp/permission.h"
#include "components/services/app_service/public/mojom/types.mojom.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
namespace apps {
struct IconKey;
+struct RunOnOsLogin;
// Wraps two apps::mojom::AppPtr's, a prior state and a delta on top of that
// state. The state is conceptually the "sum" of all of the previous deltas,
@@ -108,6 +111,7 @@ class COMPONENT_EXPORT(APP_UPDATE) AppUpdate {
bool VersionChanged() const;
std::vector<std::string> AdditionalSearchTerms() const;
+ std::vector<std::string> GetAdditionalSearchTerms() const;
bool AdditionalSearchTermsChanged() const;
apps::mojom::IconKeyPtr IconKey() const;
@@ -115,69 +119,93 @@ class COMPONENT_EXPORT(APP_UPDATE) AppUpdate {
bool IconKeyChanged() const;
base::Time LastLaunchTime() const;
+ base::Time GetLastLaunchTime() const;
bool LastLaunchTimeChanged() const;
base::Time InstallTime() const;
+ base::Time GetInstallTime() const;
bool InstallTimeChanged() const;
std::vector<apps::mojom::PermissionPtr> Permissions() const;
+ apps::Permissions GetPermissions() const;
bool PermissionsChanged() const;
apps::mojom::InstallReason InstallReason() const;
+ apps::InstallReason GetInstallReason() const;
bool InstallReasonChanged() const;
apps::mojom::InstallSource InstallSource() const;
+ apps::InstallSource GetInstallSource() const;
bool InstallSourceChanged() const;
// An optional ID used for policy to identify the app.
// For web apps, it contains the install URL.
const std::string& PolicyId() const;
+ const std::string& GetPolicyId() const;
bool PolicyIdChanged() const;
apps::mojom::OptionalBool InstalledInternally() const;
apps::mojom::OptionalBool IsPlatformApp() const;
+ absl::optional<bool> GetIsPlatformApp() const;
bool IsPlatformAppChanged() const;
apps::mojom::OptionalBool Recommendable() const;
+ absl::optional<bool> GetRecommendable() const;
bool RecommendableChanged() const;
apps::mojom::OptionalBool Searchable() const;
+ absl::optional<bool> GetSearchable() const;
bool SearchableChanged() const;
apps::mojom::OptionalBool ShowInLauncher() const;
+ absl::optional<bool> GetShowInLauncher() const;
bool ShowInLauncherChanged() const;
apps::mojom::OptionalBool ShowInShelf() const;
+ absl::optional<bool> GetShowInShelf() const;
bool ShowInShelfChanged() const;
apps::mojom::OptionalBool ShowInSearch() const;
+ absl::optional<bool> GetShowInSearch() const;
bool ShowInSearchChanged() const;
apps::mojom::OptionalBool ShowInManagement() const;
+ absl::optional<bool> GetShowInManagement() const;
bool ShowInManagementChanged() const;
apps::mojom::OptionalBool HandlesIntents() const;
+ absl::optional<bool> GetHandlesIntents() const;
bool HandlesIntentsChanged() const;
apps::mojom::OptionalBool AllowUninstall() const;
+ absl::optional<bool> GetAllowUninstall() const;
bool AllowUninstallChanged() const;
apps::mojom::OptionalBool HasBadge() const;
+ absl::optional<bool> GetHasBadge() const;
bool HasBadgeChanged() const;
apps::mojom::OptionalBool Paused() const;
+ absl::optional<bool> GetPaused() const;
bool PausedChanged() const;
std::vector<apps::mojom::IntentFilterPtr> IntentFilters() const;
+ apps::IntentFilters GetIntentFilters() const;
bool IntentFiltersChanged() const;
apps::mojom::OptionalBool ResizeLocked() const;
+ absl::optional<bool> GetResizeLocked() const;
bool ResizeLockedChanged() const;
apps::mojom::WindowMode WindowMode() const;
+ apps::WindowMode GetWindowMode() const;
bool WindowModeChanged() const;
+ apps::mojom::RunOnOsLoginPtr RunOnOsLogin() const;
+ absl::optional<apps::RunOnOsLogin> GetRunOnOsLogin() const;
+ bool RunOnOsLoginChanged() const;
+
const ::AccountId& AccountId() const;
private:
diff --git a/chromium/components/services/app_service/public/cpp/app_update_mojom_unittest.cc b/chromium/components/services/app_service/public/cpp/app_update_mojom_unittest.cc
index 87c933f790a..3e2bf019056 100644
--- a/chromium/components/services/app_service/public/cpp/app_update_mojom_unittest.cc
+++ b/chromium/components/services/app_service/public/cpp/app_update_mojom_unittest.cc
@@ -2,8 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "components/services/app_service/public/cpp/app_types.h"
#include "components/services/app_service/public/cpp/app_update.h"
+#include "components/services/app_service/public/cpp/icon_types.h"
+#include "components/services/app_service/public/cpp/intent_filter.h"
#include "components/services/app_service/public/cpp/intent_filter_util.h"
+#include "components/services/app_service/public/cpp/permission.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
@@ -100,6 +104,9 @@ class AppUpdateMojomTest : public testing::Test {
apps::mojom::WindowMode expect_window_mode_;
bool expect_window_mode_changed_;
+ apps::mojom::RunOnOsLoginPtr expect_run_on_os_login_;
+ bool expect_run_on_os_login_changed_;
+
AccountId account_id_ = AccountId::FromUserEmail("test@gmail.com");
apps::mojom::PermissionPtr MakePermission(
@@ -141,6 +148,7 @@ class AppUpdateMojomTest : public testing::Test {
expect_intent_filters_changed_ = false;
expect_resize_locked_changed_ = false;
expect_window_mode_changed_ = false;
+ expect_run_on_os_login_changed_ = false;
}
void CheckExpects(const apps::AppUpdate& u) {
@@ -230,6 +238,9 @@ class AppUpdateMojomTest : public testing::Test {
EXPECT_EQ(expect_window_mode_, u.WindowMode());
EXPECT_EQ(expect_window_mode_changed_, u.WindowModeChanged());
+ EXPECT_EQ(expect_run_on_os_login_, u.RunOnOsLogin());
+ EXPECT_EQ(expect_run_on_os_login_changed_, u.RunOnOsLoginChanged());
+
EXPECT_EQ(account_id_, u.AccountId());
}
@@ -269,6 +280,7 @@ class AppUpdateMojomTest : public testing::Test {
expect_intent_filters_.clear();
expect_resize_locked_ = apps::mojom::OptionalBool::kUnknown;
expect_window_mode_ = apps::mojom::WindowMode::kUnknown;
+ expect_run_on_os_login_ = nullptr;
ExpectNoChange();
CheckExpects(u);
@@ -939,6 +951,32 @@ class AppUpdateMojomTest : public testing::Test {
ExpectNoChange();
CheckExpects(u);
}
+
+ // RunOnOsLogin tests.
+
+ if (state) {
+ auto runOnOsLoginTestPtr = apps::mojom::RunOnOsLogin::New(
+ apps::mojom::RunOnOsLoginMode::kNotRun, false);
+ state->run_on_os_login = runOnOsLoginTestPtr.Clone();
+ expect_run_on_os_login_ = runOnOsLoginTestPtr.Clone();
+ expect_run_on_os_login_changed_ = false;
+ CheckExpects(u);
+ }
+
+ if (delta) {
+ auto runOnOsLoginTestPtr = apps::mojom::RunOnOsLogin::New(
+ apps::mojom::RunOnOsLoginMode::kWindowed, false);
+ delta->run_on_os_login = runOnOsLoginTestPtr.Clone();
+ expect_run_on_os_login_ = runOnOsLoginTestPtr.Clone();
+ expect_run_on_os_login_changed_ = true;
+ CheckExpects(u);
+ }
+
+ if (state) {
+ apps::AppUpdate::Merge(state, delta);
+ ExpectNoChange();
+ CheckExpects(u);
+ }
}
};
@@ -969,3 +1007,168 @@ TEST_F(AppUpdateMojomTest, BothAreNonNull) {
TestAppUpdate(state.get(), delta.get());
}
+
+TEST_F(AppUpdateMojomTest, AppConvert) {
+ apps::mojom::AppPtr input = apps::mojom::App::New();
+ input->app_type = apps::mojom::AppType::kWeb;
+ input->app_id = "abcdefg";
+ input->readiness = apps::mojom::Readiness::kReady;
+ input->name = "lacros test name";
+ input->short_name = "lacros test name";
+ input->publisher_id = "publisher_id";
+ input->description = "description";
+ input->version = "version";
+ input->additional_search_terms = {"1", "2"};
+
+ auto icon_key = apps::mojom::IconKey::New();
+ icon_key->timeline = 1;
+ icon_key->icon_effects = 2;
+ input->icon_key = std::move(icon_key);
+
+ input->last_launch_time = base::Time() + base::Days(1);
+ input->install_time = base::Time() + base::Days(2);
+
+ input->install_reason = apps::mojom::InstallReason::kUser;
+ input->policy_id = "https://app.site/alpha";
+ input->is_platform_app = apps::mojom::OptionalBool::kFalse;
+ input->recommendable = apps::mojom::OptionalBool::kTrue;
+ input->searchable = apps::mojom::OptionalBool::kTrue;
+ input->paused = apps::mojom::OptionalBool::kFalse;
+ input->show_in_launcher = apps::mojom::OptionalBool::kTrue;
+ input->show_in_shelf = apps::mojom::OptionalBool::kTrue;
+ input->show_in_search = apps::mojom::OptionalBool::kTrue;
+ input->show_in_management = apps::mojom::OptionalBool::kTrue;
+ input->has_badge = apps::mojom::OptionalBool::kUnknown;
+ input->paused = apps::mojom::OptionalBool::kFalse;
+
+ auto intent_filter = apps::mojom::IntentFilter::New();
+ apps_util::AddSingleValueCondition(
+ apps::mojom::ConditionType::kScheme, "https",
+ apps::mojom::PatternMatchType::kNone, intent_filter);
+ intent_filter->activity_name = "activity_name";
+ intent_filter->activity_label = "activity_label";
+ input->intent_filters.push_back(std::move(intent_filter));
+
+ input->window_mode = apps::mojom::WindowMode::kWindow;
+
+ auto permission = apps::mojom::Permission::New();
+ permission->permission_type = apps::mojom::PermissionType::kCamera;
+ permission->value = apps::mojom::PermissionValue::New();
+ permission->value->set_bool_value(true);
+ permission->is_managed = true;
+ input->permissions.push_back(std::move(permission));
+
+ input->allow_uninstall = apps::mojom::OptionalBool::kTrue;
+ input->handles_intents = apps::mojom::OptionalBool::kTrue;
+
+ auto output = apps::ConvertMojomAppToApp(input);
+
+ EXPECT_EQ(output->app_type, apps::AppType::kWeb);
+ EXPECT_EQ(output->app_id, "abcdefg");
+ EXPECT_EQ(output->readiness, apps::Readiness::kReady);
+ EXPECT_EQ(output->name, "lacros test name");
+ EXPECT_EQ(output->short_name, "lacros test name");
+ EXPECT_EQ(output->publisher_id, "publisher_id");
+ EXPECT_EQ(output->description, "description");
+ EXPECT_EQ(output->version, "version");
+ EXPECT_EQ(output->additional_search_terms, input->additional_search_terms);
+
+ EXPECT_EQ(output->icon_key->timeline, 1U);
+ EXPECT_EQ(output->icon_key->icon_effects, 2U);
+
+ EXPECT_EQ(output->last_launch_time, base::Time() + base::Days(1));
+ EXPECT_EQ(output->install_time, base::Time() + base::Days(2));
+
+ EXPECT_EQ(output->install_reason, apps::InstallReason::kUser);
+ EXPECT_EQ(output->policy_id, "https://app.site/alpha");
+ EXPECT_FALSE(output->is_platform_app.value());
+ EXPECT_TRUE(output->recommendable.value());
+ EXPECT_TRUE(output->searchable.value());
+ EXPECT_FALSE(output->paused.value());
+ EXPECT_TRUE(output->show_in_launcher.value());
+ EXPECT_TRUE(output->show_in_shelf.value());
+ EXPECT_TRUE(output->show_in_search.value());
+ EXPECT_TRUE(output->show_in_management.value());
+ EXPECT_FALSE(output->has_badge.has_value());
+ EXPECT_FALSE(output->paused.value());
+
+ ASSERT_EQ(output->intent_filters.size(), 1U);
+ auto& filter = output->intent_filters[0];
+ ASSERT_EQ(filter->conditions.size(), 1U);
+ auto& condition = filter->conditions[0];
+ EXPECT_EQ(condition->condition_type, apps::ConditionType::kScheme);
+ ASSERT_EQ(condition->condition_values.size(), 1U);
+ EXPECT_EQ(condition->condition_values[0]->value, "https");
+ EXPECT_EQ(condition->condition_values[0]->match_type,
+ apps::PatternMatchType::kNone);
+ EXPECT_EQ(filter->activity_name, "activity_name");
+ EXPECT_EQ(filter->activity_label, "activity_label");
+
+ EXPECT_EQ(output->window_mode, apps::WindowMode::kWindow);
+
+ ASSERT_EQ(output->permissions.size(), 1U);
+ auto& out_permission = output->permissions[0];
+ EXPECT_EQ(out_permission->permission_type, apps::PermissionType::kCamera);
+ ASSERT_TRUE(out_permission->value->bool_value.has_value());
+ EXPECT_TRUE(out_permission->value->bool_value.value());
+ EXPECT_TRUE(out_permission->is_managed);
+
+ EXPECT_TRUE(output->allow_uninstall.value());
+ EXPECT_TRUE(output->handles_intents.value());
+
+ auto mojom_app = apps::ConvertAppToMojomApp(output);
+
+ EXPECT_EQ(mojom_app->app_type, apps::mojom::AppType::kWeb);
+ EXPECT_EQ(mojom_app->app_id, "abcdefg");
+ EXPECT_EQ(mojom_app->readiness, apps::mojom::Readiness::kReady);
+ EXPECT_EQ(mojom_app->name, "lacros test name");
+ EXPECT_EQ(mojom_app->short_name, "lacros test name");
+ EXPECT_EQ(mojom_app->publisher_id, "publisher_id");
+ EXPECT_EQ(mojom_app->description, "description");
+ EXPECT_EQ(mojom_app->version, "version");
+ EXPECT_EQ(mojom_app->additional_search_terms, input->additional_search_terms);
+
+ EXPECT_EQ(mojom_app->icon_key->timeline, 1U);
+ EXPECT_EQ(mojom_app->icon_key->icon_effects, 2U);
+
+ EXPECT_EQ(mojom_app->last_launch_time, base::Time() + base::Days(1));
+ EXPECT_EQ(mojom_app->install_time, base::Time() + base::Days(2));
+
+ EXPECT_EQ(mojom_app->install_reason, apps::mojom::InstallReason::kUser);
+ EXPECT_EQ(mojom_app->policy_id, "https://app.site/alpha");
+ EXPECT_EQ(mojom_app->recommendable, apps::mojom::OptionalBool::kTrue);
+ EXPECT_EQ(mojom_app->searchable, apps::mojom::OptionalBool::kTrue);
+ EXPECT_EQ(mojom_app->paused, apps::mojom::OptionalBool::kFalse);
+ EXPECT_EQ(mojom_app->show_in_launcher, apps::mojom::OptionalBool::kTrue);
+ EXPECT_EQ(mojom_app->show_in_shelf, apps::mojom::OptionalBool::kTrue);
+ EXPECT_EQ(mojom_app->show_in_search, apps::mojom::OptionalBool::kTrue);
+ EXPECT_EQ(mojom_app->show_in_management, apps::mojom::OptionalBool::kTrue);
+ EXPECT_EQ(mojom_app->has_badge, apps::mojom::OptionalBool::kUnknown);
+ EXPECT_EQ(mojom_app->paused, apps::mojom::OptionalBool::kFalse);
+
+ ASSERT_EQ(mojom_app->intent_filters.size(), 1U);
+ auto& mojom_filter = mojom_app->intent_filters[0];
+ ASSERT_EQ(mojom_filter->conditions.size(), 1U);
+ auto& mojom_condition = mojom_filter->conditions[0];
+ EXPECT_EQ(mojom_condition->condition_type,
+ apps::mojom::ConditionType::kScheme);
+ ASSERT_EQ(mojom_condition->condition_values.size(), 1U);
+ EXPECT_EQ(mojom_condition->condition_values[0]->value, "https");
+ EXPECT_EQ(mojom_condition->condition_values[0]->match_type,
+ apps::mojom::PatternMatchType::kNone);
+ EXPECT_EQ(mojom_filter->activity_name, "activity_name");
+ EXPECT_EQ(mojom_filter->activity_label, "activity_label");
+
+ EXPECT_EQ(mojom_app->window_mode, apps::mojom::WindowMode::kWindow);
+
+ ASSERT_EQ(mojom_app->permissions.size(), 1U);
+ auto& mojom_permission = mojom_app->permissions[0];
+ EXPECT_EQ(mojom_permission->permission_type,
+ apps::mojom::PermissionType::kCamera);
+ ASSERT_TRUE(mojom_permission->value->is_bool_value());
+ EXPECT_TRUE(mojom_permission->value->get_bool_value());
+ EXPECT_TRUE(mojom_permission->is_managed);
+
+ EXPECT_EQ(mojom_app->allow_uninstall, apps::mojom::OptionalBool::kTrue);
+ EXPECT_EQ(mojom_app->handles_intents, apps::mojom::OptionalBool::kTrue);
+}
diff --git a/chromium/components/services/app_service/public/cpp/app_update_unittest.cc b/chromium/components/services/app_service/public/cpp/app_update_unittest.cc
index 00f4613d62f..a969a8d995d 100644
--- a/chromium/components/services/app_service/public/cpp/app_update_unittest.cc
+++ b/chromium/components/services/app_service/public/cpp/app_update_unittest.cc
@@ -3,20 +3,69 @@
// found in the LICENSE file.
#include "components/services/app_service/public/cpp/app_update.h"
-#include "components/services/app_service/public/cpp/intent_filter_util.h"
+
+#include "components/services/app_service/public/cpp/app_update.h"
+#include "components/services/app_service/public/cpp/intent_filter.h"
+#include "components/services/app_service/public/cpp/permission.h"
+#include "components/services/app_service/public/cpp/run_on_os_login_types.h"
#include "testing/gtest/include/gtest/gtest.h"
+namespace apps {
+
namespace {
-const apps::AppType app_type = apps::AppType::kArc;
+const AppType app_type = AppType::kArc;
const char app_id[] = "abcdefgh";
const char test_name_0[] = "Inigo Montoya";
const char test_name_1[] = "Dread Pirate Roberts";
+
+PermissionPtr MakePermission(PermissionType permission_type,
+ TriState tri_state,
+ bool is_managed) {
+ return std::make_unique<Permission>(
+ permission_type, std::make_unique<PermissionValue>(tri_state),
+ is_managed);
+}
+
+PermissionPtr MakePermission(PermissionType permission_type,
+ bool bool_value,
+ bool is_managed) {
+ return std::make_unique<Permission>(
+ permission_type, std::make_unique<PermissionValue>(bool_value),
+ is_managed);
+}
+
+bool IsEqual(const Permissions& source, const Permissions& target) {
+ if (source.size() != target.size()) {
+ return false;
+ }
+
+ for (int i = 0; i < static_cast<int>(source.size()); i++) {
+ if (*source[i] != *target[i]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool IsEqual(const IntentFilters& source, const IntentFilters& target) {
+ if (source.size() != target.size()) {
+ return false;
+ }
+
+ for (int i = 0; i < static_cast<int>(source.size()); i++) {
+ if (*source[i] != *target[i]) {
+ return false;
+ }
+ }
+ return true;
+}
+
} // namespace
class AppUpdateTest : public testing::Test {
protected:
- apps::Readiness expect_readiness_;
- apps::Readiness expect_prior_readiness_;
+ Readiness expect_readiness_;
+ Readiness expect_prior_readiness_;
std::string expect_name_;
bool expect_name_changed_;
@@ -29,11 +78,55 @@ class AppUpdateTest : public testing::Test {
std::string expect_version_;
- absl::optional<apps::IconKey> expect_icon_key_;
+ std::vector<std::string> expect_additional_search_terms_;
+
+ absl::optional<IconKey> expect_icon_key_;
+
+ base::Time expect_last_launch_time_;
+
+ base::Time expect_install_time_;
+
+ Permissions expect_permissions_;
+
+ InstallReason expect_install_reason_;
+
+ InstallSource expect_install_source_;
+
+ std::string expect_policy_id_;
+
+ absl::optional<bool> expect_is_platform_app_;
+
+ absl::optional<bool> expect_recommendable_;
+
+ absl::optional<bool> expect_searchable_;
+
+ absl::optional<bool> expect_show_in_launcher_;
+
+ absl::optional<bool> expect_show_in_shelf_;
+
+ absl::optional<bool> expect_show_in_search_;
+
+ absl::optional<bool> expect_show_in_management_;
+
+ absl::optional<bool> expect_handles_intents_;
+
+ absl::optional<bool> expect_allow_uninstall_;
+
+ absl::optional<bool> expect_has_badge_;
+
+ absl::optional<bool> expect_paused_;
+
+ IntentFilters expect_intent_filters_;
+
+ absl::optional<bool> expect_resize_locked_;
+
+ WindowMode expect_window_mode_;
+
+ absl::optional<RunOnOsLogin> expect_run_on_os_login_;
AccountId account_id_ = AccountId::FromUserEmail("test@gmail.com");
- void CheckExpects(const apps::AppUpdate& u) {
+ void CheckExpects(const AppUpdate& u) {
EXPECT_EQ(expect_readiness_, u.GetReadiness());
EXPECT_EQ(expect_prior_readiness_, u.GetPriorReadiness());
@@ -47,6 +140,8 @@ class AppUpdateTest : public testing::Test {
EXPECT_EQ(expect_version_, u.GetVersion());
+ EXPECT_EQ(expect_additional_search_terms_, u.GetAdditionalSearchTerms());
+
if (expect_icon_key_.has_value()) {
ASSERT_TRUE(u.GetIconKey().has_value());
EXPECT_EQ(expect_icon_key_.value(), u.GetIconKey().value());
@@ -54,23 +149,88 @@ class AppUpdateTest : public testing::Test {
ASSERT_FALSE(u.GetIconKey().has_value());
}
+ EXPECT_EQ(expect_last_launch_time_, u.GetLastLaunchTime());
+
+ EXPECT_EQ(expect_install_time_, u.GetInstallTime());
+
+ EXPECT_TRUE(IsEqual(expect_permissions_, u.GetPermissions()));
+
+ EXPECT_EQ(expect_install_reason_, u.GetInstallReason());
+
+ EXPECT_EQ(expect_install_source_, u.GetInstallSource());
+
+ EXPECT_EQ(expect_policy_id_, u.GetPolicyId());
+
+ EXPECT_EQ(expect_is_platform_app_, u.GetIsPlatformApp());
+
+ EXPECT_EQ(expect_recommendable_, u.GetRecommendable());
+
+ EXPECT_EQ(expect_searchable_, u.GetSearchable());
+
+ EXPECT_EQ(expect_show_in_launcher_, u.GetShowInLauncher());
+
+ EXPECT_EQ(expect_show_in_shelf_, u.GetShowInShelf());
+
+ EXPECT_EQ(expect_show_in_search_, u.GetShowInSearch());
+
+ EXPECT_EQ(expect_show_in_management_, u.GetShowInManagement());
+
+ EXPECT_EQ(expect_handles_intents_, u.GetHandlesIntents());
+
+ EXPECT_EQ(expect_has_badge_, u.GetHasBadge());
+
+ EXPECT_EQ(expect_paused_, u.GetPaused());
+
+ EXPECT_TRUE(IsEqual(expect_intent_filters_, u.GetIntentFilters()));
+
+ EXPECT_EQ(expect_resize_locked_, u.GetResizeLocked());
+
+ EXPECT_EQ(expect_window_mode_, u.GetWindowMode());
+ if (expect_run_on_os_login_.has_value()) {
+ ASSERT_TRUE(u.GetRunOnOsLogin().has_value());
+ EXPECT_EQ(expect_run_on_os_login_.value(), u.GetRunOnOsLogin().value());
+ } else {
+ ASSERT_FALSE(u.GetRunOnOsLogin().has_value());
+ }
+
EXPECT_EQ(account_id_, u.AccountId());
}
- void TestAppUpdate(apps::App* state, apps::App* delta) {
- apps::AppUpdate u(state, delta, account_id_);
+ void TestAppUpdate(App* state, App* delta) {
+ AppUpdate u(state, delta, account_id_);
EXPECT_EQ(app_type, u.GetAppType());
EXPECT_EQ(app_id, u.GetAppId());
- expect_readiness_ = apps::Readiness::kUnknown;
- expect_prior_readiness_ = apps::Readiness::kUnknown;
+ expect_readiness_ = Readiness::kUnknown;
+ expect_prior_readiness_ = Readiness::kUnknown;
expect_name_ = "";
expect_short_name_ = "";
expect_publisher_id_ = "";
expect_description_ = "";
expect_version_ = "";
+ expect_additional_search_terms_.clear();
expect_icon_key_ = absl::nullopt;
+ expect_last_launch_time_ = base::Time();
+ expect_install_time_ = base::Time();
+ expect_permissions_.clear();
+ expect_install_reason_ = InstallReason::kUnknown;
+ expect_install_source_ = InstallSource::kUnknown;
+ expect_policy_id_ = "";
+ expect_is_platform_app_ = absl::nullopt;
+ expect_recommendable_ = absl::nullopt;
+ expect_searchable_ = absl::nullopt;
+ expect_show_in_launcher_ = absl::nullopt;
+ expect_show_in_shelf_ = absl::nullopt;
+ expect_show_in_search_ = absl::nullopt;
+ expect_show_in_management_ = absl::nullopt;
+ expect_handles_intents_ = absl::nullopt;
+ expect_has_badge_ = absl::nullopt;
+ expect_paused_ = absl::nullopt;
+ expect_intent_filters_.clear();
+ expect_resize_locked_ = absl::nullopt;
+ expect_window_mode_ = WindowMode::kUnknown;
+ expect_run_on_os_login_ = absl::nullopt;
CheckExpects(u);
if (delta) {
@@ -88,8 +248,8 @@ class AppUpdateTest : public testing::Test {
}
if (delta) {
- delta->readiness = apps::Readiness::kReady;
- expect_readiness_ = apps::Readiness::kReady;
+ delta->readiness = Readiness::kReady;
+ expect_readiness_ = Readiness::kReady;
CheckExpects(u);
delta->name = absl::nullopt;
@@ -99,14 +259,16 @@ class AppUpdateTest : public testing::Test {
}
if (state) {
- apps::AppUpdate::Merge(state, delta);
+ AppUpdate::Merge(state, delta);
expect_prior_readiness_ = state->readiness;
+ EXPECT_EQ(expect_name_, state->name);
+ EXPECT_EQ(expect_readiness_, state->readiness);
CheckExpects(u);
}
if (delta) {
- delta->readiness = apps::Readiness::kDisabledByPolicy;
- expect_readiness_ = apps::Readiness::kDisabledByPolicy;
+ delta->readiness = Readiness::kDisabledByPolicy;
+ expect_readiness_ = Readiness::kDisabledByPolicy;
delta->name = test_name_1;
expect_name_ = test_name_1;
expect_name_changed_ = true;
@@ -128,8 +290,9 @@ class AppUpdateTest : public testing::Test {
}
if (state) {
- apps::AppUpdate::Merge(state, delta);
+ AppUpdate::Merge(state, delta);
expect_prior_readiness_ = state->readiness;
+ EXPECT_EQ(expect_short_name_, state->short_name);
CheckExpects(u);
}
@@ -148,7 +311,8 @@ class AppUpdateTest : public testing::Test {
}
if (state) {
- apps::AppUpdate::Merge(state, delta);
+ AppUpdate::Merge(state, delta);
+ EXPECT_EQ(expect_publisher_id_, state->publisher_id);
CheckExpects(u);
}
@@ -167,7 +331,8 @@ class AppUpdateTest : public testing::Test {
}
if (state) {
- apps::AppUpdate::Merge(state, delta);
+ AppUpdate::Merge(state, delta);
+ EXPECT_EQ(expect_description_, state->description);
CheckExpects(u);
}
@@ -186,43 +351,548 @@ class AppUpdateTest : public testing::Test {
}
if (state) {
+ AppUpdate::Merge(state, delta);
+ EXPECT_EQ(expect_version_, state->version);
+ CheckExpects(u);
+ }
+
+ // AdditionalSearchTerms tests.
+
+ if (state) {
+ state->additional_search_terms.push_back("cat");
+ state->additional_search_terms.push_back("dog");
+ expect_additional_search_terms_.push_back("cat");
+ expect_additional_search_terms_.push_back("dog");
+ CheckExpects(u);
+ }
+
+ if (delta) {
+ expect_additional_search_terms_.clear();
+ delta->additional_search_terms.push_back("horse");
+ delta->additional_search_terms.push_back("mouse");
+ expect_additional_search_terms_.push_back("horse");
+ expect_additional_search_terms_.push_back("mouse");
+ CheckExpects(u);
+ }
+
+ if (state) {
apps::AppUpdate::Merge(state, delta);
+ EXPECT_EQ(expect_additional_search_terms_,
+ state->additional_search_terms);
CheckExpects(u);
}
// IconKey tests.
if (state) {
- state->icon_key = apps::IconKey(100, 0, 0);
- expect_icon_key_ = apps::IconKey(100, 0, 0);
+ state->icon_key = IconKey(100, 0, 0);
+ expect_icon_key_ = IconKey(100, 0, 0);
+ CheckExpects(u);
+ }
+
+ if (delta) {
+ delta->icon_key = IconKey(200, 0, 0);
+ expect_icon_key_ = IconKey(200, 0, 0);
+ CheckExpects(u);
+ }
+
+ if (state) {
+ AppUpdate::Merge(state, delta);
+ EXPECT_EQ(expect_icon_key_.value(), state->icon_key.value());
+ CheckExpects(u);
+ }
+
+ // LastLaunchTime tests.
+
+ if (state) {
+ state->last_launch_time = base::Time::FromDoubleT(1000.0);
+ expect_last_launch_time_ = base::Time::FromDoubleT(1000.0);
CheckExpects(u);
}
if (delta) {
- delta->icon_key = apps::IconKey(200, 0, 0);
- expect_icon_key_ = apps::IconKey(200, 0, 0);
+ delta->last_launch_time = base::Time::FromDoubleT(1001.0);
+ expect_last_launch_time_ = base::Time::FromDoubleT(1001.0);
CheckExpects(u);
}
if (state) {
apps::AppUpdate::Merge(state, delta);
+ EXPECT_EQ(expect_last_launch_time_, state->last_launch_time);
+ CheckExpects(u);
+ }
+
+ // InstallTime tests.
+
+ if (state) {
+ state->install_time = base::Time::FromDoubleT(2000.0);
+ expect_install_time_ = base::Time::FromDoubleT(2000.0);
+ CheckExpects(u);
+ }
+
+ if (delta) {
+ delta->install_time = base::Time::FromDoubleT(2001.0);
+ expect_install_time_ = base::Time::FromDoubleT(2001.0);
+ CheckExpects(u);
+ }
+
+ if (state) {
+ apps::AppUpdate::Merge(state, delta);
+ EXPECT_EQ(expect_install_time_, state->install_time);
+ CheckExpects(u);
+ }
+
+ // Permission tests.
+
+ if (state) {
+ auto p0 = MakePermission(PermissionType::kLocation, TriState::kAllow,
+ /*is_managed=*/true);
+ auto p1 = MakePermission(PermissionType::kNotifications, TriState::kBlock,
+ /*is_managed=*/false);
+ state->permissions.push_back(p0->Clone());
+ state->permissions.push_back(p1->Clone());
+ expect_permissions_.push_back(p0->Clone());
+ expect_permissions_.push_back(p1->Clone());
+ CheckExpects(u);
+ }
+
+ if (delta) {
+ expect_permissions_.clear();
+ auto p0 = MakePermission(PermissionType::kNotifications,
+ /*bool_value=*/true,
+ /*is_managed=*/false);
+ auto p1 = MakePermission(PermissionType::kLocation,
+ /*bool_value=*/false,
+ /*is_managed=*/true);
+ delta->permissions.push_back(p0->Clone());
+ delta->permissions.push_back(p1->Clone());
+ expect_permissions_.push_back(p0->Clone());
+ expect_permissions_.push_back(p1->Clone());
+ CheckExpects(u);
+ }
+
+ if (state) {
+ apps::AppUpdate::Merge(state, delta);
+ EXPECT_TRUE(IsEqual(expect_permissions_, state->permissions));
+ CheckExpects(u);
+ }
+
+ // InstallReason tests.
+
+ if (state) {
+ state->install_reason = InstallReason::kUser;
+ expect_install_reason_ = InstallReason::kUser;
+ CheckExpects(u);
+ }
+
+ if (delta) {
+ delta->install_reason = InstallReason::kPolicy;
+ expect_install_reason_ = InstallReason::kPolicy;
+ CheckExpects(u);
+ }
+
+ if (state) {
+ AppUpdate::Merge(state, delta);
+ EXPECT_EQ(expect_install_reason_, state->install_reason);
+ CheckExpects(u);
+ }
+
+ // InstallSource tests.
+
+ if (state) {
+ state->install_source = InstallSource::kPlayStore;
+ expect_install_source_ = InstallSource::kPlayStore;
+ CheckExpects(u);
+ }
+
+ if (delta) {
+ delta->install_source = InstallSource::kSync;
+ expect_install_source_ = InstallSource::kSync;
+ CheckExpects(u);
+ }
+
+ if (state) {
+ AppUpdate::Merge(state, delta);
+ EXPECT_EQ(expect_install_source_, state->install_source);
+ CheckExpects(u);
+ }
+
+ // PolicyId tests.
+
+ if (state) {
+ state->policy_id = "https://app.site/alpha";
+ expect_policy_id_ = "https://app.site/alpha";
+ CheckExpects(u);
+ }
+
+ if (delta) {
+ delta->policy_id = "https://app.site/delta";
+ expect_policy_id_ = "https://app.site/delta";
+ CheckExpects(u);
+ }
+
+ if (state) {
+ apps::AppUpdate::Merge(state, delta);
+ EXPECT_EQ(expect_policy_id_, state->policy_id);
+ CheckExpects(u);
+ }
+
+ // IsPlatformApp tests.
+
+ if (state) {
+ state->is_platform_app = false;
+ expect_is_platform_app_ = false;
+ CheckExpects(u);
+ }
+
+ if (delta) {
+ delta->is_platform_app = true;
+ expect_is_platform_app_ = true;
+ CheckExpects(u);
+ }
+
+ if (state) {
+ apps::AppUpdate::Merge(state, delta);
+ EXPECT_EQ(expect_is_platform_app_, state->is_platform_app);
+ CheckExpects(u);
+ }
+
+ // Recommendable tests.
+
+ if (state) {
+ state->recommendable = false;
+ expect_recommendable_ = false;
+ CheckExpects(u);
+ }
+
+ if (delta) {
+ delta->recommendable = true;
+ expect_recommendable_ = true;
+ CheckExpects(u);
+ }
+
+ if (state) {
+ apps::AppUpdate::Merge(state, delta);
+ EXPECT_EQ(expect_recommendable_, state->recommendable);
+ CheckExpects(u);
+ }
+
+ // Searchable tests.
+
+ if (state) {
+ state->searchable = false;
+ expect_searchable_ = false;
+ CheckExpects(u);
+ }
+
+ if (delta) {
+ delta->searchable = true;
+ expect_searchable_ = true;
+ CheckExpects(u);
+ }
+
+ if (state) {
+ apps::AppUpdate::Merge(state, delta);
+ EXPECT_EQ(expect_searchable_, state->searchable);
+ CheckExpects(u);
+ }
+
+ // ShowInLauncher tests.
+
+ if (state) {
+ state->show_in_launcher = false;
+ expect_show_in_launcher_ = false;
+ CheckExpects(u);
+ }
+
+ if (delta) {
+ delta->show_in_launcher = true;
+ expect_show_in_launcher_ = true;
+ CheckExpects(u);
+ }
+
+ if (state) {
+ apps::AppUpdate::Merge(state, delta);
+ EXPECT_EQ(expect_show_in_launcher_, state->show_in_launcher);
+ CheckExpects(u);
+ }
+
+ // ShowInShelf tests.
+
+ if (state) {
+ state->show_in_shelf = false;
+ expect_show_in_shelf_ = false;
+ CheckExpects(u);
+ }
+
+ if (delta) {
+ delta->show_in_shelf = true;
+ expect_show_in_shelf_ = true;
+ CheckExpects(u);
+ }
+
+ if (state) {
+ apps::AppUpdate::Merge(state, delta);
+ EXPECT_EQ(expect_show_in_shelf_, state->show_in_shelf);
+ CheckExpects(u);
+ }
+
+ // ShowInSearch tests.
+
+ if (state) {
+ state->show_in_search = false;
+ expect_show_in_search_ = false;
+ CheckExpects(u);
+ }
+
+ if (delta) {
+ delta->show_in_search = true;
+ expect_show_in_search_ = true;
+ CheckExpects(u);
+ }
+
+ if (state) {
+ apps::AppUpdate::Merge(state, delta);
+ EXPECT_EQ(expect_show_in_search_, state->show_in_search);
+ CheckExpects(u);
+ }
+
+ // ShowInManagement tests.
+
+ if (state) {
+ state->show_in_management = false;
+ expect_show_in_management_ = false;
+ CheckExpects(u);
+ }
+
+ if (delta) {
+ delta->show_in_management = true;
+ expect_show_in_management_ = true;
+ CheckExpects(u);
+ }
+
+ if (state) {
+ apps::AppUpdate::Merge(state, delta);
+ EXPECT_EQ(expect_show_in_management_, state->show_in_management);
+ CheckExpects(u);
+ }
+
+ // HandlesIntents tests.
+
+ if (state) {
+ state->handles_intents = false;
+ expect_handles_intents_ = false;
+ CheckExpects(u);
+ }
+
+ if (delta) {
+ delta->handles_intents = true;
+ expect_handles_intents_ = true;
+ CheckExpects(u);
+ }
+
+ if (state) {
+ apps::AppUpdate::Merge(state, delta);
+ EXPECT_EQ(expect_handles_intents_, state->handles_intents);
+ CheckExpects(u);
+ }
+
+ // AllowUninstall tests
+
+ if (state) {
+ state->allow_uninstall = false;
+ expect_allow_uninstall_ = false;
+ CheckExpects(u);
+ }
+
+ if (delta) {
+ delta->allow_uninstall = true;
+ expect_allow_uninstall_ = true;
+ CheckExpects(u);
+ }
+
+ if (state) {
+ apps::AppUpdate::Merge(state, delta);
+ EXPECT_EQ(expect_allow_uninstall_, state->allow_uninstall);
+ CheckExpects(u);
+ }
+
+ // HasBadge tests.
+
+ if (state) {
+ state->has_badge = false;
+ expect_has_badge_ = false;
+ CheckExpects(u);
+ }
+
+ if (delta) {
+ delta->has_badge = true;
+ expect_has_badge_ = true;
+ CheckExpects(u);
+ }
+
+ if (state) {
+ apps::AppUpdate::Merge(state, delta);
+ EXPECT_EQ(expect_has_badge_, state->has_badge);
+ CheckExpects(u);
+ }
+
+ // Pause tests.
+
+ if (state) {
+ state->paused = false;
+ expect_paused_ = false;
+ CheckExpects(u);
+ }
+
+ if (delta) {
+ delta->paused = true;
+ expect_paused_ = true;
+ CheckExpects(u);
+ }
+
+ if (state) {
+ apps::AppUpdate::Merge(state, delta);
+ EXPECT_EQ(expect_paused_, state->paused);
+ CheckExpects(u);
+ }
+
+ // Intent Filter tests.
+
+ if (state) {
+ IntentFilterPtr intent_filter = std::make_unique<IntentFilter>();
+
+ ConditionValues scheme_condition_values;
+ scheme_condition_values.push_back(
+ std::make_unique<ConditionValue>("https", PatternMatchType::kNone));
+ ConditionPtr scheme_condition = std::make_unique<Condition>(
+ ConditionType::kScheme, std::move(scheme_condition_values));
+
+ ConditionValues host_condition_values;
+ host_condition_values.push_back(std::make_unique<ConditionValue>(
+ "www.google.com", PatternMatchType::kNone));
+ auto host_condition = std::make_unique<Condition>(
+ ConditionType::kHost, std::move(host_condition_values));
+
+ intent_filter->conditions.push_back(std::move(scheme_condition));
+ intent_filter->conditions.push_back(std::move(host_condition));
+
+ state->intent_filters.push_back(intent_filter->Clone());
+ expect_intent_filters_.push_back(intent_filter->Clone());
+ CheckExpects(u);
+ }
+
+ if (delta) {
+ expect_intent_filters_.clear();
+
+ IntentFilterPtr intent_filter = std::make_unique<IntentFilter>();
+
+ ConditionValues scheme_condition_values;
+ scheme_condition_values.push_back(
+ std::make_unique<ConditionValue>("https", PatternMatchType::kNone));
+ ConditionPtr scheme_condition = std::make_unique<Condition>(
+ ConditionType::kScheme, std::move(scheme_condition_values));
+ intent_filter->conditions.push_back(scheme_condition->Clone());
+
+ ConditionValues host_condition_values;
+ host_condition_values.push_back(std::make_unique<ConditionValue>(
+ "www.abc.com", PatternMatchType::kNone));
+ auto host_condition = std::make_unique<Condition>(
+ ConditionType::kHost, std::move(host_condition_values));
+ intent_filter->conditions.push_back(host_condition->Clone());
+
+ intent_filter->conditions.push_back(std::move(scheme_condition));
+ intent_filter->conditions.push_back(std::move(host_condition));
+
+ delta->intent_filters.push_back(intent_filter->Clone());
+ expect_intent_filters_.push_back(intent_filter->Clone());
+ CheckExpects(u);
+ }
+
+ if (state) {
+ apps::AppUpdate::Merge(state, delta);
+ EXPECT_TRUE(IsEqual(expect_intent_filters_, state->intent_filters));
+ CheckExpects(u);
+ }
+
+ // ResizeLocked tests.
+
+ if (state) {
+ state->resize_locked = false;
+ expect_resize_locked_ = false;
+ CheckExpects(u);
+ }
+
+ if (delta) {
+ delta->resize_locked = true;
+ expect_resize_locked_ = true;
+ CheckExpects(u);
+ }
+
+ if (state) {
+ apps::AppUpdate::Merge(state, delta);
+ EXPECT_EQ(expect_resize_locked_, state->resize_locked);
+ CheckExpects(u);
+ }
+
+ // WindowMode tests.
+
+ if (state) {
+ state->window_mode = WindowMode::kBrowser;
+ expect_window_mode_ = WindowMode::kBrowser;
+ CheckExpects(u);
+ }
+
+ if (delta) {
+ delta->window_mode = WindowMode::kWindow;
+ expect_window_mode_ = WindowMode::kWindow;
+ CheckExpects(u);
+ }
+
+ if (state) {
+ apps::AppUpdate::Merge(state, delta);
+ EXPECT_EQ(expect_window_mode_, state->window_mode);
+ CheckExpects(u);
+ }
+
+ // RunOnOsLogin tests.
+
+ if (state) {
+ state->run_on_os_login = RunOnOsLogin(RunOnOsLoginMode::kNotRun, false);
+ expect_run_on_os_login_ = RunOnOsLogin(RunOnOsLoginMode::kNotRun, false);
+ CheckExpects(u);
+ }
+
+ if (delta) {
+ delta->run_on_os_login = RunOnOsLogin(RunOnOsLoginMode::kWindowed, false);
+ expect_run_on_os_login_ =
+ RunOnOsLogin(RunOnOsLoginMode::kWindowed, false);
+ CheckExpects(u);
+ }
+
+ if (state) {
+ AppUpdate::Merge(state, delta);
+ EXPECT_EQ(expect_run_on_os_login_.value(),
+ state->run_on_os_login.value());
CheckExpects(u);
}
}
};
TEST_F(AppUpdateTest, StateIsNonNull) {
- apps::App state(app_type, app_id);
+ App state(app_type, app_id);
TestAppUpdate(&state, nullptr);
}
TEST_F(AppUpdateTest, DeltaIsNonNull) {
- apps::App delta(app_type, app_id);
+ App delta(app_type, app_id);
TestAppUpdate(nullptr, &delta);
}
TEST_F(AppUpdateTest, BothAreNonNull) {
- apps::App state(app_type, app_id);
- apps::App delta(app_type, app_id);
+ App state(app_type, app_id);
+ App delta(app_type, app_id);
TestAppUpdate(&state, &delta);
}
+
+} // namespace apps
diff --git a/chromium/components/services/app_service/public/cpp/browser_app_instance_update.h b/chromium/components/services/app_service/public/cpp/browser_app_instance_update.h
index 37f7c25c493..dfaa7dd3783 100644
--- a/chromium/components/services/app_service/public/cpp/browser_app_instance_update.h
+++ b/chromium/components/services/app_service/public/cpp/browser_app_instance_update.h
@@ -27,8 +27,10 @@ struct BrowserAppInstanceUpdate {
std::string app_id;
std::string window_id;
std::string title;
- bool is_browser_active;
- bool is_web_contents_active;
+ bool is_browser_active = false;
+ bool is_web_contents_active = false;
+ uint32_t browser_session_id = 0;
+ uint32_t restored_browser_session_id = 0;
};
} // namespace apps
diff --git a/chromium/components/services/app_service/public/cpp/browser_window_instance_update.h b/chromium/components/services/app_service/public/cpp/browser_window_instance_update.h
index 4f0d3c1b504..83402c01707 100644
--- a/chromium/components/services/app_service/public/cpp/browser_window_instance_update.h
+++ b/chromium/components/services/app_service/public/cpp/browser_window_instance_update.h
@@ -12,7 +12,9 @@ namespace apps {
struct BrowserWindowInstanceUpdate {
base::UnguessableToken id;
std::string window_id;
- bool is_active;
+ bool is_active = false;
+ uint32_t browser_session_id = 0;
+ uint32_t restored_browser_session_id = 0;
};
} // namespace apps
diff --git a/chromium/components/services/app_service/public/cpp/features.cc b/chromium/components/services/app_service/public/cpp/features.cc
new file mode 100644
index 00000000000..af71190a101
--- /dev/null
+++ b/chromium/components/services/app_service/public/cpp/features.cc
@@ -0,0 +1,16 @@
+// Copyright 2022 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.
+
+#include "components/services/app_service/public/cpp/features.h"
+
+namespace apps {
+
+const base::Feature kAppServiceOnAppTypeInitializedWithoutMojom{
+ "AppServiceOnAppTypeInitializedWithoutMojom",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+const base::Feature kAppServiceOnAppUpdateWithoutMojom{
+ "AppServiceOnAppUpdateWithoutMojom", base::FEATURE_DISABLED_BY_DEFAULT};
+
+} // namespace apps
diff --git a/chromium/components/services/app_service/public/cpp/features.h b/chromium/components/services/app_service/public/cpp/features.h
new file mode 100644
index 00000000000..dcc3bbc7c41
--- /dev/null
+++ b/chromium/components/services/app_service/public/cpp/features.h
@@ -0,0 +1,19 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_SERVICES_APP_SERVICE_PUBLIC_CPP_FEATURES_H_
+#define COMPONENTS_SERVICES_APP_SERVICE_PUBLIC_CPP_FEATURES_H_
+
+#include "base/component_export.h"
+#include "base/feature_list.h"
+
+namespace apps {
+
+COMPONENT_EXPORT(APP_UPDATE)
+extern const base::Feature kAppServiceOnAppTypeInitializedWithoutMojom;
+extern const base::Feature kAppServiceOnAppUpdateWithoutMojom;
+
+} // namespace apps
+
+#endif // COMPONENTS_SERVICES_APP_SERVICE_PUBLIC_CPP_FEATURES_H_
diff --git a/chromium/components/services/app_service/public/cpp/icon_loader.h b/chromium/components/services/app_service/public/cpp/icon_loader.h
index 8da5708cc0e..37f7e89b49d 100644
--- a/chromium/components/services/app_service/public/cpp/icon_loader.h
+++ b/chromium/components/services/app_service/public/cpp/icon_loader.h
@@ -58,7 +58,8 @@ class IconLoader {
virtual absl::optional<IconKey> GetIconKey(const std::string& app_id);
// This can return nullptr, meaning that the IconLoader does not track when
- // the icon is no longer actively used by the caller.
+ // the icon is no longer actively used by the caller. `callback` may be
+ // dispatched synchronously if it's possible to quickly return a result.
virtual std::unique_ptr<Releaser> LoadIconFromIconKey(
AppType app_type,
const std::string& app_id,
@@ -69,7 +70,8 @@ class IconLoader {
apps::LoadIconCallback callback) = 0;
// Convenience method that calls "LoadIconFromIconKey(app_type, app_id,
- // GetIconKey(app_id), etc)".
+ // GetIconKey(app_id), etc)". `callback` may be dispatched synchronously if
+ // it's possible to quickly return a result.
std::unique_ptr<Releaser> LoadIcon(AppType app_type,
const std::string& app_id,
const IconType& icon_type,
diff --git a/chromium/components/services/app_service/public/cpp/icon_types.h b/chromium/components/services/app_service/public/cpp/icon_types.h
index 5391b835c4f..7d89bdd2b22 100644
--- a/chromium/components/services/app_service/public/cpp/icon_types.h
+++ b/chromium/components/services/app_service/public/cpp/icon_types.h
@@ -7,6 +7,7 @@
#include <vector>
+#include "base/component_export.h"
#include "components/services/app_service/public/mojom/types.mojom.h"
#include "ui/gfx/image/image_skia.h"
@@ -60,6 +61,8 @@ struct COMPONENT_EXPORT(ICON_TYPES) IconKey {
// components/services/app_service/public/cpp/icon_loader.*
};
+using IconKeyPtr = std::unique_ptr<IconKey>;
+
enum class IconType {
// Sentinel value used in error cases.
kUnknown,
diff --git a/chromium/components/services/app_service/public/cpp/instance_update.cc b/chromium/components/services/app_service/public/cpp/instance_update.cc
index 028b19cb5e5..1bc5e1b53c2 100644
--- a/chromium/components/services/app_service/public/cpp/instance_update.cc
+++ b/chromium/components/services/app_service/public/cpp/instance_update.cc
@@ -125,7 +125,8 @@ bool InstanceUpdate::WindowChanged() const {
}
const std::string& InstanceUpdate::LaunchId() const {
- GET_VALUE_WITH_CHECK_AND_DEFAULT_RETURN(LaunchId, empty, base::EmptyString());
+ GET_VALUE_WITH_CHECK_AND_DEFAULT_RETURN(LaunchId(), empty,
+ base::EmptyString());
}
bool InstanceUpdate::LaunchIdChanged() const {
@@ -133,7 +134,7 @@ bool InstanceUpdate::LaunchIdChanged() const {
}
InstanceState InstanceUpdate::State() const {
- GET_VALUE_WITH_DEFAULT_VALUE(State, InstanceState::kUnknown);
+ GET_VALUE_WITH_DEFAULT_VALUE(State(), InstanceState::kUnknown);
}
bool InstanceUpdate::StateChanged() const {
@@ -141,7 +142,7 @@ bool InstanceUpdate::StateChanged() const {
}
base::Time InstanceUpdate::LastUpdatedTime() const {
- GET_VALUE_WITH_CHECK_AND_DEFAULT_RETURN(LastUpdatedTime, is_null,
+ GET_VALUE_WITH_CHECK_AND_DEFAULT_RETURN(LastUpdatedTime(), is_null,
base::Time());
}
diff --git a/chromium/components/services/app_service/public/cpp/intent_filter.cc b/chromium/components/services/app_service/public/cpp/intent_filter.cc
new file mode 100644
index 00000000000..c58fbbac959
--- /dev/null
+++ b/chromium/components/services/app_service/public/cpp/intent_filter.cc
@@ -0,0 +1,318 @@
+// Copyright 2022 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.
+
+#include "components/services/app_service/public/cpp/intent_filter.h"
+
+namespace apps {
+
+ConditionValue::ConditionValue(const std::string& value,
+ PatternMatchType match_type)
+ : value(value), match_type(match_type) {}
+
+ConditionValue::~ConditionValue() = default;
+
+bool ConditionValue::operator==(const ConditionValue& other) const {
+ return value == other.value && match_type == other.match_type;
+}
+
+bool ConditionValue::operator!=(const ConditionValue& other) const {
+ return !(*this == other);
+}
+
+Condition::Condition(ConditionType condition_type,
+ ConditionValues condition_values)
+ : condition_type(condition_type),
+ condition_values(std::move(condition_values)) {}
+
+Condition::~Condition() = default;
+
+bool Condition::operator==(const Condition& other) const {
+ if (condition_values.size() != other.condition_values.size()) {
+ return false;
+ }
+
+ for (int i = 0; i < static_cast<int>(condition_values.size()); i++) {
+ if (*condition_values[i] != *other.condition_values[i]) {
+ return false;
+ }
+ }
+
+ return condition_type == other.condition_type;
+}
+
+bool Condition::operator!=(const Condition& other) const {
+ return !(*this == other);
+}
+
+ConditionPtr Condition::Clone() const {
+ ConditionValues values;
+ for (const auto& condition_value : condition_values) {
+ values.push_back(std::make_unique<ConditionValue>(
+ condition_value->value, condition_value->match_type));
+ }
+
+ return std::make_unique<Condition>(condition_type, std::move(values));
+}
+
+IntentFilter::IntentFilter() = default;
+IntentFilter::~IntentFilter() = default;
+
+bool IntentFilter::operator==(const IntentFilter& other) const {
+ if (conditions.size() != other.conditions.size()) {
+ return false;
+ }
+
+ for (int i = 0; i < static_cast<int>(conditions.size()); i++) {
+ if (*conditions[i] != *other.conditions[i]) {
+ return false;
+ }
+ }
+
+ return activity_name == other.activity_name &&
+ activity_label == other.activity_label;
+}
+
+bool IntentFilter::operator!=(const IntentFilter& other) const {
+ return !(*this == other);
+}
+
+IntentFilterPtr IntentFilter::Clone() const {
+ IntentFilterPtr intent_filter = std::make_unique<IntentFilter>();
+
+ for (const auto& condition : conditions) {
+ intent_filter->conditions.push_back(condition->Clone());
+ }
+
+ if (activity_name.has_value())
+ intent_filter->activity_name = activity_name.value();
+
+ if (activity_label.has_value())
+ intent_filter->activity_label = activity_label.value();
+
+ return intent_filter;
+}
+
+IntentFilters CloneIntentFilters(const IntentFilters& intent_filters) {
+ IntentFilters ret;
+ for (const auto& intent_filter : intent_filters) {
+ ret.push_back(intent_filter->Clone());
+ }
+ return ret;
+}
+
+ConditionType ConvertMojomConditionTypeToConditionType(
+ const apps::mojom::ConditionType& mojom_condition_type) {
+ switch (mojom_condition_type) {
+ case apps::mojom::ConditionType::kScheme:
+ return ConditionType::kScheme;
+ case apps::mojom::ConditionType::kHost:
+ return ConditionType::kHost;
+ case apps::mojom::ConditionType::kPattern:
+ return ConditionType::kPattern;
+ case apps::mojom::ConditionType::kAction:
+ return ConditionType::kAction;
+ case apps::mojom::ConditionType::kMimeType:
+ return ConditionType::kMimeType;
+ case apps::mojom::ConditionType::kFile:
+ return ConditionType::kFile;
+ }
+}
+
+apps::mojom::ConditionType ConvertConditionTypeToMojomConditionType(
+ const ConditionType& condition_type) {
+ switch (condition_type) {
+ case ConditionType::kScheme:
+ return apps::mojom::ConditionType::kScheme;
+ case ConditionType::kHost:
+ return apps::mojom::ConditionType::kHost;
+ case ConditionType::kPattern:
+ return apps::mojom::ConditionType::kPattern;
+ case ConditionType::kAction:
+ return apps::mojom::ConditionType::kAction;
+ case ConditionType::kMimeType:
+ return apps::mojom::ConditionType::kMimeType;
+ case ConditionType::kFile:
+ return apps::mojom::ConditionType::kFile;
+ }
+}
+
+PatternMatchType ConvertMojomPatternMatchTypeToPatternMatchType(
+ const apps::mojom::PatternMatchType& mojom_pattern_match_type) {
+ switch (mojom_pattern_match_type) {
+ case apps::mojom::PatternMatchType::kNone:
+ return PatternMatchType::kNone;
+ case apps::mojom::PatternMatchType::kLiteral:
+ return PatternMatchType::kLiteral;
+ case apps::mojom::PatternMatchType::kPrefix:
+ return PatternMatchType::kPrefix;
+ case apps::mojom::PatternMatchType::kGlob:
+ return PatternMatchType::kGlob;
+ case apps::mojom::PatternMatchType::kMimeType:
+ return PatternMatchType::kMimeType;
+ case apps::mojom::PatternMatchType::kFileExtension:
+ return PatternMatchType::kFileExtension;
+ case apps::mojom::PatternMatchType::kIsDirectory:
+ return PatternMatchType::kIsDirectory;
+ }
+}
+
+apps::mojom::PatternMatchType ConvertPatternMatchTypeToMojomPatternMatchType(
+ const PatternMatchType& pattern_match_type) {
+ switch (pattern_match_type) {
+ case PatternMatchType::kNone:
+ return apps::mojom::PatternMatchType::kNone;
+ case PatternMatchType::kLiteral:
+ return apps::mojom::PatternMatchType::kLiteral;
+ case PatternMatchType::kPrefix:
+ return apps::mojom::PatternMatchType::kPrefix;
+ case PatternMatchType::kGlob:
+ return apps::mojom::PatternMatchType::kGlob;
+ case PatternMatchType::kMimeType:
+ return apps::mojom::PatternMatchType::kMimeType;
+ case PatternMatchType::kFileExtension:
+ return apps::mojom::PatternMatchType::kFileExtension;
+ case PatternMatchType::kIsDirectory:
+ return apps::mojom::PatternMatchType::kIsDirectory;
+ }
+}
+
+ConditionValuePtr ConvertMojomConditionValueToConditionValue(
+ const apps::mojom::ConditionValuePtr& mojom_condition_value) {
+ if (!mojom_condition_value) {
+ return nullptr;
+ }
+
+ ConditionValuePtr condition_value = std::make_unique<ConditionValue>(
+ mojom_condition_value->value,
+ ConvertMojomPatternMatchTypeToPatternMatchType(
+ mojom_condition_value->match_type));
+ return condition_value;
+}
+
+apps::mojom::ConditionValuePtr ConvertConditionValueToMojomConditionValue(
+ const ConditionValuePtr& condition_value) {
+ auto mojom_condition_value = apps::mojom::ConditionValue::New();
+ if (!condition_value) {
+ return mojom_condition_value;
+ }
+
+ mojom_condition_value->value = condition_value->value;
+ mojom_condition_value->match_type =
+ ConvertPatternMatchTypeToMojomPatternMatchType(
+ condition_value->match_type);
+ return mojom_condition_value;
+}
+
+ConditionPtr ConvertMojomConditionToCondition(
+ const apps::mojom::ConditionPtr& mojom_condition) {
+ if (!mojom_condition) {
+ return nullptr;
+ }
+
+ ConditionValues values;
+ for (const auto& condition_value : mojom_condition->condition_values) {
+ values.push_back(
+ ConvertMojomConditionValueToConditionValue(condition_value));
+ }
+ return std::make_unique<Condition>(
+ ConvertMojomConditionTypeToConditionType(mojom_condition->condition_type),
+ std::move(values));
+}
+
+apps::mojom::ConditionPtr ConvertConditionToMojomCondition(
+ const ConditionPtr& condition) {
+ auto mojom_condition = apps::mojom::Condition::New();
+ if (!condition) {
+ return mojom_condition;
+ }
+
+ mojom_condition->condition_type =
+ ConvertConditionTypeToMojomConditionType(condition->condition_type);
+
+ for (const auto& condition_value : condition->condition_values) {
+ if (condition_value) {
+ mojom_condition->condition_values.push_back(
+ ConvertConditionValueToMojomConditionValue(condition_value));
+ }
+ }
+ return mojom_condition;
+}
+
+IntentFilterPtr ConvertMojomIntentFilterToIntentFilter(
+ const apps::mojom::IntentFilterPtr& mojom_intent_filter) {
+ if (!mojom_intent_filter) {
+ return nullptr;
+ }
+
+ IntentFilterPtr intent_filter = std::make_unique<IntentFilter>();
+ for (const auto& condition : mojom_intent_filter->conditions) {
+ if (condition) {
+ intent_filter->conditions.push_back(
+ ConvertMojomConditionToCondition(condition));
+ }
+ }
+
+ if (mojom_intent_filter->activity_name.has_value())
+ intent_filter->activity_name = mojom_intent_filter->activity_name.value();
+
+ if (mojom_intent_filter->activity_label.has_value())
+ intent_filter->activity_label = mojom_intent_filter->activity_label.value();
+
+ return intent_filter;
+}
+
+apps::mojom::IntentFilterPtr ConvertIntentFilterToMojomIntentFilter(
+ const IntentFilterPtr& intent_filter) {
+ auto mojom_intent_filter = apps::mojom::IntentFilter::New();
+ if (!intent_filter) {
+ return mojom_intent_filter;
+ }
+
+ for (const auto& condition : intent_filter->conditions) {
+ if (condition) {
+ mojom_intent_filter->conditions.push_back(
+ ConvertConditionToMojomCondition(condition));
+ }
+ }
+
+ mojom_intent_filter->activity_name = intent_filter->activity_name;
+ mojom_intent_filter->activity_label = intent_filter->activity_label;
+ return mojom_intent_filter;
+}
+
+base::flat_map<std::string, std::vector<apps::mojom::IntentFilterPtr>>
+ConvertIntentFiltersToMojomIntentFilters(
+ const base::flat_map<std::string, apps::IntentFilters>& intent_filter) {
+ base::flat_map<std::string, std::vector<apps::mojom::IntentFilterPtr>> ret;
+ for (const auto& it : intent_filter) {
+ std::vector<apps::mojom::IntentFilterPtr> mojom_filters;
+ for (const auto& filter_it : it.second) {
+ if (filter_it) {
+ mojom_filters.push_back(
+ ConvertIntentFilterToMojomIntentFilter(filter_it));
+ }
+ }
+ ret[it.first] = std::move(mojom_filters);
+ }
+ return ret;
+}
+
+base::flat_map<std::string, apps::IntentFilters>
+ConvertMojomIntentFiltersToIntentFilters(
+ const base::flat_map<std::string,
+ std::vector<apps::mojom::IntentFilterPtr>>&
+ mojom_intent_filter) {
+ base::flat_map<std::string, apps::IntentFilters> ret;
+ for (const auto& it : mojom_intent_filter) {
+ apps::IntentFilters filters;
+ for (const auto& filter_it : it.second) {
+ if (filter_it)
+ filters.push_back(ConvertMojomIntentFilterToIntentFilter(filter_it));
+ }
+ ret[it.first] = std::move(filters);
+ }
+ return ret;
+}
+
+} // namespace apps
diff --git a/chromium/components/services/app_service/public/cpp/intent_filter.h b/chromium/components/services/app_service/public/cpp/intent_filter.h
new file mode 100644
index 00000000000..7b1ba9bf476
--- /dev/null
+++ b/chromium/components/services/app_service/public/cpp/intent_filter.h
@@ -0,0 +1,167 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_SERVICES_APP_SERVICE_PUBLIC_CPP_INTENT_FILTER_H_
+#define COMPONENTS_SERVICES_APP_SERVICE_PUBLIC_CPP_INTENT_FILTER_H_
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/component_export.h"
+#include "base/containers/flat_map.h"
+#include "components/services/app_service/public/mojom/types.mojom.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace apps {
+
+// The intent filter matching condition types.
+enum class ConditionType {
+ kScheme, // Matches the URL scheme (e.g. https, tel).
+ kHost, // Matches the URL host (e.g. www.google.com).
+ kPattern, // Matches the URL pattern (e.g. /abc/*).
+ kAction, // Matches the action type (e.g. view, send).
+ kMimeType, // Matches the top-level mime type (e.g. text/plain).
+ kFile, // Matches against all files.
+};
+
+// The pattern match type for intent filter pattern condition.
+enum class PatternMatchType {
+ kNone = 0,
+ kLiteral,
+ kPrefix,
+ kGlob,
+ kMimeType,
+ kFileExtension,
+ kIsDirectory,
+};
+
+// For pattern type of condition, the value match will be based on the pattern
+// match type. If the match_type is kNone, then an exact match with the value
+// will be required.
+struct COMPONENT_EXPORT(APP_TYPES) ConditionValue {
+ ConditionValue(const std::string& value, PatternMatchType match_type);
+ ConditionValue(const ConditionValue&) = delete;
+ ConditionValue& operator=(const ConditionValue&) = delete;
+ ~ConditionValue();
+
+ bool operator==(const ConditionValue& other) const;
+ bool operator!=(const ConditionValue& other) const;
+
+ std::string value;
+ PatternMatchType match_type; // This will be None for non pattern conditions.
+};
+
+using ConditionValuePtr = std::unique_ptr<ConditionValue>;
+using ConditionValues = std::vector<ConditionValuePtr>;
+
+// The condition for an intent filter. It matches if the intent contains this
+// condition type and the corresponding value matches with any of the
+// condition_values.
+struct COMPONENT_EXPORT(APP_TYPES) Condition {
+ Condition(ConditionType condition_type, ConditionValues condition_values);
+ Condition(const Condition&) = delete;
+ Condition& operator=(const Condition&) = delete;
+ ~Condition();
+
+ bool operator==(const Condition& other) const;
+ bool operator!=(const Condition& other) const;
+
+ std::unique_ptr<Condition> Clone() const;
+
+ ConditionType condition_type;
+ ConditionValues condition_values;
+};
+
+using ConditionPtr = std::unique_ptr<Condition>;
+using Conditions = std::vector<ConditionPtr>;
+
+// An intent filter is defined by an app, and contains a list of conditions that
+// an intent needs to match. If all conditions match, then this intent filter
+// matches against an intent.
+struct COMPONENT_EXPORT(APP_TYPES) IntentFilter {
+ IntentFilter();
+ IntentFilter(const IntentFilter&) = delete;
+ IntentFilter& operator=(const IntentFilter&) = delete;
+ ~IntentFilter();
+
+ bool operator==(const IntentFilter& other) const;
+ bool operator!=(const IntentFilter& other) const;
+
+ std::unique_ptr<IntentFilter> Clone() const;
+
+ Conditions conditions;
+
+ // Activity which registered this filter. We only fill this field for ARC
+ // share intent filters and Web App file_handlers.
+ absl::optional<std::string> activity_name;
+
+ // The label shown to the user for this activity.
+ absl::optional<std::string> activity_label;
+};
+
+using IntentFilterPtr = std::unique_ptr<IntentFilter>;
+using IntentFilters = std::vector<IntentFilterPtr>;
+
+// Creates a deep copy of `intent_filters`.
+COMPONENT_EXPORT(APP_TYPES)
+IntentFilters CloneIntentFilters(const IntentFilters& intent_filters);
+
+// TODO(crbug.com/1253250): Remove these functions after migrating to non-mojo
+// AppService.
+COMPONENT_EXPORT(APP_TYPES)
+ConditionType ConvertMojomConditionTypeToConditionType(
+ const apps::mojom::ConditionType& mojom_condition_type);
+
+COMPONENT_EXPORT(APP_TYPES)
+apps::mojom::ConditionType ConvertConditionTypeToMojomConditionType(
+ const ConditionType& condition_type);
+
+COMPONENT_EXPORT(APP_TYPES)
+PatternMatchType ConvertMojomPatternMatchTypeToPatternMatchType(
+ const apps::mojom::PatternMatchType& mojom_pattern_match_type);
+
+COMPONENT_EXPORT(APP_TYPES)
+apps::mojom::PatternMatchType ConvertPatternMatchTypeToMojomPatternMatchType(
+ const PatternMatchType& pattern_match_type);
+
+COMPONENT_EXPORT(APP_TYPES)
+ConditionValuePtr ConvertMojomConditionValueToConditionValue(
+ const apps::mojom::ConditionValuePtr& mojom_condition_value);
+
+COMPONENT_EXPORT(APP_TYPES)
+apps::mojom::ConditionValuePtr ConvertConditionValueToMojomConditionValue(
+ const ConditionValuePtr& condition_value);
+
+COMPONENT_EXPORT(APP_TYPES)
+ConditionPtr ConvertMojomConditionToCondition(
+ const apps::mojom::ConditionPtr& mojom_condition);
+
+COMPONENT_EXPORT(APP_TYPES)
+apps::mojom::ConditionPtr ConvertConditionToMojomCondition(
+ const ConditionPtr& condition);
+
+COMPONENT_EXPORT(APP_TYPES)
+IntentFilterPtr ConvertMojomIntentFilterToIntentFilter(
+ const apps::mojom::IntentFilterPtr& mojom_intent_filter);
+
+COMPONENT_EXPORT(APP_TYPES)
+apps::mojom::IntentFilterPtr ConvertIntentFilterToMojomIntentFilter(
+ const IntentFilterPtr& intent_filter);
+
+COMPONENT_EXPORT(APP_TYPES)
+base::flat_map<std::string, std::vector<apps::mojom::IntentFilterPtr>>
+ConvertIntentFiltersToMojomIntentFilters(
+ const base::flat_map<std::string, apps::IntentFilters>& intent_filter);
+
+COMPONENT_EXPORT(APP_TYPES)
+base::flat_map<std::string, apps::IntentFilters>
+ConvertMojomIntentFiltersToIntentFilters(
+ const base::flat_map<std::string,
+ std::vector<apps::mojom::IntentFilterPtr>>&
+ mojom_intent_filter);
+
+} // namespace apps
+
+#endif // COMPONENTS_SERVICES_APP_SERVICE_PUBLIC_CPP_INTENT_FILTER_H_
diff --git a/chromium/components/services/app_service/public/cpp/intent_filter_util.cc b/chromium/components/services/app_service/public/cpp/intent_filter_util.cc
index ca849f67af7..811cb6fb04c 100644
--- a/chromium/components/services/app_service/public/cpp/intent_filter_util.cc
+++ b/chromium/components/services/app_service/public/cpp/intent_filter_util.cc
@@ -84,6 +84,17 @@ apps::mojom::ConditionPtr MakeCondition(
return condition;
}
+void AddSingleValueCondition(apps::ConditionType condition_type,
+ const std::string& value,
+ apps::PatternMatchType pattern_match_type,
+ apps::IntentFilterPtr& intent_filter) {
+ apps::ConditionValues condition_values;
+ condition_values.push_back(
+ std::make_unique<apps::ConditionValue>(value, pattern_match_type));
+ intent_filter->conditions.push_back(std::make_unique<apps::Condition>(
+ condition_type, std::move(condition_values)));
+}
+
void AddSingleValueCondition(apps::mojom::ConditionType condition_type,
const std::string& value,
apps::mojom::PatternMatchType pattern_match_type,
diff --git a/chromium/components/services/app_service/public/cpp/intent_filter_util.h b/chromium/components/services/app_service/public/cpp/intent_filter_util.h
index 8624079f7a6..e4ec59576ad 100644
--- a/chromium/components/services/app_service/public/cpp/intent_filter_util.h
+++ b/chromium/components/services/app_service/public/cpp/intent_filter_util.h
@@ -9,6 +9,7 @@
#include <string>
+#include "components/services/app_service/public/cpp/intent_filter.h"
#include "components/services/app_service/public/mojom/types.mojom.h"
#include "url/gurl.h"
@@ -47,6 +48,12 @@ apps::mojom::ConditionPtr MakeCondition(
// Creates condition that only contain one value and add the condition to
// the intent filter.
+void AddSingleValueCondition(apps::ConditionType condition_type,
+ const std::string& value,
+ apps::PatternMatchType pattern_match_type,
+ apps::IntentFilterPtr& intent_filter);
+
+// TODO(crbug.com/1253250): Remove after migrating to non-mojo AppService.
void AddSingleValueCondition(apps::mojom::ConditionType condition_type,
const std::string& value,
apps::mojom::PatternMatchType pattern_match_type,
diff --git a/chromium/components/services/app_service/public/cpp/intent_filter_util_unittest.cc b/chromium/components/services/app_service/public/cpp/intent_filter_util_unittest.cc
index 190ad7d3570..bb6e1140105 100644
--- a/chromium/components/services/app_service/public/cpp/intent_filter_util_unittest.cc
+++ b/chromium/components/services/app_service/public/cpp/intent_filter_util_unittest.cc
@@ -5,6 +5,7 @@
#include "components/services/app_service/public/cpp/intent_filter_util.h"
#include "base/values.h"
+#include "components/services/app_service/public/cpp/intent_filter.h"
#include "components/services/app_service/public/cpp/intent_test_util.h"
#include "components/services/app_service/public/cpp/intent_util.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -370,3 +371,108 @@ TEST_F(IntentFilterUtilTest, PatternGlobAndLiteralOverlap) {
ASSERT_FALSE(apps_util::FiltersHaveOverlap(literal_pattern_filter2,
glob_pattern_filter));
}
+
+TEST_F(IntentFilterUtilTest, IntentFiltersConvert) {
+ base::flat_map<std::string, std::vector<apps::IntentFilterPtr>> filters;
+
+ auto intent_filter1 = std::make_unique<apps::IntentFilter>();
+ apps_util::AddSingleValueCondition(apps::ConditionType::kScheme, "1",
+ apps::PatternMatchType::kNone,
+ intent_filter1);
+ filters["1"].push_back(std::move(intent_filter1));
+
+ auto intent_filter2 = std::make_unique<apps::IntentFilter>();
+ apps_util::AddSingleValueCondition(apps::ConditionType::kHost, "2",
+ apps::PatternMatchType::kLiteral,
+ intent_filter2);
+ apps_util::AddSingleValueCondition(apps::ConditionType::kPattern, "3",
+ apps::PatternMatchType::kPrefix,
+ intent_filter2);
+ filters["1"].push_back(std::move(intent_filter2));
+
+ apps::IntentFilters intent_filters2;
+ auto intent_filter3 = std::make_unique<apps::IntentFilter>();
+ apps_util::AddSingleValueCondition(apps::ConditionType::kAction, "4",
+ apps::PatternMatchType::kGlob,
+ intent_filter3);
+ apps_util::AddSingleValueCondition(apps::ConditionType::kMimeType, "5",
+ apps::PatternMatchType::kMimeType,
+ intent_filter3);
+ filters["2"].push_back(std::move(intent_filter3));
+
+ auto intent_filter4 = std::make_unique<apps::IntentFilter>();
+ apps_util::AddSingleValueCondition(apps::ConditionType::kFile, "6",
+ apps::PatternMatchType::kMimeType,
+ intent_filter4);
+ apps_util::AddSingleValueCondition(apps::ConditionType::kFile, "7",
+ apps::PatternMatchType::kFileExtension,
+ intent_filter4);
+ filters["2"].push_back(std::move(intent_filter4));
+
+ auto output = apps::ConvertMojomIntentFiltersToIntentFilters(
+ apps::ConvertIntentFiltersToMojomIntentFilters(filters));
+
+ ASSERT_EQ(output.size(), 2U);
+ EXPECT_EQ(*filters["1"][0], *output["1"][0]);
+ EXPECT_EQ(*filters["1"][1], *output["1"][1]);
+
+ EXPECT_EQ(*filters["2"][0], *output["2"][0]);
+ EXPECT_EQ(*filters["2"][1], *output["2"][1]);
+
+ {
+ auto& condition = output["1"][0]->conditions[0];
+ EXPECT_EQ(condition->condition_type, apps::ConditionType::kScheme);
+ ASSERT_EQ(condition->condition_values.size(), 1U);
+ EXPECT_EQ(condition->condition_values[0]->match_type,
+ apps::PatternMatchType::kNone);
+ EXPECT_EQ(condition->condition_values[0]->value, "1");
+ }
+ {
+ auto& condition = output["1"][1]->conditions[0];
+ EXPECT_EQ(condition->condition_type, apps::ConditionType::kHost);
+ ASSERT_EQ(condition->condition_values.size(), 1U);
+ EXPECT_EQ(condition->condition_values[0]->match_type,
+ apps::PatternMatchType::kLiteral);
+ EXPECT_EQ(condition->condition_values[0]->value, "2");
+ }
+ {
+ auto& condition = output["1"][1]->conditions[1];
+ EXPECT_EQ(condition->condition_type, apps::ConditionType::kPattern);
+ ASSERT_EQ(condition->condition_values.size(), 1U);
+ EXPECT_EQ(condition->condition_values[0]->match_type,
+ apps::PatternMatchType::kPrefix);
+ EXPECT_EQ(condition->condition_values[0]->value, "3");
+ }
+ {
+ auto& condition = output["2"][0]->conditions[0];
+ EXPECT_EQ(condition->condition_type, apps::ConditionType::kAction);
+ ASSERT_EQ(condition->condition_values.size(), 1U);
+ EXPECT_EQ(condition->condition_values[0]->match_type,
+ apps::PatternMatchType::kGlob);
+ EXPECT_EQ(condition->condition_values[0]->value, "4");
+ }
+ {
+ auto& condition = output["2"][0]->conditions[1];
+ EXPECT_EQ(condition->condition_type, apps::ConditionType::kMimeType);
+ ASSERT_EQ(condition->condition_values.size(), 1U);
+ EXPECT_EQ(condition->condition_values[0]->match_type,
+ apps::PatternMatchType::kMimeType);
+ EXPECT_EQ(condition->condition_values[0]->value, "5");
+ }
+ {
+ auto& condition = output["2"][1]->conditions[0];
+ EXPECT_EQ(condition->condition_type, apps::ConditionType::kFile);
+ ASSERT_EQ(condition->condition_values.size(), 1U);
+ EXPECT_EQ(condition->condition_values[0]->match_type,
+ apps::PatternMatchType::kMimeType);
+ EXPECT_EQ(condition->condition_values[0]->value, "6");
+ }
+ {
+ auto& condition = output["2"][1]->conditions[1];
+ EXPECT_EQ(condition->condition_type, apps::ConditionType::kFile);
+ ASSERT_EQ(condition->condition_values.size(), 1U);
+ EXPECT_EQ(condition->condition_values[0]->match_type,
+ apps::PatternMatchType::kFileExtension);
+ EXPECT_EQ(condition->condition_values[0]->value, "7");
+ }
+}
diff --git a/chromium/components/services/app_service/public/cpp/intent_util.cc b/chromium/components/services/app_service/public/cpp/intent_util.cc
index d08a4483572..57d426c8753 100644
--- a/chromium/components/services/app_service/public/cpp/intent_util.cc
+++ b/chromium/components/services/app_service/public/cpp/intent_util.cc
@@ -610,22 +610,20 @@ base::Value ConvertIntentToValue(const apps::mojom::IntentPtr& intent) {
absl::optional<std::string> GetStringValueFromDict(
const base::DictionaryValue& dict,
const std::string& key_name) {
- if (!dict.HasKey(key_name))
+ const base::Value* value = dict.FindKey(key_name);
+ if (!value)
return absl::nullopt;
- const std::string* value = dict.FindStringKey(key_name);
- if (!value || value->empty())
+ const std::string* string_value = value->GetIfString();
+ if (!string_value || string_value->empty())
return absl::nullopt;
- return *value;
+ return *string_value;
}
apps::mojom::OptionalBool GetBoolValueFromDict(
const base::DictionaryValue& dict,
const std::string& key_name) {
- if (!dict.HasKey(key_name))
- return apps::mojom::OptionalBool::kUnknown;
-
absl::optional<bool> value = dict.FindBoolKey(key_name);
if (!value.has_value())
return apps::mojom::OptionalBool::kUnknown;
@@ -636,9 +634,6 @@ apps::mojom::OptionalBool GetBoolValueFromDict(
absl::optional<GURL> GetGurlValueFromDict(const base::DictionaryValue& dict,
const std::string& key_name) {
- if (!dict.HasKey(key_name))
- return absl::nullopt;
-
const std::string* url_spec = dict.FindStringKey(key_name);
if (!url_spec)
return absl::nullopt;
@@ -653,15 +648,12 @@ absl::optional<GURL> GetGurlValueFromDict(const base::DictionaryValue& dict,
absl::optional<std::vector<apps::mojom::IntentFilePtr>> GetFilesFromDict(
const base::DictionaryValue& dict,
const std::string& key_name) {
- if (!dict.HasKey(key_name))
- return absl::nullopt;
-
const base::Value* value = dict.FindListKey(key_name);
- if (!value || !value->is_list() || value->GetList().empty())
+ if (!value || !value->is_list() || value->GetListDeprecated().empty())
return absl::nullopt;
std::vector<apps::mojom::IntentFilePtr> files;
- for (const auto& item : value->GetList()) {
+ for (const auto& item : value->GetListDeprecated()) {
GURL url(item.GetString());
if (url.is_valid()) {
auto file = apps::mojom::IntentFile::New();
@@ -675,15 +667,12 @@ absl::optional<std::vector<apps::mojom::IntentFilePtr>> GetFilesFromDict(
absl::optional<std::vector<std::string>> GetCategoriesFromDict(
const base::DictionaryValue& dict,
const std::string& key_name) {
- if (!dict.HasKey(key_name))
- return absl::nullopt;
-
const base::Value* value = dict.FindListKey(key_name);
- if (!value || !value->is_list() || value->GetList().empty())
+ if (!value || !value->is_list() || value->GetListDeprecated().empty())
return absl::nullopt;
std::vector<std::string> categories;
- for (const auto& item : value->GetList())
+ for (const auto& item : value->GetListDeprecated())
categories.push_back(item.GetString());
return categories;
@@ -692,9 +681,6 @@ absl::optional<std::vector<std::string>> GetCategoriesFromDict(
absl::optional<base::flat_map<std::string, std::string>> GetExtrasFromDict(
const base::DictionaryValue& dict,
const std::string& key_name) {
- if (!dict.HasKey(key_name))
- return absl::nullopt;
-
const base::Value* value = dict.FindDictKey(key_name);
if (!value || !value->is_dict())
return absl::nullopt;
diff --git a/chromium/components/services/app_service/public/cpp/macros.h b/chromium/components/services/app_service/public/cpp/macros.h
index 9cef7b39213..6e7d30d9844 100644
--- a/chromium/components/services/app_service/public/cpp/macros.h
+++ b/chromium/components/services/app_service/public/cpp/macros.h
@@ -7,6 +7,16 @@
namespace apps {
+#define SET_OPTIONAL_VALUE(VALUE) \
+ if (delta->VALUE.has_value()) { \
+ state->VALUE = delta->VALUE; \
+ }
+
+#define SET_ENUM_VALUE(VALUE, DEFAULT_VALUE) \
+ if (delta->VALUE != DEFAULT_VALUE) { \
+ state->VALUE = delta->VALUE; \
+ }
+
#define GET_VALUE(VALUE) \
if (delta_ && delta_->VALUE()) { \
return delta_->VALUE(); \
@@ -20,12 +30,21 @@ namespace apps {
return delta_ && delta_->VALUE() && \
(!state_ || (delta_->VALUE() != state_->VALUE()));
+#define GET_VALUE_WITH_FALLBACK(VALUE, FALLBACK_VALUE) \
+ if (delta_ && delta_->VALUE.has_value()) { \
+ return delta_->VALUE.value(); \
+ } \
+ if (state_ && state_->VALUE.has_value()) { \
+ return state_->VALUE.value(); \
+ } \
+ return FALLBACK_VALUE;
+
#define GET_VALUE_WITH_DEFAULT_VALUE(VALUE, DEFAULT_VALUE) \
- if (delta_ && delta_->VALUE() != (DEFAULT_VALUE)) { \
- return delta_->VALUE(); \
+ if (delta_ && delta_->VALUE != (DEFAULT_VALUE)) { \
+ return delta_->VALUE; \
} \
if (state_) { \
- return state_->VALUE(); \
+ return state_->VALUE; \
} \
return DEFAULT_VALUE;
@@ -34,11 +53,11 @@ namespace apps {
(!state_ || (delta_->VALUE() != state_->VALUE()));
#define GET_VALUE_WITH_CHECK_AND_DEFAULT_RETURN(VALUE, CHECK, DEFAULT_RETURN) \
- if (delta_ && !delta_->VALUE().CHECK()) { \
- return delta_->VALUE(); \
+ if (delta_ && !delta_->VALUE.CHECK()) { \
+ return delta_->VALUE; \
} \
- if (state_ && !state_->VALUE().CHECK()) { \
- return state_->VALUE(); \
+ if (state_ && !state_->VALUE.CHECK()) { \
+ return state_->VALUE; \
} \
return DEFAULT_RETURN;
diff --git a/chromium/components/services/app_service/public/cpp/permission.cc b/chromium/components/services/app_service/public/cpp/permission.cc
new file mode 100644
index 00000000000..7e91f5ab680
--- /dev/null
+++ b/chromium/components/services/app_service/public/cpp/permission.cc
@@ -0,0 +1,213 @@
+// Copyright 2022 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.
+
+#include "components/services/app_service/public/cpp/permission.h"
+
+namespace apps {
+
+PermissionValue::PermissionValue(bool bool_value) : bool_value(bool_value) {}
+
+PermissionValue::PermissionValue(TriState tristate_value)
+ : tristate_value(tristate_value) {}
+
+PermissionValue::~PermissionValue() = default;
+
+bool PermissionValue::operator==(const PermissionValue& other) const {
+ if (tristate_value.has_value() && other.tristate_value.has_value()) {
+ return tristate_value.value() == other.tristate_value.value();
+ }
+
+ if (bool_value.has_value() && other.bool_value.has_value()) {
+ return bool_value.value() == other.bool_value.value();
+ }
+
+ return false;
+}
+
+std::unique_ptr<PermissionValue> PermissionValue::Clone() const {
+ if (tristate_value.has_value()) {
+ return std::make_unique<PermissionValue>(tristate_value.value());
+ }
+
+ if (bool_value.has_value()) {
+ return std::make_unique<PermissionValue>(bool_value.value());
+ }
+
+ return nullptr;
+}
+
+bool PermissionValue::IsPermissionEnabled() {
+ if (tristate_value.has_value()) {
+ return tristate_value.value() == TriState::kAllow;
+ } else if (bool_value.has_value()) {
+ return bool_value.value();
+ }
+ return false;
+}
+
+Permission::Permission(PermissionType permission_type,
+ PermissionValuePtr value,
+ bool is_managed)
+ : permission_type(permission_type),
+ value(std::move(value)),
+ is_managed(is_managed) {}
+
+Permission::~Permission() = default;
+
+bool Permission::operator==(const Permission& other) const {
+ return permission_type == other.permission_type &&
+ ((!value && !other.value) || (*value == *other.value)) &&
+ is_managed == other.is_managed;
+}
+
+bool Permission::operator!=(const Permission& other) const {
+ return !(*this == other);
+}
+
+PermissionPtr Permission::Clone() const {
+ if (!value) {
+ return nullptr;
+ }
+
+ return std::make_unique<Permission>(permission_type, value->Clone(),
+ is_managed);
+}
+
+Permissions ClonePermissions(const Permissions& source_permissions) {
+ Permissions permissions;
+ for (const auto& permission : source_permissions) {
+ permissions.push_back(permission->Clone());
+ }
+ return permissions;
+}
+
+PermissionType ConvertMojomPermissionTypeToPermissionType(
+ apps::mojom::PermissionType mojom_permission_type) {
+ switch (mojom_permission_type) {
+ case apps::mojom::PermissionType::kUnknown:
+ return PermissionType::kUnknown;
+ case apps::mojom::PermissionType::kCamera:
+ return PermissionType::kCamera;
+ case apps::mojom::PermissionType::kLocation:
+ return PermissionType::kLocation;
+ case apps::mojom::PermissionType::kMicrophone:
+ return PermissionType::kMicrophone;
+ case apps::mojom::PermissionType::kNotifications:
+ return PermissionType::kNotifications;
+ case apps::mojom::PermissionType::kContacts:
+ return PermissionType::kContacts;
+ case apps::mojom::PermissionType::kStorage:
+ return PermissionType::kStorage;
+ case apps::mojom::PermissionType::kPrinting:
+ return PermissionType::kPrinting;
+ }
+}
+
+apps::mojom::PermissionType ConvertPermissionTypeToMojomPermissionType(
+ PermissionType permission_type) {
+ switch (permission_type) {
+ case PermissionType::kUnknown:
+ return apps::mojom::PermissionType::kUnknown;
+ case PermissionType::kCamera:
+ return apps::mojom::PermissionType::kCamera;
+ case PermissionType::kLocation:
+ return apps::mojom::PermissionType::kLocation;
+ case PermissionType::kMicrophone:
+ return apps::mojom::PermissionType::kMicrophone;
+ case PermissionType::kNotifications:
+ return apps::mojom::PermissionType::kNotifications;
+ case PermissionType::kContacts:
+ return apps::mojom::PermissionType::kContacts;
+ case PermissionType::kStorage:
+ return apps::mojom::PermissionType::kStorage;
+ case PermissionType::kPrinting:
+ return apps::mojom::PermissionType::kPrinting;
+ }
+}
+
+TriState ConvertMojomTriStateToTriState(apps::mojom::TriState mojom_tri_state) {
+ switch (mojom_tri_state) {
+ case apps::mojom::TriState::kAllow:
+ return TriState::kAllow;
+ case apps::mojom::TriState::kBlock:
+ return TriState::kBlock;
+ case apps::mojom::TriState::kAsk:
+ return TriState::kAsk;
+ }
+}
+
+apps::mojom::TriState ConvertTriStateToMojomTriState(TriState tri_state) {
+ switch (tri_state) {
+ case TriState::kAllow:
+ return apps::mojom::TriState::kAllow;
+ case TriState::kBlock:
+ return apps::mojom::TriState::kBlock;
+ case TriState::kAsk:
+ return apps::mojom::TriState::kAsk;
+ }
+}
+
+PermissionValuePtr ConvertMojomPermissionValueToPermissionValue(
+ const apps::mojom::PermissionValuePtr& mojom_permission_value) {
+ if (!mojom_permission_value) {
+ return nullptr;
+ }
+
+ if (mojom_permission_value->is_tristate_value()) {
+ return std::make_unique<PermissionValue>(ConvertMojomTriStateToTriState(
+ mojom_permission_value->get_tristate_value()));
+ } else if (mojom_permission_value->is_bool_value()) {
+ return std::make_unique<PermissionValue>(
+ mojom_permission_value->get_bool_value());
+ }
+ return nullptr;
+}
+
+apps::mojom::PermissionValuePtr ConvertPermissionValueToMojomPermissionValue(
+ const PermissionValuePtr& permission_value) {
+ auto mojom_permission_value = apps::mojom::PermissionValue::New();
+ if (!permission_value) {
+ return mojom_permission_value;
+ }
+
+ if (permission_value->bool_value.has_value()) {
+ mojom_permission_value->set_bool_value(
+ permission_value->bool_value.value());
+ }
+ if (permission_value->tristate_value.has_value()) {
+ mojom_permission_value->set_tristate_value(ConvertTriStateToMojomTriState(
+ permission_value->tristate_value.value()));
+ }
+ return mojom_permission_value;
+}
+
+PermissionPtr ConvertMojomPermissionToPermission(
+ const apps::mojom::PermissionPtr& mojom_permission) {
+ if (!mojom_permission) {
+ return nullptr;
+ }
+
+ return std::make_unique<Permission>(
+ ConvertMojomPermissionTypeToPermissionType(
+ mojom_permission->permission_type),
+ ConvertMojomPermissionValueToPermissionValue(mojom_permission->value),
+ mojom_permission->is_managed);
+}
+
+apps::mojom::PermissionPtr ConvertPermissionToMojomPermission(
+ const PermissionPtr& permission) {
+ auto mojom_permission = apps::mojom::Permission::New();
+ if (!permission) {
+ return mojom_permission;
+ }
+
+ mojom_permission->permission_type =
+ ConvertPermissionTypeToMojomPermissionType(permission->permission_type);
+ mojom_permission->value =
+ ConvertPermissionValueToMojomPermissionValue(permission->value);
+ mojom_permission->is_managed = permission->is_managed;
+ return mojom_permission;
+}
+
+} // namespace apps
diff --git a/chromium/components/services/app_service/public/cpp/permission.h b/chromium/components/services/app_service/public/cpp/permission.h
new file mode 100644
index 00000000000..1483cf52b8a
--- /dev/null
+++ b/chromium/components/services/app_service/public/cpp/permission.h
@@ -0,0 +1,117 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_SERVICES_APP_SERVICE_PUBLIC_CPP_PERMISSION_H_
+#define COMPONENTS_SERVICES_APP_SERVICE_PUBLIC_CPP_PERMISSION_H_
+
+#include <utility>
+#include <vector>
+
+#include "base/component_export.h"
+#include "components/services/app_service/public/mojom/types.mojom.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace apps {
+
+// The types of permissions in App Service.
+enum class PermissionType {
+ kUnknown = 0,
+ kCamera = 1,
+ kLocation = 2,
+ kMicrophone = 3,
+ kNotifications = 4,
+ kContacts = 5,
+ kStorage = 6,
+ kPrinting = 7,
+};
+
+enum class TriState {
+ kAllow,
+ kBlock,
+ kAsk,
+};
+
+// The permission value could be a TriState or a bool
+struct COMPONENT_EXPORT(APP_TYPES) PermissionValue {
+ explicit PermissionValue(bool bool_value);
+ explicit PermissionValue(TriState tristate_value);
+ PermissionValue(const PermissionValue&) = delete;
+ PermissionValue& operator=(const PermissionValue&) = delete;
+ ~PermissionValue();
+
+ bool operator==(const PermissionValue& other) const;
+
+ std::unique_ptr<PermissionValue> Clone() const;
+
+ // Checks whether this is equal to permission enabled. If it is TriState, only
+ // Allow represent permission enabled.
+ bool IsPermissionEnabled();
+
+ absl::optional<bool> bool_value;
+ absl::optional<TriState> tristate_value;
+};
+
+using PermissionValuePtr = std::unique_ptr<PermissionValue>;
+
+struct COMPONENT_EXPORT(APP_TYPES) Permission {
+ Permission(PermissionType permission_type,
+ PermissionValuePtr value,
+ bool is_managed);
+ Permission(const Permission&) = delete;
+ Permission& operator=(const Permission&) = delete;
+ ~Permission();
+
+ bool operator==(const Permission& other) const;
+ bool operator!=(const Permission& other) const;
+
+ std::unique_ptr<Permission> Clone() const;
+
+ PermissionType permission_type;
+ std::unique_ptr<PermissionValue> value;
+ // If the permission is managed by an enterprise policy.
+ bool is_managed;
+};
+
+using PermissionPtr = std::unique_ptr<Permission>;
+using Permissions = std::vector<PermissionPtr>;
+
+// Creates a deep copy of `source_permissions`.
+COMPONENT_EXPORT(APP_TYPES)
+Permissions ClonePermissions(const Permissions& source_permissions);
+
+// TODO(crbug.com/1253250): Remove these functions after migrating to non-mojo
+// AppService.
+COMPONENT_EXPORT(APP_TYPES)
+PermissionType ConvertMojomPermissionTypeToPermissionType(
+ apps::mojom::PermissionType mojom_permission_type);
+
+COMPONENT_EXPORT(APP_TYPES)
+apps::mojom::PermissionType ConvertPermissionTypeToMojomPermissionType(
+ PermissionType permission_type);
+
+COMPONENT_EXPORT(APP_TYPES)
+TriState ConvertMojomTriStateToTriState(apps::mojom::TriState mojom_tri_state);
+
+COMPONENT_EXPORT(APP_TYPES)
+apps::mojom::TriState ConvertTriStateToMojomTriState(TriState tri_state);
+
+COMPONENT_EXPORT(APP_TYPES)
+PermissionValuePtr ConvertMojomPermissionValueToPermissionValue(
+ const apps::mojom::PermissionValuePtr& mojom_permission_value);
+
+COMPONENT_EXPORT(APP_TYPES)
+apps::mojom::PermissionValuePtr ConvertPermissionValueToMojomPermissionValue(
+ const PermissionValuePtr& permission_value);
+
+COMPONENT_EXPORT(APP_TYPES)
+PermissionPtr ConvertMojomPermissionToPermission(
+ const apps::mojom::PermissionPtr& mojom_permission);
+
+COMPONENT_EXPORT(APP_TYPES)
+apps::mojom::PermissionPtr ConvertPermissionToMojomPermission(
+ const PermissionPtr& permission);
+
+} // namespace apps
+
+#endif // COMPONENTS_SERVICES_APP_SERVICE_PUBLIC_CPP_PERMISSION_H_
diff --git a/chromium/components/services/app_service/public/cpp/preferred_apps_converter.cc b/chromium/components/services/app_service/public/cpp/preferred_apps_converter.cc
index 0114a7944e2..e83d2165923 100644
--- a/chromium/components/services/app_service/public/cpp/preferred_apps_converter.cc
+++ b/chromium/components/services/app_service/public/cpp/preferred_apps_converter.cc
@@ -84,7 +84,7 @@ apps::mojom::ConditionPtr ParseValueToCondition(const base::Value& value) {
<< apps::kConditionValuesKey << "\" key with list value.";
return nullptr;
}
- for (auto& condition_value : condition_values->GetList()) {
+ for (auto& condition_value : condition_values->GetListDeprecated()) {
auto parsed_condition_value = ParseValueToConditionValue(condition_value);
if (!parsed_condition_value) {
DVLOG(0) << "Fail to parse condition. Cannot parse condition values";
@@ -102,7 +102,7 @@ apps::mojom::IntentFilterPtr ParseValueToIntentFilter(
return nullptr;
}
auto intent_filter = apps::mojom::IntentFilter::New();
- for (auto& condition : value->GetList()) {
+ for (auto& condition : value->GetListDeprecated()) {
auto parsed_condition = ParseValueToCondition(condition);
if (!parsed_condition) {
DVLOG(0) << "Fail to parse intent filter. Cannot parse conditions.";
@@ -160,7 +160,7 @@ PreferredAppsList::PreferredApps ParseValueToPreferredApps(
}
PreferredAppsList::PreferredApps preferred_apps;
- for (auto& entry : preferred_apps_list->GetList()) {
+ for (auto& entry : preferred_apps_list->GetListDeprecated()) {
auto* app_id = entry.FindStringKey(kAppIdKey);
if (!app_id) {
DVLOG(0) << "Fail to parse condition value. Cannot find \""
diff --git a/chromium/components/services/app_service/public/cpp/preferred_apps_converter_unittest.cc b/chromium/components/services/app_service/public/cpp/preferred_apps_converter_unittest.cc
index acc8599f795..b40d83862db 100644
--- a/chromium/components/services/app_service/public/cpp/preferred_apps_converter_unittest.cc
+++ b/chromium/components/services/app_service/public/cpp/preferred_apps_converter_unittest.cc
@@ -33,20 +33,21 @@ TEST_F(PreferredAppsConverterTest, ConvertSimpleEntry) {
auto* converted_preferred_apps =
converted_value.FindKey(apps::kPreferredAppsKey);
// Check that each entry is correct.
- ASSERT_EQ(1u, converted_preferred_apps->GetList().size());
- auto& entry = converted_preferred_apps->GetList()[0];
+ ASSERT_EQ(1u, converted_preferred_apps->GetListDeprecated().size());
+ auto& entry = converted_preferred_apps->GetListDeprecated()[0];
EXPECT_EQ(kAppId1, *entry.FindStringKey(apps::kAppIdKey));
auto* converted_intent_filter = entry.FindKey(apps::kIntentFilterKey);
ASSERT_EQ(intent_filter->conditions.size(),
- converted_intent_filter->GetList().size());
+ converted_intent_filter->GetListDeprecated().size());
for (size_t i = 0; i < intent_filter->conditions.size(); i++) {
auto& condition = intent_filter->conditions[i];
- auto& converted_condition = converted_intent_filter->GetList()[i];
+ auto& converted_condition = converted_intent_filter->GetListDeprecated()[i];
auto& condition_values = condition->condition_values;
auto converted_condition_values =
- converted_condition.FindKey(apps::kConditionValuesKey)->GetList();
+ converted_condition.FindKey(apps::kConditionValuesKey)
+ ->GetListDeprecated();
EXPECT_EQ(static_cast<int>(condition->condition_type),
converted_condition.FindIntKey(apps::kConditionTypeKey));
diff --git a/chromium/components/services/app_service/public/cpp/publisher_base.cc b/chromium/components/services/app_service/public/cpp/publisher_base.cc
index 2fb5657d845..9f1d5aa4e28 100644
--- a/chromium/components/services/app_service/public/cpp/publisher_base.cc
+++ b/chromium/components/services/app_service/public/cpp/publisher_base.cc
@@ -181,4 +181,10 @@ void PublisherBase::SetWindowMode(const std::string& app_id,
NOTIMPLEMENTED();
}
+void PublisherBase::SetRunOnOsLoginMode(
+ const std::string& app_id,
+ apps::mojom::RunOnOsLoginMode run_on_os_login_mode) {
+ NOTIMPLEMENTED();
+}
+
} // namespace apps
diff --git a/chromium/components/services/app_service/public/cpp/publisher_base.h b/chromium/components/services/app_service/public/cpp/publisher_base.h
index 20f8955123a..d5e4951902a 100644
--- a/chromium/components/services/app_service/public/cpp/publisher_base.h
+++ b/chromium/components/services/app_service/public/cpp/publisher_base.h
@@ -101,6 +101,9 @@ class PublisherBase : public apps::mojom::Publisher {
apps::mojom::OptionalBool locked) override;
void SetWindowMode(const std::string& app_id,
apps::mojom::WindowMode window_mode) override;
+ void SetRunOnOsLoginMode(
+ const std::string& app_id,
+ apps::mojom::RunOnOsLoginMode run_on_os_login_mode) override;
mojo::Receiver<apps::mojom::Publisher> receiver_{this};
};
diff --git a/chromium/components/services/app_service/public/cpp/run_on_os_login_types.cc b/chromium/components/services/app_service/public/cpp/run_on_os_login_types.cc
new file mode 100644
index 00000000000..0cf4bacdd45
--- /dev/null
+++ b/chromium/components/services/app_service/public/cpp/run_on_os_login_types.cc
@@ -0,0 +1,62 @@
+// Copyright 2022 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.
+
+#include "components/services/app_service/public/cpp/run_on_os_login_types.h"
+
+namespace apps {
+
+RunOnOsLogin::RunOnOsLogin() = default;
+
+RunOnOsLogin::RunOnOsLogin(RunOnOsLoginMode login_mode, bool is_managed)
+ : login_mode(login_mode), is_managed(is_managed) {}
+
+RunOnOsLogin::~RunOnOsLogin() = default;
+
+bool RunOnOsLogin::operator==(const RunOnOsLogin& other) const {
+ return login_mode == other.login_mode && is_managed == other.is_managed;
+}
+
+apps::mojom::RunOnOsLoginPtr ConvertRunOnOsLoginToMojomRunOnOsLogin(
+ const RunOnOsLogin& run_on_os_login) {
+ auto run_on_os_login_mojom = apps::mojom::RunOnOsLogin::New();
+ run_on_os_login_mojom->login_mode =
+ ConvertRunOnOsLoginModeToMojomRunOnOsLoginMode(
+ run_on_os_login.login_mode);
+ run_on_os_login_mojom->is_managed = run_on_os_login.is_managed;
+ return run_on_os_login_mojom;
+}
+
+std::unique_ptr<RunOnOsLogin> ConvertMojomRunOnOsLoginToRunOnOsLogin(
+ const apps::mojom::RunOnOsLoginPtr& run_on_os_login) {
+ DCHECK(run_on_os_login);
+ return std::make_unique<RunOnOsLogin>(
+ ConvertMojomRunOnOsLoginModeToRunOnOsLoginMode(
+ run_on_os_login->login_mode),
+ run_on_os_login->is_managed);
+}
+
+apps::mojom::RunOnOsLoginMode ConvertRunOnOsLoginModeToMojomRunOnOsLoginMode(
+ RunOnOsLoginMode login_mode) {
+ switch (login_mode) {
+ case RunOnOsLoginMode::kUnknown:
+ return apps::mojom::RunOnOsLoginMode::kUnknown;
+ case RunOnOsLoginMode::kNotRun:
+ return apps::mojom::RunOnOsLoginMode::kNotRun;
+ case RunOnOsLoginMode::kWindowed:
+ return apps::mojom::RunOnOsLoginMode::kWindowed;
+ }
+}
+
+RunOnOsLoginMode ConvertMojomRunOnOsLoginModeToRunOnOsLoginMode(
+ apps::mojom::RunOnOsLoginMode login_mode) {
+ switch (login_mode) {
+ case apps::mojom::RunOnOsLoginMode::kUnknown:
+ return RunOnOsLoginMode::kUnknown;
+ case apps::mojom::RunOnOsLoginMode::kNotRun:
+ return RunOnOsLoginMode::kNotRun;
+ case apps::mojom::RunOnOsLoginMode::kWindowed:
+ return RunOnOsLoginMode::kWindowed;
+ }
+}
+} // namespace apps \ No newline at end of file
diff --git a/chromium/components/services/app_service/public/cpp/run_on_os_login_types.h b/chromium/components/services/app_service/public/cpp/run_on_os_login_types.h
new file mode 100644
index 00000000000..fccf6d8a239
--- /dev/null
+++ b/chromium/components/services/app_service/public/cpp/run_on_os_login_types.h
@@ -0,0 +1,64 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_SERVICES_APP_SERVICE_PUBLIC_CPP_RUN_ON_OS_LOGIN_TYPES_H_
+#define COMPONENTS_SERVICES_APP_SERVICE_PUBLIC_CPP_RUN_ON_OS_LOGIN_TYPES_H_
+
+#include <vector>
+
+#include "base/component_export.h"
+#include "components/services/app_service/public/mojom/types.mojom.h"
+
+namespace apps {
+
+enum class RunOnOsLoginMode {
+ // kUnknown to be used for app_update.cc.
+ kUnknown,
+ // App won't run on OS Login.
+ kNotRun,
+ // App runs in windowed mode on OS Login.
+ kWindowed,
+};
+
+struct COMPONENT_EXPORT(LOGIN_MODE) RunOnOsLogin {
+ RunOnOsLogin();
+ RunOnOsLogin(RunOnOsLoginMode login_mode, bool is_managed);
+
+ RunOnOsLogin(const RunOnOsLogin&) = delete;
+ RunOnOsLogin& operator=(const RunOnOsLogin&) = delete;
+ RunOnOsLogin(RunOnOsLogin&&) = default;
+ RunOnOsLogin& operator=(RunOnOsLogin&&) = default;
+
+ bool operator==(const RunOnOsLogin& other) const;
+
+ ~RunOnOsLogin();
+
+ // RunOnOsLoginMode struct to be used
+ // to verify if the mode is set by policy
+ // or not.
+ RunOnOsLoginMode login_mode;
+ // If the run on os login mode is policy
+ // controlled or not.
+ bool is_managed;
+};
+
+COMPONENT_EXPORT(LOGIN_MODE)
+apps::mojom::RunOnOsLoginPtr ConvertRunOnOsLoginToMojomRunOnOsLogin(
+ const RunOnOsLogin& run_on_os_login);
+
+COMPONENT_EXPORT(LOGIN_MODE)
+std::unique_ptr<RunOnOsLogin> ConvertMojomRunOnOsLoginToRunOnOsLogin(
+ const apps::mojom::RunOnOsLoginPtr& run_on_os_login);
+
+COMPONENT_EXPORT(LOGIN_MODE)
+apps::mojom::RunOnOsLoginMode ConvertRunOnOsLoginModeToMojomRunOnOsLoginMode(
+ RunOnOsLoginMode login_mode);
+
+COMPONENT_EXPORT(LOGIN_MODE)
+RunOnOsLoginMode ConvertMojomRunOnOsLoginModeToRunOnOsLoginMode(
+ apps::mojom::RunOnOsLoginMode login_mode);
+
+} // namespace apps
+
+#endif // COMPONENTS_SERVICES_APP_SERVICE_PUBLIC_CPP_RUN_ON_OS_LOGIN_TYPES_H_ \ No newline at end of file
diff --git a/chromium/components/services/app_service/public/mojom/BUILD.gn b/chromium/components/services/app_service/public/mojom/BUILD.gn
index b2a043d80dd..76718d3985c 100644
--- a/chromium/components/services/app_service/public/mojom/BUILD.gn
+++ b/chromium/components/services/app_service/public/mojom/BUILD.gn
@@ -6,13 +6,13 @@ import("//mojo/public/tools/bindings/mojom.gni")
mojom("types") {
sources = [ "types.mojom" ]
+ webui_module_path = "/"
public_deps = [
"//mojo/public/mojom/base",
"//skia/public/mojom",
"//ui/gfx/geometry/mojom",
"//ui/gfx/image/mojom",
- "//ui/gfx/image/mojom",
"//ui/gfx/mojom",
"//ui/gfx/range/mojom",
"//url/mojom:url_mojom_gurl",
@@ -21,6 +21,7 @@ mojom("types") {
mojom("mojom") {
sources = [ "app_service.mojom" ]
+ webui_module_path = "/"
public_deps = [ ":types" ]
}
diff --git a/chromium/components/services/app_service/public/mojom/app_service.mojom b/chromium/components/services/app_service/public/mojom/app_service.mojom
index 7fcc26c101b..199129ed973 100644
--- a/chromium/components/services/app_service/public/mojom/app_service.mojom
+++ b/chromium/components/services/app_service/public/mojom/app_service.mojom
@@ -13,6 +13,9 @@ import "components/services/app_service/public/mojom/types.mojom";
// app's name and icon) that are satisfied by the appropriate provider.
//
// See components/services/app_service/README.md.
+//
+// Mojom AppService is DEPRECATED. When adding new interfaces, use AppPublisher
+// in chrome/browser/apps/app_service/publishers/app_publisher.h.
interface AppService {
// Called by a publisher of apps to register itself and its apps with the App
// Service.
@@ -166,6 +169,12 @@ interface AppService {
AppType app_type,
string app_id,
WindowMode window_mode);
+
+ // Set the mode for the app to be run on os login identified by |app_id|.
+ SetRunOnOsLoginMode(
+ AppType app_type,
+ string app_id,
+ RunOnOsLoginMode run_on_os_login_mode);
};
interface Publisher {
@@ -333,6 +342,12 @@ interface Publisher {
SetWindowMode(
string app_id,
WindowMode window_mode);
+
+ // Set the mode to run on OS Login for the app identified by |app_id|.
+ // Implemented if the publisher supports setting this mode for OS Login,
+ // otherwise should do nothing.
+ SetRunOnOsLoginMode(string app_id,
+ RunOnOsLoginMode run_on_os_login_mode);
};
// Subscriber works as a proxy, to receive a stream of apps from publishers,
diff --git a/chromium/components/services/app_service/public/mojom/types.mojom b/chromium/components/services/app_service/public/mojom/types.mojom
index b419afc1580..626bb17c7c9 100644
--- a/chromium/components/services/app_service/public/mojom/types.mojom
+++ b/chromium/components/services/app_service/public/mojom/types.mojom
@@ -91,7 +91,11 @@ struct App {
// Whether the app's display mode is in the browser or otherwise.
WindowMode window_mode;
- // When adding new fields, also update the Merge method and other helpers in
+ // Whether the app runs on os login.
+ RunOnOsLogin? run_on_os_login;
+ // When adding new fields, also update the App struct in
+ // components/services/app_service/public/cpp/app_types.* and the Merge method
+ // and other helpers in
// components/services/app_service/public/cpp/app_update.*
};
@@ -533,3 +537,24 @@ enum WindowMode {
// Opens in a tabbed app window
kTabbedWindow,
};
+
+// The RunOnOsLoginModes must be kept in sync
+// with RunOnOsLoginMode in
+// chrome/browser/web_applications/web_app_constants.h
+enum RunOnOsLoginMode {
+ kUnknown = 0,
+ // App won't run on OS Login.
+ kNotRun,
+ // App will run in windowed mode on OS Login.
+ kWindowed,
+};
+
+// RunOnOsLoginMode struct to be used
+// to verify if the mode is set by policy
+// or not.
+struct RunOnOsLogin {
+ RunOnOsLoginMode login_mode;
+ // If the run on os login mode is policy
+ // controlled or not.
+ bool is_managed;
+};
diff --git a/chromium/components/services/filesystem/directory_impl.cc b/chromium/components/services/filesystem/directory_impl.cc
index 82b49267de7..e484cc0eb29 100644
--- a/chromium/components/services/filesystem/directory_impl.cc
+++ b/chromium/components/services/filesystem/directory_impl.cc
@@ -259,7 +259,7 @@ void DirectoryImpl::IsWritable(const std::string& raw_path,
void DirectoryImpl::Flush(FlushCallback callback) {
// On Windows no need to sync directories. Their metadata will be updated when
// files are created, without an explicit sync.
-#if !defined(OS_WIN)
+#if !BUILDFLAG(IS_WIN)
base::File file(directory_path_,
base::File::FLAG_OPEN | base::File::FLAG_READ);
if (!file.IsValid()) {
diff --git a/chromium/components/services/filesystem/file_impl.cc b/chromium/components/services/filesystem/file_impl.cc
index 29e51005498..a8417ea7367 100644
--- a/chromium/components/services/filesystem/file_impl.cc
+++ b/chromium/components/services/filesystem/file_impl.cc
@@ -65,7 +65,7 @@ bool FileImpl::IsValid() const {
return file_.IsValid();
}
-#if !defined(OS_FUCHSIA)
+#if !BUILDFLAG(IS_FUCHSIA)
base::File::Error FileImpl::RawLockFile() {
return file_.Lock(base::File::LockMode::kExclusive);
}
@@ -73,7 +73,7 @@ base::File::Error FileImpl::RawLockFile() {
base::File::Error FileImpl::RawUnlockFile() {
return file_.Unlock();
}
-#endif // !OS_FUCHSIA
+#endif // !BUILDFLAG(IS_FUCHSIA)
void FileImpl::Close(CloseCallback callback) {
if (!file_.IsValid()) {
@@ -143,7 +143,7 @@ void FileImpl::Write(const std::vector<uint8_t>& bytes_to_write,
// Who knows what |write()| would return if the size is that big (and it
// actually wrote that much).
if (bytes_to_write.size() >
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
static_cast<size_t>(std::numeric_limits<int>::max())) {
#else
static_cast<size_t>(std::numeric_limits<ssize_t>::max())) {
diff --git a/chromium/components/services/filesystem/file_impl.h b/chromium/components/services/filesystem/file_impl.h
index 4a3d4a0f70e..8ae90799d29 100644
--- a/chromium/components/services/filesystem/file_impl.h
+++ b/chromium/components/services/filesystem/file_impl.h
@@ -41,12 +41,12 @@ class FileImpl : public mojom::File {
// Returns whether the underlying file handle is valid.
bool IsValid() const;
-#if !defined(OS_FUCHSIA)
+#if !BUILDFLAG(IS_FUCHSIA)
// Attempts to perform the native operating system's locking operations on
// the internal mojom::File handle. Not supported on Fuchsia.
base::File::Error RawLockFile();
base::File::Error RawUnlockFile();
-#endif // !OS_FUCHSIA
+#endif // !BUILDFLAG(IS_FUCHSIA)
const base::FilePath& path() const { return path_; }
diff --git a/chromium/components/services/filesystem/lock_table.cc b/chromium/components/services/filesystem/lock_table.cc
index a3402a9ef54..e1bdf6b71fa 100644
--- a/chromium/components/services/filesystem/lock_table.cc
+++ b/chromium/components/services/filesystem/lock_table.cc
@@ -23,7 +23,7 @@ base::File::Error LockTable::LockFile(FileImpl* file) {
return base::File::FILE_ERROR_FAILED;
}
-#if !defined(OS_FUCHSIA)
+#if !BUILDFLAG(IS_FUCHSIA)
// Fuchsia doesn't provide a file locking mechanism, so file locks work only
// within a single process. File locking is used only by LevelDB which stores
// all files in the profile directory and normally there shouldn't be more
@@ -36,7 +36,7 @@ base::File::Error LockTable::LockFile(FileImpl* file) {
// Locking failed for some reason.
return lock_err;
}
-#endif // !OS_FUCHSIA
+#endif // !BUILDFLAG(IS_FUCHSIA)
locked_files_.insert(file->path());
return base::File::FILE_OK;
@@ -45,14 +45,14 @@ base::File::Error LockTable::LockFile(FileImpl* file) {
base::File::Error LockTable::UnlockFile(FileImpl* file) {
auto it = locked_files_.find(file->path());
if (it != locked_files_.end()) {
-#if !defined(OS_FUCHSIA)
+#if !BUILDFLAG(IS_FUCHSIA)
base::File::Error lock_err = file->RawUnlockFile();
if (lock_err != base::File::FILE_OK) {
// TODO(erg): When can we fail to release a lock?
NOTREACHED();
return lock_err;
}
-#endif // !OS_FUCHSIA
+#endif // !BUILDFLAG(IS_FUCHSIA)
locked_files_.erase(it);
}
diff --git a/chromium/components/services/filesystem/util.cc b/chromium/components/services/filesystem/util.cc
index 1aef24d61b7..ddfdc58bfdb 100644
--- a/chromium/components/services/filesystem/util.cc
+++ b/chromium/components/services/filesystem/util.cc
@@ -15,7 +15,7 @@
#include "base/strings/string_util.h"
#include "build/build_config.h"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include "base/strings/utf_string_conversions.h"
#endif
@@ -97,9 +97,9 @@ base::File::Error ValidatePath(const std::string& raw_path,
if (!base::IsStringUTF8(raw_path))
return base::File::Error::FILE_ERROR_INVALID_OPERATION;
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
base::FilePath::StringType path = base::UTF8ToWide(raw_path);
-#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
base::FilePath::StringType path = raw_path;
#endif
diff --git a/chromium/components/services/font/BUILD.gn b/chromium/components/services/font/BUILD.gn
index b065131e035..1d4965449a5 100644
--- a/chromium/components/services/font/BUILD.gn
+++ b/chromium/components/services/font/BUILD.gn
@@ -16,6 +16,7 @@ source_set("lib") {
deps = [
"//base",
+ "//build:chromeos_buildflags",
"//components/services/font/public/mojom",
"//mojo/public/cpp/bindings",
"//mojo/public/cpp/system",
diff --git a/chromium/components/services/font/font_service_app.cc b/chromium/components/services/font/font_service_app.cc
index 4bbeebcb52c..32adf6f3c5c 100644
--- a/chromium/components/services/font/font_service_app.cc
+++ b/chromium/components/services/font/font_service_app.cc
@@ -8,10 +8,12 @@
#include "base/bind.h"
#include "base/command_line.h"
+#include "base/feature_list.h"
#include "base/files/file.h"
#include "base/files/file_path.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "components/services/font/fontconfig_matching.h"
#include "mojo/public/cpp/system/platform_handle.h"
#include "ppapi/buildflags/buildflags.h"
@@ -77,11 +79,24 @@ font_service::mojom::RenderStyleSwitch ConvertSubpixelRendering(
return font_service::mojom::RenderStyleSwitch::NO_PREFERENCE;
}
+// A feature that controls whether we use a cache for font family matching.
+const base::Feature kCacheFontFamilyMatching {
+ "CacheFontFamilyMatching",
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+ base::FEATURE_ENABLED_BY_DEFAULT
+#else
+ base::FEATURE_DISABLED_BY_DEFAULT
+#endif
+};
+
+// The maximum number of entries to keep in the font family matching cache.
+constexpr int kCacheFontFamilyMaxSize = 10000;
+
} // namespace
namespace font_service {
-FontServiceApp::FontServiceApp() = default;
+FontServiceApp::FontServiceApp() : match_cache_(kCacheFontFamilyMaxSize) {}
FontServiceApp::~FontServiceApp() = default;
@@ -100,37 +115,59 @@ void FontServiceApp::MatchFamilyName(const std::string& family_name,
SkFontStyle result_style;
SkFontConfigInterface* fc =
SkFontConfigInterface::GetSingletonDirectInterface();
- const bool r = fc->matchFamilyName(
- family_name.data(),
- SkFontStyle(requested_style->weight, requested_style->width,
- static_cast<SkFontStyle::Slant>(requested_style->slant)),
- &result_identity, &result_family, &result_style);
-
- if (!r) {
- mojom::TypefaceStylePtr style(mojom::TypefaceStyle::New());
+ SkFontStyle font_style(
+ requested_style->weight, requested_style->width,
+ static_cast<SkFontStyle::Slant>(requested_style->slant));
+
+ MatchCacheKey key;
+ if (base::FeatureList::IsEnabled(kCacheFontFamilyMatching)) {
+ key.family_name = family_name;
+ key.font_style = font_style;
+ auto it = match_cache_.Get(key);
+ if (it != match_cache_.end()) {
+ std::move(callback).Run(
+ it->second.identity ? it->second.identity.Clone() : nullptr,
+ it->second.family_name, it->second.style.Clone());
+ return;
+ }
+ }
+ const bool r =
+ fc->matchFamilyName(family_name.data(), font_style, &result_identity,
+ &result_family, &result_style);
+
+ mojom::FontIdentityPtr identity = nullptr;
+ mojom::TypefaceStylePtr style(mojom::TypefaceStyle::New());
+ std::string result_family_cppstring = result_family.c_str();
+
+ if (r) {
+ // Stash away the returned path, so we can give it an ID (index)
+ // which will later be given to us in a request to open the file.
+ base::FilePath path(result_identity.fString.c_str());
+ size_t index = FindOrAddPath(path);
+
+ identity = mojom::FontIdentity::New();
+ identity->id = static_cast<uint32_t>(index);
+ identity->ttc_index = result_identity.fTTCIndex;
+ identity->filepath = path;
+
+ style->weight = result_style.weight();
+ style->width = result_style.width();
+ style->slant = static_cast<mojom::TypefaceSlant>(result_style.slant());
+ } else {
style->weight = SkFontStyle().weight();
style->width = SkFontStyle().width();
style->slant = static_cast<mojom::TypefaceSlant>(SkFontStyle().slant());
- std::move(callback).Run(nullptr, "", std::move(style));
- return;
}
- // Stash away the returned path, so we can give it an ID (index)
- // which will later be given to us in a request to open the file.
- base::FilePath path(result_identity.fString.c_str());
- size_t index = FindOrAddPath(path);
-
- mojom::FontIdentityPtr identity(mojom::FontIdentity::New());
- identity->id = static_cast<uint32_t>(index);
- identity->ttc_index = result_identity.fTTCIndex;
- identity->filepath = path;
-
- mojom::TypefaceStylePtr style(mojom::TypefaceStyle::New());
- style->weight = result_style.weight();
- style->width = result_style.width();
- style->slant = static_cast<mojom::TypefaceSlant>(result_style.slant());
+ if (base::FeatureList::IsEnabled(kCacheFontFamilyMatching)) {
+ MatchCacheValue value;
+ value.family_name = result_family_cppstring;
+ value.identity = identity ? identity.Clone() : nullptr;
+ value.style = style.Clone();
+ match_cache_.Put(key, std::move(value));
+ }
- std::move(callback).Run(std::move(identity), result_family.c_str(),
+ std::move(callback).Run(std::move(identity), result_family_cppstring,
std::move(style));
}
@@ -256,4 +293,8 @@ size_t FontServiceApp::FindOrAddPath(const base::FilePath& path) {
return count;
}
+FontServiceApp::MatchCacheValue::MatchCacheValue() = default;
+FontServiceApp::MatchCacheValue::~MatchCacheValue() = default;
+FontServiceApp::MatchCacheValue::MatchCacheValue(MatchCacheValue&&) = default;
+
} // namespace font_service
diff --git a/chromium/components/services/font/font_service_app.h b/chromium/components/services/font/font_service_app.h
index 949551b6949..2b2aac722a4 100644
--- a/chromium/components/services/font/font_service_app.h
+++ b/chromium/components/services/font/font_service_app.h
@@ -6,14 +6,18 @@
#define COMPONENTS_SERVICES_FONT_FONT_SERVICE_APP_H_
#include <stdint.h>
+#include <tuple>
#include <vector>
+#include "base/containers/lru_cache.h"
#include "base/files/file_path.h"
#include "components/services/font/public/mojom/font_service.mojom.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
+#include "third_party/skia/include/core/SkFontStyle.h"
namespace font_service {
+// This class is instantiated in the browser process.
class FontServiceApp : public mojom::FontService {
public:
FontServiceApp();
@@ -58,6 +62,35 @@ class FontServiceApp : public mojom::FontService {
// We don't want to leak paths to our callers; we thus enumerate the paths of
// fonts.
std::vector<base::FilePath> paths_;
+
+ // On some platforms, font matching is very expensive, ranging from 2-30+ms.
+ // We keep a cache of results to speed this up.
+ struct MatchCacheKey {
+ std::string family_name;
+ SkFontStyle font_style;
+ bool operator==(const MatchCacheKey& other) const {
+ return family_name == other.family_name && font_style == other.font_style;
+ }
+ };
+ struct MatchCacheKeyCompare {
+ bool operator()(const MatchCacheKey& lhs, const MatchCacheKey& rhs) const {
+ return std::make_tuple(lhs.family_name, lhs.font_style.weight(),
+ lhs.font_style.width(), lhs.font_style.slant()) <
+ std::make_tuple(rhs.family_name, rhs.font_style.weight(),
+ rhs.font_style.width(), rhs.font_style.slant());
+ }
+ };
+ struct MatchCacheValue {
+ MatchCacheValue();
+ ~MatchCacheValue();
+ MatchCacheValue(MatchCacheValue&&);
+ std::string family_name;
+ mojom::FontIdentityPtr identity;
+ mojom::TypefaceStylePtr style;
+ };
+
+ base::LRUCache<MatchCacheKey, MatchCacheValue, MatchCacheKeyCompare>
+ match_cache_;
};
} // namespace font_service
diff --git a/chromium/components/services/heap_profiling/heap_profiling_service.cc b/chromium/components/services/heap_profiling/heap_profiling_service.cc
index ede6ca04444..b21009e1106 100644
--- a/chromium/components/services/heap_profiling/heap_profiling_service.cc
+++ b/chromium/components/services/heap_profiling/heap_profiling_service.cc
@@ -9,7 +9,6 @@
#include "base/bind.h"
#include "base/memory/weak_ptr.h"
-#include "base/no_destructor.h"
#include "base/task/post_task.h"
#include "base/task/thread_pool.h"
#include "components/services/heap_profiling/connection_manager.h"
diff --git a/chromium/components/services/heap_profiling/json_exporter_unittest.cc b/chromium/components/services/heap_profiling/json_exporter_unittest.cc
index e8a17017bb4..f6ba7ceb574 100644
--- a/chromium/components/services/heap_profiling/json_exporter_unittest.cc
+++ b/chromium/components/services/heap_profiling/json_exporter_unittest.cc
@@ -37,7 +37,7 @@ const base::Value* FindFirstRegionWithAnyName(
if (!found_regions)
return nullptr;
- for (const base::Value& cur : found_regions->GetList()) {
+ for (const base::Value& cur : found_regions->GetListDeprecated()) {
const base::Value* found_name =
cur.FindKeyOfType("mf", base::Value::Type::STRING);
if (!found_name)
@@ -51,7 +51,7 @@ const base::Value* FindFirstRegionWithAnyName(
// Looks up a given string id from the string table. Returns -1 if not found.
int GetIdFromStringTable(const base::Value* strings, const char* text) {
- for (const auto& string : strings->GetList()) {
+ for (const auto& string : strings->GetListDeprecated()) {
const base::Value* string_id =
string.FindKeyOfType("id", base::Value::Type::INTEGER);
const base::Value* string_text =
@@ -66,7 +66,7 @@ int GetIdFromStringTable(const base::Value* strings, const char* text) {
// Looks up a given string from the string table. Returns empty string if not
// found.
std::string GetStringFromStringTable(const base::Value* strings, int sid) {
- for (const auto& string : strings->GetList()) {
+ for (const auto& string : strings->GetListDeprecated()) {
const base::Value* string_id =
string.FindKeyOfType("id", base::Value::Type::INTEGER);
if (string_id->GetInt() == sid) {
@@ -81,7 +81,7 @@ std::string GetStringFromStringTable(const base::Value* strings, int sid) {
}
int GetNodeWithNameID(const base::Value* nodes, int sid) {
- for (const auto& node : nodes->GetList()) {
+ for (const auto& node : nodes->GetListDeprecated()) {
const base::Value* node_id =
node.FindKeyOfType("id", base::Value::Type::INTEGER);
const base::Value* node_name_sid =
@@ -95,7 +95,7 @@ int GetNodeWithNameID(const base::Value* nodes, int sid) {
int GetOffsetForBacktraceID(const base::Value* nodes, int id) {
int offset = 0;
- for (const auto& node : nodes->GetList()) {
+ for (const auto& node : nodes->GetListDeprecated()) {
if (node.GetInt() == id)
return offset;
offset++;
@@ -104,7 +104,7 @@ int GetOffsetForBacktraceID(const base::Value* nodes, int id) {
}
bool IsBacktraceInList(const base::Value* backtraces, int id, int parent) {
- for (const auto& backtrace : backtraces->GetList()) {
+ for (const auto& backtrace : backtraces->GetListDeprecated()) {
const base::Value* backtrace_id =
backtrace.FindKeyOfType("id", base::Value::Type::INTEGER);
if (backtrace_id == nullptr)
@@ -192,7 +192,7 @@ TEST(ProfilingJsonExporterTest, Simple) {
ASSERT_TRUE(strings);
// Validate the strings table.
- EXPECT_EQ(5u, strings->GetList().size());
+ EXPECT_EQ(5u, strings->GetListDeprecated().size());
int sid_unknown = GetIdFromStringTable(strings, "[unknown]");
int sid_1234 = GetIdFromStringTable(strings, "pc:1234");
int sid_5678 = GetIdFromStringTable(strings, "pc:5678");
@@ -210,7 +210,7 @@ TEST(ProfilingJsonExporterTest, Simple) {
// [1] => address: 5678 parent: 0
// [2] => address: 9012 parent: 0
// [3] => address: 9013 parent: 2
- EXPECT_EQ(4u, nodes->GetList().size());
+ EXPECT_EQ(4u, nodes->GetListDeprecated().size());
int id0 = GetNodeWithNameID(nodes, sid_1234);
int id1 = GetNodeWithNameID(nodes, sid_5678);
int id2 = GetNodeWithNameID(nodes, sid_9012);
@@ -241,9 +241,9 @@ TEST(ProfilingJsonExporterTest, Simple) {
// Counts should be a list of two items, a 1 and a 2. The two matching 20-byte
// allocations should be coalesced to produce the 2.
- EXPECT_EQ(2u, counts->GetList().size());
- EXPECT_EQ(2u, types->GetList().size());
- EXPECT_EQ(2u, sizes->GetList().size());
+ EXPECT_EQ(2u, counts->GetListDeprecated().size());
+ EXPECT_EQ(2u, types->GetListDeprecated().size());
+ EXPECT_EQ(2u, sizes->GetListDeprecated().size());
int node1 = GetOffsetForBacktraceID(backtraces, id1);
int node3 = GetOffsetForBacktraceID(backtraces, id3);
@@ -251,16 +251,16 @@ TEST(ProfilingJsonExporterTest, Simple) {
EXPECT_NE(-1, node3);
// Validate node allocated with |stack1|.
- EXPECT_EQ(2, counts->GetList()[node1].GetInt());
- EXPECT_EQ(0, types->GetList()[node1].GetInt());
- EXPECT_EQ(40, sizes->GetList()[node1].GetInt());
- EXPECT_EQ(id1, backtraces->GetList()[node1].GetInt());
+ EXPECT_EQ(2, counts->GetListDeprecated()[node1].GetInt());
+ EXPECT_EQ(0, types->GetListDeprecated()[node1].GetInt());
+ EXPECT_EQ(40, sizes->GetListDeprecated()[node1].GetInt());
+ EXPECT_EQ(id1, backtraces->GetListDeprecated()[node1].GetInt());
// Validate node allocated with |stack2|.
- EXPECT_EQ(2, counts->GetList()[node3].GetInt());
- EXPECT_EQ(0, types->GetList()[node3].GetInt());
- EXPECT_EQ(44, sizes->GetList()[node3].GetInt());
- EXPECT_EQ(id3, backtraces->GetList()[node3].GetInt());
+ EXPECT_EQ(2, counts->GetListDeprecated()[node3].GetInt());
+ EXPECT_EQ(0, types->GetListDeprecated()[node3].GetInt());
+ EXPECT_EQ(44, sizes->GetListDeprecated()[node3].GetInt());
+ EXPECT_EQ(id3, backtraces->GetListDeprecated()[node3].GetInt());
// Validate that the partition alloc one got through.
counts = heaps_v2->FindPath({"allocators", "partition_alloc", "counts"});
@@ -274,9 +274,9 @@ TEST(ProfilingJsonExporterTest, Simple) {
ASSERT_TRUE(backtraces);
// There should just be one entry for the partition_alloc allocation.
- EXPECT_EQ(1u, counts->GetList().size());
- EXPECT_EQ(1u, types->GetList().size());
- EXPECT_EQ(1u, sizes->GetList().size());
+ EXPECT_EQ(1u, counts->GetListDeprecated().size());
+ EXPECT_EQ(1u, types->GetListDeprecated().size());
+ EXPECT_EQ(1u, sizes->GetListDeprecated().size());
}
// GetProcessMemoryMaps iterates through every memory region, making allocations
@@ -354,8 +354,8 @@ TEST(ProfilingJsonExporterTest, Context) {
heaps_v2->FindPath({"allocators", "partition_alloc", "types"});
ASSERT_TRUE(types);
- const auto& counts_list = counts->GetList();
- const auto& types_list = types->GetList();
+ const auto& counts_list = counts->GetListDeprecated();
+ const auto& types_list = types->GetListDeprecated();
// There should be three allocations, two coalesced ones, one with unique
// context, and one with no context.
@@ -369,7 +369,7 @@ TEST(ProfilingJsonExporterTest, Context) {
// Reconstruct the map from type id to string.
std::map<int, std::string> type_to_string;
- for (const auto& type : types_map->GetList()) {
+ for (const auto& type : types_map->GetListDeprecated()) {
const base::Value* id =
type.FindKeyOfType("id", base::Value::Type::INTEGER);
ASSERT_TRUE(id);
@@ -447,8 +447,8 @@ TEST(ProfilingJsonExporterTest, LargeAllocation) {
const base::Value* malloc =
parsed_json.value->FindPath({"heaps_v2", "allocators", "malloc"});
const base::Value* malloc_sizes = malloc->FindKey("sizes");
- EXPECT_EQ(1u, malloc_sizes->GetList().size());
- EXPECT_EQ(0x9876543210ul, malloc_sizes->GetList()[0].GetDouble());
+ EXPECT_EQ(1u, malloc_sizes->GetListDeprecated().size());
+ EXPECT_EQ(0x9876543210ul, malloc_sizes->GetListDeprecated()[0].GetDouble());
}
#endif
diff --git a/chromium/components/services/heap_profiling/public/cpp/heap_profiling_trace_source.cc b/chromium/components/services/heap_profiling/public/cpp/heap_profiling_trace_source.cc
index 31391d6b0d5..1860fe83ded 100644
--- a/chromium/components/services/heap_profiling/public/cpp/heap_profiling_trace_source.cc
+++ b/chromium/components/services/heap_profiling/public/cpp/heap_profiling_trace_source.cc
@@ -4,6 +4,7 @@
#include "components/services/heap_profiling/public/cpp/heap_profiling_trace_source.h"
+#include "base/no_destructor.h"
#include "base/profiler/frame.h"
#include "base/profiler/module_cache.h"
#include "base/trace_event/trace_event.h"
diff --git a/chromium/components/services/heap_profiling/public/cpp/profiling_client.cc b/chromium/components/services/heap_profiling/public/cpp/profiling_client.cc
index 72d2d2016be..964890d3773 100644
--- a/chromium/components/services/heap_profiling/public/cpp/profiling_client.cc
+++ b/chromium/components/services/heap_profiling/public/cpp/profiling_client.cc
@@ -21,16 +21,16 @@
#include "base/trace_event/memory_dump_manager.h"
#include "build/build_config.h"
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
#include "components/services/heap_profiling/public/cpp/heap_profiling_trace_source.h"
#endif
-#if defined(OS_ANDROID) && BUILDFLAG(CAN_UNWIND_WITH_CFI_TABLE) && \
+#if BUILDFLAG(IS_ANDROID) && BUILDFLAG(CAN_UNWIND_WITH_CFI_TABLE) && \
defined(OFFICIAL_BUILD)
#include "base/trace_event/cfi_backtrace_android.h"
#endif
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
#include "base/allocator/allocator_interception_mac.h"
#endif
@@ -51,14 +51,14 @@ void ProfilingClient::StartProfiling(mojom::ProfilingParamsPtr params,
started_profiling_ = true;
base::trace_event::MallocDumpProvider::GetInstance()->DisableMetrics();
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
// On macOS, this call is necessary to shim malloc zones that were created
// after startup. This cannot be done during shim initialization because the
// task scheduler has not yet been initialized.
base::allocator::PeriodicallyShimNewMallocZones();
#endif
-#if defined(OS_ANDROID) && BUILDFLAG(CAN_UNWIND_WITH_CFI_TABLE) && \
+#if BUILDFLAG(IS_ANDROID) && BUILDFLAG(CAN_UNWIND_WITH_CFI_TABLE) && \
defined(OFFICIAL_BUILD)
// On Android the unwinder initialization requires file reading before
// initializing shim. So, post task on background thread.
@@ -78,7 +78,7 @@ void ProfilingClient::StartProfiling(mojom::ProfilingParamsPtr params,
StartProfilingInternal(std::move(params), std::move(callback));
#endif
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
// Create trace source so that it registers itself to the tracing system.
HeapProfilingTraceSource::GetInstance();
#endif
@@ -215,7 +215,7 @@ void ProfilingClient::AddHeapProfileToTrace(
std::vector<base::SamplingHeapProfiler::Sample> samples =
profiler->GetSamples(/*profile_id=*/0);
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
bool success =
HeapProfilingTraceSource::GetInstance()->AddToTraceIfEnabled(samples);
#else
diff --git a/chromium/components/services/paint_preview_compositor/paint_preview_compositor_collection_impl.cc b/chromium/components/services/paint_preview_compositor/paint_preview_compositor_collection_impl.cc
index cfae6933194..7b54280f3c3 100644
--- a/chromium/components/services/paint_preview_compositor/paint_preview_compositor_collection_impl.cc
+++ b/chromium/components/services/paint_preview_compositor/paint_preview_compositor_collection_impl.cc
@@ -17,9 +17,9 @@
#include "third_party/skia/include/core/SkGraphics.h"
#include "third_party/skia/include/ports/SkFontConfigInterface.h"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include "content/public/child/dwrite_font_proxy_init_win.h"
-#elif defined(OS_LINUX) || defined(OS_CHROMEOS)
+#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
#include "components/services/font/public/cpp/font_loader.h"
#endif
@@ -48,7 +48,7 @@ PaintPreviewCompositorCollectionImpl::PaintPreviewCompositorCollectionImpl(
// Adapted from content::InitializeSkia().
// TODO(crbug/1199857): Tune these limits.
constexpr int kMB = 1024 * 1024;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
SkGraphics::SetFontCacheLimit(base::SysInfo::IsLowEndDevice() ? kMB
: 8 * kMB);
SkGraphics::SetResourceCacheTotalByteLimit(
@@ -56,15 +56,15 @@ PaintPreviewCompositorCollectionImpl::PaintPreviewCompositorCollectionImpl(
SkGraphics::SetResourceCacheSingleAllocationByteLimit(16 * kMB);
#else
SkGraphics::SetResourceCacheSingleAllocationByteLimit(64 * kMB);
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
if (!initialize_environment_)
return;
// Initialize font access for Skia.
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
content::InitializeDWriteFontProxy();
-#elif defined(OS_LINUX) || defined(OS_CHROMEOS)
+#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
mojo::PendingRemote<font_service::mojom::FontService> font_service;
content::UtilityThread::Get()->BindHostReceiver(
font_service.InitWithNewPipeAndPassReceiver());
@@ -87,7 +87,7 @@ PaintPreviewCompositorCollectionImpl::PaintPreviewCompositorCollectionImpl(
base::BindOnce([] { SkFontMgr::RefDefault(); }));
// Sanity check that fonts are working.
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
// No WebSandbox is provided on Linux so the local fonts aren't accessible.
// This is fine since since the subsetted fonts are provided in the SkPicture.
// However, we still need to check that the SkFontMgr starts as it is used by
@@ -100,7 +100,7 @@ PaintPreviewCompositorCollectionImpl::PaintPreviewCompositorCollectionImpl(
PaintPreviewCompositorCollectionImpl::~PaintPreviewCompositorCollectionImpl() {
g_in_shutdown_key.Set("true");
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
content::UninitializeDWriteFontProxy();
#endif
}
diff --git a/chromium/components/services/paint_preview_compositor/paint_preview_compositor_collection_impl.h b/chromium/components/services/paint_preview_compositor/paint_preview_compositor_collection_impl.h
index 7c09acbe61e..a7f8fe5d35b 100644
--- a/chromium/components/services/paint_preview_compositor/paint_preview_compositor_collection_impl.h
+++ b/chromium/components/services/paint_preview_compositor/paint_preview_compositor_collection_impl.h
@@ -21,7 +21,7 @@
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/receiver.h"
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
#include "components/services/font/public/cpp/font_loader.h"
#include "third_party/skia/include/core/SkRefCnt.h"
#endif
@@ -73,7 +73,7 @@ class PaintPreviewCompositorCollectionImpl
std::unique_ptr<PaintPreviewCompositorImpl>>
compositors_;
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
sk_sp<font_service::FontLoader> font_loader_;
#endif
diff --git a/chromium/components/services/patch/content/patch_service.cc b/chromium/components/services/patch/content/patch_service.cc
index 1c8ff4fc446..d384c3cb559 100644
--- a/chromium/components/services/patch/content/patch_service.cc
+++ b/chromium/components/services/patch/content/patch_service.cc
@@ -4,7 +4,6 @@
#include "components/services/patch/content/patch_service.h"
-#include "base/no_destructor.h"
#include "components/services/patch/public/mojom/file_patcher.mojom.h"
#include "components/strings/grit/components_strings.h"
#include "content/public/browser/service_process_host.h"
diff --git a/chromium/components/services/print_compositor/print_compositor_impl.cc b/chromium/components/services/print_compositor/print_compositor_impl.cc
index 8f6f77381fb..e3739baf49f 100644
--- a/chromium/components/services/print_compositor/print_compositor_impl.cc
+++ b/chromium/components/services/print_compositor/print_compositor_impl.cc
@@ -29,12 +29,12 @@
#include "third_party/skia/src/utils/SkMultiPictureDocument.h"
#include "ui/accessibility/ax_tree_update.h"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include "content/public/child/dwrite_font_proxy_init_win.h"
-#elif defined(OS_APPLE)
+#elif BUILDFLAG(IS_APPLE)
#include "third_party/blink/public/platform/platform.h"
#include "third_party/skia/include/core/SkFontMgr.h"
-#elif defined(OS_POSIX) && !defined(OS_ANDROID)
+#elif BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_ANDROID)
#include "third_party/blink/public/platform/platform.h"
#endif
@@ -51,7 +51,7 @@ PrintCompositorImpl::PrintCompositorImpl(
if (!initialize_environment)
return;
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// Initialize direct write font proxy so skia can use it.
content::InitializeDWriteFontProxy();
#endif
@@ -60,7 +60,7 @@ PrintCompositorImpl::PrintCompositorImpl(
SkGraphics::SetImageGeneratorFromEncodedDataFactory(
blink::WebImageGenerator::CreateAsSkImageGenerator);
-#if defined(OS_POSIX) && !defined(OS_ANDROID)
+#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_ANDROID)
content::UtilityThread::Get()->EnsureBlinkInitializedWithSandboxSupport();
// Check that we have sandbox support on this platform.
DCHECK(blink::Platform::Current()->GetSandboxSupport());
@@ -68,7 +68,7 @@ PrintCompositorImpl::PrintCompositorImpl(
content::UtilityThread::Get()->EnsureBlinkInitialized();
#endif
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
// Check that font access is granted.
// This doesn't do comprehensive tests to make sure fonts can work properly.
// It is just a quick and simple check to catch things like improper sandbox
@@ -78,7 +78,7 @@ PrintCompositorImpl::PrintCompositorImpl(
}
PrintCompositorImpl::~PrintCompositorImpl() {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
content::UninitializeDWriteFontProxy();
#endif
}
diff --git a/chromium/components/services/quarantine/BUILD.gn b/chromium/components/services/quarantine/BUILD.gn
index 4411ebbb4a4..d8d69e696ba 100644
--- a/chromium/components/services/quarantine/BUILD.gn
+++ b/chromium/components/services/quarantine/BUILD.gn
@@ -27,7 +27,6 @@ static_library("quarantine") {
if (is_win) {
sources += [ "quarantine_win.cc" ]
- deps += [ "//components/services/quarantine/public/cpp:features" ]
}
if (is_mac) {
@@ -136,7 +135,6 @@ source_set("unit_tests") {
if (is_win) {
sources += [ "quarantine_win_unittest.cc" ]
- deps += [ "//components/services/quarantine/public/cpp:features" ]
}
if (is_mac) {
diff --git a/chromium/components/services/quarantine/OWNERS b/chromium/components/services/quarantine/OWNERS
index 15eb1078310..2a42cbefb8f 100644
--- a/chromium/components/services/quarantine/OWNERS
+++ b/chromium/components/services/quarantine/OWNERS
@@ -1,2 +1 @@
-asanka@chromium.org
wfh@chromium.org
diff --git a/chromium/components/services/quarantine/README.md b/chromium/components/services/quarantine/README.md
index 8caf099c5e2..b23584c478e 100644
--- a/chromium/components/services/quarantine/README.md
+++ b/chromium/components/services/quarantine/README.md
@@ -1,6 +1,4 @@
Quarantine service to scan/mark a downloaded file with a mark-of-the-web.
-The service will run in browser process except for Windows
-with kOutOfProcessQuarantine flag set, where will run in a utility process
-
-TODO: Implement, add call sites, and refactor components/download/quarantine.
+The service will run in browser process except for Windows, where will run in a
+utility process
diff --git a/chromium/components/services/quarantine/public/cpp/BUILD.gn b/chromium/components/services/quarantine/public/cpp/BUILD.gn
deleted file mode 100644
index 40fab13c662..00000000000
--- a/chromium/components/services/quarantine/public/cpp/BUILD.gn
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright 2019 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.
-
-import("//mojo/public/tools/bindings/mojom.gni")
-
-if (is_win) {
- source_set("features") {
- sources = [
- "quarantine_features_win.cc",
- "quarantine_features_win.h",
- ]
-
- public_deps = [ "//base" ]
- }
-}
diff --git a/chromium/components/services/quarantine/public/cpp/quarantine_features_win.cc b/chromium/components/services/quarantine/public/cpp/quarantine_features_win.cc
deleted file mode 100644
index 47bf5a470f0..00000000000
--- a/chromium/components/services/quarantine/public/cpp/quarantine_features_win.cc
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright 2019 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.
-
-#include "components/services/quarantine/public/cpp/quarantine_features_win.h"
-
-namespace quarantine {
-
-// This feature controls whether the quarantine service should run in
-// the browser process or a new utility process.
-// Unused until quarantine service is fully implemented.
-const base::Feature kOutOfProcessQuarantine{"OutOfProcessQuarantine",
- base::FEATURE_ENABLED_BY_DEFAULT};
-
-} // namespace quarantine
diff --git a/chromium/components/services/quarantine/public/cpp/quarantine_features_win.h b/chromium/components/services/quarantine/public/cpp/quarantine_features_win.h
deleted file mode 100644
index b97fd1e6535..00000000000
--- a/chromium/components/services/quarantine/public/cpp/quarantine_features_win.h
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2019 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.
-
-#ifndef COMPONENTS_SERVICES_QUARANTINE_PUBLIC_CPP_QUARANTINE_FEATURES_WIN_H_
-#define COMPONENTS_SERVICES_QUARANTINE_PUBLIC_CPP_QUARANTINE_FEATURES_WIN_H_
-
-#include "base/feature_list.h"
-
-namespace quarantine {
-
-extern const base::Feature kOutOfProcessQuarantine;
-
-} // namespace quarantine
-
-#endif // COMPONENTS_SERVICES_QUARANTINE_PUBLIC_CPP_QUARANTINE_FEATURES_WIN_H_
diff --git a/chromium/components/services/quarantine/quarantine.cc b/chromium/components/services/quarantine/quarantine.cc
index 83e907cbfb4..84215bc6fa0 100644
--- a/chromium/components/services/quarantine/quarantine.cc
+++ b/chromium/components/services/quarantine/quarantine.cc
@@ -6,7 +6,7 @@
#include "build/build_config.h"
-#if !defined(OS_WIN) && !defined(OS_APPLE) && !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_WIN) && !BUILDFLAG(IS_APPLE) && !BUILDFLAG(IS_CHROMEOS)
namespace quarantine {
diff --git a/chromium/components/services/quarantine/quarantine.h b/chromium/components/services/quarantine/quarantine.h
index 949a17921ba..be1b49a881b 100644
--- a/chromium/components/services/quarantine/quarantine.h
+++ b/chromium/components/services/quarantine/quarantine.h
@@ -73,7 +73,7 @@ void QuarantineFile(const base::FilePath& file,
const std::string& client_guid,
mojom::Quarantine::QuarantineFileCallback callback);
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
QuarantineFileResult SetInternetZoneIdentifierDirectly(
const base::FilePath& full_path,
const GURL& source_url,
diff --git a/chromium/components/services/quarantine/quarantine_impl.cc b/chromium/components/services/quarantine/quarantine_impl.cc
index 5fcd99151c8..63339384418 100644
--- a/chromium/components/services/quarantine/quarantine_impl.cc
+++ b/chromium/components/services/quarantine/quarantine_impl.cc
@@ -7,6 +7,7 @@
#include "base/bind.h"
#include "base/task/post_task.h"
#include "base/task/thread_pool.h"
+#include "build/build_config.h"
#include "components/services/quarantine/quarantine.h"
namespace quarantine {
@@ -35,16 +36,16 @@ void QuarantineImpl::QuarantineFile(
const GURL& referrer_url,
const std::string& client_guid,
mojom::Quarantine::QuarantineFileCallback callback) {
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
// On Mac posting to a new task runner to do the potentially blocking
// quarantine work.
scoped_refptr<base::TaskRunner> task_runner =
base::ThreadPool::CreateTaskRunner(
{base::MayBlock(), base::TaskPriority::USER_VISIBLE});
-#else // OS_MAC
+#else // BUILDFLAG(IS_MAC)
scoped_refptr<base::TaskRunner> task_runner =
base::ThreadTaskRunnerHandle::Get();
-#endif // OS_MAC
+#endif // BUILDFLAG(IS_MAC)
task_runner->PostTask(
FROM_HERE,
base::BindOnce(
diff --git a/chromium/components/services/quarantine/quarantine_impl.h b/chromium/components/services/quarantine/quarantine_impl.h
index 877414bb3c1..87dbc72b11a 100644
--- a/chromium/components/services/quarantine/quarantine_impl.h
+++ b/chromium/components/services/quarantine/quarantine_impl.h
@@ -12,9 +12,9 @@
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/receiver.h"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include "base/win/scoped_com_initializer.h"
-#endif // OS_WIN
+#endif // BUILDFLAG(IS_WIN)
namespace quarantine {
@@ -39,10 +39,10 @@ class QuarantineImpl : public mojom::Quarantine {
private:
mojo::Receiver<mojom::Quarantine> receiver_{this};
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
base::win::ScopedCOMInitializer com_initializer_{
base::win::ScopedCOMInitializer::Uninitialization::kBlockPremature};
-#endif // OS_WIN
+#endif // BUILDFLAG(IS_WIN)
};
} // namespace quarantine
diff --git a/chromium/components/services/quarantine/quarantine_unittest.cc b/chromium/components/services/quarantine/quarantine_unittest.cc
index 052430ab8f9..4701858bcb7 100644
--- a/chromium/components/services/quarantine/quarantine_unittest.cc
+++ b/chromium/components/services/quarantine/quarantine_unittest.cc
@@ -18,7 +18,7 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include "base/win/scoped_com_initializer.h"
#endif
@@ -39,7 +39,7 @@ void CheckQuarantineResult(QuarantineFileResult result,
class QuarantineTest : public testing::Test {
public:
void SetUp() override {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
ASSERT_TRUE(com_initializer_.Succeeded());
#endif
ASSERT_TRUE(test_dir_.CreateUniqueTempDir());
@@ -54,7 +54,7 @@ class QuarantineTest : public testing::Test {
}
private:
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
base::win::ScopedCOMInitializer com_initializer_;
#endif
base::test::SingleThreadTaskEnvironment task_environment_;
diff --git a/chromium/components/services/quarantine/quarantine_win.cc b/chromium/components/services/quarantine/quarantine_win.cc
index e4cd1da3d70..010bb335d5e 100644
--- a/chromium/components/services/quarantine/quarantine_win.cc
+++ b/chromium/components/services/quarantine/quarantine_win.cc
@@ -29,7 +29,6 @@
#include "base/win/windows_version.h"
#include "components/services/quarantine/common.h"
#include "components/services/quarantine/common_win.h"
-#include "components/services/quarantine/public/cpp/quarantine_features_win.h"
#include "url/gurl.h"
namespace quarantine {
diff --git a/chromium/components/services/quarantine/quarantine_win_unittest.cc b/chromium/components/services/quarantine/quarantine_win_unittest.cc
index 3c38a6c2220..12540ae6899 100644
--- a/chromium/components/services/quarantine/quarantine_win_unittest.cc
+++ b/chromium/components/services/quarantine/quarantine_win_unittest.cc
@@ -19,7 +19,6 @@
#include "base/win/scoped_com_initializer.h"
#include "base/win/win_util.h"
#include "base/win/windows_version.h"
-#include "components/services/quarantine/public/cpp/quarantine_features_win.h"
#include "components/services/quarantine/quarantine.h"
#include "components/services/quarantine/test_support.h"
#include "net/base/filename_util.h"
diff --git a/chromium/components/services/quarantine/test_support.cc b/chromium/components/services/quarantine/test_support.cc
index 1bd7bc3b4f4..a2a09fbee61 100644
--- a/chromium/components/services/quarantine/test_support.cc
+++ b/chromium/components/services/quarantine/test_support.cc
@@ -6,7 +6,7 @@
#include "build/build_config.h"
-#if !defined(OS_WIN) && !defined(OS_APPLE)
+#if !BUILDFLAG(IS_WIN) && !BUILDFLAG(IS_APPLE)
namespace quarantine {
diff --git a/chromium/components/services/storage/BUILD.gn b/chromium/components/services/storage/BUILD.gn
index 007edf013a8..00ed503c1d1 100644
--- a/chromium/components/services/storage/BUILD.gn
+++ b/chromium/components/services/storage/BUILD.gn
@@ -77,6 +77,12 @@ source_set("storage") {
"service_worker/service_worker_storage.h",
"service_worker/service_worker_storage_control_impl.cc",
"service_worker/service_worker_storage_control_impl.h",
+ "shared_storage/async_shared_storage_database.cc",
+ "shared_storage/async_shared_storage_database.h",
+ "shared_storage/shared_storage_database.cc",
+ "shared_storage/shared_storage_database.h",
+ "shared_storage/shared_storage_options.cc",
+ "shared_storage/shared_storage_options.h",
"storage_service_impl.cc",
"storage_service_impl.h",
]
@@ -90,6 +96,7 @@ source_set("storage") {
"//components/services/storage/service_worker:service_worker_proto",
"//mojo/public/cpp/bindings",
"//sql",
+ "//third_party/abseil-cpp:absl",
"//third_party/blink/public/common",
"//third_party/leveldatabase",
"//url",
@@ -101,6 +108,7 @@ source_set("storage") {
"//net",
"//services/network/public/cpp",
"//services/network/public/mojom",
+ "//storage/browser",
"//storage/common",
]
}
@@ -136,6 +144,18 @@ component("test_api_stubs") {
defines = [ "IS_STORAGE_SERVICE_TEST_API_STUBS_IMPL" ]
}
+bundle_data("tests_bundle_data") {
+ visibility = [ ":tests" ]
+ testonly = true
+ sources = [
+ "//components/test/data/storage/shared_storage.v0.init_too_old.sql",
+ "//components/test/data/storage/shared_storage.v1.init_too_new.sql",
+ "//components/test/data/storage/shared_storage.v1.sql",
+ ]
+ outputs = [ "{{bundle_resources_dir}}/" +
+ "{{source_root_relative_dir}}/{{source_file_part}}" ]
+}
+
source_set("tests") {
testonly = true
@@ -164,12 +184,15 @@ source_set("tests") {
"service_worker/service_worker_storage_test_utils.cc",
"service_worker/service_worker_storage_test_utils.h",
"service_worker/service_worker_storage_unittest.cc",
+ "shared_storage/async_shared_storage_database_unittest.cc",
+ "shared_storage/shared_storage_database_unittest.cc",
"storage_service_impl_unittest.cc",
]
deps = [
":storage",
":test_support",
+ ":tests_bundle_data",
"//base",
"//base/test:test_support",
"//components/services/storage/public/cpp",
@@ -180,8 +203,13 @@ source_set("tests") {
"//mojo/public/cpp/system",
"//net",
"//net:test_support",
+ "//sql",
+ "//sql:test_support",
+ "//storage/browser:browser",
+ "//storage/browser:test_support",
"//testing/gmock",
"//testing/gtest",
+ "//third_party/sqlite",
]
data = [ "//components/services/storage/test_data/" ]
@@ -201,11 +229,14 @@ source_set("test_support") {
"indexed_db/leveldb/mock_level_db.h",
"indexed_db/scopes/leveldb_scopes_test_utils.cc",
"indexed_db/scopes/leveldb_scopes_test_utils.h",
+ "shared_storage/shared_storage_test_utils.cc",
+ "shared_storage/shared_storage_test_utils.h",
]
deps = [
":storage",
"//base/test:test_support",
+ "//sql:test_support",
"//testing/gmock",
"//testing/gtest",
"//third_party/leveldatabase",
diff --git a/chromium/components/services/storage/DEPS b/chromium/components/services/storage/DEPS
index fadaaf00f3c..8c47aae7a79 100644
--- a/chromium/components/services/storage/DEPS
+++ b/chromium/components/services/storage/DEPS
@@ -4,4 +4,6 @@ include_rules = [
"+third_party/blink/public/mojom",
"+third_party/leveldatabase",
"+sql",
+ "+storage/browser/quota/special_storage_policy.h",
+ "+storage/browser/test/mock_special_storage_policy.h",
]
diff --git a/chromium/components/services/storage/dom_storage/local_storage_impl.cc b/chromium/components/services/storage/dom_storage/local_storage_impl.cc
index 749ba0bb361..82a90a61105 100644
--- a/chromium/components/services/storage/dom_storage/local_storage_impl.cc
+++ b/chromium/components/services/storage/dom_storage/local_storage_impl.cc
@@ -79,7 +79,7 @@ const int kCommitErrorThreshold = 8;
// Limits on the cache size and number of areas in memory, over which the areas
// are purged.
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
const unsigned kMaxLocalStorageAreaCount = 10;
const size_t kMaxLocalStorageCacheSize = 2 * 1024 * 1024;
#else
@@ -213,7 +213,7 @@ class LocalStorageImpl::StorageAreaHolder final
options.default_commit_delay = kCommitDefaultDelaySecs;
options.max_bytes_per_hour = kMaxBytesPerHour;
options.max_commits_per_hour = kMaxCommitsPerHour;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
options.cache_mode = StorageAreaImpl::CacheMode::KEYS_ONLY_WHEN_POSSIBLE;
#else
options.cache_mode = StorageAreaImpl::CacheMode::KEYS_AND_VALUES;
diff --git a/chromium/components/services/storage/dom_storage/local_storage_impl_unittest.cc b/chromium/components/services/storage/dom_storage/local_storage_impl_unittest.cc
index 89ddf64633f..3b617b6302c 100644
--- a/chromium/components/services/storage/dom_storage/local_storage_impl_unittest.cc
+++ b/chromium/components/services/storage/dom_storage/local_storage_impl_unittest.cc
@@ -4,13 +4,14 @@
#include "components/services/storage/dom_storage/local_storage_impl.h"
+#include <tuple>
+
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/containers/span.h"
#include "base/files/file_enumerator.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
-#include "base/ignore_result.h"
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
@@ -256,7 +257,7 @@ class LocalStorageImplTest : public testing::Test {
base::RunLoop run_loop;
std::vector<blink::mojom::KeyValuePtr> data;
mojo::PendingRemote<blink::mojom::StorageAreaObserver> unused_observer;
- ignore_result(unused_observer.InitWithNewPipeAndPassReceiver());
+ std::ignore = unused_observer.InitWithNewPipeAndPassReceiver();
area->GetAll(std::move(unused_observer),
test::MakeGetAllCallback(run_loop.QuitClosure(), &data));
run_loop.Run();
diff --git a/chromium/components/services/storage/dom_storage/session_storage_data_map_unittest.cc b/chromium/components/services/storage/dom_storage/session_storage_data_map_unittest.cc
index b798967fd47..5d3362c5473 100644
--- a/chromium/components/services/storage/dom_storage/session_storage_data_map_unittest.cc
+++ b/chromium/components/services/storage/dom_storage/session_storage_data_map_unittest.cc
@@ -5,11 +5,11 @@
#include "components/services/storage/dom_storage/session_storage_data_map.h"
#include <map>
+#include <tuple>
#include <vector>
#include "base/bind.h"
#include "base/containers/span.h"
-#include "base/ignore_result.h"
#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
#include "base/task/post_task.h"
@@ -41,7 +41,7 @@ base::span<const uint8_t> MakeBytes(base::StringPiece str) {
mojo::PendingRemote<blink::mojom::StorageAreaObserver> MakeStubObserver() {
mojo::PendingRemote<blink::mojom::StorageAreaObserver> observer;
- ignore_result(observer.InitWithNewPipeAndPassReceiver());
+ std::ignore = observer.InitWithNewPipeAndPassReceiver();
return observer;
}
diff --git a/chromium/components/services/storage/dom_storage/session_storage_impl.cc b/chromium/components/services/storage/dom_storage/session_storage_impl.cc
index 70bd2345f7c..80aecec0563 100644
--- a/chromium/components/services/storage/dom_storage/session_storage_impl.cc
+++ b/chromium/components/services/storage/dom_storage/session_storage_impl.cc
@@ -41,7 +41,7 @@ const int kSessionStorageCommitErrorThreshold = 8;
// Limits on the cache size and number of areas in memory, over which the areas
// are purged.
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
const unsigned kMaxSessionStorageAreaCount = 10;
const size_t kMaxSessionStorageCacheSize = 2 * 1024 * 1024;
#else
diff --git a/chromium/components/services/storage/dom_storage/storage_area_impl_unittest.cc b/chromium/components/services/storage/dom_storage/storage_area_impl_unittest.cc
index 502c7b980bc..299d5380ab0 100644
--- a/chromium/components/services/storage/dom_storage/storage_area_impl_unittest.cc
+++ b/chromium/components/services/storage/dom_storage/storage_area_impl_unittest.cc
@@ -7,13 +7,13 @@
#include <list>
#include <memory>
#include <string>
+#include <tuple>
#include <vector>
#include "base/atomic_ref_count.h"
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/containers/span.h"
-#include "base/ignore_result.h"
#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
@@ -903,7 +903,7 @@ TEST_F(StorageAreaImplTest, GetAllWhenCacheOnlyKeys) {
MakeSuccessCallback(barrier.AddClosure(), &put_result1));
mojo::PendingRemote<blink::mojom::StorageAreaObserver> unused_observer;
- ignore_result(unused_observer.InitWithNewPipeAndPassReceiver());
+ std::ignore = unused_observer.InitWithNewPipeAndPassReceiver();
storage_area()->GetAll(std::move(unused_observer),
MakeGetAllCallback(barrier.AddClosure(), &data));
storage_area()->Put(
@@ -974,7 +974,7 @@ TEST_F(StorageAreaImplTest, GetAllAfterSetCacheMode) {
upgrade_loop.Run();
mojo::PendingRemote<blink::mojom::StorageAreaObserver> unused_observer;
- ignore_result(unused_observer.InitWithNewPipeAndPassReceiver());
+ std::ignore = unused_observer.InitWithNewPipeAndPassReceiver();
storage_area()->GetAll(
std::move(unused_observer),
MakeGetAllCallback(upgrade_loop.QuitClosure(), &data));
diff --git a/chromium/components/services/storage/dom_storage/testing_legacy_session_storage_database.cc b/chromium/components/services/storage/dom_storage/testing_legacy_session_storage_database.cc
index 29cd8d1609f..ecd979bc3e1 100644
--- a/chromium/components/services/storage/dom_storage/testing_legacy_session_storage_database.cc
+++ b/chromium/components/services/storage/dom_storage/testing_legacy_session_storage_database.cc
@@ -499,7 +499,7 @@ leveldb::Status TestingLegacySessionStorageDatabase::TryToOpen(
options.block_cache = leveldb_chrome::GetSharedWebBlockCache();
std::string db_name = file_path_.AsUTF8Unsafe();
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// On Android there is no support for session storage restoring, and since
// the restoring code is responsible for database cleanup, we must manually
// delete the old database here before we open it.
diff --git a/chromium/components/services/storage/indexed_db/leveldb/leveldb_factory.cc b/chromium/components/services/storage/indexed_db/leveldb/leveldb_factory.cc
index c4082447fb4..dd3646d6e61 100644
--- a/chromium/components/services/storage/indexed_db/leveldb/leveldb_factory.cc
+++ b/chromium/components/services/storage/indexed_db/leveldb/leveldb_factory.cc
@@ -50,16 +50,13 @@ std::tuple<scoped_refptr<LevelDBState>,
DefaultLevelDBFactory::OpenLevelDBState(const base::FilePath& file_name,
bool create_if_missing,
size_t write_buffer_size) {
- leveldb::Status status;
- std::unique_ptr<leveldb::DB> db;
-
if (file_name.empty()) {
if (!create_if_missing)
return {nullptr, leveldb::Status::NotFound("", ""), false};
std::unique_ptr<leveldb::Env> in_memory_env =
leveldb_chrome::NewMemEnv(in_memory_db_name_, options_.env);
- std::tie(db, status) = OpenInMemoryDB(in_memory_env.get());
+ auto [db, status] = OpenInMemoryDB(in_memory_env.get());
if (UNLIKELY(!status.ok())) {
LOG(ERROR) << "Failed to open in-memory LevelDB database: "
<< status.ToString();
@@ -73,7 +70,7 @@ DefaultLevelDBFactory::OpenLevelDBState(const base::FilePath& file_name,
}
// ChromiumEnv assumes UTF8, converts back to FilePath before using.
- std::tie(db, status) =
+ auto [db, status] =
OpenDB(file_name.AsUTF8Unsafe(), create_if_missing, write_buffer_size);
if (UNLIKELY(!status.ok())) {
if (!create_if_missing && status.IsInvalidArgument())
diff --git a/chromium/components/services/storage/indexed_db/scopes/leveldb_scope.h b/chromium/components/services/storage/indexed_db/scopes/leveldb_scope.h
index 26f70a76dfc..13f5d1723f6 100644
--- a/chromium/components/services/storage/indexed_db/scopes/leveldb_scope.h
+++ b/chromium/components/services/storage/indexed_db/scopes/leveldb_scope.h
@@ -13,7 +13,6 @@
#include "base/callback.h"
#include "base/check_op.h"
-#include "base/compiler_specific.h"
#include "base/containers/flat_map.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
@@ -81,19 +80,19 @@ class LevelDBScope {
return scope_id_;
}
- leveldb::Status Put(const leveldb::Slice& key,
- const leveldb::Slice& value) WARN_UNUSED_RESULT;
- leveldb::Status Delete(const leveldb::Slice& key) WARN_UNUSED_RESULT;
+ [[nodiscard]] leveldb::Status Put(const leveldb::Slice& key,
+ const leveldb::Slice& value);
+ [[nodiscard]] leveldb::Status Delete(const leveldb::Slice& key);
// Deletes the range. |begin| is always inclusive. See
// |LevelDBScopeDeletionMode| for the different types of range deletion.
- leveldb::Status DeleteRange(const leveldb::Slice& begin,
- const leveldb::Slice& end,
- LevelDBScopeDeletionMode mode) WARN_UNUSED_RESULT;
+ [[nodiscard]] leveldb::Status DeleteRange(const leveldb::Slice& begin,
+ const leveldb::Slice& end,
+ LevelDBScopeDeletionMode mode);
// Submits pending changes & the undo log to LevelDB. Required to be able to
// read any keys that have been submitted to |Put|, |Delete|, or
// |DeleteRange|.
- leveldb::Status WriteChangesAndUndoLog() WARN_UNUSED_RESULT;
+ [[nodiscard]] leveldb::Status WriteChangesAndUndoLog();
// In the case of LevelDBScopes being in the mode
// TaskRunnerMode::kUseCurrentSequence, rollbacks happen synchronously. The
@@ -148,8 +147,7 @@ class LevelDBScope {
// status & the mode of this scope. The caller (LevelDBScopes) is expected to
// queue up a cleanup task if the mode is kUndoLogOnDisk. This instance should
// not be used after this call.
- std::pair<leveldb::Status, Mode> Commit(bool sync_on_commit)
- WARN_UNUSED_RESULT;
+ [[nodiscard]] std::pair<leveldb::Status, Mode> Commit(bool sync_on_commit);
// Submits pending changes & the undo log to LevelDB. Required to be able to
// read any keys that have been submitted to Put, Delete, or
@@ -181,7 +179,7 @@ class LevelDBScope {
bool CanSkipWritingUndoEntry(const leveldb::Slice& key);
void AddCommitPoint();
- leveldb::Status WriteBufferBatch(bool sync) WARN_UNUSED_RESULT;
+ [[nodiscard]] leveldb::Status WriteBufferBatch(bool sync);
#if DCHECK_IS_ON()
std::vector<std::pair<std::string, std::string>> deferred_delete_ranges_;
diff --git a/chromium/components/services/storage/indexed_db/scopes/leveldb_scopes.cc b/chromium/components/services/storage/indexed_db/scopes/leveldb_scopes.cc
index e45257801f0..e2d1299ba13 100644
--- a/chromium/components/services/storage/indexed_db/scopes/leveldb_scopes.cc
+++ b/chromium/components/services/storage/indexed_db/scopes/leveldb_scopes.cc
@@ -111,9 +111,7 @@ leveldb::Status LevelDBScopes::Initialize() {
for (; iterator->Valid() && iterator->key().starts_with(prefix_key);
iterator->Next()) {
// Parse the key & value.
- int64_t scope_id;
- bool success;
- std::tie(success, scope_id) = leveldb_scopes::ParseScopeMetadataId(
+ auto [success, scope_id] = leveldb_scopes::ParseScopeMetadataId(
iterator->key(), metadata_key_prefix_);
if (UNLIKELY(!success)) {
return leveldb::Status::Corruption(base::StrCat(
@@ -274,9 +272,7 @@ leveldb::Status LevelDBScopes::Commit(std::unique_ptr<LevelDBScope> scope,
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(recovery_finished_);
DCHECK(cleanup_runner_);
- LevelDBScope::Mode scopes_mode;
- leveldb::Status s;
- std::tie(s, scopes_mode) = scope->Commit(sync_on_commit);
+ auto [status, scopes_mode] = scope->Commit(sync_on_commit);
if (scopes_mode == LevelDBScope::Mode::kUndoLogOnDisk) {
auto task = std::make_unique<CleanupScopeTask>(
level_db_, metadata_key_prefix_, scope->scope_id(),
@@ -288,7 +284,7 @@ leveldb::Status LevelDBScopes::Commit(std::unique_ptr<LevelDBScope> scope,
base::BindOnce(&LevelDBScopes::OnCleanupTaskResult,
weak_factory_.GetWeakPtr(), std::move(on_complete)));
}
- return s;
+ return status;
}
leveldb::Status LevelDBScopes::Rollback(int64_t scope_id,
diff --git a/chromium/components/services/storage/indexed_db/scopes/leveldb_scopes_tasks.h b/chromium/components/services/storage/indexed_db/scopes/leveldb_scopes_tasks.h
index 97c02f337c9..f8fca7817c0 100644
--- a/chromium/components/services/storage/indexed_db/scopes/leveldb_scopes_tasks.h
+++ b/chromium/components/services/storage/indexed_db/scopes/leveldb_scopes_tasks.h
@@ -9,7 +9,6 @@
#include <vector>
#include "base/callback.h"
-#include "base/compiler_specific.h"
#include "base/memory/scoped_refptr.h"
#include "base/sequence_checker.h"
#include "components/services/storage/indexed_db/leveldb/leveldb_state.h"
@@ -38,18 +37,18 @@ class LevelDBScopesTask {
protected:
// Submits the in-progress WriteBatch to LevelDB, no matter what size the
// batch is.
- leveldb::Status SubmitWriteBatch(const leveldb::WriteOptions& options)
- WARN_UNUSED_RESULT;
+ [[nodiscard]] leveldb::Status SubmitWriteBatch(
+ const leveldb::WriteOptions& options);
// Submits thein-progress WriteBatch to LevelDB only if the approximate size
// of the batch is > |max_write_batch_size_|.
- leveldb::Status MaybeSubmitWriteBatch(const leveldb::WriteOptions& options)
- WARN_UNUSED_RESULT;
+ [[nodiscard]] leveldb::Status MaybeSubmitWriteBatch(
+ const leveldb::WriteOptions& options);
- leveldb::Status DeleteRange(leveldb::Slice range_start,
- leveldb::Slice range_end,
- const leveldb::ReadOptions& read_options,
- const leveldb::WriteOptions& write_options)
- WARN_UNUSED_RESULT;
+ [[nodiscard]] leveldb::Status DeleteRange(
+ leveldb::Slice range_start,
+ leveldb::Slice range_end,
+ const leveldb::ReadOptions& read_options,
+ const leveldb::WriteOptions& write_options);
SEQUENCE_CHECKER(sequence_checker_);
@@ -79,16 +78,16 @@ class CleanupScopeTask : private LevelDBScopesTask {
size_t max_write_batch_size_bytes);
~CleanupScopeTask();
- leveldb::Status Run() WARN_UNUSED_RESULT;
+ [[nodiscard]] leveldb::Status Run();
private:
- leveldb::Status ExecuteAndDeleteCleanupTasks(
+ [[nodiscard]] leveldb::Status ExecuteAndDeleteCleanupTasks(
const leveldb::ReadOptions& read_options,
- const leveldb::WriteOptions& write_options) WARN_UNUSED_RESULT;
- leveldb::Status DeletePrefixedRange(
+ const leveldb::WriteOptions& write_options);
+ [[nodiscard]] leveldb::Status DeletePrefixedRange(
leveldb::Slice prefix,
const leveldb::ReadOptions& read_options,
- const leveldb::WriteOptions& write_options) WARN_UNUSED_RESULT;
+ const leveldb::WriteOptions& write_options);
const std::vector<uint8_t> metadata_prefix_;
const int64_t scope_number_;
@@ -109,7 +108,7 @@ class RevertScopeTask : private LevelDBScopesTask {
size_t max_write_batch_size_bytes);
~RevertScopeTask();
- leveldb::Status Run() WARN_UNUSED_RESULT;
+ [[nodiscard]] leveldb::Status Run();
private:
const std::vector<uint8_t> metadata_prefix_;
diff --git a/chromium/components/services/storage/indexed_db/scopes/leveldb_scopes_test_utils.cc b/chromium/components/services/storage/indexed_db/scopes/leveldb_scopes_test_utils.cc
index 9486bf3a1b0..cf380e68105 100644
--- a/chromium/components/services/storage/indexed_db/scopes/leveldb_scopes_test_utils.cc
+++ b/chromium/components/services/storage/indexed_db/scopes/leveldb_scopes_test_utils.cc
@@ -101,9 +101,7 @@ void LevelDBScopesTestBase::SetUpBreakableDB(
TearDown();
ASSERT_TRUE(temp_directory_.CreateUniqueTempDir());
- leveldb::Status status;
- std::unique_ptr<leveldb::DB> temp_real_db;
- std::tie(temp_real_db, status) =
+ auto [temp_real_db, status] =
leveldb_factory_->OpenDB(temp_directory_.GetPath().AsUTF8Unsafe(),
/*create_if_missing=*/true, kWriteBufferSize);
ASSERT_TRUE(status.ok());
@@ -124,10 +122,8 @@ void LevelDBScopesTestBase::SetUpFlakyDB(
if (leveldb_)
TearDown();
ASSERT_TRUE(temp_directory_.CreateUniqueTempDir());
- leveldb::Status status;
- std::unique_ptr<leveldb::DB> temp_db;
- std::tie(temp_db, status) =
+ auto [temp_db, status] =
leveldb_factory_->OpenDB(temp_directory_.GetPath().AsUTF8Unsafe(),
/*create_if_missing=*/true, kWriteBufferSize);
ASSERT_TRUE(status.ok());
diff --git a/chromium/components/services/storage/indexed_db/scopes/varint_coding.h b/chromium/components/services/storage/indexed_db/scopes/varint_coding.h
index 640061229cb..eca8f086a92 100644
--- a/chromium/components/services/storage/indexed_db/scopes/varint_coding.h
+++ b/chromium/components/services/storage/indexed_db/scopes/varint_coding.h
@@ -22,7 +22,7 @@ void EncodeVarInt(int64_t from, std::string* into);
// Decodes a varint from the given string piece into the given int64_t. Returns
// if the string had a valid varint (where a byte was found with it's top bit
// set). This function does NOT check to see if move than 64 bits were read.
-WARN_UNUSED_RESULT bool DecodeVarInt(base::StringPiece* from, int64_t* into);
+[[nodiscard]] bool DecodeVarInt(base::StringPiece* from, int64_t* into);
} // namespace content
diff --git a/chromium/components/services/storage/indexed_db/transactional_leveldb/transactional_leveldb_database.cc b/chromium/components/services/storage/indexed_db/transactional_leveldb/transactional_leveldb_database.cc
index 0c8aa710d02..473a0b1d85a 100644
--- a/chromium/components/services/storage/indexed_db/transactional_leveldb/transactional_leveldb_database.cc
+++ b/chromium/components/services/storage/indexed_db/transactional_leveldb/transactional_leveldb_database.cc
@@ -53,7 +53,7 @@ namespace {
//
// Sync writes are necessary on Windows for quota calculations; POSIX
// calculates file sizes correctly even when not synced to disk.
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
const bool kSyncWrites = true;
#else
// TODO(dgrogan): Either remove the #if block or change this back to false.
diff --git a/chromium/components/services/storage/indexed_db/transactional_leveldb/transactional_leveldb_iterator.cc b/chromium/components/services/storage/indexed_db/transactional_leveldb/transactional_leveldb_iterator.cc
index c9d2b0a5bb0..8b2932c34dd 100644
--- a/chromium/components/services/storage/indexed_db/transactional_leveldb/transactional_leveldb_iterator.cc
+++ b/chromium/components/services/storage/indexed_db/transactional_leveldb/transactional_leveldb_iterator.cc
@@ -113,11 +113,9 @@ leveldb::Status TransactionalLevelDBIterator::Next() {
CheckState();
bool iterator_is_loaded = (iterator_ != nullptr);
- std::string key_before_eviction;
- leveldb::Status s;
- std::tie(key_before_eviction, s) = WillUseDBIterator(/*perform_seek=*/true);
- if (!s.ok())
- return s;
+ auto [key_before_eviction, status] = WillUseDBIterator(/*perform_seek=*/true);
+ if (!status.ok())
+ return status;
DCHECK(iterator_);
// Exit early if not valid.
diff --git a/chromium/components/services/storage/indexed_db/transactional_leveldb/transactional_leveldb_iterator.h b/chromium/components/services/storage/indexed_db/transactional_leveldb/transactional_leveldb_iterator.h
index aa497672c5d..293ce558002 100644
--- a/chromium/components/services/storage/indexed_db/transactional_leveldb/transactional_leveldb_iterator.h
+++ b/chromium/components/services/storage/indexed_db/transactional_leveldb/transactional_leveldb_iterator.h
@@ -72,16 +72,16 @@ class TransactionalLevelDBIterator {
enum class Direction { kNext, kPrev };
enum class IteratorState { kActive, kEvictedAndValid, kEvictedAndInvalid };
- leveldb::Status WrappedIteratorStatus() WARN_UNUSED_RESULT;
+ [[nodiscard]] leveldb::Status WrappedIteratorStatus();
// Notifies the database of iterator usage and recreates iterator if needed.
// If the iterator was previously evicted, this method returns the key that
// was used, the status of reloading the iterator.
- std::tuple<std::string, leveldb::Status> WillUseDBIterator(bool perform_seek)
- WARN_UNUSED_RESULT;
+ [[nodiscard]] std::tuple<std::string, leveldb::Status> WillUseDBIterator(
+ bool perform_seek);
// If this method fails, then iterator_ will be nullptr.
- leveldb::Status ReloadIterator() WARN_UNUSED_RESULT;
+ [[nodiscard]] leveldb::Status ReloadIterator();
void NextPastScopesMetadata();
void PrevPastScopesMetadata();
diff --git a/chromium/components/services/storage/indexed_db/transactional_leveldb/transactional_leveldb_transaction.h b/chromium/components/services/storage/indexed_db/transactional_leveldb/transactional_leveldb_transaction.h
index a3a5c752fcc..2c4652fc481 100644
--- a/chromium/components/services/storage/indexed_db/transactional_leveldb/transactional_leveldb_transaction.h
+++ b/chromium/components/services/storage/indexed_db/transactional_leveldb/transactional_leveldb_transaction.h
@@ -10,7 +10,6 @@
#include <string>
#include "base/callback.h"
-#include "base/compiler_specific.h"
#include "base/containers/flat_set.h"
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
@@ -50,24 +49,24 @@ class TransactionalLevelDBTransaction
TransactionalLevelDBTransaction& operator=(
const TransactionalLevelDBTransaction&) = delete;
- leveldb::Status Put(const base::StringPiece& key,
- std::string* value) WARN_UNUSED_RESULT;
+ [[nodiscard]] leveldb::Status Put(const base::StringPiece& key,
+ std::string* value);
- leveldb::Status Remove(const base::StringPiece& key) WARN_UNUSED_RESULT;
+ [[nodiscard]] leveldb::Status Remove(const base::StringPiece& key);
- leveldb::Status RemoveRange(const base::StringPiece& begin,
- const base::StringPiece& end,
- LevelDBScopeDeletionMode deletion_mode)
- WARN_UNUSED_RESULT;
+ [[nodiscard]] leveldb::Status RemoveRange(
+ const base::StringPiece& begin,
+ const base::StringPiece& end,
+ LevelDBScopeDeletionMode deletion_mode);
- virtual leveldb::Status Get(const base::StringPiece& key,
- std::string* value,
- bool* found) WARN_UNUSED_RESULT;
- virtual leveldb::Status Commit(bool sync_on_commit) WARN_UNUSED_RESULT;
+ [[nodiscard]] virtual leveldb::Status Get(const base::StringPiece& key,
+ std::string* value,
+ bool* found);
+ [[nodiscard]] virtual leveldb::Status Commit(bool sync_on_commit);
// If the underlying scopes system is in single-sequence mode, then this
// method will return the result of the rollback task.
- leveldb::Status Rollback() WARN_UNUSED_RESULT;
+ [[nodiscard]] leveldb::Status Rollback();
// The returned iterator must be destroyed before the destruction of this
// transaction. This may return null, if it does, status will explain why.
diff --git a/chromium/components/services/storage/indexed_db/transactional_leveldb/transactional_leveldb_transaction_unittest.cc b/chromium/components/services/storage/indexed_db/transactional_leveldb/transactional_leveldb_transaction_unittest.cc
index 644beeed548..f2602dae6a6 100644
--- a/chromium/components/services/storage/indexed_db/transactional_leveldb/transactional_leveldb_transaction_unittest.cc
+++ b/chromium/components/services/storage/indexed_db/transactional_leveldb/transactional_leveldb_transaction_unittest.cc
@@ -15,7 +15,6 @@
#include "base/files/file.h"
#include "base/files/file_path.h"
-#include "base/no_destructor.h"
#include "base/strings/string_piece.h"
#include "base/test/bind.h"
#include "base/threading/sequenced_task_runner_handle.h"
diff --git a/chromium/components/services/storage/partition_impl.cc b/chromium/components/services/storage/partition_impl.cc
index 88d5a877127..d77cb004a94 100644
--- a/chromium/components/services/storage/partition_impl.cc
+++ b/chromium/components/services/storage/partition_impl.cc
@@ -88,7 +88,7 @@ void PartitionImpl::BindSessionStorageControl(
{base::MayBlock(), base::WithBaseSyncPrimitives(),
base::TaskShutdownBehavior::BLOCK_SHUTDOWN}),
base::SequencedTaskRunnerHandle::Get(),
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// On Android there is no support for session storage restoring, and since
// the restoring code is responsible for database cleanup, we must
// manually delete the old database here before we open a new one.
diff --git a/chromium/components/services/storage/public/cpp/BUILD.gn b/chromium/components/services/storage/public/cpp/BUILD.gn
index 3b259d0b6cf..867ebf97832 100644
--- a/chromium/components/services/storage/public/cpp/BUILD.gn
+++ b/chromium/components/services/storage/public/cpp/BUILD.gn
@@ -10,7 +10,6 @@ component("cpp") {
"constants.h",
"quota_client_callback_wrapper.h",
"quota_error_or.h",
- "storage_key_quota_client.h",
]
sources = [
diff --git a/chromium/components/services/storage/public/cpp/constants.cc b/chromium/components/services/storage/public/cpp/constants.cc
index c79decd3187..0ca6aa5ba1f 100644
--- a/chromium/components/services/storage/public/cpp/constants.cc
+++ b/chromium/components/services/storage/public/cpp/constants.cc
@@ -24,4 +24,8 @@ const char kLocalStorageLeveldbName[] = "leveldb";
const base::FilePath::CharType kServiceWorkerDirectory[] =
FILE_PATH_LITERAL("Service Worker");
+// The file name of the database storing media license data.
+const base::FilePath::CharType kMediaLicenseDatabaseFileName[] =
+ FILE_PATH_LITERAL("Media Licenses.db");
+
} // namespace storage
diff --git a/chromium/components/services/storage/public/cpp/constants.h b/chromium/components/services/storage/public/cpp/constants.h
index 3897d6b73b4..b2cdcf60758 100644
--- a/chromium/components/services/storage/public/cpp/constants.h
+++ b/chromium/components/services/storage/public/cpp/constants.h
@@ -22,6 +22,9 @@ extern const char kLocalStorageLeveldbName[];
COMPONENT_EXPORT(STORAGE_SERVICE_PUBLIC)
extern const base::FilePath::CharType kServiceWorkerDirectory[];
+COMPONENT_EXPORT(STORAGE_SERVICE_PUBLIC)
+extern const base::FilePath::CharType kMediaLicenseDatabaseFileName[];
+
} // namespace storage
#endif // COMPONENTS_SERVICES_STORAGE_PUBLIC_CPP_CONSTANTS_H_
diff --git a/chromium/components/services/storage/public/cpp/filesystem/filesystem_impl.cc b/chromium/components/services/storage/public/cpp/filesystem/filesystem_impl.cc
index fab8aa8f523..fbe4ab5b280 100644
--- a/chromium/components/services/storage/public/cpp/filesystem/filesystem_impl.cc
+++ b/chromium/components/services/storage/public/cpp/filesystem/filesystem_impl.cc
@@ -19,7 +19,7 @@
#include "build/build_config.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include <windows.h>
#endif
@@ -81,7 +81,7 @@ class FileLockImpl : public mojom::FileLock {
return;
}
-#if defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_FUCHSIA)
std::move(callback).Run(base::File::FILE_OK);
#else
std::move(callback).Run(file_.Unlock());
@@ -124,12 +124,11 @@ void FilesystemImpl::GetEntries(const base::FilePath& path,
// Fix up the absolute paths to be relative to |path|.
std::vector<base::FilePath> entries;
- std::vector<base::FilePath::StringType> root_components;
- full_path.GetComponents(&root_components);
+ std::vector<base::FilePath::StringType> root_components =
+ full_path.GetComponents();
const size_t num_components_to_strip = root_components.size();
for (const auto& entry : result.value()) {
- std::vector<base::FilePath::StringType> components;
- entry.GetComponents(&components);
+ std::vector<base::FilePath::StringType> components = entry.GetComponents();
base::FilePath relative_path;
for (size_t i = num_components_to_strip; i < components.size(); ++i)
relative_path = relative_path.Append(components[i]);
@@ -288,7 +287,7 @@ base::FileErrorOr<base::File> FilesystemImpl::LockFileLocal(
if (!GetLockTable().AddLock(path))
return base::File::FILE_ERROR_IN_USE;
-#if !defined(OS_FUCHSIA)
+#if !BUILDFLAG(IS_FUCHSIA)
base::File::Error error = file.Lock(base::File::LockMode::kExclusive);
if (error != base::File::FILE_OK)
return error;
@@ -306,7 +305,7 @@ void FilesystemImpl::UnlockFileLocal(const base::FilePath& path) {
mojom::PathAccessInfoPtr FilesystemImpl::GetPathAccessLocal(
const base::FilePath& path) {
mojom::PathAccessInfoPtr info;
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
uint32_t attributes = ::GetFileAttributes(path.value().c_str());
if (attributes != INVALID_FILE_ATTRIBUTES) {
info = mojom::PathAccessInfo::New();
@@ -314,7 +313,7 @@ mojom::PathAccessInfoPtr FilesystemImpl::GetPathAccessLocal(
if ((attributes & FILE_ATTRIBUTE_READONLY) == 0)
info->can_write = true;
}
-#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
const char* const c_path = path.value().c_str();
if (!access(c_path, F_OK)) {
info = mojom::PathAccessInfo::New();
diff --git a/chromium/components/services/storage/public/cpp/filesystem/filesystem_proxy.cc b/chromium/components/services/storage/public/cpp/filesystem/filesystem_proxy.cc
index 67a934a7c40..c2d7895529f 100644
--- a/chromium/components/services/storage/public/cpp/filesystem/filesystem_proxy.cc
+++ b/chromium/components/services/storage/public/cpp/filesystem/filesystem_proxy.cc
@@ -23,12 +23,6 @@ namespace storage {
namespace {
-size_t GetNumPathComponents(const base::FilePath& path) {
- std::vector<base::FilePath::StringType> components;
- path.GetComponents(&components);
- return components.size();
-}
-
class LocalFileLockImpl : public FilesystemProxy::FileLock {
public:
LocalFileLockImpl(base::FilePath path, base::File lock)
@@ -41,7 +35,7 @@ class LocalFileLockImpl : public FilesystemProxy::FileLock {
// FilesystemProxy::FileLock implementation:
base::File::Error Release() override {
base::File::Error error = base::File::FILE_OK;
-#if !defined(OS_FUCHSIA)
+#if !BUILDFLAG(IS_FUCHSIA)
error = lock_.Unlock();
#endif
lock_.Close();
@@ -89,7 +83,7 @@ FilesystemProxy::FilesystemProxy(
mojo::PendingRemote<mojom::Directory> directory,
scoped_refptr<base::SequencedTaskRunner> ipc_task_runner)
: root_(root),
- num_root_components_(GetNumPathComponents(root_)),
+ num_root_components_(root_.GetComponents().size()),
remote_directory_(std::move(directory), ipc_task_runner) {
DCHECK(root_.IsAbsolute());
}
@@ -380,8 +374,7 @@ base::FilePath FilesystemProxy::MakeRelative(const base::FilePath& path) const {
return base::FilePath();
// Absolute paths need to be rebased onto |root_|.
- std::vector<base::FilePath::StringType> components;
- path.GetComponents(&components);
+ std::vector<base::FilePath::StringType> components = path.GetComponents();
base::FilePath relative_path;
for (size_t i = num_root_components_; i < components.size(); ++i)
relative_path = relative_path.Append(components[i]);
diff --git a/chromium/components/services/storage/public/cpp/quota_client_callback_wrapper.cc b/chromium/components/services/storage/public/cpp/quota_client_callback_wrapper.cc
index 883a17d9f81..32256f4166b 100644
--- a/chromium/components/services/storage/public/cpp/quota_client_callback_wrapper.cc
+++ b/chromium/components/services/storage/public/cpp/quota_client_callback_wrapper.cc
@@ -8,6 +8,7 @@
#include "base/check_op.h"
#include "base/sequence_checker.h"
+#include "components/services/storage/public/cpp/buckets/bucket_locator.h"
#include "components/services/storage/public/mojom/quota_client.mojom.h"
#include "mojo/public/cpp/bindings/callback_helpers.h"
#include "third_party/blink/public/common/storage_key/storage_key.h"
@@ -26,14 +27,13 @@ QuotaClientCallbackWrapper::~QuotaClientCallbackWrapper() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
-void QuotaClientCallbackWrapper::GetStorageKeyUsage(
- const blink::StorageKey& storage_key,
- blink::mojom::StorageType type,
- GetStorageKeyUsageCallback callback) {
+void QuotaClientCallbackWrapper::GetBucketUsage(
+ const BucketLocator& bucket,
+ GetBucketUsageCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- wrapped_client_->GetStorageKeyUsage(
- storage_key, type,
+ wrapped_client_->GetBucketUsage(
+ bucket,
mojo::WrapCallbackWithDefaultInvokeIfNotRun(std::move(callback), 0));
}
@@ -47,26 +47,13 @@ void QuotaClientCallbackWrapper::GetStorageKeysForType(
std::move(callback), std::vector<blink::StorageKey>()));
}
-void QuotaClientCallbackWrapper::GetStorageKeysForHost(
- blink::mojom::StorageType type,
- const std::string& host,
- GetStorageKeysForHostCallback callback) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
- wrapped_client_->GetStorageKeysForHost(
- type, host,
- mojo::WrapCallbackWithDefaultInvokeIfNotRun(
- std::move(callback), std::vector<blink::StorageKey>()));
-}
-
-void QuotaClientCallbackWrapper::DeleteStorageKeyData(
- const blink::StorageKey& storage_key,
- blink::mojom::StorageType type,
- DeleteStorageKeyDataCallback callback) {
+void QuotaClientCallbackWrapper::DeleteBucketData(
+ const BucketLocator& bucket,
+ DeleteBucketDataCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- wrapped_client_->DeleteStorageKeyData(
- storage_key, type,
+ wrapped_client_->DeleteBucketData(
+ bucket,
mojo::WrapCallbackWithDefaultInvokeIfNotRun(
std::move(callback), blink::mojom::QuotaStatusCode::kErrorAbort));
}
diff --git a/chromium/components/services/storage/public/cpp/quota_client_callback_wrapper.h b/chromium/components/services/storage/public/cpp/quota_client_callback_wrapper.h
index f964baf1528..5935e56d02a 100644
--- a/chromium/components/services/storage/public/cpp/quota_client_callback_wrapper.h
+++ b/chromium/components/services/storage/public/cpp/quota_client_callback_wrapper.h
@@ -10,12 +10,10 @@
#include "base/thread_annotations.h"
#include "components/services/storage/public/mojom/quota_client.mojom.h"
-namespace blink {
-class StorageKey;
-} // namespace blink
-
namespace storage {
+struct BucketLocator;
+
// Stopgap for QuotaClients in systems with an unclear ownership graph.
//
// Implements the QuotaClient interface by proxying to a "real" implementation.
@@ -54,17 +52,12 @@ class COMPONENT_EXPORT(STORAGE_SERVICE_PUBLIC) QuotaClientCallbackWrapper
~QuotaClientCallbackWrapper() override;
// mojom::QuotaClient.
- void GetStorageKeyUsage(const blink::StorageKey& storage_key,
- blink::mojom::StorageType type,
- GetStorageKeyUsageCallback callback) override;
+ void GetBucketUsage(const BucketLocator& bucket,
+ GetBucketUsageCallback callback) override;
void GetStorageKeysForType(blink::mojom::StorageType type,
GetStorageKeysForTypeCallback callback) override;
- void GetStorageKeysForHost(blink::mojom::StorageType type,
- const std::string& host,
- GetStorageKeysForHostCallback callback) override;
- void DeleteStorageKeyData(const blink::StorageKey& storage_key,
- blink::mojom::StorageType type,
- DeleteStorageKeyDataCallback callback) override;
+ void DeleteBucketData(const BucketLocator& bucket,
+ DeleteBucketDataCallback callback) override;
void PerformStorageCleanup(blink::mojom::StorageType type,
PerformStorageCleanupCallback callback) override;
diff --git a/chromium/components/services/storage/public/cpp/storage_key_quota_client.h b/chromium/components/services/storage/public/cpp/storage_key_quota_client.h
deleted file mode 100644
index 7c0ac11520c..00000000000
--- a/chromium/components/services/storage/public/cpp/storage_key_quota_client.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2021 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.
-
-#ifndef COMPONENTS_SERVICES_STORAGE_PUBLIC_CPP_STORAGE_KEY_QUOTA_CLIENT_H_
-#define COMPONENTS_SERVICES_STORAGE_PUBLIC_CPP_STORAGE_KEY_QUOTA_CLIENT_H_
-
-#include "components/services/storage/public/mojom/quota_client.mojom.h"
-
-namespace storage {
-
-// Interface for storage key based QuotaClient to be inherited by quota managed
-// storage APIs that have not implemented Storage Buckets support yet. As
-// Storage APIs migrate their implementation to support Storage Buckets, they
-// should use the bucket base QuotaClient to be added as part of
-// crbug.com/1199417.
-//
-// TODO(crbug.com/1214066): Once all storage API's have migrated off storage key
-// based QuotaClient. This class should be removed and all API's should inherit
-// from bucket based QuotaClient.
-class COMPONENT_EXPORT(STORAGE_SERVICE_PUBLIC) StorageKeyQuotaClient
- : public mojom::QuotaClient {
- protected:
- ~StorageKeyQuotaClient() override = default;
-};
-
-} // namespace storage
-
-#endif // COMPONENTS_SERVICES_STORAGE_PUBLIC_CPP_STORAGE_KEY_QUOTA_CLIENT_H_
diff --git a/chromium/components/services/storage/public/mojom/quota_client.mojom b/chromium/components/services/storage/public/mojom/quota_client.mojom
index e64fb788eab..52f9aea8cde 100644
--- a/chromium/components/services/storage/public/mojom/quota_client.mojom
+++ b/chromium/components/services/storage/public/mojom/quota_client.mojom
@@ -6,6 +6,7 @@ module storage.mojom;
import "third_party/blink/public/mojom/quota/quota_types.mojom";
import "third_party/blink/public/mojom/storage_key/storage_key.mojom";
+import "components/services/storage/public/mojom/buckets/bucket_locator.mojom";
// Interface between each storage API and the quota manager.
//
@@ -17,25 +18,24 @@ import "third_party/blink/public/mojom/storage_key/storage_key.mojom";
// currently lives in the browser process, and will eventually move to the
// Storage Service process.
interface QuotaClient {
- // Returns the amount of data stored in the storage specified by `storage_key`
- // and `type`.
- GetStorageKeyUsage(blink.mojom.StorageKey storage_key,
- blink.mojom.StorageType type)
- => (int64 usage);
+ // Returns the amount of data stored in the storage specified by `bucket`.
+ // The quota manager should not assume that 0 `usage` means the
+ // storage API has no record of the `bucket`'s existence.
+ // DeleteBucketData() is the only way to guarantee that storage APIs erase
+ // all tracks of a `bucket`.
+ GetBucketUsage(BucketLocator bucket) => (int64 usage);
- // Returns a list of storage keys that have data in the `type` storage.
- GetStorageKeysForType(blink.mojom.StorageType type)
- => (array<blink.mojom.StorageKey> storage_keys);
-
- // Returns a list of storage keys that match the `host` and have data in the
+ // Returns a list of storage keys that have data in the default bucket for
// `type` storage.
- GetStorageKeysForHost(blink.mojom.StorageType type, string host)
+ //
+ // This method is currently used to bootstrap the buckets table in the quota
+ // database with data produced by old code. No other uses should be added.
+ // We're planning to remove this around 2024.
+ GetStorageKeysForType(blink.mojom.StorageType type)
=> (array<blink.mojom.StorageKey> storage_keys);
- // Returns after all data belonging to `storage_key` in the `type` storage
- // has been deleted.
- DeleteStorageKeyData(blink.mojom.StorageKey storage_key,
- blink.mojom.StorageType type)
+ // Returns after all data belonging to `bucket` has been deleted.
+ DeleteBucketData(BucketLocator bucket)
=> (blink.mojom.QuotaStatusCode status);
// An opportunity to perform a cleanup step after major deletions.
diff --git a/chromium/components/services/storage/service_worker/service_worker_database.cc b/chromium/components/services/storage/service_worker/service_worker_database.cc
index c539b19c5c8..dbf4ba5d433 100644
--- a/chromium/components/services/storage/service_worker/service_worker_database.cc
+++ b/chromium/components/services/storage/service_worker/service_worker_database.cc
@@ -19,6 +19,7 @@
#include "components/services/storage/filesystem_proxy_factory.h"
#include "components/services/storage/service_worker/service_worker_database.pb.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "third_party/blink/public/common/storage_key/storage_key.h"
#include "third_party/blink/public/mojom/service_worker/service_worker_database.mojom.h"
#include "third_party/leveldatabase/env_chromium.h"
#include "third_party/leveldatabase/leveldb_chrome.h"
@@ -63,7 +64,8 @@
// be updated in the future to avoid a migration.
// TODO(crbug.com/1199077): Update name during a migration to Version 3.
// key: "REG:" + <StorageKey 'key'.origin> + "/" + [ "^0" + <StorageKey
-// `key`.top_level_site> ] + '\x00' + <int64_t 'registration_id'>
+// `key`.top_level_site> + "^3" + <StorageKey `key`.ancestor_chain_bit> ] +
+// '\x00' + <int64_t 'registration_id'>
// - or -
// key: "REG:" + <StorageKey 'key'.origin> + "/" + "^1" + <StorageKey
// 'nonce'.High64Bits> + "^2" + <StorageKey 'nonce'.Low64Bits> + '\x00' +
@@ -95,7 +97,7 @@
// TODO(crbug.com/1199077): Update name during a migration to Version 3.
// key: "REGID_TO_ORIGIN:" + <int64_t 'registration_id'>
// value: <StorageKey 'key'.origin> + "/" + [ "^0" + <StorageKey
-// `key`.top_level_site> ]
+// `key`.top_level_site> + "^3" + <StorageKey `key`.ancestor_chain_bit>]
// - or -
// value: <StorageKey 'key'.origin> + "/" + "^1" + <StorageKey
// 'nonce'.High64Bits> + "^2" + <StorageKey 'nonce'.Low64Bits>
@@ -115,45 +117,6 @@
// OBSOLETE: https://crbug.com/788604
// key: "INITDATA_FOREIGN_FETCH_ORIGIN:" + <GURL 'origin'>
// value: <empty>
-namespace {
-
-// Returns true if the registration key string is partitioned by top-level site
-// but storage partitioning is currently disabled. Returns false if the key
-// string contains a serialized nonce.
-bool ShouldSkipKeyDueToPartitioning(const std::string& reg_key_string) {
- // Don't skip anything if storage partitioning is enabled.
- if (blink::StorageKey::IsThirdPartyStoragePartitioningEnabled())
- return false;
-
- // TODO(crbug.com/1246549) : This currently counts carets to tell the
- // difference between nonce and top-level site schemes. When the ancestor bit
- // is implemented this will need to be modified to handle that case (since it
- // will also use 2 carets).
- int number_of_carets =
- std::count(reg_key_string.begin(), reg_key_string.end(), '^');
-
- switch (number_of_carets) {
- case 2: {
- // Don't skip if a nonce serialization scheme is found.
- return false;
- }
- case 1: {
- // Do skip if partitioning is disabled and we detect a top-level site
- // serialization scheme.
- return true;
- }
- case 0: {
- // Don't skip for a 1p context key.
- return false;
- }
- default: {
- NOTREACHED();
- return true;
- }
- }
-}
-
-} // namespace
namespace storage {
@@ -431,7 +394,7 @@ ServiceWorkerDatabase::GetStorageKeysWithRegistrations(
service_worker_internals::kUniqueOriginKey, &key_str))
break;
- if (ShouldSkipKeyDueToPartitioning(key_str))
+ if (blink::StorageKey::ShouldSkipKeyDueToPartitioning(key_str))
continue;
absl::optional<blink::StorageKey> key =
@@ -623,7 +586,7 @@ ServiceWorkerDatabase::Status ServiceWorkerDatabase::GetAllRegistrations(
// Get only the sub-string before the separator.
std::string reg_key_string = prefix_string.substr(0, separator_pos);
- if (ShouldSkipKeyDueToPartitioning(reg_key_string))
+ if (blink::StorageKey::ShouldSkipKeyDueToPartitioning(reg_key_string))
continue;
absl::optional<blink::StorageKey> key =
@@ -700,7 +663,7 @@ ServiceWorkerDatabase::Status ServiceWorkerDatabase::ReadRegistrationStorageKey(
// If storage partitioning is disabled we shouldn't have any handles to
// registration IDs associated with partitioned entries.
- DCHECK(!ShouldSkipKeyDueToPartitioning(value));
+ DCHECK(!blink::StorageKey::ShouldSkipKeyDueToPartitioning(value));
absl::optional<blink::StorageKey> parsed =
blink::StorageKey::Deserialize(value);
diff --git a/chromium/components/services/storage/service_worker/service_worker_storage.cc b/chromium/components/services/storage/service_worker/service_worker_storage.cc
index 59a32d7e89a..3dbac654f20 100644
--- a/chromium/components/services/storage/service_worker/service_worker_storage.cc
+++ b/chromium/components/services/storage/service_worker/service_worker_storage.cc
@@ -20,6 +20,7 @@
#include "base/task/sequenced_task_runner.h"
#include "base/task/task_runner_util.h"
#include "base/task/thread_pool.h"
+#include "base/time/time.h"
#include "base/trace_event/trace_event.h"
#include "components/services/storage/public/cpp/constants.h"
#include "components/services/storage/service_worker/service_worker_disk_cache.h"
@@ -1580,6 +1581,8 @@ void ServiceWorkerStorage::ReadInitialDataFromDB(
ServiceWorkerDatabase* database,
scoped_refptr<base::SequencedTaskRunner> original_task_runner,
InitializeCallback callback) {
+ base::TimeTicks now = base::TimeTicks::Now();
+
DCHECK(database);
std::unique_ptr<ServiceWorkerStorage::InitialData> data(
new ServiceWorkerStorage::InitialData());
@@ -1604,6 +1607,10 @@ void ServiceWorkerStorage::ReadInitialDataFromDB(
original_task_runner->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), std::move(data), status));
+
+ base::UmaHistogramMediumTimes(
+ "ServiceWorker.Storage.ReadInitialDataFromDB.Time",
+ base::TimeTicks::Now() - now);
}
void ServiceWorkerStorage::DeleteRegistrationFromDB(
diff --git a/chromium/components/services/storage/service_worker/service_worker_storage_control_impl.cc b/chromium/components/services/storage/service_worker/service_worker_storage_control_impl.cc
index d5d1ccb754f..9001b00dc84 100644
--- a/chromium/components/services/storage/service_worker/service_worker_storage_control_impl.cc
+++ b/chromium/components/services/storage/service_worker/service_worker_storage_control_impl.cc
@@ -5,6 +5,7 @@
#include "components/services/storage/service_worker/service_worker_storage_control_impl.h"
#include "base/containers/contains.h"
+#include "base/debug/alias.h"
#include "components/services/storage/service_worker/service_worker_resource_ops.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
@@ -483,6 +484,10 @@ ServiceWorkerStorageControlImpl::CreateLiveVersionReferenceRemote(
reference->Add(remote_reference.InitWithNewPipeAndPassReceiver());
live_versions_[version_id] = std::move(reference);
} else {
+ // TODO(https://crbug.com/1277263): Remove the following CHECK() once the
+ // cause is identified.
+ base::debug::Alias(&version_id);
+ CHECK(it->second.get()) << "Invalid version id: " << version_id;
it->second->Add(remote_reference.InitWithNewPipeAndPassReceiver());
}
return remote_reference;
diff --git a/chromium/components/services/storage/service_worker/service_worker_storage_control_impl_unittest.cc b/chromium/components/services/storage/service_worker/service_worker_storage_control_impl_unittest.cc
index 4ba4aaa8093..a17552bdbee 100644
--- a/chromium/components/services/storage/service_worker/service_worker_storage_control_impl_unittest.cc
+++ b/chromium/components/services/storage/service_worker/service_worker_storage_control_impl_unittest.cc
@@ -88,6 +88,11 @@ struct GetUserDataForAllRegistrationsResult {
std::vector<mojom::ServiceWorkerUserDataPtr> values;
};
+struct GetUsageForStorageKeyResult {
+ DatabaseStatus status;
+ int64_t usage;
+};
+
ReadResponseHeadResult ReadResponseHead(
mojom::ServiceWorkerResourceReader* reader) {
ReadResponseHeadResult result;
@@ -570,6 +575,21 @@ class ServiceWorkerStorageControlImplTest : public testing::Test {
return return_value;
}
+ GetUsageForStorageKeyResult GetUsageForStorageKey(
+ const blink::StorageKey& key) {
+ GetUsageForStorageKeyResult result;
+ base::RunLoop loop;
+ storage()->GetUsageForStorageKey(
+ key,
+ base::BindLambdaForTesting([&](DatabaseStatus status, int64_t usage) {
+ result.status = status;
+ result.usage = usage;
+ loop.Quit();
+ }));
+ loop.Run();
+ return result;
+ }
+
// Creates a registration with the given resource records.
RegistrationData CreateRegistrationData(
int64_t registration_id,
@@ -1423,6 +1443,92 @@ TEST_F(ServiceWorkerStorageControlImplTest,
EXPECT_EQ(result.values.size(), 0UL);
}
+// Tests that getting usage for a storage key works at different stages of
+// registration resource update.
+TEST_F(ServiceWorkerStorageControlImplTest, GetUsageForStorageKey) {
+ const GURL kScope("https://www.example.com/");
+ const blink::StorageKey kKey(url::Origin::Create(kScope));
+ const GURL kScriptUrl("https://www.example.com/sw.js");
+ const GURL kImportedScriptUrl("https://www.example.com/imported.js");
+
+ LazyInitializeForTest();
+
+ // No data has written yet for a given storage key.
+ {
+ GetUsageForStorageKeyResult result = GetUsageForStorageKey(kKey);
+ ASSERT_EQ(result.status, DatabaseStatus::kOk);
+ ASSERT_EQ(result.usage, 0);
+ }
+
+ // Preparation: Create a registration with two resources. These aren't written
+ // to storage yet.
+ std::vector<ResourceRecord> resources;
+ const int64_t resource_id1 = GetNewResourceId();
+ const std::string resource_data1 = "main script data";
+ resources.push_back(mojom::ServiceWorkerResourceRecord::New(
+ resource_id1, kScriptUrl, resource_data1.size()));
+
+ const int64_t resource_id2 = GetNewResourceId();
+ const std::string resource_data2 = "imported script data";
+ resources.push_back(mojom::ServiceWorkerResourceRecord::New(
+ resource_id2, kImportedScriptUrl, resource_data2.size()));
+
+ const int64_t registration_id = GetNewRegistrationId();
+ const int64_t version_id = GetNewVersionId().version_id;
+ RegistrationData registration_data = CreateRegistrationData(
+ registration_id, version_id, kScope, kKey, kScriptUrl, resources);
+
+ // Put these resources ids on the uncommitted list in storage.
+ DatabaseStatus status;
+ status = StoreUncommittedResourceId(resource_id1);
+ ASSERT_EQ(status, DatabaseStatus::kOk);
+ status = StoreUncommittedResourceId(resource_id2);
+ ASSERT_EQ(status, DatabaseStatus::kOk);
+
+ {
+ GetUsageForStorageKeyResult result = GetUsageForStorageKey(kKey);
+ ASSERT_EQ(result.status, DatabaseStatus::kOk);
+ ASSERT_EQ(result.usage, 0)
+ << "Resources that aren't stored with the registration "
+ << "don't use quota.";
+ }
+
+ // Write responses and the registration data.
+ {
+ int result = WriteResource(resource_id1, resource_data1);
+ ASSERT_GT(result, 0);
+ }
+ {
+ int result = WriteResource(resource_id2, resource_data2);
+ ASSERT_GT(result, 0);
+ }
+ status =
+ StoreRegistration(std::move(registration_data), std::move(resources));
+ ASSERT_EQ(status, DatabaseStatus::kOk);
+
+ // Expect the storage usage for resources stored.
+ {
+ GetUsageForStorageKeyResult result = GetUsageForStorageKey(kKey);
+ ASSERT_EQ(result.status, DatabaseStatus::kOk);
+ const int64_t expected_usage =
+ resource_data1.size() + resource_data2.size();
+ ASSERT_EQ(result.usage, expected_usage);
+ }
+
+ // Delete the registration.
+ {
+ DeleteRegistrationResult result = DeleteRegistration(registration_id, kKey);
+ ASSERT_EQ(result.status, DatabaseStatus::kOk);
+ }
+
+ // Expect no storage usage.
+ {
+ GetUsageForStorageKeyResult result = GetUsageForStorageKey(kKey);
+ ASSERT_EQ(result.status, DatabaseStatus::kOk);
+ ASSERT_EQ(result.usage, 0);
+ }
+}
+
// Tests that apply policy updates work.
TEST_F(ServiceWorkerStorageControlImplTest, ApplyPolicyUpdates) {
const GURL kScope1("https://foo.example.com/");
diff --git a/chromium/components/services/storage/service_worker/service_worker_storage_unittest.cc b/chromium/components/services/storage/service_worker/service_worker_storage_unittest.cc
index be27d1faa0e..8b325727c14 100644
--- a/chromium/components/services/storage/service_worker/service_worker_storage_unittest.cc
+++ b/chromium/components/services/storage/service_worker/service_worker_storage_unittest.cc
@@ -913,7 +913,7 @@ TEST_F(ServiceWorkerStorageDiskTest, DeleteAndStartOver_OpenedFileExists) {
base::BindOnce(&DatabaseStatusCallback, run_loop.QuitClosure(), &status));
run_loop.Run();
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// On Windows, deleting the directory containing an opened file should fail.
EXPECT_EQ(ServiceWorkerDatabase::Status::kErrorIOError, *status);
EXPECT_TRUE(storage()->IsDisabled());
diff --git a/chromium/components/services/storage/shared_storage/DIR_METADATA b/chromium/components/services/storage/shared_storage/DIR_METADATA
new file mode 100644
index 00000000000..95ccec4a089
--- /dev/null
+++ b/chromium/components/services/storage/shared_storage/DIR_METADATA
@@ -0,0 +1,12 @@
+# Metadata information for this directory.
+#
+# For more information on DIR_METADATA files, see:
+# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/README.md
+#
+# For the schema of this file, see Metadata message:
+# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
+
+monorail {
+ component: "Blink>Storage>SharedStorage"
+}
+team_email: "chrome-ads-core@google.com"
diff --git a/chromium/components/services/storage/shared_storage/OWNERS b/chromium/components/services/storage/shared_storage/OWNERS
new file mode 100644
index 00000000000..6ab87565cd2
--- /dev/null
+++ b/chromium/components/services/storage/shared_storage/OWNERS
@@ -0,0 +1,6 @@
+# Primary:
+cammie@chromium.org
+
+# Secondary:
+yaoxia@chromium.org
+jkarlin@chromium.org
diff --git a/chromium/components/services/storage/shared_storage/async_shared_storage_database.cc b/chromium/components/services/storage/shared_storage/async_shared_storage_database.cc
new file mode 100644
index 00000000000..3a6d9f438e6
--- /dev/null
+++ b/chromium/components/services/storage/shared_storage/async_shared_storage_database.cc
@@ -0,0 +1,196 @@
+// Copyright 2021 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.
+
+#include "components/services/storage/shared_storage/async_shared_storage_database.h"
+
+#include <inttypes.h>
+
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/files/file_util.h"
+#include "base/time/time.h"
+#include "components/services/storage/public/mojom/storage_usage_info.mojom.h"
+#include "components/services/storage/shared_storage/shared_storage_options.h"
+#include "storage/browser/quota/special_storage_policy.h"
+#include "url/origin.h"
+
+namespace storage {
+
+// static
+std::unique_ptr<AsyncSharedStorageDatabase> AsyncSharedStorageDatabase::Create(
+ base::FilePath db_path,
+ scoped_refptr<base::SequencedTaskRunner> blocking_task_runner,
+ scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy,
+ std::unique_ptr<SharedStorageDatabaseOptions> options) {
+ return absl::WrapUnique(new AsyncSharedStorageDatabase(
+ std::move(db_path), std::move(blocking_task_runner),
+ std::move(special_storage_policy), std::move(options)));
+}
+
+AsyncSharedStorageDatabase::AsyncSharedStorageDatabase(
+ base::FilePath db_path,
+ scoped_refptr<base::SequencedTaskRunner> blocking_task_runner,
+ scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy,
+ std::unique_ptr<SharedStorageDatabaseOptions> options)
+ : database_(base::SequenceBound<SharedStorageDatabase>(
+ std::move(blocking_task_runner),
+ std::move(db_path),
+ std::move(special_storage_policy),
+ std::move(options))) {}
+
+AsyncSharedStorageDatabase::~AsyncSharedStorageDatabase() = default;
+
+void AsyncSharedStorageDatabase::Destroy(
+ base::OnceCallback<void(bool)> callback) {
+ DCHECK(database_);
+ database_.AsyncCall(&SharedStorageDatabase::Destroy)
+ .Then(std::move(callback));
+}
+
+void AsyncSharedStorageDatabase::TrimMemory(base::OnceClosure callback) {
+ DCHECK(database_);
+ database_.AsyncCall(&SharedStorageDatabase::TrimMemory)
+ .Then(std::move(callback));
+}
+
+void AsyncSharedStorageDatabase::Get(
+ url::Origin context_origin,
+ std::u16string key,
+ base::OnceCallback<void(GetResult)> callback) {
+ DCHECK(database_);
+ database_.AsyncCall(&SharedStorageDatabase::Get)
+ .WithArgs(std::move(context_origin), std::move(key))
+ .Then(std::move(callback));
+}
+
+void AsyncSharedStorageDatabase::Set(
+ url::Origin context_origin,
+ std::u16string key,
+ std::u16string value,
+ base::OnceCallback<void(OperationResult)> callback,
+ SetBehavior behavior) {
+ DCHECK(database_);
+ database_.AsyncCall(&SharedStorageDatabase::Set)
+ .WithArgs(std::move(context_origin), std::move(key), std::move(value),
+ behavior)
+ .Then(std::move(callback));
+}
+
+void AsyncSharedStorageDatabase::Append(
+ url::Origin context_origin,
+ std::u16string key,
+ std::u16string value,
+ base::OnceCallback<void(OperationResult)> callback) {
+ DCHECK(database_);
+ database_.AsyncCall(&SharedStorageDatabase::Append)
+ .WithArgs(std::move(context_origin), std::move(key), std::move(value))
+ .Then(std::move(callback));
+}
+
+void AsyncSharedStorageDatabase::Delete(
+ url::Origin context_origin,
+ std::u16string key,
+ base::OnceCallback<void(OperationResult)> callback) {
+ DCHECK(database_);
+ database_.AsyncCall(&SharedStorageDatabase::Delete)
+ .WithArgs(std::move(context_origin), std::move(key))
+ .Then(std::move(callback));
+}
+
+void AsyncSharedStorageDatabase::Clear(
+ url::Origin context_origin,
+ base::OnceCallback<void(OperationResult)> callback) {
+ DCHECK(database_);
+ database_.AsyncCall(&SharedStorageDatabase::Clear)
+ .WithArgs(std::move(context_origin))
+ .Then(std::move(callback));
+}
+
+void AsyncSharedStorageDatabase::Length(
+ url::Origin context_origin,
+ base::OnceCallback<void(int)> callback) {
+ DCHECK(database_);
+ database_.AsyncCall(&SharedStorageDatabase::Length)
+ .WithArgs(std::move(context_origin))
+ .Then(std::move(callback));
+}
+
+void AsyncSharedStorageDatabase::Key(
+ url::Origin context_origin,
+ int index,
+ base::OnceCallback<void(GetResult)> callback) {
+ DCHECK_GE(index, 0);
+ DCHECK(database_);
+ database_.AsyncCall(&SharedStorageDatabase::Key)
+ .WithArgs(std::move(context_origin), static_cast<uint64_t>(index))
+ .Then(std::move(callback));
+}
+
+void AsyncSharedStorageDatabase::PurgeMatchingOrigins(
+ OriginMatcherFunction origin_matcher,
+ base::Time begin,
+ base::Time end,
+ base::OnceCallback<void(OperationResult)> callback,
+ bool perform_storage_cleanup) {
+ DCHECK(database_);
+ database_.AsyncCall(&SharedStorageDatabase::PurgeMatchingOrigins)
+ .WithArgs(std::move(origin_matcher), begin, end, perform_storage_cleanup)
+ .Then(std::move(callback));
+}
+
+void AsyncSharedStorageDatabase::PurgeStaleOrigins(
+ base::TimeDelta window_to_be_deemed_active,
+ base::OnceCallback<void(OperationResult)> callback) {
+ DCHECK(database_);
+ database_.AsyncCall(&SharedStorageDatabase::PurgeStaleOrigins)
+ .WithArgs(window_to_be_deemed_active)
+ .Then(std::move(callback));
+}
+
+void AsyncSharedStorageDatabase::FetchOrigins(
+ base::OnceCallback<void(std::vector<mojom::StorageUsageInfoPtr>)>
+ callback) {
+ DCHECK(database_);
+ database_.AsyncCall(&SharedStorageDatabase::FetchOrigins)
+ .Then(std::move(callback));
+}
+
+void AsyncSharedStorageDatabase::IsOpenForTesting(
+ base::OnceCallback<void(bool)> callback) {
+ DCHECK(database_);
+ database_.AsyncCall(&SharedStorageDatabase::IsOpenForTesting)
+ .Then(std::move(callback));
+}
+
+void AsyncSharedStorageDatabase::DBStatusForTesting(
+ base::OnceCallback<void(InitStatus)> callback) {
+ DCHECK(database_);
+ database_.AsyncCall(&SharedStorageDatabase::DBStatusForTesting)
+ .Then(std::move(callback));
+}
+
+void AsyncSharedStorageDatabase::OverrideLastUsedTimeForTesting(
+ url::Origin context_origin,
+ base::Time override_last_used_time,
+ base::OnceCallback<void(bool)> callback) {
+ DCHECK(database_);
+ database_.AsyncCall(&SharedStorageDatabase::OverrideLastUsedTimeForTesting)
+ .WithArgs(std::move(context_origin), override_last_used_time)
+ .Then(std::move(callback));
+}
+
+void AsyncSharedStorageDatabase::OverrideSpecialStoragePolicyForTesting(
+ scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy,
+ base::OnceCallback<void(bool)> callback) {
+ DCHECK(database_);
+ database_
+ .AsyncCall(&SharedStorageDatabase::OverrideSpecialStoragePolicyForTesting)
+ .WithArgs(std::move(special_storage_policy))
+ .Then(std::move(callback));
+}
+
+} // namespace storage
diff --git a/chromium/components/services/storage/shared_storage/async_shared_storage_database.h b/chromium/components/services/storage/shared_storage/async_shared_storage_database.h
new file mode 100644
index 00000000000..1771c4ff3d8
--- /dev/null
+++ b/chromium/components/services/storage/shared_storage/async_shared_storage_database.h
@@ -0,0 +1,237 @@
+// Copyright 2021 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.
+
+#ifndef COMPONENTS_SERVICES_STORAGE_SHARED_STORAGE_ASYNC_SHARED_STORAGE_DATABASE_H_
+#define COMPONENTS_SERVICES_STORAGE_SHARED_STORAGE_ASYNC_SHARED_STORAGE_DATABASE_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/callback_forward.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/task/sequenced_task_runner.h"
+#include "base/threading/sequence_bound.h"
+#include "components/services/storage/shared_storage/shared_storage_database.h"
+
+namespace base {
+class FilePath;
+class Time;
+class TimeDelta;
+} // namespace base
+
+namespace url {
+class Origin;
+} // namespace url
+
+namespace storage {
+struct SharedStorageDatabaseOptions;
+class SpecialStoragePolicy;
+
+// A wrapper around SharedStorageDatabase which makes the operations
+// asynchronous.
+class AsyncSharedStorageDatabase {
+ public:
+ using InitStatus = SharedStorageDatabase::InitStatus;
+ using SetBehavior = SharedStorageDatabase::SetBehavior;
+ using OperationResult = SharedStorageDatabase::OperationResult;
+ using GetResult = SharedStorageDatabase::GetResult;
+
+ // A callback type to check if a given origin matches a storage policy.
+ // Can be passed empty/null where used, which means the origin will always
+ // match.
+ using OriginMatcherFunction = SharedStorageDatabase::OriginMatcherFunction;
+
+ // Creates an `AsyncSharedStorageDatabase` instance. If `db_path` is empty,
+ // creates a temporary, in-memory database; otherwise creates a persistent
+ // database within a filesystem directory given by `db_path`, which must be an
+ // absolute path. If file-backed, the database may or may not already exist at
+ // `db_path`, and if it doesn't, it will be created.
+ //
+ // The instance will be bound to and perform all operations on
+ // `blocking_task_runner`, which must support blocking operations.
+ static std::unique_ptr<AsyncSharedStorageDatabase> Create(
+ base::FilePath db_path,
+ scoped_refptr<base::SequencedTaskRunner> blocking_task_runner,
+ scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy,
+ std::unique_ptr<SharedStorageDatabaseOptions> options);
+
+ AsyncSharedStorageDatabase(const AsyncSharedStorageDatabase&) = delete;
+ AsyncSharedStorageDatabase& operator=(const AsyncSharedStorageDatabase&) =
+ delete;
+ AsyncSharedStorageDatabase(const AsyncSharedStorageDatabase&&) = delete;
+ AsyncSharedStorageDatabase& operator=(const AsyncSharedStorageDatabase&&) =
+ delete;
+
+ ~AsyncSharedStorageDatabase();
+
+ base::SequenceBound<SharedStorageDatabase>&
+ GetSequenceBoundDatabaseForTesting() {
+ return database_;
+ }
+
+ // Destroys the database.
+ //
+ // If filebacked, deletes the persistent database within the filesystem
+ // directory.
+ //
+ // It is OK to call `Destroy()` regardless of whether database initialization
+ // was successful.
+ void Destroy(base::OnceCallback<void(bool)> callback);
+
+ // `TrimMemory()`, `Get()`, `Set()`, `Append()`, `Delete()`, `Clear()`,
+ // `Length()`, `Key()`, `PurgeMatchingOrigins()`, `PurgeStaleOrigins()`, and
+ // `FetchOrigins()` are all async versions of the corresponding methods in
+ // `storage::SharedStorageDatabase`, with the modification that `Set()` and
+ // `Append()` take a boolean callback to indicate that a value was set or
+ // appended, rather than a long integer callback with the row number for the
+ // next available row.
+ //
+ // It is OK to call these async methods even if the database has failed to
+ // initialize, as there is an alternate code path to handle this case that
+ // skips accessing `database_` (as it will be null) and hence performing the
+ // intending operation, logs the occurrence of the missing database to UMA,
+ // and runs the callback with a trivial instance of its expected result type).
+
+ // Releases all non-essential memory associated with this database connection.
+ // `callback` runs once the operation is finished.
+ void TrimMemory(base::OnceClosure callback);
+
+ // Retrieves the `value` for `context_origin` and `key`. `callback` is called
+ // with a struct bundling a string `value` in its data field if one is found,
+ // `absl::nullopt` otherwise, and a OperationResult to indicate whether the
+ // transaction was free of database errors.
+ //
+ // `key` must be of length at most
+ // `SharedStorageDatabaseOptions::max_string_length`, with the burden on the
+ // caller to handle errors for strings that exceed this length.
+ void Get(url::Origin context_origin,
+ std::u16string key,
+ base::OnceCallback<void(GetResult)> callback);
+
+ // Sets an entry for `context_origin` and `key` to have `value`.
+ // If `behavior` is `kIgnoreIfPresent` and an entry already exists for
+ // `context_origin` and `key`, then the database table is not modified.
+ // The parameter of `callback` reports whether or not any entry is added, the
+ // request is ignored, or if there is an error.
+ //
+ // `key` and `value` must be each of length at most
+ // `SharedStorageDatabaseOptions::max_string_length`, with the burden on the
+ // caller to handle errors for strings that exceed this length. Moreover, if
+ // the length retrieved by `Length(context_origin, callback)` equals
+ // `SharedStorageDatabaseOptions::max_entries_per_origin_`, `Set()` will fail
+ // and the table will not be modified.
+ void Set(url::Origin context_origin,
+ std::u16string key,
+ std::u16string value,
+ base::OnceCallback<void(OperationResult)> callback,
+ SetBehavior behavior = SetBehavior::kDefault);
+
+ // Appends `value` to the end of the current `value` for `context_origin` and
+ // `key`, if `key` exists. If `key` does not exist, creates an entry for `key`
+ // with value `value`. The parameter of `callback` reports whether or not any
+ // entry is added or modified or if there is an error.
+ //
+ // `key` and `value` must be each of length at most
+ // `SharedStorageDatabaseOptions::max_string_length`, with the burden on the
+ // caller to handle errors for strings that exceed this length. Moreover, if
+ // the length of the string obtained by concatening the current `script_value`
+ // (if one exists) and `value` exceeds
+ // `SharedStorageDatabaseOptions::max_string_length`, or if the length
+ // retrieved by `Length(context_origin, callback)` equals
+ // `SharedStorageDatabaseOptions::max_entries_per_origin_`, `Append()` will
+ // fail and the database table will not be modified.
+ void Append(url::Origin context_origin,
+ std::u16string key,
+ std::u16string value,
+ base::OnceCallback<void(OperationResult)> callback);
+
+ // Deletes the entry for `context_origin` and `key`. The parameter of
+ // `callback` reports whether the deletion is successful.
+ //
+ // `key` must be of length at most
+ // `SharedStorageDatabaseOptions::max_string_length`, with the burden on the
+ // caller to handle errors for strings that exceed this length.
+ void Delete(url::Origin context_origin,
+ std::u16string key,
+ base::OnceCallback<void(OperationResult)> callback);
+
+ // Clears all entries for `context_origin`. The parameter of `callback`
+ // reports whether the operation is successful.
+ void Clear(url::Origin context_origin,
+ base::OnceCallback<void(OperationResult)> callback);
+
+ // The parameter of `callback` reports the number of entries for
+ // `context_origin`, 0 if there are none, or -1 on operation failure.
+ void Length(url::Origin context_origin,
+ base::OnceCallback<void(int)> callback);
+
+ // If a list of all the keys for `context_origin` are taken in lexicographic
+ // order, retrieves the `key` at `index` of the list and calls `callback` with
+ // a struct bundling it as a parameter (along with a OperationResult to
+ // indicate whether the transaction was free of database errors); otherwise
+ // calls `callback` with `absl::nullopt` in the data field of the struct.
+ // `index` must be non-negative.
+ //
+ // TODO(crbug.com/1247861): Replace with an async iterator.
+ void Key(url::Origin context_origin,
+ int index,
+ base::OnceCallback<void(GetResult)> callback);
+
+ // Clears all origins that match `origin_matcher` run on the owning
+ // StoragePartition's `SpecialStoragePolicy` and have `last_used_time` between
+ // the times `begin` and `end`. If `perform_storage_cleanup` is true, vacuums
+ // the database afterwards. The parameter of `callback` reports whether the
+ // transaction was successful.
+ //
+ // Note that `origin_matcher` is accessed on a different sequence than where
+ // it was created.
+ void PurgeMatchingOrigins(OriginMatcherFunction origin_matcher,
+ base::Time begin,
+ base::Time end,
+ base::OnceCallback<void(OperationResult)> callback,
+ bool perform_storage_cleanup = false);
+
+ // Clear all entries for all origins whose `last_read_time` falls before
+ // `base::Time::Now() - window_to_be_deemed_active`.
+ void PurgeStaleOrigins(base::TimeDelta window_to_be_deemed_active,
+ base::OnceCallback<void(OperationResult)> callback);
+
+ // Fetches a vector of `mojom::StorageUsageInfoPtr`, with one
+ // `mojom::StorageUsageInfoPtr` for each origin currently using shared storage
+ // in this profile.
+ void FetchOrigins(
+ base::OnceCallback<void(std::vector<mojom::StorageUsageInfoPtr>)>
+ callback);
+
+ // Asynchronously determines whether the database is open. Useful for testing.
+ void IsOpenForTesting(base::OnceCallback<void(bool)> callback);
+
+ // Asynchronously determines the database `InitStatus`. Useful for testing.
+ void DBStatusForTesting(base::OnceCallback<void(InitStatus)> callback);
+
+ // Changes `last_used_time` to `override_last_used_time` for `context_origin`.
+ void OverrideLastUsedTimeForTesting(url::Origin context_origin,
+ base::Time override_last_used_time,
+ base::OnceCallback<void(bool)> callback);
+
+ // Overrides the `SpecialStoragePolicy` for tests.
+ void OverrideSpecialStoragePolicyForTesting(
+ scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy,
+ base::OnceCallback<void(bool)> callback);
+
+ private:
+ // Instances should be obtained from the `Create()` factory method.
+ AsyncSharedStorageDatabase(
+ base::FilePath db_path,
+ scoped_refptr<base::SequencedTaskRunner> blocking_task_runner,
+ scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy,
+ std::unique_ptr<SharedStorageDatabaseOptions> options);
+
+ base::SequenceBound<SharedStorageDatabase> database_;
+};
+
+} // namespace storage
+
+#endif // COMPONENTS_SERVICES_STORAGE_SHARED_STORAGE_ASYNC_SHARED_STORAGE_DATABASE_H_
diff --git a/chromium/components/services/storage/shared_storage/async_shared_storage_database_unittest.cc b/chromium/components/services/storage/shared_storage/async_shared_storage_database_unittest.cc
new file mode 100644
index 00000000000..fdf3041a271
--- /dev/null
+++ b/chromium/components/services/storage/shared_storage/async_shared_storage_database_unittest.cc
@@ -0,0 +1,1648 @@
+// Copyright 2021 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.
+
+#include "components/services/storage/shared_storage/async_shared_storage_database.h"
+
+#include <memory>
+#include <queue>
+#include <string>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/callback_helpers.h"
+#include "base/files/file.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/run_loop.h"
+#include "base/strings/strcat.h"
+#include "base/task/sequenced_task_runner.h"
+#include "base/task/thread_pool.h"
+#include "base/test/bind.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/test/task_environment.h"
+#include "base/test/test_future.h"
+#include "base/threading/sequence_bound.h"
+#include "base/threading/thread.h"
+#include "components/services/storage/public/mojom/storage_usage_info.mojom.h"
+#include "components/services/storage/shared_storage/shared_storage_database.h"
+#include "components/services/storage/shared_storage/shared_storage_options.h"
+#include "components/services/storage/shared_storage/shared_storage_test_utils.h"
+#include "sql/database.h"
+#include "storage/browser/quota/special_storage_policy.h"
+#include "storage/browser/test/mock_special_storage_policy.h"
+#include "testing/gmock/include/gmock/gmock-matchers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/features.h"
+#include "url/gurl.h"
+#include "url/origin.h"
+
+namespace storage {
+
+namespace {
+
+using ::testing::ElementsAre;
+using InitStatus = SharedStorageDatabase::InitStatus;
+using SetBehavior = SharedStorageDatabase::SetBehavior;
+using OperationResult = SharedStorageDatabase::OperationResult;
+using GetResult = SharedStorageDatabase::GetResult;
+using DBOperation = TestDatabaseOperationReceiver::DBOperation;
+using Type = DBOperation::Type;
+
+const int kMaxEntriesPerOrigin = 5;
+const int kMaxStringLength = 100;
+
+} // namespace
+
+class AsyncSharedStorageDatabaseTest : public testing::Test {
+ public:
+ AsyncSharedStorageDatabaseTest()
+ : task_runner_(base::ThreadPool::CreateSequencedTaskRunner(
+ {base::MayBlock(), base::WithBaseSyncPrimitives(),
+ base::TaskShutdownBehavior::BLOCK_SHUTDOWN})),
+ special_storage_policy_(
+ base::MakeRefCounted<MockSpecialStoragePolicy>()),
+ receiver_(std::make_unique<TestDatabaseOperationReceiver>()) {}
+
+ ~AsyncSharedStorageDatabaseTest() override = default;
+
+ void SetUp() override {
+ InitSharedStorageFeature();
+
+ // Get a temporary directory for the test DB files.
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+
+ file_name_ = temp_dir_.GetPath().AppendASCII("TestSharedStorage.db");
+ }
+
+ void TearDown() override {
+ task_environment_.RunUntilIdle();
+
+ // It's not strictly necessary as part of test cleanup, but here we test
+ // the code path that force razes the database, and, if file-backed,
+ // force deletes the database file.
+ EXPECT_TRUE(DestroySync());
+ EXPECT_FALSE(base::PathExists(file_name_));
+ EXPECT_TRUE(temp_dir_.Delete());
+ }
+
+ virtual void InitSharedStorageFeature() {
+ scoped_feature_list_.InitAndEnableFeatureWithParameters(
+ {blink::features::kSharedStorageAPI},
+ {{"MaxSharedStorageInitTries", "1"}});
+ }
+
+ // Initialize an async shared storage database instance from the SQL file at
+ // `relative_file_path` in the "storage/" subdirectory of test data.
+ void LoadFromFileSync(const char* relative_file_path) {
+ DCHECK(!file_name_.empty());
+
+ ASSERT_TRUE(CreateDatabaseFromSQL(file_name_, relative_file_path));
+
+ async_database_ = AsyncSharedStorageDatabase::Create(
+ file_name_, task_runner_, special_storage_policy_,
+ SharedStorageOptions::Create()->GetDatabaseOptions());
+ }
+
+ void CreateSync(const base::FilePath& db_path,
+ std::unique_ptr<SharedStorageDatabaseOptions> options) {
+ async_database_ = AsyncSharedStorageDatabase::Create(
+ db_path, task_runner_, special_storage_policy_, std::move(options));
+ }
+
+ void Destroy(bool* out_success) {
+ DCHECK(out_success);
+ DCHECK(async_database_);
+ DCHECK(receiver_);
+
+ DBOperation operation(Type::DB_DESTROY);
+ auto callback =
+ receiver_->MakeBoolCallback(std::move(operation), out_success);
+ async_database_->Destroy(std::move(callback));
+ }
+
+ bool DestroySync() {
+ if (!async_database_)
+ return true;
+
+ base::test::TestFuture<bool> future;
+ async_database_->Destroy(future.GetCallback());
+ EXPECT_TRUE(future.Wait());
+ return future.Get();
+ }
+
+ bool is_finished() const {
+ DCHECK(receiver_);
+ return receiver_->is_finished();
+ }
+
+ void SetExpectedOperationList(std::queue<DBOperation> expected_operations) {
+ DCHECK(receiver_);
+ receiver_->set_expected_operations(std::move(expected_operations));
+ }
+
+ void WaitForOperations() {
+ DCHECK(receiver_);
+ receiver_->WaitForOperations();
+ }
+
+ void VerifySharedStorageTablesAndColumnsSync() {
+ DCHECK(async_database_);
+
+ auto task = base::BindOnce([](SharedStorageDatabase* db) -> bool {
+ auto* sql_db = db->db();
+ EXPECT_TRUE(sql_db);
+ VerifySharedStorageTablesAndColumns(*sql_db);
+ return true;
+ });
+
+ base::test::TestFuture<bool> future;
+
+ auto wrapped_task = base::BindOnce(
+ [](base::OnceCallback<bool(SharedStorageDatabase*)> task,
+ base::OnceCallback<void(bool)> callback,
+ scoped_refptr<base::SequencedTaskRunner> callback_task_runner,
+ SharedStorageDatabase* db) {
+ callback_task_runner->PostTask(
+ FROM_HERE,
+ base::BindOnce(std::move(callback), std::move(task).Run(db)));
+ },
+ std::move(task), future.GetCallback(),
+ base::SequencedTaskRunnerHandle::Get());
+
+ async_database_->GetSequenceBoundDatabaseForTesting()
+ .PostTaskWithThisObject(std::move(wrapped_task));
+
+ EXPECT_TRUE(future.Wait());
+ EXPECT_TRUE(future.Get());
+ }
+
+ void IsOpen(bool* out_boolean) {
+ DCHECK(out_boolean);
+ DCHECK(async_database_);
+ DCHECK(receiver_);
+
+ DBOperation operation(Type::DB_IS_OPEN);
+ auto callback =
+ receiver_->MakeBoolCallback(std::move(operation), out_boolean);
+ async_database_->IsOpenForTesting(std::move(callback));
+ }
+
+ bool IsOpenSync() {
+ DCHECK(async_database_);
+
+ base::test::TestFuture<bool> future;
+ async_database_->IsOpenForTesting(future.GetCallback());
+ EXPECT_TRUE(future.Wait());
+ return future.Get();
+ }
+
+ void DBStatus(InitStatus* out_status) {
+ DCHECK(out_status);
+ DCHECK(async_database_);
+ DCHECK(receiver_);
+
+ DBOperation operation(Type::DB_STATUS);
+ auto callback =
+ receiver_->MakeStatusCallback(std::move(operation), out_status);
+ async_database_->DBStatusForTesting(std::move(callback));
+ }
+
+ InitStatus DBStatusSync() {
+ DCHECK(async_database_);
+
+ base::test::TestFuture<InitStatus> future;
+ async_database_->DBStatusForTesting(future.GetCallback());
+ EXPECT_TRUE(future.Wait());
+ return future.Get();
+ }
+
+ void TrimMemory() {
+ DCHECK(async_database_);
+ DCHECK(receiver_);
+
+ DBOperation operation(Type::DB_TRIM_MEMORY);
+ auto callback = receiver_->MakeOnceClosure(std::move(operation));
+ async_database_->TrimMemory(std::move(callback));
+ }
+
+ void OverrideLastUsedTime(url::Origin context_origin,
+ base::Time override_last_used_time,
+ bool* out_success) {
+ DCHECK(out_success);
+ DCHECK(async_database_);
+ DCHECK(receiver_);
+
+ DBOperation operation(Type::DB_OVERRIDE_TIME, context_origin,
+ {TestDatabaseOperationReceiver::SerializeTime(
+ override_last_used_time)});
+ auto callback =
+ receiver_->MakeBoolCallback(std::move(operation), out_success);
+ async_database_->OverrideLastUsedTimeForTesting(std::move(context_origin),
+ override_last_used_time,
+ std::move(callback));
+ }
+
+ void Get(url::Origin context_origin,
+ std::u16string key,
+ GetResult* out_value) {
+ DCHECK(out_value);
+ DCHECK(async_database_);
+ DCHECK(receiver_);
+
+ DBOperation operation(Type::DB_GET, context_origin, {key});
+ auto callback =
+ receiver_->MakeGetResultCallback(std::move(operation), out_value);
+ async_database_->Get(std::move(context_origin), std::move(key),
+ std::move(callback));
+ }
+
+ GetResult GetSync(url::Origin context_origin, std::u16string key) {
+ DCHECK(async_database_);
+
+ base::test::TestFuture<GetResult> future;
+ async_database_->Get(std::move(context_origin), std::move(key),
+ future.GetCallback());
+ EXPECT_TRUE(future.Wait());
+ return future.Get();
+ }
+
+ void Set(url::Origin context_origin,
+ std::u16string key,
+ std::u16string value,
+ OperationResult* out_result,
+ SetBehavior behavior = SetBehavior::kDefault) {
+ DCHECK(out_result);
+ DCHECK(async_database_);
+ DCHECK(receiver_);
+
+ *out_result = OperationResult::kSqlError;
+ DBOperation operation(
+ Type::DB_SET, context_origin,
+ {key, value, base::NumberToString16(static_cast<int>(behavior))});
+ auto callback = receiver_->MakeOperationResultCallback(std::move(operation),
+ out_result);
+ async_database_->Set(std::move(context_origin), std::move(key),
+ std::move(value), std::move(callback), behavior);
+ }
+
+ OperationResult SetSync(url::Origin context_origin,
+ std::u16string key,
+ std::u16string value,
+ SetBehavior behavior = SetBehavior::kDefault) {
+ DCHECK(async_database_);
+
+ base::test::TestFuture<OperationResult> future;
+ async_database_->Set(std::move(context_origin), std::move(key),
+ std::move(value), future.GetCallback(), behavior);
+ EXPECT_TRUE(future.Wait());
+ return future.Get();
+ }
+
+ void Append(url::Origin context_origin,
+ std::u16string key,
+ std::u16string value,
+ OperationResult* out_result) {
+ DCHECK(out_result);
+ DCHECK(async_database_);
+ DCHECK(receiver_);
+
+ *out_result = OperationResult::kSqlError;
+ DBOperation operation(Type::DB_APPEND, context_origin, {key, value});
+ auto callback = receiver_->MakeOperationResultCallback(std::move(operation),
+ out_result);
+ async_database_->Append(std::move(context_origin), std::move(key),
+ std::move(value), std::move(callback));
+ }
+
+ OperationResult AppendSync(url::Origin context_origin,
+ std::u16string key,
+ std::u16string value) {
+ DCHECK(async_database_);
+
+ base::test::TestFuture<OperationResult> future;
+ async_database_->Append(std::move(context_origin), std::move(key),
+ std::move(value), future.GetCallback());
+ EXPECT_TRUE(future.Wait());
+ return future.Get();
+ }
+
+ void Delete(url::Origin context_origin,
+ std::u16string key,
+ OperationResult* out_result) {
+ DCHECK(out_result);
+ DCHECK(async_database_);
+ DCHECK(receiver_);
+
+ *out_result = OperationResult::kSqlError;
+ DBOperation operation(Type::DB_DELETE, context_origin, {key});
+ auto callback = receiver_->MakeOperationResultCallback(std::move(operation),
+ out_result);
+ async_database_->Delete(std::move(context_origin), std::move(key),
+ std::move(callback));
+ }
+
+ OperationResult DeleteSync(url::Origin context_origin, std::u16string key) {
+ DCHECK(async_database_);
+
+ base::test::TestFuture<OperationResult> future;
+ async_database_->Delete(std::move(context_origin), std::move(key),
+ future.GetCallback());
+ EXPECT_TRUE(future.Wait());
+ return future.Get();
+ }
+
+ void Length(url::Origin context_origin, int* out_length) {
+ DCHECK(out_length);
+ DCHECK(async_database_);
+ DCHECK(receiver_);
+
+ *out_length = -1;
+ DBOperation operation(Type::DB_LENGTH, context_origin);
+ auto callback =
+ receiver_->MakeIntCallback(std::move(operation), out_length);
+ async_database_->Length(std::move(context_origin), std::move(callback));
+ }
+
+ int LengthSync(url::Origin context_origin) {
+ DCHECK(async_database_);
+
+ base::test::TestFuture<int> future;
+ async_database_->Length(std::move(context_origin), future.GetCallback());
+ EXPECT_TRUE(future.Wait());
+ return future.Get();
+ }
+
+ void Key(url::Origin context_origin, int index, GetResult* out_key) {
+ DCHECK(out_key);
+ DCHECK(async_database_);
+ DCHECK(receiver_);
+
+ DBOperation operation(Type::DB_KEY, context_origin,
+ {base::NumberToString16(index)});
+ auto callback =
+ receiver_->MakeGetResultCallback(std::move(operation), out_key);
+ async_database_->Key(std::move(context_origin), index, std::move(callback));
+ }
+
+ GetResult KeySync(url::Origin context_origin, int index) {
+ DCHECK(async_database_);
+
+ base::test::TestFuture<GetResult> future;
+ async_database_->Key(std::move(context_origin), index,
+ future.GetCallback());
+ EXPECT_TRUE(future.Wait());
+ return future.Get();
+ }
+
+ void Clear(url::Origin context_origin, OperationResult* out_result) {
+ DCHECK(out_result);
+ DCHECK(async_database_);
+ DCHECK(receiver_);
+
+ *out_result = OperationResult::kSqlError;
+ DBOperation operation(Type::DB_CLEAR, context_origin);
+ auto callback = receiver_->MakeOperationResultCallback(std::move(operation),
+ out_result);
+ async_database_->Clear(std::move(context_origin), std::move(callback));
+ }
+
+ OperationResult ClearSync(url::Origin context_origin) {
+ DCHECK(async_database_);
+
+ base::test::TestFuture<OperationResult> future;
+ async_database_->Clear(std::move(context_origin), future.GetCallback());
+ EXPECT_TRUE(future.Wait());
+ return future.Get();
+ }
+
+ void FetchOrigins(std::vector<mojom::StorageUsageInfoPtr>* out_result) {
+ DCHECK(out_result);
+ DCHECK(async_database_);
+ DCHECK(receiver_);
+
+ DBOperation operation(Type::DB_FETCH_ORIGINS);
+ auto callback =
+ receiver_->MakeInfosCallback(std::move(operation), out_result);
+ async_database_->FetchOrigins(std::move(callback));
+ }
+
+ std::vector<mojom::StorageUsageInfoPtr> FetchOriginsSync() {
+ DCHECK(async_database_);
+
+ base::test::TestFuture<std::vector<mojom::StorageUsageInfoPtr>> future;
+ async_database_->FetchOrigins(future.GetCallback());
+ EXPECT_TRUE(future.Wait());
+ return future.Take();
+ }
+
+ void PurgeMatchingOrigins(OriginMatcherFunctionUtility* matcher_utility,
+ size_t matcher_id,
+ base::Time begin,
+ base::Time end,
+ OperationResult* out_result,
+ bool perform_storage_cleanup = false) {
+ DCHECK(out_result);
+ DCHECK(async_database_);
+ DCHECK(receiver_);
+ DCHECK(matcher_utility);
+ DCHECK(!(*matcher_utility).is_empty());
+ DCHECK_LT(matcher_id, (*matcher_utility).size());
+
+ std::vector<std::u16string> params(
+ {base::NumberToString16(matcher_id),
+ TestDatabaseOperationReceiver::SerializeTime(begin),
+ TestDatabaseOperationReceiver::SerializeTime(end),
+ TestDatabaseOperationReceiver::SerializeBool(
+ perform_storage_cleanup)});
+ DBOperation operation(Type::DB_PURGE_MATCHING, std::move(params));
+ auto callback = receiver_->MakeOperationResultCallback(std::move(operation),
+ out_result);
+ async_database_->PurgeMatchingOrigins(
+ matcher_utility->TakeMatcherFunctionForId(matcher_id), begin, end,
+ std::move(callback), perform_storage_cleanup);
+ }
+
+ void PurgeStaleOrigins(base::TimeDelta window_to_be_deemed_active,
+ OperationResult* out_result) {
+ DCHECK(out_result);
+ DCHECK(async_database_);
+ DCHECK(receiver_);
+
+ DBOperation operation(Type::DB_PURGE_STALE,
+ {TestDatabaseOperationReceiver::SerializeTimeDelta(
+ window_to_be_deemed_active)});
+ auto callback = receiver_->MakeOperationResultCallback(std::move(operation),
+ out_result);
+ async_database_->PurgeStaleOrigins(window_to_be_deemed_active,
+ std::move(callback));
+ }
+
+ protected:
+ base::test::TaskEnvironment task_environment_;
+ scoped_refptr<base::SequencedTaskRunner> task_runner_;
+ scoped_refptr<storage::MockSpecialStoragePolicy> special_storage_policy_;
+ std::unique_ptr<AsyncSharedStorageDatabase> async_database_;
+ std::unique_ptr<TestDatabaseOperationReceiver> receiver_;
+ base::test::ScopedFeatureList scoped_feature_list_;
+ base::ScopedTempDir temp_dir_;
+ base::FilePath file_name_;
+};
+
+// Test loading version 1 database.
+TEST_F(AsyncSharedStorageDatabaseTest, Version1_LoadFromFile) {
+ LoadFromFileSync("shared_storage.v1.sql");
+ ASSERT_TRUE(async_database_);
+
+ url::Origin google_com = url::Origin::Create(GURL("http://google.com/"));
+ EXPECT_EQ(GetSync(google_com, u"key1").data, u"value1");
+ EXPECT_EQ(GetSync(google_com, u"key2").data, u"value2");
+
+ // Because the SQL database is lazy-initialized, wait to verify tables and
+ // columns until after the first call to `GetSync()`.
+ VerifySharedStorageTablesAndColumnsSync();
+
+ std::vector<url::Origin> origins;
+ for (const auto& info : FetchOriginsSync())
+ origins.push_back(info->origin);
+ EXPECT_THAT(
+ origins,
+ ElementsAre(url::Origin::Create(GURL("http://abc.xyz")),
+ url::Origin::Create(GURL("http://chromium.org")), google_com,
+ url::Origin::Create(GURL("http://google.org")),
+ url::Origin::Create(GURL("http://growwithgoogle.com")),
+ url::Origin::Create(GURL("http://gv.com")),
+ url::Origin::Create(GURL("http://waymo.com")),
+ url::Origin::Create(GURL("http://withgoogle.com")),
+ url::Origin::Create(GURL("http://youtube.com"))));
+}
+
+TEST_F(AsyncSharedStorageDatabaseTest, Version1_DestroyTooNew) {
+ // Initialization should fail, since the last compatible version number
+ // is too high.
+ LoadFromFileSync("shared_storage.v1.init_too_new.sql");
+ ASSERT_TRUE(async_database_);
+
+ // Call an operation so that the database will attempt to be lazy-initialized.
+ EXPECT_EQ(
+ OperationResult::kInitFailure,
+ SetSync(url::Origin::Create(GURL("http://www.a.com")), u"key", u"value"));
+ ASSERT_FALSE(IsOpenSync());
+ EXPECT_EQ(InitStatus::kTooNew, DBStatusSync());
+
+ // Test that it is still OK to `Destroy()` the database.
+ EXPECT_TRUE(DestroySync());
+}
+
+TEST_F(AsyncSharedStorageDatabaseTest, Version0_DestroyTooOld) {
+ // Initialization should fail, since the current version number
+ // is too low and we're forcing there not to be a retry attempt.
+ LoadFromFileSync("shared_storage.v0.init_too_old.sql");
+ ASSERT_TRUE(async_database_);
+
+ // Call an operation so that the database will attempt to be lazy-initialized.
+ EXPECT_EQ(
+ OperationResult::kInitFailure,
+ SetSync(url::Origin::Create(GURL("http://www.a.com")), u"key", u"value"));
+ ASSERT_FALSE(IsOpenSync());
+ EXPECT_EQ(InitStatus::kTooOld, DBStatusSync());
+
+ // Test that it is still OK to `Destroy()` the database.
+ EXPECT_TRUE(DestroySync());
+}
+
+class AsyncSharedStorageDatabaseParamTest
+ : public AsyncSharedStorageDatabaseTest,
+ public testing::WithParamInterface<SharedStorageWrappedBool> {
+ public:
+ void SetUp() override {
+ AsyncSharedStorageDatabaseTest::SetUp();
+
+ auto options = SharedStorageOptions::Create()->GetDatabaseOptions();
+
+ if (GetParam().in_memory_only)
+ CreateSync(base::FilePath(), std::move(options));
+ else
+ CreateSync(file_name_, std::move(options));
+ }
+
+ void TearDown() override {
+ if (!GetParam().in_memory_only) {
+ // `TearDown()` will call `DestroySync()`. First verify that the file
+ // exists, so that when the we verify after destruction in `TearDown()`
+ // that the file no longer exists, we know that `Destroy()` was indeed
+ // successful.
+ EXPECT_TRUE(base::PathExists(file_name_));
+ }
+
+ AsyncSharedStorageDatabaseTest::TearDown();
+ }
+
+ void InitSharedStorageFeature() override {
+ scoped_feature_list_.InitAndEnableFeatureWithParameters(
+ {blink::features::kSharedStorageAPI},
+ {{"MaxSharedStorageEntriesPerOrigin",
+ base::NumberToString(kMaxEntriesPerOrigin)},
+ {"MaxSharedStorageStringLength",
+ base::NumberToString(kMaxStringLength)}});
+ }
+};
+
+INSTANTIATE_TEST_SUITE_P(All,
+ AsyncSharedStorageDatabaseParamTest,
+ testing::ValuesIn(GetSharedStorageWrappedBools()),
+ testing::PrintToStringParamName());
+
+// Operations are tested more thoroughly in shared_storage_database_unittest.cc.
+TEST_P(AsyncSharedStorageDatabaseParamTest, SyncOperations) {
+ url::Origin kOrigin1 = url::Origin::Create(GURL("http://www.example1.test"));
+ EXPECT_EQ(OperationResult::kSet, SetSync(kOrigin1, u"key1", u"value1"));
+ EXPECT_EQ(GetSync(kOrigin1, u"key1").data, u"value1");
+
+ EXPECT_EQ(OperationResult::kSet, SetSync(kOrigin1, u"key1", u"value2"));
+ EXPECT_EQ(GetSync(kOrigin1, u"key1").data, u"value2");
+
+ EXPECT_EQ(OperationResult::kSet, SetSync(kOrigin1, u"key2", u"value1"));
+ EXPECT_EQ(GetSync(kOrigin1, u"key2").data, u"value1");
+ EXPECT_EQ(2, LengthSync(kOrigin1));
+
+ EXPECT_EQ(OperationResult::kSuccess, DeleteSync(kOrigin1, u"key1"));
+ EXPECT_FALSE(GetSync(kOrigin1, u"key1").data);
+ EXPECT_EQ(1, LengthSync(kOrigin1));
+
+ EXPECT_EQ(OperationResult::kSet, AppendSync(kOrigin1, u"key1", u"value1"));
+ EXPECT_EQ(GetSync(kOrigin1, u"key1").data, u"value1");
+ EXPECT_EQ(2, LengthSync(kOrigin1));
+
+ EXPECT_EQ(OperationResult::kSet, AppendSync(kOrigin1, u"key1", u"value1"));
+ EXPECT_EQ(GetSync(kOrigin1, u"key1").data,
+ base::StrCat({u"value1", u"value1"}));
+ EXPECT_EQ(2, LengthSync(kOrigin1));
+
+ EXPECT_EQ(KeySync(kOrigin1, 0).data, u"key1");
+ EXPECT_EQ(KeySync(kOrigin1, 1).data, u"key2");
+
+ EXPECT_EQ(OperationResult::kSuccess, ClearSync(kOrigin1));
+ EXPECT_EQ(0, LengthSync(kOrigin1));
+}
+
+// Verifies that the async operations are executed in order and without races.
+TEST_P(AsyncSharedStorageDatabaseParamTest, AsyncOperations) {
+ url::Origin kOrigin1 = url::Origin::Create(GURL("http://www.example1.test"));
+
+ std::queue<DBOperation> operation_list(
+ {{Type::DB_SET,
+ kOrigin1,
+ {u"key1", u"value1",
+ TestDatabaseOperationReceiver::SerializeSetBehavior(
+ SetBehavior::kDefault)}},
+ {Type::DB_GET, kOrigin1, {u"key1"}},
+ {Type::DB_SET,
+ kOrigin1,
+ {u"key1", u"value2",
+ TestDatabaseOperationReceiver::SerializeSetBehavior(
+ SetBehavior::kDefault)}},
+ {Type::DB_GET, kOrigin1, {u"key1"}},
+ {Type::DB_SET,
+ kOrigin1,
+ {u"key2", u"value1",
+ TestDatabaseOperationReceiver::SerializeSetBehavior(
+ SetBehavior::kDefault)}},
+ {Type::DB_GET, kOrigin1, {u"key2"}},
+ {Type::DB_LENGTH, kOrigin1},
+ {Type::DB_DELETE, kOrigin1, {u"key1"}},
+ {Type::DB_LENGTH, kOrigin1},
+ {Type::DB_APPEND, kOrigin1, {u"key1", u"value1"}},
+ {Type::DB_GET, kOrigin1, {u"key1"}},
+ {Type::DB_LENGTH, kOrigin1},
+ {Type::DB_APPEND, kOrigin1, {u"key1", u"value1"}},
+ {Type::DB_GET, kOrigin1, {u"key1"}},
+ {Type::DB_LENGTH, kOrigin1},
+ {Type::DB_KEY, kOrigin1, {base::NumberToString16(0)}},
+ {Type::DB_KEY, kOrigin1, {base::NumberToString16(1)}},
+ {Type::DB_CLEAR, kOrigin1},
+ {Type::DB_LENGTH, kOrigin1}});
+
+ SetExpectedOperationList(std::move(operation_list));
+
+ OperationResult result1 = OperationResult::kSqlError;
+ Set(kOrigin1, u"key1", u"value1", &result1);
+ GetResult value1;
+ Get(kOrigin1, u"key1", &value1);
+ OperationResult result2 = OperationResult::kSqlError;
+ Set(kOrigin1, u"key1", u"value2", &result2);
+ GetResult value2;
+ Get(kOrigin1, u"key1", &value2);
+ OperationResult result3 = OperationResult::kSqlError;
+ Set(kOrigin1, u"key2", u"value1", &result3);
+ GetResult value3;
+ Get(kOrigin1, u"key2", &value3);
+ int length1 = -1;
+ Length(kOrigin1, &length1);
+
+ OperationResult result4 = OperationResult::kSqlError;
+ Delete(kOrigin1, u"key1", &result4);
+ int length2 = -1;
+ Length(kOrigin1, &length2);
+
+ OperationResult result5 = OperationResult::kSqlError;
+ Append(kOrigin1, u"key1", u"value1", &result5);
+ GetResult value4;
+ Get(kOrigin1, u"key1", &value4);
+ int length3 = -1;
+ Length(kOrigin1, &length3);
+
+ OperationResult result6 = OperationResult::kSqlError;
+ Append(kOrigin1, u"key1", u"value1", &result6);
+ GetResult value5;
+ Get(kOrigin1, u"key1", &value5);
+ int length4 = -1;
+ Length(kOrigin1, &length4);
+
+ GetResult key1;
+ Key(kOrigin1, 0, &key1);
+ GetResult key2;
+ Key(kOrigin1, 1, &key2);
+
+ OperationResult result7 = OperationResult::kSqlError;
+ Clear(kOrigin1, &result7);
+ int length5 = -1;
+ Length(kOrigin1, &length5);
+
+ WaitForOperations();
+ EXPECT_TRUE(is_finished());
+
+ EXPECT_EQ(OperationResult::kSet, result1);
+ EXPECT_EQ(value1.data, u"value1");
+ EXPECT_EQ(OperationResult::kSet, result2);
+ EXPECT_EQ(value2.data, u"value2");
+ EXPECT_EQ(OperationResult::kSet, result3);
+ EXPECT_EQ(value3.data, u"value1");
+ EXPECT_EQ(2, length1);
+
+ EXPECT_EQ(OperationResult::kSuccess, result4);
+ EXPECT_EQ(1, length2);
+
+ EXPECT_EQ(OperationResult::kSet, result5);
+ EXPECT_EQ(value4.data, u"value1");
+ EXPECT_EQ(2, length3);
+
+ EXPECT_EQ(OperationResult::kSet, result6);
+ EXPECT_EQ(value5.data, u"value1value1");
+ EXPECT_EQ(2, length4);
+
+ EXPECT_EQ(key1.data, u"key1");
+ EXPECT_EQ(key2.data, u"key2");
+
+ EXPECT_EQ(OperationResult::kSuccess, result7);
+ EXPECT_EQ(0, length5);
+}
+
+TEST_P(AsyncSharedStorageDatabaseParamTest,
+ LazyInit_IgnoreForGet_CreateForSet) {
+ url::Origin kOrigin1 = url::Origin::Create(GURL("http://www.example1.test"));
+
+ std::queue<DBOperation> operation_list;
+ operation_list.push(DBOperation(Type::DB_IS_OPEN));
+ operation_list.push(DBOperation(Type::DB_STATUS));
+ operation_list.push(DBOperation(Type::DB_GET, kOrigin1, {u"key1"}));
+ operation_list.push(DBOperation(Type::DB_IS_OPEN));
+ operation_list.push(DBOperation(Type::DB_STATUS));
+ operation_list.push(
+ DBOperation(Type::DB_SET, kOrigin1,
+ {u"key1", u"value1",
+ TestDatabaseOperationReceiver::SerializeSetBehavior(
+ SetBehavior::kDefault)}));
+ operation_list.push(DBOperation(Type::DB_IS_OPEN));
+ operation_list.push(DBOperation(Type::DB_STATUS));
+ operation_list.push(DBOperation(Type::DB_GET, kOrigin1, {u"key1"}));
+ operation_list.push(DBOperation(Type::DB_LENGTH, kOrigin1));
+
+ SetExpectedOperationList(std::move(operation_list));
+
+ bool open1 = false;
+ IsOpen(&open1);
+ InitStatus status1 = InitStatus::kUnattempted;
+ DBStatus(&status1);
+
+ // Test that we can successfully call `Get()` on a nonexistent key before the
+ // database is initialized.
+ GetResult value1;
+ Get(kOrigin1, u"key1", &value1);
+ bool open2 = false;
+ IsOpen(&open2);
+ InitStatus status2 = InitStatus::kUnattempted;
+ DBStatus(&status2);
+
+ // Call an operation that initializes the database.
+ OperationResult result1 = OperationResult::kSqlError;
+ Set(kOrigin1, u"key1", u"value1", &result1);
+ bool open3 = false;
+ IsOpen(&open3);
+ InitStatus status3 = InitStatus::kUnattempted;
+ DBStatus(&status3);
+
+ GetResult value2;
+ Get(kOrigin1, u"key1", &value2);
+ int length1 = -1;
+ Length(kOrigin1, &length1);
+
+ WaitForOperations();
+ EXPECT_TRUE(is_finished());
+
+ EXPECT_FALSE(open1);
+ EXPECT_EQ(InitStatus::kUnattempted, status1);
+
+ EXPECT_FALSE(value1.data);
+ EXPECT_EQ(OperationResult::kSuccess, value1.result);
+ EXPECT_EQ(!GetParam().in_memory_only, open2);
+ EXPECT_EQ(InitStatus::kUnattempted, status2);
+
+ EXPECT_EQ(OperationResult::kSet, result1);
+ EXPECT_TRUE(open3);
+ EXPECT_EQ(InitStatus::kSuccess, status3);
+
+ EXPECT_EQ(value2.data, u"value1");
+ EXPECT_EQ(OperationResult::kSuccess, value2.result);
+ EXPECT_EQ(1, length1);
+}
+
+TEST_P(AsyncSharedStorageDatabaseParamTest,
+ LazyInit_IgnoreForDelete_CreateForAppend) {
+ url::Origin kOrigin1 = url::Origin::Create(GURL("http://www.example1.test"));
+
+ std::queue<DBOperation> operation_list;
+ operation_list.push(DBOperation(Type::DB_IS_OPEN));
+ operation_list.push(DBOperation(Type::DB_STATUS));
+ operation_list.push(DBOperation(Type::DB_DELETE, kOrigin1, {u"key1"}));
+ operation_list.push(DBOperation(Type::DB_IS_OPEN));
+ operation_list.push(DBOperation(Type::DB_STATUS));
+ operation_list.push(
+ DBOperation(Type::DB_APPEND, kOrigin1, {u"key1", u"value1"}));
+ operation_list.push(DBOperation(Type::DB_IS_OPEN));
+ operation_list.push(DBOperation(Type::DB_STATUS));
+ operation_list.push(DBOperation(Type::DB_DELETE, kOrigin1, {u"key2"}));
+
+ SetExpectedOperationList(std::move(operation_list));
+
+ bool open1 = false;
+ IsOpen(&open1);
+ InitStatus status1 = InitStatus::kUnattempted;
+ DBStatus(&status1);
+
+ // Test that we can successfully call `Delete()` on a nonexistent key before
+ // the database is initialized.
+ OperationResult result1 = OperationResult::kSqlError;
+ Delete(kOrigin1, u"key1", &result1);
+ bool open2 = false;
+ IsOpen(&open2);
+ InitStatus status2 = InitStatus::kUnattempted;
+ DBStatus(&status2);
+
+ // Call an operation that initializes the database.
+ OperationResult result2 = OperationResult::kSqlError;
+ Append(kOrigin1, u"key1", u"value1", &result2);
+ bool open3 = false;
+ IsOpen(&open3);
+ InitStatus status3 = InitStatus::kUnattempted;
+ DBStatus(&status3);
+
+ // Test that we can successfully call `Delete()` on a nonexistent key after
+ // the database is initialized.
+ OperationResult result3 = OperationResult::kSqlError;
+ Delete(kOrigin1, u"key2", &result3);
+
+ WaitForOperations();
+ EXPECT_TRUE(is_finished());
+
+ EXPECT_FALSE(open1);
+ EXPECT_EQ(InitStatus::kUnattempted, status1);
+
+ EXPECT_EQ(OperationResult::kSuccess, result1);
+ EXPECT_EQ(!GetParam().in_memory_only, open2);
+ EXPECT_EQ(InitStatus::kUnattempted, status2);
+
+ EXPECT_EQ(OperationResult::kSet, result2);
+ EXPECT_TRUE(open3);
+ EXPECT_EQ(InitStatus::kSuccess, status3);
+
+ EXPECT_EQ(OperationResult::kSuccess, result3);
+}
+
+TEST_P(AsyncSharedStorageDatabaseParamTest,
+ LazyInit_IgnoreForClear_CreateForAppend) {
+ url::Origin kOrigin1 = url::Origin::Create(GURL("http://www.example1.test"));
+ url::Origin kOrigin2 = url::Origin::Create(GURL("http://www.example2.test"));
+
+ std::queue<DBOperation> operation_list;
+ operation_list.push(DBOperation(Type::DB_IS_OPEN));
+ operation_list.push(DBOperation(Type::DB_STATUS));
+ operation_list.push(DBOperation(Type::DB_CLEAR, kOrigin1));
+ operation_list.push(DBOperation(Type::DB_IS_OPEN));
+ operation_list.push(DBOperation(Type::DB_STATUS));
+ operation_list.push(
+ DBOperation(Type::DB_APPEND, kOrigin1, {u"key1", u"value1"}));
+ operation_list.push(DBOperation(Type::DB_IS_OPEN));
+ operation_list.push(DBOperation(Type::DB_STATUS));
+ operation_list.push(DBOperation(Type::DB_CLEAR, kOrigin2));
+
+ SetExpectedOperationList(std::move(operation_list));
+
+ bool open1 = false;
+ IsOpen(&open1);
+ InitStatus status1 = InitStatus::kUnattempted;
+ DBStatus(&status1);
+
+ // Test that we can successfully call `Clear()` on a nonexistent origin before
+ // the database is initialized.
+ OperationResult result1 = OperationResult::kSqlError;
+ Clear(kOrigin1, &result1);
+ bool open2 = false;
+ IsOpen(&open2);
+ InitStatus status2 = InitStatus::kUnattempted;
+ DBStatus(&status2);
+
+ // Call an operation that initializes the database.
+ OperationResult result2 = OperationResult::kSqlError;
+ Append(kOrigin1, u"key1", u"value1", &result2);
+ bool open3 = false;
+ IsOpen(&open3);
+ InitStatus status3 = InitStatus::kUnattempted;
+ DBStatus(&status3);
+
+ // Test that we can successfully call `Clear()` on a nonexistent origin after
+ // the database is initialized.
+ OperationResult result3 = OperationResult::kSqlError;
+ Clear(kOrigin2, &result3);
+
+ WaitForOperations();
+ EXPECT_TRUE(is_finished());
+
+ EXPECT_FALSE(open1);
+ EXPECT_EQ(InitStatus::kUnattempted, status1);
+
+ EXPECT_EQ(OperationResult::kSuccess, result1);
+ EXPECT_EQ(!GetParam().in_memory_only, open2);
+ EXPECT_EQ(InitStatus::kUnattempted, status2);
+
+ EXPECT_EQ(OperationResult::kSet, result2);
+ EXPECT_TRUE(open3);
+ EXPECT_EQ(InitStatus::kSuccess, status3);
+
+ EXPECT_EQ(OperationResult::kSuccess, result3);
+}
+
+TEST_P(AsyncSharedStorageDatabaseParamTest, PurgeStaleOrigins) {
+ url::Origin kOrigin1 = url::Origin::Create(GURL("http://www.example1.test"));
+ url::Origin kOrigin2 = url::Origin::Create(GURL("http://www.example2.test"));
+ url::Origin kOrigin3 = url::Origin::Create(GURL("http://www.example3.test"));
+ url::Origin kOrigin4 = url::Origin::Create(GURL("http://www.example4.test"));
+
+ std::queue<DBOperation> operation_list;
+ operation_list.push(DBOperation(Type::DB_FETCH_ORIGINS));
+ operation_list.push(DBOperation(Type::DB_IS_OPEN));
+ operation_list.push(DBOperation(Type::DB_STATUS));
+
+ operation_list.push(DBOperation(
+ Type::DB_PURGE_STALE,
+ {TestDatabaseOperationReceiver::SerializeTimeDelta(base::Days(1))}));
+
+ operation_list.push(
+ DBOperation(Type::DB_SET, kOrigin1,
+ {u"key1", u"value1",
+ TestDatabaseOperationReceiver::SerializeSetBehavior(
+ SetBehavior::kDefault)}));
+ operation_list.push(DBOperation(Type::DB_IS_OPEN));
+ operation_list.push(DBOperation(Type::DB_STATUS));
+
+ operation_list.push(
+ DBOperation(Type::DB_SET, kOrigin1,
+ {u"key2", u"value2",
+ TestDatabaseOperationReceiver::SerializeSetBehavior(
+ SetBehavior::kDefault)}));
+ operation_list.push(DBOperation(Type::DB_LENGTH, kOrigin1));
+
+ operation_list.push(
+ DBOperation(Type::DB_SET, kOrigin2,
+ {u"key1", u"value1",
+ TestDatabaseOperationReceiver::SerializeSetBehavior(
+ SetBehavior::kDefault)}));
+ operation_list.push(DBOperation(Type::DB_LENGTH, kOrigin2));
+
+ operation_list.push(
+ DBOperation(Type::DB_SET, kOrigin3,
+ {u"key1", u"value1",
+ TestDatabaseOperationReceiver::SerializeSetBehavior(
+ SetBehavior::kDefault)}));
+ operation_list.push(
+ DBOperation(Type::DB_SET, kOrigin3,
+ {u"key2", u"value2",
+ TestDatabaseOperationReceiver::SerializeSetBehavior(
+ SetBehavior::kDefault)}));
+ operation_list.push(
+ DBOperation(Type::DB_SET, kOrigin3,
+ {u"key3", u"value3",
+ TestDatabaseOperationReceiver::SerializeSetBehavior(
+ SetBehavior::kDefault)}));
+ operation_list.push(DBOperation(Type::DB_LENGTH, kOrigin3));
+
+ operation_list.push(
+ DBOperation(Type::DB_SET, kOrigin4,
+ {u"key1", u"value1",
+ TestDatabaseOperationReceiver::SerializeSetBehavior(
+ SetBehavior::kDefault)}));
+ operation_list.push(
+ DBOperation(Type::DB_SET, kOrigin4,
+ {u"key2", u"value2",
+ TestDatabaseOperationReceiver::SerializeSetBehavior(
+ SetBehavior::kDefault)}));
+ operation_list.push(
+ DBOperation(Type::DB_SET, kOrigin4,
+ {u"key3", u"value3",
+ TestDatabaseOperationReceiver::SerializeSetBehavior(
+ SetBehavior::kDefault)}));
+ operation_list.push(
+ DBOperation(Type::DB_SET, kOrigin4,
+ {u"key4", u"value4",
+ TestDatabaseOperationReceiver::SerializeSetBehavior(
+ SetBehavior::kDefault)}));
+ operation_list.push(DBOperation(Type::DB_LENGTH, kOrigin4));
+
+ operation_list.push(DBOperation(Type::DB_FETCH_ORIGINS));
+
+ base::Time override_time1 = base::Time::Now() - base::Days(2);
+ operation_list.push(DBOperation(
+ Type::DB_OVERRIDE_TIME, kOrigin1,
+ {TestDatabaseOperationReceiver::SerializeTime(override_time1)}));
+ operation_list.push(DBOperation(
+ Type::DB_PURGE_STALE,
+ {TestDatabaseOperationReceiver::SerializeTimeDelta(base::Days(1))}));
+
+ operation_list.push(DBOperation(Type::DB_LENGTH, kOrigin1));
+ operation_list.push(DBOperation(Type::DB_LENGTH, kOrigin2));
+ operation_list.push(DBOperation(Type::DB_LENGTH, kOrigin3));
+ operation_list.push(DBOperation(Type::DB_LENGTH, kOrigin4));
+ operation_list.push(DBOperation(Type::DB_FETCH_ORIGINS));
+
+ base::Time override_time2 = base::Time::Now() - base::Hours(2);
+ operation_list.push(DBOperation(
+ Type::DB_OVERRIDE_TIME, kOrigin3,
+ {TestDatabaseOperationReceiver::SerializeTime(override_time2)}));
+ operation_list.push(DBOperation(
+ Type::DB_PURGE_STALE,
+ {TestDatabaseOperationReceiver::SerializeTimeDelta(base::Hours(1))}));
+
+ operation_list.push(DBOperation(Type::DB_LENGTH, kOrigin1));
+ operation_list.push(DBOperation(Type::DB_LENGTH, kOrigin2));
+ operation_list.push(DBOperation(Type::DB_LENGTH, kOrigin3));
+ operation_list.push(DBOperation(Type::DB_LENGTH, kOrigin4));
+
+ operation_list.push(DBOperation(Type::DB_TRIM_MEMORY));
+ operation_list.push(DBOperation(Type::DB_FETCH_ORIGINS));
+
+ operation_list.push(DBOperation(Type::DB_GET, kOrigin2, {u"key1"}));
+ operation_list.push(DBOperation(Type::DB_GET, kOrigin4, {u"key1"}));
+ operation_list.push(DBOperation(Type::DB_GET, kOrigin4, {u"key2"}));
+ operation_list.push(DBOperation(Type::DB_GET, kOrigin4, {u"key3"}));
+ operation_list.push(DBOperation(Type::DB_GET, kOrigin4, {u"key4"}));
+
+ SetExpectedOperationList(std::move(operation_list));
+
+ // Check that origin list is initially empty due to the database not being
+ // initialized.
+ std::vector<mojom::StorageUsageInfoPtr> infos1;
+ FetchOrigins(&infos1);
+
+ // Check that calling `PurgeStaleOrigins()` on the uninitialized database
+ // doesn't give an error.
+ bool open1 = false;
+ IsOpen(&open1);
+ InitStatus status1 = InitStatus::kUnattempted;
+ DBStatus(&status1);
+
+ OperationResult result1 = OperationResult::kSqlError;
+ PurgeStaleOrigins(base::Days(1), &result1);
+
+ OperationResult result2 = OperationResult::kSqlError;
+ Set(kOrigin1, u"key1", u"value1", &result2);
+
+ bool open2 = false;
+ IsOpen(&open2);
+ InitStatus status2 = InitStatus::kUnattempted;
+ DBStatus(&status2);
+
+ OperationResult result3 = OperationResult::kSqlError;
+ Set(kOrigin1, u"key2", u"value2", &result3);
+ int length1 = -1;
+ Length(kOrigin1, &length1);
+
+ OperationResult result4 = OperationResult::kSqlError;
+ Set(kOrigin2, u"key1", u"value1", &result4);
+ int length2 = -1;
+ Length(kOrigin2, &length2);
+
+ OperationResult result5 = OperationResult::kSqlError;
+ Set(kOrigin3, u"key1", u"value1", &result5);
+ OperationResult result6 = OperationResult::kSqlError;
+ Set(kOrigin3, u"key2", u"value2", &result6);
+ OperationResult result7 = OperationResult::kSqlError;
+ Set(kOrigin3, u"key3", u"value3", &result7);
+ int length3 = -1;
+ Length(kOrigin3, &length3);
+
+ OperationResult result8 = OperationResult::kSqlError;
+ Set(kOrigin4, u"key1", u"value1", &result8);
+ OperationResult result9 = OperationResult::kSqlError;
+ Set(kOrigin4, u"key2", u"value2", &result9);
+ OperationResult result10 = OperationResult::kSqlError;
+ Set(kOrigin4, u"key3", u"value3", &result10);
+ OperationResult result11 = OperationResult::kSqlError;
+ Set(kOrigin4, u"key4", u"value4", &result11);
+ int length4 = -1;
+ Length(kOrigin4, &length4);
+
+ std::vector<mojom::StorageUsageInfoPtr> infos2;
+ FetchOrigins(&infos2);
+
+ bool success1 = false;
+ OverrideLastUsedTime(kOrigin1, override_time1, &success1);
+
+ OperationResult result12 = OperationResult::kSqlError;
+ PurgeStaleOrigins(base::Days(1), &result12);
+
+ int length5 = -1;
+ Length(kOrigin1, &length5);
+ int length6 = -1;
+ Length(kOrigin2, &length6);
+ int length7 = -1;
+ Length(kOrigin3, &length7);
+ int length8 = -1;
+ Length(kOrigin4, &length8);
+
+ std::vector<mojom::StorageUsageInfoPtr> infos3;
+ FetchOrigins(&infos3);
+
+ bool success2 = false;
+ OverrideLastUsedTime(kOrigin3, override_time2, &success2);
+
+ OperationResult result13 = OperationResult::kSqlError;
+ PurgeStaleOrigins(base::Hours(1), &result13);
+
+ int length9 = -1;
+ Length(kOrigin1, &length9);
+ int length10 = -1;
+ Length(kOrigin2, &length10);
+ int length11 = -1;
+ Length(kOrigin3, &length11);
+ int length12 = -1;
+ Length(kOrigin4, &length12);
+
+ TrimMemory();
+
+ std::vector<mojom::StorageUsageInfoPtr> infos4;
+ FetchOrigins(&infos4);
+
+ GetResult value1;
+ Get(kOrigin2, u"key1", &value1);
+ GetResult value2;
+ Get(kOrigin4, u"key1", &value2);
+ GetResult value3;
+ Get(kOrigin4, u"key2", &value3);
+ GetResult value4;
+ Get(kOrigin4, u"key3", &value4);
+ GetResult value5;
+ Get(kOrigin4, u"key4", &value5);
+
+ WaitForOperations();
+ EXPECT_TRUE(is_finished());
+
+ // Database is not yet initialized. `FetchOrigins()` returns an empty vector.
+ EXPECT_TRUE(infos1.empty());
+ EXPECT_EQ(!GetParam().in_memory_only, open1);
+ EXPECT_EQ(InitStatus::kUnattempted, status1);
+
+ // No error from calling `PurgeStaleOrigins()` on an uninitialized
+ // database.
+ EXPECT_EQ(OperationResult::kSuccess, result1);
+
+ // The call to `Set()` initializes the database.
+ EXPECT_EQ(OperationResult::kSet, result2);
+ EXPECT_TRUE(open2);
+ EXPECT_EQ(InitStatus::kSuccess, status2);
+
+ EXPECT_EQ(OperationResult::kSet, result3);
+ EXPECT_EQ(2, length1);
+
+ EXPECT_EQ(OperationResult::kSet, result4);
+ EXPECT_EQ(1, length2);
+
+ EXPECT_EQ(OperationResult::kSet, result5);
+ EXPECT_EQ(OperationResult::kSet, result6);
+ EXPECT_EQ(OperationResult::kSet, result7);
+ EXPECT_EQ(3, length3);
+
+ EXPECT_EQ(OperationResult::kSet, result8);
+ EXPECT_EQ(OperationResult::kSet, result9);
+ EXPECT_EQ(OperationResult::kSet, result10);
+ EXPECT_EQ(OperationResult::kSet, result11);
+ EXPECT_EQ(4, length4);
+
+ std::vector<url::Origin> origins;
+ for (const auto& info : infos2)
+ origins.push_back(info->origin);
+ EXPECT_THAT(origins, ElementsAre(kOrigin1, kOrigin2, kOrigin3, kOrigin4));
+
+ EXPECT_TRUE(success1);
+ EXPECT_EQ(OperationResult::kSuccess, result12);
+
+ // `kOrigin1` is cleared. The other origins are not.
+ EXPECT_EQ(0, length5);
+ EXPECT_EQ(1, length6);
+ EXPECT_EQ(3, length7);
+ EXPECT_EQ(4, length8);
+
+ origins.clear();
+ for (const auto& info : infos3)
+ origins.push_back(info->origin);
+ EXPECT_THAT(origins, ElementsAre(kOrigin2, kOrigin3, kOrigin4));
+
+ EXPECT_TRUE(success2);
+ EXPECT_EQ(OperationResult::kSuccess, result13);
+
+ // `kOrigin3` is cleared. The other remaining ones are not.
+ EXPECT_EQ(0, length9);
+ EXPECT_EQ(1, length10);
+ EXPECT_EQ(0, length11);
+ EXPECT_EQ(4, length12);
+
+ origins.clear();
+ for (const auto& info : infos4)
+ origins.push_back(info->origin);
+ EXPECT_THAT(origins, ElementsAre(kOrigin2, kOrigin4));
+
+ // Database is still intact after trimming memory.
+ EXPECT_EQ(value1.data, u"value1");
+ EXPECT_EQ(OperationResult::kSuccess, value1.result);
+ EXPECT_EQ(value2.data, u"value1");
+ EXPECT_EQ(OperationResult::kSuccess, value2.result);
+ EXPECT_EQ(value3.data, u"value2");
+ EXPECT_EQ(OperationResult::kSuccess, value3.result);
+ EXPECT_EQ(value4.data, u"value3");
+ EXPECT_EQ(OperationResult::kSuccess, value4.result);
+ EXPECT_EQ(value5.data, u"value4");
+ EXPECT_EQ(OperationResult::kSuccess, value5.result);
+}
+
+class AsyncSharedStorageDatabasePurgeMatchingOriginsParamTest
+ : public AsyncSharedStorageDatabaseTest,
+ public testing::WithParamInterface<PurgeMatchingOriginsParams> {
+ public:
+ void SetUp() override {
+ AsyncSharedStorageDatabaseTest::SetUp();
+
+ auto options = SharedStorageOptions::Create()->GetDatabaseOptions();
+
+ if (GetParam().in_memory_only)
+ CreateSync(base::FilePath(), std::move(options));
+ else
+ CreateSync(file_name_, std::move(options));
+ }
+
+ void InitSharedStorageFeature() override {
+ scoped_feature_list_.InitAndEnableFeatureWithParameters(
+ {blink::features::kSharedStorageAPI},
+ {{"MaxSharedStorageEntriesPerOrigin",
+ base::NumberToString(kMaxEntriesPerOrigin)},
+ {"MaxSharedStorageStringLength",
+ base::NumberToString(kMaxStringLength)}});
+ }
+};
+
+INSTANTIATE_TEST_SUITE_P(
+ All,
+ AsyncSharedStorageDatabasePurgeMatchingOriginsParamTest,
+ testing::ValuesIn(GetPurgeMatchingOriginsParams()),
+ testing::PrintToStringParamName());
+
+TEST_P(AsyncSharedStorageDatabasePurgeMatchingOriginsParamTest,
+ SinceThreshold) {
+ url::Origin kOrigin1 = url::Origin::Create(GURL("http://www.example1.test"));
+ url::Origin kOrigin2 = url::Origin::Create(GURL("http://www.example2.test"));
+ url::Origin kOrigin3 = url::Origin::Create(GURL("http://www.example3.test"));
+ url::Origin kOrigin4 = url::Origin::Create(GURL("http://www.example4.test"));
+ url::Origin kOrigin5 = url::Origin::Create(GURL("http://www.example5.test"));
+
+ std::queue<DBOperation> operation_list;
+ operation_list.push(DBOperation(Type::DB_FETCH_ORIGINS));
+ operation_list.push(DBOperation(Type::DB_IS_OPEN));
+ operation_list.push(DBOperation(Type::DB_STATUS));
+
+ base::Time threshold1 = base::Time::Now();
+ OriginMatcherFunctionUtility matcher_utility;
+ size_t matcher_id1 = matcher_utility.RegisterMatcherFunction({kOrigin1});
+
+ operation_list.push(DBOperation(
+ Type::DB_PURGE_MATCHING,
+ {base::NumberToString16(matcher_id1),
+ TestDatabaseOperationReceiver::SerializeTime(threshold1),
+ TestDatabaseOperationReceiver::SerializeTime(base::Time::Max()),
+ TestDatabaseOperationReceiver::SerializeBool(
+ GetParam().perform_storage_cleanup)}));
+
+ operation_list.push(
+ DBOperation(Type::DB_SET, kOrigin1,
+ {u"key1", u"value1",
+ TestDatabaseOperationReceiver::SerializeSetBehavior(
+ SetBehavior::kDefault)}));
+ operation_list.push(DBOperation(Type::DB_IS_OPEN));
+ operation_list.push(DBOperation(Type::DB_STATUS));
+
+ operation_list.push(
+ DBOperation(Type::DB_SET, kOrigin1,
+ {u"key2", u"value2",
+ TestDatabaseOperationReceiver::SerializeSetBehavior(
+ SetBehavior::kDefault)}));
+ operation_list.push(DBOperation(Type::DB_LENGTH, kOrigin1));
+
+ operation_list.push(
+ DBOperation(Type::DB_SET, kOrigin2,
+ {u"key1", u"value1",
+ TestDatabaseOperationReceiver::SerializeSetBehavior(
+ SetBehavior::kDefault)}));
+ operation_list.push(DBOperation(Type::DB_LENGTH, kOrigin2));
+
+ operation_list.push(
+ DBOperation(Type::DB_SET, kOrigin3,
+ {u"key1", u"value1",
+ TestDatabaseOperationReceiver::SerializeSetBehavior(
+ SetBehavior::kDefault)}));
+ operation_list.push(
+ DBOperation(Type::DB_SET, kOrigin3,
+ {u"key2", u"value2",
+ TestDatabaseOperationReceiver::SerializeSetBehavior(
+ SetBehavior::kDefault)}));
+ operation_list.push(
+ DBOperation(Type::DB_SET, kOrigin3,
+ {u"key3", u"value3",
+ TestDatabaseOperationReceiver::SerializeSetBehavior(
+ SetBehavior::kDefault)}));
+ operation_list.push(DBOperation(Type::DB_LENGTH, kOrigin3));
+
+ operation_list.push(
+ DBOperation(Type::DB_SET, kOrigin4,
+ {u"key1", u"value1",
+ TestDatabaseOperationReceiver::SerializeSetBehavior(
+ SetBehavior::kDefault)}));
+ operation_list.push(
+ DBOperation(Type::DB_SET, kOrigin4,
+ {u"key2", u"value2",
+ TestDatabaseOperationReceiver::SerializeSetBehavior(
+ SetBehavior::kDefault)}));
+ operation_list.push(
+ DBOperation(Type::DB_SET, kOrigin4,
+ {u"key3", u"value3",
+ TestDatabaseOperationReceiver::SerializeSetBehavior(
+ SetBehavior::kDefault)}));
+ operation_list.push(
+ DBOperation(Type::DB_SET, kOrigin4,
+ {u"key4", u"value4",
+ TestDatabaseOperationReceiver::SerializeSetBehavior(
+ SetBehavior::kDefault)}));
+ operation_list.push(DBOperation(Type::DB_LENGTH, kOrigin4));
+
+ operation_list.push(
+ DBOperation(Type::DB_SET, kOrigin5,
+ {u"key1", u"value1",
+ TestDatabaseOperationReceiver::SerializeSetBehavior(
+ SetBehavior::kDefault)}));
+ operation_list.push(DBOperation(Type::DB_LENGTH, kOrigin5));
+
+ operation_list.push(DBOperation(Type::DB_FETCH_ORIGINS));
+
+ base::Time threshold2 = base::Time::Now() + base::Seconds(100);
+ base::Time override_time1 = threshold2 + base::Milliseconds(5);
+ operation_list.push(DBOperation(
+ Type::DB_OVERRIDE_TIME, kOrigin1,
+ {TestDatabaseOperationReceiver::SerializeTime(override_time1)}));
+
+ size_t matcher_id2 =
+ matcher_utility.RegisterMatcherFunction({kOrigin1, kOrigin2, kOrigin5});
+ operation_list.push(DBOperation(
+ Type::DB_PURGE_MATCHING,
+ {base::NumberToString16(matcher_id2),
+ TestDatabaseOperationReceiver::SerializeTime(threshold2),
+ TestDatabaseOperationReceiver::SerializeTime(base::Time::Max()),
+ TestDatabaseOperationReceiver::SerializeBool(
+ GetParam().perform_storage_cleanup)}));
+
+ operation_list.push(DBOperation(Type::DB_LENGTH, kOrigin1));
+ operation_list.push(DBOperation(Type::DB_LENGTH, kOrigin2));
+ operation_list.push(DBOperation(Type::DB_LENGTH, kOrigin3));
+ operation_list.push(DBOperation(Type::DB_LENGTH, kOrigin4));
+ operation_list.push(DBOperation(Type::DB_LENGTH, kOrigin5));
+
+ operation_list.push(DBOperation(Type::DB_FETCH_ORIGINS));
+
+ base::Time threshold3 = base::Time::Now() + base::Seconds(200);
+ operation_list.push(
+ DBOperation(Type::DB_OVERRIDE_TIME, kOrigin3,
+ {TestDatabaseOperationReceiver::SerializeTime(threshold3)}));
+
+ base::Time threshold4 = threshold3 + base::Seconds(100);
+ operation_list.push(
+ DBOperation(Type::DB_OVERRIDE_TIME, kOrigin5,
+ {TestDatabaseOperationReceiver::SerializeTime(threshold4)}));
+
+ size_t matcher_id3 = matcher_utility.RegisterMatcherFunction(
+ {kOrigin2, kOrigin3, kOrigin4, kOrigin5});
+ operation_list.push(
+ DBOperation(Type::DB_PURGE_MATCHING,
+ {base::NumberToString16(matcher_id3),
+ TestDatabaseOperationReceiver::SerializeTime(threshold3),
+ TestDatabaseOperationReceiver::SerializeTime(threshold4),
+ TestDatabaseOperationReceiver::SerializeBool(
+ GetParam().perform_storage_cleanup)}));
+
+ operation_list.push(DBOperation(Type::DB_LENGTH, kOrigin1));
+ operation_list.push(DBOperation(Type::DB_LENGTH, kOrigin2));
+ operation_list.push(DBOperation(Type::DB_LENGTH, kOrigin3));
+ operation_list.push(DBOperation(Type::DB_LENGTH, kOrigin4));
+ operation_list.push(DBOperation(Type::DB_LENGTH, kOrigin5));
+
+ operation_list.push(DBOperation(Type::DB_TRIM_MEMORY));
+
+ operation_list.push(DBOperation(Type::DB_FETCH_ORIGINS));
+
+ operation_list.push(DBOperation(Type::DB_GET, kOrigin2, {u"key1"}));
+ operation_list.push(DBOperation(Type::DB_GET, kOrigin4, {u"key1"}));
+ operation_list.push(DBOperation(Type::DB_GET, kOrigin4, {u"key2"}));
+ operation_list.push(DBOperation(Type::DB_GET, kOrigin4, {u"key3"}));
+ operation_list.push(DBOperation(Type::DB_GET, kOrigin4, {u"key4"}));
+
+ operation_list.push(DBOperation(Type::DB_DESTROY));
+
+ SetExpectedOperationList(std::move(operation_list));
+
+ // Check that origin list is initially empty due to the database not being
+ // initialized.
+ std::vector<mojom::StorageUsageInfoPtr> infos1;
+ FetchOrigins(&infos1);
+
+ // Check that calling `PurgeMatchingOrigins()` on the uninitialized database
+ // doesn't give an error.
+ bool open1 = false;
+ IsOpen(&open1);
+ InitStatus status1 = InitStatus::kUnattempted;
+ DBStatus(&status1);
+
+ OperationResult result1 = OperationResult::kSqlError;
+ PurgeMatchingOrigins(&matcher_utility, matcher_id1, threshold1,
+ base::Time::Max(), &result1,
+ GetParam().perform_storage_cleanup);
+
+ OperationResult result2 = OperationResult::kSqlError;
+ Set(kOrigin1, u"key1", u"value1", &result2);
+
+ bool open2 = false;
+ IsOpen(&open2);
+ InitStatus status2 = InitStatus::kUnattempted;
+ DBStatus(&status2);
+
+ OperationResult result3 = OperationResult::kSqlError;
+ Set(kOrigin1, u"key2", u"value2", &result3);
+ int length1 = -1;
+ Length(kOrigin1, &length1);
+
+ OperationResult result4 = OperationResult::kSqlError;
+ Set(kOrigin2, u"key1", u"value1", &result4);
+ int length2 = -1;
+ Length(kOrigin2, &length2);
+
+ OperationResult result5 = OperationResult::kSqlError;
+ Set(kOrigin3, u"key1", u"value1", &result5);
+ OperationResult result6 = OperationResult::kSqlError;
+ Set(kOrigin3, u"key2", u"value2", &result6);
+ OperationResult result7 = OperationResult::kSqlError;
+ Set(kOrigin3, u"key3", u"value3", &result7);
+ int length3 = -1;
+ Length(kOrigin3, &length3);
+
+ OperationResult result8 = OperationResult::kSqlError;
+ Set(kOrigin4, u"key1", u"value1", &result8);
+ OperationResult result9 = OperationResult::kSqlError;
+ Set(kOrigin4, u"key2", u"value2", &result9);
+ OperationResult result10 = OperationResult::kSqlError;
+ Set(kOrigin4, u"key3", u"value3", &result10);
+ OperationResult result11 = OperationResult::kSqlError;
+ Set(kOrigin4, u"key4", u"value4", &result11);
+ int length4 = -1;
+ Length(kOrigin4, &length4);
+
+ OperationResult result12 = OperationResult::kSqlError;
+ Set(kOrigin5, u"key1", u"value1", &result12);
+ int length5 = -1;
+ Length(kOrigin5, &length5);
+
+ std::vector<mojom::StorageUsageInfoPtr> infos2;
+ FetchOrigins(&infos2);
+
+ bool success1 = false;
+ OverrideLastUsedTime(kOrigin1, override_time1, &success1);
+
+ // Verify that the only match we get is for `kOrigin1`, whose `last_used_time`
+ // is between the time parameters.
+ OperationResult result13 = OperationResult::kSqlError;
+ PurgeMatchingOrigins(&matcher_utility, matcher_id2, threshold2,
+ base::Time::Max(), &result13,
+ GetParam().perform_storage_cleanup);
+
+ int length6 = -1;
+ Length(kOrigin1, &length6);
+ int length7 = -1;
+ Length(kOrigin2, &length7);
+ int length8 = -1;
+ Length(kOrigin3, &length8);
+ int length9 = -1;
+ Length(kOrigin4, &length9);
+ int length10 = -1;
+ Length(kOrigin5, &length10);
+
+ std::vector<mojom::StorageUsageInfoPtr> infos3;
+ FetchOrigins(&infos3);
+
+ bool success2 = false;
+ OverrideLastUsedTime(kOrigin3, threshold3, &success2);
+ bool success3 = false;
+ OverrideLastUsedTime(kOrigin5, threshold4, &success3);
+
+ // Verify that we still get matches for `kOrigin3`, whose `last_used_time` is
+ // exactly at the `begin` time, as well as for `kOrigin5`, whose
+ // `last_used_time` is exactly at the `end` time.
+ OperationResult result14 = OperationResult::kSqlError;
+ PurgeMatchingOrigins(&matcher_utility, matcher_id3, threshold3, threshold4,
+ &result14, GetParam().perform_storage_cleanup);
+
+ int length11 = -1;
+ Length(kOrigin1, &length11);
+ int length12 = -1;
+ Length(kOrigin2, &length12);
+ int length13 = -1;
+ Length(kOrigin3, &length13);
+ int length14 = -1;
+ Length(kOrigin4, &length14);
+ int length15 = -1;
+ Length(kOrigin5, &length15);
+
+ TrimMemory();
+
+ std::vector<mojom::StorageUsageInfoPtr> infos4;
+ FetchOrigins(&infos4);
+
+ GetResult value1;
+ Get(kOrigin2, u"key1", &value1);
+ GetResult value2;
+ Get(kOrigin4, u"key1", &value2);
+ GetResult value3;
+ Get(kOrigin4, u"key2", &value3);
+ GetResult value4;
+ Get(kOrigin4, u"key3", &value4);
+ GetResult value5;
+ Get(kOrigin4, u"key4", &value5);
+
+ bool success4 = false;
+ Destroy(&success4);
+
+ WaitForOperations();
+ EXPECT_TRUE(is_finished());
+
+ // Database is not yet initialized. `FetchOrigins()` returns an empty vector.
+ EXPECT_TRUE(infos1.empty());
+ EXPECT_EQ(!GetParam().in_memory_only, open1);
+ EXPECT_EQ(InitStatus::kUnattempted, status1);
+
+ // No error from calling `PurgeMatchingOrigins()` on an uninitialized
+ // database.
+ EXPECT_EQ(OperationResult::kSuccess, result1);
+
+ // The call to `Set()` initializes the database.
+ EXPECT_EQ(OperationResult::kSet, result2);
+ EXPECT_TRUE(open2);
+ EXPECT_EQ(InitStatus::kSuccess, status2);
+
+ EXPECT_EQ(OperationResult::kSet, result3);
+ EXPECT_EQ(2, length1);
+
+ EXPECT_EQ(OperationResult::kSet, result4);
+ EXPECT_EQ(1, length2);
+
+ EXPECT_EQ(OperationResult::kSet, result5);
+ EXPECT_EQ(OperationResult::kSet, result6);
+ EXPECT_EQ(OperationResult::kSet, result7);
+ EXPECT_EQ(3, length3);
+
+ EXPECT_EQ(OperationResult::kSet, result8);
+ EXPECT_EQ(OperationResult::kSet, result9);
+ EXPECT_EQ(OperationResult::kSet, result10);
+ EXPECT_EQ(OperationResult::kSet, result11);
+ EXPECT_EQ(4, length4);
+
+ EXPECT_EQ(OperationResult::kSet, result12);
+ EXPECT_EQ(1, length5);
+
+ std::vector<url::Origin> origins;
+ for (const auto& info : infos2)
+ origins.push_back(info->origin);
+ EXPECT_THAT(origins,
+ ElementsAre(kOrigin1, kOrigin2, kOrigin3, kOrigin4, kOrigin5));
+
+ EXPECT_TRUE(success1);
+ EXPECT_EQ(OperationResult::kSuccess, result13);
+
+ // `kOrigin1` is cleared. The other origins are not.
+ EXPECT_EQ(0, length6);
+ EXPECT_EQ(1, length7);
+ EXPECT_EQ(3, length8);
+ EXPECT_EQ(4, length9);
+ EXPECT_EQ(1, length10);
+
+ origins.clear();
+ for (const auto& info : infos3)
+ origins.push_back(info->origin);
+ EXPECT_THAT(origins, ElementsAre(kOrigin2, kOrigin3, kOrigin4, kOrigin5));
+
+ EXPECT_TRUE(success2);
+ EXPECT_TRUE(success3);
+
+ EXPECT_EQ(OperationResult::kSuccess, result14);
+
+ // `kOrigin3` and `kOrigin5` are cleared. The others weren't modified within
+ // the given time period.
+ EXPECT_EQ(0, length11);
+ EXPECT_EQ(1, length12);
+ EXPECT_EQ(0, length13);
+ EXPECT_EQ(4, length14);
+ EXPECT_EQ(0, length15);
+
+ origins.clear();
+ for (const auto& info : infos4)
+ origins.push_back(info->origin);
+ EXPECT_THAT(origins, ElementsAre(kOrigin2, kOrigin4));
+
+ // Database is still intact after trimming memory (and possibly performing
+ // storage cleanup).
+ EXPECT_EQ(value1.data, u"value1");
+ EXPECT_EQ(OperationResult::kSuccess, value1.result);
+ EXPECT_EQ(value2.data, u"value1");
+ EXPECT_EQ(OperationResult::kSuccess, value2.result);
+ EXPECT_EQ(value3.data, u"value2");
+ EXPECT_EQ(OperationResult::kSuccess, value3.result);
+ EXPECT_EQ(value4.data, u"value3");
+ EXPECT_EQ(OperationResult::kSuccess, value4.result);
+ EXPECT_EQ(value5.data, u"value4");
+ EXPECT_EQ(OperationResult::kSuccess, value5.result);
+
+ EXPECT_TRUE(success4);
+}
+
+} // namespace storage
diff --git a/chromium/components/services/storage/shared_storage/shared_storage_database.cc b/chromium/components/services/storage/shared_storage/shared_storage_database.cc
new file mode 100644
index 00000000000..923717a5467
--- /dev/null
+++ b/chromium/components/services/storage/shared_storage/shared_storage_database.cc
@@ -0,0 +1,900 @@
+// Copyright 2021 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.
+
+#include "components/services/storage/shared_storage/shared_storage_database.h"
+
+#include <inttypes.h>
+
+#include <algorithm>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/files/file_util.h"
+#include "base/metrics/histogram_functions.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/time/default_clock.h"
+#include "base/time/time.h"
+#include "components/services/storage/public/mojom/storage_usage_info.mojom.h"
+#include "components/services/storage/shared_storage/shared_storage_options.h"
+#include "sql/error_delegate_util.h"
+#include "sql/statement.h"
+#include "sql/transaction.h"
+#include "storage/browser/quota/special_storage_policy.h"
+#include "third_party/blink/public/common/features.h"
+#include "url/gurl.h"
+#include "url/origin.h"
+
+namespace storage {
+
+// Because each entry is a key-value pair, and both keys and values are
+// std::u16strings and bounded by `max_string_length_`, the total bytes used per
+// entry is at most 2 * 2 * `max_string_length_`.
+const int kSharedStorageEntryTotalBytesMultiplier = 4;
+
+namespace {
+
+// Version number of the database.
+const int kCurrentVersionNumber = 1;
+
+[[nodiscard]] std::string SerializeOrigin(const url::Origin& origin) {
+ DCHECK(!origin.opaque());
+ DCHECK_NE(url::kFileScheme, origin.scheme());
+ return origin.Serialize();
+}
+
+[[nodiscard]] bool InitSchema(sql::Database& db) {
+ static constexpr char kValuesMappingSql[] =
+ "CREATE TABLE IF NOT EXISTS values_mapping("
+ "context_origin TEXT NOT NULL,"
+ "key TEXT NOT NULL,"
+ "value TEXT,"
+ "PRIMARY KEY(context_origin,key)) WITHOUT ROWID";
+ if (!db.Execute(kValuesMappingSql))
+ return false;
+
+ static constexpr char kPerOriginMappingSql[] =
+ "CREATE TABLE IF NOT EXISTS per_origin_mapping("
+ "context_origin TEXT NOT NULL PRIMARY KEY,"
+ "last_used_time INTEGER NOT NULL,"
+ "length INTEGER NOT NULL) WITHOUT ROWID";
+ if (!db.Execute(kPerOriginMappingSql))
+ return false;
+
+ static constexpr char kLastUsedTimeIndexSql[] =
+ "CREATE INDEX IF NOT EXISTS per_origin_mapping_last_used_time_idx "
+ "ON per_origin_mapping(last_used_time)";
+ if (!db.Execute(kLastUsedTimeIndexSql))
+ return false;
+
+ return true;
+}
+
+} // namespace
+
+SharedStorageDatabase::GetResult::GetResult() = default;
+
+SharedStorageDatabase::GetResult::GetResult(const GetResult&) = default;
+
+SharedStorageDatabase::GetResult::GetResult(GetResult&&) = default;
+
+SharedStorageDatabase::GetResult::~GetResult() = default;
+
+SharedStorageDatabase::GetResult& SharedStorageDatabase::GetResult::operator=(
+ const GetResult&) = default;
+
+SharedStorageDatabase::GetResult& SharedStorageDatabase::GetResult::operator=(
+ GetResult&&) = default;
+
+SharedStorageDatabase::SharedStorageDatabase(
+ base::FilePath db_path,
+ scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy,
+ std::unique_ptr<SharedStorageDatabaseOptions> options)
+ : db_({// Run the database in exclusive mode. Nobody else should be
+ // accessing the database while we're running, and this will give
+ // somewhat improved perf.
+ .exclusive_locking = true,
+ .page_size = options->max_page_size,
+ .cache_size = options->max_cache_size}),
+ db_path_(std::move(db_path)),
+ special_storage_policy_(std::move(special_storage_policy)),
+ max_entries_per_origin_(int64_t{options->max_entries_per_origin}),
+ clock_(base::DefaultClock::GetInstance()) {
+ DCHECK(db_path_.empty() || db_path_.IsAbsolute());
+ DCHECK_GT(max_entries_per_origin_, 0);
+ DCHECK_GT(options->max_init_tries, 0);
+ DCHECK_GT(options->max_string_length, 0);
+ max_string_length_ = static_cast<size_t>(options->max_string_length);
+ max_init_tries_ = static_cast<size_t>(options->max_init_tries);
+ db_file_status_ = db_path_.empty() ? DBFileStatus::kNoPreexistingFile
+ : DBFileStatus::kNotChecked;
+}
+
+SharedStorageDatabase::~SharedStorageDatabase() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+}
+
+bool SharedStorageDatabase::Destroy() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ if (db_.is_open() && !db_.RazeAndClose())
+ return false;
+
+ // The file already doesn't exist.
+ if (db_path_.empty())
+ return true;
+
+ return base::DeleteFile(db_path_);
+}
+
+void SharedStorageDatabase::TrimMemory() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK_EQ(InitStatus::kSuccess, db_status_);
+ db_.TrimMemory();
+}
+
+SharedStorageDatabase::GetResult SharedStorageDatabase::Get(
+ url::Origin context_origin,
+ std::u16string key) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK_LE(key.size(), max_string_length_);
+ GetResult result;
+
+ if (LazyInit(DBCreationPolicy::kIgnoreIfAbsent) != InitStatus::kSuccess) {
+ // We do not return an error if the database doesn't exist, but only if it
+ // pre-exists on disk and yet fails to initialize.
+ if (db_status_ == InitStatus::kUnattempted)
+ result.result = OperationResult::kSuccess;
+ else
+ result.result = OperationResult::kInitFailure;
+
+ return result;
+ }
+
+ // In theory, there ought to be at most one entry found. But we make no
+ // assumption about the state of the disk. In the rare case that multiple
+ // entries are found, we return only the value from the first entry found.
+ static constexpr char kSelectSql[] =
+ "SELECT value FROM values_mapping "
+ "WHERE context_origin=? AND key=? "
+ "LIMIT 1";
+
+ sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE, kSelectSql));
+ std::string origin_str(SerializeOrigin(context_origin));
+ statement.BindString(0, origin_str);
+ statement.BindString16(1, key);
+
+ if (statement.Step())
+ result.data = statement.ColumnString16(0);
+ if (!statement.Succeeded())
+ return result;
+
+ if (UpdateLastUsedTime(origin_str))
+ result.result = OperationResult::kSuccess;
+
+ return result;
+}
+
+SharedStorageDatabase::OperationResult SharedStorageDatabase::Set(
+ url::Origin context_origin,
+ std::u16string key,
+ std::u16string value,
+ SetBehavior behavior) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(!key.empty());
+ DCHECK_LE(key.size(), max_string_length_);
+ DCHECK_LE(value.size(), max_string_length_);
+
+ if (LazyInit(DBCreationPolicy::kCreateIfAbsent) != InitStatus::kSuccess)
+ return OperationResult::kInitFailure;
+
+ sql::Transaction transaction(&db_);
+ if (!transaction.Begin())
+ return OperationResult::kSqlError;
+
+ std::string origin_str(SerializeOrigin(context_origin));
+ if (HasEntryFor(origin_str, key)) {
+ if (behavior == SharedStorageDatabase::SetBehavior::kIgnoreIfPresent) {
+ // If we are in a nested transaction, we need to commit, even though we
+ // haven't made any changes, so that the failure to set in this case
+ // isn't seen as an error (as then the entire stack of transactions
+ // will be rolled back and the next transaction within the parent
+ // transaction will fail to begin).
+ if (db_.transaction_nesting())
+ transaction.Commit();
+ return OperationResult::kIgnored;
+ }
+
+ if (Delete(context_origin, key) != OperationResult::kSuccess)
+ return OperationResult::kSqlError;
+ } else if (!HasCapacity(origin_str)) {
+ return OperationResult::kNoCapacity;
+ }
+
+ if (!InsertIntoValuesMapping(origin_str, key, value))
+ return OperationResult::kSqlError;
+
+ if (!UpdateLength(origin_str, /*delta=*/1))
+ return OperationResult::kSqlError;
+
+ if (!transaction.Commit())
+ return OperationResult::kSqlError;
+
+ return OperationResult::kSet;
+}
+
+SharedStorageDatabase::OperationResult SharedStorageDatabase::Append(
+ url::Origin context_origin,
+ std::u16string key,
+ std::u16string tail_value) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(!key.empty());
+ DCHECK_LE(key.size(), max_string_length_);
+ DCHECK_LE(tail_value.size(), max_string_length_);
+
+ if (LazyInit(DBCreationPolicy::kCreateIfAbsent) != InitStatus::kSuccess)
+ return OperationResult::kInitFailure;
+
+ sql::Transaction transaction(&db_);
+ if (!transaction.Begin())
+ return OperationResult::kSqlError;
+
+ GetResult get_result = Get(context_origin, key);
+ if (get_result.result != OperationResult::kSuccess)
+ return OperationResult::kSqlError;
+
+ std::u16string new_value;
+ std::string origin_str(SerializeOrigin(context_origin));
+
+ if (get_result.data) {
+ new_value = std::move(*get_result.data);
+ new_value.append(tail_value);
+
+ if (new_value.size() > max_string_length_)
+ return OperationResult::kInvalidAppend;
+
+ if (Delete(context_origin, key) != OperationResult::kSuccess)
+ return OperationResult::kSqlError;
+ } else {
+ new_value = std::move(tail_value);
+
+ if (!HasCapacity(origin_str))
+ return OperationResult::kNoCapacity;
+ }
+
+ if (!InsertIntoValuesMapping(origin_str, key, new_value))
+ return OperationResult::kSqlError;
+
+ if (!UpdateLength(origin_str, /*delta=*/1))
+ return OperationResult::kSqlError;
+
+ if (!transaction.Commit())
+ return OperationResult::kSqlError;
+
+ return OperationResult::kSet;
+}
+
+SharedStorageDatabase::OperationResult SharedStorageDatabase::Delete(
+ url::Origin context_origin,
+ std::u16string key) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK_LE(key.size(), max_string_length_);
+
+ if (LazyInit(DBCreationPolicy::kIgnoreIfAbsent) != InitStatus::kSuccess) {
+ // We do not return an error if the database doesn't exist, but only if it
+ // pre-exists on disk and yet fails to initialize.
+ if (db_status_ == InitStatus::kUnattempted)
+ return OperationResult::kSuccess;
+ else
+ return OperationResult::kInitFailure;
+ }
+
+ std::string origin_str(SerializeOrigin(context_origin));
+ if (!HasEntryFor(origin_str, key))
+ return OperationResult::kSuccess;
+
+ sql::Transaction transaction(&db_);
+ if (!transaction.Begin())
+ return OperationResult::kSqlError;
+
+ static constexpr char kDeleteSql[] =
+ "DELETE FROM values_mapping "
+ "WHERE context_origin=? AND key=?";
+
+ sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE, kDeleteSql));
+ statement.BindString(0, origin_str);
+ statement.BindString16(1, key);
+
+ if (!statement.Run())
+ return OperationResult::kSqlError;
+
+ if (!UpdateLength(origin_str, /*delta=*/-1))
+ return OperationResult::kSqlError;
+
+ if (!transaction.Commit())
+ return OperationResult::kSqlError;
+ return OperationResult::kSuccess;
+}
+
+SharedStorageDatabase::OperationResult SharedStorageDatabase::Clear(
+ url::Origin context_origin) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ if (LazyInit(DBCreationPolicy::kIgnoreIfAbsent) != InitStatus::kSuccess) {
+ // We do not return an error if the database doesn't exist, but only if it
+ // pre-exists on disk and yet fails to initialize.
+ if (db_status_ == InitStatus::kUnattempted)
+ return OperationResult::kSuccess;
+ else
+ return OperationResult::kInitFailure;
+ }
+
+ if (!Purge(SerializeOrigin(context_origin)))
+ return OperationResult::kSqlError;
+ return OperationResult::kSuccess;
+}
+
+int64_t SharedStorageDatabase::Length(url::Origin context_origin) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ if (LazyInit(DBCreationPolicy::kIgnoreIfAbsent) != InitStatus::kSuccess) {
+ // We do not return -1 (to signifiy an error) if the database doesn't exist,
+ // but only if it pre-exists on disk and yet fails to initialize.
+ if (db_status_ == InitStatus::kUnattempted)
+ return 0L;
+ else
+ return -1;
+ }
+
+ std::string origin_str(SerializeOrigin(context_origin));
+ int64_t length = NumEntries(origin_str);
+ if (!length)
+ return 0L;
+
+ if (!UpdateLastUsedTime(origin_str))
+ return -1;
+
+ return length;
+}
+
+SharedStorageDatabase::GetResult SharedStorageDatabase::Key(
+ url::Origin context_origin,
+ uint64_t index) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ GetResult result;
+
+ if (LazyInit(DBCreationPolicy::kIgnoreIfAbsent) != InitStatus::kSuccess) {
+ // We do not return an error if the database doesn't exist, but only if it
+ // pre-exists on disk and yet fails to initialize.
+ if (db_status_ == InitStatus::kUnattempted)
+ result.result = OperationResult::kSuccess;
+ else
+ result.result = OperationResult::kInitFailure;
+ return result;
+ }
+
+ static constexpr char kSelectSql[] =
+ "SELECT key FROM values_mapping "
+ "WHERE context_origin=? "
+ "ORDER BY key";
+
+ sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE, kSelectSql));
+ std::string origin_str(SerializeOrigin(context_origin));
+ statement.BindString(0, origin_str);
+
+ uint64_t current_index = 0UL;
+
+ while (statement.Step()) {
+ if (!statement.Succeeded())
+ return result;
+ if (current_index == index) {
+ result.data = statement.ColumnString16(0);
+ break;
+ }
+
+ current_index++;
+ }
+
+ if (UpdateLastUsedTime(origin_str))
+ result.result = OperationResult::kSuccess;
+
+ return result;
+}
+
+SharedStorageDatabase::OperationResult
+SharedStorageDatabase::PurgeMatchingOrigins(
+ OriginMatcherFunction origin_matcher,
+ base::Time begin,
+ base::Time end,
+ bool perform_storage_cleanup) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK_LE(begin, end);
+
+ if (LazyInit(DBCreationPolicy::kIgnoreIfAbsent) != InitStatus::kSuccess) {
+ // We do not return an error if the database doesn't exist, but only if it
+ // pre-exists on disk and yet fails to initialize.
+ if (db_status_ == InitStatus::kUnattempted)
+ return OperationResult::kSuccess;
+ else
+ return OperationResult::kInitFailure;
+ }
+
+ static constexpr char kSelectSql[] =
+ "SELECT context_origin FROM per_origin_mapping "
+ "WHERE last_used_time BETWEEN ? AND ? "
+ "ORDER BY last_used_time";
+ sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE, kSelectSql));
+ statement.BindTime(0, begin);
+ statement.BindTime(1, end);
+
+ std::vector<std::string> origins;
+
+ while (statement.Step())
+ origins.push_back(statement.ColumnString(0));
+
+ if (!statement.Succeeded())
+ return OperationResult::kSqlError;
+
+ if (origins.empty())
+ return OperationResult::kSuccess;
+
+ sql::Transaction transaction(&db_);
+ if (!transaction.Begin())
+ return OperationResult::kSqlError;
+
+ for (const auto& origin : origins) {
+ if (origin_matcher && !origin_matcher.Run(url::Origin::Create(GURL(origin)),
+ special_storage_policy_.get())) {
+ continue;
+ }
+
+ if (!Purge(origin))
+ return OperationResult::kSqlError;
+ }
+
+ if (!transaction.Commit())
+ return OperationResult::kSqlError;
+
+ if (perform_storage_cleanup && !Vacuum())
+ return OperationResult::kSqlError;
+
+ return OperationResult::kSuccess;
+}
+
+SharedStorageDatabase::OperationResult SharedStorageDatabase::PurgeStaleOrigins(
+ base::TimeDelta window_to_be_deemed_active) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK_GT(window_to_be_deemed_active, base::TimeDelta());
+
+ if (LazyInit(DBCreationPolicy::kIgnoreIfAbsent) != InitStatus::kSuccess) {
+ // We do not return an error if the database doesn't exist, but only if it
+ // pre-exists on disk and yet fails to initialize.
+ if (db_status_ == InitStatus::kUnattempted)
+ return OperationResult::kSuccess;
+ else
+ return OperationResult::kInitFailure;
+ }
+
+ base::Time threshold = clock_->Now() - window_to_be_deemed_active;
+
+ static constexpr char kSelectSql[] =
+ "SELECT context_origin FROM per_origin_mapping "
+ "WHERE last_used_time<? "
+ "ORDER BY last_used_time";
+ sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE, kSelectSql));
+ statement.BindTime(0, threshold);
+
+ std::vector<std::string> stale_origins;
+
+ while (statement.Step())
+ stale_origins.push_back(statement.ColumnString(0));
+
+ if (!statement.Succeeded())
+ return OperationResult::kSqlError;
+
+ if (stale_origins.empty())
+ return OperationResult::kSuccess;
+
+ sql::Transaction transaction(&db_);
+ if (!transaction.Begin())
+ return OperationResult::kSqlError;
+
+ for (const auto& origin : stale_origins) {
+ if (!Purge(origin))
+ return OperationResult::kSqlError;
+ }
+
+ if (!transaction.Commit())
+ return OperationResult::kSqlError;
+ return OperationResult::kSuccess;
+}
+
+std::vector<mojom::StorageUsageInfoPtr> SharedStorageDatabase::FetchOrigins() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ if (LazyInit(DBCreationPolicy::kIgnoreIfAbsent) != InitStatus::kSuccess)
+ return {};
+
+ static constexpr char kSelectSql[] =
+ "SELECT context_origin,last_used_time,length FROM per_origin_mapping "
+ "ORDER BY context_origin";
+
+ sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE, kSelectSql));
+ std::vector<mojom::StorageUsageInfoPtr> fetched_origin_infos;
+
+ while (statement.Step()) {
+ fetched_origin_infos.emplace_back(mojom::StorageUsageInfo::New(
+ url::Origin::Create(GURL(statement.ColumnString(0))),
+ statement.ColumnInt64(2) * kSharedStorageEntryTotalBytesMultiplier *
+ max_string_length_,
+ statement.ColumnTime(1)));
+ }
+
+ if (!statement.Succeeded())
+ return {};
+
+ return fetched_origin_infos;
+}
+
+bool SharedStorageDatabase::IsOpenForTesting() const {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ return db_.is_open();
+}
+
+SharedStorageDatabase::InitStatus SharedStorageDatabase::DBStatusForTesting()
+ const {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ return db_status_;
+}
+
+bool SharedStorageDatabase::OverrideLastUsedTimeForTesting(
+ url::Origin context_origin,
+ base::Time override_last_used_time) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ if (LazyInit(DBCreationPolicy::kIgnoreIfAbsent) != InitStatus::kSuccess)
+ return false;
+
+ return SetLastUsedTime(SerializeOrigin(context_origin),
+ override_last_used_time);
+}
+
+void SharedStorageDatabase::OverrideClockForTesting(base::Clock* clock) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(clock);
+ clock_ = clock;
+}
+
+bool SharedStorageDatabase::OverrideSpecialStoragePolicyForTesting(
+ scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ special_storage_policy_ = std::move(special_storage_policy);
+ return true;
+}
+
+SharedStorageDatabase::InitStatus SharedStorageDatabase::LazyInit(
+ DBCreationPolicy policy) {
+ // Early return in case of previous failure, to prevent an unbounded
+ // number of re-attempts.
+ if (db_status_ != InitStatus::kUnattempted)
+ return db_status_;
+
+ if (policy == DBCreationPolicy::kIgnoreIfAbsent && !DBExists())
+ return InitStatus::kUnattempted;
+
+ for (size_t i = 0; i < max_init_tries_; ++i) {
+ db_status_ = InitImpl();
+ if (db_status_ == InitStatus::kSuccess)
+ return db_status_;
+
+ meta_table_.Reset();
+ db_.Close();
+ }
+
+ return db_status_;
+}
+
+bool SharedStorageDatabase::DBExists() {
+ DCHECK_EQ(InitStatus::kUnattempted, db_status_);
+
+ if (db_file_status_ == DBFileStatus::kNoPreexistingFile)
+ return false;
+
+ // The in-memory case is included in `DBFileStatus::kNoPreexistingFile`.
+ DCHECK(!db_path_.empty());
+
+ // We do not expect `DBExists()` to be called in the case where
+ // `db_file_status_ == DBFileStatus::kPreexistingFile`, as then
+ // `db_status_ != InitStatus::kUnattempted`, which would force an early return
+ // in `LazyInit()`.
+ DCHECK_EQ(DBFileStatus::kNotChecked, db_file_status_);
+
+ // The histogram tag must be set before opening.
+ db_.set_histogram_tag("SharedStorage");
+
+ if (!db_.Open(db_path_)) {
+ db_file_status_ = DBFileStatus::kNoPreexistingFile;
+ return false;
+ }
+
+ static const char kSelectSql[] =
+ "SELECT COUNT(*) FROM sqlite_schema WHERE type=?";
+ sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE, kSelectSql));
+ statement.BindCString(0, "table");
+
+ if (!statement.Step() || statement.ColumnInt(0) == 0) {
+ db_file_status_ = DBFileStatus::kNoPreexistingFile;
+ return false;
+ }
+
+ db_file_status_ = DBFileStatus::kPreexistingFile;
+ return true;
+}
+
+bool SharedStorageDatabase::OpenDatabase() {
+ // If the database is open, the histogram tag will have already been set in
+ // `DBExists()`, since it must be set before opening.
+ if (!db_.is_open())
+ db_.set_histogram_tag("SharedStorage");
+
+ // base::Unretained is safe here because this SharedStorageDatabase owns
+ // the sql::Database instance that stores and uses the callback. So,
+ // `this` is guaranteed to outlive the callback.
+ db_.set_error_callback(base::BindRepeating(
+ &SharedStorageDatabase::DatabaseErrorCallback, base::Unretained(this)));
+
+ if (!db_path_.empty()) {
+ if (!db_.is_open() && !db_.Open(db_path_))
+ return false;
+
+ db_.Preload();
+ } else {
+ if (!db_.OpenInMemory())
+ return false;
+ }
+
+ return true;
+}
+
+void SharedStorageDatabase::DatabaseErrorCallback(int extended_error,
+ sql::Statement* stmt) {
+ base::UmaHistogramSparse("Storage.SharedStorage.Database.Error",
+ extended_error);
+
+ if (sql::IsErrorCatastrophic(extended_error)) {
+ bool success = Destroy();
+ UMA_HISTOGRAM_BOOLEAN("Storage.SharedStorage.Database.Destruction",
+ success);
+ if (!success) {
+ DLOG(FATAL) << "Database destruction failed after catastrophic error:\n"
+ << db_.GetErrorMessage();
+ }
+ }
+
+ // The default handling is to assert on debug and to ignore on release.
+ if (!sql::Database::IsExpectedSqliteError(extended_error))
+ DLOG(FATAL) << db_.GetErrorMessage();
+}
+
+SharedStorageDatabase::InitStatus SharedStorageDatabase::InitImpl() {
+ if (!OpenDatabase())
+ return InitStatus::kError;
+
+ // Database should now be open.
+ DCHECK(db_.is_open());
+
+ // Scope initialization in a transaction so we can't be partially initialized.
+ sql::Transaction transaction(&db_);
+ if (!transaction.Begin()) {
+ LOG(WARNING) << "Shared storage database begin initialization failed.";
+ db_.RazeAndClose();
+ return InitStatus::kError;
+ }
+
+ // Create the tables.
+ if (!meta_table_.Init(&db_, kCurrentVersionNumber, kCurrentVersionNumber) ||
+ !InitSchema(db_)) {
+ return InitStatus::kError;
+ }
+
+ if (meta_table_.GetCompatibleVersionNumber() > kCurrentVersionNumber) {
+ LOG(WARNING) << "Shared storage database is too new.";
+ return InitStatus::kTooNew;
+ }
+
+ int cur_version = meta_table_.GetVersionNumber();
+
+ if (cur_version < kCurrentVersionNumber) {
+ LOG(WARNING) << "Shared storage database is too old to be compatible.";
+ db_.RazeAndClose();
+ return InitStatus::kTooOld;
+ }
+
+ // The initialization is complete.
+ if (!transaction.Commit()) {
+ LOG(WARNING) << "Shared storage database initialization commit failed.";
+ db_.RazeAndClose();
+ return InitStatus::kError;
+ }
+
+ return InitStatus::kSuccess;
+}
+
+bool SharedStorageDatabase::Vacuum() {
+ DCHECK_EQ(InitStatus::kSuccess, db_status_);
+ DCHECK_EQ(0, db_.transaction_nesting())
+ << "Can not have a transaction when vacuuming.";
+ return db_.Execute("VACUUM");
+}
+
+bool SharedStorageDatabase::Purge(const std::string& context_origin) {
+ sql::Transaction transaction(&db_);
+ if (!transaction.Begin())
+ return false;
+
+ static constexpr char kDeleteSql[] =
+ "DELETE FROM values_mapping "
+ "WHERE context_origin=?";
+
+ sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE, kDeleteSql));
+ statement.BindString(0, context_origin);
+
+ if (!statement.Run())
+ return false;
+
+ if (!DeleteFromPerOriginMapping(context_origin))
+ return false;
+
+ return transaction.Commit();
+}
+
+int64_t SharedStorageDatabase::NumEntries(const std::string& context_origin) {
+ // In theory, there ought to be at most one entry found. But we make no
+ // assumption about the state of the disk. In the rare case that multiple
+ // entries are found, we return only the `length` from the first entry found.
+ static constexpr char kSelectSql[] =
+ "SELECT length FROM per_origin_mapping "
+ "WHERE context_origin=? "
+ "LIMIT 1";
+
+ sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE, kSelectSql));
+ statement.BindString(0, context_origin);
+
+ int64_t length = 0;
+ if (statement.Step())
+ length = statement.ColumnInt64(0);
+
+ return length;
+}
+
+bool SharedStorageDatabase::HasEntryFor(const std::string& context_origin,
+ const std::u16string& key) {
+ static constexpr char kSelectSql[] =
+ "SELECT 1 FROM values_mapping "
+ "WHERE context_origin=? AND key=? "
+ "LIMIT 1";
+
+ sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE, kSelectSql));
+ statement.BindString(0, context_origin);
+ statement.BindString16(1, key);
+
+ return statement.Step();
+}
+
+bool SharedStorageDatabase::SetLastUsedTime(const std::string& context_origin,
+ base::Time new_last_used_time) {
+ int64_t length = NumEntries(context_origin);
+
+ // If length is zero, no need to delete, and don't insert the origin into the
+ // `per_origin_mapping`.
+ if (!length)
+ return true;
+
+ sql::Transaction transaction(&db_);
+ if (!transaction.Begin())
+ return false;
+
+ if (!DeleteFromPerOriginMapping(context_origin))
+ return false;
+
+ if (!InsertIntoPerOriginMapping(context_origin, new_last_used_time, length))
+ return false;
+
+ return transaction.Commit();
+}
+
+bool SharedStorageDatabase::UpdateLastUsedTime(
+ const std::string& context_origin) {
+ return SetLastUsedTime(context_origin, clock_->Now());
+}
+
+bool SharedStorageDatabase::UpdateLength(const std::string& context_origin,
+ int64_t delta,
+ bool should_update_time) {
+ // In theory, there ought to be at most one entry found. But we make no
+ // assumption about the state of the disk. In the rare case that multiple
+ // entries are found, we retrieve only the `length` (and possibly the `time`)
+ // from the first entry found.
+ static constexpr char kSelectSql[] =
+ "SELECT length,last_used_time FROM per_origin_mapping "
+ "WHERE context_origin=? "
+ "LIMIT 1";
+
+ sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE, kSelectSql));
+ statement.BindString(0, context_origin);
+ int64_t length = 0;
+ base::Time time = clock_->Now();
+
+ if (statement.Step()) {
+ length = statement.ColumnInt64(0);
+ if (!should_update_time)
+ time = statement.ColumnTime(1);
+ }
+
+ sql::Transaction transaction(&db_);
+ if (!transaction.Begin())
+ return false;
+
+ if (!DeleteFromPerOriginMapping(context_origin))
+ return false;
+
+ // If the new length is zero, then don't re-insert the origin into the
+ // `per_origin_mapping`.
+ if (length + delta == 0L)
+ return transaction.Commit();
+
+ if (!InsertIntoPerOriginMapping(context_origin, time, length + delta))
+ return false;
+
+ return transaction.Commit();
+}
+
+bool SharedStorageDatabase::InsertIntoValuesMapping(
+ const std::string& context_origin,
+ const std::u16string& key,
+ const std::u16string& value) {
+ static constexpr char kInsertSql[] =
+ "INSERT INTO values_mapping(context_origin,key,value)"
+ "VALUES(?,?,?)";
+
+ sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE, kInsertSql));
+ statement.BindString(0, context_origin);
+ statement.BindString16(1, key);
+ statement.BindString16(2, value);
+
+ return statement.Run();
+}
+
+bool SharedStorageDatabase::DeleteFromPerOriginMapping(
+ const std::string& context_origin) {
+ static constexpr char kDeleteSql[] =
+ "DELETE FROM per_origin_mapping "
+ "WHERE context_origin=?";
+
+ sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE, kDeleteSql));
+ statement.BindString(0, context_origin);
+
+ return statement.Run();
+}
+
+bool SharedStorageDatabase::InsertIntoPerOriginMapping(
+ const std::string& context_origin,
+ base::Time last_used_time,
+ uint64_t length) {
+ static constexpr char kInsertSql[] =
+ "INSERT INTO per_origin_mapping(context_origin,last_used_time,length)"
+ "VALUES(?,?,?)";
+
+ sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE, kInsertSql));
+ statement.BindString(0, context_origin);
+ statement.BindTime(1, last_used_time);
+ statement.BindInt64(2, static_cast<int64_t>(length));
+
+ return statement.Run();
+}
+
+bool SharedStorageDatabase::HasCapacity(const std::string& context_origin) {
+ return NumEntries(context_origin) < max_entries_per_origin_;
+}
+
+} // namespace storage
diff --git a/chromium/components/services/storage/shared_storage/shared_storage_database.h b/chromium/components/services/storage/shared_storage/shared_storage_database.h
new file mode 100644
index 00000000000..413396a9efa
--- /dev/null
+++ b/chromium/components/services/storage/shared_storage/shared_storage_database.h
@@ -0,0 +1,388 @@
+// Copyright 2021 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.
+
+#ifndef COMPONENTS_SERVICES_STORAGE_SHARED_STORAGE_SHARED_STORAGE_DATABASE_H_
+#define COMPONENTS_SERVICES_STORAGE_SHARED_STORAGE_SHARED_STORAGE_DATABASE_H_
+
+#include <inttypes.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/memory/raw_ptr.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/sequence_checker.h"
+#include "base/thread_annotations.h"
+#include "base/threading/sequence_bound.h"
+#include "base/time/clock.h"
+#include "components/services/storage/public/mojom/storage_usage_info.mojom-forward.h"
+#include "sql/database.h"
+#include "sql/meta_table.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace base {
+class FilePath;
+class Time;
+class TimeDelta;
+} // namespace base
+
+namespace sql {
+class Statement;
+}
+
+namespace url {
+class Origin;
+} // namespace url
+
+namespace storage {
+struct SharedStorageDatabaseOptions;
+class SpecialStoragePolicy;
+
+// Multiplier for determining the padded total size in bytes that an origin
+// is using.
+extern const int kSharedStorageEntryTotalBytesMultiplier;
+
+// Wraps its own `sql::Database` instance on behalf of the Shared Storage
+// backend implementation. This object is not sequence-safe and must be
+// instantiated on a sequence which allows use of blocking file operations.
+class SharedStorageDatabase {
+ public:
+ // A callback type to check if a given origin matches a storage policy.
+ // Can be passed empty/null where used, which means the origin will always
+ // match.
+ using OriginMatcherFunction =
+ base::RepeatingCallback<bool(const url::Origin&, SpecialStoragePolicy*)>;
+
+ enum class InitStatus {
+ kUnattempted =
+ 0, // Status if `LazyInit()` has not yet been called or if `LazyInit()`
+ // has early returned due to `DBCreationPolicy::kIgnoreIfAbsent`.
+ kSuccess = 1, // Status if `LazyInit()` was successful.
+ kError = 2, // Status if `LazyInit()` failed and a more specific error
+ // wasn't diagnosed.
+ kTooNew = 3, // Status if `LazyInit()` failed due to a compatible version
+ // number being too high.
+ kTooOld = 4, // Status if `LazyInit()` failed due to a version number being
+ // too low.
+ };
+
+ enum class DBFileStatus {
+ kNotChecked = 0, // Status if DB is file-backed and there hasn't been an
+ // attempt to open the SQL database for the given FilePath
+ // to see if it exists and contains data.
+ kNoPreexistingFile =
+ 1, // Status if the DB is in-memory or if the DB is file-backed but the
+ // attempt to open it was unsuccessful or any pre-existing file
+ // contained no data.
+ kPreexistingFile =
+ 2, // Status if there was a pre-existing file containing at least one
+ // table that we were able to successfully open.
+ };
+
+ enum class SetBehavior {
+ kDefault = 0, // Sets entry regardless of whether one previously exists.
+ kIgnoreIfPresent = 1, // Does not set an entry if one previously exists.
+ };
+
+ enum class OperationResult {
+ kSuccess = 0, // Result if a non-setting operation is successful.
+ kSet = 1, // Result if value is set.
+ kIgnored = 2, // Result if value was present and ignored; no error.
+ kSqlError = 3, // Result if there is a SQL database error.
+ kInitFailure = 4, // Result if database initialization failed and a
+ // database is required.
+ kNoCapacity = 5, // Result if there was insufficient capacity for the
+ // requesting origin.
+ kInvalidAppend = 6, // Result if the length of the value after appending
+ // would exceed the maximum allowed length.
+ };
+
+ // Bundles a retrieved string from the database along with a field indicating
+ // whether the transaction was free of SQL errors.
+ struct GetResult {
+ absl::optional<std::u16string> data;
+ OperationResult result = OperationResult::kSqlError;
+ GetResult();
+ GetResult(const GetResult&);
+ GetResult(GetResult&&);
+ ~GetResult();
+ GetResult& operator=(const GetResult&);
+ GetResult& operator=(GetResult&&);
+ };
+
+ // When `db_path` is empty, the database will be opened in memory only.
+ SharedStorageDatabase(
+ base::FilePath db_path,
+ scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy,
+ std::unique_ptr<SharedStorageDatabaseOptions> options);
+
+ SharedStorageDatabase(const SharedStorageDatabase&) = delete;
+ SharedStorageDatabase(const SharedStorageDatabase&&) = delete;
+
+ ~SharedStorageDatabase();
+
+ SharedStorageDatabase& operator=(const SharedStorageDatabase&) = delete;
+ SharedStorageDatabase& operator=(const SharedStorageDatabase&&) = delete;
+
+ // Deletes the database and returns whether the operation was successful.
+ //
+ // It is OK to call `Destroy()` regardless of whether `Init()` was successful.
+ [[nodiscard]] bool Destroy();
+
+ // Returns a pointer to the database containing the actual data.
+ [[nodiscard]] sql::Database* db() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ return &db_;
+ }
+
+ // Releases all non-essential memory associated with this database connection.
+ void TrimMemory();
+
+ // Retrieves the `entry` for `context_origin` and `key`. Returns a
+ // struct containing a `value` string if one is found, `absl::nullopt`
+ // otherwise, with a bool `success` indicating whether the transaction was
+ // free of errors.
+ //
+ // Note that `key` is assumed to be of length at most
+ // `max_string_length_`, with the burden on the caller to handle errors for
+ // strings that exceed this length.
+ [[nodiscard]] GetResult Get(url::Origin context_origin, std::u16string key);
+
+ // Sets an entry for `context_origin` and `key` to have `value`.
+ // If `behavior` is `kIgnoreIfPresent` and an entry already exists for
+ // `context_origin` and `key`, then the table is not modified.
+ // Returns an enum indicating whether or not a new entry is added, the request
+ // is ignored, or if there is an error.
+ //
+ // Note that `key` and `value` assumed to be each of length at
+ // most `max_string_length_`, with the burden on the caller to handle errors
+ // for strings that exceed this length. Moreover, if `Length(context_origin)`
+ // equals `max_entries_per_origin_`, `Set()` will return a value of
+ // `OperationResult::kNoCapacity` and the table will not be modified.
+ [[nodiscard]] OperationResult Set(
+ url::Origin context_origin,
+ std::u16string key,
+ std::u16string value,
+ SetBehavior behavior = SetBehavior::kDefault);
+
+ // Appends `tail_value` to the end of the current `value`
+ // for `context_origin` and `key`, if `key` exists. If
+ // `key` does not exist, creates an entry for `key` with value
+ // `tail_value`. Returns an enum indicating whether or not an entry is
+ // added/modified or if there is an error.
+ //
+ // Note that `key` and `value` are assumed to be each of length
+ // at most `max_string_length_`, with the burden on the caller to handle
+ // errors for strings that exceed this length. Moreover, if the length of the
+ // string obtained by concatening the current `value` (if one exists)
+ // and `tail_value` exceeds `max_string_length_`, or if
+ // `Length(context_origin)` equals `max_entries_per_origin_`, `Append()` will
+ // return a value of `OperationResult::kNoCapacity` and the table will not be
+ // modified.
+ [[nodiscard]] OperationResult Append(url::Origin context_origin,
+ std::u16string key,
+ std::u16string tail_value);
+
+ // Deletes the entry for `context_origin` and `key`. Returns
+ // whether the deletion is successful.
+ //
+ // Note that `key` is assumed to be of length at most
+ // `max_string_length_`, with the burden on the caller to handle errors for
+ // strings that exceed this length.
+ [[nodiscard]] OperationResult Delete(url::Origin context_origin,
+ std::u16string key);
+
+ // Clears all entries for `context_origin`. Returns whether the operation is
+ // successful.
+ [[nodiscard]] OperationResult Clear(url::Origin context_origin);
+
+ // Returns the number of entries for `context_origin` in the database, or -1
+ // on error. Note that this call will update the origin's `last_used_time`.
+ // TODO(crbug.com/1277662): Consider renaming to something more descriptive.
+ [[nodiscard]] int64_t Length(url::Origin context_origin);
+
+ // If a list of all the keys for `context_origin` are taken in lexicographic
+ // order, retrieves the `key` at `index` of the list and sets it as
+ // data in the returned struct; otherwise the struct holds `absl::nullopt` if
+ // no such `key` exists. The `GetResult` struct also has a bool
+ // `success` indicating whether the transaction was free of errors.
+ //
+ // TODO(crbug.com/1247861): Replace with an async iterator.
+ [[nodiscard]] GetResult Key(url::Origin context_origin, uint64_t index);
+
+ // Clears all origins that match `origin_matcher` run on the owning
+ // StoragePartition's `SpecialStoragePolicy` and have `last_used_time` between
+ // the times `begin` and `end`. If `perform_storage_cleanup` is true, vacuums
+ // the database afterwards. Returns whether the transaction was successful.
+ [[nodiscard]] OperationResult PurgeMatchingOrigins(
+ OriginMatcherFunction origin_matcher,
+ base::Time begin,
+ base::Time end,
+ bool perform_storage_cleanup = false);
+
+ // Clear all entries for all origins whose `last_read_time` falls before
+ // `base::Time::Now() - window_to_be_deemed_active`. Returns whether the
+ // transaction was successful.
+ [[nodiscard]] OperationResult PurgeStaleOrigins(
+ base::TimeDelta window_to_be_deemed_active);
+
+ // Fetches a vector of `mojom::StorageUsageInfoPtr`, with one
+ // `mojom::StorageUsageInfoPtr` for each origin currently using shared storage
+ // in this profile.
+ [[nodiscard]] std::vector<mojom::StorageUsageInfoPtr> FetchOrigins();
+
+ // Returns whether the SQLite database is open.
+ [[nodiscard]] bool IsOpenForTesting() const;
+
+ // Returns the `db_status_` for tests.
+ [[nodiscard]] InitStatus DBStatusForTesting() const;
+
+ // Changes `last_used_time` to `override_last_used_time` for `context_origin`.
+ [[nodiscard]] bool OverrideLastUsedTimeForTesting(
+ url::Origin context_origin,
+ base::Time override_last_used_time);
+
+ // Overrides the clock used to check the time.
+ void OverrideClockForTesting(base::Clock* clock);
+
+ // Overrides the `SpecialStoragePolicy` for tests. Returns true.
+ [[nodiscard]] bool OverrideSpecialStoragePolicyForTesting(
+ scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy);
+
+ private:
+ // Policy to tell `LazyInit()` whether or not to create a new database if a
+ // pre-existing on-disk database is not found.
+ enum class DBCreationPolicy {
+ kIgnoreIfAbsent = 0,
+ kCreateIfAbsent = 1,
+ };
+
+ // Called at the start of each public operation, and initializes the database
+ // if it isn't already initialized (unless there is no pre-existing on-disk
+ // database to initialize and `policy` is
+ // `DBCreationPolicy::kIgnoreIfAbsent`).
+ [[nodiscard]] InitStatus LazyInit(DBCreationPolicy policy)
+ VALID_CONTEXT_REQUIRED(sequence_checker_);
+
+ // Determines whether or not an uninitialized DB already exists on disk.
+ [[nodiscard]] bool DBExists() VALID_CONTEXT_REQUIRED(sequence_checker_);
+
+ // If `db_path_` is empty, opens a temporary database in memory; otherwise
+ // opens a persistent database with the absolute path `db_path`, creating the
+ // file if it does not yet exist. Returns whether opening was successful.
+ [[nodiscard]] bool OpenDatabase() VALID_CONTEXT_REQUIRED(sequence_checker_);
+
+ // Callback for database errors. Schedules a call to Destroy() if the
+ // error is catastrophic.
+ void DatabaseErrorCallback(int extended_error, sql::Statement* stmt)
+ VALID_CONTEXT_REQUIRED(sequence_checker_);
+
+ // Helper function to implement internals of `Init()`. This allows
+ // Init() to retry in case of failure, since some failures run
+ // recovery code.
+ [[nodiscard]] InitStatus InitImpl() VALID_CONTEXT_REQUIRED(sequence_checker_);
+
+ // Vacuums the database. This will cause sqlite to defragment and collect
+ // unused space in the file. It can be VERY SLOW. Returns whether the
+ // operation was successful.
+ [[nodiscard]] bool Vacuum() VALID_CONTEXT_REQUIRED(sequence_checker_);
+
+ // Clears all entries for `context_origin`. Returns whether deletion is
+ // successful. Not named `Clear()` to distinguish it from the public method
+ // called via `SequenceBound::AsyncCall()`.
+ [[nodiscard]] bool Purge(const std::string& context_origin)
+ VALID_CONTEXT_REQUIRED(sequence_checker_);
+
+ // Returns the number of entries for `context_origin`, i.e. the `length`.
+ // Not named `Length()` to distinguish it from the public method called via
+ // `SequenceBound::AsyncCall()`.
+ [[nodiscard]] int64_t NumEntries(const std::string& context_origin)
+ VALID_CONTEXT_REQUIRED(sequence_checker_);
+
+ // Returns whether an entry exists for `context_origin` and `key`.
+ [[nodiscard]] bool HasEntryFor(const std::string& context_origin,
+ const std::u16string& key)
+ VALID_CONTEXT_REQUIRED(sequence_checker_);
+
+ // Sets `last_used_time` to `new_last_used_time` for `context_origin`.
+ [[nodiscard]] bool SetLastUsedTime(const std::string& context_origin,
+ base::Time new_last_used_time)
+ VALID_CONTEXT_REQUIRED(sequence_checker_);
+
+ // Updates `last_used_time` to `base::Time::Now()` for `context_origin`.
+ [[nodiscard]] bool UpdateLastUsedTime(const std::string& context_origin)
+ VALID_CONTEXT_REQUIRED(sequence_checker_);
+
+ // Updates `length` by `delta` for `context_origin`. If `should_update_time`
+ // is true, also updates `last_used_time` to `base::Time::Now()`.
+ [[nodiscard]] bool UpdateLength(const std::string& context_origin,
+ int64_t delta,
+ bool should_update_time = true)
+ VALID_CONTEXT_REQUIRED(sequence_checker_);
+
+ // Inserts a triple for `(context_origin,key,value)` into
+ // `values_mapping`.
+ [[nodiscard]] bool InsertIntoValuesMapping(const std::string& context_origin,
+ const std::u16string& key,
+ const std::u16string& value)
+ VALID_CONTEXT_REQUIRED(sequence_checker_);
+
+ // Deletes the row for `context_origin` from `per_origin_mapping`.
+ [[nodiscard]] bool DeleteFromPerOriginMapping(
+ const std::string& context_origin)
+ VALID_CONTEXT_REQUIRED(sequence_checker_);
+
+ // Inserts the triple for `(context_origin, last_used_time, length)` into
+ // `per_origin_mapping`.
+ [[nodiscard]] bool InsertIntoPerOriginMapping(
+ const std::string& context_origin,
+ base::Time last_used_time,
+ uint64_t length) VALID_CONTEXT_REQUIRED(sequence_checker_);
+
+ // Returns whether the `length` for `context_origin` is less than
+ // `max_entries_per_origin_`.
+ [[nodiscard]] bool HasCapacity(const std::string& context_origin)
+ VALID_CONTEXT_REQUIRED(sequence_checker_);
+
+ // The database containing the actual data.
+ sql::Database db_ GUARDED_BY_CONTEXT(sequence_checker_);
+
+ // Contains the version information.
+ sql::MetaTable meta_table_ GUARDED_BY_CONTEXT(sequence_checker_);
+
+ // Initialization status of `db_`.
+ GUARDED_BY_CONTEXT(sequence_checker_)
+ InitStatus db_status_ = InitStatus::kUnattempted;
+
+ // Only set to true if `DBExists()
+ DBFileStatus db_file_status_ GUARDED_BY_CONTEXT(sequence_checker_);
+
+ // The path to the database, if file-backed.
+ base::FilePath db_path_ GUARDED_BY_CONTEXT(sequence_checker_);
+
+ // The owning partition's storage policy.
+ scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy_
+ GUARDED_BY_CONTEXT(sequence_checker_);
+
+ // The maximum allowed number of entries per origin.
+ const int64_t max_entries_per_origin_ GUARDED_BY_CONTEXT(sequence_checker_);
+
+ // The maximum size of a string input from any origin's script. Applies
+ // separately to both script keys and script values.
+ size_t max_string_length_ GUARDED_BY_CONTEXT(sequence_checker_);
+
+ // Maxmium number of times that SQL database attempts to initialize.
+ size_t max_init_tries_ GUARDED_BY_CONTEXT(sequence_checker_);
+
+ // Clock used to determine current time. Can be overridden in tests.
+ raw_ptr<base::Clock> clock_ GUARDED_BY_CONTEXT(sequence_checker_);
+
+ SEQUENCE_CHECKER(sequence_checker_);
+};
+
+} // namespace storage
+
+#endif // COMPONENTS_SERVICES_STORAGE_SHARED_STORAGE_SHARED_STORAGE_DATABASE_H_
diff --git a/chromium/components/services/storage/shared_storage/shared_storage_database_unittest.cc b/chromium/components/services/storage/shared_storage/shared_storage_database_unittest.cc
new file mode 100644
index 00000000000..364bead255c
--- /dev/null
+++ b/chromium/components/services/storage/shared_storage/shared_storage_database_unittest.cc
@@ -0,0 +1,835 @@
+// Copyright 2021 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.
+
+#include "components/services/storage/shared_storage/shared_storage_database.h"
+
+#include <algorithm>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/run_loop.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/test/simple_test_clock.h"
+#include "base/test/task_environment.h"
+#include "base/time/time.h"
+#include "components/services/storage/public/mojom/storage_usage_info.mojom.h"
+#include "components/services/storage/shared_storage/shared_storage_options.h"
+#include "components/services/storage/shared_storage/shared_storage_test_utils.h"
+#include "sql/database.h"
+#include "storage/browser/quota/special_storage_policy.h"
+#include "storage/browser/test/mock_special_storage_policy.h"
+#include "testing/gmock/include/gmock/gmock-matchers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/features.h"
+#include "url/gurl.h"
+#include "url/origin.h"
+
+namespace storage {
+
+namespace {
+
+using ::testing::ElementsAre;
+using OriginMatcherFunction = SharedStorageDatabase::OriginMatcherFunction;
+using InitStatus = SharedStorageDatabase::InitStatus;
+using SetBehavior = SharedStorageDatabase::SetBehavior;
+using OperationResult = SharedStorageDatabase::OperationResult;
+using GetResult = SharedStorageDatabase::GetResult;
+
+const int kMaxEntriesPerOrigin = 5;
+const int kMaxStringLength = 100;
+
+} // namespace
+
+class SharedStorageDatabaseTest : public testing::Test {
+ public:
+ SharedStorageDatabaseTest() {
+ special_storage_policy_ = base::MakeRefCounted<MockSpecialStoragePolicy>();
+ }
+
+ ~SharedStorageDatabaseTest() override = default;
+
+ void SetUp() override {
+ InitSharedStorageFeature();
+
+ // Get a temporary directory for the test DB files.
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+
+ file_name_ = temp_dir_.GetPath().AppendASCII("TestSharedStorage.db");
+ }
+
+ void TearDown() override {
+ db_.reset();
+ EXPECT_TRUE(temp_dir_.Delete());
+ }
+
+ // Initialize a shared storage database instance from the SQL file at
+ // `relative_file_path` in the "storage/" subdirectory of test data.
+ std::unique_ptr<SharedStorageDatabase> LoadFromFile(
+ const char* relative_file_path) {
+ if (!CreateDatabaseFromSQL(file_name_, relative_file_path)) {
+ ADD_FAILURE() << "Failed loading " << relative_file_path;
+ return nullptr;
+ }
+
+ return std::make_unique<SharedStorageDatabase>(
+ file_name_, special_storage_policy_,
+ SharedStorageOptions::Create()->GetDatabaseOptions());
+ }
+
+ sql::Database* SqlDB() { return db_ ? db_->db() : nullptr; }
+
+ virtual void InitSharedStorageFeature() {
+ scoped_feature_list_.InitAndEnableFeatureWithParameters(
+ {blink::features::kSharedStorageAPI},
+ {{"MaxSharedStorageInitTries", "1"}});
+ }
+
+ protected:
+ base::ScopedTempDir temp_dir_;
+ base::FilePath file_name_;
+ scoped_refptr<storage::MockSpecialStoragePolicy> special_storage_policy_;
+ std::unique_ptr<SharedStorageDatabase> db_;
+ base::test::ScopedFeatureList scoped_feature_list_;
+ base::SimpleTestClock clock_;
+
+ private:
+ base::test::SingleThreadTaskEnvironment task_environment_;
+};
+
+// Test loading version 1 database.
+TEST_F(SharedStorageDatabaseTest, Version1_LoadFromFile) {
+ db_ = LoadFromFile("shared_storage.v1.sql");
+ ASSERT_TRUE(db_);
+
+ url::Origin google_com = url::Origin::Create(GURL("http://google.com/"));
+ EXPECT_EQ(db_->Get(google_com, u"key1").data, u"value1");
+ EXPECT_EQ(db_->Get(google_com, u"key2").data, u"value2");
+
+ // Because the SQL database is lazy-initialized, wait to verify tables and
+ // columns until after the first call to `Get()`.
+ ASSERT_TRUE(SqlDB());
+ VerifySharedStorageTablesAndColumns(*SqlDB());
+
+ url::Origin youtube_com = url::Origin::Create(GURL("http://youtube.com/"));
+ EXPECT_EQ(1L, db_->Length(youtube_com));
+
+ url::Origin chromium_org = url::Origin::Create(GURL("http://chromium.org/"));
+ EXPECT_EQ(db_->Get(chromium_org, u"a").data, u"");
+ EXPECT_EQ(db_->Key(chromium_org, 2UL).data, u"c");
+
+ url::Origin google_org = url::Origin::Create(GURL("http://google.org/"));
+ EXPECT_EQ(
+ db_->Get(google_org, u"1").data,
+ u"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ "fffffffffffffffff");
+ EXPECT_EQ(db_->Get(google_org,
+ u"ffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ "fffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ "fffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ "fffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ "fffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ "fffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ "fffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ "fffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ "fffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ "fffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ "fffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ "fffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ "fffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ "fffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ "fffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ "fffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ "fffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ "ffffffffffffffffffffffffffffffffffffffffffffffffffffffff")
+ .data,
+ u"k");
+
+ std::vector<url::Origin> origins;
+ for (const auto& info : db_->FetchOrigins())
+ origins.push_back(info->origin);
+ EXPECT_THAT(
+ origins,
+ ElementsAre(
+ url::Origin::Create(GURL("http://abc.xyz")), chromium_org, google_com,
+ google_org, url::Origin::Create(GURL("http://growwithgoogle.com")),
+ url::Origin::Create(GURL("http://gv.com")),
+ url::Origin::Create(GURL("http://waymo.com")),
+ url::Origin::Create(GURL("http://withgoogle.com")), youtube_com));
+
+ EXPECT_TRUE(db_->Destroy());
+}
+
+TEST_F(SharedStorageDatabaseTest, Version1_DestroyTooNew) {
+ // Initialization should fail, since the last compatible version number
+ // is too high.
+ db_ = LoadFromFile("shared_storage.v1.init_too_new.sql");
+ ASSERT_TRUE(db_);
+ ASSERT_TRUE(SqlDB());
+
+ // Call an operation so that the database will attempt to be lazy-initialized.
+ const url::Origin kOrigin = url::Origin::Create(GURL("http://www.a.com"));
+ EXPECT_EQ(OperationResult::kInitFailure, db_->Set(kOrigin, u"key", u"value"));
+ ASSERT_FALSE(db_->IsOpenForTesting());
+ EXPECT_EQ(InitStatus::kTooNew, db_->DBStatusForTesting());
+
+ // Test that other operations likewise fail, in order to exercise these code
+ // paths.
+ EXPECT_EQ(OperationResult::kInitFailure, db_->Get(kOrigin, u"key").result);
+ EXPECT_EQ(OperationResult::kInitFailure,
+ db_->Append(kOrigin, u"key", u"value"));
+ EXPECT_EQ(OperationResult::kInitFailure, db_->Delete(kOrigin, u"key"));
+ EXPECT_EQ(OperationResult::kInitFailure, db_->Clear(kOrigin));
+ EXPECT_EQ(-1, db_->Length(kOrigin));
+ EXPECT_EQ(OperationResult::kInitFailure, db_->Key(kOrigin, 0).result);
+ EXPECT_EQ(OperationResult::kInitFailure,
+ db_->PurgeMatchingOrigins(OriginMatcherFunction(),
+ base::Time::Min(), base::Time::Max(),
+ /*perform_storage_cleanup=*/false));
+ EXPECT_EQ(OperationResult::kInitFailure,
+ db_->PurgeStaleOrigins(base::Seconds(1)));
+
+ // Test that it is still OK to Destroy() the database.
+ EXPECT_TRUE(db_->Destroy());
+}
+
+TEST_F(SharedStorageDatabaseTest, Version0_DestroyTooOld) {
+ // Initialization should fail, since the current version number
+ // is too low and we're forcing there not to be a retry attempt.
+ db_ = LoadFromFile("shared_storage.v0.init_too_old.sql");
+ ASSERT_TRUE(db_);
+ ASSERT_TRUE(SqlDB());
+
+ // Call an operation so that the database will attempt to be lazy-initialized.
+ EXPECT_EQ(OperationResult::kInitFailure,
+ db_->Set(url::Origin::Create(GURL("http://www.a.com")), u"key",
+ u"value"));
+ ASSERT_FALSE(db_->IsOpenForTesting());
+ EXPECT_EQ(InitStatus::kTooOld, db_->DBStatusForTesting());
+
+ // Test that it is still OK to Destroy() the database.
+ EXPECT_TRUE(db_->Destroy());
+}
+
+class SharedStorageDatabaseParamTest
+ : public SharedStorageDatabaseTest,
+ public testing::WithParamInterface<SharedStorageWrappedBool> {
+ public:
+ void SetUp() override {
+ SharedStorageDatabaseTest::SetUp();
+
+ auto options = SharedStorageOptions::Create()->GetDatabaseOptions();
+ base::FilePath db_path =
+ (GetParam().in_memory_only) ? base::FilePath() : file_name_;
+ db_ = std::make_unique<SharedStorageDatabase>(
+ db_path, special_storage_policy_, std::move(options));
+ db_->OverrideClockForTesting(&clock_);
+ }
+
+ void InitSharedStorageFeature() override {
+ scoped_feature_list_.InitAndEnableFeatureWithParameters(
+ {blink::features::kSharedStorageAPI},
+ {{"MaxSharedStorageEntriesPerOrigin",
+ base::NumberToString(kMaxEntriesPerOrigin)},
+ {"MaxSharedStorageStringLength",
+ base::NumberToString(kMaxStringLength)}});
+ }
+};
+
+INSTANTIATE_TEST_SUITE_P(All,
+ SharedStorageDatabaseParamTest,
+ testing::ValuesIn(GetSharedStorageWrappedBools()),
+ testing::PrintToStringParamName());
+
+TEST_P(SharedStorageDatabaseParamTest, BasicOperations) {
+ const url::Origin kOrigin1 =
+ url::Origin::Create(GURL("http://www.example1.test"));
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin1, u"key1", u"value1"));
+ EXPECT_EQ(db_->Get(kOrigin1, u"key1").data, u"value1");
+
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin1, u"key1", u"value2"));
+ EXPECT_EQ(db_->Get(kOrigin1, u"key1").data, u"value2");
+
+ EXPECT_EQ(OperationResult::kSuccess, db_->Delete(kOrigin1, u"key1"));
+ EXPECT_FALSE(db_->Get(kOrigin1, u"key1").data);
+
+ // Check that trying to retrieve the empty key doesn't give an error, even
+ // though the input is invalid and no value is found.
+ GetResult result = db_->Get(kOrigin1, u"");
+ EXPECT_EQ(OperationResult::kSuccess, result.result);
+ EXPECT_FALSE(result.data);
+
+ // Check that trying to delete the empty key doesn't give an error, even
+ // though the input is invalid and no value is found to delete.
+ EXPECT_EQ(OperationResult::kSuccess, db_->Delete(kOrigin1, u""));
+}
+
+TEST_P(SharedStorageDatabaseParamTest, IgnoreIfPresent) {
+ const url::Origin kOrigin1 =
+ url::Origin::Create(GURL("http://www.example1.test"));
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin1, u"key1", u"value1"));
+ EXPECT_EQ(db_->Get(kOrigin1, u"key1").data, u"value1");
+
+ // The database does not set a new value for "key1", but retains the
+ // previously set value "value1" because `behavior` is `kIgnoreIfPresent`.
+ EXPECT_EQ(OperationResult::kIgnored,
+ db_->Set(kOrigin1, u"key1", u"value2",
+ /*behavior=*/SetBehavior::kIgnoreIfPresent));
+ EXPECT_EQ(db_->Get(kOrigin1, u"key1").data, u"value1");
+
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin1, u"key2", u"value1"));
+ EXPECT_EQ(db_->Get(kOrigin1, u"key2").data, u"value1");
+
+ // Having `behavior` set to `kDefault` makes `Set()` override any previous
+ // value.
+ EXPECT_EQ(OperationResult::kSet,
+ db_->Set(kOrigin1, u"key2", u"value2",
+ /*behavior=*/SetBehavior::kDefault));
+ EXPECT_EQ(db_->Get(kOrigin1, u"key2").data, u"value2");
+
+ const url::Origin kOrigin2 =
+ url::Origin::Create(GURL("http://www.example2.test"));
+
+ // If no previous value exists, it makes no difference whether
+ // `behavior` is set to `kDefault` or `kIgnoreIfPresent`.
+ EXPECT_EQ(OperationResult::kSet,
+ db_->Set(kOrigin2, u"key1", u"value1",
+ /*behavior=*/SetBehavior::kIgnoreIfPresent));
+ EXPECT_EQ(db_->Get(kOrigin2, u"key1").data, u"value1");
+
+ EXPECT_EQ(OperationResult::kSet,
+ db_->Set(kOrigin2, u"key2", u"value2",
+ /*behavior=*/SetBehavior::kDefault));
+ EXPECT_EQ(db_->Get(kOrigin2, u"key2").data, u"value2");
+}
+
+TEST_P(SharedStorageDatabaseParamTest, Append) {
+ const url::Origin kOrigin1 =
+ url::Origin::Create(GURL("http://www.example1.test"));
+ EXPECT_EQ(OperationResult::kSet, db_->Append(kOrigin1, u"key1", u"value1"));
+ EXPECT_EQ(db_->Get(kOrigin1, u"key1").data, u"value1");
+
+ EXPECT_EQ(OperationResult::kSet, db_->Append(kOrigin1, u"key1", u"value1"));
+ EXPECT_EQ(db_->Get(kOrigin1, u"key1").data, u"value1value1");
+
+ EXPECT_EQ(OperationResult::kSet, db_->Append(kOrigin1, u"key1", u"value1"));
+ EXPECT_EQ(db_->Get(kOrigin1, u"key1").data, u"value1value1value1");
+}
+
+TEST_P(SharedStorageDatabaseParamTest, Length) {
+ const url::Origin kOrigin1 =
+ url::Origin::Create(GURL("http://www.example1.test"));
+ EXPECT_EQ(0L, db_->Length(kOrigin1));
+
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin1, u"key1", u"value1"));
+ EXPECT_EQ(1L, db_->Length(kOrigin1));
+
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin1, u"key2", u"value2"));
+ EXPECT_EQ(2L, db_->Length(kOrigin1));
+
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin1, u"key2", u"value3"));
+ EXPECT_EQ(2L, db_->Length(kOrigin1));
+
+ const url::Origin kOrigin2 =
+ url::Origin::Create(GURL("http://www.example2.test"));
+ EXPECT_EQ(0L, db_->Length(kOrigin2));
+
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin2, u"key1", u"value1"));
+ EXPECT_EQ(1L, db_->Length(kOrigin2));
+ EXPECT_EQ(2L, db_->Length(kOrigin1));
+
+ EXPECT_EQ(OperationResult::kSuccess, db_->Delete(kOrigin2, u"key1"));
+ EXPECT_EQ(0L, db_->Length(kOrigin2));
+ EXPECT_EQ(2L, db_->Length(kOrigin1));
+
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin1, u"key3", u"value3"));
+ EXPECT_EQ(3L, db_->Length(kOrigin1));
+ EXPECT_EQ(0L, db_->Length(kOrigin2));
+}
+
+TEST_P(SharedStorageDatabaseParamTest, Key) {
+ const url::Origin kOrigin1 =
+ url::Origin::Create(GURL("http://www.example1.test"));
+ EXPECT_FALSE(db_->Key(kOrigin1, 0UL).data);
+
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin1, u"key1", u"value1"));
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin1, u"key2", u"value2"));
+ EXPECT_EQ(db_->Key(kOrigin1, 0UL).data, u"key1");
+ EXPECT_EQ(db_->Key(kOrigin1, 1UL).data, u"key2");
+ EXPECT_FALSE(db_->Key(kOrigin1, 2UL).data);
+
+ const url::Origin kOrigin2 =
+ url::Origin::Create(GURL("http://www.example2.test"));
+ EXPECT_FALSE(db_->Key(kOrigin2, 0UL).data);
+
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin2, u"key2", u"value2"));
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin2, u"key1", u"value1"));
+ EXPECT_EQ(db_->Key(kOrigin2, 0UL).data, u"key1");
+ EXPECT_EQ(db_->Key(kOrigin2, 1UL).data, u"key2");
+
+ EXPECT_EQ(OperationResult::kSuccess, db_->Delete(kOrigin2, u"key2"));
+ EXPECT_EQ(db_->Key(kOrigin2, 0UL).data, u"key1");
+
+ // There is no longer a key at this index.
+ EXPECT_FALSE(db_->Key(kOrigin2, 1UL).data);
+}
+
+TEST_P(SharedStorageDatabaseParamTest, Clear) {
+ const url::Origin kOrigin1 =
+ url::Origin::Create(GURL("http://www.example1.test"));
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin1, u"key1", u"value1"));
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin1, u"key2", u"value2"));
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin1, u"key3", u"value3"));
+ EXPECT_EQ(3L, db_->Length(kOrigin1));
+
+ const url::Origin kOrigin2 =
+ url::Origin::Create(GURL("http://www.example2.test"));
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin2, u"key1", u"value1"));
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin2, u"key2", u"value2"));
+ EXPECT_EQ(2L, db_->Length(kOrigin2));
+
+ EXPECT_EQ(OperationResult::kSuccess, db_->Clear(kOrigin1));
+ EXPECT_EQ(0L, db_->Length(kOrigin1));
+ EXPECT_EQ(2L, db_->Length(kOrigin2));
+
+ EXPECT_EQ(OperationResult::kSuccess, db_->Clear(kOrigin2));
+ EXPECT_EQ(0L, db_->Length(kOrigin2));
+}
+
+TEST_P(SharedStorageDatabaseParamTest, FetchOrigins) {
+ EXPECT_TRUE(db_->FetchOrigins().empty());
+
+ const url::Origin kOrigin1 =
+ url::Origin::Create(GURL("http://www.example1.test"));
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin1, u"key1", u"value1"));
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin1, u"key2", u"value2"));
+ EXPECT_EQ(2L, db_->Length(kOrigin1));
+
+ const url::Origin kOrigin2 =
+ url::Origin::Create(GURL("http://www.example2.test"));
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin2, u"key1", u"value1"));
+ EXPECT_EQ(1L, db_->Length(kOrigin2));
+
+ const url::Origin kOrigin3 =
+ url::Origin::Create(GURL("http://www.example3.test"));
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin3, u"key1", u"value1"));
+ EXPECT_EQ(1L, db_->Length(kOrigin3));
+
+ const url::Origin kOrigin4 =
+ url::Origin::Create(GURL("http://www.example4.test"));
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin4, u"key1", u"value1"));
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin4, u"key2", u"value2"));
+ EXPECT_EQ(2L, db_->Length(kOrigin4));
+
+ std::vector<url::Origin> origins;
+ for (const auto& info : db_->FetchOrigins())
+ origins.push_back(info->origin);
+ EXPECT_THAT(origins, ElementsAre(kOrigin1, kOrigin2, kOrigin3, kOrigin4));
+
+ EXPECT_EQ(OperationResult::kSuccess, db_->Clear(kOrigin1));
+ EXPECT_EQ(0L, db_->Length(kOrigin1));
+
+ EXPECT_EQ(OperationResult::kSuccess, db_->Delete(kOrigin2, u"key1"));
+ EXPECT_EQ(0L, db_->Length(kOrigin2));
+
+ origins.clear();
+ EXPECT_TRUE(origins.empty());
+ for (const auto& info : db_->FetchOrigins())
+ origins.push_back(info->origin);
+ EXPECT_THAT(origins, ElementsAre(kOrigin3, kOrigin4));
+}
+
+class SharedStorageDatabasePurgeMatchingOriginsParamTest
+ : public SharedStorageDatabaseTest,
+ public testing::WithParamInterface<PurgeMatchingOriginsParams> {
+ public:
+ void SetUp() override {
+ SharedStorageDatabaseTest::SetUp();
+
+ auto options = SharedStorageOptions::Create()->GetDatabaseOptions();
+ base::FilePath db_path =
+ (GetParam().in_memory_only) ? base::FilePath() : file_name_;
+ db_ = std::make_unique<SharedStorageDatabase>(
+ db_path, special_storage_policy_, std::move(options));
+ db_->OverrideClockForTesting(&clock_);
+ }
+
+ void InitSharedStorageFeature() override {
+ scoped_feature_list_.InitAndEnableFeatureWithParameters(
+ {blink::features::kSharedStorageAPI},
+ {{"MaxSharedStorageEntriesPerOrigin",
+ base::NumberToString(kMaxEntriesPerOrigin)},
+ {"MaxSharedStorageStringLength",
+ base::NumberToString(kMaxStringLength)}});
+ }
+};
+
+INSTANTIATE_TEST_SUITE_P(All,
+ SharedStorageDatabasePurgeMatchingOriginsParamTest,
+ testing::ValuesIn(GetPurgeMatchingOriginsParams()),
+ testing::PrintToStringParamName());
+
+TEST_P(SharedStorageDatabasePurgeMatchingOriginsParamTest, AllTime) {
+ EXPECT_TRUE(db_->FetchOrigins().empty());
+
+ const url::Origin kOrigin1 =
+ url::Origin::Create(GURL("http://www.example1.test"));
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin1, u"key1", u"value1"));
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin1, u"key2", u"value2"));
+ EXPECT_EQ(2L, db_->Length(kOrigin1));
+
+ const url::Origin kOrigin2 =
+ url::Origin::Create(GURL("http://www.example2.test"));
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin2, u"key1", u"value1"));
+ EXPECT_EQ(1L, db_->Length(kOrigin2));
+
+ const url::Origin kOrigin3 =
+ url::Origin::Create(GURL("http://www.example3.test"));
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin3, u"key1", u"value1"));
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin3, u"key2", u"value2"));
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin3, u"key3", u"value3"));
+ EXPECT_EQ(3L, db_->Length(kOrigin3));
+
+ std::vector<url::Origin> origins;
+ for (const auto& info : db_->FetchOrigins())
+ origins.push_back(info->origin);
+ EXPECT_THAT(origins, ElementsAre(kOrigin1, kOrigin2, kOrigin3));
+
+ EXPECT_EQ(
+ OperationResult::kSuccess,
+ db_->PurgeMatchingOrigins(
+ OriginMatcherFunctionUtility::MakeMatcherFunction({kOrigin1}),
+ base::Time(), base::Time::Max(), GetParam().perform_storage_cleanup));
+
+ // `kOrigin1` is cleared. The other origins are not.
+ EXPECT_EQ(0L, db_->Length(kOrigin1));
+ EXPECT_EQ(1L, db_->Length(kOrigin2));
+ EXPECT_EQ(3L, db_->Length(kOrigin3));
+
+ origins.clear();
+ for (const auto& info : db_->FetchOrigins())
+ origins.push_back(info->origin);
+ EXPECT_THAT(origins, ElementsAre(kOrigin2, kOrigin3));
+
+ EXPECT_EQ(
+ OperationResult::kSuccess,
+ db_->PurgeMatchingOrigins(
+ OriginMatcherFunctionUtility::MakeMatcherFunction(
+ {kOrigin2, kOrigin3}),
+ base::Time(), base::Time::Max(), GetParam().perform_storage_cleanup));
+
+ // All three origins should be cleared.
+ EXPECT_EQ(0L, db_->Length(kOrigin1));
+ EXPECT_EQ(0L, db_->Length(kOrigin2));
+ EXPECT_EQ(0L, db_->Length(kOrigin3));
+
+ EXPECT_TRUE(db_->FetchOrigins().empty());
+
+ // There is no error from trying to clear an origin that isn't in the
+ // database.
+ EXPECT_EQ(
+ OperationResult::kSuccess,
+ db_->PurgeMatchingOrigins(
+ OriginMatcherFunctionUtility::MakeMatcherFunction(
+ {"http://www.example4.test"}),
+ base::Time(), base::Time::Max(), GetParam().perform_storage_cleanup));
+}
+
+TEST_P(SharedStorageDatabasePurgeMatchingOriginsParamTest, SinceThreshold) {
+ EXPECT_TRUE(db_->FetchOrigins().empty());
+
+ const url::Origin kOrigin1 =
+ url::Origin::Create(GURL("http://www.example1.test"));
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin1, u"key1", u"value1"));
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin1, u"key2", u"value2"));
+ EXPECT_EQ(2L, db_->Length(kOrigin1));
+
+ const url::Origin kOrigin2 =
+ url::Origin::Create(GURL("http://www.example2.test"));
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin2, u"key1", u"value1"));
+ EXPECT_EQ(1L, db_->Length(kOrigin2));
+
+ const url::Origin kOrigin3 =
+ url::Origin::Create(GURL("http://www.example3.test"));
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin3, u"key1", u"value1"));
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin3, u"key2", u"value2"));
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin3, u"key3", u"value3"));
+ EXPECT_EQ(3L, db_->Length(kOrigin3));
+
+ const url::Origin kOrigin4 =
+ url::Origin::Create(GURL("http://www.example4.test"));
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin4, u"key1", u"value1"));
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin4, u"key2", u"value2"));
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin4, u"key3", u"value3"));
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin4, u"key4", u"value4"));
+ EXPECT_EQ(4L, db_->Length(kOrigin4));
+
+ clock_.SetNow(base::Time::Now());
+ clock_.Advance(base::Milliseconds(50));
+
+ // Time threshold that will be used as a starting point for deletion.
+ base::Time threshold = clock_.Now();
+
+ std::vector<url::Origin> origins;
+ for (const auto& info : db_->FetchOrigins())
+ origins.push_back(info->origin);
+ EXPECT_THAT(origins, ElementsAre(kOrigin1, kOrigin2, kOrigin3, kOrigin4));
+
+ // Read from `kOrigin1`.
+ EXPECT_EQ(db_->Get(kOrigin1, u"key1").data, u"value1");
+
+ EXPECT_EQ(
+ OperationResult::kSuccess,
+ db_->PurgeMatchingOrigins(
+ OriginMatcherFunctionUtility::MakeMatcherFunction(
+ {kOrigin1, kOrigin2}),
+ threshold, base::Time::Max(), GetParam().perform_storage_cleanup));
+
+ // `kOrigin1` is cleared. The other origins are not.
+ EXPECT_EQ(0L, db_->Length(kOrigin1));
+ EXPECT_EQ(1L, db_->Length(kOrigin2));
+ EXPECT_EQ(3L, db_->Length(kOrigin3));
+ EXPECT_EQ(4L, db_->Length(kOrigin4));
+
+ clock_.Advance(base::Milliseconds(50));
+
+ // Time threshold that will be used as a starting point for deletion.
+ threshold = clock_.Now();
+
+ // Write to `kOrigin3`.
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin3, u"key4", u"value4"));
+ EXPECT_EQ(4L, db_->Length(kOrigin3));
+
+ origins.clear();
+ for (const auto& info : db_->FetchOrigins())
+ origins.push_back(info->origin);
+ EXPECT_THAT(origins, ElementsAre(kOrigin2, kOrigin3, kOrigin4));
+
+ EXPECT_EQ(
+ OperationResult::kSuccess,
+ db_->PurgeMatchingOrigins(
+ OriginMatcherFunctionUtility::MakeMatcherFunction(
+ {kOrigin2, kOrigin3, kOrigin4}),
+ threshold, base::Time::Max(), GetParam().perform_storage_cleanup));
+
+ // `kOrigin3` is cleared. The others weren't modified within the given time
+ // period.
+ EXPECT_EQ(0L, db_->Length(kOrigin1));
+ EXPECT_EQ(1L, db_->Length(kOrigin2));
+ EXPECT_EQ(0L, db_->Length(kOrigin3));
+ EXPECT_EQ(4L, db_->Length(kOrigin4));
+
+ origins.clear();
+ for (const auto& info : db_->FetchOrigins())
+ origins.push_back(info->origin);
+ EXPECT_THAT(origins, ElementsAre(kOrigin2, kOrigin4));
+
+ // There is no error from trying to clear an origin that isn't in the
+ // database.
+ EXPECT_EQ(
+ OperationResult::kSuccess,
+ db_->PurgeMatchingOrigins(
+ OriginMatcherFunctionUtility::MakeMatcherFunction(
+ {"http://www.example5.test"}),
+ threshold, base::Time::Max(), GetParam().perform_storage_cleanup));
+}
+
+TEST_P(SharedStorageDatabaseParamTest, PurgeStaleOrigins) {
+ EXPECT_TRUE(db_->FetchOrigins().empty());
+
+ const url::Origin kOrigin1 =
+ url::Origin::Create(GURL("http://www.example1.test"));
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin1, u"key1", u"value1"));
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin1, u"key2", u"value2"));
+ EXPECT_EQ(2L, db_->Length(kOrigin1));
+ EXPECT_EQ(db_->Get(kOrigin1, u"key1").data, u"value1");
+ EXPECT_EQ(db_->Get(kOrigin1, u"key2").data, u"value2");
+
+ const url::Origin kOrigin2 =
+ url::Origin::Create(GURL("http://www.example2.test"));
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin2, u"key1", u"value1"));
+ EXPECT_EQ(1L, db_->Length(kOrigin2));
+ EXPECT_EQ(db_->Get(kOrigin2, u"key1").data, u"value1");
+
+ const url::Origin kOrigin3 =
+ url::Origin::Create(GURL("http://www.example3.test"));
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin3, u"key1", u"value1"));
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin3, u"key2", u"value2"));
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin3, u"key3", u"value3"));
+ EXPECT_EQ(3L, db_->Length(kOrigin3));
+
+ const url::Origin kOrigin4 =
+ url::Origin::Create(GURL("http://www.example4.test"));
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin4, u"key1", u"value1"));
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin4, u"key2", u"value2"));
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin4, u"key3", u"value3"));
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin4, u"key4", u"value4"));
+ EXPECT_EQ(4L, db_->Length(kOrigin4));
+
+ std::vector<url::Origin> origins;
+ for (const auto& info : db_->FetchOrigins())
+ origins.push_back(info->origin);
+ EXPECT_THAT(origins, ElementsAre(kOrigin1, kOrigin2, kOrigin3, kOrigin4));
+
+ clock_.SetNow(base::Time::Now());
+ clock_.Advance(base::Milliseconds(50));
+
+ // Time threshold after which an origin must be read from or written to in
+ // order to be considered active.
+ base::Time threshold = clock_.Now();
+ clock_.Advance(base::Milliseconds(50));
+
+ // Read from `kOrigin1`.
+ EXPECT_EQ(db_->Get(kOrigin1, u"key1").data, u"value1");
+
+ // Write to `kOrigin3`.
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin3, u"key4", u"value4"));
+ EXPECT_EQ(4L, db_->Length(kOrigin3));
+
+ EXPECT_EQ(OperationResult::kSuccess,
+ db_->PurgeStaleOrigins(clock_.Now() - threshold));
+
+ // `kOrigin1` was active.
+ EXPECT_EQ(2L, db_->Length(kOrigin1));
+
+ // `kOrigin2` was inactive.
+ EXPECT_EQ(0L, db_->Length(kOrigin2));
+
+ // `kOrigin3` was active.
+ EXPECT_EQ(4L, db_->Length(kOrigin3));
+
+ // `kOrigin4` was inactive.
+ EXPECT_EQ(0L, db_->Length(kOrigin4));
+
+ origins.clear();
+ for (const auto& info : db_->FetchOrigins())
+ origins.push_back(info->origin);
+ EXPECT_THAT(origins, ElementsAre(kOrigin1, kOrigin3));
+}
+
+TEST_P(SharedStorageDatabaseParamTest, TrimMemory) {
+ EXPECT_TRUE(db_->FetchOrigins().empty());
+
+ const url::Origin kOrigin1 =
+ url::Origin::Create(GURL("http://www.example1.test"));
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin1, u"key1", u"value1"));
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin1, u"key2", u"value2"));
+ EXPECT_EQ(2L, db_->Length(kOrigin1));
+
+ const url::Origin kOrigin2 =
+ url::Origin::Create(GURL("http://www.example2.test"));
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin2, u"key1", u"value1"));
+ EXPECT_EQ(1L, db_->Length(kOrigin2));
+
+ const url::Origin kOrigin3 =
+ url::Origin::Create(GURL("http://www.example3.test"));
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin3, u"key1", u"value1"));
+ EXPECT_EQ(1L, db_->Length(kOrigin3));
+
+ const url::Origin kOrigin4 =
+ url::Origin::Create(GURL("http://www.example4.test"));
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin4, u"key1", u"value1"));
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin4, u"key2", u"value2"));
+ EXPECT_EQ(2L, db_->Length(kOrigin4));
+
+ std::vector<url::Origin> origins;
+ for (const auto& info : db_->FetchOrigins())
+ origins.push_back(info->origin);
+ EXPECT_THAT(origins, ElementsAre(kOrigin1, kOrigin2, kOrigin3, kOrigin4));
+
+ EXPECT_EQ(OperationResult::kSuccess, db_->Clear(kOrigin1));
+ EXPECT_EQ(0L, db_->Length(kOrigin1));
+
+ EXPECT_EQ(OperationResult::kSuccess, db_->Delete(kOrigin2, u"key1"));
+ EXPECT_EQ(0L, db_->Length(kOrigin2));
+
+ origins.clear();
+ for (const auto& info : db_->FetchOrigins())
+ origins.push_back(info->origin);
+ EXPECT_THAT(origins, ElementsAre(kOrigin3, kOrigin4));
+
+ // Release nonessential memory.
+ db_->TrimMemory();
+
+ // Check that the database is still intact.
+ origins.clear();
+ for (const auto& info : db_->FetchOrigins())
+ origins.push_back(info->origin);
+ EXPECT_THAT(origins, ElementsAre(kOrigin3, kOrigin4));
+
+ EXPECT_EQ(1L, db_->Length(kOrigin3));
+ EXPECT_EQ(2L, db_->Length(kOrigin4));
+
+ EXPECT_EQ(db_->Get(kOrigin3, u"key1").data, u"value1");
+ EXPECT_EQ(db_->Get(kOrigin4, u"key1").data, u"value1");
+ EXPECT_EQ(db_->Get(kOrigin4, u"key2").data, u"value2");
+}
+
+TEST_P(SharedStorageDatabaseParamTest, MaxEntriesPerOrigin) {
+ const url::Origin kOrigin1 =
+ url::Origin::Create(GURL("http://www.example1.test"));
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin1, u"key1", u"value1"));
+ EXPECT_EQ(1L, db_->Length(kOrigin1));
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin1, u"key2", u"value2"));
+ EXPECT_EQ(2L, db_->Length(kOrigin1));
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin1, u"key3", u"value3"));
+ EXPECT_EQ(3L, db_->Length(kOrigin1));
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin1, u"key4", u"value4"));
+ EXPECT_EQ(4L, db_->Length(kOrigin1));
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin1, u"key5", u"value5"));
+ EXPECT_EQ(5L, db_->Length(kOrigin1));
+
+ // `kOrigin1` should have hit capacity, and hence this value will not be set.
+ EXPECT_EQ(OperationResult::kNoCapacity,
+ db_->Set(kOrigin1, u"key6", u"value6"));
+
+ EXPECT_EQ(5L, db_->Length(kOrigin1));
+ EXPECT_EQ(OperationResult::kSuccess, db_->Delete(kOrigin1, u"key5"));
+ EXPECT_EQ(4L, db_->Length(kOrigin1));
+
+ // There should now be capacity and the value will be set.
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin1, u"key6", u"value6"));
+ EXPECT_EQ(5L, db_->Length(kOrigin1));
+}
+
+TEST_P(SharedStorageDatabaseParamTest, MaxStringLength) {
+ const url::Origin kOrigin1 =
+ url::Origin::Create(GURL("http://www.example1.test"));
+ const std::u16string kLongString(kMaxStringLength, u'g');
+
+ // This value has the maximum allowed length.
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin1, u"key1", kLongString));
+ EXPECT_EQ(1L, db_->Length(kOrigin1));
+
+ // Appending to the value would exceed the allowed length and so won't
+ // succeed.
+ EXPECT_EQ(OperationResult::kInvalidAppend,
+ db_->Append(kOrigin1, u"key1", u"h"));
+
+ EXPECT_EQ(1L, db_->Length(kOrigin1));
+
+ // This key has the maximum allowed length.
+ EXPECT_EQ(OperationResult::kSet, db_->Set(kOrigin1, kLongString, u"value1"));
+ EXPECT_EQ(2L, db_->Length(kOrigin1));
+}
+
+} // namespace storage
diff --git a/chromium/components/services/storage/shared_storage/shared_storage_options.cc b/chromium/components/services/storage/shared_storage/shared_storage_options.cc
new file mode 100644
index 00000000000..fcbb0343a98
--- /dev/null
+++ b/chromium/components/services/storage/shared_storage/shared_storage_options.cc
@@ -0,0 +1,80 @@
+// Copyright 2021 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.
+
+#include "components/services/storage/shared_storage/shared_storage_options.h"
+
+#include "base/bits.h"
+#include "third_party/blink/public/common/features.h"
+
+namespace storage {
+
+namespace {
+
+bool IsValidPageSize(int page_size) {
+ if (page_size < 512 || page_size > 65536)
+ return false;
+ return base::bits::IsPowerOfTwo(page_size);
+}
+
+} // namespace
+
+// static
+std::unique_ptr<SharedStorageOptions> SharedStorageOptions::Create() {
+ return std::make_unique<SharedStorageOptions>(
+ blink::features::kMaxSharedStoragePageSize.Get(),
+ blink::features::kMaxSharedStorageCacheSize.Get(),
+ blink::features::kMaxSharedStorageEntriesPerOrigin.Get(),
+ blink::features::kMaxSharedStorageStringLength.Get(),
+ blink::features::kMaxSharedStorageInitTries.Get(),
+ blink::features::kMaxSharedStorageConsecutiveOperationErrorsAllowed.Get(),
+ blink::features::kSharedStorageStaleOriginPurgeInitialInterval.Get(),
+ blink::features::kSharedStorageStaleOriginPurgeRecurringInterval.Get(),
+ blink::features::kSharedStorageOriginStalenessThreshold.Get());
+}
+
+SharedStorageOptions::SharedStorageOptions(
+ int max_page_size,
+ int max_cache_size,
+ int max_entries_per_origin,
+ int max_string_length,
+ int max_init_tries,
+ int max_allowed_consecutive_errors,
+ base::TimeDelta stale_origin_purge_initial_interval,
+ base::TimeDelta stale_origin_purge_recurring_interval,
+ base::TimeDelta origin_staleness_threshold)
+ : max_page_size(max_page_size),
+ max_cache_size(max_cache_size),
+ max_entries_per_origin(max_entries_per_origin),
+ max_string_length(max_string_length),
+ max_init_tries(max_init_tries),
+ max_allowed_consecutive_errors(max_allowed_consecutive_errors),
+ stale_origin_purge_initial_interval(stale_origin_purge_initial_interval),
+ stale_origin_purge_recurring_interval(
+ stale_origin_purge_recurring_interval),
+ origin_staleness_threshold(origin_staleness_threshold) {
+ DCHECK(IsValidPageSize(max_page_size));
+}
+
+std::unique_ptr<SharedStorageDatabaseOptions>
+SharedStorageOptions::GetDatabaseOptions() {
+ return std::make_unique<SharedStorageDatabaseOptions>(
+ max_page_size, max_cache_size, max_entries_per_origin, max_string_length,
+ max_init_tries);
+}
+
+SharedStorageDatabaseOptions::SharedStorageDatabaseOptions(
+ int max_page_size,
+ int max_cache_size,
+ int max_entries_per_origin,
+ int max_string_length,
+ int max_init_tries)
+ : max_page_size(max_page_size),
+ max_cache_size(max_cache_size),
+ max_entries_per_origin(max_entries_per_origin),
+ max_string_length(max_string_length),
+ max_init_tries(max_init_tries) {
+ DCHECK(IsValidPageSize(max_page_size));
+}
+
+} // namespace storage
diff --git a/chromium/components/services/storage/shared_storage/shared_storage_options.h b/chromium/components/services/storage/shared_storage/shared_storage_options.h
new file mode 100644
index 00000000000..751662e24a2
--- /dev/null
+++ b/chromium/components/services/storage/shared_storage/shared_storage_options.h
@@ -0,0 +1,104 @@
+// Copyright 2021 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.
+
+#ifndef COMPONENTS_SERVICES_STORAGE_SHARED_STORAGE_SHARED_STORAGE_OPTIONS_H_
+#define COMPONENTS_SERVICES_STORAGE_SHARED_STORAGE_SHARED_STORAGE_OPTIONS_H_
+
+#include <memory>
+
+#include "base/time/time.h"
+
+namespace storage {
+
+struct SharedStorageDatabaseOptions;
+
+// Bundles Finch-configurable constants for the `SharedStorageManager`,
+// `AsyncSharedStorageDatabase`, and `SharedStorageDatabase` classes.
+struct SharedStorageOptions {
+ // The static `Create()` method accesses field trial params to populate one or
+ // more attributes, and so must be called on the main thread.
+ static std::unique_ptr<SharedStorageOptions> Create();
+
+ SharedStorageOptions(int max_page_size,
+ int max_cache_size,
+ int max_entries_per_origin,
+ int max_string_length,
+ int max_init_tries,
+ int max_allowed_consecutive_errors,
+ base::TimeDelta stale_origin_purge_initial_interval,
+ base::TimeDelta stale_origin_purge_recurring_interval,
+ base::TimeDelta origin_staleness_threshold);
+
+ // Creates a pointer to a smaller bundle of just the constants that need to
+ // be forwarded to `AsyncSharedStorageDatabase` and `SharedStorageDatabase`.
+ std::unique_ptr<SharedStorageDatabaseOptions> GetDatabaseOptions();
+
+ // The max size of a database page, in bytes. Must be a power of 2 between
+ // 512 and 65536 inclusive.
+ const int max_page_size;
+
+ // The max size of the database cache, in pages.
+ const int max_cache_size;
+
+ // The maximum number of entries allowed per origin.
+ const int max_entries_per_origin;
+
+ // The maximum allowed string length for each script key or script value.
+ const int max_string_length;
+
+ // The maximum number of times that `SharedStorageDatabase` will try to
+ // initialize the SQL database.
+ const int max_init_tries;
+
+ // Maximum number of consecutive operation errors allowed before the database
+ // is deleted and recreated.
+ const int max_allowed_consecutive_errors;
+
+ // The initial interval at which stale origins are purged.
+ const base::TimeDelta stale_origin_purge_initial_interval;
+
+ // The recurring interval at which stale origins are purged. May differ from
+ // the initial interval.
+ const base::TimeDelta stale_origin_purge_recurring_interval;
+
+ // The amount of time that an origin needs to be inactive in order for it to
+ // be deemed stale.
+ const base::TimeDelta origin_staleness_threshold;
+};
+
+// Bundles Finch-configurable constants for the `AsyncSharedStorageDatabase`
+// and `SharedStorageDatabase` classes. This smaller class is separate from the
+// larger `SharedStorageOptions` (which has the ability to create an instance of
+// `SharedStorageDatabaseOptions` from a subset of its members) so that the
+// smaller `SharedStorageDatabaseOptions` bundle can be read on an alternate
+// thread while the larger class's bundle can continue to be accessed on the
+// main thread.
+struct SharedStorageDatabaseOptions {
+ SharedStorageDatabaseOptions(int max_page_size,
+ int max_cache_size,
+ int max_entries_per_origin,
+ int max_string_length,
+ int max_init_tries);
+
+ // The max size of a database page, in bytes. Must be a power of 2 between
+ // 512 and 65536 inclusive.
+ const int max_page_size;
+
+ // The max size of the database cache, in pages.
+ const int max_cache_size;
+
+ // The maximum number of entries allowed per origin.
+ const int max_entries_per_origin;
+
+ // The maximum allowed string length for each script key or script value.
+ const int max_string_length;
+
+ // The maximum number of times that `SharedStorageDatabase` will try to
+ // initialize the SQL database.
+ const int max_init_tries;
+};
+
+} // namespace storage
+
+#endif // COMPONENTS_SERVICES_STORAGE_SHARED_STORAGE_SHARED_STORAGE_OPTIONS_H_
diff --git a/chromium/components/services/storage/shared_storage/shared_storage_test_utils.cc b/chromium/components/services/storage/shared_storage/shared_storage_test_utils.cc
new file mode 100644
index 00000000000..2c13bbf283a
--- /dev/null
+++ b/chromium/components/services/storage/shared_storage/shared_storage_test_utils.cc
@@ -0,0 +1,369 @@
+// Copyright 2021 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.
+
+#include "components/services/storage/shared_storage/shared_storage_test_utils.h"
+
+#include <queue>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/containers/contains.h"
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+#include "base/strings/strcat.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/services/storage/public/mojom/storage_usage_info.mojom.h"
+#include "sql/database.h"
+#include "sql/test/test_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace storage {
+
+TestDatabaseOperationReceiver::DBOperation::DBOperation(Type type)
+ : type(type) {
+ DCHECK(type == Type::DB_IS_OPEN || type == Type::DB_STATUS ||
+ type == Type::DB_DESTROY || type == Type::DB_TRIM_MEMORY ||
+ type == Type::DB_FETCH_ORIGINS);
+}
+
+TestDatabaseOperationReceiver::DBOperation::DBOperation(Type type,
+ url::Origin origin)
+ : type(type), origin(std::move(origin)) {
+ DCHECK(type == Type::DB_LENGTH || type == Type::DB_CLEAR);
+}
+
+TestDatabaseOperationReceiver::DBOperation::DBOperation(
+ Type type,
+ url::Origin origin,
+ std::vector<std::u16string> params)
+ : type(type), origin(std::move(origin)), params(std::move(params)) {
+ DCHECK(type == Type::DB_GET || type == Type::DB_SET ||
+ type == Type::DB_APPEND || type == Type::DB_DELETE ||
+ type == Type::DB_KEY || type == Type::DB_OVERRIDE_TIME);
+}
+
+TestDatabaseOperationReceiver::DBOperation::DBOperation(
+ Type type,
+ std::vector<std::u16string> params)
+ : type(type), params(std::move(params)) {
+ DCHECK(type == Type::DB_PURGE_MATCHING || type == Type::DB_PURGE_STALE);
+}
+
+TestDatabaseOperationReceiver::DBOperation::~DBOperation() = default;
+
+TestDatabaseOperationReceiver::DBOperation::DBOperation(const DBOperation&) =
+ default;
+
+bool TestDatabaseOperationReceiver::DBOperation::operator==(
+ const DBOperation& operation) const {
+ if (type != operation.type || params != operation.params)
+ return false;
+
+ if (origin.opaque() && operation.origin.opaque())
+ return true;
+
+ return origin == operation.origin;
+}
+
+bool TestDatabaseOperationReceiver::DBOperation::operator!=(
+ const DBOperation& operation) const {
+ if (type != operation.type || params != operation.params)
+ return true;
+
+ if (origin.opaque() && operation.origin.opaque())
+ return false;
+
+ return origin != operation.origin;
+}
+
+std::string TestDatabaseOperationReceiver::DBOperation::Serialize() const {
+ std::string serialization(
+ base::StrCat({"type: ", base::NumberToString(static_cast<int>(type)),
+ "; origin: ", origin.Serialize(), "; params: {"}));
+ for (int i = 0; i < static_cast<int>(params.size()) - 1; i++) {
+ serialization =
+ base::StrCat({serialization, base::UTF16ToUTF8(params[i]), ","});
+ }
+ serialization = params.empty()
+ ? base::StrCat({serialization, "}"})
+ : base::StrCat({serialization,
+ base::UTF16ToUTF8(params.back()), "}"});
+ return serialization;
+}
+
+TestDatabaseOperationReceiver::TestDatabaseOperationReceiver() = default;
+
+TestDatabaseOperationReceiver::~TestDatabaseOperationReceiver() = default;
+
+// static
+std::u16string TestDatabaseOperationReceiver::SerializeTime(base::Time time) {
+ return SerializeTimeDelta(time.ToDeltaSinceWindowsEpoch());
+}
+
+// static
+
+std::u16string TestDatabaseOperationReceiver::SerializeTimeDelta(
+ base::TimeDelta delta) {
+ return base::StrCat({base::NumberToString16(delta.InMicroseconds()), u"us"});
+}
+
+// static
+std::u16string TestDatabaseOperationReceiver::SerializeBool(bool b) {
+ return b ? u"true" : u"false";
+}
+
+// static
+std::u16string TestDatabaseOperationReceiver::SerializeSetBehavior(
+ SetBehavior behavior) {
+ return base::NumberToString16(static_cast<int>(behavior));
+}
+
+void TestDatabaseOperationReceiver::WaitForOperations() {
+ finished_ = false;
+ loop_.Run();
+ if (expected_operations_.empty())
+ Finish();
+}
+
+void TestDatabaseOperationReceiver::GetResultCallbackBase(
+ const DBOperation& current_operation,
+ GetResult* out_result,
+ GetResult result) {
+ DCHECK(out_result);
+ *out_result = std::move(result);
+
+ if (ExpectationsMet(current_operation) && loop_.running())
+ Finish();
+}
+
+base::OnceCallback<void(GetResult)>
+TestDatabaseOperationReceiver::MakeGetResultCallback(
+ const DBOperation& current_operation,
+ GetResult* out_result) {
+ return base::BindOnce(&TestDatabaseOperationReceiver::GetResultCallbackBase,
+ base::Unretained(this), current_operation, out_result);
+}
+
+void TestDatabaseOperationReceiver::OperationResultCallbackBase(
+ const DBOperation& current_operation,
+ OperationResult* out_result,
+ OperationResult result) {
+ DCHECK(out_result);
+ *out_result = result;
+
+ if (ExpectationsMet(current_operation) && loop_.running())
+ Finish();
+}
+
+base::OnceCallback<void(OperationResult)>
+TestDatabaseOperationReceiver::MakeOperationResultCallback(
+ const DBOperation& current_operation,
+ OperationResult* out_result) {
+ return base::BindOnce(
+ &TestDatabaseOperationReceiver::OperationResultCallbackBase,
+ base::Unretained(this), current_operation, out_result);
+}
+
+void TestDatabaseOperationReceiver::IntCallbackBase(
+ const DBOperation& current_operation,
+ int* out_length,
+ int length) {
+ DCHECK(out_length);
+ *out_length = length;
+
+ if (ExpectationsMet(current_operation) && loop_.running())
+ Finish();
+}
+
+base::OnceCallback<void(int)> TestDatabaseOperationReceiver::MakeIntCallback(
+ const DBOperation& current_operation,
+ int* out_length) {
+ return base::BindOnce(&TestDatabaseOperationReceiver::IntCallbackBase,
+ base::Unretained(this), current_operation, out_length);
+}
+
+void TestDatabaseOperationReceiver::BoolCallbackBase(
+ const DBOperation& current_operation,
+ bool* out_boolean,
+ bool boolean) {
+ DCHECK(out_boolean);
+ *out_boolean = boolean;
+
+ if (ExpectationsMet(current_operation) && loop_.running())
+ Finish();
+}
+
+base::OnceCallback<void(bool)> TestDatabaseOperationReceiver::MakeBoolCallback(
+ const DBOperation& current_operation,
+ bool* out_boolean) {
+ return base::BindOnce(&TestDatabaseOperationReceiver::BoolCallbackBase,
+ base::Unretained(this), current_operation, out_boolean);
+}
+
+void TestDatabaseOperationReceiver::StatusCallbackBase(
+ const DBOperation& current_operation,
+ InitStatus* out_status,
+ InitStatus status) {
+ DCHECK(out_status);
+ *out_status = status;
+
+ if (ExpectationsMet(current_operation) && loop_.running())
+ Finish();
+}
+
+base::OnceCallback<void(InitStatus)>
+TestDatabaseOperationReceiver::MakeStatusCallback(
+ const DBOperation& current_operation,
+ InitStatus* out_status) {
+ return base::BindOnce(&TestDatabaseOperationReceiver::StatusCallbackBase,
+ base::Unretained(this), current_operation, out_status);
+}
+
+void TestDatabaseOperationReceiver::InfosCallbackBase(
+ const DBOperation& current_operation,
+ std::vector<mojom::StorageUsageInfoPtr>* out_infos,
+ std::vector<mojom::StorageUsageInfoPtr> infos) {
+ DCHECK(out_infos);
+ *out_infos = std::move(infos);
+
+ if (ExpectationsMet(current_operation) && loop_.running())
+ Finish();
+}
+
+base::OnceCallback<void(std::vector<mojom::StorageUsageInfoPtr>)>
+TestDatabaseOperationReceiver::MakeInfosCallback(
+ const DBOperation& current_operation,
+ std::vector<mojom::StorageUsageInfoPtr>* out_infos) {
+ return base::BindOnce(&TestDatabaseOperationReceiver::InfosCallbackBase,
+ base::Unretained(this), current_operation, out_infos);
+}
+
+void TestDatabaseOperationReceiver::OnceClosureBase(
+ const DBOperation& current_operation) {
+ if (ExpectationsMet(current_operation) && loop_.running())
+ Finish();
+}
+
+base::OnceClosure TestDatabaseOperationReceiver::MakeOnceClosure(
+ const DBOperation& current_operation) {
+ return base::BindOnce(&TestDatabaseOperationReceiver::OnceClosureBase,
+ base::Unretained(this), current_operation);
+}
+
+bool TestDatabaseOperationReceiver::ExpectationsMet(
+ const DBOperation& current_operation) {
+ EXPECT_FALSE(expected_operations_.empty());
+
+ if (expected_operations_.empty())
+ return false;
+
+ EXPECT_EQ(expected_operations_.front(), current_operation)
+ << "expected operation: " << expected_operations_.front().Serialize()
+ << std::endl
+ << "actual operation: " << current_operation.Serialize() << std::endl;
+
+ if (expected_operations_.front() != current_operation) {
+ return false;
+ } else {
+ expected_operations_.pop();
+ return expected_operations_.empty();
+ }
+}
+
+void TestDatabaseOperationReceiver::Finish() {
+ finished_ = true;
+ loop_.Quit();
+}
+
+OriginMatcherFunctionUtility::OriginMatcherFunctionUtility() = default;
+OriginMatcherFunctionUtility::~OriginMatcherFunctionUtility() = default;
+
+OriginMatcherFunction OriginMatcherFunctionUtility::MakeMatcherFunction(
+ std::vector<url::Origin> origins_to_match) {
+ return base::BindRepeating(
+ [](std::vector<url::Origin> origins_to_match, const url::Origin& origin,
+ SpecialStoragePolicy* policy) {
+ return base::Contains(origins_to_match, origin);
+ },
+ origins_to_match);
+}
+
+OriginMatcherFunction OriginMatcherFunctionUtility::MakeMatcherFunction(
+ std::vector<std::string> origin_strs_to_match) {
+ std::vector<url::Origin> origins_to_match;
+ for (const auto& str : origin_strs_to_match)
+ origins_to_match.push_back(url::Origin::Create(GURL(str)));
+ return MakeMatcherFunction(origins_to_match);
+}
+
+size_t OriginMatcherFunctionUtility::RegisterMatcherFunction(
+ std::vector<url::Origin> origins_to_match) {
+ matcher_table_.emplace_back(MakeMatcherFunction(origins_to_match));
+ return matcher_table_.size() - 1;
+}
+
+OriginMatcherFunction OriginMatcherFunctionUtility::TakeMatcherFunctionForId(
+ size_t id) {
+ DCHECK_LT(id, matcher_table_.size());
+ return std::move(matcher_table_[id]);
+}
+
+std::vector<SharedStorageWrappedBool> GetSharedStorageWrappedBools() {
+ return std::vector<SharedStorageWrappedBool>({{true}, {false}});
+}
+
+std::string PrintToString(const SharedStorageWrappedBool& b) {
+ return b.in_memory_only ? "InMemoryOnly" : "FileBacked";
+}
+
+std::vector<PurgeMatchingOriginsParams> GetPurgeMatchingOriginsParams() {
+ return std::vector<PurgeMatchingOriginsParams>(
+ {{true, true}, {true, false}, {false, true}, {false, false}});
+}
+
+std::string PrintToString(const PurgeMatchingOriginsParams& p) {
+ return base::StrCat({(p.in_memory_only ? "InMemoryOnly" : "FileBacked"),
+ "_With", (p.perform_storage_cleanup ? "" : "out"),
+ "Cleanup"});
+}
+
+void VerifySharedStorageTablesAndColumns(sql::Database& db) {
+ // `meta`, `values_mapping`, and `per_origin_mapping`.
+ EXPECT_EQ(3u, sql::test::CountSQLTables(&db));
+
+ // Implicit index on `meta` and `per_origin_mapping_last_used_time_idx`.
+ EXPECT_EQ(2u, sql::test::CountSQLIndices(&db));
+
+ // `key` and `value`.
+ EXPECT_EQ(2u, sql::test::CountTableColumns(&db, "meta"));
+
+ // `context_origin`, `script_key`, and `script_value`.
+ EXPECT_EQ(3u, sql::test::CountTableColumns(&db, "values_mapping"));
+
+ // `context_origin`, `last_used_time`, and `length`.
+ EXPECT_EQ(3u, sql::test::CountTableColumns(&db, "per_origin_mapping"));
+}
+
+bool GetTestDataSharedStorageDir(base::FilePath* dir) {
+ if (!base::PathService::Get(base::DIR_SOURCE_ROOT, dir))
+ return false;
+ *dir = dir->AppendASCII("components");
+ *dir = dir->AppendASCII("test");
+ *dir = dir->AppendASCII("data");
+ *dir = dir->AppendASCII("storage");
+ return true;
+}
+
+bool CreateDatabaseFromSQL(const base::FilePath& db_path,
+ const char* ascii_path) {
+ base::FilePath dir;
+ if (!GetTestDataSharedStorageDir(&dir))
+ return false;
+ return sql::test::CreateDatabaseFromSQL(db_path, dir.AppendASCII(ascii_path));
+}
+
+} // namespace storage
diff --git a/chromium/components/services/storage/shared_storage/shared_storage_test_utils.h b/chromium/components/services/storage/shared_storage/shared_storage_test_utils.h
new file mode 100644
index 00000000000..b518d06321f
--- /dev/null
+++ b/chromium/components/services/storage/shared_storage/shared_storage_test_utils.h
@@ -0,0 +1,210 @@
+// Copyright 2021 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.
+
+#ifndef COMPONENTS_SERVICES_STORAGE_SHARED_STORAGE_SHARED_STORAGE_TEST_UTILS_H_
+#define COMPONENTS_SERVICES_STORAGE_SHARED_STORAGE_SHARED_STORAGE_TEST_UTILS_H_
+
+#include <queue>
+#include <string>
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "components/services/storage/public/mojom/storage_usage_info.mojom-forward.h"
+#include "components/services/storage/shared_storage/shared_storage_database.h"
+#include "url/origin.h"
+
+namespace base {
+class FilePath;
+} // namespace base
+
+namespace sql {
+class Database;
+} // namespace sql
+
+namespace storage {
+
+using OriginMatcherFunction = SharedStorageDatabase::OriginMatcherFunction;
+using InitStatus = SharedStorageDatabase::InitStatus;
+using SetBehavior = SharedStorageDatabase::SetBehavior;
+using OperationResult = SharedStorageDatabase::OperationResult;
+using GetResult = SharedStorageDatabase::GetResult;
+
+// Helper class for testing async operations, accessible here for unit tests
+// of both `AsyncSharedStorageDatabase` and `SharedStorageManager`.
+class TestDatabaseOperationReceiver {
+ public:
+ struct DBOperation {
+ enum class Type {
+ DB_DESTROY = 0,
+ DB_TRIM_MEMORY = 1,
+ DB_GET = 2,
+ DB_SET = 3,
+ DB_APPEND = 4,
+ DB_DELETE = 5,
+ DB_CLEAR = 6,
+ DB_LENGTH = 7,
+ DB_KEY = 8,
+ DB_PURGE_MATCHING = 9,
+ DB_PURGE_STALE = 10,
+ DB_FETCH_ORIGINS = 11,
+ DB_IS_OPEN = 12,
+ DB_STATUS = 13,
+ DB_OVERRIDE_TIME = 14,
+ } type;
+ url::Origin origin;
+ std::vector<std::u16string> params;
+ explicit DBOperation(Type type);
+ DBOperation(Type type, url::Origin origin);
+ DBOperation(Type type,
+ url::Origin origin,
+ std::vector<std::u16string> params);
+ DBOperation(Type type, std::vector<std::u16string> params);
+ DBOperation(const DBOperation&);
+ ~DBOperation();
+ bool operator==(const DBOperation& operation) const;
+ bool operator!=(const DBOperation& operation) const;
+ std::string Serialize() const;
+ };
+
+ TestDatabaseOperationReceiver();
+
+ ~TestDatabaseOperationReceiver();
+
+ // For serializing parameters to insert into `params` when creating a
+ // `DBOperation` struct.
+ static std::u16string SerializeTime(base::Time time);
+ static std::u16string SerializeTimeDelta(base::TimeDelta delta);
+ static std::u16string SerializeBool(bool b);
+ static std::u16string SerializeSetBehavior(SetBehavior behavior);
+
+ bool is_finished() const { return finished_; }
+
+ void set_expected_operations(std::queue<DBOperation> expected_operations) {
+ expected_operations_ = std::move(expected_operations);
+ }
+
+ void WaitForOperations();
+
+ void GetResultCallbackBase(const DBOperation& current_operation,
+ GetResult* out_result,
+ GetResult result);
+ base::OnceCallback<void(GetResult)> MakeGetResultCallback(
+ const DBOperation& current_operation,
+ GetResult* out_result);
+
+ void OperationResultCallbackBase(const DBOperation& current_operation,
+ OperationResult* out_result,
+ OperationResult result);
+ base::OnceCallback<void(OperationResult)> MakeOperationResultCallback(
+ const DBOperation& current_operation,
+ OperationResult* out_result);
+
+ void IntCallbackBase(const DBOperation& current_operation,
+ int* out_length,
+ int length);
+ base::OnceCallback<void(int)> MakeIntCallback(
+ const DBOperation& current_operation,
+ int* out_length);
+
+ void BoolCallbackBase(const DBOperation& current_operation,
+ bool* out_boolean,
+ bool boolean);
+ base::OnceCallback<void(bool)> MakeBoolCallback(
+ const DBOperation& current_operation,
+ bool* out_boolean);
+
+ void StatusCallbackBase(const DBOperation& current_operation,
+ InitStatus* out_status,
+ InitStatus status);
+ base::OnceCallback<void(InitStatus)> MakeStatusCallback(
+ const DBOperation& current_operation,
+ InitStatus* out_status);
+
+ void InfosCallbackBase(const DBOperation& current_operation,
+ std::vector<mojom::StorageUsageInfoPtr>* out_infos,
+ std::vector<mojom::StorageUsageInfoPtr> infos);
+ base::OnceCallback<void(std::vector<mojom::StorageUsageInfoPtr>)>
+ MakeInfosCallback(const DBOperation& current_operation,
+ std::vector<mojom::StorageUsageInfoPtr>* out_infos);
+
+ void OnceClosureBase(const DBOperation& current_operation);
+ base::OnceClosure MakeOnceClosure(const DBOperation& current_operation);
+
+ private:
+ bool ExpectationsMet(const DBOperation& current_operation);
+ void Finish();
+
+ base::RunLoop loop_;
+ bool finished_ = true;
+ std::queue<DBOperation> expected_operations_;
+};
+
+class OriginMatcherFunctionUtility {
+ public:
+ OriginMatcherFunctionUtility();
+ ~OriginMatcherFunctionUtility();
+
+ [[nodiscard]] static OriginMatcherFunction MakeMatcherFunction(
+ std::vector<url::Origin> origins_to_match);
+
+ [[nodiscard]] static OriginMatcherFunction MakeMatcherFunction(
+ std::vector<std::string> origin_strs_to_match);
+
+ [[nodiscard]] size_t RegisterMatcherFunction(
+ std::vector<url::Origin> origins_to_match);
+
+ [[nodiscard]] OriginMatcherFunction TakeMatcherFunctionForId(size_t id);
+
+ [[nodiscard]] bool is_empty() const { return matcher_table_.empty(); }
+
+ [[nodiscard]] size_t size() const { return matcher_table_.size(); }
+
+ private:
+ std::vector<OriginMatcherFunction> matcher_table_;
+};
+
+// Wraps a bool indicating if the database is in memory only,
+// for the purpose of customizing a `PrintToString()` method below, which will
+// be used in the parameterized test names via
+// `testing::PrintToStringParamName()`.
+struct SharedStorageWrappedBool {
+ bool in_memory_only;
+};
+
+// Wraps bools indicating if the database is in memory only and if storage
+// cleanup should be performed after purging, for the purpose of customizing a
+// `PrintToString()` method below, which will be used in the parameterized test
+// names via `testing::PrintToStringParamName()`.
+struct PurgeMatchingOriginsParams {
+ bool in_memory_only;
+ bool perform_storage_cleanup;
+};
+
+[[nodiscard]] std::vector<SharedStorageWrappedBool>
+GetSharedStorageWrappedBools();
+
+// Used by `testing::PrintToStringParamName()`.
+[[nodiscard]] std::string PrintToString(const SharedStorageWrappedBool& b);
+
+[[nodiscard]] std::vector<PurgeMatchingOriginsParams>
+GetPurgeMatchingOriginsParams();
+
+// Used by testing::PrintToStringParamName().
+[[nodiscard]] std::string PrintToString(const PurgeMatchingOriginsParams& p);
+
+// Verify that the up-to-date SQL Shared Storage database has the expected
+// tables and columns. Functional tests only check whether the things which
+// should be there are, but do not check if extraneous items are
+// present. Any extraneous items have the potential to interact
+// negatively with future schema changes.
+void VerifySharedStorageTablesAndColumns(sql::Database& db);
+
+[[nodiscard]] bool GetTestDataSharedStorageDir(base::FilePath* dir);
+
+[[nodiscard]] bool CreateDatabaseFromSQL(const base::FilePath& db_path,
+ const char* ascii_path);
+
+} // namespace storage
+
+#endif // COMPONENTS_SERVICES_STORAGE_SHARED_STORAGE_SHARED_STORAGE_TEST_UTILS_H_
diff --git a/chromium/components/services/storage/storage_service_impl.cc b/chromium/components/services/storage/storage_service_impl.cc
index d119afafeb4..d848fb3c480 100644
--- a/chromium/components/services/storage/storage_service_impl.cc
+++ b/chromium/components/services/storage/storage_service_impl.cc
@@ -25,7 +25,7 @@ namespace {
// We don't use out-of-process Storage Service on Android, so we can avoid
// pulling all the related code (including Directory mojom) into the build.
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
// The name under which we register our own sandboxed VFS instance when running
// out-of-process.
constexpr char kVfsName[] = "storage_service";
@@ -61,7 +61,7 @@ void StorageServiceImpl::EnableAggressiveDomStorageFlushing() {
StorageAreaImpl::EnableAggressiveCommitDelay();
}
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
void StorageServiceImpl::SetDataDirectory(
const base::FilePath& path,
mojo::PendingRemote<mojom::Directory> directory) {
@@ -91,7 +91,7 @@ void StorageServiceImpl::SetDataDirectory(
kVfsName, std::make_unique<SandboxedVfsDelegate>(CreateFilesystemProxy()),
/*make_default=*/true);
}
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
void StorageServiceImpl::BindPartition(
const absl::optional<base::FilePath>& path,
@@ -132,7 +132,7 @@ void StorageServiceImpl::RemovePartition(PartitionImpl* partition) {
partitions_.erase(iter);
}
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
void StorageServiceImpl::BindDataDirectoryReceiver(
mojo::PendingReceiver<mojom::Directory> receiver) {
DCHECK(remote_data_directory_.is_bound());
diff --git a/chromium/components/services/storage/storage_service_impl.h b/chromium/components/services/storage/storage_service_impl.h
index 76838adc62c..e02fc94c2f8 100644
--- a/chromium/components/services/storage/storage_service_impl.h
+++ b/chromium/components/services/storage/storage_service_impl.h
@@ -45,7 +45,7 @@ class StorageServiceImpl : public mojom::StorageService {
// mojom::StorageService implementation:
void EnableAggressiveDomStorageFlushing() override;
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
void SetDataDirectory(
const base::FilePath& path,
mojo::PendingRemote<mojom::Directory> directory) override;
@@ -60,7 +60,7 @@ class StorageServiceImpl : public mojom::StorageService {
// Removes a partition from the set of tracked partitions.
void RemovePartition(PartitionImpl* partition);
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
// Binds a Directory receiver to the same remote implementation to which
// |remote_data_directory_| is bound. It is invalid to call this when
// |remote_data_directory_| is unbound.
@@ -71,7 +71,7 @@ class StorageServiceImpl : public mojom::StorageService {
const mojo::Receiver<mojom::StorageService> receiver_;
const scoped_refptr<base::SequencedTaskRunner> io_task_runner_;
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
// If bound, the service will assume it should not perform certain filesystem
// operations directly and will instead go through this interface.
base::FilePath remote_data_directory_path_;
diff --git a/chromium/components/services/unzip/BUILD.gn b/chromium/components/services/unzip/BUILD.gn
index d2648aecb43..a21e47cabef 100644
--- a/chromium/components/services/unzip/BUILD.gn
+++ b/chromium/components/services/unzip/BUILD.gn
@@ -11,6 +11,7 @@ source_set("lib") {
deps = [
"//base",
"//mojo/public/cpp/bindings",
+ "//third_party/ced",
"//third_party/zlib/google:zip",
]
@@ -45,6 +46,21 @@ bundle_data("unit_tests_bundle_data") {
visibility = [ ":unit_tests" ]
testonly = true
sources = [
+ "//components/test/data/unzip_service/SJIS 00.zip",
+ "//components/test/data/unzip_service/SJIS 01.zip",
+ "//components/test/data/unzip_service/SJIS 02.zip",
+ "//components/test/data/unzip_service/SJIS 03.zip",
+ "//components/test/data/unzip_service/SJIS 04.zip",
+ "//components/test/data/unzip_service/SJIS 05.zip",
+ "//components/test/data/unzip_service/SJIS 06.zip",
+ "//components/test/data/unzip_service/SJIS 07.zip",
+ "//components/test/data/unzip_service/SJIS 08.zip",
+ "//components/test/data/unzip_service/SJIS 09.zip",
+ "//components/test/data/unzip_service/SJIS 10.zip",
+ "//components/test/data/unzip_service/SJIS 11.zip",
+ "//components/test/data/unzip_service/SJIS 12.zip",
+ "//components/test/data/unzip_service/SJIS 13.zip",
+ "//components/test/data/unzip_service/UTF8 (Bug 903664).zip",
"//components/test/data/unzip_service/bad_archive.zip",
"//components/test/data/unzip_service/good_archive.zip",
]
diff --git a/chromium/components/services/unzip/DEPS b/chromium/components/services/unzip/DEPS
index c182c3ca877..c84c5757b14 100644
--- a/chromium/components/services/unzip/DEPS
+++ b/chromium/components/services/unzip/DEPS
@@ -1,5 +1,6 @@
include_rules = [
"+components/services/filesystem",
"+mojo/public",
+ "+third_party/ced",
"+third_party/zlib/google",
]
diff --git a/chromium/components/services/unzip/OWNERS b/chromium/components/services/unzip/OWNERS
index ec81839d0ad..76d860e1f41 100644
--- a/chromium/components/services/unzip/OWNERS
+++ b/chromium/components/services/unzip/OWNERS
@@ -1,2 +1,5 @@
+adanilo@chromium.org
+fdegros@chromium.org
+noel@chromium.org
sorin@chromium.org
waffles@chromium.org
diff --git a/chromium/components/services/unzip/public/cpp/unzip.cc b/chromium/components/services/unzip/public/cpp/unzip.cc
index b2b929ca7c1..d487f1f2393 100644
--- a/chromium/components/services/unzip/public/cpp/unzip.cc
+++ b/chromium/components/services/unzip/public/cpp/unzip.cc
@@ -11,12 +11,15 @@
#include "base/callback.h"
#include "base/files/file.h"
#include "base/files/file_path.h"
+#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_refptr.h"
+#include "base/metrics/histogram_functions.h"
#include "base/task/post_task.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/thread_pool.h"
#include "base/threading/sequenced_task_runner_handle.h"
+#include "base/time/time.h"
#include "components/services/filesystem/directory_impl.h"
#include "components/services/filesystem/lock_table.h"
#include "components/services/unzip/public/mojom/unzipper.mojom.h"
@@ -25,9 +28,12 @@
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
namespace unzip {
-
namespace {
+std::string Redact(const base::FilePath& path) {
+ return LOG_IS_ON(INFO) ? "'" + path.AsUTF8Unsafe() + "'" : "(redacted)";
+}
+
class UnzipFilter : public unzip::mojom::UnzipFilter {
public:
UnzipFilter(mojo::PendingReceiver<unzip::mojom::UnzipFilter> receiver,
@@ -72,6 +78,8 @@ class UnzipParams : public base::RefCounted<UnzipParams> {
callback_task_runner_->PostTask(
FROM_HERE, base::BindOnce(std::move(callback_), result));
}
+
+ unzipper_.reset();
}
void set_unzip_filter(std::unique_ptr<UnzipFilter> filter) {
@@ -94,12 +102,52 @@ class UnzipParams : public base::RefCounted<UnzipParams> {
scoped_refptr<base::SequencedTaskRunner> background_task_runner_keep_alive_;
};
-void UnzipDone(scoped_refptr<UnzipParams> params, bool success) {
- params->InvokeCallback(success);
- params->unzipper().reset();
-}
+class DetectEncodingParams : public base::RefCounted<DetectEncodingParams> {
+ public:
+ DetectEncodingParams(
+ mojo::PendingRemote<mojom::Unzipper> unzipper,
+ DetectEncodingCallback callback,
+ scoped_refptr<base::SequencedTaskRunner> callback_task_runner,
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner)
+ : unzipper_(std::move(unzipper)),
+ callback_(std::move(callback)),
+ callback_task_runner_(std::move(callback_task_runner)),
+ background_task_runner_(std::move(background_task_runner)) {}
+
+ DetectEncodingParams(const DetectEncodingParams&) = delete;
+ DetectEncodingParams& operator=(const DetectEncodingParams&) = delete;
+
+ mojo::Remote<mojom::Unzipper>& unzipper() { return unzipper_; }
+
+ void InvokeCallback(int encoding) {
+ if (callback_) {
+ base::UmaHistogramEnumeration("Unzipper.DetectEncoding.Result",
+ static_cast<Encoding>(encoding),
+ Encoding::NUM_ENCODINGS);
+ base::UmaHistogramTimes("Unzipper.DetectEncoding.Time",
+ base::TimeTicks::Now() - start_time_);
+ callback_task_runner_->PostTask(
+ FROM_HERE, base::BindOnce(std::move(callback_),
+ static_cast<Encoding>(encoding)));
+ }
+
+ unzipper_.reset();
+ }
+
+ private:
+ friend class base::RefCounted<DetectEncodingParams>;
+
+ ~DetectEncodingParams() = default;
+
+ // The Remote is stored so it does not get deleted before the callback runs.
+ mojo::Remote<mojom::Unzipper> unzipper_;
+ DetectEncodingCallback callback_;
+ scoped_refptr<base::SequencedTaskRunner> callback_task_runner_;
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner_;
+ const base::TimeTicks start_time_ = base::TimeTicks::Now();
+};
-void DoUnzipWithFilter(
+void DoUnzip(
mojo::PendingRemote<mojom::Unzipper> unzipper,
const base::FilePath& zip_path,
const base::FilePath& output_dir,
@@ -129,22 +177,50 @@ void DoUnzipWithFilter(
background_task_runner_keep_alive);
unzip_params->unzipper().set_disconnect_handler(
- base::BindOnce(&UnzipDone, unzip_params, false));
-
- if (filter_callback.is_null()) {
- unzip_params->unzipper()->Unzip(std::move(zip_file),
- std::move(directory_remote),
- base::BindOnce(&UnzipDone, unzip_params));
- return;
- }
+ base::BindOnce(&UnzipParams::InvokeCallback, unzip_params, false));
mojo::PendingRemote<unzip::mojom::UnzipFilter> unzip_filter_remote;
- unzip_params->set_unzip_filter(std::make_unique<UnzipFilter>(
- unzip_filter_remote.InitWithNewPipeAndPassReceiver(), filter_callback));
+ if (filter_callback) {
+ unzip_params->set_unzip_filter(std::make_unique<UnzipFilter>(
+ unzip_filter_remote.InitWithNewPipeAndPassReceiver(),
+ std::move(filter_callback)));
+ }
- unzip_params->unzipper()->UnzipWithFilter(
+ unzip_params->unzipper()->Unzip(
std::move(zip_file), std::move(directory_remote),
- std::move(unzip_filter_remote), base::BindOnce(&UnzipDone, unzip_params));
+ std::move(unzip_filter_remote),
+ base::BindOnce(&UnzipParams::InvokeCallback, unzip_params));
+}
+
+void DoDetectEncoding(
+ mojo::PendingRemote<mojom::Unzipper> unzipper,
+ const base::FilePath& zip_path,
+ DetectEncodingCallback result_callback,
+ scoped_refptr<base::SequencedTaskRunner> callback_task_runner,
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner) {
+ base::File zip_file(zip_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
+ if (!zip_file.IsValid()) {
+ LOG(ERROR) << "Cannot open ZIP archive " << Redact(zip_path) << ": "
+ << base::File::ErrorToString(zip_file.error_details());
+ callback_task_runner->PostTask(
+ FROM_HERE,
+ base::BindOnce(std::move(result_callback), UNKNOWN_ENCODING));
+ return;
+ }
+
+ // |result_callback| is shared between the connection error handler and the
+ // DetectEncoding call using a refcounted DetectEncodingParams object that
+ // owns |result_callback|.
+ auto params = base::MakeRefCounted<DetectEncodingParams>(
+ std::move(unzipper), std::move(result_callback),
+ std::move(callback_task_runner), std::move(background_task_runner));
+
+ params->unzipper().set_disconnect_handler(base::BindOnce(
+ &DetectEncodingParams::InvokeCallback, params, UNKNOWN_ENCODING));
+
+ params->unzipper()->DetectEncoding(
+ std::move(zip_file),
+ base::BindOnce(&DetectEncodingParams::InvokeCallback, params));
}
} // namespace
@@ -170,10 +246,23 @@ void UnzipWithFilter(mojo::PendingRemote<mojom::Unzipper> unzipper,
base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN});
background_task_runner->PostTask(
FROM_HERE,
- base::BindOnce(&DoUnzipWithFilter, std::move(unzipper), zip_path,
- output_dir, base::SequencedTaskRunnerHandle::Get(),
- filter_callback, std::move(result_callback),
- background_task_runner));
+ base::BindOnce(&DoUnzip, std::move(unzipper), zip_path, output_dir,
+ base::SequencedTaskRunnerHandle::Get(), filter_callback,
+ std::move(result_callback), background_task_runner));
+}
+
+void DetectEncoding(mojo::PendingRemote<mojom::Unzipper> unzipper,
+ const base::FilePath& zip_path,
+ DetectEncodingCallback result_callback) {
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner =
+ base::ThreadPool::CreateSequencedTaskRunner(
+ {base::TaskPriority::USER_VISIBLE, base::MayBlock(),
+ base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN});
+ background_task_runner->PostTask(
+ FROM_HERE, base::BindOnce(&DoDetectEncoding, std::move(unzipper),
+ zip_path, std::move(result_callback),
+ base::SequencedTaskRunnerHandle::Get(),
+ background_task_runner));
}
} // namespace unzip
diff --git a/chromium/components/services/unzip/public/cpp/unzip.h b/chromium/components/services/unzip/public/cpp/unzip.h
index e62a4ac524d..1f4bbb0f203 100644
--- a/chromium/components/services/unzip/public/cpp/unzip.h
+++ b/chromium/components/services/unzip/public/cpp/unzip.h
@@ -8,6 +8,7 @@
#include "base/callback_forward.h"
#include "components/services/unzip/public/mojom/unzipper.mojom.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "third_party/ced/src/util/encodings/encodings.h"
namespace base {
class FilePath;
@@ -32,6 +33,11 @@ void UnzipWithFilter(mojo::PendingRemote<mojom::Unzipper> unzipper,
UnzipFilterCallback filter_callback,
UnzipCallback result_callback);
+using DetectEncodingCallback = base::OnceCallback<void(Encoding)>;
+void DetectEncoding(mojo::PendingRemote<mojom::Unzipper> unzipper,
+ const base::FilePath& zip_file,
+ DetectEncodingCallback result_callback);
+
} // namespace unzip
#endif // COMPONENTS_SERVICES_UNZIP_PUBLIC_CPP_UNZIP_H_
diff --git a/chromium/components/services/unzip/public/cpp/unzip_unittest.cc b/chromium/components/services/unzip/public/cpp/unzip_unittest.cc
index ccb9053207a..658301c4b44 100644
--- a/chromium/components/services/unzip/public/cpp/unzip_unittest.cc
+++ b/chromium/components/services/unzip/public/cpp/unzip_unittest.cc
@@ -4,33 +4,33 @@
#include "components/services/unzip/public/cpp/unzip.h"
+#include <utility>
+
#include "base/base_paths.h"
-#include "base/bind.h"
#include "base/files/file_enumerator.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/path_service.h"
#include "base/run_loop.h"
+#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "components/services/unzip/unzipper_impl.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace unzip {
-
namespace {
-// Note: this method has to return void for the ASSERTION_* to compile.
-void GetArchivePath(const base::FilePath::StringPieceType& archive_name,
- base::FilePath* path) {
- ASSERT_TRUE(base::PathService::Get(base::DIR_SOURCE_ROOT, path));
- *path = path->Append(FILE_PATH_LITERAL("components"))
- .Append(FILE_PATH_LITERAL("test"))
- .Append(FILE_PATH_LITERAL("data"))
- .Append(FILE_PATH_LITERAL("unzip_service"))
- .Append(archive_name);
- ASSERT_TRUE(base::PathExists(*path));
+base::FilePath GetArchivePath(
+ const base::FilePath::StringPieceType archive_name) {
+ base::FilePath path;
+ EXPECT_TRUE(base::PathService::Get(base::DIR_SOURCE_ROOT, &path));
+ return path.Append(FILE_PATH_LITERAL("components"))
+ .Append(FILE_PATH_LITERAL("test"))
+ .Append(FILE_PATH_LITERAL("data"))
+ .Append(FILE_PATH_LITERAL("unzip_service"))
+ .Append(archive_name);
}
// Sets the number of files under |dir| in |file_count| and if
@@ -63,37 +63,44 @@ class UnzipTest : public testing::Test {
~UnzipTest() override = default;
// Unzips |zip_file| into |output_dir| and returns true if the unzip was
- // successful.
+ // successful. Only extract files for which |filter_callback| returns true, if
+ // it is provided.
bool DoUnzip(const base::FilePath& zip_file,
- const base::FilePath& output_dir) {
- return DoUnzipWithFilter(zip_file, output_dir, UnzipFilterCallback());
+ const base::FilePath& output_dir,
+ UnzipFilterCallback filter_callback = {}) {
+ mojo::PendingRemote<mojom::Unzipper> unzipper;
+ receivers_.Add(&unzipper_, unzipper.InitWithNewPipeAndPassReceiver());
+
+ base::RunLoop run_loop;
+ bool result = false;
+
+ UnzipCallback result_callback =
+ base::BindLambdaForTesting([&](const bool success) {
+ result = success;
+ run_loop.QuitClosure().Run();
+ });
+
+ UnzipWithFilter(std::move(unzipper), zip_file, output_dir,
+ std::move(filter_callback), std::move(result_callback));
+
+ run_loop.Run();
+ return result;
}
- // Same as DoUnzip() but only extract files for which |filter_callback|
- // returns true.
- bool DoUnzipWithFilter(const base::FilePath& zip_file,
- const base::FilePath& output_dir,
- UnzipFilterCallback filter_callback) {
+ Encoding DoDetectEncoding(const base::FilePath& zip_file) {
mojo::PendingRemote<mojom::Unzipper> unzipper;
receivers_.Add(&unzipper_, unzipper.InitWithNewPipeAndPassReceiver());
base::RunLoop run_loop;
- bool result = false;
+ Encoding result = UNKNOWN_ENCODING;
- UnzipCallback result_callback = base::BindOnce(
- [](base::OnceClosure quit_closure, bool* out_result, bool result) {
- *out_result = result;
- std::move(quit_closure).Run();
- },
- run_loop.QuitClosure(), &result);
-
- if (filter_callback) {
- UnzipWithFilter(std::move(unzipper), zip_file, output_dir,
- std::move(filter_callback), std::move(result_callback));
- } else {
- Unzip(std::move(unzipper), zip_file, output_dir,
- std::move(result_callback));
- }
+ DetectEncodingCallback result_callback =
+ base::BindLambdaForTesting([&](const Encoding encoding) {
+ result = encoding;
+ run_loop.QuitClosure().Run();
+ });
+
+ DetectEncoding(std::move(unzipper), zip_file, std::move(result_callback));
run_loop.Run();
return result;
}
@@ -114,9 +121,8 @@ class UnzipTest : public testing::Test {
};
TEST_F(UnzipTest, UnzipBadArchive) {
- base::FilePath bad_archive;
- GetArchivePath(FILE_PATH_LITERAL("bad_archive.zip"), &bad_archive);
- EXPECT_FALSE(DoUnzip(bad_archive, unzip_dir_));
+ EXPECT_FALSE(DoUnzip(GetArchivePath(FILE_PATH_LITERAL("bad_archive.zip")),
+ unzip_dir_));
// No files should have been extracted.
int64_t file_count = -1;
@@ -125,9 +131,8 @@ TEST_F(UnzipTest, UnzipBadArchive) {
}
TEST_F(UnzipTest, UnzipGoodArchive) {
- base::FilePath archive;
- GetArchivePath(FILE_PATH_LITERAL("good_archive.zip"), &archive);
- EXPECT_TRUE(DoUnzip(archive, unzip_dir_));
+ EXPECT_TRUE(DoUnzip(GetArchivePath(FILE_PATH_LITERAL("good_archive.zip")),
+ unzip_dir_));
// Sanity check that the right number of files have been extracted and that
// they are not empty.
@@ -139,13 +144,11 @@ TEST_F(UnzipTest, UnzipGoodArchive) {
}
TEST_F(UnzipTest, UnzipWithFilter) {
- base::FilePath archive;
- GetArchivePath(FILE_PATH_LITERAL("good_archive.zip"), &archive);
- EXPECT_TRUE(DoUnzipWithFilter(
- archive, unzip_dir_,
- base::BindRepeating([](const base::FilePath& path) -> bool {
- return path.MatchesExtension(FILE_PATH_LITERAL(".txt"));
- })));
+ EXPECT_TRUE(DoUnzip(GetArchivePath(FILE_PATH_LITERAL("good_archive.zip")),
+ unzip_dir_,
+ base::BindRepeating([](const base::FilePath& path) {
+ return path.MatchesExtension(FILE_PATH_LITERAL(".txt"));
+ })));
// It should only have kept the 2 text files from the archive.
int64_t file_count = -1;
@@ -155,5 +158,51 @@ TEST_F(UnzipTest, UnzipWithFilter) {
EXPECT_FALSE(some_files_empty);
}
+TEST_F(UnzipTest, DetectEncodingAbsentArchive) {
+ EXPECT_EQ(UNKNOWN_ENCODING, DoDetectEncoding(GetArchivePath(
+ FILE_PATH_LITERAL("absent_archive.zip"))));
+}
+
+TEST_F(UnzipTest, DetectEncodingBadArchive) {
+ EXPECT_EQ(
+ UNKNOWN_ENCODING,
+ DoDetectEncoding(GetArchivePath(FILE_PATH_LITERAL("bad_archive.zip"))));
+}
+
+TEST_F(UnzipTest, DetectEncodingAscii) {
+ EXPECT_EQ(
+ Encoding::ASCII_7BIT,
+ DoDetectEncoding(GetArchivePath(FILE_PATH_LITERAL("good_archive.zip"))));
+}
+
+// See https://crbug.com/903664
+TEST_F(UnzipTest, DetectEncodingUtf8) {
+ EXPECT_EQ(Encoding::UTF8, DoDetectEncoding(GetArchivePath(
+ FILE_PATH_LITERAL("UTF8 (Bug 903664).zip"))));
+}
+
+// See https://crbug.com/1287893
+TEST_F(UnzipTest, DetectEncodingSjis) {
+ for (const base::FilePath::StringPieceType name : {
+ FILE_PATH_LITERAL("SJIS 00.zip"),
+ FILE_PATH_LITERAL("SJIS 01.zip"),
+ FILE_PATH_LITERAL("SJIS 02.zip"),
+ FILE_PATH_LITERAL("SJIS 03.zip"),
+ FILE_PATH_LITERAL("SJIS 04.zip"),
+ FILE_PATH_LITERAL("SJIS 05.zip"),
+ FILE_PATH_LITERAL("SJIS 06.zip"),
+ FILE_PATH_LITERAL("SJIS 07.zip"),
+ FILE_PATH_LITERAL("SJIS 08.zip"),
+ FILE_PATH_LITERAL("SJIS 09.zip"),
+ FILE_PATH_LITERAL("SJIS 10.zip"),
+ FILE_PATH_LITERAL("SJIS 11.zip"),
+ FILE_PATH_LITERAL("SJIS 12.zip"),
+ FILE_PATH_LITERAL("SJIS 13.zip"),
+ }) {
+ EXPECT_EQ(Encoding::JAPANESE_SHIFT_JIS,
+ DoDetectEncoding(GetArchivePath(name)));
+ }
+}
+
} // namespace
} // namespace unzip
diff --git a/chromium/components/services/unzip/public/mojom/unzipper.mojom b/chromium/components/services/unzip/public/mojom/unzipper.mojom
index 00273934dd9..a16f891cd85 100644
--- a/chromium/components/services/unzip/public/mojom/unzipper.mojom
+++ b/chromium/components/services/unzip/public/mojom/unzipper.mojom
@@ -20,14 +20,17 @@ interface UnzipFilter {
interface Unzipper {
// Unzip |zip_file| into |output_dir|.
// Returns true on success, false otherwise.
- Unzip(mojo_base.mojom.ReadOnlyFile zip_file,
- pending_remote<filesystem.mojom.Directory> output_dir)
- => (bool result);
-
- // Same as |unzip| but only includes the files for which |filter| returns
- // true. Note that this incurs one IPC for each file of the archive.
- UnzipWithFilter(
+ // If provided, |filter| is called for each entry of the archive (which incurs
+ // one IPC for each entry) and only the entries for which it returns true are
+ // extracted.
+ Unzip(
mojo_base.mojom.ReadOnlyFile zip_file,
pending_remote<filesystem.mojom.Directory> output_dir,
- pending_remote<UnzipFilter> filter) => (bool result);
+ pending_remote<UnzipFilter>? filter) => (bool result);
+
+ // Detects the encoding of filenames stored in the ZIP archive.
+ // Returns an Encoding as defined in
+ // third_party/ced/src/util/encodings/encodings.pb.h
+ // or UNKNOWN_ENCODING in case of error.
+ DetectEncoding(mojo_base.mojom.ReadOnlyFile zip_file) => (int32 encoding);
};
diff --git a/chromium/components/services/unzip/unzipper_impl.cc b/chromium/components/services/unzip/unzipper_impl.cc
index b710ab8b2bf..10e1a68bfef 100644
--- a/chromium/components/services/unzip/unzipper_impl.cc
+++ b/chromium/components/services/unzip/unzipper_impl.cc
@@ -9,10 +9,13 @@
#include "base/bind.h"
#include "base/compiler_specific.h"
+#include "base/files/file.h"
+#include "base/logging.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "components/services/filesystem/public/mojom/directory.mojom.h"
#include "mojo/public/cpp/bindings/remote.h"
+#include "third_party/ced/src/compact_enc_det/compact_enc_det.h"
#include "third_party/zlib/google/zip.h"
#include "third_party/zlib/google/zip_reader.h"
@@ -20,24 +23,8 @@ namespace unzip {
namespace {
-// A writer delegate that reports errors instead of writing.
-class DudWriterDelegate : public zip::WriterDelegate {
- public:
- DudWriterDelegate() {}
-
- DudWriterDelegate(const DudWriterDelegate&) = delete;
- DudWriterDelegate& operator=(const DudWriterDelegate&) = delete;
-
- ~DudWriterDelegate() override {}
-
- // WriterDelegate methods:
- bool PrepareOutput() override { return false; }
- bool WriteBytes(const char* data, int num_bytes) override { return false; }
- void SetTimeModified(const base::Time& time) override {}
-};
-
std::string PathToMojoString(const base::FilePath& path) {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
return base::WideToUTF8(path.value());
#else
return path.value();
@@ -64,7 +51,7 @@ std::unique_ptr<zip::WriterDelegate> MakeFileWriterDelegateNoParent(
filesystem::mojom::kFlagWriteAttributes,
&err, file.get()) ||
err != base::File::Error::FILE_OK) {
- return std::make_unique<DudWriterDelegate>();
+ return nullptr;
}
return std::make_unique<zip::FileWriterDelegate>(std::move(file));
}
@@ -80,22 +67,51 @@ std::unique_ptr<zip::WriterDelegate> MakeFileWriterDelegate(
parent.BindNewPipeAndPassReceiver(),
filesystem::mojom::kFlagOpenAlways, &err) ||
err != base::File::Error::FILE_OK) {
- return std::make_unique<DudWriterDelegate>();
+ return nullptr;
}
return MakeFileWriterDelegateNoParent(parent.get(), path.BaseName());
}
-bool FilterNoFiles(const base::FilePath& unused) {
- return true;
-}
-
-bool FilterWithFilterRemote(mojom::UnzipFilter* filter,
- const base::FilePath& path) {
+bool Filter(const mojo::Remote<mojom::UnzipFilter>& filter,
+ const base::FilePath& path) {
bool result = false;
filter->ShouldUnzipFile(path, &result);
return result;
}
+// Reads the given ZIP archive, and returns all the filenames concatenated
+// together in one long string capped at ~100KB, without any separator, and in
+// the encoding used by the ZIP archive itself. Returns an empty string if the
+// ZIP cannot be read.
+std::string GetRawFileNamesFromZip(const base::File& zip_file) {
+ std::string result;
+
+ // Open ZIP archive for reading.
+ zip::ZipReader reader;
+ if (!reader.OpenFromPlatformFile(zip_file.GetPlatformFile())) {
+ LOG(ERROR) << "Cannot decode ZIP archive";
+ return result;
+ }
+
+ // Reserve a ~100KB buffer.
+ result.reserve(100000);
+
+ // Iterate over file entries of the ZIP archive.
+ while (const zip::ZipReader::Entry* const entry = reader.Next()) {
+ const std::string& path = entry->path_in_original_encoding;
+
+ // Stop if we have enough data in |result|.
+ if (path.size() > (result.capacity() - result.size()))
+ break;
+
+ // Accumulate data in |result|.
+ result += path;
+ }
+
+ LOG_IF(ERROR, result.empty()) << "Cannot extract filenames from ZIP archive";
+ return result;
+}
+
} // namespace
UnzipperImpl::UnzipperImpl() = default;
@@ -108,38 +124,53 @@ UnzipperImpl::~UnzipperImpl() = default;
void UnzipperImpl::Unzip(
base::File zip_file,
mojo::PendingRemote<filesystem::mojom::Directory> output_dir_remote,
+ mojo::PendingRemote<mojom::UnzipFilter> filter_remote,
UnzipCallback callback) {
DCHECK(zip_file.IsValid());
mojo::Remote<filesystem::mojom::Directory> output_dir(
std::move(output_dir_remote));
- std::move(callback).Run(zip::UnzipWithFilterAndWriters(
- zip_file.GetPlatformFile(),
- base::BindRepeating(&MakeFileWriterDelegate, output_dir.get()),
- base::BindRepeating(&CreateDirectory, output_dir.get()),
- base::BindRepeating(&FilterNoFiles), /*log_skipped_files=*/false));
+ zip::FilterCallback filter_cb;
+ if (filter_remote) {
+ filter_cb = base::BindRepeating(
+ &Filter, mojo::Remote<mojom::UnzipFilter>(std::move(filter_remote)));
+ }
+
+ std::move(callback).Run(
+ zip::Unzip(zip_file.GetPlatformFile(),
+ base::BindRepeating(&MakeFileWriterDelegate, output_dir.get()),
+ base::BindRepeating(&CreateDirectory, output_dir.get()),
+ {.filter = std::move(filter_cb)}));
}
-void UnzipperImpl::UnzipWithFilter(
- base::File zip_file,
- mojo::PendingRemote<filesystem::mojom::Directory> output_dir_remote,
- mojo::PendingRemote<mojom::UnzipFilter> filter_remote,
- UnzipCallback callback) {
+void UnzipperImpl::DetectEncoding(base::File zip_file,
+ DetectEncodingCallback callback) {
DCHECK(zip_file.IsValid());
- mojo::Remote<filesystem::mojom::Directory> output_dir(
- std::move(output_dir_remote));
- mojo::Remote<mojom::UnzipFilter> filter(std::move(filter_remote));
-
- // Note that we pass a pointer to |filter| below, as it is a repeating
- // callback and transferring its value would cause the callback to fail when
- // called more than once. It is safe to pass a pointer as
- // UnzipWithFilterAndWriters is synchronous, so |filter| won't be used when
- // the method returns.
- std::move(callback).Run(zip::UnzipWithFilterAndWriters(
- zip_file.GetPlatformFile(),
- base::BindRepeating(&MakeFileWriterDelegate, output_dir.get()),
- base::BindRepeating(&CreateDirectory, output_dir.get()),
- base::BindRepeating(&FilterWithFilterRemote, filter.get()),
- /*log_skipped_files=*/false));
+
+ // Accumulate raw filenames.
+ const std::string all_names = GetRawFileNamesFromZip(zip_file);
+ if (all_names.empty()) {
+ std::move(callback).Run(UNKNOWN_ENCODING);
+ return;
+ }
+
+ // Detect encoding.
+ int consumed_bytes = 0;
+ bool is_reliable = false;
+ const Encoding encoding = CompactEncDet::DetectEncoding(
+ all_names.data(), all_names.size(), nullptr, nullptr, nullptr,
+ UNKNOWN_ENCODING, UNKNOWN_LANGUAGE,
+ CompactEncDet::QUERY_CORPUS, // Plain text
+ true, // Exclude 7-bit encodings
+ &consumed_bytes, &is_reliable);
+
+ VLOG(1) << "Detected encoding: " << MimeEncodingName(encoding) << " ("
+ << encoding << "), reliable: " << is_reliable
+ << ", consumed bytes: " << consumed_bytes;
+
+ LOG_IF(ERROR, encoding == UNKNOWN_ENCODING)
+ << "Cannot detect encoding of filenames in ZIP archive";
+
+ std::move(callback).Run(encoding);
}
} // namespace unzip
diff --git a/chromium/components/services/unzip/unzipper_impl.h b/chromium/components/services/unzip/unzipper_impl.h
index 330b716f910..6503523312a 100644
--- a/chromium/components/services/unzip/unzipper_impl.h
+++ b/chromium/components/services/unzip/unzipper_impl.h
@@ -32,13 +32,11 @@ class UnzipperImpl : public mojom::Unzipper {
void Unzip(
base::File zip_file,
mojo::PendingRemote<filesystem::mojom::Directory> output_dir_remote,
+ mojo::PendingRemote<mojom::UnzipFilter> filter_remote,
UnzipCallback callback) override;
- void UnzipWithFilter(
- base::File zip_file,
- mojo::PendingRemote<filesystem::mojom::Directory> output_dir_remote,
- mojo::PendingRemote<mojom::UnzipFilter> filter_remote,
- UnzipWithFilterCallback callback) override;
+ void DetectEncoding(base::File zip_file,
+ DetectEncodingCallback callback) override;
mojo::Receiver<mojom::Unzipper> receiver_{this};
};
diff --git a/chromium/components/session_manager/session_manager_types.h b/chromium/components/session_manager/session_manager_types.h
index 1fa7d875bfc..eeda482ae99 100644
--- a/chromium/components/session_manager/session_manager_types.h
+++ b/chromium/components/session_manager/session_manager_types.h
@@ -37,6 +37,9 @@ enum class SessionState {
// Same as LOGIN_PRIMARY but for multi-profiles sign in i.e. when there's at
// least one user already active in the session.
LOGIN_SECONDARY,
+
+ // Device is being repaired and the RMA app is active.
+ RMA,
};
// A type for session id.
diff --git a/chromium/components/sessions/BUILD.gn b/chromium/components/sessions/BUILD.gn
index 463df08fd33..e50ea8009b4 100644
--- a/chromium/components/sessions/BUILD.gn
+++ b/chromium/components/sessions/BUILD.gn
@@ -2,8 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-import("//extensions/buildflags/buildflags.gni")
-
if (is_android) {
import("//build/config/android/config.gni")
}
@@ -44,14 +42,9 @@ if (!is_ios) {
"//base",
"//base/third_party/dynamic_annotations",
"//content/public/common",
- "//extensions/buildflags",
"//ui/base",
"//url",
]
-
- if (enable_extensions) {
- deps += [ "//extensions/common" ]
- }
}
} else {
source_set("sessions") {
@@ -235,7 +228,10 @@ source_set("unit_tests") {
"//content/test:test_support",
]
} else {
- deps += [ "//ios/web/public/test" ]
+ deps += [
+ "//ios/web/public/test",
+ "//ios/web/public/test:test_fixture",
+ ]
}
}
diff --git a/chromium/components/sessions/content/DEPS b/chromium/components/sessions/content/DEPS
index 89bf3d57fe6..92e83a8f31e 100644
--- a/chromium/components/sessions/content/DEPS
+++ b/chromium/components/sessions/content/DEPS
@@ -2,11 +2,9 @@ include_rules = [
"+content/public/browser",
"+content/public/common",
"+content/public/test",
- "+extensions/buildflags",
- "+extensions/common",
"+third_party/blink/public/common/page_state/page_state.h",
"+third_party/blink/public/common/user_agent/user_agent_metadata.h",
"+third_party/blink/public/platform",
"+services/network/public/mojom/referrer_policy.mojom.h",
"+services/network/public/cpp/shared_url_loader_factory.h",
-] \ No newline at end of file
+]
diff --git a/chromium/components/sessions/content/session_tab_helper.cc b/chromium/components/sessions/content/session_tab_helper.cc
index a1ad7931c83..a393a073fa0 100644
--- a/chromium/components/sessions/content/session_tab_helper.cc
+++ b/chromium/components/sessions/content/session_tab_helper.cc
@@ -11,11 +11,6 @@
#include "components/sessions/core/serialized_user_agent_override.h"
#include "content/public/browser/navigation_details.h"
#include "content/public/browser/web_contents.h"
-#include "extensions/buildflags/buildflags.h"
-
-#if BUILDFLAG(ENABLE_EXTENSIONS)
-#include "extensions/common/extension_messages.h"
-#endif
namespace sessions {
@@ -31,13 +26,7 @@ SessionTabHelper::~SessionTabHelper() = default;
void SessionTabHelper::SetWindowID(const SessionID& id) {
window_id_ = id;
-
-#if BUILDFLAG(ENABLE_EXTENSIONS)
- // Extension code in the renderer holds the ID of the window that hosts it.
- // Notify it that the window ID changed.
- web_contents()->SendToAllFrames(
- new ExtensionMsg_UpdateBrowserWindowId(MSG_ROUTING_NONE, id.id()));
-#endif
+ window_id_changed_callbacks_.Notify(id);
}
// static
@@ -57,6 +46,11 @@ SessionID SessionTabHelper::IdForWindowContainingTab(
: SessionID::InvalidValue();
}
+base::CallbackListSubscription SessionTabHelper::RegisterForWindowIdChanged(
+ WindowIdChangedCallbackList::CallbackType callback) {
+ return window_id_changed_callbacks_.Add(std::move(callback));
+}
+
void SessionTabHelper::UserAgentOverrideSet(
const blink::UserAgentOverride& ua_override) {
SessionTabHelperDelegate* delegate = GetDelegate();
diff --git a/chromium/components/sessions/content/session_tab_helper.h b/chromium/components/sessions/content/session_tab_helper.h
index ca14a1b082c..1a68abd5ebd 100644
--- a/chromium/components/sessions/content/session_tab_helper.h
+++ b/chromium/components/sessions/content/session_tab_helper.h
@@ -6,6 +6,7 @@
#define COMPONENTS_SESSIONS_CONTENT_SESSION_TAB_HELPER_H_
#include "base/callback.h"
+#include "base/callback_list.h"
#include "components/sessions/core/session_id.h"
#include "components/sessions/core/sessions_export.h"
#include "content/public/browser/web_contents_observer.h"
@@ -22,6 +23,8 @@ class SESSIONS_EXPORT SessionTabHelper
public:
using DelegateLookup =
base::RepeatingCallback<SessionTabHelperDelegate*(content::WebContents*)>;
+ using WindowIdChangedCallbackList =
+ base::RepeatingCallbackList<void(const SessionID& id)>;
SessionTabHelper(const SessionTabHelper&) = delete;
SessionTabHelper& operator=(const SessionTabHelper&) = delete;
@@ -53,6 +56,9 @@ class SESSIONS_EXPORT SessionTabHelper
// WebContents has no SessionTabHelper.
static SessionID IdForWindowContainingTab(const content::WebContents* tab);
+ base::CallbackListSubscription RegisterForWindowIdChanged(
+ WindowIdChangedCallbackList::CallbackType callback);
+
// content::WebContentsObserver:
void UserAgentOverrideSet(
const blink::UserAgentOverride& ua_override) override;
@@ -70,6 +76,8 @@ class SESSIONS_EXPORT SessionTabHelper
sessions::SessionTabHelperDelegate* GetDelegate();
+ WindowIdChangedCallbackList window_id_changed_callbacks_;
+
DelegateLookup delegate_lookup_;
// Unique identifier of the tab for session restore. This id is only unique
diff --git a/chromium/components/sessions/core/command_storage_backend.cc b/chromium/components/sessions/core/command_storage_backend.cc
index b7b1347fd57..3a9012e50ab 100644
--- a/chromium/components/sessions/core/command_storage_backend.cc
+++ b/chromium/components/sessions/core/command_storage_backend.cc
@@ -352,9 +352,9 @@ bool SessionFileReader::FillBuffer() {
}
base::FilePath::StringType TimestampToString(const base::Time time) {
-#if defined(OS_POSIX) || defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
return base::NumberToString(time.ToDeltaSinceWindowsEpoch().InMicroseconds());
-#elif defined(OS_WIN)
+#elif BUILDFLAG(IS_WIN)
return base::NumberToWString(
time.ToDeltaSinceWindowsEpoch().InMicroseconds());
#endif
diff --git a/chromium/components/sessions/core/command_storage_backend.h b/chromium/components/sessions/core/command_storage_backend.h
index 1c7576d9af7..854e4ba2f21 100644
--- a/chromium/components/sessions/core/command_storage_backend.h
+++ b/chromium/components/sessions/core/command_storage_backend.h
@@ -14,6 +14,7 @@
#include "base/callback_forward.h"
#include "base/files/file_path.h"
#include "base/memory/ref_counted_delete_on_sequence.h"
+#include "base/time/time.h"
#include "components/sessions/core/command_storage_manager.h"
#include "components/sessions/core/session_command.h"
#include "components/sessions/core/sessions_export.h"
diff --git a/chromium/components/sessions/core/serialized_navigation_entry.cc b/chromium/components/sessions/core/serialized_navigation_entry.cc
index ebbbf2e8ae6..f03b7f45e65 100644
--- a/chromium/components/sessions/core/serialized_navigation_entry.cc
+++ b/chromium/components/sessions/core/serialized_navigation_entry.cc
@@ -5,9 +5,10 @@
#include "components/sessions/core/serialized_navigation_entry.h"
#include <stddef.h>
+
+#include <tuple>
#include <utility>
-#include "base/ignore_result.h"
#include "base/pickle.h"
#include "base/trace_event/memory_usage_estimator.h"
#include "components/sessions/core/serialized_navigation_driver.h"
@@ -206,7 +207,7 @@ bool SerializedNavigationEntry::ReadFromPickle(base::PickleIterator* iterator) {
// and ignored. A correct referrer policy is extracted later (see
// |correct_referrer_policy| below).
int ignored_referrer_policy;
- ignore_result(iterator->ReadInt(&ignored_referrer_policy));
+ std::ignore = iterator->ReadInt(&ignored_referrer_policy);
// If the original URL can't be found, leave it empty.
std::string original_request_url_spec;
@@ -228,7 +229,7 @@ bool SerializedNavigationEntry::ReadFromPickle(base::PickleIterator* iterator) {
// The |search_terms_| field was removed, but it still exists in the binary
// format to keep backwards compatibility. Just get rid of it.
std::u16string search_terms;
- ignore_result(iterator->ReadString16(&search_terms));
+ std::ignore = iterator->ReadString16(&search_terms);
if (!iterator->ReadInt(&http_status_code_))
http_status_code_ = 0;
@@ -267,7 +268,7 @@ bool SerializedNavigationEntry::ReadFromPickle(base::PickleIterator* iterator) {
// Child task ids are no longer used.
int children_task_ids_size = 0;
- ignore_result(iterator->ReadInt(&children_task_ids_size));
+ std::ignore = iterator->ReadInt(&children_task_ids_size);
}
SerializedNavigationDriver::Get()->Sanitize(this);
diff --git a/chromium/components/sessions/core/session_command.cc b/chromium/components/sessions/core/session_command.cc
index 2de11d95439..9b9d1583a5b 100644
--- a/chromium/components/sessions/core/session_command.cc
+++ b/chromium/components/sessions/core/session_command.cc
@@ -2,7 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <algorithm>
#include <limits>
+#include <memory>
#include "base/pickle.h"
#include "components/sessions/core/session_command.h"
diff --git a/chromium/components/sessions/core/session_service_commands.cc b/chromium/components/sessions/core/session_service_commands.cc
index bda93c0a8dd..b3c28cb682f 100644
--- a/chromium/components/sessions/core/session_service_commands.cc
+++ b/chromium/components/sessions/core/session_service_commands.cc
@@ -8,12 +8,12 @@
#include <string.h>
#include <map>
+#include <tuple>
#include <utility>
#include <vector>
#include "base/containers/flat_set.h"
#include "base/guid.h"
-#include "base/ignore_result.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/pickle.h"
@@ -680,7 +680,7 @@ bool CreateTabsAndWindows(
// The |is_collapsed| boolean was added in M88 to save the collapsed
// state, so previous versions may not have this stored.
bool is_collapsed = false;
- ignore_result(!iter.ReadBool(&is_collapsed));
+ std::ignore = iter.ReadBool(&is_collapsed);
group->visual_data =
tab_groups::TabGroupVisualData(title, color_int, is_collapsed);
break;
diff --git a/chromium/components/sessions/core/tab_restore_service.h b/chromium/components/sessions/core/tab_restore_service.h
index 89f1a706278..fb49fa35ce8 100644
--- a/chromium/components/sessions/core/tab_restore_service.h
+++ b/chromium/components/sessions/core/tab_restore_service.h
@@ -10,6 +10,7 @@
#include <string>
#include <vector>
+#include "base/callback_forward.h"
#include "base/memory/ref_counted.h"
#include "base/time/time.h"
#include "base/token.h"
diff --git a/chromium/components/sessions/core/tab_restore_service_helper.cc b/chromium/components/sessions/core/tab_restore_service_helper.cc
index 62ac841dfb0..f52e0da0e44 100644
--- a/chromium/components/sessions/core/tab_restore_service_helper.cc
+++ b/chromium/components/sessions/core/tab_restore_service_helper.cc
@@ -30,6 +30,7 @@
#include "components/sessions/core/live_tab.h"
#include "components/sessions/core/live_tab_context.h"
#include "components/sessions/core/serialized_navigation_entry.h"
+#include "components/sessions/core/session_constants.h"
#include "components/sessions/core/session_id.h"
#include "components/sessions/core/session_types.h"
#include "components/sessions/core/tab_restore_service_client.h"
@@ -38,6 +39,60 @@
#include "components/tab_groups/tab_group_visual_data.h"
namespace sessions {
+namespace {
+
+// Specifies what entries are added.
+enum class AddBehavior {
+ // Adds the current entry, and entries preceeding it.
+ kCurrentAndPreceedingEntries,
+
+ // Adds entries after the current.
+ kEntriesFollowingCurrentEntry,
+};
+
+// Adds serialized navigation entries from a LiveTab.
+void AddSerializedNavigationEntries(
+ LiveTab* live_tab,
+ AddBehavior behavior,
+ std::vector<SerializedNavigationEntry>& navigations) {
+ // It is assumed this is called for back navigations first, at which point the
+ // vector should be empty. This is necessary as back navigations are added
+ // in reverse order and then the vector is reversed.
+ DCHECK(behavior == AddBehavior::kEntriesFollowingCurrentEntry ||
+ navigations.empty());
+ const int max_index = live_tab->GetEntryCount();
+ const int delta =
+ (behavior == AddBehavior::kCurrentAndPreceedingEntries) ? -1 : 1;
+ int current_index = live_tab->GetCurrentEntryIndex();
+ if (behavior == AddBehavior::kEntriesFollowingCurrentEntry)
+ ++current_index;
+ int added_count = 0;
+ while (current_index >= 0 && current_index < max_index &&
+ added_count <= gMaxPersistNavigationCount) {
+ SerializedNavigationEntry entry = live_tab->GetEntryAtIndex(current_index);
+ current_index += delta;
+ // Reader Mode is meant to be considered a "mode" that users can only enter
+ // using a button in the omnibox, so it does not show up in recently closed
+ // tabs, session sync, or chrome://history. Remove Reader Mode pages from
+ // the navigations.
+ if (entry.virtual_url().SchemeIs(dom_distiller::kDomDistillerScheme))
+ continue;
+
+ // As this code was identified as doing a lot of allocations, push_back is
+ // always used and the vector is reversed for `kCurrentAndPreceedingEntries`
+ // when done. Doing this instead of inserting at the beginning results in
+ // less memory operations.
+ navigations.push_back(std::move(entry));
+ ++added_count;
+ }
+ // Iteration for `kCurrentAndPreceedingEntries` happens in descending order.
+ // This results in the entries being added in reverse order. Use
+ // std::reverse() so the entries end up in ascending order.
+ if (behavior == AddBehavior::kCurrentAndPreceedingEntries)
+ std::reverse(navigations.begin(), navigations.end());
+}
+
+} // namespace
// TabRestoreServiceHelper::Observer -------------------------------------------
@@ -430,9 +485,10 @@ std::vector<LiveTab*> TabRestoreServiceHelper::RestoreEntryById(
auto& window = static_cast<Window&>(entry);
// When restoring a window, either the entire window can be restored, or a
- // single tab within it. If the entry's ID matches the one to restore,
- // then the entire window will be restored.
- if (entry_id_matches_restore_id) {
+ // single tab within it. If the entry's ID matches the one to restore, or
+ // the entry corresponds to an application, then the entire window will be
+ // restored.
+ if (entry_id_matches_restore_id || !window.app_name.empty()) {
context = client_->CreateLiveTabContext(
window.app_name, window.bounds, window.show_state, window.workspace,
window.user_title, window.extra_data);
@@ -754,30 +810,19 @@ void TabRestoreServiceHelper::PopulateTab(Tab* tab,
int index,
LiveTabContext* context,
LiveTab* live_tab) {
- int max_entry_count =
- live_tab->IsInitialBlankNavigation() ? 0 : live_tab->GetEntryCount();
- tab->navigations.resize(static_cast<int>(max_entry_count));
- int actual_entry_count = 0;
- int current_navigation_index = live_tab->GetCurrentEntryIndex();
- for (int i = 0; i < max_entry_count; ++i) {
- SerializedNavigationEntry entry = live_tab->GetEntryAtIndex(i);
- // Reader Mode is meant to be considered a "mode" that users can only enter
- // using a button in the omnibox, so it does not show up in recently closed
- // tabs, session sync, or chrome://history. Remove Reader Mode pages from
- // the navigations.
- if (!entry.virtual_url().SchemeIs(dom_distiller::kDomDistillerScheme)) {
- tab->navigations[actual_entry_count++] = entry;
- } else if (current_navigation_index >= i) {
- // The page removed was behind the current navigation index, so
- // decrement the current navigation index.
- current_navigation_index--;
+ tab->current_navigation_index = 0;
+ if (!live_tab->IsInitialBlankNavigation() && live_tab->GetEntryCount() > 0) {
+ AddSerializedNavigationEntries(
+ live_tab, AddBehavior::kCurrentAndPreceedingEntries, tab->navigations);
+ if (!tab->navigations.empty()) {
+ tab->current_navigation_index =
+ static_cast<int>(tab->navigations.size()) - 1;
}
+ AddSerializedNavigationEntries(
+ live_tab, AddBehavior::kEntriesFollowingCurrentEntry, tab->navigations);
}
- if (actual_entry_count != max_entry_count)
- tab->navigations.resize(static_cast<int>(actual_entry_count));
tab->timestamp = TimeNow();
- tab->current_navigation_index = current_navigation_index;
tab->tabstrip_index = index;
tab->extension_app_id = client_->GetExtensionAppIDForTab(live_tab);
tab->user_agent_override = live_tab->GetUserAgentOverride();
diff --git a/chromium/components/sessions/core/tab_restore_service_helper.h b/chromium/components/sessions/core/tab_restore_service_helper.h
index 3b514aefdb4..c3906026f1b 100644
--- a/chromium/components/sessions/core/tab_restore_service_helper.h
+++ b/chromium/components/sessions/core/tab_restore_service_helper.h
@@ -63,8 +63,8 @@ class SESSIONS_EXPORT TabRestoreServiceHelper
};
enum {
- // Max number of entries we'll keep around.
-#if defined(OS_ANDROID)
+ // Max number of entries we'll keep around.
+#if BUILDFLAG(IS_ANDROID)
// Android keeps at most 5 recent tabs.
kMaxEntries = 5,
#else
diff --git a/chromium/components/sessions/core/tab_restore_service_impl.cc b/chromium/components/sessions/core/tab_restore_service_impl.cc
index e894c1475e3..59d0d98a09d 100644
--- a/chromium/components/sessions/core/tab_restore_service_impl.cc
+++ b/chromium/components/sessions/core/tab_restore_service_impl.cc
@@ -14,6 +14,7 @@
#include "base/bind.h"
#include "base/check_op.h"
#include "base/compiler_specific.h"
+#include "base/containers/adapters.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/memory/raw_ptr.h"
@@ -1280,9 +1281,9 @@ void TabRestoreServiceImpl::PersistenceDelegate::ValidateAndDeleteEmptyEntries(
std::vector<std::unique_ptr<Entry>> valid_entries;
// Iterate from the back so that we keep the most recently closed entries.
- for (auto i = entries->rbegin(); i != entries->rend(); ++i) {
- if (TabRestoreServiceHelper::ValidateEntry(**i))
- valid_entries.push_back(std::move(*i));
+ for (std::unique_ptr<Entry>& entry : base::Reversed(*entries)) {
+ if (TabRestoreServiceHelper::ValidateEntry(*entry))
+ valid_entries.push_back(std::move(entry));
}
// NOTE: at this point the entries are ordered with newest at the front.
entries->swap(valid_entries);
diff --git a/chromium/components/sessions/ios/ios_serialized_navigation_builder.mm b/chromium/components/sessions/ios/ios_serialized_navigation_builder.mm
index 5bd2936e388..736c72f8a3a 100644
--- a/chromium/components/sessions/ios/ios_serialized_navigation_builder.mm
+++ b/chromium/components/sessions/ios/ios_serialized_navigation_builder.mm
@@ -29,8 +29,10 @@ IOSSerializedNavigationBuilder::FromNavigationItem(
navigation.title_ = item.GetTitle();
navigation.transition_type_ = item.GetTransitionType();
navigation.timestamp_ = item.GetTimestamp();
- if (item.GetFavicon().valid)
- navigation.favicon_url_ = item.GetFavicon().url;
+
+ const web::FaviconStatus& favicon_status = item.GetFaviconStatus();
+ if (favicon_status.valid)
+ navigation.favicon_url_ = favicon_status.url;
return navigation;
}
@@ -70,7 +72,9 @@ IOSSerializedNavigationBuilder::ToNavigationItem(
item->SetTimestamp(navigation->timestamp_);
if (navigation->favicon_url_.is_valid()) {
- item->GetFavicon().url = navigation->favicon_url_;
+ web::FaviconStatus favicon_status = item->GetFaviconStatus();
+ favicon_status.url = navigation->favicon_url_;
+ item->SetFaviconStatus(favicon_status);
}
return item;
diff --git a/chromium/components/sessions/ios/ios_serialized_navigation_builder_unittest.mm b/chromium/components/sessions/ios/ios_serialized_navigation_builder_unittest.mm
index efaba8d143a..40fb1284a09 100644
--- a/chromium/components/sessions/ios/ios_serialized_navigation_builder_unittest.mm
+++ b/chromium/components/sessions/ios/ios_serialized_navigation_builder_unittest.mm
@@ -32,9 +32,10 @@ std::unique_ptr<web::NavigationItem> MakeNavigationItemForTest() {
navigation_item->SetTitle(test_data::kTitle);
navigation_item->SetTransitionType(test_data::kTransitionType);
navigation_item->SetTimestamp(test_data::kTimestamp);
- navigation_item->GetFavicon().valid = true;
- navigation_item->GetFavicon().url =
- GURL("http://virtual-url.com/favicon.ico");
+ web::FaviconStatus favicon_status;
+ favicon_status.valid = true;
+ favicon_status.url = GURL("http://virtual-url.com/favicon.ico");
+ navigation_item->SetFaviconStatus(favicon_status);
return navigation_item;
}
@@ -61,7 +62,7 @@ TEST_F(IOSSerializedNavigationBuilderTest, FromNavigationItem) {
EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
navigation.transition_type(), navigation_item->GetTransitionType()));
EXPECT_EQ(navigation_item->GetTimestamp(), navigation.timestamp());
- EXPECT_EQ(navigation_item->GetFavicon().url, navigation.favicon_url());
+ EXPECT_EQ(navigation_item->GetFaviconStatus().url, navigation.favicon_url());
// The following fields should be left at their default values.
SerializedNavigationEntry default_navigation;
diff --git a/chromium/components/shared_highlighting/core/common/BUILD.gn b/chromium/components/shared_highlighting/core/common/BUILD.gn
index 30b33bff6fa..e7b06630cc6 100644
--- a/chromium/components/shared_highlighting/core/common/BUILD.gn
+++ b/chromium/components/shared_highlighting/core/common/BUILD.gn
@@ -2,6 +2,10 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+if (is_android) {
+ import("//build/config/android/rules.gni")
+}
+
static_library("common") {
sources = [
"disabled_sites.cc",
@@ -59,3 +63,15 @@ source_set("data_driven_testing") {
"//testing/gtest",
]
}
+
+if (is_android) {
+ java_cpp_enum("shared_highlighting_android_enums") {
+ sources = [ "shared_highlighting_metrics.h" ]
+ }
+
+ android_library("shared_highlighting_android_enums_java") {
+ deps = [ "//third_party/androidx:androidx_annotation_annotation_java" ]
+
+ srcjar_deps = [ ":shared_highlighting_android_enums" ]
+ }
+}
diff --git a/chromium/components/shared_highlighting/core/common/disabled_sites.cc b/chromium/components/shared_highlighting/core/common/disabled_sites.cc
index 80c66bd12a2..e544474d690 100644
--- a/chromium/components/shared_highlighting/core/common/disabled_sites.cc
+++ b/chromium/components/shared_highlighting/core/common/disabled_sites.cc
@@ -2,10 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <unordered_set>
+
#include "components/shared_highlighting/core/common/disabled_sites.h"
#include "base/containers/fixed_flat_map.h"
#include "base/feature_list.h"
+#include "base/strings/string_util.h"
#include "components/shared_highlighting/core/common/shared_highlighting_features.h"
#include "third_party/re2/src/re2/re2.h"
@@ -50,4 +53,14 @@ bool ShouldOfferLinkToText(const GURL& url) {
return true;
}
+bool SupportsLinkGenerationInIframe(GURL url) {
+ const std::unordered_set<std::string> good_hosts = {
+ "www.google.com", "m.google.com", "mobile.google.com",
+ "www.bing.com", "m.bing.com", "mobile.bing.com"};
+
+ return url.SchemeIs(url::kHttpsScheme) &&
+ good_hosts.find(url.host()) != good_hosts.end() &&
+ base::StartsWith(url.path(), "/amp/");
+}
+
} // namespace shared_highlighting
diff --git a/chromium/components/shared_highlighting/core/common/disabled_sites.h b/chromium/components/shared_highlighting/core/common/disabled_sites.h
index 01d509e631f..d836c6de197 100644
--- a/chromium/components/shared_highlighting/core/common/disabled_sites.h
+++ b/chromium/components/shared_highlighting/core/common/disabled_sites.h
@@ -15,6 +15,10 @@ namespace shared_highlighting {
// shared.
bool ShouldOfferLinkToText(const GURL& url);
+// Returns true if given url supports link generation in iframe.
+// This will only be called if the url is an iframe.
+bool SupportsLinkGenerationInIframe(GURL url);
+
} // namespace shared_highlighting
#endif // COMPONENTS_SHARED_HIGHLIGHTING_CORE_COMMON_DISABLED_SITES_H_
diff --git a/chromium/components/shared_highlighting/core/common/disabled_sites_unittest.cc b/chromium/components/shared_highlighting/core/common/disabled_sites_unittest.cc
index 5fbcd27fbc9..4ff0e2e7415 100644
--- a/chromium/components/shared_highlighting/core/common/disabled_sites_unittest.cc
+++ b/chromium/components/shared_highlighting/core/common/disabled_sites_unittest.cc
@@ -56,5 +56,37 @@ TEST(DisabledSitesTest, AmpFeatureEnabled) {
EXPECT_TRUE(ShouldOfferLinkToText(GURL("https://google.com/amp/foo")));
}
+TEST(DisabledSitesTest, SupportsLinkGenerationInIframe) {
+ EXPECT_TRUE(SupportsLinkGenerationInIframe(
+ GURL("https://www.google.com/amp/www.nyt.com/ampthml/blogs.html")));
+ EXPECT_FALSE(
+ SupportsLinkGenerationInIframe(GURL("https://www.example.com/")));
+
+ EXPECT_TRUE(SupportsLinkGenerationInIframe(
+ GURL("https://mobile.google.com/amp/www.nyt.com/ampthml/blogs.html")));
+ EXPECT_FALSE(SupportsLinkGenerationInIframe(GURL("https://mobile.foo.com")));
+
+ EXPECT_TRUE(SupportsLinkGenerationInIframe(
+ GURL("https://m.google.com/amp/www.nyt.com/ampthml/blogs.html")));
+ EXPECT_FALSE(SupportsLinkGenerationInIframe(GURL("https://m.foo.com")));
+
+ EXPECT_TRUE(SupportsLinkGenerationInIframe(
+ GURL("https://www.bing.com/amp/www.nyt.com/ampthml/blogs.html")));
+ EXPECT_FALSE(SupportsLinkGenerationInIframe(GURL("https://www.nyt.com")));
+
+ EXPECT_TRUE(SupportsLinkGenerationInIframe(
+ GURL("https://mobile.bing.com/amp/www.nyt.com/ampthml/blogs.html")));
+ EXPECT_FALSE(SupportsLinkGenerationInIframe(GURL("https://mobile.nyt.com")));
+
+ EXPECT_TRUE(SupportsLinkGenerationInIframe(
+ GURL("https://m.bing.com/amp/www.nyt.com/ampthml/blogs.html")));
+ EXPECT_FALSE(SupportsLinkGenerationInIframe(GURL("https://m.nyt.com")));
+
+ EXPECT_FALSE(SupportsLinkGenerationInIframe(
+ GURL("https://www.google.com/www.nyt.com/ampthml/blogs.html")));
+ EXPECT_FALSE(SupportsLinkGenerationInIframe(
+ GURL("https://m.bing.com/a/www.nyt.com/ampthml/blogs.html")));
+}
+
} // namespace
} // namespace shared_highlighting
diff --git a/chromium/components/shared_highlighting/core/common/fragment_directives_utils_unittest.cc b/chromium/components/shared_highlighting/core/common/fragment_directives_utils_unittest.cc
index 11643166495..9e97cbd63fe 100644
--- a/chromium/components/shared_highlighting/core/common/fragment_directives_utils_unittest.cc
+++ b/chromium/components/shared_highlighting/core/common/fragment_directives_utils_unittest.cc
@@ -62,11 +62,13 @@ TEST(TextFragmentsUtilsTest, ParseTextFragments) {
GURL url_with_fragment(
"https://www.example.com/#idFrag:~:text=text%201&text=text%202");
base::Value result = ParseTextFragments(url_with_fragment);
- ASSERT_EQ(2u, result.GetList().size());
- EXPECT_EQ("text 1",
- result.GetList()[0].FindKey(kFragmentTextStartKey)->GetString());
- EXPECT_EQ("text 2",
- result.GetList()[1].FindKey(kFragmentTextStartKey)->GetString());
+ ASSERT_EQ(2u, result.GetListDeprecated().size());
+ EXPECT_EQ("text 1", result.GetListDeprecated()[0]
+ .FindKey(kFragmentTextStartKey)
+ ->GetString());
+ EXPECT_EQ("text 2", result.GetListDeprecated()[1]
+ .FindKey(kFragmentTextStartKey)
+ ->GetString());
GURL url_no_fragment("www.example.com");
base::Value empty_result = ParseTextFragments(url_no_fragment);
diff --git a/chromium/components/shared_highlighting/core/common/shared_highlighting_data_driven_test.cc b/chromium/components/shared_highlighting/core/common/shared_highlighting_data_driven_test.cc
index 63fbe74c6bf..016a4e36aa8 100644
--- a/chromium/components/shared_highlighting/core/common/shared_highlighting_data_driven_test.cc
+++ b/chromium/components/shared_highlighting/core/common/shared_highlighting_data_driven_test.cc
@@ -17,7 +17,7 @@
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
#include "base/mac/foundation_util.h"
#endif
@@ -81,9 +81,9 @@ SharedHighlightingDataDrivenTest::GetTestFiles() {
}
std::sort(files.begin(), files.end());
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
base::mac::ClearAmIBundledCache();
-#endif // defined(OS_MAC)
+#endif // BUILDFLAG(IS_MAC)
return files;
}
diff --git a/chromium/components/shared_highlighting/core/common/shared_highlighting_features.cc b/chromium/components/shared_highlighting/core/common/shared_highlighting_features.cc
index f2ae62ba239..abbe08a3528 100644
--- a/chromium/components/shared_highlighting/core/common/shared_highlighting_features.cc
+++ b/chromium/components/shared_highlighting/core/common/shared_highlighting_features.cc
@@ -14,11 +14,14 @@ constexpr base::FeatureParam<int> kPreemptiveLinkGenTimeoutLengthMs{
&kPreemptiveLinkToTextGeneration, "TimeoutLengthMs", 500};
const base::Feature kSharedHighlightingV2{"SharedHighlightingV2",
- base::FEATURE_DISABLED_BY_DEFAULT};
+ base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kSharedHighlightingAmp{"SharedHighlightingAmp",
base::FEATURE_ENABLED_BY_DEFAULT};
+const base::Feature kIOSSharedHighlightingV2{"IOSSharedHighlightingV2",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
int GetPreemptiveLinkGenTimeoutLengthMs() {
return kPreemptiveLinkGenTimeoutLengthMs.Get();
}
diff --git a/chromium/components/shared_highlighting/core/common/shared_highlighting_features.h b/chromium/components/shared_highlighting/core/common/shared_highlighting_features.h
index 56b737bbb13..144dfcf54ab 100644
--- a/chromium/components/shared_highlighting/core/common/shared_highlighting_features.h
+++ b/chromium/components/shared_highlighting/core/common/shared_highlighting_features.h
@@ -24,6 +24,9 @@ extern const base::Feature kSharedHighlightingV2;
// Enables shared highlighting for AMP viewers pages.
extern const base::Feature kSharedHighlightingAmp;
+// Feature flag that enable Shared Highlighting V2 in iOS.
+extern const base::Feature kIOSSharedHighlightingV2;
+
// Returns the pre-emptive link generation timeout length.
int GetPreemptiveLinkGenTimeoutLengthMs();
diff --git a/chromium/components/shared_highlighting/core/common/shared_highlighting_metrics.cc b/chromium/components/shared_highlighting/core/common/shared_highlighting_metrics.cc
index ba30c06a542..a29b7387b66 100644
--- a/chromium/components/shared_highlighting/core/common/shared_highlighting_metrics.cc
+++ b/chromium/components/shared_highlighting/core/common/shared_highlighting_metrics.cc
@@ -6,6 +6,7 @@
#include "base/metrics/histogram_functions.h"
#include "base/notreached.h"
+#include "base/strings/strcat.h"
#include "components/search_engines/search_engine_utils.h"
#include "services/metrics/public/cpp/ukm_builders.h"
@@ -13,6 +14,8 @@ namespace shared_highlighting {
namespace {
+constexpr char kUmaPrefix[] = "SharedHighlights.LinkGenerated";
+
TextFragmentLinkOpenSource GetLinkSource(const GURL& referrer) {
bool from_search_engine =
referrer.is_valid() && SearchEngineUtils::GetEngineType(referrer) > 0;
@@ -28,11 +31,36 @@ void LogDesktopLinkGenerationCopiedLinkType(LinkGenerationCopiedLinkType type) {
}
void LogLinkGenerationErrorReason(LinkGenerationError reason) {
+ DCHECK_NE(reason, LinkGenerationError::kNone);
base::UmaHistogramEnumeration("SharedHighlights.LinkGenerated.Error", reason);
}
-void LogLinkGenerationStatus(bool link_generated) {
- base::UmaHistogramBoolean("SharedHighlights.LinkGenerated", link_generated);
+void LogLinkRequestedErrorReason(LinkGenerationError reason) {
+ DCHECK_NE(reason, LinkGenerationError::kNone);
+ base::UmaHistogramEnumeration(
+ "SharedHighlights.LinkGenerated.Error.Requested", reason);
+}
+
+void LogLinkGenerationStatus(LinkGenerationStatus status) {
+ base::UmaHistogramBoolean("SharedHighlights.LinkGenerated",
+ status == LinkGenerationStatus::kSuccess);
+}
+
+void LogLinkRequestedStatus(LinkGenerationStatus status) {
+ base::UmaHistogramBoolean("SharedHighlights.LinkGenerated.Requested",
+ status == LinkGenerationStatus::kSuccess);
+}
+
+void LogRequestedSuccessMetrics(ukm::SourceId source_id) {
+ LogLinkRequestedStatus(LinkGenerationStatus::kSuccess);
+ LogLinkGeneratedRequestedSuccessUkmEvent(source_id);
+}
+
+void LogRequestedFailureMetrics(ukm::SourceId source_id,
+ LinkGenerationError error) {
+ LogLinkRequestedStatus(LinkGenerationStatus::kFailure);
+ LogLinkRequestedErrorReason(error);
+ LogLinkGeneratedRequestedErrorUkmEvent(source_id, error);
}
void LogTextFragmentAmbiguousMatch(bool ambiguous_match) {
@@ -61,31 +89,6 @@ void LogTextFragmentSelectorCount(int count) {
base::UmaHistogramCounts100("TextFragmentAnchor.SelectorCount", count);
}
-// TODO(gayane): Replace by one function LogGenerateError(Error).
-void LogGenerateErrorTabHidden() {
- LogLinkGenerationErrorReason(LinkGenerationError::kTabHidden);
-}
-
-void LogGenerateErrorOmniboxNavigation() {
- LogLinkGenerationErrorReason(LinkGenerationError::kOmniboxNavigation);
-}
-
-void LogGenerateErrorTabCrash() {
- LogLinkGenerationErrorReason(LinkGenerationError::kTabCrash);
-}
-
-void LogGenerateErrorIFrame() {
- LogLinkGenerationErrorReason(LinkGenerationError::kIFrame);
-}
-
-void LogGenerateErrorBlockList() {
- LogLinkGenerationErrorReason(LinkGenerationError::kBlockList);
-}
-
-void LogGenerateErrorTimeout() {
- LogLinkGenerationErrorReason(LinkGenerationError::kTimeout);
-}
-
void LogGenerateSuccessLatency(base::TimeDelta latency) {
base::UmaHistogramTimes("SharedHighlights.LinkGenerated.TimeToGenerate",
latency);
@@ -96,6 +99,11 @@ void LogGenerateErrorLatency(base::TimeDelta latency) {
latency);
}
+void LogLinkToTextReshareStatus(LinkToTextReshareStatus status) {
+ base::UmaHistogramEnumeration("SharedHighlights.ObtainReshareLink.Status",
+ status);
+}
+
void LogLinkOpenedUkmEvent(ukm::SourceId source_id,
const GURL& referrer,
bool success) {
@@ -146,4 +154,40 @@ void LogLinkGeneratedErrorUkmEvent(ukm::UkmRecorder* recorder,
}
}
+void LogLinkGeneratedRequestedSuccessUkmEvent(ukm::SourceId source_id) {
+ ukm::UkmRecorder* recorder = ukm::UkmRecorder::Get();
+
+ DCHECK(recorder);
+ if (source_id != ukm::kInvalidSourceId) {
+ ukm::builders::SharedHighlights_LinkGenerated_Requested(source_id)
+ .SetSuccess(true)
+ .Record(recorder);
+ }
+}
+
+void LogLinkGeneratedRequestedErrorUkmEvent(ukm::SourceId source_id,
+ LinkGenerationError reason) {
+ ukm::UkmRecorder* recorder = ukm::UkmRecorder::Get();
+
+ DCHECK(recorder);
+ if (source_id != ukm::kInvalidSourceId) {
+ ukm::builders::SharedHighlights_LinkGenerated_Requested(source_id)
+ .SetSuccess(false)
+ .SetError(static_cast<int64_t>(reason))
+ .Record(recorder);
+ }
+}
+
+void LogLinkRequestedBeforeStatus(LinkGenerationStatus status,
+ LinkGenerationReadyStatus ready_status) {
+ std::string uma_name;
+ if (ready_status == LinkGenerationReadyStatus::kRequestedBeforeReady) {
+ uma_name = base::StrCat({kUmaPrefix, ".RequestedBeforeReady"});
+ } else {
+ uma_name = base::StrCat({kUmaPrefix, ".RequestedAfterReady"});
+ }
+ bool success = status == LinkGenerationStatus::kSuccess;
+ base::UmaHistogramBoolean(uma_name, success);
+}
+
} // namespace shared_highlighting
diff --git a/chromium/components/shared_highlighting/core/common/shared_highlighting_metrics.h b/chromium/components/shared_highlighting/core/common/shared_highlighting_metrics.h
index ec128930401..7830b48f8a6 100644
--- a/chromium/components/shared_highlighting/core/common/shared_highlighting_metrics.h
+++ b/chromium/components/shared_highlighting/core/common/shared_highlighting_metrics.h
@@ -12,6 +12,19 @@
namespace shared_highlighting {
+// Used to indicate whether link generation complited successfully.
+// Java counterpart will be auto-generated for this enum.
+// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.share.link_to_text
+enum class LinkGenerationStatus { kSuccess = 0, kFailure = 1 };
+
+// Used to indicate whether generated link was ready at the time of the request.
+// Java counterpart will be auto-generated for this enum.
+// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.share.link_to_text
+enum class LinkGenerationReadyStatus {
+ kRequestedBeforeReady = 0,
+ kRequestedAfterReady = 1
+};
+
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
// The type of copied Shared Highlighting Link on Desktop.
@@ -26,7 +39,11 @@ enum class LinkGenerationCopiedLinkType {
// numeric values should never be reused.
// The type of errors that can happen during link generation.
// Update corresponding |LinkGenerationError| in enums.xml.
+// Java counterpart will be auto-generated for this enum.
+// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.share.link_to_text
enum class LinkGenerationError {
+ kNone = -1,
+
kIncorrectSelector = 0,
kNoRange = 1,
kNoContext = 2,
@@ -52,7 +69,15 @@ enum class LinkGenerationError {
// Recorded on Android/Desktop.
kBlockList = 12,
- kMaxValue = kBlockList
+ // Link to text cannot be requested because connection with the renderer side
+ // cannot be established. Android only.
+ kNoRemoteConnection = 13,
+
+ // TODO(crbug.com/1301794): This shouldn't happen, but sometimes browser side
+ // requests link to text when generation was never started.
+ kNotGenerated = 14,
+
+ kMaxValue = kNotGenerated
};
// These values are persisted to logs. Entries should not be renumbered and
@@ -65,14 +90,44 @@ enum class TextFragmentLinkOpenSource {
kMaxValue = kSearchEngine,
};
+// These values are persisted in histograms. Entries should not be renumbered
+// and numeric values should never be reused. The status of link to text reshare
+// attempt. Update corresponding |LinkToTextReshareStatus| in enums.xml.
+// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.share.link_to_text
+enum class LinkToTextReshareStatus {
+ kSuccess = 0,
+ kNoRemoteConnection = 1,
+ kTabHidden = 2,
+ kOmniboxNavigation = 3,
+ kTabCrash = 4,
+ kTimeout = 5,
+ kEmptySelector = 6,
+
+ kMaxValue = kEmptySelector,
+};
+
// Records the type of link generation that was copied on desktop.
void LogDesktopLinkGenerationCopiedLinkType(LinkGenerationCopiedLinkType type);
// Records the reason why the link generation failed.
void LogLinkGenerationErrorReason(LinkGenerationError reason);
+// Records the reason why the link to text was not available for the user.
+void LogLinkRequestedErrorReason(LinkGenerationError reason);
+
// Records whether the link generation attempt was successful or not.
-void LogLinkGenerationStatus(bool link_generated);
+void LogLinkGenerationStatus(LinkGenerationStatus status);
+
+// Records whether the generated link to text was available for the user.
+void LogLinkRequestedStatus(LinkGenerationStatus status);
+
+// Records metrics when successfully generated link to text was available for
+// the user.
+void LogRequestedSuccessMetrics(ukm::SourceId source_id);
+
+// Records metrics when link to text was not available for the user.
+void LogRequestedFailureMetrics(ukm::SourceId source_id,
+ LinkGenerationError error);
// Records whether an individual text fragment could not be scrolled to because
// there was an |ambiguous_match| (generally because more than one matching
@@ -90,33 +145,15 @@ void LogTextFragmentMatchRate(int matches, int text_fragments);
// Records the total |count| of text fragment selectors in the URL param.
void LogTextFragmentSelectorCount(int count);
-// Records when tab is hidden before generation is complete.
-void LogGenerateErrorTabHidden();
-
-// Records when new navigation happens on the tab by user typing in the omnibox.
-void LogGenerateErrorOmniboxNavigation();
-
-// Records when tab crashes before generation is complete.
-void LogGenerateErrorTabCrash();
-
-// Records when link generation was not completed because selection happened on
-// iframe.
-void LogGenerateErrorIFrame();
-
-// Records when link generation was not triggered because selection happened on
-// a blocklisted page.
-void LogGenerateErrorBlockList();
-
-// Records when link generation was not triggered because selection happened on
-// a blocklisted page.
-void LogGenerateErrorTimeout();
-
// Records the latency for successfully generating a link.
void LogGenerateSuccessLatency(base::TimeDelta latency);
// Records the latency for failing to generate a link.
void LogGenerateErrorLatency(base::TimeDelta latency);
+// Records the outcome of link to text reshare attempt.
+void LogLinkToTextReshareStatus(LinkToTextReshareStatus status);
+
// Records a UKM event for opening a link with text fragments. |source_id|
// refers to the navigation action's ID, |referrer| will be used to record the
// source and |success| should be true only if fragments highlighting was a
@@ -168,6 +205,25 @@ void LogLinkGeneratedErrorUkmEvent(ukm::UkmRecorder* recorder,
ukm::SourceId source_id,
LinkGenerationError reason);
+// Records a UKM event when link with text fragments was available for the user.
+// |source_id| refers to the current frame, and this function will record using
+// the static Recorder. This API can only be used when calling from the browser
+// process, otherwise no event will be recorded.
+void LogLinkGeneratedRequestedSuccessUkmEvent(ukm::SourceId source_id);
+
+// Records a UKM event when link with text fragments was not available for the
+// user. |source_id| refers to the current frame and |reason| highlights the
+// cause of the failure. This function will record using the static Recorder.
+// This API can only be used when calling from the browser process, otherwise no
+// event will be recorded.
+void LogLinkGeneratedRequestedErrorUkmEvent(ukm::SourceId source_id,
+ LinkGenerationError reason);
+
+// Records whether link to text was requested before or after link generation
+// was complete with corresponding success status.
+void LogLinkRequestedBeforeStatus(LinkGenerationStatus status,
+ LinkGenerationReadyStatus ready_status);
+
} // namespace shared_highlighting
#endif // COMPONENTS_SHARED_HIGHLIGHTING_CORE_COMMON_SHARED_HIGHLIGHTING_METRICS_H_
diff --git a/chromium/components/shared_highlighting/core/common/shared_highlighting_metrics_unittest.cc b/chromium/components/shared_highlighting/core/common/shared_highlighting_metrics_unittest.cc
index 48d9b02a6c5..66f5454f7df 100644
--- a/chromium/components/shared_highlighting/core/common/shared_highlighting_metrics_unittest.cc
+++ b/chromium/components/shared_highlighting/core/common/shared_highlighting_metrics_unittest.cc
@@ -104,11 +104,11 @@ TEST_F(SharedHighlightingMetricsTest, LogTextFragmentSelectorCount) {
}
TEST_F(SharedHighlightingMetricsTest, LogLinkGenerationStatus) {
- LogLinkGenerationStatus(true);
+ LogLinkGenerationStatus(LinkGenerationStatus::kSuccess);
histogram_tester_.ExpectUniqueSample("SharedHighlights.LinkGenerated", true,
1);
- LogLinkGenerationStatus(false);
+ LogLinkGenerationStatus(LinkGenerationStatus::kFailure);
histogram_tester_.ExpectBucketCount("SharedHighlights.LinkGenerated", false,
1);
histogram_tester_.ExpectTotalCount("SharedHighlights.LinkGenerated", 2);
@@ -126,22 +126,6 @@ TEST_F(SharedHighlightingMetricsTest, LogLinkGenerationErrorReason) {
histogram_tester_.ExpectTotalCount("SharedHighlights.LinkGenerated.Error", 2);
}
-TEST_F(SharedHighlightingMetricsTest, LogAndroidLinkGenerationErrorReason) {
- LogGenerateErrorTabHidden();
- histogram_tester_.ExpectBucketCount("SharedHighlights.LinkGenerated.Error",
- LinkGenerationError::kTabHidden, 1);
-
- LogGenerateErrorOmniboxNavigation();
- histogram_tester_.ExpectBucketCount("SharedHighlights.LinkGenerated.Error",
- LinkGenerationError::kOmniboxNavigation,
- 1);
-
- LogGenerateErrorTabCrash();
- histogram_tester_.ExpectBucketCount("SharedHighlights.LinkGenerated.Error",
- LinkGenerationError::kTabCrash, 1);
- histogram_tester_.ExpectTotalCount("SharedHighlights.LinkGenerated.Error", 3);
-}
-
TEST_F(SharedHighlightingMetricsTest, LinkOpenedUkmSuccessSearchEngine) {
ukm::TestAutoSetUkmRecorder ukm_recorder;
ukm::SourceId source_id = 1;
@@ -298,6 +282,114 @@ TEST_F(SharedHighlightingMetricsTest, LinkGeneratedErrorLatency) {
"SharedHighlights.LinkGenerated.Error.TimeToGenerate", test_delta, 1);
}
+// Tests all the metrics that need to be recorded in case of a failure.
+TEST_F(SharedHighlightingMetricsTest, LogRequestedFailureMetrics) {
+ ukm::TestAutoSetUkmRecorder ukm_recorder;
+ ukm::SourceId source_id = 1;
+ LogRequestedFailureMetrics(source_id, LinkGenerationError::kEmptySelection);
+
+ histogram_tester_.ExpectBucketCount(
+ "SharedHighlights.LinkGenerated.Requested", false, 1);
+ histogram_tester_.ExpectTotalCount("SharedHighlights.LinkGenerated.Requested",
+ 1);
+ histogram_tester_.ExpectBucketCount(
+ "SharedHighlights.LinkGenerated.Error.Requested",
+ LinkGenerationError::kEmptySelection, 1);
+ histogram_tester_.ExpectTotalCount(
+ "SharedHighlights.LinkGenerated.Error.Requested", 1);
+
+ // Check UKM
+ auto entries = ukm_recorder.GetEntriesByName(
+ ukm::builders::SharedHighlights_LinkGenerated_Requested::kEntryName);
+ ASSERT_EQ(1u, entries.size());
+ const ukm::mojom::UkmEntry* entry = entries[0];
+ EXPECT_EQ(source_id, entry->source_id);
+ ukm_recorder.ExpectEntryMetric(entry, kSuccessUkmMetric, false);
+ ukm_recorder.ExpectEntryMetric(
+ entry, kErrorUkmMetric,
+ static_cast<int64_t>(LinkGenerationError::kEmptySelection));
+}
+
+// Tests all the metrics that need to be recorded in case of a success.
+TEST_F(SharedHighlightingMetricsTest, LogRequestedSuccessMetrics) {
+ ukm::TestAutoSetUkmRecorder ukm_recorder;
+ ukm::SourceId source_id = 1;
+ LogRequestedSuccessMetrics(source_id);
+
+ histogram_tester_.ExpectBucketCount(
+ "SharedHighlights.LinkGenerated.Requested", true, 1);
+ histogram_tester_.ExpectTotalCount("SharedHighlights.LinkGenerated.Requested",
+ 1);
+
+ // Check UKM
+ auto entries = ukm_recorder.GetEntriesByName(
+ ukm::builders::SharedHighlights_LinkGenerated_Requested::kEntryName);
+ ASSERT_EQ(1u, entries.size());
+ const ukm::mojom::UkmEntry* entry = entries[0];
+ EXPECT_EQ(source_id, entry->source_id);
+ ukm_recorder.ExpectEntryMetric(entry, kSuccessUkmMetric, true);
+ EXPECT_FALSE(ukm_recorder.GetEntryMetric(entry, kErrorUkmMetric));
+}
+
+// Tests that requested before or after histogram is correctly recorded.
+TEST_F(SharedHighlightingMetricsTest, LogLinkRequestedBeforeStatus) {
+ LogLinkRequestedBeforeStatus(
+ LinkGenerationStatus::kSuccess,
+ LinkGenerationReadyStatus::kRequestedBeforeReady);
+
+ histogram_tester_.ExpectBucketCount(
+ "SharedHighlights.LinkGenerated.RequestedBeforeReady", true, 1);
+ histogram_tester_.ExpectTotalCount(
+ "SharedHighlights.LinkGenerated.RequestedBeforeReady", 1);
+ histogram_tester_.ExpectTotalCount(
+ "SharedHighlights.LinkGenerated.RequestedAfterReady", 0);
+
+ LogLinkRequestedBeforeStatus(
+ LinkGenerationStatus::kFailure,
+ LinkGenerationReadyStatus::kRequestedBeforeReady);
+ histogram_tester_.ExpectBucketCount(
+ "SharedHighlights.LinkGenerated.RequestedBeforeReady", false, 1);
+ histogram_tester_.ExpectTotalCount(
+ "SharedHighlights.LinkGenerated.RequestedBeforeReady", 2);
+ histogram_tester_.ExpectTotalCount(
+ "SharedHighlights.LinkGenerated.RequestedAfterReady", 0);
+
+ LogLinkRequestedBeforeStatus(LinkGenerationStatus::kSuccess,
+ LinkGenerationReadyStatus::kRequestedAfterReady);
+ histogram_tester_.ExpectTotalCount(
+ "SharedHighlights.LinkGenerated.RequestedBeforeReady", 2);
+ histogram_tester_.ExpectBucketCount(
+ "SharedHighlights.LinkGenerated.RequestedAfterReady", true, 1);
+ histogram_tester_.ExpectTotalCount(
+ "SharedHighlights.LinkGenerated.RequestedAfterReady", 1);
+
+ LogLinkRequestedBeforeStatus(LinkGenerationStatus::kFailure,
+ LinkGenerationReadyStatus::kRequestedAfterReady);
+ histogram_tester_.ExpectTotalCount(
+ "SharedHighlights.LinkGenerated.RequestedBeforeReady", 2);
+ histogram_tester_.ExpectBucketCount(
+ "SharedHighlights.LinkGenerated.RequestedAfterReady", false, 1);
+ histogram_tester_.ExpectTotalCount(
+ "SharedHighlights.LinkGenerated.RequestedAfterReady", 2);
+}
+
+// Tests that link generation failure latency logs to the right histogram.
+TEST_F(SharedHighlightingMetricsTest, LogLinkToTextReshareStatus) {
+ LogLinkToTextReshareStatus(LinkToTextReshareStatus::kSuccess);
+ histogram_tester_.ExpectBucketCount(
+ "SharedHighlights.ObtainReshareLink.Status",
+ LinkToTextReshareStatus::kSuccess, 1);
+ histogram_tester_.ExpectTotalCount(
+ "SharedHighlights.ObtainReshareLink.Status", 1);
+
+ LogLinkToTextReshareStatus(LinkToTextReshareStatus::kTimeout);
+ histogram_tester_.ExpectBucketCount(
+ "SharedHighlights.ObtainReshareLink.Status",
+ LinkToTextReshareStatus::kTimeout, 1);
+ histogram_tester_.ExpectTotalCount(
+ "SharedHighlights.ObtainReshareLink.Status", 2);
+}
+
} // namespace
} // namespace shared_highlighting
diff --git a/chromium/components/shared_highlighting/ios/BUILD.gn b/chromium/components/shared_highlighting/ios/BUILD.gn
new file mode 100644
index 00000000000..b6f511a236d
--- /dev/null
+++ b/chromium/components/shared_highlighting/ios/BUILD.gn
@@ -0,0 +1,32 @@
+# Copyright 2022 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.
+
+source_set("ios") {
+ configs += [ "//build/config/compiler:enable_arc" ]
+ sources = [
+ "parsing_utils.h",
+ "parsing_utils.mm",
+ "shared_highlighting_constants.h",
+ "shared_highlighting_constants.mm",
+ ]
+
+ deps = [
+ "//base",
+ "//ios/web/public",
+ "//ios/web/public/ui",
+ "//url",
+ ]
+}
+
+source_set("unit_tests") {
+ configs += [ "//build/config/compiler:enable_arc" ]
+ testonly = true
+ sources = [ "parsing_utils_unittest.mm" ]
+ deps = [
+ ":ios",
+ "//base/test:test_support",
+ "//testing/gtest",
+ "//url",
+ ]
+}
diff --git a/chromium/components/shared_highlighting/ios/DEPS b/chromium/components/shared_highlighting/ios/DEPS
new file mode 100644
index 00000000000..0fc0ddddacd
--- /dev/null
+++ b/chromium/components/shared_highlighting/ios/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+ios/web/public",
+]
diff --git a/chromium/components/shared_highlighting/ios/parsing_utils.h b/chromium/components/shared_highlighting/ios/parsing_utils.h
new file mode 100644
index 00000000000..f8457b5230d
--- /dev/null
+++ b/chromium/components/shared_highlighting/ios/parsing_utils.h
@@ -0,0 +1,43 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_SHARED_HIGHLIGHTING_IOS_PARSING_UTILS_H_
+#define COMPONENTS_SHARED_HIGHLIGHTING_IOS_PARSING_UTILS_H_
+
+#import <string>
+
+#import <CoreGraphics/CoreGraphics.h>
+
+#import "third_party/abseil-cpp/absl/types/optional.h"
+#import "url/gurl.h"
+
+namespace base {
+class Value;
+} // namespace base
+
+namespace web {
+class WebState;
+} // namespace web
+
+namespace shared_highlighting {
+
+// Returns whether |value| is a dictionary value, and is not empty.
+BOOL IsValidDictValue(const base::Value* value);
+
+// Attempts to parse the given |value| into a CGRect. If |value| does not map
+// into the expected structure, an empty absl::optional instance will be
+// returned.
+absl::optional<CGRect> ParseRect(const base::Value* value);
+
+// Attempts to parse the given |url_value| into a GURL instance. If |url_value|
+// is empty or invalid, an empty absl::optional instance will be returned.
+absl::optional<GURL> ParseURL(const std::string* url_value);
+
+// Converts a given |web_view_rect| into its browser coordinates counterpart.
+// Uses the given |web_state| to do the conversion.
+CGRect ConvertToBrowserRect(CGRect web_view_rect, web::WebState* web_state);
+
+} // namespace shared_highlighting
+
+#endif // COMPONENTS_SHARED_HIGHLIGHTING_IOS_PARSING_UTILS_H_
diff --git a/chromium/components/shared_highlighting/ios/parsing_utils.mm b/chromium/components/shared_highlighting/ios/parsing_utils.mm
new file mode 100644
index 00000000000..77ebb67e360
--- /dev/null
+++ b/chromium/components/shared_highlighting/ios/parsing_utils.mm
@@ -0,0 +1,76 @@
+// Copyright 2022 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.
+
+#import "components/shared_highlighting/ios/parsing_utils.h"
+
+#import "base/values.h"
+#import "ios/web/public/ui/crw_web_view_proxy.h"
+#import "ios/web/public/ui/crw_web_view_scroll_view_proxy.h"
+#import "ios/web/public/web_state.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace {
+const CGFloat kCaretWidth = 4.0;
+} // namespace
+
+namespace shared_highlighting {
+
+BOOL IsValidDictValue(const base::Value* value) {
+ return value && value->is_dict() && !value->DictEmpty();
+}
+
+absl::optional<CGRect> ParseRect(const base::Value* value) {
+ if (!IsValidDictValue(value)) {
+ return absl::nullopt;
+ }
+
+ const base::Value* xValue =
+ value->FindKeyOfType("x", base::Value::Type::DOUBLE);
+ const base::Value* yValue =
+ value->FindKeyOfType("y", base::Value::Type::DOUBLE);
+ const base::Value* widthValue =
+ value->FindKeyOfType("width", base::Value::Type::DOUBLE);
+ const base::Value* heightValue =
+ value->FindKeyOfType("height", base::Value::Type::DOUBLE);
+
+ if (!xValue || !yValue || !widthValue || !heightValue) {
+ return absl::nullopt;
+ }
+
+ return CGRectMake(xValue->GetDouble(), yValue->GetDouble(),
+ widthValue->GetDouble(), heightValue->GetDouble());
+}
+
+absl::optional<GURL> ParseURL(const std::string* url_value) {
+ if (!url_value) {
+ return absl::nullopt;
+ }
+
+ GURL url(*url_value);
+ if (!url.is_empty() && url.is_valid()) {
+ return url;
+ }
+
+ return absl::nullopt;
+}
+
+CGRect ConvertToBrowserRect(CGRect web_view_rect, web::WebState* web_state) {
+ if (CGRectEqualToRect(web_view_rect, CGRectZero) || !web_state) {
+ return web_view_rect;
+ }
+
+ id<CRWWebViewProxy> web_view_proxy = web_state->GetWebViewProxy();
+ CGFloat zoom_scale = web_view_proxy.scrollViewProxy.zoomScale;
+ UIEdgeInsets inset = web_view_proxy.scrollViewProxy.contentInset;
+
+ return CGRectMake((web_view_rect.origin.x * zoom_scale) + inset.left,
+ (web_view_rect.origin.y * zoom_scale) + inset.top,
+ (web_view_rect.size.width * zoom_scale) + kCaretWidth,
+ web_view_rect.size.height * zoom_scale);
+}
+
+} // namespace shared_highlighting
diff --git a/chromium/components/shared_highlighting/ios/parsing_utils_unittest.mm b/chromium/components/shared_highlighting/ios/parsing_utils_unittest.mm
new file mode 100644
index 00000000000..7e05816d5e4
--- /dev/null
+++ b/chromium/components/shared_highlighting/ios/parsing_utils_unittest.mm
@@ -0,0 +1,74 @@
+// Copyright 2022 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.
+
+#import "components/shared_highlighting/ios/parsing_utils.h"
+
+#import <CoreGraphics/CoreGraphics.h>
+
+#import "base/values.h"
+#import "testing/gtest/include/gtest/gtest.h"
+#import "testing/platform_test.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+typedef PlatformTest ParsingUtilsTest;
+
+namespace shared_highlighting {
+
+// Tests the ParseRect utility function.
+TEST_F(ParsingUtilsTest, ParseRect) {
+ CGRect expected_rect = CGRectMake(1, 2, 3, 4);
+ base::Value rect_value = base::Value(base::Value::Type::DICTIONARY);
+ rect_value.SetDoubleKey("x", expected_rect.origin.x);
+ rect_value.SetDoubleKey("y", expected_rect.origin.y);
+ rect_value.SetDoubleKey("width", expected_rect.size.width);
+ rect_value.SetDoubleKey("height", expected_rect.size.height);
+
+ absl::optional<CGRect> opt_rect = ParseRect(&rect_value);
+ ASSERT_TRUE(opt_rect.has_value());
+ EXPECT_TRUE(CGRectEqualToRect(expected_rect, opt_rect.value()));
+
+ // Invalid values.
+ EXPECT_FALSE(ParseRect(nil).has_value());
+ base::Value string_value = base::Value(base::Value::Type::STRING);
+ EXPECT_FALSE(ParseRect(&string_value).has_value());
+ base::Value empty_dict_value = base::Value(base::Value::Type::DICTIONARY);
+ EXPECT_FALSE(ParseRect(&empty_dict_value).has_value());
+
+ base::Value copied_value = rect_value.Clone();
+ copied_value.RemoveKey("x");
+ EXPECT_FALSE(ParseRect(&copied_value).has_value());
+
+ copied_value = rect_value.Clone();
+ copied_value.RemoveKey("y");
+ EXPECT_FALSE(ParseRect(&copied_value).has_value());
+
+ copied_value = rect_value.Clone();
+ copied_value.RemoveKey("width");
+ EXPECT_FALSE(ParseRect(&copied_value).has_value());
+
+ copied_value = rect_value.Clone();
+ copied_value.RemoveKey("height");
+ EXPECT_FALSE(ParseRect(&copied_value).has_value());
+}
+
+// Tests for the ParseURL utility function.
+TEST_F(ParsingUtilsTest, ParseURL) {
+ EXPECT_FALSE(ParseURL(nil).has_value());
+
+ std::string empty_str = "";
+ EXPECT_FALSE(ParseURL(&empty_str).has_value());
+
+ std::string invalid_url_str = "abcd";
+ EXPECT_FALSE(ParseURL(&invalid_url_str).has_value());
+
+ std::string valid_url_str = "https://www.example.com/";
+ absl::optional<GURL> valid_url = ParseURL(&valid_url_str);
+ EXPECT_TRUE(valid_url.has_value());
+ EXPECT_EQ(GURL(valid_url_str).spec(), valid_url.value().spec());
+}
+
+} // namespace shared_highlighting
diff --git a/chromium/components/shared_highlighting/ios/shared_highlighting_constants.h b/chromium/components/shared_highlighting/ios/shared_highlighting_constants.h
new file mode 100644
index 00000000000..866650e49ab
--- /dev/null
+++ b/chromium/components/shared_highlighting/ios/shared_highlighting_constants.h
@@ -0,0 +1,15 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_SHARED_HIGHLIGHTING_IOS_SHARED_HIGHLIGHTING_CONSTANTS_H_
+#define COMPONENTS_SHARED_HIGHLIGHTING_IOS_SHARED_HIGHLIGHTING_CONSTANTS_H_
+
+namespace shared_highlighting {
+
+// The URL pointing to a help article about shared highlighting.
+const extern char kLearnMoreUrl[];
+
+} // namespace shared_highlighting
+
+#endif // COMPONENTS_SHARED_HIGHLIGHTING_IOS_SHARED_HIGHLIGHTING_CONSTANTS_H_
diff --git a/chromium/components/shared_highlighting/ios/shared_highlighting_constants.mm b/chromium/components/shared_highlighting/ios/shared_highlighting_constants.mm
new file mode 100644
index 00000000000..1247af7f277
--- /dev/null
+++ b/chromium/components/shared_highlighting/ios/shared_highlighting_constants.mm
@@ -0,0 +1,16 @@
+// Copyright 2022 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.
+
+#import "components/shared_highlighting/ios/shared_highlighting_constants.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace shared_highlighting {
+
+const char kLearnMoreUrl[] =
+ "https://support.google.com/chrome/?p=shared_highlighting";
+
+} // namespace shared_highlighting
diff --git a/chromium/components/signin/core/browser/BUILD.gn b/chromium/components/signin/core/browser/BUILD.gn
index d577cf2baf7..64c2d2bf6f1 100644
--- a/chromium/components/signin/core/browser/BUILD.gn
+++ b/chromium/components/signin/core/browser/BUILD.gn
@@ -98,6 +98,12 @@ static_library("browser") {
"//chromeos/crosapi/mojom",
"//chromeos/lacros",
]
+ sources += [
+ "consistency_cookie_manager.cc",
+ "consistency_cookie_manager.h",
+ "mirror_landing_account_reconcilor_delegate.cc",
+ "mirror_landing_account_reconcilor_delegate.h",
+ ]
}
if (!enable_dice_support) {
@@ -162,6 +168,10 @@ source_set("unit_tests") {
"//chromeos/lacros",
"//chromeos/lacros:test_support",
]
+ sources += [
+ "consistency_cookie_manager_unittest.cc",
+ "mirror_landing_account_reconcilor_delegate_unittest.cc",
+ ]
}
if (!enable_dice_support) {
diff --git a/chromium/components/signin/core/browser/account_investigator_unittest.cc b/chromium/components/signin/core/browser/account_investigator_unittest.cc
index d6b28c25d49..a43cd77de5e 100644
--- a/chromium/components/signin/core/browser/account_investigator_unittest.cc
+++ b/chromium/components/signin/core/browser/account_investigator_unittest.cc
@@ -393,7 +393,7 @@ TEST_F(AccountInvestigatorTest, TryPeriodicReportWithPrimary) {
}
// Neither iOS nor Android support unconsented primary accounts.
-#if !defined(OS_IOS) && !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_IOS) && !BUILDFLAG(IS_ANDROID)
TEST_F(AccountInvestigatorTest, TryPeriodicReportWithUnconsentedPrimary) {
investigator()->Initialize();
@@ -413,7 +413,7 @@ TEST_F(AccountInvestigatorTest, TryPeriodicReportWithUnconsentedPrimary) {
"Signin.CookieJar.SignedInCountWithPrimary.SyncConsumer",
/*count=*/0);
}
-#endif // !defined(OS_IOS) && !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_IOS) && !BUILDFLAG(IS_ANDROID)
TEST_F(AccountInvestigatorTest, TryPeriodicReportWithEnterprisePrimary) {
investigator()->Initialize();
diff --git a/chromium/components/signin/core/browser/account_reconcilor.cc b/chromium/components/signin/core/browser/account_reconcilor.cc
index 2319062bb55..cf5b71c5079 100644
--- a/chromium/components/signin/core/browser/account_reconcilor.cc
+++ b/chromium/components/signin/core/browser/account_reconcilor.cc
@@ -22,7 +22,6 @@
#include "base/strings/string_util.h"
#include "base/task/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
-#include "build/build_config.h"
#include "components/content_settings/core/browser/content_settings_observer.h"
#include "components/signin/core/browser/account_reconcilor_delegate.h"
#include "components/signin/public/base/account_consistency_method.h"
@@ -225,7 +224,7 @@ void AccountReconcilor::EnableReconcile() {
void AccountReconcilor::DisableReconcile(bool logout_all_accounts) {
AbortReconcile();
- SetState(AccountReconcilorState::ACCOUNT_RECONCILOR_OK);
+ SetState(AccountReconcilorState::ACCOUNT_RECONCILOR_INACTIVE);
UnregisterWithAllDependencies();
if (logout_all_accounts)
@@ -284,7 +283,7 @@ void AccountReconcilor::UnregisterWithIdentityManager() {
registered_with_identity_manager_ = false;
}
-AccountReconcilorState AccountReconcilor::GetState() {
+AccountReconcilorState AccountReconcilor::GetState() const {
return state_;
}
@@ -389,7 +388,7 @@ void AccountReconcilor::StartReconcile(Trigger trigger) {
CHECK(client_);
if (!delegate_->IsReconcileEnabled() || !client_->AreSigninCookiesAllowed()) {
VLOG(1) << "AccountReconcilor::StartReconcile: !enabled or no cookies";
- SetState(AccountReconcilorState::ACCOUNT_RECONCILOR_OK);
+ SetState(AccountReconcilorState::ACCOUNT_RECONCILOR_INACTIVE);
return;
}
@@ -663,13 +662,13 @@ AccountReconcilor::LoadValidAccountsFromTokenService() const {
void AccountReconcilor::OnReceivedManageAccountsResponse(
signin::GAIAServiceType service_type) {
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS)
// TODO(https://crbug.com/1224872): check if it's still required on Android
// and iOS.
if (service_type == signin::GAIA_SERVICE_TYPE_ADDSESSION) {
identity_manager_->GetAccountsCookieMutator()->TriggerCookieJarUpdate();
}
-#endif // !defined(OS_CHROMEOS)
+#endif // !BUILDFLAG(IS_CHROMEOS)
}
void AccountReconcilor::AbortReconcile() {
diff --git a/chromium/components/signin/core/browser/account_reconcilor.h b/chromium/components/signin/core/browser/account_reconcilor.h
index 3a0b0974fcc..ac10b0d4c74 100644
--- a/chromium/components/signin/core/browser/account_reconcilor.h
+++ b/chromium/components/signin/core/browser/account_reconcilor.h
@@ -16,6 +16,8 @@
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "build/build_config.h"
+#include "build/buildflag.h"
+#include "build/chromeos_buildflags.h"
#include "components/content_settings/core/browser/content_settings_observer.h"
#include "components/content_settings/core/common/content_settings_pattern.h"
#include "components/keyed_service/core/keyed_service.h"
@@ -30,6 +32,10 @@
namespace signin {
class AccountReconcilorDelegate;
enum class SetAccountsInCookieResult;
+
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+class ConsistencyCookieManagerTest;
+#endif
}
class SigninClient;
@@ -121,7 +127,7 @@ class AccountReconcilor : public KeyedService,
void Shutdown() override;
// Determine what the reconcilor is currently doing.
- signin_metrics::AccountReconcilorState GetState();
+ signin_metrics::AccountReconcilorState GetState() const;
// Adds ands removes observers.
void AddObserver(Observer* observer);
@@ -141,10 +147,15 @@ class AccountReconcilor : public KeyedService,
private:
friend class AccountReconcilorTest;
- friend class DiceBrowserTest;
- friend class BaseAccountReconcilorTestTable;
- friend class AccountReconcilorThrottlerTest;
friend class AccountReconcilorTestForceDiceMigration;
+ friend class AccountReconcilorThrottlerTest;
+ friend class BaseAccountReconcilorTestTable;
+ friend class DiceBrowserTest;
+
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+ friend class signin::ConsistencyCookieManagerTest;
+#endif
+
FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTestForceDiceMigration,
TableRowTestCheckNoOp);
FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorTest,
@@ -422,8 +433,11 @@ class AccountReconcilor : public KeyedService,
// not invalidate the primary token while this is happening.
int synced_data_deletion_in_progress_count_ = 0;
+ // Note: when the reconcilor is blocked with `BlockReconcile()` the state is
+ // set to ACCOUNT_RECONCILOR_SCHEDULED rather than ACCOUNT_RECONCILOR_INACTIVE
+ // as this is only used to temporarily suspend the reconcilor.
signin_metrics::AccountReconcilorState state_ =
- signin_metrics::ACCOUNT_RECONCILOR_OK;
+ signin_metrics::ACCOUNT_RECONCILOR_INACTIVE;
// Set to true when Shutdown() is called.
bool was_shut_down_ = false;
diff --git a/chromium/components/signin/core/browser/chrome_connected_header_helper.cc b/chromium/components/signin/core/browser/chrome_connected_header_helper.cc
index e252a6805ee..78876a115e0 100644
--- a/chromium/components/signin/core/browser/chrome_connected_header_helper.cc
+++ b/chromium/components/signin/core/browser/chrome_connected_header_helper.cc
@@ -15,6 +15,7 @@
#include "build/chromeos_buildflags.h"
#include "components/google/core/common/google_util.h"
#include "components/signin/core/browser/cookie_settings_util.h"
+#include "components/signin/public/base/signin_switches.h"
#include "components/signin/public/identity_manager/tribool.h"
#include "google_apis/gaia/gaia_auth_util.h"
#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
@@ -41,7 +42,7 @@ const char kProfileModeAttrName[] = "mode";
const char kServiceTypeAttrName[] = "action";
const char kSupervisedAttrName[] = "supervised";
const char kSourceAttrName[] = "source";
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
const char kEligibleForConsistency[] = "eligible_for_consistency";
const char kShowConsistencyPromo[] = "show_consistency_promo";
#endif
@@ -110,7 +111,7 @@ ManageAccountsParams ChromeConnectedHeaderHelper::BuildManageAccountsParams(
params.continue_url = value;
} else if (key_name == kIsSameTabAttrName) {
params.is_same_tab = value == "true";
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
} else if (key_name == kShowConsistencyPromo) {
params.show_consistency_promo = value == "true";
#endif
@@ -211,13 +212,13 @@ std::string ChromeConnectedHeaderHelper::BuildRequestHeader(
#endif
if (!force_account_consistency && gaia_id.empty()) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
if (gaia::IsGaiaSignonRealm(url.DeprecatedGetOriginAsURL())) {
parts.push_back(
base::StringPrintf("%s=%s", kEligibleForConsistency, "true"));
return base::JoinString(parts, is_header_request ? "," : ":");
}
-#endif // defined(OS_ANDROID) || defined(OS_IOS)
+#endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
return std::string();
}
@@ -246,8 +247,19 @@ std::string ChromeConnectedHeaderHelper::BuildRequestHeader(
// Do not add the supervised parameter.
break;
}
- parts.push_back(base::StringPrintf(
- "%s=%s", kConsistencyEnabledByDefaultAttrName, "false"));
+
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+ std::string consistency_enabled_by_default =
+ base::FeatureList::IsEnabled(switches::kLacrosNonSyncingProfiles)
+ ? "true"
+ : "false";
+#else
+ std::string consistency_enabled_by_default = "false";
+#endif
+
+ parts.push_back(base::StringPrintf("%s=%s",
+ kConsistencyEnabledByDefaultAttrName,
+ consistency_enabled_by_default.c_str()));
return base::JoinString(parts, is_header_request ? "," : ":");
}
diff --git a/chromium/components/signin/core/browser/consistency_cookie_manager.cc b/chromium/components/signin/core/browser/consistency_cookie_manager.cc
new file mode 100644
index 00000000000..29a36d582e8
--- /dev/null
+++ b/chromium/components/signin/core/browser/consistency_cookie_manager.cc
@@ -0,0 +1,106 @@
+// Copyright 2022 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.
+
+#include "components/signin/core/browser/consistency_cookie_manager.h"
+
+#include "base/check.h"
+#include "base/time/time.h"
+#include "components/signin/public/base/signin_client.h"
+#include "google_apis/gaia/gaia_urls.h"
+#include "net/cookies/canonical_cookie.h"
+#include "net/cookies/cookie_options.h"
+#include "net/cookies/cookie_util.h"
+#include "services/network/public/mojom/cookie_manager.mojom.h"
+#include "url/gurl.h"
+
+namespace signin {
+
+const char ConsistencyCookieManager::kCookieName[] =
+ "CHROME_ID_CONSISTENCY_STATE";
+const char ConsistencyCookieManager::kCookieValueStringConsistent[] =
+ "Consistent";
+const char ConsistencyCookieManager::kCookieValueStringInconsistent[] =
+ "Inconsistent";
+const char ConsistencyCookieManager::kCookieValueStringUpdating[] = "Updating";
+
+ConsistencyCookieManager::ConsistencyCookieManager(
+ SigninClient* signin_client,
+ AccountReconcilor* reconcilor)
+ : signin_client_(signin_client), account_reconcilor_(reconcilor) {
+ DCHECK(signin_client_);
+ DCHECK(account_reconcilor_);
+ account_reconcilor_observation_.Observe(account_reconcilor_);
+ UpdateCookieIfNeeded();
+}
+
+ConsistencyCookieManager::~ConsistencyCookieManager() = default;
+
+// static
+void ConsistencyCookieManager::UpdateCookie(
+ network::mojom::CookieManager* cookie_manager,
+ CookieValue value) {
+ std::string cookie_value_string;
+ switch (value) {
+ case CookieValue::kConsistent:
+ cookie_value_string = kCookieValueStringConsistent;
+ break;
+ case CookieValue::kInconsistent:
+ cookie_value_string = kCookieValueStringInconsistent;
+ break;
+ case CookieValue::kUpdating:
+ cookie_value_string = kCookieValueStringUpdating;
+ break;
+ }
+ DCHECK(!cookie_value_string.empty());
+
+ // Update the cookie with the new value.
+ base::Time now = base::Time::Now();
+ base::Time expiry = now + base::Days(2 * 365); // Two years.
+ std::unique_ptr<net::CanonicalCookie> cookie =
+ net::CanonicalCookie::CreateSanitizedCookie(
+ GaiaUrls::GetInstance()->gaia_url(), kCookieName, cookie_value_string,
+ GaiaUrls::GetInstance()->gaia_url().host(),
+ /*path=*/"/", /*creation=*/now, /*expiration=*/expiry,
+ /*last_access=*/now, /*secure=*/true, /*httponly=*/false,
+ net::CookieSameSite::LAX_MODE, net::COOKIE_PRIORITY_DEFAULT,
+ /*same_party=*/false, /*partition_key=*/absl::nullopt);
+ net::CookieOptions cookie_options;
+ // Permit to set SameSite cookies.
+ cookie_options.set_same_site_cookie_context(
+ net::CookieOptions::SameSiteCookieContext::MakeInclusive());
+ cookie_manager->SetCanonicalCookie(
+ *cookie, net::cookie_util::SimulatedCookieSource(*cookie, "https"),
+ cookie_options,
+ network::mojom::CookieManager::SetCanonicalCookieCallback());
+}
+
+void ConsistencyCookieManager::OnStateChanged(
+ signin_metrics::AccountReconcilorState state) {
+ UpdateCookieIfNeeded();
+}
+
+absl::optional<ConsistencyCookieManager::CookieValue>
+ConsistencyCookieManager::CalculateCookieValue() const {
+ switch (account_reconcilor_->GetState()) {
+ case signin_metrics::ACCOUNT_RECONCILOR_OK:
+ return CookieValue::kConsistent;
+ case signin_metrics::ACCOUNT_RECONCILOR_RUNNING:
+ case signin_metrics::ACCOUNT_RECONCILOR_SCHEDULED:
+ return CookieValue::kUpdating;
+ case signin_metrics::ACCOUNT_RECONCILOR_ERROR:
+ return CookieValue::kInconsistent;
+ case signin_metrics::ACCOUNT_RECONCILOR_INACTIVE:
+ return absl::nullopt;
+ }
+}
+
+void ConsistencyCookieManager::UpdateCookieIfNeeded() {
+ absl::optional<CookieValue> cookie_value = CalculateCookieValue();
+ if (!cookie_value.has_value() || cookie_value == cookie_value_)
+ return;
+ cookie_value_ = cookie_value;
+ UpdateCookie(signin_client_->GetCookieManager(), cookie_value_.value());
+}
+
+} // namespace signin
diff --git a/chromium/components/signin/core/browser/consistency_cookie_manager.h b/chromium/components/signin/core/browser/consistency_cookie_manager.h
new file mode 100644
index 00000000000..45255ee8791
--- /dev/null
+++ b/chromium/components/signin/core/browser/consistency_cookie_manager.h
@@ -0,0 +1,77 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_SIGNIN_CORE_BROWSER_CONSISTENCY_COOKIE_MANAGER_H_
+#define COMPONENTS_SIGNIN_CORE_BROWSER_CONSISTENCY_COOKIE_MANAGER_H_
+
+#include "base/gtest_prod_util.h"
+#include "base/scoped_observation.h"
+#include "components/signin/core/browser/account_reconcilor.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace network::mojom {
+class CookieManager;
+}
+
+class SigninClient;
+
+namespace signin {
+
+// The `ConsistencyCookieManager` manages the CHROME_ID_CONSISTENCY_STATE
+// cookie, which is used to display an interstitial page (a.k.a. "Mirror
+// Landing") while account additions are in progress. This avoids issues where
+// the user has to manually reload the page or retry their navigation after
+// adding an account to the OS account manager.
+// The value of the cookie depends on the state of the `AccountReconcilor` and
+// whether there is a native account addition flow in progress.
+//
+// TODO(https://crbug.com/1260291): The `ConsistencyCookieManager` only
+// listens to the `AccountReconcilor` for now, it is not updated by UI flows
+// yet.
+class ConsistencyCookieManager : public AccountReconcilor::Observer {
+ public:
+ explicit ConsistencyCookieManager(SigninClient* signin_client,
+ AccountReconcilor* reconcilor);
+ ~ConsistencyCookieManager() override;
+
+ ConsistencyCookieManager& operator=(const ConsistencyCookieManager&) = delete;
+ ConsistencyCookieManager(const ConsistencyCookieManager&) = delete;
+
+ private:
+ friend class ConsistencyCookieManagerTest;
+ FRIEND_TEST_ALL_PREFIXES(ConsistencyCookieManagerTest, ReconcilorState);
+
+ enum class CookieValue { kConsistent, kInconsistent, kUpdating };
+
+ // Cookie name and values.
+ static const char kCookieName[];
+ static const char kCookieValueStringConsistent[];
+ static const char kCookieValueStringInconsistent[];
+ static const char kCookieValueStringUpdating[];
+
+ // Sets the cookie to match `value`.
+ static void UpdateCookie(network::mojom::CookieManager* cookie_manager,
+ CookieValue value);
+
+ // AccountReconcilor::Observer:
+ void OnStateChanged(signin_metrics::AccountReconcilorState state) override;
+
+ // Calculates the cookie value based on the reconcilor state.
+ absl::optional<CookieValue> CalculateCookieValue() const;
+
+ // Gets the new value using `CalculateCookieValue()` and sets the cookie if it
+ // changed.
+ void UpdateCookieIfNeeded();
+
+ SigninClient* const signin_client_;
+ AccountReconcilor* const account_reconcilor_;
+ absl::optional<CookieValue> cookie_value_ = absl::nullopt;
+
+ base::ScopedObservation<AccountReconcilor, AccountReconcilor::Observer>
+ account_reconcilor_observation_{this};
+};
+
+} // namespace signin
+
+#endif // COMPONENTS_SIGNIN_CORE_BROWSER_CONSISTENCY_COOKIE_MANAGER_H_
diff --git a/chromium/components/signin/core/browser/consistency_cookie_manager_unittest.cc b/chromium/components/signin/core/browser/consistency_cookie_manager_unittest.cc
new file mode 100644
index 00000000000..2bfef6e0f8d
--- /dev/null
+++ b/chromium/components/signin/core/browser/consistency_cookie_manager_unittest.cc
@@ -0,0 +1,133 @@
+// Copyright 2022 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.
+
+#include "components/signin/core/browser/consistency_cookie_manager.h"
+
+#include "components/signin/core/browser/account_reconcilor.h"
+#include "components/signin/core/browser/account_reconcilor_delegate.h"
+#include "components/signin/public/base/signin_metrics.h"
+#include "components/signin/public/base/test_signin_client.h"
+#include "google_apis/gaia/gaia_urls.h"
+#include "net/cookies/canonical_cookie.h"
+#include "services/network/test/test_cookie_manager.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace signin {
+
+namespace {
+
+class MockCookieManager
+ : public testing::StrictMock<network::TestCookieManager> {
+ public:
+ MOCK_METHOD4(SetCanonicalCookie,
+ void(const net::CanonicalCookie& cookie,
+ const GURL& source_url,
+ const net::CookieOptions& cookie_options,
+ SetCanonicalCookieCallback callback));
+};
+
+} // namespace
+
+class ConsistencyCookieManagerTest : public testing::Test {
+ public:
+ ConsistencyCookieManagerTest() {
+ std::unique_ptr<MockCookieManager> mock_cookie_manager =
+ std::make_unique<MockCookieManager>();
+ cookie_manager_ = mock_cookie_manager.get();
+ signin_client_.set_cookie_manager(std::move(mock_cookie_manager));
+ }
+
+ ~ConsistencyCookieManagerTest() override { reconcilor_.Shutdown(); }
+
+ void ExpectCookieSet(const std::string& value) {
+ const std::string expected_domain =
+ std::string(".") + GaiaUrls::GetInstance()->gaia_url().host();
+ EXPECT_CALL(
+ *cookie_manager_,
+ SetCanonicalCookie(
+ testing::AllOf(
+ testing::Property(&net::CanonicalCookie::Name,
+ ConsistencyCookieManager::kCookieName),
+ testing::Property(&net::CanonicalCookie::Value, value),
+ testing::Property(&net::CanonicalCookie::Domain,
+ expected_domain),
+ testing::Property(&net::CanonicalCookie::Path, "/"),
+ testing::Property(&net::CanonicalCookie::IsSecure, true),
+ testing::Property(&net::CanonicalCookie::IsHttpOnly, false)),
+ GaiaUrls::GetInstance()->gaia_url(), testing::_, testing::_));
+ }
+
+ void SetReconcilorState(signin_metrics::AccountReconcilorState state) {
+ account_reconcilor()->SetState(state);
+ }
+
+ AccountReconcilor* account_reconcilor() { return &reconcilor_; }
+ SigninClient* signin_client() { return &signin_client_; }
+ MockCookieManager* cookie_manager() { return cookie_manager_; }
+
+ private:
+ TestSigninClient signin_client_{/*prefs=*/nullptr};
+ MockCookieManager* cookie_manager_ = nullptr; // Owned by `signin_client_`.
+ AccountReconcilor reconcilor_{/*identity_manager=*/nullptr, &signin_client_,
+ std::make_unique<AccountReconcilorDelegate>()};
+};
+
+TEST_F(ConsistencyCookieManagerTest, ReconcilorState) {
+ // Initial state.
+ EXPECT_EQ(account_reconcilor()->GetState(),
+ signin_metrics::ACCOUNT_RECONCILOR_INACTIVE);
+ ConsistencyCookieManager cookie_consistency_manager(signin_client(),
+ account_reconcilor());
+ // Cookie has not been set.
+ testing::Mock::VerifyAndClearExpectations(cookie_manager());
+
+ struct AccountReconcilorStateTestCase {
+ signin_metrics::AccountReconcilorState state;
+ absl::optional<std::string> cookie_value;
+ };
+
+ // Iterate over all reconcilor state and check that they map to the right
+ // cookie value.
+ // Notes about the order:
+ // - Don't start with OK, as this is the current state.
+ // - Always change the reconcilor state to something that results in a
+ // different cookie value (otherwise the cookie is not updated).
+ AccountReconcilorStateTestCase cases[] = {
+ {signin_metrics::ACCOUNT_RECONCILOR_RUNNING,
+ ConsistencyCookieManager::kCookieValueStringUpdating},
+ {signin_metrics::ACCOUNT_RECONCILOR_OK,
+ ConsistencyCookieManager::kCookieValueStringConsistent},
+ {signin_metrics::ACCOUNT_RECONCILOR_ERROR,
+ ConsistencyCookieManager::kCookieValueStringInconsistent},
+ {signin_metrics::ACCOUNT_RECONCILOR_SCHEDULED,
+ ConsistencyCookieManager::kCookieValueStringUpdating},
+ {signin_metrics::ACCOUNT_RECONCILOR_INACTIVE, absl::nullopt},
+ };
+
+ for (const AccountReconcilorStateTestCase& test_case : cases) {
+ if (test_case.cookie_value.has_value())
+ ExpectCookieSet(test_case.cookie_value.value());
+ SetReconcilorState(test_case.state);
+ testing::Mock::VerifyAndClearExpectations(cookie_manager());
+ }
+
+ // Check that the cookie is not updated needlessly.
+ EXPECT_EQ(account_reconcilor()->GetState(),
+ signin_metrics::ACCOUNT_RECONCILOR_INACTIVE);
+ // Set again the state that was used before INACTIVE.
+ SetReconcilorState(signin_metrics::ACCOUNT_RECONCILOR_SCHEDULED);
+ testing::Mock::VerifyAndClearExpectations(cookie_manager());
+ // Setting the same state again does not update the cookie.
+ SetReconcilorState(signin_metrics::ACCOUNT_RECONCILOR_SCHEDULED);
+ testing::Mock::VerifyAndClearExpectations(cookie_manager());
+ // Setting a state that maps to the same value does not update the cookie.
+ EXPECT_EQ(account_reconcilor()->GetState(),
+ signin_metrics::ACCOUNT_RECONCILOR_SCHEDULED);
+ SetReconcilorState(signin_metrics::ACCOUNT_RECONCILOR_RUNNING);
+ testing::Mock::VerifyAndClearExpectations(cookie_manager());
+}
+
+} // namespace signin
diff --git a/chromium/components/signin/core/browser/mirror_account_reconcilor_delegate.cc b/chromium/components/signin/core/browser/mirror_account_reconcilor_delegate.cc
index b1ec78b2b6b..b83cc8b7b86 100644
--- a/chromium/components/signin/core/browser/mirror_account_reconcilor_delegate.cc
+++ b/chromium/components/signin/core/browser/mirror_account_reconcilor_delegate.cc
@@ -40,7 +40,7 @@ bool MirrorAccountReconcilorDelegate::ShouldAbortReconcileIfPrimaryHasError()
ConsentLevel MirrorAccountReconcilorDelegate::GetConsentLevelForPrimaryAccount()
const {
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
return ConsentLevel::kSignin;
#elif BUILDFLAG(IS_CHROMEOS_LACROS)
// Whenever Mirror is enabled on a Lacros Profile, the Primary Account may or
diff --git a/chromium/components/signin/core/browser/mirror_account_reconcilor_delegate.h b/chromium/components/signin/core/browser/mirror_account_reconcilor_delegate.h
index 5d986ceaa8f..6e0de8ba33c 100644
--- a/chromium/components/signin/core/browser/mirror_account_reconcilor_delegate.h
+++ b/chromium/components/signin/core/browser/mirror_account_reconcilor_delegate.h
@@ -56,8 +56,6 @@ class MirrorAccountReconcilorDelegate : public AccountReconcilorDelegate,
// IdentityManager::Observer:
void OnPrimaryAccountChanged(const PrimaryAccountChangeEvent& event) override;
- void UpdateReconcilorStatus();
-
raw_ptr<IdentityManager> identity_manager_;
bool reconcile_enabled_;
};
diff --git a/chromium/components/signin/core/browser/mirror_landing_account_reconcilor_delegate.cc b/chromium/components/signin/core/browser/mirror_landing_account_reconcilor_delegate.cc
new file mode 100644
index 00000000000..b62569359f5
--- /dev/null
+++ b/chromium/components/signin/core/browser/mirror_landing_account_reconcilor_delegate.cc
@@ -0,0 +1,74 @@
+// Copyright 2022 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.
+
+#include "components/signin/core/browser/mirror_landing_account_reconcilor_delegate.h"
+
+#include "base/containers/contains.h"
+#include "base/logging.h"
+#include "google_apis/gaia/core_account_id.h"
+#include "google_apis/gaia/gaia_auth_fetcher.h"
+#include "google_apis/gaia/gaia_auth_util.h"
+
+namespace signin {
+
+MirrorLandingAccountReconcilorDelegate::
+ MirrorLandingAccountReconcilorDelegate() = default;
+
+MirrorLandingAccountReconcilorDelegate::
+ ~MirrorLandingAccountReconcilorDelegate() = default;
+
+bool MirrorLandingAccountReconcilorDelegate::IsReconcileEnabled() const {
+ return true;
+}
+
+gaia::GaiaSource MirrorLandingAccountReconcilorDelegate::GetGaiaApiSource()
+ const {
+ return gaia::GaiaSource::kAccountReconcilorMirror;
+}
+
+bool MirrorLandingAccountReconcilorDelegate::
+ ShouldAbortReconcileIfPrimaryHasError() const {
+ return true;
+}
+
+ConsentLevel
+MirrorLandingAccountReconcilorDelegate::GetConsentLevelForPrimaryAccount()
+ const {
+ return ConsentLevel::kSignin;
+}
+
+CoreAccountId
+MirrorLandingAccountReconcilorDelegate::GetFirstGaiaAccountForReconcile(
+ const std::vector<CoreAccountId>& chrome_accounts,
+ const std::vector<gaia::ListedAccount>& gaia_accounts,
+ const CoreAccountId& primary_account,
+ bool first_execution,
+ bool will_logout) const {
+ if (!primary_account.empty()) {
+ // `ShouldAbortReconcileIfPrimaryHasError()` returns true.
+ DCHECK(base::Contains(chrome_accounts, primary_account));
+ return primary_account;
+ }
+
+ // If there is no primary account, there should be no account at all.
+ DCHECK(chrome_accounts.empty());
+ return CoreAccountId();
+}
+
+std::vector<CoreAccountId>
+MirrorLandingAccountReconcilorDelegate::GetChromeAccountsForReconcile(
+ const std::vector<CoreAccountId>& chrome_accounts,
+ const CoreAccountId& primary_account,
+ const std::vector<gaia::ListedAccount>& gaia_accounts,
+ bool first_execution,
+ bool primary_has_error,
+ const gaia::MultiloginMode mode) const {
+ DCHECK(!primary_has_error);
+ DCHECK_EQ(mode,
+ gaia::MultiloginMode::MULTILOGIN_UPDATE_COOKIE_ACCOUNTS_ORDER);
+ return ReorderChromeAccountsForReconcile(chrome_accounts, primary_account,
+ gaia_accounts);
+}
+
+} // namespace signin
diff --git a/chromium/components/signin/core/browser/mirror_landing_account_reconcilor_delegate.h b/chromium/components/signin/core/browser/mirror_landing_account_reconcilor_delegate.h
new file mode 100644
index 00000000000..ae252c016af
--- /dev/null
+++ b/chromium/components/signin/core/browser/mirror_landing_account_reconcilor_delegate.h
@@ -0,0 +1,47 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_SIGNIN_CORE_BROWSER_MIRROR_LANDING_ACCOUNT_RECONCILOR_DELEGATE_H_
+#define COMPONENTS_SIGNIN_CORE_BROWSER_MIRROR_LANDING_ACCOUNT_RECONCILOR_DELEGATE_H_
+
+#include "components/signin/core/browser/account_reconcilor_delegate.h"
+
+namespace signin {
+
+// AccountReconcilorDelegate specialized for Mirror, using the "Mirror landing"
+// variant. Mirror is always enabled, even when there is no primary account.
+class MirrorLandingAccountReconcilorDelegate
+ : public AccountReconcilorDelegate {
+ public:
+ MirrorLandingAccountReconcilorDelegate();
+ ~MirrorLandingAccountReconcilorDelegate() override;
+
+ MirrorLandingAccountReconcilorDelegate(
+ const MirrorLandingAccountReconcilorDelegate&) = delete;
+ MirrorLandingAccountReconcilorDelegate& operator=(
+ const MirrorLandingAccountReconcilorDelegate&) = delete;
+
+ // AccountReconcilorDelegate:
+ bool IsReconcileEnabled() const override;
+ gaia::GaiaSource GetGaiaApiSource() const override;
+ bool ShouldAbortReconcileIfPrimaryHasError() const override;
+ ConsentLevel GetConsentLevelForPrimaryAccount() const override;
+ CoreAccountId GetFirstGaiaAccountForReconcile(
+ const std::vector<CoreAccountId>& chrome_accounts,
+ const std::vector<gaia::ListedAccount>& gaia_accounts,
+ const CoreAccountId& primary_account,
+ bool first_execution,
+ bool will_logout) const override;
+ std::vector<CoreAccountId> GetChromeAccountsForReconcile(
+ const std::vector<CoreAccountId>& chrome_accounts,
+ const CoreAccountId& primary_account,
+ const std::vector<gaia::ListedAccount>& gaia_accounts,
+ bool first_execution,
+ bool primary_has_error,
+ const gaia::MultiloginMode mode) const override;
+};
+
+} // namespace signin
+
+#endif // COMPONENTS_SIGNIN_CORE_BROWSER_MIRROR_LANDING_ACCOUNT_RECONCILOR_DELEGATE_H_
diff --git a/chromium/components/signin/core/browser/mirror_landing_account_reconcilor_delegate_unittest.cc b/chromium/components/signin/core/browser/mirror_landing_account_reconcilor_delegate_unittest.cc
new file mode 100644
index 00000000000..94cc99bdc1d
--- /dev/null
+++ b/chromium/components/signin/core/browser/mirror_landing_account_reconcilor_delegate_unittest.cc
@@ -0,0 +1,90 @@
+// Copyright 2022 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.
+
+#include "components/signin/core/browser/mirror_landing_account_reconcilor_delegate.h"
+
+#include <string>
+
+#include "google_apis/gaia/core_account_id.h"
+#include "google_apis/gaia/gaia_auth_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace signin {
+
+namespace {
+
+gaia::ListedAccount BuildListedAccount(const std::string& gaia_id) {
+ CoreAccountId account_id = CoreAccountId::FromGaiaId(gaia_id);
+ gaia::ListedAccount gaia_account;
+ gaia_account.id = account_id;
+ gaia_account.email = gaia_id + std::string("@gmail.com");
+ gaia_account.gaia_id = gaia_id;
+ gaia_account.raw_email = gaia_account.email;
+ return gaia_account;
+}
+
+} // namespace
+
+TEST(MirrorLandingAccountReconcilorDelegateTest,
+ GetFirstGaiaAccountForReconcile) {
+ gaia::ListedAccount gaia_account = BuildListedAccount("gaia");
+ CoreAccountId kPrimaryAccountId = CoreAccountId::FromGaiaId("primary");
+ CoreAccountId kOtherAccountId = CoreAccountId::FromGaiaId("other");
+ MirrorLandingAccountReconcilorDelegate delegate;
+ // No primary account.
+ EXPECT_TRUE(delegate
+ .GetFirstGaiaAccountForReconcile(
+ /*chrome_accounts=*/{},
+ /*gaia_accounts=*/{gaia_account},
+ /*primary_account=*/CoreAccountId(),
+ /*first_execution=*/true,
+ /*will_logout=*/false)
+ .empty());
+ // With primary account.
+ EXPECT_EQ(delegate.GetFirstGaiaAccountForReconcile(
+ /*chrome_accounts=*/{{kOtherAccountId, kPrimaryAccountId}},
+ /*gaia_accounts=*/{gaia_account},
+ /*primary_account=*/kPrimaryAccountId,
+ /*first_execution=*/true,
+ /*will_logout=*/false),
+ kPrimaryAccountId);
+}
+
+TEST(MirrorLandingAccountReconcilorDelegateTest,
+ GetChromeAccountsForReconcile) {
+ CoreAccountId kPrimaryAccountId = CoreAccountId::FromGaiaId("primary");
+ CoreAccountId kOtherAccountId1 = CoreAccountId::FromGaiaId("1");
+ CoreAccountId kOtherAccountId2 = CoreAccountId::FromGaiaId("2");
+ gaia::ListedAccount gaia_account_primary = BuildListedAccount("primary");
+ gaia::ListedAccount gaia_account_1 = BuildListedAccount("1");
+ gaia::ListedAccount gaia_account_2 = BuildListedAccount("2");
+ gaia::ListedAccount gaia_account_3 = BuildListedAccount("3");
+ MirrorLandingAccountReconcilorDelegate delegate;
+ // No primary account. Gaia accounts are removed.
+ EXPECT_TRUE(
+ delegate
+ .GetChromeAccountsForReconcile(
+ /*chrome_accounts=*/{},
+ /*primary_account=*/CoreAccountId(),
+ /*gaia_accounts=*/{gaia_account_1, gaia_account_2},
+ /*first_execution=*/true,
+ /*primary_has_error=*/false,
+ gaia::MultiloginMode::MULTILOGIN_UPDATE_COOKIE_ACCOUNTS_ORDER)
+ .empty());
+ // With primary account. Primary is moved in front, account 1 is kept in the
+ // same slot, account 2 is added, account 3 is removed.
+ EXPECT_EQ(delegate.GetChromeAccountsForReconcile(
+ /*chrome_accounts=*/{kOtherAccountId1, kOtherAccountId2,
+ kPrimaryAccountId},
+ /*primary_account=*/kPrimaryAccountId,
+ /*gaia_accounts=*/
+ {gaia_account_3, gaia_account_primary, gaia_account_1},
+ /*first_execution=*/true,
+ /*primary_has_error=*/false,
+ gaia::MultiloginMode::MULTILOGIN_UPDATE_COOKIE_ACCOUNTS_ORDER),
+ (std::vector<CoreAccountId>{kPrimaryAccountId, kOtherAccountId2,
+ kOtherAccountId1}));
+}
+
+} // namespace signin
diff --git a/chromium/components/signin/core/browser/signin_header_helper.h b/chromium/components/signin/core/browser/signin_header_helper.h
index 47853fc055f..f6e601fcc0a 100644
--- a/chromium/components/signin/core/browser/signin_header_helper.h
+++ b/chromium/components/signin/core/browser/signin_header_helper.h
@@ -87,7 +87,7 @@ struct ManageAccountsParams {
std::string continue_url;
// Whether the continue URL should be loaded in the same tab.
bool is_same_tab = false;
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
// Whether to show consistency promo.
bool show_consistency_promo = false;
#endif
diff --git a/chromium/components/signin/core/browser/signin_header_helper_unittest.cc b/chromium/components/signin/core/browser/signin_header_helper_unittest.cc
index 52df4a179aa..3884e498914 100644
--- a/chromium/components/signin/core/browser/signin_header_helper_unittest.cc
+++ b/chromium/components/signin/core/browser/signin_header_helper_unittest.cc
@@ -19,6 +19,7 @@
#include "components/signin/core/browser/chrome_connected_header_helper.h"
#include "components/signin/public/base/account_consistency_method.h"
#include "components/signin/public/base/signin_buildflags.h"
+#include "components/signin/public/base/signin_switches.h"
#include "components/signin/public/identity_manager/tribool.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "google_apis/gaia/gaia_urls.h"
@@ -153,6 +154,14 @@ class SigninHeaderHelperTest : public testing::Test {
}
#endif
+ std::string consistency_enabled_by_default_value() const {
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+ return "true";
+#else
+ return "false";
+#endif
+ }
+
base::test::TaskEnvironment task_environment_;
bool sync_enabled_ = false;
@@ -164,6 +173,8 @@ class SigninHeaderHelperTest : public testing::Test {
sync_preferences::TestingPrefServiceSyncable prefs_;
#if BUILDFLAG(IS_CHROMEOS_LACROS)
+ base::test::ScopedFeatureList scoped_feature_list_{
+ switches::kLacrosNonSyncingProfiles};
std::unique_ptr<chromeos::ScopedLacrosServiceTestHelper>
scoped_lacros_test_helper_;
#endif // BUILDFLAG(IS_CHROMEOS_LACROS)
@@ -180,13 +191,15 @@ TEST_F(SigninHeaderHelperTest, TestMirrorRequestNoAccountIdChromeOS) {
GURL("https://docs.google.com"), /*gaia_id=*/"",
/*is_child_account=*/Tribool::kUnknown,
"source=TestSource,mode=0,enable_account_consistency=true,"
- "consistency_enabled_by_default=false");
+ "consistency_enabled_by_default=" +
+ consistency_enabled_by_default_value());
CheckMirrorCookieRequest(GURL("https://docs.google.com"), /*gaia_id=*/"",
"mode=0:enable_account_consistency=true:"
- "consistency_enabled_by_default=false");
+ "consistency_enabled_by_default=" +
+ consistency_enabled_by_default_value());
}
#else // BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Tests that eligible_for_consistency request is returned on Android
// when reaching to Gaia origin and there's no primary account.
TEST_F(SigninHeaderHelperTest, TestEligibleForConsistencyRequestGaiaOrigin) {
@@ -219,7 +232,7 @@ TEST_F(SigninHeaderHelperTest, TestForceAccountConsistencyMobile) {
"source=TestSource,mode=0,enable_account_consistency=true,"
"consistency_enabled_by_default=false");
}
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
// Tests that no Mirror request is returned when the user is not signed in (no
// account id), for non Chrome OS platforms.
@@ -257,10 +270,12 @@ TEST_F(SigninHeaderHelperTest, TestMirrorRequestGoogleTLD) {
GURL("https://google.fr"), "0123456789",
/*is_child_account=*/Tribool::kUnknown,
"source=TestSource,mode=0,enable_account_consistency=true,"
- "consistency_enabled_by_default=false");
+ "consistency_enabled_by_default=" +
+ consistency_enabled_by_default_value());
CheckMirrorCookieRequest(GURL("https://google.de"), "0123456789",
"mode=0:enable_account_consistency=true:"
- "consistency_enabled_by_default=false");
+ "consistency_enabled_by_default=" +
+ consistency_enabled_by_default_value());
}
// Tests that the Mirror request is returned when the target is the domain
@@ -271,10 +286,12 @@ TEST_F(SigninHeaderHelperTest, TestMirrorRequestGoogleCom) {
GURL("https://www.google.com"), "0123456789",
/*is_child_account=*/Tribool::kUnknown,
"source=TestSource,mode=0,enable_account_consistency=true,"
- "consistency_enabled_by_default=false");
+ "consistency_enabled_by_default=" +
+ consistency_enabled_by_default_value());
CheckMirrorCookieRequest(GURL("https://www.google.com"), "0123456789",
"mode=0:enable_account_consistency=true:"
- "consistency_enabled_by_default=false");
+ "consistency_enabled_by_default=" +
+ consistency_enabled_by_default_value());
}
// Tests that no header sent when mirror account consistency is nor requested.
@@ -305,7 +322,8 @@ TEST_F(SigninHeaderHelperTest, TestMirrorRequestGoogleComProfileConsistency) {
CheckAccountConsistencyHeaderRequest(
request_adapter.GetFinalHeaders(), kChromeConnectedHeader,
"source=TestSource,mode=0,enable_account_consistency=true,"
- "consistency_enabled_by_default=false");
+ "consistency_enabled_by_default=" +
+ consistency_enabled_by_default_value());
}
TEST_F(SigninHeaderHelperTest, TestMirrorRequestGoogleComSupervised) {
@@ -314,17 +332,20 @@ TEST_F(SigninHeaderHelperTest, TestMirrorRequestGoogleComSupervised) {
GURL("https://www.google.com"), "0123456789",
/*is_child_account=*/Tribool::kUnknown,
"source=TestSource,mode=0,enable_account_consistency=true,"
- "consistency_enabled_by_default=false");
+ "consistency_enabled_by_default=" +
+ consistency_enabled_by_default_value());
CheckMirrorHeaderRequest(
GURL("https://www.google.com"), "0123456789",
/*is_child_account=*/Tribool::kTrue,
"source=TestSource,mode=0,enable_account_consistency=true,"
- "supervised=true,consistency_enabled_by_default=false");
+ "supervised=true,consistency_enabled_by_default=" +
+ consistency_enabled_by_default_value());
CheckMirrorHeaderRequest(
GURL("https://www.google.com"), "0123456789",
/*is_child_account=*/Tribool::kFalse,
"source=TestSource,mode=0,enable_account_consistency=true,"
- "supervised=false,consistency_enabled_by_default=false");
+ "supervised=false,consistency_enabled_by_default=" +
+ consistency_enabled_by_default_value());
}
// Mirror is always enabled on Android and iOS, so these tests are only relevant
@@ -711,7 +732,7 @@ TEST_F(SigninHeaderHelperTest, TestBuildManageAccountsParams) {
"action=ADDSESSION,email=%s,is_saml=true,"
"is_same_tab=true,continue_url=%s",
kEmail, kContinueURL);
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
header += ",show_consistency_promo=true";
#endif
@@ -721,7 +742,7 @@ TEST_F(SigninHeaderHelperTest, TestBuildManageAccountsParams) {
EXPECT_EQ(true, params.is_saml);
EXPECT_EQ(true, params.is_same_tab);
EXPECT_EQ(GURL(kContinueURL), params.continue_url);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
EXPECT_EQ(true, params.show_consistency_promo);
#endif
}
diff --git a/chromium/components/signin/internal/identity_manager/account_capabilities_constants.cc b/chromium/components/signin/internal/identity_manager/account_capabilities_constants.cc
index 44fe564401d..78be14efdb2 100644
--- a/chromium/components/signin/internal/identity_manager/account_capabilities_constants.cc
+++ b/chromium/components/signin/internal/identity_manager/account_capabilities_constants.cc
@@ -4,6 +4,9 @@
#include "components/signin/internal/identity_manager/account_capabilities_constants.h"
+const char kIsSubjectToParentalControlsCapabilityName[] =
+ "accountcapabilities/guydolldmfya";
+
const char kCanOfferExtendedChromeSyncPromosCapabilityName[] =
"accountcapabilities/gi2tklldmfya";
diff --git a/chromium/components/signin/internal/identity_manager/account_capabilities_constants.h b/chromium/components/signin/internal/identity_manager/account_capabilities_constants.h
index df8cb64191d..0e638dc6c1f 100644
--- a/chromium/components/signin/internal/identity_manager/account_capabilities_constants.h
+++ b/chromium/components/signin/internal/identity_manager/account_capabilities_constants.h
@@ -7,5 +7,6 @@
extern const char kCanOfferExtendedChromeSyncPromosCapabilityName[];
extern const char kCanOfferExtendedChromeSyncPromosCapabilityPrefsPath[];
+extern const char kIsSubjectToParentalControlsCapabilityName[];
#endif // COMPONENTS_SIGNIN_INTERNAL_IDENTITY_MANAGER_ACCOUNT_CAPABILITIES_CONSTANTS_H_
diff --git a/chromium/components/signin/internal/identity_manager/account_fetcher_service.cc b/chromium/components/signin/internal/identity_manager/account_fetcher_service.cc
index 60ce8066134..748b82f641a 100644
--- a/chromium/components/signin/internal/identity_manager/account_fetcher_service.cc
+++ b/chromium/components/signin/internal/identity_manager/account_fetcher_service.cc
@@ -34,7 +34,7 @@
#include "ash/constants/ash_features.h"
#endif
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "components/signin/internal/identity_manager/child_account_info_fetcher_android.h"
#include "components/signin/public/identity_manager/tribool.h"
#endif
@@ -57,7 +57,7 @@ AccountFetcherService::AccountFetcherService() = default;
AccountFetcherService::~AccountFetcherService() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
token_service_->RemoveObserver(this);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// child_info_request_ is an invalidation handler and needs to be
// unregistered during the lifetime of the invalidation service.
child_info_request_.reset();
@@ -113,7 +113,7 @@ bool AccountFetcherService::AreAllAccountCapabilitiesFetched() const {
void AccountFetcherService::OnNetworkInitialized() {
DCHECK(!network_initialized_);
DCHECK(!network_fetches_enabled_);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
DCHECK(!child_info_request_);
#endif
network_initialized_ = true;
@@ -148,7 +148,7 @@ void AccountFetcherService::RefreshAllAccountInfo(bool only_fetch_if_invalid) {
// dependency on PrimaryAccountManager which we get around by only allowing a
// single account. This is possible since we only support a single account to be
// a child anyway.
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
void AccountFetcherService::RefreshAccountInfoIfStale(
const CoreAccountId& account_id) {
DCHECK(network_fetches_enabled_);
@@ -185,7 +185,7 @@ void AccountFetcherService::MaybeEnableNetworkFetches() {
repeating_timer_->Start();
}
RefreshAllAccountInfo(/*only_fetch_if_invalid=*/true);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
UpdateChildInfo();
#endif
}
@@ -210,7 +210,7 @@ void AccountFetcherService::StartFetchingUserInfo(
}
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Starts fetching whether this is a child account. Handles refresh internally.
void AccountFetcherService::StartFetchingChildInfo(
const CoreAccountId& account_id) {
@@ -243,7 +243,7 @@ bool AccountFetcherService::IsAccountCapabilitiesFetcherEnabled() {
return true;
#if BUILDFLAG(IS_CHROMEOS_ASH)
- return ash::features::IsMinorModeRestrictionEnabled();
+ return true;
#else
return false;
#endif
@@ -411,7 +411,7 @@ void AccountFetcherService::OnRefreshTokenAvailable(
if (!network_fetches_enabled_)
return;
RefreshAccountInfo(account_id, /*only_fetch_if_invalid=*/true);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
UpdateChildInfo();
#endif
}
@@ -433,7 +433,7 @@ void AccountFetcherService::OnRefreshTokenRevoked(
user_info_requests_.erase(account_id);
account_capabilities_requests_.erase(account_id);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
UpdateChildInfo();
#endif
account_tracker_service_->StopTrackingAccount(account_id);
diff --git a/chromium/components/signin/internal/identity_manager/account_fetcher_service.h b/chromium/components/signin/internal/identity_manager/account_fetcher_service.h
index 10dd7063b89..6e579a3f287 100644
--- a/chromium/components/signin/internal/identity_manager/account_fetcher_service.h
+++ b/chromium/components/signin/internal/identity_manager/account_fetcher_service.h
@@ -29,7 +29,7 @@ class ProfileOAuth2TokenService;
class PrefRegistrySimple;
class SigninClient;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
class ChildAccountInfoFetcherAndroid;
#endif
@@ -101,7 +101,7 @@ class AccountFetcherService : public ProfileOAuth2TokenServiceObserver {
// force-enable off.
void EnableAccountCapabilitiesFetcherForTest(bool enabled);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Refresh the AccountInfo if the existing one is stale
void RefreshAccountInfoIfStale(const CoreAccountId& account_id);
@@ -121,7 +121,7 @@ class AccountFetcherService : public ProfileOAuth2TokenServiceObserver {
void RefreshAllAccountInfo(bool only_fetch_if_invalid);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Called on all account state changes. Decides whether to fetch new child
// status information or reset old values that aren't valid now.
void UpdateChildInfo();
@@ -133,7 +133,7 @@ class AccountFetcherService : public ProfileOAuth2TokenServiceObserver {
// Further the two fetches are managed by a different refresh logic and
// thus, can not be combined.
void StartFetchingUserInfo(const CoreAccountId& account_id);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
void StartFetchingChildInfo(const CoreAccountId& account_id);
// Resets the child status to false if it is true. If there is more than one
@@ -180,7 +180,7 @@ class AccountFetcherService : public ProfileOAuth2TokenServiceObserver {
bool enable_account_capabilities_fetcher_for_test_ = false;
std::unique_ptr<signin::PersistentRepeatingTimer> repeating_timer_;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
CoreAccountId child_request_account_id_;
std::unique_ptr<ChildAccountInfoFetcherAndroid> child_info_request_;
#endif
diff --git a/chromium/components/signin/internal/identity_manager/account_info_util.cc b/chromium/components/signin/internal/identity_manager/account_info_util.cc
index f9f9f45c4c3..07e2c382712 100644
--- a/chromium/components/signin/internal/identity_manager/account_info_util.cc
+++ b/chromium/components/signin/internal/identity_manager/account_info_util.cc
@@ -94,7 +94,7 @@ absl::optional<AccountCapabilities> AccountCapabilitiesFromValue(
// 1. Create "capability name" -> "boolean value" mapping.
std::map<std::string, bool> boolean_capabilities;
- for (const auto& capability_value : list->GetList()) {
+ for (const auto& capability_value : list->GetListDeprecated()) {
const std::string* name =
capability_value.FindStringKey(kAccountCapabilityNameKey);
if (!name)
diff --git a/chromium/components/signin/internal/identity_manager/account_tracker_service.cc b/chromium/components/signin/internal/identity_manager/account_tracker_service.cc
index 56c45d33dcd..c48334c0389 100644
--- a/chromium/components/signin/internal/identity_manager/account_tracker_service.cc
+++ b/chromium/components/signin/internal/identity_manager/account_tracker_service.cc
@@ -35,7 +35,7 @@
#include "components/signin/public/identity_manager/tribool.h"
#include "ui/gfx/image/image.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "base/android/jni_array.h"
#include "components/signin/public/android/jni_headers/AccountTrackerService_jni.h"
#endif
@@ -132,10 +132,18 @@ signin::Tribool FindAccountCapabilityPath(const base::Value& value,
}
}
+void GetString(const base::Value& dict,
+ base::StringPiece key,
+ std::string& result) {
+ if (const std::string* value = dict.FindStringKey(key)) {
+ result = *value;
+ }
+}
+
} // namespace
AccountTrackerService::AccountTrackerService() {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
JNIEnv* env = base::android::AttachCurrentThread();
base::android::ScopedJavaLocalRef<jobject> java_ref =
signin::Java_AccountTrackerService_Constructor(
@@ -524,13 +532,13 @@ void AccountTrackerService::OnAccountImageUpdated(
base::DictionaryValue* dict = nullptr;
ListPrefUpdate update(pref_service_, prefs::kAccountInfo);
- for (size_t i = 0; i < update->GetList().size(); ++i, dict = nullptr) {
- base::Value& dict_value = update->GetList()[i];
+ for (size_t i = 0; i < update->GetListDeprecated().size();
+ ++i, dict = nullptr) {
+ base::Value& dict_value = update->GetListDeprecated()[i];
if (dict_value.is_dict()) {
dict = static_cast<base::DictionaryValue*>(&dict_value);
- std::string value;
- if (dict->GetString(kAccountKeyPath, &value) &&
- value == account_id.ToString()) {
+ const std::string* account_key = dict->FindStringKey(kAccountKeyPath);
+ if (account_key && *account_key == account_id.ToString()) {
break;
}
}
@@ -551,42 +559,35 @@ void AccountTrackerService::RemoveAccountImageFromDisk(
}
void AccountTrackerService::LoadFromPrefs() {
- const base::ListValue* list = pref_service_->GetList(prefs::kAccountInfo);
+ const base::Value* list = pref_service_->GetList(prefs::kAccountInfo);
std::set<CoreAccountId> to_remove;
- for (size_t i = 0; i < list->GetList().size(); ++i) {
- const base::Value& dict_value = list->GetList()[i];
+ for (size_t i = 0; i < list->GetListDeprecated().size(); ++i) {
+ const base::Value& dict_value = list->GetListDeprecated()[i];
if (dict_value.is_dict()) {
const base::DictionaryValue& dict =
base::Value::AsDictionaryValue(dict_value);
- std::string value;
- if (dict.GetString(kAccountKeyPath, &value)) {
+ if (const std::string* account_key =
+ dict.FindStringKey(kAccountKeyPath)) {
// Ignore incorrectly persisted non-canonical account ids.
- if (value.find('@') != std::string::npos &&
- value != gaia::CanonicalizeEmail(value)) {
- to_remove.insert(CoreAccountId::FromString(value));
+ if (account_key->find('@') != std::string::npos &&
+ *account_key != gaia::CanonicalizeEmail(*account_key)) {
+ to_remove.insert(CoreAccountId::FromString(*account_key));
continue;
}
- CoreAccountId account_id = CoreAccountId::FromString(value);
+ CoreAccountId account_id = CoreAccountId::FromString(*account_key);
StartTrackingAccount(account_id);
AccountInfo& account_info = accounts_[account_id];
- if (dict.GetString(kAccountGaiaPath, &value))
- account_info.gaia = value;
- if (dict.GetString(kAccountEmailPath, &value))
- account_info.email = value;
- if (dict.GetString(kAccountHostedDomainPath, &value))
- account_info.hosted_domain = value;
- if (dict.GetString(kAccountFullNamePath, &value))
- account_info.full_name = value;
- if (dict.GetString(kAccountGivenNamePath, &value))
- account_info.given_name = value;
- if (dict.GetString(kAccountLocalePath, &value))
- account_info.locale = value;
- if (dict.GetString(kAccountPictureURLPath, &value))
- account_info.picture_url = value;
- if (dict.GetString(kLastDownloadedImageURLWithSizePath, &value))
- account_info.last_downloaded_image_url_with_size = value;
+ GetString(dict, kAccountGaiaPath, account_info.gaia);
+ GetString(dict, kAccountEmailPath, account_info.email);
+ GetString(dict, kAccountHostedDomainPath, account_info.hosted_domain);
+ GetString(dict, kAccountFullNamePath, account_info.full_name);
+ GetString(dict, kAccountGivenNamePath, account_info.given_name);
+ GetString(dict, kAccountLocalePath, account_info.locale);
+ GetString(dict, kAccountPictureURLPath, account_info.picture_url);
+ GetString(dict, kLastDownloadedImageURLWithSizePath,
+ account_info.last_downloaded_image_url_with_size);
if (absl::optional<bool> is_child_status =
dict.FindBoolKey(kDeprecatedChildStatusPath)) {
@@ -595,7 +596,7 @@ void AccountTrackerService::LoadFromPrefs() {
: signin::Tribool::kFalse;
// Migrate to kAccountChildAttributePath.
ListPrefUpdate update(pref_service_, prefs::kAccountInfo);
- base::Value* update_dict = &update->GetList()[i];
+ base::Value* update_dict = &update->GetListDeprecated()[i];
DCHECK(update_dict->is_dict());
SetAccountCapabilityPath(update_dict, kAccountChildAttributePath,
account_info.is_child_account);
@@ -663,23 +664,21 @@ void AccountTrackerService::SaveToPrefs(const AccountInfo& account_info) {
base::DictionaryValue* dict = nullptr;
ListPrefUpdate update(pref_service_, prefs::kAccountInfo);
- for (size_t i = 0; i < update->GetList().size(); ++i, dict = nullptr) {
- base::Value& dict_value = update->GetList()[i];
+ for (size_t i = 0; i < update->GetListDeprecated().size();
+ ++i, dict = nullptr) {
+ base::Value& dict_value = update->GetListDeprecated()[i];
if (dict_value.is_dict()) {
dict = static_cast<base::DictionaryValue*>(&dict_value);
- std::string value;
- if (dict->GetString(kAccountKeyPath, &value) &&
- value == account_info.account_id.ToString()) {
+ const std::string* account_key = dict->FindStringKey(kAccountKeyPath);
+ if (account_key && *account_key == account_info.account_id.ToString()) {
break;
}
}
}
if (!dict) {
- dict = new base::DictionaryValue();
- update->Append(base::WrapUnique(dict));
- // |dict| is invalidated at this point, so it needs to be reset.
- base::Value& dict_value = update->GetList().back();
+ update->Append(base::Value(base::Value::Type::DICTIONARY));
+ base::Value& dict_value = update->GetListDeprecated().back();
DCHECK(dict_value.is_dict());
dict = static_cast<base::DictionaryValue*>(&dict_value);
dict->SetString(kAccountKeyPath, account_info.account_id.ToString());
@@ -788,7 +787,7 @@ void AccountTrackerService::RemoveAccount(const CoreAccountId& account_id) {
StopTrackingAccount(account_id);
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
base::android::ScopedJavaLocalRef<jobject>
AccountTrackerService::GetJavaObject() {
return base::android::ScopedJavaLocalRef<jobject>(java_ref_);
diff --git a/chromium/components/signin/internal/identity_manager/account_tracker_service.h b/chromium/components/signin/internal/identity_manager/account_tracker_service.h
index 63dcaa0fcec..bf4650caa40 100644
--- a/chromium/components/signin/internal/identity_manager/account_tracker_service.h
+++ b/chromium/components/signin/internal/identity_manager/account_tracker_service.h
@@ -5,7 +5,6 @@
#ifndef COMPONENTS_SIGNIN_INTERNAL_IDENTITY_MANAGER_ACCOUNT_TRACKER_SERVICE_H_
#define COMPONENTS_SIGNIN_INTERNAL_IDENTITY_MANAGER_ACCOUNT_TRACKER_SERVICE_H_
-#include <list>
#include <map>
#include <string>
#include <vector>
@@ -22,7 +21,7 @@
#include "google_apis/gaia/core_account_id.h"
#include "google_apis/gaia/gaia_auth_util.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "base/android/scoped_java_ref.h"
#endif
@@ -126,7 +125,7 @@ class AccountTrackerService {
AccountIdMigrationState GetMigrationState() const;
void SetMigrationDone();
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Returns a reference to the corresponding Java AccountTrackerService object.
base::android::ScopedJavaLocalRef<jobject> GetJavaObject();
@@ -239,7 +238,7 @@ class AccountTrackerService {
// Task runner used for file operations on avatar images.
scoped_refptr<base::SequencedTaskRunner> image_storage_task_runner_;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// A reference to the Java counterpart of this object.
base::android::ScopedJavaGlobalRef<jobject> java_ref_;
#endif
diff --git a/chromium/components/signin/internal/identity_manager/account_tracker_service_unittest.cc b/chromium/components/signin/internal/identity_manager/account_tracker_service_unittest.cc
index 037837a07ce..c1bf49a8a4d 100644
--- a/chromium/components/signin/internal/identity_manager/account_tracker_service_unittest.cc
+++ b/chromium/components/signin/internal/identity_manager/account_tracker_service_unittest.cc
@@ -45,7 +45,7 @@
#include "ash/constants/ash_features.h"
#endif
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "components/signin/public/identity_manager/identity_test_utils.h"
#endif
@@ -70,7 +70,7 @@ const AccountKey kAccountKeyIncomplete = {"incomplete"};
const AccountKey kAccountKeyFooBar = {"foobar"};
const AccountKey kAccountKeyFooDotBar = {"foo.bar"};
-#if !defined(OS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_ASH) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_IOS)
const AccountKey kAccountKeyAdvancedProtection = {"advanced_protection"};
#endif
@@ -202,7 +202,7 @@ class AccountTrackerServiceTest : public testing::Test {
AccountTrackerServiceTest()
: signin_client_(&pref_service_),
fake_oauth2_token_service_(&pref_service_) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Mock AccountManagerFacade in java code for tests that require its
// initialization.
signin::SetUpMockAccountManagerFacade();
@@ -707,14 +707,9 @@ TEST_F(AccountTrackerServiceTest,
CheckAccountCapabilities(kAccountKeyAlpha, account_info);
}
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
TEST_F(AccountTrackerServiceTest,
TokenAvailable_AccountCapabilitiesFetcherDisabled) {
-#if BUILDFLAG(IS_CHROMEOS_ASH)
- base::test::ScopedFeatureList scoped_feature_list;
- scoped_feature_list.InitAndDisableFeature(
- ash::features::kMinorModeRestriction);
-#endif
-
account_fetcher()->EnableAccountCapabilitiesFetcherForTest(false);
SimulateTokenAvailable(kAccountKeyAlpha);
EXPECT_TRUE(account_fetcher()->AreAllAccountCapabilitiesFetched());
@@ -723,6 +718,7 @@ TEST_F(AccountTrackerServiceTest,
AccountKeyToAccountId(kAccountKeyAlpha));
EXPECT_FALSE(account_info.capabilities.AreAllCapabilitiesKnown());
}
+#endif
TEST_F(AccountTrackerServiceTest, TokenAvailableTwice_UserInfoOnce) {
SimulateTokenAvailable(kAccountKeyAlpha);
@@ -972,7 +968,7 @@ TEST_F(AccountTrackerServiceTest, Persistence) {
// This will allow testing removal as well as child accounts which is only
// allowed for a single account.
SimulateTokenRevoked(kAccountKeyAlpha);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
account_fetcher()->SetIsChildAccount(AccountKeyToAccountId(kAccountKeyBeta),
true);
#else
@@ -980,7 +976,7 @@ TEST_F(AccountTrackerServiceTest, Persistence) {
true);
#endif
-#if !BUILDFLAG(IS_CHROMEOS_ASH) && !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
account_tracker()->SetIsAdvancedProtectionAccount(
AccountKeyToAccountId(kAccountKeyBeta), true);
#endif
@@ -994,7 +990,7 @@ TEST_F(AccountTrackerServiceTest, Persistence) {
CheckAccountDetails(kAccountKeyBeta, infos[0]);
CheckAccountCapabilities(kAccountKeyBeta, infos[0]);
EXPECT_EQ(signin::Tribool::kTrue, infos[0].is_child_account);
-#if !BUILDFLAG(IS_CHROMEOS_ASH) && !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
EXPECT_TRUE(infos[0].is_under_advanced_protection);
#else
EXPECT_FALSE(infos[0].is_under_advanced_protection);
@@ -1028,17 +1024,17 @@ TEST_F(AccountTrackerServiceTest, ChildStatusMigration) {
->GetAccountInfo(AccountKeyToAccountId(kAccountKeyAlpha))
.is_child_account);
ListPrefUpdate update(prefs(), prefs::kAccountInfo);
- base::Value* dict = nullptr;
- update->Get(0, &dict);
- ASSERT_TRUE(dict && dict->is_dict());
+ ASSERT_FALSE(update->GetListDeprecated().empty());
+ base::Value& dict = update->GetListDeprecated()[0];
+ ASSERT_TRUE(dict.is_dict());
const char kDeprecatedChildKey[] = "is_child_account";
const char kNewChildKey[] = "is_supervised_child";
// The deprecated key is not set.
- EXPECT_FALSE(dict->FindBoolKey(kDeprecatedChildKey));
+ EXPECT_FALSE(dict.FindBoolKey(kDeprecatedChildKey));
// Set the child status using the deprecated key, and reload the account.
- dict->SetBoolKey(kDeprecatedChildKey, true);
- dict->RemoveKey(kNewChildKey);
+ dict.SetBoolKey(kDeprecatedChildKey, true);
+ dict.RemoveKey(kNewChildKey);
ClearAccountTrackerEvents();
ResetAccountTrackerWithPersistence(scoped_user_data_dir.GetPath());
EXPECT_TRUE(CheckAccountTrackerEvents(
@@ -1053,9 +1049,9 @@ TEST_F(AccountTrackerServiceTest, ChildStatusMigration) {
// The deprecated key has been read.
EXPECT_EQ(signin::Tribool::kTrue, infos[0].is_child_account);
// The deprecated key has been removed.
- EXPECT_FALSE(dict->FindBoolKey(kDeprecatedChildKey));
+ EXPECT_FALSE(dict.FindBoolKey(kDeprecatedChildKey));
// The new key has been written.
- absl::optional<int> new_key = dict->FindIntKey(kNewChildKey);
+ absl::optional<int> new_key = dict.FindIntKey(kNewChildKey);
ASSERT_TRUE(new_key.has_value());
EXPECT_EQ(static_cast<int>(signin::Tribool::kTrue), new_key.value());
}
@@ -1449,7 +1445,7 @@ TEST_F(AccountTrackerServiceTest, GaiaIdMigrationCrashInTheMiddle) {
TEST_F(AccountTrackerServiceTest, ChildAccountBasic) {
SimulateTokenAvailable(kAccountKeyChild);
IssueAccessToken(kAccountKeyChild);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
account_fetcher()->SetIsChildAccount(AccountKeyToAccountId(kAccountKeyChild),
true);
#else
@@ -1468,7 +1464,7 @@ TEST_F(AccountTrackerServiceTest, ChildAccountBasic) {
TEST_F(AccountTrackerServiceTest, ChildAccountWithSecondaryEdu) {
SimulateTokenAvailable(kAccountKeyChild);
IssueAccessToken(kAccountKeyChild);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
account_fetcher()->SetIsChildAccount(AccountKeyToAccountId(kAccountKeyChild),
true);
#else
@@ -1478,7 +1474,7 @@ TEST_F(AccountTrackerServiceTest, ChildAccountWithSecondaryEdu) {
SimulateTokenAvailable(kAccountKeyEdu);
IssueAccessToken(kAccountKeyEdu);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
account_fetcher()->SetIsChildAccount(AccountKeyToAccountId(kAccountKeyEdu),
false);
#else
@@ -1502,7 +1498,7 @@ TEST_F(AccountTrackerServiceTest, ChildAccountWithSecondaryEdu) {
TEST_F(AccountTrackerServiceTest, ChildAccountUpdatedAndRevoked) {
SimulateTokenAvailable(kAccountKeyChild);
IssueAccessToken(kAccountKeyChild);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
account_fetcher()->SetIsChildAccount(AccountKeyToAccountId(kAccountKeyChild),
false);
#else
@@ -1531,7 +1527,7 @@ TEST_F(AccountTrackerServiceTest, ChildAccountUpdatedAndRevoked) {
TEST_F(AccountTrackerServiceTest, ChildAccountUpdatedAndRevokedWithUpdate) {
SimulateTokenAvailable(kAccountKeyChild);
IssueAccessToken(kAccountKeyChild);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
account_fetcher()->SetIsChildAccount(AccountKeyToAccountId(kAccountKeyChild),
true);
#else
@@ -1550,7 +1546,7 @@ TEST_F(AccountTrackerServiceTest, ChildAccountUpdatedAndRevokedWithUpdate) {
AccountKeyToAccountId(kAccountKeyChild));
EXPECT_EQ(signin::Tribool::kTrue, info.is_child_account);
SimulateTokenRevoked(kAccountKeyChild);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// On Android, is_child_account is set to false before removing it.
EXPECT_TRUE(CheckAccountTrackerEvents({
TrackingEvent(UPDATED, AccountKeyToAccountId(kAccountKeyChild),
@@ -1575,7 +1571,7 @@ TEST_F(AccountTrackerServiceTest, ChildAccountUpdatedTwiceThenRevoked) {
// Since the account state is already valid, this will notify the
// observers for the second time.
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
account_fetcher()->SetIsChildAccount(AccountKeyToAccountId(kAccountKeyChild),
true);
#else
@@ -1591,7 +1587,7 @@ TEST_F(AccountTrackerServiceTest, ChildAccountUpdatedTwiceThenRevoked) {
AccountKeyToEmail(kAccountKeyChild)),
}));
SimulateTokenRevoked(kAccountKeyChild);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// On Android, is_child_account is set to false before removing it.
EXPECT_TRUE(CheckAccountTrackerEvents({
TrackingEvent(UPDATED, AccountKeyToAccountId(kAccountKeyChild),
@@ -1615,7 +1611,7 @@ TEST_F(AccountTrackerServiceTest, ChildAccountGraduation) {
IssueAccessToken(kAccountKeyChild);
// Set and verify this is a child account.
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
account_fetcher()->SetIsChildAccount(AccountKeyToAccountId(kAccountKeyChild),
true);
#else
@@ -1635,7 +1631,7 @@ TEST_F(AccountTrackerServiceTest, ChildAccountGraduation) {
}));
// Now simulate child account graduation.
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
account_fetcher()->SetIsChildAccount(AccountKeyToAccountId(kAccountKeyChild),
false);
#else
@@ -1678,7 +1674,7 @@ TEST_F(AccountTrackerServiceTest, RemoveAccountBeforeImageFetchDone) {
}));
}
-#if !defined(OS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_ASH) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_IOS)
TEST_F(AccountTrackerServiceTest, AdvancedProtectionAccountBasic) {
SimulateTokenAvailable(kAccountKeyAdvancedProtection);
IssueAccessToken(kAccountKeyAdvancedProtection);
diff --git a/chromium/components/signin/internal/identity_manager/accounts_cookie_mutator_impl.cc b/chromium/components/signin/internal/identity_manager/accounts_cookie_mutator_impl.cc
index 12a0aa80973..e55e14a903f 100644
--- a/chromium/components/signin/internal/identity_manager/accounts_cookie_mutator_impl.cc
+++ b/chromium/components/signin/internal/identity_manager/accounts_cookie_mutator_impl.cc
@@ -104,7 +104,7 @@ void AccountsCookieMutatorImpl::TriggerCookieJarUpdate() {
gaia_cookie_manager_service_->TriggerListAccounts();
}
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
void AccountsCookieMutatorImpl::ForceTriggerOnCookieChange() {
gaia_cookie_manager_service_->ForceOnCookieChangeProcessing();
}
diff --git a/chromium/components/signin/internal/identity_manager/accounts_cookie_mutator_impl.h b/chromium/components/signin/internal/identity_manager/accounts_cookie_mutator_impl.h
index a7d661eac8d..2032b2df59d 100644
--- a/chromium/components/signin/internal/identity_manager/accounts_cookie_mutator_impl.h
+++ b/chromium/components/signin/internal/identity_manager/accounts_cookie_mutator_impl.h
@@ -65,7 +65,7 @@ class AccountsCookieMutatorImpl : public AccountsCookieMutator {
void TriggerCookieJarUpdate() override;
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
void ForceTriggerOnCookieChange() override;
#endif
diff --git a/chromium/components/signin/internal/identity_manager/device_accounts_synchronizer_impl.cc b/chromium/components/signin/internal/identity_manager/device_accounts_synchronizer_impl.cc
index f284e6a8ca0..9f140374d66 100644
--- a/chromium/components/signin/internal/identity_manager/device_accounts_synchronizer_impl.cc
+++ b/chromium/components/signin/internal/identity_manager/device_accounts_synchronizer_impl.cc
@@ -5,6 +5,7 @@
#include "components/signin/internal/identity_manager/device_accounts_synchronizer_impl.h"
#include "base/check.h"
+#include "build/build_config.h"
#include "components/signin/internal/identity_manager/profile_oauth2_token_service_delegate.h"
namespace signin {
@@ -24,7 +25,7 @@ void DeviceAccountsSynchronizerImpl::
primary_account_id);
}
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
void DeviceAccountsSynchronizerImpl::ReloadAccountFromSystem(
const CoreAccountId& account_id) {
token_service_delegate_->ReloadAccountFromSystem(account_id);
diff --git a/chromium/components/signin/internal/identity_manager/device_accounts_synchronizer_impl.h b/chromium/components/signin/internal/identity_manager/device_accounts_synchronizer_impl.h
index 5b0e341da11..08a8aee7443 100644
--- a/chromium/components/signin/internal/identity_manager/device_accounts_synchronizer_impl.h
+++ b/chromium/components/signin/internal/identity_manager/device_accounts_synchronizer_impl.h
@@ -24,7 +24,7 @@ class DeviceAccountsSynchronizerImpl : public DeviceAccountsSynchronizer {
void ReloadAllAccountsFromSystemWithPrimaryAccount(
const absl::optional<CoreAccountId>& primary_account_id) override;
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
void ReloadAccountFromSystem(const CoreAccountId& account_id) override;
#endif
diff --git a/chromium/components/signin/internal/identity_manager/fake_profile_oauth2_token_service_delegate.cc b/chromium/components/signin/internal/identity_manager/fake_profile_oauth2_token_service_delegate.cc
index 0bff65ff384..255d8e5abd9 100644
--- a/chromium/components/signin/internal/identity_manager/fake_profile_oauth2_token_service_delegate.cc
+++ b/chromium/components/signin/internal/identity_manager/fake_profile_oauth2_token_service_delegate.cc
@@ -8,6 +8,7 @@
#include "base/containers/cxx20_erase.h"
#include "base/ranges/algorithm.h"
+#include "build/build_config.h"
#include "components/signin/internal/identity_manager/profile_oauth2_token_service.h"
#include "google_apis/gaia/gaia_access_token_fetcher.h"
#include "google_apis/gaia/gaia_constants.h"
@@ -179,7 +180,7 @@ void FakeProfileOAuth2TokenServiceDelegate::UpdateAuthError(
FireAuthErrorChanged(account_id, error);
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
base::android::ScopedJavaLocalRef<jobject>
FakeProfileOAuth2TokenServiceDelegate::GetJavaObject() {
return base::android::ScopedJavaLocalRef<jobject>();
diff --git a/chromium/components/signin/internal/identity_manager/fake_profile_oauth2_token_service_delegate.h b/chromium/components/signin/internal/identity_manager/fake_profile_oauth2_token_service_delegate.h
index 2b54a9a3177..8cc9a884060 100644
--- a/chromium/components/signin/internal/identity_manager/fake_profile_oauth2_token_service_delegate.h
+++ b/chromium/components/signin/internal/identity_manager/fake_profile_oauth2_token_service_delegate.h
@@ -80,7 +80,7 @@ class FakeProfileOAuth2TokenServiceDelegate
void IssueRefreshTokenForUser(const CoreAccountId& account_id,
const std::string& token);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
base::android::ScopedJavaLocalRef<jobject> GetJavaObject() override;
#endif
diff --git a/chromium/components/signin/internal/identity_manager/gaia_cookie_manager_service.cc b/chromium/components/signin/internal/identity_manager/gaia_cookie_manager_service.cc
index 0a840ec20c6..5e1934169ac 100644
--- a/chromium/components/signin/internal/identity_manager/gaia_cookie_manager_service.cc
+++ b/chromium/components/signin/internal/identity_manager/gaia_cookie_manager_service.cc
@@ -275,14 +275,14 @@ void GaiaCookieManagerService::ExternalCcResultFetcher::
}
// If there is nothing to check, terminate immediately.
- if (value->GetList().size() == 0) {
+ if (value->GetListDeprecated().size() == 0) {
CleanupTransientState();
GetCheckConnectionInfoCompleted(true);
return;
}
// Start a fetcher for each connection URL that needs to be checked.
- for (const base::Value& elem : value->GetList()) {
+ for (const base::Value& elem : value->GetListDeprecated()) {
if (!elem.is_dict())
continue;
@@ -715,12 +715,12 @@ GaiaCookieManagerService::GetURLLoaderFactory() {
void GaiaCookieManagerService::MarkListAccountsStale() {
list_accounts_stale_ = true;
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(&GaiaCookieManagerService::ForceOnCookieChangeProcessing,
weak_ptr_factory_.GetWeakPtr()));
-#endif // defined(OS_IOS)
+#endif // BUILDFLAG(IS_IOS)
}
void GaiaCookieManagerService::OnCookieChange(
diff --git a/chromium/components/signin/internal/identity_manager/mutable_profile_oauth2_token_service_delegate_unittest.cc b/chromium/components/signin/internal/identity_manager/mutable_profile_oauth2_token_service_delegate_unittest.cc
index 6791237e16b..794ebcc79ae 100644
--- a/chromium/components/signin/internal/identity_manager/mutable_profile_oauth2_token_service_delegate_unittest.cc
+++ b/chromium/components/signin/internal/identity_manager/mutable_profile_oauth2_token_service_delegate_unittest.cc
@@ -1102,10 +1102,10 @@ TEST_F(MutableProfileOAuth2TokenServiceDelegateTest, GaiaIdMigration) {
ListPrefUpdate update(&pref_service_, prefs::kAccountInfo);
update->ClearList();
- auto dict = std::make_unique<base::DictionaryValue>();
- dict->SetString("account_id", email);
- dict->SetString("email", email);
- dict->SetString("gaia", gaia_id);
+ base::Value dict(base::Value::Type::DICTIONARY);
+ dict.SetStringKey("account_id", email);
+ dict.SetStringKey("email", email);
+ dict.SetStringKey("gaia", gaia_id);
update->Append(std::move(dict));
account_tracker_service_.ResetForTesting();
@@ -1165,16 +1165,16 @@ TEST_F(MutableProfileOAuth2TokenServiceDelegateTest,
ListPrefUpdate update(&pref_service_, prefs::kAccountInfo);
update->ClearList();
- auto dict = std::make_unique<base::DictionaryValue>();
- dict->SetString("account_id", email1);
- dict->SetString("email", email1);
- dict->SetString("gaia", gaia_id1);
- update->Append(std::move(dict));
- dict = std::make_unique<base::DictionaryValue>();
- dict->SetString("account_id", email2);
- dict->SetString("email", email2);
- dict->SetString("gaia", gaia_id2);
- update->Append(std::move(dict));
+ base::Value account1(base::Value::Type::DICTIONARY);
+ account1.SetStringKey("account_id", email1);
+ account1.SetStringKey("email", email1);
+ account1.SetStringKey("gaia", gaia_id1);
+ update->Append(std::move(account1));
+ base::Value account2(base::Value::Type::DICTIONARY);
+ account2.SetStringKey("account_id", email2);
+ account2.SetStringKey("email", email2);
+ account2.SetStringKey("gaia", gaia_id2);
+ update->Append(std::move(account2));
account_tracker_service_.ResetForTesting();
AddAuthTokenManually("AccountId-" + email1, "refresh_token");
diff --git a/chromium/components/signin/internal/identity_manager/primary_account_manager.cc b/chromium/components/signin/internal/identity_manager/primary_account_manager.cc
index 51ca2abc2b1..741a2b973ef 100644
--- a/chromium/components/signin/internal/identity_manager/primary_account_manager.cc
+++ b/chromium/components/signin/internal/identity_manager/primary_account_manager.cc
@@ -145,18 +145,34 @@ CoreAccountId PrimaryAccountManager::GetPrimaryAccountId(
return GetPrimaryAccountInfo(consent_level).account_id;
}
-void PrimaryAccountManager::SetUnconsentedPrimaryAccountInfo(
- const CoreAccountInfo& account_info) {
+void PrimaryAccountManager::SetPrimaryAccountInfo(
+ const CoreAccountInfo& account_info,
+ signin::ConsentLevel consent_level) {
if (HasPrimaryAccount(signin::ConsentLevel::kSync)) {
- DCHECK_EQ(account_info, GetPrimaryAccountInfo(signin::ConsentLevel::kSync));
+ DCHECK_EQ(account_info, GetPrimaryAccountInfo(signin::ConsentLevel::kSync))
+ << "Changing the primary sync account is not allowed.";
return;
}
+ DCHECK(!account_info.account_id.empty());
+ DCHECK(!account_info.gaia.empty());
+ DCHECK(!account_info.email.empty());
+ DCHECK(!account_tracker_service_->GetAccountInfo(account_info.account_id)
+ .IsEmpty())
+ << "Account must be seeded before being set as primary account";
- bool account_changed = account_info != primary_account_info();
PrimaryAccountChangeEvent::State previous_state = GetPrimaryAccountState();
- SetPrimaryAccountInternal(account_info, /*consented_to_sync=*/false);
- if (account_changed)
- FirePrimaryAccountChanged(previous_state);
+ switch (consent_level) {
+ case signin::ConsentLevel::kSync:
+ SetSyncPrimaryAccountInternal(account_info);
+ FirePrimaryAccountChanged(previous_state);
+ return;
+ case signin::ConsentLevel::kSignin:
+ bool account_changed = account_info != primary_account_info();
+ SetPrimaryAccountInternal(account_info, /*consented_to_sync=*/false);
+ if (account_changed)
+ FirePrimaryAccountChanged(previous_state);
+ return;
+ }
}
void PrimaryAccountManager::SetSyncPrimaryAccountInternal(
@@ -226,28 +242,6 @@ bool PrimaryAccountManager::HasPrimaryAccount(
}
}
-void PrimaryAccountManager::SetSyncPrimaryAccountInfo(
- const CoreAccountInfo& account_info) {
-#if DCHECK_IS_ON()
- DCHECK(!account_info.account_id.empty());
- DCHECK(!account_info.gaia.empty());
- DCHECK(!account_info.email.empty());
- DCHECK(!account_tracker_service_->GetAccountInfo(account_info.account_id)
- .IsEmpty())
- << "Account should have been seeded before being set as primary account";
-#endif
- if (HasPrimaryAccount(signin::ConsentLevel::kSync)) {
- DCHECK_EQ(account_info.account_id,
- GetPrimaryAccountId(signin::ConsentLevel::kSync))
- << "Changing the primary sync account is not allowed.";
- return;
- }
-
- PrimaryAccountChangeEvent::State previous_state = GetPrimaryAccountState();
- SetSyncPrimaryAccountInternal(account_info);
- FirePrimaryAccountChanged(previous_state);
-}
-
void PrimaryAccountManager::UpdatePrimaryAccountInfo() {
const CoreAccountId primary_account_id = primary_account_info().account_id;
DCHECK(!primary_account_id.empty());
diff --git a/chromium/components/signin/internal/identity_manager/primary_account_manager.h b/chromium/components/signin/internal/identity_manager/primary_account_manager.h
index c4de592916e..04671a78c3c 100644
--- a/chromium/components/signin/internal/identity_manager/primary_account_manager.h
+++ b/chromium/components/signin/internal/identity_manager/primary_account_manager.h
@@ -99,15 +99,12 @@ class PrimaryAccountManager : public ProfileOAuth2TokenServiceObserver {
// convenience wrapper over GetPrimaryAccountInfo().account_id.
CoreAccountId GetPrimaryAccountId(signin::ConsentLevel consent_level) const;
- // Signs a user in. PrimaryAccountManager assumes that |username| can be used
- // to look up the corresponding account_id and gaia_id for this email.
- void SetSyncPrimaryAccountInfo(const CoreAccountInfo& account_info);
-
- // Sets the unconsented primary account. The unconsented primary account can
- // only be changed if the user has not consented for sync If the user has
- // consented for sync already, then use ClearPrimaryAccount() or RevokeSync()
- // instead.
- void SetUnconsentedPrimaryAccountInfo(const CoreAccountInfo& account_info);
+ // Sets the primary account with the required consent level. The primary
+ // account can only be changed if the user has not consented for sync. If the
+ // user has consented for sync already, then use ClearPrimaryAccount() or
+ // RevokeSync() instead.
+ void SetPrimaryAccountInfo(const CoreAccountInfo& account_info,
+ signin::ConsentLevel consent_level);
// Updates the primary account information from AccountTrackerService.
void UpdatePrimaryAccountInfo();
diff --git a/chromium/components/signin/internal/identity_manager/primary_account_manager_unittest.cc b/chromium/components/signin/internal/identity_manager/primary_account_manager_unittest.cc
index 1140a44a215..1ea83d7b7c6 100644
--- a/chromium/components/signin/internal/identity_manager/primary_account_manager_unittest.cc
+++ b/chromium/components/signin/internal/identity_manager/primary_account_manager_unittest.cc
@@ -155,8 +155,8 @@ TEST_F(PrimaryAccountManagerTest, SignOut) {
CreatePrimaryAccountManager();
CoreAccountId main_account_id =
AddToAccountTracker("account_id", "user@gmail.com");
- manager_->SetSyncPrimaryAccountInfo(
- account_tracker()->GetAccountInfo(main_account_id));
+ manager_->SetPrimaryAccountInfo(
+ account_tracker()->GetAccountInfo(main_account_id), ConsentLevel::kSync);
manager_->ClearPrimaryAccount(signin_metrics::SIGNOUT_TEST,
signin_metrics::SignoutDelete::kIgnoreMetric);
EXPECT_EQ(1, num_successful_signouts_);
@@ -183,8 +183,8 @@ TEST_F(PrimaryAccountManagerTest, SignOutRevoke) {
AddToAccountTracker("other_id", "other@gmail.com");
token_service_.UpdateCredentials(main_account_id, "token");
token_service_.UpdateCredentials(other_account_id, "token");
- manager_->SetSyncPrimaryAccountInfo(
- account_tracker()->GetAccountInfo(main_account_id));
+ manager_->SetPrimaryAccountInfo(
+ account_tracker()->GetAccountInfo(main_account_id), ConsentLevel::kSync);
EXPECT_TRUE(manager_->HasPrimaryAccount(ConsentLevel::kSync));
EXPECT_EQ(main_account_id,
manager_->GetPrimaryAccountId(ConsentLevel::kSync));
@@ -207,8 +207,8 @@ TEST_F(PrimaryAccountManagerTest, SignOutWhileProhibited) {
CoreAccountId main_account_id =
AddToAccountTracker("gaia_id", "user@gmail.com");
- manager_->SetSyncPrimaryAccountInfo(
- account_tracker()->GetAccountInfo(main_account_id));
+ manager_->SetPrimaryAccountInfo(
+ account_tracker()->GetAccountInfo(main_account_id), ConsentLevel::kSync);
signin_client()->set_is_signout_allowed(false);
manager_->ClearPrimaryAccount(signin_metrics::SIGNOUT_TEST,
signin_metrics::SignoutDelete::kIgnoreMetric);
@@ -230,7 +230,7 @@ TEST_F(PrimaryAccountManagerTest, UnconsentedSignOutWhileProhibited) {
CoreAccountId account_id = AddToAccountTracker("gaia_id", "user@gmail.com");
CoreAccountInfo account_info = account_tracker()->GetAccountInfo(account_id);
- manager_->SetUnconsentedPrimaryAccountInfo(account_info);
+ manager_->SetPrimaryAccountInfo(account_info, ConsentLevel::kSignin);
EXPECT_TRUE(manager_->HasPrimaryAccount(ConsentLevel::kSignin));
EXPECT_FALSE(manager_->HasPrimaryAccount(ConsentLevel::kSync));
signin_client()->set_is_signout_allowed(false);
@@ -278,7 +278,7 @@ TEST_F(PrimaryAccountManagerTest, NoopSignOutDoesNotNotifyObservers) {
CoreAccountId account_id = AddToAccountTracker("gaia_id", "user@gmail.com");
CoreAccountInfo account_info = account_tracker()->GetAccountInfo(account_id);
- manager_->SetUnconsentedPrimaryAccountInfo(account_info);
+ manager_->SetPrimaryAccountInfo(account_info, ConsentLevel::kSignin);
EXPECT_EQ(1, num_unconsented_account_changed_);
EXPECT_TRUE(manager_->HasPrimaryAccount(ConsentLevel::kSignin));
EXPECT_FALSE(manager_->HasPrimaryAccount(ConsentLevel::kSync));
@@ -300,8 +300,8 @@ TEST_F(PrimaryAccountManagerTest, SignIn) {
EXPECT_EQ(0, num_unconsented_account_changed_);
CoreAccountId account_id = AddToAccountTracker("gaia_id", "user@gmail.com");
- manager_->SetSyncPrimaryAccountInfo(
- account_tracker()->GetAccountInfo(account_id));
+ manager_->SetPrimaryAccountInfo(account_tracker()->GetAccountInfo(account_id),
+ ConsentLevel::kSync);
EXPECT_EQ(1, num_successful_signins_);
EXPECT_EQ(1, num_unconsented_account_changed_);
EXPECT_EQ("user@gmail.com",
@@ -321,16 +321,16 @@ TEST_F(PrimaryAccountManagerTest,
EXPECT_EQ(0, num_unconsented_account_changed_);
CoreAccountId account_id = AddToAccountTracker("gaia_id", "user@gmail.com");
- manager_->SetSyncPrimaryAccountInfo(
- account_tracker()->GetAccountInfo(account_id));
+ manager_->SetPrimaryAccountInfo(account_tracker()->GetAccountInfo(account_id),
+ ConsentLevel::kSync);
EXPECT_EQ(1, num_successful_signins_);
EXPECT_EQ(1, num_unconsented_account_changed_);
EXPECT_EQ("user@gmail.com",
manager_->GetPrimaryAccountInfo(ConsentLevel::kSync).email);
EXPECT_EQ(account_id, manager_->GetPrimaryAccountId(ConsentLevel::kSync));
- manager_->SetSyncPrimaryAccountInfo(
- account_tracker()->GetAccountInfo(account_id));
+ manager_->SetPrimaryAccountInfo(account_tracker()->GetAccountInfo(account_id),
+ ConsentLevel::kSync);
EXPECT_EQ(1, num_successful_signins_);
EXPECT_EQ(1, num_unconsented_account_changed_);
EXPECT_EQ("user@gmail.com",
@@ -367,10 +367,10 @@ TEST_F(PrimaryAccountManagerTest, GaiaIdMigration) {
AccountTrackerService::MIGRATION_NOT_STARTED);
ListPrefUpdate update(client_prefs, prefs::kAccountInfo);
update->ClearList();
- auto dict = std::make_unique<base::DictionaryValue>();
- dict->SetString("account_id", email);
- dict->SetString("email", email);
- dict->SetString("gaia", gaia_id);
+ base::Value dict(base::Value::Type::DICTIONARY);
+ dict.SetStringKey("account_id", email);
+ dict.SetStringKey("email", email);
+ dict.SetStringKey("gaia", gaia_id);
update->Append(std::move(dict));
account_tracker()->ResetForTesting();
@@ -400,10 +400,10 @@ TEST_F(PrimaryAccountManagerTest, GaiaIdMigrationCrashInTheMiddle) {
AccountTrackerService::MIGRATION_NOT_STARTED);
ListPrefUpdate update(client_prefs, prefs::kAccountInfo);
update->ClearList();
- auto dict = std::make_unique<base::DictionaryValue>();
- dict->SetString("account_id", email);
- dict->SetString("email", email);
- dict->SetString("gaia", gaia_id);
+ base::Value dict(base::Value::Type::DICTIONARY);
+ dict.SetStringKey("account_id", email);
+ dict.SetStringKey("email", email);
+ dict.SetStringKey("gaia", gaia_id);
update->Append(std::move(dict));
account_tracker()->ResetForTesting();
@@ -433,9 +433,9 @@ TEST_F(PrimaryAccountManagerTest, GaiaIdMigration_ForceAllAccounts) {
AccountTrackerService::MIGRATION_NOT_STARTED);
ListPrefUpdate update(client_prefs, prefs::kAccountInfo);
update->ClearList();
- auto dict = std::make_unique<base::DictionaryValue>();
- dict->SetString("account_id", email);
- dict->SetString("email", email);
+ base::Value dict(base::Value::Type::DICTIONARY);
+ dict.SetStringKey("account_id", email);
+ dict.SetStringKey("email", email);
update->Append(std::move(dict));
account_tracker()->ResetForTesting();
@@ -505,11 +505,9 @@ TEST_F(PrimaryAccountManagerTest, SetUnconsentedPrimaryAccountInfo) {
EXPECT_EQ(0, num_successful_signins_);
// Set the unconsented primary account.
- CoreAccountInfo account_info;
- account_info.account_id = CoreAccountId("gaia_id");
- account_info.gaia = "gaia_id";
- account_info.email = "user@gmail.com";
- manager_->SetUnconsentedPrimaryAccountInfo(account_info);
+ CoreAccountId account_id = AddToAccountTracker("gaia_id", "user@gmail.com");
+ CoreAccountInfo account_info = account_tracker()->GetAccountInfo(account_id);
+ manager_->SetPrimaryAccountInfo(account_info, ConsentLevel::kSignin);
EXPECT_EQ(0, num_successful_signins_);
EXPECT_EQ(0, num_successful_signouts_);
EXPECT_EQ(1, num_unconsented_account_changed_);
@@ -519,7 +517,7 @@ TEST_F(PrimaryAccountManagerTest, SetUnconsentedPrimaryAccountInfo) {
manager_->GetPrimaryAccountInfo(ConsentLevel::kSync));
// Set the same account again.
- manager_->SetUnconsentedPrimaryAccountInfo(account_info);
+ manager_->SetPrimaryAccountInfo(account_info, ConsentLevel::kSignin);
EXPECT_EQ(0, num_successful_signins_);
EXPECT_EQ(0, num_successful_signouts_);
EXPECT_EQ(1, num_unconsented_account_changed_);
@@ -531,7 +529,7 @@ TEST_F(PrimaryAccountManagerTest, SetUnconsentedPrimaryAccountInfo) {
// Change the email to another equivalent email. The account is updated but
// observers are not notified.
account_info.email = "us.er@gmail.com";
- manager_->SetUnconsentedPrimaryAccountInfo(account_info);
+ manager_->SetPrimaryAccountInfo(account_info, ConsentLevel::kSignin);
EXPECT_EQ(0, num_successful_signins_);
EXPECT_EQ(0, num_successful_signouts_);
EXPECT_EQ(1, num_unconsented_account_changed_);
@@ -539,23 +537,13 @@ TEST_F(PrimaryAccountManagerTest, SetUnconsentedPrimaryAccountInfo) {
manager_->GetPrimaryAccountInfo(ConsentLevel::kSignin));
EXPECT_EQ(CoreAccountInfo(),
manager_->GetPrimaryAccountInfo(ConsentLevel::kSync));
-
- // Clear it.
- manager_->SetUnconsentedPrimaryAccountInfo(CoreAccountInfo());
- EXPECT_EQ(0, num_successful_signins_);
- EXPECT_EQ(0, num_successful_signouts_);
- EXPECT_EQ(2, num_unconsented_account_changed_);
- EXPECT_EQ(CoreAccountInfo(),
- manager_->GetPrimaryAccountInfo(ConsentLevel::kSignin));
- EXPECT_EQ(CoreAccountInfo(),
- manager_->GetPrimaryAccountInfo(ConsentLevel::kSync));
}
TEST_F(PrimaryAccountManagerTest, RevokeSyncConsent) {
CreatePrimaryAccountManager();
CoreAccountId account_id = AddToAccountTracker("gaia_id", "user@gmail.com");
- manager_->SetSyncPrimaryAccountInfo(
- account_tracker()->GetAccountInfo(account_id));
+ manager_->SetPrimaryAccountInfo(account_tracker()->GetAccountInfo(account_id),
+ ConsentLevel::kSync);
EXPECT_TRUE(manager_->HasPrimaryAccount(ConsentLevel::kSync));
manager_->RevokeSyncConsent(signin_metrics::ProfileSignout::SIGNOUT_TEST,
@@ -571,8 +559,8 @@ TEST_F(PrimaryAccountManagerTest, RevokeSyncConsent) {
TEST_F(PrimaryAccountManagerTest, ClearPrimaryAccount) {
CreatePrimaryAccountManager();
CoreAccountId account_id = AddToAccountTracker("gaia_id", "user@gmail.com");
- manager_->SetSyncPrimaryAccountInfo(
- account_tracker()->GetAccountInfo(account_id));
+ manager_->SetPrimaryAccountInfo(account_tracker()->GetAccountInfo(account_id),
+ ConsentLevel::kSync);
EXPECT_TRUE(manager_->HasPrimaryAccount(ConsentLevel::kSync));
manager_->ClearPrimaryAccount(signin_metrics::ProfileSignout::SIGNOUT_TEST,
diff --git a/chromium/components/signin/internal/identity_manager/primary_account_mutator_impl.cc b/chromium/components/signin/internal/identity_manager/primary_account_mutator_impl.cc
index a330da198d7..e611eba72c1 100644
--- a/chromium/components/signin/internal/identity_manager/primary_account_mutator_impl.cc
+++ b/chromium/components/signin/internal/identity_manager/primary_account_mutator_impl.cc
@@ -37,9 +37,9 @@ PrimaryAccountMutatorImpl::PrimaryAccountMutatorImpl(
#if BUILDFLAG(IS_CHROMEOS_ASH)
// |account_consistency_| is not used on CHROMEOS_ASH, however it is preferred
- // to have it defined to avoid a lof of ifdefs in the header file.
- signin::AccountConsistencyMethod unused = account_consistency_;
- ALLOW_UNUSED_LOCAL(unused);
+ // to have it defined to avoid a lot of ifdefs in the header file.
+ [[maybe_unused]] signin::AccountConsistencyMethod unused =
+ account_consistency_;
#endif
}
@@ -75,8 +75,7 @@ PrimaryAccountMutatorImpl::SetPrimaryAccount(const CoreAccountId& account_id,
if (primary_account_manager_->HasPrimaryAccount(ConsentLevel::kSync))
return PrimaryAccountError::kSyncConsentAlreadySet;
#endif
- primary_account_manager_->SetSyncPrimaryAccountInfo(account_info);
- return PrimaryAccountError::kNoError;
+ break;
case ConsentLevel::kSignin:
#if BUILDFLAG(IS_CHROMEOS_ASH)
// On Chrome OS the UPA can only be set once and never removed or changed.
@@ -84,10 +83,9 @@ PrimaryAccountMutatorImpl::SetPrimaryAccount(const CoreAccountId& account_id,
!primary_account_manager_->HasPrimaryAccount(ConsentLevel::kSignin));
#endif
DCHECK(!primary_account_manager_->HasPrimaryAccount(ConsentLevel::kSync));
- primary_account_manager_->SetUnconsentedPrimaryAccountInfo(account_info);
- return PrimaryAccountError::kNoError;
+ break;
}
- CHECK(false) << "Unknown consent level: " << static_cast<int>(consent_level);
+ primary_account_manager_->SetPrimaryAccountInfo(account_info, consent_level);
return PrimaryAccountError::kNoError;
}
@@ -110,8 +108,17 @@ bool PrimaryAccountMutatorImpl::RevokeConsentShouldClearPrimaryAccount() const {
// should consider moving it to |SigninManager|.
return token_service_->RefreshTokenHasError(
primary_account_manager_->GetPrimaryAccountId(ConsentLevel::kSync));
- case AccountConsistencyMethod::kDisabled:
case AccountConsistencyMethod::kMirror:
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+ // TODO(crbug.com/1217645): Consider making this return false only for the
+ // main profile and return true, otherwise. This requires implementing
+ // ProfileOAuth2TokenServiceDelegateChromeOS::Revoke* and it's not clear
+ // what these functions should do.
+ return false;
+#else
+ return true;
+#endif
+ case AccountConsistencyMethod::kDisabled:
return true;
}
}
@@ -120,11 +127,6 @@ bool PrimaryAccountMutatorImpl::RevokeConsentShouldClearPrimaryAccount() const {
void PrimaryAccountMutatorImpl::RevokeSyncConsent(
signin_metrics::ProfileSignout source_metric,
signin_metrics::SignoutDelete delete_metric) {
-#if BUILDFLAG(IS_CHROMEOS_LACROS)
- // On Lacros with Mirror, revoking consent is not supported yet.
- // TODO(https://crbug.com/1260291): Remove this when it is supported.
- CHECK_NE(account_consistency_, AccountConsistencyMethod::kMirror);
-#endif
DCHECK(primary_account_manager_->HasPrimaryAccount(ConsentLevel::kSync));
#if !BUILDFLAG(IS_CHROMEOS_ASH)
@@ -143,12 +145,6 @@ bool PrimaryAccountMutatorImpl::ClearPrimaryAccount(
if (!primary_account_manager_->HasPrimaryAccount(ConsentLevel::kSignin))
return false;
-#if BUILDFLAG(IS_CHROMEOS_LACROS)
- // On Lacros with Mirror, signout is not supported yet.
- // TODO(https://crbug.com/1260291): Remove this when signout is supported.
- CHECK_NE(account_consistency_, AccountConsistencyMethod::kMirror);
-#endif
-
primary_account_manager_->ClearPrimaryAccount(source_metric, delete_metric);
return true;
}
diff --git a/chromium/components/signin/internal/identity_manager/profile_oauth2_token_service.cc b/chromium/components/signin/internal/identity_manager/profile_oauth2_token_service.cc
index b554cd39768..a98fecb0302 100644
--- a/chromium/components/signin/internal/identity_manager/profile_oauth2_token_service.cc
+++ b/chromium/components/signin/internal/identity_manager/profile_oauth2_token_service.cc
@@ -58,8 +58,8 @@ std::string SourceToString(SourceForRefreshTokenOperation source) {
return "DiceResponseHandler::Signin";
case SourceForRefreshTokenOperation::kDiceResponseHandler_Signout:
return "DiceResponseHandler::Signout";
- case SourceForRefreshTokenOperation::kDiceTurnOnSyncHelper_Abort:
- return "DiceTurnOnSyncHelper::Abort";
+ case SourceForRefreshTokenOperation::kTurnOnSyncHelper_Abort:
+ return "TurnOnSyncHelper::Abort";
case SourceForRefreshTokenOperation::kMachineLogon_CredentialProvider:
return "MachineLogon::CredentialProvider";
case SourceForRefreshTokenOperation::kTokenService_ExtractCredentials:
diff --git a/chromium/components/signin/internal/identity_manager/profile_oauth2_token_service_builder.cc b/chromium/components/signin/internal/identity_manager/profile_oauth2_token_service_builder.cc
index 55a8894c4d3..f9018596b17 100644
--- a/chromium/components/signin/internal/identity_manager/profile_oauth2_token_service_builder.cc
+++ b/chromium/components/signin/internal/identity_manager/profile_oauth2_token_service_builder.cc
@@ -7,6 +7,7 @@
#include <string>
#include <utility>
+#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "components/prefs/pref_service.h"
#include "components/signin/internal/identity_manager/profile_oauth2_token_service.h"
@@ -15,7 +16,7 @@
#include "components/signin/public/base/signin_client.h"
#include "components/signin/public/base/signin_switches.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_android.h"
#endif
@@ -28,14 +29,14 @@
#include "components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_chromeos.h"
#endif
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
#include "components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_ios.h"
#include "components/signin/public/identity_manager/ios/device_accounts_provider.h"
#endif
namespace {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// TODO(crbug.com/986435) Provide AccountManagerFacade as a parameter once
// IdentityServicesProvider owns its instance management.
std::unique_ptr<ProfileOAuth2TokenServiceDelegateAndroid>
@@ -43,7 +44,7 @@ CreateAndroidOAuthDelegate(AccountTrackerService* account_tracker_service) {
return std::make_unique<ProfileOAuth2TokenServiceDelegateAndroid>(
account_tracker_service);
}
-#elif defined(OS_IOS)
+#elif BUILDFLAG(IS_IOS)
std::unique_ptr<ProfileOAuth2TokenServiceIOSDelegate> CreateIOSOAuthDelegate(
SigninClient* signin_client,
std::unique_ptr<DeviceAccountsProvider> device_accounts_provider,
@@ -71,7 +72,7 @@ CreateMutableProfileOAuthDelegate(
bool delete_signin_cookies_on_exit,
scoped_refptr<TokenWebData> token_web_data,
SigninClient* signin_client,
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
MutableProfileOAuth2TokenServiceDelegate::FixRequestErrorCallback
reauth_callback,
#endif
@@ -85,14 +86,14 @@ CreateMutableProfileOAuthDelegate(
return std::make_unique<MutableProfileOAuth2TokenServiceDelegate>(
signin_client, account_tracker_service, network_connection_tracker,
token_web_data, account_consistency, revoke_all_tokens_on_load,
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
reauth_callback
#else
MutableProfileOAuth2TokenServiceDelegate::FixRequestErrorCallback()
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
);
}
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
std::unique_ptr<ProfileOAuth2TokenServiceDelegate>
CreateOAuth2TokenServiceDelegate(
@@ -107,17 +108,17 @@ CreateOAuth2TokenServiceDelegate(
bool delete_signin_cookies_on_exit,
scoped_refptr<TokenWebData> token_web_data,
#endif
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
std::unique_ptr<DeviceAccountsProvider> device_accounts_provider,
#endif
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
MutableProfileOAuth2TokenServiceDelegate::FixRequestErrorCallback
reauth_callback,
#endif
network::NetworkConnectionTracker* network_connection_tracker) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
return CreateAndroidOAuthDelegate(account_tracker_service);
-#elif defined(OS_IOS)
+#elif BUILDFLAG(IS_IOS)
return CreateIOSOAuthDelegate(signin_client,
std::move(device_accounts_provider),
account_tracker_service);
@@ -131,14 +132,14 @@ CreateOAuth2TokenServiceDelegate(
return CreateMutableProfileOAuthDelegate(
account_tracker_service, account_consistency,
delete_signin_cookies_on_exit, token_web_data, signin_client,
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
reauth_callback,
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
network_connection_tracker);
#else
NOTREACHED();
return nullptr;
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
}
} // namespace
@@ -156,10 +157,10 @@ std::unique_ptr<ProfileOAuth2TokenService> BuildProfileOAuth2TokenService(
bool delete_signin_cookies_on_exit,
scoped_refptr<TokenWebData> token_web_data,
#endif
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
std::unique_ptr<DeviceAccountsProvider> device_accounts_provider,
#endif
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
MutableProfileOAuth2TokenServiceDelegate::FixRequestErrorCallback
reauth_callback,
#endif
@@ -183,10 +184,10 @@ std::unique_ptr<ProfileOAuth2TokenService> BuildProfileOAuth2TokenService(
#if BUILDFLAG(ENABLE_DICE_SUPPORT)
delete_signin_cookies_on_exit, token_web_data,
#endif
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
std::move(device_accounts_provider),
#endif
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
reauth_callback,
#endif
network_connection_tracker));
diff --git a/chromium/components/signin/internal/identity_manager/profile_oauth2_token_service_builder.h b/chromium/components/signin/internal/identity_manager/profile_oauth2_token_service_builder.h
index 19a13e6a45d..ffbb90f818b 100644
--- a/chromium/components/signin/internal/identity_manager/profile_oauth2_token_service_builder.h
+++ b/chromium/components/signin/internal/identity_manager/profile_oauth2_token_service_builder.h
@@ -12,11 +12,11 @@
#include "build/chromeos_buildflags.h"
#include "components/signin/public/base/signin_buildflags.h"
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
#include "base/memory/scoped_refptr.h"
#endif
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include "components/signin/internal/identity_manager/mutable_profile_oauth2_token_service_delegate.h"
#endif
@@ -25,7 +25,7 @@ class PrefService;
class ProfileOAuth2TokenService;
class SigninClient;
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
class DeviceAccountsProvider;
#endif
@@ -60,10 +60,10 @@ std::unique_ptr<ProfileOAuth2TokenService> BuildProfileOAuth2TokenService(
bool delete_signin_cookies_on_exit,
scoped_refptr<TokenWebData> token_web_data,
#endif
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
std::unique_ptr<DeviceAccountsProvider> device_accounts_provider,
#endif
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
MutableProfileOAuth2TokenServiceDelegate::FixRequestErrorCallback
reauth_callback,
#endif
diff --git a/chromium/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate.h b/chromium/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate.h
index bb9d332bcbe..7cbe1702118 100644
--- a/chromium/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate.h
+++ b/chromium/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate.h
@@ -21,7 +21,7 @@
#include "net/base/backoff_entry.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "base/android/jni_android.h"
#endif
@@ -48,10 +48,11 @@ class ProfileOAuth2TokenServiceDelegate {
virtual ~ProfileOAuth2TokenServiceDelegate();
- virtual std::unique_ptr<OAuth2AccessTokenFetcher> CreateAccessTokenFetcher(
+ [[nodiscard]] virtual std::unique_ptr<OAuth2AccessTokenFetcher>
+ CreateAccessTokenFetcher(
const CoreAccountId& account_id,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
- OAuth2AccessTokenConsumer* consumer) WARN_UNUSED_RESULT = 0;
+ OAuth2AccessTokenConsumer* consumer) = 0;
// Returns |true| if a refresh token is available for |account_id|, and
// |false| otherwise.
@@ -133,19 +134,19 @@ class ProfileOAuth2TokenServiceDelegate {
// and false otherwise.
virtual bool FixRequestErrorIfPossible();
-#if defined(OS_IOS) || defined(OS_ANDROID)
+#if BUILDFLAG(IS_IOS) || BUILDFLAG(IS_ANDROID)
// Triggers platform specific implementation to reload accounts from system.
virtual void ReloadAllAccountsFromSystemWithPrimaryAccount(
const absl::optional<CoreAccountId>& primary_account_id) {}
#endif
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
// Triggers platform specific implementation for iOS to add a given account
// to the token service from a system account.
virtual void ReloadAccountFromSystem(const CoreAccountId& account_id) {}
#endif
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Returns a reference to the corresponding Java object.
virtual base::android::ScopedJavaLocalRef<jobject> GetJavaObject() = 0;
#endif
diff --git a/chromium/components/signin/ios/browser/BUILD.gn b/chromium/components/signin/ios/browser/BUILD.gn
index 79715757758..55fdf5b766f 100644
--- a/chromium/components/signin/ios/browser/BUILD.gn
+++ b/chromium/components/signin/ios/browser/BUILD.gn
@@ -82,6 +82,7 @@ source_set("unit_tests") {
"//components/sync_preferences:test_support",
"//ios/web",
"//ios/web/public/test",
+ "//ios/web/public/test:test_fixture",
"//ios/web/public/test/fakes",
"//net:test_support",
"//testing/gmock",
diff --git a/chromium/components/signin/ios/browser/account_consistency_service.h b/chromium/components/signin/ios/browser/account_consistency_service.h
index 6f72ce6fd5c..04b9fa53352 100644
--- a/chromium/components/signin/ios/browser/account_consistency_service.h
+++ b/chromium/components/signin/ios/browser/account_consistency_service.h
@@ -51,7 +51,7 @@ class AccountConsistencyService : public KeyedService,
// Sets the handler for |web_state| that reacts on Gaia responses with the
// X-Chrome-Manage-Accounts header and notifies |delegate|.
void SetWebStateHandler(web::WebState* web_state,
- id<ManageAccountsDelegate> delegate);
+ ManageAccountsDelegate* delegate);
// Removes the handler associated with |web_state|.
void RemoveWebStateHandler(web::WebState* web_state);
diff --git a/chromium/components/signin/ios/browser/account_consistency_service.mm b/chromium/components/signin/ios/browser/account_consistency_service.mm
index 9a768a889c4..03de401f8cb 100644
--- a/chromium/components/signin/ios/browser/account_consistency_service.mm
+++ b/chromium/components/signin/ios/browser/account_consistency_service.mm
@@ -107,7 +107,7 @@ class AccountConsistencyService::AccountConsistencyHandler
AccountConsistencyService* service,
AccountReconcilor* account_reconcilor,
signin::IdentityManager* identity_manager,
- id<ManageAccountsDelegate> delegate);
+ ManageAccountsDelegate* delegate);
void WebStateDestroyed(web::WebState* web_state) override;
@@ -137,12 +137,15 @@ class AccountConsistencyService::AccountConsistencyHandler
// Handles the AddAccount request depending on |has_cookie_changed|.
void HandleAddAccountRequest(GURL url, BOOL has_cookie_changed);
- bool show_consistency_promo_ = false;
+ // The consistency web sign-in needs to be shown once the page is loaded.
+ // It is required to avoid having the keyboard showing up on top of the web
+ // sign-in dialog.
+ bool show_consistency_web_signin_ = false;
AccountConsistencyService* account_consistency_service_; // Weak.
AccountReconcilor* account_reconcilor_; // Weak.
signin::IdentityManager* identity_manager_;
web::WebState* web_state_;
- __weak id<ManageAccountsDelegate> delegate_;
+ ManageAccountsDelegate* delegate_; // Weak.
base::WeakPtrFactory<AccountConsistencyHandler> weak_ptr_factory_;
};
@@ -151,7 +154,7 @@ AccountConsistencyService::AccountConsistencyHandler::AccountConsistencyHandler(
AccountConsistencyService* service,
AccountReconcilor* account_reconcilor,
signin::IdentityManager* identity_manager,
- id<ManageAccountsDelegate> delegate)
+ ManageAccountsDelegate* delegate)
: web::WebStatePolicyDecider(web_state),
account_consistency_service_(service),
account_reconcilor_(account_reconcilor),
@@ -199,11 +202,6 @@ void AccountConsistencyService::AccountConsistencyHandler::ShouldAllowResponse(
{url, GURL(kGoogleUrl)});
}
- // Reset boolean that tracks displaying the sign-in consistency promo. This
- // ensures that the promo is cancelled once navigation has started and the
- // WKWebView is cancelling previous navigations.
- show_consistency_promo_ = false;
-
if (!gaia::IsGaiaSignonRealm(url.DeprecatedGetOriginAsURL())) {
std::move(callback).Run(PolicyDecision::Allow());
return;
@@ -218,7 +216,7 @@ void AccountConsistencyService::AccountConsistencyHandler::ShouldAllowResponse(
NSString* x_autologin_header = [[http_response allHeaderFields]
objectForKey:[NSString stringWithUTF8String:signin::kAutoLoginHeader]];
if (x_autologin_header) {
- show_consistency_promo_ = true;
+ show_consistency_web_signin_ = true;
}
std::move(callback).Run(PolicyDecision::Allow());
return;
@@ -234,7 +232,8 @@ void AccountConsistencyService::AccountConsistencyHandler::ShouldAllowResponse(
GURL continue_url = GURL(params.continue_url);
DLOG_IF(ERROR, !params.continue_url.empty() && !continue_url.is_valid())
<< "Invalid continuation URL: \"" << continue_url << "\"";
- [delegate_ onGoIncognito:continue_url];
+ if (delegate_)
+ delegate_->OnGoIncognito(continue_url);
break;
}
case signin::GAIA_SERVICE_TYPE_SIGNUP:
@@ -254,19 +253,14 @@ void AccountConsistencyService::AccountConsistencyHandler::ShouldAllowResponse(
// have been restored.
return;
}
- } else if (!identity_manager_->GetAccountsWithRefreshTokens().empty()) {
- show_consistency_promo_ = true;
- // Allows the URL response to load before showing the consistency promo.
- // The promo should always be displayed in the foreground of Gaia
- // sign-on.
- std::move(callback).Run(PolicyDecision::Allow());
- return;
}
- [delegate_ onAddAccount];
+ if (delegate_)
+ delegate_->OnAddAccount();
break;
case signin::GAIA_SERVICE_TYPE_SIGNOUT:
case signin::GAIA_SERVICE_TYPE_DEFAULT:
- [delegate_ onManageAccounts];
+ if (delegate_)
+ delegate_->OnManageAccounts();
break;
case signin::GAIA_SERVICE_TYPE_NONE:
NOTREACHED();
@@ -290,13 +284,15 @@ void AccountConsistencyService::AccountConsistencyHandler::
// is not in an inconsistent state (where the identities on the device
// are different than those on the web). Fallback to asking the user to
// add an account.
- [delegate_ onAddAccount];
+ if (delegate_)
+ delegate_->OnAddAccount();
return;
}
web_state_->OpenURL(web::WebState::OpenURLParams(
url, web::Referrer(), WindowOpenDisposition::CURRENT_TAB,
ui::PAGE_TRANSITION_AUTO_TOPLEVEL, false));
- [delegate_ onRestoreGaiaCookies];
+ if (delegate_)
+ delegate_->OnRestoreGaiaCookies();
LogIOSGaiaCookiesState(
GaiaCookieStateOnSignedInNavigation::kGaiaCookieRestoredOnShowInfobar);
}
@@ -312,11 +308,11 @@ void AccountConsistencyService::AccountConsistencyHandler::PageLoaded(
return;
}
- if (show_consistency_promo_ &&
+ if (delegate_ && show_consistency_web_signin_ &&
gaia::IsGaiaSignonRealm(url.DeprecatedGetOriginAsURL())) {
- [delegate_ onShowConsistencyPromo:url webState:web_state];
- show_consistency_promo_ = false;
+ delegate_->OnShowConsistencyPromo(url, web_state);
}
+ show_consistency_web_signin_ = false;
}
void AccountConsistencyService::AccountConsistencyHandler::WebStateDestroyed(
@@ -406,7 +402,7 @@ void AccountConsistencyService::RunGaiaCookiesRestoredCallbacks(
void AccountConsistencyService::SetWebStateHandler(
web::WebState* web_state,
- id<ManageAccountsDelegate> delegate) {
+ ManageAccountsDelegate* delegate) {
DCHECK(!is_shutdown_) << "SetWebStateHandler called after Shutdown";
DCHECK(handlers_map_.find(web_state) == handlers_map_.end());
handlers_map_.insert(std::make_pair(
diff --git a/chromium/components/signin/ios/browser/account_consistency_service_unittest.mm b/chromium/components/signin/ios/browser/account_consistency_service_unittest.mm
index 21906c9e82b..4621cd690ab 100644
--- a/chromium/components/signin/ios/browser/account_consistency_service_unittest.mm
+++ b/chromium/components/signin/ios/browser/account_consistency_service_unittest.mm
@@ -44,6 +44,8 @@
#error "This file requires ARC support."
#endif
+using testing::NiceMock;
+
namespace {
// Fake identity email.
const char* kFakeEmail = "janedoe@gmail.com";
@@ -94,6 +96,34 @@ class MockAccountReconcilor : public AccountReconcilor {
MOCK_METHOD1(OnReceivedManageAccountsResponse, void(signin::GAIAServiceType));
};
+// Fake delegate implementation; all it does it count delegate calls.
+class FakeManageAccountsDelegate : public ManageAccountsDelegate {
+ public:
+ FakeManageAccountsDelegate() {}
+ ~FakeManageAccountsDelegate() override {}
+
+ void OnRestoreGaiaCookies() override { restore_cookies_call_count_++; }
+ void OnManageAccounts() override { manage_accounts_call_count_++; }
+ void OnAddAccount() override { add_account_call_count_++; }
+ void OnShowConsistencyPromo(const GURL& url,
+ web::WebState* webState) override {
+ show_promo_call_count_++;
+ }
+ void OnGoIncognito(const GURL& url) override { go_incognito_call_count_++; }
+
+ int total_call_count() {
+ return restore_cookies_call_count_ + manage_accounts_call_count_ +
+ add_account_call_count_ + show_promo_call_count_ +
+ go_incognito_call_count_;
+ }
+
+ int restore_cookies_call_count_ = 0;
+ int manage_accounts_call_count_ = 0;
+ int add_account_call_count_ = 0;
+ int show_promo_call_count_ = 0;
+ int go_incognito_call_count_ = 0;
+};
+
// FakeWebState that allows control over its policy decider.
class FakeWebState : public web::FakeWebState {
public:
@@ -155,8 +185,9 @@ class AccountConsistencyServiceTest : public PlatformTest {
false /* restore_session */);
cookie_settings_ = new content_settings::CookieSettings(settings_map_.get(),
&prefs_, false, "");
+ // Use a NiceMock here to suppress "uninteresting call" warnings.
account_reconcilor_ =
- std::make_unique<MockAccountReconcilor>(signin_client_.get());
+ std::make_unique<NiceMock<MockAccountReconcilor>>(signin_client_.get());
ResetAccountConsistencyService();
}
@@ -230,7 +261,7 @@ class AccountConsistencyServiceTest : public PlatformTest {
// Navigation APIs.
void SimulateNavigateToURL(NSURLResponse* response,
- id<ManageAccountsDelegate> delegate) {
+ ManageAccountsDelegate* delegate) {
SimulateNavigateToURL(response, delegate,
web::PageLoadCompletionStatus::SUCCESS,
/* expected_allowed_response=*/true);
@@ -238,15 +269,14 @@ class AccountConsistencyServiceTest : public PlatformTest {
void SimulateNavigateToURLWithPageLoadFailure(
NSURLResponse* response,
- id<ManageAccountsDelegate> delegate) {
+ ManageAccountsDelegate* delegate) {
SimulateNavigateToURL(response, delegate,
web::PageLoadCompletionStatus::FAILURE,
/* expected_allowed_response=*/true);
}
- void SimulateNavigateToURLWithInterruption(
- NSURLResponse* response,
- id<ManageAccountsDelegate> delegate) {
+ void SimulateNavigateToURLWithInterruption(NSURLResponse* response,
+ ManageAccountsDelegate* delegate) {
SimulateNavigateToURL(response, delegate,
web::PageLoadCompletionStatus::SUCCESS,
/* expected_allowed_response=*/false);
@@ -283,7 +313,7 @@ class AccountConsistencyServiceTest : public PlatformTest {
base::OnceCallback<void(uint)>());
}
- void SetWebStateHandler(id<ManageAccountsDelegate> delegate) {
+ void SetWebStateHandler(ManageAccountsDelegate* delegate) {
// If we have already added the |web_state_| with a previous |delegate|,
// remove it to enforce a one-to-one mapping between web state handler and
// web state.
@@ -301,6 +331,7 @@ class AccountConsistencyServiceTest : public PlatformTest {
web::FakeBrowserState browser_state_;
sync_preferences::TestingPrefServiceSyncable prefs_;
FakeWebState web_state_;
+ FakeManageAccountsDelegate delegate_;
network::TestURLLoaderFactory test_url_loader_factory_;
std::unique_ptr<signin::IdentityTestEnvironment> identity_test_env_;
@@ -309,7 +340,7 @@ class AccountConsistencyServiceTest : public PlatformTest {
private:
void SimulateNavigateToURL(NSURLResponse* response,
- id<ManageAccountsDelegate> delegate,
+ ManageAccountsDelegate* delegate,
web::PageLoadCompletionStatus page_status,
bool expect_allowed_response) {
SetWebStateHandler(delegate);
@@ -361,8 +392,6 @@ TEST_F(AccountConsistencyServiceTest, SignInSignOut) {
CheckDomainHasChromeConnectedCookie(kYoutubeDomain);
CheckNoChromeConnectedCookieForDomain(kCountryGoogleDomain);
- id delegate =
- [OCMockObject mockForProtocol:@protocol(ManageAccountsDelegate)];
NSDictionary* headers = [NSDictionary dictionary];
NSHTTPURLResponse* response = [[NSHTTPURLResponse alloc]
@@ -371,7 +400,7 @@ TEST_F(AccountConsistencyServiceTest, SignInSignOut) {
HTTPVersion:@"HTTP/1.1"
headerFields:headers];
- SimulateNavigateToURL(response, delegate);
+ SimulateNavigateToURL(response, &delegate_);
// Check that cookies was also added for |kCountryGoogleDomain|.
CheckDomainHasChromeConnectedCookie(kGoogleDomain);
@@ -393,8 +422,6 @@ TEST_F(AccountConsistencyServiceTest, SignOutWithoutDomains) {
// Tests that the X-Chrome-Manage-Accounts header is ignored unless it comes
// from Gaia signon realm.
TEST_F(AccountConsistencyServiceTest, ChromeManageAccountsNotOnGaia) {
- id delegate =
- [OCMockObject mockForProtocol:@protocol(ManageAccountsDelegate)];
NSDictionary* headers =
[NSDictionary dictionaryWithObject:@"action=DEFAULT"
forKey:@"X-Chrome-Manage-Accounts"];
@@ -404,17 +431,13 @@ TEST_F(AccountConsistencyServiceTest, ChromeManageAccountsNotOnGaia) {
HTTPVersion:@"HTTP/1.1"
headerFields:headers];
- SimulateNavigateToURL(response, delegate);
-
- EXPECT_OCMOCK_VERIFY(delegate);
+ SimulateNavigateToURL(response, &delegate_);
+ EXPECT_EQ(0, delegate_.total_call_count());
}
// Tests that navigation to Gaia signon realm with no X-Chrome-Manage-Accounts
// header in the response are simply untouched.
TEST_F(AccountConsistencyServiceTest, ChromeManageAccountsNoHeader) {
- id delegate =
- [OCMockObject mockForProtocol:@protocol(ManageAccountsDelegate)];
-
NSDictionary* headers = [NSDictionary dictionary];
NSHTTPURLResponse* response = [[NSHTTPURLResponse alloc]
initWithURL:[NSURL URLWithString:@"https://accounts.google.com/"]
@@ -422,20 +445,14 @@ TEST_F(AccountConsistencyServiceTest, ChromeManageAccountsNoHeader) {
HTTPVersion:@"HTTP/1.1"
headerFields:headers];
- SimulateNavigateToURL(response, delegate);
-
- EXPECT_OCMOCK_VERIFY(delegate);
+ SimulateNavigateToURL(response, &delegate_);
+ EXPECT_EQ(0, delegate_.total_call_count());
}
// Tests that the ManageAccountsDelegate is notified when a navigation on Gaia
// signon realm returns with a X-Chrome-Manage-Accounts header with action
// DEFAULT.
TEST_F(AccountConsistencyServiceTest, ChromeManageAccountsDefault) {
- id delegate =
- [OCMockObject mockForProtocol:@protocol(ManageAccountsDelegate)];
- // Default action is |onManageAccounts|.
- [[delegate expect] onManageAccounts];
-
NSDictionary* headers =
[NSDictionary dictionaryWithObject:@"action=DEFAULT"
forKey:@"X-Chrome-Manage-Accounts"];
@@ -448,19 +465,15 @@ TEST_F(AccountConsistencyServiceTest, ChromeManageAccountsDefault) {
signin::GAIA_SERVICE_TYPE_DEFAULT))
.Times(1);
- SimulateNavigateToURLWithInterruption(response, delegate);
+ SimulateNavigateToURLWithInterruption(response, &delegate_);
- EXPECT_OCMOCK_VERIFY(delegate);
+ EXPECT_EQ(1, delegate_.total_call_count());
+ EXPECT_EQ(1, delegate_.manage_accounts_call_count_);
}
// Tests that the ManageAccountsDelegate is notified when a navigation on Gaia
// signon realm returns with a X-Auto-Login header.
TEST_F(AccountConsistencyServiceTest, ChromeShowConsistencyPromo) {
- id delegate =
- [OCMockObject mockForProtocol:@protocol(ManageAccountsDelegate)];
- [[[delegate expect] ignoringNonObjectArgs] onShowConsistencyPromo:GURL()
- webState:nullptr];
-
NSDictionary* headers = [NSDictionary dictionaryWithObject:@"args=unused"
forKey:@"X-Auto-Login"];
NSHTTPURLResponse* response = [[NSHTTPURLResponse alloc]
@@ -469,19 +482,15 @@ TEST_F(AccountConsistencyServiceTest, ChromeShowConsistencyPromo) {
HTTPVersion:@"HTTP/1.1"
headerFields:headers];
- SimulateNavigateToURL(response, delegate);
+ SimulateNavigateToURL(response, &delegate_);
- EXPECT_OCMOCK_VERIFY(delegate);
+ EXPECT_EQ(1, delegate_.total_call_count());
+ EXPECT_EQ(1, delegate_.show_promo_call_count_);
}
// Tests that the consistency promo is not displayed when a page fails to load.
TEST_F(AccountConsistencyServiceTest,
ChromeNotShowConsistencyPromoOnPageLoadFailure) {
- id delegate =
- [OCMockObject mockForProtocol:@protocol(ManageAccountsDelegate)];
- [[[delegate reject] ignoringNonObjectArgs] onShowConsistencyPromo:GURL()
- webState:nullptr];
-
NSDictionary* headers = [NSDictionary dictionaryWithObject:@"args=unused"
forKey:@"X-Auto-Login"];
NSHTTPURLResponse* response = [[NSHTTPURLResponse alloc]
@@ -490,21 +499,14 @@ TEST_F(AccountConsistencyServiceTest,
HTTPVersion:@"HTTP/1.1"
headerFields:headers];
- SimulateNavigateToURLWithPageLoadFailure(response, delegate);
-
- EXPECT_OCMOCK_VERIFY(delegate);
+ SimulateNavigateToURLWithPageLoadFailure(response, &delegate_);
+ EXPECT_EQ(0, delegate_.total_call_count());
}
// Tests that the consistency promo is not displayed when a page fails to load
// and user chooses another action.
TEST_F(AccountConsistencyServiceTest,
ChromeNotShowConsistencyPromoOnPageLoadFailureRedirect) {
- id delegate =
- [OCMockObject mockForProtocol:@protocol(ManageAccountsDelegate)];
- [[delegate expect] onAddAccount];
- [[[delegate reject] ignoringNonObjectArgs] onShowConsistencyPromo:GURL()
- webState:nullptr];
-
EXPECT_CALL(*account_reconcilor_, OnReceivedManageAccountsResponse(
signin::GAIA_SERVICE_TYPE_ADDSESSION));
@@ -516,7 +518,7 @@ TEST_F(AccountConsistencyServiceTest,
HTTPVersion:@"HTTP/1.1"
headerFields:headers];
- SimulateNavigateToURLWithPageLoadFailure(responseSignin, delegate);
+ SimulateNavigateToURLWithPageLoadFailure(responseSignin, &delegate_);
NSDictionary* headersAddAccount =
[NSDictionary dictionaryWithObject:@"action=ADDSESSION"
@@ -527,19 +529,17 @@ TEST_F(AccountConsistencyServiceTest,
HTTPVersion:@"HTTP/1.1"
headerFields:headersAddAccount];
- SimulateNavigateToURLWithInterruption(responseAddAccount, delegate);
+ SimulateNavigateToURLWithInterruption(responseAddAccount, &delegate_);
- EXPECT_OCMOCK_VERIFY(delegate);
+ EXPECT_EQ(1, delegate_.total_call_count());
+ EXPECT_EQ(1, delegate_.add_account_call_count_);
+ EXPECT_EQ(0, delegate_.show_promo_call_count_);
}
// Tests that the ManageAccountsDelegate is notified when a navigation on Gaia
// signon realm returns with a X-Chrome-Manage-Accounts header with ADDSESSION
// action.
TEST_F(AccountConsistencyServiceTest, ChromeManageAccountsShowAddAccount) {
- id delegate =
- [OCMockObject mockForProtocol:@protocol(ManageAccountsDelegate)];
- [[delegate expect] onAddAccount];
-
NSDictionary* headers =
[NSDictionary dictionaryWithObject:@"action=ADDSESSION"
forKey:@"X-Chrome-Manage-Accounts"];
@@ -552,9 +552,9 @@ TEST_F(AccountConsistencyServiceTest, ChromeManageAccountsShowAddAccount) {
signin::GAIA_SERVICE_TYPE_ADDSESSION))
.Times(1);
- SimulateNavigateToURLWithInterruption(response, delegate);
-
- EXPECT_OCMOCK_VERIFY(delegate);
+ SimulateNavigateToURLWithInterruption(response, &delegate_);
+ EXPECT_EQ(1, delegate_.total_call_count());
+ EXPECT_EQ(1, delegate_.add_account_call_count_);
}
// Tests that domains with cookie are correctly loaded from the prefs on service
@@ -619,8 +619,6 @@ TEST_F(AccountConsistencyServiceTest,
TEST_F(AccountConsistencyServiceTest, SetChromeConnectedCookie) {
SignIn();
- id delegate =
- [OCMockObject mockForProtocol:@protocol(ManageAccountsDelegate)];
NSDictionary* headers = [NSDictionary dictionary];
// HTTP response URL is eligible for Mirror (the test does not use google.com
@@ -631,10 +629,10 @@ TEST_F(AccountConsistencyServiceTest, SetChromeConnectedCookie) {
HTTPVersion:@"HTTP/1.1"
headerFields:headers];
- SimulateNavigateToURL(response, delegate);
+ SimulateNavigateToURL(response, &delegate_);
SimulateExternalSourceRemovesAllGoogleDomainCookies();
- SimulateNavigateToURL(response, delegate);
+ SimulateNavigateToURL(response, &delegate_);
CheckDomainHasChromeConnectedCookie(kGoogleDomain);
CheckDomainHasChromeConnectedCookie(kYoutubeDomain);
@@ -645,10 +643,6 @@ TEST_F(AccountConsistencyServiceTest, SetChromeConnectedCookie) {
TEST_F(AccountConsistencyServiceTest, GAIACookieMissingOnSignin) {
SignIn();
- id delegate =
- [OCMockObject mockForProtocol:@protocol(ManageAccountsDelegate)];
- [[delegate expect] onAddAccount];
-
NSDictionary* headers =
[NSDictionary dictionaryWithObject:@"action=ADDSESSION"
forKey:@"X-Chrome-Manage-Accounts"];
@@ -661,17 +655,18 @@ TEST_F(AccountConsistencyServiceTest, GAIACookieMissingOnSignin) {
signin::GAIA_SERVICE_TYPE_ADDSESSION))
.Times(2);
- SimulateNavigateToURL(response, delegate);
+ SimulateNavigateToURL(response, &delegate_);
base::HistogramTester histogram_tester;
histogram_tester.ExpectTotalCount(kGAIACookieOnNavigationHistogram, 0);
SimulateExternalSourceRemovesAllGoogleDomainCookies();
// Gaia cookie is not restored due to one-hour time restriction.
- SimulateNavigateToURLWithInterruption(response, delegate);
+ SimulateNavigateToURLWithInterruption(response, &delegate_);
histogram_tester.ExpectTotalCount(kGAIACookieOnNavigationHistogram, 1);
- EXPECT_OCMOCK_VERIFY(delegate);
+ EXPECT_EQ(1, delegate_.total_call_count());
+ EXPECT_EQ(1, delegate_.add_account_call_count_);
}
// Ensures that set and remove cookie operations are handled in the order
@@ -716,9 +711,6 @@ TEST_F(AccountConsistencyServiceTest, SetChromeConnectedCookiesAfterDelete) {
// is signed out and navigating to google.com.
TEST_F(AccountConsistencyServiceTest,
SetChromeConnectedCookiesSignedOutGoogleVisitor) {
- id delegate =
- [OCMockObject mockForProtocol:@protocol(ManageAccountsDelegate)];
-
NSDictionary* headers =
[NSDictionary dictionaryWithObject:@"action=ADDSESSION"
forKey:@"X-Chrome-Manage-Accounts"];
@@ -730,21 +722,16 @@ TEST_F(AccountConsistencyServiceTest,
CheckNoChromeConnectedCookies();
- SimulateNavigateToURL(response, delegate);
+ SimulateNavigateToURL(response, &delegate_);
CheckNoChromeConnectedCookies();
- EXPECT_OCMOCK_VERIFY(delegate);
+ EXPECT_EQ(0, delegate_.total_call_count());
}
// Ensures that CHROME_CONNECTED cookies are not set when the user is signed out
// after the sign-in promo is shown.
TEST_F(AccountConsistencyServiceTest,
SetChromeConnectedCookiesSignedOutGaiaVisitor) {
- id delegate =
- [OCMockObject mockForProtocol:@protocol(ManageAccountsDelegate)];
- [[[delegate expect] ignoringNonObjectArgs] onShowConsistencyPromo:GURL()
- webState:nullptr];
-
NSDictionary* headers = [NSDictionary dictionaryWithObject:@"args=unused"
forKey:@"X-Auto-Login"];
NSHTTPURLResponse* response = [[NSHTTPURLResponse alloc]
@@ -753,7 +740,7 @@ TEST_F(AccountConsistencyServiceTest,
HTTPVersion:@"HTTP/1.1"
headerFields:headers];
- SetWebStateHandler(delegate);
+ SetWebStateHandler(&delegate_);
EXPECT_TRUE(web_state_.ShouldAllowResponse(response,
/* for_main_frame = */ true));
@@ -761,7 +748,8 @@ TEST_F(AccountConsistencyServiceTest,
web_state_.OnPageLoaded(web::PageLoadCompletionStatus::SUCCESS);
CheckNoChromeConnectedCookies();
- EXPECT_OCMOCK_VERIFY(delegate);
+ EXPECT_EQ(1, delegate_.total_call_count());
+ EXPECT_EQ(1, delegate_.show_promo_call_count_);
}
TEST_F(AccountConsistencyServiceTest, SetGaiaCookieUpdateBeforeDelay) {
@@ -781,7 +769,7 @@ TEST_F(AccountConsistencyServiceTest, SetGaiaCookieUpdateBeforeDelay) {
// Advance clock, but stay within the one-hour Gaia update time.
base::TimeDelta oneMinuteDelta = base::Minutes(1);
task_environment_.FastForwardBy(oneMinuteDelta);
- SimulateNavigateToURLWithInterruption(response, nil);
+ SimulateNavigateToURLWithInterruption(response, nullptr);
// Does not process the second Gaia restore event.
CheckGaiaCookieWithUpdateTime(base::Time::Now() - oneMinuteDelta);
diff --git a/chromium/components/signin/ios/browser/features.cc b/chromium/components/signin/ios/browser/features.cc
index 27c8fcb3324..c3b4640bb80 100644
--- a/chromium/components/signin/ios/browser/features.cc
+++ b/chromium/components/signin/ios/browser/features.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "components/signin/ios/browser/features.h"
+
#include "components/signin/public/base/signin_switches.h"
namespace signin {
@@ -22,4 +23,10 @@ const char kDelayThresholdMinutesToUpdateGaiaCookie[] =
const char kWaitThresholdMillisecondsForCapabilitiesApi[] =
"wait-threshold-milliseconds-for-capabilities-api";
+const base::Feature kFREMobileIdentityConsistency{
+ "FREMobileIdentityConsistency", base::FEATURE_DISABLED_BY_DEFAULT};
+
+const base::Feature kEnableUnicornAccountSupport{
+ "EnableUnicornAccountSupport", base::FEATURE_DISABLED_BY_DEFAULT};
+
} // namespace signin
diff --git a/chromium/components/signin/ios/browser/features.h b/chromium/components/signin/ios/browser/features.h
index b301ec1e280..3a780500408 100644
--- a/chromium/components/signin/ios/browser/features.h
+++ b/chromium/components/signin/ios/browser/features.h
@@ -23,6 +23,12 @@ extern const char kDelayThresholdMinutesToUpdateGaiaCookie[];
// waiting for a response from the Account Capabilities API.
extern const char kWaitThresholdMillisecondsForCapabilitiesApi[];
+// Feature to enable FRE MICe.
+extern const base::Feature kFREMobileIdentityConsistency;
+
+// Feature to enable Unicorn account sign-in for iOS.
+extern const base::Feature kEnableUnicornAccountSupport;
+
} // namespace signin
#endif // COMPONENTS_SIGNIN_IOS_BROWSER_FEATURES_H_
diff --git a/chromium/components/signin/ios/browser/manage_accounts_delegate.h b/chromium/components/signin/ios/browser/manage_accounts_delegate.h
index 5d3293d269e..4a4c4ac6d83 100644
--- a/chromium/components/signin/ios/browser/manage_accounts_delegate.h
+++ b/chromium/components/signin/ios/browser/manage_accounts_delegate.h
@@ -10,32 +10,40 @@ namespace web {
class WebState;
}
-@protocol ManageAccountsDelegate<NSObject>
-
-// Called when Gaia cookies have been regenerated for a specific user sign-in.
-// This occurs when a SAPISID cookie has been deleted by the operating system.
-- (void)onRestoreGaiaCookies;
-
-// Called when the user taps on a manage accounts button in a Google web
-// property.
-- (void)onManageAccounts;
-
-// Called when the user taps on an add account button in a Google web property.
-- (void)onAddAccount;
-
-// Called when the user taps a sign-in or add account button in a Google web
-// property.
-// |url| is the continuation URL received from the server. If it is valid,
-// then this delegate should navigate to |url|.
-- (void)onShowConsistencyPromo:(const GURL&)url
- webState:(web::WebState*)webState;
-
-// Called when the user taps on go incognito button in a Google web property.
-// |url| is the continuation URL received from the server. If it is valid,
-// then this delegate should open an incognito tab and navigate to |url|.
-// If it is not valid, then this delegate should open a new incognito tab.
-- (void)onGoIncognito:(const GURL&)url;
-
-@end
+class ManageAccountsDelegate {
+ public:
+ ManageAccountsDelegate(const ManageAccountsDelegate&) = delete;
+ ManageAccountsDelegate& operator=(const ManageAccountsDelegate&) = delete;
+
+ virtual ~ManageAccountsDelegate() = default;
+
+ // Called when Gaia cookies have been regenerated for a specific user sign-in.
+ // This occurs when a SAPISID cookie has been deleted by the operating system.
+ virtual void OnRestoreGaiaCookies() = 0;
+
+ // Called when the user taps on a manage accounts button in a Google web
+ // property.
+ virtual void OnManageAccounts() = 0;
+
+ // Called when the user taps on an add account button in a Google web
+ // property.
+ virtual void OnAddAccount() = 0;
+
+ // Called when the user taps a sign-in or add account button in a Google web
+ // property.
+ // |url| is the continuation URL received from the server. If it is valid,
+ // then this delegate should navigate to |url|.
+ virtual void OnShowConsistencyPromo(const GURL& url,
+ web::WebState* webState) = 0;
+
+ // Called when the user taps on go incognito button in a Google web property.
+ // |url| is the continuation URL received from the server. If it is valid,
+ // then this delegate should open an incognito tab and navigate to |url|.
+ // If it is not valid, then this delegate should open a new incognito tab.
+ virtual void OnGoIncognito(const GURL& url) = 0;
+
+ protected:
+ ManageAccountsDelegate() = default;
+};
#endif // COMPONENTS_SIGNIN_IOS_BROWSER_MANAGE_ACCOUNTS_DELEGATE_H_
diff --git a/chromium/components/signin/public/android/BUILD.gn b/chromium/components/signin/public/android/BUILD.gn
index 53ace5c5c3d..51428c88de6 100644
--- a/chromium/components/signin/public/android/BUILD.gn
+++ b/chromium/components/signin/public/android/BUILD.gn
@@ -30,7 +30,6 @@ android_library("java") {
"java/src/org/chromium/components/signin/AccountsChangeObserver.java",
"java/src/org/chromium/components/signin/AuthException.java",
"java/src/org/chromium/components/signin/ChildAccountInfoFetcher.java",
- "java/src/org/chromium/components/signin/ChildAccountStatus.java",
"java/src/org/chromium/components/signin/ConnectionRetry.java",
"java/src/org/chromium/components/signin/PatternMatcher.java",
"java/src/org/chromium/components/signin/SystemAccountManagerDelegate.java",
diff --git a/chromium/components/signin/public/android/junit/src/org/chromium/components/signin/AccountManagerFacadeImplTest.java b/chromium/components/signin/public/android/junit/src/org/chromium/components/signin/AccountManagerFacadeImplTest.java
index 88aad1c98f5..715c1f75948 100644
--- a/chromium/components/signin/public/android/junit/src/org/chromium/components/signin/AccountManagerFacadeImplTest.java
+++ b/chromium/components/signin/public/android/junit/src/org/chromium/components/signin/AccountManagerFacadeImplTest.java
@@ -36,6 +36,7 @@ import org.mockito.quality.Strictness;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.android.util.concurrent.RoboExecutorService;
import org.robolectric.annotation.Config;
+import org.robolectric.annotation.LooperMode;
import org.robolectric.shadows.ShadowAccountManager;
import org.robolectric.shadows.ShadowUserManager;
@@ -59,6 +60,7 @@ import java.util.List;
@RunWith(BaseRobolectricTestRunner.class)
@Config(shadows = {CustomShadowAsyncTask.class, ShadowUserManager.class,
ShadowAccountManager.class})
+@LooperMode(LooperMode.Mode.LEGACY)
public class AccountManagerFacadeImplTest {
private static final String TEST_TOKEN_SCOPE = "test-token-scope";
@@ -257,37 +259,13 @@ public class AccountManagerFacadeImplTest {
}
@Test
- public void testCheckChildAccountForRegularChild() {
- final Account account = setFeaturesForAccount(
- "uca@gmail.com", AccountManagerFacadeImpl.FEATURE_IS_CHILD_ACCOUNT_KEY);
-
- mFacadeWithSystemDelegate.checkChildAccountStatus(account, mChildAccountStatusListenerMock);
-
- verify(mChildAccountStatusListenerMock)
- .onStatusReady(ChildAccountStatus.REGULAR_CHILD, account);
- }
-
- @Test
- public void testCheckChildAccountForUSMChild() {
+ public void testCheckChildAccount() {
final Account account = setFeaturesForAccount(
"usm@gmail.com", AccountManagerFacadeImpl.FEATURE_IS_USM_ACCOUNT_KEY);
mFacadeWithSystemDelegate.checkChildAccountStatus(account, mChildAccountStatusListenerMock);
- verify(mChildAccountStatusListenerMock)
- .onStatusReady(ChildAccountStatus.USM_CHILD, account);
- }
-
- @Test
- public void testCheckChildAccountForRegularUSMChild() {
- final Account account = setFeaturesForAccount("usm_uca@gmail.com",
- AccountManagerFacadeImpl.FEATURE_IS_USM_ACCOUNT_KEY,
- AccountManagerFacadeImpl.FEATURE_IS_CHILD_ACCOUNT_KEY);
-
- mFacadeWithSystemDelegate.checkChildAccountStatus(account, mChildAccountStatusListenerMock);
-
- verify(mChildAccountStatusListenerMock)
- .onStatusReady(ChildAccountStatus.REGULAR_CHILD, account);
+ verify(mChildAccountStatusListenerMock).onStatusReady(true, account);
}
@Test
@@ -296,7 +274,7 @@ public class AccountManagerFacadeImplTest {
mFacadeWithSystemDelegate.checkChildAccountStatus(account, mChildAccountStatusListenerMock);
- verify(mChildAccountStatusListenerMock).onStatusReady(ChildAccountStatus.NOT_CHILD, null);
+ verify(mChildAccountStatusListenerMock).onStatusReady(false, null);
}
@Test
diff --git a/chromium/components/signin/public/android/junit/src/org/chromium/components/signin/AccountRenameCheckerTest.java b/chromium/components/signin/public/android/junit/src/org/chromium/components/signin/AccountRenameCheckerTest.java
index af336538277..00e1e5abcac 100644
--- a/chromium/components/signin/public/android/junit/src/org/chromium/components/signin/AccountRenameCheckerTest.java
+++ b/chromium/components/signin/public/android/junit/src/org/chromium/components/signin/AccountRenameCheckerTest.java
@@ -19,6 +19,7 @@ import org.junit.runner.RunWith;
import org.robolectric.annotation.Config;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
+import org.robolectric.annotation.LooperMode;
import org.chromium.base.task.test.CustomShadowAsyncTask;
import org.chromium.base.test.BaseRobolectricTestRunner;
@@ -36,6 +37,7 @@ import java.util.concurrent.atomic.AtomicReference;
@RunWith(BaseRobolectricTestRunner.class)
@Config(shadows = {AccountRenameCheckerTest.ShadowGoogleAuthUtil.class,
CustomShadowAsyncTask.class})
+@LooperMode(LooperMode.Mode.LEGACY)
public class AccountRenameCheckerTest {
@Implements(GoogleAuthUtil.class)
static final class ShadowGoogleAuthUtil {
diff --git a/chromium/components/signin/public/android/junit/src/org/chromium/components/signin/AccountUtilsTest.java b/chromium/components/signin/public/android/junit/src/org/chromium/components/signin/AccountUtilsTest.java
index 2d1474eef0c..b673a4c25ab 100644
--- a/chromium/components/signin/public/android/junit/src/org/chromium/components/signin/AccountUtilsTest.java
+++ b/chromium/components/signin/public/android/junit/src/org/chromium/components/signin/AccountUtilsTest.java
@@ -47,7 +47,7 @@ public class AccountUtilsTest {
@Test
public void testChildAccountStatusWhenNoAccountsOnDevice() {
AccountUtils.checkChildAccountStatus(mFakeFacade, Collections.emptyList(), mListenerMock);
- verify(mListenerMock).onStatusReady(ChildAccountStatus.NOT_CHILD, null);
+ verify(mListenerMock).onStatusReady(/*is_child_account=*/false, null);
}
@Test
@@ -55,7 +55,7 @@ public class AccountUtilsTest {
// This is a supported configuration (where the second account might be an EDU account).
AccountUtils.checkChildAccountStatus(
mFakeFacade, List.of(CHILD_ACCOUNT1, EDU_ACCOUNT), mListenerMock);
- verify(mListenerMock).onStatusReady(ChildAccountStatus.REGULAR_CHILD, CHILD_ACCOUNT1);
+ verify(mListenerMock).onStatusReady(/*is_child_account=*/true, CHILD_ACCOUNT1);
}
@Test
@@ -64,25 +64,25 @@ public class AccountUtilsTest {
// is present then it must be the default one). This test is here for completeness.
AccountUtils.checkChildAccountStatus(
mFakeFacade, List.of(EDU_ACCOUNT, CHILD_ACCOUNT1), mListenerMock);
- verify(mListenerMock).onStatusReady(ChildAccountStatus.NOT_CHILD, null);
+ verify(mListenerMock).onStatusReady(/*is_child_account=*/false, null);
}
@Test
public void testChildAccountStatusWhenTwoAdultAccountsOnDevice() {
AccountUtils.checkChildAccountStatus(
mFakeFacade, List.of(ADULT_ACCOUNT1, ADULT_ACCOUNT2), mListenerMock);
- verify(mListenerMock).onStatusReady(ChildAccountStatus.NOT_CHILD, null);
+ verify(mListenerMock).onStatusReady(/*is_child_account=*/false, null);
}
@Test
public void testChildAccountStatusWhenOnlyOneAdultAccountOnDevice() {
AccountUtils.checkChildAccountStatus(mFakeFacade, List.of(ADULT_ACCOUNT1), mListenerMock);
- verify(mListenerMock).onStatusReady(ChildAccountStatus.NOT_CHILD, null);
+ verify(mListenerMock).onStatusReady(/*is_child_account=*/false, null);
}
@Test
public void testChildAccountStatusWhenOnlyOneChildAccountOnDevice() {
AccountUtils.checkChildAccountStatus(mFakeFacade, List.of(CHILD_ACCOUNT1), mListenerMock);
- verify(mListenerMock).onStatusReady(ChildAccountStatus.REGULAR_CHILD, CHILD_ACCOUNT1);
+ verify(mListenerMock).onStatusReady(/*is_child_account=*/true, CHILD_ACCOUNT1);
}
}
diff --git a/chromium/components/signin/public/android/junit/src/org/chromium/components/signin/identitymanager/AccountTrackerServiceTest.java b/chromium/components/signin/public/android/junit/src/org/chromium/components/signin/identitymanager/AccountTrackerServiceTest.java
index 0b30930c4b2..dd9648bb5b3 100644
--- a/chromium/components/signin/public/android/junit/src/org/chromium/components/signin/identitymanager/AccountTrackerServiceTest.java
+++ b/chromium/components/signin/public/android/junit/src/org/chromium/components/signin/identitymanager/AccountTrackerServiceTest.java
@@ -32,6 +32,7 @@ import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.mockito.quality.Strictness;
import org.robolectric.annotation.Config;
+import org.robolectric.annotation.LooperMode;
import org.chromium.base.Promise;
import org.chromium.base.task.test.CustomShadowAsyncTask;
@@ -51,6 +52,7 @@ import java.util.concurrent.atomic.AtomicInteger;
*/
@RunWith(BaseRobolectricTestRunner.class)
@Config(manifest = Config.NONE, shadows = {CustomShadowAsyncTask.class})
+@LooperMode(LooperMode.Mode.LEGACY)
public class AccountTrackerServiceTest {
private static final long ACCOUNT_TRACKER_SERVICE_NATIVE = 10001L;
private static final String ACCOUNT_EMAIL = "test@gmail.com";
diff --git a/chromium/components/signin/public/base/account_consistency_method.cc b/chromium/components/signin/public/base/account_consistency_method.cc
index dbd69e50bf8..b1bc6af8743 100644
--- a/chromium/components/signin/public/base/account_consistency_method.cc
+++ b/chromium/components/signin/public/base/account_consistency_method.cc
@@ -4,15 +4,11 @@
#include "components/signin/public/base/account_consistency_method.h"
+#include "build/build_config.h"
namespace signin {
-// Do not merge the two feature flags.
-// Experiments for MICE will be run independently per platform (Android, iOS).
-#if defined(OS_ANDROID)
-// Feature flag for FRE related changes as part of MICE.
-const base::Feature kMobileIdentityConsistencyFRE{
- "MobileIdentityConsistencyFRE", base::FEATURE_DISABLED_BY_DEFAULT};
+#if BUILDFLAG(IS_ANDROID)
const base::Feature kMobileIdentityConsistencyPromos{
"MobileIdentityConsistencyPromos", base::FEATURE_ENABLED_BY_DEFAULT};
#endif
diff --git a/chromium/components/signin/public/base/account_consistency_method.h b/chromium/components/signin/public/base/account_consistency_method.h
index b5b7935097f..06028904800 100644
--- a/chromium/components/signin/public/base/account_consistency_method.h
+++ b/chromium/components/signin/public/base/account_consistency_method.h
@@ -14,13 +14,10 @@
namespace signin {
-#if defined(OS_ANDROID)
-// Feature flag for FRE related changes as part of MICE.
-extern const base::Feature kMobileIdentityConsistencyFRE;
-
+#if BUILDFLAG(IS_ANDROID)
// Feature flag for promo-related changes of `kMobileIdentityConsistency`.
extern const base::Feature kMobileIdentityConsistencyPromos;
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
enum class AccountConsistencyMethod : int {
// No account consistency.
diff --git a/chromium/components/signin/public/base/signin_metrics.cc b/chromium/components/signin/public/base/signin_metrics.cc
index fe89b842780..d7d90415914 100644
--- a/chromium/components/signin/public/base/signin_metrics.cc
+++ b/chromium/components/signin/public/base/signin_metrics.cc
@@ -12,6 +12,7 @@
#include "base/metrics/user_metrics.h"
#include "base/numerics/safe_conversions.h"
#include "base/time/time.h"
+#include "build/build_config.h"
namespace signin_metrics {
@@ -133,6 +134,7 @@ void RecordSigninUserActionForAccessPoint(AccessPoint access_point) {
case AccessPoint::ACCESS_POINT_FORCED_SIGNIN:
case AccessPoint::ACCESS_POINT_ACCOUNT_RENAMED:
case AccessPoint::ACCESS_POINT_WEB_SIGNIN:
+ case AccessPoint::ACCESS_POINT_SIGNIN_INTERCEPT_FIRST_RUN_EXPERIENCE:
NOTREACHED() << "Access point " << static_cast<int>(access_point)
<< " is not supposed to log signin user actions.";
break;
@@ -215,6 +217,7 @@ void RecordSigninWithDefaultUserActionForAccessPoint(
case AccessPoint::ACCESS_POINT_WEB_SIGNIN:
case AccessPoint::ACCESS_POINT_SAFETY_CHECK:
case AccessPoint::ACCESS_POINT_KALEIDOSCOPE:
+ case AccessPoint::ACCESS_POINT_SIGNIN_INTERCEPT_FIRST_RUN_EXPERIENCE:
NOTREACHED() << "Signin_SigninWithDefault_From* user actions"
<< " are not recorded for access_point "
<< static_cast<int>(access_point)
@@ -295,6 +298,7 @@ void RecordSigninNotDefaultUserActionForAccessPoint(
case AccessPoint::ACCESS_POINT_WEB_SIGNIN:
case AccessPoint::ACCESS_POINT_SAFETY_CHECK:
case AccessPoint::ACCESS_POINT_KALEIDOSCOPE:
+ case AccessPoint::ACCESS_POINT_SIGNIN_INTERCEPT_FIRST_RUN_EXPERIENCE:
NOTREACHED() << "Signin_SigninNotDefault_From* user actions"
<< " are not recorded for access point "
<< static_cast<int>(access_point)
@@ -379,6 +383,7 @@ void RecordSigninNewAccountNoExistingAccountUserActionForAccessPoint(
case AccessPoint::ACCESS_POINT_WEB_SIGNIN:
case AccessPoint::ACCESS_POINT_SAFETY_CHECK:
case AccessPoint::ACCESS_POINT_KALEIDOSCOPE:
+ case AccessPoint::ACCESS_POINT_SIGNIN_INTERCEPT_FIRST_RUN_EXPERIENCE:
// These access points do not support personalized sign-in promos, so
// |Signin_SigninNewAccountNoExistingAccount_From*| user actions should
// not be recorded for them. Note: To avoid bloating the sign-in APIs, the
@@ -466,6 +471,7 @@ void RecordSigninNewAccountExistingAccountUserActionForAccessPoint(
case AccessPoint::ACCESS_POINT_WEB_SIGNIN:
case AccessPoint::ACCESS_POINT_SAFETY_CHECK:
case AccessPoint::ACCESS_POINT_KALEIDOSCOPE:
+ case AccessPoint::ACCESS_POINT_SIGNIN_INTERCEPT_FIRST_RUN_EXPERIENCE:
// These access points do not support personalized sign-in promos, so
// |Signin_SigninNewAccountExistingAccount_From*| user actions should not
// be recorded for them. Note: To avoid bloating the sign-in APIs, the
@@ -651,7 +657,7 @@ void LogAuthError(const GoogleServiceAuthError& auth_error) {
void LogAccountReconcilorStateOnGaiaResponse(AccountReconcilorState state) {
UMA_HISTOGRAM_ENUMERATION("Signin.AccountReconcilorState.OnGaiaResponse",
- state, ACCOUNT_RECONCILOR_HISTOGRAM_COUNT);
+ state);
}
void LogAccountEquality(AccountEquality equality) {
@@ -879,6 +885,7 @@ void RecordSigninImpressionUserActionForAccessPoint(AccessPoint access_point) {
case AccessPoint::ACCESS_POINT_ACCOUNT_RENAMED:
case AccessPoint::ACCESS_POINT_WEB_SIGNIN:
case AccessPoint::ACCESS_POINT_SAFETY_CHECK:
+ case AccessPoint::ACCESS_POINT_SIGNIN_INTERCEPT_FIRST_RUN_EXPERIENCE:
NOTREACHED() << "Signin_Impression_From* user actions"
<< " are not recorded for access point "
<< static_cast<int>(access_point);
@@ -1014,6 +1021,7 @@ void RecordSigninImpressionWithAccountUserActionForAccessPoint(
case AccessPoint::ACCESS_POINT_WEB_SIGNIN:
case AccessPoint::ACCESS_POINT_SAFETY_CHECK:
case AccessPoint::ACCESS_POINT_KALEIDOSCOPE:
+ case AccessPoint::ACCESS_POINT_SIGNIN_INTERCEPT_FIRST_RUN_EXPERIENCE:
NOTREACHED() << "Signin_Impression{With|WithNo}Account_From* user actions"
<< " are not recorded for access point "
<< static_cast<int>(access_point)
@@ -1025,12 +1033,12 @@ void RecordSigninImpressionWithAccountUserActionForAccessPoint(
}
}
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
void RecordConsistencyPromoUserAction(AccountConsistencyPromoAction action) {
UMA_HISTOGRAM_ENUMERATION(
"Signin.AccountConsistencyPromoAction", static_cast<int>(action),
static_cast<int>(AccountConsistencyPromoAction::MAX));
}
-#endif // defined(OS_IOS)
+#endif // BUILDFLAG(IS_IOS)
} // namespace signin_metrics
diff --git a/chromium/components/signin/public/base/signin_metrics.h b/chromium/components/signin/public/base/signin_metrics.h
index 43ae5032632..2523c63fab2 100644
--- a/chromium/components/signin/public/base/signin_metrics.h
+++ b/chromium/components/signin/public/base/signin_metrics.h
@@ -168,6 +168,9 @@ enum class AccessPoint : int {
ACCESS_POINT_SAFETY_CHECK = 32,
ACCESS_POINT_KALEIDOSCOPE = 33,
ACCESS_POINT_ENTERPRISE_SIGNOUT_COORDINATOR = 34,
+ ACCESS_POINT_SIGNIN_INTERCEPT_FIRST_RUN_EXPERIENCE = 35,
+ // Add values above this line with a corresponding label to the
+ // "SigninAccessPoint" enum in tools/metrics/histograms/enums.xml
ACCESS_POINT_MAX, // This must be last.
};
@@ -210,7 +213,7 @@ enum class PromoAction : int {
PROMO_ACTION_NEW_ACCOUNT_EXISTING_ACCOUNT
};
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
// This class is used to record user action that was taken after
// receiving the header from Gaia in the web sign-in flow.
// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.components.signin.metrics
@@ -266,7 +269,7 @@ enum class AccountConsistencyPromoAction : int {
TIMEOUT_ERROR_SHOWN = 17,
MAX = 18,
};
-#endif // defined(OS_ANDROID) || defined(OS_IOS)
+#endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
// Enum values which enumerates all reasons to start sign in process.
// These values are persisted to logs. Entries should not be renumbered and
@@ -303,8 +306,11 @@ enum AccountReconcilorState {
ACCOUNT_RECONCILOR_ERROR,
// The account reconcilor will start running soon.
ACCOUNT_RECONCILOR_SCHEDULED,
+ // The account reconcilor is inactive, e.g. initializing or disabled.
+ ACCOUNT_RECONCILOR_INACTIVE,
+
// Always the last enumerated type.
- ACCOUNT_RECONCILOR_HISTOGRAM_COUNT,
+ kMaxValue = ACCOUNT_RECONCILOR_SCHEDULED,
};
// Values of histogram comparing account id and email.
@@ -402,7 +408,7 @@ enum class SourceForRefreshTokenOperation {
kAccountReconcilor_Reconcile = 12,
kDiceResponseHandler_Signin = 13,
kDiceResponseHandler_Signout = 14,
- kDiceTurnOnSyncHelper_Abort = 15,
+ kTurnOnSyncHelper_Abort = 15,
kMachineLogon_CredentialProvider = 16,
kTokenService_ExtractCredentials = 17,
// DEPRECATED on 09/2021 (used for force migration to DICE)
@@ -540,10 +546,10 @@ void RecordSigninImpressionWithAccountUserActionForAccessPoint(
AccessPoint access_point,
bool with_account);
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
// Records |Signin.AccountConsistencyPromoAction| histogram.
void RecordConsistencyPromoUserAction(AccountConsistencyPromoAction action);
-#endif // defined(OS_IOS)
+#endif // BUILDFLAG(IS_IOS)
} // namespace signin_metrics
diff --git a/chromium/components/signin/public/base/signin_metrics_unittest.cc b/chromium/components/signin/public/base/signin_metrics_unittest.cc
index 4002a434e58..58581394b77 100644
--- a/chromium/components/signin/public/base/signin_metrics_unittest.cc
+++ b/chromium/components/signin/public/base/signin_metrics_unittest.cc
@@ -146,6 +146,8 @@ class SigninMetricsTest : public ::testing::Test {
return "Kaleidoscope";
case AccessPoint::ACCESS_POINT_ENTERPRISE_SIGNOUT_COORDINATOR:
return "EnterpriseSignoutResignSheet";
+ case AccessPoint::ACCESS_POINT_SIGNIN_INTERCEPT_FIRST_RUN_EXPERIENCE:
+ return "SigninInterceptFirstRunExperience";
case AccessPoint::ACCESS_POINT_MAX:
NOTREACHED();
return "";
diff --git a/chromium/components/signin/public/base/signin_switches.cc b/chromium/components/signin/public/base/signin_switches.cc
index 95adc32a0b5..7f2ff625e4a 100644
--- a/chromium/components/signin/public/base/signin_switches.cc
+++ b/chromium/components/signin/public/base/signin_switches.cc
@@ -4,12 +4,22 @@
#include "components/signin/public/base/signin_switches.h"
-#include "base/feature_list.h"
-#include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
-
namespace switches {
+// All switches in alphabetical order.
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+const base::Feature kAccountIdMigration{"AccountIdMigration",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+#endif
+
+#if BUILDFLAG(IS_ANDROID)
+// If enabled, child accounts (i.e. Unicorn accounts) on Android do not have the
+// Sync feature forced on.
+const base::Feature kAllowSyncOffForChildAccounts{
+ "AllowSyncOffForChildAccounts", base::FEATURE_DISABLED_BY_DEFAULT};
+#endif
+
// Clears the token service before using it. This allows simulating the
// expiration of credentials during testing.
const char kClearTokenService[] = "clear-token-service";
@@ -17,17 +27,20 @@ const char kClearTokenService[] = "clear-token-service";
// Disables sending signin scoped device id to LSO with refresh token request.
const char kDisableSigninScopedDeviceId[] = "disable-signin-scoped-device-id";
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-const base::Feature kAccountIdMigration{"AccountIdMigration",
- base::FEATURE_DISABLED_BY_DEFAULT};
-#endif
+// This feature disables all extended sync promos.
+const base::Feature kForceDisableExtendedSyncPromos{
+ "ForceDisableExtendedSyncPromos", base::FEATURE_DISABLED_BY_DEFAULT};
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
+// Features to trigger the startup sign-in promo at boot.
const base::Feature kForceStartupSigninPromo{"ForceStartupSigninPromo",
base::FEATURE_DISABLED_BY_DEFAULT};
#endif
-const base::Feature kForceDisableExtendedSyncPromos{
- "ForceDisableExtendedSyncPromos", base::FEATURE_DISABLED_BY_DEFAULT};
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+// Allows local (not signed-in) profiles on lacros.
+const base::Feature kLacrosNonSyncingProfiles{
+ "LacrosNonSyncingProfiles", base::FEATURE_DISABLED_BY_DEFAULT};
+#endif
} // namespace switches
diff --git a/chromium/components/signin/public/base/signin_switches.h b/chromium/components/signin/public/base/signin_switches.h
index 061abc063ac..e394a215681 100644
--- a/chromium/components/signin/public/base/signin_switches.h
+++ b/chromium/components/signin/public/base/signin_switches.h
@@ -18,25 +18,28 @@ namespace switches {
// All switches in alphabetical order. The switches should be documented
// alongside the definition of their values in the .cc file.
-extern const char kClearTokenService[];
-extern const char kDisableSigninScopedDeviceId[];
#if BUILDFLAG(IS_CHROMEOS_ASH)
extern const base::Feature kAccountIdMigration;
#endif
-#if defined(OS_ANDROID)
-// This feature flag is used to wipe device data on child account signin.
-extern const base::Feature kWipeDataOnChildAccountSignin;
-#endif // defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
+extern const base::Feature kAllowSyncOffForChildAccounts;
+#endif
+
+extern const char kClearTokenService[];
-#if defined(OS_ANDROID) || defined(OS_IOS)
-// Features to trigger the startup sign-in promo at boot.
+extern const char kDisableSigninScopedDeviceId[];
+
+extern const base::Feature kForceDisableExtendedSyncPromos;
+
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
extern const base::Feature kForceStartupSigninPromo;
#endif
-// This feature disables all extended sync promos.
-extern const base::Feature kForceDisableExtendedSyncPromos;
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+extern const base::Feature kLacrosNonSyncingProfiles;
+#endif
} // namespace switches
diff --git a/chromium/components/signin/public/identity_manager/access_token_constants.cc b/chromium/components/signin/public/identity_manager/access_token_constants.cc
index cda6a367fb0..d18d4d050dc 100644
--- a/chromium/components/signin/public/identity_manager/access_token_constants.cc
+++ b/chromium/components/signin/public/identity_manager/access_token_constants.cc
@@ -57,6 +57,10 @@ const std::set<std::string> GetUnconsentedOAuth2Scopes() {
GaiaConstants::kPhotosModuleOAuth2Scope,
GaiaConstants::kPhotosModuleImageOAuth2Scope,
+ // Required for displaying information about parents on supervised child
+ // devices. Consent is obtained outside Chrome within Family Link flows.
+ GaiaConstants::kKidFamilyReadonlyOAuth2Scope,
+
// Required by ChromeOS only.
#if BUILDFLAG(IS_CHROMEOS_ASH)
GaiaConstants::kAccountsReauthOAuth2Scope,
diff --git a/chromium/components/signin/public/identity_manager/access_token_fetcher.cc b/chromium/components/signin/public/identity_manager/access_token_fetcher.cc
index a49158ae293..bb41d02c07f 100644
--- a/chromium/components/signin/public/identity_manager/access_token_fetcher.cc
+++ b/chromium/components/signin/public/identity_manager/access_token_fetcher.cc
@@ -97,7 +97,7 @@ AccessTokenFetcher::AccessTokenFetcher(
mode_(mode),
callback_(std::move(callback)) {
DCHECK(client_id_.empty() == client_secret_.empty());
- DCHECK(client_id_.empty() || !url_loader_factory);
+ DCHECK(client_id_.empty() || !url_loader_factory_);
if (mode_ == Mode::kImmediate || IsRefreshTokenAvailable()) {
StartAccessTokenRequest();
diff --git a/chromium/components/signin/public/identity_manager/access_token_fetcher.h b/chromium/components/signin/public/identity_manager/access_token_fetcher.h
index 3770ba05860..0595ef34757 100644
--- a/chromium/components/signin/public/identity_manager/access_token_fetcher.h
+++ b/chromium/components/signin/public/identity_manager/access_token_fetcher.h
@@ -251,7 +251,7 @@ class AccessTokenFetcher : public ProfileOAuth2TokenServiceObserver,
raw_ptr<ProfileOAuth2TokenService> token_service_;
// Suppress unused typedef warnings in some compiler builds when DCHECK is
// disabled.
- raw_ptr<PrimaryAccountManager> primary_account_manager_ ALLOW_UNUSED_TYPE;
+ [[maybe_unused]] raw_ptr<PrimaryAccountManager> primary_account_manager_;
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
const ScopeSet scopes_;
const Mode mode_;
diff --git a/chromium/components/signin/public/identity_manager/access_token_fetcher_unittest.cc b/chromium/components/signin/public/identity_manager/access_token_fetcher_unittest.cc
index 81f36b720a9..e9db325aa28 100644
--- a/chromium/components/signin/public/identity_manager/access_token_fetcher_unittest.cc
+++ b/chromium/components/signin/public/identity_manager/access_token_fetcher_unittest.cc
@@ -81,18 +81,11 @@ class AccessTokenFetcherTest
token_service_.RemoveAccessTokenDiagnosticsObserver(this);
}
- CoreAccountId AddSyncPrimaryAccount(const std::string& gaia_id,
- const std::string& email) {
+ CoreAccountId SetPrimaryAccount(const std::string& gaia_id,
+ const std::string& email,
+ ConsentLevel consent_level) {
CoreAccountInfo account_info = AddAccount(gaia_id, email);
- primary_account_manager_.SetSyncPrimaryAccountInfo(account_info);
-
- return account_info.account_id;
- }
-
- CoreAccountId AddPrimaryAccount(const std::string& gaia_id,
- const std::string& email) {
- CoreAccountInfo account_info = AddAccount(gaia_id, email);
- primary_account_manager_.SetUnconsentedPrimaryAccountInfo(account_info);
+ primary_account_manager_.SetPrimaryAccountInfo(account_info, consent_level);
return account_info.account_id;
}
@@ -225,7 +218,8 @@ TEST_F(AccessTokenFetcherTest, OneShotShouldCallBackOnFulfilledRequest) {
base::RunLoop run_loop;
set_on_access_token_request_callback(run_loop.QuitClosure());
- CoreAccountId account_id = AddSyncPrimaryAccount(kTestGaiaId, kTestEmail);
+ CoreAccountId account_id =
+ SetPrimaryAccount(kTestGaiaId, kTestEmail, ConsentLevel::kSync);
token_service()->UpdateCredentials(account_id, "refresh token");
// This should result in a request for an access token.
@@ -254,7 +248,8 @@ TEST_F(AccessTokenFetcherTest,
base::RunLoop run_loop;
set_on_access_token_request_callback(run_loop.QuitClosure());
- CoreAccountId account_id = AddSyncPrimaryAccount(kTestGaiaId, kTestEmail);
+ CoreAccountId account_id =
+ SetPrimaryAccount(kTestGaiaId, kTestEmail, ConsentLevel::kSync);
token_service()->UpdateCredentials(account_id, "refresh token");
// Since the refresh token is already available, this should result in an
@@ -285,7 +280,8 @@ TEST_F(AccessTokenFetcherTest,
base::RunLoop run_loop;
set_on_access_token_request_callback(run_loop.QuitClosure());
- CoreAccountId account_id = AddSyncPrimaryAccount(kTestGaiaId, kTestEmail);
+ CoreAccountId account_id =
+ SetPrimaryAccount(kTestGaiaId, kTestEmail, ConsentLevel::kSync);
// Since the refresh token is not available yet, this should just start
// waiting for it.
@@ -332,7 +328,8 @@ TEST_F(AccessTokenFetcherTest,
MockCallback<base::OnceClosure> access_token_request_callback;
set_on_access_token_request_callback(access_token_request_callback.Get());
- CoreAccountId account_id = AddSyncPrimaryAccount(kTestGaiaId, kTestEmail);
+ CoreAccountId account_id =
+ SetPrimaryAccount(kTestGaiaId, kTestEmail, ConsentLevel::kSync);
CoreAccountId other_account_id =
AddAccount(kTestGaiaId2, kTestEmail2).account_id;
@@ -356,7 +353,8 @@ TEST_F(AccessTokenFetcherTest, ShouldNotReplyIfDestroyed) {
base::RunLoop run_loop;
set_on_access_token_request_callback(run_loop.QuitClosure());
- CoreAccountId account_id = AddSyncPrimaryAccount(kTestGaiaId, kTestEmail);
+ CoreAccountId account_id =
+ SetPrimaryAccount(kTestGaiaId, kTestEmail, ConsentLevel::kSync);
token_service()->UpdateCredentials(account_id, "refresh token");
// This should result in a request for an access token.
@@ -382,7 +380,8 @@ TEST_F(AccessTokenFetcherTest, ReturnsErrorWhenAccountHasNoRefreshToken) {
base::RunLoop run_loop;
- CoreAccountId account_id = AddSyncPrimaryAccount(kTestGaiaId, kTestEmail);
+ CoreAccountId account_id =
+ SetPrimaryAccount(kTestGaiaId, kTestEmail, ConsentLevel::kSync);
// Account has no refresh token -> we should get called back.
auto fetcher = CreateFetcher(account_id, callback.Get(),
@@ -403,7 +402,8 @@ TEST_F(AccessTokenFetcherTest, CanceledAccessTokenRequest) {
base::RunLoop run_loop;
set_on_access_token_request_callback(run_loop.QuitClosure());
- CoreAccountId account_id = AddSyncPrimaryAccount(kTestGaiaId, kTestEmail);
+ CoreAccountId account_id =
+ SetPrimaryAccount(kTestGaiaId, kTestEmail, ConsentLevel::kSync);
token_service()->UpdateCredentials(account_id, "refresh token");
// This should result in a request for an access token.
@@ -433,7 +433,8 @@ TEST_F(AccessTokenFetcherTest, RefreshTokenRevoked) {
TestTokenCallback callback;
- CoreAccountId account_id = AddSyncPrimaryAccount(kTestGaiaId, kTestEmail);
+ CoreAccountId account_id =
+ SetPrimaryAccount(kTestGaiaId, kTestEmail, ConsentLevel::kSync);
token_service()->UpdateCredentials(account_id, "refresh token");
// This should result in a request for an access token.
@@ -457,7 +458,8 @@ TEST_F(AccessTokenFetcherTest, FailedAccessTokenRequest) {
TestTokenCallback callback;
- CoreAccountId account_id = AddSyncPrimaryAccount(kTestGaiaId, kTestEmail);
+ CoreAccountId account_id =
+ SetPrimaryAccount(kTestGaiaId, kTestEmail, ConsentLevel::kSync);
token_service()->UpdateCredentials(account_id, "refresh token");
// Signed in and refresh token already exists, so this should result in a
@@ -483,7 +485,8 @@ TEST_F(AccessTokenFetcherTest, MultipleRequestsForSameAccountFulfilled) {
base::RunLoop run_loop;
set_on_access_token_request_callback(run_loop.QuitClosure());
- CoreAccountId account_id = AddSyncPrimaryAccount(kTestGaiaId, kTestEmail);
+ CoreAccountId account_id =
+ SetPrimaryAccount(kTestGaiaId, kTestEmail, ConsentLevel::kSync);
token_service()->UpdateCredentials(account_id, "refresh token");
// This should result in a request for an access token.
@@ -520,7 +523,8 @@ TEST_F(AccessTokenFetcherTest, MultipleRequestsForDifferentAccountsFulfilled) {
base::RunLoop run_loop;
set_on_access_token_request_callback(run_loop.QuitClosure());
- CoreAccountId account_id = AddSyncPrimaryAccount(kTestGaiaId, kTestEmail);
+ CoreAccountId account_id =
+ SetPrimaryAccount(kTestGaiaId, kTestEmail, ConsentLevel::kSync);
token_service()->UpdateCredentials(account_id, "refresh token");
// This should result in a request for an access token.
@@ -574,7 +578,8 @@ TEST_F(AccessTokenFetcherTest,
base::RunLoop run_loop;
set_on_access_token_request_callback(run_loop.QuitClosure());
- CoreAccountId account_id = AddSyncPrimaryAccount(kTestGaiaId, kTestEmail);
+ CoreAccountId account_id =
+ SetPrimaryAccount(kTestGaiaId, kTestEmail, ConsentLevel::kSync);
token_service()->UpdateCredentials(account_id, "refresh token");
// This should result in a request for an access token.
@@ -629,7 +634,8 @@ TEST_F(AccessTokenFetcherTest, FetcherWithCustomURLLoaderFactory) {
base::RunLoop run_loop;
set_on_access_token_request_callback(run_loop.QuitClosure());
- CoreAccountId account_id = AddSyncPrimaryAccount(kTestGaiaId, kTestEmail);
+ CoreAccountId account_id =
+ SetPrimaryAccount(kTestGaiaId, kTestEmail, ConsentLevel::kSync);
token_service()->UpdateCredentials(account_id, "refresh token");
network::TestURLLoaderFactory test_url_loader_factory;
@@ -709,7 +715,8 @@ TEST_F(AccessTokenFetcherTest, FetcherWithCustomURLLoaderFactory) {
// Tests that a request with a consented client accessing an OAuth2 API
// that requires sync consent is fulfilled.
TEST_F(AccessTokenFetcherTest, FetcherWithConsentedClientAccessToConsentAPI) {
- CoreAccountId account_id = AddSyncPrimaryAccount(kTestGaiaId, kTestEmail);
+ CoreAccountId account_id =
+ SetPrimaryAccount(kTestGaiaId, kTestEmail, ConsentLevel::kSync);
VerifyScopeAccess(account_id, "test_consumer",
{GaiaConstants::kOAuth1LoginScope});
}
@@ -718,7 +725,8 @@ TEST_F(AccessTokenFetcherTest, FetcherWithConsentedClientAccessToConsentAPI) {
// that does not require sync consent is fulfilled.
TEST_F(AccessTokenFetcherTest,
FetcherWithConsentedClientAccessToUnconsentedAPI) {
- CoreAccountId account_id = AddSyncPrimaryAccount(kTestGaiaId, kTestEmail);
+ CoreAccountId account_id =
+ SetPrimaryAccount(kTestGaiaId, kTestEmail, ConsentLevel::kSync);
VerifyScopeAccess(account_id, "test_consumer",
{GaiaConstants::kChromeSafeBrowsingOAuth2Scope});
}
@@ -727,7 +735,8 @@ TEST_F(AccessTokenFetcherTest,
// that does not require consent is fulfilled.
TEST_F(AccessTokenFetcherTest,
FetcherWithUnconsentedClientAccessToUnconsentedAPI) {
- CoreAccountId account_id = AddPrimaryAccount(kTestGaiaId, kTestEmail);
+ CoreAccountId account_id =
+ SetPrimaryAccount(kTestGaiaId, kTestEmail, ConsentLevel::kSignin);
VerifyScopeAccess(account_id, "test_consumer",
{GaiaConstants::kChromeSafeBrowsingOAuth2Scope});
}
@@ -738,7 +747,8 @@ TEST_F(AccessTokenFetcherTest,
FetcherWithPriveledgedClientAccessToPriveledgedAPI) {
EXPECT_FALSE(GetPrivilegedOAuth2Consumers().empty());
for (const std::string& privileged_client : GetPrivilegedOAuth2Consumers()) {
- CoreAccountId account_id = AddPrimaryAccount(kTestGaiaId, kTestEmail);
+ CoreAccountId account_id =
+ SetPrimaryAccount(kTestGaiaId, kTestEmail, ConsentLevel::kSignin);
VerifyScopeAccess(account_id, privileged_client,
{GaiaConstants::kAnyApiOAuth2Scope});
}
@@ -749,7 +759,8 @@ TEST_F(AccessTokenFetcherTest,
TEST_F(AccessTokenFetcherTest, FetcherWithPriveledgedClientAccessToConsentAPI) {
EXPECT_FALSE(GetPrivilegedOAuth2Consumers().empty());
for (const std::string& privileged_client : GetPrivilegedOAuth2Consumers()) {
- CoreAccountId account_id = AddPrimaryAccount(kTestGaiaId, kTestEmail);
+ CoreAccountId account_id =
+ SetPrimaryAccount(kTestGaiaId, kTestEmail, ConsentLevel::kSignin);
VerifyScopeAccess(account_id, privileged_client,
{GaiaConstants::kOAuth1LoginScope});
}
@@ -761,7 +772,8 @@ TEST_F(AccessTokenFetcherTest,
FetcherWithPriveledgedClientAccessToUnconsentedAPI) {
EXPECT_FALSE(GetPrivilegedOAuth2Consumers().empty());
for (const std::string& privileged_client : GetPrivilegedOAuth2Consumers()) {
- CoreAccountId account_id = AddPrimaryAccount(kTestGaiaId, kTestEmail);
+ CoreAccountId account_id =
+ SetPrimaryAccount(kTestGaiaId, kTestEmail, ConsentLevel::kSignin);
VerifyScopeAccess(account_id, privileged_client,
{GaiaConstants::kChromeSafeBrowsingOAuth2Scope});
}
@@ -771,7 +783,8 @@ TEST_F(AccessTokenFetcherTest,
// that requires privileged access fails.
TEST_F(AccessTokenFetcherTest,
FetcherWithUnconsentedClientAccessToPrivelegedAPI) {
- CoreAccountId account_id = AddPrimaryAccount(kTestGaiaId, kTestEmail);
+ CoreAccountId account_id =
+ SetPrimaryAccount(kTestGaiaId, kTestEmail, ConsentLevel::kSignin);
EXPECT_CHECK_DEATH(VerifyScopeAccess(account_id, "test_consumer",
{GaiaConstants::kAnyApiOAuth2Scope}));
}
@@ -780,7 +793,8 @@ TEST_F(AccessTokenFetcherTest,
// API fails.
TEST_F(AccessTokenFetcherTest,
FetcherWithConsentedClientAccessToPrivilegedAPI) {
- CoreAccountId account_id = AddSyncPrimaryAccount(kTestGaiaId, kTestEmail);
+ CoreAccountId account_id =
+ SetPrimaryAccount(kTestGaiaId, kTestEmail, ConsentLevel::kSync);
EXPECT_CHECK_DEATH(VerifyScopeAccess(account_id, "test_consumer",
{GaiaConstants::kAnyApiOAuth2Scope}));
}
diff --git a/chromium/components/signin/public/identity_manager/account_info.cc b/chromium/components/signin/public/identity_manager/account_info.cc
index 2d5444fa7cc..06fe0eb79e8 100644
--- a/chromium/components/signin/public/identity_manager/account_info.cc
+++ b/chromium/components/signin/public/identity_manager/account_info.cc
@@ -3,9 +3,11 @@
// found in the LICENSE file.
#include "components/signin/public/identity_manager/account_info.h"
+
+#include "build/build_config.h"
#include "google_apis/gaia/gaia_auth_util.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "base/android/jni_string.h"
#include "components/signin/public/android/jni_headers/AccountInfo_jni.h"
#include "components/signin/public/android/jni_headers/CoreAccountId_jni.h"
@@ -150,7 +152,7 @@ std::ostream& operator<<(std::ostream& os, const CoreAccountInfo& account) {
return os;
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
base::android::ScopedJavaLocalRef<jobject> ConvertToJavaCoreAccountInfo(
JNIEnv* env,
const CoreAccountInfo& account_info) {
diff --git a/chromium/components/signin/public/identity_manager/account_info.h b/chromium/components/signin/public/identity_manager/account_info.h
index 1ec976376f3..5e95a0bf9ae 100644
--- a/chromium/components/signin/public/identity_manager/account_info.h
+++ b/chromium/components/signin/public/identity_manager/account_info.h
@@ -13,7 +13,7 @@
#include "google_apis/gaia/core_account_id.h"
#include "ui/gfx/image/image.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "base/android/scoped_java_ref.h"
#endif
@@ -94,7 +94,7 @@ bool operator==(const CoreAccountInfo& l, const CoreAccountInfo& r);
bool operator!=(const CoreAccountInfo& l, const CoreAccountInfo& r);
std::ostream& operator<<(std::ostream& os, const CoreAccountInfo& account);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Constructs a Java CoreAccountInfo from the provided C++ CoreAccountInfo
base::android::ScopedJavaLocalRef<jobject> ConvertToJavaCoreAccountInfo(
JNIEnv* env,
diff --git a/chromium/components/signin/public/identity_manager/accounts_cookie_mutator.h b/chromium/components/signin/public/identity_manager/accounts_cookie_mutator.h
index b7e4ac49327..a3d8c0cb57a 100644
--- a/chromium/components/signin/public/identity_manager/accounts_cookie_mutator.h
+++ b/chromium/components/signin/public/identity_manager/accounts_cookie_mutator.h
@@ -116,7 +116,7 @@ class AccountsCookieMutator {
// know that the contents of the Gaia cookie might have changed.
virtual void TriggerCookieJarUpdate() = 0;
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
// Forces the processing of GaiaCookieManagerService::OnCookieChange. On
// iOS, it's necessary to force-trigger the processing of cookie changes
// from the client as the normal mechanism for internally observing them
diff --git a/chromium/components/signin/public/identity_manager/accounts_cookie_mutator_unittest.cc b/chromium/components/signin/public/identity_manager/accounts_cookie_mutator_unittest.cc
index 6677e68dde2..cdea8a820b1 100644
--- a/chromium/components/signin/public/identity_manager/accounts_cookie_mutator_unittest.cc
+++ b/chromium/components/signin/public/identity_manager/accounts_cookie_mutator_unittest.cc
@@ -493,7 +493,7 @@ TEST_F(AccountsCookieMutatorTest, TriggerCookieJarUpdate_OneListedAccounts) {
GoogleServiceAuthError::NONE);
}
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
TEST_F(AccountsCookieMutatorTest, ForceTriggerOnCookieChange) {
PrepareURLLoaderResponsesForAction(
AccountsCookiesMutatorAction::kTriggerOnCookieChangeNoAccounts);
diff --git a/chromium/components/signin/public/identity_manager/device_accounts_synchronizer.h b/chromium/components/signin/public/identity_manager/device_accounts_synchronizer.h
index 20c2e3a551f..21dae3ef23f 100644
--- a/chromium/components/signin/public/identity_manager/device_accounts_synchronizer.h
+++ b/chromium/components/signin/public/identity_manager/device_accounts_synchronizer.h
@@ -24,7 +24,7 @@ class DeviceAccountsSynchronizer {
virtual void ReloadAllAccountsFromSystemWithPrimaryAccount(
const absl::optional<CoreAccountId>& primary_account_id) = 0;
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
// Reloads the information of the device-level account with |account_id|. The
// account will be visible in IdentityManager::GetAccountsWithRefreshTokens()
// with any persistent error cleared after this method is called.
diff --git a/chromium/components/signin/public/identity_manager/identity_manager.cc b/chromium/components/signin/public/identity_manager/identity_manager.cc
index bc38f4cc02a..d1bcdddae0f 100644
--- a/chromium/components/signin/public/identity_manager/identity_manager.cc
+++ b/chromium/components/signin/public/identity_manager/identity_manager.cc
@@ -24,7 +24,7 @@
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "base/android/jni_string.h"
#include "base/metrics/histogram_functions.h"
#include "components/signin/internal/identity_manager/profile_oauth2_token_service_delegate.h"
@@ -140,7 +140,7 @@ IdentityManager::IdentityManager(IdentityManager::InitParameters&& parameters)
base::BindRepeating(&IdentityManager::OnRefreshTokenRevokedFromSource,
base::Unretained(this)));
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
java_identity_manager_ = Java_IdentityManager_create(
base::android::AttachCurrentThread(), reinterpret_cast<intptr_t>(this),
token_service_->GetDelegate()->GetJavaObject());
@@ -162,7 +162,7 @@ IdentityManager::IdentityManager(IdentityManager::InitParameters&& parameters)
}
IdentityManager::~IdentityManager() {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
if (java_identity_manager_)
Java_IdentityManager_destroy(base::android::AttachCurrentThread(),
java_identity_manager_);
@@ -430,7 +430,7 @@ DiagnosticsProvider* IdentityManager::GetDiagnosticsProvider() {
return diagnostics_provider_.get();
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
base::android::ScopedJavaLocalRef<jobject>
IdentityManager::LegacyGetAccountTrackerServiceJavaObject() {
return account_tracker_service_->GetJavaObject();
@@ -545,7 +545,7 @@ AccountInfo IdentityManager::GetAccountInfoForAccountWithRefreshToken(
// enforce on Android due to the underlying relationship between
// O2TS::GetAccounts(), O2TS::RefreshTokenIsAvailable(), and
// O2TS::Observer::OnRefreshTokenAvailable().
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
DCHECK(HasAccountWithRefreshToken(account_id));
#endif
@@ -571,7 +571,7 @@ void IdentityManager::OnPrimaryAccountChanged(
GetPrimaryAccountId(event_details.GetCurrentState().consent_level));
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
if (java_identity_manager_) {
JNIEnv* env = base::android::AttachCurrentThread();
Java_IdentityManager_onPrimaryAccountChanged(
@@ -588,7 +588,7 @@ void IdentityManager::OnRefreshTokenAvailable(const CoreAccountId& account_id) {
for (auto& observer : observer_list_) {
observer.OnRefreshTokenUpdatedForAccount(account_info);
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
if (java_identity_manager_) {
JNIEnv* env = base::android::AttachCurrentThread();
Java_IdentityManager_onRefreshTokenUpdatedForAccount(
@@ -642,7 +642,7 @@ void IdentityManager::OnGaiaCookieDeletedByUserAction() {
for (auto& observer : observer_list_) {
observer.OnAccountsCookieDeletedByUserAction();
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
if (java_identity_manager_) {
Java_IdentityManager_onAccountsCookieDeletedByUserAction(
base::android::AttachCurrentThread(), java_identity_manager_);
@@ -703,7 +703,7 @@ void IdentityManager::OnAccountUpdated(const AccountInfo& info) {
for (auto& observer : observer_list_) {
observer.OnExtendedAccountInfoUpdated(info);
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
if (java_identity_manager_) {
if (account_info_fetch_start_times_.count(info.account_id) &&
!info.account_image.IsEmpty()) {
diff --git a/chromium/components/signin/public/identity_manager/identity_manager.h b/chromium/components/signin/public/identity_manager/identity_manager.h
index b3c710ec7ea..4cce79d3bf3 100644
--- a/chromium/components/signin/public/identity_manager/identity_manager.h
+++ b/chromium/components/signin/public/identity_manager/identity_manager.h
@@ -27,7 +27,7 @@
#include "components/signin/public/identity_manager/ubertoken_fetcher.h"
#include "google_apis/gaia/oauth2_access_token_manager.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "base/android/jni_android.h"
#include "base/containers/flat_map.h"
#include "base/time/time.h"
@@ -180,34 +180,35 @@ class IdentityManager : public KeyedService,
bool HasPrimaryAccount(ConsentLevel consent_level) const;
// Creates an AccessTokenFetcher given the passed-in information.
- std::unique_ptr<AccessTokenFetcher> CreateAccessTokenFetcherForAccount(
- const CoreAccountId& account_id,
- const std::string& oauth_consumer_name,
- const ScopeSet& scopes,
- AccessTokenFetcher::TokenCallback callback,
- AccessTokenFetcher::Mode mode) WARN_UNUSED_RESULT;
+ [[nodiscard]] std::unique_ptr<AccessTokenFetcher>
+ CreateAccessTokenFetcherForAccount(const CoreAccountId& account_id,
+ const std::string& oauth_consumer_name,
+ const ScopeSet& scopes,
+ AccessTokenFetcher::TokenCallback callback,
+ AccessTokenFetcher::Mode mode);
// Creates an AccessTokenFetcher given the passed-in information, allowing
// to specify a custom |url_loader_factory| as well.
- std::unique_ptr<AccessTokenFetcher> CreateAccessTokenFetcherForAccount(
+ [[nodiscard]] std::unique_ptr<AccessTokenFetcher>
+ CreateAccessTokenFetcherForAccount(
const CoreAccountId& account_id,
const std::string& oauth_consumer_name,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
const ScopeSet& scopes,
AccessTokenFetcher::TokenCallback callback,
- AccessTokenFetcher::Mode mode) WARN_UNUSED_RESULT;
+ AccessTokenFetcher::Mode mode);
// Creates an AccessTokenFetcher given the passed-in information, allowing to
// specify custom |client_id| and |client_secret| to identify the OAuth client
// app.
- std::unique_ptr<AccessTokenFetcher> CreateAccessTokenFetcherForClient(
- const CoreAccountId& account_id,
- const std::string& client_id,
- const std::string& client_secret,
- const std::string& oauth_consumer_name,
- const ScopeSet& scopes,
- AccessTokenFetcher::TokenCallback callback,
- AccessTokenFetcher::Mode mode) WARN_UNUSED_RESULT;
+ [[nodiscard]] std::unique_ptr<AccessTokenFetcher>
+ CreateAccessTokenFetcherForClient(const CoreAccountId& account_id,
+ const std::string& client_id,
+ const std::string& client_secret,
+ const std::string& oauth_consumer_name,
+ const ScopeSet& scopes,
+ AccessTokenFetcher::TokenCallback callback,
+ AccessTokenFetcher::Mode mode);
// If an entry exists in the cache of access tokens corresponding to the
// given information, removes that entry; in this case, the next access token
@@ -434,7 +435,7 @@ class IdentityManager : public KeyedService,
return account_consistency_;
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Returns a pointer to the AccountTrackerService Java instance associated
// with this object.
// TODO(https://crbug.com/934688): Eliminate this method once
@@ -711,7 +712,7 @@ class IdentityManager : public KeyedService,
AccountConsistencyMethod account_consistency_ =
AccountConsistencyMethod::kDisabled;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Java-side IdentityManager object.
base::android::ScopedJavaGlobalRef<jobject> java_identity_manager_;
diff --git a/chromium/components/signin/public/identity_manager/identity_manager_builder.cc b/chromium/components/signin/public/identity_manager/identity_manager_builder.cc
index f948d706318..b3d1243ee17 100644
--- a/chromium/components/signin/public/identity_manager/identity_manager_builder.cc
+++ b/chromium/components/signin/public/identity_manager/identity_manager_builder.cc
@@ -7,6 +7,7 @@
#include <string>
#include <utility>
+#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "components/image_fetcher/core/image_decoder.h"
#include "components/prefs/pref_service.h"
@@ -25,19 +26,19 @@
#include "components/signin/public/identity_manager/accounts_mutator.h"
#include "components/signin/public/identity_manager/device_accounts_synchronizer.h"
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
#include "components/signin/public/webdata/token_web_data.h"
#endif
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
#include "components/signin/public/identity_manager/ios/device_accounts_provider.h"
#endif
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
#include "components/signin/internal/identity_manager/device_accounts_synchronizer_impl.h"
#endif
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
#include "components/signin/internal/identity_manager/accounts_mutator_impl.h"
#endif
@@ -64,7 +65,7 @@ std::unique_ptr<PrimaryAccountManager> BuildPrimaryAccountManager(
PrefService* local_state) {
std::unique_ptr<PrimaryAccountManager> primary_account_manager;
std::unique_ptr<PrimaryAccountPolicyManager> policy_manager;
-#if !BUILDFLAG(IS_CHROMEOS_ASH) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_IOS)
policy_manager = std::make_unique<PrimaryAccountPolicyManagerImpl>(client);
#endif
primary_account_manager = std::make_unique<PrimaryAccountManager>(
@@ -79,7 +80,7 @@ std::unique_ptr<AccountsMutator> BuildAccountsMutator(
AccountTrackerService* account_tracker_service,
ProfileOAuth2TokenService* token_service,
PrimaryAccountManager* primary_account_manager) {
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
return std::make_unique<AccountsMutatorImpl>(
token_service, account_tracker_service, primary_account_manager, prefs);
#else
@@ -120,10 +121,10 @@ IdentityManager::InitParameters BuildIdentityManagerInitParameters(
#if BUILDFLAG(ENABLE_DICE_SUPPORT)
params->delete_signin_cookies_on_exit, params->token_web_data,
#endif
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
std::move(params->device_accounts_provider),
#endif
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
params->reauth_callback,
#endif
params->signin_client);
@@ -160,7 +161,7 @@ IdentityManager::InitParameters BuildIdentityManagerInitParameters(
params->signin_client, token_service.get(), account_tracker_service.get(),
std::move(params->image_decoder));
-#if defined(OS_IOS) || defined(OS_ANDROID)
+#if BUILDFLAG(IS_IOS) || BUILDFLAG(IS_ANDROID)
init_params.device_accounts_synchronizer =
std::make_unique<DeviceAccountsSynchronizerImpl>(
token_service->GetDelegate());
diff --git a/chromium/components/signin/public/identity_manager/identity_manager_builder.h b/chromium/components/signin/public/identity_manager/identity_manager_builder.h
index 21bc1f82e84..3f76111603d 100644
--- a/chromium/components/signin/public/identity_manager/identity_manager_builder.h
+++ b/chromium/components/signin/public/identity_manager/identity_manager_builder.h
@@ -14,11 +14,11 @@
#include "components/signin/public/base/signin_buildflags.h"
#include "components/signin/public/identity_manager/identity_manager.h"
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
#include "base/memory/scoped_refptr.h"
#endif
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include "base/callback.h"
#endif
@@ -29,7 +29,7 @@ class SigninClient;
class TokenWebData;
#endif
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
class DeviceAccountsProvider;
#endif
@@ -73,11 +73,11 @@ struct IdentityManagerBuildParams {
bool is_regular_profile = false;
#endif
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
std::unique_ptr<DeviceAccountsProvider> device_accounts_provider;
#endif
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
base::RepeatingCallback<bool()> reauth_callback;
#endif
};
diff --git a/chromium/components/signin/public/identity_manager/identity_manager_builder_unittest.cc b/chromium/components/signin/public/identity_manager/identity_manager_builder_unittest.cc
index 20fee48f400..8d57ea54e6e 100644
--- a/chromium/components/signin/public/identity_manager/identity_manager_builder_unittest.cc
+++ b/chromium/components/signin/public/identity_manager/identity_manager_builder_unittest.cc
@@ -19,7 +19,7 @@
#include "services/network/test/test_url_loader_factory.h"
#include "testing/gtest/include/gtest/gtest.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "components/signin/public/identity_manager/identity_test_utils.h"
#endif
@@ -27,7 +27,7 @@
#include "components/account_manager_core/mock_account_manager_facade.h"
#endif
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
#include "components/signin/public/identity_manager/ios/fake_device_accounts_provider.h"
#endif
@@ -67,7 +67,7 @@ TEST_F(IdentityManagerBuilderTest, BuildIdentityManagerInitParameters) {
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
base::FilePath dest_path = temp_dir.GetPath();
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
SetUpMockAccountManagerFacade();
#endif
@@ -81,7 +81,7 @@ TEST_F(IdentityManagerBuilderTest, BuildIdentityManagerInitParameters) {
params.profile_path = dest_path;
params.signin_client = GetSigninClient();
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
params.device_accounts_provider =
std::make_unique<FakeDeviceAccountsProvider>();
#endif
@@ -104,7 +104,7 @@ TEST_F(IdentityManagerBuilderTest, BuildIdentityManagerInitParameters) {
EXPECT_NE(init_params.primary_account_mutator, nullptr);
EXPECT_NE(init_params.accounts_cookie_mutator, nullptr);
EXPECT_NE(init_params.diagnostics_provider, nullptr);
-#if defined(OS_IOS) || defined(OS_ANDROID)
+#if BUILDFLAG(IS_IOS) || BUILDFLAG(IS_ANDROID)
EXPECT_NE(init_params.device_accounts_synchronizer, nullptr);
EXPECT_EQ(init_params.accounts_mutator, nullptr);
#else
diff --git a/chromium/components/signin/public/identity_manager/identity_manager_unittest.cc b/chromium/components/signin/public/identity_manager/identity_manager_unittest.cc
index b2a19425c68..5fb341a9e2e 100644
--- a/chromium/components/signin/public/identity_manager/identity_manager_unittest.cc
+++ b/chromium/components/signin/public/identity_manager/identity_manager_unittest.cc
@@ -56,7 +56,7 @@
#include "services/network/test/test_url_loader_factory.h"
#include "testing/gtest/include/gtest/gtest.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "components/signin/internal/identity_manager/child_account_info_fetcher_android.h"
#endif
@@ -417,8 +417,9 @@ class IdentityManagerTest : public testing::Test {
PrimaryAccountManagerSetup::kWithAuthenticatedAccout) {
CoreAccountId account_id =
account_tracker_service->SeedAccountInfo(kTestGaiaId, kTestEmail);
- primary_account_manager->SetSyncPrimaryAccountInfo(
- account_tracker_service->GetAccountInfo(account_id));
+ primary_account_manager->SetPrimaryAccountInfo(
+ account_tracker_service->GetAccountInfo(account_id),
+ ConsentLevel::kSync);
}
IdentityManager::InitParameters init_params;
@@ -437,7 +438,7 @@ class IdentityManagerTest : public testing::Test {
account_tracker_service.get(), token_service.get(),
primary_account_manager.get(), &pref_service_, account_consistency);
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
init_params.device_accounts_synchronizer =
std::make_unique<DeviceAccountsSynchronizerImpl>(
token_service->GetDelegate());
@@ -543,7 +544,7 @@ TEST_F(IdentityManagerTest, Construct) {
EXPECT_NE(identity_manager()->GetPrimaryAccountMutator(), nullptr);
EXPECT_NE(identity_manager()->GetAccountsCookieMutator(), nullptr);
EXPECT_NE(identity_manager()->GetDiagnosticsProvider(), nullptr);
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
EXPECT_EQ(identity_manager()->GetAccountsMutator(), nullptr);
EXPECT_NE(identity_manager()->GetDeviceAccountsSynchronizer(), nullptr);
#else
@@ -2454,7 +2455,7 @@ TEST_F(IdentityManagerTest, TestPickAccountIdForAccount) {
}
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
TEST_F(IdentityManagerTest, RefreshAccountInfoIfStale) {
// The flow of this test results in an interaction with
// ChildAccountInfoFetcherAndroid, which requires initialization of
diff --git a/chromium/components/signin/public/identity_manager/identity_mutator.cc b/chromium/components/signin/public/identity_manager/identity_mutator.cc
index 7e33dbdeedf..e0d1d8d02c7 100644
--- a/chromium/components/signin/public/identity_manager/identity_mutator.cc
+++ b/chromium/components/signin/public/identity_manager/identity_mutator.cc
@@ -4,13 +4,14 @@
#include "components/signin/public/identity_manager/identity_mutator.h"
+#include "build/build_config.h"
#include "components/signin/public/base/consent_level.h"
#include "components/signin/public/identity_manager/accounts_cookie_mutator.h"
#include "components/signin/public/identity_manager/accounts_mutator.h"
#include "components/signin/public/identity_manager/device_accounts_synchronizer.h"
#include "components/signin/public/identity_manager/primary_account_mutator.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "base/android/jni_string.h"
#include "components/signin/public/android/jni_headers/IdentityMutator_jni.h"
#include "components/signin/public/identity_manager/account_info.h"
@@ -18,7 +19,7 @@
namespace signin {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
JniIdentityMutator::JniIdentityMutator(IdentityMutator* identity_mutator)
: identity_mutator_(identity_mutator) {}
@@ -62,7 +63,7 @@ void JniIdentityMutator::ReloadAllAccountsFromSystemWithPrimaryAccount(
device_accounts_synchronizer->ReloadAllAccountsFromSystemWithPrimaryAccount(
primary_account_id);
}
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
IdentityMutator::IdentityMutator(
std::unique_ptr<PrimaryAccountMutator> primary_account_mutator,
@@ -77,7 +78,7 @@ IdentityMutator::IdentityMutator(
DCHECK(!accounts_mutator_ || !device_accounts_synchronizer_)
<< "Cannot have both an AccountsMutator and a DeviceAccountsSynchronizer";
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
jni_identity_mutator_.reset(new JniIdentityMutator(this));
java_identity_mutator_ = Java_IdentityMutator_Constructor(
base::android::AttachCurrentThread(),
@@ -86,14 +87,14 @@ IdentityMutator::IdentityMutator(
}
IdentityMutator::~IdentityMutator() {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
if (java_identity_mutator_)
Java_IdentityMutator_destroy(base::android::AttachCurrentThread(),
java_identity_mutator_);
#endif
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
base::android::ScopedJavaLocalRef<jobject> IdentityMutator::GetJavaObject() {
DCHECK(java_identity_mutator_);
return base::android::ScopedJavaLocalRef<jobject>(java_identity_mutator_);
diff --git a/chromium/components/signin/public/identity_manager/identity_mutator.h b/chromium/components/signin/public/identity_manager/identity_mutator.h
index 84f1a889c64..faca17ba0dd 100644
--- a/chromium/components/signin/public/identity_manager/identity_mutator.h
+++ b/chromium/components/signin/public/identity_manager/identity_mutator.h
@@ -9,7 +9,7 @@
#include "base/memory/raw_ptr.h"
#include "build/build_config.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "base/android/jni_android.h"
#endif
@@ -19,7 +19,7 @@ class AccountsCookieMutator;
class PrimaryAccountMutator;
class DeviceAccountsSynchronizer;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
class IdentityMutator;
// This class is the JNI interface accessing IdentityMutator.
@@ -86,7 +86,7 @@ class IdentityMutator {
IdentityMutator(const IdentityMutator& other) = delete;
IdentityMutator const& operator=(const IdentityMutator& other) = delete;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Get the reference on the java IdentityManager.
base::android::ScopedJavaLocalRef<jobject> GetJavaObject();
#endif
@@ -110,7 +110,7 @@ class IdentityMutator {
DeviceAccountsSynchronizer* GetDeviceAccountsSynchronizer();
private:
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// C++ endpoint for identity mutator calls originating from java.
std::unique_ptr<JniIdentityMutator> jni_identity_mutator_;
diff --git a/chromium/components/signin/public/identity_manager/identity_test_environment.cc b/chromium/components/signin/public/identity_manager/identity_test_environment.cc
index 6275bcf530e..6ff97c052de 100644
--- a/chromium/components/signin/public/identity_manager/identity_test_environment.cc
+++ b/chromium/components/signin/public/identity_manager/identity_test_environment.cc
@@ -3,7 +3,6 @@
// found in the LICENSE file.
#include "components/signin/public/identity_manager/identity_test_environment.h"
-#include "base/memory/raw_ptr.h"
#include <limits>
#include <memory>
@@ -13,6 +12,7 @@
#include "base/bind.h"
#include "base/callback_helpers.h"
+#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
@@ -51,12 +51,12 @@
#include "components/account_manager_core/chromeos/account_manager_facade_factory.h"
#endif
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
#include "components/signin/internal/identity_manager/device_accounts_synchronizer_impl.h"
#include "components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_ios.h"
#endif
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
#include "components/signin/internal/identity_manager/accounts_mutator_impl.h"
#endif
@@ -357,7 +357,7 @@ IdentityTestEnvironment::FinishBuildIdentityManagerForTests(
account_tracker_service.get(), token_service.get(),
primary_account_manager.get(), pref_service, account_consistency);
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
init_params.accounts_mutator = std::make_unique<AccountsMutatorImpl>(
token_service.get(), account_tracker_service.get(),
primary_account_manager.get(), pref_service);
@@ -371,7 +371,7 @@ IdentityTestEnvironment::FinishBuildIdentityManagerForTests(
signin_client, token_service.get(), gaia_cookie_manager_service.get(),
account_tracker_service.get());
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
init_params.device_accounts_synchronizer =
std::make_unique<DeviceAccountsSynchronizerImpl>(
token_service->GetDelegate());
diff --git a/chromium/components/signin/public/identity_manager/identity_test_utils.cc b/chromium/components/signin/public/identity_manager/identity_test_utils.cc
index 168fb13fd43..a583e60bbe1 100644
--- a/chromium/components/signin/public/identity_manager/identity_test_utils.cc
+++ b/chromium/components/signin/public/identity_manager/identity_test_utils.cc
@@ -31,7 +31,7 @@
#include "components/account_manager_core/chromeos/account_manager_facade_factory.h"
#endif // BUILDFLAG(IS_CHROMEOS_LACROS)
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_android.h"
#include "components/signin/public/android/test_support_jni_headers/AccountManagerFacadeUtil_jni.h"
#endif
@@ -40,7 +40,7 @@ namespace signin {
namespace {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS)
// Whether identity_test_utils uses `AccountManagerFacade` or
// `ProfileOAuth2TokenService` for managing credentials.
bool ShouldUseAccountManagerFacade(IdentityManager* identity_manager) {
@@ -54,7 +54,7 @@ bool ShouldUseAccountManagerFacade(IdentityManager* identity_manager) {
return true;
#endif
}
-#endif // defined(OS_CHROMEOS)
+#endif // BUILDFLAG(IS_CHROMEOS)
// Helper function that updates the refresh token for |account_id| to
// |new_token|. Before updating the refresh token, blocks until refresh tokens
@@ -162,13 +162,7 @@ CoreAccountInfo SetPrimaryAccount(IdentityManager* identity_manager,
PrimaryAccountManager* primary_account_manager =
identity_manager->GetPrimaryAccountManager();
- switch (consent_level) {
- case ConsentLevel::kSync:
- primary_account_manager->SetSyncPrimaryAccountInfo(account_info);
- break;
- case ConsentLevel::kSignin:
- primary_account_manager->SetUnconsentedPrimaryAccountInfo(account_info);
- }
+ primary_account_manager->SetPrimaryAccountInfo(account_info, consent_level);
DCHECK(identity_manager->HasPrimaryAccount(consent_level));
DCHECK_EQ(account_info.gaia,
@@ -486,7 +480,7 @@ void EnableAccountCapabilitiesFetches(IdentityManager* identity_manager) {
->EnableAccountCapabilitiesFetcherForTest(true);
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
void SetUpMockAccountManagerFacade() {
Java_AccountManagerFacadeUtil_setUpMockFacade(
base::android::AttachCurrentThread());
diff --git a/chromium/components/signin/public/identity_manager/identity_test_utils.h b/chromium/components/signin/public/identity_manager/identity_test_utils.h
index cb09fc2e67b..499bb6ed890 100644
--- a/chromium/components/signin/public/identity_manager/identity_test_utils.h
+++ b/chromium/components/signin/public/identity_manager/identity_test_utils.h
@@ -21,7 +21,7 @@ class TestURLLoaderFactory;
namespace account_manager {
class AccountManagerFacade;
}
-#endif // defined(OS_CHROMEOS)
+#endif // BUILDFLAG(IS_CHROMEOS)
class GoogleServiceAuthError;
@@ -185,7 +185,7 @@ void DisableAccessTokenFetchRetries(IdentityManager* identity_manager);
// Enables account capabilities fetches in AccountFetcherService.
void EnableAccountCapabilitiesFetches(IdentityManager* identity_manager);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Stubs AccountManagerFacade, which requires special initialization of the java
// subsystems.
void SetUpMockAccountManagerFacade();
diff --git a/chromium/components/signin/public/identity_manager/primary_account_access_token_fetcher_unittest.cc b/chromium/components/signin/public/identity_manager/primary_account_access_token_fetcher_unittest.cc
index cbc4136a7a7..a4d347a6789 100644
--- a/chromium/components/signin/public/identity_manager/primary_account_access_token_fetcher_unittest.cc
+++ b/chromium/components/signin/public/identity_manager/primary_account_access_token_fetcher_unittest.cc
@@ -10,6 +10,7 @@
#include "base/run_loop.h"
#include "base/test/mock_callback.h"
#include "base/test/task_environment.h"
+#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "components/signin/public/base/consent_level.h"
#include "components/signin/public/identity_manager/access_token_info.h"
@@ -407,7 +408,7 @@ TEST_P(PrimaryAccountAccessTokenFetcherTest,
identity_test_env()->ClearPrimaryAccount();
}
-#endif // !OS_CHROMEOS
+#endif // !BUILDFLAG(IS_CHROMEOS)
TEST_P(PrimaryAccountAccessTokenFetcherTest,
ShouldNotRetryCanceledAccessTokenRequestIfRefreshTokenRevoked) {
diff --git a/chromium/components/signin/public/identity_manager/primary_account_change_event.cc b/chromium/components/signin/public/identity_manager/primary_account_change_event.cc
index 3c7c7d212c6..a152c963229 100644
--- a/chromium/components/signin/public/identity_manager/primary_account_change_event.cc
+++ b/chromium/components/signin/public/identity_manager/primary_account_change_event.cc
@@ -4,7 +4,9 @@
#include "components/signin/public/identity_manager/primary_account_change_event.h"
-#if defined(OS_ANDROID)
+#include "build/build_config.h"
+
+#if BUILDFLAG(IS_ANDROID)
#include "components/signin/public/android/jni_headers/PrimaryAccountChangeEvent_jni.h"
#endif
@@ -103,7 +105,7 @@ std::ostream& operator<<(std::ostream& os,
return os;
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
base::android::ScopedJavaLocalRef<jobject>
ConvertToJavaPrimaryAccountChangeEvent(
JNIEnv* env,
@@ -120,6 +122,6 @@ ConvertToJavaPrimaryAccountChangeEvent(
env, jint(event_type_not_required), jint(event_type_sync));
}
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
} // namespace signin
diff --git a/chromium/components/signin/public/identity_manager/primary_account_change_event.h b/chromium/components/signin/public/identity_manager/primary_account_change_event.h
index 508fea8593e..5b6dfba8cdd 100644
--- a/chromium/components/signin/public/identity_manager/primary_account_change_event.h
+++ b/chromium/components/signin/public/identity_manager/primary_account_change_event.h
@@ -9,7 +9,7 @@
#include "components/signin/public/base/consent_level.h"
#include "components/signin/public/identity_manager/account_info.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "base/android/scoped_java_ref.h"
#endif
@@ -68,7 +68,7 @@ std::ostream& operator<<(std::ostream& os,
std::ostream& operator<<(std::ostream& os,
const PrimaryAccountChangeEvent& event);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
base::android::ScopedJavaLocalRef<jobject>
ConvertToJavaPrimaryAccountChangeEvent(
JNIEnv* env,
diff --git a/chromium/components/signin/public/identity_manager/primary_account_mutator_unittest.cc b/chromium/components/signin/public/identity_manager/primary_account_mutator_unittest.cc
index 36c6081bfbb..24abd003994 100644
--- a/chromium/components/signin/public/identity_manager/primary_account_mutator_unittest.cc
+++ b/chromium/components/signin/public/identity_manager/primary_account_mutator_unittest.cc
@@ -448,13 +448,9 @@ TEST_F(PrimaryAccountMutatorTest, ClearPrimaryAccount_NotSignedIn) {
// consistency method.
TEST_F(PrimaryAccountMutatorTest, ClearPrimaryAccount) {
const signin::AccountConsistencyMethod kTestedAccountConsistencyMethods[] = {
- signin::AccountConsistencyMethod::kDisabled,
-#if !BUILDFLAG(IS_CHROMEOS_LACROS)
- // Signout is not supported with Mirror on Lacros.
- // TODO(https://crbug.com/1260291): Re-enable when signout is supported.
- signin::AccountConsistencyMethod::kMirror,
-#endif
- signin::AccountConsistencyMethod::kDice,
+ signin::AccountConsistencyMethod::kDisabled,
+ signin::AccountConsistencyMethod::kMirror,
+ signin::AccountConsistencyMethod::kDice,
};
for (signin::AccountConsistencyMethod account_consistency_method :
kTestedAccountConsistencyMethods) {
@@ -470,15 +466,16 @@ TEST_F(PrimaryAccountMutatorTest, RevokeSyncConsent_DisabledConsistency) {
}
// Test that revoking sync consent when Mirror account consistency is enabled
-// clears the primary account.
-#if !BUILDFLAG(IS_CHROMEOS_LACROS)
-// Revoking sync consent not supported with Mirror on Lacros.
-// TODO(https://crbug.com/1260291): Re-enable when it is supported.
+// clears the primary account (except for lacros).
TEST_F(PrimaryAccountMutatorTest, RevokeSyncConsent_MirrorConsistency) {
RunRevokeSyncConsentTest(signin::AccountConsistencyMethod::kMirror,
- RemoveAccountExpectation::kRemoveAll);
-}
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+ RemoveAccountExpectation::kKeepAll
+#else
+ RemoveAccountExpectation::kRemoveAll
#endif
+ );
+}
// Test that revoking the sync consent when DICE account consistency is
// enabled does not clear the primary account.
diff --git a/chromium/components/signin/public/identity_manager/ubertoken_fetcher.h b/chromium/components/signin/public/identity_manager/ubertoken_fetcher.h
index 178f1acfe79..cc473321fb1 100644
--- a/chromium/components/signin/public/identity_manager/ubertoken_fetcher.h
+++ b/chromium/components/signin/public/identity_manager/ubertoken_fetcher.h
@@ -5,9 +5,9 @@
#ifndef COMPONENTS_SIGNIN_PUBLIC_IDENTITY_MANAGER_UBERTOKEN_FETCHER_H_
#define COMPONENTS_SIGNIN_PUBLIC_IDENTITY_MANAGER_UBERTOKEN_FETCHER_H_
-#include <memory>
+#include <string>
-#include "base/bind.h"
+#include "base/callback_forward.h"
class GoogleServiceAuthError;
diff --git a/chromium/components/signin/public/webdata/token_web_data.h b/chromium/components/signin/public/webdata/token_web_data.h
index 64c8aab5a6f..6e606e70849 100644
--- a/chromium/components/signin/public/webdata/token_web_data.h
+++ b/chromium/components/signin/public/webdata/token_web_data.h
@@ -13,7 +13,6 @@
#include <string>
#include <vector>
-#include "base/location.h"
#include "base/memory/ref_counted.h"
#include "components/signin/public/webdata/token_service_table.h"
#include "components/webdata/common/web_data_results.h"
diff --git a/chromium/components/site_engagement/content/site_engagement_score.cc b/chromium/components/site_engagement/content/site_engagement_score.cc
index 44407334644..1b715ff6cf0 100644
--- a/chromium/components/site_engagement/content/site_engagement_score.cc
+++ b/chromium/components/site_engagement/content/site_engagement_score.cc
@@ -16,6 +16,7 @@
#include "components/content_settings/core/browser/host_content_settings_map.h"
#include "components/content_settings/core/common/content_settings.h"
#include "components/content_settings/core/common/content_settings_types.h"
+#include "components/content_settings/core/common/content_settings_utils.h"
#include "components/site_engagement/content/engagement_type.h"
#include "components/site_engagement/content/site_engagement_metrics.h"
#include "components/variations/variations_associated_data.h"
@@ -47,9 +48,10 @@ std::unique_ptr<base::DictionaryValue> GetSiteEngagementScoreDictForSettings(
if (!settings)
return std::make_unique<base::DictionaryValue>();
- std::unique_ptr<base::DictionaryValue> value =
- base::DictionaryValue::From(settings->GetWebsiteSetting(
- origin_url, origin_url, ContentSettingsType::SITE_ENGAGEMENT, NULL));
+ std::unique_ptr<base::DictionaryValue> value = base::DictionaryValue::From(
+ content_settings::ToNullableUniquePtrValue(settings->GetWebsiteSetting(
+ origin_url, origin_url, ContentSettingsType::SITE_ENGAGEMENT,
+ nullptr)));
if (value.get())
return value;
@@ -277,7 +279,7 @@ void SiteEngagementScore::Commit() {
settings_map_->SetWebsiteSettingDefaultScope(
origin_, GURL(), ContentSettingsType::SITE_ENGAGEMENT,
- std::move(score_dict_));
+ base::Value::FromUniquePtrValue(std::move(score_dict_)));
}
blink::mojom::EngagementLevel SiteEngagementScore::GetEngagementLevel() const {
diff --git a/chromium/components/site_engagement/content/site_engagement_service.cc b/chromium/components/site_engagement/content/site_engagement_service.cc
index bb19a1313f3..4ae3fb19be6 100644
--- a/chromium/components/site_engagement/content/site_engagement_service.cc
+++ b/chromium/components/site_engagement/content/site_engagement_service.cc
@@ -14,11 +14,13 @@
#include "base/metrics/field_trial.h"
#include "base/strings/string_util.h"
#include "base/task/thread_pool.h"
+#include "base/threading/thread_restrictions.h"
#include "base/time/clock.h"
#include "base/time/default_clock.h"
#include "base/time/time.h"
#include "base/trace_event/trace_event.h"
#include "base/values.h"
+#include "build/build_config.h"
#include "components/browsing_data/core/browsing_data_utils.h"
#include "components/content_settings/core/browser/host_content_settings_map.h"
#include "components/content_settings/core/common/content_settings_pattern.h"
@@ -37,7 +39,7 @@
#include "content/public/browser/web_contents.h"
#include "url/gurl.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "components/site_engagement/content/android/site_engagement_service_android.h"
#endif
@@ -220,6 +222,7 @@ SiteEngagementService::GetAllDetailsInBackground(
base::Time now,
scoped_refptr<HostContentSettingsMap> map) {
StoppedClock clock(now);
+ base::AssertLongCPUWorkAllowed();
return GetAllDetailsImpl(browsing_data::TimePeriod::ALL_TIME, &clock,
map.get());
}
@@ -255,7 +258,6 @@ std::vector<mojom::SiteEngagementDetails> SiteEngagementService::GetAllDetails()
const {
if (IsLastEngagementStale())
CleanupEngagementScores(true);
-
return GetAllDetailsImpl(
browsing_data::TimePeriod::ALL_TIME, clock_,
permissions::PermissionsClient::Get()->GetSettingsMap(browser_context_));
@@ -378,7 +380,7 @@ void SiteEngagementService::AddPointsForTesting(const GURL& url,
AddPoints(url, points);
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
SiteEngagementServiceAndroid* SiteEngagementService::GetAndroidService() const {
return android_service_.get();
}
@@ -482,7 +484,7 @@ void SiteEngagementService::CleanupEngagementScores(
// This origin has a score of 0. Wipe it from content settings.
settings_map->SetWebsiteSettingDefaultScope(
- origin, GURL(), ContentSettingsType::SITE_ENGAGEMENT, nullptr);
+ origin, GURL(), ContentSettingsType::SITE_ENGAGEMENT, base::Value());
}
// Set the last engagement time to be consistent with the scores. This will
diff --git a/chromium/components/site_engagement/content/site_engagement_service.h b/chromium/components/site_engagement/content/site_engagement_service.h
index 7413d36eec0..c54b3c8c6f4 100644
--- a/chromium/components/site_engagement/content/site_engagement_service.h
+++ b/chromium/components/site_engagement/content/site_engagement_service.h
@@ -48,7 +48,7 @@ enum class EngagementType;
class SiteEngagementObserver;
class SiteEngagementScore;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
class SiteEngagementServiceAndroid;
#endif
@@ -220,7 +220,7 @@ class SiteEngagementService : public KeyedService,
FRIEND_TEST_ALL_PREFIXES(AppBannerSettingsHelperTest, SiteEngagementTrigger);
FRIEND_TEST_ALL_PREFIXES(HostedAppPWAOnlyTest, EngagementHistogram);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Shim class to expose the service to Java.
friend class SiteEngagementServiceAndroid;
SiteEngagementServiceAndroid* GetAndroidService() const;
@@ -311,7 +311,7 @@ class SiteEngagementService : public KeyedService,
// The clock used to vend times.
raw_ptr<base::Clock> clock_;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
std::unique_ptr<SiteEngagementServiceAndroid> android_service_;
#endif
diff --git a/chromium/components/site_isolation/features.cc b/chromium/components/site_isolation/features.cc
index cf3725d3817..0ee83daecb7 100644
--- a/chromium/components/site_isolation/features.cc
+++ b/chromium/components/site_isolation/features.cc
@@ -19,7 +19,7 @@ const base::Feature kSiteIsolationForPasswordSites {
"site-isolation-for-password-sites",
// Enabled by default on Android; see https://crbug.com/849815. Note that this
// should not affect Android Webview, which does not include this code.
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
base::FEATURE_ENABLED_BY_DEFAULT
#else
base::FEATURE_DISABLED_BY_DEFAULT
@@ -40,7 +40,7 @@ const base::Feature kSiteIsolationForPasswordSites {
const base::Feature kSiteIsolationForOAuthSites{
"SiteIsolationForOAuthSites",
// Enabled by default on Android only; see https://crbug.com/1206770.
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
base::FEATURE_ENABLED_BY_DEFAULT
#else
base::FEATURE_DISABLED_BY_DEFAULT
diff --git a/chromium/components/site_isolation/site_isolation_policy.cc b/chromium/components/site_isolation/site_isolation_policy.cc
index 773fbfc833e..d7caa5a3b0d 100644
--- a/chromium/components/site_isolation/site_isolation_policy.cc
+++ b/chromium/components/site_isolation/site_isolation_policy.cc
@@ -17,6 +17,7 @@
#include "components/user_prefs/user_prefs.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/site_instance.h"
+#include "content/public/browser/site_isolation_mode.h"
#include "content/public/browser/site_isolation_policy.h"
#include "content/public/common/content_features.h"
@@ -85,7 +86,7 @@ bool SiteIsolationPolicy::IsIsolationForOAuthSitesEnabled() {
// static
bool SiteIsolationPolicy::IsEnterprisePolicyApplicable() {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// https://crbug.com/844118: Limiting policy to devices with > 1GB RAM.
// Using 1077 rather than 1024 because 1) it helps ensure that devices with
// exactly 1GB of RAM won't get included because of inaccuracies or off-by-one
@@ -114,7 +115,7 @@ bool SiteIsolationPolicy::ShouldDisableSiteIsolationDueToMemoryThreshold(
// it doesn't, use a default that's slightly higher than 1GB (see
// https://crbug.com/844118).
int default_memory_threshold_mb;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
if (site_isolation_mode == content::SiteIsolationMode::kStrictSiteIsolation) {
default_memory_threshold_mb = 3200;
} else {
@@ -140,7 +141,7 @@ bool SiteIsolationPolicy::ShouldDisableSiteIsolationDueToMemoryThreshold(
return base::SysInfo::AmountOfPhysicalMemoryMB() <= memory_threshold_mb;
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
if (base::SysInfo::AmountOfPhysicalMemoryMB() <=
default_memory_threshold_mb) {
return true;
@@ -180,9 +181,9 @@ void SiteIsolationPolicy::PersistUserTriggeredIsolatedOrigin(
// See https://crbug.com/1172407.
ListPrefUpdate update(user_prefs::UserPrefs::Get(context),
site_isolation::prefs::kUserTriggeredIsolatedOrigins);
- base::ListValue* list = update.Get();
+ base::Value* list = update.Get();
base::Value value(origin.Serialize());
- if (!base::Contains(list->GetList(), value))
+ if (!base::Contains(list->GetListDeprecated(), value))
list->Append(std::move(value));
}
@@ -196,7 +197,7 @@ void SiteIsolationPolicy::PersistWebTriggeredIsolatedOrigin(
DictionaryPrefUpdate update(
user_prefs::UserPrefs::Get(context),
site_isolation::prefs::kWebTriggeredIsolatedOrigins);
- base::DictionaryValue* dict = update.Get();
+ base::Value* dict = update.Get();
// Add the origin. If it already exists, this will just update the
// timestamp.
@@ -235,7 +236,7 @@ void SiteIsolationPolicy::ApplyPersistedIsolatedOrigins(
std::vector<url::Origin> origins;
for (const auto& value : user_prefs::UserPrefs::Get(browser_context)
->GetList(prefs::kUserTriggeredIsolatedOrigins)
- ->GetList()) {
+ ->GetListDeprecated()) {
origins.push_back(url::Origin::Create(GURL(value.GetString())));
}
@@ -278,7 +279,7 @@ void SiteIsolationPolicy::ApplyPersistedIsolatedOrigins(
if (!expired_entries.empty()) {
DictionaryPrefUpdate update(pref_service,
prefs::kWebTriggeredIsolatedOrigins);
- base::DictionaryValue* updated_dict = update.Get();
+ base::Value* updated_dict = update.Get();
for (const auto& entry : expired_entries)
updated_dict->RemoveKey(entry);
}
diff --git a/chromium/components/site_isolation/site_isolation_policy_unittest.cc b/chromium/components/site_isolation/site_isolation_policy_unittest.cc
index b80078291ea..808e57c850d 100644
--- a/chromium/components/site_isolation/site_isolation_policy_unittest.cc
+++ b/chromium/components/site_isolation/site_isolation_policy_unittest.cc
@@ -245,7 +245,7 @@ TEST_F(WebTriggeredIsolatedOriginsPolicyTest, UpdatedMaxSize) {
DictionaryPrefUpdate update(
user_prefs::UserPrefs::Get(browser_context()),
site_isolation::prefs::kWebTriggeredIsolatedOrigins);
- base::DictionaryValue* dict = update.Get();
+ base::Value* dict = update.Get();
dict->SetKey("https://foo1.com", base::TimeToValue(base::Time::Now()));
dict->SetKey("https://foo2.com", base::TimeToValue(base::Time::Now()));
dict->SetKey("https://foo3.com", base::TimeToValue(base::Time::Now()));
@@ -346,7 +346,7 @@ TEST_F(PasswordSiteIsolationPolicyTest, ApplyPersistedIsolatedOrigins) {
// Add foo.com and bar.com to stored isolated origins.
{
ListPrefUpdate update(prefs(), prefs::kUserTriggeredIsolatedOrigins);
- base::ListValue* list = update.Get();
+ base::Value* list = update.Get();
list->Append("http://foo.com");
list->Append("https://bar.com");
}
@@ -427,7 +427,7 @@ TEST_F(NoPasswordSiteIsolationPolicyTest,
// Add foo.com to stored isolated origins.
{
ListPrefUpdate update(prefs(), prefs::kUserTriggeredIsolatedOrigins);
- base::ListValue* list = update.Get();
+ base::Value* list = update.Get();
list->Append("http://foo.com");
}
@@ -534,7 +534,7 @@ class SitePerProcessMemoryThresholdBrowserTest
// ContentBrowserClient::ShouldDisableSiteIsolation() returns true.
std::vector<url::Origin> expected_embedder_origins_;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// On Android we don't expect any trial origins because the 512MB
// physical memory used for testing is below the Android specific
// hardcoded 1024MB memory limit that disables site isolation.
@@ -577,7 +577,7 @@ INSTANTIATE_TEST_SUITE_P(
NoIsolation,
SitePerProcessMemoryThresholdBrowserTestNoIsolation,
testing::Values(
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Expect no isolation on Android because 512MB physical memory
// triggered by kEnableLowEndDeviceMode in SetUp() is below the 1024MB
// Android specific memory limit which disables site isolation for all
@@ -601,7 +601,7 @@ INSTANTIATE_TEST_SUITE_P(
INSTANTIATE_TEST_SUITE_P(Isolation,
SitePerProcessMemoryThresholdBrowserTestIsolation,
testing::Values(
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
// See the note above regarding why this
// expectation is different on Android.
SitePerProcessMemoryThresholdBrowserTestParams{
@@ -658,7 +658,7 @@ INSTANTIATE_TEST_SUITE_P(
TrialNoIsolatedOrigin,
SitePerProcessMemoryThresholdBrowserTestNoIsolatedOrigin,
testing::Values(
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// When the memory threshold is not explicitly specified, Android uses
// a 1900MB global memory threshold. The 512MB simulated device memory
// is below 1900MB, so the test origin should not be isolated.
@@ -766,7 +766,7 @@ TEST_F(EnabledPasswordSiteIsolationFieldTrialTest, BelowThreshold) {
// enabled on desktop. It should be disabled on Android, because Android
// defaults to a 1900MB memory threshold, which is above the 512MB physical
// memory that this test simulates.
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
EXPECT_FALSE(SiteIsolationPolicy::IsIsolationForPasswordSitesEnabled());
#else
EXPECT_TRUE(SiteIsolationPolicy::IsIsolationForPasswordSitesEnabled());
@@ -803,7 +803,7 @@ TEST_F(EnabledPasswordSiteIsolationFieldTrialTest, AboveThreshold) {
// enabled on desktop. It should be disabled on Android, because Android
// defaults to a 1900MB memory threshold, which is above the 512MB physical
// memory that this test simulates.
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
EXPECT_FALSE(SiteIsolationPolicy::IsIsolationForPasswordSitesEnabled());
#else
EXPECT_TRUE(SiteIsolationPolicy::IsIsolationForPasswordSitesEnabled());
@@ -978,7 +978,7 @@ TEST_F(EnabledStrictOriginIsolationFieldTrialTest,
// enabled on desktop. It should be disabled on Android, because Android
// defaults to a 1900MB memory threshold, which is above the 512MB physical
// memory that this test simulates.
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
EXPECT_FALSE(content::SiteIsolationPolicy::IsStrictOriginIsolationEnabled());
#else
EXPECT_TRUE(content::SiteIsolationPolicy::IsStrictOriginIsolationEnabled());
@@ -1041,7 +1041,7 @@ TEST_F(DisabledStrictOriginIsolationFieldTrialTest,
// The following tests verify that the list of Android's built-in isolated
// origins takes effect. This list is only used in official builds, and only
// when above the memory threshold.
-#if BUILDFLAG(GOOGLE_CHROME_BRANDING) && defined(OS_ANDROID)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING) && BUILDFLAG(IS_ANDROID)
class BuiltInIsolatedOriginsTest : public SiteIsolationPolicyTest {
public:
BuiltInIsolatedOriginsTest() = default;
diff --git a/chromium/components/soda/constants.cc b/chromium/components/soda/constants.cc
index aea5cd14d64..7330bfa5921 100644
--- a/chromium/components/soda/constants.cc
+++ b/chromium/components/soda/constants.cc
@@ -11,6 +11,8 @@
#include "base/files/file_path.h"
#include "base/notreached.h"
#include "base/path_service.h"
+#include "base/strings/strcat.h"
+#include "build/build_config.h"
#include "components/component_updater/component_updater_paths.h"
#include "components/crx_file/id_util.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
@@ -19,7 +21,16 @@ namespace speech {
const char kUsEnglishLocale[] = "en-US";
-#ifdef OS_WIN
+const char kSodaBinaryInstallationResult[] =
+ "SodaInstaller.BinaryInstallationResult";
+
+const char kSodaBinaryInstallationSuccessTimeTaken[] =
+ "SodaInstaller.BinaryInstallationSuccessTime";
+
+const char kSodaBinaryInstallationFailureTimeTaken[] =
+ "SodaInstaller.BinaryInstallationFailureTime";
+
+#if BUILDFLAG(IS_WIN)
constexpr base::FilePath::CharType kSodaBinaryRelativePath[] =
FILE_PATH_LITERAL("SODAFiles/SODA.dll");
#else
@@ -182,4 +193,28 @@ int GetLanguageDisplayName(const std::string& language_name) {
return 0;
}
+const std::string GetInstallationSuccessTimeMetricForLanguagePack(
+ const LanguageCode& language_code) {
+ auto config = GetLanguageComponentConfig(language_code);
+ DCHECK(config && config->language_name);
+ return base::StrCat({"SodaInstaller.Language.", config->language_name,
+ ".InstallationSuccessTime"});
+}
+
+const std::string GetInstallationFailureTimeMetricForLanguagePack(
+ const LanguageCode& language_code) {
+ auto config = GetLanguageComponentConfig(language_code);
+ DCHECK(config && config->language_name);
+ return base::StrCat({"SodaInstaller.Language.", config->language_name,
+ ".InstallationFailureTime"});
+}
+
+const std::string GetInstallationResultMetricForLanguagePack(
+ const LanguageCode& language_code) {
+ auto config = GetLanguageComponentConfig(language_code);
+ DCHECK(config && config->language_name);
+ return base::StrCat({"SodaInstaller.Language.", config->language_name,
+ ".InstallationResult"});
+}
+
} // namespace speech
diff --git a/chromium/components/soda/constants.h b/chromium/components/soda/constants.h
index 7ee3b26bf8a..990b42c11fa 100644
--- a/chromium/components/soda/constants.h
+++ b/chromium/components/soda/constants.h
@@ -16,6 +16,11 @@ namespace speech {
extern const char kUsEnglishLocale[];
+// Metrics names for keeping track of SODA installation.
+extern const char kSodaBinaryInstallationResult[];
+extern const char kSodaBinaryInstallationSuccessTimeTaken[];
+extern const char kSodaBinaryInstallationFailureTimeTaken[];
+
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
enum class LanguageCode {
@@ -159,6 +164,21 @@ LanguageCode GetLanguageCode(const std::string& language_name);
int GetLanguageDisplayName(const std::string& language_name);
+// Returns the `SodaInstaller.Language.{language}.InstallationSuccessTime` uma
+// metric string for the language code.
+const std::string GetInstallationSuccessTimeMetricForLanguagePack(
+ const LanguageCode& language_code);
+
+// Returns the `SodaInstaller.Language.{language}.InstallationFailureTime` uma
+// metric string for the language code.
+const std::string GetInstallationFailureTimeMetricForLanguagePack(
+ const LanguageCode& language_code);
+
+// Returns the `SodaInstaller.Language.{language}.InstallationResult` uma
+// metric string for the language code..
+const std::string GetInstallationResultMetricForLanguagePack(
+ const LanguageCode& language_code);
+
} // namespace speech
#endif // COMPONENTS_SODA_CONSTANTS_H_
diff --git a/chromium/components/soda/soda_installer.cc b/chromium/components/soda/soda_installer.cc
index 90e92950e19..37658048c00 100644
--- a/chromium/components/soda/soda_installer.cc
+++ b/chromium/components/soda/soda_installer.cc
@@ -81,10 +81,10 @@ void SodaInstaller::Init(PrefService* profile_prefs,
#if BUILDFLAG(IS_CHROMEOS_ASH)
if (!base::FeatureList::IsEnabled(
ash::features::kOnDeviceSpeechRecognition) ||
+ soda_installer_initialized_) {
#else // !BUILDFLAG(IS_CHROMEOS_ASH)
- if (!base::FeatureList::IsEnabled(media::kUseSodaForLiveCaption) ||
+ if (soda_installer_initialized_) {
#endif
- soda_installer_initialized_) {
return;
}
@@ -96,7 +96,7 @@ void SodaInstaller::Init(PrefService* profile_prefs,
SodaInstaller::GetInstance()->InstallSoda(global_prefs);
if (global_prefs->GetList(prefs::kSodaRegisteredLanguagePacks)
- ->GetList()
+ ->GetListDeprecated()
.empty()) {
// TODO(crbug.com/1200667): Register the default language used by
// Dictation on ChromeOS.
@@ -111,7 +111,7 @@ void SodaInstaller::Init(PrefService* profile_prefs,
for (const auto& language :
global_prefs->GetList(prefs::kSodaRegisteredLanguagePacks)
- ->GetList()) {
+ ->GetListDeprecated()) {
SodaInstaller::GetInstance()->InstallLanguage(language.GetString(),
global_prefs);
}
@@ -262,7 +262,7 @@ void SodaInstaller::NotifyOnSodaLanguagePackProgress(
void SodaInstaller::RegisterLanguage(const std::string& language,
PrefService* global_prefs) {
ListPrefUpdate update(global_prefs, prefs::kSodaRegisteredLanguagePacks);
- if (!base::Contains(update->GetList(), base::Value(language))) {
+ if (!base::Contains(update->GetListDeprecated(), base::Value(language))) {
update->Append(language);
}
}
diff --git a/chromium/components/soda/soda_installer_impl_chromeos.cc b/chromium/components/soda/soda_installer_impl_chromeos.cc
index 7b1b8e58f4f..7582987c351 100644
--- a/chromium/components/soda/soda_installer_impl_chromeos.cc
+++ b/chromium/components/soda/soda_installer_impl_chromeos.cc
@@ -6,7 +6,7 @@
#include "base/bind.h"
#include "base/feature_list.h"
-#include "base/no_destructor.h"
+#include "base/metrics/histogram_functions.h"
#include "base/numerics/safe_conversions.h"
#include "chromeos/dbus/dlcservice/dlcservice_client.h"
#include "components/live_caption/pref_names.h"
@@ -55,7 +55,7 @@ void SodaInstallerImplChromeOS::InstallSoda(PrefService* global_prefs) {
chromeos::DlcserviceClient::Get()->Install(
kSodaDlcName,
base::BindOnce(&SodaInstallerImplChromeOS::OnSodaInstalled,
- base::Unretained(this)),
+ base::Unretained(this), base::Time::Now()),
base::BindRepeating(&SodaInstallerImplChromeOS::OnSodaProgress,
base::Unretained(this)));
}
@@ -81,7 +81,8 @@ void SodaInstallerImplChromeOS::InstallLanguage(const std::string& language,
chromeos::DlcserviceClient::Get()->Install(
kSodaEnglishUsDlcName,
base::BindOnce(&SodaInstallerImplChromeOS::OnLanguageInstalled,
- base::Unretained(this)),
+ base::Unretained(this), LanguageCode::kEnUs,
+ base::Time::Now()),
base::BindRepeating(&SodaInstallerImplChromeOS::OnLanguageProgress,
base::Unretained(this)));
}
@@ -119,6 +120,7 @@ void SodaInstallerImplChromeOS::SetLanguagePath(base::FilePath new_path) {
}
void SodaInstallerImplChromeOS::OnSodaInstalled(
+ const base::Time start_time,
const chromeos::DlcserviceClient::InstallResult& install_result) {
is_soda_downloading_ = false;
if (install_result.error == dlcservice::kErrorNone) {
@@ -127,27 +129,49 @@ void SodaInstallerImplChromeOS::OnSodaInstalled(
if (IsLanguageInstalled(LanguageCode::kEnUs)) {
NotifyOnSodaInstalled();
}
+
+ base::UmaHistogramTimes(kSodaBinaryInstallationSuccessTimeTaken,
+ base::Time::Now() - start_time);
} else {
soda_binary_installed_ = false;
soda_progress_ = 0.0;
NotifyOnSodaError();
+ base::UmaHistogramTimes(kSodaBinaryInstallationFailureTimeTaken,
+ base::Time::Now() - start_time);
}
+
+ base::UmaHistogramBoolean(kSodaBinaryInstallationResult,
+ install_result.error == dlcservice::kErrorNone);
}
void SodaInstallerImplChromeOS::OnLanguageInstalled(
+ const LanguageCode language_code,
+ const base::Time start_time,
const chromeos::DlcserviceClient::InstallResult& install_result) {
- language_pack_progress_.erase(LanguageCode::kEnUs);
+ language_pack_progress_.erase(language_code);
if (install_result.error == dlcservice::kErrorNone) {
- installed_languages_.insert(LanguageCode::kEnUs);
+ installed_languages_.insert(language_code);
SetLanguagePath(base::FilePath(install_result.root_path));
if (soda_binary_installed_) {
NotifyOnSodaInstalled();
}
+ base::UmaHistogramTimes(
+ GetInstallationSuccessTimeMetricForLanguagePack(language_code),
+ base::Time::Now() - start_time);
+
} else {
- // TODO: Notify the observer of the specific language pack that failed to
- // install. ChromeOS currently only supports the en-US language pack.
- NotifyOnSodaLanguagePackError(LanguageCode::kEnUs);
+ // TODO: Notify the observer of the specific language pack that failed
+ // to install. ChromeOS currently only supports the en-US language pack.
+ NotifyOnSodaLanguagePackError(language_code);
+
+ base::UmaHistogramTimes(
+ GetInstallationFailureTimeMetricForLanguagePack(language_code),
+ base::Time::Now() - start_time);
}
+
+ base::UmaHistogramBoolean(
+ GetInstallationResultMetricForLanguagePack(language_code),
+ install_result.error == dlcservice::kErrorNone);
}
void SodaInstallerImplChromeOS::OnSodaProgress(double progress) {
diff --git a/chromium/components/soda/soda_installer_impl_chromeos.h b/chromium/components/soda/soda_installer_impl_chromeos.h
index f9fd32c0cad..024ab9ccd9d 100644
--- a/chromium/components/soda/soda_installer_impl_chromeos.h
+++ b/chromium/components/soda/soda_installer_impl_chromeos.h
@@ -54,8 +54,11 @@ class COMPONENT_EXPORT(SODA_INSTALLER) SodaInstallerImplChromeOS
// These functions are the InstallCallbacks for DlcserviceClient::Install().
void OnSodaInstalled(
+ const base::Time start_time,
const chromeos::DlcserviceClient::InstallResult& install_result);
void OnLanguageInstalled(
+ const LanguageCode language_code,
+ const base::Time start_time,
const chromeos::DlcserviceClient::InstallResult& install_result);
// These functions are the ProgressCallbacks for DlcserviceClient::Install().
diff --git a/chromium/components/soda/soda_installer_impl_chromeos_unittest.cc b/chromium/components/soda/soda_installer_impl_chromeos_unittest.cc
index faa2f1f22b2..97cfd783088 100644
--- a/chromium/components/soda/soda_installer_impl_chromeos_unittest.cc
+++ b/chromium/components/soda/soda_installer_impl_chromeos_unittest.cc
@@ -6,6 +6,7 @@
#include "ash/constants/ash_features.h"
#include "ash/constants/ash_pref_names.h"
+#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "chromeos/dbus/dbus_thread_manager.h"
@@ -19,6 +20,9 @@
namespace {
const speech::LanguageCode kEnglishLocale = speech::LanguageCode::kEnUs;
const base::TimeDelta kSodaUninstallTime = base::Days(30);
+
+constexpr char kSodaEnglishLanguageInstallationResult[] =
+ "SodaInstaller.Language.en-US.InstallationResult";
} // namespace
namespace speech {
@@ -129,11 +133,23 @@ class SodaInstallerImplChromeOSTest : public testing::Test {
};
TEST_F(SodaInstallerImplChromeOSTest, IsSodaInstalled) {
+ base::HistogramTester histogram_tester;
+
ASSERT_FALSE(IsSodaInstalled());
Init();
ASSERT_FALSE(IsSodaInstalled());
RunUntilIdle();
ASSERT_TRUE(IsSodaInstalled());
+
+ // SODA binary and english language installation never failed.
+ histogram_tester.ExpectBucketCount(kSodaBinaryInstallationResult, 0, 0);
+ histogram_tester.ExpectBucketCount(kSodaEnglishLanguageInstallationResult, 0,
+ 0);
+
+ // SODA binary and english language installation succeeded once.
+ histogram_tester.ExpectBucketCount(kSodaBinaryInstallationResult, 1, 1);
+ histogram_tester.ExpectBucketCount(kSodaEnglishLanguageInstallationResult, 1,
+ 1);
}
TEST_F(SodaInstallerImplChromeOSTest, IsDownloading) {
diff --git a/chromium/components/spellcheck/browser/spell_check_host_impl.cc b/chromium/components/spellcheck/browser/spell_check_host_impl.cc
index 581a48a5c76..7f36baf78c7 100644
--- a/chromium/components/spellcheck/browser/spell_check_host_impl.cc
+++ b/chromium/components/spellcheck/browser/spell_check_host_impl.cc
@@ -32,8 +32,10 @@ void SpellCheckHostImpl::CallSpellingService(
CallSpellingServiceCallback callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
- if (text.empty())
+ if (text.empty()) {
mojo::ReportBadMessage("Requested spelling service with empty text");
+ return;
+ }
// This API requires Chrome-only features.
std::move(callback).Run(false, std::vector<SpellCheckResult>());
@@ -46,8 +48,10 @@ void SpellCheckHostImpl::RequestTextCheck(const std::u16string& text,
RequestTextCheckCallback callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
- if (text.empty())
+ if (text.empty()) {
mojo::ReportBadMessage("Requested text check with empty text");
+ return;
+ }
session_bridge_.RequestTextCheck(text, std::move(callback));
}
@@ -68,7 +72,7 @@ void SpellCheckHostImpl::FillSuggestionList(
std::move(callback).Run({});
}
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
void SpellCheckHostImpl::InitializeDictionaries(
InitializeDictionariesCallback callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
@@ -76,11 +80,11 @@ void SpellCheckHostImpl::InitializeDictionaries(
std::move(callback).Run(/*dictionaries=*/{}, /*custom_words=*/{},
/*enable=*/false);
}
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
#endif // BUILDFLAG(USE_BROWSER_SPELLCHECKER) &&
// !BUILDFLAG(ENABLE_SPELLING_SERVICE)
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
void SpellCheckHostImpl::DisconnectSessionBridge() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
session_bridge_.DisconnectSession();
diff --git a/chromium/components/spellcheck/browser/spell_check_host_impl.h b/chromium/components/spellcheck/browser/spell_check_host_impl.h
index 39bbc6cefaa..fde1c92c539 100644
--- a/chromium/components/spellcheck/browser/spell_check_host_impl.h
+++ b/chromium/components/spellcheck/browser/spell_check_host_impl.h
@@ -10,7 +10,7 @@
#include "components/spellcheck/spellcheck_buildflags.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "components/spellcheck/browser/spellchecker_session_bridge_android.h"
#endif
@@ -54,19 +54,19 @@ class SpellCheckHostImpl : public spellcheck::mojom::SpellCheckHost {
void FillSuggestionList(const std::u16string& word,
FillSuggestionListCallback callback) override;
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
void InitializeDictionaries(InitializeDictionariesCallback callback) override;
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
#endif // BUILDFLAG(USE_BROWSER_SPELLCHECKER) &&
// !BUILDFLAG(ENABLE_SPELLING_SERVICE)
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// spellcheck::mojom::SpellCheckHost:
void DisconnectSessionBridge() override;
#endif
private:
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Android-specific object used to query the Android spellchecker.
SpellCheckerSessionBridge session_bridge_;
#endif
diff --git a/chromium/components/spellcheck/browser/spellcheck_host_metrics.cc b/chromium/components/spellcheck/browser/spellcheck_host_metrics.cc
index 0ba28ca467b..ea78f3e2172 100644
--- a/chromium/components/spellcheck/browser/spellcheck_host_metrics.cc
+++ b/chromium/components/spellcheck/browser/spellcheck_host_metrics.cc
@@ -148,7 +148,7 @@ void SpellCheckHostMetrics::RecordSpellingServiceStats(bool enabled) {
base::UmaHistogramBoolean("SpellCheck.SpellingService.Enabled", enabled);
}
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
void SpellCheckHostMetrics::RecordAcceptLanguageStats(
const LocalesSupportInfo& locales_info) {
base::UmaHistogramExactLinear(
@@ -187,4 +187,4 @@ void SpellCheckHostMetrics::RecordSpellcheckLanguageStats(
base::saturated_cast<int>(locales_info.locales_supported_by_native_only),
20);
}
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
diff --git a/chromium/components/spellcheck/browser/spellcheck_host_metrics.h b/chromium/components/spellcheck/browser/spellcheck_host_metrics.h
index 3adf80fd5d5..392f9693ab7 100644
--- a/chromium/components/spellcheck/browser/spellcheck_host_metrics.h
+++ b/chromium/components/spellcheck/browser/spellcheck_host_metrics.h
@@ -14,7 +14,7 @@
#include "base/timer/timer.h"
#include "build/build_config.h"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// Simple struct to keep track of how many languages are supported by which
// spell checker.
struct LocalesSupportInfo {
@@ -23,7 +23,7 @@ struct LocalesSupportInfo {
size_t locales_supported_by_native_only;
size_t unsupported_locales;
};
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
// A helper object for recording spell-check related histograms.
// This class encapsulates histogram names and metrics API.
@@ -71,7 +71,7 @@ class SpellCheckHostMetrics {
// Records if spelling service is enabled or disabled.
void RecordSpellingServiceStats(bool enabled);
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// Records spell check support for user-added Chrome languages that are not
// eligible for spell checking (due to the hard-coded spell check locales
// list).
@@ -79,7 +79,7 @@ class SpellCheckHostMetrics {
// Records which spell checker can handle which enabled spell check locales.
void RecordSpellcheckLanguageStats(const LocalesSupportInfo& locales_info);
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
private:
friend class SpellcheckHostMetricsTest;
diff --git a/chromium/components/spellcheck/browser/spellcheck_host_metrics_unittest.cc b/chromium/components/spellcheck/browser/spellcheck_host_metrics_unittest.cc
index fea2af9e1bf..2a9fb53e4be 100644
--- a/chromium/components/spellcheck/browser/spellcheck_host_metrics_unittest.cc
+++ b/chromium/components/spellcheck/browser/spellcheck_host_metrics_unittest.cc
@@ -50,7 +50,7 @@ TEST_F(SpellcheckHostMetricsTest, RecordEnabledStats) {
histogram_tester2.ExpectBucketCount(kMetricName, 1, 1);
}
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// Failing consistently on Win7. See crbug.com/230534.
#define MAYBE_CustomWordStats DISABLED_CustomWordStats
#else
@@ -105,7 +105,7 @@ TEST_F(SpellcheckHostMetricsTest, RecordSpellingServiceStats) {
histogram_tester2.ExpectBucketCount(kMetricName, 1, 1);
}
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
TEST_F(SpellcheckHostMetricsTest, RecordAcceptLanguageStats) {
const char* const histogram_names[] = {
"Spellcheck.Windows.ChromeLocalesSupport.Both",
@@ -143,4 +143,4 @@ TEST_F(SpellcheckHostMetricsTest, RecordSpellcheckLanguageStats) {
static_cast<int>(expected_counts[i]), 1);
}
}
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
diff --git a/chromium/components/spellcheck/browser/spellcheck_platform.h b/chromium/components/spellcheck/browser/spellcheck_platform.h
index c4b1f1cdd22..aa965e2083b 100644
--- a/chromium/components/spellcheck/browser/spellcheck_platform.h
+++ b/chromium/components/spellcheck/browser/spellcheck_platform.h
@@ -16,13 +16,13 @@
#include "build/build_config.h"
#include "components/spellcheck/spellcheck_buildflags.h"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include "components/spellcheck/browser/spellcheck_host_metrics.h"
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
-#if defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+#if BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
#include "components/spellcheck/common/spellcheck_common.h"
-#endif // defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+#endif // BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
class PlatformSpellChecker;
@@ -33,10 +33,10 @@ namespace spellcheck_platform {
typedef base::OnceCallback<void(const std::vector<SpellCheckResult>&)>
TextCheckCompleteCallback;
-#if defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+#if BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
typedef base::OnceCallback<void(const spellcheck::PerLanguageSuggestions&)>
GetSuggestionsCallback;
-#endif // defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+#endif // BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
typedef base::OnceCallback<void(const std::vector<std::string>& /* results */)>
RetrieveSpellcheckLanguagesCompleteCallback;
@@ -135,14 +135,14 @@ void RequestTextCheck(PlatformSpellChecker* spell_checker_instance,
const std::u16string& text,
TextCheckCompleteCallback callback);
-#if defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+#if BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
// Finds the replacement suggestions for each language for the given word.
void GetPerLanguageSuggestions(PlatformSpellChecker* spell_checker_instance,
const std::u16string& word,
GetSuggestionsCallback callback);
-#endif // defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+#endif // BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// Records statistics about spell check support for the user's Chrome locales.
void RecordChromeLocalesStats(PlatformSpellChecker* spell_checker_instance,
const std::vector<std::string> chrome_locales,
@@ -154,7 +154,7 @@ void RecordSpellcheckLocalesStats(
PlatformSpellChecker* spell_checker_instance,
const std::vector<std::string> spellcheck_locales,
SpellCheckHostMetrics* metrics);
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
// Internal state, to restore system state after testing.
// Not public since it contains Cocoa data types.
diff --git a/chromium/components/spellcheck/browser/spellcheck_platform_win.cc b/chromium/components/spellcheck/browser/spellcheck_platform_win.cc
index fe839caa0ca..a8656471c36 100644
--- a/chromium/components/spellcheck/browser/spellcheck_platform_win.cc
+++ b/chromium/components/spellcheck/browser/spellcheck_platform_win.cc
@@ -7,7 +7,6 @@
#include <string>
#include "base/callback.h"
-#include "base/no_destructor.h"
#include "base/task/post_task.h"
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
@@ -61,14 +60,14 @@ void RequestTextCheck(PlatformSpellChecker* spell_checker_instance,
->RequestTextCheck(document_tag, text, std::move(callback));
}
-#if defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+#if BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
void GetPerLanguageSuggestions(PlatformSpellChecker* spell_checker_instance,
const std::u16string& word,
GetSuggestionsCallback callback) {
static_cast<WindowsSpellChecker*>(spell_checker_instance)
->GetPerLanguageSuggestions(word, std::move(callback));
}
-#endif // defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+#endif // BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
void AddWord(PlatformSpellChecker* spell_checker_instance,
const std::u16string& word) {
diff --git a/chromium/components/spellcheck/browser/spelling_service_client.cc b/chromium/components/spellcheck/browser/spelling_service_client.cc
index 27f76ccd51b..6877a46522e 100644
--- a/chromium/components/spellcheck/browser/spelling_service_client.cc
+++ b/chromium/components/spellcheck/browser/spelling_service_client.cc
@@ -74,7 +74,7 @@ bool SpellingServiceClient::RequestTextCheck(
const base::Value* dicts_list =
pref->GetList(spellcheck::prefs::kSpellCheckDictionaries);
DCHECK(dicts_list->is_list());
- base::Value::ConstListView dicts_lists_view = dicts_list->GetList();
+ base::Value::ConstListView dicts_lists_view = dicts_list->GetListDeprecated();
if (0u < dicts_lists_view.size() && dicts_lists_view[0].is_string())
dictionary = dicts_lists_view[0].GetString();
@@ -183,7 +183,7 @@ bool SpellingServiceClient::IsAvailable(content::BrowserContext* context,
const base::Value* dicts_list =
pref->GetList(spellcheck::prefs::kSpellCheckDictionaries);
DCHECK(dicts_list->is_list());
- base::Value::ConstListView dicts_lists_view = dicts_list->GetList();
+ base::Value::ConstListView dicts_lists_view = dicts_list->GetListDeprecated();
if (0u < dicts_lists_view.size() && dicts_lists_view[0].is_string())
locale = dicts_lists_view[0].GetString();
@@ -252,57 +252,48 @@ bool SpellingServiceClient::ParseResponse(
// }
// }
- std::unique_ptr<base::DictionaryValue> value(
- static_cast<base::DictionaryValue*>(
- base::JSONReader::ReadDeprecated(data,
- base::JSON_ALLOW_TRAILING_COMMAS)
- .release()));
+ absl::optional<base::Value> value(
+ base::JSONReader::Read(data, base::JSON_ALLOW_TRAILING_COMMAS));
if (!value || !value->is_dict())
return false;
// Check for errors from spelling service.
- base::DictionaryValue* error = nullptr;
- if (value->GetDictionary(kErrorPath, &error))
+ const base::Value* error = value->FindDictPath(kErrorPath);
+ if (error)
return false;
// Retrieve the array of Misspelling objects. When the input text does not
// have misspelled words, it returns an empty JSON. (In this case, its HTTP
// status is 200.) We just return true for this case.
- base::ListValue* misspellings = nullptr;
+ const base::Value* misspellings = value->FindListPath(kMisspellingsRestPath);
- if (!value->GetList(kMisspellingsRestPath, &misspellings))
+ if (!misspellings)
return true;
- for (const base::Value& misspelling_value : misspellings->GetList()) {
+ for (const base::Value& misspelling : misspellings->GetListDeprecated()) {
// Retrieve the i-th misspelling region and put it to the given vector. When
// the Spelling service sends two or more suggestions, we read only the
// first one because SpellCheckResult can store only one suggestion.
- if (!misspelling_value.is_dict())
+ if (!misspelling.is_dict())
return false;
- const base::DictionaryValue& misspelling =
- base::Value::AsDictionaryValue(misspelling_value);
-
- int start = 0;
- int length = 0;
- const base::ListValue* suggestions = nullptr;
- if (!misspelling.GetInteger("charStart", &start) ||
- !misspelling.GetInteger("charLength", &length) ||
- !misspelling.GetList("suggestions", &suggestions)) {
+ absl::optional<int> start = misspelling.FindIntKey("charStart");
+ absl::optional<int> length = misspelling.FindIntKey("charLength");
+ const base::Value* suggestions = misspelling.FindListKey("suggestions");
+ if (!start || !length || !suggestions) {
return false;
}
- const base::Value& suggestion_value = suggestions->GetList()[0];
- const base::DictionaryValue* suggestion = nullptr;
- if (suggestion_value.is_dict())
- suggestion = &base::Value::AsDictionaryValue(suggestion_value);
+ const base::Value& suggestion = suggestions->GetListDeprecated()[0];
+ if (!suggestion.is_dict())
+ return false;
- std::u16string replacement;
- if (!suggestion || !suggestion->GetString("suggestion", &replacement)) {
+ const std::string* replacement = suggestion.FindStringKey("suggestion");
+ if (!replacement) {
return false;
}
- SpellCheckResult result(SpellCheckResult::SPELLING, start, length,
- replacement);
+ SpellCheckResult result(SpellCheckResult::SPELLING, *start, *length,
+ base::UTF8ToUTF16(*replacement));
results->push_back(result);
}
return true;
diff --git a/chromium/components/spellcheck/common/spellcheck_features.cc b/chromium/components/spellcheck/common/spellcheck_features.cc
index 3c0b009abba..df76bd328e0 100644
--- a/chromium/components/spellcheck/common/spellcheck_features.cc
+++ b/chromium/components/spellcheck/common/spellcheck_features.cc
@@ -16,7 +16,7 @@ namespace spellcheck {
bool UseBrowserSpellChecker() {
#if !BUILDFLAG(USE_BROWSER_SPELLCHECKER)
return false;
-#elif defined(OS_WIN)
+#elif BUILDFLAG(IS_WIN)
return base::FeatureList::IsEnabled(spellcheck::kWinUseBrowserSpellChecker) &&
WindowsVersionSupportsSpellchecker();
#else
@@ -24,7 +24,7 @@ bool UseBrowserSpellChecker() {
#endif
}
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
const base::Feature kWinUseBrowserSpellChecker{
"WinUseBrowserSpellChecker", base::FEATURE_ENABLED_BY_DEFAULT};
@@ -38,13 +38,13 @@ bool WindowsVersionSupportsSpellchecker() {
return base::win::GetVersion() > base::win::Version::WIN7 &&
base::win::GetVersion() < base::win::Version::WIN_LAST;
}
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
bool IsAndroidSpellCheckFeatureEnabled() {
return !base::SysInfo::IsLowEndDevice();
}
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
#endif // BUILDFLAG(ENABLE_SPELLCHECK)
diff --git a/chromium/components/spellcheck/common/spellcheck_features.h b/chromium/components/spellcheck/common/spellcheck_features.h
index 2b52fe18cf2..774522884ee 100644
--- a/chromium/components/spellcheck/common/spellcheck_features.h
+++ b/chromium/components/spellcheck/common/spellcheck_features.h
@@ -15,7 +15,7 @@ namespace spellcheck {
bool UseBrowserSpellChecker();
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
extern const base::Feature kWinUseBrowserSpellChecker;
// If the kWinDelaySpellcheckServiceInit feature flag is enabled, don't
@@ -45,11 +45,11 @@ extern const base::Feature kWinDelaySpellcheckServiceInit;
extern const base::Feature kWinRetrieveSuggestionsOnlyOnDemand;
bool WindowsVersionSupportsSpellchecker();
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
bool IsAndroidSpellCheckFeatureEnabled();
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
#endif // BUILDFLAG(ENABLE_SPELLCHECK)
diff --git a/chromium/components/spellcheck/renderer/spellcheck.cc b/chromium/components/spellcheck/renderer/spellcheck.cc
index e5721c97c3d..54c7d9e652b 100644
--- a/chromium/components/spellcheck/renderer/spellcheck.cc
+++ b/chromium/components/spellcheck/renderer/spellcheck.cc
@@ -300,7 +300,7 @@ bool SpellCheck::SpellCheckWord(
suggestions_list.clear();
for (auto language = languages_.begin(); language != languages_.end();) {
-#if defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+#if BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
if (!(*language)->IsEnabled()) {
// In the case of hybrid spell checking on Windows, languages that are
// handled on the browser side are marked as disabled on the renderer
@@ -309,7 +309,7 @@ bool SpellCheck::SpellCheckWord(
language++;
continue;
}
-#endif // defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+#endif // BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
language_suggestions.clear();
SpellcheckLanguage::SpellcheckWordResult result =
@@ -366,7 +366,7 @@ bool SpellCheck::SpellCheckWord(
return false;
}
-#if defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+#if BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
// If we're performing a hybrid spell check, we're only interested in
// knowing whether some Hunspell languages considered this text range as
// correctly spelled. If no misspellings were found, but the entire text was
@@ -377,7 +377,7 @@ bool SpellCheck::SpellCheckWord(
agreed_skippable_len == text_length) {
return false;
}
-#endif // defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+#endif // BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
}
NOTREACHED();
@@ -473,11 +473,11 @@ void SpellCheck::PerformSpellCheck(SpellcheckRequest* param) {
WebVector<blink::WebTextCheckingResult> results;
SpellCheckParagraph(param->text(), &results);
param->completion()->DidFinishCheckingText(results);
-#if defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+#if BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
spellcheck_renderer_metrics::RecordSpellcheckDuration(
base::TimeTicks::Now() - param->start_ticks(),
/*used_hunspell=*/true, /*used_native=*/false);
-#endif // defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+#endif // BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
}
}
#endif
@@ -504,14 +504,14 @@ void SpellCheck::CreateTextCheckingResults(
spellcheck_result.replacements;
SpellCheckResult::Decoration decoration = spellcheck_result.decoration;
-#if defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+#if BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
// Ignore words that are in a script not supported by any of the enabled
// spellcheck languages.
if (spellcheck::UseBrowserSpellChecker() &&
!IsWordInSupportedScript(misspelled_word)) {
continue;
}
-#endif // defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+#endif // BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
// Ignore words in custom dictionary.
if (custom_dictionary_.SpellCheckWord(misspelled_word, 0,
@@ -542,7 +542,7 @@ void SpellCheck::CreateTextCheckingResults(
decoration = SpellCheckResult::GRAMMAR;
}
}
-#if defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+#if BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
else if (filter == USE_HUNSPELL_FOR_HYBRID_CHECK &&
spellcheck::UseBrowserSpellChecker() &&
EnabledLanguageCount() > 0) {
@@ -574,7 +574,7 @@ void SpellCheck::CreateTextCheckingResults(
}
}
}
-#endif // defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+#endif // BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
results.push_back(
WebTextCheckingResult(static_cast<WebTextDecorationType>(decoration),
@@ -586,7 +586,7 @@ void SpellCheck::CreateTextCheckingResults(
}
bool SpellCheck::IsSpellcheckEnabled() {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
if (!spellcheck::IsAndroidSpellCheckFeatureEnabled()) return false;
#endif
return spellcheck_enabled_;
diff --git a/chromium/components/spellcheck/renderer/spellcheck_provider.cc b/chromium/components/spellcheck/renderer/spellcheck_provider.cc
index 81f932be7ef..2e6b48af364 100644
--- a/chromium/components/spellcheck/renderer/spellcheck_provider.cc
+++ b/chromium/components/spellcheck/renderer/spellcheck_provider.cc
@@ -136,7 +136,7 @@ void SpellCheckProvider::RequestTextChecking(
#if BUILDFLAG(USE_BROWSER_SPELLCHECKER)
if (spellcheck::UseBrowserSpellChecker()) {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
if (base::FeatureList::IsEnabled(
spellcheck::kWinDelaySpellcheckServiceInit) &&
!dictionaries_loaded_) {
@@ -155,7 +155,7 @@ void SpellCheckProvider::RequestTextChecking(
weak_factory_.GetWeakPtr(), text));
return;
}
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
RequestTextCheckingFromBrowser(text);
}
@@ -175,7 +175,7 @@ void SpellCheckProvider::RequestTextChecking(
void SpellCheckProvider::RequestTextCheckingFromBrowser(
const std::u16string& text) {
DCHECK(spellcheck::UseBrowserSpellChecker());
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// Determine whether a hybrid check is needed.
bool use_hunspell = spellcheck_->EnabledLanguageCount() > 0;
@@ -205,7 +205,7 @@ void SpellCheckProvider::RequestTextCheckingFromBrowser(
hybrid_requests_info_[last_identifier_] = {/*used_hunspell=*/use_hunspell,
/*used_native=*/use_native,
base::TimeTicks::Now()};
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
// Text check (unified request for grammar and spell check) is only
// available for browser process, so we ask the system spellchecker
@@ -216,7 +216,7 @@ void SpellCheckProvider::RequestTextCheckingFromBrowser(
weak_factory_.GetWeakPtr(), last_identifier_, text));
}
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
void SpellCheckProvider::OnRespondInitializeDictionaries(
const std::u16string& text,
std::vector<spellcheck::mojom::SpellCheckBDictLanguagePtr> dictionaries,
@@ -235,12 +235,12 @@ void SpellCheckProvider::OnRespondInitializeDictionaries(
RequestTextCheckingFromBrowser(text);
}
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
#endif // BUILDFLAG(USE_BROWSER_SPELLCHECKER)
void SpellCheckProvider::FocusedElementChanged(
const blink::WebElement& unused) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
if (!spell_check_host_.is_bound())
return;
@@ -251,7 +251,7 @@ void SpellCheckProvider::FocusedElementChanged(
bool enabled = !element.IsNull() && element.IsEditable();
if (!enabled)
GetSpellCheckHost().DisconnectSessionBridge();
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
}
bool SpellCheckProvider::IsSpellCheckingEnabled() const {
@@ -267,9 +267,9 @@ void SpellCheckProvider::CheckSpelling(
const int kWordStart = 0;
if (optional_suggestions) {
-#if defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+#if BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
base::TimeTicks suggestions_start = base::TimeTicks::Now();
-#endif // defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+#endif // BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
// Retrieve suggestions from Hunspell. Windows platform spellchecker
// suggestions are retrieved in SpellingMenuObserver::InitMenu on the
// browser process side to avoid a blocking IPC.
@@ -278,10 +278,10 @@ void SpellCheckProvider::CheckSpelling(
routing_id(), &offset, &length,
&per_language_suggestions);
-#if defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+#if BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
spellcheck_renderer_metrics::RecordHunspellSuggestionDuration(
base::TimeTicks::Now() - suggestions_start);
-#endif // defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+#endif // BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
std::vector<std::u16string> suggestions;
spellcheck::FillSuggestions(per_language_suggestions, &suggestions);
@@ -374,7 +374,7 @@ void SpellCheckProvider::OnRespondTextCheck(
SpellCheck::ResultFilter result_filter = SpellCheck::DO_NOT_MODIFY;
-#if defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+#if BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
const auto& request_info = hybrid_requests_info_.find(identifier);
if (spellcheck::UseBrowserSpellChecker() &&
request_info != hybrid_requests_info_.end() &&
@@ -383,20 +383,20 @@ void SpellCheckProvider::OnRespondTextCheck(
// mistake against Hunspell in the locales that weren't checked.
result_filter = SpellCheck::USE_HUNSPELL_FOR_HYBRID_CHECK;
}
-#endif // defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+#endif // BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
spellcheck_->CreateTextCheckingResults(result_filter,
/*line_offset=*/0, line, results,
&textcheck_results);
-#if defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+#if BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
if (request_info != hybrid_requests_info_.end()) {
spellcheck_renderer_metrics::RecordSpellcheckDuration(
base::TimeTicks::Now() - request_info->second.request_start_ticks,
request_info->second.used_hunspell, request_info->second.used_native);
hybrid_requests_info_.erase(request_info);
}
-#endif // defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+#endif // BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
completion->DidFinishCheckingText(textcheck_results);
diff --git a/chromium/components/spellcheck/renderer/spellcheck_provider.h b/chromium/components/spellcheck/renderer/spellcheck_provider.h
index cfdf56fb211..44620effc84 100644
--- a/chromium/components/spellcheck/renderer/spellcheck_provider.h
+++ b/chromium/components/spellcheck/renderer/spellcheck_provider.h
@@ -17,9 +17,9 @@
#include "mojo/public/cpp/bindings/remote.h"
#include "third_party/blink/public/web/web_text_check_client.h"
-#if defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+#if BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
#include <unordered_map>
-#endif // defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+#endif // BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
class SpellCheck;
struct SpellCheckResult;
@@ -45,14 +45,14 @@ class SpellCheckProvider : public content::RenderFrameObserver,
using WebTextCheckCompletions =
base::IDMap<std::unique_ptr<blink::WebTextCheckingCompletion>>;
-#if defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+#if BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
// A struct to hold information related to hybrid spell check requests.
struct HybridSpellCheckRequestInfo {
bool used_hunspell;
bool used_native;
base::TimeTicks request_start_ticks;
};
-#endif // defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+#endif // BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
SpellCheckProvider(
content::RenderFrame* render_frame,
@@ -138,7 +138,7 @@ class SpellCheckProvider : public content::RenderFrameObserver,
// Makes mojo calls to the browser process to perform platform spellchecking.
void RequestTextCheckingFromBrowser(const std::u16string& text);
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// Callback for when spellcheck service has been initialized on demand.
void OnRespondInitializeDictionaries(
const std::u16string& text,
@@ -150,7 +150,7 @@ class SpellCheckProvider : public content::RenderFrameObserver,
// the dictionaries have been loaded initially. Used to avoid an unnecessary
// mojo call to determine this in every text check request.
bool dictionaries_loaded_ = false;
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
#endif // BUILDFLAG(USE_BROWSER_SPELLCHECKER)
// Holds ongoing spellchecking operations.
@@ -174,9 +174,9 @@ class SpellCheckProvider : public content::RenderFrameObserver,
// Dictionary updated observer.
std::unique_ptr<DictionaryUpdateObserverImpl> dictionary_update_observer_;
-#if defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+#if BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
std::unordered_map<int, HybridSpellCheckRequestInfo> hybrid_requests_info_;
-#endif // defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+#endif // BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
base::WeakPtrFactory<SpellCheckProvider> weak_factory_{this};
};
diff --git a/chromium/components/spellcheck/renderer/spellcheck_provider_hunspell_unittest.cc b/chromium/components/spellcheck/renderer/spellcheck_provider_hunspell_unittest.cc
index 7973230df53..07c2e0420f2 100644
--- a/chromium/components/spellcheck/renderer/spellcheck_provider_hunspell_unittest.cc
+++ b/chromium/components/spellcheck/renderer/spellcheck_provider_hunspell_unittest.cc
@@ -20,11 +20,11 @@ void CheckSpellingServiceCallCount(size_t actual, size_t expected) {
// On Windows, if the native spell checker integration is enabled,
// CallSpellingService() is not used, so the call count will always be 0.
// Don't assert the call count in that case.
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
if (base::FeatureList::IsEnabled(spellcheck::kWinUseBrowserSpellChecker)) {
return;
}
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
EXPECT_EQ(actual, expected);
}
@@ -33,11 +33,11 @@ void CheckProviderText(std::u16string expected, std::u16string actual) {
// On Windows, if the native spell checker integration is enabled,
// CallSpellingService() is not used, so the fake provider's |text_| is never
// assigned. Don't assert the text in that case.
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
if (base::FeatureList::IsEnabled(spellcheck::kWinUseBrowserSpellChecker)) {
return;
}
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
EXPECT_EQ(actual, expected);
}
diff --git a/chromium/components/spellcheck/renderer/spellcheck_provider_test.cc b/chromium/components/spellcheck/renderer/spellcheck_provider_test.cc
index e406f0989c2..dde9ed90636 100644
--- a/chromium/components/spellcheck/renderer/spellcheck_provider_test.cc
+++ b/chromium/components/spellcheck/renderer/spellcheck_provider_test.cc
@@ -17,7 +17,7 @@
#include "components/spellcheck/renderer/spellcheck_language.h"
#include "components/spellcheck/spellcheck_buildflags.h"
-#if defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+#if BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/path_service.h"
@@ -33,7 +33,7 @@ base::FilePath GetHunspellDirectory() {
return hunspell_directory;
}
} // namespace
-#endif // defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+#endif // BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
FakeTextCheckingResult::FakeTextCheckingResult() = default;
FakeTextCheckingResult::~FakeTextCheckingResult() = default;
@@ -66,7 +66,7 @@ void FakeSpellCheck::SetFakeLanguageCounts(size_t language_count,
enabled_language_count_ = enabled_count;
}
-#if defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+#if BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
void FakeSpellCheck::InitializeSpellCheckForLocale(const std::string& language,
bool use_hunspell) {
// Non-Hunspell case is passed invalid file to SpellcheckLanguage::Init.
@@ -90,7 +90,7 @@ void FakeSpellCheck::InitializeSpellCheckForLocale(const std::string& language,
std::make_unique<HunspellEngine>(embedder_provider_);
SpellCheck::languages_.back()->Init(std::move(file), language);
}
-#endif // defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+#endif // BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
size_t FakeSpellCheck::LanguageCount() {
return use_fake_counts_ ? language_count_ : SpellCheck::LanguageCount();
@@ -185,7 +185,7 @@ void TestingSpellCheckProvider::FillSuggestionList(const std::u16string&,
NOTREACHED();
}
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
void TestingSpellCheckProvider::InitializeDictionaries(
InitializeDictionariesCallback callback) {
if (base::FeatureList::IsEnabled(
@@ -197,10 +197,10 @@ void TestingSpellCheckProvider::InitializeDictionaries(
NOTREACHED();
}
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
#endif // BUILDFLAG(USE_BROWSER_SPELLCHECKER)
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
void TestingSpellCheckProvider::DisconnectSessionBridge() {
NOTREACHED();
}
@@ -219,7 +219,7 @@ bool TestingSpellCheckProvider::SatisfyRequestFromCache(
return SpellCheckProvider::SatisfyRequestFromCache(text, completion);
}
-#if defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+#if BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
int TestingSpellCheckProvider::AddCompletionForTest(
std::unique_ptr<FakeTextCheckingCompletion> completion,
SpellCheckProvider::HybridSpellCheckRequestInfo request_info) {
@@ -236,7 +236,7 @@ void TestingSpellCheckProvider::OnRespondTextCheck(
SpellCheckProvider::OnRespondTextCheck(identifier, line, results);
base::RunLoop().RunUntilIdle();
}
-#endif // defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+#endif // BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
SpellCheckProviderTest::SpellCheckProviderTest()
: provider_(&embedder_provider_) {}
diff --git a/chromium/components/spellcheck/renderer/spellcheck_provider_test.h b/chromium/components/spellcheck/renderer/spellcheck_provider_test.h
index 493cbd18ded..4e7208f2bc5 100644
--- a/chromium/components/spellcheck/renderer/spellcheck_provider_test.h
+++ b/chromium/components/spellcheck/renderer/spellcheck_provider_test.h
@@ -53,11 +53,11 @@ class FakeSpellCheck : public SpellCheck {
// Test-only method to set the fake language counts
void SetFakeLanguageCounts(size_t language_count, size_t enabled_count);
-#if defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+#if BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
// Test-only method to initialize SpellCheck object for the given locale.
void InitializeSpellCheckForLocale(const std::string& language,
bool use_hunspell);
-#endif // defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+#endif // BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
// Returns the current number of spell check languages.
size_t LanguageCount() override;
@@ -92,7 +92,7 @@ class TestingSpellCheckProvider : public SpellCheckProvider,
bool SatisfyRequestFromCache(const std::u16string& text,
blink::WebTextCheckingCompletion* completion);
-#if defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+#if BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
int AddCompletionForTest(
std::unique_ptr<FakeTextCheckingCompletion> completion,
SpellCheckProvider::HybridSpellCheckRequestInfo request_info);
@@ -100,7 +100,7 @@ class TestingSpellCheckProvider : public SpellCheckProvider,
void OnRespondTextCheck(int identifier,
const std::u16string& line,
const std::vector<SpellCheckResult>& results);
-#endif // defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+#endif // BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
#if BUILDFLAG(USE_RENDERER_SPELLCHECKER)
void ResetResult();
@@ -144,12 +144,12 @@ class TestingSpellCheckProvider : public SpellCheckProvider,
CheckSpellingCallback) override;
void FillSuggestionList(const std::u16string&,
FillSuggestionListCallback) override;
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
void InitializeDictionaries(InitializeDictionariesCallback callback) override;
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
#endif // BUILDFLAG(USE_BROWSER_SPELLCHECKER)
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
void DisconnectSessionBridge() override;
#endif
diff --git a/chromium/components/spellcheck/renderer/spellcheck_provider_unittest.cc b/chromium/components/spellcheck/renderer/spellcheck_provider_unittest.cc
index ff1c38e6238..a65ea4aea78 100644
--- a/chromium/components/spellcheck/renderer/spellcheck_provider_unittest.cc
+++ b/chromium/components/spellcheck/renderer/spellcheck_provider_unittest.cc
@@ -18,7 +18,7 @@
namespace {
-#if defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+#if BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
struct HybridSpellCheckTestCase {
size_t language_count;
size_t enabled_language_count;
@@ -43,7 +43,7 @@ std::ostream& operator<<(std::ostream& out,
<< "\", use_spelling_service=" << test_case.use_spelling_service;
return out;
}
-#endif // defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+#endif // BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
class SpellCheckProviderCacheTest : public SpellCheckProviderTest {
protected:
@@ -57,7 +57,7 @@ class SpellCheckProviderCacheTest : public SpellCheckProviderTest {
}
};
-#if defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+#if BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
// Test fixture for testing hybrid check cases.
class HybridSpellCheckTest
: public testing::TestWithParam<HybridSpellCheckTestCase> {
@@ -109,7 +109,7 @@ class CombineSpellCheckResultsTest
spellcheck::EmptyLocalInterfaceProvider embedder_provider_;
TestingSpellCheckProvider provider_;
};
-#endif // defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+#endif // BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
TEST_F(SpellCheckProviderCacheTest, SubstringWithoutMisspellings) {
FakeTextCheckingResult result;
@@ -159,7 +159,7 @@ TEST_F(SpellCheckProviderCacheTest, ResetCacheOnCustomDictionaryUpdate) {
EXPECT_EQ(result.completion_count_, 0U);
}
-#if defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+#if BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
// Tests that the SpellCheckProvider does not call into the native spell checker
// on Windows when the native spell checker flags are disabled.
TEST_F(SpellCheckProviderTest, ShouldNotUseBrowserSpellCheck) {
@@ -648,6 +648,6 @@ TEST_P(CombineSpellCheckResultsTest, ShouldCorrectlyCombineHybridResults) {
}
}
}
-#endif // defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+#endif // BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
} // namespace
diff --git a/chromium/components/spellcheck/renderer/spellcheck_renderer_metrics.cc b/chromium/components/spellcheck/renderer/spellcheck_renderer_metrics.cc
index 44d29923868..11edd1ab00a 100644
--- a/chromium/components/spellcheck/renderer/spellcheck_renderer_metrics.cc
+++ b/chromium/components/spellcheck/renderer/spellcheck_renderer_metrics.cc
@@ -12,7 +12,7 @@
#include "build/build_config.h"
#include "components/spellcheck/spellcheck_buildflags.h"
-#if defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+#if BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
namespace {
// Records the duration of a spell check request. This variation is for when
@@ -37,7 +37,7 @@ void RecordNativeSpellcheckDuration(base::TimeDelta duration) {
}
} // anonymous namespace
-#endif // defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+#endif // BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
namespace spellcheck_renderer_metrics {
@@ -53,7 +53,7 @@ void RecordCheckedTextLengthWithSuggestions(int length) {
UMA_HISTOGRAM_COUNTS_1M("SpellCheck.api.check.suggestions", length);
}
-#if defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+#if BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
void RecordHunspellSuggestionDuration(base::TimeDelta duration) {
UMA_HISTOGRAM_TIMES(
"Spellcheck.Windows.SuggestionGatheringDuration.HunspellOnly", duration);
@@ -75,7 +75,7 @@ void RecordSpellcheckDuration(base::TimeDelta duration,
RecordNativeSpellcheckDuration(duration);
}
}
-#endif // defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+#endif // BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
} // namespace spellcheck_renderer_metrics
diff --git a/chromium/components/spellcheck/renderer/spellcheck_renderer_metrics.h b/chromium/components/spellcheck/renderer/spellcheck_renderer_metrics.h
index a052bf7ff0b..c2cff412aba 100644
--- a/chromium/components/spellcheck/renderer/spellcheck_renderer_metrics.h
+++ b/chromium/components/spellcheck/renderer/spellcheck_renderer_metrics.h
@@ -25,7 +25,7 @@ void RecordCheckedTextLengthNoSuggestions(int length);
// requested.
void RecordCheckedTextLengthWithSuggestions(int length);
-#if defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+#if BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
// Records the duration of gathering spelling suggestions. This variation is for
// when spell check is performed only by Hunspell.
void RecordHunspellSuggestionDuration(base::TimeDelta duration);
@@ -41,7 +41,7 @@ void RecordHybridSuggestionDuration(base::TimeDelta duration);
void RecordSpellcheckDuration(base::TimeDelta duration,
bool used_hunspell,
bool used_native);
-#endif // defined(OS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
+#endif // BUILDFLAG(IS_WIN) && BUILDFLAG(USE_BROWSER_SPELLCHECKER)
} // namespace spellcheck_renderer_metrics
diff --git a/chromium/components/spellcheck/renderer/spellcheck_unittest.cc b/chromium/components/spellcheck/renderer/spellcheck_unittest.cc
index 387fb378b80..7f5af686913 100644
--- a/chromium/components/spellcheck/renderer/spellcheck_unittest.cc
+++ b/chromium/components/spellcheck/renderer/spellcheck_unittest.cc
@@ -74,7 +74,7 @@ class SpellCheckTest : public testing::Test {
base::File::FLAG_OPEN | base::File::FLAG_READ);
EXPECT_TRUE(file.IsValid()) << hunspell_file_path << " is not valid"
<< file.ErrorToString(file.GetLastFileError());
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
// TODO(groby): Forcing spellcheck to use hunspell, even on OSX.
// Instead, tests should exercise individual spelling engines.
spell_check_->languages_.push_back(
@@ -107,7 +107,7 @@ class SpellCheckTest : public testing::Test {
spellcheck::FillSuggestions(suggestions_list, optional_suggestions);
}
-#if !defined(OS_APPLE)
+#if !BUILDFLAG(IS_APPLE)
protected:
void TestSpellCheckParagraph(const std::u16string& input,
const std::vector<SpellCheckResult>& expected) {
@@ -737,7 +737,7 @@ TEST_F(SpellCheckTest, SpellCheckText) {
L"\x092E\x0947\x0902 \x0914\x0930 \x0909\x092A\x092F\x094B\x0917\x0940 "
L"\x092C\x0928\x093E\x0928\x093E \x0939\x0948."},
{
-#if !defined(OS_WIN)
+#if !BUILDFLAG(IS_WIN)
// Hungarian
"hu-HU",
L"A Google azt a k\x00FCldet\x00E9st v\x00E1llalta mag\x00E1ra, "
@@ -746,8 +746,8 @@ TEST_F(SpellCheckTest, SpellCheckText) {
L"el\x00E9rhet\x0151v\x00E9, "
L"illetve haszn\x00E1lhat\x00F3v\x00E1 tegye."},
{
-#endif // !defined(OS_WIN)
- // Croatian
+#endif // !BUILDFLAG(IS_WIN)
+ // Croatian
"hr-HR",
// L"Googleova " - to be added.
L"je misija organizirati svjetske informacije i u\x010Diniti ih "
@@ -797,30 +797,30 @@ TEST_F(SpellCheckTest, SpellCheckText) {
L"zasob\x00F3w informacji, aby sta\x0142y si\x0119 one powszechnie "
L"dost\x0119pne i u\x017Cyteczne."},
{
-#if !defined(OS_WIN)
+#if !BUILDFLAG(IS_WIN)
// Portuguese (Brazil)
"pt-BR",
L"A miss\x00E3o do "
-#if !defined(OS_APPLE)
+#if !BUILDFLAG(IS_APPLE)
L"Google "
#endif
L"\x00E9 organizar as informa\x00E7\x00F5"
L"es do mundo todo e "
-#if !defined(OS_APPLE)
+#if !BUILDFLAG(IS_APPLE)
L"torn\x00E1-las "
#endif
L"acess\x00EDveis e \x00FAteis em car\x00E1ter universal."},
{
-#endif // !defined(OS_WIN)
- // Portuguese (Portugal)
+#endif // !BUILDFLAG(IS_WIN)
+ // Portuguese (Portugal)
"pt-PT",
L"O "
-#if !defined(OS_APPLE)
+#if !BUILDFLAG(IS_APPLE)
L"Google "
#endif
L"tem por miss\x00E3o organizar a informa\x00E7\x00E3o do "
L"mundo e "
-#if !defined(OS_APPLE)
+#if !BUILDFLAG(IS_APPLE)
L"torn\x00E1-la "
#endif
L"universalmente acess\x00EDvel e \x00FAtil"},
@@ -875,7 +875,7 @@ TEST_F(SpellCheckTest, SpellCheckText) {
L"samlade information och g\x00F6ra den tillg\x00E4nglig f\x00F6r "
L"alla."},
{
-#if !defined(OS_WIN)
+#if !BUILDFLAG(IS_WIN)
// Turkish
"tr-TR",
// L"Google\x2019\x0131n " - to be added.
@@ -883,8 +883,8 @@ TEST_F(SpellCheckTest, SpellCheckText) {
L"organize etmek ve evrensel olarak eri\x015Filebilir ve "
L"kullan\x0131\x015Fl\x0131 k\x0131lmakt\x0131r."},
{
-#endif // !defined(OS_WIN)
- // Ukranian
+#endif // !BUILDFLAG(IS_WIN)
+ // Ukrainian
"uk-UA",
L"\x041c\x0456\x0441\x0456\x044f "
L"\x043a\x043e\x043c\x043f\x0430\x043d\x0456\x0457 Google "
@@ -907,7 +907,7 @@ TEST_F(SpellCheckTest, SpellCheckText) {
L"th\x1EBF gi\x1EDBi va l\x00E0m cho n\x00F3 universal c\x00F3 "
L"th\x1EC3 truy c\x1EADp va h\x1EEFu d\x1EE5ng h\x01A1n."},
{
-#if !defined(OS_WIN)
+#if !BUILDFLAG(IS_WIN)
// Korean
"ko",
L"Google\xC758 \xBAA9\xD45C\xB294 \xC804\xC138\xACC4\xC758 "
@@ -916,8 +916,8 @@ TEST_F(SpellCheckTest, SpellCheckText) {
L"\xD3B8\xB9AC\xD558\xAC8C \xC774\xC6A9\xD560 \xC218 "
L"\xC788\xB3C4\xB85D \xD558\xB294 \xAC83\xC785\xB2C8\xB2E4."},
{
-#endif // !defined(OS_WIN)
- // Albanian
+#endif // !BUILDFLAG(IS_WIN)
+ // Albanian
"sq",
L"Misioni i Google \x00EBsht\x00EB q\x00EB t\x00EB organizoj\x00EB "
L"informacionin e bot\x00EBs dhe t\x00EB b\x00EBjn\x00EB at\x00EB "
@@ -1024,7 +1024,7 @@ TEST_F(SpellCheckTest, MisspelledWords) {
// Since SpellCheck::SpellCheckParagraph is not implemented on Mac,
// we skip these SpellCheckParagraph tests on Mac.
-#if !defined(OS_APPLE)
+#if !BUILDFLAG(IS_APPLE)
// Make sure SpellCheckParagraph does not crash if the input is empty.
TEST_F(SpellCheckTest, SpellCheckParagraphEmptyParagraph) {
diff --git a/chromium/components/spellcheck/renderer/spelling_engine.cc b/chromium/components/spellcheck/renderer/spelling_engine.cc
index 9791b5d97a8..74dcc73455b 100644
--- a/chromium/components/spellcheck/renderer/spelling_engine.cc
+++ b/chromium/components/spellcheck/renderer/spelling_engine.cc
@@ -20,7 +20,7 @@
SpellingEngine* CreateNativeSpellingEngine(
service_manager::LocalInterfaceProvider* embedder_provider) {
DCHECK(embedder_provider);
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// On Windows, always return a HunspellEngine. This is a simplification to
// avoid needing an async Mojo call to the browser process to determine which
// languages are supported by the native spell checker. Returning a
diff --git a/chromium/components/ssl_errors/error_classification.cc b/chromium/components/ssl_errors/error_classification.cc
index a6dcbbeb1e2..b5f217a636d 100644
--- a/chromium/components/ssl_errors/error_classification.cc
+++ b/chromium/components/ssl_errors/error_classification.cc
@@ -25,7 +25,7 @@
#include "net/cert/x509_certificate.h"
#include "url/gurl.h"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include "base/win/win_util.h"
#include "base/win/windows_version.h"
#endif
diff --git a/chromium/components/startup_metric_utils/browser/startup_metric_utils.cc b/chromium/components/startup_metric_utils/browser/startup_metric_utils.cc
index d1e155f87ec..9216c68651a 100644
--- a/chromium/components/startup_metric_utils/browser/startup_metric_utils.cc
+++ b/chromium/components/startup_metric_utils/browser/startup_metric_utils.cc
@@ -28,7 +28,7 @@
#include "components/version_info/version_info.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include <windows.h>
#include <winternl.h>
#include "base/win/win_util.h"
@@ -80,7 +80,7 @@ enum StartupTemperature {
StartupTemperature g_startup_temperature = UNDETERMINED_STARTUP_TEMPERATURE;
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// These values are taken from the Startup.BrowserMessageLoopStartHardFaultCount
// histogram. The latest revision landed on <5 and >3500 for a good split
@@ -203,7 +203,7 @@ absl::optional<uint32_t> GetHardFaultCountForCurrentProcess() {
return absl::nullopt;
}
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
// Helper function for splitting out an UMA histogram based on startup
// temperature. |histogram_function| is the histogram type, and corresponds to
@@ -298,7 +298,7 @@ void UmaHistogramAndTraceWithTemperatureAndMaxPressure(
// current chrome.exe process since it was started. This is a nop on other
// platforms.
void RecordHardFaultHistogram() {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
DCHECK_EQ(UNDETERMINED_STARTUP_TEMPERATURE, g_startup_temperature);
const absl::optional<uint32_t> hard_fault_count =
@@ -329,7 +329,7 @@ void RecordHardFaultHistogram() {
// Record the startup 'temperature'.
base::UmaHistogramEnumeration("Startup.Temperature", g_startup_temperature,
STARTUP_TEMPERATURE_COUNT);
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
}
// Converts a base::Time value to a base::TimeTicks value. The conversion isn't
@@ -347,7 +347,7 @@ base::TimeTicks StartupTimeToTimeTicks(base::Time time) {
// Enabling this logic on OS X causes a significant performance regression.
// https://crbug.com/601270
-#if !defined(OS_APPLE)
+#if !BUILDFLAG(IS_APPLE)
static bool statics_initialized = false;
base::ThreadPriority previous_priority = base::ThreadPriority::NORMAL;
@@ -361,7 +361,7 @@ base::TimeTicks StartupTimeToTimeTicks(base::Time time) {
static const base::Time time_base = base::Time::Now();
static const base::TimeTicks trace_ticks_base = base::TimeTicks::Now();
-#if !defined(OS_APPLE)
+#if !BUILDFLAG(IS_APPLE)
if (!statics_initialized) {
base::PlatformThread::SetCurrentThreadPriority(previous_priority);
}
diff --git a/chromium/components/storage_monitor/image_capture_device.mm b/chromium/components/storage_monitor/image_capture_device.mm
index 58667a6a356..d66dd56afc4 100644
--- a/chromium/components/storage_monitor/image_capture_device.mm
+++ b/chromium/components/storage_monitor/image_capture_device.mm
@@ -5,6 +5,7 @@
#import "components/storage_monitor/image_capture_device.h"
#include "base/bind.h"
+#include "base/containers/adapters.h"
#include "base/files/file_util.h"
#include "base/task/post_task.h"
#include "base/task/task_traits.h"
@@ -44,9 +45,8 @@ base::FilePath PathForCameraItem(ICCameraItem* item) {
folder = [folder parentFolder];
}
base::FilePath path;
- for (std::vector<std::string>::reverse_iterator i = components.rbegin();
- i != components.rend(); ++i) {
- path = path.Append(*i);
+ for (const std::string& component : base::Reversed(components)) {
+ path = path.Append(component);
}
path = path.Append(name);
diff --git a/chromium/components/storage_monitor/media_storage_util.cc b/chromium/components/storage_monitor/media_storage_util.cc
index 1def34a97db..12d1f6cfa84 100644
--- a/chromium/components/storage_monitor/media_storage_util.cc
+++ b/chromium/components/storage_monitor/media_storage_util.cc
@@ -24,7 +24,7 @@ namespace storage_monitor {
namespace {
-#if !defined(OS_WIN)
+#if !BUILDFLAG(IS_WIN)
const char kRootPath[] = "/";
#endif
@@ -142,7 +142,7 @@ bool MediaStorageUtil::GetDeviceInfoFromPath(const base::FilePath& path,
// TODO(gbillock): Delete this stanza? Posix systems should have the root
// volume information. If not, we should move the below into the
// right GetStorageInfoForPath implementations.
-#if !defined(OS_POSIX)
+#if !BUILDFLAG(IS_POSIX)
if (!found_device)
return false;
#endif
@@ -175,7 +175,7 @@ base::FilePath MediaStorageUtil::FindDevicePathById(
// For ImageCapture, the synthetic filesystem will be rooted at a fake
// top-level directory which is the device_id.
if (type == StorageInfo::MAC_IMAGE_CAPTURE) {
-#if !defined(OS_WIN)
+#if !BUILDFLAG(IS_WIN)
return base::FilePath(kRootPath + device_id);
#endif
}
diff --git a/chromium/components/storage_monitor/mtp_manager_client_chromeos.cc b/chromium/components/storage_monitor/mtp_manager_client_chromeos.cc
index bcaad1d10ab..036f88763b9 100644
--- a/chromium/components/storage_monitor/mtp_manager_client_chromeos.cc
+++ b/chromium/components/storage_monitor/mtp_manager_client_chromeos.cc
@@ -34,8 +34,8 @@ bool MtpManagerClientChromeOS::GetStorageInfoForPath(
if (!path.IsAbsolute())
return false;
- std::vector<base::FilePath::StringType> path_components;
- path.GetComponents(&path_components);
+ std::vector<base::FilePath::StringType> path_components =
+ path.GetComponents();
if (path_components.size() < 2)
return false;
diff --git a/chromium/components/storage_monitor/removable_device_constants.cc b/chromium/components/storage_monitor/removable_device_constants.cc
index 8bb46a419c8..6c2297b4199 100644
--- a/chromium/components/storage_monitor/removable_device_constants.cc
+++ b/chromium/components/storage_monitor/removable_device_constants.cc
@@ -10,11 +10,11 @@ namespace storage_monitor {
const char kFSUniqueIdPrefix[] = "UUID:";
const char kVendorModelSerialPrefix[] = "VendorModelSerial:";
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
const char kVendorModelVolumeStoragePrefix[] = "VendorModelVolumeStorage:";
#endif
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
const wchar_t kWPDDevInterfaceGUID[] =
L"{6ac27878-a6fa-4155-ba85-f98f491d4f33}";
#endif
diff --git a/chromium/components/storage_monitor/removable_device_constants.h b/chromium/components/storage_monitor/removable_device_constants.h
index cbbd6a5101d..7bf5203b991 100644
--- a/chromium/components/storage_monitor/removable_device_constants.h
+++ b/chromium/components/storage_monitor/removable_device_constants.h
@@ -14,11 +14,11 @@ namespace storage_monitor {
extern const char kFSUniqueIdPrefix[];
extern const char kVendorModelSerialPrefix[];
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
extern const char kVendorModelVolumeStoragePrefix[];
#endif
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// Windows portable device interface GUID constant.
extern const wchar_t kWPDDevInterfaceGUID[];
#endif
diff --git a/chromium/components/storage_monitor/storage_monitor.h b/chromium/components/storage_monitor/storage_monitor.h
index 2d0f14264fb..5e3e16f758c 100644
--- a/chromium/components/storage_monitor/storage_monitor.h
+++ b/chromium/components/storage_monitor/storage_monitor.h
@@ -108,7 +108,7 @@ class StorageMonitor {
// TODO(gbillock): make this either unnecessary (implementation-specific) or
// platform-independent.
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// Gets the MTP device storage information specified by |storage_device_id|.
// On success, returns true and fills in |device_location| with device
// interface details and |storage_object_id| with the string ID that
diff --git a/chromium/components/storage_monitor/storage_monitor_linux_unittest.cc b/chromium/components/storage_monitor/storage_monitor_linux_unittest.cc
index 819e58bbd20..8d0f2ef5a79 100644
--- a/chromium/components/storage_monitor/storage_monitor_linux_unittest.cc
+++ b/chromium/components/storage_monitor/storage_monitor_linux_unittest.cc
@@ -125,20 +125,20 @@ class TestStorageMonitorLinux : public StorageMonitorLinux {
~TestStorageMonitorLinux() override = default;
+ void SetOnMtabUpdateCallback(base::OnceClosure on_mtab_update_callback) {
+ EXPECT_FALSE(on_mtab_update_callback_);
+ on_mtab_update_callback_ = std::move(on_mtab_update_callback);
+ }
+
private:
void UpdateMtab(
const MtabWatcherLinux::MountPointDeviceMap& new_mtab) override {
StorageMonitorLinux::UpdateMtab(new_mtab);
-
- // The UpdateMtab call performs the actual mounting by posting tasks
- // to the thread pool. This also needs to be flushed.
- base::ThreadPoolInstance::Get()->FlushForTesting();
-
- // Once the storage monitor picks up the changes to the fake mtab file,
- // exit the RunLoop that should be blocking the main test thread.
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::RunLoop::QuitCurrentWhenIdleClosureDeprecated());
+ if (on_mtab_update_callback_)
+ std::move(on_mtab_update_callback_).Run();
}
+
+ base::OnceClosure on_mtab_update_callback_;
};
class StorageMonitorLinuxTest : public testing::Test {
@@ -199,16 +199,14 @@ class StorageMonitorLinuxTest : public testing::Test {
// file, and run the message loop.
void AppendToMtabAndRunLoop(const MtabTestData* data, size_t data_size) {
WriteToMtab(data, data_size, /*overwrite=*/false);
- // Block until the mtab changes are detected by the file watcher.
- base::RunLoop().Run();
+ WaitForMtabUpdate();
}
// Overwrite the mtab file with mtab entries from the |data| array of size
// |data_size|, and run the message loop.
void OverwriteMtabAndRunLoop(const MtabTestData* data, size_t data_size) {
WriteToMtab(data, data_size, /*overwrite=*/true);
- // Block until the mtab changes are detected by the file watcher.
- base::RunLoop().Run();
+ WaitForMtabUpdate();
}
// Simplied version of OverwriteMtabAndRunLoop() that just deletes all the
@@ -254,6 +252,22 @@ class StorageMonitorLinuxTest : public testing::Test {
}
private:
+ // Invoked after making an mtab update. Blocks (in an active RunLoop) until
+ // the mtab changes are detected by the file watcher and side-effects of
+ // UpdateMtab() propagate.
+ void WaitForMtabUpdate() {
+ base::RunLoop run_loop;
+ monitor_->SetOnMtabUpdateCallback(run_loop.QuitClosure());
+ // Wait until the UpdateMtab() notification comes in from the system
+ // (cannot use RunUntilIdle right away as that would racily return early
+ // per being idle until the system notification comes in).
+ run_loop.Run();
+ // UpdateMtab() causes asynchronous work on internal task runners, flush
+ // everything to make sure `mock_storage_observer_` gets to observe the
+ // change.
+ task_environment_.RunUntilIdle();
+ }
+
// Create a directory named |dir| relative to the test directory.
// Set |with_dcim_dir| to true if the created directory will have a "DCIM"
// subdirectory.
@@ -315,8 +329,9 @@ class StorageMonitorLinuxTest : public testing::Test {
std::unique_ptr<TestStorageMonitorLinux> monitor_;
};
+// TODO(https://crbug.com/1297464): This test is flaky.
// Simple test case where we attach and detach a media device.
-TEST_F(StorageMonitorLinuxTest, BasicAttachDetach) {
+TEST_F(StorageMonitorLinuxTest, DISABLED_BasicAttachDetach) {
base::FilePath test_path = CreateMountPointWithDCIMDir(kMountPointA);
ASSERT_FALSE(test_path.empty());
MtabTestData test_data[] = {
@@ -341,7 +356,7 @@ TEST_F(StorageMonitorLinuxTest, BasicAttachDetach) {
// Only removable devices are recognized.
// This test is flaky, see https://crbug.com/1012211
-TEST_F(StorageMonitorLinuxTest, DISABLED_Removable) {
+TEST_F(StorageMonitorLinuxTest, Removable) {
base::FilePath test_path_a = CreateMountPointWithDCIMDir(kMountPointA);
ASSERT_FALSE(test_path_a.empty());
MtabTestData test_data1[] = {
@@ -426,7 +441,7 @@ TEST_F(StorageMonitorLinuxTest, SwapMountPoints) {
}
// More complicated test case with multiple devices on multiple mount points.
-TEST_F(StorageMonitorLinuxTest, DISABLED_MultiDevicesMultiMountPoints) {
+TEST_F(StorageMonitorLinuxTest, MultiDevicesMultiMountPoints) {
base::FilePath test_path_a = CreateMountPointWithDCIMDir(kMountPointA);
base::FilePath test_path_b = CreateMountPointWithDCIMDir(kMountPointB);
ASSERT_FALSE(test_path_a.empty());
@@ -493,8 +508,7 @@ TEST_F(StorageMonitorLinuxTest, DISABLED_MultiDevicesMultiMountPoints) {
EXPECT_EQ(5, observer().detach_calls());
}
-TEST_F(StorageMonitorLinuxTest,
- DISABLED_MultipleMountPointsWithNonDCIMDevices) {
+TEST_F(StorageMonitorLinuxTest, MultipleMountPointsWithNonDCIMDevices) {
base::FilePath test_path_a = CreateMountPointWithDCIMDir(kMountPointA);
base::FilePath test_path_b = CreateMountPointWithDCIMDir(kMountPointB);
ASSERT_FALSE(test_path_a.empty());
@@ -654,7 +668,7 @@ TEST_F(StorageMonitorLinuxTest, DeviceLookUp) {
EXPECT_EQ(1, observer().detach_calls());
}
-TEST_F(StorageMonitorLinuxTest, DISABLED_DevicePartitionSize) {
+TEST_F(StorageMonitorLinuxTest, DevicePartitionSize) {
base::FilePath test_path_a = CreateMountPointWithDCIMDir(kMountPointA);
base::FilePath test_path_b = CreateMountPointWithoutDCIMDir(kMountPointB);
ASSERT_FALSE(test_path_a.empty());
diff --git a/chromium/components/storage_monitor/test_storage_monitor.cc b/chromium/components/storage_monitor/test_storage_monitor.cc
index 07f06fc028b..edae88fc734 100644
--- a/chromium/components/storage_monitor/test_storage_monitor.cc
+++ b/chromium/components/storage_monitor/test_storage_monitor.cc
@@ -106,7 +106,7 @@ bool TestStorageMonitor::GetStorageInfoForPath(
return true;
}
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
bool TestStorageMonitor::GetMTPStorageInfoFromDeviceId(
const std::string& storage_device_id,
std::wstring* device_location,
diff --git a/chromium/components/storage_monitor/test_storage_monitor.h b/chromium/components/storage_monitor/test_storage_monitor.h
index ce80dd617e7..3672554503b 100644
--- a/chromium/components/storage_monitor/test_storage_monitor.h
+++ b/chromium/components/storage_monitor/test_storage_monitor.h
@@ -46,7 +46,7 @@ class TestStorageMonitor : public StorageMonitor {
bool GetStorageInfoForPath(const base::FilePath& path,
StorageInfo* device_info) const override;
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
bool GetMTPStorageInfoFromDeviceId(
const std::string& storage_device_id,
std::wstring* device_location,
diff --git a/chromium/components/storage_monitor/volume_mount_watcher_win.cc b/chromium/components/storage_monitor/volume_mount_watcher_win.cc
index 9eabfb5cceb..e95259d29aa 100644
--- a/chromium/components/storage_monitor/volume_mount_watcher_win.cc
+++ b/chromium/components/storage_monitor/volume_mount_watcher_win.cc
@@ -19,6 +19,7 @@
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/containers/contains.h"
+#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
diff --git a/chromium/components/strings/components_chromium_strings_de.xtb b/chromium/components/strings/components_chromium_strings_de.xtb
index 96265c8ef28..705e1e33fb6 100644
--- a/chromium/components/strings/components_chromium_strings_de.xtb
+++ b/chromium/components/strings/components_chromium_strings_de.xtb
@@ -1,25 +1,25 @@
<?xml version="1.0" ?>
<!DOCTYPE translationbundle>
<translationbundle lang="de">
-<translation id="130631256467250065">Ihre Änderungen werden beim nächsten Neustart wirksam.</translation>
+<translation id="130631256467250065">Deine Änderungen werden beim nächsten Neustart wirksam.</translation>
<translation id="275588974610408078">Absturzberichte sind in Chromium nicht verfügbar.</translation>
<translation id="3064346599913645280">Dies ist eine sichere Chromium-Seite</translation>
<translation id="3550966579244642892">Die Ersteinrichtung von Chromium OS wurde nicht abgeschlossen.</translation>
<translation id="358997566136285270">Chromium-Logo</translation>
<translation id="4365115785552740256">Chromium wird durch das Open-Source-Projekt <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> und andere <ph name="BEGIN_LINK_OSS" />Open-Source-Software<ph name="END_LINK_OSS" /> ermöglicht.</translation>
-<translation id="4559775032954821361">Gehen Sie zum Chromium-Menü &gt; "<ph name="SETTINGS_TITLE" />" &gt; "<ph name="ADVANCED_TITLE" />" &gt; "<ph name="PROXIES_TITLE" />" &gt; "LAN-Einstellungen" und deaktivieren Sie das Kästchen "Proxyserver für LAN verwenden".</translation>
+<translation id="4559775032954821361">Gehe zum Chromium-Menü &gt; „<ph name="SETTINGS_TITLE" />“ &gt; „<ph name="ADVANCED_TITLE" />“ &gt; „<ph name="PROXIES_TITLE" />“ &gt; „LAN-Einstellungen“ und deaktiviere das Kästchen „Proxyserver für LAN verwenden“.</translation>
<translation id="4622039161600275920">Diese Seite wurde von Chromium blockiert</translation>
-<translation id="48558539577516920">Erlauben Sie Chromium in Ihren Firewall- und Virenschutzeinstellungen den Zugriff auf das Netzwerk.</translation>
-<translation id="580822234363523061">Gehen Sie zum Chromium-Menü &gt; "<ph name="SETTINGS_TITLE" />" &gt; "<ph name="ADVANCED_TITLE" />" &gt; "<ph name="PROXIES_TITLE" />" und vergewissern Sie sich, dass in Ihrer Konfiguration die Einstellung "Kein Proxy" oder "Direkt" verwendet wird.</translation>
-<translation id="6613594504749178791">Ihre Änderungen werden beim nächsten Neustart von Chromium wirksam.</translation>
-<translation id="7861509383340276692">Öffnen Sie
+<translation id="48558539577516920">Erlaube Chromium in deinen Firewall- und Virenschutzeinstellungen den Zugriff auf das Netzwerk.</translation>
+<translation id="580822234363523061">Gehe zum Chromium-Menü &gt; „<ph name="SETTINGS_TITLE" />“ &gt; „<ph name="ADVANCED_TITLE" />“ &gt; „<ph name="PROXIES_TITLE" />“ und vergewissere dich, dass in deiner Konfiguration die Einstellung „Kein Proxy“ oder „Direkt“ verwendet wird.</translation>
+<translation id="6613594504749178791">Deine Änderungen werden beim nächsten Neustart von Chromium wirksam.</translation>
+<translation id="7861509383340276692">Öffne
das Chromium-Menü &gt;
<ph name="SETTINGS_TITLE" />
&gt;
<ph name="ADVANCED_TITLE" />
- und deaktivieren Sie "<ph name="NO_PREFETCH_DESCRIPTION" />".
+ und deaktiviere "<ph name="NO_PREFETCH_DESCRIPTION" />".
Falls das Problem nicht dadurch verursacht wurde, empfehlen wir,
diese Option für eine verbesserte Leistung wieder zu aktivieren.</translation>
-<translation id="8187289872471304532">Gehen Sie zu "Programme" &gt; "Systemeinstellungen" &gt; "Netzwerk" &gt; "Erweitert" &gt; "Proxys" und deaktivieren Sie alle ausgewählten Proxyserver.</translation>
+<translation id="8187289872471304532">Gehe zu „Programme“ &gt; „Systemeinstellungen“ &gt; „Netzwerk“ &gt; „Erweitert“ &gt; „Proxys“ und deaktiviere alle ausgewählten Proxyserver.</translation>
<translation id="8684913864886094367">Chromium wurde nicht richtig beendet.</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/strings/components_chromium_strings_hy.xtb b/chromium/components/strings/components_chromium_strings_hy.xtb
index 4d2eff24a18..60d7c463e42 100644
--- a/chromium/components/strings/components_chromium_strings_hy.xtb
+++ b/chromium/components/strings/components_chromium_strings_hy.xtb
@@ -16,7 +16,7 @@
<ph name="PROXIES_TITLE" />
&gt;
LAN Õ¯Õ¡Ö€Õ£Õ¡Õ¾Õ¸Ö€Õ¸Ö‚Õ´Õ¶Õ¥Ö€
- և ապանշեք «Օգտագործել միջնորդ սերվեր LAN-ի համար» նշավանդակը:</translation>
+ և ապանշեք «Օգտագործել պրոքսի սերվեր LAN-ի համար» նշավանդակը:</translation>
<translation id="4622039161600275920">Ô±ÕµÕ½ Õ§Õ»Õ¶ Õ¡Ö€Õ£Õ¥Õ¬Õ¡ÖƒÕ¡Õ¯Õ¾Õ¥Õ¬ Õ§ Chromium-Õ« Õ¯Õ¸Õ²Õ´Õ«Ö</translation>
<translation id="48558539577516920">Õ€Ö€Õ¡ÕºÕ¡Õ¿Õ« Õ¯Õ¡Õ´ Õ°Õ¡Õ¯Õ¡Õ¾Õ«Ö€Õ¸Ö‚Õ½Õ¡ÕµÕ«Õ¶ Õ®Ö€Õ¡Õ£Ö€Õ« Õ¯Õ¡Ö€Õ£Õ¡Õ¾Õ¸Ö€Õ¸Ö‚Õ´Õ¶Õ¥Ö€Õ¸Ö‚Õ´
Õ©Õ¸Ö‚ÕµÕ¬Õ¡Õ¿Ö€Õ¥Ö„ Chromium-Õ«Õ¶ Õ´Õ«Õ¡Õ¶Õ¡Õ¬ ÖÕ¡Õ¶ÖÕ«Õ¶:</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_af.xtb b/chromium/components/strings/components_google_chrome_strings_af.xtb
index e65791de387..2313c287ffa 100644
--- a/chromium/components/strings/components_google_chrome_strings_af.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_af.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">Jou veranderinge sal die volgende keer wanneer jy Chrome herbegin, in werking tree.</translation>
<translation id="2447485272386224171">Chrome word moontlik gemaak deur die <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" />-oopbronprojek en ander <ph name="BEGIN_LINK_OSS" />oopbronsagteware<ph name="END_LINK_OSS" />.</translation>
<translation id="2588322182880276190">Chrome-logo</translation>
+<translation id="290720624583273918">CloudReady 2.0 het nie sy aanvanklike opstelling voltooi nie.</translation>
<translation id="3444832043240812445">Hierdie bladsy wys net inligting oor jou onlangse omvalle as jy <ph name="BEGIN_LINK" />omvalrapportering aktiveer<ph name="END_LINK" />.</translation>
<translation id="3875312571075912821">Laat Chrome in jou brandmuur- of antivirusinstellings toe om by jou netwerk
in te gaan.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_am.xtb b/chromium/components/strings/components_google_chrome_strings_am.xtb
index 508c3c15951..67d6ec3112c 100644
--- a/chromium/components/strings/components_google_chrome_strings_am.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_am.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">ለá‹áŒ¦á‰½á‹Ž Chrome ዳáŒáˆ በሚያስጀáˆáˆ©á‰ á‰µ ቀጣዩ ጊዜ ላይ ይተገበራሉá¢</translation>
<translation id="2447485272386224171">Chrome በ<ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> ክáት áˆáŠ•áŒ­ á•áˆ®áŒ€áŠ­á‰µ እና በሌላ <ph name="BEGIN_LINK_OSS" />ክáት áˆáŠ•áŒ­ ሶáትዌር<ph name="END_LINK_OSS" /> ሊሰራ ችáˆáˆá¢</translation>
<translation id="2588322182880276190">የChrome አርማ</translation>
+<translation id="290720624583273918">CloudReady 2.0 የመጀመሪያ á‹á‰…ረቱን አላጠናቀቀáˆá¢</translation>
<translation id="3444832043240812445">ይህ ገጽ <ph name="BEGIN_LINK" />የብáˆáˆ½á‰µ ሪá–ርት ማድረáŒ<ph name="END_LINK" />ን ካáŠá‰ የቅርብ ጊዜ ብáˆáˆ½á‰¶á‰½á‹ŽáŠ• ብቻ áŠá‹ መረጃ የሚያሳየá‹á¢</translation>
<translation id="3875312571075912821">Chrome በኬላ ወይሠየጸረ-ቫይረስ ቅንብሮችዎን á‹áˆµáŒ¥ አá‹á‰³áˆ¨ መረቡን እንዲደርስበት
á‹­áቀዱለትá¢</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_ar.xtb b/chromium/components/strings/components_google_chrome_strings_ar.xtb
index 07dc5023419..9e4cc31b484 100644
--- a/chromium/components/strings/components_google_chrome_strings_ar.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_ar.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">â€Ø³ØªØ³Ø±ÙŠ التغييرات ÙÙŠ المرة التالية التي تعيد Ùيها تشغيل Chrome.</translation>
<translation id="2447485272386224171">â€Ø£ØµØ¨Ø­ Chrome الآن متاحًا بÙضل المشروع المÙتوح المصدر <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> Ùˆ<ph name="BEGIN_LINK_OSS" />برامج أخرى Ù…Ùتوحة المصدر<ph name="END_LINK_OSS" />.</translation>
<translation id="2588322182880276190">â€Ø´Ø¹Ø§Ø± Chrome</translation>
+<translation id="290720624583273918">â€Ù„Ù… يكتمل الإعداد الأولي لنظام التشغيل CloudReady 2.0.</translation>
<translation id="3444832043240812445">تعرض هذه الصÙحة Ùقط معلومات عن الأعطال الحديثة إذا <ph name="BEGIN_LINK" />Ùعّلت الإبلاغ عن الأعطال<ph name="END_LINK" />.</translation>
<translation id="3875312571075912821">â€Ø§Ø³Ù…Ø­ لمتصÙØ­ Chrome بالدخول إلى الشبكة من خلال إعدادات الجدار الناري أو
برنامج مكاÙحة الÙيروسات.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_as.xtb b/chromium/components/strings/components_google_chrome_strings_as.xtb
index 1adc79d8644..7f933b38164 100644
--- a/chromium/components/strings/components_google_chrome_strings_as.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_as.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">আপà§à¦¨à¦¿ পৰৱৰà§à¦¤à§€ সময়ত Chrome পà§à¦¨à§° লঞà§à¦š কৰিলে আপà§à¦¨à¦¿ কৰা সলনিসমূহ কাৰà§à¦¯à¦•à§°à§€ হ’ব।</translation>
<translation id="2447485272386224171"><ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" />ৰ মà§à¦•à§à¦¤ উৎসৰ পà§à§°â€™à¦œà§‡à¦•à§à¦Ÿ আৰৠঅনà§à¦¯ <ph name="BEGIN_LINK_OSS" />মà§à¦•à§à¦¤ উৎসৰ ছফà§à¦Ÿà§±à§‡à§°<ph name="END_LINK_OSS" />ৰ দà§à¦¬à¦¾à§°à¦¾ Chromeক সহজসাধà§à¦¯ কৰা হৈছে।</translation>
<translation id="2588322182880276190">Chromeৰ ল'গ'</translation>
+<translation id="290720624583273918">CloudReady 2.0ঠনিজৰ পà§à§°à¦¾à§°à¦®à§à¦­à¦¿à¦• ছেটআপ সমà§à¦ªà§‚ৰà§à¦£ কৰা নাই।</translation>
<translation id="3444832043240812445">যদি আপà§à¦¨à¦¿ <ph name="BEGIN_LINK" />কà§à§°à§‡à¦¶à§à¦¬ ৰিপরà§à¦Ÿ কৰা সà§à¦¬à¦¿à¦§à¦¾à¦Ÿà§‹ সকà§à¦·à¦® কৰে<ph name="END_LINK" /> তেনà§à¦¤à§‡ à¦à¦‡ পৃষà§à¦ à¦¾à¦Ÿà§‹à§±à§‡ কেৱল আপোনাৰ শেহতীয়া কà§à§°à§‡à¦¶à§à¦¬à¦¸à¦®à§‚হৰ তথà§à¦¯ দেখà§à§±à¦¾à§Ÿà¥¤</translation>
<translation id="3875312571075912821">আপোনাৰ ফায়াৰৱাল বা à¦à¦£à§à¦Ÿà¦¿à¦­à¦¾à¦‡à§°à¦¾à¦›à§° ছেটিঙত Chromeক নেটৱরà§à¦• à¦à¦•à§à¦¸à§‡à¦› কৰিবলৈ অনà§à¦®à¦¤à¦¿ দিয়ক।</translation>
<translation id="4010643444566880169">Chrome OSঠনিজৰ পà§à§°à¦¾à§°à¦®à§à¦­à¦¿à¦• ছেট আপ সমà§à¦ªà§‚রà§à¦£ কৰা নাই।</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_az.xtb b/chromium/components/strings/components_google_chrome_strings_az.xtb
index 8dd07c8835b..44e73a027c3 100644
--- a/chromium/components/strings/components_google_chrome_strings_az.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_az.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">Dəyişiklikləriniz gələn dəfə Chrome'u başlatdıqda qüvvəyə minəcək.</translation>
<translation id="2447485272386224171">Chrome <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> açıq mənbə layihəsi və digər <ph name="BEGIN_LINK_OSS" />açıq mənbə proqram təminatları tərəfindən<ph name="END_LINK_OSS" /> əlçatan edilib.</translation>
<translation id="2588322182880276190">Chrome logosu</translation>
+<translation id="290720624583273918">CloudReady 2.0 ilkin ayarlamanı tamamlamayıb.</translation>
<translation id="3444832043240812445"><ph name="BEGIN_LINK" />Xəta haqqında hesabatı aktiv etdikdə<ph name="END_LINK" />, bu səhifə yalnız son xətalar haqqında məlumatı göstərir.</translation>
<translation id="3875312571075912821">Chrome'a brandmauerinizdə və ya antivirus ayarlarınızda şəbəkəyə giriş imkanı verin.</translation>
<translation id="4010643444566880169">Chrome OS ilkin quraşdırmanı tamamlamadı.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_be.xtb b/chromium/components/strings/components_google_chrome_strings_be.xtb
index 2be155a4b4e..1a7f37dae41 100644
--- a/chromium/components/strings/components_google_chrome_strings_be.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_be.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">Змены ÑžÑтупÑць у Ñілу паÑÐ»Ñ Ð¿ÐµÑ€Ð°Ð·Ð°Ð¿ÑƒÑку Chrome.</translation>
<translation id="2447485272386224171">Chrome працуе дзÑкуючы праекту <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> з адкрытым зыходным кодам Ñ– іншаму <ph name="BEGIN_LINK_OSS" />праграмнаму забеÑпÑчÑнню з адкрытым зыходным кодам<ph name="END_LINK_OSS" />.</translation>
<translation id="2588322182880276190">Лагатып Chrome</translation>
+<translation id="290720624583273918">ÐС CloudReady 2.0 не завÑршыла першапачатковы працÑÑ Ð½Ð°Ð»Ð°Ð´Ð¶Ð²Ð°Ð½Ð½Ñ.</translation>
<translation id="3444832043240812445">Ð†Ð½Ñ„Ð°Ñ€Ð¼Ð°Ñ†Ñ‹Ñ Ð°Ð± нÑдаўніх збоÑÑ… паказваецца на гÑтай Ñтаронцы, толькі калі <ph name="BEGIN_LINK" />ўключана адпраўка Ñправаздач аб збоÑÑ…<ph name="END_LINK" />.</translation>
<translation id="3875312571075912821">Дазвольце Chrome доÑтуп да Ñеткі Ñž наладах брандмаўÑра або
антывіруÑа.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_bg.xtb b/chromium/components/strings/components_google_chrome_strings_bg.xtb
index 81b005787a0..81af4c44388 100644
--- a/chromium/components/strings/components_google_chrome_strings_bg.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_bg.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">Промените ви ще влÑзат в Ñила ÑÐ»ÐµÐ´Ð²Ð°Ñ‰Ð¸Ñ Ð¿ÑŠÑ‚, когато Ñтартирате отново Chrome.</translation>
<translation id="2447485272386224171">Chrome е възможен благодарение на проекта Ñ Ð¾Ñ‚Ð²Ð¾Ñ€ÐµÐ½ код <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> и на друг <ph name="BEGIN_LINK_OSS" />Ñофтуер Ñ Ð¾Ñ‚Ð²Ð¾Ñ€ÐµÐ½ код<ph name="END_LINK_OSS" />.</translation>
<translation id="2588322182880276190">Лого на Chrome</translation>
+<translation id="290720624583273918">Първоначалното наÑтройване на CloudReady 2.0 не е завършено.</translation>
<translation id="3444832043240812445">Ð’ тази Ñтраница Ñе показва Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð·Ð° Ñкорошните Ñривове Ñамо ако Ñте <ph name="BEGIN_LINK" />активирали изпращането на Ñигнали за Ñривове<ph name="END_LINK" />.</translation>
<translation id="3875312571075912821">Разрешете доÑтъпа на Chrome до мрежата от наÑтройките на защитната Ñтена
или антивируÑÐ½Ð¸Ñ Ñи Ñофтуер.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_bn.xtb b/chromium/components/strings/components_google_chrome_strings_bn.xtb
index 2764da400be..9cb85fb71f4 100644
--- a/chromium/components/strings/components_google_chrome_strings_bn.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_bn.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">আপনি পরে আবার যখন Google Chrome লঞà§à¦š করবেন, তখন আপনার পরিবরà§à¦¤à¦¨à¦—à§à¦²à¦¿ কারà§à¦¯à¦•à¦° হবে।</translation>
<translation id="2447485272386224171"><ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> ওপেন সোরà§à¦¸ পà§à¦°à§‹à¦œà§‡à¦•à§à¦Ÿ à¦à¦¬à¦‚ অনà§à¦¯à¦¾à¦¨à§à¦¯ <ph name="BEGIN_LINK_OSS" />ওপেন সোরà§à¦¸ সফà§à¦Ÿà¦“য়à§à¦¯à¦¾à¦°<ph name="END_LINK_OSS" /> বà§à¦¯à¦¬à¦¹à¦¾à¦° করে Chrome তৈরি করা সমà§à¦­à¦¬ হয়েছে।</translation>
<translation id="2588322182880276190">Chrome লোগো</translation>
+<translation id="290720624583273918">CloudReady 2.0 তার পà§à¦°à¦¾à¦¥à¦®à¦¿à¦• সেট-আপ সমà§à¦ªà§‚রà§à¦£ করেনি।</translation>
<translation id="3444832043240812445">যদি আপনি <ph name="BEGIN_LINK" />কà§à¦°à§à¦¯à¦¾à¦¶ পà§à¦°à¦¤à¦¿à¦¬à§‡à¦¦à¦¨ সকà§à¦·à¦® করেন<ph name="END_LINK" /> তাহলে à¦à¦‡ পৃষà§à¦ à¦¾à¦Ÿà¦¿ কেবল আপনার সামà§à¦ªà§à¦°à¦¤à¦¿à¦• কà§à¦°à§à¦¯à¦¾à¦¶à¦—à§à¦²à¦¿à¦° তথà§à¦¯ দেখায়৷</translation>
<translation id="3875312571075912821">আপনার ফায়ারওয়াল বা অà§à¦¯à¦¾à¦¨à§à¦Ÿà¦¿à¦­à¦¾à¦‡à¦°à¦¾à¦¸ সেটিংসে Chrome কে নেটওয়ারà§à¦• অà§à¦¯à¦¾à¦•à§à¦¸à§‡à¦¸
করতে অনà§à¦®à¦¤à¦¿ দিন।</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_bs.xtb b/chromium/components/strings/components_google_chrome_strings_bs.xtb
index d6c67881d63..8dc05649f04 100644
--- a/chromium/components/strings/components_google_chrome_strings_bs.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_bs.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">Promjene će stupiti na snagu kada sljedeći put pokrenete Chrome.</translation>
<translation id="2447485272386224171">Chrome su omogućili <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> projekat otvorenog koda i drugi <ph name="BEGIN_LINK_OSS" />softveri otvorenog koda<ph name="END_LINK_OSS" />.</translation>
<translation id="2588322182880276190">Chromeov logotip</translation>
+<translation id="290720624583273918">CloudReady 2.0 nije dovrÅ¡io poÄetno postavljanje.</translation>
<translation id="3444832043240812445">Ova stranica prikazuje iskljuÄivo informacije o nedavnim padovima aplikacija ako <ph name="BEGIN_LINK" />omogućite izvjeÅ¡taj o padovima aplikacije<ph name="END_LINK" />.</translation>
<translation id="3875312571075912821">Dozvolite Chromeu da pristupi mreži u postavkama vašeg zaštitnog zida ili
antivirusnog programa.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_ca.xtb b/chromium/components/strings/components_google_chrome_strings_ca.xtb
index 8ff0a55f956..db7f693ca25 100644
--- a/chromium/components/strings/components_google_chrome_strings_ca.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_ca.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">Els canvis s'aplicaran la propera vegada que reiniciïs Chrome.</translation>
<translation id="2447485272386224171">Chrome és possible gràcies al projecte de codi obert <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> i a altres <ph name="BEGIN_LINK_OSS" />programes de codi obert<ph name="END_LINK_OSS" />.</translation>
<translation id="2588322182880276190">Logotip de Chrome</translation>
+<translation id="290720624583273918">CloudReady 2.0 no ha completat la configuració inicial.</translation>
<translation id="3444832043240812445">Aquesta pàgina només mostrarà informació sobre els bloqueigs recents si <ph name="BEGIN_LINK" />activeu la creació d'informes de bloqueig<ph name="END_LINK" />.</translation>
<translation id="3875312571075912821">Configureu el tallafoc o l'antivirus per permetre que Chrome accedeixi
a la xarxa.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_cs.xtb b/chromium/components/strings/components_google_chrome_strings_cs.xtb
index f9a4ba2bacc..1431f0c0433 100644
--- a/chromium/components/strings/components_google_chrome_strings_cs.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_cs.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">ZmÄ›ny se projeví po příštím restartu prohlížeÄe Chrome.</translation>
<translation id="2447485272386224171">Chrome staví na projektu s otevřeným zdrojovým kódem <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> a využívá i další <ph name="BEGIN_LINK_OSS" />otevřený software<ph name="END_LINK_OSS" />.</translation>
<translation id="2588322182880276190">Logo Chrome</translation>
+<translation id="290720624583273918">Systém CloudReady 2.0 jeÅ¡tÄ› nedokonÄil úvodní nastavení.</translation>
<translation id="3444832043240812445">Pokud zvolíte možnost <ph name="BEGIN_LINK" />povolit zprávy o selhání<ph name="END_LINK" />, tato stránka bude zobrazovat jen informace o posledních selháních.</translation>
<translation id="3875312571075912821">V nastavení firewallu a antivirového programu povolte prohlížeÄi Chrome přístup k síti.</translation>
<translation id="4010643444566880169">Systém Chrome OS nedokonÄil úvodní nastavení.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_da.xtb b/chromium/components/strings/components_google_chrome_strings_da.xtb
index 69e5f3ed210..78b9096ed01 100644
--- a/chromium/components/strings/components_google_chrome_strings_da.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_da.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">Dine ændringer træder i kraft, næste gang du genstarter Chrome.</translation>
<translation id="2447485272386224171">Open source-projektet <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> og anden <ph name="BEGIN_LINK_OSS" />open source-software<ph name="END_LINK_OSS" /> er med til at gøre Chrome muligt.</translation>
<translation id="2588322182880276190">Chrome-logo</translation>
+<translation id="290720624583273918">CloudReady 2.0 har ikke fuldført sin indledende konfiguration.</translation>
<translation id="3444832043240812445">Denne side viser kun oplysninger om dine seneste nedbrud, hvis du <ph name="BEGIN_LINK" />aktiverer rapportering af nedbrud<ph name="END_LINK" />.</translation>
<translation id="3875312571075912821">Tillad, at Chrome får adgang til netværket i dine indstillinger for firewall eller
antivirus.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_de.xtb b/chromium/components/strings/components_google_chrome_strings_de.xtb
index 25d24d61f8e..7f7adaa1825 100644
--- a/chromium/components/strings/components_google_chrome_strings_de.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_de.xtb
@@ -2,24 +2,25 @@
<!DOCTYPE translationbundle>
<translationbundle lang="de">
<translation id="1016765312371154165">Chrome wurde nicht richtig beendet.</translation>
-<translation id="130631256467250065">Ihre Änderungen werden beim nächsten Neustart wirksam.</translation>
-<translation id="1635457557763038537">Ihre Änderungen werden beim nächsten Neustart von Chrome wirksam.</translation>
+<translation id="130631256467250065">Deine Änderungen werden beim nächsten Neustart wirksam.</translation>
+<translation id="1635457557763038537">Deine Änderungen werden beim nächsten Neustart von Chrome wirksam.</translation>
<translation id="2447485272386224171">Chrome wird durch das Open-Source-Projekt <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> und andere <ph name="BEGIN_LINK_OSS" />Open-Source-Software<ph name="END_LINK_OSS" /> ermöglicht.</translation>
<translation id="2588322182880276190">Chrome-Logo</translation>
-<translation id="3444832043240812445">Diese Seite zeigt nur Informationen zu Ihren letzten Abstürzen, wenn Sie die <ph name="BEGIN_LINK" />Absturzberichtsfunktion aktivieren<ph name="END_LINK" />.</translation>
-<translation id="3875312571075912821">Erlauben Sie Chrome in Ihren Firewall- und Virenschutzeinstellungen den Zugriff auf das Netzwerk.</translation>
+<translation id="290720624583273918">Die Ersteinrichtung von CloudReady 2.0 wurde nicht abgeschlossen.</translation>
+<translation id="3444832043240812445">Diese Seite zeigt nur Informationen zu deinen letzten Abstürzen, wenn du die <ph name="BEGIN_LINK" />Absturzberichtsfunktion aktivierst<ph name="END_LINK" />.</translation>
+<translation id="3875312571075912821">Erlaube Chrome in deinen Firewall- und Virenschutzeinstellungen den Zugriff auf das Netzwerk.</translation>
<translation id="4010643444566880169">Die Ersteinrichtung von Chrome OS wurde nicht abgeschlossen.</translation>
<translation id="5005121315113832363">Diese Seite wurde von Chrome blockiert</translation>
-<translation id="6011049234605203654">Gehen Sie zum Chrome-Menü &gt; "<ph name="SETTINGS_TITLE" />" &gt; "<ph name="ADVANCED_TITLE" />" &gt; "<ph name="PROXIES_TITLE" />" und vergewissern Sie sich, dass in Ihrer Konfiguration die Einstellung "Kein Proxy" oder "Direkt" verwendet wird.</translation>
-<translation id="6341737370356890233">Öffnen Sie
+<translation id="6011049234605203654">Gehe zum Chrome-Menü &gt; „<ph name="SETTINGS_TITLE" />“ &gt; „<ph name="ADVANCED_TITLE" />“ &gt; „<ph name="PROXIES_TITLE" />“ und vergewissere dich, dass in deiner Konfiguration die Einstellung „Kein Proxy“ oder „Direkt“ verwendet wird.</translation>
+<translation id="6341737370356890233">Öffne
das Chrome-Menü &gt;
<ph name="SETTINGS_TITLE" />
&gt;
<ph name="ADVANCED_TITLE" />
- und deaktivieren Sie "<ph name="NO_PREFETCH_DESCRIPTION" />".
+ und deaktiviere "<ph name="NO_PREFETCH_DESCRIPTION" />".
Falls das Problem nicht dadurch verursacht wurde, empfehlen wir,
diese Option für eine verbesserte Leistung wieder zu aktivieren.</translation>
-<translation id="6855094794438142393">Gehen Sie zum Chrome-Menü &gt; "<ph name="SETTINGS_TITLE" />" &gt; "<ph name="ADVANCED_TITLE" />" &gt; "<ph name="PROXIES_TITLE" />" &gt; "LAN-Einstellungen" und deaktivieren Sie die Option "Proxyserver für LAN verwenden".</translation>
+<translation id="6855094794438142393">Gehe zum Chrome-Menü &gt; „<ph name="SETTINGS_TITLE" />“ &gt; „<ph name="ADVANCED_TITLE" />“ &gt; „<ph name="PROXIES_TITLE" />“ &gt; „LAN-Einstellungen“ und deaktiviere die Option „Proxyserver für LAN verwenden“.</translation>
<translation id="7230956101631259640">Dies ist eine sichere Chrome-Seite</translation>
-<translation id="8187289872471304532">Gehen Sie zu "Programme" &gt; "Systemeinstellungen" &gt; "Netzwerk" &gt; "Erweitert" &gt; "Proxys" und deaktivieren Sie alle ausgewählten Proxyserver.</translation>
+<translation id="8187289872471304532">Gehe zu „Programme“ &gt; „Systemeinstellungen“ &gt; „Netzwerk“ &gt; „Erweitert“ &gt; „Proxys“ und deaktiviere alle ausgewählten Proxyserver.</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/strings/components_google_chrome_strings_el.xtb b/chromium/components/strings/components_google_chrome_strings_el.xtb
index fe3b6f984c1..00c5b43076a 100644
--- a/chromium/components/strings/components_google_chrome_strings_el.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_el.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">Οι αλλαγές που Ï€Ïαγματοποιήσατε θα ισχÏσουν την επόμενη φοÏά που θα εκκινήσετε το Chrome.</translation>
<translation id="2447485272386224171">Το Chrome δημιουÏγήθηκε με τη βοήθεια του έÏγου Î±Î½Î¿Î¹ÎºÏ„Î¿Ï ÎºÏŽÎ´Î¹ÎºÎ± <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> και άλλου <ph name="BEGIN_LINK_OSS" />Î»Î¿Î³Î¹ÏƒÎ¼Î¹ÎºÎ¿Ï Î±Î½Î¿Î¹ÎºÏ„Î¿Ï ÎºÏŽÎ´Î¹ÎºÎ±<ph name="END_LINK_OSS" />.</translation>
<translation id="2588322182880276190">Λογότυπο Chrome</translation>
+<translation id="290720624583273918">Το CloudReady 2.0 δεν ολοκλήÏωσε την αÏχική του ÏÏθμιση.</translation>
<translation id="3444832043240812445">Αυτή η σελίδα εμφανίζει μόνο πληÏοφοÏίες για τα σφάλματα που παÏουσιάστηκαν Ï€Ïόσφατα εφόσον <ph name="BEGIN_LINK" />έχετε ενεÏγοποιημένη την αναφοÏά σφαλμάτων<ph name="END_LINK" />.</translation>
<translation id="3875312571075912821">ΕπιτÏέψτε στο Chrome να αποκτήσει Ï€Ïόσβαση στο δίκτυο από τις Ïυθμίσεις του τείχους Ï€Ïοστασίας
ή του Î»Î¿Î³Î¹ÏƒÎ¼Î¹ÎºÎ¿Ï Ï€Ïοστασίας από ιοÏÏ‚ που διαθέτετε.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_en-GB.xtb b/chromium/components/strings/components_google_chrome_strings_en-GB.xtb
index 01e29d57054..c1d8a6aa69f 100644
--- a/chromium/components/strings/components_google_chrome_strings_en-GB.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_en-GB.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">Your changes will take effect the next time that you relaunch Chrome.</translation>
<translation id="2447485272386224171">Chrome is made possible by the <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> open-source project and other <ph name="BEGIN_LINK_OSS" />open-source software<ph name="END_LINK_OSS" />.</translation>
<translation id="2588322182880276190">Chrome logo</translation>
+<translation id="290720624583273918">CloudReady 2.0 hasn’t completed its initial setup.</translation>
<translation id="3444832043240812445">This page only shows information on your recent crashes if you <ph name="BEGIN_LINK" />enable crash reporting<ph name="END_LINK" />.</translation>
<translation id="3875312571075912821">Allow Chrome to access the network in your firewall or antivirus
settings.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_es-419.xtb b/chromium/components/strings/components_google_chrome_strings_es-419.xtb
index f612ada7657..81089cf48f6 100644
--- a/chromium/components/strings/components_google_chrome_strings_es-419.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_es-419.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">Los cambios se aplicarán la próxima vez que reinicies Chrome.</translation>
<translation id="2447485272386224171">Chrome es una realidad gracias al proyecto de código abierto <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> y a otros <ph name="BEGIN_LINK_OSS" />software de código abierto<ph name="END_LINK_OSS" />.</translation>
<translation id="2588322182880276190">Logo de Chrome</translation>
+<translation id="290720624583273918">No se completó la configuración inicial de CloudReady 2.0</translation>
<translation id="3444832043240812445">Esta página sólo muestra información sobre fallas recientes si se <ph name="BEGIN_LINK" />activan los informes sobre fallas<ph name="END_LINK" />.</translation>
<translation id="3875312571075912821">Permite que Chrome acceda a la red en tu configuración de firewall
o antivirus.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_es.xtb b/chromium/components/strings/components_google_chrome_strings_es.xtb
index df110ce4efa..5378aa2ea5d 100644
--- a/chromium/components/strings/components_google_chrome_strings_es.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_es.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">Los cambios se aplicarán la próxima vez que reinicies Chrome.</translation>
<translation id="2447485272386224171">Chrome se ha creado gracias al proyecto de software libre <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> y a otro <ph name="BEGIN_LINK_OSS" />software libre<ph name="END_LINK_OSS" />.</translation>
<translation id="2588322182880276190">Logotipo de Chrome</translation>
+<translation id="290720624583273918">No se ha completado la configuración inicial de CloudReady 2.0.</translation>
<translation id="3444832043240812445">Esta página solo muestra información sobre fallos recientes si se <ph name="BEGIN_LINK" />habilitan los informes sobre fallos<ph name="END_LINK" />.</translation>
<translation id="3875312571075912821">Configura tu cortafuegos o tu antivirus para permitir el acceso de Chrome
a la red.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_et.xtb b/chromium/components/strings/components_google_chrome_strings_et.xtb
index 6021c216c7f..40e9156cda5 100644
--- a/chromium/components/strings/components_google_chrome_strings_et.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_et.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">Teie muudatused jõustuvad järgmisel korral, kui käivitate Chrome'i uuesti.</translation>
<translation id="2447485272386224171">Chrome'i aluseks on avatud lähtekoodiga projekt <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> ja muu <ph name="BEGIN_LINK_OSS" />avatud lähtekoodiga tarkvara<ph name="END_LINK_OSS" />.</translation>
<translation id="2588322182880276190">Chrome'i logo</translation>
+<translation id="290720624583273918">CloudReady 2.0 algne seadistamine ei ole lõpule viidud.</translation>
<translation id="3444832043240812445">Lehel näidatakse vaid teavet hiljutiste krahhide kohta, kui olete <ph name="BEGIN_LINK" />krahhide aruandluse lubanud<ph name="END_LINK" />.</translation>
<translation id="3875312571075912821">Lubage Chrome'i juurdepääs võrgule tulemüüri või viirusetõrje
seadetes.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_eu.xtb b/chromium/components/strings/components_google_chrome_strings_eu.xtb
index f147897dfba..fab919393e8 100644
--- a/chromium/components/strings/components_google_chrome_strings_eu.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_eu.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">Aldaketek Chrome abiarazten duzun hurrengo aldian izango dute eragina.</translation>
<translation id="2447485272386224171">Kode irekiko <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> proiektuak eta <ph name="BEGIN_LINK_OSS" />kode irekiko beste software<ph name="END_LINK_OSS" /> batzuek egiten dute Chrome posible.</translation>
<translation id="2588322182880276190">Chrome logotipoa</translation>
+<translation id="290720624583273918">CloudReady 2.0-k ez du amaitu hasierako konfigurazio-prozesua.</translation>
<translation id="3444832043240812445">Orri honek azken hutsegiteei buruzko informazioa soilik bistaratzen du, <ph name="BEGIN_LINK" />hutsegiteen berri ematea gaitzen baduzu<ph name="END_LINK" />.</translation>
<translation id="3875312571075912821">Ez eman suebakiaren edo birusen aurkako softwarearen ezarpenetan sarea atzitzeko baimena Chrome-ri.</translation>
<translation id="4010643444566880169">Chrome OS-k ez du amaitu hasierako konfigurazioa.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_fa.xtb b/chromium/components/strings/components_google_chrome_strings_fa.xtb
index 672a4edf8d7..2ef25cc2af3 100644
--- a/chromium/components/strings/components_google_chrome_strings_fa.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_fa.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">â€Ø¯Ùعه بعد Ú©Ù‡ Chrome را راه‌اندازی مجدد کنید، این تغییرات اعمال خواهد شد.</translation>
<translation id="2447485272386224171">â€Ø§Ø±Ø§Ø¦Ù‡ Chrome با پروژه متن‌باز <ph name="BEGIN_LINK_CHROMIUM" />Chromium <ph name="END_LINK_CHROMIUM" /> Ùˆ دیگر <ph name="BEGIN_LINK_OSS" />نرم‌اÙزارهای متن‌باز<ph name="END_LINK_OSS" /> ممکن شده است.</translation>
<translation id="2588322182880276190">â€Ù†Ø´Ø§Ù†â€ŒÙˆØ§Ø±Ù‡ Chrome</translation>
+<translation id="290720624583273918">â€Ø±Ø§Ù‡â€ŒØ§Ù†Ø¯Ø§Ø²ÛŒ اولیه CloudReady 2.0 کامل نشده است.</translation>
<translation id="3444832043240812445">درصورتی‌که <ph name="BEGIN_LINK" />ارسال گزارش خرابی را Ùعال کنید<ph name="END_LINK" />ØŒ این صÙحه Ùقط اطلاعاتی را در مورد مشکلات اخیر شما نشان می‌دهد.</translation>
<translation id="3875312571075912821">â€Ø¯Ø± تنظیمات دیوار آتش یا ضدویروستان، به Chrome اجازه دسترسی به شبکه را
بدهید.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_fi.xtb b/chromium/components/strings/components_google_chrome_strings_fi.xtb
index 03715181627..aaf8f68e5ef 100644
--- a/chromium/components/strings/components_google_chrome_strings_fi.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_fi.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">Muutokset tulevat voimaan, kun käynnistät Chromen seuraavan kerran.</translation>
<translation id="2447485272386224171">Chromen mahdollistivat avoimen lähdekoodin projekti <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> ja muut <ph name="BEGIN_LINK_OSS" />avoimen lähdekoodin ohjelmistot<ph name="END_LINK_OSS" />.</translation>
<translation id="2588322182880276190">Chrome-logo</translation>
+<translation id="290720624583273918">CloudReady 2.0 ei ole suorittanut käyttöönottoa loppuun.</translation>
<translation id="3444832043240812445">Tällä sivulla näkyy tietoja viimeaikaisista kaatumisista vain, jos <ph name="BEGIN_LINK" />otat kaatumisraportit käyttöön<ph name="END_LINK" />.</translation>
<translation id="3875312571075912821">Myönnä Chromelle verkon käyttöoikeus palomuurin tai virustorjuntaohjelmiston
asetuksissa</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_fil.xtb b/chromium/components/strings/components_google_chrome_strings_fil.xtb
index 9ef7dab8b84..ec747e9b67d 100644
--- a/chromium/components/strings/components_google_chrome_strings_fil.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_fil.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">Magkakabisa ang iyong mga pagbabago sa susunod na ilunsad mo ulit ang Chrome.</translation>
<translation id="2447485272386224171">Nagiging posible ang Chrome sa pamamagitan ng <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> open source project at iba pang <ph name="BEGIN_LINK_OSS" />open source software<ph name="END_LINK_OSS" />.</translation>
<translation id="2588322182880276190">Logo ng Chrome</translation>
+<translation id="290720624583273918">Hindi pa nakukumpleto ng CloudReady 2.0 ang paunang setup nito.</translation>
<translation id="3444832043240812445">Ipinapakita lang ng pahinang ito ang impormasyon ng iyong kamakailang mga pag-crash kung <ph name="BEGIN_LINK" />papaganahin mo ang pag-uulat ng pag-crash<ph name="END_LINK" />.</translation>
<translation id="3875312571075912821">Pahintulutan ang Chrome na i-access ang network
sa mga setting ng iyong firewall o antivirus.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_fr-CA.xtb b/chromium/components/strings/components_google_chrome_strings_fr-CA.xtb
index 1639ff18d85..51d32979a3c 100644
--- a/chromium/components/strings/components_google_chrome_strings_fr-CA.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_fr-CA.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">Vos modifications seront appliquées au prochain redémarrage de Chrome.</translation>
<translation id="2447485272386224171">Chrome fonctionne grâce au projet de logiciel libre <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> ainsi qu'à d'autres <ph name="BEGIN_LINK_OSS" />logiciels libres<ph name="END_LINK_OSS" />.</translation>
<translation id="2588322182880276190">Logo de Google Chrome</translation>
+<translation id="290720624583273918">La configuration initiale de CloudReady 2.0 n'est pas terminée.</translation>
<translation id="3444832043240812445">Cette page affiche uniquement de l'information sur les erreurs récentes si vous <ph name="BEGIN_LINK" />activez la génération de rapports d'erreur<ph name="END_LINK" />.</translation>
<translation id="3875312571075912821">Autorisez Chrome à accéder au réseau dans les paramètres de votre pare-feu
ou de votre antivirus.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_fr.xtb b/chromium/components/strings/components_google_chrome_strings_fr.xtb
index 6ca2e3d0b12..ea51d22d0e7 100644
--- a/chromium/components/strings/components_google_chrome_strings_fr.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_fr.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">Vos modifications seront prises en compte au prochain redémarrage de Chrome.</translation>
<translation id="2447485272386224171">Chrome fonctionne grâce au projet Open Source <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> et à d'autres <ph name="BEGIN_LINK_OSS" />logiciels libres<ph name="END_LINK_OSS" />.</translation>
<translation id="2588322182880276190">Logo Google Chrome</translation>
+<translation id="290720624583273918">La configuration initiale de CloudReady 2.0 n'est pas terminée.</translation>
<translation id="3444832043240812445">Cette page affiche uniquement des informations sur les erreurs récentes si vous <ph name="BEGIN_LINK" />activez l'envoi de rapports d'erreur<ph name="END_LINK" />.</translation>
<translation id="3875312571075912821">Autorisez Chrome à accéder au réseau dans les paramètres du pare-feu ou
de l'antivirus.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_gl.xtb b/chromium/components/strings/components_google_chrome_strings_gl.xtb
index aa1ce45193f..6277daacf1d 100644
--- a/chromium/components/strings/components_google_chrome_strings_gl.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_gl.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">Os cambios aplicaranse a próxima vez que reinicies Chrome.</translation>
<translation id="2447485272386224171">Chrome creouse grazas ao proxecto de código aberto <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> e a outro <ph name="BEGIN_LINK_OSS" />software de código aberto<ph name="END_LINK_OSS" />.</translation>
<translation id="2588322182880276190">Logotipo de Chrome</translation>
+<translation id="290720624583273918">CloudReady 2.0 non completou a súa configuración inicial.</translation>
<translation id="3444832043240812445">Esta páxina só mostra información sobre os teus erros recentes se <ph name="BEGIN_LINK" />activas os informes de erros<ph name="END_LINK" />.</translation>
<translation id="3875312571075912821">Configura o teu firewall ou o teu antivirus para permitir o acceso
de Chrome á rede.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_gu.xtb b/chromium/components/strings/components_google_chrome_strings_gu.xtb
index 8715c5be409..90f179d0dd0 100644
--- a/chromium/components/strings/components_google_chrome_strings_gu.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_gu.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">તમે આગલી વખતે Chromeને ફરીથી લૉનà«àªš કરશો તà«àª¯àª¾àª°à«‡ તમારા ફેરફારો લાગૠથશે.</translation>
<translation id="2447485272386224171">Chrome, <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> ઓપન સૉરà«àª¸ પà«àª°à«‹àªœà«‡àª•à«àªŸ અને અનà«àª¯ <ph name="BEGIN_LINK_OSS" />ઓપન સૉરà«àª¸ સૉફà«àªŸàªµà«‡àª°<ph name="END_LINK_OSS" /> દà«àªµàª¾àª°àª¾ શકà«àª¯ બનà«àª¯à«àª‚ છે.</translation>
<translation id="2588322182880276190">Chrome લૉગો</translation>
+<translation id="290720624583273918">CloudReady 2.0નà«àª‚ શરૂઆતનà«àª‚ સેટઅપ પૂરà«àª‚ થયà«àª‚ નથી.</translation>
<translation id="3444832043240812445">જો તમે <ph name="BEGIN_LINK" />કà«àª°à«…શ રિપોરà«àªŸàª¿àª‚ગ ચાલૠકરો છો<ph name="END_LINK" /> તો આ પેજ માતà«àª° તમારા હાલનાં કà«àª°à«…શ પર માહિતી બતાવે છે</translation>
<translation id="3875312571075912821">Chromeને તમારા ફાયરવૉલ અથવા àªàª¨à«àªŸàª¿àªµàª¾àª¯àª°àª¸ સેટિંગમાં નેટવરà«àª• àªàª•à«àª¸à«‡àª¸ કરવાની
મંજૂરી આપો.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_hi.xtb b/chromium/components/strings/components_google_chrome_strings_hi.xtb
index 7e225ce4872..aab5923e340 100644
--- a/chromium/components/strings/components_google_chrome_strings_hi.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_hi.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">अगली बार जब आप Chrome को फिर से लॉनà¥à¤š करेंगे, तो आपके बदलाव लागू होंगे.</translation>
<translation id="2447485272386224171">Chrome को <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> ओपन सोरà¥à¤¸ पà¥à¤°à¥‹à¤œà¥‡à¤•à¥à¤Ÿ और अनà¥à¤¯ <ph name="BEGIN_LINK_OSS" />ओपन सोरà¥à¤¸ सॉफ़à¥à¤Ÿà¤µà¥‡à¤¯à¤°<ph name="END_LINK_OSS" /> ने संभव बनाया है.</translation>
<translation id="2588322182880276190">Chrome लोगो</translation>
+<translation id="290720624583273918">CloudReady 2.0 ने अपना शà¥à¤°à¥à¤†à¤¤à¥€ सेट अप पूरा नहीं किया है.</translation>
<translation id="3444832043240812445">अगर आप <ph name="BEGIN_LINK" />कà¥à¤°à¥ˆà¤¶ रिपोरà¥à¤Ÿ करना चालू<ph name="END_LINK" /> करते हैं तो यह पेज सिरà¥à¥ž आपके हाल ही के कà¥à¤°à¥ˆà¤¶ की जानकारी दिखाà¤à¤—ा.</translation>
<translation id="3875312571075912821">Chrome को अपनी फ़ायरवॉल और à¤à¤‚टीवायरस सेटिंग में
नेटवरà¥à¤• à¤à¤•à¥à¤¸à¥‡à¤¸ करने दें.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_hr.xtb b/chromium/components/strings/components_google_chrome_strings_hr.xtb
index 02dcacfb2f0..762994fc541 100644
--- a/chromium/components/strings/components_google_chrome_strings_hr.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_hr.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">Promjene će poÄeti vrijediti sljedeći put kad ponovo pokrenete Chrome.</translation>
<translation id="2447485272386224171">Chrome je omogućio <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" />, projekt otvorenog koda i drugi <ph name="BEGIN_LINK_OSS" />softveri otvorenog koda<ph name="END_LINK_OSS" />.</translation>
<translation id="2588322182880276190">Logotip Chrome</translation>
+<translation id="290720624583273918">CloudReady 2.0 nije dovrÅ¡io poÄetno postavljanje.</translation>
<translation id="3444832043240812445">Ova stranica prikazuje samo informacije o vašim nedavnim padovima ako <ph name="BEGIN_LINK" />omogućite izvješćivanja o padu<ph name="END_LINK" />.</translation>
<translation id="3875312571075912821">U postavkama vatrozida ili antivirusnog programa omogućite Chromeu da pristupa mreži.</translation>
<translation id="4010643444566880169">OS Chrome nije dovrÅ¡io poÄetno postavljanje.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_hu.xtb b/chromium/components/strings/components_google_chrome_strings_hu.xtb
index ac87fbc9e95..7a1a4e2f201 100644
--- a/chromium/components/strings/components_google_chrome_strings_hu.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_hu.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">Módosításai a Chrome újraindítása után lépnek érvénybe.</translation>
<translation id="2447485272386224171">A Chrome a <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> nyílt forráskódú projektnek és további <ph name="BEGIN_LINK_OSS" />nyílt forráskódú szoftvereknek<ph name="END_LINK_OSS" /> köszönhetően jött létre.</translation>
<translation id="2588322182880276190">Chrome embléma</translation>
+<translation id="290720624583273918">A CloudReady 2.0 nem fejezte be a kezdeti beállítását.</translation>
<translation id="3444832043240812445">Ez az oldal csak akkor jelenít meg információkat a legutóbbi rendszerösszeomlásokról, ha <ph name="BEGIN_LINK" />engedélyezi a hibabejelentést<ph name="END_LINK" /> .</translation>
<translation id="3875312571075912821">A hálózat elérésének engedélyezése a Chrome számára a tűzfal-
vagy vírusirtó-beállításokban.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_hy.xtb b/chromium/components/strings/components_google_chrome_strings_hy.xtb
index 7ce0526898f..e97f72f5a28 100644
--- a/chromium/components/strings/components_google_chrome_strings_hy.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_hy.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">ÕÕ¥Ö€ ÖƒÕ¸ÖƒÕ¸Õ­Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¶ Õ¸Ö‚ÕªÕ« Õ´Õ¥Õ» Õ¯Õ´Õ¿Õ¶Õ¥Õ¶ Õ°Õ¡Õ»Õ¸Ö€Õ¤ Õ¡Õ¶Õ£Õ¡Õ´ Chrome-Õ¨ Õ£Õ¸Ö€Õ®Õ¡Ö€Õ¯Õ¥Õ¬Õ«Õ½Ö‰</translation>
<translation id="2447485272386224171">Chrome-Õ¨ Õ½Õ¿Õ¥Õ²Õ®Õ¾Õ¥Õ¬ Õ§ <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> Õ¶Õ¡Õ­Õ¡Õ£Õ®Õ« Ö‡ Õ¡ÕµÕ¬ <ph name="BEGIN_LINK_OSS" />Õ¢Õ¡Ö Õ¯Õ¸Õ¤Õ¸Õ¾ Õ®Ö€Õ¡Õ£Ö€Õ¡Õ¯Õ¡Õ¦Õ´Õ¥Ö€Õ«<ph name="END_LINK_OSS" /> Õ°Õ«Õ´Õ¡Õ¶ Õ¾Ö€Õ¡Ö‰</translation>
<translation id="2588322182880276190">Chrome-Õ« ÕºÕ¡Õ¿Õ¯Õ¥Ö€Õ¡Õ¶Õ·Õ¡Õ¶</translation>
+<translation id="290720624583273918">CloudReady 2.0-Õ¨ Õ¹Õ« Õ¡Õ¾Õ¡Ö€Õ¿Õ¥Õ¬ Õ«Ö€ Õ¶Õ¡Õ­Õ¶Õ¡Õ¯Õ¡Õ¶ Õ¯Õ¡Ö€Õ£Õ¡Õ¾Õ¸Ö€Õ¸Ö‚Õ´Õ¨Ö‰</translation>
<translation id="3444832043240812445">Ô±ÕµÕ½ Õ§Õ»Õ¨ ÖÕ¸Ö‚ÕµÖ Õ¯Õ¿Õ¡ Õ´Õ«Õ¡ÕµÕ¶ Õ¾Õ¥Ö€Õ»Õ«Õ¶ Õ­Õ¡ÖƒÕ¡Õ¶Õ¸Ö‚Õ´Õ¶Õ¥Ö€Õ« Õ´Õ¡Õ½Õ«Õ¶ Õ¿Õ¥Õ²Õ¥Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¨, Õ¥Õ©Õ¥ <ph name="BEGIN_LINK" />Õ´Õ«Õ¡ÖÕ¶Õ¥Ö„ Õ­Õ¡ÖƒÕ¡Õ¶Õ´Õ¡Õ¶ Õ°Õ¡Õ·Õ¾Õ¥Õ¿Õ¾Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ« Õ¸Ö‚Õ²Õ¡Ö€Õ¯Õ¸Ö‚Õ´Õ¨<ph name="END_LINK" />:</translation>
<translation id="3875312571075912821">Õ€Ö€Õ¡ÕºÕ¡Õ¿Õ« Õ¯Õ¡Õ´ Õ°Õ¡Õ¯Õ¡Õ¾Õ«Ö€Õ¸Ö‚Õ½Õ¡ÕµÕ«Õ¶ Õ®Ö€Õ¡Õ£Ö€Õ« Õ¯Õ¡Ö€Õ£Õ¡Õ¾Õ¸Ö€Õ¸Ö‚Õ´Õ¶Õ¥Ö€Õ¸Ö‚Õ´
Õ©Õ¸Ö‚ÕµÕ¬Õ¡Õ¿Ö€Õ¥Ö„ Chrome-Õ«Õ¶ Õ´Õ«Õ¡Õ¶Õ¡Õ¬ ÖÕ¡Õ¶ÖÕ«Õ¶:</translation>
@@ -36,7 +37,7 @@
<ph name="PROXIES_TITLE" />
&gt;
LAN-Õ« Õ¯Õ¡Ö€Õ£Õ¡Õ¾Õ¸Ö€Õ¸Ö‚Õ´Õ¶Õ¥Ö€
- և ապանշեք «Օգտագործել միջնորդ սերվեր LAN-ի համար»:</translation>
+ և ապանշեք «Օգտագործել պրոքսի սերվեր LAN-ի համար»:</translation>
<translation id="7230956101631259640">Ô´Õ¸Ö‚Ö„ Õ¤Õ«Õ¿Õ¸Ö‚Õ´ Õ¥Ö„ Chrome-Õ« Õ¡Õ¶Õ¾Õ¿Õ¡Õ¶Õ£ Õ§Õ»</translation>
<translation id="8187289872471304532">Ô±Õ¶ÖÕ¥Ö„
Applications &gt; System Preferences &gt; Network &gt; Advanced &gt; Proxies
diff --git a/chromium/components/strings/components_google_chrome_strings_id.xtb b/chromium/components/strings/components_google_chrome_strings_id.xtb
index 9a97f597e98..51b75e02754 100644
--- a/chromium/components/strings/components_google_chrome_strings_id.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_id.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">Perubahan akan diterapkan saat berikutnya Anda meluncurkan kembali Chrome.</translation>
<translation id="2447485272386224171">Chrome terwujud karena adanya project open source <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> dan <ph name="BEGIN_LINK_OSS" />software open source<ph name="END_LINK_OSS" /> lainnya.</translation>
<translation id="2588322182880276190">Logo Chrome</translation>
+<translation id="290720624583273918">CloudReady 2.0 belum menyelesaikan penyiapan awal.</translation>
<translation id="3444832043240812445">Halaman ini hanya menunjukkan informasi tentang kondisi ngadat terkini jika Anda <ph name="BEGIN_LINK" />mengaktifkan pelaporan kondisi ngadat<ph name="END_LINK" />.</translation>
<translation id="3875312571075912821">Izinkan Chrome untuk mengakses jaringan di setelan firewall atau antivirus
Anda.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_is.xtb b/chromium/components/strings/components_google_chrome_strings_is.xtb
index 1592f863656..0702be52d67 100644
--- a/chromium/components/strings/components_google_chrome_strings_is.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_is.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">Breytingarnar taka gildi næst þegar þú endurræsir Chrome.</translation>
<translation id="2447485272386224171">Opna kóðaverkefnið <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> og annar <ph name="BEGIN_LINK_OSS" />opinn hugbúnaður<ph name="END_LINK_OSS" /> gerir Chrome mögulegt.</translation>
<translation id="2588322182880276190">Chrome lógóið</translation>
+<translation id="290720624583273918">CloudReady 2.0 hefur ekki lokið frumuppsetningu.</translation>
<translation id="3444832043240812445">Þessi síða sýnir aðeins upplýsingar um nýleg hrun ef þú <ph name="BEGIN_LINK" />kveikir á tilkynningum um hrun<ph name="END_LINK" />.</translation>
<translation id="3875312571075912821">Veittu Chrome aðgang að netkerfinu þínu í eldveggsstillingunum þínum eða
vírusvarnarstillingunum.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_it.xtb b/chromium/components/strings/components_google_chrome_strings_it.xtb
index 4b52023f76c..d684da34a9d 100644
--- a/chromium/components/strings/components_google_chrome_strings_it.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_it.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">Le modifiche verranno applicate al prossimo riavvio di Chrome.</translation>
<translation id="2447485272386224171">La realizzazione di Chrome è stata possibile grazie al progetto open source <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> e ad altri <ph name="BEGIN_LINK_OSS" />software open source<ph name="END_LINK_OSS" />.</translation>
<translation id="2588322182880276190">Logo di Chrome</translation>
+<translation id="290720624583273918">La configurazione iniziale di CloudReady 2.0 non è stata completata.</translation>
<translation id="3444832043240812445">Questa pagina mostra solo informazioni sugli arresti anomali recenti se <ph name="BEGIN_LINK" />attivi la segnalazione degli arresti anomali<ph name="END_LINK" />.</translation>
<translation id="3875312571075912821">Consenti a Chrome di accedere alla rete nelle impostazioni del firewall o del software
antivirus.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_iw.xtb b/chromium/components/strings/components_google_chrome_strings_iw.xtb
index eb947954005..978d75ed370 100644
--- a/chromium/components/strings/components_google_chrome_strings_iw.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_iw.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">â€×”×©×™× ×•×™×™× ×™×™×›× ×¡×• לתוקף ×‘×¤×¢× ×”×‘××” שדפדפן Chrome יופעל מחדש.</translation>
<translation id="2447485272386224171">â€Chrome ×§×™×™× ×”×•×“×•×ª לפרויקט הקוד הפתוח של <ph name="BEGIN_LINK_CHROMIUM" /> Chromium<ph name="END_LINK_CHROMIUM" /> ו<ph name="BEGIN_LINK_OSS" />תוכנות קוד פתוח<ph name="END_LINK_OSS" /> נוספות.</translation>
<translation id="2588322182880276190">â€×”לוגו של Chrome</translation>
+<translation id="290720624583273918">â€×”הגדרה הר×שונית של CloudReady 2.0 ×œ× ×”×•×©×œ×ž×”.</translation>
<translation id="3444832043240812445">דף ×–×” מציג מידע על הקריסות ×”×חרונות בלבד ×× <ph name="BEGIN_LINK" />תפעיל ×ת ×פשרות הדיווח על קריסות<ph name="END_LINK" />.</translation>
<translation id="3875312571075912821">â€×›×“××™ לשנות ×ת הגדרות חומת ×”×ש ×ו ×”×נטי-וירוס כדי ל×פשר ל-Chrome לגשת לרשת.</translation>
<translation id="4010643444566880169">â€×ž×¢×¨×›×ª ההפעלה של Chrome ×œ× ×”×©×œ×™×ž×” ×ת ההגדרה הר×שונית.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_ja.xtb b/chromium/components/strings/components_google_chrome_strings_ja.xtb
index a4074c27990..0d820311ea8 100644
--- a/chromium/components/strings/components_google_chrome_strings_ja.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_ja.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">変更内容ã¯æ¬¡ã« Chrome ã‚’å†èµ·å‹•ã—ãŸã¨ãã«æœ‰åŠ¹ã«ãªã‚Šã¾ã™ã€‚</translation>
<translation id="2447485272386224171">Chrome ã¯ã‚ªãƒ¼ãƒ—ンソース プロジェクト <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> ã‚„ãã®ä»–ã®<ph name="BEGIN_LINK_OSS" />オープンソース ソフトウェア<ph name="END_LINK_OSS" />ã«ã‚ˆã£ã¦å®Ÿç¾ã—ã¾ã—ãŸã€‚</translation>
<translation id="2588322182880276190">Chrome ロゴ</translation>
+<translation id="290720624583273918">CloudReady 2.0 ã¯åˆæœŸè¨­å®šãŒå®Œäº†ã—ã¦ã„ã¾ã›ã‚“。</translation>
<translation id="3444832043240812445"><ph name="BEGIN_LINK" />障害レãƒãƒ¼ãƒˆã‚’有効<ph name="END_LINK" />ã«ã—ãŸå ´åˆã«ã®ã¿ã€ã“ã®ãƒšãƒ¼ã‚¸ã«æœ€è¿‘ã®éšœå®³æƒ…å ±ãŒè¡¨ç¤ºã•ã‚Œã¾ã™ã€‚</translation>
<translation id="3875312571075912821">ファイアウォールやウイルス対策ã®è¨­å®šã§ã€Chrome ã‹ã‚‰ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ã‚’
許å¯ã—ã¾ã™ã€‚</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_ka.xtb b/chromium/components/strings/components_google_chrome_strings_ka.xtb
index 9b3b7f427cd..dd1a464b26c 100644
--- a/chromium/components/strings/components_google_chrome_strings_ka.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_ka.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">თქვენი ცვლილებები Chrome-ის ხელáƒáƒ®áƒšáƒ გáƒáƒ¨áƒ•áƒ”ბის შემდეგ შევრძáƒáƒšáƒáƒ¨áƒ˜.</translation>
<translation id="2447485272386224171">Chrome áƒáƒ áƒ¡áƒ”ბáƒáƒ‘ს <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> ღირწყáƒáƒ áƒáƒ¡ პრáƒáƒ”ქტის დრსხვრ<ph name="BEGIN_LINK_OSS" />ღირწყáƒáƒ áƒáƒ¡ პრáƒáƒ’რáƒáƒ›áƒ£áƒšáƒ˜ უზრუნველყáƒáƒ¤áƒ˜áƒ¡<ph name="END_LINK_OSS" /> წყáƒáƒšáƒáƒ‘ით.</translation>
<translation id="2588322182880276190">Chrome-ის ლáƒáƒ’áƒ</translation>
+<translation id="290720624583273918">CloudReady 2.0-ის სáƒáƒ¬áƒ§áƒ˜áƒ¡áƒ˜ დáƒáƒ§áƒ”ნებრáƒáƒ  დáƒáƒ¡áƒ áƒ£áƒšáƒ”ბულáƒ.</translation>
<translation id="3444832043240812445">áƒáƒ› გვერდზე ნáƒáƒ©áƒ•áƒ”ნები იქნებრინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ მხáƒáƒšáƒáƒ“ ბáƒáƒšáƒ შეცდáƒáƒ›áƒ”ბის შესáƒáƒ®áƒ”ბ, თუ თქვენ <ph name="BEGIN_LINK" />ჩáƒáƒ áƒ—áƒáƒ•áƒ— შეცდáƒáƒ›áƒ”ბის შესáƒáƒ®áƒ”ბ მáƒáƒ®áƒ¡áƒ”ნებების გáƒáƒ’ზáƒáƒ•áƒœáƒáƒ¡<ph name="END_LINK" />.</translation>
<translation id="3875312571075912821">თქვენი ქსელის დáƒáƒªáƒ•áƒ˜áƒ¡ áƒáƒœ áƒáƒœáƒ¢áƒ˜áƒ•áƒ˜áƒ áƒ£áƒ¡áƒ˜áƒ¡ პáƒáƒ áƒáƒ›áƒ”ტრებში, მიეცით Chrome-ს ქსელზე წვდáƒáƒ›áƒ˜áƒ¡
უფლებáƒ.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_kk.xtb b/chromium/components/strings/components_google_chrome_strings_kk.xtb
index dd02767340a..d521989d505 100644
--- a/chromium/components/strings/components_google_chrome_strings_kk.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_kk.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">Өзгертулеріңіз Chrome келеÑіде қайта Ñ–Ñке қоÑылғанда күшіне енеді.</translation>
<translation id="2447485272386224171">Chrome браузері <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> ашық кодты бағдарлама жобаÑÑ‹ мен баÑқа <ph name="BEGIN_LINK_OSS" />ашық кодты бағдарлама<ph name="END_LINK_OSS" /> негізінде жаÑалды.</translation>
<translation id="2588322182880276190">Chrome логотипі</translation>
+<translation id="290720624583273918">CloudReady 2.0 операциÑлық жүйеÑÑ– өз баÑтапқы реттеуін аÑқтамады.</translation>
<translation id="3444832043240812445">Бұл бет <ph name="BEGIN_LINK" />Ð¶Ð°Ò£Ñ‹Ð»Ñ‹Ñ Ñ‚ÑƒÑ€Ð°Ð»Ñ‹ хабарлау<ph name="END_LINK" /> мүмкіндігін Ñ–Ñке қоÑÑаңыз, Ñоңғы жаңылыÑтарыңыздағы ақпаратты ғана көрÑетеді.</translation>
<translation id="3875312571075912821">БрандмауÑÑ€ немеÑе Ð°Ð½Ñ‚Ð¸Ð²Ð¸Ñ€ÑƒÑ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ð»ÐµÑ€Ñ–Ð½Ð´Ðµ Chrome жүйеÑіне
желіге кіруге Ñ€Ò±Ò›Ñат беріңіз.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_km.xtb b/chromium/components/strings/components_google_chrome_strings_km.xtb
index 2a691b70c56..190c3a6c87c 100644
--- a/chromium/components/strings/components_google_chrome_strings_km.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_km.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">ការផ្លាស់ប្ដូរ​របស់អ្នក​នឹងមានប្រសិទ្ធភាព​នៅពáŸáž›ážŠáŸ‚ល​អ្នកចាប់ផ្ដើម Chrome ឡើងវិញ​លើកក្រោយ។</translation>
<translation id="2447485272386224171">Chrome អាចបង្កើážâ€‹áž¡áž¾áž„បាន​ដោយគម្រោង​កូដចំហ​របស់ <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> áž“áž·áž„<ph name="BEGIN_LINK_OSS" />កម្មវិធី​កូដចំហ<ph name="END_LINK_OSS" />ផ្សáŸáž„ទៀážáŸ”</translation>
<translation id="2588322182880276190">និមិážáŸ’ážážŸáž‰áŸ’ញា Chrome</translation>
+<translation id="290720624583273918">CloudReady 2.0 មិនបានបញ្ចប់ការរៀបចំដំបូងរបស់វាទáŸáŸ”</translation>
<translation id="3444832043240812445">ទំពáŸážšáž“áŸáŸ‡áž”ង្ហាញážáŸ‚áž–áŸážáŸŒáž˜áž¶áž“ការគាំងកន្លងទៅážáŸ’មីៗរបស់អ្នកážáŸ‚ប៉ុណ្ណោះ ប្រសិនបើអ្នក <ph name="BEGIN_LINK" />បើកដំណើរការការរាយការណáŸáž€áž¶ážšáž‚ាំង<ph name="END_LINK" />។</translation>
<translation id="3875312571075912821">អនុញ្ញាážáž²áŸ’áž™ Chrome ចូលប្រើបណ្ážáž¶áž‰áž“ៅក្នុងការកំណážáŸ‹ firewall ឬកម្មវិធីកម្ចាážáŸ‹áž˜áŸážšáŸ„áž‚
diff --git a/chromium/components/strings/components_google_chrome_strings_kn.xtb b/chromium/components/strings/components_google_chrome_strings_kn.xtb
index 57b0eabb062..be85d64374c 100644
--- a/chromium/components/strings/components_google_chrome_strings_kn.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_kn.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">ನೀವೠಮà³à²‚ದಿನ ಬಾರಿ Chrome ಅನà³à²¨à³ ಮರà³à²ªà³à²°à²¾à²°à²‚ಭಿಸಿದಾಗ ನಿಮà³à²® ಬದಲಾವಣೆಗಳೠಕಾರà³à²¯à²—ತಗೊಳà³à²³à³à²¤à³à²¤à²µà³†.</translation>
<translation id="2447485272386224171"><ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> ಓಪನೠಸೋರà³à²¸à³ ಪà³à²°à²¾à²œà³†à²•à³à²Ÿà³ ಮತà³à²¤à³ ಇತರ <ph name="BEGIN_LINK_OSS" />ಓಪನೠಸೋರà³à²¸à³ ಸಾಫà³à²Ÿà³â€Œà²µà³‡à²°à³â€Œà²¨à²¿à²‚ದ<ph name="END_LINK_OSS" /> Chrome ಅನà³à²¨à³ ಸಾಕಾರಗೊಳಿಸಲಾಗಿದೆ.</translation>
<translation id="2588322182880276190">Chrome ಲೋಗೊ</translation>
+<translation id="290720624583273918">CloudReady 2.0 ತನà³à²¨ ಆರಂಭಿಕ ಸೆಟಪೠಪೂರà³à²£à²—ೊಳಿಸಿಲà³à²².</translation>
<translation id="3444832043240812445">ನೀವೠ<ph name="BEGIN_LINK" />ಕà³à²°â€à³à²¯à²¾à²¶à³â€Œâ€Œ ವರದಿಮಾಡà³à²µà²¿à²•à³†à²¯à²¨à³à²¨à³ ಸಕà³à²°à²¿à²¯à²—ೊಳಿಸಿದರೆ<ph name="END_LINK" /> ನಿಮà³à²® ಇತà³à²¤à³€à²šà²¿à²¨ ಕà³à²°â€à³à²¯à²¾à²¶à³â€Œà²—ಳಲà³à²²à²¿ ಮಾಹಿತಿಯನà³à²¨à³ ಈ ಪà³à²Ÿ ತೋರಿಸà³à²¤à³à²¤à²¦à³†.</translation>
<translation id="3875312571075912821">ನಿಮà³à²® ಫೈರà³â€Œà²µà²¾à²²à³ ಮತà³à²¤à³ ಆಂಟಿವೈರಸೠಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳಲà³à²²à²¿ ನೆಟà³â€Œà²µà²°à³à²•à³ ಪà³à²°à²µà³‡à²¶à²¿à²¸à²²à³
Chrome ಗೆ ಅನà³à²®à²¤à²¿à²¸à²¿.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_ko.xtb b/chromium/components/strings/components_google_chrome_strings_ko.xtb
index 6b0012e1d86..fa6921b4eba 100644
--- a/chromium/components/strings/components_google_chrome_strings_ko.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_ko.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">ë³€ê²½ì‚¬í•­ì€ ë‹¤ìŒì— Chromeì„ ë‹¤ì‹œ 시작할 ë•Œ ì ìš©ë©ë‹ˆë‹¤.</translation>
<translation id="2447485272386224171">Chromeì€ <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> 오픈소스 프로ì íŠ¸ë¥¼ 비롯한 여러 <ph name="BEGIN_LINK_OSS" />오픈소스 소프트웨어<ph name="END_LINK_OSS" />를 기반으로 ì œìž‘ëœ ë¸Œë¼ìš°ì €ìž…니다</translation>
<translation id="2588322182880276190">Chrome 로고</translation>
+<translation id="290720624583273918">CloudReady 2.0ì—ì„œ 초기 ì„¤ì •ì„ ì™„ë£Œí•˜ì§€ 않았습니다.</translation>
<translation id="3444832043240812445"><ph name="BEGIN_LINK" />ë¹„ì •ìƒ ì¢…ë£Œ 보고를 사용<ph name="END_LINK" />하면 최근 ë¹„ì •ìƒ ì¢…ë£Œì— ëŒ€í•œ 정보만 ì´ íŽ˜ì´ì§€ì— 표시ë©ë‹ˆë‹¤.</translation>
<translation id="3875312571075912821">Chromeì´ ë°©í™”ë²½ì´ë‚˜ 백신 í”„ë¡œê·¸ëž¨ì´ ì„¤ì •ëœ
네트워í¬ì— 액세스할 수 있ë„ë¡ í—ˆìš©í•©ë‹ˆë‹¤.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_ky.xtb b/chromium/components/strings/components_google_chrome_strings_ky.xtb
index 7d64e9fe7a3..f7284719d3a 100644
--- a/chromium/components/strings/components_google_chrome_strings_ky.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_ky.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">Өзгөртүүлөрүңүз Chrome кийинки жолу кайра ишке киргизилгенде күчүнө кирет.</translation>
<translation id="2447485272386224171">Chrome ÑерепчиÑи <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> ачык реÑÑƒÑ€Ñ Ð´Ð¾Ð»Ð±Ð¾Ð¾Ñ€Ñƒ жана башка <ph name="BEGIN_LINK_OSS" />ачык булак программаÑÑ‹<ph name="END_LINK_OSS" /> аркылуу түзүлдү.</translation>
<translation id="2588322182880276190">Chrome логотиби</translation>
+<translation id="290720624583273918">CloudReady 2.0 алгачкы жөндөөÑүн аÑгына чыгарган жок.</translation>
<translation id="3444832043240812445"><ph name="BEGIN_LINK" />Кыйроолор жөнүндө кабар берүү мүмкүнчүлүгү иштетилгенде<ph name="END_LINK" />, бул бет акыркы кыйроолор жөнүндө маалыматты гана көрÑÓ©Ñ‚Ó©Ñ‚.</translation>
<translation id="3875312571075912821">Chrome'го коргоо ÑиÑтемаÑында тармакка же Ð°Ð½Ñ‚Ð¸Ð²Ð¸Ñ€ÑƒÑ Ð¶Ó©Ð½Ð´Ó©Ó©Ð»Ó©Ñ€Ò¯Ð½Ó© кирүүгө
урукÑат бериңиз.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_lo.xtb b/chromium/components/strings/components_google_chrome_strings_lo.xtb
index f4ad6c63e64..5a56e1f66da 100644
--- a/chromium/components/strings/components_google_chrome_strings_lo.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_lo.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">àºàº²àº™àº›à»ˆàº½àº™à»àº›àº‡àº‚ອງທ່ານຈະມີຜົນເທື່ອຕà»à»ˆà»„ປທີ່ທ່ານເລີ່ມເປີດໃຊ້ Chrome ໃà»à»ˆ.</translation>
<translation id="2447485272386224171">Chrome ເàºàºµàº”ຂຶ້ນໄດ້ໂດàºà»‚ຄງàºàº²àº™à»‚ອເພນຊອດ <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> à»àº¥àº° <ph name="BEGIN_LINK_OSS" />ຊອບà»àº§à»‚ອເພນຊອດ<ph name="END_LINK_OSS" /> ອື່ນໆ.</translation>
<translation id="2588322182880276190">ໂລໂàºà»ˆàº‚ອງ Chrome</translation>
+<translation id="290720624583273918">CloudReady 2.0 àºàº±àº‡àºšà»à»ˆà»„ດ້ສຳເລັດàºàº²àº™àº•àº±à»‰àº‡àº„່າເບື້ອງຕົ້ນຂອງມັນເທື່ອ.</translation>
<translation id="3444832043240812445">ໜ້ານີ້ພຽງà»àº•à»ˆàºªàº°à»àº”ງຂà»à»‰àº¡àº¹àº™àºà»ˆàº½àº§â€‹àºàº±àºšâ€‹àºàº²àº™â€‹àº‚ັດຂ້ອງ​ເມື່ອ​ບà»à»ˆâ€‹àº”ົນ​ມາ​ນີ້ຂອງທ່ານ ຖ້າທ່ານ <ph name="BEGIN_LINK" />ເປີດໃຊ້ງານàºàº²àº™àº¥àº²àºàº‡àº²àº™àºàº²àº™â€‹àº‚ັດຂ້ອງ<ph name="END_LINK" />.</translation>
<translation id="3875312571075912821">ອະນຸàºàº²àº”ໃຫ້ Chrome ເຂົ້າເຖິງເຄືອຂ່າàºà»ƒàº™àºàº²àº™àº•àº±à»‰àº‡àº„່າໄຟຣ໌ວ໠ຫຼື ໂປຣà»àºàº£àº¡
ຕ້ານໄວຣັສຂອງທ່ານ.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_lt.xtb b/chromium/components/strings/components_google_chrome_strings_lt.xtb
index 1a9370e1ffa..f683dc0805e 100644
--- a/chromium/components/strings/components_google_chrome_strings_lt.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_lt.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">Pakeitimai įsigalios kitą kartą iš naujo paleidus „Chrome“.</translation>
<translation id="2447485272386224171">„Chrome“ pasiekiama naudojant <ph name="BEGIN_LINK_CHROMIUM" />„Chromium“<ph name="END_LINK_CHROMIUM" /> atvirojo šaltinio projektą ir kitą <ph name="BEGIN_LINK_OSS" />atvirojo šaltinio programinę įrangą<ph name="END_LINK_OSS" />.</translation>
<translation id="2588322182880276190">„Chrome“ logotipas</translation>
+<translation id="290720624583273918">2.0 versijos „CloudReady“ neužbaigė šios pradinės sąrankos.</translation>
<translation id="3444832043240812445">Å iame puslapyje rodoma informacija apie paskutines strigtis, jei <ph name="BEGIN_LINK" />įgalinote strigÄių ataskaitų teikimÄ…<ph name="END_LINK" />.</translation>
<translation id="3875312571075912821">Leiskite „Chrome“ pasiekti tinklą užkardos arba antivirusinės
programos nustatymuose.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_lv.xtb b/chromium/components/strings/components_google_chrome_strings_lv.xtb
index c4e2afba30f..047f6c51ef3 100644
--- a/chromium/components/strings/components_google_chrome_strings_lv.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_lv.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">JÅ«su izmaiņas stÄsies spÄ“kÄ nÄkamajÄ reizÄ“, kad atkÄrtoti palaidÄ«siet pÄrlÅ«ku Chrome.</translation>
<translation id="2447485272386224171">PÄrlÅ«ku Chrome nodroÅ¡ina <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> atklÄtÄ pirmkoda projekts un cita <ph name="BEGIN_LINK_OSS" />atklÄtÄ pirmkoda programmatÅ«ra<ph name="END_LINK_OSS" />.</translation>
<translation id="2588322182880276190">Chrome logotips</translation>
+<translation id="290720624583273918">OperÄ“tÄjsistÄ“mas CloudReady 2.0 sÄkotnÄ“jÄ iestatÄ«Å¡ana nav pabeigta.</translation>
<translation id="3444832043240812445">Å ajÄ lapÄ tiek parÄdÄ«ta tikai informÄcija par pÄ“dÄ“jÄ laika avÄrijÄm, ja <ph name="BEGIN_LINK" />iespÄ“jojat avÄriju pÄrskatu izveidi<ph name="END_LINK" />.</translation>
<translation id="3875312571075912821">UgunsmÅ«ra vai antivÄ«rusu programmas iestatÄ«jumu maiņa, lai atļautu pÄrlÅ«kam Chrome piekļūt tÄ«klam.</translation>
<translation id="4010643444566880169">OperÄ“tÄjsistÄ“mÄ Chrome OS nav izpildÄ«ta sÄkotnÄ“jÄ iestatÄ«Å¡ana.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_mk.xtb b/chromium/components/strings/components_google_chrome_strings_mk.xtb
index 71ed5eebdb3..d3c44881fd1 100644
--- a/chromium/components/strings/components_google_chrome_strings_mk.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_mk.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">Вашите промени ќе Ñтапат на Ñила Ñледниот пат кога ќе го реÑтартирате Chrome.</translation>
<translation id="2447485272386224171">Chrome е овозможен од проектот Ñо отворен код <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> и друг <ph name="BEGIN_LINK_OSS" />Ñофтвер Ñо отворен код<ph name="END_LINK_OSS" />.</translation>
<translation id="2588322182880276190">Лого на Chrome</translation>
+<translation id="290720624583273918">CloudReady 2.0 не го завршил првичното поÑтавување.</translation>
<translation id="3444832043240812445">Страницава прикажува Ñамо информации за неодамнешните падови ако <ph name="BEGIN_LINK" />овозможите пријавување падови<ph name="END_LINK" />.</translation>
<translation id="3875312571075912821">Дозволете Chromе да приÑтапи на мрежата во поÑтавките за
заштитен ѕид или антивируÑ.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_ml.xtb b/chromium/components/strings/components_google_chrome_strings_ml.xtb
index 40ae1d903e4..bebb94f7157 100644
--- a/chromium/components/strings/components_google_chrome_strings_ml.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_ml.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">à´…à´Ÿàµà´¤àµà´¤ തവണ Chrome വീണàµà´Ÿàµà´‚ ആരംഭികàµà´•àµà´®àµà´ªàµ‹àµ¾ നിങàµà´™à´³àµà´Ÿàµ† മാറàµà´±à´™àµà´™àµ¾ à´ªàµà´°à´¾à´¬à´²àµà´¯à´¤àµà´¤à´¿àµ½ വരàµà´‚.</translation>
<translation id="2447485272386224171"><ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> à´“à´ªàµà´ªà´£àµâ€ സോഴàµà´¸àµ à´ªàµà´°àµ‹à´œà´•àµâ€Œà´Ÿàµà´‚ മറàµà´±àµ <ph name="BEGIN_LINK_OSS" />à´“à´ªàµà´ªàµº സോഴàµà´¸àµ സോഫàµà´±àµà´±àµâ€Œà´µàµ†à´¯à´±àµà´‚<ph name="END_LINK_OSS" /> ഉപയോഗിചàµà´šà´¾à´£àµ Chrome സാധàµà´¯à´®à´¾à´•àµà´•à´¿à´¯à´¤àµ.</translation>
<translation id="2588322182880276190">Chrome ലോഗോ</translation>
+<translation id="290720624583273918">CloudReady 2.0 അതിനàµà´±àµ† à´ªàµà´°à´¾à´°à´‚à´­ സജàµà´œàµ€à´•à´°à´£à´‚ പൂർതàµà´¤à´¿à´¯à´¾à´•àµà´•à´¿à´¯à´¿à´Ÿàµà´Ÿà´¿à´²àµà´².</translation>
<translation id="3444832043240812445">നിങàµà´™à´³àµâ€ <ph name="BEGIN_LINK" />à´•àµà´°à´¾à´·àµ റിപàµà´ªàµ‹à´°àµâ€à´Ÿàµà´Ÿà´¿à´‚ഗൠപàµà´°à´µàµ¼à´¤àµà´¤à´¨à´•àµà´·à´®à´®à´¾à´•àµà´•àµà´•à´¯à´¾à´£àµ†à´™àµà´•à´¿àµ½<ph name="END_LINK" /> നിങàµà´™à´³àµà´Ÿàµ† സമീപകാല à´•àµà´°à´¾à´·àµà´•à´³à´¿à´²àµ† വിവരങàµà´™à´³àµâ€ മാതàµà´°à´‚ à´ˆ പേജൠകാണികàµà´•àµà´¨àµà´¨àµ.</translation>
<translation id="3875312571075912821">നിങàµà´™à´³àµà´Ÿàµ† ഫയർവാളിലെയോ ആനàµà´±à´¿à´µàµˆà´±à´¸àµ à´•àµà´°à´®àµ€à´•à´°à´£à´¤àµà´¤à´¿à´²àµ†à´¯àµ‹ നെറàµà´±àµâ€Œà´µàµ¼à´•àµà´•àµ ആകàµâ€Œà´¸à´¸àµ
ചെയàµà´¯à´¾àµ» Chrome-നെ à´…à´¨àµà´µà´¦à´¿à´•àµà´•àµà´•.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_mn.xtb b/chromium/components/strings/components_google_chrome_strings_mn.xtb
index f7ac2642cbb..30b86e95e91 100644
--- a/chromium/components/strings/components_google_chrome_strings_mn.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_mn.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">Таныг дараагийн удаа Chrome-г дахин ачаалахад өөрчлөлт тань Ñ…ÑÑ€ÑгжинÑ.</translation>
<translation id="2447485272386224171">Chrome-г <ph name="BEGIN_LINK_CHROMIUM" />Chromium-н<ph name="END_LINK_CHROMIUM" /> нÑÑлттÑй ÑÑ… кодын Ñ‚Ó©Ñөл болон буÑад <ph name="BEGIN_LINK_OSS" />нÑÑлттÑй ÑÑ… кодын программ хангамжаар<ph name="END_LINK_OSS" /> боломжтой болгоÑон.</translation>
<translation id="2588322182880276190">Chrome лого</translation>
+<translation id="290720624583273918">CloudReady 2.0 нь анхны тохируулгыг дууÑгаагүй байна.</translation>
<translation id="3444832043240812445">Ð¥ÑÑ€Ñв та <ph name="BEGIN_LINK" /> ÑвдрÑл гÑмтлийн тайланг<ph name="END_LINK" /> идÑвхжүүлбÑл ÑÐ½Ñ Ñ…ÑƒÑƒÐ´Ð°Ñ Ð½ÑŒ таны хамгийн Ñүүлийн ÑвдрÑл гÑмтлийн мÑдÑÑллийг л харуулна.</translation>
<translation id="3875312571075912821">Chrome-г галт хана ÑÑвÑл вируÑны ÑÑÑ€Ñг программын тохиргоонд хандахыг 
зөвшөөрөх.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_mr.xtb b/chromium/components/strings/components_google_chrome_strings_mr.xtb
index adbc34939c2..6e48e398206 100644
--- a/chromium/components/strings/components_google_chrome_strings_mr.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_mr.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">पà¥à¤¢à¥€à¤² वेळी तà¥à¤®à¥à¤¹à¥€ Chrome पà¥à¤¨à¥à¤¹à¤¾ लाà¤à¤š केलà¥à¤¯à¤¾à¤¨à¤‚तर तà¥à¤®à¤šà¥‡ बदल लागू होतील.</translation>
<translation id="2447485272386224171"><ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> मà¥à¤•à¥à¤¤-सà¥à¤°à¥‹à¤¤ पà¥à¤°à¥‹à¤œà¥‡à¤•à¥à¤Ÿ आणि इतर <ph name="BEGIN_LINK_OSS" />मà¥à¤•à¥à¤¤ सà¥à¤°à¥‹à¤¤ सॉफà¥à¤Ÿà¤µà¥‡à¤…र<ph name="END_LINK_OSS" /> दà¥à¤µà¤¾à¤°à¥‡ Chrome ची निरà¥à¤®à¤¿à¤¤à¥€ करणे शकà¥à¤¯ à¤à¤¾à¤²à¥‡.</translation>
<translation id="2588322182880276190">Chrome लोगो</translation>
+<translation id="290720624583273918">CloudReady 2.0 ने सà¥à¤µà¤¤à¤ƒà¤šà¤¾ सà¥à¤°à¥à¤µà¤¾à¤¤à¥€à¤šà¤¾ सेटअप पूरà¥à¤£ केला नाही.</translation>
<translation id="3444832043240812445">हे पेज तà¥à¤®à¥à¤¹à¥€ <ph name="BEGIN_LINK" />कॅशे अहवाल सà¥à¤°à¥‚<ph name="END_LINK" /> केलà¥à¤¯à¤¾à¤¸ केवळ तà¥à¤®à¥à¤¹à¤¾à¤²à¤¾ अलीकडील कà¥à¤°à¥…शची माहिती दाखवते.</translation>
<translation id="3875312571075912821">तà¥à¤®à¤šà¥à¤¯à¤¾ फायरवॉल किंवा अà¤à¤Ÿà¥€à¤µà¥à¤¹à¤¾à¤¯à¤°à¤¸ सेटिंगà¥à¤œà¤®à¤§à¥€à¤² नेटवरà¥à¤• ॲकà¥à¤¸à¥‡à¤¸ करणà¥à¤¯à¤¾à¤¸
Chrome ला परवानगी दà¥à¤¯à¤¾.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_ms.xtb b/chromium/components/strings/components_google_chrome_strings_ms.xtb
index 613f958a699..abd98297764 100644
--- a/chromium/components/strings/components_google_chrome_strings_ms.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_ms.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">Perubahan anda akan dilaksanakan apabila anda melancarkan semula Chrome selepas ini.</translation>
<translation id="2447485272386224171">Chrome berjaya dilaksanakan melalui projek sumber terbuka <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> dan <ph name="BEGIN_LINK_OSS" />perisian sumber terbuka<ph name="END_LINK_OSS" /> yang lain.</translation>
<translation id="2588322182880276190">Logo Chrome</translation>
+<translation id="290720624583273918">CloudReady 2.0 belum menyelesaikan persediaan awal.</translation>
<translation id="3444832043240812445">Halaman ini hanya menunjukkan maklumat mengenai nahas terkini anda jika anda <ph name="BEGIN_LINK" />mendayakan laporan nahas<ph name="END_LINK" />.</translation>
<translation id="3875312571075912821">Benarkan Chrome mengakses rangkaian di tetapan tembok api atau
antivirus anda.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_my.xtb b/chromium/components/strings/components_google_chrome_strings_my.xtb
index f762a30c71d..70349ba4a7b 100644
--- a/chromium/components/strings/components_google_chrome_strings_my.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_my.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">သင်áအပြောင်းအလဲများသည် Chromium ကို နောက်á€á€…်ကြိမ် ပြန်ဖွင့်á€á€»á€­á€”်á€á€½á€„် သက်ရောက်မှုရှိပါမည်á‹</translation>
<translation id="2447485272386224171"><ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> အá€á€™á€²á€· ရင်းမြစ် စီမံကိန်းနှင့် အá€á€¼á€¬á€¸ <ph name="BEGIN_LINK_OSS" />အá€á€™á€²á€· ရင်းမြစ် ဆော့ဖ်á€á€²<ph name="END_LINK_OSS" /> á€á€­á€¯á€·á€€ Chrome ကို ထုá€á€ºá€œá€¯á€•á€ºá€‘ားသည်á‹</translation>
<translation id="2588322182880276190">Chrome လိုဂို</translation>
+<translation id="290720624583273918">CloudReady 2.0 က áŽá€„်းá ကနဦးစနစ်ထည့်သွင်းမှုကို အပြီးသá€á€ºá€™á€‘ားပါá‹</translation>
<translation id="3444832043240812445">အကယ်áသင် <ph name="BEGIN_LINK" /> ပျက်စီးမှု အစီရင်á€á€¶á€á€»á€€á€º <ph name="END_LINK" /> ဖွင့်ထားလျှင် ဤစာမျက်နှာသည် မကြာသေးá€á€„်က ပျက်စီးမှု အá€á€»á€€á€ºá€œá€€á€ºá€™á€»á€¬á€¸á€€á€­á€¯á€žá€¬ ပြသည်á‹</translation>
<translation id="3875312571075912821">သင့် Firewall သို့မဟုá€á€º ဗိုင်းရပ်စ်á€á€¯á€á€¶á€…နစ် ဆက်á€á€„်များအá€á€½á€„်း ကွန်ရက်အသုံးပြုရန် Chrome ကိုá€á€½á€„့်ပြုပါá‹</translation>
<translation id="4010643444566880169">Chrome OS သည်áŽá€„်းá ကနဦးá€á€•á€ºá€†á€„်မှုကို မပြီးစီးရသေးပါá‹</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_ne.xtb b/chromium/components/strings/components_google_chrome_strings_ne.xtb
index b5f6c71adc8..8a748a46d39 100644
--- a/chromium/components/strings/components_google_chrome_strings_ne.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_ne.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">तपाईंले अरà¥à¤•à¥‹ पटक Chrome खोलà¥à¤¦à¤¾ तपाईंले गरà¥à¤¨à¥à¤­à¤à¤•à¤¾ परिवरà¥à¤¤à¤¨à¤¹à¤°à¥‚ लागू हà¥à¤¨à¥‡ छनà¥à¥¤</translation>
<translation id="2447485272386224171"><ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> खà¥à¤²à¤¾ सà¥à¤°à¥‹à¤¤à¤•à¥‹ परियोजना र अनà¥à¤¯ <ph name="BEGIN_LINK_OSS" />खà¥à¤²à¤¾ सà¥à¤°à¥‹à¤¤à¤•à¥‹ सफà¥à¤Ÿà¤µà¥‡à¤¯à¤°<ph name="END_LINK_OSS" /> पà¥à¤°à¤¯à¥‹à¤— गरी Chrome निरà¥à¤®à¤¾à¤£ गरिà¤à¤•à¥‹ हो।</translation>
<translation id="2588322182880276190">Chrome चिनà¥à¤¹</translation>
+<translation id="290720624583273918">CloudReady २.० ले आफà¥à¤¨à¥‹ पà¥à¤°à¤¾à¤°à¤®à¥à¤­à¤¿à¤• सेटअप पूरा गरेको छैन।</translation>
<translation id="3444832043240812445">यदि तपाइà¤à¤²à¥‡ <ph name="BEGIN_LINK" />कà¥à¤°à¤¯à¤¾à¤¸ पà¥à¤°à¤¤à¤¿à¤µà¥‡à¤¦à¤¨ सकà¥à¤·à¤®<ph name="END_LINK" /> गरà¥à¤¨à¥à¤­à¤¯à¥‹ बने यस पृषà¥à¤ à¤²à¥‡ तपाइà¤à¤•à¤¾ भरà¥à¤–रैका कà¥à¤°à¤¯à¤¾à¤¸à¤¹à¤°à¥‚मा जानकारी देखाउà¤à¤›à¥¤</translation>
<translation id="3875312571075912821">Chrome लाई आफà¥à¤¨à¥‹ फायरवाल वा à¤à¤¨à¥à¤Ÿà¤¿à¤­à¤¾à¤‡à¤°à¤¸à¤•à¤¾ सेटिङहरूमा
नेटवरà¥à¤•à¤®à¤¾ पहà¥à¤à¤š गरà¥à¤¨à¥‡ अनà¥à¤®à¤¤à¤¿ दिनà¥à¤¹à¥‹à¤¸à¥à¥¤</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_nl.xtb b/chromium/components/strings/components_google_chrome_strings_nl.xtb
index f11a087b3ab..7bd29c3fce6 100644
--- a/chromium/components/strings/components_google_chrome_strings_nl.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_nl.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">Je wijzigingen worden toegepast als je Chrome opnieuw start.</translation>
<translation id="2447485272386224171">Chrome wordt mogelijk gemaakt door het opensource-project <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> en andere <ph name="BEGIN_LINK_OSS" />opensource-software<ph name="END_LINK_OSS" />.</translation>
<translation id="2588322182880276190">Chrome-logo</translation>
+<translation id="290720624583273918">CloudReady 2.0 heeft de eerste instelling nog niet afgerond.</translation>
<translation id="3444832043240812445">Deze pagina bevat alleen informatie over recente crashes als je <ph name="BEGIN_LINK" />crashrapportage aanzet<ph name="END_LINK" />.</translation>
<translation id="3875312571075912821">Sta Chrome toe via je firewall- of antivirusinstellingen het netwerk te gebruiken.</translation>
<translation id="4010643444566880169">De eerste configuratie van Chrome OS is niet voltooid.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_no.xtb b/chromium/components/strings/components_google_chrome_strings_no.xtb
index 90b5db1055d..6e2d1633fcb 100644
--- a/chromium/components/strings/components_google_chrome_strings_no.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_no.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">Endringene dine trer i kraft neste gang du starter Chrome på nytt.</translation>
<translation id="2447485272386224171">Chrome er gjort mulig av åpen kildekode-prosjektet <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> og annen <ph name="BEGIN_LINK_OSS" />programvare med åpen kildekode<ph name="END_LINK_OSS" />.</translation>
<translation id="2588322182880276190">Chrome-logo</translation>
+<translation id="290720624583273918">Den innledende konfigureringen av CloudReady 2.0 er ikke fullført.</translation>
<translation id="3444832043240812445">Denne siden viser kun informasjon om nylige programstopp hvis du <ph name="BEGIN_LINK" />aktiverer rapportering av programstopp<ph name="END_LINK" />.</translation>
<translation id="3875312571075912821">Tillat at Chrome bruker nettverket, i brannmur- eller
antivirusinnstillingene dine.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_or.xtb b/chromium/components/strings/components_google_chrome_strings_or.xtb
index 5656d49d061..c67d9383efd 100644
--- a/chromium/components/strings/components_google_chrome_strings_or.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_or.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">ପରବରà­à¬¤à­à¬¤à­€ ସମୟରେ ଆପଣ Chromeକୠପà­à¬£à¬¿ ଲଞà­à¬š କଲେ ଆପଣ କରିଥିବା ପରିବରà­à¬¤à­à¬¤à¬¨à¬—à­à­œà¬¿à¬• ଲାଗୠହେବ।</translation>
<translation id="2447485272386224171">Chrome <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> ଓପନୠସୋରà­à¬¸ ପà­à¬°à­‹à¬œà­‡à¬•à­à¬Ÿ à¬à¬¬à¬‚ ଅନà­à­Ÿ <ph name="BEGIN_LINK_OSS" />ଓପନୠସୋରà­à¬¸ ସଫà­à¬Ÿà­±à­‡à¬°à­<ph name="END_LINK_OSS" /> ଦà­à¬µà¬¾à¬°à¬¾ ସମà­à¬­à¬¬à¬ªà¬° ହୋଇଛି।</translation>
<translation id="2588322182880276190">Chrome ଲୋଗୋ</translation>
+<translation id="290720624583273918">CloudReady 2.0 à¬à¬¹à¬¾à¬° ପà­à¬°à¬¾à¬°à¬®à­à¬­à¬¿à¬• ସେଟଅପକୠସମà­à¬ªà­‚ରà­à¬£à­à¬£ କରିନାହିà¬à¥¤</translation>
<translation id="3444832043240812445">ଯଦି ଆପଣ <ph name="BEGIN_LINK" />କà­à¬°à¬¾à¬¸à­ ରିପୋରà­à¬Ÿ ସକà­à¬·à¬® କରିବେ<ph name="END_LINK" />, ତେବେ à¬à¬¹à¬¿ ପୃଷà­à¬ à¬¾ କେବଳ ଆପଣଙà­à¬•à¬° ବରà­à¬¤à­à¬¤à¬®à¬¾à¬¨ କà­à¬°à¬¾à¬¸à­â€Œà¬—à­à¬¡à¬¼à¬¿à¬• ଉପରେ ସୂଚନା ଦେଖାଇବ।</translation>
<translation id="3875312571075912821">ଆପଣଙà­à¬•à¬° ଫାୟାରà­â€Œà­±à¬¾à¬²à­â€Œ କିମà­à¬¬à¬¾ ଆଣà­à¬Ÿà¬¿à¬­à¬¾à¬‡à¬°à¬¸à­â€Œ ସେଟିଂସà­â€Œà¬°à­‡ ନେଟà­â€à­±à¬°à­à¬• ଆକà­à¬¸à­‡à¬¸à­â€Œ କରିବାକୠChromeକୠଅନà­à¬®à¬¤à¬¿ ଦିଅନà­à¬¤à­à¥¤</translation>
<translation id="4010643444566880169">Chrome OS à¬à¬¹à¬¾à¬° ପà­à¬°à¬¾à¬°à¬®à­à¬­à¬¿à¬• ସେଟୠଅପୠସମà­à¬ªà­‚ରà­à¬£à­à¬£ କରିପାରିଲା ନାହିà¬à¥¤</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_pa.xtb b/chromium/components/strings/components_google_chrome_strings_pa.xtb
index 545eca22fd8..5f48944959c 100644
--- a/chromium/components/strings/components_google_chrome_strings_pa.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_pa.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">ਤà©à¨¹à¨¾à¨¡à©‡ ਵੱਲੋਂ ਅਗਲੀ ਵਾਰ Chrome ਨੂੰ ਮà©à©œ-ਲਾਂਚ ਕਰਨ 'ਤੇ ਤà©à¨¹à¨¾à¨¡à©€à¨†à¨‚ ਤਬਦੀਲੀਆਂ ਲਾਗੂ ਹੋਣਗੀਆਂ।</translation>
<translation id="2447485272386224171">Chrome ਨੂੰ <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> ਖà©à©±à¨²à©à¨¹à¨¾ ਸਰੋਤ ਪà©à¨°à©‹à¨œà©ˆà¨•à¨Ÿ ਅਤੇ ਹੋਰ <ph name="BEGIN_LINK_OSS" />ਖà©à©±à¨²à©à¨¹à¨¾ ਸਰੋਤ ਸਾਫ਼ਟਵੇਅਰ<ph name="END_LINK_OSS" /> ਵੱਲੋਂ ਸੰਭਵ ਬਣਾਇਆ ਗਿਆ ਹੈ।</translation>
<translation id="2588322182880276190">Chrome ਲੋਗੋ</translation>
+<translation id="290720624583273918">CloudReady 2.0 ਨੇ ਆਪਣਾ ਸ਼à©à¨°à©‚ਆਤੀ ਸੈੱਟਅੱਪ ਪੂਰਾ ਨਹੀਂ ਕੀਤਾ।</translation>
<translation id="3444832043240812445">ਇਹ ਪੰਨਾ ਕੇਵਲ ਤà©à¨¹à¨¾à¨¡à©‡ ਮੌਜੂਦਾ ਕà©à¨°à©ˆà¨¶ ਬਾਰੇ ਜਾਣਕਾਰੀ ਦਿਖਾਉਂਦਾ ਹੈ ਜੇਕਰ ਤà©à¨¸à©€à¨‚ <ph name="BEGIN_LINK" />ਕà©à¨°à©ˆà¨¶ ਰਿਪੋਰਟ ਨੂੰ ਚਾਲੂ<ph name="END_LINK" /> ਕਰਦੇ ਹੋ।</translation>
<translation id="3875312571075912821">Chrome ਨੂੰ ਆਪਣੀਆਂ ਫ਼ਾਇਰਵਾਲ ਜਾਂ à¨à¨‚ਟੀਵਾਇਰਸ ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਨੈੱਟਵਰਕ ਤੱਕ ਪਹà©à©°à¨š ਕਰਨ ਦਿਓ।</translation>
<translation id="4010643444566880169">Chrome OS ਨੇ ਆਪਣਾ ਸ਼à©à¨°à©‚ਆਤੀ ਸੈੱਟਅੱਪ ਮà©à¨•à©°à¨®à¨² ਨਹੀਂ ਕੀਤਾ।</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_pl.xtb b/chromium/components/strings/components_google_chrome_strings_pl.xtb
index e3867ee8280..f970fd5f8d0 100644
--- a/chromium/components/strings/components_google_chrome_strings_pl.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_pl.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">Zmiany zaczną obowiązywać po ponownym uruchomieniu Chrome.</translation>
<translation id="2447485272386224171">Stworzenie przeglądarki Chrome było możliwe dzięki projektowi open source <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> i innym <ph name="BEGIN_LINK_OSS" />programom o otwartym kodzie źródłowym<ph name="END_LINK_OSS" />.</translation>
<translation id="2588322182880276190">Logo Chrome</translation>
+<translation id="290720624583273918">Nie ukończono wstępnej konfiguracji CloudReady 2.0.</translation>
<translation id="3444832043240812445">Ta strona zawiera informacje o ostatnich awariach tylko w przypadku <ph name="BEGIN_LINK" />włączenia funkcji zgłaszania awarii<ph name="END_LINK" />.</translation>
<translation id="3875312571075912821">Zezwalaj Chrome na korzystanie z sieci w ustawieniach zapory sieciowej
lub oprogramowania antywirusowego.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_pt-BR.xtb b/chromium/components/strings/components_google_chrome_strings_pt-BR.xtb
index 102c967d4fa..f898cdad2e9 100644
--- a/chromium/components/strings/components_google_chrome_strings_pt-BR.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_pt-BR.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">As mudanças entrarão em vigor na próxima vez que você reinicializar o Chrome.</translation>
<translation id="2447485272386224171">O Chrome tornou-se possível graças ao projeto de código aberto <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> e outros <ph name="BEGIN_LINK_OSS" />softwares de código aberto<ph name="END_LINK_OSS" />.</translation>
<translation id="2588322182880276190">Logotipo do Google Chrome</translation>
+<translation id="290720624583273918">O CloudReady 2.0 não concluiu a configuração inicial.</translation>
<translation id="3444832043240812445">Esta página mostra apenas informações sobre suas falhas recentes se você <ph name="BEGIN_LINK" />ativar relatórios de erros<ph name="END_LINK" />.</translation>
<translation id="3875312571075912821">Permitir que o Chrome acesse a rede nas configurações do seu
firewall ou antivírus.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_pt-PT.xtb b/chromium/components/strings/components_google_chrome_strings_pt-PT.xtb
index 4d140864b05..4e3fc71ecba 100644
--- a/chromium/components/strings/components_google_chrome_strings_pt-PT.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_pt-PT.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">As alterações terão efeito da próxima vez que voltar a iniciar o Chrome.</translation>
<translation id="2447485272386224171">O Chrome foi concretizado graças ao projeto de código aberto <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" />, assim como a outro <ph name="BEGIN_LINK_OSS" />software de código aberto<ph name="END_LINK_OSS" />.</translation>
<translation id="2588322182880276190">Logótipo do Chrome</translation>
+<translation id="290720624583273918">O CloudReady 2.0 não concluiu a configuração inicial.</translation>
<translation id="3444832043240812445">Esta página mostra informações sobre falhas recentes apenas se <ph name="BEGIN_LINK" />ativar relatórios de falha<ph name="END_LINK" />.</translation>
<translation id="3875312571075912821">Permita que o Chrome aceda à rede nas definições da sua firewall ou
do antívirus.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_ro.xtb b/chromium/components/strings/components_google_chrome_strings_ro.xtb
index 14e5ac43edf..ddab470d400 100644
--- a/chromium/components/strings/components_google_chrome_strings_ro.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_ro.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">Modificările vor intra în vigoare la următoarea relansare a browserului Chrome.</translation>
<translation id="2447485272386224171">Chrome există ca urmare a proiectului open source <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> și al altor <ph name="BEGIN_LINK_OSS" />software-uri open source<ph name="END_LINK_OSS" />.</translation>
<translation id="2588322182880276190">Sigla Chrome</translation>
+<translation id="290720624583273918">CloudReady 2.0 nu a finalizat configurarea inițială.</translation>
<translation id="3444832043240812445">Această pagină afișează informații cu privire la recentele blocări numai dacă <ph name="BEGIN_LINK" />activezi raportarea blocărilor<ph name="END_LINK" />.</translation>
<translation id="3875312571075912821">Din setările pentru firewall sau antivirus, permite browserului Chrome să acceseze
rețeaua.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_ru.xtb b/chromium/components/strings/components_google_chrome_strings_ru.xtb
index 512cc5c8a50..bc9b87961f7 100644
--- a/chromium/components/strings/components_google_chrome_strings_ru.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_ru.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">Ð˜Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð²ÑтупÑÑ‚ в Ñилу поÑле перезапуÑка Chrome.</translation>
<translation id="2447485272386224171">Браузер Chrome Ñоздан на оÑнове проекта <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> и другого <ph name="BEGIN_LINK_OSS" />программного обеÑÐ¿ÐµÑ‡ÐµÐ½Ð¸Ñ Ñ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ñ‹Ð¼ иÑходным кодом<ph name="END_LINK_OSS" />.</translation>
<translation id="2588322182880276190">Логотип Chrome</translation>
+<translation id="290720624583273918">ÐŸÐµÑ€Ð²Ð¾Ð½Ð°Ñ‡Ð°Ð»ÑŒÐ½Ð°Ñ Ð½Ð°Ñтройка CloudReady 2.0 не завершена.</translation>
<translation id="3444832043240812445">Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾ недавних ÑбоÑÑ… отображаетÑÑ Ð½Ð° Ñтой Ñтранице только при <ph name="BEGIN_LINK" />включенной функции отчетов о ÑбоÑÑ…<ph name="END_LINK" />.</translation>
<translation id="3875312571075912821">Разрешите доÑтуп к Ñети Ð´Ð»Ñ Chrome
в наÑтройках брандмауÑра или антивируÑа.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_si.xtb b/chromium/components/strings/components_google_chrome_strings_si.xtb
index f05555a7d73..ed85b081aa4 100644
--- a/chromium/components/strings/components_google_chrome_strings_si.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_si.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">ඔබ ඊළඟ අවස්ථà·à·€à·š Chrome යළි දියත් කරන විට ඔබගේ වෙනස් කිරීම් බලà·à¶­à·Šà¶¸à¶š වනු ඇත.</translation>
<translation id="2447485272386224171">Chrome සෑදීමට à·„à·à¶šà·’ වූයේ <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> විවෘත මූලà·à·à·Šâ€à¶» ව්â€à¶ºà·à¶´à·˜à¶­à·’ය සහ වෙනත් <ph name="BEGIN_LINK_OSS" />විවෘත මූලà·à·à·Šâ€à¶» මෘදුකà·à¶‚ග<ph name="END_LINK_OSS" /> මගිනි.</translation>
<translation id="2588322182880276190">ක්â€à¶»à·à¶¸à·Š ලà·à¶‚ඡනය</translation>
+<translation id="290720624583273918">CloudReady 2.0 එහි මූලික පිහිටුවීම සම්පූර්ණ කර නà·à¶­.</translation>
<translation id="3444832043240812445">ඔබ <ph name="BEGIN_LINK" />බිඳවà·à¶§à·”ම් à·€à·à¶»à·Šà¶­à· සබල කර<ph name="END_LINK" /> ඇත්නම් පමණක් මෙම පිටුව ඔබේ මෑතකදී සිදු වූ බිඳවà·à¶§à·“ම් පෙන්වනු ඇත.</translation>
<translation id="3875312571075912821">ඔබගේ ෆයර් à·€à·à¶½ හ෠ප්â€à¶»à¶­à·’වයිරස à·ƒà·à¶šà·ƒà·“ම් තුළ Chrome හට ජà·à¶½à¶ºà¶§ පිවිසීමට
අවසර දෙන්න.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_sk.xtb b/chromium/components/strings/components_google_chrome_strings_sk.xtb
index aa39263e062..ac36bc1fa57 100644
--- a/chromium/components/strings/components_google_chrome_strings_sk.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_sk.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">Zmeny sa prejavia po ÄalÅ¡om opätovnom spustení Chromu.</translation>
<translation id="2447485272386224171">Chrome je založený na open source projekte <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> a ÄalÅ¡om <ph name="BEGIN_LINK_OSS" />open source softvéri<ph name="END_LINK_OSS" />.</translation>
<translation id="2588322182880276190">Logo Chrome</translation>
+<translation id="290720624583273918">Systém CloudReady 2.0 nedokonÄil svoje pôvodné nastavenie.</translation>
<translation id="3444832043240812445">Táto stránka zobrazuje informácie o nedávnych zlyhaniach, len ak ste <ph name="BEGIN_LINK" />povolili hlásenia zlyhaní<ph name="END_LINK" />.</translation>
<translation id="3875312571075912821">Chromu povoľte prístup k sieti v nastaveniach brány firewall alebo antivírusového softvéru.</translation>
<translation id="4010643444566880169">Systém Chrome OS nedokonÄil poÄiatoÄné nastavenie.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_sl.xtb b/chromium/components/strings/components_google_chrome_strings_sl.xtb
index 3a9fdafe0f9..455f6c0056d 100644
--- a/chromium/components/strings/components_google_chrome_strings_sl.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_sl.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">Spremembe bodo zaÄele veljati ob naslednjem zagonu Chroma.</translation>
<translation id="2447485272386224171">Chrome omogoÄajo odprtokodni projekt <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> in druga <ph name="BEGIN_LINK_OSS" />odprtokodna programska oprema<ph name="END_LINK_OSS" />.</translation>
<translation id="2588322182880276190">Chromov logotip</translation>
+<translation id="290720624583273918">CloudReady 2.0 ni dokonÄal zaÄetne nastavitve.</translation>
<translation id="3444832043240812445">Ta stran prikazuje informacije o zadnjih zruÅ¡itvah, samo Äe <ph name="BEGIN_LINK" />omogoÄite poroÄanje o zruÅ¡itvah<ph name="END_LINK" />.</translation>
<translation id="3875312571075912821">V nastavitvah požarnega zidu ali protivirusnega programa omogoÄite Chromu dostop do
omrežja.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_sq.xtb b/chromium/components/strings/components_google_chrome_strings_sq.xtb
index fa00fc6454c..160a3be8e39 100644
--- a/chromium/components/strings/components_google_chrome_strings_sq.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_sq.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">Ndryshimet e tua do të hyjnë në fuqi herën tjetër kur të rihapësh Chrome.</translation>
<translation id="2447485272386224171">Chrome është bërë i mundur nga projekti me burim të hapur <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> dhe <ph name="BEGIN_LINK_OSS" />softuerë të tjerë me burim të hapur<ph name="END_LINK_OSS" />.</translation>
<translation id="2588322182880276190">Logoja e Chrome</translation>
+<translation id="290720624583273918">CloudReady 2.0 nuk e ka përfunduar konfigurimin e tij fillestar.</translation>
<translation id="3444832043240812445">Kjo faqe shfaq vetëm informacione mbi ndërprerjet e tua të fundit aksidentale, nëse <ph name="BEGIN_LINK" />aktivizon raportimin e ndërprerjeve aksidentale<ph name="END_LINK" />.</translation>
<translation id="3875312571075912821">Lejo Chrome të qaset në rrjet, në cilësimet e murit mbrojtës ose
të antivirusit.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_sr-Latn.xtb b/chromium/components/strings/components_google_chrome_strings_sr-Latn.xtb
index c5f054d0d04..3f0c947be27 100644
--- a/chromium/components/strings/components_google_chrome_strings_sr-Latn.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_sr-Latn.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">Promene cÌe stupiti na snagu kada sledecÌi put ponovo pokrenete Chrome.</translation>
<translation id="2447485272386224171">Chrome omogucÌavaju <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> projekat otvorenog koda i drugi <ph name="BEGIN_LINK_OSS" />softver otvorenog koda<ph name="END_LINK_OSS" />.</translation>
<translation id="2588322182880276190">Chrome logotip</translation>
+<translation id="290720624583273918">CloudReady 2.0 nije dovrÅ¡io poÄetno podeÅ¡avanje.</translation>
<translation id="3444832043240812445">Ova stranica prikazuje informacije o nedavnim otkazivanjima samo ukoliko <ph name="BEGIN_LINK" />omogucÌite izveÅ¡tavanje o otkazivanjima<ph name="END_LINK" />.</translation>
<translation id="3875312571075912821">Dozvolite Chrome-u da pristupa mreži u zaštitnom zidu ili antivirusnim
podešavanjima.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_sr.xtb b/chromium/components/strings/components_google_chrome_strings_sr.xtb
index 34084fe0046..bc6125766f2 100644
--- a/chromium/components/strings/components_google_chrome_strings_sr.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_sr.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">Промене ће Ñтупити на Ñнагу када Ñледећи пут поново покренете Chrome.</translation>
<translation id="2447485272386224171">Chrome омогућавају <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> пројекат отвореног кода и други <ph name="BEGIN_LINK_OSS" />Ñофтвер отвореног кода<ph name="END_LINK_OSS" />.</translation>
<translation id="2588322182880276190">Chrome логотип</translation>
+<translation id="290720624583273918">CloudReady 2.0 није довршио почетно подешавање.</translation>
<translation id="3444832043240812445">Ова Ñтраница приказује информације о недавним отказивањима Ñамо уколико <ph name="BEGIN_LINK" />омогућите извештавање о отказивањима<ph name="END_LINK" />.</translation>
<translation id="3875312571075912821">Дозволите Chrome-у да приÑтупа мрежи у заштитном зиду или антивируÑним
подешавањима.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_sv.xtb b/chromium/components/strings/components_google_chrome_strings_sv.xtb
index 3e23f475e13..84621bf90d1 100644
--- a/chromium/components/strings/components_google_chrome_strings_sv.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_sv.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">Ändringarna börjar gälla nästa gång du startar Chrome.</translation>
<translation id="2447485272386224171">Chrome finns tack vare det öppna källkodsprojektet <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> och andra <ph name="BEGIN_LINK_OSS" />program med öppen källkod<ph name="END_LINK_OSS" />.</translation>
<translation id="2588322182880276190">Logotypen för Chrome</translation>
+<translation id="290720624583273918">Den första konfigureringen av CloudReady 2.0 har inte slutförts.</translation>
<translation id="3444832043240812445">Du måste <ph name="BEGIN_LINK" />aktivera kraschrapportering<ph name="END_LINK" /> för att information om de senaste krascherna ska visas på den här sidan.</translation>
<translation id="3875312571075912821">Tillåt att Chrome får åtkomst till nätverket i inställningarna för brandväggen eller
antivirusprogrammet.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_sw.xtb b/chromium/components/strings/components_google_chrome_strings_sw.xtb
index cfafec83d39..700a1fbee6f 100644
--- a/chromium/components/strings/components_google_chrome_strings_sw.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_sw.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">Mabadiliko yako yatatekelezwa wakati mwingine utakapofungua Chrome.</translation>
<translation id="2447485272386224171">Chrome imefanikishwa na mradi wa programu huria wa <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> na <ph name="BEGIN_LINK_OSS" />programu huria<ph name="END_LINK_OSS" /> zingine.</translation>
<translation id="2588322182880276190">Nembo ya Chrome</translation>
+<translation id="290720624583273918">Mfumo wa CloudReady 2.0 haujakamilisha kuweka mipangilio yake ya mwanzo.</translation>
<translation id="3444832043240812445">Ukurasa huu unaonyesha tu maelezo yako ya uharibifu wa hivi karibuni ukiwezesha <ph name="BEGIN_LINK" />kuripoti uharibifu<ph name="END_LINK" />.</translation>
<translation id="3875312571075912821">Ruhusu Chrome ifikie mtandao katika mipangilio ya kinga mtandao au
kingavirusi yako.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_ta.xtb b/chromium/components/strings/components_google_chrome_strings_ta.xtb
index f3ffb6f8410..912644b8139 100644
--- a/chromium/components/strings/components_google_chrome_strings_ta.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_ta.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">அடà¯à®¤à¯à®¤ à®®à¯à®±à¯ˆ Chromeமை மீணà¯à®Ÿà¯à®®à¯ தொடஙà¯à®•à¯à®®à¯à®ªà¯‹à®¤à¯, நீஙà¯à®•à®³à¯ செயà¯à®¤ மாறà¯à®±à®™à¯à®•à®³à¯ செயலà¯à®ªà®Ÿà¯à®¤à¯à®¤à®ªà¯à®ªà®Ÿà¯à®®à¯.</translation>
<translation id="2447485272386224171"><ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> ஓபà¯à®ªà®©à¯ சோரà¯à®¸à¯ திடà¯à®Ÿà®ªà¯à®ªà®£à®¿ மறà¯à®±à¯à®®à¯ பிற <ph name="BEGIN_LINK_OSS" />ஓபà¯à®ªà®©à¯ சோரà¯à®¸à¯ மெனà¯à®ªà¯Šà®°à¯à®³à¯<ph name="END_LINK_OSS" /> காரணமாக Chromeமை உரà¯à®µà®¾à®•à¯à®•à¯à®µà®¤à¯ சாதà¯à®¤à®¿à®¯à®®à®¾à®©à®¤à¯.</translation>
<translation id="2588322182880276190">Chrome லோகோ</translation>
+<translation id="290720624583273918">தà¯à®µà®•à¯à®•à®¨à®¿à®²à¯ˆ அமைவை CloudReady 2.0 நிறைவà¯à®šà¯†à®¯à¯à®¯à®µà®¿à®²à¯à®²à¯ˆ.</translation>
<translation id="3444832043240812445">நீஙà¯à®•à®³à¯ <ph name="BEGIN_LINK" />செயலிழபà¯à®ªà¯ பà¯à®•à®¾à®°à®³à®¿à®¤à¯à®¤à®²à¯ˆ இயகà¯à®•à®¿à®¯à®¿à®°à¯à®¨à¯à®¤à®¾à®²à¯<ph name="END_LINK" /> மடà¯à®Ÿà¯à®®à¯‡, இநà¯à®¤à®ªà¯ பகà¯à®•à®®à¯ உஙà¯à®•à®³à¯à®Ÿà¯ˆà®¯ சமீபதà¯à®¤à®¿à®¯ செயலிழபà¯à®ªà¯à®•à®³à¯ˆà®ªà¯ பறà¯à®±à®¿à®¯ தகவலà¯à®•à®³à¯ˆà®•à¯ காணà¯à®ªà®¿à®•à¯à®•à¯à®®à¯.</translation>
<translation id="3875312571075912821">ஃபயரà¯à®µà®¾à®²à®¿à®²à¯‹ வைரஸ௠தடà¯à®ªà¯à®ªà¯
அமைபà¯à®ªà¯à®•à®³à®¿à®²à¯‹ நெடà¯à®µà¯Šà®°à¯à®•à¯à®•à¯ˆ அணà¯à®• Chromeமை அனà¯à®®à®¤à®¿à®•à¯à®•à®µà¯à®®à¯.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_te.xtb b/chromium/components/strings/components_google_chrome_strings_te.xtb
index 33013bfcc1a..4f62411fd0c 100644
--- a/chromium/components/strings/components_google_chrome_strings_te.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_te.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">మీరౠచేసిన మారà±à°ªà±à°²à± మీరౠChromeనౠమరà±à°¸à°Ÿà°¿à°¸à°¾à°°à°¿ à°°à±€-లాంచౠచేసినపà±à°ªà±à°¡à± à°ªà±à°°à°­à°¾à°µà°¾à°¨à±à°¨à°¿ చూపà±à°¤à°¾à°¯à°¿.</translation>
<translation id="2447485272386224171"><ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> ఓపెనౠసోరà±à°¸à± à°ªà±à°°à°¾à°œà±†à°•à±à°Ÿà±, ఇతర <ph name="BEGIN_LINK_OSS" />ఓపెనౠసోరà±à°¸à± సాఫà±à°Ÿà±â€Œà°µà±‡à°°à±<ph name="END_LINK_OSS" /> à°¦à±à°µà°¾à°°à°¾ Chromeనౠరూపొందించడం సాధà±à°¯à°®à°¯à±à°¯à°¿à°‚ది.</translation>
<translation id="2588322182880276190">Chrome లోగో</translation>
+<translation id="290720624583273918">CloudReady 2.0 దాని à°ªà±à°°à°¾à°°à°‚à°­ సెటపà±â€Œà°¨à± పూరà±à°¤à°¿ చేయలేదà±.</translation>
<translation id="3444832043240812445">మీరౠ<ph name="BEGIN_LINK" />à°•à±à°°à°¾à°·à±â€Œ రిపోరà±à°Ÿà±â€Œà°¨à± à°ªà±à°°à°¾à°°à°‚భించినపà±à°¡à±<ph name="END_LINK" /> à°ˆ పేజీ మీ ఇటీవలి à°•à±à°°à°¾à°·à±â€Œà°² సమాచారానà±à°¨à°¿ మాతà±à°°à°®à±‡ చూపిసà±à°¤à±à°‚ది.</translation>
<translation id="3875312571075912821">మీ ఫైరà±â€Œà°µà°¾à°²à± లేదా యాంటీవైరసౠసెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²à±à°²à±‹ నెటà±â€Œà°µà°°à±à°•à±â€Œà°¨à± యాకà±à°¸à±†à°¸à± చేయడానికి
Chromeనౠఅనà±à°®à°¤à°¿à°‚à°šà°‚à°¡à°¿.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_th.xtb b/chromium/components/strings/components_google_chrome_strings_th.xtb
index a4326bb9fa1..065aeb3b2ec 100644
--- a/chromium/components/strings/components_google_chrome_strings_th.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_th.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">à¸à¸²à¸£à¹€à¸›à¸¥à¸µà¹ˆà¸¢à¸™à¹à¸›à¸¥à¸‡à¸‚องคุณจะมีผลในครั้งถัดไปที่คุณเปิด Chrome อีà¸à¸„รั้ง</translation>
<translation id="2447485272386224171">Chrome เป็นจริงขึ้นได้จาà¸à¹‚ปรเจ็à¸à¸•à¹Œà¹‚อเพนซอร์ส <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> à¹à¸¥à¸°<ph name="BEGIN_LINK_OSS" />ซอฟต์à¹à¸§à¸£à¹Œà¹‚อเพนซอร์ส<ph name="END_LINK_OSS" />อื่นๆ</translation>
<translation id="2588322182880276190">โลโà¸à¹‰ Chrome</translation>
+<translation id="290720624583273918">à¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่าà¹à¸£à¸à¹€à¸£à¸´à¹ˆà¸¡à¸‚อง CloudReady 2.0 ไม่เสร็จสมบูรณ์</translation>
<translation id="3444832043240812445">หน้าเว็บนี้จะà¹à¸ªà¸”งเฉพาะข้อมูลเà¸à¸µà¹ˆà¸¢à¸§à¸à¸±à¸šà¸‚้อขัดข้องที่เà¸à¸´à¸”ขึ้นเมื่อเร็วๆ นี้ของคุณเท่านั้น หาà¸à¸„ุณ<ph name="BEGIN_LINK" />เปิดใช้งานà¸à¸²à¸£à¸£à¸²à¸¢à¸‡à¸²à¸™à¸‚้อขัดข้อง<ph name="END_LINK" /></translation>
<translation id="3875312571075912821">อนุà¸à¸²à¸•à¹ƒà¸«à¹‰ Chrome เข้าถึงเครือข่ายในà¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่าไฟร์วอลล์
หรือà¸à¸²à¸£à¸›à¹‰à¸­à¸‡à¸à¸±à¸™à¹„วรัส</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_tr.xtb b/chromium/components/strings/components_google_chrome_strings_tr.xtb
index 956b22c8da9..e457ca8d842 100644
--- a/chromium/components/strings/components_google_chrome_strings_tr.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_tr.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">Yaptığınız değişiklikler Chrome'u yeniden başlattığınızda geçerli olacak.</translation>
<translation id="2447485272386224171">Chrome, <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> açık kaynak projesi ve diğer <ph name="BEGIN_LINK_OSS" />açık kaynak yazılımlar<ph name="END_LINK_OSS" /> ile oluşturulmuştur.</translation>
<translation id="2588322182880276190">Chrome logosu</translation>
+<translation id="290720624583273918">CloudReady 2.0 ilk kurulumunu tamamlamadı.</translation>
<translation id="3444832043240812445">Karşılaştığınız son kilitlenme olayları hakkındaki bilgiler yalnızca <ph name="BEGIN_LINK" />kilitlenme bildirmeyi etkinleştirdiyseniz<ph name="END_LINK" /> bu sayfada gösterilir.</translation>
<translation id="3875312571075912821">Güvenlik duvarınızın veya virüsten korunma programınızın ayarlarından,
Chrome'un aÄŸa eriÅŸmesine izin verin.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_uk.xtb b/chromium/components/strings/components_google_chrome_strings_uk.xtb
index 1994a03ac15..3c1768103c0 100644
--- a/chromium/components/strings/components_google_chrome_strings_uk.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_uk.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">Ваші зміни почнуть діÑти піÑÐ»Ñ Ð½Ð°Ñтупного перезапуÑку Chrome.</translation>
<translation id="2447485272386224171">Chrome було Ñтворено на оÑнові проекту програмного Ð·Ð°Ð±ÐµÐ·Ð¿ÐµÑ‡ÐµÐ½Ð½Ñ Ð· відкритим кодом <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> та іншого <ph name="BEGIN_LINK_OSS" />програмного Ð·Ð°Ð±ÐµÐ·Ð¿ÐµÑ‡ÐµÐ½Ð½Ñ Ð· відкритим кодом<ph name="END_LINK_OSS" />.</translation>
<translation id="2588322182880276190">Логотип Chrome</translation>
+<translation id="290720624583273918">Ðе завершено початкове Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ CloudReady 2.0.</translation>
<translation id="3444832043240812445">Ðа цій Ñторінці відображаєтьÑÑ Ñ–Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ñ–Ñ Ð»Ð¸ÑˆÐµ про оÑтанні випадки аварійного Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð½Ñ Ñ€Ð¾Ð±Ð¾Ñ‚Ð¸, Ñкщо <ph name="BEGIN_LINK" />ввімкнено Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾ аварійне Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð½Ñ Ñ€Ð¾Ð±Ð¾Ñ‚Ð¸<ph name="END_LINK" />.</translation>
<translation id="3875312571075912821">Ðадайте Chrome доÑтуп до мережі в налаштуваннÑÑ… брандмауера чи
антивіруÑної програми.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_ur.xtb b/chromium/components/strings/components_google_chrome_strings_ur.xtb
index 37d445c690a..8f5a6af07a3 100644
--- a/chromium/components/strings/components_google_chrome_strings_ur.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_ur.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">â€Ø§Ú¯Ù„ÛŒ بار جب آپ Chrome بند کرکے Ø¯ÙˆØ¨Ø§Ø±Û Ø´Ø±ÙˆØ¹ کریں Ú¯Û’ تو آپ Ú©ÛŒ تبدیلیاں ناÙØ° ÛÙˆÚº گی۔</translation>
<translation id="2447485272386224171">â€Chrome Ú©Ùˆ <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> اوپن سورس پروجیکٹ اور دیگر <ph name="BEGIN_LINK_OSS" />اوپن سورس ساÙÙ¹ ویئر<ph name="END_LINK_OSS" /> Ú©Û’ ذریعے ممکن بنایا گیا ÛÛ’Û”</translation>
<translation id="2588322182880276190">â€Chrome کا لوگو</translation>
+<translation id="290720624583273918">â€CloudReady 2.0 Ù†Û’ اپنا ابتدائی سیٹ اپ مکمل Ù†Ûیں کیا ÛÛ’Û”</translation>
<translation id="3444832043240812445">اگر آپ <ph name="BEGIN_LINK" />کریش Ú©ÛŒ اطلاع دÛندگی Ùعال کرتے Ûیں<ph name="END_LINK" /> تو ÛŒÛ ØµÙØ­Û ØµØ±Ù Ø¢Ù¾ Ú©Û’ Ø­Ø§Ù„ÛŒÛ Ú©Ø±ÛŒØ´Ø² Ú©ÛŒ بابت معلومات Ú©Ùˆ دکھاتا ÛÛ’Û”</translation>
<translation id="3875312571075912821">â€Chrome Ú©Ùˆ اپنے Ùائروال یا اینٹی وائرس Ú©ÛŒ
ترتیبات میں نیٹ ورک تک رسائی حاصل کرنے کی اجازت دیں۔</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_uz.xtb b/chromium/components/strings/components_google_chrome_strings_uz.xtb
index c863440b358..06d0adcf540 100644
--- a/chromium/components/strings/components_google_chrome_strings_uz.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_uz.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">Oʻzgartirishlar Google Chrome qaytadan ishga tushirilganda kuchga kiradi.</translation>
<translation id="2447485272386224171">Google Chrome paydo boʻlishida <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> ochiq kodli loyihasi va boshqa <ph name="BEGIN_LINK_OSS" />ochiq kodli dasturiy taʼminotlarning<ph name="END_LINK_OSS" /> katta oʻrni bor.</translation>
<translation id="2588322182880276190">Chrome logotipi</translation>
+<translation id="290720624583273918">CloudReady 2.0 dastlabki sozlamalarni yakunlay olmadi.</translation>
<translation id="3444832043240812445">Yaqinda yuz bergan ishdan chiqishlar haqidagi ma’lumotlar bu sahifada faqatgina <ph name="BEGIN_LINK" />ishdan chiqishlar hisoboti funksiyasi yoniq bo‘lganda<ph name="END_LINK" /> ko‘rsatiladi.</translation>
<translation id="3875312571075912821">Himoya devori yoki antivirus dasturi sozlamalari orqali Chrome brauzeriga tarmoqqa ulanishiga ruxsat bering</translation>
<translation id="4010643444566880169">Chrome OS boshlang‘ich sozlamalarni yakunlay olmadi.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_vi.xtb b/chromium/components/strings/components_google_chrome_strings_vi.xtb
index c0d9b681c7a..a89dab1cc7d 100644
--- a/chromium/components/strings/components_google_chrome_strings_vi.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_vi.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">Các thay đổi của bạn sẽ có hiệu lực vào lần tiếp theo bạn chạy lại Chrome.</translation>
<translation id="2447485272386224171">Chrome được xây dá»±ng bằng dá»± án nguồn mở <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> và <ph name="BEGIN_LINK_OSS" />phần má»m nguồn mở<ph name="END_LINK_OSS" /> khác.</translation>
<translation id="2588322182880276190">Biểu trưng Chrome</translation>
+<translation id="290720624583273918">CloudReady 2.0 chưa hoàn tất quá trình thiết lập ban đầu.</translation>
<translation id="3444832043240812445">Trang này chỉ hiển thị thông tin vỠcác sự cố gần đây của bạn nếu bạn <ph name="BEGIN_LINK" />bật báo cáo sự cố<ph name="END_LINK" />.</translation>
<translation id="3875312571075912821">Cho phép Chrome truy cập mạng trong cài đặt tÆ°á»ng lá»­a hoặc diệt vi-rút
của bạn.</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_zh-CN.xtb b/chromium/components/strings/components_google_chrome_strings_zh-CN.xtb
index d9ec3854cae..796d88ad359 100644
--- a/chromium/components/strings/components_google_chrome_strings_zh-CN.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_zh-CN.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">您所åšçš„更改会在下次é‡æ–°å¯åŠ¨ Chrome 时生效。</translation>
<translation id="2447485272386224171">Chrome 的诞生离ä¸å¼€ <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> å¼€æºé¡¹ç›®ä»¥åŠå…¶ä»–<ph name="BEGIN_LINK_OSS" />å¼€æºè½¯ä»¶<ph name="END_LINK_OSS" />。</translation>
<translation id="2588322182880276190">Chrome 徽标</translation>
+<translation id="290720624583273918">CloudReady 2.0 尚未完æˆå…¶åˆå§‹è®¾ç½®ã€‚</translation>
<translation id="3444832043240812445">如果<ph name="BEGIN_LINK" />å¯ç”¨å´©æºƒæŠ¥å‘Š<ph name="END_LINK" />,则该网页将åªæ˜¾ç¤ºæ‚¨æœ€è¿‘的崩溃信æ¯ã€‚</translation>
<translation id="3875312571075912821">在防ç«å¢™æˆ–防病毒设置部分设为å…许 Chrome 访问网络。</translation>
<translation id="4010643444566880169">Chrome æ“作系统尚未完æˆå…¶åˆå§‹è®¾ç½®ã€‚</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_zh-HK.xtb b/chromium/components/strings/components_google_chrome_strings_zh-HK.xtb
index d9b6d8a7bd6..c33e894eb77 100644
--- a/chromium/components/strings/components_google_chrome_strings_zh-HK.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_zh-HK.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">您的變更將於下次é‡æ–°å•Ÿå‹• Chrome 時生效。</translation>
<translation id="2447485272386224171">Chrome 的開發有賴 <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> 開放原始碼計劃和其他<ph name="BEGIN_LINK_OSS" />開放原始碼軟件<ph name="END_LINK_OSS" />çš„å”助æ‰å¾—以完æˆã€‚</translation>
<translation id="2588322182880276190">Chrome 標誌</translation>
+<translation id="290720624583273918">CloudReady 2.0 並未完æˆåˆå§‹è¨­å®šã€‚</translation>
<translation id="3444832043240812445">如果您<ph name="BEGIN_LINK" />啟用當機報告功能<ph name="END_LINK" />,這個é é¢åªæœƒé¡¯ç¤ºæœ€è¿‘的當機資料。</translation>
<translation id="3875312571075912821">在防ç«ç‰†æˆ–防毒軟件設定中å…許 Chrome å­˜å–
網絡。</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_zh-TW.xtb b/chromium/components/strings/components_google_chrome_strings_zh-TW.xtb
index e82618ef3ba..b46dc2e1133 100644
--- a/chromium/components/strings/components_google_chrome_strings_zh-TW.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_zh-TW.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">你的變更將於下次é‡æ–°å•Ÿå‹• Chrome 時生效。</translation>
<translation id="2447485272386224171">Chrome 的開發仰賴 <ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> 開放原始碼計畫與其他<ph name="BEGIN_LINK_OSS" />開放原始碼軟體<ph name="END_LINK_OSS" />çš„å”助æ‰å¾—以完æˆã€‚</translation>
<translation id="2588322182880276190">Chrome 標誌</translation>
+<translation id="290720624583273918">CloudReady 2.0 尚未完æˆåˆå§‹è¨­å®šã€‚</translation>
<translation id="3444832043240812445">如果你<ph name="BEGIN_LINK" />啟用當機報告功能<ph name="END_LINK" />,這個é é¢åƒ…會顯示最近的當機資訊。</translation>
<translation id="3875312571075912821">å…許 Chrome å­˜å–å—到防ç«ç‰†æˆ–防毒軟體設定所阻擋的
網路。</translation>
diff --git a/chromium/components/strings/components_google_chrome_strings_zu.xtb b/chromium/components/strings/components_google_chrome_strings_zu.xtb
index 3cf0e34772d..d6dd802ba19 100644
--- a/chromium/components/strings/components_google_chrome_strings_zu.xtb
+++ b/chromium/components/strings/components_google_chrome_strings_zu.xtb
@@ -6,6 +6,7 @@
<translation id="1635457557763038537">Izinguquko zakho zizosebenza ngesikhathi esilandelayo lapho uqalisa kabusha i-Chrome.</translation>
<translation id="2447485272386224171">I-Chrome yenziwa ikhonakale i-<ph name="BEGIN_LINK_CHROMIUM" />Chromium<ph name="END_LINK_CHROMIUM" /> iphrojekthi yomthombo ovulekile kanye nenye <ph name="BEGIN_LINK_OSS" />isofthiwe yomthombo ovulekile<ph name="END_LINK_OSS" />.</translation>
<translation id="2588322182880276190">Ilogo ye-Chrome</translation>
+<translation id="290720624583273918">I-CloudReady 2.0 ayiqedanga ukusetha kwayo kwasekuqaleni.</translation>
<translation id="3444832043240812445">Leli khasi libonisa kuphela ulwazi lokuphahlazeka kwakho kwakamuva uma ngabe <ph name="BEGIN_LINK" />unika amandla ukubikwa kokuphahlazeka<ph name="END_LINK" />.</translation>
<translation id="3875312571075912821">Vumela i-Chrome ukufinyelela inethiwekhi kuzilungiselelo zakho zohlelo lokuvikela noma isilwi magciwane.</translation>
<translation id="4010643444566880169">I-Chrome OS ayiqedanga ukusethwa kwayo kwasekuqaleni.</translation>
diff --git a/chromium/components/strings/components_strings_af.xtb b/chromium/components/strings/components_strings_af.xtb
index 833714dcc92..63bec569b57 100644
--- a/chromium/components/strings/components_strings_af.xtb
+++ b/chromium/components/strings/components_strings_af.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">Sien besonderhede</translation>
<translation id="1030706264415084469"><ph name="URL" /> wil groot data permanent op jou toestel berg</translation>
<translation id="1032854598605920125">Draai kloksgewys</translation>
+<translation id="1033329911862281889">Incognito maak jou nie onsigbaar aanlyn nie:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Werwe en die dienste wat hulle gebruik, kan besoeke sien<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Werkgewers of skole kan blaai-aktiwiteit naspoor<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Internetdiensverskaffers kan webverkeer monitor<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">Skakel af</translation>
<translation id="1036982837258183574">Druk |<ph name="ACCELERATOR" />| om volskerm te verlaat</translation>
<translation id="1038106730571050514">Wys voorstelle</translation>
<translation id="1038842779957582377">onbekende naam</translation>
<translation id="1041998700806130099">Taakbladsyboodskap</translation>
<translation id="1048785276086539861">Hierdie dokument sal na enkelbladsyaansig toe terugkeer wanneer jy aantekeninge redigeer</translation>
-<translation id="1049743911850919806">Incognito</translation>
<translation id="1050038467049342496">Maak ander programme toe</translation>
<translation id="1055184225775184556">Ontdoen byvoeging</translation>
<translation id="1056898198331236512">Waarskuwing</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">Beleidkas OK</translation>
<translation id="1130564665089811311">Vertaal Bladsy-knoppie; druk Enter om hierdie bladsy met Google Vertaal te vertaal</translation>
<translation id="1131264053432022307">Prent wat jy gekopieer het</translation>
+<translation id="1142846828089312304">Blokkeer derdepartywebkoekies in Incognito</translation>
<translation id="1150979032973867961">Hierdie bediener kon nie bewys dat dit <ph name="DOMAIN" /> is nie; sy sekuriteitsertifikaat word nie deur jou rekenaar se bedryfstelsel vertrou nie. Dit kan veroorsaak word deur 'n wanopstelling of 'n aanvaller wat jou verbinding onderskep.</translation>
<translation id="1151972924205500581">Wagwoord word vereis</translation>
<translation id="1156303062776767266">Jy bekyk tans 'n plaaslike of gedeelde lêer</translation>
@@ -64,7 +70,6 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="1178581264944972037">Laat wag</translation>
<translation id="1181037720776840403">Verwyder</translation>
<translation id="1186201132766001848">Gaan wagwoorde na</translation>
-<translation id="1195210374336998651">Gaan na programinstellings toe</translation>
<translation id="1195558154361252544">Kennisgewings word outomaties geblokkeer vir alle werwe behalwe dié wat jy toelaat</translation>
<translation id="1197088940767939838">Oranje</translation>
<translation id="1201402288615127009">Volgende</translation>
@@ -111,7 +116,7 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="1307966114820526988">Opgeskorte kenmerke</translation>
<translation id="1308113895091915999">Aanbieding beskikbaar</translation>
<translation id="1312803275555673949">Watter bewyse steun dit?</translation>
-<translation id="131405271941274527"><ph name="URL" /> wil inligting stuur en ontvang wanneer jy jou foon op 'n NFC-toestel tik</translation>
+<translation id="1314311879718644478">Bekyk aangevulderealiteit-inhoud</translation>
<translation id="1314509827145471431">Regs gebind</translation>
<translation id="1318023360584041678">Gestoor in oortjiegroep</translation>
<translation id="1319245136674974084">Moenie weer vir hierdie program vra nie</translation>
@@ -161,6 +166,7 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="142858679511221695">Wolkgebruiker</translation>
<translation id="1428729058023778569">Jy sien hierdie waarskuwing omdat hierdie werf nie HTTPS ondersteun nie. <ph name="BEGIN_LEARN_MORE_LINK" />Kom meer te wete<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">Druk uit</translation>
+<translation id="1432187715652018471">bladsy wil 'n dienshanteerder installeer.</translation>
<translation id="1432581352905426595">Bestuur soekenjins</translation>
<translation id="1436185428532214179">Kan vra om lêers of vouers op jou toestel te wysig</translation>
<translation id="1442386063175183758">Uitvoublad regs</translation>
@@ -181,6 +187,12 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="1483493594462132177">Stuur</translation>
<translation id="1484290072879560759">Kies versendingadres</translation>
<translation id="1492194039220927094">Deurstuur van beleide:</translation>
+<translation id="149293076951187737">Jou aktiwiteit in oortjies word op hierdie toestel uitgevee wanneer jy alle Incognito-oortjies in Chromium toemaak:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Blaai-aktiwiteit<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Soekgeskiedenis<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Inligting wat op vorms ingevoer is<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">Terug na oortjie</translation>
<translation id="1501859676467574491">Wys kaarte van jou Google-rekening</translation>
<translation id="1507202001669085618">&lt;p&gt;Jy sal hierdie fout sien as jy 'n Wi-Fi-portaal gebruik waar jy moet aanmeld voordat jy aanlyn kan gaan.&lt;/p&gt;
@@ -208,6 +220,8 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="1559572115229829303">&lt;p&gt;'n Private verbinding aan <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> kon nie gevestig word nie omdat jou toestel se datum en tyd (<ph name="DATE_AND_TIME" />) verkeerd is.&lt;/p&gt;
&lt;p&gt;Stel asseblief die datum en tyd reg in die &lt;strong&gt;Algemeen&lt;/strong&gt;-afdeling van die &lt;strong&gt;Instellings&lt;/strong&gt;-program.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">Jou administrateur sal jou toestel om <ph name="TIME" /> op <ph name="DATE" /> herbegin</translation>
+<translation id="156703335097561114">Netwerkinligting soos adresse, koppelvlakopstelling en verbindinggehalte</translation>
<translation id="1567040042588613346">Hierdie beleid werk soos bedoel, maar dieselfde waarde is elders gestel en word deur hierdie beleid vervang.</translation>
<translation id="1569487616857761740">Voer vervaldatum in</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="1583429793053364125">Kon nie hierdie webbladsy vertoon nie.</translation>
<translation id="1586541204584340881">Watter uitbreidings jy geïnstalleer het</translation>
<translation id="1588438908519853928">Normaal</translation>
+<translation id="1589050138437146318">Installeer ARCore?</translation>
<translation id="1592005682883173041">Toegang tot plaaslike data</translation>
<translation id="1594030484168838125">Kies</translation>
<translation id="160851722280695521">Speel die Dino Run-speletjie in Chrome</translation>
@@ -254,7 +269,7 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="1711234383449478798">Geïgnoreer omdat <ph name="POLICY_NAME" /> nie op <ph name="VALUE" /> gestel is nie.</translation>
<translation id="1712552549805331520"><ph name="URL" /> wil data permanent op jou plaaslike rekenaar berg</translation>
<translation id="1713628304598226412">Laai 2</translation>
-<translation id="1715874602234207">F</translation>
+<translation id="1715874602234207">V</translation>
<translation id="1717218214683051432">Bewegingsensors</translation>
<translation id="1717494416764505390">Posbus 3</translation>
<translation id="1718029547804390981">Dokument is te groot om aantekeninge by te maak</translation>
@@ -283,6 +298,7 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
die opskrif is misvormd, wat die blaaier verhinder om jou versoek
vir <ph name="SITE" /> uit te voer. Werfoperateurs kan oorsprongbeleide gebruik om
sekuriteit- en ander eienskappe vir 'n werf op te stel.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Kom meer te wete oor Incognito in Chromium<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">Jou oop oortjies verskyn hier</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -410,6 +426,7 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="22081806969704220">Laai 3</translation>
<translation id="2212735316055980242">Beleid nie gevind nie</translation>
<translation id="2213606439339815911">Gaan haal tans inskrywings …</translation>
+<translation id="2213612003795704869">Bladsy is gedruk</translation>
<translation id="2215727959747642672">Lêerwysiging</translation>
<translation id="2218879909401188352">Aanvallers wat tans op <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> is, kan dalk gevaarlike programme installeer wat jou toestel kan beskadig, verskuilde koste by jou toestelrekening kan voeg of jou persoonlike inligting kan steel. <ph name="BEGIN_LEARN_MORE_LINK" />Kom meer te wete<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">Geen internet nie</translation>
@@ -419,6 +436,7 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="2248949050832152960">Gerbruik WebAuthn</translation>
<translation id="2250931979407627383">Randhegting links</translation>
<translation id="225207911366869382">Hierdie waarde is vir hierdie beleid opgeskort.</translation>
+<translation id="2256115617011615191">Herbegin nou</translation>
<translation id="2258928405015593961">Voer 'n vervaldatum in die toekoms in en probeer weer</translation>
<translation id="225943865679747347">Foutkode: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">HTTP-fout</translation>
@@ -446,6 +464,7 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="2337852623177822836">Instelling word deur jou administrateur gekontroleer</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> wil saambind</translation>
<translation id="2346319942568447007">Prent wat jy gekopieer het</translation>
+<translation id="2350796302381711542">Laat <ph name="HANDLER_HOSTNAME" /> toe om alle <ph name="PROTOCOL" />-skakels oop te maak eerder as <ph name="REPLACED_HANDLER_TITLE" />?</translation>
<translation id="2354001756790975382">Ander boekmerke</translation>
<translation id="2354430244986887761">Google Veiligblaai het onlangs <ph name="BEGIN_LINK" />skadelike programme<ph name="END_LINK" /> op <ph name="SITE" /> gevind.</translation>
<translation id="2355395290879513365">Aanvallers sal dalk die prente kan sien waarna jy op hierdie werf kyk en jou mislei deur hulle te wysig.</translation>
@@ -471,6 +490,7 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="2413528052993050574">Hierdie bediener kon nie bewys dat dit <ph name="DOMAIN" /> is nie; sy sekuriteitsertifikaat is dalk herroep. Dit kan veroorsaak word deur 'n wanopstelling of 'n aanvaller wat jou verbinding onderskep.</translation>
<translation id="2414886740292270097">Donker</translation>
<translation id="2430968933669123598">Bestuur Google-rekening; druk Enter om jou inligting, privaatheid en sekuriteit in jou Google-rekening te bestuur</translation>
+<translation id="2436186046335138073">Laat <ph name="HANDLER_HOSTNAME" /> toe om alle <ph name="PROTOCOL" />-skakels oop te maak?</translation>
<translation id="2438874542388153331">Vierpons regs</translation>
<translation id="2450021089947420533">Reise</translation>
<translation id="2463739503403862330">Vul in</translation>
@@ -478,6 +498,7 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="2465655957518002998">Kies afleweringmetode</translation>
<translation id="2465688316154986572">Kram</translation>
<translation id="2465914000209955735">Bestuur lêers wat jy in Chrome afgelaai het</translation>
+<translation id="2466004615675155314">Wys inligting van die web af</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Voer tans netwerkdiagnostiek uit<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">Volgorde: 1-tot-N</translation>
<translation id="2470767536994572628">Hierdie dokument sal na enkelbladsyaansig en die oorspronklike rotasie daarvan toe terugkeer wanneer jy aantekeninge redigeer</translation>
@@ -498,6 +519,7 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="2523886232349826891">Net op hierdie toestel gestoor</translation>
<translation id="2524461107774643265">Voeg meer inligting by</translation>
<translation id="2529899080962247600">Hierdie veld moenie meer as <ph name="MAX_ITEMS_LIMIT" /> inskrywings hê nie. Alle verdere inskrywings sal geïgnoreer word.</translation>
+<translation id="2535585790302968248">Maak 'n nuwe Incognito-oortjie oop om privaat te blaai</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{en nog 1}other{en nog #}}</translation>
<translation id="2536110899380797252">Voeg adres by</translation>
<translation id="2539524384386349900">Bespeur</translation>
@@ -523,7 +545,14 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="2597378329261239068">Hierdie dokument word deur 'n wagwoord beskerm. Voer asseblief 'n wagwoord in.</translation>
<translation id="2609632851001447353">Variasies</translation>
<translation id="2610561535971892504">Klik om te kopieer</translation>
+<translation id="2617988307566202237">Chrome sal nie die volgende inligting <ph name="BEGIN_EMPHASIS" />stoor nie<ph name="END_EMPHASIS" />:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Jou blaaigeskiedenis
+ <ph name="LIST_ITEM" />Webkoekies en werfdata
+ <ph name="LIST_ITEM" />Inligting wat op vorms ingevul is
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (Envelope)</translation>
+<translation id="2623663032199728144">Kan vra om inligting oor jou skerms te gebruik</translation>
<translation id="2625385379895617796">Jou horlosie is voor</translation>
<translation id="262745152991669301">Kan vra om aan USB-toestelle te koppel</translation>
<translation id="2629325967560697240"><ph name="BEGIN_ENHANCED_PROTECTION_LINK" />Skakel gevorderde beskerming aan<ph name="END_ENHANCED_PROTECTION_LINK" /> om Chrome se hoogste vlak van beskerming te kry</translation>
@@ -557,6 +586,7 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="2709516037105925701">Outovul</translation>
<translation id="2713444072780614174">Wit</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />, druk Tab en dan Enter om jou betalings- en kredietkaartinligting in Chrome-instellings te bestuur</translation>
+<translation id="271663710482723385">Druk |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| om volskerm te verlaat</translation>
<translation id="2721148159707890343">Versoek was suksesvol</translation>
<translation id="2723669454293168317">Doen 'n veiligheidskontrole in Chrome-instellings</translation>
<translation id="2726001110728089263">Kantlaai</translation>
@@ -587,6 +617,7 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="2850739647070081192">Invite (Envelope)</translation>
<translation id="2856444702002559011">Aanvallers probeer dalk om jou inligting (byvoorbeeld: wagwoorde, boodskappe of kredietkaartinligting) op <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> te steel. <ph name="BEGIN_LEARN_MORE_LINK" />Kom meer te wete<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">Hierdie werf wys indringerige of misleidende advertensies.</translation>
+<translation id="286512204874376891">'n Virtuele kaart verberg jou werklike kaart om te help om jou teen potensiële bedrog te beskerm. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">Vriendelik</translation>
<translation id="2876489322757410363">Verlaat tans Incognitomodus om deur 'n eksterne program te betaal. Gaan voort?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />, druk Tab en dan Enter om jou Veiligblaai en meer in Chrome-instellings te bestuur</translation>
@@ -611,6 +642,7 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="2930577230479659665">Knip ná elke kopie</translation>
<translation id="2932085390869194046">Stel wagwoord voor …</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019">Maak <ph name="PROTOCOL" />-skakels oop</translation>
<translation id="2941952326391522266">Hierdie bediener kon nie bewys dat dit <ph name="DOMAIN" /> is nie; sy sekuriteitsertifikaat is van <ph name="DOMAIN2" /> af. Dit kan veroorsaak word deur 'n wanopstelling of 'n aanvaller wat jou verbinding onderskep.</translation>
<translation id="2943895734390379394">Oplaaityd:</translation>
<translation id="2948083400971632585">Jy kan enige instaanbedieners wat vir 'n verbinding opgestel is van die instellingsbladsy af deaktiveer.</translation>
@@ -643,6 +675,7 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="3037605927509011580">O, mapstieks!</translation>
<translation id="3041612393474885105">Sertifikaatinligting</translation>
<translation id="3044034790304486808">Hervat jou navorsing</translation>
+<translation id="305162504811187366">Geskiedenis van Chrome-afstandwerkskerm, insluitend tydstempels, gasheer- en kliëntsessie-ID's</translation>
<translation id="3060227939791841287">C9 (Envelope)</translation>
<translation id="3061707000357573562">Regstellingdiens</translation>
<translation id="306573536155379004">Speletjie het begin.</translation>
@@ -683,6 +716,7 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="3197136577151645743">Kan vra om te weet wanneer jy hierdie toestel aktief gebruik</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />, druk Tab en dan Enter om te bestuur watter inligting jy in Chrome-instellings sinkroniseer</translation>
<translation id="320323717674993345">Kanselleer betaling</translation>
+<translation id="3203366800380907218">Op die web</translation>
<translation id="3207960819495026254">Geboekmerk</translation>
<translation id="3209034400446768650">Bladsy kan geld hef</translation>
<translation id="3212581601480735796">Jou aktiwiteit op <ph name="HOSTNAME" /> word gemonitor</translation>
@@ -699,10 +733,12 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="3234666976984236645">Bespeur altyd belangrike inhoud op hierdie werf</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />; druk Tab en dan Enter om die voorkoms van jou blaaier te pasmaak</translation>
<translation id="3240791268468473923">Blad vir geen passende eiebewys vir veilige betalingeiebewys is oopgemaak</translation>
+<translation id="324180406144491771">“<ph name="HOST_NAME" />â€-skakels word geblokkeer</translation>
<translation id="3249845759089040423">Fantasties</translation>
<translation id="3252266817569339921">Frans</translation>
<translation id="3257954757204451555">Wie is verantwoordelik vir hierdie inligting?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />, druk Tab en dan Enter om vinnig 'n nuwe geleentheid in Google Kalender te skep</translation>
+<translation id="3261488570342242926">Kom meer te wete oor virtuele kaarte</translation>
<translation id="3264837738038045344">Knoppie om Chrome-instellings te bestuur. Druk Enter om jou Chrome-instellings te besoek</translation>
<translation id="3266793032086590337">Waarde (konflik)</translation>
<translation id="3268451620468152448">Maak oortjies oop</translation>
@@ -716,6 +752,7 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="3288238092761586174"><ph name="URL" /> sal dalk bykomende stappe moet doen om jou betaling te verifieer</translation>
<translation id="3293642807462928945">Kom meer te wete oor <ph name="POLICY_NAME" />-beleid</translation>
<translation id="3295444047715739395">Bekyk en bestuur jou wagwoorde in Chrome-instellings</translation>
+<translation id="3303795387212510132">Laat program toe om <ph name="PROTOCOL_SCHEME" />-skakels oop te maak?</translation>
<translation id="3303855915957856445">Geen soekresultate gevind nie</translation>
<translation id="3304073249511302126">bluetooth-opsporing</translation>
<translation id="3308006649705061278">Organisatoriese eenheid (OU)</translation>
@@ -729,12 +766,6 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="3345782426586609320">Oë</translation>
<translation id="3355823806454867987">Verander instaanbedienerinstellings …</translation>
<translation id="3360103848165129075">Betalinghanteerdersigblad</translation>
-<translation id="3361596688432910856">Chrome sal nie die volgende inligting <ph name="BEGIN_EMPHASIS" />stoor nie<ph name="END_EMPHASIS" />:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Jou blaaigeskiedenis
- <ph name="LIST_ITEM" />Webkoekies en werfdata
- <ph name="LIST_ITEM" />Inligting wat op vorms ingevul is
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">Hierdie beleid is outomaties van die opgeskorte <ph name="OLD_POLICY" />-beleid af gekopieer. Jy moet liewer hierdie beleid gebruik.</translation>
<translation id="3364869320075768271"><ph name="URL" /> wil jou virtuelerealiteittoestel en -data gebruik</translation>
<translation id="3366477098757335611">Bekyk kaarte</translation>
@@ -817,7 +848,6 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="3587738293690942763">Middel</translation>
<translation id="3592413004129370115">Italian (Envelope)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{Jy kan jou groep enige tyd terugstel. Dit neem omtrent 'n dag om by 'n nuwe groep aan te sluit.}=1{Jy kan jou groep enige tyd terugstel. Dit neem omtrent 'n dag om by 'n nuwe groep aan te sluit.}other{Jy kan jou groep enige tyd terugstel. Dit neem {NUM_DAYS} dae om by 'n nuwe groep aan te sluit.}}</translation>
-<translation id="3596012367874587041">Programinstellings</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">Jou administrateur blokkeer die program</translation>
<translation id="3608932978122581043">Stroomoriëntasie</translation>
@@ -860,6 +890,7 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="370972442370243704">Skakel Reise aan</translation>
<translation id="3711895659073496551">Skort op</translation>
<translation id="3712624925041724820">Lisensies is op</translation>
+<translation id="3714633008798122362">webkalender</translation>
<translation id="3714780639079136834">Mobiele data of Wi-Fi aanskakel</translation>
<translation id="3715597595485130451">Koppel aan Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Die instaanbediener, brandmuur en DNS-opstelling nagaan<ph name="END_LINK" /></translation>
@@ -921,6 +952,7 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="3906954721959377182">Tablet</translation>
<translation id="3909477809443608991"><ph name="URL" /> wil beskermde inhoud speel. Jou toestel se identiteit sal deur Google geverifieer word en hierdie werf kan toegang daartoe kry.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">Weier</translation>
<translation id="3939773374150895049">Gebruik WebAuthn pleks van CVC?</translation>
<translation id="3946209740501886391">Vra altyd op hierdie werf</translation>
<translation id="3947595700203588284">Kan vra om aan MIDI-toestelle te koppel</translation>
@@ -942,6 +974,7 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="3990250421422698716">Gelykskudafwyking</translation>
<translation id="3996311196211510766">Die werf <ph name="ORIGIN" /> het versoek dat 'n oorsprongbeleid
op alle versoeke daaraan toegepas word, maar hierdie beleid kan nie op die oomblik toegepas word nie.</translation>
+<translation id="4009243425692662128">Die inhoud van bladsye wat jy druk, word na Google Wolk of derde partye toe gestuur vir ontleding. Dit kan byvoorbeeld vir sensitiewe data geskandeer word.</translation>
<translation id="4010758435855888356">Laat bergingtoegang toe?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{PDF-dokument met {COUNT} bladsy}other{PDF-dokument met {COUNT} bladsye}}</translation>
<translation id="4023431997072828269">Ander mense sal jou inligting kan sien omdat hierdie vorm ingedien word oor 'n verbinding wat nie heeltemal veilig is nie.</translation>
@@ -1036,6 +1069,7 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="4250680216510889253">Nee</translation>
<translation id="4253168017788158739">Nota</translation>
<translation id="425582637250725228">Veranderinge wat jy aangebring het, sal dalk nie gestoor word nie.</translation>
+<translation id="425869179292622354">Maak dit veiliger met 'n virtuele kaart?</translation>
<translation id="4258748452823770588">Swak handtekening</translation>
<translation id="4261046003697461417">Aantekeninge kan nie op beskermde dokumente gemaak word nie</translation>
<translation id="4265872034478892965">Toegelaat deur jou administrateur</translation>
@@ -1098,6 +1132,7 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="4434045419905280838">Opspringers en herleidings</translation>
<translation id="4435702339979719576">Postcard)</translation>
<translation id="443673843213245140">Die gebruik van 'n instaanbediener is gedeaktiveer, maar 'n eksplisiete instaanbedieneropstelling word gespesifiseer.</translation>
+<translation id="4441832193888514600">Geïgnoreer omdat die beleid slegs as ’n wolkgebruikerbeleid gestel kan word.</translation>
<translation id="4450893287417543264">Moenie weer wys nie</translation>
<translation id="4451135742916150903">Kan vra om aan HID-toestelle te koppel</translation>
<translation id="4452328064229197696">Die wagwoord wat jy gebruik het, is in 'n dataskending gekry. Google Wagwoordbestuurder beveel aan dat jy jou gestoorde wagwoorde nagaan om jou rekeninge te beveilig.</translation>
@@ -1153,6 +1188,7 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="4628948037717959914">Foto</translation>
<translation id="4631649115723685955">Kontantterugbetaling is gekoppel</translation>
<translation id="4636930964841734540">Inligting</translation>
+<translation id="4638670630777875591">Incognito in Chromium</translation>
<translation id="464342062220857295">Soekkenmerke</translation>
<translation id="4644670975240021822">Omgekeerde volgorde, voorkant na onder</translation>
<translation id="4646534391647090355">Vat my nou soontoe</translation>
@@ -1173,6 +1209,7 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="4708268264240856090">Jou verbinding is onderbreek</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Voer tans Windows Network Diagnostics uit<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426">Wagwoord vir <ph name="USERNAME" /></translation>
<translation id="4724144314178270921">Kan vra om teks en prente op jou knipbord te sien</translation>
<translation id="4726672564094551039">Herlaai beleide</translation>
<translation id="4728558894243024398">Platform</translation>
@@ -1194,6 +1231,7 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="4757993714154412917">Jy het sopas jou wagwoord op 'n bedrieglike werf ingevoer. Chromium beveel aan dat jy jou gestoorde wagwoorde nagaan om jou rekeninge te beveilig.</translation>
<translation id="4758311279753947758">Voeg kontakinligting by</translation>
<translation id="4761104368405085019">Gebruik jou mikrofoon</translation>
+<translation id="4761869838909035636">Doen Chrome-veiligheidskontrole</translation>
<translation id="4764776831041365478">Die webbladsy by <ph name="URL" /> kan dalk tydelik af wees of dit kon permanent na 'n nuwe webadres geskuif het.</translation>
<translation id="4766713847338118463">Dubbelkram onder</translation>
<translation id="4771973620359291008">'n Onbekende fout het voorgekom.</translation>
@@ -1214,12 +1252,6 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="4819347708020428563">Redigeer aantekeninge in verstekaansig?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />, druk Tab en dan Enter om vinnig 'n nuwe Google Blad te skep</translation>
<translation id="4825507807291741242">Kragtig</translation>
-<translation id="4827402517081186284">Incognito maak jou nie onsigbaar aanlyn nie:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Werwe weet wanneer jy hulle besoek<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Werknemers of skole kan blaai-aktiwiteit naspoor<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Internetdiensverskaffers kan webverkeer monitor<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">Skakel waarskuwings aan</translation>
<translation id="4838327282952368871">Dromerig</translation>
<translation id="4840250757394056958">Bekyk jou Chrome-geskiedenis</translation>
@@ -1231,12 +1263,12 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="4854362297993841467">Daardie afleweringmetode is nie beskikbaar nie. Probeer 'n ander metode.</translation>
<translation id="4854853140771946034">Skep vinnig 'n nuwe nota in Google Keep</translation>
<translation id="485902285759009870">Verifieer tans kode …</translation>
+<translation id="4866506163384898554">Druk |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| om jou skermpyltjie te wys</translation>
<translation id="4876188919622883022">Vereenvoudigde aansig</translation>
<translation id="4876305945144899064">Geen gebruikernaam nie</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{Geen}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831"><ph name="TEXT" />-soektog</translation>
<translation id="4879491255372875719">Outomaties (verstek)</translation>
-<translation id="4879725228911483934">Maak vensters oop en plaas hulle op jou skerms</translation>
<translation id="4880827082731008257">Soekgeskiedenis</translation>
<translation id="4881695831933465202">Maak oop</translation>
<translation id="4885256590493466218">Betaal met <ph name="CARD_DETAIL" /> by betaalpunt</translation>
@@ -1245,6 +1277,7 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">Negende rol</translation>
<translation id="4901778704868714008">Stoor …</translation>
+<translation id="4905659621780993806">Jou admin sal jou toestel op <ph name="DATE" /> om <ph name="TIME" /> outomaties herbegin. Stoor enige oop items voordat jou toestel herbegin.</translation>
<translation id="4913987521957242411">Pons links bo</translation>
<translation id="4918221908152712722">Installeer <ph name="APP_NAME" /> (geen aflaai word vereis nie)</translation>
<translation id="4923459931733593730">Betaling</translation>
@@ -1253,6 +1286,7 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, druk Tab en dan Enter om te soek</translation>
<translation id="4930153903256238152">Groot kapasiteit</translation>
+<translation id="4940163644868678279">Incognito in Chrome</translation>
<translation id="4943872375798546930">Geen resultate nie</translation>
<translation id="4950898438188848926">Oortjiewisselingknoppie, druk Enter om na die oop oortjie toe oor te skakel, <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="495170559598752135">Handelinge</translation>
@@ -1262,6 +1296,7 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="4968522289500246572">Hierdie program is vir mobiele toestelle ontwerp en sy grootte is dalk nie maklik om te verander nie. Die program sal dalk kwessies ervaar of herbegin.</translation>
<translation id="4969341057194253438">Vee opname uit</translation>
<translation id="4973922308112707173">Dubbelpons bo</translation>
+<translation id="4976702386844183910">Laas besoek op <ph name="DATE" /></translation>
<translation id="4984088539114770594">Gebruik mikrofoon?</translation>
<translation id="4984339528288761049">Prc5 (Envelope)</translation>
<translation id="4989163558385430922">Sien alles</translation>
@@ -1323,6 +1358,7 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="5138227688689900538">Wys minder</translation>
<translation id="5145883236150621069">Foutkode kom voor in die beleidantwoord</translation>
<translation id="5146995429444047494">Kennisgewings vir <ph name="ORIGIN" /> word geblokkeer</translation>
+<translation id="514704532284964975"><ph name="URL" /> wil inligting op NFC-toestelle sien en verander wanneer jy op jou foon tik</translation>
<translation id="5148809049217731050">Voorkant na bo</translation>
<translation id="515292512908731282">C4 (Envelope)</translation>
<translation id="5158275234811857234">Omslag</translation>
@@ -1347,6 +1383,7 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="5215116848420601511">Betaalmetodes en adresse wat Google Pay gebruik</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">Laai 13</translation>
+<translation id="5216942107514965959">Laas vandag besoek</translation>
<translation id="5222812217790122047">E-posadres word vereis</translation>
<translation id="5230733896359313003">Versendingadres</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1367,7 +1404,6 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">Dokumenteienskappe</translation>
<translation id="528468243742722775">Einde</translation>
-<translation id="5284909709419567258">Netwerkadresse</translation>
<translation id="5285570108065881030">Wys alle gestoorde wagwoorde</translation>
<translation id="5287240709317226393">Wys webkoekies</translation>
<translation id="5287456746628258573">Hierdie werf gebruik 'n verouderde sekuriteitopstelling, wat jou inligting (byvoorbeeld, wagwoorde en kredietkaartnommers) kan blootstel wanneer dit na hierdie werf toe gestuur word.</translation>
@@ -1451,6 +1487,7 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="5556459405103347317">Herlaai</translation>
<translation id="5560088892362098740">Vervaldatum</translation>
<translation id="55635442646131152">Dokumentraamwerk</translation>
+<translation id="5565613213060953222">Maak Incognito-oortjie oop</translation>
<translation id="5565735124758917034">Aktief</translation>
<translation id="5570825185877910964">Beskerm rekening</translation>
<translation id="5571083550517324815">Kan nie by hierdie adres oplaai nie. Kies 'n ander adres.</translation>
@@ -1533,6 +1570,7 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="5869522115854928033">Gestoorde wagwoorde</translation>
<translation id="5873013647450402046">Jou bank wil bevestig dis jy.</translation>
<translation id="5887400589839399685">Kaart is gestoor</translation>
+<translation id="5887687176710214216">Gister laas besoek</translation>
<translation id="5895138241574237353">Herbegin</translation>
<translation id="5895187275912066135">Uitgereik op</translation>
<translation id="5901630391730855834">Geel</translation>
@@ -1546,6 +1584,7 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="5921639886840618607">Stoor kaart in Google-rekening?</translation>
<translation id="5922853866070715753">Amper klaar</translation>
<translation id="5932224571077948991">Werf wys indringerige of misleidende advertensies</translation>
+<translation id="5938153366081463283">Voeg virtuele kaart by</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347">Maak tans <ph name="SITE_NAME" /> oop …</translation>
<translation id="5951495562196540101">Kan nie met 'n verbruikerrekening inskryf nie (verpakte lisensie beskikbaar).</translation>
@@ -1610,6 +1649,7 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="6120179357481664955">Onthou jy jou UPI-ID?</translation>
<translation id="6124432979022149706">Chrome Enterprise-verbinders</translation>
<translation id="6127379762771434464">Item is verwyder</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Kom meer te wete oor Incognito in Chrome<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">Gaan alle kabels na en herselflaai enige roeteerders, modems of ander
netwerktoestelle wat jy gebruik.</translation>
<translation id="614940544461990577">Probeer:</translation>
@@ -1622,7 +1662,6 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="6169916984152623906">Jy kan nou privaat blaai en ander mense wat hierdie toestel gebruik sal nie jou aktiwiteit sien nie. Aflaaie en boekmerke sal egter gestoor word.</translation>
<translation id="6177128806592000436">Jou verbinding aan hierdie werf is nie veilig nie</translation>
<translation id="6180316780098470077">Herprobeer-interval</translation>
-<translation id="619448280891863779">Kan vra om vensters op jou skerms oop te maak en te plaas</translation>
<translation id="6196640612572343990">Blokkeer derdeparty-webkoekies</translation>
<translation id="6203231073485539293">Gaan jou internetverbinding na</translation>
<translation id="6218753634732582820">Verwyder adres uit Chromium?</translation>
@@ -1645,7 +1684,7 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="6272383483618007430">Google-opdatering</translation>
<translation id="6276112860590028508">Bladsye uit jou leeslys verskyn hier</translation>
<translation id="627746635834430766">Stoor jou kaart en faktureringadres in jou Google-rekening om volgende keer vinniger te betaal.</translation>
-<translation id="6279098320682980337">Is virtuelekaartnommer nie ingevul nie? Klik kaartbesonderhede om te kopieer</translation>
+<translation id="6279183038361895380">Druk |<ph name="ACCELERATOR" />| om jou merker te wys</translation>
<translation id="6280223929691119688">Kan nie by hierdie adres aflewer nie. Kies 'n ander adres.</translation>
<translation id="6282194474023008486">Poskode</translation>
<translation id="6285507000506177184">Knoppie om aflaaie in Chrome te bestuur; druk Enter om lêers wat jy in Chrome afgelaai het, te bestuur</translation>
@@ -1653,6 +1692,7 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="6290238015253830360">Jou voorgestelde artikels verskyn hier</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{Jou toestel sal nou herbegin}=1{Jou toestel sal oor 1 sekonde herbegin}other{Jou toestel sal oor # sekondes herbegin}}</translation>
<translation id="6302269476990306341">Google Assistent in Chrome stop tans</translation>
<translation id="6305205051461490394"><ph name="URL" /> is onbereikbaar.</translation>
<translation id="6312113039770857350">Webbladsy is nie beskikbaar nie</translation>
@@ -1726,6 +1766,7 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="6529602333819889595">Herdoen uitvee</translation>
<translation id="6545864417968258051">Bluetooth-opsporing</translation>
<translation id="6547208576736763147">Dubbelpons links</translation>
+<translation id="6554732001434021288">Laas <ph name="NUM_DAYS" /> dae gelede besoek</translation>
<translation id="6556866813142980365">Herdoen</translation>
<translation id="6569060085658103619">Jy bekyk tans 'n uitbreidingbladsy</translation>
<translation id="6573200754375280815">Dubbelpons regs</translation>
@@ -1786,7 +1827,6 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="6757797048963528358">Jou toestel het gaan slaap.</translation>
<translation id="6767985426384634228">Dateer adres op?</translation>
<translation id="6768213884286397650">Hagaki (Postcard)</translation>
-<translation id="6774185088257932239"><ph name="BEGIN_LINK" />Kom meer te wete<ph name="END_LINK" /> oor Incognito</translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">Pers</translation>
<translation id="6786747875388722282">Uitbreidings</translation>
@@ -1870,7 +1910,6 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="706295145388601875">Voeg adresse in Chrome-instellings by en bestuur hulle</translation>
<translation id="7064851114919012435">Kontakinligting</translation>
<translation id="7068733155164172741">Voer <ph name="OTP_LENGTH" />-syferkode in</translation>
-<translation id="7070090581017165256">Meer oor hierdie werf</translation>
<translation id="70705239631109039">Jou verbinding is nie heeltemal veilig nie</translation>
<translation id="7075452647191940183">Versoek is te groot</translation>
<translation id="7079718277001814089">Hierdie werf bevat wanware</translation>
@@ -1887,6 +1926,12 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="7111012039238467737">(Geldig)</translation>
<translation id="7118618213916969306">Soek vir knipbord-URL, <ph name="SHORT_URL" /></translation>
<translation id="7119414471315195487">Maak ander oortjies of programme toe</translation>
+<translation id="7129355289156517987">Jou aktiwiteit in oortjies word op hierdie toestel uitgevee wanneer jy alle Incognito-oortjies in Chromium toemaak:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Blaai-aktiwiteit<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Soekgeskiedenis<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Inligting wat op vorms ingevoer is<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">Kan nie na hierdie adres versend nie. Kies 'n ander adres.</translation>
<translation id="7132939140423847331">Jou admin het verbied dat hierdie data gekopieer word.</translation>
<translation id="7135130955892390533">Wys status</translation>
@@ -1909,6 +1954,7 @@ Dit sal andersins deur jou privaatheidinstellings geblokkeer word. Dit sal die i
<translation id="7192203810768312527">Maak <ph name="SIZE" /> beskikbaar. Sommige werwe sal dalk stadiger laai met jou volgende besoek.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">Jou administrateur kan sien:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, druk Tab en dan Enter om 'n nuwe Incognito-oortjie oop te maak om privaat te blaai</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> kom nie sekuriteitstandaarde na nie.</translation>
<translation id="7210993021468939304">Linux-aktiwiteit binne die houer, en kan Linux-programme binne die houer installeer en laat loop</translation>
@@ -1940,6 +1986,7 @@ Bykomende besonderhede:
<translation id="7304562222803846232">Bestuur Google-rekening se privaatheidsinstellings</translation>
<translation id="7305756307268530424">Begin stadiger</translation>
<translation id="7308436126008021607">agtergrondsinkronisering</translation>
+<translation id="7310392214323165548">Toestel sal binnekort herbegin</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">Verbindinghulp</translation>
<translation id="7323804146520582233">Versteek die "<ph name="SECTION" />"-afdeling</translation>
@@ -1947,6 +1994,7 @@ Bykomende besonderhede:
<translation id="7334320624316649418">Herdoen herrangskikking</translation>
<translation id="7335157162773372339">Kan vra om jou kamera te gebruik</translation>
<translation id="7337248890521463931">Wys meer reëls</translation>
+<translation id="7337418456231055214">Is virtuelekaartnommer nie ingevul nie? Klik kaartbesonderhede om te kopieer. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">Nie op jou platform beskikbaar nie.</translation>
<translation id="733923710415886693">Hierdie bediener se sertifikaat is nie via sertifikaatdeursigtigheid openbaar gemaak nie.</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1969,6 +2017,7 @@ Bykomende besonderhede:
<translation id="7378627244592794276">Nee</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">Nie van toepassing nie</translation>
+<translation id="7388594495505979117">{0,plural, =1{Jou toestel sal oor 1 minuut herbegin}other{Jou toestel sal oor # minute herbegin}}</translation>
<translation id="7390545607259442187">Bevestig kaart</translation>
<translation id="7392089738299859607">Dateer adres op</translation>
<translation id="7399802613464275309">Veiligheidskontrole</translation>
@@ -2005,6 +2054,12 @@ om uit te vind hoe om die sagteware permanent van jou rekenaar te verwyder&lt;/o
<translation id="7485870689360869515">Geen data gevind nie.</translation>
<translation id="7495528107193238112">Hierdie inhoud is geblokkeer. Kontak die werfeienaar om die kwessie reg te stel.</translation>
<translation id="7497998058912824456">Skep Dokument-knoppie – druk Enter om vinnig 'n nuwe Google-dokument te skep</translation>
+<translation id="7506488012654002225">Chromium sal nie die volgende inligting <ph name="BEGIN_EMPHASIS" />stoor nie<ph name="END_EMPHASIS" />:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Jou blaaigeskiedenis
+ <ph name="LIST_ITEM" />Webkoekies en werfdata
+ <ph name="LIST_ITEM" />Inligting wat op vorms ingevul is
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">Teruggestuurde beleidtoestel-ID is leeg of stem nie met huidige toestel-ID ooreen nie</translation>
<translation id="7508870219247277067">Avokadogroen</translation>
<translation id="7511955381719512146">Die Wi-Fi wat jy gebruik, kan vereis dat jy <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> besoek.</translation>
@@ -2118,7 +2173,6 @@ om uit te vind hoe om die sagteware permanent van jou rekenaar te verwyder&lt;/o
<translation id="7813600968533626083">Verwyder vormvoorstel uit Chrome?</translation>
<translation id="781440967107097262">Deel knipbord?</translation>
<translation id="7815407501681723534">Het <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> vir "<ph name="SEARCH_STRING" />" gevind</translation>
-<translation id="782125616001965242">Wys inligting oor hierdie werf</translation>
<translation id="782886543891417279">Die Wi-Fi wat jy gebruik (<ph name="WIFI_NAME" />), kan vereis dat jy sy aanmeldbladsy besoek.</translation>
<translation id="7836231406687464395">Postfix (Envelope)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{Geen}=1{1 program (<ph name="EXAMPLE_APP_1" />)}=2{2 programme (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}other{# programme (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}}</translation>
@@ -2135,7 +2189,6 @@ om uit te vind hoe om die sagteware permanent van jou rekenaar te verwyder&lt;/o
<translation id="7888575728750733395">Drukleweringvoorneme</translation>
<translation id="7894280532028510793">As die spelling korrek is, kan jy <ph name="BEGIN_LINK" />Netwerkdiagnostiek probeer gebruik<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (Envelope)</translation>
-<translation id="7931318309563332511">Onbekend</translation>
<translation id="793209273132572360">Dateer adres op?</translation>
<translation id="7932579305932748336">Bestryk</translation>
<translation id="79338296614623784">Voer 'n geldige foonnommer in</translation>
@@ -2160,13 +2213,14 @@ om uit te vind hoe om die sagteware permanent van jou rekenaar te verwyder&lt;/o
<translation id="7976214039405368314">Te veel versoeke</translation>
<translation id="7977538094055660992">Uitvoertoestel</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">Gekoppel met</translation>
<translation id="798134797138789862">Kan vra om virtuelerealiteittoestelle en -data te gebruik</translation>
<translation id="7984945080620862648">Jy kan nie <ph name="SITE" /> op die oomblik besoek nie, want die webwerf het deurmekaar eiebewyse gestuur wat Chrome nie kan verwerk nie. Netwerkfoute en aanvalle is gewoonlik tydelik en daarom sal hierdie bladsy waarskynlik later werk.</translation>
-<translation id="79859296434321399">Installeer ARCore om verhoogderealiteitinhoud te bekyk</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">Gebind</translation>
<translation id="7992044431894087211">Skermdeling met <ph name="APPLICATION_TITLE" /> is hervat</translation>
<translation id="7995512525968007366">Nie gespesifiseer nie</translation>
+<translation id="7998269595945679889">Maak Incognito-oortjie Oop-knoppie; druk Enter om 'n nuwe Incognito-oortjie oop te maak om privaat te blaai</translation>
<translation id="800218591365569300">Probeer ander oortjies of programme toemaak om berging beskikbaar te maak.</translation>
<translation id="8004582292198964060">Blaaier</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{Hierdie kaart en sy faktureringadres sal gestoor word. Jy sal dit kan gebruik wanneer jy by <ph name="USER_EMAIL" />aangemeld is.}other{Hierdie kaarte en hul faktureringadresse sal gestoor word. Jy sal hulle kan gebruik wanneer jy by <ph name="USER_EMAIL" /> aangemeld is.}}</translation>
@@ -2226,6 +2280,7 @@ om uit te vind hoe om die sagteware permanent van jou rekenaar te verwyder&lt;/o
<translation id="8202370299023114387">Konflik</translation>
<translation id="8206978196348664717">Prc4 (Envelope)</translation>
<translation id="8211406090763984747">Verbinding is veilig</translation>
+<translation id="8217240300496046857">Werwe kan nie webkoekies gebruik wat jou op die web naspoor nie. Kenmerke op sommige werwe kan breek.</translation>
<translation id="8218327578424803826">Toegewysde ligging:</translation>
<translation id="8220146938470311105">C7/C6 (Envelope)</translation>
<translation id="8225771182978767009">Die persoon wat hierdie rekenaar opgestel het, het besluit om hierdie werf te blokkeer.</translation>
@@ -2266,14 +2321,9 @@ om uit te vind hoe om die sagteware permanent van jou rekenaar te verwyder&lt;/o
<translation id="830498451218851433">Halfgevou</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">Programme wat geïnstalleer is en hoe gereeld hulle gebruik word</translation>
+<translation id="8317207217658302555">Dateer ARCore op?</translation>
<translation id="831997045666694187">Aand</translation>
<translation id="8321476692217554900">kennisgewings</translation>
-<translation id="8328484624016508118">Nadat alle Incognito-oortjies toegemaak is, vee Chrome die volgende uit:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Jou blaai-aktiwiteit op hierdie toestel<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Jou soekgeskiedenis op hierdie toestel<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Inligting wat op vorms ingevul is<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489">Toegang tot <ph name="HOST_NAME" /> is geweier</translation>
<translation id="833262891116910667">Merk</translation>
<translation id="8339163506404995330">Bladsye in <ph name="LANGUAGE" /> sal nie vertaal word nie</translation>
@@ -2325,6 +2375,7 @@ Bykomende besonderhede:
<translation id="8507227106804027148">Bevellyn</translation>
<translation id="8508648098325802031">Search-ikoon</translation>
<translation id="8511402995811232419">Bestuur webkoekies</translation>
+<translation id="8519753333133776369">HID-toestel word deur jou admin toegelaat</translation>
<translation id="8522552481199248698">Chrome kan jou help om jou Google-rekening te beskerm en jou wagwoord te verander.</translation>
<translation id="8530813470445476232">Vee jou blaaigeskiedenis, webkoekies, kasgeheue en meer in Chrome-instellings uit</translation>
<translation id="8533619373899488139">Besoek &lt;strong&gt;chrome://policy&lt;/strong&gt; om die lys geblokkeerde URL'e en ander beleide wat jou stelseladministrateur toepas te sien.</translation>
@@ -2336,7 +2387,6 @@ Bykomende besonderhede:
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{Stel toestemming terug}other{Stel toestemmings terug}}</translation>
<translation id="8555010941760982128">Gebruik hierdie kode by die betaalpunt</translation>
<translation id="8557066899867184262">Die CVC is agterop jou kaart.</translation>
-<translation id="8558485628462305855">Dateer ARCore op om verhoogderealiteitinhoud te bekyk</translation>
<translation id="8559762987265718583">'n Private verbinding aan <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> kan nie gevestig word nie omdat jou toestel se datum en tyd (<ph name="DATE_AND_TIME" />) verkeerd is.</translation>
<translation id="8564182942834072828">Afsonderlike dokumente/nie-ingesorteerde kopieë</translation>
<translation id="8564985650692024650">Chromium beveel aan dat jy jou <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" />-wagwoord terugstel as jy dit ook op ander werwe gebruik het.</translation>
@@ -2355,6 +2405,7 @@ Bykomende besonderhede:
<translation id="865032292777205197">bewegingsensors</translation>
<translation id="8663226718884576429">Bestellingopsomming, <ph name="TOTAL_LABEL" />, meer besonderhede</translation>
<translation id="8666678546361132282">Engels</translation>
+<translation id="8669306706049782872">Gebruik inligting oor jou skerms om vensters oop te maak en te plaas</translation>
<translation id="867224526087042813">Handtekening</translation>
<translation id="8676424191133491403">Geen wagperiode nie</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, antwoord, <ph name="ANSWER" /></translation>
@@ -2381,6 +2432,7 @@ Bykomende besonderhede:
<translation id="8731544501227493793">Bestuur Wagwoorde-knoppie; druk Enter om jou wagwoorde in Chrome-instellings te bekyk en te bestuur</translation>
<translation id="8734529307927223492">Jou <ph name="DEVICE_TYPE" /> word bestuur deur <ph name="MANAGER" /></translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, druk Tab en dan Enter om 'n nuwe incognitovenster oop te maak om privaat te blaai</translation>
+<translation id="8737685506611670901">Maak <ph name="PROTOCOL" />-skakels oop pleks van <ph name="REPLACED_HANDLER_TITLE" /></translation>
<translation id="8738058698779197622">Om 'n veilige verbinding te maak, moet jou horlosie reg gestel wees. Die rede hiervoor is omdat sertifikate wat webwerwe gebruik om hulself te identifiseer, net vir sekere tydperke beskikbaar is. Chromium kan nie hierdie sertifikate verifieer nie, omdat jou toestel se horlosie nie reg gestel is nie.</translation>
<translation id="8740359287975076522"><ph name="HOST_NAME" /> se &lt;abbr id="dnsDefinition"&gt;DNS-adres&lt;/abbr&gt; kon nie gevind word nie. Diagnoseer tans die probleem.</translation>
<translation id="8742371904523228557"><ph name="ONE_TIME_CODE" /> is jou kode vir <ph name="ORIGIN" /></translation>
@@ -2408,6 +2460,7 @@ Bykomende besonderhede:
<translation id="883848425547221593">Ander boekmerke</translation>
<translation id="884264119367021077">Versendingsadres</translation>
<translation id="884923133447025588">Geen herroepingmeganisme gevind nie.</translation>
+<translation id="8849262850971482943">Gebruik jou virtuele kaart vir bykomende sekuriteit</translation>
<translation id="885730110891505394">Deling met Google</translation>
<translation id="8858065207712248076">Chrome beveel aan dat jy jou <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" />-wagwoord terugstel as jy dit ook op ander werwe gebruik het.</translation>
<translation id="885906927438988819">As die spelling korrek is, kan jy <ph name="BEGIN_LINK" />Windows Network Diagnostics probeer gebruik<ph name="END_LINK" />.</translation>
@@ -2457,6 +2510,7 @@ Bykomende besonderhede:
<translation id="9004367719664099443">VR-sessie is aan die gang</translation>
<translation id="9005998258318286617">Kon nie 'n PDF-dokument laai nie.</translation>
<translation id="9008201768610948239">Ignoreer</translation>
+<translation id="901834265349196618">e-pos</translation>
<translation id="9020200922353704812">Kaart se faktureringadres word vereis</translation>
<translation id="9020542370529661692">Hierdie bladsy is in <ph name="TARGET_LANGUAGE" /> vertaal</translation>
<translation id="9020742383383852663">A8</translation>
@@ -2505,6 +2559,7 @@ Bykomende besonderhede:
<translation id="9150045010208374699">Gebruik jou kamera</translation>
<translation id="9150685862434908345">Jou administrateur kan jou blaaieropstelling oor 'n afstand verander. Aktiwiteit op hierdie toestel kan ook buite Chrome bestuur word. <ph name="BEGIN_LINK" />Kom meer te wete<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">Opgedateer</translation>
+<translation id="9155211586651734179">Oudiorandtoestelle is aangeheg</translation>
<translation id="9157595877708044936">Stel tans op …</translation>
<translation id="9158625974267017556">C6 (Envelope)</translation>
<translation id="9164029392738894042">Akkuraatheidkontrole</translation>
diff --git a/chromium/components/strings/components_strings_am.xtb b/chromium/components/strings/components_strings_am.xtb
index c141f39ecc0..5b266ecffb7 100644
--- a/chromium/components/strings/components_strings_am.xtb
+++ b/chromium/components/strings/components_strings_am.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">á‹áˆ­á‹áˆ®á‰½áŠ• ይመáˆáŠ¨á‰±</translation>
<translation id="1030706264415084469"><ph name="URL" /> ትáˆá‰… á‹áˆ‚ብ በእርስዎ መሣሪያ ላይ እስከ መጨረሻዠማከማቸት á‹­áˆáˆáŒ‹áˆ</translation>
<translation id="1032854598605920125">በሰዓት አቅጣጫ አሽከርክር</translation>
+<translation id="1033329911862281889">ማንáŠá‰µ የማያሳá‹á‰… በመስመር ላይ ስá‹áˆ­ አያደርገዎትáˆá¦
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ጣቢያዎች እና የሚጠቀሙባቸዠአገáˆáŒáˆŽá‰¶á‰½ ጉብáŠá‰¶á‰½áŠ• ማየት ይችላሉ<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />አሰሪዎች ወይሠትáˆáˆ…ርት ቤቶች የአሰሳ እንቅስቃሴን መከታተሠይችላሉ<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />የበይáŠáˆ˜áˆ¨á‰¥ አገáˆáŒáˆŽá‰µ አቅራቢዎች የድር ትራáŠáŠ­áŠ• መከታተሠይችላሉ<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">አጥá‹</translation>
<translation id="1036982837258183574">ከሙሉ ማያ ገጽ ለመá‹áŒ£á‰µ |<ph name="ACCELERATOR" />|ን ይጫኑ</translation>
<translation id="1038106730571050514">የአስተያየት ጥቆማዎችን አሳይ</translation>
<translation id="1038842779957582377">á‹«áˆá‰³á‹ˆá‰€ ስáˆ</translation>
<translation id="1041998700806130099">የስራ ሉህ መáˆá‹•áŠ­á‰µ</translation>
<translation id="1048785276086539861">ማብራሪያዎችን ሲያርትዑ ይህ ሰáŠá‹µ ወደ የáŠáŒ áˆ‹ ገጽ እይታ ይመለሳáˆ</translation>
-<translation id="1049743911850919806">ማንáŠá‰µ የማያሳá‹á‰…</translation>
<translation id="1050038467049342496">ሌሎች መተáŒá‰ áˆªá‹«á‹Žá‰½áŠ• á‹­á‹áŒ‰</translation>
<translation id="1055184225775184556">&amp;አክáˆáŠ• ቀáˆá‰¥áˆµ</translation>
<translation id="1056898198331236512">ማስጠንቀቂያ</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">የመáˆáˆªá‹« መሸጎጫ እሺ</translation>
<translation id="1130564665089811311">የገጽ ተርጉሠአá‹áˆ«áˆ­á£ ይህን ገጽ በGoogle ትርጉሠለመተርጎሠአስገባን ይጫኑá¢</translation>
<translation id="1131264053432022307">እርስዎ የቀዱት áˆáˆµáˆ</translation>
+<translation id="1142846828089312304">ማንáŠá‰µáŠ• በማያሳá‹á‰… áˆáŠá‰³ ላይ የሶስተኛ ወገን ኩኪዎችን á‹«áŒá‹±</translation>
<translation id="1150979032973867961">ይህ አገáˆáŒ‹á‹­ <ph name="DOMAIN" /> መሆኑን ሊያረጋáŒáŒ¥ አáˆá‰»áˆˆáˆá¤ የደህንáŠá‰µ እá‹á‰…ና ማረጋገጫዠበኮáˆá’á‹á‰°áˆ­á‹Ž ስርዓተ ክወና የሚታመን አይደለáˆá¢ ይሄ በተሳሳተ አወቃቀር ወይሠአንድ አጥቂ áŒáŠ•áŠ™áŠá‰µá‹ŽáŠ• በመጥለበየተከሰተ ሊሆን ይችላáˆá¢</translation>
<translation id="1151972924205500581">የይለá ቃሠያስáˆáˆáŒ‹áˆ</translation>
<translation id="1156303062776767266">አካባቢያዊ ወይሠየተጋራ á‹á‹­áˆ እየተመለከቱ áŠá‹</translation>
@@ -64,7 +70,6 @@
<translation id="1178581264944972037">ለአáታ አá‰áˆ</translation>
<translation id="1181037720776840403">አስወáŒá‹µ</translation>
<translation id="1186201132766001848">የይለá ቃላትዎን á‹­áˆá‰µáˆ¹</translation>
-<translation id="1195210374336998651">ወደ የመተáŒá‰ áˆªá‹« ቅንብሮች ይሂዱ</translation>
<translation id="1195558154361252544">እርስዎ ከáˆá‰€á‹±áˆ‹á‰¸á‹ ጣቢያዎች በስተቀር ማሳወቂያዎች ለáˆáˆ‰áˆ ጣቢያዎች በራስ-ሰር ይታገዳሉ</translation>
<translation id="1197088940767939838">ብርቱካናማ</translation>
<translation id="1201402288615127009">ቀጣይ</translation>
@@ -111,7 +116,7 @@
<translation id="1307966114820526988">የተቋረጡ ባህሪያት</translation>
<translation id="1308113895091915999">ቅናሽ ይገኛáˆ</translation>
<translation id="1312803275555673949">áˆáŠ• ማስረጃ á‹­á‹°áŒáˆá‹‹áˆ?</translation>
-<translation id="131405271941274527"><ph name="URL" /> የእርስዎን የNFC መሣሪያ መታ በሚያደርጉበት ጊዜ መረጃ መላክ እና መቀበሠይáˆáˆáŒ‹áˆ</translation>
+<translation id="1314311879718644478">የላቀ እá‹áŠá‰³ ይዘትን ይመáˆáŠ¨á‰±</translation>
<translation id="1314509827145471431">ወደቀአእጠá</translation>
<translation id="1318023360584041678">በትር ቡድን á‹áˆµáŒ¥ ተቀáˆáŒ§áˆ</translation>
<translation id="1319245136674974084">ለዚህ መተáŒá‰ áˆªá‹« ዳáŒáˆ አትጠይቅ</translation>
@@ -161,6 +166,7 @@
<translation id="142858679511221695">የደመና ተጠቃሚ</translation>
<translation id="1428729058023778569">ይህ ጣቢያ ኤችቲቲá’ኤስ ስለማይደáŒá ይህን ማስጠንቀቂያ እያዩ áŠá‹á¢ <ph name="BEGIN_LEARN_MORE_LINK" />የበለጠ ለመረዳት<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">አትáˆ</translation>
+<translation id="1432187715652018471">ገጽ የአገáˆáŒáˆŽá‰µ ተቆጣጣሪን መጫን á‹­áˆáˆáŒ‹áˆá¢</translation>
<translation id="1432581352905426595">የáለጋ á•áˆ®áŒáˆ«áˆžá‰½áŠ• ያቀናብሩ</translation>
<translation id="1436185428532214179">በመሣሪያዎ ላይ ያሉ á‹á‹­áˆŽá‰½áŠ• እና አቃáŠá‹Žá‰½áŠ• ለማርትዕ መጠየቅ ይችላáˆ</translation>
<translation id="1442386063175183758">ቀአበር እጠá</translation>
@@ -181,6 +187,12 @@
<translation id="1483493594462132177">ላክ</translation>
<translation id="1484290072879560759">የመላኪያ አድራሻ á‹­áˆáˆ¨áŒ¡</translation>
<translation id="1492194039220927094">የመመሪያዎች áŒáŠá‰µá¦</translation>
+<translation id="149293076951187737">áˆáˆ‰áŠ•áˆ የChrome ማንáŠá‰µ የማያሳá‹á‰ ትሮች ሲዘጉ በእáŠá‹šáˆ… ትሮች á‹áˆµáŒ¥ ያለዎት እንቅስቃሴ ከዚህ መሣሪያ ይጸዳáˆá¦
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />የአሰሳ እንቅስቃሴ<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />የáለጋ ታሪክ<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />በቅጾች á‹áˆµáŒ¥ የገባ መረጃ<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">ወደ ትር ተመለስ</translation>
<translation id="1501859676467574491">ከእርስዎ የGoogle መለያ ካርዶችን አሳይ</translation>
<translation id="1507202001669085618">&lt;p&gt;መስመር ላይ መሆን ከመቻáˆá‹Ž በáŠá‰µ በመለያ መáŒá‰£á‰µ የሚያስáˆáˆáŒá‰ á‰µ የWi-Fi መáŒá‰¢á‹« እየተጠቀሙ ከሆኑ ይህን ስህተት ይመለከታሉá¢&lt;/p&gt;
@@ -208,6 +220,8 @@
<translation id="1559572115229829303">&lt;p&gt;የእርስዎ መሣሪያ ቀን እና ሰዓት (<ph name="DATE_AND_TIME" />) ትክክሠስላáˆáˆ†áŠ‘ ወደ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> የáŒáˆ áŒáŠ•áŠ™áŠá‰µ ሊመሰረት አይችáˆáˆá¢&lt;/p&gt;
&lt;p&gt;እባክዎ በ&lt;strong&gt;ቅንብሮች&lt;/strong&gt; መተáŒá‰ áˆªá‹«á‹ የ&lt;strong&gt;አጠቃላይ&lt;/strong&gt; ክáሠላይ ቀን እና ሰዓቱን ያስተካክሉá¢&lt;/p&gt;</translation>
+<translation id="1559839503761818503">የእርስዎ አስተዳዳሪ መሣሪያዎን በ<ph name="DATE" /> <ph name="TIME" /> ላይ እንደገና ያስጀáˆáˆ¨á‹‹áˆá¢</translation>
+<translation id="156703335097561114">እንደ አድራሻዎችᣠየበይáŠáŒˆáŒ½ á‹á‰…ረት እና የáŒáŠ•áŠ™áŠá‰µ ጥራት ያሉ የአá‹á‰³áˆ¨ መረብ መረጃ</translation>
<translation id="1567040042588613346">ይህ መመሪያ እንደታሰበዠእየሰራ áŠá‹á£ áŠáŒˆáˆ­ áŒáŠ• ተመሳሳይ እሴት በሌላ ቦታ የተቀናበረ ሲሆን በዚህ መመሪያ ተተክቷáˆá¢</translation>
<translation id="1569487616857761740">የጊዜ ማብቂያ ቀን ያስገቡ</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@
<translation id="1583429793053364125">ይህን ድረ-ገጽ በማሳየት ላይ ሳለ የሆአችáŒáˆ­ ተáˆáŒ¥áˆ¯áˆá¢</translation>
<translation id="1586541204584340881">የትኛዎቹ ቅጥያዎች ናቸዠእርስዎ የጫኑት</translation>
<translation id="1588438908519853928">መደበኛ</translation>
+<translation id="1589050138437146318">ARCore ይጫን?</translation>
<translation id="1592005682883173041">አካባቢያዊ የá‹áˆ‚ብ መድረሻ</translation>
<translation id="1594030484168838125">áˆáˆ¨áŒ¥</translation>
<translation id="160851722280695521">በChrome á‹áˆµáŒ¥ የDino አሂድ ጨዋታ አጫá‹á‰µ</translation>
@@ -254,7 +269,7 @@
<translation id="1711234383449478798"><ph name="POLICY_NAME" /> ወደ <ph name="VALUE" /> ስላáˆá‰°á‰€áŠ“በረ ችላ ተብáˆáˆá¢</translation>
<translation id="1712552549805331520"><ph name="URL" /> á‹áˆ‚ብ በአካባቢያዊ ኮáˆá’á‹á‰°áˆ­á‹Ž ላይ እስከመጨረሻዠማከማቸት á‹­áˆáˆáŒ‹áˆ</translation>
<translation id="1713628304598226412">መሳቢያ 2</translation>
-<translation id="1715874602234207">F</translation>
+<translation id="1715874602234207">á‹“</translation>
<translation id="1717218214683051432">የእንቅስቃሴ ዳሳሾች</translation>
<translation id="1717494416764505390">የመáˆá‹•áŠ­á‰µ ሳጥን 3</translation>
<translation id="1718029547804390981">ሰáŠá‹µ ለመብራራት ከáˆáŠ­ በላይ ትáˆá‰… áŠá‹</translation>
@@ -279,6 +294,7 @@
<translation id="1763864636252898013">ይህ አገáˆáŒ‹á‹­ <ph name="DOMAIN" /> መሆኑን ሊያረጋáŒáŒ¥ አáˆá‰»áˆˆáˆá¤ የደህንáŠá‰µ እá‹á‰…ና ማረጋገጫዠበመሣሪያዎ ስርዓተ ክወና የሚታመን አይደለáˆá¢ ይሄ በተሳሳተ አወቃቀር ወይሠአንድ አጥቂ áŒáŠ•áŠ™áŠá‰µá‹ŽáŠ• በመጥለበየተከሰተ ሊሆን ይችላáˆá¢</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />የWindows አá‹á‰³áˆ¨ መረብ መመርመሪያá‹áŠ• ለማሄድ ይሞክሩ<ph name="END_LINK" />á¢</translation>
<translation id="1772163372082567643">እየሄዱበት ያለዠአገáˆáŒ‹á‹­ <ph name="ORIGIN" /> ወደ እሱ በሚደረጉ áˆáˆ‰áˆ ጥያቄዎች ላይ የáˆáŠ•áŒ­ መመሪያ እንዲተገብር የሚáˆáˆáŒ ራስጌ አቀናብሯáˆá¢ áŠáŒˆáˆ­ áŒáŠ• ራስጌዠየተበላሸ áŠá‹á£ ይህ አሳሹ <ph name="SITE" /> ጥያቄዎን እንዳያሟላ ይከለክለዋáˆá¢ የáˆáŠ•áŒ­ መመሪያዎች በጣቢያ ሥርዓት ከዋáŠáŠžá‰½ የደኅንáŠá‰µ እና ሌላ ባሕሪያትን ለጣቢያዠለማዋቀር ጥቅሠላይ ሊá‹áˆ ይችላáˆá¢</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />በChromium á‹áˆµáŒ¥ ስላለ ማንáŠá‰µ የማያሳá‹á‰… ተጨማሪ ይወá‰<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">የእርስዎ ክáት ትሮች እዚህ ይመጣሉ</translation>
<translation id="1791429645902722292">Google ዘመናዊ á‰áˆá</translation>
@@ -406,6 +422,7 @@
<translation id="22081806969704220">መሳቢያ 3</translation>
<translation id="2212735316055980242">መመሪያ አáˆá‰°áŒˆáŠ˜áˆ</translation>
<translation id="2213606439339815911">áŒá‰¤á‰¶á‰½áŠ• በማáˆáŒ£á‰µ ላይ...</translation>
+<translation id="2213612003795704869">ገጽ ታትሟáˆ</translation>
<translation id="2215727959747642672">የá‹á‹­áˆ አርትዖት አደራረáŒ</translation>
<translation id="2218879909401188352">በ<ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ላይ አáˆáŠ• ያሉ አጥቂዎች የእርስዎን መሣሪያ የሚያበላሹ አደገኛ መተáŒá‰ áˆªá‹«á‹Žá‰½áŠ• ሊጭኑᣠበእርስዎ ሞባይሠክáá‹« መጠየቂያ ላይ የተደበበክáá‹« መጠየቂያዎችን ሊያክሉ ወይሠየእርስዎን የáŒáˆ መረጃ ሊሰርበይችላሉᢠ<ph name="BEGIN_LEARN_MORE_LINK" />የበለጠ ለመረዳት<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">áˆáŠ•áˆ በይáŠáˆ˜áˆ¨á‰¥ የለáˆ</translation>
@@ -415,6 +432,7 @@
<translation id="2248949050832152960">WebAuthnን ተጠቀáˆ</translation>
<translation id="2250931979407627383">በáŒáˆ« በኩሠጫá‰áŠ• ስá‹á¢</translation>
<translation id="225207911366869382">ይህ ዋጋ ለዚህ መመሪያ ተቋርጧáˆá¢</translation>
+<translation id="2256115617011615191">አáˆáŠ• ዳáŒáˆ አስጀáˆáˆ­</translation>
<translation id="2258928405015593961">ለወደáŠá‰± የአገáˆáŒáˆŽá‰µ ጊዜ ማብቂያ ቀን ያስገቡና እንደገና ይሞክሩ</translation>
<translation id="225943865679747347">የስህተት ኮድᦠ<ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">የኤች ቲ ቲ ᒠስህተት</translation>
@@ -442,6 +460,7 @@
<translation id="2337852623177822836">ቅንብር በአስተዳዳሪዎ áŠá‹ á‰áŒ¥áŒ¥áˆ­ የሚደረáŒá‰ á‰µ</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> መጣመር á‹­áˆáˆáŒ‹áˆ</translation>
<translation id="2346319942568447007">እርስዎ የቀዱት áˆáˆµáˆ</translation>
+<translation id="2350796302381711542"><ph name="HANDLER_HOSTNAME" /> ከ<ph name="REPLACED_HANDLER_TITLE" /> á‹­áˆá‰… áˆáˆ‰áŠ•áˆ የ<ph name="PROTOCOL" /> አገናኞች እንዲከáት á‹­áˆá‰€á‹µáˆˆá‰µ?</translation>
<translation id="2354001756790975382">ሌላ እáˆá‰£á‰¶á‰½</translation>
<translation id="2354430244986887761">Google የጥንቃቄ አሰሳ በቅርብ ጊዜ በ<ph name="SITE" /> ላይ <ph name="BEGIN_LINK" />ጎጂ መተáŒá‰ áˆªá‹«á‹Žá‰½áŠ• አáŒáŠá‰·áˆ<ph name="END_LINK" />á¢</translation>
<translation id="2355395290879513365">አጥቂዎች በዚህ ጣቢያ ላይ እርስዎ እየተመለከቱዋቸዠያሉ áˆáˆµáˆŽá‰½áŠ• ማየት እና በላያቸዠላይ ለá‹áŒ¦á‰½áŠ• በማድረጠሊያታáˆáˆá‹Žá‰µ ይችሉ ይሆናáˆá¢</translation>
@@ -467,6 +486,7 @@
<translation id="2413528052993050574">ይህ አገáˆáŒ‹á‹­ <ph name="DOMAIN" /> መሆኑን ሊያረጋáŒáŒ¥ አáˆá‰»áˆˆáˆá¤ የደህንáŠá‰µ እá‹á‰…ና ማረጋገጫዠተሽሮ ሊሆን ይችላáˆá¢ ይሄ በተሳሳተ አወቃቀር ወይሠአንድ አጥቂ áŒáŠ•áŠ™áŠá‰µá‹ŽáŠ• በመጥለበየተከሰተ ሊሆን ይችላáˆá¢</translation>
<translation id="2414886740292270097">ጨለማ</translation>
<translation id="2430968933669123598">Google መለያን ያስተዳድሩᣠበGoogle መለያዎ á‹áˆµáŒ¥ የእርስዎን መረጃᣠáŒáˆ‹á‹ŠáŠá‰µ እና ደህንáŠá‰µ ለማስተዳደር አስገባን ይጫኑ</translation>
+<translation id="2436186046335138073"><ph name="HANDLER_HOSTNAME" /> áˆáˆ‰áŠ•áˆ የ<ph name="PROTOCOL" /> አገናኞች እንዲከáት á‹­áˆá‰€á‹µáˆˆá‰µ?</translation>
<translation id="2438874542388153331">በቀአበኩሠአራቴ ብሳ</translation>
<translation id="2450021089947420533">ጉዞዎች</translation>
<translation id="2463739503403862330">ሙላ</translation>
@@ -474,6 +494,7 @@
<translation id="2465655957518002998">የማድረሻ ዘዴ á‹­áˆáˆ¨áŒ¡</translation>
<translation id="2465688316154986572">ስቴá•áˆˆáˆ­ áˆá‰³</translation>
<translation id="2465914000209955735">በChrome á‹áˆµáŒ¥ ያወረዷቸá‹áŠ• á‹á‹­áˆŽá‰½ ያቀናብሩ</translation>
+<translation id="2466004615675155314">ከድሩ መረጃ አሳይ</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />የአá‹á‰³áˆ¨ መረብ መመርመሪያን በማሄድ ላይ<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">1-ለN ቅደáˆ-ተከተáˆ</translation>
<translation id="2470767536994572628">ማብራሪያዎችን ሲያርትዑ ይህ ሰáŠá‹µ ወደ የáŠáŒ áˆ‹ ገጽ እይታ እና የመጀመሪያዠማዞር ይመለሳáˆ</translation>
@@ -494,6 +515,7 @@
<translation id="2523886232349826891">በዚህ መሣሪያ ላይ ብቻ ይቀመጣáˆ</translation>
<translation id="2524461107774643265">ተጨማሪ መረጃ ያክሉ</translation>
<translation id="2529899080962247600">ይህ መስክ ከ<ph name="MAX_ITEMS_LIMIT" /> áŒá‰¤á‰¶á‰½ በላይ ሊኖሩት አይገባáˆá¢ áˆáˆ‰áˆ ተጨማሪ áŒá‰¤á‰¶á‰½ ችላ ይባላሉá¢</translation>
+<translation id="2535585790302968248">በáŒáˆ ለማሰስ አዲስ ማንáŠá‰µáŠ• የማያሳá‹á‰… ትርን ክáˆá‰µ</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{እና 1 ተጨማሪ}one{እና # ተጨማሪ}other{እና # ተጨማሪ}}</translation>
<translation id="2536110899380797252">አድራሻ ያክሉ</translation>
<translation id="2539524384386349900">አáŒáŠ</translation>
@@ -519,7 +541,14 @@
<translation id="2597378329261239068">ይህ ሰáŠá‹µ በይለá ቃሠየተጠበቀ áŠá‹á¢ እባክዎ የይለá ቃሠያስገቡá¢</translation>
<translation id="2609632851001447353">áˆá‹©áŠá‰¶á‰½</translation>
<translation id="2610561535971892504">ለመቅዳት ጠቅ ያድርጉ</translation>
+<translation id="2617988307566202237">Chrome የሚከተለá‹áŠ• መረጃ <ph name="BEGIN_EMPHASIS" />አያስቀáˆáŒ¥áˆ<ph name="END_EMPHASIS" />á¦
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />የእርስዎ የአሰሳ ታሪክ
+ <ph name="LIST_ITEM" />ኩኪዎች እና የጣቢያ á‹áˆ‚ብ
+ <ph name="LIST_ITEM" />በቅጾች ላይ የገባዠመረጃ
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (የደብዳቤ á–ስታ)</translation>
+<translation id="2623663032199728144">ስለማያ ገጾችዎ ያለ መረጃን ለመጠቀሠመጠየቅ ይችላሉ</translation>
<translation id="2625385379895617796">የእርስዎ ሰዓት ገና የወደáŠá‰µ áŠá‹</translation>
<translation id="262745152991669301">ከዩኤስቢ መሣሪያዎች ጋር ለመገናኘት መጠየቅ ይችላáˆ</translation>
<translation id="2629325967560697240">የChrome ከáተኛዠየደህንáŠá‰µ ደረጃን ለማáŒáŠ˜á‰µ <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />የተሻሻለá‹áŠ• ጥበቃ ያብሩ<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -553,6 +582,7 @@
<translation id="2709516037105925701">ራስ-ሙላ</translation>
<translation id="2713444072780614174">áŠáŒ­</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />ᣠትር ይጫኑᣠከዚያ የእርስዎን ክáያዎች እና የክሬዲት ካርድ መረጃ በChrome ቅንብሮች á‹áˆµáŒ¥ ለማቀናበር አስገባን ይጫኑ</translation>
+<translation id="271663710482723385">ከሙሉ ገጽ ዕይታ ለመá‹áŒ£á‰µ |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />|ን ይጫኑ</translation>
<translation id="2721148159707890343">ጥያቄ ተሳክቷáˆ</translation>
<translation id="2723669454293168317">በChrome ቅንብሮች á‹áˆµáŒ¥ የደህንáŠá‰µ áተሻን ያሂዱ</translation>
<translation id="2726001110728089263">የጎን መሳቢያ</translation>
@@ -583,6 +613,7 @@
<translation id="2850739647070081192">áŒá‰¥á‹£ (የደብዳቤ á–ስታ)</translation>
<translation id="2856444702002559011">አጥቂዎች የእርስዎን መረጃ (ለáˆáˆ³áˆŒá¦ የይለá ቃላትንᣠመáˆá‹•áŠ­á‰¶á‰½áŠ•á£ ወይሠየክሬዲት ካርዶችን የመሳሰሉ) ከ<ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ለመስረቅ እየሞከሩ ሊሆኑ ይችላሉᢠ<ph name="BEGIN_LEARN_MORE_LINK" />የበለጠ ለመረዳት<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">ይህ ጣቢያ ረባሽ ወይሠአሳሳች ማስታወቂያዎችን ያሳያáˆá¢</translation>
+<translation id="286512204874376891">áˆáŠ“ባዊ ካርድ እርስዎን ሊሆን ከሚችሠማጭበርበር ለመጠበቅ እንዲረዳዎት ትክክለኛá‹áŠ• ካርድዎን አስመስሎ ይደብቀዋáˆá¢ <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">የወዳጅáŠá‰µ</translation>
<translation id="2876489322757410363">በá‹áŒ«á‹Š ማከማቻ በኩሠለማጫወት ማንáŠá‰µ ከማያሳá‹á‰… áˆáŠá‰³ በመá‹áŒ£á‰µ ላይᢠይቀጥáˆ?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />ᣠበChrome ቅንብሮች á‹áˆµáŒ¥ የጥንቃቄ አሰሳዎን እና ተጨማሪ áŠáŒˆáˆ®á‰½áŠ• ለማቀናበር ትርን ከዚያ አስገባን ይጫኑ</translation>
@@ -607,6 +638,7 @@
<translation id="2930577230479659665">ከእያንዳንዱ ቅጂ በኋላ ከርክáˆ</translation>
<translation id="2932085390869194046">የይለá ቃሠጠá‰áˆ...</translation>
<translation id="2934466151127459956">መንáŒáˆµá‰µ-ደብዳቤ</translation>
+<translation id="2938225289965773019"><ph name="PROTOCOL" /> አገናኞችን ክáˆá‰µ</translation>
<translation id="2941952326391522266">ይህ አገáˆáŒ‹á‹­ <ph name="DOMAIN" /> መሆኑን ሊያረጋáŒáŒ¥ አáˆá‰»áˆˆáˆá¤ የደህንáŠá‰µ እá‹á‰…ና ማረጋገጫዠበ<ph name="DOMAIN2" /> áŠá‹ የተሰጠá‹á¢ ይሄ በተሳሳተ አወቃቀር ወይሠአንድ አጥቂ áŒáŠ•áŠ™áŠá‰µá‹ŽáŠ• በመጥለበየተከሰተ ሊሆን ይችላáˆá¢</translation>
<translation id="2943895734390379394">የሰቀላ ጊዜá¦</translation>
<translation id="2948083400971632585">ከቅንብሮች ገጽ ሆáŠá‹ ማናቸá‹áŠ•áˆ ለáŒáŠ•áŠ™áŠá‰µ የተዋቀሩ ተኪዎችን ማሰናከሠይችላሉá¢</translation>
@@ -639,6 +671,7 @@
<translation id="3037605927509011580">á‹á‹­á£ ተሰናከለ!</translation>
<translation id="3041612393474885105">የሰርቲáŠáŠ¬á‰µ መረጃ</translation>
<translation id="3044034790304486808">áˆáˆ­áˆáˆ­á‹ŽáŠ• ከቆመበት ይቀጥሉ</translation>
+<translation id="305162504811187366">የጊዜ ማህተሞችᣠአስተናጋጆች እና የደንበኛ ክáለ-ጊዜ መታወቂያዎችን ጨáˆáˆ® Chrome የርቀት ዴስክቶᕠታሪክ</translation>
<translation id="3060227939791841287">C9 (የደብዳቤ á–ስታ)</translation>
<translation id="3061707000357573562">የመጠገኛ አገáˆáŒáˆŽá‰µ</translation>
<translation id="306573536155379004">ጨዋታዠተጀáˆáˆ¯áˆá¢</translation>
@@ -678,6 +711,7 @@
<translation id="3197136577151645743">ይህን መሣሪያ በንቃት ሲጠቀሙ ለማወቅ መጠየቅ ይችላáˆ</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />ᣠበChrome ቅንብሮች á‹áˆµáŒ¥ áˆáŠ• መረጃ እንደሚያሰáˆáˆ© ለማቀናበር ትርን ከዚያ አስገባን ይጫኑ</translation>
<translation id="320323717674993345">ክáያን ሰርá‹</translation>
+<translation id="3203366800380907218">ከድሩ</translation>
<translation id="3207960819495026254">á‹•áˆá‰£á‰µ ተደርጎበታáˆ</translation>
<translation id="3209034400446768650">ገጽ ገንዘብ ሊያስከáሠይችሠይሆናáˆ</translation>
<translation id="3212581601480735796">በ<ph name="HOSTNAME" /> ላይ የእርስዎ እንቅስቃሴ á‰áŒ¥áŒ¥áˆ­ እየተደረገበት áŠá‹</translation>
@@ -694,10 +728,12 @@
<translation id="3234666976984236645">áˆáˆáŒŠá‹œ በዚህ ጣቢያ ላይ ያለ አስáˆáˆ‹áŒŠ ይዘትን አáŒáŠ</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />ᣠየአሳሽዎን መáˆáŠ­ ለማበጀት ትርን ከዚያ አስገባን ይጫኑ</translation>
<translation id="3240791268468473923">ደህንáŠá‰± የተጠበቀ የመáŒá‰¢á‹« ማስረጃ áˆáŠ•áˆ ተዛማጅ የመáŒá‰¢á‹« ማስረጃ ሉህ አáˆá‰°áŠ¨áˆá‰°áˆ</translation>
+<translation id="324180406144491771">የ«<ph name="HOST_NAME" />» አገናኞች ታáŒá‹°á‹‹áˆ</translation>
<translation id="3249845759089040423">ቅጥ ያለá‹</translation>
<translation id="3252266817569339921">áˆáˆ¨áŠ•áˆ³á‹­áŠ›</translation>
<translation id="3257954757204451555">ከዚህ መረጃ በስተጀርባ ያለዠማáŠá‹?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />ᣠበGoogle ቀን መá‰áŒ áˆªá‹« á‹áˆµáŒ¥ አዲስ ክስተት በáጥáŠá‰µ ለመáጠር ትርን ከዚያ አስገባን ይጫኑ</translation>
+<translation id="3261488570342242926">ስለáˆáŠ“ባዊ ካርዶች ይወá‰</translation>
<translation id="3264837738038045344">የChrome ቅንብሮች አá‹áˆ«áˆ­áŠ• ያቀናብሩᣠየChrome ቅንብሮችዎን ለመጎብኘት አስገባን ይጫኑ</translation>
<translation id="3266793032086590337">እሴት (áŒáŒ­á‰µ)</translation>
<translation id="3268451620468152448">ክáት ትሮች</translation>
@@ -711,6 +747,7 @@
<translation id="3288238092761586174"><ph name="URL" /> ክáያዎን ለማረጋገጥ ተጨማሪ እርáˆáŒƒá‹Žá‰½áŠ• መá‹áˆ°á‹µ ሊáˆáˆáŒ ይችላáˆ</translation>
<translation id="3293642807462928945">ስለ<ph name="POLICY_NAME" /> መመሪያዠተጨማሪ ይወá‰</translation>
<translation id="3295444047715739395">በChrome ቅንብሮች á‹áˆµáŒ¥ የእርስዎን የይለá ቃላት ይመáˆáŠ¨á‰± እና ያስተዳድሩ</translation>
+<translation id="3303795387212510132"><ph name="PROTOCOL_SCHEME" /> አገናኞችን እንዲከáት ለመተáŒá‰ áˆªá‹« á‹­áˆá‰€á‹µáˆˆá‰µ?</translation>
<translation id="3303855915957856445">áˆáŠ•áˆ የáለጋ á‹áŒ¤á‰¶á‰½ አáˆá‰°áŒˆáŠ™áˆ</translation>
<translation id="3304073249511302126">የብሉቱዠቅáŠá‰µ</translation>
<translation id="3308006649705061278">ድርጅታዊ መስáˆáˆ­á‰µ (OU)</translation>
@@ -724,12 +761,6 @@
<translation id="3345782426586609320">አይኖች</translation>
<translation id="3355823806454867987">የተኪ ቅንብሮችን በመቀየር ላይ...</translation>
<translation id="3360103848165129075">የክáá‹« ተቆጣጣሪ ሉህ</translation>
-<translation id="3361596688432910856">Chrome የሚከተሉትን መረጃዎች <ph name="BEGIN_EMPHASIS" />አያስቀáˆáŒ¥áˆ<ph name="END_EMPHASIS" />á¦
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />የእርስዎ የአሰሳ ታሪክ
- <ph name="LIST_ITEM" />ኩኪዎች እና የጣቢያ á‹áˆ‚ብ
- <ph name="LIST_ITEM" />በቅጾች á‹áˆµáŒ¥ የገባ መረጃ
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">ይህ መመሪያ በራስ-ሰር ከተቋረጠዠየ<ph name="OLD_POLICY" /> መመሪያ የተቀዳ áŠá‹á¢ በáˆá‰µáŠ© ይህን መመሪያ መጠቀሠአለብዎትá¢</translation>
<translation id="3364869320075768271"><ph name="URL" /> የእርስዎን áˆáŠ“ባዊ እá‹áŠá‰³ መሣሪያ እና á‹áˆ‚ብ መጠቀሠይáˆáˆáŒ‹áˆ</translation>
<translation id="3366477098757335611">ካርዶችን ይመáˆáŠ¨á‰±</translation>
@@ -812,7 +843,6 @@
<translation id="3587738293690942763">መሃáˆ</translation>
<translation id="3592413004129370115">ጣáˆá‹«áŠ•áŠ› (የደብዳቤ á–ስታ)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{ቡድንዎን በማንኛá‹áˆ ጊዜ ዳáŒáˆ ማስጀመር ይችላሉᢠአዲስ ቡድን ለመቀላቀሠአንድ ቀን ያህሠጊዜ ይወስዳáˆá¢}=1{ቡድንዎን በማንኛá‹áˆ ጊዜ ዳáŒáˆ ማስጀመር ይችላሉᢠአዲስ ቡድን ለመቀላቀሠአንድ ቀን ያህሠጊዜ ይወስዳáˆá¢}one{ቡድንዎን በማንኛá‹áˆ ጊዜ ዳáŒáˆ ማስጀመር ይችላሉᢠአዲስ ቡድን ለመቀላቀሠ{NUM_DAYS} ቀኖች ያህሠጊዜ ይወስዳáˆá¢}other{ቡድንዎን በማንኛá‹áˆ ጊዜ ዳáŒáˆ ማስጀመር ይችላሉᢠአዲስ ቡድን ለመቀላቀሠ{NUM_DAYS} ቀኖች ያህሠጊዜ ይወስዳáˆá¢}}</translation>
-<translation id="3596012367874587041">የመተáŒá‰ áˆªá‹« ቅንብሮች</translation>
<translation id="3600246354004376029"><ph name="TITLE" />ᣠ<ph name="DOMAIN" />ᣠ<ph name="TIME" /></translation>
<translation id="3603507503523709">መተáŒá‰ áˆªá‹« በእርስዎ አስተዳዳሪ ታáŒá‹·áˆ</translation>
<translation id="3608932978122581043">የáˆáŒˆá‰£ አቀማመጥ</translation>
@@ -855,6 +885,7 @@
<translation id="370972442370243704">ጉዞዎችን ያብሩ</translation>
<translation id="3711895659073496551">አንጠáˆáŒ¥áˆ</translation>
<translation id="3712624925041724820">áˆáˆ‰áˆ áቃዶች ተሞክረዋáˆ</translation>
+<translation id="3714633008798122362">የድር ቀን መá‰áŒ áˆªá‹«</translation>
<translation id="3714780639079136834">የሞባይሠá‹áˆ‚ብ ወይሠWi-Fi ማብራት</translation>
<translation id="3715597595485130451">ከWi-Fi ጋር ይገናኙ</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />ወኪሉንᣠኬላá‹áŠ• እና የዲኤንኤስ á‹á‰…ረትን መáˆá‰°áˆ½<ph name="END_LINK" /></translation>
@@ -916,6 +947,7 @@
<translation id="3906954721959377182">ጡባዊ</translation>
<translation id="3909477809443608991"><ph name="URL" /> የተጠበቀ ይዘትን ማጫወት á‹­áˆáˆáŒ‹áˆá¢ የመሣሪያዎ ማንáŠá‰µ በGoogle የሚረጋገጥ ሲሆን በዚህ ጣቢያ ሊደረስበት ይችላáˆá¢</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">ከáˆáŠ­áˆ</translation>
<translation id="3939773374150895049">ከCVC á‹­áˆá‰… WebAuthnን ይጠቀሙ?</translation>
<translation id="3946209740501886391">áˆáˆáŒŠá‹œ በዚህ ጣቢያ ላይ ጠይቅ</translation>
<translation id="3947595700203588284">ከMIDI መሣሪያዎች ጋር ለመገናኘት መጠየቅ ይችላáˆ</translation>
@@ -937,6 +969,7 @@
<translation id="3990250421422698716">ሕትመት አጠናቅ</translation>
<translation id="3996311196211510766">የ<ph name="ORIGIN" /> ጣቢያ የመጀመሪያ መመሪያ
በáˆáˆ‰áˆ ወደ እሱ በተላኩ ጥያቄዎች ላይ ተáˆáŒ»áˆš እንዲሆን ጠይቋáˆá£ áŠáŒˆáˆ­ áŒáŠ• ይህ መመሪያ በአáˆáŠ‘ ጊዜ ሊተገበር አይችáˆáˆá¢</translation>
+<translation id="4009243425692662128">እርስዎ የሚያትሙት የገጾች ይዘት ለትንተና ወደ Google ደመና ወይሠሶስተኛ ወገኖች ይላካáˆá¢ ለáˆáˆ³áˆŒá£ አደጋን ሊያስከትሠለሚችሠá‹áˆ‚ብ ሊቃኙ ይችላሉá¢</translation>
<translation id="4010758435855888356">የማከማቻ መዳረሻ á‹­áˆá‰€á‹µ?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{{COUNT} ገጽ የያዘ የá’ዲኤá ሰáŠá‹µ}one{{COUNT} ገጾችን የያዘ የá’ዲኤá ሰáŠá‹µ}other{{COUNT} ገጾችን የያዘ የá’ዲኤá ሰáŠá‹µ}}</translation>
<translation id="4023431997072828269">ይህ ቅጽ ደህንáŠá‰± በማያስተማáˆáŠ• áŒáŠ•áŠ™áŠá‰µ በመጠቀሠእየገባ ያለ ስለሆአየእርስዎ መረጃ ለሌሎች የሚታይ ይሆናáˆá¢</translation>
@@ -1028,6 +1061,7 @@
<translation id="4250680216510889253">አይ</translation>
<translation id="4253168017788158739">ማስታወሻ</translation>
<translation id="425582637250725228">ያደረጓቸዠለá‹áŒ¦á‰½ ላይቀመጡ ይችላሉá¢</translation>
+<translation id="425869179292622354">በáˆáŠ“ባዊ ካርድ ደህንáŠá‰± ይበáˆáŒ¥ የተጠበቀ á‹­áˆáŠ•?</translation>
<translation id="4258748452823770588">መጥᎠáŠáˆ­áˆ›</translation>
<translation id="4261046003697461417">ጥበቃ የሚደረáŒáˆ‹á‰¸á‹ ሰáŠá‹¶á‰½ ሊብራሩ አይችሉáˆ</translation>
<translation id="4265872034478892965">በእርስዎ አስተዳዳሪ የተáˆá‰€á‹°</translation>
@@ -1090,6 +1124,7 @@
<translation id="4434045419905280838">ብቅ-ባዮች እና አቅጣጫ ማዞሮች</translation>
<translation id="4435702339979719576">የá–ስታ ካርድ)</translation>
<translation id="443673843213245140">የተኪ መጠቀሠተሰናክáˆáˆ áŒáŠ• áŒáˆáŒ½ የሆአየተኪ á‹á‰…ር ተገáˆáŒ¿áˆá¢</translation>
+<translation id="4441832193888514600">መመሪያዠሊዋቀር የሚችለዠእንደ ደመና ተጠቃሚ መመሪያ ብቻ ስለሆአችላ ተብáˆáˆá¢</translation>
<translation id="4450893287417543264">ዳáŒáˆ አታሳይ</translation>
<translation id="4451135742916150903">ከHID መሣሪያዎች ጋር ለመገናኘት መጠየቅ ይችላáˆ</translation>
<translation id="4452328064229197696">አáˆáŠ• የተጠቀሙበት የይለá ቃሠበá‹áˆ‚ብ ጥሰት á‹áˆµáŒ¥ ተገáŠá‰·áˆá¢ የእርስዎን መለያዎች ደህንáŠá‰µ ለመጠበቅᣠGoogle የይለá ቃሠአስተዳዳሪ የተቀመጡ የይለá ቃላትዎን እንዲáˆá‰µáˆ¹ ይመክራáˆá¢</translation>
@@ -1145,6 +1180,7 @@
<translation id="4628948037717959914">áŽá‰¶</translation>
<translation id="4631649115723685955">ከተመላሽ ገንዘብ ጋር ተገናáŠá‰·áˆ</translation>
<translation id="4636930964841734540">መረጃ</translation>
+<translation id="4638670630777875591">በChromium á‹áˆµáŒ¥ ማንáŠá‰µ የማያሳá‹á‰…</translation>
<translation id="464342062220857295">ባህሪያትን á‹­áˆáˆáŒ‰</translation>
<translation id="4644670975240021822">ተቃራኒ ቅደáˆ-ተከተሠáŠá‰± ወደ ታች</translation>
<translation id="4646534391647090355">አáˆáŠ• ወደዚያ á‹áˆ°á‹°áŠ</translation>
@@ -1165,6 +1201,7 @@
<translation id="4708268264240856090">የእርስዎ áŒáŠ•áŠ™áŠá‰µ ተቋርጧáˆ</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />የWindows አá‹á‰³áˆ¨ መረብ መመርመሪያን በማሄድ ላይ<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426">የ<ph name="USERNAME" /> ይለá ቃáˆ</translation>
<translation id="4724144314178270921">በቅንጥብ ሰሌዳዎ ላይ ጽሑáን እና áˆáˆµáˆŽá‰½áŠ• ለማየት መጠየቅ ይችላáˆ</translation>
<translation id="4726672564094551039">መáˆáˆªá‹«á‹Žá‰½áŠ• ዳáŒáˆ ጫን</translation>
<translation id="4728558894243024398">መድረክ</translation>
@@ -1186,6 +1223,7 @@
<translation id="4757993714154412917">አáˆáŠ• የይለá ቃáˆá‹ŽáŠ• በአንድ አታላይ ጣቢያ ላይ አስገብተዋáˆá¢ የእርስዎን መለያዎች ደህንáŠá‰µ ለመጠበቅ Chromium የተቀመጡ ይለá ቃላትዎን መáˆá‰°áˆ½ ይመክራáˆá¢</translation>
<translation id="4758311279753947758">የእá‹á‰‚á‹« መረጃን ያክሉ</translation>
<translation id="4761104368405085019">ማይክáŽáˆ®áŠ•á‹ŽáŠ• ይጠቀማáˆ</translation>
+<translation id="4761869838909035636">የChrome ደህንáŠá‰µ áተሻን ያሂዱ</translation>
<translation id="4764776831041365478"><ph name="URL" /> ላይ ያለዠድረ-ገጽ ለጊዜዠየማይሰራ ወይሠእስከመጨረሻዠወደ አዲስ የድር አድራሻ ተዛá‹áˆ® ሊሆን ይችላáˆá¢</translation>
<translation id="4766713847338118463">ድርብ ከታች ስቴá•áˆˆáˆ­ áˆá‰³</translation>
<translation id="4771973620359291008">á‹«áˆá‰³á‹ˆá‰€ ስህተት ተከስቷáˆá¢</translation>
@@ -1206,12 +1244,6 @@
<translation id="4819347708020428563">በáŠá‰£áˆª እይታ á‹áˆµáŒ¥ ማብራሪያዎችን ያርትዑ?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />ᣠአዲስ Google ሉህ በáጥáŠá‰µ ለመáጠር ትርን ከዚያ አስገባን ይጫኑ</translation>
<translation id="4825507807291741242">ኃይለኛ</translation>
-<translation id="4827402517081186284">ማንáŠá‰µ የማያሳá‹á‰… በመስመር ላይ ስá‹áˆ­ አያደርገዎትáˆá¦
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />ጣቢያዎች እርስዎ ሲጎበኟቸዠያá‹á‰ƒáˆ‰<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />አሰሪዎች ወይሠትáˆáˆ…ርት ቤቶች የአሰሳ እንቅስቃሴን መከታተሠይችላሉ<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />የበይáŠáˆ˜áˆ¨á‰¥ አገáˆáŒáˆŽá‰µ አቅራቢዎች የድር ትራáŠáŠ­áŠ• ሊከታተሉ ይችላሉ<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">ማስጠንቀቂያዎችን አብራ</translation>
<translation id="4838327282952368871">ህáˆáˆ˜áŠ›</translation>
<translation id="4840250757394056958">የChrome ታሪክዎን ይመáˆáŠ¨á‰±</translation>
@@ -1223,12 +1255,12 @@
<translation id="4854362297993841467">የማድረሻ ዘዴዠአይገáŠáˆá¢ የተለየ ዘዴ ይሞክሩá¢</translation>
<translation id="4854853140771946034">በGoogle Keep á‹áˆµáŒ¥ አዲስ ማስታወሻ በáጥáŠá‰µ áጠር</translation>
<translation id="485902285759009870">ኮድ በማረጋገጥ ላይ...</translation>
+<translation id="4866506163384898554">የእርስዎን ጠቋሚ ለማሳየት |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| ይጫኑ</translation>
<translation id="4876188919622883022">የተቃለለ እይታ</translation>
<translation id="4876305945144899064">áˆáŠ•áˆ የተጠቃሚ ስሠየለáˆ</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{áˆáŠ•áˆ}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />ᣠ<ph name="EXAMPLE_DOMAIN_2" />}one{<ph name="EXAMPLE_DOMAIN_1" />ᣠ<ph name="EXAMPLE_DOMAIN_2" />ᣠ<ph name="AND_MORE" />}other{<ph name="EXAMPLE_DOMAIN_1" />ᣠ<ph name="EXAMPLE_DOMAIN_2" />ᣠ<ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831">የ<ph name="TEXT" /> áለጋ</translation>
<translation id="4879491255372875719">ራስ-ሰር (áŠá‰£áˆª)</translation>
-<translation id="4879725228911483934">በእርስዎ ማያ ገጾች ላይ መስኮቶችን ይክáˆá‰± እና ይመድቡ</translation>
<translation id="4880827082731008257">የáለጋ ታሪክ</translation>
<translation id="4881695831933465202">ክáት የሚሆንባቸá‹</translation>
<translation id="4885256590493466218">ከáሎ መá‹áŒ«á‹ ላይ በ<ph name="CARD_DETAIL" /> ይክáˆáˆ‰</translation>
@@ -1237,6 +1269,7 @@
<translation id="4895877746940133817"><ph name="TYPE_1" />ᣠ<ph name="TYPE_2" />á£, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">ዘጠáŠáŠ› ጥቅáˆáˆ</translation>
<translation id="4901778704868714008">አስቀáˆáŒ¥...</translation>
+<translation id="4905659621780993806">የእርስዎ አስተዳዳሪ መሣሪያዎን በ<ph name="DATE" /> <ph name="TIME" /> ላይ በራስ-ሰር ዳáŒáˆ ያስáŠáˆ³á‹‹áˆá¢ መሣሪያዎ ዳáŒáˆ ከመáŠáˆ³á‰± በáŠá‰µ ማናቸá‹áŠ•áˆ ክáት ንጥሎች ያስቀáˆáŒ¡á¢</translation>
<translation id="4913987521957242411">ከላይ በáŒáˆ« ብሳ</translation>
<translation id="4918221908152712722"><ph name="APP_NAME" />ን ይጫኑ (áˆáŠ•áˆ ማá‹áˆ¨á‹µ አያስáˆáˆáŒáˆ)</translation>
<translation id="4923459931733593730">ክáá‹«</translation>
@@ -1245,6 +1278,7 @@
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />ᣠትሩን ተጫን ከዛ ለመáˆáˆˆáŒ አስገባ</translation>
<translation id="4930153903256238152">ትáˆá‰… የመያዠአቅáˆ</translation>
+<translation id="4940163644868678279">በChrome á‹áˆµáŒ¥ ያለ ማንáŠá‰µ የማያሳá‹á‰…</translation>
<translation id="4943872375798546930">á‹áŒ¤á‰¶á‰½ የሉáˆ</translation>
<translation id="4950898438188848926">የትር መቀየሪያ አá‹áˆ«áˆ­á£ ወደ ክáቱ ትር <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /> ለመቀየር Enterን ይጫኑ</translation>
<translation id="495170559598752135">እርáˆáŒƒá‹Žá‰½</translation>
@@ -1254,6 +1288,7 @@
<translation id="4968522289500246572">ይህ መተáŒá‰ áˆªá‹« ለሞባይሠየተáŠá‹°áˆ áŠá‹á£ እና በጥሩ áˆáŠ”ታ መጠን ላይቀይር ይችላáˆá¢ መተáŒá‰ áˆªá‹«á‹ ችáŒáˆ®á‰½ ሊያጋጥሙት ወይሠዳáŒáˆ ሊáŠáˆ³ ይችላáˆá¢</translation>
<translation id="4969341057194253438">ቀረጻ ሰርá‹</translation>
<translation id="4973922308112707173">ከላይ áˆáˆˆá‰´ ብሳ</translation>
+<translation id="4976702386844183910">ለመጨረሻ ጊዜ የተጎበኘዠበ<ph name="DATE" /></translation>
<translation id="4984088539114770594">ማይክáŽáˆ®áŠ• ይጠቀáˆ?</translation>
<translation id="4984339528288761049">Prc5 (የደብዳቤ á–ስታ)</translation>
<translation id="4989163558385430922">áˆáˆ‰áŠ•áˆ ይመáˆáŠ¨á‰±</translation>
@@ -1315,6 +1350,7 @@
<translation id="5138227688689900538">á‹«áŠáˆ° አሳይ</translation>
<translation id="5145883236150621069">የስህተት ኮድ በመáˆáˆªá‹«á‹ áˆáˆ‹áˆ½ á‹áˆµáŒ¥ አለ</translation>
<translation id="5146995429444047494">ለ <ph name="ORIGIN" /> ማሳወቂያዎች ታáŒá‹°á‹‹áˆ</translation>
+<translation id="514704532284964975"><ph name="URL" /> በኤንኤáሲ መሣሪያዎች ላይ በስáˆáŠ®á‹Ž መታ የሚያደርጉትን መረጃ ማየት እና መለወጥ á‹­áˆáˆáŒ‹áˆ</translation>
<translation id="5148809049217731050">áŠá‰µ ወደ ላይይ</translation>
<translation id="515292512908731282">C4 (የደብዳቤ á–ስታ)</translation>
<translation id="5158275234811857234">ሽá‹áŠ•</translation>
@@ -1339,6 +1375,7 @@
<translation id="5215116848420601511">Google Payን የሚጠቀሙ የመክáˆá‹« ዘዴዎች እና አድራሻዎች</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">መሳቢያ 13</translation>
+<translation id="5216942107514965959">መጨረሻ የተጎበኘዠዛሬ</translation>
<translation id="5222812217790122047">ኢሜይሠያስáˆáˆáŒ‹áˆ</translation>
<translation id="5230733896359313003">የሚላክበት አድራሻ</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1359,7 +1396,6 @@
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">የሰáŠá‹µ ባሕሪያት</translation>
<translation id="528468243742722775">ጨርስ</translation>
-<translation id="5284909709419567258">የአá‹á‰³áˆ¨ መረብ አድራሻዎች</translation>
<translation id="5285570108065881030">áˆáˆ‰áŠ•áˆ የተቀመጡ የይለá ቃላት አሳይ</translation>
<translation id="5287240709317226393">ኩኪዎችን አሳይ</translation>
<translation id="5287456746628258573">ይህ ጣቢያ ጊዜ ያለáˆá‰ á‰µ የደህንáŠá‰µ á‹á‰…ረትን ይጠቀማáˆá£ ይህ ወደዚህ ጣቢያ ሲላክ መረጃዎን (ለáˆáˆ³áˆŒá¦ የይለá ቃላት ወይሠየክሬዲት ካርድ á‰áŒ¥áˆ®á‰½) ሊያጋáˆáŒ¥ ይችላáˆá¢</translation>
@@ -1443,6 +1479,7 @@
<translation id="5556459405103347317">ዳáŒáˆ ጫን</translation>
<translation id="5560088892362098740">አገáˆáŒáˆŽá‰± የሚያበቃበት ቀን</translation>
<translation id="55635442646131152">የሰáŠá‹µ ቢጋር</translation>
+<translation id="5565613213060953222">ማንáŠá‰µ የማያሳá‹á‰… ትርን ክáˆá‰µ</translation>
<translation id="5565735124758917034">ገባሪ</translation>
<translation id="5570825185877910964">መለያን ጠብቅ</translation>
<translation id="5571083550517324815">ከዚህ አድራሻ ላይ መá‹áˆ°á‹µ አይቻáˆáˆá¢ የተለየ አድራሻ á‹­áˆáˆ¨áŒ¡á¢</translation>
@@ -1525,6 +1562,7 @@
<translation id="5869522115854928033">የተቀመጡ የይለá ቃሎች</translation>
<translation id="5873013647450402046">ባንክዎ እርስዎ መሆንዎን ማረጋገጥ á‹­áˆáˆáŒ‹áˆá¢</translation>
<translation id="5887400589839399685">ካርድ ተቀáˆáŒ§áˆ</translation>
+<translation id="5887687176710214216">ለመጨረሻ ጊዜ የተጎበኘዠትላንትና</translation>
<translation id="5895138241574237353">እንደገና ጀáˆáˆ­</translation>
<translation id="5895187275912066135">በዚህ ቀን ቀርቧáˆ</translation>
<translation id="5901630391730855834">ቢጫ</translation>
@@ -1538,6 +1576,7 @@
<translation id="5921639886840618607">ወደ Google መለያ ካርድ ይቀመጥ?</translation>
<translation id="5922853866070715753">በቃ ሊያáˆá‰… áŠá‹</translation>
<translation id="5932224571077948991">ጣቢያ ረባሽ ወይሠአሳሳች ማስታወቂያዎችን ያሳያáˆ</translation>
+<translation id="5938153366081463283">áˆáŠ“ባዊ ካርድ ያክሉ</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347"><ph name="SITE_NAME" />ን በመክáˆá‰µ ላይ…</translation>
<translation id="5951495562196540101">በሸማች መለያ መመá‹áŒˆá‰¥ አይቻáˆáˆ (የጥቅሠáˆá‰ƒá‹µ ይገኛáˆ)á¢</translation>
@@ -1602,6 +1641,7 @@
<translation id="6120179357481664955">የእርስዎን UPI መታወቂያ ያስታá‹áˆ³áˆ‰?</translation>
<translation id="6124432979022149706">Chrome Enterprise አያያዦች</translation>
<translation id="6127379762771434464">ንጥሠተወáŒá‹·áˆ</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />በChrome á‹áˆµáŒ¥ ስለማንáŠá‰µ የማያሳá‹á‰… ተጨማሪ ይወá‰<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">ማናቸá‹áˆ ገመዶችን á‹­áˆá‰µáˆ¹áŠ“ እየተጠቀሙ ሊሆኑ የሚችáˆá‰¸á‹áŠ• ማንኛá‹áˆ ራá‹á‰°áˆ®á‰½á£
ሞደሞችን ወይሠሌላ አá‹á‰³áˆ¨ መረብ መሣሪያዎችን ዳáŒáˆ ያስጀáˆáˆ©á¢</translation>
<translation id="614940544461990577">ይሞክሩá¦</translation>
@@ -1614,7 +1654,6 @@
<translation id="6169916984152623906">አáˆáŠ• በáŒáˆ ማሰስ ይችላሉᣠእና ይህን መሣሪያ የሚጠቀሙ ሰዎች የእርስዎን እንቅስቃሴ አይመለከቱáˆá¢ á‹­áˆáŠ•áŠ“ᣠá‹áˆ­á‹¶á‰½ እና á‹•áˆá‰£á‰¶á‰½ ይቀመጣሉá¢</translation>
<translation id="6177128806592000436">ወደዚህ ጣቢያ á‹«áˆá‹Žá‰µ áŒáŠ•áŠ™áŠá‰µ ደህንáŠá‰± አስተማማአአይደለáˆ</translation>
<translation id="6180316780098470077">የዳáŒáˆ መሞከር ክáተት</translation>
-<translation id="619448280891863779">በማያ ገጾችዎ ላይ መስኮቶችን ለመክáˆá‰µ እና ለማስቀመጥ መጠየቅ ይችላáˆ</translation>
<translation id="6196640612572343990">የሦስተኛ ወገን ኩኪዎችን አáŒá‹µ</translation>
<translation id="6203231073485539293">የበይáŠáˆ˜áˆ¨á‰¥ áŒáŠ‘áŠáŠá‰µá‹ŽáŠ• ያረጋáŒáŒ¡</translation>
<translation id="6218753634732582820">ከChromium ላይ አድራሻ ይወገድ?</translation>
@@ -1637,7 +1676,7 @@
<translation id="6272383483618007430">የGoogle á‹áˆ›áŠ”</translation>
<translation id="6276112860590028508">ከእርስዎ የንባብ á‹áˆ­á‹áˆ­ የመጡ ገጾች እዚህ ይታያሉ</translation>
<translation id="627746635834430766">በሚቀጥለዠጊዜ በበለጠ áጥáŠá‰µ ለመክáˆáˆ ካርድዎን እና የማስከáˆá‹« አድራሻዎን በGoogle መለያዎ ላይ ያስቀáˆáŒ¡á¢</translation>
-<translation id="6279098320682980337">የáˆáŠ“ባዊ ካርድ á‰áŒ¥áˆ­ አáˆá‰°áˆžáˆ‹áˆ? የሚቀዱ የካርድ á‹áˆ­á‹áˆ®á‰½áŠ• ጠቅ ያድርጉ</translation>
+<translation id="6279183038361895380">የእርስዎን ጠቋሚ ለማሳየት |<ph name="ACCELERATOR" />| ይጫኑ</translation>
<translation id="6280223929691119688">ወደዚህ አድራሻ ማድረስ አይቻáˆáˆá¢ የተለየ አድራሻ á‹­áˆáˆ¨áŒ¡á¢</translation>
<translation id="6282194474023008486">የá–ስታ ኮድ</translation>
<translation id="6285507000506177184">በChrome አá‹áˆ«áˆ­ á‹áˆµáŒ¥ á‹áˆ­á‹¶á‰½áŠ• ያቀናብሩᣠበChrome á‹áˆµáŒ¥ ያወረዷቸá‹áŠ• á‹á‹­áˆŽá‰½ ለማቀናበር አስገባን ይጫኑ</translation>
@@ -1645,6 +1684,7 @@
<translation id="6290238015253830360">የእርስዎ የተጠቆሙ ዘገባዎች እዚህ ይመጣሉ</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">ካርድ ማረጋገጫ ኮድá¦</translation>
+<translation id="6300452962057769623">{0,plural, =0{መሣሪያዎ አáˆáŠ• ዳáŒáˆ á‹­áŠáˆ³áˆ}=1{መሣሪያዎ በ1 ሰከንድ á‹áˆµáŒ¥ ዳáŒáˆ á‹­áŠáˆ³áˆ}one{መሣሪያዎ በ# ሰከንዶች á‹áˆµáŒ¥ ዳáŒáˆ á‹­áŠáˆ³áˆ}other{መሣሪያዎ በ# ሰከንዶች á‹áˆµáŒ¥ ዳáŒáˆ á‹­áŠáˆ³áˆ}}</translation>
<translation id="6302269476990306341">በChrome á‹áˆµáŒ¥ Google ረዳት እያቆመ áŠá‹</translation>
<translation id="6305205051461490394"><ph name="URL" /> ሊደረስበት አይችáˆáˆá¢</translation>
<translation id="6312113039770857350">ድረ-ገጽ አይገáŠáˆ</translation>
@@ -1718,6 +1758,7 @@
<translation id="6529602333819889595">&amp;ሰርá‹áŠ• ድገáˆ</translation>
<translation id="6545864417968258051">የብሉቱዠቅáŠá‰µ</translation>
<translation id="6547208576736763147">በáŒáˆ« በኩሠብሳ</translation>
+<translation id="6554732001434021288">ለመጨረሻ ጊዜ የተጎበኘዠከ<ph name="NUM_DAYS" /> ቀናት በáŠá‰µ áŠá‹</translation>
<translation id="6556866813142980365">ድገáˆ</translation>
<translation id="6569060085658103619">የቅጥያ ገጽ እየተመለከቱ áŠá‹</translation>
<translation id="6573200754375280815">ድርብ ብስ ቀáŠ</translation>
@@ -1778,7 +1819,6 @@
<translation id="6757797048963528358">የእርስዎ መሣሪያ ተáŠá‰·áˆá¢</translation>
<translation id="6767985426384634228">አድራሻ ይዘáˆáŠ•?</translation>
<translation id="6768213884286397650">ሃጋኪ (á–ስታ ካርድ)</translation>
-<translation id="6774185088257932239">ማንáŠá‰µ ስለማያሳá‹á‰… áˆáŠá‰³ <ph name="BEGIN_LINK" />የበለጠ ይወá‰<ph name="END_LINK" /></translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">ወይን ጠጅ</translation>
<translation id="6786747875388722282">ቅጥያዎች</translation>
@@ -1862,7 +1902,6 @@
<translation id="706295145388601875">በChrome ቅንብሮች á‹áˆµáŒ¥ አድራሻዎችን ያክሉ እና ያቀናብሩ</translation>
<translation id="7064851114919012435">የእá‹á‰‚á‹« መረጃ</translation>
<translation id="7068733155164172741">ባለ<ph name="OTP_LENGTH" />-አኃዠኮድ ያስገቡ</translation>
-<translation id="7070090581017165256">ስለዚህ ጣቢያ</translation>
<translation id="70705239631109039">የእርስዎ áŒáŠ•áŠ™áŠá‰µ ደህንáŠá‰µ ሙሉ ለሙሉ አይደለሠየተጠበቀá‹</translation>
<translation id="7075452647191940183">ጥያቄ ከáˆáŠ­ በላይ áŒá‹™á áŠá‹</translation>
<translation id="7079718277001814089">ይህ ጣቢያ ተንኮáˆ-አዘሠዌር á‹­á‹Ÿáˆ</translation>
@@ -1879,6 +1918,12 @@
<translation id="7111012039238467737">(የሚሰራ)</translation>
<translation id="7118618213916969306">የቅንጥብ ሰሌዳ ዩአርኤሠ<ph name="SHORT_URL" /> á‹­áˆáˆáŒ‰</translation>
<translation id="7119414471315195487">ሌሎች ትሮችን ወይሠá•áˆ®áŒáˆ«áˆžá‰½áŠ• á‹­á‹áŒ‰</translation>
+<translation id="7129355289156517987">áˆáˆ‰áŠ•áˆ የChromium ማንáŠá‰µ የማያሳá‹á‰ ትሮች ሲዘጉ በእáŠá‹šáˆ… ትሮች á‹áˆµáŒ¥ ያለዎት እንቅስቃሴ ከዚህ መሣሪያ ይጸዳáˆá¦
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />የአሰሳ እንቅስቃሴ<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />የáለጋ ታሪክ<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />በቅጾች á‹áˆµáŒ¥ የገባ መረጃ<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">ወደዚህ አድራሻ መላክ አይቻáˆáˆá¢ የተለየ አድራሻ á‹­áˆáˆ¨áŒ¡á¢</translation>
<translation id="7132939140423847331">የእርስዎ አስተዳዳሪ ይህ á‹áˆ‚ብ እንዳይቀዳ ከáˆáŠ­áˆáˆá¢</translation>
<translation id="7135130955892390533">áˆáŠ”ታን አሳይ</translation>
@@ -1901,6 +1946,7 @@
<translation id="7192203810768312527">እስከ <ph name="SIZE" /> ያስለቅቃáˆá¢ አንዳንድ ጣቢያዎች በሚቀጥለዠጉብáŠá‰µá‹Ž ላይ ይበáˆáŒ¥ በá‹áŒá‰³ ሊጫኑ ይችላሉá¢</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">የእርስዎ አስተዳዳሪ እáŠá‹šáˆ…ን መመáˆáŠ¨á‰µ ይችላáˆá¦</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />ᣠትርን ይጫኑና ከዚያ በáŒáˆ እንዲያስሱ አዲስ ማንáŠá‰µ የማያሳá‹á‰… ትርን ለመክáˆá‰µ አስገባን ይጫኑ</translation>
<translation id="7202346780273620635">ደብዳቤ-ተጨማሪ</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> የደህንáŠá‰µ መስáˆáˆ­á‰¶á‰½áŠ• አያከብርáˆá¢</translation>
<translation id="7210993021468939304">በመያዣዠá‹áˆµáŒ¥ ያለ የLinux እንቅስቃሴᣠእና በመያዣዠá‹áˆµáŒ¥ የLinux መተáŒá‰ áˆªá‹«á‹Žá‰½áŠ• መጫንና ማሄድ ይችላáˆ</translation>
@@ -1932,6 +1978,7 @@
<translation id="7304562222803846232">የGoogle መለያ áŒáˆ‹á‹ŠáŠá‰µ ቅንብሮችን ያስተዳድሩ</translation>
<translation id="7305756307268530424">በá‹áŒá‰³ ይጀáˆáˆ©</translation>
<translation id="7308436126008021607">የዳራ ስáˆáˆ¨á‰µ</translation>
+<translation id="7310392214323165548">መሣሪያዠበጣሠበቅርቡ እንደገና ይጀáˆáˆ«áˆ</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">የáŒáŠ•áŠ™áŠá‰µ እገዛ</translation>
<translation id="7323804146520582233">የ«<ph name="SECTION" />» ክáሉን ሰርá‹</translation>
@@ -1939,6 +1986,7 @@
<translation id="7334320624316649418">&amp;ማስተካከáˆáŠ• ድገáˆ</translation>
<translation id="7335157162773372339">ካሜራዎን ለመጠቀሠመጠየቅ ይችላሉ</translation>
<translation id="7337248890521463931">ተጨማሪ መስመሮችን አሳይ</translation>
+<translation id="7337418456231055214">የáˆáŠ“ባዊ ካርድ á‰áŒ¥áˆ­ አáˆá‰°áˆžáˆ‹áˆ? የሚቀዱ የካርድ á‹áˆ­á‹áˆ®á‰½áŠ• ጠቅ ያድርጉᢠ<ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">በእርስዎ የመሣሪያ ስርዓት ላይ አይገáŠáˆá¢</translation>
<translation id="733923710415886693">የአገáˆáŒ‹á‹© የእá‹á‰…ና ማረጋገጫ በእá‹á‰…ና ማረጋገጫ áŒáˆáŒ½áŠá‰µ በኩሠአáˆá‰°áŒˆáˆˆáŒ¸áˆá¢</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1961,6 +2009,7 @@
<translation id="7378627244592794276">አይ</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">አይመለከተá‹áˆ</translation>
+<translation id="7388594495505979117">{0,plural, =1{መሣሪያዎ በ1 ደቂቃ á‹áˆµáŒ¥ ዳáŒáˆ á‹­áŠáˆ³áˆ}one{መሣሪያዎ በ# ደቂቃዎች á‹áˆµáŒ¥ ዳáŒáˆ á‹­áŠáˆ³áˆ}other{መሣሪያዎ በ# ደቂቃዎች á‹áˆµáŒ¥ ዳáŒáˆ á‹­áŠáˆ³áˆ}}</translation>
<translation id="7390545607259442187">ካርድ ያረጋáŒáŒ¡</translation>
<translation id="7392089738299859607">አድራሻን ያዘáˆáŠ‘</translation>
<translation id="7399802613464275309">የደህንáŠá‰µ áተሻ</translation>
@@ -1997,6 +2046,12 @@
<translation id="7485870689360869515">áˆáŠ•áˆ á‹áˆ‚ብ አáˆá‰°áŒˆáŠ˜áˆá¢</translation>
<translation id="7495528107193238112">ይህ ይዘት ታáŒá‹·áˆá¢ ችáŒáˆ©áŠ• ለማስተካከሠየጣቢያá‹áŠ• ባለቤት á‹«áŠáŒ‹áŒáˆ©á¢</translation>
<translation id="7497998058912824456">የሰáŠá‹µ አá‹áˆ«áˆ­áŠ• á‹­áጠሩᣠአዲስ Google ሰáŠá‹µ በáጥáŠá‰µ ለመáጠር አስገባን ይጫኑ</translation>
+<translation id="7506488012654002225">Chromium የሚከተለá‹áŠ• መረጃ <ph name="BEGIN_EMPHASIS" />አያስቀáˆáŒ¥áˆ<ph name="END_EMPHASIS" />á¦
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />የእርስዎ የአሰሳ ታሪክ
+ <ph name="LIST_ITEM" />ኩኪዎች እና የጣቢያ á‹áˆ‚ብ
+ <ph name="LIST_ITEM" />በቅጾች ላይ የገባዠመረጃ
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">የተመላሽ መመሪያ መሣሪያ መታወቂያ ባዶ áŠá‹ ወይሠከአáˆáŠ‘ የመሣሪያ መታወቂያ ጋር አይዛመድáˆ</translation>
<translation id="7508870219247277067">አቮካዶ አረንጓዴ</translation>
<translation id="7511955381719512146">እየተጠቀሙበት ያለዠWi-Fi <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />ን እንዲጎበኙ ሊጠይቅዎት ይችላáˆá¢</translation>
@@ -2110,7 +2165,6 @@
<translation id="7813600968533626083">የአስተያየት ጥቆማ ከChrome ይወገድ?</translation>
<translation id="781440967107097262">ቅንጥብ ሰሌዳ ይጋራ?</translation>
<translation id="7815407501681723534">ለ«<ph name="SEARCH_STRING" />» <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> ተገáŠá‰°á‹‹áˆá¢</translation>
-<translation id="782125616001965242">ስለዚህ ጣቢያ መረጃን አሳይ</translation>
<translation id="782886543891417279">እየተጠቀሙበት ያለዠWi-Fi (<ph name="WIFI_NAME" />) በመለያ መáŒá‰¢á‹« ገጹን እንዲጎበኙ ሊጠይቅዎት ይችላáˆá¢</translation>
<translation id="7836231406687464395">Postfix (የደብዳቤ á–ስታ)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{áˆáŠ•áˆ}=1{1 መተáŒá‰ áˆªá‹« (<ph name="EXAMPLE_APP_1" />)}=2{2 መተáŒá‰ áˆªá‹«á‹Žá‰½ (<ph name="EXAMPLE_APP_1" />ᣠ<ph name="EXAMPLE_APP_2" />)}one{# መተáŒá‰ áˆªá‹«á‹Žá‰½ (<ph name="EXAMPLE_APP_1" />ᣠ<ph name="EXAMPLE_APP_2" />ᣠ<ph name="AND_MORE" />)}other{# መተáŒá‰ áˆªá‹«á‹Žá‰½ (<ph name="EXAMPLE_APP_1" />ᣠ<ph name="EXAMPLE_APP_2" />ᣠ<ph name="AND_MORE" />)}}</translation>
@@ -2127,7 +2181,6 @@
<translation id="7888575728750733395">የህትመት áˆáˆµáˆ ስራ áˆáˆ³á‰¥</translation>
<translation id="7894280532028510793">የáŠá‹°áˆ አጻጻበትክክሠከሆአ<ph name="BEGIN_LINK" />የአá‹á‰³áˆ¨ መረብ áˆáˆ­áˆ˜áˆ«áŠ• ለማስኬድ ይሞክሩ<ph name="END_LINK" />á¢</translation>
<translation id="7904208859782148177">C3 (የደብዳቤ á–ስታ)</translation>
-<translation id="7931318309563332511">á‹«áˆá‰³á‹ˆá‰€</translation>
<translation id="793209273132572360">አድራሻ ይዘáˆáŠ•?</translation>
<translation id="7932579305932748336">ኮት</translation>
<translation id="79338296614623784">የሚሰራ ስáˆáŠ­ á‰áŒ¥áˆ­ ያስገቡ</translation>
@@ -2152,13 +2205,14 @@
<translation id="7976214039405368314">በጣሠብዙ ጥያቄዎች</translation>
<translation id="7977538094055660992">የá‹áŒ½á‹“ት መሣሪያ</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">ተገናáŠá‰·áˆ ከ</translation>
<translation id="798134797138789862">áˆáŠ“ባዊ የእá‹áŠá‰³ መሣሪያዎችን እና á‹áˆ‚ብን ለመጠቀሠመጠየቅ ይችላáˆ</translation>
<translation id="7984945080620862648">ድር ጣቢያዠChrome ሊሰራባቸዠየማይችላቸዠየተዘበራረበáˆáˆµáŠ­áˆ­áŠá‰¶á‰½áŠ• ስለላከ <ph name="SITE" />ን አáˆáŠ• መጎብኘት ይችላሉᢠየአá‹á‰³áˆ¨ መረብ ስህተቶች እና ጥቃቶች አብዛኛዠጊዜ ጊዜያዊ ናቸá‹á£ ስለዚህ ይህ ገጽ በኋላ ላይ ሊሰራ ይችላáˆá¢</translation>
-<translation id="79859296434321399">የትክክለኛ እá‹áŠá‰³ ይዘትን ለማየት ARCore ይጫኑ</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">ጠርá‹</translation>
<translation id="7992044431894087211">ከ <ph name="APPLICATION_TITLE" /> ጋር የማያ ገጽ መጋራት ከቆመበት ቀጥáˆáˆ</translation>
<translation id="7995512525968007366">አáˆá‰°áŒ á‰€áˆ°áˆ</translation>
+<translation id="7998269595945679889">ማንáŠá‰µ የማያሳá‹á‰… ትር አá‹áˆ«áˆ­áŠ• ይክáˆá‰±á£ በáŒáˆ እንዲያስሱ አዲስ ማንáŠá‰µ የማያሳá‹á‰… ትርን ለመክáˆá‰µ አስገባን ይጫኑ</translation>
<translation id="800218591365569300">የማህደረ ትá‹áˆµá‰³ ቦታን ለማስለቀቅ ሌሎች ትሮችን ወይሠá•áˆ®áŒáˆ«áˆžá‰½áŠ• ዘáŒá‰°á‹ ይሞክሩá¢</translation>
<translation id="8004582292198964060">አሳሽ</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{ይህ ካርድ እና የክáá‹« መጠየቂያ አድራሻዠይቀመጣሉᢠበመለያ ወደ <ph name="USER_EMAIL" /> ሲገቡ ሊጠቀሙበት ይችላሉá¢}one{እáŠá‹šáˆ… ካርዶች እና የክáá‹« መጠየቂያ አድራሻዎቻቸዠይቀመጣሉᢠበመለያ ወደ <ph name="USER_EMAIL" /> ሲገቡ ሊጠቀሙባቸዠይችላሉá¢}other{እáŠá‹šáˆ… ካርዶች እና የክáá‹« መጠየቂያ አድራሻዎቻቸዠይቀመጣሉᢠበመለያ ወደ <ph name="USER_EMAIL" /> ሲገቡ ሊጠቀሙባቸዠይችላሉá¢}}</translation>
@@ -2218,6 +2272,7 @@
<translation id="8202370299023114387">áŒáŒ­á‰µ</translation>
<translation id="8206978196348664717">Prc4 (የደብዳቤ á–ስታ)</translation>
<translation id="8211406090763984747">áŒáŠ•áŠ™áŠá‰µ ደኅንáŠá‰± የተጠበቀ áŠá‹</translation>
+<translation id="8217240300496046857">ጣቢያዎች እርስዎን በመላ ድር ላይ የሚከታተሉ ኩኪዎችን መጠቀሠአይችሉáˆá¢ በአንዳንድ ጣቢያዎች ላይ ያሉ ባህሪያት ሊሰበሩ ይችላሉá¢</translation>
<translation id="8218327578424803826">የተመደበ መገኛ አካባቢá¦</translation>
<translation id="8220146938470311105">C7/C6 (የደብዳቤ á–ስታ)</translation>
<translation id="8225771182978767009">ይህን ኮáˆá’á‹á‰°áˆ­ ያቀናበረዠሰዠይህን ጣቢያ ለማገድ መርጧáˆá¢</translation>
@@ -2258,14 +2313,9 @@
<translation id="830498451218851433">áŒáˆ›áˆ½ እጠá</translation>
<translation id="8307358339886459768">ትንሽ-áŽá‰¶</translation>
<translation id="8307888238279532626">መተáŒá‰ áˆªá‹«á‹Žá‰½ ተጭáŠá‹‹áˆ እና áˆáŠ• ያህሠጊዜ ስራ ላይ የሚá‹áˆ‰</translation>
+<translation id="8317207217658302555">ARCore ይዘáˆáŠ•?</translation>
<translation id="831997045666694187">áˆáˆ½á‰µ</translation>
<translation id="8321476692217554900">ማሳወቂያዎች</translation>
-<translation id="8328484624016508118">áˆáˆ‰áŠ•áˆ ማንáŠá‰µ የማያሳá‹á‰ ትሮችን ከዘጋ በኋላ Chrome የሚከተሉትን ያጸዳáˆá¦
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />ከዚህ መሣሪያ የእርስዎን የአሰሳ እንቅስቃሴ<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />ከዚህ መሣሪያ የáለጋ ታሪክዎ<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />በቅጾች á‹áˆµáŒ¥ የገባ መረጃ<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489">የ<ph name="HOST_NAME" /> መዳረሻ ተከáˆáŠ­áˆáˆ</translation>
<translation id="833262891116910667">አድáˆá‰…</translation>
<translation id="8339163506404995330">በ<ph name="LANGUAGE" /> ያሉ ገጾች አይተረጎሙáˆ</translation>
@@ -2317,6 +2367,7 @@
<translation id="8507227106804027148">የትዕዛዠመስመር</translation>
<translation id="8508648098325802031">የáለጋ አዶ</translation>
<translation id="8511402995811232419">ኩኪዎችን አቀናብር</translation>
+<translation id="8519753333133776369">በአስተዳዳሪዎ የተáˆá‰€á‹° የHID መሣሪያ</translation>
<translation id="8522552481199248698">Chrome የGoogle መለያዎን እንዲጠብበእና የይለá ቃáˆá‹ŽáŠ• እንዲቀይሩት á‹«áŒá‹˜á‹Žá‰³áˆá¢</translation>
<translation id="8530813470445476232">የእርስዎን የአሰሳ ታሪክᣠኩኪዎችᣠመሸጎጫዎች እና ተጨማሪ በChrome ቅንብሮች á‹áˆµáŒ¥ ያጽዱ</translation>
<translation id="8533619373899488139">የታገዱ የዩአርኤሎች á‹áˆ­á‹áˆ­ እና ሌሎች በሥርዓት አስተዳዳሪዎ አስገዳጅáŠá‰µ የተሰጣቸዠመመሪያዎችን ለማየት &lt;strong&gt;chrome://policy&lt;/strong&gt;ን ይጎብኙá¢</translation>
@@ -2328,7 +2379,6 @@
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{áˆá‰ƒá‹µáŠ• ዳáŒáˆ አስጀáˆáˆ­}one{áˆá‰ƒá‹¶á‰½áŠ• ዳáŒáˆ አስጀáˆáˆ­}other{áˆá‰ƒá‹¶á‰½áŠ• ዳáŒáˆ አስጀáˆáˆ­}}</translation>
<translation id="8555010941760982128">ተመá‹áŒá‰ á‹ ሲወጡ ይህን ኮድ ይጠቀሙ</translation>
<translation id="8557066899867184262">CVC ከካርድዎ በስተጀርባ ላይ ይገኛáˆá¢</translation>
-<translation id="8558485628462305855">የትክክለኛ እá‹áŠá‰³ ይዘትን ለማየት ARCore ያዘáˆáŠ‘</translation>
<translation id="8559762987265718583">የእርስዎ መሣሪያ ቀን (<ph name="DATE_AND_TIME" />) áˆáŠ­ ስላáˆáˆ†áŠ ወደ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> የáŒáˆ áŒáŠ•áŠ™áŠá‰µ መመስረት አይቻáˆáˆá¢</translation>
<translation id="8564182942834072828">የተለዩ ሰáŠá‹¶á‰½/á‹«áˆá‰°áŒ£áˆ˜áˆ© ቅጂዎች</translation>
<translation id="8564985650692024650">Chromium የእርስዎን የ<ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> ይለá ቃሠበሌሎች ጣቢያዎች ላይ ዳáŒáˆ ከተጠቀሙበት እንደገና እንዲያዋቅሩት ይመክራáˆá¢</translation>
@@ -2348,6 +2398,7 @@
<translation id="865032292777205197">የእንቅስቃሴ ዳሳሾች</translation>
<translation id="8663226718884576429">የትዕዛዠማጠቃለያᣠ<ph name="TOTAL_LABEL" />ᣠተጨማሪ á‹áˆ­á‹áˆ®á‰½</translation>
<translation id="8666678546361132282">እንáŒáˆŠá‹áŠ›</translation>
+<translation id="8669306706049782872">መስኮቶችን ለመክáˆá‰µ እና ለማስቀመጥ ስለማያ ገጽዎ ያለ መረጃን ይጠቀሙ</translation>
<translation id="867224526087042813">áŠáˆ­áˆ›</translation>
<translation id="8676424191133491403">የዘገየ የለáˆ</translation>
<translation id="8680536109547170164"><ph name="QUERY" />ᣠመáˆáˆµá£ <ph name="ANSWER" /></translation>
@@ -2374,6 +2425,7 @@
<translation id="8731544501227493793">የይለá ቃላት አá‹áˆ«áˆ­áŠ• ያቀናብሩᣠየእርስዎን የይለá ቃላት በChrome ቅንብሮች á‹áˆµáŒ¥ ለማየት እና ለማቀናበር አስገባን ይጫኑ</translation>
<translation id="8734529307927223492">የእርስዎ <ph name="DEVICE_TYPE" /> በ<ph name="MANAGER" /> የሚተዳደር áŠá‹</translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />ᣠትርን ይጫኑና ከዚያ በáŒáˆ እንዲያስሱ ማንáŠá‰µ የማያሳá‹á‰… áˆáŠá‰³ መስኮት ለመክáˆá‰µ አስገባን ይጫኑ</translation>
+<translation id="8737685506611670901"><ph name="PROTOCOL" /> አገናኞች በ<ph name="REPLACED_HANDLER_TITLE" /> áˆáŠ•á‰³ ክáˆá‰µ</translation>
<translation id="8738058698779197622">ደህንáŠá‰± የተጠበቀ áŒáŠ•áŠ™áŠá‰µ ለመመስረትᣠየእርስዎ ሰዓት በትክክሠመቀናበር ያስáˆáˆáŒˆá‹‹áˆá¢ ይህን የሆáŠá‰ á‰µ áˆáŠ­áŠ•á‹«á‰µ የድር ጣቢያዎች ራሳቸá‹áŠ• ለማሳወቅ የሚጠቀሙባቸዠየáˆáˆµáŠ­áˆ­ ወረቀቶች የሚሰሩት ለተወሰኑ ክáለ ጊዜያቶች ብቻ ስለሆአáŠá‹á¢ የእርስዎ መሣሪያ ሰዓት áˆáŠ­ እንዳለመሆኑ መጠን Chromium እáŠá‹šáˆ…ን áˆáˆµáŠ­áˆ­ ወረቀቶች ሊያረጋáŒáŒ£á‰¸á‹ አይችáˆáˆá¢</translation>
<translation id="8740359287975076522">የ<ph name="HOST_NAME" /> &lt;abbr id="dnsDefinition"&gt;የዲኤንኤስ አድራሻ&lt;/abbr&gt; ሊገአአáˆá‰°á‰»áˆˆáˆá¢ ችáŒáˆ©áŠ• በመመርመር ላይá¢</translation>
<translation id="8742371904523228557"><ph name="ONE_TIME_CODE" /> የእርስዎ የ <ph name="ORIGIN" /> ኮድ áŠá‹</translation>
@@ -2401,6 +2453,7 @@
<translation id="883848425547221593">ሌላ እáˆá‰£á‰¶á‰½</translation>
<translation id="884264119367021077">የመላኪያ አድራሻ</translation>
<translation id="884923133447025588">áˆáŠ•áˆ የመሻሪያ ዘዴ አáˆá‰°áŒˆáŠ˜áˆá¢</translation>
+<translation id="8849262850971482943">ለተጨማሪ ደህንáŠá‰µ የእርስዎን áˆáŠ“ባዊ ካርድ ይጠቀሙ</translation>
<translation id="885730110891505394">ከGoogle ጋር ማጋራት</translation>
<translation id="8858065207712248076">Chrome የእርስዎን የ<ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> ይለá ቃሠበሌሎች ጣቢያዎች ላይ ዳáŒáˆ ከተጠቀሙበት እንደገና እንዲያዋቅሩት ይመክራáˆá¢</translation>
<translation id="885906927438988819">የáŠá‹°áˆ አጻጻበትክክሠከሆአ<ph name="BEGIN_LINK" />የWindows አá‹á‰³áˆ¨ መረብ áˆáˆ­áˆ˜áˆ«áŠ• ለማስኬድ ይሞክሩ<ph name="END_LINK" />á¢</translation>
@@ -2450,6 +2503,7 @@
<translation id="9004367719664099443">VR ክáለ ጊዜ በሂደት ላይ áŠá‹</translation>
<translation id="9005998258318286617">የá’ዲኤá ሰáŠá‹µ መጫን አáˆá‰°áˆ³áŠ«áˆá¢</translation>
<translation id="9008201768610948239">ችላ በáˆ</translation>
+<translation id="901834265349196618">ኢሜይáˆ</translation>
<translation id="9020200922353704812">የካርድ ማስከáˆá‹« አድራሻ ያስáˆáˆáŒ‹áˆ</translation>
<translation id="9020542370529661692">ይህ ገጽ ወደ <ph name="TARGET_LANGUAGE" /> ተተርጉሟáˆ</translation>
<translation id="9020742383383852663">A8</translation>
@@ -2498,6 +2552,7 @@
<translation id="9150045010208374699">ካሜራዎን ይጠቀማáˆ</translation>
<translation id="9150685862434908345">የእርስዎ አስተዳዳሪ በርቀት የአሳሽዎን á‹á‰…ረት መቀየር ይችላáˆá¢ በዚህ መሣሪያ ላይ ያለ እንቅስቃሴ ከChrome á‹áŒ­áˆ ሊስተዳደር ይችላáˆá¢ <ph name="BEGIN_LINK" />የበለጠ ለመረዳት<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">የተዘመáŠ</translation>
+<translation id="9155211586651734179">የድáˆá… መሳሪያዎች ተያይዘዋáˆ</translation>
<translation id="9157595877708044936">በማዋቀር ላይ…</translation>
<translation id="9158625974267017556">C6 (የደብዳቤ á–ስታ)</translation>
<translation id="9164029392738894042">የትክክለáŠáŠá‰µ áተሻ</translation>
diff --git a/chromium/components/strings/components_strings_ar.xtb b/chromium/components/strings/components_strings_ar.xtb
index 65848bbcb4e..c11dbd78a00 100644
--- a/chromium/components/strings/components_strings_ar.xtb
+++ b/chromium/components/strings/components_strings_ar.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">عرض التÙاصيل</translation>
<translation id="1030706264415084469">يريد <ph name="URL" /> تخزين حجم كبير من البيانات بشكل دائم على جهازك.</translation>
<translation id="1032854598605920125">تدوير ÙÙŠ اتجاه عقارب الساعة</translation>
+<translation id="1033329911862281889">لا يخÙÙŠ وضع التصÙّح المتخÙÙŠ هويتك عند زيارتك للمواقع الإلكترونية:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ترصد المواقع الإلكترونية والخدمات المتوÙّرة عليها زيارتك لها<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />بإمكان أصحاب الأعمال أو المؤسسات التعليمية تتبّÙع نشاط التصÙّح<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />قد يراقب مزوّدو خدمة الإنترنت عدد زيارات المستخدمين للمواقع الإلكترونية<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">إيقاÙ</translation>
<translation id="1036982837258183574">اضغط على |<ph name="ACCELERATOR" />| للخروج من وضع ملء الشاشة</translation>
<translation id="1038106730571050514">عرض الاقتراحات</translation>
<translation id="1038842779957582377">اسم غير معروÙ</translation>
<translation id="1041998700806130099">رسالة ورقة المهمة</translation>
<translation id="1048785276086539861">عند تعديل التعليقات التوضيحية، سيعود هذا المستند إلى عرض صÙحة واحدة.</translation>
-<translation id="1049743911850919806">التصÙØ­ المتخÙÙŠ</translation>
<translation id="1050038467049342496">إغلاق التطبيقات الأخرى</translation>
<translation id="1055184225775184556">تراجع عن الإ&amp;ضاÙØ©</translation>
<translation id="1056898198331236512">تحذير</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">ذاكرة التخزين المؤقت للسياسة بحالة جيدة</translation>
<translation id="1130564665089811311">â€Ø²Ø± "ترجمة الصÙحة"ØŒ اضغط على Ù…Ùتاح Enter لترجمة هذه الصÙحة باستخدام "ترجمة Google".</translation>
<translation id="1131264053432022307">الصورة التي نسختها</translation>
+<translation id="1142846828089312304">حظر ملÙات تعري٠الارتباط التابعة لجهات خارجية ÙÙŠ وضع التصÙÙ‘ÙØ­ المتخÙÙŠ</translation>
<translation id="1150979032973867961">هذا الخادم لم يتمكن من إثبات أن ذلك <ph name="DOMAIN" />Ø› بل إنه شهادة أمان غير موثقة من خلال نظام تشغيل الكمبيوتر. وربما يكون السبب ÙÙŠ ذلك خطأ ÙÙŠ التكوين أو مهاجمًا يعترض الاتصال.</translation>
<translation id="1151972924205500581">كلمة المرور مطلوبة</translation>
<translation id="1156303062776767266">يتمّ عرض مل٠محلي أو مشترك.</translation>
@@ -64,7 +70,6 @@
<translation id="1178581264944972037">الإيقا٠مؤقتًا</translation>
<translation id="1181037720776840403">إزالة</translation>
<translation id="1186201132766001848">التحقق من كلمات المرور</translation>
-<translation id="1195210374336998651">الانتقال إلى إعدادات التطبيق</translation>
<translation id="1195558154361252544">يتم حظر الإشعارات تلقائيًا لجميع المواقع الإلكترونية باستثناء المواقع التي تسمح بها.</translation>
<translation id="1197088940767939838">برتقالي</translation>
<translation id="1201402288615127009">التالي</translation>
@@ -111,7 +116,7 @@
<translation id="1307966114820526988">الميزات المتوقÙØ©</translation>
<translation id="1308113895091915999">العرض متاح</translation>
<translation id="1312803275555673949">ما الدليل الذي يؤيد ذلك؟</translation>
-<translation id="131405271941274527">â€ÙŠØ±ÙŠØ¯ <ph name="URL" /> إرسال المعلومات وتلقّيها عند النقر على جهاز NFC الظاهر على هاتÙÙƒ.</translation>
+<translation id="1314311879718644478">يمكنك عرض محتوى الواقع المعزّز.</translation>
<translation id="1314509827145471431">التجليد من الناحية اليمنى</translation>
<translation id="1318023360584041678">تم Ø­Ùظ نتيجة البحث ÙÙŠ مجموعة علامات تبويب</translation>
<translation id="1319245136674974084">عدم السؤال مرة أخرى عند استخدام هذا التطبيق</translation>
@@ -161,6 +166,7 @@
<translation id="142858679511221695">مستخدم السحابة الإلكترونية</translation>
<translation id="1428729058023778569">â€ÙŠØ¸Ù‡Ø± هذا التحذير لأنّ هذا الموقع الإلكتروني لا يتواÙÙ‚ مع بروتوكول HTTPS. <ph name="BEGIN_LEARN_MORE_LINK" />مزيد من المعلومات<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">طباعة</translation>
+<translation id="1432187715652018471">تريد هذه الصÙحة تثبيت معالج الخدمة.</translation>
<translation id="1432581352905426595">إدارة محركات البحث</translation>
<translation id="1436185428532214179">السماح للموقع الإلكتروني بطلب تعديل الملÙات والمجلدات على جهازك</translation>
<translation id="1442386063175183758">الطي على شكل بوابة يمينًا</translation>
@@ -181,6 +187,12 @@
<translation id="1483493594462132177">إرسال</translation>
<translation id="1484290072879560759">اختيار عنوان الشحن</translation>
<translation id="1492194039220927094">إرسال السياسات:</translation>
+<translation id="149293076951187737">â€Ø¹Ù†Ø¯ إغلاق كل علامات التبويب ÙÙŠ وضع التصÙّح المتخÙÙŠ ÙÙŠ متصÙّح ChromeØŒ يتم محو نشاطك ÙÙŠ علامات التبويب تلك من هذا الجهاز:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />نشاط التصÙّح<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />سجلّ البحث<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />المعلومات التي تمّ إدخالها ÙÙŠ النماذج<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">الرجوع إلى علامة التبويب</translation>
<translation id="1501859676467574491">â€Ø¹Ø±Ø¶ البطاقات من حسابك على Google</translation>
<translation id="1507202001669085618">â€&lt;p&gt;سيظهر هذا الخطأ عند استخدام بوابة شبكة Wi-Fi تتطلّب تسجيل الدخول قبل الاتصال بالإنترنت.&lt;/p&gt;
@@ -208,6 +220,8 @@
<translation id="1559572115229829303">â€&lt;p&gt;تعذر إنشاء اتصال خاص بـ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> نظرًا لأن تاريخ ووقت جهازك (<ph name="DATE_AND_TIME" />) غير صحيحين.&lt;/p&gt;
&lt;p&gt;ÙŠÙرجى تعديل التاريخ والوقت من القسم &lt;strong&gt;عام&lt;/strong&gt; ÙÙŠ تطبيق &lt;strong&gt;الإعدادات&lt;/strong&gt; .&lt;/p&gt;</translation>
+<translation id="1559839503761818503">سيعيد المشر٠تشغيل الجهاز ÙÙŠ <ph name="TIME" /> بتاريخ <ph name="DATE" />.</translation>
+<translation id="156703335097561114">معلومات الشبكة، مثل العناوين وإعدادات الواجهة وجودة الاتصال</translation>
<translation id="1567040042588613346">تعمل هذه السياسة على النحو المنشود، غير أنّ القيمة Ù†Ùسها Ù…Ùحدّدة ÙÙŠ مكان آخر ومن ثمَّ تم استبدالها بموجب هذه السياسة.</translation>
<translation id="1569487616857761740">إدخال تاريخ انتهاء الصلاحية</translation>
<translation id="1581080074034554886">â€Ø±Ù…ز التحقق من البطاقة (CVC)</translation>
@@ -215,6 +229,7 @@
<translation id="1583429793053364125">حدث خطأ ما أثناء عرض صÙحة الويب هذه.</translation>
<translation id="1586541204584340881">الإضاÙات التي ثبّتها</translation>
<translation id="1588438908519853928">عادي</translation>
+<translation id="1589050138437146318">â€Ù‡Ù„ تريد تثبيت ARCoreØŸ</translation>
<translation id="1592005682883173041">الوصول إلى البيانات المحلية</translation>
<translation id="1594030484168838125">اختيار</translation>
<translation id="160851722280695521">â€ØªØ´ØºÙŠÙ„ لعبة الديناصور ÙÙŠ Chrome</translation>
@@ -283,6 +298,7 @@
العنوان غير صالح، مما يمنع المتصÙÙ‘ÙØ­ من إكمال
طلبك ذي الصلة بالموقع الإلكتروني <ph name="SITE" />. ويمكن استخدام سياسات المصدر من خلال
عوامل تشغيل المواقع الإلكترونية لضبط الأمان والخصائص الأخرى لموقع إلكتروني.</translation>
+<translation id="1774592222195216949">â€<ph name="BEGIN_LINK" />مزيد من المعلومات حول وضع التصÙّح المتخÙÙŠ ÙÙŠ متصÙّح Chromium<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">تظهر علامات التبويب المÙتوحة هنا</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -410,6 +426,7 @@
<translation id="22081806969704220">الدÙرج 3</translation>
<translation id="2212735316055980242">تعذر العثور على السياسة</translation>
<translation id="2213606439339815911">جار٠جلب الإدخالات...</translation>
+<translation id="2213612003795704869">تمت طباعة الصÙحة.</translation>
<translation id="2215727959747642672">تعديل الملÙ</translation>
<translation id="2218879909401188352">يمكن للمهاجمين الموجودين حاليًا على <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> تثبيت تطبيقات خطيرة تضرّ جهازك أو تضي٠رسومًا إلى Ùاتورة الجوّال أو تسرق معلوماتك الشخصية. <ph name="BEGIN_LEARN_MORE_LINK" />مزيد من المعلومات<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">الاتصال بالإنترنت مقطوع</translation>
@@ -419,6 +436,7 @@
<translation id="2248949050832152960">â€Ø§Ø³ØªØ®Ø¯Ø§Ù… WebAuthn</translation>
<translation id="2250931979407627383">خزم الحوا٠يسارًا</translation>
<translation id="225207911366869382">تم تجاهل القيمة لهذه السياسة.</translation>
+<translation id="2256115617011615191">إعادة التشغيل الآن</translation>
<translation id="2258928405015593961">ÙŠÙرجى إدخال تاريخ انتهاء صلاحية ÙÙŠ المستقبل وإعادة المحاولة.</translation>
<translation id="225943865679747347">رمز الخطأ: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">â€Ø®Ø·Ø£ HTTP</translation>
@@ -446,6 +464,7 @@
<translation id="2337852623177822836">يتم التحكّم ÙÙŠ الإعداد من قبل المشرÙ</translation>
<translation id="2340263603246777781">يريد <ph name="ORIGIN" /> الاقتران</translation>
<translation id="2346319942568447007">الصورة التي نسختها</translation>
+<translation id="2350796302381711542">هل تريد السماح لـ <ph name="HANDLER_HOSTNAME" /> بÙتح كل روابط <ph name="PROTOCOL" /> بدلاً من <ph name="REPLACED_HANDLER_TITLE" />ØŸ</translation>
<translation id="2354001756790975382">الإشارات الأخرى</translation>
<translation id="2354430244986887761">â€Ø¹Ø«Ø± â€â€«Ø§Ù„تصÙØ­ الآمن من Google‬ مؤخرًا <ph name="BEGIN_LINK" />على تطبيقات ضارة<ph name="END_LINK" /> ÙÙŠ <ph name="SITE" />.</translation>
<translation id="2355395290879513365">قد يتمكن المهاجمون من رؤية الصور التي تتطلع عليها على هذا الموقع وخداعك من خلال تعديلها.</translation>
@@ -471,13 +490,15 @@
<translation id="2413528052993050574">هذا الخادم لم يتمكن من إثبات أن ذلك <ph name="DOMAIN" />Ø› بل إنه شهادة أمان ربما تم إلغاء صلاحيتها. وربما يكون السبب ÙÙŠ ذلك خطأ ÙÙŠ التكوين أو مهاجمًا يعترض اتصالك.</translation>
<translation id="2414886740292270097">داكن</translation>
<translation id="2430968933669123598">â€Ø¥Ø¯Ø§Ø±Ø© حساب Google: اضغط على Ù…Ùتاح Enter لإدارة المعلومات والخصوصية والأمان ÙÙŠ حسابك على Google.</translation>
+<translation id="2436186046335138073">هل تريد السماح لـ <ph name="HANDLER_HOSTNAME" /> بÙتح كل روابط <ph name="PROTOCOL" />ØŸ</translation>
<translation id="2438874542388153331">عمل أربعة ثقوب يمينًا</translation>
-<translation id="2450021089947420533">سجلّ أنشطة البحث والتصÙÙ‘ÙØ­</translation>
+<translation id="2450021089947420533">رحلات البحث</translation>
<translation id="2463739503403862330">ملء</translation>
<translation id="2465402087343596252">Architecture-E</translation>
<translation id="2465655957518002998">اختيار طريقة التسليم للمستخدم</translation>
<translation id="2465688316154986572">وضع دبوس واحد</translation>
<translation id="2465914000209955735">â€Ø¥Ø¯Ø§Ø±Ø© الملÙات التي تم تنزيلها ÙÙŠ Chrome</translation>
+<translation id="2466004615675155314">عرض معلومات من الويب</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />تشغيل بيانات تشخيص الشبكة<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">طباعة الصÙحات بالترتيب الأساسي</translation>
<translation id="2470767536994572628">عند تعديل التعليقات التوضيحية، سيعود هذا المستند إلى اتجاه تدويره الأصلي وإلى عرض صÙحة واحدة.</translation>
@@ -498,6 +519,7 @@
<translation id="2523886232349826891">سيتم Ø­Ùظ البطاقة على هذا الجهاز Ùقط</translation>
<translation id="2524461107774643265">إضاÙØ© مزيد من المعلومات</translation>
<translation id="2529899080962247600">يجب ألا يحتوي هذا الحقل على أكثر من <ph name="MAX_ITEMS_LIMIT" /> إدخال. وسيتم تجاهل جميع الإدخالات الأخرى.</translation>
+<translation id="2535585790302968248">Ùتح علامة تبويب جديدة ÙÙŠ وضع التصÙّح المتخÙÙŠ للتصÙÙ‘ÙØ­ بخصوصية تامة</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{وكلمة مرور واحدة أخرى}zero{و# كلمة مرور أخرى}two{وكلمتا مرور أخريان}few{و# كلمات مرور أخرى}many{و# كلمة مرور أخرى}other{و# كلمة مرور أخرى}}</translation>
<translation id="2536110899380797252">إضاÙØ© عنوان</translation>
<translation id="2539524384386349900">اكتشاÙ</translation>
@@ -523,7 +545,14 @@
<translation id="2597378329261239068">هذا المستند محمي بكلمة المرور. ÙŠÙرجى إدخال كلمة مرور.</translation>
<translation id="2609632851001447353">الاختلاÙات</translation>
<translation id="2610561535971892504">النقر لنسخ النص</translation>
+<translation id="2617988307566202237">â€<ph name="BEGIN_EMPHASIS" />لن يحÙظ<ph name="END_EMPHASIS" /> Chrome المعلومات التالية:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />سجلّ التصÙÙ‘ÙØ­
+ <ph name="LIST_ITEM" />ملÙات تعري٠الارتباط وبيانات المواقع الإلكترونية
+ <ph name="LIST_ITEM" />المعلومات التي تم إدخالها ÙÙŠ النماذج
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">â€C10 (مغلÙ)</translation>
+<translation id="2623663032199728144">يمكن للموقع الإلكتروني أن يطلب استخدام المعلومات المتعلقة بشاشاتك.</translation>
<translation id="2625385379895617796">توقيت ساعتك متقدم عن الوقت الحالي</translation>
<translation id="262745152991669301">â€Ø§Ù„سماح للموقع الإلكتروني بطلب الاتصال بأجهزة USB</translation>
<translation id="2629325967560697240">â€Ù„لحصول على أعلى مستوى من الحماية ÙÙŠ متصÙÙ‘ÙØ­ ChromeØŒ يمكنك <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />تÙعيل "الحماية المÙحسَّنة"<ph name="END_ENHANCED_PROTECTION_LINK" />.</translation>
@@ -557,6 +586,7 @@
<translation id="2709516037105925701">الملء التلقائي</translation>
<translation id="2713444072780614174">أبيض</translation>
<translation id="2715612312510870559">â€<ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />ØŒ اضغط على Ù…Ùتاح التبويب (Tab) ثم Ù…Ùتاح Enter لإدارة الدÙعات ومعلومات بطاقة الائتمان ÙÙŠ إعدادات Chrome.</translation>
+<translation id="271663710482723385">اضغط على |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| للخروج من وضع ملء الشاشة.</translation>
<translation id="2721148159707890343">تم إرسال الطلب بنجاح</translation>
<translation id="2723669454293168317">â€ØªØ´ØºÙŠÙ„ ميزة "تأكيد السلامة" ÙÙŠ إعدادات Chrome</translation>
<translation id="2726001110728089263">الدÙرج الجانبي</translation>
@@ -587,6 +617,7 @@
<translation id="2850739647070081192">دعوة (مغلÙ)</translation>
<translation id="2856444702002559011">قد يحاول المهاجمون سرقة معلوماتك من <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (مثل كلمات المرور أو الرسائل أو بطاقات الائتمان). <ph name="BEGIN_LEARN_MORE_LINK" />مزيد من المعلومات<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">يعرض هذا الموقع الإلكتروني إعلانات مضلّÙلة أو غير مرغوب Ùيها.</translation>
+<translation id="286512204874376891">تÙØ®ÙÙŠ البطاقة الاÙتراضية بطاقتك الÙعلية للمساعدة على حمايتك من عمليات الاحتيال المحتمَلة. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">سهل الاستخدام</translation>
<translation id="2876489322757410363">ستتم مغادرة وضع التصÙÙ‘ÙØ­ المتخÙÙŠ للدÙع عبر تطبيق خارجي. هل تريد المتابعة؟</translation>
<translation id="2876949457278336305">â€<ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />ØŒ اضغط على Ù…Ùتاح Tab ثم Ù…Ùتاح Enter لإدارة إعدادات ميزة "التصÙÙ‘ÙØ­ الآمن" وغيرها ÙÙŠ إعدادات Chrome</translation>
@@ -611,6 +642,7 @@
<translation id="2930577230479659665">القطع بعد كل نسخة</translation>
<translation id="2932085390869194046">اقتراح كلمة مرور...</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019">Ùتح روابط <ph name="PROTOCOL" /></translation>
<translation id="2941952326391522266">هذا الخادم لم يتمكن من إثبات أن ذلك <ph name="DOMAIN" />Ø› بل إنه شهادة أمان من <ph name="DOMAIN2" />. وربما سبب ذلك خطأ ÙÙŠ التكوين أو مهاجمًا يعترض اتصالك.</translation>
<translation id="2943895734390379394">وقت التحميل:</translation>
<translation id="2948083400971632585">يمكنك إيقا٠أي خوادم وكيلة تم إعدادها لاتصال من صÙحة الإعدادات.</translation>
@@ -643,6 +675,7 @@
<translation id="3037605927509011580">عذرًا!</translation>
<translation id="3041612393474885105">معلومات الشهادة</translation>
<translation id="3044034790304486808">استئنا٠عملية البحث</translation>
+<translation id="305162504811187366">â€Ø³Ø¬Ù„Ù‘ الوصول إلى الكمبيوتر المكتبي عن بÙعد من ChromeØŒ بما ÙÙŠ ذلك الطوابع الزمنية والمضيÙين وأرقام تعري٠جلسات العملاء</translation>
<translation id="3060227939791841287">â€C9 (مغلÙ)</translation>
<translation id="3061707000357573562">خدمة رمز التصحيح</translation>
<translation id="306573536155379004">بدأت اللعبة.</translation>
@@ -683,6 +716,7 @@
<translation id="3197136577151645743">السماح للموقع الإلكتروني بطلب إذن لمعرÙØ© الأوقات التي تستخدم Ùيها هذا الجهاز بشكل نشط</translation>
<translation id="3202497928925179914">â€<ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />ØŒ اضغط على Ù…Ùتاح التبويب (Tab) ثم Ù…Ùتاح Enter لإدارة نوع المعلومات التي تريد مزامنتها من خلال إعدادات متصÙّح Chrome.</translation>
<translation id="320323717674993345">إلغاء الدÙع</translation>
+<translation id="3203366800380907218">من الويب</translation>
<translation id="3207960819495026254">تمت إضاÙتها إلى الإشارات المرجعية.</translation>
<translation id="3209034400446768650">إمكانية تحصيل الصÙحة للرسوم</translation>
<translation id="3212581601480735796">تتم مراقبة نشاطك على <ph name="HOSTNAME" /></translation>
@@ -699,10 +733,12 @@
<translation id="3234666976984236645">الكش٠دائمًا عن المحتوى المهم على هذا الموقع</translation>
<translation id="3240683217920639535">â€<ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />ØŒ اضغط على Ù…Ùتاح Tab ثم Ù…Ùتاح Enter لتخصيص مظهر المتصÙÙ‘ÙØ­</translation>
<translation id="3240791268468473923">تم Ùتح صÙحة عدم تطابق بيانات اعتماد الدÙع الآمن.</translation>
+<translation id="324180406144491771">تم حظر روابط "<ph name="HOST_NAME" />"</translation>
<translation id="3249845759089040423">أنيق</translation>
<translation id="3252266817569339921">الÙرنسية</translation>
<translation id="3257954757204451555">ما الجهة التي توÙّر هذه المعلومات؟</translation>
<translation id="3259648571731540213">â€<ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />: اضغط على Ù…Ùتاح التبويب (Tab) ثم Enter لإنشاء حدث جديد ÙÙŠ "تقويم Google" بسرعة.</translation>
+<translation id="3261488570342242926">تعرّ٠على البطاقات الاÙتراضية.</translation>
<translation id="3264837738038045344">â€Ø²Ø± إدارة إعدادات Chrome: اضغط على Ù…Ùتاح Enter للانتقال إلى إعدادات Chrome.</translation>
<translation id="3266793032086590337">القيمة (المتعارضة)</translation>
<translation id="3268451620468152448">علامات التبويب المÙتوحة</translation>
@@ -716,6 +752,7 @@
<translation id="3288238092761586174">قد ÙŠÙطلب من <ph name="URL" /> تنÙيذ خطوات إضاÙية للتحقّق من عملية الدÙع التي تجريها.</translation>
<translation id="3293642807462928945">مزيد من المعلومات عن سياسة <ph name="POLICY_NAME" /></translation>
<translation id="3295444047715739395">â€Ø¹Ø±Ø¶ كلمات المرور وإدارتها ÙÙŠ إعدادات متصÙÙ‘ÙØ­ Chrome</translation>
+<translation id="3303795387212510132">هل تريد السماح للتطبيق بÙتح روابط <ph name="PROTOCOL_SCHEME" />ØŸ</translation>
<translation id="3303855915957856445">لم يتم العثور على أي نتائج بحث</translation>
<translation id="3304073249511302126">البحث عن أجهزة تتضمن بلوتوث</translation>
<translation id="3308006649705061278">â€Ø§Ù„وحدة التنظيمية (OU)</translation>
@@ -729,12 +766,6 @@
<translation id="3345782426586609320">عينان</translation>
<translation id="3355823806454867987">تغيير إعدادات الخادم الوكيل...</translation>
<translation id="3360103848165129075">جدول بيانات معالج الدÙع</translation>
-<translation id="3361596688432910856">â€Ù„Ù† يحÙظ <ph name="BEGIN_EMPHASIS" />Chrome<ph name="END_EMPHASIS" /> المعلومات التالية:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />سجل التصÙّح لديك
- <ph name="LIST_ITEM" />ملÙات تعري٠الارتباط وبيانات الموقع
- <ph name="LIST_ITEM" />المعلومات التي تم إدخالها ÙÙŠ النماذج
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">تم نسخ هذه السياسة تلقائيًا من السياسة المتوقÙØ© <ph name="OLD_POLICY" />. يمكنك استخدام هذه السياسة بدلاً من ذلك.</translation>
<translation id="3364869320075768271">يريد <ph name="URL" /> استخدام جهاز الواقع الاÙتراضي وبياناته.</translation>
<translation id="3366477098757335611">عرض البطاقات</translation>
@@ -817,7 +848,6 @@
<translation id="3587738293690942763">متوسط</translation>
<translation id="3592413004129370115">â€Italian (مغلÙ)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{يمكنك إعادة ضبط مجموعتك متى شئت، مع العÙلم أنّ الانضمام إلى مجموعة جديدة يستغرق يومًا تقريبًا.}=1{يمكنك إعادة ضبط مجموعتك متى شئت، مع العÙلم أنّ الانضمام إلى مجموعة جديدة يستغرق يومًا واحدًا تقريبًا.}two{يمكنك إعادة ضبط مجموعتك متى شئت، مع العÙلم أنّ الانضمام إلى مجموعة جديدة يستغرق يومَين ({NUM_DAYS}) تقريبًا.}few{يمكنك إعادة ضبط مجموعتك متى شئت، مع العÙلم أنّ الانضمام إلى مجموعة جديدة يستغرق {NUM_DAYS} أيام تقريبًا.}many{يمكنك إعادة ضبط مجموعتك متى شئت، مع العÙلم أنّ الانضمام إلى مجموعة جديدة يستغرق {NUM_DAYS} يومًا تقريبًا.}other{يمكنك إعادة ضبط مجموعتك متى شئت، مع العÙلم أنّ الانضمام إلى مجموعة جديدة يستغرق {NUM_DAYS} يوم تقريبًا.}}</translation>
-<translation id="3596012367874587041">إعدادات التطبيق</translation>
<translation id="3600246354004376029"><ph name="TITLE" />، و<ph name="DOMAIN" />، و<ph name="TIME" /></translation>
<translation id="3603507503523709">حظر مشرÙÙƒ التطبيق</translation>
<translation id="3608932978122581043">تخطيط الاتجاه</translation>
@@ -857,9 +887,11 @@
<translation id="3705189812819839667"><ph name="RESULT_OWNER" /> - <ph name="RESULT_PRODUCT_SOURCE" /></translation>
<translation id="370665806235115550">جار٠التحميل...</translation>
<translation id="3709599264800900598">النص الذي نسخته</translation>
-<translation id="370972442370243704">تÙعيل ميزة "سجلّ أنشطة البحث والتصÙÙ‘ÙØ­"</translation>
+<translation id="370972442370243704">تÙعيل ميزة "رحلات البحث"
+</translation>
<translation id="3711895659073496551">تعليق</translation>
<translation id="3712624925041724820">التراخيص مستنÙذة</translation>
+<translation id="3714633008798122362">تقويم الويب</translation>
<translation id="3714780639079136834">â€ØªØ´ØºÙŠÙ„ بيانات شبكة الجوّال أو Wi-Fi</translation>
<translation id="3715597595485130451">â€Ø§Ù„اتصال بـ Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />التحقق من إعداد الخادم الوكيل والجدار الناري ونظام أسماء النطاقات<ph name="END_LINK" /></translation>
@@ -921,6 +953,7 @@
<translation id="3906954721959377182">جهاز لوحي</translation>
<translation id="3909477809443608991">â€ÙŠØ±ÙŠØ¯ <ph name="URL" /> تشغيل المحتوى المÙحمي. ستتحقَّق Google من هوية جهازك ويمكن الوصول إليه من خلال هذا الموقع.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">رÙض</translation>
<translation id="3939773374150895049">â€Ù‡Ù„ تريد استخدم WebAuthn بدلاً من رمز التحقق من البطاقة (CVC)ØŸ</translation>
<translation id="3946209740501886391">السؤال دائمًا على الموقع الإلكتروني هذا</translation>
<translation id="3947595700203588284">â€Ø§Ù„سماح للموقع الإلكتروني بطلب الاتصال بأجهزة MIDI</translation>
@@ -942,6 +975,7 @@
<translation id="3990250421422698716">ترتيب النسخ مع الÙصل بينها</translation>
<translation id="3996311196211510766">لقد طلب الموقع الإلكتروني <ph name="ORIGIN" /> تطبيق سياسة المصدر
على جميع الطلبات المقدَّمة إليه، ولكن يتعذّر تطبيق هذه السياسة حاليًا.</translation>
+<translation id="4009243425692662128">â€ÙŠØªÙ… إرسال محتوى الصÙحات التي تطبعها إلى Google Cloud أو أطرا٠خارجية لتحليله. على سبيل المثال، قد يتم Ùحص هذا المحتوى بحثًا عن بيانات حسّاسة.</translation>
<translation id="4010758435855888356">هل تريد السماح بالوصول إلى مساحة التخزين؟</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{â€Ù…ستند PDF يتأل٠من صÙحة واحدة ({COUNT})}zero{â€Ù…ستند PDF يتأل٠من {COUNT} صÙحة}two{â€Ù…ستند PDF يتأل٠من صÙحتين ({COUNT})}few{â€Ù…ستند PDF يتأل٠من {COUNT} صÙحات}many{â€Ù…ستند PDF يتأل٠من {COUNT} صÙحة}other{â€Ù…ستند PDF يتأل٠من {COUNT} صÙحة}}</translation>
<translation id="4023431997072828269">ستظهر معلوماتك للآخرين لأن هذا النموذج يستخدم اتصالاً غير آمن.</translation>
@@ -1036,6 +1070,7 @@
<translation id="4250680216510889253">لا</translation>
<translation id="4253168017788158739">ملاحظة</translation>
<translation id="425582637250725228">قد لا يتم Ø­Ùظ التغييرات التي أجريتها.</translation>
+<translation id="425869179292622354">هل تريد الحصول على حماية إضاÙية باستخدام بطاقة اÙتراضية؟</translation>
<translation id="4258748452823770588">توقيع غير صالح</translation>
<translation id="4261046003697461417">يتعذّر إضاÙØ© تعليق توضيحي إلى المستندات المحمية</translation>
<translation id="4265872034478892965">تم السماح من قبل المشرÙ</translation>
@@ -1098,6 +1133,7 @@
<translation id="4434045419905280838">النواÙØ° المنبثقة وإعادة التوجيه</translation>
<translation id="4435702339979719576">بطاقة بريدية)</translation>
<translation id="443673843213245140">تم إيقا٠استخدام الخادم الوكيل ولكن تم تحديد إعداد صريح للخادم الوكيل.</translation>
+<translation id="4441832193888514600">تم التجاهل لأنّ هذه السياسة لا يمكن ضبطها كسياسة مستخدم على السحابة الإلكترونية.</translation>
<translation id="4450893287417543264">عدم الإظهار مرة أخرى</translation>
<translation id="4451135742916150903">â€Ø§Ù„سماح للموقع الإلكتروني بطلب الاتصال بأجهزة HID</translation>
<translation id="4452328064229197696">â€ÙƒÙ„مة المرور التي استخدمتها للتو تم رصدها ضمن عملية اختراق للبيانات. ولتأمين حساباتك، ينصح "مدير كلمات المرور" من Google بالتحقّق من كلمات المرور المحÙوظة.</translation>
@@ -1121,7 +1157,8 @@
<translation id="4508814173490746936">â€ØªØ¹Ø°Ù‘ر استخدام ميزة Touch ID</translation>
<translation id="4509074745930862522">â€<ph name="TRANSLATE_FOCUSED_FRIENDLY_MATCH_TEXT" />ØŒ اضغط على Ù…Ùتاح التبويب (Tab) ثم Ù…Ùتاح Enter لترجمة هذه الصÙحة باستخدام "ترجمة Google".</translation>
<translation id="4510487217173779431">â€Chou4 (مغلÙ)</translation>
-<translation id="4514308731478712184">إيقا٠ميزة "سجلّ أنشطة البحث والتصÙÙ‘ÙØ­"</translation>
+<translation id="4514308731478712184">إيقا٠ميزة "رحلات البحث"
+</translation>
<translation id="4515275063822566619">â€ÙŠØªÙ… أخذ البطاقات والعناوين من Chrome وحسابك على Google (<ph name="ACCOUNT_EMAIL" />)ØŒ ويمكنك إدارتها ÙÙŠ <ph name="BEGIN_LINK" />الإعدادات<ph name="END_LINK" />.</translation>
<translation id="4517607026994743406">â€Comm-10 (مغلÙ)</translation>
<translation id="4521157617044179198">â€<ph name="WIDTH" /> x <ph name="HEIGHT" /> ملم (<ph name="ORIENTATION" />)</translation>
@@ -1153,6 +1190,7 @@
<translation id="4628948037717959914">صورة</translation>
<translation id="4631649115723685955">تم ربط مكاÙأة لاسترداد جزء من المال.</translation>
<translation id="4636930964841734540">معلومات</translation>
+<translation id="4638670630777875591">â€ÙˆØ¶Ø¹ التصÙّح المتخÙÙŠ ÙÙŠ متصÙّح Chromium</translation>
<translation id="464342062220857295">ميزات البحث</translation>
<translation id="4644670975240021822">ترتيب عكسي والوجه للأسÙÙ„</translation>
<translation id="4646534391647090355">الانتقال الآن</translation>
@@ -1173,6 +1211,7 @@
<translation id="4708268264240856090">تم قطع اتصالك</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131">â€<ph name="BEGIN_LINK" />تشغيل بيانات تشخيص شبكة Windows<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426">كلمة مرور <ph name="USERNAME" /></translation>
<translation id="4724144314178270921">السماح للموقع الإلكتروني بطلب الاطّلاع على النصوص والصور التي تم نسخها إلى الحاÙظة</translation>
<translation id="4726672564094551039">إعادة تحميل السياسات</translation>
<translation id="4728558894243024398">النظام الأساسي</translation>
@@ -1194,6 +1233,7 @@
<translation id="4757993714154412917">â€Ù„قد أدخلت للتو كلمة مرورك ÙÙŠ موقع إلكتروني مريب. لحماية حساباتك، يقترح متصÙÙ‘ÙØ­ Chromium التحقّق من كلمات المرور المحÙوظة.</translation>
<translation id="4758311279753947758">إضاÙØ© معلومات الاتصال</translation>
<translation id="4761104368405085019">استخدام الميكروÙون</translation>
+<translation id="4761869838909035636">â€ØªØ´ØºÙŠÙ„ ميزة "تأكيد السلامة" ÙÙŠ Chrome</translation>
<translation id="4764776831041365478">قد تكون صÙحة الويب على العنوان <ph name="URL" /> غير متاحة مؤقتًا أو قد يكون تم نقلها نهائيًا إلى عنوان ويب جديد.</translation>
<translation id="4766713847338118463">وضع دبوسَين بالأسÙÙ„</translation>
<translation id="4771973620359291008">حدث خطأ غير محدّد.</translation>
@@ -1214,12 +1254,6 @@
<translation id="4819347708020428563">هل تريد تعديل التعليقات التوضيحية ÙÙŠ العرض التلقائي؟</translation>
<translation id="4825496307559726072">â€<ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />: اضغط على Ù…Ùتاح التبويب (Tab) ثم Enter لإنشاء "جدول بيانات Google" جديد بسرعة.</translation>
<translation id="4825507807291741242">قوي</translation>
-<translation id="4827402517081186284">لا يخÙÙŠ وضع التصÙÙ‘ÙØ­ المتخÙÙŠ هويتك عند زيارتك للمواقع الإلكترونية:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />ترصد المواقع الإلكترونية بيانات زيارتك لها<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />بإمكان أصحاب العمل أو المؤسسات التعليمية تتبّع نشاط التصÙÙ‘ÙØ­<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />قد يراقب مزوّدو خدمة الإنترنت زيارات المستخدمين للمواقع الإلكترونية<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">تÙعيل التحذيرات</translation>
<translation id="4838327282952368871">جذّاب</translation>
<translation id="4840250757394056958">â€Ø¹Ø±Ø¶ سجلّ Chrome</translation>
@@ -1231,12 +1265,12 @@
<translation id="4854362297993841467">طريقة التسليم هذه غير متاحة. جرّÙب طريقة أخرى.</translation>
<translation id="4854853140771946034">â€Ø¥Ù†Ø´Ø§Ø¡ ملاحظة جديدة ÙÙŠ Google Keep بسرعة</translation>
<translation id="485902285759009870">جار٠التحقّق من الرمز…</translation>
+<translation id="4866506163384898554">اضغط على |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| لعرض المؤشر.</translation>
<translation id="4876188919622883022">العرض المبسَّط</translation>
<translation id="4876305945144899064">ليس هناك اسم مستخدم</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{ما من أسماء نطاقات.}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" /> و<ph name="EXAMPLE_DOMAIN_2" />}few{<ph name="EXAMPLE_DOMAIN_1" /> و<ph name="EXAMPLE_DOMAIN_2" /> و<ph name="AND_MORE" /> نطاقات أخرى}many{<ph name="EXAMPLE_DOMAIN_1" /> و<ph name="EXAMPLE_DOMAIN_2" /> و<ph name="AND_MORE" /> نطاقًا آخر}other{<ph name="EXAMPLE_DOMAIN_1" /> و<ph name="EXAMPLE_DOMAIN_2" /> و<ph name="AND_MORE" /> نطاق آخر}}</translation>
<translation id="4877422487531841831">البحث عن <ph name="TEXT" /></translation>
<translation id="4879491255372875719">الإعداد التلقائي (تلقائي)</translation>
-<translation id="4879725228911483934">يمكنك Ùتح النواÙØ° ووضعها على شاشتك.</translation>
<translation id="4880827082731008257">سجلّ البحث</translation>
<translation id="4881695831933465202">Ùتح</translation>
<translation id="4885256590493466218">الدÙع باستخدام <ph name="CARD_DETAIL" />.</translation>
@@ -1245,6 +1279,7 @@
<translation id="4895877746940133817"><ph name="TYPE_1" />، <ph name="TYPE_2" />، <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">اللÙاÙØ© التاسعة</translation>
<translation id="4901778704868714008">Ø­Ùظ...</translation>
+<translation id="4905659621780993806">سيعيد المشر٠تشغيل الجهاز تلقائيًا عند الساعة <ph name="TIME" /> ÙÙŠ <ph name="DATE" />. عليك Ø­Ùظ أي نواÙØ° Ù…Ùتوحة قبل إعادة تشغيل الجهاز.</translation>
<translation id="4913987521957242411">عمل ثقب أعلى اليسار</translation>
<translation id="4918221908152712722">تثبيت <ph name="APP_NAME" /> (لا يتطلَّب تنزيلاً)</translation>
<translation id="4923459931733593730">الدÙع</translation>
@@ -1253,6 +1288,7 @@
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101">â€<ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />ØŒ اضغط على Ù…Ùتاح التبويب (Tab) ثم Ù…Ùتاح Enter للبحث.</translation>
<translation id="4930153903256238152">سÙعة كبيرة</translation>
+<translation id="4940163644868678279">â€ÙˆØ¶Ø¹ التصÙّح المتخÙÙŠ ÙÙŠ متصÙّح Chrome</translation>
<translation id="4943872375798546930">لا نتائج</translation>
<translation id="4950898438188848926">â€Ø²Ø± التبديل بين علامات التبويب، اضغط على Enter للتبديل إلى علامة التبويب المÙتوحة هذه <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="495170559598752135">إجراءات</translation>
@@ -1262,6 +1298,7 @@
<translation id="4968522289500246572">هذا التطبيق مصمّم للعمل مع الأجهزة الجوّالة وقد يتعذّر تغيير حجمه بشكل مناسب. من الممكن أن يواجه التطبيق بعض المشاكل أو يتعرّض لإعادة التشغيل.</translation>
<translation id="4969341057194253438">حذ٠التسجيل</translation>
<translation id="4973922308112707173">عمل ثقبَين بالأعلى</translation>
+<translation id="4976702386844183910">تاريخ آخر زيارة للموقع الإلكتروني: <ph name="DATE" /></translation>
<translation id="4984088539114770594">هل تريد استخدام الميكروÙون؟</translation>
<translation id="4984339528288761049">â€Prc5 (مغلÙ)</translation>
<translation id="4989163558385430922">عرض الكل</translation>
@@ -1323,6 +1360,7 @@
<translation id="5138227688689900538">عرض أقل</translation>
<translation id="5145883236150621069">يوجد رمز خطأ ÙÙŠ استجابة السياسة</translation>
<translation id="5146995429444047494">يتم حظر الإشعارات للنطاق <ph name="ORIGIN" /></translation>
+<translation id="514704532284964975">â€Ù‡Ù†Ø§Ùƒ طلب من <ph name="URL" /> بالاطّلاع على المعلومات وتعديلها على الأجهزة المزوَّدة بتقنية NFC التي نقرت عليها باستخدام هاتÙÙƒ.</translation>
<translation id="5148809049217731050">الوجه للأعلى</translation>
<translation id="515292512908731282">â€C4 (مغلÙ)</translation>
<translation id="5158275234811857234">غلاÙ</translation>
@@ -1347,6 +1385,7 @@
<translation id="5215116848420601511">â€Ø·Ø±Ù‚ الدÙع والعناوين باستخدام Google Pay</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">الدÙرج 13</translation>
+<translation id="5216942107514965959">تمّت زيارة الموقع الإلكتروني آخر مرّة اليوم.</translation>
<translation id="5222812217790122047">البريد الإلكتروني مطلوب</translation>
<translation id="5230733896359313003">عنوان الشحن</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1367,7 +1406,6 @@
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">خصائص المستند</translation>
<translation id="528468243742722775">â€Ù…Ùتاح End</translation>
-<translation id="5284909709419567258">عناوين الشبكة</translation>
<translation id="5285570108065881030">عرض جميع كلمات المرور المحÙوظة</translation>
<translation id="5287240709317226393">عرض ملÙات تعري٠الارتباط</translation>
<translation id="5287456746628258573">يستخدم هذا الموقع الإلكتروني ضبط الأمان القديم الذي قد يكش٠عن معلوماتك (مثل كلمات المرور أو أرقام بطاقة الائتمان) عند إرسالها إلى هذا الموقع الإلكتروني.</translation>
@@ -1451,6 +1489,7 @@
<translation id="5556459405103347317">إعادة التحميل</translation>
<translation id="5560088892362098740">تاريخ انتهاء الصلاحية</translation>
<translation id="55635442646131152">مخطط المستند</translation>
+<translation id="5565613213060953222">Ùتح علامة تبويب ÙÙŠ وضع التصÙّح المتخÙÙŠ</translation>
<translation id="5565735124758917034">نشط</translation>
<translation id="5570825185877910964">حماية الحساب</translation>
<translation id="5571083550517324815">لا يمكن الاستلام من هذا العنوان. اختَر عنوانًا آخر.</translation>
@@ -1533,6 +1572,7 @@
<translation id="5869522115854928033">كلمات المرور المحÙوظة</translation>
<translation id="5873013647450402046">يجب تأكيد هويتك للمصرÙ.</translation>
<translation id="5887400589839399685">تم Ø­Ùظ البطاقة</translation>
+<translation id="5887687176710214216">تمّت زيارة الموقع الإلكتروني آخر مرة أمس.</translation>
<translation id="5895138241574237353">إعادة التشغيل</translation>
<translation id="5895187275912066135">تاريخ الإصدار</translation>
<translation id="5901630391730855834">أصÙر</translation>
@@ -1546,6 +1586,7 @@
<translation id="5921639886840618607">â€Ù‡Ù„ تريد Ø­Ùظ البطاقة ÙÙŠ حساب GoogleØŸ</translation>
<translation id="5922853866070715753">أوشكْت على الانتهاء.</translation>
<translation id="5932224571077948991">يعرض الموقع الإلكتروني إعلانات مضلّÙلة أو غير مرغوب Ùيها</translation>
+<translation id="5938153366081463283">إضاÙØ© بطاقة اÙتراضية</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347">جار٠Ùتح <ph name="SITE_NAME" />…</translation>
<translation id="5951495562196540101">لا يمكن التسجيل باستخدام حساب المستهلك (الترخيص المجمّع متوÙّر).</translation>
@@ -1610,6 +1651,7 @@
<translation id="6120179357481664955">هل تتذكر معرّ٠واجهة الدÙعات الموحّدة؟</translation>
<translation id="6124432979022149706">Chrome Enterprise Connectors</translation>
<translation id="6127379762771434464">Ø£Ùزيلَ عنصر</translation>
+<translation id="6132161237766805930">â€<ph name="BEGIN_LINK" />مزيد من المعلومات حول وضع التصÙّح المتخÙÙŠ ÙÙŠ متصÙّح Chrome<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">تحقق من أي كابلات وأعد تشغيل أي أجهزة توجيه أو أجهزة مودم أو أجهزة شبكة
أخرى ربما تستخدمها.</translation>
<translation id="614940544461990577">يمكنك محاولة:</translation>
@@ -1622,7 +1664,6 @@
<translation id="6169916984152623906">يمكنك الآن التصÙّح بخصوصية تامّة، ولن يتمكّن الأشخاص الآخرون الذين يستخدمون هذا الجهاز من مشاهدة نشاطك. ولكن، سيتم Ø­Ùظ عمليات التنزيل والإشارات المرجعيّة.</translation>
<translation id="6177128806592000436">إن اتصالك بهذا الموقع غير آمن</translation>
<translation id="6180316780098470077">الÙاصل الزمني لإعادة المحاولة</translation>
-<translation id="619448280891863779">السماح للموقع الإلكتروني بطلب Ùتح النواÙØ° ووضعها على شاشاتك</translation>
<translation id="6196640612572343990">حظر ملÙات تعري٠الارتباط للجهات الخارجية</translation>
<translation id="6203231073485539293">التحقق من اتصالك بالإنترنت</translation>
<translation id="6218753634732582820">â€Ù‡Ù„ تريد إزالة العنوان من ChromiumØŸ</translation>
@@ -1645,7 +1686,7 @@
<translation id="6272383483618007430">â€ØªØ­Ø¯ÙŠØ« Google</translation>
<translation id="6276112860590028508">تظهر الصÙحات من قائمة القراءة التابعة لك هنا</translation>
<translation id="627746635834430766">â€Ù„لدÙع بشكل٠أسرع ÙÙŠ المرة القادمة، يجب Ø­Ùظ البطاقة وعنوان إرسال الÙواتير ÙÙŠ حسابك على Google.</translation>
-<translation id="6279098320682980337">ألم تتم تعبئة النموذج برقم البطاقة الاÙتراضية؟ يمكنك النقر على تÙاصيل البطاقة لنسخها.</translation>
+<translation id="6279183038361895380">اضغط على |<ph name="ACCELERATOR" />| لعرض المؤشر</translation>
<translation id="6280223929691119688">لا يمكن التسليم على هذا العنوان. اختَر عنوانًا آخر.</translation>
<translation id="6282194474023008486">الرمز البريدي</translation>
<translation id="6285507000506177184">â€Ø²Ø± إدارة عمليات التنزيل ÙÙŠ Chrome: اضغط على Ù…Ùتاح Enter لإدارة الملÙات التي تم تنزيلها ÙÙŠ Chrome</translation>
@@ -1653,6 +1694,7 @@
<translation id="6290238015253830360">ستظهر المقالات المقترحة هنا</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{ستتم إعادة تشغيل جهازك الآن}=1{ستتم إعادة تشغيل جهازك بعد ثانية واحدة}two{ستتم إعادة تشغيل جهازك بعد ثانيتين}few{ستتم إعادة تشغيل جهازك بعد # ثوانÙ}many{ستتم إعادة تشغيل جهازك بعد # ثانية}other{ستتم إعادة تشغيل جهازك بعد # ثانية}}</translation>
<translation id="6302269476990306341">â€Ø¬Ø§Ø±Ù إيقا٠"مساعد Google" على Chrome</translation>
<translation id="6305205051461490394">يتعذر الوصول إلى <ph name="URL" />.</translation>
<translation id="6312113039770857350">صÙحة الويب غير متاحة</translation>
@@ -1726,6 +1768,7 @@
<translation id="6529602333819889595">إعادة الح&amp;Ø°Ù</translation>
<translation id="6545864417968258051">البحث عن بلوتوث</translation>
<translation id="6547208576736763147">عمل ثقبَين يسارًا</translation>
+<translation id="6554732001434021288">تمّت زيارة الموقع الإلكتروني آخر مرّة قبل <ph name="NUM_DAYS" /> يوم.</translation>
<translation id="6556866813142980365">إعادة</translation>
<translation id="6569060085658103619">أنت تعرض صÙحة إضاÙØ©</translation>
<translation id="6573200754375280815">عمل ثقبَين يمينًا</translation>
@@ -1786,7 +1829,6 @@
<translation id="6757797048963528358">خضع جهازك إلى وضع السكون.</translation>
<translation id="6767985426384634228">هل تريد تعديل العنوان؟</translation>
<translation id="6768213884286397650">â€Hagaki (بطاقة بريدية)</translation>
-<translation id="6774185088257932239"><ph name="BEGIN_LINK" />مزيد من المعلومات<ph name="END_LINK" /> حول وضع التصÙÙ‘ÙØ­ المتخÙÙŠ</translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">بنÙسجي</translation>
<translation id="6786747875388722282">الإضاÙات</translation>
@@ -1870,7 +1912,6 @@
<translation id="706295145388601875">â€Ø¥Ø¶Ø§ÙØ© عناوين وإدارتها ÙÙŠ إعدادات متصÙّح Chrome</translation>
<translation id="7064851114919012435">معلومات الاتصال</translation>
<translation id="7068733155164172741">أدخÙÙ„ الرمز المكوَّن من <ph name="OTP_LENGTH" /> رقم.</translation>
-<translation id="7070090581017165256">لمحة عن هذا الموقع الإلكتروني</translation>
<translation id="70705239631109039">اتصالك بهذا الموقع تتخلله ثغرات أمنية.</translation>
<translation id="7075452647191940183">الطلب كبير جدًا</translation>
<translation id="7079718277001814089">يحتوي هذا الموقع على برامج ضارة</translation>
@@ -1887,6 +1928,12 @@
<translation id="7111012039238467737">(صالح)</translation>
<translation id="7118618213916969306">â€Ø§Ù„بحث عن عنوان URL للحاÙظة، <ph name="SHORT_URL" /></translation>
<translation id="7119414471315195487">إغلاق علامات التبويب أو البرامج الأخرى</translation>
+<translation id="7129355289156517987">â€Ø¹Ù†Ø¯ إغلاق كل علامات التبويب ÙÙŠ وضع التصÙّح المتخÙÙŠ ÙÙŠ متصÙّح ChromiumØŒ يتم محو نشاطك ÙÙŠ علامات التبويب تلك من هذا الجهاز:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />نشاط التصÙّح<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />سجلّ البحث<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />المعلومات التي تمّ إدخالها ÙÙŠ النماذج<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">لا يمكن الشحن على هذا العنوان. اختَر عنوانًا آخر.</translation>
<translation id="7132939140423847331">حظر المشر٠نسخ هذه البيانات.</translation>
<translation id="7135130955892390533">عرض الحالة</translation>
@@ -1909,6 +1956,7 @@
<translation id="7192203810768312527">يوÙÙ‘Ùر <ph name="SIZE" />. قد يتم تحميل بعض المواقع الإلكترونية بشكل أبطأ عند زيارتها ÙÙŠ المرة القادمة.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">يمكن للمشر٠الاطÙّلاع على ما يلي:</translation>
+<translation id="7202217080450895452">â€<ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />ØŒ اضغط على Ù…Ùتاح التبويب (Tab)ØŒ ثم المÙتاح Enter Ù„Ùتح علامة تبويب جديدة ÙÙŠ وضع التصÙّح المتخÙÙŠ للتصÙÙ‘ÙØ­ بخصوصية تامة.</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423">لا يلتزم <ph name="HOST_NAME" /> بمعايير الأمان.</translation>
<translation id="7210993021468939304">â€Ù†Ø´Ø§Ø· نظام التشغيل Linux ÙÙŠ الحاوية ويمكن تثبيت تطبيقات نظام التشغيل Linux وتشغيلها ÙÙŠ الحاوية.</translation>
@@ -1940,6 +1988,7 @@
<translation id="7304562222803846232">â€Ø¥Ø¯Ø§Ø±Ø© إعدادات خصوصية حسابك على Google</translation>
<translation id="7305756307268530424">تشغيل اللعبة ببطء</translation>
<translation id="7308436126008021607">المزامنة ÙÙŠ الخلÙية</translation>
+<translation id="7310392214323165548">ستتم إعادة تشغيل الجهاز قريبًا.</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">المساعدة بشأن الاتصال</translation>
<translation id="7323804146520582233">إخÙاء قسم "<ph name="SECTION" />"</translation>
@@ -1947,6 +1996,7 @@
<translation id="7334320624316649418">إعادة إ&amp;جراء الترتيب</translation>
<translation id="7335157162773372339">السماح للموقع الإلكتروني بطلب استخدام الكاميرا</translation>
<translation id="7337248890521463931">عرض المزيد من الأسطر</translation>
+<translation id="7337418456231055214">ألم تتم تعبئة الحقل برقم البطاقة الاÙتراضية؟ انقر على تÙاصيل البطاقة لنسخها. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">غير متاحة على نظامك الأساسي.</translation>
<translation id="733923710415886693">لم يتم الكش٠عن شهادة الخادم عن طريق شهادة الشÙاÙية.</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1969,6 +2019,7 @@
<translation id="7378627244592794276">لا</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">غير سارÙ</translation>
+<translation id="7388594495505979117">{0,plural, =1{ستتم إعادة تشغيل جهازك بعد دقيقة واحدة}zero{ستتم إعادة تشغيل جهازك بعد # دقيقة}two{ستتم إعادة تشغيل جهازك بعد دقيقتين}few{ستتم إعادة تشغيل جهازك بعد # دقائق}many{ستتم إعادة تشغيل جهازك بعد # دقيقة}other{ستتم إعادة تشغيل جهازك بعد # دقيقة}}</translation>
<translation id="7390545607259442187">التأكد من البطاقة</translation>
<translation id="7392089738299859607">تعديل العنوان</translation>
<translation id="7399802613464275309">تأكيد السلامة</translation>
@@ -2005,6 +2056,12 @@
<translation id="7485870689360869515">لم يتم العثور على بيانات.</translation>
<translation id="7495528107193238112">هذا المحتوى محظور. يمكنك التواصل مع مالك الموقع الإلكتروني لحلّ المشكلة.</translation>
<translation id="7497998058912824456">â€Ø²Ø±Ù‘ إنشاء مستند: اضغط على Ù…Ùتاح Enter لإنشاء "مستند Google" جديد بسرعة.</translation>
+<translation id="7506488012654002225">â€<ph name="BEGIN_EMPHASIS" />لن يحÙظ<ph name="END_EMPHASIS" /> Chromium المعلومات التالية:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />سجلّ التصÙÙ‘ÙØ­
+ <ph name="LIST_ITEM" />ملÙات تعري٠الارتباط وبيانات المواقع الإلكترونية
+ <ph name="LIST_ITEM" />المعلومات التي تم إدخالها ÙÙŠ النماذج
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">رقم تعري٠الجهاز المعروض للسياسة Ùارغ أو لا يتطابق مع رقم تعري٠الجهاز الحالي</translation>
<translation id="7508870219247277067">أخضر مصÙر</translation>
<translation id="7511955381719512146">â€Ù‚د يتتطلب Wi-Fi الذي تستخدمه زيارة <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
@@ -2118,7 +2175,6 @@
<translation id="7813600968533626083">â€Ù‡Ù„ تريد إزالة اقتراح النموذج من ChromeØŸ</translation>
<translation id="781440967107097262">هل تريد مشاركة الحاÙظة؟</translation>
<translation id="7815407501681723534">تم العثور على <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> لـ "<ph name="SEARCH_STRING" />"</translation>
-<translation id="782125616001965242">عرض معلومات حول هذا الموقع الإلكتروني</translation>
<translation id="782886543891417279">â€Ù‚د يتطلب Wi-Fi الذي تستخدمه (<ph name="WIFI_NAME" />) زيارة صÙحة تسجيل الدخول.</translation>
<translation id="7836231406687464395">â€Postfix (مغلÙ)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{لا تتوÙَّر تطبيقات}=1{تطبيق واحد (<ph name="EXAMPLE_APP_1" />)}=2{تطبيقان (<ph name="EXAMPLE_APP_1" />ØŒ Ùˆ<ph name="EXAMPLE_APP_2" />)}few{# تطبيقات (<ph name="EXAMPLE_APP_1" />ØŒ Ùˆ<ph name="EXAMPLE_APP_2" />ØŒ Ùˆ<ph name="AND_MORE" /> من التطبيقات الأخرى)}many{# تطبيقات (<ph name="EXAMPLE_APP_1" />ØŒ Ùˆ<ph name="EXAMPLE_APP_2" />ØŒ Ùˆ<ph name="AND_MORE" /> من التطبيقات الأخرى)}other{# تطبيقات (<ph name="EXAMPLE_APP_1" />ØŒ Ùˆ<ph name="EXAMPLE_APP_2" />ØŒ Ùˆ<ph name="AND_MORE" /> من التطبيقات الأخرى)}}</translation>
@@ -2135,7 +2191,6 @@
<translation id="7888575728750733395">تحديد لون الصورة</translation>
<translation id="7894280532028510793">إذا تم التأكÙد من عدم ورود أخطاء إملائية، ÙŠÙرجى <ph name="BEGIN_LINK" />محاولة تشغيل بيانات تشخيص الشبكة<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">â€C3 (مغلÙ)</translation>
-<translation id="7931318309563332511">غير معروÙ</translation>
<translation id="793209273132572360">هل تريد تعديل العنوان؟</translation>
<translation id="7932579305932748336">الطبقة الخارجية</translation>
<translation id="79338296614623784">أدخÙÙ„ رقم هات٠صحيحًا</translation>
@@ -2160,13 +2215,14 @@
<translation id="7976214039405368314">عدد الطلبات كبير جدًا.</translation>
<translation id="7977538094055660992">جهاز إخراج</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">البطاقة المرتبطة:</translation>
<translation id="798134797138789862">السماح للموقع الإلكتروني بطلب استخدام أجهزة الواقع الاÙتراضي وبياناتها</translation>
<translation id="7984945080620862648">â€Ù„ا يمكنك زيارة <ph name="SITE" /> الآن لأن الموقع الإلكتروني أرسل بيانات اعتماد مختلطة يتعذر على Chrome معالجتها. أخطاء الشبكة والهجمات عليها عادةً ما تكون مؤقتة، لذا ستعمل هذه الصÙحة لاحقًا على الأرجح.</translation>
-<translation id="79859296434321399">â€Ù„عرض محتوى الواقع المÙعزَّز، ÙŠÙرجى تثبيت ARCore</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">التجليد</translation>
<translation id="7992044431894087211">تم استئنا٠"مشاركة الشاشة" مع <ph name="APPLICATION_TITLE" />.</translation>
<translation id="7995512525968007366">غير محدد</translation>
+<translation id="7998269595945679889">â€Ø²Ø± Ùتح علامة تبويب ÙÙŠ وضع التصÙÙ‘ÙØ­ المتخÙÙŠ. اضغط على المÙتاح Enter Ù„Ùتح علامة تبويب جديدة ÙÙŠ وضع التصÙÙ‘ÙØ­ المتخÙÙŠ للتصÙÙ‘ÙØ­ بخصوصية تامة.</translation>
<translation id="800218591365569300">جرّب إغلاق علامات التبويب أو البرامج الأخرى لتÙريغ مساحة من الذاكرة.</translation>
<translation id="8004582292198964060">المتصÙّح</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{سيتم Ø­Ùظ هذه البطاقة وعنوان إرسال الÙواتير. ستتمكَّن من استخدامها عند تسجيل الدخول إلى <ph name="USER_EMAIL" />.}zero{سيتم Ø­Ùظ هذه البطاقات وعناوين إرسال الÙواتير. ستتمكَّن من استخدامها عند تسجيل الدخول إلى <ph name="USER_EMAIL" />.}two{سيتم Ø­Ùظ هاتين البطاقتين وعنواني إرسال الÙواتير. ستتمكَّن من استخدامهما عند تسجيل الدخول إلى <ph name="USER_EMAIL" />.}few{سيتم Ø­Ùظ هذه البطاقات وعناوين إرسال الÙواتير. ستتمكَّن من استخدامها عند تسجيل الدخول إلى <ph name="USER_EMAIL" />.}many{سيتم Ø­Ùظ هذه البطاقات وعناوين إرسال الÙواتير. ستتمكَّن من استخدامها عند تسجيل الدخول إلى <ph name="USER_EMAIL" />.}other{سيتم Ø­Ùظ هذه البطاقات وعناوين إرسال الÙواتير. ستتمكَّن من استخدامها عند تسجيل الدخول إلى <ph name="USER_EMAIL" />.}}</translation>
@@ -2225,7 +2281,9 @@
<translation id="8202097416529803614">ملخص الطلب</translation>
<translation id="8202370299023114387">تعارض</translation>
<translation id="8206978196348664717">â€Prc4 (مغلÙ)</translation>
-<translation id="8211406090763984747">الاتصال بموقع الويب هذا آمن</translation>
+<translation id="8211406090763984747">الاتصال بهذا الموقع الإلكتروني آمن
+</translation>
+<translation id="8217240300496046857">لا يمكن للمواقع الإلكترونية استخدام ملÙات تعري٠الارتباط لتتبّع نشاط تصÙحّك على الإنترنت. وقد تتعطّل بعض الميزات على بعض المواقع الإلكترونية.</translation>
<translation id="8218327578424803826">الموقع الذي تم تعيينه:</translation>
<translation id="8220146938470311105">â€C7/C6 (مغلÙ)</translation>
<translation id="8225771182978767009">اختار الشخص الذي أعد جهاز الكمبيوتر حظر الموقع الإلكتروني هذا.</translation>
@@ -2266,14 +2324,9 @@
<translation id="830498451218851433">الطي إلى نصÙَين</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">التطبيقات المثبَّتة وعدد مرات استخدامها</translation>
+<translation id="8317207217658302555">â€Ù‡Ù„ تريد تحديث ARCoreØŸ</translation>
<translation id="831997045666694187">مساءً</translation>
<translation id="8321476692217554900">الإشعارات</translation>
-<translation id="8328484624016508118">â€Ø¨Ø¹Ø¯ إغلاق جميع علامات التبويب ÙÙŠ وضع التصÙÙ‘ÙØ­ المتخÙÙŠØŒ يمحو Chrome:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />نشاط التصÙÙ‘ÙØ­ على هذا الجهاز<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />سجلّ البحث على هذا الجهاز<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />المعلومات التي تم إدخالها ÙÙŠ النماذج<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489">تم رÙض الدخول إلى <ph name="HOST_NAME" />.</translation>
<translation id="833262891116910667">تمييز</translation>
<translation id="8339163506404995330">لن تتم ترجمة الصÙحات باللغة <ph name="LANGUAGE" /></translation>
@@ -2283,7 +2336,8 @@
<translation id="8351131234907093545">إنشاء ملاحظة</translation>
<translation id="8355270400102541638">سياق التعطّل على جهاز المستخدÙÙ…:</translation>
<translation id="8363502534493474904">إيقا٠"وضع الطيران"</translation>
-<translation id="8364627913115013041">لم يتم تعيينها.</translation>
+<translation id="8364627913115013041">لم يتم ضبطها.
+</translation>
<translation id="8368027906805972958">جهاز غير معرو٠أو غير متواÙÙ‚ (<ph name="DEVICE_ID" />)</translation>
<translation id="8368476060205742148">â€Ø®Ø¯Ù…ات Google Play</translation>
<translation id="8369073279043109617">الحصول على رمز جديد</translation>
@@ -2325,6 +2379,7 @@
<translation id="8507227106804027148">سطر الأوامر</translation>
<translation id="8508648098325802031">رمز البحث</translation>
<translation id="8511402995811232419">إدارة ملÙات تعري٠الارتباط</translation>
+<translation id="8519753333133776369">â€Ø¬Ù‡Ø§Ø² HID سمحَ به مشرÙÙƒ</translation>
<translation id="8522552481199248698">â€ÙŠÙ…كن أن يساعدك Chrome على حماية حسابك على Google وتغيير كلمة المرور.</translation>
<translation id="8530813470445476232">â€Ù…حو سجلّ التصÙÙ‘ÙØ­ وملÙات تعري٠الارتباط وذاكرة التخزين المؤقت وغير ذلك ÙÙŠ إعدادات متصÙÙ‘ÙØ­ Chrome</translation>
<translation id="8533619373899488139">â€Ø§Ù†ØªÙ‚ÙÙ„ إلى &lt;strong&gt;chrome://policy&lt;/strong&gt; للاطّلاع على قائمة عناوين URL المحظورة والسياسات الأخرى التي ÙŠÙرضها مشر٠النظام.</translation>
@@ -2336,7 +2391,6 @@
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{إعادة ضبط الإذن}zero{إعادة ضبط الأذونات}two{إعادة ضبط الإذنَين}few{إعادة ضبط الأذونات}many{إعادة ضبط الأذونات}other{إعادة ضبط الأذونات}}</translation>
<translation id="8555010941760982128">استخدام هذا الرمز عند الدÙع</translation>
<translation id="8557066899867184262">â€Ø±Ù…ز التحقق من البطاقة (CVC) موجود خل٠بطاقتك.</translation>
-<translation id="8558485628462305855">â€Ù„عرض محتوى الواقع المÙعزَّز، ÙŠÙرجى تحديث ARCore</translation>
<translation id="8559762987265718583">تعذر إنشاء اتصال خاص بـ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> نظرًا لأن التاريخ والوقت للجهاز (<ph name="DATE_AND_TIME" />) غير صحيحين.</translation>
<translation id="8564182942834072828">مستندات Ù…Ùصولة/Ù†Ùسخ Ù…Ùصولة</translation>
<translation id="8564985650692024650">â€ÙŠÙوصي Chromium بإعادة تحديد كلمة المرور <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> ÙÙŠ حال إعادة استخدامها ÙÙŠ مواقع إلكترونية أخرى.</translation>
@@ -2356,6 +2410,7 @@
<translation id="865032292777205197">أجهزة استشعار الحركة</translation>
<translation id="8663226718884576429">ملخّص الطلب Ùˆ<ph name="TOTAL_LABEL" /> وتÙاصيل إضاÙية</translation>
<translation id="8666678546361132282">الإنجليزية</translation>
+<translation id="8669306706049782872">استخدام المعلومات المتعلقة بشاشاتك Ù„Ùتح النواÙØ° ووضعها عليها</translation>
<translation id="867224526087042813">التوقيع</translation>
<translation id="8676424191133491403">بلا تأخير</translation>
<translation id="8680536109547170164"><ph name="QUERY" />، إجابة، <ph name="ANSWER" /></translation>
@@ -2382,6 +2437,7 @@
<translation id="8731544501227493793">â€Ø²Ø± "إدارة كلمات المرور"ØŒ اضغط على Ù…Ùتاح Enter لعرض كلمات المرور ÙÙŠ إعدادات متصÙÙ‘ÙØ­ Chrome وإدارتها.</translation>
<translation id="8734529307927223492">يدير <ph name="MANAGER" /> الجهاز <ph name="DEVICE_TYPE" />.</translation>
<translation id="8737134861345396036">â€<ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />ØŒ اضغط على Ù…Ùتاح التبويب (Tab) ثم Ù…Ùتاح Enter Ù„Ùتح ناÙذة تصÙÙ‘ÙØ­ متخÙ٠جديدة للتصÙÙ‘ÙØ­ بخصوصية تامّة.</translation>
+<translation id="8737685506611670901">Ùتح روابط <ph name="PROTOCOL" /> بدلاً من <ph name="REPLACED_HANDLER_TITLE" /></translation>
<translation id="8738058698779197622">â€Ù„إنشاء اتصال آمن، Ùإنك بحاجة إلى ضبط ساعتك بشكل صحيح. وذلك لأن الشهادات التي تستخدمها المواقع الإلكترونية لتعري٠نÙسها تكون صالحة Ùقط Ù„Ùترات محددة من الوقت. Ùإذا كانت ساعة جهازك غير صحيحة، Ùلن يتمكن Chromium من التحقق من هذه الشهادات.</translation>
<translation id="8740359287975076522">â€ØªØ¹Ø°Ø± العثور على &lt;/abbr&gt;عنوان نظام أسماء النطاقات (DNS)â€&lt;abbr id="dnsDefinition"&gt; لـ <ph name="HOST_NAME" />. جار٠تشخيص المشكلة.</translation>
<translation id="8742371904523228557"><ph name="ONE_TIME_CODE" /> هو الرمز للنطاق <ph name="ORIGIN" /></translation>
@@ -2409,6 +2465,7 @@
<translation id="883848425547221593">إشارات أخرى</translation>
<translation id="884264119367021077">عنوان الشحن</translation>
<translation id="884923133447025588">لم يتمّ العثور على أي آلبة إبطال.</translation>
+<translation id="8849262850971482943">يمكنك استخدام بطاقتك الاÙتراضية للحصول على مستوى أعلى من الأمان.</translation>
<translation id="885730110891505394">â€Ù…شاركة مع Google</translation>
<translation id="8858065207712248076">â€ÙŠÙوصي Chrome بإعادة تحديد كلمة المرور <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> ÙÙŠ حال إعادة استخدامها ÙÙŠ مواقع إلكترونية أخرى.</translation>
<translation id="885906927438988819">â€Ø¥Ø°Ø§ تم التأكÙد من عدم ورود أخطاء إملائية، ÙŠÙرجى <ph name="BEGIN_LINK" />محاولة تشغيل بيانات التشخيص لشبكة Windows<ph name="END_LINK" />.</translation>
@@ -2458,6 +2515,7 @@
<translation id="9004367719664099443">â€Ø¬Ù„سة VR قيد التقدم</translation>
<translation id="9005998258318286617">â€Ùشل تحميل مستند PDF.</translation>
<translation id="9008201768610948239">تجاهل</translation>
+<translation id="901834265349196618">بريد إلكتروني</translation>
<translation id="9020200922353704812">عنوان إرسال الÙواتير للبطاقة مطلوب</translation>
<translation id="9020542370529661692">تمت ترجمة هذه الصÙحة إلى <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9020742383383852663">A8</translation>
@@ -2506,6 +2564,7 @@
<translation id="9150045010208374699">استخدام الكاميرا</translation>
<translation id="9150685862434908345">â€ÙŠÙ…كن لمشرÙÙƒ تغيير إعداد المتصÙÙ‘ÙØ­ عن بÙعد. وقد تتم أيضًا إدارة النشاط على هذا الجهاز خارج Chrome. <ph name="BEGIN_LINK" />مزيد من المعلومات<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">تم التحديث</translation>
+<translation id="9155211586651734179">تم ربط أجهزة صوتية ملحقة.</translation>
<translation id="9157595877708044936">جار٠الإعداد...</translation>
<translation id="9158625974267017556">â€C6 (مغلÙ)</translation>
<translation id="9164029392738894042">التحقّق من دقّة البيانات</translation>
diff --git a/chromium/components/strings/components_strings_as.xtb b/chromium/components/strings/components_strings_as.xtb
index 6f5254fb284..d440c77242a 100644
--- a/chromium/components/strings/components_strings_as.xtb
+++ b/chromium/components/strings/components_strings_as.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">সবিশেষ চাওক</translation>
<translation id="1030706264415084469"><ph name="URL" />ঠআপোনাৰ ডিভাইচত চিৰদিনৰ বাবে ডাঙৰ ডেটা সঞà§à¦šà¦¯à¦¼ কৰিব বিচাৰে</translation>
<translation id="1032854598605920125">ঘড়ীৰ কাà¦à¦Ÿà¦¾à§° দিশত ঘূৰাওক</translation>
+<translation id="1033329911862281889">ইনক’গনিট’ টেবে আপোনাক অনলাইনত অদৃশà§à¦¯ নকৰে:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />তেওà¦à¦²à§‹à¦•à§‡ বà§à¦¯à§±à¦¹à¦¾à§° কৰা ছাইট আৰৠসেৱাসমূহে আপà§à¦¨à¦¿ চোৱাটো চাব পাৰে<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />নিয়োগদাতা অথবা বিদà§à¦¯à¦¾à¦²à§Ÿà§‡ বà§à§°à¦¾à¦‰à¦œà¦¿à¦™à§° কাৰà§à¦¯à¦•à¦²à¦¾à¦ª টà§à§°à§‡à¦• কৰিব পাৰে<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ইণà§à¦Ÿà¦¾à§°à¦¨à§‡à¦Ÿ সেৱা পà§à§°à¦¦à¦¾à¦¨à¦•à¦¾à§°à§€à§Ÿà§‡ ৱেবৰ টà§à§°à§‡à¦«à¦¿à¦• নিৰীকà§à¦·à¦£ কৰিব পাৰে<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">অফ কৰক</translation>
<translation id="1036982837258183574">সমà§à¦ªà§‚ৰà§à¦£ সà§à¦•à§à¦°à§€à¦£à§° পৰা ওলাই যাবলৈ |<ph name="ACCELERATOR" />|ত টিপক</translation>
<translation id="1038106730571050514">পৰামৰà§à¦¶à¦¸à¦®à§‚হ দেখà§à§±à¦¾à¦“ক</translation>
<translation id="1038842779957582377">অজà§à¦žà¦¾à¦¤ নাম</translation>
<translation id="1041998700806130099">কামৰ শà§à¦¬à§€à¦Ÿà§° বাৰà§à¦¤à¦¾</translation>
<translation id="1048785276086539861">আপà§à¦¨à¦¿ à¦à¦¨â€™à¦Ÿà§‡à¦¶à§à¦¬à¦¨ সমà§à¦ªà¦¾à¦¦à¦¨à¦¾ কৰিলে, à¦à¦‡ নথিখন à¦à¦•à¦• পৃষà§à¦ à¦¾à§° ভিউলৈ সলনি হ’ব</translation>
-<translation id="1049743911850919806">ইনক’গনিট’</translation>
<translation id="1050038467049342496">অনà§à¦¯ à¦à¦ªà§â€Œà¦¬à§‹à§° বাছনি কৰক</translation>
<translation id="1055184225775184556">যোগ কৰা কারà§à¦¯à¦Ÿà§‹ &amp;আনডৠকৰক</translation>
<translation id="1056898198331236512">সতরà§à¦•à¦¬à¦¾à¦°à§à¦¤à¦¾</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">নীতিটোৰ কেশà§à¦¬ ঠিকে আছে</translation>
<translation id="1130564665089811311">পৃষà§à¦ à¦¾ অনà§à¦¬à¦¾à¦¦ কৰক বà§à¦Ÿà¦¾à¦®, à¦à¦‡ পৃষà§à¦ à¦¾à¦–ন Google Translateৰ জৰিয়তে অনà§à¦¬à¦¾à¦¦ কৰিবলৈ à¦à¦£à§à¦Ÿà¦¾à§° টিপক</translation>
<translation id="1131264053432022307">আপà§à¦¨à¦¿ পà§à§°à¦¤à¦¿à¦²à¦¿à¦ªà¦¿ কৰা পà§à§°à¦¤à¦¿à¦šà§à¦›à¦¬à¦¿</translation>
+<translation id="1142846828089312304">ইনক’গনিট’ত তৃতীয় পকà§à¦·à§° কà§à¦•à¦¿ অৱৰোধ কৰক</translation>
<translation id="1150979032973867961">à¦à¦‡ ছারà§à¦­à¦¾à§°à§‡ নিজকে <ph name="DOMAIN" /> বà§à¦²à¦¿ পà§à§°à¦®à¦¾à¦£ কৰিব নোৱাৰিলে আৰৠআপোনাৰ কমà§à¦ªà¦¿à¦‰à¦Ÿà¦¾à§°à§° অপাৰেটিং ছিষà§à¦Ÿà§‡à¦®à§‡ ইয়াৰ সà§à§°à¦•à§à¦·à¦¾à§° পà§à§°à¦®à¦¾à¦£à¦ªà¦¤à§à§° বিশà§à¦¬à¦¾à¦¸ নকৰে। à¦à§Ÿà¦¾ কোনো ভà§à¦² কনফিগাৰেশà§à¦¬à¦¨à§° বাবে বা কোনো আকà§à§°à¦®à¦£à¦•à¦¾à§°à§€à§Ÿà§‡ আপোনাৰ সংযোগ অৱৰোধ কৰাৰ বাবে হ'ব পাৰে।</translation>
<translation id="1151972924205500581">পাছৱৰà§à¦¡ পà§à§°à§Ÿà§‹à¦œà¦¨à§€à§Ÿ</translation>
<translation id="1156303062776767266">আপà§à¦¨à¦¿ কোনো সà§à¦¥à¦¾à¦¨à§€à§Ÿ বা শà§à¦¬à§‡à§Ÿà¦¾à§° কৰা ফাইল চাই আছে</translation>
@@ -64,7 +70,6 @@
<translation id="1178581264944972037">পজ কৰক</translation>
<translation id="1181037720776840403">আà¦à¦¤à§°à¦¾à¦“ক</translation>
<translation id="1186201132766001848">পাছৱৰà§à¦¡à¦¬à§‹à§° পৰীকà§à¦·à¦¾ কৰক</translation>
-<translation id="1195210374336998651">à¦à¦ªà§° ছেটিঙলৈ যাওক</translation>
<translation id="1195558154361252544">আপà§à¦¨à¦¿ অনà§à¦®à¦¤à¦¿ দিয়াটোৰ বাদে আন সকলো ছাইটৰ বাবে জাননীসমূহ সà§à¦¬à§Ÿà¦‚কà§à§°à¦¿à§Ÿà¦­à¦¾à§±à§‡ অৱৰোধ কৰা হয়</translation>
<translation id="1197088940767939838">কমলা</translation>
<translation id="1201402288615127009">পৰৱৰà§à¦¤à§€</translation>
@@ -111,7 +116,7 @@
<translation id="1307966114820526988">অপà§à§°à¦šà¦²à¦¿à¦¤ সà§à¦¬à¦¿à¦§à¦¾à¦¸à¦®à§‚হ</translation>
<translation id="1308113895091915999">অফাৰ উপলবà§à¦§</translation>
<translation id="1312803275555673949">à¦à¦‡à¦Ÿà§‹à§° সমৰà§à¦¥à¦¨à¦¤ কি পà§à§°à¦®à¦¾à¦£ আছে?</translation>
-<translation id="131405271941274527">আপà§à¦¨à¦¿ নিজৰ ফ’নটো কোনো NFC ডিভাইচত লগালে <ph name="URL" />ঠতথà§à¦¯ পঠিয়াব আৰৠগà§à§°à¦¹à¦£ কৰিবলৈ বিচাৰে</translation>
+<translation id="1314311879718644478">পৰিৱৰà§à¦§à¦¿à¦¤ বাসà§à¦¤à§±à¦¿à¦•à¦¤à¦¾à§° সমল চাওক</translation>
<translation id="1314509827145471431">সোà¦à¦«à¦¾à¦²à§‡ সংযà§à¦•à§à¦¤ কৰক</translation>
<translation id="1318023360584041678">টেবৰ গোটত ছেভ কৰা হৈছে</translation>
<translation id="1319245136674974084">à¦à¦‡ à¦à¦ªà§â€Œà¦Ÿà§‹à§° বাবে পà§à¦¨à§°à¦¾à¦‡ নà§à¦¸à§à¦§à¦¿à¦¬</translation>
@@ -161,6 +166,7 @@
<translation id="142858679511221695">কà§à¦²à¦¾à¦‰à¦¡ বà§à¦¯à§±à¦¹à¦¾à§°à¦•à¦¾à§°à§€</translation>
<translation id="1428729058023778569">à¦à¦‡ ছাইটটোৱে HTTPS সমৰà§à¦¥à¦¨ নকৰে বাবে আপà§à¦¨à¦¿ à¦à¦‡ সকীয়নিটো দেখা পাইছে। <ph name="BEGIN_LEARN_MORE_LINK" />অধিক জানক<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">পà§à§°à¦¿à¦£à§à¦Ÿ কৰক</translation>
+<translation id="1432187715652018471">পৃষà§à¦ à¦¾à¦–নে à¦à¦Ÿà¦¾ সেৱা হেণà§à¦¡à¦²à¦¾à§° ইনষà§à¦Ÿà¦² কৰিব বিচাৰে।</translation>
<translation id="1432581352905426595">সনà§à¦§à¦¾à¦¨à§° ইঞà§à¦œà¦¿à¦¨ পৰিচালনা কৰক</translation>
<translation id="1436185428532214179">আপোনাৰ ডিভাইচত ফাইল আৰৠফ’লà§à¦¡à¦¾à§° সমà§à¦ªà¦¾à¦¦à¦¨à¦¾ কৰিবলৈ বিচাৰিব পাৰে</translation>
<translation id="1442386063175183758">সোà¦à¦«à¦¾à¦²à§‡ গে'ট ফ'লà§à¦¡ কৰক</translation>
@@ -181,6 +187,12 @@
<translation id="1483493594462132177">পঠিয়াওক</translation>
<translation id="1484290072879560759">শà§à¦¬à¦¿à¦ªà¦¿à¦™à§° ঠিকনা বাছনি কৰক</translation>
<translation id="1492194039220927094">নীতি বলৱৎ কৰা:</translation>
+<translation id="149293076951187737">আপà§à¦¨à¦¿ Chromeৰ আটাইবোৰ ইনক’গà§à¦¨à¦¿à¦Ÿâ€™ টেব বনà§à¦§ কৰিলে, আপà§à¦¨à¦¿ সেই টেবসমূহত কৰা কাৰà§à¦¯à¦•à¦²à¦¾à¦ª à¦à¦‡ ডিভাইচটোৰ পৰা মচা হ’ব:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />বà§à§°à¦¾à¦‰à¦œà¦¿à¦™à§° কাৰà§à¦¯à¦•à¦²à¦¾à¦ª<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />সনà§à¦§à¦¾à¦¨à§° ইতিহাস<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ফ’ৰà§à¦®à¦¤ দিয়া তথà§à¦¯<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">টেবলৈ উভতি যাওক</translation>
<translation id="1501859676467574491">আপোনাৰ Google à¦à¦•à¦¾à¦‰à¦£à§à¦Ÿà§° পৰা কারà§à¦¡à¦¸à¦®à§‚হ দেখà§à§±à¦¾à¦“ক</translation>
<translation id="1507202001669085618">&lt;p&gt;আপà§à¦¨à¦¿ অনলাইন হোৱাৰ পূরà§à¦¬à§‡ ছাইন ইন কৰিব লগা কোনো ৱাই-ফাই পরà§à¦Ÿà§‡à¦² বà§à¦¯à§±à¦¹à¦¾à§° কৰিলে à¦à¦‡ সমসà§à¦¯à¦Ÿà§‹à§° সনà§à¦®à§à¦–ীন হ’ব।&lt;/p&gt;
@@ -208,6 +220,8 @@
<translation id="1559572115229829303">&lt;p&gt;আপোনাৰ ডিভাইচৰ তাৰিখ আৰৠসময় (<ph name="DATE_AND_TIME" />) অশà§à¦¦à§à¦§ হোৱাৰ বাবে <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />লৈ কোনো বà§à¦¯à¦•à§à¦¤à¦¿à¦—ত সংযোগ সà§à¦¥à¦¾à¦ªà¦¨ কৰিব নোৱাৰি।&lt;/p&gt;
&lt;p&gt;অনà§à¦—à§à§°à¦¹ কৰি &lt;strong&gt;ছেটিংছ&lt;/strong&gt; à¦à¦ªà§° &lt;strong&gt;সাধাৰণ&lt;/strong&gt; অংশত তাৰিখ আৰৠসময় মিলাওক।&lt;/p&gt;</translation>
+<translation id="1559839503761818503">আপোনাৰ পà§à§°à¦¶à¦¾à¦¸à¦•à§‡ আপোনাৰ ডিভাইচটো <ph name="DATE" />ৰ <ph name="TIME" />ত ৰিষà§à¦Ÿà¦¾à¦°à§à¦Ÿ কৰিব</translation>
+<translation id="156703335097561114">ঠিকনা, ইণà§à¦Ÿà¦¾à§°à¦«à§‡â€™à¦šà§° কনফিগাৰেশà§à¦¬à¦¨ আৰৠসংযোগৰ গà§à¦£à¦—ত মানৰ দৰে নেটৱৰà§à¦•à¦¿à¦™à§° তথà§à¦¯</translation>
<translation id="1567040042588613346">à¦à¦‡ নীতিটোৱে বিচৰা ধৰণে কাম কৰি আছে, কিনà§à¦¤à§ অনà§à¦¯ কোনো ঠাইত à¦à¦•à§‡à¦Ÿà¦¾ মান ছেট কৰা হৈছে আৰৠসেইটোক à¦à¦‡ নীতিটোৱে অপসাৰণ কৰিছে।</translation>
<translation id="1569487616857761740">মà§à¦¯à¦¾à¦¦ উকলাৰ তাৰিখ দিয়ক</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@
<translation id="1583429793053364125">à¦à¦‡ ৱেবপৃষà§à¦ à¦¾à¦Ÿà§‹ পà§à§°à¦¦à¦°à§à¦¶à¦¨ কৰোà¦à¦¤à§‡ কিবা আসোà¦à§±à¦¾à¦¹ হ’ল।</translation>
<translation id="1586541204584340881">আপà§à¦¨à¦¿ ইনষà§à¦Ÿà¦² কৰা à¦à¦•à§à¦¸à¦Ÿà§‡à¦¨à¦¶à§à¦¬à¦¨à¦¸à¦®à§‚হ</translation>
<translation id="1588438908519853928">সাধাৰণ</translation>
+<translation id="1589050138437146318">ARCore ইনষà§à¦Ÿà¦² কৰিবনে?</translation>
<translation id="1592005682883173041">সà§à¦¥à¦¾à¦¨à§€à¦¯à¦¼ ডেটাৰ à¦à¦•à§à¦¸à§‡à¦›</translation>
<translation id="1594030484168838125">বাছনি কৰক</translation>
<translation id="160851722280695521">Chromeত Dino Run গে’মটো খেলক</translation>
@@ -283,6 +298,7 @@
হেডাৰটো তà§à§°à§à¦Ÿà¦¿à¦ªà§‚ৰà§à¦£, যিয়ে বà§à§°à¦¾à¦‰à¦œà¦¾à§°à¦Ÿà§‹à¦• আপà§à¦¨à¦¿ <ph name="SITE" />ৰ বাবে কৰা
অনà§à§°à§‹à¦§à¦Ÿà§‹ পৰিপূৰà§à¦£ কৰাত বাধা দিয়ে। কোনো ছাইটৰ বাবে
সà§à§°à¦•à§à¦·à¦¾ আৰৠঅনà§à¦¯ বৈশিষà§à¦Ÿà§à¦¯à¦¸à¦®à§‚হ কনফিগাৰ কৰিবলৈ ছাইট অপাৰেটৰসকলে মূল নীতিসমূহ বà§à¦¯à§±à¦¹à¦¾à§° কৰিব পাৰে।</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Chromiumত ইনক’গনিট’ৰ বিষয়ে অধিক জানক<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">আপà§à¦¨à¦¿ খোলা টেববোৰ ইয়াত দেখা যাব</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -410,6 +426,7 @@
<translation id="22081806969704220">টà§à§°à§‡â€™ ৩</translation>
<translation id="2212735316055980242">নীতিটো বিচাৰি পোৱা নগ’ল</translation>
<translation id="2213606439339815911">পà§à§°à¦¬à¦¿à¦·à§à¦Ÿà¦¿à¦¬à§‹à§° আহৰণ কৰি থকা হৈছে...</translation>
+<translation id="2213612003795704869">পৃষà§à¦ à¦¾à¦–ন পà§à§°à¦¿à¦£à§à¦Ÿ কৰা হ’ল</translation>
<translation id="2215727959747642672">ফাইল সমà§à¦ªà¦¾à¦¦à¦¨à¦¾</translation>
<translation id="2218879909401188352"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />ত থকা আকà§à§°à¦®à¦£à¦•à¦¾à§°à§€à¦¸à¦•à¦²à§‡ à¦à¦¤à¦¿à§Ÿà¦¾à¦“ কà§à¦·à¦¤à¦¿à¦•à¦¾à§°à¦• à¦à¦ªà§ ইনষà§à¦Ÿà¦² কৰিব পাৰে যিবিলাকে আপোনাৰ ডিভাইচটোৰ কà§à¦·à¦¤à¦¿ কৰিব পাৰে, আপোনাৰ ম’বাইল ফ‘নৰ বিলত আপà§à¦¨à¦¿ গম নোপোৱাকৈ মাচà§à¦² যোগ কৰিব পাৰে বা আপোনাৰ বà§à¦¯à¦•à§à¦¤à¦¿à¦—ত তথà§à¦¯ চà§à§°à¦¿ কৰিব পাৰে। <ph name="BEGIN_LEARN_MORE_LINK" />অধিক জানক<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">ইণà§à¦Ÿà¦¾à§°à¦¨à§‡à¦Ÿ নাই</translation>
@@ -419,6 +436,7 @@
<translation id="2248949050832152960">WebAuthn বà§à¦¯à§±à¦¹à¦¾à§° কৰক</translation>
<translation id="2250931979407627383">বাওà¦à¦«à¦¾à¦²à§‡ কাষত চিলাওক</translation>
<translation id="225207911366869382">à¦à¦‡ নীতিটোৰ বাবে à¦à¦‡ মানটো অপà§à§°à¦šà¦²à¦¿à¦¤à¥¤</translation>
+<translation id="2256115617011615191">à¦à¦¤à¦¿à§Ÿà¦¾à¦‡ ৰিষà§à¦Ÿà¦¾à¦°à§à¦Ÿ কৰক</translation>
<translation id="2258928405015593961">মà§à¦¯à¦¾à¦¦ উকলাৰ তাৰিখ হিচাপে ভৱিষà§à¦¯à¦¤à§° à¦à¦Ÿà¦¾ তাৰিখ দিয়ক আৰৠপà§à¦¨à§° চেষà§à¦Ÿà¦¾ কৰক</translation>
<translation id="225943865679747347">আসোà¦à§±à¦¾à¦¹ ক’ড: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">HTTPৰ আসোà¦à§±à¦¾à¦¹</translation>
@@ -444,8 +462,9 @@
<translation id="2329182534073751090">ৱিণà§à¦¡â€™à¦• নিৰà§à¦¦à¦¿à¦·à§à¦Ÿ ঠাইত ৰখা</translation>
<translation id="2330137317877982892"><ph name="CREDIT_CARD" />, <ph name="EXPIRATION_DATE_ABBR" />ত মà§à¦¯à¦¾à¦¦ উকলিব</translation>
<translation id="2337852623177822836">ছেটিংটো আপোনাৰ পà§à§°à¦¶à¦¾à¦¸à¦•à§° দà§à¦¬à¦¾à§°à¦¾ নিয়নà§à¦¤à§à§°à¦£ কৰা হয়</translation>
-<translation id="2340263603246777781"><ph name="ORIGIN" />ঠযোৰা লাগিব খোজে</translation>
+<translation id="2340263603246777781"><ph name="ORIGIN" />ঠপেয়াৰ কৰিব বিচাৰে</translation>
<translation id="2346319942568447007">আপà§à¦¨à¦¿ পà§à§°à¦¤à¦¿à¦²à¦¿à¦ªà¦¿ কৰা পà§à§°à¦¤à¦¿à¦šà§à¦›à¦¬à¦¿</translation>
+<translation id="2350796302381711542">সকলো <ph name="PROTOCOL" /> লিংক <ph name="REPLACED_HANDLER_TITLE" />ৰ সলনি <ph name="HANDLER_HOSTNAME" />ক খà§à¦²à¦¿à¦¬à¦²à§ˆ অনà§à¦®à¦¤à¦¿ দিবনে?</translation>
<translation id="2354001756790975382">অনà§à¦¯ বà§à¦•à¦®à¦¾à§°à§à¦•à¦¸à¦®à§‚হ</translation>
<translation id="2354430244986887761">Googleৰ সà§à§°à¦•à§à¦·à¦¿à¦¤ বà§à§°à¦¾à¦‰à¦œà¦¿à¦™à§‡ অলপতে <ph name="SITE" />ত <ph name="BEGIN_LINK" />কà§à¦·à¦¤à¦¿à¦•à¦¾à§°à¦• à¦à¦ªà§â€Œ বিচাৰি পাইছিল<ph name="END_LINK" />।</translation>
<translation id="2355395290879513365">আকà§à§°à¦®à¦£à¦•à¦¾à§°à§€à¦¯à¦¼à§‡ আপà§à¦¨à¦¿ à¦à¦‡ ছাইটটোত চাই থকা পà§à§°à¦¤à¦¿à¦šà§à¦›à¦¬à¦¿à¦¸à¦®à§‚হ চাব পাৰিব পাৰে আৰৠসেইসমূহ সলনি কৰি আপোনাক জালত পেলাব পাৰে।</translation>
@@ -471,6 +490,7 @@
<translation id="2413528052993050574">à¦à¦‡ ছারà§à¦­à¦¾à§°à§‡ নিজকে <ph name="DOMAIN" /> বà§à¦²à¦¿ পà§à§°à¦®à¦¾à¦£ কৰিব নোৱাৰিলে আৰৠইয়াৰ সà§à§°à¦•à§à¦·à¦¾ পà§à§°à¦®à¦¾à¦£à¦ªà¦¤à§à§° হয়তো পà§à§°à¦¤à§à¦¯à¦¾à¦¹à¦¾à§° কৰা হৈছে। à¦à§Ÿà¦¾ কোনো ভà§à¦² কনফিগাৰেশà§à¦¬à¦¨à§° বাবে বা কোনো আকà§à§°à¦®à¦£à¦•à¦¾à§°à§€à§Ÿà§‡ আপোনাৰ সংযোগ পà§à§°à¦¤à¦¿à§°à§‹à¦§ কৰাৰ বাবে হ‘ব পাৰে।</translation>
<translation id="2414886740292270097">গাà§</translation>
<translation id="2430968933669123598">Google à¦à¦•à¦¾à¦‰à¦£à§à¦Ÿ পৰিচালনা কৰক, আপোনাৰ Google à¦à¦•à¦¾à¦‰à¦£à§à¦Ÿà¦¤ নিজৰ তথà§à¦¯, গোপনীয়তা আৰৠসà§à§°à¦•à§à¦·à¦¾ পৰিচালনা কৰিবলৈ à¦à¦£à§à¦Ÿà¦¾à§° টিপক</translation>
+<translation id="2436186046335138073"><ph name="HANDLER_HOSTNAME" />ক সকলো <ph name="PROTOCOL" />ৰ লিংক খà§à¦²à¦¿à¦¬à¦²à§ˆ অনà§à¦®à¦¤à¦¿ দিবনে?</translation>
<translation id="2438874542388153331">সোà¦à¦«à¦¾à¦²à§‡ চতà§à¦°à§à¦­à§‚জ আকাৰত পাঞà§à¦š কৰক</translation>
<translation id="2450021089947420533">যাতà§à§°à¦¾à¦¸à¦®à§‚হ</translation>
<translation id="2463739503403862330">পà§à§° কৰক</translation>
@@ -478,6 +498,7 @@
<translation id="2465655957518002998">ডেলিভাৰীৰ পদà§à¦§à¦¤à¦¿ বাছনি কৰক</translation>
<translation id="2465688316154986572">ষà§à¦Ÿà§‡'পল</translation>
<translation id="2465914000209955735">আপà§à¦¨à¦¿ Chromeত ডাউনল’ড কৰা ফাইল পৰিচালনা কৰক</translation>
+<translation id="2466004615675155314">ৱেবৰ পৰা তথà§à¦¯ দেখà§à§±à¦¾à¦“ক</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />নেটৱৰà§à¦• ডায়গন’ষà§à¦Ÿà¦¿à¦•à§à¦¸ চলাই চাওক<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">à¦à¦Ÿà¦¾à§° পৰা বহà§à¦¤à§‹ কà§à§°à¦®</translation>
<translation id="2470767536994572628">আপà§à¦¨à¦¿ à¦à¦¨â€™à¦Ÿà§‡à¦¶à§à¦¬à¦¨ সমà§à¦ªà¦¾à¦¦à¦¨à¦¾ কৰিলে, à¦à¦‡ নথিখন à¦à¦•à¦• পৃষà§à¦ à¦¾à§° ভিউলৈ আৰৠইয়াৰ মূল ঘূৰà§à¦£à¦¨à¦²à§ˆ পà§à¦¨à§° সলনি হ’ব</translation>
@@ -498,6 +519,7 @@
<translation id="2523886232349826891">কেৱল à¦à¦‡ ডিভাইচটোত ছেভ কৰা হয়</translation>
<translation id="2524461107774643265">অধিক তথà§à¦¯ যোগ কৰক</translation>
<translation id="2529899080962247600">à¦à¦‡ কà§à¦·à§‡à¦¤à§à§°à¦–নত <ph name="MAX_ITEMS_LIMIT" /> টাতকৈ অধিক পà§à§°à¦¬à¦¿à¦·à§à¦Ÿà¦¿ থাকিব নালাগে। পৰৱৰà§à¦¤à§€ আটাইবোৰ পà§à§°à¦¬à¦¿à¦·à§à¦Ÿà¦¿ অৱজà§à¦žà¦¾ কৰা হ’ব।</translation>
+<translation id="2535585790302968248">বà§à¦¯à¦•à§à¦¤à¦¿à¦—তভাৱে বà§à§°à¦¾à¦‰à¦œ কৰিবলৈ à¦à¦Ÿà¦¾ নতà§à¦¨ ইনক’গনিট’ টেব খোলক</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{আৰৠ১টা}one{আৰৠঅনà§à¦¯ #টা}other{আৰৠঅনà§à¦¯ #টা}}</translation>
<translation id="2536110899380797252">ঠিকনা যোগ কৰক</translation>
<translation id="2539524384386349900">চিনাকà§à¦¤ কৰক</translation>
@@ -523,7 +545,14 @@
<translation id="2597378329261239068">à¦à¦‡ নথি পাছৱরà§à¦¡à§° দà§à¦¬à¦¾à§°à¦¾ সà§à§°à¦•à§à¦·à¦¿à¦¤à¥¤ অনà§à¦—à§à§°à¦¹ কৰি à¦à¦Ÿà¦¾ পাছৱরà§à¦¡ দিয়ক।</translation>
<translation id="2609632851001447353">পà§à§°à¦•à¦¾à§°à¦­à§‡à¦¦</translation>
<translation id="2610561535971892504">পà§à§°à¦¤à¦¿à¦²à¦¿à¦ªà¦¿ কৰিবলৈ কà§à¦²à¦¿à¦• কৰক</translation>
+<translation id="2617988307566202237">Chromeঠতলত দিয়া তথà§à¦¯à¦¸à¦®à§‚হ <ph name="BEGIN_EMPHASIS" />ছেভ নকৰিব<ph name="END_EMPHASIS" />:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />আপোনাৰ বà§à§°à¦¾à¦‰à¦œà¦¿à¦™à§° ইতিহাস
+ <ph name="LIST_ITEM" />কà§à¦•à¦¿ আৰৠছাইটৰ ডেটা
+ <ph name="LIST_ITEM" />ফৰà§à¦®à¦¤ দিয়া তথà§à¦¯
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (লেফাফা)</translation>
+<translation id="2623663032199728144">আপোনাৰ সà§à¦•à§à§°à§€à¦¨à§° বিষয়ে তথà§à¦¯ বà§à¦¯à§±à¦¹à¦¾à§° কৰিবলৈ বিচাৰিব পাৰে</translation>
<translation id="2625385379895617796">আপোনাৰ ঘড়ীৰ সময় আগবাà§à¦¿ আছে</translation>
<translation id="262745152991669301">ইউà¦à¦›à¦¬à¦¿ ডিভাইচৰ সৈতে সংযোগ কৰিবলৈ বিচাৰিব পাৰে</translation>
<translation id="2629325967560697240">Chromeৰ সৰà§à¦¬à§‹à¦šà§à¦š সà§à¦¤à§°à§° সà§à§°à¦•à§à¦·à¦¾ লাভ কৰিবলৈ <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />বৰà§à¦§à¦¿à¦¤ সà§à§°à¦•à§à¦·à¦¾à§° সà§à¦¬à¦¿à¦§à¦¾à¦Ÿà§‹ অন কৰক<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -557,6 +586,7 @@
<translation id="2709516037105925701">সà§à¦¬à§Ÿà¦‚পূৰà§à¦¤à¦¿</translation>
<translation id="2713444072780614174">বগা</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />, Chromeৰ ছেটিংসমূহত আপোনাৰ পৰিশোধসমূহ আৰৠকà§à§°à§‡à¦¡à¦¿à¦Ÿ কাৰà§à¦¡à§° তথà§à¦¯ পৰিচালনা কৰিবলৈ পà§à§°à¦¥à¦®à§‡ টেব আৰৠতাৰ পাছত à¦à¦£à§à¦Ÿà¦¾à§° টিপক</translation>
+<translation id="271663710482723385">পূৰà§à¦£ সà§à¦•à§à§°à§€à¦¨à§° পৰা বাহিৰ ওলাবলৈ |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| টিপক</translation>
<translation id="2721148159707890343">অনà§à§°à§‹à¦§ সফল হৈছে</translation>
<translation id="2723669454293168317">Chromeৰ ছেটিঙত সà§à§°à¦•à§à¦·à¦¾ পৰীকà§à¦·à¦¾ চলাওক</translation>
<translation id="2726001110728089263">কাষৰ টà§à§°à§‡â€™</translation>
@@ -587,6 +617,7 @@
<translation id="2850739647070081192">আমনà§à¦¤à§à§°à¦£ (লেফাফা)</translation>
<translation id="2856444702002559011">আকà§à§°à¦®à¦£à¦•à¦¾à§°à§€à§Ÿà§‡ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />ৰ পৰা আপোনাৰ তথà§à¦¯ চà§à§°à¦¿ কৰিবলৈ চেষà§à¦Ÿà¦¾ কৰি থাকিব পাৰে (উদাহৰণসà§à¦¬à§°à§‚পে, পাছৱরà§à¦¡, বারà§à¦¤à¦¾ বা কà§à§°à§‡à¦¡à¦¿à¦Ÿ কারà§à¦¡)। <ph name="BEGIN_LEARN_MORE_LINK" />অধিক জানক<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">à¦à¦‡ ছাইটোৱে বিনা অনà§à¦®à¦¤à¦¿à¦¤ বা কোনো বিভà§à§°à¦¾à¦¨à§à¦¤à¦¿à¦•à§° বিজà§à¦žà¦¾à¦ªà¦¨ দেখà§à§±à¦¾à§Ÿà¥¤</translation>
+<translation id="286512204874376891">à¦à¦–ন ভাৰà§à¦›à§à§±à§‡à¦² কাৰà§à¦¡à§‡ আপোনাক সমà§à¦­à¦¾à¦¬à§à¦¯ পà§à§°à¦¤à¦¾à§°à¦£à¦¾à§° পৰা সà§à§°à¦•à§à¦·à¦¿à¦¤ কৰাত সহায় কৰিবলৈ আপোনাৰ পà§à§°à¦•à§ƒà¦¤ কাৰà§à¦¡à§° পৰিচয় লà§à¦•à§à§±à¦¾à§Ÿà¥¤ <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">বনà§à¦§à§à¦¤à§à¦¬à¦¸à§à¦²à¦­</translation>
<translation id="2876489322757410363">বাহà§à¦¯à¦¿à¦• কোনো à¦à¦ªà§à¦²à¦¿à¦•à§‡à¦¶à§à¦¬à¦¨à§‡à§°à§‡ পৰিশোধ কৰিবলৈ ইনক’গনিট’ ম’ড à¦à§°à¦¿ আছে। অবà§à¦¯à¦¾à¦¹à¦¤ ৰাখিবনে?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />, Chromeৰ ছেটিঙত আপোনাৰ সà§à§°à¦•à§à¦·à¦¿à¦¤ বà§à§°à¦¾à¦‰à¦œà¦¿à¦‚ আৰৠবহà§à¦¤à§‹ সà§à¦¬à¦¿à¦§à¦¾ পৰিচালনা কৰিবলৈ টেব টিপক আৰৠতাৰ পাছত à¦à¦£à§à¦Ÿà¦¾à§° টিপক</translation>
@@ -611,6 +642,7 @@
<translation id="2930577230479659665">পà§à§°à¦¤à¦¿à¦–ন পà§à§°à¦¤à¦¿à¦²à¦¿à¦ªà¦¿à§° পাছত টà§à§°à¦¿à¦® কৰক</translation>
<translation id="2932085390869194046">পাছৱৰà§à¦¡à§° পৰামৰà§à¦¶ দিয়ক...</translation>
<translation id="2934466151127459956">চৰকাৰী-পতà§à§°</translation>
+<translation id="2938225289965773019"><ph name="PROTOCOL" /> লিংকবোৰ খোলক</translation>
<translation id="2941952326391522266">à¦à¦‡ ছারà§à¦­à¦¾à§°à¦Ÿà§‹à§±à§‡ নিজকে <ph name="DOMAIN" /> বà§à¦²à¦¿ পà§à§°à¦®à¦¾à¦£ কৰিব নোৱাৰিলে; ইয়াৰ সà§à§°à¦•à§à¦·à¦¾à§° পà§à§°à¦®à¦¾à¦£à¦ªà¦¤à§à§° <ph name="DOMAIN2" />ৰ পà§à§°à¦¦à¦¾à¦¨ কৰা। à¦à§Ÿà¦¾ কোনো ভà§à¦² কনফিগাৰেশà§à¦¬à¦¨à§° বাবে বা কোনো আকà§à§°à¦®à¦£à¦•à¦¾à§°à§€à§Ÿà§‡ আপোনাৰ সংযোগ অৱৰোধ কৰাৰ বাবে হ'ব পাৰে।</translation>
<translation id="2943895734390379394">আপল'ডৰ সময়:</translation>
<translation id="2948083400971632585">আপà§à¦¨à¦¿ ছেটিঙৰ পৃষà§à¦ à¦¾à¦Ÿà§‹à§° পৰা কোনো সংযোগৰ বাবে কনফিগাৰ কৰা যিকোনো পà§à§°à¦•à§à¦¸à¦¿ অকà§à¦·à¦® কৰিব পাৰে।</translation>
@@ -643,6 +675,7 @@
<translation id="3037605927509011580">আমি দà§à¦ƒà¦–িত!</translation>
<translation id="3041612393474885105">পà§à§°à¦®à¦¾à¦£à¦ªà¦¤à§à§°à§° তথà§à¦¯</translation>
<translation id="3044034790304486808">আপোনাৰ সনà§à¦§à¦¾à¦¨ পà§à¦¨à§° আৰমà§à¦­ কৰক</translation>
+<translation id="305162504811187366">টাইমষà§à¦Ÿà¦¾à¦®à§à¦ª, হ’ষà§à¦Ÿ আৰৠকà§à¦²à¦¾à§Ÿà§‡à¦£à§à¦Ÿà§° ছেশà§à¦¬à¦¨ আইডিকে ধৰি Chrome ৰিম’ট ডেসà§à¦•à¦Ÿà¦ªà§° ইতিহাস</translation>
<translation id="3060227939791841287">C9 (লেফাফা)</translation>
<translation id="3061707000357573562">পেচà§à¦šà§â€Œ সেৱা</translation>
<translation id="306573536155379004">গে’ম আৰমà§à¦­ হৈছে।</translation>
@@ -681,6 +714,7 @@
<translation id="3197136577151645743">আপà§à¦¨à¦¿ à¦à¦‡ ডিভাইচটো কেতিয়া সকà§à§°à¦¿à§Ÿà¦­à¦¾à§±à§‡ বà§à¦¯à§±à¦¹à¦¾à§° কৰি থাকে সেয়া জানিবলৈ বিচাৰিব পাৰে</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />, আপà§à¦¨à¦¿ Chromeৰ ছেটিঙত কি তথà§à¦¯ ছিংক কৰিব সেয়া পৰিচালনা কৰিবলৈ পà§à§°à¦¥à¦®à§‡ টেব আৰৠতাৰ পাছত à¦à¦£à§à¦Ÿà¦¾à§° টিপক</translation>
<translation id="320323717674993345">পৰিশোধ বাতিল কৰক</translation>
+<translation id="3203366800380907218">ৱেবৰ পৰা</translation>
<translation id="3207960819495026254">বà§à¦•à¦®à¦¾à¦°à§à¦• কৰা হৈছে</translation>
<translation id="3209034400446768650">পৃষà§à¦ à¦¾à¦–নে মাচà§à¦² হিচাপে টকা ল’ব পাৰে</translation>
<translation id="3212581601480735796">আপà§à¦¨à¦¿ <ph name="HOSTNAME" />ত কৰা কারà§à¦¯à¦•à¦²à¦¾à¦ª নিৰীকà§à¦·à¦£ কৰি থকা হৈছে</translation>
@@ -697,10 +731,12 @@
<translation id="3234666976984236645">à¦à¦‡ ছাইটটোত সদায়েই গà§à§°à§à¦¤à§à¦¬à¦ªà§‚ৰà§à¦£ সমল ধৰা পেলাওক</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />, আপোনাৰ বà§à§°à¦¾à¦‰à¦œà¦¾à§°à§° ৰূপ কাষà§à¦Ÿà¦®à¦¾à¦‡à¦œ কৰিবলৈ টেব টিপক আৰৠতাৰ পাছত à¦à¦£à§à¦Ÿà¦¾à§° টিপক</translation>
<translation id="3240791268468473923">কোনো মিল নথকা সà§à§°à¦•à§à¦·à¦¿à¦¤ পৰিশোধৰ কà§à§°à¦¿à¦¡à§‡à¦¨à¦¶à§à¦¬à¦¿à¦¯à¦¼à§‡à¦² থকা শà§à¦¬à§€à¦Ÿà¦–ন খোলা হৈছে</translation>
+<translation id="324180406144491771">“<ph name="HOST_NAME" />â€à§° লিংকসমূহ অৱৰোধ কৰা হৈছে</translation>
<translation id="3249845759089040423">আকৰà§à¦·à¦£à§€à§Ÿ</translation>
<translation id="3252266817569339921">ফৰাচী</translation>
<translation id="3257954757204451555">à¦à¦‡ তথà§à¦¯à¦–িনিৰ উৎস কি?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />, Google Calendarত কà§à¦·à¦¿à¦ªà§à§°à¦­à¦¾à§±à§‡ à¦à¦Ÿà¦¾ নতà§à¦¨ অনà§à¦·à§à¦ à¦¾à¦¨ সৃষà§à¦Ÿà¦¿ কৰিবলৈ পà§à§°à¦¥à¦®à§‡ টেব তাৰ পাছত à¦à¦£à§à¦Ÿà¦¾à§° টিপক</translation>
+<translation id="3261488570342242926">ভাৰà§à¦›à§à§±à§‡à¦² কাৰà§à¦¡à§° বিষয়ে জানক</translation>
<translation id="3264837738038045344">Chromeৰ ছেটিঙৰ বà§à¦Ÿà¦¾à¦® পৰিচালনা কৰক, আপোনাৰ Chromeৰ ছেটিঙলৈ যাবলৈ à¦à¦£à§à¦Ÿà¦¾à§° টিপক</translation>
<translation id="3266793032086590337">মান (সংঘাত)</translation>
<translation id="3268451620468152448">খà§à¦²à¦¿ ৰখা টেব</translation>
@@ -714,6 +750,7 @@
<translation id="3288238092761586174"><ph name="URL" />ঠআপোনাৰ পৰিশোধ সতà§à¦¯à¦¾à¦ªà¦¨ কৰিবলৈ অতিৰিকà§à¦¤ পদকà§à¦·à§‡à¦ª ল’বলগীয়া হ’ব পাৰে</translation>
<translation id="3293642807462928945"><ph name="POLICY_NAME" /> নীতিৰ বিষয়ে অধিক জানক</translation>
<translation id="3295444047715739395">Chromeৰ ছেটিংসমূহত আপোনাৰ পাছৱৰà§à¦¡à¦¸à¦®à§‚হ চাওক আৰৠপৰিচালনা কৰক</translation>
+<translation id="3303795387212510132"><ph name="PROTOCOL_SCHEME" /> লিংক খà§à¦²à¦¿à¦¬à¦²à§ˆ à¦à¦ªà§â€Œà¦Ÿà§‹à¦• অনà§à¦®à¦¤à¦¿ দিবনে?</translation>
<translation id="3303855915957856445">সনà§à¦§à¦¾à¦¨à§° কোনো ফলাফল পোৱা নগ'ল</translation>
<translation id="3304073249511302126">বà§à¦²à§à¦Ÿà§à¦¥ সà§à¦•à§‡à¦¨à¦¿à¦‚</translation>
<translation id="3308006649705061278">পà§à§°à¦¤à¦¿à¦·à§à¦ à¦¾à¦¨à§° ইউনিট (অ’ইউ)</translation>
@@ -727,12 +764,6 @@
<translation id="3345782426586609320">চকà§</translation>
<translation id="3355823806454867987">পà§à§°à¦•à§à¦¸à¦¿ ছেটিংসমূহ সলনি কৰক...</translation>
<translation id="3360103848165129075">পৰিশোধ নিয়নà§à¦¤à§à§°à¦• শà§à¦¬à§€à¦Ÿà¦–ন</translation>
-<translation id="3361596688432910856">Chromeঠতলৰ তথà§à¦¯à¦¸à¦®à§‚হ <ph name="BEGIN_EMPHASIS" />ছেভ নকৰে<ph name="END_EMPHASIS" />:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />আপোনাৰ বà§à§°à¦¾à¦‰à¦œà¦¿à¦™à§° ইতিহাস
- <ph name="LIST_ITEM" />কà§à¦•à¦¿ আৰৠছাইটৰ ডেটা
- <ph name="LIST_ITEM" />ফ’মবোৰত দিয়া তথà§à¦¯
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">à¦à¦‡ নীতিটো অপà§à§°à¦šà¦²à¦¿à¦¤ <ph name="OLD_POLICY" /> নীতিটোৰ পৰা সà§à¦¬à¦¯à¦¼à¦‚কà§à§°à¦¿à¦¯à¦¼à¦­à¦¾à§±à§‡ পà§à§°à¦¤à¦¿à¦²à¦¿à¦ªà¦¿ কৰা হৈছে। আপà§à¦¨à¦¿ তাৰ পৰিৱৰà§à¦¤à§‡ à¦à¦‡ নীতিটো বà§à¦¯à§±à¦¹à¦¾à§° কৰা উচিত।</translation>
<translation id="3364869320075768271"><ph name="URL" />ঠআপোনাৰ ভাৰà§à¦šà§à§±à§‡à¦² ৰিয়েলিটি ডিভাইচ আৰৠডেটা বà§à¦¯à§±à¦¹à¦¾à§° কৰিব বিচাৰিছে</translation>
<translation id="3366477098757335611">কারà§à¦¡ চাওক</translation>
@@ -814,7 +845,6 @@
<translation id="3587738293690942763">মাজভাগ</translation>
<translation id="3592413004129370115">ইটালিয়ান (লেফাফা)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{আপà§à¦¨à¦¿ যিকোনো সময়তে নিজৰ গোটটো ৰিছেট কৰিব পাৰে। à¦à¦Ÿà¦¾ নতà§à¦¨ গোটত যোগদান কৰিবলৈ পà§à§°à¦¾à§Ÿ à¦à¦¦à¦¿à¦¨ সময় লাগে।}=1{আপà§à¦¨à¦¿ যিকোনো সময়তে নিজৰ গোটটো ৰিছেট কৰিব পাৰে। à¦à¦Ÿà¦¾ নতà§à¦¨ গোটত যোগদান কৰিবলৈ পà§à§°à¦¾à§Ÿ à¦à¦¦à¦¿à¦¨ সময় লাগে।}one{আপà§à¦¨à¦¿ যিকোনো সময়তে নিজৰ গোটটো ৰিছেট কৰিব পাৰে। à¦à¦Ÿà¦¾ নতà§à¦¨ গোটত যোগদান কৰিবলৈ {NUM_DAYS} দিন সময় লাগে।}other{আপà§à¦¨à¦¿ যিকোনো সময়তে নিজৰ গোটটো ৰিছেট কৰিব পাৰে। à¦à¦Ÿà¦¾ নতà§à¦¨ গোটত যোগদান কৰিবলৈ {NUM_DAYS} দিন সময় লাগে।}}</translation>
-<translation id="3596012367874587041">à¦à¦ªà§° ছেটিং</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">আপোনাৰ পà§à§°à¦¶à¦¾à¦¸à¦•à§° দà§à¦¬à¦¾à§°à¦¾ à¦à¦ªà§à¦²à¦¿à¦•à§‡à¦¶à§à¦¬à¦¨à¦Ÿà§‹ অৱৰোধ কৰা হৈছে</translation>
<translation id="3608932978122581043">ফীডৰ দিশ</translation>
@@ -857,6 +887,7 @@
<translation id="370972442370243704">যাতà§à§°à¦¾à§° সà§à¦¬à¦¿à¦§à¦¾à¦Ÿà§‹ অন কৰক</translation>
<translation id="3711895659073496551">নিলমà§à¦¬à¦¨ কৰক</translation>
<translation id="3712624925041724820">অনà§à¦œà§à¦žà¦¾à¦ªà¦¤à§à§° নাই</translation>
+<translation id="3714633008798122362">ৱেব কেলেণà§à¦¡à¦¾à§°</translation>
<translation id="3714780639079136834">ম'বাইল ডেটা বা ৱাই-ফাই অন কৰক</translation>
<translation id="3715597595485130451">ৱাই-ফাইৰ সৈতে সংযোগ কৰক</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />পà§à§°à¦•à§à¦¸à¦¿, ফায়াৰৱাল আৰৠDNS কনফিগাৰেশà§à¦¬à¦¨ পৰীকà§à¦·à¦£<ph name="END_LINK" /></translation>
@@ -918,6 +949,7 @@
<translation id="3906954721959377182">টেবলেট</translation>
<translation id="3909477809443608991"><ph name="URL" />ঠসà§à§°à¦•à§à¦·à¦¿à¦¤ সমল পà§à¦²à§‡â€™ কৰিব বিচাৰে। Googleঠআপোনাৰ ডিভাইচৰ পৰিচয় সতà§à¦¯à¦¾à¦ªà¦¨ কৰিব আৰৠà¦à¦‡ ছাইটটোৱে à¦à¦•à§à¦¸à§‡à¦› কৰিব পাৰে।</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">অসà§à¦¬à§€à¦•à¦¾à§° কৰক</translation>
<translation id="3939773374150895049">CVCৰ পৰিৱৰà§à¦¤à§‡ WebAuthn বà§à¦¯à§±à¦¹à¦¾à§° কৰিবনে?</translation>
<translation id="3946209740501886391">à¦à¦‡ ছাইটত সদায় সোধক</translation>
<translation id="3947595700203588284">MIDI ডিভাইচৰ সৈতে সংযোগ কৰিবলৈ অনà§à¦®à¦¤à¦¿ বিচাৰিব পাৰে</translation>
@@ -939,6 +971,7 @@
<translation id="3990250421422698716">লাহেকৈ অফছেটক হেà¦à¦šà¦•</translation>
<translation id="3996311196211510766">à¦à¦‡ <ph name="ORIGIN" /> ছাইটটোৱে অনà§à§°à§‹à¦§ কৰিছে যে à¦à¦Ÿà¦¾ মূল নীতি
ইয়াৰ সকলো অনà§à§°à§‹à¦§à¦¤à§‡ পà§à§°à¦¯à§‹à¦œà§à¦¯ কৰা হওক, কিনà§à¦¤à§ à¦à¦‡ নীতিটো বরà§à¦¤à¦®à¦¾à¦¨ পà§à§°à§Ÿà§‹à¦— কৰিব নোৱাৰি।</translation>
+<translation id="4009243425692662128">আপà§à¦¨à¦¿ পà§à§°à¦¿à¦£à§à¦Ÿ কৰা পৃষà§à¦ à¦¾à¦–নৰ সমলখিনি বিশà§à¦²à§‡à¦·à¦£ কৰিবলৈ Google Cloud অথবা তৃতীয় পকà§à¦·à¦¸à¦®à§‚হলৈ পঠিওৱা হয়। উদাহৰণসà§à¦¬à§°à§‚পে, সেইসমূহ সংবেদনশীল ডেটাৰ বাবে সà§à¦•à§‡à¦¨ কৰা হ’ব পাৰে।</translation>
<translation id="4010758435855888356">ষà§à¦Ÿâ€™à§°à§‡à¦œ à¦à¦•à§à¦¸à§‡à¦› কৰাৰ অনà§à¦®à¦¤à¦¿ দিবনে?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{{COUNT} খন পৃষà§à¦ à¦¾ থকা PDF নথি}one{{COUNT} খন পৃষà§à¦ à¦¾ থকা PDF নথি}other{{COUNT} খন পৃষà§à¦ à¦¾ থকা PDF নথি}}</translation>
<translation id="4023431997072828269">যিহেতৠà¦à¦‡ ফৰà§à¦®à¦–ন à¦à¦Ÿà¦¾ অসà§à§°à¦•à§à¦·à¦¿à¦¤ সংযোগ বà§à¦¯à§±à¦¹à¦¾à§° কৰি দাখিল কৰি থকা হৈছে, আপোনাৰ তথà§à¦¯ অনà§à¦¯ লোকে দেখা পাব।</translation>
@@ -1032,6 +1065,7 @@
<translation id="4250680216510889253">নহয়</translation>
<translation id="4253168017788158739">টোকা</translation>
<translation id="425582637250725228">আপà§à¦¨à¦¿ কৰা সালসলনিখিনি ছেভ কৰা নহ’ব পাৰে।</translation>
+<translation id="425869179292622354">à¦à¦–ন ভাৰà§à¦›à§à§±à§‡à¦² কাৰà§à¦¡à§° জৰিয়তে à¦à¦‡à¦–ন অধিক সà§à§°à¦•à§à¦·à¦¿à¦¤ কৰিবনে?</translation>
<translation id="4258748452823770588">বেয়া সà§à¦¬à¦¾à¦•à§à¦·à§°</translation>
<translation id="4261046003697461417">সà§à§°à¦•à§à¦·à¦¿à¦¤ দসà§à¦¤à¦¾à¦¬à§‡à¦œ à¦à¦¨â€™à¦Ÿà§‡à¦Ÿ কৰিব নোৱাৰি</translation>
<translation id="4265872034478892965">আপোনাৰ পà§à§°à¦¶à¦¾à¦¸à¦•à§‡ অনà§à¦®à¦¤à¦¿ দিছে</translation>
@@ -1094,6 +1128,7 @@
<translation id="4434045419905280838">পপ-আপ আৰৠপà§à¦¨à§° নিরà§à¦¦à§‡à¦¶</translation>
<translation id="4435702339979719576">প’ষà§à¦Ÿà¦•à¦¾à¦°à§à¦¡)</translation>
<translation id="443673843213245140">à¦à¦Ÿà¦¾ পà§à§°à¦•à§à¦¸à¦¿à§° বà§à¦¯à§±à¦¹à¦¾à§° অকà§à¦·à¦® কৰা হৈছে কিনà§à¦¤à§ à¦à¦Ÿà¦¾ মà§à¦–à§à¦¯ পà§à§°à¦•à§à¦¸à¦¿à§° কনফিগাৰেশà§à¦¬à¦¨ নিৰà§à¦¦à¦¿à¦·à§à¦Ÿ কৰা হৈছে।</translation>
+<translation id="4441832193888514600">নীতিটো কেৱল কà§à¦²à¦¾à¦‰à¦¡ বà§à¦¯à§±à¦¹à¦¾à§°à¦•à¦¾à§°à§€à§° নীতি হিচাপে ছেট কৰিব পাৰে বাবে উপেকà§à¦·à¦¾ কৰা হৈছে।</translation>
<translation id="4450893287417543264">পà§à¦¨à§° নেদেখà§à§±à¦¾à¦¬</translation>
<translation id="4451135742916150903">HID ডিভাইচৰ সৈতে সংযোগ কৰিবলৈ বিচাৰিব পাৰে</translation>
<translation id="4452328064229197696">আপà§à¦¨à¦¿ à¦à¦‡à¦®à¦¾à¦¤à§à§° বà§à¦¯à§±à¦¹à¦¾à§° কৰা পাছৱৰà§à¦¡à¦Ÿà§‹ à¦à¦• ডেটা উলংঘনত বিচাৰি পোৱা গৈছিল। আপোনাৰ à¦à¦•à¦¾à¦‰à¦£à§à¦Ÿà¦¸à¦®à§‚হ সà§à§°à¦•à§à¦·à¦¿à¦¤ কৰিবলৈ Google পাছৱৰà§à¦¡ পৰিচালকে আপোনাৰ ছেভ হৈ থকা পাছৱৰà§à¦¡à¦¸à¦®à§‚হ পৰীকà§à¦·à¦¾ কৰিবলৈ চà§à¦ªà¦¾à§°à¦¿à¦› কৰে।</translation>
@@ -1149,6 +1184,7 @@
<translation id="4628948037717959914">Photo</translation>
<translation id="4631649115723685955">কেশà§à¦¬à¦¬à§‡à¦• লিংক কৰা হ'ল</translation>
<translation id="4636930964841734540">তথà§à¦¯</translation>
+<translation id="4638670630777875591">Chromiumত ইনক’গনিট’</translation>
<translation id="464342062220857295">সনà§à¦§à¦¾à¦¨à§° সà§à¦¬à¦¿à¦§à¦¾à¦¸à¦®à§‚হ</translation>
<translation id="4644670975240021822">তলমà§à¦–ীয়াকৈ বিপৰীত কà§à§°à¦®</translation>
<translation id="4646534391647090355">মোক à¦à¦¤à¦¿à§Ÿà¦¾à¦‡ তালৈ নিয়ক</translation>
@@ -1169,6 +1205,7 @@
<translation id="4708268264240856090">আপোনাৰ সংযোগটো বাধাপà§à§°à¦¾à¦ªà§à¦¤ হৈছিল</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Windows Network Diagnostics চলি আছে<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426"><ph name="USERNAME" />ৰ পাছৱৰà§à¦¡</translation>
<translation id="4724144314178270921">আপোনাৰ কà§à¦²à¦¿à¦ªà¦¬â€™à§°à§à¦¡ থকা পাঠ আৰৠপà§à§°à¦¤à¦¿à¦šà§à¦›à¦¬à¦¿à¦¸à¦®à§‚হ চাবলৈ বিচাৰিব পাৰে</translation>
<translation id="4726672564094551039">নীতিসমূহ পà§à¦¨à§° ল'ড কৰক</translation>
<translation id="4728558894243024398">পà§à¦²à§‡à¦Ÿà¦«â€™à§°à§à¦®</translation>
@@ -1190,6 +1227,7 @@
<translation id="4757993714154412917">আপà§à¦¨à¦¿ à¦à¦Ÿà¦¾ পà§à§°à§±à¦žà§à¦šà¦¨à¦¾à¦®à§‚লক ছাইটত à¦à¦‡à¦®à¦¾à¦¤à§à§° নিজৰ পাছৱৰà§à¦¡à¦Ÿà§‹ দিছে। আপোনাৰ à¦à¦•à¦¾à¦‰à¦£à§à¦Ÿà¦¸à¦®à§‚হ সà§à§°à¦•à§à¦·à¦¿à¦¤ কৰিবলৈ Chromiumঠআপোনাৰ ছেভ হৈ থকা পাছৱৰà§à¦¡à¦¸à¦®à§‚হ পৰীকà§à¦·à¦¾ কৰিবলৈ চà§à¦ªà¦¾à§°à¦¿à¦› কৰে।</translation>
<translation id="4758311279753947758">সমà§à¦ªà¦°à§à¦•à§° তথà§à¦¯ যোগ কৰক</translation>
<translation id="4761104368405085019">আপোনাৰ মাইকà§à§°â€™à¦«â€™à¦¨ বà§à¦¯à§±à¦¹à¦¾à§° কৰক</translation>
+<translation id="4761869838909035636">Chromeৰ সà§à§°à¦•à§à¦·à¦¾ পৰীকà§à¦·à¦¾ চলাওক</translation>
<translation id="4764776831041365478"><ph name="URL" />ৰ ৱেবপৃষà§à¦ à¦¾à¦Ÿà§‹ অসà§à¦¥à¦¾à§Ÿà§€à¦­à¦¾à§±à§‡ বà§à¦¯à§±à¦¹à¦¾à§°à¦¯à§‹à¦—à§à¦¯ হৈ নাথাকিব পাৰে বা ইয়াক কোনো নতà§à¦¨ ৱেব ঠিকনালৈ সà§à¦¥à¦¾à§Ÿà§€ ভাৱে নিয়া হ’ব পাৰে।</translation>
<translation id="4766713847338118463">তলৰ অংশত দà§à¦¬à¦¾à§° ষà§à¦Ÿà§‡'পল কৰক</translation>
<translation id="4771973620359291008">কোনো অজà§à¦žà¦¾à¦¤ আসোà¦à§±à¦¾à¦¹ হৈছে।</translation>
@@ -1210,12 +1248,6 @@
<translation id="4819347708020428563">ডিফ’লà§à¦Ÿ ভিউত à¦à¦¨â€™à¦Ÿà§‡à¦¶à§à¦¬à¦¨ সমà§à¦ªà¦¾à¦¦à¦¨à¦¾ কৰিবনে?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />, à¦à¦–ন নতà§à¦¨ Google Sheet কà§à¦·à¦¿à¦ªà§à§°à¦­à¦¾à§±à§‡ সৃষà§à¦Ÿà¦¿ কৰিবলৈ পà§à§°à¦¥à¦®à§‡ টেব আৰৠতাৰ পাছত à¦à¦£à§à¦Ÿà¦¾à§° টিপক</translation>
<translation id="4825507807291741242">শকà§à¦¤à¦¿à¦¶à¦¾à¦²à§€</translation>
-<translation id="4827402517081186284">ইনক’গনিট’ টেবে আপোনাক অনলাইনত অদৃশà§à¦¯ নকৰে:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />আপà§à¦¨à¦¿ ছাইটসমূহ কেতিয়া চাইছিল সেয়া ছাইটসমূহে জানে<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />নিয়োগদাতা অথবা বিদà§à¦¯à¦¾à¦²à§Ÿà§‡ বà§à§°à¦¾à¦‰à¦œà¦¿à¦™à§° কারà§à¦¯à¦•à¦²à¦¾à¦ª টà§à§°à§‡à¦• কৰিব পাৰে<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />ইণà§à¦Ÿà¦¾à§°à¦¨à§‡à¦Ÿ সেৱা পà§à§°à¦¦à¦¾à¦¨à¦•à¦¾à§°à§€à§Ÿà§‡ ৱেবৰ টà§à§°à§‡à¦«à¦¿à¦• নিৰীকà§à¦·à¦£ কৰিব পাৰে<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">সকীয়নি অন কৰক</translation>
<translation id="4838327282952368871">সà§à¦¬à¦ªà§à¦¨à¦®à¦¯à¦¼</translation>
<translation id="4840250757394056958">আপোনাৰ Chromeৰ ইতিহাস চাওক</translation>
@@ -1227,12 +1259,12 @@
<translation id="4854362297993841467">ডেলিভাৰীৰ à¦à¦‡ পদà§à¦§à¦¤à¦¿à¦Ÿà§‹ নাই। অনà§à¦¯ কোনো পদà§à¦§à¦¤à¦¿ বà§à¦¯à§±à¦¹à¦¾à§° কৰি চাওক।</translation>
<translation id="4854853140771946034">Google Keepত কà§à¦·à¦¿à¦ªà§à§°à¦­à¦¾à§±à§‡ à¦à¦Ÿà¦¾ নতà§à¦¨ টোকা সৃষà§à¦Ÿà¦¿ কৰক</translation>
<translation id="485902285759009870">ক’ডটো সতà§à¦¯à¦¾à¦ªà¦¨ কৰি থকা হৈছে...</translation>
+<translation id="4866506163384898554">আপোনাৰ কাৰà§à¦›à§°à¦Ÿà§‹ দেখà§à§±à¦¾à¦¬à¦²à§ˆ |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| টিপক</translation>
<translation id="4876188919622883022">সৰলীকৃত ভিউ</translation>
<translation id="4876305945144899064">কোনো বà§à¦¯à§±à¦¹à¦¾à§°à¦•à¦¾à§°à§€à§° নাম নাই</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{à¦à¦Ÿà¦¾à¦“ নাই}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}one{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831"><ph name="TEXT" />ৰ সনà§à¦§à¦¾à¦¨</translation>
<translation id="4879491255372875719">সà§à¦¬à§Ÿà¦‚কà§à§°à¦¿à§Ÿ (ডিফ'লà§à¦Ÿ)</translation>
-<translation id="4879725228911483934">ৱিণà§à¦¡â€™à¦¸à¦®à§‚হ খোলক আৰৠআপোনাৰ সà§à¦•à§à§°à§€à¦¨à¦¸à¦®à§‚হত ৰাখক</translation>
<translation id="4880827082731008257">সনà§à¦§à¦¾à¦¨à§° ইতিহাস</translation>
<translation id="4881695831933465202">খোলক</translation>
<translation id="4885256590493466218">চেকআউট কৰাৰ সময়ত <ph name="CARD_DETAIL" />ৰ জৰিয়তে পৰিশোধ কৰক</translation>
@@ -1241,6 +1273,7 @@
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">নৱম ৰোল</translation>
<translation id="4901778704868714008">ছেভ কৰক...</translation>
+<translation id="4905659621780993806">আপোনাৰ পà§à§°à¦¶à¦¾à¦¸à¦•à§‡ আপোনাৰ ডিভাইচটো <ph name="DATE" />ৰ <ph name="TIME" />ত সà§à¦¬à§Ÿà¦‚কà§à§°à¦¿à§Ÿà¦­à¦¾à§±à§‡ ৰিষà§à¦Ÿà¦¾à¦°à§à¦Ÿ কৰিব। আপোনাৰ ডিভাইচটো ৰিষà§à¦Ÿà¦¾à¦°à§à¦Ÿ হোৱাৰ পূরà§à¦¬à§‡ যিকোনো খোলা বসà§à¦¤à§ ছেভ কৰক।</translation>
<translation id="4913987521957242411">বাওà¦à¦«à¦¾à¦²à§‡ ওপৰৰ অংশত পাঞà§à¦š কৰক</translation>
<translation id="4918221908152712722"><ph name="APP_NAME" /> ইনষà§à¦Ÿà¦² কৰক (ডাউনল’ড কৰাৰ পà§à§°à¦¯à¦¼à§‹à¦œà¦¨ নাই)</translation>
<translation id="4923459931733593730">পৰিশোধ</translation>
@@ -1249,6 +1282,7 @@
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, সনà§à¦§à¦¾à¦¨ কৰিবলৈ টেব আৰৠতাৰ পাছত à¦à¦£à§à¦Ÿà¦¾à§° টিপক</translation>
<translation id="4930153903256238152">সৰহীয়া বহনকà§à¦·à¦®à¦¤à¦¾</translation>
+<translation id="4940163644868678279">Chromeত ইনক’গনিট’</translation>
<translation id="4943872375798546930">কোনো ফলাফল নাই</translation>
<translation id="4950898438188848926">টেব সলনি কৰা বà§à¦Ÿà¦¾à¦®, খà§à¦²à¦¿ থোৱা <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /> টেবটোলৈ যাবলৈ Enter দবাওক</translation>
<translation id="495170559598752135">কাৰà§à¦¯à¦¸à¦®à§‚হ</translation>
@@ -1258,6 +1292,7 @@
<translation id="4968522289500246572">à¦à¦‡ à¦à¦ªà§â€Œà¦Ÿà§‹ ম’বাইলৰ বাবে ডিজাইন কৰা হৈছে আৰৠইয়াৰ আকাৰ ভালদৰে সলনি নহ’ব পাৰে। à¦à¦ªà§â€Œà¦Ÿà§‹ সমসà§à¦¯à¦¾à§° সনà§à¦®à§à¦–ীন অথবা ৰিষà§à¦Ÿà¦¾à§°à§à¦Ÿ হ’ব পাৰে।</translation>
<translation id="4969341057194253438">ৰেকৰà§à¦¡à¦¿à¦‚ মচক</translation>
<translation id="4973922308112707173">ওপৰৰ অংশত দà§à¦¬à¦¾à§° পাঞà§à¦š কৰক</translation>
+<translation id="4976702386844183910">শেষবাৰে <ph name="DATE" /> তাৰিখে চাইছে</translation>
<translation id="4984088539114770594">মাইকà§à¦°â€™à¦«â€™à¦¨ বà§à¦¯à§±à¦¹à¦¾à§° কৰিবনে?</translation>
<translation id="4984339528288761049">Prc5 (লেফাফা)</translation>
<translation id="4989163558385430922">সকলো চাওক</translation>
@@ -1319,6 +1354,7 @@
<translation id="5138227688689900538">কমকৈ দেখà§à§±à¦¾à¦“ক</translation>
<translation id="5145883236150621069">নীতিৰ সà¦à¦¹à¦¾à§°à¦¿à¦¤ কোনো আসোà¦à§±à¦¾à¦ªà§‚রà§à¦£ ক'ড আছে</translation>
<translation id="5146995429444047494"><ph name="ORIGIN" />ৰ জাননীসমূহ অৱৰোধ কৰা আছে</translation>
+<translation id="514704532284964975">আপà§à¦¨à¦¿ নিজৰ ফ’নৰ জৰিয়তে টিপা NFC ডিভাইচত <ph name="URL" />ঠতথà§à¦¯ চাব আৰৠসলনি কৰিব বিচাৰে</translation>
<translation id="5148809049217731050">ওপৰমà§à¦–ীয়া</translation>
<translation id="515292512908731282">C4 (লেফাফা)</translation>
<translation id="5158275234811857234">ক'ভাৰ</translation>
@@ -1343,6 +1379,7 @@
<translation id="5215116848420601511">Google Pay বà§à¦¯à§±à¦¹à¦¾à§° কৰা পৰিশোধ পদà§à¦§à¦¤à¦¿ আৰৠঠিকনা</translation>
<translation id="5215363486134917902">ফ'লিঅ'-Sp</translation>
<translation id="521659676233207110">টà§à§°à§‡â€™ ১৩</translation>
+<translation id="5216942107514965959">শেষবাৰ আজি চাইছে</translation>
<translation id="5222812217790122047">ইমেইল বাধà§à¦¯à¦¤à¦¾à¦®à§‚লক</translation>
<translation id="5230733896359313003">শà§à¦¬à¦¿à¦ªà¦¿à¦™à§° ঠিকনা</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1363,7 +1400,6 @@
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">নথিৰ বৈশিষà§à¦Ÿà§à¦¯</translation>
<translation id="528468243742722775">সমাপà§à¦¤</translation>
-<translation id="5284909709419567258">নেটৱৰà§à¦•à§° ঠিকনাসমূহ</translation>
<translation id="5285570108065881030">ছেভ কৰি থোৱা সকলো পাছৱৰà§à¦¡ দেখà§à§±à¦¾à¦“ক</translation>
<translation id="5287240709317226393">কà§à¦•à¦¿à¦¸à¦®à§‚হ দেখà§à§±à¦¾à¦“ক</translation>
<translation id="5287456746628258573">à¦à¦‡ ছাইটটোৱে à¦à¦Ÿà¦¾ পà§à§°à¦£à¦¿ সà§à§°à¦•à§à¦·à¦¾ সমà§à¦ªà§°à§à¦•à§€à§Ÿ কনফিগাৰেশà§à¦¬à¦¨ বà§à¦¯à§±à¦¹à¦¾à§° কৰে, যিয়ে আপোনাৰ তথà§à¦¯ (উদাহৰণসà§à¦¬à§°à§‚পে, পাছৱৰà§à¦¡à¦¸à¦®à§‚হ অথবা কà§à§°à§‡à¦¡à¦¿à¦Ÿ কাৰà§à¦¡à§° নমà§à¦¬à§°à¦¸à¦®à§‚হ) সদৰী কৰিব পাৰে যেতিয়া à¦à§Ÿà¦¾ à¦à¦‡ ছাইটটোলৈ পঠিওৱা হয়।</translation>
@@ -1447,6 +1483,7 @@
<translation id="5556459405103347317">পà§à¦¨à§° ল’ড কৰক</translation>
<translation id="5560088892362098740">মà§à¦¯à¦¾à¦¦ উকলাৰ তাৰিখ</translation>
<translation id="55635442646131152">নথিৰ ৰূপৰেখা</translation>
+<translation id="5565613213060953222">ইনক’গনিট’ টেব খোলক</translation>
<translation id="5565735124758917034">সকà§à§°à¦¿à§Ÿ</translation>
<translation id="5570825185877910964">à¦à¦•à¦¾à¦‰à¦£à§à¦Ÿ সà§à§°à¦•à§à¦·à¦¿à¦¤ কৰক</translation>
<translation id="5571083550517324815">à¦à¦‡ ঠিকনাৰ পৰা পিকআপ কৰিব নোৱাৰি। অনà§à¦¯ à¦à¦Ÿà¦¾ ঠিকনা বাছনি কৰক।</translation>
@@ -1514,7 +1551,7 @@
<translation id="5810442152076338065">আপোনাৰ <ph name="DOMAIN" />ৰ সৈতে থকা সংযোগ কোনো অপà§à§°à¦šà¦²à¦¿à¦¤ চাইফাৰ ছà§à¦Ÿ বà§à¦¯à§±à¦¹à¦¾à§° কৰি à¦à¦¨à¦•à§à§°à¦¿à¦ªà§à¦Ÿ কৰা হৈছে।</translation>
<translation id="5812947184178430888">Chromeঠসà§à§°à¦•à§à¦·à¦¾ সমà§à¦ªà§°à§à¦•à§€à¦¯à¦¼ ঘটনা ফà§à¦²à§‡à¦— কৰিলে ঘটনাসমূহৰ বিষয়ে পà§à§°à¦¾à¦¸à¦‚গিক ডেটা আপোনাৰ পà§à§°à¦¶à¦¾à¦¸à¦•à¦²à§ˆ পঠিওৱা হয়। ইয়াত আপà§à¦¨à¦¿ Chromeত চোৱা পৃষà§à¦ à¦¾à¦¸à¦®à§‚হৰ URL, ফাইলৰ নাম অথবা মেটাডেটা আৰৠআপà§à¦¨à¦¿ ৱেবৰ ওপৰত আধাৰিত à¦à¦ªà§à¦²à¦¿à¦•à§‡à¦¶à§à¦¬à¦¨, নিজৰ ডিভাইচ তথা Chromeত ছাইন ইন কৰিবলৈ বà§à¦¯à§±à¦¹à¦¾à§° কৰা বà§à¦¯à§±à¦¹à¦¾à§°à¦•à¦¾à§°à§€à§° নামটো থাকিব পাৰে।</translation>
<translation id="5813119285467412249">যোগ কৰা কারà§à¦¯ &amp;ৰিডৠকৰক</translation>
-<translation id="5817918615728894473">যোৰা লগাওক</translation>
+<translation id="5817918615728894473">পেয়াৰ কৰক</translation>
<translation id="5824687817967109979">{NUM_CARDS,plural, =1{আপà§à¦¨à¦¿ পৰিশোধ কৰিলে à¦à¦‡ কাৰà§à¦¡à¦–নৰ পৰা টকা আদায় দিয়া হ’ব কিনà§à¦¤à§ ইয়াৰ পà§à§°à¦•à§ƒà¦¤ নমà§à¦¬à§°à¦Ÿà§‹ à¦à¦‡ ছাইটটোৰ সৈতে শà§à¦¬à§‡à¦¯à¦¼à¦¾à§° কৰা নহ’ব। অতিৰিকà§à¦¤ সà§à§°à¦•à§à¦·à¦¾à§° বাবে à¦à¦Ÿà¦¾ সাময়িক CVC সৃষà§à¦Ÿà¦¿ কৰা হ’ব।}one{আপà§à¦¨à¦¿ পৰিশোধ কৰিলে আপà§à¦¨à¦¿ বাছনি কৰা কাৰà§à¦¡à¦–নৰ পৰা টকা আদায় দিয়া হ’ব কিনà§à¦¤à§ ইয়াৰ পà§à§°à¦•à§ƒà¦¤ নমà§à¦¬à§°à¦Ÿà§‹ à¦à¦‡ ছাইটটোৰ সৈতে শà§à¦¬à§‡à¦¯à¦¼à¦¾à§° কৰা নহ’ব। অতিৰিকà§à¦¤ সà§à§°à¦•à§à¦·à¦¾à§° বাবে à¦à¦Ÿà¦¾ সাময়িক CVC সৃষà§à¦Ÿà¦¿ কৰা হ’ব।}other{আপà§à¦¨à¦¿ পৰিশোধ কৰিলে আপà§à¦¨à¦¿ বাছনি কৰা কাৰà§à¦¡à¦–নৰ পৰা টকা আদায় দিয়া হ’ব কিনà§à¦¤à§ ইয়াৰ পà§à§°à¦•à§ƒà¦¤ নমà§à¦¬à§°à¦Ÿà§‹ à¦à¦‡ ছাইটটোৰ সৈতে শà§à¦¬à§‡à¦¯à¦¼à¦¾à§° কৰা নহ’ব। অতিৰিকà§à¦¤ সà§à§°à¦•à§à¦·à¦¾à§° বাবে à¦à¦Ÿà¦¾ সাময়িক CVC সৃষà§à¦Ÿà¦¿ কৰা হ’ব।}}</translation>
<translation id="5826507051599432481">কামাণà§à¦¡à§° নাম (CN)</translation>
<translation id="5830698870816298009">কেমেৰাৰ বà§à¦¯à§±à¦¹à¦¾à§° আৰৠগতিবিধি</translation>
@@ -1529,6 +1566,7 @@
<translation id="5869522115854928033">ছেভ কৰা পাছৱৰà§à¦¡à¦¸à¦®à§‚হ</translation>
<translation id="5873013647450402046">আপোনাৰ বেংকে à¦à¦¯à¦¼à¦¾ আপà§à¦¨à¦¿ বà§à¦²à¦¿ নিশà§à¦šà¦¿à¦¤ কৰিবলৈ বিচাৰে।</translation>
<translation id="5887400589839399685">কাৰà§à¦¡ ছেভ কৰা হ’ল</translation>
+<translation id="5887687176710214216">শেষবাৰ কালি চাইছিল</translation>
<translation id="5895138241574237353">ৰিষà§à¦Ÿà¦¾à§°à§à¦Ÿ কৰক</translation>
<translation id="5895187275912066135">জাৰি কৰা তাৰিখ</translation>
<translation id="5901630391730855834">হালধীয়া</translation>
@@ -1538,10 +1576,11 @@
<translation id="59174027418879706">সকà§à¦·à¦® কৰা আছে</translation>
<translation id="5919090499915321845">B10</translation>
<translation id="5920262536204764679">{NUM_COOKIES,plural, =1{১টা বà§à¦¯à§±à¦¹à¦¾à§° হৈ আছে}one{#টা বà§à¦¯à§±à¦¹à¦¾à§° হৈ আছে}other{#টা বà§à¦¯à§±à¦¹à¦¾à§° হৈ আছে}}</translation>
-<translation id="5921185718311485855">অন</translation>
+<translation id="5921185718311485855">অন আছে</translation>
<translation id="5921639886840618607">কাৰà§à¦¡à¦–ন Google à¦à¦•à¦¾à¦‰à¦£à§à¦Ÿà¦¤ ছেভ কৰিবনে?</translation>
<translation id="5922853866070715753">পà§à§°à¦¾à§Ÿ সমà§à¦ªà§‚রà§à¦£ হৈছেই</translation>
<translation id="5932224571077948991">ছাইটে বিনা অনà§à¦®à¦¤à¦¿à¦¤ বা কোনো বিভà§à§°à¦¾à¦¨à§à¦¤à¦¿à¦•à§° বিজà§à¦žà¦¾à¦ªà¦¨ দেখà§à§±à¦¾à§Ÿ</translation>
+<translation id="5938153366081463283">ভাৰà§à¦šà§à§±à§‡à¦² কাৰà§à¦¡à¦–ন যোগ দিয়ক</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347"><ph name="SITE_NAME" /> খà§à¦²à¦¿ থকা হৈছে…</translation>
<translation id="5951495562196540101">উপভোকà§à¦¤à¦¾à§° à¦à¦•à¦¾à¦‰à¦£à§à¦Ÿà§° সৈতে পঞà§à¦œà§€à§Ÿà¦¨ কৰিব নোৱাৰি (পেকেজ অনà§à¦œà§à¦žà¦¾à¦ªà¦¤à§à§° উপলবà§à¦§)।</translation>
@@ -1606,6 +1645,7 @@
<translation id="6120179357481664955">আপোনাৰ UPI IDটো মনত আছেনে?</translation>
<translation id="6124432979022149706">Chrome à¦à¦£à§à¦Ÿà¦¾à§°à¦ªà§à§°à¦¾à¦‡à¦œ কানেকà§à¦Ÿà§°à¦¸à¦®à§‚হ</translation>
<translation id="6127379762771434464">বসà§à¦¤à§à¦Ÿà§‹ আà¦à¦¤à§°à§‹à§±à¦¾ হ’ল</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Chromeত ইনক’গনিট’ৰ বিষয়ে অধিক জানক<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">কোনো কেবল পৰীকà§à¦·à¦¾ কৰক আৰৠআপà§à¦¨à¦¿ বà§à¦¯à§±à¦¹à¦¾à§° কৰি থকা কোনো ৰাউটাৰ, ম’ডেম বা অনà§à¦¯ নেটৱৰà§à¦• ডিভাইচ ৰিবà§à¦Ÿ কৰক।</translation>
<translation id="614940544461990577">à¦à¦‡à¦–িনি কৰি চাওক:</translation>
<translation id="6150036310511284407">বাওà¦à¦«à¦¾à¦²à§‡ তিনিবাৰ পাঞà§à¦š কৰক</translation>
@@ -1617,7 +1657,6 @@
<translation id="6169916984152623906">বরà§à¦¤à¦®à¦¾à¦¨ আপà§à¦¨à¦¿ বà§à¦¯à¦•à§à¦¤à¦¿à¦—তভাৱে বà§à§°à¦¾à¦œà¦¿à¦‚ কৰিব পাৰিব আৰৠà¦à¦‡ ডিভাইচটো বà§à¦¯à§±à¦¹à¦¾à§° কৰা অনà§à¦¯ লোকসকলে আপোনাৰ কারà§à¦¯à¦•à¦²à¦¾à¦ª দেখা নাপাব। তথাপিও, ডাউনল’ড আৰৠবà§à¦•à¦®à¦¾à¦°à§à¦•à¦¸à¦®à§‚হ ছেভ কৰা হ’ব।</translation>
<translation id="6177128806592000436">à¦à¦‡ ছাইটলৈ থকা আপোনাৰ সংযোগটো সà§à§°à¦•à§à¦·à¦¿à¦¤ নহয়</translation>
<translation id="6180316780098470077">পà§à¦¨à¦ƒà¦šà§‡à¦·à§à¦Ÿà¦¾à§° অনà§à¦¤à§°à¦¾à¦²</translation>
-<translation id="619448280891863779">আপোনাৰ সà§à¦•à§à§°à§€à¦¨à¦¸à¦®à§‚হত ৱিণà§à¦¡â€™ খà§à¦²à¦¿à¦¬à¦²à§ˆ আৰৠথ’বলৈ বিচাৰিব পাৰে</translation>
<translation id="6196640612572343990">তৃতীয়-পকà§à¦·à§° কà§à¦•à¦¿à¦¸à¦®à§‚হ অৱৰোধ কৰক</translation>
<translation id="6203231073485539293">আপোনাৰ ইণà§à¦Ÿà¦¾à§°à¦¨à§‡à¦Ÿ সংযোগ পৰীকà§à¦·à¦¾ কৰক</translation>
<translation id="6218753634732582820">Chromiumৰ পৰা ঠিকনা আà¦à¦¤à§°à¦¾à¦¬à¦¨à§‡?</translation>
@@ -1640,7 +1679,7 @@
<translation id="6272383483618007430">Google আপডে’ট</translation>
<translation id="6276112860590028508">আপোনাৰ পà§à¦¾à§° সূচীৰ পৃষà§à¦ à¦¾à¦¸à¦®à§‚হ ইয়াত পà§à§°à¦¦à¦°à§à¦¶à¦¨ হয়</translation>
<translation id="627746635834430766">পৰৱৰà§à¦¤à§€ সময়ত দà§à§°à§à¦¤à¦­à¦¾à§±à§‡ পৰিশোধ কৰিবলৈ আপোনাৰ কাৰà§à¦¡ আৰৠবিলিঙৰ ঠিকনা নিজৰ Google à¦à¦•à¦¾à¦‰à¦£à§à¦Ÿà¦¤ ছেভ কৰক।</translation>
-<translation id="6279098320682980337">ভাৰà§à¦šà§à§±à§‡à¦² কাৰà§à¦¡à§° নমà§à¦¬à§°à¦Ÿà§‹ পূৰ কৰা নাই নেকি? পà§à§°à¦¤à¦¿à¦²à¦¿à¦ªà¦¿ কৰিবলৈ কাৰà§à¦¡à§° সবিশেষত কà§à¦²à¦¿à¦• কৰক</translation>
+<translation id="6279183038361895380">আপোনাৰ কাৰà§à¦›à§°à¦Ÿà§‹ দেখà§à§±à¦¾à¦¬à¦²à§ˆ |<ph name="ACCELERATOR" />| টিপক</translation>
<translation id="6280223929691119688">à¦à¦‡ ঠিকনাটোত পঠিয়াব নোৱাৰি৷ অনà§à¦¯ à¦à¦Ÿà¦¾ ঠিকনা বাছনি কৰক।</translation>
<translation id="6282194474023008486">পিন ক'ড</translation>
<translation id="6285507000506177184">Chrome বà§à¦Ÿà¦¾à¦®à¦¤ ডাউনল’ড পৰিচালনা কৰক, আপà§à¦¨à¦¿ Chromeৰ জৰিয়তে ডাউনল’ড কৰা ফাইল পৰিচালনা কৰিবলৈ à¦à¦£à§à¦Ÿà¦¾à§° টিপক</translation>
@@ -1648,6 +1687,7 @@
<translation id="6290238015253830360">আপà§à¦¨à¦¿ পৰামৰà§à¦¶ দিয়া পà§à§°à¦¬à¦¨à§à¦§à¦¬à§‹à§° ইয়াত দেখা যাব</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">চিভিচি:</translation>
+<translation id="6300452962057769623">{0,plural, =0{আপোনাৰ ডিভাইচটো à¦à¦¤à¦¿à§Ÿà¦¾à¦‡ ৰিষà§à¦Ÿà¦¾à§°à§à¦Ÿ হ'ব}=1{আপোনাৰ ডিভাইচটো ১ ছেকেণà§à¦¡à¦¤ ৰিষà§à¦Ÿà¦¾à§°à§à¦Ÿ হ'ব}one{আপোনাৰ ডিভাইচটো # ছেকেণà§à¦¡à¦¤ ৰিষà§à¦Ÿà¦¾à§°à§à¦Ÿ হ'ব}other{আপোনাৰ ডিভাইচটো # ছেকেণà§à¦¡à¦¤ ৰিষà§à¦Ÿà¦¾à§°à§à¦Ÿ হ'ব}}</translation>
<translation id="6302269476990306341">Chromeত Google Assistant বনà§à¦§ হ'ব</translation>
<translation id="6305205051461490394"><ph name="URL" />ত উপনীত হ’ব নোৱাৰি৷</translation>
<translation id="6312113039770857350">ৱেবপৃষà§à¦ à¦¾ উপলবà§à¦§ নহয়</translation>
@@ -1721,6 +1761,7 @@
<translation id="6529602333819889595">মচা কারà§à¦¯ &amp;ৰিডৠকৰক</translation>
<translation id="6545864417968258051">বà§à¦²à§à¦Ÿà§à¦¥ সà§à¦•à§‡à¦¨à¦¿à¦‚</translation>
<translation id="6547208576736763147">বাওà¦à¦«à¦¾à¦²à§‡ দà§à¦¬à¦¾à§° পাঞà§à¦š কৰক</translation>
+<translation id="6554732001434021288"><ph name="NUM_DAYS" /> দিনৰ পূৰà§à¦¬à§‡ শেষবাৰ চাইছিল</translation>
<translation id="6556866813142980365">ৰিডà§</translation>
<translation id="6569060085658103619">আপà§à¦¨à¦¿ কোনো à¦à¦•à§à¦¸à¦Ÿà§‡à¦¨à¦¶à§à¦¬à¦¨à§° পৃষà§à¦ à¦¾ চাই আছে</translation>
<translation id="6573200754375280815">সোà¦à¦«à¦¾à¦²à§‡ দà§à¦¬à¦¾à§° পাঞà§à¦š কৰক</translation>
@@ -1781,7 +1822,6 @@
<translation id="6757797048963528358">আপোনাৰ ডিভাইচটো সà§à¦ªà§à¦¤ অৱসà§à¦¥à¦¾à¦²à§ˆ গৈছে।</translation>
<translation id="6767985426384634228">ঠিকনা আপডে’ট কৰিবনে?</translation>
<translation id="6768213884286397650">হেগাকি (প'ষà§à¦Ÿà¦•à¦¾à§°à§à¦¡)</translation>
-<translation id="6774185088257932239">ইনক’গনিট’ টেবৰ বিষয়ে <ph name="BEGIN_LINK" />অধিক জানক<ph name="END_LINK" /></translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">বেঙà§à¦¨à§€à§Ÿà¦¾</translation>
<translation id="6786747875388722282">à¦à¦•à§à¦¸à¦Ÿà§‡à¦¨à¦¶à§à¦¬à¦¨à¦¸à¦®à§‚হ</translation>
@@ -1865,7 +1905,6 @@
<translation id="706295145388601875">Chromeৰ ছেটিঙত ঠিকনা যোগ দিয়ক আৰৠপৰিচালনা কৰক</translation>
<translation id="7064851114919012435">যোগাযোগৰ তথà§à¦¯</translation>
<translation id="7068733155164172741"><ph name="OTP_LENGTH" />-টা অংকৰ ক’ডটো দিয়ক</translation>
-<translation id="7070090581017165256">à¦à¦‡ ছাইটটোৰ বিষয়ে</translation>
<translation id="70705239631109039">আপোনাৰ সংযোগটো সমà§à¦ªà§‚রà§à¦£à¦­à¦¾à§±à§‡ সà§à§°à¦•à§à¦·à¦¿à¦¤ নহয়</translation>
<translation id="7075452647191940183">অনà§à§°à§‹à¦§à¦Ÿà§‹ অতি ডাঙৰ</translation>
<translation id="7079718277001814089">à¦à¦‡ ছাইটটোত মালৱেৰ আছে</translation>
@@ -1882,6 +1921,12 @@
<translation id="7111012039238467737">(মানà§à¦¯)</translation>
<translation id="7118618213916969306">কà§à¦²à¦¿à¦ªà¦¬'ৰà§à¦¡ URL, <ph name="SHORT_URL" /> সনà§à¦§à¦¾à¦¨ কৰক</translation>
<translation id="7119414471315195487">অনà§à¦¯ টেব বা পà§à§°â€™à¦—à§à§°à¦¾à¦®à¦¬à§‹à§° বনà§à¦§ কৰক</translation>
+<translation id="7129355289156517987">আপà§à¦¨à¦¿ Chromiumৰ আটাইবোৰ ইনক’গà§à¦¨à¦¿à¦Ÿâ€™ টেব বনà§à¦§ কৰিলে, আপà§à¦¨à¦¿ সেই টেবসমূহত কৰা কাৰà§à¦¯à¦•à¦²à¦¾à¦ª à¦à¦‡ ডিভাইচটোৰ পৰা মচা হ’ব:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />বà§à§°à¦¾à¦‰à¦œà¦¿à¦™à§° কাৰà§à¦¯à¦•à¦²à¦¾à¦ª<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />সনà§à¦§à¦¾à¦¨à§° ইতিহাস<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ফ’ৰà§à¦®à¦¤ দিয়া তথà§à¦¯<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">à¦à¦‡ ঠিকনালৈ পঠিয়াব নোৱাৰি। অনà§à¦¯ à¦à¦Ÿà¦¾ ঠিকনা বাছনি কৰক।</translation>
<translation id="7132939140423847331">আপোনাৰ পà§à§°à¦¶à¦¾à¦¸à¦•à§‡ à¦à¦‡à¦–িনি ডেটা পà§à§°à¦¤à¦¿à¦²à¦¿à¦ªà¦¿ কৰাটো নিষিদà§à¦§ কৰি থৈছে।</translation>
<translation id="7135130955892390533">সà§à¦¥à¦¿à¦¤à¦¿ দেখà§à§±à¦¾à¦“ক</translation>
@@ -1904,6 +1949,7 @@
<translation id="7192203810768312527"><ph name="SIZE" />লৈকে বিনামূলীয়া। আপà§à¦¨à¦¿ পৰৱরà§à¦¤à§€ সময়ত কিছà§à¦®à¦¾à¦¨ ছাইট চাওতে লেহেমীয়াকৈ ল’ড হ’ব পাৰে।</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">আপোনাৰ পà§à§°à¦¶à¦¾à¦¸à¦•à§‡ à¦à¦¯à¦¼à¦¾ চাব পাৰে:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, বà§à¦¯à¦•à§à¦¤à¦¿à¦—তভাৱে বà§à§°à¦¾à¦‰à¦œ কৰাৰ বাবে à¦à¦Ÿà¦¾ নতà§à¦¨ ইনক’গনিট’ টেব খà§à¦²à¦¿à¦¬à¦²à§ˆ পà§à§°à¦¥à¦®à§‡ টেব আৰৠতাৰ পাছত à¦à¦£à§à¦Ÿà¦¾à§° টিপক</translation>
<translation id="7202346780273620635">পতà§à§°-অতিৰিকà§à¦¤</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" />ঠসà§à§°à¦•à§à¦·à¦¾à§° নীতি মানি নচলে।</translation>
<translation id="7210993021468939304">কণà§à¦Ÿà§‡à¦‡à¦¨à¦¾à§°à¦Ÿà§‹à§° ভিতৰৰ Linux কাৰà§à¦¯à¦•à¦²à¦¾à¦ªà§‡ কণà§à¦Ÿà§‡à¦‡à¦¨à¦¾à§°à§° ভিতৰত থকা Linux à¦à¦ªà§â€Œà¦¸à¦®à§‚হ ইনষà§à¦Ÿà¦² কৰিব আৰৠচলাব পাৰে</translation>
@@ -1935,6 +1981,7 @@
<translation id="7304562222803846232">Google à¦à¦•à¦¾à¦‰à¦£à§à¦Ÿà§° গোপনীয়তাৰ ছেটিং পৰিচালনা কৰক</translation>
<translation id="7305756307268530424">লেহেমীয়া গতি আৰমà§à¦­ কৰক</translation>
<translation id="7308436126008021607">নেপথà§à¦¯à¦¤ ছিংক কৰা</translation>
+<translation id="7310392214323165548">ডিভাইচটো শীঘà§à§°à§‡à¦‡ ৰিষà§à¦Ÿà¦¾à¦°à§à¦Ÿ হ’ব</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">সংযোগ সমà§à¦ªà§°à§à¦•à§€à§Ÿ সহায়</translation>
<translation id="7323804146520582233">"<ph name="SECTION" />" শাখাটো লà§à¦•à§à§±à¦¾à¦“ক</translation>
@@ -1942,6 +1989,7 @@
<translation id="7334320624316649418">&amp;পà§à¦¨à§° কà§à§°à¦®à¦¬à¦¦à§à¦§ কৰাটো ৰিডৠকৰক</translation>
<translation id="7335157162773372339">আপোনাৰ কেমেৰা বà§à¦¯à§±à¦¹à¦¾à§° কৰিবলৈ বিচাৰিব পাৰে</translation>
<translation id="7337248890521463931">অধিক শাৰী দেখà§à§±à¦¾à¦“ক</translation>
+<translation id="7337418456231055214">ভাৰà§à¦šà§à§±à§‡à¦² কাৰà§à¦¡à§° নমà§à¦¬à§°à¦Ÿà§‹ পূৰ কৰা নাই নেকি? পà§à§°à¦¤à¦¿à¦²à¦¿à¦ªà¦¿ কৰিবলৈ কাৰà§à¦¡à§° সবিশেষত কà§à¦²à¦¿à¦• কৰক। <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">আপোনাৰ পà§à¦²à§‡à¦Ÿà¦«â€™à§°à§à¦®à¦¤ উপলবà§à¦§ নহয়৷</translation>
<translation id="733923710415886693">ছারà§à¦­à¦¾à§°à§° পà§à§°à¦®à¦¾à¦£à¦ªà¦¤à§à§°à¦–ন পà§à§°à¦®à¦¾à¦£à¦ªà¦¤à§à§°à§° সà§à¦¬à¦šà§à¦›à¦¤à¦¾à§° মাধà§à¦¯à¦®à§‡à§°à§‡ ঘোষণা কৰা হোৱা নাছিল।</translation>
<translation id="734600844861828519">১১x১৫</translation>
@@ -1964,6 +2012,7 @@
<translation id="7378627244592794276">নহয়</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">পà§à§°à¦¯à§‹à¦œà§à¦¯ নহয়</translation>
+<translation id="7388594495505979117">{0,plural, =1{আপোনাৰ ডিভাইচটো ১ মিনিটত ৰিষà§à¦Ÿà¦¾à§°à§à¦Ÿ হ'ব}one{আপোনাৰ ডিভাইচটো # মিনিটত ৰিষà§à¦Ÿà¦¾à§°à§à¦Ÿ হ'ব}other{আপোনাৰ ডিভাইচটো # মিনিটত ৰিষà§à¦Ÿà¦¾à§°à§à¦Ÿ হ'ব}}</translation>
<translation id="7390545607259442187">কাৰà§à¦¡à¦–ন নিশà§à¦šà¦¿à¦¤ কৰক</translation>
<translation id="7392089738299859607">ঠিকনা আপডে’ট কৰক</translation>
<translation id="7399802613464275309">সà§à§°à¦•à§à¦·à¦¾ পৰীকà§à¦·à¦¾</translation>
@@ -2000,6 +2049,12 @@
<translation id="7485870689360869515">কোনো ডেটা বিচাৰি পোৱা নগ’ল।</translation>
<translation id="7495528107193238112">à¦à¦‡ সমলটো অৱৰোধ কৰা হৈছে। সমসà§à¦¯à¦¾à¦Ÿà§‹ সমাধান কৰিবলৈ ছাইটৰ গৰাকীৰ সৈতে যোগাযোগ কৰক।</translation>
<translation id="7497998058912824456">নথি সৃষà§à¦Ÿà¦¿ কৰাৰ বà§à¦Ÿà¦¾à¦®, à¦à¦–ন নতà§à¦¨ Google Doc কà§à¦·à¦¿à¦ªà§à§°à¦¤à¦¾à§°à§‡ সৃষà§à¦Ÿà¦¿ কৰিবলৈ à¦à¦£à§à¦Ÿà¦¾à§° টিপক</translation>
+<translation id="7506488012654002225">Chromiumঠতলত দিয়া তথà§à¦¯à¦¸à¦®à§‚হ <ph name="BEGIN_EMPHASIS" />ছেভ নকৰিব<ph name="END_EMPHASIS" />:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />আপোনাৰ বà§à§°à¦¾à¦‰à¦œà¦¿à¦™à§° ইতিহাস
+ <ph name="LIST_ITEM" />কà§à¦•à¦¿ আৰৠছাইটৰ ডেটা
+ <ph name="LIST_ITEM" />ফৰà§à¦®à¦¤ দিয়া তথà§à¦¯
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">উভতোৱা নীতিৰ ডিভাইচ আইডি খালী বা বরà§à¦¤à¦®à¦¾à¦¨ আইডি সৈতে অমিল</translation>
<translation id="7508870219247277067">গাৠসেউজীয়া</translation>
<translation id="7511955381719512146">আপà§à¦¨à¦¿ বà§à¦¯à§±à¦¹à¦¾à§° কৰি থকা ৱাই-ফাইৰ বাবে আপà§à¦¨à¦¿ <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />লৈ যাব লগিব।</translation>
@@ -2113,7 +2168,6 @@
<translation id="7813600968533626083">Chromeৰ পৰামৰà§à¦¶à§° পৰা আà¦à¦¤à§°à¦¾à¦¬à¦¨à§‡?</translation>
<translation id="781440967107097262">কà§à¦²à¦¿à¦ªà¦¬â€™à§°à§à¦¡ শà§à¦¬à§‡à§Ÿà¦¾à§° কৰিবনে?</translation>
<translation id="7815407501681723534">'<ph name="SEARCH_STRING" />'ৰ বাবে <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> পাইছে</translation>
-<translation id="782125616001965242">à¦à¦‡ ছাইটটোৰ বিষয়ে তথà§à¦¯ দেখà§à§±à¦¾à¦“ক</translation>
<translation id="782886543891417279">আপà§à¦¨à¦¿ বà§à¦¯à§±à¦¹à¦¾à§° কৰি থকা ৱাই-ফাইটোৰ(<ph name="WIFI_NAME" />) বাবে আপà§à¦¨à¦¿ তাৰ লগ ইন কৰা পৃষà§à¦ à¦¾à¦²à§ˆ যাব লগা হ’ব পাৰে।</translation>
<translation id="7836231406687464395">প'ষà§à¦Ÿà¦«à¦¿à¦•à§à¦¸ (লেফাফা)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{à¦à¦Ÿà¦¾à¦“ নহয়}=1{১টা à¦à¦ªà§ (<ph name="EXAMPLE_APP_1" />)}=2{২টা à¦à¦ªà§ (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}one{#টা à¦à¦ªà§ (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}other{#টা à¦à¦ªà§ (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}}</translation>
@@ -2130,7 +2184,6 @@
<translation id="7888575728750733395">পà§à§°à¦¿à¦£à§à¦Ÿ ৰেণà§à¦¡à¦¾à§° কৰা ইনটেণà§à¦Ÿ</translation>
<translation id="7894280532028510793">যদি বানান ঠিকে আছে, <ph name="BEGIN_LINK" />নেটৱৰà§à¦• ডায়গন’ষà§à¦Ÿà¦¿à¦•à§à¦¸ চলাই চাওক<ph name="END_LINK" />।</translation>
<translation id="7904208859782148177">C3 (লেফাফা)</translation>
-<translation id="7931318309563332511">অজà§à¦žà¦¾à¦¤</translation>
<translation id="793209273132572360">ঠিকনা আপডে’ট কৰিবনে?</translation>
<translation id="7932579305932748336">ক'ট কৰক</translation>
<translation id="79338296614623784">à¦à¦Ÿà¦¾ মানà§à¦¯ ফ’ন নমà§à¦¬à§° দিয়ক</translation>
@@ -2155,13 +2208,14 @@
<translation id="7976214039405368314">অতি বেছিসংখà§à¦¯à¦• অনà§à§°à§‹à¦§</translation>
<translation id="7977538094055660992">আউটপà§à¦Ÿ ডিভাইচ</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">ইয়াৰ সৈতে লিংক কৰা হ’ল</translation>
<translation id="798134797138789862">ভাৰà§à¦šà§à§±à§‡à¦² ৰিয়েলিটি ডিভাইচসমূহ আৰৠডেটা বà§à¦¯à§±à¦¹à¦¾à§° কৰিবলৈ বিচাৰিব পাৰে</translation>
<translation id="7984945080620862648">আপà§à¦¨à¦¿ à¦à¦‡ মà§à¦¹à§‚ৰà§à¦¤à¦¤ <ph name="SITE" /> ছাইটটো খà§à¦²à¦¿à¦¬ নোৱাৰে কাৰণ ৱেবছাইটটোৱে বিশৃংখল কà§à§°à§‡à¦¡à§‡à¦¨à¦¶à§à¦¬à¦¿à§Ÿà§‡à¦² পঠিয়াইছে যিটো Chromeঠচলাব নোৱাৰে। নেটৱৰà§à¦•à§° আসোà¦à§±à¦¾à¦¹ আৰৠআকà§à§°à¦®à¦£à¦¬à§‹à§° সাধাৰণতে অসà§à¦¥à¦¾à§Ÿà§€ হয় গতিকে à¦à¦‡ পৃষà§à¦ à¦¾à¦Ÿà§‹à§±à§‡ পাছত কাম কৰিব পাৰে।</translation>
-<translation id="79859296434321399">পৰিৱৰà§à¦§à¦¿à¦¤ বাসà§à¦¤à§±à¦¿à¦•à¦¤à¦¾à§° সমল চাবলৈ ARCore ইনষà§à¦Ÿà¦² কৰক</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">সংযà§à¦•à§à¦¤ কৰক</translation>
<translation id="7992044431894087211"><ph name="APPLICATION_TITLE" />ৰ সৈতে সà§à¦•à§à§°à§€à¦¨ শà§à¦¬à§‡à§Ÿà¦¾à§° কৰাৰ সà§à¦¬à¦¿à¦§à¦¾à¦Ÿà§‹ পà§à¦¨à§° আৰমà§à¦­ কৰা হৈছে</translation>
<translation id="7995512525968007366">নিরà§à¦¦à¦¿à¦·à§à¦Ÿ কৰা হোৱা নাই</translation>
+<translation id="7998269595945679889">বà§à¦¯à¦•à§à¦¤à¦¿à¦—তভাৱে বà§à§°à¦¾à¦‰à¦œ কৰিবলৈ ইনক’গনিট’ টেবৰ বà§à¦Ÿà¦¾à¦®à¦Ÿà§‹ খোলক আৰৠà¦à¦Ÿà¦¾ নতà§à¦¨ ইনক’গনিট’ টেব খà§à¦²à¦¿à¦¬à¦²à§ˆ à¦à¦£à§à¦Ÿà¦¾à§° টিপক</translation>
<translation id="800218591365569300">মেম’ৰী খালী কৰিবলৈ অনà§à¦¯ টেব বা পà§à¦°â€™à¦—à§à§°à§‡à¦® বনà§à¦§ কৰি চাওক।</translation>
<translation id="8004582292198964060">বà§à§°à¦¾à¦‰à¦œà¦¾à§°</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{à¦à¦‡ কাৰà§à¦¡à¦–ন আৰৠইয়াৰ বিলিঙৰ ঠিকনা ছেভ কৰা হ’ব। আপà§à¦¨à¦¿ <ph name="USER_EMAIL" />ত ছাইন ইন কৰিলে à¦à§Ÿà¦¾ বà§à¦¯à§±à¦¹à¦¾à§° কৰিব পাৰিব।}one{à¦à¦‡ কাৰà§à¦¡à¦¬à§‹à§° আৰৠইয়াৰ বিলিঙৰ ঠিকনা ছেভ কৰা হ’ব। আপà§à¦¨à¦¿ <ph name="USER_EMAIL" />ত ছাইন ইন কৰিলে à¦à¦‡à¦¬à§‹à§° বà§à¦¯à§±à¦¹à¦¾à§° কৰিব পাৰিব।}other{à¦à¦‡ কাৰà§à¦¡à¦¬à§‹à§° আৰৠইয়াৰ বিলিঙৰ ঠিকনা ছেভ কৰা হ’ব। আপà§à¦¨à¦¿ <ph name="USER_EMAIL" />ত ছাইন ইন কৰিলে à¦à¦‡à¦¬à§‹à§° বà§à¦¯à§±à¦¹à¦¾à§° কৰিব পাৰিব।}}</translation>
@@ -2221,6 +2275,7 @@
<translation id="8202370299023114387">সংঘাত</translation>
<translation id="8206978196348664717">Prc4 (লেফাফা)</translation>
<translation id="8211406090763984747">সংযোগটো নিৰাপদ</translation>
+<translation id="8217240300496046857">ছাইটসমূহে আপোনাক সমগà§à§° ৱেবত টà§à§°à§‡à¦• কৰা কà§à¦•à¦¿à¦¸à¦®à§‚হ বà§à¦¯à§±à¦¹à¦¾à§° কৰিব নোৱাৰে। কিছà§à¦®à¦¾à¦¨ ছাইটত সà§à¦¬à¦¿à¦§à¦¾à¦¸à¦®à§‚হ বà§à¦¯à¦¾à¦¹à¦¤ হ’ব পাৰে।</translation>
<translation id="8218327578424803826">অভিযোজন কৰা অৱসà§à¦¥à¦¾à¦¨:</translation>
<translation id="8220146938470311105">C7/C6 (লেফাফা)</translation>
<translation id="8225771182978767009">à¦à¦‡ কমà§à¦ªà¦¿à¦‰à¦Ÿà¦¾à§°à¦Ÿà§‹ ছেট আপ কৰা লোকজনে à¦à¦‡ ছাইটটো অৱৰোধ কৰিছে।</translation>
@@ -2261,14 +2316,9 @@
<translation id="830498451218851433">আধা ফ'লà§à¦¡ কৰক</translation>
<translation id="8307358339886459768">সৰà§-ফট’</translation>
<translation id="8307888238279532626">কি à¦à¦ªà§â€Œ ইনষà§à¦Ÿà¦² কৰা হৈছে আৰৠসেইবোৰ কিমান সঘনাই বà§à¦¯à§±à¦¹à¦¾à§° কৰা হৈছে</translation>
+<translation id="8317207217658302555">ARCore আপডে’ট কৰিবনে?</translation>
<translation id="831997045666694187">সনà§à¦§à¦¿à§Ÿà¦¾</translation>
<translation id="8321476692217554900">জাননী</translation>
-<translation id="8328484624016508118">আটাইবোৰ ইনক’গনিট’ টেব বনà§à¦§ কৰাৰ পাছত, Chromeঠতলত দিয়া তথà§à¦¯à¦¸à¦®à§‚হ মচে:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />à¦à¦‡ ডিভাইচটোত আপোনাৰ বà§à§°à¦¾à¦‰à¦œà¦¿à¦™à§° কারà§à¦¯à¦•à¦²à¦¾à¦ª<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />à¦à¦‡ ডিভাইচটোৰ পৰা আপোনাৰ সনà§à¦§à¦¾à¦¨à§° ইতিহাস<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />ফ'রà§à¦®à¦¤ দিয়া তথà§à¦¯<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489"><ph name="HOST_NAME" />লৈ à¦à¦•à§à¦¸à§‡à¦› অগà§à§°à¦¾à¦¹à§à¦¯ কৰা হৈছিল</translation>
<translation id="833262891116910667">হাইলাইট</translation>
<translation id="8339163506404995330"><ph name="LANGUAGE" /> ভাষাৰ পৃষà§à¦ à¦¾à¦¸à¦®à§‚হ অনà§à¦¬à¦¾à¦¦ কৰা নহয়</translation>
@@ -2320,6 +2370,7 @@
<translation id="8507227106804027148">কামাণà§à¦¡ লাইন</translation>
<translation id="8508648098325802031">সনà§à¦§à¦¾à¦¨ আইকন</translation>
<translation id="8511402995811232419">কà§à¦•à¦¿ পৰিচালনা কৰক</translation>
+<translation id="8519753333133776369">আপোনাৰ পà§à§°à¦¶à¦¾à¦¸à¦•à§‡ অনà§à¦®à¦¤à¦¿ দিয়া HID ডিভাইচ</translation>
<translation id="8522552481199248698">Chromeঠআপোনাৰ Google à¦à¦•à¦¾à¦‰à¦£à§à¦Ÿ সà§à§°à¦•à§à¦·à¦¿à¦¤ কৰাত আৰৠআপোনৰ পাছৱৰà§à¦¡ সলনি কৰাত সহায় কৰিব পাৰে।</translation>
<translation id="8530813470445476232">Chromeৰ ছেটিংসমূহত আপোনাৰ বà§à§°à¦¾à¦‰à¦œà¦¿à¦™à§° ইতিহাস, কà§à¦•à¦¿, কেশà§à¦¬ আৰৠঅধিক বসà§à¦¤à§ মচক</translation>
<translation id="8533619373899488139">অৱৰোধ কৰা URL আৰৠআপোনাৰ ছিষà§à¦Ÿà§‡à¦®à§° পà§à§°à¦¶à¦¾à¦¸à¦•à§‡ বলৱৎ কৰা অনà§à¦¯ নীতিসমূহৰ সূচীখন চাবলৈ &lt;strong&gt;chrome://policy&lt;/strong&gt;লৈ যাওক।</translation>
@@ -2331,7 +2382,6 @@
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{অনà§à¦®à¦¤à¦¿ ৰিছেট কৰক}one{অনà§à¦®à¦¤à¦¿ ৰিছেট কৰক}other{অনà§à¦®à¦¤à¦¿ ৰিছেট কৰক}}</translation>
<translation id="8555010941760982128">চেকআউট কৰাৰ সময়ত à¦à¦‡ ক’ডটো বà§à¦¯à§±à¦¹à¦¾à§° কৰক</translation>
<translation id="8557066899867184262">CVCটো আপোনাৰ কাৰà§à¦¡à§° পিছফালে আছে।</translation>
-<translation id="8558485628462305855">পৰিৱৰà§à¦§à¦¿à¦¤ বাসà§à¦¤à§±à¦¿à¦•à¦¤à¦¾à§° সমল চাবলৈ ARCore আপডে’ট কৰক</translation>
<translation id="8559762987265718583">আপোনাৰ ডিভাইচৰ তাৰিখ আৰৠসময় (<ph name="DATE_AND_TIME" />) অশà§à¦¦à§à¦§ হোৱাৰ বাবে <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />লৈ কোনো বà§à¦¯à¦•à§à¦¤à¦¿à¦—ত সংযোগ সà§à¦¥à¦¾à¦ªà¦¨ কৰিব নোৱাৰি।</translation>
<translation id="8564182942834072828">পৃথক নথি/নিমিলোৱা পà§à§°à¦¤à¦¿à¦²à¦¿à¦ªà¦¿à¦¸à¦®à§‚হ</translation>
<translation id="8564985650692024650">আপà§à¦¨à¦¿ যদি নিজৰ পাছৱৰà§à¦¡à¦Ÿà§‹ অনà§à¦¯ ছাইটত পà§à¦¨à§° বà§à¦¯à§±à¦¹à¦¾à§° কৰিছিল <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" />ঠআপোনাৰ পাছৱরà§à¦¡à¦Ÿà§‹ ৰিছেট কৰিবলৈ চà§à¦ªà¦¾à§°à¦¿à¦› কৰে।</translation>
@@ -2350,6 +2400,7 @@
<translation id="865032292777205197">ম'শà§à¦¬à¦¨ ছেনà§à¦¸à§°</translation>
<translation id="8663226718884576429">অৰà§à¦¡à¦¾à§°à§° সাৰাংশ, <ph name="TOTAL_LABEL" />, অধিক বিৱৰণ</translation>
<translation id="8666678546361132282">ইংৰাজী</translation>
+<translation id="8669306706049782872">ৱিণà§à¦¡â€™ খà§à¦²à¦¿à¦¬à¦²à§ˆ আৰৠথ’বলৈ আপোনাৰ সà§à¦•à§à§°à§€à¦¨à§° বিষয়ে তথà§à¦¯ বà§à¦¯à§±à¦¹à¦¾à§° কৰক</translation>
<translation id="867224526087042813">চহী</translation>
<translation id="8676424191133491403">কোনো বিলমà§à¦¬ নাই</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, উতà§à¦¤à§°, <ph name="ANSWER" /></translation>
@@ -2376,6 +2427,7 @@
<translation id="8731544501227493793">পাছৱৰà§à¦¡à¦¸à¦®à§‚হ পৰিচালনা কৰক বà§à¦Ÿà¦¾à¦®, Chromeৰ ছেটিংসমূহত আপোনাৰ পাছৱৰà§à¦¡à¦¸à¦®à§‚হ চাবলৈ আৰৠপৰিচালনা কৰিবলৈ à¦à¦£à§à¦Ÿà¦¾à§° টিপক</translation>
<translation id="8734529307927223492">আপোনাৰ <ph name="DEVICE_TYPE" /> <ph name="MANAGER" />ঠপৰিচালনা কৰে</translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, বà§à¦¯à¦•à§à¦¤à¦¿à¦—তভাৱে বà§à§°à¦¾à¦‰à¦œ কৰাৰ বাবে à¦à¦–ন নতà§à¦¨ ইনক'গনিট' ৱিণà§à¦¡' খà§à¦²à¦¿à¦¬à¦²à§ˆ পà§à§°à¦¥à¦®à§‡ টেব আৰৠতাৰ পাছত à¦à¦£à§à¦Ÿà¦¾à§° টিপক</translation>
+<translation id="8737685506611670901"><ph name="REPLACED_HANDLER_TITLE" />ৰ সলনি <ph name="PROTOCOL" /> লিংকসমূহ খোলক</translation>
<translation id="8738058698779197622">কোনো সà§à§°à¦•à§à¦·à¦¿à¦¤ সংযোগ সà§à¦¥à¦¾à¦ªà¦¨ কৰিবলৈ আপোনাৰ ঘড়ীটো সঠিককৈ ছেট কৰাৰ আৱশà§à¦¯à¦•à¥¤ ইয়াৰ কাৰণ হৈছে ৱেবছাইটসমূহে নিজৰ চিনাকà§à¦¤à¦•à§°à¦£à§° বাবে বà§à¦¯à§±à¦¹à¦¾à§° কৰা পà§à§°à¦®à¦¾à¦£à¦ªà¦¤à§à§°à¦¸à¦®à§‚হ কোনো নিরà§à¦¦à¦¿à¦·à§à¦Ÿ সময়সীমাৰ বাবেহে মানà§à¦¯ হয়। আপোনাৰ ডিভাইচৰ ঘড়ীটো অশà§à¦¦à§à¦§ হোৱাৰ বাবে Chromiumঠপà§à§°à¦®à¦¾à¦£à¦ªà¦¤à§à§°à¦¸à¦®à§‚হ সতà§à¦¯à¦¾à¦ªà¦¨ কৰিব নোৱাৰে।</translation>
<translation id="8740359287975076522"><ph name="HOST_NAME" />ৰ &lt;abbr id="dnsDefinition"&gt;DNS ঠিকনা&lt;/abbr&gt; বিচাৰিব পৰা নগ’ল। সমসà§à¦¯à¦¾à¦Ÿà§‹à§° কাৰণ জানিবলৈ চেষà§à¦Ÿà¦¾ কৰি থকা হৈছে।</translation>
<translation id="8742371904523228557"><ph name="ONE_TIME_CODE" /> হৈছে <ph name="ORIGIN" />ৰ ক’ড</translation>
@@ -2403,6 +2455,7 @@
<translation id="883848425547221593">অনà§à¦¯ বà§à¦•à¦®à¦¾à§°à§à¦•</translation>
<translation id="884264119367021077">শà§à¦¬à¦¿à¦ªà¦¿à¦‚ ঠিকনা</translation>
<translation id="884923133447025588">পà§à§°à¦¤à§à¦¯à¦¾à¦¹à¦¾à§°à§° কোনো উপায় বিচাৰি পোৱা নগ’ল।</translation>
+<translation id="8849262850971482943">অতিৰিকà§à¦¤ সà§à§°à¦•à§à¦·à¦¾à§° বাবে আপোনাৰ ভাৰà§à¦šà§à§±à§‡à¦² কাৰà§à¦¡à¦–ন বà§à¦¯à§±à¦¹à¦¾à§° কৰক</translation>
<translation id="885730110891505394">Google জৰিয়তে শà§à¦¬à§‡à§Ÿà¦¾à§° কৰি আছে</translation>
<translation id="8858065207712248076">যদি আপà§à¦¨à¦¿ নিজৰ <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" />ৰ পাছৱরà§à¦¡à¦Ÿà§‹ অনà§à¦¯ ছাইটত পà§à¦¨à§° বà§à¦¯à§±à¦¹à¦¾à§° কৰে, তেনà§à¦¤à§‡ Chromeঠআপোনাৰ পাছৱরà§à¦¡à¦Ÿà§‹ ৰিছেট কৰিবলৈ চà§à¦ªà¦¾à§°à¦¿à¦› কৰে।</translation>
<translation id="885906927438988819">যদি বানান ঠিকে আছে, <ph name="BEGIN_LINK" />Windowsৰ নেটৱৰà§à¦• ডায়গন’ষà§à¦Ÿà¦¿à¦•à§à¦¸ চলাই চাওক<ph name="END_LINK" />।</translation>
@@ -2452,6 +2505,7 @@
<translation id="9004367719664099443">VR ছেশà§à¦¬à¦¨ চলি আছে</translation>
<translation id="9005998258318286617">PDF নথি ল’ড কৰিব নোৱাৰিলে।</translation>
<translation id="9008201768610948239">উপেকà§à¦·à¦¾ কৰক</translation>
+<translation id="901834265349196618">ইমেইল</translation>
<translation id="9020200922353704812">কারà§à¦¡ বিলিংৰ ঠিকনাৰ আৱশà§à¦¯à¦•</translation>
<translation id="9020542370529661692">à¦à¦‡ পৃষà§à¦ à¦¾à¦Ÿà§‹ <ph name="TARGET_LANGUAGE" />লৈ অনà§à¦¬à¦¾à¦¦ কৰা হৈছে</translation>
<translation id="9020742383383852663">A8</translation>
@@ -2500,6 +2554,7 @@
<translation id="9150045010208374699">আপোনাৰ কেমেৰা বà§à¦¯à§±à¦¹à¦¾à§° কৰক</translation>
<translation id="9150685862434908345">আপোনাৰ পà§à§°à¦¶à¦¾à¦¸à¦•à§‡ দূৰৰপৰাই আপোনাৰ বà§à§°à¦¾à¦‰à¦œà¦¾à§°à§° ছেটআপ সলনি কৰিব পাৰে। à¦à¦‡ ডিভাইচটোত কৰা কাৰà§à¦¯à¦•à¦²à¦¾à¦ª Chromeৰ বাহিৰৰ পৰাও পৰিচালনা কৰা হ'ব পাৰে। <ph name="BEGIN_LINK" />অধিক জানক<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">আপডে’ট কৰা হ’ল</translation>
+<translation id="9155211586651734179">অডিঅ’ পৰিধীয় সংযà§à¦•à§à¦¤ কৰা হ’ল</translation>
<translation id="9157595877708044936">ছেট আপ কৰি থকা হৈছে...</translation>
<translation id="9158625974267017556">C6 (লেফাফা)</translation>
<translation id="9164029392738894042">সঠিকতা পৰীকà§à¦·à¦£</translation>
diff --git a/chromium/components/strings/components_strings_az.xtb b/chromium/components/strings/components_strings_az.xtb
index 52639c2692a..a036811b2cd 100644
--- a/chromium/components/strings/components_strings_az.xtb
+++ b/chromium/components/strings/components_strings_az.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">Detallara baxın</translation>
<translation id="1030706264415084469"><ph name="URL" /> böyük həcmli datanı həmişəlik cihazınızda yadda saxlamaq istəyir</translation>
<translation id="1032854598605920125">Saat əqrəbi istiqamətində fırladın</translation>
+<translation id="1033329911862281889">Anonim rejim sizi onlayn görünməz etmir:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Saytlar və onların istifadə etdiyi xidmətlər onları ziyarət etdiyiniz zaman xəbərdar olur<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />İşəgötürənlər və ya məktəblər axtarış fəaliyyətini izləyə bilir<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />İnternet xidmət təminatçıları veb trafikini izləyə bilir<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">Deaktiv edin</translation>
<translation id="1036982837258183574">Tam ekrandan çıxmaq üçün |<ph name="ACCELERATOR" />| basın</translation>
<translation id="1038106730571050514">Təklifləri göstərin</translation>
<translation id="1038842779957582377">bilinməyən ad</translation>
<translation id="1041998700806130099">İş vərəqi mesajı</translation>
<translation id="1048785276086539861">Annotasiyaları redaktə etdiyiniz zaman bu sənəd bir səhifəlik görünüşə qayıdacaq</translation>
-<translation id="1049743911850919806">Gizli Rejim</translation>
<translation id="1050038467049342496">Digər tətbiqləri bağlayın</translation>
<translation id="1055184225775184556">ÆlavÉ™ni geri qaytarın</translation>
<translation id="1056898198331236512">Xəbərdarlıq</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">Siyasət keşi OK-dir</translation>
<translation id="1130564665089811311">"Səhifəni tərcümə edin" düyməsi, Google Tərcümə ilə bu səhifəni tərcümə etmək üçün Enter düyməsinə basın</translation>
<translation id="1131264053432022307">Kopyalanmış Şəkil</translation>
+<translation id="1142846828089312304">Anonim rejimdə üçüncü tərəf kukilərini bloklayın</translation>
<translation id="1150979032973867961">Bu server <ph name="DOMAIN" /> domenini təsdiqləyə bilmədi; onun güvənlik sertifikatı kompüterinizin əməliyyat sistemi tərəfindən doğrulanmayıb. Buna səbəb yanlış konfiqurasiya və ya hücumçu tərəfindən bağlantınızın ələ keçirilməsi ola bilər.</translation>
<translation id="1151972924205500581">Parol tələb olunur</translation>
<translation id="1156303062776767266">Lokal və ya paylaşılmış fayla baxırsınız</translation>
@@ -64,7 +70,6 @@
<translation id="1178581264944972037">Durdurun</translation>
<translation id="1181037720776840403">Silin</translation>
<translation id="1186201132766001848">Parolları yoxlayın</translation>
-<translation id="1195210374336998651">Tətbiq ayarlarına keçin</translation>
<translation id="1195558154361252544">İcazə verdiklərinizdən başqa bütün saytlarda bildirişlər blok edilib</translation>
<translation id="1197088940767939838">Narıncı</translation>
<translation id="1201402288615127009">Növbəti</translation>
@@ -111,7 +116,7 @@
<translation id="1307966114820526988">Ləğv edilmiş funksiya</translation>
<translation id="1308113895091915999">Təklif əlçatandır</translation>
<translation id="1312803275555673949">Hansı dəlillər bunu dəstəkləyir?</translation>
-<translation id="131405271941274527">NFC cihazında telefonunuza toxunan zaman <ph name="URL" /> məlumat göndərmək və qəbul etmək istəyir</translation>
+<translation id="1314311879718644478">Artırılmış reallıq məzmununa baxın</translation>
<translation id="1314509827145471431">Sağdan uclarını qovuşdurun</translation>
<translation id="1318023360584041678">Tab qrupunda saxlanıldı</translation>
<translation id="1319245136674974084">Bu tətbiq haqqında bir daha soruşmayın</translation>
@@ -161,6 +166,7 @@
<translation id="142858679511221695">Bulud istifadəçisi</translation>
<translation id="1428729058023778569">Bu sayt HTTPS-i dÉ™stÉ™klÉ™mÉ™diyinÉ™ görÉ™ bu xÉ™bÉ™rdarlığı görürsünüz. <ph name="BEGIN_LEARN_MORE_LINK" />Ætraflı mÉ™lumat<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">Çap edin</translation>
+<translation id="1432187715652018471">səhifə xidmət işləyici quraşdırmaq istəyir.</translation>
<translation id="1432581352905426595">Axtarış sistemlərini idarə edin</translation>
<translation id="1436185428532214179">Saytlar cihazınızdakı faylları və qovluqları redaktə etmək üçün icazə istəyə bilər</translation>
<translation id="1442386063175183758">Sağ küncə qatlayın</translation>
@@ -181,6 +187,12 @@
<translation id="1483493594462132177">Göndərin</translation>
<translation id="1484290072879560759">Göndəriş Ünvanı seçin</translation>
<translation id="1492194039220927094">Siyasət bildirişləri:</translation>
+<translation id="149293076951187737">Bütün Chrome Anonim tablarını bağladığınız zaman həmin tablardakı fəaliyyətiniz bu cihazdan silinir:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Axtarış fəaliyyəti<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Axtarış tarixçəsi<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Formalara daxil edilmiş məlumatlar<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">Taba geri qayıdın</translation>
<translation id="1501859676467574491">Google Hesabındakı kartları göstərin</translation>
<translation id="1507202001669085618">&lt;p&gt;Onlayn olmadan öncə giriş tələb edilən Wi-Fi portalından istifadə edirsinizsə, bu xətanı görəcəksiniz.&lt;/p&gt;
@@ -208,6 +220,8 @@
<translation id="1559572115229829303">&lt;p&gt;Cihazınızın tarixi və vaxtı (<ph name="DATE_AND_TIME" />) yanlış olduğundan, <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> domeninə şəxsi bağlantı yaradıla bilməz.&lt;/p&gt;
&lt;p&gt;Lütfən, tarix və saatı &lt;strong&gt;Ayarlar&lt;/strong&gt; tətbiqinin &lt;strong&gt;Ümumi&lt;/strong&gt; bölməsində düzəldin.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">Administrator cihazınızı bu vaxt yenidən başladacaq: <ph name="TIME" />, <ph name="DATE" /></translation>
+<translation id="156703335097561114">Ünvanlar, interfeys konfiqurasiyası və bağlantı keyfiyyəti kimi şəbəkə məlumatları</translation>
<translation id="1567040042588613346">Bu siyasət nəzərdə tutulduğu kimi işləyir, lakin eyni dəyər başqa bir yerdə təyin olunub və bu siyasət tərəfindən əvəz edilib.</translation>
<translation id="1569487616857761740">Bitmə vaxtını daxil edin</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@
<translation id="1583429793053364125">Bu veb səhifəni göstərərkən xəta baş verdi.</translation>
<translation id="1586541204584340881">Quraşdırdığınız artırmalar</translation>
<translation id="1588438908519853928">Normal</translation>
+<translation id="1589050138437146318">ARCore quraşdırılsın?</translation>
<translation id="1592005682883173041">Yerli Data GiriÅŸi</translation>
<translation id="1594030484168838125">Seçin</translation>
<translation id="160851722280695521">Chrome'da Dinozavr Qaçış oyununu oynayın</translation>
@@ -283,6 +298,7 @@
başlıq yanlış formadadır, bu da brauzerin <ph name="SITE" />
üzrə olan sorğunuzu yerinə yetirməsinə mane olur. Mənbə siyasətlər
təhlükəsizlik və digər xüsusiyyətləri konfiqurasiya etmək üçün sayt operatorları tərəfindən istifadə edilə bilər.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Chromium'da Anonim Rejim barədə məlumat<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">Açıq tablarınız burada görünür</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -410,6 +426,7 @@
<translation id="22081806969704220">Qab 3</translation>
<translation id="2212735316055980242">Siyasət tapılmadı</translation>
<translation id="2213606439339815911">Daxil etmələr əldə edilir...</translation>
+<translation id="2213612003795704869">Səhifə çap olunub</translation>
<translation id="2215727959747642672">Fayl redaktəsi</translation>
<translation id="2218879909401188352">Hazırda <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> saytındakı hücumçular cihazı zÉ™dÉ™lÉ™yÉ™n tÉ™hlükÉ™li tÉ™tbiqlÉ™r quraÅŸdıra, mobil fakturaya gizli ödÉ™niÅŸ É™lavÉ™ edÉ™ vÉ™ ya ÅŸÉ™xsi mÉ™lumatı oÄŸurlaya bilÉ™rlÉ™r. <ph name="BEGIN_LEARN_MORE_LINK" />Ætraflı mÉ™lumat<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">Ä°nternet yoxdur</translation>
@@ -419,6 +436,7 @@
<translation id="2248949050832152960">WebAuthn işlədin</translation>
<translation id="2250931979407627383">Soldan kənarını tikin</translation>
<translation id="225207911366869382">Bu dəyər bu qayda üçün köhnəlib.</translation>
+<translation id="2256115617011615191">İndi yenidən başladın</translation>
<translation id="2258928405015593961">Gələcəkdə olan son tarix daxil edin və yenidən cəhd edin</translation>
<translation id="225943865679747347">Xəta kodu: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">HTTP xətası</translation>
@@ -446,6 +464,7 @@
<translation id="2337852623177822836">Ayara administrator tərəfindən nəzarət edilir</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> ütləndirmək istəyir</translation>
<translation id="2346319942568447007">Kopyalanmış şəkil</translation>
+<translation id="2350796302381711542"><ph name="HANDLER_HOSTNAME" /> hostuna <ph name="REPLACED_HANDLER_TITLE" /> əvəzinə <ph name="PROTOCOL" /> linklərinin açılması icazəsi verilsin?</translation>
<translation id="2354001756790975382">Digər əlfəcinlər</translation>
<translation id="2354430244986887761">Təhlükəsiz Google Axtarış bu yaxınlarda <ph name="SITE" /> saytında <ph name="BEGIN_LINK" />zərərli tətbiq tapdı<ph name="END_LINK" />.</translation>
<translation id="2355395290879513365">Hücumçular bu saytda baxdığınız şəkilləri görə bilər və onları deyişdirərək Sizi aldada bilər.</translation>
@@ -471,6 +490,7 @@
<translation id="2413528052993050574">Bu server <ph name="DOMAIN" /> domenini təsdiqləyə bilmir; təhlükəsizlik sertifikatı ləğv edilə bilər. Buna yanlış konfiqurasiya və ya hücumçu tərəfindən bağlantının ələ keçirilməsi səbəb ola bilər.</translation>
<translation id="2414886740292270097">Qara</translation>
<translation id="2430968933669123598">"Google Hesabını idarə edin" düyməsi, Enter düyməsinə basaraq Google Hesabınızda məlumat, məxfilik və təhlükəsizliyinizi idarə edin</translation>
+<translation id="2436186046335138073"><ph name="HANDLER_HOSTNAME" /> hostuna bütün <ph name="PROTOCOL" /> linklərini açmaq icazəsi verirsiniz?</translation>
<translation id="2438874542388153331">Sağdan dördlü deşik açın</translation>
<translation id="2450021089947420533">Baxışlar</translation>
<translation id="2463739503403862330">Doldurun</translation>
@@ -478,6 +498,7 @@
<translation id="2465655957518002998">Çatdırılma Üsulu seçin</translation>
<translation id="2465688316154986572">Åžtapel vurun</translation>
<translation id="2465914000209955735">Chrome'da endirdiyiniz faylları idarə edin</translation>
+<translation id="2466004615675155314">Vebdən məlumatları göstərin</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Şəbəkə Diaqnostikası İşləyir<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">1-N sırası</translation>
<translation id="2470767536994572628">Annotasiyaları redaktə etdiyiniz zaman bu sənəd bir səhifəlik görünüşə və ilkin vəziyyətinə qayıdacaq</translation>
@@ -498,6 +519,7 @@
<translation id="2523886232349826891">Yalnız bu cihaz yadda saxlanıldı</translation>
<translation id="2524461107774643265">Ætraflı MÉ™lumat ÆlavÉ™ Edin</translation>
<translation id="2529899080962247600">Bu sahədə maksimum <ph name="MAX_ITEMS_LIMIT" /> daxiletmə olmalıdır. Bundan sonrakı daxiletmələr nəzərə alınmayacaq.</translation>
+<translation id="2535585790302968248">Gizli baxış üçün yeni Anonim tab açın</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{vÉ™ daha 1}other{and daha #}}</translation>
<translation id="2536110899380797252">Ãœnvan ÆlavÉ™ Edin</translation>
<translation id="2539524384386349900">Aşkarlayın</translation>
@@ -523,7 +545,14 @@
<translation id="2597378329261239068">Bu sənəd parol ilə qorunur. Parolu yazın.</translation>
<translation id="2609632851001447353">Variasiyalar</translation>
<translation id="2610561535971892504">Kopyalamaq üçün klikləyin</translation>
+<translation id="2617988307566202237">Chrome aşağıdakı məlumatları <ph name="BEGIN_EMPHASIS" />yadda saxlamayacaq<ph name="END_EMPHASIS" />:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Axtarış tarixçəniz
+ <ph name="LIST_ITEM" />Kuki və sayt datası
+ <ph name="LIST_ITEM" />Formalara daxil edilmiş məlumatlar
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (Zərf)</translation>
+<translation id="2623663032199728144">Ekranlarınız haqqında məlumatdan istifadə etməyi istəyə bilər</translation>
<translation id="2625385379895617796">Saatınız irəlidədir</translation>
<translation id="262745152991669301">Saytlar USB cihazlarına qoşulmaq icazəsi istəyə bilər</translation>
<translation id="2629325967560697240">Chrome'un ən yüksək təhlükəsizlik səviyyəsini əldə etmək üçün<ph name="BEGIN_ENHANCED_PROTECTION_LINK" />genişləndirilmiş qorumanı aktiv edin<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -557,6 +586,7 @@
<translation id="2709516037105925701">Avtomatik doldurma</translation>
<translation id="2713444072780614174">AÄŸ</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />, Tab düyməsi, sonra Enter düyməsinə basaraq Chrome ayarlarında ödənişlərinizi və kredit kartı məlumatlarınızı idarə edin</translation>
+<translation id="271663710482723385">Tam ekrandan çıxmaq üçün |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| düyməsinə basın</translation>
<translation id="2721148159707890343">SorÄŸu uÄŸurlu oldu</translation>
<translation id="2723669454293168317">Chrome ayarlarında Təhlükəsizlik Yoxlanışı icra edin</translation>
<translation id="2726001110728089263">Yan Qab</translation>
@@ -587,6 +617,7 @@
<translation id="2850739647070081192">Dəvət edin (Zərf)</translation>
<translation id="2856444702002559011">Hücumçular <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> saytından mÉ™lumat (mÉ™sÉ™lÉ™n, parol, mesaj vÉ™ ya kredit kartları) oÄŸurlamaÄŸa çalışa bilÉ™rlÉ™r. <ph name="BEGIN_LEARN_MORE_LINK" />Ætraflı mÉ™lumat<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">Bu sayt inadçı və ya aldadıcı reklamlar göstərir.</translation>
+<translation id="286512204874376891">Virtual kart sizi potensial dələduzluqdan qorumaq üçün faktiki kartınızı gizlədir. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">Dost</translation>
<translation id="2876489322757410363">Xarici tətbiqlə ödəniş etmək üçün Anonim rejimdən çıxırsınız. Davam edilsin?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />, Chrome ayarlarında Təhlükəsiz Baxış və daha çoxunu idarə etmək üçün Tab, sonra Enter düyməsinə basın</translation>
@@ -611,6 +642,7 @@
<translation id="2930577230479659665">Hər kopyadan sonra kəsin</translation>
<translation id="2932085390869194046">Parol təklif edin...</translation>
<translation id="2934466151127459956">Hökumət Məktubu</translation>
+<translation id="2938225289965773019"><ph name="PROTOCOL" /> linklərini açın</translation>
<translation id="2941952326391522266">Server <ph name="DOMAIN" /> olmasını sübut edə bilmədi; güvənlik sertifikatı <ph name="DOMAIN2" /> domenindəndir.</translation>
<translation id="2943895734390379394">Yükləmə Vaxtı:</translation>
<translation id="2948083400971632585">Ayarlar səhifəsindən bağlantı üçün sazlanmış istənilən proksini deaktiv edə bilərsiniz.</translation>
@@ -643,6 +675,7 @@
<translation id="3037605927509011580">Yapon xalq musiqisi dinləmisiniz?</translation>
<translation id="3041612393474885105">Sertifikat Məlumatı</translation>
<translation id="3044034790304486808">Araşdırmaya davam edin</translation>
+<translation id="305162504811187366">Chrome Remote Desktop tarixçəsi, eləcə də zaman nişanları, görüş başladıcıları və kliyent sessiyasının ID-ləri</translation>
<translation id="3060227939791841287">C9 (Zərf)</translation>
<translation id="3061707000357573562">Təmir Xidməti</translation>
<translation id="306573536155379004">Oyun başladı.</translation>
@@ -681,6 +714,7 @@
<translation id="3197136577151645743">Saytlar bu cihazdan nə vaxt aktiv istifadə etdiyinizi öyrənmək üçün icazə istəyə bilər</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />, Chrome ayarlarında sinxronlaşdırdığınız məlumatları idarə etmək üçün Tab, sonra Enter düyməsinə basın</translation>
<translation id="320323717674993345">Ödənişi ləğv edin</translation>
+<translation id="3203366800380907218">Vebdən</translation>
<translation id="3207960819495026254">ÆlfÉ™cinlÉ™nib</translation>
<translation id="3209034400446768650">Səhifədə pul çıxıla bilər</translation>
<translation id="3212581601480735796"><ph name="HOSTNAME" /> hostundakı fəaliyyətinizə nəzarət edilir</translation>
@@ -697,10 +731,12 @@
<translation id="3234666976984236645">Bu saytda həmişə önəmli məzmunu aşkarlayın</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />, Tab düyməsi, sonra Enter düyməsinə basaraq brauzerinizin görünüşünü fərdiləşdirin</translation>
<translation id="3240791268468473923">"Təhlükəsiz ödəniş giriş məlumatları uyğun gəlmir" giriş məlumatları səhifəsi açılıb</translation>
+<translation id="324180406144491771">“<ph name="HOST_NAME" />†keçidləri bloklanıb</translation>
<translation id="3249845759089040423">Modern</translation>
<translation id="3252266817569339921">Fransız</translation>
<translation id="3257954757204451555">Bu məlumatların arxasında kim dayanır?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />, Tab düyməsi, sonra Enter düyməsinə basaraq Google Calendar'da cəld yeni tədbir yaradın</translation>
+<translation id="3261488570342242926">Virtual kartlar barədə məlumat</translation>
<translation id="3264837738038045344">"Chrome ayarlarını idarə edin" düyməsi, Enter düyməsinə basaraq Chrome ayarlarını ziyarət edin</translation>
<translation id="3266793032086590337">Dəyər (zidd)</translation>
<translation id="3268451620468152448">Panelləri Açın</translation>
@@ -714,6 +750,7 @@
<translation id="3288238092761586174"><ph name="URL" /> ödənişinizi doğrulamaq üçün əlavə addımlar atmalı ola bilər</translation>
<translation id="3293642807462928945"><ph name="POLICY_NAME" /> siyasəti haqqında ətraflı məlumat əldə edin</translation>
<translation id="3295444047715739395">Parollarınıza Chrome ayarlarında baxın və idarə edin</translation>
+<translation id="3303795387212510132">Tətbiqin <ph name="PROTOCOL_SCHEME" /> keçidlərini açmasına icazə verilsin?</translation>
<translation id="3303855915957856445">Heç bir axtarış nəticəsi tapılmadı</translation>
<translation id="3304073249511302126">bluetooth skanlaması</translation>
<translation id="3308006649705061278">Təşkilati Birlik (OU)</translation>
@@ -727,12 +764,6 @@
<translation id="3345782426586609320">Gözlər</translation>
<translation id="3355823806454867987">Proksi ayarlarını dəyişin...</translation>
<translation id="3360103848165129075">Ödəniş səhifəsi</translation>
-<translation id="3361596688432910856">Chrome aşağıdakı məlumatları <ph name="BEGIN_EMPHASIS" />yadda saxlamayacaq<ph name="END_EMPHASIS" />:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Axtarış tarixçəsi
- <ph name="LIST_ITEM" />Kuki və sayt datası
- <ph name="LIST_ITEM" />Formaya daxil edilən məlumat
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">Bu siyasÉ™t ləğv edilmiÅŸ <ph name="OLD_POLICY" /> siyasÉ™tindÉ™n avtomatik kopyalanıb. ÆvÉ™zinÉ™ bu siyasÉ™tdÉ™n istifadÉ™ etmÉ™lisiniz.</translation>
<translation id="3364869320075768271"><ph name="URL" /> virtual reallıq cihazınız və datanızı istifadə etmək istəyir</translation>
<translation id="3366477098757335611">Kartlara baxın</translation>
@@ -814,7 +845,6 @@
<translation id="3587738293690942763">Orta</translation>
<translation id="3592413004129370115">İtalyan (Zərf)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{Qrupunuzu istənilən vaxt sıfırlaya bilərsiniz. Yeni bir qrupa qoşulmaq təxminən bir gün çəkir.}=1{Qrupunuzu istənilən vaxt sıfırlaya bilərsiniz. Yeni bir qrupa qoşulmaq təxminən bir gün çəkir.}other{Qrupunuzu istənilən vaxt sıfırlaya bilərsiniz. Yeni bir qrupa qoşulmaq təxminən {NUM_DAYS} gün çəkir.}}</translation>
-<translation id="3596012367874587041">Tətbiq ayarları</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">Tətbiq admin tərəfindən bloklanıb</translation>
<translation id="3608932978122581043">İstiqaməti tənzimləyin</translation>
@@ -856,6 +886,7 @@
<translation id="370972442370243704">Baxışları aktiv edin</translation>
<translation id="3711895659073496551">Durdurun</translation>
<translation id="3712624925041724820">Lisenziyalar bitib</translation>
+<translation id="3714633008798122362">veb təqvimi</translation>
<translation id="3714780639079136834">Mobil data vÉ™ ya Wi-Fi aktiv edilir</translation>
<translation id="3715597595485130451">Wi-Fi'a qoÅŸulun</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Proksi, güvənlik divarı və DNS konfiqurasiyası yoxlanılır<ph name="END_LINK" /></translation>
@@ -917,6 +948,7 @@
<translation id="3906954721959377182">PlanÅŸet</translation>
<translation id="3909477809443608991"><ph name="URL" /> qorunan kontenti oxutmaq istəyir. Cihazın kimliyi Google tərəfindən doğrulanacaq və bu sayt cihaza daxil ola biləcək.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">Rədd edin</translation>
<translation id="3939773374150895049">CVC əvəzinə WebAuthn istifadə edilsin?</translation>
<translation id="3946209740501886391">Həmişə bu saytda sual verin</translation>
<translation id="3947595700203588284">Saytlar MIDI cihazlarına qoşulmaq üçün icazə istəyə bilər</translation>
@@ -938,6 +970,7 @@
<translation id="3990250421422698716">Kənarını bükün</translation>
<translation id="3996311196211510766"><ph name="ORIGIN" /> saytı ona yönləndirilən
bütün sorğulara mənbə siyasətin tətbiq edilməsini tələb edib, lakin bu siyasət hazırda tətbiq edilə bilmir.</translation>
+<translation id="4009243425692662128">Çap etdiyiniz səhifələrin məzmunu təhlil üçün Google Cloud və ya üçüncü tərəflərə göndərilir. Məsələn, onlar həssas dataya görə skanlana bilər.</translation>
<translation id="4010758435855888356">Yaddaşa giriş icazəsi verilsin?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{{COUNT} səhifədən ibarət PDF sənədi}other{{COUNT} səhifədən ibarət PDF sənədi}}</translation>
<translation id="4023431997072828269">Bu forma təhlükəsiz olmayan bağlantıdan istifadə etməklə təqdim edildiyinə görə məlumatlarınız digərləri tərəfindən görüləcək.</translation>
@@ -1031,6 +1064,7 @@
<translation id="4250680216510889253">Yox</translation>
<translation id="4253168017788158739">Qeyd</translation>
<translation id="425582637250725228">Etdiyiniz dəyişikliklər yadda saxlanıla bilməz.</translation>
+<translation id="425869179292622354">Virtual kart ilə güvənliyi artırılsın?</translation>
<translation id="4258748452823770588">Yanlış imza</translation>
<translation id="4261046003697461417">Qorunan sənədlərdə annotasiya mümkün deyil</translation>
<translation id="4265872034478892965">Administrator tərəfindən icazə verildi</translation>
@@ -1093,6 +1127,7 @@
<translation id="4434045419905280838">Popap və yönləndirmələr</translation>
<translation id="4435702339979719576">Postkart)</translation>
<translation id="443673843213245140">Proksi istifadəsi deaktiv edilib, amma ətraflı proksi konfiqurasiyası müəyyən edilib.</translation>
+<translation id="4441832193888514600">Siyasət yalnız bulud istifadəçisi siyasəti kimi təyin oluna bildiyi üçün nəzərə alınmadı.</translation>
<translation id="4450893287417543264">Göstərilməsin</translation>
<translation id="4451135742916150903">Saytlar HID cihazlarına qoşulmaq üçün icazə istəyə bilər</translation>
<translation id="4452328064229197696">İndicə istifadə etdiyiniz parol bir data pozuntusunda tapılıb. Hesablarınızı qorumaq üçün Google Parol Meneceri yadda saxladığınız parolları yoxlamağı tövsiyə edir.</translation>
@@ -1148,6 +1183,7 @@
<translation id="4628948037717959914">Foto</translation>
<translation id="4631649115723685955">Keşbek əlaqələndirilib</translation>
<translation id="4636930964841734540">Ä°nfo</translation>
+<translation id="4638670630777875591">Chromium'da Anonim Rejim</translation>
<translation id="464342062220857295">Axtarış funksiyaları</translation>
<translation id="4644670975240021822">Tərs sıra ilə üzü aşağı</translation>
<translation id="4646534391647090355">Ä°ndi giriÅŸ edilsin</translation>
@@ -1168,6 +1204,7 @@
<translation id="4708268264240856090">Bağlantınız kəsildi</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Windows Şəbəkə Diaqnostikası İşləyir<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426"><ph name="USERNAME" /> üçün parol</translation>
<translation id="4724144314178270921">Saytlar mübadilə buferinizdəki mətn və şəkilləri görmək üçün icazə istəyə bilər</translation>
<translation id="4726672564094551039">Qaydaları yenidən yükləyin</translation>
<translation id="4728558894243024398">Platforma</translation>
@@ -1189,6 +1226,7 @@
<translation id="4757993714154412917">İndicə parolunuzu aldadıcı sayt içində yazdınız. Hesablarınızı qorumaq üçün Chromium yadda saxladığınız parolları yoxlamağı tövsiyə edir.</translation>
<translation id="4758311279753947758">Kontakt məlumatı əlavə edin</translation>
<translation id="4761104368405085019">Mikrofon işlədin</translation>
+<translation id="4761869838909035636">Chrome Təhlükəsizlik Yoxlanışı icra edin</translation>
<translation id="4764776831041365478"><ph name="URL" /> ünvanındakı səhifə müvəqqəti olaraq deaktiv ola və ya həmişəlik olaraq yeni ünvana köçə bilər.</translation>
<translation id="4766713847338118463">Aşağıdan qoşa ştapel vurun</translation>
<translation id="4771973620359291008">Naməlum xəta baş verdi.</translation>
@@ -1209,12 +1247,6 @@
<translation id="4819347708020428563">Annotasiyalar defolt görünüşdə redaktə edilsin?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />, Tab düyməsi, sonra Enter düyməsinə basaraq cəld yeni Google Cədvəli yaradın</translation>
<translation id="4825507807291741242">Güclü</translation>
-<translation id="4827402517081186284">Anonim rejim sizi onlayn görünməz etmir:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Saytlar onları ziyarət etdiyiniz zaman xəbərdar olur<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />İşəgötürənlər və ya məktəblər axtarış fəaliyyətini izləyə bilir<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />İnternet xidmət təminatçıları veb trafikini izləyə bilər<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">Xəbərdarlıqları aktiv edin</translation>
<translation id="4838327282952368871">Xəyali</translation>
<translation id="4840250757394056958">Chrome tarixçənizə baxın</translation>
@@ -1226,12 +1258,12 @@
<translation id="4854362297993841467">Bu çatdırılma üsulu əlçatan deyil. Başqa üsul seçin.</translation>
<translation id="4854853140771946034">Google Keep'də cəld yeni qeyd yaradın</translation>
<translation id="485902285759009870">Kod doğrulanır...</translation>
+<translation id="4866506163384898554">Kursoru göstərmək üçün |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| düyməsinə basın</translation>
<translation id="4876188919622883022">Sadə görüntü</translation>
<translation id="4876305945144899064">İstifadəçi adı yoxdur</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{Heç biri}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831"><ph name="TEXT" /> axtarışı</translation>
<translation id="4879491255372875719">Avtomatik (defolt)</translation>
-<translation id="4879725228911483934">Ekranlarınızda pəncərələri açın və yerləşdirin</translation>
<translation id="4880827082731008257">Axtarış tarixçəsi</translation>
<translation id="4881695831933465202">Açın</translation>
<translation id="4885256590493466218">Ödəniş zamanı <ph name="CARD_DETAIL" /> ilə ödəyin</translation>
@@ -1240,6 +1272,7 @@
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">Doqquzuncu Rulon</translation>
<translation id="4901778704868714008">Yadda saxlayın...</translation>
+<translation id="4905659621780993806">Administrator cihazınızı bu vaxt avtomatik olaraq yenidən başladacaq: <ph name="TIME" />, <ph name="DATE" /> Cihazınız yenidən başlamazdan əvvəl hər hansı açıq elementləri yadda saxlayın.</translation>
<translation id="4913987521957242411">Yuxarı soldan deşik açın</translation>
<translation id="4918221908152712722"><ph name="APP_NAME" /> tətbiqini quraşdırın (endirmək tələb edilmir)</translation>
<translation id="4923459931733593730">Ödəniş</translation>
@@ -1248,6 +1281,7 @@
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, Tab düyməsi, sonra Enter düyməsinə basaraq axtarış edin</translation>
<translation id="4930153903256238152">Böyük tutum</translation>
+<translation id="4940163644868678279">Chrome'da Anonim Rejim</translation>
<translation id="4943872375798546930">Nəticə yoxdur</translation>
<translation id="4950898438188848926">Keçid düyməsinə klikləyin, açıq <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /> tabına keçmək üçün "Daxil olun" düyməsinə basın</translation>
<translation id="495170559598752135">Fəaliyyətlər</translation>
@@ -1257,6 +1291,7 @@
<translation id="4968522289500246572">Bu tətbiq mobil cihaz üçün nəzərdə tutulmuşdur və ölçüsü hər cihaz üçün uyğun olmaya bilər. Tətbiq problemlərlə qarşılaşa bilər və ya yenidən başladıla bilər.</translation>
<translation id="4969341057194253438">Qeydəalmanı silin</translation>
<translation id="4973922308112707173">Yuxarıdan qoşa deşik açın</translation>
+<translation id="4976702386844183910">Son ziyarət: <ph name="DATE" /></translation>
<translation id="4984088539114770594">Mikrofondan istifadÉ™ edilsin?</translation>
<translation id="4984339528288761049">Prc5 (Zərf)</translation>
<translation id="4989163558385430922">Hamısına baxın</translation>
@@ -1318,6 +1353,7 @@
<translation id="5138227688689900538">Daha azına baxın</translation>
<translation id="5145883236150621069">Xəta kodu siyasət cavabında mövcuddur</translation>
<translation id="5146995429444047494"><ph name="ORIGIN" /> üçün bildirişlər blok edilib</translation>
+<translation id="514704532284964975"><ph name="URL" /> telefonunuzla toxunduğunuz NFC cihazlarında məlumatları görmək və dəyişmək istəyir</translation>
<translation id="5148809049217731050">Üzü yuxarı</translation>
<translation id="515292512908731282">C4 (Zərf)</translation>
<translation id="5158275234811857234">Üzlük</translation>
@@ -1342,6 +1378,7 @@
<translation id="5215116848420601511">Google Pay istifadə edən kart və ünvanlar</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">Qab 13</translation>
+<translation id="5216942107514965959">Son ziyarət bu gün olub</translation>
<translation id="5222812217790122047">E-poçt ünvanı tələb olunur</translation>
<translation id="5230733896359313003">Göndəriş Ünvanı</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1362,7 +1399,6 @@
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">Sənəd xüsusiyyətləri</translation>
<translation id="528468243742722775">Son</translation>
-<translation id="5284909709419567258">Şəbəkə ünvanları</translation>
<translation id="5285570108065881030">Yadda saxlanmış bütün parolları göstərin</translation>
<translation id="5287240709317226393">Kukilərə baxın</translation>
<translation id="5287456746628258573">Bu sayt vaxtı keçmiş təhlükəsizlik konfiqurasiyasından istifadə edir və bu da sayta göndərilən məlumatınızın (məsələn, parol və ya kredit kartı nömrəsi) yayılmasına səbəb ola bilər.</translation>
@@ -1446,6 +1482,7 @@
<translation id="5556459405103347317">Yenidən yükləyin</translation>
<translation id="5560088892362098740">BitmÉ™ Tarixi</translation>
<translation id="55635442646131152">Sənəd icmalı</translation>
+<translation id="5565613213060953222">Anonim tab açın</translation>
<translation id="5565735124758917034">Aktiv</translation>
<translation id="5570825185877910964">Hesabınızı qoruyun</translation>
<translation id="5571083550517324815">Bu ünvandan götürmək mümkün deyil. Başqa ünvan seçin.</translation>
@@ -1528,6 +1565,7 @@
<translation id="5869522115854928033">Saxlanılmış parollar</translation>
<translation id="5873013647450402046">Bankınız bunun siz olduğunuzu təsdiq etmək istəyir.</translation>
<translation id="5887400589839399685">Kart yadda saxlanıldı</translation>
+<translation id="5887687176710214216">Son ziyarət dünən olub</translation>
<translation id="5895138241574237353">Yenidən başladın</translation>
<translation id="5895187275912066135">Buraxılış Tarixi</translation>
<translation id="5901630391730855834">Sarı</translation>
@@ -1541,6 +1579,7 @@
<translation id="5921639886840618607">Kart Google Hesabında yadda saxlanılsın?</translation>
<translation id="5922853866070715753">Demək olar ki, hazırdır</translation>
<translation id="5932224571077948991">Sayt intruziv və ya aldadıcı reklamlar göstərir</translation>
+<translation id="5938153366081463283">Virtual kart əlavə edin</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347"><ph name="SITE_NAME" /> açılır…</translation>
<translation id="5951495562196540101">Müştəri hesabı (toplu lisenziya əlçatandır) ilə qeydiyyatdan keçmək mümkün deyil.</translation>
@@ -1605,6 +1644,7 @@
<translation id="6120179357481664955">UPI ID'niz yadda saxlansın?</translation>
<translation id="6124432979022149706">Chrome Enterprise Birləşdiriciləri</translation>
<translation id="6127379762771434464">Element silindi</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Chrome'da Anonim Rejim barədə məlumat<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">Kabelləri yoxlayın və istifadə edəcəyiniz hər hansı router, modem və ya digər
şəbəkə cihazlarını yenidən yükləyin.</translation>
<translation id="614940544461990577">Cəhd edin:</translation>
@@ -1617,7 +1657,6 @@
<translation id="6169916984152623906">İndi şəxsi axtarış edə bilərsiniz və bu cihazı istifadə edən digər şəxslər fəaliyyətinizi görməyəcək. Lakin endirmələr və əlfəcinlər yadda saxlanacaq.</translation>
<translation id="6177128806592000436">Bu sayta olan bağlantınız güvənli deyil</translation>
<translation id="6180316780098470077">Təkrar cəhd intervalı</translation>
-<translation id="619448280891863779">Saytlar ekranlarınızda pəncərələr açmaq və yerləşdirmək üçün icazə istəyə bilər</translation>
<translation id="6196640612572343990">Üçüncü tərəf kukiləri blok edin</translation>
<translation id="6203231073485539293">İnternet bağlantısını yoxlayın</translation>
<translation id="6218753634732582820">Ãœnvan Chromium'dan silinsin?</translation>
@@ -1640,7 +1679,7 @@
<translation id="6272383483618007430">Google Güncəlləməsi</translation>
<translation id="6276112860590028508">Oxu siyahısının səhifələri burada görünəcək</translation>
<translation id="627746635834430766">Növbəti dəfə daha sürətli ödəniş etmək üçün kartı və faktura ünvanını Google Hesabınızda yadda saxlayın.</translation>
-<translation id="6279098320682980337">Virtual kart nömrəsi daxil edilməyib? Kopyalamaq üçün kart məlumatlarını tıklayın</translation>
+<translation id="6279183038361895380">Kursorunuzu göstərmək üçün |<ph name="ACCELERATOR" />| basın</translation>
<translation id="6280223929691119688">Bu ünvana çatdırmaq mümkün deyil. Başqa ünvan seçin.</translation>
<translation id="6282194474023008486">Poçt kodu</translation>
<translation id="6285507000506177184">"Chrome'da endirmələri idarə edin" düyməsi, Enter düyməsinə basaraq Chrome'da endirdiyiniz faylları idarə edin</translation>
@@ -1648,6 +1687,7 @@
<translation id="6290238015253830360">Təklif edilən məqalələriniz burada görünür</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{Cihazınız indi yenidən başladılacaq}=1{Cihazınız 1 saniyə ərzində yenidən başladılacaq}other{Cihazınız # saniyə ərzində yenidən başladılacaq}}</translation>
<translation id="6302269476990306341">Google Assistent Chrome'da dayanmağa başlayır</translation>
<translation id="6305205051461490394"><ph name="URL" /> əlçatmazdır.</translation>
<translation id="6312113039770857350">Veb səhifə əlçatan deyil</translation>
@@ -1721,6 +1761,7 @@
<translation id="6529602333819889595">Silinməni yenidən edin</translation>
<translation id="6545864417968258051">Bluetooth axtarışı</translation>
<translation id="6547208576736763147">Soldan qoşa deşik açın</translation>
+<translation id="6554732001434021288">Son ziyarət <ph name="NUM_DAYS" /> gün əvvəl olub</translation>
<translation id="6556866813142980365">Yenidən edin</translation>
<translation id="6569060085658103619">Artırma səhifəsinə baxırsınız</translation>
<translation id="6573200754375280815">Sağdan qoşa deşik açın</translation>
@@ -1781,7 +1822,6 @@
<translation id="6757797048963528358">Cihazınız yatmağa getdi.</translation>
<translation id="6767985426384634228">Ünvan yenilənsin?</translation>
<translation id="6768213884286397650">Hagaki (Postkart)</translation>
-<translation id="6774185088257932239">Anonim rejim haqqında <ph name="BEGIN_LINK" />ətraflı məlumat<ph name="END_LINK" /></translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">Tünd-bənövşəyi</translation>
<translation id="6786747875388722282">Artırmalar</translation>
@@ -1865,7 +1905,6 @@
<translation id="706295145388601875">Chrome ayarlarında ünvanlar əlavə edin və idarə edin</translation>
<translation id="7064851114919012435">Kontakt məlumatı</translation>
<translation id="7068733155164172741"><ph name="OTP_LENGTH" /> rəqəmli kodu daxil edin</translation>
-<translation id="7070090581017165256">Bu sayt haqqında</translation>
<translation id="70705239631109039">Bağlantınız tam təhlükəsiz deyil</translation>
<translation id="7075452647191940183">Sorğu çox uzundur</translation>
<translation id="7079718277001814089">Bu saytda virus var</translation>
@@ -1882,6 +1921,12 @@
<translation id="7111012039238467737">(Düzgün)</translation>
<translation id="7118618213916969306">Mübadilə buferindən link axtarın, <ph name="SHORT_URL" /></translation>
<translation id="7119414471315195487">Digər tab və ya proqramları bağlayın</translation>
+<translation id="7129355289156517987">Bütün Chromium Anonim tablarını bağladığınız zaman həmin tablardakı fəaliyyətiniz bu cihazdan silinir:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Axtarış fəaliyyəti<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Axtarış tarixçəsi<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Formalara daxil edilmiş məlumatlar<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">Bu ünvana göndərmək mümkün deyil. Başqa ünvan seçin.</translation>
<translation id="7132939140423847331">Admininiz bu məlumatın kopyalanmasını qadağan edib.</translation>
<translation id="7135130955892390533">Statusu göstərin</translation>
@@ -1904,6 +1949,7 @@
<translation id="7192203810768312527"><ph name="SIZE" /> yer boşaldır. Bəzi saytlar növbəti dəfə daxil olduğunuzda gec yüklənə bilər.</translation>
<translation id="719464814642662924">Viza</translation>
<translation id="7201591969684833065">Administrator baxa bilər:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, Tab düyməsi, sonra Enter düyməsinə basaraq yeni Anonim tab açın və gizli baxış keçirin</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> təhlükəsizlik standartlarına əməl etmir.</translation>
<translation id="7210993021468939304">Konteyner nəzdində Linux fəaliyyəti. Konteyner nəzdində Linux tətbiqləri quraşdırmaq, icra etmək mümkündür</translation>
@@ -1935,6 +1981,7 @@
<translation id="7304562222803846232">Google Hesabının məxfilik ayarlarını idarə edin</translation>
<translation id="7305756307268530424">Daha asta sürəti başladın</translation>
<translation id="7308436126008021607">arxa fonda sinxronizasiya</translation>
+<translation id="7310392214323165548">Cihaz tezliklə yenidən başladılacaq</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">Bağlantı Yardımı</translation>
<translation id="7323804146520582233">"<ph name="SECTION" />" bölməsini gizlədin</translation>
@@ -1942,6 +1989,7 @@
<translation id="7334320624316649418">&amp;Yenidən yerbəyer edin</translation>
<translation id="7335157162773372339">Saytlar kameranızdan istifadə üçün icazə tələb edə bilər</translation>
<translation id="7337248890521463931">Daha çox sətir göstərin</translation>
+<translation id="7337418456231055214">Virtual kart nömrəsi daxil edilməyib? Kopyalamaq üçün kart məlumatlarını tıklayın. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">Platformanızda əlçatan deyil.</translation>
<translation id="733923710415886693">Serverin sertifikatı Sertifikat Şəffaflığı vasitəsi ilə aşkarlanmayıb.</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1964,6 +2012,7 @@
<translation id="7378627244592794276">Xeyr</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">Tətbiq olunmur</translation>
+<translation id="7388594495505979117">{0,plural, =1{Cihazınız 1 dəqiqə ərzində yenidən başladılacaq}other{Cihazınız # dəqiqə ərzində yenidən başladılacaq}}</translation>
<translation id="7390545607259442187">Kartı Təsdiqləyin</translation>
<translation id="7392089738299859607">Ünvanı yeniləyin</translation>
<translation id="7399802613464275309">Təhlükəsizlik Yoxlanışı</translation>
@@ -2000,6 +2049,12 @@
<translation id="7485870689360869515">Heç bir data tapılmadı.</translation>
<translation id="7495528107193238112">Bu məzmun bloklanıb. Problemi düzəltmək üçün sayt sahibi ilə əlaqə saxlayın.</translation>
<translation id="7497998058912824456">"Sənəd yaradın" düyməsi, Enter düyməsinə basaraq cəld yeni Google Sənəd yaradın</translation>
+<translation id="7506488012654002225">Chromium aşağıdakı məlumatları <ph name="BEGIN_EMPHASIS" />yadda saxlamayacaq<ph name="END_EMPHASIS" />:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Axtarış tarixçəniz
+ <ph name="LIST_ITEM" />Kuki və sayt datası
+ <ph name="LIST_ITEM" />Formalara daxil edilmiş məlumatlar
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">Qaytarılmış qaydalar cihaz İD'si boşdur və ya cari cihaz İD'si ilə üst-üstə düşmür</translation>
<translation id="7508870219247277067">Avokado Yaşılı</translation>
<translation id="7511955381719512146">İşlətdiyiniz Wi-Fi <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> linkinə daxil olmağı tələb edə bilər.</translation>
@@ -2113,7 +2168,6 @@
<translation id="7813600968533626083">Təkliflər Chrome'dan silinsin?</translation>
<translation id="781440967107097262">Mübadilə buferi paylaşılsın?</translation>
<translation id="7815407501681723534">'<ph name="SEARCH_STRING" />' üçün <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> tapılmışdır</translation>
-<translation id="782125616001965242">Bu sayt haqqında məlumat göstərin</translation>
<translation id="782886543891417279">İstifadə etdiyiniz Wi-Fi (<ph name="WIFI_NAME" />) Sizdən login səhifəsinə daxil olmağınızı tələb edə bilər.</translation>
<translation id="7836231406687464395">Postfix (Zərf)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{Heç bir tətbiq}=1{1 tətbiq (<ph name="EXAMPLE_APP_1" />)}=2{2 tətbiq (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}other{# tətbiq (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}}</translation>
@@ -2130,7 +2184,6 @@
<translation id="7888575728750733395">Çapın göstərilmə məqsədi</translation>
<translation id="7894280532028510793">Yazılış doğrudursa, <ph name="BEGIN_LINK" />Şəbəkə Diaqnostikasını icra edin<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (Zərf)</translation>
-<translation id="7931318309563332511">Naməlum</translation>
<translation id="793209273132572360">Ünvan yenilənsin?</translation>
<translation id="7932579305932748336">Palto</translation>
<translation id="79338296614623784">Düzgün telefon nömrəsi daxil edin</translation>
@@ -2155,13 +2208,14 @@
<translation id="7976214039405368314">Həddən çox sorğu var</translation>
<translation id="7977538094055660992">Çıxış cihazı</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">Bununla əlaqələndirilib:</translation>
<translation id="798134797138789862">Saytlar virtual reallıq cihazları və datadan istifadə üçün icazə istəyə bilər</translation>
<translation id="7984945080620862648">Sayt güvənsiz kredensiallar göndərdiyi üçün <ph name="SITE" /> ünvanına girə bilməzsiniz.</translation>
-<translation id="79859296434321399">Artırılmış virtual reallıq kontentinə baxmaq üçün ARCore quraşdırın</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">Uclarını qovuşdurun</translation>
<translation id="7992044431894087211"><ph name="APPLICATION_TITLE" /> ilə ekran paylaşımı davam etdirilib</translation>
<translation id="7995512525968007366">Göstərilməəyib</translation>
+<translation id="7998269595945679889">"Anonim tab açın" düyməsi, gizli baxış üçün yeni Anonim tab açmaq üçün Enter düyməsinə basın</translation>
<translation id="800218591365569300">Yaddaşı boşaltmaq üçün digər tab və proqramları bağlayın.</translation>
<translation id="8004582292198964060">Brauzer</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{Bu kart və faktura ünvanı yadda saxlanacaq. <ph name="USER_EMAIL" /> hesabına daxil olduqda bundan istifadə edə bilməyəcəksiniz.}other{Bu kartlar və faktura ünvanları yadda saxlanacaq. <ph name="USER_EMAIL" /> hesabına daxil olduqda bunlardan istifadə edə bilməyəcəksiniz.}}</translation>
@@ -2221,6 +2275,7 @@
<translation id="8202370299023114387">Ziddiyət</translation>
<translation id="8206978196348664717">Prc4 (Zərf)</translation>
<translation id="8211406090763984747">Bağlantı təhlükəsizdir</translation>
+<translation id="8217240300496046857">Saytlar vebdə sizi izləyən kukilərdən istifadə edə bilmir. Bəzi saytlarda funksiyalar işləməyə bilər.</translation>
<translation id="8218327578424803826">Ayrılmış yer:</translation>
<translation id="8220146938470311105">C7/C6 (Zərf)</translation>
<translation id="8225771182978767009">Kompüteri quraşdıran şəxs bu saytı blok etməyi seçib.</translation>
@@ -2261,14 +2316,9 @@
<translation id="830498451218851433">Yarımçıq qatlayın</translation>
<translation id="8307358339886459768">Kiçik Ölçülü Foto</translation>
<translation id="8307888238279532626">Quraşdırılmış tətbiqlər və nə zaman istifadə edildikləri</translation>
+<translation id="8317207217658302555">ARCore güncəllənsin?</translation>
<translation id="831997045666694187">AxÅŸam</translation>
<translation id="8321476692217554900">bildirişlər</translation>
-<translation id="8328484624016508118">Bütün Anonim tabları bağladıqdan sonra Chrome bunları təmizləyəcək:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Bu cihazdan axtarış fəaliyyətinizi<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Bu cihazdan axtarış tarixçənizi<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Formalara daxil edilən məlumatları<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489"><ph name="HOST_NAME" /> hostuna giriş rədd edildi</translation>
<translation id="833262891116910667">VurÄŸulama</translation>
<translation id="8339163506404995330"><ph name="LANGUAGE" /> dilində olan səhifələr tərcümə edilməyəcək</translation>
@@ -2320,6 +2370,7 @@
<translation id="8507227106804027148">Æmr sahÉ™si</translation>
<translation id="8508648098325802031">Axtarış işarəsi</translation>
<translation id="8511402995811232419">Kukiləri idarə edin</translation>
+<translation id="8519753333133776369">Administratorunuz tərəfindən icazə verilən HID cihazı</translation>
<translation id="8522552481199248698">Chrome Google Hesabınızı qorumağa və parolu dəyişməyə kömək edə bilər.</translation>
<translation id="8530813470445476232">Baxış tarixçəsi, kukilər, keş və daha çoxunu Chrome ayarlarında təmizləyin</translation>
<translation id="8533619373899488139">Bloklanmış URL-ləri və sistem admininin tətbiq etdiyi digər siyasətləri görmək üçün buraya keçin: &lt;strong&gt;chrome://policy&lt;/strong&gt;</translation>
@@ -2331,7 +2382,6 @@
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{İcazəni sıfırlayın}other{İcazələri sıfırlayın}}</translation>
<translation id="8555010941760982128">Ödəniş zamanı bu koddan istifadə edin</translation>
<translation id="8557066899867184262">CVC kartın arxasında yerləşir.</translation>
-<translation id="8558485628462305855">Artırılmış virtual reallıq kontentinə baxmaq üçün ARCore'u güncəlləyin</translation>
<translation id="8559762987265718583">Cihazınızın tarixi və vaxtı (<ph name="DATE_AND_TIME" />) yanlış olduğundan, <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> domeninə şəxsi bağlantı yaradıla bilməz.</translation>
<translation id="8564182942834072828">Ayrıca sənədlər/Sıralanmamış nüsxələr</translation>
<translation id="8564985650692024650">Parolunuzdan digər saytlarda təkrar istifadə etmisinizsə, Chromium <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> parolunuzu sıfırlamağı tövsiyə edir.</translation>
@@ -2350,6 +2400,7 @@
<translation id="865032292777205197">hərəkət sensorları</translation>
<translation id="8663226718884576429">Sifarişin Yekunu, <ph name="TOTAL_LABEL" />, Daha Çox Məlumat</translation>
<translation id="8666678546361132282">Ingilis</translation>
+<translation id="8669306706049782872">Pəncərələri açmaq və yerləşdirmək üçün ekranlarınız haqqında məlumatdan istifadə edin</translation>
<translation id="867224526087042813">Ä°mza</translation>
<translation id="8676424191133491403">GecikmÉ™ yoxdur</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, cavab, <ph name="ANSWER" /></translation>
@@ -2376,6 +2427,7 @@
<translation id="8731544501227493793">"Parolları idarə edin" düyməsi, Chrome ayarlarında parollarınıza baxmaq və idarə etmək üçün Enter düyməsinə basın</translation>
<translation id="8734529307927223492"><ph name="DEVICE_TYPE" /> cihazınız <ph name="MANAGER" /> tərəfindən idarə edilir</translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, Tab düyməsi, sonra Enter düyməsinə basaraq yeni Anonim pəncərə açın və gizli baxış keçirin</translation>
+<translation id="8737685506611670901"><ph name="REPLACED_HANDLER_TITLE" /> əvəzinə <ph name="PROTOCOL" /> linklərini açın</translation>
<translation id="8738058698779197622">Güvənli bağlantı yaratmaq üçün saatınız düzgün ayarlanmalıdır. Çünki saytların işlətdikləri sertifikatlar zamana bağlıdır. Saatınız düzgün işləmədiyi halda Chromium bu sertifikatları doğrulaya bilmir.</translation>
<translation id="8740359287975076522"><ph name="HOST_NAME" />’s &lt;abbr id="dnsDefinition"&gt;DNS address&lt;/abbr&gt; tapılmadı. Problem təyin edilir.</translation>
<translation id="8742371904523228557"><ph name="ORIGIN" /> üçün kodunuz: <ph name="ONE_TIME_CODE" /></translation>
@@ -2403,6 +2455,7 @@
<translation id="883848425547221593">DigÉ™r ÆlfÉ™cinlÉ™r</translation>
<translation id="884264119367021077">Göndərmə ünvanı</translation>
<translation id="884923133447025588">Ləğv etmə mexanizmi tapılmadı.</translation>
+<translation id="8849262850971482943">ÆlavÉ™ tÉ™hlükÉ™sizlik üçün virtual kartınızdan istifadÉ™ edin</translation>
<translation id="885730110891505394">Google ilə paylaşılır</translation>
<translation id="8858065207712248076">Parolunuzdan digər saytlarda təkrar istifadə etmisinizsə, Chrome <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> parolunuzu sıfırlamağı tövsiyə edir.</translation>
<translation id="885906927438988819">Yazılış doğrudursa, <ph name="BEGIN_LINK" />Windows Şəbəkə Diaqnostikasını icra edin<ph name="END_LINK" />.</translation>
@@ -2452,6 +2505,7 @@
<translation id="9004367719664099443">VR sessiyası davam edir</translation>
<translation id="9005998258318286617">PDF sənədini yükləmək alınmadı.</translation>
<translation id="9008201768610948239">Ä°qnor</translation>
+<translation id="901834265349196618">e-poçt</translation>
<translation id="9020200922353704812">Kart faktura ünvanı tələb edilir</translation>
<translation id="9020542370529661692">Bu səhifə <ph name="TARGET_LANGUAGE" /> dilinə tərcümə edilmişdir</translation>
<translation id="9020742383383852663">A8</translation>
@@ -2500,6 +2554,7 @@
<translation id="9150045010208374699">Kameranızı istifadə edin</translation>
<translation id="9150685862434908345">Administratorunuz brauzer quraÅŸdırmanızı uzaqdan dÉ™yiÅŸÉ™ bilÉ™r. Bu cihazdakı fÉ™aliyyÉ™t Chrome'dan kÉ™narda da idarÉ™ edilÉ™ bilÉ™r. <ph name="BEGIN_LINK" />Ætraflı mÉ™lumat<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">Güncəlləşib</translation>
+<translation id="9155211586651734179">Köməkçi audio cihazları əlavə edilib</translation>
<translation id="9157595877708044936">Ayarlanır...</translation>
<translation id="9158625974267017556">C6 (Zərf)</translation>
<translation id="9164029392738894042">Dəqiqliyin Yoxlanması</translation>
diff --git a/chromium/components/strings/components_strings_be.xtb b/chromium/components/strings/components_strings_be.xtb
index e4ff3a3340b..0e41192b7a9 100644
--- a/chromium/components/strings/components_strings_be.xtb
+++ b/chromium/components/strings/components_strings_be.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">Больш падрабÑзна</translation>
<translation id="1030706264415084469">Сайт <ph name="URL" /> запытвае дазволу захоўваць вÑлікі аб'ём даных на вашай прыладзе</translation>
<translation id="1032854598605920125">ПавÑрнуць па гадзіннікавай ÑÑ‚Ñ€Ñлцы</translation>
+<translation id="1033329911862281889">РÑжым інкогніта не робіць нÑбачнай вашу прыÑутнаÑць у інтÑрнÑце:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Ñайты Ñ– ÑÑрвіÑÑ‹, ÑÐºÑ–Ñ Ñны выкарыÑтоўваюць, Ñ€ÑгіÑтруюць наведванні;<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />работадаўцы Ñ– Ð½Ð°Ð²ÑƒÑ‡Ð°Ð»ÑŒÐ½Ñ‹Ñ ÑžÑтановы могуць адÑочваць дзеÑнні Ñž браўзеры;<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />інтÑрнÑÑ‚-правайдары могуць адÑочваць інтÑрнÑÑ‚-трафік.<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">Выключыць</translation>
<translation id="1036982837258183574">ÐаціÑніце "<ph name="ACCELERATOR" />", каб выйÑці з поўнаÑкраннага Ñ€Ñжыму</translation>
<translation id="1038106730571050514">Паказаць прапановы</translation>
<translation id="1038842779957582377">невÑдомае імÑ</translation>
<translation id="1041998700806130099">Паведамленне аркуша заданнÑ</translation>
<translation id="1048785276086539861">Калі вы будзеце змÑнÑць анатацыі, гÑÑ‚Ñ‹ дакумент вернецца Ñž аднаÑтаронкавы выглÑд</translation>
-<translation id="1049743911850919806">Інкогніта</translation>
<translation id="1050038467049342496">Закрыйце Ñ–Ð½ÑˆÑ‹Ñ Ð¿Ñ€Ð°Ð³Ñ€Ð°Ð¼Ñ‹</translation>
<translation id="1055184225775184556">&amp;Ðдрабіць дадаванне</translation>
<translation id="1056898198331236512">ПапÑÑ€Ñджанне</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">У кÑшы правіла нÑма памылак</translation>
<translation id="1130564665089811311">Кнопка "ПераклаÑці Ñтаронку". Каб пераклаÑці гÑту Ñтаронку Ñž Перакладчыку Google, націÑніце Enter</translation>
<translation id="1131264053432022307">Скапіраваны вамі відарыÑ</translation>
+<translation id="1142846828089312304">Блакіраваць ÑÑ‚Ð°Ñ€Ð¾Ð½Ð½Ñ–Ñ Ñ„Ð°Ð¹Ð»Ñ‹ cookie у Ñ€Ñжыме інкогніта</translation>
<translation id="1150979032973867961">Серверу не ўдалоÑÑ Ð´Ð°ÐºÐ°Ð·Ð°Ñ†ÑŒ, што гÑта <ph name="DOMAIN" />: Ð°Ð¿ÐµÑ€Ð°Ñ†Ñ‹Ð¹Ð½Ð°Ñ ÑÑ–ÑÑ‚Ñма камп'ютара не давÑрае Ñертыфікату бÑÑпекі гÑтага дамена. Прычынай могуць быць нÑÐ¿Ñ€Ð°Ð²Ñ–Ð»ÑŒÐ½Ñ‹Ñ Ð½Ð°Ð»Ð°Ð´Ñ‹ або зламыÑнік, Ñкі Ñпрабуе перахапіць падключÑнне.</translation>
<translation id="1151972924205500581">УвÑдзіце пароль</translation>
<translation id="1156303062776767266">Ð’Ñ‹ праглÑдаеце лакальны ці абагулены файл</translation>
@@ -64,7 +70,6 @@
<translation id="1178581264944972037">Прыпыніць</translation>
<translation id="1181037720776840403">Выдаліць</translation>
<translation id="1186201132766001848">Праверыць паролі</translation>
-<translation id="1195210374336998651">ПерайÑці Ñž налады праграмы</translation>
<translation id="1195558154361252544">ÐпавÑшчÑнні аўтаматычна блакіруюцца Ð´Ð»Ñ ÑžÑÑ–Ñ… Ñайтаў, Ð°ÐºÑ€Ð°Ð¼Ñ Ñ‚Ñ‹Ñ…, Ñкім вы далі дазвол Ñ–Ñ… паказваць</translation>
<translation id="1197088940767939838">Ðранжавы</translation>
<translation id="1201402288615127009">Далей</translation>
@@ -111,7 +116,7 @@
<translation id="1307966114820526988">СаÑтарÑÐ»Ñ‹Ñ Ñ„ÑƒÐ½ÐºÑ†Ñ‹Ñ–</translation>
<translation id="1308113895091915999">ÐÑць прапанова</translation>
<translation id="1312803275555673949">Што пацвÑрджае гÑту інфармацыю?</translation>
-<translation id="131405271941274527">Сайт <ph name="URL" /> запытвае доÑтуп на абмен інфармацыÑй, калі вы націÑканнем выбіраеце Ñвой Ñ‚Ñлефон на прыладзе NFC</translation>
+<translation id="1314311879718644478">ПраглÑдайце змеÑціва Ñž Ñ€Ñжыме дапоўненай Ñ€ÑальнаÑці</translation>
<translation id="1314509827145471431">Пераплёт Ñправа</translation>
<translation id="1318023360584041678">Захавана ў групе ўкладак</translation>
<translation id="1319245136674974084">Больш не пытаць адноÑна гÑтай праграмы</translation>
@@ -161,6 +166,7 @@
<translation id="142858679511221695">КарыÑтальнік воблачнага ÑÑрвіÑу</translation>
<translation id="1428729058023778569">ГÑта папÑÑ€Ñджанне паказана вам, бо дадзены Ñайт не падтрымлівае HTTPS. <ph name="BEGIN_LEARN_MORE_LINK" />Даведацца больш<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">Друк</translation>
+<translation id="1432187715652018471">Старонка Ñпрабуе ÑžÑталÑваць апрацоўшчык ÑÑрвіÑу.</translation>
<translation id="1432581352905426595">Кіраваць пошукавымі ÑÑ–ÑÑ‚Ñмамі</translation>
<translation id="1436185428532214179">Сайт можа запытваць дазвол на змÑненне файлаў або папак на прыладзе</translation>
<translation id="1442386063175183758">Згіб "вароты" Ñправа</translation>
@@ -181,6 +187,12 @@
<translation id="1483493594462132177">Ðдправіць</translation>
<translation id="1484290072879560759">Выбраць Ð°Ð´Ñ€Ð°Ñ Ð´Ð°Ñтаўкі</translation>
<translation id="1492194039220927094">Паказ палітык:</translation>
+<translation id="149293076951187737">Пры закрыцці ÑžÑÑ–Ñ… укладак, адкрытых у Ñ€Ñжыме інкогніта Ñž браўзеры Chrome, з гÑтай прылады выдалÑюцца Ð´Ð°Ð½Ñ‹Ñ Ð¿Ñ€Ð° ÑžÑе вашы дзеÑнні Ñž гÑÑ‚Ñ‹Ñ… укладках:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />дзеÑнні Ñž браўзеры;<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />гіÑÑ‚Ð¾Ñ€Ñ‹Ñ Ð¿Ð¾ÑˆÑƒÐºÑƒ;<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />звеÑткі, ÑÐºÑ–Ñ Ð±Ñ‹Ð»Ñ– ўведзены Ñž формах.<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">Ð’Ñрнуцца на ўкладку</translation>
<translation id="1501859676467574491">Паказаць карткі з вашага Уліковага запіÑу Google</translation>
<translation id="1507202001669085618">&lt;p&gt;ГÑта памылка ўзнікае, калі вы карыÑтаецеÑÑ Ð¿Ð°Ñ€Ñ‚Ð°Ð»Ð°Ð¼ Wi-Fi, на Ñкім перад выхадам у інтÑрнÑÑ‚ Ñ‚Ñ€Ñба выканаць уваход.&lt;/p&gt;
@@ -208,6 +220,8 @@
<translation id="1559572115229829303">&lt;p&gt;Ðемагчыма ÑžÑтанавіць прыватнае падключÑнне да дамена <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />, бо дата Ñ– Ñ‡Ð°Ñ Ð½Ð° прыладзе (<ph name="DATE_AND_TIME" />) нÑправільныÑ.&lt;/p&gt;
&lt;p&gt;ЗмÑніце дату Ñ– Ñ‡Ð°Ñ Ñƒ раздзеле &lt;strong&gt;ÐгульныÑ&lt;/strong&gt; праграмы &lt;strong&gt;Ðалады&lt;/strong&gt;.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">ÐдмініÑтратар перазапуÑціць прыладу Ñž <ph name="TIME" /> <ph name="DATE" /></translation>
+<translation id="156703335097561114">Ð¡ÐµÑ‚ÐºÐ°Ð²Ñ‹Ñ Ð´Ð°Ð½Ñ‹Ñ, Ñ‚Ð°ÐºÐ°Ñ Ñк адраÑÑ‹, налады інтÑрфейÑу Ñ– ÑкаÑць падключÑннÑ</translation>
<translation id="1567040042588613346">ГÑта палітыка працуе належным чынам, але замÑнÑе аднолькавае значÑнне, зададзенае з іншай крыніцы.</translation>
<translation id="1569487616857761740">УвÑдзіце Ñ‚Ñрмін дзеÑннÑ</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@
<translation id="1583429793053364125">ÐŸÐ°Ð´Ñ‡Ð°Ñ Ð¿Ð°ÐºÐ°Ð·Ñƒ вÑб-Ñтаронкі нешта пайшло не так.</translation>
<translation id="1586541204584340881">Ð¯ÐºÑ–Ñ Ð¿Ð°ÑˆÑ‹Ñ€Ñнні вы ÑžÑталÑвалі.</translation>
<translation id="1588438908519853928">Звычайны</translation>
+<translation id="1589050138437146318">УÑталÑваць ARCore?</translation>
<translation id="1592005682883173041">ДоÑтуп да лакальных даных</translation>
<translation id="1594030484168838125">Выбраць</translation>
<translation id="160851722280695521">ГулÑць у "Прабежку з дыназаўрам" у Chrome</translation>
@@ -254,7 +269,7 @@
<translation id="1711234383449478798">Ðе прымÑнÑецца, паколькі палітыка "<ph name="POLICY_NAME" />" не мае значÑÐ½Ð½Ñ "<ph name="VALUE" />".</translation>
<translation id="1712552549805331520">Сайт <ph name="URL" /> запытвае дазволу захоўваць Ð´Ð°Ð½Ñ‹Ñ Ð½Ð° лакальным камп'ютары</translation>
<translation id="1713628304598226412">Латок 2</translation>
-<translation id="1715874602234207">F</translation>
+<translation id="1715874602234207">Пт</translation>
<translation id="1717218214683051432">Датчыкі руху</translation>
<translation id="1717494416764505390">ÐŸÐ°ÑˆÑ‚Ð¾Ð²Ð°Ñ Ñкрынка 3</translation>
<translation id="1718029547804390981">Занадта вÑлікі дакумент Ð´Ð»Ñ Ð°Ð½Ð°Ñ‚Ð°Ñ†Ñ‹Ð¹</translation>
@@ -283,6 +298,7 @@
фармат загалоўка нÑправільны, што не дазвалÑе браўзеру
выканаць запыт Ñайта "<ph name="SITE" />". Палітыкі крыніцы могуць выкарыÑтоўвацца
аператарамі Ñайтаў Ð´Ð»Ñ Ð½Ð°Ð»Ð°Ð´Ð¶Ð²Ð°Ð½Ð½Ñ Ð±ÑÑпекі Ñ– іншых улаÑціваÑцей Ñайта.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Даведацца больш пра Ñ€Ñжым інкогніта Ñž браўзеры Chromium<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">ÐÐ´ÐºÑ€Ñ‹Ñ‚Ñ‹Ñ ÑžÐºÐ»Ð°Ð´ÐºÑ– з'ÑвÑцца тут</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -410,6 +426,7 @@
<translation id="22081806969704220">Латок 3</translation>
<translation id="2212735316055980242">Палітыка не знойдзена</translation>
<translation id="2213606439339815911">Ідзе атрыманне запіÑаў...</translation>
+<translation id="2213612003795704869">Старонка надрукавана</translation>
<translation id="2215727959747642672">ЗмÑненне файлаў</translation>
<translation id="2218879909401188352">ЗламыÑнікі на Ñайце <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> могуць уÑталÑваць праграмы, ÑÐºÑ–Ñ Ð¼Ð¾Ð³ÑƒÑ†ÑŒ Ñтаць прычынай Ð¿Ð°ÑˆÐºÐ¾Ð´Ð¶Ð°Ð½Ð½Ñ Ð²Ð°ÑˆÐ°Ð¹ прылады, ÑÐ¿Ð°Ð³Ð½Ð°Ð½Ð½Ñ Ð´Ð°Ð´Ð°Ñ‚ÐºÐ¾Ð²Ð°Ð¹ Ñхаванай аплаты за паÑлугі мабільнай ÑувÑзі або крадзÑжу вашай аÑабіÑтай інфармацыі. <ph name="BEGIN_LEARN_MORE_LINK" />Даведацца больш<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">ÐÑма падключÑÐ½Ð½Ñ Ð´Ð° інтÑрнÑту</translation>
@@ -419,6 +436,7 @@
<translation id="2248949050832152960">ВыкарыÑтоўваць WebAuthn</translation>
<translation id="2250931979407627383">Сшыванне па краі злева</translation>
<translation id="225207911366869382">ГÑта ÑаÑтарÑлае значÑнне Ð´Ð»Ñ Ð¿Ð°Ð»Ñ–Ñ‚Ñ‹ÐºÑ–.</translation>
+<translation id="2256115617011615191">ПеразапуÑціць</translation>
<translation id="2258928405015593961">УвÑдзіце дату заканчÑÐ½Ð½Ñ Ñ‚Ñрміну дзеÑннÑ, ÑÐºÐ°Ñ ÑÑˆÑ‡Ñ Ð½Ðµ наÑтупіла, Ñ– паўтарыце Ñпробу</translation>
<translation id="225943865679747347">Код памылкі: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">Памылка HTTP</translation>
@@ -446,6 +464,7 @@
<translation id="2337852623177822836">Ðаладай кіруе ваш адмініÑтратар</translation>
<translation id="2340263603246777781">Сайт <ph name="ORIGIN" /> запытвае ÑпалучÑнне</translation>
<translation id="2346319942568447007">Скапіраваны вамі відарыÑ</translation>
+<translation id="2350796302381711542">Дазволіць хоÑту <ph name="HANDLER_HOSTNAME" /> адкрываць уÑе ÑпаÑылкі тыпу "<ph name="PROTOCOL" />" (замеÑÑ‚ <ph name="REPLACED_HANDLER_TITLE" />)?</translation>
<translation id="2354001756790975382">Ð†Ð½ÑˆÑ‹Ñ Ð·Ð°ÐºÐ»Ð°Ð´ÐºÑ–</translation>
<translation id="2354430244986887761">Google БÑÑпечны праглÑд нÑдаўна <ph name="BEGIN_LINK" />выÑвіў ÑˆÐºÐ¾Ð´Ð½Ñ‹Ñ Ð¿Ñ€Ð°Ð³Ñ€Ð°Ð¼Ñ‹<ph name="END_LINK" /> на Ñайце <ph name="SITE" />.</translation>
<translation id="2355395290879513365">ЗламыÑнікі могуць бачыць відарыÑÑ‹, ÑÐºÑ–Ñ Ð²Ñ‹ праглÑдаеце на гÑтым Ñайце, Ñ– падмануць ваÑ, мадыфікуючы Ñ–Ñ….</translation>
@@ -471,6 +490,7 @@
<translation id="2413528052993050574">Серверу не ўдалоÑÑ Ð´Ð°ÐºÐ°Ð·Ð°Ñ†ÑŒ, што гÑта <ph name="DOMAIN" />; магчыма, Ñго Ñертыфікат бÑÑпекі адкліканы. Прычынай могуць быць нÑÐ¿Ñ€Ð°Ð²Ñ–Ð»ÑŒÐ½Ñ‹Ñ Ð½Ð°Ð»Ð°Ð´Ñ‹ або зламыÑнік, Ñкі Ñпрабуе перахапіць падключÑнне.</translation>
<translation id="2414886740292270097">ЦёмнаÑ</translation>
<translation id="2430968933669123598">Кіраванне Уліковым запіÑам Google. Каб кіраваць параметрамі даных, прыватнаÑці Ñ– бÑÑпекі ва Уліковым запіÑе Google, націÑніце Enter</translation>
+<translation id="2436186046335138073">Дазволіць <ph name="HANDLER_HOSTNAME" /> адкрываць уÑе ÑпаÑылкі тыпу "<ph name="PROTOCOL" />"?</translation>
<translation id="2438874542388153331">Чатыры дзіркі Ñправа</translation>
<translation id="2450021089947420533">ШлÑÑ…Ñ– карыÑтальніка</translation>
<translation id="2463739503403862330">Запоўніць</translation>
@@ -478,6 +498,7 @@
<translation id="2465655957518002998">Выбраць ÑпоÑаб даÑтаўкі</translation>
<translation id="2465688316154986572">Скаба</translation>
<translation id="2465914000209955735">Кіраваць файламі, ÑÐºÑ–Ñ Ð²Ñ‹ Ñпампавалі Ñž браўзеры Chrome</translation>
+<translation id="2466004615675155314">Паказаць інфармацыю з інтÑрнÑту</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />ЗапуÑціць дыÑгноÑтыку Ñеткі<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">Парадак "ад 1 да N"</translation>
<translation id="2470767536994572628">Калі вы будзеце змÑнÑць анатацыі, гÑÑ‚Ñ‹ дакумент вернецца Ñž аднаÑтаронкавы выглÑд Ñ– прыме першапачатковую пазіцыю</translation>
@@ -498,6 +519,7 @@
<translation id="2523886232349826891">Захавана толькі на гÑтай прыладзе</translation>
<translation id="2524461107774643265">Дадаць болей звеÑтак</translation>
<translation id="2529899080962247600">МакÑÑ–Ð¼Ð°Ð»ÑŒÐ½Ð°Ñ ÐºÐ¾Ð»ÑŒÐºÐ°Ñць запіÑаў у гÑтым полі: <ph name="MAX_ITEMS_LIMIT" />. ЗапіÑÑ‹, ÑÐºÑ–Ñ Ð²Ñ‹Ð¹Ð´ÑƒÑ†ÑŒ за абмежаванне, будуць праігнараваны.</translation>
+<translation id="2535585790302968248">Ðдкрыць укладку Ñž Ñ€Ñжыме інкогніта Ð´Ð»Ñ Ð¿Ñ€Ñ‹Ð²Ð°Ñ‚Ð½Ð°Ð³Ð° праглÑду вÑб-Ñтаронак</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{Ñ– ÑÑˆÑ‡Ñ 1}one{Ñ– ÑÑˆÑ‡Ñ #}few{Ñ– ÑÑˆÑ‡Ñ #}many{Ñ– ÑÑˆÑ‡Ñ #}other{Ñ– ÑÑˆÑ‡Ñ #}}</translation>
<translation id="2536110899380797252">Дадаць адраÑ</translation>
<translation id="2539524384386349900">Ð’Ñ‹Ñвіць</translation>
@@ -523,7 +545,14 @@
<translation id="2597378329261239068">ГÑÑ‚Ñ‹ дакумент абаронены паролем. УвÑдзіце пароль.</translation>
<translation id="2609632851001447353">ВарыÑнты</translation>
<translation id="2610561535971892504">Капіруецца адным дотыкам</translation>
+<translation id="2617988307566202237">Chrome <ph name="BEGIN_EMPHASIS" />не будзе захоўваць<ph name="END_EMPHASIS" /> наÑтупную інфармацыю:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />вашу гіÑторыю праглÑду Ñайтаў;
+ <ph name="LIST_ITEM" />файлы cookie Ñ– Ð´Ð°Ð½Ñ‹Ñ Ñайтаў;
+ <ph name="LIST_ITEM" />звеÑткі, ÑÐºÑ–Ñ ÑžÐ²Ð¾Ð´Ð·Ñ–Ð»Ñ–ÑÑ Ñž формах.
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (канверт)</translation>
+<translation id="2623663032199728144">Можа запытваць дазвол на выкарыÑтанне звеÑтак пра вашы Ñкраны</translation>
<translation id="2625385379895617796">Ваш гадзіннік ÑпÑшаецца</translation>
<translation id="262745152991669301">Сайт можа запытваць дазвол на падключÑнне да прылад USB</translation>
<translation id="2629325967560697240">Каб у браўзеры Chrome падтрымліваўÑÑ Ð½Ð°Ð¹Ð²Ñ‹ÑˆÑйшы ўзровень бÑÑпекі, <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />уключыце палепшаную абарону<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -557,6 +586,7 @@
<translation id="2709516037105925701">Ðўтазапаўненне</translation>
<translation id="2713444072780614174">Белы</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />. Каб кіраваць плацÑжамі Ñ– звеÑткамі крÑдытных картак праз налады Chrome, націÑніце Tab, затым Enter</translation>
+<translation id="271663710482723385">ÐаціÑніце |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />|, каб выйÑці з поўнаÑкраннага Ñ€Ñжыму</translation>
<translation id="2721148159707890343">Запыт выкананы</translation>
<translation id="2723669454293168317">ЗапуÑціць праверку бÑÑпекі Ñž наладах Chrome</translation>
<translation id="2726001110728089263">Бакавы латок</translation>
@@ -587,6 +617,7 @@
<translation id="2850739647070081192">Invite (канверт)</translation>
<translation id="2856444702002559011">ЗламыÑнікі могуць Ñпрабаваць украÑці вашы Ð´Ð°Ð½Ñ‹Ñ Ð· Ñайта <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (напрыклад, паролі, паведамленні або Ð´Ð°Ð½Ñ‹Ñ ÐºÑ€Ñдытных картак). <ph name="BEGIN_LEARN_MORE_LINK" />Даведацца больш<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">ГÑÑ‚Ñ‹ Ñайт паказвае назойлівую Ñ€Ñкламу або Ñ€Ñкламу, ÑÐºÐ°Ñ ÑžÐ²Ð¾Ð´Ð·Ñ–Ñ†ÑŒ у зман.</translation>
+<translation id="286512204874376891">Каб абараніць Ð²Ð°Ñ Ð°Ð´ патÑнцыÑльнага махлÑÑ€Ñтва, замеÑÑ‚ захаванай вамі карткі будзе паказвацца віртуальнаÑ. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">ТаварыÑкі</translation>
<translation id="2876489322757410363">Ðдбудзецца выхад з Ñ€Ñжыму інкогніта Ð´Ð»Ñ Ð¿Ð»Ð°Ñ†Ñжу праз знешнюю праграму. ПрацÑгнуць?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />. Каб кіраваць параметрамі БÑÑпечнага праглÑду Ñ– выконваць Ñ–Ð½ÑˆÑ‹Ñ Ð´Ð·ÐµÑнні праз налады Chrome, націÑніце Tab, затым Enter</translation>
@@ -611,6 +642,7 @@
<translation id="2930577230479659665">ÐбрÑзка паÑÐ»Ñ ÐºÐ¾Ð¶Ð½Ð°Ð¹ копіі</translation>
<translation id="2932085390869194046">Прапанаваць пароль...</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019">Ðдкрыць ÑпаÑылкі <ph name="PROTOCOL" /></translation>
<translation id="2941952326391522266">Серверу не ўдалоÑÑ Ð´Ð°ÐºÐ°Ð·Ð°Ñ†ÑŒ, што гÑта <ph name="DOMAIN" />: Ñго Ñертыфікат бÑÑпекі паходзіць з <ph name="DOMAIN2" />. Прычынай могуць быць нÑÐ¿Ñ€Ð°Ð²Ñ–Ð»ÑŒÐ½Ñ‹Ñ Ð½Ð°Ð»Ð°Ð´Ñ‹ або зламыÑнік, Ñкі Ñпрабуе перахапіць падключÑнне.</translation>
<translation id="2943895734390379394">Ð§Ð°Ñ Ð·Ð°Ð¿Ð°Ð¼Ð¿Ð¾ÑžÐºÑ–:</translation>
<translation id="2948083400971632585">Ðа Ñтаронцы налад можна выключыць уÑе прокÑÑ–-Ñерверы, Ð·Ð°Ð´Ð°Ð´Ð·ÐµÐ½Ñ‹Ñ Ð´Ð»Ñ Ð¿Ð°Ð´ÐºÐ»ÑŽÑ‡ÑннÑ.</translation>
@@ -643,6 +675,7 @@
<translation id="3037605927509011580">Ð¯ÐºÐ°Ñ Ð½ÐµÑпадзÑванка!</translation>
<translation id="3041612393474885105">Ð†Ð½Ñ„Ð°Ñ€Ð¼Ð°Ñ†Ñ‹Ñ Ð°Ð± Ñертыфікаце</translation>
<translation id="3044034790304486808">ПрацÑгнуць пошук</translation>
+<translation id="305162504811187366">ГіÑторыю Ðддаленага працоўнага Ñтала Chrome, у тым ліку меткі чаÑу, хоÑÑ‚Ñ‹ Ñ– ідÑнтыфікатары ÑеанÑаў кліентаў</translation>
<translation id="3060227939791841287">C9 (канверт)</translation>
<translation id="3061707000357573562">СÑÑ€Ð²Ñ–Ñ Ð²Ñ‹Ð¿Ñ€Ð°ÑžÐ»ÐµÐ½Ð½ÑÑž</translation>
<translation id="306573536155379004">Ð“ÑƒÐ»ÑŒÐ½Ñ Ð¿Ð°Ñ‡Ð°Ð»Ð°ÑÑ.</translation>
@@ -683,6 +716,7 @@
<translation id="3197136577151645743">Сайт можа атрымліваць інфармацыю пра тое, калі вы карыÑтаецеÑÑ Ð³Ñтай прыладай</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />. Каб задаць у наладах Chrome, ÑÐºÐ°Ñ Ñ–Ð¼ÐµÐ½Ð½Ð° Ñ–Ð½Ñ„Ð°Ñ€Ð¼Ð°Ñ†Ñ‹Ñ Ð±ÑƒÐ´Ð·Ðµ Ñінхранізавацца, націÑніце Tab, затым Enter</translation>
<translation id="320323717674993345">СкаÑаваць плацеж</translation>
+<translation id="3203366800380907218">З інтÑрнÑту</translation>
<translation id="3207960819495026254">Дададзена ў закладкі</translation>
<translation id="3209034400446768650">Ðа Ñтаронцы могуць ÑпаганÑцца грошы</translation>
<translation id="3212581601480735796">Вашы дзеÑнні на <ph name="HOSTNAME" /> адÑочваюцца</translation>
@@ -699,10 +733,12 @@
<translation id="3234666976984236645">ЗаўÑёды выÑўлÑць важнае змеÑціва на гÑтым Ñайце</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />. Каб наладзіць выглÑд браўзера, націÑніце Tab, затым Enter</translation>
<translation id="3240791268468473923">Быў адкрыты аркуш, Ñкі паказваецца пры адÑутнаÑці ÑÑƒÐ¿Ð°Ð´Ð·ÐµÐ½Ð½Ñ ÑžÐ»Ñ–ÐºÐ¾Ð²Ñ‹Ñ… даных Ð´Ð»Ñ Ð±ÑÑпечных плацÑжоў</translation>
+<translation id="324180406144491771">СпаÑылкі "<ph name="HOST_NAME" />" заблакіраваны</translation>
<translation id="3249845759089040423">Стыльны</translation>
<translation id="3252266817569339921">ФранцузÑкаÑ</translation>
<translation id="3257954757204451555">Ðд каго атрымана гÑта інфармацыÑ?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />. Каб хутка Ñтварыць новую падзею Ñž Google Календары, націÑніце Tab, затым Enter</translation>
+<translation id="3261488570342242926">Даведацца больш пра Ð²Ñ–Ñ€Ñ‚ÑƒÐ°Ð»ÑŒÐ½Ñ‹Ñ ÐºÐ°Ñ€Ñ‚ÐºÑ–</translation>
<translation id="3264837738038045344">Кнопка "Кіраваць наладамі Chrome". Каб адкрыць налады Chrome, націÑніце Enter</translation>
<translation id="3266793032086590337">ЗначÑнне (канфліктуючае)</translation>
<translation id="3268451620468152448">ÐÐ´ÐºÑ€Ñ‹Ñ‚Ñ‹Ñ ÑžÐºÐ»Ð°Ð´ÐºÑ–</translation>
@@ -716,6 +752,7 @@
<translation id="3288238092761586174">Каб Ñпраўдзіць ваш плацеж, Ñайту <ph name="URL" /> можа ÑпатрÑбіцца выканаць Ð´Ð°Ð´Ð°Ñ‚ÐºÐ¾Ð²Ñ‹Ñ Ð´Ð·ÐµÑнні</translation>
<translation id="3293642807462928945">Даведацца больш пра палітыку "<ph name="POLICY_NAME" />"</translation>
<translation id="3295444047715739395">ПраглÑдаць Ñвае паролі Ñ– кіраваць імі Ñž наладах Chrome</translation>
+<translation id="3303795387212510132">Дазволіць праграме адкрываць ÑпаÑылкі <ph name="PROTOCOL_SCHEME" />?</translation>
<translation id="3303855915957856445">ÐÑма вынікаў пошуку</translation>
<translation id="3304073249511302126">пошук прылад Bluetooth</translation>
<translation id="3308006649705061278">ÐÑ€Ð³Ð°Ð½Ñ–Ð·Ð°Ñ†Ñ‹Ð¹Ð½Ð°Ñ Ð°Ð´Ð·Ñ–Ð½ÐºÐ° (ÐÐ)</translation>
@@ -729,12 +766,6 @@
<translation id="3345782426586609320">Вочы</translation>
<translation id="3355823806454867987">ЗмÑніць налады прокÑÑ–-Ñервера...</translation>
<translation id="3360103848165129075">Ðркуш апрацоўшчыка плацÑжоў</translation>
-<translation id="3361596688432910856">Chrome <ph name="BEGIN_EMPHASIS" />не будзе захоўваць<ph name="END_EMPHASIS" /> наÑтупную інфармацыю:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />вашу гіÑторыю праглÑду Ñайтаў;
- <ph name="LIST_ITEM" />файлы cookie Ñ– Ð´Ð°Ð½Ñ‹Ñ Ñайтаў;
- <ph name="LIST_ITEM" />звеÑткі, ÑÐºÑ–Ñ ÑžÐ²Ð¾Ð´Ð·Ñ–Ð»Ñ–ÑÑ Ñž формах.
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">ГÑта палітыка была аўтаматычна Ñкапіравана з ÑаÑтарÑлай палітыкі "<ph name="OLD_POLICY" />" – выкарыÑтоўвайце гÑту новую палітыку.</translation>
<translation id="3364869320075768271">Сайт <ph name="URL" /> запытвае дазвол выкарыÑтоўваць Ð´Ð°Ð½Ñ‹Ñ Ñ– прылады віртуальнай Ñ€ÑальнаÑці</translation>
<translation id="3366477098757335611">ПраглÑд картак</translation>
@@ -816,7 +847,6 @@
<translation id="3587738293690942763">СÑÑ€Ñдні</translation>
<translation id="3592413004129370115">Italian (канверт)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{Ð’Ñ‹ можаце Ñкінуць параметры Ñваёй групы Ñž любы чаÑ. ДалучÑнне да новай групы адбываецца прыблізна праз дзень.}=1{Ð’Ñ‹ можаце Ñкінуць параметры Ñваёй групы Ñž любы чаÑ. ДалучÑнне да новай групы адбываецца прыблізна праз дзень.}one{Ð’Ñ‹ можаце Ñкінуць параметры Ñваёй групы Ñž любы чаÑ. ДалучÑнне да новай групы адбываецца прыблізна праз {NUM_DAYS} дзень.}few{Ð’Ñ‹ можаце Ñкінуць параметры Ñваёй групы Ñž любы чаÑ. ДалучÑнне да новай групы адбываецца прыблізна праз {NUM_DAYS} дні.}many{Ð’Ñ‹ можаце Ñкінуць параметры Ñваёй групы Ñž любы чаÑ. ДалучÑнне да новай групы адбываецца прыблізна праз {NUM_DAYS} дзён.}other{Ð’Ñ‹ можаце Ñкінуць параметры Ñваёй групы Ñž любы чаÑ. ДалучÑнне да новай групы адбываецца прыблізна праз {NUM_DAYS} днÑ.}}</translation>
-<translation id="3596012367874587041">Ðалады праграмы</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">Праграма заблакіравана адмініÑтратарам</translation>
<translation id="3608932978122581043">ÐÑ€Ñ‹ÐµÐ½Ñ‚Ð°Ñ†Ñ‹Ñ Ð¿Ð°Ð´Ð°Ñ‡Ñ‹</translation>
@@ -859,6 +889,7 @@
<translation id="370972442370243704">Уключыць функцыю "ШлÑÑ…Ñ– карыÑтальніка"</translation>
<translation id="3711895659073496551">Прыпыненне</translation>
<translation id="3712624925041724820">ЛіцÑнзіі ÑкончыліÑÑ</translation>
+<translation id="3714633008798122362">вÑб-калÑндар</translation>
<translation id="3714780639079136834">Уключыць мабільную перадачу даных або Wi-Fi.</translation>
<translation id="3715597595485130451">ПадключÑнне да Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Праверыць прокÑÑ–-Ñервер, брандмаўÑÑ€ Ñ– канфігурацыю DNS<ph name="END_LINK" /></translation>
@@ -920,6 +951,7 @@
<translation id="3906954721959377182">ПланшÑÑ‚</translation>
<translation id="3909477809443608991"><ph name="URL" /> запытвае дазвол на прайграванне абароненага змеÑціва. Google Ñпраўдзіць ідÑнтыфікатар вашай прылады; Ñайт можа атрымаць да Ñго доÑтуп.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">Ðдмовіць</translation>
<translation id="3939773374150895049">ВыкарыÑтоўваць WebAuthn замеÑÑ‚ CVC?</translation>
<translation id="3946209740501886391">ЗаўÑёды пытацца на гÑтым Ñайце</translation>
<translation id="3947595700203588284">Сайт можа запытваць дазвол на падключÑнне да прылад MIDI</translation>
@@ -941,6 +973,7 @@
<translation id="3990250421422698716">Ð’ÐµÐ»Ñ–Ñ‡Ñ‹Ð½Ñ Ð·Ñ€ÑƒÑ…Ñƒ</translation>
<translation id="3996311196211510766">Сайт "<ph name="ORIGIN" />" патрабуе, каб на ÑžÑе запыты да Ñго раÑпаўÑюджвалаÑÑ
палітыка крыніцы, але гÑту палітыку зараз прымÑніць нельга.</translation>
+<translation id="4009243425692662128">ЗмеÑціва Ñтаронак, ÑÐºÑ–Ñ Ð²Ñ‹ друкуеце, пераÑылаецца Ð´Ð»Ñ Ð°Ð½Ð°Ð»Ñ–Ð·Ñƒ Ñž Google Cloud або ÑÑ‚Ð°Ñ€Ð¾Ð½Ð½Ñ–Ñ ÑÑрвіÑÑ‹ (напрыклад, Ð´Ð»Ñ Ð¿Ñ€Ð°Ð²ÐµÑ€ÐºÑ– на наÑўнаÑць канфідÑнцыÑльных даных).</translation>
<translation id="4010758435855888356">Дазволіць доÑтуп да Ñховішча?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{Дакумент PDF з {COUNT} Ñтаронкай}one{Дакумент PDF з {COUNT} Ñтаронкай}few{Дакумент PDF з {COUNT} Ñтаронкамі}many{Дакумент PDF з {COUNT} Ñтаронкамі}other{Дакумент PDF з {COUNT} Ñтаронкі}}</translation>
<translation id="4023431997072828269">З-за таго што форма адпраўлÑецца праз падключÑнне, Ñкое не з'ÑўлÑецца бÑÑпечным, вашы звеÑткі будуць Ð±Ð°Ñ‡Ð½Ñ‹Ñ Ñ–Ð½ÑˆÑ‹Ð¼ карыÑтальнікам.</translation>
@@ -1035,6 +1068,7 @@
<translation id="4250680216510889253">Ðе</translation>
<translation id="4253168017788158739">Ðататка</translation>
<translation id="425582637250725228">Магчыма, унеÑÐµÐ½Ñ‹Ñ Ð·Ð¼ÐµÐ½Ñ‹ не будуць захаваны.</translation>
+<translation id="425869179292622354">Ðбараніць Ñе, выкарыÑтоўваючы віртуальную картку?</translation>
<translation id="4258748452823770588">Ðедапушчальны подпіÑ</translation>
<translation id="4261046003697461417">Дадаваць анатацыі Ñž Ð°Ð±Ð°Ñ€Ð¾Ð½ÐµÐ½Ñ‹Ñ Ð´Ð°ÐºÑƒÐ¼ÐµÐ½Ñ‚Ñ‹ нельга</translation>
<translation id="4265872034478892965">Дазволена адмініÑтратарам</translation>
@@ -1097,6 +1131,7 @@
<translation id="4434045419905280838">УÑплыв. вокны Ñ– перанакіраванні</translation>
<translation id="4435702339979719576">паштоўка)</translation>
<translation id="443673843213245140">ВыкарыÑтанне прокÑÑ–-Ñервера выключана, але ÑÑžÐ½Ð°Ñ ÐºÐ°Ð½Ñ„Ñ–Ð³ÑƒÑ€Ð°Ñ†Ñ‹Ñ Ð¿Ñ€Ð¾ÐºÑÑ– вызначана.</translation>
+<translation id="4441832193888514600">Ігнаруецца, бо гÑÑ‚Ñ‹Ñ Ð¿Ñ€Ð°Ð²Ñ–Ð»Ñ‹ могуць задавацца толькі Ñк палітыка Ð´Ð»Ñ ÐºÐ°Ñ€Ñ‹Ñтальнікаў на ўзроўні воблака.</translation>
<translation id="4450893287417543264">Больш не паказваць</translation>
<translation id="4451135742916150903">Сайт можа запытваць дазвол на падключÑнне да прылад з HID</translation>
<translation id="4452328064229197696">Пароль, Ñкі вы толькі што выкарыÑталі, быў раÑкрыты пры ўцечцы даных. Каб абараніць Ñвае ÑžÐ»Ñ–ÐºÐ¾Ð²Ñ‹Ñ Ð·Ð°Ð¿Ñ–ÑÑ‹, праверце Ð·Ð°Ñ…Ð°Ð²Ð°Ð½Ñ‹Ñ Ð¿Ð°Ñ€Ð¾Ð»Ñ– Ñž Менеджары паролÑÑž Google.</translation>
@@ -1152,6 +1187,7 @@
<translation id="4628948037717959914">Фота</translation>
<translation id="4631649115723685955">З вÑртаннем грошай</translation>
<translation id="4636930964841734540">ІнфармацыÑ</translation>
+<translation id="4638670630777875591">РÑжым інкогніта Ñž браўзеры Chromium</translation>
<translation id="464342062220857295">Функцыі пошуку</translation>
<translation id="4644670975240021822">У адваротным парадку, рабочым бокам уніз</translation>
<translation id="4646534391647090355">ПерайÑці туды</translation>
@@ -1172,6 +1208,7 @@
<translation id="4708268264240856090">ПадключÑнне перапынена</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />ЗапуÑціць дыÑгноÑтыку Ñеткі Windows<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426">Пароль карыÑтальніка <ph name="USERNAME" /></translation>
<translation id="4724144314178270921">Сайт можа запытваць дазвол на праглÑд Ñ‚ÑкÑту Ñ– відарыÑаў у буферы абмену</translation>
<translation id="4726672564094551039">Перазагрузіць палітыкі</translation>
<translation id="4728558894243024398">Платформа</translation>
@@ -1193,6 +1230,7 @@
<translation id="4757993714154412917">Ð’Ñ‹ толькі што ўвÑлі Ñвой пароль на Ñайце, вÑдомым падманнымі паводзінамі. Chromium Ñ€Ñкамендуе вам праверыць Ð·Ð°Ñ…Ð°Ð²Ð°Ð½Ñ‹Ñ Ð¿Ð°Ñ€Ð¾Ð»Ñ–, каб абараніць Ñвае ÑžÐ»Ñ–ÐºÐ¾Ð²Ñ‹Ñ Ð·Ð°Ð¿Ñ–ÑÑ‹.</translation>
<translation id="4758311279753947758">Дадаць кантактную інфармацыю</translation>
<translation id="4761104368405085019">ВыкарыÑтоўваць мікрафон</translation>
+<translation id="4761869838909035636">ЗапуÑціць праверку бÑÑпекі Chrome</translation>
<translation id="4764776831041365478">Магчыма, вÑб-Ñтаронка па адраÑе <ph name="URL" /> чаÑова недаÑÑ‚ÑƒÐ¿Ð½Ð°Ñ Ð°Ð±Ð¾ была перамешчана на новы вÑб-адраÑ.</translation>
<translation id="4766713847338118463">Дзве Ñкабы знізу</translation>
<translation id="4771973620359291008">Узнікла невÑÐ´Ð¾Ð¼Ð°Ñ Ð¿Ð°Ð¼Ñ‹Ð»ÐºÐ°.</translation>
@@ -1213,12 +1251,6 @@
<translation id="4819347708020428563">ЗбіраецеÑÑ Ð·Ð¼ÑнÑць анатацыі Ñž Ñтандартным выглÑдзе?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />. Каб хутка Ñтварыць новую табліцу Google, націÑніце Tab, затым Enter</translation>
<translation id="4825507807291741242">Моцны</translation>
-<translation id="4827402517081186284">РÑжым інкогніта не робіць нÑбачнай вашу прыÑутнаÑць у інтÑрнÑце:
-<ph name="BEGIN_LIST" />
-<ph name="LIST_ITEM" />Ñайты бачаць, калі вы Ñ–Ñ… наведваеце;<ph name="END_LIST_ITEM" />
-<ph name="LIST_ITEM" />работадаўцы Ñ– Ð½Ð°Ð²ÑƒÑ‡Ð°Ð»ÑŒÐ½Ñ‹Ñ ÑžÑтановы могуць адÑочваць дзеÑнні Ñž браўзеры;<ph name="END_LIST_ITEM" />
-<ph name="LIST_ITEM" />інтÑрнÑÑ‚-правайдары могуць адÑочваць інтÑрнÑÑ‚-трафік.<ph name="END_LIST_ITEM" />
-<ph name="END_LIST" /></translation>
<translation id="483241715238664915">Уключыць папÑÑ€Ñджанні</translation>
<translation id="4838327282952368871">Летуценны</translation>
<translation id="4840250757394056958">ПраглÑдзець гіÑторыю Chrome</translation>
@@ -1230,12 +1262,12 @@
<translation id="4854362297993841467">ГÑÑ‚Ñ‹ ÑпоÑаб даÑтаўкі недаÑтупны. Выберыце іншы.</translation>
<translation id="4854853140771946034">Хутка Ñтварыць новую нататку Ñž Google Keep</translation>
<translation id="485902285759009870">Ідзе Ñпраўджанне кода…</translation>
+<translation id="4866506163384898554">ÐаціÑніце "<ph name="ACCELERATOR1" />" + "<ph name="ACCELERATOR2" />", каб убачыць курÑор</translation>
<translation id="4876188919622883022">Спрошчаны выглÑд</translation>
<translation id="4876305945144899064">ÐдÑутнічае Ñ–Ð¼Ñ ÐºÐ°Ñ€Ñ‹Ñтальніка</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{ÐÑма}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}one{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}few{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}many{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831">Пошук па запыце "<ph name="TEXT" />"</translation>
<translation id="4879491255372875719">Ðўтаматычна (Ñтандартна)</translation>
-<translation id="4879725228911483934">Ðдкрываць Ñ– размÑшчаць вокны на Ñкранах.</translation>
<translation id="4880827082731008257">ГіÑÑ‚Ð¾Ñ€Ñ‹Ñ Ð¿Ð¾ÑˆÑƒÐºÑƒ</translation>
<translation id="4881695831933465202">Ðдкрыць</translation>
<translation id="4885256590493466218">Ðплаціць карткай <ph name="CARD_DETAIL" /> пры афармленні заказу</translation>
@@ -1244,6 +1276,7 @@
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">ДзÑвÑÑ‚Ñ‹ рулон</translation>
<translation id="4901778704868714008">Захаваць...</translation>
+<translation id="4905659621780993806">ÐдмініÑтратар аўтаматычна перазапуÑціць прыладу Ñž <ph name="TIME" /> <ph name="DATE" />. Захавайце перад перазапуÑкам прылады ÑžÑÑ‘, што вы адкрылі.</translation>
<translation id="4913987521957242411">Дзірка зверху злева</translation>
<translation id="4918221908152712722">УÑталюйце праграму "<ph name="APP_NAME" />" (Ñпампоўка не патрабуецца)</translation>
<translation id="4923459931733593730">Плацеж</translation>
@@ -1252,6 +1285,7 @@
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, Ð´Ð»Ñ Ð¿Ð¾ÑˆÑƒÐºÑƒ націÑніце Tab, затым Enter</translation>
<translation id="4930153903256238152">Ð’ÑÐ»Ñ–ÐºÐ°Ñ Ñ‘Ð¼Ñ–ÑтаÑць</translation>
+<translation id="4940163644868678279">РÑжым інкогніта Ñž браўзеры Chrome</translation>
<translation id="4943872375798546930">ÐÑма вынікаў</translation>
<translation id="4950898438188848926">Кнопка пераключÑÐ½Ð½Ñ ÑžÐºÐ»Ð°Ð´Ð°Ðº. ÐаціÑніце Enter, каб пераключыцца на адкрытую ўкладку, <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="495170559598752135">ДзеÑнні</translation>
@@ -1261,6 +1295,7 @@
<translation id="4968522289500246572">ГÑта праграма Ñтворана Ð´Ð»Ñ Ð¼Ð°Ð±Ñ–Ð»ÑŒÐ½Ñ‹Ñ… прылад, таму змÑненне Ñе памеру можа выклікаць памылкі. Праграма можа працаваць нÑправільна або перазапуÑціцца.</translation>
<translation id="4969341057194253438">Выдаліць запіÑ</translation>
<translation id="4973922308112707173">Дзве дзіркі зверху</translation>
+<translation id="4976702386844183910">ÐпошнÑе наведванне: <ph name="DATE" /></translation>
<translation id="4984088539114770594">ВыкарыÑтоўваць мікрафон?</translation>
<translation id="4984339528288761049">Prc5 (канверт)</translation>
<translation id="4989163558385430922">Паказаць уÑе</translation>
@@ -1322,6 +1357,7 @@
<translation id="5138227688689900538">Паказаць менш</translation>
<translation id="5145883236150621069">Код памылкі, указаны ў адказе, атрыманым ад палітыкі</translation>
<translation id="5146995429444047494">ÐпавÑшчÑнні Ð´Ð»Ñ <ph name="ORIGIN" /> заблакіраваны</translation>
+<translation id="514704532284964975">Сайт <ph name="URL" /> запытвае дазвол праглÑдаць Ñ– змÑнÑць інфармацыю на прыладах NFC, да Ñкіх вы дакранаецеÑÑ Ñ‚Ñлефонам</translation>
<translation id="5148809049217731050">Рабочым бокам уверх</translation>
<translation id="515292512908731282">C4 (канверт)</translation>
<translation id="5158275234811857234">Вокладка</translation>
@@ -1346,6 +1382,7 @@
<translation id="5215116848420601511">СпоÑабы аплаты Ñ– адраÑÑ‹, ÑÐºÑ–Ñ Ð²Ñ‹ÐºÐ°Ñ€Ñ‹Ñтоўваюць Google Pay</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">Латок 13</translation>
+<translation id="5216942107514965959">ÐпошнÑе наведванне: ÑённÑ</translation>
<translation id="5222812217790122047">Электронны Ð°Ð´Ñ€Ð°Ñ (абавÑзкова)</translation>
<translation id="5230733896359313003">ÐÐ´Ñ€Ð°Ñ Ð´Ð°Ñтаўкі</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1366,7 +1403,6 @@
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">Параметры дакумента</translation>
<translation id="528468243742722775">Канец</translation>
-<translation id="5284909709419567258">Ð¡ÐµÑ‚ÐºÐ°Ð²Ñ‹Ñ Ð°Ð´Ñ€Ð°ÑÑ‹</translation>
<translation id="5285570108065881030">Паказваць уÑе Ð·Ð°Ñ…Ð°Ð²Ð°Ð½Ñ‹Ñ Ð¿Ð°Ñ€Ð¾Ð»Ñ–</translation>
<translation id="5287240709317226393">Паказаць файлы cookie</translation>
<translation id="5287456746628258573">ГÑÑ‚Ñ‹ Ñайт выкарыÑтоўвае ÑаÑтарÑлую канфігурацыю бÑÑпекі, таму звеÑткі пра Ð²Ð°Ñ (напрыклад, паролі або нумары крÑдытных картак) пры Ñ–Ñ… адпраўцы на гÑÑ‚Ñ‹ Ñайт могуць быць раÑкрыты.</translation>
@@ -1450,6 +1486,7 @@
<translation id="5556459405103347317">Перазагрузіць</translation>
<translation id="5560088892362098740">ЗаканчÑнне Ñ‚Ñрміну дзеÑннÑ</translation>
<translation id="55635442646131152">Структура дакумента</translation>
+<translation id="5565613213060953222">Ðдкрыць укладку Ñž Ñ€Ñжыме інкогніта</translation>
<translation id="5565735124758917034">Ðктыўны</translation>
<translation id="5570825185877910964">Ðбараніць уліковы запіÑ</translation>
<translation id="5571083550517324815">З гÑтага адраÑа забраць нельга – выберыце іншы.</translation>
@@ -1532,6 +1569,7 @@
<translation id="5869522115854928033">Ð—Ð°Ñ…Ð°Ð²Ð°Ð½Ñ‹Ñ Ð¿Ð°Ñ€Ð¾Ð»Ñ–</translation>
<translation id="5873013647450402046">Ваш банк хоча пацвердзіць, што гÑта вы.</translation>
<translation id="5887400589839399685">Картка захавана</translation>
+<translation id="5887687176710214216">ÐпошнÑе наведванне: учора</translation>
<translation id="5895138241574237353">ПеразапуÑціць</translation>
<translation id="5895187275912066135">Выдадзены</translation>
<translation id="5901630391730855834">Жоўты</translation>
@@ -1545,6 +1583,7 @@
<translation id="5921639886840618607">Захаваць картку ва Уліковы Ð·Ð°Ð¿Ñ–Ñ Google?</translation>
<translation id="5922853866070715753">Ðмаль гатова</translation>
<translation id="5932224571077948991">Сайт паказвае назойлівую Ñ€Ñкламу або Ñ€Ñкламу, ÑÐºÐ°Ñ ÑžÐ²Ð¾Ð´Ð·Ñ–Ñ†ÑŒ у зман</translation>
+<translation id="5938153366081463283">Дадаць віртуальную картку</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347">Ðдкрываецца <ph name="SITE_NAME" />…</translation>
<translation id="5951495562196540101">Ðе ўдалоÑÑ Ð·Ð°Ñ€ÑгіÑтраваць з дапамогай уліковага запіÑу Ñпажыўца (даÑтупна Ð¿Ð°ÐºÐµÑ‚Ð½Ð°Ñ Ð»Ñ–Ñ†ÑнзіÑ).</translation>
@@ -1609,6 +1648,7 @@
<translation id="6120179357481664955">Запомніць ідÑнтыфікатар UPI?</translation>
<translation id="6124432979022149706">Злучальнікі Chrome Enterprise</translation>
<translation id="6127379762771434464">Элемент выдалены</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Даведацца больш пра Ñ€Ñжым інкогніта Ñž браўзеры Chrome<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">Праверце кабелі Ñ– перазагрузіце маршрутызатары, мадÑмы або Ñ–Ð½ÑˆÑ‹Ñ ÑеткавыÑ
прылады, ÑÐºÑ–Ñ Ð²Ñ‹ÐºÐ°Ñ€Ñ‹Ñтоўваеце.</translation>
<translation id="614940544461990577">ПаÑпрабуйце наÑтупнае:</translation>
@@ -1621,7 +1661,6 @@
<translation id="6169916984152623906">ЦÑпер вы можаце праглÑдаць вÑб-Ñтаронкі Ñž прыватным Ñ€Ñжыме, Ñ–Ð½ÑˆÑ‹Ñ ÐºÐ°Ñ€Ñ‹Ñтальнікі гÑтай прылады не будуць бачыць вашы дзеÑнні. Ðднак Ñпампоўкі Ñ– закладкі будуць захоўвацца.</translation>
<translation id="6177128806592000436">Ваша падключÑнне да гÑтага Ñайта небÑÑпечнае</translation>
<translation id="6180316780098470077">ІнтÑрвал паміж Ñпробамі</translation>
-<translation id="619448280891863779">Сайт можа запытваць дазвол адкрываць Ñ– размÑшчаць вокны на Ñкранах</translation>
<translation id="6196640612572343990">Блакіраваць ÑÑ‚Ð°Ñ€Ð¾Ð½Ð½Ñ–Ñ Ñ„Ð°Ð¹Ð»Ñ‹ cookie</translation>
<translation id="6203231073485539293">Праверце падключÑнне да інтÑрнÑту</translation>
<translation id="6218753634732582820">Выдаліць Ð°Ð´Ñ€Ð°Ñ Ð· Chromium?</translation>
@@ -1644,7 +1683,7 @@
<translation id="6272383483618007430">Ðбнаўленне Google</translation>
<translation id="6276112860590028508">Старонкі Ñа ÑпіÑа Ñ‡Ñ‹Ñ‚Ð°Ð½Ð½Ñ Ð·'ÑвÑцца тут</translation>
<translation id="627746635834430766">Каб наÑтупны раз плаціць хутчÑй, захавайце картку Ñ– Ð°Ð´Ñ€Ð°Ñ Ð´Ð»Ñ Ð²Ñ‹ÑÑ‚Ð°ÑžÐ»ÐµÐ½Ð½Ñ Ñ€Ð°Ñ…ÑƒÐ½ÐºÐ°Ñž ва Уліковым запіÑе Google.</translation>
-<translation id="6279098320682980337">Ðе ўказаны нумар віртуальнай карткі? Скапіруйце Ñ€Ñквізіты карткі, націÑнуўшы на Ñ–Ñ…</translation>
+<translation id="6279183038361895380">ÐаціÑніце "<ph name="ACCELERATOR" />", каб убачыць курÑор</translation>
<translation id="6280223929691119688">Ðемагчыма адправіць на гÑÑ‚Ñ‹ адраÑ. Выберыце іншы адраÑ.</translation>
<translation id="6282194474023008486">Паштовы індÑкÑ</translation>
<translation id="6285507000506177184">Кнопка "Кіраваць Ñпампоўкамі Ñž Chrome". Каб кіраваць файламі, ÑÐºÑ–Ñ Ð²Ñ‹ Ñпампавалі Ñž браўзеры Chrome, націÑніце Enter</translation>
@@ -1652,6 +1691,7 @@
<translation id="6290238015253830360">РÑÐºÐ°Ð¼ÐµÐ½Ð´Ð°Ð²Ð°Ð½Ñ‹Ñ Ð²Ð°Ð¼ артыкулы з'ÑвÑцца тут</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{Прылада будзе перазапушчана зараз}=1{Прылада будзе перазапушчана праз 1 Ñекунду}one{Прылада будзе перазапушчана праз # Ñекунду}few{Прылада будзе перазапушчана праз # Ñекунды}many{Прылада будзе перазапушчана праз # Ñекунд}other{Прылада будзе перазапушчана праз # Ñекунды}}</translation>
<translation id="6302269476990306341">Памочнік Google у Chrome ÑпынÑецца</translation>
<translation id="6305205051461490394">Сайт <ph name="URL" /> недаÑтупны.</translation>
<translation id="6312113039770857350">Ð’Ñб-Ñтаронка недаÑтупнаÑ</translation>
@@ -1725,6 +1765,7 @@
<translation id="6529602333819889595">&amp;Узнавіць выдаленне</translation>
<translation id="6545864417968258051">Пошук прылад Bluetooth</translation>
<translation id="6547208576736763147">Дзве дзіркі злева</translation>
+<translation id="6554732001434021288">ÐпошнÑе наведванне: <ph name="NUM_DAYS" /> Ñут таму</translation>
<translation id="6556866813142980365">Узнавіць</translation>
<translation id="6569060085658103619">Ð’Ñ‹ праглÑдаеце Ñтаронку пашырÑннÑ</translation>
<translation id="6573200754375280815">Дзве дзіркі Ñправа</translation>
@@ -1785,7 +1826,6 @@
<translation id="6757797048963528358">Прылада перайшла Ñž Ñ€Ñжым Ñну.</translation>
<translation id="6767985426384634228">Ðбнавіць адраÑ?</translation>
<translation id="6768213884286397650">Hagaki (паштоўка)</translation>
-<translation id="6774185088257932239"><ph name="BEGIN_LINK" />Даведацца больш<ph name="END_LINK" /> пра Ñ€Ñжым інкогніта</translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">ФіÑлетавы</translation>
<translation id="6786747875388722282">ПашырÑнні</translation>
@@ -1869,7 +1909,6 @@
<translation id="706295145388601875">Дадавайце адраÑÑ‹ Ñ– кіруйце імі праз налады Chrome</translation>
<translation id="7064851114919012435">ÐšÐ°Ð½Ñ‚Ð°ÐºÑ‚Ð½Ð°Ñ Ñ–Ð½Ñ„Ð°Ñ€Ð¼Ð°Ñ†Ñ‹Ñ</translation>
<translation id="7068733155164172741">УвÑдзіце <ph name="OTP_LENGTH" />-значны код</translation>
-<translation id="7070090581017165256">Ð†Ð½Ñ„Ð°Ñ€Ð¼Ð°Ñ†Ñ‹Ñ Ð¿Ñ€Ð° гÑÑ‚Ñ‹ Ñайт</translation>
<translation id="70705239631109039">Ваша падключÑнне не цалкам бÑÑпечнае</translation>
<translation id="7075452647191940183">Запыт занадта вÑлікі</translation>
<translation id="7079718277001814089">ГÑÑ‚Ñ‹ Ñайт змÑшчае шкоднае ПЗ</translation>
@@ -1886,6 +1925,12 @@
<translation id="7111012039238467737">(Сапраўдны)</translation>
<translation id="7118618213916969306">Пошук URL-адраÑа з буфера абмену: <ph name="SHORT_URL" /></translation>
<translation id="7119414471315195487">Закрыйце Ñ–Ð½ÑˆÑ‹Ñ ÑžÐºÐ»Ð°Ð´ÐºÑ– або праграмы</translation>
+<translation id="7129355289156517987">Пры закрыцці ÑžÑÑ–Ñ… укладак, адкрытых у Ñ€Ñжыме інкогніта Ñž браўзеры Chromium, з гÑтай прылады выдалÑюцца Ð´Ð°Ð½Ñ‹Ñ Ð¿Ñ€Ð° ÑžÑе вашы дзеÑнні Ñž гÑÑ‚Ñ‹Ñ… укладках:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />дзеÑнні Ñž браўзеры;<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />гіÑÑ‚Ð¾Ñ€Ñ‹Ñ Ð¿Ð¾ÑˆÑƒÐºÑƒ;<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />звеÑткі, ÑÐºÑ–Ñ Ð±Ñ‹Ð»Ñ– ўведзены Ñž формах.<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">Ðдпраўка на гÑÑ‚Ñ‹ Ð°Ð´Ñ€Ð°Ñ Ð½ÐµÐ¼Ð°Ð³Ñ‡Ñ‹Ð¼Ð°Ñ. Выберыце іншы адраÑ.</translation>
<translation id="7132939140423847331">Ваш адмініÑтратар забараніў капіраванне гÑÑ‚Ñ‹Ñ… даных.</translation>
<translation id="7135130955892390533">Паказаць Ñтан</translation>
@@ -1908,6 +1953,7 @@
<translation id="7192203810768312527">Вызваліцца <ph name="SIZE" />. ÐÐµÐºÐ°Ñ‚Ð¾Ñ€Ñ‹Ñ Ñайты могуць загружацца павальней пры наÑтупным наведванні.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">Ваш адмініÑтратар можа бачыць:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />. Каб адкрыць новую ўкладку Ñž Ñ€Ñжыме інкогніта Ð´Ð»Ñ Ð¿Ñ€Ñ‹Ð²Ð°Ñ‚Ð½Ð°Ð³Ð° праглÑду вÑб-Ñтаронак, націÑніце Tab, затым Увод</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> не адпавÑдае Ñтандартам бÑÑпекі.</translation>
<translation id="7210993021468939304">ДзеÑнні Linux у кантÑйнеры, а такÑама ÑžÑталёўка Ñ– запуÑк праграм Linux у кантÑйнеры</translation>
@@ -1939,6 +1985,7 @@
<translation id="7304562222803846232">Кіраваць наладамі прыватнаÑці Уліковага запіÑу Google</translation>
<translation id="7305756307268530424">ЗапуÑціць павальней</translation>
<translation id="7308436126008021607">Ñ„Ð¾Ð½Ð°Ð²Ð°Ñ ÑінхранізацыÑ</translation>
+<translation id="7310392214323165548">Скора прылада перазапуÑціцца</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">Даведка па падключÑнні</translation>
<translation id="7323804146520582233">Схаваць раздзел "<ph name="SECTION" />"</translation>
@@ -1946,6 +1993,7 @@
<translation id="7334320624316649418">&amp;Паўтарыць змÑненне парадку</translation>
<translation id="7335157162773372339">Сайт можа запытваць дазвол на выкарыÑтанне мікрафона</translation>
<translation id="7337248890521463931">Паказваць больш радкоў</translation>
+<translation id="7337418456231055214">Ðе ўказаны нумар віртуальнай карткі? Скапіруйце Ñ€Ñквізіты карткі, націÑнуўшы на Ñ–Ñ…. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">ÐедаÑтупна на вашай платформе.</translation>
<translation id="733923710415886693">Сертыфікат Ñервера не быў раÑкрыты Ñž адпаведнаÑці Ñа Ñтандартам "ПразрыÑтаÑць Ñертыфікатаў".</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1968,6 +2016,7 @@
<translation id="7378627244592794276">РвоÑÑŒ i не!</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">ÐедаÑтаÑоўна</translation>
+<translation id="7388594495505979117">{0,plural, =1{Прылада будзе перазапушчана праз 1 хвіліну}one{Прылада будзе перазапушчана праз # хвіліну}few{Прылада будзе перазапушчана праз # хвіліны}many{Прылада будзе перазапушчана праз # хвілін}other{Прылада будзе перазапушчана праз # хвіліны}}</translation>
<translation id="7390545607259442187">Пацвердзіце картку</translation>
<translation id="7392089738299859607">Ðбнавіць адраÑ</translation>
<translation id="7399802613464275309">Праверка бÑÑпекі</translation>
@@ -2005,6 +2054,12 @@
<translation id="7485870689360869515">Ð”Ð°Ð½Ñ‹Ñ Ð½Ðµ знойдзены.</translation>
<translation id="7495528107193238112">ГÑта змеÑціва заблакіравана. Каб вырашыць праблему, звÑрніцеÑÑ Ð´Ð° ўладальніка Ñайта.</translation>
<translation id="7497998058912824456">Кнопка "Стварыць дакумент". Каб хутка Ñтварыць новы дакумент Google, націÑніце Enter</translation>
+<translation id="7506488012654002225">Chromium <ph name="BEGIN_EMPHASIS" />не будзе захоўваць<ph name="END_EMPHASIS" /> наÑтупную інфармацыю:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />вашу гіÑторыю праглÑду Ñайтаў;
+ <ph name="LIST_ITEM" />файлы cookie Ñ– Ð´Ð°Ð½Ñ‹Ñ Ñайтаў;
+ <ph name="LIST_ITEM" />звеÑткі, ÑÐºÑ–Ñ ÑžÐ²Ð¾Ð´Ð·Ñ–Ð»Ñ–ÑÑ Ñž формах.
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">Ðтрыманы з палітыкі ідÑнтыфікатар прылады пуÑÑ‚Ñ‹ або не Ñупадае з бÑгучым ідÑнтыфікатарам прылады</translation>
<translation id="7508870219247277067">Цёмна-зÑлёны</translation>
<translation id="7511955381719512146">Wi-Fi-Ñетка, Ñкую вы выкарыÑтоўваеце, можа запатрабаваць ад Ð²Ð°Ñ Ð½Ð°Ð²ÐµÐ´Ð°Ñ†ÑŒ <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
@@ -2118,7 +2173,6 @@
<translation id="7813600968533626083">Выдаліць прапанову Ð°ÑžÑ‚Ð°Ð·Ð°Ð¿Ð°ÑžÐ½ÐµÐ½Ð½Ñ Ñ„Ð¾Ñ€Ð¼ з Chrome?</translation>
<translation id="781440967107097262">Ðбагуліць змеÑціва буфера абмену?</translation>
<translation id="7815407501681723534"><ph name="SEARCH_RESULTS" />: знойдзена <ph name="NUMBER_OF_RESULTS" /> па запыце "<ph name="SEARCH_STRING" />"</translation>
-<translation id="782125616001965242">Паказаць інфармацыю пра гÑÑ‚Ñ‹ Ñайт</translation>
<translation id="782886543891417279">Сетка Wi-Fi, Ñкую вы выкарыÑтоўваеце (<ph name="WIFI_NAME" />), можа запатрабаваць ад Ð²Ð°Ñ Ð½Ð°Ð²ÐµÐ´Ð°Ñ†ÑŒ Ñе Ñтаронку ўваходу.</translation>
<translation id="7836231406687464395">Postfix (канверт)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{ÐÑма}=1{1 праграма (<ph name="EXAMPLE_APP_1" />)}=2{2 праграмы (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}one{# праграма (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}few{# праграмы (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}many{# праграм (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}other{# праграмы (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}}</translation>
@@ -2135,7 +2189,6 @@
<translation id="7888575728750733395">Ðамер візуалізацыі раздрукоўкі</translation>
<translation id="7894280532028510793">Калі напіÑанне правільнае, <ph name="BEGIN_LINK" />паÑпрабуйце запуÑціць дыÑгноÑтыку Ñеткі<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (канверт)</translation>
-<translation id="7931318309563332511">ÐевÑдома</translation>
<translation id="793209273132572360">Ðбнавіць адраÑ?</translation>
<translation id="7932579305932748336">Пакрыццё</translation>
<translation id="79338296614623784">УвÑдзіце Ñапраўдны нумар Ñ‚Ñлефона</translation>
@@ -2160,13 +2213,14 @@
<translation id="7976214039405368314">Занадта шмат запытаў</translation>
<translation id="7977538094055660992">Прылада вываду</translation>
<translation id="7977894662897852582">EDP</translation>
+<translation id="7981260203882740562">Картка звÑзана з наÑтупнай карткай:</translation>
<translation id="798134797138789862">Сайт можа запытваць дазвол на выкарыÑтанне даных Ñ– прылад віртуальнай Ñ€ÑальнаÑці</translation>
<translation id="7984945080620862648">Ð’Ñ‹ не можаце адкрыць вÑб-Ñайт <ph name="SITE" />, бо ён адправіў Ð·Ð°ÑˆÑ‹Ñ„Ñ€Ð°Ð²Ð°Ð½Ñ‹Ñ ÑžÐ»Ñ–ÐºÐ¾Ð²Ñ‹Ñ Ð´Ð°Ð½Ñ‹Ñ, ÑÐºÑ–Ñ Chrome не можа апрацаваць. Звычайна памылкі Ñеткі Ñ– атакі – чаÑÐ¾Ð²Ð°Ñ Ð·'Ñва, таму гÑта Ñтаронка будзе, хутчÑй за ÑžÑÑ‘, працаваць пазней.</translation>
-<translation id="79859296434321399">Каб праглÑдаць змеÑціва Ñž Ñ€Ñжыме дапоўненай Ñ€ÑальнаÑці, уÑталюйце ARCore</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">Пераплёт</translation>
<translation id="7992044431894087211"><ph name="APPLICATION_TITLE" /> зноў абагульвае Ñкран</translation>
<translation id="7995512525968007366">Ðе вызначана</translation>
+<translation id="7998269595945679889">Кнопка "Ðдкрыць укладку Ñž Ñ€Ñжыме інкогніта". Каб адкрыць новую ўкладку Ñž Ñ€Ñжыме інкогніта Ð´Ð»Ñ Ð¿Ñ€Ñ‹Ð²Ð°Ñ‚Ð½Ð°Ð³Ð° праглÑду вÑб-Ñтаронак, націÑніце Увод</translation>
<translation id="800218591365569300">Каб вызваліць памÑць, закрыйце Ñ–Ð½ÑˆÑ‹Ñ ÑžÐºÐ»Ð°Ð´ÐºÑ– або праграмы.</translation>
<translation id="8004582292198964060">Браўзер</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{ГÑта картка Ñ– Ñе Ð°Ð´Ñ€Ð°Ñ Ð´Ð»Ñ Ð²Ñ‹ÑÑ‚Ð°ÑžÐ»ÐµÐ½Ð½Ñ Ñ€Ð°Ñ…ÑƒÐ½ÐºÐ°Ñž будуць захаваны. Ð’Ñ‹ зможаце карыÑтацца Ñ‘ÑŽ, калі ўвойдзеце ва ўліковы Ð·Ð°Ð¿Ñ–Ñ <ph name="USER_EMAIL" />.}one{ГÑÑ‚Ñ‹Ñ ÐºÐ°Ñ€Ñ‚ÐºÑ– Ñ– Ñ–Ñ… адраÑÑ‹ Ð´Ð»Ñ Ð²Ñ‹ÑÑ‚Ð°ÑžÐ»ÐµÐ½Ð½Ñ Ñ€Ð°Ñ…ÑƒÐ½ÐºÐ°Ñž будуць захаваны. Ð’Ñ‹ зможаце карыÑтацца імі, калі ўвойдзеце ва ўліковы Ð·Ð°Ð¿Ñ–Ñ <ph name="USER_EMAIL" />.}few{ГÑÑ‚Ñ‹Ñ ÐºÐ°Ñ€Ñ‚ÐºÑ– Ñ– Ñ–Ñ… адраÑÑ‹ Ð´Ð»Ñ Ð²Ñ‹ÑÑ‚Ð°ÑžÐ»ÐµÐ½Ð½Ñ Ñ€Ð°Ñ…ÑƒÐ½ÐºÐ°Ñž будуць захаваны. Ð’Ñ‹ зможаце карыÑтацца імі, калі ўвойдзеце ва ўліковы Ð·Ð°Ð¿Ñ–Ñ <ph name="USER_EMAIL" />.}many{ГÑÑ‚Ñ‹Ñ ÐºÐ°Ñ€Ñ‚ÐºÑ– Ñ– Ñ–Ñ… адраÑÑ‹ Ð´Ð»Ñ Ð²Ñ‹ÑÑ‚Ð°ÑžÐ»ÐµÐ½Ð½Ñ Ñ€Ð°Ñ…ÑƒÐ½ÐºÐ°Ñž будуць захаваны. Ð’Ñ‹ зможаце карыÑтацца імі, калі ўвойдзеце ва ўліковы Ð·Ð°Ð¿Ñ–Ñ <ph name="USER_EMAIL" />.}other{ГÑÑ‚Ñ‹Ñ ÐºÐ°Ñ€Ñ‚ÐºÑ– Ñ– Ñ–Ñ… адраÑÑ‹ Ð´Ð»Ñ Ð²Ñ‹ÑÑ‚Ð°ÑžÐ»ÐµÐ½Ð½Ñ Ñ€Ð°Ñ…ÑƒÐ½ÐºÐ°Ñž будуць захаваны. Ð’Ñ‹ зможаце карыÑтацца імі, калі ўвойдзеце ва ўліковы Ð·Ð°Ð¿Ñ–Ñ <ph name="USER_EMAIL" />.}}</translation>
@@ -2226,6 +2280,7 @@
<translation id="8202370299023114387">Канфлікт</translation>
<translation id="8206978196348664717">Prc4 (канверт)</translation>
<translation id="8211406090763984747">ПадключÑнне бÑÑпечнае</translation>
+<translation id="8217240300496046857">Сайты не могуць выкарыÑтоўваць файлы cookie Ð´Ð»Ñ Ð°Ð´ÑÐ¾Ñ‡Ð²Ð°Ð½Ð½Ñ Ð²Ð°Ñ Ñƒ інтÑрнÑце. Ðа некаторых Ñайтах можа пераÑтаць працаваць чаÑтка функцый.</translation>
<translation id="8218327578424803826">Прызначанае меÑцазнаходжанне:</translation>
<translation id="8220146938470311105">C7/C6 (канверт)</translation>
<translation id="8225771182978767009">КарыÑтальнік, Ñкі наладжваў гÑÑ‚Ñ‹ камп'ютар, вырашыў заблакіраваць гÑÑ‚Ñ‹ Ñайт.</translation>
@@ -2266,14 +2321,9 @@
<translation id="830498451218851433">Згіб напалову</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">УÑталÑÐ²Ð°Ð½Ñ‹Ñ Ð¿Ñ€Ð°Ð³Ñ€Ð°Ð¼Ñ‹, Ñ– Ñк чаÑта Ñны выкарыÑтоўваліÑÑ</translation>
+<translation id="8317207217658302555">Ðбнавіць ARCore?</translation>
<translation id="831997045666694187">Вечар</translation>
<translation id="8321476692217554900">апавÑшчÑнні</translation>
-<translation id="8328484624016508118">ПаÑÐ»Ñ Ð·Ð°ÐºÑ€Ñ‹Ñ†Ñ†Ñ ÑžÑÑ–Ñ… укладак у Ñ€Ñжыме інкогніта, Chrome выдаліць:
-<ph name="BEGIN_LIST" />
-<ph name="LIST_ITEM" />Ð´Ð°Ð½Ñ‹Ñ Ð¿Ñ€Ð° дзеÑнні Ñž браўзеры, Ð°Ð¶Ñ‹Ñ†Ñ†Ñ‘ÑžÐ»ÐµÐ½Ñ‹Ñ Ð½Ð° гÑтай прыладзе;<ph name="END_LIST_ITEM" />
-<ph name="LIST_ITEM" />гіÑторыю пошуку з гÑтай прылады;<ph name="END_LIST_ITEM" />
-<ph name="LIST_ITEM" />звеÑткі, ÑƒÐ²ÐµÐ´Ð·ÐµÐ½Ñ‹Ñ Ñž формах.<ph name="END_LIST_ITEM" />
-<ph name="END_LIST" /></translation>
<translation id="8332188693563227489">ДоÑтуп да хоÑта <ph name="HOST_NAME" /> забаронены</translation>
<translation id="833262891116910667">ВылучÑнне</translation>
<translation id="8339163506404995330">Старонкі на мове <ph name="LANGUAGE" /> не будуць перакладацца</translation>
@@ -2325,6 +2375,7 @@
<translation id="8507227106804027148">Камандны радок</translation>
<translation id="8508648098325802031">Значок пошуку</translation>
<translation id="8511402995811232419">Кіраваць файламі cookie</translation>
+<translation id="8519753333133776369">ÐдмініÑтратар дазволіў выкарыÑтанне гÑтай прылады HID</translation>
<translation id="8522552481199248698">Chrome можа дапамагчы абараніць Уліковы Ð·Ð°Ð¿Ñ–Ñ Google Ñ– змÑніць ваш пароль.</translation>
<translation id="8530813470445476232">Выдаліць гіÑторыю праглÑду Ñайтаў, файлы cookie, кÑшаванае змеÑціва Ñ– іншае праз налады Chrome</translation>
<translation id="8533619373899488139">Каб прагледзець ÑÐ¿Ñ–Ñ Ð·Ð°Ð±Ð»Ð°ÐºÑ–Ñ€Ð°Ð²Ð°Ð½Ñ‹Ñ… URL-адраÑоў Ñ– Ñ–Ð½ÑˆÑ‹Ñ Ð¿Ð°Ð»Ñ–Ñ‚Ñ‹ÐºÑ–, Ñкімі кіруе ÑÑ–ÑÑ‚Ñмны адмініÑтратар, наведайце &lt;strong&gt;chrome://policy&lt;/strong&gt;.</translation>
@@ -2336,7 +2387,6 @@
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{Скінуць дазвол}one{Скінуць дазволы}few{Скінуць дазволы}many{Скінуць дазволы}other{Скінуць дазволы}}</translation>
<translation id="8555010941760982128">ВыкарыÑтайце гÑÑ‚Ñ‹ код пры афармленні заказу</translation>
<translation id="8557066899867184262">CVC знаходзіцца на адвароце карткі.</translation>
-<translation id="8558485628462305855">Каб праглÑдаць змеÑціва Ñž Ñ€Ñжыме дапоўненай Ñ€ÑальнаÑці, абнавіце ARCore</translation>
<translation id="8559762987265718583">Памылка прыватнага падключÑÐ½Ð½Ñ Ð´Ð° дамена <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />: дата Ñ– Ñ‡Ð°Ñ Ð½Ð° вашай прыладзе (<ph name="DATE_AND_TIME" />) нÑправільныÑ.</translation>
<translation id="8564182942834072828">ÐÑÐ¾Ð±Ð½Ñ‹Ñ Ð´Ð°ÐºÑƒÐ¼ÐµÐ½Ñ‚Ñ‹, Ð½ÐµÑ€Ð°Ð·Ð°Ð±Ñ€Ð°Ð½Ñ‹Ñ ÐºÐ¾Ð¿Ñ–Ñ–</translation>
<translation id="8564985650692024650">Chromium Ñ€Ñкамендуе Ñкінуць пароль <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" />, калі вы карыÑталіÑÑ Ñ–Ð¼ на іншых Ñайтах.</translation>
@@ -2355,6 +2405,7 @@
<translation id="865032292777205197">датчыкі руху</translation>
<translation id="8663226718884576429">Зводка па заказе, <ph name="TOTAL_LABEL" />, Ð´Ð°Ð´Ð°Ñ‚ÐºÐ¾Ð²Ð°Ñ Ñ–Ð½Ñ„Ð°Ñ€Ð¼Ð°Ñ†Ñ‹Ñ</translation>
<translation id="8666678546361132282">ÐнглійÑкаÑ</translation>
+<translation id="8669306706049782872">ВыкарыÑтоўваць звеÑткі пра Ñкраны, каб адкрываць Ñ– размÑшчаць вокны.</translation>
<translation id="867224526087042813">ПодпіÑ</translation>
<translation id="8676424191133491403">Без затрымкі</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, адказ, <ph name="ANSWER" /></translation>
@@ -2381,6 +2432,7 @@
<translation id="8731544501227493793">Кнопка "Кіраваць паролÑмі". Каб паглÑдзець паролі або кіраваць імі Ñž наладах Chrome, націÑніце Enter</translation>
<translation id="8734529307927223492">Вашай прыладай <ph name="DEVICE_TYPE" /> кіруе <ph name="MANAGER" />.</translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />. Каб адкрыць новае акно Ñž Ñ€Ñжыме інкогніта Ð´Ð»Ñ Ð¿Ñ€Ñ‹Ð²Ð°Ñ‚Ð½Ð°Ð³Ð° праглÑду вÑб-Ñайтаў, націÑніце Tab, затым Enter</translation>
+<translation id="8737685506611670901">Ðдкрываць ÑпаÑылкі <ph name="PROTOCOL" /> замеÑÑ‚ <ph name="REPLACED_HANDLER_TITLE" /></translation>
<translation id="8738058698779197622">Ð”Ð»Ñ ÑžÑÑ‚Ð°Ð½Ð°ÑžÐ»ÐµÐ½Ð½Ñ Ð±ÑÑпечнага злучÑÐ½Ð½Ñ Ñ‚Ñ€Ñба, каб гадзіннік быў наладжаны правільна. ГÑта патрабуецца таму, што Ñертыфікаты, ÑÐºÑ–Ñ Ð²Ñ‹ÐºÐ°Ñ€Ñ‹Ñтоўваюцца вÑб-Ñайтамі Ð´Ð»Ñ Ñ–Ñ… ідÑнтыфікацыі, дзейнічаюць толькі пÑўны чаÑ. Калі гадзіннік на вашай прыладзе наладжаны нÑправільна, Chromium не зможа Ñпраўдзіць гÑÑ‚Ñ‹Ñ Ñертыфікаты.</translation>
<translation id="8740359287975076522">&lt;abbr id="dnsDefinition"&gt;ÐÐ´Ñ€Ð°Ñ DNS &lt;/abbr&gt; хоÑта <ph name="HOST_NAME" /> не знойдзены. ДыÑгноÑтыка праблемы.</translation>
<translation id="8742371904523228557"><ph name="ONE_TIME_CODE" /> – ваш код Ð´Ð»Ñ <ph name="ORIGIN" /></translation>
@@ -2408,6 +2460,7 @@
<translation id="883848425547221593">Ð†Ð½ÑˆÑ‹Ñ Ð·Ð°ÐºÐ»Ð°Ð´ÐºÑ–</translation>
<translation id="884264119367021077">ÐÐ´Ñ€Ð°Ñ Ð´Ð°Ñтаўкі</translation>
<translation id="884923133447025588">Механізм Ð°Ð´ÐºÐ»Ñ–ÐºÐ°Ð½Ð½Ñ Ð½Ðµ знойдзены.</translation>
+<translation id="8849262850971482943">Ð”Ð»Ñ Ð±Ð¾Ð»ÑŒÑˆÐ°Ð¹ бÑÑпекі выкарыÑтоўвайце віртуальную картку</translation>
<translation id="885730110891505394">Ðбагульваецца з Google</translation>
<translation id="8858065207712248076">Chrome Ñ€Ñкамендуе Ñкінуць ваш пароль <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" />, калі вы карыÑталіÑÑ Ñ–Ð¼ на іншых Ñайтах.</translation>
<translation id="885906927438988819">Калі напіÑанне правільнае, <ph name="BEGIN_LINK" />паÑпрабуйце запуÑціць дыÑгноÑтыку Ñеткі Windows<ph name="END_LINK" />.</translation>
@@ -2457,6 +2510,7 @@
<translation id="9004367719664099443">Ідзе ÑÐµÐ°Ð½Ñ VR</translation>
<translation id="9005998258318286617">Ðе ўдалоÑÑ Ð·Ð°Ð³Ñ€ÑƒÐ·Ñ–Ñ†ÑŒ дакумент PDF.</translation>
<translation id="9008201768610948239">Ігнараваць</translation>
+<translation id="901834265349196618">ÑÐ»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð°Ñ Ð¿Ð¾ÑˆÑ‚Ð°</translation>
<translation id="9020200922353704812">Патрабуецца Ð°Ð´Ñ€Ð°Ñ Ð´Ð»Ñ Ð²Ñ‹ÑÑ‚Ð°ÑžÐ»ÐµÐ½Ð½Ñ Ñ€Ð°Ñ…ÑƒÐ½ÐºÐ°Ñž па крÑдытнай картцы</translation>
<translation id="9020542370529661692">ГÑта Ñтаронка была перакладзена на наÑтупную мову: <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9020742383383852663">A8</translation>
@@ -2505,6 +2559,7 @@
<translation id="9150045010208374699">ВыкарыÑтоўваць камеру</translation>
<translation id="9150685862434908345">ÐдмініÑтратар можа аддалена змÑнÑць налады браўзера. Сама прылада такÑама можа знаходзіцца пад знешнім кіраваннем. <ph name="BEGIN_LINK" />Даведацца больш<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">Ðбноўлена</translation>
+<translation id="9155211586651734179">Ð¯ÐºÑ–Ñ Ð¿ÐµÑ€Ñ‹Ñ„ÐµÑ€Ñ‹Ð¹Ð½Ñ‹Ñ Ð¿Ñ€Ñ‹Ð»Ð°Ð´Ñ‹ падключаны</translation>
<translation id="9157595877708044936">Ідзе наладжванне...</translation>
<translation id="9158625974267017556">C6 (канверт)</translation>
<translation id="9164029392738894042">Праверка дакладнаÑці</translation>
diff --git a/chromium/components/strings/components_strings_bg.xtb b/chromium/components/strings/components_strings_bg.xtb
index fb6f341ddbb..0016e18a092 100644
--- a/chromium/components/strings/components_strings_bg.xtb
+++ b/chromium/components/strings/components_strings_bg.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">Преглед на подробноÑтите</translation>
<translation id="1030706264415084469"><ph name="URL" /> иÑка да ÑъхранÑва за поÑтоÑнно голÑмо количеÑтво данни на уÑтройÑтвото ви</translation>
<translation id="1032854598605920125">Завъртане по чаÑовниковата Ñтрелка</translation>
+<translation id="1033329911862281889">Режимът „инкогнито“ не ви прави невидими онлайн:
+<ph name="BEGIN_LIST" />
+<ph name="LIST_ITEM" />Сайтовете и използваните от Ñ‚ÑÑ… уÑлуги могат да виждат поÑещениÑта.<ph name="END_LIST_ITEM" />
+<ph name="LIST_ITEM" />Работодателите или учебните Ð·Ð°Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¸Ð¼Ð°Ñ‚ възможноÑÑ‚ да проÑледÑват активноÑтта при Ñърфиране.<ph name="END_LIST_ITEM" />
+<ph name="LIST_ITEM" />ДоÑтавчиците на интернет уÑлуги могат да ÑледÑÑ‚ уеб трафика.<ph name="END_LIST_ITEM" />
+<ph name="END_LIST" /></translation>
<translation id="1036348656032585052">Изключване</translation>
<translation id="1036982837258183574">ÐатиÑнете |<ph name="ACCELERATOR" />| за изход от режима на цÑл екран</translation>
<translation id="1038106730571050514">Показване на предложениÑ</translation>
<translation id="1038842779957582377">неизвеÑтно име</translation>
<translation id="1041998700806130099">Съобщение за лиÑта за заданието</translation>
<translation id="1048785276086539861">Когато редактирате поÑÑнениÑта, изгледът на документа ще бъде на една Ñтраница</translation>
-<translation id="1049743911850919806">„Инкогнито“</translation>
<translation id="1050038467049342496">Затворете другите приложениÑ.</translation>
<translation id="1055184225775184556">&amp;ОтмÑна на добавÑнето</translation>
<translation id="1056898198331236512">Предупреждение</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">Кешът на правилото е в добро ÑÑŠÑтоÑние</translation>
<translation id="1130564665089811311">Бутон „Превод на Ñтраницата“. ÐатиÑнете Enter, за да преведете тази Ñтраница Ñ Google Преводач</translation>
<translation id="1131264053432022307">Копирано от Ð²Ð°Ñ Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ðµ</translation>
+<translation id="1142846828089312304">Блокиране на „биÑквитките“ на трети Ñтрани в режим „инкогнито“</translation>
<translation id="1150979032973867961">Сървърът не можа да докаже, че е <ph name="DOMAIN" />; операционната ÑиÑтема на компютъра ви нÑма доверие на Ñертификата му за ÑигурноÑÑ‚. Това може да Ñе дължи на неправилно конфигуриране или на прихващане на връзката ви от атакуващ.</translation>
<translation id="1151972924205500581">ИзиÑква Ñе парола</translation>
<translation id="1156303062776767266">Преглеждате локален или Ñподелен файл</translation>
@@ -64,7 +70,6 @@
<translation id="1178581264944972037">Пауза</translation>
<translation id="1181037720776840403">Премахване</translation>
<translation id="1186201132766001848">Проверка на паролите</translation>
-<translation id="1195210374336998651">Към наÑтройките за приложението</translation>
<translation id="1195558154361252544">ИзвеÑтиÑта Ñе блокират автоматично за вÑички Ñайтове оÑвен за онези, за които ги разрешите</translation>
<translation id="1197088940767939838">оранжево</translation>
<translation id="1201402288615127009">Ðапред</translation>
@@ -111,7 +116,7 @@
<translation id="1307966114820526988">Оттеглени функции</translation>
<translation id="1308113895091915999">Ðалице е оферта</translation>
<translation id="1312803275555673949">Какви доказателÑтва подкрепÑÑ‚ твърдението?</translation>
-<translation id="131405271941274527"><ph name="URL" /> иÑка да изпраща и да получава Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¿Ñ€Ð¸ докоÑване на телефона ви до уÑтройÑтва Ñ NFC</translation>
+<translation id="1314311879718644478">Преглед на Ñъдържанието за обогатена реалноÑÑ‚</translation>
<translation id="1314509827145471431">Подвързване отдÑÑно</translation>
<translation id="1318023360584041678">Запазено в групата Ñ Ñ€Ð°Ð·Ð´ÐµÐ»Ð¸</translation>
<translation id="1319245136674974084">Да не Ñе пита отново за това приложение</translation>
@@ -161,6 +166,7 @@
<translation id="142858679511221695">Потребител на облака</translation>
<translation id="1428729058023778569">Виждате това предупреждение, защото Ñайтът не поддържа HTTPS. <ph name="BEGIN_LEARN_MORE_LINK" />Ðаучете повече<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">Печат</translation>
+<translation id="1432187715652018471">Страницата иÑка да инÑталира манипулатор на уÑлуги.</translation>
<translation id="1432581352905426595">Управление на Ñ‚ÑŠÑ€Ñещите машини</translation>
<translation id="1436185428532214179">Може да поиÑка разрешение да редактира файлове и папки на уÑтройÑтвото ви</translation>
<translation id="1442386063175183758">Сгъване на деÑÐ½Ð¸Ñ ÐºÑ€Ð°Ð¹ навътре</translation>
@@ -181,6 +187,12 @@
<translation id="1483493594462132177">Изпращане</translation>
<translation id="1484290072879560759">Избиране на Ð°Ð´Ñ€ÐµÑ Ð·Ð° доÑтавка</translation>
<translation id="1492194039220927094">РазпроÑтранение на правилата:</translation>
+<translation id="149293076951187737">Когато затворите вÑички раздели на Chrome в режим „инкогнито“, активноÑтта ви в Ñ‚ÑÑ… Ñе изчиÑтва от уÑтройÑтвото. Това включва:
+<ph name="BEGIN_LIST" />
+<ph name="LIST_ITEM" />активноÑтта при Ñърфиране;<ph name="END_LIST_ITEM" />
+<ph name="LIST_ITEM" />иÑториÑта на Ñ‚ÑŠÑ€ÑениÑта;<ph name="END_LIST_ITEM" />
+<ph name="LIST_ITEM" />информациÑта, въведена във формулÑри.<ph name="END_LIST_ITEM" />
+<ph name="END_LIST" /></translation>
<translation id="1495677929897281669">Ðазад към раздела</translation>
<translation id="1501859676467574491">Показване на картите от профила ви в Google</translation>
<translation id="1507202001669085618">&lt;p&gt;Ще виждате това Ñъобщение за грешка, ако използвате портал за Wi-Fi, където Ñ‚Ñ€Ñбва да влезете в профил, преди да можете да преминете онлайн.&lt;/p&gt;
@@ -208,6 +220,8 @@
<translation id="1559572115229829303">&lt;p&gt;Ðе може да Ñе уÑтанови чаÑтна връзка Ñ/ÑŠÑ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />, тъй като датата и чаÑÑŠÑ‚ на уÑтройÑтвото ви (<ph name="DATE_AND_TIME" />) Ñа неправилни.&lt;/p&gt;
&lt;p&gt;МолÑ, коригирайте датата и чаÑа от ÑекциÑта &lt;strong&gt;General&lt;/strong&gt; на приложението &lt;strong&gt;Settings&lt;/strong&gt;.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">ÐдминиÑтраторът ще реÑтартира уÑтройÑтвото ви в <ph name="TIME" /> на <ph name="DATE" /></translation>
+<translation id="156703335097561114">Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð·Ð° мрежите, като например адреÑи, ÐºÐ¾Ð½Ñ„Ð¸Ð³ÑƒÑ€Ð°Ñ†Ð¸Ñ Ð½Ð° интерфейÑа и качеÑтво на връзката</translation>
<translation id="1567040042588613346">Това правило работи нормално, но на друго мÑÑто е зададена Ñъщата ÑтойноÑÑ‚, коÑто е заменена от него.</translation>
<translation id="1569487616857761740">Въведете дата на валидноÑÑ‚</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@
<translation id="1583429793053364125">Възникна проблем при показването на тази уеб Ñтраница.</translation>
<translation id="1586541204584340881">Кои Ñ€Ð°Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð¸Ñ Ñте инÑталирали</translation>
<translation id="1588438908519853928">Ðормално</translation>
+<translation id="1589050138437146318">Да Ñе инÑталира ли ARCore?</translation>
<translation id="1592005682883173041">ДоÑтъп до локални данни</translation>
<translation id="1594030484168838125">Избор</translation>
<translation id="160851722280695521">Играене на играта Ñ Ð´Ð¸Ð½Ð¾Ð·Ð°Ð²ÑŠÑ€Ð° в Chrome</translation>
@@ -254,7 +269,7 @@
<translation id="1711234383449478798">Пренебрегнато, защото <ph name="POLICY_NAME" /> не е „<ph name="VALUE" />“.</translation>
<translation id="1712552549805331520"><ph name="URL" /> иÑка да ÑъхранÑва за поÑтоÑнно данни на Ð»Ð¾ÐºÐ°Ð»Ð½Ð¸Ñ Ð²Ð¸ компютър</translation>
<translation id="1713628304598226412">Тава 2</translation>
-<translation id="1715874602234207">F</translation>
+<translation id="1715874602234207">пт</translation>
<translation id="1717218214683051432">Сензори за движение</translation>
<translation id="1717494416764505390">ПощенÑка ÐºÑƒÑ‚Ð¸Ñ 3</translation>
<translation id="1718029547804390981">Документът е твърде голÑм за добавÑне на поÑÑнениÑ</translation>
@@ -281,6 +296,7 @@
<translation id="1772163372082567643">Сървърът, който поÑещавате (<ph name="ORIGIN" />), има зададена заглавка,
изиÑкваща за вÑички заÑвки към него да Ñе прилага правило за източник. Ð¢Ñ Ð¾Ð±Ð°Ñ‡Ðµ е неправилно образувана, поради което браузърът не може да изпълни заÑвката ви за <ph name="SITE" />. Операторите на Ñайтове могат да използват правилата за източник,
за да конфигурират ÑигурноÑтта и други ÑвойÑтва за даден Ñайт.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Ðаучете повече за режима „инкогнито“ в Chromium<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">Тук ще Ñе показват отворените ви раздели</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -408,6 +424,7 @@
<translation id="22081806969704220">Тава 3</translation>
<translation id="2212735316055980242">Правилото не е намерено</translation>
<translation id="2213606439339815911">ЗапиÑите Ñе извличат...</translation>
+<translation id="2213612003795704869">Страницата е отпечатана</translation>
<translation id="2215727959747642672">Редактиране на файлове</translation>
<translation id="2218879909401188352">ПонаÑтоÑщем извършители на атака Ñрещу <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> могат да инÑталират опаÑни приложениÑ, които да повредÑÑ‚ уÑтройÑтвото ви, да добавÑÑ‚ Ñкрити такÑи към Ñметката ви за мобилни уÑлуги или да откраднат личната ви информациÑ. <ph name="BEGIN_LEARN_MORE_LINK" />Ðаучете повече<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">ÐÑма доÑтъп до интернет</translation>
@@ -417,6 +434,7 @@
<translation id="2248949050832152960">Използване на WebAuthn</translation>
<translation id="2250931979407627383">Зашиване на Ð»ÐµÐ²Ð¸Ñ Ñ€ÑŠÐ±</translation>
<translation id="225207911366869382">СтойноÑтта е оттеглена за това правило.</translation>
+<translation id="2256115617011615191">РеÑтартиране Ñега</translation>
<translation id="2258928405015593961">Въведете дата на валидноÑÑ‚, коÑто е в бъдещето, и опитайте отново</translation>
<translation id="225943865679747347">Код на грешката: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">HTTP грешка</translation>
@@ -444,6 +462,7 @@
<translation id="2337852623177822836">ÐаÑтройката Ñе контролира от админиÑтратора ви</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> иÑка да Ñе Ñдвои</translation>
<translation id="2346319942568447007">Копирано от Ð²Ð°Ñ Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ðµ</translation>
+<translation id="2350796302381711542">Да Ñе разреши ли на <ph name="HANDLER_HOSTNAME" /> да Ð¾Ñ‚Ð²Ð°Ñ€Ñ Ð²Ð¼ÐµÑто <ph name="REPLACED_HANDLER_TITLE" /> вÑички връзки от типа „<ph name="PROTOCOL" />“?</translation>
<translation id="2354001756790975382">Други отметки</translation>
<translation id="2354430244986887761">Google БезопаÑно Ñърфиране наÑкоро <ph name="BEGIN_LINK" />откри опаÑни приложениÑ<ph name="END_LINK" /> на <ph name="SITE" />.</translation>
<translation id="2355395290879513365">Извършители на атаки може да Ñа в ÑÑŠÑтоÑние да видÑÑ‚ изображениÑта, които преглеждате на този Ñайт, и да ви подведат, като ги променÑÑ‚.</translation>
@@ -469,6 +488,7 @@
<translation id="2413528052993050574">Сървърът не можа да докаже, че е <ph name="DOMAIN" />; възможно е Ñертификатът му за ÑигурноÑÑ‚ да е оттеглен. Това може да Ñе дължи на неправилно конфигуриране или на прихващане на връзката ви от атакуващ.</translation>
<translation id="2414886740292270097">Тъмно</translation>
<translation id="2430968933669123598">Управление на профила в Google. ÐатиÑнете Enter, за да управлÑвате информациÑта Ñи и наÑтройките за поверителноÑÑ‚ и ÑигурноÑÑ‚ в профила Ñи в Google</translation>
+<translation id="2436186046335138073">Да Ñе разреши ли на <ph name="HANDLER_HOSTNAME" /> да Ð¾Ñ‚Ð²Ð°Ñ€Ñ Ð²Ñички връзки от типа „<ph name="PROTOCOL" />“?</translation>
<translation id="2438874542388153331">Четворно перфориране отдÑÑно</translation>
<translation id="2450021089947420533">ПътешеÑтвиÑ</translation>
<translation id="2463739503403862330">Попълване</translation>
@@ -476,6 +496,7 @@
<translation id="2465655957518002998">Избиране на начин на бърза доÑтавка</translation>
<translation id="2465688316154986572">Телбодиране</translation>
<translation id="2465914000209955735">Управление на файловете, които Ñте изтеглили Ñ Chrome</translation>
+<translation id="2466004615675155314">Показване на Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾Ñ‚ мрежата</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Стартирайте мрежова диагноÑтика<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">Подредба от 1 до N</translation>
<translation id="2470767536994572628">Когато редактирате поÑÑнениÑта, изгледът на документа ще бъде на една Ñтраница Ñ Ð¾Ñ€Ð¸Ð³Ð¸Ð½Ð°Ð»Ð½Ð°Ñ‚Ð° му ориентациÑ</translation>
@@ -496,6 +517,7 @@
<translation id="2523886232349826891">Запазено Ñамо на това уÑтройÑтво</translation>
<translation id="2524461107774643265">ДобавÑне на още информациÑ</translation>
<translation id="2529899080962247600">Това поле не Ñ‚Ñ€Ñбва да Ñъдържа повече от <ph name="MAX_ITEMS_LIMIT" /> запиÑа. Следващите Ñе пренебрегват.</translation>
+<translation id="2535585790302968248">Отворете нов раздел в режим „инкогнито“, за да Ñърфирате чаÑтно</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{и още 1}other{и още #}}</translation>
<translation id="2536110899380797252">ДобавÑне на адреÑ</translation>
<translation id="2539524384386349900">Откриване</translation>
@@ -521,7 +543,14 @@
<translation id="2597378329261239068">Този документ е защитен Ñ Ð¿Ð°Ñ€Ð¾Ð»Ð°. МолÑ, въведете Ñ.</translation>
<translation id="2609632851001447353">Вариации</translation>
<translation id="2610561535971892504">Кликнете, за да копирате</translation>
+<translation id="2617988307566202237">Chrome <ph name="BEGIN_EMPHASIS" />нÑма да запазва<ph name="END_EMPHASIS" /> Ñледната информациÑ:
+<ph name="BEGIN_LIST" />
+<ph name="LIST_ITEM" />иÑториÑта ви на Ñърфиране;
+<ph name="LIST_ITEM" />„биÑквитките“ и данните за Ñайтовете;
+<ph name="LIST_ITEM" />информациÑта, въведена във формулÑри.
+<ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (плик)</translation>
+<translation id="2623663032199728144">Може да извежда Ð·Ð°Ð¿Ð¸Ñ‚Ð²Ð°Ð½Ð¸Ñ Ð·Ð° използване на информациÑта за екраните ви</translation>
<translation id="2625385379895617796">ЧаÑовникът ви е напред</translation>
<translation id="262745152991669301">Може да поиÑка разрешение да Ñе Ñвързва Ñ USB уÑтройÑтва</translation>
<translation id="2629325967560697240">За да използвате най-виÑокото ниво на ÑигурноÑÑ‚ на Chrome, <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />включете подобрената защита<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -555,6 +584,7 @@
<translation id="2709516037105925701">Ðвтоматично попълване</translation>
<translation id="2713444072780614174">бÑло</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />. ÐатиÑнете Tab и Ñлед това – Enter, за да управлÑвате информациÑта Ñи за плащане и данните за кредитните Ñи карти в наÑтройките на Chrome</translation>
+<translation id="271663710482723385">ÐатиÑнете |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| за изход от режима на цÑл екран</translation>
<translation id="2721148159707890343">ЗаÑвката е уÑпешна</translation>
<translation id="2723669454293168317">Стартиране на проверка на безопаÑноÑтта от наÑтройките на Chrome</translation>
<translation id="2726001110728089263">Странична тава</translation>
@@ -585,6 +615,7 @@
<translation id="2850739647070081192">Invite (плик)</translation>
<translation id="2856444702002559011">Възможно е извършители на атака да опитват да откраднат информациÑта ви от <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (например пароли, ÑÑŠÐ¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð¸Ð»Ð¸ номера на кредитни карти). <ph name="BEGIN_LEARN_MORE_LINK" />Ðаучете повече<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">Ðа този Ñайт Ñе показват натрапчиви или подвеждащи реклами.</translation>
+<translation id="286512204874376891">Виртуалната карта прикрива дейÑтвителната ви, за да ви защити от потенциална измама. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">ПриÑтелÑко</translation>
<translation id="2876489322757410363">Ще напуÑнете режим „инкогнито“, за да платите във външно приложение. ИÑкате ли да продължите?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />. ÐатиÑнете Tab и Ñлед това Enter, за да управлÑвате БезопаÑно Ñърфиране и други функции от наÑтройките на Chrome</translation>
@@ -609,6 +640,7 @@
<translation id="2930577230479659665">ОтрÑзване Ñлед вÑÑко копие</translation>
<translation id="2932085390869194046">Предложение за парола...</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019">Да Ð¾Ñ‚Ð²Ð°Ñ€Ñ Ð²Ñ€ÑŠÐ·ÐºÐ¸ от типа „<ph name="PROTOCOL" />“.</translation>
<translation id="2941952326391522266">Сървърът не можа да докаже, че е <ph name="DOMAIN" />; Ñертификатът му за ÑигурноÑÑ‚ е от <ph name="DOMAIN2" />. Това може да Ñе дължи на неправилно конфигуриране или на прихващане на връзката ви от атакуващ.</translation>
<translation id="2943895734390379394">Време на качване:</translation>
<translation id="2948083400971632585">Можете да деактивирате вÑички конфигурирани за дадена връзка прокÑи Ñървъри от Ñтраницата „ÐаÑтройки“.</translation>
@@ -641,6 +673,7 @@
<translation id="3037605927509011580">УжаÑ!</translation>
<translation id="3041612393474885105">Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð·Ð° Ñертификата</translation>
<translation id="3044034790304486808">ВъзобновÑване на проучването</translation>
+<translation id="305162504811187366">ИÑториÑта на „Отдалечен работен плот на Chrome“, включително клейма за дата и чаÑ, хоÑтове и идентификатори за клиентÑки ÑеÑии.</translation>
<translation id="3060227939791841287">C9 (плик)</translation>
<translation id="3061707000357573562">УÑлуга за корекции</translation>
<translation id="306573536155379004">Играта е Ñтартирана.</translation>
@@ -681,6 +714,7 @@
<translation id="3197136577151645743">Може да поиÑка разрешение да разпознава кога използвате уÑтройÑтвото активно</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />. ÐатиÑнете Tab и Ñлед това Enter, за да управлÑвате данните, които да Ñе Ñинхронизират, от наÑтройките на Chrome</translation>
<translation id="320323717674993345">Ðнулиране на плащането</translation>
+<translation id="3203366800380907218">От мрежата</translation>
<translation id="3207960819495026254">С отметка</translation>
<translation id="3209034400446768650">Страницата може да ви такÑува</translation>
<translation id="3212581601480735796">ÐктивноÑтта ви в <ph name="HOSTNAME" /> Ñе Ñледи</translation>
@@ -697,10 +731,12 @@
<translation id="3234666976984236645">Важното Ñъдържание на този Ñайт да Ñе открива винаги</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />. ÐатиÑнете Tab и Ñлед това Enter, за да перÑонализирате облика на браузъра Ñи</translation>
<translation id="3240791268468473923">ЛиÑÑ‚ÑŠÑ‚ за неÑъответÑтващи идентификационни данни за Ñигурни Ð¿Ð»Ð°Ñ‰Ð°Ð½Ð¸Ñ Ðµ отворен</translation>
+<translation id="324180406144491771">Връзките от тип <ph name="HOST_NAME" /> Ñа блокирани</translation>
<translation id="3249845759089040423">ПриÑтно</translation>
<translation id="3252266817569339921">френÑки</translation>
<translation id="3257954757204451555">Кой е източникът на тази информациÑ?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />. ÐатиÑнете Tab и Ñлед това Enter, за да Ñъздадете бързо Ñъбитие в Google Календар</translation>
+<translation id="3261488570342242926">Ðаучете повече за виртуалните карти</translation>
<translation id="3264837738038045344">Бутон „Управление на наÑтройките на Chrome“. ÐатиÑнете Enter, за да отворите наÑтройките на браузъра</translation>
<translation id="3266793032086590337">СтойноÑÑ‚ (неÑъвмеÑтима)</translation>
<translation id="3268451620468152448">Отворени раздели</translation>
@@ -714,6 +750,7 @@
<translation id="3288238092761586174">Може да Ñе наложи <ph name="URL" /> да предприеме допълнителни Ñтъпки за потвърждаване на плащането ви</translation>
<translation id="3293642807462928945">Ðаучете повече за правилото <ph name="POLICY_NAME" /></translation>
<translation id="3295444047715739395">Преглеждайте и управлÑвайте паролите Ñи в наÑтройките на Chrome</translation>
+<translation id="3303795387212510132">Да Ñе разреши ли на приложението да Ð¾Ñ‚Ð²Ð°Ñ€Ñ Ð²Ñ€ÑŠÐ·ÐºÐ¸ от типа <ph name="PROTOCOL_SCHEME" />?</translation>
<translation id="3303855915957856445">ÐÑма намерени резултати от Ñ‚ÑŠÑ€Ñенето</translation>
<translation id="3304073249511302126">Ñканиране за уÑтройÑтва Ñ Bluetooth</translation>
<translation id="3308006649705061278">Организационна единица (OU)</translation>
@@ -727,12 +764,6 @@
<translation id="3345782426586609320">Очи</translation>
<translation id="3355823806454867987">ПромÑна на наÑтройките на прокÑи Ñървъра...</translation>
<translation id="3360103848165129075">ЛиÑÑ‚ на инÑтрумента за обработване на плащаниÑ</translation>
-<translation id="3361596688432910856">Chrome <ph name="BEGIN_EMPHASIS" />нÑма да ÑъхранÑва<ph name="END_EMPHASIS" /> Ñледната информациÑ:
-<ph name="BEGIN_LIST" />
-<ph name="LIST_ITEM" />иÑториÑта на Ñърфирането ви;
-<ph name="LIST_ITEM" />„биÑквитките“ и данните за Ñайтове;
-<ph name="LIST_ITEM" />въведените във формулÑри данни.
-<ph name="END_LIST" /></translation>
<translation id="3362968246557010467">Това правило е копирано автоматично от оттегленото <ph name="OLD_POLICY" />. Препоръчваме ви да използвате него.</translation>
<translation id="3364869320075768271"><ph name="URL" /> иÑка да използва уÑтройÑтвата и данните ви за виртуална реалноÑÑ‚</translation>
<translation id="3366477098757335611">Преглед на картите</translation>
@@ -815,7 +846,6 @@
<translation id="3587738293690942763">Среден</translation>
<translation id="3592413004129370115">Italian (плик)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{Можете да зададете повторно групата Ñи по вÑÑко време. ПриÑъединÑването към нова група отнема около един ден.}=1{Можете да зададете повторно групата Ñи по вÑÑко време. ПриÑъединÑването към нова група отнема около един ден.}other{Можете да зададете повторно групата Ñи по вÑÑко време. ПриÑъединÑването към нова група отнема около {NUM_DAYS} дни.}}</translation>
-<translation id="3596012367874587041">ÐаÑтройки за приложението</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">Приложението е блокирано от админиÑтратора ви</translation>
<translation id="3608932978122581043">ÐžÑ€Ð¸ÐµÐ½Ñ‚Ð°Ñ†Ð¸Ñ Ð¿Ñ€Ð¸ подаване</translation>
@@ -858,6 +888,7 @@
<translation id="370972442370243704">Включване на пътешеÑтвиÑта</translation>
<translation id="3711895659073496551">Спиране</translation>
<translation id="3712624925041724820">Лицензите Ñа изчерпани</translation>
+<translation id="3714633008798122362">уеб календар</translation>
<translation id="3714780639079136834">Включете мобилните данни или Wi-Fi.</translation>
<translation id="3715597595485130451">Свързване Ñ Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Проверете конфигурациÑта на прокÑи Ñървъра, защитната Ñтена и DNS<ph name="END_LINK" />.</translation>
@@ -919,6 +950,7 @@
<translation id="3906954721959377182">Таблет</translation>
<translation id="3909477809443608991"><ph name="URL" /> иÑка разрешение за възпроизвеждане на защитено Ñъдържание. ИдентичноÑтта на уÑтройÑтвото ви ще бъде потвърдена от Google и този Ñайт може да оÑъщеÑтви доÑтъп до неÑ.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> – <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">Отказ</translation>
<translation id="3939773374150895049">ИÑкате ли да използвате WebAuthn вмеÑто код за проверка?</translation>
<translation id="3946209740501886391">Винаги да Ñе извежда запитване за този Ñайт</translation>
<translation id="3947595700203588284">Може да поиÑка разрешение да Ñе Ñвързва Ñ MIDI уÑтройÑтва</translation>
@@ -940,6 +972,7 @@
<translation id="3990250421422698716">Разделно офÑетово отпечатване</translation>
<translation id="3996311196211510766">Сайтът <ph name="ORIGIN" /> изиÑква за вÑички заÑвки към него
да Ñе прилага правило за източник, но понаÑтоÑщем то не може да бъде приложено.</translation>
+<translation id="4009243425692662128">Съдържанието на Ñтраниците, които отпечатвате, Ñе изпраща до Google Cloud или трети Ñтрани за анализ. Възможно е например да бъдат Ñканирани за чувÑтвителни данни.</translation>
<translation id="4010758435855888356">Да Ñе разреши ли доÑтъпът до хранилището?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{PDF документ, Ñъдържащ {COUNT} Ñтраница}other{PDF документ, Ñъдържащ {COUNT} Ñтраници}}</translation>
<translation id="4023431997072828269">Тъй като този формулÑÑ€ Ñе изпраща поÑредÑтвом незащитена връзка, информациÑта ви ще е видима за други хора.</translation>
@@ -1034,6 +1067,7 @@
<translation id="4250680216510889253">Ðе</translation>
<translation id="4253168017788158739">Забележка</translation>
<translation id="425582637250725228">Ðаправените от Ð²Ð°Ñ Ð¿Ñ€Ð¾Ð¼ÐµÐ½Ð¸ може да не Ñе запазÑÑ‚.</translation>
+<translation id="425869179292622354">ИÑкате ли да повишите ÑигурноÑтта чрез виртуална карта?</translation>
<translation id="4258748452823770588">Ðевалиден подпиÑ</translation>
<translation id="4261046003697461417">Ðе могат да Ñе добавÑÑ‚ поÑÑÐ½ÐµÐ½Ð¸Ñ ÐºÑŠÐ¼ защитени документи</translation>
<translation id="4265872034478892965">Разрешено от админиÑтратора ви</translation>
@@ -1096,6 +1130,7 @@
<translation id="4434045419905280838">ИзÑкач. прозорци и пренаÑочваниÑ</translation>
<translation id="4435702339979719576">пощенÑка картичка)</translation>
<translation id="443673843213245140">Използването на прокÑи Ñървър е деактивирано, но е поÑочена изрична негова конфигурациÑ.</translation>
+<translation id="4441832193888514600">Пренебрегнато, защото правилото може да бъде зададено Ñамо като правило за потребители в облака.</translation>
<translation id="4450893287417543264">Да не Ñе показва отново</translation>
<translation id="4451135742916150903">Може да поиÑка разрешение да Ñе Ñвързва Ñ HID уÑтройÑтва</translation>
<translation id="4452328064229197696">Паролата, коÑто току-що използвахте, е разкрита при нарушение на ÑигурноÑтта на данните. За да защитите профилите Ñи, мениджърът на паролите в Google ви препоръчва да проверите запазените Ñи пароли.</translation>
@@ -1151,6 +1186,7 @@
<translation id="4628948037717959914">Снимка</translation>
<translation id="4631649115723685955">ОпциÑта за връщане на пари при покупка е Ñвързана</translation>
<translation id="4636930964841734540">ИнформациÑ</translation>
+<translation id="4638670630777875591">Режим инкогнито в Chromium</translation>
<translation id="464342062220857295">Функции за Ñ‚ÑŠÑ€Ñене</translation>
<translation id="4644670975240021822">Ð’ обратен ред Ñ Ð¾Ñ‚Ð¿ÐµÑ‡Ð°Ñ‚Ð°Ð½Ð°Ñ‚Ð° Ñтрана надолу</translation>
<translation id="4646534391647090355">Към изтеглÑниÑта</translation>
@@ -1171,6 +1207,7 @@
<translation id="4708268264240856090">Връзката ви бе прекъÑната</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Стартирайте мрежова диагноÑтика в Windows<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426">Парола за <ph name="USERNAME" /></translation>
<translation id="4724144314178270921">Може да поиÑка разрешение да чете текÑта и изображениÑта в буферната памет</translation>
<translation id="4726672564094551039">Презареждане на правилата</translation>
<translation id="4728558894243024398">Платформа</translation>
@@ -1192,6 +1229,7 @@
<translation id="4757993714154412917">Току-що въведохте паролата Ñи в измамничеÑки Ñайт. За да защитите профилите Ñи, Chromium препоръчва да проверите запазените Ñи пароли.</translation>
<translation id="4758311279753947758">ДобавÑне на Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð·Ð° връзка</translation>
<translation id="4761104368405085019">Използване на микрофона ви</translation>
+<translation id="4761869838909035636">Стартиране на проверка на безопаÑноÑтта в Chrome</translation>
<translation id="4764776831041365478">До уеб Ñтраницата на Ð°Ð´Ñ€ÐµÑ <ph name="URL" /> може временно да нÑма доÑтъп или да е премеÑтена за поÑтоÑнно на нов уеб адреÑ.</translation>
<translation id="4766713847338118463">Двуточково телбодиране в долната чаÑÑ‚</translation>
<translation id="4771973620359291008">Възникна неизвеÑтна грешка.</translation>
@@ -1212,12 +1250,6 @@
<translation id="4819347708020428563">ИÑкате ли да редактирате поÑÑнениÑта в ÑÑ‚Ð°Ð½Ð´Ð°Ñ€Ñ‚Ð½Ð¸Ñ Ð¸Ð·Ð³Ð»ÐµÐ´?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />. ÐатиÑнете Tab и Ñлед това Enter, за да Ñъздадете бързо таблица в Google Таблици</translation>
<translation id="4825507807291741242">ВпечатлÑващо</translation>
-<translation id="4827402517081186284">Режимът „инкогнито“ не ви прави невидими онлайн:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Когато поÑещавате Ñайтове, те знаÑÑ‚ за това.<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Работодателите или учебните Ð·Ð°Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³Ð°Ñ‚ да проÑледÑват активноÑтта при Ñърфиране.<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />ДоÑтавчиците на интернет уÑлуги може да ÑледÑÑ‚ уеб трафика.<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">Включване на предупреждениÑта</translation>
<translation id="4838327282952368871">Замечтано</translation>
<translation id="4840250757394056958">Преглед на иÑториÑта ви в Chrome</translation>
@@ -1229,12 +1261,12 @@
<translation id="4854362297993841467">Този начин на бърза доÑтавка не Ñе поддържа. Опитайте Ñ Ð´Ñ€ÑƒÐ³.</translation>
<translation id="4854853140771946034">Бързо Ñъздаване на бележка в Google Keep</translation>
<translation id="485902285759009870">Кодът Ñе потвърждава...</translation>
+<translation id="4866506163384898554">ÐатиÑнете |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />|, за да Ñе покаже курÑорът</translation>
<translation id="4876188919622883022">ОпроÑтен изглед</translation>
<translation id="4876305945144899064">ÐÑма потребителÑко име</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{ÐÑма}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831">ТърÑене на „<ph name="TEXT" />“</translation>
<translation id="4879491255372875719">Ðвтоматично (Ñтандартно)</translation>
-<translation id="4879725228911483934">да Ð¾Ñ‚Ð²Ð°Ñ€Ñ Ð¿Ñ€Ð¾Ð·Ð¾Ñ€Ñ†Ð¸ и да ги разполага на екраните ви</translation>
<translation id="4880827082731008257">ТърÑене в иÑториÑта</translation>
<translation id="4881695831933465202">ОтварÑне</translation>
<translation id="4885256590493466218">Плащане Ñ <ph name="CARD_DETAIL" /></translation>
@@ -1243,6 +1275,7 @@
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" /> и <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">Девета ролка</translation>
<translation id="4901778704868714008">Запазване...</translation>
+<translation id="4905659621780993806">ÐдминиÑтраторът ще реÑтартира уÑтройÑтвото ви в <ph name="TIME" /> на <ph name="DATE" />, без да е необходимо дейÑтвие от ваша Ñтрана. Запазете отворените елементи, преди да бъде реÑтартирано.</translation>
<translation id="4913987521957242411">Перфориране горе влÑво</translation>
<translation id="4918221908152712722">ИнÑталирайте <ph name="APP_NAME" /> (не Ñе изиÑква изтеглÑне)</translation>
<translation id="4923459931733593730">Плащане</translation>
@@ -1251,6 +1284,7 @@
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />. ÐатиÑнете Tab и Ñлед това – Enter, за да Ñ‚ÑŠÑ€Ñите</translation>
<translation id="4930153903256238152">ГолÑма вмеÑтимоÑÑ‚</translation>
+<translation id="4940163644868678279">Режим „инкогнито“ в Chrome</translation>
<translation id="4943872375798546930">ÐÑма резултати</translation>
<translation id="4950898438188848926">Бутон за превключване между раздели. ÐатиÑнете Enter, за да преминете към Ð¾Ñ‚Ð²Ð¾Ñ€ÐµÐ½Ð¸Ñ Ñ€Ð°Ð·Ð´ÐµÐ» – <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="495170559598752135">ДейÑтвиÑ</translation>
@@ -1260,6 +1294,7 @@
<translation id="4968522289500246572">Това приложение е предназначено за мобилни уÑтройÑтва и може да не функционира правилно Ñлед преоразмерÑване. То може да има проблеми или да Ñе реÑтартира.</translation>
<translation id="4969341057194253438">Изтриване на запиÑа</translation>
<translation id="4973922308112707173">Двойно перфориране в горната чаÑÑ‚</translation>
+<translation id="4976702386844183910">ПоÑледно поÑещение: <ph name="DATE" /></translation>
<translation id="4984088539114770594">Да Ñе използва ли микрофонът?</translation>
<translation id="4984339528288761049">Prc5 (плик)</translation>
<translation id="4989163558385430922">Преглед на вÑички</translation>
@@ -1321,6 +1356,7 @@
<translation id="5138227688689900538">Показване на по-малко</translation>
<translation id="5145883236150621069">Ð’ отговора за правилото приÑÑŠÑтва код на грешка</translation>
<translation id="5146995429444047494">ИзвеÑтиÑта за <ph name="ORIGIN" /> Ñа блокирани</translation>
+<translation id="514704532284964975"><ph name="URL" /> иÑка да чете и Ð¿Ñ€Ð¾Ð¼ÐµÐ½Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñта на уÑтройÑтвата Ñ NFC, които докоÑвате Ñ Ñ‚ÐµÐ»ÐµÑ„Ð¾Ð½Ð° Ñи</translation>
<translation id="5148809049217731050">С отпечатаната Ñтрана нагоре</translation>
<translation id="515292512908731282">C4 (плик)</translation>
<translation id="5158275234811857234">Корица</translation>
@@ -1345,6 +1381,7 @@
<translation id="5215116848420601511">Ðачини на плащане и адреÑи поÑредÑтвом Google Pay</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">Тава 13</translation>
+<translation id="5216942107514965959">ПоÑледно поÑещение: днеÑ</translation>
<translation id="5222812217790122047">Имейл адреÑÑŠÑ‚ е задължителен</translation>
<translation id="5230733896359313003">ÐÐ´Ñ€ÐµÑ Ð·Ð° доÑтавка</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1365,7 +1402,6 @@
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">СвойÑтва на документа</translation>
<translation id="528468243742722775">Край</translation>
-<translation id="5284909709419567258">Мрежовите адреÑи</translation>
<translation id="5285570108065881030">Показване на вÑички запазени пароли</translation>
<translation id="5287240709317226393">Показване на „биÑквитките“</translation>
<translation id="5287456746628258573">Този Ñайт използва оÑтарÑла ÐºÐ¾Ð½Ñ„Ð¸Ð³ÑƒÑ€Ð°Ñ†Ð¸Ñ Ð·Ð° ÑигурноÑÑ‚, коÑто може да разкрие информациÑта ви (например пароли или номера на кредитни карти) при изпращането Ñ Ð´Ð¾ него.</translation>
@@ -1449,6 +1485,7 @@
<translation id="5556459405103347317">Повторно зареждане</translation>
<translation id="5560088892362098740">Дата на изтичане</translation>
<translation id="55635442646131152">Структура на документа</translation>
+<translation id="5565613213060953222">ОтварÑне на раздел в режим „инкогнито“</translation>
<translation id="5565735124758917034">Ðктивно</translation>
<translation id="5570825185877910964">Защита на профила</translation>
<translation id="5571083550517324815">Този Ð°Ð´Ñ€ÐµÑ Ð·Ð° вземане не Ñе поддържа. Изберете друг.</translation>
@@ -1531,6 +1568,7 @@
<translation id="5869522115854928033">Запазени пароли</translation>
<translation id="5873013647450402046">Банката иÑка да потвърди ÑамоличноÑтта ви.</translation>
<translation id="5887400589839399685">Картата бе запазена</translation>
+<translation id="5887687176710214216">ПоÑледно поÑещение: вчера</translation>
<translation id="5895138241574237353">РеÑтартиране</translation>
<translation id="5895187275912066135">Издаден на</translation>
<translation id="5901630391730855834">жълто</translation>
@@ -1544,6 +1582,7 @@
<translation id="5921639886840618607">Картата да Ñе запази ли в профила в Google?</translation>
<translation id="5922853866070715753">Почти готово</translation>
<translation id="5932224571077948991">Ðа Ñайта Ñе показват натрапчиви или подвеждащи реклами</translation>
+<translation id="5938153366081463283">ДобавÑне на виртуална карта</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347">ÐžÑ‚Ð²Ð°Ñ€Ñ Ñе <ph name="SITE_NAME" />…</translation>
<translation id="5951495562196540101">Ðе е възможно региÑтриране Ñ Ð¿Ñ€Ð¾Ñ„Ð¸Ð» на потребител (налице е лиценз в пакет).</translation>
@@ -1608,6 +1647,7 @@
<translation id="6120179357481664955">Помните ли Ð¸Ð´ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ð¾Ð½Ð½Ð¸Ñ Ñи номер за UPI?</translation>
<translation id="6124432979022149706">Конектори за Chrome Enterprise</translation>
<translation id="6127379762771434464">Елементът бе премахнат</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Ðаучете повече за режима „инкогнито“ в Chrome<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">Проверете вÑички кабели и реÑтартирайте маршрутизаторите, модемите или другите мрежови
уÑтройÑтва, които може да използвате.</translation>
<translation id="614940544461990577">Изпробвайте Ñледното:</translation>
@@ -1620,7 +1660,6 @@
<translation id="6169916984152623906">Вече можете да Ñърфирате чаÑтно. Така другите хора, които използват това уÑтройÑтво, нÑма да виждат активноÑтта ви. ИзтеглÑниÑта и отметките обаче ще Ñе запазват.</translation>
<translation id="6177128806592000436">Връзката ви Ñ Ñ‚Ð¾Ð·Ð¸ Ñайт не е защитена</translation>
<translation id="6180316780098470077">Интервал за повторен опит</translation>
-<translation id="619448280891863779">Може да поиÑка разрешение да Ð¾Ñ‚Ð²Ð°Ñ€Ñ Ð¸ разполага прозорци на екраните ви</translation>
<translation id="6196640612572343990">Блокиране на „биÑквитките“ на трети Ñтрани</translation>
<translation id="6203231073485539293">Проверете връзката Ñи Ñ Ð¸Ð½Ñ‚ÐµÑ€Ð½ÐµÑ‚</translation>
<translation id="6218753634732582820">ÐдреÑÑŠÑ‚ да Ñе премахне ли от Chromium?</translation>
@@ -1643,7 +1682,7 @@
<translation id="6272383483618007430">Google Ðктуализиране</translation>
<translation id="6276112860590028508">Страниците от ÑпиÑъка ви за четене Ñе показват тук</translation>
<translation id="627746635834430766">За да платите по-бързо ÑÐ»ÐµÐ´Ð²Ð°Ñ‰Ð¸Ñ Ð¿ÑŠÑ‚, запазете картата и адреÑа Ñи за фактуриране в профила Ñи в Google.</translation>
-<translation id="6279098320682980337">Ðомерът на виртуалната карта не е попълнен? Кликнете върху данните за картата, за да ги копирате</translation>
+<translation id="6279183038361895380">ÐатиÑнете |<ph name="ACCELERATOR" />|, за да Ñе покаже курÑорът</translation>
<translation id="6280223929691119688">Този Ð°Ð´Ñ€ÐµÑ Ð·Ð° бърза доÑтавка не Ñе поддържа. Изберете друг.</translation>
<translation id="6282194474023008486">ПощенÑки код</translation>
<translation id="6285507000506177184">Бутон „Управление на изтеглÑниÑта Ñ Chrome“. ÐатиÑнете Enter, за да управлÑвате файловете, които Ñте изтеглили Ñ Chrome</translation>
@@ -1651,6 +1690,7 @@
<translation id="6290238015253830360">Предложените ви Ñтатии ще Ñе показват тук</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">Код за ÑигурноÑÑ‚:</translation>
+<translation id="6300452962057769623">{0,plural, =0{УÑтройÑтвото ви ще Ñе реÑтартира Ñега}=1{УÑтройÑтвото ви ще Ñе реÑтартира Ñлед 1 Ñекунда}other{УÑтройÑтвото ви ще Ñе реÑтартира Ñлед # Ñекунди}}</translation>
<translation id="6302269476990306341">Google ÐÑиÑтент в Chrome Ñе Ñпира</translation>
<translation id="6305205051461490394">ÐÑма доÑтъп до <ph name="URL" />.</translation>
<translation id="6312113039770857350">Уеб Ñтраницата не е налице</translation>
@@ -1724,6 +1764,7 @@
<translation id="6529602333819889595">&amp;ВъзÑтановÑване на изтриването</translation>
<translation id="6545864417968258051">Сканиране за уÑтройÑтва Ñ Bluetooth</translation>
<translation id="6547208576736763147">Двойно перфориране отлÑво</translation>
+<translation id="6554732001434021288">ПоÑледно поÑещение: преди <ph name="NUM_DAYS" /> дни</translation>
<translation id="6556866813142980365">ВъзÑтановÑване</translation>
<translation id="6569060085658103619">Преглеждате Ñтраница на разширение</translation>
<translation id="6573200754375280815">Двойно перфориране отдÑÑно</translation>
@@ -1784,7 +1825,6 @@
<translation id="6757797048963528358">УÑтройÑтвото ви премина в ÑпÑщ режим.</translation>
<translation id="6767985426384634228">Да Ñе актуализира ли адреÑÑŠÑ‚?</translation>
<translation id="6768213884286397650">Hagaki (пощенÑка картичка)</translation>
-<translation id="6774185088257932239"><ph name="BEGIN_LINK" />Ðаучете повече<ph name="END_LINK" /> за режима „инкогнито“</translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">виолетово</translation>
<translation id="6786747875388722282">РазширениÑ</translation>
@@ -1868,7 +1908,6 @@
<translation id="706295145388601875">ДобавÑне на адреÑи и управлението им от наÑтройките на Chrome</translation>
<translation id="7064851114919012435">Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð·Ð° връзка</translation>
<translation id="7068733155164172741">Въведете <ph name="OTP_LENGTH" />-Ñ†Ð¸Ñ„Ñ€ÐµÐ½Ð¸Ñ ÐºÐ¾Ð´</translation>
-<translation id="7070090581017165256">Ð’Ñичко за този Ñайт</translation>
<translation id="70705239631109039">Връзката ви не е напълно защитена</translation>
<translation id="7075452647191940183">ЗаÑвката е прекалено голÑма</translation>
<translation id="7079718277001814089">Този Ñайт Ñъдържа злонамерен Ñофтуер</translation>
@@ -1885,6 +1924,12 @@
<translation id="7111012039238467737">(валиден)</translation>
<translation id="7118618213916969306">ТърÑене на URL адреÑа от буферната памет, <ph name="SHORT_URL" /></translation>
<translation id="7119414471315195487">Затворете другите раздели или програми.</translation>
+<translation id="7129355289156517987">Когато затворите вÑички раздели на Chromium в режим „инкогнито“, активноÑтта ви в Ñ‚ÑÑ… Ñе изчиÑтва от уÑтройÑтвото. Това включва:
+<ph name="BEGIN_LIST" />
+<ph name="LIST_ITEM" />активноÑтта при Ñърфиране;<ph name="END_LIST_ITEM" />
+<ph name="LIST_ITEM" />иÑториÑта на Ñ‚ÑŠÑ€ÑениÑта;<ph name="END_LIST_ITEM" />
+<ph name="LIST_ITEM" />информациÑта, въведена във формулÑри.<ph name="END_LIST_ITEM" />
+<ph name="END_LIST" /></translation>
<translation id="7129409597930077180">Този Ð°Ð´Ñ€ÐµÑ Ð·Ð° доÑтавка не Ñе поддържа. Изберете друг.</translation>
<translation id="7132939140423847331">ÐдминиÑтраторът ви е забранил копирането на тези данни.</translation>
<translation id="7135130955892390533">Показване на ÑÑŠÑтоÑнието</translation>
@@ -1907,6 +1952,7 @@
<translation id="7192203810768312527">Ще оÑвободите <ph name="SIZE" />. ÐÑкои Ñайтове може да Ñе заредÑÑ‚ по-бавно при Ñледващото ви поÑещение.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">ÐдминиÑтраторът ви може да вижда:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />. ÐатиÑнете Tab и Ñлед това – Enter, за да отворите нов раздел в режим „инкогнито“ и да Ñърфирате чаÑтно</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> не Ñе придържа към Ñтандартите за ÑигурноÑÑ‚.</translation>
<translation id="7210993021468939304">Може да инÑталира и Ñтартира Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð·Ð° Linux в контейнера, както и да вижда активноÑтта в него</translation>
@@ -1938,6 +1984,7 @@
<translation id="7304562222803846232">Управление на наÑтройките за поверителноÑÑ‚ за профила в Google</translation>
<translation id="7305756307268530424">Стартиране Ñ Ð¿Ð¾-бавна ÑкороÑÑ‚</translation>
<translation id="7308436126008021607">Ñинхронизиране на заден план</translation>
+<translation id="7310392214323165548">УÑтройÑтвото ще Ñе реÑтартира много Ñкоро</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">Помощ при проблеми Ñ Ð²Ñ€ÑŠÐ·ÐºÐ°Ñ‚Ð°</translation>
<translation id="7323804146520582233">Скриване на ÑекциÑта „<ph name="SECTION" />“</translation>
@@ -1945,6 +1992,7 @@
<translation id="7334320624316649418">&amp;ВъзÑтановÑване на пренареждането</translation>
<translation id="7335157162773372339">Може да поиÑка разрешение да използва камерата ви</translation>
<translation id="7337248890521463931">Показване на повече редове</translation>
+<translation id="7337418456231055214">Ðомерът на виртуалната карта не е попълнен? Кликнете върху данните за картата, за да ги копирате. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">Ðе е налице за платформата ви.</translation>
<translation id="733923710415886693">Сертификатът на Ñървъра не е разкрит чрез ПрозрачноÑÑ‚ на Ñертификатите.</translation>
<translation id="734600844861828519">11 x 15</translation>
@@ -1967,6 +2015,7 @@
<translation id="7378627244592794276">Ðе</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">Ðе е приложимо</translation>
+<translation id="7388594495505979117">{0,plural, =1{УÑтройÑтвото ви ще Ñе реÑтартира Ñлед 1 минута}other{УÑтройÑтвото ви ще Ñе реÑтартира Ñлед # минути}}</translation>
<translation id="7390545607259442187">Потвърждаване на картата</translation>
<translation id="7392089738299859607">Ðктуализиране на адреÑ</translation>
<translation id="7399802613464275309">Проверка на безопаÑноÑтта</translation>
@@ -2003,6 +2052,12 @@
<translation id="7485870689360869515">ÐÑма намерени данни.</translation>
<translation id="7495528107193238112">Това Ñъдържание е блокирано. Свържете Ñе ÑÑŠÑ ÑобÑтвеника на Ñайта, за да отÑтрани проблема.</translation>
<translation id="7497998058912824456">Бутон за Ñъздаване на документ. ÐатиÑнете Enter, за да Ñъздадете бързо документ в Google Документи</translation>
+<translation id="7506488012654002225">Chromium <ph name="BEGIN_EMPHASIS" />нÑма да ÑъхранÑва<ph name="END_EMPHASIS" /> Ñледната информациÑ:
+<ph name="BEGIN_LIST" />
+<ph name="LIST_ITEM" />иÑториÑта на Ñърфирането ви;
+<ph name="LIST_ITEM" />„биÑквитките“ и данните за Ñайтовете;
+<ph name="LIST_ITEM" />въведените във формулÑри данни.
+<ph name="END_LIST" /></translation>
<translation id="7508255263130623398">ВърнатиÑÑ‚ от правилата идентификационен номер на уÑтройÑтвото е празен или не ÑъответÑтва на текущиÑ</translation>
<translation id="7508870219247277067">авокадовозелено</translation>
<translation id="7511955381719512146">Използваната от Ð²Ð°Ñ Wi-Fi мрежа може да изиÑква да поÑетите <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
@@ -2116,7 +2171,6 @@
<translation id="7813600968533626083">Предложението за формулÑри да Ñе премахне ли от Chrome?</translation>
<translation id="781440967107097262">Да Ñе Ñподели ли буферната памет?</translation>
<translation id="7815407501681723534"><ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> за „<ph name="SEARCH_STRING" />“</translation>
-<translation id="782125616001965242">Показване на Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð·Ð° този Ñайт</translation>
<translation id="782886543891417279">Използваната от Ð²Ð°Ñ Wi-Fi мрежа (<ph name="WIFI_NAME" />) може да изиÑква да поÑетите Ñтраницата й за вход.</translation>
<translation id="7836231406687464395">Postfix (плик)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{ÐÑма}=1{1 приложение (<ph name="EXAMPLE_APP_1" />)}=2{2 Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}other{# Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" /> <ph name="AND_MORE" />)}}</translation>
@@ -2133,7 +2187,6 @@
<translation id="7888575728750733395">Режим на изобразÑване на цветовете при отпечатване</translation>
<translation id="7894280532028510793">Ðко изпиÑването е правилно, <ph name="BEGIN_LINK" />Ñтартирайте мрежова диагноÑтика<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (плик)</translation>
-<translation id="7931318309563332511">ÐеизвеÑтно</translation>
<translation id="793209273132572360">Да Ñе актуализира ли адреÑÑŠÑ‚?</translation>
<translation id="7932579305932748336">Покритие</translation>
<translation id="79338296614623784">Въведете валиден телефонен номер</translation>
@@ -2158,13 +2211,14 @@
<translation id="7976214039405368314">Твърде много заÑвки</translation>
<translation id="7977538094055660992">Изходно уÑтройÑтво</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">Свързана Ñ(ÑŠÑ)</translation>
<translation id="798134797138789862">Може да поиÑка разрешение да използва уÑтройÑтва и данни за виртуална реалноÑÑ‚</translation>
<translation id="7984945080620862648">Ð’ момента не можете да поÑетите <ph name="SITE" />, защото уебÑайтът изпрати кодирани идентификационни данни, които Chrome не може да обработи. Обикновено грешките в мрежата и атаките Ñрещу Ð½ÐµÑ Ñа временни, така че тази Ñтраница вероÑтно ще работи по-къÑно.</translation>
-<translation id="79859296434321399">За да гледате Ñъдържание Ñ Ð¾Ð±Ð¾Ð³Ð°Ñ‚ÐµÐ½Ð° реалноÑÑ‚, инÑталирайте ARCore</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">Подвързване</translation>
<translation id="7992044431894087211">СподелÑнето на екрана Ñ(ÑŠÑ) <ph name="APPLICATION_TITLE" /> бе възобновено</translation>
<translation id="7995512525968007366">Ðе е поÑочено</translation>
+<translation id="7998269595945679889">Бутон „ОтварÑне на раздел в режим „инкогнито“. ÐатиÑнете Enter, за да отворите нов раздел в режим „инкогнито“ и да Ñърфирате чаÑтно</translation>
<translation id="800218591365569300">Затворете другите раздели или програми, за да оÑвободите памет.</translation>
<translation id="8004582292198964060">Браузър</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{Тази карта и адреÑÑŠÑ‚ й за фактуриране ще бъдат запазени. Ще можете да Ñ Ð¸Ð·Ð¿Ð¾Ð»Ð·Ð²Ð°Ñ‚Ðµ, когато Ñте влезли в профила <ph name="USER_EMAIL" />.}other{Тези карти и адреÑите им за фактуриране ще бъдат запазени. Ще можете да ги използвате, когато Ñте влезли в профила <ph name="USER_EMAIL" />.}}</translation>
@@ -2224,6 +2278,7 @@
<translation id="8202370299023114387">Конфликт</translation>
<translation id="8206978196348664717">Prc4 (плик)</translation>
<translation id="8211406090763984747">Връзката е защитена</translation>
+<translation id="8217240300496046857">Сайтовете не могат да използват „биÑквитки“, които ви ÑледÑÑ‚ в мрежата. Функциите в нÑкои от Ñ‚ÑÑ… може да не работÑÑ‚ правилно.</translation>
<translation id="8218327578424803826">Зададено меÑтоположение:</translation>
<translation id="8220146938470311105">C7/C6 (плик)</translation>
<translation id="8225771182978767009">Човекът, който е наÑтроил компютъра, е блокирал този Ñайт.</translation>
@@ -2264,14 +2319,9 @@
<translation id="830498451218851433">Сгъване в Ñредата</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">ИнÑталираните Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¸ колко чеÑто Ñа използвани</translation>
+<translation id="8317207217658302555">Да Ñе актуализира ли ARCore?</translation>
<translation id="831997045666694187">Вечерта</translation>
<translation id="8321476692217554900">извеÑтиÑ</translation>
-<translation id="8328484624016508118">След като затворите вÑички раздели в режим „инкогнито“, Chrome изчиÑтва:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />активноÑтта ви при Ñърфиране от това уÑтройÑтво;<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />иÑториÑта на Ñ‚ÑŠÑ€ÑениÑта от това уÑтройÑтво;<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />въведената във формулÑри информациÑ.<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489">ДоÑтъпът до <ph name="HOST_NAME" /> бе отказан</translation>
<translation id="833262891116910667">ОткроÑване</translation>
<translation id="8339163506404995330">Страниците на <ph name="LANGUAGE" /> нÑма да Ñе превеждат</translation>
@@ -2323,6 +2373,7 @@
<translation id="8507227106804027148">Команден ред</translation>
<translation id="8508648098325802031">Икона за Ñ‚ÑŠÑ€Ñене</translation>
<translation id="8511402995811232419">Управление на „биÑквитките“</translation>
+<translation id="8519753333133776369">HID уÑтройÑтво, разрешено от админиÑтратора ви</translation>
<translation id="8522552481199248698">Chrome може да ви помогне да защитите профила Ñи в Google и да промените паролата Ñи.</translation>
<translation id="8530813470445476232">ИзчиÑтете иÑториÑта Ñи на Ñърфиране, „биÑквитките“, кеша и др. в наÑтройките на Chrome</translation>
<translation id="8533619373899488139">ПоÑетете &lt;strong&gt;chrome://policy&lt;/strong&gt;, за да видите блокираните URL адреÑи и другите правила, наложени от ÑиÑÑ‚ÐµÐ¼Ð½Ð¸Ñ Ð²Ð¸ админиÑтратор.</translation>
@@ -2334,7 +2385,6 @@
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{Ðулиране на разрешението}other{Ðулиране на разрешениÑта}}</translation>
<translation id="8555010941760982128">Използвайте този код при плащане</translation>
<translation id="8557066899867184262">Кодът за проверка Ñе намира на гърба на картата ви.</translation>
-<translation id="8558485628462305855">За да гледате Ñъдържание Ñ Ð¾Ð±Ð¾Ð³Ð°Ñ‚ÐµÐ½Ð° реалноÑÑ‚, актуализирайте ARCore</translation>
<translation id="8559762987265718583">Ðе може да Ñе уÑтанови чаÑтна връзка Ñ/ÑŠÑ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />, тъй като датата и чаÑÑŠÑ‚ на уÑтройÑтвото ви (<ph name="DATE_AND_TIME" />) Ñа неправилни.</translation>
<translation id="8564182942834072828">Отделни документи/неподредени копиÑ</translation>
<translation id="8564985650692024650">Chromium препоръчва да зададете повторно паролата Ñи за <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" />, ако Ñте Ñ Ð¸Ð·Ð¿Ð¾Ð»Ð·Ð²Ð°Ð»Ð¸ и на други Ñайтове.</translation>
@@ -2353,6 +2403,7 @@
<translation id="865032292777205197">Ñензори за движение</translation>
<translation id="8663226718884576429">Обобщение на поръчката, <ph name="TOTAL_LABEL" />, още подробноÑти</translation>
<translation id="8666678546361132282">английÑки</translation>
+<translation id="8669306706049782872">Да използва информациÑта за екраните ви Ñ Ñ†ÐµÐ» отварÑне и позициониране на прозорци.</translation>
<translation id="867224526087042813">ПодпиÑ</translation>
<translation id="8676424191133491403">Без забавÑне</translation>
<translation id="8680536109547170164">„<ph name="QUERY" />“, отговор: „<ph name="ANSWER" />“</translation>
@@ -2379,6 +2430,7 @@
<translation id="8731544501227493793">Бутон „Управление на паролите“. ÐатиÑнете Enter, за да прегледате и управлÑвате паролите в наÑтройките на Chrome</translation>
<translation id="8734529307927223492">ВашиÑÑ‚ <ph name="DEVICE_TYPE" /> Ñе управлÑва от <ph name="MANAGER" /></translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />. ÐатиÑнете Tab и Ñлед това – Enter, за да отворите нов прозорец в режим „инкогнито“ и да Ñърфирате чаÑтно</translation>
+<translation id="8737685506611670901">Да Ð¾Ñ‚Ð²Ð°Ñ€Ñ Ð²Ñ€ÑŠÐ·ÐºÐ¸ от типа „<ph name="PROTOCOL" />“ вмеÑто <ph name="REPLACED_HANDLER_TITLE" /></translation>
<translation id="8738058698779197622">За уÑтановÑване на Ñигурна връзка е необходимо чаÑовникът ви да е верен. Това е така, защото Ñертификатите, Ñ ÐºÐ¾Ð¸Ñ‚Ð¾ уебÑайтовете Ñе идентифицират, Ñа валидни Ñамо за конкретни периоди от време. Тъй като чаÑовникът на уÑтройÑтвото ви не е верен, Chromium не може да потвърди тези Ñертификати.</translation>
<translation id="8740359287975076522">&lt;abbr id="dnsDefinition"&gt;DNS адреÑÑŠÑ‚&lt;/abbr&gt; на <ph name="HOST_NAME" /> не можа да бъде намерен. Проблемът Ñе диагноÑтицира.</translation>
<translation id="8742371904523228557"><ph name="ONE_TIME_CODE" /> е кодът ви за <ph name="ORIGIN" /></translation>
@@ -2406,6 +2458,7 @@
<translation id="883848425547221593">Други отметки</translation>
<translation id="884264119367021077">ÐÐ´Ñ€ÐµÑ Ð·Ð° доÑтавка</translation>
<translation id="884923133447025588">Ðе е намерен механизъм за анулиране.</translation>
+<translation id="8849262850971482943">За по-голÑма ÑигурноÑÑ‚ използвайте виртуалната Ñи карта</translation>
<translation id="885730110891505394">СподелÑне Ñ Google</translation>
<translation id="8858065207712248076">Chrome препоръчва да зададете повторно паролата Ñи за <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" />, ако Ñте Ñ Ð¸Ð·Ð¿Ð¾Ð»Ð·Ð²Ð°Ð»Ð¸ и на други Ñайтове.</translation>
<translation id="885906927438988819">Ðко изпиÑването е правилно, <ph name="BEGIN_LINK" />Ñтартирайте мрежова диагноÑтика в Windows<ph name="END_LINK" />.</translation>
@@ -2455,6 +2508,7 @@
<translation id="9004367719664099443">СеÑиÑта за VR е в ход</translation>
<translation id="9005998258318286617">Зареждането на PDF документа не бе уÑпешно.</translation>
<translation id="9008201768610948239">Пренебрегване</translation>
+<translation id="901834265349196618">имейл</translation>
<translation id="9020200922353704812">СвързаниÑÑ‚ Ñ ÐºÐ°Ñ€Ñ‚Ð°Ñ‚Ð° Ð°Ð´Ñ€ÐµÑ Ð·Ð° фактуриране е задължителен</translation>
<translation id="9020542370529661692">Тази Ñтраница е преведена на <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9020742383383852663">A8</translation>
@@ -2503,6 +2557,7 @@
<translation id="9150045010208374699">Използване на камерата ви</translation>
<translation id="9150685862434908345">ÐдминиÑтраторът ви може отдалечено да Ð¿Ñ€Ð¾Ð¼ÐµÐ½Ñ Ð½Ð°Ñтройките на браузъра. Възможно е активноÑтта на това уÑтройÑтво да Ñе управлÑва и извън Chrome. <ph name="BEGIN_LINK" />Ðаучете повече<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">Ðктуализирано</translation>
+<translation id="9155211586651734179">Ñвързаните периферни аудиоуÑтройÑтва;</translation>
<translation id="9157595877708044936">ÐаÑтройва Ñе...</translation>
<translation id="9158625974267017556">C6 (плик)</translation>
<translation id="9164029392738894042">Проверка на точноÑтта</translation>
diff --git a/chromium/components/strings/components_strings_bn.xtb b/chromium/components/strings/components_strings_bn.xtb
index 91716ae407e..25d08ee6c71 100644
--- a/chromium/components/strings/components_strings_bn.xtb
+++ b/chromium/components/strings/components_strings_bn.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">বিবরণ দেখà§à¦¨</translation>
<translation id="1030706264415084469"><ph name="URL" /> আপনার ডিভাইসে সà§à¦¥à¦¾à§Ÿà§€à¦­à¦¾à¦¬à§‡ বেশি ডেটা সà§à¦Ÿà§‹à¦° করে রাখতে চায়</translation>
<translation id="1032854598605920125">ঘড়ির কাà¦à¦Ÿà¦¾à¦° দিকে ঘোরান</translation>
+<translation id="1033329911862281889">ছদà§à¦®à¦¬à§‡à¦¶à§€' মোড আপনাকে অনলাইন থাকাকালীন অদৃশà§à¦¯ করে রাখে না:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />সাইট à¦à¦¬à¦‚ যে পরিষেবাগà§à¦²à¦¿ তারা বà§à¦¯à¦¬à¦¹à¦¾à¦° করবেন সেগà§à¦²à¦¿ ভিজিট করতে পারেন<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />নিয়োগকরà§à¦¤à¦¾ বা সà§à¦•à§à¦² বà§à¦°à¦¾à¦‰à¦œà¦¿à¦‚ অà§à¦¯à¦¾à¦•à§à¦Ÿà¦¿à¦­à¦¿à¦Ÿà¦¿ টà§à¦°à§à¦¯à¦¾à¦• করতে পারে<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ইনà§à¦Ÿà¦¾à¦°à¦¨à§‡à¦Ÿ পরিষেবা পà§à¦°à¦¦à¦¾à¦¨à¦•à¦¾à¦°à§€ ওয়েব টà§à¦°à¦¾à¦«à¦¿à¦• মনিটর করতে পারে<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">বনà§à¦§ করà§à¦¨</translation>
<translation id="1036982837258183574">পূরà§à¦£ সà§à¦•à§à¦°à¦¿à¦¨ থেকে বেরিয়ে যেতে |<ph name="ACCELERATOR" />| চাপà§à¦¨</translation>
<translation id="1038106730571050514">সাজেশনগà§à¦²à¦¿ দেখান</translation>
<translation id="1038842779957582377">অজানা নাম</translation>
<translation id="1041998700806130099">জব শিট মেসেজ</translation>
<translation id="1048785276086539861">অà§à¦¯à¦¾à¦¨à§‹à¦Ÿà§‡à¦¶à¦¨ à¦à¦¡à¦¿à¦Ÿ করার সময় à¦à¦‡ ডকà§à¦®à§‡à¦¨à§à¦Ÿ আবার 'সিঙà§à¦—েল পেজ ভিউ' মোডে দেখা যাবে</translation>
-<translation id="1049743911850919806">ছদà§à¦®à¦¬à§‡à¦¶à§€</translation>
<translation id="1050038467049342496">অনà§à¦¯à¦¾à¦¨à§à¦¯ অà§à¦¯à¦¾à¦ªà§à¦²à¦¿à¦•à§‡à¦¶à¦¾à¦¨à¦—à§à¦²à¦¿ বনà§à¦§ করà§à¦¨</translation>
<translation id="1055184225775184556">&amp;যোগ করাকে পূরà§à¦¬à¦¾à¦¬à¦¸à§à¦¥à¦¾à¦¯à¦¼ ফেরান</translation>
<translation id="1056898198331236512">সতরà§à¦•à¦¤à¦¾</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">নীতি কà§à¦¯à¦¾à¦¶à§‡à¦Ÿà¦¿ ঠিক আছে</translation>
<translation id="1130564665089811311">'পৃষà§à¦ à¦¾ অনà§à¦¬à¦¾à¦¦ করà§à¦¨' বোতাম, Google Translate বà§à¦¯à¦¬à¦¹à¦¾à¦° করে à¦à¦‡ পৃষà§à¦ à¦¾ অনà§à¦¬à¦¾à¦¦ করতে Enter পà§à¦°à§‡à¦¸ করà§à¦¨à¥¤</translation>
<translation id="1131264053432022307">আপনার কপি করা ছবি</translation>
+<translation id="1142846828089312304">ছদà§à¦®à¦¬à§‡à¦¶à§€ মোডে থারà§à¦¡-পারà§à¦Ÿà¦¿ কà§à¦•à¦¿ বà§à¦²à¦• করà§à¦¨</translation>
<translation id="1150979032973867961">à¦à¦‡ সারà§à¦­à¦¾à¦° পà§à¦°à¦®à¦¾à¦£ করতে পারেনি যে à¦à¦Ÿà¦¿ <ph name="DOMAIN" />; à¦à¦° নিরাপতà§à¦¤à¦¾ সারà§à¦Ÿà¦¿à¦«à¦¿à¦•à§‡à¦Ÿà¦Ÿà¦¿ আপনার কমà§à¦ªà¦¿à¦‰à¦Ÿà¦¾à¦° অপারেটিং সিসà§à¦Ÿà§‡à¦®à§‡à¦° কাছে বিশà§à¦¬à¦¸à§à¦¤ নয়। কোনও ভà§à¦² কনফিগারেশনের কারণে অথবা কোনও আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€ আপনার সংযোগ মাà¦à¦ªà¦¥à§‡ আটকে দিচà§à¦›à§‡ বলে à¦à¦®à¦¨à¦Ÿà¦¾ হতে পারে।</translation>
<translation id="1151972924205500581">পাসওয়ারà§à¦¡ পà§à¦°à§Ÿà§‹à¦œà¦¨</translation>
<translation id="1156303062776767266">আপনি à¦à¦•à¦Ÿà¦¿ সà§à¦¥à¦¾à¦¨à§€à§Ÿ বা শেয়ার করা ফাইল দেখছেন</translation>
@@ -64,7 +70,6 @@
<translation id="1178581264944972037">বিরতি</translation>
<translation id="1181037720776840403">সরান</translation>
<translation id="1186201132766001848">পাসওয়ারà§à¦¡ চেক করà§à¦¨</translation>
-<translation id="1195210374336998651">অà§à¦¯à¦¾à¦ª সেটিংসে যান</translation>
<translation id="1195558154361252544">আপনার অনà§à¦®à¦¤à¦¿ দেওয়া সাইট ছাড়া, বাকি সব সাইটের জনà§à¦¯ বিজà§à¦žà¦ªà§à¦¤à¦¿ অটোমেটিক বà§à¦²à¦• করা হয়েছে</translation>
<translation id="1197088940767939838">কমলা</translation>
<translation id="1201402288615127009">পরের</translation>
@@ -111,7 +116,7 @@
<translation id="1307966114820526988">শীঘà§à¦°à¦‡ বনà§à¦§ করা হবে à¦à¦®à¦¨ ফিচার</translation>
<translation id="1308113895091915999">অফার উপলভà§à¦¯</translation>
<translation id="1312803275555673949">কোন পà§à¦°à¦®à¦¾à¦£ à¦à¦–ানে কাজ করে?</translation>
-<translation id="131405271941274527">NFC ডিভাইসে আপনার ফোন টà§à¦¯à¦¾à¦ª করলে <ph name="URL" /> তথà§à¦¯ পাঠাতে à¦à¦¬à¦‚ পেতে চায়</translation>
+<translation id="1314311879718644478">অগমেনà§à¦Ÿà§‡à¦¡ রিয়েলিটি কনà§à¦Ÿà§‡à¦¨à§à¦Ÿ দেখà§à¦¨</translation>
<translation id="1314509827145471431">ডানদিকে বাà¦à¦§à¦¾à¦‡ করà§à¦¨</translation>
<translation id="1318023360584041678">টà§à¦¯à¦¾à¦¬ গà§à¦°à§à¦ªà§‡ সেভ করা হয়েছে</translation>
<translation id="1319245136674974084">à¦à¦‡ অà§à¦¯à¦¾à¦ªà§‡à¦° জনà§à¦¯ আর জিজà§à¦žà¦¾à¦¸à¦¾ করবেন না</translation>
@@ -161,6 +166,7 @@
<translation id="142858679511221695">কà§à¦²à¦¾à¦‰à¦¡ বà§à¦¯à¦¬à¦¹à¦¾à¦°à¦•à¦¾à¦°à§€</translation>
<translation id="1428729058023778569">à¦à¦‡ সাইটে HTTPS কাজ করে না, তাই আপনি à¦à¦‡ সতরà§à¦•à¦¤à¦¾ দেখছেন। <ph name="BEGIN_LEARN_MORE_LINK" />আরও জানà§à¦¨<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">পà§à¦°à¦¿à¦¨à§à¦Ÿ</translation>
+<translation id="1432187715652018471">পৃষà§à¦ à¦¾à¦Ÿà¦¿ à¦à¦•à¦Ÿà¦¿ পরিষেবা নিয়নà§à¦¤à§à¦°à¦• ইনসà§à¦Ÿà¦² করতে চায়।</translation>
<translation id="1432581352905426595">সারà§à¦š ইঞà§à¦œà¦¿à¦¨à¦—à§à¦²à¦¿ পরিচালনা করà§à¦¨</translation>
<translation id="1436185428532214179">আপনার ডিভাইসের ফাইল ও ফোলà§à¦¡à¦¾à¦° à¦à¦¡à¦¿à¦Ÿ করার অনà§à¦®à¦¤à¦¿ চাইতে পারে</translation>
<translation id="1442386063175183758">ডানদিকে গেট ফোলà§à¦¡</translation>
@@ -181,6 +187,12 @@
<translation id="1483493594462132177">পাঠান</translation>
<translation id="1484290072879560759">শিপিং ঠিকানা বেছে নিন</translation>
<translation id="1492194039220927094">নীতি সংকà§à¦°à¦¾à¦¨à§à¦¤ পà§à¦¶:</translation>
+<translation id="149293076951187737">অআপনি সমসà§à¦¤ Chrome ছদà§à¦®à¦¬à§‡à¦¶à§€ টà§à¦¯à¦¾à¦¬ বনà§à¦§ করলে, à¦à¦‡ ডিভাইস থেকে সেই টà§à¦¯à¦¾à¦¬à§‡ অà§à¦¯à¦¾à¦•à§à¦Ÿà¦¿à¦­à¦¿à¦Ÿà¦¿ মà§à¦›à§‡ যাবে:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />বà§à¦°à¦¾à¦‰à¦œà¦¿à¦‚ অà§à¦¯à¦¾à¦•à§à¦Ÿà¦¿à¦­à¦¿à¦Ÿà¦¿<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />সারà§à¦š ইতিহাস<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ফরà§à¦®à§‡ তথà§à¦¯ দেওয়া হয়েছে<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">টà§à¦¯à¦¾à¦¬à§‡ ফিরে যান</translation>
<translation id="1501859676467574491">আপনার Google Account থেকে কারà§à¦¡ দেখà§à¦¨</translation>
<translation id="1507202001669085618">&lt;p&gt;আপনি যদি à¦à¦®à¦¨ কোনও ওয়াই-ফাই পোরà§à¦Ÿà¦¾à¦² বà§à¦¯à¦¬à¦¹à¦¾à¦° করেন যেখানে অনলাইন হওয়ার জনà§à¦¯ সাইন-ইন করতে হয়, তাহলে à¦à¦‡ সমসà§à¦¯à¦¾à¦Ÿà¦¿ হতে পারে।&lt;/p&gt;
@@ -208,6 +220,8 @@
<translation id="1559572115229829303">&lt;p&gt;<ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> ঠà¦à¦•à¦Ÿà¦¿ বà§à¦¯à¦•à§à¦¤à¦¿à¦—ত সংযোগ সà§à¦¥à¦¾à¦ªà¦¨ করা যায়নি কারণ আপনার ডিভাইসের তারিখ à¦à¦¬à¦‚ সময় (<ph name="DATE_AND_TIME" />) সঠিক নয়৷&lt;/p&gt;
&lt;p&gt;দয়া করে &lt;strong&gt;সেটিংস&lt;/strong&gt; অà§à¦¯à¦¾à¦ªà§à¦²à¦¿à¦•à§‡à¦¶à¦¾à¦¨à§‡à¦° &lt;strong&gt;সাধারণ&lt;/strong&gt; বিভাগ থেকে তারিখ à¦à¦¬à¦‚ সময় সংশোধন করà§à¦¨à§·&lt;/p&gt;</translation>
+<translation id="1559839503761818503"><ph name="DATE" />-ঠ<ph name="TIME" />-ঠআপনার অà§à¦¯à¦¾à¦¡à¦®à¦¿à¦¨à¦¿à¦¸à§à¦Ÿà§à¦°à§‡à¦Ÿà¦° আপনার ডিভাইস রিসà§à¦Ÿà¦¾à¦°à§à¦Ÿ করবে</translation>
+<translation id="156703335097561114">নেটওয়ারà§à¦•à¦¿à¦‚ তথà§à¦¯ যেমন ঠিকানা, ইনà§à¦Ÿà¦¾à¦°à¦«à§‡à¦¸ কনফিগারেশন à¦à¦¬à¦‚ কানেকশন কোয়ালিটি</translation>
<translation id="1567040042588613346">à¦à¦‡ নীতি আশানà§à¦°à§‚প কাজ করছে। আসলে অনà§à¦¯ à¦à¦•à¦Ÿà¦¿ জায়গাতে à¦à¦•à¦‡ ধরনের মান সেট করা হয়েছে à¦à¦¬à¦‚ সেই মানের জায়গাতে à¦à¦‡ নীতি পà§à¦°à§Ÿà§‹à¦— করা হয়।</translation>
<translation id="1569487616857761740">মেয়াদ শেষ হওয়ার তারিখ লিখà§à¦¨</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@
<translation id="1583429793053364125">à¦à¦‡ ওয়েবপৃষà§à¦ à¦¾à¦Ÿà¦¿ দেখানোর সময় কোনো সমসà§à¦¯à¦¾ হয়েছে।</translation>
<translation id="1586541204584340881">কোন কোন à¦à¦•à§à¦¸à¦Ÿà§‡à¦¨à¦¶à¦¨ আপনি ইনসà§à¦Ÿà¦² করেছেন</translation>
<translation id="1588438908519853928">সাধারণ</translation>
+<translation id="1589050138437146318">ARCore ইনসà§à¦Ÿà¦² করবেন?</translation>
<translation id="1592005682883173041">সà§à¦¥à¦¾à¦¨à§€à§Ÿ ডেটা অà§à¦¯à¦¾à¦•à§à¦¸à§‡à¦¸</translation>
<translation id="1594030484168838125">বেছে নিন</translation>
<translation id="160851722280695521">Chrome-ঠডাইনো রান গেম খেলà§à¦¨</translation>
@@ -283,6 +298,7 @@
হেডারটি সঠিকভাবে কাজ করছে না, তাই বà§à¦°à¦¾à¦‰à¦œà¦¾à¦° আপনার অনà§à¦°à§‹à¦§ অনà§à¦¯à¦¾à§Ÿà§€ <ph name="SITE" />-à¦à¦°
সাথে যোগাযোগ বা তা অà§à¦¯à¦¾à¦•à§à¦¸à§‡à¦¸ করতে পারছে না। সাইট অপারেটর কোনও সাইটের
নিরাপতà§à¦¤à¦¾ ও অনà§à¦¯à¦¾à¦¨à§à¦¯ পà§à¦°à¦ªà¦¾à¦°à§à¦Ÿà¦¿ কনফিগার করতে 'অরিজিন নীতি' বà§à¦¯à¦¬à¦¹à¦¾à¦° করতে পারে।</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Chromium-ঠছদà§à¦®à¦¬à§‡à¦¶à§€ মোডের বিষয়ে আরও জানà§à¦¨<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">আপনার খোলা টà§à¦¯à¦¾à¦¬à¦—à§à¦²à¦¿ à¦à¦–ানে দেখা যাবে</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -411,6 +427,7 @@
<translation id="22081806969704220">টà§à¦°à§‡ ৩</translation>
<translation id="2212735316055980242">নীতি পাওয়া যায়নি</translation>
<translation id="2213606439339815911">à¦à¦¨à§à¦Ÿà§à¦°à¦¿à¦—à§à¦²à¦¿ আনা হচà§à¦›à§‡...</translation>
+<translation id="2213612003795704869">পৃষà§à¦ à¦¾ পà§à¦°à¦¿à¦¨à§à¦Ÿ করা হয়েছে</translation>
<translation id="2215727959747642672">ফাইল à¦à¦¡à¦¿à¦Ÿ করা</translation>
<translation id="2218879909401188352"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />-ঠযে আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€à¦°à¦¾ à¦à¦‡ মà§à¦¹à§‚রà§à¦¤à§‡ সকà§à¦°à¦¿à§Ÿ আছে, তারা à¦à¦®à¦¨ বিপজà§à¦œà¦¨à¦• অà§à¦¯à¦¾à¦ª ইনসà§à¦Ÿà¦² করে দিতে পারে যেগà§à¦²à¦¿ আপনার ডিভাইসের কà§à¦·à¦¤à¦¿ করতে, আপনার মোবাইলের বিলে লà§à¦•à¦¾à¦¨à§‹ চারà§à¦œ যোগ করতে বা আপনার বà§à¦¯à¦•à§à¦¤à¦¿à¦—ত তথà§à¦¯ চà§à¦°à¦¿ করতে পারে৷ <ph name="BEGIN_LEARN_MORE_LINK" />আরও জানà§à¦¨<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">ইনà§à¦Ÿà¦¾à¦°à¦¨à§‡à¦Ÿ কানেকশন নেই</translation>
@@ -420,6 +437,7 @@
<translation id="2248949050832152960">WebAuthn বà§à¦¯à¦¬à¦¹à¦¾à¦° করà§à¦¨</translation>
<translation id="2250931979407627383">বাà¦à¦¦à¦¿à¦•à§‡ ধারের দিকে সেলাই</translation>
<translation id="225207911366869382">à¦à¦‡ মান à¦à¦‡ নীতির জনà§à¦¯ অসমরà§à¦¥à¦¿à¦¤ হয়েছে৷</translation>
+<translation id="2256115617011615191">à¦à¦–ন আবার চালৠকরà§à¦¨</translation>
<translation id="2258928405015593961">ভবিষà§à¦¯à¦¤à§‡à¦° কোনও à¦à¦•à¦Ÿà¦¿ তারিখকে মেয়াদ শেষের তারিখ হিসেবে লিখà§à¦¨ à¦à¦¬à¦‚ আবার চেষà§à¦Ÿà¦¾ করà§à¦¨</translation>
<translation id="225943865679747347">তà§à¦°à§à¦Ÿà¦¿ কোড: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">HTTP তà§à¦°à§à¦Ÿà¦¿</translation>
@@ -447,6 +465,7 @@
<translation id="2337852623177822836">সেটিংস আপনার পà§à¦°à¦¶à¦¾à¦¸à¦• নিয়নà§à¦¤à§à¦°à¦£ করে</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> à¦à¦¦à§‡à¦° সঙà§à¦—ে যà§à¦•à§à¦¤ হতে চাচà§à¦›à§‡</translation>
<translation id="2346319942568447007">আপনার কপি করা ছবি</translation>
+<translation id="2350796302381711542"><ph name="REPLACED_HANDLER_TITLE" /> à¦à¦° পরিবরà§à¦¤à§‡ সমসà§à¦¤ <ph name="PROTOCOL" /> লিঙà§à¦•à¦—à§à¦²à¦¿ খà§à¦²à¦¤à§‡ <ph name="HANDLER_HOSTNAME" />কে অনà§à¦®à§‹à¦¦à¦¿à¦¤ করবেন?</translation>
<translation id="2354001756790975382">অনà§à¦¯ বà§à¦•à¦®à¦¾à¦°à§à¦•</translation>
<translation id="2354430244986887761">Google নিরাপদ বà§à¦°à¦¾à¦‰à¦œà¦¿à¦‚ সমà§à¦ªà§à¦°à¦¤à¦¿ <ph name="SITE" /> ঠ<ph name="BEGIN_LINK" />কà§à¦·à¦¤à¦¿à¦•à¦¾à¦°à¦• অà§à¦¯à¦¾à¦ª<ph name="END_LINK" /> খà§à¦à¦œà§‡ পেয়েছে।</translation>
<translation id="2355395290879513365">আপনি à¦à¦‡ সাইটে যেসব ছবি দেখছেন, আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€à¦°à¦¾ সেগà§à¦²à¦¿ দেখতে পেতে পারে à¦à¦¬à¦‚ সেগà§à¦²à¦¿ পরিবরà§à¦¤à¦¨ করে আপনাকে বোকা বানাতে পারে।</translation>
@@ -472,6 +491,7 @@
<translation id="2413528052993050574">à¦à¦‡ সারà§à¦­à¦¾à¦° পà§à¦°à¦®à¦¾à¦£ করতে পারেনি যে à¦à¦Ÿà¦¿ <ph name="DOMAIN" />; à¦à¦° নিরাপতà§à¦¤à¦¾ সারà§à¦Ÿà¦¿à¦«à¦¿à¦•à§‡à¦Ÿ পà§à¦°à¦¤à§à¦¯à¦¾à¦¹à¦¾à¦° করা হতে পারে। কোনো ভà§à¦² কনফিগারেশনের কারণে অথবা কোনো আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€ আপনার সংযোগ মাà¦à¦ªà¦¥à§‡ আটকে দিচà§à¦›à§‡ বলে à¦à¦®à¦¨à¦Ÿà¦¾ হতে পারে।</translation>
<translation id="2414886740292270097">অনà§à¦§à¦•à¦¾à¦°</translation>
<translation id="2430968933669123598">Google অà§à¦¯à¦¾à¦•à¦¾à¦‰à¦¨à§à¦Ÿ মà§à¦¯à¦¾à¦¨à§‡à¦œ করà§à¦¨, আপনার Google অà§à¦¯à¦¾à¦•à¦¾à¦‰à¦¨à§à¦Ÿà§‡ নিজের সমà§à¦ªà¦°à§à¦•à§‡ তথà§à¦¯, গোপনীয়তা à¦à¦¬à¦‚ সà§à¦°à¦•à§à¦·à¦¾ মà§à¦¯à¦¾à¦¨à§‡à¦œ করতে Enter পà§à¦°à§‡à¦¸ করà§à¦¨</translation>
+<translation id="2436186046335138073">সমসà§à¦¤ <ph name="PROTOCOL" /> লিঙà§à¦•à¦—à§à¦²à¦¿à¦•à§‡ খà§à¦²à¦¤à§‡ <ph name="HANDLER_HOSTNAME" />কে সকà§à¦·à¦® করবেন?</translation>
<translation id="2438874542388153331">ডানদিকে কোয়াড পাঞà§à¦š</translation>
<translation id="2450021089947420533">অà§à¦¯à¦¾à¦•à§à¦Ÿà¦¿à¦­à¦¿à¦Ÿà¦¿à¦° সিরিজ</translation>
<translation id="2463739503403862330">পূরণ করà§à¦¨</translation>
@@ -479,6 +499,7 @@
<translation id="2465655957518002998">ডেলিভারি পদà§à¦§à¦¤à¦¿ বেছে নিন</translation>
<translation id="2465688316154986572">সà§à¦Ÿà§‡à¦ªà¦² করà§à¦¨</translation>
<translation id="2465914000209955735">Chrome-ঠডাউনলোড করা ফাইল মà§à¦¯à¦¾à¦¨à§‡à¦œ করà§à¦¨</translation>
+<translation id="2466004615675155314">ওয়েব থেকে তথà§à¦¯ দেখà§à¦¨</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />নেটওয়ারà§à¦• ডায়গনিসà§à¦Ÿà¦¿à¦•à§à¦¸ চালান<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">1-to-N অরà§à¦¡à¦¾à¦°</translation>
<translation id="2470767536994572628">অà§à¦¯à¦¾à¦¨à§‹à¦Ÿà§‡à¦¶à¦¨ à¦à¦¡à¦¿à¦Ÿ করার সময় à¦à¦‡ ডকà§à¦®à§‡à¦¨à§à¦Ÿ 'সিঙà§à¦—েল পেজ ভিউ' মোডে à¦à¦¬à¦‚ à¦à¦° আসল রোটেশনে ফিরে যাবে</translation>
@@ -499,6 +520,7 @@
<translation id="2523886232349826891">শà§à¦§à§à¦®à¦¾à¦¤à§à¦° à¦à¦‡ ডিভাইসে সেভ করা যাবে</translation>
<translation id="2524461107774643265">আরও তথà§à¦¯ যোগ করà§à¦¨</translation>
<translation id="2529899080962247600">à¦à¦‡ ফিলà§à¦¡à§‡ <ph name="MAX_ITEMS_LIMIT" />টির বেশি à¦à¦¨à§à¦Ÿà§à¦°à¦¿ লেখা যাবে না। অনà§à¦¯ সব à¦à¦¨à§à¦Ÿà§à¦°à¦¿ বাতিল করা হবে।</translation>
+<translation id="2535585790302968248">গোপনে বà§à¦°à¦¾à¦‰à¦œ করতে ছদà§à¦®à¦¬à§‡à¦¶à§€ টà§à¦¯à¦¾à¦¬ খà§à¦²à§à¦¨</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{à¦à¦¬à¦‚ আরও ১টি}one{à¦à¦¬à¦‚ আরও #টি}other{à¦à¦¬à¦‚ আরও #টি}}</translation>
<translation id="2536110899380797252">ঠিকানা যোগ করà§à¦¨</translation>
<translation id="2539524384386349900">শনাকà§à¦¤ করà§à¦¨</translation>
@@ -524,7 +546,14 @@
<translation id="2597378329261239068">à¦à¦‡ দসà§à¦¤à¦¾à¦¬à§‡à¦œà¦Ÿà¦¿ পাসওয়ারà§à¦¡ সà§à¦°à¦•à§à¦·à¦¿à¦¤à§· দয়া করে à¦à¦•à¦Ÿà¦¿ পাসওয়ারà§à¦¡ লিখà§à¦¨à§·</translation>
<translation id="2609632851001447353">বৈচিতà§à¦°à¦¤à¦¾</translation>
<translation id="2610561535971892504">কপি করতে কà§à¦²à¦¿à¦• করà§à¦¨</translation>
+<translation id="2617988307566202237">à¦à¦•à§à¦·à§‡à¦¤à§à¦°à§‡ নিচে দেওয়া তথà§à¦¯ Chrome <ph name="BEGIN_EMPHASIS" />সেভ করবে না<ph name="END_EMPHASIS" />:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />আপনার বà§à¦°à¦¾à¦‰à¦œà¦¿à¦‚ ইতিহাস
+ <ph name="LIST_ITEM" />কà§à¦•à¦¿ à¦à¦¬à¦‚ সাইট ডেটা
+ <ph name="LIST_ITEM" />ফরà§à¦®à§‡ লেখা তথà§à¦¯
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (Envelope)</translation>
+<translation id="2623663032199728144">আপনার সà§à¦•à§à¦°à¦¿à¦¨ সমà§à¦ªà¦°à§à¦•à§‡ তথà§à¦¯ বà§à¦¯à¦¬à¦¹à¦¾à¦° করতে চাইতে পারেন</translation>
<translation id="2625385379895617796">আপনার ঘড়ির সময় অনেকটা à¦à¦—িয়ে</translation>
<translation id="262745152991669301">USB ডিভাইসের সাথে কানেকà§à¦Ÿ করতে, অনà§à¦®à¦¤à¦¿ চাইতে পারে</translation>
<translation id="2629325967560697240">Chrome-ঠসবচেয়ে বেশি সà§à¦°à¦•à§à¦·à¦¾ পেতে, <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />উনà§à¦¨à¦¤ সà§à¦°à¦•à§à¦·à¦¾ চালৠকরà§à¦¨<ph name="END_ENHANCED_PROTECTION_LINK" />।</translation>
@@ -558,6 +587,7 @@
<translation id="2709516037105925701">সà§à¦¬à§Ÿà¦‚পূরণ</translation>
<translation id="2713444072780614174">সাদা</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />, Chrome সেটিংসে আপনার পেমেনà§à¦Ÿ ও কà§à¦°à§‡à¦¡à¦¿à¦Ÿ কারà§à¦¡à§‡à¦° তথà§à¦¯ মà§à¦¯à¦¾à¦¨à§‡à¦œ করতে পà§à¦°à¦¥à¦®à§‡ Tab আর তারপরে Enter পà§à¦°à§‡à¦¸ করà§à¦¨</translation>
+<translation id="271663710482723385">ফà§à¦²-সà§à¦•à§à¦°à¦¿à¦¨ থেকে বেরিয়ে আসতে |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| পà§à¦°à§‡à¦¸ করà§à¦¨</translation>
<translation id="2721148159707890343">অনà§à¦°à§‹à¦§ সফল হয়েছে</translation>
<translation id="2723669454293168317">Chrome সেটিংস থেকে 'নিরাপতà§à¦¤à¦¾ সংকà§à¦°à¦¾à¦¨à§à¦¤ পরীকà§à¦·à¦¾' চালান</translation>
<translation id="2726001110728089263">সাইড টà§à¦°à§‡</translation>
@@ -588,6 +618,7 @@
<translation id="2850739647070081192">Invite (Envelope)</translation>
<translation id="2856444702002559011">আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€à¦°à¦¾ হয়ত <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> থেকে আপনার তথà§à¦¯ (যেমন পাসওয়ারà§à¦¡, মেসেজ বা কà§à¦°à§‡à¦¡à¦¿à¦Ÿ কারà§à¦¡) চà§à¦°à¦¿ করার চেষà§à¦Ÿà¦¾ করছে। <ph name="BEGIN_LEARN_MORE_LINK" />আরও জানà§à¦¨<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">à¦à¦‡ সাইট বà§à¦¯à¦¾à¦˜à¦¾à¦¤ সৃষà§à¦Ÿà¦¿à¦•à¦¾à¦°à§€ বা বিভà§à¦°à¦¾à¦¨à§à¦¤à¦¿à¦•à¦° বিজà§à¦žà¦¾à¦ªà¦¨ দেখায়।</translation>
+<translation id="286512204874376891">কোনও ভারà§à¦šà§à§Ÿà¦¾à¦² কারà§à¦¡ আপনাকে সমà§à¦­à¦¾à¦¬à§à¦¯ জালিয়াতির হাত থেকে রকà§à¦·à¦¾ করতে আপনার আসল কারà§à¦¡à§‡à¦° ছদà§à¦®à¦¬à§‡à¦¶ নিতে পারে। <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">বনà§à¦§à§à¦¤à§à¦¬à¦ªà§‚রà§à¦£</translation>
<translation id="2876489322757410363">à¦à¦•à§à¦¸à¦Ÿà¦¾à¦°à§à¦¨à¦¾à¦² অà§à¦¯à¦¾à¦ªà§à¦²à¦¿à¦•à§‡à¦¶à¦¨à§‡à¦° মাধà§à¦¯à¦®à§‡ পেমেনà§à¦Ÿ করার জনà§à¦¯ ছদà§à¦®à¦¬à§‡à¦¶à§€ মোড ছেড়ে বেরিয়ে আসা হচà§à¦›à§‡à¥¤ চালিয়ে যেতে চান?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />, Chrome সেটিংসে আপনার Safe Browsing ও আরও অনেক কিছৠমà§à¦¯à¦¾à¦¨à§‡à¦œ করতে পà§à¦°à¦¥à¦®à§‡ Tab, তারপরে Enter পà§à¦°à§‡à¦¸ করà§à¦¨</translation>
@@ -612,6 +643,7 @@
<translation id="2930577230479659665">পà§à¦°à¦¤à¦¿à¦Ÿà¦¿ কপির পর টà§à¦°à¦¿à¦® করà§à¦¨</translation>
<translation id="2932085390869194046">পাসওয়ারà§à¦¡ পà§à¦°à¦¸à§à¦¤à¦¾à¦¬ করà§à¦¨â€¦</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019"><ph name="PROTOCOL" /> লিঙà§à¦•à¦—à§à¦²à¦¿ খà§à¦²à§à¦¨</translation>
<translation id="2941952326391522266">à¦à¦‡ সারà§à¦­à¦¾à¦° পà§à¦°à¦®à¦¾à¦£ করতে পারেনি যে à¦à¦Ÿà¦¿ <ph name="DOMAIN" />; à¦à¦° নিরাপতà§à¦¤à¦¾ সারà§à¦Ÿà¦¿à¦«à¦¿à¦•à§‡à¦Ÿ <ph name="DOMAIN2" /> থেকে পাওয়া। কোনো ভà§à¦² কনফিগারেশনের কারণে অথবা কোনো আকà§à¦°à¦®à¦£à¦•à¦¾à¦°à§€ আপনার সংযোগ মাà¦à¦ªà¦¥à§‡ আটকে দিচà§à¦›à§‡ বলে à¦à¦®à¦¨à¦Ÿà¦¾ হতে পারে।</translation>
<translation id="2943895734390379394">যে সময়ে আপলোড করা হয়েছিল:</translation>
<translation id="2948083400971632585">আপনি সেটিংস পৃষà§à¦ à¦¾ থেকে কানেকশনের জনà§à¦¯ কনফিগার করা যেকোনো পà§à¦°à¦•à§à¦¸à¦¿ নিষà§à¦•à§à¦°à¦¿à¦¯à¦¼ করতে পারেন৷</translation>
@@ -644,6 +676,7 @@
<translation id="3037605927509011580">ইস!</translation>
<translation id="3041612393474885105">সারà§à¦Ÿà¦¿à¦«à¦¿à¦•à§‡à¦Ÿ তথà§à¦¯</translation>
<translation id="3044034790304486808">আপনার সারà§à¦š আবার চালৠকরà§à¦¨</translation>
+<translation id="305162504811187366">টাইমসà§à¦Ÿà§à¦¯à¦¾à¦®à§à¦ª, হোসà§à¦Ÿ à¦à¦¬à¦‚ কà§à¦²à¦¾à¦¯à¦¼à§‡à¦¨à§à¦Ÿ সেশন আইডি সহ Chrome রিমোট ডেসà§à¦•à¦Ÿà¦ª ইতিহাস</translation>
<translation id="3060227939791841287">C9 (Envelope)</translation>
<translation id="3061707000357573562">পà§à¦¯à¦¾à¦š পরিষেবা</translation>
<translation id="306573536155379004">গেম শà§à¦°à§ হয়েছে।</translation>
@@ -684,6 +717,7 @@
<translation id="3197136577151645743">আপনি কখন ডিভাইস সকà§à¦°à¦¿à§Ÿà¦­à¦¾à¦¬à§‡ বà§à¦¯à¦¬à¦¹à¦¾à¦° করেন তা জানতে চাইতে পারে</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />, Chrome সেটিংসে কী ধরনের তথà§à¦¯ আপনি সিঙà§à¦• করবেন, তা মà§à¦¯à¦¾à¦¨à§‡à¦œ করতে পà§à¦°à¦¥à¦®à§‡ Tab, তারপরে Enter পà§à¦°à§‡à¦¸ করà§à¦¨</translation>
<translation id="320323717674993345">পেমেনà§à¦Ÿ বাতিল করà§à¦¨</translation>
+<translation id="3203366800380907218">ওয়েব থেকে</translation>
<translation id="3207960819495026254">বà§à¦•à¦®à¦¾à¦°à§à¦• করা হয়েছে</translation>
<translation id="3209034400446768650">পৃষà§à¦ à¦¾à¦Ÿà¦¿à¦° মাধà§à¦¯à¦®à§‡ টাকা চারà§à¦œ করা হতে পারে</translation>
<translation id="3212581601480735796"><ph name="HOSTNAME" />-ঠআপনার অà§à¦¯à¦¾à¦•à§à¦Ÿà¦¿à¦­à¦¿à¦Ÿà¦¿ মনিটর করা হচà§à¦›à§‡</translation>
@@ -700,10 +734,12 @@
<translation id="3234666976984236645">à¦à¦‡ সাইটে সবসময় গà§à¦°à§à¦¤à§à¦¬à¦ªà§‚রà§à¦£ কনà§à¦Ÿà§‡à¦¨à§à¦Ÿ শনাকà§à¦¤ করà§à¦¨</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />, আপনার বà§à¦°à¦¾à¦‰à¦œà¦¾à¦° কেমন দেখাবে তা কাসà§à¦Ÿà¦®à¦¾à¦‡à¦œ করতে Tab পà§à¦°à§‡à¦¸ করার পর Enter পà§à¦°à§‡à¦¸ করà§à¦¨</translation>
<translation id="3240791268468473923">সà§à¦°à¦•à§à¦·à¦¿à¦¤ পেমেনà§à¦Ÿ কà§à¦°à§‡à¦¡à§‡à¦¨à¦¶à¦¿à§Ÿà¦¾à¦²à§‡à¦° সাথে মিল নেই à¦à¦®à¦¨ পেমেনà§à¦Ÿ কà§à¦°à§‡à¦¡à§‡à¦¨à¦¶à¦¿à§Ÿà¦¾à¦²à§‡à¦° শিট খোলা আছে</translation>
+<translation id="324180406144491771">“<ph name="HOST_NAME" />†লিঙà§à¦• বà§à¦²à¦• করা হয়েছে</translation>
<translation id="3249845759089040423">গà§à§°à§à¦­à¦¿</translation>
<translation id="3252266817569339921">ফরাসী</translation>
<translation id="3257954757204451555">à¦à¦‡ তথà§à¦¯à§‡à¦° পিছনে কে আছে?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />, চটপট নতà§à¦¨ Google Calendar তৈরি করতে পà§à¦°à¦¥à¦®à§‡ Tab, তারপরে Enter পà§à¦°à§‡à¦¸ করà§à¦¨</translation>
+<translation id="3261488570342242926">ভারà§à¦šà§à§Ÿà¦¾à¦² কারà§à¦¡à§‡à¦° বিষয়ে জানà§à¦¨</translation>
<translation id="3264837738038045344">Chrome সেটিংস বোতাম মà§à¦¯à¦¾à¦¨à§‡à¦œ করà§à¦¨, আপনার Chrome সেটিংস দেখতে Enter পà§à¦°à§‡à¦¸ করà§à¦¨</translation>
<translation id="3266793032086590337">মান (মà§à¦¯à¦¾à¦š করছে না)</translation>
<translation id="3268451620468152448">ওপেন টà§à¦¯à¦¾à¦¬</translation>
@@ -717,6 +753,7 @@
<translation id="3288238092761586174">আপনার পেমেনà§à¦Ÿ যাচাই করতে, <ph name="URL" />হয়ত আরও কিছৠকরতে পারে</translation>
<translation id="3293642807462928945"><ph name="POLICY_NAME" /> নীতি সমà§à¦ªà¦°à§à¦•à§‡ আরও জানà§à¦¨</translation>
<translation id="3295444047715739395">Chrome সেটিংস থেকে আপনার পাসওয়ারà§à¦¡ দেখà§à¦¨ ও মà§à¦¯à¦¾à¦¨à§‡à¦œ করà§à¦¨</translation>
+<translation id="3303795387212510132"><ph name="PROTOCOL_SCHEME" /> লিঙà§à¦• খà§à¦²à¦¤à§‡ অà§à¦¯à¦¾à¦ªà¦•à§‡ অনà§à¦®à¦¤à¦¿ দেবেন?</translation>
<translation id="3303855915957856445">কোনো সারà§à¦š ফলাফল পাওয়া যায়নি</translation>
<translation id="3304073249511302126">বà§à¦²à§à¦Ÿà§à¦¥ সà§à¦•à§à¦¯à¦¾à¦¨à¦¿à¦‚</translation>
<translation id="3308006649705061278">অরà§à¦—ানাইজেশনাল ইউনিট (OU) </translation>
@@ -730,12 +767,6 @@
<translation id="3345782426586609320">চোখ</translation>
<translation id="3355823806454867987">পà§à¦°à¦•à§à¦¸à¦¿ সেটিংস পরিবরà§à¦¤à¦¨ করà§à¦¨...</translation>
<translation id="3360103848165129075">পেমেনà§à¦Ÿ হà§à¦¯à¦¾à¦¨à§à¦¡à¦²à¦¾à¦° শিট</translation>
-<translation id="3361596688432910856">Chrome ঠনিমà§à¦¨à¦²à¦¿à¦–িত তথà§à¦¯ <ph name="BEGIN_EMPHASIS" />সংরকà§à¦·à¦£ করা হয় না<ph name="END_EMPHASIS" />:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />আপনার বà§à¦°à¦¾à¦‰à¦œà¦¿à¦‚ à¦à¦° ইতিহাস
- <ph name="LIST_ITEM" />কà§à¦•à¦¿à¦œ à¦à¦¬à¦‚ সাইটের ডেটা
- <ph name="LIST_ITEM" />আপনি ফরà§à¦®à§‡ যে তথà§à¦¯ দিয়েছেন
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">শীঘà§à¦°à¦‡ বনà§à¦§ হওয়া <ph name="OLD_POLICY" /> নীতি থেকে à¦à¦‡ নীতি অটোমেটিক পদà§à¦§à¦¤à¦¿à¦¤à§‡ কপি করা হয়েছে। পরিবরà§à¦¤à§‡ à¦à¦‡ নীতি বà§à¦¯à¦¬à¦¹à¦¾à¦° করতে হবে।</translation>
<translation id="3364869320075768271"><ph name="URL" /> আপনার ভারà§à¦šà§à¦¯à¦¼à¦¾à¦² রিয়েলিটি ডিভাইস ও ডেটা বà§à¦¯à¦¬à¦¹à¦¾à¦° করার অনà§à¦®à¦¤à¦¿ চাইছে</translation>
<translation id="3366477098757335611">কারà§à¦¡ দেখà§à¦¨</translation>
@@ -818,7 +849,6 @@
<translation id="3587738293690942763">মাà¦à¦¾à¦°à¦¿</translation>
<translation id="3592413004129370115">Italian (Envelope)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{আপনি যেকোনও সময় আপনার গà§à¦°à§à¦ª রিসেট করতে পারবেন। নতà§à¦¨ গà§à¦°à§à¦ªà§‡ যোগ দিতে পà§à¦°à¦¾à§Ÿ à¦à¦• দিন সময় লাগে।}=1{আপনি যেকোনও সময় আপনার গà§à¦°à§à¦ª রিসেট করতে পারবেন। নতà§à¦¨ গà§à¦°à§à¦ªà§‡ যোগ দিতে পà§à¦°à¦¾à§Ÿ à¦à¦• দিন সময় লাগে।}one{আপনি যেকোনও সময় আপনার গà§à¦°à§à¦ª রিসেট করতে পারবেন। নতà§à¦¨ গà§à¦°à§à¦ªà§‡ যোগ দিতে {NUM_DAYS} দিন সময় লাগে।}other{আপনি যেকোনও সময় আপনার গà§à¦°à§à¦ª রিসেট করতে পারবেন। নতà§à¦¨ গà§à¦°à§à¦ªà§‡ যোগ দিতে {NUM_DAYS} দিন সময় লাগে।}}</translation>
-<translation id="3596012367874587041">অà§à¦¯à¦¾à¦ª সেটিংস</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">অà§à¦¯à¦¾à¦ªà§à¦²à¦¿à¦•à§‡à¦¶à¦¨à¦Ÿà¦¿à¦•à§‡ আপনার অà§à¦¯à¦¾à¦¡à¦®à¦¿à¦¨à¦¿à¦¸à§à¦Ÿà§à¦°à§‡à¦Ÿà¦° বà§à¦²à¦• করেছে</translation>
<translation id="3608932978122581043">ফিড ওরিয়েনà§à¦Ÿà§‡à¦¶à¦¨</translation>
@@ -861,6 +891,7 @@
<translation id="370972442370243704">অà§à¦¯à¦¾à¦•à§à¦Ÿà¦¿à¦­à¦¿à¦Ÿà¦¿à¦° সিরিজ চালৠকরà§à¦¨</translation>
<translation id="3711895659073496551">সাসপেনà§à¦¡</translation>
<translation id="3712624925041724820">লাইসেনà§à¦¸à¦—à§à¦²à¦¿à¦° মেয়াদ শেষ হয়ে গেছে</translation>
+<translation id="3714633008798122362">ওয়েব কà§à¦¯à¦¾à¦²à§‡à¦¨à§à¦¡à¦¾à¦°</translation>
<translation id="3714780639079136834">মোবাইল ডেটা বা ওয়াই-ফাই চালৠকরে দেখà§à¦¨</translation>
<translation id="3715597595485130451">ওয়াই-ফাইতে কানেকà§à¦Ÿ করà§à¦¨</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />পà§à¦°à¦•à§à¦¸à¦¿, ফায়ারওয়াল à¦à¦¬à¦‚ ডিà¦à¦¨à¦à¦¸ কনফিগারেশন পরীকà§à¦·à¦¾ করে দেখà§à¦¨<ph name="END_LINK" /></translation>
@@ -922,6 +953,7 @@
<translation id="3906954721959377182">টà§à¦¯à¦¾à¦¬à¦²à§‡à¦Ÿ</translation>
<translation id="3909477809443608991"><ph name="URL" /> সà§à¦°à¦•à§à¦·à¦¿à¦¤ কনà§à¦Ÿà§‡à¦¨à§à¦Ÿ চালাতে চায়। আপনার ডিভাইসের পরিচয় Google যাচাই করে দেখবে à¦à¦¬à¦‚ à¦à¦‡ সাইট সমà§à¦­à¦¬à¦¤ সেটি অà§à¦¯à¦¾à¦•à§à¦¸à§‡à¦¸ করবে।</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">অসà§à¦¬à§€à¦•à¦¾à¦°</translation>
<translation id="3939773374150895049">সিভিসি কোডের পরিবরà§à¦¤à§‡ WebAuthn বà§à¦¯à¦¬à¦¹à¦¾à¦° করবেন?</translation>
<translation id="3946209740501886391">à¦à¦‡ সাইটে সরà§à¦¬à¦¦à¦¾ জিজà§à¦žà¦¾à¦¸à¦¾ করà§à¦¨</translation>
<translation id="3947595700203588284">MIDI ডিভাইসের সাথে কানেকà§à¦Ÿ করতে অনà§à¦®à¦¤à¦¿ চাইতে পারে</translation>
@@ -943,6 +975,7 @@
<translation id="3990250421422698716">জগ অফসেট</translation>
<translation id="3996311196211510766"><ph name="ORIGIN" /> সাইট থেকে অনà§à¦°à§‹à¦§ করা হয়েছে যে à¦à¦¤à§‡ করা সমসà§à¦¤ অনà§à¦°à§‹à¦§à§‡à¦° কà§à¦·à§‡à¦¤à§à¦°à§‡
à¦à¦•à¦Ÿà¦¿ 'অরিজিন নীতি' পà§à¦°à§Ÿà§‹à¦— করা হোক, কিনà§à¦¤à§ বরà§à¦¤à¦®à¦¾à¦¨à§‡ à¦à¦‡ নীতি কারà§à¦¯à¦•à¦° করা যাচà§à¦›à§‡ না।</translation>
+<translation id="4009243425692662128">আপনার পà§à¦°à¦¿à¦¨à§à¦Ÿ করা পৃষà§à¦ à¦¾à¦° কনà§à¦Ÿà§‡à¦¨à§à¦Ÿ বিশà§à¦²à§‡à¦·à¦£à§‡à¦° জনà§à¦¯ Google Cloud বা থারà§à¦¡-পারà§à¦Ÿà¦¿à¦•à§‡ পাঠানো হয়েছে। যেমন, কোনও সংবেদনশীল ডেটা আছে কিনা জানার জনà§à¦¯ à¦à¦Ÿà¦¿ হয়ত সà§à¦•à§à¦¯à¦¾à¦¨ করা হতে পারে।</translation>
<translation id="4010758435855888356">সà§à¦Ÿà§‹à¦°à§‡à¦œ অà§à¦¯à¦¾à¦•à§à¦¸à§‡à¦¸à§‡à¦° অনà§à¦®à¦¤à¦¿ দেবেন?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{পিডিà¦à¦« ডকà§à¦®à§‡à¦¨à§à¦Ÿà§‡ {COUNT}টি পৃষà§à¦ à¦¾ আছে}one{পিডিà¦à¦« ডকà§à¦®à§‡à¦¨à§à¦Ÿà§‡ {COUNT}টি পৃষà§à¦ à¦¾ আছে}other{পিডিà¦à¦« ডকà§à¦®à§‡à¦¨à§à¦Ÿà§‡ {COUNT}টি পৃষà§à¦ à¦¾ আছে}}</translation>
<translation id="4023431997072828269">à¦à¦‡ ফরà§à¦®à¦Ÿà¦¿ à¦à¦®à¦¨ কানেকশন বà§à¦¯à¦¬à¦¹à¦¾à¦° করে জমা দেওয়া হয়েছে যা নিরাপদ নয়, তাই আপনার তথà§à¦¯ অনà§à¦¯à¦¾à¦¨à§à¦¯ বà§à¦¯à¦¬à¦¹à¦¾à¦°à¦•à¦¾à¦°à§€à¦°à¦¾ দেখতে পাবেন।</translation>
@@ -1037,6 +1070,7 @@
<translation id="4250680216510889253">না</translation>
<translation id="4253168017788158739">টিকা</translation>
<translation id="425582637250725228">আপনার করা পরিবরà§à¦¤à¦¨à¦—à§à¦²à¦¿ সংরকà§à¦·à¦£ নাও করা হতে পারে।</translation>
+<translation id="425869179292622354">ভারà§à¦šà§à§Ÿà¦¾à¦² কারà§à¦¡à§‡à¦° মাধà§à¦¯à¦®à§‡ à¦à¦Ÿà¦¿ আরও সà§à¦°à¦•à§à¦·à¦¿à¦¤ করতে চান?</translation>
<translation id="4258748452823770588">তà§à¦°à§à¦Ÿà¦¿à¦ªà§‚রà§à¦£ সà§à¦¬à¦¾à¦•à§à¦·à¦°</translation>
<translation id="4261046003697461417">সà§à¦°à¦•à§à¦·à¦¿à¦¤ ডকà§à¦®à§‡à¦¨à§à¦Ÿ বà§à¦¯à¦¾à¦–à§à¦¯à¦¾ করা যাবে না</translation>
<translation id="4265872034478892965">আপনার পà§à¦°à¦¶à¦¾à¦¸à¦• অনà§à¦®à¦¤à¦¿ দিয়েছে</translation>
@@ -1099,6 +1133,7 @@
<translation id="4434045419905280838">পপ-আপ à¦à¦¬à¦‚ রিডাইরেকà§à¦Ÿ</translation>
<translation id="4435702339979719576">Postcard)</translation>
<translation id="443673843213245140">পà§à¦°à¦•à§à¦¸à¦¿à¦° বà§à¦¯à¦¬à¦¹à¦¾à¦° অকà§à¦·à¦® করা হয়েছে কিনà§à¦¤à§ কোনো সà§à¦ªà¦·à§à¦Ÿ পà§à¦°à¦•à§à¦¸à¦¿ কনফিগারেশান নিরà§à¦¦à¦¿à¦·à§à¦Ÿ করা হয়েছে৷</translation>
+<translation id="4441832193888514600">উপেকà§à¦·à¦¾ করা হয়েছে কারণ নীতিটি শà§à¦§à§à¦®à¦¾à¦¤à§à¦° কà§à¦²à¦¾à¦‰à¦¡ বà§à¦¯à¦¬à¦¹à¦¾à¦°à¦•à¦¾à¦°à§€ নীতি হিসেবে সেট করা যেতে পারে।</translation>
<translation id="4450893287417543264">আর দেখতে চাই না</translation>
<translation id="4451135742916150903">HID ডিভাইসের সাথে কানেকà§à¦Ÿ করার অনà§à¦®à¦¤à¦¿ চাইতে পারে</translation>
<translation id="4452328064229197696">আপনি à¦à¦‡à¦®à¦¾à¦¤à§à¦° যে পাসওয়ারà§à¦¡ বà§à¦¯à¦¬à¦¹à¦¾à¦° করলেন, সেটি হà§à¦¯à¦¾à¦• হওয়া কোনও ডেটাবেসে পাওয়া গেছে। আপনার অà§à¦¯à¦¾à¦•à¦¾à¦‰à¦¨à§à¦Ÿ সà§à¦°à¦•à§à¦·à¦¿à¦¤ করতে, Google পাসওয়ারà§à¦¡ মà§à¦¯à¦¾à¦¨à§‡à¦œà¦¾à¦° আপনার সেভ করা পাসওয়ারà§à¦¡ চেক করার সাজেশন দিচà§à¦›à§‡à¥¤</translation>
@@ -1154,6 +1189,7 @@
<translation id="4628948037717959914">ফটো</translation>
<translation id="4631649115723685955">কà§à¦¯à¦¾à¦¶à¦¬à§à¦¯à¦¾à¦• অফার লিঙà§à¦• করা হয়েছে</translation>
<translation id="4636930964841734540">তথà§à¦¯</translation>
+<translation id="4638670630777875591">Chromium-ঠছদà§à¦®à¦¬à§‡à¦¶à§€ মোড</translation>
<translation id="464342062220857295">সারà§à¦šà§‡à¦° ফিচার</translation>
<translation id="4644670975240021822">রিভারà§à¦¸ অরà§à¦¡à¦¾à¦°, সামনের দিক নীচে</translation>
<translation id="4646534391647090355">আমাকে à¦à¦–নই সেখানে নিয়ে চলà§à¦¨</translation>
@@ -1174,6 +1210,7 @@
<translation id="4708268264240856090">আপনার সংযোগ বাধাপà§à¦°à¦¾à¦ªà§à¦¤ হয়েছে</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Windows নেটওয়ারà§à¦• ডায়গনিসà§à¦Ÿà¦¿à¦•à§à¦¸ চালান<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426"><ph name="USERNAME" />-à¦à¦° পাসওয়ারà§à¦¡</translation>
<translation id="4724144314178270921">আপনার কà§à¦²à¦¿à¦ªà¦¬à§‹à¦°à§à¦¡à§‡ টেকà§à¦¸à¦Ÿ ও ছবি দেখতে অনà§à¦®à¦¤à¦¿ চাইতে পারে</translation>
<translation id="4726672564094551039">নীতিগà§à¦²à¦¿ রিলোড করà§à¦¨</translation>
<translation id="4728558894243024398">পà§à¦²à§à¦¯à¦¾à¦Ÿà¦«à¦°à§à¦®</translation>
@@ -1195,6 +1232,7 @@
<translation id="4757993714154412917">আপনি à¦à¦‡à¦®à¦¾à¦¤à§à¦° à¦à¦•à¦Ÿà¦¿ পà§à¦°à¦¤à¦¾à¦°à¦£à¦¾à¦®à§‚লক সাইটে আপনার পাসওয়ারà§à¦¡ লিখেছেন। আপনার অà§à¦¯à¦¾à¦•à¦¾à¦‰à¦¨à§à¦Ÿ সà§à¦°à¦•à§à¦·à¦¿à¦¤ করার জনà§à¦¯, Chromium আপনার সেভ করা পাসওয়ারà§à¦¡ চেক করে নিতে সাজেসà§à¦Ÿ করছে।</translation>
<translation id="4758311279753947758">পরিচিতির তথà§à¦¯ জà§à§œà§à¦¨</translation>
<translation id="4761104368405085019">আপনার মাইকà§à¦°à§‹à¦«à§‹à¦¨ বà§à¦¯à¦¬à¦¹à¦¾à¦° করà§à¦¨</translation>
+<translation id="4761869838909035636">'Chrome নিরাপতà§à¦¤à¦¾ সংকà§à¦°à¦¾à¦¨à§à¦¤ পরীকà§à¦·à¦¾' চালান</translation>
<translation id="4764776831041365478"><ph name="URL" />-ঠওয়েবপৃষà§à¦ à¦¾à¦Ÿà¦¿ অসà§à¦¥à¦¾à§Ÿà§€à¦­à¦¾à¦¬à§‡ ডাউন থাকতে পারে অথবা à¦à¦Ÿà¦¿ সà§à¦¥à¦¾à§Ÿà§€à¦­à¦¾à¦¬à§‡ কোনো নতà§à¦¨ ওয়েব অà§à¦¯à¦¾à¦¡à§à¦°à§‡à¦¸à§‡ সরানো হয়ে থাকতে পারে৷</translation>
<translation id="4766713847338118463">নিচে ডà§à§Ÿà¦¾à¦² সà§à¦Ÿà§‡à¦ªà¦²</translation>
<translation id="4771973620359291008">à¦à¦•à¦Ÿà¦¿ অজানা তà§à¦°à§à¦Ÿà¦¿ ঘটেছে৷</translation>
@@ -1215,12 +1253,6 @@
<translation id="4819347708020428563">ডিফলà§à¦Ÿ ভিউতে অà§à¦¯à¦¾à¦¨à§‹à¦Ÿà§‡à¦¶à¦¨ à¦à¦¡à¦¿à¦Ÿ করবেন?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />, চটপট নতà§à¦¨ Google Sheet তৈরি করতে পà§à¦°à¦¥à¦®à§‡ Tab, তারপরে Enter পà§à¦°à§‡à¦¸ করà§à¦¨</translation>
<translation id="4825507807291741242">কà§à¦·à¦®à¦¤à¦¾à¦¶à¦¾à¦²à§€</translation>
-<translation id="4827402517081186284">'ছদà§à¦®à¦¬à§‡à¦¶à§€' মোড আপনাকে অনলাইন থাকাকালীন অদৃশà§à¦¯ করে রাখে না:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />সাইটগà§à¦²à¦¿ জানে যে আপনি কখন সেগà§à¦²à¦¿ ভিজিট করেন<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />নিয়োগকরà§à¦¤à¦¾ বা সà§à¦•à§à¦² বà§à¦°à¦¾à¦‰à¦œà¦¿à¦‚ অà§à¦¯à¦¾à¦•à§à¦Ÿà¦¿à¦­à¦¿à¦Ÿà¦¿ টà§à¦°à§à¦¯à¦¾à¦• করতে পারে<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />ইনà§à¦Ÿà¦¾à¦°à¦¨à§‡à¦Ÿ পরিষেবা পà§à¦°à¦¦à¦¾à¦¨à¦•à¦¾à¦°à§€, ওয়েব টà§à¦°à¦¾à¦«à¦¿à¦• মনিটর করতে পারে<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">সতরà§à¦•à¦¤à¦¾ চালৠকরà§à¦¨</translation>
<translation id="4838327282952368871">সà§à¦¬à¦ªà§à¦¨à¦¾à¦²à§</translation>
<translation id="4840250757394056958">আপনার Chrome ইতিহাস দেখà§à¦¨</translation>
@@ -1232,12 +1264,12 @@
<translation id="4854362297993841467">à¦à¦‡ পদà§à¦§à¦¤à¦¿à¦¤à§‡ ডেলিভারি করা যাবে না। অনà§à¦¯ পদà§à¦§à¦¤à¦¿ বà§à¦¯à¦¬à¦¹à¦¾à¦° করà§à¦¨à¥¤</translation>
<translation id="4854853140771946034">Google Keep-ঠচটপট নতà§à¦¨ নোট তৈরি করà§à¦¨</translation>
<translation id="485902285759009870">কোড যাচাই করা হচà§à¦›à§‡â€¦</translation>
+<translation id="4866506163384898554">আপনার কারà§à¦¸à¦¾à¦° দেখাতে |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| পà§à¦°à§‡à¦¸ করà§à¦¨</translation>
<translation id="4876188919622883022">সরলীকৃত ভিউ</translation>
<translation id="4876305945144899064">কোনও বà§à¦¯à¦¬à¦¹à¦¾à¦°à¦•à¦¾à¦°à§€à¦° নাম নেই</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{à¦à¦•à¦Ÿà¦¿à¦“ নয়}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}one{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831"><ph name="TEXT" /> সারà§à¦š</translation>
<translation id="4879491255372875719">অটোমেটিক (ডিফলà§à¦Ÿ)</translation>
-<translation id="4879725228911483934">উইনà§à¦¡à§‹ খà§à¦²à§‡ আপনার সà§à¦•à§à¦°à¦¿à¦¨à§‡ রাখà§à¦¨</translation>
<translation id="4880827082731008257">সারà§à¦šà§‡à¦° ইতিহাস</translation>
<translation id="4881695831933465202">খà§à¦²à§à¦¨</translation>
<translation id="4885256590493466218">চেক-আউট করার সময় <ph name="CARD_DETAIL" /> দিয়ে পেমেনà§à¦Ÿ করà§à¦¨</translation>
@@ -1246,6 +1278,7 @@
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">Ninth Roll</translation>
<translation id="4901778704868714008">সেভ করà§à¦¨...</translation>
+<translation id="4905659621780993806"><ph name="DATE" />-ঠ<ph name="TIME" />-ঠঅà§à¦¯à¦¾à¦¡à¦®à¦¿à¦¨à¦¿à¦¸à§à¦Ÿà§à¦°à§‡à¦Ÿà¦° অটোমেটিক আপনার ডিভাইস রিসà§à¦Ÿà¦¾à¦°à§à¦Ÿ করবে। ডিভাইস রিসà§à¦Ÿà¦¾à¦°à§à¦Ÿ হওয়ার আগে খোলা আছে à¦à¦®à¦¨ যেকোনও আইটেম সেভ করà§à¦¨à¥¤</translation>
<translation id="4913987521957242411">উপরের বাà¦à¦¦à¦¿à¦•à§‡ পাঞà§à¦š</translation>
<translation id="4918221908152712722"><ph name="APP_NAME" /> ইনসà§à¦Ÿà¦² করà§à¦¨ (ডাউনলোডের পà§à¦°à§Ÿà§‹à¦œà¦¨ নেই)</translation>
<translation id="4923459931733593730">অরà§à¦¥à¦ªà§à¦°à¦¦à¦¾à¦¨</translation>
@@ -1254,6 +1287,7 @@
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, সারà§à¦š করতে টà§à¦¯à¦¾à¦¬ টিপে à¦à¦¨à§à¦Ÿà¦¾à¦° টিপà§à¦¨</translation>
<translation id="4930153903256238152">অধিক কà§à¦·à¦®à¦¤à¦¾ সমà§à¦ªà¦¨à§à¦¨</translation>
+<translation id="4940163644868678279">Chrome-ঠছদà§à¦®à¦¬à§‡à¦¶à§€ মোড</translation>
<translation id="4943872375798546930">কোন ফলাফল নেই</translation>
<translation id="4950898438188848926">à¦à¦•à¦Ÿà¦¿ টà§à¦¯à¦¾à¦¬ থেকে অনà§à¦¯ টà§à¦¯à¦¾à¦¬à§‡ যাওয়ার বোতাম, খোলা টà§à¦¯à¦¾à¦¬à§‡ যেতে à¦à¦¨à§à¦Ÿà¦¾à¦° টিপà§à¦¨, <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="495170559598752135">কà§à¦°à¦¿à§Ÿà¦¾à¦¸à¦®à§‚হ</translation>
@@ -1263,6 +1297,7 @@
<translation id="4968522289500246572">à¦à¦‡ অà§à¦¯à¦¾à¦ªà¦Ÿà¦¿ মোবাইল ডিভাইসের জনà§à¦¯ তৈরি করা হয়েছে à¦à¦¬à¦‚ সঠিকভাবে ছোট বড় করা নাও যেতে পারে। à¦à¦‡ অà§à¦¯à¦¾à¦ª বà§à¦¯à¦¬à¦¹à¦¾à¦° করতে হয়ত সমসà§à¦¯à¦¾ হতে পারে বা à¦à¦Ÿà¦¿ রিসà§à¦Ÿà¦¾à¦°à§à¦Ÿ করতে হতে পারে।</translation>
<translation id="4969341057194253438">রেকরà§à¦¡à¦¿à¦‚ মà§à¦›à§‡ ফেলà§à¦¨</translation>
<translation id="4973922308112707173">উপরে ডà§à§Ÿà¦¾à¦² পাঞà§à¦š</translation>
+<translation id="4976702386844183910"><ph name="DATE" />-ঠশেষবার দেখেছেন</translation>
<translation id="4984088539114770594">মাইকà§à¦°à§‹à¦«à§‹à¦¨ বà§à¦¯à¦¬à¦¹à¦¾à¦° করবেন?</translation>
<translation id="4984339528288761049">Prc5 (Envelope)</translation>
<translation id="4989163558385430922">সবগà§à¦²à¦¿ দেখà§à¦¨</translation>
@@ -1324,6 +1359,7 @@
<translation id="5138227688689900538">কম দেখà§à¦¨</translation>
<translation id="5145883236150621069">নীতি পà§à¦°à¦¤à¦¿à¦•à§à¦°à¦¿à¦¯à¦¼à¦¾à¦° মধà§à¦¯à§‡ তà§à¦°à§à¦Ÿà¦¿ কোড উপসà§à¦¥à¦¿à¦¤</translation>
<translation id="5146995429444047494"><ph name="ORIGIN" />-à¦à¦° বিজà§à¦žà¦ªà§à¦¤à¦¿ বà§à¦²à¦• করা হয়েছে</translation>
+<translation id="514704532284964975"><ph name="URL" /> আপনার ফোনে টà§à¦¯à¦¾à¦ª করেন à¦à¦®à¦¨ NFC ডিভাইসে তথà§à¦¯ দেখতে à¦à¦¬à¦‚ পরিবরà§à¦¤à¦¨ করতে চায়</translation>
<translation id="5148809049217731050">সামনের দিক উপরে</translation>
<translation id="515292512908731282">C4 (Envelope)</translation>
<translation id="5158275234811857234">কভার</translation>
@@ -1348,6 +1384,7 @@
<translation id="5215116848420601511">Google Pay বà§à¦¯à¦¬à¦¹à¦¾à¦° করে à¦à¦®à¦¨ পেমেনà§à¦Ÿà§‡à¦° পদà§à¦§à¦¤à¦¿ à¦à¦¬à¦‚ ঠিকানা</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">টà§à¦°à§‡ ১৩</translation>
+<translation id="5216942107514965959">আজ শেষবার দেখা হয়েছে</translation>
<translation id="5222812217790122047">ইমেল আইডি পà§à¦°à§Ÿà§‹à¦œà¦¨</translation>
<translation id="5230733896359313003">শিপিংয়ের ঠিকানা</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1368,7 +1405,6 @@
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">ডকà§à¦®à§‡à¦¨à§à¦Ÿ পà§à¦°à¦ªà¦¾à¦°à§à¦Ÿà¦¿</translation>
<translation id="528468243742722775">শেষ</translation>
-<translation id="5284909709419567258">নেটওয়ারà§à¦• ঠিকানা</translation>
<translation id="5285570108065881030">সেভ করা সমসà§à¦¤ পাসওয়ারà§à¦¡ দেখান</translation>
<translation id="5287240709317226393">কà§à¦•à¦¿à¦œ দেখান</translation>
<translation id="5287456746628258573">à¦à¦‡ সাইটটি পà§à¦°à¦¨à§‹ সিকিউরিটি কনফিগারেশন বà§à¦¯à¦¬à¦¹à¦¾à¦° করে তাই আপনার সংবেদনশীল তথà§à¦¯ (যেমন, পাসওয়ারà§à¦¡ বা কà§à¦°à§‡à¦¡à¦¿à¦Ÿ কারà§à¦¡à§‡à¦° নমà§à¦¬à¦°) à¦à¦‡ সাইটে পাঠানোর সময় à¦à¦‡à¦¸à¦¬ তথà§à¦¯à§‡à¦° নিরাপতà§à¦¤à¦¾ বিঘà§à¦¨à¦¿à¦¤ হতে পারে।</translation>
@@ -1452,6 +1488,7 @@
<translation id="5556459405103347317">রিলোড করà§à¦¨</translation>
<translation id="5560088892362098740">মেয়াদ শেষের তারিখ</translation>
<translation id="55635442646131152">ডকà§à¦®à§‡à¦¨à§à¦Ÿ আউটলাইন</translation>
+<translation id="5565613213060953222">ছদà§à¦®à¦¬à§‡à¦¶à§€ টà§à¦¯à¦¾à¦¬ খà§à¦²à§à¦¨</translation>
<translation id="5565735124758917034">সকà§à¦°à¦¿à§Ÿ</translation>
<translation id="5570825185877910964">অà§à¦¯à¦¾à¦•à¦¾à¦‰à¦¨à§à¦Ÿ সà§à¦°à¦•à§à¦·à¦¿à¦¤ রাখà§à¦¨</translation>
<translation id="5571083550517324815">à¦à¦‡ ঠিকানা থেকে পিক-আপ করা যাবে না। অনà§à¦¯ ঠিকানা বেছে নিন।</translation>
@@ -1534,6 +1571,7 @@
<translation id="5869522115854928033">সংরকà§à¦·à¦¿à¦¤ পাসওয়ারà§à¦¡</translation>
<translation id="5873013647450402046">à¦à¦Ÿà¦¿ যে আপনিই সেই বিষয়ে আপনার বà§à¦¯à¦¾à¦™à§à¦• নিশà§à¦šà¦¿à¦¤ হতে চায়।</translation>
<translation id="5887400589839399685">কারà§à¦¡ সেভ করা হয়েছে</translation>
+<translation id="5887687176710214216">গতকাল শেষবার দেখা হয়েছে</translation>
<translation id="5895138241574237353">পà§à¦¨à¦°à§à¦¸à§‚চনা</translation>
<translation id="5895187275912066135">à¦à¦‡ তারিখে ইসà§à¦¯à§ করা</translation>
<translation id="5901630391730855834">হলà§à¦¦</translation>
@@ -1547,6 +1585,7 @@
<translation id="5921639886840618607">Google অà§à¦¯à¦¾à¦•à¦¾à¦‰à¦¨à§à¦Ÿà§‡ কারà§à¦¡ সেভ করবেন?</translation>
<translation id="5922853866070715753">পà§à¦°à¦¾à¦¯à¦¼ শেষ</translation>
<translation id="5932224571077948991">সাইট বà§à¦¯à¦¾à¦˜à¦¾à¦¤ সৃষà§à¦Ÿà¦¿à¦•à¦¾à¦°à§€ বা বিভà§à¦°à¦¾à¦¨à§à¦¤à¦¿à¦•à¦° বিজà§à¦žà¦¾à¦ªà¦¨ দেখায়</translation>
+<translation id="5938153366081463283">ভারà§à¦šà§à§Ÿà¦¾à¦² কারà§à¦¡ যোগ করà§à¦¨</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347"><ph name="SITE_NAME" /> খà§à¦²à¦›à§‡â€¦</translation>
<translation id="5951495562196540101">কà§à¦°à§‡à¦¤à¦¾à¦° অà§à¦¯à¦¾à¦•à¦¾à¦‰à¦¨à§à¦Ÿà§‡à¦° মাধà§à¦¯à¦®à§‡ à¦à¦¨à¦°à§‹à¦² করা যাচà§à¦›à§‡ না (পà§à¦¯à¦¾à¦•à§‡à¦œ লাইসেনà§à¦¸ পাওয়া যাবে)৷</translation>
@@ -1611,6 +1650,7 @@
<translation id="6120179357481664955">আপনার UPI আইডি মনে আছে?</translation>
<translation id="6124432979022149706">Chrome Enterprise কানেকà§à¦Ÿà¦°</translation>
<translation id="6127379762771434464">আইটেম সরানো হয়েছে</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Chrome-ঠছদà§à¦®à¦¬à§‡à¦¶à§€ মোডের বিষয়ে আরও জানà§à¦¨<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">সব কেবল পরীকà§à¦·à¦¾ করà§à¦¨ à¦à¦¬à¦‚ আপনি বà§à¦¯à¦¬à¦¹à¦¾à¦° করছেন à¦à¦®à¦¨ যেকোনো রাউটার, মডেম বা অনà§à¦¯à¦¾à¦¨à§à¦¯ নেটওয়ারà§à¦• ডিভাইসগà§à¦²à¦¿ আবার চালৠকরà§à¦¨à¥¤</translation>
<translation id="614940544461990577">à¦à¦Ÿà¦¿ করে দেখà§à¦¨:</translation>
<translation id="6150036310511284407">বাà¦à¦¦à¦¿à¦•à§‡ টà§à¦°à¦¿à¦ªà¦² পাঞà§à¦š</translation>
@@ -1622,7 +1662,6 @@
<translation id="6169916984152623906">à¦à¦–ন আপনি গোপনভাবে বà§à¦°à¦¾à¦‰à¦œ করতে পারেন à¦à¦¬à¦‚ অনà§à¦¯ যেসব বকà§à¦¤à¦¿ à¦à¦‡ ডিভাইস বà§à¦¯à¦¬à¦¹à¦¾à¦° করেন তারা আপনার অà§à¦¯à¦¾à¦•à§à¦Ÿà¦¿à¦­à¦¿à¦Ÿà¦¿ দেখতে পাবেন না। তবে, আপনার ডাউনলোড à¦à¦¬à¦‚ বà§à¦•à¦®à¦¾à¦°à§à¦•à¦—à§à¦²à¦¿ সেভ করা হবে।</translation>
<translation id="6177128806592000436">à¦à¦‡ সাইটে আপনার সংযোগ নিরাপদ নয়</translation>
<translation id="6180316780098470077">কতকà§à¦·à¦£ পর আবার চেষà§à¦Ÿà¦¾ করা যাবে</translation>
-<translation id="619448280891863779">সà§à¦•à§à¦°à¦¿à¦¨à§‡ উইনà§à¦¡à§‹ খà§à¦²à¦¤à§‡ à¦à¦¬à¦‚ রাখতে চাইলে অনà§à¦®à¦¤à¦¿ চাইতে পারে</translation>
<translation id="6196640612572343990">তৃতীয় পকà§à¦·à§‡à¦° কà§à¦•à¦¿à¦œ অবরà§à¦¦à§à¦§ করà§à¦¨</translation>
<translation id="6203231073485539293">আপনার ইনà§à¦Ÿà¦¾à¦°à¦¨à§‡à¦Ÿ সংযোগ পরীকà§à¦·à¦¾ করà§à¦¨</translation>
<translation id="6218753634732582820">Chromium থেকে ঠিকানা সরাবেন?</translation>
@@ -1645,7 +1684,7 @@
<translation id="6272383483618007430">Google আপডেট</translation>
<translation id="6276112860590028508">পড়ার তালিকার পৃষà§à¦ à¦¾à¦—à§à¦²à¦¿ à¦à¦–ানে দেখা যাবে</translation>
<translation id="627746635834430766">পরের বার আরও দà§à¦°à§à¦¤ পেমেনà§à¦Ÿ করা জনà§à¦¯ আপনার à¦à¦‡ কারà§à¦¡ à¦à¦¬à¦‚ বিলিং ঠিকানাটি Google অà§à¦¯à¦¾à¦•à¦¾à¦‰à¦¨à§à¦Ÿà§‡ সেভ করে রাখà§à¦¨à¥¤</translation>
-<translation id="6279098320682980337">ভারà§à¦šà§à§Ÿà¦¾à¦² কারà§à¦¡à§‡à¦° নমà§à¦¬à¦° দেওয়া হয়নি? কপি করতে কারà§à¦¡à§‡à¦° বিবরণে কà§à¦²à¦¿à¦• করà§à¦¨</translation>
+<translation id="6279183038361895380">আপনার কারà§à¦¸à¦¾à¦° দেখাতে |<ph name="ACCELERATOR" />| চাপà§à¦¨</translation>
<translation id="6280223929691119688">à¦à¦‡ ঠিকানায় ডেলিভারি করা যাবে না। অনà§à¦¯ ঠিকানা বেছে নিন।</translation>
<translation id="6282194474023008486">পোসà§à¦Ÿà¦¾à¦² কোড</translation>
<translation id="6285507000506177184">Chrome বোতামে ডাউনলোড মà§à¦¯à¦¾à¦¨à§‡à¦œ করà§à¦¨, Chrome-ঠডাউনলোড করা ফাইল মà§à¦¯à¦¾à¦¨à§‡à¦œ করতে Enter পà§à¦°à§‡à¦¸ করà§à¦¨</translation>
@@ -1653,6 +1692,7 @@
<translation id="6290238015253830360">আপনার পà§à¦°à¦¸à§à¦¤à¦¾à¦¬à¦¿à¦¤ নিবনà§à¦§à¦—à§à¦²à¦¿ à¦à¦–ানে দেখা যাবে</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{আপনার ডিভাইস à¦à¦–নই রিসà§à¦Ÿà¦¾à¦°à§à¦Ÿ হবে}=1{১ সেকেনà§à¦¡ পরেই আপনার ডিভাইস রিসà§à¦Ÿà¦¾à¦°à§à¦Ÿ হবে}one{# সেকেনà§à¦¡ পরেই আপনার ডিভাইস রিসà§à¦Ÿà¦¾à¦°à§à¦Ÿ হবে}other{# সেকেনà§à¦¡ পরেই আপনার ডিভাইস রিসà§à¦Ÿà¦¾à¦°à§à¦Ÿ হবে}}</translation>
<translation id="6302269476990306341">Chrome-ঠGoogle অà§à¦¯à¦¾à¦¸à¦¿à¦¸à§à¦Ÿà§à¦¯à¦¾à¦¨à§à¦Ÿ à¦à¦¤à¦•à§à¦·à¦£ পরে বনà§à¦§ হয়ে যাবে:</translation>
<translation id="6305205051461490394"><ph name="URL" /> ঠপৌà¦à¦›à¦¾à¦¨à§‹ যাচà§à¦›à§‡ না</translation>
<translation id="6312113039770857350">Webpage not available</translation>
@@ -1726,6 +1766,7 @@
<translation id="6529602333819889595">&amp;মà§à¦›à§‡ ফেলাকে আবার করà§à¦¨</translation>
<translation id="6545864417968258051">বà§à¦²à§à¦Ÿà§à¦¥ সà§à¦•à§à¦¯à¦¾à¦¨à¦¿à¦‚</translation>
<translation id="6547208576736763147">বাà¦à¦¦à¦¿à¦•à§‡ ডà§à§Ÿà¦¾à¦² পাঞà§à¦š</translation>
+<translation id="6554732001434021288"><ph name="NUM_DAYS" /> দিন আগে শেষবার দেখেছেন</translation>
<translation id="6556866813142980365">আবার করà§à¦¨</translation>
<translation id="6569060085658103619">আপনি à¦à¦•à¦Ÿà¦¿ à¦à¦•à§à¦¸à¦Ÿà§‡à¦¨à¦¶à¦¨ পৃষà§à¦ à¦¾ দেখছেন</translation>
<translation id="6573200754375280815">ডানদিকে ডà§à§Ÿà¦¾à¦² পাঞà§à¦š</translation>
@@ -1786,7 +1827,6 @@
<translation id="6757797048963528358">আপনার ডিভাইস নিদà§à¦°à¦¾ মোডে গিয়েছে।</translation>
<translation id="6767985426384634228">ঠিকানা আপডেট করবেন?</translation>
<translation id="6768213884286397650">Hagaki (Postcard)</translation>
-<translation id="6774185088257932239">'ছদà§à¦®à¦¬à§‡à¦¶à§€' মোড সমà§à¦ªà¦°à§à¦•à§‡ <ph name="BEGIN_LINK" />আরও জানà§à¦¨<ph name="END_LINK" /></translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">বেগà§à¦¨à¦¿</translation>
<translation id="6786747875388722282">à¦à¦•à§à¦¸à¦Ÿà§‡à¦¨à¦¶à¦¾à¦¨à¦¸à¦®à§‚হ</translation>
@@ -1870,7 +1910,6 @@
<translation id="706295145388601875">Chrome সেটিংসে ঠিকানা যোগ ও মà§à¦¯à¦¾à¦¨à§‡à¦œ করà§à¦¨</translation>
<translation id="7064851114919012435">পরিচিতি তথà§à¦¯</translation>
<translation id="7068733155164172741"><ph name="OTP_LENGTH" />-সংখà§à¦¯à¦¾à¦° কোড লিখà§à¦¨</translation>
-<translation id="7070090581017165256">à¦à¦‡ সাইটের বিষয়ে</translation>
<translation id="70705239631109039">à¦à¦‡ কানেকশন সমà§à¦ªà§‚রà§à¦£à¦°à§‚পে নিরাপদ নয়</translation>
<translation id="7075452647191940183">অনà§à¦°à§‡à¦¾à¦§ অতà§à¦¯à¦¨à§à¦¤ বড়</translation>
<translation id="7079718277001814089">à¦à¦‡ সাইটটিতে মà§à¦¯à¦¾à¦²à¦“য়à§à¦¯à¦¾à¦° আছে</translation>
@@ -1887,6 +1926,12 @@
<translation id="7111012039238467737">(সঠিক)</translation>
<translation id="7118618213916969306">কà§à¦²à¦¿à¦ªà¦¬à§‹à¦°à§à¦¡ ইউআরà¦à¦² <ph name="SHORT_URL" /> সারà§à¦š করà§à¦¨</translation>
<translation id="7119414471315195487">অনà§à¦¯à¦¾à¦¨à§à¦¯ টà§à¦¯à¦¾à¦¬ বা পà§à¦°à§‹à¦—à§à¦°à¦¾à¦® বনà§à¦§ করà§à¦¨</translation>
+<translation id="7129355289156517987">অআপনি সমসà§à¦¤ Chromium ছদà§à¦®à¦¬à§‡à¦¶à§€ টà§à¦¯à¦¾à¦¬ বনà§à¦§ করলে, à¦à¦‡ ডিভাইস থেকে সেই টà§à¦¯à¦¾à¦¬à§‡ অà§à¦¯à¦¾à¦•à§à¦Ÿà¦¿à¦­à¦¿à¦Ÿà¦¿ মà§à¦›à§‡ যাবে:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />বà§à¦°à¦¾à¦‰à¦œà¦¿à¦‚ অà§à¦¯à¦¾à¦•à§à¦Ÿà¦¿à¦­à¦¿à¦Ÿà¦¿<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />সারà§à¦š ইতিহাস<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ফরà§à¦®à§‡ তথà§à¦¯ দেওয়া হয়েছে<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">à¦à¦‡ ঠিকানায় শিপিং করা যাবে না। অনà§à¦¯ ঠিকানা বেছে নিন।</translation>
<translation id="7132939140423847331">আপনার অà§à¦¯à¦¾à¦¡à¦®à¦¿à¦¨ à¦à¦‡ ডেটা কপি করার থেকে সীমাবদà§à¦§ করেছেন।</translation>
<translation id="7135130955892390533">সà§à¦Ÿà§à¦¯à¦¾à¦Ÿà¦¾à¦¸ দেখà§à¦¨</translation>
@@ -1909,6 +1954,7 @@
<translation id="7192203810768312527"><ph name="SIZE" /> জায়গা খালি করে। পরের বার যখন দেখবেন তখন কিছৠসাইট লোড হতে দেরি হতে পারে।</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">আপনার অà§à¦¯à¦¾à¦¡à¦®à¦¿à¦¨à¦¿à¦¸à§à¦Ÿà§à¦°à§‡à¦Ÿà¦° দেখতে পাবেন:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, গোপনে বà§à¦°à¦¾à¦‰à¦œà¦¿à¦‚য়ের জনà§à¦¯ নতà§à¦¨ ছদà§à¦®à¦¬à§‡à¦¶à§€ টà§à¦¯à¦¾à¦¬ খà§à¦²à¦¤à§‡ পà§à¦°à¦¥à¦®à§‡ Tab আর তারপরে Enter পà§à¦°à§‡à¦¸ করà§à¦¨</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> নিরাপতà§à¦¤à¦¾ মান মেনে চলে না।</translation>
<translation id="7210993021468939304">কনà§à¦Ÿà§‡à¦¨à¦¾à¦°à§‡à¦° মধà§à¦¯à§‡ Linux অà§à¦¯à¦¾à¦•à§à¦Ÿà¦¿à¦­à¦¿à¦Ÿà¦¿ দেখা যাবে à¦à¦¬à¦‚ কনà§à¦Ÿà§‡à¦¨à¦¾à¦°à§‡à¦° মধà§à¦¯à§‡à¦‡ Linux অà§à¦¯à¦¾à¦ª ইনসà§à¦Ÿà¦² করা ও চালানো যাবে</translation>
@@ -1940,6 +1986,7 @@
<translation id="7304562222803846232">Google অà§à¦¯à¦¾à¦•à¦¾à¦‰à¦¨à§à¦Ÿà§‡à¦° গোপনীয়তা সেটিংস মà§à¦¯à¦¾à¦¨à§‡à¦œ করà§à¦¨</translation>
<translation id="7305756307268530424">কম সà§à¦ªà¦¿à¦¡à§‡ শà§à¦°à§ করà§à¦¨</translation>
<translation id="7308436126008021607">বà§à¦¯à¦¾à¦•à¦—à§à¦°à¦¾à¦‰à¦¨à§à¦¡ সিঙà§à¦•</translation>
+<translation id="7310392214323165548">ডিভাইস খà§à¦¬ শীঘà§à¦°à¦‡ রিসà§à¦Ÿà¦¾à¦°à§à¦Ÿ হবে</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">কানেকশন সহায়তা</translation>
<translation id="7323804146520582233">"<ph name="SECTION" />" বিভাগ লà§à¦•à¦¾à¦¨</translation>
@@ -1947,6 +1994,7 @@
<translation id="7334320624316649418">&amp;পà§à¦¨à¦°à§à¦¬à¦¿à¦¨à§à¦¯à¦¾à¦¸à¦•à§‡ আবার করà§à¦¨</translation>
<translation id="7335157162773372339">কà§à¦¯à¦¾à¦®à§‡à¦°à¦¾ বà§à¦¯à¦¬à¦¹à¦¾à¦° করার অনà§à¦®à¦¤à¦¿ চাইতে পারে</translation>
<translation id="7337248890521463931">বেশি লাইন দেখà§à¦¨</translation>
+<translation id="7337418456231055214">ভারà§à¦šà§à§Ÿà¦¾à¦² কারà§à¦¡à§‡à¦° নমà§à¦¬à¦° দেওয়া হয়নি? কপি করতে কারà§à¦¡à§‡à¦° বিবরণে কà§à¦²à¦¿à¦• করà§à¦¨à¥¤ <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">আপনার পà§à¦²à§à¦¯à¦¾à¦Ÿà¦«à¦°à§à¦®à§‡ উপলভà§à¦¯ নেই।</translation>
<translation id="733923710415886693">সারà§à¦­à¦¾à¦°à§‡à¦° সারà§à¦Ÿà¦¿à¦«à¦¿à¦•à§‡à¦Ÿà¦Ÿà¦¿ সারà§à¦Ÿà¦¿à¦«à¦¿à¦•à§‡à¦Ÿà§‡à¦° সà§à¦¬à¦šà§à¦›à¦¤à¦¾à¦° মাধà§à¦¯à¦®à§‡ পà§à¦°à¦•à¦¾à¦¶ করা হয়নি।</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1969,6 +2017,7 @@
<translation id="7378627244592794276">না</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">পà§à¦°à¦¯à§‹à¦œà§à¦¯ নয়</translation>
+<translation id="7388594495505979117">{0,plural, =1{১ মিনিট পরেই আপনার ডিভাইস রিসà§à¦Ÿà¦¾à¦°à§à¦Ÿ হবে}one{# মিনিট পরেই আপনার ডিভাইস রিসà§à¦Ÿà¦¾à¦°à§à¦Ÿ হবে}other{# মিনিট পরেই আপনার ডিভাইস রিসà§à¦Ÿà¦¾à¦°à§à¦Ÿ হবে}}</translation>
<translation id="7390545607259442187">কারà§à¦¡ নিশà§à¦šà¦¿à¦¤ করà§à¦¨</translation>
<translation id="7392089738299859607">ঠিকানা আপডেট করà§à¦¨</translation>
<translation id="7399802613464275309">নিরাপতà§à¦¤à¦¾ পরীকà§à¦·à¦¾</translation>
@@ -2005,6 +2054,12 @@
<translation id="7485870689360869515">কোনো ডেটা পাওয়া যায়নি৷</translation>
<translation id="7495528107193238112">à¦à¦‡ কনà§à¦Ÿà§‡à¦¨à§à¦Ÿ বà§à¦²à¦• করা হয়েছে। à¦à¦‡ সমসà§à¦¯à¦¾à¦° সমাধান করতে সাইটের মালিকের সাথে যোগাযোগ করà§à¦¨à¥¤</translation>
<translation id="7497998058912824456">'Doc তৈরি করà§à¦¨ বোতাম', চটপট নতà§à¦¨ Google Doc তৈরি করতে Enter পà§à¦°à§‡à¦¸ করà§à¦¨</translation>
+<translation id="7506488012654002225">à¦à¦•à§à¦·à§‡à¦¤à§à¦°à§‡ নিচে দেওয়া তথà§à¦¯ Chromium <ph name="BEGIN_EMPHASIS" />সেভ করবে না<ph name="END_EMPHASIS" />:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />আপনার বà§à¦°à¦¾à¦‰à¦œà¦¿à¦‚ ইতিহাস
+ <ph name="LIST_ITEM" />কà§à¦•à¦¿ à¦à¦¬à¦‚ সাইট ডেটা
+ <ph name="LIST_ITEM" />ফরà§à¦®à§‡ লেখা তথà§à¦¯
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">ফিরে পাওয়া নীতির ডিভাইস আইডি খালি অথবা বরà§à¦¤à¦®à¦¾à¦¨ ডিভাইস আইডির সাথে মিলছে না</translation>
<translation id="7508870219247277067">অà§à¦¯à¦¾à¦­à§‹à¦•à¦¾à¦¡à§‹ সবà§à¦œ</translation>
<translation id="7511955381719512146">আপনি যে ওয়াই-ফাই-টি বà§à¦¯à¦¬à¦¹à¦¾à¦° করছেন সেটির জনà§à¦¯ অপনাকে <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />-তে যেতে হতে পারে৷</translation>
@@ -2118,7 +2173,6 @@
<translation id="7813600968533626083">Chrome থেকে ফরà§à¦® পà§à¦°à¦¸à§à¦¤à¦¾à¦¬à¦¨à¦¾ সরাবেন?</translation>
<translation id="781440967107097262">কà§à¦²à¦¿à¦ªà¦¬à§‹à¦°à§à¦¡ শেয়ার করবেন?</translation>
<translation id="7815407501681723534">'<ph name="SEARCH_STRING" />' à¦à¦° জনà§à¦¯ <ph name="NUMBER_OF_RESULTS" />টি <ph name="SEARCH_RESULTS" /> খà§à¦à¦œà§‡ পাওয়া গেছে</translation>
-<translation id="782125616001965242">à¦à¦‡ সাইটের বিষয়ে তথà§à¦¯ দেখà§à¦¨</translation>
<translation id="782886543891417279">আপনি যে (<ph name="WIFI_NAME" />) ওয়াই-ফাই বà§à¦¯à¦¬à¦¹à¦¾à¦° করছেন সেটির জনà§à¦¯ অপনাকে à¦à¦Ÿà¦¿à¦° লগ-ইন পৃষà§à¦ à¦¾à¦¤à§‡ যেতে হতে পরে৷</translation>
<translation id="7836231406687464395">Postfix (Envelope)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{à¦à¦•à¦Ÿà¦¿à¦“ নয়}=1{১টি অà§à¦¯à¦¾à¦ª (<ph name="EXAMPLE_APP_1" />)}=2{২টি অà§à¦¯à¦¾à¦ª (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}one{#টি অà§à¦¯à¦¾à¦ª (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" /> <ph name="AND_MORE" />)}other{#টি অà§à¦¯à¦¾à¦ª (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" /> <ph name="AND_MORE" />)}}</translation>
@@ -2135,7 +2189,6 @@
<translation id="7888575728750733395">পà§à¦°à¦¿à¦¨à§à¦Ÿ রেনà§à¦¡à¦¾à¦°à¦¿à¦‚ ইনটেনà§à¦Ÿ</translation>
<translation id="7894280532028510793">বানান সঠিক হলে, <ph name="BEGIN_LINK" />'নেটওয়ারà§à¦• ডায়াগনসà§à¦Ÿà¦¿à¦•' টà§à¦² চালিয়ে দেখà§à¦¨<ph name="END_LINK" />।</translation>
<translation id="7904208859782148177">C3 (Envelope)</translation>
-<translation id="7931318309563332511">অজানা</translation>
<translation id="793209273132572360">ঠিকানা আপডেট করবেন?</translation>
<translation id="7932579305932748336">কোট</translation>
<translation id="79338296614623784">à¦à¦•à¦Ÿà¦¿ সঠিক ফোন নমà§à¦¬à¦° লিখà§à¦¨</translation>
@@ -2160,13 +2213,14 @@
<translation id="7976214039405368314">অতà§à¦¯à¦§à¦¿à¦• অনà§à¦°à§‹à¦§</translation>
<translation id="7977538094055660992">আউটপà§à¦Ÿ ডিভাইস</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">à¦à¦° সাথে লিঙà§à¦• করা আছে</translation>
<translation id="798134797138789862">ভারà§à¦šà§à§Ÿà¦¾à¦² রিয়েলিটি ডিভাইস ও ডেটা বà§à¦¯à¦¬à¦¹à¦¾à¦° করতে অনà§à¦®à¦¤à¦¿ চাইতে পারে</translation>
<translation id="7984945080620862648">আপনি <ph name="SITE" /> ঠযেতে পারবেন না কারণ অসমà§à¦ªà§‚রà§à¦£ শংসাপতà§à¦° পাঠিয়েছে যেটি Chrome পà§à¦°à¦•à§à¦°à¦¿à§Ÿà¦¾ করতে পারে না। নেটওয়ারà§à¦• তà§à¦°à§à¦Ÿà¦¿ à¦à¦¬à¦‚ আকà§à¦°à¦®à¦£ সাধারণত সাময়িকভাবে হয়, তাই à¦à¦‡ পৃষà§à¦ à¦¾ সমà§à¦­à¦¬à¦¤ পরে কাজ করবে।</translation>
-<translation id="79859296434321399">অগমেনà§à¦Ÿà§‡à¦¡ রিয়েলিটি কনà§à¦Ÿà§‡à¦¨à§à¦Ÿ দেখার জনà§à¦¯ ARCore ইনসà§à¦Ÿà¦² করà§à¦¨</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">বাà¦à¦§à¦¾à¦‡</translation>
<translation id="7992044431894087211"><ph name="APPLICATION_TITLE" />-à¦à¦° সাথে আবার সà§à¦•à§à¦°à¦¿à¦¨ শেয়ার করা চালৠকরা হয়েছে</translation>
<translation id="7995512525968007366">নিরà§à¦¦à¦¿à¦·à§à¦Ÿ করে উলà§à¦²à§‡à¦– করা নেই</translation>
+<translation id="7998269595945679889">'ছদà§à¦®à¦¬à§‡à¦¶à§€ টà§à¦¯à¦¾à¦¬' বোতাম খà§à¦²à§à¦¨, গোপনে বà§à¦°à¦¾à¦‰à¦œà¦¿à¦‚য়ের জনà§à¦¯ নতà§à¦¨ ছদà§à¦®à¦¬à§‡à¦¶à§€ টà§à¦¯à¦¾à¦¬ খà§à¦²à¦¤à§‡ Enter পà§à¦°à§‡à¦¸ করà§à¦¨</translation>
<translation id="800218591365569300">মেমরি ফাà¦à¦•à¦¾ করতে অনà§à¦¯à¦¾à¦¨à§à¦¯ টà§à¦¯à¦¾à¦¬ বা পà§à¦°à§‹à¦—à§à¦°à¦¾à¦® বনà§à¦§ করার চেষà§à¦Ÿà¦¾ করà§à¦¨à¥¤</translation>
<translation id="8004582292198964060">বà§à¦°à¦¾à¦‰à¦œà¦¾à¦°</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{à¦à¦‡ কারà§à¦¡ ও সেটির বিলিং ঠিকানা সেভ করা হবে। <ph name="USER_EMAIL" />-ঠসাইন-ইন করে থাকা অবসà§à¦¥à¦¾à§Ÿ আপনি সেটি বà§à¦¯à¦¬à¦¹à¦¾à¦° করতে পারবেন।}one{à¦à¦‡ কারà§à¦¡à¦—à§à¦²à¦¿ ও সেগà§à¦²à¦¿à¦° বিলিং ঠিকানা সেভ করা হবে। <ph name="USER_EMAIL" />-ঠসাইন-ইন করে থাকা অবসà§à¦¥à¦¾à§Ÿ আপনি সেগà§à¦²à¦¿ বà§à¦¯à¦¬à¦¹à¦¾à¦° করতে পারবেন।}other{à¦à¦‡ কারà§à¦¡à¦—à§à¦²à¦¿ ও সেগà§à¦²à¦¿à¦° বিলিং ঠিকানা সেভ করা হবে। <ph name="USER_EMAIL" />-ঠসাইন-ইন করে থাকা অবসà§à¦¥à¦¾à§Ÿ আপনি সেগà§à¦²à¦¿ বà§à¦¯à¦¬à¦¹à¦¾à¦° করতে পারবেন।}}</translation>
@@ -2226,6 +2280,7 @@
<translation id="8202370299023114387">দà§à¦¬à¦¨à§à¦¦à§à¦¬</translation>
<translation id="8206978196348664717">Prc4 (Envelope)</translation>
<translation id="8211406090763984747">কানেকশনটি নিরাপদ</translation>
+<translation id="8217240300496046857">যেসব কà§à¦•à¦¿ ওয়েব জà§à¦¡à¦¼à§‡ আপনার অà§à¦¯à¦¾à¦•à§à¦Ÿà¦¿à¦­à¦¿à¦Ÿà¦¿ টà§à¦°à§à¦¯à¦¾à¦• করে, সাইট সেগà§à¦²à¦¿ বà§à¦¯à¦¬à¦¹à¦¾à¦° করতে পারবে না। কিছৠসাইটের ফিচার কাজ নাও করতে পারে।</translation>
<translation id="8218327578424803826">নিরà§à¦§à¦¾à¦°à¦¿à¦¤ লোকেশন:</translation>
<translation id="8220146938470311105">C7/C6 (Envelope)</translation>
<translation id="8225771182978767009">à¦à¦‡ কমà§à¦ªà¦¿à¦‰à¦Ÿà¦¾à¦° যিনি সেট-আপ করেছেন তিনি à¦à¦‡ সাইটটি অবরà§à¦¦à§à¦§ করার বিষয়টি চয়ন করেছেন।</translation>
@@ -2266,14 +2321,9 @@
<translation id="830498451218851433">অরà§à¦§à§‡à¦• ফোলà§à¦¡ করà§à¦¨</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">কোন কোন অà§à¦¯à¦¾à¦ª ইনসà§à¦Ÿà¦² করা আছে à¦à¦¬à¦‚ কত ঘন ঘন সেগà§à¦²à¦¿ বà§à¦¯à¦¬à¦¹à¦¾à¦° করা হয়েছে</translation>
+<translation id="8317207217658302555">ARCore আপডেট করবেন?</translation>
<translation id="831997045666694187">সনà§à¦§à§à¦¯à¦¾</translation>
<translation id="8321476692217554900">বিজà§à¦žà¦ªà§à¦¤à¦¿</translation>
-<translation id="8328484624016508118">সব 'ছদà§à¦®à¦¬à§‡à¦¶à§€' টà§à¦¯à¦¾à¦¬ বনà§à¦§ করার পরে, Chrome à¦à¦—à§à¦²à¦¿ মà§à¦›à§‡ ফেলে:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />à¦à¦‡ ডিভাইস থেকে আপনার বà§à¦°à¦¾à¦‰à¦œà¦¿à¦‚ অà§à¦¯à¦¾à¦•à§à¦Ÿà¦¿à¦­à¦¿à¦Ÿà¦¿<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />à¦à¦‡ ডিভাইস থেকে আপনার সারà§à¦š ইতিহাস<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />ফরà§à¦®à§‡ লেখা তথà§à¦¯<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489"><ph name="HOST_NAME" /> ঠঅà§à¦¯à¦¾à¦•à§à¦¸à§‡à¦¸ অসà§à¦¬à§€à¦•à¦¾à¦° করা হয়েছে</translation>
<translation id="833262891116910667">হাইলাইট</translation>
<translation id="8339163506404995330"><ph name="LANGUAGE" /> ভাষার পৃষà§à¦ à¦¾à¦° অনà§à¦¬à¦¾à¦¦ করা হবে না</translation>
@@ -2325,6 +2375,7 @@
<translation id="8507227106804027148">কমানà§à¦¡ লাইন</translation>
<translation id="8508648098325802031">সারà§à¦š আইকন</translation>
<translation id="8511402995811232419">কà§à¦•à¦¿ মà§à¦¯à¦¾à¦¨à§‡à¦œ করà§à¦¨</translation>
+<translation id="8519753333133776369">আপনার অà§à¦¯à¦¾à¦¡à¦®à¦¿à¦¨à¦¿à¦¸à§à¦Ÿà§à¦°à§‡à¦Ÿà¦° HID ডিভাইস বà§à¦¯à¦¬à¦¹à¦¾à¦°à§‡à¦° অনà§à¦®à¦¤à¦¿ দিয়েছেন</translation>
<translation id="8522552481199248698">পাসওয়ারà§à¦¡ পরিবরà§à¦¤à¦¨ করে আপনার Google অà§à¦¯à¦¾à¦•à¦¾à¦‰à¦¨à§à¦Ÿ সà§à¦°à¦•à§à¦·à¦¿à¦¤ রাখতে Chrome সাহাযà§à¦¯ করতে পারবে।</translation>
<translation id="8530813470445476232">Chrome সেটিংস থেকে আপনার বà§à¦°à¦¾à¦‰à¦œà¦¿à¦‚ ইতিহাস, কà§à¦•à¦¿, কà§à¦¯à¦¾à¦¶à§‡ ও আরও অনেক কিছৠমà§à¦›à§à¦¨</translation>
<translation id="8533619373899488139">বà§à¦²à¦• করা ইউআরà¦à¦²à§‡à¦° তালিকা à¦à¦¬à¦‚ আপনার সিসà§à¦Ÿà§‡à¦® অà§à¦¯à¦¾à¦¡à¦®à¦¿à¦¨à¦¿à¦¸à§à¦Ÿà§à¦°à§‡à¦Ÿà¦°à§‡à¦° পà§à¦°à§Ÿà§‹à¦— করা অনà§à¦¯à¦¾à¦¨à§à¦¯ নীতিগà§à¦²à¦¿ দেখার জনà§à¦¯ &lt;strong&gt;chrome://policy&lt;/strong&gt;-ঠযান।</translation>
@@ -2336,7 +2387,6 @@
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{অনà§à¦®à¦¤à¦¿ রিসেট করà§à¦¨}one{অনà§à¦®à¦¤à¦¿ রিসেট করà§à¦¨}other{অনà§à¦®à¦¤à¦¿ রিসেট করà§à¦¨}}</translation>
<translation id="8555010941760982128">চেকআউটের সময় à¦à¦‡ কোড বà§à¦¯à¦¬à¦¹à¦¾à¦° করà§à¦¨</translation>
<translation id="8557066899867184262">আপনার কারà§à¦¡à§‡à¦° পিছনে CVC ছবিটি আছে।</translation>
-<translation id="8558485628462305855">অগমেনà§à¦Ÿà§‡à¦¡ রিয়েলিটি কনà§à¦Ÿà§‡à¦¨à§à¦Ÿ দেখার জনà§à¦¯ ARCore আপডেট করà§à¦¨</translation>
<translation id="8559762987265718583"><ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> ঠà¦à¦•à¦Ÿà¦¿ বà§à¦¯à¦•à§à¦¤à¦¿à¦—ত সংযোগ সà§à¦¥à¦¾à¦ªà¦¨ করা যায়নি কারণ আপনার ডিভাইসের তারিখ à¦à¦¬à¦‚ সময় (<ph name="DATE_AND_TIME" />) সঠিক নয়৷</translation>
<translation id="8564182942834072828">আলাদা ডকà§à¦®à§‡à¦¨à§à¦Ÿ/সংগà§à¦°à¦¹ না করা কপি</translation>
<translation id="8564985650692024650">Chromium-à¦à¦° নীতি অনà§à¦¯à¦¾à§Ÿà§€ আপনার <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> পাসওয়ারà§à¦¡ বদলে ফেলা উচিত যদি আপনি সেটি অনà§à¦¯ কোনও সাইটে বà§à¦¯à¦¬à¦¹à¦¾à¦° করে থাকেন।</translation>
@@ -2355,6 +2405,7 @@
<translation id="865032292777205197">মোশন সেনà§à¦¸à¦°</translation>
<translation id="8663226718884576429">অরà§à¦¡à¦¾à¦°à§‡à¦° সারসংকà§à¦·à§‡à¦ª, <ph name="TOTAL_LABEL" />, আরও বিবরণ</translation>
<translation id="8666678546361132282">ইংরাজি</translation>
+<translation id="8669306706049782872">উইনà§à¦¡à§‹ খà§à¦²à§‡ রাখার জনà§à¦¯ আপনার সà§à¦•à§à¦°à¦¿à¦¨à§‡à¦° বিষয়ে তথà§à¦¯ বà§à¦¯à¦¬à¦¹à¦¾à¦° করà§à¦¨</translation>
<translation id="867224526087042813">সà§à¦¬à¦¾à¦•à§à¦·à¦°</translation>
<translation id="8676424191133491403">কোনও দেরি হয়নি</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, উতà§à¦¤à¦°, <ph name="ANSWER" /></translation>
@@ -2381,6 +2432,7 @@
<translation id="8731544501227493793">পাসওয়ারà§à¦¡ মà§à¦¯à¦¾à¦¨à§‡à¦œ করার বোতাম, Chrome সেটিংসে আপনার পাসওয়ারà§à¦¡ দেখতে ও মà§à¦¯à¦¾à¦¨à§‡à¦œ করতে Enter পà§à¦°à§‡à¦¸ করà§à¦¨</translation>
<translation id="8734529307927223492">আপনার <ph name="DEVICE_TYPE" />, <ph name="MANAGER" />-à¦à¦° মাধà§à¦¯à¦®à§‡ মà§à¦¯à¦¾à¦¨à§‡à¦œ করা হয়</translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, গোপনে বà§à¦°à¦¾à¦‰à¦œà¦¿à¦‚য়ের জনà§à¦¯ নতà§à¦¨ ছদà§à¦®à¦¬à§‡à¦¶à§€ উইনà§à¦¡à§‹ খà§à¦²à¦¤à§‡ পà§à¦°à¦¥à¦®à§‡ Tab আর তারপরে Enter পà§à¦°à§‡à¦¸ করà§à¦¨</translation>
+<translation id="8737685506611670901"><ph name="REPLACED_HANDLER_TITLE" />-à¦à¦° পরিবরà§à¦¤à§‡ <ph name="PROTOCOL" /> লিঙà§à¦•à¦¸à¦®à§‚হ খà§à¦²à§à¦¨</translation>
<translation id="8738058698779197622">নিরাপদ নেটওয়ারà§à¦• সংযোগ সà§à¦¥à¦¾à¦ªà¦¨ করতে আপনার ঘড়িকে সঠিকভাবে সেট করতে হবে৷ নিরাপদ সংযোগ সà§à¦¥à¦¾à¦ªà¦¨ করার জনà§à¦¯ নিজেদের শনাকà§à¦¤ করার জনà§à¦¯ ওয়েবসাইটগà§à¦²à¦¿ যে শংসাপতà§à¦°à¦—à§à¦²à¦¿ বà§à¦¯à¦¬à¦¹à¦¾à¦° করে, সেগà§à¦²à¦¿ শà§à¦§à§à¦®à¦¾à¦¤à§à¦° নিরà§à¦¦à¦¿à¦·à§à¦Ÿ সময়ের জনà§à¦¯ বৈধ থাকে৷ যেহেতৠআপনার ডিভাইসের ঘড়িটি ভà§à¦², সেই জনà§à¦¯ Chromium সঠিকভাবে শংসাপতà§à¦°à¦—à§à¦²à¦¿ পরীকà§à¦·à¦¾ করতে পারে না৷</translation>
<translation id="8740359287975076522"><ph name="HOST_NAME" /> à¦à¦° &lt;abbr id="ডিà¦à¦¨à¦à¦¸Definition"&gt;ডিà¦à¦¨à¦à¦¸ ঠিকানা&lt;/abbr&gt; পাওয়া যায়নি। সমসà§à¦¯à¦¾ নিরà§à¦£à§Ÿ করা হচà§à¦›à§‡à¥¤</translation>
<translation id="8742371904523228557"><ph name="ONE_TIME_CODE" /> হল আপনার <ph name="ORIGIN" />-à¦à¦° কোড</translation>
@@ -2408,6 +2460,7 @@
<translation id="883848425547221593">অনà§à¦¯à¦¾à¦¨à§à¦¯ বà§à¦•à¦®à¦¾à¦°à§à¦•</translation>
<translation id="884264119367021077">শিপিং ঠিকানা</translation>
<translation id="884923133447025588">কোন পà§à¦°à¦¤à§à¦¯à¦¾à¦¹à¦¾à¦° নিরà§à¦®à¦¾à¦£à¦•à§Œà¦¶à¦² পাওয়া যায় নি৷</translation>
+<translation id="8849262850971482943">অতিরিকà§à¦¤ সà§à¦°à¦•à§à¦·à¦¾à¦° জনà§à¦¯ আপনার ভারà§à¦šà§à§Ÿà¦¾à¦² কারà§à¦¡ বà§à¦¯à¦¬à¦¹à¦¾à¦° করà§à¦¨</translation>
<translation id="885730110891505394">Google à¦à¦° সাথে ভাগ করছে</translation>
<translation id="8858065207712248076">Chrome-à¦à¦° নীতি অনà§à¦¯à¦¾à§Ÿà§€ আপনার <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> পাসওয়ারà§à¦¡ বদলে ফেলা উচিত যদি আপনি সেটি অনà§à¦¯ কোনও সাইটে বà§à¦¯à¦¬à¦¹à¦¾à¦° করে থাকেন।</translation>
<translation id="885906927438988819">বানান সঠিক হলে, <ph name="BEGIN_LINK" />'Windows নেটওয়ারà§à¦• ডায়াগনসà§à¦Ÿà¦¿à¦•' টà§à¦² চালিয়ে দেখà§à¦¨<ph name="END_LINK" />।</translation>
@@ -2457,6 +2510,7 @@
<translation id="9004367719664099443">ভিআর (VR) সেশন চলছে</translation>
<translation id="9005998258318286617">পিডিà¦à¦« ডকà§à¦®à§‡à¦¨à§à¦Ÿ লোড করা যায়নি।</translation>
<translation id="9008201768610948239">উপেকà§à¦·à¦¾ করà§à¦¨</translation>
+<translation id="901834265349196618">ইমেল আইডি</translation>
<translation id="9020200922353704812">কারà§à¦¡à§‡à¦° বিলিং ঠিকানা পà§à¦°à¦¯à¦¼à§‹à¦œà¦¨</translation>
<translation id="9020542370529661692">à¦à¦‡ পৃষà§à¦ à¦¾à¦Ÿà¦¿ <ph name="TARGET_LANGUAGE" /> ঠঅনà§à¦¬à¦¾à¦¦ করা হয়েছে</translation>
<translation id="9020742383383852663">A8</translation>
@@ -2505,6 +2559,7 @@
<translation id="9150045010208374699">আপনার কà§à¦¯à¦¾à¦®à§‡à¦°à¦¾ বà§à¦¯à¦¬à¦¹à¦¾à¦° করà§à¦¨</translation>
<translation id="9150685862434908345">আপনার অà§à¦¯à¦¾à¦¡à¦®à¦¿à¦¨à¦¿à¦¸à§à¦Ÿà§à¦°à§‡à¦Ÿà¦° রিমোট লোকেশন থেকে আপনার বà§à¦°à¦¾à¦‰à¦œà¦¾à¦°à§‡à¦° সেটআপ পরিবরà§à¦¤à¦¨ করতে পারেন। তাছাড়া, à¦à¦‡ ডিভাইসের অà§à¦¯à¦¾à¦•à§à¦Ÿà¦¿à¦­à¦¿à¦Ÿà¦¿ Chrome-à¦à¦° বাইরে থেকেও মà§à¦¯à¦¾à¦¨à§‡à¦œ করা হতে পারে। <ph name="BEGIN_LINK" />আরও জানà§à¦¨<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">আপডেট রয়েছে</translation>
+<translation id="9155211586651734179">অডিও পেরিফেরাল অà§à¦¯à¦¾à¦Ÿà¦¾à¦š করা হয়েছে</translation>
<translation id="9157595877708044936">সেট-আপ হচà§à¦›à§‡...</translation>
<translation id="9158625974267017556">C6 (Envelope)</translation>
<translation id="9164029392738894042">আরও উনà§à¦¨à¦¤ করার জনà§à¦¯, দেওয়া পরামরà§à¦¶ যাচাই করা</translation>
diff --git a/chromium/components/strings/components_strings_bs.xtb b/chromium/components/strings/components_strings_bs.xtb
index 3b8ee5db8cf..b628caa56cd 100644
--- a/chromium/components/strings/components_strings_bs.xtb
+++ b/chromium/components/strings/components_strings_bs.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">Prikaži detalje</translation>
<translation id="1030706264415084469"><ph name="URL" /> želi trajno pohraniti veliku koliÄinu podataka na vaÅ¡ ureÄ‘aj</translation>
<translation id="1032854598605920125">Okreni u smjeru kretanja kazaljki na satu</translation>
+<translation id="1033329911862281889">Anonimnim naÄinom rada niste nevidljivi online:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Web lokacije i usluge koje koriste mogu vidjeti šta posjećujete.<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Poslodavci ili Å¡kole mogu pratiti aktivnost pregledanja.<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Pružaoci internetskih usluga mogu pratiti web saobraćaj.<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">IskljuÄi</translation>
<translation id="1036982837258183574">Pritisnite |<ph name="ACCELERATOR" />| da biste zatvorili prikaz na cijelom zaslonu</translation>
<translation id="1038106730571050514">Prikažite prijedloge</translation>
<translation id="1038842779957582377">nepoznato ime</translation>
<translation id="1041998700806130099">Poruka u tabeli za posao</translation>
<translation id="1048785276086539861">Kada uredite bilješke, ovaj dokument će se vratiti na prikaz na jednoj stranici</translation>
-<translation id="1049743911850919806">Anonimno</translation>
<translation id="1050038467049342496">Zatvorite druge aplikacije</translation>
<translation id="1055184225775184556">&amp;Poništi dodavanje</translation>
<translation id="1056898198331236512">Upozorenje</translation>
@@ -36,7 +41,7 @@
<translation id="1081061862829655580">Ladica 19</translation>
<translation id="1086953900555227778">Index-5x8</translation>
<translation id="1088860948719068836">Dodajte ime na karticu</translation>
-<translation id="1089439967362294234">Promijenite lozinku</translation>
+<translation id="1089439967362294234">Promijeni lozinku</translation>
<translation id="1096545575934602868">Ovo polje ne smije sadržavati viÅ¡e od sljedećeg broja unosa: <ph name="MAX_ITEMS_LIMIT" />. Svi daljnji unosi će biti odbaÄeni.</translation>
<translation id="1100782917270858593">Dugme za nastavak iskustva pregledanja, pritisnite Enter da nastavite pregledati te da vidite relevantne aktivnosti u historiji Chromea</translation>
<translation id="1101672080107056897">Postupak u sluÄaju greÅ¡ke</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">Keš memorija pravila UREDU</translation>
<translation id="1130564665089811311">Dugme Prevedi stranicu, pritisnite Enter da prevedete ovu stranicu pomoću Google Prevodioca</translation>
<translation id="1131264053432022307">Slika koju ste kopirali</translation>
+<translation id="1142846828089312304">Blokiraj kolaÄiće trećih strana u anonimnom naÄinu rada</translation>
<translation id="1150979032973867961">Ovaj server nije mogao potvrditi da je ovo domena <ph name="DOMAIN" />. Operativni sistem vaÅ¡eg raÄunara ne smatra njenu potvrdu sigurnosti pouzdanom. Uzrok tome može biti pogreÅ¡na konfiguracija ili napadaÄ koji je prekinuo vaÅ¡u vezu.</translation>
<translation id="1151972924205500581">Potrebna je lozinka</translation>
<translation id="1156303062776767266">Pregledate lokalni ili dijeljeni fajl</translation>
@@ -64,7 +70,6 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="1178581264944972037">Pauziraj</translation>
<translation id="1181037720776840403">Ukloni</translation>
<translation id="1186201132766001848">Provjeri lozinke</translation>
-<translation id="1195210374336998651">Idite u postavke aplikacije</translation>
<translation id="1195558154361252544">Obavještenja se automatski blokiraju za sve web lokacije osim onih koje omogućite</translation>
<translation id="1197088940767939838">Narandžasta</translation>
<translation id="1201402288615127009">Naprijed</translation>
@@ -111,7 +116,7 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="1307966114820526988">Zastarjele funkcije</translation>
<translation id="1308113895091915999">Dostupna je ponuda</translation>
<translation id="1312803275555673949">Koji dokazi idu tome u prilog?</translation>
-<translation id="131405271941274527"><ph name="URL" /> želi slati i primati informacije kada svojim telefonom dodirnete NFC uređaj</translation>
+<translation id="1314311879718644478">Pogledajte sadržaj proširene realnosti</translation>
<translation id="1314509827145471431">Povezivanje desne strane</translation>
<translation id="1318023360584041678">SaÄuvano je u grupu kartica</translation>
<translation id="1319245136674974084">Ne pitaj me više za ovu aplikaciju</translation>
@@ -161,6 +166,7 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="142858679511221695">Korisnik usluge u oblaku</translation>
<translation id="1428729058023778569">Ovo upozorenje vam se prikazuje jer ova web lokacija ne podržava HTTPS. <ph name="BEGIN_LEARN_MORE_LINK" />Saznajte više<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">Å tampaj</translation>
+<translation id="1432187715652018471">stranica želi instalirati obraÄ‘ivaÄa usluge.</translation>
<translation id="1432581352905426595">Upravljaj pretraživaÄima</translation>
<translation id="1436185428532214179">Može tražiti da uređuje fajlove i foldere na vašem uređaju</translation>
<translation id="1442386063175183758">Presavijanje s desne strane</translation>
@@ -181,6 +187,12 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="1483493594462132177">Pošalji</translation>
<translation id="1484290072879560759">Odaberite adresu za dostavu</translation>
<translation id="1492194039220927094">Slanje pravila:</translation>
+<translation id="149293076951187737">Kada zatvorite sve kartice u anonimnom naÄinu rada u Chromeu, vaÅ¡a aktivnost na tim karticama se briÅ¡e s ovog ureÄ‘aja:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />aktivnost pregledanja<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />historija pretraživanja<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />informacije unesene u obrasce<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">Natrag na karticu</translation>
<translation id="1501859676467574491">Prikažite kartice s Google raÄuna</translation>
<translation id="1507202001669085618">&lt;p&gt;Ova greška će se prikazati ako koristite WiFi portal na koji se morate prijaviti za povezivanje na internet.&lt;/p&gt;
@@ -208,6 +220,8 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="1559572115229829303">&lt;p&gt;Nije moguće uspostaviti privatnu vezu s domenom <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> jer datum i vrijeme (<ph name="DATE_AND_TIME" />) na vaÅ¡em ureÄ‘aju nisu taÄni.&lt;/p&gt;
&lt;p&gt;Podesite datum i vrijeme iz odjeljka &lt;strong&gt;Opće&lt;/strong&gt; u aplikaciji &lt;strong&gt;Postavke&lt;/strong&gt;.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">Vaš administrator će ponovo pokrenuti uređaj u <ph name="TIME" />, <ph name="DATE" /></translation>
+<translation id="156703335097561114">Informacije o umrežavanju, naprimjer adrese, konfiguracija interfejsa i kvalitet veze</translation>
<translation id="1567040042588613346">Ovo pravilo radi kako je predviđeno, ali je ista vrijednost postavljena negdje drugo i ovo pravilo ju je zaobišlo.</translation>
<translation id="1569487616857761740">Unesite datum isteka</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="1583429793053364125">Došlo je do problema prilikom prikazivanja ove web stranice.</translation>
<translation id="1586541204584340881">Koje ekstenzije ste instalirali</translation>
<translation id="1588438908519853928">Normalno</translation>
+<translation id="1589050138437146318">Instalirati ARCore?</translation>
<translation id="1592005682883173041">Pristup lokalnim podacima</translation>
<translation id="1594030484168838125">Odaberi</translation>
<translation id="160851722280695521">Igrajte igru Dino Run u Chromeu</translation>
@@ -283,6 +298,7 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
zaglavlje je neispravno Å¡to spreÄava preglednik da ispuni
vaš zahtjev za web lokaciju <ph name="SITE" />. Operateri web lokacija mogu koristiti izvorna pravila
za konfiguriranje sigurnosti i drugih osobina web lokacije.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Saznajte viÅ¡e o anonimnom naÄinu rada u Chromiumu<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">Ovdje se prikazuju vaše otvorene kartice</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -410,6 +426,7 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="22081806969704220">Ladica 3</translation>
<translation id="2212735316055980242">Pravilo nije pronađeno</translation>
<translation id="2213606439339815911">Dohvaćanje unosa...</translation>
+<translation id="2213612003795704869">Stranica je odštampana</translation>
<translation id="2215727959747642672">Uređivanje fajla</translation>
<translation id="2218879909401188352">NapadaÄi koji se trenutno nalaze na web lokaciji <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> mogu instalirati opasne aplikacije koje izazivaju oÅ¡tećenja vaÅ¡eg ureÄ‘aja, prouzrokuju skrivene troÅ¡kove na vaÅ¡em raÄunu za mobilnu mrežu ili kradu vaÅ¡e liÄne podatke. <ph name="BEGIN_LEARN_MORE_LINK" />Saznajte viÅ¡e<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">Nema internetske veze</translation>
@@ -419,6 +436,7 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="2248949050832152960">Koristi mrežnu provjeru autentiÄnosti</translation>
<translation id="2250931979407627383">Uvez uz desni rub</translation>
<translation id="225207911366869382">Ova vrijednost je zastarjela za ovo pravilo.</translation>
+<translation id="2256115617011615191">Ponovo pokreni sada</translation>
<translation id="2258928405015593961">Unesite datum isteka koji je u budućnosti i pokušajte ponovo</translation>
<translation id="225943865679747347">Kôd pogreške: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">HTTP greška</translation>
@@ -446,6 +464,7 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="2337852623177822836">Postavkom upravlja administrator</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> se želi upariti</translation>
<translation id="2346319942568447007">Slika koju ste kopirali</translation>
+<translation id="2350796302381711542">Dozvoliti da <ph name="HANDLER_HOSTNAME" /> otvori sve linkove za <ph name="PROTOCOL" /> umjesto obraÄ‘ivaÄa <ph name="REPLACED_HANDLER_TITLE" />?</translation>
<translation id="2354001756790975382">Ostale oznake</translation>
<translation id="2354430244986887761">Usluga Sigurno pregledanje na Googleu je nedavno <ph name="BEGIN_LINK" />pronašla štetne aplikacije <ph name="END_LINK" /> na web lokaciji <ph name="SITE" />.</translation>
<translation id="2355395290879513365">NapadaÄi mogu vidjeti slike koje gledate na ovoj web lokaciji i navesti vas da ih izmijenite.</translation>
@@ -471,6 +490,7 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="2413528052993050574">Ovaj server nije uspio dokazati da je <ph name="DOMAIN" />; možda je njegova potvrda sigurnosti opozvana. Uzrok tome može biti pogreÅ¡na konfiguracija ili napadaÄ koji je prekinuo vaÅ¡u vezu.</translation>
<translation id="2414886740292270097">Tamno</translation>
<translation id="2430968933669123598">Upravljajte Google raÄunom, pritisnite Enter da upravljate informacijama, privatnošću i sigurnošću na Google raÄunu</translation>
+<translation id="2436186046335138073">Dozvoliti da <ph name="HANDLER_HOSTNAME" /> otvori sve linkove za protokol <ph name="PROTOCOL" />?</translation>
<translation id="2438874542388153331">Četverostruko bušenje na desnoj strani</translation>
<translation id="2450021089947420533">Iskustva pregledanja</translation>
<translation id="2463739503403862330">Ispuni</translation>
@@ -478,6 +498,7 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="2465655957518002998">Odaberi naÄin isporuke</translation>
<translation id="2465688316154986572">Spajanje</translation>
<translation id="2465914000209955735">Upravljajte fajlovima koje ste preuzeli u Chromeu</translation>
+<translation id="2466004615675155314">Pogledajte informacije s interneta</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Pokrenuti dijagnostiku mreže<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">Redoslijed od 1 do N</translation>
<translation id="2470767536994572628">Kada uredite bilješke, ovaj dokument će se vratiti na prikaz na jednoj stranici i na svoju izvornu rotaciju</translation>
@@ -498,6 +519,7 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="2523886232349826891">SaÄuvano iskljuÄivo na ovom ureÄ‘aju</translation>
<translation id="2524461107774643265">Dodajte više informacija</translation>
<translation id="2529899080962247600">Ovo polje ne smije sadržavati više od sljedećeg broja unosa: <ph name="MAX_ITEMS_LIMIT" />. Svi daljnji unosi će se zanemariti.</translation>
+<translation id="2535585790302968248">Otvorite novu anonimnu karticu da privatno pregledate</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{i još 1}one{i još #}few{i još #}other{i još #}}</translation>
<translation id="2536110899380797252">Dodaj adresu</translation>
<translation id="2539524384386349900">Otkrij</translation>
@@ -523,7 +545,14 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="2597378329261239068">Ovaj dokument je zaštićen lozinkom. Unesite lozinku.</translation>
<translation id="2609632851001447353">Varijacije</translation>
<translation id="2610561535971892504">Kopiranje klikom</translation>
+<translation id="2617988307566202237">Chrome <ph name="BEGIN_EMPHASIS" />neće saÄuvati<ph name="END_EMPHASIS" /> sljedeće informacije:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />historiju pregledanja
+ <ph name="LIST_ITEM" />kolaÄiće i podatke web lokacije
+ <ph name="LIST_ITEM" />informacije unesene u obrasce
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (koverta)</translation>
+<translation id="2623663032199728144">Može tražiti da koristi informacije o vašim ekranima</translation>
<translation id="2625385379895617796">Sat ide unaprijed</translation>
<translation id="262745152991669301">Može tražiti da se poveže na USB uređaje</translation>
<translation id="2629325967560697240">Da postignete najviÅ¡i nivo sigurnosti Chromea, <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />ukljuÄite poboljÅ¡anu zaÅ¡titu<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -557,6 +586,7 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="2709516037105925701">Automatsko popunjavanje</translation>
<translation id="2713444072780614174">Bijela</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />. Pritisnite Tab, a nakon toga Enter da upravljate plaćanjima i informacijama o kreditnim karticama u postavkama Chromea</translation>
+<translation id="271663710482723385">Pritisnite |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| da zatvorite prikaz preko cijelog ekrana</translation>
<translation id="2721148159707890343">Zahtjev je uspio</translation>
<translation id="2723669454293168317">Pokrenite sigurnosnu provjeru u postavkama Chromea</translation>
<translation id="2726001110728089263">BoÄna ladica</translation>
@@ -587,6 +617,7 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="2850739647070081192">Invite (koverta)</translation>
<translation id="2856444702002559011">Moguće je da napadaÄi pokuÅ¡avaju ukrasti vaÅ¡e podatke s web lokacije <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (naprimjer, lozinke, poruke ili kreditne kartice). <ph name="BEGIN_LEARN_MORE_LINK" />Saznajte viÅ¡e<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">Ova web lokacija prikazuje nametljive ili obmanjujuće oglase.</translation>
+<translation id="286512204874376891">Virtuelna kartica kamuflira vašu stvarnu karticu radi zaštite od potencijalne prevare. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">Prijateljski</translation>
<translation id="2876489322757410363">NapuÅ¡tate anonimni naÄin rada radi plaćanja putem vanjske aplikacije. Nastaviti?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />, pritisnite Tab, a zatim Enter da upravljate Sigurnim pregledanjem i drugim funkcijama u postavkama Chromea</translation>
@@ -611,6 +642,7 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="2930577230479659665">Skraćivanje nakon svakog primjerka</translation>
<translation id="2932085390869194046">Predloži lozinku…</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019">Otvoriti linkove protokola <ph name="PROTOCOL" /></translation>
<translation id="2941952326391522266">Ovaj server nije uspio dokazati da je <ph name="DOMAIN" />. Njegova potvrda sigurnosti je s domene <ph name="DOMAIN2" />. Uzrok tome može biti pogreÅ¡na konfiguracija ili napadaÄ koji je prekinuo vaÅ¡u vezu.</translation>
<translation id="2943895734390379394">Vrijeme otpremanja:</translation>
<translation id="2948083400971632585">U Postavkama možete onemogućiti bilo koji proksi server koji je konfiguriran za povezivanje.</translation>
@@ -643,6 +675,7 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="3037605927509011580">Oh, ne!</translation>
<translation id="3041612393474885105">Informacije o potvrdi</translation>
<translation id="3044034790304486808">Nastavi istraživanje</translation>
+<translation id="305162504811187366">Historija Chrome udaljenog raÄunara, ukljuÄujući vremenske oznake, host raÄunare i ID-jeve sesija klijenta</translation>
<translation id="3060227939791841287">C9 (omotnica)</translation>
<translation id="3061707000357573562">Usluga za zakrpe</translation>
<translation id="306573536155379004">Igra je poÄela.</translation>
@@ -683,6 +716,7 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="3197136577151645743">Može tražiti da zna kada aktivno koristite ovaj uređaj</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />, pritisnite Tab, a zatim Enter da upravljate time koje ćete informacije sinhronizirati u postavkama Chromea</translation>
<translation id="320323717674993345">Otkaži plaćanje</translation>
+<translation id="3203366800380907218">S interneta</translation>
<translation id="3207960819495026254">OznaÄeno</translation>
<translation id="3209034400446768650">Stranica se možda naplaćuje</translation>
<translation id="3212581601480735796">Vaša aktivnost na <ph name="HOSTNAME" /> je pod nadzorom</translation>
@@ -699,10 +733,12 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="3234666976984236645">Uvijek detektiraj važan sadržaj s ove web lokacije</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />, pritisnite Tab, a zatim Enter da prilagodite izgled preglednika</translation>
<translation id="3240791268468473923">Otvorena je tabela obavještenja da nema akreditiva za sigurno plaćanje koji se podudaraju</translation>
+<translation id="324180406144491771">Linkovi hosta "<ph name="HOST_NAME" />" su blokirani</translation>
<translation id="3249845759089040423">Cool</translation>
<translation id="3252266817569339921">Francuska</translation>
<translation id="3257954757204451555">Ko stoji iza ovih informacija?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />, pritisnite Tab, a zatim Enter da brzo kreirate novi događaj u Google Kalendaru</translation>
+<translation id="3261488570342242926">Saznajte više o virtuelnim karticama</translation>
<translation id="3264837738038045344">Dugme za upravljanje postavkama Chromea, pritisnite Enter da posjetite postavke Chromea</translation>
<translation id="3266793032086590337">Vrijednost (konflikt)</translation>
<translation id="3268451620468152448">Otvorene kartice</translation>
@@ -716,6 +752,7 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="3288238092761586174"><ph name="URL" /> možda mora poduzeti dodatne korake da potvrdi vaše plaćanje</translation>
<translation id="3293642807462928945">Saznajte više o pravilu <ph name="POLICY_NAME" /></translation>
<translation id="3295444047715739395">Pregledajte lozinke i upravljajte njima u postavkama Chromea</translation>
+<translation id="3303795387212510132">Dozvoliti da aplikacija otvori linkove <ph name="PROTOCOL_SCHEME" />?</translation>
<translation id="3303855915957856445">Nije pronađen nijedan rezultat pretraživanja</translation>
<translation id="3304073249511302126">skeniranje Bluetootha</translation>
<translation id="3308006649705061278">Organizaciona jedinica (OU)</translation>
@@ -729,12 +766,6 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="3345782426586609320">OÄi</translation>
<translation id="3355823806454867987">Promijeni postavke proksi servera...</translation>
<translation id="3360103848165129075">Stranica obraÄ‘ivaÄa uplate</translation>
-<translation id="3361596688432910856">Chrome <ph name="BEGIN_EMPHASIS" />neće saÄuvati<ph name="END_EMPHASIS" /> sljedeće informacije:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Vašu historiju pregledanja
- <ph name="LIST_ITEM" />KolaÄiće i podatke o web lokacijama
- <ph name="LIST_ITEM" />Informacije koje unosite u obrasce
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">Ovo pravilo je automatski kopirano iz zastarjelog pravila <ph name="OLD_POLICY" />. Umjesto toga koristite ovo pravilo.</translation>
<translation id="3364869320075768271"><ph name="URL" /> želi koristiti vaš uređaj i podatke virtuelne realnosti</translation>
<translation id="3366477098757335611">Prikaži kartice</translation>
@@ -817,7 +848,6 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="3587738293690942763">Srednje</translation>
<translation id="3592413004129370115">Italijanska (koverta)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{Možete vratiti grupu na zadano kad god želite. Potreban je otprilike jedan dan da se pridružite novoj grupi.}=1{Možete vratiti grupu na zadano kad god želite. Potreban je otprilike jedan dan da se pridružite novoj grupi.}one{Možete vratiti grupu na zadano kad god želite. Potreban je otprilike {NUM_DAYS} dan da se pridružite novoj grupi.}few{Možete vratiti grupu na zadano kad god želite. Potrebna su otprilike {NUM_DAYS} dana da se pridružite novoj grupi.}other{Možete vratiti grupu na zadano kad god želite. Potrebno je otprilike {NUM_DAYS} dana da se pridružite novoj grupi.}}</translation>
-<translation id="3596012367874587041">Postavke aplikacije</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">Aplikaciju je blokirao vaš administrator</translation>
<translation id="3608932978122581043">Orijentacija sažetka sadržaja</translation>
@@ -860,8 +890,9 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="370972442370243704">UkljuÄi iskustva pregledanja</translation>
<translation id="3711895659073496551">Obustavi</translation>
<translation id="3712624925041724820">Licence su potrošene</translation>
+<translation id="3714633008798122362">web kalendar</translation>
<translation id="3714780639079136834">UkljuÄivanje prijenosa podataka na mobilnoj mreži ili WiFi-ja</translation>
-<translation id="3715597595485130451">Povežite se s WiFi mrežom</translation>
+<translation id="3715597595485130451">Povežite se s WiFi-jem</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />provjerite proxy, vatrozid i konfiguraciju DNS-a<ph name="END_LINK" /></translation>
<translation id="372429172604983730">Aplikacije koje mogu prouzroÄiti tu pogreÅ¡ku ukljuÄuju antivirusni softver, softver vatrozida ili proxyja ili softver za filtriranje weba.</translation>
<translation id="3727101516080730231"><ph name="CREATE_GOOGLE_SLIDE_FOCUSED_FRIENDLY_MATCH_TEXT" />, pritisnite Tab, a zatim Enter da brzo kreirate novu Google prezentaciju u Prezentacijama</translation>
@@ -921,6 +952,7 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="3906954721959377182">Tablet</translation>
<translation id="3909477809443608991">URL <ph name="URL" /> želi reproducirati zaštićeni sadržaj. Identitet vašeg uređaja će potvrditi Google i ova web lokacija mu može pristupiti.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">Odbij</translation>
<translation id="3939773374150895049">Koristiti mrežnu provjeru autentiÄnosti umjesto CVC-a?</translation>
<translation id="3946209740501886391">Uvijek pitaj na ovoj web lokaciji</translation>
<translation id="3947595700203588284">Može tražiti da se poveže na MIDI uređaje</translation>
@@ -942,6 +974,7 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="3990250421422698716">Odvajanje dokumenata</translation>
<translation id="3996311196211510766">Web lokacija <ph name="ORIGIN" /> je zatražila da se izvorno pravilo
primijeni na sve zahtjeve upućenje njoj, ali ovo se pravilo trenutno ne može primijeniti.</translation>
+<translation id="4009243425692662128">Sadržaj stranica koje štampate se šalje na analizu u Google Cloud ili trećim stranama. Naprimjer, može se skenirati radi otkrivanja postojanja osjetljivih podataka.</translation>
<translation id="4010758435855888356">Dozvoliti pristup pohrani?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{PDF dokument sadrži {COUNT} stranicu}one{PDF dokument sadrži {COUNT} stranicu}few{PDF dokument sadrži {COUNT} stranice}other{PDF dokument sadrži {COUNT} stranica}}</translation>
<translation id="4023431997072828269">Pošto se ovaj obrazac šalje vezom koja nije sigurna, vaši će podaci biti vidljivi drugima.</translation>
@@ -1036,6 +1069,7 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="4250680216510889253">Ne</translation>
<translation id="4253168017788158739">Napomena</translation>
<translation id="425582637250725228">Postoji mogućnost da se unesene promjene neće saÄuvati.</translation>
+<translation id="425869179292622354">PojaÄajte sigurnost s virtuelnom karticom?</translation>
<translation id="4258748452823770588">Nepravilan potpis</translation>
<translation id="4261046003697461417">Na zaštićenim dokumentima se ne mogu praviti bilješke</translation>
<translation id="4265872034478892965">Dozvolio vaš administrator</translation>
@@ -1098,6 +1132,7 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="4434045419905280838">SkoÄni proz. i preusmjeravanja</translation>
<translation id="4435702339979719576">Razglednica)</translation>
<translation id="443673843213245140">Korištenje proksi servera je onemogućeno ali je određena eksplicitna konfiguracija proksi servera.</translation>
+<translation id="4441832193888514600">Zanemareno jer se pravilo može postaviti samo kao korisniÄko pravilo oblaka.</translation>
<translation id="4450893287417543264">Ne prikazuj ponovo</translation>
<translation id="4451135742916150903">Može tražiti da se poveže na HID uređaje</translation>
<translation id="4452328064229197696">Lozinka koju ste upravo koristili pronaÄ‘ena je prilikom naruÅ¡avanja podataka. Da osigura vaÅ¡e raÄune, Googleov Upravitelj lozinki preporuÄuje da provjerite saÄuvane lozinke.</translation>
@@ -1153,6 +1188,7 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="4628948037717959914">Fotografija</translation>
<translation id="4631649115723685955">Usluga povrata novca je povezana</translation>
<translation id="4636930964841734540">Informacije</translation>
+<translation id="4638670630777875591">Anonimni naÄin rada u Chromiumu</translation>
<translation id="464342062220857295">Funkcije pretraživanja</translation>
<translation id="4644670975240021822">Obrnuti redoslijed s odštampanom stranom prema dolje</translation>
<translation id="4646534391647090355">Odvedi me tamo sada</translation>
@@ -1173,6 +1209,7 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="4708268264240856090">Vaša veza je prekinuta</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Pokrenuti Mrežnu dijagnostiku za Windows<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426">Lozinka za korisniÄko ime <ph name="USERNAME" /></translation>
<translation id="4724144314178270921">Može tražiti da vidi tekst i slike u međumemoriji</translation>
<translation id="4726672564094551039">Ponovo uÄitaj pravila</translation>
<translation id="4728558894243024398">Platforma</translation>
@@ -1194,6 +1231,7 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="4757993714154412917">Upravo ste unijeli lozinku na obmanjujućoj web lokaciji. Da zaÅ¡titite raÄune, Chromium preporuÄuje da provjerite saÄuvane lozinke.</translation>
<translation id="4758311279753947758">Dodaj informacije o kontaktu</translation>
<translation id="4761104368405085019">Korištenje vašeg mikrofona</translation>
+<translation id="4761869838909035636">Pokrenite Sigurnosnu provjeru Chromea</translation>
<translation id="4764776831041365478">Web-stranica na adresi <ph name="URL" /> možda privremeno nije dostupna ili je trajno preseljena na novu web-adresu.</translation>
<translation id="4766713847338118463">Dvostruko spajanje na donjoj strani</translation>
<translation id="4771973620359291008">Došlo je do nepoznate greške.</translation>
@@ -1214,12 +1252,6 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="4819347708020428563">Urediti bilješke u zadanom prikazu?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />, pritisnite Tab, a zatim Enter da brzo kreirate novu Google tabelu</translation>
<translation id="4825507807291741242">Snažno</translation>
-<translation id="4827402517081186284">Anonimni naÄin rada vas ne Äini nevidljivim online:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />web lokacije znaju kada ih posjetite<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />poslodavci ili Å¡kole mogu pratiti aktivnost pregledanja<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />pružaoci internet usluga mogu pratiti saobraćaj na internetu<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">UkljuÄi upozorenja</translation>
<translation id="4838327282952368871">Sanjivo</translation>
<translation id="4840250757394056958">Pregledajte historiju Chromea</translation>
@@ -1231,12 +1263,12 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="4854362297993841467">Taj naÄin dostave nije dostupan. PokuÅ¡ajte s nekim drugim naÄinom.</translation>
<translation id="4854853140771946034">Brzo kreirajte novu bilješku u Google Keepu</translation>
<translation id="485902285759009870">Potvrda koda...</translation>
+<translation id="4866506163384898554">Pritisnite |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| da prikažete kursor</translation>
<translation id="4876188919622883022">Pojednostavljeni prikaz</translation>
<translation id="4876305945144899064">Nema korisniÄkog imena</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{Ništa}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}one{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}few{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831">Pretraživanje <ph name="TEXT" /></translation>
<translation id="4879491255372875719">Automatski (zadano)</translation>
-<translation id="4879725228911483934">Otvarati i postavljati prozore na ekranima</translation>
<translation id="4880827082731008257">Pretraži povijest</translation>
<translation id="4881695831933465202">Otvori</translation>
<translation id="4885256590493466218">Platite karticom <ph name="CARD_DETAIL" /></translation>
@@ -1245,6 +1277,7 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">Deveta rolna</translation>
<translation id="4901778704868714008">SaÄuvaj...</translation>
+<translation id="4905659621780993806">VaÅ¡ administrator će ponovo pokrenuti ureÄ‘aj automatski u <ph name="TIME" /> <ph name="DATE" />. SaÄuvajte sve otvorene stavke prije ponovnog pokretanja ureÄ‘aja.</translation>
<translation id="4913987521957242411">Bušenje gornjeg lijevog ugla</translation>
<translation id="4918221908152712722">Instalirajte aplikaciju <ph name="APP_NAME" /> (nije potrebno preuzeti)</translation>
<translation id="4923459931733593730">Plaćanje</translation>
@@ -1253,6 +1286,7 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />. Pritisnite Tab, a zatim Enter da pretražujete</translation>
<translation id="4930153903256238152">Veliki kapacitet</translation>
+<translation id="4940163644868678279">Anonimni naÄin rada u Chromeu</translation>
<translation id="4943872375798546930">Nema rezultata</translation>
<translation id="4950898438188848926">Dugme za promjenu kartice; pritisnite Enter da se prebacite na otvorenu karticu, <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="495170559598752135">Radnje</translation>
@@ -1262,6 +1296,7 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="4968522289500246572">Ova aplikacija je dizajnirana za mobilne ureÄ‘aje i možda neće dobro promijeniti veliÄinu. Aplikacija može naići na probleme ili se ponovo pokrenuti.</translation>
<translation id="4969341057194253438">Izbrisati snimak?</translation>
<translation id="4973922308112707173">Dvostruko bušenje na gornjoj strani</translation>
+<translation id="4976702386844183910">Posljednji put je posjećeno <ph name="DATE" /></translation>
<translation id="4984088539114770594">Koristiti mikrofon?</translation>
<translation id="4984339528288761049">Prc5 (koverta)</translation>
<translation id="4989163558385430922">Prikaži sve</translation>
@@ -1323,6 +1358,7 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="5138227688689900538">Prikaži manje</translation>
<translation id="5145883236150621069">Odgovor na pravilo sadrži kÈd greÅ¡ke</translation>
<translation id="5146995429444047494">Obavještenja za <ph name="ORIGIN" /> su blokirana</translation>
+<translation id="514704532284964975"><ph name="URL" /> želi pregledati i mijenjati informacije na NFC uređajima koje dodirnete telefonom</translation>
<translation id="5148809049217731050">Odštampana strana prema gore</translation>
<translation id="515292512908731282">C4 (koverta)</translation>
<translation id="5158275234811857234">Naslovnica</translation>
@@ -1347,6 +1383,7 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="5215116848420601511">NaÄini plaćanja i adrese iz Google Paya</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">Ladica 13</translation>
+<translation id="5216942107514965959">Posljednji put je posjećeno danas</translation>
<translation id="5222812217790122047">Adresa e-pošte je obavezna</translation>
<translation id="5230733896359313003">Adresa za isporuku</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1367,7 +1404,6 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">Osobine dokumenta</translation>
<translation id="528468243742722775">Prekid</translation>
-<translation id="5284909709419567258">Mrežne adrese</translation>
<translation id="5285570108065881030">Prikaži sve saÄuvane lozinke</translation>
<translation id="5287240709317226393">Prikaži kolaÄiće</translation>
<translation id="5287456746628258573">Ova web lokacija koristi zastarjelu konfiguraciju sigurnosti, zbog Äega može doći do otkrivanja vaÅ¡ih informacija (naprimjer, lozinki ili brojeva kreditnih kartica) kada se Å¡alju na ovu web lokaciju.</translation>
@@ -1451,6 +1487,7 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="5556459405103347317">UÄitaj ponovo</translation>
<translation id="5560088892362098740">Rok trajanja</translation>
<translation id="55635442646131152">Pregled dokumenta</translation>
+<translation id="5565613213060953222">Otvori anonimnu karticu</translation>
<translation id="5565735124758917034">Aktivan</translation>
<translation id="5570825185877910964">ZaÅ¡titi raÄun</translation>
<translation id="5571083550517324815">Nije moguće preuzeti s ove adrese. Odaberite drugu adresu.</translation>
@@ -1533,6 +1570,7 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="5869522115854928033">SaÄuvane lozinke</translation>
<translation id="5873013647450402046">Vaša banka želi potvrditi vaš identitet.</translation>
<translation id="5887400589839399685">Kartica je spremljena</translation>
+<translation id="5887687176710214216">Posljednji put je posjećeno juÄer</translation>
<translation id="5895138241574237353">Ponovo pokreni</translation>
<translation id="5895187275912066135">Izdano</translation>
<translation id="5901630391730855834">Žuta</translation>
@@ -1546,6 +1584,7 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="5921639886840618607">SaÄuvati karticu na Google raÄunu?</translation>
<translation id="5922853866070715753">Skoro je gotovo</translation>
<translation id="5932224571077948991">Web-lokacija prikazuje ometajuće ili obmanjujuće oglase</translation>
+<translation id="5938153366081463283">Dodajte virtuelnu karticu</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347">Otvaranje web lokacije <ph name="SITE_NAME" />…</translation>
<translation id="5951495562196540101">Nije moguća prijava s potroÅ¡aÄkim raÄunom (dostupna je paketna licenca).</translation>
@@ -1610,6 +1649,7 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="6120179357481664955">Zapamtiti vaš UPI ID?</translation>
<translation id="6124432979022149706">Konektori Chromea za preduzeća</translation>
<translation id="6127379762771434464">Stavka je uklonjena</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Saznajte viÅ¡e o anonimnom naÄinu rada u Chromeu<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">Provjerite sve kablove i ponovo pokrenite sve rutere, modeme ili druge mrežne
uređaje koje koristite.</translation>
<translation id="614940544461990577">Pokušajte:</translation>
@@ -1622,7 +1662,6 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="6169916984152623906">Sada može pregledati privatno, a drugi korisnici ovog ureÄ‘aja neće vidjeti vaÅ¡u aktivnost. MeÄ‘utim, preuzimanja i oznake će se saÄuvati.</translation>
<translation id="6177128806592000436">Vaša veza s ovom web lokacijom nije sigurna</translation>
<translation id="6180316780098470077">Interval ponovnih pokušaja</translation>
-<translation id="619448280891863779">Može tražiti da otvori i postavi prozore na vašim ekranima</translation>
<translation id="6196640612572343990">Blokiraj kolaÄiće trećih strana</translation>
<translation id="6203231073485539293">Provjerite internetsku vezu</translation>
<translation id="6218753634732582820">Ukloniti adresu iz Chromiuma?</translation>
@@ -1645,7 +1684,7 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="6272383483618007430">Google Ažuriranje</translation>
<translation id="6276112860590028508">Stranice s vaÅ¡eg spiska za Äitanje će se pojaviti ovdje</translation>
<translation id="627746635834430766">Da sljedeći put brže izvrÅ¡ite plaćanje, saÄuvajte adresu kartice i adresu za naplatu na svoj Google raÄun.</translation>
-<translation id="6279098320682980337">Broj virtuelne kartice nije ispunjen? Kliknite na detalje kartice da ih kopirate</translation>
+<translation id="6279183038361895380">Pritisnite |<ph name="ACCELERATOR" />| da prikažete kursor</translation>
<translation id="6280223929691119688">Isporuka na ovu adresu nije moguća. Odaberite drugu adresu.</translation>
<translation id="6282194474023008486">Poštanski broj</translation>
<translation id="6285507000506177184">Dugme za upravljanje preuzimanjima u Chromeu, pritisnite Enter da upravljate fajlovima koje ste preuzeli u Chromeu</translation>
@@ -1653,6 +1692,7 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="6290238015253830360">Predloženi Älanci će se pojaviti ovdje</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{Uređaj će se sada ponovo pokrenuti}=1{Uređaj će se ponovo pokrenuti za 1 s}one{Uređaj će se ponovo pokrenuti za # s}few{Uređaj će se ponovo pokrenuti za # s}other{Uređaj će se ponovo pokrenuti za # s}}</translation>
<translation id="6302269476990306341">Zaustavljanje Google Asistenta u Chromeu</translation>
<translation id="6305205051461490394"><ph name="URL" /> je nedostupan.</translation>
<translation id="6312113039770857350">Web stranica nije dostupna</translation>
@@ -1726,6 +1766,7 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="6529602333819889595">&amp;Ponovi brisanje</translation>
<translation id="6545864417968258051">Skeniranje Bluetootha</translation>
<translation id="6547208576736763147">Dvostruko bušenje na lijevoj strani</translation>
+<translation id="6554732001434021288">Posljednji put je posjećeno prije <ph name="NUM_DAYS" /> dan(a)</translation>
<translation id="6556866813142980365">Ponovi</translation>
<translation id="6569060085658103619">Gledate stranicu s ekstenzijama</translation>
<translation id="6573200754375280815">Dvostruko bušenje na desnoj strani</translation>
@@ -1786,7 +1827,6 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="6757797048963528358">Vaš uređaj je u stanju mirovanja.</translation>
<translation id="6767985426384634228">Ažurirati adresu?</translation>
<translation id="6768213884286397650">Hagaki (dopisnica)</translation>
-<translation id="6774185088257932239"><ph name="BEGIN_LINK" />Saznajte viÅ¡e<ph name="END_LINK" /> o anonimnom naÄinu rada</translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">LjubiÄasta</translation>
<translation id="6786747875388722282">Ekstenzije</translation>
@@ -1870,7 +1910,6 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="706295145388601875">Dodajte adrese i upravljajte njima u postavkama Chromea</translation>
<translation id="7064851114919012435">Podaci za kontakt</translation>
<translation id="7068733155164172741">Unesite <ph name="OTP_LENGTH" />-cifreni kôd</translation>
-<translation id="7070090581017165256">O ovoj web lokaciji</translation>
<translation id="70705239631109039">Vaša veza nije u potpunosti sigurna</translation>
<translation id="7075452647191940183">Zahtjev je prevelik</translation>
<translation id="7079718277001814089">Ova web lokacija sadrži zlonamjeran softver</translation>
@@ -1887,6 +1926,12 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="7111012039238467737">(važeće)</translation>
<translation id="7118618213916969306">Traženje URL-a u međumemoriji, <ph name="SHORT_URL" /></translation>
<translation id="7119414471315195487">Zatvorite druge kartice ili programe</translation>
+<translation id="7129355289156517987">Kada zatvorite sve kartice u anonimnom naÄinu rada u Chromiumu, vaÅ¡a aktivnost na tim karticama se briÅ¡e s ovog ureÄ‘aja:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />aktivnost pregledanja<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />historija pretraživanja<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />informacije unesene u obrasce<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">Dostava na ovu adresu nije moguća. Odaberite drugu adresu.</translation>
<translation id="7132939140423847331">Vaš administrator je zabranio kopiranje ovih podataka.</translation>
<translation id="7135130955892390533">Prikaži status</translation>
@@ -1909,6 +1954,7 @@ To će u suprotnom biti blokirano prema vašim postavkama privatnosti. Ovo će o
<translation id="7192203810768312527">Oslobodit će se <ph name="SIZE" />. Neke web lokacije će se možda uÄitavati sporije kada ih posjetite sljedeći put.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">Administrator može vidjeti:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />. Pritisnite Tab, a zatim Enter da otvorite novu anonimnu karticu i da privatno pregledate</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> se ne pridržava sigurnosnih standarda.</translation>
<translation id="7210993021468939304">Aktivnost Linuxa se nalazi u spremniku i moguće je instalirati i pokrenuti Linux aplikacije unutar spremnika</translation>
@@ -1940,6 +1986,7 @@ Dodatni detalji:
<translation id="7304562222803846232">Upravljajte postavkama privatnosti Google raÄuna</translation>
<translation id="7305756307268530424">PoÄni sporije</translation>
<translation id="7308436126008021607">sinhronizacija u pozadini</translation>
+<translation id="7310392214323165548">Uređaj će se veoma brzo ponovo pokrenuti</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">Pomoć s povezivanjem</translation>
<translation id="7323804146520582233">Sakrij odjeljak "<ph name="SECTION" />"</translation>
@@ -1947,6 +1994,7 @@ Dodatni detalji:
<translation id="7334320624316649418">&amp;Ponovi preuređivanje</translation>
<translation id="7335157162773372339">Može tražiti da koristi kameru</translation>
<translation id="7337248890521463931">Prikaži više redova</translation>
+<translation id="7337418456231055214">Broj virtuelne kartice nije ispunjen? Kliknite na detalje kartice da ih kopirate. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">Nije dostupno na vašoj platformi.</translation>
<translation id="733923710415886693">Potvrda servera nije otkrivena korištenjem pravila o transparentnosti potvrde.</translation>
<translation id="734600844861828519">11 x 15</translation>
@@ -1969,6 +2017,7 @@ Dodatni detalji:
<translation id="7378627244592794276">Ne</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">Nije primjenjivo</translation>
+<translation id="7388594495505979117">{0,plural, =1{Uređaj će se ponovo pokrenuti za 1 min}one{Uređaj će se ponovo pokrenuti za # min}few{Uređaj će se ponovo pokrenuti za # min}other{Uređaj će se ponovo pokrenuti za # min}}</translation>
<translation id="7390545607259442187">Potvrdite karticu</translation>
<translation id="7392089738299859607">Ažurirajte adresu</translation>
<translation id="7399802613464275309">Sigurnosna provjera</translation>
@@ -2005,6 +2054,12 @@ Dodatni detalji:
<translation id="7485870689360869515">Nije pronađen nijedan rezultat.</translation>
<translation id="7495528107193238112">Ovaj sadržaj je blokiran. Kontaktirajte vlasnika web lokacije da riješite problem.</translation>
<translation id="7497998058912824456">Dugme Kreiraj dokument, pritisnite Enter da brzo kreirate novi Google dokument</translation>
+<translation id="7506488012654002225">Chromium <ph name="BEGIN_EMPHASIS" />neće saÄuvati<ph name="END_EMPHASIS" /> sljedeće informacije:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />historiju pregledanja
+ <ph name="LIST_ITEM" />kolaÄiće i podatke web lokacije
+ <ph name="LIST_ITEM" />informacije unesene u obrasce
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">Vraćeni ID uređaja pravila ne postoji ili ne odgovara trenutnom ID-u uređaja</translation>
<translation id="7508870219247277067">Avokado zelena</translation>
<translation id="7511955381719512146">WiFi koji koristite može od vas tražiti da posjetite <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
@@ -2118,7 +2173,6 @@ Dodatni detalji:
<translation id="7813600968533626083">Ukloniti prijedlog obrasca iz Chromea?</translation>
<translation id="781440967107097262">Dijeliti međumemoriju?</translation>
<translation id="7815407501681723534">Pronađeno <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> za "<ph name="SEARCH_STRING" />"</translation>
-<translation id="782125616001965242">Pogledajte informacije o ovoj web lokaciji</translation>
<translation id="782886543891417279">WiFi koji koristite (<ph name="WIFI_NAME" />) može zahtijevati da posjetite stranicu za prijavu.</translation>
<translation id="7836231406687464395">Postfix (koverta)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{Ništa}=1{1 aplikacija (<ph name="EXAMPLE_APP_1" />)}=2{2 aplikacije (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}one{# aplikacija (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}few{# aplikacije (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}other{# aplikacija (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}}</translation>
@@ -2135,7 +2189,6 @@ Dodatni detalji:
<translation id="7888575728750733395">Å tampanje namjere iscrtavanja</translation>
<translation id="7894280532028510793">Ako nema greške u pravopisu, <ph name="BEGIN_LINK" />pokušajte pokrenuti Dijagnostiku mreže<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (koverta)</translation>
-<translation id="7931318309563332511">Nepoznato</translation>
<translation id="793209273132572360">Ažurirati adresu?</translation>
<translation id="7932579305932748336">Premaz</translation>
<translation id="79338296614623784">Unesite važeći broj telefona</translation>
@@ -2160,13 +2213,14 @@ Dodatni detalji:
<translation id="7976214039405368314">Previše zahtjeva</translation>
<translation id="7977538094055660992">Izlazni uređaj</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">Povezani ste sa</translation>
<translation id="798134797138789862">Može tražiti da koristi uređaje i podatke virtuelne realnosti</translation>
<translation id="7984945080620862648">TrenutaÄno ne možete posjetiti <ph name="SITE" /> jer je web-lokacija poslala kodirane vjerodajnice koje Chrome ne može obraditi. Mrežne pogreÅ¡ke i napadi uglavnom su privremeni, tako da će ta stranica vjerojatno kasnije funkcionirati.</translation>
-<translation id="79859296434321399">Instalirajte ARCore da vidite sadržaj proširene realnosti</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">Povezivanje</translation>
<translation id="7992044431894087211">Dijeljenje ekrana s aplikacijom <ph name="APPLICATION_TITLE" /> je nastavljeno</translation>
<translation id="7995512525968007366">Nije navedeno</translation>
+<translation id="7998269595945679889">Dugme Otvori anonimnu karticu, pritisnite Enter da otvorite novu anonimnu karticu i da privatno pregledate</translation>
<translation id="800218591365569300">Pokušajte zatvoriti druge kartice ili programe da oslobodite memoriju.</translation>
<translation id="8004582292198964060">Preglednik</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{Ova kartica će se saÄuvati kao i njena povezana adresa za naplatu. Moći ćete je koristiti kada se prijavite na raÄun <ph name="USER_EMAIL" />.}one{Ove kartice će se saÄuvati kao i njihove povezane adrese za naplatu. Moći ćete ih koristiti kada se prijavite na raÄun <ph name="USER_EMAIL" />.}few{Ove kartice će se saÄuvati kao i njihove povezane adrese za naplatu. Moći ćete ih koristiti kada se prijavite na raÄun <ph name="USER_EMAIL" />.}other{Ove kartice će se saÄuvati kao i njihove povezane adrese za naplatu. Moći ćete ih koristiti kada se prijavite na raÄun <ph name="USER_EMAIL" />.}}</translation>
@@ -2195,7 +2249,7 @@ Dodatni detalji:
<translation id="8079031581361219619">Ponovo uÄitati web lokaciju?</translation>
<translation id="8086971161893892807">Nedovršena verzija</translation>
<translation id="8088680233425245692">Prikazivanje Älanka nije uspjelo.</translation>
-<translation id="808894953321890993">Promijenite lozinku</translation>
+<translation id="808894953321890993">Promijeni lozinku</translation>
<translation id="8090403583893450254">VeliÄina 20</translation>
<translation id="8091372947890762290">Aktivacija je na Äekanju na serveru</translation>
<translation id="8092774999298748321">Zagasito ljubiÄasta</translation>
@@ -2226,6 +2280,7 @@ Dodatni detalji:
<translation id="8202370299023114387">Neslaganje</translation>
<translation id="8206978196348664717">Prc4 (koverta)</translation>
<translation id="8211406090763984747">Veza je sigurna</translation>
+<translation id="8217240300496046857">Web lokacije ne mogu koristiti kolaÄiće koji vas prate na webu. Moguće je da će funkcije na nekim web lokacijama prestati s radom.</translation>
<translation id="8218327578424803826">Dodijeljena lokacija:</translation>
<translation id="8220146938470311105">C7/C6 (koverta)</translation>
<translation id="8225771182978767009">Osoba koja je postavila raÄunalo blokirala je tu web-lokaciju.</translation>
@@ -2266,14 +2321,9 @@ Dodatni detalji:
<translation id="830498451218851433">Presavijanje napola</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">Instalirane aplikacije i koliko Äesto se koriste</translation>
+<translation id="8317207217658302555">Ažurirati ARCore?</translation>
<translation id="831997045666694187">VeÄer</translation>
<translation id="8321476692217554900">obavještenja</translation>
-<translation id="8328484624016508118">Nakon što zatvorite sve anonimne kartice, Chrome će obrisati:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />vašu aktivnost pregledanja s ovog uređaja<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />vašu historiju pretraživanja s ovog uređaja<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />informacije unesene u obrasce<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489">Pristup host raÄunaru <ph name="HOST_NAME" /> je zabranjen</translation>
<translation id="833262891116910667">Istaknuto</translation>
<translation id="8339163506404995330">Stranice Äiji je jezik <ph name="LANGUAGE" /> neće se prevoditi</translation>
@@ -2325,6 +2375,7 @@ Dodatni detalji:
<translation id="8507227106804027148">Komandna linija</translation>
<translation id="8508648098325802031">Ikona pretraživanja</translation>
<translation id="8511402995811232419">Upravljajte kolaÄićima</translation>
+<translation id="8519753333133776369">HID uređaj koji je dozvolio vaš administrator</translation>
<translation id="8522552481199248698">Chrome vam može pomoći da zaÅ¡titite svoj Google raÄun i promijenite lozinku.</translation>
<translation id="8530813470445476232">IzbriÅ¡ite historiju pregledanja, kolaÄiće, keÅ¡ memoriju i drugo u postavkama Chromea</translation>
<translation id="8533619373899488139">Posjetite &lt;strong&gt;chrome://policy&lt;/strong&gt; da vidite listu blokiranih URL-ova i druga pravila koja je nametnuo vaš administrator sistema.</translation>
@@ -2336,7 +2387,6 @@ Dodatni detalji:
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{Poništi odobrenje}one{Poništi odobrenja}few{Poništi odobrenja}other{Poništi odobrenja}}</translation>
<translation id="8555010941760982128">Koristite ovaj kôd prilikom nastavka na plaćanje</translation>
<translation id="8557066899867184262">CVC se nalazi na poleđini vaše kartice.</translation>
-<translation id="8558485628462305855">Za prikaz sadržaja proširene realnosti ažurirajte ARCore</translation>
<translation id="8559762987265718583">Nije moguće uspostaviti privatnu vezu s domenom <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> jer datum i vrijeme (<ph name="DATE_AND_TIME" />) na vaÅ¡em ureÄ‘aju nisu taÄni.</translation>
<translation id="8564182942834072828">Zasebni dokumenti/nerazvrstane kopije</translation>
<translation id="8564985650692024650">Chromium preporuÄuje da poniÅ¡tite lozinku za <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> ako ste je ponovo koristili na drugim web lokacijama.</translation>
@@ -2355,6 +2405,7 @@ Dodatni detalji:
<translation id="865032292777205197">senzori kretanja</translation>
<translation id="8663226718884576429">Sažetak narudžbe, <ph name="TOTAL_LABEL" />, više detalja</translation>
<translation id="8666678546361132282">Engleski</translation>
+<translation id="8669306706049782872">Koristi informacije o vašim ekranima radi otvaranja i postavljanja prozora</translation>
<translation id="867224526087042813">Potpis</translation>
<translation id="8676424191133491403">Bez odgode</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, odgovor, <ph name="ANSWER" /></translation>
@@ -2381,6 +2432,7 @@ Dodatni detalji:
<translation id="8731544501227493793">Dugme Upravljaj lozinkama, pritisnite Enter da pregledate lozinke i upravljate njima u postavkama Chromea</translation>
<translation id="8734529307927223492">Uređajem <ph name="DEVICE_TYPE" /> upravlja <ph name="MANAGER" /></translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />. Pritisnite Tab, a zatim Enter da otvorite novi anonimni prozor i da privatno pregledate</translation>
+<translation id="8737685506611670901">Otvaranje linkova protokola <ph name="PROTOCOL" /> umjesto obraÄ‘ivaÄa <ph name="REPLACED_HANDLER_TITLE" /></translation>
<translation id="8738058698779197622">Ispravno podesite sat da uspostavite sigurnu vezu. Razlog tome je taj što su certifikati koji web lokacije koriste da se identificiraju valjane samo na određeni period. Kako sat na vašem uređaju nije ispravan, Chromium ne može provjeriti ove certifikate.</translation>
<translation id="8740359287975076522">Nije moguće pronaći &lt;abbr id="dnsDefinition"&gt;DNS adresu&lt;/abbr&gt; host raÄunara <ph name="HOST_NAME" />. Dijagnosticiranje problema.</translation>
<translation id="8742371904523228557"><ph name="ONE_TIME_CODE" /> je vaš kôd za <ph name="ORIGIN" /></translation>
@@ -2408,6 +2460,7 @@ Dodatni detalji:
<translation id="883848425547221593">Ostale oznake</translation>
<translation id="884264119367021077">Adresa za isporuku</translation>
<translation id="884923133447025588">Nije pronađen nijedan mehanizam za opoziv.</translation>
+<translation id="8849262850971482943">Koristite virtuelnu karticu radi dodatne sigurnosti</translation>
<translation id="885730110891505394">Dijeljenje s Googleom</translation>
<translation id="8858065207712248076">Chrome preporuÄuje ponovno postavljanje lozinke za <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> ako sto je ponovo koristili na drugim web lokacijama.</translation>
<translation id="885906927438988819">Ako nema greške u pravopisu, <ph name="BEGIN_LINK" />pokušajte pokrenuti Windows dijagnostiku mreže<ph name="END_LINK" />.</translation>
@@ -2457,6 +2510,7 @@ Dodatni detalji:
<translation id="9004367719664099443">VR sesija je u toku</translation>
<translation id="9005998258318286617">UÄitavanje PDF dokumenta nije uspjelo.</translation>
<translation id="9008201768610948239">Zanemari</translation>
+<translation id="901834265349196618">e-pošta</translation>
<translation id="9020200922353704812">Potrebna je adresa za naplatu kartice</translation>
<translation id="9020542370529661692">Ova stranica je prevedena na <ph name="TARGET_LANGUAGE" /> jezik</translation>
<translation id="9020742383383852663">A8</translation>
@@ -2467,7 +2521,7 @@ Dodatni detalji:
<translation id="9036306139374661733">Dozvoliti mikrofon?</translation>
<translation id="9038649477754266430">Upotreba usluge predviÄ‘anja za brže uÄitavanje stranica</translation>
<translation id="9039213469156557790">Dalje, ova stranica obuhvata druge resurse koji nisu sigurni. Te resurse mogu vidjeti drugi dok su u tranzitu, a može ih izmijeniti napadaÄ kako bi promijenio ponaÅ¡anje stranice.</translation>
-<translation id="9040464167025094690">Dugme za funkciju PronaÄ‘i moj ureÄ‘aj, pritisnite Enter da posjetite funkciju PronaÄ‘i moj ureÄ‘aj na Google raÄunu</translation>
+<translation id="9040464167025094690">Dugme PronaÄ‘i moj ureÄ‘aj, pritisnite Enter da otvorite uslugu PronaÄ‘i moj ureÄ‘aj na Google raÄunu</translation>
<translation id="9042617223719777575">Veliki kapacitet</translation>
<translation id="9044359186343685026">Koristi Touch ID</translation>
<translation id="9045525010788763347"><ph name="RESULT_MODIFIED_DATE" /> – <ph name="RESULT_PRODUCT_SOURCE" /></translation>
@@ -2505,6 +2559,7 @@ Dodatni detalji:
<translation id="9150045010208374699">Korištenje kamere</translation>
<translation id="9150685862434908345">Vaš administrator može promijeniti postavke preglednika daljinskim putem. Aktivnostima na ovom uređaju se može upravljati i van Chromea. <ph name="BEGIN_LINK" />Saznajte više<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">Ažurirano</translation>
+<translation id="9155211586651734179">Povezane periferne zvuÄne ureÄ‘aje</translation>
<translation id="9157595877708044936">Postavljanje...</translation>
<translation id="9158625974267017556">C6 (koverta)</translation>
<translation id="9164029392738894042">Provjera taÄnosti</translation>
diff --git a/chromium/components/strings/components_strings_ca.xtb b/chromium/components/strings/components_strings_ca.xtb
index 21d5e312029..f4e6cc22951 100644
--- a/chromium/components/strings/components_strings_ca.xtb
+++ b/chromium/components/strings/components_strings_ca.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">Mostra els detalls</translation>
<translation id="1030706264415084469"><ph name="URL" /> vol emmagatzemar una gran quantitat de dades al dispositiu de manera permanent</translation>
<translation id="1032854598605920125">Gira en sentit horari</translation>
+<translation id="1033329911862281889">Amb el mode d'incògnit no ets invisible en línia:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Els llocs web i els serveis que utilitzen poden veure les visites.<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Les empreses o els centres educatius poden fer el seguiment de l'activitat de navegació.<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Els proveïdors d'Internet poden monitorar el trànsit web.<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">Desactiva</translation>
<translation id="1036982837258183574">Premeu |<ph name="ACCELERATOR" />| per sortir de la pantalla completa</translation>
<translation id="1038106730571050514">Mostra els suggeriments</translation>
<translation id="1038842779957582377">nom desconegut</translation>
<translation id="1041998700806130099">Missatge del full de treball</translation>
<translation id="1048785276086539861">Quan editis anotacions, aquest document tornarà a la visualització d'una sola pàgina</translation>
-<translation id="1049743911850919806">Incògnit</translation>
<translation id="1050038467049342496">Tanca altres aplicacions</translation>
<translation id="1055184225775184556">&amp;Desfés l'addició</translation>
<translation id="1056898198331236512">Advertiment</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">La memòria cau de la política està en bon estat</translation>
<translation id="1130564665089811311">Botó Tradueix la pàgina; prem Retorn per traduir aquesta pàgina amb el Traductor de Google</translation>
<translation id="1131264053432022307">Imatge que has copiat</translation>
+<translation id="1142846828089312304">Bloqueja les galetes de tercers en mode d'incògnit</translation>
<translation id="1150979032973867961">Aquest servidor no ha pogut comprovar que sigui <ph name="DOMAIN" /> perquè el sistema operatiu del vostre ordinador considera que el seu certificat de seguretat no és de confiança. Això pot ser a causa d'una configuració incorrecta o d'un atacant que intercepta la vostra connexió.</translation>
<translation id="1151972924205500581">Es requereix una contrasenya</translation>
<translation id="1156303062776767266">Estàs consultant un fitxer local o compartit</translation>
@@ -64,7 +70,6 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="1178581264944972037">Posa en pausa</translation>
<translation id="1181037720776840403">Suprimeix</translation>
<translation id="1186201132766001848">Comprova les contrasenyes</translation>
-<translation id="1195210374336998651">Ves a la configuració de l'aplicació</translation>
<translation id="1195558154361252544">Les notificacions de tots els llocs web estan bloquejades automàticament excepte les que permetis</translation>
<translation id="1197088940767939838">Taronja</translation>
<translation id="1201402288615127009">Següent</translation>
@@ -111,7 +116,7 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="1307966114820526988">Funcions obsoletes</translation>
<translation id="1308113895091915999">Oferta disponible</translation>
<translation id="1312803275555673949">Quines proves hi ha?</translation>
-<translation id="131405271941274527"><ph name="URL" /> vol enviar i rebre informació quan el teu telèfon toca un dispositiu NFC</translation>
+<translation id="1314311879718644478">Mostra el contingut de realitat augmentada</translation>
<translation id="1314509827145471431">Enquadernació a la dreta</translation>
<translation id="1318023360584041678">S'ha desat al grup de pestanyes</translation>
<translation id="1319245136674974084">No ho tornis a preguntar per a aquesta aplicació</translation>
@@ -161,6 +166,7 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="142858679511221695">Usuari al núvol</translation>
<translation id="1428729058023778569">Estàs veient aquest advertiment perquè aquest lloc web no admet HTTPS. <ph name="BEGIN_LEARN_MORE_LINK" />Més informació<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">Imprimeix</translation>
+<translation id="1432187715652018471">La pàgina vol instal·lar un gestor de serveis</translation>
<translation id="1432581352905426595">Gestiona els motors de cerca</translation>
<translation id="1436185428532214179">Pot demanar permís per editar fitxers i carpetes del dispositiu</translation>
<translation id="1442386063175183758">Plegat amb finestra a la dreta</translation>
@@ -181,6 +187,12 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="1483493594462132177">Envia</translation>
<translation id="1484290072879560759">Tria l'adreça d'enviament</translation>
<translation id="1492194039220927094">Tramesa automàtica de les polítiques:</translation>
+<translation id="149293076951187737">Quan tanques totes les pestanyes d'incògnit a Chrome, la teva activitat en aquelles pestanyes s'esborra del dispositiu:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Activitat de navegació<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Historial de cerques<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Informació introduïda en formularis<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">Torna a la pestanya</translation>
<translation id="1501859676467574491">Mostra les targetes del Compte de Google</translation>
<translation id="1507202001669085618">&lt;p&gt;Aquest error es mostra si utilitzeu un portal Wi-Fi en què cal que inicieu la sessió per connectar-vos a Internet.&lt;/p&gt;
@@ -208,6 +220,8 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="1559572115229829303">&lt;p&gt;No es pot establir una connexió privada amb <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> perquè la data i l'hora (<ph name="DATE_AND_TIME" />) del vostre dispositiu no són correctes.&lt;/p&gt;
&lt;p&gt;Canvieu la data i l'hora a la secció &lt;strong&gt;General&lt;/strong&gt; de l'aplicació &lt;strong&gt;Configuració&lt;/strong&gt;.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">L'administrador reiniciarà el dispositiu el dia <ph name="DATE" /> a les <ph name="TIME" /></translation>
+<translation id="156703335097561114">Informació de les xarxes, com ara les adreces, la configuració de les interfícies i la qualitat de la connexió</translation>
<translation id="1567040042588613346">Aquesta política funciona correctament, però s'ha establert el mateix valor en un altre lloc i s'ha substituït per la política.</translation>
<translation id="1569487616857761740">Introdueix la data de caducitat</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="1583429793053364125">S'ha produït un error en mostrar aquesta pàgina web.</translation>
<translation id="1586541204584340881">Quines extensions has instal·lat</translation>
<translation id="1588438908519853928">Normal</translation>
+<translation id="1589050138437146318">Vols instal·lar ARCore?</translation>
<translation id="1592005682883173041">Accés a les dades locals</translation>
<translation id="1594030484168838125">Tria</translation>
<translation id="160851722280695521">Juga al joc del dinosaure de Chrome</translation>
@@ -254,7 +269,7 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="1711234383449478798">S'ha ignorat perquè la política <ph name="POLICY_NAME" /> no s'ha establert com a <ph name="VALUE" />.</translation>
<translation id="1712552549805331520"><ph name="URL" /> vol emmagatzemar dades a l'ordinador local de manera permanent</translation>
<translation id="1713628304598226412">Safata 2</translation>
-<translation id="1715874602234207">F</translation>
+<translation id="1715874602234207">Dv.</translation>
<translation id="1717218214683051432">Sensors de moviment</translation>
<translation id="1717494416764505390">Bústia de correu 3</translation>
<translation id="1718029547804390981">No es poden afegir anotacions a aquest fitxer perquè és massa gran</translation>
@@ -279,6 +294,7 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="1763864636252898013">Aquest servidor no ha pogut comprovar que sigui <ph name="DOMAIN" /> perquè el sistema operatiu del vostre dispositiu considera que el seu certificat de seguretat no és de confiança. Això pot ser a causa d'una configuració incorrecta o d'un atacant que intercepta la vostra connexió.</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Prova d'executar el diagnòstic de xarxes de Windows<ph name="END_LINK" />.</translation>
<translation id="1772163372082567643">El servidor de destinació, <ph name="ORIGIN" />, ha establert una capçalera en què se sol·licita que s'apliqui una política d'origen a totes les sol·licituds que rebi. Tanmateix, com que la capçalera no està ben formada, el navegador no pot completar la sol·licitud que has fet per a <ph name="SITE" />. Els operadors de llocs web poden fer servir les polítiques d'origen per configurar la seguretat i altres propietats d'un lloc web.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Més informació sobre el mode d'incògnit a Chromium<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">Les pestanyes obertes es mostren aquí</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -406,6 +422,7 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="22081806969704220">Safata 3</translation>
<translation id="2212735316055980242">No es troba la política</translation>
<translation id="2213606439339815911">S'estan recuperant les entrades...</translation>
+<translation id="2213612003795704869">La pàgina està impresa</translation>
<translation id="2215727959747642672">Edició de fitxers</translation>
<translation id="2218879909401188352">És possible que els atacants que es troben a <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> instal·lin aplicacions perilloses que malmetin el teu dispositiu, afegeixin càrrecs amagats a la teva factura telefònica o et robin informació personal. <ph name="BEGIN_LEARN_MORE_LINK" />Més informació<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">Sense connexió a Internet</translation>
@@ -415,6 +432,7 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="2248949050832152960">Utilitza WebAuthn</translation>
<translation id="2250931979407627383">Cosit de la vora a l'esquerra</translation>
<translation id="225207911366869382">El valor d'aquesta política és obsolet.</translation>
+<translation id="2256115617011615191">Reinicia ara</translation>
<translation id="2258928405015593961">Introdueix una data de caducitat situada en el futur i torna-ho a provar</translation>
<translation id="225943865679747347">Codi d'error: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">Error d'HTTP</translation>
@@ -442,6 +460,7 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="2337852623177822836">L'administrador controla l'opció de configuració</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> es vol vincular</translation>
<translation id="2346319942568447007">Imatge que has copiat</translation>
+<translation id="2350796302381711542">Voleu permetre que <ph name="HANDLER_HOSTNAME" /> obri tots els enllaços de <ph name="PROTOCOL" /> en comptes de <ph name="REPLACED_HANDLER_TITLE" />?</translation>
<translation id="2354001756790975382">Altres adreces d'interès</translation>
<translation id="2354430244986887761">Recentment, Navegació segura de Google <ph name="BEGIN_LINK" />ha trobat aplicacions perjudicials<ph name="END_LINK" /> a <ph name="SITE" />.</translation>
<translation id="2355395290879513365">És possible que els atacants puguin veure les imatges que miris en aquest lloc i que les modifiquin per enganyar-te.</translation>
@@ -467,6 +486,7 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="2413528052993050574">El servidor no ha pogut comprovar que sigui <ph name="DOMAIN" /> perquè és possible que el seu certificat de seguretat s'hagi revocat. Això pot ser a causa d'una configuració incorrecta o d'un atacant que intercepta la vostra connexió.</translation>
<translation id="2414886740292270097">Fosc</translation>
<translation id="2430968933669123598">Gestiona el Compte de Google: prem Retorn per gestionar la teva informació, privadesa i seguretat al Compte de Google</translation>
+<translation id="2436186046335138073">Voleu permetre que <ph name="HANDLER_HOSTNAME" /> obri tots els enllaços de <ph name="PROTOCOL" />?</translation>
<translation id="2438874542388153331">Encunyació quàdruple a la dreta</translation>
<translation id="2450021089947420533">Recorreguts</translation>
<translation id="2463739503403862330">Emplena</translation>
@@ -474,6 +494,7 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="2465655957518002998">Tria el mètode d'entrega</translation>
<translation id="2465688316154986572">Grapat</translation>
<translation id="2465914000209955735">Gestiona els fitxers que has baixat a Chrome</translation>
+<translation id="2466004615675155314">Mostra informació del web</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Executar el diagnòstic de xarxes<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">Ordre d'1 a N</translation>
<translation id="2470767536994572628">Quan editis anotacions, aquest document tornarà a la visualització d'una sola pàgina i a la seva rotació original</translation>
@@ -494,6 +515,7 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="2523886232349826891">Només es desarà en aquest dispositiu</translation>
<translation id="2524461107774643265">Afegeix més informació</translation>
<translation id="2529899080962247600">Aquest camp no pot tenir més de <ph name="MAX_ITEMS_LIMIT" /> entrades. Totes les altres entrades s'ignoraran.</translation>
+<translation id="2535585790302968248">Obre una pestanya d'incògnit nova per navegar en privat</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{i 1 més}other{i # més}}</translation>
<translation id="2536110899380797252">Afegeix una adreça</translation>
<translation id="2539524384386349900">Detecta</translation>
@@ -519,7 +541,14 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="2597378329261239068">Aquest document està protegit mitjançant contrasenya. Introduïu una contrasenya.</translation>
<translation id="2609632851001447353">Variacions</translation>
<translation id="2610561535971892504">Fes clic per copiar</translation>
+<translation id="2617988307566202237">Chrome <ph name="BEGIN_EMPHASIS" />no desarà<ph name="END_EMPHASIS" /> la informació següent:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />El teu historial de navegació
+ <ph name="LIST_ITEM" />Les galetes o les dades de llocs web
+ <ph name="LIST_ITEM" />La informació introduïda en formularis
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (sobre)</translation>
+<translation id="2623663032199728144">Pot demanar-te permís per utilitzar informació sobre les teves pantalles</translation>
<translation id="2625385379895617796">El rellotge està avançat</translation>
<translation id="262745152991669301">Pot demanar permís per connectar-se a dispositius USB</translation>
<translation id="2629325967560697240">Per obtenir el màxim nivell de seguretat de Chrome, <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />activa la protecció millorada<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -553,6 +582,7 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="2709516037105925701">Emplenament automàtic</translation>
<translation id="2713444072780614174">Blanc</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />; prem Tab i després Retorn per gestionar la informació dels pagaments i de les targetes de crèdit a la configuració de Chrome</translation>
+<translation id="271663710482723385">Prem |<ph name="ACCELERATOR1" />|+|<ph name="ACCELERATOR2" />| per sortir de la pantalla completa</translation>
<translation id="2721148159707890343">Sol·licitud realitzada correctament</translation>
<translation id="2723669454293168317">Executa una comprovació de seguretat a la configuració de Chrome</translation>
<translation id="2726001110728089263">Safata lateral</translation>
@@ -583,6 +613,7 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="2850739647070081192">Invite (sobre)</translation>
<translation id="2856444702002559011">Pot ser que els atacants provin de robar la teva informació del lloc web <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (per exemple, contrasenyes, missatges o targetes de crèdit). <ph name="BEGIN_LEARN_MORE_LINK" />Més informació<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">Aquest lloc web mostra anuncis intrusius o enganyosos.</translation>
+<translation id="286512204874376891">Una targeta virtual oculta la teva targeta real per contribuir a protegir-te de possibles fraus. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">Amistosa</translation>
<translation id="2876489322757410363">Per pagar amb una aplicació externa, sortiràs del mode d'incògnit. Vols continuar?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />: prem Tab i després Retorn per gestionar Navegació segura i altres opcions de la configuració de Chrome</translation>
@@ -607,6 +638,7 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="2930577230479659665">Retalla després de cada còpia</translation>
<translation id="2932085390869194046">Suggereix una contrasenya...</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019">Obrir els enllaços del protocol <ph name="PROTOCOL" /></translation>
<translation id="2941952326391522266">Aquest servidor no ha pogut comprovar que sigui <ph name="DOMAIN" /> perquè el seu certificat de seguretat prové del domini <ph name="DOMAIN2" />. Això pot ser a causa d'una configuració incorrecta o d'un atacant que intercepta la vostra connexió.</translation>
<translation id="2943895734390379394">Hora de la pujada:</translation>
<translation id="2948083400971632585">Podeu desactivar qualsevol servidor intermediari configurat per a una connexió des de la pàgina de configuració.</translation>
@@ -639,6 +671,7 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="3037605927509011580">Vaja!</translation>
<translation id="3041612393474885105">Informació del certificat</translation>
<translation id="3044034790304486808">Reprèn la cerca</translation>
+<translation id="305162504811187366">Historial de l'Escriptori remot de Chrome, inclosos els amfitrions, les marques de temps i els identificadors de sessió de client</translation>
<translation id="3060227939791841287">C9 (sobre)</translation>
<translation id="3061707000357573562">Servei de pedaç</translation>
<translation id="306573536155379004">S'ha iniciat el joc.</translation>
@@ -679,6 +712,7 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="3197136577151645743">Pot demanar permís per saber quan estàs utilitzant aquest dispositiu de manera activa</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />: prem Tab i després Retorn per gestionar la informació que sincronitzes a la configuració de Chrome</translation>
<translation id="320323717674993345">Cancel·la el pagament</translation>
+<translation id="3203366800380907218">Del web</translation>
<translation id="3207960819495026254">S'ha afegit a les adreces d'interès.</translation>
<translation id="3209034400446768650">És possible que la pàgina faci un càrrec de diners</translation>
<translation id="3212581601480735796">La teva activitat a <ph name="HOSTNAME" /> s'està supervisant</translation>
@@ -695,10 +729,12 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="3234666976984236645">Detecta sempre el contingut important d'aquest lloc</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />: prem Tab i després Retorn per personalitzar l'aspecte del teu navegador</translation>
<translation id="3240791268468473923">S'ha obert el full de credencials no coincidents de credencials de pagament segur</translation>
+<translation id="324180406144491771">Els enllaços de "<ph name="HOST_NAME" />" estan bloquejats</translation>
<translation id="3249845759089040423">Atrevida</translation>
<translation id="3252266817569339921">Francès</translation>
<translation id="3257954757204451555">Qui hi ha darrere d'aquesta informació?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />: prem Tab i després Retorn per crear un esdeveniment ràpidament a Google Calendar</translation>
+<translation id="3261488570342242926">Informació sobre les targetes virtuals</translation>
<translation id="3264837738038045344">Botó Gestiona la configuració de Chrome: prem Retorn per veure la configuració de Chrome</translation>
<translation id="3266793032086590337">Valor (en conflicte)</translation>
<translation id="3268451620468152448">Pestanyes obertes</translation>
@@ -712,6 +748,7 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="3288238092761586174">És possible que <ph name="URL" /> hagi de fer més passos per verificar el teu pagament</translation>
<translation id="3293642807462928945">Més informació sobre la política <ph name="POLICY_NAME" /></translation>
<translation id="3295444047715739395">Consulta i gestiona les teves contrasenyes a la configuració de Chrome</translation>
+<translation id="3303795387212510132">Vols permetre que l'aplicació obri els enllaços <ph name="PROTOCOL_SCHEME" />?</translation>
<translation id="3303855915957856445">No s'ha trobat cap resultat de la cerca</translation>
<translation id="3304073249511302126">cerca de dispositius Bluetooth</translation>
<translation id="3308006649705061278">Unitat organitzativa (OU)</translation>
@@ -725,12 +762,6 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="3345782426586609320">Ulls</translation>
<translation id="3355823806454867987">Canvia la configuració del servidor intermediari...</translation>
<translation id="3360103848165129075">Full del gestor de pagaments</translation>
-<translation id="3361596688432910856">Chrome <ph name="BEGIN_EMPHASIS" />no desarà<ph name="END_EMPHASIS" /> la informació següent:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />El teu historial de navegació
- <ph name="LIST_ITEM" />Les galetes i les dades de llocs web
- <ph name="LIST_ITEM" />La informació que introdueixis en formularis
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">Aquesta política s'ha copiat automàticament de la política <ph name="OLD_POLICY" />, que està obsoleta. Hauries de fer servir aquesta política.</translation>
<translation id="3364869320075768271"><ph name="URL" /> vol utilitzar les teves dades i els teus dispositius de realitat virtual</translation>
<translation id="3366477098757335611">Mostra les targetes</translation>
@@ -813,7 +844,6 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="3587738293690942763">Mitjà</translation>
<translation id="3592413004129370115">Italian (sobre)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{Pots restablir el teu grup en qualsevol moment. Ha de transcórrer aproximadament un dia per unir-te a un grup nou.}=1{Pots restablir el teu grup en qualsevol moment. Ha de transcórrer aproximadament un dia per unir-te a un grup nou.}other{Pots restablir el teu grup en qualsevol moment. Han de transcórrer aproximadament {NUM_DAYS} dies per unir-te a un grup nou.}}</translation>
-<translation id="3596012367874587041">Configuració de l'aplicació</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">Aplicació bloquejada per l'administrador</translation>
<translation id="3608932978122581043">Orientació de l'entrada</translation>
@@ -853,9 +883,10 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="3705189812819839667"><ph name="RESULT_OWNER" /> - <ph name="RESULT_PRODUCT_SOURCE" /></translation>
<translation id="370665806235115550">S'està carregant...</translation>
<translation id="3709599264800900598">Text que has copiat</translation>
-<translation id="370972442370243704">Activa Recorreguts</translation>
+<translation id="370972442370243704">Activa els recorreguts</translation>
<translation id="3711895659073496551">Suspèn</translation>
<translation id="3712624925041724820">Llicències exhaurides</translation>
+<translation id="3714633008798122362">calendari web</translation>
<translation id="3714780639079136834">Activa les dades mòbils o la Wi-Fi.</translation>
<translation id="3715597595485130451">Connexió a xarxes Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Comproveu el servidor intermediari, el tallafoc i la configuració de DNS<ph name="END_LINK" /></translation>
@@ -917,6 +948,7 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="3906954721959377182">Tauleta</translation>
<translation id="3909477809443608991"><ph name="URL" /> vol reproduir contingut protegit. Google verificarà la identitat del teu dispositiu i aquest lloc web hi podrà accedir.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">Denega</translation>
<translation id="3939773374150895049">Vols utilitzar WebAuthn en lloc del CVC?</translation>
<translation id="3946209740501886391">Pregunta sempre en aquest lloc</translation>
<translation id="3947595700203588284">Pot demanar permís per connectar-se a dispositius MIDI</translation>
@@ -937,6 +969,7 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="3987940399970879459">Menys d'1 MB</translation>
<translation id="3990250421422698716">Jog offset</translation>
<translation id="3996311196211510766">El lloc web <ph name="ORIGIN" /> ha sol·licitat que s'apliqui una política d'origen a totes les sol·licituds que rebi, però en aquest moment aquesta política no es pot aplicar.</translation>
+<translation id="4009243425692662128">El contingut de les pàgines que imprimeixes s'envia a Google Cloud o a tercers perquè l'analitzin. Per exemple, pot ser que s'analitzi per detectar-hi dades sensibles.</translation>
<translation id="4010758435855888356">Vols permetre l'accés a l'emmagatzematge?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{Document PDF que conté {COUNT} pàgina}other{Document PDF que conté {COUNT} pàgines}}</translation>
<translation id="4023431997072828269">Com que el formulari s'està enviant mitjançant una connexió que no és segura, altres persones podran veure la teva informació.</translation>
@@ -1027,6 +1060,7 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="4250680216510889253">No</translation>
<translation id="4253168017788158739">Nota</translation>
<translation id="425582637250725228">És possible que els canvis que heu fet no es desin.</translation>
+<translation id="425869179292622354">Vols que tot sigui més segur amb una targeta virtual?</translation>
<translation id="4258748452823770588">Signatura errònia</translation>
<translation id="4261046003697461417">No es poden fer anotacions en documents protegits</translation>
<translation id="4265872034478892965">Permès per l'administrador</translation>
@@ -1089,6 +1123,7 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="4434045419905280838">Finestres emergents i redireccions</translation>
<translation id="4435702339979719576">Postal)</translation>
<translation id="443673843213245140">L'ús d'un servidor intermediari no està activat, però s'ha especificat una configuració explícita d'un servidor intermediari.</translation>
+<translation id="4441832193888514600">S'ha ignorat perquè la política només es pot establir com a política d'usuari basada en el núvol.</translation>
<translation id="4450893287417543264">No ho tornis a mostrar</translation>
<translation id="4451135742916150903">Pot demanar permís per connectar-se a dispositius HID</translation>
<translation id="4452328064229197696">La contrasenya que acabes d'utilitzar s'ha trobat en una violació de les dades. Per protegir els teus comptes, el gestor de contrasenyes de Google recomana que comprovis les contrasenyes desades.</translation>
@@ -1112,7 +1147,7 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="4508814173490746936">No s'ha pogut fer servir Touch ID</translation>
<translation id="4509074745930862522"><ph name="TRANSLATE_FOCUSED_FRIENDLY_MATCH_TEXT" />; prem Tab i després Retorn per traduir aquesta pàgina amb el Traductor de Google</translation>
<translation id="4510487217173779431">Chou4 (sobre)</translation>
-<translation id="4514308731478712184">Desactiva Recorreguts</translation>
+<translation id="4514308731478712184">Desactiva els recorreguts</translation>
<translation id="4515275063822566619">Les targetes i les adreces s'obtenen de Chrome i del teu Compte de Google (<ph name="ACCOUNT_EMAIL" />). Pots gestionar-les des de <ph name="BEGIN_LINK" />Configuració<ph name="END_LINK" />.</translation>
<translation id="4517607026994743406">Comm-10 (sobre)</translation>
<translation id="4521157617044179198"><ph name="WIDTH" /> × <ph name="HEIGHT" /> mm (<ph name="ORIENTATION" />)</translation>
@@ -1144,6 +1179,7 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="4628948037717959914">Foto</translation>
<translation id="4631649115723685955">Devolució de diners associada</translation>
<translation id="4636930964841734540">Informació</translation>
+<translation id="4638670630777875591">Mode d'incògnit a Chromium</translation>
<translation id="464342062220857295">Funcions de cerca</translation>
<translation id="4644670975240021822">Ordre invers de cara avall</translation>
<translation id="4646534391647090355">Porta-m'hi ara</translation>
@@ -1164,6 +1200,7 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="4708268264240856090">La connexió s'ha interromput</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Executar el diagnòstic de xarxes de Windows<ph name="END_LINK" />.</translation>
+<translation id="4722735765955348426">Contrasenya per a <ph name="USERNAME" /></translation>
<translation id="4724144314178270921">Pot demanar permís per veure el text i les imatges del porta-retalls</translation>
<translation id="4726672564094551039">Torna a carregar les polítiques</translation>
<translation id="4728558894243024398">Plataforma</translation>
@@ -1185,6 +1222,7 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="4757993714154412917">Acabes d'introduir la contrasenya en un lloc web enganyós. Per protegir els teus comptes, Chromium et recomana que comprovis les contrasenyes desades.</translation>
<translation id="4758311279753947758">Afegiu informació de contacte</translation>
<translation id="4761104368405085019">Utilitzar el micròfon</translation>
+<translation id="4761869838909035636">Executa la comprovació de seguretat de Chrome</translation>
<translation id="4764776831041365478">És possible que la pàgina web <ph name="URL" /> estigui temporalment fora de servei o s'hagi traslladat permanentment a una adreça web nova.</translation>
<translation id="4766713847338118463">Grapat doble a la part inferior</translation>
<translation id="4771973620359291008">S'ha produït un error desconegut.</translation>
@@ -1205,12 +1243,6 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="4819347708020428563">Vols editar les anotacions en la visualització predeterminada?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />: prem Tab i després Retorn per crear un full de càlcul de Google ràpidament</translation>
<translation id="4825507807291741242">Potent</translation>
-<translation id="4827402517081186284">Amb el mode d'incògnit no ets invisible en línia:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Els llocs web saben quan els visites.<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Les empreses o els centres educatius poden fer el seguiment de l'activitat de navegació.<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Els proveïdors d'Internet poden monitorar el trànsit web.<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">Activa els advertiments</translation>
<translation id="4838327282952368871">Somiadora</translation>
<translation id="4840250757394056958">Mostra l'historial de Chrome</translation>
@@ -1222,12 +1254,12 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="4854362297993841467">Aquest mètode d'entrega no està disponible. Prova'n un altre.</translation>
<translation id="4854853140771946034">Crea una nota nova a Google Keep ràpidament</translation>
<translation id="485902285759009870">S'està verificant el codi...</translation>
+<translation id="4866506163384898554">Prem |<ph name="ACCELERATOR1" />|+|<ph name="ACCELERATOR2" />| perquè es mostri el cursor</translation>
<translation id="4876188919622883022">Visualització simplificada</translation>
<translation id="4876305945144899064">Sense nom d'usuari</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{Cap}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" /> i <ph name="EXAMPLE_DOMAIN_2" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831">Cerca: <ph name="TEXT" /></translation>
<translation id="4879491255372875719">Automàtic (opció predeterminada)</translation>
-<translation id="4879725228911483934">Obrir i col·locar finestres a les teves pantalles</translation>
<translation id="4880827082731008257">Cerca a l'historial</translation>
<translation id="4881695831933465202">Obre</translation>
<translation id="4885256590493466218">Paga amb <ph name="CARD_DETAIL" /> en tramitar la compra.</translation>
@@ -1236,6 +1268,7 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">Novè corró</translation>
<translation id="4901778704868714008">Desa...</translation>
+<translation id="4905659621780993806">L'administrador reiniciarà automàticament el dispositiu el dia <ph name="DATE" /> a les <ph name="TIME" />. Abans no es reiniciï, desa tots els elements oberts.</translation>
<translation id="4913987521957242411">Encunyació a la part superior esquerra</translation>
<translation id="4918221908152712722">Instal·la l'aplicació <ph name="APP_NAME" /> (no cal que la baixis)</translation>
<translation id="4923459931733593730">Pagament</translation>
@@ -1244,6 +1277,7 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, prem el tabulador i després Retorn per fer una cerca</translation>
<translation id="4930153903256238152">Gran capacitat</translation>
+<translation id="4940163644868678279">Mode d'incògnit a Chrome</translation>
<translation id="4943872375798546930">No hi ha cap resultat</translation>
<translation id="4950898438188848926">Botó per canviar de pestanya; prem Retorn per canviar a la pestanya oberta, <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="495170559598752135">Accions</translation>
@@ -1253,6 +1287,7 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="4968522289500246572">Aquesta aplicació està dissenyada per a mòbils i és possible que no canviï de mida correctament. L'aplicació podria tenir problemes o reiniciar-se.</translation>
<translation id="4969341057194253438">Suprimeix la gravació</translation>
<translation id="4973922308112707173">Encunyació doble a la part superior</translation>
+<translation id="4976702386844183910">Darrera visita: <ph name="DATE" /></translation>
<translation id="4984088539114770594">Vols utilitzar el micròfon?</translation>
<translation id="4984339528288761049">Prc5 (sobre)</translation>
<translation id="4989163558385430922">Mostra-ho tot</translation>
@@ -1274,7 +1309,7 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="503069730517007720"><ph name="SOFTWARE_NAME" /> requereix un certificat arrel, però no està instal·lat. Per resoldre aquest problema, l'administrador de TI ha de consultar les instruccions per configurar <ph name="SOFTWARE_NAME" />. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="5031870354684148875">Sobre el Traductor de Google</translation>
<translation id="503498442187459473"><ph name="HOST" /> vol utilitzar la càmera i el micròfon</translation>
-<translation id="5039762155821394373">Mida de la lletra</translation>
+<translation id="5039762155821394373">Cos de font</translation>
<translation id="5039804452771397117">Permet</translation>
<translation id="5040262127954254034">Privadesa</translation>
<translation id="5043480802608081735">Enllaç que has copiat</translation>
@@ -1314,6 +1349,7 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="5138227688689900538">Mostra'n menys</translation>
<translation id="5145883236150621069">Hi ha un codi d'error en la resposta a la política</translation>
<translation id="5146995429444047494">Les notificacions per a <ph name="ORIGIN" /> estan bloquejades</translation>
+<translation id="514704532284964975"><ph name="URL" /> vol veure i canviar la informació que hi ha als dispositius amb NFC que toquis amb el teu telèfon</translation>
<translation id="5148809049217731050">Cara amunt</translation>
<translation id="515292512908731282">C4 (sobre)</translation>
<translation id="5158275234811857234">Portada</translation>
@@ -1338,6 +1374,7 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="5215116848420601511">Formes de pagament i adreces que fan servir Google Pay</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">Safata 13</translation>
+<translation id="5216942107514965959">Darrera visita: avui</translation>
<translation id="5222812217790122047">El correu electrònic és obligatori</translation>
<translation id="5230733896359313003">Adreça d'enviament</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1358,7 +1395,6 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">Propietats del document</translation>
<translation id="528468243742722775">Finalitza</translation>
-<translation id="5284909709419567258">Adreces de xarxa</translation>
<translation id="5285570108065881030">Mostra totes les contrasenyes desades</translation>
<translation id="5287240709317226393">Mostra les galetes</translation>
<translation id="5287456746628258573">Aquest lloc web utilitza una configuració de seguretat obsoleta i, per tant, la informació que hi enviïs podria quedar exposada (per exemple, les contrasenyes o els números de les targetes de crèdit).</translation>
@@ -1442,6 +1478,7 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="5556459405103347317">Torna a carregar</translation>
<translation id="5560088892362098740">Data de caducitat</translation>
<translation id="55635442646131152">Esquema del document</translation>
+<translation id="5565613213060953222">Obre una pestanya d'incògnit</translation>
<translation id="5565735124758917034">Actiu</translation>
<translation id="5570825185877910964">Protegeix el compte</translation>
<translation id="5571083550517324815">No es pot fer la recollida en aquesta adreça. Selecciona'n una altra.</translation>
@@ -1524,6 +1561,7 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="5869522115854928033">Contrasenyes desades</translation>
<translation id="5873013647450402046">El banc vol confirmar la teva identitat.</translation>
<translation id="5887400589839399685">S'ha desat la targeta</translation>
+<translation id="5887687176710214216">Darrera visita: ahir</translation>
<translation id="5895138241574237353">Reinicia</translation>
<translation id="5895187275912066135">Emès el</translation>
<translation id="5901630391730855834">Groc</translation>
@@ -1537,6 +1575,7 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="5921639886840618607">Vols desar la targeta al Compte de Google?</translation>
<translation id="5922853866070715753">Ja queda poc</translation>
<translation id="5932224571077948991">El lloc web mostra anuncis intrusius o enganyosos</translation>
+<translation id="5938153366081463283">Afegeix una targeta virtual</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347">S'està obrint <ph name="SITE_NAME" />…</translation>
<translation id="5951495562196540101">El dispositiu no es pot inscriure amb un compte de consumidor (hi ha una llicència associada disponible).</translation>
@@ -1601,6 +1640,7 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="6120179357481664955">Recordes el teu identificador d'UPI?</translation>
<translation id="6124432979022149706">Connectors de Chrome Enterprise</translation>
<translation id="6127379762771434464">S'ha suprimit l'element</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Més informació sobre el mode d'incògnit a Chrome<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">Reviseu els cables i reinicieu els encaminadors, els mòdems o altres
dispositius de xarxa que feu servir.</translation>
<translation id="614940544461990577">Prova el següent:</translation>
@@ -1613,7 +1653,6 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="6169916984152623906">Ara pots navegar de manera privada i les altres persones que utilitzin aquest dispositiu no veuran la teva activitat. Tanmateix, les baixades i les adreces d'interès sí que es desaran.</translation>
<translation id="6177128806592000436">La connexió amb aquest lloc web no és segura</translation>
<translation id="6180316780098470077">Interval d'intents</translation>
-<translation id="619448280891863779">Pot demanar permís per obrir i col·locar finestres a les pantalles</translation>
<translation id="6196640612572343990">Bloqueja les galetes de tercers</translation>
<translation id="6203231073485539293">Comprovació de la connexió a Internet</translation>
<translation id="6218753634732582820">Voleu suprimir l'adreça de Chromium?</translation>
@@ -1636,7 +1675,7 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="6272383483618007430">Google Update</translation>
<translation id="6276112860590028508">Les pàgines de la teva llista de lectura es mostren aquí</translation>
<translation id="627746635834430766">Perquè la propera vegada puguis pagar més ràpidament, desa la targeta i l'adreça de facturació al compte de Google.</translation>
-<translation id="6279098320682980337">No s'ha emplenat el número de la targeta virtual? Fes clic als detalls de la targeta per copiar-los.</translation>
+<translation id="6279183038361895380">Premeu |<ph name="ACCELERATOR" />| per veure el cursor</translation>
<translation id="6280223929691119688">No es pot entregar a aquesta adreça. Selecciona'n una altra.</translation>
<translation id="6282194474023008486">Codi postal</translation>
<translation id="6285507000506177184">Botó Gestiona les baixades a Chrome: prem Retorn per gestionar els fitxers que has baixat a Chrome</translation>
@@ -1644,6 +1683,7 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="6290238015253830360">Els articles suggerits es mostren aquí</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{El dispositiu es reiniciarà ara}=1{El dispositiu es reiniciarà d'aquí a 1 segon}other{El dispositiu es reiniciarà d'aquí a # segons}}</translation>
<translation id="6302269476990306341">S'està aturant l'Assistent de Google a Chrome</translation>
<translation id="6305205051461490394">No es pot accedir a <ph name="URL" />.</translation>
<translation id="6312113039770857350">La pàgina web no està disponible</translation>
@@ -1717,6 +1757,7 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="6529602333819889595">&amp;Refés la supressió</translation>
<translation id="6545864417968258051">Cerca de dispositius Bluetooth</translation>
<translation id="6547208576736763147">Encunyació doble a l'esquerra</translation>
+<translation id="6554732001434021288">Darrera visita: fa <ph name="NUM_DAYS" /> dies</translation>
<translation id="6556866813142980365">Refés</translation>
<translation id="6569060085658103619">Estàs consultant la pàgina d'una extensió</translation>
<translation id="6573200754375280815">Encunyació doble a la dreta</translation>
@@ -1752,7 +1793,7 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="6665553082534466207">Encunyació triple a la dreta</translation>
<translation id="6671697161687535275">Voleu suprimir el suggeriment de formulari de Chromium?</translation>
<translation id="6685834062052613830">Tanqueu la sessió i completeu la configuració</translation>
-<translation id="6687335167692595844">Mida de la lletra sol·licitada</translation>
+<translation id="6687335167692595844">Cos de font sol·licitada</translation>
<translation id="6688743156324860098">Actualitza…</translation>
<translation id="6688775486821967877">La targeta virtual no està disponible en aquests moments. Torna-ho a provar més tard.</translation>
<translation id="6689249931105087298">Relatiu amb compressió de punts negres</translation>
@@ -1777,7 +1818,6 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="6757797048963528358">El dispositiu ha entrat en mode de repòs.</translation>
<translation id="6767985426384634228">Vols actualitzar l'adreça?</translation>
<translation id="6768213884286397650">Hagaki (postal)</translation>
-<translation id="6774185088257932239"><ph name="BEGIN_LINK" />Més informació<ph name="END_LINK" /> sobre el mode d'incògnit</translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">Violeta</translation>
<translation id="6786747875388722282">Extensions</translation>
@@ -1861,7 +1901,6 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="706295145388601875">Afegeix i gestiona adreces a la configuració de Chrome</translation>
<translation id="7064851114919012435">Informació de contacte</translation>
<translation id="7068733155164172741">Introdueix el codi de <ph name="OTP_LENGTH" /> dígits</translation>
-<translation id="7070090581017165256">Sobre aquest lloc web</translation>
<translation id="70705239631109039">La connexió no és del tot segura</translation>
<translation id="7075452647191940183">La sol·licitud és massa llarga</translation>
<translation id="7079718277001814089">Aquest lloc web conté programari maliciós</translation>
@@ -1878,6 +1917,12 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="7111012039238467737">(Vàlid)</translation>
<translation id="7118618213916969306">Cerca l'URL (<ph name="SHORT_URL" />) del porta-retalls</translation>
<translation id="7119414471315195487">Tanca altres pestanyes o programes</translation>
+<translation id="7129355289156517987">Quan tanques totes les pestanyes d'incògnit a Chromium, la teva activitat en aquelles pestanyes s'esborra del dispositiu:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Activitat de navegació<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Historial de cerques<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Informació introduïda en formularis<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">No es pot enviar a aquesta adreça. Selecciona'n una altra.</translation>
<translation id="7132939140423847331">L'administrador ha prohibit copiar aquestes dades.</translation>
<translation id="7135130955892390533">Mostra l'estat</translation>
@@ -1900,6 +1945,7 @@ En cas contrari, la configuració de privadesa el bloquejarà. Això permetrà q
<translation id="7192203810768312527">Allibera <ph name="SIZE" />. És possible que alguns llocs es carreguin més a poc a poc la propera vegada que els visitis.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">L'administrador pot veure el següent:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />. Prem Tab i després Retorn per obrir una pestanya d'incògnit nova i navegar en privat.</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> no compleix la normativa de seguretat.</translation>
<translation id="7210993021468939304">L'activitat de Linux al contenidor; i també pot instal·lar-hi i executar-hi aplicacions de Linux</translation>
@@ -1931,6 +1977,7 @@ Detalls addicionals:
<translation id="7304562222803846232">Gestiona la configuració de privadesa del Compte de Google</translation>
<translation id="7305756307268530424">Inicia més a poc a poc</translation>
<translation id="7308436126008021607">sincronització en segon pla</translation>
+<translation id="7310392214323165548">El dispositiu es reiniciarà aviat</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">Ajuda amb la connexió</translation>
<translation id="7323804146520582233">Amaga la secció "<ph name="SECTION" />"</translation>
@@ -1938,6 +1985,7 @@ Detalls addicionals:
<translation id="7334320624316649418">&amp;Refés el canvi d'ordre</translation>
<translation id="7335157162773372339">Pot demanar permís per utilitzar la càmera</translation>
<translation id="7337248890521463931">Mostra més línies</translation>
+<translation id="7337418456231055214">No s'ha emplenat el número de la targeta virtual? Fes clic als detalls de la targeta per copiar-los. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">No està disponible a la teva plataforma.</translation>
<translation id="733923710415886693">El certificat del servidor no s'ha divulgat mitjançant la Transparència de certificats.</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1960,6 +2008,7 @@ Detalls addicionals:
<translation id="7378627244592794276">No</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">No aplicable</translation>
+<translation id="7388594495505979117">{0,plural, =1{El dispositiu es reiniciarà d'aquí a 1 minut}other{El dispositiu es reiniciarà d'aquí a # minuts}}</translation>
<translation id="7390545607259442187">Confirma la targeta</translation>
<translation id="7392089738299859607">Actualitza l'adreça</translation>
<translation id="7399802613464275309">Comprovació de seguretat</translation>
@@ -1996,6 +2045,12 @@ Detalls addicionals:
<translation id="7485870689360869515">No s'han trobat dades.</translation>
<translation id="7495528107193238112">Aquest contingut està bloquejat. Contacta amb el propietari del lloc web per resoldre el problema.</translation>
<translation id="7497998058912824456">Botó Crea un document: prem Retorn per crear un document de Google ràpidament</translation>
+<translation id="7506488012654002225">Chromium <ph name="BEGIN_EMPHASIS" />no desarà<ph name="END_EMPHASIS" /> la informació següent:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />El teu historial de navegació
+ <ph name="LIST_ITEM" />Les galetes o les dades de llocs web
+ <ph name="LIST_ITEM" />La informació introduïda en formularis
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">L'identificador de dispositiu de la política que s'ha tornat és buit o no coincideix amb l'actual</translation>
<translation id="7508870219247277067">Verd alvocat</translation>
<translation id="7511955381719512146">És possible que la xarxa Wi-Fi que esteu fent servir requereixi que visiteu <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
@@ -2109,7 +2164,6 @@ Detalls addicionals:
<translation id="7813600968533626083">Voleu suprimir el suggeriment de formulari de Chrome?</translation>
<translation id="781440967107097262">Vols compartir el porta-retalls?</translation>
<translation id="7815407501681723534">S'han trobat <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> per a "<ph name="SEARCH_STRING" />"</translation>
-<translation id="782125616001965242">Mostra informació sobre aquest lloc web</translation>
<translation id="782886543891417279">És possible que la xarxa Wi-Fi (<ph name="WIFI_NAME" />) que esteu fent servir requereixi que visiteu la seva pàgina d'inici de sessió.</translation>
<translation id="7836231406687464395">Postfix (sobre)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{Cap}=1{1 aplicació (<ph name="EXAMPLE_APP_1" />)}=2{2 aplicacions (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}other{# aplicacions (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}}</translation>
@@ -2126,7 +2180,6 @@ Detalls addicionals:
<translation id="7888575728750733395">Intent de renderització d'impressió</translation>
<translation id="7894280532028510793">Si està ben escrit, <ph name="BEGIN_LINK" />prova d'executar el diagnòstic de xarxes<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (sobre)</translation>
-<translation id="7931318309563332511">Desconegut</translation>
<translation id="793209273132572360">Vols actualitzar l'adreça?</translation>
<translation id="7932579305932748336">Recobriment</translation>
<translation id="79338296614623784">Introdueix un número de telèfon vàlid</translation>
@@ -2151,13 +2204,14 @@ Detalls addicionals:
<translation id="7976214039405368314">Hi ha massa sol·licituds</translation>
<translation id="7977538094055660992">Dispositiu de sortida</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">Enllaçada a</translation>
<translation id="798134797138789862">Pot demanar permís per utilitzar dispositius i dades de realitat virtual</translation>
<translation id="7984945080620862648">En aquest moment no podeu visitar <ph name="SITE" /> perquè el lloc web ha enviat credencials barrejades que Chrome no pot processar. Els errors i els atacs de xarxa solen ser temporals, de manera que és probable que aquesta pàgina torni a funcionar més tard.</translation>
-<translation id="79859296434321399">Per veure contingut en realitat augmentada, instal·la ARCore</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">Enquadernació</translation>
<translation id="7992044431894087211">S'ha reprès la compartició de la pantalla amb <ph name="APPLICATION_TITLE" /></translation>
<translation id="7995512525968007366">No especificat</translation>
+<translation id="7998269595945679889">Botó Obre una pestanya d'incògnit. Prem Retorn per obrir una pestanya d'incògnit nova i navegar en privat.</translation>
<translation id="800218591365569300">Prova de tancar altres pestanyes o programes per alliberar memòria.</translation>
<translation id="8004582292198964060">Navegador</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{Aquesta targeta i l'adreça de facturació associada es desaran. La podràs utilitzar quan tinguis la sessió iniciada a <ph name="USER_EMAIL" />.}other{Aquestes targetes i les adreces de facturació associades es desaran. Les podràs utilitzar quan tinguis la sessió iniciada a <ph name="USER_EMAIL" />.}}</translation>
@@ -2217,6 +2271,7 @@ Detalls addicionals:
<translation id="8202370299023114387">Conflicte</translation>
<translation id="8206978196348664717">Prc4 (sobre)</translation>
<translation id="8211406090763984747">La connexió és segura</translation>
+<translation id="8217240300496046857">Els llocs web no poden utilitzar galetes que facin un seguiment de la teva activitat al web. Pot ser que les funcions d'alguns llocs web no funcionin.</translation>
<translation id="8218327578424803826">Ubicació assignada:</translation>
<translation id="8220146938470311105">C7/C6 (sobre)</translation>
<translation id="8225771182978767009">La persona que ha configurat l'ordinador ha bloquejat aquest lloc.</translation>
@@ -2257,14 +2312,9 @@ Detalls addicionals:
<translation id="830498451218851433">Plegat per la meitat</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">Aplicacions instal·lades i freqüència d'utilització</translation>
+<translation id="8317207217658302555">Vols actualitzar ARCore?</translation>
<translation id="831997045666694187">Tarda</translation>
<translation id="8321476692217554900">notificacions</translation>
-<translation id="8328484624016508118">Quan s'han tancat totes les pestanyes d'incògnit, Chrome esborra:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />L'activitat de navegació d'aquest dispositiu.<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />L'historial de cerques d'aquest dispositiu.<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />La informació introduïda en formularis.<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489">S'ha rebutjat l'accés a <ph name="HOST_NAME" /></translation>
<translation id="833262891116910667">Destacat</translation>
<translation id="8339163506404995330">Les pàgines en <ph name="LANGUAGE" /> no es traduiran</translation>
@@ -2316,6 +2366,7 @@ Detalls addicionals:
<translation id="8507227106804027148">Línia d'ordres</translation>
<translation id="8508648098325802031">Icona de la cerca</translation>
<translation id="8511402995811232419">Gestiona les galetes</translation>
+<translation id="8519753333133776369">Dispositiu d'interfície humana permès pel teu administrador</translation>
<translation id="8522552481199248698">Chrome et pot ajudar a protegir el Compte de Google i a canviar la contrasenya.</translation>
<translation id="8530813470445476232">Esborra l'historial de navegació, les galetes, la memòria cau i molt més a la configuració de Chrome</translation>
<translation id="8533619373899488139">Ves a &lt;strong&gt;chrome://policy&lt;/strong&gt; per veure la llista d'URL bloquejats i altres polítiques aplicades per l'administrador del sistema.</translation>
@@ -2327,7 +2378,6 @@ Detalls addicionals:
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{Restableix el permís}other{Restableix els permisos}}</translation>
<translation id="8555010941760982128">Utilitza aquest codi en el moment de tramitar la compra</translation>
<translation id="8557066899867184262">El CVC es troba a la part posterior de la targeta.</translation>
-<translation id="8558485628462305855">Per veure contingut en realitat augmentada, actualitza ARCore</translation>
<translation id="8559762987265718583">No es pot establir una connexió privada amb <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> perquè la data i l'hora (<ph name="DATE_AND_TIME" />) del dispositiu són incorrectes.</translation>
<translation id="8564182942834072828">Documents independents / Còpies sense recopilar</translation>
<translation id="8564985650692024650">Chromium et recomana que restableixis la contrasenya per a <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> si l'has fet servir en altres llocs web.</translation>
@@ -2346,6 +2396,7 @@ Detalls addicionals:
<translation id="865032292777205197">sensors de moviment</translation>
<translation id="8663226718884576429">Resum de la comanda, <ph name="TOTAL_LABEL" />, més detalls</translation>
<translation id="8666678546361132282">Anglès</translation>
+<translation id="8669306706049782872">Utilitza informació sobre les teves pantalles per obrir i col·locar finestres</translation>
<translation id="867224526087042813">Signatura</translation>
<translation id="8676424191133491403">Sense retard</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, resposta, <ph name="ANSWER" /></translation>
@@ -2372,6 +2423,7 @@ Detalls addicionals:
<translation id="8731544501227493793">Botó Gestiona les contrasenyes; prem Retorn per veure i gestionar les teves contrasenyes a la configuració de Chrome</translation>
<translation id="8734529307927223492">El teu dispositiu <ph name="DEVICE_TYPE" /> està gestionat per <ph name="MANAGER" /></translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />; prem Tab i després Retorn per obrir una finestra d'incògnit nova i navegar en privat</translation>
+<translation id="8737685506611670901">Obrir els enllaços del protocol <ph name="PROTOCOL" /> en lloc del gestor <ph name="REPLACED_HANDLER_TITLE" /></translation>
<translation id="8738058698779197622">Per establir una connexió segura, el rellotge ha d'estar ben ajustat, perquè els certificats que els llocs web fan servir per identificar-se només són vàlids per a períodes de temps concrets. Com que el rellotge del dispositiu no està ben ajustat, Chromium no pot verificar aquests certificats.</translation>
<translation id="8740359287975076522">No s'ha trobat l'&lt;abbr id="dnsDefinition"&gt;adreça DNS&lt;/abbr&gt; de <ph name="HOST_NAME" />. S'està diagnosticant el problema.</translation>
<translation id="8742371904523228557"><ph name="ONE_TIME_CODE" /> és el teu codi per a <ph name="ORIGIN" /></translation>
@@ -2399,6 +2451,7 @@ Detalls addicionals:
<translation id="883848425547221593">Altres adreces d'interès</translation>
<translation id="884264119367021077">Adreça d’enviament</translation>
<translation id="884923133447025588">No s'ha trobat cap mecanisme de revocació.</translation>
+<translation id="8849262850971482943">Utilitza la teva targeta virtual per millorar la seguretat</translation>
<translation id="885730110891505394">Comparteix informació amb Google</translation>
<translation id="8858065207712248076">Chrome et recomana que restableixis la contrasenya per a <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> si l'has fet servir en altres llocs web.</translation>
<translation id="885906927438988819">Si està ben escrit, <ph name="BEGIN_LINK" />prova d'executar el diagnòstic de xarxes de Windows<ph name="END_LINK" />.</translation>
@@ -2448,6 +2501,7 @@ Detalls addicionals:
<translation id="9004367719664099443">Sessió de realitat virtual en curs</translation>
<translation id="9005998258318286617">No es pot carregar el document PDF.</translation>
<translation id="9008201768610948239">Ignora</translation>
+<translation id="901834265349196618">correu electrònic</translation>
<translation id="9020200922353704812">Es requereix l'adreça de facturació de la targeta</translation>
<translation id="9020542370529661692">Aquesta pàgina s'ha traduït a <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9020742383383852663">A8</translation>
@@ -2496,6 +2550,7 @@ Detalls addicionals:
<translation id="9150045010208374699">Utilitzar la càmera</translation>
<translation id="9150685862434908345">L'administrador pot modificar la configuració del navegador de manera remota. És possible que l'activitat d'aquest dispositiu també es gestioni fora de Chrome. <ph name="BEGIN_LINK" />Més informació<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">S'ha actualitzat.</translation>
+<translation id="9155211586651734179">Els perifèrics d'àudio enllaçats</translation>
<translation id="9157595877708044936">S'està configurant...</translation>
<translation id="9158625974267017556">C6 (sobre)</translation>
<translation id="9164029392738894042">Comprovació de la precisió</translation>
diff --git a/chromium/components/strings/components_strings_cs.xtb b/chromium/components/strings/components_strings_cs.xtb
index d4e25057254..1c7054cce99 100644
--- a/chromium/components/strings/components_strings_cs.xtb
+++ b/chromium/components/strings/components_strings_cs.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">Zobrazit podrobnosti</translation>
<translation id="1030706264415084469">Stránka <ph name="URL" /> chce v zařízení trvale ukládat velké množství dat</translation>
<translation id="1032854598605920125">OtoÄit ve smÄ›ru hodinových ruÄiÄek</translation>
+<translation id="1033329911862281889">Anonymní režim neznamená, že jste neviditelní:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />weby a jimi používané služby poznají, když je navštívíte,<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />zaměstnavatel nebo škola mohou sledovat, co si prohlížíte,<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />poskytovatelé internetových služeb mohou sledovat návštěvnost webů.<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">Vypnout</translation>
<translation id="1036982837258183574">Režim celé obrazovky ukonÄíte stisknutím klávesy |<ph name="ACCELERATOR" />|</translation>
<translation id="1038106730571050514">Zobrazit návrhy</translation>
<translation id="1038842779957582377">neznámé jméno</translation>
<translation id="1041998700806130099">Zpráva listu úlohy</translation>
<translation id="1048785276086539861">Když poznámky upravíte, tento dokument se vrátí do zobrazení jedné stránky</translation>
-<translation id="1049743911850919806">Anonymní režim</translation>
<translation id="1050038467049342496">Zavřete ostatní aplikace</translation>
<translation id="1055184225775184556">&amp;Vrátit přidání zpět</translation>
<translation id="1056898198331236512">Upozornění</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">Mezipaměť zásady je v pořádku</translation>
<translation id="1130564665089811311">TlaÄítko PÅ™eložit stránku, stisknutím klávesy Enter tuto stránku pÅ™eložíte pomocí PÅ™ekladaÄe Google</translation>
<translation id="1131264053432022307">Obrázek, který jste zkopírovali</translation>
+<translation id="1142846828089312304">V anonymním režimu blokovat soubory cookie třetích stran</translation>
<translation id="1150979032973867961">Server nedokázal prokázat, že patří doménÄ› <ph name="DOMAIN" />. OperaÄní systém vaÅ¡eho poÄítaÄe nedůvěřuje jeho bezpeÄnostnímu certifikátu.Může to být způsobeno nesprávnou konfigurací nebo tím, že vaÅ¡e pÅ™ipojení zachytává útoÄník.</translation>
<translation id="1151972924205500581">Je vyžadováno heslo</translation>
<translation id="1156303062776767266">Prohlížíte si místní nebo sdílený soubor.</translation>
@@ -64,7 +70,6 @@ Jinak to vaše nastavení ochrany soukromí bude blokovat. Povolením umožníte
<translation id="1178581264944972037">Pozastavit</translation>
<translation id="1181037720776840403">Odebrat</translation>
<translation id="1186201132766001848">Zkontrolovat hesla</translation>
-<translation id="1195210374336998651">Přejít na nastavení aplikace</translation>
<translation id="1195558154361252544">Oznámení jsou automaticky blokována u všech webů s výjimkou těch, u nichž je povolíte</translation>
<translation id="1197088940767939838">Oranžová</translation>
<translation id="1201402288615127009">Další</translation>
@@ -111,7 +116,7 @@ Jinak to vaše nastavení ochrany soukromí bude blokovat. Povolením umožníte
<translation id="1307966114820526988">Funkce, které již nejsou podporovány</translation>
<translation id="1308113895091915999">Je k dispozici nabídka</translation>
<translation id="1312803275555673949">Jaké důkazy to dokládají?</translation>
-<translation id="131405271941274527">Web <ph name="URL" /> chce odesílat a přijímat informace, když se telefonem dotknete zařízení NFC</translation>
+<translation id="1314311879718644478">Zobrazit obsah rozšířené reality</translation>
<translation id="1314509827145471431">Vazba vpravo</translation>
<translation id="1318023360584041678">Uloženo do skupiny karet</translation>
<translation id="1319245136674974084">U této aplikace se již příště neptat</translation>
@@ -161,6 +166,7 @@ Jinak to vaše nastavení ochrany soukromí bude blokovat. Povolením umožníte
<translation id="142858679511221695">Uživatel cloudu</translation>
<translation id="1428729058023778569">Toto varování se vám zobrazuje, protože tento web nepodporuje protokol HTTPS. <ph name="BEGIN_LEARN_MORE_LINK" />Další informace<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">Tisk</translation>
+<translation id="1432187715652018471">stránka chce instalovat obslužný nástroj služby.</translation>
<translation id="1432581352905426595">Spravovat vyhledávaÄe</translation>
<translation id="1436185428532214179">Může žádat o úpravu souborů a složek v zařízení</translation>
<translation id="1442386063175183758">Pravé otevírací přeložení</translation>
@@ -181,6 +187,12 @@ Jinak to vaše nastavení ochrany soukromí bude blokovat. Povolením umožníte
<translation id="1483493594462132177">Odeslat</translation>
<translation id="1484290072879560759">Vybrat dodací adresu</translation>
<translation id="1492194039220927094">Přenesení zásad:</translation>
+<translation id="149293076951187737">Když zavřete všechny anonymní karty Chromu, vaše aktivita na těchto kartách bude ze zařízení vymazána:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />aktivita prohlížení,<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />historie vyhledávání,<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />údaje zadané do formulářů.<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">Zpět na kartu</translation>
<translation id="1501859676467574491">Zobrazit karty z vaÅ¡eho úÄtu Google</translation>
<translation id="1507202001669085618">&lt;p&gt;Tato chyba se zobrazí při použití portálu Wi-Fi, na kterém je třeba se před přístupem na internet přihlásit.&lt;/p&gt;
@@ -208,6 +220,8 @@ Jinak to vaše nastavení ochrany soukromí bude blokovat. Povolením umožníte
<translation id="1559572115229829303">&lt;p&gt;Soukromé pÅ™ipojení k doménÄ› <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> nelze navázat, protože máte v zařízení nastaveno chybné datum a Äas (<ph name="DATE_AND_TIME" />).&lt;/p&gt;
&lt;p&gt;Datum a Äas upravte v aplikaci &lt;strong&gt;Nastavení&lt;/strong&gt; v sekci &lt;strong&gt;Obecné&lt;/strong&gt;.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">Administrátor restartuje zařízení <ph name="DATE" /> v <ph name="TIME" /></translation>
+<translation id="156703335097561114">Informace o síti, jako jsou adresy, konfigurace rozhraní a kvalita připojení</translation>
<translation id="1567040042588613346">Zásada funguje podle oÄekávání, ale jinde je nastavena stejná hodnota, kterou tato zásada nahrazuje.</translation>
<translation id="1569487616857761740">Zadejte datum vypršení platnosti</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@ Jinak to vaše nastavení ochrany soukromí bude blokovat. Povolením umožníte
<translation id="1583429793053364125">Při zobrazování této webové stránky došlo k chybě.</translation>
<translation id="1586541204584340881">Která rozšíření máte nainstalovaná</translation>
<translation id="1588438908519853928">Normální</translation>
+<translation id="1589050138437146318">Nainstalovat ARCore?</translation>
<translation id="1592005682883173041">Přístup k místním datům</translation>
<translation id="1594030484168838125">Zvolit</translation>
<translation id="160851722280695521">Spustit v Chromu dinosauří hru</translation>
@@ -279,6 +294,7 @@ Jinak to vaše nastavení ochrany soukromí bude blokovat. Povolením umožníte
<translation id="1763864636252898013">Server nedokázal prokázat, že patří doménÄ› <ph name="DOMAIN" />. OperaÄní systém vaÅ¡eho zařízení nedůvěřuje jeho bezpeÄnostnímu certifikátu. Může to být způsobeno nesprávnou konfigurací nebo tím, že vaÅ¡e pÅ™ipojení zachytává útoÄník.</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Zkuste spustit Diagnostiku sítě systému Windows<ph name="END_LINK" />.</translation>
<translation id="1772163372082567643">Server, na který pÅ™echázíte (<ph name="ORIGIN" />), nastavil záhlaví, které vyžaduje, aby se na vÅ¡echny na nÄ›j odesílané požadavky vztahovaly zásady ohlednÄ› původu. Záhlaví má ale nesprávný tvar. ProhlížeÄ proto váš požadavek na web <ph name="SITE" /> nemůže splnit. Zásady ohlednÄ› původu mohou použít provozovatelé webů ke konfiguraci bezpeÄnostních a dalších vlastností webu.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Další informace o anonymním režimu v prohlížeÄi Chromium<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">Zde se zobrazí otevřené karty</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -406,6 +422,7 @@ Jinak to vaše nastavení ochrany soukromí bude blokovat. Povolením umožníte
<translation id="22081806969704220">Přihrádka 3</translation>
<translation id="2212735316055980242">Zásada nebyla nalezena</translation>
<translation id="2213606439339815911">NaÄítání záznamů...</translation>
+<translation id="2213612003795704869">Stránka je vytisknuta</translation>
<translation id="2215727959747642672">Úprava souborů</translation>
<translation id="2218879909401188352">ÚtoÄníci, kteří na webu <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> aktuálnÄ› působí, by vám do zařízení mohli nainstalovat nebezpeÄné aplikace, které jej poÅ¡kodí, pÅ™idat skryté poplatky na úÄet za mobilní služby nebo odcizit osobní údaje. <ph name="BEGIN_LEARN_MORE_LINK" />Další informace<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">Nejste připojeni k internetu</translation>
@@ -415,6 +432,7 @@ Jinak to vaše nastavení ochrany soukromí bude blokovat. Povolením umožníte
<translation id="2248949050832152960">Použít WebAuthn</translation>
<translation id="2250931979407627383">Sešití na levém okraji</translation>
<translation id="225207911366869382">Tato hodnota již pro tuto zásadu není podporována.</translation>
+<translation id="2256115617011615191">Restartovat</translation>
<translation id="2258928405015593961">Zadejte datum vypršení platnosti v budoucnosti a zkuste to znovu.</translation>
<translation id="225943865679747347">Kód chyby: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">Chyba protokolu HTTP</translation>
@@ -442,6 +460,7 @@ Jinak to vaše nastavení ochrany soukromí bude blokovat. Povolením umožníte
<translation id="2337852623177822836">Nastavení je spravováno administrátorem</translation>
<translation id="2340263603246777781">Web <ph name="ORIGIN" /> žádá o spárování</translation>
<translation id="2346319942568447007">Obrázek, který jste zkopírovali</translation>
+<translation id="2350796302381711542">Chcete obslužnému nástroji <ph name="HANDLER_HOSTNAME" /> povolit otevírat všechny odkazy s protokolem <ph name="PROTOCOL" /> (namísto obslužného nástroje <ph name="REPLACED_HANDLER_TITLE" />)?</translation>
<translation id="2354001756790975382">Ostatní záložky</translation>
<translation id="2354430244986887761">BezpeÄné prohlížení Google na webu <ph name="SITE" /> nedávno <ph name="BEGIN_LINK" />nalezlo Å¡kodlivé aplikace<ph name="END_LINK" />.</translation>
<translation id="2355395290879513365">ÚtoÄníci mohou vidÄ›t obrázky, které si na tomto webu prohlížíte, a oklamat vás tím, že tyto obrázky upraví.</translation>
@@ -467,6 +486,7 @@ Jinak to vaše nastavení ochrany soukromí bude blokovat. Povolením umožníte
<translation id="2413528052993050574">Server nedokázal prokázat, že patří doménÄ› <ph name="DOMAIN" />. Jeho bezpeÄnostní certifikát byl zÅ™ejmÄ› zruÅ¡en. Může to být způsobeno nesprávnou konfigurací nebo tím, že vaÅ¡e pÅ™ipojení zachytává útoÄník.</translation>
<translation id="2414886740292270097">Tmavé</translation>
<translation id="2430968933669123598">Spravovat úÄet Google, stisknutím klávesy Enter můžete spravovat své údaje, ochranu soukromí a zabezpeÄení v úÄtu Google</translation>
+<translation id="2436186046335138073">Chcete obslužnému nástroji <ph name="HANDLER_HOSTNAME" /> povolit otevírat všechny odkazy s protokolem <ph name="PROTOCOL" />?</translation>
<translation id="2438874542388153331">Čtyři otvory vpravo</translation>
<translation id="2450021089947420533">Cesty</translation>
<translation id="2463739503403862330">Vyplnit</translation>
@@ -474,6 +494,7 @@ Jinak to vaše nastavení ochrany soukromí bude blokovat. Povolením umožníte
<translation id="2465655957518002998">Vybrat způsob doruÄení</translation>
<translation id="2465688316154986572">Sponka</translation>
<translation id="2465914000209955735">Spravovat soubory, které jste v Chromu stáhli</translation>
+<translation id="2466004615675155314">Zobrazit informace z webu</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Spustit Diagnostiku sítě<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">Pořadí N stránek na list</translation>
<translation id="2470767536994572628">Když upravíte poznámky, tento dokument se vrátí do zobrazení jedné stránky a obnoví se jeho původní orientace</translation>
@@ -494,6 +515,7 @@ Jinak to vaše nastavení ochrany soukromí bude blokovat. Povolením umožníte
<translation id="2523886232349826891">Uloženo pouze do tohoto zařízení</translation>
<translation id="2524461107774643265">Přidání dalších informací</translation>
<translation id="2529899080962247600">Toto pole nesmí mít více než <ph name="MAX_ITEMS_LIMIT" /> položek. Všechny další položky budou ignorovány.</translation>
+<translation id="2535585790302968248">Otevřete novou anonymní kartu a prohlížejte v soukromí</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{a 1 další}few{a # další}many{a # další}other{a # dalších}}</translation>
<translation id="2536110899380797252">Přidat adresu</translation>
<translation id="2539524384386349900">Rozpoznat</translation>
@@ -519,7 +541,14 @@ Jinak to vaše nastavení ochrany soukromí bude blokovat. Povolením umožníte
<translation id="2597378329261239068">Tento dokument je chráněn heslem. Zadejte prosím heslo.</translation>
<translation id="2609632851001447353">Varianty</translation>
<translation id="2610561535971892504">Kliknutím zkopírujte</translation>
+<translation id="2617988307566202237">Chrome <ph name="BEGIN_EMPHASIS" />nebude ukládat<ph name="END_EMPHASIS" /> následující informace:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />vaši historii prohlížení,
+ <ph name="LIST_ITEM" />soubory cookie a data webů,
+ <ph name="LIST_ITEM" />údaje zadané do formulářů.
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (obálka)</translation>
+<translation id="2623663032199728144">Může žádat o použití informací o vašich obrazovkách</translation>
<translation id="2625385379895617796">Vaše hodiny jdou napřed</translation>
<translation id="262745152991669301">Může žádat o připojení k zařízením USB</translation>
<translation id="2629325967560697240">Pokud v Chromu chcete mít nejvyšší úroveň zabezpeÄení, <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />zapnÄ›te vylepÅ¡enou ochranu<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -553,6 +582,7 @@ Jinak to vaše nastavení ochrany soukromí bude blokovat. Povolením umožníte
<translation id="2709516037105925701">Automatické vyplňování</translation>
<translation id="2713444072780614174">Bílá</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />, stisknutím klávesy Tab a poté Enter můžete spravovat údaje o platbách a platebních kartách v nastavení Chromu</translation>
+<translation id="271663710482723385">Režim celé obrazovky ukonÄíte stisknutím kláves |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />|</translation>
<translation id="2721148159707890343">Požadavek byl úspěšný</translation>
<translation id="2723669454293168317">SpusÅ¥te v nastavení Chromu bezpeÄnostní kontrolu</translation>
<translation id="2726001110728089263">BoÄní zásobník</translation>
@@ -583,6 +613,7 @@ Jinak to vaše nastavení ochrany soukromí bude blokovat. Povolením umožníte
<translation id="2850739647070081192">Invite (obálka)</translation>
<translation id="2856444702002559011">ÚtoÄníci se mohou pokusit odcizit vaÅ¡e údaje na webu <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (například hesla, zprávy nebo informace o platebních kartách). <ph name="BEGIN_LEARN_MORE_LINK" />Další informace<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">Tento web zobrazuje rušivé nebo zavádějící reklamy.</translation>
+<translation id="286512204874376891">Virtuální karta maskuje vaÅ¡i skuteÄnou kartu a chrání vás pÅ™ed případným podvodem. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">Přátelské</translation>
<translation id="2876489322757410363">Chystáte se opustit anonymní režim, abyste mohli zaplatit v externí aplikaci. PokraÄovat?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />, stisknutím tabulátoru a poté klávesy Enter můžete spravovat BezpeÄné prohlížení a další funkce v nastavení Chromu</translation>
@@ -607,6 +638,7 @@ Jinak to vaše nastavení ochrany soukromí bude blokovat. Povolením umožníte
<translation id="2930577230479659665">Oříznout za každou kopií</translation>
<translation id="2932085390869194046">Navrhnout heslo...</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019">Otevírat odkazy <ph name="PROTOCOL" /></translation>
<translation id="2941952326391522266">Server nedokázal prokázat, že patří doménÄ› <ph name="DOMAIN" />. Jeho bezpeÄnostní certifikát pochází z domény <ph name="DOMAIN2" />. Může to být způsobeno nesprávnou konfigurací nebo tím, že vaÅ¡e pÅ™ipojení zachytává útoÄník.</translation>
<translation id="2943895734390379394">Čas nahrání:</translation>
<translation id="2948083400971632585">Libovolné servery proxy nakonfigurované pro připojení můžete zakázat na stránce Nastavení.</translation>
@@ -639,6 +671,7 @@ Jinak to vaše nastavení ochrany soukromí bude blokovat. Povolením umožníte
<translation id="3037605927509011580">Aj, chyba!</translation>
<translation id="3041612393474885105">Informace o certifikátu</translation>
<translation id="3044034790304486808">Vrátit se k vyhledávání</translation>
+<translation id="305162504811187366">Historie Vzdálené plochy Chrome, vÄetnÄ› Äasových razítek, hostitelů a ID relací klientů</translation>
<translation id="3060227939791841287">C9 (obálka)</translation>
<translation id="3061707000357573562">Služba oprav</translation>
<translation id="306573536155379004">Hra byla spuštěna.</translation>
@@ -676,6 +709,7 @@ Jinak to vaše nastavení ochrany soukromí bude blokovat. Povolením umožníte
<translation id="3197136577151645743">Může zjišťovat, kdy aktivně používáte toto zařízení</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />, stisknutím tabulátoru a poté klávesy Enter můžete v nastavení Chromu spravovat, jaké informace synchronizujete</translation>
<translation id="320323717674993345">Zrušit platbu</translation>
+<translation id="3203366800380907218">Z webu</translation>
<translation id="3207960819495026254">Přidáno do záložek</translation>
<translation id="3209034400446768650">Stránka může úÄtovat poplatky</translation>
<translation id="3212581601480735796">Vaše aktivita na webu <ph name="HOSTNAME" /> je sledována</translation>
@@ -692,10 +726,12 @@ Jinak to vaše nastavení ochrany soukromí bude blokovat. Povolením umožníte
<translation id="3234666976984236645">Vždy na tomto webu zjišťovat důležitý obsah</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />, stisknutím tabulátoru a poté klávesy Enter si pÅ™izpůsobíte vzhled prohlížeÄe</translation>
<translation id="3240791268468473923">List identifikaÄních údajů pro zabezpeÄené platby o nenalezených odpovídajících identifikaÄních údajích je otevÅ™ený</translation>
+<translation id="324180406144491771">Odkazy „<ph name="HOST_NAME" />“ jsou blokovány</translation>
<translation id="3249845759089040423">Elegantní</translation>
<translation id="3252266817569339921">francouzština</translation>
<translation id="3257954757204451555">Kdo za těmito informacemi stojí?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />, stisknutím klávesy Tab a poté Enter rychle vytvoříte novou událost v Kalendáři Google</translation>
+<translation id="3261488570342242926">Informace o virtuálních kartách</translation>
<translation id="3264837738038045344">TlaÄítko správy nastavení Chromu. Stisknutím klávesy Enter pÅ™ejdete do nastavení Chromu</translation>
<translation id="3266793032086590337">Hodnota (konflikt)</translation>
<translation id="3268451620468152448">Otevřené karty</translation>
@@ -709,6 +745,7 @@ Jinak to vaše nastavení ochrany soukromí bude blokovat. Povolením umožníte
<translation id="3288238092761586174"><ph name="URL" /> zÅ™ejmÄ› bude muset vaÅ¡i platbu ověřit pomocí dodateÄných kroků</translation>
<translation id="3293642807462928945">Další informace o zásadě <ph name="POLICY_NAME" /></translation>
<translation id="3295444047715739395">Zobrazte a spravujte svá hesla v nastavení Chromu</translation>
+<translation id="3303795387212510132">Povolit aplikaci otevírat odkazy <ph name="PROTOCOL_SCHEME" />?</translation>
<translation id="3303855915957856445">Nebyly nalezeny žádné výsledky</translation>
<translation id="3304073249511302126">vyhledávání bluetooth</translation>
<translation id="3308006649705061278">OrganizaÄní jednotka (OU)</translation>
@@ -722,12 +759,6 @@ Jinak to vaše nastavení ochrany soukromí bude blokovat. Povolením umožníte
<translation id="3345782426586609320">OÄi</translation>
<translation id="3355823806454867987">Změna nastavení proxy...</translation>
<translation id="3360103848165129075">List obslužného nástroje pro platby</translation>
-<translation id="3361596688432910856">Chrome <ph name="BEGIN_EMPHASIS" />nebude ukládat<ph name="END_EMPHASIS" /> následující informace:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />vaši historii prohlížení,
- <ph name="LIST_ITEM" />soubory cookie a data webů,
- <ph name="LIST_ITEM" />údaje zadané do formulářů.
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">Tato zásada byla automaticky zkopírována ze zásady <ph name="OLD_POLICY" />, jejíž podpora byla ukonÄena. MÄ›li byste místo ní používat tuto zásadu.</translation>
<translation id="3364869320075768271"><ph name="URL" /> chce používat vaše zařízení a data pro virtuální realitu</translation>
<translation id="3366477098757335611">Zobrazit karty</translation>
@@ -810,7 +841,6 @@ Jinak to vaše nastavení ochrany soukromí bude blokovat. Povolením umožníte
<translation id="3587738293690942763">Střední</translation>
<translation id="3592413004129370115">Italian (obálka)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{Skupinu můžete kdykoli resetovat. Zařazení do nové skupiny trvá přibližně jeden den.}=1{Skupinu můžete kdykoli resetovat. Zařazení do nové skupiny trvá přibližně jeden den.}few{Skupinu můžete kdykoli resetovat. Zařazení do nové skupiny trvá přibližně {NUM_DAYS} dny.}many{Skupinu můžete kdykoli resetovat. Zařazení do nové skupiny trvá přibližně {NUM_DAYS} dne.}other{Skupinu můžete kdykoli resetovat. Zařazení do nové skupiny trvá přibližně {NUM_DAYS} dní.}}</translation>
-<translation id="3596012367874587041">Nastavení aplikace</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">Aplikace je blokována administrátorem</translation>
<translation id="3608932978122581043">Orientace podávání</translation>
@@ -852,6 +882,7 @@ Jinak to vaše nastavení ochrany soukromí bude blokovat. Povolením umožníte
<translation id="370972442370243704">Zapnout cesty</translation>
<translation id="3711895659073496551">Pozastavit</translation>
<translation id="3712624925041724820">Byly vyÄerpány licence</translation>
+<translation id="3714633008798122362">webový kalendář</translation>
<translation id="3714780639079136834">Zapnout mobilní datové připojení nebo Wi-Fi</translation>
<translation id="3715597595485130451">Připojení k síti Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Zkontrolovat proxy server, firewall a konfiguraci DNS<ph name="END_LINK" /></translation>
@@ -913,6 +944,7 @@ Jinak to vaše nastavení ochrany soukromí bude blokovat. Povolením umožníte
<translation id="3906954721959377182">Tablet</translation>
<translation id="3909477809443608991"><ph name="URL" /> chce přehrávat chráněný obsah. Google ověří identitu vašeho zařízení a tento web k ní může získat přístup.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">Odmítnout</translation>
<translation id="3939773374150895049">Použít WebAuthn namísto CVC?</translation>
<translation id="3946209740501886391">Na tomto webu se vždy zeptat</translation>
<translation id="3947595700203588284">Může žádat o připojení k zařízením MIDI</translation>
@@ -933,6 +965,7 @@ Jinak to vaše nastavení ochrany soukromí bude blokovat. Povolením umožníte
<translation id="3987940399970879459">Méně než 1 MB</translation>
<translation id="3990250421422698716">Běžící odsazení</translation>
<translation id="3996311196211510766">Web <ph name="ORIGIN" /> požádal, aby se na všechny na něj odesílané požadavky vztahovaly zásady ohledně původu, ale tyto zásady momentálně nelze použít.</translation>
+<translation id="4009243425692662128">Obsah tisknutých stránek se odesílá do služby Google Cloud nebo třetím stranám k analýze. Může například projít kontrolou přítomnosti citlivých údajů.</translation>
<translation id="4010758435855888356">Povolit přístup k úložišti?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{Dokument PDF obsahující {COUNT} stránku}few{Dokument PDF obsahující {COUNT} stránky}many{Dokument PDF obsahující {COUNT} stránky}other{Dokument PDF obsahující {COUNT} stránek}}</translation>
<translation id="4023431997072828269">VaÅ¡e informace budou viditelné ostatním, protože je tento formulář odesílán prostÅ™ednictvím nezabezpeÄeného pÅ™ipojení.</translation>
@@ -1023,6 +1056,7 @@ Jinak to vaše nastavení ochrany soukromí bude blokovat. Povolením umožníte
<translation id="4250680216510889253">Ne</translation>
<translation id="4253168017788158739">Poznámka</translation>
<translation id="425582637250725228">Je možné, že provedené změny nebudou uloženy.</translation>
+<translation id="425869179292622354">Zvýšit zabezpeÄení pomocí virtuální karty?</translation>
<translation id="4258748452823770588">Chybný podpis</translation>
<translation id="4261046003697461417">Do chránÄ›ných dokumentů nelze pÅ™idávat znaÄky a poznámky</translation>
<translation id="4265872034478892965">Povoleno administrátorem</translation>
@@ -1085,6 +1119,7 @@ Jinak to vaše nastavení ochrany soukromí bude blokovat. Povolením umožníte
<translation id="4434045419905280838">Vyskakovací okna a přesměrování</translation>
<translation id="4435702339979719576">Postcard)</translation>
<translation id="443673843213245140">Využití proxy serveru je zakázáno, je vÅ¡ak urÄena explicitní konfigurace proxy serveru.</translation>
+<translation id="4441832193888514600">Ignorováno, protože zásadu lze nastavit pouze jako zásadu cloudového uživatele.</translation>
<translation id="4450893287417543264">Tuto zprávu již nezobrazovat</translation>
<translation id="4451135742916150903">Může žádat o připojení k zařízením HID</translation>
<translation id="4452328064229197696">PrávÄ› použité heslo bylo nalezeno na seznamu hesel uniklých pÅ™i incidentu poruÅ¡ení zabezpeÄení údajů. K zabezpeÄení vaÅ¡ich úÄtů doporuÄuje Správce hesel Google zkontrolovat uložená hesla.</translation>
@@ -1140,6 +1175,7 @@ Jinak to vaše nastavení ochrany soukromí bude blokovat. Povolením umožníte
<translation id="4628948037717959914">Fotka</translation>
<translation id="4631649115723685955">Cashback je propojen</translation>
<translation id="4636930964841734540">Informace</translation>
+<translation id="4638670630777875591">Anonymní režim v prohlížeÄi Chromium</translation>
<translation id="464342062220857295">Funkce vyhledávání</translation>
<translation id="4644670975240021822">Obrácené pořadí lícem dolů</translation>
<translation id="4646534391647090355">Zobrazit</translation>
@@ -1160,6 +1196,7 @@ Jinak to vaše nastavení ochrany soukromí bude blokovat. Povolením umožníte
<translation id="4708268264240856090">Připojení bylo přerušeno</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Spustit Diagnostiku sítě systému Windows<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426">Heslo uživatele <ph name="USERNAME" /></translation>
<translation id="4724144314178270921">Může žádat o zobrazení textu a obrázků ve schránce</translation>
<translation id="4726672564094551039">Znovu naÄíst zásady</translation>
<translation id="4728558894243024398">Platforma</translation>
@@ -1181,6 +1218,7 @@ Jinak to vaše nastavení ochrany soukromí bude blokovat. Povolením umožníte
<translation id="4757993714154412917">PrávÄ› jste své heslo zadali na klamavém webu. Pokud chcete zabezpeÄit své úÄty, Chromium vám doporuÄuje zkontrolovat uložená hesla.</translation>
<translation id="4758311279753947758">Přidat kontaktní údaje</translation>
<translation id="4761104368405085019">Používat mikrofon</translation>
+<translation id="4761869838909035636">Spustit bezpeÄnostní kontrolu Chromu</translation>
<translation id="4764776831041365478">Webové stránky na adrese <ph name="URL" /> jsou možná doÄasnÄ› nedostupné nebo mohly být pÅ™emístÄ›ny na novou webovou adresu.</translation>
<translation id="4766713847338118463">DvÄ› sponky dole</translation>
<translation id="4771973620359291008">Došlo k neznámé chybě.</translation>
@@ -1201,12 +1239,6 @@ Jinak to vaše nastavení ochrany soukromí bude blokovat. Povolením umožníte
<translation id="4819347708020428563">Upravit poznámky ve výchozím zobrazení?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />, stisknutím klávesy Tab a poté Enter rychle vytvoříte novou Tabulku Google</translation>
<translation id="4825507807291741242">Důrazné</translation>
-<translation id="4827402517081186284">Anonymní režim neznamená, že jste neviditelní:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />weby poznají, když je navštívíte,<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />zaměstnavatel nebo škola mohou sledovat, co si prohlížíte,<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />poskytovatelé internetových služeb mohou sledovat návštěvnost webů.<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">Zapnout upozornění</translation>
<translation id="4838327282952368871">Zasněné</translation>
<translation id="4840250757394056958">Zobrazit historii Chromu</translation>
@@ -1218,12 +1250,12 @@ Jinak to vaše nastavení ochrany soukromí bude blokovat. Povolením umožníte
<translation id="4854362297993841467">Tento způsob doruÄení není k dispozici. Zkuste použít jiný způsob.</translation>
<translation id="4854853140771946034">Rychle vytvořit novou poznámku v aplikaci Google Keep</translation>
<translation id="485902285759009870">Ověřování kódu…</translation>
+<translation id="4866506163384898554">Kurzor zobrazíte stisknutím kláves |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />|</translation>
<translation id="4876188919622883022">Zjednodušené zobrazení</translation>
<translation id="4876305945144899064">Žádné uživatelské jméno</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{Žádné}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}few{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}many{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831">Vyhledávání dotazu <ph name="TEXT" /></translation>
<translation id="4879491255372875719">Automatické (výchozí)</translation>
-<translation id="4879725228911483934">Otevírat a umisťovat okna na obrazovkách</translation>
<translation id="4880827082731008257">Hledat v historii</translation>
<translation id="4881695831933465202">Otevřít</translation>
<translation id="4885256590493466218">U pokladny zaplaťte kartou <ph name="CARD_DETAIL" /></translation>
@@ -1232,6 +1264,7 @@ Jinak to vaše nastavení ochrany soukromí bude blokovat. Povolením umožníte
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">Devátá role</translation>
<translation id="4901778704868714008">Uložit...</translation>
+<translation id="4905659621780993806">V <ph name="TIME" /> dne <ph name="DATE" /> administrátor zařízení automaticky restartuje. Před restartováním zařízení uložte všechny otevřené položky.</translation>
<translation id="4913987521957242411">Děrování vlevo nahoře</translation>
<translation id="4918221908152712722">Nainstalujte si aplikaci <ph name="APP_NAME" /> (není potřeba nic stahovat)</translation>
<translation id="4923459931733593730">Platba</translation>
@@ -1240,6 +1273,7 @@ Jinak to vaše nastavení ochrany soukromí bude blokovat. Povolením umožníte
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, vyhledávat můžete stisknutím klávesy Tab a poté Enter</translation>
<translation id="4930153903256238152">Velká kapacita</translation>
+<translation id="4940163644868678279">Anonymní režim v Chromu</translation>
<translation id="4943872375798546930">Žádné výsledky</translation>
<translation id="4950898438188848926">TlaÄítko pÅ™epínání karet. Stisknutím klávesy Enter pÅ™ejdete na otevÅ™enou kartu (<ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" />)</translation>
<translation id="495170559598752135">Akce</translation>
@@ -1249,6 +1283,7 @@ Jinak to vaše nastavení ochrany soukromí bude blokovat. Povolením umožníte
<translation id="4968522289500246572">Tato aplikace je urÄena pro mobily a zmÄ›na velikosti nemusí fungovat správnÄ›. V aplikaci může docházet k problémům nebo se může restartovat.</translation>
<translation id="4969341057194253438">Smazat nahrávku</translation>
<translation id="4973922308112707173">Dvě díry nahoře</translation>
+<translation id="4976702386844183910">Naposledy navštíveno <ph name="DATE" /></translation>
<translation id="4984088539114770594">Použít mikrofon?</translation>
<translation id="4984339528288761049">Prc5 (obálka)</translation>
<translation id="4989163558385430922">Zobrazit vše</translation>
@@ -1310,6 +1345,7 @@ Jinak to vaše nastavení ochrany soukromí bude blokovat. Povolením umožníte
<translation id="5138227688689900538">Zobrazit méně</translation>
<translation id="5145883236150621069">OdpovÄ›Ä zásady obsahuje kód chyby</translation>
<translation id="5146995429444047494">Oznámení z webu <ph name="ORIGIN" /> jsou blokována</translation>
+<translation id="514704532284964975">Web <ph name="URL" /> chce Äíst a mÄ›nit informace na zařízeních NFC, kterých se dotknete telefonem</translation>
<translation id="5148809049217731050">Lícem nahoru</translation>
<translation id="515292512908731282">C4 (obálka)</translation>
<translation id="5158275234811857234">Titulní strana</translation>
@@ -1334,6 +1370,7 @@ Jinak to vaše nastavení ochrany soukromí bude blokovat. Povolením umožníte
<translation id="5215116848420601511">Platební metody a adresy pomocí služby Google Pay</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">Přihrádka 13</translation>
+<translation id="5216942107514965959">Naposledy navštíveno dnes</translation>
<translation id="5222812217790122047">Je nutné zadat e-mail</translation>
<translation id="5230733896359313003">Dodací adresa</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1354,7 +1391,6 @@ Jinak to vaše nastavení ochrany soukromí bude blokovat. Povolením umožníte
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">Vlastnosti dokumentu</translation>
<translation id="528468243742722775">Konec</translation>
-<translation id="5284909709419567258">Síťové adresy</translation>
<translation id="5285570108065881030">Zobrazit všechna uložená hesla</translation>
<translation id="5287240709317226393">Zobrazit soubory cookie</translation>
<translation id="5287456746628258573">Tento web používá zastaralou konfiguraci zabezpeÄení, která vaÅ¡e informace odesílané na tento web (například hesla nebo Äísla kreditních karet) vystavuje riziku odhalení.</translation>
@@ -1438,6 +1474,7 @@ Kontaktujte administrátora systému.</translation>
<translation id="5556459405103347317">NaÄíst znovu</translation>
<translation id="5560088892362098740">Datum vypršení platnosti</translation>
<translation id="55635442646131152">Osnova dokumentu</translation>
+<translation id="5565613213060953222">Otevřít anonymní kartu</translation>
<translation id="5565735124758917034">Aktivní</translation>
<translation id="5570825185877910964">Ochránit úÄet</translation>
<translation id="5571083550517324815">Vyzvednutí na této adrese není možné. Vyberte jinou adresu.</translation>
@@ -1520,6 +1557,7 @@ Kontaktujte administrátora systému.</translation>
<translation id="5869522115854928033">Uložená hesla</translation>
<translation id="5873013647450402046">Banka chce potvrdit vaši totožnost.</translation>
<translation id="5887400589839399685">Karta byla uložena</translation>
+<translation id="5887687176710214216">Naposledy navÅ¡tíveno vÄera</translation>
<translation id="5895138241574237353">Restartovat</translation>
<translation id="5895187275912066135">Datum vydání</translation>
<translation id="5901630391730855834">Žlutá</translation>
@@ -1533,6 +1571,7 @@ Kontaktujte administrátora systému.</translation>
<translation id="5921639886840618607">Uložit kartu do úÄtu Google?</translation>
<translation id="5922853866070715753">Téměř dokonÄeno</translation>
<translation id="5932224571077948991">Web zobrazuje rušivé nebo zavádějící reklamy</translation>
+<translation id="5938153366081463283">Přidat virtuální kartu</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347">Otevírání webu <ph name="SITE_NAME" />…</translation>
<translation id="5951495562196540101">Pomocí běžného uživatelského úÄtu se nelze zaregistrovat (je k dispozici licence v balíÄku).</translation>
@@ -1597,6 +1636,7 @@ Kontaktujte administrátora systému.</translation>
<translation id="6120179357481664955">Uložit vaše UPI ID?</translation>
<translation id="6124432979022149706">Konektory Chrome Enterprise</translation>
<translation id="6127379762771434464">Položka byla odstraněna</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Další informace o anonymním režimu v Chromu<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">Zkontrolujte vÅ¡echny kabely a restartujte vÅ¡echny smÄ›rovaÄe, modemy a další síťová zařízení, která používáte.</translation>
<translation id="614940544461990577">Zkuste:</translation>
<translation id="6150036310511284407">Tři díry vlevo</translation>
@@ -1608,7 +1648,6 @@ Kontaktujte administrátora systému.</translation>
<translation id="6169916984152623906">Nyní můžete procházet internet v soukromí a ostatní uživatelé tohoto zařízení vaši aktivitu neuvidí. Stažené soubory a záložky budou uloženy.</translation>
<translation id="6177128806592000436">Spojení s tímto webem není bezpeÄné</translation>
<translation id="6180316780098470077">Interval opakování</translation>
-<translation id="619448280891863779">Může žádat o otevírání a umísťování oken na obrazovkách</translation>
<translation id="6196640612572343990">Blokovat soubory cookie třetích stran</translation>
<translation id="6203231073485539293">Zkontrolujte připojení k internetu</translation>
<translation id="6218753634732582820">Odstranit adresu z prohlížeÄe Chromium?</translation>
@@ -1631,7 +1670,7 @@ Kontaktujte administrátora systému.</translation>
<translation id="6272383483618007430">Aktualizace Google</translation>
<translation id="6276112860590028508">Zde naleznete stránky ze seznamu Äetby</translation>
<translation id="627746635834430766">Abyste příštÄ› mohli zaplatit rychleji, uložte si kartu a fakturaÄní adresu do úÄtu Google.</translation>
-<translation id="6279098320682980337">Číslo virtuální karty není vyplněno? Klikněte na podrobnosti o kartě a zkopírujte ho</translation>
+<translation id="6279183038361895380">Kurzor zobrazíte stisknutím klávesy |<ph name="ACCELERATOR" />|</translation>
<translation id="6280223929691119688">DoruÄení na tuto adresu není možné. Vyberte jinou adresu.</translation>
<translation id="6282194474023008486">PSČ</translation>
<translation id="6285507000506177184">TlaÄítko správy stažených souborů v Chromu. Stisknutím klávesy Enter můžete spravovat soubory, které jste v Chromu stáhli</translation>
@@ -1639,6 +1678,7 @@ Kontaktujte administrátora systému.</translation>
<translation id="6290238015253830360">Zde se zobrazí navrhované Älánky</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">BezpeÄnostní kód kreditní karty (CVC):</translation>
+<translation id="6300452962057769623">{0,plural, =0{Zařízení se teÄ restartuje}=1{Zařízení se za 1 sekundu restartuje}few{Zařízení se za # sekundy restartuje}many{Zařízení se za # sekundy restartuje}other{Zařízení se za # sekund restartuje}}</translation>
<translation id="6302269476990306341">Zastavování Asistenta Google v Chromu</translation>
<translation id="6305205051461490394">Web <ph name="URL" /> není dostupný.</translation>
<translation id="6312113039770857350">Webová stránka není k dispozici</translation>
@@ -1712,6 +1752,7 @@ Kontaktujte administrátora systému.</translation>
<translation id="6529602333819889595">&amp;Opakovat smazání</translation>
<translation id="6545864417968258051">Vyhledávání Bluetooth</translation>
<translation id="6547208576736763147">Dva otvory vlevo</translation>
+<translation id="6554732001434021288">Naposledy navštíveno před <ph name="NUM_DAYS" /> dny</translation>
<translation id="6556866813142980365">Opakovat</translation>
<translation id="6569060085658103619">Prohlížíte si stránku rozšíření</translation>
<translation id="6573200754375280815">Dvě díry vpravo</translation>
@@ -1772,7 +1813,6 @@ Kontaktujte administrátora systému.</translation>
<translation id="6757797048963528358">Zařízení přešlo do režimu spánku.</translation>
<translation id="6767985426384634228">Aktualizovat adresu?</translation>
<translation id="6768213884286397650">Hagaki (pohlednice)</translation>
-<translation id="6774185088257932239"><ph name="BEGIN_LINK" />Další informace<ph name="END_LINK" /> o anonymním režimu</translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">Fialová</translation>
<translation id="6786747875388722282">Rozšíření</translation>
@@ -1856,7 +1896,6 @@ Kontaktujte administrátora systému.</translation>
<translation id="706295145388601875">Přidávejte a spravujte adresy v nastavení Chromu</translation>
<translation id="7064851114919012435">Kontaktní údaje</translation>
<translation id="7068733155164172741">Zadejte <ph name="OTP_LENGTH" />místný kód</translation>
-<translation id="7070090581017165256">O tomto webu</translation>
<translation id="70705239631109039">VaÅ¡e pÅ™ipojení není plnÄ› zabezpeÄené</translation>
<translation id="7075452647191940183">Požadavek je příliš velký</translation>
<translation id="7079718277001814089">Tento web obsahuje malware</translation>
@@ -1873,6 +1912,12 @@ Kontaktujte administrátora systému.</translation>
<translation id="7111012039238467737">(platný)</translation>
<translation id="7118618213916969306">Vyhledat adresu URL ve schránce, <ph name="SHORT_URL" /></translation>
<translation id="7119414471315195487">Zavřete ostatní karty nebo programy</translation>
+<translation id="7129355289156517987">Když zavÅ™ete vÅ¡echny anonymní karty prohlížeÄe Chromium, vaÅ¡e aktivita na tÄ›chto kartách bude ze zařízení vymazána:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />aktivita prohlížení,<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />historie vyhledávání,<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />údaje zadané do formulářů.<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">Dodání na tuto adresu není možné. Vyberte jinou adresu.</translation>
<translation id="7132939140423847331">Váš správce kopírování těchto dat zakázal.</translation>
<translation id="7135130955892390533">Zobrazit stav</translation>
@@ -1895,6 +1940,7 @@ Kontaktujte administrátora systému.</translation>
<translation id="7192203810768312527">Uvolní <ph name="SIZE" />. Je možné, že se nÄ›které weby pÅ™i příští návÅ¡tÄ›vÄ› budou naÄítat pomaleji.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">Administrátor má přístup k následujícím údajům:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, stisknutím klávesy Tab a poté Enter otevřete novou anonymní kartu, abyste mohli prohlížet v soukromí</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423">Web <ph name="HOST_NAME" /> nevyhovuje bezpeÄnostním standardům.</translation>
<translation id="7210993021468939304">Aktivita systému Linux v rámci kontejneru, může instalovat a spouštět aplikace Linux v kontejneru</translation>
@@ -1925,6 +1971,7 @@ Kontaktujte administrátora systému.</translation>
<translation id="7304562222803846232">Spravovat nastavení ochrany soukromí v úÄtu Google</translation>
<translation id="7305756307268530424">ZaÄít pomaleji</translation>
<translation id="7308436126008021607">synchronizace na pozadí</translation>
+<translation id="7310392214323165548">Zařízení se brzy restartuje</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">Pomoc s připojením</translation>
<translation id="7323804146520582233">Skrýt sekci <ph name="SECTION" /></translation>
@@ -1932,6 +1979,7 @@ Kontaktujte administrátora systému.</translation>
<translation id="7334320624316649418">&amp;Opakovat změnu uspořádání</translation>
<translation id="7335157162773372339">Může žádat o použití kamery</translation>
<translation id="7337248890521463931">Zobrazit další řádky</translation>
+<translation id="7337418456231055214">Číslo virtuální karty není vyplněno? Klikněte na podrobnosti o kartě a zkopírujte ho. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">Pro vaši platformu nedostupné.</translation>
<translation id="733923710415886693">Certifikát serveru nebyl zveřejněn prostřednictvím projektu Certificate Transparency.</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1954,6 +2002,7 @@ Kontaktujte administrátora systému.</translation>
<translation id="7378627244592794276">Ne</translation>
<translation id="7378810950367401542"> / </translation>
<translation id="7386364858855961704">Nelze použít</translation>
+<translation id="7388594495505979117">{0,plural, =1{Zařízení se za 1 minutu restartuje}few{Zařízení se za # minuty restartuje}many{Zařízení se za # minuty restartuje}other{Zařízení se za # minut restartuje}}</translation>
<translation id="7390545607259442187">Ověření karty</translation>
<translation id="7392089738299859607">Aktualizovat adresu</translation>
<translation id="7399802613464275309">BezpeÄnostní kontrola</translation>
@@ -1990,6 +2039,12 @@ Kontaktujte administrátora systému.</translation>
<translation id="7485870689360869515">Nebyla nalezena žádná data.</translation>
<translation id="7495528107193238112">Tento obsah je blokován. Požádejte vlastníka webu, aby tento problém vyřešil.</translation>
<translation id="7497998058912824456">TlaÄítko VytvoÅ™it dokument, stisknutím klávesy Enter rychle vytvoříte nový Dokument Google</translation>
+<translation id="7506488012654002225">Chromium <ph name="BEGIN_EMPHASIS" />nebude ukládat<ph name="END_EMPHASIS" /> následující informace:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />vaši historii prohlížení,
+ <ph name="LIST_ITEM" />soubory cookie a data webů,
+ <ph name="LIST_ITEM" />údaje zadané do formulářů.
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">Vrácené ID zařízení pro zásady je prázdné nebo neodpovídá aktuálnímu ID zařízení</translation>
<translation id="7508870219247277067">Žlutozelená</translation>
<translation id="7511955381719512146">Síť Wi-Fi, kterou používáte, může vyžadovat, abyste navštívili stránku <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
@@ -2103,7 +2158,6 @@ Kontaktujte administrátora systému.</translation>
<translation id="7813600968533626083">Odstranit návrh položky formuláře z Chromu?</translation>
<translation id="781440967107097262">Sdílet schránku?</translation>
<translation id="7815407501681723534">Nalezené <ph name="SEARCH_RESULTS" /> pro dotaz „<ph name="SEARCH_STRING" />“: <ph name="NUMBER_OF_RESULTS" /></translation>
-<translation id="782125616001965242">Zobrazit informace o tomto webu</translation>
<translation id="782886543891417279">Síť Wi-Fi, kterou používáte (<ph name="WIFI_NAME" />), může vyžadovat, abyste navštívili její stránku přihlášení.</translation>
<translation id="7836231406687464395">Postfix (obálka)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{Žádné}=1{1 aplikace (<ph name="EXAMPLE_APP_1" />)}=2{2 aplikace (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}few{# aplikace (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}many{# aplikace (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}other{# aplikací (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}}</translation>
@@ -2120,7 +2174,6 @@ Kontaktujte administrátora systému.</translation>
<translation id="7888575728750733395">Vykreslovací vzor tisku</translation>
<translation id="7894280532028510793">Pokud je adresa zadána správně, <ph name="BEGIN_LINK" />zkuste spustit Diagnostiku sítě<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (obálka)</translation>
-<translation id="7931318309563332511">Neznámé</translation>
<translation id="793209273132572360">Aktualizovat adresu?</translation>
<translation id="7932579305932748336">Potah</translation>
<translation id="79338296614623784">Zadejte platné telefonní Äíslo</translation>
@@ -2145,13 +2198,14 @@ Kontaktujte administrátora systému.</translation>
<translation id="7976214039405368314">Příliš mnoho požadavků</translation>
<translation id="7977538094055660992">Výstupní zařízení</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">Propojeno s</translation>
<translation id="798134797138789862">Může žádat o použití zařízení a dat pro virtuální realitu</translation>
<translation id="7984945080620862648">Web <ph name="SITE" /> teÄ nemůžete navÅ¡tívit, protože webové stránky odeslaly zakódované identifikaÄní údaje, které Chrome nedokáže zpracovat. Síťové chyby a útoky jsou obvykle doÄasné, tato stránka pravdÄ›podobnÄ› pozdÄ›ji bude fungovat.</translation>
-<translation id="79859296434321399">Chcete-li zobrazit obsah pro rozšířenou realitu, nainstalujte ARCore</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">Vazba</translation>
<translation id="7992044431894087211">Sdílení obrazovky s aplikací <ph name="APPLICATION_TITLE" /> bylo obnoveno</translation>
<translation id="7995512525968007366">Není zadáno</translation>
+<translation id="7998269595945679889">TlaÄítko Otevřít anonymní kartu, stisknutím klávesy Enter otevÅ™ete novou anonymní kartu, abyste mohli prohlížet v soukromí</translation>
<translation id="800218591365569300">Zkuste uvolnit paměť tím, že zavřete ostatní karty nebo programy.</translation>
<translation id="8004582292198964060">ProhlížeÄ</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{Tato karta a její fakturaÄní adresa se uloží. Budete ji moci používat, když budete pÅ™ihlášeni k úÄtu <ph name="USER_EMAIL" />.}few{Tyto karty a jejich fakturaÄní adresy se uloží. Budete je moci používat, když budete pÅ™ihlášeni k úÄtu <ph name="USER_EMAIL" />.}many{Tyto karty a jejich fakturaÄní adresy se uloží. Budete je moci používat, když budete pÅ™ihlášeni k úÄtu <ph name="USER_EMAIL" />.}other{Tyto karty a jejich fakturaÄní adresy se uloží. Budete je moci používat, když budete pÅ™ihlášeni k úÄtu <ph name="USER_EMAIL" />.}}</translation>
@@ -2211,6 +2265,7 @@ Kontaktujte administrátora systému.</translation>
<translation id="8202370299023114387">Konflikt</translation>
<translation id="8206978196348664717">Prc4 (obálka)</translation>
<translation id="8211406090763984747">PÅ™ipojení je zabezpeÄené</translation>
+<translation id="8217240300496046857">Weby vás nemohou na internetu sledovat pomocí souborů cookie. Některé weby mohou přestat fungovat.</translation>
<translation id="8218327578424803826">Přiřazené místo:</translation>
<translation id="8220146938470311105">C7/C6 (obálka)</translation>
<translation id="8225771182978767009">Uživatel, který tento poÄítaÄ nastavoval, se rozhodl tento web blokovat.</translation>
@@ -2251,14 +2306,9 @@ Kontaktujte administrátora systému.</translation>
<translation id="830498451218851433">Přeložení napůl</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">Nainstalované aplikace a Äetnost jejich používání</translation>
+<translation id="8317207217658302555">Aktualizovat ARCore?</translation>
<translation id="831997045666694187">VeÄer</translation>
<translation id="8321476692217554900">oznámení</translation>
-<translation id="8328484624016508118">Po zavření všech anonymních karet smaže Chrome:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />aktivitu prohlížení z tohoto zařízení,<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />historii vyhledávání z tohoto zařízení,<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />informace zadané ve formulářích.<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489">Přístup k webu <ph name="HOST_NAME" /> byl odepřen</translation>
<translation id="833262891116910667">Zvýraznit</translation>
<translation id="8339163506404995330">Stránky v jazyce <ph name="LANGUAGE" /> nebudou překládány</translation>
@@ -2310,6 +2360,7 @@ Další podrobnosti:
<translation id="8507227106804027148">Příkazový řádek</translation>
<translation id="8508648098325802031">Ikona Vyhledávání</translation>
<translation id="8511402995811232419">Spravovat soubory cookie</translation>
+<translation id="8519753333133776369">Zařízení HID povolené administrátorem</translation>
<translation id="8522552481199248698">Chrome vám může pomoci ochránit váš úÄet Google a zmÄ›nit heslo.</translation>
<translation id="8530813470445476232">Vymažte historii prohlížení, soubory cookie, mezipaměť a další data v nastavení Chromu</translation>
<translation id="8533619373899488139">Na stránce &lt;strong&gt;chrome://policy&lt;/strong&gt; naleznete seznam blokovaných adres URL a další zásady vynucené vaším administrátorem systému.</translation>
@@ -2321,7 +2372,6 @@ Další podrobnosti:
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{Resetovat oprávnění}few{Resetovat oprávnění}many{Resetovat oprávnění}other{Resetovat oprávnění}}</translation>
<translation id="8555010941760982128">Při placení použijte tento kód</translation>
<translation id="8557066899867184262">Kód CVC je uveden na zadní straně karty.</translation>
-<translation id="8558485628462305855">Chcete-li zobrazit obsah pro rozšířenou realitu, aktualizujte ARCore</translation>
<translation id="8559762987265718583">Soukromé pÅ™ipojení k doménÄ› <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> nelze navázat, protože máte v zařízení nastaveno chybné datum a Äas (<ph name="DATE_AND_TIME" />).</translation>
<translation id="8564182942834072828">Oddělené dokumenty / nekompletované kopie</translation>
<translation id="8564985650692024650">Pokud jste heslo organizace <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> použili na jiném webu, doporuÄujeme vám ho resetovat.</translation>
@@ -2341,6 +2391,7 @@ Další podrobnosti:
<translation id="865032292777205197">senzory pohybu</translation>
<translation id="8663226718884576429">Shrnutí objednávky, <ph name="TOTAL_LABEL" />, další podrobnosti</translation>
<translation id="8666678546361132282">angliÄtina</translation>
+<translation id="8669306706049782872">Použít informace o vašich obrazovkách k otevírání a umísťování oken</translation>
<translation id="867224526087042813">Podpis</translation>
<translation id="8676424191133491403">Bez prodlevy</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, odpovÄ›Ä, <ph name="ANSWER" /></translation>
@@ -2367,6 +2418,7 @@ Další podrobnosti:
<translation id="8731544501227493793">TlaÄítko Spravovat hesla, stisknutím klávesy Enter můžete zobrazit a spravovat hesla v nastavení Chromu</translation>
<translation id="8734529307927223492">Váš <ph name="DEVICE_TYPE" /> spravuje doména <ph name="MANAGER" /></translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, stisknutím klávesy Tab a poté Enter otevřete nové anonymní okno, abyste mohli prohlížet v soukromí</translation>
+<translation id="8737685506611670901">Otevírat odkazy <ph name="PROTOCOL" /> namísto aplikace <ph name="REPLACED_HANDLER_TITLE" /></translation>
<translation id="8738058698779197622">Aby bylo možné navázat zabezpeÄené spojení, hodiny musejí být nastaveny správnÄ›. Důvodem je, že certifikáty, pomocí kterých se weby identifikují, platí pouze pro pevnÄ› daná období. Jelikož hodiny v zařízení nejsou nastaveny správnÄ›, prohlížeÄ Chromium tyto certifikáty nemůže ověřit.</translation>
<translation id="8740359287975076522">&lt;abbr id="dnsDefinition"&gt;Adresu DNS&lt;/abbr&gt; webu <ph name="HOST_NAME" /> nelze najít. Diagnostikování problému…</translation>
<translation id="8742371904523228557">Váš kód pro <ph name="ORIGIN" /> je <ph name="ONE_TIME_CODE" /></translation>
@@ -2394,6 +2446,7 @@ Další podrobnosti:
<translation id="883848425547221593">Jiné záložky</translation>
<translation id="884264119367021077">Dodací adresa</translation>
<translation id="884923133447025588">Nebyl nalezen žádný mechanismus zamítnutí.</translation>
+<translation id="8849262850971482943">Pro vÄ›tší bezpeÄnost používejte virtuální kartu</translation>
<translation id="885730110891505394">Sdílení s Googlem</translation>
<translation id="8858065207712248076">Pokud jste heslo organizace <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> použili na jiném webu, doporuÄujeme vám ho resetovat.</translation>
<translation id="885906927438988819">Pokud je adresa zadána správně, <ph name="BEGIN_LINK" />zkuste spustit Diagnostiku sítě systému Windows<ph name="END_LINK" />.</translation>
@@ -2443,6 +2496,7 @@ Další podrobnosti:
<translation id="9004367719664099443">Probíhá relace VR</translation>
<translation id="9005998258318286617">NaÄtení dokumentu PDF se nezdaÅ™ilo.</translation>
<translation id="9008201768610948239">Ignorovat</translation>
+<translation id="901834265349196618">e-mail</translation>
<translation id="9020200922353704812">FakturaÄní adresa karty je povinná</translation>
<translation id="9020542370529661692">Stránka byla přeložena do jazyka <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9020742383383852663">A8</translation>
@@ -2491,6 +2545,7 @@ Další podrobnosti:
<translation id="9150045010208374699">Používat fotoaparát</translation>
<translation id="9150685862434908345">Administrátor může nastavení prohlížeÄe vzdálenÄ› zmÄ›nit. Aktivita na tomto zařízení může být spravována také mimo Chrome. <ph name="BEGIN_LINK" />Další informace<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">Aktualizováno</translation>
+<translation id="9155211586651734179">Jsou připojeny zvukové periferie</translation>
<translation id="9157595877708044936">Nastavování...</translation>
<translation id="9158625974267017556">C6 (obálka)</translation>
<translation id="9164029392738894042">Kontrola přesnosti</translation>
diff --git a/chromium/components/strings/components_strings_da.xtb b/chromium/components/strings/components_strings_da.xtb
index b804568cc79..639cdef6edc 100644
--- a/chromium/components/strings/components_strings_da.xtb
+++ b/chromium/components/strings/components_strings_da.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">FÃ¥ flere oplysninger</translation>
<translation id="1030706264415084469"><ph name="URL" /> anmoder om at gemme store datamængder permanent på din enhed</translation>
<translation id="1032854598605920125">Rotér med uret</translation>
+<translation id="1033329911862281889">Inkognitotilstand gør dig ikke usynlig på nettet:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Websites og de tjenester, de anvender, kan se besøg<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Arbejdsgivere og skoler kan spore browseraktivitet<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Internetudbydere kan overvåge webtrafik<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">Deaktiver</translation>
<translation id="1036982837258183574">Tryk på |<ph name="ACCELERATOR" />| for at afslutte fuld skærm</translation>
<translation id="1038106730571050514">Vis forslag</translation>
<translation id="1038842779957582377">ukendt navn</translation>
<translation id="1041998700806130099">Jobarksmeddelelse</translation>
<translation id="1048785276086539861">NÃ¥r du redigerer annoteringer, skifter dette dokument tilbage til enkeltsidevisning</translation>
-<translation id="1049743911850919806">Inkognito</translation>
<translation id="1050038467049342496">Luk andre apps</translation>
<translation id="1055184225775184556">&amp;Fortryd tilføjelse</translation>
<translation id="1056898198331236512">Advarsel</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">Cache for politik er OK</translation>
<translation id="1130564665089811311">Knappen Oversæt side – tryk på Enter for at oversætte denne side med Google Oversæt</translation>
<translation id="1131264053432022307">Billede, du har kopieret</translation>
+<translation id="1142846828089312304">Bloker tredjepartscookies i inkognitotilstand</translation>
<translation id="1150979032973867961">Denne server kunne ikke bevise, at den er <ph name="DOMAIN" />, da operativsystemet på din computer ikke har tillid til sikkerhedscertifikatet. Dette kan skyldes en fejlkonfiguration, eller at en hacker har opfanget din forbindelse.</translation>
<translation id="1151972924205500581">En adgangskode er påkrævet</translation>
<translation id="1156303062776767266">Du får vist en lokal eller delt fil</translation>
@@ -64,7 +70,6 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="1178581264944972037">Pause</translation>
<translation id="1181037720776840403">Fjern</translation>
<translation id="1186201132766001848">Tjek adgangskoder</translation>
-<translation id="1195210374336998651">GÃ¥ til appindstillinger</translation>
<translation id="1195558154361252544">Notifikationer blokeres automatisk for alle website med undtagelse dem, du har givet tilladelse til</translation>
<translation id="1197088940767939838">Orange</translation>
<translation id="1201402288615127009">Næste</translation>
@@ -111,7 +116,7 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="1307966114820526988">Udfasede funktioner</translation>
<translation id="1308113895091915999">Tilgængeligt kampagnetilbud</translation>
<translation id="1312803275555673949">Hvilke beviser underbygger dette?</translation>
-<translation id="131405271941274527"><ph name="URL" /> ønsker at sende og modtage oplysninger, når du parrer din telefon med en NFC-enhed</translation>
+<translation id="1314311879718644478">Vis indhold med augmented reality</translation>
<translation id="1314509827145471431">Bind i højre side</translation>
<translation id="1318023360584041678">Gemt i fanegruppe</translation>
<translation id="1319245136674974084">Spørg ikke igen for denne app</translation>
@@ -161,6 +166,7 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="142858679511221695">Skybruger</translation>
<translation id="1428729058023778569">Du får vist denne advarsel, fordi dette website ikke understøtter HTTPS. <ph name="BEGIN_LEARN_MORE_LINK" />Få flere oplysninger<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">Udskriv</translation>
+<translation id="1432187715652018471">Denne side ønsker at installere en tjenestehandler.</translation>
<translation id="1432581352905426595">Administrer søgemaskiner</translation>
<translation id="1436185428532214179">Websitet kan anmode om tilladelse til at redigere filer og mapper på din enhed</translation>
<translation id="1442386063175183758">Portfals i højre side</translation>
@@ -181,6 +187,12 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="1483493594462132177">Send</translation>
<translation id="1484290072879560759">Vælg leveringsadresse</translation>
<translation id="1492194039220927094">Underretning om politikker:</translation>
+<translation id="149293076951187737">NÃ¥r du lukker alle inkognitofaner i Chrome, slettes din aktivitet i disse faner fra denne enhed:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Browseraktivitet<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Søgehistorik<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Oplysninger, der er angivet i formularer<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">Tilbage til fanen</translation>
<translation id="1501859676467574491">Vis kort fra din Google-konto</translation>
<translation id="1507202001669085618">&lt;p&gt;Denne fejl vises, hvis du bruger en Wi-Fi-portal, hvor du skal logge ind, før du kan komme på nettet.&lt;/p&gt;
@@ -208,6 +220,8 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="1559572115229829303">&lt;p&gt;Der kan ikke oprettes en privat forbindelse til <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />, da datoen og tiden på din enhed (<ph name="DATE_AND_TIME" />) er forkert.&lt;/p&gt;
&lt;p&gt;Juster datoen og tiden i sektionen &lt;strong&gt;Generelt&lt;/strong&gt; i appen &lt;strong&gt;Indstillinger&lt;/strong&gt;.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">Din administrator vil genstarte din enhed klokken <ph name="TIME" /> den <ph name="DATE" /></translation>
+<translation id="156703335097561114">Netværksoplysninger som f.eks. adresser, grænsefladekonfiguration og forbindelseskvalitet</translation>
<translation id="1567040042588613346">Denne politik fungerer efter hensigten, men et andet sted er den samme værdi blevet tilsidesat af denne politik.</translation>
<translation id="1569487616857761740">Angiv udløbsdato</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="1583429793053364125">Noget gik galt ved visningen af denne webside.</translation>
<translation id="1586541204584340881">Hvilke udvidelser, du har installeret</translation>
<translation id="1588438908519853928">Normal</translation>
+<translation id="1589050138437146318">Vil du installere ARCore?</translation>
<translation id="1592005682883173041">Lokal dataadgang</translation>
<translation id="1594030484168838125">Vælg</translation>
<translation id="160851722280695521">Spil Dino Run-spillet i Chrome</translation>
@@ -283,6 +298,7 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
en fejl i headeren, som forhindrer browseren i at opfylde
din anmodning til <ph name="SITE" />. Politikker for oprindelse kan anvendes af
websiteoperatorer til at konfigurere sikkerhed og andre egenskaber for et website.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />FÃ¥ flere oplysninger om inkognitotilstand i Chromium<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">Dine åbne faner vises her</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -410,6 +426,7 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="22081806969704220">Bakke 3</translation>
<translation id="2212735316055980242">Politikken blev ikke fundet</translation>
<translation id="2213606439339815911">Indlæg hentes...</translation>
+<translation id="2213612003795704869">Siden er udskrevet</translation>
<translation id="2215727959747642672">Filredigering</translation>
<translation id="2218879909401188352">Hackere, der i øjeblikket er på <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />, kan installere farlige apps, som kan skade din enhed, føje skjulte gebyrer til din mobilregning eller stjæle dine personlige oplysninger. <ph name="BEGIN_LEARN_MORE_LINK" />Få flere oplysninger<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">Der er ingen internetforbindelse</translation>
@@ -419,6 +436,7 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="2248949050832152960">Brug WebAuthn</translation>
<translation id="2250931979407627383">Kanthæftning i venstre side</translation>
<translation id="225207911366869382">Denne værdi er forældet for denne politik.</translation>
+<translation id="2256115617011615191">Genstart nu</translation>
<translation id="2258928405015593961">Angiv en fremtidig udløbsdato, og prøv igen</translation>
<translation id="225943865679747347">Fejlkode: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">HTTP-fejl</translation>
@@ -446,6 +464,7 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="2337852623177822836">Indstillingen styres af din administrator</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> vil gerne parre</translation>
<translation id="2346319942568447007">Billede, du har kopieret</translation>
+<translation id="2350796302381711542">Vil du tillade, at <ph name="HANDLER_HOSTNAME" /> åbner alle <ph name="PROTOCOL" />-links i stedet for <ph name="REPLACED_HANDLER_TITLE" />?</translation>
<translation id="2354001756790975382">Andre bogmærker</translation>
<translation id="2354430244986887761">Google Beskyttet browsing har for nylig <ph name="BEGIN_LINK" />fundet skadelige apps<ph name="END_LINK" /> på <ph name="SITE" />.</translation>
<translation id="2355395290879513365">Hackere kan muligvis se de billeder, du kigger på på dette website, og narre dig ved at ændre dem.</translation>
@@ -471,6 +490,7 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="2413528052993050574">Denne server kunne ikke bevise, at den er <ph name="DOMAIN" />, da sikkerhedscertifikatet muligvis er blevet tilbagekaldt. Dette kan skyldes en fejlkonfiguration, eller at en hacker har opfanget din forbindelse.</translation>
<translation id="2414886740292270097">Mørk</translation>
<translation id="2430968933669123598">Administrer Google-konto, tryk på Enter for at administrere dine oplysninger, dit privatliv og beskyttelsen på din Google-konto</translation>
+<translation id="2436186046335138073">Vil du tillade, at <ph name="HANDLER_HOSTNAME" /> åbner alle <ph name="PROTOCOL" />-links?</translation>
<translation id="2438874542388153331">Fire huller i højre side</translation>
<translation id="2450021089947420533">Søgninger</translation>
<translation id="2463739503403862330">Udfyld</translation>
@@ -478,6 +498,7 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="2465655957518002998">Vælg leveringsmetode</translation>
<translation id="2465688316154986572">Hæftning</translation>
<translation id="2465914000209955735">Administrer de filer, du har downloadet i Chrome</translation>
+<translation id="2466004615675155314">Se oplysninger fra nettet</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Køre Netværksdiagnosticering<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">1-til-N-rækkefølge</translation>
<translation id="2470767536994572628">NÃ¥r du redigerer annoteringer, skifter dette dokument tilbage til enkeltsidevisning og dets oprindelige rotation</translation>
@@ -498,6 +519,7 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="2523886232349826891">Gemmes kun på denne enhed</translation>
<translation id="2524461107774643265">Tilføj flere oplysninger</translation>
<translation id="2529899080962247600">Dette felt må ikke have mere end <ph name="MAX_ITEMS_LIMIT" /> poster. Alle yderligere poster ignoreres.</translation>
+<translation id="2535585790302968248">Ã…bn en ny inkognitofane for at browse privat</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{og 1 mere}one{og # mere}other{og # mere}}</translation>
<translation id="2536110899380797252">Tilføj adresse</translation>
<translation id="2539524384386349900">Registrer</translation>
@@ -523,7 +545,14 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="2597378329261239068">Dette dokument er adgangskodebeskyttet. Angiv en adgangskode.</translation>
<translation id="2609632851001447353">Varianter</translation>
<translation id="2610561535971892504">Klik for at kopiere</translation>
+<translation id="2617988307566202237">Chrome <ph name="BEGIN_EMPHASIS" />gemmer ikke<ph name="END_EMPHASIS" /> følgende oplysninger:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Din browserhistorik
+ <ph name="LIST_ITEM" />Cookies og websitedata
+ <ph name="LIST_ITEM" />Oplysninger, der er angivet i formularer
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (Envelope)</translation>
+<translation id="2623663032199728144">Kan anmode om at bruge oplysninger om dine skærme</translation>
<translation id="2625385379895617796">Dit ur er foran</translation>
<translation id="262745152991669301">Websitet kan anmode om tilladelse til at oprette forbindelse til USB-enheder</translation>
<translation id="2629325967560697240"><ph name="BEGIN_ENHANCED_PROTECTION_LINK" />Aktivér forbedret beskyttelse<ph name="END_ENHANCED_PROTECTION_LINK" /> for at få Chromes højeste sikkerhedsniveau</translation>
@@ -557,6 +586,7 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="2709516037105925701">AutoFyld</translation>
<translation id="2713444072780614174">Hvid</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" /> – tryk på Tab-tasten efterfulgt af Enter for at administrere oplysninger om dine betalinger og betalingskort i Chrome-indstillingerne</translation>
+<translation id="271663710482723385">Tryk på |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| for at afslutte visning i fuld skærm</translation>
<translation id="2721148159707890343">Anmodning lykkedes</translation>
<translation id="2723669454293168317">Kør et sikkerhedstjek i Chrome-indstillingerne</translation>
<translation id="2726001110728089263">Sidebakke</translation>
@@ -587,6 +617,7 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="2850739647070081192">Invite (Envelope)</translation>
<translation id="2856444702002559011">Brugere med ondsindede hensigter kan forsøge at stjæle dine oplysninger fra <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (f.eks. adgangskoder, beskeder eller kreditkort). <ph name="BEGIN_LEARN_MORE_LINK" />Få flere oplysninger<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">Dette website viser påtrængende eller vildledende annoncer.</translation>
+<translation id="286512204874376891">Et virtuelt kort skjuler dit faktiske kort og beskytter dig på den måde mod potentiel svindel. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">Afslappet</translation>
<translation id="2876489322757410363">Du forlader inkognitotilstand for at betale via en ekstern app. Vil du fortsætte?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />– tryk på Tab-tasten efterfulgt af Enter for at administrere Beskyttet browsing m.m. i Chrome-indstillingerne</translation>
@@ -611,6 +642,7 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="2930577230479659665">Beskær efter hver kopi</translation>
<translation id="2932085390869194046">Foreslå adgangskode...</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019">Ã…bne <ph name="PROTOCOL" />-links</translation>
<translation id="2941952326391522266">Denne server kunne ikke bevise, at den er <ph name="DOMAIN" />, da sikkerhedscertifikatet er fra <ph name="DOMAIN2" />. Dette kan skyldes en fejlkonfiguration, eller at en hacker har opfanget din forbindelse.</translation>
<translation id="2943895734390379394">Tidspunkt for upload:</translation>
<translation id="2948083400971632585">Du kan deaktivere alle proxyer, der er konfigureret for en forbindelse, fra siden Indstillinger.</translation>
@@ -643,6 +675,7 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="3037605927509011580">Øv, surt!</translation>
<translation id="3041612393474885105">Certifikatoplysninger</translation>
<translation id="3044034790304486808">Genoptag din søgning</translation>
+<translation id="305162504811187366">Historik for Chrome Fjernskrivebord, herunder tidsstempler, hosts og id'er for klientsessioner</translation>
<translation id="3060227939791841287">C9 (Envelope)</translation>
<translation id="3061707000357573562">Tjeneste til programrettelse</translation>
<translation id="306573536155379004">Spillet er startet.</translation>
@@ -683,6 +716,7 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="3197136577151645743">Websitet kan anmode om tilladelse til at blive underrettet, når du aktivt bruger din enhed</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />, tryk på Tab-tasten efterfulgt af Enter for at administrere, hvilke oplysninger der skal synkroniseres, i Chrome-indstillingerne</translation>
<translation id="320323717674993345">Annuller betaling</translation>
+<translation id="3203366800380907218">Fra nettet</translation>
<translation id="3207960819495026254">Gemt som bogmærke</translation>
<translation id="3209034400446768650">Siden kan opkræve betaling</translation>
<translation id="3212581601480735796">Din aktivitet på <ph name="HOSTNAME" /> overvåges</translation>
@@ -699,10 +733,12 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="3234666976984236645">Registrer altid vigtigt indhold på dette website</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />– tryk på Tab-tasten efterfulgt af Enter for at tilpasse din browsers udseende</translation>
<translation id="3240791268468473923">Regneark uden matchende loginoplysninger til sikker betaling er åbent</translation>
+<translation id="324180406144491771">"<ph name="HOST_NAME" />"-links er blokeret</translation>
<translation id="3249845759089040423">Groovy</translation>
<translation id="3252266817569339921">Fransk</translation>
<translation id="3257954757204451555">Hvor stammer disse oplysninger fra?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />, tryk på Tab-tasten efterfulgt af Enter for hurtigt at oprette en ny begivenhed i Google Kalender</translation>
+<translation id="3261488570342242926">FÃ¥ flere oplysninger om virtuelle kort</translation>
<translation id="3264837738038045344">Knappen Administrer Chrome-indstillinger, tryk på Enter for at gå til dine Chrome-indstillinger</translation>
<translation id="3266793032086590337">Værdi (modstridende)</translation>
<translation id="3268451620468152448">Ã…bne faner</translation>
@@ -716,6 +752,7 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="3288238092761586174"><ph name="URL" /> er muligvis nødt til at gennemføre yderligere trin for at bekræfte din betaling</translation>
<translation id="3293642807462928945">FÃ¥ flere oplysninger om politikken <ph name="POLICY_NAME" /></translation>
<translation id="3295444047715739395">Se og administrer dine adgangskoder i Chrome-indstillingerne</translation>
+<translation id="3303795387212510132">Vil du tillade, at appen åbner <ph name="PROTOCOL_SCHEME" />-links?</translation>
<translation id="3303855915957856445">Der blev ikke fundet nogen søgeresultater</translation>
<translation id="3304073249511302126">Bluetooth-scanning</translation>
<translation id="3308006649705061278">Organisationsenhed (OU)</translation>
@@ -729,12 +766,6 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="3345782426586609320">Øjne</translation>
<translation id="3355823806454867987">Skift indstillinger for proxy...</translation>
<translation id="3360103848165129075">Regneark for betalingshandler</translation>
-<translation id="3361596688432910856">Chrome <ph name="BEGIN_EMPHASIS" />gemmer ikke<ph name="END_EMPHASIS" /> følgende oplysninger:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Din browserhistorik
- <ph name="LIST_ITEM" />Cookies og websitedata
- <ph name="LIST_ITEM" />Oplysninger, du angiver i formularer
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">Denne politik blev automatisk kopieret fra den udfasede politik <ph name="OLD_POLICY" />. Du bør bruge denne politik i stedet.</translation>
<translation id="3364869320075768271"><ph name="URL" /> vil gerne anvende din virtual reality-enhed og dine VR-data</translation>
<translation id="3366477098757335611">Se kort</translation>
@@ -817,7 +848,6 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="3587738293690942763">I midten</translation>
<translation id="3592413004129370115">Italian (Envelope)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{Du kan til enhver tid nulstille din gruppe. Det tager ca. en dag at blive medlem af en nye gruppe.}=1{Du kan til enhver tid nulstille din gruppe. Det tager ca. en dag at blive medlem af en nye gruppe.}one{Du kan til enhver tid nulstille din gruppe. Det tager {NUM_DAYS} dag at blive medlem af en ny gruppe.}other{Du kan til enhver tid nulstille din gruppe. Det tager {NUM_DAYS} dage at blive medlem af en ny gruppe.}}</translation>
-<translation id="3596012367874587041">Appindstillinger</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">Appen er blokeret af din administrator</translation>
<translation id="3608932978122581043">Retning for indførelse</translation>
@@ -860,6 +890,7 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="370972442370243704">Aktivér Søgninger</translation>
<translation id="3711895659073496551">Suspender</translation>
<translation id="3712624925041724820">Licenserne er opbrugt</translation>
+<translation id="3714633008798122362">webkalender</translation>
<translation id="3714780639079136834">Tænde for mobildata eller Wi-Fi</translation>
<translation id="3715597595485130451">Opret forbindelse til Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Tjekke proxy-, firewall- og DNS-konfigurationen<ph name="END_LINK" /></translation>
@@ -921,6 +952,7 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="3906954721959377182">Tablet</translation>
<translation id="3909477809443608991"><ph name="URL" /> vil afspille beskyttet indhold. Din enheds identitet bekræftes af Google, og dette website får muligvis adgang til enheden.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">Afvis</translation>
<translation id="3939773374150895049">Vil du bruge WebAuthn i stedet for kontrolkoden?</translation>
<translation id="3946209740501886391">Spørg altid på dette website</translation>
<translation id="3947595700203588284">Websitet kan anmode om tilladelse til at oprette forbindelse til MIDI-enheder</translation>
@@ -942,6 +974,7 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="3990250421422698716">Langsom offsetkørsel</translation>
<translation id="3996311196211510766">Websitet <ph name="ORIGIN" /> har anmodet om, at en politik for oprindelse
skal gælde for alle anmodninger til websitet, men i øjeblikket kan denne politik ikke anvendes.</translation>
+<translation id="4009243425692662128">Indholdet på de sider, du udskriver, sendes til analyse i Google Cloud eller hos tredjeparter. Tekst kan f.eks. blive scannet for følsomme oplysninger.</translation>
<translation id="4010758435855888356">Vil du give adgang til lagerpladsen?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{PDF-dokument, der indeholder {COUNT} side}one{PDF-dokument, der indeholder {COUNT} side}other{PDF-dokument, der indeholder {COUNT} sider}}</translation>
<translation id="4023431997072828269">Da denne formular indsendes via en forbindelse, som ikke er sikker, bliver dine oplysninger synlige for andre.</translation>
@@ -1036,6 +1069,7 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="4250680216510889253">Nej</translation>
<translation id="4253168017788158739">Note</translation>
<translation id="425582637250725228">Ændringer, du har foretaget, gemmes muligvis ikke.</translation>
+<translation id="425869179292622354">Vil du gøre det mere sikkert med et virtuelt kort?</translation>
<translation id="4258748452823770588">Forkert signatur</translation>
<translation id="4261046003697461417">Beskyttede dokumenter kan ikke annoteres</translation>
<translation id="4265872034478892965">Tilladt af din administrator</translation>
@@ -1098,6 +1132,7 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="4434045419905280838">Pop op-vinduer og omdirigeringer</translation>
<translation id="4435702339979719576">Postcard)</translation>
<translation id="443673843213245140">Brug af en proxy er deaktiveret, men en eksplicit proxykonfiguration er angivet.</translation>
+<translation id="4441832193888514600">Ignoreret, fordi politikken kun kan angives som en skybrugerpolitik.</translation>
<translation id="4450893287417543264">Vis ikke igen</translation>
<translation id="4451135742916150903">Websitet kan anmode om tilladelse til at oprette forbindelse til HID-enheder</translation>
<translation id="4452328064229197696">Den adgangskode, du lige har brugt, er blevet lækket i forbindelse med et brud på datasikkerheden. For at beskytte dine konti anbefaler Google Adgangskodeadministrator, at du tjekker dine gemte adgangskoder.</translation>
@@ -1110,7 +1145,7 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="4481251927743463293">Hvad gør inkognitotilstand?</translation>
<translation id="4482953324121162758">Dette website kan ikke oversættes.</translation>
<translation id="4490717597759821841">A7</translation>
-<translation id="449126573531210296">Krypter synkroniserede adgangskoder med din Google-konto</translation>
+<translation id="449126573531210296">Kryptér synkroniserede adgangskoder med din Google-konto</translation>
<translation id="4492519888999857993">Disse funktioner er som standard deaktiveret. De vil ikke være tilgængelige i fremtidige versioner af Chrome.</translation>
<translation id="4493480324863638523">Webadressen er ugyldig. Webadressen skal indeholde et standardskema, f.eks. http://eksempel.dk eller https://eksempel.dk.</translation>
<translation id="4500587658229086076">usikkert indhold</translation>
@@ -1153,6 +1188,7 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="4628948037717959914">Billede</translation>
<translation id="4631649115723685955">Penge tilbage er tilknyttet</translation>
<translation id="4636930964841734540">Oplysninger</translation>
+<translation id="4638670630777875591">Inkognitotilstand i Chromium</translation>
<translation id="464342062220857295">Søgefunktioner</translation>
<translation id="4644670975240021822">Omvendt rækkefølge med forside nedad</translation>
<translation id="4646534391647090355">Før mig dertil nu</translation>
@@ -1173,6 +1209,7 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="4708268264240856090">Din forbindelse blev afbrudt</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Køre Windows Netværksdiagnosticering<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426">Adgangskode til <ph name="USERNAME" /></translation>
<translation id="4724144314178270921">Websitet kan anmode om tilladelse til at se tekst og billeder i din udklipsholder</translation>
<translation id="4726672564094551039">Opdater politikker</translation>
<translation id="4728558894243024398">Platform</translation>
@@ -1194,6 +1231,7 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="4757993714154412917">Du har lige angivet din adgangskode på et vildledende website. Chromium anbefaler, at du tjekker dine gemte adgangskoder for at sikre dine konti.</translation>
<translation id="4758311279753947758">Tilføj kontaktoplysninger</translation>
<translation id="4761104368405085019">Bruge din mikrofon</translation>
+<translation id="4761869838909035636">Kør Chrome-sikkerhedstjekket</translation>
<translation id="4764776831041365478">Websiden på <ph name="URL" /> kan være midlertidigt nede, eller også er den permanent flyttet til en ny webadresse.</translation>
<translation id="4766713847338118463">Dobbelthæftning nederst</translation>
<translation id="4771973620359291008">Der er opstået en ukendt fejl.</translation>
@@ -1214,12 +1252,6 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="4819347708020428563">Vil du redigere annoteringer i standardvisningen?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />, tryk på Tab-tasten efterfulgt af Enter for hurtigt at oprette et nyt Google-regneark</translation>
<translation id="4825507807291741242">Kraftfuld</translation>
-<translation id="4827402517081186284">Inkognitotilstand gør dig ikke usynlig på nettet:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Websites ved, hvornår du besøger dem<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Arbejdspladser og skoler kan spore browseraktivitet<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Internetudbydere kan spore webtrafik<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">Aktivér advarsler</translation>
<translation id="4838327282952368871">Drømmende</translation>
<translation id="4840250757394056958">Se din Chrome-historik</translation>
@@ -1231,12 +1263,12 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="4854362297993841467">Denne leveringsmetode er ikke tilgængelig. Prøv en anden metode.</translation>
<translation id="4854853140771946034">Opret hurtigt en ny note i Google Keep</translation>
<translation id="485902285759009870">Bekræfter koden...</translation>
+<translation id="4866506163384898554">Tryk på |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| for at se din markør</translation>
<translation id="4876188919622883022">Enkel visning</translation>
<translation id="4876305945144899064">Intet brugernavn</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{Ingen}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}one{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831"><ph name="TEXT" />-søgning</translation>
<translation id="4879491255372875719">Automatisk (standard)</translation>
-<translation id="4879725228911483934">Åbne og placere vinduer på dine skærme</translation>
<translation id="4880827082731008257">Søg i historikken</translation>
<translation id="4881695831933465202">Ã…bn</translation>
<translation id="4885256590493466218">Betal med <ph name="CARD_DETAIL" /> ved kassen</translation>
@@ -1245,6 +1277,7 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">Niende papirrulle</translation>
<translation id="4901778704868714008">Gem...</translation>
+<translation id="4905659621780993806">Din administrator genstarter automatisk din enhed <ph name="TIME" /> <ph name="DATE" />. Gem eventuelle åbne elementer, inden din enhed genstarter.</translation>
<translation id="4913987521957242411">Hul øverst til venstre</translation>
<translation id="4918221908152712722">Installer <ph name="APP_NAME" /> (kræver ikke download)</translation>
<translation id="4923459931733593730">Betaling</translation>
@@ -1253,6 +1286,7 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, tryk på Tab-tasten efterfulgt af Enter for at søge</translation>
<translation id="4930153903256238152">Stor kapacitet</translation>
+<translation id="4940163644868678279">Inkognitotilstand i Chrome</translation>
<translation id="4943872375798546930">Ingen resultater</translation>
<translation id="4950898438188848926">Knap til faneskift. Tryk på Enter for at skifte til den åbne fane, <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="495170559598752135">Handlinger</translation>
@@ -1262,6 +1296,7 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="4968522289500246572">Denne app er udviklet til mobilenheder. Du kan muligvis ikke justere størrelsen på den uden at opleve problemer. Hvis du gør, kan der opstå fejl, eller appen kan genstarte.</translation>
<translation id="4969341057194253438">Slet optagelse</translation>
<translation id="4973922308112707173">To huller øverst</translation>
+<translation id="4976702386844183910">Senest besøgt <ph name="DATE" /></translation>
<translation id="4984088539114770594">Vil du bruge mikrofonen?</translation>
<translation id="4984339528288761049">Prc5 (Envelope)</translation>
<translation id="4989163558385430922">Se alle</translation>
@@ -1323,6 +1358,7 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="5138227688689900538">Vis færre</translation>
<translation id="5145883236150621069">Fejlkode til stede i politiksvar</translation>
<translation id="5146995429444047494">Notifikationer for <ph name="ORIGIN" /> blokeres</translation>
+<translation id="514704532284964975"><ph name="URL" /> vil have adgang til og ændre oplysninger på NFC-enheder, som du trykker på via din telefon</translation>
<translation id="5148809049217731050">Forside opad</translation>
<translation id="515292512908731282">C4 (Envelope)</translation>
<translation id="5158275234811857234">Forside</translation>
@@ -1347,6 +1383,7 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="5215116848420601511">Betalingsmetoder og adresser, der bruger Google Pay</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">Bakke 13</translation>
+<translation id="5216942107514965959">Senest besøgt i dag</translation>
<translation id="5222812217790122047">Mail påkrævet</translation>
<translation id="5230733896359313003">Leveringsadresse</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1367,7 +1404,6 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">Dokumentegenskaber</translation>
<translation id="528468243742722775">Afslut</translation>
-<translation id="5284909709419567258">Netværksadresser</translation>
<translation id="5285570108065881030">Se alle gemte adgangskoder</translation>
<translation id="5287240709317226393">Vis cookies</translation>
<translation id="5287456746628258573">Dette website benytter en forældet sikkerhedskonfiguration, der muligvis afslører dine oplysninger (f.eks. adgangskoder eller betalingskortnumre), når de sendes til dette website.</translation>
@@ -1451,6 +1487,7 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="5556459405103347317">Genindlæs</translation>
<translation id="5560088892362098740">Udløbsdato</translation>
<translation id="55635442646131152">Indholdsfortegnelse</translation>
+<translation id="5565613213060953222">Ã…bn inkognitofane</translation>
<translation id="5565735124758917034">Aktiv</translation>
<translation id="5570825185877910964">Beskyt konto</translation>
<translation id="5571083550517324815">Der kan ikke afhentes på denne adresse. Vælg en anden adresse.</translation>
@@ -1533,6 +1570,7 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="5869522115854928033">Gemte adgangskoder</translation>
<translation id="5873013647450402046">Din bank vil gerne bekræfte, at det er dig.</translation>
<translation id="5887400589839399685">Kortet er gemt</translation>
+<translation id="5887687176710214216">Senest besøgt i går</translation>
<translation id="5895138241574237353">Genstart</translation>
<translation id="5895187275912066135">Udstedt den</translation>
<translation id="5901630391730855834">Gul</translation>
@@ -1546,6 +1584,7 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="5921639886840618607">Vil du gemme kortet på din Google-konto?</translation>
<translation id="5922853866070715753">Næsten færdig</translation>
<translation id="5932224571077948991">Websitet viser påtrængende eller vildledende annoncer</translation>
+<translation id="5938153366081463283">Tilføj virtuelt kort</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347">Åbner <ph name="SITE_NAME" />…</translation>
<translation id="5951495562196540101">Det er ikke muligt at tilmelde sig med en forbrugerkonto (mulighed for tilknyttet licens ).</translation>
@@ -1610,6 +1649,7 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="6120179357481664955">Skal dit UPI-id huskes?</translation>
<translation id="6124432979022149706">Chrome Enterprise-connectorer</translation>
<translation id="6127379762771434464">Elementet blev fjernet</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />FÃ¥ flere oplysninger om inkognitotilstand i Chrome<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">Kontrollér eventuelle kabler, og genstart alle routere, modemmer eller andre
netværksenheder, du bruger.</translation>
<translation id="614940544461990577">Prøv at:</translation>
@@ -1622,7 +1662,6 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="6169916984152623906">Nu kan du gå på nettet privat, og andre brugere på denne enhed kan ikke se din aktivitet. Downloads og bogmærker gemmes dog stadig.</translation>
<translation id="6177128806592000436">Din forbindelse til dette website er ikke sikker.</translation>
<translation id="6180316780098470077">Interval for gentagelse af forsøg</translation>
-<translation id="619448280891863779">Websitet kan anmode om tilladelse til at åbne og placere vinduer på dine skærme</translation>
<translation id="6196640612572343990">Bloker cookies fra tredjeparter</translation>
<translation id="6203231073485539293">Kontrollér din internetforbindelse</translation>
<translation id="6218753634732582820">Vil du fjerne adressen fra Chromium?</translation>
@@ -1645,7 +1684,7 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="6272383483618007430">Google Update</translation>
<translation id="6276112860590028508">Sider fra din læseliste vises her</translation>
<translation id="627746635834430766">Gem dit kort og din faktureringsadresse på din Google-konto for at betale hurtigere næste gang.</translation>
-<translation id="6279098320682980337">Er det virtuelle kortnummer ikke udfyldt? Klik på kortoplysningerne for at kopiere</translation>
+<translation id="6279183038361895380">Tryk på |<ph name="ACCELERATOR" />| at se markøren</translation>
<translation id="6280223929691119688">Der kan ikke leveres til denne adresse. Vælg en anden adresse.</translation>
<translation id="6282194474023008486">Postnummer</translation>
<translation id="6285507000506177184">Knappen "Administrer downloads i Chrome" – tryk på Enter for at administrere de filer, du har downloadet i Chrome</translation>
@@ -1653,6 +1692,7 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="6290238015253830360">Forslag til artikler til dig vises her</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{Din enhed genstarter nu}=1{Din enhed genstarter om 1 sekund}one{Din enhed genstarter om # sekund}other{Din enhed genstarter om # sekunder}}</translation>
<translation id="6302269476990306341">Google Assistent i Chrome stopper</translation>
<translation id="6305205051461490394"><ph name="URL" /> kan ikke nås.</translation>
<translation id="6312113039770857350">Websiden er ikke tilgængelig</translation>
@@ -1726,6 +1766,7 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="6529602333819889595">&amp;Annuller fortryd slet</translation>
<translation id="6545864417968258051">Bluetooth-scanning</translation>
<translation id="6547208576736763147">To huller i venstre side</translation>
+<translation id="6554732001434021288">Senest besøgt for <ph name="NUM_DAYS" /> dage siden</translation>
<translation id="6556866813142980365">Gør det igen</translation>
<translation id="6569060085658103619">Du ser en udvidelsesside</translation>
<translation id="6573200754375280815">To huller i højre side</translation>
@@ -1786,7 +1827,6 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="6757797048963528358">Din enhed gik i dvale.</translation>
<translation id="6767985426384634228">Vil du opdatere adressen?</translation>
<translation id="6768213884286397650">Hagaki (Postcard)</translation>
-<translation id="6774185088257932239"><ph name="BEGIN_LINK" />FÃ¥ flere oplysninger<ph name="END_LINK" /> om inkognitotilstand</translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">Violet</translation>
<translation id="6786747875388722282">Udvidelser</translation>
@@ -1870,7 +1910,6 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="706295145388601875">Tilføj og administrer adresser i Chrome-indstillingerne</translation>
<translation id="7064851114919012435">Kontaktoplysninger</translation>
<translation id="7068733155164172741">Angiv <ph name="OTP_LENGTH" />-cifret kode</translation>
-<translation id="7070090581017165256">Om dette website</translation>
<translation id="70705239631109039">Din forbindelse er ikke 100 % sikker</translation>
<translation id="7075452647191940183">Anmodningen er for stor</translation>
<translation id="7079718277001814089">Dette website indeholder malware</translation>
@@ -1887,6 +1926,12 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="7111012039238467737">(gyldigt)</translation>
<translation id="7118618213916969306">Søg efter webadresse til udklipsholderen, <ph name="SHORT_URL" /></translation>
<translation id="7119414471315195487">Luk andre faner eller programmer</translation>
+<translation id="7129355289156517987">NÃ¥r du lukker alle inkognitofaner i Chromium, slettes din aktivitet i disse faner fra denne enhed:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Browseraktivitet<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Søgehistorik<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Oplysninger, der er angivet i formularer<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">Der kan ikke sendes til denne adresse. Vælg en anden adresse.</translation>
<translation id="7132939140423847331">Din administrator tillader ikke kopiering af disse data.</translation>
<translation id="7135130955892390533">Vis status</translation>
@@ -1909,6 +1954,7 @@ Ellers vil det blive blokeret af dine privatlivsindstillinger. Det giver det ind
<translation id="7192203810768312527">Frigør <ph name="SIZE" />. Nogle websites indlæses muligvis langsommere, næste gang du besøger websitet.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">Din administrator kan se:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" /> – tryk på Tab-tasten efterfulgt af Enter for at åbne en ny inkognitofane, så du kan browse privat</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> overholder ikke sikkerhedsstandarderne.</translation>
<translation id="7210993021468939304">Linux-aktivitet i containeren. Kan også installere og køre Linux-apps i containeren.</translation>
@@ -1940,6 +1986,7 @@ Yderligere oplysninger:
<translation id="7304562222803846232">Administrer privatlivsindstillingerne for din Google-konto</translation>
<translation id="7305756307268530424">Start langsommere</translation>
<translation id="7308436126008021607">synkronisering i baggrunden.</translation>
+<translation id="7310392214323165548">Enheden genstarter meget snart</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">Hjælp til at oprette forbindelse</translation>
<translation id="7323804146520582233">Skjul sektionen "<ph name="SECTION" />"</translation>
@@ -1947,6 +1994,7 @@ Yderligere oplysninger:
<translation id="7334320624316649418">&amp;Annuller fortryd omarrangering</translation>
<translation id="7335157162773372339">Websitet kan anmode om tilladelse til at bruge dit kamera</translation>
<translation id="7337248890521463931">Vis flere linjer</translation>
+<translation id="7337418456231055214">Er det virtuelle kortnummer ikke udfyldt? Klik på kortoplysningerne for at kopiere. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">Ikke tilgængelig på din platform.</translation>
<translation id="733923710415886693">Servercertifikatet blev ikke fremvist via Certifikatsgennemsigtighed.</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1969,6 +2017,7 @@ Yderligere oplysninger:
<translation id="7378627244592794276">Nej</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">Ikke relevant</translation>
+<translation id="7388594495505979117">{0,plural, =1{Din enhed genstarter om 1 minut}one{Din enhed genstarter om # minut}other{Din enhed genstarter om # minutter}}</translation>
<translation id="7390545607259442187">Bekræft kort</translation>
<translation id="7392089738299859607">Opdater adresse</translation>
<translation id="7399802613464275309">Sikkerhedstjek</translation>
@@ -2005,6 +2054,12 @@ Yderligere oplysninger:
<translation id="7485870689360869515">Der blev ikke fundet nogen data.</translation>
<translation id="7495528107193238112">Dette indhold er blokeret. Kontakt ejeren af websitet for at løse problemet.</translation>
<translation id="7497998058912824456">Knappen Opret et Google-dokument, tryk på Enter for hurtigt at oprette et nyt Google-dokument</translation>
+<translation id="7506488012654002225">Chromium <ph name="BEGIN_EMPHASIS" />gemmer ikke<ph name="END_EMPHASIS" /> følgende oplysninger:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Din browserhistorik
+ <ph name="LIST_ITEM" />Cookies og websitedata
+ <ph name="LIST_ITEM" />Oplysninger, der er angivet i formularer
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">Det returnerede enheds-id for politikken er tomt eller stemmer ikke overens med det nuværende enheds-id</translation>
<translation id="7508870219247277067">Avocadogrøn</translation>
<translation id="7511955381719512146">Det Wi-Fi-netværk, du bruger, kan kræve, at du går til <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
@@ -2118,7 +2173,6 @@ Yderligere oplysninger:
<translation id="7813600968533626083">Vil du fjerne formularforslaget fra Chrome?</translation>
<translation id="781440967107097262">Vil du dele din udklipsholder?</translation>
<translation id="7815407501681723534">Der blev fundet <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> for "<ph name="SEARCH_STRING" />"</translation>
-<translation id="782125616001965242">Se oplysninger om dette website</translation>
<translation id="782886543891417279">Det Wi-Fi-netværk, du bruger (<ph name="WIFI_NAME" />), kan kræve, at du går til netværkets loginside.</translation>
<translation id="7836231406687464395">Postfix (Envelope)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{Ingen}=1{1 app (<ph name="EXAMPLE_APP_1" />)}=2{2 apps (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}one{# app (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" /> <ph name="AND_MORE" />)}other{# apps (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" /> <ph name="AND_MORE" />)}}</translation>
@@ -2135,7 +2189,6 @@ Yderligere oplysninger:
<translation id="7888575728750733395">Formål for udskriftsgengivelse</translation>
<translation id="7894280532028510793">Hvis stavningen er korrekt, kan du <ph name="BEGIN_LINK" />prøve at køre Netværksdiagnosticering<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (Envelope)</translation>
-<translation id="7931318309563332511">ukendt</translation>
<translation id="793209273132572360">Vil du opdater adressen?</translation>
<translation id="7932579305932748336">Bestrygning</translation>
<translation id="79338296614623784">Angiv et gyldigt telefonnummer</translation>
@@ -2160,13 +2213,14 @@ Yderligere oplysninger:
<translation id="7976214039405368314">For mange anmodninger</translation>
<translation id="7977538094055660992">Outputenhed</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">Tilknyttet</translation>
<translation id="798134797138789862">Websitet kan anmode om tilladelse til at bruge virtual reality-enheder og -data</translation>
<translation id="7984945080620862648">Du kan ikke gå til <ph name="SITE" /> lige nu, da websitet sendte krypterede legitimationsoplysninger, som Chrome ikke kan håndtere. Netværksfejl og angreb er normalt midlertidige, så denne side vil sandsynligvis fungere senere.</translation>
-<translation id="79859296434321399">Installer ARCore for at se augmented reality-indhold</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">Bind</translation>
<translation id="7992044431894087211">Skærmdelingen med <ph name="APPLICATION_TITLE" /> blev genoptaget</translation>
<translation id="7995512525968007366">Ikke angivet</translation>
+<translation id="7998269595945679889">Knappen Åbn inkognitofane – tryk på Enter for at åbne en ny inkognitofane, så du kan browse privat</translation>
<translation id="800218591365569300">Prøv at lukke andre faner eller programmer for at frigøre hukommelse.</translation>
<translation id="8004582292198964060">Browser</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{Kortet og faktureringsadressen gemmes. Du kan bruge dem, når du er logget ind på <ph name="USER_EMAIL" />.}one{Kortet og faktureringsadressen gemmes. Du kan bruge dem, når du er logget ind på <ph name="USER_EMAIL" />.}other{Kortene og faktureringsadresserne gemmes. Du kan bruge dem, når du er logget ind på <ph name="USER_EMAIL" />.}}</translation>
@@ -2226,6 +2280,7 @@ Yderligere oplysninger:
<translation id="8202370299023114387">Konflikt</translation>
<translation id="8206978196348664717">Prc4 (Envelope)</translation>
<translation id="8211406090763984747">Forbindelsen er sikker</translation>
+<translation id="8217240300496046857">Websites kan ikke bruge cookies, der sporer din aktivitet på nettet. Funktioner på visse websites virker muligvis ikke.</translation>
<translation id="8218327578424803826">Tildelt placering:</translation>
<translation id="8220146938470311105">C7/C6 (Envelope)</translation>
<translation id="8225771182978767009">Den person, der har konfigureret denne computer, har valgt at blokere dette website.</translation>
@@ -2266,14 +2321,9 @@ Yderligere oplysninger:
<translation id="830498451218851433">Fals halvt</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">Installerede apps, og hvor ofte de bruges</translation>
+<translation id="8317207217658302555">Vil du opdatere ARCore?</translation>
<translation id="831997045666694187">Aften</translation>
<translation id="8321476692217554900">notifikationer</translation>
-<translation id="8328484624016508118">NÃ¥r du har lukket alle inkognitofaner, rydder Chrome:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Din browseraktivitet fra denne enhed<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Din søgehistorik fra denne enhed<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />De oplysninger, du har angivet i formularer<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489">Adgangen til <ph name="HOST_NAME" /> blev nægtet</translation>
<translation id="833262891116910667">Fremhæv</translation>
<translation id="8339163506404995330">Sider på <ph name="LANGUAGE" /> oversættes ikke</translation>
@@ -2325,6 +2375,7 @@ Yderligere oplysninger:
<translation id="8507227106804027148">Kommandolinje</translation>
<translation id="8508648098325802031">Søgeikon</translation>
<translation id="8511402995811232419">Administrer cookies</translation>
+<translation id="8519753333133776369">Din administrator har tilladt HID-enheden</translation>
<translation id="8522552481199248698">Chrome kan hjælpe dig med at beskytte din Google-konto og ændre din adgangskode.</translation>
<translation id="8530813470445476232">Ryd browserhistorik, cookies, cache m.m. i Chrome-indstillingerne</translation>
<translation id="8533619373899488139">Gå til &lt;strong&gt;chrome://policy&lt;/strong&gt; for at se listen over blokerede webadresser og andre politikker, der håndhæves af din systemadministrator.</translation>
@@ -2336,7 +2387,6 @@ Yderligere oplysninger:
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{Nulstil tilladelse}one{Nulstil tilladelse}other{Nulstil tilladelser}}</translation>
<translation id="8555010941760982128">Angiv denne kode ved betalingen</translation>
<translation id="8557066899867184262">Kontrolkoden findes på bagsiden af kortet.</translation>
-<translation id="8558485628462305855">Opdater ARCore for at se augmented reality-indhold</translation>
<translation id="8559762987265718583">Der kan ikke oprettes en privat forbindelse til <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />, da tid og dato (<ph name="DATE_AND_TIME" />) på din enhed er forkerte.</translation>
<translation id="8564182942834072828">Individuelle dokumenter/ikke-samlede kopier</translation>
<translation id="8564985650692024650">Chromium anbefaler, at du nulstiller din adgangskode til <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" />, hvis du har brugt den på andre websites.</translation>
@@ -2356,6 +2406,7 @@ Yderligere oplysninger:
<translation id="865032292777205197">bevægelsessensorer</translation>
<translation id="8663226718884576429">Ordreoversigt, <ph name="TOTAL_LABEL" />, flere oplysninger</translation>
<translation id="8666678546361132282">Engelsk</translation>
+<translation id="8669306706049782872">Bruge oplysninger om dine skærme til at åbne og placere vinduer</translation>
<translation id="867224526087042813">Underskrift</translation>
<translation id="8676424191133491403">Ingen forsinkelse</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, svar, <ph name="ANSWER" /></translation>
@@ -2382,6 +2433,7 @@ Yderligere oplysninger:
<translation id="8731544501227493793">Knappen Administrer adgangskoder – tryk på Enter for at se og administrere dine adgangskoder i Chrome-indstillingerne</translation>
<translation id="8734529307927223492">Din <ph name="DEVICE_TYPE" /> administreres af <ph name="MANAGER" /></translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" /> – tryk på Tab-tasten efterfulgt af Enter for at åbne et nyt inkognitovindue, så du kan browse privat</translation>
+<translation id="8737685506611670901">Ã…bne <ph name="PROTOCOL" />-links i stedet for <ph name="REPLACED_HANDLER_TITLE" /></translation>
<translation id="8738058698779197622">For at kunne oprette en sikker forbindelse skal dit ur være indstillet korrekt. Det er vigtigt, da de certifikater, som websites bruger til at identificere sig selv, kun er gyldige i bestemte tidsperioder. Da uret på din enhed går forkert, kan Chromium ikke bekræfte disse certifikater.</translation>
<translation id="8740359287975076522">&lt;abbr id="dnsDefinition"&gt;DNS-adressen&lt;/abbr&gt; for <ph name="HOST_NAME" /> blev ikke fundet. Diagnosticerer problemet.</translation>
<translation id="8742371904523228557"><ph name="ONE_TIME_CODE" /> er din kode til <ph name="ORIGIN" /></translation>
@@ -2409,6 +2461,7 @@ Yderligere oplysninger:
<translation id="883848425547221593">Andre bogmærker</translation>
<translation id="884264119367021077">Leveringsadresse</translation>
<translation id="884923133447025588">Der blev ikke fundet nogen funktion til tilbagekaldelse.</translation>
+<translation id="8849262850971482943">Brug dit virtuelle kort som ekstra beskyttelse</translation>
<translation id="885730110891505394">Deling med Google</translation>
<translation id="8858065207712248076">Chrome anbefaler, at du nulstiller din adgangskode til <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" />, hvis du har brugt den på andre websites.</translation>
<translation id="885906927438988819">Hvis stavningen er korrekt, kan du <ph name="BEGIN_LINK" />prøve at køre Windows Netværksdiagnosticering<ph name="END_LINK" />.</translation>
@@ -2458,6 +2511,7 @@ Yderligere oplysninger:
<translation id="9004367719664099443">VR-sessionen er i gang</translation>
<translation id="9005998258318286617">PDF-dokumentet kunne ikke indlæses.</translation>
<translation id="9008201768610948239">Ignorer</translation>
+<translation id="901834265349196618">mail</translation>
<translation id="9020200922353704812">Kortets faktureringsadresse er obligatorisk</translation>
<translation id="9020542370529661692">Denne side er oversat til <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9020742383383852663">A8</translation>
@@ -2506,6 +2560,7 @@ Yderligere oplysninger:
<translation id="9150045010208374699">Bruge dit kamera</translation>
<translation id="9150685862434908345">Din administrator kan ændre konfigurationen af din browser via fjernadgang. Aktivitet på denne enhed administreres muligvis også uden for Chrome. <ph name="BEGIN_LINK" />Få flere oplysninger<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">Opdateret</translation>
+<translation id="9155211586651734179">Forbundne eksterne lydenheder</translation>
<translation id="9157595877708044936">Konfigurerer...</translation>
<translation id="9158625974267017556">C6 (Envelope)</translation>
<translation id="9164029392738894042">Nøjagtighedstjek</translation>
diff --git a/chromium/components/strings/components_strings_de.xtb b/chromium/components/strings/components_strings_de.xtb
index 2c8e945d838..b6b3cf0a5e0 100644
--- a/chromium/components/strings/components_strings_de.xtb
+++ b/chromium/components/strings/components_strings_de.xtb
@@ -9,22 +9,27 @@
<translation id="1015730422737071372">Weitere Details angeben</translation>
<translation id="1019413721762100891">Aus</translation>
<translation id="1021110881106174305">Akzeptierte Karten</translation>
-<translation id="1021753677514347426">Sie sehen diesen Fehler aufgrund eines Zertifikats, das auf Ihrem Gerät installiert ist. Chromium vertraut dem Zertifikat nicht, weil es Netzwerke unterbrechen und überwachen kann. Natürlich gibt es berechtigte Gründe für eine Überwachung, z. B. im Netzwerk von Schulen oder Unternehmen. Trotzdem soll sichergestellt werden, dass Sie über die Überwachung informiert sind, selbst wenn Sie sie nicht unterbinden können. Die Überwachung ist in jedem Browser und jeder Anwendung mit Webzugriff möglich.</translation>
+<translation id="1021753677514347426">Du siehst diesen Fehler aufgrund eines Zertifikats, das auf deinem Gerät installiert ist. Chromium vertraut dem Zertifikat nicht, weil es Netzwerke unterbrechen und überwachen kann. Natürlich gibt es berechtigte Gründe für eine Überwachung, z. B. im Netzwerk von Schulen oder Unternehmen. Trotzdem soll sichergestellt werden, dass du über die Überwachung informiert bist, selbst wenn du sie nicht unterbinden kannst. Die Überwachung ist in jedem Browser und jeder Anwendung mit Webzugriff möglich.</translation>
<translation id="1024111578869940408">Angreifer kopieren manchmal Websites und nehmen unauffällige Änderungen an der Webadresse vor.</translation>
<translation id="1028781062521375153">Details anzeigen</translation>
-<translation id="1030706264415084469"><ph name="URL" /> möchte dauerhaft umfangreiche Daten auf Ihrem Gerät speichern</translation>
+<translation id="1030706264415084469"><ph name="URL" /> möchte dauerhaft umfangreiche Daten auf deinem Gerät speichern</translation>
<translation id="1032854598605920125">Im Uhrzeigersinn drehen</translation>
+<translation id="1033329911862281889">Der Inkognitomodus macht dich online nicht unsichtbar:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Websites und Dienste, die darauf verwendet werden, erkennen Besuche<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Arbeitgeber und Bildungseinrichtungen können Browseraktivitäten erfassen<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Internetanbieter behalten ggf. den Web-Traffic im Blick<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">Deaktivieren</translation>
<translation id="1036982837258183574">Zum Beenden des Vollbildmodus |<ph name="ACCELERATOR" />| drücken</translation>
<translation id="1038106730571050514">Vorschläge anzeigen</translation>
<translation id="1038842779957582377">Unbekannter Name</translation>
<translation id="1041998700806130099">Auftragsblattnachricht</translation>
-<translation id="1048785276086539861">Wenn Sie Anmerkungen bearbeiten, wechselt das Dokument zur Einzelseitenansicht zurück</translation>
-<translation id="1049743911850919806">Inkognito</translation>
+<translation id="1048785276086539861">Wenn du Anmerkungen bearbeitest, wechselt das Dokument zur Einzelseitenansicht zurück</translation>
<translation id="1050038467049342496">Andere Apps schließen</translation>
<translation id="1055184225775184556">&amp;Hinzufügen rückgängig machen</translation>
<translation id="1056898198331236512">Warnung</translation>
-<translation id="1058344460600311577"><ph name="PLAY_CHROME_DINO_GAME_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücken Sie die Tabulatortaste und dann die Eingabetaste, um Chrome Dino in Chrome zu spielen</translation>
+<translation id="1058344460600311577"><ph name="PLAY_CHROME_DINO_GAME_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücke die Tabulatortaste und dann die Eingabetaste, um Chrome Dino in Chrome zu spielen</translation>
<translation id="1058479211578257048">Karten werden gespeichert…</translation>
<translation id="10614374240317010">Nie speichern für…</translation>
<translation id="1062160989074299343">Prc10 (Umschlag)</translation>
@@ -38,7 +43,7 @@
<translation id="1088860948719068836">Angabe für "Name auf der Karte" hinzufügen</translation>
<translation id="1089439967362294234">Passwort ändern</translation>
<translation id="1096545575934602868">Dieses Feld sollte nicht mehr als <ph name="MAX_ITEMS_LIMIT" /> Einträge enthalten. Alle weiteren werden verworfen.</translation>
-<translation id="1100782917270858593">Schaltfläche „Weiter stöbern“ – drücken Sie die Eingabetaste, um weiter zu recherchieren und relevante Aktivitäten in Ihrem Chrome-Verlauf zu sehen</translation>
+<translation id="1100782917270858593">Schaltfläche „Weiter stöbern“ – drücke die Eingabetaste, um weiter zu recherchieren und relevante Aktivitäten in deinem Chrome-Verlauf zu sehen</translation>
<translation id="1101672080107056897">Fehleraktion</translation>
<translation id="1103523840287552314"><ph name="LANGUAGE" /> immer übersetzen</translation>
<translation id="1110994991967754504">Berechtigung für <ph name="PERMISSION_NAME" /> auswählen</translation>
@@ -46,33 +51,33 @@
<translation id="1123753900084781868">Die Funktion „Automatische Untertitel“ ist derzeit nicht verfügbar</translation>
<translation id="1125573121925420732">Wenn die Sicherheitsfunktionen von Websites aktualisiert werden, können Warnungen häufiger auftreten. Dies sollte sich bald verbessern.</translation>
<translation id="112840717907525620">Richtlinien-Cache einwandfrei</translation>
-<translation id="1130564665089811311">Schaltfläche "Seite übersetzen" – drücken Sie die Eingabetaste, um diese Seite mit Google Übersetzer übersetzen zu lassen</translation>
-<translation id="1131264053432022307">Von Ihnen kopiertes Bild</translation>
-<translation id="1150979032973867961">Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat wird vom Betriebssystem Ihres Computers als nicht vertrauenswürdig eingestuft. Mögliche Gründe sind eine fehlerhafte Konfiguration oder ein Angreifer, der Ihre Verbindung abfängt.</translation>
+<translation id="1130564665089811311">Schaltfläche „Seite übersetzen“ – drücke die Eingabetaste, um diese Seite mit Google Übersetzer übersetzen zu lassen</translation>
+<translation id="1131264053432022307">Von dir kopiertes Bild</translation>
+<translation id="1142846828089312304">Cookies von Drittanbietern im Inkognitomodus blockieren</translation>
+<translation id="1150979032973867961">Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat wird vom Betriebssystem deines Computers als nicht vertrauenswürdig eingestuft. Mögliche Gründe sind eine fehlerhafte Konfiguration oder ein Angreifer, der deine Verbindung abfängt.</translation>
<translation id="1151972924205500581">Passwort erforderlich</translation>
-<translation id="1156303062776767266">Sie sehen sich eine lokale oder freigegebene Datei an</translation>
+<translation id="1156303062776767266">Du siehst dir eine lokale oder freigegebene Datei an</translation>
<translation id="1158211211994409885"><ph name="HOST_NAME" /> hat die Verbindung unerwartet geschlossen.</translation>
-<translation id="115926840831309955">Prüfen Sie Ihren CVC und versuchen Sie es noch einmal oder ändern Sie das Ablaufdatum</translation>
+<translation id="115926840831309955">Prüfe deinen CVC und versuche es noch einmal oder ändere das Ablaufdatum</translation>
<translation id="1161325031994447685">WLAN-Verbindung erneut herstellen</translation>
<translation id="1165039591588034296">Fehler</translation>
<translation id="1165174597379888365">Seite aufgerufen</translation>
-<translation id="1174723505405632867">Möchten Sie <ph name="EMBEDDED_URL" /> erlauben, auf <ph name="TOP_LEVEL_URL" /> Cookies und Websitedaten zu verwenden?
+<translation id="1174723505405632867">Möchtest du <ph name="EMBEDDED_URL" /> erlauben, auf <ph name="TOP_LEVEL_URL" /> Cookies und Websitedaten zu verwenden?
-Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies und Websitedaten verwendet werden dürfen, funktionieren die gewünschten Inhalte erwartungsgemäß, <ph name="EMBEDDED_URL" /> kann dadurch aber möglicherweise Ihre Aktivitäten verfolgen.</translation>
+Du wirst sonst gemäß deinen Datenschutzeinstellungen blockiert. Wenn Cookies und Websitedaten verwendet werden dürfen, funktionieren die gewünschten Inhalte erwartungsgemäß, <ph name="EMBEDDED_URL" /> kann dadurch aber möglicherweise deine Aktivitäten verfolgen.</translation>
<translation id="1175364870820465910">&amp;Drucken...</translation>
<translation id="1175875016430184367">Drei Heftklammern rechts</translation>
<translation id="1178581264944972037">Pause</translation>
<translation id="1181037720776840403">Entfernen</translation>
<translation id="1186201132766001848">Passwörter prüfen</translation>
-<translation id="1195210374336998651">App-Einstellungen öffnen</translation>
-<translation id="1195558154361252544">Benachrichtigungen werden automatisch für alle Websites blockiert, außer für diejenigen, die Sie zulassen</translation>
+<translation id="1195558154361252544">Benachrichtigungen werden automatisch für alle Websites blockiert, außer für diejenigen, die du zulässt</translation>
<translation id="1197088940767939838">Orange</translation>
<translation id="1201402288615127009">Weiter</translation>
<translation id="1201895884277373915">Mehr von dieser Website</translation>
<translation id="1206967143813997005">Erste Signatur ungültig</translation>
<translation id="1209206284964581585">Vorerst ausblenden</translation>
-<translation id="1209221128712833642">Schaltfläche „Formular erstellen“ – drücken Sie die Eingabetaste, um schnell ein neues Formular in Google Formulare zu erstellen</translation>
-<translation id="121201262018556460">Sie haben versucht, auf <ph name="DOMAIN" /> zuzugreifen, der Server hat jedoch ein Zertifikat mit einem schwachen Schlüssel übermittelt. Ein Hacker könnte den privaten Schlüssel geknackt haben, sodass es sich möglicherweise nicht um den erwarteten Server handelt, sondern Sie stattdessen mit einem Hacker kommunizieren.</translation>
+<translation id="1209221128712833642">Schaltfläche „Formular erstellen“ – drücke die Eingabetaste, um schnell ein neues Formular in Google Formulare zu erstellen</translation>
+<translation id="121201262018556460">Du hast versucht, auf <ph name="DOMAIN" /> zuzugreifen, der Server hat jedoch ein Zertifikat mit einem schwachen Schlüssel übermittelt. Ein Hacker könnte den privaten Schlüssel geknackt haben, sodass es sich möglicherweise nicht um den erwarteten Server handelt, sondern du stattdessen mit einem Hacker kommunizierst.</translation>
<translation id="1219129156119358924">Systemsicherheit</translation>
<translation id="1222060260947439312">Rechtes Fach</translation>
<translation id="1227224963052638717">Unbekannte Richtlinie</translation>
@@ -83,19 +88,19 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="124116460088058876">Weitere Sprachen</translation>
<translation id="1243027604378859286">Autor:</translation>
<translation id="1246424317317450637">Fett</translation>
-<translation id="1248573052514400575"><ph name="MANAGE_CHROMEOS_ACCESSIBILITY_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücken Sie die Tabulatortaste und dann die Eingabetaste, um die Bedienungshilfen in den Chrome OS-Einstellungen zu personalisieren</translation>
-<translation id="1250759482327835220">Damit Zahlungen zukünftig schneller abgewickelt werden können, speichern Sie Ihre Kreditkartendaten, Ihren Namen und Ihre Rechnungsadresse in Ihrem Google-Konto.</translation>
-<translation id="1252799212227771492">Schaltfläche „Tabelle erstellen“ – drücken Sie die Eingabetaste, um schnell eine neue Google-Tabelle zu erstellen</translation>
+<translation id="1248573052514400575"><ph name="MANAGE_CHROMEOS_ACCESSIBILITY_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücke die Tabulatortaste und dann die Eingabetaste, um die Bedienungshilfen in den Chrome OS-Einstellungen zu personalisieren</translation>
+<translation id="1250759482327835220">Damit Zahlungen zukünftig schneller abgewickelt werden können, speichere deine Kreditkartendaten, deinen Namen und deine Rechnungsadresse in deinem Google-Konto.</translation>
+<translation id="1252799212227771492">Schaltfläche „Tabelle erstellen“ – drücke die Eingabetaste, um schnell eine neue Google-Tabelle zu erstellen</translation>
<translation id="1253921432148366685"><ph name="TYPE_1" />, <ph name="TYPE_2" /> (synchronisiert)</translation>
-<translation id="1256368399071562588">&lt;p&gt;Wenn Sie eine bestimmte Website nicht aufrufen können, versuchen Sie zuerst, das Problem folgendermaßen zu beheben:&lt;/p&gt;
+<translation id="1256368399071562588">&lt;p&gt;Wenn du eine bestimmte Website nicht aufrufen kannst, versuche zuerst, das Problem folgendermaßen zu beheben:&lt;/p&gt;
&lt;ol&gt;
- &lt;li&gt;Prüfen Sie die Webadresse auf Tippfehler.&lt;/li&gt;
- &lt;li&gt;Prüfen Sie, ob Ihre Internetverbindung richtig funktioniert.&lt;/li&gt;
- &lt;li&gt;Wenden Sie sich an den Websiteinhaber.&lt;/li&gt;
+ &lt;li&gt;Prüfe die Webadresse auf Tippfehler.&lt;/li&gt;
+ &lt;li&gt;Prüfe, ob deine Internetverbindung richtig funktioniert.&lt;/li&gt;
+ &lt;li&gt;Wende dich an den Websiteinhaber.&lt;/li&gt;
&lt;/ol&gt;</translation>
-<translation id="1257286744552378071">Sie haben Ihr Passwort auf einer Website eingegeben, die nicht von Ihrer Organisation verwaltet wird. Zum Schutz Ihres Kontos sollten Sie das Passwort nicht für andere Apps und Websites verwenden.</translation>
+<translation id="1257286744552378071">Du hast dein Passwort auf einer Website eingegeben, die nicht von deiner Organisation verwaltet wird. Zum Schutz deines Kontos solltest du das Passwort nicht für andere Apps und Websites verwenden.</translation>
<translation id="1257553931232494454">Zoomstufen</translation>
-<translation id="1262388120645841613"><ph name="MANAGE_CHROME_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücken Sie die Tabulatortaste und dann die Eingabetaste, um Ihre Chrome-Einstellungen zu verwalten</translation>
+<translation id="1262388120645841613"><ph name="MANAGE_CHROME_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücke die Tabulatortaste und dann die Eingabetaste, um deine Chrome-Einstellungen zu verwalten</translation>
<translation id="1263231323834454256">Leseliste</translation>
<translation id="1264309058268477500">Wechselnd</translation>
<translation id="1269516672602708785">Schnell eine neue Website in Google Sites erstellen</translation>
@@ -103,15 +108,15 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="1281476433249504884">Stapelfach 1</translation>
<translation id="1285320974508926690">Diese Website nie übersetzen</translation>
<translation id="1292571435393770077">Fach 16</translation>
-<translation id="1292701964462482250">"Software auf Ihrem Computer verhindert, dass Chrome eine sichere Internetverbindung herstellt" (nur Windows-Computer)</translation>
+<translation id="1292701964462482250">"Software auf deinem Computer verhindert, dass Chrome eine sichere Internetverbindung herstellt" (nur Windows-Computer)</translation>
<translation id="1294154142200295408">Befehlszeilen-Varianten</translation>
<translation id="129553762522093515">Kürzlich geschlossen</translation>
-<translation id="129863573139666797"><ph name="BEGIN_LINK" />Löschen Sie Ihre Cookies<ph name="END_LINK" /></translation>
-<translation id="1301324364792935241">Prüfen Sie die Einstellungen für sichere DNS-Abfragen</translation>
+<translation id="129863573139666797"><ph name="BEGIN_LINK" />Lösche deine Cookies<ph name="END_LINK" /></translation>
+<translation id="1301324364792935241">Prüfe die Einstellungen für sichere DNS-Abfragen</translation>
<translation id="1307966114820526988">Eingestellte Funktionen</translation>
<translation id="1308113895091915999">Angebot verfügbar</translation>
<translation id="1312803275555673949">Welche Hinweise unterstützen dies?</translation>
-<translation id="131405271941274527"><ph name="URL" /> möchte Informationen senden und empfangen, wenn Sie Ihr Smartphone an NFC-Geräte halten</translation>
+<translation id="1314311879718644478">Augmented-Reality-Inhalte anzeigen</translation>
<translation id="1314509827145471431">Bindung rechts</translation>
<translation id="1318023360584041678">In Tabgruppe gespeichert</translation>
<translation id="1319245136674974084">Für diese App nicht mehr nachfragen</translation>
@@ -120,24 +125,24 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="1323433172918577554">Mehr anzeigen</translation>
<translation id="132390688737681464">Adressen speichern und ausfüllen</translation>
<translation id="1330449323196174374">Linksseitige Fensterfaltung</translation>
-<translation id="1333989956347591814">Ihre Aktivität <ph name="BEGIN_EMPHASIS" />bleibt eventuell sichtbar<ph name="END_EMPHASIS" /> für:
+<translation id="1333989956347591814">Deine Aktivität <ph name="BEGIN_EMPHASIS" />bleibt eventuell sichtbar<ph name="END_EMPHASIS" /> für:
<ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Von Ihnen besuchte Websites
- <ph name="LIST_ITEM" />Ihren Arbeitgeber oder Ihre Bildungseinrichtung
- <ph name="LIST_ITEM" />Ihren Internetanbieter
+ <ph name="LIST_ITEM" />Von dir besuchte Websites
+ <ph name="LIST_ITEM" />Deinen Arbeitgeber oder deine Bildungseinrichtung
+ <ph name="LIST_ITEM" />Deinen Internetanbieter
<ph name="END_LIST" /></translation>
<translation id="1337692097987160377">Tab teilen</translation>
<translation id="1339601241726513588">Registrierungsdomain:</translation>
<translation id="1340482604681802745">Abholadresse</translation>
<translation id="1346748346194534595">Rechts</translation>
-<translation id="1348198688976932919">Die Website, die Sie aufrufen möchten, enthält gefährliche Apps</translation>
+<translation id="1348198688976932919">Die Website, die du aufrufen möchtest, enthält gefährliche Apps</translation>
<translation id="1348779747280417563">Namen bestätigen</translation>
<translation id="1357195169723583938">Letzte Nutzer dieses Geräts und Zeitpunkt der Verwendung</translation>
<translation id="1358187717814494928">Tabelle erstellen</translation>
<translation id="1360955481084547712">Ein neues Inkognitofenster öffnen, um privat zu surfen</translation>
<translation id="1363819917331173092">Ãœbersetzen von Seiten in <ph name="SOURCE_LANGUAGE" /> nicht anbieten</translation>
<translation id="1364822246244961190">Diese Richtlinie ist blockiert und ihr Wert wird deshalb ignoriert.</translation>
-<translation id="1368318639262510626">Dino-Spiel. Ein verpixelter Dinosaurier weicht Kakteen und kleinen Flugsauriern aus, während er durch eine karge Landschaft läuft. Sobald Sie einen Ton hören, drücken Sie die Leertaste, um über Hindernisse zu springen.</translation>
+<translation id="1368318639262510626">Dino-Spiel. Ein verpixelter Dinosaurier weicht Kakteen und kleinen Flugsauriern aus, während er durch eine karge Landschaft läuft. Sobald du einen Ton hörst, drücke die Leertaste, um über Hindernisse zu springen.</translation>
<translation id="1374468813861204354">Vorschläge</translation>
<translation id="1374692235857187091">Index-4x6 (Postkarte)</translation>
<translation id="1375198122581997741">Informationen zur Version</translation>
@@ -145,12 +150,12 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="1377321085342047638">Kartennummer</translation>
<translation id="1380591466760231819">Brieffaltung</translation>
<translation id="138218114945450791">Hellblau</translation>
-<translation id="1382194467192730611">USB-Gerät wurde von Ihrem Administrator zugelassen</translation>
-<translation id="1382912999714108023">Ihre aktuellen Daten werden nicht angezeigt? Kontaktieren Sie Ihre Bank, um die Daten zu aktualisieren.</translation>
+<translation id="1382194467192730611">USB-Gerät wurde von deinem Administrator zugelassen</translation>
+<translation id="1382912999714108023">Deine aktuellen Daten werden nicht angezeigt? Kontaktiere deine Bank, um die Daten zu aktualisieren.</translation>
<translation id="1384725838384960382">Ansicht zum Authentifizieren der sicheren Anmeldedaten für Zahlungen</translation>
<translation id="1386623374109090026">Anmerkungen</translation>
<translation id="139305205187523129"><ph name="HOST_NAME" /> hat keine Daten gesendet.</translation>
-<translation id="1403196654932095242"><ph name="HISTORY_CLUSTERS_SEARCH_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücken Sie die Tabulatortaste und dann die Eingabetaste, um weiter zu stöbern und relevante Aktivitäten in Ihrem Chrome-Verlauf zu sehen</translation>
+<translation id="1403196654932095242"><ph name="HISTORY_CLUSTERS_SEARCH_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücke die Tabulatortaste und dann die Eingabetaste, um weiter zu stöbern und relevante Aktivitäten in deinem Chrome-Verlauf zu sehen</translation>
<translation id="1405567553485452995">Hellgrün</translation>
<translation id="1407135791313364759">Alle öffnen</translation>
<translation id="1408787208417187241">Drei Heftklammern oben</translation>
@@ -159,8 +164,9 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="1426410128494586442">Ja</translation>
<translation id="1428146450423315676">Stapelfach 7</translation>
<translation id="142858679511221695">Cloud-Nutzer</translation>
-<translation id="1428729058023778569">Sie sehen diese Warnung, weil diese Website kein HTTPS unterstützt. <ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="1428729058023778569">Du siehst diese Warnung, weil diese Website kein HTTPS unterstützt. <ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">Drucken</translation>
+<translation id="1432187715652018471">Seite möchte einen Service-Handler installieren.</translation>
<translation id="1432581352905426595">Suchmaschinen verwalten</translation>
<translation id="1436185428532214179">Darf nachfragen, wenn sie Dateien oder Ordner auf meinem Gerät bearbeiten möchte</translation>
<translation id="1442386063175183758">Rechtsseitige Fensterfaltung</translation>
@@ -169,22 +175,28 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="1453974140256777690">Eingefügter oder angehängter Text wird zur Analyse an Google Cloud oder Dritte gesendet. Er wird beispielsweise auf sensible Daten geprüft.</translation>
<translation id="1455413310270022028">Radierer</translation>
<translation id="1462245070427461050">JIS B9</translation>
-<translation id="1462951478840426066">Die Schriftarten auf Ihrem Computer verwenden, damit Sie High Fidelity-Inhalte erstellen können</translation>
+<translation id="1462951478840426066">Die Schriftarten auf deinem Computer verwenden, damit du High Fidelity-Inhalte erstellen kannst</translation>
<translation id="1463543813647160932">5 x 7</translation>
<translation id="1467432559032391204">Links</translation>
-<translation id="1468653229182955856"><ph name="ONE_TIME_CODE" /> ist Ihr Code für <ph name="EMBEDDED_ORIGIN" />, damit Sie auf <ph name="TOP_ORIGIN" /> fortfahren können</translation>
+<translation id="1468653229182955856"><ph name="ONE_TIME_CODE" /> ist dein Code für <ph name="EMBEDDED_ORIGIN" />, damit du auf <ph name="TOP_ORIGIN" /> fortfahren kannst</translation>
<translation id="1472675084647422956">Mehr anzeigen</translation>
<translation id="1473183651233018052">JIS B10</translation>
<translation id="147358896496811705">2A0</translation>
-<translation id="1475299637784133125">Suchen Sie die Browser-Version? Gehen Sie zu</translation>
+<translation id="1475299637784133125">Suchst du die Browser-Version? Gehe zu</translation>
<translation id="1476595624592550506">Passwort ändern</translation>
<translation id="1483493594462132177">Senden</translation>
<translation id="1484290072879560759">Versandadresse auswählen</translation>
<translation id="1492194039220927094">Richtlinien per Push-Benachrichtigung:</translation>
+<translation id="149293076951187737">Wenn du alle Inkognitotabs in Chrome schließt, werden deine Aktivitäten auf diesen Tabs von diesem Gerät gelöscht:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Browseraktivitäten<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Suchverlauf<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />In Formulare eingegebene Informationen<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">Zurück zum Tab</translation>
-<translation id="1501859676467574491">Zeigen Sie Karten von Ihrem Google-Konto</translation>
-<translation id="1507202001669085618">&lt;p&gt;Diese Fehlermeldung wird angezeigt, wenn Sie ein WLAN-Portal verwenden, bei dem eine Anmeldung erforderlich ist, bevor Sie online gehen können.&lt;/p&gt;
- &lt;p&gt;Klicken Sie auf der Seite, die Sie öffnen möchten, auf &lt;strong&gt;Verbinden&lt;/strong&gt;, um den Fehler zu beheben.&lt;/p&gt;</translation>
+<translation id="1501859676467574491">Zeige Karten von deinem Google-Konto</translation>
+<translation id="1507202001669085618">&lt;p&gt;Diese Fehlermeldung wird angezeigt, wenn du ein WLAN-Portal verwendest, bei dem eine Anmeldung erforderlich ist, bevor du online gehen kannst.&lt;/p&gt;
+ &lt;p&gt;Klicke auf der Seite, die du öffnen möchtest, auf &lt;strong&gt;Verbinden&lt;/strong&gt;, um den Fehler zu beheben.&lt;/p&gt;</translation>
<translation id="1513706915089223971">Liste der Verlaufseinträge</translation>
<translation id="1517433312004943670">Telefonnummer erforderlich</translation>
<translation id="1519264250979466059">Build-Datum</translation>
@@ -192,7 +204,7 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="1527263332363067270">Warten auf Verbindung…</translation>
<translation id="1529521330346880926">10x15 (Umschlag)</translation>
<translation id="1529789484829130889">Fach 8</translation>
-<translation id="1530707389502320859">Die Website, die Sie besuchen möchten, ist möglicherweise eine Fälschung. Angreifer kopieren manchmal Websites und nehmen kleine, unauffällige Änderungen an der URL vor.</translation>
+<translation id="1530707389502320859">Die Website, die du besuchen möchtest, ist möglicherweise eine Fälschung. Angreifer kopieren manchmal Websites und nehmen kleine, unauffällige Änderungen an der URL vor.</translation>
<translation id="1531205177818805254">Exec</translation>
<translation id="1532118530259321453">Auf dieser Seite wird Folgendes angezeigt</translation>
<translation id="153384715582417236">Das ist im Moment alles</translation>
@@ -205,16 +217,19 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="1555130319947370107">Blau</translation>
<translation id="1559447966090556585">Benachrichtigungen erhalten?</translation>
<translation id="1559528461873125649">Datei oder Verzeichnis nicht vorhanden</translation>
-<translation id="1559572115229829303">&lt;p&gt;Es kann keine private Verbindung zu <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> hergestellt werden, weil Datum und Uhrzeit (<ph name="DATE_AND_TIME" />) Ihres Geräts falsch sind.&lt;/p&gt;
+<translation id="1559572115229829303">&lt;p&gt;Es kann keine private Verbindung zu <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> hergestellt werden, weil Datum und Uhrzeit (<ph name="DATE_AND_TIME" />) deines Geräts falsch sind.&lt;/p&gt;
- &lt;p&gt;Stellen Sie in der App &lt;strong&gt;Einstellungen&lt;/strong&gt; im Bereich &lt;strong&gt;Allgemein&lt;/strong&gt; Datum und Uhrzeit richtig ein.&lt;/p&gt;</translation>
+ &lt;p&gt;Stelle in der App &lt;strong&gt;Einstellungen&lt;/strong&gt; im Bereich &lt;strong&gt;Allgemein&lt;/strong&gt; Datum und Uhrzeit richtig ein.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">Dein Administrator startet das Gerät um <ph name="TIME" /> am <ph name="DATE" /> neu</translation>
+<translation id="156703335097561114">Netzwerkinformationen wie Adressen, Schnittstellenkonfigurationen und Verbindungsqualität</translation>
<translation id="1567040042588613346">Diese Richtlinie funktioniert wie beabsichtigt, an anderer Stelle ist jedoch der gleiche Wert festgelegt, der von dieser Richtlinie ersetzt wird.</translation>
<translation id="1569487616857761740">Ablaufdatum eingeben</translation>
<translation id="1581080074034554886">CVC</translation>
<translation id="1583294866416602487">Plex</translation>
<translation id="1583429793053364125">Fehler beim Anzeigen dieser Webseite.</translation>
-<translation id="1586541204584340881">Welche Erweiterungen Sie installiert haben</translation>
+<translation id="1586541204584340881">Welche Erweiterungen du installiert hast</translation>
<translation id="1588438908519853928">Normal</translation>
+<translation id="1589050138437146318">ARCore installieren?</translation>
<translation id="1592005682883173041">Zugriff auf lokale Daten</translation>
<translation id="1594030484168838125">Auswählen</translation>
<translation id="160851722280695521">Chrome Dino in Chrome spielen</translation>
@@ -228,10 +243,10 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="1638780421120290329">Karte kann nicht gespeichert werden</translation>
<translation id="1639239467298939599">Wird geladen...</translation>
<translation id="1640180200866533862">Nutzerrichtlinien</translation>
-<translation id="1640244768702815859">Versuchen Sie, <ph name="BEGIN_LINK" />die Startseite aufzurufen<ph name="END_LINK" />.</translation>
+<translation id="1640244768702815859">Versuche, <ph name="BEGIN_LINK" />die Startseite aufzurufen<ph name="END_LINK" />.</translation>
<translation id="1641976391427233992">Ausgabe verzögern bis</translation>
<translation id="164212631332220697">An der Kasse mit <ph name="CARD_DETAIL" /> zahlen.</translation>
-<translation id="1642410292376109062">Schaltfläche „Google-Passwort ändern“ – drücken Sie die Eingabetaste, um das Passwort für Ihr Google-Konto zu ändern</translation>
+<translation id="1642410292376109062">Schaltfläche „Google-Passwort ändern“ – drücke die Eingabetaste, um das Passwort für dein Google-Konto zu ändern</translation>
<translation id="1644574205037202324">Verlauf</translation>
<translation id="1645368109819982629">Nicht unterstütztes Protokoll</translation>
<translation id="1650602712345345441">Chrome-Einstellungen verwalten</translation>
@@ -249,10 +264,10 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="1699570257714336246">Fehlende Informationen</translation>
<translation id="1703835215927279855">Letter</translation>
<translation id="1706625117072057435">Zoomstufen</translation>
-<translation id="1706954506755087368">{1,plural, =1{Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat gilt vermutlich erst ab morgen. Mögliche Gründe sind eine fehlerhafte Konfiguration oder ein Angreifer, der Ihre Verbindung abfängt.}other{Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat gilt vermutlich erst in # Tagen. Mögliche Gründe sind eine fehlerhafte Konfiguration oder ein Angreifer, der Ihre Verbindung abfängt.}}</translation>
+<translation id="1706954506755087368">{1,plural, =1{Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat gilt vermutlich erst ab morgen. Mögliche Gründe sind eine fehlerhafte Konfiguration oder ein Angreifer, der deine Verbindung abfängt.}other{Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat gilt vermutlich erst in # Tagen. Mögliche Gründe sind eine fehlerhafte Konfiguration oder ein Angreifer, der deine Verbindung abfängt.}}</translation>
<translation id="1710259589646384581">Betriebssystem</translation>
<translation id="1711234383449478798">Ignoriert, weil <ph name="POLICY_NAME" /> nicht auf <ph name="VALUE" /> festgelegt ist.</translation>
-<translation id="1712552549805331520"><ph name="URL" /> möchte Daten dauerhaft auf Ihrem lokalen Computer speichern</translation>
+<translation id="1712552549805331520"><ph name="URL" /> möchte Daten dauerhaft auf deinem lokalen Computer speichern</translation>
<translation id="1713628304598226412">Fach 2</translation>
<translation id="1715874602234207">F</translation>
<translation id="1717218214683051432">Bewegungssensoren</translation>
@@ -265,25 +280,26 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="173080396488393970">Dieser Kartentyp wird nicht unterstützt</translation>
<translation id="1733064249834771892">Schriftarten</translation>
<translation id="1734864079702812349">American Express</translation>
-<translation id="1734878702283171397">Setzen Sie sich mit dem Systemadministrator in Verbindung.</translation>
+<translation id="1734878702283171397">Setze dich mit dem Systemadministrator in Verbindung.</translation>
<translation id="1736420071277903564">Computer</translation>
-<translation id="1740951997222943430">Geben Sie einen gültigen Ablaufmonat ein</translation>
+<translation id="1740951997222943430">Gib einen gültigen Ablaufmonat ein</translation>
<translation id="1741613555002899862">Muss angegeben werden und ein gültiger String sein, wenn "DnsOverHttpsMode" auf <ph name="SECURE_DNS_MODE_SECURE" /> gesetzt ist.</translation>
-<translation id="1745880797583122200">Ihr Browser wird verwaltet</translation>
+<translation id="1745880797583122200">Dein Browser wird verwaltet</translation>
<translation id="1746113442205726301">Y-Verschiebung des Bilds</translation>
<translation id="1747819498338037826">Automatisch ändern</translation>
<translation id="17513872634828108">Geöffnete Tabs</translation>
<translation id="1752021286346845558">Ablage 8</translation>
<translation id="1753706481035618306">Seitennummer</translation>
<translation id="1757773103848038814">Dicktengleiche Schrift</translation>
-<translation id="1763864636252898013">Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat wird vom Betriebssystem Ihres Geräts als nicht vertrauenswürdig eingestuft. Mögliche Gründe sind eine fehlerhafte Konfiguration oder ein Angreifer, der Ihre Verbindung abfängt.</translation>
-<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Versuchen Sie, die Windows-Netzwerkdiagnose auszuführen.<ph name="END_LINK" /></translation>
-<translation id="1772163372082567643">Der Server <ph name="ORIGIN" />, zu dem Sie gehen, verlangt in einer Header-Datei, dass auf alle an ihn gerichteten Anfragen eine Ursprungsrichtlinie angewendet wird. Die Header-Datei ist allerdings fehlerhaft. Daher kann der Browser Ihre Anforderung für <ph name="SITE" /> nicht ausführen. Ursprungsrichtlinien können von Websitebetreibern verwendet werden, um die Sicherheit und andere Eigenschaften einer Website zu konfigurieren.</translation>
+<translation id="1763864636252898013">Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat wird vom Betriebssystem deines Geräts als nicht vertrauenswürdig eingestuft. Mögliche Gründe sind eine fehlerhafte Konfiguration oder ein Angreifer, der deine Verbindung abfängt.</translation>
+<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Versuche, die Windows-Netzwerkdiagnose auszuführen.<ph name="END_LINK" /></translation>
+<translation id="1772163372082567643">Der Server <ph name="ORIGIN" />, zu dem du gehst, verlangt in einer Header-Datei, dass auf alle an ihn gerichteten Anfragen eine Ursprungsrichtlinie angewendet wird. Die Header-Datei ist allerdings fehlerhaft. Daher kann der Browser deine Anforderung für <ph name="SITE" /> nicht ausführen. Ursprungsrichtlinien können von Websitebetreibern verwendet werden, um die Sicherheit und andere Eigenschaften einer Website zu konfigurieren.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Weitere Informationen zum Inkognitomodus in Chromium<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
-<translation id="1787142507584202372">Hier werden Ihre offenen Tabs angezeigt</translation>
+<translation id="1787142507584202372">Hier werden deine offenen Tabs angezeigt</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
-<translation id="1791820510173628507"><ph name="MANAGE_GOOGLE_ACCOUNT_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücken Sie die Tabulatortaste und dann die Eingabetaste, um Daten sowie Datenschutz- und Sicherheitseinstellungen in Ihrem Google-Konto zu verwalten</translation>
-<translation id="1798447301915465742"><ph name="MULTIPLE_ACTIONS_FOCUSED_FRIENDLY_MATCH_TEXT" />, es sind mehrere Aktionen verfügbar, drücken Sie die Tabulatortaste, um sie durchzugehen</translation>
+<translation id="1791820510173628507"><ph name="MANAGE_GOOGLE_ACCOUNT_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücke die Tabulatortaste und dann die Eingabetaste, um Daten sowie Datenschutz- und Sicherheitseinstellungen in deinem Google-Konto zu verwalten</translation>
+<translation id="1798447301915465742"><ph name="MULTIPLE_ACTIONS_FOCUSED_FRIENDLY_MATCH_TEXT" />, es sind mehrere Aktionen verfügbar, drücke die Tabulatortaste, um sie durchzugehen</translation>
<translation id="1800473098294731951">B9</translation>
<translation id="1803264062614276815">Name des Karteninhabers</translation>
<translation id="1803351196216024260">Darf nachfragen, wenn sie mein Mikrofon verwenden möchte</translation>
@@ -292,7 +308,7 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="1812527064848182527">Querformat</translation>
<translation id="182139138257690338">Auto-Downloads</translation>
<translation id="1821930232296380041">Anfrage oder Anfrageparameter ungültig</translation>
-<translation id="1822540298136254167">Von Ihnen besuchte Websites und Dauer des Besuchs</translation>
+<translation id="1822540298136254167">Von dir besuchte Websites und Dauer des Besuchs</translation>
<translation id="1824402189105105503">Achte Rolle</translation>
<translation id="1826516787628120939">Überprüfung läuft</translation>
<translation id="1834321415901700177">Diese Website enthält schädliche Programme</translation>
@@ -308,42 +324,42 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="1875512691959384712">Google Formulare</translation>
<translation id="187918866476621466">"Beim Start"-Seiten öffnen</translation>
<translation id="1883255238294161206">Liste ausblenden</translation>
-<translation id="1890171020361705182">Dino-Spiel. Ein verpixelter Dinosaurier weicht Kakteen und kleinen Flugsauriern aus, während er durch eine karge Landschaft läuft. Sobald Sie einen Ton hören, tippen Sie, um über Hindernisse zu springen.</translation>
+<translation id="1890171020361705182">Dino-Spiel. Ein verpixelter Dinosaurier weicht Kakteen und kleinen Flugsauriern aus, während er durch eine karge Landschaft läuft. Sobald du einen Ton hörst, tippe, um über Hindernisse zu springen.</translation>
<translation id="1898423065542865115">Filtern</translation>
-<translation id="1901443836186977402">{1,plural, =1{Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat ist in den letzten 24 Stunden abgelaufen. Mögliche Gründe sind eine fehlerhafte Konfiguration oder ein Angreifer, der Ihre Verbindung abfängt. Die Uhr Ihres Computers ist derzeit auf <ph name="CURRENT_DATE" /> eingestellt. Ist das korrekt? Falls nicht, stellen Sie die Uhr Ihres Systems richtig ein und aktualisieren Sie anschließend diese Seite.}other{Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat ist vor # Tagen abgelaufen. Mögliche Gründe sind eine fehlerhafte Konfiguration oder ein Angreifer, der Ihre Verbindung abfängt. Die Uhr Ihres Computers ist momentan auf <ph name="CURRENT_DATE" /> eingestellt. Ist das richtig? Wenn nicht, korrigieren Sie die Uhrzeit Ihres Systems und aktualisieren Sie dann diese Seite.}}</translation>
+<translation id="1901443836186977402">{1,plural, =1{Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat ist in den letzten 24 Stunden abgelaufen. Mögliche Gründe sind eine fehlerhafte Konfiguration oder ein Angreifer, der deine Verbindung abfängt. Die Uhr deines Computers ist derzeit auf <ph name="CURRENT_DATE" /> eingestellt. Ist das korrekt? Falls nicht, stelle die Uhr deines Systems richtig ein und aktualisiere anschließend diese Seite.}other{Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat ist vor # Tagen abgelaufen. Mögliche Gründe sind eine fehlerhafte Konfiguration oder ein Angreifer, der deine Verbindung abfängt. Die Uhr deines Computers ist momentan auf <ph name="CURRENT_DATE" /> eingestellt. Ist das richtig? Wenn nicht, korrigiere die Uhrzeit deines Systems und aktualisiere dann diese Seite.}}</translation>
<translation id="1902576642799138955">Gültigkeitsdauer</translation>
-<translation id="1906155288650175567">Schaltfläche „Notiz erstellen“ – drücken Sie die Eingabetaste, um schnell eine neue Notiz in Google Notizen zu erstellen</translation>
+<translation id="1906155288650175567">Schaltfläche „Notiz erstellen“ – drücke die Eingabetaste, um schnell eine neue Notiz in Google Notizen zu erstellen</translation>
<translation id="1908217026282415406">Kamera verwenden und bewegen</translation>
<translation id="191374271204266022">Als JSON kopieren</translation>
<translation id="1914326953223720820">Dienst entpacken</translation>
<translation id="1915697529809968049">Touch ID anstelle des CVCs verwenden?</translation>
-<translation id="1916770123977586577">Laden Sie diese Seite neu, um die aktualisierten Einstellungen für diese Website zu übernehmen</translation>
+<translation id="1916770123977586577">Lade diese Seite neu, um die aktualisierten Einstellungen für diese Website zu übernehmen</translation>
<translation id="1919345977826869612">Werbung</translation>
<translation id="1919367280705858090">Hilfe bei bestimmten Fehlermeldungen</translation>
<translation id="192020519938775529">{COUNT,plural, =0{Keine}=1{1 Website}other{# Websites}}</translation>
-<translation id="1923390796829649802">Schaltfläche „Einstellungen für Bedienungshilfen verwalten“ – drücken Sie die Eingabetaste, um die Bedienungshilfen in den Chrome OS-Einstellungen zu personalisieren</translation>
+<translation id="1923390796829649802">Schaltfläche „Einstellungen für Bedienungshilfen verwalten“ – drücke die Eingabetaste, um die Bedienungshilfen in den Chrome OS-Einstellungen zu personalisieren</translation>
<translation id="1924727005275031552">Neu</translation>
-<translation id="1927439593081478069">Schaltfläche zum Ausführen des Chrome-Sicherheitschecks – drücken Sie die Eingabetaste, um den Sicherheitscheck in den Chrome-Einstellungen auszuführen</translation>
+<translation id="1927439593081478069">Schaltfläche zum Ausführen des Chrome-Sicherheitschecks – drücke die Eingabetaste, um den Sicherheitscheck in den Chrome-Einstellungen auszuführen</translation>
<translation id="1939175642807587452">Darf nachfragen, wenn sie Benachrichtigungen senden möchte</translation>
-<translation id="1945968466830820669">Sie könnten den Zugriff auf das Konto Ihres Unternehmens verlieren oder zum Opfer von Identitätsdiebstahl werden. Chromium empfiehlt Ihnen, Ihr Passwort jetzt zu ändern.</translation>
+<translation id="1945968466830820669">Du könntest den Zugriff auf das Konto deines Unternehmens verlieren oder zum Opfer von Identitätsdiebstahl werden. Chromium empfiehlt dir, dein Passwort jetzt zu ändern.</translation>
<translation id="1947454675006758438">Heftklammer oben rechts</translation>
-<translation id="1956486093533522234">Ihr Gerät finden, sichern oder löschen</translation>
-<translation id="1958218078413065209">Ihr Highscore ist <ph name="SCORE" />.</translation>
-<translation id="1959001866257244765">Helfen Sie mit, die Sicherheit im Web für alle zu verbessern, und senden Sie die <ph name="BEGIN_WHITEPAPER_LINK" />URLs einiger von Ihnen besuchter Seiten, eingeschränkte Systemdaten und manche Seiteninhalte<ph name="END_WHITEPAPER_LINK" /> an Google. <ph name="BEGIN_PRIVACY_PAGE_LINK" />Datenschutzerklärung<ph name="END_PRIVACY_PAGE_LINK" /></translation>
+<translation id="1956486093533522234">Dein Gerät finden, sichern oder löschen</translation>
+<translation id="1958218078413065209">Dein Highscore ist <ph name="SCORE" />.</translation>
+<translation id="1959001866257244765">Hilf mit, die Sicherheit im Web für alle zu verbessern, und sende die <ph name="BEGIN_WHITEPAPER_LINK" />URLs einiger von dir besuchter Seiten, eingeschränkte Systemdaten und manche Seiteninhalte<ph name="END_WHITEPAPER_LINK" /> an Google. <ph name="BEGIN_PRIVACY_PAGE_LINK" />Datenschutzerklärung<ph name="END_PRIVACY_PAGE_LINK" /></translation>
<translation id="1962204205936693436"><ph name="DOMAIN" />-Lesezeichen</translation>
<translation id="1973335181906896915">Fehler bei der Serialisierung</translation>
<translation id="1974060860693918893">Erweitert</translation>
<translation id="1975457531113383421">Papierfach</translation>
<translation id="1975584088563498795">Ablage 10</translation>
<translation id="1978555033938440688">Firmwareversion</translation>
-<translation id="1988881251331415125">Wenn die URL keinen Tippfehler enthält, <ph name="BEGIN_LINK" />können Sie die Verbindungsdiagnose durchführen<ph name="END_LINK" />.</translation>
+<translation id="1988881251331415125">Wenn die URL keinen Tippfehler enthält, <ph name="BEGIN_LINK" />kannst du die Verbindungsdiagnose durchführen<ph name="END_LINK" />.</translation>
<translation id="1992331125980284532">JIS B3</translation>
-<translation id="1997484222658892567"><ph name="URL" /> möchte umfangreiche Daten dauerhaft auf Ihrem lokalen Computer speichern</translation>
+<translation id="1997484222658892567"><ph name="URL" /> möchte umfangreiche Daten dauerhaft auf deinem lokalen Computer speichern</translation>
<translation id="2001146170449793414">{COUNT,plural, =1{und 1 weitere}other{und # weitere}}</translation>
<translation id="2003709556000175978">Jetzt Passwort zurücksetzen</translation>
<translation id="2003775180883135320">Vierfache Lochung oben</translation>
<translation id="201174227998721785">Berechtigungen und gespeicherte Daten von Websites in den Chrome-Einstellungen verwalten</translation>
-<translation id="2019607688127825327">Schaltfläche „Einstellungen für Bedienungshilfen verwalten“ – drücken Sie die Eingabetaste, um die Bedienungshilfen in den Chrome-Einstellungen zu personalisieren</translation>
+<translation id="2019607688127825327">Schaltfläche „Einstellungen für Bedienungshilfen verwalten“ – drücke die Eingabetaste, um die Bedienungshilfen in den Chrome-Einstellungen zu personalisieren</translation>
<translation id="2025115093177348061">Augmented Reality</translation>
<translation id="2025186561304664664">Proxy ist auf automatische Konfiguration eingestellt.</translation>
<translation id="2025891858974379949">Unsichere Inhalte</translation>
@@ -352,18 +368,18 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="2036983605131262583">Wechselnde Rolle</translation>
<translation id="2040894699575719559">Standort blockiert</translation>
<translation id="2042213636306070719">Fach 7</translation>
-<translation id="204357726431741734">Anmelden, um die in Ihrem Google-Konto gespeicherten Passwörter zu verwenden</translation>
+<translation id="204357726431741734">Anmelden, um die in deinem Google-Konto gespeicherten Passwörter zu verwenden</translation>
<translation id="2053111141626950936">Seiten auf <ph name="LANGUAGE" /> werden nicht übersetzt.</translation>
-<translation id="2053373601901562871">{NUM_DAYS,plural, =0{Wenn dieses Steuerelement aktiviert und aktiv ist, bestimmt Chrome, welcher großen Personengruppe oder „Kohorte“ Ihre aktuellen Browseraktivitäten am ähnlichsten sind. Werbetreibende können Werbung für die einzelnen Gruppen auswählen und Ihre Browseraktivitäten werden sicher auf Ihrem Gerät gespeichert. Ihre Gruppe wird täglich aktualisiert.}=1{Wenn dieses Steuerelement aktiviert und aktiv ist, bestimmt Chrome, welcher großen Personengruppe oder „Kohorte“ Ihre aktuellen Browseraktivitäten am ähnlichsten sind. Werbetreibende können Werbung für die einzelnen Gruppen auswählen und Ihre Browseraktivitäten werden sicher auf Ihrem Gerät gespeichert. Ihre Gruppe wird täglich aktualisiert.}other{Wenn dieses Steuerelement aktiviert und aktiv ist, bestimmt Chrome, welcher großen Personengruppe oder „Kohorte“ Ihre aktuellen Browseraktivitäten am ähnlichsten sind. Werbetreibende können Werbung für die einzelnen Gruppen auswählen und Ihre Browseraktivitäten werden sicher auf Ihrem Gerät gespeichert. Ihre Gruppe wird alle {NUM_DAYS} Tage aktualisiert.}}</translation>
+<translation id="2053373601901562871">{NUM_DAYS,plural, =0{Wenn dieses Steuerelement aktiviert und aktiv ist, bestimmt Chrome, welcher großen Personengruppe oder „Kohorte“ deine aktuellen Browseraktivitäten am ähnlichsten sind. Werbetreibende können Werbung für die einzelnen Gruppen auswählen und deine Browseraktivitäten werden sicher auf deinem Gerät gespeichert. Deine Gruppe wird täglich aktualisiert.}=1{Wenn dieses Steuerelement aktiviert und aktiv ist, bestimmt Chrome, welcher großen Personengruppe oder „Kohorte“ deine aktuellen Browseraktivitäten am ähnlichsten sind. Werbetreibende können Werbung für die einzelnen Gruppen auswählen und deine Browseraktivitäten werden sicher auf deinem Gerät gespeichert. Deine Gruppe wird täglich aktualisiert.}other{Wenn dieses Steuerelement aktiviert und aktiv ist, bestimmt Chrome, welcher großen Personengruppe oder „Kohorte“ deine aktuellen Browseraktivitäten am ähnlichsten sind. Werbetreibende können Werbung für die einzelnen Gruppen auswählen und deine Browseraktivitäten werden sicher auf deinem Gerät gespeichert. Deine Gruppe wird alle {NUM_DAYS} Tage aktualisiert.}}</translation>
<translation id="2053553514270667976">Postleitzahl</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 Vorschlag}other{# Vorschläge}}</translation>
<translation id="2071156619270205202">Für diese Karte ist keine virtuelle Kartennummer verfügbar.</translation>
-<translation id="2071692954027939183">Benachrichtigungen wurden automatisch blockiert, da Sie sie normalerweise nicht zulassen</translation>
+<translation id="2071692954027939183">Benachrichtigungen wurden automatisch blockiert, da du sie normalerweise nicht zulässt</translation>
<translation id="2079545284768500474">Rückgängig machen</translation>
<translation id="20817612488360358">Die System-Proxy-Einstellungen sind zur Verwendung angegeben, gleichzeitig wurde aber auch eine explizite Proxy-Konfiguration festgelegt.</translation>
<translation id="2082238445998314030">Ergebnis <ph name="RESULT_NUMBER" /> von <ph name="TOTAL_RESULTS" /></translation>
<translation id="2085876078937250610">Speichern…</translation>
-<translation id="2088086323192747268">Schaltfläche zum Verwalten der Synchronisierung – drücken Sie die Eingabetaste, um in den Chrome-Einstellungen zu verwalten, welche Informationen synchronisiert werden</translation>
+<translation id="2088086323192747268">Schaltfläche zum Verwalten der Synchronisierung – drücke die Eingabetaste, um in den Chrome-Einstellungen zu verwalten, welche Informationen synchronisiert werden</translation>
<translation id="2091887806945687916">Ton</translation>
<translation id="2094505752054353250">Domains stimmen nicht überein.</translation>
<translation id="2096368010154057602">Abteilung</translation>
@@ -373,7 +389,7 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="2102495993840063010">Android-Apps</translation>
<translation id="2107021941795971877">Stützstrukturen für Druck</translation>
<translation id="2108755909498034140">Computer neu starten</translation>
-<translation id="2111166930115883695">Drücken Sie die Leertaste, um das Spiel zu starten</translation>
+<translation id="2111166930115883695">Drücke die Leertaste, um das Spiel zu starten</translation>
<translation id="2111256659903765347">Super-A</translation>
<translation id="2112529237938317174">Berechtigungsdetails anzeigen</translation>
<translation id="2113977810652731515">Karte</translation>
@@ -382,16 +398,16 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="2119867082804433120">Lochung unten rechts</translation>
<translation id="2122719317867821810">Diese Richtlinie funktioniert wie beabsichtigt, an anderer Stelle ist jedoch ein widersprüchlicher Wert festgelegt, der von dieser Richtlinie überschrieben wird.</translation>
<translation id="2126374524350484896">PDF-Erstellungsprogramm:</translation>
-<translation id="2130448033692577677">Die von Ihnen angegebenen Vorlagen können nicht angewendet werden, weil die Richtlinie "DnsOverHttpsMode" nicht konfiguriert ist.</translation>
+<translation id="2130448033692577677">Die von dir angegebenen Vorlagen können nicht angewendet werden, weil die Richtlinie "DnsOverHttpsMode" nicht konfiguriert ist.</translation>
<translation id="213826338245044447">Mobile Lesezeichen</translation>
<translation id="214556005048008348">Zahlung abbrechen</translation>
<translation id="2148613324460538318">Karte hinzufügen</translation>
<translation id="2149968176347646218">Verbindung ist nicht sicher</translation>
-<translation id="2154054054215849342">Die Synchronisierung ist für Ihre Domain nicht verfügbar</translation>
+<translation id="2154054054215849342">Die Synchronisierung ist für deine Domain nicht verfügbar</translation>
<translation id="2154484045852737596">Karte bearbeiten</translation>
<translation id="2161656808144014275">Text</translation>
<translation id="2162510787844374618">Bank wird kontaktiert…</translation>
-<translation id="2164510882479075877">Prüfen Sie, ob "<ph name="HOST_NAME" />" einen Tippfehler enthält.</translation>
+<translation id="2164510882479075877">Prüfe, ob „<ph name="HOST_NAME" />“ einen Tippfehler enthält.</translation>
<translation id="2166049586286450108">Vollständiger Administratorzugriff</translation>
<translation id="2166378884831602661">Diese Website kann keine sichere Verbindung bereitstellen</translation>
<translation id="2168151236314517198">Die Administratorrichtlinie blockiert das Drucken dieses Inhalts</translation>
@@ -401,21 +417,23 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="2184405333245229118">{COUNT,plural, =1{1 Adresse}other{# Adressen}}</translation>
<translation id="2187317261103489799">Erkennen (Standardeinstellung)</translation>
<translation id="2188375229972301266">Mehrfache Lochung unten</translation>
-<translation id="2188852899391513400">Das Passwort, das Sie gerade verwendet haben, wurde in einer Datenpanne gefunden. Zum besseren Schutz Ihrer Konten empfiehlt der Passwortmanager von Google, das Passwort jetzt zu ändern und Ihre gespeicherten Passwörter zu prüfen.</translation>
-<translation id="2202020181578195191">Geben Sie ein gültiges Ablaufjahr ein</translation>
+<translation id="2188852899391513400">Das Passwort, das du gerade verwendet hast, wurde in einer Datenpanne gefunden. Zum besseren Schutz deiner Konten empfiehlt der Passwortmanager von Google, das Passwort jetzt zu ändern und deine gespeicherten Passwörter zu prüfen.</translation>
+<translation id="2202020181578195191">Gib ein gültiges Ablaufjahr ein</translation>
<translation id="22081806969704220">Fach 3</translation>
<translation id="2212735316055980242">Richtlinie nicht gefunden</translation>
<translation id="2213606439339815911">Einträge werden abgerufen...</translation>
+<translation id="2213612003795704869">Seite wird gedruckt</translation>
<translation id="2215727959747642672">Dateien bearbeiten</translation>
-<translation id="2218879909401188352">Angreifer auf der Website <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> könnten gefährliche Apps installieren, die Ihr Gerät beschädigen, Ihrer Mobilfunkrechnung versteckte Kosten hinzufügen oder Ihre personenbezogenen Daten stehlen könnten. <ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2218879909401188352">Angreifer auf der Website <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> könnten gefährliche Apps installieren, die dein Gerät beschädigen, deiner Mobilfunkrechnung versteckte Kosten hinzufügen oder deine personenbezogenen Daten stehlen könnten. <ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">Kein Internet</translation>
-<translation id="2230458221926704099">Beheben Sie den Verbindungsfehler mithilfe der <ph name="BEGIN_LINK" />Diagnose-App<ph name="END_LINK" /></translation>
+<translation id="2230458221926704099">Behebe den Verbindungsfehler mithilfe der <ph name="BEGIN_LINK" />Diagnose-App<ph name="END_LINK" /></translation>
<translation id="2239100178324503013">Jetzt senden</translation>
<translation id="2241693394036365668">Datei heruntergeladen</translation>
<translation id="2248949050832152960">WebAuthn verwenden</translation>
<translation id="2250931979407627383">Mehrere Heftklammern links</translation>
<translation id="225207911366869382">Dieser Wert für die Richtlinie ist veraltet.</translation>
-<translation id="2258928405015593961">Geben Sie ein Gültigkeitsdatum ein, das in der Zukunft liegt, und versuchen Sie es noch einmal</translation>
+<translation id="2256115617011615191">Jetzt neu starten</translation>
+<translation id="2258928405015593961">Gib ein Gültigkeitsdatum ein, das in der Zukunft liegt, und versuche es noch einmal</translation>
<translation id="225943865679747347">Fehlercode: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">HTTP-Fehler</translation>
<translation id="2267047181501709434">Identität wird überprüft...</translation>
@@ -425,13 +443,13 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="2277753418458118549">Verbindungsdetails anzeigen</translation>
<translation id="2283340219607151381">Adressen speichern und ausfüllen</translation>
<translation id="2283447177162560884">„<ph name="PAGE_TITLE" />“ wurde gelöscht</translation>
-<translation id="2288422996159078444">Alles, was Sie eingeben, alle Seiten, die Sie besuchen, und alle sonstigen Aktivitäten im Internet werden überwacht. Inhalte von Websites können ohne Ihr Wissen verändert werden.</translation>
+<translation id="2288422996159078444">Alles, was du eingibst, alle Seiten, die du besuchst, und alle sonstigen Aktivitäten im Internet werden überwacht. Inhalte von Websites können ohne dein Wissen verändert werden.</translation>
<translation id="2289385804009217824">Zuschneiden</translation>
-<translation id="2292556288342944218">Ihre Internetverbindung ist gesperrt</translation>
-<translation id="2293443924986248631">Wenn diese Funktion aktiviert ist, können Websites keine Cookies nutzen, die Sie durch das Web verfolgen. Einige Websites funktionieren dann möglicherweise nicht mehr richtig.</translation>
-<translation id="2295290966866883927">URLs von Seiten, die Sie besuchen, werden zur Analyse an Google Cloud oder Dritte gesendet. Sie werden beispielsweise gescannt, um unsichere Websites zu identifizieren.</translation>
+<translation id="2292556288342944218">Deine Internetverbindung ist gesperrt</translation>
+<translation id="2293443924986248631">Wenn diese Funktion aktiviert ist, können Websites keine Cookies nutzen, die deine Webaktivitäten erfassen. Einige Websites funktionieren dann möglicherweise nicht mehr richtig.</translation>
+<translation id="2295290966866883927">URLs von Seiten, die du besuchst, werden zur Analyse an Google Cloud oder Dritte gesendet. Sie werden beispielsweise gescannt, um unsichere Websites zu identifizieren.</translation>
<translation id="2297722699537546652">B5 (Umschlag)</translation>
-<translation id="2298855485018661510">Schaltfläche zum Verwalten von Cookies – drücken Sie die Eingabetaste, um Ihre Cookie-Einstellungen in den Chrome-Einstellungen zu verwalten</translation>
+<translation id="2298855485018661510">Schaltfläche zum Verwalten von Cookies – drücke die Eingabetaste, um deine Cookie-Einstellungen in den Chrome-Einstellungen zu verwalten</translation>
<translation id="2300306941146563769">Nicht hochgeladen</translation>
<translation id="2310021320168182093">Chou2 (Umschlag)</translation>
<translation id="2316887270356262533">Es werden weniger als 1 MB Speicherplatz freigegeben. Manche Websites werden beim nächsten Öffnen eventuell langsamer geladen.</translation>
@@ -439,12 +457,13 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="2328651992442742497">Zugelassen (Standardeinstellung)</translation>
<translation id="2329182534073751090">Fensterpositionierung</translation>
<translation id="2330137317877982892"><ph name="CREDIT_CARD" />, läuft am <ph name="EXPIRATION_DATE_ABBR" /> ab</translation>
-<translation id="2337852623177822836">Einstellung wird von Ihrem Administrator gesteuert</translation>
+<translation id="2337852623177822836">Einstellung wird von deinem Administrator gesteuert</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> möchte eine Kopplung durchführen</translation>
-<translation id="2346319942568447007">Von Ihnen kopiertes Bild</translation>
+<translation id="2346319942568447007">Von dir kopiertes Bild</translation>
+<translation id="2350796302381711542">Öffnen aller <ph name="PROTOCOL" />-Links durch <ph name="HANDLER_HOSTNAME" /> anstatt <ph name="REPLACED_HANDLER_TITLE" /> zulassen?</translation>
<translation id="2354001756790975382">Weitere Lesezeichen</translation>
<translation id="2354430244986887761">Google Safe Browsing hat kürzlich <ph name="BEGIN_LINK" />schädliche Apps<ph name="END_LINK" /> auf der Website <ph name="SITE" /> gefunden.</translation>
-<translation id="2355395290879513365">Angreifer können unter Umständen die Bilder sehen, die Sie sich auf dieser Website ansehen, und könnten dann versuchen, Sie durch Ändern der Bilder zu täuschen.</translation>
+<translation id="2355395290879513365">Angreifer können unter Umständen die Bilder sehen, die du dir auf dieser Website ansiehst, und könnten dann versuchen, dich durch Ändern der Bilder zu täuschen.</translation>
<translation id="2356070529366658676">Nachfragen</translation>
<translation id="2357481397660644965">Dein Gerät wird von <ph name="DEVICE_MANAGER" /> und dein Konto von <ph name="ACCOUNT_MANAGER" /> verwaltet.</translation>
<translation id="2359347814217202136">{NUM_DAYS,plural, =0{In weniger als einem Tag}=1{In einem Tag}other{In {NUM_DAYS} Tagen}}</translation>
@@ -452,21 +471,22 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="2359808026110333948">Weiter</translation>
<translation id="236340516568226369">Menü für die Größenanpassung</translation>
<translation id="2367567093518048410">Ebene</translation>
-<translation id="2372464001869762664">Nach erfolgter Bestätigung werden die Kartendetails Ihres Google-Kontos an diese Website weitergegeben. Den CVC finden Sie in den Details Ihres Plex-Kontos.</translation>
+<translation id="2372464001869762664">Nach erfolgter Bestätigung werden die Kartendetails deines Google-Kontos an diese Website weitergegeben. Den CVC findest du in den Details deines Plex-Kontos.</translation>
<translation id="2380886658946992094">Legal</translation>
<translation id="2383455408879745299">Bedienungshilfen in den Chrome-Einstellungen personalisieren</translation>
<translation id="2384307209577226199">Unternehmensstandard</translation>
<translation id="2385809941344967209">Chrome über die Chrome-Einstellungen aktualisieren</translation>
<translation id="2386255080630008482">Das Serverzertifikat wurde aufgehoben.</translation>
<translation id="2392959068659972793">Richtlinien ohne Wert zeigen</translation>
-<translation id="239429038616798445">Diese Versandart ist nicht verfügbar. Bitte wählen Sie eine andere aus.</translation>
+<translation id="239429038616798445">Diese Versandart ist nicht verfügbar. Bitte wähle eine andere aus.</translation>
<translation id="2396249848217231973">&amp;Löschen rückgängig machen</translation>
<translation id="2400600116338235695">Darf nachfragen, wenn sie eine Verbindung mit seriellen Ports herstellen möchte</translation>
<translation id="2410754574180102685">Government-Legal</translation>
<translation id="2413155254802890957">Alt</translation>
-<translation id="2413528052993050574">Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat wurde möglicherweise widerrufen. Mögliche Gründe sind eine fehlerhafte Konfiguration oder ein Angreifer, der Ihre Verbindung abfängt.</translation>
+<translation id="2413528052993050574">Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat wurde möglicherweise widerrufen. Mögliche Gründe sind eine fehlerhafte Konfiguration oder ein Angreifer, der deine Verbindung abfängt.</translation>
<translation id="2414886740292270097">Dunkel</translation>
-<translation id="2430968933669123598">Google-Konto verwalten – drücken Sie die Eingabetaste, um Daten sowie Datenschutz- und Sicherheitseinstellungen in Ihrem Google-Konto zu verwalten</translation>
+<translation id="2430968933669123598">Google-Konto verwalten – drücke die Eingabetaste, um Daten sowie Datenschutz- und Sicherheitseinstellungen in deinem Google-Konto zu verwalten</translation>
+<translation id="2436186046335138073">Öffnen aller <ph name="PROTOCOL" />-Links durch <ph name="HANDLER_HOSTNAME" /> zulassen?</translation>
<translation id="2438874542388153331">Vierfache Lochung rechts</translation>
<translation id="2450021089947420533">Recherchen</translation>
<translation id="2463739503403862330">Ausfüllen</translation>
@@ -474,9 +494,10 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="2465655957518002998">Lieferoption auswählen</translation>
<translation id="2465688316154986572">Heften</translation>
<translation id="2465914000209955735">In Chrome heruntergeladene Dateien verwalten</translation>
+<translation id="2466004615675155314">Informationen aus dem Web anzeigen</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Netzwerkdiagnose ausführen<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">1-zu-N-Reihenfolge</translation>
-<translation id="2470767536994572628">Wenn Sie Anmerkungen bearbeiten, wechselt das Dokument zur Einzelseitenansicht und seiner ursprünglichen Ausrichtung zurück</translation>
+<translation id="2470767536994572628">Wenn du Anmerkungen bearbeitest, wechselt das Dokument zur Einzelseitenansicht und seiner ursprünglichen Ausrichtung zurück</translation>
<translation id="2479410451996844060">Ungültige Such-URL</translation>
<translation id="2482878487686419369">Benachrichtigungen</translation>
<translation id="248348093745724435">Computerrichtlinien</translation>
@@ -488,46 +509,54 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="2501278716633472235">Zurück</translation>
<translation id="2505268675989099013">Konto schützen</translation>
<translation id="2512101340618156538">Nicht zugelassen (Standardeinstellung)</translation>
-<translation id="2515629240566999685">Signal an Ihrem Standort prüfen</translation>
+<translation id="2515629240566999685">Signal an deinem Standort prüfen</translation>
<translation id="2521385132275182522">Heftklammer unten rechts</translation>
<translation id="2521736961081452453">Formular erstellen</translation>
<translation id="2523886232349826891">Nur auf diesem Gerät gespeichert</translation>
<translation id="2524461107774643265">Weitere Informationen hinzufügen</translation>
<translation id="2529899080962247600">Dieses Feld sollte nicht mehr als <ph name="MAX_ITEMS_LIMIT" /> Einträge enthalten. Alle weiteren Einträge werden ignoriert.</translation>
+<translation id="2535585790302968248">Einen neuen Inkognitotab öffnen, um privat zu surfen</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{und 1 weitere}other{und # weitere}}</translation>
<translation id="2536110899380797252">Adresse hinzufügen</translation>
<translation id="2539524384386349900">Erkennen</translation>
<translation id="2540701853218677861">An- und Abmeldeverlauf des Geräts, einschließlich Zeitstempel und Fehlversuchen</translation>
-<translation id="2541219929084442027">Seiten, die Sie sich auf Inkognitotabs ansehen, werden nach dem Schließen aller Inkognitotabs nicht in Ihrem Browserverlauf, Cookiespeicher oder Suchverlauf gespeichert. Ihre Lesezeichen und heruntergeladenen Dateien bleiben erhalten.</translation>
+<translation id="2541219929084442027">Seiten, die du dir auf Inkognitotabs ansiehst, werden nach dem Schließen aller Inkognitotabs nicht in deinem Browserverlauf, Cookiespeicher oder Suchverlauf gespeichert. Deine Lesezeichen und heruntergeladenen Dateien bleiben erhalten.</translation>
<translation id="2544644783021658368">Einzelnes Dokument</translation>
<translation id="2546283357679194313">Cookies und Websitedaten</translation>
<translation id="254947805923345898">Der Richtlinienwert ist ungültig.</translation>
<translation id="255002559098805027"><ph name="HOST_NAME" /> hat eine ungültige Antwort gesendet.</translation>
<translation id="2552246211866555379">Hagaki</translation>
<translation id="2552295903035773204">Von jetzt an Displaysperre verwenden, um Karten zu bestätigen</translation>
-<translation id="2553853292994445426">Prüfen Sie die Einstellungen für sichere DNS-Abfragen. Sie haben möglicherweise einen sicheren DNS-Server konfiguriert, zu dem keine Verbindung aufgebaut werden kann.</translation>
+<translation id="2553853292994445426">Prüfe die Einstellungen für sichere DNS-Abfragen. Du hast möglicherweise einen sicheren DNS-Server konfiguriert, zu dem keine Verbindung aufgebaut werden kann.</translation>
<translation id="2556876185419854533">&amp;Bearbeiten rückgängig machen</translation>
<translation id="2570734079541893434">Einstellungen verwalten</translation>
<translation id="257674075312929031">Gruppe</translation>
-<translation id="2576880857912732701">Schaltfläche zum Verwalten der Sicherheitseinstellungen – drücken Sie die Eingabetaste, um beispielsweise Safe Browsing in den Chrome-Einstellungen zu verwalten</translation>
+<translation id="2576880857912732701">Schaltfläche zum Verwalten der Sicherheitseinstellungen – drücke die Eingabetaste, um beispielsweise Safe Browsing in den Chrome-Einstellungen zu verwalten</translation>
<translation id="2586657967955657006">Zwischenablage</translation>
<translation id="2587730715158995865">Von <ph name="ARTICLE_PUBLISHER" />. Diese Meldung und <ph name="OTHER_ARTICLE_COUNT" /> weitere Meldungen lesen.</translation>
<translation id="2587841377698384444">Directory API-ID: </translation>
<translation id="2594318783181750337">Schnelle Webanzeige:</translation>
<translation id="2595719060046994702">Dieses Gerät und dieses Konto werden nicht von einem Unternehmen oder einer anderen Organisation verwaltet.</translation>
-<translation id="2596415276201385844">Zum Aufbau einer sicheren Verbindung muss die Uhrzeit richtig eingestellt sein. Der Grund hierfür ist, dass Websites sich mithilfe von Zertifikaten identifizieren, die nur für einen bestimmten Zeitraum gelten. Da die Uhrzeit Ihres Geräts falsch ist, kann Chrome diese Zertifikate nicht bestätigen.</translation>
-<translation id="2597378329261239068">Dieses Dokument ist passwortgeschützt. Geben Sie ein Passwort ein.</translation>
+<translation id="2596415276201385844">Zum Aufbau einer sicheren Verbindung muss die Uhrzeit richtig eingestellt sein. Der Grund hierfür ist, dass Websites sich mithilfe von Zertifikaten identifizieren, die nur für einen bestimmten Zeitraum gelten. Da die Uhrzeit deines Geräts falsch ist, kann Chrome diese Zertifikate nicht bestätigen.</translation>
+<translation id="2597378329261239068">Dieses Dokument ist passwortgeschützt. Gib ein Passwort ein.</translation>
<translation id="2609632851001447353">Varianten</translation>
<translation id="2610561535971892504">Zum Kopieren klicken</translation>
+<translation id="2617988307566202237">Chrome speichert folgende Daten <ph name="BEGIN_EMPHASIS" />nicht<ph name="END_EMPHASIS" />:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Den Browserverlauf
+ <ph name="LIST_ITEM" />Cookies und Websitedaten
+ <ph name="LIST_ITEM" />In Formulare eingegebene Informationen
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (Umschlag)</translation>
-<translation id="2625385379895617796">Ihre Uhr geht vor</translation>
+<translation id="2623663032199728144">Darf nachfragen, wenn sie Informationen über meine Bildschirme verwenden möchte</translation>
+<translation id="2625385379895617796">Deine Uhr geht vor</translation>
<translation id="262745152991669301">Darf nachfragen, wenn sie eine Verbindung mit USB-Geräten herstellen möchte</translation>
-<translation id="2629325967560697240">Schalten Sie für größtmögliche Sicherheit in Chrome das <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />erweiterte Safe Browsing<ph name="END_ENHANCED_PROTECTION_LINK" /> ein</translation>
+<translation id="2629325967560697240">Schalte für größtmögliche Sicherheit in Chrome das <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />erweiterte Safe Browsing<ph name="END_ENHANCED_PROTECTION_LINK" /> ein</translation>
<translation id="2634124572758952069">Die Server-IP-Adresse von <ph name="HOST_NAME" /> wurde nicht gefunden.</translation>
<translation id="2639739919103226564">Status: </translation>
<translation id="264810637653812429">Es wurden keine kompatiblen Geräte gefunden.</translation>
<translation id="2649204054376361687"><ph name="CITY" />, <ph name="COUNTRY" /></translation>
-<translation id="2649259151839507861"><ph name="CLEAR_BROWSING_DATA_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücken Sie die Tabulatortaste und dann die Eingabetaste, um in den Chrome-Einstellungen Ihren Browserverlauf, Ihre Cookies und andere Daten zu löschen sowie den Cache zu leeren</translation>
+<translation id="2649259151839507861"><ph name="CLEAR_BROWSING_DATA_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücke die Tabulatortaste und dann die Eingabetaste, um in den Chrome-Einstellungen deinen Browserverlauf, deine Cookies und andere Daten zu löschen sowie den Cache zu leeren</translation>
<translation id="2650446666397867134">Der Zugriff auf die Datei wurde verweigert.</translation>
<translation id="2653659639078652383">Senden</translation>
<translation id="2659491813326907275">Bedienungshilfen in den Chrome OS-Einstellungen personalisieren</translation>
@@ -535,8 +564,8 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="2664887757054927933">{COUNT,plural, =0{Keins}=1{1 Passwort (für <ph name="DOMAIN_LIST" />)}=2{2 Passwörter (für <ph name="DOMAIN_LIST" />)}other{# Passwörter (für <ph name="DOMAIN_LIST" />)}}</translation>
<translation id="2666092431469916601">Oben</translation>
<translation id="2666117266261740852">Andere Tabs oder Apps schließen</translation>
-<translation id="2672201172023654893">Ihr Browser wird nicht verwaltet.</translation>
-<translation id="2674170444375937751">Möchten Sie diese Seiten wirklich aus dem Verlauf löschen?</translation>
+<translation id="2672201172023654893">Dein Browser wird nicht verwaltet.</translation>
+<translation id="2674170444375937751">Möchtest du diese Seiten wirklich aus dem Verlauf löschen?</translation>
<translation id="2674804415323431591">Vorschläge ausblenden</translation>
<translation id="2676271551327853224">Roc-8K</translation>
<translation id="2677748264148917807">Verlassen</translation>
@@ -552,13 +581,14 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="2705137772291741111">Die (im Cache) gespeicherte Kopie dieser Website war nicht lesbar.</translation>
<translation id="2709516037105925701">Automatisches Ausfüllen</translation>
<translation id="2713444072780614174">Weiß</translation>
-<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücken Sie die Eingabetaste, um Zahlungen und Kreditkartendaten in den Chrome-Einstellungen zu verwalten</translation>
+<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücke die Eingabetaste, um Zahlungen und Kreditkartendaten in den Chrome-Einstellungen zu verwalten</translation>
+<translation id="271663710482723385">Zum Beenden des Vollbildmodus |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| drücken</translation>
<translation id="2721148159707890343">Anfrage erfolgreich</translation>
<translation id="2723669454293168317">Sicherheitscheck in den Chrome-Einstellungen ausführen</translation>
<translation id="2726001110728089263">Seitenfach</translation>
<translation id="2728127805433021124">Das Serverzertifikat ist mit einem schwachen Signaturalgorithmus signiert.</translation>
<translation id="2730326759066348565"><ph name="BEGIN_LINK" />Verbindungsdiagnose ausführen<ph name="END_LINK" /></translation>
-<translation id="2737403869486738563">Stöbern Sie weiter, um relevante Aktivitäten in Ihrem Chrome-Verlauf zu sehen</translation>
+<translation id="2737403869486738563">Stöbere weiter, um relevante Aktivitäten in deinem Chrome-Verlauf zu sehen</translation>
<translation id="2738330467931008676">Abholadresse auswählen</translation>
<translation id="2740531572673183784">Ok</translation>
<translation id="2742870351467570537">Ausgewählte Einträge entfernen</translation>
@@ -568,10 +598,10 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="2775884851269838147">Erste Druckseite</translation>
<translation id="2781692009645368755">Google Pay</translation>
<translation id="2784949926578158345">Verbindung wurde zurückgesetzt.</translation>
-<translation id="2792012897584536778">Administratoren dieses Geräts haben Sicherheitszertifikate eingerichtet, die es ihnen möglicherweise erlauben, Inhalte der von Ihnen besuchten Websites anzuzeigen.</translation>
-<translation id="2799020568854403057">Die Website, die Sie aufrufen möchten, enthält schädliche Apps</translation>
+<translation id="2792012897584536778">Administratoren dieses Geräts haben Sicherheitszertifikate eingerichtet, die es ihnen möglicherweise erlauben, Inhalte der von dir besuchten Websites anzuzeigen.</translation>
+<translation id="2799020568854403057">Die Website, die du aufrufen möchtest, enthält schädliche Apps</translation>
<translation id="2799223571221894425">Neu starten</translation>
-<translation id="2799846101868535739">Schaltfläche „Weiter stöbern“ – drücken Sie die Eingabetaste, um weiter zu recherchieren und relevante Aktivitäten in Ihrem Chrome-Verlauf anzusehen</translation>
+<translation id="2799846101868535739">Schaltfläche „Weiter stöbern“ – drücke die Eingabetaste, um weiter zu recherchieren und relevante Aktivitäten in deinem Chrome-Verlauf anzusehen</translation>
<translation id="2803306138276472711">Google Safe Browsing hat kürzlich <ph name="BEGIN_LINK" />Malware<ph name="END_LINK" /> auf <ph name="SITE" /> gefunden. Websites, die in der Regel sicher sind, können gelegentlich mit Malware infiziert sein.</translation>
<translation id="2807052079800581569">Y-Position des Bilds</translation>
<translation id="2820957248982571256">Wird gescannt...</translation>
@@ -581,11 +611,12 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="2839032553903800133">Benachrichtigungen blockiert</translation>
<translation id="2839501879576190149">Warnung: Gefälschte Website</translation>
<translation id="2850739647070081192">Invite (Umschlag)</translation>
-<translation id="2856444702002559011">Hacker könnten versuchen, Ihre Daten von <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> zu stehlen, zum Beispiel Passwörter, Nachrichten oder Kreditkartendaten. <ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2856444702002559011">Hacker könnten versuchen, deine Daten von <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> zu stehlen, zum Beispiel Passwörter, Nachrichten oder Kreditkartendaten. <ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">Diese Website zeigt aufdringliche oder irreführende Werbung an.</translation>
+<translation id="286512204874376891">Wenn du eine virtuelle Karte verwendest, werden deine tatsächlichen Kartendetails nicht preisgegeben – dadurch bist du besser vor Betrugsversuchen geschützt. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">Freundlich</translation>
-<translation id="2876489322757410363">Der Inkognitomodus wird deaktiviert, um über eine externe Anwendung zu zahlen. Möchten Sie fortfahren?</translation>
-<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücken Sie die Tabulatortaste und dann die Eingabetaste, um beispielsweise Safe Browsing in den Chrome-Einstellungen zu verwalten</translation>
+<translation id="2876489322757410363">Der Inkognitomodus wird deaktiviert, um über eine externe Anwendung zu zahlen. Möchtest du fortfahren?</translation>
+<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücke die Tabulatortaste und dann die Eingabetaste, um beispielsweise Safe Browsing in den Chrome-Einstellungen zu verwalten</translation>
<translation id="2878197950673342043">Posterfaltung</translation>
<translation id="2878424575911748999">A1</translation>
<translation id="2880660355386638022">Fensterpositionierung</translation>
@@ -597,7 +628,7 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="290376772003165898">Diese Seite ist nicht auf <ph name="LANGUAGE" />?</translation>
<translation id="2909946352844186028">Eine Netzwerkänderung ist aufgetreten.</translation>
<translation id="2911973620368911614">Nutzer-ID der Konto-ID des Auftrags</translation>
-<translation id="2914160345369867329"><ph name="SITE" /> schützt Ihre Informationen in der Regel durch Verschlüsselung. Als Chrome dieses Mal versuchte, eine Verbindung zu <ph name="SITE" /> herzustellen, gab die Website ungewöhnliche und falsche Anmeldedaten zurück. Entweder versucht ein Angreifer, sich als <ph name="SITE" /> auszugeben, oder die Verbindung wurde durch eine WLAN-Anmeldeseite unterbrochen. Da Chrome die Verbindung vor dem Austausch von Daten unterbrochen hat, sind Ihre Informationen weiterhin sicher.</translation>
+<translation id="2914160345369867329"><ph name="SITE" /> schützt deine Informationen in der Regel durch Verschlüsselung. Als Chrome dieses Mal versuchte, eine Verbindung zu <ph name="SITE" /> herzustellen, gab die Website ungewöhnliche und falsche Anmeldedaten zurück. Entweder versucht ein Angreifer, sich als <ph name="SITE" /> auszugeben, oder die Verbindung wurde durch eine WLAN-Anmeldeseite unterbrochen. Da Chrome die Verbindung vor dem Austausch von Daten unterbrochen hat, sind deine Informationen weiterhin sicher.</translation>
<translation id="2915068235268646559">Absturz vom <ph name="CRASH_TIME" /></translation>
<translation id="2916038427272391327">Andere Programme schließen</translation>
<translation id="2922350208395188000">Das Serverzertifikat kann nicht überprüft werden.</translation>
@@ -607,9 +638,10 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="2930577230479659665">Nach jeder Kopie zuschneiden</translation>
<translation id="2932085390869194046">Passwort vorschlagen…</translation>
<translation id="2934466151127459956">Government-Letter</translation>
-<translation id="2941952326391522266">Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat stammt von <ph name="DOMAIN2" />. Mögliche Gründe sind eine fehlerhafte Konfiguration oder ein Angreifer, der Ihre Verbindung abfängt.</translation>
+<translation id="2938225289965773019"><ph name="PROTOCOL" />-Links öffnen</translation>
+<translation id="2941952326391522266">Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat stammt von <ph name="DOMAIN2" />. Mögliche Gründe sind eine fehlerhafte Konfiguration oder ein Angreifer, der deine Verbindung abfängt.</translation>
<translation id="2943895734390379394">Uhrzeit des Uploads:</translation>
-<translation id="2948083400971632585">Sie können alle für eine Verbindung konfigurierten Proxys auf der Seite "Einstellungen" deaktivieren.</translation>
+<translation id="2948083400971632585">Du kannst alle für eine Verbindung konfigurierten Proxys auf der Seite „Einstellungen“ deaktivieren.</translation>
<translation id="2949183777371959169">Ignoriert, da der Computer nicht bei der Chrome-Verwaltung über die Cloud angemeldet ist.</translation>
<translation id="2951588413176968965">Meine Ablage</translation>
<translation id="2952820037279740115">Alle Inkognitofenster schließen</translation>
@@ -617,33 +649,34 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="2955913368246107853">Suchleiste schließen</translation>
<translation id="2972581237482394796">&amp;Wiederholen</translation>
<translation id="2977665033722899841"><ph name="ROW_NAME" />, aktuell ausgewählt. <ph name="ROW_CONTENT" /></translation>
-<translation id="2985306909656435243">Wenn Sie diese Option auswählen, speichert Chromium eine Kopie Ihrer Karte auf diesem Gerät, damit Formulare schneller ausgefüllt werden können.</translation>
+<translation id="2985306909656435243">Wenn du diese Option auswählst, speichert Chromium eine Kopie deiner Karte auf diesem Gerät, damit Formulare schneller ausgefüllt werden können.</translation>
<translation id="2985398929374701810">Gültige Adresse eingeben</translation>
-<translation id="2986368408720340940">Diese Abholoption ist nicht verfügbar. Bitte wählen Sie eine andere Option aus.</translation>
+<translation id="2986368408720340940">Diese Abholoption ist nicht verfügbar. Bitte wähle eine andere Option aus.</translation>
<translation id="2987034854559945715">Keine passenden Funktionen</translation>
<translation id="2989742184762224133">Zwei Heftklammern oben</translation>
<translation id="2991174974383378012">Datenfreigabe an Websites</translation>
<translation id="299122504639061328">Standardmäßige Suchmaschine und Websitesuche verwalten</translation>
-<translation id="2991571918955627853">Sie können <ph name="SITE" /> derzeit nicht aufrufen, da die Website HSTS verwendet. Netzwerkfehler und Angriffe sind in der Regel nur vorübergehend, sodass die Seite wahrscheinlich später wieder funktioniert.</translation>
+<translation id="2991571918955627853">Du kannst <ph name="SITE" /> derzeit nicht aufrufen, da die Website HSTS verwendet. Netzwerkfehler und Angriffe sind in der Regel nur vorübergehend, sodass die Seite wahrscheinlich später wieder funktioniert.</translation>
<translation id="2995517112308048736">Dateigröße:</translation>
<translation id="3002501248619246229">Medien im Eingabefach prüfen</translation>
<translation id="3005723025932146533">Gespeicherte Kopie anzeigen</translation>
-<translation id="3008447029300691911">Geben Sie den CVC für <ph name="CREDIT_CARD" /> ein. Nach erfolgter Bestätigung werden die Kartendetails an diese Website weitergegeben.</translation>
+<translation id="3008447029300691911">Gib den CVC für <ph name="CREDIT_CARD" /> ein. Nach erfolgter Bestätigung werden die Kartendetails an diese Website weitergegeben.</translation>
<translation id="3010559122411665027">Listeneintrag "<ph name="ENTRY_INDEX" />": <ph name="ERROR" /></translation>
<translation id="3013291976881901233">MIDI-Geräte</translation>
<translation id="301521992641321250">Automatisch blockiert</translation>
-<translation id="3016780570757425217">Ihren Standort abrufen</translation>
-<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" /> – drücken Sie die Tabulatortaste und dann die Eingabetaste, um den Vorschlag zu entfernen.</translation>
+<translation id="3016780570757425217">Deinen Standort abrufen</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" /> – drücke die Tabulatortaste und dann die Eingabetaste, um den Vorschlag zu entfernen.</translation>
<translation id="3023071826883856138">You4 (Umschlag)</translation>
<translation id="3024663005179499861">Falscher Richtlinientyp</translation>
<translation id="3037605927509011580">Oh nein!</translation>
<translation id="3041612393474885105">Zertifikatinformationen</translation>
<translation id="3044034790304486808">Weiter stöbern</translation>
+<translation id="305162504811187366">Chrome Remote Desktop-Verlauf, einschließlich Zeitstempeln, Hosts und Client-Sitzungs-IDs</translation>
<translation id="3060227939791841287">C9 (Umschlag)</translation>
<translation id="3061707000357573562">Patchdienst</translation>
<translation id="306573536155379004">Spiel gestartet.</translation>
<translation id="3080254622891793721">Grafik</translation>
-<translation id="3086579638707268289">Ihre Aktivitäten im Web werden überwacht</translation>
+<translation id="3086579638707268289">Deine Aktivitäten im Web werden überwacht</translation>
<translation id="3087734570205094154">Unten</translation>
<translation id="3095940652251934233">Statement</translation>
<translation id="3096100844101284527">Abholadresse hinzufügen</translation>
@@ -651,12 +684,12 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="3105172416063519923">Asset-ID:</translation>
<translation id="3107591622054137333"><ph name="BEGIN_LINK" />Konfiguration der sicheren DNS-Abfragen prüfen<ph name="END_LINK" /></translation>
<translation id="3108943290502734357">Mittleres Fach</translation>
-<translation id="3109728660330352905">Sie sind nicht zum Aufrufen dieser Seite autorisiert.</translation>
+<translation id="3109728660330352905">Du bist nicht zum Aufrufen dieser Seite autorisiert.</translation>
<translation id="3113284927548439113">Dritte Schicht</translation>
<translation id="3115874930288085374">Gemäß <ph name="ENROLLMENT_DOMAIN" /> ist es notwendig, ein Daten-Backup zu erstellen und dieses <ph name="DEVICE_TYPE" /> zurückzugeben.</translation>
<translation id="3116158981186517402">Laminieren</translation>
<translation id="3120730422813725195">Elo</translation>
-<translation id="31207688938192855"><ph name="BEGIN_LINK" />Versuchen Sie, die Verbindungsdiagnose auszuführen.<ph name="END_LINK" /></translation>
+<translation id="31207688938192855"><ph name="BEGIN_LINK" />Versuche, die Verbindungsdiagnose auszuführen.<ph name="END_LINK" /></translation>
<translation id="3121994479408824897">Zu <ph name="DOMAIN" /> wechseln</translation>
<translation id="3137507986424712703">{COUNT,plural, =0{Keine}=1{Anmeldedaten für 1 Konto}other{Anmeldedaten für # Konten}}</translation>
<translation id="3145945101586104090">Fehler beim Dekodieren der Antwort</translation>
@@ -666,52 +699,56 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="315504272643575312">Dein Konto wird von <ph name="MANAGER" /> verwaltet.</translation>
<translation id="3157931365184549694">Wieder­her­stellen</translation>
<translation id="3158539265159265653">CD</translation>
-<translation id="3162559335345991374">Unter Umständen müssen Sie die Anmeldeseite des verwendeten WLAN-Netzwerken aufrufen.</translation>
+<translation id="3162559335345991374">Unter Umständen musst du die Anmeldeseite des verwendeten WLAN-Netzwerken aufrufen.</translation>
<translation id="3169472444629675720">Discover</translation>
<translation id="3174168572213147020">Insel</translation>
-<translation id="3176929007561373547">Vergewissern Sie sich, dass der Proxyserver funktioniert. Überprüfen Sie die
- Proxyeinstellungen oder wenden Sie sich an Ihren Netzwerkadministrator.
- Falls Sie keinen Proxyserver verwenden möchten, deaktivieren Sie ihn wie
+<translation id="3176929007561373547">Vergewissere dich, dass der Proxyserver funktioniert. Überprüfe die
+ Proxyeinstellungen oder wende dich an deinen Netzwerkadministrator.
+ Falls du keinen Proxyserver verwenden möchtest, deaktiviere ihn wie
folgt: <ph name="PLATFORM_TEXT" /></translation>
-<translation id="317878711435188021">Informationen zu Ihrer aktiven Nutzung dieses Geräts abrufen</translation>
-<translation id="3194737229810486521"><ph name="URL" /> möchte Daten dauerhaft auf Ihrem Gerät speichern</translation>
+<translation id="317878711435188021">Informationen zu deiner aktiven Nutzung dieses Geräts abrufen</translation>
+<translation id="3194737229810486521"><ph name="URL" /> möchte Daten dauerhaft auf deinem Gerät speichern</translation>
<translation id="3195213714973468956"><ph name="PRINTER_NAME" /> auf <ph name="SERVER_NAME" /></translation>
<translation id="3197136577151645743">Darf nachfragen, wenn sie Informationen zu meiner aktiven Nutzung dieses Geräts abrufen möchte</translation>
-<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücken Sie die Tabulatortaste und dann die Eingabetaste, um in den Chrome-Einstellungen zu verwalten, welche Informationen synchronisiert werden</translation>
+<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücke die Tabulatortaste und dann die Eingabetaste, um in den Chrome-Einstellungen zu verwalten, welche Informationen synchronisiert werden</translation>
<translation id="320323717674993345">Zahlung abbrechen</translation>
+<translation id="3203366800380907218">Aus dem Web</translation>
<translation id="3207960819495026254">Mit einem Lesezeichen versehen</translation>
<translation id="3209034400446768650">Auf der Seite wird möglicherweise Geld verlangt</translation>
-<translation id="3212581601480735796">Ihre Aktivität auf <ph name="HOSTNAME" /> wird überwacht</translation>
+<translation id="3212581601480735796">Deine Aktivität auf <ph name="HOSTNAME" /> wird überwacht</translation>
<translation id="3215092763954878852">WebAuthn konnte nicht verwendet werden</translation>
<translation id="3218181027817787318">Relativ</translation>
<translation id="3223287115535306850">Ladesymbol beim Starten der App</translation>
<translation id="3225347164936328585">Applaus</translation>
-<translation id="3225919329040284222">Der Server hat ein Zertifikat übermittelt, das nicht mit den integrierten Erwartungen übereinstimmt. Diese Erwartungen sind zu Ihrem Schutz in bestimmten Websites mit hohen Sicherheitsstandards enthalten.</translation>
-<translation id="3226128629678568754">Klicken Sie auf die Schaltfläche zum erneuten Laden, um die für das Laden der Seite erforderlichen Daten noch einmal zu senden.</translation>
+<translation id="3225919329040284222">Der Server hat ein Zertifikat übermittelt, das nicht mit den integrierten Erwartungen übereinstimmt. Diese Erwartungen sind zu deinem Schutz in bestimmten Websites mit hohen Sicherheitsstandards enthalten.</translation>
+<translation id="3226128629678568754">Klicke auf die Schaltfläche zum erneuten Laden, um die für das Laden der Seite erforderlichen Daten noch einmal zu senden.</translation>
<translation id="3226387218769101247">Miniaturansichten</translation>
<translation id="3227137524299004712">Mikrofon</translation>
-<translation id="3229041911291329567">Versionsinformationen zu Ihrem Gerät und Browser</translation>
+<translation id="3229041911291329567">Versionsinformationen zu deinem Gerät und Browser</translation>
<translation id="323107829343500871">CVC für <ph name="CREDIT_CARD" /> eingeben</translation>
<translation id="3234666976984236645">Wichtige Inhalte auf dieser Website immer erkennen</translation>
-<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücken Sie die Tabulatortaste und dann die Eingabetaste, um das Erscheinungsbild Ihres Browsers anzupassen</translation>
+<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücke die Tabulatortaste und dann die Eingabetaste, um das Erscheinungsbild deines Browsers anzupassen</translation>
<translation id="3240791268468473923">Sichere Anmeldedaten für Zahlungen – Tabellenblatt für nicht übereinstimmende sichere Anmeldedaten ist geöffnet</translation>
+<translation id="324180406144491771">Links von „<ph name="HOST_NAME" />“ werden blockiert</translation>
<translation id="3249845759089040423">Cool</translation>
<translation id="3252266817569339921">Französisch</translation>
<translation id="3257954757204451555">Woher stammt diese Information?</translation>
-<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücken Sie die Tabulatortaste und dann die Eingabetaste, um schnell einen neuen Termin in Google Kalender zu erstellen</translation>
-<translation id="3264837738038045344">Schaltfläche zum Verwalten der Chrome-Einstellungen – drücken Sie die Eingabetaste, um Ihre Chrome-Einstellungen aufzurufen</translation>
+<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücke die Tabulatortaste und dann die Eingabetaste, um schnell einen neuen Termin in Google Kalender zu erstellen</translation>
+<translation id="3261488570342242926">Informationen zu virtuellen Karten</translation>
+<translation id="3264837738038045344">Schaltfläche zum Verwalten der Chrome-Einstellungen – drücke die Eingabetaste, um deine Chrome-Einstellungen aufzurufen</translation>
<translation id="3266793032086590337">Wert (Konflikt)</translation>
<translation id="3268451620468152448">Geöffnete Tabs</translation>
<translation id="3270847123878663523">&amp;Neu anordnen rückgängig machen</translation>
<translation id="3271648667212143903"><ph name="ORIGIN" /> möchte eine Verbindung herstellen</translation>
<translation id="3274521967729236597">Pa-Kai</translation>
-<translation id="3282085321714087552">Ihre Organisation, <ph name="ENROLLMENT_DOMAIN" />, hat Informationen wie z. B. Einstellungen oder Richtlinien an folgende Websites gesendet.</translation>
+<translation id="3282085321714087552">Deine Organisation, <ph name="ENROLLMENT_DOMAIN" />, hat Informationen wie z. B. Einstellungen oder Richtlinien an folgende Websites gesendet.</translation>
<translation id="3282497668470633863">Angabe für "Name auf der Karte" hinzufügen</translation>
<translation id="3286372614333682499">Hochformat</translation>
<translation id="3287510313208355388">Herunterladen, sobald eine Internetverbindung besteht</translation>
-<translation id="3288238092761586174"><ph name="URL" /> muss möglicherweise zusätzliche Schritte ausführen, um Ihre Zahlung zu bestätigen</translation>
+<translation id="3288238092761586174"><ph name="URL" /> muss möglicherweise zusätzliche Schritte ausführen, um deine Zahlung zu bestätigen</translation>
<translation id="3293642807462928945">Weitere Informationen zur "<ph name="POLICY_NAME" />"-Richtlinie</translation>
<translation id="3295444047715739395">Passwörter in den Chrome-Einstellungen ansehen und verwalten</translation>
+<translation id="3303795387212510132">App erlauben, Links vom Typ <ph name="PROTOCOL_SCHEME" /> zu öffnen?</translation>
<translation id="3303855915957856445">Keine Suchergebnisse gefunden</translation>
<translation id="3304073249511302126">Bluetooth-Suche</translation>
<translation id="3308006649705061278">Organisationseinheit (OU)</translation>
@@ -725,19 +762,13 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="3345782426586609320">Augen</translation>
<translation id="3355823806454867987">Proxy-Einstellungen ändern...</translation>
<translation id="3360103848165129075">Dokument zur Zahlungsabwicklung</translation>
-<translation id="3361596688432910856">Chrome <ph name="BEGIN_EMPHASIS" />speichert die folgenden Daten nicht<ph name="END_EMPHASIS" />:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Ihren Browserverlauf
- <ph name="LIST_ITEM" />Cookies und Websitedaten
- <ph name="LIST_ITEM" />In Formulare eingegebene Daten
- <ph name="END_LIST" /></translation>
-<translation id="3362968246557010467">Diese Richtlinie wurde automatisch aus der verworfenen Richtlinie "<ph name="OLD_POLICY" />" kopiert. Verwenden Sie stattdessen diese Richtlinie.</translation>
-<translation id="3364869320075768271"><ph name="URL" /> möchte Ihr Virtual-Reality-Gerät und Ihre Virtual-Reality-Daten verwenden</translation>
+<translation id="3362968246557010467">Diese Richtlinie wurde automatisch aus der verworfenen Richtlinie "<ph name="OLD_POLICY" />" kopiert. Verwende stattdessen diese Richtlinie.</translation>
+<translation id="3364869320075768271"><ph name="URL" /> möchte dein Virtual-Reality-Gerät und deine Virtual-Reality-Daten verwenden</translation>
<translation id="3366477098757335611">Karten ansehen</translation>
<translation id="3369192424181595722">Fehler bei der Uhrzeit</translation>
<translation id="3371076217486966826"><ph name="URL" /> möchte:
- • eine dreidimensionale Karte Ihrer Umgebung erstellen und die Kameraposition verfolgen
- • Ihre Kamera verwenden</translation>
+ • eine dreidimensionale Karte deiner Umgebung erstellen und die Kameraposition verfolgen
+ • deine Kamera verwenden</translation>
<translation id="337363190475750230">Bereitstellung aufgehoben</translation>
<translation id="3375754925484257129">Chrome-Sicherheitscheck ausführen</translation>
<translation id="3377144306166885718">Der Server hat eine veraltete TLS-Version verwendet.</translation>
@@ -745,7 +776,7 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="3377736046129930310">Bildschirmsperre verwenden, um Karten schneller zu bestätigen</translation>
<translation id="3380365263193509176">Unbekannter Fehler</translation>
<translation id="3380864720620200369">Client-ID: </translation>
-<translation id="3381668585148405088">Ihren Einkauf bestätigen</translation>
+<translation id="3381668585148405088">Deinen Einkauf bestätigen</translation>
<translation id="3383566085871012386">Aktuelle Rangfolge</translation>
<translation id="3387261909427947069">Zahlungsmethoden</translation>
<translation id="3391030046425686457">Lieferadresse</translation>
@@ -757,12 +788,12 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="3409896703495473338">Sicherheitseinstellungen verwalten</translation>
<translation id="3414952576877147120">Größe:</translation>
<translation id="3417660076059365994">Hochgeladene oder angehängte Dateien werden zur Analyse an Google Cloud oder Dritte gesendet. Sie werden beispielsweise auf sensible Daten oder Malware geprüft.</translation>
-<translation id="3422248202833853650">Versuchen Sie, andere Programme zu beenden, um Speicher freizugeben.</translation>
+<translation id="3422248202833853650">Versuche, andere Programme zu beenden, um Speicher freizugeben.</translation>
<translation id="3422472998109090673"><ph name="HOST_NAME" /> ist momentan nicht erreichbar.</translation>
<translation id="3423742043356668186">Vom System angegeben</translation>
<translation id="3427092606871434483">Zulassen (Standard)</translation>
<translation id="3427342743765426898">&amp;Bearbeiten wiederholen</translation>
-<translation id="342781501876943858">Chromium empfiehlt, Ihr Passwort zurückzusetzen, wenn Sie es auf anderen Websites verwendet haben.</translation>
+<translation id="342781501876943858">Chromium empfiehlt, dein Passwort zurückzusetzen, wenn du es auf anderen Websites verwendet hast.</translation>
<translation id="3428151540071562330">Einer oder mehrere der "DnsOverHttpsTemplates"-Servervorlagen-URIs sind ungültig und werden nicht verwendet.</translation>
<translation id="3431636764301398940">Diese Karte für dieses Gerät speichern</translation>
<translation id="3432601291244612633">Seite schließen</translation>
@@ -781,21 +812,21 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="3462200631372590220">Erweiterte Informationen ausblenden</translation>
<translation id="3467763166455606212">Name des Karteninhabers erforderlich</translation>
<translation id="3468054117417088249"><ph name="TAB_SWITCH_SUFFIX" />, derzeit geöffnet, Tabulatortaste und dann Eingabetaste drücken, um zum offenen Tab zu wechseln</translation>
-<translation id="3470563864795286535"><ph name="CLOSE_INCOGNITO_WINDOWS_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücken Sie die Tabulatortaste und dann die Eingabetaste, um alle geöffneten Inkognitofenster zu schließen</translation>
+<translation id="3470563864795286535"><ph name="CLOSE_INCOGNITO_WINDOWS_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücke die Tabulatortaste und dann die Eingabetaste, um alle geöffneten Inkognitofenster zu schließen</translation>
<translation id="3479552764303398839">Jetzt nicht</translation>
-<translation id="3484560055331845446">Sie könnten den Zugriff auf Ihr Google-Konto verlieren. Chrome empfiehlt Ihnen, Ihr Passwort jetzt zu ändern. Sie werden dazu aufgefordert, sich anzumelden.</translation>
+<translation id="3484560055331845446">Du könntest den Zugriff auf dein Google-Konto verlieren. Chrome empfiehlt dir, dein Passwort jetzt zu ändern. Du wirst dazu aufgefordert, dich anzumelden.</translation>
<translation id="3487845404393360112">Fach 4</translation>
<translation id="3495081129428749620">Auf Seite "<ph name="PAGE_TITLE" />" suchen</translation>
<translation id="350069200438440499">Dateiname:</translation>
-<translation id="3507936815618196901">Eine 3D-Karte Ihrer Umgebung erstellen und die Kameraposition verfolgen</translation>
+<translation id="3507936815618196901">Eine 3D-Karte deiner Umgebung erstellen und die Kameraposition verfolgen</translation>
<translation id="3512163584740124171">Diese Richtlinie wird ignoriert, da eine andere Richtlinie aus derselben Richtliniengruppe eine höhere Priorität hat.</translation>
-<translation id="35172538073169599">Schaltfläche zum Verwalten von Adressen – drücken Sie die Eingabetaste, um Adressen in den Chrome-Einstellungen hinzuzufügen und zu verwalten</translation>
+<translation id="35172538073169599">Schaltfläche zum Verwalten von Adressen – drücke die Eingabetaste, um Adressen in den Chrome-Einstellungen hinzuzufügen und zu verwalten</translation>
<translation id="3518941727116570328">Handhabung mehrerer Objekte</translation>
<translation id="3528171143076753409">Serverzertifikat ist nicht vertrauenswürdig.</translation>
<translation id="3528485271872257980">Dunkelbraun</translation>
<translation id="3530944546672790857">{COUNT,plural, =0{Mindestens 1 Eintrag auf synchronisierten Geräten}=1{1 Eintrag (und weitere auf synchronisierten Geräten)}other{# Einträge (und weitere auf synchronisierten Geräten)}}</translation>
<translation id="3531780078352352885">Auftragsblätter</translation>
-<translation id="3532844647053365774"><ph name="HOST" /> möchte Ihr Mikrofon verwenden</translation>
+<translation id="3532844647053365774"><ph name="HOST" /> möchte dein Mikrofon verwenden</translation>
<translation id="3533328374079021623">Ablage 5</translation>
<translation id="3552297013052089404">Schriftart Sans-Serif</translation>
<translation id="3558573058928565255">Tageszeit</translation>
@@ -804,68 +835,68 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="3574305903863751447"><ph name="CITY" />, <ph name="STATE" /> <ph name="COUNTRY" /></translation>
<translation id="3575121482199441727">Für diese Website zulassen</translation>
<translation id="3576616784287504635">Hinweis einer in <ph name="SITE" /> eingebetteten Seite</translation>
-<translation id="3581089476000296252">Chrome informiert Sie, wenn diese Seite bereit ist. &lt;a&gt;Abbrechen&lt;/a&gt;</translation>
+<translation id="3581089476000296252">Chrome informiert dich, wenn diese Seite bereit ist. &lt;a&gt;Abbrechen&lt;/a&gt;</translation>
<translation id="3582930987043644930">Namen hinzufügen</translation>
<translation id="3583757800736429874">&amp;Verschieben wiederholen</translation>
<translation id="3584299510153766161">Doppelte Lochung unten</translation>
<translation id="3586931643579894722">Details ausblenden</translation>
<translation id="3587738293690942763">Mitte</translation>
<translation id="3592413004129370115">Italian (Umschlag)</translation>
-<translation id="3595699422137460894">{NUM_DAYS,plural, =0{Sie können Ihre Gruppe jederzeit zurücksetzen. Es dauert ungefähr einen Tag, einer neuen Gruppe beizutreten.}=1{Sie können Ihre Gruppe jederzeit zurücksetzen. Es dauert ungefähr einen Tag, einer neuen Gruppe beizutreten.}other{Sie können Ihre Gruppe jederzeit zurücksetzen. Es dauert {NUM_DAYS} Tage, einer neuen Gruppe beizutreten.}}</translation>
-<translation id="3596012367874587041">App-Einstellungen</translation>
+<translation id="3595699422137460894">{NUM_DAYS,plural, =0{Du kannst deine Gruppe jederzeit zurücksetzen. Es dauert ungefähr einen Tag, einer neuen Gruppe beizutreten.}=1{Du kannst deine Gruppe jederzeit zurücksetzen. Es dauert ungefähr einen Tag, einer neuen Gruppe beizutreten.}other{Du kannst deine Gruppe jederzeit zurücksetzen. Es dauert {NUM_DAYS} Tage, einer neuen Gruppe beizutreten.}}</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">App durch Administrator blockiert</translation>
<translation id="3608932978122581043">Einzugsausrichtung</translation>
<translation id="3611395257124510155">Virtuelle Karte für <ph name="CARD_IDENTIFIER" /></translation>
<translation id="3614103345592970299">Größe 2</translation>
<translation id="361438452008624280">Listeneintrag "<ph name="LANGUAGE_ID" />": Unbekannte oder nicht unterstützte Sprache.</translation>
-<translation id="3614934205542186002"><ph name="RUN_CHROME_SAFETY_CHECK_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücken Sie die Tabulatortaste und dann die Eingabetaste, um den Sicherheitscheck in den Chrome-Einstellungen auszuführen</translation>
-<translation id="3615877443314183785">Geben Sie ein gültiges Ablaufdatum ein</translation>
+<translation id="3614934205542186002"><ph name="RUN_CHROME_SAFETY_CHECK_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücke die Tabulatortaste und dann die Eingabetaste, um den Sicherheitscheck in den Chrome-Einstellungen auszuführen</translation>
+<translation id="3615877443314183785">Gib ein gültiges Ablaufdatum ein</translation>
<translation id="36224234498066874">Browserdaten löschen...</translation>
<translation id="362276910939193118">Gesamtverlauf anzeigen</translation>
-<translation id="3630155396527302611">Falls das Programm schon in der Liste mit erlaubtem Netzwerkzugriff eingetragen ist, entfernen Sie es aus der Liste und fügen Sie es noch einmal hinzu.</translation>
-<translation id="3630699740441428070">Administratoren dieses Geräts haben Ihre Netzwerkverbindung konfiguriert. Dadurch erhalten sie möglicherweise Einblick in Ihren Netzwerkverkehr und können sehen, welche Websites Sie besuchen.</translation>
+<translation id="3630155396527302611">Falls das Programm schon in der Liste mit erlaubtem Netzwerkzugriff eingetragen ist, entferne es aus der Liste und füge es noch einmal hinzu.</translation>
+<translation id="3630699740441428070">Administratoren dieses Geräts haben deine Netzwerkverbindung konfiguriert. Dadurch erhalten sie möglicherweise Einblick in deinen Netzwerkverkehr und können sehen, welche Websites du besuchst.</translation>
<translation id="3631244953324577188">Biometrisches Verfahren</translation>
<translation id="3632503704576938756">Bildschirmfreigabe fortgesetzt</translation>
<translation id="3632892046558972264">Bildschirmfreigabe pausiert</translation>
-<translation id="3633738897356909127">Schaltfläche "Chrome aktualisieren" – drücken Sie die Eingabetaste, um Chrome über die Chrome-Einstellungen zu aktualisieren</translation>
+<translation id="3633738897356909127">Schaltfläche „Chrome aktualisieren“ – drücke die Eingabetaste, um Chrome über die Chrome-Einstellungen zu aktualisieren</translation>
<translation id="3634530185120165534">Fach 5</translation>
-<translation id="3634567936866541746">Sie haben Ihr Passwort gerade auf einer verdächtigen Seite eingegeben. Chrome empfiehlt, Ihre gespeicherten Passwörter zu überprüfen, um Ihre Konten besser zu schützen.</translation>
+<translation id="3634567936866541746">Du hast dein Passwort gerade auf einer verdächtigen Seite eingegeben. Chrome empfiehlt, deine gespeicherten Passwörter zu überprüfen, um deine Konten besser zu schützen.</translation>
<translation id="3637662659967048211">In Google-Konto speichern</translation>
<translation id="3640766068866876100">Index-4x6-Ext</translation>
<translation id="3642638418806704195">Anwendung:</translation>
<translation id="3650584904733503804">Überprüfung erfolgreich</translation>
<translation id="3655241534245626312">Berechtigungseinstellungen aufrufen</translation>
-<translation id="3655670868607891010">Sollte Ihnen diese Meldung häufiger angezeigt werden, sehen Sie sich unsere <ph name="HELP_LINK" /> an.</translation>
+<translation id="3655670868607891010">Sollte dir diese Meldung häufiger angezeigt werden, sieh dir unsere <ph name="HELP_LINK" /> an.</translation>
<translation id="3658742229777143148">Ãœberarbeitung</translation>
<translation id="3664782872746246217">Suchbegriffe:</translation>
<translation id="3671540257457995106">Größenanpassung zulassen?</translation>
<translation id="3675563144891642599">Dritte Rolle</translation>
<translation id="3676592649209844519">Geräte-ID:</translation>
-<translation id="3677008721441257057">Meinten Sie vielleicht &lt;a href="#" id="dont-proceed-link"&gt;<ph name="DOMAIN" />&lt;/a&gt;?</translation>
+<translation id="3677008721441257057">Meintest du vielleicht &lt;a href="#" id="dont-proceed-link"&gt;<ph name="DOMAIN" />&lt;/a&gt;?</translation>
<translation id="3678029195006412963">Anfrage konnte nicht signiert werden</translation>
<translation id="3678529606614285348">Seite in einem neuen Inkognitofenster öffnen (Strg + Umschalttaste + N)</translation>
<translation id="3681007416295224113">Zertifikatinformationen</translation>
<translation id="3701427423622901115">Zurücksetzen bestätigt.</translation>
-<translation id="3704162925118123524">Eventuell müssen Sie die Anmeldeseite des verwendeten Netzwerks aufrufen.</translation>
+<translation id="3704162925118123524">Eventuell musst du die Anmeldeseite des verwendeten Netzwerks aufrufen.</translation>
<translation id="3705189812819839667"><ph name="RESULT_OWNER" /> – <ph name="RESULT_PRODUCT_SOURCE" /></translation>
<translation id="370665806235115550">Wird geladen...</translation>
-<translation id="3709599264800900598">Von Ihnen kopierter Text</translation>
+<translation id="3709599264800900598">Von dir kopierter Text</translation>
<translation id="370972442370243704">„Recherchen“ aktivieren</translation>
<translation id="3711895659073496551">Suspend-Modus</translation>
<translation id="3712624925041724820">Lizenzen aufgebraucht</translation>
+<translation id="3714633008798122362">Web-Kalender</translation>
<translation id="3714780639079136834">Mobile Daten oder WLAN aktivieren</translation>
<translation id="3715597595485130451">WLAN-Verbindung herstellen</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Proxy, Firewall und DNS-Konfiguration prüfen<ph name="END_LINK" /></translation>
<translation id="372429172604983730">Anwendungen, die diesen Fehler verursachen können, sind Antivirensoftware, Firewalls, Webfilter- oder Proxy-Software.</translation>
-<translation id="3727101516080730231"><ph name="CREATE_GOOGLE_SLIDE_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücken Sie die Tabulatortaste und dann die Eingabetaste, um schnell eine neue Präsentation in Google Präsentationen zu erstellen</translation>
+<translation id="3727101516080730231"><ph name="CREATE_GOOGLE_SLIDE_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücke die Tabulatortaste und dann die Eingabetaste, um schnell eine neue Präsentation in Google Präsentationen zu erstellen</translation>
<translation id="373042150751172459">B4 (Umschlag)</translation>
-<translation id="3736520371357197498">Wenn Sie die Sicherheitsrisiken kennen, können Sie <ph name="BEGIN_LINK" />diese unsichere Website aufrufen<ph name="END_LINK" />, bevor die gefährlichen Programme entfernt wurden.</translation>
-<translation id="3738166223076830879">Ihr Browser wird von Ihrem Administrator verwaltet.</translation>
+<translation id="3736520371357197498">Wenn du die Sicherheitsrisiken kennst, kannst du <ph name="BEGIN_LINK" />diese unsichere Website aufrufen<ph name="END_LINK" />, bevor die gefährlichen Programme entfernt wurden.</translation>
+<translation id="3738166223076830879">Dein Browser wird von deinem Administrator verwaltet.</translation>
<translation id="3744111561329211289">Hintergrundsynchronisierung</translation>
-<translation id="3744899669254331632">Sie können <ph name="SITE" /> zurzeit nicht aufrufen, weil die Website verschlüsselte Anmeldedaten gesendet hat, die von Chromium nicht verarbeitet werden können. Netzwerkfehler und Angriffe sind in der Regel nur vorübergehend, sodass die Seite wahrscheinlich später wieder funktioniert.</translation>
-<translation id="3745099705178523657">Nach erfolgter Bestätigung werden die Kartendetails Ihres Google-Kontos an diese Website weitergegeben.</translation>
-<translation id="3748148204939282805">Hacker könnten auf <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> etwa versuchen, Sie zur Installation von Software oder zur Herausgabe von Daten wie Passwörtern, Telefonnummern oder Kreditkartendetails zu bewegen. <ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="3744899669254331632">Du kannst <ph name="SITE" /> zurzeit nicht aufrufen, weil die Website verschlüsselte Anmeldedaten gesendet hat, die von Chromium nicht verarbeitet werden können. Netzwerkfehler und Angriffe sind in der Regel nur vorübergehend, sodass die Seite wahrscheinlich später wieder funktioniert.</translation>
+<translation id="3745099705178523657">Nach erfolgter Bestätigung werden die Kartendetails deines Google-Kontos an diese Website weitergegeben.</translation>
+<translation id="3748148204939282805">Hacker könnten auf <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> etwa versuchen, dich zur Installation von Software oder zur Herausgabe von Daten wie Passwörtern, Telefonnummern oder Kreditkartendetails zu bewegen. <ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="3754210790023674521">Bild im Bild beenden</translation>
<translation id="3759461132968374835">Es liegen keine kürzlich gemeldeten Abstürze vor. Abstürze, die bei deaktivierter Absturzberichtsfunktion aufgetreten sind, werden hier nicht angezeigt.</translation>
<translation id="3760561303380396507">Windows Hello anstelle des CVCs verwenden?</translation>
@@ -873,8 +904,8 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="3761718714832595332">Status ausblenden</translation>
<translation id="3765588406864124894">Ablage 9</translation>
<translation id="3767485424735936570">Die Administratorrichtlinie empfiehlt, keine Inhalte zu kopieren und an dieser Stelle (<ph name="VM_NAME" />) einzufügen</translation>
-<translation id="377451872037045164"><ph name="CREATE_GOOGLE_KEEP_NOTE_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücken Sie die Tabulatortaste und dann die Eingabetaste, um schnell eine neue Notiz in Google Notizen zu erstellen</translation>
-<translation id="3778403066972421603">Möchten Sie diese Karte in Ihrem Google-Konto und auf diesem Gerät speichern?</translation>
+<translation id="377451872037045164"><ph name="CREATE_GOOGLE_KEEP_NOTE_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücke die Tabulatortaste und dann die Eingabetaste, um schnell eine neue Notiz in Google Notizen zu erstellen</translation>
+<translation id="3778403066972421603">Möchtest du diese Karte in deinem Google-Konto und auf diesem Gerät speichern?</translation>
<translation id="3780694243617746492">Ausgabefach</translation>
<translation id="3781428340399460090">Dunkelrosa</translation>
<translation id="3783418713923659662">Mastercard</translation>
@@ -890,15 +921,15 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="3807873520724684969">Schädliche Inhalte blockiert.</translation>
<translation id="3810973564298564668">Verwalten</translation>
<translation id="3816482573645936981">Wert (ersetzt)</translation>
-<translation id="382518646247711829">Falls Sie einen Proxyserver verwenden...</translation>
+<translation id="382518646247711829">Falls du einen Proxyserver verwendest...</translation>
<translation id="3827112369919217609">Absolut</translation>
-<translation id="3827475930221174051">Auf Grundlage Ihrer Aktivitäten mit Bezug zu „<ph name="SEARCH_TERM" />“</translation>
+<translation id="3827475930221174051">Auf Grundlage deiner Aktivitäten mit Bezug zu „<ph name="SEARCH_TERM" />“</translation>
<translation id="3828924085048779000">Eine leere Passphrase ist nicht zulässig.</translation>
<translation id="3831065134033923230">Gespeicherte Passwörter prüfen</translation>
-<translation id="3831915413245941253"><ph name="ENROLLMENT_DOMAIN" /> hat Erweiterungen für zusätzliche Funktionen installiert. Diese Erweiterungen können auf einige Ihrer Daten zugreifen.</translation>
+<translation id="3831915413245941253"><ph name="ENROLLMENT_DOMAIN" /> hat Erweiterungen für zusätzliche Funktionen installiert. Diese Erweiterungen können auf einige deiner Daten zugreifen.</translation>
<translation id="3832522519263485449">Mehrfache Lochung links</translation>
<translation id="3835233591525155343">Meine Gerätenutzung</translation>
-<translation id="3848487483475744267"><ph name="CREATE_GOOGLE_DOC_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücken Sie die Tabulatortaste und dann die Eingabetaste, um schnell ein neues Google-Dokument zu erstellen</translation>
+<translation id="3848487483475744267"><ph name="CREATE_GOOGLE_DOC_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücke die Tabulatortaste und dann die Eingabetaste, um schnell ein neues Google-Dokument zu erstellen</translation>
<translation id="385051799172605136">Zurück</translation>
<translation id="3858027520442213535">Datum und Uhrzeit aktualisieren</translation>
<translation id="3858860766373142691">Name</translation>
@@ -913,13 +944,14 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="3901925938762663762">Die Karte ist abgelaufen.</translation>
<translation id="3906600011954732550">B5-Extra</translation>
<translation id="3906954721959377182">Tablet</translation>
-<translation id="3909477809443608991"><ph name="URL" /> möchte geschützten Inhalt abspielen. Die Identität Ihres Geräts wird von Google überprüft, weshalb möglicherweise ein Zugriff durch diese Website erfolgt.</translation>
+<translation id="3909477809443608991"><ph name="URL" /> möchte geschützten Inhalt abspielen. Die Identität deines Geräts wird von Google überprüft, weshalb möglicherweise ein Zugriff durch diese Website erfolgt.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> – <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">Ablehnen</translation>
<translation id="3939773374150895049">WebAuthn anstelle des CVCs verwenden?</translation>
<translation id="3946209740501886391">Auf dieser Website immer fragen</translation>
<translation id="3947595700203588284">Darf nachfragen, wenn sie eine Verbindung mit MIDI-Geräten herstellen möchte</translation>
-<translation id="3949571496842715403">Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat gibt keine alternativen Namen an. Mögliche Gründe sind eine fehlerhafte Konfiguration oder ein Angreifer, der Ihre Verbindung abfängt.</translation>
-<translation id="3949601375789751990">Hier wird Ihr Browserverlauf angezeigt</translation>
+<translation id="3949571496842715403">Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat gibt keine alternativen Namen an. Mögliche Gründe sind eine fehlerhafte Konfiguration oder ein Angreifer, der deine Verbindung abfängt.</translation>
+<translation id="3949601375789751990">Hier wird dein Browserverlauf angezeigt</translation>
<translation id="3949790930165450333"><ph name="DEVICE_NAME" /> (<ph name="DEVICE_ID" />)</translation>
<translation id="3949870428812919180">Keine gespeicherten Zahlungsmethoden</translation>
<translation id="3950820424414687140">Anmelden</translation>
@@ -928,39 +960,40 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="3963721102035795474">Lesemodus</translation>
<translation id="3963837677003247395">Manuell fortfahren?</translation>
<translation id="3964661563329879394">{COUNT,plural, =0{Keine}=1{Von 1 Website }other{Von # Websites }}</translation>
-<translation id="3969052498612555048">Sie können Ihren Code nicht finden? <ph name="BEGIN_LINK" />Neuen Code anfordern<ph name="END_LINK" /></translation>
+<translation id="3969052498612555048">Du kannst deinen Code nicht finden? <ph name="BEGIN_LINK" />Neuen Code anfordern<ph name="END_LINK" /></translation>
<translation id="397105322502079400">Wird berechnet...</translation>
<translation id="3973234410852337861"><ph name="HOST_NAME" /> ist gesperrt</translation>
<translation id="3986705137476756801">Automatische Untertitel vorerst deaktivieren</translation>
<translation id="3987940399970879459">Weniger als 1 MB</translation>
<translation id="3990250421422698716">Jog-Versatz</translation>
<translation id="3996311196211510766">Die Website <ph name="ORIGIN" /> verlangt, dass auf alle an sie gerichteten Anfragen eine Ursprungsrichtlinie angewendet wird. Diese Richtlinie kann jedoch momentan nicht angewandt werden.</translation>
+<translation id="4009243425692662128">Die Inhalt der gedruckten Seiten wird zur Analyse an Google Cloud oder Drittanbieter gesendet. Er wird beispielsweise auf sensible Daten geprüft.</translation>
<translation id="4010758435855888356">Zugriff auf Speicher erlauben?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{PDF-Dokument mit {COUNT} Seite}other{PDF-Dokument mit {COUNT} Seiten}}</translation>
-<translation id="4023431997072828269">Dieses Formular wird über eine Verbindung gesendet, die nicht vollständig sicher ist. Hierdurch können Ihre Informationen für andere sichtbar sein.</translation>
-<translation id="4025913568718019429">Schaltfläche „Datenschutzeinstellungen des Google-Kontos verwalten“ – drücken Sie die Eingabetaste, um die Datenschutzeinstellungen Ihres Google-Kontos aufzurufen</translation>
+<translation id="4023431997072828269">Dieses Formular wird über eine Verbindung gesendet, die nicht vollständig sicher ist. Hierdurch können deine Informationen für andere sichtbar sein.</translation>
+<translation id="4025913568718019429">Schaltfläche „Datenschutzeinstellungen des Google-Kontos verwalten“ – drücke die Eingabetaste, um die Datenschutzeinstellungen deines Google-Kontos aufzurufen</translation>
<translation id="4030383055268325496">&amp;Hinzufügen rückgängig machen</translation>
<translation id="4056223980640387499">Sepia</translation>
<translation id="4058922952496707368">Schlüssel "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4067263367174615723">C1 (Umschlag)</translation>
<translation id="4067947977115446013">Gültige Adresse hinzufügen</translation>
<translation id="4072193657607981494">Richtlinien werden geladen</translation>
-<translation id="4072486802667267160">Bei der Verarbeitung Ihrer Bestellung ist ein Fehler aufgetreten. Bitte versuchen Sie es noch einmal.</translation>
+<translation id="4072486802667267160">Bei der Verarbeitung deiner Bestellung ist ein Fehler aufgetreten. Bitte versuche es noch einmal.</translation>
<translation id="4073797364926776829">Karte ansehen</translation>
<translation id="4075732493274867456">Client und Server unterstützen keine gemeinsame SSL-Protokollversion oder Verschlüsselungssammlung.</translation>
<translation id="4075941231477579656">Touch ID</translation>
<translation id="4079302484614802869">Die Proxy-Konfiguration ist auf die Verwendung einer PAC-Skript-URL und nicht die von festen Proxyservern eingestellt.</translation>
<translation id="4082393374666368382">Einstellungen – Verwaltung</translation>
-<translation id="4084120443451129199">Suchmodus, drücken Sie die Eingabetaste, um nach "<ph name="KEYWORD_SUFFIX" />" zu suchen</translation>
-<translation id="4087296516249690906">Termin erstellen – drücken Sie die Eingabetaste, um schnell einen neuen Termin in Google Kalender zu erstellen</translation>
+<translation id="4084120443451129199">Suchmodus, drücke die Eingabetaste, um nach "<ph name="KEYWORD_SUFFIX" />" zu suchen</translation>
+<translation id="4087296516249690906">Termin erstellen – drücke die Eingabetaste, um schnell einen neuen Termin in Google Kalender zu erstellen</translation>
<translation id="4088981014127559358">Seite 1 – Y-Verschiebung des Bilds</translation>
<translation id="4089152113577680600">Fach 14</translation>
<translation id="4098354747657067197">Bei der aufgerufenen Website besteht Phishing-Verdacht!</translation>
-<translation id="4099048595830172239">Gemäß Administratorrichtlinie wird nicht empfohlen, Ihren Bildschirm mit <ph name="APPLICATION_TITLE" /> zu teilen, wenn vertrauliche Inhalte zu sehen sind:</translation>
-<translation id="4099391883283080991"><ph name="CUSTOMIZE_CHROME_FONTS_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücken Sie die Tabulatortaste und dann die Eingabetaste, um Schriftgrößen und Schriftarten in Chrome anzupassen</translation>
+<translation id="4099048595830172239">Gemäß Administratorrichtlinie wird nicht empfohlen, deinen Bildschirm mit <ph name="APPLICATION_TITLE" /> zu teilen, wenn vertrauliche Inhalte zu sehen sind:</translation>
+<translation id="4099391883283080991"><ph name="CUSTOMIZE_CHROME_FONTS_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücke die Tabulatortaste und dann die Eingabetaste, um Schriftgrößen und Schriftarten in Chrome anzupassen</translation>
<translation id="4101413244023615925">Text und Grafik</translation>
<translation id="4103249731201008433">Seriennummer des Geräts ist ungültig.</translation>
-<translation id="4106133539597032659">Schaltfläche „Website erstellen“ – drücken Sie die Eingabetaste, um schnell eine neue Website in Google Sites zu erstellen</translation>
+<translation id="4106133539597032659">Schaltfläche „Website erstellen“ – drücke die Eingabetaste, um schnell eine neue Website in Google Sites zu erstellen</translation>
<translation id="4110652170750985508">Zahlung überprüfen</translation>
<translation id="4112140312785995938">Zurück springen</translation>
<translation id="4114146879518089587">Weiter zur Website</translation>
@@ -969,7 +1002,7 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="4117700440116928470">Richtlinienbereich wird nicht unterstützt.</translation>
<translation id="4121428309786185360">Gültig bis</translation>
<translation id="4123572138124678573">Dreifache Lochung unten</translation>
-<translation id="4127575959421463246">Suchen Sie die ChromeOS-Flags? Aufrufen</translation>
+<translation id="4127575959421463246">Suchst du die ChromeOS-Flags? Besuche</translation>
<translation id="4129401438321186435">{COUNT,plural, =1{1 weiterer}other{# weitere}}</translation>
<translation id="4130226655945681476">Netzwerkkabel, Modem und Router prüfen</translation>
<translation id="4134123981501319574">Dokument erstellen</translation>
@@ -988,56 +1021,57 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{<ph name="ITEM_COUNT" /> weiteres Element}other{<ph name="ITEM_COUNT" /> weitere Elemente}}</translation>
<translation id="4176463684765177261">Deaktiviert</translation>
<translation id="4179515394835346607"><ph name="ROW_NAME" />: <ph name="ROW_CONTENT" /></translation>
-<translation id="4194250254487269611">Ihre Karte kann momentan nicht gespeichert werden</translation>
+<translation id="4194250254487269611">Deine Karte kann momentan nicht gespeichert werden</translation>
<translation id="4196861286325780578">&amp;Verschieben wiederholen</translation>
<translation id="4202554117186904723">Fünfte Rolle</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />Firewall und Antivirenkonfiguration prüfen<ph name="END_LINK" /></translation>
<translation id="4209092469652827314">Groß</translation>
-<translation id="4209166701302774460">Der Server <ph name="ORIGIN" />, zu dem Sie gehen, verlangt, dass auf alle an ihn gerichteten Anfragen eine Ursprungsrichtlinie angewendet wird. Er hat jedoch keine Richtlinie übergeben, was den Browser daran hindert, Ihre Anfrage für <ph name="SITE" /> auszuführen. Ursprungsrichtlinien können von Websitebetreibern verwendet werden, um die Sicherheit und andere Eigenschaften einer Website zu konfigurieren.</translation>
-<translation id="4210602799576081649">Bestätigungscode abgelaufen, fordern Sie einen neuen an</translation>
+<translation id="4209166701302774460">Der Server <ph name="ORIGIN" />, zu dem du gehst, verlangt, dass auf alle an ihn gerichteten Anfragen eine Ursprungsrichtlinie angewendet wird. Er hat jedoch keine Richtlinie übergeben, was den Browser daran hindert, deine Anfrage für <ph name="SITE" /> auszuführen. Ursprungsrichtlinien können von Websitebetreibern verwendet werden, um die Sicherheit und andere Eigenschaften einer Website zu konfigurieren.</translation>
+<translation id="4210602799576081649">Bestätigungscode abgelaufen, fordere einen neuen an</translation>
<translation id="421066178035138955">Virtual-Reality-Geräte und ‑Daten verwenden</translation>
<translation id="4214357935346142455">Profil der Anmeldeseite</translation>
<translation id="4215751373031079683">7x9 (Umschlag)</translation>
<translation id="4220128509585149162">Abstürze</translation>
-<translation id="422022731706691852">Hacker könnten auf <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> versuchen, Sie zur Installation von Programmen zu bewegen, die sich nachteilig auf Ihre Browsernutzung auswirken. Dabei kann zum Beispiel Ihre Startseite geändert werden oder es erscheint zusätzliche Werbung auf von Ihnen besuchten Websites.<ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="422022731706691852">Hacker könnten auf <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> versuchen, dich zur Installation von Programmen zu bewegen, die sich nachteilig auf deine Browsernutzung auswirken. Dabei kann zum Beispiel deine Startseite geändert werden oder es erscheint zusätzliche Werbung auf von dir besuchten Websites.<ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="4221630205957821124">&lt;h4&gt;Schritt 1: Beim Portal anmelden&lt;/h4&gt;
- &lt;p&gt;An manchen Orten wie in Cafés oder auf Flughäfen ist in WLANs eine Anmeldung erforderlich. Um zur Anmeldeseite zu gelangen, besuchen Sie eine Seite, die mit &lt;code&gt;http://&lt;/code&gt; beginnt.&lt;/p&gt;
+ &lt;p&gt;An manchen Orten wie in Cafés oder auf Flughäfen ist in WLANs eine Anmeldung erforderlich. Um zur Anmeldeseite zu gelangen, besuche eine Seite, die mit &lt;code&gt;http://&lt;/code&gt; beginnt.&lt;/p&gt;
&lt;ol&gt;
- &lt;li&gt;Rufen Sie eine beliebige Website auf, deren URL mit &lt;code&gt;http://&lt;/code&gt; beginnt, wie beispielsweise &lt;a href="http://example.com" target="_blank"&gt;http://example.com&lt;/a&gt;.&lt;/li&gt;
- &lt;li&gt;Die Anmeldeseite wird geöffnet. Melden Sie sich dort an, um das Internet zu nutzen.&lt;/li&gt;
+ &lt;li&gt;Rufe eine beliebige Website auf, deren URL mit &lt;code&gt;http://&lt;/code&gt; beginnt, wie beispielsweise &lt;a href="http://example.com" target="_blank"&gt;http://example.com&lt;/a&gt;.&lt;/li&gt;
+ &lt;li&gt;Die Anmeldeseite wird geöffnet. Melde dich dort an, um das Internet zu nutzen.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;Schritt 2: Seite im Inkognitomodus öffnen (nur Computer)&lt;/h4&gt;
- &lt;p&gt;Öffnen Sie die besuchte Seite in einem Inkognitofenster.&lt;/p&gt;
- &lt;p&gt;Wenn die Seite geöffnet wird, funktioniert eine Chrome-Erweiterung nicht richtig. Deaktivieren Sie die Erweiterung, um den Fehler zu beheben.&lt;/p&gt;
+ &lt;p&gt;Öffne die besuchte Seite in einem Inkognitofenster.&lt;/p&gt;
+ &lt;p&gt;Wenn die Seite geöffnet wird, funktioniert eine Chrome-Erweiterung nicht richtig. Deaktiviere die Erweiterung, um den Fehler zu beheben.&lt;/p&gt;
&lt;h4&gt;Schritt 3: Betriebssystem aktualisieren&lt;/h4&gt;
- &lt;p&gt;Bringen Sie Ihr Gerät auf den aktuellen Stand.&lt;/p&gt;
+ &lt;p&gt;Bringe dein Gerät auf den aktuellen Stand.&lt;/p&gt;
&lt;h4&gt;Schritt 4: Antivirenprogramm vorübergehend deaktivieren&lt;/h4&gt;
- &lt;p&gt;Diese Fehlermeldung wird angezeigt, wenn Sie eine Antivirensoftware mit "HTTPS-Schutz" oder "HTTPS-Scanning" verwenden, die die Sicherheitsfunktionen von Chrome beeinträchtigt.&lt;/p&gt;
- &lt;p&gt;Deaktivieren Sie die Antivirensoftware, um das Problem zu beheben. Wenn die Seite danach funktioniert, deaktivieren Sie diese Software immer dann, wenn Sie sichere Websites besuchen.&lt;/p&gt;
- &lt;p&gt;Vergessen Sie nicht, Ihr Antivirenprogramm danach wieder zu aktivieren.&lt;/p&gt;
+ &lt;p&gt;Diese Fehlermeldung wird angezeigt, wenn du eine Antivirensoftware mit „HTTPS-Schutz“ oder „HTTPS-Scanning“ verwendest, die die Sicherheitsfunktionen von Chrome beeinträchtigt.&lt;/p&gt;
+ &lt;p&gt;Deaktiviere die Antivirensoftware, um das Problem zu beheben. Wenn die Seite danach funktioniert, deaktiviere diese Software immer dann, wenn du sichere Websites besuchst.&lt;/p&gt;
+ &lt;p&gt;Vergiss nicht, dein Antivirenprogramm danach wieder zu aktivieren.&lt;/p&gt;
&lt;h4&gt;Schritt 5: Weitere Hilfe erhalten&lt;/h4&gt;
- &lt;p&gt;Wenden Sie sich an den Websiteinhaber, wenn der Fehler noch immer angezeigt wird.&lt;/p&gt;</translation>
-<translation id="4226937834893929579"><ph name="BEGIN_LINK" />Versuchen Sie, die Netzwerkdiagnose auszuführen.<ph name="END_LINK" /></translation>
+ &lt;p&gt;Wende dich an den Websiteinhaber, wenn der Fehler noch immer angezeigt wird.&lt;/p&gt;</translation>
+<translation id="4226937834893929579"><ph name="BEGIN_LINK" />Versuche, die Netzwerkdiagnose auszuführen.<ph name="END_LINK" /></translation>
<translation id="4230204356098880324">Darf nachfragen, wenn sie meine Kamera verwenden und bewegen möchte</translation>
<translation id="4234495348042597185"><ph name="BEGIN_LINK" />Weiter zu <ph name="SITE" /><ph name="END_LINK" /></translation>
<translation id="4235360514405112390">Gültig</translation>
<translation id="4250431568374086873">Die Verbindung zu dieser Website ist nicht uneingeschränkt sicher</translation>
<translation id="4250680216510889253">Nein</translation>
<translation id="4253168017788158739">Notiz</translation>
-<translation id="425582637250725228">Ihre Änderungen werden eventuell nicht gespeichert.</translation>
+<translation id="425582637250725228">Deine Änderungen werden eventuell nicht gespeichert.</translation>
+<translation id="425869179292622354">Möchtest du deine Karte durch eine virtuelle Karte besser schützen?</translation>
<translation id="4258748452823770588">Fehlerhafte Signatur</translation>
<translation id="4261046003697461417">Geschützte Dokumente können nicht mit Anmerkungen versehen werden</translation>
-<translation id="4265872034478892965">Von Ihrem Administrator zugelassen</translation>
+<translation id="4265872034478892965">Von deinem Administrator zugelassen</translation>
<translation id="4270541775497538019">Stapelfach 6</translation>
<translation id="4275830172053184480">Gerät neu starten</translation>
<translation id="4277028893293644418">Passwort zurücksetzen</translation>
<translation id="4278390842282768270">Zugelassen</translation>
-<translation id="428639260510061158">{NUM_CARDS,plural, =1{Diese Karte wurde in Ihrem Google-Konto gespeichert}other{Diese Karten wurden in Ihrem Google-Konto gespeichert}}</translation>
+<translation id="428639260510061158">{NUM_CARDS,plural, =1{Diese Karte wurde in deinem Google-Konto gespeichert}other{Diese Karten wurden in deinem Google-Konto gespeichert}}</translation>
<translation id="4287885627794386150">Testversion möglich, aber nicht aktiv</translation>
<translation id="4297502707443874121">Miniaturansicht für Seite <ph name="THUMBNAIL_PAGE" /></translation>
<translation id="42981349822642051">Maximieren</translation>
<translation id="4300675098767811073">Mehrfache Lochung rechts</translation>
-<translation id="4302514097724775343">Tippen Sie auf den Dino, um die Wiedergabe zu starten</translation>
+<translation id="4302514097724775343">Tippe auf den Dino, um die Wiedergabe zu starten</translation>
<translation id="4302965934281694568">Chou3 (Umschlag)</translation>
<translation id="4305666528087210886">Zugriff auf die Datei nicht möglich</translation>
<translation id="4306529830550717874">Adresse speichern?</translation>
@@ -1049,11 +1083,11 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="4318566738941496689">Gerätename und Netzwerkadresse</translation>
<translation id="4325600325087822253">Fach 17</translation>
<translation id="4325863107915753736">Der Artikel wurde nicht gefunden.</translation>
-<translation id="4326324639298822553">Prüfen Sie Ihr Ablaufdatum und versuchen Sie es dann erneut</translation>
+<translation id="4326324639298822553">Prüfe das Ablaufdatum und versuche es dann erneut</translation>
<translation id="4329871760342656885">Fehler beim Parsen der Richtlinie: <ph name="ERROR" /></translation>
<translation id="4331519897422864041">Stapelfach 5</translation>
<translation id="4331708818696583467">Nicht sicher</translation>
-<translation id="4340575312453649552">Diese Werbeanzeige erfordert auf Ihrem Gerät zu viele Ressourcen. Darum hat Chrome sie entfernt.</translation>
+<translation id="4340575312453649552">Diese Werbeanzeige erfordert auf deinem Gerät zu viele Ressourcen. Darum hat Chrome sie entfernt.</translation>
<translation id="4340982228985273705">Dieser Computer wird nicht als von einem Unternehmen verwaltet erkannt, sodass nur Erweiterungen, die im Chrome Web Store gehostet sind, automatisch durch die Richtlinie installiert werden können. Die Update-URL des Chrome Web Store lautet "<ph name="CWS_UPDATE_URL" />".</translation>
<translation id="4346197816712207223">Akzeptierte Kreditkarten</translation>
<translation id="4346833872170306413">Roc-16K</translation>
@@ -1062,15 +1096,15 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="4350629523305688469">Multifunktionsfach</translation>
<translation id="4351060348582610152"><ph name="ORIGIN" /> möchte nach Bluetooth-Geräten in der Nähe suchen. Die folgenden Geräte wurden gefunden:</translation>
<translation id="4351175281479794167">Bestätigungscode eingeben</translation>
-<translation id="4356973930735388585">Unbefugte Dritte auf dieser Website versuchen unter Umständen, gefährliche Programme auf Ihrem Computer zu installieren, um Ihre Daten zu stehlen oder zu löschen, zum Beispiel Fotos, Passwörter, Nachrichten und Kreditkartendaten.</translation>
-<translation id="4358059973562876591">Die von Ihnen angegebenen Vorlagen können wegen eines Fehlers bei der Richtlinie "DnsOverHttpsMode" nicht angewendet werden.</translation>
+<translation id="4356973930735388585">Unbefugte Dritte auf dieser Website versuchen unter Umständen, gefährliche Programme auf deinem Computer zu installieren, um deine Daten zu stehlen oder zu löschen, zum Beispiel Fotos, Passwörter, Nachrichten und Kreditkartendaten.</translation>
+<translation id="4358059973562876591">Die von dir angegebenen Vorlagen können wegen eines Fehlers bei der Richtlinie "DnsOverHttpsMode" nicht angewendet werden.</translation>
<translation id="4358461427845829800">Zahlungsmethoden verwalten…</translation>
-<translation id="4359160567981085931">Sie haben Ihr Passwort gerade auf einer verdächtigen Website eingegeben. Chrome kann Ihnen helfen. Wenn Sie Ihr Passwort ändern und Google darüber informieren möchten, dass Ihr Konto gefährdet sein könnte, klicken Sie auf "Konto schützen".</translation>
+<translation id="4359160567981085931">Du hast dein Passwort gerade auf einer verdächtigen Website eingegeben. Chrome kann dir helfen. Wenn du dein Passwort ändern und Google darüber informieren möchtest, dass dein Konto gefährdet sein könnte, klicke auf "Konto schützen".</translation>
<translation id="4367563149485757821">Number-12 (Umschlag)</translation>
<translation id="437040971055499437">Sicherheitshinweis aufgetreten</translation>
<translation id="4372516964750095882">Fanfold-Us</translation>
<translation id="4372948949327679948">Erwarteter <ph name="VALUE_TYPE" />-Wert</translation>
-<translation id="4377125064752653719">Sie haben versucht, auf <ph name="DOMAIN" /> zuzugreifen, das vom Server übermittelte Zertifikat wurde jedoch vom entsprechenden Aussteller widerrufen. Das bedeutet, dass die vom Server übermittelten Sicherheitsinformationen nicht vertrauenswürdig sind. Möglicherweise kommunizieren Sie mit einem Hacker.</translation>
+<translation id="4377125064752653719">Du hast versucht, auf <ph name="DOMAIN" /> zuzugreifen, das vom Server übermittelte Zertifikat wurde jedoch vom entsprechenden Aussteller widerrufen. Das bedeutet, dass die vom Server übermittelten Sicherheitsinformationen nicht vertrauenswürdig sind. Möglicherweise kommunizierst du mit einem Hacker.</translation>
<translation id="4378154925671717803">Telefon</translation>
<translation id="4390472908992056574">Brim</translation>
<translation id="4406883609789734330">Automatische Untertitel</translation>
@@ -1079,20 +1113,21 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="4408413947728134509">Cookies <ph name="NUM_COOKIES" /></translation>
<translation id="4414515549596849729">Cookies und Websitedaten</translation>
<translation id="4415426530740016218">Abholadresse</translation>
-<translation id="4424024547088906515">Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat wird von Chrome als nicht vertrauenswürdig eingestuft. Mögliche Gründe sind eine fehlerhafte Konfiguration oder ein Angreifer, der Ihre Verbindung abfängt.</translation>
+<translation id="4424024547088906515">Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat wird von Chrome als nicht vertrauenswürdig eingestuft. Mögliche Gründe sind eine fehlerhafte Konfiguration oder ein Angreifer, der deine Verbindung abfängt.</translation>
<translation id="443121186588148776">Serieller Port</translation>
-<translation id="4432688616882109544"><ph name="HOST_NAME" /> hat Ihr Anmeldezertifikat nicht akzeptiert oder es wurde keines bereitgestellt.</translation>
+<translation id="4432688616882109544"><ph name="HOST_NAME" /> hat dein Anmeldezertifikat nicht akzeptiert oder es wurde keines bereitgestellt.</translation>
<translation id="4432792777822557199">Seiten auf <ph name="SOURCE_LANGUAGE" /> werden ab jetzt auf <ph name="TARGET_LANGUAGE" /> übersetzt</translation>
<translation id="4433642172056592619">Ignoriert, weil der Nutzer nicht mit der Maschinenverwaltung verknüpft ist oder die Maschine nicht verwaltet wird.</translation>
<translation id="4434045419905280838">Pop-ups und Weiterleitungen</translation>
<translation id="4435702339979719576">Postkarte)</translation>
<translation id="443673843213245140">Die Proxy-Nutzung ist deaktiviert, es ist jedoch eine explizite Proxy-Konfiguration festgelegt.</translation>
+<translation id="4441832193888514600">Ignoriert, da die Richtlinie nur als Cloud-Nutzerrichtlinie festgelegt werden kann.</translation>
<translation id="4450893287417543264">Nicht mehr anzeigen</translation>
<translation id="4451135742916150903">Darf nachfragen, wenn sie eine Verbindung mit HID-Geräten herstellen möchte</translation>
-<translation id="4452328064229197696">Das Passwort, das Sie gerade verwendet haben, wurde in einer Datenpanne gefunden. Zum besseren Schutz Ihrer Konten empfiehlt der Passwortmanager von Google, Ihre gespeicherten Passwörter zu prüfen.</translation>
+<translation id="4452328064229197696">Das Passwort, das du gerade verwendet hast, wurde in einer Datenpanne gefunden. Zum besseren Schutz deiner Konten empfiehlt der Passwortmanager von Google, deine gespeicherten Passwörter zu prüfen.</translation>
<translation id="4455222631300069614">Passwort jetzt ändern</translation>
-<translation id="4460315069258617173">Zugelassen, bis Sie Tabs dieser Website schließen</translation>
-<translation id="4464826014807964867">Websites mit Informationen Ihrer Organisation</translation>
+<translation id="4460315069258617173">Zugelassen, bis du Tabs dieser Website schließt</translation>
+<translation id="4464826014807964867">Websites mit Informationen deiner Organisation</translation>
<translation id="447665707681730621"><ph name="BUBBLE_MESSAGE" />. <ph name="LEARN_MORE_TEXT" /></translation>
<translation id="4476953670630786061">Dieses Formular ist nicht sicher. Die Funktion „Automatisches Ausfüllen“ wurde deaktiviert.</translation>
<translation id="4477350412780666475">Nächster Titel</translation>
@@ -1108,10 +1143,10 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="4506599922270137252">Kontakt mit dem Systemadministrator aufnehmen</translation>
<translation id="450710068430902550">Datenfreigabe an Administrator</translation>
<translation id="4508814173490746936">Touch ID konnte nicht verwendet werden</translation>
-<translation id="4509074745930862522"><ph name="TRANSLATE_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücken Sie die Tabulatortaste und dann die Eingabetaste, um diese Seite mit Google Übersetzer übersetzen zu lassen</translation>
+<translation id="4509074745930862522"><ph name="TRANSLATE_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücke die Tabulatortaste und dann die Eingabetaste, um diese Seite mit Google Übersetzer übersetzen zu lassen</translation>
<translation id="4510487217173779431">Chou4 (Umschlag)</translation>
<translation id="4514308731478712184">„Recherchen“ deaktivieren</translation>
-<translation id="4515275063822566619">Karten und Adressen stammen aus Chrome und aus Ihrem Google-Konto (<ph name="ACCOUNT_EMAIL" />). Sie können sie in den <ph name="BEGIN_LINK" />Einstellungen<ph name="END_LINK" /> verwalten.</translation>
+<translation id="4515275063822566619">Karten und Adressen stammen aus Chrome und aus deinem Google-Konto (<ph name="ACCOUNT_EMAIL" />). Du kannst sie in den <ph name="BEGIN_LINK" />Einstellungen<ph name="END_LINK" /> verwalten.</translation>
<translation id="4517607026994743406">Comm-10 (Umschlag)</translation>
<translation id="4521157617044179198"><ph name="WIDTH" /> × <ph name="HEIGHT" /> mm (<ph name="ORIENTATION" />)</translation>
<translation id="4521916730539354575">Linkes Fach</translation>
@@ -1122,36 +1157,37 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="4541810033354695636">Augmented Reality</translation>
<translation id="4542971377163063093">Fach 6</translation>
<translation id="455113658016510503">A9</translation>
-<translation id="4558551763791394412">Deaktivieren Sie Ihre Erweiterungen.</translation>
+<translation id="4558551763791394412">Deaktiviere deine Erweiterungen.</translation>
<translation id="4559332380232738994">10x11</translation>
-<translation id="4567686777917670400">Ihr Administrator kann die Browsereinstellungen per Remotezugriff ändern. Aktivitäten auf diesem Gerät können auch außerhalb von Chromium verwaltet werden. <ph name="BEGIN_LINK" />Weitere Informationen<ph name="END_LINK" /></translation>
+<translation id="4567686777917670400">Dein Administrator kann die Browsereinstellungen per Remotezugriff ändern. Aktivitäten auf diesem Gerät können auch außerhalb von Chromium verwaltet werden. <ph name="BEGIN_LINK" />Weitere Informationen<ph name="END_LINK" /></translation>
<translation id="457875822857220463">Lieferung</translation>
<translation id="4579056131138995126">Personal (Umschlag)</translation>
<translation id="4582204425268416675">Karte entfernen</translation>
<translation id="4587425331216688090">Adresse aus Chrome entfernen?</translation>
<translation id="459089498662672729">Die Administratorrichtlinie empfiehlt, keine Inhalte aus <ph name="ORIGIN_NAME" /> an dieser Stelle einzufügen</translation>
-<translation id="4592951414987517459">Ihre Verbindung zu <ph name="DOMAIN" /> ist mit einer modernen Codier-Suite verschlüsselt.</translation>
+<translation id="4592951414987517459">Deine Verbindung zu <ph name="DOMAIN" /> ist mit einer modernen Codier-Suite verschlüsselt.</translation>
<translation id="4594403342090139922">&amp;Löschen rückgängig machen</translation>
<translation id="4597348597567598915">Größe 8</translation>
<translation id="4598556348158889687">Speicherplatzverwaltung</translation>
<translation id="4600854749408232102">C6/C5 (Umschlag)</translation>
<translation id="4606870351894164739">Wirkungsvoll</translation>
-<translation id="4607603470419975064">Schaltfläche „Chrome-Tipps aufrufen“ – drücken Sie die Eingabetaste, um mehr über die Funktionen von Chrome zu erfahren</translation>
+<translation id="4607603470419975064">Schaltfläche „Chrome-Tipps aufrufen“ – drücke die Eingabetaste, um mehr über die Funktionen von Chrome zu erfahren</translation>
<translation id="4607608436550361748">Chrome-Tipps aufrufen</translation>
<translation id="4627675673814409125">Diese Richtlinie kann nicht auf der Chrome-Profilebene festgelegt werden und wird ignoriert.</translation>
<translation id="4628948037717959914">Foto</translation>
<translation id="4631649115723685955">Cashback zugeordnet</translation>
<translation id="4636930964841734540">Info</translation>
+<translation id="4638670630777875591">Inkognitomodus in Chromium</translation>
<translation id="464342062220857295">Suchfunktionen</translation>
<translation id="4644670975240021822">Umgekehrte Reihenfolge mit der Vorderseite nach unten</translation>
<translation id="4646534391647090355">Jetzt aufrufen</translation>
<translation id="4652266463001779298">Nicht zugelassen</translation>
<translation id="4658638640878098064">Heftklammer oben links</translation>
-<translation id="4660119392514473465">Sie können jetzt privat surfen. Andere Personen, die dieses Gerät verwenden, können Ihre Aktivität nicht sehen. Downloads, Lesezeichen und Webseiten auf Ihrer Leseliste werden jedoch gespeichert.</translation>
+<translation id="4660119392514473465">Du kannst jetzt privat surfen. Andere Personen, die dieses Gerät verwenden, können deine Aktivität nicht sehen. Downloads, Lesezeichen und Webseiten auf deiner Leseliste werden jedoch gespeichert.</translation>
<translation id="4668929960204016307">,</translation>
<translation id="4670064810192446073">Virtual Reality</translation>
<translation id="4673460618347856347">Dino-Spiel, spielen</translation>
-<translation id="467662567472608290">Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat enthält Fehler. Mögliche Gründe sind eine fehlerhafte Konfiguration oder ein Angreifer, der Ihre Verbindung abfängt.</translation>
+<translation id="467662567472608290">Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat enthält Fehler. Mögliche Gründe sind eine fehlerhafte Konfiguration oder ein Angreifer, der deine Verbindung abfängt.</translation>
<translation id="4677585247300749148"><ph name="URL" /> möchte auf Bedienungshilfen reagieren</translation>
<translation id="467809019005607715">Google Präsentationen</translation>
<translation id="468314109939257734">Virtuelle Kartennummer anzeigen</translation>
@@ -1162,12 +1198,13 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="4708268264240856090">Die Verbindung wurde unterbrochen</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Windows-Netzwerkdiagnose ausführen<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426">Passwort für <ph name="USERNAME" /></translation>
<translation id="4724144314178270921">Darf nachfragen, wenn sie auf Text und Bilder in meiner Zwischenablage zugreifen möchte</translation>
<translation id="4726672564094551039">Richtlinien neu laden</translation>
<translation id="4728558894243024398">Plattform</translation>
-<translation id="4731638775147756694">Diese App wurde von Ihrem Administrator blockiert</translation>
+<translation id="4731638775147756694">Diese App wurde von deinem Administrator blockiert</translation>
<translation id="4731967714531604179">Prc2 (Umschlag)</translation>
-<translation id="4733082559415072992"><ph name="URL" /> möchte den Standort Ihres Geräts nutzen</translation>
+<translation id="4733082559415072992"><ph name="URL" /> möchte den Standort deines Geräts nutzen</translation>
<translation id="4736825316280949806">Chromium neu starten</translation>
<translation id="4736934858538408121">Virtuelle Karte</translation>
<translation id="473775607612524610">Aktualisieren</translation>
@@ -1175,14 +1212,15 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="4742407542027196863">Passwörter verwalten…</translation>
<translation id="4744514002166662487">Präsentation erstellen</translation>
<translation id="4744603770635761495">Programmdateipfad</translation>
-<translation id="4749011317274908093">Sie befinden sich jetzt im Inkognitomodus</translation>
-<translation id="4750917950439032686">Ihre Daten wie Passwörter oder Kreditkartennummern sind geschützt, wenn Sie sie an diese Website senden.</translation>
+<translation id="4749011317274908093">Du befindest dich jetzt im Inkognitomodus</translation>
+<translation id="4750917950439032686">Deine Daten wie Passwörter oder Kreditkartennummern sind geschützt, wenn du sie an diese Website sendest.</translation>
<translation id="4751476147751820511">Bewegungs- oder Lichtsensoren</translation>
<translation id="4754461935447132332">Nicht zulässig für nicht sichere Websites</translation>
<translation id="4756388243121344051">&amp;Verlauf</translation>
-<translation id="4757993714154412917">Sie haben Ihr Passwort gerade auf einer verdächtigen Seite eingegeben. Chromium empfiehlt, Ihre gespeicherten Passwörter zu überprüfen, um Ihre Konten besser zu schützen.</translation>
+<translation id="4757993714154412917">Du hast dein Passwort gerade auf einer verdächtigen Seite eingegeben. Chromium empfiehlt, deine gespeicherten Passwörter zu überprüfen, um deine Konten besser zu schützen.</translation>
<translation id="4758311279753947758">Kontaktdaten hinzufügen</translation>
<translation id="4761104368405085019">Mikrofon verwenden</translation>
+<translation id="4761869838909035636">Chrome-Sicherheitscheck ausführen</translation>
<translation id="4764776831041365478">Die Webseite unter <ph name="URL" /> ist eventuell vorübergehend nicht verfügbar oder wurde dauerhaft an eine neue Webadresse verschoben.</translation>
<translation id="4766713847338118463">Zwei Heftklammern unten</translation>
<translation id="4771973620359291008">Ein unbekannter Fehler ist aufgetreten.</translation>
@@ -1191,24 +1229,18 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="4785376858512657294">Google-Konto verwalten</translation>
<translation id="4785689107224900852">Zu diesem Tab wechseln</translation>
<translation id="4791134497475588553">Installierte Linux-Apps und wann sie zuletzt verwendet wurden</translation>
-<translation id="4792686369684665359">Die Angaben, die Sie senden möchten, sind nicht sicher</translation>
+<translation id="4792686369684665359">Die Angaben, die du senden möchtest, sind nicht sicher</translation>
<translation id="4796594887379589189">Konto-ID des Auftrags</translation>
-<translation id="4798078619018708837">Geben Sie das Ablaufdatum und die Kartenprüfnummer (CVC) für <ph name="CREDIT_CARD" /> ein, um Ihre Kartendetails zu aktualisieren. Nach erfolgter Bestätigung werden die Kartendetails Ihres Google-Kontos an diese Website weitergegeben.</translation>
-<translation id="4800132727771399293">Prüfen Sie Ihr Ablaufdatum und Ihren CVC und versuchen Sie es dann erneut.</translation>
+<translation id="4798078619018708837">Gib das Ablaufdatum und die Kartenprüfnummer (CVC) für <ph name="CREDIT_CARD" /> ein, um deine Kartendetails zu aktualisieren. Nach erfolgter Bestätigung werden die Kartendetails deines Google-Kontos an diese Website weitergegeben.</translation>
+<translation id="4800132727771399293">Prüfe das Ablaufdatum und deinen CVC und versuche es dann noch einmal.</translation>
<translation id="480334179571489655">Fehler bezüglich Ursprungsrichtlinie</translation>
<translation id="4803924862070940586"><ph name="FORMATTED_TOTAL_AMOUNT" /> <ph name="CURRENCY_CODE" /></translation>
<translation id="4809079943450490359">Anweisungen des Geräteadministrators:</translation>
<translation id="4813512666221746211">Netzwerkfehler</translation>
<translation id="4816492930507672669">An Seite anpassen</translation>
<translation id="4819347708020428563">Anmerkungen in der Standardansicht bearbeiten?</translation>
-<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücken Sie die Tabulatortaste und dann die Eingabetaste, um schnell eine neue Google-Tabelle zu erstellen</translation>
+<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücke die Tabulatortaste und dann die Eingabetaste, um schnell eine neue Google-Tabelle zu erstellen</translation>
<translation id="4825507807291741242">Beeindruckend</translation>
-<translation id="4827402517081186284">Der Inkognitomodus macht Sie online nicht unsichtbar:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Websites erkennen, dass Sie sie besuchen<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Arbeitgeber und Bildungseinrichtungen können Browseraktivitäten erfassen<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Internetanbieter behalten ggf. den Web-Traffic im Blick<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">Warnmeldungen aktivieren</translation>
<translation id="4838327282952368871">Träumerisch</translation>
<translation id="4840250757394056958">Chrome-Verlauf anzeigen</translation>
@@ -1216,32 +1248,34 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="4849865131988503897">Genauigkeitsprüfung</translation>
<translation id="4850886885716139402">Anzeigen</translation>
<translation id="485316830061041779">Deutsch</translation>
-<translation id="4853901935952445031">Diese Website kann die U2F API nach Februar 2022 nicht mehr nutzen. Wenn Sie Inhaber dieser Website sind, sollten Sie sie auf die Nutzung der Web Authentication API umstellen.</translation>
-<translation id="4854362297993841467">Diese Lieferoption ist nicht verfügbar. Bitte wählen Sie eine andere Option aus.</translation>
+<translation id="4853901935952445031">Diese Website kann die U2F API nach Februar 2022 nicht mehr nutzen. Wenn du Inhaber dieser Website bist, solltest du sie auf die Nutzung der Web Authentication API umstellen.</translation>
+<translation id="4854362297993841467">Diese Lieferoption ist nicht verfügbar. Bitte wähle eine andere Option aus.</translation>
<translation id="4854853140771946034">Schnell eine neue Notiz in Google Notizen erstellen</translation>
<translation id="485902285759009870">Code wird geprüft...</translation>
+<translation id="4866506163384898554">Zum Einblenden des Cursors |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| drücken</translation>
<translation id="4876188919622883022">Vereinfachte Ansicht</translation>
<translation id="4876305945144899064">Kein Nutzername</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{Keine}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831">"<ph name="TEXT" />" suchen</translation>
<translation id="4879491255372875719">Automatisch (Standard)</translation>
-<translation id="4879725228911483934">Fenster auf Ihren Bildschirmen öffnen und positionieren</translation>
<translation id="4880827082731008257">Im Verlauf suchen</translation>
<translation id="4881695831933465202">Öffnen</translation>
<translation id="4885256590493466218">An der Kasse mit <ph name="CARD_DETAIL" /> zahlen</translation>
-<translation id="4889420713887366944">Schaltfläche "Inkognitofenster öffnen" – drücken Sie die Eingabetaste, um ein neues Inkognitofenster zu öffnen und privat zu surfen</translation>
+<translation id="4889420713887366944">Schaltfläche „Inkognitofenster öffnen“ – drücke die Eingabetaste, um ein neues Inkognitofenster zu öffnen und privat zu surfen</translation>
<translation id="4892518386797173871">Hinten</translation>
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">Neunte Rolle</translation>
<translation id="4901778704868714008">Wird gespeichert...</translation>
+<translation id="4905659621780993806">Dein Administrator startet das Gerät automatisch am <ph name="DATE" /> um <ph name="TIME" /> neu. Speichere vor dem Neustart alle geöffneten Inhalte.</translation>
<translation id="4913987521957242411">Lochung oben links</translation>
<translation id="4918221908152712722"><ph name="APP_NAME" /> installieren (kein Download erforderlich)</translation>
<translation id="4923459931733593730">Zahlung</translation>
<translation id="4926049483395192435">Angabe erforderlich</translation>
<translation id="4926159001844873046">Auf <ph name="SITE" /> wird Folgendes angezeigt:</translation>
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
-<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, drücken Sie zum Suchen die Tabulatortaste und dann die Eingabetaste</translation>
+<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, drücke zum Suchen die Tabulatortaste und dann die Eingabetaste</translation>
<translation id="4930153903256238152">Hohe Kapazität</translation>
+<translation id="4940163644868678279">Inkognitomodus in Chrome</translation>
<translation id="4943872375798546930">Keine Ergebnisse</translation>
<translation id="4950898438188848926">Schaltfläche zum Wechseln von Tabs, Eingabetaste drücken, um zum offenen Tab "<ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" />" zu wechseln</translation>
<translation id="495170559598752135">Aktionen</translation>
@@ -1251,35 +1285,36 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="4968522289500246572">Diese App wurde für Mobilgeräte entwickelt. Ihre Größe kann deshalb eventuell nicht richtig angepasst werden. Außerdem können Probleme auftreten und sie wird möglicherweise neu gestartet.</translation>
<translation id="4969341057194253438">Aufnahme löschen</translation>
<translation id="4973922308112707173">Doppelte Lochung oben</translation>
+<translation id="4976702386844183910">Zuletzt besucht am <ph name="DATE" /></translation>
<translation id="4984088539114770594">Mikrofon verwenden?</translation>
<translation id="4984339528288761049">Prc5 (Umschlag)</translation>
<translation id="4989163558385430922">Alle ansehen</translation>
<translation id="4989542687859782284">Nicht verfügbar</translation>
<translation id="4989809363548539747">Dieses Plug-in wird nicht unterstützt</translation>
<translation id="4992066212339426712">Stummschaltung aufheben</translation>
-<translation id="4995216769782533993">Bestätigen Sie den Sicherheitscode, um Ihre Kartendetails mit dieser Website zu teilen</translation>
+<translation id="4995216769782533993">Bestätige den Sicherheitscode, um deine Kartendetails mit dieser Website zu teilen</translation>
<translation id="4995474875135717171">Geändert:</translation>
-<translation id="4995749490935861684"><ph name="CUSTOMIZE_SEARCH_ENGINES_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücken Sie die Tabulatortaste und dann die Eingabetaste, um die Website-Suche und Ihre Standardsuchmaschine zu verwalten</translation>
-<translation id="5002932099480077015">Wenn diese Funktion aktiviert ist, speichert Chrome eine Kopie Ihrer Karte auf diesem Gerät, um ein Ausfüllen von Formularen zu beschleunigen.</translation>
+<translation id="4995749490935861684"><ph name="CUSTOMIZE_SEARCH_ENGINES_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücke die Tabulatortaste und dann die Eingabetaste, um die Website-Suche und deine Standardsuchmaschine zu verwalten</translation>
+<translation id="5002932099480077015">Wenn diese Funktion aktiviert ist, speichert Chrome eine Kopie deiner Karte auf diesem Gerät, um ein Ausfüllen von Formularen zu beschleunigen.</translation>
<translation id="5011561501798487822">Erkannte Sprache</translation>
<translation id="5015510746216210676">Computername:</translation>
-<translation id="5017554619425969104">Von Ihnen kopierter Text</translation>
+<translation id="5017554619425969104">Von dir kopierter Text</translation>
<translation id="5018422839182700155">Diese Seite kann nicht geöffnet werden</translation>
<translation id="5019198164206649151">Sicherungsspeicher ist fehlerhaft.</translation>
-<translation id="5023310440958281426">Informieren Sie sich über die von Ihrem Administrator festgelegten Richtlinien.</translation>
+<translation id="5023310440958281426">Informiere dich über die von deinem Administrator festgelegten Richtlinien.</translation>
<translation id="5029568752722684782">Kopie löschen</translation>
<translation id="5030338702439866405">Ausgestellt von</translation>
-<translation id="503069730517007720">Für "<ph name="SOFTWARE_NAME" />" ist ein Stammzertifikat erforderlich, das nicht installiert ist. Ihr IT-Administrator sollte die Konfigurationsanweisungen für "<ph name="SOFTWARE_NAME" />" lesen, um das Problem zu beheben. <ph name="FURTHER_EXPLANATION" /></translation>
+<translation id="503069730517007720">Für „<ph name="SOFTWARE_NAME" />“ ist ein Stammzertifikat erforderlich, das nicht installiert ist. Dein IT-Administrator sollte die Konfigurationsanweisungen für „<ph name="SOFTWARE_NAME" />“ lesen, um das Problem zu beheben. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="5031870354684148875">Ãœber Google Ãœbersetzer</translation>
-<translation id="503498442187459473"><ph name="HOST" /> möchte Ihre Kamera und Ihr Mikrofon verwenden</translation>
+<translation id="503498442187459473"><ph name="HOST" /> möchte deine Kamera und dein Mikrofon verwenden</translation>
<translation id="5039762155821394373">Schriftgröße</translation>
<translation id="5039804452771397117">Zulassen</translation>
<translation id="5040262127954254034">Datenschutz</translation>
-<translation id="5043480802608081735">Von Ihnen kopierter Link</translation>
+<translation id="5043480802608081735">Von dir kopierter Link</translation>
<translation id="5045550434625856497">Falsches Passwort</translation>
-<translation id="5056425809654826431">{NUM_FILES,plural, =1{Damit Sie diese Datei mit Nearby Share senden können, müssen Sie auf Ihrem Gerät Speicherplatz (<ph name="DISK_SPACE_SIZE" />) freigeben}other{Damit Sie diese Dateien mit Nearby Share senden können, müssen Sie auf Ihrem Gerät Speicherplatz (<ph name="DISK_SPACE_SIZE" />) freigeben}}</translation>
+<translation id="5056425809654826431">{NUM_FILES,plural, =1{Damit du diese Datei mit Nearby Share senden kannst, musst du auf deinem Gerät Speicherplatz (<ph name="DISK_SPACE_SIZE" />) freigeben}other{Damit du diese Dateien mit Nearby Share senden kannst, musst du auf deinem Gerät Speicherplatz (<ph name="DISK_SPACE_SIZE" />) freigeben}}</translation>
<translation id="5056549851600133418">Artikel für mich</translation>
-<translation id="5061227663725596739">Meinten Sie <ph name="LOOKALIKE_DOMAIN" />?</translation>
+<translation id="5061227663725596739">Meintest du <ph name="LOOKALIKE_DOMAIN" />?</translation>
<translation id="5066056036849835175">Druckverlauf</translation>
<translation id="5068524481479508725">A10</translation>
<translation id="5068778127327928576">{NUM_COOKIES,plural, =1{(1 wird verwendet)}other{(# werden verwendet)}}</translation>
@@ -1291,7 +1326,7 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="5088142053160410913">Nachricht an den Bediener</translation>
<translation id="5089810972385038852">Bundesstaat</translation>
<translation id="5093232627742069661">Z-Faltung</translation>
-<translation id="5094747076828555589">Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat wird von Chromium als nicht vertrauenswürdig eingestuft. Mögliche Gründe sind eine fehlerhafte Konfiguration oder ein Angreifer, der Ihre Verbindung abfängt.</translation>
+<translation id="5094747076828555589">Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat wird von Chromium als nicht vertrauenswürdig eingestuft. Mögliche Gründe sind eine fehlerhafte Konfiguration oder ein Angreifer, der deine Verbindung abfängt.</translation>
<translation id="5095208057601539847">Provinz</translation>
<translation id="5097099694988056070">Gerätestatistiken, z. B. CPU/RAM-Nutzung</translation>
<translation id="5097501891273180634">A2</translation>
@@ -1305,13 +1340,14 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="5123063207673082822">Wochenende</translation>
<translation id="5125394840236832993">B-Plus</translation>
<translation id="5126510351761255129">Karte bestätigen</translation>
-<translation id="512670116361803001">Die Größe von <ph name="APP_NAME" /> kann eventuell nicht richtig angepasst werden. Verwenden Sie voreingestellte Fenstergrößen, damit die App ordnungsgemäß funktioniert.</translation>
+<translation id="512670116361803001">Die Größe von <ph name="APP_NAME" /> kann eventuell nicht richtig angepasst werden. Verwende voreingestellte Fenstergrößen, damit die App ordnungsgemäß funktioniert.</translation>
<translation id="5135404736266831032">Adressen verwalten…</translation>
<translation id="5136841603454277753">Richtigen Code eingeben</translation>
-<translation id="5138014172396933048">Die virtuelle Karte ist zurzeit nicht verfügbar, bitte kontaktieren Sie Ihre Bank</translation>
+<translation id="5138014172396933048">Die virtuelle Karte ist zurzeit nicht verfügbar, bitte kontaktiere deine Bank</translation>
<translation id="5138227688689900538">Weniger anzeigen</translation>
<translation id="5145883236150621069">Fehlercode in der Richtlinienantwort</translation>
<translation id="5146995429444047494">Benachrichtigungen von <ph name="ORIGIN" /> werden blockiert</translation>
+<translation id="514704532284964975"><ph name="URL" /> möchte Informationen auf NFC-Geräten abrufen und ändern, die du mit deinem Smartphone berührst</translation>
<translation id="5148809049217731050">Vorderseite nach oben</translation>
<translation id="515292512908731282">C4 (Umschlag)</translation>
<translation id="5158275234811857234">Titelseite</translation>
@@ -1319,8 +1355,8 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="5161334686036120870">Thema:</translation>
<translation id="5161506081086828129">Stapelfach 9</translation>
<translation id="5164798890604758545">Text eingegeben</translation>
-<translation id="516920405563544094">Geben Sie die Kartenprüfnummer (CVC) für <ph name="CREDIT_CARD" /> ein. Nach erfolgter Bestätigung werden die Kartendetails Ihres Google-Kontos an diese Website weitergegeben.</translation>
-<translation id="5169827969064885044">Sie könnten den Zugriff auf das Konto Ihres Unternehmens verlieren oder zum Opfer von Identitätsdiebstahl werden. Chrome empfiehlt Ihnen, Ihr Passwort jetzt zu ändern.</translation>
+<translation id="516920405563544094">Gib die Kartenprüfnummer (CVC) für <ph name="CREDIT_CARD" /> ein. Nach erfolgter Bestätigung werden die Kartendetails deines Google-Kontos an diese Website weitergegeben.</translation>
+<translation id="5169827969064885044">Du könntest den Zugriff auf das Konto deines Unternehmens verlieren oder zum Opfer von Identitätsdiebstahl werden. Chrome empfiehlt dir, dein Passwort jetzt zu ändern.</translation>
<translation id="5171045022955879922">Suchen oder URL eingeben</translation>
<translation id="5171689220826475070">Fanfold-European</translation>
<translation id="5172758083709347301">Computer</translation>
@@ -1329,13 +1365,14 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="51918995459521422"><ph name="ORIGIN" /> möchte mehrere Dateien herunterladen</translation>
<translation id="519422657042045905">Anmerkungsmodus nicht verfügbar</translation>
<translation id="5201306358585911203">Auf einer in dieser Seite eingebetteten Seite wird Folgendes angezeigt</translation>
-<translation id="5204468114771111727">Chrome hat erkannt, dass das Passwort, das Sie gerade verwendet haben, aufgrund einer Datenpanne veröffentlicht wurde. Google Assistant kann Ihr Passwort automatisch ändern.</translation>
+<translation id="5204468114771111727">Chrome hat erkannt, dass das Passwort, das du gerade verwendet hast, aufgrund einer Datenpanne veröffentlicht wurde. Google Assistant kann dein Passwort automatisch ändern.</translation>
<translation id="5205222826937269299">Name erforderlich</translation>
<translation id="5209518306177824490">SHA-1-Fingerabdruck</translation>
<translation id="5209670883520018268">Fach 20</translation>
<translation id="5215116848420601511">Bei Google Pay gespeicherte Zahlungsmethoden und Adressen</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">Fach 13</translation>
+<translation id="5216942107514965959">Heute zuletzt besucht</translation>
<translation id="5222812217790122047">E-Mail-Adresse erforderlich</translation>
<translation id="5230733896359313003">Versandadresse</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1356,12 +1393,11 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">Dokumenteigenschaften</translation>
<translation id="528468243742722775">Ende</translation>
-<translation id="5284909709419567258">Netzwerkadressen</translation>
<translation id="5285570108065881030">Alle gespeicherten Passwörter anzeigen</translation>
<translation id="5287240709317226393">Cookies anzeigen</translation>
<translation id="5287456746628258573">Diese Website nutzt eine veraltete Sicherheitskonfiguration. Hierdurch können Informationen wie etwa Passwörter oder Kreditkartennummern, die an diese Website gesendet werden, in die Hände Unbefugter gelangen.</translation>
<translation id="5288108484102287882">Die Validierung der Richtlinienwerte hat Warnungen ergeben</translation>
-<translation id="5288808348893593856">Websiteverbindungen sind sicher, solange Chrome Sie nicht auf eine unsichere Verbindung hinweist.</translation>
+<translation id="5288808348893593856">Websiteverbindungen sind sicher, solange Chrome dich nicht auf eine unsichere Verbindung hinweist.</translation>
<translation id="5289384342738547352">Handhabung mehrerer Dokumente</translation>
<translation id="5299298092464848405">Fehler beim Parsen der Richtlinie</translation>
<translation id="5300589172476337783">Anzeigen</translation>
@@ -1374,32 +1410,32 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="5317780077021120954">Speichern</translation>
<translation id="5323105697514565458"><ph name="FRIENDLY_MATCH_TEXT" />, <ph name="MATCH_POSITION" /> von <ph name="NUM_MATCHES" /></translation>
<translation id="5324080437450482387">Kontaktdaten auswählen</translation>
-<translation id="5329858041417644019">Ihr Browser wird nicht verwaltet</translation>
+<translation id="5329858041417644019">Dein Browser wird nicht verwaltet</translation>
<translation id="5332219387342487447">Versandart</translation>
-<translation id="5333022057423422993">Chrome hat das Passwort, das Sie gerade verwendet haben, in einer Datenpanne gefunden. Wir empfehlen Ihnen, Ihre gespeicherten Passwörter zu prüfen, um Ihre Konten besser zu schützen.</translation>
+<translation id="5333022057423422993">Chrome hat das Passwort, das du gerade verwendet hast, in einer Datenpanne gefunden. Wir empfehlen dir, deine gespeicherten Passwörter zu prüfen, um deine Konten besser zu schützen.</translation>
<translation id="5334013548165032829">Detaillierte Systemprotokolle</translation>
<translation id="5334145288572353250">Adresse speichern?</translation>
<translation id="5335920952954443287">Schlagendes Herz</translation>
<translation id="5340250774223869109">Die App ist blockiert</translation>
<translation id="534295439873310000">NFC-Geräte</translation>
-<translation id="5344579389779391559">Auf dieser Seite wird möglicherweise versucht, Ihnen etwas in Rechnung zu stellen</translation>
-<translation id="5347645913823149105">Schaltfläche zum Anpassen von Schriftarten in Chrome – drücken Sie die Eingabetaste, um Schriftgrößen und Schriftarten in Chrome anzupassen</translation>
-<translation id="5355557959165512791">Sie können <ph name="SITE" /> zurzeit nicht aufrufen, da das Zertifikat widerrufen wurde. Netzwerkfehler und Angriffe sind in der Regel nur vorübergehend, sodass die Seite wahrscheinlich später wieder funktioniert.</translation>
+<translation id="5344579389779391559">Auf dieser Seite wird möglicherweise versucht, dir etwas in Rechnung zu stellen</translation>
+<translation id="5347645913823149105">Schaltfläche zum Anpassen von Schriftarten in Chrome – drücke die Eingabetaste, um Schriftgrößen und Schriftarten in Chrome anzupassen</translation>
+<translation id="5355557959165512791">Du kannst <ph name="SITE" /> zurzeit nicht aufrufen, da das Zertifikat widerrufen wurde. Netzwerkfehler und Angriffe sind in der Regel nur vorübergehend, sodass die Seite wahrscheinlich später wieder funktioniert.</translation>
<translation id="5356837363448394805">Errötet</translation>
<translation id="536296301121032821">Fehler beim Speichern der Richtlinieneinstellungen</translation>
-<translation id="5363309033720083897">Serielle Ports sind von Ihrem Administrator zugelassen</translation>
+<translation id="5363309033720083897">Serielle Ports sind von deinem Administrator zugelassen</translation>
<translation id="5371425731340848620">Karte aktualisieren</translation>
-<translation id="5377026284221673050">"Ihre Uhr geht nach", "Ihre Uhr geht vor" oder "&lt;span class="error-code"&gt;NET::ERR_CERT_DATE_INVALID&lt;/span&gt;"</translation>
-<translation id="5379027395132364855">Schaltfläche „Präsentation erstellen“ – drücken Sie die Eingabetaste, um schnell eine neue Präsentation in Google Präsentationen zu erstellen</translation>
+<translation id="5377026284221673050">"Deine Uhr geht nach", "Deine Uhr geht vor" oder "&lt;span class="error-code"&gt;NET::ERR_CERT_DATE_INVALID&lt;/span&gt;"</translation>
+<translation id="5379027395132364855">Schaltfläche „Präsentation erstellen“ – drücke die Eingabetaste, um schnell eine neue Präsentation in Google Präsentationen zu erstellen</translation>
<translation id="5386426401304769735">Die Zertifikatskette für diese Website enthält ein Zertifikat mit SHA-1-Signatur.</translation>
<translation id="538659543871111977">A4-Tab</translation>
<translation id="5396631636586785122">Mehrere Heftklammern rechts</translation>
<translation id="5398772614898833570">Werbung blockiert</translation>
<translation id="5400836586163650660">Grau</translation>
-<translation id="540969355065856584">Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat ist zurzeit ungültig. Mögliche Gründe sind eine fehlerhafte Konfiguration oder ein Angreifer, der Ihre Verbindung abfängt.</translation>
+<translation id="540969355065856584">Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat ist zurzeit ungültig. Mögliche Gründe sind eine fehlerhafte Konfiguration oder ein Angreifer, der deine Verbindung abfängt.</translation>
<translation id="541416427766103491">Stapelfach 4</translation>
<translation id="5421136146218899937">Browserdaten löschen...</translation>
-<translation id="5426179911063097041"><ph name="SITE" /> möchte Ihnen Benachrichtigungen senden</translation>
+<translation id="5426179911063097041"><ph name="SITE" /> möchte dir Benachrichtigungen senden</translation>
<translation id="5428105026674456456">Spanisch</translation>
<translation id="5430298929874300616">Lesezeichen löschen</translation>
<translation id="5439770059721715174">Schemavalidierungsfehler in "<ph name="ERROR_PATH" />": <ph name="ERROR" /></translation>
@@ -1413,13 +1449,13 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="5469868506864199649">Italienisch</translation>
<translation id="5470861586879999274">&amp;Bearbeiten wiederholen</translation>
<translation id="5478437291406423475">B6/C4 (Umschlag)</translation>
-<translation id="5481076368049295676">Diese Inhalte versuchen möglicherweise, gefährliche Software auf Ihrem Gerät zu installieren, durch die Ihre Informationen gestohlen oder gelöscht werden. <ph name="BEGIN_LINK" />Trotzdem anzeigen<ph name="END_LINK" /></translation>
+<translation id="5481076368049295676">Diese Inhalte versuchen möglicherweise, gefährliche Software auf deinem Gerät zu installieren, durch die deine Informationen gestohlen oder gelöscht werden. <ph name="BEGIN_LINK" />Trotzdem anzeigen<ph name="END_LINK" /></translation>
<translation id="54817484435770891">Gültige Adresse hinzufügen</translation>
<translation id="5485973315555778056">Cloudgerät</translation>
<translation id="5490432419156082418">Adressen</translation>
<translation id="5492298309214877701">Diese Website im Intranet des Unternehmens, der Organisation oder der Schule hat die gleiche URL wie eine externe Website.
<ph name="LINE_BREAK" />
- Wenden Sie sich an Ihren Systemadministrator.</translation>
+ Wende dich an deinen Systemadministrator.</translation>
<translation id="549333378215107354">Größe 3</translation>
<translation id="5509762909502811065">B0</translation>
<translation id="5509780412636533143">Verwaltete Lesezeichen</translation>
@@ -1429,21 +1465,22 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="5523118979700054094">Richtlinienname</translation>
<translation id="55293785478302737">Mehrere Heftklammern</translation>
<translation id="553484882784876924">Prc6 (Umschlag)</translation>
-<translation id="5535133333442455806">Schaltfläche "Browserdaten löschen" – drücken Sie die Eingabetaste, um Ihren Browserverlauf, Ihre Cookies und andere Daten zu löschen sowie den Cache zu leeren</translation>
+<translation id="5535133333442455806">Schaltfläche "Browserdaten löschen" – drücke die Eingabetaste, um deinen Browserverlauf, deine Cookies und andere Daten zu löschen sowie den Cache zu leeren</translation>
<translation id="5536214594743852365">Abschnitt "<ph name="SECTION" />" einblenden</translation>
<translation id="5539243836947087108">Raft</translation>
<translation id="5540224163453853">Der gewünschte Artikel wurde nicht gefunden.</translation>
<translation id="5541086400771735334">Ablage 7</translation>
<translation id="5541546772353173584">E-Mail-Adresse hinzufügen</translation>
<translation id="5545756402275714221">Artikel für mich</translation>
-<translation id="5552137475244467770">Chrome prüft in regelmäßigen Abständen, ob Ihre Passwörter auf Listen erscheinen, die online veröffentlicht wurden. Dabei werden Ihre Passwörter und Nutzernamen verschlüsselt, damit sie von niemandem gelesen werden können, auch nicht von Google.</translation>
+<translation id="5552137475244467770">Chrome prüft in regelmäßigen Abständen, ob deine Passwörter auf Listen erscheinen, die online veröffentlicht wurden. Dabei werden deine Passwörter und Nutzernamen verschlüsselt, damit sie von niemandem gelesen werden können, auch nicht von Google.</translation>
<translation id="5556459405103347317">Neu laden</translation>
<translation id="5560088892362098740">Ablaufdatum</translation>
-<translation id="55635442646131152">Dokumentenstruktur</translation>
+<translation id="55635442646131152">Dokumentstruktur</translation>
+<translation id="5565613213060953222">Inkognitotab öffnen</translation>
<translation id="5565735124758917034">Aktiv</translation>
<translation id="5570825185877910964">Konto schützen</translation>
-<translation id="5571083550517324815">Diese Abholadresse wird nicht unterstützt. Bitte wählen Sie eine andere Adresse aus.</translation>
-<translation id="5580958916614886209">Prüfen Sie Ihren Ablaufmonat und versuchen Sie es dann erneut</translation>
+<translation id="5571083550517324815">Diese Abholadresse wird nicht unterstützt. Bitte wähle eine andere Adresse aus.</translation>
+<translation id="5580958916614886209">Prüfe den Ablaufmonat und versuche es dann erneut</translation>
<translation id="5586446728396275693">Keine gespeicherten Adressen</translation>
<translation id="5587987780934666589">Plattformnutzer</translation>
<translation id="5593349413089863479">Verbindung ist nicht uneingeschränkt sicher</translation>
@@ -1453,14 +1490,14 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="5605670050355397069">Ledger</translation>
<translation id="5607240918979444548">Architecture-C</translation>
<translation id="5610142619324316209">Verbindung prüfen</translation>
-<translation id="5610807607761827392"><ph name="BEGIN_LINK" />Karten und Adressen können Sie in den Einstellungen verwalten.<ph name="END_LINK" /></translation>
+<translation id="5610807607761827392"><ph name="BEGIN_LINK" />Karten und Adressen kannst du in den Einstellungen verwalten.<ph name="END_LINK" /></translation>
<translation id="561165882404867731">Diese Seite mit Google Übersetzer übersetzen</translation>
-<translation id="5612720917913232150"><ph name="URL" /> möchte den Standort Ihres Computers nutzen</translation>
-<translation id="5617949217645503996"><ph name="HOST_NAME" /> hat Sie zu oft weitergeleitet.</translation>
+<translation id="5612720917913232150"><ph name="URL" /> möchte den Standort deines Computers nutzen</translation>
+<translation id="5617949217645503996"><ph name="HOST_NAME" /> hat dich zu oft weitergeleitet.</translation>
<translation id="5624120631404540903">Passwörter verwalten</translation>
<translation id="5629630648637658800">Fehler beim Laden der Richtlinieneinstellungen</translation>
<translation id="5631439013527180824">Ungültiges Management-Token für das Gerät</translation>
-<translation id="5633066919399395251">Zurzeit auf <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> befindliche Hacker könnten versuchen, gefährliche Programme auf Ihrem Computer zu installieren, um Daten wie Fotos, Passwörter, Nachrichten und Kreditkartendaten zu stehlen oder zu löschen. <ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="5633066919399395251">Zurzeit auf <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> befindliche Hacker könnten versuchen, gefährliche Programme auf deinem Computer zu installieren, um Daten wie Fotos, Passwörter, Nachrichten und Kreditkartendaten zu stehlen oder zu löschen. <ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="563324245173044180">Betrügerische Inhalte blockiert.</translation>
<translation id="5644090287519800334">Seite 1 – X-Verschiebung des Bilds</translation>
<translation id="5645854190134202180">Zweite Schicht</translation>
@@ -1468,7 +1505,7 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="5654927323611874862">ID für hochgeladenen Absturzbericht:</translation>
<translation id="5659593005791499971">E-Mail</translation>
<translation id="5663614846592581799">9x11 (Umschlag)</translation>
-<translation id="5663955426505430495">Der Administrator dieses Geräts hat Erweiterungen für zusätzliche Funktionen installiert. Diese Erweiterungen können auf einige Ihrer Daten zugreifen.</translation>
+<translation id="5663955426505430495">Der Administrator dieses Geräts hat Erweiterungen für zusätzliche Funktionen installiert. Diese Erweiterungen können auf einige deiner Daten zugreifen.</translation>
<translation id="5675650730144413517">Diese Seite funktioniert nicht</translation>
<translation id="568292603005599551">X-Position des Bilds</translation>
<translation id="5684277895745049190">Liste</translation>
@@ -1477,7 +1514,7 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="5689199277474810259">Als JSON exportieren</translation>
<translation id="5689516760719285838">Standort</translation>
<translation id="569000877158168851">Der Wert von "DnsOverHttpsTemplates" ist nicht relevant und wird nicht verwendet, es sei denn, die Richtlinie "DnsOverHttpsMode" ist auf <ph name="SECURE_DNS_MODE_AUTOMATIC" /> oder <ph name="SECURE_DNS_MODE_SECURE" /> gesetzt.</translation>
-<translation id="5695542892312572833">Möchten Sie zum Bestätigen und Abschließen Ihres Kaufs Windows Hello verwenden?</translation>
+<translation id="5695542892312572833">Möchtest du zum Bestätigen und Abschließen deines Kaufs Windows Hello verwenden?</translation>
<translation id="5701381305118179107">Zentrieren</translation>
<translation id="570530837424789914">Verwalten…</translation>
<translation id="5707154300732650394">Weiter stöbern</translation>
@@ -1485,43 +1522,44 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="571403275720188526">(arm64)</translation>
<translation id="5720705177508910913">Aktueller Nutzer</translation>
<translation id="5728056243719941842">C5 (Umschlag)</translation>
-<translation id="5730040223043577876">Chrome empfiehlt, Ihr Passwort zurückzusetzen, wenn Sie es auf anderen Websites verwendet haben.</translation>
-<translation id="5737183892635480227">{NUM_CARDS,plural, =1{Karte in Ihrem Google-Konto speichern}other{Karten in Ihrem Google-Konto speichern}}</translation>
+<translation id="5730040223043577876">Chrome empfiehlt, dein Passwort zurückzusetzen, wenn du es auf anderen Websites verwendet hast.</translation>
+<translation id="5737183892635480227">{NUM_CARDS,plural, =1{Karte in deinem Google-Konto speichern}other{Karten in deinem Google-Konto speichern}}</translation>
<translation id="5745733273847572235">Darf nach meinem Standort fragen</translation>
<translation id="5745980000221562234">{NUM_CARDS,plural, =1{Für diese Karte eine virtuelle Nummer verwenden}other{Karte auswählen}}</translation>
<translation id="5759751709240058861">Kamera verwenden und bewegen</translation>
-<translation id="5763042198335101085">Geben Sie eine gültige E-Mail-Adresse ein</translation>
-<translation id="5765072501007116331">Wählen Sie eine Adresse aus, um Lieferoptionen und -anforderungen zu sehen</translation>
+<translation id="5763042198335101085">Gib eine gültige E-Mail-Adresse ein</translation>
+<translation id="5765072501007116331">Wähle eine Adresse aus, um Lieferoptionen und -anforderungen zu sehen</translation>
<translation id="57689295674415555">Wurde die virtuelle Kartennummer nicht eingefügt?</translation>
<translation id="5776313857861697733">Priorität</translation>
<translation id="5781136890105823427">Test aktiviert</translation>
<translation id="578305955206182703">Bernsteingelb</translation>
<translation id="57838592816432529">Stummschalten</translation>
-<translation id="5784606427469807560">Beim Bestätigen Ihrer Karte ist ein Problem aufgetreten. Überprüfen Sie Ihre Internetverbindung und versuchen Sie es noch einmal.</translation>
+<translation id="5784606427469807560">Beim Bestätigen deiner Karte ist ein Problem aufgetreten. Überprüfe deine Internetverbindung und versuche es noch einmal.</translation>
<translation id="5785756445106461925">Außerdem enthält diese Seite andere, nicht sichere Ressourcen. Diese Ressourcen können während der Übertragung von anderen Nutzern angezeigt und von Angreifern bearbeitet werden, die das Layout der Seite verändern.</translation>
-<translation id="5786044859038896871">Möchten Sie Ihre Kreditkarteninformationen eingeben?</translation>
-<translation id="578633867165174378">Chrome hat das Passwort, das Sie gerade verwendet haben, in einer Datenpanne gefunden. Wie empfehlen Ihnen, dieses Passwort jetzt zu ändern.</translation>
+<translation id="5786044859038896871">Möchtest du deine Kreditkarteninformationen eingeben?</translation>
+<translation id="578633867165174378">Chrome hat das Passwort, das du gerade verwendet hast, in einer Datenpanne gefunden. Wie empfehlen dir, dieses Passwort jetzt zu ändern.</translation>
<translation id="5789643057113097023">.</translation>
-<translation id="5803412860119678065">Möchten Sie die Daten Ihrer <ph name="CARD_DETAIL" /> eingeben?</translation>
+<translation id="5803412860119678065">Möchtest du die Daten deiner <ph name="CARD_DETAIL" /> eingeben?</translation>
<translation id="5804241973901381774">Berechtigungen</translation>
-<translation id="5810442152076338065">Ihre Verbindung zu <ph name="DOMAIN" /> ist mit einer veralteten Codier-Suite verschlüsselt.</translation>
-<translation id="5812947184178430888">Wenn Chrome Sicherheitshinweise meldet, werden relevante Informationen an Ihren Administrator gesendet. Dazu gehören z. B. URLs der von Ihnen in Chrome besuchten Seiten, Dateinamen oder Metadaten sowie der Nutzername, den Sie zum Anmelden in Webanwendungen, auf Ihrem Gerät und in Chrome verwenden.</translation>
+<translation id="5810442152076338065">Deine Verbindung zu <ph name="DOMAIN" /> ist mit einer veralteten Codier-Suite verschlüsselt.</translation>
+<translation id="5812947184178430888">Wenn Chrome Sicherheitshinweise meldet, werden relevante Informationen an deinen Administrator gesendet. Dazu gehören z. B. URLs der von dir in Chrome besuchten Seiten, Dateinamen oder Metadaten sowie der Nutzername, den du zum Anmelden in Webanwendungen, auf deinem Gerät und in Chrome verwendest.</translation>
<translation id="5813119285467412249">&amp;Hinzufügen wiederholen</translation>
<translation id="5817918615728894473">Koppeln</translation>
<translation id="5824687817967109979">{NUM_CARDS,plural, =1{Diese Karte wird beim Bezahlen zwar belastet, doch die echte Kreditkartennummer wird nicht an diese Website weitergegeben. Für zusätzliche Sicherheit wird ein temporärer CVC generiert.}other{Die ausgewählte Karte wird beim Bezahlen zwar belastet, doch die echte Kreditkartennummer wird nicht an diese Website weitergegeben. Für zusätzliche Sicherheit wird ein temporärer CVC generiert.}}</translation>
<translation id="5826507051599432481">Allgemeiner Name (CN)</translation>
<translation id="5830698870816298009">Kamera verwenden und bewegen</translation>
-<translation id="5838278095973806738">Sie sollten keine vertraulichen Informationen wie Passwörter oder Kreditkartennummern auf dieser Website eingeben, da sie von Angreifern gestohlen werden könnten.</translation>
+<translation id="5838278095973806738">Du solltest keine vertraulichen Informationen wie Passwörter oder Kreditkartennummern auf dieser Website eingeben, da sie von Angreifern gestohlen werden könnten.</translation>
<translation id="5851548754964597211">Tab-Liste</translation>
<translation id="5860033963881614850">Aus</translation>
<translation id="5862579898803147654">Stapelfach 8</translation>
-<translation id="5863847714970149516">Auf der nächsten Seite wird möglicherweise versucht, Ihnen etwas in Rechnung zu stellen</translation>
+<translation id="5863847714970149516">Auf der nächsten Seite wird möglicherweise versucht, dir etwas in Rechnung zu stellen</translation>
<translation id="5866257070973731571">Telefonnummer hinzufügen</translation>
-<translation id="5866898949289125849">Sie haben eine Entwicklertools-Seite aufgerufen</translation>
+<translation id="5866898949289125849">Du hast eine Entwicklertools-Seite aufgerufen</translation>
<translation id="5869405914158311789">Die Website ist nicht erreichbar</translation>
<translation id="5869522115854928033">Gespeicherte Passwörter</translation>
-<translation id="5873013647450402046">Ihre Bank muss Ihre Identität bestätigen.</translation>
+<translation id="5873013647450402046">Deine Bank muss deine Identität bestätigen.</translation>
<translation id="5887400589839399685">Karte gespeichert</translation>
+<translation id="5887687176710214216">Gestern zuletzt besucht</translation>
<translation id="5895138241574237353">Neu starten</translation>
<translation id="5895187275912066135">Ausgestellt am</translation>
<translation id="5901630391730855834">Gelb</translation>
@@ -1535,6 +1573,7 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="5921639886840618607">Karte im Google-Konto speichern?</translation>
<translation id="5922853866070715753">Fast fertig</translation>
<translation id="5932224571077948991">Website zeigt aufdringliche oder irreführende Werbung an</translation>
+<translation id="5938153366081463283">Virtuelle Karte hinzufügen</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347"><ph name="SITE_NAME" /> wird geöffnet…</translation>
<translation id="5951495562196540101">Registrierung mit Kundenkonto nicht möglich (Paketlizenz verfügbar).</translation>
@@ -1550,7 +1589,7 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="598637245381783098">Fehler beim Öffnen der Zahlungs-App</translation>
<translation id="5989320800837274978">Weder feste Proxyserver noch eine PAC-Skript-URL sind festgelegt.</translation>
<translation id="5992691462791905444">Technische Z-Faltung</translation>
-<translation id="5995727681868049093">Daten, Datenschutz- und Sicherheitseinstellungen in Ihrem Google-Konto verwalten</translation>
+<translation id="5995727681868049093">Daten, Datenschutz- und Sicherheitseinstellungen in deinem Google-Konto verwalten</translation>
<translation id="6000758707621254961"><ph name="RESULT_COUNT" /> Ergebnisse für "<ph name="SEARCH_TEXT" />"</translation>
<translation id="6006484371116297560">Klassisch</translation>
<translation id="6008122969617370890">N-zu-1-Reihenfolge</translation>
@@ -1559,34 +1598,34 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="6014851866995737824">Ignoriert, da die „enable“- oder „disable“-Liste fehlt.</translation>
<translation id="6015796118275082299">Jahr</translation>
<translation id="6017514345406065928">Grün</translation>
-<translation id="6017850046339264347">Angreifer auf der Website <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> könnten betrügerische Apps installieren, die scheinbar einem anderen Zweck dienen oder Daten erfassen, um Sie auszuspionieren. <ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="6017850046339264347">Angreifer auf der Website <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> könnten betrügerische Apps installieren, die scheinbar einem anderen Zweck dienen oder Daten erfassen, um dich auszuspionieren. <ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6025416945513303461"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /> (synchronisiert)</translation>
-<translation id="6027201098523975773">Geben Sie einen Namen ein</translation>
+<translation id="6027201098523975773">Gib einen Namen ein</translation>
<translation id="603068602130820122">Zwei Heftklammern rechts</translation>
<translation id="6032524144326295339">Ablage 2</translation>
<translation id="6032955021262906325">Bindung links</translation>
<translation id="6034000775414344507">Hellgrau</translation>
<translation id="6034283069659657473">10x14 (Umschlag)</translation>
<translation id="6034514109191629503">Akkordeonfaltung</translation>
-<translation id="6039846035001940113">Falls das Problem weiterhin besteht, wenden Sie sich an den Inhaber der Website.</translation>
+<translation id="6039846035001940113">Falls das Problem weiterhin besteht, wende dich an den Inhaber der Website.</translation>
<translation id="6040143037577758943">Schließen</translation>
<translation id="6041777658117377052">Temperatur der Kammer</translation>
<translation id="6044573915096792553">Größe 12</translation>
<translation id="6045164183059402045">Vorlage für Ausschießen</translation>
-<translation id="6047233362582046994">Wenn Sie die Sicherheitsrisiken kennen, können Sie <ph name="BEGIN_LINK" />diese Website aufrufen<ph name="END_LINK" />, bevor die schädlichen Apps entfernt wurden.</translation>
-<translation id="6047927260846328439">Mit diesen Inhalten wird möglicherweise versucht, Sie zu täuschen und so zur Installation von Software oder der Offenlegung personenbezogener Daten zu bringen. <ph name="BEGIN_LINK" />Trotzdem anzeigen<ph name="END_LINK" /></translation>
+<translation id="6047233362582046994">Wenn du die Sicherheitsrisiken kennst, kannst du <ph name="BEGIN_LINK" />diese Website aufrufen<ph name="END_LINK" />, bevor die schädlichen Apps entfernt wurden.</translation>
+<translation id="6047927260846328439">Mit diesen Inhalten wird möglicherweise versucht, dich zu täuschen und so zur Installation von Software oder der Offenlegung personenbezogener Daten zu bringen. <ph name="BEGIN_LINK" />Trotzdem anzeigen<ph name="END_LINK" /></translation>
<translation id="6049004884579590341">|<ph name="ACCELERATOR" />| gedrückt halten, um den Vollbildmodus zu beenden</translation>
<translation id="6049488691372270142">Ausgabe der Seiten</translation>
-<translation id="6051221802930200923">Sie können <ph name="SITE" /> zurzeit nicht aufrufen, weil die Website das Zertifikats-Pinning nutzt. Netzwerkfehler und Angriffe sind in der Regel nur vorübergehend, sodass die Seite wahrscheinlich später wieder funktioniert.</translation>
+<translation id="6051221802930200923">Du kannst <ph name="SITE" /> zurzeit nicht aufrufen, weil die Website das Zertifikats-Pinning nutzt. Netzwerkfehler und Angriffe sind in der Regel nur vorübergehend, sodass die Seite wahrscheinlich später wieder funktioniert.</translation>
<translation id="6051898664905071243">Seitenzahl:</translation>
<translation id="6052284303005792909">•</translation>
-<translation id="6052319569711353666">Das Passwort, das Sie gerade verwendet haben, wurde in einer Datenpanne gefunden. Der Passwortmanager von Google empfiehlt, dieses Passwort jetzt zu ändern.</translation>
+<translation id="6052319569711353666">Das Passwort, das du gerade verwendet hast, wurde in einer Datenpanne gefunden. Der Passwortmanager von Google empfiehlt, dieses Passwort jetzt zu ändern.</translation>
<translation id="6055888660316801977">Sichere Anmeldedaten für Zahlungen – Tabellenblatt für nicht übereinstimmende sichere Anmeldedaten</translation>
-<translation id="6058977677006700226">Karten auf allen Ihren Geräten nutzen?</translation>
+<translation id="6058977677006700226">Karten auf allen deinen Geräten nutzen?</translation>
<translation id="6059925163896151826">USB-Geräte</translation>
<translation id="6060009363608157444">Ungültiger DnsOverHttps-Modus.</translation>
<translation id="6064217302520318294">Displaysperre</translation>
-<translation id="6080696365213338172">Sie haben über ein vom Administrator bereitgestelltes Zertifikat auf Inhalte zugegriffen. Die Daten, die Sie innerhalb von <ph name="DOMAIN" /> bereitstellen, können von Ihrem Administrator abgefangen werden.</translation>
+<translation id="6080696365213338172">Du hast über ein vom Administrator bereitgestelltes Zertifikat auf Inhalte zugegriffen. Die Daten, die du innerhalb von <ph name="DOMAIN" /> bereitstellst, können von deinem Administrator abgefangen werden.</translation>
<translation id="6087312102907839798">Ähnliche Suchanfragen</translation>
<translation id="6094273045989040137">Anmerkung hinzufügen</translation>
<translation id="6094290315941448991">Die Administratorrichtlinie blockiert die Bildschirmaufzeichnung, wenn vertrauliche Inhalte sichtbar sind</translation>
@@ -1594,63 +1633,64 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="6105460996796456817">Website erstellen</translation>
<translation id="6106989379647458772">Die Webseite unter <ph name="PAGE" /> ist möglicherweise vorübergehend nicht verfügbar oder ist jetzt unter einer neuen Webadresse aufrufbar.</translation>
<translation id="6107012941649240045">Ausgestellt für</translation>
-<translation id="610911394827799129">Unter <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" /> sind möglicherweise weitere Arten von Browserverlaufsdaten für Ihr Google-Konto gespeichert.</translation>
+<translation id="610911394827799129">Unter <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" /> sind möglicherweise weitere Arten von Browserverlaufsdaten für dein Google-Konto gespeichert.</translation>
<translation id="6116338172782435947">Texte und Bilder aus der Zwischenablage abrufen</translation>
-<translation id="6120179357481664955">Soll Ihre UPI-ID gespeichert werden?</translation>
+<translation id="6120179357481664955">Soll deine UPI-ID gespeichert werden?</translation>
<translation id="6124432979022149706">Chrome Enterprise Connectors</translation>
<translation id="6127379762771434464">Eintrag entfernt</translation>
-<translation id="6146055958333702838">Überprüfen Sie alle Kabel und starten Sie alle verwendeten Router, Modems und
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Weitere Informationen zum Inkognitomodus in Chrome<ph name="END_LINK" /></translation>
+<translation id="6146055958333702838">Überprüfe alle Kabel und starte alle verwendeten Router, Modems und
anderen Netzwerkgeräte neu.</translation>
-<translation id="614940544461990577">Versuchen Sie Folgendes:</translation>
+<translation id="614940544461990577">Versuche Folgendes:</translation>
<translation id="6150036310511284407">Dreifache Lochung links</translation>
<translation id="6151417162996330722">Die Gültigkeitsdauer des Serverzertifikats ist zu lang.</translation>
<translation id="6153243098246946146"><ph name="WIDTH" /> × <ph name="HEIGHT" /> in (<ph name="ORIENTATION" />)</translation>
<translation id="6157754950574419155">Alle aus Verlauf entfernen</translation>
-<translation id="6157877588268064908">Wählen Sie eine Adresse aus, um Versandoptionen und -anforderungen zu sehen</translation>
+<translation id="6157877588268064908">Wähle eine Adresse aus, um Versandoptionen und -anforderungen zu sehen</translation>
<translation id="6165508094623778733">Weitere Informationen</translation>
-<translation id="6169916984152623906">Sie können jetzt privat surfen. Für andere Personen, die dieses Gerät nutzen, sind Ihre Aktivitäten nicht sichtbar. Ihre Downloads und Lesezeichen werden jedoch gespeichert.</translation>
+<translation id="6169916984152623906">Du kannst jetzt privat surfen. Für andere Personen, die dieses Gerät nutzen, sind deine Aktivitäten nicht sichtbar. Deine Downloads und Lesezeichen werden jedoch gespeichert.</translation>
<translation id="6177128806592000436">Die Verbindung zu dieser Website ist nicht sicher</translation>
<translation id="6180316780098470077">Wiederholungsintervall</translation>
-<translation id="619448280891863779">Darf nachfragen, wenn sie Fenster auf ihren Bildschirmen öffnen und platzieren möchte</translation>
<translation id="6196640612572343990">Drittanbieter-Cookies blockieren</translation>
-<translation id="6203231073485539293">Bitte überprüfen Sie Ihre Internetverbindung.</translation>
+<translation id="6203231073485539293">Bitte überprüfe deine Internetverbindung.</translation>
<translation id="6218753634732582820">Adresse aus Chromium entfernen?</translation>
<translation id="622039917539443112">Parallele Faltung</translation>
<translation id="6221345481584921695">Google Safe Browsing hat kürzlich <ph name="BEGIN_LINK" />Malware<ph name="END_LINK" /> auf <ph name="SITE" /> gefunden. Websites, die in der Regel sicher sind, können gelegentlich mit Malware infiziert sein. Der schädliche Inhalt stammt von <ph name="SUBRESOURCE_HOST" />, einem bekannten Verteiler von Malware.</translation>
-<translation id="6226163402662242066"><ph name="MANAGE_CHROME_ACCESSIBILITY_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücken Sie die Tabulatortaste und dann die Eingabetaste, um die Bedienungshilfen in den Chrome-Einstellungen zu personalisieren</translation>
+<translation id="6226163402662242066"><ph name="MANAGE_CHROME_ACCESSIBILITY_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücke die Tabulatortaste und dann die Eingabetaste, um die Bedienungshilfen in den Chrome-Einstellungen zu personalisieren</translation>
<translation id="6233160458685643793">Grinsen</translation>
<translation id="6234122620015464377">Nach jedem Dokument zuschneiden</translation>
<translation id="6240447795304464094">Google Pay-Logo</translation>
<translation id="6241121617266208201">Vorschläge ausblenden</translation>
<translation id="624499991300733384">Druck-Setzdienst</translation>
-<translation id="6252613631861574218"><ph name="MANAGE_CHROME_DOWNLOADS_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücken Sie die Tabulatortaste und dann die Eingabetaste, um in Chrome heruntergeladene Dateien zu verwalten</translation>
+<translation id="6252613631861574218"><ph name="MANAGE_CHROME_DOWNLOADS_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücke die Tabulatortaste und dann die Eingabetaste, um in Chrome heruntergeladene Dateien zu verwalten</translation>
<translation id="6254436959401408446">Nicht genügend Speicher, um diese Seite zu öffnen</translation>
<translation id="6259156558325130047">&amp;Neu anordnen rückgängig machen</translation>
<translation id="6263376278284652872"><ph name="DOMAIN" />-Lesezeichen</translation>
<translation id="6264485186158353794">Zurück zu sicherer Website</translation>
<translation id="6265794661083428563">Den Wert der Richtlinie <ph name="POLICY_NAME" /> kopieren</translation>
<translation id="6266934640124581640">Helles Blaugrün</translation>
-<translation id="6272088941196661550">Sie können weiter stöbern, um relevante Aktivitäten in Ihrem Chrome-Verlauf zu sehen</translation>
+<translation id="6272088941196661550">Du kannst weiter stöbern, um relevante Aktivitäten in deinem Chrome-Verlauf zu sehen</translation>
<translation id="6272383483618007430">Google Update</translation>
-<translation id="6276112860590028508">Seiten von Ihrer Leseliste werden hier angezeigt</translation>
-<translation id="627746635834430766">Damit Zahlungen zukünftig schneller abgewickelt werden können, speichern Sie Ihre Kreditkartendaten und Ihre Rechnungsadresse in Ihrem Google-Konto.</translation>
-<translation id="6279098320682980337">Wurde die virtuelle Kartennummer nicht eingefügt? Klicken Sie auf die Kartendetails, um sie zu kopieren.</translation>
-<translation id="6280223929691119688">Die Lieferadresse wird nicht unterstützt. Bitte wählen Sie eine andere Adresse aus.</translation>
+<translation id="6276112860590028508">Seiten von deiner Leseliste werden hier angezeigt</translation>
+<translation id="627746635834430766">Damit Zahlungen zukünftig schneller abgewickelt werden können, speichere deine Kreditkartendaten und deine Rechnungsadresse in deinem Google-Konto.</translation>
+<translation id="6279183038361895380">Zum Einblenden des Cursors |<ph name="ACCELERATOR" />| drücken</translation>
+<translation id="6280223929691119688">Die Lieferadresse wird nicht unterstützt. Bitte wähle eine andere Adresse aus.</translation>
<translation id="6282194474023008486">Postleitzahl</translation>
-<translation id="6285507000506177184">Schaltfläche zum Verwalten von Downloads in Chrome – drücken Sie die Eingabetaste, um in Chrome heruntergeladene Dateien zu verwalten</translation>
+<translation id="6285507000506177184">Schaltfläche zum Verwalten von Downloads in Chrome – drücke die Eingabetaste, um in Chrome heruntergeladene Dateien zu verwalten</translation>
<translation id="6289939620939689042">Seitenfarbe</translation>
-<translation id="6290238015253830360">Hier werden Ihre vorgeschlagenen Artikel angezeigt</translation>
+<translation id="6290238015253830360">Hier werden deine vorgeschlagenen Artikel angezeigt</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{Dein Gerät startet jetzt neu}=1{Dein Gerät startet in 1 Sekunde neu}other{Dein Gerät startet in # Sekunden neu}}</translation>
<translation id="6302269476990306341">Google Assistant für Chrome wird beendet</translation>
<translation id="6305205051461490394"><ph name="URL" /> ist nicht erreichbar.</translation>
<translation id="6312113039770857350">Webseite nicht verfügbar</translation>
<translation id="63172326633386613">Einstellungen für Bedienungshilfen verwalten</translation>
-<translation id="6321917430147971392">Überprüfen Sie die DNS-Einstellungen.</translation>
+<translation id="6321917430147971392">Überprüfe die DNS-Einstellungen.</translation>
<translation id="6322182122604171028">Windows Hello konnte nicht verwendet werden</translation>
-<translation id="6328639280570009161">Deaktivieren Sie die Netzwerkvorhersage.</translation>
+<translation id="6328639280570009161">Deaktiviere die Netzwerkvorhersage.</translation>
<translation id="6328784461820205019">"Dies ist keine sichere Verbindung" oder "&lt;span class="error-code"&gt;NET::ERR_CERT_AUTHORITY_INVALID&lt;/span&gt;" oder "&lt;span class="error-code"&gt;ERR_CERT_COMMON_NAME_INVALID&lt;/span&gt;" oder "&lt;span class="error-code"&gt;NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM&lt;/span&gt;" oder "&lt;span class="error-code"&gt;ERR_CERT_SYMANTEC_LEGACY&lt;/span&gt;" oder "SSL-Zertifikatfehler"</translation>
-<translation id="6328786501058569169">Sie befinden sich auf einer betrügerischen Website</translation>
+<translation id="6328786501058569169">Du befindest dich auf einer betrügerischen Website</translation>
<translation id="6337133576188860026">Es werden weniger als <ph name="SIZE" /> Speicherplatz freigegeben. Manche Websites werden beim nächsten Öffnen eventuell langsamer geladen.</translation>
<translation id="6337534724793800597">Richtlinien nach Name filtern</translation>
<translation id="6340739886198108203">Gemäß der Administratorrichtlinie wird nicht empfohlen, Screenshots oder Aufnahmen zu machen, wenn vertrauliche Inhalte zu sehen sind:</translation>
@@ -1673,11 +1713,11 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="6393956493820063117">Die Administratorrichtlinie blockiert das Einfügen von Inhalten aus <ph name="ORIGIN_NAME" /> an dieser Stelle</translation>
<translation id="6398277657359595425">Laut weinen</translation>
<translation id="6398765197997659313">Vollbildmodus beenden</translation>
-<translation id="6401136357288658127">Diese Richtlinie ist veraltet. Verwenden Sie stattdessen die Richtlinie "<ph name="NEW_POLICY" />".</translation>
+<translation id="6401136357288658127">Diese Richtlinie ist veraltet. Verwende stattdessen die Richtlinie "<ph name="NEW_POLICY" />".</translation>
<translation id="6404511346730675251">Lesezeichen bearbeiten</translation>
<translation id="6406765186087300643">C0 (Umschlag)</translation>
<translation id="6410264514553301377">Ablaufdatum und CVC für <ph name="CREDIT_CARD" /> eingeben</translation>
-<translation id="6415778972515849510">Mithilfe von Chromium können Sie Ihr Google-Konto schützen und Ihr Passwort ändern.</translation>
+<translation id="6415778972515849510">Mithilfe von Chromium kannst du dein Google-Konto schützen und dein Passwort ändern.</translation>
<translation id="6423385022588644828">Karten mithilfe von Touch ID ab sofort schneller bestätigen</translation>
<translation id="6425092077175753609">Material</translation>
<translation id="6427730057873428458">Fensterfaltung</translation>
@@ -1687,7 +1727,7 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="6433595998831338502"><ph name="HOST_NAME" /> hat die Verbindung abgelehnt.</translation>
<translation id="6438025220577812695">Selbst ändern</translation>
<translation id="6440503408713884761">Ignoriert</translation>
-<translation id="6443406338865242315">Welche Erweiterungen und Plug-ins Sie installiert haben</translation>
+<translation id="6443406338865242315">Welche Erweiterungen und Plug-ins du installiert hast</translation>
<translation id="6446163441502663861">Kahu (Umschlag)</translation>
<translation id="6446608382365791566">Weitere Informationen hinzufügen</translation>
<translation id="6447842834002726250">Cookies</translation>
@@ -1715,6 +1755,7 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="6529602333819889595">&amp;Löschen wiederholen</translation>
<translation id="6545864417968258051">Bluetooth-Suche</translation>
<translation id="6547208576736763147">Doppelte Lochung links</translation>
+<translation id="6554732001434021288">Vor <ph name="NUM_DAYS" /> Tagen zuletzt besucht</translation>
<translation id="6556866813142980365">Wiederholen</translation>
<translation id="6569060085658103619">Dies ist eine Erweiterungsseite</translation>
<translation id="6573200754375280815">Doppelte Lochung rechts</translation>
@@ -1722,10 +1763,10 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="6579630537141957243">MIDI-Gerät verbinden?</translation>
<translation id="6579990219486187401">Hellrosa</translation>
<translation id="6583674473685352014">B6 (Umschlag)</translation>
-<translation id="6587182488465657433">Chrome hat das Passwort, das Sie gerade verwendet haben, in einer Datenpanne gefunden. Wir empfehlen Ihnen, es jetzt zu ändern, und dann Ihre gespeicherten Passwörter zu prüfen, um Ihre Konten besser zu schützen.</translation>
-<translation id="6587923378399804057">Von Ihnen kopierter Link</translation>
-<translation id="6591833882275308647">Ihr <ph name="DEVICE_TYPE" /> wird nicht verwaltet</translation>
-<translation id="6592952801936330159">Schaltfläche zum Verwalten der Website-Einstellungen – drücken Sie die Eingabetaste, um Berechtigungen und gespeicherte Daten von Websites in den Chrome-Einstellungen zu verwalten</translation>
+<translation id="6587182488465657433">Chrome hat das Passwort, das du gerade verwendet hast, in einer Datenpanne gefunden. Wir empfehlen dir, es jetzt zu ändern, und dann deine gespeicherten Passwörter zu prüfen, um deine Konten besser zu schützen.</translation>
+<translation id="6587923378399804057">Von dir kopierter Link</translation>
+<translation id="6591833882275308647">Dein <ph name="DEVICE_TYPE" /> wird nicht verwaltet</translation>
+<translation id="6592952801936330159">Schaltfläche zum Verwalten der Website-Einstellungen – drücke die Eingabetaste, um Berechtigungen und gespeicherte Daten von Websites in den Chrome-Einstellungen zu verwalten</translation>
<translation id="6596325263575161958">Verschlüsselungsoptionen</translation>
<translation id="6609880536175561541">Prc7 (Umschlag)</translation>
<translation id="6615297766614333076">Stapelfach 2</translation>
@@ -1733,12 +1774,12 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="6626291197371920147">Gültige Kartennummer hinzufügen</translation>
<translation id="6628463337424475685"><ph name="ENGINE" />-Suche</translation>
<translation id="6630043285902923878">USB-Geräte werden gesucht…</translation>
-<translation id="6630809736994426279">Zurzeit auf <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> befindliche Hacker könnten versuchen, gefährliche Programme auf Ihrem Mac zu installieren, um Daten wie Fotos, Passwörter, Nachrichten und Kreditkartendaten zu stehlen oder zu löschen. <ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="6630809736994426279">Zurzeit auf <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> befindliche Hacker könnten versuchen, gefährliche Programme auf deinem Mac zu installieren, um Daten wie Fotos, Passwörter, Nachrichten und Kreditkartendaten zu stehlen oder zu löschen. <ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="663260587451432563">JIS B4</translation>
<translation id="6643016212128521049">Löschen</translation>
<translation id="6645291930348198241">Auf Cookies und Websitedaten zugreifen.</translation>
<translation id="6646269444027925224">{COUNT,plural, =0{Keine}=1{1 Website (Anmeldung in Google-Konto bleibt erhalten)}other{# Websites (Anmeldung in Google-Konto bleibt erhalten)}}</translation>
-<translation id="6648459603387803038">Ihr Administrator kann die Browsereinstellungen per Remotezugriff ändern. Aktivitäten auf diesem Gerät können auch außerhalb von Chrome verwaltet werden.</translation>
+<translation id="6648459603387803038">Dein Administrator kann die Browsereinstellungen per Remotezugriff ändern. Aktivitäten auf diesem Gerät können auch außerhalb von Chrome verwaltet werden.</translation>
<translation id="6648524591329069940">Schriftart Serif</translation>
<translation id="6651270836885078973">Verwaltet von:</translation>
<translation id="6652101503459149953">Windows Hello verwenden</translation>
@@ -1752,30 +1793,29 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="6685834062052613830">Abmelden und Einrichtung abschließen</translation>
<translation id="6687335167692595844">Gewünschte Schriftgröße</translation>
<translation id="6688743156324860098">Aktualisieren…</translation>
-<translation id="6688775486821967877">Die virtuelle Karte ist zurzeit nicht verfügbar, bitte versuchen Sie es später noch einmal</translation>
+<translation id="6688775486821967877">Die virtuelle Karte ist zurzeit nicht verfügbar, bitte versuche es später noch einmal</translation>
<translation id="6689249931105087298">Relativ mit Schwarzpunktkompensation</translation>
-<translation id="6689271823431384964">Chrome bietet Ihnen die Möglichkeit, die Karten in Ihrem Google-Konto zu speichern, weil Sie angemeldet sind. Sie können dies in den Einstellungen ändern. Der Name des Karteninhabers stammt aus Ihrem Konto.</translation>
-<translation id="6694681292321232194"><ph name="FIND_MY_PHONE_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücken Sie die Tabulatortaste und dann die Eingabetaste, um Ihr Gerät im Google-Konto zu finden</translation>
-<translation id="6696588630955820014">Schaltfläche „Tab teilen“ – drücken Sie die Eingabetaste, um diesen Tab über den Link, über einen QR-Code, über Streamen usw. zu teilen</translation>
+<translation id="6689271823431384964">Chrome bietet dir die Möglichkeit, die Karten in deinem Google-Konto zu speichern, weil du angemeldet bist. Du kannst dies in den Einstellungen ändern. Der Name des Karteninhabers stammt aus deinem Konto.</translation>
+<translation id="6694681292321232194"><ph name="FIND_MY_PHONE_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücke die Tabulatortaste und dann die Eingabetaste, um dein Gerät im Google-Konto zu finden</translation>
+<translation id="6696588630955820014">Schaltfläche „Tab teilen“ – drücke die Eingabetaste, um diesen Tab über den Link, über einen QR-Code, über Streamen usw. zu teilen</translation>
<translation id="6698381487523150993">Erstellt:</translation>
<translation id="6702919718839027939">Präsentieren</translation>
<translation id="6710213216561001401">Zurück</translation>
<translation id="6710594484020273272">&lt;Suchbegriff eingeben&gt;</translation>
<translation id="671076103358959139">Registrierungstoken:</translation>
<translation id="6711464428925977395">Mit dem Proxyserver ist ein Problem aufgetreten oder die Adresse ist falsch.</translation>
-<translation id="6716672519412350405"><ph name="URL" /> möchte eine 3D-Karte Ihrer Umgebung erstellen und die Kameraposition verfolgen</translation>
+<translation id="6716672519412350405"><ph name="URL" /> möchte eine 3D-Karte deiner Umgebung erstellen und die Kameraposition verfolgen</translation>
<translation id="6718612893943028815">Kamera verwenden?</translation>
-<translation id="6721678857435001674">Den Hersteller und das Modell Ihres Sicherheitsschlüssels auslesen</translation>
+<translation id="6721678857435001674">Den Hersteller und das Modell deines Sicherheitsschlüssels auslesen</translation>
<translation id="6732087373923685049">Kamera</translation>
-<translation id="6738516213925468394">Ihre Daten wurden am <ph name="TIME" /> mit Ihrer <ph name="BEGIN_LINK" />Synchronisierungspassphrase<ph name="END_LINK" /> verschlüsselt. Geben Sie diese ein, um die Synchronisierung zu starten.</translation>
+<translation id="6738516213925468394">Deine Daten wurden am <ph name="TIME" /> mit deiner <ph name="BEGIN_LINK" />Synchronisierungspassphrase<ph name="END_LINK" /> verschlüsselt. Gib diese ein, um die Synchronisierung zu starten.</translation>
<translation id="674375294223700098">Fehler wegen unbekanntem Serverzertifikat</translation>
-<translation id="6744009308914054259">Während Sie auf eine Verbindung warten, können Sie "Downloads" aufrufen und Offline-Artikel lesen.</translation>
+<translation id="6744009308914054259">Während du auf eine Verbindung wartest, kannst du "Downloads" aufrufen und Offline-Artikel lesen.</translation>
<translation id="6753269504797312559">Wert der Richtlinie</translation>
<translation id="6755241357817244406">chrome://flags</translation>
-<translation id="6757797048963528358">Ihr Gerät ist im Ruhemodus.</translation>
+<translation id="6757797048963528358">Dein Gerät ist im Ruhemodus.</translation>
<translation id="6767985426384634228">Adresse aktualisieren?</translation>
<translation id="6768213884286397650">Hagaki (Postkarte)</translation>
-<translation id="6774185088257932239"><ph name="BEGIN_LINK" />Weitere Informationen<ph name="END_LINK" /> zum Inkognitomodus</translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">Violett</translation>
<translation id="6786747875388722282">Erweiterungen</translation>
@@ -1787,7 +1827,7 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="6810899417690483278">Personalisierungs-ID</translation>
<translation id="6817217109584391709">JavaScript</translation>
<translation id="6820143000046097424">Serielle Schnittstellen</translation>
-<translation id="6825578344716086703">Sie haben versucht, auf <ph name="DOMAIN" /> zuzugreifen, der Server hat jedoch ein Zertifikat übermittelt, das einen schwachen Signaturalgorithmus verwendet, zum Beispiel SHA-1. Das bedeutet, dass die vom Server übermittelten Sicherheitsinformationen gefälscht sein könnten und es sich möglicherweise gar nicht um den erwarteten Server handelt, sondern Sie mit einem Hacker kommunizieren.</translation>
+<translation id="6825578344716086703">Du hast versucht, auf <ph name="DOMAIN" /> zuzugreifen, der Server hat jedoch ein Zertifikat übermittelt, das einen schwachen Signaturalgorithmus verwendet, zum Beispiel SHA-1. Das bedeutet, dass die vom Server übermittelten Sicherheitsinformationen gefälscht sein könnten und es sich möglicherweise gar nicht um den erwarteten Server handelt, sondern du mit einem Hacker kommunizierst.</translation>
<translation id="6826993739343257035">AR zulassen?</translation>
<translation id="6831043979455480757">Ãœbersetzen</translation>
<translation id="6839929833149231406">Region</translation>
@@ -1804,25 +1844,25 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="6890443033788248019">Standortermittlung zulassen?</translation>
<translation id="6891596781022320156">Richtlinienebene wird nicht unterstützt.</translation>
<translation id="6895143722905299846">Virtuelle Nummer:</translation>
-<translation id="6895330447102777224">Ihre Karte wurde bestätigt</translation>
+<translation id="6895330447102777224">Deine Karte wurde bestätigt</translation>
<translation id="6897140037006041989">User-Agent</translation>
<translation id="6898699227549475383">Organisation (O)</translation>
<translation id="6899000063526916106"><ph name="NUMBER_OF_DIGITS" />-stelligen Code eingeben</translation>
<translation id="6907293445143367439">„<ph name="SITE_NAME" />“ Folgendes gestatten:</translation>
-<translation id="6910240653697687763"><ph name="URL" /> fordert die vollständige Kontrolle über Ihre MIDI-Geräte</translation>
+<translation id="6910240653697687763"><ph name="URL" /> fordert die vollständige Kontrolle über deine MIDI-Geräte</translation>
<translation id="691024665142758461">Mehrere Dateien herunterladen</translation>
<translation id="6915804003454593391">Nutzer: </translation>
-<translation id="6934672428414710184">Dieser Name stammt aus Ihrem Google-Konto</translation>
-<translation id="6944692733090228304">Sie haben Ihr Passwort auf einer Website eingegeben, die nicht von <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> verwaltet wird. Zum Schutz Ihres Kontos sollten Sie das Passwort nicht für andere Apps und Websites verwenden.</translation>
+<translation id="6934672428414710184">Dieser Name stammt aus deinem Google-Konto</translation>
+<translation id="6944692733090228304">Du hast dein Passwort auf einer Website eingegeben, die nicht von <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> verwaltet wird. Zum Schutz deines Kontos solltest du das Passwort nicht für andere Apps und Websites verwenden.</translation>
<translation id="6945221475159498467">Auswählen</translation>
<translation id="6946722113367118030">Denken</translation>
-<translation id="6948051842255602737">Spiel vorbei, Ihre Punktzahl ist <ph name="SCORE" />.</translation>
-<translation id="6948701128805548767">Wählen Sie eine Adresse aus, um Abholoptionen und -anforderungen zu sehen</translation>
+<translation id="6948051842255602737">Spiel vorbei, deine Punktzahl ist <ph name="SCORE" />.</translation>
+<translation id="6948701128805548767">Wähle eine Adresse aus, um Abholoptionen und -anforderungen zu sehen</translation>
<translation id="6949872517221025916">Passwort zurücksetzen</translation>
<translation id="6950684638814147129">Fehler beim Parsen des JSON-Werts: <ph name="ERROR" /></translation>
<translation id="695140971690006676">Alle zurücksetzen</translation>
<translation id="6957887021205513506">Das Zertifikat des Servers ist möglicherweise eine Fälschung.</translation>
-<translation id="6958564499836457428">Datenschutzeinstellungen in Ihrem Google-Konto verwalten</translation>
+<translation id="6958564499836457428">Datenschutzeinstellungen in deinem Google-Konto verwalten</translation>
<translation id="6961844873822989059">Darf nachfragen, ob Schriftarten verwendet werden können, die auf meinem Gerät installiert sind</translation>
<translation id="6963520811470373926">Ersetzt</translation>
<translation id="6964255747740675745">Netzwerkkonfiguration konnte nicht geparst werden (ungültige JSON-Datei).</translation>
@@ -1834,7 +1874,7 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="6971439137020188025">Schnell eine neue Präsentation in Google Präsentationen erstellen</translation>
<translation id="6972629891077993081">HID-Geräte</translation>
<translation id="6973656660372572881">Sowohl feste Proxyserver als auch eine PAC-Skript-URL sind festgelegt.</translation>
-<translation id="6973932557599545801">Ich kann Ihnen leider nicht helfen. Bitte fahren Sie alleine fort.</translation>
+<translation id="6973932557599545801">Ich kann dir leider nicht helfen. Bitte fahre alleine fort.</translation>
<translation id="6978236010531171013">Trotzdem freigeben</translation>
<translation id="6979158407327259162">Google Drive</translation>
<translation id="6979440798594660689">Stummschalten (Standard)</translation>
@@ -1849,9 +1889,9 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="7016992613359344582">Diese Belastungen können einmalig oder wiederkehrend sein und sind vielleicht nicht offensichtlich.</translation>
<translation id="7029809446516969842">Passwörter</translation>
<translation id="7030436163253143341">Zertifikat ist ungültig</translation>
-<translation id="7031646650991750659">Welche Google Play-Apps Sie installiert haben</translation>
-<translation id="7038063300915481831"><ph name="MANAGE_GOOGLE_PRIVACY_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücken Sie die Tabulatortaste und dann die Eingabetaste, um die Datenschutzeinstellungen Ihres Google-Kontos zu verwalten</translation>
-<translation id="7050187094878475250">Sie haben versucht, <ph name="DOMAIN" /> zu erreichen. Der Server hat jedoch ein Zertifikat präsentiert, dessen Gültigkeitsdauer zu lang ist, um vertrauenswürdig zu sein.</translation>
+<translation id="7031646650991750659">Welche Google Play-Apps du installiert hast</translation>
+<translation id="7038063300915481831"><ph name="MANAGE_GOOGLE_PRIVACY_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücke die Tabulatortaste und dann die Eingabetaste, um die Datenschutzeinstellungen deines Google-Kontos zu verwalten</translation>
+<translation id="7050187094878475250">Du hast versucht, <ph name="DOMAIN" /> zu erreichen. Der Server hat jedoch ein Zertifikat präsentiert, dessen Gültigkeitsdauer zu lang ist, um vertrauenswürdig zu sein.</translation>
<translation id="705310974202322020">{NUM_CARDS,plural, =1{Diese Karte kann momentan nicht gespeichert werden}other{Diese Karten können momentan nicht gespeichert werden}}</translation>
<translation id="7053983685419859001">Blockieren</translation>
<translation id="7058163556978339998"><ph name="BROWSER" /> hat verifiziert, dass <ph name="ISSUER" /> das Zertifikat dieser Website ausgestellt hat.</translation>
@@ -1859,25 +1899,30 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="706295145388601875">Adressen in den Chrome-Einstellungen hinzufügen und verwalten</translation>
<translation id="7064851114919012435">Kontaktdaten</translation>
<translation id="7068733155164172741"><ph name="OTP_LENGTH" />-stelligen Code eingeben</translation>
-<translation id="7070090581017165256">Ãœber diese Website</translation>
-<translation id="70705239631109039">Ihre Verbindung ist nicht uneingeschränkt sicher</translation>
+<translation id="70705239631109039">Deine Verbindung ist nicht uneingeschränkt sicher</translation>
<translation id="7075452647191940183">Die Anfrage ist zu groß</translation>
<translation id="7079718277001814089">Diese Website enthält Malware</translation>
-<translation id="7081308185095828845">Diese Funktion ist auf Ihrem Gerät nicht verfügbar</translation>
+<translation id="7081308185095828845">Diese Funktion ist auf deinem Gerät nicht verfügbar</translation>
<translation id="7083258188081898530">Fach 9</translation>
<translation id="7086090958708083563">Upload vom Nutzer angefordert</translation>
<translation id="7087282848513945231">Landkreis</translation>
-<translation id="7095139009144195559"><ph name="MANAGE_SITE_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücken Sie die Tabulatortaste und dann die Eingabetaste, um Berechtigungen und gespeicherte Daten von Websites in den Chrome-Einstellungen zu verwalten</translation>
+<translation id="7095139009144195559"><ph name="MANAGE_SITE_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücke die Tabulatortaste und dann die Eingabetaste, um Berechtigungen und gespeicherte Daten von Websites in den Chrome-Einstellungen zu verwalten</translation>
<translation id="7096937462164235847">Die Identität dieser Website konnte nicht überprüft werden.</translation>
<translation id="7102554173784142865">Chrome Dino spielen</translation>
<translation id="7108338896283013870">Ausblenden</translation>
-<translation id="7108634116785509031"><ph name="HOST" /> möchte Ihre Kamera verwenden</translation>
+<translation id="7108634116785509031"><ph name="HOST" /> möchte deine Kamera verwenden</translation>
<translation id="7108819624672055576">Von einer Erweiterung zugelassen</translation>
<translation id="7111012039238467737">(Gültig)</translation>
<translation id="7118618213916969306">Nach URL aus Zwischenablage suchen, <ph name="SHORT_URL" /></translation>
<translation id="7119414471315195487">Andere Tabs oder Programme schließen</translation>
-<translation id="7129409597930077180">Der Versand an diese Adresse ist nicht möglich. Bitte wählen Sie eine andere Adresse aus.</translation>
-<translation id="7132939140423847331">Ihr Administrator hat das Kopieren dieser Daten untersagt.</translation>
+<translation id="7129355289156517987">Wenn du alle Inkognitotabs in Chromium schließt, werden deine Aktivitäten auf folgenden Tabs von diesem Gerät gelöscht:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Browseraktivitäten<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Suchverlauf<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />In Formulare eingegebene Informationen<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
+<translation id="7129409597930077180">Der Versand an diese Adresse ist nicht möglich. Bitte wähle eine andere Adresse aus.</translation>
+<translation id="7132939140423847331">Dein Administrator hat das Kopieren dieser Daten untersagt.</translation>
<translation id="7135130955892390533">Status anzeigen</translation>
<translation id="7138472120740807366">Lieferoption</translation>
<translation id="7139724024395191329">Emirat</translation>
@@ -1897,31 +1942,32 @@ Sie werden sonst gemäß Ihren Datenschutzeinstellungen blockiert. Wenn Cookies
<translation id="7186367841673660872">Diese Seite wurde von<ph name="ORIGINAL_LANGUAGE" />in<ph name="LANGUAGE_LANGUAGE" />übersetzt.</translation>
<translation id="7192203810768312527">Freigabe von <ph name="SIZE" /> Speicherplatz. Manche Websites werden beim nächsten Öffnen eventuell langsamer geladen.</translation>
<translation id="719464814642662924">Visa</translation>
-<translation id="7201591969684833065">Ihr Administrator hat Zugriff auf Folgendes:</translation>
+<translation id="7201591969684833065">Dein Administrator hat Zugriff auf Folgendes:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücke die Tabulatortaste und die Eingabetaste, um einen neuen Inkognitotab zu öffnen und privat zu surfen</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> erfüllt die Sicherheitsstandards nicht.</translation>
<translation id="7210993021468939304">Linux-Aktivität innerhalb des Containers, kann Linux-Anwendungen innerhalb des Containers installieren und ausführen</translation>
<translation id="721197778055552897"><ph name="BEGIN_LINK" />Weitere Informationen<ph name="END_LINK" /> zu diesem Problem.</translation>
-<translation id="7215025035562547931">Überprüfen Sie die Richtigkeit</translation>
-<translation id="7217745192097460130">Möchten Sie zum Bestätigen und Abschließen Ihres Kaufs Touch ID verwenden?</translation>
+<translation id="7215025035562547931">Überprüfe die Richtigkeit</translation>
+<translation id="7217745192097460130">Möchtest du zum Bestätigen und Abschließen deines Kaufs Touch ID verwenden?</translation>
<translation id="7219179957768738017">Die Verbindung verwendet <ph name="SSL_VERSION" />.</translation>
<translation id="7220786058474068424">Verarbeitung läuft</translation>
<translation id="7221855153210829124">Benachrichtigungen anzeigen</translation>
-<translation id="722454870747268814">Neuer Inkognito-Tab</translation>
+<translation id="722454870747268814">Neuer Inkognitotab</translation>
<translation id="7233592378249864828">Bestätigungsblatt drucken</translation>
<translation id="7238585580608191973">SHA-256-Fingerabdruck</translation>
<translation id="7240120331469437312">Alternativer Name für den Zertifikatsinhaber</translation>
<translation id="7243010569062352439"><ph name="PASSWORDS" />; <ph name="SIGNIN_DATA" /></translation>
<translation id="724691107663265825">Malware auf nachfolgender Website</translation>
-<translation id="724975217298816891">Geben Sie das Gültigkeitsdatum und den CVC für <ph name="CREDIT_CARD" /> ein, um Ihre Kartendetails zu aktualisieren. Nach erfolgter Bestätigung werden die Kartendetails an diese Website weitergegeben.</translation>
+<translation id="724975217298816891">Gib das Gültigkeitsdatum und den CVC für <ph name="CREDIT_CARD" /> ein, um deine Kartendetails zu aktualisieren. Nach erfolgter Bestätigung werden die Kartendetails an diese Website weitergegeben.</translation>
<translation id="7251437084390964440">Die Netzwerkkonfiguration entspricht nicht dem ONC-Standard. Die Konfiguration wird unter Umständen nicht vollständig importiert.
Weitere Details:
<ph name="DEBUG_INFO" /></translation>
<translation id="7256634549594854023">Hinteres Fach</translation>
-<translation id="725866823122871198">Es kann keine private Verbindung zu <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> hergestellt werden, weil Datum und Uhrzeit Ihres Computers falsch sind (<ph name="DATE_AND_TIME" />).</translation>
+<translation id="725866823122871198">Es kann keine private Verbindung zu <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> hergestellt werden, weil Datum und Uhrzeit deines Computers falsch sind (<ph name="DATE_AND_TIME" />).</translation>
<translation id="7260504762447901703">Zugriff entziehen</translation>
<translation id="7275334191706090484">Verwaltete Lesezeichen</translation>
-<translation id="7285654172857511148"><ph name="CHANGE_GOOGLE_PASSWORD_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücken Sie die Tabulatortaste und dann die Eingabetaste, um das Passwort für Ihr Google-Konto zu ändern</translation>
+<translation id="7285654172857511148"><ph name="CHANGE_GOOGLE_PASSWORD_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücke die Tabulatortaste und dann die Eingabetaste, um das Passwort für dein Google-Konto zu ändern</translation>
<translation id="7292031607255951991">Name des Empfängers</translation>
<translation id="7298195798382681320">Empfohlen</translation>
<translation id="7300012071106347854">Kobaltblau</translation>
@@ -1929,6 +1975,7 @@ Weitere Details:
<translation id="7304562222803846232">Datenschutzeinstellungen des Google-Kontos verwalten</translation>
<translation id="7305756307268530424">Verlangsamen</translation>
<translation id="7308436126008021607">Hintergrundsynchronisierung</translation>
+<translation id="7310392214323165548">Das Gerät wird sehr bald neu gestartet</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">Hilfe bei der Verbindungsherstellung</translation>
<translation id="7323804146520582233">Abschnitt "<ph name="SECTION" />" ausblenden</translation>
@@ -1936,67 +1983,75 @@ Weitere Details:
<translation id="7334320624316649418">&amp;Neu anordnen wiederholen</translation>
<translation id="7335157162773372339">Darf nachfragen, wenn sie meine Kamera verwenden möchte</translation>
<translation id="7337248890521463931">Mehr Zeilen anzeigen</translation>
-<translation id="7337706099755338005">Nicht auf Ihrer Plattform verfügbar.</translation>
+<translation id="7337418456231055214">Wurde die virtuelle Kartennummer nicht eingefügt? Klicke auf die Kartendetails, um sie zu kopieren. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
+<translation id="7337706099755338005">Nicht auf deiner Plattform verfügbar.</translation>
<translation id="733923710415886693">Das Serverzertifikat wurde nicht über die Zertifikatstransparenz offengelegt.</translation>
<translation id="734600844861828519">11x15</translation>
<translation id="7346048084945669753">Ist zugehörig:</translation>
<translation id="7349430561505560861">A4-Extra</translation>
-<translation id="7349921148288539306">Zugelassen, bis Sie diesen Tab schließen</translation>
+<translation id="7349921148288539306">Zugelassen, bis du diesen Tab schließt</translation>
<translation id="7352651011704765696">Ein Problem ist aufgetreten.</translation>
<translation id="7353601530677266744">Befehlszeile</translation>
<translation id="7359588939039777303">Werbung blockiert.</translation>
-<translation id="7363096869660964304">Sie sind jedoch nicht unsichtbar. Der Inkognitomodus verhindert nicht, dass Informationen zu Ihren Webaktivitäten von Ihrem Arbeitgeber, Ihrem Internetanbieter oder den von Ihnen besuchten Websites erfasst werden.</translation>
-<translation id="7365596969960773405"><ph name="MANAGE_ADDRESSES_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücken Sie die Tabulatortaste und dann die Eingabetaste, um Adressen in den Chrome-Einstellungen hinzuzufügen und zu verwalten</translation>
-<translation id="7365849542400970216">Informationen zu Ihrer Gerätenutzung abrufen?</translation>
+<translation id="7363096869660964304">Du bist jedoch nicht unsichtbar. Der Inkognitomodus verhindert nicht, dass Informationen zu deinen Webaktivitäten von deinem Arbeitgeber, deinem Internetanbieter oder den von dir besuchten Websites erfasst werden.</translation>
+<translation id="7365596969960773405"><ph name="MANAGE_ADDRESSES_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücke die Tabulatortaste und dann die Eingabetaste, um Adressen in den Chrome-Einstellungen hinzuzufügen und zu verwalten</translation>
+<translation id="7365849542400970216">Informationen zu deiner Gerätenutzung abrufen?</translation>
<translation id="7366362069757178916">Zahlungs-Handler</translation>
<translation id="7372973238305370288">Suchergebnis</translation>
<translation id="7374461526650987610">Protokoll-Handler</translation>
-<translation id="7374733840632556089">Sie sehen diesen Fehler aufgrund eines Zertifikats, das auf Ihrem Gerät installiert ist. Chrome vertraut dem Zertifikat nicht, weil es Netzwerke unterbrechen und überwachen kann. Natürlich gibt es berechtigte Gründe für eine Überwachung, z. B. im Netzwerk von Schulen oder Unternehmen. Trotzdem soll sichergestellt werden, dass Sie über die Überwachung informiert sind, selbst wenn Sie sie nicht unterbinden können. Die Überwachung ist in jedem Browser und jeder Anwendung mit Webzugriff möglich.</translation>
+<translation id="7374733840632556089">Du siehst diesen Fehler aufgrund eines Zertifikats, das auf deinem Gerät installiert ist. Chrome vertraut dem Zertifikat nicht, weil es Netzwerke unterbrechen und überwachen kann. Natürlich gibt es berechtigte Gründe für eine Überwachung, z. B. im Netzwerk von Schulen oder Unternehmen. Trotzdem soll sichergestellt werden, dass du über die Überwachung informiert bist, selbst wenn du sie nicht unterbinden kannst. Die Überwachung ist in jedem Browser und jeder Anwendung mit Webzugriff möglich.</translation>
<translation id="7375818412732305729">Datei angehängt</translation>
<translation id="7377249249140280793"><ph name="RELATIVE_DATE" /> - <ph name="FULL_DATE" /></translation>
<translation id="7378594059915113390">Mediensteuerelemente</translation>
<translation id="7378627244592794276">Nein</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">Nicht zutreffend</translation>
+<translation id="7388594495505979117">{0,plural, =1{Dein Gerät startet in 1 Minute neu}other{Dein Gerät startet in # Minuten neu}}</translation>
<translation id="7390545607259442187">Karte bestätigen</translation>
<translation id="7392089738299859607">Adresse aktualisieren</translation>
<translation id="7399802613464275309">Sicherheitscheck</translation>
<translation id="7400418766976504921">URL</translation>
<translation id="7403392780200267761">Diesen Tab über den Link, über einen QR-Code, über Streamen usw. teilen</translation>
-<translation id="7403591733719184120">Ihr <ph name="DEVICE_NAME" /> wird verwaltet</translation>
-<translation id="7407424307057130981">&lt;p&gt;Sie erhalten diese Fehlermeldung, wenn auf Ihrem Windows-Computer Superfish-Software installiert ist.&lt;/p&gt;
- &lt;p&gt;Gehen Sie folgendermaßen vor, um die Software vorübergehend zu deaktivieren und auf das Web zuzugreifen. Wenn Sie die Software deaktivieren möchten, benötigen Sie Administratorrechte.&lt;/p&gt;
+<translation id="7403591733719184120">Dein <ph name="DEVICE_NAME" /> wird verwaltet</translation>
+<translation id="7407424307057130981">&lt;p&gt;Du erhältst diese Fehlermeldung, wenn auf deinem Windows-Computer Superfish-Software installiert ist.&lt;/p&gt;
+ &lt;p&gt;Gehe folgendermaßen vor, um die Software vorübergehend zu deaktivieren und auf das Web zuzugreifen. Wenn du die Software deaktivieren möchtest, benötigst du Administratorrechte.&lt;/p&gt;
&lt;ol&gt;
- &lt;li&gt;Klicken Sie auf &lt;strong&gt;Start&lt;/strong&gt;, suchen Sie nach &lt;strong&gt;Lokale Dienste anzeigen&lt;/strong&gt; und wählen Sie die Option aus.
- &lt;li&gt;Wählen Sie &lt;strong&gt;VisualDiscovery&lt;/strong&gt; aus.
- &lt;li&gt;Wählen Sie unter &lt;strong&gt;Starttyp&lt;/strong&gt; die Option &lt;strong&gt;Deaktiviert&lt;/strong&gt; aus.
- &lt;li&gt;Klicken Sie unter &lt;strong&gt;Dienststatus&lt;/strong&gt; auf &lt;strong&gt;Beenden&lt;/strong&gt;.
- &lt;li&gt;Klicken Sie auf &lt;strong&gt;Ãœbernehmen&lt;/strong&gt; und dann auf &lt;strong&gt;Ok&lt;/strong&gt;.
- &lt;li&gt;In der &lt;a href="https://support.google.com/chrome/answer/6098869"&gt;Chrome-Hilfe&lt;/a&gt; finden Sie eine Anleitung dazu, wie Sie die Software von Ihrem Computer entfernen.
+ &lt;li&gt;Klicke auf &lt;strong&gt;Start&lt;/strong&gt;, suche nach &lt;strong&gt;Lokale Dienste anzeigen&lt;/strong&gt; und wähle die Option aus.
+ &lt;li&gt;Wähle &lt;strong&gt;VisualDiscovery&lt;/strong&gt; aus.
+ &lt;li&gt;Wähle unter &lt;strong&gt;Starttyp&lt;/strong&gt; die Option &lt;strong&gt;Deaktiviert&lt;/strong&gt; aus.
+ &lt;li&gt;Klicke unter &lt;strong&gt;Dienststatus&lt;/strong&gt; auf &lt;strong&gt;Beenden&lt;/strong&gt;.
+ &lt;li&gt;Klicke auf &lt;strong&gt;Ãœbernehmen&lt;/strong&gt; und dann auf &lt;strong&gt;Ok&lt;/strong&gt;.
+ &lt;li&gt;In der &lt;a href="https://support.google.com/chrome/answer/6098869"&gt;Chrome-Hilfe&lt;/a&gt; findest du eine Anleitung dazu, wie du die Software von deinem Computer entfernst.
&lt;/ol&gt;</translation>
<translation id="741007362987735528">Wide-Format</translation>
<translation id="7410471291937727359">Hübsch</translation>
<translation id="7416351320495623771">Passwörter verwalten…</translation>
<translation id="7419106976560586862">Profilpfad</translation>
<translation id="7421067045979951561">Protokoll-Handler</translation>
-<translation id="7426022697669111648">Schaltfläche zum Anzeigen Ihres Chrome-Verlaufs – drücken Sie die Eingabetaste, um Ihren Browserverlauf in den Chrome-Einstellungen aufzurufen und zu verwalten</translation>
+<translation id="7426022697669111648">Schaltfläche zum Anzeigen deines Chrome-Verlaufs – drücke die Eingabetaste, um deinen Browserverlauf in den Chrome-Einstellungen aufzurufen und zu verwalten</translation>
<translation id="7437289804838430631">Kontaktdaten hinzufügen</translation>
<translation id="7440140511386898319">Verfügbare Offline-Inhalte</translation>
<translation id="7441627299479586546">Falsche(r) Nutzername/Domain der Richtlinie</translation>
<translation id="7442725080345379071">Helles Orange</translation>
-<translation id="7445762425076701745">Die Identität des Servers, mit dem Sie verbunden sind, kann nicht vollständig überprüft werden. Sie sind mit einem Server verbunden, dessen Name nur innerhalb Ihres Netzwerks gültig ist und dessen Eigentümerschaft von einer externen Zertifizierungsstelle nicht überprüft werden kann. Da einige Zertifizierungsstellen ungeachtet dessen dennoch Zertifikate für diese Namen ausstellen, gibt es keine Möglichkeit, sicherzustellen, dass Sie mit der gewünschten Website und nicht mit einem Angreifer verbunden sind.</translation>
+<translation id="7445762425076701745">Die Identität des Servers, mit dem du verbunden bist, kann nicht vollständig überprüft werden. Du bist mit einem Server verbunden, dessen Name nur innerhalb deines Netzwerks gültig ist und dessen Eigentümerschaft von einer externen Zertifizierungsstelle nicht überprüft werden kann. Da einige Zertifizierungsstellen ungeachtet dessen dennoch Zertifikate für diese Namen ausstellen, gibt es keine Möglichkeit, sicherzustellen, dass du mit der gewünschten Website und nicht mit einem Angreifer verbunden bist.</translation>
<translation id="7451311239929941790"><ph name="BEGIN_LINK" />Weitere Informationen<ph name="END_LINK" /> zu diesem Problem.</translation>
<translation id="7455133967321480974">Globalen Standard verwenden (Blockieren)</translation>
-<translation id="7460618730930299168">Die Filmvorführung entspricht nicht Ihrer Auswahl. Möchten Sie fortfahren?</translation>
+<translation id="7460618730930299168">Die Filmvorführung entspricht nicht deiner Auswahl. Möchtest du fortfahren?</translation>
<translation id="7469935732330206581">Dieses Formular ist nicht sicher</translation>
<translation id="7473891865547856676">Nein danke</translation>
<translation id="7481312909269577407">Vorwärts</translation>
<translation id="7485870689360869515">Keine Daten gefunden</translation>
-<translation id="7495528107193238112">Dieser Inhalt ist blockiert. Setzen Sie sich mit dem Websiteinhaber in Verbindung, um das Problem zu beheben.</translation>
-<translation id="7497998058912824456">Schaltfläche „Dokument erstellen“ – drücken Sie die Eingabetaste, um schnell ein neues Google-Dokument zu erstellen</translation>
+<translation id="7495528107193238112">Dieser Inhalt ist blockiert. Setze dich mit dem Websiteinhaber in Verbindung, um das Problem zu beheben.</translation>
+<translation id="7497998058912824456">Schaltfläche „Dokument erstellen“ – drücke die Eingabetaste, um schnell ein neues Google-Dokument zu erstellen</translation>
+<translation id="7506488012654002225">Chromium speichert folgende Daten <ph name="BEGIN_EMPHASIS" />nicht<ph name="END_EMPHASIS" />:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Den Browserverlauf
+ <ph name="LIST_ITEM" />Cookies und Websitedaten
+ <ph name="LIST_ITEM" />In Formulare eingegebene Informationen
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">Zurückgegebene Geräte-ID der Richtlinie ist leer oder entspricht nicht der aktuellen Geräte-ID</translation>
<translation id="7508870219247277067">Avocadogrün</translation>
-<translation id="7511955381719512146">Unter Umständen erfordert das verwendete WLAN, dass Sie <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> aufrufen.</translation>
+<translation id="7511955381719512146">Unter Umständen erfordert das verwendete WLAN, dass du <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> aufrufst.</translation>
<translation id="7512685745044087310">Diese Richtlinie kann nicht auf „Wahr“ eingestellt und gleichzeitig verbindlich sein. Deshalb wurde sie zu „Empfohlen“ geändert.</translation>
<translation id="7514365320538308">Herunterladen</translation>
<translation id="7518003948725431193">Für folgende Webadresse wurde keine Webseite gefunden: <ph name="URL" />.</translation>
@@ -2010,20 +2065,20 @@ Weitere Details:
<translation id="7542403920425041731">Nach erfolgter Bestätigung werden die Kartendetails an diese Website weitergegeben.</translation>
<translation id="7542995811387359312">Die Funktion zur automatischen Ausfüllung der Kreditkartendaten ist deaktiviert, da dieses Formular keine sichere Verbindung nutzt.</translation>
<translation id="7548892272833184391">Verbindungsfehler beheben</translation>
-<translation id="7549584377607005141">Damit diese Webseite richtig angezeigt wird, werden die Daten benötigt, die Sie vorher eingegeben haben. Sie können diese Daten noch einmal senden, dabei werden jedoch sämtliche Aktionen wiederholt, die vorher durch diese Seite ausgeführt wurden.</translation>
-<translation id="7550637293666041147">Ihre Nutzernamen auf dem Gerät und in Chrome</translation>
+<translation id="7549584377607005141">Damit diese Webseite richtig angezeigt wird, werden die Daten benötigt, die du vorher eingegeben hast. Du kannst diese Daten noch einmal senden, dabei werden jedoch sämtliche Aktionen wiederholt, die vorher durch diese Seite ausgeführt wurden.</translation>
+<translation id="7550637293666041147">Deine Nutzernamen auf dem Gerät und in Chrome</translation>
<translation id="755279583747225797">Testversion ist aktiv</translation>
-<translation id="7552846755917812628">Probieren Sie folgende Tipps aus:</translation>
+<translation id="7552846755917812628">Probiere folgende Tipps aus:</translation>
<translation id="7554475479213504905">Aktualisieren und trotzdem anzeigen</translation>
<translation id="7554791636758816595">Neuer Tab</translation>
<translation id="7559278538486662777">Die Größe dieser App kann nicht geändert werden.</translation>
-<translation id="7564049878696755256">Sie könnten den Zugriff auf Ihr <ph name="ORG_NAME" />-Konto verlieren oder zum Opfer von Identitätsdiebstahl werden. Chrome empfiehlt Ihnen, Ihr Passwort jetzt zu ändern.</translation>
-<translation id="7567204685887185387">Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat wurde möglicherweise in betrügerischer Absicht ausgegeben. Mögliche Gründe sind eine fehlerhafte Konfiguration oder ein Angreifer, der Ihre Verbindung abfängt.</translation>
-<translation id="7569761772822664555">Schaltfläche „Suchmaschinen verwalten“ – drücken Sie die Eingabetaste, um Ihre standardmäßige Suchmaschine und Websitesuche zu verwalten</translation>
+<translation id="7564049878696755256">Du könntest den Zugriff auf dein <ph name="ORG_NAME" />-Konto verlieren oder zum Opfer von Identitätsdiebstahl werden. Chrome empfiehlt dir, dein Passwort jetzt zu ändern.</translation>
+<translation id="7567204685887185387">Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat wurde möglicherweise in betrügerischer Absicht ausgegeben. Mögliche Gründe sind eine fehlerhafte Konfiguration oder ein Angreifer, der deine Verbindung abfängt.</translation>
+<translation id="7569761772822664555">Schaltfläche „Suchmaschinen verwalten“ – drücke die Eingabetaste, um deine standardmäßige Suchmaschine und Websitesuche zu verwalten</translation>
<translation id="7569952961197462199">Kreditkarte aus Chrome entfernen?</translation>
<translation id="7569983096843329377">Schwarz</translation>
<translation id="7575207903026901870">Schaltfläche "Vorschlag entfernen", zum Entfernen dieses Vorschlags Eingabetaste drücken</translation>
-<translation id="7578104083680115302">Mit Karten, die Sie bei Google gespeichert haben, können Sie schnell und geräteübergreifend auf Websites und in Apps bezahlen.</translation>
+<translation id="7578104083680115302">Mit Karten, die du bei Google gespeichert hast, kannst du schnell und geräteübergreifend auf Websites und in Apps bezahlen.</translation>
<translation id="7581199239021537589">Seite 2 – Y-Verschiebung des Bilds</translation>
<translation id="7582602800368606489">Schnell einen neuen Termin in Google Kalender erstellen</translation>
<translation id="7591288787774558753">Vertrauliche Inhalte freigeben?</translation>
@@ -2034,20 +2089,20 @@ Weitere Details:
<translation id="7600965453749440009"><ph name="LANGUAGE" /> nie übersetzen</translation>
<translation id="7610193165460212391">Wert liegt außerhalb des zulässigen Bereichs (<ph name="VALUE" />).</translation>
<translation id="7613889955535752492">Gültig bis: <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
-<translation id="7614494068621678628"><ph name="MANAGE_PASSWORDS_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücken Sie die Tabulatortaste und dann die Eingabetaste, um Passwörter in den Chrome-Einstellungen abzurufen und zu verwalten</translation>
-<translation id="7616645509853975347">Ihr Administrator hat Chrome Enterprise Connectors für Ihren Browser aktiviert. Diese Connectors haben Zugriff auf einen Teil Ihrer Daten.</translation>
+<translation id="7614494068621678628"><ph name="MANAGE_PASSWORDS_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücke die Tabulatortaste und dann die Eingabetaste, um Passwörter in den Chrome-Einstellungen abzurufen und zu verwalten</translation>
+<translation id="7616645509853975347">Dein Administrator hat Chrome Enterprise Connectors für deinen Browser aktiviert. Diese Connectors haben Zugriff auf einen Teil deiner Daten.</translation>
<translation id="7619838219691048931">Endblatt</translation>
<translation id="7625242817712715120">Gemäß der Administratorrichtlinie wird nicht empfohlen, diese Inhalte zu drucken</translation>
<translation id="762844065391966283">Einzeln</translation>
<translation id="7633909222644580952">Leistungsdaten und Absturzberichte</translation>
<translation id="7637571805876720304">Kreditkarte aus Chromium entfernen?</translation>
-<translation id="7637586430889951925">{COUNT,plural, =0{Keins}=1{1 Passwort in Ihrem Konto (für <ph name="DOMAIN_LIST" />)}other{# Passwörter in Ihrem Konto (für <ph name="DOMAIN_LIST" />)}}</translation>
+<translation id="7637586430889951925">{COUNT,plural, =0{Keins}=1{1 Passwort in deinem Konto (für <ph name="DOMAIN_LIST" />)}other{# Passwörter in deinem Konto (für <ph name="DOMAIN_LIST" />)}}</translation>
<translation id="7638605456503525968">Serielle Schnittstellen</translation>
<translation id="7639968568612851608">Dunkelgrau</translation>
<translation id="7647206758853451655">Druckqualität</translation>
<translation id="7648992873808071793">Dateien auf diesem Gerät speichern</translation>
<translation id="7653957176542370971">Das Dokument zur Zahlungsabwicklung ist geschlossen</translation>
-<translation id="7654909834015434372">Wenn Sie Anmerkungen bearbeiten, wechselt das Dokument zu seiner ursprünglichen Ausrichtung zurück</translation>
+<translation id="7654909834015434372">Wenn du Anmerkungen bearbeitest, wechselt das Dokument zu seiner ursprünglichen Ausrichtung zurück</translation>
<translation id="765676359832457558">Erweiterte Einstellungen ausblenden</translation>
<translation id="7658239707568436148">Abbrechen</translation>
<translation id="7659878911471462949">Freudentränen</translation>
@@ -2056,22 +2111,22 @@ Weitere Details:
<translation id="7666397036351755929">Nicht zulässig im Inkognitomodus</translation>
<translation id="7667346355482952095">Zurückgegebenes Token der Richtlinie ist leer oder entspricht nicht dem aktuellen Token</translation>
<translation id="7668654391829183341">Unbekanntes Gerät</translation>
-<translation id="7669271284792375604">Unbefugte Dritte auf dieser Website versuchen eventuell, Sie zur Installation von Programmen zu bewegen, die sich nachteilig auf Ihre Browsernutzung auswirken. Dabei kann zum Beispiel Ihre Startseite geändert werden oder es erscheinen zusätzliche Anzeigen auf von Ihnen besuchten Websites.</translation>
+<translation id="7669271284792375604">Unbefugte Dritte auf dieser Website versuchen eventuell, dich zur Installation von Programmen zu bewegen, die sich nachteilig auf deine Browsernutzung auswirken. Dabei kann zum Beispiel deine Startseite geändert werden oder es erscheinen zusätzliche Anzeigen auf von dir besuchten Websites.</translation>
<translation id="7669907849388166732">{COUNT,plural, =1{Maßnahmen, die für Daten ergriffen werden, die als vertraulich gekennzeichnet sind (eine Maßnahme seit Anmeldung). <ph name="BEGIN_LINK" />Weitere Informationen<ph name="END_LINK" />}other{Maßnahmen, die für Daten ergriffen werden, die als vertraulich gekennzeichnet sind (# Maßnahmen seit Anmeldung). <ph name="BEGIN_LINK" />Weitere Informationen<ph name="END_LINK" />}}</translation>
<translation id="7673278391011283842">Ablage 6</translation>
<translation id="7676643023259824263">Nach Text aus Zwischenablage suchen: <ph name="TEXT" /></translation>
<translation id="7679367271685653708">Browserverlauf in den Chrome-Einstellungen anzeigen und verwalten</translation>
<translation id="7682287625158474539">Versand</translation>
-<translation id="7687186412095877299">Zahlungsformulare werden mit Ihren gespeicherten Zahlungsmethoden ausgefüllt</translation>
+<translation id="7687186412095877299">Zahlungsformulare werden mit deinen gespeicherten Zahlungsmethoden ausgefüllt</translation>
<translation id="7687305263118037187">Zeitüberschreitung bei Wiederholung</translation>
<translation id="7693583928066320343">Empfangene Seitenreihenfolge</translation>
<translation id="7697066736081121494">Prc8 (Umschlag)</translation>
-<translation id="769721561045429135">Derzeit können bestimmte Karten nur auf diesem Gerät verwendet werden. Klicken Sie auf "Weiter", um sich die Karten anzusehen.</translation>
+<translation id="769721561045429135">Derzeit können bestimmte Karten nur auf diesem Gerät verwendet werden. Klicke auf "Weiter", um dir die Karten anzusehen.</translation>
<translation id="7699293099605015246">Momentan sind keine Artikel verfügbar</translation>
<translation id="7701040980221191251">Keine</translation>
<translation id="7704050614460855821"><ph name="BEGIN_LINK" />Weiter zu <ph name="SITE" /> (unsicher)<ph name="END_LINK" /></translation>
<translation id="7714464543167945231">Zertifikat</translation>
-<translation id="7716147886133743102">Von Ihrem Administrator blockiert</translation>
+<translation id="7716147886133743102">Von deinem Administrator blockiert</translation>
<translation id="7716375162095500223">Ignoriert oder noch nicht hochgeladen</translation>
<translation id="7716424297397655342">Diese Website kann nicht aus dem Cache geladen werden</translation>
<translation id="7723047071702270851">Karte bearbeiten</translation>
@@ -2101,14 +2156,13 @@ Weitere Details:
<translation id="7800304661137206267">Die Verbindung ist mit <ph name="CIPHER" /> verschlüsselt; für die Nachrichtenauthentifizierung wird <ph name="MAC" /> verwendet und als Mechanismus für den Schlüsselaustausch <ph name="KX" />.</translation>
<translation id="7802523362929240268">Website ist vertrauenswürdig</translation>
<translation id="780301667611848630">Kein Interesse</translation>
-<translation id="7805571567667010077">Wird von Ihrer Organisation verwaltet</translation>
+<translation id="7805571567667010077">Wird von deiner Organisation verwaltet</translation>
<translation id="7805768142964895445">Status</translation>
<translation id="7812922009395017822">Mir</translation>
<translation id="7813600968533626083">Vorschlag für das Formular aus Chrome entfernen?</translation>
<translation id="781440967107097262">Zwischenablage teilen?</translation>
<translation id="7815407501681723534"><ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> für "<ph name="SEARCH_STRING" />" gefunden</translation>
-<translation id="782125616001965242">Informationen über diese Website anzeigen</translation>
-<translation id="782886543891417279">Unter Umständen müssen Sie die Anmeldeseite des verwendeten WLAN-Netzwerken (<ph name="WIFI_NAME" />) aufrufen.</translation>
+<translation id="782886543891417279">Unter Umständen musst du die Anmeldeseite des verwendeten WLAN-Netzwerken (<ph name="WIFI_NAME" />) aufrufen.</translation>
<translation id="7836231406687464395">Postfix (Umschlag)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{Keine}=1{1 App (<ph name="EXAMPLE_APP_1" />)}=2{2 Apps (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}other{# Apps (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}}</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="FORMATTED_TOTAL_AMOUNT" /> <ph name="CURRENCY_CODE" /></translation>
@@ -2116,26 +2170,25 @@ Weitere Details:
<translation id="7865448901209910068">Beste Geschwindigkeit</translation>
<translation id="7871445724586827387">Passwort des Google-Kontos ändern</translation>
<translation id="7877007680666472091">geschützte Inhalts-IDs</translation>
-<translation id="7878562273885520351">Ihr Passwort könnte gefährdet sein</translation>
+<translation id="7878562273885520351">Dein Passwort könnte gefährdet sein</translation>
<translation id="7880146494886811634">Adresse speichern</translation>
<translation id="7882421473871500483">Braun</translation>
-<translation id="7887683347370398519">Prüfen Sie Ihren CVC und versuchen Sie es dann erneut.</translation>
+<translation id="7887683347370398519">Prüfe deinen CVC und versuche es dann noch einmal.</translation>
<translation id="7887885240995164102">Bild im Bild aktivieren</translation>
<translation id="7888575728750733395">Rendering Intent für Druck</translation>
-<translation id="7894280532028510793">Wenn die URL keinen Tippfehler enthält, <ph name="BEGIN_LINK" />können Sie die Netzwerkdiagnose durchführen<ph name="END_LINK" />.</translation>
+<translation id="7894280532028510793">Wenn die URL keinen Tippfehler enthält, <ph name="BEGIN_LINK" />kannst du die Netzwerkdiagnose durchführen<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (Umschlag)</translation>
-<translation id="7931318309563332511">Unbekannt</translation>
<translation id="793209273132572360">Adresse aktualisieren?</translation>
<translation id="7932579305932748336">Im­prä­g­nie­ren</translation>
-<translation id="79338296614623784">Geben Sie eine gültige Telefonnummer ein</translation>
-<translation id="7934414805353235750"><ph name="URL" /> möchte geschützte Inhalte abspielen. Die Identität Ihres Geräts wird von Google geprüft.</translation>
+<translation id="79338296614623784">Gib eine gültige Telefonnummer ein</translation>
+<translation id="7934414805353235750"><ph name="URL" /> möchte geschützte Inhalte abspielen. Die Identität deines Geräts wird von Google geprüft.</translation>
<translation id="7935318582918952113">DOM Distiller</translation>
<translation id="7937554595067888181">Läuft am <ph name="EXPIRATION_DATE_ABBR" /> ab</translation>
<translation id="7938958445268990899">Serverzertifikat ist noch nicht gültig.</translation>
<translation id="7942349550061667556">Rot</translation>
<translation id="7943893128817522649">Darf nachfragen, wenn sie automatisch mehrere Dateien herunterladen möchte</translation>
-<translation id="7947285636476623132">Prüfen Sie Ihr Ablaufjahr und versuchen Sie es dann erneut</translation>
-<translation id="7947813448670013867"><ph name="SEE_CHROME_TIPS_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücken Sie die Tabulatortaste und dann die Eingabetaste, um mehr über die Funktionen von Chrome zu erfahren</translation>
+<translation id="7947285636476623132">Prüfe das Ablaufjahr und versuche es dann erneut</translation>
+<translation id="7947813448670013867"><ph name="SEE_CHROME_TIPS_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücke die Tabulatortaste und dann die Eingabetaste, um mehr über die Funktionen von Chrome zu erfahren</translation>
<translation id="7950027195171824198">Cookie-Einstellungen in den Chrome-Einstellungen verwalten</translation>
<translation id="7951415247503192394">(32-Bit)</translation>
<translation id="7953569069500808819">Mehrere Heftklammern oben</translation>
@@ -2149,20 +2202,21 @@ Weitere Details:
<translation id="7976214039405368314">Zu viele Anfragen</translation>
<translation id="7977538094055660992">Ausgabegerät</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">Verknüpft mit</translation>
<translation id="798134797138789862">Darf nachfragen, wenn sie Virtual-Reality-Geräte und -Daten verwenden möchte</translation>
-<translation id="7984945080620862648">Sie können <ph name="SITE" /> zurzeit nicht aufrufen, weil die Website verschlüsselte Anmeldedaten gesendet hat, die von Chrome nicht verarbeitet werden können. Netzwerkfehler und Angriffe sind in der Regel nur vorübergehend, sodass die Seite wahrscheinlich später wieder funktioniert.</translation>
-<translation id="79859296434321399">ARCore installieren, um Augmented-Reality-Inhalte zu sehen</translation>
+<translation id="7984945080620862648">Du kannst <ph name="SITE" /> zurzeit nicht aufrufen, weil die Website verschlüsselte Anmeldedaten gesendet hat, die von Chrome nicht verarbeitet werden können. Netzwerkfehler und Angriffe sind in der Regel nur vorübergehend, sodass die Seite wahrscheinlich später wieder funktioniert.</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">Binden</translation>
<translation id="7992044431894087211">Die Bildschirmfreigabe mit <ph name="APPLICATION_TITLE" /> wurde fortgesetzt</translation>
<translation id="7995512525968007366">Nicht angegeben</translation>
-<translation id="800218591365569300">Versuchen Sie, andere Tabs oder Programme zu schließen, um Speicher freizugeben.</translation>
+<translation id="7998269595945679889">Schaltfläche „Inkognitotab öffnen“ – drücke die Eingabetaste, um einen neuen Inkognitotab zu öffnen und privat zu surfen</translation>
+<translation id="800218591365569300">Versuche, andere Tabs oder Programme zu schließen, um Speicher freizugeben.</translation>
<translation id="8004582292198964060">Browser</translation>
-<translation id="8012116502927253373">{NUM_CARDS,plural, =1{Diese Karte und die entsprechende Rechnungsadresse werden gespeichert. Sie können sie nutzen, wenn Sie in <ph name="USER_EMAIL" /> angemeldet sind.}other{Diese Karten und die entsprechenden Rechnungsadressen werden gespeichert. Sie können sie nutzen, wenn Sie in <ph name="USER_EMAIL" /> angemeldet sind.}}</translation>
-<translation id="8025119109950072390">Unbefugte Dritte auf dieser Website versuchen unter Umständen auf betrügerische Weise, Sie zur Installation von Software zu bewegen oder Ihnen personenbezogene Daten zu entlocken, zum Beispiel Passwörter, Telefonnummern oder Kreditkartendaten.</translation>
+<translation id="8012116502927253373">{NUM_CARDS,plural, =1{Diese Karte und die entsprechende Rechnungsadresse werden gespeichert. Du kannst sie nutzen, wenn du in <ph name="USER_EMAIL" /> angemeldet bist.}other{Diese Karten und die entsprechenden Rechnungsadressen werden gespeichert. Du kannst sie nutzen, wenn du in <ph name="USER_EMAIL" /> angemeldet bist.}}</translation>
+<translation id="8025119109950072390">Unbefugte Dritte auf dieser Website versuchen unter Umständen auf betrügerische Weise, dich zur Installation von Software zu bewegen oder dir personenbezogene Daten zu entlocken, zum Beispiel Passwörter, Telefonnummern oder Kreditkartendaten.</translation>
<translation id="8026334261755873520">Browserdaten löschen</translation>
<translation id="8027077570865220386">Fach 15</translation>
-<translation id="8028698320761417183"><ph name="CREATE_GOOGLE_FORM_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücken Sie die Tabulatortaste und dann die Eingabetaste, um schnell ein neues Formular in Google Formulare zu erstellen</translation>
+<translation id="8028698320761417183"><ph name="CREATE_GOOGLE_FORM_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücke die Tabulatortaste und dann die Eingabetaste, um schnell ein neues Formular in Google Formulare zu erstellen</translation>
<translation id="8028960012888758725">Nach Auftrag zuschneiden</translation>
<translation id="8034522405403831421">Diese Seite ist auf <ph name="SOURCE_LANGUAGE" />. In folgende Sprache übersetzen: <ph name="TARGET_LANGUAGE" />?</translation>
<translation id="8035152190676905274">Stift</translation>
@@ -2175,7 +2229,7 @@ Weitere Details:
<translation id="8052898407431791827">In Zwischenablage kopiert</translation>
<translation id="8057711352706143257">"<ph name="SOFTWARE_NAME" />" ist nicht ordnungsgemäß konfiguriert. Durch die Deinstallation von "<ph name="SOFTWARE_NAME" />" sollte das Problem behoben werden. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="8066955247577885446">Ein Fehler ist aufgetreten.</translation>
-<translation id="8067872629359326442">Sie haben Ihr Passwort gerade auf einer verdächtigen Website eingegeben. Chromium kann Ihnen helfen. Wenn Sie Ihr Passwort ändern und Google darüber informieren möchten, dass Ihr Konto gefährdet sein könnte, klicken Sie auf "Konto schützen".</translation>
+<translation id="8067872629359326442">Du hast dein Passwort gerade auf einer verdächtigen Website eingegeben. Chromium kann dir helfen. Wenn du dein Passwort ändern und Google darüber informieren möchtest, dass dein Konto gefährdet sein könnte, klicke auf "Konto schützen".</translation>
<translation id="8070439594494267500">App-Symbol</translation>
<translation id="8074253406171541171">10x13 (Umschlag)</translation>
<translation id="8075736640322370409">Schnell eine neue Google-Tabelle erstellen</translation>
@@ -2188,7 +2242,7 @@ Weitere Details:
<translation id="8090403583893450254">Größe 20</translation>
<translation id="8091372947890762290">Aktivierung auf dem Server steht noch aus.</translation>
<translation id="8092774999298748321">Dunkelviolett</translation>
-<translation id="8094917007353911263">Unter Umständen erfordert das von Ihnen verwendete Netzwerk, dass Sie <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> aufrufen.</translation>
+<translation id="8094917007353911263">Unter Umständen erfordert das von dir verwendete Netzwerk, dass du <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> aufrufst.</translation>
<translation id="809898108652741896">A6</translation>
<translation id="8100588592594801589">Die ungültigen Karten wurden entfernt</translation>
<translation id="8103161714697287722">Zahlungsmethode</translation>
@@ -2197,15 +2251,15 @@ Weitere Details:
<translation id="810875025413331850">Keine Geräte in der Nähe gefunden.</translation>
<translation id="8116925261070264013">Stummgeschaltet</translation>
<translation id="8118489163946903409">Zahlungsmethode</translation>
-<translation id="8124639700796374294">Schaltfläche „Chrome anpassen“ – drücken Sie die Eingabetaste, um das Erscheinungsbild Ihres Browsers anzupassen</translation>
-<translation id="8127301229239896662">"<ph name="SOFTWARE_NAME" />" war nicht ordnungsgemäß auf Ihrem Computer oder im Netzwerk installiert. Bitten Sie Ihren IT-Administrator, das Problem zu lösen.</translation>
+<translation id="8124639700796374294">Schaltfläche „Chrome anpassen“ – drücke die Eingabetaste, um das Erscheinungsbild deines Browsers anzupassen</translation>
+<translation id="8127301229239896662">"<ph name="SOFTWARE_NAME" />" war nicht ordnungsgemäß auf deinem Computer oder im Netzwerk installiert. Bitte deinen IT-Administrator, das Problem zu lösen.</translation>
<translation id="8131740175452115882">Bestätigen</translation>
<translation id="8148608574971654810">PDF-Version:</translation>
-<translation id="8149426793427495338">Ihr Computer ist im Ruhemodus.</translation>
+<translation id="8149426793427495338">Dein Computer ist im Ruhemodus.</translation>
<translation id="8150722005171944719">Die Datei unter <ph name="URL" /> kann nicht gelesen werden. Sie wurde möglicherweise entfernt oder verschoben oder die Dateiberechtigungen verhindern den Zugriff.</translation>
<translation id="8157295877370077682">Website verlassen</translation>
<translation id="8163866351304776260">Vierfache Lochung links</translation>
-<translation id="8175796834047840627">Chrome bietet Ihnen die Möglichkeit, die Karten in Ihrem Google-Konto zu speichern, weil Sie angemeldet sind. Sie können dies in den Einstellungen ändern.</translation>
+<translation id="8175796834047840627">Chrome bietet dir die Möglichkeit, die Karten in deinem Google-Konto zu speichern, weil du angemeldet bist. Du kannst dies in den Einstellungen ändern.</translation>
<translation id="8176440868214972690">Der Administrator dieses Geräts hat Informationen wie z. B. Einstellungen oder Richtlinien an folgende Websites gesendet.</translation>
<translation id="8184538546369750125">Globalen Standard verwenden (Zulassen)</translation>
<translation id="8190193880870196235">Wird über eine Erweiterung verwaltet</translation>
@@ -2215,6 +2269,7 @@ Weitere Details:
<translation id="8202370299023114387">Konflikt</translation>
<translation id="8206978196348664717">Prc4 (Umschlag)</translation>
<translation id="8211406090763984747">Verbindung ist sicher</translation>
+<translation id="8217240300496046857">Websites können keine Cookies verwenden, die deine Browserdaten über mehrere Websites hinweg erfassen. Einige Websites funktionieren dann möglicherweise nicht mehr richtig.</translation>
<translation id="8218327578424803826">Zugewiesener Standort: </translation>
<translation id="8220146938470311105">C7/C6 (Umschlag)</translation>
<translation id="8225771182978767009">Die Person, die diesen Computer eingerichtet hat, hat diese Website gesperrt.</translation>
@@ -2223,7 +2278,7 @@ Weitere Details:
<translation id="8232343881378637145">Plattformtemperatur</translation>
<translation id="8233773197406738106">Datei wird vorbereitet</translation>
<translation id="8238581221633243064">Seite in einem neuen Inkognitotab öffnen</translation>
-<translation id="8241707690549784388">Die gesuchte Seite hat die von Ihnen eingegebenen Informationen verwendet bzw. verarbeitet. Wenn Sie zu dieser Seite zurückgehen, wird eventuell eine schon ausgeführte Aktion wiederholt. Möchten Sie fortfahren?</translation>
+<translation id="8241707690549784388">Die gesuchte Seite hat die von dir eingegebenen Informationen verwendet bzw. verarbeitet. Wenn du zu dieser Seite zurückgehst, wird eventuell eine schon ausgeführte Aktion wiederholt. Möchtest du fortfahren?</translation>
<translation id="8241712895048303527">Auf dieser Website blockieren</translation>
<translation id="8242426110754782860">Fortfahren</translation>
<translation id="8249296373107784235">Abbrechen</translation>
@@ -2241,33 +2296,28 @@ Weitere Details:
<translation id="8277900682056760511">Das Dokument zur Zahlungsabwicklung ist geöffnet</translation>
<translation id="8280630997017109758">Fach 11</translation>
<translation id="8281084378435768645">Large-Photo</translation>
-<translation id="8282947398454257691">Ihre eindeutige Geräte-ID abrufen</translation>
+<translation id="8282947398454257691">Deine eindeutige Geräte-ID abrufen</translation>
<translation id="8284769179630993263">Safe Browsing und mehr in den Chrome-Einstellungen verwalten</translation>
<translation id="8286036467436129157">Anmelden</translation>
<translation id="8288807391153049143">Zertifikat anzeigen</translation>
-<translation id="8289355894181816810">Wenn Sie weitere Informationen dazu benötigen, kann Ihnen Ihr Netzwerkadministrator weiterhelfen.</translation>
+<translation id="8289355894181816810">Wenn du weitere Informationen dazu benötigst, kann dir dein Netzwerkadministrator weiterhelfen.</translation>
<translation id="8293206222192510085">Lesezeichen hinzufügen</translation>
<translation id="829335040383910391">Ton</translation>
<translation id="8294431847097064396">Quelle</translation>
-<translation id="8298115750975731693">Unter Umständen erfordert das verwendete WLAN (<ph name="WIFI_NAME" />), dass Sie <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> aufrufen.</translation>
+<translation id="8298115750975731693">Unter Umständen erfordert das verwendete WLAN (<ph name="WIFI_NAME" />), dass du <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> aufrufst.</translation>
<translation id="8299269255470343364">Japanisch</translation>
<translation id="8303854710873047864">Abschnitt "<ph name="SECTION" />" eingeblendet</translation>
<translation id="830498451218851433">Zur Hälfte falten</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">Installierte Apps und Häufigkeit ihrer Verwendung</translation>
+<translation id="8317207217658302555">ARCore aktualisieren?</translation>
<translation id="831997045666694187">Abends</translation>
<translation id="8321476692217554900">Benachrichtigungen</translation>
-<translation id="8328484624016508118">Nach dem Schließen aller Inkognitotabs löscht Chrome Folgendes:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Ihre Browseraktivitäten auf diesem Gerät<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Ihren Suchverlauf auf diesem Gerät<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Formulareingaben<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489">Der Zugriff auf <ph name="HOST_NAME" /> wurde verweigert</translation>
<translation id="833262891116910667">Markieren</translation>
<translation id="8339163506404995330">Seiten auf <ph name="LANGUAGE" /> werden nicht übersetzt</translation>
<translation id="8340095855084055290"><ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
-<translation id="834457929814110454">Wenn Sie die Sicherheitsrisiken kennen, können Sie <ph name="BEGIN_LINK" />diese Website aufrufen<ph name="END_LINK" />, bevor die schädlichen Programme entfernt wurden.</translation>
+<translation id="834457929814110454">Wenn du die Sicherheitsrisiken kennst, kannst du <ph name="BEGIN_LINK" />diese Website aufrufen<ph name="END_LINK" />, bevor die schädlichen Programme entfernt wurden.</translation>
<translation id="8349305172487531364">Lesezeichenleiste</translation>
<translation id="8351131234907093545">Notiz erstellen</translation>
<translation id="8355270400102541638">Kontext für lokalen Absturz:</translation>
@@ -2285,14 +2335,14 @@ Weitere Details:
<translation id="8405579342203358118">In den Chrome-Einstellungen verwalten, welche Informationen synchronisiert werden</translation>
<translation id="8409413588194360210">Zahlungs-Handler</translation>
<translation id="8412145213513410671">Abstürze (<ph name="CRASH_COUNT" />)</translation>
-<translation id="8412392972487953978">Sie müssen zweimal dieselbe Passphrase eingeben.</translation>
+<translation id="8412392972487953978">Du musst zweimal dieselbe Passphrase eingeben.</translation>
<translation id="8416694386774425977">Die Netzwerkkonfiguration ist ungültig und konnte nicht importiert werden.
Weitere Details:
<ph name="DEBUG_INFO" /></translation>
<translation id="8424582179843326029"><ph name="FIRST_LABEL" />, <ph name="SECOND_LABEL" />, <ph name="THIRD_LABEL" /></translation>
<translation id="8428213095426709021">Einstellungen</translation>
-<translation id="8431194080598727332"><ph name="MANAGE_COOKIES_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücken Sie die Tabulatortaste und dann die Eingabetaste, um Ihre Cookie-Einstellungen in den Chrome-Einstellungen zu verwalten</translation>
-<translation id="8433057134996913067">Dadurch werden Sie von den meisten Websites abgemeldet.</translation>
+<translation id="8431194080598727332"><ph name="MANAGE_COOKIES_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücke die Tabulatortaste und dann die Eingabetaste, um deine Cookie-Einstellungen in den Chrome-Einstellungen zu verwalten</translation>
+<translation id="8433057134996913067">Dadurch wirst du von den meisten Websites abgemeldet.</translation>
<translation id="8437238597147034694">&amp;Verschieben rückgängig machen</translation>
<translation id="8438476240229491014">Einstellung speichern</translation>
<translation id="8438786541497918448">Kamera und Mikrofon verwenden?</translation>
@@ -2304,7 +2354,7 @@ Weitere Details:
<translation id="8473863474539038330">Adressen</translation>
<translation id="8474910779563686872">Entwicklerdetails anzeigen</translation>
<translation id="8479754468255770962">Heftklammer unten links</translation>
-<translation id="8483780878231876732">Melden Sie sich in Chrome an, um in Ihrem Google-Konto gespeicherte Kreditkarten zu verwenden</translation>
+<translation id="8483780878231876732">Melde dich in Chrome an, um in deinem Google-Konto gespeicherte Kreditkarten zu verwenden</translation>
<translation id="8488350697529856933">Gilt für</translation>
<translation id="8490137692873530638">Stapelfach 10</translation>
<translation id="8493948351860045254">Speicherplatz freigeben</translation>
@@ -2314,21 +2364,21 @@ Weitere Details:
<translation id="8507227106804027148">Befehlszeile</translation>
<translation id="8508648098325802031">Symbol "Suche"</translation>
<translation id="8511402995811232419">Cookies verwalten</translation>
-<translation id="8522552481199248698">Mithilfe von Chrome können Sie Ihr Google-Konto schützen und Ihr Passwort ändern.</translation>
+<translation id="8519753333133776369">HID-Geräte sind von deinem Administrator zugelassen</translation>
+<translation id="8522552481199248698">Mithilfe von Chrome kannst du dein Google-Konto schützen und dein Passwort ändern.</translation>
<translation id="8530813470445476232">In den Chrome-Einstellungen Browserverlauf, Cookies und mehr löschen sowie Cache leeren</translation>
-<translation id="8533619373899488139">Unter &lt;strong&gt;chrome://policy&lt;/strong&gt; finden Sie eine Liste mit blockierten URLs und andere Richtlinien, die von Ihrem Systemadministrator festgelegt wurden.</translation>
+<translation id="8533619373899488139">Unter &lt;strong&gt;chrome://policy&lt;/strong&gt; findest du eine Liste mit blockierten URLs und andere Richtlinien, die von deinem Systemadministrator festgelegt wurden.</translation>
<translation id="8539500321752640291">Beide Berechtigungen erteilen?</translation>
<translation id="8541158209346794904">Bluetooth-Gerät</translation>
<translation id="8542014550340843547">Drei Heftklammern unten</translation>
-<translation id="8543181531796978784">Sie können ein <ph name="BEGIN_ERROR_LINK" />Erkennungsproblem melden<ph name="END_ERROR_LINK" /> oder, wenn Sie die Sicherheitsrisiken kennen, <ph name="BEGIN_LINK" />diese unsichere Website aufrufen<ph name="END_LINK" />.</translation>
+<translation id="8543181531796978784">Du kannst ein <ph name="BEGIN_ERROR_LINK" />Erkennungsproblem melden<ph name="END_ERROR_LINK" /> oder, wenn du die Sicherheitsrisiken kennst, <ph name="BEGIN_LINK" />diese unsichere Website aufrufen<ph name="END_LINK" />.</translation>
<translation id="8554010658308662631">Weitere laden</translation>
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{Berechtigung zurücksetzen}other{Berechtigungen zurücksetzen}}</translation>
<translation id="8555010941760982128">Diesen Code beim Bezahlen verwenden</translation>
-<translation id="8557066899867184262">Der CVC befindet sich auf der Rückseite Ihrer Karte.</translation>
-<translation id="8558485628462305855">ARCore aktualisieren, um Augmented-Reality-Inhalte zu sehen</translation>
-<translation id="8559762987265718583">Es kann keine private Verbindung zu <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> hergestellt werden, weil Datum und Uhrzeit Ihres Geräts falsch sind (<ph name="DATE_AND_TIME" />).</translation>
+<translation id="8557066899867184262">Der CVC befindet sich auf der Rückseite deiner Karte.</translation>
+<translation id="8559762987265718583">Es kann keine private Verbindung zu <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> hergestellt werden, weil Datum und Uhrzeit deines Geräts falsch sind (<ph name="DATE_AND_TIME" />).</translation>
<translation id="8564182942834072828">Getrennte Dokumente/nicht sortierte Kopien</translation>
-<translation id="8564985650692024650">Chromium empfiehlt, Ihr Passwort für <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> zurückzusetzen, wenn Sie es auf anderen Websites verwendet haben.</translation>
+<translation id="8564985650692024650">Chromium empfiehlt, dein Passwort für <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> zurückzusetzen, wenn du es auf anderen Websites verwendet hast.</translation>
<translation id="8574899947864779331">Touch ID verwenden, um Karten schneller zu bestätigen</translation>
<translation id="8577348305244205642">Virtuelle Karte nicht verfügbar</translation>
<translation id="858637041960032120">Weitere Nummer
@@ -2336,8 +2386,8 @@ Weitere Details:
<translation id="8589998999637048520">Beste Qualität</translation>
<translation id="8600271352425265729">Nur dieses Mal</translation>
<translation id="860043288473659153">Name des Karteninhabers</translation>
-<translation id="8606726445206553943">Ihre MIDI-Geräte verwenden</translation>
-<translation id="8617269623452051934">Informationen zu Ihrer Gerätenutzung</translation>
+<translation id="8606726445206553943">Deine MIDI-Geräte verwenden</translation>
+<translation id="8617269623452051934">Informationen zu deiner Gerätenutzung</translation>
<translation id="861775596732816396">Größe 4</translation>
<translation id="8622948367223941507">Legal-Extra</translation>
<translation id="8623885649813806493">Keine übereinstimmenden Passwörter. Alle gespeicherten Passwörter anzeigen.</translation>
@@ -2345,6 +2395,7 @@ Weitere Details:
<translation id="865032292777205197">Bewegungssensoren</translation>
<translation id="8663226718884576429">Bestellübersicht, <ph name="TOTAL_LABEL" />, weitere Details</translation>
<translation id="8666678546361132282">Englisch</translation>
+<translation id="8669306706049782872">Informationen über meine Bildschirme verwenden, um Fenster zu öffnen und zu platzieren</translation>
<translation id="867224526087042813">Signatur</translation>
<translation id="8676424191133491403">Keine Verzögerung</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, Antwort, <ph name="ANSWER" /></translation>
@@ -2355,7 +2406,7 @@ Weitere Details:
<translation id="868922510921656628">Seiten pro Satz</translation>
<translation id="869891660844655955">Ablaufdatum</translation>
<translation id="8699041776323235191">HID-Gerät</translation>
-<translation id="8699899385443889493">Schaltfläche „Chrome Dino spielen“ – drücken Sie die Eingabetaste, um Chrome Dino zu spielen</translation>
+<translation id="8699899385443889493">Schaltfläche „Chrome Dino spielen“ – drücke die Eingabetaste, um Chrome Dino zu spielen</translation>
<translation id="8703575177326907206">Die Verbindung zu <ph name="DOMAIN" /> ist nicht verschlüsselt.</translation>
<translation id="8705331520020532516">Seriennummer</translation>
<translation id="8708134712139312373">Darf nachfragen, wenn sie eine Verbindung mit Bluetooth-Geräten herstellen möchte</translation>
@@ -2368,14 +2419,15 @@ Weitere Details:
<translation id="8725066075913043281">Erneut versuchen</translation>
<translation id="8726549941689275341">Seitengröße:</translation>
<translation id="8730621377337864115">Fertig</translation>
-<translation id="8731544501227493793">Schaltfläche "Passwörter verwalten" – drücken Sie die Eingabetaste, um Passwörter in den Chrome-Einstellungen abzurufen und zu verwalten</translation>
+<translation id="8731544501227493793">Schaltfläche „Passwörter verwalten“ – drücke die Eingabetaste, um Passwörter in den Chrome-Einstellungen abzurufen und zu verwalten</translation>
<translation id="8734529307927223492">Dein <ph name="DEVICE_TYPE" /> wird von <ph name="MANAGER" /> verwaltet</translation>
-<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücken Sie die Tabulatortaste und dann die Eingabetaste, um ein neues Inkognitofenster zu öffnen und privat zu surfen</translation>
-<translation id="8738058698779197622">Zum Aufbau einer sicheren Verbindung muss die Uhrzeit richtig eingestellt sein. Der Grund hierfür ist, dass Websites sich mithilfe von Zertifikaten identifizieren, die nur für einen bestimmten Zeitraum gelten. Da die Uhrzeit Ihres Geräts falsch ist, kann Chromium diese Zertifikate nicht bestätigen.</translation>
+<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücke die Tabulatortaste und dann die Eingabetaste, um ein neues Inkognitofenster zu öffnen und privat zu surfen</translation>
+<translation id="8737685506611670901"><ph name="PROTOCOL" />-Links anstelle von <ph name="REPLACED_HANDLER_TITLE" /> öffnen</translation>
+<translation id="8738058698779197622">Zum Aufbau einer sicheren Verbindung muss die Uhrzeit richtig eingestellt sein. Der Grund hierfür ist, dass Websites sich mithilfe von Zertifikaten identifizieren, die nur für einen bestimmten Zeitraum gelten. Da die Uhrzeit deines Geräts falsch ist, kann Chromium diese Zertifikate nicht bestätigen.</translation>
<translation id="8740359287975076522">Die &lt;abbr id="dnsDefinition"&gt;DNS-Adresse&lt;/abbr&gt; von <ph name="HOST_NAME" /> wurde nicht gefunden. Eine Problemdiagnose wird durchgeführt.</translation>
-<translation id="8742371904523228557"><ph name="ONE_TIME_CODE" /> ist Ihr Code für <ph name="ORIGIN" /></translation>
+<translation id="8742371904523228557"><ph name="ONE_TIME_CODE" /> ist dein Code für <ph name="ORIGIN" /></translation>
<translation id="874918643257405732">Lesezeichen für diesen Tab erstellen</translation>
-<translation id="8751426954251315517">Bitte versuchen Sie es später noch einmal</translation>
+<translation id="8751426954251315517">Bitte versuche es später noch einmal</translation>
<translation id="8759274551635299824">Diese Karte ist abgelaufen</translation>
<translation id="87601671197631245">Diese Website nutzt eine veraltete Sicherheitskonfiguration. Hierdurch können Informationen wie etwa Passwörter, Nachrichten oder Kreditkartendaten, die an diese Website gesendet werden, in die Hände Unbefugter gelangen.</translation>
<translation id="8761567432415473239">Google Safe Browsing hat vor Kurzem <ph name="BEGIN_LINK" />schädliche Programme<ph name="END_LINK" /> auf <ph name="SITE" /> gefunden.</translation>
@@ -2384,31 +2436,32 @@ Weitere Details:
<translation id="8766943070169463815">Ansicht zum Authentifizieren der sicheren Anmeldedaten für Zahlungen ist geöffnet</translation>
<translation id="877985182522063539">A4</translation>
<translation id="8790007591277257123">&amp;Löschen wiederholen</translation>
-<translation id="8792621596287649091">Sie könnten den Zugriff auf Ihr <ph name="ORG_NAME" />-Konto verlieren oder zum Opfer von Identitätsdiebstahl werden. Chromium empfiehlt Ihnen, Ihr Passwort jetzt zu ändern.</translation>
+<translation id="8792621596287649091">Du könntest den Zugriff auf dein <ph name="ORG_NAME" />-Konto verlieren oder zum Opfer von Identitätsdiebstahl werden. Chromium empfiehlt dir, dein Passwort jetzt zu ändern.</translation>
<translation id="8792626944327216835">Mikrofon</translation>
-<translation id="8793655568873652685"><ph name="ENROLLMENT_DOMAIN" /> hat Chrome Enterprise Connectors für Ihren Browser aktiviert. Diese Connectors haben Zugriff auf einen Teil Ihrer Daten.</translation>
+<translation id="8793655568873652685"><ph name="ENROLLMENT_DOMAIN" /> hat Chrome Enterprise Connectors für deinen Browser aktiviert. Diese Connectors haben Zugriff auf einen Teil deiner Daten.</translation>
<translation id="8798099450830957504">Standard</translation>
-<translation id="8798739476508189189">Suchen Sie Browser-Flags? Aufrufen</translation>
+<translation id="8798739476508189189">Suchst du Browser-Flags? Besuche</translation>
<translation id="8805819170075074995">Listeneintrag "<ph name="LANGUAGE_ID" />": Der Eintrag wird ignoriert, weil er auch in der Richtlinie "SpellcheckLanguage" enthalten ist.</translation>
<translation id="8807160976559152894">Nach jeder Seite zuschneiden</translation>
-<translation id="8816395686387277279"><ph name="UPDATE_CHROME_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücken Sie die Tabulatortaste und dann die Eingabetaste, um Chrome über die Chrome-Einstellungen zu aktualisieren</translation>
+<translation id="8816395686387277279"><ph name="UPDATE_CHROME_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücke die Tabulatortaste und dann die Eingabetaste, um Chrome über die Chrome-Einstellungen zu aktualisieren</translation>
<translation id="8820817407110198400">Lesezeichen</translation>
<translation id="882338992931677877">Manueller Einzug</translation>
-<translation id="8834380158646307944">Schaltfläche „Inkognitofenster schließen“ – drücken Sie die Eingabetaste, um alle geöffneten Inkognitofenster zu schließen</translation>
+<translation id="8834380158646307944">Schaltfläche „Inkognitofenster schließen“ – drücke die Eingabetaste, um alle geöffneten Inkognitofenster zu schließen</translation>
<translation id="883848425547221593">Andere Lesezeichen</translation>
<translation id="884264119367021077">Versandadresse</translation>
<translation id="884923133447025588">Kein Sperrmechanismus gefunden.</translation>
+<translation id="8849262850971482943">Verwende für zusätzliche Sicherheit deine virtuelle Karte</translation>
<translation id="885730110891505394">Datenfreigabe an Google</translation>
-<translation id="8858065207712248076">Chrome empfiehlt, Ihr Passwort für <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> zurückzusetzen, wenn Sie es auf anderen Websites verwendet haben.</translation>
-<translation id="885906927438988819">Wenn die URL keinen Tippfehler enthält, <ph name="BEGIN_LINK" />können Sie die Windows-Netzwerkdiagnose durchführen<ph name="END_LINK" />.</translation>
+<translation id="8858065207712248076">Chrome empfiehlt, dein Passwort für <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> zurückzusetzen, wenn du es auf anderen Websites verwendet hast.</translation>
+<translation id="885906927438988819">Wenn die URL keinen Tippfehler enthält, <ph name="BEGIN_LINK" />kannst du die Windows-Netzwerkdiagnose durchführen<ph name="END_LINK" />.</translation>
<translation id="8866481888320382733">Fehler beim Parsen der Richtlinieneinstellungen</translation>
<translation id="8866928039507595380">Falten</translation>
<translation id="886872106311861689">B3</translation>
<translation id="8870413625673593573">Kürzlich geschlossen</translation>
<translation id="8870494189203302833">Gleiche Reihenfolge Vorderseite nach unten</translation>
<translation id="8870700989640064057">Vertrauliche Datei drucken?</translation>
-<translation id="8871553383647848643">Erscheinungsbild Ihres Browsers anpassen</translation>
-<translation id="8874824191258364635">Geben Sie eine gültige Kartennummer ein</translation>
+<translation id="8871553383647848643">Erscheinungsbild deines Browsers anpassen</translation>
+<translation id="8874824191258364635">Gib eine gültige Kartennummer ein</translation>
<translation id="8884537526797090108">Vertrauliche Inhalte können nicht aufgezeichnet werden</translation>
<translation id="8891727572606052622">Ungültiger Proxymodus</translation>
<translation id="8894794286471754040">Lange Seite zuerst</translation>
@@ -2416,41 +2469,42 @@ Weitere Details:
<translation id="890485472659500557">Engineering-C</translation>
<translation id="890493561996401738">Schaltfläche "Vorschlag entfernen", zum Entfernen Eingabetaste drücken, <ph name="REMOVE_BUTTON_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="8912362522468806198">Google-Konto</translation>
-<translation id="8913778647360618320">Schaltfläche "Zahlungsmethoden verwalten" – drücken Sie die Eingabetaste, um Zahlungen und Kreditkartendaten in den Chrome-Einstellungen zu verwalten</translation>
+<translation id="8913778647360618320">Schaltfläche „Zahlungsmethoden verwalten“ – drücke die Eingabetaste, um Zahlungen und Kreditkartendaten in den Chrome-Einstellungen zu verwalten</translation>
<translation id="8922013791253848639">Werbung auf dieser Website immer zulassen</translation>
<translation id="892588693504540538">Lochung oben rechts</translation>
-<translation id="8931333241327730545">Möchten Sie diese Karte in Ihrem Google-Konto speichern?</translation>
-<translation id="8932102934695377596">Ihre Uhr geht nach</translation>
+<translation id="8931333241327730545">Möchtest du diese Karte in deinem Google-Konto speichern?</translation>
+<translation id="8932102934695377596">Deine Uhr geht nach</translation>
<translation id="893332455753468063">Namen hinzufügen</translation>
-<translation id="8942355029279167844">Ihr Administrator hat der App "<ph name="APP_NAME" />" erlaubt, Diagnosedaten zu erheben, um die Produktqualität zu verbessern. Weitere Informationen erhalten Sie unter <ph name="BEGIN_LINK" />https://www.parallels.com/pcep<ph name="END_LINK" />.</translation>
+<translation id="8942355029279167844">Dein Administrator hat der App "<ph name="APP_NAME" />" erlaubt, Diagnosedaten zu erheben, um die Produktqualität zu verbessern. Weitere Informationen erhältst du unter <ph name="BEGIN_LINK" />https://www.parallels.com/pcep<ph name="END_LINK" />.</translation>
<translation id="8943282376843390568">Limone</translation>
<translation id="8957210676456822347">Erfassungsportal-Autorisierung</translation>
<translation id="8962950042226115166">Verdächtige Website</translation>
<translation id="8963117664422609631">Website-Einstellungen aufrufen</translation>
-<translation id="8963213021028234748"><ph name="MARKUP_1" />Vorschläge:<ph name="MARKUP_2" />Vergewissern Sie sich, dass Sie über eine Datenverbindung verfügen.<ph name="MARKUP_3" />Laden Sie diese Webseite später neu.<ph name="MARKUP_4" />Überprüfen Sie die von Ihnen eingegebene Adresse.<ph name="MARKUP_5" /></translation>
+<translation id="8963213021028234748"><ph name="MARKUP_1" />Vorschläge:<ph name="MARKUP_2" />Vergewissere dich, dass du über eine Datenverbindung verfügst.<ph name="MARKUP_3" />Lade diese Webseite später neu.<ph name="MARKUP_4" />Überprüfe die von dir eingegebene Adresse.<ph name="MARKUP_5" /></translation>
<translation id="8968766641738584599">Karte speichern</translation>
<translation id="8971063699422889582">Das Serverzertifikat ist abgelaufen.</translation>
<translation id="8975012916872825179">Enthält Informationen wie Telefonnummern, E-Mail-Adressen und Lieferadressen</translation>
-<translation id="8975263830901772334">Namen von Dateien, die Sie drucken</translation>
-<translation id="8978053250194585037">Google Safe Browsing hat kürzlich <ph name="BEGIN_LINK" />Phishingaktivitäten<ph name="END_LINK" /> auf <ph name="SITE" /> festgestellt. Phishingwebsites geben sich als andere Websites aus, um Sie zu täuschen.</translation>
+<translation id="8975263830901772334">Namen von Dateien, die du druckst</translation>
+<translation id="8978053250194585037">Google Safe Browsing hat kürzlich <ph name="BEGIN_LINK" />Phishingaktivitäten<ph name="END_LINK" /> auf <ph name="SITE" /> festgestellt. Phishingwebsites geben sich als andere Websites aus, um dich zu täuschen.</translation>
<translation id="8983003182662520383">Bei Google Pay gespeicherte Zahlungsmethoden und Adressen</translation>
-<translation id="8983369100812962543">Sie können die Größe der App jetzt ändern</translation>
-<translation id="8987245424886630962"><ph name="VIEW_CHROME_HISTORY_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücken Sie die Tabulatortaste und dann die Eingabetaste, um Ihren Browserverlauf in Chrome aufzurufen</translation>
+<translation id="8983369100812962543">Du kannst die Größe der App jetzt ändern</translation>
+<translation id="8987245424886630962"><ph name="VIEW_CHROME_HISTORY_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücke die Tabulatortaste und dann die Eingabetaste, um deinen Browserverlauf in Chrome aufzurufen</translation>
<translation id="8987927404178983737">Monat</translation>
<translation id="8989148748219918422"><ph name="ORGANIZATION" /> [<ph name="COUNTRY" />]</translation>
-<translation id="8992061558343343009">Suchen Sie die Systemversion? Gehen Sie zu</translation>
-<translation id="899688752321268742"><ph name="URL" /> möchte Informationen zu Ihrer aktiven Nutzung dieses Geräts abrufen</translation>
-<translation id="8996941253935762404">Die Website, die Sie aufrufen möchten, enthält schädliche Programme</translation>
+<translation id="8992061558343343009">Suchst du die Systemversion? Gehe zu</translation>
+<translation id="899688752321268742"><ph name="URL" /> möchte Informationen zu deiner aktiven Nutzung dieses Geräts abrufen</translation>
+<translation id="8996941253935762404">Die Website, die du aufrufen möchtest, enthält schädliche Programme</translation>
<translation id="8997023839087525404">Der Server präsentierte ein Zertifikat, das nicht gemäß der Richtlinie zur Zertifikatstransparenz öffentlich offengelegt wurde. Dies ist für einige Zertifikate jedoch eine Voraussetzung, mit der sichergestellt wird, dass sie vertrauenswürdig sind und vor Angriffen schützen.</translation>
<translation id="9001074447101275817">Für den Proxy <ph name="DOMAIN" /> sind ein Nutzername und ein Passwort erforderlich.</translation>
<translation id="9001963517402879850">Springen!</translation>
<translation id="9004367719664099443">VR-Sitzung läuft</translation>
<translation id="9005998258318286617">Fehler beim Laden des PDF-Dokuments.</translation>
<translation id="9008201768610948239">Ignorieren</translation>
+<translation id="901834265349196618">E-Mail</translation>
<translation id="9020200922353704812">Rechnungsadresse für Kreditkarte erforderlich</translation>
<translation id="9020542370529661692">Die Seite wurde übersetzt und liegt nun auf <ph name="TARGET_LANGUAGE" /> vor.</translation>
<translation id="9020742383383852663">A8</translation>
-<translation id="9021429684248523859"><ph name="SHARE_THIS_PAGE_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücken Sie die Tabulatortaste und dann die Eingabetaste, um diesen Tab über den Link, über einen QR-Code, über Streamen usw. zu teilen</translation>
+<translation id="9021429684248523859"><ph name="SHARE_THIS_PAGE_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücke die Tabulatortaste und dann die Eingabetaste, um diesen Tab über den Link, über einen QR-Code, über Streamen usw. zu teilen</translation>
<translation id="9025348182339809926">(Ungültig)</translation>
<translation id="9030265603405983977">Schwarz-weiß</translation>
<translation id="9035022520814077154">Sicherheitsfehler</translation>
@@ -2458,11 +2512,11 @@ Weitere Details:
<translation id="9038649477754266430">Vorhersagefunktion zum schnelleren Laden von Seiten verwenden
</translation>
<translation id="9039213469156557790">Außerdem enthält diese Seite andere, nicht sichere Ressourcen. Diese Ressourcen können während der Übertragung von anderen Nutzern angezeigt und von Angreifern bearbeitet werden, die das Verhalten der Seite verändern.</translation>
-<translation id="9040464167025094690">Schaltfläche „Mein Gerät finden“ – drücken Sie die Eingabetaste, um „Mein Gerät finden“ im Google-Konto aufzurufen</translation>
+<translation id="9040464167025094690">Schaltfläche „Mein Gerät finden“ – drücke die Eingabetaste, um „Mein Gerät finden“ im Google-Konto aufzurufen</translation>
<translation id="9042617223719777575">Hohe Kapazität</translation>
<translation id="9044359186343685026">Touch ID verwenden</translation>
<translation id="9045525010788763347"><ph name="RESULT_MODIFIED_DATE" /> – <ph name="RESULT_PRODUCT_SOURCE" /></translation>
-<translation id="9049981332609050619">Sie haben versucht, auf <ph name="DOMAIN" /> zuzugreifen, der Server hat sich jedoch mit einem ungültigen Zertifikat ausgewiesen.</translation>
+<translation id="9049981332609050619">Du hast versucht, auf <ph name="DOMAIN" /> zuzugreifen, der Server hat sich jedoch mit einem ungültigen Zertifikat ausgewiesen.</translation>
<translation id="9050666287014529139">Passphrase</translation>
<translation id="9056953843249698117">Store</translation>
<translation id="9062620674789239642">Eventuell wurde sie verschoben, bearbeitet oder gelöscht.</translation>
@@ -2470,20 +2524,20 @@ Weitere Details:
<translation id="9065203028668620118">Bearbeiten</translation>
<translation id="9065745800631924235">"<ph name="TEXT" />" im Verlauf suchen</translation>
<translation id="9069693763241529744">Von einer Erweiterung blockiert</translation>
-<translation id="9073799351042754113">Sie haben die Sicherheitswarnungen für diese Website deaktiviert.</translation>
+<translation id="9073799351042754113">Du hast die Sicherheitswarnungen für diese Website deaktiviert.</translation>
<translation id="9078964945751709336">Weitere Informationen erforderlich</translation>
<translation id="9080712759204168376">Bestellübersicht</translation>
<translation id="9089260154716455634">Richtlinie für Abwesenheitszeiten:</translation>
<translation id="9095388113577226029">Weitere Sprachen...</translation>
<translation id="9101630580131696064">Fach 1</translation>
-<translation id="9103872766612412690"><ph name="SITE" /> schützt Ihre Daten in der Regel durch Verschlüsselung. Als Chromium dieses Mal versuchte, eine Verbindung zu <ph name="SITE" /> herzustellen, gab die Website ungewöhnliche und falsche Anmeldedaten zurück. Entweder versucht ein Angreifer, sich als <ph name="SITE" /> auszugeben, oder die Verbindung wurde durch eine WLAN-Anmeldeseite unterbrochen. Da Chromium die Verbindung vor dem Austausch von Daten unterbrochen hat, sind Ihre Informationen weiterhin sicher.</translation>
+<translation id="9103872766612412690"><ph name="SITE" /> schützt deine Daten in der Regel durch Verschlüsselung. Als Chromium dieses Mal versuchte, eine Verbindung zu <ph name="SITE" /> herzustellen, gab die Website ungewöhnliche und falsche Anmeldedaten zurück. Entweder versucht ein Angreifer, sich als <ph name="SITE" /> auszugeben, oder die Verbindung wurde durch eine WLAN-Anmeldeseite unterbrochen. Da Chromium die Verbindung vor dem Austausch von Daten unterbrochen hat, sind deine Informationen weiterhin sicher.</translation>
<translation id="9106062320799175032">Rechnungsadresse hinzufügen</translation>
<translation id="9107467864910557787">Der Browser wird von <ph name="MANAGER" /> verwaltet</translation>
<translation id="91108059142052966">Die Administratorrichtlinie blockiert die Bildschirmfreigabe mit <ph name="APPLICATION_TITLE" />, wenn vertrauliche Inhalte sichtbar sind</translation>
<translation id="9114524666733003316">Karte wird bestätigt…</translation>
<translation id="9114581008513152754">Dieser Browser wird nicht von einem Unternehmen oder einer anderen Organisation verwaltet. Aktivitäten auf diesem Gerät werden eventuell außerhalb von Chrome verwaltet. <ph name="BEGIN_LINK" />Weitere Informationen<ph name="END_LINK" /></translation>
<translation id="9117930699067497412">Frisch</translation>
-<translation id="9118692854637641831"><ph name="HISTORY_CLUSTERS_SEARCH_FOCUSED_FRIENDLY_MATCH_TEXT" />, drücken Sie die Tabulatortaste und dann die Eingabetaste, um weiter zu stöbern und relevante Aktivitäten in Ihrem Chrome-Verlauf anzusehen</translation>
+<translation id="9118692854637641831"><ph name="HISTORY_CLUSTERS_SEARCH_FOCUSED_FRIENDLY_MATCH_TEXT" />, drücke die Tabulatortaste und dann die Eingabetaste, um weiter zu stöbern und relevante Aktivitäten in deinem Chrome-Verlauf anzusehen</translation>
<translation id="9119042192571987207">Hochgeladen</translation>
<translation id="9128016270925453879">Richtlinien wurden geladen</translation>
<translation id="9128870381267983090">Mit Netzwerk verbinden</translation>
@@ -2493,9 +2547,10 @@ Weitere Details:
<translation id="9144951720726881238">Ablaufdatum:</translation>
<translation id="9148088599418889305">Versandart auswählen</translation>
<translation id="9148507642005240123">&amp;Bearbeiten rückgängig machen</translation>
-<translation id="9150045010208374699">Ihre Kamera verwenden</translation>
-<translation id="9150685862434908345">Ihr Administrator kann die Browsereinstellungen per Remotezugriff ändern. Aktivitäten auf diesem Gerät können auch außerhalb von Chrome verwaltet werden. <ph name="BEGIN_LINK" />Weitere Informationen<ph name="END_LINK" /></translation>
+<translation id="9150045010208374699">Deine Kamera verwenden</translation>
+<translation id="9150685862434908345">Dein Administrator kann die Browsereinstellungen per Remotezugriff ändern. Aktivitäten auf diesem Gerät können auch außerhalb von Chrome verwaltet werden. <ph name="BEGIN_LINK" />Weitere Informationen<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">Aktualisiert</translation>
+<translation id="9155211586651734179">Verbundene Audio-Peripheriegeräte</translation>
<translation id="9157595877708044936">Einrichtung läuft...</translation>
<translation id="9158625974267017556">C6 (Umschlag)</translation>
<translation id="9164029392738894042">Genauigkeitsprüfung</translation>
@@ -2514,8 +2569,8 @@ Weitere Details:
<translation id="9183425211371246419"><ph name="HOST_NAME" /> verwendet ein nicht unterstütztes Protokoll.</translation>
<translation id="9191834167571392248">Lochung unten links</translation>
<translation id="9199905725844810519">Drucken ist blockiert</translation>
-<translation id="9205078245616868884">Ihre Daten sind mit Ihrer Synchronisierungspassphrase verschlüsselt. Geben Sie diese ein, um die Synchronisierung zu starten.</translation>
-<translation id="920511547311754821">Sie können den Code nicht finden? <ph name="IDS_AUTOFILL_CARD_UNMASK_OTP_INPUT_DIALOG_NEW_CODE_MESSAGE" /></translation>
+<translation id="9205078245616868884">Deine Daten sind mit deiner Synchronisierungspassphrase verschlüsselt. Gib diese ein, um die Synchronisierung zu starten.</translation>
+<translation id="920511547311754821">Du kannst den Code nicht finden? <ph name="IDS_AUTOFILL_CARD_UNMASK_OTP_INPUT_DIALOG_NEW_CODE_MESSAGE" /></translation>
<translation id="9207861905230894330">Der Artikel konnte nicht hinzugefügt werden.</translation>
<translation id="9213433120051936369">Layout anpassen</translation>
<translation id="9215416866750762878">Eine Anwendung verhindert, dass Chrome eine sichere Internetverbindung zu dieser Website herstellt</translation>
@@ -2524,21 +2579,21 @@ Weitere Details:
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">Formular leeren</translation>
<translation id="936474030629450166">Super-B</translation>
-<translation id="936602727769022409">Sie könnten den Zugriff auf Ihr Google-Konto verlieren. Chromium empfiehlt Ihnen, Ihr Passwort jetzt zu ändern. Sie werden dazu aufgefordert, sich anzumelden.</translation>
+<translation id="936602727769022409">Du könntest den Zugriff auf dein Google-Konto verlieren. Chromium empfiehlt dir, dein Passwort jetzt zu ändern. Du wirst dazu aufgefordert, dich anzumelden.</translation>
<translation id="939736085109172342">Neuer Ordner</translation>
<translation id="945522503751344254">Feedback geben</translation>
-<translation id="945855313015696284">Lesen Sie sich die unten stehenden Informationen durch und löschen Sie ungültige Karten</translation>
-<translation id="947370374845726940"><ph name="CREATE_GOOGLE_SITE_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücken Sie die Tabulatortaste und dann die Eingabetaste, um schnell eine neue Website in Google Sites zu erstellen</translation>
+<translation id="945855313015696284">Lies dir die unten stehenden Informationen durch und lösche ungültige Karten</translation>
+<translation id="947370374845726940"><ph name="CREATE_GOOGLE_SITE_FOCUSED_FRIENDLY_MATCH_TEXT" /> – drücke die Tabulatortaste und dann die Eingabetaste, um schnell eine neue Website in Google Sites zu erstellen</translation>
<translation id="950736567201356821">Dreifache Lochung oben</translation>
<translation id="961663415146723894">Bindung unten</translation>
-<translation id="962484866189421427">Dieser Inhalt könnte betrügerische Apps installieren, die scheinbar einem anderen Zweck dienen oder Daten erfassen, um Sie auszuspionieren. <ph name="BEGIN_LINK" />Trotzdem zeigen<ph name="END_LINK" /></translation>
+<translation id="962484866189421427">Dieser Inhalt könnte betrügerische Apps installieren, die scheinbar einem anderen Zweck dienen oder Daten erfassen, um dich auszuspionieren. <ph name="BEGIN_LINK" />Trotzdem zeigen<ph name="END_LINK" /></translation>
<translation id="969892804517981540">Offizieller Build</translation>
<translation id="973773823069644502">Lieferadresse hinzufügen</translation>
<translation id="975560348586398090">{COUNT,plural, =0{Keine}=1{1 Eintrag}other{# Einträge}}</translation>
<translation id="981121421437150478">Offline</translation>
<translation id="984275831282074731">Zahlungsmethoden</translation>
-<translation id="985199708454569384">&lt;p&gt;Diese Fehlermeldung wird angezeigt, wenn das Datum bzw. die Uhrzeit auf Ihrem Computer oder Mobilgerät nicht korrekt ist.&lt;/p&gt;
- &lt;p&gt;Korrigieren Sie in den Geräteeinstellungen die Uhrzeit und das Datum, um den Fehler zu beheben.&lt;/p&gt;</translation>
+<translation id="985199708454569384">&lt;p&gt;Diese Fehlermeldung wird angezeigt, wenn das Datum bzw. die Uhrzeit auf deinem Computer oder Mobilgerät nicht korrekt ist.&lt;/p&gt;
+ &lt;p&gt;Korrigiere in den Geräteeinstellungen die Uhrzeit und das Datum, um den Fehler zu beheben.&lt;/p&gt;</translation>
<translation id="985956168329721395">Prc-32K</translation>
<translation id="987264212798334818">Allgemein</translation>
<translation id="988159990683914416">Entwickler-Build</translation>
@@ -2546,10 +2601,10 @@ Weitere Details:
<translation id="991413375315957741">Bewegungs- oder Lichtsensoren</translation>
<translation id="992115559265932548"><ph name="MICROSOFT_ACTIVE_DIRECTORY" /></translation>
<translation id="992256792861109788">Rosa</translation>
-<translation id="992432478773561401">"<ph name="SOFTWARE_NAME" />" war nicht ordnungsgemäß auf Ihrem Computer oder in Ihrem Netzwerk installiert:
+<translation id="992432478773561401">"<ph name="SOFTWARE_NAME" />" war nicht ordnungsgemäß auf deinem Computer oder in deinem Netzwerk installiert:
&lt;ul&gt;
- &lt;li&gt;Deinstallieren oder deaktivieren Sie "<ph name="SOFTWARE_NAME" />".&lt;/li&gt;
- &lt;li&gt;Stellen Sie eine Verbindung zu einem anderen Netzwerk her.&lt;/li&gt;
+ &lt;li&gt;Deinstalliere oder deaktiviere "<ph name="SOFTWARE_NAME" />".&lt;/li&gt;
+ &lt;li&gt;Stelle eine Verbindung zu einem anderen Netzwerk her.&lt;/li&gt;
&lt;/ul&gt;</translation>
<translation id="994346157028146140">JIS B1</translation>
<translation id="997986563973421916">Aus Google Pay</translation>
diff --git a/chromium/components/strings/components_strings_el.xtb b/chromium/components/strings/components_strings_el.xtb
index 34d38dfe513..439cb38fb0a 100644
--- a/chromium/components/strings/components_strings_el.xtb
+++ b/chromium/components/strings/components_strings_el.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">ΠÏοβολή λεπτομεÏειών</translation>
<translation id="1030706264415084469">Ο ιστότοπος <ph name="URL" /> θέλει να αποθηκεÏσει δεδομένα μεγάλου όγκου μόνιμα στη συσκευή σας</translation>
<translation id="1032854598605920125">ΠεÏιστÏοφή Ï€Ïος τα δεξιά</translation>
+<translation id="1033329911862281889">Η Ανώνυμη πεÏιήγηση δεν σας κάνει αόÏατους στο διαδίκτυο:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Οι ιστότοποι και οι υπηÏεσίες που χÏησιμοποιοÏν μποÏοÏν να βλέπουν τις επισκέψεις.<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Οι εÏγοδότες ή τα εκπαιδευτικά ιδÏÏματα μποÏοÏν να παÏακολουθοÏν τη δÏαστηÏιότητα πεÏιήγησης.<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Οι πάÏοχοι υπηÏεσιών διαδικτÏου μποÏοÏν να παÏακολουθοÏν την επισκεψιμότητα στον ιστό.<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">ΑπενεÏγοποίηση</translation>
<translation id="1036982837258183574">Πατήστε το |<ph name="ACCELERATOR" />| για να εξέλθετε από την πλήÏη οθόνη</translation>
<translation id="1038106730571050514">Εμφάνιση Ï€Ïοτάσεων</translation>
<translation id="1038842779957582377">άγνωστο όνομα</translation>
<translation id="1041998700806130099">Μήνυμα φÏλλου εÏγασίας</translation>
<translation id="1048785276086539861">Όταν επεξεÏγάζεστε σχολιασμοÏÏ‚, αυτό το έγγÏαφο θα επιστÏέφει στην Ï€Ïοβολή μίας σελίδας.</translation>
-<translation id="1049743911850919806">Ανώνυμη πεÏιήγηση</translation>
<translation id="1050038467049342496">Κλείστε τις άλλες εφαÏμογές</translation>
<translation id="1055184225775184556">&amp;ΑναίÏεση Ï€Ïοσθήκης</translation>
<translation id="1056898198331236512">ΠÏοειδοποίηση</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">Η Ï€ÏοσωÏινή μνήμη της πολιτικής είναι εντάξει</translation>
<translation id="1130564665089811311">Κουμπί μετάφÏασης σελίδας, πατήστε Enter για μετάφÏαση της σελίδας με τη ΜετάφÏαση Google.</translation>
<translation id="1131264053432022307">Εικόνα που αντιγÏάψατε</translation>
+<translation id="1142846828089312304">Αποκλεισμός cookie Ï„Ïίτου μέÏους στην Ανώνυμη πεÏιήγηση</translation>
<translation id="1150979032973867961">Ο διακομιστής δεν μπόÏεσε να αποδείξει ότι είναι <ph name="DOMAIN" />. Το πιστοποιητικό ασφαλείας του δεν θεωÏείται έμπιστο από το λειτουÏγικό σÏστημα της συσκευής σας. Αυτό μποÏεί να οφείλεται σε λανθασμένη ÏÏθμιση ή σε κάποιον Ï„Ïίτο που επιτίθεται στη σÏνδεσή σας.</translation>
<translation id="1151972924205500581">Απαιτείται κωδικός Ï€Ïόσβασης</translation>
<translation id="1156303062776767266">Βλέπετε ένα τοπικό ή κοινόχÏηστο αÏχείο</translation>
@@ -64,7 +70,6 @@
<translation id="1178581264944972037">ΠαÏση</translation>
<translation id="1181037720776840403">ΚατάÏγηση</translation>
<translation id="1186201132766001848">Έλεγχος κωδικών Ï€Ïόσβασης</translation>
-<translation id="1195210374336998651">Μετάβαση στις Ïυθμίσεις εφαÏμογής</translation>
<translation id="1195558154361252544">Οι ειδοποιήσεις αποκλείονται αυτόματα για όλους τους ιστοτόπους εκτός από αυτοÏÏ‚ στους οποίους τις επιτÏέπετε</translation>
<translation id="1197088940767939838">ΠοÏτοκαλί</translation>
<translation id="1201402288615127009">Επόμενο</translation>
@@ -111,7 +116,7 @@
<translation id="1307966114820526988">ΛειτουÏγίες που καταÏγήθηκαν</translation>
<translation id="1308113895091915999">ΥπάÏχει διαθέσιμη Ï€ÏοσφοÏά</translation>
<translation id="1312803275555673949">ΥπάÏχουν αποδεικτικά στοιχεία;</translation>
-<translation id="131405271941274527">Η διεÏθυνση <ph name="URL" /> θέλει να στέλνει και να λαμβάνει πληÏοφοÏίες όταν ακουμπάτε το τηλέφωνό σας σε μια συσκευή NFC</translation>
+<translation id="1314311879718644478">ΠÏοβολή πεÏιεχομένου επαυξημένης Ï€Ïαγματικότητας</translation>
<translation id="1314509827145471431">Δέσιμο δεξιά</translation>
<translation id="1318023360584041678">ΑποθηκεÏτηκε στην ομάδα καÏτελών</translation>
<translation id="1319245136674974084">Îα μην εÏωτηθώ ξανά για αυτήν την εφαÏμογή</translation>
@@ -161,6 +166,7 @@
<translation id="142858679511221695">ΧÏήστης cloud</translation>
<translation id="1428729058023778569">Βλέπετε αυτήν την Ï€Ïοειδοποίηση, επειδή αυτός ο ιστότοπος δεν υποστηÏίζει HTTPS. <ph name="BEGIN_LEARN_MORE_LINK" />Μάθετε πεÏισσότεÏα<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">ΕκτÏπωση</translation>
+<translation id="1432187715652018471">Η σελίδα θέλει να κάνει εγκατάσταση ενός δείκτη χειÏÎ¹ÏƒÎ¼Î¿Ï Ï…Ï€Î·Ïεσιών.</translation>
<translation id="1432581352905426595">ΔιαχείÏιση μηχανών αναζήτησης</translation>
<translation id="1436185428532214179">ΜποÏεί να ζητά να επεξεÏγαστεί αÏχεία και φακέλους στη συσκευή σας.</translation>
<translation id="1442386063175183758">Δεξιά δίπλωση παÏάθυÏο</translation>
@@ -181,6 +187,12 @@
<translation id="1483493594462132177">Αποστολή</translation>
<translation id="1484290072879560759">Επιλογή διεÏθυνσης αποστολής</translation>
<translation id="1492194039220927094">ΠÏοώθηση πολιτικών:</translation>
+<translation id="149293076951187737">Όταν κλείνετε όλες τις καÏτέλες ανώνυμης πεÏιήγησης του Chrome, οι δÏαστηÏιότητά σας σε αυτές τις καÏτέλες διαγÏάφεται από αυτήν τη συσκευή:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ΔÏαστηÏιότητα πεÏιήγησης<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ΙστοÏικό αναζήτησης<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ΠληÏοφοÏίες που εισάγετε σε φόÏμες<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">ΕπιστÏοφή στην καÏτέλα</translation>
<translation id="1501859676467574491">Εμφάνιση καÏτών από τον ΛογαÏιασμό σας Google</translation>
<translation id="1507202001669085618">&lt;p&gt;Αυτό το σφάλμα παÏουσιάζεται εάν χÏησιμοποιείτε μια Ï€Ïλη Wi-Fi στην οποία Ï€Ïέπει να συνδέεστε, για να μποÏέσετε να πεÏιηγηθείτε στο διαδίκτυο.&lt;/p&gt;
@@ -208,6 +220,8 @@
<translation id="1559572115229829303">&lt;p&gt;Δεν είναι δυνατή η επίτευξη ιδιωτικής σÏνδεσης με τον τομέα <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> επειδή η ημεÏομηνία και η ÏŽÏα (<ph name="DATE_AND_TIME" />) της συσκευής σας είναι λανθασμένες.&lt;/p&gt;
&lt;p&gt;ΠÏοσαÏμόστε την ημεÏομηνία και την ÏŽÏα από την ενότητα &lt;strong&gt;Γενικές&lt;/strong&gt; της εφαÏμογής &lt;strong&gt;Ρυθμίσεις&lt;/strong&gt;.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">Ο διαχειÏιστής σας θα επανεκκινήσει τη συσκευή σας στις <ph name="TIME" /> στις <ph name="DATE" /></translation>
+<translation id="156703335097561114">ΠληÏοφοÏίες δικτÏωσης, όπως διευθÏνσεις, διαμόÏφωση διεπαφής και ποιότητα σÏνδεσης</translation>
<translation id="1567040042588613346">Αυτή η πολιτική λειτουÏγεί με τον αναμενόμενο Ï„Ïόπο αλλά η ίδια τιμή έχει οÏιστεί Î±Î»Î»Î¿Ï ÎºÎ±Î¹ αντικαθίσταται από αυτήν την πολιτική.</translation>
<translation id="1569487616857761740">Εισαγωγή ημεÏομηνίας λήξης</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@
<translation id="1583429793053364125">ΠαÏουσιάστηκε Ï€Ïόβλημα κατά την εμφάνιση αυτής της ιστοσελίδας.</translation>
<translation id="1586541204584340881">Ποιες επεκτάσεις έχετε εγκαταστήσει</translation>
<translation id="1588438908519853928">Κανονική λειτουÏγία</translation>
+<translation id="1589050138437146318">Εγκατάσταση ARCore;</translation>
<translation id="1592005682883173041">ΠÏόσβαση σε τοπικά δεδομένα</translation>
<translation id="1594030484168838125">Επιλογή</translation>
<translation id="160851722280695521">Παίξτε το παιχνίδι Dino Run στο Chrome</translation>
@@ -254,7 +269,7 @@
<translation id="1711234383449478798">ΠαÏαβλέφθηκε επειδή η πολιτική <ph name="POLICY_NAME" /> δεν έχει οÏιστεί σε <ph name="VALUE" />.</translation>
<translation id="1712552549805331520">Ο ιστότοπος <ph name="URL" /> θέλει να αποθηκεÏσει μόνιμα δεδομένα στον τοπικό υπολογιστή σας</translation>
<translation id="1713628304598226412">Δίσκος 2</translation>
-<translation id="1715874602234207">F</translation>
+<translation id="1715874602234207">Π</translation>
<translation id="1717218214683051432">ΑισθητήÏες κίνησης</translation>
<translation id="1717494416764505390">ΓÏαμματοκιβώτιο 3</translation>
<translation id="1718029547804390981">Το έγγÏαφο είναι πάÏα Ï€Î¿Î»Ï Î¼ÎµÎ³Î¬Î»Î¿ για σχολιασμό.</translation>
@@ -283,6 +298,7 @@
η κεφαλίδα είναι εσφαλμένη, κάτι που αποτÏέπει την εκπλήÏωση του αιτήματός σας
για τον ιστότοπο <ph name="SITE" /> από το Ï€ÏόγÏαμμα πεÏιήγησης. Οι πολιτικές Ï€Ïοέλευσης μποÏοÏν να χÏησιμοποιηθοÏν από
χειÏιστές ιστοτόπων για τη διαμόÏφωση της ασφάλειας και άλλων ιδιοτήτων ενός ιστοτόπου.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Μάθετε πεÏισσότεÏα σχετικά με την Ανώνυμη πεÏιήγηση στο Chromium<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">Οι ανοιχτές καÏτέλες σας εμφανίζονται εδώ</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -410,6 +426,7 @@
<translation id="22081806969704220">Δίσκος 3</translation>
<translation id="2212735316055980242">Η πολιτική δε βÏέθηκε</translation>
<translation id="2213606439339815911">Ανάκτηση καταχωÏίσεων…</translation>
+<translation id="2213612003795704869">Η σελίδα εκτυπώθηκε</translation>
<translation id="2215727959747642672">ΕπεξεÏγασία αÏχείου</translation>
<translation id="2218879909401188352">Οι εισβολείς στον ιστότοπο <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> θα μποÏοÏσαν να εγκαταστήσουν επικίνδυνες εφαÏμογές που Ï€ÏοκαλοÏν ζημιά στη συσκευή σας, να Ï€Ïοσθέσουν κÏυφές χÏεώσεις στον λογαÏιασμό του ÎºÎ¹Î½Î·Ï„Î¿Ï ÏƒÎ±Ï‚ ή να κλέψουν τα Ï€Ïοσωπικά στοιχεία σας. <ph name="BEGIN_LEARN_MORE_LINK" />Μάθετε πεÏισσότεÏα<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">ΧωÏίς σÏνδεση στο διαδίκτυο</translation>
@@ -419,6 +436,7 @@
<translation id="2248949050832152960">ΧÏήση WebAuthn</translation>
<translation id="2250931979407627383">Ραφή στο αÏιστεÏÏŒ άκÏο</translation>
<translation id="225207911366869382">Αυτή η πολιτική έχει καταÏγηθεί για τη συγκεκÏιμένη πολιτική.</translation>
+<translation id="2256115617011615191">Άμεση επανεκκίνηση</translation>
<translation id="2258928405015593961">Εισαγάγετε μια ημεÏομηνία λήξης στο μέλλον και δοκιμάστε ξανά.</translation>
<translation id="225943865679747347">Κωδικός σφάλματος: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">Σφάλμα HTTP</translation>
@@ -446,6 +464,7 @@
<translation id="2337852623177822836">Η ÏÏθμιση ελέγχεται από τον διαχειÏιστή σας</translation>
<translation id="2340263603246777781">Ο ιστότοπος <ph name="ORIGIN" /> επιθυμεί σÏζευξη</translation>
<translation id="2346319942568447007">Εικόνα που αντιγÏάψατε</translation>
+<translation id="2350796302381711542">Îα επιτÏέπεται στο <ph name="HANDLER_HOSTNAME" /> το άνοιγμα όλων των συνδέσμων <ph name="PROTOCOL" /> αντί για το χειÏιστή <ph name="REPLACED_HANDLER_TITLE" />;</translation>
<translation id="2354001756790975382">Άλλοι σελιδοδείκτες</translation>
<translation id="2354430244986887761">Η Ασφαλής πεÏιήγηση Google Ï€Ïόσφατα <ph name="BEGIN_LINK" />εντόπισε επιβλαβείς εφαÏμογές<ph name="END_LINK" /> στον ιστότοπο <ph name="SITE" />.</translation>
<translation id="2355395290879513365">Οι εισβολείς ενδέχεται να έχουν τη δυνατότητα να δουν τις εικόνες που Ï€Ïοβάλετε σε αυτόν τον ιστότοπο και να σας εξαπατήσουν Ï„Ïοποποιώντας τες.</translation>
@@ -471,6 +490,7 @@
<translation id="2413528052993050574">Ο διακομιστής δεν κατάφεÏε να αποδείξει ότι είναι <ph name="DOMAIN" />. Το πιστοποιητικό ασφαλείας του μποÏεί να έχει ανακληθεί. Αυτό μποÏεί να οφείλεται σε λανθασμένη ÏÏθμιση ή σε κάποιον Ï„Ïίτο που επιτίθεται στη σÏνδεσή σας.</translation>
<translation id="2414886740292270097">ΣκοÏÏο</translation>
<translation id="2430968933669123598">ΔιαχείÏιση ΛογαÏÎ¹Î±ÏƒÎ¼Î¿Ï Google, πατήστε το πλήκτÏο Enter για να διαχειÏιστείτε τις πληÏοφοÏίες, το απόÏÏητο και την ασφάλειά σας στον ΛογαÏιασμό σας Google</translation>
+<translation id="2436186046335138073">Îα επιτÏέπεται στο <ph name="HANDLER_HOSTNAME" /> το άνοιγμα όλων των συνδέσμων <ph name="PROTOCOL" />;</translation>
<translation id="2438874542388153331">ΤετÏαπλό Ï„ÏÏπημα στα δεξιά</translation>
<translation id="2450021089947420533">ΔιαδÏομές</translation>
<translation id="2463739503403862330">ΣυμπλήÏωση</translation>
@@ -478,6 +498,7 @@
<translation id="2465655957518002998">Επιλογή Ï„Ïόπου παÏάδοσης</translation>
<translation id="2465688316154986572">ΣυÏÏαφή</translation>
<translation id="2465914000209955735">ΔιαχείÏιση των αÏχείων που έχετε κατεβάσει στο Chrome.</translation>
+<translation id="2466004615675155314">Εμφάνιση πληÏοφοÏιών από τον ιστό</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Îα εκτελέσετε τον Διαγνωστικό έλεγχο δικτÏου<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">ΣειÏά 1 Ï€Ïος N</translation>
<translation id="2470767536994572628">Όταν επεξεÏγάζεστε σχολιασμοÏÏ‚, αυτό το έγγÏαφο θα επιστÏέφει στην Ï€Ïοβολή μίας σελίδας και στην αÏχική του πεÏιστÏοφή.</translation>
@@ -498,6 +519,7 @@
<translation id="2523886232349826891">ΑποθηκεÏτηκε μόνο σε αυτήν τη συσκευή</translation>
<translation id="2524461107774643265">ΠÏοσθήκη πεÏισσότεÏων πληÏοφοÏιών</translation>
<translation id="2529899080962247600">Αυτό το πεδίο δεν θα Ï€Ïέπει να έχει πεÏισσότεÏες από <ph name="MAX_ITEMS_LIMIT" /> καταχωÏίσεις. Τυχόν επιπλέον καταχωÏίσεις θα παÏαβλέπονται.</translation>
+<translation id="2535585790302968248">Ανοίξτε μια νέα καÏτέλα ανώνυμης πεÏιήγησης για ιδιωτική πεÏιήγηση</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{και 1 ακόμα}other{και # ακόμα}}</translation>
<translation id="2536110899380797252">ΠÏοσθήκη διεÏθυνσης</translation>
<translation id="2539524384386349900">ΑναγνώÏιση</translation>
@@ -523,7 +545,14 @@
<translation id="2597378329261239068">Αυτό το έγγÏαφο Ï€ÏοστατεÏεται με κωδικό Ï€Ïόσβασης. ΠληκτÏολογήστε έναν κωδικό Ï€Ïόσβασης.</translation>
<translation id="2609632851001447353">ΠαÏαλλαγές</translation>
<translation id="2610561535971892504">Κλικ για αντιγÏαφή</translation>
+<translation id="2617988307566202237">Το Chrome <ph name="BEGIN_EMPHASIS" />δεν θα αποθηκεÏει<ph name="END_EMPHASIS" /> τις παÏακάτω πληÏοφοÏίες:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Το ιστοÏικό πεÏιήγησής σας
+ <ph name="LIST_ITEM" />Cookie και δεδομένα ιστοτόπου
+ <ph name="LIST_ITEM" />ΠληÏοφοÏίες που εισάγετε σε φόÏμες
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (Φάκελος)</translation>
+<translation id="2623663032199728144">ΜποÏεί να αιτηθεί τη χÏήση πληÏοφοÏιών σχετικά με τις οθόνες σας</translation>
<translation id="2625385379895617796">Το Ïολόι σας πάει μπÏοστά</translation>
<translation id="262745152991669301">ΜποÏεί να ζητά να συνδεθεί σε συσκευές USB.</translation>
<translation id="2629325967560697240">Για να λάβετε το υψηλότεÏο επίπεδο ασφάλειας του Chrome, <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />ενεÏγοποιήστε τη βελτιωμένη Ï€Ïοστασία<ph name="END_ENHANCED_PROTECTION_LINK" />.</translation>
@@ -557,6 +586,7 @@
<translation id="2709516037105925701">Αυτόματη συμπλήÏωση</translation>
<translation id="2713444072780614174">Λευκό</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />, πατήστε Tab και έπειτα Enter για να διαχειÏιστείτε τα στοιχεία πληÏωμών και πιστωτικών καÏτών στις Ïυθμίσεις του Chrome.</translation>
+<translation id="271663710482723385">Πατήστε |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| για έξοδο από την πλήÏη οθόνη</translation>
<translation id="2721148159707890343">Το αίτημα ήταν επιτυχές</translation>
<translation id="2723669454293168317">Εκτέλεση ελέγχου ασφαλείας στις Ïυθμίσεις του Chrome</translation>
<translation id="2726001110728089263">ΠλευÏικός Ï„Ïοφοδότης χαÏτιοÏ</translation>
@@ -587,6 +617,7 @@
<translation id="2850739647070081192">Invite (Φάκελος)</translation>
<translation id="2856444702002559011">Οι εισβολείς ενδέχεται να Ï€Ïοσπαθήσουν να υποκλέψουν τα στοιχεία σας από τον ιστότοπο <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (για παÏάδειγμα, κωδικοÏÏ‚ Ï€Ïόσβασης, μηνÏματα ή πιστωτικές κάÏτες). <ph name="BEGIN_LEARN_MORE_LINK" />Μάθετε πεÏισσότεÏα<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">Αυτός ο ιστότοπος εμφανίζει παÏεμβατικές ή παÏαπλανητικές διαφημίσεις.</translation>
+<translation id="286512204874376891">Μια εικονική κάÏτα κÏÏβει την Ï€Ïαγματική κάÏτα, Ï€Ïοκειμένου να σας Ï€ÏοστατεÏει από πιθανή απάτη. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">Φιλικό</translation>
<translation id="2876489322757410363">Έξοδος από την κατάσταση ανώνυμης πεÏιήγησης για πληÏωμή μέσω εξωτεÏικής εφαÏμογής. Θέλετε να συνεχίστε;</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />, πατήστε το πλήκτÏο Tab και έπειτα το πλήκτÏο Enter για να διαχειÏιστείτε την Ασφαλή πεÏιήγηση και άλλες επιλογές από τις Ïυθμίσεις του Chrome</translation>
@@ -611,6 +642,7 @@
<translation id="2930577230479659665">ΠεÏικοπή μετά από κάθε αντίγÏαφο</translation>
<translation id="2932085390869194046">ΠÏόταση για κωδικό Ï€Ïόσβασης…</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019">Άνοιγμα συνδέσμων <ph name="PROTOCOL" /></translation>
<translation id="2941952326391522266">Ο διακομιστής δεν μπόÏεσε να αποδείξει ότι είναι <ph name="DOMAIN" />. Το πιστοποιητικό ασφαλείας του είναι από το <ph name="DOMAIN2" />. Αυτό μποÏεί να οφείλεται σε λανθασμένη ÏÏθμιση ή σε κάποιον Ï„Ïίτο που επιτίθεται στη σÏνδεσή σας.</translation>
<translation id="2943895734390379394">ÎÏα μεταφόÏτωσης:</translation>
<translation id="2948083400971632585">ΜποÏείτε να απενεÏγοποιήσετε τυχόν διακομιστές μεσολάβησης που έχουν διαμοÏφωθεί για μια σÏνδεση από τη σελίδα Ïυθμίσεων.</translation>
@@ -643,6 +675,7 @@
<translation id="3037605927509011580">Όπα! Κάτι πήγε στÏαβά!</translation>
<translation id="3041612393474885105">ΠληÏοφοÏίες πιστοποιητικοÏ</translation>
<translation id="3044034790304486808">Συνέχιση της έÏευνάς σας</translation>
+<translation id="305162504811187366">ΙστοÏικό της ΑπομακÏυσμένης επιφάνειας εÏγασίας Chrome, συμπεÏιλαμβανομένων χÏονικών σημάνσεων, κεντÏικών υπολογιστών και αναγνωÏιστικών πεÏιόδου λειτουÏγίας εφαÏμογών πελατών</translation>
<translation id="3060227939791841287">C9 (Φάκελος)</translation>
<translation id="3061707000357573562">ΥπηÏεσία ενημέÏωσης κώδικα</translation>
<translation id="306573536155379004">Το παιχνίδι ξεκίνησε.</translation>
@@ -683,6 +716,7 @@
<translation id="3197136577151645743">ΜποÏεί να ζητά να γνωÏίζει πότε χÏησιμοποιείτε ενεÏγά αυτήν τη συσκευή.</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />, πατήστε Tab και μετά Enter για να διαχειÏιστείτε τις πληÏοφοÏίες που συγχÏονίζετε από τις Ïυθμίσεις Chrome</translation>
<translation id="320323717674993345">ΑκÏÏωση πληÏωμής</translation>
+<translation id="3203366800380907218">Από τον ιστό</translation>
<translation id="3207960819495026254">ΠÏοστέθηκε στους σελιδοδείκτες</translation>
<translation id="3209034400446768650">Η σελίδα ενδέχεται να σας χÏεώσει</translation>
<translation id="3212581601480735796">Η δÏαστηÏιότητά σας στο <ph name="HOSTNAME" /> παÏακολουθείται</translation>
@@ -699,11 +733,13 @@
<translation id="3234666976984236645">Îα εντοπίζεται πάντα σημαντικό πεÏιεχόμενο σε αυτόν τον ιστότοπο</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />, πατήστε το πλήκτÏο Tab και έπειτα το πλήκτÏο Enter για να Ï€ÏοσαÏμόσετε την εμφάνιση του Ï€ÏογÏάμματος πεÏιήγησης</translation>
<translation id="3240791268468473923">Έχει ανοίξει το φÏλλο μη αντιστοίχισης διαπιστευτηÏίων με τα διαπιστευτήÏια ασφαλοÏÏ‚ πληÏωμής</translation>
+<translation id="324180406144491771">Οι σÏνδεσμοι <ph name="HOST_NAME" /> έχουν αποκλειστεί</translation>
<translation id="3249845759089040423">Μοδάτο</translation>
<translation id="3252266817569339921">Γαλλικά
</translation>
<translation id="3257954757204451555">Από Ï€Î¿Ï Ï€ÏοέÏχονται αυτές οι πληÏοφοÏίες;</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />, πατήστε το πλήκτÏο Tab και έπειτα το πλήκτÏο Enter για να δημιουÏγήσετε γÏήγοÏα ένα νέο συμβάν στο ΗμεÏολόγιο Google</translation>
+<translation id="3261488570342242926">Μάθετε σχετικά με τις εικονικές κάÏτες</translation>
<translation id="3264837738038045344">Κουμπί ΔιαχείÏιση των Ïυθμίσεων Chrome, πατήστε το πλήκτÏο Enter για να επισκεφτείτε τις Ïυθμίσεις του Chrome.</translation>
<translation id="3266793032086590337">Τιμή (διένεξη)</translation>
<translation id="3268451620468152448">Ανοικτές καÏτέλες</translation>
@@ -717,6 +753,7 @@
<translation id="3288238092761586174">Ενδέχεται να χÏειαστοÏν επιπλέον βήματα από το <ph name="URL" /> για την επαλήθευση της πληÏωμής σας.</translation>
<translation id="3293642807462928945">Μάθετε πεÏισσότεÏα σχετικά με την πολιτική <ph name="POLICY_NAME" /></translation>
<translation id="3295444047715739395">Δείτε και διαχειÏιστείτε τους κωδικοÏÏ‚ Ï€Ïόσβασής σας στις Ïυθμίσεις του Chrome.</translation>
+<translation id="3303795387212510132">Îα επιτÏέπεται στην εφαÏμογή το άνοιγμα συνδέσμων <ph name="PROTOCOL_SCHEME" />;</translation>
<translation id="3303855915957856445">Δεν βÏέθηκαν αποτελέσματα αναζήτησης</translation>
<translation id="3304073249511302126">σάÏωση Bluetooth</translation>
<translation id="3308006649705061278">ΟÏγανωτική ομάδα (OU)</translation>
@@ -730,12 +767,6 @@
<translation id="3345782426586609320">Μάτια</translation>
<translation id="3355823806454867987">Αλλαγή Ïυθμίσεων διακομιστή μεσολάβησης...</translation>
<translation id="3360103848165129075">ΦÏλλο δείκτη χειÏÎ¹ÏƒÎ¼Î¿Ï Ï€Î»Î·Ïωμών</translation>
-<translation id="3361596688432910856">Το Chrome <ph name="BEGIN_EMPHASIS" />δεν θα αποθηκεÏει<ph name="END_EMPHASIS" /> τις παÏακάτω πληÏοφοÏίες:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Το ιστοÏικό πεÏιήγησής σας
- <ph name="LIST_ITEM" />Cookie και δεδομένα ιστοτόπου
- <ph name="LIST_ITEM" />ΠληÏοφοÏίες που εισάγετε σε φόÏμες
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">Αυτή η πολιτική αντιγÏάφηκε αυτόματα από την πολιτική <ph name="OLD_POLICY" /> που έχει καταÏγηθεί. Θα Ï€Ïέπει να χÏησιμοποιήσετε εναλλακτικά αυτήν την πολιτική.</translation>
<translation id="3364869320075768271">Το <ph name="URL" /> θέλει να χÏησιμοποιήσει τη συσκευή και τα δεδομένα εικονικής Ï€Ïαγματικότητας.</translation>
<translation id="3366477098757335611">ΠÏοβολή καÏτών</translation>
@@ -818,7 +849,6 @@
<translation id="3587738293690942763">Μέσο</translation>
<translation id="3592413004129370115">Italian (Φάκελος)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{ΜποÏείτε να επαναφέÏετε την ομάδα σας ανά πάσα στιγμή. ΧÏειάζεται πεÏίπου μία μέÏα για να εγγÏαφείτε σε μια νέα ομάδα.}=1{ΜποÏείτε να επαναφέÏετε την ομάδα σας ανά πάσα στιγμή. ΧÏειάζεται πεÏίπου μία μέÏα για να εγγÏαφείτε σε μια νέα ομάδα.}other{ΜποÏείτε να επαναφέÏετε την ομάδα σας ανά πάσα στιγμή. ΧÏειάζονται {NUM_DAYS} ημέÏες για να εγγÏαφείτε σε μια νέα ομάδα.}}</translation>
-<translation id="3596012367874587041">Ρυθμίσεις εφαÏμογής</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">Η εφαÏμογή έχει αποκλειστεί από τον διαχειÏιστή σας.</translation>
<translation id="3608932978122581043">ΠÏοσανατολισμός Ïοής</translation>
@@ -861,6 +891,7 @@
<translation id="370972442370243704">ΕνεÏγοποίηση διαδÏομών</translation>
<translation id="3711895659073496551">Αναστολή</translation>
<translation id="3712624925041724820">Οι άδειες έχουν εξαντληθεί</translation>
+<translation id="3714633008798122362">ημεÏολόγιο ιστοÏ</translation>
<translation id="3714780639079136834">ΕνεÏγοποιήστε τα δεδομένα κινητής τηλεφωνίας ή το Wi-Fi.</translation>
<translation id="3715597595485130451">ΣÏνδεση σε Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Ελέγξτε το διακομιστή μεσολάβησης, το τείχος Ï€Ïοστασίας και τη διαμόÏφωση DNS<ph name="END_LINK" /></translation>
@@ -922,6 +953,7 @@
<translation id="3906954721959377182">Tablet</translation>
<translation id="3909477809443608991">Το <ph name="URL" /> επιθυμεί την αναπαÏαγωγή Ï€Ïοστατευμένου πεÏιεχομένου. Η ταυτότητα της συσκευής σας θα επαληθευτεί από την Google και αυτός ο ιστότοπος μποÏεί να αποκτήσει Ï€Ïόσβαση σε αυτήν.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">ΆÏνηση</translation>
<translation id="3939773374150895049">ΧÏήση WebAuthn αντί του CVC;</translation>
<translation id="3946209740501886391">Îα γίνεται πάντα εÏώτηση σε αυτόν τον ιστότοπο</translation>
<translation id="3947595700203588284">ΜποÏεί να ζητά να συνδεθεί σε συσκευές MIDI.</translation>
@@ -943,6 +975,7 @@
<translation id="3990250421422698716">Μετατόπιση στοίβας</translation>
<translation id="3996311196211510766">Ο ιστότοπος <ph name="ORIGIN" /> ζήτησε να εφαÏμοστεί μια πολιτική Ï€Ïοέλευσης
για όλα τα αιτήματά του, αλλά δεν είναι δυνατή η εφαÏμογή της πολιτικής αυτήν τη στιγμή.</translation>
+<translation id="4009243425692662128">Το πεÏιεχόμενο των σελίδων που εκτυπώνετε αποστέλλεται στο Google Cloud ή σε Ï„Ïίτα μέÏη για ανάλυση. Για παÏάδειγμα, ενδέχεται να σαÏώνεται για ευαίσθητα δεδομένα.</translation>
<translation id="4010758435855888356">Îα επιτÏέπεται η Ï€Ïόσβαση στον αποθηκευτικό χώÏο;</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{ΈγγÏαφο PDF που πεÏιέχει {COUNT} σελίδα}other{ΈγγÏαφο PDF που πεÏιέχει {COUNT} σελίδες}}</translation>
<translation id="4023431997072828269">Επειδή αυτή η φόÏμα υποβάλλεται χÏησιμοποιώντας μια σÏνδεση που δεν είναι ασφαλής, οι πληÏοφοÏίες σας θα είναι οÏατές σε άλλους χÏήστες.</translation>
@@ -1038,6 +1071,7 @@
<translation id="4250680216510889253">Όχι</translation>
<translation id="4253168017788158739">Σημείωση</translation>
<translation id="425582637250725228">Οι αλλαγές που κάνατε ενδέχεται να μην έχουν αποθηκευτεί.</translation>
+<translation id="425869179292622354">Θέλετε να βελτιώσετε την ασφάλεια με μια εικονική κάÏτα;</translation>
<translation id="4258748452823770588">Εσφαλμένη υπογÏαφή</translation>
<translation id="4261046003697461417">Δεν είναι δυνατός ο σχολιασμός των Ï€Ïοστατευμένων εγγÏάφων</translation>
<translation id="4265872034478892965">ΕπιτÏέπεται από τον διαχειÏιστή σας</translation>
@@ -1100,6 +1134,7 @@
<translation id="4434045419905280838">Αναδυόμενα παÏάθυÏα και ανακατευθÏνσεις</translation>
<translation id="4435702339979719576">ΤαχυδÏομική κάÏτα)</translation>
<translation id="443673843213245140">Η χÏήση ενός διακομιστή μεσολάβησης είναι απενεÏγοποιημένη, αλλά έχει καθοÏιστεί μια Ïητή διαμόÏφωση διακομιστή μεσολάβησης.</translation>
+<translation id="4441832193888514600">Έγινε παÏάβλεψη επειδή η πολιτική μποÏεί να οÏιστεί μόνο ως πολιτική χÏήστη cloud.</translation>
<translation id="4450893287417543264">Îα μην εμφανιστεί ξανά</translation>
<translation id="4451135742916150903">ΜποÏεί να ζητά να συνδεθεί σε συσκευές HID.</translation>
<translation id="4452328064229197696">Ο κωδικός Ï€Ïόσβασης που μόλις χÏησιμοποιήσατε εντοπίστηκε σε μια παÏαβίαση δεδομένων. Για την ασφάλεια των λογαÏιασμών σας, ο ΔιαχειÏιστής κωδικών Ï€Ïόσβασης της Google συνιστά να ελέγξετε τους αποθηκευμένους κωδικοÏÏ‚ Ï€Ïόσβασής σας.</translation>
@@ -1155,6 +1190,7 @@
<translation id="4628948037717959914">ΦωτογÏαφία</translation>
<translation id="4631649115723685955">Συνδέθηκε επιστÏοφή μετÏητών</translation>
<translation id="4636930964841734540">ΠληÏοφοÏίες</translation>
+<translation id="4638670630777875591">Ανώνυμη πεÏιήγηση στο Chromium</translation>
<translation id="464342062220857295">ΛειτουÏγίες αναζήτησης</translation>
<translation id="4644670975240021822">ΑντίστÏοφη σειÏά με την Ï€Ïόσοψη Ï€Ïος τα κάτω</translation>
<translation id="4646534391647090355">Μετάβαση εκεί Ï„ÏŽÏα</translation>
@@ -1175,6 +1211,7 @@
<translation id="4708268264240856090">Η σÏνδεσή σας διακόπηκε</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Îα εκτελέσετε τον Διαγνωστικό έλεγχο δικτÏου των Windows<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426">Κωδικός Ï€Ïόσβασης για <ph name="USERNAME" /></translation>
<translation id="4724144314178270921">ΜποÏεί να ζητά να βλέπει το κείμενο και τις εικόνες στο Ï€ÏόχειÏο.</translation>
<translation id="4726672564094551039">Επανάληψη φόÏτωσης πολιτικών</translation>
<translation id="4728558894243024398">ΠλατφόÏμα</translation>
@@ -1196,6 +1233,7 @@
<translation id="4757993714154412917">Μόλις καταχωÏίσατε τον κωδικό Ï€Ïόσβασής σας σε έναν παÏαπλανητικό ιστότοπο. Για την Ï€Ïοστασία των λογαÏιασμών σας, το Chromium συνιστά να ελέγξετε τους αποθηκευμένους κωδικοÏÏ‚ Ï€Ïόσβασής σας.</translation>
<translation id="4758311279753947758">ΠÏοσθήκη στοιχείων επικοινωνίας</translation>
<translation id="4761104368405085019">ΧÏήση του μικÏοφώνου σας</translation>
+<translation id="4761869838909035636">Εκτέλεση Ελέγχου ασφαλείας Chrome</translation>
<translation id="4764776831041365478">Η ιστοσελίδα στη διεÏθυνση <ph name="URL" /> μποÏεί να βÏίσκεται Ï€ÏοσωÏινά εκτός λειτουÏγίας ή ίσως έχει μεταφεÏθεί μόνιμα σε νέα διεÏθυνση ιστοÏ.</translation>
<translation id="4766713847338118463">Διπλή συÏÏαφή στο κάτω μέÏος</translation>
<translation id="4771973620359291008">ΠαÏουσιάστηκε άγνωστο σφάλμα.</translation>
@@ -1216,12 +1254,6 @@
<translation id="4819347708020428563">ΕπεξεÏγασία σχολιασμών στην Ï€Ïοεπιλεγμένη Ï€Ïοβολή;</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />, πατήστε το πλήκτÏο Tab και έπειτα το πλήκτÏο Enter για να δημιουÏγήσετε γÏήγοÏα ένα νέο ΦÏλλο Google</translation>
<translation id="4825507807291741242">ΙσχυÏÏŒ</translation>
-<translation id="4827402517081186284">Η Ανώνυμη πεÏιήγηση δεν σας κάνει αόÏατους στο διαδίκτυο:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Οι ιστότοποι γνωÏίζουν πότε τους επισκέπτεστε.<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Οι εÏγοδότες ή τα εκπαιδευτικά ιδÏÏματα μποÏοÏν να παÏακολουθοÏν τη δÏαστηÏιότητα πεÏιήγησης.<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Οι πάÏοχοι υπηÏεσιών διαδικτÏου μποÏοÏν να παÏακολουθοÏν την επισκεψιμότητα στον ιστό.<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">ΕνεÏγοποίηση ειδοποιήσεων</translation>
<translation id="4838327282952368871">ΟνειÏικό</translation>
<translation id="4840250757394056958">ΠÏοβολή του ιστοÏÎ¹ÎºÎ¿Ï Chrome</translation>
@@ -1234,12 +1266,12 @@
<translation id="4854362297993841467">Αυτός ο Ï„Ïόπος παÏάδοσης δεν είναι διαθέσιμος. Δοκιμάστε έναν άλλο Ï„Ïόπο.</translation>
<translation id="4854853140771946034">ΓÏήγοÏη δημιουÏγία νέας σημείωσης στο Google Keep</translation>
<translation id="485902285759009870">Επαλήθευση κωδικοÏ…</translation>
+<translation id="4866506163384898554">Πατήστε |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| για να εμφανιστεί ο δείκτης</translation>
<translation id="4876188919622883022">Απλοποιημένη Ï€Ïοβολή</translation>
<translation id="4876305945144899064">Δεν υπάÏχει όνομα χÏήστη</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{Κανένας}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831">Αναζήτηση <ph name="TEXT" /></translation>
<translation id="4879491255372875719">Αυτόματο (Ï€Ïοεπιλογή)</translation>
-<translation id="4879725228911483934">Άνοιγμα και τοποθέτηση παÏαθÏÏων στις οθόνες σας</translation>
<translation id="4880827082731008257">Αναζήτηση ιστοÏικοÏ</translation>
<translation id="4881695831933465202">Άνοιγμα</translation>
<translation id="4885256590493466218">ΠληÏωμή με την κάÏτα <ph name="CARD_DETAIL" /> κατά την ολοκλήÏωση της αγοÏάς</translation>
@@ -1248,6 +1280,7 @@
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">Ένατο Ïολό</translation>
<translation id="4901778704868714008">Αποθήκευση…</translation>
+<translation id="4905659621780993806">Ο διαχειÏιστής σας θα επανεκκινήσει τη συσκευή σας αυτόματα στις <ph name="TIME" /> στις <ph name="DATE" />. ΑποθηκεÏστε τυχόν ανοιχτά στοιχεία Ï€Ïιν από την επανεκκίνηση της συσκευής σας.</translation>
<translation id="4913987521957242411">ΤÏÏπημα επάνω αÏιστεÏά</translation>
<translation id="4918221908152712722">Εγκατάσταση εφαÏμογής <ph name="APP_NAME" /> (δεν απαιτείται λήψη)</translation>
<translation id="4923459931733593730">ΠληÏωμή</translation>
@@ -1256,6 +1289,7 @@
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />. Πατήστε το πλήκτÏο Tab και μετά το πλήκτÏο Enter για αναζήτηση.</translation>
<translation id="4930153903256238152">Μεγάλη χωÏητικότητα</translation>
+<translation id="4940163644868678279">Ανώνυμη πεÏιήγηση στο Chrome</translation>
<translation id="4943872375798546930">Δεν υπάÏχουν αποτελέσματα</translation>
<translation id="4950898438188848926">Κουμπί εναλλαγής καÏτέλας, πατήστε Enter για μετάβαση στην ανοιχτή καÏτέλα, <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="495170559598752135">ΕνέÏγειες</translation>
@@ -1265,6 +1299,7 @@
<translation id="4968522289500246572">Αυτή η εφαÏμογή σχεδιάστηκε για κινητά. Συνεπώς, η αλλαγή μεγέθους μποÏεί να μην λειτουÏγεί σωστά. Η εφαÏμογή ενδέχεται να παÏουσιάσει Ï€Ïοβλήματα ή να επανεκκινηθεί.</translation>
<translation id="4969341057194253438">ΔιαγÏαφή εγγÏαφής</translation>
<translation id="4973922308112707173">Διπλό Ï„ÏÏπημα στο επάνω μέÏος</translation>
+<translation id="4976702386844183910">Τελευταία επίσκεψη <ph name="DATE" /></translation>
<translation id="4984088539114770594">ΧÏήση μικÏοφώνου;</translation>
<translation id="4984339528288761049">Prc5 (Φάκελος)</translation>
<translation id="4989163558385430922">Εμφάνιση όλων</translation>
@@ -1326,6 +1361,7 @@
<translation id="5138227688689900538">Εμφάνιση λιγότεÏων</translation>
<translation id="5145883236150621069">Î’Ïέθηκε κωδικός σφάλματος στην απόκÏιση πολιτικής</translation>
<translation id="5146995429444047494">Οι ειδοποιήσεις για την Ï€Ïοέλευση <ph name="ORIGIN" /> έχουν αποκλειστεί</translation>
+<translation id="514704532284964975">Η διεÏθυνση <ph name="URL" /> θέλει να βλέπει και να αλλάζει πληÏοφοÏίες για συσκευές NFC που πατάτε με το τηλέφωνό σας</translation>
<translation id="5148809049217731050">ΠÏόσοψη Ï€Ïος τα επάνω</translation>
<translation id="515292512908731282">C4 (Φάκελος)</translation>
<translation id="5158275234811857234">Εξώφυλλο</translation>
@@ -1350,6 +1386,7 @@
<translation id="5215116848420601511">ΤÏόποι πληÏωμής και διευθÏνσεις που χÏησιμοποιοÏν το Google Pay</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">ΤÏοφοδότης χαÏÏ„Î¹Î¿Ï 13</translation>
+<translation id="5216942107514965959">Τελευταία επίσκεψη σήμεÏα</translation>
<translation id="5222812217790122047">Απαιτείται διεÏθυνση ηλεκτÏÎ¿Î½Î¹ÎºÎ¿Ï Ï„Î±Ï‡Ï…Î´Ïομείου</translation>
<translation id="5230733896359313003">ΔιεÏθυνση αποστολής</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1370,7 +1407,6 @@
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">Ιδιότητες εγγÏάφου</translation>
<translation id="528468243742722775">Τέλος</translation>
-<translation id="5284909709419567258">ΔιευθÏνσεις δικτÏου</translation>
<translation id="5285570108065881030">Εμφάνιση όλων των αποθηκευμένων κωδικών Ï€Ïόσβασης</translation>
<translation id="5287240709317226393">Εμφάνιση cookie</translation>
<translation id="5287456746628258573">Αυτός ο ιστότοπος χÏησιμοποιεί μια παÏωχημένη διαμόÏφωση ασφαλείας, η οποία μποÏεί να εκθέσει τις πληÏοφοÏίες σας (για παÏάδειγμα, τους κωδικοÏÏ‚ Ï€Ïόσβασης ή τα στοιχεία των πιστωτικών σας καÏτών) κατά την αποστολή της σε αυτόν τον ιστότοπο.</translation>
@@ -1455,6 +1491,7 @@
<translation id="5556459405103347317">ΕπαναφόÏτωση</translation>
<translation id="5560088892362098740">ΗμεÏομηνία λήξης</translation>
<translation id="55635442646131152">ΠεÏίγÏαμμα εγγÏάφου</translation>
+<translation id="5565613213060953222">Άνοιγμα καÏτέλας ανώνυμης πεÏιήγησης</translation>
<translation id="5565735124758917034">ΕνεÏγό</translation>
<translation id="5570825185877910964">ΠÏοστασία λογαÏιασμοÏ</translation>
<translation id="5571083550517324815">Δεν είναι δυνατή η παÏαλαβή από αυτήν τη διεÏθυνση. Επιλέξτε μια άλλη διεÏθυνση.</translation>
@@ -1537,6 +1574,7 @@
<translation id="5869522115854928033">Αποθηκευμένοι κωδικοί Ï€Ïόσβασης</translation>
<translation id="5873013647450402046">Η Ï„Ïάπεζά σας θέλει να επιβεβαιώσει την ταυτότητά σας.</translation>
<translation id="5887400589839399685">Η κάÏτα αποθηκεÏτηκε</translation>
+<translation id="5887687176710214216">Τελευταία επίσκεψη χθες</translation>
<translation id="5895138241574237353">Επανεκκίνηση</translation>
<translation id="5895187275912066135">Εκδόθηκε την</translation>
<translation id="5901630391730855834">ΚίτÏινο</translation>
@@ -1550,6 +1588,7 @@
<translation id="5921639886840618607">Αποθήκευση κάÏτας στον ΛογαÏιασμό Google;</translation>
<translation id="5922853866070715753">Σχεδόν ολοκληÏώθηκε</translation>
<translation id="5932224571077948991">Ο ιστότοπος εμφανίζει παÏεμβατικές ή παÏαπλανητικές διαφημίσεις</translation>
+<translation id="5938153366081463283">ΠÏοσθήκη εικονικής κάÏτας</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347">Άνοιγμα <ph name="SITE_NAME" />…</translation>
<translation id="5951495562196540101">Δεν είναι δυνατή η εγγÏαφή με λογαÏιασμό Ï€Ïοσωπικής χÏήσης (διατίθεται σχετική άδεια).</translation>
@@ -1614,6 +1653,7 @@
<translation id="6120179357481664955">Θυμάστε το αναγνωÏιστικό UPI;</translation>
<translation id="6124432979022149706">ΕφαÏμογές σÏνδεσης Chrome για επιχειÏήσεις</translation>
<translation id="6127379762771434464">Το στοιχείο καταÏγήθηκε</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Μάθετε πεÏισσότεÏα σχετικά με την Ανώνυμη πεÏιήγηση στο Chrome<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">Ελέγξτε τυχόν καλώδια και επανεκκινήστε δÏομολογητές, μόντεμ ή άλλες συσκευές
του δικτÏου που ενδεχομένως χÏησιμοποιείτε.</translation>
<translation id="614940544461990577">Δοκιμάστε να κάνετε τα εξής:</translation>
@@ -1626,7 +1666,6 @@
<translation id="6169916984152623906">Στο εξής μποÏείτε να πεÏιηγηθείτε ιδιωτικά και η δÏαστηÏιότητά σας δεν θα είναι οÏατή στα άλλα άτομα που χÏησιμοποιοÏν αυτήν τη συσκευή. Ωστόσο, οι λήψεις και οι σελιδοδείκτες θα αποθηκεÏονται</translation>
<translation id="6177128806592000436">Η σÏνδεσή σας σε αυτόν τον ιστότοπο δεν είναι ασφαλής</translation>
<translation id="6180316780098470077">Διάστημα επανάληψης</translation>
-<translation id="619448280891863779">ΜποÏεί να ζητά να ανοίγει και να τοποθετεί παÏάθυÏα στις οθόνες σας.</translation>
<translation id="6196640612572343990">Αποκλεισμός cookie Ï„Ïίτων</translation>
<translation id="6203231073485539293">Ελέγξτε τη σÏνδεσή σας στο Internet</translation>
<translation id="6218753634732582820">Îα καταÏγηθεί η διεÏθυνση από το Chromium;</translation>
@@ -1649,7 +1688,7 @@
<translation id="6272383483618007430">Google Update</translation>
<translation id="6276112860590028508">Εδώ εμφανίζονται οι σελίδες από τη λίστα ανάγνωσής σας</translation>
<translation id="627746635834430766">Για πιο γÏήγοÏες πληÏωμές, αποθηκεÏστε τα στοιχεία της κάÏτας και τη διεÏθυνση χÏέωσης στον ΛογαÏιασμό σας Google.</translation>
-<translation id="6279098320682980337">Δεν συμπληÏώθηκε ο αÏιθμός εικονικής κάÏτας; Κάντε κλικ στις λεπτομέÏειες της κάÏτας για αντιγÏαφή.</translation>
+<translation id="6279183038361895380">Πιέστε |<ph name="ACCELERATOR" />| για να εμφανιστεί ο δÏομέας</translation>
<translation id="6280223929691119688">Δεν είναι δυνατή η παÏάδοση σε αυτήν τη διεÏθυνση. Επιλέξτε μια άλλη διεÏθυνση.</translation>
<translation id="6282194474023008486">ΤαχυδÏομικός κώδικας</translation>
<translation id="6285507000506177184">Κουμπί ΔιαχείÏιση λήψεων στο Chrome, πατήστε το πλήκτÏο Enter για να διαχειÏιστείτε τα αÏχεία που έχετε κατεβάσει στο Chrome</translation>
@@ -1657,6 +1696,7 @@
<translation id="6290238015253830360">Τα Ï€Ïοτεινόμενα άÏθÏα σας εμφανίζονται εδώ</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{Η επανεκκίνηση της συσκευής σας θα γίνει Ï„ÏŽÏα}=1{Η επανεκκίνηση της συσκευής σας θα γίνει σε 1 δευτεÏόλεπτο}other{Η επανεκκίνηση της συσκευής σας θα γίνει σε # δευτεÏόλεπτα}}</translation>
<translation id="6302269476990306341">Διακοπή Î’Î¿Î·Î¸Î¿Ï Google στο Chrome</translation>
<translation id="6305205051461490394">Δεν είναι δυνατή η Ï€Ïόσβαση στο <ph name="URL" />.</translation>
<translation id="6312113039770857350">Η ιστοσελίδα δεν είναι διαθέσιμη</translation>
@@ -1730,6 +1770,7 @@
<translation id="6529602333819889595">&amp;Επανάληψη διαγÏαφής</translation>
<translation id="6545864417968258051">ΣάÏωση Bluetooth</translation>
<translation id="6547208576736763147">Διπλό Ï„ÏÏπημα στα αÏιστεÏά</translation>
+<translation id="6554732001434021288">Τελευταία επίσκεψη Ï€Ïιν από <ph name="NUM_DAYS" /> ημέÏες</translation>
<translation id="6556866813142980365">Επανάληψη ενέÏγειας</translation>
<translation id="6569060085658103619">Βλέπετε μια σελίδα επέκτασης</translation>
<translation id="6573200754375280815">Διπλό Ï„ÏÏπημα στα δεξιά</translation>
@@ -1757,7 +1798,7 @@
<translation id="6648524591329069940">ΓÏαμματοσειÏά Serif</translation>
<translation id="6651270836885078973">Η διαχείÏιση γίνεται από:</translation>
<translation id="6652101503459149953">ΧÏήση Windows Hello</translation>
-<translation id="6657585470893396449">Κωδικός ΠÏόσβασης</translation>
+<translation id="6657585470893396449">Κωδικός Ï€Ïόσβασης</translation>
<translation id="6660413144148052430">τοποθεσία</translation>
<translation id="6662457027866368246">ΠÏώτο Ïολό</translation>
<translation id="666259744093848177">(x86_64 μεταφÏασμένο)</translation>
@@ -1790,7 +1831,6 @@
<translation id="6757797048963528358">Η συσκευή σας τέθηκε σε αδÏάνεια.</translation>
<translation id="6767985426384634228">ΕνημέÏωση διεÏθυνσης;</translation>
<translation id="6768213884286397650">Hagaki (ΤαχυδÏομική κάÏτα)</translation>
-<translation id="6774185088257932239"><ph name="BEGIN_LINK" />Μάθετε πεÏισσότεÏα<ph name="END_LINK" /> σχετικά με την Ανώνυμη πεÏιήγηση</translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">Βιολετί</translation>
<translation id="6786747875388722282">Επεκτάσεις</translation>
@@ -1874,7 +1914,6 @@
<translation id="706295145388601875">ΠÏοσθήκη και διαχείÏιση διευθÏνσεων από τις Ïυθμίσεις του Chrome</translation>
<translation id="7064851114919012435">Στοιχεία επικοινωνίας</translation>
<translation id="7068733155164172741">Εισαγάγετε τον <ph name="OTP_LENGTH" />-ψήφιο κωδικό</translation>
-<translation id="7070090581017165256">Σχετικά με αυτόν τον ιστότοπο</translation>
<translation id="70705239631109039">Η σÏνδεσή σας δεν είναι πλήÏως ασφαλής</translation>
<translation id="7075452647191940183">Το αίτημα είναι Ï€Î¿Î»Ï Î¼ÎµÎ³Î¬Î»Î¿</translation>
<translation id="7079718277001814089">Ο ιστότοπος πεÏιέχει κακόβουλο Ï€ÏόγÏαμμα</translation>
@@ -1891,6 +1930,12 @@
<translation id="7111012039238467737">(ΈγκυÏο)</translation>
<translation id="7118618213916969306">Αναζήτηση URL στο Ï€ÏόχειÏο, <ph name="SHORT_URL" /></translation>
<translation id="7119414471315195487">Κλείστε τις άλλες καÏτέλες ή τα Ï€ÏογÏάμματα</translation>
+<translation id="7129355289156517987">Όταν κλείνετε όλες τις καÏτέλες ανώνυμης πεÏιήγησης του Chromium, οι δÏαστηÏιότητά σας σε αυτές τις καÏτέλες διαγÏάφεται από αυτήν τη συσκευή:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ΔÏαστηÏιότητα πεÏιήγησης<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ΙστοÏικό αναζήτησης<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ΠληÏοφοÏίες που εισάγετε σε φόÏμες<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">Δεν είναι δυνατή η αποστολή σε αυτήν τη διεÏθυνση. Επιλέξτε μια άλλη διεÏθυνση.</translation>
<translation id="7132939140423847331">Ο διαχειÏιστής απαγοÏεÏει την αντιγÏαφή αυτών των δεδομένων.</translation>
<translation id="7135130955892390533">Εμφάνιση κατάστασης</translation>
@@ -1913,6 +1958,7 @@
<translation id="7192203810768312527">ΑπελευθεÏώνει <ph name="SIZE" />. ΟÏισμένοι ιστότοποι μποÏεί να φοÏτωθοÏν πιο αÏγά κατά την επόμενη επίσκεψή σας.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">Ο διαχειÏιστής σας μποÏεί να βλέπει:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, πατήστε Tab και έπειτα Enter για να ανοίξετε μια νέα καÏτέλα ανώνυμης πεÏιήγησης για ιδιωτική πεÏιήγηση</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423">Ο κεντÏικός υπολογιστής <ph name="HOST_NAME" /> δεν συμμοÏφώνεται με τα Ï€Ïότυπα ασφάλειας.</translation>
<translation id="7210993021468939304">ΔÏαστηÏιότητα Linux εντός του ÎºÎ¿Î½Ï„Î­Î¹Î½ÎµÏ ÎºÎ±Î¸ÏŽÏ‚ και δυνατότητα εγκατάστασης και εκτέλεσης εφαÏμογών Linux εντός του κοντέινεÏ.</translation>
@@ -1944,6 +1990,7 @@
<translation id="7304562222803846232">ΔιαχείÏιση Ïυθμίσεων αποÏÏήτου ΛογαÏÎ¹Î±ÏƒÎ¼Î¿Ï Google</translation>
<translation id="7305756307268530424">ΈναÏξη σε πιο αÏγή ταχÏτητα</translation>
<translation id="7308436126008021607">συγχÏονισμός παÏασκηνίου</translation>
+<translation id="7310392214323165548">Θα γίνει επανεκκίνηση της συσκευής Ï€Î¿Î»Ï ÏƒÏντομα</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">Βοήθεια σÏνδεσης</translation>
<translation id="7323804146520582233">ΑπόκÏυψη της ενότητας "<ph name="SECTION" />"</translation>
@@ -1951,6 +1998,7 @@
<translation id="7334320624316649418">&amp;Επανάληψη αναδιάταξης</translation>
<translation id="7335157162773372339">ΜποÏεί να ζητά να χÏησιμοποιεί την κάμεÏά σας.</translation>
<translation id="7337248890521463931">Εμφάνιση πεÏισσότεÏων γÏαμμών</translation>
+<translation id="7337418456231055214">Δεν συμπληÏώθηκε ο αÏιθμός εικονικής κάÏτας; Κάντε κλικ στις λεπτομέÏειες της κάÏτας για αντιγÏαφή. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">Δεν είναι διαθέσιμο στην πλατφόÏμα σας.</translation>
<translation id="733923710415886693">Το πιστοποιητικό του διακομιστή δεν αποκαλÏφθηκε μέσω της Διαφάνειας πιστοποιητικών.</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1973,6 +2021,7 @@
<translation id="7378627244592794276">Όχι</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">Δεν ισχÏει</translation>
+<translation id="7388594495505979117">{0,plural, =1{Η επανεκκίνηση της συσκευής σας θα γίνει σε 1 λεπτό}other{Η επανεκκίνηση της συσκευής σας θα γίνει σε # λεπτά}}</translation>
<translation id="7390545607259442187">Επιβεβαίωση κάÏτας</translation>
<translation id="7392089738299859607">ΕνημέÏωση διεÏθυνσης</translation>
<translation id="7399802613464275309">Έλεγχος ασφαλείας</translation>
@@ -2009,6 +2058,12 @@
<translation id="7485870689360869515">Δεν βÏέθηκαν δεδομένα</translation>
<translation id="7495528107193238112">Αυτό το πεÏιεχόμενο είναι αποκλεισμένο. Επικοινωνήστε με τον κάτοχο του ιστοτόπου για να διοÏθώσετε το Ï€Ïόβλημα.</translation>
<translation id="7497998058912824456">Κουμπί δημιουÏγίας εγγÏάφου, πατήστε το πλήκτÏο Enter για γÏήγοÏη δημιουÏγία ενός νέου ΕγγÏάφου Google</translation>
+<translation id="7506488012654002225">Το Chromium <ph name="BEGIN_EMPHASIS" />δεν θα αποθηκεÏει<ph name="END_EMPHASIS" /> τις παÏακάτω πληÏοφοÏίες:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Το ιστοÏικό πεÏιήγησής σας
+ <ph name="LIST_ITEM" />Cookie και δεδομένα ιστοτόπου
+ <ph name="LIST_ITEM" />ΠληÏοφοÏίες που εισάγετε σε φόÏμες
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">Η εμφανιζόμενη συσκευή πολιτικής είναι κενή ή δεν αντιστοιχεί στο Ï„Ïέχον αναγνωÏιστικό συσκευής</translation>
<translation id="7508870219247277067">ΠÏάσινο αβοκάντο</translation>
<translation id="7511955381719512146">Το Wi-Fi που χÏησιμοποιείτε ενδέχεται να σας ζητήσει να επισκεφτείτε τη διεÏθυνση <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
@@ -2122,7 +2177,6 @@
<translation id="7813600968533626083">ΚατάÏγηση Ï€Ïότασης φόÏμας από το Chrome;</translation>
<translation id="781440967107097262">Κοινοποίηση Ï€ÏοχείÏου;</translation>
<translation id="7815407501681723534">Î’Ïέθηκαν <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> για τον ÏŒÏο αναζήτησης "<ph name="SEARCH_STRING" />"</translation>
-<translation id="782125616001965242">Εμφάνιση πληÏοφοÏιών σχετικά με αυτόν τον ιστότοπο</translation>
<translation id="782886543891417279">Το Wi-Fi που χÏησιμοποιείτε (<ph name="WIFI_NAME" />) ενδέχεται να σας ζητήσει να επισκεφτείτε τη σελίδα σÏνδεσής του.</translation>
<translation id="7836231406687464395">Postfix (Φάκελος)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{Κανένα}=1{1 εφαÏμογή (<ph name="EXAMPLE_APP_1" />)}=2{2 εφαÏμογές (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}other{# εφαÏμογές (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}}</translation>
@@ -2139,7 +2193,6 @@
<translation id="7888575728750733395">ΕκτÏπωση intent απόδοσης</translation>
<translation id="7894280532028510793">Εάν δεν υπάÏχει οÏθογÏαφικό λάθος, <ph name="BEGIN_LINK" />δοκιμάστε να εκτελέσετε έναν έλεγχο Διαγνωστικών δικτÏου<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (Φάκελος)</translation>
-<translation id="7931318309563332511">Άγνωστη</translation>
<translation id="793209273132572360">ΕνημέÏωση διεÏθυνσης;</translation>
<translation id="7932579305932748336">Επικάλυψη</translation>
<translation id="79338296614623784">Εισαγάγετε έναν έγκυÏο αÏιθμό τηλεφώνου</translation>
@@ -2164,13 +2217,14 @@
<translation id="7976214039405368314">ΠάÏα πολλά αιτήματα</translation>
<translation id="7977538094055660992">Συσκευή εξόδου</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">Συνδέθηκε με</translation>
<translation id="798134797138789862">ΜποÏεί να ζητά να χÏησιμοποιεί συσκευές και δεδομένα εικονικής Ï€Ïαγματικότητας.</translation>
<translation id="7984945080620862648">Δεν μποÏείτε να επισκεφτείτε το <ph name="SITE" /> αυτήν τη στιγμή επειδή ο ιστότοπος έστειλε κωδικοποιημένα διαπιστευτήÏια τα οποία δεν μποÏεί να επεξεÏγαστεί το Chrome. Τα σφάλματα δικτÏου και οι επιθέσεις είναι συνήθως Ï€ÏοσωÏινά, συνεπώς αυτή η σελίδα πιθανότατα θα λειτουÏγήσει αÏγότεÏα.</translation>
-<translation id="79859296434321399">Για να δείτε πεÏιεχόμενο επαυξημένης Ï€Ïαγματικότητας, εγκαταστήστε το ARCore</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">Δέσιμο</translation>
<translation id="7992044431894087211">Έγινε συνέχιση της κοινής χÏήσης οθόνης με την εφαÏμογή <ph name="APPLICATION_TITLE" />.</translation>
<translation id="7995512525968007366">Δεν καθοÏίστηκε</translation>
+<translation id="7998269595945679889">Κουμπί για άνοιγμα καÏτέλας ανώνυμης πεÏιήγησης, πατήστε Enter για να ανοίξετε μια νέα καÏτέλα ανώνυμης πεÏιήγησης για ιδιωτική πεÏιήγηση</translation>
<translation id="800218591365569300">Δοκιμάστε να κλείσετε τις άλλες καÏτέλες ή τα άλλα Ï€ÏογÏάμματα για να απελευθεÏώσετε μνήμη.</translation>
<translation id="8004582292198964060">ΠÏόγÏαμμα πεÏιήγησης</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{Αυτή η κάÏτα και η διεÏθυνση χÏέωσής της θα αποθηκευτοÏν. Θα μποÏείτε να τη χÏησιμοποιείτε όταν συνδέεστε στον λογαÏιασμό <ph name="USER_EMAIL" />.}other{Αυτές οι κάÏτες και οι διευθÏνσεις χÏέωσής τους θα αποθηκευτοÏν. Θα μποÏείτε να τις χÏησιμοποιείτε όταν συνδέεστε στον λογαÏιασμό <ph name="USER_EMAIL" />.}}</translation>
@@ -2230,6 +2284,7 @@
<translation id="8202370299023114387">Διένεξη</translation>
<translation id="8206978196348664717">Prc4 (Φάκελος)</translation>
<translation id="8211406090763984747">Η σÏνδεση είναι ασφαλής</translation>
+<translation id="8217240300496046857">Οι ιστότοποι δεν μποÏοÏν να χÏησιμοποιοÏν cookie που σας παÏακολουθοÏν στον ιστό. ΜποÏεί να παÏουσιαστοÏν Ï€Ïοβλήματα με τη λειτουÏγία οÏισμένων ιστοτόπων.</translation>
<translation id="8218327578424803826">ΕκχωÏημένη τοποθεσία:</translation>
<translation id="8220146938470311105">C7/C6 (Φάκελος)</translation>
<translation id="8225771182978767009">Το άτομο που ÏÏθμισε αυτόν τον υπολογιστή επέλεξε να αποκλείσει αυτόν τον ιστότοπο.</translation>
@@ -2271,14 +2326,9 @@
<translation id="830498451218851433">Δίπλωση στη μέση</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">Εγκατεστημένες εφαÏμογές και η συχνότητα χÏήσης τους</translation>
+<translation id="8317207217658302555">ΕνημέÏωση ARCore;</translation>
<translation id="831997045666694187">Î’Ïάδυ</translation>
<translation id="8321476692217554900">ειδοποιήσεις</translation>
-<translation id="8328484624016508118">Μετά το κλείσιμο όλων των καÏτελών ανώνυμης πεÏιήγησης, το Chrome διαγÏάφει:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Τη δÏαστηÏιότητα πεÏιήγησής σας από αυτήν τη συσκευή<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Το ιστοÏικό αναζήτησής σας από αυτήν τη συσκευή<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Τις πληÏοφοÏίες που είχαν καταχωÏιστεί σε φόÏμες<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489">ΑποÏÏίφθηκε η Ï€Ïόσβαση στο κεντÏικό υπολογιστή <ph name="HOST_NAME" /></translation>
<translation id="833262891116910667">Επισήμανση</translation>
<translation id="8339163506404995330">Οι σελίδες στα <ph name="LANGUAGE" /> δεν θα μεταφÏάζονται</translation>
@@ -2330,6 +2380,7 @@
<translation id="8507227106804027148">ΓÏαμμή εντολών</translation>
<translation id="8508648098325802031">Εικονίδιο αναζήτησης</translation>
<translation id="8511402995811232419">ΔιαχείÏιση cookie</translation>
+<translation id="8519753333133776369">Συσκευή HID που επιτÏέπεται από τον διαχειÏιστή σας</translation>
<translation id="8522552481199248698">Το Chrome μποÏεί να σας βοηθήσει να Ï€ÏοστατεÏσετε τον ΛογαÏιασμό σας Google και να αλλάξετε τον κωδικό Ï€Ïόσβασής σας.</translation>
<translation id="8530813470445476232">ΔιαγÏάψτε το ιστοÏικό πεÏιήγησης, τα cookie, την κÏυφή μνήμη και άλλα στοιχεία στις Ïυθμίσεις του Chrome.</translation>
<translation id="8533619373899488139">Μεταβείτε στη διεÏθυνση &lt;strong&gt;chrome://policy&lt;/strong&gt; για να δείτε τη λίστα των αποκλεισμένων URL και άλλες πολιτικές που έχουν τεθεί σε εφαÏμογή από τον διαχειÏιστή του συστήματός σας.</translation>
@@ -2341,7 +2392,6 @@
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{ΕπαναφοÏά άδειας}other{ΕπαναφοÏά αδειών}}</translation>
<translation id="8555010941760982128">ΧÏησιμοποιήστε αυτόν τον κωδικό κατά την ολοκλήÏωση αγοÏάς</translation>
<translation id="8557066899867184262">Ο κωδικός CVC βÏίσκεται στο πίσω μέÏος της κάÏτας.</translation>
-<translation id="8558485628462305855">Για να δείτε πεÏιεχόμενο επαυξημένης Ï€Ïαγματικότητας, ενημεÏώστε το ARCore</translation>
<translation id="8559762987265718583">Δεν είναι δυνατή η επίτευξη ιδιωτικής σÏνδεσης με τον τομέα <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> επειδή η ημεÏομηνία και η ÏŽÏα (<ph name="DATE_AND_TIME" />) της συσκευής σας είναι λανθασμένες.</translation>
<translation id="8564182942834072828">ΞεχωÏιστά έγγÏαφα/ΑντίγÏαφα χωÏίς συÏÏαφή</translation>
<translation id="8564985650692024650">Το Chromium συνιστά την επαναφοÏά του ÎºÏ‰Î´Î¹ÎºÎ¿Ï Ï€Ïόσβασης <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" />, εάν τον έχετε χÏησιμοποιήσει και σε άλλους ιστοτόπους.</translation>
@@ -2362,6 +2412,7 @@
<translation id="8663226718884576429">ΣÏνοψη παÏαγγελίας, <ph name="TOTAL_LABEL" />, ΠεÏισσότεÏες λεπτομέÏειες</translation>
<translation id="8666678546361132282">Αγγλικά
</translation>
+<translation id="8669306706049782872">Îα χÏησιμοποιεί πληÏοφοÏίες για τις οθόνες σας για άνοιγμα και τοποθέτηση παÏαθÏÏων</translation>
<translation id="867224526087042813">ΥπογÏαφή</translation>
<translation id="8676424191133491403">ΧωÏίς καθυστέÏηση</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, απάντηση, <ph name="ANSWER" /></translation>
@@ -2388,6 +2439,7 @@
<translation id="8731544501227493793">Κουμπί διαχείÏισης κωδικών Ï€Ïόσβασης, πατήστε Enter για Ï€Ïοβολή και διαχείÏιση των κωδικών Ï€Ïόσβασής σας στις Ïυθμίσεις του Chrome</translation>
<translation id="8734529307927223492">Η διαχείÏιση της συσκευής <ph name="DEVICE_TYPE" /> γίνεται από τον τομέα <ph name="MANAGER" /></translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, πατήστε Tab και έπειτα Enter για να ανοίξετε ένα νέο παÏάθυÏο για ανώνυμη πεÏιήγηση.</translation>
+<translation id="8737685506611670901">Άνοιγμα συνδέσμων <ph name="PROTOCOL" /> αντί για <ph name="REPLACED_HANDLER_TITLE" /></translation>
<translation id="8738058698779197622">Για την επίτευξη μιας ασφαλοÏÏ‚ σÏνδεσης, θα Ï€Ïέπει να γίνει σωστή ÏÏθμιση του ÏÎ¿Î»Î¿Î³Î¹Î¿Ï ÏƒÎ±Ï‚. Αυτό οφείλεται στο γεγονός ότι τα πιστοποιητικά που χÏησιμοποιοÏν οι ιστότοποι για την ταυτοποίησή τους είναι έγκυÏα μόνο για συγκεκÏιμένες χÏονικές πεÏιόδους. Εφόσον το Ïολόι της συσκευής σας δεν είναι σωστά Ïυθμισμένο, το Chromium δεν μποÏεί να επαληθεÏσει αυτά τα πιστοποιητικά.</translation>
<translation id="8740359287975076522">Δεν ήταν δυνατός ο εντοπισμός της &lt;abbr id="dnsDefinition"&gt;διεÏθυνσης DNS&lt;/abbr&gt; του κεντÏÎ¹ÎºÎ¿Ï Ï…Ï€Î¿Î»Î¿Î³Î¹ÏƒÏ„Î® <ph name="HOST_NAME" />. Γίνεται διάγνωση του Ï€Ïοβλήματος.</translation>
<translation id="8742371904523228557">Το <ph name="ONE_TIME_CODE" /> είναι ο κωδικός σας για το <ph name="ORIGIN" /></translation>
@@ -2415,6 +2467,7 @@
<translation id="883848425547221593">Άλλοι σελιδοδείκτες</translation>
<translation id="884264119367021077">ΔιεÏθυνση αποστολής</translation>
<translation id="884923133447025588">Δεν εντοπίστηκε μηχανισμός ακÏÏωσης.</translation>
+<translation id="8849262850971482943">ΧÏησιμοποιήστε την εικονική σας κάÏτα για Ï€Ïόσθετη ασφάλεια</translation>
<translation id="885730110891505394">Κοινοποίηση στις υπηÏεσίες της Google</translation>
<translation id="8858065207712248076">Το Chrome συνιστά την επαναφοÏά του ÎºÏ‰Î´Î¹ÎºÎ¿Ï Ï€Ïόσβασης <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> εάν τον έχετε χÏησιμοποιήσει και σε άλλους ιστοτόπους.</translation>
<translation id="885906927438988819">Εάν δεν υπάÏχει οÏθογÏαφικό λάθος, <ph name="BEGIN_LINK" />δοκιμάστε να εκτελέσετε έναν έλεγχο Διαγνωστικών δικτÏου των Windows<ph name="END_LINK" />.</translation>
@@ -2464,6 +2517,7 @@
<translation id="9004367719664099443">ΠεÏίοδος λειτουÏγίας VR σε εξέλιξη</translation>
<translation id="9005998258318286617">Η φόÏτωση του εγγÏάφου PDF απέτυχε.</translation>
<translation id="9008201768610948239">ΠαÏάβλεψη</translation>
+<translation id="901834265349196618">ηλεκτÏονικό ταχυδÏομείο</translation>
<translation id="9020200922353704812">Απαιτείται διεÏθυνση χÏέωσης της κάÏτας</translation>
<translation id="9020542370529661692">Αυτή η σελίδα έχει μεταφÏαστεί στα <ph name="TARGET_LANGUAGE" />.</translation>
<translation id="9020742383383852663">A8</translation>
@@ -2512,6 +2566,7 @@
<translation id="9150045010208374699">ΧÏήση της κάμεÏάς σας</translation>
<translation id="9150685862434908345">Ο διαχειÏιστής σας μποÏεί να αλλάξει τη ÏÏθμιση του Ï€ÏογÏάμματος πεÏιήγησής σας απομακÏυσμένα. Η διαχείÏιση της δÏαστηÏιότητας σε αυτήν τη συσκευή μποÏεί επίσης να Ï€Ïαγματοποιηθεί εκτός Chrome. <ph name="BEGIN_LINK" />Μάθετε πεÏισσότεÏα<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">ΕνημεÏώθηκε</translation>
+<translation id="9155211586651734179">Τυχόν συνδεδεμένα πεÏιφεÏειακά ήχου</translation>
<translation id="9157595877708044936">ΡÏθμιση...</translation>
<translation id="9158625974267017556">C6 (Φάκελος)</translation>
<translation id="9164029392738894042">Έλεγχος ακÏίβειας</translation>
diff --git a/chromium/components/strings/components_strings_en-GB.xtb b/chromium/components/strings/components_strings_en-GB.xtb
index 899d04a8d13..ceb811a4804 100644
--- a/chromium/components/strings/components_strings_en-GB.xtb
+++ b/chromium/components/strings/components_strings_en-GB.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">See details</translation>
<translation id="1030706264415084469"><ph name="URL" /> wants to permanently store large data on your device</translation>
<translation id="1032854598605920125">Rotate clockwise</translation>
+<translation id="1033329911862281889">Incognito does not make you invisible online:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Sites and the services that they use can see visits<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Employers or schools can track browsing activity<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Internet service providers can monitor web traffic<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">Turn off</translation>
<translation id="1036982837258183574">Press |<ph name="ACCELERATOR" />| to exit full screen</translation>
<translation id="1038106730571050514">Show suggestions</translation>
<translation id="1038842779957582377">unknown name</translation>
<translation id="1041998700806130099">Job sheet message</translation>
<translation id="1048785276086539861">When you edit annotations, this document will return to single-page view</translation>
-<translation id="1049743911850919806">Incognito</translation>
<translation id="1050038467049342496">Close other apps</translation>
<translation id="1055184225775184556">&amp;Undo add</translation>
<translation id="1056898198331236512">Warning</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">Policy cache OK</translation>
<translation id="1130564665089811311">Translate page button; press enter to translate this page with Google Translate</translation>
<translation id="1131264053432022307">Image that you copied</translation>
+<translation id="1142846828089312304">Block third-party cookies in Incognito</translation>
<translation id="1150979032973867961">This server could not prove that it is <ph name="DOMAIN" />; its security certificate is not trusted by your computer's operating system. This may be caused by a misconfiguration or an attacker intercepting your connection.</translation>
<translation id="1151972924205500581">Password required</translation>
<translation id="1156303062776767266">You're viewing a local or shared file</translation>
@@ -64,7 +70,6 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="1178581264944972037">Pause</translation>
<translation id="1181037720776840403">Remove</translation>
<translation id="1186201132766001848">Check passwords</translation>
-<translation id="1195210374336998651">Go to app settings</translation>
<translation id="1195558154361252544">Notifications are automatically blocked for all sites except ones that you allow</translation>
<translation id="1197088940767939838">Orange</translation>
<translation id="1201402288615127009">Next</translation>
@@ -111,7 +116,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="1307966114820526988">Deprecated features</translation>
<translation id="1308113895091915999">Offer available</translation>
<translation id="1312803275555673949">What evidence supports it?</translation>
-<translation id="131405271941274527"><ph name="URL" /> wants to send and receive info when you tap your phone on an NFC device</translation>
+<translation id="1314311879718644478">View augmented reality content</translation>
<translation id="1314509827145471431">Bind right</translation>
<translation id="1318023360584041678">Saved in tab group</translation>
<translation id="1319245136674974084">Don’t ask again for this app</translation>
@@ -161,6 +166,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="142858679511221695">Cloud user</translation>
<translation id="1428729058023778569">You are seeing this warning because this site does not support HTTPS. <ph name="BEGIN_LEARN_MORE_LINK" />Learn more<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">Print</translation>
+<translation id="1432187715652018471">page wants to install a service handler.</translation>
<translation id="1432581352905426595">Manage search engines</translation>
<translation id="1436185428532214179">Can ask to edit files and folders on your device</translation>
<translation id="1442386063175183758">Right gate fold</translation>
@@ -181,6 +187,12 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="1483493594462132177">Send</translation>
<translation id="1484290072879560759">Choose delivery address</translation>
<translation id="1492194039220927094">Policies push:</translation>
+<translation id="149293076951187737">When you close all Chrome Incognito tabs, your activity in those tabs is cleared from this device:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Browsing activity<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Search history<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Information entered in forms<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">Back to tab</translation>
<translation id="1501859676467574491">Show cards from your Google Account</translation>
<translation id="1507202001669085618">&lt;p&gt;You'll see this error if you're using a Wi-Fi portal where you have to sign in before you can get online.&lt;/p&gt;
@@ -208,6 +220,8 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="1559572115229829303">&lt;p&gt;A private connection to <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> can't be established because your device's date and time (<ph name="DATE_AND_TIME" />) are incorrect.&lt;/p&gt;
&lt;p&gt;Please adjust the date and time from the &lt;strong&gt;General&lt;/strong&gt; section of the &lt;strong&gt;Settings&lt;/strong&gt; app.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">Your administrator will restart your device at <ph name="TIME" /> on <ph name="DATE" /></translation>
+<translation id="156703335097561114">Networking information, such as addresses, interface configuration and connection quality</translation>
<translation id="1567040042588613346">This policy is working as intended but the same value is set elsewhere and is superseded by this policy.</translation>
<translation id="1569487616857761740">Enter expiry date</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="1583429793053364125">Something went wrong while displaying this web page.</translation>
<translation id="1586541204584340881">Which extensions you have installed</translation>
<translation id="1588438908519853928">Normal</translation>
+<translation id="1589050138437146318">Install ARCore?</translation>
<translation id="1592005682883173041">Local Data Access</translation>
<translation id="1594030484168838125">Choose</translation>
<translation id="160851722280695521">Play the Dino Run game in Chrome</translation>
@@ -237,7 +252,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="1650602712345345441">Manage your Chrome settings</translation>
<translation id="1652415888492971589">JIS B8</translation>
<translation id="1656024727720460136">Chrome simplified this page to make it easier to read. Chrome retrieved the original page over a secure connection.</translation>
-<translation id="1656489000284462475">Pick up</translation>
+<translation id="1656489000284462475">Pick-up</translation>
<translation id="1658918301167915956">bluetooth devices</translation>
<translation id="1662550410081243962">Save and fill payment methods</translation>
<translation id="1663943134801823270">Cards and addresses are from Chrome. You can manage them in <ph name="BEGIN_LINK" />Settings<ph name="END_LINK" />.</translation>
@@ -282,6 +297,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
requiring that an origin policy is to be applied to all requests to it. But
the header is malformed, which prevents the browser from fulfilling
your request for <ph name="SITE" />. Origin policies can be used by site operators to configure security and other properties for a site.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Learn more about Incognito in Chromium<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">Your open tabs appear here</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -358,7 +374,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="204357726431741734">Sign in to use passwords saved in your Google Account</translation>
<translation id="2053111141626950936">Pages in <ph name="LANGUAGE" /> will not be translated.</translation>
<translation id="2053373601901562871">{NUM_DAYS,plural, =0{When this control is on and the status is active, Chrome determines which large group of people, or 'cohort', your recent browsing activity is most similar to. Advertisers can select ads for the group, and your browsing activity is kept private on your device. Your group is updated every day.}=1{When this control is on and the status is active, Chrome determines which large group of people, or 'cohort', your recent browsing activity is most similar to. Advertisers can select ads for the group, and your browsing activity is kept private on your device. Your group is updated every day.}other{When this control is on and the status is active, Chrome determines which large group of people, or 'cohort', your recent browsing activity is most similar to. Advertisers can select ads for the group, and your browsing activity is kept private on your device. Your group is updated every {NUM_DAYS} days.}}</translation>
-<translation id="2053553514270667976">ZIP code</translation>
+<translation id="2053553514270667976">Postcode</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 suggestion}other{# suggestions}}</translation>
<translation id="2071156619270205202">This card is not eligible for virtual card number.</translation>
<translation id="2071692954027939183">Notifications were automatically blocked because you usually don't allow them</translation>
@@ -409,6 +425,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="22081806969704220">Tray 3</translation>
<translation id="2212735316055980242">Policy not found</translation>
<translation id="2213606439339815911">Fetching entries...</translation>
+<translation id="2213612003795704869">Page is printed</translation>
<translation id="2215727959747642672">File editing</translation>
<translation id="2218879909401188352">Attackers currently on <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> could install dangerous apps that damage your device, add hidden charges to your mobile bill or steal your personal information. <ph name="BEGIN_LEARN_MORE_LINK" />Learn more<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">No Internet</translation>
@@ -418,6 +435,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="2248949050832152960">Use WebAuthn</translation>
<translation id="2250931979407627383">Edge stitch left</translation>
<translation id="225207911366869382">This value is deprecated for this policy.</translation>
+<translation id="2256115617011615191">Restart now</translation>
<translation id="2258928405015593961">Enter an expiry date in the future and try again</translation>
<translation id="225943865679747347">Error code: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">HTTP error</translation>
@@ -445,6 +463,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="2337852623177822836">Setting controlled by your administrator</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> wants to pair</translation>
<translation id="2346319942568447007">Image that you copied</translation>
+<translation id="2350796302381711542">Allow <ph name="HANDLER_HOSTNAME" /> to open all <ph name="PROTOCOL" /> links instead of <ph name="REPLACED_HANDLER_TITLE" />?</translation>
<translation id="2354001756790975382">Other bookmarks</translation>
<translation id="2354430244986887761">Google Safe Browsing recently <ph name="BEGIN_LINK" />found harmful apps<ph name="END_LINK" /> on <ph name="SITE" />.</translation>
<translation id="2355395290879513365">Attackers might be able to see the images that you’re looking at on this site and trick you by modifying them.</translation>
@@ -470,6 +489,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="2413528052993050574">This server could not prove that it is <ph name="DOMAIN" />; its security certificate might be revoked. This may be caused by a misconfiguration or an attacker intercepting your connection.</translation>
<translation id="2414886740292270097">Dark</translation>
<translation id="2430968933669123598">Manage Google Account: press Enter to manage your info, privacy and security in your Google Account</translation>
+<translation id="2436186046335138073">Allow <ph name="HANDLER_HOSTNAME" /> to open all <ph name="PROTOCOL" /> links?</translation>
<translation id="2438874542388153331">Quad punch right</translation>
<translation id="2450021089947420533">Journeys</translation>
<translation id="2463739503403862330">Fill in</translation>
@@ -477,6 +497,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="2465655957518002998">Choose delivery method</translation>
<translation id="2465688316154986572">Staple</translation>
<translation id="2465914000209955735">Manage files that you have downloaded in Chrome</translation>
+<translation id="2466004615675155314">Show information from the web</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Running network diagnostics<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">1-to-N order</translation>
<translation id="2470767536994572628">When you edit annotations, this document will return to single-page view and its original rotation</translation>
@@ -497,6 +518,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="2523886232349826891">Saved on this device only</translation>
<translation id="2524461107774643265">Add More Information</translation>
<translation id="2529899080962247600">This field should not have more than <ph name="MAX_ITEMS_LIMIT" /> entries. All further entries will be ignored.</translation>
+<translation id="2535585790302968248">Open a new incognito tab to browse privately</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{and 1 more}other{and # more}}</translation>
<translation id="2536110899380797252">Add Address</translation>
<translation id="2539524384386349900">Detect</translation>
@@ -522,7 +544,14 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="2597378329261239068">This document is password-protected. Please enter a password.</translation>
<translation id="2609632851001447353">Variations</translation>
<translation id="2610561535971892504">Click to copy</translation>
+<translation id="2617988307566202237">Chrome <ph name="BEGIN_EMPHASIS" />won’t save<ph name="END_EMPHASIS" /> the following information:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Your browsing history
+ <ph name="LIST_ITEM" />Cookies and site data
+ <ph name="LIST_ITEM" />Information entered in forms
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (Envelope)</translation>
+<translation id="2623663032199728144">Can ask to use info about your screens</translation>
<translation id="2625385379895617796">Your clock is ahead</translation>
<translation id="262745152991669301">Can ask to connect to USB devices</translation>
<translation id="2629325967560697240">To get Chrome’s highest level of security, <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />turn on enhanced protection<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -556,6 +585,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="2709516037105925701">Auto-fill</translation>
<translation id="2713444072780614174">White</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />, press tab, then enter to manage your payments and credit card info in Chrome settings</translation>
+<translation id="271663710482723385">Press |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| to exit full screen</translation>
<translation id="2721148159707890343">Request succeeded</translation>
<translation id="2723669454293168317">Run a safety check in Chrome settings</translation>
<translation id="2726001110728089263">Side tray</translation>
@@ -586,6 +616,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="2850739647070081192">Invite (Envelope)</translation>
<translation id="2856444702002559011">Attackers might be trying to steal your information from <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (for example, passwords, messages or credit cards). <ph name="BEGIN_LEARN_MORE_LINK" />Learn more<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">This site shows intrusive or misleading ads.</translation>
+<translation id="286512204874376891">A virtual card disguises your actual card to help protect you from potential fraud. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">Friendly</translation>
<translation id="2876489322757410363">Leaving Incognito mode to pay via an external application. Continue?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />; press tab and then Enter to manage your Safe Browsing and more in Chrome settings</translation>
@@ -610,6 +641,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="2930577230479659665">Trim after each copy</translation>
<translation id="2932085390869194046">Suggest password...</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019">Open <ph name="PROTOCOL" /> links</translation>
<translation id="2941952326391522266">This server could not prove that it is <ph name="DOMAIN" />; its security certificate is from <ph name="DOMAIN2" />. This may be caused by a misconfiguration or an attacker intercepting your connection.</translation>
<translation id="2943895734390379394">Upload time:</translation>
<translation id="2948083400971632585">You can disable any proxies configured for a connection from the settings page.</translation>
@@ -642,6 +674,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="3037605927509011580">Aw, Snap!</translation>
<translation id="3041612393474885105">Certificate Information</translation>
<translation id="3044034790304486808">Resume your research</translation>
+<translation id="305162504811187366">Chrome Remote Desktop history, including timestamps, hosts and client session ids</translation>
<translation id="3060227939791841287">C9 (Envelope)</translation>
<translation id="3061707000357573562">Patch Service</translation>
<translation id="306573536155379004">Game started.</translation>
@@ -682,6 +715,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="3197136577151645743">Can ask to know when you're actively using this device</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />, press Tab then Enter to manage what info you sync in Chrome settings</translation>
<translation id="320323717674993345">Cancel payment</translation>
+<translation id="3203366800380907218">From the web</translation>
<translation id="3207960819495026254">Bookmarked</translation>
<translation id="3209034400446768650">Page may charge money</translation>
<translation id="3212581601480735796">Your activity on <ph name="HOSTNAME" /> is being monitored</translation>
@@ -698,10 +732,12 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="3234666976984236645">Always detect important content on this site</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />; press tab and then Enter to customise the look of your browser</translation>
<translation id="3240791268468473923">Secure payment credential no matching credential sheet is opened</translation>
+<translation id="324180406144491771">'<ph name="HOST_NAME" />' links are blocked</translation>
<translation id="3249845759089040423">Groovy</translation>
<translation id="3252266817569339921">French</translation>
<translation id="3257954757204451555">Who’s behind this information?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />: press Tab then Enter to create a new event in Google Calendar quickly</translation>
+<translation id="3261488570342242926">Learn about virtual cards</translation>
<translation id="3264837738038045344">Manage Chrome settings button. Press Enter to visit your Chrome settings</translation>
<translation id="3266793032086590337">Value (conflict)</translation>
<translation id="3268451620468152448">Open tabs</translation>
@@ -715,6 +751,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="3288238092761586174"><ph name="URL" /> may need to take additional steps to verify your payment</translation>
<translation id="3293642807462928945">Learn more about <ph name="POLICY_NAME" /> policy</translation>
<translation id="3295444047715739395">View and manage your passwords in Chrome settings</translation>
+<translation id="3303795387212510132">Allow app to open <ph name="PROTOCOL_SCHEME" /> links?</translation>
<translation id="3303855915957856445">No search results found</translation>
<translation id="3304073249511302126">bluetooth scanning</translation>
<translation id="3308006649705061278">Organisational Unit (OU)</translation>
@@ -728,12 +765,6 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="3345782426586609320">Eyes</translation>
<translation id="3355823806454867987">Change proxy settings...</translation>
<translation id="3360103848165129075">Payment handler sheet</translation>
-<translation id="3361596688432910856">Chrome <ph name="BEGIN_EMPHASIS" />won’t save<ph name="END_EMPHASIS" /> the following information:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Your browsing history
- <ph name="LIST_ITEM" />Cookies and site data
- <ph name="LIST_ITEM" />Information entered in forms
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">This policy was automatically copied from the deprecated <ph name="OLD_POLICY" /> policy. You should use this policy instead.</translation>
<translation id="3364869320075768271"><ph name="URL" /> wants to use your virtual reality device and data</translation>
<translation id="3366477098757335611">View cards</translation>
@@ -816,7 +847,6 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="3587738293690942763">Middle</translation>
<translation id="3592413004129370115">Italian (Envelope)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{You can reset your group at any time. It takes about a day to join a new group.}=1{You can reset your group at any time. It takes about a day to join a new group.}other{You can reset your group at any time. It takes {NUM_DAYS} days to join a new group.}}</translation>
-<translation id="3596012367874587041">App settings</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">Application blocked by your administrator</translation>
<translation id="3608932978122581043">Feed orientation</translation>
@@ -859,6 +889,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="370972442370243704">Turn on Journeys</translation>
<translation id="3711895659073496551">Suspend</translation>
<translation id="3712624925041724820">Licenses exhausted</translation>
+<translation id="3714633008798122362">web calendar</translation>
<translation id="3714780639079136834">Turning on mobile data or Wi-Fi</translation>
<translation id="3715597595485130451">Connect to Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Checking the proxy, firewall and DNS configuration<ph name="END_LINK" /></translation>
@@ -920,6 +951,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="3906954721959377182">Tablet</translation>
<translation id="3909477809443608991"><ph name="URL" /> wants to play protected content. Your device's identity will be verified by Google and may be accessed by this site.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">Deny</translation>
<translation id="3939773374150895049">Use WebAuthn instead of CVC?</translation>
<translation id="3946209740501886391">Always ask on this site</translation>
<translation id="3947595700203588284">Can ask to connect to MIDI devices</translation>
@@ -941,6 +973,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="3990250421422698716">Jog offset</translation>
<translation id="3996311196211510766">The site <ph name="ORIGIN" /> has requested that an origin policy will
apply to all requests to it, but this policy cannot presently be applied.</translation>
+<translation id="4009243425692662128">The content of pages that you print is sent to Google Cloud or third parties for analysis. For example, it might be scanned for sensitive data.</translation>
<translation id="4010758435855888356">Allow storage access?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{PDF document containing {COUNT} page}other{PDF document containing {COUNT} pages}}</translation>
<translation id="4023431997072828269">Because this form is being submitted using a connection that’s not secure, your information will be visible to others.</translation>
@@ -1035,6 +1068,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="4250680216510889253">No</translation>
<translation id="4253168017788158739">Note</translation>
<translation id="425582637250725228">Changes that you made may not be saved.</translation>
+<translation id="425869179292622354">Make it more secure with a virtual card?</translation>
<translation id="4258748452823770588">Bad signature</translation>
<translation id="4261046003697461417">Protected documents cannot be annotated</translation>
<translation id="4265872034478892965">Allowed by your administrator</translation>
@@ -1097,6 +1131,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="4434045419905280838">Pop-ups and redirects</translation>
<translation id="4435702339979719576">Postcard)</translation>
<translation id="443673843213245140">Use of a proxy is disabled but an explicit proxy configuration is specified.</translation>
+<translation id="4441832193888514600">Ignored because the policy can only be set as a cloud user policy.</translation>
<translation id="4450893287417543264">Don't show again</translation>
<translation id="4451135742916150903">Can ask to connect to HID devices</translation>
<translation id="4452328064229197696">The password that you just used was found in a data breach. To secure your accounts, Google Password Manager recommends checking your saved passwords.</translation>
@@ -1152,6 +1187,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="4628948037717959914">Photo</translation>
<translation id="4631649115723685955">Cashback linked</translation>
<translation id="4636930964841734540">Info</translation>
+<translation id="4638670630777875591">Incognito in Chromium</translation>
<translation id="464342062220857295">Search features</translation>
<translation id="4644670975240021822">Reverse order face down</translation>
<translation id="4646534391647090355">Take me there now</translation>
@@ -1172,6 +1208,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="4708268264240856090">Your connection was interrupted</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Running Windows Network Diagnostics<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426">Password for <ph name="USERNAME" /></translation>
<translation id="4724144314178270921">Can ask to see text and images on your clipboard</translation>
<translation id="4726672564094551039">Reload policies</translation>
<translation id="4728558894243024398">Platform</translation>
@@ -1193,6 +1230,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="4757993714154412917">You just entered your password on a deceptive site. To secure your accounts, Chromium recommends checking your saved passwords.</translation>
<translation id="4758311279753947758">Add contact info</translation>
<translation id="4761104368405085019">Use your microphone</translation>
+<translation id="4761869838909035636">Run Chrome safety check</translation>
<translation id="4764776831041365478">The web page at <ph name="URL" /> might be temporarily down or it may have moved permanently to a new web address.</translation>
<translation id="4766713847338118463">Dual staple bottom</translation>
<translation id="4771973620359291008">An unknown error has occurred.</translation>
@@ -1213,12 +1251,6 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="4819347708020428563">Edit annotations in default view?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />: press Tab then Enter to create a new Google Sheet quickly</translation>
<translation id="4825507807291741242">Powerful</translation>
-<translation id="4827402517081186284">Incognito does not make you invisible online:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Sites know when you visit them<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Employers or schools can track browsing activity<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Internet service providers may monitor web traffic<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">Turn on warnings</translation>
<translation id="4838327282952368871">Dreamy</translation>
<translation id="4840250757394056958">View your Chrome history</translation>
@@ -1230,12 +1262,12 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="4854362297993841467">This delivery method isn’t available. Try a different method.</translation>
<translation id="4854853140771946034">Create a new note in Google Keep quickly</translation>
<translation id="485902285759009870">Verifying code…</translation>
+<translation id="4866506163384898554">Press |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| to show your cursor</translation>
<translation id="4876188919622883022">Simplified view</translation>
<translation id="4876305945144899064">No username</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{None}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831"><ph name="TEXT" /> search</translation>
<translation id="4879491255372875719">Automatic (default)</translation>
-<translation id="4879725228911483934">Open and place windows on your screens</translation>
<translation id="4880827082731008257">Search history</translation>
<translation id="4881695831933465202">Open</translation>
<translation id="4885256590493466218">Pay with <ph name="CARD_DETAIL" /> at checkout</translation>
@@ -1244,6 +1276,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">Ninth roll</translation>
<translation id="4901778704868714008">Save...</translation>
+<translation id="4905659621780993806">Your administrator will restart your device automatically at <ph name="TIME" /> on <ph name="DATE" />. Save any open items before your device restarts.</translation>
<translation id="4913987521957242411">Punch top left</translation>
<translation id="4918221908152712722">Install <ph name="APP_NAME" /> (no download required)</translation>
<translation id="4923459931733593730">Payment</translation>
@@ -1252,6 +1285,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, press 'Tab', then 'Enter' to search</translation>
<translation id="4930153903256238152">Large capacity</translation>
+<translation id="4940163644868678279">Incognito in Chrome</translation>
<translation id="4943872375798546930">No results</translation>
<translation id="4950898438188848926">Tab switch button, press Enter to switch to the open tab, <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="495170559598752135">Actions</translation>
@@ -1261,6 +1295,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="4968522289500246572">This app is designed for mobile and may not resize well. The app may experience issues or restart.</translation>
<translation id="4969341057194253438">Delete recording</translation>
<translation id="4973922308112707173">Dual punch top</translation>
+<translation id="4976702386844183910">Last visited <ph name="DATE" /></translation>
<translation id="4984088539114770594">Use microphone?</translation>
<translation id="4984339528288761049">Prc5 (Envelope)</translation>
<translation id="4989163558385430922">See all</translation>
@@ -1322,6 +1357,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="5138227688689900538">Show less</translation>
<translation id="5145883236150621069">Error code present in the policy response</translation>
<translation id="5146995429444047494">Notifications for <ph name="ORIGIN" /> are blocked</translation>
+<translation id="514704532284964975"><ph name="URL" /> wants to see and change information on NFC devices that you tap with your phone</translation>
<translation id="5148809049217731050">Face up</translation>
<translation id="515292512908731282">C4 (Envelope)</translation>
<translation id="5158275234811857234">Cover</translation>
@@ -1346,6 +1382,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="5215116848420601511">Payment methods and addresses using Google Pay</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">Tray 13</translation>
+<translation id="5216942107514965959">Last visited today</translation>
<translation id="5222812217790122047">Email (required)</translation>
<translation id="5230733896359313003">Delivery Address</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1366,7 +1403,6 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">Document properties</translation>
<translation id="528468243742722775">End</translation>
-<translation id="5284909709419567258">Network addresses</translation>
<translation id="5285570108065881030">Show all saved passwords</translation>
<translation id="5287240709317226393">Show cookies</translation>
<translation id="5287456746628258573">This site uses an outdated security configuration, which may expose your information (for example, passwords or credit card numbers) when it is sent to this site.</translation>
@@ -1450,6 +1486,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="5556459405103347317">Reload</translation>
<translation id="5560088892362098740">Expiry Date</translation>
<translation id="55635442646131152">Document outline</translation>
+<translation id="5565613213060953222">Open incognito tab</translation>
<translation id="5565735124758917034">Active</translation>
<translation id="5570825185877910964">Protect account</translation>
<translation id="5571083550517324815">Can’t pick up from this address. Select a different address.</translation>
@@ -1532,6 +1569,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="5869522115854928033">Saved passwords</translation>
<translation id="5873013647450402046">Your bank wants to confirm that it's you.</translation>
<translation id="5887400589839399685">Card saved</translation>
+<translation id="5887687176710214216">Last visited yesterday</translation>
<translation id="5895138241574237353">Restart</translation>
<translation id="5895187275912066135">Issued On</translation>
<translation id="5901630391730855834">Yellow</translation>
@@ -1545,6 +1583,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="5921639886840618607">Save card to Google Account?</translation>
<translation id="5922853866070715753">Almost finished</translation>
<translation id="5932224571077948991">Site shows intrusive or misleading ads</translation>
+<translation id="5938153366081463283">Add virtual card</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347">Opening <ph name="SITE_NAME" />…</translation>
<translation id="5951495562196540101">Can't enrol with consumer account (packaged licence available).</translation>
@@ -1609,6 +1648,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="6120179357481664955">Remember your UPI ID?</translation>
<translation id="6124432979022149706">Chrome Enterprise connectors</translation>
<translation id="6127379762771434464">Item removed</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Learn more about Incognito in Chrome<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">Check any cables and reboot any routers, modems or other network
devices you may be using.</translation>
<translation id="614940544461990577">Try:</translation>
@@ -1621,7 +1661,6 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="6169916984152623906">Now you can browse privately, and other people who use this device won’t see your activity. However, downloads and bookmarks will be saved.</translation>
<translation id="6177128806592000436">Your connection to this site is not secure</translation>
<translation id="6180316780098470077">Retry interval</translation>
-<translation id="619448280891863779">Can ask to open and place windows on your screens</translation>
<translation id="6196640612572343990">Block third-party cookies</translation>
<translation id="6203231073485539293">Check your Internet connection</translation>
<translation id="6218753634732582820">Remove address from Chromium?</translation>
@@ -1644,7 +1683,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="6272383483618007430">Google update</translation>
<translation id="6276112860590028508">Pages from your reading list appear here</translation>
<translation id="627746635834430766">To pay faster next time, save your card and billing address to your Google Account.</translation>
-<translation id="6279098320682980337">Virtual card number not filled in? Click card details to copy</translation>
+<translation id="6279183038361895380">Press |<ph name="ACCELERATOR" />| to show your cursor</translation>
<translation id="6280223929691119688">Can’t deliver to this address. Select a different address.</translation>
<translation id="6282194474023008486">Postcode</translation>
<translation id="6285507000506177184">Manage downloads in Chrome button; press Enter to manage files that you have downloaded in Chrome</translation>
@@ -1652,6 +1691,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="6290238015253830360">Your suggested articles appear here</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{Your device will restart now}=1{Your device will restart in 1 second}other{Your device will restart in # seconds}}</translation>
<translation id="6302269476990306341">Google Assistant in Chrome stopping</translation>
<translation id="6305205051461490394"><ph name="URL" /> is unreachable.</translation>
<translation id="6312113039770857350">Web page not available</translation>
@@ -1725,6 +1765,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="6529602333819889595">&amp;Redo Delete</translation>
<translation id="6545864417968258051">Bluetooth scanning</translation>
<translation id="6547208576736763147">Dual punch left</translation>
+<translation id="6554732001434021288">Last visited <ph name="NUM_DAYS" /> days ago</translation>
<translation id="6556866813142980365">Redo</translation>
<translation id="6569060085658103619">You're viewing an extension page</translation>
<translation id="6573200754375280815">Dual punch right</translation>
@@ -1785,7 +1826,6 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="6757797048963528358">Your device went to sleep.</translation>
<translation id="6767985426384634228">Update address?</translation>
<translation id="6768213884286397650">Hagaki (Postcard)</translation>
-<translation id="6774185088257932239"><ph name="BEGIN_LINK" />Learn more<ph name="END_LINK" /> about Incognito</translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">Violet</translation>
<translation id="6786747875388722282">Extensions</translation>
@@ -1869,7 +1909,6 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="706295145388601875">Add and manage addresses in Chrome settings</translation>
<translation id="7064851114919012435">Contact info</translation>
<translation id="7068733155164172741">Enter <ph name="OTP_LENGTH" />-digit code</translation>
-<translation id="7070090581017165256">About this site</translation>
<translation id="70705239631109039">Your connection is not fully secure</translation>
<translation id="7075452647191940183">Request is too large</translation>
<translation id="7079718277001814089">This site contains malware</translation>
@@ -1886,6 +1925,12 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="7111012039238467737">(Valid)</translation>
<translation id="7118618213916969306">Search for clipboard URL, <ph name="SHORT_URL" /></translation>
<translation id="7119414471315195487">Close other tabs or programmes</translation>
+<translation id="7129355289156517987">When you close all Chromium Incognito tabs, your activity in those tabs is cleared from this device:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Browsing activity<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Search history<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Information entered in forms<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">Can’t deliver to this address. Select a different address.</translation>
<translation id="7132939140423847331">Your admin has prohibited this data from being copied.</translation>
<translation id="7135130955892390533">Show status</translation>
@@ -1908,6 +1953,7 @@ This will otherwise be blocked by your privacy settings. This will allow the con
<translation id="7192203810768312527">Frees up <ph name="SIZE" />. Some sites may load more slowly on your next visit.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">Your administrator can see:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, press Tab, then Enter to open a new incognito tab to browse privately</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> doesn't adhere to security standards.</translation>
<translation id="7210993021468939304">Linux activity within the container, and can install and run Linux apps within the container</translation>
@@ -1939,6 +1985,7 @@ Additional details:
<translation id="7304562222803846232">Manage Google Account privacy settings</translation>
<translation id="7305756307268530424">Start slower</translation>
<translation id="7308436126008021607">background sync</translation>
+<translation id="7310392214323165548">Device will restart very soon</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">Connection help</translation>
<translation id="7323804146520582233">Hide the '<ph name="SECTION" />' section</translation>
@@ -1946,6 +1993,7 @@ Additional details:
<translation id="7334320624316649418">&amp;Redo reorder</translation>
<translation id="7335157162773372339">Can ask to use your camera</translation>
<translation id="7337248890521463931">Show more lines</translation>
+<translation id="7337418456231055214">Virtual card number not filled in? Click card details to copy. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">Not available on your platform.</translation>
<translation id="733923710415886693">The server's certificate was not disclosed via Certificate Transparency.</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1968,6 +2016,7 @@ Additional details:
<translation id="7378627244592794276">Nope</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">Not applicable</translation>
+<translation id="7388594495505979117">{0,plural, =1{Your device will restart in 1 minute}other{Your device will restart in # minutes}}</translation>
<translation id="7390545607259442187">Confirm Card</translation>
<translation id="7392089738299859607">Update address</translation>
<translation id="7399802613464275309">Safety check</translation>
@@ -2004,6 +2053,12 @@ Additional details:
<translation id="7485870689360869515">No data found.</translation>
<translation id="7495528107193238112">This content is blocked. Contact the site owner to fix the issue.</translation>
<translation id="7497998058912824456">Create doc button: press Enter to create a new Google Doc quickly</translation>
+<translation id="7506488012654002225">Chromium <ph name="BEGIN_EMPHASIS" />won’t save<ph name="END_EMPHASIS" /> the following information:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Your browsing history
+ <ph name="LIST_ITEM" />Cookies and site data
+ <ph name="LIST_ITEM" />Information entered in forms
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">Returned policy device ID is empty or doesn't match current device ID</translation>
<translation id="7508870219247277067">Avocado green</translation>
<translation id="7511955381719512146">The Wi-Fi that you are using may require you to visit <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
@@ -2117,7 +2172,6 @@ Additional details:
<translation id="7813600968533626083">Remove form suggestion from Chrome?</translation>
<translation id="781440967107097262">Share clipboard?</translation>
<translation id="7815407501681723534">Found <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> for '<ph name="SEARCH_STRING" />'</translation>
-<translation id="782125616001965242">Show information about this site</translation>
<translation id="782886543891417279">The Wi-Fi that you are using (<ph name="WIFI_NAME" />) may require you to visit its login page.</translation>
<translation id="7836231406687464395">Postfix (Envelope)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{None}=1{1 app (<ph name="EXAMPLE_APP_1" />)}=2{2 apps (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}other{# apps (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" /> <ph name="AND_MORE" />)}}</translation>
@@ -2134,7 +2188,6 @@ Additional details:
<translation id="7888575728750733395">Print rendering intent</translation>
<translation id="7894280532028510793">If spelling is correct, <ph name="BEGIN_LINK" />try running network Diagnostics<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (Envelope)</translation>
-<translation id="7931318309563332511">Unknown</translation>
<translation id="793209273132572360">Update address?</translation>
<translation id="7932579305932748336">Coat</translation>
<translation id="79338296614623784">Enter a valid phone number</translation>
@@ -2159,13 +2212,14 @@ Additional details:
<translation id="7976214039405368314">Too many requests</translation>
<translation id="7977538094055660992">Output device</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">Linked with</translation>
<translation id="798134797138789862">Can ask to use virtual reality devices and data</translation>
<translation id="7984945080620862648">You cannot visit <ph name="SITE" /> at the moment because the website sent scrambled credentials that Chrome cannot process. Network errors and attacks are usually temporary, so this page will probably work later.</translation>
-<translation id="79859296434321399">To view augmented reality content, install ARCore</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">Bind</translation>
<translation id="7992044431894087211">Screen sharing with <ph name="APPLICATION_TITLE" /> was resumed</translation>
<translation id="7995512525968007366">Not Specified</translation>
+<translation id="7998269595945679889">Open the incognito tab button, press Enter to open a new incognito tab to browse privately</translation>
<translation id="800218591365569300">Try closing other tabs or programmes to free up memory.</translation>
<translation id="8004582292198964060">Browser</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{This card and its billing address will be saved. You'll be able to use it when signed in to <ph name="USER_EMAIL" />.}other{These cards and their billing addresses will be saved. You'll be able to use them when signed in to <ph name="USER_EMAIL" />.}}</translation>
@@ -2225,6 +2279,7 @@ Additional details:
<translation id="8202370299023114387">Conflict</translation>
<translation id="8206978196348664717">Prc4 (Envelope)</translation>
<translation id="8211406090763984747">Connection is secure</translation>
+<translation id="8217240300496046857">Sites can't use cookies that track you across the web. Features on some sites may break.</translation>
<translation id="8218327578424803826">Assigned Location:</translation>
<translation id="8220146938470311105">C7/C6 (Envelope)</translation>
<translation id="8225771182978767009">The person who set up this computer has chosen to block this site.</translation>
@@ -2265,14 +2320,9 @@ Additional details:
<translation id="830498451218851433">Fold half</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">Apps installed and how often they are used</translation>
+<translation id="8317207217658302555">Update ARCore?</translation>
<translation id="831997045666694187">Evening</translation>
<translation id="8321476692217554900">notifications</translation>
-<translation id="8328484624016508118">After closing all Incognito tabs, Chrome clears:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Your browsing activity from this device<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Your search history from this device<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Information entered into forms<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489">Access to <ph name="HOST_NAME" /> was denied</translation>
<translation id="833262891116910667">Highlight</translation>
<translation id="8339163506404995330">Pages in <ph name="LANGUAGE" /> will not be translated</translation>
@@ -2324,6 +2374,7 @@ Additional details:
<translation id="8507227106804027148">Command line</translation>
<translation id="8508648098325802031">Search icon</translation>
<translation id="8511402995811232419">Manage cookies</translation>
+<translation id="8519753333133776369">HID device allowed by your administrator</translation>
<translation id="8522552481199248698">Chrome can help you protect your Google account and change your password.</translation>
<translation id="8530813470445476232">Clear your browsing history, cookies, cache and more in Chrome settings</translation>
<translation id="8533619373899488139">Visit &lt;strong&gt;chrome://policy&lt;/strong&gt; to see the list of blocked URLs and other policies enforced by your system administrator.</translation>
@@ -2335,7 +2386,6 @@ Additional details:
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{Reset permission}other{Reset permissions}}</translation>
<translation id="8555010941760982128">Use this code at checkout</translation>
<translation id="8557066899867184262">The CVC is located behind your card.</translation>
-<translation id="8558485628462305855">To view augmented reality content, update ARCore</translation>
<translation id="8559762987265718583">A private connection to <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> can't be established because your device's date and time (<ph name="DATE_AND_TIME" />) are incorrect.</translation>
<translation id="8564182942834072828">Separate documents/Uncollated copies</translation>
<translation id="8564985650692024650">Chromium recommends resetting your <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> password if you reused it on other sites.</translation>
@@ -2354,6 +2404,7 @@ Additional details:
<translation id="865032292777205197">motion sensors</translation>
<translation id="8663226718884576429">Order Summary, <ph name="TOTAL_LABEL" />, More Details</translation>
<translation id="8666678546361132282">English</translation>
+<translation id="8669306706049782872">Use info about your screens to open and place windows</translation>
<translation id="867224526087042813">Signature</translation>
<translation id="8676424191133491403">No delay</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, answer, <ph name="ANSWER" /></translation>
@@ -2380,6 +2431,7 @@ Additional details:
<translation id="8731544501227493793">Manage passwords button; press enter to view and manage your passwords in Chrome settings</translation>
<translation id="8734529307927223492">Your <ph name="DEVICE_TYPE" /> is managed by <ph name="MANAGER" /></translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, press tab, then enter to open a new incognito window to browse privately</translation>
+<translation id="8737685506611670901">Open <ph name="PROTOCOL" /> links instead of <ph name="REPLACED_HANDLER_TITLE" /></translation>
<translation id="8738058698779197622">To establish a secure connection, your clock needs to be set correctly. This is because the certificates that websites use to identify themselves are only valid for specific periods of time. Since your device's clock is incorrect, Chromium cannot verify these certificates.</translation>
<translation id="8740359287975076522"><ph name="HOST_NAME" />’s &lt;abbr id="dnsDefinition"&gt;DNS address&lt;/abbr&gt; could not be found. Diagnosing the problem.</translation>
<translation id="8742371904523228557"><ph name="ONE_TIME_CODE" /> is your code for <ph name="ORIGIN" /></translation>
@@ -2407,6 +2459,7 @@ Additional details:
<translation id="883848425547221593">Other Bookmarks</translation>
<translation id="884264119367021077">Delivery address</translation>
<translation id="884923133447025588">No revocation mechanism found.</translation>
+<translation id="8849262850971482943">Use your virtual card for added security</translation>
<translation id="885730110891505394">Sharing with Google</translation>
<translation id="8858065207712248076">Chrome recommends resetting your <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> password if you reused it on other sites.</translation>
<translation id="885906927438988819">If spelling is correct, <ph name="BEGIN_LINK" />try running windows network Diagnostics<ph name="END_LINK" />.</translation>
@@ -2456,6 +2509,7 @@ Additional details:
<translation id="9004367719664099443">VR session in progress</translation>
<translation id="9005998258318286617">Failed to load PDF document.</translation>
<translation id="9008201768610948239">Ignore</translation>
+<translation id="901834265349196618">email</translation>
<translation id="9020200922353704812">Card billing address required</translation>
<translation id="9020542370529661692">This page has been translated to <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9020742383383852663">A8</translation>
@@ -2504,6 +2558,7 @@ Additional details:
<translation id="9150045010208374699">Use your camera</translation>
<translation id="9150685862434908345">Your administrator can change your browser setup remotely. Activity on this device may also be managed outside of Chrome. <ph name="BEGIN_LINK" />Learn more<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">Updated</translation>
+<translation id="9155211586651734179">Audio peripherals attached</translation>
<translation id="9157595877708044936">Setting up...</translation>
<translation id="9158625974267017556">C6 (Envelope)</translation>
<translation id="9164029392738894042">Accuracy Check</translation>
diff --git a/chromium/components/strings/components_strings_es-419.xtb b/chromium/components/strings/components_strings_es-419.xtb
index 01901d39504..e8752100455 100644
--- a/chromium/components/strings/components_strings_es-419.xtb
+++ b/chromium/components/strings/components_strings_es-419.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">Ver detalles</translation>
<translation id="1030706264415084469"><ph name="URL" /> quiere almacenar datos de gran tamaño de forma permanente en tu dispositivo</translation>
<translation id="1032854598605920125">Girar a la derecha</translation>
+<translation id="1033329911862281889">El modo Incógnito no hace que seas invisible en línea:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Los sitios y servicios que uses pueden ver las visitas.<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Los empleadores o instituciones educativas pueden rastrear tu actividad de navegación.<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Los proveedores de servicios de Internet pueden supervisar el tráfico web.<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">Desactivar</translation>
<translation id="1036982837258183574">Presiona |<ph name="ACCELERATOR" />| para salir de la pantalla completa</translation>
<translation id="1038106730571050514">Mostrar sugerencias</translation>
<translation id="1038842779957582377">nombre desconocido</translation>
<translation id="1041998700806130099">Mensaje de la hoja del trabajo</translation>
<translation id="1048785276086539861">Cuando edites anotaciones, se mostrará este documento en una vista de una sola página</translation>
-<translation id="1049743911850919806">Incógnito</translation>
<translation id="1050038467049342496">Cierra las demás apps.</translation>
<translation id="1055184225775184556">&amp;Deshacer Agregar</translation>
<translation id="1056898198331236512">Advertencia</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">Caché de política correcta</translation>
<translation id="1130564665089811311">Botón Traducir página: presiona Intro para traducir esta página con Google Traductor</translation>
<translation id="1131264053432022307">Imagen que copiaste</translation>
+<translation id="1142846828089312304">Bloquear cookies de terceros en el modo Incógnito</translation>
<translation id="1150979032973867961">Este servidor no pudo probar que su dominio es <ph name="DOMAIN" />; el sistema operativo de la computadora no confía en el certificado de seguridad. Es posible que esto se deba a una configuración incorrecta o a que un atacante interceptó la conexión.</translation>
<translation id="1151972924205500581">Contraseña obligatoria</translation>
<translation id="1156303062776767266">Estás viendo un archivo local o compartido</translation>
@@ -64,7 +70,6 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="1178581264944972037">Detener</translation>
<translation id="1181037720776840403">Quitar</translation>
<translation id="1186201132766001848">Revisar contraseñas</translation>
-<translation id="1195210374336998651">Ir a la configuración de la app</translation>
<translation id="1195558154361252544">Se bloquearon automáticamente las notificaciones para todos los sitios, excepto en los sitios en que las permites</translation>
<translation id="1197088940767939838">Naranja</translation>
<translation id="1201402288615127009">Siguiente</translation>
@@ -111,7 +116,7 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="1307966114820526988">Funciones obsoletas</translation>
<translation id="1308113895091915999">Oferta disponible</translation>
<translation id="1312803275555673949">¿Qué evidencia lo respalda?</translation>
-<translation id="131405271941274527"><ph name="URL" /> quiere enviar y recibir información cuando presionas tu teléfono en un dispositivo NFC</translation>
+<translation id="1314311879718644478">Ver contenido de realidad aumentada</translation>
<translation id="1314509827145471431">Encuadernado a la derecha</translation>
<translation id="1318023360584041678">Guardado en el grupo de pestañas</translation>
<translation id="1319245136674974084">No volver a preguntar sobre esta app</translation>
@@ -161,6 +166,7 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="142858679511221695">Usuario de la nube</translation>
<translation id="1428729058023778569">Se muestra esta advertencia porque este sitio no admite HTTPS. <ph name="BEGIN_LEARN_MORE_LINK" />Más información<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">Imprimir</translation>
+<translation id="1432187715652018471">Esta página quiere instalar un controlador de servicios.</translation>
<translation id="1432581352905426595">Administrar motores de búsqueda</translation>
<translation id="1436185428532214179">Puede solicitar permiso para editar archivos y carpetas del dispositivo</translation>
<translation id="1442386063175183758">Plegado en ventana a la derecha</translation>
@@ -181,6 +187,12 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="1483493594462132177">Enviar</translation>
<translation id="1484290072879560759">Elegir dirección de envío</translation>
<translation id="1492194039220927094">Notificaciones push de políticas:</translation>
+<translation id="149293076951187737">Cuando cierras todas las pestañas de incógnito en Chrome, tu actividad en ellas se borra del dispositivo:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />La actividad de navegación<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />El historial de búsqueda<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />La información que ingreses en formularios<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">Volver a la pestaña</translation>
<translation id="1501859676467574491">Mostrar tarjetas de tu Cuenta de Google</translation>
<translation id="1507202001669085618">&lt;p&gt;Se muestra este error si usas un portal Wi-Fi donde debes acceder para establecer la conexión.&lt;/p&gt;
@@ -208,6 +220,8 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="1559572115229829303">&lt;p&gt;No se puede establecer una conexión privada a <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> porque la fecha y la hora del dispositivo (<ph name="DATE_AND_TIME" />) son incorrectas.&lt;/p&gt;
&lt;p&gt;Ajusta la fecha y la hora desde la sección &lt;strong&gt;General&lt;/strong&gt; de la app de &lt;strong&gt;Configuración&lt;/strong&gt; .&lt;/p&gt;</translation>
+<translation id="1559839503761818503">El administrador reiniciará el dispositivo el <ph name="DATE" /> a las <ph name="TIME" /></translation>
+<translation id="156703335097561114">La información de la red, como las direcciones, la configuración de las interfaces y la calidad de la conexión</translation>
<translation id="1567040042588613346">Esta política se comporta según lo esperado, pero sustituyó el mismo valor que se configuró en otro lugar.</translation>
<translation id="1569487616857761740">Ingresa una fecha de vencimiento</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="1583429793053364125">Se produjo un error cuando se mostraba la página web.</translation>
<translation id="1586541204584340881">Las extensiones que instalaste</translation>
<translation id="1588438908519853928">Normal</translation>
+<translation id="1589050138437146318">¿Deseas instalar ARCore?</translation>
<translation id="1592005682883173041">Acceso a datos locales</translation>
<translation id="1594030484168838125">Seleccionar</translation>
<translation id="160851722280695521">Jugar al juego del dinosaurio de Chrome</translation>
@@ -279,6 +294,7 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="1763864636252898013">Este servidor no pudo probar que su dominio es <ph name="DOMAIN" />; el sistema operativo del dispositivo no confía en el certificado de seguridad. Es posible que esto se deba a una configuración incorrecta o a que un atacante interceptó la conexión.</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Intenta ejecutar el Diagnóstico de red de Windows<ph name="END_LINK" />.</translation>
<translation id="1772163372082567643">El servidor <ph name="ORIGIN" /> al que te diriges estableció un encabezado donde se indica que se aplica una política de origen a todas las solicitudes. Sin embargo, el encabezado tiene un formato no válido, por lo que el navegador no puede cumplir con tu solicitud para <ph name="SITE" />. Los operadores de sitios pueden usar políticas de origen para configurar la seguridad y otras propiedades de un sitio.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Obtén más información sobre el modo Incógnito en Chromium<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">Tus pestañas abiertas aparecen aquí</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -406,6 +422,7 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="22081806969704220">Bandeja 3</translation>
<translation id="2212735316055980242">No se encontró la política.</translation>
<translation id="2213606439339815911">Recuperando entradas…</translation>
+<translation id="2213612003795704869">Se imprime la página</translation>
<translation id="2215727959747642672">Edición de archivo</translation>
<translation id="2218879909401188352">Es posible que los atacantes que se encuentran actualmente en <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> instalen apps peligrosas que dañen tu dispositivo, agreguen cargos ocultos en la factura de tu servicio móvil o roben tu información personal. <ph name="BEGIN_LEARN_MORE_LINK" />Más información<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">Sin Internet</translation>
@@ -415,6 +432,7 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="2248949050832152960">Usar WebAuthn</translation>
<translation id="2250931979407627383">Costura de borde a la izquierda</translation>
<translation id="225207911366869382">Este valor ya no se utiliza para esta política.</translation>
+<translation id="2256115617011615191">Reiniciar ahora</translation>
<translation id="2258928405015593961">Ingresa una fecha de vencimiento futura y vuelve a intentarlo</translation>
<translation id="225943865679747347">Código de error: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">Error de HTTP</translation>
@@ -442,6 +460,7 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="2337852623177822836">Configuración controlada por tu administrador</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> desea sincronizarse</translation>
<translation id="2346319942568447007">Imagen que copiaste</translation>
+<translation id="2350796302381711542">¿Deseas permitir que <ph name="HANDLER_HOSTNAME" /> abra todos los vínculos de <ph name="PROTOCOL" /> en lugar de <ph name="REPLACED_HANDLER_TITLE" />?</translation>
<translation id="2354001756790975382">Otros favoritos</translation>
<translation id="2354430244986887761">Navegación segura de Google recientemente <ph name="BEGIN_LINK" />encontró apps dañinas<ph name="END_LINK" /> en <ph name="SITE" />.</translation>
<translation id="2355395290879513365">Es posible que los atacantes vean las imágenes que observas en este sitio y las modifiquen para engañarte.</translation>
@@ -467,6 +486,7 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="2413528052993050574">Este servidor no pudo probar que su dominio es <ph name="DOMAIN" /> y se podría revocar el certificado de seguridad. Es posible que esto se deba a una configuración incorrecta o a que un atacante interceptó la conexión.</translation>
<translation id="2414886740292270097">Oscuro</translation>
<translation id="2430968933669123598">Botón Administrar la Cuenta de Google, presiona Intro para administrar la información, privacidad y seguridad de tu Cuenta de Google</translation>
+<translation id="2436186046335138073">¿Deseas permitir que <ph name="HANDLER_HOSTNAME" /> abra todos los vínculos de <ph name="PROTOCOL" />?</translation>
<translation id="2438874542388153331">Perforación cuádruple a la derecha</translation>
<translation id="2450021089947420533">Exploraciones</translation>
<translation id="2463739503403862330">Llenar</translation>
@@ -474,6 +494,7 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="2465655957518002998">Elegir método de entrega</translation>
<translation id="2465688316154986572">Grapa</translation>
<translation id="2465914000209955735">Administrar los archivos que has descargado en Chrome</translation>
+<translation id="2466004615675155314">Mostrar información de la Web</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Ejecución del Diagnóstico de red<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">Orden de 1 a N</translation>
<translation id="2470767536994572628">Cuando edites anotaciones, se mostrará este documento en una vista de una sola página y en su rotación original</translation>
@@ -494,6 +515,7 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="2523886232349826891">Solo se guardará en este dispositivo</translation>
<translation id="2524461107774643265">Agregar más información</translation>
<translation id="2529899080962247600">Esta campo no debe tener más de <ph name="MAX_ITEMS_LIMIT" /> entradas. Se ignorarán todas las entradas posteriores.</translation>
+<translation id="2535585790302968248">Abre una nueva pestaña de incógnito para navegar de forma privada</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{y 1 más}other{y # más}}</translation>
<translation id="2536110899380797252">Agregar dirección</translation>
<translation id="2539524384386349900">Detectar</translation>
@@ -519,7 +541,14 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="2597378329261239068">Este documento está protegido por contraseña. Ingresa una contraseña.</translation>
<translation id="2609632851001447353">Variaciones</translation>
<translation id="2610561535971892504">Haz clic para copiar.</translation>
+<translation id="2617988307566202237">Chrome <ph name="BEGIN_EMPHASIS" />no guardará<ph name="END_EMPHASIS" /> la siguiente información:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />El historial de navegación
+ <ph name="LIST_ITEM" />Las cookies y datos de sitios
+ <ph name="LIST_ITEM" />La información que ingreses en formularios
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (Envelope)</translation>
+<translation id="2623663032199728144">Puede solicitar permiso para usar información de tus pantallas</translation>
<translation id="2625385379895617796">El reloj está adelantado</translation>
<translation id="262745152991669301">Puede solicitar permiso para establecer conexión con dispositivos USB</translation>
<translation id="2629325967560697240">Para acceder al nivel más alto de seguridad de Chrome, <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />activa la protección mejorada<ph name="END_ENHANCED_PROTECTION_LINK" />.</translation>
@@ -553,6 +582,7 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="2709516037105925701">Autocompletar</translation>
<translation id="2713444072780614174">Blanco</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />: presiona Tab y, luego, Intro para administrar tus datos de pago y de tarjetas de crédito en la configuración de Chrome</translation>
+<translation id="271663710482723385">Presiona |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| para salir de la pantalla completa</translation>
<translation id="2721148159707890343">Solicitud correcta</translation>
<translation id="2723669454293168317">Ejecutar una verificación de seguridad en la configuración de Chrome</translation>
<translation id="2726001110728089263">Bandeja lateral</translation>
@@ -583,6 +613,7 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="2850739647070081192">Invite (Envelope)</translation>
<translation id="2856444702002559011">Es posible que algunos atacantes intenten robar tu información de <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (p. ej., contraseñas, mensajes o tarjetas de crédito). <ph name="BEGIN_LEARN_MORE_LINK" />Más información<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">Este sitio muestra anuncios intrusivos o engañosos.</translation>
+<translation id="286512204874376891">La tarjeta virtual oculta tu tarjeta real para protegerte contra posibles fraudes. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">Friendly</translation>
<translation id="2876489322757410363">Saldrás del modo Incógnito para pagar mediante una aplicación externa. ¿Deseas continuar?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />, presiona Tab y, luego, Intro para administrar tu Navegación segura y más en la configuración de Chrome</translation>
@@ -607,6 +638,7 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="2930577230479659665">Cortar después de cada copia</translation>
<translation id="2932085390869194046">Sugerir contraseña…</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019">Abrir vínculos de <ph name="PROTOCOL" /></translation>
<translation id="2941952326391522266">Este servidor no pudo probar que su dominio es <ph name="DOMAIN" />; el certificado de seguridad proviene de <ph name="DOMAIN2" />. Es posible que esto se deba a una configuración incorrecta o a que un atacante interceptó la conexión.</translation>
<translation id="2943895734390379394">Hora de carga:</translation>
<translation id="2948083400971632585">Puedes inhabilitar los servidores proxy configurados para una conexión desde la página de configuración.</translation>
@@ -639,6 +671,7 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="3037605927509011580">¡Oh, no!</translation>
<translation id="3041612393474885105">Información sobre el certificado</translation>
<translation id="3044034790304486808">Reanudar la búsqueda</translation>
+<translation id="305162504811187366">El historial del Escritorio remoto de Chrome, incluidas las marcas de tiempo, los hosts y las ID de sesión de los clientes</translation>
<translation id="3060227939791841287">C9 (Envelope)</translation>
<translation id="3061707000357573562">Aplicar parche al servicio</translation>
<translation id="306573536155379004">Comenzó el juego.</translation>
@@ -680,6 +713,7 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="3197136577151645743">Puede solicitar permiso para saber en qué momento estás usando activamente este dispositivo</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />: presiona Tab y, luego, Intro para administrar en la configuración de Chrome qué información sincronizar</translation>
<translation id="320323717674993345">Cancelar pago</translation>
+<translation id="3203366800380907218">Desde la Web</translation>
<translation id="3207960819495026254">Agregada a favoritos</translation>
<translation id="3209034400446768650">La página puede cobrar cargos</translation>
<translation id="3212581601480735796">Se supervisa tu actividad en <ph name="HOSTNAME" /></translation>
@@ -696,10 +730,12 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="3234666976984236645">Siempre detectar contenido importante en este sitio</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />, presiona Tab y, luego, Intro para personalizar el estilo del navegador</translation>
<translation id="3240791268468473923">Se abrió la hoja inferior para indicar que las credenciales de pago seguro no coinciden</translation>
+<translation id="324180406144491771">Los vínculos “<ph name="HOST_NAME" />†están bloqueados</translation>
<translation id="3249845759089040423">Groovy</translation>
<translation id="3252266817569339921">Francés</translation>
<translation id="3257954757204451555">¿Quién es el autor de esta información?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />, presiona Tab, luego, Intro para crear un evento nuevo en el Calendario de Google rápidamente</translation>
+<translation id="3261488570342242926">Obtén más información sobre las tarjetas virtuales</translation>
<translation id="3264837738038045344">Botón Administrar la configuración de Chrome, presiona Intro para visitar tu configuración de Chrome</translation>
<translation id="3266793032086590337">Valor (en conflicto)</translation>
<translation id="3268451620468152448">Pestañas abiertas</translation>
@@ -713,6 +749,7 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="3288238092761586174">Es posible que <ph name="URL" /> deba realizar pasos adicionales para verificar tu pago.</translation>
<translation id="3293642807462928945">Más información sobre la política <ph name="POLICY_NAME" /></translation>
<translation id="3295444047715739395">Consulta y administra tus contraseñas en la configuración de Chrome</translation>
+<translation id="3303795387212510132">¿Deseas permitir que la app abra vínculos de <ph name="PROTOCOL_SCHEME" />?</translation>
<translation id="3303855915957856445">No se encontraron resultados en la búsqueda</translation>
<translation id="3304073249511302126">búsqueda de dispositivos Bluetooth</translation>
<translation id="3308006649705061278">Unidad organizativa (OU)</translation>
@@ -726,12 +763,6 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="3345782426586609320">Ojos</translation>
<translation id="3355823806454867987">Cambiar la configuración del proxy...</translation>
<translation id="3360103848165129075">Hoja del controlador de pagos</translation>
-<translation id="3361596688432910856">Chrome <ph name="BEGIN_EMPHASIS" />no guardará<ph name="END_EMPHASIS" /> la siguiente información:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />El historial de navegación
- <ph name="LIST_ITEM" />Cookies y datos de sitios
- <ph name="LIST_ITEM" />Información que ingreses en formularios
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">Se copió esta política de forma automática a partir de la política obsoleta <ph name="OLD_POLICY" />. En su lugar, debes usar esta política.</translation>
<translation id="3364869320075768271"><ph name="URL" /> quiere usar tus datos y dispositivos de realidad virtual</translation>
<translation id="3366477098757335611">Ver tarjetas</translation>
@@ -814,7 +845,6 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="3587738293690942763">Medio</translation>
<translation id="3592413004129370115">Italian (Envelope)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{Puedes restablecer tu grupo en cualquier momento. Te llevará aproximadamente un día unirte a un grupo nuevo.}=1{Puedes restablecer tu grupo en cualquier momento. Te llevará aproximadamente un día unirte a un grupo nuevo.}other{Puedes restablecer tu grupo en cualquier momento. Te llevará {NUM_DAYS} días unirte a un grupo nuevo.}}</translation>
-<translation id="3596012367874587041">Configuración de la app</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">El administrador bloqueó la aplicación</translation>
<translation id="3608932978122581043">Orientación de la entrada</translation>
@@ -857,6 +887,7 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="370972442370243704">Activar Exploraciones</translation>
<translation id="3711895659073496551">Suspender</translation>
<translation id="3712624925041724820">Licencias agotadas</translation>
+<translation id="3714633008798122362">Calendario web</translation>
<translation id="3714780639079136834">Activar los datos móviles o la conexión Wi-Fi.</translation>
<translation id="3715597595485130451">Conectar a Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Comprobar la configuración del proxy, firewall o DNS<ph name="END_LINK" />.</translation>
@@ -918,6 +949,7 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="3906954721959377182">Tablet</translation>
<translation id="3909477809443608991"><ph name="URL" /> quiere reproducir contenido protegido. Google verificará la identidad de tu dispositivo, y es posible que este sitio acceda a ella.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">Rechazar</translation>
<translation id="3939773374150895049">¿Deseas usar WebAuthn en lugar de CVC?</translation>
<translation id="3946209740501886391">Preguntar siempre en este sitio</translation>
<translation id="3947595700203588284">Puede solicitar permiso para conectarse con dispositivos MIDI</translation>
@@ -938,6 +970,7 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="3987940399970879459">Menos de 1 MB</translation>
<translation id="3990250421422698716">Desplazamiento del borde</translation>
<translation id="3996311196211510766">El sitio <ph name="ORIGIN" /> solicitó que se aplique una política de origen a todas las solicitudes. Sin embargo, no es posible en este momento.</translation>
+<translation id="4009243425692662128">Se envía el contenido de las páginas que imprimes a Google Cloud o a terceros para su análisis. Por ejemplo, es posible que se analice para detectar datos sensibles.</translation>
<translation id="4010758435855888356">¿Quieres permitir el acceso al almacenamiento?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{Documento PDF con {COUNT} página}other{Documento PDF con {COUNT} páginas}}</translation>
<translation id="4023431997072828269">Dado que se está utilizando una conexión no segura para enviar este formulario, otras personas podrán ver tu información.</translation>
@@ -1028,6 +1061,7 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="4250680216510889253">No</translation>
<translation id="4253168017788158739">Nota</translation>
<translation id="425582637250725228">Es posible que los cambios que implementaste no se puedan guardar.</translation>
+<translation id="425869179292622354">¿Deseas aumentar su nivel de seguridad con una tarjeta virtual?</translation>
<translation id="4258748452823770588">Firma no válida</translation>
<translation id="4261046003697461417">No se pueden realizar anotaciones en documentos protegidos</translation>
<translation id="4265872034478892965">Permitido por tu administrador</translation>
@@ -1090,6 +1124,7 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="4434045419905280838">Ventanas emergentes y redireccionamientos</translation>
<translation id="4435702339979719576">Postcard)</translation>
<translation id="443673843213245140">Se inhabilitó el uso de un proxy, pero se especificó una configuración explícita de proxy.</translation>
+<translation id="4441832193888514600">Se ignoró porque la política puede establecerse solo como política del usuario basada en la nube.</translation>
<translation id="4450893287417543264">No volver a mostrar</translation>
<translation id="4451135742916150903">Puede solicitar permiso para conectarse a dispositivos HID</translation>
<translation id="4452328064229197696">La contraseña que acabas de usar se encontró en una violación de la seguridad de los datos. A fin de asegurar tu cuenta, el Administrador de contraseñas de Google te recomienda revisar las contraseñas guardadas.</translation>
@@ -1145,6 +1180,7 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="4628948037717959914">Foto</translation>
<translation id="4631649115723685955">Devolución de dinero vinculada</translation>
<translation id="4636930964841734540">Información</translation>
+<translation id="4638670630777875591">Modo Incógnito en Chromium</translation>
<translation id="464342062220857295">Buscar funciones</translation>
<translation id="4644670975240021822">Orden inverso hacia abajo</translation>
<translation id="4646534391647090355">Ir ahora</translation>
@@ -1165,6 +1201,7 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="4708268264240856090">Se interrumpió la conexión</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Ejecución del Diagnóstico de red de Windows<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426">Contraseña de <ph name="USERNAME" /></translation>
<translation id="4724144314178270921">Puede solicitar permiso para ver imágenes y texto del portapapeles</translation>
<translation id="4726672564094551039">Volver a cargar políticas</translation>
<translation id="4728558894243024398">Plataforma</translation>
@@ -1186,6 +1223,7 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="4757993714154412917">Ingresaste tu contraseña en un sitio engañoso. Para proteger tus cuentas, Chromium te recomienda revisar las contraseñas que tengas guardadas.</translation>
<translation id="4758311279753947758">Agregar información de contacto</translation>
<translation id="4761104368405085019">Usar tu micrófono</translation>
+<translation id="4761869838909035636">Ejecutar la Verificación de seguridad de Chrome</translation>
<translation id="4764776831041365478">Es posible que la página web en <ph name="URL" /> no funcione temporalmente o se haya trasladado de manera permanente a una nueva dirección web.</translation>
<translation id="4766713847338118463">Grapas dobles en la parte inferior</translation>
<translation id="4771973620359291008">Se ha producido un error desconocido.</translation>
@@ -1206,12 +1244,6 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="4819347708020428563">¿Quieres editar anotaciones en la vista predeterminada?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />, presiona Tab y, luego, Intro para crear una nueva hoja de cálculo de Google rápidamente</translation>
<translation id="4825507807291741242">Powerful</translation>
-<translation id="4827402517081186284">El modo Incógnito no te hace invisible en línea:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Los sitios saben que los visitas.<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Las empresas o instituciones educativas pueden rastrear tu actividad de navegación.<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Los proveedores de servicios de Internet pueden supervisar el tráfico web.<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">Activar advertencias</translation>
<translation id="4838327282952368871">Dreamy</translation>
<translation id="4840250757394056958">Ver tu historial de Chrome</translation>
@@ -1223,12 +1255,12 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="4854362297993841467">Este método de entrega no está disponible. Prueba otro método.</translation>
<translation id="4854853140771946034">Crear una nota nueva en Google Keep rápidamente</translation>
<translation id="485902285759009870">Verificando código…</translation>
+<translation id="4866506163384898554">Presiona |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| para mostrar tu cursor</translation>
<translation id="4876188919622883022">Vista simplificada</translation>
<translation id="4876305945144899064">Sin nombre de usuario</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{Ninguna}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831">Búsqueda de <ph name="TEXT" /></translation>
<translation id="4879491255372875719">Automático (predeterminado)</translation>
-<translation id="4879725228911483934">Abrir y ubicar ventanas en tus pantallas</translation>
<translation id="4880827082731008257">Buscar historial</translation>
<translation id="4881695831933465202">Abrir</translation>
<translation id="4885256590493466218">Pagar con <ph name="CARD_DETAIL" /> en la confirmación de la compra</translation>
@@ -1237,6 +1269,7 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">Noveno rollo</translation>
<translation id="4901778704868714008">Guardar…</translation>
+<translation id="4905659621780993806">El administrador reiniciará el dispositivo el <ph name="DATE" /> a las <ph name="TIME" />. Guarda los elementos abiertos antes de reiniciar el dispositivo.</translation>
<translation id="4913987521957242411">Perforación en la esquina superior izquierda</translation>
<translation id="4918221908152712722">Instala <ph name="APP_NAME" /> (no es necesario que descargues la app)</translation>
<translation id="4923459931733593730">Pago</translation>
@@ -1245,6 +1278,7 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />: presiona Tab y, luego, Intro para realizar una búsqueda</translation>
<translation id="4930153903256238152">Gran capacidad</translation>
+<translation id="4940163644868678279">Modo Incógnito en Chrome</translation>
<translation id="4943872375798546930">Sin resultados</translation>
<translation id="4950898438188848926">Botón para cambiar de pestaña; presiona Intro para cambiar a la pestaña abierta <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="495170559598752135">Acciones</translation>
@@ -1254,6 +1288,7 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="4968522289500246572">Esta app está diseñada para dispositivos móviles y es posible que el cambio de tamaño no funcione correctamente. Posiblemente la app se reiniciará o presentará problemas.</translation>
<translation id="4969341057194253438">Borrar grabación</translation>
<translation id="4973922308112707173">Perforación doble en la parte superior</translation>
+<translation id="4976702386844183910">Última visita: <ph name="DATE" /></translation>
<translation id="4984088539114770594">¿Permitir el uso del micrófono?</translation>
<translation id="4984339528288761049">Prc5 (Envelope)</translation>
<translation id="4989163558385430922">Ver todo</translation>
@@ -1315,6 +1350,7 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="5138227688689900538">Mostrar menos</translation>
<translation id="5145883236150621069">Código de error en la respuesta de la política</translation>
<translation id="5146995429444047494">Se bloquearon las notificaciones de <ph name="ORIGIN" /></translation>
+<translation id="514704532284964975"><ph name="URL" /> quiere ver y cambiar la información de los dispositivos NFC que presionas con tu teléfono</translation>
<translation id="5148809049217731050">Hacia arriba</translation>
<translation id="515292512908731282">C4 (Envelope)</translation>
<translation id="5158275234811857234">Portada</translation>
@@ -1339,6 +1375,7 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="5215116848420601511">Formas de pago y direcciones con Google Pay</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">Bandeja 13</translation>
+<translation id="5216942107514965959">Última visita: hoy</translation>
<translation id="5222812217790122047">Correo electrónico (obligatorio)</translation>
<translation id="5230733896359313003">Dirección de envío</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1359,7 +1396,6 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">Propiedades del documento</translation>
<translation id="528468243742722775">Finalizar</translation>
-<translation id="5284909709419567258">Direcciones de red</translation>
<translation id="5285570108065881030">Mostrar todas las contraseñas guardadas</translation>
<translation id="5287240709317226393">Mostrar cookies</translation>
<translation id="5287456746628258573">Este sitio usa una configuración de seguridad obsoleta. Si envías información (p. ej., contraseñas o números de tarjetas de crédito) a este sitio, es posible que quede expuesta.</translation>
@@ -1443,6 +1479,7 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="5556459405103347317">Cargar de nuevo</translation>
<translation id="5560088892362098740">Fecha de vencimiento</translation>
<translation id="55635442646131152">Esquema del documento</translation>
+<translation id="5565613213060953222">Abrir pestaña de incógnito</translation>
<translation id="5565735124758917034">Activo</translation>
<translation id="5570825185877910964">Proteger cuenta</translation>
<translation id="5571083550517324815">No se puede retirar el artículo en esta dirección. Selecciona una diferente.</translation>
@@ -1525,6 +1562,7 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="5869522115854928033">Contraseñas almacenadas</translation>
<translation id="5873013647450402046">El banco desea confirmar tu identidad.</translation>
<translation id="5887400589839399685">Tarjeta guardada</translation>
+<translation id="5887687176710214216">Última visita: ayer</translation>
<translation id="5895138241574237353">Reiniciar</translation>
<translation id="5895187275912066135">Emitido el</translation>
<translation id="5901630391730855834">Amarillo</translation>
@@ -1538,6 +1576,7 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="5921639886840618607">¿Quieres guardar la tarjeta en la Cuenta de Google?</translation>
<translation id="5922853866070715753">Ya casi</translation>
<translation id="5932224571077948991">El sitio muestra anuncios intrusivos o engañosos</translation>
+<translation id="5938153366081463283">Agregar tarjeta virtual</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347">Abriendo <ph name="SITE_NAME" />…</translation>
<translation id="5951495562196540101">No se puede realizar la inscripción con una cuenta personal (licencia de paquete disponible).</translation>
@@ -1602,6 +1641,7 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="6120179357481664955">¿Recuerdas tu ID de IUP?</translation>
<translation id="6124432979022149706">Conectores de Chrome Enterprise</translation>
<translation id="6127379762771434464">Se eliminó el elemento</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Obtén más información sobre el modo Incógnito en Chrome<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">Revisa los cables y reinicia los routers, módems u otros dispositivos
de red que estés usando.</translation>
<translation id="614940544461990577">Intenta:</translation>
@@ -1614,7 +1654,6 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="6169916984152623906">Ahora puedes navegar con privacidad. Si otras personas usan este dispositivo, no verán tu actividad. Sin embargo, se guardarán las descargas y los favoritos.</translation>
<translation id="6177128806592000436">Tu conexión con este sitio no es segura</translation>
<translation id="6180316780098470077">Intervalo entre reintentos</translation>
-<translation id="619448280891863779">Puede solicitar permiso para abrir ventanas y colocarlas en tus pantallas</translation>
<translation id="6196640612572343990">Bloquear cookies de terceros</translation>
<translation id="6203231073485539293">Comprueba tu conexión a Internet.</translation>
<translation id="6218753634732582820">¿Confirmas que quieres quitar la dirección de Chromium?</translation>
@@ -1637,7 +1676,7 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="6272383483618007430">Google Actualización</translation>
<translation id="6276112860590028508">Las páginas de tu lista de lectura aparecen aquí</translation>
<translation id="627746635834430766">Para realizar pagos de forma más rápida la próxima vez, guarda tu tarjeta y dirección de facturación en tu Cuenta de Google.</translation>
-<translation id="6279098320682980337">¿No se completó el número de la tarjeta virtual? Haz clic en los detalles de la tarjeta para copiarlos.</translation>
+<translation id="6279183038361895380">Presiona |<ph name="ACCELERATOR" />| para mostrar tu cursor</translation>
<translation id="6280223929691119688">La dirección de envío no es válida. Selecciona una dirección diferente.</translation>
<translation id="6282194474023008486">Código postal</translation>
<translation id="6285507000506177184">Botón Administrar las descargas en Chrome: presiona Intro para administrar los archivos que has descargado en Chrome</translation>
@@ -1645,6 +1684,7 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="6290238015253830360">Tus artículos sugeridos aparecen aquí</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{El dispositivo se reiniciará ahora}=1{El dispositivo se reiniciará dentro de 1 segundo}other{El dispositivo se reiniciará dentro de # segundos}}</translation>
<translation id="6302269476990306341">Se está deteniendo el Asistente de Google en Chrome</translation>
<translation id="6305205051461490394">No se puede acceder a <ph name="URL" />.</translation>
<translation id="6312113039770857350">Página web no disponible</translation>
@@ -1718,6 +1758,7 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="6529602333819889595">&amp;Rehacer Eliminar</translation>
<translation id="6545864417968258051">Búsqueda de dispositivos Bluetooth</translation>
<translation id="6547208576736763147">Perforación doble a la izquierda</translation>
+<translation id="6554732001434021288">Última visita: hace <ph name="NUM_DAYS" /> días</translation>
<translation id="6556866813142980365">Rehacer</translation>
<translation id="6569060085658103619">Estás viendo la página de una extensión</translation>
<translation id="6573200754375280815">Perforación doble a la derecha</translation>
@@ -1778,7 +1819,6 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="6757797048963528358">El dispositivo se suspendió.</translation>
<translation id="6767985426384634228">¿Deseas actualizar la dirección?</translation>
<translation id="6768213884286397650">Hagaki (Postcard)</translation>
-<translation id="6774185088257932239"><ph name="BEGIN_LINK" />Más información<ph name="END_LINK" /> sobre el modo Incógnito</translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">Violeta</translation>
<translation id="6786747875388722282">Extensiones</translation>
@@ -1862,7 +1902,6 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="706295145388601875">Agrega y administra direcciones en la configuración de Chrome</translation>
<translation id="7064851114919012435">Información de contacto</translation>
<translation id="7068733155164172741">Ingresa un código de <ph name="OTP_LENGTH" /> dígitos</translation>
-<translation id="7070090581017165256">Acerca de este sitio</translation>
<translation id="70705239631109039">La conexión no es completamente segura</translation>
<translation id="7075452647191940183">La solicitud es demasiado grande</translation>
<translation id="7079718277001814089">Este sitio contiene software malicioso</translation>
@@ -1879,6 +1918,12 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="7111012039238467737">(Válido)</translation>
<translation id="7118618213916969306">Buscar la URL <ph name="SHORT_URL" /> del portapapeles</translation>
<translation id="7119414471315195487">Cierra las demás pestañas o programas.</translation>
+<translation id="7129355289156517987">Cuando cierras todas las pestañas de incógnito en Chromium, tu actividad en ellas se borra del dispositivo:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Actividad de navegación<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Historial de búsqueda<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Información que ingreses en formularios<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">No se pueden realizar envíos a esa dirección. Selecciona una dirección diferente.</translation>
<translation id="7132939140423847331">Tu administrador prohíbe que se copien estos datos.</translation>
<translation id="7135130955892390533">Mostrar estado</translation>
@@ -1901,6 +1946,7 @@ De lo contrario, la configuración de privacidad bloqueará esta acción. Esto p
<translation id="7192203810768312527">Esta acción libera hasta <ph name="SIZE" />. Es posible que algunos sitios carguen más lento en tu próxima visita.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">Tu administrador puede ver lo siguiente:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, presiona Tab y, luego, Intro para abrir una nueva pestaña de incógnito y así navegar de forma privada</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> no cumple con las normas de seguridad.</translation>
<translation id="7210993021468939304">La actividad de Linux en el contenedor; también pueden instalar y ejecutar apps de Linux en el contenedor</translation>
@@ -1932,6 +1978,7 @@ Detalles adicionales:
<translation id="7304562222803846232">Administra la configuración de privacidad de la Cuenta de Google</translation>
<translation id="7305756307268530424">Empezar más despacio</translation>
<translation id="7308436126008021607">sincronización en segundo plano</translation>
+<translation id="7310392214323165548">El dispositivo se reiniciará en breve</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">Ayuda con la conexión</translation>
<translation id="7323804146520582233">Ocultar la sección "<ph name="SECTION" />"</translation>
@@ -1939,6 +1986,7 @@ Detalles adicionales:
<translation id="7334320624316649418">&amp;Rehacer Reorganizar</translation>
<translation id="7335157162773372339">Puede solicitar permiso para usar la cámara</translation>
<translation id="7337248890521463931">Mostrar más líneas</translation>
+<translation id="7337418456231055214">¿No se completó el número de la tarjeta virtual? Haz clic en los detalles de la tarjeta para copiarlos. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">No está disponible para tu plataforma.</translation>
<translation id="733923710415886693">El certificado del servidor no se divulgó mediante el Certificado de transparencia.</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1961,6 +2009,7 @@ Detalles adicionales:
<translation id="7378627244592794276">No</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">No aplicable</translation>
+<translation id="7388594495505979117">{0,plural, =1{El dispositivo se reiniciará dentro de 1 minuto}other{El dispositivo se reiniciará dentro de # minutos}}</translation>
<translation id="7390545607259442187">Confirmar tarjeta</translation>
<translation id="7392089738299859607">Actualizar dirección</translation>
<translation id="7399802613464275309">Verificación de seguridad</translation>
@@ -1997,6 +2046,12 @@ Detalles adicionales:
<translation id="7485870689360869515">No se encontró ningún dato.</translation>
<translation id="7495528107193238112">Este contenido está bloqueado. Comunícate con el propietario del sitio para solucionar el problema.</translation>
<translation id="7497998058912824456">Botón Crear documento, presiona Intro para crear un nuevo documento de Google</translation>
+<translation id="7506488012654002225">Chromium <ph name="BEGIN_EMPHASIS" />no guardará<ph name="END_EMPHASIS" /> la siguiente información:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />El historial de navegación
+ <ph name="LIST_ITEM" />Las cookies y datos de sitios
+ <ph name="LIST_ITEM" />La información que ingreses en formularios
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">El ID de dispositivo de la política que se muestra está vacío o no coincide con el ID de dispositivo actual</translation>
<translation id="7508870219247277067">Verde aguacate</translation>
<translation id="7511955381719512146">Es posible que la red Wi-Fi que estás usando requiera que accedas a <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
@@ -2110,7 +2165,6 @@ Detalles adicionales:
<translation id="7813600968533626083">¿Confirmas que quieres quitar la sugerencia de formulario de Chrome?</translation>
<translation id="781440967107097262">¿Quieres compartir el portapapeles?</translation>
<translation id="7815407501681723534">Se encontraron <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> para "<ph name="SEARCH_STRING" />"</translation>
-<translation id="782125616001965242">Mostrar información acerca de este sitio</translation>
<translation id="782886543891417279">Es posible que la red Wi-Fi que estás usando (<ph name="WIFI_NAME" />) requiera que visites la página de acceso.</translation>
<translation id="7836231406687464395">Postfix (Envelope)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{Ninguna}=1{1 app (<ph name="EXAMPLE_APP_1" />)}=2{2 apps (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}other{# apps (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}}</translation>
@@ -2127,7 +2181,6 @@ Detalles adicionales:
<translation id="7888575728750733395">Propósito de conversión para impresión</translation>
<translation id="7894280532028510793">Si no hay errores, <ph name="BEGIN_LINK" />prueba ejecutar el diagnóstico de red<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (Envelope)</translation>
-<translation id="7931318309563332511">Desconocido</translation>
<translation id="793209273132572360">¿Quieres actualizar la dirección?</translation>
<translation id="7932579305932748336">Recubrimiento</translation>
<translation id="79338296614623784">Ingresa un número de teléfono válido</translation>
@@ -2152,13 +2205,14 @@ Detalles adicionales:
<translation id="7976214039405368314">Demasiadas solicitudes</translation>
<translation id="7977538094055660992">Dispositivo de salida</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">Está vinculada con</translation>
<translation id="798134797138789862">Puede solicitar permiso para usar datos y dispositivos de realidad virtual</translation>
<translation id="7984945080620862648">No puedes visitar <ph name="SITE" /> ahora porque el sitio web envió credenciales confusas que Chrome no puede procesar. Los ataques y errores de red suelen ser temporales, por lo que es posible que esta página funcione más tarde.</translation>
-<translation id="79859296434321399">Para ver contenido de realidad aumentada, instala ARCore</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">Encuadernado</translation>
<translation id="7992044431894087211">Se reanudó el uso compartido de la pantalla con <ph name="APPLICATION_TITLE" /></translation>
<translation id="7995512525968007366">Sin especificar</translation>
+<translation id="7998269595945679889">Botón Abrir pestaña de incógnito, presiona Intro para abrir una nueva pestaña de incógnito y así navegar de forma privada</translation>
<translation id="800218591365569300">Prueba cerrar las demás pestañas o programas para liberar memoria.</translation>
<translation id="8004582292198964060">Navegador</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{Se guardará esta tarjeta y su dirección de facturación. Podrás usarla cuando accedas a <ph name="USER_EMAIL" />.}other{Se guardarán estas tarjetas y sus direcciones de facturación. Podrás usarlas cuando accedas a <ph name="USER_EMAIL" />.}}</translation>
@@ -2218,6 +2272,7 @@ Detalles adicionales:
<translation id="8202370299023114387">Conflicto</translation>
<translation id="8206978196348664717">Prc4 (Envelope)</translation>
<translation id="8211406090763984747">La conexión es segura</translation>
+<translation id="8217240300496046857">Los sitios no pueden usar cookies para rastrearte en la Web. Es posible que las características de algunos sitios no funcionen adecuadamente.</translation>
<translation id="8218327578424803826">Ubicación asignada:</translation>
<translation id="8220146938470311105">C7/C6 (Envelope)</translation>
<translation id="8225771182978767009">La persona que configuró esta computadora decidió bloquear este sitio.</translation>
@@ -2258,14 +2313,9 @@ Detalles adicionales:
<translation id="830498451218851433">Plegado a la mitad</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">Las apps instaladas y su frecuencia de uso</translation>
+<translation id="8317207217658302555">¿Deseas actualizar ARCore?</translation>
<translation id="831997045666694187">Tarde</translation>
<translation id="8321476692217554900">notificaciones</translation>
-<translation id="8328484624016508118">Después de cerrar todas las pestañas de incógnito, Chrome borrará lo siguiente:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />La actividad de navegación de este dispositivo<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />El historial de búsqueda de este dispositivo<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />La información que hayas ingresado en formularios<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489">Se denegó el acceso a <ph name="HOST_NAME" /></translation>
<translation id="833262891116910667">Destacar</translation>
<translation id="8339163506404995330">No se traducirán las páginas en <ph name="LANGUAGE" /></translation>
@@ -2317,6 +2367,7 @@ Detalles adicionales:
<translation id="8507227106804027148">Línea de comandos</translation>
<translation id="8508648098325802031">Ãcono de Búsqueda</translation>
<translation id="8511402995811232419">Administrar cookies</translation>
+<translation id="8519753333133776369">Dispositivo HID que permite tu administrador</translation>
<translation id="8522552481199248698">Chrome puede ayudarte a proteger tu Cuenta de Google y cambiar tu contraseña.</translation>
<translation id="8530813470445476232">Borra el historial de navegación, las cookies, la memoria caché y mucho más en la configuración de Chrome</translation>
<translation id="8533619373899488139">Visita &lt;strong&gt;chrome://policy&lt;/strong&gt; para ver la lista de URL bloqueadas y otras políticas que estableció el administrador del sistema.</translation>
@@ -2328,7 +2379,6 @@ Detalles adicionales:
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{Restablecer permiso}other{Restablecer permisos}}</translation>
<translation id="8555010941760982128">Usa este código cuando confirmes la compra</translation>
<translation id="8557066899867184262">El CVC se encuentra al dorso de tu tarjeta.</translation>
-<translation id="8558485628462305855">Para ver contenido de realidad aumentada, actualiza ARCore</translation>
<translation id="8559762987265718583">No se puede establecer una conexión privada a <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> porque la fecha y la hora del dispositivo (<ph name="DATE_AND_TIME" />) son incorrectas.</translation>
<translation id="8564182942834072828">Documentos separados/copias sin intercalar</translation>
<translation id="8564985650692024650">Chromium te recomienda que restablezcas la contraseña de <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> si la volviste a usar en otros sitios.</translation>
@@ -2348,6 +2398,7 @@ Detalles adicionales:
<translation id="865032292777205197">sensores de movimiento</translation>
<translation id="8663226718884576429">Resumen del pedido, <ph name="TOTAL_LABEL" />, Más detalles</translation>
<translation id="8666678546361132282">English</translation>
+<translation id="8669306706049782872">Usar información de tus pantallas para abrir y ubicar ventanas</translation>
<translation id="867224526087042813">Firma</translation>
<translation id="8676424191133491403">Sin demora</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, respuesta, <ph name="ANSWER" /></translation>
@@ -2374,6 +2425,7 @@ Detalles adicionales:
<translation id="8731544501227493793">Botón Administrar contraseñas: presiona Intro para ver y administrar tus contraseñas en la configuración de Chrome</translation>
<translation id="8734529307927223492"><ph name="MANAGER" /> administra tu dispositivo <ph name="DEVICE_TYPE" /></translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />: presiona Tab y, luego, Intro para abrir una nueva ventana de incógnito de Chrome y así navegar de forma privada</translation>
+<translation id="8737685506611670901">Abrir vínculos de <ph name="PROTOCOL" /> en lugar de <ph name="REPLACED_HANDLER_TITLE" /></translation>
<translation id="8738058698779197622">Para establecer una conexión segura, el reloj debe estar configurado correctamente. Esto se debe a que los certificados que usan los sitios web para su identificación solo son válidos por períodos de tiempo específicos. Debido a que la configuración del reloj del dispositivo es incorrecta, Chromium no puede verificar estos certificados.</translation>
<translation id="8740359287975076522">No se encontró <ph name="HOST_NAME" />’s &lt;abbr id="dnsDefinition"&gt;DNS address&lt;/abbr&gt;. Se está diagnosticando el problema.</translation>
<translation id="8742371904523228557"><ph name="ONE_TIME_CODE" /> es tu código para <ph name="ORIGIN" /></translation>
@@ -2401,6 +2453,7 @@ Detalles adicionales:
<translation id="883848425547221593">Otros favoritos</translation>
<translation id="884264119367021077">Dirección de envío</translation>
<translation id="884923133447025588">No se ha encontrado ningún mecanismo de revocación.</translation>
+<translation id="8849262850971482943">Usa tu tarjeta virtual para mejorar la seguridad</translation>
<translation id="885730110891505394">Compartir con Google</translation>
<translation id="8858065207712248076">Chrome te recomienda que restablezcas la contraseña de <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> si la volviste a usar en otros sitios.</translation>
<translation id="885906927438988819">Si no hay errores, <ph name="BEGIN_LINK" />prueba ejecutar el diagnóstico de red de Windows<ph name="END_LINK" />.</translation>
@@ -2450,6 +2503,7 @@ Detalles adicionales:
<translation id="9004367719664099443">La sesión de RV está en curso</translation>
<translation id="9005998258318286617">No se pudo cargar el documento PDF.</translation>
<translation id="9008201768610948239">Ignorar</translation>
+<translation id="901834265349196618">Correo electrónico</translation>
<translation id="9020200922353704812">Se requiere una dirección de facturación de la tarjeta</translation>
<translation id="9020542370529661692">Esta página se tradujo al <ph name="TARGET_LANGUAGE" />.</translation>
<translation id="9020742383383852663">A8</translation>
@@ -2498,6 +2552,7 @@ Detalles adicionales:
<translation id="9150045010208374699">Usar tu cámara</translation>
<translation id="9150685862434908345">Tu administrador puede cambiar la configuración de tu navegador de forma remota. Es posible que la actividad en este dispositivo también se administre fuera de Chrome. <ph name="BEGIN_LINK" />Más información<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">Actualizado</translation>
+<translation id="9155211586651734179">Periféricos de audio conectados</translation>
<translation id="9157595877708044936">Configurando...</translation>
<translation id="9158625974267017556">C6 (Envelope)</translation>
<translation id="9164029392738894042">Verificación de exactitud</translation>
diff --git a/chromium/components/strings/components_strings_es.xtb b/chromium/components/strings/components_strings_es.xtb
index 3e98df88e1c..63350aeb721 100644
--- a/chromium/components/strings/components_strings_es.xtb
+++ b/chromium/components/strings/components_strings_es.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">Ver detalles</translation>
<translation id="1030706264415084469"><ph name="URL" /> quiere almacenar datos de gran tamaño de forma permanente en tu dispositivo</translation>
<translation id="1032854598605920125">Girar hacia la derecha</translation>
+<translation id="1033329911862281889">El modo Incógnito no te hace invisible online:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Los sitios y los servicios que usen pueden ver las visitas<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Las empresas o los centros educativos pueden monitorizar la actividad de navegación<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Los proveedores de Internet pueden monitorizar el tráfico web<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">Desactivar</translation>
<translation id="1036982837258183574">Pulsa |<ph name="ACCELERATOR" />| para salir del modo de pantalla completa</translation>
<translation id="1038106730571050514">Mostrar sugerencias</translation>
<translation id="1038842779957582377">nombre desconocido</translation>
<translation id="1041998700806130099">Mensaje de hoja de tarea</translation>
<translation id="1048785276086539861">Cuando edites las anotaciones, este documento volverá a la vista de una única página</translation>
-<translation id="1049743911850919806">Incógnito</translation>
<translation id="1050038467049342496">Cierra otras aplicaciones</translation>
<translation id="1055184225775184556">&amp;Deshacer acción de añadir</translation>
<translation id="1056898198331236512">Advertencia</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">Caché de política correcta</translation>
<translation id="1130564665089811311">Botón Traducir página, pulsa Intro para traducir esta página con el Traductor de Google</translation>
<translation id="1131264053432022307">Imagen copiada</translation>
+<translation id="1142846828089312304">Bloquear cookies de terceros en incógnito</translation>
<translation id="1150979032973867961">Este servidor no ha podido probar que su dominio es <ph name="DOMAIN" />, el sistema operativo de tu ordenador no confía en su certificado de seguridad. Este problema puede deberse a una configuración incorrecta o a que un atacante haya interceptado la conexión.</translation>
<translation id="1151972924205500581">Contraseña obligatoria</translation>
<translation id="1156303062776767266">Estás viendo un archivo local o compartido</translation>
@@ -56,7 +62,7 @@
<translation id="1161325031994447685">Volver a conectarte a una red Wi-Fi</translation>
<translation id="1165039591588034296">Error</translation>
<translation id="1165174597379888365">Se visita una página</translation>
-<translation id="1174723505405632867">¿Quieres permitir que <ph name="EMBEDDED_URL" /> use cookies y datos de sitios en <ph name="TOP_LEVEL_URL" />?
+<translation id="1174723505405632867">¿Permitir que <ph name="EMBEDDED_URL" /> use cookies y datos de sitios en <ph name="TOP_LEVEL_URL" />?
De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el contenido con el que interactúes funcione correctamente, pero se concederá permiso a <ph name="EMBEDDED_URL" /> para que pueda monitorizar tu actividad.</translation>
<translation id="1175364870820465910">Im&amp;primir...</translation>
@@ -64,7 +70,6 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="1178581264944972037">Pausar</translation>
<translation id="1181037720776840403">Quitar</translation>
<translation id="1186201132766001848">Comprobar contraseñas</translation>
-<translation id="1195210374336998651">Accede a la configuración de la aplicación</translation>
<translation id="1195558154361252544">Las notificaciones se bloquean automáticamente en todos los sitios, excepto en los que las permitas.</translation>
<translation id="1197088940767939838">Naranja</translation>
<translation id="1201402288615127009">Siguiente</translation>
@@ -111,7 +116,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="1307966114820526988">Funciones obsoletas</translation>
<translation id="1308113895091915999">Oferta disponible</translation>
<translation id="1312803275555673949">¿Qué pruebas la respaldan?</translation>
-<translation id="131405271941274527"><ph name="URL" /> quiere enviar y recibir información cuando tu teléfono toque un dispositivo NFC</translation>
+<translation id="1314311879718644478">Visualizar contenido de realidad aumentada</translation>
<translation id="1314509827145471431">Encuadernar por la derecha</translation>
<translation id="1318023360584041678">Guardado en un grupo de pestañas</translation>
<translation id="1319245136674974084">No volver a preguntar para esta aplicación</translation>
@@ -161,6 +166,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="142858679511221695">Usuario de la nube</translation>
<translation id="1428729058023778569">Si ves esta advertencia, significa que este sitio no es compatible con HTTPS. <ph name="BEGIN_LEARN_MORE_LINK" />Más información<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">Imprimir</translation>
+<translation id="1432187715652018471">página quiere instalar un controlador de servicios.</translation>
<translation id="1432581352905426595">Gestionar buscadores</translation>
<translation id="1436185428532214179">Puede solicitar permiso para editar archivos y carpetas de tu dispositivo</translation>
<translation id="1442386063175183758">Plegado en ventana a la derecha</translation>
@@ -181,6 +187,12 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="1483493594462132177">Enviar</translation>
<translation id="1484290072879560759">Seleccionar dirección de envío</translation>
<translation id="1492194039220927094">Envío de políticas:</translation>
+<translation id="149293076951187737">Cuando cierras todas las pestañas de incógnito de Chrome, se borra de este dispositivo la siguiente información sobre tu actividad en esas pestañas:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Actividad de navegación<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Historial de búsqueda<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Información introducida en formularios<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">Volver a la pestaña</translation>
<translation id="1501859676467574491">Mostrar las tarjetas de tu cuenta de Google</translation>
<translation id="1507202001669085618">&lt;p&gt;Este error se muestra si utilizas un portal Wi‑Fi en el que debes iniciar sesión antes de conectarte a Internet.&lt;/p&gt;
@@ -208,6 +220,8 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="1559572115229829303">&lt;p&gt;No se puede establecer una conexión privada con <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> porque la fecha y la hora de tu dispositivo (<ph name="DATE_AND_TIME" />) no son correctas.&lt;/p&gt;
&lt;p&gt;Ajusta la fecha y la hora en la sección &lt;strong&gt;General&lt;/strong&gt; de la aplicación &lt;strong&gt;Configuración&lt;/strong&gt;.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">Tu administrador reiniciará tu dispositivo a las <ph name="TIME" /> el <ph name="DATE" /></translation>
+<translation id="156703335097561114">Información de redes como las direcciones, la configuración de la interfaz y la calidad de la conexión</translation>
<translation id="1567040042588613346">Esta política funciona según lo previsto, pero ha sustituido el mismo valor definido en otra parte.</translation>
<translation id="1569487616857761740">Introducir fecha de vencimiento</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="1583429793053364125">Se ha producido un error al mostrar esta página web.</translation>
<translation id="1586541204584340881">Qué extensiones tienes instaladas</translation>
<translation id="1588438908519853928">Modo normal</translation>
+<translation id="1589050138437146318">¿Instalar ARCore?</translation>
<translation id="1592005682883173041">Acceso a datos locales</translation>
<translation id="1594030484168838125">Seleccionar</translation>
<translation id="160851722280695521">Juega al juego del dinosaurio de Chrome</translation>
@@ -283,6 +298,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
el encabezado tiene errores, lo que impide al navegador procesar
tu solicitud de ir a <ph name="SITE" />. Los operadores de sitios
pueden usar las políticas de origen para configurar la seguridad y otras propiedades de un sitio web.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Más información sobre el modo Incógnito de Chromium<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">Las pestañas abiertas aparecen aquí</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -303,7 +319,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="1838374766361614909">Borrar búsqueda</translation>
<translation id="1839551713262164453">No se ha podido hacer la validación de los valores de la política porque se han producido errores</translation>
<translation id="1842969606798536927">Pagar</translation>
-<translation id="1856713167556118146">Lo que no hace el modo de incógnito</translation>
+<translation id="1856713167556118146">Lo que no hace el modo Incógnito</translation>
<translation id="1863257867908022953">Bandeja 12</translation>
<translation id="1864927262126810325">De <ph name="SOURCE_NAME" /></translation>
<translation id="1871208020102129563">Se ha configurado el proxy de forma que use servidores proxy fijos, en lugar de una URL de secuencia de comandos .pac.</translation>
@@ -410,6 +426,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="22081806969704220">Bandeja 3</translation>
<translation id="2212735316055980242">Política no encontrada</translation>
<translation id="2213606439339815911">Recuperando entradas...</translation>
+<translation id="2213612003795704869">La página se ha imprimido</translation>
<translation id="2215727959747642672">Edición de archivos</translation>
<translation id="2218879909401188352">Se ha detectado la presencia de atacantes en <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> que podrían instalar aplicaciones peligrosas que dañen tu dispositivo, añadir cargos ocultos a tu factura del móvil o robar tu información personal. <ph name="BEGIN_LEARN_MORE_LINK" />Más información<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">Sin conexión a Internet</translation>
@@ -419,6 +436,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="2248949050832152960">Usar WebAuthn</translation>
<translation id="2250931979407627383">Grapado en el borde izquierdo</translation>
<translation id="225207911366869382">Este valor ya no se utiliza para esta política.</translation>
+<translation id="2256115617011615191">Reiniciar ahora</translation>
<translation id="2258928405015593961">Introduce una fecha de vencimiento futura y vuelve a intentarlo</translation>
<translation id="225943865679747347">Código de error: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">Error de HTTP</translation>
@@ -446,6 +464,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="2337852623177822836">Configuración controlada por el administrador</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> quiere emparejarse</translation>
<translation id="2346319942568447007">Imagen copiada</translation>
+<translation id="2350796302381711542">¿Permitir que <ph name="HANDLER_HOSTNAME" /> en lugar de <ph name="REPLACED_HANDLER_TITLE" /> abra todos los enlaces de <ph name="PROTOCOL" />?</translation>
<translation id="2354001756790975382">Otros marcadores</translation>
<translation id="2354430244986887761">La función Navegación segura de Google <ph name="BEGIN_LINK" />encontró aplicaciones dañinas<ph name="END_LINK" /> recientemente en <ph name="SITE" />.</translation>
<translation id="2355395290879513365">Es posible que los atacantes puedan ver las imágenes que ves en este sitio web y que las modifiquen para engañarte.</translation>
@@ -471,6 +490,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="2413528052993050574">Este servidor no ha podido probar que su dominio es <ph name="DOMAIN" /> y se podría rechazar su certificado de seguridad. Este problema puede deberse a una configuración incorrecta o a que un atacante haya interceptado la conexión.</translation>
<translation id="2414886740292270097">Oscuro</translation>
<translation id="2430968933669123598">Gestionar cuenta de Google, pulsa Intro para gestionar la información, la privacidad y la seguridad de tu cuenta de Google</translation>
+<translation id="2436186046335138073">¿Permitir que <ph name="HANDLER_HOSTNAME" /> abra todos los enlaces de <ph name="PROTOCOL" />?</translation>
<translation id="2438874542388153331">Perforado cuádruple en la parte derecha</translation>
<translation id="2450021089947420533">Recorridos</translation>
<translation id="2463739503403862330">Rellenar</translation>
@@ -478,6 +498,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="2465655957518002998">Seleccionar método de entrega</translation>
<translation id="2465688316154986572">Grapar</translation>
<translation id="2465914000209955735">Gestiona archivos que has descargado en Chrome</translation>
+<translation id="2466004615675155314">Muestra información del sitio web</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Ejecutar Diagnósticos de red<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">Orden de 1 a N</translation>
<translation id="2470767536994572628">Cuando edites las anotaciones, este documento volverá a la vista de una única página y a su rotación original</translation>
@@ -498,6 +519,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="2523886232349826891">Solo se guardará en este dispositivo</translation>
<translation id="2524461107774643265">Añade más información</translation>
<translation id="2529899080962247600">Este campo no debe tener más de <ph name="MAX_ITEMS_LIMIT" /> entradas. Se ignorarán las demás entradas.</translation>
+<translation id="2535585790302968248">Abre una pestaña de Incógnito nueva para navegar en privado</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{y 1 más}other{y # más}}</translation>
<translation id="2536110899380797252">Añadir dirección</translation>
<translation id="2539524384386349900">Detectar</translation>
@@ -523,7 +545,14 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="2597378329261239068">Este documento está protegido por contraseña. Introduce una contraseña.</translation>
<translation id="2609632851001447353">Variaciones</translation>
<translation id="2610561535971892504">Haz clic para copiar</translation>
+<translation id="2617988307566202237">Chrome <ph name="BEGIN_EMPHASIS" />no almacenará<ph name="END_EMPHASIS" /> la siguiente información:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Tu historial de navegación
+ <ph name="LIST_ITEM" />Cookies y datos de sitios
+ <ph name="LIST_ITEM" />Información introducida en formularios
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (sobre)</translation>
+<translation id="2623663032199728144">Puede solicitar permiso para usar información sobre tus pantallas</translation>
<translation id="2625385379895617796">Tu reloj está adelantado</translation>
<translation id="262745152991669301">Puede solicitar permiso para conectarse a dispositivos USB</translation>
<translation id="2629325967560697240">Para disfrutar del máximo nivel de seguridad en Chrome, <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />activa la protección mejorada<ph name="END_ENHANCED_PROTECTION_LINK" />.</translation>
@@ -557,6 +586,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="2709516037105925701">Autocompletar</translation>
<translation id="2713444072780614174">Blanco</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />, pulsa Tabulador y, a continuación, Intro para gestionar la información de tus pagos y tarjetas de crédito desde la configuración de Chrome</translation>
+<translation id="271663710482723385">Pulsa |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| para salir de la pantalla completa</translation>
<translation id="2721148159707890343">Solicitud correcta</translation>
<translation id="2723669454293168317">Realiza una comprobación de seguridad en la configuración de Chrome</translation>
<translation id="2726001110728089263">Bandeja lateral</translation>
@@ -587,8 +617,9 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="2850739647070081192">Invite (sobre)</translation>
<translation id="2856444702002559011">Es posible que los atacantes estén intentando robar tu información de <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (por ejemplo, contraseñas, mensajes o tarjetas de crédito). <ph name="BEGIN_LEARN_MORE_LINK" />Más información<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">Este sitio web muestra anuncios invasivos o engañosos.</translation>
+<translation id="286512204874376891">Una tarjeta virtual oculta tu tarjeta real para protegerte frente a posibles fraudes. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">Amistosa</translation>
-<translation id="2876489322757410363">Saldrás del modo de incógnito para pagar en una aplicación externa. ¿Quieres continuar?</translation>
+<translation id="2876489322757410363">Saldrás del modo Incógnito para pagar en una aplicación externa. ¿Quieres continuar?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />: pulsa Tabulador y, después, Intro para gestionar Navegación segura y otras opciones en la configuración de Chrome</translation>
<translation id="2878197950673342043">Plegado en cruz</translation>
<translation id="2878424575911748999">A1</translation>
@@ -611,6 +642,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="2930577230479659665">Recortar después de cada copia</translation>
<translation id="2932085390869194046">Sugerir contraseña...</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019">Abrir enlaces de <ph name="PROTOCOL" /></translation>
<translation id="2941952326391522266">Este servidor no ha podido probar que su dominio es <ph name="DOMAIN" />, su certificado de seguridad procede de <ph name="DOMAIN2" />. Este problema puede deberse a una configuración incorrecta o a que un atacante haya interceptado la conexión.</translation>
<translation id="2943895734390379394">Fecha de subida:</translation>
<translation id="2948083400971632585">Puedes inhabilitar los servidores proxy configurados para una conexión en la página de configuración.</translation>
@@ -643,6 +675,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="3037605927509011580">¡Vaya!</translation>
<translation id="3041612393474885105">Datos del certificado</translation>
<translation id="3044034790304486808">Reanudar búsqueda</translation>
+<translation id="305162504811187366">Historial de Escritorio Remoto de Chrome, incluidas las marcas de tiempo, los hosts y los IDs de sesión del cliente</translation>
<translation id="3060227939791841287">C9 (sobre)</translation>
<translation id="3061707000357573562">Aplicar parche a servicio</translation>
<translation id="306573536155379004">Juego iniciado.</translation>
@@ -683,6 +716,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="3197136577151645743">Puede solicitar permiso para saber cuándo usas activamente este dispositivo</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />, pulsa Tabulador y luego Intro para gestionar qué información quieres sincronizar en la configuración de Chrome</translation>
<translation id="320323717674993345">Cancelar pago</translation>
+<translation id="3203366800380907218">Información del sitio web</translation>
<translation id="3207960819495026254">Añadido a marcadores</translation>
<translation id="3209034400446768650">La página puede cobrarte dinero</translation>
<translation id="3212581601480735796">Se está vigilando tu actividad en <ph name="HOSTNAME" /></translation>
@@ -699,10 +733,12 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="3234666976984236645">Detectar siempre contenido importante en este sitio</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />: pulsa Tabulador y, después, Intro para personalizar el diseño de tu navegador</translation>
<translation id="3240791268468473923">Se ha abierto la hoja de credenciales de pago seguro con una credencial que no coincide</translation>
+<translation id="324180406144491771">Los enlaces de <ph name="HOST_NAME" /> se han bloqueado</translation>
<translation id="3249845759089040423">Estilosa</translation>
<translation id="3252266817569339921">Francés</translation>
<translation id="3257954757204451555">¿Quién está detrás de esta información?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />, pulsa Tabulador y luego Intro para crear un nuevo evento en Google Calendar rápidamente</translation>
+<translation id="3261488570342242926">Información sobre las tarjetas virtuales</translation>
<translation id="3264837738038045344">Botón Gestionar la configuración de Chrome: pulsa Intro para ir a la configuración de Chrome</translation>
<translation id="3266793032086590337">Valor (en conflicto)</translation>
<translation id="3268451620468152448">Pestañas abiertas</translation>
@@ -716,6 +752,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="3288238092761586174">Es posible que <ph name="URL" /> tenga que completar pasos adicionales para verificar tu pago</translation>
<translation id="3293642807462928945">Más información sobre la política <ph name="POLICY_NAME" /></translation>
<translation id="3295444047715739395">Consulta y gestiona tus contraseñas desde la configuración de Chrome</translation>
+<translation id="3303795387212510132">¿Permitir que la aplicación abra enlaces <ph name="PROTOCOL_SCHEME" />?</translation>
<translation id="3303855915957856445">No se han encontrado resultados de búsqueda</translation>
<translation id="3304073249511302126">búsqueda de dispositivos Bluetooth</translation>
<translation id="3308006649705061278">Unidad organizativa (OU)</translation>
@@ -729,12 +766,6 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="3345782426586609320">Ojos</translation>
<translation id="3355823806454867987">Cambiar la configuración de proxy...</translation>
<translation id="3360103848165129075">Hoja del controlador de pagos</translation>
-<translation id="3361596688432910856">Chrome <ph name="BEGIN_EMPHASIS" />no guardará<ph name="END_EMPHASIS" /> la siguiente información:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Tu historial de navegación
- <ph name="LIST_ITEM" />Las cookies y los datos de sitios web
- <ph name="LIST_ITEM" />La información introducida en formularios
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">Esta política se ha copiado automáticamente de la política obsoleta <ph name="OLD_POLICY" />. Deberías usar esta política en su lugar.</translation>
<translation id="3364869320075768271"><ph name="URL" /> quiere usar tu dispositivo y tus datos de realidad virtual</translation>
<translation id="3366477098757335611">Ver tarjetas</translation>
@@ -817,7 +848,6 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="3587738293690942763">Medio</translation>
<translation id="3592413004129370115">Italian (sobre)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{Puedes restablecer tu grupo en cualquier momento. Se tarda alrededor de un día en unirse a un nuevo grupo.}=1{Puedes restablecer tu grupo en cualquier momento. Se tarda alrededor de un día en unirse a un nuevo grupo.}other{Puedes restablecer tu grupo en cualquier momento. Se tardan {NUM_DAYS} días en unirse a un nuevo grupo.}}</translation>
-<translation id="3596012367874587041">Configuración de la aplicación</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">Tu administrador ha bloqueado esta aplicación</translation>
<translation id="3608932978122581043">Orientación de entrada</translation>
@@ -860,6 +890,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="370972442370243704">Activar recorridos</translation>
<translation id="3711895659073496551">Suspender</translation>
<translation id="3712624925041724820">Licencias agotadas</translation>
+<translation id="3714633008798122362">calendario web</translation>
<translation id="3714780639079136834">Activar los datos móviles o la conexión Wi-Fi</translation>
<translation id="3715597595485130451">Conectarse a una red Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Comprobar el proxy, el cortafuegos y la configuración de DNS<ph name="END_LINK" /></translation>
@@ -921,6 +952,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="3906954721959377182">Tablet</translation>
<translation id="3909477809443608991"><ph name="URL" /> solicita reproducir contenido protegido. Google verificará la identidad de tu dispositivo y el sitio web podrá consultarla.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">Denegar</translation>
<translation id="3939773374150895049">¿Usar WebAuthn en lugar de CVC?</translation>
<translation id="3946209740501886391">Preguntar siempre en este sitio web</translation>
<translation id="3947595700203588284">Puede solicitar permiso para conectarse a dispositivos MIDI</translation>
@@ -942,6 +974,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="3990250421422698716">Agrupar</translation>
<translation id="3996311196211510766">El sitio web <ph name="ORIGIN" /> ha solicitado que se aplique una política de origen
a todas las solicitudes que reciba, pero esta política no se puede aplicar actualmente.</translation>
+<translation id="4009243425692662128">El contenido de las páginas que imprimes se envía a Google Cloud o a terceros para analizarlo. Por ejemplo, puede que se analice para buscar datos sensibles.</translation>
<translation id="4010758435855888356">¿Permitir espacio de almacenamiento?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{Documento PDF que contiene {COUNT} página}other{Documento PDF que contiene {COUNT} páginas}}</translation>
<translation id="4023431997072828269">Se está usando una conexión no segura para enviar este formulario, por lo que otros usuarios podrán ver tu información.</translation>
@@ -987,7 +1020,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="4152318981910038897">{COUNT,plural, =1{Página 1}other{Página {COUNT}}}</translation>
<translation id="4154664944169082762">Huellas digitales</translation>
<translation id="4159784952369912983">Morado</translation>
-<translation id="4165986682804962316">Configuración de sitios</translation>
+<translation id="4165986682804962316">Configuración del sitio</translation>
<translation id="4171400957073367226">La firma de verificación no es válida</translation>
<translation id="4171489848299289778"><ph name="RESULT_MODIFIED_DATE" /> - <ph name="RESULT_OWNER" /> - <ph name="RESULT_PRODUCT_SOURCE" /></translation>
<translation id="4172051516777682613">Mostrar siempre</translation>
@@ -1017,7 +1050,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
&lt;li&gt;Accede a cualquier sitio web que empiece por &lt;code&gt;http://&lt;/code&gt;, como &lt;a href="http://example.com" target="_blank"&gt;http://example.com&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;En la página de inicio de sesión que se abre, inicia sesión para utilizar la conexión a Internet.&lt;/li&gt;
&lt;/ol&gt;
- &lt;h4&gt;Paso 2: Abre la página en modo de incógnito (solo en ordenadores)&lt;/h4&gt;
+ &lt;h4&gt;Paso 2: Abre la página en modo Incógnito (solo en ordenadores)&lt;/h4&gt;
&lt;p&gt;Abre la página que estabas visitando en una ventana de incógnito.&lt;/p&gt;
&lt;p&gt;Si la página se abre, significa que una extensión de Chrome no funciona correctamente. Para solucionarlo, desactiva esa extensión.&lt;/p&gt;
&lt;h4&gt;Paso 3: Actualiza tu sistema operativo&lt;/h4&gt;
@@ -1036,6 +1069,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="4250680216510889253">No</translation>
<translation id="4253168017788158739">Nota</translation>
<translation id="425582637250725228">Es posible que los cambios no se guarden.</translation>
+<translation id="425869179292622354">¿Hacerla más segura con una tarjeta virtual?</translation>
<translation id="4258748452823770588">Firma errónea</translation>
<translation id="4261046003697461417">No se pueden añadir anotaciones a los documentos protegidos</translation>
<translation id="4265872034478892965">Permitido por el administrador</translation>
@@ -1098,6 +1132,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="4434045419905280838">Ventanas emergentes y redirecciones</translation>
<translation id="4435702339979719576">Postcard)</translation>
<translation id="443673843213245140">Se ha inhabilitado el uso de un servidor proxy, pero se han especificado ajustes de proxy explícitos.</translation>
+<translation id="4441832193888514600">Se ignora porque la política solo se puede establecer como una política de usuarios basada en la nube.</translation>
<translation id="4450893287417543264">No volver a mostrar</translation>
<translation id="4451135742916150903">Puede solicitar permiso para conectarse a dispositivos HID</translation>
<translation id="4452328064229197696">La contraseña que acabas de usar se ha visto expuesta en una quiebra de seguridad de datos. Para proteger tus cuentas, el gestor de contraseñas de Google te recomienda que compruebes las contraseñas que tengas guardadas.</translation>
@@ -1107,7 +1142,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="447665707681730621"><ph name="BUBBLE_MESSAGE" />. <ph name="LEARN_MORE_TEXT" /></translation>
<translation id="4476953670630786061">Este formulario no es seguro. Autocompletar se ha desactivado.</translation>
<translation id="4477350412780666475">Pista siguiente</translation>
-<translation id="4481251927743463293">Lo que hace el modo de incógnito</translation>
+<translation id="4481251927743463293">Lo que hace el modo Incógnito</translation>
<translation id="4482953324121162758">Este sitio web no se traducirá.</translation>
<translation id="4490717597759821841">A7</translation>
<translation id="449126573531210296">Cifrar contraseñas sincronizadas con tu cuenta de Google</translation>
@@ -1153,6 +1188,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="4628948037717959914">Foto</translation>
<translation id="4631649115723685955">Devolución de dinero asociada</translation>
<translation id="4636930964841734540">Información</translation>
+<translation id="4638670630777875591">Incógnito en Chromium</translation>
<translation id="464342062220857295">Buscar funciones</translation>
<translation id="4644670975240021822">Orden inverso boca abajo</translation>
<translation id="4646534391647090355">Ir allí ahora</translation>
@@ -1173,6 +1209,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="4708268264240856090">Se ha interrumpido la conexión</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Ejecutar Diagnósticos de red de Windows<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426">Contraseña de <ph name="USERNAME" /></translation>
<translation id="4724144314178270921">Puede solicitar permiso para ver texto e imágenes del portapapeles</translation>
<translation id="4726672564094551039">Volver a cargar políticas</translation>
<translation id="4728558894243024398">Plataforma</translation>
@@ -1186,7 +1223,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="4742407542027196863">Gestionar contraseñas…</translation>
<translation id="4744514002166662487">Crear presentación</translation>
<translation id="4744603770635761495">Ruta del ejecutable</translation>
-<translation id="4749011317274908093">Estás en modo de incógnito</translation>
+<translation id="4749011317274908093">Estás en modo Incógnito</translation>
<translation id="4750917950439032686">Tu información (por ejemplo, tus contraseñas o números de tarjeta de crédito) es privada cuando se envía a este sitio web.</translation>
<translation id="4751476147751820511">Sensores de luz o movimiento</translation>
<translation id="4754461935447132332">No permitido en sitios no seguros</translation>
@@ -1194,6 +1231,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="4757993714154412917">Acabas de escribir tu contraseña en un sitio engañoso. Para proteger tus cuentas, Chromium recomienda que compruebes las contraseñas que tengas guardadas.</translation>
<translation id="4758311279753947758">Añadir información de contacto</translation>
<translation id="4761104368405085019">Utilizar el micrófono</translation>
+<translation id="4761869838909035636">Realizar comprobación de seguridad de Chrome</translation>
<translation id="4764776831041365478">Es posible que la página web <ph name="URL" /> esté temporalmente inactiva o que se haya trasladado definitivamente a otra dirección.</translation>
<translation id="4766713847338118463">Grapado doble en la parte inferior</translation>
<translation id="4771973620359291008">Se ha producido un error desconocido.</translation>
@@ -1214,12 +1252,6 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="4819347708020428563">¿Editar anotaciones en la vista predeterminada?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />, pulsa Tabulador y luego Intro para crear una nueva Hoja de cálculo de Google rápidamente</translation>
<translation id="4825507807291741242">Potente</translation>
-<translation id="4827402517081186284">El modo de incógnito no te hace invisible online:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Los sitios saben que los visitas<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Las empresas o los centros educativos pueden monitorizar la actividad de navegación<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Los proveedores de Internet pueden monitorizar el tráfico web<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">Activar advertencias</translation>
<translation id="4838327282952368871">De ensueño</translation>
<translation id="4840250757394056958">Ver tu historial de Chrome</translation>
@@ -1231,12 +1263,12 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="4854362297993841467">Este método de entrega no está disponible. Selecciona otro.</translation>
<translation id="4854853140771946034">Crea una nueva nota en Google Keep rápidamente</translation>
<translation id="485902285759009870">Verificando código...</translation>
+<translation id="4866506163384898554">Pulsa |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| para mostrar el cursor</translation>
<translation id="4876188919622883022">Vista simplificada</translation>
<translation id="4876305945144899064">Ningún nombre de usuario</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{No hay}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" /> y <ph name="EXAMPLE_DOMAIN_2" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831">Búsqueda de <ph name="TEXT" /></translation>
<translation id="4879491255372875719">Automático (predeterminado)</translation>
-<translation id="4879725228911483934">Abrir y colocar ventanas en tus pantallas</translation>
<translation id="4880827082731008257">Buscar en el historial</translation>
<translation id="4881695831933465202">Abrir</translation>
<translation id="4885256590493466218">Paga con <ph name="CARD_DETAIL" /> al tramitar la compra.</translation>
@@ -1245,6 +1277,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" /> y <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">Noveno rollo</translation>
<translation id="4901778704868714008">Guardar...</translation>
+<translation id="4905659621780993806">Tu administrador reiniciará tu dispositivo automáticamente a las <ph name="TIME" /> el <ph name="DATE" />. Guarda los elementos que tengas abiertos antes de que el dispositivo se reinicie.</translation>
<translation id="4913987521957242411">Perforado en la parte superior izquierda</translation>
<translation id="4918221908152712722">Instala <ph name="APP_NAME" /> (sin descargar nada)</translation>
<translation id="4923459931733593730">Pago</translation>
@@ -1253,6 +1286,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, pulsa Tabulador y, a continuación, Intro para buscar</translation>
<translation id="4930153903256238152">Gran capacidad</translation>
+<translation id="4940163644868678279">Incógnito en Chrome</translation>
<translation id="4943872375798546930">Sin resultados</translation>
<translation id="4950898438188848926">Botón de cambio de pestaña; pulsa Intro para cambiar a la pestaña abierta, <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="495170559598752135">Acciones</translation>
@@ -1262,6 +1296,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="4968522289500246572">Esta aplicación se ha diseñado para móviles y es posible que su tamaño no se cambie correctamente. Puede que la aplicación dé problemas o se reinicie.</translation>
<translation id="4969341057194253438">Eliminar grabación</translation>
<translation id="4973922308112707173">Perforado doble en la parte superior</translation>
+<translation id="4976702386844183910">Última visita: <ph name="DATE" /></translation>
<translation id="4984088539114770594">¿Usar micrófono?</translation>
<translation id="4984339528288761049">Prc5 (sobre)</translation>
<translation id="4989163558385430922">Ver todo</translation>
@@ -1323,6 +1358,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="5138227688689900538">Mostrar menos</translation>
<translation id="5145883236150621069">Código de error presente en respuesta de la política</translation>
<translation id="5146995429444047494">Las notificaciones de <ph name="ORIGIN" /> están bloqueadas</translation>
+<translation id="514704532284964975"><ph name="URL" /> quiere ver y cambiar la información de los dispositivos NFC que tocas desde tu teléfono</translation>
<translation id="5148809049217731050">Boca arriba</translation>
<translation id="515292512908731282">C4 (sobre)</translation>
<translation id="5158275234811857234">Portada</translation>
@@ -1347,6 +1383,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="5215116848420601511">Métodos de pago y direcciones con Google Pay</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">Bandeja 13</translation>
+<translation id="5216942107514965959">Última visita: hoy</translation>
<translation id="5222812217790122047">Correo electrónico obligatorio</translation>
<translation id="5230733896359313003">Dirección de envío</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1367,7 +1404,6 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">Propiedades del documento</translation>
<translation id="528468243742722775">Finalizar</translation>
-<translation id="5284909709419567258">Direcciones de red</translation>
<translation id="5285570108065881030">Mostrar todas las contraseñas guardadas</translation>
<translation id="5287240709317226393">Mostrar cookies</translation>
<translation id="5287456746628258573">Este sitio web usa una configuración de seguridad obsoleta y puede que exponga tu información (por ejemplo, las contraseñas o los números de las tarjetas de crédito) cuando se envíe a este sitio web.</translation>
@@ -1451,6 +1487,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="5556459405103347317">Volver a cargar</translation>
<translation id="5560088892362098740">Fecha de caducidad</translation>
<translation id="55635442646131152">Esquema del documento</translation>
+<translation id="5565613213060953222">Abrir pestaña de Incógnito</translation>
<translation id="5565735124758917034">Activo</translation>
<translation id="5570825185877910964">Proteger cuenta</translation>
<translation id="5571083550517324815">Los pedidos no se pueden recoger en esta dirección. Selecciona otra.</translation>
@@ -1533,6 +1570,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="5869522115854928033">Contraseñas guardadas</translation>
<translation id="5873013647450402046">Tu banco quiere confirmar tu identidad.</translation>
<translation id="5887400589839399685">Tarjeta guardada</translation>
+<translation id="5887687176710214216">Última visita: ayer</translation>
<translation id="5895138241574237353">Reiniciar</translation>
<translation id="5895187275912066135">Emitido el</translation>
<translation id="5901630391730855834">Amarillo</translation>
@@ -1546,6 +1584,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="5921639886840618607">¿Quieres guardar la tarjeta en tu cuenta de Google?</translation>
<translation id="5922853866070715753">Casi hemos acabado</translation>
<translation id="5932224571077948991">El sitio web muestra anuncios invasivos o engañosos</translation>
+<translation id="5938153366081463283">Añadir tarjeta virtual</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347">Abriendo <ph name="SITE_NAME" />…</translation>
<translation id="5951495562196540101">No te puedes registrar con una cuenta de consumidor (hay una licencia asociada disponible).</translation>
@@ -1610,6 +1649,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="6120179357481664955">¿Recuerdas tu ID de UPI?</translation>
<translation id="6124432979022149706">Conectores de Chrome Enterprise</translation>
<translation id="6127379762771434464">Elemento quitado</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Más información sobre el modo Incógnito de Chrome<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">Comprueba los cables y reinicia los routers, los módems o cualquier otro dispositivo
de red que estés utilizando.</translation>
<translation id="614940544461990577">Prueba a:</translation>
@@ -1622,7 +1662,6 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="6169916984152623906">Ahora puedes navegar de forma privada; las otras personas que usen este dispositivo no verán tu actividad. No obstante, se guardarán las descargas y los marcadores.</translation>
<translation id="6177128806592000436">La conexión con este sitio web no es segura</translation>
<translation id="6180316780098470077">Intervalo de reintentos</translation>
-<translation id="619448280891863779">Puede pedir permiso para abrir y colocar ventanas en tus pantallas</translation>
<translation id="6196640612572343990">Bloquear cookies de terceros</translation>
<translation id="6203231073485539293">Comprueba tu conexión a Internet</translation>
<translation id="6218753634732582820">¿Quitar dirección de Chromium?</translation>
@@ -1645,7 +1684,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="6272383483618007430">Google Update</translation>
<translation id="6276112860590028508">Las páginas de tu lista de lectura aparecen aquí</translation>
<translation id="627746635834430766">Para pagar más rápido la próxima vez, guarda tu tarjeta y tu dirección de facturación en tu cuenta de Google.</translation>
-<translation id="6279098320682980337">¿No se ha introducido el número de tarjeta virtual? Haz clic en la información de la tarjeta para copiarla.</translation>
+<translation id="6279183038361895380">Pulsa |<ph name="ACCELERATOR" />| para mostrar el cursor</translation>
<translation id="6280223929691119688">Los pedidos no se pueden entregar en esta dirección. Selecciona otra.</translation>
<translation id="6282194474023008486">Código postal</translation>
<translation id="6285507000506177184">Botón Gestionar las descargas en Chrome: pulsa Intro para gestionar los archivos que has descargado en Chrome</translation>
@@ -1653,6 +1692,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="6290238015253830360">Los artículos sugeridos aparecen aquí</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{Tu dispositivo se reiniciará ahora}=1{Tu dispositivo se reiniciará dentro de 1 segundo}other{Tu dispositivo se reiniciará dentro de # segundos}}</translation>
<translation id="6302269476990306341">Se está parando el Asistente de Google en Chrome</translation>
<translation id="6305205051461490394">No se puede acceder a <ph name="URL" />.</translation>
<translation id="6312113039770857350">Página web no disponible</translation>
@@ -1726,6 +1766,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="6529602333819889595">&amp;Rehacer eliminación</translation>
<translation id="6545864417968258051">Búsqueda de dispositivos Bluetooth</translation>
<translation id="6547208576736763147">Perforado doble en la parte izquierda</translation>
+<translation id="6554732001434021288">Última visita: hace <ph name="NUM_DAYS" /> días</translation>
<translation id="6556866813142980365">Rehacer</translation>
<translation id="6569060085658103619">Estas viendo la página de una extensión</translation>
<translation id="6573200754375280815">Perforado doble en la parte derecha</translation>
@@ -1786,7 +1827,6 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="6757797048963528358">El dispositivo se ha suspendido.</translation>
<translation id="6767985426384634228">¿Actualizar dirección?</translation>
<translation id="6768213884286397650">Hagaki (Postcard)</translation>
-<translation id="6774185088257932239"><ph name="BEGIN_LINK" />Más información<ph name="END_LINK" /> sobre el modo de incógnito</translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">Violeta</translation>
<translation id="6786747875388722282">Extensiones</translation>
@@ -1870,7 +1910,6 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="706295145388601875">Añade y gestiona direcciones en la configuración de Chrome</translation>
<translation id="7064851114919012435">Información de contacto</translation>
<translation id="7068733155164172741">Introduce el código de <ph name="OTP_LENGTH" /> dígitos</translation>
-<translation id="7070090581017165256">Acerca de este sitio</translation>
<translation id="70705239631109039">Tu conexión no es completamente segura</translation>
<translation id="7075452647191940183">La solicitud es demasiado grande</translation>
<translation id="7079718277001814089">Este sitio web contiene software malicioso</translation>
@@ -1887,6 +1926,12 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="7111012039238467737">(válido)</translation>
<translation id="7118618213916969306">Buscar la URL <ph name="SHORT_URL" /> del portapapeles</translation>
<translation id="7119414471315195487">Cierra otros programas o pestañas</translation>
+<translation id="7129355289156517987">Cuando cierras todas las pestañas de incógnito de Chromium, se borra de este dispositivo la siguiente información sobre tu actividad en esas pestañas:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Actividad de navegación<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Historial de búsqueda<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Información introducida en formularios<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">Los pedidos no se pueden enviar a esta dirección. Selecciona otra.</translation>
<translation id="7132939140423847331">Tu administrador ha prohibido que se copien estos datos.</translation>
<translation id="7135130955892390533">Mostrar estado</translation>
@@ -1903,12 +1948,13 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" /> y <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> más}other{<ph name="SHIPPING_OPTION_PREVIEW" /> y <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> más}}</translation>
<translation id="7179323680825933600">Guardar y autocompletar métodos de pago</translation>
<translation id="7180611975245234373">Actualizar</translation>
-<translation id="7181261019481237103">Abrir una ventana de incógnito</translation>
+<translation id="7181261019481237103">Abrir ventana de incógnito</translation>
<translation id="7182878459783632708">No hay políticas establecidas.</translation>
<translation id="7186367841673660872">Esta página se ha traducido del<ph name="ORIGINAL_LANGUAGE" />al<ph name="LANGUAGE_LANGUAGE" />.</translation>
<translation id="7192203810768312527">Libera <ph name="SIZE" />. Algunos sitios pueden tardar más en cargarse la próxima vez que accedas a ellos.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">El administrador puede consultar lo siguiente:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, pulsa Tabulador y, a continuación, Intro para abrir una pestaña de Incógnito nueva y navegar de forma privada</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423">La página <ph name="HOST_NAME" /> no cumple los estándares de seguridad.</translation>
<translation id="7210993021468939304">Los administradores pueden ver la actividad de Linux en el contenedor, y también pueden instalar y ejecutar aplicaciones de Linux en el contenedor</translation>
@@ -1918,7 +1964,7 @@ De lo contrario, lo impedirá tu configuración de privacidad. Permitirá que el
<translation id="7219179957768738017">La conexión utiliza <ph name="SSL_VERSION" />.</translation>
<translation id="7220786058474068424">Procesando pago</translation>
<translation id="7221855153210829124">Mostrar notificaciones</translation>
-<translation id="722454870747268814">Nueva pestaña de incógnito</translation>
+<translation id="722454870747268814">Nueva pestaña de Incógnito</translation>
<translation id="7233592378249864828">Imprimir hoja de confirmación</translation>
<translation id="7238585580608191973">Huella digital SHA-256</translation>
<translation id="7240120331469437312">Nombre alternativo de la entidad receptora del certificado</translation>
@@ -1940,6 +1986,7 @@ Más información:
<translation id="7304562222803846232">Gestionar configuración de privacidad de la cuenta de Google</translation>
<translation id="7305756307268530424">Empezar más lento</translation>
<translation id="7308436126008021607">sincronización en segundo plano</translation>
+<translation id="7310392214323165548">El dispositivo se reiniciará en breve</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">Ayuda para la conexión</translation>
<translation id="7323804146520582233">Ocultar la sección "<ph name="SECTION" />"</translation>
@@ -1947,6 +1994,7 @@ Más información:
<translation id="7334320624316649418">&amp;Rehacer reorganización</translation>
<translation id="7335157162773372339">Puede solicitar permiso para usar tu cámara</translation>
<translation id="7337248890521463931">Mostrar más líneas</translation>
+<translation id="7337418456231055214">¿No se ha introducido el número de tarjeta virtual? Haz clic en la información de la tarjeta para copiarla. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">No está disponible en esta plataforma.</translation>
<translation id="733923710415886693">El certificado del servidor no se ha revelado a través de la Transparencia en los Certificados.</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1956,7 +2004,7 @@ Más información:
<translation id="7352651011704765696">Se ha producido un problema</translation>
<translation id="7353601530677266744">Línea de comandos</translation>
<translation id="7359588939039777303">Los anuncios están bloqueados.</translation>
-<translation id="7363096869660964304">Sin embargo, tus acciones no son invisibles. El modo de incógnito no oculta tu actividad de navegación a tu empresa, a tu proveedor de Internet ni a los sitios web que visites.</translation>
+<translation id="7363096869660964304">Sin embargo, tus acciones no son invisibles. El modo Incógnito no oculta tu actividad de navegación a tu empresa, a tu proveedor de Internet ni a los sitios web que visites.</translation>
<translation id="7365596969960773405"><ph name="MANAGE_ADDRESSES_FOCUSED_FRIENDLY_MATCH_TEXT" />, pulsa Tabulador y luego Intro para añadir y gestionar direcciones en la configuración de Chrome</translation>
<translation id="7365849542400970216">¿Detectar el uso de tu dispositivo?</translation>
<translation id="7366362069757178916">Controladores de pago</translation>
@@ -1969,6 +2017,7 @@ Más información:
<translation id="7378627244592794276">No</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">No aplicable</translation>
+<translation id="7388594495505979117">{0,plural, =1{Tu dispositivo se reiniciará dentro de 1 minuto}other{Tu dispositivo se reiniciará dentro de # minutos}}</translation>
<translation id="7390545607259442187">Confirmar tarjeta</translation>
<translation id="7392089738299859607">Actualizar dirección</translation>
<translation id="7399802613464275309">Comprobación de seguridad</translation>
@@ -2005,6 +2054,12 @@ Más información:
<translation id="7485870689360869515">No se han encontrado datos.</translation>
<translation id="7495528107193238112">Este contenido está bloqueado. Para solucionar el problema, ponte en contacto con el propietario del sitio web.</translation>
<translation id="7497998058912824456">Botón de crear documento, pulsa Intro para crear un nuevo Documento de Google rápidamente</translation>
+<translation id="7506488012654002225">Chromium <ph name="BEGIN_EMPHASIS" />no almacenará<ph name="END_EMPHASIS" /> la siguiente información:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Tu historial de navegación
+ <ph name="LIST_ITEM" />Cookies y datos de sitios
+ <ph name="LIST_ITEM" />Información introducida en formularios
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">El ID de dispositivo de política devuelto está vacío o no coincide con el ID de dispositivo actual</translation>
<translation id="7508870219247277067">Verde aguacate</translation>
<translation id="7511955381719512146">La red Wi-Fi que estás utilizando puede requerir que accedas a la página <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
@@ -2118,7 +2173,6 @@ Más información:
<translation id="7813600968533626083">¿Eliminar sugerencia de formulario de Chrome?</translation>
<translation id="781440967107097262">¿Compartir portapapeles?</translation>
<translation id="7815407501681723534">Se han encontrado <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> de <ph name="SEARCH_STRING" /></translation>
-<translation id="782125616001965242">Mostrar información sobre este sitio</translation>
<translation id="782886543891417279">La red Wi-Fi que estás utilizando (<ph name="WIFI_NAME" />) puede requerir que accedas a su página de inicio de sesión.</translation>
<translation id="7836231406687464395">Postfix (sobre)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{Ninguna}=1{1 aplicación (<ph name="EXAMPLE_APP_1" />)}=2{2 aplicaciones (<ph name="EXAMPLE_APP_1" /> y <ph name="EXAMPLE_APP_2" />)}other{# aplicaciones (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" /> <ph name="AND_MORE" />)}}</translation>
@@ -2135,7 +2189,6 @@ Más información:
<translation id="7888575728750733395">Imprimir intent de renderizado</translation>
<translation id="7894280532028510793">Si está escrito correctamente, <ph name="BEGIN_LINK" />prueba a ejecutar el diagnóstico de red<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (sobre)</translation>
-<translation id="7931318309563332511">Desconocido</translation>
<translation id="793209273132572360">¿Actualizar dirección?</translation>
<translation id="7932579305932748336">Capa</translation>
<translation id="79338296614623784">Introduce un número de teléfono válido</translation>
@@ -2160,13 +2213,14 @@ Más información:
<translation id="7976214039405368314">Demasiadas solicitudes</translation>
<translation id="7977538094055660992">Dispositivo de salida</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">Vinculada con</translation>
<translation id="798134797138789862">Puede solicitar permiso para utilizar dispositivos y datos de realidad virtual</translation>
<translation id="7984945080620862648">No puedes acceder a <ph name="SITE" /> en este momento porque el sitio web ha enviado credenciales codificadas que Chrome no puede procesar. Los ataques y los errores de red suelen ser temporales, por lo que es probable que esta página funcione más tarde.</translation>
-<translation id="79859296434321399">Instala ARCore para visualizar contenido de realidad aumentada</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">Encuadernar</translation>
<translation id="7992044431894087211">Se ha reanudado la pantalla compartida con <ph name="APPLICATION_TITLE" /></translation>
<translation id="7995512525968007366">Sin especificar</translation>
+<translation id="7998269595945679889">Botón Abrir pestaña de Incógnito, pulsa Intro para abrir una pestaña de Incógnito nueva para navegar de forma privada</translation>
<translation id="800218591365569300">Prueba a cerrar otros programas o pestañas para liberar memoria.</translation>
<translation id="8004582292198964060">Navegador</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{Se guardará la tarjeta y su dirección de facturación. Podrás utilizarla cuando inicies sesión como <ph name="USER_EMAIL" />.}other{Se guardarán las tarjetas y sus direcciones de facturación. Podrás utilizarlas cuando inicies sesión como <ph name="USER_EMAIL" />.}}</translation>
@@ -2226,6 +2280,7 @@ Más información:
<translation id="8202370299023114387">Conflicto</translation>
<translation id="8206978196348664717">Prc4 (sobre)</translation>
<translation id="8211406090763984747">La conexión es segura</translation>
+<translation id="8217240300496046857">Los sitios no pueden usar cookies para hacer un seguimiento de tu actividad en la Web. Es posible que las funciones de algunos sitios no funcionen correctamente.</translation>
<translation id="8218327578424803826">Ubicación asignada:</translation>
<translation id="8220146938470311105">C7/C6 (sobre)</translation>
<translation id="8225771182978767009">La persona que ha configurado este ordenador ha elegido bloquear este sitio web.</translation>
@@ -2233,7 +2288,7 @@ Más información:
<translation id="822964464349305906"><ph name="TYPE_1" /> o <ph name="TYPE_2" /></translation>
<translation id="8232343881378637145">Temperatura de plataforma</translation>
<translation id="8233773197406738106">Preparando archivo</translation>
-<translation id="8238581221633243064">Abre una página en una nueva pestaña de incógnito</translation>
+<translation id="8238581221633243064">Abre una página en una nueva pestaña de Incógnito</translation>
<translation id="8241707690549784388">La página que buscas ha utilizado la información que has especificado. Volver a la página podría provocar la repetición de alguna acción. ¿Quieres continuar?</translation>
<translation id="8241712895048303527">Bloquear en este sitio web</translation>
<translation id="8242426110754782860">Continuar</translation>
@@ -2266,14 +2321,9 @@ Más información:
<translation id="830498451218851433">Plegado al medio</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">Las aplicaciones instaladas y la frecuencia con la que se usan</translation>
+<translation id="8317207217658302555">¿Actualizar ARCore?</translation>
<translation id="831997045666694187">Tarde</translation>
<translation id="8321476692217554900">notificaciones</translation>
-<translation id="8328484624016508118">Al cerrar todas las pestañas de incógnito, Chrome borra lo siguiente:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Tu actividad de navegación en este dispositivo<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Tu historial de búsqueda en este dispositivo<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />La información que hayas introducido en formularios<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489">Se ha denegado el acceso a <ph name="HOST_NAME" /></translation>
<translation id="833262891116910667">Resaltar</translation>
<translation id="8339163506404995330">No se traducirán las páginas en <ph name="LANGUAGE" /></translation>
@@ -2282,7 +2332,7 @@ Más información:
<translation id="8349305172487531364">Barra de marcadores</translation>
<translation id="8351131234907093545">Crear nota</translation>
<translation id="8355270400102541638">Contexto del fallo local:</translation>
-<translation id="8363502534493474904">Desactivar el modo avión</translation>
+<translation id="8363502534493474904">Desactivar el modo Avión</translation>
<translation id="8364627913115013041">No establecida</translation>
<translation id="8368027906805972958">Dispositivo desconocido o no compatible (<ph name="DEVICE_ID" />)</translation>
<translation id="8368476060205742148">Servicios de Google Play</translation>
@@ -2325,6 +2375,7 @@ Más información:
<translation id="8507227106804027148">Línea de comandos</translation>
<translation id="8508648098325802031">Icono de búsqueda</translation>
<translation id="8511402995811232419">Gestionar cookies</translation>
+<translation id="8519753333133776369">Tu administrador permite el dispositivo de interfaz humana (HID)</translation>
<translation id="8522552481199248698">Chrome puede ayudarte a proteger tu cuenta de Google y a cambiar tu contraseña.</translation>
<translation id="8530813470445476232">Borra el historial de navegación, las cookies, la caché y más desde la configuración de Chrome</translation>
<translation id="8533619373899488139">Visita &lt;strong&gt;chrome://policy&lt;/strong&gt; para ver la lista de URL boloqueadas y otras políticas implementadas por el administrador del sistema.</translation>
@@ -2336,7 +2387,6 @@ Más información:
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{Restablecer permiso}other{Restablecer permisos}}</translation>
<translation id="8555010941760982128">Usa este código al tramitar la compra</translation>
<translation id="8557066899867184262">Puedes encontrar el CVC en el reverso de la tarjeta.</translation>
-<translation id="8558485628462305855">Actualiza ARCore para visualizar contenido de realidad aumentada</translation>
<translation id="8559762987265718583">No se puede establecer una conexión privada con <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> porque la fecha y la hora de tu dispositivo (<ph name="DATE_AND_TIME" />) no son correctas.</translation>
<translation id="8564182942834072828">Separar documentos/Copias sin intercalar</translation>
<translation id="8564985650692024650">Chromium te recomienda que cambies tu contraseña de <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> si la has vuelto a utilizar en otros sitios.</translation>
@@ -2355,6 +2405,7 @@ Más información:
<translation id="865032292777205197">sensores de movimiento</translation>
<translation id="8663226718884576429">Resumen del pedido: <ph name="TOTAL_LABEL" /> (más detalles)</translation>
<translation id="8666678546361132282">Inglés</translation>
+<translation id="8669306706049782872">Usar información sobre tus pantallas para abrir y colocar ventanas</translation>
<translation id="867224526087042813">Firma</translation>
<translation id="8676424191133491403">Sin retraso</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, respuesta: <ph name="ANSWER" /></translation>
@@ -2381,6 +2432,7 @@ Más información:
<translation id="8731544501227493793">Botón Gestionar contraseñas, pulsa Intro para ver y gestionar tus contraseñas desde la configuración de Chrome</translation>
<translation id="8734529307927223492"><ph name="MANAGER" /> gestiona tu <ph name="DEVICE_TYPE" /></translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, pulsa Tabulador y, a continuación, Intro para abrir una ventana de incógnito para navegar de forma privada</translation>
+<translation id="8737685506611670901">Abrir enlaces de <ph name="PROTOCOL" /> en lugar de <ph name="REPLACED_HANDLER_TITLE" /></translation>
<translation id="8738058698779197622">Para establecer una conexión segura, tu reloj debe estar correctamente configurado. Esto se debe a que los certificados utilizados por los sitios web para identificarse son solo válidos durante períodos específicos de tiempo. Dado que la hora de tu dispositivo no es correcta, Chromium no puede verificar estos certificados.</translation>
<translation id="8740359287975076522">No se ha podido encontrar la &lt;abbr id="dnsDefinition"&gt;dirección DNS&lt;/abbr&gt; de la página <ph name="HOST_NAME" />. Se está diagnosticando el problema.</translation>
<translation id="8742371904523228557">El código de <ph name="ORIGIN" /> es <ph name="ONE_TIME_CODE" /></translation>
@@ -2408,6 +2460,7 @@ Más información:
<translation id="883848425547221593">Otros marcadores</translation>
<translation id="884264119367021077">Dirección de envío</translation>
<translation id="884923133447025588">No se ha encontrado ningún mecanismo de revocación.</translation>
+<translation id="8849262850971482943">Usa tu tarjeta virtual para aumentar la seguridad</translation>
<translation id="885730110891505394">Compartir con Google</translation>
<translation id="8858065207712248076">Chrome te recomienda que cambies tu contraseña de <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> si la has vuelto a utilizar en otros sitios.</translation>
<translation id="885906927438988819">Si está escrito correctamente, <ph name="BEGIN_LINK" />prueba a ejecutar el diagnóstico de red de Windows<ph name="END_LINK" />.</translation>
@@ -2457,6 +2510,7 @@ Más información:
<translation id="9004367719664099443">Sesión de realidad virtual en curso</translation>
<translation id="9005998258318286617">Se ha producido un error al cargar el documento PDF.</translation>
<translation id="9008201768610948239">Ignorar</translation>
+<translation id="901834265349196618">correo electrónico</translation>
<translation id="9020200922353704812">La dirección de facturación de la tarjeta es obligatoria</translation>
<translation id="9020542370529661692">Esta página se ha traducido al <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9020742383383852663">A8</translation>
@@ -2505,6 +2559,7 @@ Más información:
<translation id="9150045010208374699">Utilizar la cámara</translation>
<translation id="9150685862434908345">El administrador puede modificar la configuración del navegador de manera remota. Es posible que también se administre la actividad de este dispositivo fuera de Chrome. <ph name="BEGIN_LINK" />Más información<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">Actualizado</translation>
+<translation id="9155211586651734179">Periféricos de audio conectados</translation>
<translation id="9157595877708044936">Configurando...</translation>
<translation id="9158625974267017556">C6 (sobre)</translation>
<translation id="9164029392738894042">Comprobación de la precisión</translation>
diff --git a/chromium/components/strings/components_strings_et.xtb b/chromium/components/strings/components_strings_et.xtb
index 64c0347a0ed..3811d39c5fa 100644
--- a/chromium/components/strings/components_strings_et.xtb
+++ b/chromium/components/strings/components_strings_et.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">Kuva üksikasjad</translation>
<translation id="1030706264415084469"><ph name="URL" /> soovib suure koguse andmeid alaliselt teie seadmesse salvestada</translation>
<translation id="1032854598605920125">Pööra päripäeva</translation>
+<translation id="1033329911862281889">Inkognito režiim ei muuda teid veebis nähtamatuks.
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Külastatavad saidid ja teenused näevad külastusi.<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Tööandjad ja koolid võivad sirvimistegevusi jälgida.<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Internetiteenuse pakkujad võivad veebiliiklust jälgida.<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">Lülita välja</translation>
<translation id="1036982837258183574">Täisekraanilt väljumiseks vajutage klahvi |<ph name="ACCELERATOR" />|</translation>
<translation id="1038106730571050514">Kuva soovitused</translation>
<translation id="1038842779957582377">tundmatu nimi</translation>
<translation id="1041998700806130099">Töölehe sõnum</translation>
<translation id="1048785276086539861">Märkuste muutmisel naaseb see dokument ühe lehe vaatele</translation>
-<translation id="1049743911850919806">Inkognito</translation>
<translation id="1050038467049342496">Sulgege muud rakendused</translation>
<translation id="1055184225775184556">&amp;Võta lisamine tagasi</translation>
<translation id="1056898198331236512">Hoiatus</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">Reegli vahemälu töötab probleemideta</translation>
<translation id="1130564665089811311">Nupp Tõlgi leht, selle lehe tõlkimiseks rakendusega Google'i tõlge vajutage sisestusklahvi</translation>
<translation id="1131264053432022307">Teie kopeeritud pilt</translation>
+<translation id="1142846828089312304">Blokeeri kolmanda osapoole küpsisefailid inkognito režiimis</translation>
<translation id="1150979032973867961">Server ei suutnud tõestada, et see on domeen <ph name="DOMAIN" />, arvuti operatsioonisüsteem ei usalda selle turvasertifikaati. Selle põhjuseks võib olla vale seadistus või ründaja, kes on sekkunud teie ühendusse.</translation>
<translation id="1151972924205500581">Parool on nõutav</translation>
<translation id="1156303062776767266">Vaatate kohalikku või jagatud faili</translation>
@@ -64,7 +70,6 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="1178581264944972037">Peata</translation>
<translation id="1181037720776840403">Eemalda</translation>
<translation id="1186201132766001848">Kontrolli paroole</translation>
-<translation id="1195210374336998651">Rakenduse seadete avamine</translation>
<translation id="1195558154361252544">Märguanded blokeeritakse automaatselt kõigi saitide, välja arvatud lubatud saitide puhul.</translation>
<translation id="1197088940767939838">Oranž</translation>
<translation id="1201402288615127009">Järgmine</translation>
@@ -111,7 +116,7 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="1307966114820526988">Katkestatud toega funktsioonid</translation>
<translation id="1308113895091915999">Pakkumine on saadaval</translation>
<translation id="1312803275555673949">Millised tõendid seda toetavad?</translation>
-<translation id="131405271941274527"><ph name="URL" /> soovib andmeid saata ja vastu võtta, kui puudutate telefoniga NFC-seadet</translation>
+<translation id="1314311879718644478">Liitreaalse sisu vaatamine</translation>
<translation id="1314509827145471431">Köide paremal</translation>
<translation id="1318023360584041678">Salvestati vahelehtede gruppi</translation>
<translation id="1319245136674974084">Ära enam selle rakenduse kohta küsi</translation>
@@ -161,6 +166,7 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="142858679511221695">Pilves olev kasutaja</translation>
<translation id="1428729058023778569">Näete seda hoiatust, kuna see sait ei toeta HTTPS-i. <ph name="BEGIN_LEARN_MORE_LINK" />Lisateave<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">Printimine</translation>
+<translation id="1432187715652018471">leht soovib installida teenusetöötleja.</translation>
<translation id="1432581352905426595">Halda otsingumootoreid</translation>
<translation id="1436185428532214179">Saab küsida luba teie seadmes olevate failide ja kaustade muutmiseks</translation>
<translation id="1442386063175183758">Paremalt väravakujuliselt volditud</translation>
@@ -181,6 +187,12 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="1483493594462132177">Saada</translation>
<translation id="1484290072879560759">Valige tarneaadress</translation>
<translation id="1492194039220927094">Reeglite saatmine:</translation>
+<translation id="149293076951187737">Kui sulgete kõik Chrome'i inkognito vahelehed, kustutatakse järgmised nendel vahelehtedel tehtud toimingud sellest seadmest.
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Sirvimistegevused.<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Otsinguajalugu.<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Vormidesse sisestatud teave.<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">Tagasi vahelehele</translation>
<translation id="1501859676467574491">Kuva kaardid minu Google'i kontolt</translation>
<translation id="1507202001669085618">&lt;p&gt;Seda viga näete juhul, kui kasutate WiFi-portaali, kuhu tuleb enne võrguühenduse loomist sisse logida.&lt;/p&gt;
@@ -208,6 +220,8 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="1559572115229829303">&lt;p&gt;Domeeniga <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> ei saa privaatset ühendust luua, kuna seadme kuupäev ja kellaaeg (<ph name="DATE_AND_TIME" />DATE_AND_TIME) on valed.&lt;/p&gt;
&lt;p&gt;Kohandage kuupäeva ja kellaaega rakenduse &lt;strong&gt;Seaded&lt;/strong&gt; jaotises &lt;strong&gt;Üldine&lt;/strong&gt;.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">Administraator taaskäivitab teie seadme kuupäeval <ph name="DATE" />, kell <ph name="TIME" /></translation>
+<translation id="156703335097561114">Võrguteave, nagu aadressid, liidese seadistus ja ühenduse kvaliteet</translation>
<translation id="1567040042588613346">See reegel töötab eesmärgipäraselt, kuid mujal on seadistatud sama väärtus, mis on selle reegliga asendatud.</translation>
<translation id="1569487616857761740">Sisestage aegumiskuupäev</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="1583429793053364125">Veebilehe kuvamisel läks midagi valesti.</translation>
<translation id="1586541204584340881">Millised laiendused olete installinud</translation>
<translation id="1588438908519853928">Tavaline</translation>
+<translation id="1589050138437146318">Kas installida ARCore?</translation>
<translation id="1592005682883173041">Juurdepääs kohalikele andmetele</translation>
<translation id="1594030484168838125">Vali</translation>
<translation id="160851722280695521">Chrome'is mängu Dino Run mängimine</translation>
@@ -254,7 +269,7 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="1711234383449478798">Eirati, kuna reegel <ph name="POLICY_NAME" /> pole seadistatud väärtusele <ph name="VALUE" />.</translation>
<translation id="1712552549805331520"><ph name="URL" /> soovib andmed alaliselt teie kohalikku arvutisse salvestada</translation>
<translation id="1713628304598226412">Salv 2</translation>
-<translation id="1715874602234207">F</translation>
+<translation id="1715874602234207">R</translation>
<translation id="1717218214683051432">Liikumisandurid</translation>
<translation id="1717494416764505390">Postkast 3</translation>
<translation id="1718029547804390981">Dokument on märkuste lisamiseks liiga suur</translation>
@@ -282,6 +297,7 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
mis nõuab lähtekohareegli rakendamist kõigi sellele saadetud taotluste puhul. Päis on aga valesti moodustatud ja see ei lase brauseril teie
saidile <ph name="SITE" /> esitatud taotlust täita. Saidioperaatorid saavad kasutada
lähtekohareegleid saidi turbe ja muude atribuutide seadistamiseks.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Lisateave Chromiumi inkognito režiimi kohta<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">Teie avatud vahelehed kuvatakse siin</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -358,7 +374,7 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="204357726431741734">Logige sisse, et kasutada oma Google'i kontole salvestatud paroole</translation>
<translation id="2053111141626950936">Selles keeles lehti ei tõlgita: <ph name="LANGUAGE" />.</translation>
<translation id="2053373601901562871">{NUM_DAYS,plural, =0{Kui see juhtelement on sisse lülitatud ja olek on aktiivne, määrab Chrome, millise suure grupi (ehk rühma) inimestega on teie hiljutine sirvimistegevus kõige sarnasem. Reklaamijad saavad grupi jaoks reklaame valida ja teie sirvimistegevus jääb teie seadmes privaatseks. Teie gruppi värskendatakse iga päev.}=1{Kui see juhtelement on sisse lülitatud ja olek on aktiivne, määrab Chrome, millise suure grupi (ehk rühma) inimestega on teie hiljutine sirvimistegevus kõige sarnasem. Reklaamijad saavad grupi jaoks reklaame valida ja teie sirvimistegevus jääb teie seadmes privaatseks. Teie gruppi värskendatakse iga päev.}other{Kui see juhtelement on sisse lülitatud ja olek on aktiivne, määrab Chrome, millise suure grupi (ehk rühma) inimestega on teie hiljutine sirvimistegevus kõige sarnasem. Reklaamijad saavad grupi jaoks reklaame valida ja teie sirvimistegevus jääb teie seadmes privaatseks. Teie gruppi värskendatakse iga {NUM_DAYS} päeva järel.}}</translation>
-<translation id="2053553514270667976">Postiindeks</translation>
+<translation id="2053553514270667976">Sihtnumber</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 soovitus}other{# soovitust}}</translation>
<translation id="2071156619270205202">Seda kaarti ei saa virtuaalkaardi numbrina kasutada.</translation>
<translation id="2071692954027939183">Märguanded blokeeriti automaatselt, kuna tavaliselt ei luba te neid kuvada</translation>
@@ -409,6 +425,7 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="22081806969704220">Salv 3</translation>
<translation id="2212735316055980242">Reeglit ei leitud</translation>
<translation id="2213606439339815911">Kirjete toomine ...</translation>
+<translation id="2213612003795704869">Leht prinditakse</translation>
<translation id="2215727959747642672">Failide muutmine</translation>
<translation id="2218879909401188352">Saidil <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> olevad ründajad võivad installida ohtlikke rakendusi, mis kahjustavad teie seadet, lisavad mobiiliarvele varjatud kulusid või varastavad teie isiklikke andmeid. <ph name="BEGIN_LEARN_MORE_LINK" />Lisateave<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">Interneti-ühendus puudub</translation>
@@ -418,6 +435,7 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="2248949050832152960">Kasuta WebAuthn-autentimist</translation>
<translation id="2250931979407627383">Õmblus vasakus servas</translation>
<translation id="225207911366869382">Väärtus on eeskirjade jaoks aegunud.</translation>
+<translation id="2256115617011615191">Taaskäivita kohe</translation>
<translation id="2258928405015593961">Sisestage tulevikus olev aegumiskuupäev ja proovige uuesti</translation>
<translation id="225943865679747347">Veakood: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">HTTP viga</translation>
@@ -445,6 +463,7 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="2337852623177822836">Seadet juhib administraator</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> soovib siduda</translation>
<translation id="2346319942568447007">Teie kopeeritud pilt</translation>
+<translation id="2350796302381711542">Kas lubada kasutajal <ph name="HANDLER_HOSTNAME" /> avada kõik protokolli <ph name="PROTOCOL" /> lingid kasutaja <ph name="REPLACED_HANDLER_TITLE" /> asemel?</translation>
<translation id="2354001756790975382">Muud järjehoidjad</translation>
<translation id="2354430244986887761">Google'i ohutu sirvimine leidis hiljuti saidilt <ph name="SITE" /> <ph name="BEGIN_LINK" />ohtlikke rakendusi<ph name="END_LINK" />.</translation>
<translation id="2355395290879513365">Ründajad võivad näha pilte, mida sellel saidil vaatate, ja teid neid pilte muutes petta.</translation>
@@ -470,6 +489,7 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="2413528052993050574">Server ei suutnud tõestada, et see on domeen <ph name="DOMAIN" />, selle turvasertifikaat võib olla tühistatud. Selle põhjuseks võib olla vale seadistus või ründaja, kes on sekkunud teie ühendusse.</translation>
<translation id="2414886740292270097">Tume</translation>
<translation id="2430968933669123598">Google'i konto haldamine, oma Google'i kontol teabe, privaatsuse ja turvalisuse haldamiseks vajutage sisestusklahvi</translation>
+<translation id="2436186046335138073">Kas lubada kasutajal <ph name="HANDLER_HOSTNAME" /> avada kõik protokolli <ph name="PROTOCOL" /> lingid?</translation>
<translation id="2438874542388153331">Neli auku paremal</translation>
<translation id="2450021089947420533">Teekonnad</translation>
<translation id="2463739503403862330">Täida</translation>
@@ -477,6 +497,7 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="2465655957518002998">Valige kohaletoimetamisviis</translation>
<translation id="2465688316154986572">Kirjaklamber</translation>
<translation id="2465914000209955735">Chrome'is allalaaditud failide haldamine</translation>
+<translation id="2466004615675155314">Teabe kuvamine veebist</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Võrgudiagnostika käitamine<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">Järjestus 1–N</translation>
<translation id="2470767536994572628">Märkuste muutmisel naaseb see dokument ühe lehe vaatele ja algsesse asendisse</translation>
@@ -497,6 +518,7 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="2523886232349826891">Salvestatakse ainult sellesse seadmesse</translation>
<translation id="2524461107774643265">Lisateabe lisamine</translation>
<translation id="2529899080962247600">Sellel väljal ei tohi olla üle <ph name="MAX_ITEMS_LIMIT" /> kirje. Kõiki järgnevaid kirjeid eiratakse.</translation>
+<translation id="2535585790302968248">Privaatselt sirvimiseks avage uus inkognito vaheleht</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{ja veel 1}other{ja veel #}}</translation>
<translation id="2536110899380797252">Lisa aadress</translation>
<translation id="2539524384386349900">Tuvasta</translation>
@@ -522,7 +544,14 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="2597378329261239068">Dokument on parooliga kaitstud. Sisestage parool.</translation>
<translation id="2609632851001447353">Variatsioonid</translation>
<translation id="2610561535971892504">Klõpsake kopeerimiseks</translation>
+<translation id="2617988307566202237">Chrome <ph name="BEGIN_EMPHASIS" />ei salvesta<ph name="END_EMPHASIS" /> järgmist teavet.
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Teie sirvimisajalugu.
+ <ph name="LIST_ITEM" />Küpsisefailid ja saidi andmed.
+ <ph name="LIST_ITEM" />Vormidesse sisestatud teave.
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (ümbrik)</translation>
+<translation id="2623663032199728144">Saab küsida luba teabe kasutamiseks teie ekraanikuvade kohta</translation>
<translation id="2625385379895617796">Teie kell on ees</translation>
<translation id="262745152991669301">Saab küsida luba USB-seadmetega ühenduse loomiseks</translation>
<translation id="2629325967560697240">Chrome'i kõrgeima taseme turvalisuse saavutamiseks <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />lülitage sisse täiustatud kaitse<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -556,6 +585,7 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="2709516037105925701">Automaatne täitmine</translation>
<translation id="2713444072780614174">Valge</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />, vajutage Chrome'i seadetes maksete ja krediitkaarditeabe haldamiseks tabulaatorit ning seejärel sisestusklahvi</translation>
+<translation id="271663710482723385">Täisekraanilt väljumiseks vajutage klahve |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />|</translation>
<translation id="2721148159707890343">Taotlus õnnestus</translation>
<translation id="2723669454293168317">Käitage Chrome'i seadetes ohutuskontroll</translation>
<translation id="2726001110728089263">Külgmine salv</translation>
@@ -586,6 +616,7 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="2850739647070081192">Invite (ümbrik)</translation>
<translation id="2856444702002559011">Ründajad võivad üritada varastada teie teavet (nt paroole, sõnumeid või krediitkaarditeavet) saidilt <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />. <ph name="BEGIN_LEARN_MORE_LINK" />Lisateave<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">Sait kuvab sekkuvaid või eksitavaid reklaame.</translation>
+<translation id="286512204874376891">Virtuaalkaart varjab teie päriskaarti, et teid võimalike pettuste eest kaitsta. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">Sõbralik</translation>
<translation id="2876489322757410363">Väljute inkognito režiimist, et välise rakenduse kaudu maksta. Kas soovite jätkata?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />, vajutage Chrome'i seadetes Google'i ohutu sirvimise ja muu haldamiseks tabulaatorit ja seejärel sisestusklahvi</translation>
@@ -610,6 +641,7 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="2930577230479659665">Kärbi pärast iga koopiat</translation>
<translation id="2932085390869194046">Soovita parooli …</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019">Avada protokolli <ph name="PROTOCOL" /> lingid</translation>
<translation id="2941952326391522266">Server ei suutnud tõestada, et see on domeen <ph name="DOMAIN" />, selle turvasertifikaati pärineb domeenilt <ph name="DOMAIN2" />. Selle põhjuseks võib olla vale seadistus või ründaja, kes on sekkunud teie ühendusse.</translation>
<translation id="2943895734390379394">Ãœleslaadimise aeg:</translation>
<translation id="2948083400971632585">Seadete lehel saate keelata kõik ühenduse jaoks konfigureeritud puhverserverid.</translation>
@@ -642,6 +674,7 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="3037605927509011580">Ups, ebaõnn!</translation>
<translation id="3041612393474885105">Sertifikaadi andmed</translation>
<translation id="3044034790304486808">Jätkake uurimist</translation>
+<translation id="305162504811187366">Chrome Remote Desktopi ajalugu, sh ajatemplid, hostid ja kliendiseansside ID-d</translation>
<translation id="3060227939791841287">C9 (ümbrik)</translation>
<translation id="3061707000357573562">Teenuse paikamine</translation>
<translation id="306573536155379004">Mäng algas.</translation>
@@ -682,6 +715,7 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="3197136577151645743">Saab küsida luba selle teadmiseks, millal seadet aktiivselt kasutate</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />, vajutage Chrome'i seadetes sünkroonitava teabe haldamiseks tabulaatorit ja seejärel sisestusklahvi</translation>
<translation id="320323717674993345">Tühista makse</translation>
+<translation id="3203366800380907218">Veebist</translation>
<translation id="3207960819495026254">Järjehoidjatesse lisatud</translation>
<translation id="3209034400446768650">Leht võib võtta tasu</translation>
<translation id="3212581601480735796">Teie tegevust seadmes <ph name="HOSTNAME" /> jälgitakse</translation>
@@ -698,10 +732,12 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="3234666976984236645">Sellel saidil olulise sisu alati tuvastamine</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />, oma brauseri ilme kohandamiseks vajutage tabulaatorit ja siis sisestusklahvi</translation>
<translation id="3240791268468473923">Turvalise maksemandaadi leht selle kohta, et pole ühtegi sobivat mandaati, on avatud</translation>
+<translation id="324180406144491771">Hosti „<ph name="HOST_NAME" />“ lingid on blokeeritud</translation>
<translation id="3249845759089040423">Särtsakas</translation>
<translation id="3252266817569339921">prantsuse keel</translation>
<translation id="3257954757204451555">Kelle selle teabe taga on?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />, rakenduses Google'i kalender kiirelt uue sündmuse loomiseks vajutage tabulaatorit ja seejärel sisestusklahvi</translation>
+<translation id="3261488570342242926">Lisateave virtuaalkaartide kohta</translation>
<translation id="3264837738038045344">Nupp Chrome'i seadete haldamine, Chrome'i seadete avamiseks vajutage sisestusklahvi.</translation>
<translation id="3266793032086590337">Väärtus (konflikt)</translation>
<translation id="3268451620468152448">Avatud vahelehed</translation>
@@ -715,6 +751,7 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="3288238092761586174"><ph name="URL" /> peab teie makse kinnitamiseks võib-olla täiendavaid toiminguid tegema</translation>
<translation id="3293642807462928945">Lisateave reegli <ph name="POLICY_NAME" /> kohta</translation>
<translation id="3295444047715739395">Vaadake ja hallake oma paroole Chrome'i seadetes</translation>
+<translation id="3303795387212510132">Kas lubada rakendusel <ph name="PROTOCOL_SCHEME" />-linke avada?</translation>
<translation id="3303855915957856445">Otsingutulemusi ei leitud</translation>
<translation id="3304073249511302126">Bluetoothi otsimine</translation>
<translation id="3308006649705061278">Organisatsiooniüksus (OU)</translation>
@@ -728,12 +765,6 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="3345782426586609320">Silmad</translation>
<translation id="3355823806454867987">Muuda puhverserveri seadeid ...</translation>
<translation id="3360103848165129075">Maksetöötleja leht</translation>
-<translation id="3361596688432910856">Chrome <ph name="BEGIN_EMPHASIS" />ei salvesta<ph name="END_EMPHASIS" /> järgmist teavet:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />teie sirvimisajalugu;
- <ph name="LIST_ITEM" />küpsisefailid ja saidi andmed;
- <ph name="LIST_ITEM" />vormidesse sisestatud teave.
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">See reegel kopeeriti automaatselt katkestatud toega reeglist <ph name="OLD_POLICY" />. Peaksite selle asemel kasutama seda reeglit.</translation>
<translation id="3364869320075768271"><ph name="URL" /> soovib kasutada teie virtuaalreaalsuse seadet ja andmeid</translation>
<translation id="3366477098757335611">Kuva kaardid</translation>
@@ -816,7 +847,6 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="3587738293690942763">Keskmine</translation>
<translation id="3592413004129370115">Italian (ümbrik)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{Saate grupi mis tahes ajal lähtestada. Uue grupiga liitumiseks kulub umbes päev.}=1{Saate grupi mis tahes ajal lähtestada. Uue grupiga liitumiseks kulub umbes päev.}other{Saate grupi mis tahes ajal lähtestada. Uue grupiga liitumiseks kulub {NUM_DAYS} päeva.}}</translation>
-<translation id="3596012367874587041">Rakenduse seaded</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">Rakenduse blokeeris administraator</translation>
<translation id="3608932978122581043">Voo suund</translation>
@@ -859,6 +889,7 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="370972442370243704">Lülita sisse funktsioon Teekonnad</translation>
<translation id="3711895659073496551">Peata</translation>
<translation id="3712624925041724820">Litsentsid on ammendunud</translation>
+<translation id="3714633008798122362">veebikalender</translation>
<translation id="3714780639079136834">Lülitage sisse mobiilne andmeside või WiFi</translation>
<translation id="3715597595485130451">Ühenduse loomine WiFi-võrguga</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Kontrollige puhverserveri, tulemüüri ja DNS-i seadistust<ph name="END_LINK" /></translation>
@@ -920,6 +951,7 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="3906954721959377182">Tahvelarvuti</translation>
<translation id="3909477809443608991"><ph name="URL" /> soovib esitada kaitstud sisu. Google kinnitab teie seadme identiteedi ning sait võib sellele juurde pääseda.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">Keela</translation>
<translation id="3939773374150895049">Kas kasutada CVC asemel WebAuthn-autentimist?</translation>
<translation id="3946209740501886391">Küsi sellel saidil alati</translation>
<translation id="3947595700203588284">Saab küsida luba MIDI-seadmetega ühenduse loomiseks</translation>
@@ -941,6 +973,7 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="3990250421422698716">Astme nihe</translation>
<translation id="3996311196211510766">Sait <ph name="ORIGIN" /> nõuab, et lähtekohareeglit
kohaldataks kõigi taotluste puhul, kuid reeglit ei saa praegu rakendada.</translation>
+<translation id="4009243425692662128">Sisu teie prinditavatel lehtedel saadetakse analüüsiks Google Cloudile või kolmandatele osapooltele. Näiteks võidakse seda skannida tundlike andmete tuvastamiseks.</translation>
<translation id="4010758435855888356">Kas lubada juurdepääs salvestusruumile?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{PDF-dokument sisaldab {COUNT} lehte}other{PDF-dokument sisaldab {COUNT} lehte}}</translation>
<translation id="4023431997072828269">Kuna see vorm esitatakse ühenduse kaudu, mis pole turvaline, on teie teave teistele nähtav.</translation>
@@ -1035,6 +1068,7 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="4250680216510889253">Ei</translation>
<translation id="4253168017788158739">Märkus</translation>
<translation id="425582637250725228">Tehtud muudatusi ei pruugita salvestada.</translation>
+<translation id="425869179292622354">Kas soovite selle virtuaalkaardiga turvalisemaks muuta?</translation>
<translation id="4258748452823770588">Sobimatu allkiri</translation>
<translation id="4261046003697461417">Kaitstud dokumentidele ei saa märkusi lisada</translation>
<translation id="4265872034478892965">Lubas administraator</translation>
@@ -1097,6 +1131,7 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="4434045419905280838">Hüpikaknad ja ümbersuunamised</translation>
<translation id="4435702339979719576">Postkaart)</translation>
<translation id="443673843213245140">Puhverserveri kasutamine on keelatud, kuid määratud on ka konkreetne puhverserveri konfigureerimine.</translation>
+<translation id="4441832193888514600">Eiratakse, kuna reegli saab seadistada ainult pilves olev kasutaja.</translation>
<translation id="4450893287417543264">Ära kuva uuesti</translation>
<translation id="4451135742916150903">Saab küsida luba HID-seadmetega ühenduse loomiseks</translation>
<translation id="4452328064229197696">Äsja kasutatud parool leiti andmetega seotud rikkumisest. Teie kontode turvalisuse kaitsmiseks soovitab Google'i paroolihaldur teil kontrollida oma salvestatud paroole.</translation>
@@ -1152,6 +1187,7 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="4628948037717959914">Foto</translation>
<translation id="4631649115723685955">Ostuboonus on lingitud</translation>
<translation id="4636930964841734540">Teave</translation>
+<translation id="4638670630777875591">Inkognito režiim Chromiumis</translation>
<translation id="464342062220857295">Otsingufunktsioonid</translation>
<translation id="4644670975240021822">Vastupidine järjestus, esikülg allapoole</translation>
<translation id="4646534391647090355">Vii mind kohe sinna</translation>
@@ -1172,6 +1208,7 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="4708268264240856090">Teie ühendus katkes</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Windowsi võrgudiagnostika käitamine<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426">Kasutaja <ph name="USERNAME" /> parool</translation>
<translation id="4724144314178270921">Saab küsida luba lõikelaual oleva teksti ja piltide nägemiseks</translation>
<translation id="4726672564094551039">Laadi reeglid uuesti</translation>
<translation id="4728558894243024398">Platvorm</translation>
@@ -1193,6 +1230,7 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="4757993714154412917">Sisestasite äsja oma parooli kahtlasele saidile. Teie kontode turvalisuse tagamiseks soovitab Chromium teil salvestatud paroole kohe kontrollida.</translation>
<translation id="4758311279753947758">Lisage kontaktteave</translation>
<translation id="4761104368405085019">Mikrofoni kasutamine</translation>
+<translation id="4761869838909035636">Käita Chrome'i ohutuskontroll</translation>
<translation id="4764776831041365478">Veebileht aadressil <ph name="URL" /> võib olla ajutiselt maas või jäädavalt uuele veebiaadressile teisaldatud.</translation>
<translation id="4766713847338118463">Kaks kirjaklambrit all</translation>
<translation id="4771973620359291008">Tekkis tundmatu viga.</translation>
@@ -1213,12 +1251,6 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="4819347708020428563">Kas muuta märkusi vaikekuval?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />, kiirelt uue Google'i arvutustabeli loomiseks vajutage tabulaatorit ja seejärel sisestusklahvi</translation>
<translation id="4825507807291741242">Võimas</translation>
-<translation id="4827402517081186284">Inkognito režiim ei muuda teid veebis nähtamatuks.
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Saidid teavad, kui neid külastate.<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Tööandjad või koolid saavad teie sirvimistegevust jälgida.<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Interneti teenusepakkujad võivad veebiliiklust jälgida.<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">Lülita hoiatused sisse</translation>
<translation id="4838327282952368871">Unistav</translation>
<translation id="4840250757394056958">Chrome’i ajaloo vaatamine</translation>
@@ -1230,12 +1262,12 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="4854362297993841467">See kohaletoimetamisviis pole saadaval. Proovige mõnda teist kohaletoimetamisviisi.</translation>
<translation id="4854853140771946034">Rakenduses Google Keep kiirelt uue märkuse loomine</translation>
<translation id="485902285759009870">Koodi kinnitamine …</translation>
+<translation id="4866506163384898554">Vajutage kursori kuvamiseks klahve |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />|</translation>
<translation id="4876188919622883022">Lihtsustatud vaade</translation>
<translation id="4876305945144899064">Kasutajanimi puudub</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{Puudub}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831">Otsing <ph name="TEXT" /></translation>
<translation id="4879491255372875719">Automaatne (vaikimisi)</translation>
-<translation id="4879725228911483934">Avada ja paigutada aknaid teie ekraanikuvadel</translation>
<translation id="4880827082731008257">Otsi ajaloost</translation>
<translation id="4881695831933465202">Ava</translation>
<translation id="4885256590493466218">Makske kassas kaardiga <ph name="CARD_DETAIL" /></translation>
@@ -1244,6 +1276,7 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">Ãœheksas rull</translation>
<translation id="4901778704868714008">Salvesta …</translation>
+<translation id="4905659621780993806">Administraator taaskäivitab teie seadme kuupäeval <ph name="DATE" /> kell <ph name="TIME" /> automaatselt. Salvestage avatud üksused enne seadme taaskäivitamist.</translation>
<translation id="4913987521957242411">Auk vasakul ülal</translation>
<translation id="4918221908152712722">Installige rakendus <ph name="APP_NAME" /> (allalaadimine pole vajalik)</translation>
<translation id="4923459931733593730">Makse</translation>
@@ -1252,6 +1285,7 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, vajutage otsimiseks tabulaatorit ja siis sisestusklahvi</translation>
<translation id="4930153903256238152">Suur mahutavus</translation>
+<translation id="4940163644868678279">Inkognito režiim Chrome'is</translation>
<translation id="4943872375798546930">Tulemusi pole</translation>
<translation id="4950898438188848926">Vahelehe vahetamise nupp, vajutage sisestusklahvi avatud vahelehe aktiveerimiseks, <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="495170559598752135">Toimingud</translation>
@@ -1261,6 +1295,7 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="4968522289500246572">Rakendus on loodud mobiilseadmetele ja selle suuruse muutmine võib rakendusele halvasti mõjuda. Rakenduse töös võib esineda probleeme või rakendus võib taaskäivituda.</translation>
<translation id="4969341057194253438">Kustuta salvestis</translation>
<translation id="4973922308112707173">Kaks auku ülal</translation>
+<translation id="4976702386844183910">Viimati külastati <ph name="DATE" /></translation>
<translation id="4984088539114770594">Kas kasutada mikrofoni?</translation>
<translation id="4984339528288761049">Prc5 (ümbrik)</translation>
<translation id="4989163558385430922">Kuva kõik</translation>
@@ -1322,6 +1357,7 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="5138227688689900538">Kuva vähem</translation>
<translation id="5145883236150621069">Reegli vastuses sisaldus veakood</translation>
<translation id="5146995429444047494">Saidi <ph name="ORIGIN" /> märguanded on blokeeritud</translation>
+<translation id="514704532284964975"><ph name="URL" /> soovib vaadata ja muuta teavet NFC-seadmes, mida oma telefoniga puudutate</translation>
<translation id="5148809049217731050">Esikülg ülespoole</translation>
<translation id="515292512908731282">C4 (ümbrik)</translation>
<translation id="5158275234811857234">Kaas</translation>
@@ -1346,6 +1382,7 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="5215116848420601511">Makseviisid ja aadressid, mis kasutavad teenust Google Pay.</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">Salv 13</translation>
+<translation id="5216942107514965959">Viimati külastati täna</translation>
<translation id="5222812217790122047">E-posti aadress on nõutav</translation>
<translation id="5230733896359313003">Tarneaadress</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1366,7 +1403,6 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">Dokumendi atribuudid</translation>
<translation id="528468243742722775">Lõpeta</translation>
-<translation id="5284909709419567258">Võrguaadressid</translation>
<translation id="5285570108065881030">Kuva kõik salvestatud paroolid</translation>
<translation id="5287240709317226393">Kuva küpsised</translation>
<translation id="5287456746628258573">See sait kasutab vananenud turvaseadistust, mis võib paljastada teie teabe (näiteks paroolid või krediitkaardinumbrid), kui see saadetakse sellele saidile.</translation>
@@ -1450,6 +1486,7 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="5556459405103347317">Laadi uuesti</translation>
<translation id="5560088892362098740">Aegumiskuupäev</translation>
<translation id="55635442646131152">Dokumendi liigendus</translation>
+<translation id="5565613213060953222">Ava inkognito vaheleht</translation>
<translation id="5565735124758917034">Aktiivne</translation>
<translation id="5570825185877910964">Kaitse kontot</translation>
<translation id="5571083550517324815">Sellelt aadressilt ei saa kaupa kätte. Valige mõni teine aadress.</translation>
@@ -1532,6 +1569,7 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="5869522115854928033">Salvestatud paroolid</translation>
<translation id="5873013647450402046">Teie pank soovib teie isikut kinnitada.</translation>
<translation id="5887400589839399685">Kaart on salvestatud</translation>
+<translation id="5887687176710214216">Viimati külastati eile</translation>
<translation id="5895138241574237353">Taaskäivitamine</translation>
<translation id="5895187275912066135">Väljastamiskuupäev</translation>
<translation id="5901630391730855834">Kollane</translation>
@@ -1545,6 +1583,7 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="5921639886840618607">Kas salvestada kaart Google'i kontole?</translation>
<translation id="5922853866070715753">Peaaegu valmis</translation>
<translation id="5932224571077948991">Sait kuvab sekkuvaid või eksitavaid reklaame</translation>
+<translation id="5938153366081463283">Virtuaalkaardi lisamine</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347">Saidi <ph name="SITE_NAME" /> avamine …</translation>
<translation id="5951495562196540101">Tarbijakontoga ei saa registreeruda (paketipõhine litsents on saadaval).</translation>
@@ -1609,6 +1648,7 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="6120179357481664955">Kas jätta teie UPI ID meelde?</translation>
<translation id="6124432979022149706">Chrome Enterprise'i liidesed</translation>
<translation id="6127379762771434464">Ãœksus eemaldati</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Lisateave inkognito režiimi kohta Chrome'is<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">Kontrollige kaableid ning taaskäivitage kõik ruuterid, modemid ja muud
kasutuses olevad võrguseadmed.</translation>
<translation id="614940544461990577">Proovige järgmist.</translation>
@@ -1621,7 +1661,6 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="6169916984152623906">Nüüd saate sirvida privaatselt ja teised seadme kasutajad ei näe teie tegevusi. Allalaaditud failid ja järjehoidjad siiski salvestatakse.</translation>
<translation id="6177128806592000436">Teie ühendus selle saidiga pole turvaline</translation>
<translation id="6180316780098470077">Uuesti proovimise intervall</translation>
-<translation id="619448280891863779">Saab küsida luba aknaid teie ekraanikuvadel avada ja paigutada</translation>
<translation id="6196640612572343990">Blokeeri kolmanda osapoole küpsisefailid</translation>
<translation id="6203231073485539293">Kontrollige Interneti-ühendust</translation>
<translation id="6218753634732582820">Kas eemaldada Chromiumist aadress?</translation>
@@ -1644,7 +1683,7 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="6272383483618007430">Google Update</translation>
<translation id="6276112860590028508">Siin kuvatakse teie lugemisloendis olevad lehed</translation>
<translation id="627746635834430766">Kui soovite järgmisel korral kiiremini maksta, salvestage kaart ja arveldusaadress oma Google'i kontole.</translation>
-<translation id="6279098320682980337">Kas virtuaalkaardi numbrit pole sisestatud? Klõpsake kopeerimiseks kaardi üksikasjadel</translation>
+<translation id="6279183038361895380">Kursori kuvamiseks vajutage klahvi |<ph name="ACCELERATOR" />|</translation>
<translation id="6280223929691119688">Sellele aadressile ei saa kaupa kohale toimetada. Valige mõni teine aadress.</translation>
<translation id="6282194474023008486">Sihtnumber</translation>
<translation id="6285507000506177184">Nupp Chrome'i allalaadimiste haldamine, Chrome'is allalaaditud failide haldamiseks vajutage sisestusklahvi</translation>
@@ -1652,6 +1691,7 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="6290238015253830360">Teie soovitatud artiklid kuvatakse siin</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{Teie seade taaskäivitub kohe}=1{Teie seade taaskäivitub 1 sekundi pärast}other{Teie seade taaskäivitub # sekundi pärast}}</translation>
<translation id="6302269476990306341">Chrome'ile mõeldud Google'i assistenti peatatakse</translation>
<translation id="6305205051461490394">URL-iga <ph name="URL" /> ei saa ühendust.</translation>
<translation id="6312113039770857350">Veebileht ei ole saadaval</translation>
@@ -1725,6 +1765,7 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="6529602333819889595">&amp;Kustuta uuesti</translation>
<translation id="6545864417968258051">Bluetoothi otsimine</translation>
<translation id="6547208576736763147">Kaks auku vasakul</translation>
+<translation id="6554732001434021288">Viimati külastati <ph name="NUM_DAYS" /> päeva tagasi</translation>
<translation id="6556866813142980365">Tee uuesti</translation>
<translation id="6569060085658103619">Vaatate laienduse lehte</translation>
<translation id="6573200754375280815">Kaks auku paremal</translation>
@@ -1785,7 +1826,6 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="6757797048963528358">Teie seade lülitus unerežiimile.</translation>
<translation id="6767985426384634228">Kas värskendada aadressi?</translation>
<translation id="6768213884286397650">Hagaki (postkaart)</translation>
-<translation id="6774185088257932239"><ph name="BEGIN_LINK" />Lisateave<ph name="END_LINK" /> inkognito režiimi kohta</translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">Violetne</translation>
<translation id="6786747875388722282">Laiendused</translation>
@@ -1869,7 +1909,6 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="706295145388601875">Lisage ja hallake Chrome'i seadetes aadresse</translation>
<translation id="7064851114919012435">Kontaktteave</translation>
<translation id="7068733155164172741">Sisestage <ph name="OTP_LENGTH" />-kohaline kood</translation>
-<translation id="7070090581017165256">Teave selle saidi kohta</translation>
<translation id="70705239631109039">Teie ühendus ei ole täielikult turvaline</translation>
<translation id="7075452647191940183">Taotlus on liiga suur</translation>
<translation id="7079718277001814089">See sait sisaldab pahavara</translation>
@@ -1886,6 +1925,12 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="7111012039238467737">(Kehtiv)</translation>
<translation id="7118618213916969306">Lõikelaua URL-i otsimine, <ph name="SHORT_URL" /></translation>
<translation id="7119414471315195487">Sulgege muud vahelehed või programmid</translation>
+<translation id="7129355289156517987">Kui sulgete kõik Chromiumi inkognito vahelehed, kustutatakse järgmised nendel vahelehtedel tehtud toimingud sellest seadmest.
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Sirvimistegevused.<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Otsinguajalugu.<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Vormidesse sisestatud teave.<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">Sellele aadressile ei saa tarnida. Valige mõni teine aadress.</translation>
<translation id="7132939140423847331">Teie administraator on keelanud nende andmete kopeerimise.</translation>
<translation id="7135130955892390533">Kuva olek</translation>
@@ -1908,6 +1953,7 @@ Vastasel korral blokeeritakse see teie privaatsusseadetes. See võimaldab teie k
<translation id="7192203810768312527">Vabastab <ph name="SIZE" />. Mõne saidi laadimine võib järgmisel külastusel rohkem aega võtta.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">Teie administraator näeb järgmist.</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, vajutage privaatse sirvimise jaoks uue inkognito vahelehe avamiseks tabulaatorit ja seejärel sisestusklahvi</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423">Host <ph name="HOST_NAME" /> ei pea turvastandarditest kinni.</translation>
<translation id="7210993021468939304">Saab vaadata Linuxi tegevusi konteineris ning installida ja käitada konteineris Linuxi rakendusi</translation>
@@ -1939,6 +1985,7 @@ Lisateave:
<translation id="7304562222803846232">Google’i konto privaatsusseadete haldamine</translation>
<translation id="7305756307268530424">Aeglasemalt alustamine</translation>
<translation id="7308436126008021607">taustal sünkroonimine</translation>
+<translation id="7310392214323165548">Seade taaskäivitub peagi</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">Ãœhendamise abi</translation>
<translation id="7323804146520582233">Peida jaotis „<ph name="SECTION" />â€</translation>
@@ -1946,6 +1993,7 @@ Lisateave:
<translation id="7334320624316649418">&amp;Korrasta uuesti</translation>
<translation id="7335157162773372339">Saab küsida luba teie kaamera kasutamiseks</translation>
<translation id="7337248890521463931">Kuva rohkem ridu</translation>
+<translation id="7337418456231055214">Kas virtuaalkaardi numbrit pole sisestatud? Klõpsake kopeerimiseks kaardi üksikasjadel. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">Pole teie platvormil saadaval.</translation>
<translation id="733923710415886693">Serveri sertifikaati ei avalikustatud sertifikaadi läbipaistvuse reegli kaudu.</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1968,6 +2016,7 @@ Lisateave:
<translation id="7378627244592794276">Ei</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">Pole asjakohane</translation>
+<translation id="7388594495505979117">{0,plural, =1{Teie seade taaskäivitub 1 minuti pärast}other{Teie seade taaskäivitub # minuti pärast}}</translation>
<translation id="7390545607259442187">Kaardi kinnitamine</translation>
<translation id="7392089738299859607">Värskenda aadressi</translation>
<translation id="7399802613464275309">Ohutuskontroll</translation>
@@ -2004,6 +2053,12 @@ Lisateave:
<translation id="7485870689360869515">Andmeid ei leitud.</translation>
<translation id="7495528107193238112">See sisu on blokeeritud. Probleemi lahendamiseks võtke ühendust saidi omanikuga.</translation>
<translation id="7497998058912824456">Nupp Loo dokument, kiirelt uue Google'i dokumendi loomiseks vajutage sisestusklahvi</translation>
+<translation id="7506488012654002225">Chromium <ph name="BEGIN_EMPHASIS" />ei salvesta<ph name="END_EMPHASIS" /> järgmist teavet.
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Teie sirvimisajalugu.
+ <ph name="LIST_ITEM" />Küpsisefailid ja saidi andmed.
+ <ph name="LIST_ITEM" />Vormidesse sisestatud teave.
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">Tagastatud reegli seadme-ID on tühi või ei kattu praeguse seadme-ID-ga</translation>
<translation id="7508870219247277067">Avokaadoroheline</translation>
<translation id="7511955381719512146">WiFi-võrk, mida kasutate, võib nõuda veebilehe <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> külastamist.</translation>
@@ -2117,7 +2172,6 @@ Lisateave:
<translation id="7813600968533626083">Kas eemaldada Chrome'ist vormi soovitus?</translation>
<translation id="781440967107097262">Kas jagada lõikelauda?</translation>
<translation id="7815407501681723534">Otsingule „<ph name="SEARCH_STRING" />†leiti <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" />.</translation>
-<translation id="782125616001965242">Kuva teave selle saidi kohta</translation>
<translation id="782886543891417279">WiFi-võrk, mida kasutate (<ph name="WIFI_NAME" />), võib nõuda sisselogimislehe külastamist.</translation>
<translation id="7836231406687464395">Postfix (ümbrik)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{Puudub}=1{1 rakendus (<ph name="EXAMPLE_APP_1" />)}=2{2 rakendust (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}other{# rakendust (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}}</translation>
@@ -2134,7 +2188,6 @@ Lisateave:
<translation id="7888575728750733395">Prindirenderduse kavatsus</translation>
<translation id="7894280532028510793">Kui õigekirjavigu pole, <ph name="BEGIN_LINK" />käitage võrgudiagnostika<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (ümbrik)</translation>
-<translation id="7931318309563332511">Teadmata</translation>
<translation id="793209273132572360">Kas värskendada aadressi?</translation>
<translation id="7932579305932748336">Kate</translation>
<translation id="79338296614623784">Sisestage kehtiv telefoninumber</translation>
@@ -2159,13 +2212,14 @@ Lisateave:
<translation id="7976214039405368314">Liiga palju päringuid</translation>
<translation id="7977538094055660992">Väljundseade</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">Lingitud kaardiga</translation>
<translation id="798134797138789862">Saab küsida luba VR-seadmete ja -andmete kasutamiseks</translation>
<translation id="7984945080620862648">Te ei saa saiti <ph name="SITE" /> praegu külastada, sest veebisait saatis tagasi arusaamatud mandaadid, mida Chrome ei saa töödelda. Võrguvead ja -rünnakud on tavaliselt ajutised, nii et leht tõenäoliselt hiljem töötab.</translation>
-<translation id="79859296434321399">Liitreaalsuse sisu vaatamiseks installige ARCore</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">Köide</translation>
<translation id="7992044431894087211">Ekraanikuva jagamist rakendusega <ph name="APPLICATION_TITLE" /> jätkati</translation>
<translation id="7995512525968007366">Ei ole määratud</translation>
+<translation id="7998269595945679889">Inkognito vahelehe avamise nupp, vajutage sisestusklahvi uue inkognito vahelehe avamiseks, et privaatselt sirvida</translation>
<translation id="800218591365569300">Sulgege muud vahelehed või programmid, et mälu vabastada.</translation>
<translation id="8004582292198964060">Brauser</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{See kaart ja selle arveldusaadress salvestatakse. Saate seda kasutada, kui olete kontole <ph name="USER_EMAIL" /> sisse logitud.}other{Need kaardid ja nende arveldusaadressid salvestatakse. Saate neid kasutada, kui olete kontole <ph name="USER_EMAIL" /> sisse logitud.}}</translation>
@@ -2225,6 +2279,7 @@ Lisateave:
<translation id="8202370299023114387">Konflikt</translation>
<translation id="8206978196348664717">Prc4 (ümbrik)</translation>
<translation id="8211406090763984747">Ãœhendus on turvaline</translation>
+<translation id="8217240300496046857">Saidid ei saa veebis teie jälgimiseks kasutada küpsisefaile. Mõne saidi funktsioonid ei pruugi töötada.</translation>
<translation id="8218327578424803826">Määratud asukoht:</translation>
<translation id="8220146938470311105">C7/C6 (ümbrik)</translation>
<translation id="8225771182978767009">Arvuti seadistanud inimene blokeeris selle saidi.</translation>
@@ -2265,14 +2320,9 @@ Lisateave:
<translation id="830498451218851433">Pooleks volditud</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">Installitud rakendused ja nende kasutussagedus</translation>
+<translation id="8317207217658302555">Kas värskendada ARCore'i?</translation>
<translation id="831997045666694187">Õhtu</translation>
<translation id="8321476692217554900">märguanded</translation>
-<translation id="8328484624016508118">Pärast kõigi inkognito vahelehtede sulgemist kustutab Chrome järgmised andmed.
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Teie sirvimistegevus selles seadmes.<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Teie otsinguajalugu selles seadmes.<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Vormidesse sisestatud teave.<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489">Juurdepääs hostile <ph name="HOST_NAME" /> blokeeriti</translation>
<translation id="833262891116910667">Tõsta esile</translation>
<translation id="8339163506404995330"><ph name="LANGUAGE" /> keeles olevaid lehti ei tõlgita</translation>
@@ -2324,6 +2374,7 @@ Lisateave:
<translation id="8507227106804027148">Käsurida</translation>
<translation id="8508648098325802031">Otsinguikoon</translation>
<translation id="8511402995811232419">Küpsiste haldamine</translation>
+<translation id="8519753333133776369">Administraator on HID-seadme lubanud</translation>
<translation id="8522552481199248698">Chrome aitab teil oma Google'i kontot kaitsta ja parooli muuta.</translation>
<translation id="8530813470445476232">Kustutage Chrome'i seadetes oma sirvimisajalugu ja küpsisefailid ning tühjendage vahemälu</translation>
<translation id="8533619373899488139">Külastage saiti &lt;strong&gt;chrome://policy&lt;/strong&gt;, et näha blokeeritud URL-ide loendit ja teisi reegleid, mille teie süsteemiadministraator on jõustanud.</translation>
@@ -2335,7 +2386,6 @@ Lisateave:
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{Lähtesta luba}other{Lähtesta load}}</translation>
<translation id="8555010941760982128">Kasutage seda koodi kassas</translation>
<translation id="8557066899867184262">CVC asub kaardi tagaküljel.</translation>
-<translation id="8558485628462305855">Liitreaalsuse sisu vaatamiseks värskendage ARCore'i</translation>
<translation id="8559762987265718583">Privaatset ühendust ei saa domeeniga <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> luua, kuna seadme kuupäev ja kellaaeg (<ph name="DATE_AND_TIME" />) on valed.</translation>
<translation id="8564182942834072828">Eraldi dokumendid / järjestamata koopiad</translation>
<translation id="8564985650692024650">Chromium soovitab teil organisatsiooni <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> parooli lähtestada, kui kasutasite seda ka muudel saitidel.</translation>
@@ -2354,6 +2404,7 @@ Lisateave:
<translation id="865032292777205197">liikumisandurid</translation>
<translation id="8663226718884576429">Tellimuse kokkuvõte, <ph name="TOTAL_LABEL" />, rohkem üksikasju</translation>
<translation id="8666678546361132282">inglise keel</translation>
+<translation id="8669306706049782872">Kasutada teavet teie ekraanikuvade kohta, et avada ja paigutada aknaid</translation>
<translation id="867224526087042813">Allkiri</translation>
<translation id="8676424191133491403">Viivituseta</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, vastus, <ph name="ANSWER" /></translation>
@@ -2380,6 +2431,7 @@ Lisateave:
<translation id="8731544501227493793">Nupp Paroolide haldamine, vajutage Chrome'i seadetes paroolide vaatamiseks ja haldamiseks sisestusklahvi</translation>
<translation id="8734529307927223492">Teie seadet <ph name="DEVICE_TYPE" /> haldab <ph name="MANAGER" /></translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, vajutage privaatse sirvimise jaoks uue inkognito akna avamiseks tabulaatorit ja seejärel sisestusklahvi</translation>
+<translation id="8737685506611670901">Ava protokolli <ph name="PROTOCOL" /> lingid teenuse <ph name="REPLACED_HANDLER_TITLE" /> asemel</translation>
<translation id="8738058698779197622">Turvalise ühenduse loomiseks peab kell olema õigesti seadistatud. See on nii, kuna sertifikaadid, mida veebisaidid kasutavad enda tuvastamiseks, kehtivad ainult teatud perioodi jooksul. Kuna teie seadme kell on vale, ei saa Chromium neid sertifikaate kinnitada.</translation>
<translation id="8740359287975076522">Hosti <ph name="HOST_NAME" /> &lt;abbr id="dnsDefinition"&gt;DNS-aadressi&lt;/abbr&gt; ei leitud. Probleemi diagnoositakse.</translation>
<translation id="8742371904523228557"><ph name="ONE_TIME_CODE" /> on saidi <ph name="ORIGIN" /> puhul teie kood</translation>
@@ -2407,6 +2459,7 @@ Lisateave:
<translation id="883848425547221593">Muud järjehoidjad</translation>
<translation id="884264119367021077">Tarneaadress</translation>
<translation id="884923133447025588">Tühistusmehhanismi ei leitud.</translation>
+<translation id="8849262850971482943">Suurendage virtuaalse kaardi abil turvalisust</translation>
<translation id="885730110891505394">Jagamine Google'iga</translation>
<translation id="8858065207712248076">Chromium soovitab teil organisatsiooni <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> parooli lähtestada, kui kasutasite seda ka muudel saitidel.</translation>
<translation id="885906927438988819">Kui õigekirjavigu pole, <ph name="BEGIN_LINK" />käitage Windowsi võrgudiagnostika<ph name="END_LINK" />.</translation>
@@ -2456,6 +2509,7 @@ Lisateave:
<translation id="9004367719664099443">VR-seanss on pooleli</translation>
<translation id="9005998258318286617">PDF-dokumendi laadimine ebaõnnestus.</translation>
<translation id="9008201768610948239">Eira</translation>
+<translation id="901834265349196618">meil:</translation>
<translation id="9020200922353704812">Kaardi arveldusaadress on nõutav</translation>
<translation id="9020542370529661692">See leht on tõlgitud <ph name="TARGET_LANGUAGE" /> keelde</translation>
<translation id="9020742383383852663">A8</translation>
@@ -2504,6 +2558,7 @@ Lisateave:
<translation id="9150045010208374699">Kaamera kasutamine</translation>
<translation id="9150685862434908345">Teie administraator saab brauseri seadistust kaugühenduse kaudu muuta. Selle seadme tegevusi võidakse hallata ka väljaspool Chrome'i. <ph name="BEGIN_LINK" />Lisateave<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">Värskendatud</translation>
+<translation id="9155211586651734179">Välised heliseadmed on ühendatud</translation>
<translation id="9157595877708044936">Seadistamine...</translation>
<translation id="9158625974267017556">C6 (ümbrik)</translation>
<translation id="9164029392738894042">Täpsuse kontroll</translation>
diff --git a/chromium/components/strings/components_strings_eu.xtb b/chromium/components/strings/components_strings_eu.xtb
index a85b95f5941..4ffb0af1180 100644
--- a/chromium/components/strings/components_strings_eu.xtb
+++ b/chromium/components/strings/components_strings_eu.xtb
@@ -14,17 +14,22 @@
<translation id="1028781062521375153">Ikusi xehetasunak</translation>
<translation id="1030706264415084469"><ph name="URL" /> webguneak datu asko gorde nahi ditu gailuan modu iraunkorrean</translation>
<translation id="1032854598605920125">Biratu eskuinera</translation>
+<translation id="1033329911862281889">Ezkutuko modua erabili arren, ez zara ikusezina izango sarean:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Webguneek eta erabiltzen dituzten zerbitzuek bisitak ikus ditzakete.<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Enpresek edo ikastetxeek arakatze-jardueren jarraipena egin dezakete.<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Interneteko zerbitzu-hornitzaileek sareko trafikoa gainbegira dezakete.<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">Desaktibatu</translation>
<translation id="1036982837258183574">Pantaila osoko ikuspegitik irteteko, sakatu |<ph name="ACCELERATOR" />|</translation>
<translation id="1038106730571050514">Erakutsi iradokizunak</translation>
<translation id="1038842779957582377">izen ezezaguna</translation>
<translation id="1041998700806130099">Lan-orriko mezua</translation>
<translation id="1048785276086539861">Oharpenak editatzen dituzunean, orri bakarreko ikuspegira itzuliko da dokumentua</translation>
-<translation id="1049743911850919806">Ezkutuko modua</translation>
<translation id="1050038467049342496">Itxi beste aplikazio batzuk</translation>
<translation id="1055184225775184556">&amp;Desegin gehitzea</translation>
<translation id="1056898198331236512">Abisua</translation>
-<translation id="1058344460600311577"><ph name="PLAY_CHROME_DINO_GAME_FOCUSED_FRIENDLY_MATCH_TEXT" />: sakatu tabuladorea eta, ondoren, sakatu Sartu tekla Chrome-ko Dino jokoan aritzeko</translation>
+<translation id="1058344460600311577"><ph name="PLAY_CHROME_DINO_GAME_FOCUSED_FRIENDLY_MATCH_TEXT" />: sakatu tabuladorea eta, ondoren, sakatu "Sartu" tekla Chrome-ko Dino jokoan aritzeko</translation>
<translation id="1058479211578257048">Txartelak gordetzen…</translation>
<translation id="10614374240317010">Sekula gorde gabeak</translation>
<translation id="1062160989074299343">Prc10 (gutun-azala)</translation>
@@ -38,7 +43,7 @@
<translation id="1088860948719068836">Gehitu titularra</translation>
<translation id="1089439967362294234">Aldatu pasahitza</translation>
<translation id="1096545575934602868">Eremu honek ez lituzke <ph name="MAX_ITEMS_LIMIT" /> sarrera baino gehiago izan behar. Baztertu egingo dira gainerako sarrerak.</translation>
-<translation id="1100782917270858593">Bilaketa-ibilbideari berrekiteko botoia: sakatu Sartu tekla bilaketa-ibilbideari berrekiteko eta Chrome-ko historian dauden erlazionatutako jarduerak ikusteko</translation>
+<translation id="1100782917270858593">Bilaketa-ibilbideari berrekiteko botoia: sakatu "Sartu" tekla bilaketa-ibilbideari berrekiteko eta Chrome-ko historian dauden erlazionatutako jarduerak ikusteko</translation>
<translation id="1101672080107056897">Errore-ekintza</translation>
<translation id="1103523840287552314">Itzuli <ph name="LANGUAGE" /> beti</translation>
<translation id="1110994991967754504">Hautatu honetarako baimena: <ph name="PERMISSION_NAME" /></translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">Gidalerroaren cachea egoera onean dago</translation>
<translation id="1130564665089811311">"Itzuli orria" botoia: sakatu "Sartu" orria Google Translate-rekin itzultzeko</translation>
<translation id="1131264053432022307">Kopiatu duzun irudia</translation>
+<translation id="1142846828089312304">Blokeatu hirugarrenen cookieak ezkutuko moduan</translation>
<translation id="1150979032973867961">Zerbitzari honek ezin izan du egiaztatu <ph name="DOMAIN" /> domeinua denik. Zure ordenagailuaren sistema eragilea ez da bere segurtasun-ziurtagiriaz fidatzen. Baliteke gaizki konfiguratuta dagoelako izatea edo erasotzaile batek zure konexioa atzeman duelako izatea.</translation>
<translation id="1151972924205500581">Pasahitza behar da</translation>
<translation id="1156303062776767266">Fitxategi lokal edo partekatu bat ari zara ikusten</translation>
@@ -64,7 +70,6 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="1178581264944972037">Pausatu</translation>
<translation id="1181037720776840403">Kendu</translation>
<translation id="1186201132766001848">Egiaztatu pasahitzak</translation>
-<translation id="1195210374336998651">Joan aplikazioen ezarpenetara</translation>
<translation id="1195558154361252544">Webgune guztien jakinarazpenak automatikoki blokeatzen dira, zuk baimentzen dituzunenak izan ezik</translation>
<translation id="1197088940767939838">Laranja</translation>
<translation id="1201402288615127009">Hurrengoa</translation>
@@ -111,7 +116,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="1307966114820526988">Eginbide zaharkituak</translation>
<translation id="1308113895091915999">Eskaintza erabilgarri</translation>
<translation id="1312803275555673949">Zer da horren oinarria?</translation>
-<translation id="131405271941274527"><ph name="URL" /> webguneak informazioa bidali eta jaso nahi du telefonoarekin NFC bidezko gailu bat ukituz gero</translation>
+<translation id="1314311879718644478">Ikusi errealitate areagotuaren edukia</translation>
<translation id="1314509827145471431">Koadernatu eskuinetik</translation>
<translation id="1318023360584041678">Fitxen taldean gordeta</translation>
<translation id="1319245136674974084">Ez galdetu berriro aplikazio honen kasuan</translation>
@@ -150,7 +155,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="1384725838384960382">Ordainketa seguruetarako kredentzialak autentifikatzeko orria</translation>
<translation id="1386623374109090026">Oharpenak</translation>
<translation id="139305205187523129"><ph name="HOST_NAME" /> webguneak ez du bidali daturik.</translation>
-<translation id="1403196654932095242"><ph name="HISTORY_CLUSTERS_SEARCH_FOCUSED_FRIENDLY_MATCH_TEXT" />: sakatu tabuladorea eta, ondoren, sakatu Sartu tekla ikerketari berrekiteko eta Chrome-ko historian dauden erlazionatutako jarduerak ikusteko.</translation>
+<translation id="1403196654932095242"><ph name="HISTORY_CLUSTERS_SEARCH_FOCUSED_FRIENDLY_MATCH_TEXT" />: sakatu tabuladorea eta, ondoren, sakatu "Sartu" tekla ikerketari berrekiteko eta Chrome-ko historian dauden erlazionatutako jarduerak ikusteko.</translation>
<translation id="1405567553485452995">Berde argia</translation>
<translation id="1407135791313364759">Ireki guztiak</translation>
<translation id="1408787208417187241">Hiru grapa goian</translation>
@@ -161,6 +166,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="142858679511221695">Hodeiko erabiltzailea</translation>
<translation id="1428729058023778569">Webgunea HTTPS protokoloarekin bateragarria ez delako erakutsi dizugu abisu hau. <ph name="BEGIN_LEARN_MORE_LINK" />Lortu informazio gehiago<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">Inprimatu</translation>
+<translation id="1432187715652018471">orriak zerbitzu-kudeatzaile bat instalatu nahi du.</translation>
<translation id="1432581352905426595">Kudeatu bilatzaileak</translation>
<translation id="1436185428532214179">Gailuko fitxategiak eta karpetak editatzea eska dezake</translation>
<translation id="1442386063175183758">Leiho-erako tolestura eskuinean</translation>
@@ -181,6 +187,12 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="1483493594462132177">Bidali</translation>
<translation id="1484290072879560759">Aukeratu bidalketa-helbidea</translation>
<translation id="1492194039220927094">Gidalerroen push gaitasuna:</translation>
+<translation id="149293076951187737">Chrome-ko ezkutuko moduko fitxa guztiak ixten dituzunean, fitxa horietan egindako jarduerak gailutik ezabatuko dira:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />arakatze-jarduerak<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />bilaketa-historia<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />inprimakietan idatzitako informazioa<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">Itzuli fitxara</translation>
<translation id="1501859676467574491">Erakutsi Google-ko kontuko txartelak</translation>
<translation id="1507202001669085618">&lt;p&gt;Internetera konektatzeko saioa hastea eskatzen dizun Wi-Fi atari bat erabiltzen ari bazara ikusiko duzu errore hori.&lt;/p&gt;
@@ -208,6 +220,8 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="1559572115229829303">&lt;p&gt;Ezin da ezarri <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> domeinurako konexio pribatua, gailuaren data eta ordua (<ph name="DATE_AND_TIME" />) okerrak direlako.&lt;/p&gt;
&lt;p&gt;Doitu data eta ordua &lt;strong&gt;Ezarpenak&lt;/strong&gt; aplikazioko &lt;strong&gt;Orokorra&lt;/strong&gt; atalean.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">Egun honetan, administratzaileak gailua berrabiaraziko du: <ph name="DATE" /> (<ph name="TIME" />)</translation>
+<translation id="156703335097561114">Sareei buruzko informazioa, hala nola helbideak, interfazeen konfigurazioa eta konexioen kalitatea</translation>
<translation id="1567040042588613346">Gidalerroak espero bezala funtzionatzen du, baina balio bera beste nonbait dago ezarrita, eta gidalerro honek hura ordezten du.</translation>
<translation id="1569487616857761740">Adierazi iraungitze-data</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="1583429793053364125">Arazo bat izan da web-orria bistaratzean.</translation>
<translation id="1586541204584340881">Instalatuta dauzkazun luzapenak.</translation>
<translation id="1588438908519853928">Arrunta</translation>
+<translation id="1589050138437146318">ARCore instalatu nahi duzu?</translation>
<translation id="1592005682883173041">Datu lokaletarako sarbidea</translation>
<translation id="1594030484168838125">Aukeratu</translation>
<translation id="160851722280695521">Aritu Chrome-ko Dino jokoan</translation>
@@ -279,6 +294,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="1763864636252898013">Zerbitzari honek ezin izan du egiaztatu <ph name="DOMAIN" /> domeinua denik. Zure gailuaren sistema eragilea ez da bere segurtasun-ziurtagiriaz fidatzen. Baliteke gaizki konfiguratuta dagoelako izatea edo erasotzaile batek zure konexioa atzeman duelako izatea.</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Exekutatu Windows-en sare-diagnostikoak<ph name="END_LINK" />.</translation>
<translation id="1772163372082567643">Aukeratu duzun zerbitzariak (<ph name="ORIGIN" />) goiburu bat ezarri du; haren arabera, jatorri-gidalerro bat aplikatuko zaie zerbitzari hartako eskaera guztiei. Alabaina, goiburua oker dago eratuta; ondorioz, arakatzaileak ezin du gauzatu <ph name="SITE" /> webgunean sartzeko egin duzun eskaera. Webgunearen segurtasuna eta beste propietate batzuk konfiguratzeko erabili ohi dituzte webguneen eragileek jatorri-gidalerroak.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Lortu Chromium-eko ezkutuko moduari buruzko informazio gehiago<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">Ireki dituzun fitxak agertuko dira hemen</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -321,7 +337,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="1919345977826869612">Iragarkiak</translation>
<translation id="1919367280705858090">Lortu errore-mezu jakin bati buruzko laguntza</translation>
<translation id="192020519938775529">{COUNT,plural, =0{Bat ere ez}=1{1 webgune}other{# webgune}}</translation>
-<translation id="1923390796829649802">Erabilerraztasun-ezarpenak kudeatzeko botoia: sakatu Sartu tekla Chrome OS-n ezarpenetan erabilerraztasun-tresnak pertsonalizatzeko</translation>
+<translation id="1923390796829649802">Erabilerraztasun-ezarpenak kudeatzeko botoia: sakatu "Sartu" tekla Chrome OS-n ezarpenetan erabilerraztasun-tresnak pertsonalizatzeko</translation>
<translation id="1924727005275031552">Berriak</translation>
<translation id="1927439593081478069">Chrome-ren segurtasun-egiaztapena egiteko botoia: sakatu "Sartu" tekla Chrome-ren ezarpenetan segurtasun-egiaztapena egiteko</translation>
<translation id="1939175642807587452">Jakinarazpenak bidaltzea eska dezake</translation>
@@ -406,6 +422,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="22081806969704220">3. erretilua</translation>
<translation id="2212735316055980242">Ez da gidalerroa aurkitu</translation>
<translation id="2213606439339815911">Sarrerak eskuratzen…</translation>
+<translation id="2213612003795704869">Orria inprimatu da</translation>
<translation id="2215727959747642672">Fitxategiak editatzeko aukera</translation>
<translation id="2218879909401188352"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> webguneko erasotzaileek aplikazio arriskutsuak instala ditzakete eta haiek gailua kalte dezakete, mugikorraren fakturan gastu ezkutuak gehi ditzakete edo informazio pertsonala ezkuta dezakete. <ph name="BEGIN_LEARN_MORE_LINK" />Lortu informazio gehiago<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">Ez dago Interneteko konexiorik</translation>
@@ -415,6 +432,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="2248949050832152960">Erabili WebAuthn</translation>
<translation id="2250931979407627383">Ezkerreko ertza josita</translation>
<translation id="225207911366869382">Balioa zaharregia da gidalerro honetarako.</translation>
+<translation id="2256115617011615191">Berrabiarazi</translation>
<translation id="2258928405015593961">Idatzi etorkizuneko iraungitze-data bat eta saiatu berriro</translation>
<translation id="225943865679747347">Errore-kodea: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">HTTParen errorea</translation>
@@ -442,6 +460,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="2337852623177822836">Administratzaileak kontrolatzen du ezarpena</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> webguneak parekatu egin nahi du</translation>
<translation id="2346319942568447007">Kopiatu duzun irudia</translation>
+<translation id="2350796302381711542"><ph name="REPLACED_HANDLER_TITLE" /> ireki ordez, <ph name="PROTOCOL" /> esteka guztiak irekitzeko baimena eman nahi diozu <ph name="HANDLER_HOSTNAME" /> maneiatzaileari?</translation>
<translation id="2354001756790975382">Beste laster-markak</translation>
<translation id="2354430244986887761">Google-ren Arakatze seguruak <ph name="BEGIN_LINK" />aplikazio kaltegarriak aurkitu ditu<ph name="END_LINK" /> <ph name="SITE" /> webgunean.</translation>
<translation id="2355395290879513365">Baliteke erasotzaileak webgune honetan zer irudi ikusi dituzun hautemateko eta, haiek aldatuz, zu engainatzeko gai izatea.</translation>
@@ -467,6 +486,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="2413528052993050574">Zerbitzari honek ezin izan du egiaztatu <ph name="DOMAIN" /> domeinua denik. Bere segurtasun-ziurtagiria baliogabetuta egon liteke. Baliteke gaizki konfiguratuta dagoelako izatea edo erasotzaile batek zure konexioa atzeman duelako izatea.</translation>
<translation id="2414886740292270097">Iluna</translation>
<translation id="2430968933669123598">Google-ko kontua kudeatzeko botoia: sakatu "Sartu" Google-ko kontuko informazioa, pribatutasuna eta segurtasuna kudeatzeko</translation>
+<translation id="2436186046335138073"><ph name="PROTOCOL" /> esteka guztiak irekitzeko baimena eman nahi diozu <ph name="HANDLER_HOSTNAME" /> maneiatzaileari?</translation>
<translation id="2438874542388153331">Lau zulo eskuinean</translation>
<translation id="2450021089947420533">Bilaketa-ibilbideak</translation>
<translation id="2463739503403862330">Bete</translation>
@@ -474,6 +494,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="2465655957518002998">Aukeratu entrega-metodoa</translation>
<translation id="2465688316154986572">Grapatu</translation>
<translation id="2465914000209955735">Kudeatu Chrome-ren bidez deskargatu dituzun fitxategiak</translation>
+<translation id="2466004615675155314">Erakutsi saretik lortutako informazioa</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Sare-diagnostikoak exekutatzen<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">1etik N-rako ordena</translation>
<translation id="2470767536994572628">Oharpenak editatzen dituzunean, orri bakarreko ikuspegira eta jatorrizko biratzera itzuliko da dokumentua</translation>
@@ -494,6 +515,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="2523886232349826891">Gailu honetan soilik gordeko da</translation>
<translation id="2524461107774643265">Gehitu informazio gehiago</translation>
<translation id="2529899080962247600">Eremu honek ez lituzke <ph name="MAX_ITEMS_LIMIT" /> sarrera baino gehiago izan behar. Sarrera gehiagorik badago, ez ikusi egingo zaie.</translation>
+<translation id="2535585790302968248">Modu pribatuan arakatzeko, ireki ezkutuko moduko fitxa bat</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{eta beste bat}other{eta beste #}}</translation>
<translation id="2536110899380797252">Gehitu helbidea</translation>
<translation id="2539524384386349900">Hauteman</translation>
@@ -519,7 +541,14 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="2597378329261239068">Dokumentua pasahitzez babestuta dago. Idatzi pasahitza.</translation>
<translation id="2609632851001447353">Aldaerak</translation>
<translation id="2610561535971892504">Sakatu kopiatzeko</translation>
+<translation id="2617988307566202237">Chrome-k <ph name="BEGIN_EMPHASIS" />ez du gordeko<ph name="END_EMPHASIS" /> informazio hau:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />arakatze-historia
+ <ph name="LIST_ITEM" />cookieak eta webguneetako datuak
+ <ph name="LIST_ITEM" />inprimakietan idatzitako informazioa
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (gutun-azala)</translation>
+<translation id="2623663032199728144">Pantailei buruzko informazioa erabiltzea eska dezake</translation>
<translation id="2625385379895617796">Erlojua aurreratuta duzu</translation>
<translation id="262745152991669301">USB bidezko gailuetara konektatzea eska dezake</translation>
<translation id="2629325967560697240">Chrome-ren segurtasun-maila handiena lortzeko, <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />aktibatu babes hobetua<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -553,6 +582,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="2709516037105925701">Betetze automatikoa</translation>
<translation id="2713444072780614174">Zuria</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />: sakatu tabuladorea eta, ondoren, sakatu Sartu ordainketak eta kreditu-txartelaren informazioa kudeatzeko Chrome-ren ezarpenetan</translation>
+<translation id="271663710482723385">Pantaila osotik irteteko, sakatu |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />|</translation>
<translation id="2721148159707890343">Eskaera behar bezala egin da</translation>
<translation id="2723669454293168317">Egin segurtasun-egiaztapena Chrome-ren ezarpenetan</translation>
<translation id="2726001110728089263">Alboko erretilua</translation>
@@ -583,6 +613,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="2850739647070081192">Invite (gutun-azala)</translation>
<translation id="2856444702002559011">Baliteke erasotzaile batzuk <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> webgunean duzun informazioa lapurtzen saiatzen aritzea (adibidez, pasahitzak, mezuak edo kreditu-txartelen datuak). <ph name="BEGIN_LEARN_MORE_LINK" />Lortu informazio gehiago<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">Webgune honek iragarki oztopatzaile edo iruzurrezkoak erakusten ditu.</translation>
+<translation id="286512204874376891">Txartel birtualek benetako txartelak mozorrotzen dituzte, iruzurren aurka babestuago egon daitezen. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">Polita</translation>
<translation id="2876489322757410363">Ezkutuko modutik irtengo zara kanpoko aplikazio baten bidez ordaintzeko. Aurrera egin nahi duzu?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />, sakatu tabuladorea eta, ondoren, sakatu "Sartu" tekla Chrome-ren ezarpenetara joan, eta Arakatze segurua eta beste gauza batzuk kudeatzeko</translation>
@@ -607,6 +638,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="2930577230479659665">Moztu kopia bakoitzaren amaieran</translation>
<translation id="2932085390869194046">Iradoki pasahitza…</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019">Ireki <ph name="PROTOCOL" /> estekak</translation>
<translation id="2941952326391522266">Zerbitzari honek ezin izan du egiaztatu <ph name="DOMAIN" /> domeinua denik. Bere segurtasun-ziurtagiria <ph name="DOMAIN2" /> domeinukoa da. Baliteke gaizki konfiguratuta dagoelako izatea edo erasotzaile batek zure konexioa atzeman duelako izatea.</translation>
<translation id="2943895734390379394">Kargatze-ordua:</translation>
<translation id="2948083400971632585">Konexio jakin baterako konfiguratu den edozein proxy desgai dezakezu ezarpenen orrian.</translation>
@@ -633,12 +665,13 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="3013291976881901233">MIDI gailuak</translation>
<translation id="301521992641321250">Automatikoki blokeatuta</translation>
<translation id="3016780570757425217">Ezagutu zure kokapena</translation>
-<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />: sakatu tabuladorea eta Sartu tekla iradokizuna kentzeko.</translation>
+<translation id="3017086357773116182"><ph name="REMOVE_SUGGESTION_SUFFIX" />: sakatu tabuladorea eta "Sartu" tekla iradokizuna kentzeko.</translation>
<translation id="3023071826883856138">You4 (gutun-azala)</translation>
<translation id="3024663005179499861">Gidalerro mota okerra</translation>
<translation id="3037605927509011580">Hutsegite bat izan da.</translation>
<translation id="3041612393474885105">Ziurtagiriari buruzko informazioa</translation>
<translation id="3044034790304486808">Berrekin ikerketari</translation>
+<translation id="305162504811187366">Chrome-ren Urruneko pantaila aplikazioko historia, denbora-zigiluak, ostalariak eta bezero-saioen IDak barne</translation>
<translation id="3060227939791841287">C9 (gutun-azala)</translation>
<translation id="3061707000357573562">Adabaki-zerbitzua</translation>
<translation id="306573536155379004">Hasi da jokoa.</translation>
@@ -676,6 +709,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="3197136577151645743">Gailu hau noiz erabiltzen ari zaren jakitea eska dezake</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />, sakatu tabuladorea eta, ondoren, sakatu Sartu Chrome-ren ezarpenetara joan, eta sinkronizatzen den informazioa kudeatzeko</translation>
<translation id="320323717674993345">Utzi bertan behera ordainketa</translation>
+<translation id="3203366800380907218">Saretik</translation>
<translation id="3207960819495026254">Laster-marka gisa gordea</translation>
<translation id="3209034400446768650">Baliteke orriak dirua kobratzea</translation>
<translation id="3212581601480735796"><ph name="HOSTNAME" /> webgunean egiten ari zarena gainbegiratzen ari dira</translation>
@@ -692,10 +726,12 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="3234666976984236645">Hauteman beti webgune honetako eduki garrantzitsua</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />: sakatu tabuladorea eta, ondoren, sakatu "Sartu" tekla arakatzailearen itxura pertsonalizatzeko</translation>
<translation id="3240791268468473923">Ordainketak egiteko kredentzial segurua bat ez datorrela dioen kredentzial-orria irekita dago</translation>
+<translation id="324180406144491771"><ph name="HOST_NAME" /> motako estekak blokeatuta daude</translation>
<translation id="3249845759089040423">Modakoa</translation>
<translation id="3252266817569339921">Frantsesa</translation>
<translation id="3257954757204451555">Nor dago informazio horren atzean?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />: sakatu tabuladorea eta, ondoren, "Sartu", Google Calendar-en gertaera bat bizkor sortzeko</translation>
+<translation id="3261488570342242926">Lortu txartel birtualei buruzko informazio gehiago</translation>
<translation id="3264837738038045344">Chrome-ren ezarpenak kudeatzeko botoia: sakatu "Sartu" Chrome-ren ezarpenetara joateko</translation>
<translation id="3266793032086590337">Balioa (gatazka)</translation>
<translation id="3268451620468152448">Ireki fitxak</translation>
@@ -709,6 +745,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="3288238092761586174">Baliteke <ph name="URL" /> ostalariak beste urrats batzuk egin behar izatea ordainketa egiaztatzeko</translation>
<translation id="3293642807462928945">Lortu informazio gehiago <ph name="POLICY_NAME" /> gidalerroari buruz</translation>
<translation id="3295444047715739395">Ikusi eta kudeatu pasahitzak Chrome-ren ezarpenetan</translation>
+<translation id="3303795387212510132"><ph name="PROTOCOL_SCHEME" /> estekak irekitzeko baimena eman nahi diozu aplikazioari?</translation>
<translation id="3303855915957856445">Ez da aurkitu bilaketa-emaitzarik</translation>
<translation id="3304073249511302126">Bluetooth bidezko gailuen bilaketa</translation>
<translation id="3308006649705061278">Erakundeko unitatea</translation>
@@ -722,12 +759,6 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="3345782426586609320">Begiak</translation>
<translation id="3355823806454867987">Aldatu proxy-ezarpenak…</translation>
<translation id="3360103848165129075">Ordainketa kudeatzeko orria</translation>
-<translation id="3361596688432910856">Chrome-k <ph name="BEGIN_EMPHASIS" />ez du gordeko<ph name="END_EMPHASIS" /> informazio hau:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />arakatze-historia,
- <ph name="LIST_ITEM" />cookieak eta webguneetako datuak,
- <ph name="LIST_ITEM" />inprimakietan idatzitako datuak.
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467"><ph name="OLD_POLICY" /> gidalerro zaharkituaren kopia automatikoa da gidalerro hau. Horren ordez gidalerro hau erabili beharko zenuke.</translation>
<translation id="3364869320075768271"><ph name="URL" /> webguneak errealitate birtualeko gailua eta datuak erabili nahi ditu</translation>
<translation id="3366477098757335611">Ikusi txartelak</translation>
@@ -809,7 +840,6 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="3587738293690942763">Erdia</translation>
<translation id="3592413004129370115">Italian (gutun-azala)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{Edozein unetan berrezar dezakezu taldea. Gutxi gorabehera egun bat behar da beste talde batean sartzeko.}=1{Edozein unetan berrezar dezakezu taldea. Gutxi gorabehera egun bat behar da beste talde batean sartzeko.}other{Edozein unetan berrezar dezakezu taldea. Gutxi gorabehera {NUM_DAYS} egun behar dira beste talde batean sartzeko.}}</translation>
-<translation id="3596012367874587041">Aplikazioen ezarpenak</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" /> (<ph name="TIME" />)</translation>
<translation id="3603507503523709">Administratzaileak aplikazioa blokeatu du</translation>
<translation id="3608932978122581043">Papera sartzeko orientazioa</translation>
@@ -852,6 +882,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="370972442370243704">Aktibatu bilaketa-ibilbideak</translation>
<translation id="3711895659073496551">Ezarri inaktibo gisa</translation>
<translation id="3712624925041724820">Lizentziak agortu dira</translation>
+<translation id="3714633008798122362">web-egutegia</translation>
<translation id="3714780639079136834">Datu-konexioa edo Wi-Fi konexioa gaitu.</translation>
<translation id="3715597595485130451">Konektatu wifi-sarera</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Proxya, suebakia eta DNS konfigurazioa egiaztatu<ph name="END_LINK" />.</translation>
@@ -913,6 +944,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="3906954721959377182">Tableta</translation>
<translation id="3909477809443608991"><ph name="URL" /> webguneak eduki babestua erreproduzitu nahi du. Gailuaren identitatea egiaztatuko du Google-k eta baliteke webgune honek atzitzea.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">Ukatu</translation>
<translation id="3939773374150895049">WebAuthn erabili nahi duzu CVC kodearen ordez?</translation>
<translation id="3946209740501886391">Galdetu beti gune honetan</translation>
<translation id="3947595700203588284">MIDI gailuetara konektatzea eska dezake</translation>
@@ -933,6 +965,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="3987940399970879459">1 MB baino gutxiago</translation>
<translation id="3990250421422698716">Tolestura-marjina</translation>
<translation id="3996311196211510766"><ph name="ORIGIN" /> webguneak hartarako eskaera guztiei jatorri-gidalerro bat aplikatzeko eskatu du, baina ezin da aplikatu gidalerroa une honetan.</translation>
+<translation id="4009243425692662128">Inprimatzen dituzun orrietako edukia Google Cloud-i edo hirugarrenei bidaltzen zaie eduki hori azter dezaten; adibidez, baliteke orrian kontuzko daturik dagoen bilatzea.</translation>
<translation id="4010758435855888356">Biltegia atzitzeko baimena eman nahi diozu?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{{COUNT} orri daukan PDF dokumentua}other{{COUNT} orri dauzkan PDF dokumentua}}</translation>
<translation id="4023431997072828269">Inprimakia segurua ez den konexio baten bidez bidaliko denez, gainerako erabiltzaileek zure informazioa ikusi ahalko dute.</translation>
@@ -949,7 +982,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="4075941231477579656">Touch ID</translation>
<translation id="4079302484614802869">Proxy-konfigurazioa .pac scripteko URLa erabiltzeko dago ezarrita, ez proxy-zerbitzari finkoak.</translation>
<translation id="4082393374666368382">Ezarpenak - Kudeaketa</translation>
-<translation id="4084120443451129199">Bilaketa moduan zaudela, sakatu Sartu tekla "<ph name="KEYWORD_SUFFIX" />" bilatzeko</translation>
+<translation id="4084120443451129199">Bilaketa moduan zaudela, sakatu "Sartu" tekla "<ph name="KEYWORD_SUFFIX" />" bilatzeko</translation>
<translation id="4087296516249690906">Gertaera bat sortzeko botoia: sakatu "Sartu", Google Calendar-en gertaera bat bizkor sortzeko</translation>
<translation id="4088981014127559358">1. aldeko irudia Y ardatzaren arabera aldatuta</translation>
<translation id="4089152113577680600">14. erretilua</translation>
@@ -1023,6 +1056,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="4250680216510889253">Ez</translation>
<translation id="4253168017788158739">Oharra</translation>
<translation id="425582637250725228">Baliteke egindako aldaketak ez gordetzea.</translation>
+<translation id="425869179292622354">Seguruago bihurtu nahi duzu txartel birtual baten bidez?</translation>
<translation id="4258748452823770588">Sinadurak ez du balio</translation>
<translation id="4261046003697461417">Babestutako dokumentuetan ezin da oharpenik egin</translation>
<translation id="4265872034478892965">Administratzaileak baimendu du</translation>
@@ -1085,6 +1119,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="4434045419905280838">Leiho gainerak. / Birbideratzeak</translation>
<translation id="4435702339979719576">Postcard)</translation>
<translation id="443673843213245140">Proxya erabiltzeko aukera desgaitu da, baina proxy-konfigurazio esplizitua zehaztu da.</translation>
+<translation id="4441832193888514600">Ez ikusi egin zaio hodeiko erabiltzaile-gidalerro gisa soilik ezar daitekeelako gidalerroa.</translation>
<translation id="4450893287417543264">Ez erakutsi berriro</translation>
<translation id="4451135742916150903">HID gailuetara konektatzea eska dezake</translation>
<translation id="4452328064229197696">Erabili berri duzun pasahitza datuen isilpekotasunaren urratze batean aurkitu da. Kontuak babesteko, Google-ren Pasahitz-kudeatzailea eginbideak gordeta dauzkazun pasahitzak seguruak direla egiaztatzea gomendatzen du.</translation>
@@ -1140,6 +1175,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="4628948037717959914">Argazkia</translation>
<translation id="4631649115723685955">Dirua berreskuratzeko aukerarekin</translation>
<translation id="4636930964841734540">Informazioa</translation>
+<translation id="4638670630777875591">Chromium-eko ezkutuko modua</translation>
<translation id="464342062220857295">Bilaketa-eginbideak</translation>
<translation id="4644670975240021822">Alderantzizko ordenan, ahuspez</translation>
<translation id="4646534391647090355">Eraman nazazu hara</translation>
@@ -1160,6 +1196,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="4708268264240856090">Eten egin da konexioa</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Windows-en sare-diagnostikoak exekutatzen<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426"><ph name="USERNAME" /> kontuko pasahitza</translation>
<translation id="4724144314178270921">Arbeleko testua eta irudiak ikustea eska dezake</translation>
<translation id="4726672564094551039">Kargatu berriro gidalerroak</translation>
<translation id="4728558894243024398">Plataforma</translation>
@@ -1181,6 +1218,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="4757993714154412917">Webgune engainagarri batean idatzi duzu pasahitza. Kontuak babesteko, gordetako pasahitzei begiratu bat ematea gomendatzen du Chromium-ek.</translation>
<translation id="4758311279753947758">Gehitu harremanetarako informazioa</translation>
<translation id="4761104368405085019">Erabili mikrofonoa</translation>
+<translation id="4761869838909035636">Egin Chrome-ren segurtasun-egiaztapena</translation>
<translation id="4764776831041365478">Baliteke <ph name="URL" /> helbideko web-orria tarte batez ez funtzionatzea edo beste web-helbide batera betiko aldatu izatea.</translation>
<translation id="4766713847338118463">Bi grapa behean</translation>
<translation id="4771973620359291008">Errore ezezagun bat gertatu da.</translation>
@@ -1201,12 +1239,6 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="4819347708020428563">Ikuspegi lehenetsian editatu nahi dituzu oharpenak?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />: sakatu tabuladorea eta, ondoren, "Sartu" Google-ko kalkulu-orri bat bizkor sortzeko</translation>
<translation id="4825507807291741242">Indartsua</translation>
-<translation id="4827402517081186284">Ezkutuko modua erabili arren, ez zara ikusezina izango sarean:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Webguneek noiz bisitatzen dituzun dakite.<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Enpresek edo ikastetxeek arakatze-jardueren jarraipena egin dezakete.<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Baliteke Interneteko zerbitzu-hornitzaileek sareko trafikoa gainbegiratzea.<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">Aktibatu abisuak</translation>
<translation id="4838327282952368871">Ametsezkoa</translation>
<translation id="4840250757394056958">Ikusi Chrome-ko historia</translation>
@@ -1218,12 +1250,12 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="4854362297993841467">Ez dago erabilgarri entrega-metodo hori. Saiatu beste metodo batekin.</translation>
<translation id="4854853140771946034">Sortu bizkor ohar bat Google Keep-en</translation>
<translation id="485902285759009870">Kodea egiaztatzen…</translation>
+<translation id="4866506163384898554">Kurtsorea ikusteko, sakatu |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />|</translation>
<translation id="4876188919622883022">Ikuspegi sinplifikatua</translation>
<translation id="4876305945144899064">Ez dago erabiltzaile-izenik</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{Bat ere ez}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831">Bilatu <ph name="TEXT" /></translation>
<translation id="4879491255372875719">Automatikoa (lehenetsia)</translation>
-<translation id="4879725228911483934">Leihoak ireki eta pantailetan kokatu.</translation>
<translation id="4880827082731008257">Bilatu historian</translation>
<translation id="4881695831933465202">Ireki</translation>
<translation id="4885256590493466218">Ordaintzerakoan, erabili <ph name="CARD_DETAIL" /> txartela</translation>
@@ -1232,6 +1264,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">Bederatzigarren arrabola</translation>
<translation id="4901778704868714008">Gorde…</translation>
+<translation id="4905659621780993806">Egun honetan, administratzaileak automatikoki berrabiaraziko du gailua: <ph name="DATE" /> (<ph name="TIME" />). Gorde irekita dauzkazun elementuak gailua berrabiarazi aurretik.</translation>
<translation id="4913987521957242411">Zulo bat goian, ezkerretara</translation>
<translation id="4918221908152712722">Instalatu <ph name="APP_NAME" /> (ez da deskargatu behar)</translation>
<translation id="4923459931733593730">Ordainketa</translation>
@@ -1240,6 +1273,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />: sakatu tabuladorea eta, ondoren, sakatu Sartu bilaketa egiteko</translation>
<translation id="4930153903256238152">Edukiera handia</translation>
+<translation id="4940163644868678279">Chrome-ko ezkutuko modua</translation>
<translation id="4943872375798546930">Ez dago emaitzarik</translation>
<translation id="4950898438188848926">Fitxa aldatzeko botoia. Ireki duzun fitxara (<ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" />) joateko, sakatu Sartu.</translation>
<translation id="495170559598752135">Ekintzak</translation>
@@ -1249,6 +1283,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="4968522289500246572">Mugikorretan erabiltzeko dago diseinatuta aplikazioa, eta agian ez da behar bezala aldatuko tamaina. Litekeena da aplikazioak arazoak izatea edo berrabiaraztea.</translation>
<translation id="4969341057194253438">Ezabatu grabaketa</translation>
<translation id="4973922308112707173">Bi zulo goian</translation>
+<translation id="4976702386844183910">Azken bisita: <ph name="DATE" /></translation>
<translation id="4984088539114770594">Mikrofonoa erabili nahi duzu?</translation>
<translation id="4984339528288761049">Prc5 (gutun-azala)</translation>
<translation id="4989163558385430922">Ikusi guztiak</translation>
@@ -1310,6 +1345,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="5138227688689900538">Erakutsi gutxiago</translation>
<translation id="5145883236150621069">Errore-kode gidalerroaren erantzunean dago</translation>
<translation id="5146995429444047494"><ph name="ORIGIN" /> webgunearen jakinarazpenak blokeatu egin dira</translation>
+<translation id="514704532284964975"><ph name="URL" /> webguneak informazioa ikusi eta aldatu nahi du NFC darabilten gailuetan baldin eta telefonoa gerturatzen badiezu</translation>
<translation id="5148809049217731050">Ahoz gora</translation>
<translation id="515292512908731282">C4 (gutun-azala)</translation>
<translation id="5158275234811857234">Azala</translation>
@@ -1334,6 +1370,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="5215116848420601511">Google Pay-rekin erabiltzen dituzun ordainketa-metodoak eta helbideak</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">13. erretilua</translation>
+<translation id="5216942107514965959">Gaur bisitatu duzu azkenengoz</translation>
<translation id="5222812217790122047">Nahitaez zehaztu behar duzu helbide elektronikoa</translation>
<translation id="5230733896359313003">Bidalketa-helbidea</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1354,7 +1391,6 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">Dokumentuaren propietateak</translation>
<translation id="528468243742722775">Amaitu</translation>
-<translation id="5284909709419567258">Sareko helbideak</translation>
<translation id="5285570108065881030">Erakutsi gordetako pasahitz guztiak</translation>
<translation id="5287240709317226393">Erakutsi cookieak</translation>
<translation id="5287456746628258573">Webgune honek segurtasun-konfigurazio zaharkitu bat erabiltzen du; ondorioz, baliteke zure informazioa (adibidez, pasahitzak edo kreditu-txartelen zenbakiak) agerian uztea webgune honetara bidaltzen duzunean.</translation>
@@ -1438,6 +1474,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="5556459405103347317">Kargatu berriro</translation>
<translation id="5560088892362098740">Iraungitze-data</translation>
<translation id="55635442646131152">Dokumentuaren eskema</translation>
+<translation id="5565613213060953222">Ireki ezkutuko moduko fitxa bat</translation>
<translation id="5565735124758917034">Aktibo</translation>
<translation id="5570825185877910964">Babestu kontua</translation>
<translation id="5571083550517324815">Ezin da jaso helbide horretan. Hautatu beste helbide bat.</translation>
@@ -1520,6 +1557,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="5869522115854928033">Gordetako pasahitzak</translation>
<translation id="5873013647450402046">Bankuak zeu zarela berretsi nahi du.</translation>
<translation id="5887400589839399685">Gorde da txartela</translation>
+<translation id="5887687176710214216">Atzo bisitatu zenuen azkenengoz</translation>
<translation id="5895138241574237353">Berrabiarazi</translation>
<translation id="5895187275912066135">Jaulkitze-data</translation>
<translation id="5901630391730855834">Horia</translation>
@@ -1533,6 +1571,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="5921639886840618607">Google-ko kontuan gorde nahi duzu txartela?</translation>
<translation id="5922853866070715753">Ia amaitu da</translation>
<translation id="5932224571077948991">Webguneak iragarki oztopatzaile edo iruzurrezkoak erakusten ditu</translation>
+<translation id="5938153366081463283">Gehitu txartel birtual bat</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347"><ph name="SITE_NAME" /> irekitzen…</translation>
<translation id="5951495562196540101">Ezin da kontsumitzaile-kontuarekin erregistratu (paketatutako lizentzia eskuragarri).</translation>
@@ -1597,6 +1636,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="6120179357481664955">Gogoan al duzu UPIko IDa?</translation>
<translation id="6124432979022149706">Chrome Enterprise Connectors</translation>
<translation id="6127379762771434464">Kendu egin da elementua</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Lortu Chrome-ko ezkutuko moduari buruzko informazio gehiago<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">Egiaztatu kableak konektatuta daudela eta berrabiarazi erabiltzen ari zaren bideratzaile, modem eta sare-gailu oro.</translation>
<translation id="614940544461990577">Konpontzeko, hauek egin ditzakezu:</translation>
<translation id="6150036310511284407">Hiru zulo ezkerrean</translation>
@@ -1608,7 +1648,6 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="6169916984152623906">Modu pribatuan arakatu ahal izango duzu sarea, gailua erabiltzen duten gainerakoek zure jardueren berririk izan ez dezaten. Hala ere, deskargak eta laster-markak gordeta geratuko dira.</translation>
<translation id="6177128806592000436">Webgune honetarako konexioa ez da guztiz segurua</translation>
<translation id="6180316780098470077">Saiakeren arteko tartea</translation>
-<translation id="619448280891863779">Pantailetan leihoak ireki eta kokatzea eska dezake</translation>
<translation id="6196640612572343990">Blokeatu hirugarrenen cookieak</translation>
<translation id="6203231073485539293">Egiaztatu Internetera konektatuta zaudela</translation>
<translation id="6218753634732582820">Helbidea Chromium-etik kendu nahi duzu?</translation>
@@ -1631,7 +1670,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="6272383483618007430">Google-ren eguneratzea</translation>
<translation id="6276112860590028508">Hemen agertuko dira irakurketa-zerrendako orriak</translation>
<translation id="627746635834430766">Hurrengoan bizkorrago ordaintzeko, gorde txartela eta fakturazio-helbidea Google-ko kontuan.</translation>
-<translation id="6279098320682980337">Txartel birtualaren zenbakia ez dago beteta? Sakatu txartelaren xehetasunak, haiek kopiatzeko.</translation>
+<translation id="6279183038361895380">Kurtsorea ikusteko, sakatu |<ph name="ACCELERATOR" />|</translation>
<translation id="6280223929691119688">Ezin da entregatu helbide horretan. Hautatu beste helbide bat.</translation>
<translation id="6282194474023008486">Posta-kodea</translation>
<translation id="6285507000506177184">Chrome-ren bidez egindako deskargak kudeatzeko botoia: sakatu "Sartu" tekla Chrome-ren bidez deskargatu dituzun fitxategiak kudeatzeko</translation>
@@ -1639,6 +1678,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="6290238015253830360">Iradokitako artikuluak agertuko zaizkizu hemen</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{Orain berrabiaraziko da gailua}=1{1 segundo barru berrabiaraziko da gailua}other{# segundo barru berrabiaraziko da gailua}}</translation>
<translation id="6302269476990306341">Chrome-rako Google-ren Laguntzailea gelditzen</translation>
<translation id="6305205051461490394">Ezin da konektatu <ph name="URL" /> webgunera.</translation>
<translation id="6312113039770857350">Ez dago erabilgarri web-orria</translation>
@@ -1712,6 +1752,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="6529602333819889595">&amp;Berregin ezabatzea</translation>
<translation id="6545864417968258051">Bluetooth bidezko gailuen bilaketa</translation>
<translation id="6547208576736763147">Bi zulo ezkerrean</translation>
+<translation id="6554732001434021288">Duela <ph name="NUM_DAYS" /> egun bisitatu zenuen azkenengoz</translation>
<translation id="6556866813142980365">Berregin</translation>
<translation id="6569060085658103619">Luzapen baten orria ari zara ikusten</translation>
<translation id="6573200754375280815">Bi zulo eskuinean</translation>
@@ -1752,7 +1793,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="6688775486821967877">Txartel birtuala ez dago erabilgarri une honetan. Saiatu berriro geroago.</translation>
<translation id="6689249931105087298">Erlatiboa, puntu beltzen konprimaketarekin</translation>
<translation id="6689271823431384964">Saioa hasita duzunez, txartelak Google-ko kontuan gordetzeko aukera ematen dizu Chrome-k. Aukera hori aldatzeko, joan Ezarpenak atalera. Txartelaren titularraren izena kontutik hartu da.</translation>
-<translation id="6694681292321232194"><ph name="FIND_MY_PHONE_FOCUSED_FRIENDLY_MATCH_TEXT" />: sakatu tabuladorea eta, ondoren, sakatu Sartu tekla zure gailua Google-ko kontuan bilatzeko</translation>
+<translation id="6694681292321232194"><ph name="FIND_MY_PHONE_FOCUSED_FRIENDLY_MATCH_TEXT" />: sakatu tabuladorea eta, ondoren, sakatu "Sartu" tekla zure gailua Google-ko kontuan bilatzeko</translation>
<translation id="6696588630955820014">Fitxa partekatzeko botoia: sakatu "Sartu" tekla fitxa partekatzeko. Modu askotara partekatu ahal izango duzu: esteka partekatuta, QR kode bat sortuta, fitxa igorrita, etab.</translation>
<translation id="6698381487523150993">Sortze-data:</translation>
<translation id="6702919718839027939">Aurkeztu</translation>
@@ -1772,7 +1813,6 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="6757797048963528358">Inaktibo geratu da gailua.</translation>
<translation id="6767985426384634228">Helbidea eguneratu nahi duzu?</translation>
<translation id="6768213884286397650">Hagaki (postala)</translation>
-<translation id="6774185088257932239"><ph name="BEGIN_LINK" />Lortu informazio gehiago<ph name="END_LINK" /> ezkutuko moduari buruz</translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">Bioleta</translation>
<translation id="6786747875388722282">Luzapenak</translation>
@@ -1847,7 +1887,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="7029809446516969842">Pasahitzak</translation>
<translation id="7030436163253143341">Ziurtagiriak ez du balio</translation>
<translation id="7031646650991750659">Instalatuta dauzkazun Google Play-ko aplikazioak.</translation>
-<translation id="7038063300915481831"><ph name="MANAGE_GOOGLE_PRIVACY_FOCUSED_FRIENDLY_MATCH_TEXT" />: sakatu tabuladorea eta, ondoren, sakatu Sartu tekla Google-ko kontuaren pribatutasun-ezarpenak kudeatzeko.</translation>
+<translation id="7038063300915481831"><ph name="MANAGE_GOOGLE_PRIVACY_FOCUSED_FRIENDLY_MATCH_TEXT" />: sakatu tabuladorea eta, ondoren, sakatu "Sartu" tekla Google-ko kontuaren pribatutasun-ezarpenak kudeatzeko.</translation>
<translation id="7050187094878475250"><ph name="DOMAIN" /> atzitzen saiatu zara, baina zerbitzariak balio-epe luzeegia duen ziurtagiri bat aurkeztu du eta ez da fidagarria.</translation>
<translation id="705310974202322020">{NUM_CARDS,plural, =1{Ezin da gorde txartela une honetan}other{Ezin dira gorde txartelak une honetan}}</translation>
<translation id="7053983685419859001">Blokeatu</translation>
@@ -1856,7 +1896,6 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="706295145388601875">Gehitu eta kudeatu helbideak Chrome-ren ezarpenetan</translation>
<translation id="7064851114919012435">Harremanetarako informazioa</translation>
<translation id="7068733155164172741">Idatzi <ph name="OTP_LENGTH" /> digituko kodea</translation>
-<translation id="7070090581017165256">Webgune honi buruz</translation>
<translation id="70705239631109039">Konexioa ez da guztiz segurua</translation>
<translation id="7075452647191940183">Eskaera handiegia da</translation>
<translation id="7079718277001814089">Webguneak malwarea dauka</translation>
@@ -1873,6 +1912,12 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="7111012039238467737">(balio du)</translation>
<translation id="7118618213916969306">Bilatu arbeleko URLa (<ph name="SHORT_URL" />)</translation>
<translation id="7119414471315195487">Itxi beste fitxa edo programa batzuk</translation>
+<translation id="7129355289156517987">Chromium-eko ezkutuko moduko fitxa guztiak ixten dituzunean, fitxa horietan egindako jarduerak gailutik ezabatuko dira:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />arakatze-jarduerak<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />bilaketa-historia<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />inprimakietan idatzitako informazioa<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">Ezin da entregatu helbide horretan. Hautatu beste helbide bat.</translation>
<translation id="7132939140423847331">Administratzaileak debekatu egin du datu hauek kopiatzea.</translation>
<translation id="7135130955892390533">Erakutsi egoera</translation>
@@ -1895,6 +1940,7 @@ Bestela, pribatutasun-ezarpenek blokeatu egingo dute baimen hori. Baimen honekin
<translation id="7192203810768312527"><ph name="SIZE" /> uzten ditu libre. Webgune batzuk mantsoago kargatuko dira bisitatzen dituzun hurrengoan.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">Administratzaileak hauek ikus ditzake:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />: sakatu tabuladorea eta, ondoren, sakatu "Sartu" ezkutuko moduko fitxa bat irekitzeko modu pribatuan arakatze aldera</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> webguneak ez ditu gordetzen segurtasun-arauak.</translation>
<translation id="7210993021468939304">Linux-en jarduera edukiontziaren barruan. Gainera, Linux-en aplikazioak instalatu eta abiaraz ditzakete edukiontziaren barruan.</translation>
@@ -1920,12 +1966,13 @@ Xehetasun gehiago:
<translation id="7275334191706090484">Kudeatutako laster-markak</translation>
<translation id="7285654172857511148"><ph name="CHANGE_GOOGLE_PASSWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />: sakatu tabuladorea eta, ondoren, "Sartu" Google-ko kontuko pasahitza aldatzeko</translation>
<translation id="7292031607255951991">Hartzailearen izena</translation>
-<translation id="7298195798382681320">Gomendatuak</translation>
+<translation id="7298195798382681320">Gomendatua</translation>
<translation id="7300012071106347854">Kobaltoa</translation>
<translation id="7304030187361489308">Altua</translation>
<translation id="7304562222803846232">Kudeatu Google-ko kontuaren pribatutasun-ezarpenak</translation>
<translation id="7305756307268530424">Hasi motelago</translation>
<translation id="7308436126008021607">atzeko planoko sinkronizazioa</translation>
+<translation id="7310392214323165548">Gailua laster berrabiaraziko da</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">Konexioari buruzko laguntza</translation>
<translation id="7323804146520582233">Ezkutatu "<ph name="SECTION" />" atala</translation>
@@ -1933,6 +1980,7 @@ Xehetasun gehiago:
<translation id="7334320624316649418">&amp;Berregin berrantolatzea</translation>
<translation id="7335157162773372339">Kamera erabiltzea eska dezake</translation>
<translation id="7337248890521463931">Erakutsi lerro gehiago</translation>
+<translation id="7337418456231055214">Txartel birtualaren zenbakia ez dago beteta? Txartelaren xehetasunak kopiatu nahi badituzu, saka itzazu. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">Ez dago erabilgarri darabilzun plataforman.</translation>
<translation id="733923710415886693">Zerbitzariaren ziurtagiria ez da ezagutarazi ziurtagirien gardentasun-gidalerroa erabilita.</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1955,6 +2003,7 @@ Xehetasun gehiago:
<translation id="7378627244592794276">Ez</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">Ez aplikagarria</translation>
+<translation id="7388594495505979117">{0,plural, =1{1 minutu barru berrabiaraziko da gailua}other{# minutu barru berrabiaraziko da gailua}}</translation>
<translation id="7390545607259442187">Berretsi txartela</translation>
<translation id="7392089738299859607">Eguneratu helbidea</translation>
<translation id="7399802613464275309">Segurtasun-egiaztapena</translation>
@@ -1991,6 +2040,12 @@ Xehetasun gehiago:
<translation id="7485870689360869515">Ez da daturik aurkitu</translation>
<translation id="7495528107193238112">Eduki hori blokeatuta dago. Jarri harremanetan webgunearen arduradunarekin arazoa konpontzeko.</translation>
<translation id="7497998058912824456">Dokumentu bat sortzeko botoia: sakatu "Sartu" Google-ko dokumentu bat bizkor sortzeko</translation>
+<translation id="7506488012654002225">Chromium-ek <ph name="BEGIN_EMPHASIS" />ez du gordeko<ph name="END_EMPHASIS" /> informazio hau:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />arakatze-historia
+ <ph name="LIST_ITEM" />cookieak eta webguneetako datuak
+ <ph name="LIST_ITEM" />inprimakietan idatzitako informazioa
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">Itzuli den gidalerroaren gailu IDa hutsik dago edo ez dator bat gailuaren IDarekin</translation>
<translation id="7508870219247277067">Ahuakatea</translation>
<translation id="7511955381719512146">Baliteke darabilzun Wi-Fi konexioaren <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> orrira joan behar izatea.</translation>
@@ -2104,7 +2159,6 @@ Xehetasun gehiago:
<translation id="7813600968533626083">Inprimaki-iradokizuna Chrome-tik kendu nahi duzu?</translation>
<translation id="781440967107097262">Arbela partekatu nahi duzu?</translation>
<translation id="7815407501681723534">"<ph name="SEARCH_STRING" />" bilaketaren <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> aurkitu dira.</translation>
-<translation id="782125616001965242">Erakutsi webgune honi buruzko informazioa</translation>
<translation id="782886543891417279">Baliteke darabilzun Wi-Fi konexioaren (<ph name="WIFI_NAME" />) saio-hasierako orrira joan behar izatea.</translation>
<translation id="7836231406687464395">Postfix (gutun-azala)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{Bat ere ez}=1{1 aplikazio (<ph name="EXAMPLE_APP_1" />)}=2{2 aplikazio (<ph name="EXAMPLE_APP_1" /> eta <ph name="EXAMPLE_APP_2" />)}other{# aplikazio (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" /> eta<ph name="AND_MORE" />)}}</translation>
@@ -2121,7 +2175,6 @@ Xehetasun gehiago:
<translation id="7888575728750733395">Inprimatzeko errendatzearen helburua</translation>
<translation id="7894280532028510793">Behar bezala idatzita badago, <ph name="BEGIN_LINK" />exekutatu sare-diagnostikoak<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (gutun-azala)</translation>
-<translation id="7931318309563332511">Ezezaguna</translation>
<translation id="793209273132572360">Helbidea eguneratu nahi duzu?</translation>
<translation id="7932579305932748336">Forratu</translation>
<translation id="79338296614623784">Idatzi balio duen telefono-zenbaki bat</translation>
@@ -2146,13 +2199,14 @@ Xehetasun gehiago:
<translation id="7976214039405368314">Eskaera gehiegi daude</translation>
<translation id="7977538094055660992">Irteera-gailua</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">Honekin lotuta:</translation>
<translation id="798134797138789862">Errealitate birtualeko gailuak eta datuak erabiltzea eska dezake</translation>
<translation id="7984945080620862648">Une honetan ezin duzu <ph name="SITE" /> bisitatu, webguneak Chrome-k prozesatu ezin dituen kredentzial nahasiak bidali baititu. Sareko erroreak eta erasoak aldi baterako izan ohi dira eta, beraz, segur aski orriak geroago funtzionatuko du.</translation>
-<translation id="79859296434321399">Errealitate areagotuko edukia ikusteko, instalatu ARCore</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" />, <ph name="TIME" />, <ph name="BOOKMARKED" />, <ph name="TITLE" />, <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">Koadernatu</translation>
<translation id="7992044431894087211">Berrekin zaio <ph name="APPLICATION_TITLE" /> bidez pantaila partekatzeari</translation>
<translation id="7995512525968007366">Ez da zehaztu</translation>
+<translation id="7998269595945679889">"Ireki ezkutuko moduko fitxa bat" botoia: sakatu "Sartu" ezkutuko moduko fitxa bat irekitzeko modu pribatuan arakatze aldera</translation>
<translation id="800218591365569300">Saiatu beste fitxa edo programa batzuk ixten memoria gehiago uzteko erabilgarri.</translation>
<translation id="8004582292198964060">Arakatzailea</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{Txartel hau eta haren fakturazio-helbidea gordeko dira. <ph name="USER_EMAIL" /> kontuan saioa hasita duzunean erabili ahalko dituzu.}other{Txartel hauek eta haien fakturazio-helbideak gordeko dira. <ph name="USER_EMAIL" /> kontuan saioa hasita duzunean erabili ahalko dituzu.}}</translation>
@@ -2212,6 +2266,7 @@ Xehetasun gehiago:
<translation id="8202370299023114387">Gatazka</translation>
<translation id="8206978196348664717">Prc4 (gutun-azala)</translation>
<translation id="8211406090763984747">Konexioa segurua da</translation>
+<translation id="8217240300496046857">Webguneek ezin dituzte erabili sarean jarraipena egiten dizuten cookieak. Baliteke webgune batzuetako eginbideek ez funtzionatzea.</translation>
<translation id="8218327578424803826">Esleitutako kokapena</translation>
<translation id="8220146938470311105">C7/C6 (gutun-azala)</translation>
<translation id="8225771182978767009">Ordenagailua konfiguratu duen pertsonak webgune hau blokeatzea aukeratu du.</translation>
@@ -2252,14 +2307,9 @@ Xehetasun gehiago:
<translation id="830498451218851433">Erdibitzeko tolestura</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">Instalatuta dauden aplikazioak eta zer maiztasunekin erabiltzen diren</translation>
+<translation id="8317207217658302555">ARCore eguneratu nahi duzu?</translation>
<translation id="831997045666694187">Arratsaldea</translation>
<translation id="8321476692217554900">jakinarazpenak</translation>
-<translation id="8328484624016508118">Ezkutuko moduko fitxa guztiak itxi ondoren, Chrome-k hauek garbitzen ditu:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />gailu honetako arakatze-jarduerak<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />gailu honetako bilaketa-historia<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />inprimakietan idatzitako informazioa<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489">Ukatu egin da <ph name="HOST_NAME" /> webgunerako sarbidea</translation>
<translation id="833262891116910667">Nabarmenduta</translation>
<translation id="8339163506404995330">Ez dira itzuliko <ph name="LANGUAGE" /> darabilten orriak</translation>
@@ -2311,6 +2361,7 @@ Xehetasun gehiago:
<translation id="8507227106804027148">Agindu-lerroa</translation>
<translation id="8508648098325802031">Bilaketa-ikonoa</translation>
<translation id="8511402995811232419">Kudeatu cookieak</translation>
+<translation id="8519753333133776369">Administratzaileak onartutako HID gailua</translation>
<translation id="8522552481199248698">Google-ko kontua babesten eta pasahitza aldatzen lagun diezazuke Chrome-k.</translation>
<translation id="8530813470445476232">Garbitu arakatze-historia, cookieak, cachea eta beste Chrome-ren ezarpenetan</translation>
<translation id="8533619373899488139">Joan &lt;strong&gt;chrome://policy&lt;/strong&gt; orrira sistemaren administratzaileak blokeatutako URLen zerrenda eta aplikatutako gidalerroak ikusteko.</translation>
@@ -2322,7 +2373,6 @@ Xehetasun gehiago:
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{Berrezarri baimena}other{Berrezarri baimenak}}</translation>
<translation id="8555010941760982128">Erabili kode hau ordainketa-prozesuan</translation>
<translation id="8557066899867184262">Txartelaren atzealdean agertzen da CVC kodea.</translation>
-<translation id="8558485628462305855">Errealitate areagotuko edukia ikusteko, eguneratu ARCore</translation>
<translation id="8559762987265718583">Ezin da ezarri <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> domeinurako konexio pribatua gailuaren data eta ordua (<ph name="DATE_AND_TIME" />) okerrak direlako.</translation>
<translation id="8564182942834072828">Dokumentu bereiziak / Elkartu gabeko kopiak</translation>
<translation id="8564985650692024650"><ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> pasahitza beste webgune batzuetan ere erabili baduzu, hura berrezartzea gomendatzen du Chromium-ek.</translation>
@@ -2341,6 +2391,7 @@ Xehetasun gehiago:
<translation id="865032292777205197">mugimendu-sentsoreak</translation>
<translation id="8663226718884576429">Eskaeraren laburpena, <ph name="TOTAL_LABEL" />, xehetasun gehiago</translation>
<translation id="8666678546361132282">Ingelesa</translation>
+<translation id="8669306706049782872">Pantailei buruzko informazioa erabili leihoak irekitzeko eta pantailan kokatzeko.</translation>
<translation id="867224526087042813">Sinadura</translation>
<translation id="8676424191133491403">Atzerapenik gabe</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, erantzuna, <ph name="ANSWER" /></translation>
@@ -2367,6 +2418,7 @@ Xehetasun gehiago:
<translation id="8731544501227493793">"Kudeatu pasahitzak" botoia: sakatu "Sartu"·pasahitzak ikusi eta kudeatzeko Chrome-ren ezarpenetan</translation>
<translation id="8734529307927223492"><ph name="MANAGER" /> domeinuak kudeatzen du <ph name="DEVICE_TYPE" /> gailua</translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />: sakatu tabuladorea ezkutuko moduko leiho bat irekitzeko, modu pribatuan arakatu ahal izateko</translation>
+<translation id="8737685506611670901">Ireki <ph name="PROTOCOL" /> estekak <ph name="REPLACED_HANDLER_TITLE" /> maneiatzailearen ordez</translation>
<translation id="8738058698779197622">Konexio segurua ezartzeko, erlojuak behar bezala ezarrita egon behar du, webguneek beren burua identifikatzeko erabiltzen dituzten ziurtagiriek denboraldi jakinetarako bakarrik balio dutelako. Gailuaren erlojua oker ezarrita dagoenez, Chromium-ek ezin ditu ziurtagiri horiek egiaztatu.</translation>
<translation id="8740359287975076522">Ezin izan da aurkitu <ph name="HOST_NAME" /> webgunearen &lt;abbr id="dnsDefinition"&gt;DNS helbidea&lt;/abbr&gt;. Arazoaren diagnostikoa egiten ari gara.</translation>
<translation id="8742371904523228557"><ph name="ONE_TIME_CODE" /> da <ph name="ORIGIN" /> webgunerako kodea</translation>
@@ -2394,6 +2446,7 @@ Xehetasun gehiago:
<translation id="883848425547221593">Beste laster-markak</translation>
<translation id="884264119367021077">Bidaltzeko helbidea</translation>
<translation id="884923133447025588">Ez da baliogabetze-mekanismorik aurkitu.</translation>
+<translation id="8849262850971482943">Segurtasun handiagoa izateko, erabili txartel birtuala</translation>
<translation id="885730110891505394">Google-rekin partekatzea</translation>
<translation id="8858065207712248076"><ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> pasahitza beste webgune batzuetan ere erabili baduzu, hura berrezartzea gomendatzen du Chrome-k.</translation>
<translation id="885906927438988819">Behar bezala idatzita badago, <ph name="BEGIN_LINK" />exekutatu Windows-en sare-diagnostikoak<ph name="END_LINK" />.</translation>
@@ -2443,6 +2496,7 @@ Xehetasun gehiago:
<translation id="9004367719664099443">Errealitate birtualeko saioa abian da</translation>
<translation id="9005998258318286617">Ezin izan da kargatu PDF dokumentua.</translation>
<translation id="9008201768610948239">Egin ez ikusi</translation>
+<translation id="901834265349196618">helbide elektronikoa</translation>
<translation id="9020200922353704812">Txartelaren fakturazio-helbidea behar da</translation>
<translation id="9020542370529661692">Orria <ph name="TARGET_LANGUAGE" /> hizkuntzara itzuli da</translation>
<translation id="9020742383383852663">A8</translation>
@@ -2491,6 +2545,7 @@ Xehetasun gehiago:
<translation id="9150045010208374699">Erabili zure kamera</translation>
<translation id="9150685862434908345">Administratzaileak urrunetik alda dezake arakatzailearen konfigurazioa. Baliteke gailu honetako jarduera Chrome-tik kanpo ere kudeatzea. <ph name="BEGIN_LINK" />Lortu informazio gehiago<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">Eguneratuta</translation>
+<translation id="9155211586651734179">Erantsitako audio-gailu periferikoak</translation>
<translation id="9157595877708044936">Konfiguratzen…</translation>
<translation id="9158625974267017556">C6 (gutun-azala)</translation>
<translation id="9164029392738894042">Zehaztasun-egiaztapena</translation>
diff --git a/chromium/components/strings/components_strings_fa.xtb b/chromium/components/strings/components_strings_fa.xtb
index bda5c67030e..fcdeda4486a 100644
--- a/chromium/components/strings/components_strings_fa.xtb
+++ b/chromium/components/strings/components_strings_fa.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">دیدن جزئیات</translation>
<translation id="1030706264415084469"><ph name="URL" /> می‌خواهد داده‌های بزرگ را برای همیشه در دستگاهتان ذخیره کند</translation>
<translation id="1032854598605920125">چرخش در جهت عقربه‌های ساعت</translation>
+<translation id="1033329911862281889">«حالت ناشناس» شما را در دنیای آنلاین نامرئی نمی‌کند:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />سایت‌ها Ùˆ سرویس‌هایی Ú©Ù‡ استÙاده می‌کنند می‌توانند بازدیدها را ببینند<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />کارÙرمایان یا مدارس می‌توانند Ùعالیت مرور را ردیابی کنند<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />رسانندگان خدمات اینترنتی می‌توانند تراÙیک وب را پایش کنند<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">خاموش کردن</translation>
<translation id="1036982837258183574">برای خروج از حالت تمام صÙحه |<ph name="ACCELERATOR" />| را Ùشار دهید</translation>
<translation id="1038106730571050514">نمایش پیشنهادها</translation>
<translation id="1038842779957582377">نام ناشناس</translation>
<translation id="1041998700806130099">پیام برگ کار</translation>
<translation id="1048785276086539861">وقتی یادداشت‌ها را ویرایش می‌کنید، این سند به نمای تک‌صÙحه‌ای برمی‌گردد</translation>
-<translation id="1049743911850919806">ناشناس</translation>
<translation id="1050038467049342496">برنامه‌های دیگر را ببندید</translation>
<translation id="1055184225775184556">&amp;واگرد اÙزودن</translation>
<translation id="1056898198331236512">اخطار</translation>
@@ -38,7 +43,7 @@
<translation id="1088860948719068836">اÙزودن نام روی کارت</translation>
<translation id="1089439967362294234">تغییر گذرواژه</translation>
<translation id="1096545575934602868">این Ùیلد نباید بیشتر از <ph name="MAX_ITEMS_LIMIT" /> ورودی داشته باشد. از همه ورودی‌های آینده صرÙ‌نظر می‌شود.</translation>
-<translation id="1100782917270858593">â€Ø¯Ú©Ù…Ù‡ «ازسرگیری سÙر»، برای ازسر گرÙتن کاوش Ùˆ دیدن Ùعالیت‌های مرتبط در سابقه ChromeØŒ کلید «ورود» را Ùشار دهید</translation>
+<translation id="1100782917270858593">â€Ø¯Ú©Ù…Ù‡ «ازسرگیری سÙر جستجو»، برای ازسر گرÙتن سÙر جستجو Ùˆ دیدن Ùعالیت‌های مرتبط در سابقه ChromeØŒ کلید «ورود» را Ùشار دهید</translation>
<translation id="1101672080107056897">اقدام خطا</translation>
<translation id="1103523840287552314"><ph name="LANGUAGE" /> همیشه ترجمه شود</translation>
<translation id="1110994991967754504">مجوز <ph name="PERMISSION_NAME" /> را انتخاب کنید</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">حاÙظه پنهان خط‌مشی مورد تأیید است</translation>
<translation id="1130564665089811311">â€Ø¯Ú©Ù…Ù‡ «ترجمه صÙحه»، برای ترجمه کردن این صÙحه بااستÙاده از «ترجمه Google»، کلید Enter (ورود) را Ùشار دهید</translation>
<translation id="1131264053432022307">تصویری که کپی کرده‌اید</translation>
+<translation id="1142846828089312304">مسدود کردن کوکی‌های شخص ثالث در «حالت ناشناس»</translation>
<translation id="1150979032973867961">این سرور نتوانست اثبات کند که این <ph name="DOMAIN" /> است؛ گواهی امنیتی آن مورداعتماد سیستم‌عامل رایانه شما نیست. ممکن است علت این موضوع پیکربندی اشتباه باشد یا مهاجی اتصال شما را قطع کرده است.</translation>
<translation id="1151972924205500581">گذرواژه ضروری است</translation>
<translation id="1156303062776767266">شما Ùایلی محلی یا هم‌رسانی‌شده را مشاهده می‌کنید</translation>
@@ -64,7 +70,6 @@
<translation id="1178581264944972037">Ù…Ú©Ø«</translation>
<translation id="1181037720776840403">حذÙ</translation>
<translation id="1186201132766001848">بررسی گذرواژه‌ها</translation>
-<translation id="1195210374336998651">رÙتن به تنظیمات برنامه</translation>
<translation id="1195558154361252544">اعلان‌ها به‌طور خودکار برای همه سایت‌ها، به‌جز آن‌هایی که مجاز کرده‌اید، مسدود می‌شوند</translation>
<translation id="1197088940767939838">نارنجی</translation>
<translation id="1201402288615127009">بعدی</translation>
@@ -111,7 +116,7 @@
<translation id="1307966114820526988">ویژگی‌های منسوخ‌شده</translation>
<translation id="1308113895091915999">پیشنهادهای موجود</translation>
<translation id="1312803275555673949">چه شواهدی آن را تأیید می‌کند؟</translation>
-<translation id="131405271941274527">â€<ph name="URL" /> می‌خواهد وقتی با تلÙنتان روی دستگاه NFC ضربه می‌زنید، اطلاعات را ارسال Ùˆ دریاÙت کند</translation>
+<translation id="1314311879718644478">مشاهده محتوای واقعیت اÙزوده</translation>
<translation id="1314509827145471431">به‌هم چسباندن از راست</translation>
<translation id="1318023360584041678">در گروه برگه ذخیره شد</translation>
<translation id="1319245136674974084">دیگر برای این برنامه سؤال نشود</translation>
@@ -161,6 +166,7 @@
<translation id="142858679511221695">کاربر ابری</translation>
<translation id="1428729058023778569">â€Ø§ÛŒÙ† هشدار را به این دلیل می‌بینید Ú©Ù‡ این سایت از HTTPS پشتیبانی نمی‌کند. <ph name="BEGIN_LEARN_MORE_LINK" />بیشتر بدانید<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">چاپ</translation>
+<translation id="1432187715652018471">این صÙحه می‌خواهد کنترل‌کننده سرویس نصب کند.</translation>
<translation id="1432581352905426595">مدیریت موتورهای جستجو</translation>
<translation id="1436185428532214179">می‌تواند برای ویرایش Ùایل‌ها Ùˆ پوشه‌های موجود در دستگاهتان درخواست دهد</translation>
<translation id="1442386063175183758">سمت راست تاخوردگی دروازه‌ای</translation>
@@ -181,6 +187,12 @@
<translation id="1483493594462132177">ارسال</translation>
<translation id="1484290072879560759">انتخاب نشانی تحویل کالا</translation>
<translation id="1492194039220927094">اعمال خط‌مشی‌ها:</translation>
+<translation id="149293076951187737">â€ÙˆÙ‚تی همه برگه‌های ناشناس Chrome را ببندید، Ùعالیتتان در این برگه‌ها از دستگاهتان پاک می‌شود:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Ùعالیت مرور<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />سابقه جستجو<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />اطلاعات واردشده در Ùرم‌ها<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">برگشتن به برگه</translation>
<translation id="1501859676467574491">â€Ú©Ø§Ø±Øªâ€ŒÙ‡Ø§ را از حساب Google خود نمایش دهید</translation>
<translation id="1507202001669085618">â€&lt;p&gt;اگر از پورتالی از Wi-Fi استÙاده می‌کنید Ú©Ù‡ پیش از آنلاین شدن شما را ملزم به ورود به سیستم می‌کند، این خطا را می‌بینید.&lt;/p&gt;
@@ -208,6 +220,8 @@
<translation id="1559572115229829303">â€&lt;p&gt;اتصال خصوصی به <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> برقرار نشد، زیرا تاریخ Ùˆ زمان دستگاه شما (<ph name="DATE_AND_TIME" />) نادرست است.&lt;/p&gt;
&lt;p&gt;لطÙاً تاریخ Ùˆ زمان را در بخش &lt;strong&gt;عمومی&lt;/strong&gt; برنامه &lt;strong&gt;تنظیمات&lt;/strong&gt; تنظیم کنید.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">سرپرست دستگاهتان را ساعت <ph name="TIME" /> در تاریخ <ph name="DATE" /> بازراه‌اندازی خواهد کرد</translation>
+<translation id="156703335097561114">اطلاعات شبکه، مثل نشانی‌ها، پیکربندی میانا، Ùˆ Ú©ÛŒÙیت اتصال</translation>
<translation id="1567040042588613346">این خط‌مشی درست کار می‌کند اما مقدار یکسانی در جای دیگری تنظیم شده است که این خط‌مشی آن را جایگزین می‌کند.</translation>
<translation id="1569487616857761740">وارد کردن تاریخ انقضا</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@
<translation id="1583429793053364125">هنگام نمایش این صÙحه وب مشکلی پیش آمد.</translation>
<translation id="1586541204584340881">اÙزونه‌هایی Ú©Ù‡ نصب کرده‌اید</translation>
<translation id="1588438908519853928">معمولی</translation>
+<translation id="1589050138437146318">â€ARCore نصب شود؟</translation>
<translation id="1592005682883173041">دسترسی داده محلی</translation>
<translation id="1594030484168838125">انتخاب</translation>
<translation id="160851722280695521">â€Ø¨Ø§Ø²ÛŒ کردن بازی دویدن دایناسور در Chrome</translation>
@@ -254,7 +269,7 @@
<translation id="1711234383449478798">نادیده گرÙته شده است زیرا <ph name="POLICY_NAME" /> روی <ph name="VALUE" /> تنظیم نشده است.</translation>
<translation id="1712552549805331520"><ph name="URL" /> می‌خواهد داده‌ها را برای همیشه در رایانه محلی‌تان ذخیره کند</translation>
<translation id="1713628304598226412">سینی ۲</translation>
-<translation id="1715874602234207">F</translation>
+<translation id="1715874602234207">ج</translation>
<translation id="1717218214683051432">حسگرهای حرکتی</translation>
<translation id="1717494416764505390">صندوق پست ۳</translation>
<translation id="1718029547804390981">این سند بسیار بزرگ است و نمی‌تواند حاشیه‌نویسی شود</translation>
@@ -283,6 +298,7 @@
قالب سرصÙحه نادرست است Ùˆ این موضوع اجازه نمی‌دهد
مرورگر درخواستتان را برای <ph name="SITE" /> اجرا کند. اپراتورهای سایت می‌توانند از
خط‌مشی‌های اصلی برای پیکربندی امنیت Ùˆ دیگر ویژگی‌های سایت استÙاده کنند.</translation>
+<translation id="1774592222195216949">â€<ph name="BEGIN_LINK" />درباره «حالت ناشناس» در Chromium بیشتر بدانید<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">برگه‌های بازتان در اینجا نشان داده می‌شوند</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -314,7 +330,7 @@
<translation id="1883255238294161206">Ú©ÙˆÚ†Ú© کردن Ùهرست</translation>
<translation id="1890171020361705182">بازی داینو. دایناسوری نقطه‌ای همان‌طور Ú©Ù‡ در دشتی دوراÙتاده می‌دود، موقع رسیدن به کاکتوس‌ها Ùˆ پتروداکتیل‌ها جاخالی می‌دهد. وقتی صدای نشانه صوتی را شنیدید، برای پریدن از روی موانع ضربه بزنید.</translation>
<translation id="1898423065542865115">Ùیلتر کردن</translation>
-<translation id="1901443836186977402">{1,plural, =1{این سرور نتوانست اثبات کند Ú©Ù‡ <ph name="DOMAIN" /> است؛ گواهی امنیتی آن روز گذشته منقضی شده است. ممکن است علت این موضوع پیکربندی اشتباه باشد یا مهاجمی درحال رهگیری اتصالتان باشد. ساعت رایانه‌تان درحال‌حاضر روی <ph name="CURRENT_DATE" /> تنظیم شده است. آیا درست است؟ اگر نه، باید ساعت سیستم را درست کنید Ùˆ سپس این صÙحه را بازخوانی کنید.}one{این سرور نتوانست اثبات کند Ú©Ù‡ <ph name="DOMAIN" /> است؛ گواهینامه امنیتی آن # روز پیش منقضی شده است. ممکن است علت این موضوع پیکربندی اشتباه باشد یا مهاجمی درحال رهگیری اتصالتان باشد. ساعت رایانه‌تان درحال‌حاضر روی <ph name="CURRENT_DATE" /> تنظیم شده است. آیا درست است؟ اگر نه، باید ساعت سیستم را درست کنید Ùˆ سپس این صÙحه را بازخوانی کنید.}other{این سرور نتوانست اثبات کند Ú©Ù‡ <ph name="DOMAIN" /> است؛ گواهینامه امنیتی آن # روز پیش منقضی شده است. ممکن است علت این موضوع پیکربندی اشتباه باشد یا مهاجمی درحال رهگیری اتصالتان باشد. ساعت رایانه‌تان درحال‌حاضر روی <ph name="CURRENT_DATE" /> تنظیم شده است. آیا درست است؟ اگر نه، باید ساعت سیستم را درست کنید Ùˆ سپس این صÙحه را بازخوانی کنید.}}</translation>
+<translation id="1901443836186977402">{1,plural, =1{این سرور نتوانست اثبات کند Ú©Ù‡ <ph name="DOMAIN" /> است؛ گواهی امنیتی آن روز گذشته منقضی شده است. ممکن است علت این موضوع پیکربندی اشتباه باشد یا مهاجمی درحال رهگیری اتصالتان باشد. ساعت رایانه‌تان درحال‌حاضر روی <ph name="CURRENT_DATE" /> تنظیم شده است. آیا درست است؟ اگر نه، باید ساعت سیستم را درست کنید Ùˆ سپس این صÙحه را بازآوری کنید.}one{این سرور نتوانست اثبات کند Ú©Ù‡ <ph name="DOMAIN" /> است؛ گواهینامه امنیتی آن # روز پیش منقضی شده است. ممکن است علت این موضوع پیکربندی اشتباه باشد یا مهاجمی درحال رهگیری اتصالتان باشد. ساعت رایانه‌تان درحال‌حاضر روی <ph name="CURRENT_DATE" /> تنظیم شده است. آیا درست است؟ اگر نه، باید ساعت سیستم را درست کنید Ùˆ سپس این صÙحه را بازآوری کنید.}other{این سرور نتوانست اثبات کند Ú©Ù‡ <ph name="DOMAIN" /> است؛ گواهینامه امنیتی آن # روز پیش منقضی شده است. ممکن است علت این موضوع پیکربندی اشتباه باشد یا مهاجمی درحال رهگیری اتصالتان باشد. ساعت رایانه‌تان درحال‌حاضر روی <ph name="CURRENT_DATE" /> تنظیم شده است. آیا درست است؟ اگر نه، باید ساعت سیستم را درست کنید Ùˆ سپس این صÙحه را بازآوری کنید.}}</translation>
<translation id="1902576642799138955">مدت اعتبار</translation>
<translation id="1906155288650175567">â€Ø¯Ú©Ù…Ù‡ ایجاد یادداشت؛ برای ایجاد سریع یادداشت جدید در Google KeepØŒ کلید «ورود» را Ùشار دهید</translation>
<translation id="1908217026282415406">استÙاده از دوربین Ùˆ حرکت دادن آن</translation>
@@ -410,6 +426,7 @@
<translation id="22081806969704220">سینی ۳</translation>
<translation id="2212735316055980242">خط‌مشی یاÙت نشد</translation>
<translation id="2213606439339815911">در حال واکشی موارد...</translation>
+<translation id="2213612003795704869">صÙحه چاپ شد</translation>
<translation id="2215727959747642672">ویرایش Ùایل</translation>
<translation id="2218879909401188352">درحال‌حاضر مهاجم‌ها در <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> می‌توانند برنامه‌های خطرناکی نصب کنند Ú©Ù‡ به دستگاهتان آسیب بزند، هزینه‌های پنهانی به صورت‌حساب دستگاه همراهتان اضاÙÙ‡ کند یا اطلاعات شخصی‌تان را سرقت کند. <ph name="BEGIN_LEARN_MORE_LINK" />بیشتر بدانید<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">اتصال اینترنت وجود ندارد</translation>
@@ -419,6 +436,7 @@
<translation id="2248949050832152960">â€Ø§Ø³ØªÙاده از WebAuthn</translation>
<translation id="2250931979407627383">دوختن لبه از چپ</translation>
<translation id="225207911366869382">این مقدار برای این خط‌مشی منسوخ شده است؟</translation>
+<translation id="2256115617011615191">راه‌اندازی مجدد در این لحظه</translation>
<translation id="2258928405015593961">تاریخی را در آینده به‌عنوان تاریخ انقضا وارد کنید و دوباره امتحان کنید</translation>
<translation id="225943865679747347">کد خطا: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">â€Ø®Ø·Ø§ÛŒ HTTP</translation>
@@ -446,6 +464,7 @@
<translation id="2337852623177822836">تنظیم توسط سرپرست کنترل می‌شود</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> می‌خواهد مرتبط شود</translation>
<translation id="2346319942568447007">تصویری که کپی کرده‌اید</translation>
+<translation id="2350796302381711542">به <ph name="HANDLER_HOSTNAME" /> امکان داده شود همه پیوندهای <ph name="PROTOCOL" /> را به‌جای <ph name="REPLACED_HANDLER_TITLE" /> باز کند؟</translation>
<translation id="2354001756790975382">نشانک‌های دیگر</translation>
<translation id="2354430244986887761">â€Ù…رور ایمن GoogleØŒ اخیراً <ph name="BEGIN_LINK" />برنامه‌های خطرناکی<ph name="END_LINK" /> در <ph name="SITE" /> پیدا کرده است.</translation>
<translation id="2355395290879513365">مهاجمین ممکن است بتوانند تصاویری را Ú©Ù‡ در این سایت می‌بینید مشاهده کنند Ùˆ با دست‌کاری آن‌ها شما را Ùریب دهند.</translation>
@@ -471,6 +490,7 @@
<translation id="2413528052993050574">این سرور نتوانست اثبات کند که این <ph name="DOMAIN" /> است؛ ممکن است گواهی امنیتی آن باطل شده باشد. ممکن است علت این موضوع پیکربندی اشتباه باشد یا مهاجمی اتصال شما را قطع کرده است.</translation>
<translation id="2414886740292270097">تاریک</translation>
<translation id="2430968933669123598">â€Ù…دیریت «حساب Google»؛ برای مدیریت اطلاعات، حریم‌خصوصی، Ùˆ امنیت در «حساب Google»، کلید «ورود» را Ùشار دهید</translation>
+<translation id="2436186046335138073">به <ph name="HANDLER_HOSTNAME" /> امکان داده شود همه پیوندهای <ph name="PROTOCOL" /> را باز کند؟</translation>
<translation id="2438874542388153331">چهار سوراخ در راست</translation>
<translation id="2450021089947420533">سÙرها</translation>
<translation id="2463739503403862330">تکمیل</translation>
@@ -478,6 +498,7 @@
<translation id="2465655957518002998">انتخاب روش ارسال</translation>
<translation id="2465688316154986572">منگنه</translation>
<translation id="2465914000209955735">â€Ù…دیریت Ùایل‌هایی Ú©Ù‡ در Chrome بارگیری کرده‌اید</translation>
+<translation id="2466004615675155314">نمایش اطلاعات برگرÙته از وب</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />در حال اجرای عیب‌یابی شبکه<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">â€ØªØ±ØªÛŒØ¨ Û± تا N</translation>
<translation id="2470767536994572628">وقتی یادداشت‌ها را ویرایش می‌کنید، این سند به نمای تک‌صÙحه‌ای Ùˆ وضعیت چرخش اصلی برمی‌گردد</translation>
@@ -498,6 +519,7 @@
<translation id="2523886232349826891">Ùقط در این دستگاه ذخیره شد</translation>
<translation id="2524461107774643265">اÙزودن اطلاعات بیشتر</translation>
<translation id="2529899080962247600">این Ùیلد نباید بیشتر از <ph name="MAX_ITEMS_LIMIT" /> ورودی داشته باشد. همه ورودی‌های بعدی نادیده گرÙته خواهند شد.</translation>
+<translation id="2535585790302968248">برگه ناشناس جدیدی برای مرور خصوصی باز می‌شود</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{و ۱ مورد دیگر}one{و # مورد دیگر}other{و # مورد دیگر}}</translation>
<translation id="2536110899380797252">اÙزودن نشانی</translation>
<translation id="2539524384386349900">تشخیص</translation>
@@ -523,7 +545,14 @@
<translation id="2597378329261239068">این سند توسط گذرواژه محاÙظت می‌شود. لطÙاً یک گذرواژه وارد کنید.</translation>
<translation id="2609632851001447353">انواع مختلÙ</translation>
<translation id="2610561535971892504">برای کپی کردن، کلیک کنید</translation>
+<translation id="2617988307566202237">â€Chrome اطلاعات زیر را <ph name="BEGIN_EMPHASIS" />ذخیره نخواهد کرد<ph name="END_EMPHASIS" />:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />سابقه مرور شما
+ <ph name="LIST_ITEM" />داده‌های سایت و کوکی‌ها
+ <ph name="LIST_ITEM" />اطلاعات واردشده در Ùرم‌ها
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (Envelope)</translation>
+<translation id="2623663032199728144">می‌تواند برای استÙاده از اطلاعات صÙحه‌نمایش‌هایتان درخواست کند</translation>
<translation id="2625385379895617796">ساعت شما جلو است</translation>
<translation id="262745152991669301">â€Ù…ی‌تواند برای اتصال به دستگاه‌های USB درخواست دهد</translation>
<translation id="2629325967560697240">â€Ø¨Ø±Ø§ÛŒ بهره‌مندی از بالاترین سطح امنیت در ChromeØŒ <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />«محاÙظت بهبودیاÙته» را روشن کنید<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -557,6 +586,7 @@
<translation id="2709516037105925701">تکمیل خودکار</translation>
<translation id="2713444072780614174">سÙید</translation>
<translation id="2715612312510870559">â€<ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />ØŒ برای مدیریت اطلاعات کارت اعتباری Ùˆ پرداخت‌ها در تنظیمات ChromeØŒ کلید Tab (جهش) Ùˆ سپس Enter (ورود) را Ùشار دهید</translation>
+<translation id="271663710482723385">برای خروج از حالت تمام صÙحه، |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| را Ùشار دهید</translation>
<translation id="2721148159707890343">درخواست با موÙقیت انجام شد</translation>
<translation id="2723669454293168317">â€Ø§Ø¬Ø±Ø§ÛŒ «بررسی ایمنی» در تنظیمات Chrome</translation>
<translation id="2726001110728089263">سینی جانبی</translation>
@@ -587,6 +617,7 @@
<translation id="2850739647070081192">Invite (Envelope)</translation>
<translation id="2856444702002559011">شاید مهاجم‌ها در تلاش باشند اطلاعات شما (مانند گذرواژه‌ها، پیام‌ها یا کارت‌های اعتباری) را از <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> سرقت کنند. <ph name="BEGIN_LEARN_MORE_LINK" />بیشتر بدانید<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">این سایتْ آگهی‌های مزاحم یا گمراه‌کننده نشان می‌دهد.</translation>
+<translation id="286512204874376891">کارت مجازی با پنهان کردن کارت واقعی‌تان از شما دربرابر کلاهبرداری‌های احتمالی محاÙظت می‌کند. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">دوستانه</translation>
<translation id="2876489322757410363">برای پرداخت ازطریق یک برنامه خارجی، از «حالت ناشناس» خارج می‌شوید. ادامه می‌دهید؟</translation>
<translation id="2876949457278336305">â€<ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />Ø› برای مدیریت «مرور ایمن» Ùˆ موارد دیگر در تنظیمات ChromeØŒ کلید «جهش» Ùˆ سپس «ورود» را Ùشار دهید</translation>
@@ -611,6 +642,7 @@
<translation id="2930577230479659665">برش زدن بعد از چاپ هر کپی</translation>
<translation id="2932085390869194046">پیشنهاد گذرواژه…</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019">باز کردن پیوندهای <ph name="PROTOCOL" /></translation>
<translation id="2941952326391522266">این سرور نتوانست اثبات کند که این <ph name="DOMAIN" /> است؛ گواهی امنیتی آن از <ph name="DOMAIN2" /> است. ممکن است علت این موضوع پیکربندی اشتباه باشد یا مهاجی اتصال شما را قطع کرده است.</translation>
<translation id="2943895734390379394">زمان بارگذاری:</translation>
<translation id="2948083400971632585">در صÙحه تنظیمات می‌توانید همه پراکسی‌های پیکربندی شده برای هر اتصال را از کار بیاندازید.</translation>
@@ -643,6 +675,7 @@
<translation id="3037605927509011580">اوه، نه!</translation>
<translation id="3041612393474885105">اطلاعات گواهی</translation>
<translation id="3044034790304486808">ازسر گرÙتن کاوش</translation>
+<translation id="305162504811187366">â€Ø³Ø§Ø¨Ù‚Ù‡ «رایانه ازدور Chrome»، ازجمله Ù…Ùهرهای زمان، میزبان‌ها، Ùˆ شناسه‌های جلسه کارخواه</translation>
<translation id="3060227939791841287">C9 (Envelope)</translation>
<translation id="3061707000357573562">سرویس وصله</translation>
<translation id="306573536155379004">بازی شروع شد.</translation>
@@ -683,6 +716,7 @@
<translation id="3197136577151645743">می‌تواند درخواست کند Ú©Ù‡ استÙاده Ùعال شما از دستگاه به او اطلاع داده شود</translation>
<translation id="3202497928925179914">â€<ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />ØŒ کلید «جهش» Ùˆ سپس «ورود» را Ùشار دهید تا اطلاعاتی را Ú©Ù‡ همگام‌سازی می‌کنید در تنظیمات Chrome مدیریت کنید</translation>
<translation id="320323717674993345">لغو پرداخت</translation>
+<translation id="3203366800380907218">برگرÙته از وب</translation>
<translation id="3207960819495026254">نشانک‌گذاری شده</translation>
<translation id="3209034400446768650">ممکن است این صÙحه از شما هزینه کسر کند</translation>
<translation id="3212581601480735796">بر Ùعالیت شما در <ph name="HOSTNAME" /> نظارت می‌شود</translation>
@@ -699,10 +733,12 @@
<translation id="3234666976984236645">همیشه محتوای مهم در این سایت شناسایی شود</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />Ø› برای سÙارشی کردن ظاهر مرورگر، کلید «جهش» Ùˆ سپس «ورود» را Ùشار دهید</translation>
<translation id="3240791268468473923">برگ «اطلاعات کاربری مطابقت ندارد» در روند وارد کردن اطلاعات کاربری پرداخت امن باز شد</translation>
+<translation id="324180406144491771">پیوندهای «<ph name="HOST_NAME" />» مسدود شده است</translation>
<translation id="3249845759089040423">شیک</translation>
<translation id="3252266817569339921">Ùرانسوی</translation>
<translation id="3257954757204451555">چه کسی مسئول این اطلاعات است؟</translation>
<translation id="3259648571731540213">â€<ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />Ø› برای ایجاد سریع رویداد جدید در «تقویم Google»، کلید «جهش» Ùˆ سپس «ورود» را Ùشار دهید</translation>
+<translation id="3261488570342242926">درباره کارت‌های مجازی بیشتر بدانید</translation>
<translation id="3264837738038045344">â€Ø¯Ú©Ù…Ù‡ «مدیریت تنظیمات Chrome»؛ برای رÙتن به تنظیمات ChromeØŒ کلید «ورود» را Ùشار دهید</translation>
<translation id="3266793032086590337">مقدار (مغایر)</translation>
<translation id="3268451620468152448">برگه‌های باز</translation>
@@ -716,6 +752,7 @@
<translation id="3288238092761586174"><ph name="URL" /> ممکن است برای تأیید پرداخت شما به انجام مراحل تکمیلی نیاز داشته باشد</translation>
<translation id="3293642807462928945">درباره خطمشی <ph name="POLICY_NAME" /> بیشتر بدانید</translation>
<translation id="3295444047715739395">â€Ú¯Ø°Ø±ÙˆØ§Ú˜Ù‡â€ŒÙ‡Ø§ÛŒØªØ§Ù† را در تنظیمات Chrome مشاهده Ùˆ مدیریت کنید</translation>
+<translation id="3303795387212510132">برنامه مجاز است پیوندهای <ph name="PROTOCOL_SCHEME" /> را باز کند؟</translation>
<translation id="3303855915957856445">هیچ نتیجه‌ای برای جستجو یاÙت نشد</translation>
<translation id="3304073249511302126">اسکن کردن بلوتوث</translation>
<translation id="3308006649705061278">â€ÙˆØ§Ø­Ø¯ سازمانی (OU)</translation>
@@ -729,12 +766,6 @@
<translation id="3345782426586609320">چشم‌ها</translation>
<translation id="3355823806454867987">تغییر تنظیمات پروکسی...</translation>
<translation id="3360103848165129075">برگ کنترل‌کننده پرداخت</translation>
-<translation id="3361596688432910856">â€Chrome اطلاعات زیر را <ph name="BEGIN_EMPHASIS" />ذخیره نخواهد کرد<ph name="END_EMPHASIS" />:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />سابقه مرور
- <ph name="LIST_ITEM" />کوکی‌ها و داده‌های سایت
- <ph name="LIST_ITEM" />اطلاعات واردشده در Ùرم‌ها
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">این خط‌مشی به‌طور خودکار از خط‌مشی منسوخ‌شده <ph name="OLD_POLICY" /> Ú©Ù¾ÛŒ شد. درعوض، باید از این خط‌مشی استÙاده کنید.</translation>
<translation id="3364869320075768271"><ph name="URL" /> می‌خواهد از دستگاه Ùˆ داده‌های واقعیت مجازی استÙاده کند</translation>
<translation id="3366477098757335611">مشاهده کارت‌ها</translation>
@@ -817,7 +848,6 @@
<translation id="3587738293690942763">وسط</translation>
<translation id="3592413004129370115">Italian (Envelope)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{هرزمان خواستید می‌توانید گروه را بازنشانی کنید. پیوستن به گروه جدید حدود یک روز طول می‌کشد.}=1{هرزمان خواستید می‌توانید گروه را بازنشانی کنید. پیوستن به گروه جدید حدود یک روز طول می‌کشد.}one{هرزمان خواستید می‌توانید گروه را بازنشانی کنید. پیوستن به گروه جدید {NUM_DAYS} روز طول می‌کشد.}other{هرزمان خواستید می‌توانید گروه را بازنشانی کنید. پیوستن به گروه جدید {NUM_DAYS} روز طول می‌کشد.}}</translation>
-<translation id="3596012367874587041">تنظیمات برنامه</translation>
<translation id="3600246354004376029"><ph name="TITLE" />، <ph name="DOMAIN" />، <ph name="TIME" /></translation>
<translation id="3603507503523709">سرپرست برنامه را مسدود کرده است</translation>
<translation id="3608932978122581043">جهت تغذیه کاغذ</translation>
@@ -860,6 +890,7 @@
<translation id="370972442370243704">روشن کردن «سÙرها»</translation>
<translation id="3711895659073496551">تعویق</translation>
<translation id="3712624925041724820">مجوزها دیگر معتبر نیستند</translation>
+<translation id="3714633008798122362">تقویم وب</translation>
<translation id="3714780639079136834">â€Ø±ÙˆØ´Ù† کردن داده‌ شبکه تلÙÙ† همراه یا Wi-Fi</translation>
<translation id="3715597595485130451">â€Ø§ØªØµØ§Ù„ به Wi-Fi</translation>
<translation id="3717027428350673159">â€<ph name="BEGIN_LINK" />بررسی پروکسی، دیوار آتش Ùˆ پیکربندی DNS<ph name="END_LINK" /></translation>
@@ -921,6 +952,7 @@
<translation id="3906954721959377182">رایانه لوحی</translation>
<translation id="3909477809443608991">â€<ph name="URL" /> می‌خواهد محتوای محاÙظت‌شده پخش کند. هویت دستگاهتان توسط Google به‌تأیید می‌رسد Ùˆ ممکن است این سایت به آن دسترسی داشته باشد.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">ردکردن</translation>
<translation id="3939773374150895049">â€Ø¨Ù‡â€ŒØ¬Ø§ÛŒ CVC از WebAuthn استÙاده شود؟</translation>
<translation id="3946209740501886391">در این سایت، همیشه سؤال شود</translation>
<translation id="3947595700203588284">â€Ù…ی‌تواند برای اتصال به دستگاه‌های MIDI درخواست دهد</translation>
@@ -942,6 +974,7 @@
<translation id="3990250421422698716">â€Ø¢Ùست Z Ø´Ú©Ù„</translation>
<translation id="3996311196211510766">سایت <ph name="ORIGIN" /> درخواست کرده است خط‌مشی مبدأ
برای همه درخواست‌هایی به سمت آن می‌رود اعمال شود، اما این خط‌مشی درحال‌حاضر نمی‌تواند اعمال شود.</translation>
+<translation id="4009243425692662128">â€Ù…حتوای صÙحه‌هایی Ú©Ù‡ چاپ می‌کنید برای تجزیه‌وتحلیل به Google Cloud یا اشخاص ثالث ارسال می‌شود. مثلاً ممکن است این محتوا ازنظر وجود داده‌های حساس بررسی شود.</translation>
<translation id="4010758435855888356">دسترسی به Ùضای ذخیره‌سازی مجاز شود؟</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{â€Ø³Ù†Ø¯ PDF {COUNT} صÙحه دارد}one{â€Ø³Ù†Ø¯ PDF {COUNT} صÙحه دارد}other{â€Ø³Ù†Ø¯ PDF {COUNT} صÙحه دارد}}</translation>
<translation id="4023431997072828269">از آنجایی‌که این Ùرم درحال ارسال ازطریق اتصال ناامنی است، دیگران می‌توانند اطلاعات شما را ببینند.</translation>
@@ -1036,6 +1069,7 @@
<translation id="4250680216510889253">نه</translation>
<translation id="4253168017788158739">یادداشت</translation>
<translation id="425582637250725228">تغییراتی که انجام داده‌اید ممکن است ذخیره نشده باشند.</translation>
+<translation id="425869179292622354">می‌خواهید آن را با کارت مجازی ایمن‌تر کنیم؟</translation>
<translation id="4258748452823770588">امضای نادرست</translation>
<translation id="4261046003697461417">نمی‌توان در سند محاÙظت‌شده حاشیه‌نویسی کرد</translation>
<translation id="4265872034478892965">توسط سرپرست مجاز شده است</translation>
@@ -1098,6 +1132,7 @@
<translation id="4434045419905280838">پنجره‌های بازشو و هدایت‌ها</translation>
<translation id="4435702339979719576">Postcard)</translation>
<translation id="443673843213245140">استÙاده از پروکسی غیرÙعال است اما یک پیکربندی خاص برای پروکسی تعیین شده است.</translation>
+<translation id="4441832193888514600">نادیده گرÙته شد زیرا این خط‌مشی Ùقط می‌تواند به‌عنوان خط‌مشی کاربر ابری تنظیم شود.</translation>
<translation id="4450893287417543264">دیگر نشان داده نشود</translation>
<translation id="4451135742916150903">â€Ù…ی‌تواند برای اتصال به دستگاه‌های HID درخواست دهد</translation>
<translation id="4452328064229197696">â€Ú¯Ø°Ø±ÙˆØ§Ú˜Ù‡â€ŒØ§ÛŒ Ú©Ù‡ اکنون استÙاده کردید مورد سرقت قرار گرÙته است. برای Ø­Ùظ امنیت حساب‌هایتان، «مدیر گذرواژه Google» توصیه می‌کند گذرواژه‌های ذخیره‌شده‌تان را بررسی کنید.</translation>
@@ -1153,6 +1188,7 @@
<translation id="4628948037717959914">عکس</translation>
<translation id="4631649115723685955">بازگشت نقدی پیوند داده شده است</translation>
<translation id="4636930964841734540">اطلاعات</translation>
+<translation id="4638670630777875591">â€Â«Ø­Ø§Ù„ت ناشناس» در Chromium</translation>
<translation id="464342062220857295">ویژگی‌های جستجو</translation>
<translation id="4644670975240021822">روبه‌پایین به‌ترتیب معکوس</translation>
<translation id="4646534391647090355">اکنون من را به آنجا ببر</translation>
@@ -1173,6 +1209,7 @@
<translation id="4708268264240856090">اتصال شما قطع شد</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131">â€<ph name="BEGIN_LINK" />اجرای Windows Network Diagnostics<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426">گذرواژه <ph name="USERNAME" /></translation>
<translation id="4724144314178270921">می‌تواند درخواست کند نوشتار و تصاویر موجود در بریده‌دان را ببیند</translation>
<translation id="4726672564094551039">تازه‌سازی خط مشی‌ها</translation>
<translation id="4728558894243024398">پلت Ùورم</translation>
@@ -1194,6 +1231,7 @@
<translation id="4757993714154412917">â€Ø§Ø®ÛŒØ±Ø§Ù‹ گذرواژه‌تان را در سایتی Ùریب‌کار وارد کرده‌اید. برای ایمن کردن حسابتان، Chromium توصیه می‌کند گذرواژه‌های ذخیره‌شده‌تان را بررسی کنید.</translation>
<translation id="4758311279753947758">اÙزودن اطلاعات تماس</translation>
<translation id="4761104368405085019">استÙاده از میکروÙون شما</translation>
+<translation id="4761869838909035636">â€Ø±Ø§Ù†Ø¯Ù† «بررسی ایمنی» در Chrome</translation>
<translation id="4764776831041365478">ممکن است صÙحهٔ وب <ph name="URL" /> موقتاً خراب باشد یا ممکن است برای همیشه به آدرس وب جدید منتقل شده باشد.</translation>
<translation id="4766713847338118463">دو منگنه در پایین</translation>
<translation id="4771973620359291008">خطای ناشناخته‌ای رخ داد.</translation>
@@ -1214,12 +1252,6 @@
<translation id="4819347708020428563">یادداشت‌ها در نمای پیش‌Ùرض ویرایش شوند؟</translation>
<translation id="4825496307559726072">â€<ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />Ø› برای ایجاد سریع «کاربرگ‌نگار Google» جدید، کلید «جهش» Ùˆ سپس «ورود» را Ùشار دهید</translation>
<translation id="4825507807291741242">نیرومند</translation>
-<translation id="4827402517081186284">«حالت ناشناس» شما را در دنیای آنلاین نامرئی نمی‌کند:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />وب‌سایت‌ها داده‌های بازدید شما را می‌بینند<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />کارÙرما یا کارکنان مدرسه می‌توانند Ùعالیت مرور را ردیابی کنند<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />«رسانندگان خدمات اینترنتی» می‌توانند تراÙیک وب را پایش کنند<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">روشن کردن هشدارها</translation>
<translation id="4838327282952368871">رؤیایی</translation>
<translation id="4840250757394056958">â€Ù…شاهده سابقه Chrome</translation>
@@ -1231,12 +1263,12 @@
<translation id="4854362297993841467">این روش تحویل در دسترس نیست. روش دیگری را امتحان کنید.</translation>
<translation id="4854853140771946034">â€Ø§ÛŒØ¬Ø§Ø¯ سریع یادداشت جدید در Google Keep</translation>
<translation id="485902285759009870">درحال تأیید کد…</translation>
+<translation id="4866506163384898554">برای نمایش نشانگر، |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| را Ùشار دهید</translation>
<translation id="4876188919622883022">نمای ساده‌شده</translation>
<translation id="4876305945144899064">بدون نام کاربری</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{هیچ‌کدام}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />، <ph name="EXAMPLE_DOMAIN_2" />}one{<ph name="EXAMPLE_DOMAIN_1" />، <ph name="EXAMPLE_DOMAIN_2" />، <ph name="AND_MORE" />}other{<ph name="EXAMPLE_DOMAIN_1" />، <ph name="EXAMPLE_DOMAIN_2" />، <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831">جستجوی <ph name="TEXT" /></translation>
<translation id="4879491255372875719">خودکار (پیش‌Ùرض)</translation>
-<translation id="4879725228911483934">پنجره‌ها در صÙحه‌های نمایش باز Ùˆ جای‌گذاری شوند</translation>
<translation id="4880827082731008257">سابقه جستجو</translation>
<translation id="4881695831933465202">باز کردن</translation>
<translation id="4885256590493466218">هنگام تصÙیه حساب، با <ph name="CARD_DETAIL" /> پرداخت کنید</translation>
@@ -1245,6 +1277,7 @@
<translation id="4895877746940133817"><ph name="TYPE_1" />،†<ph name="TYPE_2" />،†<ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">رول نهم</translation>
<translation id="4901778704868714008">ذخیره...</translation>
+<translation id="4905659621780993806">سرپرستْ دستگاهتان را ساعت <ph name="TIME" /> روز <ph name="DATE" /> به‌طور خودکار بازراه‌اندازی خواهد کرد. قبل‌از بازراه‌اندازی دستگاه، موارد باز را ذخیره کنید.</translation>
<translation id="4913987521957242411">سوراخ سمت راست بالا</translation>
<translation id="4918221908152712722">نصب <ph name="APP_NAME" /> (بارگیری لازم نیست)</translation>
<translation id="4923459931733593730">پرداخت</translation>
@@ -1253,6 +1286,7 @@
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101">â€<ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />ØŒ برای جستجو کردن، ابتدا کلید Tab Ùˆ سپس Enter را Ùشار دهید</translation>
<translation id="4930153903256238152">ظرÙیت زیاد</translation>
+<translation id="4940163644868678279">â€Â«Ø­Ø§Ù„ت ناشناس» در Chrome</translation>
<translation id="4943872375798546930">نتیجه‌ای پیدا نشد</translation>
<translation id="4950898438188848926">â€Ø¯Ú©Ù…Ù‡ جابه‌جایی برگه، برای جابه‌جایی به برگه باز، کلید Enter را Ùشار دهید، <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="495170559598752135">کنش‌ها</translation>
@@ -1262,6 +1296,7 @@
<translation id="4968522289500246572">این برنامه برای تلÙÙ† همراه طراحی شده است Ùˆ ممکن است با تغییر اندازه سازگار نباشد. برنامه ممکن است با مشکلاتی روبرو شود یا بازراه‌اندازی شود.</translation>
<translation id="4969341057194253438">حذ٠ویدیوی ضبط‌شده</translation>
<translation id="4973922308112707173">دو سوراخ در بالا</translation>
+<translation id="4976702386844183910">آخرین بازدید: <ph name="DATE" /></translation>
<translation id="4984088539114770594">از میکروÙون استÙاده شود؟</translation>
<translation id="4984339528288761049">Prc5 (Envelope)</translation>
<translation id="4989163558385430922">دیدن همه</translation>
@@ -1323,6 +1358,7 @@
<translation id="5138227688689900538">نمایش کمتر</translation>
<translation id="5145883236150621069">کد خطا در پاسخ خط‌مشی موجود است</translation>
<translation id="5146995429444047494">اعلان‌های مربوط به <ph name="ORIGIN" /> مسدود شده‌اند</translation>
+<translation id="514704532284964975">â€<ph name="URL" /> می‌خواهد اطلاعات دستگاه‌های NFC را Ú©Ù‡ با تلÙÙ† روی آن‌ها ضربه می‌زنید ببیند Ùˆ تغییر دهد</translation>
<translation id="5148809049217731050">روبه‌بالا</translation>
<translation id="515292512908731282">C4 (Envelope)</translation>
<translation id="5158275234811857234">جلد</translation>
@@ -1347,6 +1383,7 @@
<translation id="5215116848420601511">â€Ø±ÙˆØ´â€ŒÙ‡Ø§ÛŒ پرداخت Ùˆ نشانی‌های مورداستÙاده در Google Pay</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">سینی ۱۳</translation>
+<translation id="5216942107514965959">آخرین بازدید: امروز</translation>
<translation id="5222812217790122047">ایمیل ضروری است</translation>
<translation id="5230733896359313003">نشانی تحویل کالا</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1367,7 +1404,6 @@
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">مشخصات سند</translation>
<translation id="528468243742722775">پایان</translation>
-<translation id="5284909709419567258">نشانی‌های شبکه</translation>
<translation id="5285570108065881030">نمایش همه گذرواژه‌های ذخیره‌شده</translation>
<translation id="5287240709317226393">نمایش کوکی‌ها</translation>
<translation id="5287456746628258573">پیکربندی امنیتی این سایت قدیمی است Ùˆ ممکن است اطلاعاتتان (برای مثال، گذرواژه‌ها یا شماره کارت‌های اعتباری) را هنگام ارسال به این سایت اÙشا کند.</translation>
@@ -1451,6 +1487,7 @@
<translation id="5556459405103347317">تازه‌سازی</translation>
<translation id="5560088892362098740">تاریخ انقضا</translation>
<translation id="55635442646131152">طرح کلی سند</translation>
+<translation id="5565613213060953222">باز کردن «برگه ناشناس»</translation>
<translation id="5565735124758917034">Ùعال</translation>
<translation id="5570825185877910964">محاÙظت از حساب</translation>
<translation id="5571083550517324815">تحویل گرÙتن از این نشانی ممکن نیست. نشانی دیگری را انتخاب کنید.</translation>
@@ -1491,7 +1528,7 @@
<translation id="5695542892312572833">â€Ø¨Ø±Ø§ÛŒ تأیید Ùˆ تکمیل خریدتان از Windows Hello استÙاده شود؟</translation>
<translation id="5701381305118179107">مرکز</translation>
<translation id="570530837424789914">مدیریت…</translation>
-<translation id="5707154300732650394">سÙرتان را ازسر بگیرید</translation>
+<translation id="5707154300732650394">ازسرگیری سÙر جستجو</translation>
<translation id="57094364128775171">پیشنهاد گذرواژه قوی…</translation>
<translation id="571403275720188526">(arm64)</translation>
<translation id="5720705177508910913">کاربر کنونی</translation>
@@ -1533,6 +1570,7 @@
<translation id="5869522115854928033">گذرواژه‌های ذخیره‌شده</translation>
<translation id="5873013647450402046">بانکتان می‌خواهد هویت شما را تأیید کند.</translation>
<translation id="5887400589839399685">کارت ذخیره‌ شد</translation>
+<translation id="5887687176710214216">آخرین بازدید: دیروز</translation>
<translation id="5895138241574237353">راه‌اندازی مجدد</translation>
<translation id="5895187275912066135">تاریخ صدور</translation>
<translation id="5901630391730855834">زرد</translation>
@@ -1546,6 +1584,7 @@
<translation id="5921639886840618607">â€Ú©Ø§Ø±Øª در حساب Google ذخیره شود؟</translation>
<translation id="5922853866070715753">تقريباً تمام است</translation>
<translation id="5932224571077948991">سایتْ آگهی‌های مزاحم یا گمراه‌کننده نشان می‌دهد</translation>
+<translation id="5938153366081463283">اÙزودن کارت مجازی</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347">درحال باز کردن <ph name="SITE_NAME" />…</translation>
<translation id="5951495562196540101">نمی‌توان با حساب مصرÙ‌کننده ثبت‌نام کرد (مجوز بسته‌بندی دردسترس است).</translation>
@@ -1610,6 +1649,7 @@
<translation id="6120179357481664955">â€Ø´Ù†Ø§Ø³Ù‡ «رابط پرداخت‌های یکپارچه» (UPI) شما به‌خاطر سپرده شود؟</translation>
<translation id="6124432979022149706">â€Ø±Ø§Ø¨Ø·â€ŒÙ‡Ø§ÛŒ Chrome Enterprise</translation>
<translation id="6127379762771434464">مورد برداشته شد</translation>
+<translation id="6132161237766805930">â€<ph name="BEGIN_LINK" />درباره «حالت ناشناس» در Chrome بیشتر بدانید<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">همه کابل‌ها را بررسی کنید و همه ره‌یاب‌ها، مودم‌ها، یا دیگر دستگاه‌های
 شبکه‌ای را Ú©Ù‡ ممکن است درحال استÙاده از آن‌ها باشید مجدداً راه‌اندازی کنید.</translation>
<translation id="614940544461990577">این موارد را امتحان کنید:</translation>
@@ -1622,7 +1662,6 @@
<translation id="6169916984152623906">اکنون می‌توانید به‌طور خصوصی مرور کنید Ùˆ سایر اÙرادی Ú©Ù‡ از این دستگاه استÙاده می‌کنند Ùعالیت شما را نخواهند دید. بااین‌وجود بارگیری‌ها Ùˆ نشانک‌ها ذخیره خواهند شد.</translation>
<translation id="6177128806592000436">اتصال شما به این سایت امن نیست</translation>
<translation id="6180316780098470077">Ùاصله زمانی امتحان مجدد</translation>
-<translation id="619448280891863779">می‌تواند برای باز کردن Ùˆ قرار دادن پنجره در صÙحه‌ها درخواست دهد</translation>
<translation id="6196640612572343990">مسدود کردن کوکی‌های شخص ثالث</translation>
<translation id="6203231073485539293">اتصال اینترنتتان را بررسی کنید</translation>
<translation id="6218753634732582820">â€Ø¢Ø¯Ø±Ø³ از Chromium پاک شود؟</translation>
@@ -1641,11 +1680,11 @@
<translation id="6264485186158353794">بازگشت به ایمنی</translation>
<translation id="6265794661083428563">کپی کردن مقدار خط‌مشی <ph name="POLICY_NAME" /></translation>
<translation id="6266934640124581640">سبز دودی روشن</translation>
-<translation id="6272088941196661550">â€Ú©Ø§ÙˆØ´ را ازسر بگیرید تا Ùعالیت‌های مرتبط را در سابقه Chrome ببینید</translation>
+<translation id="6272088941196661550">â€Ø³Ùر جستجو را ازسر بگیرید تا Ùعالیت‌های مرتبط را در سابقه Chrome ببینید</translation>
<translation id="6272383483618007430">Google Update</translation>
<translation id="6276112860590028508">صÙحه‌های مربوط به Ùهرست خواندنتان اینجا نشان داده می‌شوند</translation>
<translation id="627746635834430766">â€Ø¨Ø±Ø§ÛŒ اینکه دÙعات بعد پرداخت سریع‌تری داشته باشید، اطلاعات کارت Ùˆ نشانی صورت‌حسابتان را در حساب Google خود ذخیره کنید.</translation>
-<translation id="6279098320682980337">شماره کارت مجازی تکمیل نشود؟ روی جزئیات کارت کلیک کنید تا کپی شود</translation>
+<translation id="6279183038361895380">برای نمایش نشان‌گر |<ph name="ACCELERATOR" />| را Ùشار دهید</translation>
<translation id="6280223929691119688">تحویل به این نشانی ممکن نیست. نشانی دیگری را انتخاب کنید.</translation>
<translation id="6282194474023008486">کد پستی</translation>
<translation id="6285507000506177184">â€Ø¯Ú©Ù…Ù‡ «مدیریت بارگیری‌ها در Chrome»؛ برای مدیریت Ùایل‌هایی Ú©Ù‡ در Chrome بارگیری کرده‌اید، کلید «ورود» را Ùشار دهید</translation>
@@ -1653,6 +1692,7 @@
<translation id="6290238015253830360">مقاله‌های پیشنهادی شما در اینجا نشان داده می‌شوند</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{دستگاه اکنون بازراه‌اندازی خواهد شد}=1{دستگاه یک ثانیه دیگر بازراه‌اندازی خواهد شد}one{دستگاه # ثانیه دیگر بازراه‌اندازی خواهد شد}other{دستگاه # ثانیه دیگر بازراه‌اندازی خواهد شد}}</translation>
<translation id="6302269476990306341">â€ØªÙˆÙ‚٠«دستیار Google» در Chrome</translation>
<translation id="6305205051461490394">دسترسی به <ph name="URL" /> امکان‌پذیر نیست.</translation>
<translation id="6312113039770857350">صÙحه وب در دسترس نیست</translation>
@@ -1726,6 +1766,7 @@
<translation id="6529602333819889595">&amp;انجام مجدد حذÙ</translation>
<translation id="6545864417968258051">اسکن کردن بلوتوث</translation>
<translation id="6547208576736763147">دو سوراخ در چپ</translation>
+<translation id="6554732001434021288">آخرین بازدید: <ph name="NUM_DAYS" /> روز پیش</translation>
<translation id="6556866813142980365">انجام مجدد</translation>
<translation id="6569060085658103619">درحال مشاهده یک صÙحه اÙزونه هستید</translation>
<translation id="6573200754375280815">دو سوراخ در راست</translation>
@@ -1786,7 +1827,6 @@
<translation id="6757797048963528358">دستگاهتان به خواب رÙته است.</translation>
<translation id="6767985426384634228">نشانی به‌روزرسانی شود؟</translation>
<translation id="6768213884286397650">Hagaki (Postcard)</translation>
-<translation id="6774185088257932239">درباره «حالت ناشناس» <ph name="BEGIN_LINK" />بیشتر بدانید<ph name="END_LINK" /></translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">بنÙØ´</translation>
<translation id="6786747875388722282">اÙزونه‌ها</translation>
@@ -1870,7 +1910,6 @@
<translation id="706295145388601875">â€Ø§Ùزودن Ùˆ مدیریت نشانی‌ها در تنظیمات Chrome</translation>
<translation id="7064851114919012435">اطلاعات تماس</translation>
<translation id="7068733155164172741">کد <ph name="OTP_LENGTH" /> رقمی را وارد کنید</translation>
-<translation id="7070090581017165256">درباره این سایت</translation>
<translation id="70705239631109039">اتصال شما کاملاً ایمن نیست</translation>
<translation id="7075452647191940183">درخواست خیلی بزرگ است</translation>
<translation id="7079718277001814089">این سایت حاوی بداÙزار است</translation>
@@ -1887,6 +1926,12 @@
<translation id="7111012039238467737">(معتبر)</translation>
<translation id="7118618213916969306">جستجوی نشانی وب بریده‌دان، <ph name="SHORT_URL" /></translation>
<translation id="7119414471315195487">برگه‌ها یا برنامه‌های دیگر را ببندید</translation>
+<translation id="7129355289156517987">â€ÙˆÙ‚تی همه برگه‌های ناشناس Chromium را ببندید، Ùعالیتتان در این برگه‌ها از دستگاهتان پاک می‌شود:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Ùعالیت مرور<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />سابقه جستجو<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />اطلاعات واردشده در Ùرم‌ها<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">ارسال به این نشانی ممکن نیست. نشانی دیگری را انتخاب کنید.</translation>
<translation id="7132939140423847331">سرپرست کپی شدن این داده‌ها را ممنوع کرده است.</translation>
<translation id="7135130955892390533">نمایش وضعیت</translation>
@@ -1909,6 +1954,7 @@
<translation id="7192203810768312527"><ph name="SIZE" /> از Ùضا را آزاد می‌کند. ممکن است برخی از سایت‌ها در بازدیدهای بعدی کندتر بارگیری شوند.</translation>
<translation id="719464814642662924">ویزا</translation>
<translation id="7201591969684833065">سرپرستتان می‌تواند این موارد را ببیند:</translation>
+<translation id="7202217080450895452">â€<ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />Ø› برای باز کردن «برگه ناشناس» جدید Ùˆ مرور کردن به‌صورت خصوصی، کلید Tab Ùˆ سپس Enter را Ùشار دهید</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> از استانداردهای امنیتی پیروی نمی‌کند.</translation>
<translation id="7210993021468939304">â€Ùعالیت Linux در محتوی Ùˆ می‌توانید برنامه‌های Linux را در محتوی نصب Ùˆ اجرا کنید</translation>
@@ -1940,6 +1986,7 @@
<translation id="7304562222803846232">â€Ù…دیریت تنظیمات حریم‌خصوصی «حساب Google»</translation>
<translation id="7305756307268530424">شروع آهسته‌تر</translation>
<translation id="7308436126008021607">همگام‌سازی پس‌زمینه</translation>
+<translation id="7310392214323165548">دستگاه به‌زودی بازراه‌اندازی خواهد شد</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">راهنمای اتصال</translation>
<translation id="7323804146520582233">پنهان کردن بخش «<ph name="SECTION" />»</translation>
@@ -1947,6 +1994,7 @@
<translation id="7334320624316649418">&amp;انجام مجدد ترتیب‌بندی مجدد</translation>
<translation id="7335157162773372339">می‌تواند برای استÙاده از دوربین درخواست دهد</translation>
<translation id="7337248890521463931">نمایش خطوط بیشتر</translation>
+<translation id="7337418456231055214">شماره کارت مجازی تکمیل نشود؟ روی جزئیات کارت کلیک کنید تا کپی شود. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">در پلتÙورم شما دردسترس نیست.</translation>
<translation id="733923710415886693">گواهی سرور از طریق Ø´ÙاÙیت گواهینامه نشان داده نشده بود.</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1969,6 +2017,7 @@
<translation id="7378627244592794276">نه</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">نامربوط</translation>
+<translation id="7388594495505979117">{0,plural, =1{دستگاه یک دقیقه دیگر بازراه‌اندازی خواهد شد}one{دستگاه # دقیقه دیگر بازراه‌اندازی خواهد شد}other{دستگاه # دقیقه دیگر بازراه‌اندازی خواهد شد}}</translation>
<translation id="7390545607259442187">تأیید کارت</translation>
<translation id="7392089738299859607">به‌روزرسانی نشانی</translation>
<translation id="7399802613464275309">بررسی ایمنی</translation>
@@ -2005,6 +2054,12 @@
<translation id="7485870689360869515">هیچ داده‌ای یاÙت نشد.</translation>
<translation id="7495528107193238112">این محتوا مسدود شده است. برای برطر٠کردن مشکل با مالک سایت تماس بگیرید.</translation>
<translation id="7497998058912824456">â€Ø¯Ú©Ù…Ù‡ ایجاد سند؛ برای ایجاد سریع «سندنگار Google» جدید، کلید «ورود» را Ùشار دهید</translation>
+<translation id="7506488012654002225">â€Chromium اطلاعات زیر را <ph name="BEGIN_EMPHASIS" />ذخیره نخواهد کرد<ph name="END_EMPHASIS" />:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />سابقه مرور شما
+ <ph name="LIST_ITEM" />داده‌های سایت و کوکی‌ها
+ <ph name="LIST_ITEM" />اطلاعات واردشده در Ùرم‌ها
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">شناسه دستگاه خط‌مشی برگردانده‌شده خالی است یا با شناسه کنونی دستگاه مطابقت ندارد</translation>
<translation id="7508870219247277067">سبز مایل به زرد</translation>
<translation id="7511955381719512146">â€Ø´Ø¨Ú©Ù‡ Wi-Fi مورد استÙاده‌تان احتمالاً نیاز دارد Ú©Ù‡ به صÙحه <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> بروید.</translation>
@@ -2118,7 +2173,6 @@
<translation id="7813600968533626083">â€Ù¾ÛŒØ´Ù†Ù‡Ø§Ø¯ Ùرم از Chrome پاک شود؟</translation>
<translation id="781440967107097262">بریده‌دان هم‌رسانی شود؟</translation>
<translation id="7815407501681723534"><ph name="NUMBER_OF_RESULTS" /><ph name="SEARCH_RESULTS" /> برای «<ph name="SEARCH_STRING" />» پیدا شد</translation>
-<translation id="782125616001965242">نمایش اطلاعات درباره این سایت</translation>
<translation id="782886543891417279">â€Ø´Ø¨Ú©Ù‡ Wi-Fi (<ph name="WIFI_NAME" />) مورد استÙاده‌تان احتمالاً نیاز دارد Ú©Ù‡ به یک صÙحه ورود به سیستم بروید.</translation>
<translation id="7836231406687464395">Postfix (Envelope)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{هیچ‌کدام}=1{۱ برنامه (<ph name="EXAMPLE_APP_1" />)}=2{۲ برنامه (<ph name="EXAMPLE_APP_1" />،†<ph name="EXAMPLE_APP_2" />)}one{# برنامه (<ph name="EXAMPLE_APP_1" />،†<ph name="EXAMPLE_APP_2" />،†<ph name="AND_MORE" />)}other{# برنامه (<ph name="EXAMPLE_APP_1" />،†<ph name="EXAMPLE_APP_2" />،†<ph name="AND_MORE" />)}}</translation>
@@ -2135,7 +2189,6 @@
<translation id="7888575728750733395">هد٠پرداز چاپ</translation>
<translation id="7894280532028510793">اگر املا صحیح است، <ph name="BEGIN_LINK" />«عیب‌یابی شبکه» را اجرا کنید<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (Envelope)</translation>
-<translation id="7931318309563332511">ناشناس</translation>
<translation id="793209273132572360">نشانی به‌روزرسانی شود؟</translation>
<translation id="7932579305932748336">جلد</translation>
<translation id="79338296614623784">شماره تلÙÙ† معتبری وارد کنید</translation>
@@ -2160,13 +2213,14 @@
<translation id="7976214039405368314">تعداد درخواست‌ها بیش از حد است</translation>
<translation id="7977538094055660992">دستگاه خروجی</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">پیوندداده‌شده با</translation>
<translation id="798134797138789862">می‌تواند برای استÙاده از داده‌ها Ùˆ دستگاه‌های واقعیت مجازی درخواست دهد</translation>
<translation id="7984945080620862648">â€Ø¯Ø± حال حاضر نمی‌توانید از <ph name="SITE" /> بازدید کنید زیرا این وب‌سایت اعتبارنامه‌های درهمی ارسال کرده است Ú©Ù‡ Chrome نمی‌تواند پردازش کند. معمولاً خطاهای شبکه Ùˆ حمله‌ها موقتی هستند، بنابراین احتمالاً این صÙحه بعداً کار خواهد کرد.</translation>
-<translation id="79859296434321399">â€Ø¨Ø±Ø§ÛŒ مشاهده محتوای واقعیت اÙزوده، ARCore را نصب کنید</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">به‌هم چسباندن</translation>
<translation id="7992044431894087211">هم‌رسانی صÙحه‌نمایش با <ph name="APPLICATION_TITLE" /> ازسر گرÙته شد</translation>
<translation id="7995512525968007366">تعیین نشده</translation>
+<translation id="7998269595945679889">â€Ø¯Ú©Ù…Ù‡ «باز کردن برگه ناشناس»؛ برای باز کردن «برگه ناشناس» جدید Ùˆ مرور کردن به‌صورت خصوصی، کلید Enter را Ùشار دهید</translation>
<translation id="800218591365569300">سعی کنید برگه‌ها یا برنامه‌های دیگر را ببندید تا حاÙظه آزاد شود.</translation>
<translation id="8004582292198964060">مرورگر</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{این کارت Ùˆ نشانی صورت‌حساب آن ذخیره می‌شود. وقتی به سیستم <ph name="USER_EMAIL" /> وارد شوید می‌توانید از آن استÙاده کنید.}one{این کارت‌ها Ùˆ نشانی صورت‌حساب آن‌ها ذخیره می‌شود. وقتی به سیستم <ph name="USER_EMAIL" /> وارد شوید می‌توانید از آن‌ها استÙاده کنید.}other{این کارت‌ها Ùˆ نشانی صورت‌حساب آن‌ها ذخیره می‌شود. وقتی به سیستم <ph name="USER_EMAIL" /> وارد شوید می‌توانید از آن‌ها استÙاده کنید.}}</translation>
@@ -2226,6 +2280,7 @@
<translation id="8202370299023114387">اختلال</translation>
<translation id="8206978196348664717">Prc4 (Envelope)</translation>
<translation id="8211406090763984747">اتصال امن است</translation>
+<translation id="8217240300496046857">سایت‌ها نمی‌توانند از کوکی‌هایی Ú©Ù‡ شما را در وب ردیابی می‌کند استÙاده کنند. ویژگی‌های برخی سایت‌ها ممکن است کار نکنند.</translation>
<translation id="8218327578424803826">مکان اختصاص یاÙته:</translation>
<translation id="8220146938470311105">C7/C6 (Envelope)</translation>
<translation id="8225771182978767009">شخصی که این رایانه را راه‌اندازی کرده این سایت را مسدود کرده است.</translation>
@@ -2266,14 +2321,9 @@
<translation id="830498451218851433">تاخوردگی از وسط</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">برنامه‌های نصب‌شده Ùˆ میزان استÙاده از آن‌ها</translation>
+<translation id="8317207217658302555">â€ARCore به‌روزرسانی شود؟</translation>
<translation id="831997045666694187">شب</translation>
<translation id="8321476692217554900">اعلان‌ها</translation>
-<translation id="8328484624016508118">â€Ø¨Ø¹Ø¯Ø§Ø² بستن برگه‌های «ناشناس»، Chrome این‌ها را پاک می‌کند:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Ùعالیت مرورتان را از این دستگاه<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />سابقه جستجویتان را از این دستگاه<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />اطلاعات واردشده در Ùرم‌ها<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489">دسترسی به <ph name="HOST_NAME" /> رد شد</translation>
<translation id="833262891116910667">برجسته‌سازی</translation>
<translation id="8339163506404995330">صÙحه‌های <ph name="LANGUAGE" /> ترجمه نخواند شد</translation>
@@ -2325,6 +2375,7 @@
<translation id="8507227106804027148">خط Ùرمان</translation>
<translation id="8508648098325802031">نماد جستجو</translation>
<translation id="8511402995811232419">مدیریت کوکی‌ها</translation>
+<translation id="8519753333133776369">â€Ø¯Ø³ØªÚ¯Ø§Ù‡ HID را سرپرستتان مجاز کرده است</translation>
<translation id="8522552481199248698">â€Chrome می‌تواند Ú©Ù…Ú© کند از حساب Google خود محاÙظت کنید Ùˆ گذرواژه‌تان را تغییر دهید.</translation>
<translation id="8530813470445476232">â€Ø³Ø§Ø¨Ù‚Ù‡ مرور، کوکی، حاÙظه پنهان Ùˆ موارد دیگر را در تنظیمات Chrome پاک کنید.</translation>
<translation id="8533619373899488139">â€Ø¨Ø±Ø§ÛŒ دیدن Ùهرست نشانی‌های وب مسدودشده Ùˆ دیگر خط‌مشی‌های اعمال‌شده توسط سرپرست سیستم، از &lt;strong&gt;chrome://policy&lt;/strong&gt; بازدید کنید.</translation>
@@ -2336,7 +2387,6 @@
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{بازنشانی اجازه}one{بازنشانی اجازه}other{بازنشانی اجازه‌ها}}</translation>
<translation id="8555010941760982128">هنگام تسویه‌حساب، از این کد استÙاده کنید</translation>
<translation id="8557066899867184262">â€CVC در پشت کارتتان قرار گرÙته است.</translation>
-<translation id="8558485628462305855">â€Ø¨Ø±Ø§ÛŒ مشاهده محتوای واقعیت اÙزوده، ARCore را به‌روزرسانی کنید</translation>
<translation id="8559762987265718583">اتصال خصوصی به <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> انجام نمی‌شود، زیرا تاریخ و زمان دستگاه شما (<ph name="DATE_AND_TIME" />) نادرست است.</translation>
<translation id="8564182942834072828">اسناد جداگانه/کپی‌های تلÙیق‌نشده</translation>
<translation id="8564985650692024650">â€Chromium توصیه می‌کند اگر از گذرواژه <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> خود در سایت دیگری استÙاده کردید آن را بازنشانی کنید.</translation>
@@ -2355,6 +2405,7 @@
<translation id="865032292777205197">حسگرهای حرکتی</translation>
<translation id="8663226718884576429">خلاصه سÙارش، <ph name="TOTAL_LABEL" />ØŒ جزئيات بیشتر</translation>
<translation id="8666678546361132282">انگلیسی</translation>
+<translation id="8669306706049782872">از اطلاعات صÙحه‌نمایش‌هایتان برای باز کردن Ùˆ جای‌گذاری پنجره‌ها استÙاده کند</translation>
<translation id="867224526087042813">امضا</translation>
<translation id="8676424191133491403">بدون تأخیر</translation>
<translation id="8680536109547170164"><ph name="QUERY" />، پاسخ، <ph name="ANSWER" /></translation>
@@ -2381,6 +2432,7 @@
<translation id="8731544501227493793">â€Ø¯Ú©Ù…Ù‡ «مدیریت گذرواژه‌ها»، برای مشاهده Ùˆ مدیریت گذرواژه‌ها در تنظیمات ChromeØŒ کلید Enter (ورود) را Ùشار دهید</translation>
<translation id="8734529307927223492"><ph name="DEVICE_TYPE" /> شما توسط <ph name="MANAGER" /> مدیریت می‌شود.</translation>
<translation id="8737134861345396036">â€<ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />ØŒ برای باز کردن «پنجره ناشناس» جدید Ùˆ مرور کردن به‌صورت خصوصی، دکمه Tab (جهش) Ùˆ سپس Enter (ورود) را Ùشار دهید</translation>
+<translation id="8737685506611670901">باز کردن پیوندهای <ph name="PROTOCOL" /> به‌جای <ph name="REPLACED_HANDLER_TITLE" /></translation>
<translation id="8738058698779197622">â€Ø¨Ù‡ منظور برقراری یک اتصال امن، لازم است Ú©Ù‡ ساعت شما به درستی تنظیم شود. زیرا گواهینامه‌هایی Ú©Ù‡ وب‌سایت‌ها برای شناسایی خودشان استÙاده می‌کنند تنها برای دوره‌های زمانی خاصی معتبر هستند. از آنجایی Ú©Ù‡ ساعت دستگاه نادرست است، Chromium نمی‌تواند این گواهینامه‌ها را تأیید کند.</translation>
<translation id="8740359287975076522">â€<ph name="HOST_NAME" />’s &lt;abbr id="dnsDefinition"&gt;آدرس DNS&lt;/abbr&gt; پیدا نشد. درحال بررسی برای تشخیص مشکل.</translation>
<translation id="8742371904523228557"><ph name="ONE_TIME_CODE" /> کد شما برای <ph name="ORIGIN" /> است</translation>
@@ -2408,6 +2460,7 @@
<translation id="883848425547221593">نشانک‌های دیگر</translation>
<translation id="884264119367021077">اطلاعات ارسال</translation>
<translation id="884923133447025588">هیچ مکانیزم ابطالی یاÙت نشد.</translation>
+<translation id="8849262850971482943">برای اÙزایش امنیت، از کارت مجازی استÙاده کنید</translation>
<translation id="885730110891505394">â€Ø§Ø´ØªØ±Ø§Ú©â€ŒÚ¯Ø°Ø§Ø±ÛŒ با Google</translation>
<translation id="8858065207712248076">â€Chrome توصیه می‌کند اگر از گذرواژه <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> خود در سایت دیگری استÙاده کردید آن را بازنشانی کنید.</translation>
<translation id="885906927438988819">â€Ø§Ú¯Ø± املا صحیح است، <ph name="BEGIN_LINK" />«عیب‌یابی شبکه Windows» را اجرا کنید<ph name="END_LINK" />.</translation>
@@ -2457,6 +2510,7 @@
<translation id="9004367719664099443">â€Ø¬Ù„سه VR درحال انجام است</translation>
<translation id="9005998258318286617">â€Ø³Ù†Ø¯ PDF بارگیری نشد.</translation>
<translation id="9008201768610948239">نادیده گرÙتن</translation>
+<translation id="901834265349196618">ایمیل</translation>
<translation id="9020200922353704812">نشانی صورت‌حساب کارت لازم است</translation>
<translation id="9020542370529661692">این صÙحه به <ph name="TARGET_LANGUAGE" /> ترجمه شده است</translation>
<translation id="9020742383383852663">A8</translation>
@@ -2467,7 +2521,7 @@
<translation id="9036306139374661733">میکروÙون مجاز شود؟</translation>
<translation id="9038649477754266430">استÙاده از یک سرویس پیش‌بینی برای بار کردن سریع‌تر صÙحه‌ها</translation>
<translation id="9039213469156557790">علاوه بر این، این صÙحه دارای منابع دیگری است Ú©Ù‡ امن نیستند. دیگران می‌توانند در حین انتقال، این منابع را ببینند Ùˆ این منابع می‌توانند برای تغییر رÙتار صÙحه، توسط یک مهاجم تغییر داده شوند.</translation>
-<translation id="9040464167025094690">â€Ø¯Ú©Ù…Ù‡ «دستگاهم را پیدا کن»؛ برای پیدا کردن دستگاهتان در «حساب Google»، کلید «ورود» را Ùشار دهید</translation>
+<translation id="9040464167025094690">â€Ø¯Ú©Ù…Ù‡ «یاÙتن دستگاهم»؛ برای پیدا کردن دستگاهتان در «حساب Google»، کلید «ورود» را Ùشار دهید</translation>
<translation id="9042617223719777575">ظرÙیت بالا</translation>
<translation id="9044359186343685026">استÙاده از شناسه لمسی</translation>
<translation id="9045525010788763347"><ph name="RESULT_MODIFIED_DATE" /> - <ph name="RESULT_PRODUCT_SOURCE" /></translation>
@@ -2492,7 +2546,7 @@
<translation id="9114524666733003316">درحال تأیید کردن کارت…</translation>
<translation id="9114581008513152754">â€Ø§ÛŒÙ† مرورگر را شرکت یا سازمان دیگری مدیریت نمی‌کند. Ùعالیت در این دستگاه ممکن است خارج از Chrome مدیریت شود. <ph name="BEGIN_LINK" />بیشتر بدانید<ph name="END_LINK" /></translation>
<translation id="9117930699067497412">تازه</translation>
-<translation id="9118692854637641831">â€<ph name="HISTORY_CLUSTERS_SEARCH_FOCUSED_FRIENDLY_MATCH_TEXT" />ØŒ کلید «جهش» Ùˆ سپس «ورود» را Ùشار دهید تا کاوش را ازسر بگیرید Ùˆ Ùعالیت‌های مرتبط را در سابقه Chrome ببینید</translation>
+<translation id="9118692854637641831">â€<ph name="HISTORY_CLUSTERS_SEARCH_FOCUSED_FRIENDLY_MATCH_TEXT" />ØŒ کلید «جهش» Ùˆ سپس «ورود» را Ùشار دهید تا سÙر جستجو را ازسر بگیرید Ùˆ Ùعالیت‌های مرتبط را در سابقه Chrome ببینید</translation>
<translation id="9119042192571987207">بارگذاری‌شده</translation>
<translation id="9128016270925453879">خط‌مشی‌ها بار شد</translation>
<translation id="9128870381267983090">اتصال به شبکه</translation>
@@ -2505,6 +2559,7 @@
<translation id="9150045010208374699">استÙاده از دوربین شما</translation>
<translation id="9150685862434908345">â€Ø³Ø±Ù¾Ø±Ø³Øª می‌تواند تنظیم مرورگرتان را ازراه‌دور تغییر دهد. Ùعالیت در این دستگاه ممکن است خارج از Chrome هم مدیریت شود. <ph name="BEGIN_LINK" />بیشتر بدانید<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">به‌روزرسانی ‌شد</translation>
+<translation id="9155211586651734179">لوازم جانبی صوتی متصل شد</translation>
<translation id="9157595877708044936">در حال راه‌اندازی...</translation>
<translation id="9158625974267017556">C6 (Envelope)</translation>
<translation id="9164029392738894042">صحت‌سنجی</translation>
diff --git a/chromium/components/strings/components_strings_fi.xtb b/chromium/components/strings/components_strings_fi.xtb
index 27a6bfe6935..76a868fae00 100644
--- a/chromium/components/strings/components_strings_fi.xtb
+++ b/chromium/components/strings/components_strings_fi.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">Katso tiedot</translation>
<translation id="1030706264415084469"><ph name="URL" /> haluaa tallentaa suuria tietomääriä pysyvästi laitteellesi.</translation>
<translation id="1032854598605920125">Käännä myötäpäivään</translation>
+<translation id="1033329911862281889">Incognito ei muuta sinua näkymättömäksi verkossa:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Sivustot ja niiden käyttämät palvelut voivat nähdä käynnit<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Työnantajat tai koulut voivat seurata selaustoimintaa<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Internetpalveluntarjoajat voivat valvoa verkkoliikennettä<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">Poista käytöstä</translation>
<translation id="1036982837258183574">Poistu koko näytön tilasta painikkeella |<ph name="ACCELERATOR" />|.</translation>
<translation id="1038106730571050514">Näytä ehdotukset</translation>
<translation id="1038842779957582377">tuntematon nimi</translation>
<translation id="1041998700806130099">Työpaikkasivun viesti</translation>
<translation id="1048785276086539861">Kun muokkaat merkintöjä, tämä dokumentti palaa yhden sivun näkymään</translation>
-<translation id="1049743911850919806">Incognito</translation>
<translation id="1050038467049342496">Sulje muita sovelluksia.</translation>
<translation id="1055184225775184556">K&amp;umoa lisäys</translation>
<translation id="1056898198331236512">Varoitus</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">Käytännön välimuisti on OK</translation>
<translation id="1130564665089811311">Käännä sivu ‑painike, käännä tämä sivu Google Kääntäjällä painamalla Enter</translation>
<translation id="1131264053432022307">Kopioimasi kuva</translation>
+<translation id="1142846828089312304">Estä kolmannen osapuolen evästeet incognito-tilassa</translation>
<translation id="1150979032973867961">Palvelin ei voinut todistaa olevansa <ph name="DOMAIN" />; tietokoneesi käyttöjärjestelmä ei luota sen suojausvarmenteeseen. Tämä voi johtua määritysvirheestä tai verkkoyhteytesi siepanneesta hyökkääjästä.</translation>
<translation id="1151972924205500581">Salasana vaaditaan</translation>
<translation id="1156303062776767266">Katselet paikallista tai jaettua tiedostoa</translation>
@@ -64,7 +70,6 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="1178581264944972037">Tauko</translation>
<translation id="1181037720776840403">Poista</translation>
<translation id="1186201132766001848">Tarkista salasanat</translation>
-<translation id="1195210374336998651">Siirry sovellusasetuksiin</translation>
<translation id="1195558154361252544">Ilmoitukset estetään automaattisesti kaikilla muilla paitsi sallituilla sivustoilla</translation>
<translation id="1197088940767939838">Oranssi</translation>
<translation id="1201402288615127009">Seuraava</translation>
@@ -111,7 +116,7 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="1307966114820526988">Käytöstä poistetut ominaisuudet</translation>
<translation id="1308113895091915999">Tarjous saatavilla</translation>
<translation id="1312803275555673949">Mikä todiste tukee sitä?</translation>
-<translation id="131405271941274527"><ph name="URL" /> haluaa lähettää ja vastaanottaa tietoja, kun kosketat puhelimella NFC-laitetta</translation>
+<translation id="1314311879718644478">Katsele lisätyn todellisuuden sisältöä</translation>
<translation id="1314509827145471431">Oikealla sidottu</translation>
<translation id="1318023360584041678">Tallennettu välilehtiryhmään</translation>
<translation id="1319245136674974084">Älä kysy uudestaan tämän sovelluksen kohdalla</translation>
@@ -161,6 +166,7 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="142858679511221695">Pilvipalvelun käyttäjä</translation>
<translation id="1428729058023778569">Näet tämän varoituksen, koska sivusto ei tue HTTPS:ää. <ph name="BEGIN_LEARN_MORE_LINK" />Lue lisää<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">Tulosta</translation>
+<translation id="1432187715652018471">sivu haluaa asentaa palvelukäsittelijän.</translation>
<translation id="1432581352905426595">Hallinnoi hakukoneita</translation>
<translation id="1436185428532214179">Saa pyytää lupaa muokata laitteen tiedostoja ja kansioita</translation>
<translation id="1442386063175183758">Oikeanpuoleinen lehtitaite</translation>
@@ -181,6 +187,12 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="1483493594462132177">Lähetä</translation>
<translation id="1484290072879560759">Valitse toimitusosoite</translation>
<translation id="1492194039220927094">Käytäntöjen kehotusviestit:</translation>
+<translation id="149293076951187737">Kun suljet kaikki Chromen incognito-välilehdet, toimintasi kyseisillä välilehdillä tyhjennetään tältä laitteelta:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Selaustoiminta<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Hakuhistoria<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Lomakkeille lisätyt tiedot<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">Takaisin välilehdelle</translation>
<translation id="1501859676467574491">Näytä Google-tilin kortit</translation>
<translation id="1507202001669085618">&lt;p&gt;Näet tämän virheen, jos käyttämäsi Wi-Fi-portaali edellyttää kirjautumista ennen verkon käyttöä.&lt;/p&gt;
@@ -208,6 +220,8 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="1559572115229829303">&lt;p&gt;Verkkotunnukseen <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> ei voi muodostaa salattua yhteyttä, koska laitteesi aika ja päivämäärä (<ph name="DATE_AND_TIME" />) ovat virheelliset.&lt;/p&gt;
&lt;p&gt;Muokkaa aikaa ja päivämäärää &lt;strong&gt;Asetukset&lt;/strong&gt;‑sovelluksen &lt;strong&gt;Yleistä&lt;/strong&gt;‑osiossa.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">Jäjestelmänvalvojasi käynnistää laitteen uudelleen <ph name="DATE" /> kello <ph name="TIME" /></translation>
+<translation id="156703335097561114">Verkkotiedot, kuten osoitteet, käyttöliittymän määritys ja yhteyden laatu</translation>
<translation id="1567040042588613346">Tämä käytäntö toimii odotetusti, mutta sama arvo on asetettu muualla, ja tämä käytäntö korvaa sen.</translation>
<translation id="1569487616857761740">Lisää viimeinen voimassaolopäivä</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="1583429793053364125">Jotain meni pieleen. tätä verkkosivua näytettäessä.</translation>
<translation id="1586541204584340881">Asentamasi laajennukset</translation>
<translation id="1588438908519853928">Normaali</translation>
+<translation id="1589050138437146318">Asennetaanko ARCore?</translation>
<translation id="1592005682883173041">Tietojen paikallinen käyttö</translation>
<translation id="1594030484168838125">Valitse</translation>
<translation id="160851722280695521">Pelaa Dino Run ‑peliä Chromessa</translation>
@@ -254,7 +269,7 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="1711234383449478798">Ohitettu, koska käytännön (<ph name="POLICY_NAME" />) arvoksi ei ole asetettu <ph name="VALUE" />.</translation>
<translation id="1712552549805331520"><ph name="URL" /> haluaa tallentaa tietoja pysyvästi paikalliselle tietokoneellesi.</translation>
<translation id="1713628304598226412">Lokero 2</translation>
-<translation id="1715874602234207">F</translation>
+<translation id="1715874602234207">Pe</translation>
<translation id="1717218214683051432">Liiketunnistimet</translation>
<translation id="1717494416764505390">Postilaatikko 3</translation>
<translation id="1718029547804390981">Tiedosto on liian suuri merkintöihin</translation>
@@ -283,6 +298,7 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
otsikko on muotoiltu väärin, selain ei voi täyttää
pyyntöäsi (<ph name="SITE" />). Alkuperäkäytäntöjen avulla
sivusto-operaattorit voivat määrittää sen tietosuojan ja muita ominaisuuksia.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Lue lisää Chromiumin incognito-tilasta<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0 (1 030 mm x 1 456 mm)</translation>
<translation id="1787142507584202372">Avoimet välilehdet näkyvät tässä.</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -410,6 +426,7 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="22081806969704220">Lokero 3</translation>
<translation id="2212735316055980242">Käytäntöä ei löydy</translation>
<translation id="2213606439339815911">Noudetaan merkintöjä…</translation>
+<translation id="2213612003795704869">Sivu on tulostettu</translation>
<translation id="2215727959747642672">Tiedostojen muokkaus</translation>
<translation id="2218879909401188352">Sivustolla <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> tällä hetkellä olevat hyökkääjät voivat asentaa vaarallisia laitettasi vahingoittavia sovelluksia, lisätä piilomaksuja puhelinlaskuusi tai varastaa henkilökohtaisia tietojasi. <ph name="BEGIN_LEARN_MORE_LINK" />Lisätietoja<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">Ei internetyhteyttä</translation>
@@ -419,6 +436,7 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="2248949050832152960">Käytä WebAuthnia</translation>
<translation id="2250931979407627383">Reunasidonta vasemmalla</translation>
<translation id="225207911366869382">Tämän käytännön arvo on vanhentunut.</translation>
+<translation id="2256115617011615191">Käynnistä uudelleen</translation>
<translation id="2258928405015593961">Syötä tulevaisuudessa oleva viimeinen voimassaolopäivä ja yritä uudelleen</translation>
<translation id="225943865679747347">Virhekoodi: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">HTTP-virhe</translation>
@@ -446,6 +464,7 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="2337852623177822836">Järjestelmänvalvojan hallinnoima asetus</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> haluaa muodostaa laiteparin</translation>
<translation id="2346319942568447007">Kopioimasi kuva</translation>
+<translation id="2350796302381711542">Haluatko tahon <ph name="HANDLER_HOSTNAME" /> avaavan kaikki <ph name="PROTOCOL" />-linkit tahon <ph name="REPLACED_HANDLER_TITLE" /> sijaan?</translation>
<translation id="2354001756790975382">Muut kirjanmerkit</translation>
<translation id="2354430244986887761">Google-selaussuoja <ph name="BEGIN_LINK" />löysi äskettäin haitallisia sovelluksia<ph name="END_LINK" /> sivustolta <ph name="SITE" />.</translation>
<translation id="2355395290879513365">Hyökkääjät voivat mahdollisesti nähdä kuvat, joita katselet tällä sivustolla, ja huijata sinua muokkaamalla niitä.</translation>
@@ -471,13 +490,15 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="2413528052993050574">Palvelin ei voinut todistaa olevansa <ph name="DOMAIN" />; sen suojausvarmenne ei välttämättä ole voimassa. Tämä voi johtua määritysvirheestä tai verkkoyhteytesi siepanneesta hyökkääjästä.</translation>
<translation id="2414886740292270097">Tumma</translation>
<translation id="2430968933669123598">Ylläpidä Google-tiliä, ylläpidä tietojasi, yksityisyyttäsi ja tietoturvaasi Google-tilillä painamalla Enter</translation>
+<translation id="2436186046335138073">Haluatko tahon <ph name="HANDLER_HOSTNAME" /> avaavan kaikki <ph name="PROTOCOL" />-linkit?</translation>
<translation id="2438874542388153331">Neljä reikää oikealla</translation>
-<translation id="2450021089947420533">Matkat</translation>
+<translation id="2450021089947420533">Selailu</translation>
<translation id="2463739503403862330">Täytä</translation>
<translation id="2465402087343596252">Arkkitehti-E</translation>
<translation id="2465655957518002998">Valitse jakelutapa</translation>
<translation id="2465688316154986572">Niitti</translation>
<translation id="2465914000209955735">Ylläpidä Chromessa lataamiasi tiedostoja</translation>
+<translation id="2466004615675155314">Näytä tietoa verkosta</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />verkon diagnostiikkaa<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">1-to-N-järjestys</translation>
<translation id="2470767536994572628">Kun muokkaat merkintöjä, tämä dokumentti palaa yhden sivun näkymään ja alkuperäiseen asentoon</translation>
@@ -498,6 +519,7 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="2523886232349826891">Tallennetaan vain tälle laitteelle</translation>
<translation id="2524461107774643265">Lisää tietoja</translation>
<translation id="2529899080962247600">Kentässä voi olla korkeintaan <ph name="MAX_ITEMS_LIMIT" /> kohtaa. Tämän määrän ylittävät merkinnät ohitetaan.</translation>
+<translation id="2535585790302968248">Avaa uusi incognito-välilehti selataksesi yksityisesti</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{ja 1 muu}other{ja # muuta}}</translation>
<translation id="2536110899380797252">Lisää osoite</translation>
<translation id="2539524384386349900">Tunnista</translation>
@@ -523,7 +545,14 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="2597378329261239068">Tämä asiakirja on suojattu salasanalla. Lisää salasana.</translation>
<translation id="2609632851001447353">Muunnelmat</translation>
<translation id="2610561535971892504">Kopioi klikkaamalla</translation>
+<translation id="2617988307566202237">Chrome <ph name="BEGIN_EMPHASIS" />ei tallenna<ph name="END_EMPHASIS" /> näitä tietoja:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Selaushistoriasi
+ <ph name="LIST_ITEM" />Evästeet ja sivustodata
+ <ph name="LIST_ITEM" />Lomakkeisiin syötetyt tiedot
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (kirjekuori)</translation>
+<translation id="2623663032199728144">Voi pyytää lupaa käyttää tietoja näytöistäsi</translation>
<translation id="2625385379895617796">Kellosi edistää</translation>
<translation id="262745152991669301">Saa pyytää lupaa yhdistää USB-laitteisiin</translation>
<translation id="2629325967560697240">Jos haluat käyttää Chromen tehokkainta suojausta, <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />ota parannettu suojaus käyttöön<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -557,6 +586,7 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="2709516037105925701">Automaattinen täyttö</translation>
<translation id="2713444072780614174">Valkoinen</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />, paina ensin sarkainta ja sitten Enter ylläpitääksesi maksu- ja credit-korttitietoja Chromen asetuksissa</translation>
+<translation id="271663710482723385">Poistu koko näytön tilasta painamalla |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />|</translation>
<translation id="2721148159707890343">Pyyntö onnistui</translation>
<translation id="2723669454293168317">Tee turvatarkistus Chromen asetuksissa</translation>
<translation id="2726001110728089263">Sivulokero</translation>
@@ -587,6 +617,7 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="2850739647070081192">Kutsu (kirjekuori)</translation>
<translation id="2856444702002559011">Sivustolle <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> hyökännyt taho voi yrittää varastaa tietojasi (esimerkiksi salasanoja, viestejä tai luottokorttitietoja). <ph name="BEGIN_LEARN_MORE_LINK" />Lisätietoja<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">Tällä sivustolla on häiritseviä tai harhaanjohtavia mainoksia.</translation>
+<translation id="286512204874376891">Virtuaalinen kortti salaa käyttämäsi kortin. Näin saat paremman suojauksen mahdollisia petoksia vastaan. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">Ystävällinen</translation>
<translation id="2876489322757410363">Poistutaan incognito-tilasta, jotta ulkoisessa sovelluksessa maksaminen onnistuu. Haluatko jatkaa?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />, ylläpidä selaussuojaa ja muita ominaisuuksia Chromen asetuksista painamalla sarkainta ja sitten Enter</translation>
@@ -611,6 +642,7 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="2930577230479659665">Leikkaa jokaisen kopion jälkeen</translation>
<translation id="2932085390869194046">Ehdota salasanaa…</translation>
<translation id="2934466151127459956">Viranomaiskirje</translation>
+<translation id="2938225289965773019">Avata <ph name="PROTOCOL" />-linkit.</translation>
<translation id="2941952326391522266">Palvelin ei voinut todistaa olevansa <ph name="DOMAIN" />; sen suojausvarmenne on verkkotunnuksesta <ph name="DOMAIN2" />. Tämä voi johtua määritysvirheestä tai verkkoyhteytesi siepanneesta hyökkääjästä.</translation>
<translation id="2943895734390379394">Latausaika:</translation>
<translation id="2948083400971632585">Voit poistaa yhteydelle määritetyt välityspalvelimet käytöstä asetussivulla.</translation>
@@ -643,6 +675,7 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="3037605927509011580">Harmin paikka!</translation>
<translation id="3041612393474885105">Varmenteen tiedot</translation>
<translation id="3044034790304486808">Jatka tiedonhakua</translation>
+<translation id="305162504811187366">Chrome-etäkäytön historia, mukaan lukien aikaleimat, isännät ja käyttökertojen tunnukset</translation>
<translation id="3060227939791841287">C9 (kirjekuori)</translation>
<translation id="3061707000357573562">Virheenkorjauspalvelu</translation>
<translation id="306573536155379004">Peli aloitettu</translation>
@@ -684,6 +717,7 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="3197136577151645743">Saa pyytää luvan tietää, kun käytät tätä laitetta aktiivisesti</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />, paina sarkainta ja Enter, niin voit valita synkronoitavat tiedot Chromen asetuksista</translation>
<translation id="320323717674993345">Peru maksu</translation>
+<translation id="3203366800380907218">Verkosta</translation>
<translation id="3207960819495026254">Kirjanmerkeissä</translation>
<translation id="3209034400446768650">Sivu voi veloittaa</translation>
<translation id="3212581601480735796">Toimintaasi (<ph name="HOSTNAME" />) tarkkaillaan</translation>
@@ -700,10 +734,12 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="3234666976984236645">Havaitse aina tärkeä sisältö tällä sivustolla</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />, muokkaa selaimen ulkoasua painamalla sarkainta ja sitten Enter</translation>
<translation id="3240791268468473923">Suojatun maksun kirjautumistiedot eivät täsmää ‑kirjautumistietotaulukko on avattu</translation>
+<translation id="324180406144491771"><ph name="HOST_NAME" />‑linkit on estetty</translation>
<translation id="3249845759089040423">Svengaava</translation>
<translation id="3252266817569339921">ranska</translation>
<translation id="3257954757204451555">Kuka on jakanut tämän tiedon?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />, luo uusi tapahtuma nopeasti Google Kalenterissa painamalla sarkainta ja sitten Enter</translation>
+<translation id="3261488570342242926">Lue lisää virtuaalikorteista</translation>
<translation id="3264837738038045344">Muuta Chromen asetuksia ‑painike, avaa Chromen asetukset painamalla Enter</translation>
<translation id="3266793032086590337">Arvo (ristiriita)</translation>
<translation id="3268451620468152448">Avoimet välilehdet</translation>
@@ -717,6 +753,7 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="3288238092761586174"><ph name="URL" /> saattaa vaatia lisävaiheita maksun vahvistamiseksi</translation>
<translation id="3293642807462928945">Lisätietoja käytännöstä: <ph name="POLICY_NAME" /></translation>
<translation id="3295444047715739395">Katso ja hallinnoi salasanojasi Chromen asetuksissa</translation>
+<translation id="3303795387212510132">Saako sovellus avata <ph name="PROTOCOL_SCHEME" /> ‑linkit?</translation>
<translation id="3303855915957856445">Ei hakutuloksia</translation>
<translation id="3304073249511302126">Bluetooth-haku</translation>
<translation id="3308006649705061278">Organisaatioyksikkö (OU)</translation>
@@ -730,12 +767,6 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="3345782426586609320">Silmät</translation>
<translation id="3355823806454867987">Muuta välityspalvelimen asetuksia...</translation>
<translation id="3360103848165129075">Maksujenkäsittelytaulukko</translation>
-<translation id="3361596688432910856">Chrome <ph name="BEGIN_EMPHASIS" />ei tallenna<ph name="END_EMPHASIS" />
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />selaushistoriaasi
- <ph name="LIST_ITEM" />evästeitä ja sivuston tietoja
- <ph name="LIST_ITEM" />lomakkeisiin syötettyjä tietoja.
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">Tämä käytäntö kopioitiin automaattisesti vanhentuneesta <ph name="OLD_POLICY" /> ‑käytännöstä. Käytä tätä käytäntöä sen sijaan.</translation>
<translation id="3364869320075768271"><ph name="URL" /> haluaa käyttää virtuaalitodellisuuslaitteitasi ja ‑dataasi</translation>
<translation id="3366477098757335611">Näytä kortit</translation>
@@ -818,7 +849,6 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="3587738293690942763">Keskitaso</translation>
<translation id="3592413004129370115">Italialainen (kirjekuori)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{Voit nollata ryhmän milloin tahansa. Uuteen ryhmään liittyminen vie noin päivän.}=1{Voit nollata ryhmän milloin tahansa. Uuteen ryhmään liittyminen vie noin päivän.}other{Voit nollata ryhmän milloin tahansa. Uuteen ryhmään liittyminen vie {NUM_DAYS} päivää.}}</translation>
-<translation id="3596012367874587041">Sovellusasetukset</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">Järjestelmänvalvoja esti sovelluksen</translation>
<translation id="3608932978122581043">Syöttösuunta</translation>
@@ -861,6 +891,7 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="370972442370243704">Ota Matkat käyttöön</translation>
<translation id="3711895659073496551">Keskeytä</translation>
<translation id="3712624925041724820">Käyttöluvat ovat lopussa</translation>
+<translation id="3714633008798122362">verkkokalenteri</translation>
<translation id="3714780639079136834">Ota mobiilidata tai Wi-Fi käyttöön.</translation>
<translation id="3715597595485130451">Yhteyden muodostaminen Wi-Fi-verkkoon</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Tarkista välityspalvelimen, palomuurin ja nimipalvelun määritykset<ph name="END_LINK" />.</translation>
@@ -922,6 +953,7 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="3906954721959377182">Tabletti</translation>
<translation id="3909477809443608991"><ph name="URL" /> haluaa toistaa suojattua sisältöä. Google vahvistaa laitteesi identiteetin, ja myös sivusto voi saada pääsyn laitteesi identiteettitietoihin.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">Estä</translation>
<translation id="3939773374150895049">Käytetäänkö WebAuthnia CVC:n sijaan?</translation>
<translation id="3946209740501886391">Kysy aina tällä sivustolla</translation>
<translation id="3947595700203588284">Saa pyytää lupaa yhdistää MIDI-laitteisiin</translation>
@@ -943,6 +975,7 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="3990250421422698716">Jog offset</translation>
<translation id="3996311196211510766">Sivusto <ph name="ORIGIN" /> pyytää alkuperäkäytännön
soveltamista kaikkiin sen pyyntöihin, mutta käytäntöä ei voi soveltaa tällä hetkellä.</translation>
+<translation id="4009243425692662128">Tulostamiesi sivujen sisältö lähetetään Google Cloudin tai kolmansien osapuolten analysoitavaksi. Se voidaan esimerkiksi skannata arkaluontoisten tietojen varalta.</translation>
<translation id="4010758435855888356">Sallitaanko tallennustilan pääsyoikeudet?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{PDF-dokumentti, jossa on {COUNT} sivu}other{PDF-dokumentti, jossa on {COUNT} sivua}}</translation>
<translation id="4023431997072828269">Koska lomake lähetetään suojaamattomalla yhteydellä, tietosi näkyvät muille.</translation>
@@ -1037,6 +1070,7 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="4250680216510889253">Ei</translation>
<translation id="4253168017788158739">Huomautus</translation>
<translation id="425582637250725228">Tekemiäsi muutoksia ei välttämättä tallenneta.</translation>
+<translation id="425869179292622354">Tehdäänkö siitä turvallisempi virtuaalisella kortilla?</translation>
<translation id="4258748452823770588">Virheellinen allekirjoitus</translation>
<translation id="4261046003697461417">Suojattuihin asiakirjoihin ei voi tehdä merkintöjä</translation>
<translation id="4265872034478892965">Järjestelmänvalvojan sallima</translation>
@@ -1099,6 +1133,7 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="4434045419905280838">Ponn.ikkunat ja uudelleenohjaus</translation>
<translation id="4435702339979719576">Postikortti</translation>
<translation id="443673843213245140">Välityspalvelinta ei saa käyttää, mutta erilliset välityspalvelimen asetukset on määritetty.</translation>
+<translation id="4441832193888514600">Ohitettu, koska käytäntö voidaan asettaa vain pilvikäyttäjäkäytäntönä.</translation>
<translation id="4450893287417543264">Älä näytä uudelleen</translation>
<translation id="4451135742916150903">Saa pyytää lupaa yhdistää HID-laitteisiin</translation>
<translation id="4452328064229197696">Juuri käyttämäsi salasana löytyi tietosuojaloukkauksesta. Tiliesi suojaamiseksi Googlen Salasanojen ylläpito suosittelee, että tarkistat tallennetut salasanasi.</translation>
@@ -1154,6 +1189,7 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="4628948037717959914">Kuva</translation>
<translation id="4631649115723685955">Hyvitystarjous linkitetty</translation>
<translation id="4636930964841734540">Tietoja</translation>
+<translation id="4638670630777875591">Chromiumin incognito-tila</translation>
<translation id="464342062220857295">Hakutoiminnot</translation>
<translation id="4644670975240021822">Käänteinen järjestys tulostuspuoli alaspäin</translation>
<translation id="4646534391647090355">Siirry nyt</translation>
@@ -1174,6 +1210,7 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="4708268264240856090">Yhteys keskeytyi</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Windowsin verkon diagnostiikkaa<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426">Salasana: <ph name="USERNAME" /></translation>
<translation id="4724144314178270921">Saa pyytää leikepöydällä olevan tekstin ja kuvien näkemistä</translation>
<translation id="4726672564094551039">Päivitä käytännöt</translation>
<translation id="4728558894243024398">Käyttöympäristö</translation>
@@ -1195,6 +1232,7 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="4757993714154412917">Lisäsit juuri salasanasi petolliselle sivustolle. Chromium suosittelee tarkistamaan tallennetut salasanasi tilisi suojaamiseksi.</translation>
<translation id="4758311279753947758">Lisää yhteystiedot</translation>
<translation id="4761104368405085019">Käyttää mikrofonia</translation>
+<translation id="4761869838909035636">Tee Chromen turvatarkistus</translation>
<translation id="4764776831041365478">Osoitteessa <ph name="URL" /> oleva sivu saattaa olla väliaikaisesti pois käytöstä tai se on voitu siirtää pysyvästi uuteen osoitteeseen.</translation>
<translation id="4766713847338118463">Kaksi niittiä alareunassa</translation>
<translation id="4771973620359291008">Tapahtui tuntematon virhe.</translation>
@@ -1215,12 +1253,6 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="4819347708020428563">Muokataanko merkintöjä oletusnäkymässä?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />, luo uusi Google-taulukko nopeasti painamalla sarkainta ja sitten Enter</translation>
<translation id="4825507807291741242">Tehokas</translation>
-<translation id="4827402517081186284">Incognito ei muuta sinua näkymättömäksi verkossa:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Sivustot tietävät, kun käyt niillä<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Työnantajat tai koulut voivat seurata selaustoimintaa<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Internetpalveluntarjoajat voivat valvoa verkkoliikennettä<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">Laita varoitukset päälle</translation>
<translation id="4838327282952368871">Unenomainen</translation>
<translation id="4840250757394056958">Tarkista Chrome-historiasi</translation>
@@ -1232,12 +1264,12 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="4854362297993841467">Tämä toimitustapa ei ole käytettävissä. Kokeile toista tapaa.</translation>
<translation id="4854853140771946034">Luo uusi muistiinpano nopeasti Google Keepissa</translation>
<translation id="485902285759009870">Vahvistetaan koodia…</translation>
+<translation id="4866506163384898554">Näytä kohdistin painamalla |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />|</translation>
<translation id="4876188919622883022">Yksinkertaistettu näkymä</translation>
<translation id="4876305945144899064">Ei käyttäjänimeä</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{Ei mitään}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831">Haku <ph name="TEXT" /></translation>
<translation id="4879491255372875719">Automaattinen (oletus)</translation>
-<translation id="4879725228911483934">Avaa ikkunat ja sijoittele ne näytöille</translation>
<translation id="4880827082731008257">Haku historiasta</translation>
<translation id="4881695831933465202">Avaa</translation>
<translation id="4885256590493466218">Käytä <ph name="CARD_DETAIL" /> ‑maksutapaa kassalla.</translation>
@@ -1246,6 +1278,7 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">Yhdeksäs rulla</translation>
<translation id="4901778704868714008">Tallenna…</translation>
+<translation id="4905659621780993806">Järjestelmänvalvojasi käynnistää laitteen uudelleen automaattisesti <ph name="DATE" /> kello <ph name="TIME" />. Tallenna avoimet kohteet, ennen kuin laite käynnistyy uudelleen.</translation>
<translation id="4913987521957242411">Reikä vasemmassa yläkulmassa</translation>
<translation id="4918221908152712722">Asenna <ph name="APP_NAME" /> (ei vaadi lataamista)</translation>
<translation id="4923459931733593730">Maksu</translation>
@@ -1254,6 +1287,7 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, tee haku painamalla ensin sarkainta ja sitten Enter</translation>
<translation id="4930153903256238152">Suuri kapasiteetti</translation>
+<translation id="4940163644868678279">Chromen incognito-tila</translation>
<translation id="4943872375798546930">Ei tuloksia</translation>
<translation id="4950898438188848926">Välilehden vaihtopainike, siirry avoimelle välilehdelle painamalla Enter, <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="495170559598752135">Toiminnot</translation>
@@ -1263,6 +1297,7 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="4968522289500246572">Sovellus on suunniteltu mobiililaitteille eikä se ehkä näy oikein, jos muutat sen kokoa. Sovellus voi käynnistyä uudelleen tai siinä voi esiintyä ongelmia.</translation>
<translation id="4969341057194253438">Poista tallenne</translation>
<translation id="4973922308112707173">Kaksi reikää yläreunassa</translation>
+<translation id="4976702386844183910">Viimeksi avattu <ph name="DATE" /></translation>
<translation id="4984088539114770594">Käytetäänkö mikrofonia?</translation>
<translation id="4984339528288761049">Prc5 (kirjekuori)</translation>
<translation id="4989163558385430922">Näytä kaikki</translation>
@@ -1324,6 +1359,7 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="5138227688689900538">Näytä vähemmän</translation>
<translation id="5145883236150621069">Käytäntövastaus sisältää virhekoodin</translation>
<translation id="5146995429444047494">Ilmoitukset on estetty: <ph name="ORIGIN" /></translation>
+<translation id="514704532284964975"><ph name="URL" /> pyytää lupaa nähdä ja muuttaa puhelimella napauttamiesi NFC-laitteiden tietoja</translation>
<translation id="5148809049217731050">Tulostuspuoli ylöspäin</translation>
<translation id="515292512908731282">C4 (kirjekuori)</translation>
<translation id="5158275234811857234">Kansi</translation>
@@ -1348,6 +1384,7 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="5215116848420601511">Maksutavat ja osoitteet Google Paysta</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">Lokero 13</translation>
+<translation id="5216942107514965959">Viimeksi avattu tänään</translation>
<translation id="5222812217790122047">Sähköposti vaaditaan</translation>
<translation id="5230733896359313003">Toimitusosoite</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1368,7 +1405,6 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">Asiakirjan ominaisuudet</translation>
<translation id="528468243742722775">Loppu</translation>
-<translation id="5284909709419567258">Verkko-osoitteet</translation>
<translation id="5285570108065881030">Näytä kaikki tallennetut salasanat</translation>
<translation id="5287240709317226393">Näytä evästeet</translation>
<translation id="5287456746628258573">Tämä sivusto käyttää vanhentunutta tietoturvamääritystä, joka voi paljastaa tietosi (esim. salasanat tai credit-korttien numerot), kun ne lähetetään sivustolle.</translation>
@@ -1451,7 +1487,8 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="5552137475244467770">Chrome vertaa salasanojasi säännöllisesti listoihin salasanoista, jotka on julkaistu verkossa. Tätä varten salasanat ja käyttäjänimet salataan, joten kukaan (myöskään Google) ei voi lukea niitä.</translation>
<translation id="5556459405103347317">Lataa uudelleen</translation>
<translation id="5560088892362098740">Viimeinen voimassaolopäivä</translation>
-<translation id="55635442646131152">Dokumentin yleiskatsaus</translation>
+<translation id="55635442646131152">Dokumentin asettelu</translation>
+<translation id="5565613213060953222">Avaa incognito-välilehti</translation>
<translation id="5565735124758917034">Aktiivinen</translation>
<translation id="5570825185877910964">Suojaa tili</translation>
<translation id="5571083550517324815">Nouto tästä osoitteesta ei onnistu. Valitse eri osoite.</translation>
@@ -1534,6 +1571,7 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="5869522115854928033">Tallennetut salasanat</translation>
<translation id="5873013647450402046">Pankkisi edellyttää henkilöllisyytesi vahvistamista.</translation>
<translation id="5887400589839399685">Kortti tallennettu</translation>
+<translation id="5887687176710214216">Avattu viimeksi eilen</translation>
<translation id="5895138241574237353">Käynnistä uudelleen</translation>
<translation id="5895187275912066135">Myönnetty</translation>
<translation id="5901630391730855834">Keltainen</translation>
@@ -1547,6 +1585,7 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="5921639886840618607">Tallennetaanko kortti Google-tilille?</translation>
<translation id="5922853866070715753">Lähes valmis</translation>
<translation id="5932224571077948991">Sivustolla on häiritseviä tai harhaanjohtavia mainoksia</translation>
+<translation id="5938153366081463283">Lisää virtuaalinen kortti</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347">Avataan <ph name="SITE_NAME" />…</translation>
<translation id="5951495562196540101">Liittyminen kuluttajatilillä ei onnistu (pakettilisenssi saatavilla).</translation>
@@ -1611,6 +1650,7 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="6120179357481664955">Muistatko UPI-tunnuksesi?</translation>
<translation id="6124432979022149706">Chrome Enterprise Connectors</translation>
<translation id="6127379762771434464">Kohde poistettu</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Lue lisää Chromen incognito-tilasta<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">Tarkista kaikki kaapelit ja käynnistä uudelleen reitittimet, modeemit ja muut
käytössä olevat verkkolaitteet.</translation>
<translation id="614940544461990577">Kokeile seuraavia toimenpiteitä:</translation>
@@ -1623,7 +1663,6 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="6169916984152623906">Nyt voit selata verkkoa yksityisesti. Laitteen muut käyttäjät eivät näe selaushistoriaasi. Lataukset ja kirjanmerkit kuitenkin tallennetaan.</translation>
<translation id="6177128806592000436">Sivustoon ei ole muodostettu turvallista yhteyttä.</translation>
<translation id="6180316780098470077">Uudelleenyritysten aikaväli</translation>
-<translation id="619448280891863779">Saa pyytää lupaa avata ikkunoita ja sijoittaa niitä näytöillesi</translation>
<translation id="6196640612572343990">Estä kolmannen osapuolen evästeet</translation>
<translation id="6203231073485539293">Tarkista internetyhteytesi</translation>
<translation id="6218753634732582820">Poistetaanko osoite Chromiumista?</translation>
@@ -1646,7 +1685,7 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="6272383483618007430">Google-päivitys</translation>
<translation id="6276112860590028508">Lukulistasi sivuja tulee näkyviin tänne.</translation>
<translation id="627746635834430766">Jos haluat maksaa nopeammin ensi kerralla, tallenna kortti ja laskutusosoite Google-tilillesi.</translation>
-<translation id="6279098320682980337">Eikö virtuaalista korttinumeroa ole täytetty? Kopioi kortin tiedot klikkaamalla</translation>
+<translation id="6279183038361895380">Näytä kursori painamalla |<ph name="ACCELERATOR" />|.</translation>
<translation id="6280223929691119688">Toimitus ei onnistu tähän osoitteeseen. Valitse eri osoite.</translation>
<translation id="6282194474023008486">Postinumero</translation>
<translation id="6285507000506177184">Ylläpidä latauksia Chromessa ‑painike, ylläpidä Chromessa lataamiasi tiedostoja painamalla Enter</translation>
@@ -1654,6 +1693,7 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="6290238015253830360">Suositellut artikkelit näkyvät tässä.</translation>
<translation id="6293309776179964942">JIS B5 (182 mm x 257 mm)</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{Laitteesi käynnistyy uudelleen nyt}=1{Laitteesi käynnistyy uudelleen 1 sekunnin kuluttua}other{Laitteesi käynnistyy uudelleen # sekunnin kuluttua}}</translation>
<translation id="6302269476990306341">Chromen Google Assistant suljetaan</translation>
<translation id="6305205051461490394">Sivustoon <ph name="URL" /> ei saada yhteyttä.</translation>
<translation id="6312113039770857350">Verkkosivu ei ole saatavilla</translation>
@@ -1727,6 +1767,7 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="6529602333819889595">&amp;Toista poisto</translation>
<translation id="6545864417968258051">Bluetooth-haku</translation>
<translation id="6547208576736763147">Kaksi reikää vasemmalla</translation>
+<translation id="6554732001434021288">Viimeksi avattu <ph name="NUM_DAYS" /> päivää sitten</translation>
<translation id="6556866813142980365">Tee uudelleen</translation>
<translation id="6569060085658103619">Tämä on laajennussivu.</translation>
<translation id="6573200754375280815">Kaksi reikää oikealla</translation>
@@ -1787,7 +1828,6 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="6757797048963528358">Laitteesi siirtyi virransäästötilaan.</translation>
<translation id="6767985426384634228">Päivitetäänkö osoite?</translation>
<translation id="6768213884286397650">Hagaki (postikortti)</translation>
-<translation id="6774185088257932239"><ph name="BEGIN_LINK" />Lue lisää<ph name="END_LINK" /> incognitosta</translation>
<translation id="6775759552199460396">JIS B2 (515 mm x 728 mm)</translation>
<translation id="67862343314499040">Lila</translation>
<translation id="6786747875388722282">Laajennukset</translation>
@@ -1871,7 +1911,6 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="706295145388601875">Lisää ja muuta osoitteita Chromen asetuksista</translation>
<translation id="7064851114919012435">Yhteystiedot</translation>
<translation id="7068733155164172741">Lisää <ph name="OTP_LENGTH" />-numeroinen koodi</translation>
-<translation id="7070090581017165256">Tietoja tästä sivustosta</translation>
<translation id="70705239631109039">Yhteytesi ei ole täysin suojattu</translation>
<translation id="7075452647191940183">Pyyntö on liian suuri</translation>
<translation id="7079718277001814089">Tämä sivusto sisältää haittaohjelmia</translation>
@@ -1888,6 +1927,12 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="7111012039238467737">(Voimassa)</translation>
<translation id="7118618213916969306">Hae leikepöydän URL-osoitetta, <ph name="SHORT_URL" /></translation>
<translation id="7119414471315195487">Sulje muita välilehtiä tai ohjelmia.</translation>
+<translation id="7129355289156517987">Kun suljet kaikki Chromiumin incognito-välilehdet, toimintasi kyseisillä välilehdillä tyhjennetään tältä laitteelta:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Selaustoiminta<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Hakuhistoria<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Lomakkeille lisätyt tiedot<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">Lähetys tähän osoitteeseen ei onnistu. Valitse eri osoite.</translation>
<translation id="7132939140423847331">Järjestelmänvalvojasi on kieltänyt tämän datan kopioimisen.</translation>
<translation id="7135130955892390533">Näytä tila</translation>
@@ -1910,6 +1955,7 @@ Muussa tapauksessa tämä estetään tietosuoja-asetuksilla. Jos sallit tämän,
<translation id="7192203810768312527">Vapauttaa <ph name="SIZE" />. Jotkin sivustot saattavat latautua hitaammin seuraavalla käynnillä.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">Järjestelmänvalvoja näkee seuraavat:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, paina ensin sarkainta ja sitten Enter avataksesi uuden incognito-välilehden, niin voit selata yksityisesti</translation>
<translation id="7202346780273620635">Kirje-ekstra</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> ei noudata tietoturvastandardeja.</translation>
<translation id="7210993021468939304">Linux-toiminta säilön sisällä, ja voi asentaa ja suorittaa Linux-sovelluksia säilön sisällä</translation>
@@ -1941,6 +1987,7 @@ Lisätietoja:
<translation id="7304562222803846232">Tarkista Google-tilin yksityisyysasetukset</translation>
<translation id="7305756307268530424">Aloita hitaampana</translation>
<translation id="7308436126008021607">taustasynkronointi</translation>
+<translation id="7310392214323165548">Laite käynnistyy pian uudelleen</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">Yhteysohjeet</translation>
<translation id="7323804146520582233">Piilota osio <ph name="SECTION" /></translation>
@@ -1948,6 +1995,7 @@ Lisätietoja:
<translation id="7334320624316649418">&amp;Toista uudelleenjärjestely</translation>
<translation id="7335157162773372339">Saa pyytää kameran käyttölupaa</translation>
<translation id="7337248890521463931">Näytä enemmän rivejä</translation>
+<translation id="7337418456231055214">Eikö virtuaalista korttinumeroa ole täytetty? Kopioi kortin tiedot klikkaamalla niitä. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">Ei saatavilla käyttöympäristössäsi</translation>
<translation id="733923710415886693">Palvelimen varmenteesta ei ole saatu Certificate Transparencyn vaatimia tietoja.</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1970,6 +2018,7 @@ Lisätietoja:
<translation id="7378627244592794276">Ei</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">Ei sovellu</translation>
+<translation id="7388594495505979117">{0,plural, =1{Laitteesi käynnistyy uudelleen 1 minuutin kuluttua}other{Laitteesi käynnistyy uudelleen # minuutin kuluttua}}</translation>
<translation id="7390545607259442187">Vahvista kortti</translation>
<translation id="7392089738299859607">Päivitä osoite</translation>
<translation id="7399802613464275309">Turvatarkistus</translation>
@@ -2006,6 +2055,12 @@ Lisätietoja:
<translation id="7485870689360869515">Tietoja ei löydy.</translation>
<translation id="7495528107193238112">Tämä sisältö on estetty. Pyydä sivuston omistajalta apua ongelman korjaamiseen.</translation>
<translation id="7497998058912824456">Luo dokumentti ‑painike, luo uusi Google-dokumentti nopeasti painamalla Enter</translation>
+<translation id="7506488012654002225">Chromium <ph name="BEGIN_EMPHASIS" />ei tallenna<ph name="END_EMPHASIS" /> näitä tietoja:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Selaushistoriasi
+ <ph name="LIST_ITEM" />Evästeet ja sivustodata
+ <ph name="LIST_ITEM" />Lomakkeisiin syötetyt tiedot
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">Palautettu käytännön laitetunnus on tyhjä tai ei vastaa nykyistä laitetunnusta.</translation>
<translation id="7508870219247277067">Avokadonvihreä</translation>
<translation id="7511955381719512146">Käyttämäsi Wi-Fi saattaa edellyttää vierailua osoitteessa <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
@@ -2119,7 +2174,6 @@ Lisätietoja:
<translation id="7813600968533626083">Poistetaanko lomake-ehdotus Chromen tiedoista?</translation>
<translation id="781440967107097262">Jaetaanko leikepöytä?</translation>
<translation id="7815407501681723534">Haku <ph name="SEARCH_STRING" /> tuotti <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" />.</translation>
-<translation id="782125616001965242">Näytä tietoja tästä sivustosta</translation>
<translation id="782886543891417279">Käyttämäsi Wi-Fi (<ph name="WIFI_NAME" />) saattaa edellyttää kirjautumista.</translation>
<translation id="7836231406687464395">Postfix (kirjekuori)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{Ei mitään}=1{1 sovellus (<ph name="EXAMPLE_APP_1" />)}=2{2 sovellusta (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}other{# sovellusta (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" /> <ph name="AND_MORE" />)}}</translation>
@@ -2136,7 +2190,6 @@ Lisätietoja:
<translation id="7888575728750733395">Tulosteen renderöintitavoite</translation>
<translation id="7894280532028510793">Jos kirjoitusasu on oikein, <ph name="BEGIN_LINK" />kokeile verkon diagnostiikkaa<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (kirjekuori)</translation>
-<translation id="7931318309563332511">Tuntematon</translation>
<translation id="793209273132572360">Päivitetäänkö osoite?</translation>
<translation id="7932579305932748336">Päällystys</translation>
<translation id="79338296614623784">Anna kelvollinen puhelinnumero.</translation>
@@ -2161,13 +2214,14 @@ Lisätietoja:
<translation id="7976214039405368314">Liikaa pyyntöjä</translation>
<translation id="7977538094055660992">Tulostuslaite</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">Linkitetty kohteeseen</translation>
<translation id="798134797138789862">Saa pyytää virtuaalitodellisuuslaitteiden ja ‑datan käyttölupaa</translation>
<translation id="7984945080620862648">Et voi siirtyä sivustoon <ph name="SITE" /> juuri nyt, koska sivusto lähetti sekoitetut tiedot, joita Chrome ei voi käsitellä. Verkkovirheet ja hyökkäykset ovat yleensä väliaikaisia, joten sivu luultavasti toimii myöhemmin.</translation>
-<translation id="79859296434321399">Asenna ARCore, niin voit nähdä AR-sisältöä.</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">Sidonta</translation>
<translation id="7992044431894087211">Näytön jakamista (<ph name="APPLICATION_TITLE" />) jatkettu</translation>
<translation id="7995512525968007366">Ei määritetty</translation>
+<translation id="7998269595945679889">Avaa incognito-välilehti ‑painike, paina Enter avataksesi uuden incognito-välilehden, niin voit selata yksityisesti</translation>
<translation id="800218591365569300">Yritä vapauttaa muistia sulkemalla muita välilehtiä tai ohjelmia.</translation>
<translation id="8004582292198964060">Selain</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{Tämä kortti ja sen laskutusosoite tallennetaan. Voit käyttää sitä sisäänkirjautuneena (<ph name="USER_EMAIL" />).}other{Nämä kortit ja niiden laskutusosoitteet tallennetaan. Voit käyttää niitä sisäänkirjautuneena (<ph name="USER_EMAIL" />).}}</translation>
@@ -2227,6 +2281,7 @@ Lisätietoja:
<translation id="8202370299023114387">Ristiriita</translation>
<translation id="8206978196348664717">Prc4 (kirjekuori)</translation>
<translation id="8211406090763984747">Yhteys on turvallinen</translation>
+<translation id="8217240300496046857">Sivustot eivät voi seurata sinua verkossa evästeiden avulla Joidenkin sivustojen ominaisuudet saattavat lakata toimimasta.</translation>
<translation id="8218327578424803826">Määrätty sijainti:</translation>
<translation id="8220146938470311105">C7/C6 (kirjekuori)</translation>
<translation id="8225771182978767009">Tämän tietokoneen määrittänyt henkilö on estänyt tämän sivuston.</translation>
@@ -2267,14 +2322,9 @@ Lisätietoja:
<translation id="830498451218851433">Keskitaite</translation>
<translation id="8307358339886459768">Pieni kuva</translation>
<translation id="8307888238279532626">Asennetut sovellukset ja se, miten usein niitä käytetään</translation>
+<translation id="8317207217658302555">Päivitetäänkö ARCore?</translation>
<translation id="831997045666694187">Ilta</translation>
<translation id="8321476692217554900">ilmoitukset</translation>
-<translation id="8328484624016508118">Suljettuasi kaikki incognito-välilehdet Chrome poistaa:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Selaustoimintasi tältä laitteelta<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Hakuhistoriasi tältä laitteelta<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Lomakkeisiin lisäämäsi tiedot<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489">Sivuston <ph name="HOST_NAME" /> käyttöoikeus evättiin</translation>
<translation id="833262891116910667">Korosta</translation>
<translation id="8339163506404995330">Kielellä <ph name="LANGUAGE" /> kirjoitettuja sivuja ei käännetä.</translation>
@@ -2326,6 +2376,7 @@ Lisätietoja:
<translation id="8507227106804027148">Komentorivi</translation>
<translation id="8508648098325802031">Hakukuvake</translation>
<translation id="8511402995811232419">Ylläpidä evästeitä</translation>
+<translation id="8519753333133776369">Järjestelmänvalvojan sallima HID-laite</translation>
<translation id="8522552481199248698">Chrome voi auttaa suojaamaan Google-tiliäsi ja vaihtamaan salasanasi.</translation>
<translation id="8530813470445476232">Tyhjennä selaushistoria, evästeet, välimuisti ja muita tietoja Chromen asetuksista</translation>
<translation id="8533619373899488139">Voit nähdä estetyt URL-osoitteet ja muut järjestelmänvalvojasi määräämät käytännöt osoitteessa &lt;strong&gt;chrome://policy&lt;/strong&gt;.</translation>
@@ -2337,7 +2388,6 @@ Lisätietoja:
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{Nollaa lupa}other{Nollaa luvat}}</translation>
<translation id="8555010941760982128">Käytä kassalla tätä koodia</translation>
<translation id="8557066899867184262">CVC sijaitsee kortin takapuolella.</translation>
-<translation id="8558485628462305855">Päivitä ARCore, niin voit nähdä AR-sisältöä.</translation>
<translation id="8559762987265718583">Verkkotunnukseen <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> ei voi muodostaa salattua yhteyttä, koska laitteesi aika ja päivämäärä (<ph name="DATE_AND_TIME" />) ovat virheelliset.</translation>
<translation id="8564182942834072828">Erilliset dokumentit / Kokoamattomat kopiot</translation>
<translation id="8564985650692024650">Chromium suosittelee organisaation <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> salasanasi vaihtamista, jos olet käyttänyt sitä myös muilla sivustoilla.</translation>
@@ -2357,6 +2407,7 @@ Lisätietoja:
<translation id="865032292777205197">liiketunnistimet</translation>
<translation id="8663226718884576429">Tilauksen yhteenveto, <ph name="TOTAL_LABEL" />, lisätietoja</translation>
<translation id="8666678546361132282">englanti</translation>
+<translation id="8669306706049782872">käyttää tietoja näytöistäsi ikkunoiden avaamiseksi ja sijoittamiseksi</translation>
<translation id="867224526087042813">Allekirjoitus</translation>
<translation id="8676424191133491403">Ei viivettä</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, vastaus, <ph name="ANSWER" /></translation>
@@ -2383,6 +2434,7 @@ Lisätietoja:
<translation id="8731544501227493793">Ylläpidä salasanoja ‑painike, katso ja ylläpidä salasanoja Chromen asetuksissa painamalla Enter</translation>
<translation id="8734529307927223492"><ph name="MANAGER" /> ylläpitää laitetta (<ph name="DEVICE_TYPE" />)</translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, paina ensin sarkainta ja sitten Enter avataksesi uuden incognito-ikkunan, niin voit selata yksityisesti</translation>
+<translation id="8737685506611670901">Avata <ph name="PROTOCOL" />-linkit palvelun <ph name="REPLACED_HANDLER_TITLE" /> sijaan.</translation>
<translation id="8738058698779197622">Kellosi täytyy asettaa oikeaan aikaan, jotta salattu yhteys voidaan muodostaa. Tämä johtuu siitä, että verkkosivustojen tunnistamisessa käytettävät varmenteet ovat voimassa vain tiettyinä ajanjaksoina. Chromium ei voi vahvistaa varmenteita, koska laitteesi kello on väärässä ajassa.</translation>
<translation id="8740359287975076522">Sivuston <ph name="HOST_NAME" /> &lt;abbr id="dnsDefinition"&gt;DNS-osoitetta&lt;/abbr&gt; ei löydy. Ongelmaa diagnosoidaan.</translation>
<translation id="8742371904523228557">Koodisi on <ph name="ONE_TIME_CODE" /> (<ph name="ORIGIN" />)</translation>
@@ -2410,6 +2462,7 @@ Lisätietoja:
<translation id="883848425547221593">Muut kirjanmerkit</translation>
<translation id="884264119367021077">Toimitusosoite</translation>
<translation id="884923133447025588">Kumoamisjärjestelmää ei löytynyt.</translation>
+<translation id="8849262850971482943">Paranna suojausta virtuaalikortilla</translation>
<translation id="885730110891505394">Googlen kanssa jakaminen</translation>
<translation id="8858065207712248076">Chrome suosittelee organisaation <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> salasanasi vaihtamista, jos olet käyttänyt sitä myös muilla sivustoilla.</translation>
<translation id="885906927438988819">Jos kirjoitusasu on oikein, <ph name="BEGIN_LINK" />kokeile Windowsin verkon diagnostiikkaa<ph name="END_LINK" />.</translation>
@@ -2459,6 +2512,7 @@ Lisätietoja:
<translation id="9004367719664099443">VR-käyttökerta on käynnissä</translation>
<translation id="9005998258318286617">PDF-asiakirjan lataaminen epäonnistui.</translation>
<translation id="9008201768610948239">Ohita</translation>
+<translation id="901834265349196618">sähköposti</translation>
<translation id="9020200922353704812">Kortin laskutusosoite pakollinen</translation>
<translation id="9020542370529661692">Sivu on käännetty kielelle <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9020742383383852663">A8</translation>
@@ -2507,6 +2561,7 @@ Lisätietoja:
<translation id="9150045010208374699">Käyttää kameraa</translation>
<translation id="9150685862434908345">Järjestelmänvalvoja voi muuttaa selaimen määrityksiä etäyhteydellä. Toimintaa tällä laitteella saatetaan ylläpitää myös Chromen ulkopuolelta. <ph name="BEGIN_LINK" />Lue lisää<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">Päivitetty</translation>
+<translation id="9155211586651734179">Yhdistetyt audiolisälaitteet</translation>
<translation id="9157595877708044936">Valmistellaan...</translation>
<translation id="9158625974267017556">C6 (kirjekuori)</translation>
<translation id="9164029392738894042">Tarkkuuden tarkistaminen</translation>
diff --git a/chromium/components/strings/components_strings_fil.xtb b/chromium/components/strings/components_strings_fil.xtb
index e599061d5c0..86438d3e0f8 100644
--- a/chromium/components/strings/components_strings_fil.xtb
+++ b/chromium/components/strings/components_strings_fil.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">Tingnan ang mga detalye</translation>
<translation id="1030706264415084469">Gusto ng <ph name="URL" /> na permanenteng mag-store ng malaking data sa iyong device</translation>
<translation id="1032854598605920125">I-rotate pakanan</translation>
+<translation id="1033329911862281889">Hindi ka ginagawang invisible ng Incognito online:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Nakakakita ng mga pagbisita ang mga site at serbisyong ginagamit nila<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Nakaka-track ng aktibidad sa pag-browse ang mga employer o paaralan<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Nasusubaybayan ng mga internet service provider ang trapiko sa web<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">I-off</translation>
<translation id="1036982837258183574">Pindutin ang |<ph name="ACCELERATOR" />| upang lumabas sa full screen</translation>
<translation id="1038106730571050514">Ipakita ang mga suhestyon</translation>
<translation id="1038842779957582377">Hindi kilalang pangalan</translation>
<translation id="1041998700806130099">Mensahe sa sheet ng trabaho</translation>
<translation id="1048785276086539861">Kapag nag-edit ka ng mga anotasyon, babalik ang dokumentong ito sa isang page na view</translation>
-<translation id="1049743911850919806">Incognito</translation>
<translation id="1050038467049342496">Isara ang iba pang app</translation>
<translation id="1055184225775184556">&amp;I-undo ang Pagdagdag</translation>
<translation id="1056898198331236512">Babala</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">OK ang cache ng patakaran</translation>
<translation id="1130564665089811311">Button na Isalin ang page, pindutin ang Enter para isalin ang page na ito gamit ang Google Translate</translation>
<translation id="1131264053432022307">Larawang Kinopya Mo</translation>
+<translation id="1142846828089312304">I-block ang third party na cookies sa Incognito</translation>
<translation id="1150979032973867961">Hindi mapatunayan ng server na ito na ito ay <ph name="DOMAIN" />; hindi pinagkakatiwalaan ng operating system ng iyong computer ang certificate ng seguridad nito. Maaaring dulot ito ng maling configuration o isang umaatake na hinahadlangan ang iyong koneksyon.</translation>
<translation id="1151972924205500581">Kinakailangan ang password</translation>
<translation id="1156303062776767266">Tumitingin ka ng lokal o nakabahaging file</translation>
@@ -64,7 +70,6 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="1178581264944972037">I-pause</translation>
<translation id="1181037720776840403">Alisin</translation>
<translation id="1186201132766001848">Suriin ang mga Password</translation>
-<translation id="1195210374336998651">Pumunta sa mga setting ng app</translation>
<translation id="1195558154361252544">Awtomatikong naka-block ang mga notification para sa lahat ng site maliban sa mga pinapayagan mo</translation>
<translation id="1197088940767939838">Orange</translation>
<translation id="1201402288615127009">Susunod</translation>
@@ -111,7 +116,7 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="1307966114820526988">Mga Hindi na Ginagamit na Feature</translation>
<translation id="1308113895091915999">Available ang alok</translation>
<translation id="1312803275555673949">Anong ebidensya ang sumusuporta rito?</translation>
-<translation id="131405271941274527">Gusto ng <ph name="URL" /> na magpadala at makatanggap ng impormasyon kapag na-tap mo ang iyong telepono sa isang NFC device</translation>
+<translation id="1314311879718644478">Tingnan ang augmented reality na content</translation>
<translation id="1314509827145471431">Bind right</translation>
<translation id="1318023360584041678">Na-save sa grupo ng tab</translation>
<translation id="1319245136674974084">Huwag nang magtanong ulit para sa app na ito</translation>
@@ -161,6 +166,7 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="142858679511221695">User ng Cloud</translation>
<translation id="1428729058023778569">Nakikita mo ang babalang ito dahil hindi sinusuportahan ng site na ito ang HTTPS. <ph name="BEGIN_LEARN_MORE_LINK" />Matuto pa<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">I-print</translation>
+<translation id="1432187715652018471">Gusto ng page na mag-install ng tagapangasiwa ng serbisyo.</translation>
<translation id="1432581352905426595">Pamahalaan ang mga search engine</translation>
<translation id="1436185428532214179">Puwedeng hilinging mag-edit ng mga file at folder sa iyong device</translation>
<translation id="1442386063175183758">Right gate fold</translation>
@@ -181,6 +187,12 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="1483493594462132177">Ipadala</translation>
<translation id="1484290072879560759">Pumili ng Address sa Pagpapadala</translation>
<translation id="1492194039220927094">Pag-push ng mga patakaran:</translation>
+<translation id="149293076951187737">Kapag isinara mo ang lahat ng tab na Incognito sa Chrome, maki-clear mula sa device na ito ang iyong aktibidad sa mga tab na iyon:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Aktibidad sa pag-browse<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />History ng paghahanap<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Impormasyong inilagay sa mga form<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">Bumalik sa tab</translation>
<translation id="1501859676467574491">Ipakita ang mga card mula sa iyong Google Account</translation>
<translation id="1507202001669085618">&lt;p&gt;Makikita mo ang error na ito kung gumagamit ka ng Wi-Fi portal kung saan kailangan mong mag-sign in bago ka makapag-online.&lt;/p&gt;
@@ -208,6 +220,8 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="1559572115229829303">&lt;p&gt;Hindi makapagtatag ng pribadong koneksyon sa <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> dahil mali ang petsa at oras ng iyong device (<ph name="DATE_AND_TIME" />).&lt;/p&gt;
&lt;p&gt;Mangyaring isaayos ang petsa at oras mula sa seksyong &lt;strong&gt;Pangkalahatan&lt;/strong&gt; ng app na &lt;strong&gt;Mga Setting&lt;/strong&gt;.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">Ire-restart ng iyong administrator ang device mo nang <ph name="TIME" /> sa <ph name="DATE" /></translation>
+<translation id="156703335097561114">Impormasyon ng networking gaya ng mga address, configuration ng interface, at kalidad ng koneksyon</translation>
<translation id="1567040042588613346">Gumagana ang patakarang ito tulad ng inaasahan pero itinatakda ang kaparehong value sa ibang lugar at nasasapawan ito ng patakarang ito.</translation>
<translation id="1569487616857761740">Ilagay ang petsa ng pag-expire</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="1583429793053364125">Nagkaproblema habang ipinapakita ang webpage na ito.</translation>
<translation id="1586541204584340881">Aling mga extension ang na-install mo</translation>
<translation id="1588438908519853928">Normal</translation>
+<translation id="1589050138437146318">I-install ang ARCore?</translation>
<translation id="1592005682883173041">Access sa Lokal na Data</translation>
<translation id="1594030484168838125">Pumili</translation>
<translation id="160851722280695521">Laruin ang Dino Run sa Chrome</translation>
@@ -283,6 +298,7 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
sira ang header, na pumipigil sa browser na matugunan
ang iyong kahilingan para sa <ph name="SITE" />. Magagamit ng mga operator ng site ang mga patakaran ng
pinagmulan para i-configure ang seguridad at iba pang property para sa isang site.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Matuto pa tungkol sa Incognito sa Chromium<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">Lalabas dito ang iyong mga bukas na tab</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -359,7 +375,7 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="204357726431741734">Mag-sign in para magamit ang mga naka-save na password sa iyong Google Account</translation>
<translation id="2053111141626950936">Hindi ita-translate ang mga page na nasa <ph name="LANGUAGE" />.</translation>
<translation id="2053373601901562871">{NUM_DAYS,plural, =0{Kapag naka-on ang kontrol na ito at aktibo ang status, tinutukoy ng Chrome kung aling malaking grupo ng mga tao, o "cohort," ang pinakakatulad ng iyong kamakailang aktibidad sa pag-browse. Makakapili ang mga advertiser ng mga ad para sa grupo at pinapanatiling pribado sa iyong device ang aktibidad mo sa pag-browse. Ina-update ang iyong grupo araw-araw.}=1{Kapag naka-on ang kontrol na ito at aktibo ang status, tinutukoy ng Chrome kung aling malaking grupo ng mga tao, o "cohort," ang pinakakatulad ng iyong kamakailang aktibidad sa pag-browse. Makakapili ang mga advertiser ng mga ad para sa grupo at pinapanatiling pribado sa iyong device ang aktibidad mo sa pag-browse. Ina-update ang iyong grupo araw-araw.}one{Kapag naka-on ang kontrol na ito at aktibo ang status, tinutukoy ng Chrome kung aling malaking grupo ng mga tao, o "cohort," ang pinakakatulad ng iyong kamakailang aktibidad sa pag-browse. Makakapili ang mga advertiser ng mga ad para sa grupo at pinapanatiling pribado sa iyong device ang aktibidad mo sa pag-browse. Ina-update ang iyong grupo kada {NUM_DAYS} araw.}other{Kapag naka-on ang kontrol na ito at aktibo ang status, tinutukoy ng Chrome kung aling malaking grupo ng mga tao, o "cohort," ang pinakakatulad ng iyong kamakailang aktibidad sa pag-browse. Makakapili ang mga advertiser ng mga ad para sa grupo at pinapanatiling pribado sa iyong device ang aktibidad mo sa pag-browse. Ina-update ang iyong grupo kada {NUM_DAYS} na araw.}}</translation>
-<translation id="2053553514270667976">ZIP code</translation>
+<translation id="2053553514270667976">Zip code</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 suhestyon}one{# suhestyon}other{# na suhestyon}}</translation>
<translation id="2071156619270205202">Hindi kwalipikado ang card na ito para sa virtual card number.</translation>
<translation id="2071692954027939183">Awtomatikong na-block ang mga notification dahil karaniwang hindi mo pinapayagan ang mga ito</translation>
@@ -410,6 +426,7 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="22081806969704220">Tray 3</translation>
<translation id="2212735316055980242">Hindi nahanap ang patakaran</translation>
<translation id="2213606439339815911">Kinukuha ang mga entry...</translation>
+<translation id="2213612003795704869">Na-print ang page</translation>
<translation id="2215727959747642672">Pag-edit ng file</translation>
<translation id="2218879909401188352">Ang mga umaatake na kasalukuyang nasa <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ay maaaring mag-install ng mga mapanganib na app na makakapinsala sa iyong device, magdagdag ng mga hindi alam na singil sa mobile bill mo, o magnakaw ng iyong personal na impormasyon. <ph name="BEGIN_LEARN_MORE_LINK" />Matuto pa<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">Walang internet</translation>
@@ -419,6 +436,7 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="2248949050832152960">Gamitin ang WebAuthn</translation>
<translation id="2250931979407627383">Edge stitch left</translation>
<translation id="225207911366869382">Hindi na gimagamit ang halagang ito para sa patakarang ito.</translation>
+<translation id="2256115617011615191">I-restart ngayon</translation>
<translation id="2258928405015593961">Maglagay ng petsa ng pag-expire sa hinaharap at subukan ulit</translation>
<translation id="225943865679747347">Code ng error: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">Error sa HTTP</translation>
@@ -446,6 +464,7 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="2337852623177822836">Kinokontrol ng iyong administrator ang setting</translation>
<translation id="2340263603246777781">Gustong makipagpares ng <ph name="ORIGIN" /></translation>
<translation id="2346319942568447007">Larawang kinopya mo</translation>
+<translation id="2350796302381711542">Papayagan ang <ph name="HANDLER_HOSTNAME" /> na buksan ang lahat ng <ph name="PROTOCOL" /> (na) link sa halip na ang <ph name="REPLACED_HANDLER_TITLE" />?</translation>
<translation id="2354001756790975382">Iba pang mga bookmark</translation>
<translation id="2354430244986887761"><ph name="BEGIN_LINK" />May nahanap na mga mapanganib na app<ph name="END_LINK" /> kamakailan ang Ligtas na Pag-browse ng Google sa <ph name="SITE" />.</translation>
<translation id="2355395290879513365">Maaaring makita ng mga umaatake ang mga larawang tinitingnan mo sa site na ito at lilinlangin ka sa pamamagitan ng pagbago sa mga ito.</translation>
@@ -471,6 +490,7 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="2413528052993050574">Hindi mapatunayan ng server na ito na ito ay <ph name="DOMAIN" />; maaaring binawi ang certificate ng seguridad nito. Maaaring dulot ito ng maling configuration o isang umaatake na hinahadlangan ang iyong koneksyon.</translation>
<translation id="2414886740292270097">Madilim</translation>
<translation id="2430968933669123598">Pamahalaan ang Google Account, pindutin ang Enter para pamahalaan ang iyong impormasyon, privacy, at seguridad sa iyong Google Account</translation>
+<translation id="2436186046335138073">Papayagan ang <ph name="HANDLER_HOSTNAME" /> na buksan ang lahat ng link ng <ph name="PROTOCOL" />?</translation>
<translation id="2438874542388153331">Quad punch right</translation>
<translation id="2450021089947420533">Mga Journey</translation>
<translation id="2463739503403862330">Punan</translation>
@@ -478,6 +498,7 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="2465655957518002998">Pumili ng Paraan ng Paghahatid</translation>
<translation id="2465688316154986572">Staple</translation>
<translation id="2465914000209955735">Pamahalaan ang mga file na na-download mo sa Chrome</translation>
+<translation id="2466004615675155314">Ipakita ang impormasyon mula sa web</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Magpatakbo ng Network Diagnostics<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">1-to-N na pagkakasunod-sunod</translation>
<translation id="2470767536994572628">Kapag nag-edit ka ng mga anotasyon, babalik ang dokumentong ito sa isang page na view at sa orihinal nitong pag-rotate</translation>
@@ -498,6 +519,7 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="2523886232349826891">Ise-save sa device lang na ito</translation>
<translation id="2524461107774643265">Magdagdag ng Higit Pang Impormasyon</translation>
<translation id="2529899080962247600">Hindi dapat magkaroon ng higit sa <ph name="MAX_ITEMS_LIMIT" /> (na) entry ang field na ito. Babalewalain ang lahat ng entry na lalampas dito.</translation>
+<translation id="2535585790302968248">Magbukas ng bagong tab na Incognito para mag-browse nang pribado</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{at 1 pa}one{at # pa}other{at # pa}}</translation>
<translation id="2536110899380797252">Magdagdag ng Address</translation>
<translation id="2539524384386349900">Tukuyin</translation>
@@ -523,7 +545,14 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="2597378329261239068">Protektado ng password ang dokumentong ito. Mangyaring magpasok ng password.</translation>
<translation id="2609632851001447353">Mga Pagkakaiba-iba</translation>
<translation id="2610561535971892504">I-click para kopyahin</translation>
+<translation id="2617988307566202237"><ph name="BEGIN_EMPHASIS" />Hindi ise-save<ph name="END_EMPHASIS" /> ng Chrome ang sumusunod na impormasyon:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Iyong history ng pag-browse
+ <ph name="LIST_ITEM" />Cookies at data ng site
+ <ph name="LIST_ITEM" />Impormasyong inilalagay sa mga form
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (Envelope)</translation>
+<translation id="2623663032199728144">Puwedeng hilining gamitin ang impormasyon tungkol sa iyong mga screen</translation>
<translation id="2625385379895617796">Nauuna ang iyong orasan</translation>
<translation id="262745152991669301">Puwedeng hilinging kumonekta sa mga USB device</translation>
<translation id="2629325967560697240">Para makuha ang pinakamataas na antas ng seguridad ng Chrome, <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />i-on ang pinahusay na proteksyon<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -557,6 +586,7 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="2709516037105925701">AutoFill</translation>
<translation id="2713444072780614174">Puti</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />, pindutin ang Tab at pagkatapos ay ang Enter para pamahalaan ang iyong mga pagbabayad at ang impormasyon ng credit card sa mga setting ng Chrome</translation>
+<translation id="271663710482723385">Pindutin ang |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| para lumabas sa full screen</translation>
<translation id="2721148159707890343">Matagumpay ang kahilingan</translation>
<translation id="2723669454293168317">Magpatakbo ng pag-check sa kaligtasan sa mga setting ng Chrome</translation>
<translation id="2726001110728089263">Side Tray</translation>
@@ -587,6 +617,7 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="2850739647070081192">Invite (Envelope)</translation>
<translation id="2856444702002559011">Maaaring sinusubukang nakawin ng mga attacker ang iyong impormasyon mula sa <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (halimbawa, mga password, mensahe, o credit card). <ph name="BEGIN_LEARN_MORE_LINK" />Matuto pa<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">Nagpapakita ang site na ito ng mga nakakasagabal o nakakapanlinlang na ad.</translation>
+<translation id="286512204874376891">Itinatago ng virtual card ang iyong aktwal na card para makatulong na protektahan ka laban sa potensyal na panloloko. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">Friendly</translation>
<translation id="2876489322757410363">Aalis sa Incognito mode upang magbayad sa pamamagitan ng external na application. Magpatuloy?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />, pindutin ang Tab at pagkatapos ay ang Enter para pamahalaan ang iyong Ligtas na Pag-browse at higit pa sa mga setting ng Chrome</translation>
@@ -611,6 +642,7 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="2930577230479659665">Paikliin pagkatapos ng bawat pagkopya</translation>
<translation id="2932085390869194046">Magmungkahi ng Password...</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019">Buksan ang mga link ng <ph name="PROTOCOL" /></translation>
<translation id="2941952326391522266">Hindi mapatunayan ng server na ito na ito ay <ph name="DOMAIN" />; mula sa <ph name="DOMAIN2" /> ang certificate ng seguridad nito. Maaaring dulot ito ng maling configuration o isang umaatake na hinahadlangan ang iyong koneksyon.</translation>
<translation id="2943895734390379394">Oras ng Pag-upload:</translation>
<translation id="2948083400971632585">Maaari mong i-disable ang anumang mga proxy na naka-configure para sa isang koneksyon mula sa pahina ng mga setting.</translation>
@@ -643,6 +675,7 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="3037605927509011580">Ay, Naku!</translation>
<translation id="3041612393474885105">Impormasyon sa Certificate</translation>
<translation id="3044034790304486808">Ipagpatuloy ang iyong pananaliksik</translation>
+<translation id="305162504811187366">History ng Remote na Desktop ng Chrome, kabilang ang mga timestamp, host, at client session id</translation>
<translation id="3060227939791841287">C9 (Envelope)</translation>
<translation id="3061707000357573562">Serbisyo sa Pag-patch</translation>
<translation id="306573536155379004">Nagsimula na ang laro.</translation>
@@ -683,6 +716,7 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="3197136577151645743">Puwedeng hilinging malaman kung aktibo mong ginagamit ang device na ito</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />, pindutin ang Tab pagkatapos ay ang Enter para pamahalaan kung anong impormasyon ang isi-sync mo sa mga setting ng Chrome</translation>
<translation id="320323717674993345">Kanselahin ang Pagbabayad</translation>
+<translation id="3203366800380907218">Mula sa web</translation>
<translation id="3207960819495026254">Naka-bookmark</translation>
<translation id="3209034400446768650">Puwedeng maningil ang page</translation>
<translation id="3212581601480735796">Sinusubaybayan ang iyong aktibidad sa <ph name="HOSTNAME" /></translation>
@@ -699,10 +733,12 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="3234666976984236645">Palaging tukuyin ang mahalagang content sa site na ito</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />, Pindutin ang tab at pagkatapos ay ang Enter para i-customize ang hitsura ng iyong browser</translation>
<translation id="3240791268468473923">Nakabukas ang sheet na walang tumutugmang kredensyal sa kredensyal sa secure na pagbabayad</translation>
+<translation id="324180406144491771">Naka-block ang mga link na “<ph name="HOST_NAME" />â€</translation>
<translation id="3249845759089040423">Groovy</translation>
<translation id="3252266817569339921">Pranses</translation>
<translation id="3257954757204451555">Sino ang nasa likod ng impormasyong ito?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />, pindutin ang Tab at pagkatapos ay ang Enter para gumawa ng bagong event sa Google Calendar nang mabilis</translation>
+<translation id="3261488570342242926">Matuto pa tungkol sa mga virtual card</translation>
<translation id="3264837738038045344">Button na Pamahalaan ang mga setting ng Chrome, pindutin ang Enter para bisitahin ang iyong mga setting ng Chrome</translation>
<translation id="3266793032086590337">Value (hindi tumutugma)</translation>
<translation id="3268451620468152448">Mga Bukas na Tab</translation>
@@ -716,6 +752,7 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="3288238092761586174">Posibleng kailanganin ng <ph name="URL" /> na magsagawa ng mga karagdagang hakbang para ma-verify ang iyong pagbabayad</translation>
<translation id="3293642807462928945">Matuto pa tungkol sa patakarang <ph name="POLICY_NAME" /></translation>
<translation id="3295444047715739395">Tingnan at pamahalaan ang iyong mga password sa mga setting ng Chrome</translation>
+<translation id="3303795387212510132">Payagan ang app na magbukas ng mga link na <ph name="PROTOCOL_SCHEME" />?</translation>
<translation id="3303855915957856445">Walang nakitang resulta ng paghahanap</translation>
<translation id="3304073249511302126">pag-scan ng bluetooth</translation>
<translation id="3308006649705061278">Organizational Unit (OU)</translation>
@@ -729,12 +766,6 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="3345782426586609320">Mga Mata</translation>
<translation id="3355823806454867987">Baguhin ang mga setting ng proxy...</translation>
<translation id="3360103848165129075">Sheet ng tagapangasiwa ng pagbabayad</translation>
-<translation id="3361596688432910856"><ph name="BEGIN_EMPHASIS" />Hindi ise-save<ph name="END_EMPHASIS" /> ng Chrome ang sumusunod na impormasyon:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Iyong history ng pag-browse
- <ph name="LIST_ITEM" />Cookies at data ng site
- <ph name="LIST_ITEM" />Impormasyong nilagay sa mga form
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">Awtomatikong kinopya ang patakarang ito mula sa hindi na ginagamit na patakarang <ph name="OLD_POLICY" />. Dapat mong gamitin ang patakarang ito sa halip.</translation>
<translation id="3364869320075768271">Gustong gamitin ng <ph name="URL" /> ang iyong virtual reality device at data</translation>
<translation id="3366477098757335611">Tingnan ang mga card</translation>
@@ -817,7 +848,6 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="3587738293690942763">Gitna</translation>
<translation id="3592413004129370115">Italian (Envelope)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{Puwede mong i-reset ang iyong grupo anumang oras. Inaabot nang humigit-kumulang isang araw para makasali sa isang bagong grupo.}=1{Puwede mong i-reset ang iyong grupo anumang oras. Inaabot nang humigit-kumulang isang araw para makasali sa isang bagong grupo.}one{Puwede mong i-reset ang iyong grupo anumang oras. Inaabot nang {NUM_DAYS} araw para makasali sa isang bagong grupo.}other{Puwede mong i-reset ang iyong grupo anumang oras. Inaabot nang {NUM_DAYS} na araw para makasali sa isang bagong grupo.}}</translation>
-<translation id="3596012367874587041">Mga setting ng app</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">Na-block ng iyong administrator ang application</translation>
<translation id="3608932978122581043">Oryentasyon ng feed</translation>
@@ -860,6 +890,7 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="370972442370243704">I-on ang Mga Journey</translation>
<translation id="3711895659073496551">Suspendihin</translation>
<translation id="3712624925041724820">Naubos na ang mga lisensya</translation>
+<translation id="3714633008798122362">kalendaryo ng web</translation>
<translation id="3714780639079136834">I-on ang mobile data o Wi-Fi</translation>
<translation id="3715597595485130451">Kumonekta sa Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Suriin ang configuration ng proxy, firewall at DNS<ph name="END_LINK" /></translation>
@@ -921,6 +952,7 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="3906954721959377182">Tablet</translation>
<translation id="3909477809443608991">Gusto ng <ph name="URL" /> na mag-play ng pinoprotektahang content. Ive-verify ng Google ang pagkakakilanlan ng iyong device, at maaari itong i-access ng site na ito.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">Tanggihan</translation>
<translation id="3939773374150895049">Gamitin ang WebAuthn sa halip na CVC?</translation>
<translation id="3946209740501886391">Palaging hilingin sa site na ito</translation>
<translation id="3947595700203588284">Puwedeng hilinging kumonekta sa mga MIDI device</translation>
@@ -942,6 +974,7 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="3990250421422698716">Jog offset</translation>
<translation id="3996311196211510766">Hiniling ng site na <ph name="ORIGIN" /> na maglapat ng patakaran ng pinagmulan
sa lahat ng kahilingan dito, pero hindi pa mailalapat sa ngayon ang patakarang ito.</translation>
+<translation id="4009243425692662128">Ipapadala ang content ng mga page na ipi-print mo sa Google Cloud o mga third party para sa pagsusuri. Halimbawa, posible itong i-scan para sa sensitibong data.</translation>
<translation id="4010758435855888356">Bigyan ng access sa storage?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{PDF na dokumentong naglalaman ng {COUNT} page}one{PDF na dokumentong naglalaman ng {COUNT} page}other{PDF na dokumentong naglalaman ng {COUNT} na page}}</translation>
<translation id="4023431997072828269">Dahil isinusumite ang form na ito gamit ang isang koneksyong hindi secure, makikita ng iba ang iyong impormasyon.</translation>
@@ -1036,6 +1069,7 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="4250680216510889253">Hindi</translation>
<translation id="4253168017788158739">Tala</translation>
<translation id="425582637250725228">Maaaring hindi ma-save ang mga pagbabagong ginawa mo.</translation>
+<translation id="425869179292622354">Gawin itong mas secure gamit ang virtual card?</translation>
<translation id="4258748452823770588">Maling lagda</translation>
<translation id="4261046003697461417">Hindi maaaring i-annotate ang mga protektadong dokumento</translation>
<translation id="4265872034478892965">Pinayagan ng iyong administrator</translation>
@@ -1098,6 +1132,7 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="4434045419905280838">Mga pop-up at pag-redirect</translation>
<translation id="4435702339979719576">Postcard)</translation>
<translation id="443673843213245140">Hindi pinagana ang paggamit ng isang proxy ngunit tinutukoy ang isang tahasang configuration ng proxy.</translation>
+<translation id="4441832193888514600">Binalewala dahil ang patakaran ay puwede lang itakda bilang patakaran ng user ng cloud.</translation>
<translation id="4450893287417543264">Huwag ipakitang muli</translation>
<translation id="4451135742916150903">Puwedeng hilinging kumonekta sa mga HID device</translation>
<translation id="4452328064229197696">Nakita sa isang paglabag sa data ang password na kakagamit mo lang. Para ma-secure ang iyong mga account, inirerekomenda ng Google Password Manager na tingnan mo ang iyong mga naka-save na password.</translation>
@@ -1153,6 +1188,7 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="4628948037717959914">Larawan</translation>
<translation id="4631649115723685955">May naka-link na cashback</translation>
<translation id="4636930964841734540">Impormasyon</translation>
+<translation id="4638670630777875591">Incognito sa Chromium</translation>
<translation id="464342062220857295">Mga feature sa paghahanap</translation>
<translation id="4644670975240021822">Baligtarin ang pagkakasunod-sunod nang nakataob</translation>
<translation id="4646534391647090355">Dalhin na ako roon</translation>
@@ -1173,6 +1209,7 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="4708268264240856090">Naputol ang iyong koneksyon</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Magpatakbo ng Windows Network Diagnostics<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426">Password ni <ph name="USERNAME" /></translation>
<translation id="4724144314178270921">Puwedeng hilinging makita ang text at mga larawan sa iyong clipboard</translation>
<translation id="4726672564094551039">I-reload ang mga patakaran</translation>
<translation id="4728558894243024398">Platform</translation>
@@ -1194,6 +1231,7 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="4757993714154412917">Kakalagay mo lang ng iyong password sa isang mapanlinang na site. Para ma-secure ang iyong mga account, inirerekomenda ng Chromium na suriin mo ang iyong mga na-save na password.</translation>
<translation id="4758311279753947758">Magdagdag ng impormasyon sa pakikipag-ugnayan</translation>
<translation id="4761104368405085019">Gamitin ang iyong mikropono</translation>
+<translation id="4761869838909035636">Magpatakbo ng Pag-check sa Kaligtasan sa Chrome</translation>
<translation id="4764776831041365478">Ang webpage sa <ph name="URL" /> ay maaaring pansamantalang hindi gumagana o maaaring permanente itong inilipat sa isang bagong web address.</translation>
<translation id="4766713847338118463">Dual staple bottom</translation>
<translation id="4771973620359291008">Isang hindi alam na error ang nangyari.</translation>
@@ -1214,12 +1252,6 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="4819347708020428563">I-edit ang mga anotasyon sa default na view?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />, pindutin ang Tab at pagkatapos ay ang Enter para gumawa ng bagong Google Sheet nang mabilis</translation>
<translation id="4825507807291741242">Mahusay</translation>
-<translation id="4827402517081186284">Hindi ka nagagawang hindi nakikita online ng Incognito:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Alam ng mga site kapag binisita mo ang mga ito<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Puwedeng subaybayan ng mga empleyado o paaralan ang aktibidad sa pag-browse<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Puwedeng i-monitor ng mga internet service provider ang trapiko sa web<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">I-on ang mga babala</translation>
<translation id="4838327282952368871">Dreamy</translation>
<translation id="4840250757394056958">Tingnan ang iyong history sa Chrome</translation>
@@ -1231,12 +1263,12 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="4854362297993841467">Hindi available ang pamamaraan ng paghahatid na ito. Sumubok ng ibang pamamaraan.</translation>
<translation id="4854853140771946034">Gumawa ng bagong tala sa Google Keep nang mabilis</translation>
<translation id="485902285759009870">Vine-verify ang code...</translation>
+<translation id="4866506163384898554">Pindutin ang |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| para ipakita ang iyong cursor</translation>
<translation id="4876188919622883022">Pinasimpleng view</translation>
<translation id="4876305945144899064">Walang username</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{Wala}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}one{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831">paghahanap para sa <ph name="TEXT" /></translation>
<translation id="4879491255372875719">Awtomatiko (default)</translation>
-<translation id="4879725228911483934">Magbukas at maglagay ng mga window sa iyong mga screen</translation>
<translation id="4880827082731008257">History ng paghahanap</translation>
<translation id="4881695831933465202">Buksan</translation>
<translation id="4885256590493466218">Magbayad gamit ang <ph name="CARD_DETAIL" /> sa pag-checkout</translation>
@@ -1245,6 +1277,7 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">Ikasiyam na Rolyo</translation>
<translation id="4901778704868714008">I-save...</translation>
+<translation id="4905659621780993806">Awtomatikong ire-restart ng iyong administrator ang device mo nang <ph name="TIME" /> sa <ph name="DATE" />. I-save ang anumang bukas na item bago mag-restart ang iyong device.</translation>
<translation id="4913987521957242411">Punch top left</translation>
<translation id="4918221908152712722">I-install ang <ph name="APP_NAME" /> (hindi kinakailangang i-download)</translation>
<translation id="4923459931733593730">Pagbabayad</translation>
@@ -1253,6 +1286,7 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, pindutin ang Tab at pagkatapos ay Enter para maghanap</translation>
<translation id="4930153903256238152">Malaking kapasidad</translation>
+<translation id="4940163644868678279">Incognito sa Chrome</translation>
<translation id="4943872375798546930">Walang mga resulta</translation>
<translation id="4950898438188848926">Button sa paglipat ng tab, pindutin ang Enter para lumipat sa nakabukas na tab, na <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="495170559598752135">Mga Pagkilos</translation>
@@ -1262,6 +1296,7 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="4968522289500246572">Idinisenyo ang app na ito para sa mobile at posibleng hindi ma-resize nang maayos. Posibleng makaranas ng mga isyu o mag-restart ang app.</translation>
<translation id="4969341057194253438">I-delete ang recording</translation>
<translation id="4973922308112707173">Dual punch top</translation>
+<translation id="4976702386844183910">Huling binisita noong <ph name="DATE" /></translation>
<translation id="4984088539114770594">Gamitin ang mikropono?</translation>
<translation id="4984339528288761049">Prc5 (Envelope)</translation>
<translation id="4989163558385430922">Tingnan lahat</translation>
@@ -1323,6 +1358,7 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="5138227688689900538">Magpakita ng mas kaunti</translation>
<translation id="5145883236150621069">May code ng error sa tugon sa patakaran</translation>
<translation id="5146995429444047494">Naka-block ang mga notification para sa <ph name="ORIGIN" /></translation>
+<translation id="514704532284964975">Gustong tingnan at baguhin ng <ph name="URL" /> ang impormasyon sa mga NFC device na tina-tap mo gamit ang iyong telepono</translation>
<translation id="5148809049217731050">Nakatihaya</translation>
<translation id="515292512908731282">C4 (Envelope)</translation>
<translation id="5158275234811857234">Cover</translation>
@@ -1347,6 +1383,7 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="5215116848420601511">Mga paraan ng pagbabayad at address gamit ang Google Pay</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">Tray 13</translation>
+<translation id="5216942107514965959">Huling binisita ngayong araw</translation>
<translation id="5222812217790122047">Kailangan ng email</translation>
<translation id="5230733896359313003">Address na Padadalhan</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1367,7 +1404,6 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">Mga katangian ng dokumento</translation>
<translation id="528468243742722775">Tapusin</translation>
-<translation id="5284909709419567258">Mga address ng network</translation>
<translation id="5285570108065881030">Ipakita ang lahat ng naka-save na password</translation>
<translation id="5287240709317226393">Ipakita ang cookies</translation>
<translation id="5287456746628258573">Gumagamit ang site na ito ng lumang configuration sa seguridad, na posibleng maglantad ng iyong impormasyon (halimbawa, mga password o numero ng credit card) kapag ipinadala ito sa site na ito.</translation>
@@ -1451,6 +1487,7 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="5556459405103347317">I-reload</translation>
<translation id="5560088892362098740">Petsa ng Pag-expire</translation>
<translation id="55635442646131152">Balangkas ng dokumento</translation>
+<translation id="5565613213060953222">Magbukas ng tab na Incognito</translation>
<translation id="5565735124758917034">Aktibo</translation>
<translation id="5570825185877910964">Protektahan ang account</translation>
<translation id="5571083550517324815">Hindi maaaring mag-pick up mula sa address na ito. Pumili ng ibang address.</translation>
@@ -1533,6 +1570,7 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="5869522115854928033">Mga naka-save na password</translation>
<translation id="5873013647450402046">Gustong kumpirmahin ng iyong bangko na ikaw ito.</translation>
<translation id="5887400589839399685">Na-save ang card</translation>
+<translation id="5887687176710214216">Huling binisita kahapon</translation>
<translation id="5895138241574237353">I-restart</translation>
<translation id="5895187275912066135">Ibinigay Noong</translation>
<translation id="5901630391730855834">Dilaw</translation>
@@ -1546,6 +1584,7 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="5921639886840618607">I-save ang card sa Google Account?</translation>
<translation id="5922853866070715753">Malapit nang matapos</translation>
<translation id="5932224571077948991">Nagpapakita ang site ng mga nakakasagabal o nakakapanlinlang na ad</translation>
+<translation id="5938153366081463283">Magdagdag ng virtual card</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347">Binubuksan ang <ph name="SITE_NAME" />…</translation>
<translation id="5951495562196540101">Hindi maka-enroll gamit ang account ng consumer (may available na naka-package na lisensya).</translation>
@@ -1610,6 +1649,7 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="6120179357481664955">Natatandaan mo ang iyong UPI ID?</translation>
<translation id="6124432979022149706">Mga Chrome Enterprise Connector</translation>
<translation id="6127379762771434464">Inalis ang item</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Matuto pa tungkol sa Incognito sa Chrome<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">Tingnan ang anumang mga kable at i-reboot ang anumang mga router, modem o iba
pang mga network device na maaaring ginagamit mo.</translation>
<translation id="614940544461990577">Subukang:</translation>
@@ -1622,7 +1662,6 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="6169916984152623906">Makakapag-browse ka na ngayon nang pribado, at hindi makikita ng ibang taong gumagamit sa device na ito ang iyong aktibidad. Gayunpaman, mase-save ang mga download at bookmark.</translation>
<translation id="6177128806592000436">Hindi ligtas ang iyong koneksyon sa site na ito</translation>
<translation id="6180316780098470077">Interval ng pag-retry</translation>
-<translation id="619448280891863779">Puwedeng hilinging magbukas at maglagay ng mga window sa iyong mga screen</translation>
<translation id="6196640612572343990">I-block ang mga third-party na cookie</translation>
<translation id="6203231073485539293">Suriin ang iyong koneksyon sa Internet</translation>
<translation id="6218753634732582820">Gusto mo bang alisin ang address sa Chromium?</translation>
@@ -1645,7 +1684,7 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="6272383483618007430">Google Update</translation>
<translation id="6276112860590028508">Lalabas dito ang mga page mula sa iyong listahan ng babasahin</translation>
<translation id="627746635834430766">Para mas mabilis na makapagbayad sa susunod, i-save ang iyong card at billing address sa Google Account mo.</translation>
-<translation id="6279098320682980337">Hindi napunan ang numero ng virtual na card? I-click ang mga detalye ng card para kopyahin</translation>
+<translation id="6279183038361895380">Pindutin ang |<ph name="ACCELERATOR" />| upang ipakita ang iyong cursor</translation>
<translation id="6280223929691119688">Hindi maaaring maghatid sa address na ito. Pumili ng ibang address.</translation>
<translation id="6282194474023008486">Postal code</translation>
<translation id="6285507000506177184">Button na Pamahalaan ang mga download sa Chrome, pindutin ang Enter para pamahalaan ang mga file na na-download mo sa Chrome</translation>
@@ -1653,6 +1692,7 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="6290238015253830360">Lalabas dito ang mga iminungkahi mong artikulo</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{Magre-restart na ngayon ang iyong device}=1{Magre-restart ang iyong device pagkalipas ng 1 segundo}one{Magre-restart ang iyong device pagkalipas ng # segundo}other{Magre-restart ang iyong device pagkalipas ng # na segundo}}</translation>
<translation id="6302269476990306341">Ihinihinto ang Google Assistant sa Chrome</translation>
<translation id="6305205051461490394">Hindi makakonekta sa <ph name="URL" />.</translation>
<translation id="6312113039770857350">Hindi available ang webpage</translation>
@@ -1726,6 +1766,7 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="6529602333819889595">&amp;Gawing Muli ang Pagtanggal</translation>
<translation id="6545864417968258051">Pag-scan ng Bluetooth</translation>
<translation id="6547208576736763147">Dual punch left</translation>
+<translation id="6554732001434021288">Huling binisita <ph name="NUM_DAYS" /> (na) araw ang nakalipas</translation>
<translation id="6556866813142980365">Redo</translation>
<translation id="6569060085658103619">Isang page ng extension ang tinitingnan mo</translation>
<translation id="6573200754375280815">Dual punch right</translation>
@@ -1786,7 +1827,6 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="6757797048963528358">Nag-sleep ang iyong device.</translation>
<translation id="6767985426384634228">I-update ang Address?</translation>
<translation id="6768213884286397650">Hagaki (Postcard)</translation>
-<translation id="6774185088257932239"><ph name="BEGIN_LINK" />Matuto pa<ph name="END_LINK" /> tungkol sa Incognito</translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">Violet</translation>
<translation id="6786747875388722282">Mga Extension</translation>
@@ -1870,7 +1910,6 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="706295145388601875">Magdagdag at mamahala ng mga address sa mga setting ng Chrome</translation>
<translation id="7064851114919012435">Impormasyon sa pakikipag-ugnayan</translation>
<translation id="7068733155164172741">Ilagay ang <ph name="OTP_LENGTH" /> (na) digit na code</translation>
-<translation id="7070090581017165256">Tungkol sa site na ito</translation>
<translation id="70705239631109039">Hindi ganap na ligtas ang iyong koneksyon</translation>
<translation id="7075452647191940183">Masyadong malaki ang kahilingan</translation>
<translation id="7079718277001814089">Naglalaman ng malware ang site na ito</translation>
@@ -1887,6 +1926,12 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="7111012039238467737">(Valid)</translation>
<translation id="7118618213916969306">Hanapin ang URL sa clipboard, na <ph name="SHORT_URL" /></translation>
<translation id="7119414471315195487">Isara ang iba pang tab o program</translation>
+<translation id="7129355289156517987">Kapag isinara mo ang lahat ng tab na Incognito sa Chromium, maki-clear mula sa device na ito ang iyong aktibidad sa mga tab na iyon:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Aktibidad sa pag-browse<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />History ng paghahanap<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Impormasyong inilagay sa mga form<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">Hindi maaaring magpadala sa address na ito. Pumili ng ibang address.</translation>
<translation id="7132939140423847331">Ipinagbawal ng iyong admin ang pagkopya sa data na ito.</translation>
<translation id="7135130955892390533">Ipakita ang status</translation>
@@ -1909,6 +1954,7 @@ Kung ayaw mo, iba-block ito ng iyong mga setting ng privacy. Papayagan nito ang
<translation id="7192203810768312527">Magbabakante ng <ph name="SIZE" />. Maaaring mag-load nang mas mabagal ang ilang site sa iyong susunod na pagbisita.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">Makikita ng iyong administrator ang:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, pindutin ang Tab at pagkatapos ay Enter para magbukas ng bagong tab na Incognito para mag-browse nang pribado</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423">Hindi sumusunod ang <ph name="HOST_NAME" /> sa mga pamantayan sa seguridad.</translation>
<translation id="7210993021468939304">Aktibidad ng Linux sa container, at puwedeng mag-install at magpatakbo ng mga Linux app sa container</translation>
@@ -1940,6 +1986,7 @@ Mga karagdagang detalye:
<translation id="7304562222803846232">Pamahalaan ang mga setting ng privacy ng Google Account</translation>
<translation id="7305756307268530424">Simulan nang mas mabagal</translation>
<translation id="7308436126008021607">pag-sync sa background</translation>
+<translation id="7310392214323165548">Malapit na malapit nang mag-restart ang device</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">Tulong sa Koneksyon</translation>
<translation id="7323804146520582233">Itago ang seksyong "<ph name="SECTION" />"</translation>
@@ -1947,6 +1994,7 @@ Mga karagdagang detalye:
<translation id="7334320624316649418">&amp;Gawing muli ang pagbabago sa ayos</translation>
<translation id="7335157162773372339">Puwedeng hilinging gamitin ang iyong camera</translation>
<translation id="7337248890521463931">Magpakita ng mas marami pang linya</translation>
+<translation id="7337418456231055214">Hindi napunan ang numero ng virtual na card? I-click ang mga detalye ng card para kopyahin. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">Hindi available sa iyong platform.</translation>
<translation id="733923710415886693">Ang certificate ng server ay hindi inihayag sa pamamagitan ng Transparency ng Certificate.</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1969,6 +2017,7 @@ Mga karagdagang detalye:
<translation id="7378627244592794276">Hindi</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">Hindi naaangkop</translation>
+<translation id="7388594495505979117">{0,plural, =1{Magre-restart ang iyong device pagkalipas ng 1 minuto}one{Magre-restart ang iyong device pagkalipas ng # minuto}other{Magre-restart ang iyong device pagkalipas ng # na minuto}}</translation>
<translation id="7390545607259442187">Kumpirmahin ang Card</translation>
<translation id="7392089738299859607">I-update ang Address</translation>
<translation id="7399802613464275309">Pagsusuri sa Kaligtasan</translation>
@@ -2005,6 +2054,12 @@ Mga karagdagang detalye:
<translation id="7485870689360869515">Walang nahanap na data.</translation>
<translation id="7495528107193238112">Naka-block ang content na ito. Makipag-ugnayan sa may-ari ng site para maayos ang isyu.</translation>
<translation id="7497998058912824456">Button na Gumawa ng doc, pindutin ang Enter para gumawa ng bagong Google Doc nang mabilis</translation>
+<translation id="7506488012654002225"><ph name="BEGIN_EMPHASIS" />Hindi ise-save<ph name="END_EMPHASIS" /> ng Chromium ang sumusunod na impormasyon:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Iyong history ng pag-browse
+ <ph name="LIST_ITEM" />Cookies at data ng site
+ <ph name="LIST_ITEM" />Impormasyong inilalagay sa mga form
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">Walang laman ang ibinalik na device id ng patakaran o hindi ito tumutugma sa kasalukuyang device id</translation>
<translation id="7508870219247277067">Avocado Green</translation>
<translation id="7511955381719512146">Maaaring hilingin ng Wi-Fi na ginagamit mo na bisitahin mo ang <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
@@ -2118,7 +2173,6 @@ Mga karagdagang detalye:
<translation id="7813600968533626083">Alisin ang suhestyon sa Chrome?</translation>
<translation id="781440967107097262">Ibahagi ang clipboard?</translation>
<translation id="7815407501681723534">Nakakita ng <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> para sa '<ph name="SEARCH_STRING" />'</translation>
-<translation id="782125616001965242">Magpakita ng impormasyon tungkol sa site na ito</translation>
<translation id="782886543891417279">Maaaring hilingin ng Wi-Fi na ginagamit mo (<ph name="WIFI_NAME" />) na bisitahin mo ang page nito sa pag-login.</translation>
<translation id="7836231406687464395">Postfix (Envelope)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{Wala}=1{1 app (<ph name="EXAMPLE_APP_1" />)}=2{2 app (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}one{# (na) app (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}other{# (na) app (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}}</translation>
@@ -2135,7 +2189,6 @@ Mga karagdagang detalye:
<translation id="7888575728750733395">Intent sa pag-render ng print</translation>
<translation id="7894280532028510793">Kung tama ang pagbabaybay, <ph name="BEGIN_LINK" />subukang patakbuhin ang Mga Diagnostic ng Network<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (Envelope)</translation>
-<translation id="7931318309563332511">Hindi Alam</translation>
<translation id="793209273132572360">I-update ang address?</translation>
<translation id="7932579305932748336">Coat</translation>
<translation id="79338296614623784">Maglagay ng wastong numero ng telepono</translation>
@@ -2160,13 +2213,14 @@ Mga karagdagang detalye:
<translation id="7976214039405368314">Masyadong maraming kahilingan</translation>
<translation id="7977538094055660992">Output device</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">Naka-link sa</translation>
<translation id="798134797138789862">Puwedeng hilinging gumamit ng mga virtual reality device at data</translation>
<translation id="7984945080620862648">Hindi mo maaaring bisitahin ang <ph name="SITE" /> sa ngayon dahil nagpadala ang website ng mga gulu-gulong kredensyal na hindi maproseso ng Chrome. Kadalasang pansamantala lang ang mga error at atake sa network, kaya malamang na gagana ang page na ito sa ibang pagkakataon.</translation>
-<translation id="79859296434321399">Para matingnan ang augmented reality na content, i-install ang ARCore</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">Bind</translation>
<translation id="7992044431894087211">Ipinagpatuloy ang pagbabahagi ng screen sa <ph name="APPLICATION_TITLE" /></translation>
<translation id="7995512525968007366">Hindi Tinukoy</translation>
+<translation id="7998269595945679889">Button na Magbukas ng tab na Incognito, pindutin ang Enter para magbukas ng bagong tab na Incognito para mag-browse nang pribado</translation>
<translation id="800218591365569300">Subukang isara ang iba pang tab o program upang magbakante ng memory.</translation>
<translation id="8004582292198964060">Browser</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{Ise-save ang card na ito at ang billing address nito. Magagamit mo ito kapag nag-sign in ka sa <ph name="USER_EMAIL" />.}one{Ise-save ang mga card na ito at ang mga billing address ng mga ito. Magagamit mo ang mga ito kapag nag-sign in ka sa <ph name="USER_EMAIL" />.}other{Ise-save ang mga card na ito at ang mga billing address ng mga ito. Magagamit mo ang mga ito kapag nag-sign in ka sa <ph name="USER_EMAIL" />.}}</translation>
@@ -2226,6 +2280,7 @@ Mga karagdagang detalye:
<translation id="8202370299023114387">Hindi pagkakasundo</translation>
<translation id="8206978196348664717">Prc4 (Envelope)</translation>
<translation id="8211406090763984747">Secure ang koneksyon</translation>
+<translation id="8217240300496046857">Hindi makakagamit ng cookies na sumusubaybay sa iyo sa buong web ang mga site. Posibleng masira ang mga feature sa ilang site.</translation>
<translation id="8218327578424803826">Itinakdang Lokasyon:</translation>
<translation id="8220146938470311105">C7/C6 (Envelope)</translation>
<translation id="8225771182978767009">Pinili ng taong nag-set up ng computer na ito na i-block ang site na ito.</translation>
@@ -2266,14 +2321,9 @@ Mga karagdagang detalye:
<translation id="830498451218851433">Fold half</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">Mga naka-install na app at kung gaano kadalas gamitin ang mga ito</translation>
+<translation id="8317207217658302555">I-update ang ARCore?</translation>
<translation id="831997045666694187">Gabi</translation>
<translation id="8321476692217554900">mga notification</translation>
-<translation id="8328484624016508118">Pagkatapos isara ang lahat ng tab na Incognito, kini-clear ng Chrome ang:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Iyong aktibidad sa pag-browse sa device na ito<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Iyong history ng paghahanap sa device na ito<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Impormasyong inilagay sa mga form<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489">Tinanggihan ang access sa <ph name="HOST_NAME" /></translation>
<translation id="833262891116910667">I-highlight</translation>
<translation id="8339163506404995330">Hindi isasalin ang mga page na nasa <ph name="LANGUAGE" /></translation>
@@ -2325,6 +2375,7 @@ Mga karagdagang detalye:
<translation id="8507227106804027148">Command line</translation>
<translation id="8508648098325802031">Icon ng paghahanap</translation>
<translation id="8511402995811232419">Pamahalaan ang cookies</translation>
+<translation id="8519753333133776369">HID device na pinapayagan ng iyong administrator</translation>
<translation id="8522552481199248698">Matutulungan ka ng Chrome na protektahan ang iyong Google Account at palitan ang password mo.</translation>
<translation id="8530813470445476232">I-clear ang iyong history ng pag-browse, cookies, cache, at higit pa sa mga setting ng Chrome</translation>
<translation id="8533619373899488139">Bisitahin ang &lt;strong&gt;chrome://policy&lt;/strong&gt; para makita ang listahan ng mga naka-block na URL at ang iba pang patakarang ipinapatupad ng iyong system administrator.</translation>
@@ -2336,7 +2387,6 @@ Mga karagdagang detalye:
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{I-reset ang pahintulot}one{I-reset ang mga pahintulot}other{I-reset ang mga pahintulot}}</translation>
<translation id="8555010941760982128">Gamitin ang code na ito kapag nag-checkout</translation>
<translation id="8557066899867184262">Makikita ang CVC sa likod ng iyong card.</translation>
-<translation id="8558485628462305855">Para matingnan ang augmented reality na content, i-update ang ARCore</translation>
<translation id="8559762987265718583">Hindi makapagtatag ng pribadong koneksyon sa <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> dahil mali ang petsa at oras ng iyong device (<ph name="DATE_AND_TIME" />).</translation>
<translation id="8564182942834072828">Mga hiwalay na dokumento/Mga hindi naka-collate na kopya</translation>
<translation id="8564985650692024650">Inirerekomenda ng Chromium na i-reset ang iyong password sa <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> kung ginamit mo ito sa iba pang site.</translation>
@@ -2355,6 +2405,7 @@ Mga karagdagang detalye:
<translation id="865032292777205197">mga sensor ng paggalaw</translation>
<translation id="8663226718884576429">Buod ng Order, <ph name="TOTAL_LABEL" />, Higit pang Detalye</translation>
<translation id="8666678546361132282">English</translation>
+<translation id="8669306706049782872">Gamitin ang impormasyon tungkol sa iyong mga screen para magbukas at maglagay ng mga window</translation>
<translation id="867224526087042813">Lagda</translation>
<translation id="8676424191133491403">Walang pagkaantala</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, sagot, <ph name="ANSWER" /></translation>
@@ -2381,6 +2432,7 @@ Mga karagdagang detalye:
<translation id="8731544501227493793">Button na Pamahalaan ang mga password, pindutin ang Enter para tingnan at pamahalaan ang mga password mo sa mga setting ng Chrome</translation>
<translation id="8734529307927223492">Pinapamahalaan ng <ph name="MANAGER" /> ang iyong <ph name="DEVICE_TYPE" /></translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, pindutin ang Tab at pagkatapos ay Enter para magbukas ng bagong Incognito window para makapag-browse nang pribado</translation>
+<translation id="8737685506611670901">Buksan ang mga link ng <ph name="PROTOCOL" /> sa halip na ang <ph name="REPLACED_HANDLER_TITLE" /></translation>
<translation id="8738058698779197622">Upang makapagtatag ng secure na koneksyon, kailangang itakda nang tama ang iyong orasan. Ito ay dahil sa may-bisa lang ang mga certificate na ginagamit ng mga website upang tukuyin ang mga sarili ng mga ito sa loob ng mga partikular na tagal ng panahon. Dahil mali ang orasan ng iyong device, hindi ma-verify ng Chromium ang mga certificate na ito.</translation>
<translation id="8740359287975076522">Hindi makita ang &lt;abbr id="dnsDefinition"&gt;DNS address&lt;/abbr&gt; ng <ph name="HOST_NAME" />. Dina-diagnose ang problema.</translation>
<translation id="8742371904523228557"><ph name="ONE_TIME_CODE" /> ang iyong code para sa <ph name="ORIGIN" /></translation>
@@ -2408,6 +2460,7 @@ Mga karagdagang detalye:
<translation id="883848425547221593">Iba Pang Mga Bookmark</translation>
<translation id="884264119367021077">Shipping address</translation>
<translation id="884923133447025588">Walang nahanap na mekanismo ng pagpapawalang-bisa.</translation>
+<translation id="8849262850971482943">Gamitin ang iyong virtual card para sa karagdagang seguridad</translation>
<translation id="885730110891505394">Pagbabahagi sa Google</translation>
<translation id="8858065207712248076">Inirerekomenda ng Chrome na i-reset ang iyong password sa <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> kung ginamit mo ito sa iba pang site.</translation>
<translation id="885906927438988819">Kung tama ang pagbabaybay, <ph name="BEGIN_LINK" />subukang patakbuhin ang Mga Diagnostic ng Network ng Windows<ph name="END_LINK" />.</translation>
@@ -2457,6 +2510,7 @@ Mga karagdagang detalye:
<translation id="9004367719664099443">Kasalukuyang isinasagawa ang VR session</translation>
<translation id="9005998258318286617">Hindi na-load ang PDF document.</translation>
<translation id="9008201768610948239">Balewalain</translation>
+<translation id="901834265349196618">email</translation>
<translation id="9020200922353704812">Kinakailangan ang address sa pagsingil ng card</translation>
<translation id="9020542370529661692">Na-translate sa <ph name="TARGET_LANGUAGE" /> ang pahinang ito</translation>
<translation id="9020742383383852663">A8</translation>
@@ -2505,6 +2559,7 @@ Mga karagdagang detalye:
<translation id="9150045010208374699">Gamitin ang iyong camera</translation>
<translation id="9150685862434908345">Mababago ng iyong administrator ang setup ng browser mo nang malayuan. Puwede ring pamahalaan sa labas ng Chrome ang aktibidad sa device na ito. <ph name="BEGIN_LINK" />Matuto pa<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">Na-update</translation>
+<translation id="9155211586651734179">Naka-attach ang mga peripheral ng audio</translation>
<translation id="9157595877708044936">Nagse-set up...</translation>
<translation id="9158625974267017556">C6 (Envelope)</translation>
<translation id="9164029392738894042">Pagsusuri sa Katumpakan</translation>
diff --git a/chromium/components/strings/components_strings_fr-CA.xtb b/chromium/components/strings/components_strings_fr-CA.xtb
index 516885f84ae..8dbc4f57711 100644
--- a/chromium/components/strings/components_strings_fr-CA.xtb
+++ b/chromium/components/strings/components_strings_fr-CA.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">Voir les renseignements</translation>
<translation id="1030706264415084469">L'URL <ph name="URL" /> veut stocker de façon permanente de grandes quantités de données sur votre appareil</translation>
<translation id="1032854598605920125">Faire pivoter dans le sens horaire</translation>
+<translation id="1033329911862281889">La navigation privée ne vous rend pas invisible en ligne :
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Les sites et les services qu'ils utilisent peuvent voir les visites.<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Les employeurs ou les écoles peuvent suivre l'activité de navigation.<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Les fournisseurs d'accès Internet peuvent surveiller le trafic Web.<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">Désactiver</translation>
<translation id="1036982837258183574">Appuyez sur |<ph name="ACCELERATOR" />| pour quitter le mode plein écran</translation>
<translation id="1038106730571050514">Afficher les suggestions</translation>
<translation id="1038842779957582377">nom inconnu</translation>
<translation id="1041998700806130099">Message de la feuille de travail</translation>
<translation id="1048785276086539861">Lorsque vous modifiez des annotations, ce document s'affiche au format de vue par page</translation>
-<translation id="1049743911850919806">Navigation privée</translation>
<translation id="1050038467049342496">Fermer les autres applications</translation>
<translation id="1055184225775184556">&amp;Annuler l'ajout</translation>
<translation id="1056898198331236512">Avertissement</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">Cache de la règle valide</translation>
<translation id="1130564665089811311">Bouton Traduire la page, appuyez sur la touche Entrée pour traduire cette page avec Google Traduction</translation>
<translation id="1131264053432022307">L'image que vous avez copiée</translation>
+<translation id="1142846828089312304">Bloquer les témoins tiers en navigation privée</translation>
<translation id="1150979032973867961">Impossible de vérifier sur le serveur qu'il s'agit bien du domaine <ph name="DOMAIN" />, car son certificat de sécurité n'est pas considéré comme fiable par le système d'exploitation de votre ordinateur. Cela peut être dû à une mauvaise configuration ou bien à l'interception de votre connexion par un pirate informatique.</translation>
<translation id="1151972924205500581">Veuillez entrer le mot de passe</translation>
<translation id="1156303062776767266">Vous consultez un fichier local ou partagé</translation>
@@ -64,7 +70,6 @@
<translation id="1178581264944972037">Interrompre</translation>
<translation id="1181037720776840403">Supprimer</translation>
<translation id="1186201132766001848">Vérifier les mots de passe</translation>
-<translation id="1195210374336998651">Accédez aux paramètres de l'application</translation>
<translation id="1195558154361252544">Les notifications sont automatiquement bloquées pour tous les sites, sauf ceux que vous autorisez</translation>
<translation id="1197088940767939838">Orange</translation>
<translation id="1201402288615127009">Suivant</translation>
@@ -111,7 +116,7 @@
<translation id="1307966114820526988">Fonctionnalités obsolètes</translation>
<translation id="1308113895091915999">Offre proposée</translation>
<translation id="1312803275555673949">Par quelles preuves est-ce appuyé?</translation>
-<translation id="131405271941274527"><ph name="URL" /> souhaite vous envoyer et recevoir de l'information lorsque vous touchez votre téléphone sur un appareil CCP</translation>
+<translation id="1314311879718644478">Affichez les contenus en réalité augmentée</translation>
<translation id="1314509827145471431">Reliure à droite</translation>
<translation id="1318023360584041678">Enregistré dans le groupe de l'onglet</translation>
<translation id="1319245136674974084">Ne plus me poser la question pour cette application</translation>
@@ -161,6 +166,7 @@
<translation id="142858679511221695">Utilisateur du nuage</translation>
<translation id="1428729058023778569">Cette mise en garde s'affiche parce que ce site ne prend pas en charge le protocole HTTPS. <ph name="BEGIN_LEARN_MORE_LINK" />En savoir plus<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">Imprimer</translation>
+<translation id="1432187715652018471">cette page veut installer un module de traitement de service.</translation>
<translation id="1432581352905426595">Gérer les moteurs de recherche</translation>
<translation id="1436185428532214179">Les sites peuvent demander à modifier les fichiers et les dossiers de votre appareil</translation>
<translation id="1442386063175183758">Pli du volet droit</translation>
@@ -181,6 +187,12 @@
<translation id="1483493594462132177">Envoi</translation>
<translation id="1484290072879560759">Choisir une adresse d'expédition</translation>
<translation id="1492194039220927094">Notifications poussées des politiques :</translation>
+<translation id="149293076951187737">Lorsque vous fermez tous les onglets de navigation privée de Chrome, votre activité dans ces onglets est effacée de cet appareil :
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Votre activité de navigation<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Votre historique de recherche<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Les informations saisies dans les formulaires<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">Retour à l'onglet</translation>
<translation id="1501859676467574491">Afficher les cartes enregistrées dans votre compte Google</translation>
<translation id="1507202001669085618">&lt;p&gt;Cette erreur s'affiche si vous utilisez un portail Wi-Fi auquel vous devez vous connecter avant de pouvoir aller en ligne.&lt;/p&gt;
@@ -208,6 +220,8 @@
<translation id="1559572115229829303">&lt;p&gt;Impossible d'établir une connexion privée à <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />, car la date et l'heure de votre appareil (<ph name="DATE_AND_TIME" />) sont incorrects.&lt;/p&gt;
&lt;p&gt;Veuillez régler la date et l'heure depuis la section &lt;strong&gt;Général&lt;/strong&gt; de l'application &lt;strong&gt;Paramètres&lt;/strong&gt;.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">Votre administrateur va redémarrer votre appareil à <ph name="TIME" /> le <ph name="DATE" /></translation>
+<translation id="156703335097561114">Renseignements relatifs au réseautage tels que les adresses, la configuration d'interface et la qualité de connexion</translation>
<translation id="1567040042588613346">Cette politique fonctionne comme prévu, mais notez que la même valeur a été définie ailleurs et que cette politique la remplace.</translation>
<translation id="1569487616857761740">Entrez la date d'expiration</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@
<translation id="1583429793053364125">Une erreur s'est produite lors de l'affichage de cette page Web.</translation>
<translation id="1586541204584340881">Les extensions que vous avez installées</translation>
<translation id="1588438908519853928">Normal</translation>
+<translation id="1589050138437146318">Installer ARCore?</translation>
<translation id="1592005682883173041">Accès aux données locales</translation>
<translation id="1594030484168838125">Choisir</translation>
<translation id="160851722280695521">Jouer au jeu du dinosaure dans Chrome</translation>
@@ -279,6 +294,7 @@
<translation id="1763864636252898013">Impossible de vérifier sur le serveur qu'il s'agit bien du domaine <ph name="DOMAIN" />, car son certificat de sécurité n'est pas considéré comme fiable par le système d'exploitation de votre appareil. Cela peut être dû à une mauvaise configuration ou bien à l'interception de votre connexion par un pirate informatique.</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Essayer d'exécuter Windows Network Diagnostics<ph name="END_LINK" />.</translation>
<translation id="1772163372082567643">Le serveur auquel vous accédez, <ph name="ORIGIN" />, a défini un en-tête qui exige qu'une politique d'origine soit appliquée à toutes les demandes qu'il reçoit. Mais l'en-tête est formaté de manière incorrecte, ce qui empêche le navigateur de répondre à votre demande pour <ph name="SITE" />. Les exploitants de sites peuvent utiliser des politiques d'origine pour configurer la sécurité et d'autres propriétés d'un site.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />En savoir plus sur la navigation privée dans Chromium<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">Vos onglets ouverts s'affichent ici</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -406,6 +422,7 @@
<translation id="22081806969704220">Bac 3</translation>
<translation id="2212735316055980242">Règle introuvable</translation>
<translation id="2213606439339815911">Récupération des entrées...</translation>
+<translation id="2213612003795704869">La page est imprimée</translation>
<translation id="2215727959747642672">Modification des fichiers</translation>
<translation id="2218879909401188352">Les cyberpirates actuellement à l'œuvre sur le site <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> pourraient installer des applications dangereuses afin d'endommager votre appareil, d'ajouter des frais cachés à votre facture de téléphonie cellulaire ou de voler vos données personnelles. <ph name="BEGIN_LEARN_MORE_LINK" />En savoir plus<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">Aucune connexion Internet</translation>
@@ -415,6 +432,7 @@
<translation id="2248949050832152960">Utiliser WebAuthn</translation>
<translation id="2250931979407627383">Agrafage par le bord droit</translation>
<translation id="225207911366869382">Cette valeur n'est plus utilisée pour cette politique.</translation>
+<translation id="2256115617011615191">Redémarrer maintenant</translation>
<translation id="2258928405015593961">Entrez une date d'expiration qui aura lieu dans l'avenir, puis réessayez</translation>
<translation id="225943865679747347">Code d'erreur : <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">Erreur HTTP</translation>
@@ -442,6 +460,7 @@
<translation id="2337852623177822836">Paramètre géré par votre administrateur</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> veut s'associer</translation>
<translation id="2346319942568447007">L'image que vous avez copiée</translation>
+<translation id="2350796302381711542">Autoriser <ph name="HANDLER_HOSTNAME" /> à ouvrir tous les liens <ph name="PROTOCOL" /> à la place de <ph name="REPLACED_HANDLER_TITLE" />?</translation>
<translation id="2354001756790975382">Autres favoris</translation>
<translation id="2354430244986887761">La fonctionnalité de navigation sécurisée de Google a récemment <ph name="BEGIN_LINK" />détecté des applications malveillantes<ph name="END_LINK" /> sur <ph name="SITE" />.</translation>
<translation id="2355395290879513365">Des pirates pourraient être en mesure de voir les images que vous regardez sur ce site et vous tromper en les modifiant.</translation>
@@ -467,6 +486,7 @@
<translation id="2413528052993050574">Impossible de vérifier sur le serveur qu'il s'agit bien du domaine <ph name="DOMAIN" />. Il se peut que son certificat de sécurité ait été révoqué. Cela peut être dû à une mauvaise configuration ou bien à l'interception de votre connexion par un pirate informatique.</translation>
<translation id="2414886740292270097">Foncé</translation>
<translation id="2430968933669123598">Gérer le compte Google, appuyez sur Entrée pour gérer vos renseignements, la confidentialité et la sécurité de votre compte Google</translation>
+<translation id="2436186046335138073">Autoriser <ph name="HANDLER_HOSTNAME" /> à ouvrir tous les liens <ph name="PROTOCOL" />?</translation>
<translation id="2438874542388153331">Quadruple perforation à droite</translation>
<translation id="2450021089947420533">Explorations</translation>
<translation id="2463739503403862330">Remplir</translation>
@@ -474,6 +494,7 @@
<translation id="2465655957518002998">Choisir un mode de livraison</translation>
<translation id="2465688316154986572">Agrafe</translation>
<translation id="2465914000209955735">Gérez les fichiers que vous avez téléchargés dans Chrome</translation>
+<translation id="2466004615675155314">Afficher les informations provenant du Web</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />d'exécuter Network Diagnostics<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">Ordre 1 sur N</translation>
<translation id="2470767536994572628">Lorsque vous modifiez des annotations, ce document s'affiche au format de vue par page, dans son orientation d'origine</translation>
@@ -494,6 +515,7 @@
<translation id="2523886232349826891">Carte enregistrée sur cet appareil uniquement</translation>
<translation id="2524461107774643265">Ajouter plus de renseignements</translation>
<translation id="2529899080962247600">Ce champ ne peut pas contenir plus de <ph name="MAX_ITEMS_LIMIT" /> entrées. Toutes les entrées supplémentaires seront ignorées.</translation>
+<translation id="2535585790302968248">Ouvrir une nouvelle fenêtre en mode de navigation privée pour naviguer en mode privé</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{et 1 autre}one{et # autre}other{et # autres}}</translation>
<translation id="2536110899380797252">Ajouter une adresse</translation>
<translation id="2539524384386349900">Détecter</translation>
@@ -519,7 +541,14 @@
<translation id="2597378329261239068">Ce document est protégé par un mot de passe. Veuillez entrer ce mot de passe.</translation>
<translation id="2609632851001447353">Variations</translation>
<translation id="2610561535971892504">Cliquer pour copier</translation>
+<translation id="2617988307566202237">Chrome <ph name="BEGIN_EMPHASIS" />n'enregistre pas<ph name="END_EMPHASIS" /> les informations suivantes :
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Votre historique de navigation
+ <ph name="LIST_ITEM" />Les témoins et les données relatives aux sites
+ <ph name="LIST_ITEM" />Les informations saisies dans les formulaires
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">Enveloppe C10</translation>
+<translation id="2623663032199728144">Vous pouvez demander à utiliser des renseignements sur vos écrans</translation>
<translation id="2625385379895617796">Votre horloge avance</translation>
<translation id="262745152991669301">Les sites peuvent demander à se connecter à des appareils USB</translation>
<translation id="2629325967560697240">Pour profiter du niveau de sécurité le plus élevé de Chrome, <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />activez la protection renforcée<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -553,6 +582,7 @@
<translation id="2709516037105925701">Remplissage automatique</translation>
<translation id="2713444072780614174">Blanc</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />, appuyez sur la touche Tabulation, puis sur la touche Entrée pour gérer vos données de paiement et vos cartes de crédit dans les paramètres de Chrome</translation>
+<translation id="271663710482723385">Appuyez sur |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| pour quitter le mode plein écran</translation>
<translation id="2721148159707890343">Demande réussie</translation>
<translation id="2723669454293168317">Effectuer une vérification de sécurité dans les paramètres de Chrome</translation>
<translation id="2726001110728089263">Plateau latéral</translation>
@@ -583,6 +613,7 @@
<translation id="2850739647070081192">Enveloppe d'invitation</translation>
<translation id="2856444702002559011">Les cyberpirates peuvent essayer de voler vos données à partir de <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (par exemple, des mots de passe, des messages ou des numéros de carte de crédit). <ph name="BEGIN_LEARN_MORE_LINK" />En savoir plus<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">Ce site diffuse des annonces intrusives ou trompeuses.</translation>
+<translation id="286512204874376891">Une carte virtuelle masque votre carte réelle pour vous protéger de fraudes potentielles. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">Amical</translation>
<translation id="2876489322757410363">Vous devez désactiver le mode de navigation privée pour effectuer un paiement par l'intermédiaire d'une application externe. Continuer?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />, appuyez sur la touche Tabulation, puis sur la touche Entrée pour gérer votre navigation sécurisée et plus dans les paramètres de Chrome</translation>
@@ -607,6 +638,7 @@
<translation id="2930577230479659665">Couper après chaque copie</translation>
<translation id="2932085390869194046">Suggérer un mot de passe…</translation>
<translation id="2934466151127459956">Lettre (gouvernement)</translation>
+<translation id="2938225289965773019">Ouvrir des liens <ph name="PROTOCOL" /></translation>
<translation id="2941952326391522266">Impossible de vérifier sur le serveur qu'il s'agit bien du domaine <ph name="DOMAIN" />, car son certificat de sécurité provient du domaine <ph name="DOMAIN2" />. Cela peut être dû à une mauvaise configuration ou bien à l'interception de votre connexion par un pirate informatique.</translation>
<translation id="2943895734390379394">Heure du téléversement :</translation>
<translation id="2948083400971632585">Vous pouvez désactiver tout mandataire configuré pour une connexion à partir de la page des paramètres.</translation>
@@ -639,6 +671,7 @@
<translation id="3037605927509011580">Aïe aïe aïe!</translation>
<translation id="3041612393474885105">Information relative au certificat</translation>
<translation id="3044034790304486808">Reprendre votre recherche</translation>
+<translation id="305162504811187366">L'historique du Bureau à distance Chrome, y compris les estampilles temporelles, les hôtes et les identifiants de session client</translation>
<translation id="3060227939791841287">Enveloppe C9</translation>
<translation id="3061707000357573562">Service de correctif</translation>
<translation id="306573536155379004">Jeu démarré.</translation>
@@ -679,6 +712,7 @@
<translation id="3197136577151645743">Les sites peuvent demander à savoir quand vous utilisez activement cet appareil</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />, appuyez sur Tabulation, puis sur Entrée pour gérer quelles données vous synchronisez dans les paramètres de Chrome</translation>
<translation id="320323717674993345">Annuler le paiement</translation>
+<translation id="3203366800380907218">Du Web</translation>
<translation id="3207960819495026254">Favori</translation>
<translation id="3209034400446768650">Cette page peut exiger des frais</translation>
<translation id="3212581601480735796">Votre activité sur <ph name="HOSTNAME" /> est surveillée</translation>
@@ -695,10 +729,12 @@
<translation id="3234666976984236645">Toujours détecter le contenu important sur ce site</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />, appuyez sur la touche Tabulation, puis sur la touche Entrée pour personnaliser le style de votre navigateur</translation>
<translation id="3240791268468473923">La zone de contenu dans le bas de l'écran indiquant qu'aucun authentifiant ne correspond au paiement sécurisé est ouverte</translation>
+<translation id="324180406144491771">Les liens de « <ph name="HOST_NAME" /> » sont bloqués</translation>
<translation id="3249845759089040423">Pimpant</translation>
<translation id="3252266817569339921">Français</translation>
<translation id="3257954757204451555">Qui est derrière cette information?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />, appuyez sur Tabulation, puis sur Entrée pour rapidement créer un événement dans Google Agenda</translation>
+<translation id="3261488570342242926">En savoir plus sur les cartes virtuelles</translation>
<translation id="3264837738038045344">Bouton Gérer les paramètres de Chrome, appuyez sur la touche Entrée pour accéder à vos paramètres de Chrome</translation>
<translation id="3266793032086590337">Valeur (conflit)</translation>
<translation id="3268451620468152448">Onglets ouverts</translation>
@@ -712,6 +748,7 @@
<translation id="3288238092761586174"><ph name="URL" /> pourrait devoir prendre des mesures supplémentaires pour vérifier votre paiement</translation>
<translation id="3293642807462928945">En savoir plus sur la politique <ph name="POLICY_NAME" /></translation>
<translation id="3295444047715739395">Affichez et gérez vos mots de passe dans les paramètres de Chrome</translation>
+<translation id="3303795387212510132">Autoriser l'application à ouvrir les liens <ph name="PROTOCOL_SCHEME" />?</translation>
<translation id="3303855915957856445">Aucun résultat de recherche n'a été trouvé</translation>
<translation id="3304073249511302126">recherche d'appareils Bluetooth</translation>
<translation id="3308006649705061278">Unité organisationnelle (« OU »)</translation>
@@ -725,12 +762,6 @@
<translation id="3345782426586609320">Yeux</translation>
<translation id="3355823806454867987">Modifier les paramètres du mandataire...</translation>
<translation id="3360103848165129075">Feuille du module de traitement du paiement</translation>
-<translation id="3361596688432910856">Chrome <ph name="BEGIN_EMPHASIS" />n'enregistrera pas<ph name="END_EMPHASIS" /> les données suivantes :
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />votre historique de navigation;
- <ph name="LIST_ITEM" />les témoins et les données de sites;
- <ph name="LIST_ITEM" />les renseignements fournis dans les formulaires.
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">Cette politique a été automatiquement copiée à partir de la politique obsolète <ph name="OLD_POLICY" />. Vous devriez utiliser cette politique à la place.</translation>
<translation id="3364869320075768271"><ph name="URL" /> souhaite utiliser vos appareils et vos données de réalité virtuelle</translation>
<translation id="3366477098757335611">Afficher les cartes</translation>
@@ -813,7 +844,6 @@
<translation id="3587738293690942763">Centre</translation>
<translation id="3592413004129370115">Enveloppe italienne</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{Vous pouvez réinitialiser votre groupe en tout temps. Il faut environ un jour pour vous joindre à un nouveau groupe.}=1{Vous pouvez réinitialiser votre groupe en tout temps. Il faut environ un jour pour vous joindre à un nouveau groupe.}one{Vous pouvez réinitialiser votre groupe en tout temps. Il faut environ {NUM_DAYS} jour pour vous joindre à un nouveau groupe.}other{Vous pouvez réinitialiser votre groupe en tout temps. Il faut environ {NUM_DAYS} jours pour vous joindre à un nouveau groupe.}}</translation>
-<translation id="3596012367874587041">Paramètres de l'application</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">Application bloquée par votre administrateur</translation>
<translation id="3608932978122581043">Orientation de l'alimentation</translation>
@@ -856,6 +886,7 @@
<translation id="370972442370243704">Activer la fonctionnalité Parcours</translation>
<translation id="3711895659073496551">Mettre en veille</translation>
<translation id="3712624925041724820">Licences épuisées.</translation>
+<translation id="3714633008798122362">Agenda Web</translation>
<translation id="3714780639079136834">D'activer les données mobiles ou le Wi-Fi</translation>
<translation id="3715597595485130451">Connexion au réseau Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />De vérifier la configuration du mandataire, du pare-feu et du DNS<ph name="END_LINK" /></translation>
@@ -917,6 +948,7 @@
<translation id="3906954721959377182">Tablette</translation>
<translation id="3909477809443608991"><ph name="URL" /> veut lire du contenu protégé. L'identité de votre appareil sera vérifiée par Google et sera accessible par ce site.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">Refuser</translation>
<translation id="3939773374150895049">Utiliser WebAuthn au lieu du code CVC?</translation>
<translation id="3946209740501886391">Toujours demander sur ce site</translation>
<translation id="3947595700203588284">Les sites peuvent demander à se connecter à des appareils MIDI</translation>
@@ -937,6 +969,7 @@
<translation id="3987940399970879459">Moins de 1 Mo</translation>
<translation id="3990250421422698716">Décalage</translation>
<translation id="3996311196211510766">Le site <ph name="ORIGIN" /> a exigé qu'une politique d'origine soit appliquée à toutes les demandes qu'il reçoit, mais cette politique ne peut pas être appliquée actuellement.</translation>
+<translation id="4009243425692662128">Le contenu des pages que vous imprimez est envoyé à Google Cloud ou à des tiers à des fins d'analyse. Par exemple, il pourrait être analysé pour déterminer s'il contient des données confidentielles.</translation>
<translation id="4010758435855888356">Autoriser l'accès à l'espace de stockage?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{Document PDF contenant {COUNT} page}one{Document PDF contenant {COUNT} page}other{Document PDF contenant {COUNT} pages}}</translation>
<translation id="4023431997072828269">Comme ce formulaire est envoyé à l'aide d'une connexion qui n'est pas sécurisée, vos données pourraient être visibles par d'autres utilisateurs.</translation>
@@ -1027,6 +1060,7 @@
<translation id="4250680216510889253">Non</translation>
<translation id="4253168017788158739">Remarque</translation>
<translation id="425582637250725228">Il est possible que les modifications que vous avez effectuées ne soient pas enregistrées.</translation>
+<translation id="425869179292622354">Augmenter la sécurité avec une carte virtuelle?</translation>
<translation id="4258748452823770588">Signature incorrecte</translation>
<translation id="4261046003697461417">Les documents protégés ne peuvent pas être annotés</translation>
<translation id="4265872034478892965">Autorisée par votre administrateur</translation>
@@ -1089,6 +1123,7 @@
<translation id="4434045419905280838">Fenêt. context. et redirections</translation>
<translation id="4435702339979719576">Carte postale</translation>
<translation id="443673843213245140">L'utilisation d'un mandataire est désactivée, mais une configuration de mandataire explicite est spécifiée.</translation>
+<translation id="4441832193888514600">Configuration ignorée parce que la politique peut uniquement être définie en tant que politique utilisateur du nuage.</translation>
<translation id="4450893287417543264">Ne plus afficher</translation>
<translation id="4451135742916150903">Les sites peuvent demander à se connecter à des appareils HID</translation>
<translation id="4452328064229197696">Le mot de passe que vous venez juste d'utiliser a été trouvé dans une violation de données. Pour sécuriser vos comptes, le Gestionnaire de mots de passe Google vous recommande de vérifier vos mots de passe enregistrés.</translation>
@@ -1144,6 +1179,7 @@
<translation id="4628948037717959914">Photo</translation>
<translation id="4631649115723685955">Avec remise en argent</translation>
<translation id="4636930964841734540">Renseignements</translation>
+<translation id="4638670630777875591">Navigation privée dans Chromium</translation>
<translation id="464342062220857295">Rechercher des fonctionnalités</translation>
<translation id="4644670975240021822">Ordre inversé, face vers le bas</translation>
<translation id="4646534391647090355">Y accéder maintenant</translation>
@@ -1164,6 +1200,7 @@
<translation id="4708268264240856090">Votre connexion a été interrompue</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />d'exécuter Windows Network Diagnostics<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426">Mot de passe pour <ph name="USERNAME" /></translation>
<translation id="4724144314178270921">Les sites peuvent demander à voir le texte et les images de votre presse-papiers</translation>
<translation id="4726672564094551039">Actualiser les règles</translation>
<translation id="4728558894243024398">Plateforme</translation>
@@ -1185,6 +1222,7 @@
<translation id="4757993714154412917">Vous venez d'entrer votre mot de passe sur un site trompeur. Pour sécuriser vos comptes, Chromium vous recommande de vérifier vos mots de passe enregistrés.</translation>
<translation id="4758311279753947758">Ajouter des coordonnées</translation>
<translation id="4761104368405085019">Utiliser votre microphone</translation>
+<translation id="4761869838909035636">Effectuer une vérification de sécurité de Chrome</translation>
<translation id="4764776831041365478">Il se peut que la page Web à l'adresse <ph name="URL" /> soit temporairement inaccessible ou qu'elle ait été déplacée de façon permanente à une autre adresse Web.</translation>
<translation id="4766713847338118463">Double agrafe en bas</translation>
<translation id="4771973620359291008">Une erreur inconnue s'est produite.</translation>
@@ -1205,12 +1243,6 @@
<translation id="4819347708020428563">Modifier les annotations dans la vue par défaut?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />, appuyez sur Tabulation, puis sur Entrée pour rapidement créer une feuille Google</translation>
<translation id="4825507807291741242">Puissant</translation>
-<translation id="4827402517081186284">La navigation privée ne vous rend pas invisible en ligne :
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Les sites savent que vous les consultez.<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Votre employeur ou votre établissement scolaire peuvent suivre votre activité de navigation.<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Les fournisseurs d'accès Internet peuvent surveiller le trafic Web.<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">Activer les avertissements</translation>
<translation id="4838327282952368871">Rêveur</translation>
<translation id="4840250757394056958">Afficher votre historique de Chrome</translation>
@@ -1222,12 +1254,12 @@
<translation id="4854362297993841467">Ce mode de livraison n'est pas disponible. Essayez un autre mode.</translation>
<translation id="4854853140771946034">Créer rapidement une note dans Google Keep</translation>
<translation id="485902285759009870">Vérification du code en cours…</translation>
+<translation id="4866506163384898554">Appuyez sur |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| pour afficher votre curseur</translation>
<translation id="4876188919622883022">Affichage simplifié</translation>
<translation id="4876305945144899064">Aucun nom d'utilisateur</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{Aucun}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}one{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831">Rechercher <ph name="TEXT" /></translation>
<translation id="4879491255372875719">Automatique (par défaut)</translation>
-<translation id="4879725228911483934">Ouvrir et placer des fenêtres sur vos écrans</translation>
<translation id="4880827082731008257">Rechercher dans l'historique</translation>
<translation id="4881695831933465202">Ouvrir</translation>
<translation id="4885256590493466218">Payez avec <ph name="CARD_DETAIL" /> au moment d'effectuer le paiement</translation>
@@ -1236,6 +1268,7 @@
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">Neuvième rouleau</translation>
<translation id="4901778704868714008">Enregistrer…</translation>
+<translation id="4905659621780993806">Votre administrateur va automatiquement redémarrer votre appareil à <ph name="TIME" /> le <ph name="DATE" />. Enregistrez tous les éléments ouverts avant le redémarrage de votre appareil.</translation>
<translation id="4913987521957242411">Perforation en haut à gauche</translation>
<translation id="4918221908152712722">Installer <ph name="APP_NAME" /> (aucun téléchargement nécessaire)</translation>
<translation id="4923459931733593730">Paiement</translation>
@@ -1244,6 +1277,7 @@
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, appuyez sur la touche Tabulation, puis sur la touche Entrée pour lancer la recherche</translation>
<translation id="4930153903256238152">Grande capacité</translation>
+<translation id="4940163644868678279">Navigation privée dans Chrome</translation>
<translation id="4943872375798546930">Aucun résultat</translation>
<translation id="4950898438188848926">Bouton de commutation d'onglet, appuyez sur Entrée pour basculer vers l'onglet ouvert, <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="495170559598752135">Actions</translation>
@@ -1253,6 +1287,7 @@
<translation id="4968522289500246572">Cette application est développée pour les appareils mobiles et elle ne sera peut-être pas bien redimensionnée. L'application peut rencontrer des problèmes ou redémarrer.</translation>
<translation id="4969341057194253438">Supprimer l'enregistrement</translation>
<translation id="4973922308112707173">Double perforation en haut</translation>
+<translation id="4976702386844183910">Dernière visite : <ph name="DATE" /></translation>
<translation id="4984088539114770594">Utiliser le microphone?</translation>
<translation id="4984339528288761049">Enveloppe Prc5</translation>
<translation id="4989163558385430922">Tout afficher</translation>
@@ -1314,6 +1349,7 @@
<translation id="5138227688689900538">Afficher moins</translation>
<translation id="5145883236150621069">Code d'erreur présent dans la réponse de la politique</translation>
<translation id="5146995429444047494">Les notifications pour <ph name="ORIGIN" /> sont bloquées</translation>
+<translation id="514704532284964975">Le site <ph name="URL" /> veut consulter et modifier les données stockées sur les appareils CCP que vous touchez avec votre téléphone</translation>
<translation id="5148809049217731050">Face vers le haut</translation>
<translation id="515292512908731282">Enveloppe C4</translation>
<translation id="5158275234811857234">Couverture</translation>
@@ -1338,6 +1374,7 @@
<translation id="5215116848420601511">Modes de paiement et adresses utilisant Google Pay</translation>
<translation id="5215363486134917902">Folio SP</translation>
<translation id="521659676233207110">Bac 13</translation>
+<translation id="5216942107514965959">Dernière visite : aujourd'hui</translation>
<translation id="5222812217790122047">Adresse de courriel obligatoire</translation>
<translation id="5230733896359313003">Adresse de livraison</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1358,7 +1395,6 @@
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">Propriétés du document</translation>
<translation id="528468243742722775">Fin</translation>
-<translation id="5284909709419567258">Adresses réseau</translation>
<translation id="5285570108065881030">Afficher tous les mots de passe enregistrés</translation>
<translation id="5287240709317226393">Afficher les témoins</translation>
<translation id="5287456746628258573">Ce site utilise une configuration de sécurité obsolète qui pourrait exposer vos données personnelles (par exemple, vos mots de passe ou vos numéros de carte de crédit) lorsqu'elles sont envoyées à ce site.</translation>
@@ -1442,6 +1478,7 @@
<translation id="5556459405103347317">Actualiser</translation>
<translation id="5560088892362098740">Date d'expiration</translation>
<translation id="55635442646131152">Plan du document</translation>
+<translation id="5565613213060953222">Ouvrir l'onglet de navigation privée</translation>
<translation id="5565735124758917034">Actif</translation>
<translation id="5570825185877910964">Protéger le compte</translation>
<translation id="5571083550517324815">Impossible d'effectuer un ramassage à partir de cette adresse. Sélectionnez une autre adresse.</translation>
@@ -1524,6 +1561,7 @@
<translation id="5869522115854928033">Mots de passe enregistrés</translation>
<translation id="5873013647450402046">Votre banque veut confirmer votre identité.</translation>
<translation id="5887400589839399685">Carte enregistrée</translation>
+<translation id="5887687176710214216">Dernière visite : hier.</translation>
<translation id="5895138241574237353">Redémarrer</translation>
<translation id="5895187275912066135">Émis le :</translation>
<translation id="5901630391730855834">Jaune</translation>
@@ -1537,6 +1575,7 @@
<translation id="5921639886840618607">Enregistrer la carte dans votre compte Google?</translation>
<translation id="5922853866070715753">Vous avez presque terminé</translation>
<translation id="5932224571077948991">Site diffusant des annonces intrusives ou trompeuses</translation>
+<translation id="5938153366081463283">Ajouter une carte virtuelle</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347">Ouverture du site <ph name="SITE_NAME" /> en cours…</translation>
<translation id="5951495562196540101">Impossible de s'inscrire avec un compte de consommateur (licence empaquetée disponible).</translation>
@@ -1601,6 +1640,7 @@
<translation id="6120179357481664955">Se souvenir de votre identifiant UPI?</translation>
<translation id="6124432979022149706">Connecteurs Chrome Enterprise</translation>
<translation id="6127379762771434464">Élément supprimé</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />En savoir plus sur la navigation privée dans Chrome<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">Vérifiez les câbles et redémarrez votre routeur, votre modem
ou tout autre périphérique réseau utilisé.</translation>
<translation id="614940544461990577">Essayez ceci :</translation>
@@ -1613,7 +1653,6 @@
<translation id="6169916984152623906">Vous pouvez maintenant naviguer de façon privée, et les autres personnes qui utilisent cet appareil ne verront pas votre activité. Cependant, les téléchargements et les favoris seront sauvegardés.</translation>
<translation id="6177128806592000436">Votre connexion à ce site n'est pas sécurisée</translation>
<translation id="6180316780098470077">Intervalle entre les nouveaux essais</translation>
-<translation id="619448280891863779">Les sites peuvent demander à ouvrir et à placer des fenêtres sur vos écrans</translation>
<translation id="6196640612572343990">Bloquer les témoins de tiers</translation>
<translation id="6203231073485539293">Vérifiez votre connexion Internet</translation>
<translation id="6218753634732582820">Supprimer l'adresse de Chromium?</translation>
@@ -1636,7 +1675,7 @@
<translation id="6272383483618007430">Mise à jour Google</translation>
<translation id="6276112860590028508">Les pages de votre liste de lecture apparaissent ici</translation>
<translation id="627746635834430766">Pour accélérer le paiement la prochaine fois, enregistrez votre carte et votre adresse de facturation dans votre compte Google.</translation>
-<translation id="6279098320682980337">Numéro de carte virtuelle non rempli? Cliquez sur les détails de la carte pour les copier</translation>
+<translation id="6279183038361895380">Appuyez sur |<ph name="ACCELERATOR" />| pour afficher votre curseur</translation>
<translation id="6280223929691119688">Impossible d'effectuer une livraison à cette adresse. Sélectionnez une autre adresse.</translation>
<translation id="6282194474023008486">Code postal</translation>
<translation id="6285507000506177184">Bouton Gérer les téléchargements dans Chrome, appuyez sur la touche Entrée pour gérer les fichiers que vous avez téléchargés dans Chrome</translation>
@@ -1644,6 +1683,7 @@
<translation id="6290238015253830360">Les articles que vous avez suggérés s'afficheront ici</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">Code CVC :</translation>
+<translation id="6300452962057769623">{0,plural, =0{Votre appareil va redémarrer maintenant}=1{Votre appareil va redémarrer dans 1 seconde}one{Votre appareil va redémarrer dans # seconde}other{Votre appareil va redémarrer dans # secondes}}</translation>
<translation id="6302269476990306341">Arrêt de l'Assistant Google dans Chrome en cours…</translation>
<translation id="6305205051461490394">Impossible d'accéder à <ph name="URL" />.</translation>
<translation id="6312113039770857350">La page Web n'est pas disponible</translation>
@@ -1717,6 +1757,7 @@
<translation id="6529602333819889595">&amp;Rétablir la suppression</translation>
<translation id="6545864417968258051">Recherche d'appareils Bluetooth</translation>
<translation id="6547208576736763147">Double perforation à gauche</translation>
+<translation id="6554732001434021288">Dernière visite il y a <ph name="NUM_DAYS" /> jours</translation>
<translation id="6556866813142980365">Rétablir</translation>
<translation id="6569060085658103619">Vous consultez une page d'extension</translation>
<translation id="6573200754375280815">Double perforation à droite</translation>
@@ -1777,7 +1818,6 @@
<translation id="6757797048963528358">Votre appareil s'est mis en veille.</translation>
<translation id="6767985426384634228">Mettre à jour l'adresse?</translation>
<translation id="6768213884286397650">Carte postale hagaki</translation>
-<translation id="6774185088257932239"><ph name="BEGIN_LINK" />En savoir plus<ph name="END_LINK" /> à propos de la navigation privée</translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">Violet</translation>
<translation id="6786747875388722282">Extensions</translation>
@@ -1861,7 +1901,6 @@
<translation id="706295145388601875">Ajoutez et gérez les adresses dans les paramètres de Chrome</translation>
<translation id="7064851114919012435">Coordonnées</translation>
<translation id="7068733155164172741">Entrez le code à <ph name="OTP_LENGTH" /> chiffres</translation>
-<translation id="7070090581017165256">À propos de ce site</translation>
<translation id="70705239631109039">Votre connexion n'est pas parfaitement sécurisée</translation>
<translation id="7075452647191940183">La taille de la requête est trop grande</translation>
<translation id="7079718277001814089">Ce site contient des logiciels malveillants</translation>
@@ -1878,6 +1917,12 @@
<translation id="7111012039238467737">(Valide)</translation>
<translation id="7118618213916969306">Rechercher l'URL du presse-papiers : <ph name="SHORT_URL" /></translation>
<translation id="7119414471315195487">Fermer les autres onglets ou programmes</translation>
+<translation id="7129355289156517987">Lorsque vous fermez tous les onglets de navigation privée de Chromium, votre activité dans ces onglets est effacée de cet appareil :
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Votre activité de navigation<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Votre historique de recherche<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Les informations saisies dans les formulaires<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">Impossible d'effectuer une livraison à cette adresse. Sélectionnez une autre adresse.</translation>
<translation id="7132939140423847331">Votre administrateur a interdit la copie de ces données.</translation>
<translation id="7135130955892390533">Afficher l’état</translation>
@@ -1900,6 +1945,7 @@
<translation id="7192203810768312527">Libère <ph name="SIZE" />. Certains sites peuvent être plus longs à charger lors de votre prochaine visite.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">Votre administrateur peut voir :</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, appuyez sur Tabulation, puis sur Entrée pour ouvrir un nouvel onglet de navigation privée afin de naviguer en mode privé</translation>
<translation id="7202346780273620635">Lettre extra</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> ne respecte pas les normes en matière de sécurité.</translation>
<translation id="7210993021468939304">Activité Linux dans le conteneur, et peut installer et exécuter des applications Linux dans le conteneur</translation>
@@ -1931,6 +1977,7 @@ Détails supplémentaires :
<translation id="7304562222803846232">Gérer les paramètres de confidentialité du compte Google</translation>
<translation id="7305756307268530424">Vitesse plus lente</translation>
<translation id="7308436126008021607">Synchronisation en arrière-plan</translation>
+<translation id="7310392214323165548">L'appareil va redémarrer sous peu</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">Aide pour la connexion</translation>
<translation id="7323804146520582233">Masquer la section « <ph name="SECTION" /> »</translation>
@@ -1938,6 +1985,7 @@ Détails supplémentaires :
<translation id="7334320624316649418">&amp;Rétablir la réorganisation</translation>
<translation id="7335157162773372339">Les sites peuvent demander à utiliser votre appareil photo</translation>
<translation id="7337248890521463931">Afficher plus de lignes</translation>
+<translation id="7337418456231055214">Le numéro de carte virtuelle n'est pas rempli? Cliquez sur les détails de la carte pour les copier. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">Non disponible sur votre plateforme.</translation>
<translation id="733923710415886693">Le certificat du serveur n'a pas été divulgué par l'intermédiaire de l'outil Certificate Transparency.</translation>
<translation id="734600844861828519">11 po x 15 po</translation>
@@ -1960,6 +2008,7 @@ Détails supplémentaires :
<translation id="7378627244592794276">Pas maintenant</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">Non applicable</translation>
+<translation id="7388594495505979117">{0,plural, =1{Votre appareil va redémarrer dans 1 minute}one{Votre appareil va redémarrer dans # minute}other{Votre appareil va redémarrer dans # minutes}}</translation>
<translation id="7390545607259442187">Confirmer la carte</translation>
<translation id="7392089738299859607">Mettre à jour l'adresse</translation>
<translation id="7399802613464275309">Vérification de sécurité</translation>
@@ -1996,6 +2045,12 @@ Détails supplémentaires :
<translation id="7485870689360869515">Aucune donnée trouvée.</translation>
<translation id="7495528107193238112">Ce contenu est bloqué. Communiquez avec le propriétaire du site pour corriger le problème.</translation>
<translation id="7497998058912824456">Bouton Créer un document, appuyez sur la touche Entrée pour rapidement créer un document Google</translation>
+<translation id="7506488012654002225">Chromium <ph name="BEGIN_EMPHASIS" />n'enregistre pas<ph name="END_EMPHASIS" /> les informations suivantes :
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Votre historique de navigation
+ <ph name="LIST_ITEM" />Les témoins et les données relatives aux sites
+ <ph name="LIST_ITEM" />Les informations saisies dans les formulaires
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">L'ID d'appareil de la règle renvoyé est vide ou ne correspond pas à l'ID d'appareil actuel</translation>
<translation id="7508870219247277067">Avocat</translation>
<translation id="7511955381719512146">Le réseau Wi-Fi que vous utilisez peut vous demander de visiter <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
@@ -2109,7 +2164,6 @@ Détails supplémentaires :
<translation id="7813600968533626083">Supprimer la suggestion de formulaire de Chrome?</translation>
<translation id="781440967107097262">Partager le presse-papiers?</translation>
<translation id="7815407501681723534"><ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> résultat(s) trouvé(s) pour « <ph name="SEARCH_STRING" /> »</translation>
-<translation id="782125616001965242">Afficher des renseignements à propos de ce site</translation>
<translation id="782886543891417279">Le réseau Wi-Fi que vous utilisez (<ph name="WIFI_NAME" />) peut vous demander de visiter sa page de connexion.</translation>
<translation id="7836231406687464395">Enveloppe Postfix</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{Aucune}=1{1 application : <ph name="EXAMPLE_APP_1" />}=2{2 applications (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}one{# application (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}other{# applications (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}}</translation>
@@ -2126,7 +2180,6 @@ Détails supplémentaires :
<translation id="7888575728750733395">Intention de rendu d'impression</translation>
<translation id="7894280532028510793">S'il n'y a pas d'erreur, <ph name="BEGIN_LINK" />essayez d'exécuter les diagnostics de réseau<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">Enveloppe C3</translation>
-<translation id="7931318309563332511">Inconnue</translation>
<translation id="793209273132572360">Mettre à jour l'adresse?</translation>
<translation id="7932579305932748336">Revêtement</translation>
<translation id="79338296614623784">Entrez un numéro de téléphone valide</translation>
@@ -2151,13 +2204,14 @@ Détails supplémentaires :
<translation id="7976214039405368314">Trop de demandes</translation>
<translation id="7977538094055660992">Appareil de sortie</translation>
<translation id="7977894662897852582">EDP</translation>
+<translation id="7981260203882740562">Associée à</translation>
<translation id="798134797138789862">Les sites peuvent demander à utiliser des données et des appareils de réalité virtuelle</translation>
<translation id="7984945080620862648">Vous ne pouvez pas consulter le site <ph name="SITE" /> pour le moment, car il a envoyé des identifiants brouillés qui ne peuvent être traités par Chrome. Les erreurs réseau et les attaques sont généralement temporaires. Vous devriez donc pouvoir accéder à cette page plus tard.</translation>
-<translation id="79859296434321399">Pour regarder du contenu de réalité augmentée, installez ARCore</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">Reliure</translation>
<translation id="7992044431894087211">Le partage d'écran avec <ph name="APPLICATION_TITLE" /> a repris</translation>
<translation id="7995512525968007366">Non spécifié</translation>
+<translation id="7998269595945679889">Ouvrez le bouton de l'onglet de navigation privée, appuyez sur Entrée pour ouvrir un nouvel onglet de navigation privée afin de naviguer en mode privé</translation>
<translation id="800218591365569300">Essayez de fermer d'autres onglets ou programmes pour libérer de la mémoire.</translation>
<translation id="8004582292198964060">Navigateur</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{Cette carte et l'adresse de facturation associée seront enregistrées. Vous serez en mesure de l'utiliser lorsque vous serez connecté en tant que <ph name="USER_EMAIL" />.}one{Cette carte et l'adresse de facturation associée seront enregistrées. Vous serez en mesure de l'utiliser lorsque vous serez connecté en tant que <ph name="USER_EMAIL" />.}other{Ces cartes et les adresses de facturation associées seront enregistrées. Vous serez en mesure de les utiliser lorsque vous serez connecté en tant que <ph name="USER_EMAIL" />.}}</translation>
@@ -2217,6 +2271,7 @@ Détails supplémentaires :
<translation id="8202370299023114387">Conflit</translation>
<translation id="8206978196348664717">Enveloppe Prc4</translation>
<translation id="8211406090763984747">Connexion sécurisée</translation>
+<translation id="8217240300496046857">Les sites ne peuvent pas utiliser de témoins qui suivent votre activité sur le Web. Les fonctionnalités sur certains sites peuvent ne pas fonctionner.</translation>
<translation id="8218327578424803826">Emplacement attribué :</translation>
<translation id="8220146938470311105">Enveloppe C7/C6</translation>
<translation id="8225771182978767009">La personne qui a configuré cet ordinateur a choisi de bloquer ce site.</translation>
@@ -2257,14 +2312,9 @@ Détails supplémentaires :
<translation id="830498451218851433">Plier en deux</translation>
<translation id="8307358339886459768">Petite photo</translation>
<translation id="8307888238279532626">Les applications installées et leur fréquence d'utilisation</translation>
+<translation id="8317207217658302555">Mettre à jour ARCore?</translation>
<translation id="831997045666694187">Soirée</translation>
<translation id="8321476692217554900">Notifications</translation>
-<translation id="8328484624016508118">Lorsque vous fermez tous les onglets de navigation privée, Chrome efface :
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />votre activité de navigation sur cet appareil;<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />l'historique de vos recherches sur cet appareil;<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />les renseignements entrés dans des formulaires.<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489">Accès à l'adresse <ph name="HOST_NAME" /> refusé</translation>
<translation id="833262891116910667">Surligner</translation>
<translation id="8339163506404995330">Les pages en <ph name="LANGUAGE" /> ne seront pas traduites</translation>
@@ -2316,6 +2366,7 @@ Détails supplémentaires :
<translation id="8507227106804027148">Ligne de commande</translation>
<translation id="8508648098325802031">Icône de recherche</translation>
<translation id="8511402995811232419">Gérer les témoins</translation>
+<translation id="8519753333133776369">Appareil HID autorisé par votre administrateur</translation>
<translation id="8522552481199248698">Chrome peut vous aider à protéger votre compte Google et à changer votre mot de passe.</translation>
<translation id="8530813470445476232">Effacez votre historique de navigation, vos témoins, votre cache et plus encore dans les paramètres de Chrome</translation>
<translation id="8533619373899488139">Consultez &lt;strong&gt;chrome://policy&lt;/strong&gt; pour voir les URL bloquées et des politiques mises en œuvre par votre administrateur système.</translation>
@@ -2327,7 +2378,6 @@ Détails supplémentaires :
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{Réinitialiser l'autorisation}one{Réinitialiser l'autorisation}other{Réinitialiser les autorisations}}</translation>
<translation id="8555010941760982128">Utiliser ce code lors du paiement</translation>
<translation id="8557066899867184262">Le code de vérification de carte (CVC) se trouve au dos de votre carte</translation>
-<translation id="8558485628462305855">Pour regarder du contenu de réalité augmentée, mettez à jour ARCore</translation>
<translation id="8559762987265718583">Impossible d'établir une connexion privée à <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />, car la date et l'heure de votre appareil (<ph name="DATE_AND_TIME" />) sont incorrectes.</translation>
<translation id="8564182942834072828">Documents séparés/Copies non assemblées</translation>
<translation id="8564985650692024650">Chromium recommande de réinitialiser votre mot de passe <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> si vous l'avez réutilisé sur d'autres sites.</translation>
@@ -2346,6 +2396,7 @@ Détails supplémentaires :
<translation id="865032292777205197">Capteurs de mouvements</translation>
<translation id="8663226718884576429">Résumé de la commande, <ph name="TOTAL_LABEL" />, plus de détails</translation>
<translation id="8666678546361132282">Anglais</translation>
+<translation id="8669306706049782872">utiliser des renseignements sur vos écrans pour ouvrir et placer des fenêtres;</translation>
<translation id="867224526087042813">Signature</translation>
<translation id="8676424191133491403">Aucun délai</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, réponse, <ph name="ANSWER" /></translation>
@@ -2372,6 +2423,7 @@ Détails supplémentaires :
<translation id="8731544501227493793">Bouton Gérer les mots de passe, appuyez sur la touche Entrée pour afficher et gérer vos mots de passe dans les paramètres de Chrome</translation>
<translation id="8734529307927223492">Votre <ph name="DEVICE_TYPE" /> est géré par <ph name="MANAGER" /></translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, appuyez sur la touche Tabulation, puis sur la touche Entrée pour ouvrir une nouvelle fenêtre de navigation privée afin de naviguer en mode privé</translation>
+<translation id="8737685506611670901">Ouvrir les liens <ph name="PROTOCOL" /> à la place de <ph name="REPLACED_HANDLER_TITLE" /></translation>
<translation id="8738058698779197622">Pour établir une connexion sécurisée, votre horloge doit être réglée correctement. En effet, les sites Web utilisent des certificats d'authentification valides pour une durée limitée. L'horloge de votre appareil étant incorrecte, Chromium ne peut pas authentifier les certificats.</translation>
<translation id="8740359287975076522">L'&lt;abbr id="dnsDefinition"&gt;adresse DNS&lt;/abbr&gt; de <ph name="HOST_NAME" /> est introuvable. Diagnostic du problème en cours.</translation>
<translation id="8742371904523228557"><ph name="ONE_TIME_CODE" /> est votre code pour <ph name="ORIGIN" /></translation>
@@ -2399,6 +2451,7 @@ Détails supplémentaires :
<translation id="883848425547221593">Autres favoris</translation>
<translation id="884264119367021077">Adresse d'expédition</translation>
<translation id="884923133447025588">Aucun mécanisme de révocation découvert.</translation>
+<translation id="8849262850971482943">Utilisez votre carte virtuelle pour renforcer la sécurité</translation>
<translation id="885730110891505394">Partage avec Google</translation>
<translation id="8858065207712248076">Chrome recommande de réinitialiser votre mot de passe <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> si vous l'avez réutilisé sur d'autres sites.</translation>
<translation id="885906927438988819">S'il n'y a pas d'erreur, <ph name="BEGIN_LINK" />essayez d'exécuter Diagnostics réseau de Windows<ph name="END_LINK" />.</translation>
@@ -2448,6 +2501,7 @@ Détails supplémentaires :
<translation id="9004367719664099443">Séance de RV en cours</translation>
<translation id="9005998258318286617">Échec du chargement du document PDF.</translation>
<translation id="9008201768610948239">OK</translation>
+<translation id="901834265349196618">courriel</translation>
<translation id="9020200922353704812">Carte de l'adresse de facturation requise</translation>
<translation id="9020542370529661692">Cette page a été traduite en <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9020742383383852663">A8</translation>
@@ -2496,6 +2550,7 @@ Détails supplémentaires :
<translation id="9150045010208374699">Utiliser votre caméra</translation>
<translation id="9150685862434908345">Votre administrateur peut modifier la configuration de votre navigateur à distance. L'activité sur cet appareil peut aussi être gérée à l'extérieur de Chrome. <ph name="BEGIN_LINK" />En savoir plus<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">Mis à jour</translation>
+<translation id="9155211586651734179">Périphériques audio connectés</translation>
<translation id="9157595877708044936">Configuration en cours...</translation>
<translation id="9158625974267017556">Enveloppe C6</translation>
<translation id="9164029392738894042">Contrôle d'exactitude</translation>
diff --git a/chromium/components/strings/components_strings_fr.xtb b/chromium/components/strings/components_strings_fr.xtb
index 13284083d75..0724082a654 100644
--- a/chromium/components/strings/components_strings_fr.xtb
+++ b/chromium/components/strings/components_strings_fr.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">Voir les détails</translation>
<translation id="1030706264415084469"><ph name="URL" /> souhaite stocker de façon permanente des données volumineuses sur votre appareil</translation>
<translation id="1032854598605920125">Faire pivoter vers la droite</translation>
+<translation id="1033329911862281889">La navigation privée ne vous rend pas invisible sur Internet :
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Les sites et les services qu'ils utilisent peuvent voir que vous les consultez<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Votre employeur ou votre établissement scolaire peuvent connaître votre activité de navigation<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Les fournisseurs d'accès à Internet peuvent surveiller le trafic Web<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">Désactiver</translation>
<translation id="1036982837258183574">Appuyez sur |<ph name="ACCELERATOR" />| pour quitter le mode plein écran.</translation>
<translation id="1038106730571050514">Afficher les suggestions</translation>
<translation id="1038842779957582377">Nom inconnu</translation>
<translation id="1041998700806130099">Message de la feuille de travail</translation>
<translation id="1048785276086539861">Si vous modifiez des annotations, ce document s'affichera en mode "Vue par page"</translation>
-<translation id="1049743911850919806">Navigation privée</translation>
<translation id="1050038467049342496">Fermez les autres applications</translation>
<translation id="1055184225775184556">&amp;Annuler l'ajout</translation>
<translation id="1056898198331236512">Avertissement</translation>
@@ -38,7 +43,7 @@
<translation id="1088860948719068836">Ajouter le nom du titulaire de la carte</translation>
<translation id="1089439967362294234">Modifier le mot de passe</translation>
<translation id="1096545575934602868">Ce champ ne peut pas contenir plus de <ph name="MAX_ITEMS_LIMIT" /> entrées. Toutes les entrées supplémentaires seront supprimées.</translation>
-<translation id="1100782917270858593">Bouton "Reprendre votre exploration", appuyez sur Entrée pour reprendre votre exploration et voir les activités pertinentes dans votre historique Chrome</translation>
+<translation id="1100782917270858593">Bouton "Reprendre votre parcours", appuyez sur Entrée pour reprendre votre parcours et voir les activités pertinentes dans votre historique Chrome</translation>
<translation id="1101672080107056897">Action en cas d'erreur</translation>
<translation id="1103523840287552314">Toujours traduire les pages en <ph name="LANGUAGE" /></translation>
<translation id="1110994991967754504">Sélectionnez une autorisation pour <ph name="PERMISSION_NAME" /></translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">Cache de la règle valide.</translation>
<translation id="1130564665089811311">Bouton "Traduire la page" : appuyer sur Entrée pour traduire cette page avec Google Traduction</translation>
<translation id="1131264053432022307">Image copiée</translation>
+<translation id="1142846828089312304">Bloquer les cookies tiers en mode navigation privée</translation>
<translation id="1150979032973867961">Impossible de vérifier sur le serveur qu'il s'agit bien du domaine <ph name="DOMAIN" />, car son certificat de sécurité n'est pas considéré comme fiable par le système d'exploitation de votre ordinateur. Cela peut être dû à une mauvaise configuration ou bien à l'interception de votre connexion par un pirate informatique.</translation>
<translation id="1151972924205500581">Veuillez saisir un mot de passe</translation>
<translation id="1156303062776767266">Vous consultez un fichier local ou partagé</translation>
@@ -64,7 +70,6 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="1178581264944972037">Suspendre</translation>
<translation id="1181037720776840403">Supprimer</translation>
<translation id="1186201132766001848">Vérifier les mots de passe</translation>
-<translation id="1195210374336998651">Accéder aux paramètres de l'appli</translation>
<translation id="1195558154361252544">Les notifications sont bloquées automatiquement pour tous les sites, sauf ceux que vous autorisez</translation>
<translation id="1197088940767939838">Orange</translation>
<translation id="1201402288615127009">Suivant</translation>
@@ -111,7 +116,7 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="1307966114820526988">Fonctionnalités obsolètes</translation>
<translation id="1308113895091915999">Offre disponible</translation>
<translation id="1312803275555673949">Quelle est la preuve à l'appui ?</translation>
-<translation id="131405271941274527"><ph name="URL" /> souhaite envoyer et recevoir des informations lorsque votre téléphone entre en contact avec un appareil NFC</translation>
+<translation id="1314311879718644478">Afficher les contenus en réalité augmentée</translation>
<translation id="1314509827145471431">Reliure à droite</translation>
<translation id="1318023360584041678">Enregistré dans le groupe d'onglets</translation>
<translation id="1319245136674974084">Ne plus me demander pour cette appli</translation>
@@ -161,6 +166,7 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="142858679511221695">Utilisateur du cloud</translation>
<translation id="1428729058023778569">Vous voyez cet avertissement, car ce site n'est pas HTTPS. <ph name="BEGIN_LEARN_MORE_LINK" />En savoir plus<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">Imprimer</translation>
+<translation id="1432187715652018471">Cette page veut installer un gestionnaire de services.</translation>
<translation id="1432581352905426595">Gérer les moteurs de recherche</translation>
<translation id="1436185428532214179">Peut demander à modifier des fichiers et des dossiers sur votre appareil</translation>
<translation id="1442386063175183758">Pli du volet droit</translation>
@@ -181,6 +187,12 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="1483493594462132177">Envoyer</translation>
<translation id="1484290072879560759">Sélectionner l'adresse de livraison</translation>
<translation id="1492194039220927094">Diffusion push des règles : </translation>
+<translation id="149293076951187737">Lorsque vous fermez tous les onglets de navigation privée de Chrome, les activités effectuées dans ces onglets sont effacées de cet appareil :
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Activité de navigation<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Historique des recherches<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Informations saisies dans les formulaires<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">Retour à l'onglet</translation>
<translation id="1501859676467574491">Afficher les cartes de votre compte Google</translation>
<translation id="1507202001669085618">&lt;p&gt;Ce message s'affiche si vous utilisez un portail Wi-Fi auquel vous devez vous connecter pour accéder à Internet.&lt;/p&gt;
@@ -208,6 +220,8 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="1559572115229829303">&lt;p&gt;Impossible d'établir une connexion privée à <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> : la date et l'heure de votre appareil (<ph name="DATE_AND_TIME" />) sont incorrectes.&lt;/p&gt;
&lt;p&gt;Veuillez ajuster la date et l'heure dans la section &lt;strong&gt;Général&lt;/strong&gt; de l'application &lt;strong&gt;Réglages&lt;/strong&gt;.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">L'administrateur redémarrera votre appareil le <ph name="DATE" /> à <ph name="TIME" /></translation>
+<translation id="156703335097561114">Les informations de réseau, comme les adresses, la configuration d'interface et la qualité de la connexion</translation>
<translation id="1567040042588613346">Cette règle fonctionne comme prévu, mais notez que la même valeur a été définie ailleurs et que cette règle la remplace.</translation>
<translation id="1569487616857761740">Saisir la date d'expiration</translation>
<translation id="1581080074034554886">Code CVC :</translation>
@@ -215,6 +229,7 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="1583429793053364125">Une erreur s'est produite lors de l'affichage de la page Web.</translation>
<translation id="1586541204584340881">Les extensions que vous avez installées</translation>
<translation id="1588438908519853928">Standard</translation>
+<translation id="1589050138437146318">Installer ARCore ?</translation>
<translation id="1592005682883173041">Accès aux données locales</translation>
<translation id="1594030484168838125">Sélectionner</translation>
<translation id="160851722280695521">Jouer au jeu du dino dans Chrome</translation>
@@ -254,7 +269,7 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="1711234383449478798">Ignorée, car <ph name="POLICY_NAME" /> n'est pas définie sur <ph name="VALUE" />.</translation>
<translation id="1712552549805331520"><ph name="URL" /> souhaite stocker des données de façon permanente sur votre ordinateur local</translation>
<translation id="1713628304598226412">Bac 2</translation>
-<translation id="1715874602234207">F</translation>
+<translation id="1715874602234207">V</translation>
<translation id="1717218214683051432">Capteurs de mouvement</translation>
<translation id="1717494416764505390">Boîte aux lettres 3</translation>
<translation id="1718029547804390981">Le document est trop volumineux pour être annoté</translation>
@@ -283,6 +298,7 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
le format de l'en-tête étant incorrect, le navigateur ne peut pas traiter
votre requête concernant <ph name="SITE" />. Les exploitants de sites peuvent utiliser
des règles d'origine pour en configurer la sécurité et d'autres propriétés.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />En savoir plus sur la navigation privée dans Chromium<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">Les onglets ouverts s'affichent ici</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -410,6 +426,7 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="22081806969704220">Bac 3</translation>
<translation id="2212735316055980242">Règle introuvable.</translation>
<translation id="2213606439339815911">Obtention des entrées en cours…</translation>
+<translation id="2213612003795704869">La page est imprimée</translation>
<translation id="2215727959747642672">Modification de fichier</translation>
<translation id="2218879909401188352">Les pirates informatiques qui contrôlent le site <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> peuvent installer des applications dangereuses qui endommagent votre appareil, ajoutent des frais cachés à votre facture de téléphonie mobile ou dérobent vos informations personnelles. <ph name="BEGIN_LEARN_MORE_LINK" />En savoir plus<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">Aucun accès à Internet</translation>
@@ -419,6 +436,7 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="2248949050832152960">Utiliser WebAuthn</translation>
<translation id="2250931979407627383">Agrafage par le bord gauche</translation>
<translation id="225207911366869382">Cette valeur n'est plus utilisée dans le cadre de cette règle.</translation>
+<translation id="2256115617011615191">Redémarrer maintenant</translation>
<translation id="2258928405015593961">Indiquez une date d'expiration située dans le futur et réessayez</translation>
<translation id="225943865679747347">Code d'erreur : <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">Erreur HTTP.</translation>
@@ -446,6 +464,7 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="2337852623177822836">Paramètre contrôlé par votre administrateur</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> tente de s'associer</translation>
<translation id="2346319942568447007">Image copiée</translation>
+<translation id="2350796302381711542">Autoriser <ph name="HANDLER_HOSTNAME" /> à ouvrir tous les liens <ph name="PROTOCOL" /> à la place de <ph name="REPLACED_HANDLER_TITLE" /> ?</translation>
<translation id="2354001756790975382">Autres favoris</translation>
<translation id="2354430244986887761">La navigation sécurisée de Google a récemment <ph name="BEGIN_LINK" />détecté des applications malveillantes<ph name="END_LINK" /> sur le site <ph name="SITE" />.</translation>
<translation id="2355395290879513365">Il se peut que des pirates informatiques puissent voir les images que vous regardez sur ce site et vous piègent en les modifiant.</translation>
@@ -471,13 +490,15 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="2413528052993050574">Impossible de vérifier sur le serveur qu'il s'agit bien du domaine <ph name="DOMAIN" />. Il se peut que son certificat de sécurité ait été révoqué. Cela peut être dû à une mauvaise configuration ou bien à l'interception de votre connexion par un pirate informatique.</translation>
<translation id="2414886740292270097">Sombre</translation>
<translation id="2430968933669123598">Gérer le compte Google, appuyez sur Entrée pour gérer vos infos, votre vie privée et votre sécurité dans votre compte Google</translation>
+<translation id="2436186046335138073">Autoriser <ph name="HANDLER_HOSTNAME" /> à ouvrir tous les liens <ph name="PROTOCOL" /> ?</translation>
<translation id="2438874542388153331">Quadruple perforation à droite</translation>
-<translation id="2450021089947420533">Explorations</translation>
+<translation id="2450021089947420533">Parcours</translation>
<translation id="2463739503403862330">Remplir</translation>
<translation id="2465402087343596252">Architecture-E</translation>
<translation id="2465655957518002998">Sélectionner un mode d'expédition</translation>
<translation id="2465688316154986572">Agrafer</translation>
<translation id="2465914000209955735">Gérez les fichiers que vous avez téléchargés dans Chrome</translation>
+<translation id="2466004615675155314">Afficher les informations du Web</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Exécuter les diagnostics du réseau<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">Ordre 1 à N</translation>
<translation id="2470767536994572628">Si vous modifiez des annotations, ce document s'affichera en mode "Vue par page", dans son orientation d'origine</translation>
@@ -498,6 +519,7 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="2523886232349826891">Enregistrée sur cet appareil uniquement</translation>
<translation id="2524461107774643265">Ajouter des informations</translation>
<translation id="2529899080962247600">Ce champ ne peut pas contenir plus de <ph name="MAX_ITEMS_LIMIT" /> entrées. Les entrées supplémentaires seront ignorées.</translation>
+<translation id="2535585790302968248">Ouvrez un nouvel onglet de navigation privée pour naviguer de manière anonyme</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{et 1 autre}one{et # autre}other{et # autres}}</translation>
<translation id="2536110899380797252">Ajouter une adresse</translation>
<translation id="2539524384386349900">Détecter</translation>
@@ -523,7 +545,14 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="2597378329261239068">Ce document est protégé par mot de passe. Veuillez saisir ce dernier.</translation>
<translation id="2609632851001447353">Variantes</translation>
<translation id="2610561535971892504">Cliquer pour copier</translation>
+<translation id="2617988307566202237">Les informations suivantes <ph name="BEGIN_EMPHASIS" />ne seront pas enregistrées<ph name="END_EMPHASIS" /> dans Chrome :
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Votre historique de navigation
+ <ph name="LIST_ITEM" />Les cookies et les données des sites
+ <ph name="LIST_ITEM" />Les informations saisies dans les formulaires
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (enveloppe)</translation>
+<translation id="2623663032199728144">Peut demander d'utiliser les infos au sujet de vos écrans</translation>
<translation id="2625385379895617796">Votre horloge est en avance.</translation>
<translation id="262745152991669301">Peut demander à se connecter à des appareils USB</translation>
<translation id="2629325967560697240">Pour bénéficier du niveau de sécurité le plus élevé de Chrome, <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />activez la protection renforcée<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -557,6 +586,7 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="2709516037105925701">Saisie automatique</translation>
<translation id="2713444072780614174">Blanc</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" /> : appuyer sur Tabulation, puis sur Entrée pour gérer vos paiements et informations sur vos cartes de crédit dans les paramètres Chrome</translation>
+<translation id="271663710482723385">Appuyez sur |<ph name="ACCELERATOR1" />|+|<ph name="ACCELERATOR2" />| pour quitter le mode plein écran</translation>
<translation id="2721148159707890343">Demande réussie.</translation>
<translation id="2723669454293168317">Effectuer un contrôle de sécurité dans les paramètres de Chrome</translation>
<translation id="2726001110728089263">Bac latéral</translation>
@@ -587,6 +617,7 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="2850739647070081192">Invite (enveloppe)</translation>
<translation id="2856444702002559011">Des individus malveillants tentent peut-être de subtiliser vos informations personnelles sur le site <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (mots de passe, messages ou numéros de carte de crédit, par exemple). <ph name="BEGIN_LEARN_MORE_LINK" />En savoir plus<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">Ce site affiche des annonces intrusives ou trompeuses.</translation>
+<translation id="286512204874376891">Une carte virtuelle masque votre carte réelle pour vous protéger des fraudes potentielles. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">Amical</translation>
<translation id="2876489322757410363">En payant via une appli externe, vous allez quitter le mode navigation privée. Voulez-vous continuer ?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />, puis Tabulation, puis Entrée pour gérer la navigation sécurisée, etc., dans les paramètres Chrome</translation>
@@ -611,6 +642,7 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="2930577230479659665">Couper après chaque copie</translation>
<translation id="2932085390869194046">Suggérer un mot de passe…</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019">Ouvrir les liens "<ph name="PROTOCOL" />"</translation>
<translation id="2941952326391522266">Impossible de vérifier sur le serveur qu'il s'agit bien du domaine <ph name="DOMAIN" />, car son certificat de sécurité provient du domaine <ph name="DOMAIN2" />. Cela peut être dû à une mauvaise configuration ou bien à l'interception de votre connexion par un pirate informatique.</translation>
<translation id="2943895734390379394">Heure de l'importation :</translation>
<translation id="2948083400971632585">Vous pouvez désactiver tout proxy configuré pour une connexion à partir de la page des paramètres.</translation>
@@ -643,6 +675,7 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="3037605927509011580">Aïe aïe aïe</translation>
<translation id="3041612393474885105">Informations relatives au certificat</translation>
<translation id="3044034790304486808">Reprendre votre recherche</translation>
+<translation id="305162504811187366">Historique du Bureau à distance Chrome, y compris les horodatages, les hôtes et les ID de sessions client</translation>
<translation id="3060227939791841287">C9 (enveloppe)</translation>
<translation id="3061707000357573562">Service d'application de correctifs</translation>
<translation id="306573536155379004">Le jeu a commencé.</translation>
@@ -683,6 +716,7 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="3197136577151645743">Peut demander à savoir quand vous utilisez activement cet appareil</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" /> : appuyez sur Tabulation, puis sur Entrée pour gérer les infos que vous synchronisez dans les paramètres Chrome</translation>
<translation id="320323717674993345">Annuler le paiement</translation>
+<translation id="3203366800380907218">Sur le Web</translation>
<translation id="3207960819495026254">Favori</translation>
<translation id="3209034400446768650">Cette page peut vous facturer de l'argent</translation>
<translation id="3212581601480735796">Votre activité sur <ph name="HOSTNAME" /> est surveillée</translation>
@@ -699,10 +733,12 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="3234666976984236645">Toujours détecter du contenu important sur ce site</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />, puis Tabulation, puis Entrée pour personnaliser l'apparence de votre navigateur</translation>
<translation id="3240791268468473923">La bottom sheet indiquant qu'aucun identifiant ne correspond pour le paiement sécurisé est ouverte</translation>
+<translation id="324180406144491771">Les liens de "<ph name="HOST_NAME" />" sont bloqués</translation>
<translation id="3249845759089040423">Tendance</translation>
<translation id="3252266817569339921">Français</translation>
<translation id="3257954757204451555">Qui est à l'origine de ces infos ?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />, appuyez sur Tabulation, puis sur Entrée pour créer rapidement un événement dans Google Agenda</translation>
+<translation id="3261488570342242926">En savoir plus sur les cartes virtuelles</translation>
<translation id="3264837738038045344">Bouton "Gérer les paramètres de Chrome", puis Entrée pour afficher vos paramètres Chrome</translation>
<translation id="3266793032086590337">Valeur (conflit)</translation>
<translation id="3268451620468152448">Onglets ouverts</translation>
@@ -716,6 +752,7 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="3288238092761586174"><ph name="URL" /> devra peut-être effectuer d'autres étapes pour valider votre paiement</translation>
<translation id="3293642807462928945">En savoir plus sur les règles <ph name="POLICY_NAME" />.</translation>
<translation id="3295444047715739395">Affichez et gérez vos mots de passe dans les paramètres Chrome</translation>
+<translation id="3303795387212510132">Autoriser l'appli à ouvrir des liens <ph name="PROTOCOL_SCHEME" /> ?</translation>
<translation id="3303855915957856445">Aucun résultat de recherche n'a été trouvé.</translation>
<translation id="3304073249511302126">Recherche Bluetooth</translation>
<translation id="3308006649705061278">Unité d'organisation (OU)</translation>
@@ -729,12 +766,6 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="3345782426586609320">Yeux</translation>
<translation id="3355823806454867987">Modifier les paramètres du proxy...</translation>
<translation id="3360103848165129075">Feuille du gestionnaire de paiement</translation>
-<translation id="3361596688432910856">Les informations suivantes <ph name="BEGIN_EMPHASIS" />ne seront pas enregistrées<ph name="END_EMPHASIS" /> dans Chrome :
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Votre historique de navigation
- <ph name="LIST_ITEM" />Les cookies et les données des sites
- <ph name="LIST_ITEM" />Les informations saisies dans les formulaires
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">Cette règle a été copiée automatiquement depuis la règle obsolète "<ph name="OLD_POLICY" />". Vous devez utiliser cette nouvelle règle à la place.</translation>
<translation id="3364869320075768271">Le site <ph name="URL" /> souhaite utiliser vos données et votre appareil de réalité virtuelle</translation>
<translation id="3366477098757335611">Afficher les cartes</translation>
@@ -817,7 +848,6 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="3587738293690942763">Milieu</translation>
<translation id="3592413004129370115">Italian (enveloppe)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{Vous pouvez réinitialiser votre groupe à tout moment. Comptez environ une journée pour rejoindre un nouveau groupe.}=1{Vous pouvez réinitialiser votre groupe à tout moment. Comptez environ une journée pour rejoindre un nouveau groupe.}one{Vous pouvez réinitialiser votre groupe à tout moment. Comptez {NUM_DAYS} jour pour rejoindre un nouveau groupe.}other{Vous pouvez réinitialiser votre groupe à tout moment. Comptez {NUM_DAYS} jours pour rejoindre un nouveau groupe.}}</translation>
-<translation id="3596012367874587041">Paramètres de l'appli</translation>
<translation id="3600246354004376029">"<ph name="TITLE" />", <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">Application bloquée par votre administrateur</translation>
<translation id="3608932978122581043">Orientation de l'alimentation</translation>
@@ -857,9 +887,10 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="3705189812819839667"><ph name="RESULT_OWNER" /> - <ph name="RESULT_PRODUCT_SOURCE" /></translation>
<translation id="370665806235115550">Chargement en cours...</translation>
<translation id="3709599264800900598">Texte copié</translation>
-<translation id="370972442370243704">Activer "Explorations"</translation>
+<translation id="370972442370243704">Activer "Parcours"</translation>
<translation id="3711895659073496551">Arrêter</translation>
<translation id="3712624925041724820">Licences épuisées.</translation>
+<translation id="3714633008798122362">Agenda sur le Web</translation>
<translation id="3714780639079136834">Activez les données mobiles ou le réseau Wi-Fi.</translation>
<translation id="3715597595485130451">Connexion au réseau Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Vérifier les configurations du proxy, du pare-feu et du DNS<ph name="END_LINK" /></translation>
@@ -921,6 +952,7 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="3906954721959377182">Tablette</translation>
<translation id="3909477809443608991"><ph name="URL" /> souhaite lire un contenu protégé. L'identité de votre appareil sera validée par Google et peut être accessible à ce site.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">Refuser</translation>
<translation id="3939773374150895049">Utiliser WebAuthn au lieu du code CVC ?</translation>
<translation id="3946209740501886391">Toujours demander sur ce site</translation>
<translation id="3947595700203588284">Peut demander à se connecter à des appareils MIDI</translation>
@@ -942,6 +974,7 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="3990250421422698716">Décalage</translation>
<translation id="3996311196211510766">Le site <ph name="ORIGIN" /> a exigé qu'une règle d'origine
soit appliquée à toutes les requêtes qu'il reçoit. Or, cette règle n'est pas applicable actuellement.</translation>
+<translation id="4009243425692662128">Le contenu des pages que vous imprimez est envoyé à Google Cloud ou à des tiers pour être analysé, par exemple pour vérifier qu'il ne contient pas de données sensibles.</translation>
<translation id="4010758435855888356">Autoriser l'accès à l'espace de stockage ?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{Document PDF contenant {COUNT} page}one{Document PDF contenant {COUNT} page}other{Document PDF contenant {COUNT} pages}}</translation>
<translation id="4023431997072828269">Comme ce formulaire est envoyé via une connexion non sécurisée, vos informations seront visibles par les autres utilisateurs.</translation>
@@ -1036,6 +1069,7 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="4250680216510889253">Non</translation>
<translation id="4253168017788158739">Remarque</translation>
<translation id="425582637250725228">Les modifications que vous avez apportées ne seront peut-être pas enregistrées.</translation>
+<translation id="425869179292622354">Renforcer la sécurité avec une carte virtuelle ?</translation>
<translation id="4258748452823770588">Signature incorrecte.</translation>
<translation id="4261046003697461417">Impossible d'ajouter des annotations aux documents protégés</translation>
<translation id="4265872034478892965">Autorisé par votre administrateur</translation>
@@ -1098,6 +1132,7 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="4434045419905280838">Pop-up et redirections</translation>
<translation id="4435702339979719576">Carte postale)</translation>
<translation id="443673843213245140">L'utilisation d'un proxy est désactivée, mais une configuration de proxy explicite est spécifiée.</translation>
+<translation id="4441832193888514600">Règle ignorée, car elle ne peut être définie que comme règle relative aux utilisateurs du cloud.</translation>
<translation id="4450893287417543264">Ne plus afficher</translation>
<translation id="4451135742916150903">Peut demander à se connecter à des périphériques HID</translation>
<translation id="4452328064229197696">Le mot de passe que vous venez d'utiliser a été détecté lors d'une violation de données. Pour sécuriser vos comptes, le Gestionnaire de mots de passe Google vous recommande de vérifier vos mots de passe enregistrés.</translation>
@@ -1121,7 +1156,7 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="4508814173490746936">Impossible d'utiliser Touch ID</translation>
<translation id="4509074745930862522"><ph name="TRANSLATE_FOCUSED_FRIENDLY_MATCH_TEXT" /> : appuyer sur Tabulation, puis sur Entrée pour traduire cette page avec Google Traduction</translation>
<translation id="4510487217173779431">Chou4 (enveloppe)</translation>
-<translation id="4514308731478712184">Désactiver "Explorations"</translation>
+<translation id="4514308731478712184">Désactiver "Parcours"</translation>
<translation id="4515275063822566619">Les cartes et les adresses proviennent de Chrome et de votre compte Google (<ph name="ACCOUNT_EMAIL" />). Vous pouvez les gérer dans les <ph name="BEGIN_LINK" />paramètres<ph name="END_LINK" />.</translation>
<translation id="4517607026994743406">Comm-10 (enveloppe)</translation>
<translation id="4521157617044179198"><ph name="WIDTH" /> × <ph name="HEIGHT" /> mm (<ph name="ORIENTATION" />)</translation>
@@ -1153,6 +1188,7 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="4628948037717959914">Photo</translation>
<translation id="4631649115723685955">Avec cashback</translation>
<translation id="4636930964841734540">Infos</translation>
+<translation id="4638670630777875591">Navigation privée dans Chromium</translation>
<translation id="464342062220857295">Rechercher des fonctionnalités</translation>
<translation id="4644670975240021822">Ordre inverse, face vers le bas</translation>
<translation id="4646534391647090355">Accéder</translation>
@@ -1173,6 +1209,7 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="4708268264240856090">Votre connexion a été interrompue</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Exécutez les diagnostics réseau de Windows<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426">Mot de passe associé à <ph name="USERNAME" /></translation>
<translation id="4724144314178270921">Peut demander à voir le texte et les images du presse-papiers</translation>
<translation id="4726672564094551039">Actualiser les règles</translation>
<translation id="4728558894243024398">Plate-forme</translation>
@@ -1194,6 +1231,7 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="4757993714154412917">Vous venez de saisir votre mot de passe sur un site trompeur. Pour sécuriser vos comptes, Chromium vous recommande de vérifier vos mots de passe enregistrés.</translation>
<translation id="4758311279753947758">Ajouter des coordonnées</translation>
<translation id="4761104368405085019">Utiliser votre micro</translation>
+<translation id="4761869838909035636">Effectuer un contrôle de sécurité de Chrome</translation>
<translation id="4764776831041365478">Il se peut que la page Web à l'adresse <ph name="URL" /> soit temporairement inaccessible ou qu'elle ait été déplacée de façon permanente à une autre adresse Web.</translation>
<translation id="4766713847338118463">Double agrafe en bas</translation>
<translation id="4771973620359291008">Une erreur inconnue s'est produite.</translation>
@@ -1214,12 +1252,6 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="4819347708020428563">Modifier les annotations dans la vue par défaut ?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />, appuyez sur Tabulation, puis sur Entrée pour créer rapidement une feuille de calcul Google Sheets</translation>
<translation id="4825507807291741242">Puissant</translation>
-<translation id="4827402517081186284">La navigation privée ne vous rend pas invisible sur Internet :
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Les sites savent que vous les consultez.<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Votre employeur ou votre établissement scolaire peuvent connaître votre activité de navigation.<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Les fournisseurs d'accès à Internet peuvent surveiller le trafic Web.<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">Activer les avertissements</translation>
<translation id="4838327282952368871">Rêveur</translation>
<translation id="4840250757394056958">Afficher votre historique Chrome</translation>
@@ -1231,12 +1263,12 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="4854362297993841467">Mode de livraison non disponible. Choisissez-en un autre.</translation>
<translation id="4854853140771946034">Créer rapidement une note dans Google Keep</translation>
<translation id="485902285759009870">Validation du code…</translation>
+<translation id="4866506163384898554">Appuyez sur |<ph name="ACCELERATOR1" />|+|<ph name="ACCELERATOR2" />| pour afficher le curseur</translation>
<translation id="4876188919622883022">Vue simplifiée</translation>
<translation id="4876305945144899064">Aucun nom d'utilisateur</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{Aucun}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}one{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831">Recherche sur "<ph name="TEXT" />"</translation>
<translation id="4879491255372875719">Automatique (par défaut)</translation>
-<translation id="4879725228911483934">Ouvrir et positionner des fenêtres sur vos écrans</translation>
<translation id="4880827082731008257">Rechercher dans l'historique</translation>
<translation id="4881695831933465202">Ouvrir</translation>
<translation id="4885256590493466218">Vous paierez avec "<ph name="CARD_DETAIL" />".</translation>
@@ -1245,6 +1277,7 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">9e rouleau</translation>
<translation id="4901778704868714008">Enregistrer…</translation>
+<translation id="4905659621780993806">L'administrateur redémarrera votre appareil automatiquement le <ph name="DATE" /> à <ph name="TIME" />. Enregistrez tous les éléments ouverts avant que votre appareil ne redémarre.</translation>
<translation id="4913987521957242411">Perforation en haut à gauche</translation>
<translation id="4918221908152712722">Installer <ph name="APP_NAME" /> (aucun téléchargement requis)</translation>
<translation id="4923459931733593730">Paiement</translation>
@@ -1253,6 +1286,7 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, appuyez sur Tabulation, puis Entrée pour lancer une recherche</translation>
<translation id="4930153903256238152">Grande capacité</translation>
+<translation id="4940163644868678279">Navigation privée dans Chrome</translation>
<translation id="4943872375798546930">Aucun résultat</translation>
<translation id="4950898438188848926">Bouton pour changer d'onglet (appuyez sur Entrée pour passer à l'onglet ouvert, <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" />)</translation>
<translation id="495170559598752135">Actions</translation>
@@ -1262,6 +1296,7 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="4968522289500246572">Cette appli est conçue pour les mobiles et ne sera peut-être pas bien redimensionnée. Elle pourrait rencontrer des problèmes ou redémarrer.</translation>
<translation id="4969341057194253438">Supprimer l'enregistrement</translation>
<translation id="4973922308112707173">Double perforation en haut</translation>
+<translation id="4976702386844183910">Dernière visite : <ph name="DATE" /></translation>
<translation id="4984088539114770594">Utiliser le micro ?</translation>
<translation id="4984339528288761049">Prc5 (enveloppe)</translation>
<translation id="4989163558385430922">Tout afficher</translation>
@@ -1323,6 +1358,7 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="5138227688689900538">Afficher moins</translation>
<translation id="5145883236150621069">Code d'erreur présent dans la réponse de la règle.</translation>
<translation id="5146995429444047494">Les notifications sont bloquées pour <ph name="ORIGIN" /></translation>
+<translation id="514704532284964975"><ph name="URL" /> souhaite consulter et modifier des informations sur les appareils NFC que vous touchez avec votre téléphone</translation>
<translation id="5148809049217731050">Vers le haut</translation>
<translation id="515292512908731282">C4 (enveloppe)</translation>
<translation id="5158275234811857234">Couverture</translation>
@@ -1347,6 +1383,7 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="5215116848420601511">Modes de paiement et adresses utilisés dans Google Pay</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">Bac 13</translation>
+<translation id="5216942107514965959">Dernière visite : aujourd'hui</translation>
<translation id="5222812217790122047">Veuillez saisir une adresse e-mail</translation>
<translation id="5230733896359313003">Adresse de livraison</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1367,7 +1404,6 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">Propriétés du document</translation>
<translation id="528468243742722775">Fin</translation>
-<translation id="5284909709419567258">Adresses réseau</translation>
<translation id="5285570108065881030">Afficher tous les mots de passe enregistrés</translation>
<translation id="5287240709317226393">Afficher les cookies</translation>
<translation id="5287456746628258573">La configuration de sécurité obsolète de ce site peut exposer vos informations, comme vos mots de passe ou vos numéros de carte de crédit, lorsqu'elles lui sont transmises.</translation>
@@ -1451,6 +1487,7 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="5556459405103347317">Actualiser</translation>
<translation id="5560088892362098740">Date d'expiration</translation>
<translation id="55635442646131152">Plan du document</translation>
+<translation id="5565613213060953222">Ouvrir un onglet de navigation privée</translation>
<translation id="5565735124758917034">Actif</translation>
<translation id="5570825185877910964">Protéger le compte</translation>
<translation id="5571083550517324815">Enlèvement impossible à cette adresse. Sélectionnez-en une autre.</translation>
@@ -1491,7 +1528,7 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="5695542892312572833">Utiliser Windows Hello pour valider et finaliser votre achat ?</translation>
<translation id="5701381305118179107">Centrer</translation>
<translation id="570530837424789914">Gérer…</translation>
-<translation id="5707154300732650394">Reprendre votre exploration</translation>
+<translation id="5707154300732650394">Reprendre votre parcours</translation>
<translation id="57094364128775171">Suggérer un mot de passe sécurisé…</translation>
<translation id="571403275720188526">(arm64)</translation>
<translation id="5720705177508910913">Utilisateur actuel</translation>
@@ -1533,6 +1570,7 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="5869522115854928033">Mots de passe enregistrés</translation>
<translation id="5873013647450402046">Vous devez confirmer votre identité auprès de votre banque.</translation>
<translation id="5887400589839399685">Carte enregistrée</translation>
+<translation id="5887687176710214216">Dernière visite : hier</translation>
<translation id="5895138241574237353">Redémarrer</translation>
<translation id="5895187275912066135">Émis le</translation>
<translation id="5901630391730855834">Jaune</translation>
@@ -1546,6 +1584,7 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="5921639886840618607">Enregistrer la carte dans votre compte Google ?</translation>
<translation id="5922853866070715753">Vous avez presque terminé !</translation>
<translation id="5932224571077948991">Le site affiche des annonces intrusives ou trompeuses</translation>
+<translation id="5938153366081463283">Ajouter une carte virtuelle</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347">Ouverture du site <ph name="SITE_NAME" />…</translation>
<translation id="5951495562196540101">Impossible d'enregistrer votre appareil avec un compte personnel (licence associée disponible).</translation>
@@ -1610,6 +1649,7 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="6120179357481664955">Souhaitez-vous mémoriser votre ID UPI ?</translation>
<translation id="6124432979022149706">Connecteurs Chrome Enterprise</translation>
<translation id="6127379762771434464">Élément supprimé</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />En savoir plus sur la navigation privée dans Chrome<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">Vérifiez les câbles et redémarrez votre routeur, votre modem
ou tout autre périphérique réseau utilisé.</translation>
<translation id="614940544461990577">Voici quelques conseils :</translation>
@@ -1622,7 +1662,6 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="6169916984152623906">Vous pouvez désormais naviguer de façon privée. Les autres utilisateurs de cet appareil ne verront pas votre activité. Les téléchargements et les favoris seront cependant enregistrés.</translation>
<translation id="6177128806592000436">Votre connexion à ce site n'est pas sécurisée</translation>
<translation id="6180316780098470077">Intervalle entre les tentatives</translation>
-<translation id="619448280891863779">Peut demander à ouvrir et placer des fenêtres sur vos écrans</translation>
<translation id="6196640612572343990">Bloquer les cookies tiers</translation>
<translation id="6203231073485539293">Vérifiez votre connexion Internet</translation>
<translation id="6218753634732582820">Supprimer l'adresse de Chromium ?</translation>
@@ -1641,11 +1680,11 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="6264485186158353794">Revenir en lieu sûr</translation>
<translation id="6265794661083428563">Copier la valeur de la règle <ph name="POLICY_NAME" /></translation>
<translation id="6266934640124581640">Turquoise clair</translation>
-<translation id="6272088941196661550">Reprenez votre exploration pour voir les activités pertinentes dans votre historique Chrome</translation>
+<translation id="6272088941196661550">Reprenez votre parcours pour voir les activités pertinentes dans votre historique Chrome</translation>
<translation id="6272383483618007430">Google Update</translation>
<translation id="6276112860590028508">Les pages de votre liste de lecture s'affichent ici</translation>
<translation id="627746635834430766">Pour régler vos achats plus rapidement la prochaine fois, enregistrez votre carte et votre adresse de facturation dans votre compte Google.</translation>
-<translation id="6279098320682980337">Le numéro de carte virtuelle n'est pas renseigné ? Cliquez sur les informations relatives à la carte pour les copier</translation>
+<translation id="6279183038361895380">Appuyez sur |<ph name="ACCELERATOR" />| pour afficher le curseur.</translation>
<translation id="6280223929691119688">Impossible de livrer à cette adresse. Sélectionnez-en une autre.</translation>
<translation id="6282194474023008486">Code postal</translation>
<translation id="6285507000506177184">Bouton "Gérer les téléchargements dans Chrome", puis Entrée pour gérer les fichiers que vous avez téléchargés dans Chrome</translation>
@@ -1653,6 +1692,7 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="6290238015253830360">Vos suggestions d'articles s'affichent ici</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">Cryptogramme :</translation>
+<translation id="6300452962057769623">{0,plural, =0{Votre appareil va redémarrer maintenant}=1{Votre appareil va redémarrer dans 1 seconde}one{Votre appareil va redémarrer dans # seconde}other{Votre appareil va redémarrer dans # secondes}}</translation>
<translation id="6302269476990306341">Arrêt de l'Assistant Google dans Chrome</translation>
<translation id="6305205051461490394"><ph name="URL" /> est inaccessible.</translation>
<translation id="6312113039770857350">Page Web non disponible</translation>
@@ -1726,6 +1766,7 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="6529602333819889595">&amp;Rétablir la suppression</translation>
<translation id="6545864417968258051">Recherche Bluetooth</translation>
<translation id="6547208576736763147">Double perforation à gauche</translation>
+<translation id="6554732001434021288">Dernière visite : il y a <ph name="NUM_DAYS" /> jours</translation>
<translation id="6556866813142980365">Rétablir</translation>
<translation id="6569060085658103619">Vous consultez actuellement une page d'extension</translation>
<translation id="6573200754375280815">Double perforation à droite</translation>
@@ -1786,7 +1827,6 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="6757797048963528358">Votre appareil s'est mis en veille.</translation>
<translation id="6767985426384634228">Modifier l'adresse ?</translation>
<translation id="6768213884286397650">Hagaki (carte postale)</translation>
-<translation id="6774185088257932239"><ph name="BEGIN_LINK" />En savoir plus<ph name="END_LINK" /> sur la navigation privée</translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">Mauve</translation>
<translation id="6786747875388722282">Extensions</translation>
@@ -1870,7 +1910,6 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="706295145388601875">Gérez les adresses et ajoutez-en dans les paramètres Chrome</translation>
<translation id="7064851114919012435">Coordonnées</translation>
<translation id="7068733155164172741">Saisissez le code à <ph name="OTP_LENGTH" /> chiffres</translation>
-<translation id="7070090581017165256">À propos de ce site</translation>
<translation id="70705239631109039">Votre connexion n'est pas totalement sécurisée</translation>
<translation id="7075452647191940183">Requête trop volumineuse</translation>
<translation id="7079718277001814089">Ce site contient des logiciels malveillants</translation>
@@ -1887,6 +1926,12 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="7111012039238467737">(Valide)</translation>
<translation id="7118618213916969306">Rechercher l'URL du presse-papier, <ph name="SHORT_URL" /></translation>
<translation id="7119414471315195487">Fermez les autres onglets ou programmes</translation>
+<translation id="7129355289156517987">Lorsque vous fermez tous les onglets de navigation privée de Chromium, les activités effectuées dans ces onglets sont effacées de cet appareil :
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Activité de navigation<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Historique des recherches<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Informations saisies dans les formulaires<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">Impossible d'expédier à cette adresse. Sélectionnez-en une autre.</translation>
<translation id="7132939140423847331">Votre administrateur a interdit la copie de ces données.</translation>
<translation id="7135130955892390533">Afficher l'état</translation>
@@ -1909,6 +1954,7 @@ Par défaut, ce type d'accès est bloqué par vos paramètres de confidentialitÃ
<translation id="7192203810768312527">Libère <ph name="SIZE" />. Il se peut que certains sites se chargent moins vite à votre prochaine visite.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">Votre administrateur peut consulter les éléments suivants :</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" /> : appuyer sur Tabulation, puis sur Entrée pour ouvrir un nouvel onglet de navigation privée</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> ne respecte pas les normes de sécurité.</translation>
<translation id="7210993021468939304">Activité Linux dans le conteneur, et peut installer et exécuter des applications Linux dans le conteneur</translation>
@@ -1941,6 +1987,7 @@ Informations supplémentaires :
<translation id="7304562222803846232">Gérer les paramètres de confidentialité du compte Google</translation>
<translation id="7305756307268530424">Vitesse plus lente</translation>
<translation id="7308436126008021607">synchronisation en arrière-plan</translation>
+<translation id="7310392214323165548">Redémarrage imminent</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">Aide à la connexion</translation>
<translation id="7323804146520582233">Masquer la section "<ph name="SECTION" />"</translation>
@@ -1948,6 +1995,7 @@ Informations supplémentaires :
<translation id="7334320624316649418">&amp;Rétablir la réorganisation</translation>
<translation id="7335157162773372339">Peut demander à utiliser votre appareil photo</translation>
<translation id="7337248890521463931">Afficher plus de lignes</translation>
+<translation id="7337418456231055214">Le numéro de carte virtuelle n'est pas renseigné ? Cliquez sur les informations de la carte pour les copier. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">Non disponible sur votre plate-forme</translation>
<translation id="733923710415886693">Le certificat du serveur n'a pas été communiqué tel que le prévoient les règles de transparence des certificats.</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1970,6 +2018,7 @@ Informations supplémentaires :
<translation id="7378627244592794276">Non</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">Non applicable</translation>
+<translation id="7388594495505979117">{0,plural, =1{Votre appareil va redémarrer dans 1 minute}one{Votre appareil va redémarrer dans # minute}other{Votre appareil va redémarrer dans # minutes}}</translation>
<translation id="7390545607259442187">Valider la carte</translation>
<translation id="7392089738299859607">Modifier l'adresse</translation>
<translation id="7399802613464275309">Contrôle de sécurité</translation>
@@ -2006,6 +2055,12 @@ Informations supplémentaires :
<translation id="7485870689360869515">Aucune donnée n'a été trouvée.</translation>
<translation id="7495528107193238112">Ce contenu est bloqué. Pour résoudre le problème, contactez le propriétaire du site.</translation>
<translation id="7497998058912824456">Bouton "Créer un document", appuyez sur Entrée pour créer rapidement un document Google Docs</translation>
+<translation id="7506488012654002225">Les informations suivantes <ph name="BEGIN_EMPHASIS" />ne seront pas enregistrées<ph name="END_EMPHASIS" /> dans Chromium :
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Votre historique de navigation
+ <ph name="LIST_ITEM" />Les cookies et les données des sites
+ <ph name="LIST_ITEM" />Les informations saisies dans les formulaires
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">L'ID d'appareil de la règle renvoyé est vide ou ne correspond pas à l'ID d'appareil actuel.</translation>
<translation id="7508870219247277067">Vert avocat</translation>
<translation id="7511955381719512146">Pour utiliser ce réseau Wi-Fi, il est possible que vous deviez vous rendre sur la page <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
@@ -2119,7 +2174,6 @@ Informations supplémentaires :
<translation id="7813600968533626083">Supprimer la suggestion de saisie de formulaire de Chrome ?</translation>
<translation id="781440967107097262">Partager le presse-papiers ?</translation>
<translation id="7815407501681723534"><ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> trouvé(s) pour "<ph name="SEARCH_STRING" />"</translation>
-<translation id="782125616001965242">Afficher des informations sur ce site</translation>
<translation id="782886543891417279">Pour utiliser ce réseau Wi-Fi (<ph name="WIFI_NAME" />), il est possible que vous deviez vous rendre sur la page de connexion correspondante.</translation>
<translation id="7836231406687464395">Postfix (enveloppe)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{Aucune}=1{1 application (<ph name="EXAMPLE_APP_1" />)}=2{2 applications (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}one{# application (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}other{# applications (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}}</translation>
@@ -2136,7 +2190,6 @@ Informations supplémentaires :
<translation id="7888575728750733395">Intent de rendu d'impression</translation>
<translation id="7894280532028510793">S'il n'y a pas d'erreur, essayez de <ph name="BEGIN_LINK" />faire un diagnostic réseau<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (enveloppe)</translation>
-<translation id="7931318309563332511">Langue source inconnue</translation>
<translation id="793209273132572360">Modifier l'adresse ?</translation>
<translation id="7932579305932748336">Revêtement</translation>
<translation id="79338296614623784">Saisissez un numéro de téléphone valide</translation>
@@ -2161,13 +2214,14 @@ Informations supplémentaires :
<translation id="7976214039405368314">Trop de demandes</translation>
<translation id="7977538094055660992">Périphérique de sortie</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">Associée à</translation>
<translation id="798134797138789862">Peut demander à utiliser des données et des appareils de réalité virtuelle</translation>
<translation id="7984945080620862648">Vous ne pouvez pas consulter le site <ph name="SITE" /> pour le moment, car il a envoyé des identifiants brouillés qui ne peuvent être traités par Chrome. Les erreurs réseau et les attaques sont généralement temporaires. Vous devriez donc pouvoir accéder à cette page ultérieurement.</translation>
-<translation id="79859296434321399">Pour afficher des contenus en réalité augmentée, installez ARCore</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">Reliure</translation>
<translation id="7992044431894087211">Le partage d'écran avec <ph name="APPLICATION_TITLE" /> a repris</translation>
<translation id="7995512525968007366">Non spécifié</translation>
+<translation id="7998269595945679889">Bouton "Ouvrir un onglet de navigation privée" : appuyer sur Entrée pour ouvrir un nouvel onglet de navigation privée</translation>
<translation id="800218591365569300">Essayez de fermer les autres onglets ou programmes pour libérer de la mémoire.</translation>
<translation id="8004582292198964060">Navigateur</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{Cette carte et l'adresse de facturation associée seront enregistrées. Vous pourrez vous en servir lorsque vous serez connecté à <ph name="USER_EMAIL" />.}one{Cette carte et l'adresse de facturation associée seront enregistrées. Vous pourrez vous en servir lorsque vous serez connecté à <ph name="USER_EMAIL" />.}other{Ces cartes et les adresses de facturation associées seront enregistrées. Vous pourrez vous en servir lorsque vous serez connecté à <ph name="USER_EMAIL" />.}}</translation>
@@ -2227,6 +2281,7 @@ Informations supplémentaires :
<translation id="8202370299023114387">Conflit</translation>
<translation id="8206978196348664717">Prc4 (enveloppe)</translation>
<translation id="8211406090763984747">La connexion est sécurisée</translation>
+<translation id="8217240300496046857">Les sites ne peuvent pas utiliser de cookies pour suivre votre activité sur le Web. Les fonctionnalités de certains sites peuvent être bloquées.</translation>
<translation id="8218327578424803826">Position attribuée : </translation>
<translation id="8220146938470311105">C7/C6 (enveloppe)</translation>
<translation id="8225771182978767009">La personne qui a configuré cet ordinateur a choisi de bloquer ce site.</translation>
@@ -2267,14 +2322,9 @@ Informations supplémentaires :
<translation id="830498451218851433">Plier en deux</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">Applications installées et leur fréquence d'utilisation</translation>
+<translation id="8317207217658302555">Mettre à jour ARCore ?</translation>
<translation id="831997045666694187">Soirée</translation>
<translation id="8321476692217554900">notifications</translation>
-<translation id="8328484624016508118">Lorsque vous fermez tous les onglets de navigation privée, Chrome efface :
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />votre activité de navigation sur cet appareil ;<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />l'historique de vos recherches sur cet appareil ;<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />les informations saisies dans des formulaires.<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489">L'accès à <ph name="HOST_NAME" /> a été refusé</translation>
<translation id="833262891116910667">Mettre en surbrillance</translation>
<translation id="8339163506404995330">Les pages en <ph name="LANGUAGE" /> ne seront pas traduites</translation>
@@ -2326,6 +2376,7 @@ Informations supplémentaires :
<translation id="8507227106804027148">Ligne de commande</translation>
<translation id="8508648098325802031">Icône Recherche</translation>
<translation id="8511402995811232419">Gérer les cookies</translation>
+<translation id="8519753333133776369">Appareil HID autorisé par votre administrateur</translation>
<translation id="8522552481199248698">Chrome peut vous aider à protéger votre compte Google et à modifier votre mot de passe.</translation>
<translation id="8530813470445476232">Effacez votre historique de navigation, supprimez les cookies, videz le cache, et plus encore dans les paramètres Chrome</translation>
<translation id="8533619373899488139">Pour consulter la liste des URL bloquées et des autres règles définies par votre administrateur système, rendez-vous sur &lt;strong&gt;chrome://policy&lt;/strong&gt;.</translation>
@@ -2337,7 +2388,6 @@ Informations supplémentaires :
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{Réinitialiser l'autorisation}one{Réinitialiser l'autorisation}other{Réinitialiser les autorisations}}</translation>
<translation id="8555010941760982128">Utilisez ce code au moment de payer</translation>
<translation id="8557066899867184262">Le code CVC figure au recto de votre carte.</translation>
-<translation id="8558485628462305855">Pour afficher des contenus en réalité augmentée, mettez à jour ARCore</translation>
<translation id="8559762987265718583">Impossible d'établir une connexion privée à <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> : la date et l'heure de votre appareil (<ph name="DATE_AND_TIME" />) sont incorrectes.</translation>
<translation id="8564182942834072828">Documents séparés/Copies non assemblées</translation>
<translation id="8564985650692024650">L'équipe Chromium vous recommande de réinitialiser votre mot de passe <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> si vous l'avez réutilisé sur d'autres sites.</translation>
@@ -2356,6 +2406,7 @@ Informations supplémentaires :
<translation id="865032292777205197">capteurs de mouvement</translation>
<translation id="8663226718884576429">Récapitulatif de la commande, <ph name="TOTAL_LABEL" />, détails supplémentaires</translation>
<translation id="8666678546361132282">Anglais</translation>
+<translation id="8669306706049782872">Utiliser les infos au sujet de vos écrans pour ouvrir et placer des fenêtres</translation>
<translation id="867224526087042813">Signature</translation>
<translation id="8676424191133491403">Sans délai</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, réponse, <ph name="ANSWER" /></translation>
@@ -2382,6 +2433,7 @@ Informations supplémentaires :
<translation id="8731544501227493793">Bouton "Gérer les mots de passe" : appuyer sur Entrée pour consulter et gérer vos mots de passe dans les paramètres Chrome</translation>
<translation id="8734529307927223492">Votre <ph name="DEVICE_TYPE" /> est géré par <ph name="MANAGER" /></translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" /> : appuyer sur Tabulation, puis sur Entrée pour ouvrir une nouvelle fenêtre de navigation privée</translation>
+<translation id="8737685506611670901">Ouvrir les liens "<ph name="PROTOCOL" />" à la place de "<ph name="REPLACED_HANDLER_TITLE" />"</translation>
<translation id="8738058698779197622">Afin d'établir une connexion sécurisée, votre horloge doit être réglée correctement. Les certificats permettant aux sites Web de s'identifier sont en effet valides pendant une période précise. Si l'horloge de votre appareil est incorrecte, Chromium n'est pas en mesure de vérifier la validité des certificats.</translation>
<translation id="8740359287975076522">L'&lt;abbr id="dnsDefinition"&gt;adresse DNS&lt;/abbr&gt; de <ph name="HOST_NAME" /> est introuvable. Identification du problème…</translation>
<translation id="8742371904523228557">Votre code pour <ph name="ORIGIN" /> est <ph name="ONE_TIME_CODE" /></translation>
@@ -2409,6 +2461,7 @@ Informations supplémentaires :
<translation id="883848425547221593">Autres favoris</translation>
<translation id="884264119367021077">Adresse de livraison</translation>
<translation id="884923133447025588">Aucun système de révocation trouvé</translation>
+<translation id="8849262850971482943">Pour plus de sécurité, utilisez votre carte virtuelle</translation>
<translation id="885730110891505394">Partage avec Google</translation>
<translation id="8858065207712248076">L'équipe Chrome vous recommande de réinitialiser votre mot de passe <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> si vous l'avez réutilisé sur d'autres sites.</translation>
<translation id="885906927438988819">S'il n'y a pas d'erreur, essayez de <ph name="BEGIN_LINK" />faire un diagnostic réseau Windows<ph name="END_LINK" />.</translation>
@@ -2458,6 +2511,7 @@ Informations supplémentaires :
<translation id="9004367719664099443">Session RV en cours</translation>
<translation id="9005998258318286617">Échec de chargement du document PDF.</translation>
<translation id="9008201768610948239">Ignorer</translation>
+<translation id="901834265349196618">e-mail</translation>
<translation id="9020200922353704812">Adresse de facturation de la carte obligatoire</translation>
<translation id="9020542370529661692">Cette page a été traduite en <ph name="TARGET_LANGUAGE" />.</translation>
<translation id="9020742383383852663">A8</translation>
@@ -2493,7 +2547,7 @@ Informations supplémentaires :
<translation id="9114524666733003316">Validation de la carte…</translation>
<translation id="9114581008513152754">Ce navigateur n'est géré par aucune entreprise ni aucune autre organisation. Il se peut que l'activité sur cet appareil soit gérée en dehors de Chrome. <ph name="BEGIN_LINK" />En savoir plus<ph name="END_LINK" /></translation>
<translation id="9117930699067497412">Frais</translation>
-<translation id="9118692854637641831"><ph name="HISTORY_CLUSTERS_SEARCH_FOCUSED_FRIENDLY_MATCH_TEXT" />, appuyez sur la touche Tabulation, puis sur Entrée pour reprendre vos recherches et voir les activités pertinentes dans votre historique Chrome</translation>
+<translation id="9118692854637641831"><ph name="HISTORY_CLUSTERS_SEARCH_FOCUSED_FRIENDLY_MATCH_TEXT" />, appuyez sur Tabulation, puis sur Entrée pour reprendre votre parcours et voir les activités pertinentes dans votre historique Chrome</translation>
<translation id="9119042192571987207">Importation terminée</translation>
<translation id="9128016270925453879">Les règles sont chargées</translation>
<translation id="9128870381267983090">Connectez-vous au réseau</translation>
@@ -2506,6 +2560,7 @@ Informations supplémentaires :
<translation id="9150045010208374699">Utiliser votre caméra</translation>
<translation id="9150685862434908345">Votre administrateur peut modifier sa configuration à distance. Il se peut que l'activité sur cet appareil soit gérée en dehors de Chrome. <ph name="BEGIN_LINK" />En savoir plus<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">Mis à jour</translation>
+<translation id="9155211586651734179">Périphériques audio connectés</translation>
<translation id="9157595877708044936">Configuration en cours...</translation>
<translation id="9158625974267017556">C6 (enveloppe)</translation>
<translation id="9164029392738894042">Vérification de la précision</translation>
diff --git a/chromium/components/strings/components_strings_gl.xtb b/chromium/components/strings/components_strings_gl.xtb
index fd9a39251e3..73110ab4321 100644
--- a/chromium/components/strings/components_strings_gl.xtb
+++ b/chromium/components/strings/components_strings_gl.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">Ver detalles</translation>
<translation id="1030706264415084469">O URL <ph name="URL" /> quere almacenar un gran volume de datos de forma permanente no teu dispositivo</translation>
<translation id="1032854598605920125">Xirar á dereita</translation>
+<translation id="1033329911862281889">O modo de incógnito non te fai invisible en liña:
+<ph name="BEGIN_LIST" />
+<ph name="LIST_ITEM" />Os sitios e os servizos que usan poden consultar as visitas<ph name="END_LIST_ITEM" />
+<ph name="LIST_ITEM" />As empresas ou centros educativos poden facer un seguimento da actividade de navegación<ph name="END_LIST_ITEM" />
+<ph name="LIST_ITEM" />Os fornecedores de servizos de Internet poden supervisar o tráfico web<ph name="END_LIST_ITEM" />
+<ph name="END_LIST" /></translation>
<translation id="1036348656032585052">Desactivar</translation>
<translation id="1036982837258183574">Preme |<ph name="ACCELERATOR" />| para saír da pantalla completa</translation>
<translation id="1038106730571050514">Mostrar suxestións</translation>
<translation id="1038842779957582377">nome descoñecido</translation>
<translation id="1041998700806130099">Mensaxe da folla do traballo</translation>
<translation id="1048785276086539861">Ao editar as anotacións, este documento volverá á vista dunha soa páxina</translation>
-<translation id="1049743911850919806">Modo de incógnito</translation>
<translation id="1050038467049342496">Pecha outras aplicacións</translation>
<translation id="1055184225775184556">&amp;Desfacer adición</translation>
<translation id="1056898198331236512">Advertencia</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">Caché de política correcta</translation>
<translation id="1130564665089811311">Botón Traducir páxina, preme Intro para traducir esta páxina co Tradutor de Google</translation>
<translation id="1131264053432022307">Imaxe que copiaches</translation>
+<translation id="1142846828089312304">Bloquear cookies de terceiros no modo de incógnito</translation>
<translation id="1150979032973867961">Este servidor non puido demostrar que é <ph name="DOMAIN" /> porque o sistema operativo do teu ordenador non confía no seu certificado de seguranza. É posible que isto se deba a un erro de configuración ou a que un atacante interceptase a túa conexión.</translation>
<translation id="1151972924205500581">Contrasinal obrigatorio</translation>
<translation id="1156303062776767266">Estás vendo un ficheiro local ou compartido</translation>
@@ -64,7 +70,6 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="1178581264944972037">Pausar</translation>
<translation id="1181037720776840403">Eliminar</translation>
<translation id="1186201132766001848">Comprobar contrasinais</translation>
-<translation id="1195210374336998651">Ir á configuración da aplicación</translation>
<translation id="1195558154361252544">Bloquéanse automaticamente as notificacións para todos os sitios, excepto para os que permitas</translation>
<translation id="1197088940767939838">Laranxa</translation>
<translation id="1201402288615127009">Seguinte</translation>
@@ -111,7 +116,7 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="1307966114820526988">Funcións obsoletas</translation>
<translation id="1308113895091915999">Oferta dispoñible</translation>
<translation id="1312803275555673949">Que probas demostran a información?</translation>
-<translation id="131405271941274527"><ph name="URL" /> quere enviar e recibir información cando o teu teléfono toque un dispositivo NFC</translation>
+<translation id="1314311879718644478">Goza de contido de realidade aumentada</translation>
<translation id="1314509827145471431">Encadernación na parte dereita</translation>
<translation id="1318023360584041678">Elemento gardado nun grupo de pestanas</translation>
<translation id="1319245136674974084">Non volver preguntar para esta aplicación</translation>
@@ -161,6 +166,7 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="142858679511221695">Usuario da nube</translation>
<translation id="1428729058023778569">Estás a ver esta advertencia porque o sitio non é compatible con HTTPS. <ph name="BEGIN_LEARN_MORE_LINK" />Máis información<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">Imprimir</translation>
+<translation id="1432187715652018471">esta páxina quere instalar un controlador de servizo.</translation>
<translation id="1432581352905426595">Xestionar motores de busca</translation>
<translation id="1436185428532214179">Pode pedirche permiso para editar ficheiros e cartafoles do teu dispositivo</translation>
<translation id="1442386063175183758">Dobrez en ventá na parte dereita</translation>
@@ -181,6 +187,12 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="1483493594462132177">Enviar</translation>
<translation id="1484290072879560759">Escoller enderezo de envío</translation>
<translation id="1492194039220927094">Aplicación de políticas:</translation>
+<translation id="149293076951187737">Ao pechar todas as pestanas do modo de incógnito de Chrome, bórrase deste dispositivo a seguinte información sobre a actividade que realizases nelas:
+<ph name="BEGIN_LIST" />
+<ph name="LIST_ITEM" />A actividade de navegación<ph name="END_LIST_ITEM" />
+<ph name="LIST_ITEM" />O historial de busca<ph name="END_LIST_ITEM" />
+<ph name="LIST_ITEM" />Os datos que puxeses en formularios<ph name="END_LIST_ITEM" />
+<ph name="END_LIST" /></translation>
<translation id="1495677929897281669">Volver á pestana</translation>
<translation id="1501859676467574491">Mostra tarxetas da túa Conta de Google</translation>
<translation id="1507202001669085618">&lt;p&gt;Verás este erro se utilizas un portal wifi no que tes que iniciar sesión para poder conectarte a Internet.&lt;/p&gt;
@@ -208,6 +220,8 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="1559572115229829303">&lt;p&gt;Non se pode establecer unha conexión privada con <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> porque a data e a hora do dispositivo (<ph name="DATE_AND_TIME" />) son incorrectas.&lt;/p&gt;
&lt;p&gt;Axusta a data e a hora na sección &lt;strong&gt;Xeral&lt;/strong&gt; da aplicación &lt;strong&gt;Configuración&lt;/strong&gt;.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">O teu administrador reiniciará o dispositivo o <ph name="DATE" /> a esta hora: <ph name="TIME" /></translation>
+<translation id="156703335097561114">Información das redes como enderezos, configuración de interfaces e calidade das conexións</translation>
<translation id="1567040042588613346">Esta política funciona segundo o previsto, pero substitúe un valor equivalente que está definido noutro lugar.</translation>
<translation id="1569487616857761740">Introduce unha data de vencemento</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="1583429793053364125">Produciuse un erro ao mostrar esta páxina web.</translation>
<translation id="1586541204584340881">As extensións que teñas instaladas</translation>
<translation id="1588438908519853928">Normal</translation>
+<translation id="1589050138437146318">Queres instalar ARCore?</translation>
<translation id="1592005682883173041">Acceso aos datos locais</translation>
<translation id="1594030484168838125">Escoller</translation>
<translation id="160851722280695521">Xogar a Dino Run en Chrome</translation>
@@ -282,6 +297,7 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
que require que se aplique unha política de orixe a todas as solicitudes que reciba. Non
obstante, o título ten un formato incorrecto, o que impide que o navegador complete
a solicitude de <ph name="SITE" />. Os operadores dos sitios poden utilizar as políticas de orixe para configurar a seguranza e outras propiedades dos sitios.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Máis información sobre o modo de incógnito de Chromium<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">As pestanas abertas aparecerán aquí</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -409,6 +425,7 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="22081806969704220">Bandexa 3</translation>
<translation id="2212735316055980242">Política non atopada</translation>
<translation id="2213606439339815911">Obtendo entradas...</translation>
+<translation id="2213612003795704869">Imprimiuse a páxina</translation>
<translation id="2215727959747642672">Modificación de ficheiros</translation>
<translation id="2218879909401188352">Os piratas informáticos do sitio <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> poderían instalar aplicacións perigosas que danen o teu dispositivo, engadir cargos ocultos á túa factura de teléfono móbil ou roubarche información persoal. <ph name="BEGIN_LEARN_MORE_LINK" />Máis información<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">Non hai conexión a Internet</translation>
@@ -418,6 +435,7 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="2248949050832152960">Usar autenticación web</translation>
<translation id="2250931979407627383">Grampa no bordo esquerdo</translation>
<translation id="225207911366869382">Este valor está obsoleto para esta política.</translation>
+<translation id="2256115617011615191">Reiniciar agora</translation>
<translation id="2258928405015593961">Introduce unha data de vencemento futura e téntao de novo</translation>
<translation id="225943865679747347">Código de erro: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">Erro de HTTP</translation>
@@ -445,6 +463,7 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="2337852623177822836">Opción de configuración controlada polo administrador</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> quere sincronizarse</translation>
<translation id="2346319942568447007">Imaxe que copiaches</translation>
+<translation id="2350796302381711542">Queres permitir que se use <ph name="HANDLER_HOSTNAME" /> en lugar de <ph name="REPLACED_HANDLER_TITLE" /> para abrir todas as ligazóns de <ph name="PROTOCOL" />?</translation>
<translation id="2354001756790975382">Outros marcadores</translation>
<translation id="2354430244986887761">A navegación segura de Google <ph name="BEGIN_LINK" />atopou aplicacións prexudiciais<ph name="END_LINK" /> recentemente en <ph name="SITE" />.</translation>
<translation id="2355395290879513365">É posible que os atacantes poidan ver as imaxes que estás observando neste sitio e enganarte modificándoas.</translation>
@@ -470,6 +489,7 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="2413528052993050574">Este servidor non puido demostrar que é <ph name="DOMAIN" /> porque quizais se revogase o certificado de seguranza. É posible que isto se deba a un erro de configuración ou a que un atacante interceptase a túa conexión.</translation>
<translation id="2414886740292270097">Escuro</translation>
<translation id="2430968933669123598">Xestionar Conta de Google. Preme Introducir para xestionar a información, a privacidade e a seguranza na túa Conta de Google</translation>
+<translation id="2436186046335138073">Queres que se use <ph name="HANDLER_HOSTNAME" /> para abrir todas as ligazóns de <ph name="PROTOCOL" />?</translation>
<translation id="2438874542388153331">Catro perforacións na parte dereita</translation>
<translation id="2450021089947420533">Percorridos</translation>
<translation id="2463739503403862330">Completar</translation>
@@ -477,6 +497,7 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="2465655957518002998">Escoller método de entrega</translation>
<translation id="2465688316154986572">Grampa</translation>
<translation id="2465914000209955735">Xestionar os ficheiros que descargaches en Chrome</translation>
+<translation id="2466004615675155314">Mostrar información da Web</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Executar diagnóstico de rede<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">Orde de 1 a N</translation>
<translation id="2470767536994572628">Ao editar as anotacións, este documento volverá á vista dunha soa páxina e á orientación orixinal</translation>
@@ -497,6 +518,7 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="2523886232349826891">Gardada só neste dispositivo</translation>
<translation id="2524461107774643265">Engadir máis información</translation>
<translation id="2529899080962247600">Este campo non debe ter máis de <ph name="MAX_ITEMS_LIMIT" /> entradas. Unha vez alcanzada esa cantidade, ignoraranse as demais entradas.</translation>
+<translation id="2535585790302968248">Abrir unha nova pestana do modo de incógnito para navegar de forma privada</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{e 1 máis}other{e # máis}}</translation>
<translation id="2536110899380797252">Engadir enderezo</translation>
<translation id="2539524384386349900">Detectar</translation>
@@ -522,7 +544,14 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="2597378329261239068">Este documento está protexido con contrasinal. Introduce un contrasinal.</translation>
<translation id="2609632851001447353">Variacións</translation>
<translation id="2610561535971892504">Fai clic para copiar a información</translation>
+<translation id="2617988307566202237">Chrome <ph name="BEGIN_EMPHASIS" />non gardará<ph name="END_EMPHASIS" /> a seguinte información:
+<ph name="BEGIN_LIST" />
+<ph name="LIST_ITEM" />O teu historial de navegación
+<ph name="LIST_ITEM" />As cookies e os datos dos sitios
+<ph name="LIST_ITEM" />Os datos que puxeses en formularios
+<ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (sobre)</translation>
+<translation id="2623663032199728144">Pode pedir usar información sobre as pantallas</translation>
<translation id="2625385379895617796">O teu reloxo está adiantado</translation>
<translation id="262745152991669301">Pode pedirche permiso para conectarse aos dispositivos USB</translation>
<translation id="2629325967560697240">Para gozar do máximo nivel de seguranza de Chrome, <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />activa a protección mellorada<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -556,6 +585,7 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="2709516037105925701">Autocompletar</translation>
<translation id="2713444072780614174">Branco</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />. Preme Tab e, a continuación, Intro para xestionar os teus métodos de pago e a información das tarxetas de crédito desde a configuración de Chrome</translation>
+<translation id="271663710482723385">Para saír da pantalla completa, preme |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />|</translation>
<translation id="2721148159707890343">Solicitude correcta</translation>
<translation id="2723669454293168317">Executar unha comprobación de seguranza na configuración de Chrome</translation>
<translation id="2726001110728089263">Bandexa lateral</translation>
@@ -586,6 +616,7 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="2850739647070081192">Invite (sobre)</translation>
<translation id="2856444702002559011">É posible que os piratas informáticos tenten roubar a túa información de <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (por exemplo, contrasinais, mensaxes ou tarxetas de crédito). <ph name="BEGIN_LEARN_MORE_LINK" />Máis información<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">Este sitio mostra anuncios intrusivos ou enganosos.</translation>
+<translation id="286512204874376891">As tarxetas virtuais ocultan as tarxetas reais para protexerte de posibles fraudes. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">Amigable</translation>
<translation id="2876489322757410363">Sairás do modo de incógnito para pagar a través dunha aplicación externa. Queres continuar?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />. Para xestionar na configuración de Chrome a Navegación segura e outras opcións, preme Tabulador e, a continuación, Introducir</translation>
@@ -610,6 +641,7 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="2930577230479659665">Recorte despois de cada copia</translation>
<translation id="2932085390869194046">Suxerir contrasinal…</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019">Abrir <ph name="PROTOCOL" /> ligazóns</translation>
<translation id="2941952326391522266">Este servidor non puido demostrar que é <ph name="DOMAIN" /> porque o seu certificado de seguranza é de <ph name="DOMAIN2" />. É posible que isto se deba a un erro de configuración ou a que un atacante interceptase a túa conexión.</translation>
<translation id="2943895734390379394">Momento da carga:</translation>
<translation id="2948083400971632585">Podes desactivar os proxies configurados para unha conexión desde a páxina de configuración.</translation>
@@ -642,6 +674,7 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="3037605927509011580">Vaia!</translation>
<translation id="3041612393474885105">Información do certificado</translation>
<translation id="3044034790304486808">Retomar investigación</translation>
+<translation id="305162504811187366">O historial de Escritorio remoto de Chrome, incluso as marcas de tempo, os hosts e os códigos de identificación da sesión do cliente</translation>
<translation id="3060227939791841287">C9 (sobre)</translation>
<translation id="3061707000357573562">Servizo de parche</translation>
<translation id="306573536155379004">Comezou a partida.</translation>
@@ -682,6 +715,7 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="3197136577151645743">Pode pedirche permiso para saber cando estás utilizando o dispositivo de maneira activa</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />. Para xestionar na configuración de Chrome a información que se sincroniza, preme Tabulador e, a continuación, Introducir</translation>
<translation id="320323717674993345">Cancelar pago</translation>
+<translation id="3203366800380907218">Da Web</translation>
<translation id="3207960819495026254">Engadida a marcadores</translation>
<translation id="3209034400446768650">Nesta páxina pódense aplicar cargos</translation>
<translation id="3212581601480735796">Estase supervisando a túa actividade en <ph name="HOSTNAME" /></translation>
@@ -698,10 +732,12 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="3234666976984236645">Detectar sempre contido importante neste sitio</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />. Para personalizar o aspecto do navegador, preme Tabulador e, a continuación, Introducir</translation>
<translation id="3240791268468473923">A folla da credencial de pagos seguros correspondente ás credenciais non coincidentes está aberta</translation>
+<translation id="324180406144491771">As ligazóns de “<ph name="HOST_NAME" />†están bloqueadas</translation>
<translation id="3249845759089040423">Moderno</translation>
<translation id="3252266817569339921">Francés</translation>
<translation id="3257954757204451555">Quen ofrece esta información?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />. Preme Tabulador e, a continuación, Introducir para crear rapidamente un novo evento en Google Calendar</translation>
+<translation id="3261488570342242926">Máis información sobre as tarxetas virtuais</translation>
<translation id="3264837738038045344">Botón para xestionar a configuración de Chrome. Para consultar a configuración de Chrome, preme Introducir</translation>
<translation id="3266793032086590337">Valor (en conflito)</translation>
<translation id="3268451620468152448">Pestanas abertas</translation>
@@ -715,6 +751,7 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="3288238092761586174">Pode que <ph name="URL" /> teña que tomar outras medidas para verificar o pago</translation>
<translation id="3293642807462928945">Máis información acerca da política de <ph name="POLICY_NAME" /></translation>
<translation id="3295444047715739395">Consulta e xestiona os teus contrasinais na configuración de Chrome</translation>
+<translation id="3303795387212510132">Queres darlle permiso á aplicación para que abra ligazóns <ph name="PROTOCOL_SCHEME" />?</translation>
<translation id="3303855915957856445">Non se encontraron resultados da busca</translation>
<translation id="3304073249511302126">busca de dispositivos Bluetooth</translation>
<translation id="3308006649705061278">Unidade organizativa (UO)</translation>
@@ -728,12 +765,6 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="3345782426586609320">Ollos</translation>
<translation id="3355823806454867987">Cambiar configuración do proxy...</translation>
<translation id="3360103848165129075">Folla do controlador de pagos</translation>
-<translation id="3361596688432910856">Chrome <ph name="BEGIN_EMPHASIS" />non gardará<ph name="END_EMPHASIS" /> a seguinte información:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />O teu historial de navegación
- <ph name="LIST_ITEM" />As cookies e os datos de sitios
- <ph name="LIST_ITEM" />A información introducida en formularios
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">Esta política copiouse automaticamente desde unha política <ph name="OLD_POLICY" /> obsoleta. Debes utilizar esta política e non a antiga.</translation>
<translation id="3364869320075768271"><ph name="URL" /> quere utilizar os teus datos e o teu dispositivo de realidade virtual</translation>
<translation id="3366477098757335611">Ver tarxetas</translation>
@@ -816,7 +847,6 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="3587738293690942763">Medio</translation>
<translation id="3592413004129370115">Italian (sobre)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{Podes restablecer o teu grupo cando queiras. Tardarás máis ou menos un día en unirte a un grupo novo.}=1{Podes restablecer o teu grupo cando queiras. Tardarás máis ou menos un día en unirte a un grupo novo.}other{Podes restablecer o teu grupo cando queiras. Tardarás {NUM_DAYS} días en unirte a un grupo novo.}}</translation>
-<translation id="3596012367874587041">Axustes da aplicación</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">O administrador bloqueou a aplicación</translation>
<translation id="3608932978122581043">Orientación da alimentación</translation>
@@ -859,6 +889,7 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="370972442370243704">Activar Percorridos</translation>
<translation id="3711895659073496551">Suspender</translation>
<translation id="3712624925041724820">Licenzas esgotadas</translation>
+<translation id="3714633008798122362">calendario web</translation>
<translation id="3714780639079136834">Activar os datos móbiles ou a wifi</translation>
<translation id="3715597595485130451">Conectarse á wifi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Comprobar o proxy, o firewall e a configuración de DNS<ph name="END_LINK" /></translation>
@@ -920,6 +951,7 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="3906954721959377182">Tableta</translation>
<translation id="3909477809443608991"><ph name="URL" /> quere reproducir contidos protexidos. Google verificará a identidade do teu dispositivo e este sitio web poderá acceder a ela.</translation>
<translation id="3909695131102177774"><ph name="LABEL" />: <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">Denegar</translation>
<translation id="3939773374150895049">Queres usar a autenticación web en lugar do CVC?</translation>
<translation id="3946209740501886391">Preguntar sempre sobre este sitio</translation>
<translation id="3947595700203588284">Pode pedirche permiso para conectarse aos dispositivos MIDI</translation>
@@ -941,6 +973,7 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="3990250421422698716">Compensación mediante empurro</translation>
<translation id="3996311196211510766">O sitio <ph name="ORIGIN" /> solicitou que se aplicase unha política de orixe
a todas as solicitudes que reciba, pero actualmente non se pode aplicar esta política.</translation>
+<translation id="4009243425692662128">O contido das páxinas que imprimas envíaselle a Google Cloud ou a terceiros para que o analicen. Por exemplo, poderíase comprobar se contén datos confidenciais.</translation>
<translation id="4010758435855888356">Queres permitir o acceso ao almacenamento?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{Documento PDF con {COUNT} páxina}other{Documento PDF con {COUNT} páxinas}}</translation>
<translation id="4023431997072828269">Dado que estás a piques de enviar este formulario a través dunha conexión non segura, a túa información será visible para outras persoas.</translation>
@@ -1035,6 +1068,7 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="4250680216510889253">Non</translation>
<translation id="4253168017788158739">Nota</translation>
<translation id="425582637250725228">É posible que non se gardasen os cambios que fixeches.</translation>
+<translation id="425869179292622354">Queres aumentar a protección cunha tarxeta virtual?</translation>
<translation id="4258748452823770588">Sinatura incorrecta</translation>
<translation id="4261046003697461417">Non se poden anotar os documentos protexidos</translation>
<translation id="4265872034478892965">Permitido polo administrador</translation>
@@ -1097,6 +1131,7 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="4434045419905280838">Ventás emerxentes e redireccións</translation>
<translation id="4435702339979719576">Postal)</translation>
<translation id="443673843213245140">O uso dun proxy está desactivado, pero especifícase unha configuración de proxy explícita.</translation>
+<translation id="4441832193888514600">Ignorada porque a política só se pode configurar como unha política de usuario da nube.</translation>
<translation id="4450893287417543264">Non mostrar outra vez</translation>
<translation id="4451135742916150903">Pode pedirche permiso para conectarse a dispositivos de interface humana</translation>
<translation id="4452328064229197696">O contrasinal que acabas de utilizar viuse implicado nunha violación da seguranza dos datos. Para protexer as túas contas, o xestor de contrasinais de Google recomenda que comprobes os contrasinais gardados.</translation>
@@ -1152,6 +1187,7 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="4628948037717959914">Foto</translation>
<translation id="4631649115723685955">Devolución de cartos vinculada</translation>
<translation id="4636930964841734540">Información</translation>
+<translation id="4638670630777875591">Modo de incógnito de Chromium</translation>
<translation id="464342062220857295">Busca funcións</translation>
<translation id="4644670975240021822">Orde inversa cara abaixo</translation>
<translation id="4646534391647090355">Visitar agora</translation>
@@ -1172,6 +1208,7 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="4708268264240856090">Interrompeuse a túa conexión</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Executar diagnóstico de rede de Windows<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426">Contrasinal de <ph name="USERNAME" /></translation>
<translation id="4724144314178270921">Pode pedirche permiso para acceder ao texto e ás imaxes do portapapeis</translation>
<translation id="4726672564094551039">Volver cargar políticas</translation>
<translation id="4728558894243024398">Plataforma</translation>
@@ -1193,6 +1230,7 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="4757993714154412917">Acabas de escribir o teu contrasinal nun sitio enganoso. Para protexer as túas contas, Chromium recoméndache que comprobes os contrasinais que tes gardados.</translation>
<translation id="4758311279753947758">Engadir información de contacto</translation>
<translation id="4761104368405085019">Utilizar o micrófono</translation>
+<translation id="4761869838909035636">Executar comprobación de seguranza de Chrome</translation>
<translation id="4764776831041365478">É posible que a páxina web de <ph name="URL" /> estea temporalmente inactiva ou que se trasladase definitivamente a outro enderezo web.</translation>
<translation id="4766713847338118463">Dúas grampas na parte inferior</translation>
<translation id="4771973620359291008">Produciuse un erro descoñecido.</translation>
@@ -1213,12 +1251,6 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="4819347708020428563">Queres editar as anotacións na vista predeterminada?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />. Preme Tabulador e, a continuación, Introducir para crear rapidamente unha nova folla de cálculo de Google</translation>
<translation id="4825507807291741242">Potente</translation>
-<translation id="4827402517081186284">O modo de incógnito non te converte en invisible en Internet:
-<ph name="BEGIN_LIST" />
-<ph name="LIST_ITEM" />Os sitios saben cando os visitas.<ph name="END_LIST_ITEM" />
-<ph name="LIST_ITEM" />A túa empresa ou centro educativo pode facer un seguimento da actividade de navegación.<ph name="END_LIST_ITEM" />
-<ph name="LIST_ITEM" />Os fornecedores de servizos de Internet poden supervisar o tráfico web.<ph name="END_LIST_ITEM" />
-<ph name="END_LIST" /></translation>
<translation id="483241715238664915">Activar advertencias</translation>
<translation id="4838327282952368871">Onírico</translation>
<translation id="4840250757394056958">Ver historial de Chrome</translation>
@@ -1230,12 +1262,12 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="4854362297993841467">Este método de entrega non está dispoñible. Proba cun diferente.</translation>
<translation id="4854853140771946034">Crear rapidamente unha nota nova en Google Keep</translation>
<translation id="485902285759009870">Verificando código…</translation>
+<translation id="4866506163384898554">Para que se mostre o cursor, preme |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />|</translation>
<translation id="4876188919622883022">Vista simplificada</translation>
<translation id="4876305945144899064">Sen nome de usuario</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{Ningún}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" /> e <ph name="EXAMPLE_DOMAIN_2" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831">Busca de "<ph name="TEXT" />"</translation>
<translation id="4879491255372875719">Automático (opción predeterminada)</translation>
-<translation id="4879725228911483934">Abrir e colocar ventás nas túas pantallas</translation>
<translation id="4880827082731008257">Historial de busca</translation>
<translation id="4881695831933465202">Abrir</translation>
<translation id="4885256590493466218">Paga con <ph name="CARD_DETAIL" /> ao procesar a compra</translation>
@@ -1244,6 +1276,7 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">Noveno rolo</translation>
<translation id="4901778704868714008">Gardar…</translation>
+<translation id="4905659621780993806">O teu administrador reiniciará o dispositivo automaticamente o <ph name="DATE" /> a esta hora: <ph name="TIME" />. Garda os elementos que teñas abertos antes de que se reinicie o dispositivo.</translation>
<translation id="4913987521957242411">Perforación na parte superior esquerda</translation>
<translation id="4918221908152712722">Instala a aplicación <ph name="APP_NAME" /> (non require descarga)</translation>
<translation id="4923459931733593730">Pago</translation>
@@ -1252,6 +1285,7 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />. Para realizar unha busca, preme Tab e despois Intro</translation>
<translation id="4930153903256238152">Gran capacidade</translation>
+<translation id="4940163644868678279">Modo de incógnito de Chrome</translation>
<translation id="4943872375798546930">Non hai resultados</translation>
<translation id="4950898438188848926">Botón de cambio de pestana, preme Intro para cambiar á pestana aberta, <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="495170559598752135">Accións</translation>
@@ -1261,6 +1295,7 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="4968522289500246572">Esta aplicación está deseñada para dispositivos móbiles e pode que non cambie ben de tamaño. É posible que se reinicie ou que se produza algún problema co seu funcionamento.</translation>
<translation id="4969341057194253438">Eliminar gravación</translation>
<translation id="4973922308112707173">Dúas perforacións na parte superior</translation>
+<translation id="4976702386844183910">Visitouse o <ph name="DATE" /> por última vez</translation>
<translation id="4984088539114770594">Queres utilizar o micrófono?</translation>
<translation id="4984339528288761049">Prc5 (sobre)</translation>
<translation id="4989163558385430922">Ver todo</translation>
@@ -1322,6 +1357,7 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="5138227688689900538">Mostrar menos</translation>
<translation id="5145883236150621069">Código de erro presente na resposta da política</translation>
<translation id="5146995429444047494">As notificacións de <ph name="ORIGIN" /> están bloqueadas</translation>
+<translation id="514704532284964975"><ph name="URL" /> quere consultar e cambiar información nos dispositivos con NFC que toques co teléfono</translation>
<translation id="5148809049217731050">Cara arriba</translation>
<translation id="515292512908731282">C4 (sobre)</translation>
<translation id="5158275234811857234">Portada</translation>
@@ -1346,6 +1382,7 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="5215116848420601511">Métodos de pago e enderezos que usan Google Pay</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">Bandexa 13</translation>
+<translation id="5216942107514965959">Visitouse hoxe por última vez</translation>
<translation id="5222812217790122047">É obrigatorio introducir o correo electrónico</translation>
<translation id="5230733896359313003">Enderezo de envío</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1366,7 +1403,6 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">Propiedades do documento</translation>
<translation id="528468243742722775">Final</translation>
-<translation id="5284909709419567258">Enderezos de rede</translation>
<translation id="5285570108065881030">Mostrar todos os contrasinais gardados</translation>
<translation id="5287240709317226393">Mostrar cookies</translation>
<translation id="5287456746628258573">Este sitio utiliza unha configuración de seguranza obsoleta que pode poñer en risco a túa información (por exemplo, contrasinais ou números de tarxetas de crédito) cando se lle envía.</translation>
@@ -1450,6 +1486,7 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="5556459405103347317">Volver cargar</translation>
<translation id="5560088892362098740">Data de caducidade</translation>
<translation id="55635442646131152">Esquema do documento</translation>
+<translation id="5565613213060953222">Abrir pestana do modo de incógnito</translation>
<translation id="5565735124758917034">Activo</translation>
<translation id="5570825185877910964">Protexer conta</translation>
<translation id="5571083550517324815">Non se pode realizar a recollida neste enderezo. Selecciona un diferente.</translation>
@@ -1532,6 +1569,7 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="5869522115854928033">Contrasinais gardados</translation>
<translation id="5873013647450402046">O teu banco quere confirmar a túa identidade.</translation>
<translation id="5887400589839399685">Gardouse a tarxeta</translation>
+<translation id="5887687176710214216">Visitouse onte por última vez</translation>
<translation id="5895138241574237353">Reiniciar</translation>
<translation id="5895187275912066135">Emitido o</translation>
<translation id="5901630391730855834">Amarelo</translation>
@@ -1545,6 +1583,7 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="5921639886840618607">Queres gardar a tarxeta na Conta de Google?</translation>
<translation id="5922853866070715753">Case está listo</translation>
<translation id="5932224571077948991">O sitio mostra anuncios enganosos ou intrusivos</translation>
+<translation id="5938153366081463283">Engadir tarxeta virtual</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347">Abrindo <ph name="SITE_NAME" />…</translation>
<translation id="5951495562196540101">Non se pode realizar a inscrición coa conta de uso particular (licenza en paquete dispoñible).</translation>
@@ -1609,6 +1648,7 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="6120179357481664955">Queres lembrar o teu código da UPI?</translation>
<translation id="6124432979022149706">Conectores de Chrome Enterprise</translation>
<translation id="6127379762771434464">Eliminouse o elemento</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Máis información sobre o modo de incógnito de Chrome<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">Comproba os cables e reinicia os routers, módems e demais dispositivos
de rede que utilices.</translation>
<translation id="614940544461990577">Proba a facer o seguinte:</translation>
@@ -1621,7 +1661,6 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="6169916984152623906">Agora podes navegar de forma privada, sen que os demais usuarios deste dispositivo vexan a túa actividade. Non obstante, gardaranse as descargas e os marcadores.</translation>
<translation id="6177128806592000436">A túa conexión a este sitio non é segura</translation>
<translation id="6180316780098470077">Intervalo de reintentos</translation>
-<translation id="619448280891863779">Pode pedirche permiso para abrir e colocar ventás nas túas pantallas</translation>
<translation id="6196640612572343990">Bloquear cookies de terceiros</translation>
<translation id="6203231073485539293">Comproba a túa conexión a Internet</translation>
<translation id="6218753634732582820">Queres eliminar o enderezo de Chromium?</translation>
@@ -1644,7 +1683,7 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="6272383483618007430">Actualización de Google</translation>
<translation id="6276112860590028508">As páxinas da túa lista de lectura aparecen aquí</translation>
<translation id="627746635834430766">Para pagar máis rápido a próxima vez, garda a túa tarxeta e o enderezo de facturación na conta de Google.</translation>
-<translation id="6279098320682980337">Non se autocompletou o número da tarxeta virtual? Para copialo, fai clic nos detalles da tarxeta</translation>
+<translation id="6279183038361895380">Preme |<ph name="ACCELERATOR" />| para mostrar o cursor</translation>
<translation id="6280223929691119688">Non se pode realizar a entrega neste enderezo. Selecciona un diferente.</translation>
<translation id="6282194474023008486">Código postal</translation>
<translation id="6285507000506177184">Botón para xestionar as descargas en Chrome. Se queres xestionar os ficheiros que descargaches en Chrome, preme Introducir</translation>
@@ -1652,6 +1691,7 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="6290238015253830360">Os teus artigos suxeridos aparecerán aquí</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{O dispositivo reiniciarase agora}=1{O dispositivo reiniciarase en 1 segundo}other{O dispositivo reiniciarase en # segundos}}</translation>
<translation id="6302269476990306341">Detendo o Asistente de Google en Chrome</translation>
<translation id="6305205051461490394">Non se pode acceder a <ph name="URL" />.</translation>
<translation id="6312113039770857350">A páxina web non está dispoñible</translation>
@@ -1725,6 +1765,7 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="6529602333819889595">&amp;Refacer eliminación</translation>
<translation id="6545864417968258051">Busca de dispositivos Bluetooth</translation>
<translation id="6547208576736763147">Dúas perforacións na parte esquerda</translation>
+<translation id="6554732001434021288">Visitouse hai <ph name="NUM_DAYS" /> días por última vez</translation>
<translation id="6556866813142980365">Refacer</translation>
<translation id="6569060085658103619">Estás vendo unha páxina de extensións</translation>
<translation id="6573200754375280815">Dúas perforacións na parte dereita</translation>
@@ -1785,7 +1826,6 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="6757797048963528358">O teu dispositivo entrou no modo de suspensión.</translation>
<translation id="6767985426384634228">Queres actualizar este enderezo?</translation>
<translation id="6768213884286397650">Hagaki (postal)</translation>
-<translation id="6774185088257932239"><ph name="BEGIN_LINK" />Máis información<ph name="END_LINK" /> sobre o modo de incógnito</translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">Violeta</translation>
<translation id="6786747875388722282">Extensións</translation>
@@ -1869,7 +1909,6 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="706295145388601875">Engade e xestiona enderezos na configuración de Chrome</translation>
<translation id="7064851114919012435">Información de contacto</translation>
<translation id="7068733155164172741">Mete un código de <ph name="OTP_LENGTH" /> díxitos</translation>
-<translation id="7070090581017165256">Acerca deste sitio</translation>
<translation id="70705239631109039">A túa conexión non é completamente segura</translation>
<translation id="7075452647191940183">A solicitude é demasiado grande</translation>
<translation id="7079718277001814089">Este sitio contén software malicioso</translation>
@@ -1886,6 +1925,12 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="7111012039238467737">(Válido)</translation>
<translation id="7118618213916969306">Buscar URL do portapapeis (<ph name="SHORT_URL" />)</translation>
<translation id="7119414471315195487">Pecha outras pestanas ou programas</translation>
+<translation id="7129355289156517987">Ao pechar todas as pestanas do modo de incógnito de Chromium, bórrase deste dispositivo a seguinte información sobre a actividade que realizases nelas:
+<ph name="BEGIN_LIST" />
+<ph name="LIST_ITEM" />A actividade de navegación<ph name="END_LIST_ITEM" />
+<ph name="LIST_ITEM" />O historial de busca<ph name="END_LIST_ITEM" />
+<ph name="LIST_ITEM" />Os datos que puxeses en formularios<ph name="END_LIST_ITEM" />
+<ph name="END_LIST" /></translation>
<translation id="7129409597930077180">Non se pode realizar o envío a este enderezo. Selecciona un diferente.</translation>
<translation id="7132939140423847331">O teu administrador prohibiu que copiases estes datos.</translation>
<translation id="7135130955892390533">Mostrar estado</translation>
@@ -1908,6 +1953,7 @@ En caso contrario, a configuración de privacidade impedirao. Se o permites, o c
<translation id="7192203810768312527">Libera ata <ph name="SIZE" />. É posible que algúns sitios carguen de forma máis lenta a próxima vez que os visites.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">O teu administrador pode ver:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />. Para abrir unha nova pestana do modo de incógnito e navegar de forma privada, preme Tabulador e, a continuación, Introducir</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> non cumpre cos estándares de seguranza.</translation>
<translation id="7210993021468939304">Actividade de Linux no contedor, e pode instalar e executar aplicacións de Linux no contedor.</translation>
@@ -1939,6 +1985,7 @@ Detalles adicionais:
<translation id="7304562222803846232">Xestionar configuración de privacidade da Conta de Google</translation>
<translation id="7305756307268530424">Iniciar a menor velocidade</translation>
<translation id="7308436126008021607">sincronización en segundo plano</translation>
+<translation id="7310392214323165548">O dispositivo reiniciarase en breve</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">Axuda de conexión</translation>
<translation id="7323804146520582233">Ocultar a sección <ph name="SECTION" /></translation>
@@ -1946,6 +1993,7 @@ Detalles adicionais:
<translation id="7334320624316649418">&amp;Refacer de cambio de orde</translation>
<translation id="7335157162773372339">Pode pedirche permiso para utilizar a cámara</translation>
<translation id="7337248890521463931">Mostrar máis liñas</translation>
+<translation id="7337418456231055214">Non se autocompletou o número da tarxeta virtual? Para copialo, fai clic nos detalles da tarxeta. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">Non está dispoñible na túa plataforma.</translation>
<translation id="733923710415886693">O certificado do servidor non se indicou mediante Certificate Transparency.</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1968,6 +2016,7 @@ Detalles adicionais:
<translation id="7378627244592794276">Non</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">Non aplicable</translation>
+<translation id="7388594495505979117">{0,plural, =1{O dispositivo reiniciarase en 1 minuto}other{O dispositivo reiniciarase en # minutos}}</translation>
<translation id="7390545607259442187">Confirmar tarxeta</translation>
<translation id="7392089738299859607">Actualizar enderezo</translation>
<translation id="7399802613464275309">Revisión de seguranza</translation>
@@ -2004,6 +2053,12 @@ Detalles adicionais:
<translation id="7485870689360869515">Non se atoparon datos.</translation>
<translation id="7495528107193238112">Este contido está bloqueado. Ponte en contacto co propietario do sitio para corrixir o problema.</translation>
<translation id="7497998058912824456">Botón Crear documento. Preme Tabulador e, a continuación, Introducir para crear rapidamente un novo documento de Google</translation>
+<translation id="7506488012654002225">Chromium <ph name="BEGIN_EMPHASIS" />non gardará<ph name="END_EMPHASIS" /> a seguinte información:
+<ph name="BEGIN_LIST" />
+<ph name="LIST_ITEM" />O teu historial de navegación
+<ph name="LIST_ITEM" />As cookies e os datos dos sitios
+<ph name="LIST_ITEM" />Os datos que puxeses en formularios
+<ph name="END_LIST" /></translation>
<translation id="7508255263130623398">O código de dispositivo da política está baleiro ou non coincide co código do dispositivo actual</translation>
<translation id="7508870219247277067">Verde aguacate</translation>
<translation id="7511955381719512146">É posible que a rede wifi que utilizas requira o acceso a <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
@@ -2117,7 +2172,6 @@ Detalles adicionais:
<translation id="7813600968533626083">Queres eliminar a suxestión de Chrome?</translation>
<translation id="781440967107097262">Queres compartir o portapapeis?</translation>
<translation id="7815407501681723534">Encontráronse <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> para "<ph name="SEARCH_STRING" />"</translation>
-<translation id="782125616001965242">Mostrar información sobre este sitio</translation>
<translation id="782886543891417279">É posible que a rede wifi que utilizas (<ph name="WIFI_NAME" />) requira o acceso á súa páxina de inicio de sesión.</translation>
<translation id="7836231406687464395">Postfix (sobre)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{Ningunha}=1{1 aplicación (<ph name="EXAMPLE_APP_1" />)}=2{2 aplicacións (<ph name="EXAMPLE_APP_1" /> e <ph name="EXAMPLE_APP_2" />)}other{# aplicacións (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" /> e <ph name="AND_MORE" />)}}</translation>
@@ -2134,7 +2188,6 @@ Detalles adicionais:
<translation id="7888575728750733395">Intent de renderización da impresión</translation>
<translation id="7894280532028510793">Se está ben escrito, podes <ph name="BEGIN_LINK" />probar a executar o diagnóstico de rede<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (sobre)</translation>
-<translation id="7931318309563332511">Descoñecido</translation>
<translation id="793209273132572360">Queres cambiar o enderezo?</translation>
<translation id="7932579305932748336">Recubrimento</translation>
<translation id="79338296614623784">Introduce un número de teléfono válido</translation>
@@ -2159,13 +2212,14 @@ Detalles adicionais:
<translation id="7976214039405368314">Hai demasiadas solicitudes</translation>
<translation id="7977538094055660992">Dispositivo de saída</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">Estableceuse unha vinculación con</translation>
<translation id="798134797138789862">Pode pedirche permiso para usar datos e dispositivos de realidade virtual</translation>
<translation id="7984945080620862648">Non podes visitar <ph name="SITE" /> agora mesmo porque o sitio web enviou credenciais cifradas que Chrome non pode procesar. Normalmente, os erros de rede e os ataques son temporais, polo que é posible que esta páxina funcione máis tarde.</translation>
-<translation id="79859296434321399">Para ver contido de realidade aumentada, instala ARCore</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">Encadernación</translation>
<translation id="7992044431894087211">Retomouse a pantalla compartida con <ph name="APPLICATION_TITLE" /></translation>
<translation id="7995512525968007366">Non especificado</translation>
+<translation id="7998269595945679889">Botón Abrir pestana do modo de incógnito. Preme Introducir para abrir unha nova pestana do modo de incógnito e navegar de forma privada</translation>
<translation id="800218591365569300">Proba a pechar outras pestanas ou programas para liberar memoria.</translation>
<translation id="8004582292198964060">Navegador</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{Gardarase esta tarxeta e o seu enderezo de facturación. Poderás utilizala ao iniciar sesión en <ph name="USER_EMAIL" />.}other{Gardaranse estas tarxetas e os seus enderezos de facturación. Poderás utilizalas ao iniciar sesión en <ph name="USER_EMAIL" />.}}</translation>
@@ -2225,6 +2279,7 @@ Detalles adicionais:
<translation id="8202370299023114387">Conflito</translation>
<translation id="8206978196348664717">Prc4 (sobre)</translation>
<translation id="8211406090763984747">A conexión é segura</translation>
+<translation id="8217240300496046857">Os sitios non poden usar cookies para seguirte pola Web. As funcións dalgúns sitios poden quedar bloqueadas.</translation>
<translation id="8218327578424803826">Localización asignada:</translation>
<translation id="8220146938470311105">C7/C6 (sobre)</translation>
<translation id="8225771182978767009">A persoa que configurou este ordenador optou por bloquear este sitio.</translation>
@@ -2265,14 +2320,9 @@ Detalles adicionais:
<translation id="830498451218851433">Dobrez á metade</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">Aplicacións instaladas e frecuencia de uso</translation>
+<translation id="8317207217658302555">Queres actualizar ARCore?</translation>
<translation id="831997045666694187">Serán</translation>
<translation id="8321476692217554900">notificacións</translation>
-<translation id="8328484624016508118">Despois de pechar todas as pestanas do modo de incógnito, Chrome borra:
-<ph name="BEGIN_LIST" />
-<ph name="LIST_ITEM" />A túa actividade de navegación deste dispositivo.<ph name="END_LIST_ITEM" />
-<ph name="LIST_ITEM" />O teu historial de busca deste dispositivo.<ph name="END_LIST_ITEM" />
-<ph name="LIST_ITEM" />Os datos que escribises en formularios.<ph name="END_LIST_ITEM" />
-<ph name="END_LIST" /></translation>
<translation id="8332188693563227489">Denegouse o acceso a <ph name="HOST_NAME" /></translation>
<translation id="833262891116910667">Destacar</translation>
<translation id="8339163506404995330">Non se traducirán as páxinas en <ph name="LANGUAGE" /></translation>
@@ -2324,6 +2374,7 @@ Detalles adicionais:
<translation id="8507227106804027148">Liña de comandos</translation>
<translation id="8508648098325802031">Icona de busca</translation>
<translation id="8511402995811232419">Xestionar cookies</translation>
+<translation id="8519753333133776369">O teu administrador permite o uso do dispositivo HID</translation>
<translation id="8522552481199248698">Chrome pode axudarche a protexer a túa Conta de Google e a cambiar o teu contrasinal.</translation>
<translation id="8530813470445476232">Borra o historial de navegación, as cookies, a memoria caché e moito máis na configuración de Chrome</translation>
<translation id="8533619373899488139">Visita &lt;strong&gt;chrome://policy&lt;/strong&gt; para ver a lista dos URL bloqueados e outras políticas aplicadas polo teu administrador do sistema.</translation>
@@ -2335,7 +2386,6 @@ Detalles adicionais:
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{Restablecer permiso}other{Restablecer permisos}}</translation>
<translation id="8555010941760982128">Usa este código ao tramitar a compra</translation>
<translation id="8557066899867184262">O código CVC atópase na parte traseira da tarxeta</translation>
-<translation id="8558485628462305855">Para ver contido de realidade aumentada, actualiza ARCore</translation>
<translation id="8559762987265718583">Non se pode establecer unha conexión privada con <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> porque a data e a hora do dispositivo (<ph name="DATE_AND_TIME" />) son incorrectas.</translation>
<translation id="8564182942834072828">Documentos independentes/copias non intercaladas</translation>
<translation id="8564985650692024650">Chromium recoméndache que restablezas o contrasinal de <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> se o reutilizaches noutros sitios.</translation>
@@ -2354,6 +2404,7 @@ Detalles adicionais:
<translation id="865032292777205197">sensores de movemento</translation>
<translation id="8663226718884576429">Resumo do pedido, <ph name="TOTAL_LABEL" />, máis detalles</translation>
<translation id="8666678546361132282">Inglés</translation>
+<translation id="8669306706049782872">Usar información sobre as pantallas para abrir e colocar ventás</translation>
<translation id="867224526087042813">Sinatura</translation>
<translation id="8676424191133491403">Sen retardo</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, resposta: <ph name="ANSWER" /></translation>
@@ -2380,6 +2431,7 @@ Detalles adicionais:
<translation id="8731544501227493793">Botón Xestionar contrasinais. Preme Intro para ver e xestionar os teus contrasinais desde a configuración de Chrome</translation>
<translation id="8734529307927223492"><ph name="MANAGER" /> xestiona o teu dispositivo (<ph name="DEVICE_TYPE" />)</translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, preme Tab e, a continuación, Intro para abrir unha ventá do modo de incógnito e navegar de forma privada</translation>
+<translation id="8737685506611670901">Abrir ligazóns de <ph name="PROTOCOL" /> en lugar de <ph name="REPLACED_HANDLER_TITLE" /></translation>
<translation id="8738058698779197622">Para establecer unha conexión segura, é necesario axustar o reloxo correctamente. Isto débese a que os certificados que utilizan os sitios web para identificarse só son válidos durante períodos de tempo específicos. Debido a que o reloxo do dispositivo non está correctamente axustado, Chromium non pode verificar estes certificados.</translation>
<translation id="8740359287975076522">Non se puido atopar o &lt;abbr id="dnsDefinition"&gt;enderezo DNS&lt;/abbr&gt; de <ph name="HOST_NAME" />. Estase diagnosticando o problema.</translation>
<translation id="8742371904523228557"><ph name="ONE_TIME_CODE" /> é o teu código para <ph name="ORIGIN" /></translation>
@@ -2407,6 +2459,7 @@ Detalles adicionais:
<translation id="883848425547221593">Outros marcadores</translation>
<translation id="884264119367021077">Enderezo de envío</translation>
<translation id="884923133447025588">Non se atopou ningún mecanismo de revogación.</translation>
+<translation id="8849262850971482943">Para operar con máis seguranza, utiliza a tarxeta virtual</translation>
<translation id="885730110891505394">Compartindo con Google</translation>
<translation id="8858065207712248076">Chrome recoméndache que restablezas o contrasinal de <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> se o reutilizaches noutros sitios.</translation>
<translation id="885906927438988819">Se está ben escrito, podes <ph name="BEGIN_LINK" />probar a executar o diagnóstico de rede de Windows<ph name="END_LINK" />.</translation>
@@ -2456,6 +2509,7 @@ Detalles adicionais:
<translation id="9004367719664099443">Sesión de RV en curso</translation>
<translation id="9005998258318286617">Produciuse un erro ao cargar o documento PDF.</translation>
<translation id="9008201768610948239">Ignorar</translation>
+<translation id="901834265349196618">correo electrónico</translation>
<translation id="9020200922353704812">É obrigatorio introducir o enderezo de facturación da tarxeta</translation>
<translation id="9020542370529661692">Traduciuse esta páxina ao <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9020742383383852663">A8</translation>
@@ -2504,6 +2558,7 @@ Detalles adicionais:
<translation id="9150045010208374699">Utilizar a túa cámara</translation>
<translation id="9150685862434908345">O teu administrador pode cambiar a configuración do navegador de forma remota. A actividade deste dispositivo tamén se pode xestionar fóra de Chrome. <ph name="BEGIN_LINK" />Máis información<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">Actualizado</translation>
+<translation id="9155211586651734179">Os periféricos de audio conectados</translation>
<translation id="9157595877708044936">Configurando...</translation>
<translation id="9158625974267017556">C6 (sobre)</translation>
<translation id="9164029392738894042">Comprobación da precisión</translation>
diff --git a/chromium/components/strings/components_strings_gu.xtb b/chromium/components/strings/components_strings_gu.xtb
index b419166e865..2326c71782c 100644
--- a/chromium/components/strings/components_strings_gu.xtb
+++ b/chromium/components/strings/components_strings_gu.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">વિગતો જà«àª“</translation>
<translation id="1030706264415084469"><ph name="URL" /> તમારા ઉપકરણ પર કાયમી ધોરણે વિશાળ ડેટા સà«àªŸà«‹àª° કરવા માગે છે</translation>
<translation id="1032854598605920125">ઘડિયાળની દિશામાં ફેરવો</translation>
+<translation id="1033329911862281889">છૂપા મોડ થકી તમે ઑનલાઇન અદૃશà«àª¯ બની જતા નથી:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />સાઇટ અને તેમના દà«àªµàª¾àª°àª¾ ઉપયોગમાં લેવાતી સેવાઓ મà«àª²àª¾àª•àª¾àª¤à«‹ જોઈ શકે છે<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />નિયોકà«àª¤àª¾ અથવા સà«àª•à«‚લ બà«àª°àª¾àª‰àªàª¿àª‚ગ પà«àª°àªµà«ƒàª¤à«àª¤àª¿ ટà«àª°à«…ક કરી શકે છે<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ઇનà«àªŸàª°àª¨à«‡àªŸ સેવા આપનાર કંપની વેબ ટà«àª°àª¾àª«àª¿àª• મૉનિટર કરી શકે છે<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">બંધ કરો</translation>
<translation id="1036982837258183574">બહાર નીકળવા માટે |<ph name="ACCELERATOR" />| દબાવો</translation>
<translation id="1038106730571050514">સૂચનો બતાવો</translation>
<translation id="1038842779957582377">અજà«àªžàª¾àª¤ નામ</translation>
<translation id="1041998700806130099">જોબ શીટ સંદેશ</translation>
<translation id="1048785276086539861">જà«àª¯àª¾àª°à«‡ તમે ટીકાટિપà«àªªàª£à«€àª®àª¾àª‚ ફેરફાર કરશો, તà«àª¯àª¾àª°à«‡ આ દસà«àª¤àª¾àªµà«‡àªœ 'àªàª• પેજના વà«àª¯à«‚' પર પાછો ફરશે</translation>
-<translation id="1049743911850919806">છૂપી</translation>
<translation id="1050038467049342496">અનà«àª¯ àªàªªà«àª²àª¿àª•à«‡àª¶àª¨à«‹ બંધ કરો</translation>
<translation id="1055184225775184556">&amp;ઉમેરવà«àª‚ પૂરà«àªµàªµàª¤à« કરો</translation>
<translation id="1056898198331236512">ચેતવણી</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">પૉલિસી કૅશ મેમરી ઓકે</translation>
<translation id="1130564665089811311">પેજનો અનà«àªµàª¾àª¦ કરો બટન, Google Translate વડે આ પેજનો અનà«àªµàª¾àª¦ કરવા માટે Enter દબાવો</translation>
<translation id="1131264053432022307">તમે કૉપિ કરેલી છબી</translation>
+<translation id="1142846828089312304">તà«àª°à«€àªœàª¾ પકà«àª·àª¨à«€ કà«àª•à«€àª¨à«‡ છૂપા મોડમાં બà«àª²à«‰àª• કરો</translation>
<translation id="1150979032973867961">આ સરà«àªµàª° સાબિત કરી શકà«àª¯à«àª‚ નથી કે ઠ<ph name="DOMAIN" /> છે; àªàª¨à«àª‚ સà«àª°àª•à«àª·àª¾ પà«àª°àª®àª¾àª£àªªàª¤à«àª° તમારા કમà«àªªà«àª¯à«àªŸàª°àª¨à«€ ઑપરેટિંગ સિસà«àªŸàª® દà«àªµàª¾àª°àª¾ વિશà«àªµàª¸àª¨à«€àª¯ નથી. આ કોઈ ખોટી ગોઠવણીને કારણે થયà«àª‚ હશે અથવા કોઈ હà«àª®àª²àª¾àª–ોર તમારા કનેકà«àª¶àª¨àª¨à«‡ અટકાવી રહà«àª¯à«‹ છે.</translation>
<translation id="1151972924205500581">પાસવરà«àª¡ આવશà«àª¯àª• છે</translation>
<translation id="1156303062776767266">તમે સà«àª¥àª¾àª¨àª¿àª• અથવા શેર કરેલી ફાઇલ જોઈ રહà«àª¯àª¾àª‚ છો</translation>
@@ -64,7 +70,6 @@
<translation id="1178581264944972037">થોભો</translation>
<translation id="1181037720776840403">કાઢી નાખો</translation>
<translation id="1186201132766001848">પાસવરà«àª¡ ચેક કરો</translation>
-<translation id="1195210374336998651">àªàªª સેટિંગ પર જાઓ</translation>
<translation id="1195558154361252544">તમે જેના માટે મંજૂરી આપી હોય તે સિવાયની બધી સાઇટ માટે નોટિફિકેશનને ઑટોમૅટિક રીતે બà«àª²à«‰àª• કરવામાં આવે છે</translation>
<translation id="1197088940767939838">નારંગી</translation>
<translation id="1201402288615127009">આગલà«àª‚</translation>
@@ -111,7 +116,7 @@
<translation id="1307966114820526988">નાપસંદ કરેલી સà«àªµàª¿àª§àª¾àª“</translation>
<translation id="1308113895091915999">ઑફર ઉપલબà«àª§ છે</translation>
<translation id="1312803275555673949">કયા પà«àª°àª¾àªµàª¾ તેને સપોરà«àªŸ કરે છે?</translation>
-<translation id="131405271941274527">જà«àª¯àª¾àª°à«‡ તમે NFC ડિવાઇસ પર તમારા ફોન પર ટૅપ કરો, તà«àª¯àª¾àª°à«‡ <ph name="URL" /> માહિતી મોકલવા અને પà«àª°àª¾àªªà«àª¤ કરવા માગે છે</translation>
+<translation id="1314311879718644478">ઑગà«àª®à«‡àª¨à«àªŸà«‡àª¡ રિયાલિટી કનà«àªŸà«‡àª¨à«àªŸ જà«àª“</translation>
<translation id="1314509827145471431">જમણી બાજà«àª જોડો</translation>
<translation id="1318023360584041678">ટૅબ ગà«àª°à«‚પમાં સાચવà«àª¯à«àª‚</translation>
<translation id="1319245136674974084">આ àªàªª માટે ફરીથી પૂછશો નહીં</translation>
@@ -161,6 +166,7 @@
<translation id="142858679511221695">કà«àª²àª¾àª‰àª¡ વપરાશકરà«àª¤àª¾</translation>
<translation id="1428729058023778569">તમે આ ચેતવણી જોઈ રહà«àª¯àª¾àª‚ છો કારણ કે આ સાઇટ HTTPSને સપોરà«àªŸ કરતી નથી. <ph name="BEGIN_LEARN_MORE_LINK" />વધૠજાણો<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">પà«àª°àª¿àª¨à«àªŸ</translation>
+<translation id="1432187715652018471">પેજ સેવાનà«àª‚ હૅનà«àª¡àª²àª° ઇનà«àª¸à«àªŸà«‰àª² કરવા માગે છે.</translation>
<translation id="1432581352905426595">શોધ àªàª¨à«àªœàª¿àª¨ મેનેજ કરો</translation>
<translation id="1436185428532214179">તમારા ડિવાઇસમાંની ફાઇલોમાં અને ફોલà«àª¡àª°à«‹àª®àª¾àª‚ ફેરફાર કરવાનà«àª‚ પૂછી શકે છે</translation>
<translation id="1442386063175183758">જમણો ગેટ ફોલà«àª¡</translation>
@@ -181,6 +187,12 @@
<translation id="1483493594462132177">મોકલો</translation>
<translation id="1484290072879560759">વિતરણ માટેનà«àª‚ સરનામà«àª‚ પસંદ કરો</translation>
<translation id="1492194039220927094">પà«àª¶ કરેલી પૉલિસી:</translation>
+<translation id="149293076951187737">તમે Chromeની બધી છૂપી ટૅબ બંધ કરી દો તà«àª¯àª¾àª°à«‡ તે ટૅબની તમારી પà«àª°àªµà«ƒàª¤à«àª¤àª¿ આ ડિવાઇસમાંથી સાફ કરી દેવાય છે:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />બà«àª°àª¾àª‰àªàª¿àª‚ગ પà«àª°àªµà«ƒàª¤à«àª¤àª¿<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />શોધ ઇતિહાસ<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ફોરà«àª®àª®àª¾àª‚ દાખલ કરેલી માહિતી<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">ટૅબ પર પાછા જાઓ</translation>
<translation id="1501859676467574491">તમારા Google àªàª•àª¾àª‰àª¨à«àªŸàª®àª¾àª‚થી કારà«àª¡ બતાવો</translation>
<translation id="1507202001669085618">&lt;p&gt;જો તમે ઑનલાઇન થાઓ ઠપહેલાં જà«àª¯àª¾àª‚ તમારે સાઇન ઇન કરવà«àª‚ જરૂરી હોય તેવા વાઇ-ફાઇ પોરà«àªŸàª²àª¨à«‹ ઉપયોગ કરી રહà«àª¯àª¾ હો, તો તમને આ ભૂલ દેખાશે.&lt;/p&gt;
@@ -208,6 +220,8 @@
<translation id="1559572115229829303">&lt;p&gt;<ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> પર ખાનગી કનેકà«àª¶àª¨ સà«àª¥àª¾àªªàª¿àª¤ કરી શકાતà«àª‚ નથી કારણ કે તમારા ડિવાઇસની તારીખ અને સમય (<ph name="DATE_AND_TIME" />) અયોગà«àª¯ છે.&lt;/p&gt;
&lt;p&gt;કૃપા કરીને &lt;strong&gt;સેટિંગ&lt;/strong&gt; અâ€à«…પના &lt;strong&gt;સામાનà«àª¯&lt;/strong&gt; વિભાગમાં તારીખ અને સમય ગોઠવો.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">તમારા àªàª¡àª®àª¿àª¨àª¿àª¸à«àªŸà«àª°à«‡àªŸàª° <ph name="DATE" />ના રોજ <ph name="TIME" /> વાગà«àª¯à«‡ તમારà«àª‚ ડિવાઇસ ફરી શરૂ કરશે</translation>
+<translation id="156703335097561114">àªàª¡à«àª°à«‡àª¸, ઇનà«àªŸàª°àª«à«‡àª¸ કનà«àª«àª¿àª—à«àª¯à«àª°à«‡àª¶àª¨ અને કનેકà«àª¶àª¨ કà«àªµà«‰àª²àª¿àªŸà«€ જેવી નેટવરà«àª•àª¨à«€ માહિતી</translation>
<translation id="1567040042588613346">આ પૉલિસી હેતૠમà«àªœàª¬ કારà«àª¯ કરી રહી છે પરંતૠસમાન મૂલà«àª¯ બીજે કà«àª¯àª¾àª‚ક સેટ કરવામાં આવà«àª¯à«àª‚ છે અને આ પૉલિસી તેની જગà«àª¯àª¾ લે છે.</translation>
<translation id="1569487616857761740">સમાપà«àª¤àª¿ તારીખ દાખલ કરો</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@
<translation id="1583429793053364125">આ વેબપેજ બતાવતી વખતે કંઈક ખોટà«àª‚ થયà«àª‚.</translation>
<translation id="1586541204584340881">તમે કયા àªàª•à«àª¸à«àªŸà«‡àª‚શન ઇનà«àª¸à«àªŸà«‰àª² કરà«àª¯àª¾ છે</translation>
<translation id="1588438908519853928">સામાનà«àª¯</translation>
+<translation id="1589050138437146318">ARCore ઇનà«àª¸à«àªŸà«‰àª² કરીàª?</translation>
<translation id="1592005682883173041">સà«àª¥àª¾àª¨àª¿àª• ડેટા àªàª•à«àª¸à«‡àª¸</translation>
<translation id="1594030484168838125">પસંદ કરો</translation>
<translation id="160851722280695521">Chromeમાં Dino Run ગેમ રમો</translation>
@@ -283,6 +298,7 @@
હેડર દૂષિત છે, જે બà«àª°àª¾àª‰àªàª°àª¨à«‡
<ph name="SITE" /> માટેની તમારી વિનંતી પૂરી કરતા અટકાવે છે. સાઇટ ઑપરેટર ઑરિજિન
પૉલિસીઓનો ઉપયોગ સાઇટ માટે સà«àª°àª•à«àª·àª¾ અને અનà«àª¯ પà«àª°à«‹àªªàª°à«àªŸà«€àª¨à«€ ગોઠવણી કરવા માટે કરી શકે છે.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Chromiumમાં છૂપા મોડ વિશે વધૠજાણો<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">તમારા ખà«àª²à«àª²àª¾ ટૅબà«àª¸ અહીં દેખાય છે</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -410,6 +426,7 @@
<translation id="22081806969704220">ટà«àª°à«‡ 3</translation>
<translation id="2212735316055980242">પૉલિસી મળી નથી</translation>
<translation id="2213606439339815911">પà«àª°àªµàª¿àª·à«àªŸàª¿àª“નà«àª‚ આનયન કરી રહà«àª¯àª¾àª‚ છે...</translation>
+<translation id="2213612003795704869">પેજ પà«àª°àª¿àª¨à«àªŸ થયà«àª‚</translation>
<translation id="2215727959747642672">ફાઇલમાં ફેરફાર કરવો</translation>
<translation id="2218879909401188352">હાલમાં હà«àª®àª²àª¾àª–ોરો <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> પર જોખમકારક àªàªªà«àª²àª¿àª•à«‡àª¶àª¨ ઇનà«àª¸à«àªŸà«‰àª² કરી શકે છે જે તમારા ઉપકરણને નà«àª•àª¸àª¾àª¨ પહોંચાડે છે, તમારા મોબાઇલ બિલમાં છà«àªªàª¾àª¯à«‡àª²àª¾ ચારà«àªœ ઉમેરી શકે છે અથવા તમારી વà«àª¯àª•à«àª¤àª¿àª—ત માહિતી ચોરી શકે છે. <ph name="BEGIN_LEARN_MORE_LINK" />વધૠજાણો<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">ઇનà«àªŸàª°àª¨à«‡àªŸ àªàª•à«àª¸à«‡àª¸ નથી</translation>
@@ -419,6 +436,7 @@
<translation id="2248949050832152960">WebAuthnનો ઉપયોગ કરો</translation>
<translation id="2250931979407627383">ડાબી બાજà«àª કિનારી જોડવી</translation>
<translation id="225207911366869382">આ પૉલિસી માટે આ મૂલà«àª¯àª¨à«‡ નાપસંદ કરેલà«àª‚ છે.</translation>
+<translation id="2256115617011615191">હવે ફરીથી પà«àª°àª¾àª°àª‚ભ કરો</translation>
<translation id="2258928405015593961">ભવિષà«àª¯àª¨à«€ સમાપà«àª¤àª¿ તારીખ દાખલ કરો અને ફરી પà«àª°àª¯àª¾àª¸ કરો</translation>
<translation id="225943865679747347">ભૂલ કોડ: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">HTTP ભૂલ</translation>
@@ -446,6 +464,7 @@
<translation id="2337852623177822836">તમારા વà«àª¯àªµàª¸à«àª¥àª¾àªªàª•à«‡ નિયંતà«àª°àª¿àª¤ કરેલ સેટિંગ</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" />, જોડી કરવા માગે છે</translation>
<translation id="2346319942568447007">તમે કૉપિ કરેલી છબી</translation>
+<translation id="2350796302381711542"><ph name="REPLACED_HANDLER_TITLE" /> ના બદલે <ph name="HANDLER_HOSTNAME" /> ને બધી <ph name="PROTOCOL" /> લિંકà«àª¸ ખોલવાની મંજૂરી આપીàª?</translation>
<translation id="2354001756790975382">અનà«àª¯ બà«àª•àª®àª¾àª°à«àª•</translation>
<translation id="2354430244986887761">Google સલામત બà«àª°àª¾àª‰àªàª¿àª‚ગને તાજેતરમાં <ph name="SITE" /> પર <ph name="BEGIN_LINK" />હાનિકારક àªàªªà«àª²àª¿àª•à«‡àª¶àª¨ મળી<ph name="END_LINK" />.</translation>
<translation id="2355395290879513365">તમે આ સાઇટ પર જોઈ રહà«àª¯àª¾àª‚ છો તે છબીઓને હà«àª®àª²àª¾àª–ોરો જોઈ શકે છે અને તેમાં ફેરફાર કરીને તમને છેતરી શકે છે.</translation>
@@ -471,6 +490,7 @@
<translation id="2413528052993050574">આ સરà«àªµàª° સાબિત કરી શકà«àª¯à«àª‚ નથી કે તે <ph name="DOMAIN" /> છે; તેનà«àª‚ સà«àª°àª•à«àª·àª¾ પà«àª°àª®àª¾àª£àªªàª¤à«àª° રદબાતલ થયà«àª‚ હશે. આ કોઈ ખોટી ગોઠવણીને કારણે થયà«àª‚ હશે અથવા કોઈ હà«àª®àª²àª¾àª–ોર તમારા કનેકà«àª¶àª¨àª¨à«‡ અટકાવી રહà«àª¯à«‹ છે.</translation>
<translation id="2414886740292270097">ઘાટà«àª‚</translation>
<translation id="2430968933669123598">Google àªàª•àª¾àª‰àª¨à«àªŸ મેનેજ કરો, તમારા Google àªàª•àª¾àª‰àª¨à«àªŸàª®àª¾àª‚ તમારી માહિતી, પà«àª°àª¾àª‡àªµàª¸à«€ અને સà«àª°àª•à«àª·àª¾ મેનેજ કરવા માટે, Enter કી દબાવો</translation>
+<translation id="2436186046335138073"><ph name="HANDLER_HOSTNAME" /> ને બધી <ph name="PROTOCOL" /> લિંકà«àª¸ ખોલવાની મંજૂરી આપીàª?</translation>
<translation id="2438874542388153331">જમણી બાજà«àª ચતà«àª·à«àª•à«‹àª£ કાણà«àª‚ પાડો</translation>
<translation id="2450021089947420533">પà«àª°àªµàª¾àª¸</translation>
<translation id="2463739503403862330">ભરો</translation>
@@ -478,6 +498,7 @@
<translation id="2465655957518002998">વિતરણ પદà«àª§àª¤àª¿ પસંદ કરો</translation>
<translation id="2465688316154986572">સà«àªŸà«‡àªªàª² લગાવો</translation>
<translation id="2465914000209955735">Chromeમાં તમે ડાઉનલોડ કરેલી ફાઇલો મેનેજ કરો</translation>
+<translation id="2466004615675155314">વેબ પરથી માહિતી બતાવો</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />નેટવરà«àª• ડાયગà«àª¨à«‹àª¸à«àªŸàª¿àª•à«àª¸ ચલાવી રહà«àª¯àª¾àª‚ છે<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">1-થી-N સà«àª§à«€àª¨à«‹ કà«àª°àª®</translation>
<translation id="2470767536994572628">જà«àª¯àª¾àª°à«‡ તમે ટીકાટિપà«àªªàª£à«€àª®àª¾àª‚ ફેરફાર કરશો, તà«àª¯àª¾àª°à«‡ આ દસà«àª¤àª¾àªµà«‡àªœ 'àªàª• પેજના વà«àª¯à«‚' અને તેના ઑરિજિનલ રોટેશન પર પાછો ફરશે</translation>
@@ -498,6 +519,7 @@
<translation id="2523886232349826891">કારà«àª¡àª¨à«€ માહિતીને માતà«àª° આ ડિવાઇસ પર સાચવવામાં આવી છે</translation>
<translation id="2524461107774643265">વધૠમાહિતી ઉમેરો</translation>
<translation id="2529899080962247600">આ ફીલà«àª¡àª®àª¾àª‚ <ph name="MAX_ITEMS_LIMIT" /> કરતાં વધારે àªàª¨à«àªŸà«àª°à«€ હોવી જોઈઠનહી. વધારાની તમામ àªàª¨à«àªŸà«àª°à«€ અવગણવામાં આવશે.</translation>
+<translation id="2535585790302968248">ખાનગી રીતે બà«àª°àª¾àª‰àª કરવા માટે, નવી છૂપી ટૅબ ખોલો</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{અને અનà«àª¯ 1}one{અને વધૠ#}other{અને વધૠ#}}</translation>
<translation id="2536110899380797252">સરનામà«àª‚ ઉમેરો</translation>
<translation id="2539524384386349900">શોધો</translation>
@@ -523,7 +545,14 @@
<translation id="2597378329261239068">આ દસà«àª¤àª¾àªµà«‡àªœ પાસવરà«àª¡ સà«àª°àª•à«àª·àª¿àª¤ છે. કૃપા કરીને પાસવરà«àª¡ દાખલ કરો.</translation>
<translation id="2609632851001447353">વૈવિધà«àª¯</translation>
<translation id="2610561535971892504">કૉપિ કરવા માટે કà«àª²àª¿àª•</translation>
+<translation id="2617988307566202237">Chrome નીચે આપેલી માહિતી <ph name="BEGIN_EMPHASIS" />સાચવશે નહીં<ph name="END_EMPHASIS" />:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />તમારો બà«àª°àª¾àª‰àªàª¿àª‚ગ ઇતિહાસ
+ <ph name="LIST_ITEM" />કà«àª•à«€ અને સાઇટ ડેટા
+ <ph name="LIST_ITEM" />ફોરà«àª®àª®àª¾àª‚ દાખલ કરેલી માહિતી
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (àªàª¨à«àªµàª²àªª)</translation>
+<translation id="2623663032199728144">તમારી સà«àª•à«àª°à«€àª¨ વિશેની માહિતીનો ઉપયોગ કરવા પરવાનગી માગી શકે છે</translation>
<translation id="2625385379895617796">તમારી ઘડિયાળ આગળ છે</translation>
<translation id="262745152991669301">USB ડિવાઇસ સાથે કનેકà«àªŸ કરવાનà«àª‚ પૂછી શકે છે</translation>
<translation id="2629325967560697240">Chromeની સૌથી ઉચà«àªš લેવલની સà«àª°àª•à«àª·àª¾ મેળવવા માટે, <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />વધારેલી સà«àª°àª•à«àª·àª¾ ચાલૠકરો<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -557,6 +586,7 @@
<translation id="2709516037105925701">સà«àªµàª¤àªƒàª­àª°à«‹</translation>
<translation id="2713444072780614174">શà«àªµà«‡àª¤</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />, Chrome સેટિંગમાં તમારી ચà«àª•àªµàª£à«€àª“ અને કà«àª°à«‡àª¡àª¿àªŸ કારà«àª¡àª¨à«€ માહિતી મેનેજ કરવા માટે Tab પછી Enter દબાવો</translation>
+<translation id="271663710482723385">પૂરà«àª£ સà«àª•à«àª°à«€àª¨àª®àª¾àª‚થી બહાર નીકળવા માટે |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| દબાવો</translation>
<translation id="2721148159707890343">વિનંતી સફળ થઇ</translation>
<translation id="2723669454293168317">Chrome સેટિંગમાં સલામતી માટે તપાસ ચલાવો</translation>
<translation id="2726001110728089263">બાજà«àª¨à«€ ટà«àª°à«‡</translation>
@@ -587,6 +617,7 @@
<translation id="2850739647070081192">આમંતà«àª°àª£ (àªàª¨à«àªµàª²àªª)</translation>
<translation id="2856444702002559011">હà«àª®àª²àª¾àª–ોરો કદાચ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />માંથી તમારી માહિતી (ઉદાહરણ તરીકે, પાસવરà«àª¡, મેસેજ અથવા કà«àª°à«‡àª¡àª¿àªŸ કારà«àª¡) ચોરવાનો પà«àª°àª¯àª¾àª¸ કરી રહà«àª¯àª¾àª‚ હોઈ શકે છે. <ph name="BEGIN_LEARN_MORE_LINK" />વધૠજાણો<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">આ સાઇટ ઘૃણાસà«àªªàª¦ અથવા ભà«àª°àª¾àª®àª• જાહેરાતો બતાવે છે.</translation>
+<translation id="286512204874376891">સંભવિત કપટ સામે તમને સà«àª°àª•à«àª·àª¿àª¤ રાખી શકાય તે માટે, કોઈ વરà«àªšà«àª¯à«àª…લ કારà«àª¡ થકી તમારા વાસà«àª¤àªµàª¿àª• કારà«àª¡àª¨à«€ ઓળખ છà«àªªàª¾àªµàª¾àª¯ છે. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">ફà«àª°à«‡àª¨à«àª¡àª²à«€</translation>
<translation id="2876489322757410363">બાહà«àª¯ àªàªªà«àª²àª¿àª•à«‡àª¶àª¨ મારફતે ચà«àª•àªµàª£à«€ કરવા માટે છૂપો મોડ છોડી રહà«àª¯àª¾àª‚ છીàª. ચાલૠરાખીàª?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />, Chrome સેટિંગમાં Safe Browsing જેવી તમારી બીજી ઘણી સà«àªµàª¿àª§àª¾àª“ મેનેજ કરવા માટે, પહેલાં Tab અને પછી Enter કી દબાવો</translation>
@@ -611,6 +642,7 @@
<translation id="2930577230479659665">પà«àª°àª¤à«àª¯à«‡àª• કૉપિ પછી ટà«àª°àª¿àª® કરો</translation>
<translation id="2932085390869194046">પાસવરà«àª¡ સૂચવો...</translation>
<translation id="2934466151127459956">સરકારી-દસà«àª¤àª¾àªµà«‡àªœ</translation>
+<translation id="2938225289965773019"><ph name="PROTOCOL" /> લિંકà«àª¸ ખોલો</translation>
<translation id="2941952326391522266">આ સરà«àªµàª° સાબિત કરી શકà«àª¯à«àª‚ નથી કે તે <ph name="DOMAIN" /> છે; તેનà«àª‚ સà«àª°àª•à«àª·àª¾ પà«àª°àª®àª¾àª£àªªàª¤à«àª° <ph name="DOMAIN2" /> નà«àª‚ છે. આ કોઈ ખોટી ગોઠવણીને કારણે થયà«àª‚ હશે અથવા કોઈ હà«àª®àª²àª¾àª–ોર તમારા કનેકà«àª¶àª¨àª¨à«‡ અટકાવી રહà«àª¯à«‹ છે.</translation>
<translation id="2943895734390379394">અપલોડ કરાયાનો સમય:</translation>
<translation id="2948083400971632585">તમે સેટિંગ પેજમાંથી કનેકà«àª¶àª¨ માટે ગોઠવવામાં આવેલ કોઈપણ પà«àª°à«‹àª•à«àª¸à«€àª“ બંધ કરી શકો છો.</translation>
@@ -643,6 +675,7 @@
<translation id="3037605927509011580">અરર કંઇક ભà«àª² થઇ!</translation>
<translation id="3041612393474885105">પà«àª°àª®àª¾àª£àªªàª¤à«àª° માહિતી</translation>
<translation id="3044034790304486808">તમારી શોધ ફરી શરૂ કરો</translation>
+<translation id="305162504811187366">ટાઇમસà«àªŸà«‡àª®à«àªª, હોસà«àªŸ અને કà«àª²àª¾àª¯àª¨à«àªŸ સતà«àª° ids સહિત Chrome રીમોટ ડેસà«àª•àªŸà«‰àªªàª¨à«‹ ઇતિહાસ</translation>
<translation id="3060227939791841287">C9 (àªàª¨à«àªµàª²àªª)</translation>
<translation id="3061707000357573562">પૅચ સેવા</translation>
<translation id="306573536155379004">ગેમ શરૂ થઈ ગઈ છે.</translation>
@@ -683,6 +716,7 @@
<translation id="3197136577151645743">તમે સકà«àª°àª¿àª¯àªªàª£à«‡ તમારા ડિવાઇસનો ઉપયોગ કà«àª¯àª¾àª°à«‡ કરો છો, તે જાણકારી મેળવવા માટે પૂછી શકે છે</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />, ટૅબ દબાવો અને પછી Chrome સેટિંગમાં તમે જે માહિતી સિંક કરવા ઇચà«àª›àª¤àª¾ હો, તે મેનેજ કરવા માટે Enter કી દબાવો</translation>
<translation id="320323717674993345">ચà«àª•àªµàª£à«€ રદ કરો</translation>
+<translation id="3203366800380907218">વેબ પરથી</translation>
<translation id="3207960819495026254">બà«àª•àª®àª¾àª°à«àª• કરેલ</translation>
<translation id="3209034400446768650">પેજ કદાચ નાણાં વસૂલી શકે છે</translation>
<translation id="3212581601480735796"><ph name="HOSTNAME" /> પરની તમારી પà«àª°àªµà«ƒàª¤à«àª¤àª¿àª¨à«àª‚ નિરીકà«àª·àª£ કરવામાં આવી રહà«àª¯à«àª‚ છે</translation>
@@ -699,10 +733,12 @@
<translation id="3234666976984236645">હંમેશાં આ સાઇટ પરનà«àª‚ મહતà«àª¤à«àªµàª¨à«àª‚ કનà«àªŸà«‡àª¨à«àªŸ શોધો</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />, તમારા બà«àª°àª¾àª‰àªàª°àª¨à«‹ દેખાવ કસà«àªŸàª®àª¾àª‡àª કરવા માટે, પહેલાં Tab અને પછી Enter કી દબાવો</translation>
<translation id="3240791268468473923">ચà«àª•àªµàª£à«€àª¨à«€ સà«àª°àª•à«àª·àª¿àª¤ લૉગ ઇન વિગત, મેળ ખાતી લૉગ ઇન વિગતની કોઈપણ શીટ ખોલવામાં આવી નથી</translation>
+<translation id="324180406144491771">“<ph name="HOST_NAME" />â€àª¨à«€ લિંક બà«àª²à«‰àª• કરેલી છે</translation>
<translation id="3249845759089040423">ગà«àª°à«‚વી</translation>
<translation id="3252266817569339921">ફà«àª°à«‡àª¨à«àªš</translation>
<translation id="3257954757204451555">આ માહિતીની પાછળ કોણ છે?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />, Google Calendarમાં àªàª¡àªªàª¥à«€ કોઈ નવી ઇવેનà«àªŸ બનાવવા માટે, પહેલાં Tab અને પછી Enter કી દબાવો</translation>
+<translation id="3261488570342242926">વરà«àªšà«àª¯à«àª…લ કારà«àª¡ વિશે જાણો</translation>
<translation id="3264837738038045344">Chrome સેટિંગ મેનેજ કરવા માટેનà«àª‚ બટન, તમારા Chrome સેટિંગની મà«àª²àª¾àª•àª¾àª¤ લેવા માટે Enter કી દબાવો</translation>
<translation id="3266793032086590337">મૂલà«àª¯ (વિરોધાભાસ)</translation>
<translation id="3268451620468152448">ઓપન ટેબà«àª¸</translation>
@@ -716,6 +752,7 @@
<translation id="3288238092761586174">તમારી ચà«àª•àªµàª£à«€àª¨à«€ ચકાસણી કરવા માટે <ph name="URL" /> દà«àªµàª¾àª°àª¾ વધારાના પગલાં લેવા જરૂરી હોઈ શકે છે</translation>
<translation id="3293642807462928945"><ph name="POLICY_NAME" /> પૉલિસી વિશે વધૠજાણો</translation>
<translation id="3295444047715739395">Chrome સેટિંગમાં તમારા પાસવરà«àª¡ જà«àª“ અને તેને મેનેજ કરો</translation>
+<translation id="3303795387212510132">શà«àª‚ àªàªªàª¨à«‡ <ph name="PROTOCOL_SCHEME" /> લિંક ખોલવાની મંજૂરી આપીàª?</translation>
<translation id="3303855915957856445">કોઈ શોધ પરિણામો મળà«àª¯àª¾àª‚ નથી</translation>
<translation id="3304073249511302126">બà«àª²à«‚ટૂથ સà«àª•à«…નિંગ</translation>
<translation id="3308006649705061278">ઑરà«àª—ેનાઇàªà«‡àª¶àª¨àª² યૂનિટ (OU)</translation>
@@ -729,11 +766,6 @@
<translation id="3345782426586609320">આંખો</translation>
<translation id="3355823806454867987">પà«àª°à«‰àª•à«àª¸à«€ સેટિંગ બદલો...</translation>
<translation id="3360103848165129075">ચà«àª•àªµàª£à«€ માટેની હૅનà«àª¡àª²àª° શીટ</translation>
-<translation id="3361596688432910856">Chrome નિમà«àª¨àª²àª¿àª–િત માહિતી <ph name="BEGIN_EMPHASIS" />સાચવશે નહીં<ph name="END_EMPHASIS" />:
- <ph name="BEGIN_LIST" /> <ph name="LIST_ITEM" />તમારો બà«àª°àª¾àª‰àªàª¿àª‚ગ ઇતિહાસ
- <ph name="LIST_ITEM" />કà«àª•à«€ અને સાઇટ ડેટા
- <ph name="LIST_ITEM" />ફોરà«àª®àª®àª¾àª‚ દાખલ કરેલી માહિતી
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">આ પૉલિસી, ટાળેલી <ph name="OLD_POLICY" /> પૉલિસીમાંથી ઑટોમૅટિક રીતે કૉપિ કરી હતી. તેના બદલે તમારે આ પૉલિસીનો ઉપયોગ કરવો જોઈàª.</translation>
<translation id="3364869320075768271"><ph name="URL" /> વરà«àªšà«àª¯à«àª…લ રિયાલિટી ડિવાઇસ અને ડેટાનો ઉપયોગ કરવા માગે છે</translation>
<translation id="3366477098757335611">કારà«àª¡ જà«àª“</translation>
@@ -816,7 +848,6 @@
<translation id="3587738293690942763">મધà«àª¯</translation>
<translation id="3592413004129370115">ઇટાલિયન (àªàª¨à«àªµàª²àªª)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{તમે કોઈપણ સમયે તમારà«àª‚ ગà«àª°à«‚પ રીસેટ કરી શકો છો. નવા ગà«àª°à«‚પમાં જોડાવામાં આશરે àªàª• દિવસ લાગે છે.}=1{તમે કોઈપણ સમયે તમારà«àª‚ ગà«àª°à«‚પ રીસેટ કરી શકો છો. નવા ગà«àª°à«‚પમાં જોડાવામાં આશરે àªàª• દિવસ લાગે છે.}one{તમે કોઈપણ સમયે તમારà«àª‚ ગà«àª°à«‚પ રીસેટ કરી શકો છો. નવા ગà«àª°à«‚પમાં જોડાવામાં આશરે {NUM_DAYS} દિવસ લાગે છે.}other{તમે કોઈપણ સમયે તમારà«àª‚ ગà«àª°à«‚પ રીસેટ કરી શકો છો. નવા ગà«àª°à«‚પમાં જોડાવામાં આશરે {NUM_DAYS} દિવસ લાગે છે.}}</translation>
-<translation id="3596012367874587041">àªàªª સેટિંગ</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">તમારા વà«àª¯àªµàª¸à«àª¥àª¾àªªàª• દà«àªµàª¾àª°àª¾ બà«àª²à«‰àª• કરેલી àªàªªà«àª²àª¿àª•à«‡àª¶àª¨</translation>
<translation id="3608932978122581043">ફીડ ઓરિàªàª¨à«àªŸà«‡àª¶àª¨</translation>
@@ -859,6 +890,7 @@
<translation id="370972442370243704">પà«àª°àªµàª¾àª¸ ચાલૠકરો</translation>
<translation id="3711895659073496551">સસà«àªªà«‡àª¨à«àª¡ કરો</translation>
<translation id="3712624925041724820">લાઇસેંસીસ પૂરà«àª£</translation>
+<translation id="3714633008798122362">વેબ કૅલેનà«àª¡àª°</translation>
<translation id="3714780639079136834">મોબાઇલ ડેટા અથવા વાઇ-ફાઇ ચાલૠકરીને</translation>
<translation id="3715597595485130451">વાઇ-ફાઇથી કનેકà«àªŸ કરો</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />પà«àª°à«‰àª•à«àª¸à«€, ફાયરવૉલ અને DNS ગોઠવણી ચેક કરવાનો પà«àª°àª¯àª¾àª¸ કરો<ph name="END_LINK" /></translation>
@@ -920,6 +952,7 @@
<translation id="3906954721959377182">ટૅબà«àª²à«‡àªŸ</translation>
<translation id="3909477809443608991"><ph name="URL" /> સà«àª°àª•à«àª·àª¿àª¤ કનà«àªŸà«‡àª¨à«àªŸ ચલાવવા માગે છે. Google દà«àªµàª¾àª°àª¾ તમારા ડિવાઇસની ઓળખ ચકાસવામાં આવશે અને તે આ સાઇટ દà«àªµàª¾àª°àª¾ àªàª•à«àª¸à«‡àª¸ કરવામાં આવી શકે છે.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">નકારો</translation>
<translation id="3939773374150895049">CVCને બદલે WebAuthnનો ઉપયોગ કરી�</translation>
<translation id="3946209740501886391">આ સાઇટ પર હંમેશાં પૂછો</translation>
<translation id="3947595700203588284">MIDI ડિવાઇસ સાથે કનેકà«àªŸ કરવાનà«àª‚ પૂછી શકે છે</translation>
@@ -941,6 +974,7 @@
<translation id="3990250421422698716">બહાર નીકળેલા ભાગને અંદર દબાવો</translation>
<translation id="3996311196211510766">આ સાઇટ <ph name="ORIGIN" /> દà«àªµàª¾àª°àª¾ વિનંતી કરવામાં આવી છે કે ઑરિજિન પૉલિસી તેની
બધી વિનંતી પર લાગૠથાય છે, પણ હાલમાં આ પૉલિસી લાગૠકરી શકાતી નથી.</translation>
+<translation id="4009243425692662128">તમે પà«àª°àª¿àª¨à«àªŸ કરશો તે પેજનà«àª‚ કનà«àªŸà«‡àª¨à«àªŸ વિશà«àª²à«‡àª·àª£ માટે, Google Cloud કે તà«àª°à«€àªœàª¾ પકà«àª·àª¨à«‡ મોકલવામાં આવશે. ઉદાહરણ તરીકે, તેને સંવેદનશીલ વà«àª¯àª•à«àª¤àª¿àª—ત ડેટા માટે સà«àª•à«…ન કરવામાં આવી શકે છે.</translation>
<translation id="4010758435855888356">શà«àª‚ સà«àªŸà«‹àª°à«‡àªœàª¨àª¾ àªàª•à«àª¸à«‡àª¸àª¨à«€ મંજૂરી આપીàª?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{{COUNT} પેજ ધરાવતો PDF દસà«àª¤àª¾àªµà«‡àªœ}one{{COUNT} પેજ ધરાવતો PDF દસà«àª¤àª¾àªµà«‡àªœ}other{{COUNT} પેજ ધરાવતો PDF દસà«àª¤àª¾àªµà«‡àªœ}}</translation>
<translation id="4023431997072828269">અસà«àª°àª•à«àª·àª¿àª¤ કનેકà«àª¶àª¨àª¨à«‹ ઉપયોગ કરીને આ ફોરà«àª® સબમિટ કરવામાં આવી રહà«àª¯à«àª‚ હોવાથી, તમારી માહિતી અનà«àª¯ લોકોને દેખાઈ શકે છે.</translation>
@@ -1035,6 +1069,7 @@
<translation id="4250680216510889253">નહીં</translation>
<translation id="4253168017788158739">નોંધ</translation>
<translation id="425582637250725228">તમે કરેલા ફેરફારો સાચવવામાં આવà«àª¯àª¾àª‚ ન હોઇ શકે.</translation>
+<translation id="425869179292622354">શà«àª‚ કોઈ વરà«àªšà«àª¯à«àª…લ કારà«àª¡ વડે તેને વધૠસà«àª°àª•à«àª·àª¿àª¤ કરવા માગો છો?</translation>
<translation id="4258748452823770588">ખરાબ હસà«àª¤àª¾àª•à«àª·àª°</translation>
<translation id="4261046003697461417">સંરકà«àª·àª¿àª¤ દસà«àª¤àª¾àªµà«‡àªœ àªàª¨à«‹àªŸà«‡àªŸ કરી શકાતા નથી</translation>
<translation id="4265872034478892965">તમારા વà«àª¯àªµàª¸à«àª¥àª¾àªªàª• દà«àªµàª¾àª°àª¾ મંજૂર</translation>
@@ -1097,6 +1132,7 @@
<translation id="4434045419905280838">પૉપ-અપ અને રીડાયરેકà«àªŸ</translation>
<translation id="4435702339979719576">પોસà«àªŸàª•àª¾àª°à«àª¡)</translation>
<translation id="443673843213245140">પà«àª°à«‰àª•à«àª¸à«€àª¨à«‹ ઉપયોગ બંધ કરેલો છે પણ àªàª• સà«àªªàª·à«àªŸ પà«àª°à«‰àª•à«àª¸à«€ ગોઠવણીનો ઉલà«àª²à«‡àª– કરેલો છે.</translation>
+<translation id="4441832193888514600">અવગણવામાં આવà«àª¯à«àª‚ કારણ કે પૉલિસી માતà«àª° કà«àª²àª¾àª‰àª¡ વપરાશકરà«àª¤àª¾àª¨à«€ પૉલિસી તરીકે જ સેટ કરવામાં આવી શકે છે.</translation>
<translation id="4450893287417543264">ફરી બતાવશો નહીં</translation>
<translation id="4451135742916150903">HID ડિવાઇસ સાથે કનેકà«àªŸ કરવાનà«àª‚ પૂછી શકે છે</translation>
<translation id="4452328064229197696">તમે હાલમાં જ ઉપયોગમાં લીધેલો પાસવરà«àª¡ ડેટા ઉલà«àª²àª‚ઘનમાં જોવા મળà«àª¯à«‹ છે. તમારા àªàª•àª¾àª‰àª¨à«àªŸ સà«àª°àª•à«àª·àª¿àª¤ રાખવા માટે, Google પાસવરà«àª¡ મેનેજર તમારા સાચવેલા પાસવરà«àª¡àª¨à«‡ ચેક કરવાનો સà«àªàª¾àªµ આપે છે.</translation>
@@ -1152,6 +1188,7 @@
<translation id="4628948037717959914">ફોટો</translation>
<translation id="4631649115723685955">કૅશબૅક લિંક કરà«àª¯à«àª‚ છે</translation>
<translation id="4636930964841734540">માહિતી</translation>
+<translation id="4638670630777875591">Chromiumમાં છૂપો મોડ</translation>
<translation id="464342062220857295">શોધ સà«àªµàª¿àª§àª¾àª“</translation>
<translation id="4644670975240021822">ઉલà«àªŸàª¾ કà«àª°àª®àª®àª¾àª‚ નીચે તરફ</translation>
<translation id="4646534391647090355">મને હવે ડાઉનલોડ હોમ પર લઈ જાઓ</translation>
@@ -1172,6 +1209,7 @@
<translation id="4708268264240856090">તમારà«àª‚ કનેકà«àª¶àª¨ અવરોધાયà«àª‚ હતà«àª‚</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Windows નેટવરà«àª• ડાયગà«àª¨à«‹àª¸à«àªŸàª¿àª•à«àª¸ ચલાવી રહà«àª¯àª¾àª‚ છે<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426"><ph name="USERNAME" /> માટેનો પાસવરà«àª¡</translation>
<translation id="4724144314178270921">તમારા કà«àª²àª¿àªªàª¬à«‹àª°à«àª¡ પરની ટેકà«àª¸à«àªŸ અને છબીઓ જોવાનà«àª‚ પૂછી શકે છે</translation>
<translation id="4726672564094551039">પૉલિસીઓ ફરીથી લોડ કરો</translation>
<translation id="4728558894243024398">પà«àª²à«‡àªŸàª«à«‹àª°à«àª®</translation>
@@ -1193,6 +1231,7 @@
<translation id="4757993714154412917">હમણાં જ કોઈ છેતરામણી સાઇટ પર તમે તમારો પાસવરà«àª¡ દાખલ કરà«àª¯à«‹ છે. તમારા àªàª•àª¾àª‰àª¨à«àªŸ સà«àª°àª•à«àª·àª¿àª¤ રાખવા માટે, Chromium તમારા સાચવેલા પાસવરà«àª¡ હમણાં જ ચેક કરવાનો સà«àªàª¾àªµ આપે છે.</translation>
<translation id="4758311279753947758">સંપરà«àª• માહિતી ઉમેરો</translation>
<translation id="4761104368405085019">તમારા માઇકà«àª°à«‹àª«à«‹àª¨àª¨à«‹ ઉપયોગ કરો</translation>
+<translation id="4761869838909035636">Chromeની સલામતી માટે તપાસ ચલાવો</translation>
<translation id="4764776831041365478"><ph name="URL" /> પરનાં વેબપેજ અસà«àª¥àª¾àª¯à«€ ધોરણે બંધ હોઈ શકે છે અથવા તે કાયમ માટે નવા વેબ àªàª¡à«àª°à«‡àª¸ પર ખસેડવામાં આવà«àª¯àª¾ હોઈ શકે છે.</translation>
<translation id="4766713847338118463">નીચે બે સà«àªŸà«‡àªªàª² લગાવો</translation>
<translation id="4771973620359291008">કોઈ અજà«àªžàª¾àª¤ ભૂલ આવી.</translation>
@@ -1213,12 +1252,6 @@
<translation id="4819347708020428563">ટીકાટિપà«àªªàª£à«€àª®àª¾àª‚ ફેરફાર કરીને ડિફૉલà«àªŸ વà«àª¯à«‚ પસંદ કરીàª?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />, Google Sheetsમાં àªàª¡àªªàª¥à«€ કોઈ નવી શીટ બનાવવા માટે, પહેલાં Tab પછી Enter કી દબાવો</translation>
<translation id="4825507807291741242">શકà«àª¤àª¿àª¶àª¾àª³à«€</translation>
-<translation id="4827402517081186284">છૂપા મોડથી તમે ઑનલાઇન અદà«àª°àª¶à«àª¯ બની જતા નથી:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />સાઇટ તમારી મà«àª²àª¾àª•àª¾àª¤ વિશે જાણી શકે છે<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />નોકરીદાતા કે સà«àª•à«‚લ, બà«àª°àª¾àª‰àªàª¿àª‚ગ પà«àª°àªµà«ƒàª¤à«àª¤àª¿ ટà«àª°à«…ક કરી શકે છે<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />ઇનà«àªŸàª°àª¨à«‡àªŸ સેવા આપનાર કંપની વેબ ટà«àª°àª¾àª«àª¿àª• મૉનિટર કરી શકે છે<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">ચેતવણીઓ ચાલૠકરો</translation>
<translation id="4838327282952368871">સà«àªµàªªà«àª¨àª¶à«€àª²</translation>
<translation id="4840250757394056958">તમારો Chrome ઇતિહાસ જà«àª“</translation>
@@ -1230,12 +1263,12 @@
<translation id="4854362297993841467">વિતરણની આ પદà«àª§àª¤àª¿ ઉપલબà«àª§ નથી. કોઈ ભિનà«àª¨ પદà«àª§àª¤àª¿ અજમાવો.</translation>
<translation id="4854853140771946034">Google Keepમાં àªàª¡àªªàª¥à«€ કોઈ નવી નોંધ બનાવો</translation>
<translation id="485902285759009870">કોડ ચકાસી રહà«àª¯àª¾àª‚ છીàª...</translation>
+<translation id="4866506163384898554">તમારà«àª‚ કરà«àª¸àª° બતાવવા |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| દબાવો</translation>
<translation id="4876188919622883022">સરળ દૃશà«àª¯</translation>
<translation id="4876305945144899064">કોઈ વપરાશકરà«àª¤àª¾ નામ નથી</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{àªàª•à«‡àª¯ નહીં}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}one{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831"><ph name="TEXT" /> શોધ</translation>
<translation id="4879491255372875719">ઑટોમૅટિક (ડિફૉલà«àªŸ)</translation>
-<translation id="4879725228911483934">ખોલો અને તમારી સà«àª•à«àª°à«€àª¨ પર વિંડોનà«àª‚ સà«àª¥àª¾àª¨ નિયોજન કરો</translation>
<translation id="4880827082731008257">શોધ ઇતિહાસ</translation>
<translation id="4881695831933465202">ખોલો</translation>
<translation id="4885256590493466218">ચેકઆઉટ કરતી વખતે <ph name="CARD_DETAIL" /> વડે ચà«àª•àªµàª£à«€ કરો</translation>
@@ -1244,6 +1277,7 @@
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">નવમો રોલ</translation>
<translation id="4901778704868714008">સાચવો...</translation>
+<translation id="4905659621780993806">તમારા àªàª¡àª®àª¿àª¨àª¿àª¸à«àªŸà«àª°à«‡àªŸàª° <ph name="DATE" />ના રોજ <ph name="TIME" /> વાગà«àª¯à«‡ ઑટોમૅટિક રીતે તમારà«àª‚ ડિવાઇસ ફરી શરૂ કરશે. તમારà«àª‚ ડિવાઇસ ફરી શરૂ થાય તે પહેલાં ખà«àª²à«€ હોય àªàªµà«€ કોઈપણ આઇટમ સાચવો.</translation>
<translation id="4913987521957242411">ઉપર ડાબી બાજà«àª કાણà«àª‚ પાડો</translation>
<translation id="4918221908152712722"><ph name="APP_NAME" />ને ઇનà«àª¸à«àªŸà«‰àª² કરો (કોઈ ડાઉનલોડ આવશà«àª¯àª• નથી)</translation>
<translation id="4923459931733593730">ચà«àª•àªµàª£à«€</translation>
@@ -1252,6 +1286,7 @@
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, શોધવા માટે Tab અને પછી Enter દબાવો</translation>
<translation id="4930153903256238152">વિશાળ કà«àª·àª®àª¤àª¾</translation>
+<translation id="4940163644868678279">Chromeમાં છૂપો મોડ</translation>
<translation id="4943872375798546930">પરિણામો નથી</translation>
<translation id="4950898438188848926">ટૅબ, સà«àªµàª¿àªš બટન, ખà«àª²à«àª²àª¾ ટૅબ, <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /> પર સà«àªµàª¿àªš કરવા માટે Enter દબાવો</translation>
<translation id="495170559598752135">કà«àª°àª¿àª¯àª¾àª“</translation>
@@ -1261,6 +1296,7 @@
<translation id="4968522289500246572">આ àªàªª મોબાઇલ માટે બનાવવામાં આવી છે અને કદાચ તે યોગà«àª¯ રીતે કદ બદલી શકશે નહીં. àªàªªàª®àª¾àª‚ સમસà«àª¯àª¾àª“ આવી શકે છે અથવા તે ફરી શરૂ થઈ શકે છે.</translation>
<translation id="4969341057194253438">રેકોરà«àª¡àª¿àª‚ગ ડિલીટ કરો</translation>
<translation id="4973922308112707173">ઉપરની બાજà«àª બે કાણાં પાડો</translation>
+<translation id="4976702386844183910">છેલà«àª²à«‡ <ph name="DATE" />ના રોજ મà«àª²àª¾àª•àª¾àª¤ લીધી</translation>
<translation id="4984088539114770594">માઇકà«àª°à«‹àª«à«‹àª¨àª¨à«‹ ઉપયોગ કરીàª?</translation>
<translation id="4984339528288761049">Prc5 (àªàª¨à«àªµàª²àªª)</translation>
<translation id="4989163558385430922">બધા જà«àª“</translation>
@@ -1322,6 +1358,7 @@
<translation id="5138227688689900538">ઓછà«àª‚ બતાવો</translation>
<translation id="5145883236150621069">પૉલિસી પà«àª°àª¤àª¿àª•à«àª°àª¿àª¯àª¾àª®àª¾àª‚ ભૂલ કોડ હાજર</translation>
<translation id="5146995429444047494"><ph name="ORIGIN" /> માટેના નોટિફિકેશન બà«àª²à«‰àª• કરà«àª¯àª¾ છે</translation>
+<translation id="514704532284964975">તમે તમારા ફોન વડે NFC ડિવાઇસ પર જે માહિતી ટૅપ કરો છો તેને <ph name="URL" /> જોવા અને બદલવા માગે છે</translation>
<translation id="5148809049217731050">ઉપર તરફ</translation>
<translation id="515292512908731282">C4 (àªàª¨à«àªµàª²àªª)</translation>
<translation id="5158275234811857234">કવર</translation>
@@ -1346,6 +1383,7 @@
<translation id="5215116848420601511">Google Payનો ઉપયોગ કરતી ચà«àª•àªµàª£à«€ પદà«àª§àª¤àª¿àª“ અને àªàª¡à«àª°à«‡àª¸</translation>
<translation id="5215363486134917902">ફોલિયો-Sp</translation>
<translation id="521659676233207110">ટà«àª°à«‡ 13</translation>
+<translation id="5216942107514965959">છેલà«àª²à«‡ આજે મà«àª²àª¾àª•àª¾àª¤ લીધી</translation>
<translation id="5222812217790122047">ઇમેઇલ આવશà«àª¯àª• છે</translation>
<translation id="5230733896359313003">વિતરણ માટેનà«àª‚ સરનામà«àª‚</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1366,7 +1404,6 @@
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">દસà«àª¤àª¾àªµà«‡àªœàª¨à«€ પà«àª°à«‹àªªàª°à«àªŸà«€</translation>
<translation id="528468243742722775">સમાપà«àª¤</translation>
-<translation id="5284909709419567258">નેટવરà«àª• àªàª¡à«àª°à«‡àª¸</translation>
<translation id="5285570108065881030">બધા સાચવેલા પાસવરà«àª¡ બતાવો</translation>
<translation id="5287240709317226393">કà«àª•à«€ બતાવો</translation>
<translation id="5287456746628258573">આ સાઇટ હજી પણ જૂના સà«àª°àª•à«àª·àª¾ કનà«àª«àª¿àª—à«àª¯à«àª°à«‡àª¶àª¨àª¨à«‹ ઉપયોગ કરે છે, જેને લીધે તમારી માહિતી (ઉદાહરણ તરીકે, પાસવરà«àª¡ અથવા કà«àª°à«‡àª¡àª¿àªŸ કારà«àª¡ નંબર) જà«àª¯àª¾àª°à«‡ આ સાઇટને મોકલવામાં આવે, તà«àª¯àª¾àª°à«‡ તે જોખમમાં આવી શકે છે.</translation>
@@ -1450,6 +1487,7 @@
<translation id="5556459405103347317">ફરીથી લોડ કરો</translation>
<translation id="5560088892362098740">સમાપà«àª¤àª¿ તારીખ</translation>
<translation id="55635442646131152">દસà«àª¤àª¾àªµà«‡àªœ આઉટલાઇન</translation>
+<translation id="5565613213060953222">છૂપી ટૅબ ખોલો</translation>
<translation id="5565735124758917034">સકà«àª°àª¿àª¯</translation>
<translation id="5570825185877910964">àªàª•àª¾àª‰àª¨à«àªŸ સà«àª°àª•à«àª·àª¿àª¤ કરો</translation>
<translation id="5571083550517324815">આ સરનામેથી પિકઅપ કરી શકતા નથી. કોઈ ભિનà«àª¨ સરનામà«àª‚ પસંદ કરો.</translation>
@@ -1532,6 +1570,7 @@
<translation id="5869522115854928033">સાચવેલા પાસવરà«àª¡à«àª¸</translation>
<translation id="5873013647450402046">તમારી બેંક કનà«àª«àª°à«àª® કરવા માગે છે કે આ તમે જ છો.</translation>
<translation id="5887400589839399685">કારà«àª¡ સાચવà«àª¯à«àª‚</translation>
+<translation id="5887687176710214216">છેલà«àª²à«‡ કાલે મà«àª²àª¾àª•àª¾àª¤ લીધી</translation>
<translation id="5895138241574237353">પà«àª¨àªƒàªªà«àª°àª¾àª°àª‚ભ કરો</translation>
<translation id="5895187275912066135">ના રોજ રજૂ કરાયà«àª‚</translation>
<translation id="5901630391730855834">પીળો</translation>
@@ -1545,6 +1584,7 @@
<translation id="5921639886840618607">Google àªàª•àª¾àª‰àª¨à«àªŸàª®àª¾àª‚ કારà«àª¡ સાચવીàª?</translation>
<translation id="5922853866070715753">લગભગ થઈ ગયà«àª‚</translation>
<translation id="5932224571077948991">સાઇટ ઘૃણાસà«àªªàª¦ અથવા ભà«àª°àª¾àª®àª• જાહેરાતો બતાવે છે</translation>
+<translation id="5938153366081463283">વરà«àªšà«àª¯à«àª…લ કારà«àª¡ ઉમેરો</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347"><ph name="SITE_NAME" /> ખોલી રહà«àª¯àª¾àª‚ છે…</translation>
<translation id="5951495562196540101">ઉપભોકà«àª¤àª¾ àªàª•àª¾àª‰àª¨à«àªŸ સાથે નોંધણી કરાવી શકાતી નથી (પૅકેજમાં લાઇસનà«àª¸ ઉપલબà«àª§ છે).</translation>
@@ -1609,6 +1649,7 @@
<translation id="6120179357481664955">તમારà«àª‚ UPI ID યાદ રાખીàª?</translation>
<translation id="6124432979022149706">Chrome àªàª¨à«àªŸàª°àªªà«àª°àª¾àª‡àª કનેકà«àªŸàª°</translation>
<translation id="6127379762771434464">આઇટમ દૂર કરી</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Chromeમાં છૂપા મોડ વિશે વધૠજાણો<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">કોઈપણ કેબલà«àª¸ તપાસો અને તમે કદાચ ઉપયોગમાં લઇ રહà«àª¯àª¾àª‚ હોય તેવા કોઇપણ રાઉટરà«àª¸, મૉડેમà«àª¸Â 
અથવા અનà«àª¯ નેટવરà«àª• ઉપકરણોને રીબૂટ કરો.</translation>
<translation id="614940544461990577">પà«àª°àª¯àª¾àª¸ કરો:</translation>
@@ -1621,7 +1662,6 @@
<translation id="6169916984152623906">હવે તમે ખાનગીમાં બà«àª°àª¾àª‰àª કરી શકો છો અને અનà«àª¯ લોકો જે આ ડિવાઇસનો ઉપયોગ કરે છે તે પણ તમારી પà«àª°àªµà«ƒàª¤à«àª¤àª¿ જોઈ શકશે નહીં. જોકે ડાઉનલોડ અને બà«àª•àª®àª¾àª°à«àª• સાચવવામાં આવશે.</translation>
<translation id="6177128806592000436">આ સાઇટ પરનà«àª‚ તમારà«àª‚ કનેકà«àª¶àª¨ સà«àª°àª•à«àª·àª¿àª¤ નથી</translation>
<translation id="6180316780098470077">ફરી પà«àª°àª¯àª¾àª¸ કરવા માટેનો અંતરાલ</translation>
-<translation id="619448280891863779">વિનà«àª¡à«‹ ખોલીને તમારી સà«àª•à«àª°à«€àª¨ પર મૂકવા માટે પૂછી શકે છે</translation>
<translation id="6196640612572343990">તà«àª°à«€àªœàª¾ પકà«àª·àª¨à«€ કà«àª•à«€àª¨à«‡ બà«àª²à«‰àª• કરો</translation>
<translation id="6203231073485539293">તમારà«àª‚ ઇનà«àªŸàª°àª¨à«‡àªŸ કનેકà«àª¶àª¨ તપાસો</translation>
<translation id="6218753634732582820">Chromium માંથી સરનામà«àª‚ દૂર કરીàª?</translation>
@@ -1644,7 +1684,7 @@
<translation id="6272383483618007430">Google અપડેટ</translation>
<translation id="6276112860590028508">તમારી વાંચન સૂચિના પેજ અહીં દેખાશે</translation>
<translation id="627746635834430766">આગલી વખતે વધૠàªàª¡àªªàª¥à«€ ચà«àª•àªµàª£à«€ કરવા માટે, તમારા કારà«àª¡ અને બિલિંગ સરનામાંને તમારા Google àªàª•àª¾àª‰àª¨à«àªŸàª®àª¾àª‚ સાચવો.</translation>
-<translation id="6279098320682980337">શà«àª‚ તમારો વરà«àªšà«àª¯à«àª…લ કારà«àª¡ નંબર ભરવામાં આવà«àª¯à«‹ નથી? કૉપિ કરવા માટે, કારà«àª¡àª¨à«€ વિગતો પર કà«àª²àª¿àª• કરો</translation>
+<translation id="6279183038361895380">તમારા કરà«àª¸àª°àª¨à«‡ બતાવવા માટે |<ph name="ACCELERATOR" />| દબાવો</translation>
<translation id="6280223929691119688">આ સરનામે વિતરણ કરી શકતા નથી. કોઈ ભિનà«àª¨ સરનામà«àª‚ પસંદ કરો.</translation>
<translation id="6282194474023008486">પોસà«àªŸàª² કોડ</translation>
<translation id="6285507000506177184">Chromeમાં ડાઉનલોડ મેનેજ કરવા માટેનà«àª‚ બટન, Chromeમાં તમે ડાઉનલોડ કરેલી ફાઇલો મેનેજ કરવા માટે Enter કી દબાવો</translation>
@@ -1652,6 +1692,7 @@
<translation id="6290238015253830360">તમારા સૂચવેલા લેખ અહીં દેખાય છે</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{તમારà«àª‚ ડિવાઇસ હમણાં જ ફરી શરૂ થશે}=1{તમારà«àª‚ ડિવાઇસ 1 સેકનà«àª¡àª®àª¾àª‚ ફરી શરૂ થશે}one{તમારà«àª‚ ડિવાઇસ # સેકનà«àª¡àª®àª¾àª‚ ફરી શરૂ થશે}other{તમારà«àª‚ ડિવાઇસ # સેકનà«àª¡àª®àª¾àª‚ ફરી શરૂ થશે}}</translation>
<translation id="6302269476990306341">Chromeમાં Google Assistant રોકાઈ રહà«àª¯à«àª‚ છે</translation>
<translation id="6305205051461490394"><ph name="URL" />, પહોંચવા યોગà«àª¯ નથી.</translation>
<translation id="6312113039770857350">વેબપેજ ઉપલબà«àª§ નથી</translation>
@@ -1725,6 +1766,7 @@
<translation id="6529602333819889595">&amp;ફરી કરો ડિલીટ કરો</translation>
<translation id="6545864417968258051">બà«àª²à«‚ટૂથ સà«àª•à«…નિંગ</translation>
<translation id="6547208576736763147">ડાબી બાજà«àª બે ચતà«àª·à«àª•à«‹àª£ કાણાં પાડો</translation>
+<translation id="6554732001434021288">છેલà«àª²à«‡ <ph name="NUM_DAYS" /> દિવસ પહેલાં મà«àª²àª¾àª•àª¾àª¤ લીધી</translation>
<translation id="6556866813142980365">ફરી કરો</translation>
<translation id="6569060085658103619">તમે àªàª•à«àª¸à«àªŸà«‡àª¨à«àª¶àª¨ પેજ જોઈ રહà«àª¯àª¾àª‚ છો</translation>
<translation id="6573200754375280815">જમણી બાજà«àª બે કાણાં પાડો</translation>
@@ -1785,7 +1827,6 @@
<translation id="6757797048963528358">તમારà«àª‚ ઉપકરણ નિષà«àª•à«àª°àª¿àª¯ થઈ ગયà«àª‚ હતà«àª‚.</translation>
<translation id="6767985426384634228">સરનામà«àª‚ અપડેટ કરીàª?</translation>
<translation id="6768213884286397650">Hagaki (પોસà«àªŸàª•àª¾àª°à«àª¡)</translation>
-<translation id="6774185088257932239">છૂપા મોડ વિશે <ph name="BEGIN_LINK" />વધૠજાણો<ph name="END_LINK" /></translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">જાંબà«àª¡àª¿àª¯à«‹</translation>
<translation id="6786747875388722282">àªàª•à«àª¸à«àªŸà«‡àª¨à«àª¶àª¨</translation>
@@ -1869,7 +1910,6 @@
<translation id="706295145388601875">Chrome સેટિંગમાં àªàª¡à«àª°à«‡àª¸ ઉમેરો અને તેને મેનેજ કરો</translation>
<translation id="7064851114919012435">સંપરà«àª• માહિતી</translation>
<translation id="7068733155164172741"><ph name="OTP_LENGTH" /> અંકનો કોડ દાખલ કરો</translation>
-<translation id="7070090581017165256">આ સાઇટ વિશે</translation>
<translation id="70705239631109039">તમારà«àª‚ કનેકà«àª¶àª¨ પૂરà«àª£àªªàª£à«‡ સà«àª°àª•à«àª·àª¿àª¤ નથી</translation>
<translation id="7075452647191940183">વિનંતી ખૂબ મોટી છે.</translation>
<translation id="7079718277001814089">આ સાઇટમાં માલવેર છે</translation>
@@ -1886,6 +1926,12 @@
<translation id="7111012039238467737">(માનà«àª¯)</translation>
<translation id="7118618213916969306">કà«àª²àª¿àªªàª¬à«‹àª°à«àª¡ URL શોધો, <ph name="SHORT_URL" /></translation>
<translation id="7119414471315195487">અનà«àª¯ ટૅબ અથવા પà«àª°à«‹àª—à«àª°àª¾àª® બંધ કરો</translation>
+<translation id="7129355289156517987">તમે Chromiumની બધી છૂપી ટૅબ બંધ કરી દો તà«àª¯àª¾àª°à«‡ તે ટૅબની તમારી પà«àª°àªµà«ƒàª¤à«àª¤àª¿ આ ડિવાઇસમાંથી સાફ કરી દેવાય છે:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />બà«àª°àª¾àª‰àªàª¿àª‚ગ પà«àª°àªµà«ƒàª¤à«àª¤àª¿<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />શોધ ઇતિહાસ<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ફોરà«àª®àª®àª¾àª‚ દાખલ કરેલી માહિતી<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">આ સરનામે વિતરણ કરી શકાતà«àª‚ નથી. કોઈ ભિનà«àª¨ સરનામà«àª‚ પસંદ કરો.</translation>
<translation id="7132939140423847331">તમારા àªàª¡àª®àª¿àª¨ દà«àªµàª¾àª°àª¾ આ ડેટાને કૉપિ કરવાથી પà«àª°àª¤àª¿àª¬àª‚ધિત કરવામાં આવà«àª¯à«‹ છે.</translation>
<translation id="7135130955892390533">સà«àªŸà«‡àªŸàª¸ બતાવો</translation>
@@ -1908,6 +1954,7 @@
<translation id="7192203810768312527"><ph name="SIZE" /> ખાલી કરે છે. તમારી આગલી મà«àª²àª¾àª•àª¾àª¤ સમયે કેટલીક સાઇટ વધૠધીમે લોડ થઈ શકે છે.</translation>
<translation id="719464814642662924">વિàªàª¾</translation>
<translation id="7201591969684833065">તમારા વà«àª¯àªµàª¸à«àª¥àª¾àªªàª• જોઈ શકે છે:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, ખાનગી રીતે બà«àª°àª¾àª‰àª કરવા નવી છૂપી ટૅબ ખોલવા માટે Tab પછી Enter દબાવો</translation>
<translation id="7202346780273620635">અકà«àª·àª°-અતિરિકà«àª¤</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" />, સà«àª°àª•à«àª·àª¾ માનકોનà«àª‚ પાલન કરતà«àª‚ નથી.</translation>
<translation id="7210993021468939304">કનà«àªŸà«‡àª¨àª°àª¨à«€ અંદર જ Linuxની પà«àª°àªµà«ƒàª¤à«àª¤àª¿ અને કનà«àªŸà«‡àª¨àª°àª¨à«€ અંદર જ Linuxની àªàªª ઇનà«àª¸à«àªŸà«‰àª² કરી શકાશે તેમજ ચલાવી શકાશે</translation>
@@ -1939,6 +1986,7 @@
<translation id="7304562222803846232">Google àªàª•àª¾àª‰àª¨à«àªŸàª¨àª¾ પà«àª°àª¾àª‡àªµàª¸à«€ સેટિંગ મેનેજ કરો</translation>
<translation id="7305756307268530424">વધૠધીમી ગતિ પર શરૂ કરો</translation>
<translation id="7308436126008021607">બૅકગà«àª°àª¾àª‰àª¨à«àª¡ સિંક</translation>
+<translation id="7310392214323165548">ડિવાઇસ ટૂંક સમયમાં ફરી શરૂ થશે</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">કનેકà«àª¶àª¨ સહાય</translation>
<translation id="7323804146520582233">"<ph name="SECTION" />" વિભાગને છà«àªªàª¾àªµà«‹</translation>
@@ -1946,6 +1994,7 @@
<translation id="7334320624316649418">&amp;પà«àª¨àªƒàª•à«àª°àª®àª¾àª‚કિત કરવà«àª‚ ફરી કરો</translation>
<translation id="7335157162773372339">તમારા કૅમેરાનો ઉપયોગ કરવાનà«àª‚ પૂછી શકે છે</translation>
<translation id="7337248890521463931">વધૠપંકà«àª¤àª¿àª“ બતાવો</translation>
+<translation id="7337418456231055214">શà«àª‚ વરà«àªšà«àª¯à«àª…લ કારà«àª¡ નંબર ભરવામાં આવà«àª¯à«‹ નથી? કૉપિ કરવા માટે, કારà«àª¡àª¨à«€ વિગતો પર કà«àª²àª¿àª• કરો. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">તમારા પà«àª²à«…ટફૉરà«àª® પર ઉપલબà«àª§ નથી.</translation>
<translation id="733923710415886693">પà«àª°àª®àª¾àª£àªªàª¤à«àª° પારદરà«àª¶àª¿àª¤àª¾ દà«àªµàª¾àª°àª¾ સરà«àªµàª°àª¨à«àª‚ પà«àª°àª®àª¾àª£àªªàª¤à«àª° જાહેર કરવામાં આવà«àª¯à«àª‚ ન હતà«àª‚.</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1968,6 +2017,7 @@
<translation id="7378627244592794276">ના</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">લાગૠથતà«àª‚ નથી</translation>
+<translation id="7388594495505979117">{0,plural, =1{તમારà«àª‚ ડિવાઇસ 1 મિનિટમાં ફરી શરૂ થશે}one{તમારà«àª‚ ડિવાઇસ # મિનિટમાં ફરી શરૂ થશે}other{તમારà«àª‚ ડિવાઇસ # મિનિટમાં ફરી શરૂ થશે}}</translation>
<translation id="7390545607259442187">કારà«àª¡àª¨à«€ પà«àª·à«àªŸàª¿ કરો</translation>
<translation id="7392089738299859607">સરનામà«àª‚ અપડેટ કરો</translation>
<translation id="7399802613464275309">સલામતી માટે તપાસ</translation>
@@ -2004,6 +2054,12 @@
<translation id="7485870689360869515">કોઈ ડેટા મળà«àª¯à«‹ નથી.</translation>
<translation id="7495528107193238112">આ કનà«àªŸà«‡àª¨à«àªŸ બà«àª²à«‰àª• કરવામાં આવà«àª¯à«àª‚ છે. સમસà«àª¯àª¾àª¨àª¾àª‚ નિરાકરણ માટે, સાઇટના માલિકનો સંપરà«àª• કરો.</translation>
<translation id="7497998058912824456">Doc બટન બનાવો, Google Docમાં àªàª¡àªªàª¥à«€ નવો દસà«àª¤àª¾àªµà«‡àªœ બનાવવા માટે Enter કી દબાવો</translation>
+<translation id="7506488012654002225">Chromium નીચે આપેલી માહિતી <ph name="BEGIN_EMPHASIS" />સાચવશે નહીં<ph name="END_EMPHASIS" />:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />તમારો બà«àª°àª¾àª‰àªàª¿àª‚ગ ઇતિહાસ
+ <ph name="LIST_ITEM" />કà«àª•à«€ અને સાઇટ ડેટા
+ <ph name="LIST_ITEM" />ફોરà«àª®àª®àª¾àª‚ દાખલ કરેલી માહિતી
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">પરત થયેલà«àª‚ પૉલિસી ડિવાઇસ id ખાલી છે અથવા વરà«àª¤àª®àª¾àª¨ ટોકન સાથે મેળ ખાતà«àª‚ નથી</translation>
<translation id="7508870219247277067">જમરૂખ જેવો લીલો</translation>
<translation id="7511955381719512146">તમે ઉપયોગ કરી રહà«àª¯àª¾ છો તે વાઇ-ફાઇને <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />ની મà«àª²àª¾àª•àª¾àª¤ લેવાની જરૂર પડી શકે છે.</translation>
@@ -2117,7 +2173,6 @@
<translation id="7813600968533626083">Chrome માંથી ફોરà«àª® સૂચનો દૂર કરીàª?</translation>
<translation id="781440967107097262">કà«àª²àª¿àªªàª¬à«‹àª°à«àª¡ શેર કરીàª?</translation>
<translation id="7815407501681723534">'<ph name="SEARCH_STRING" />' માટે <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> મળà«àª¯àª¾àª‚</translation>
-<translation id="782125616001965242">આ સાઇટ વિશેની માહિતી બતાવો</translation>
<translation id="782886543891417279">તમે વાપરી રહેલા વાઇ-ફાઇ (<ph name="WIFI_NAME" />)ના લોગિન પેજ પર જવà«àª‚ પડી શકે.</translation>
<translation id="7836231406687464395">Postfix (àªàª¨à«àªµàª²àªª)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{કોઈ નહીં}=1{1 àªàªª (<ph name="EXAMPLE_APP_1" />)}=2{2 àªàªª (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}one{# àªàªª (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}other{# àªàªª (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}}</translation>
@@ -2134,7 +2189,6 @@
<translation id="7888575728750733395">પà«àª°àª¿àª¨à«àªŸ રેનà«àª¡àª° કરવાનà«àª‚ ઇનà«àªŸà«‡àª¨à«àªŸ</translation>
<translation id="7894280532028510793">જો જોડણી સાચી હોય, તો <ph name="BEGIN_LINK" />નેટવરà«àª• નિદાન ચલાવવાનો પà«àª°àª¯àª¾àª¸ કરી જà«àª“<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (àªàª¨à«àªµàª²àªª)</translation>
-<translation id="7931318309563332511">અજાણ</translation>
<translation id="793209273132572360">સરનામà«àª‚ અપડેટ કરીàª?</translation>
<translation id="7932579305932748336">કોટ કરો</translation>
<translation id="79338296614623784">àªàª• માનà«àª¯ ફોન નંબર દાખલ કરો</translation>
@@ -2159,13 +2213,14 @@
<translation id="7976214039405368314">ઘણી બધી વિનંતીઓ</translation>
<translation id="7977538094055660992">આઉટપà«àªŸ ડિવાઇસ</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">આની સાથે લિંક કરà«àª¯à«àª‚</translation>
<translation id="798134797138789862">વરà«àªšà«àª¯à«àª…લ રિયાલિટી ડિવાઇસનો અને ડેટાનો ઉપયોગ કરવાનà«àª‚ પૂછી શકે છે</translation>
<translation id="7984945080620862648">તમે અતà«àª¯àª¾àª°à«‡ <ph name="SITE" />ની મà«àª²àª¾àª•àª¾àª¤ લઈ શકતાં નથી કારણ કે વેબસાઇટે સમજાય નહીં તેવા ઓળખપતà«àª°à«‹ મોકલà«àª¯àª¾ છે જેની પર Chrome પà«àª°àª•à«àª°àª¿àª¯àª¾ કરી શકતà«àª‚ નથી. નેટવરà«àª• ભૂલો અને હà«àª®àª²àª¾ સામાનà«àª¯ રીતે અસà«àª¥àª¾àª¯à«€ છે, તેથી આ પેજ સંભવિત રીતે પછીથી કારà«àª¯ કરશે.</translation>
-<translation id="79859296434321399">ઑગà«àª®à«‡àª¨à«àªŸà«‡àª¡ રિયાલિટી કનà«àªŸà«‡àª¨à«àªŸ જોવા માટે, ARCore ઇનà«àª¸à«àªŸà«‰àª² કરો</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">જોડો</translation>
<translation id="7992044431894087211"><ph name="APPLICATION_TITLE" /> સાથે સà«àª•à«àª°à«€àª¨ શેરિંગની સà«àªµàª¿àª§àª¾ ફરી શરૂ કરવામાં આવી</translation>
<translation id="7995512525968007366">નિરà«àª¦àª¿àª·à«àªŸ કરાયેલ નથી</translation>
+<translation id="7998269595945679889">છૂપી ટૅબ બટન ખોલો, ખાનગી રીતે બà«àª°àª¾àª‰àª કરવા, નવી છૂપી ટૅબ ખોલવા માટે Enter દબાવો</translation>
<translation id="800218591365569300">મેમરી ખાલી કરવા માટે અનà«àª¯ ટૅબ અથવા પà«àª°à«‹àª—à«àª°àª¾àª®àª¨à«‡ બંધ કરવાનો પà«àª°àª¯àª¾àª¸ કરો.</translation>
<translation id="8004582292198964060">બà«àª°àª¾àª‰àªàª°</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{આ કારà«àª¡ અને તેનà«àª‚ બિલિંગ સરનામà«àª‚ સાચવવામાં આવશે. જà«àª¯àª¾àª°à«‡ <ph name="USER_EMAIL" />માં સાઇન ઇન કરà«àª¯à«àª‚ હશે તà«àª¯àª¾àª°à«‡ તમે તેનો ઉપયોગ કરી શકશો.}one{આ કારà«àª¡ અને તેના બિલિંગ સરનામાં સાચવવામાં આવશે. જà«àª¯àª¾àª°à«‡ <ph name="USER_EMAIL" />માં સાઇન ઇન કરà«àª¯à«àª‚ હશે તà«àª¯àª¾àª°à«‡ તમે તેમનો ઉપયોગ કરી શકશો.}other{આ કારà«àª¡ અને તેના બિલિંગ સરનામાં સાચવવામાં આવશે. જà«àª¯àª¾àª°à«‡ <ph name="USER_EMAIL" />માં સાઇન ઇન કરà«àª¯à«àª‚ હશે તà«àª¯àª¾àª°à«‡ તમે તેમનો ઉપયોગ કરી શકશો.}}</translation>
@@ -2225,6 +2280,7 @@
<translation id="8202370299023114387">વિરોધ</translation>
<translation id="8206978196348664717">Prc4 (àªàª¨à«àªµàª²àªª)</translation>
<translation id="8211406090763984747">કનેકà«àª¶àª¨ સà«àª°àª•à«àª·àª¿àª¤ છે</translation>
+<translation id="8217240300496046857">સાઇટ તમને વેબ પર બધે ટà«àª°à«…ક કરતી કà«àª•à«€àª¨à«‹ ઉપયોગ કરી શકે નહીં. અમà«àª• સાઇટ પરની સà«àªµàª¿àª§àª¾àª“માં કદાચ ખલેલ પડી શકે છે.</translation>
<translation id="8218327578424803826">સોંપાયેલ સà«àª¥àª¾àª¨:</translation>
<translation id="8220146938470311105">C7/C6 (àªàª¨à«àªµàª²àªª)</translation>
<translation id="8225771182978767009">આ કમà«àªªà«àª¯à«àªŸàª°àª¨à«‡ સેટ કરનાર વà«àª¯àª•à«àª¤àª¿àª આ સાઇટને અવરોધિત કરવાનà«àª‚ પસંદ કરà«àª¯à«àª‚ છે.</translation>
@@ -2265,14 +2321,9 @@
<translation id="830498451218851433">અડધà«àª‚ વાળો</translation>
<translation id="8307358339886459768">નાનો-ફોટો</translation>
<translation id="8307888238279532626">ઇનà«àª¸à«àªŸà«‰àª² થયેલી àªàªª અને તેમનો ઉપયોગ કેટલી વાર કરવામાં આવે છે</translation>
+<translation id="8317207217658302555">ARCore અપડેટ કરી�</translation>
<translation id="831997045666694187">સાંજ</translation>
<translation id="8321476692217554900">નોટિફિકેશન</translation>
-<translation id="8328484624016508118">બધી છૂપી ટૅબ બંધ કરà«àª¯àª¾ પછી, Chrome આ સાફ કરશે:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />આ ડિવાઇસમાંની તમારી બà«àª°àª¾àª‰àªàª¿àª‚ગ પà«àª°àªµà«ƒàª¤à«àª¤àª¿<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />આ ડિવાઇસમાંનો તમારો શોધ ઇતિહાસ<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />ફોરà«àª®àª®àª¾àª‚ દાખલ કરેલી માહિતી<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489"><ph name="HOST_NAME" /> ની àªàª•à«àª¸à«‡àª¸ નકારાઈ હતી</translation>
<translation id="833262891116910667">હાઇલાઇટ</translation>
<translation id="8339163506404995330"><ph name="LANGUAGE" />માં છે તે પેજનો અનà«àªµàª¾àª¦ થશે નહીં</translation>
@@ -2324,6 +2375,7 @@
<translation id="8507227106804027148">આદેશ પંકà«àª¤àª¿</translation>
<translation id="8508648098325802031">શોધ આઇકન</translation>
<translation id="8511402995811232419">કà«àª•à«€ મેનેજ કરો</translation>
+<translation id="8519753333133776369">તમારા àªàª¡àª®àª¿àª¨àª¿àª¸à«àªŸà«àª°à«‡àªŸàª° દà«àªµàª¾àª°àª¾ મંજૂરી આપવામાં આવેલà«àª‚ HID ડિવાઇસ</translation>
<translation id="8522552481199248698">Chrome તમારા Google àªàª•àª¾àª‰àª¨à«àªŸàª¨à«‡ સà«àª°àª•à«àª·àª¿àª¤ કરવામાં અને તમારો પાસવરà«àª¡ બદલવામાં તમારી સહાય કરી શકે છે.</translation>
<translation id="8530813470445476232">તમારો બà«àª°àª¾àª‰àªàª¿àª‚ગ ઇતિહાસ, કà«àª•à«€, કૅશ મેમરી અને બીજà«àª‚ ઘણà«àª‚ Chromeના સેટિંગમાંથી સાફ કરો</translation>
<translation id="8533619373899488139">બà«àª²à«‰àª• કરેલા URLsની સૂચિ અને તમારા સિસà«àªŸàª® વà«àª¯àªµàª¸à«àª¥àª¾àªªàª• દà«àªµàª¾àª°àª¾ લાગૠકરવામાં આવેલી અનà«àª¯ પૉલિસીઓ જોવા માટે &lt;strong&gt;chrome://policy&lt;/strong&gt;ની મà«àª²àª¾àª•àª¾àª¤ લો.</translation>
@@ -2335,7 +2387,6 @@
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{પરવાનગી રીસેટ કરો}one{પરવાનગી રીસેટ કરો}other{બધી પરવાનગી રીસેટ કરો}}</translation>
<translation id="8555010941760982128">ચેકઆઉટ વખતે આ કોડનો ઉપયોગ કરો</translation>
<translation id="8557066899867184262">CVC તમારા કારà«àª¡àª¨à«€ પાછળ હોય છે.</translation>
-<translation id="8558485628462305855">ઑગà«àª®à«‡àª¨à«àªŸà«‡àª¡ રિયાલિટી કનà«àªŸà«‡àª¨à«àªŸ જોવા માટે ARCore અપડેટ કરો</translation>
<translation id="8559762987265718583"><ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> પર ખાનગી કનેકà«àª¶àª¨ સà«àª¥àª¾àªªàª¿àª¤ કરી શકાતà«àª‚ નથી કારણ કે તમારા ઉપકરણની તારીખ અને સમય (<ph name="DATE_AND_TIME" />) અયોગà«àª¯ છે.</translation>
<translation id="8564182942834072828">અલગ દસà«àª¤àª¾àªµà«‡àªœà«‹/ગોઠવણી વિનાની કૉપિ</translation>
<translation id="8564985650692024650">જો તમે અનà«àª¯ સાઇટ પર <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> પાસવરà«àª¡àª¨à«‹ ફરી ઉપયોગ કરà«àª¯à«‹ હોય, તો Chromium તેને રીસેટ કરવાનો સà«àªàª¾àªµ આપે છે.</translation>
@@ -2354,6 +2405,7 @@
<translation id="865032292777205197">મોશન સેનà«àª¸àª°</translation>
<translation id="8663226718884576429">ઑરà«àª¡àª°àª¨à«‹ સારાંશ, <ph name="TOTAL_LABEL" />, વધૠવિગતો</translation>
<translation id="8666678546361132282">અંગà«àª°à«‡àªœà«€</translation>
+<translation id="8669306706049782872">વિનà«àª¡à«‹ ખોલવા અને મૂકવા માટે, તમારી સà«àª•à«àª°à«€àª¨ વિશેની માહિતીનો ઉપયોગ કરવા માગે છે</translation>
<translation id="867224526087042813">સહી</translation>
<translation id="8676424191133491403">કોઈ વિલંબ વિના</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, જવાબ, <ph name="ANSWER" /></translation>
@@ -2380,6 +2432,7 @@
<translation id="8731544501227493793">પાસવરà«àª¡ મેનેજ કરો બટન, Chrome સેટિંગમાં તમારા પાસવરà«àª¡ જોવા અને તેમને મેનેજ કરવા માટે Enter દબાવો</translation>
<translation id="8734529307927223492"><ph name="MANAGER" /> દà«àªµàª¾àª°àª¾ તમારા <ph name="DEVICE_TYPE" />ને મેનેજ કરવામાં આવે છે</translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, ખાનગી રીતે બà«àª°àª¾àª‰àª કરવા નવી છà«àªªà«€ વિનà«àª¡à«‹ ખોલવા માટે Tab પછી Enter દબાવો</translation>
+<translation id="8737685506611670901"><ph name="REPLACED_HANDLER_TITLE" /> ને બદલે <ph name="PROTOCOL" /> લિંકà«àª¸ ખોલો</translation>
<translation id="8738058698779197622">àªàª• સà«àª°àª•à«àª·àª¿àª¤ કનેકà«àª¶àª¨ સà«àª¥àª¾àªªàª¿àª¤ કરવા માટે, તમારà«àª‚ ઘડિયાળ યોગà«àª¯ રીતે સેટ હોવà«àª‚ જરૂરી છે. આનà«àª‚ કારણ ઠકે વેબસાઇટà«àª¸ તેઓને ઓળખવા માટે જે પà«àª°àª®àª¾àª£àªªàª¤à«àª°à«‹àª¨à«‹ ઉપયોગ કરે છે તે ચોકà«àª•àª¸ સમય અવધિ માટે જ માનà«àª¯ હોય છે. તમારા ઉપકરણની ઘડિયાળ ખોટી હોવાને લીધે, Chromium આ પà«àª°àª®àª¾àª£àªªàª¤à«àª°à«‹àª¨à«‡ ચકાસી શકતà«àª‚ નથી.</translation>
<translation id="8740359287975076522"><ph name="HOST_NAME" /> નà«àª‚ &lt;abbr id="dnsDefinition"&gt;DNS સરનામà«àª‚&lt;/abbr&gt; શોધી શકાયà«àª‚ નથી. સમસà«àª¯àª¾àª¨à«àª‚ નિદાન કરી રહà«àª¯àª¾àª‚ છીàª.</translation>
<translation id="8742371904523228557"><ph name="ONE_TIME_CODE" /> ઠ<ph name="ORIGIN" /> માટેનો તમારો કોડ છે</translation>
@@ -2407,6 +2460,7 @@
<translation id="883848425547221593">અનà«àª¯ બà«àª•àª®àª¾àª°à«àª•</translation>
<translation id="884264119367021077">શિપિંગ સરનામà«àª‚</translation>
<translation id="884923133447025588">રદ કરવાની કોઈ મેકેનિàªàª® મળી નથી.</translation>
+<translation id="8849262850971482943">વધારાની સà«àª°àª•à«àª·àª¾ માટે, તમારા વરà«àªšà«àª¯à«àª…લ કારà«àª¡àª¨à«‹ ઉપયોગ કરો</translation>
<translation id="885730110891505394">Google સાથે શેર કરવà«àª‚</translation>
<translation id="8858065207712248076">જો તમે અનà«àª¯ સાઇટ પર <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> પાસવરà«àª¡àª¨à«‹ ફરી ઉપયોગ કરà«àª¯à«‹ હોય, તો Chrome તેને રીસેટ કરવાનો સà«àªàª¾àªµ આપે છે.</translation>
<translation id="885906927438988819">જો જોડણી સાચી હોય, તો <ph name="BEGIN_LINK" />Windows નેટવરà«àª• નિદાન ચલાવવાનો પà«àª°àª¯àª¾àª¸ કરી જà«àª“<ph name="END_LINK" />.</translation>
@@ -2456,6 +2510,7 @@
<translation id="9004367719664099443">VR સતà«àª° ચાલૠછે</translation>
<translation id="9005998258318286617">PDF દસà«àª¤àª¾àªµà«‡àªœ લોડ કરવામાં નિષà«àª«àª³ થયાં.</translation>
<translation id="9008201768610948239">અવગણો</translation>
+<translation id="901834265349196618">ઇમેઇલ</translation>
<translation id="9020200922353704812">કારà«àª¡àª¨à«àª‚ બિલિંગ સરનામà«àª‚ આવશà«àª¯àª• છે</translation>
<translation id="9020542370529661692">આ પેજનો <ph name="TARGET_LANGUAGE" />માં અનà«àªµàª¾àª¦ કરવામાં આવà«àª¯à«‹ છે</translation>
<translation id="9020742383383852663">A8</translation>
@@ -2504,6 +2559,7 @@
<translation id="9150045010208374699">તમારા કૅમેરાનો ઉપયોગ કરો</translation>
<translation id="9150685862434908345">તમારા વà«àª¯àªµàª¸à«àª¥àª¾àªªàª• તમારા બà«àª°àª¾àª‰àªàª° સેટઅપને દૂરથી બદલી શકે છે. આ ડિવાઇસ પરની પà«àª°àªµà«ƒàª¤à«àª¤àª¿ Chromeની બહારથી પણ મેનેજ કરી શકાય છે. <ph name="BEGIN_LINK" />વધૠજાણો<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">અપડેટેડ</translation>
+<translation id="9155211586651734179">ઑડિયો પેરિફેરલ જોડેલા છે</translation>
<translation id="9157595877708044936">સેટિંગ અપ...</translation>
<translation id="9158625974267017556">C6 (àªàª¨à«àªµàª²àªª)</translation>
<translation id="9164029392738894042">સચોટતાની તપાસ</translation>
diff --git a/chromium/components/strings/components_strings_hi.xtb b/chromium/components/strings/components_strings_hi.xtb
index 31c141891f7..bf22804b7b8 100644
--- a/chromium/components/strings/components_strings_hi.xtb
+++ b/chromium/components/strings/components_strings_hi.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">बà¥à¤¯à¥Œà¤°à¤¾ देखें</translation>
<translation id="1030706264415084469"><ph name="URL" /> आपके डिवाइस पर हमेशा के लिठबड़ी मातà¥à¤°à¤¾ में डेटा संगà¥à¤°à¤¹à¥€à¤¤ करना चाहता है</translation>
<translation id="1032854598605920125">घड़ी की दिशा में घà¥à¤®à¤¾à¤à¤‚</translation>
+<translation id="1033329911862281889">गà¥à¤ªà¥à¤¤ मोड में भी, आपको ऑनलाइन देखा जा सकता है:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />उन साइटों और सेवाओं को आपके आने/जाने का पता चलता है जिनका इसà¥à¤¤à¥‡à¤®à¤¾à¤² किया जाता है<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />नौकरी देने वाली कंपनियां या सà¥à¤•à¥‚ल, बà¥à¤°à¤¾à¤‰à¤œà¤¼à¤¿à¤‚ग गतिविधि को टà¥à¤°à¥ˆà¤• कर सकते हैं<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />इंटरनेट सेवा देने वाली कंपनियां, वेब टà¥à¤°à¥ˆà¤«à¤¼à¤¿à¤• की निगरानी कर सकती हैं<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">बंद करें</translation>
<translation id="1036982837258183574">फ़à¥à¤² सà¥à¤•à¥à¤°à¥€à¤¨ से बाहर निकलने के लिठ|<ph name="ACCELERATOR" />| दबाà¤à¤‚</translation>
<translation id="1038106730571050514">सà¥à¤à¤¾à¤µ दिखाà¤à¤‚</translation>
<translation id="1038842779957582377">अजà¥à¤žà¤¾à¤¤ नाम</translation>
<translation id="1041998700806130099">जॉब शीट मैसेज</translation>
<translation id="1048785276086539861">जब आप वीडियो के ऊपर टेकà¥à¤¸à¥à¤Ÿ, लिंक वगैरह में बदलाव करते हैं, तो दसà¥à¤¤à¤¾à¤µà¥‡à¥›, सिंगल पेज वà¥à¤¯à¥‚ पर वापस चला जाà¤à¤—ा</translation>
-<translation id="1049743911850919806">गà¥à¤ªà¥à¤¤</translation>
<translation id="1050038467049342496">दूूूूसरे à¤à¤ªà¥à¤²à¤¿à¤•à¥‡à¤¶à¤¨ बंद करें</translation>
<translation id="1055184225775184556">&amp;जोड़ना वापस लाà¤à¤‚</translation>
<translation id="1056898198331236512">चेतावनी</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">नीति कैश मेमोरी ठीक है</translation>
<translation id="1130564665089811311">'पेज का अनà¥à¤µà¤¾à¤¦ करें' बटन, Google Translate की मदद से इस पेज का अनà¥à¤µà¤¾à¤¦ करने के लिठEnter दबाà¤à¤‚</translation>
<translation id="1131264053432022307">आपकी कॉपी की हà¥à¤ˆ इमेज</translation>
+<translation id="1142846828089312304">गà¥à¤ªà¥à¤¤ मोड में, तीसरे पकà¥à¤· की कà¥à¤•à¥€ बà¥à¤²à¥‰à¤• करें</translation>
<translation id="1150979032973867961">यह सरà¥à¤µà¤° यह नहीं पà¥à¤°à¤®à¤¾à¤£à¤¿à¤¤ कर सका कि यह <ph name="DOMAIN" /> है; इसका सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° आपके कंपà¥à¤¯à¥‚टर के ऑपरेटिंग सिसà¥à¤Ÿà¤® दà¥à¤µà¤¾à¤°à¤¾ विशà¥à¤µà¤¸à¤¨à¥€à¤¯ नहीं है. à¤à¤¸à¤¾ गलत कॉनà¥à¥žà¤¿à¤—रेशन या किसी आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¤¾ दà¥à¤µà¤¾à¤°à¤¾ आपके कनेकà¥à¤¶à¤¨ में अवरोध डालने के कारण हो सकता है.</translation>
<translation id="1151972924205500581">पासवरà¥à¤¡ आवशà¥à¤¯à¤•</translation>
<translation id="1156303062776767266">आप सà¥à¤¥à¤¾à¤¨à¥€à¤¯ या शेयर की गई फ़ाइल देख रहे हैं</translation>
@@ -64,7 +70,6 @@
<translation id="1178581264944972037">रोकें</translation>
<translation id="1181037720776840403">हटाà¤à¤‚</translation>
<translation id="1186201132766001848">पासवरà¥à¤¡ जांचें</translation>
-<translation id="1195210374336998651">à¤à¤ªà¥à¤²à¤¿à¤•à¥‡à¤¶à¤¨ की सेटिंग पर जाà¤à¤‚</translation>
<translation id="1195558154361252544">जिन साइट को आप फ़ॉलो करते हैं उनà¥à¤¹à¥‡à¤‚ छोड़कर सभी साइट के लिठसूचनाà¤à¤‚ अपने आप बंद हो गई हैं</translation>
<translation id="1197088940767939838">नारंगी</translation>
<translation id="1201402288615127009">अगला</translation>
@@ -111,7 +116,7 @@
<translation id="1307966114820526988">बंद की गई सà¥à¤µà¤¿à¤§à¤¾à¤à¤‚</translation>
<translation id="1308113895091915999">ऑफ़र उपलबà¥à¤§ है</translation>
<translation id="1312803275555673949">कौनसा सबूत इस बात की पà¥à¤·à¥à¤Ÿà¤¿ करता है?</translation>
-<translation id="131405271941274527">किसी NFC डिवाइस में आपके फ़ोन पर टैप किठजाने पर, <ph name="URL" /> जानकारी भेजना और पाना चाहता है</translation>
+<translation id="1314311879718644478">ऑगमेंटेड रिà¤à¤²à¤¿à¤Ÿà¥€ (à¤à¤†à¤°) वाला कॉनà¥à¤Ÿà¥‡à¤‚ट देखें</translation>
<translation id="1314509827145471431">दाईं ओर बाइंड</translation>
<translation id="1318023360584041678">टैब गà¥à¤°à¥à¤ª में सेव किया गया</translation>
<translation id="1319245136674974084">इस à¤à¤ªà¥à¤²à¤¿à¤•à¥‡à¤¶à¤¨ के लिठफिर से न पूछें</translation>
@@ -161,6 +166,7 @@
<translation id="142858679511221695">कà¥à¤²à¤¾à¤‰à¤¡ का उपयोगकरà¥à¤¤à¤¾</translation>
<translation id="1428729058023778569">यह साइट à¤à¤šà¤Ÿà¥€à¤Ÿà¥€à¤ªà¥€à¤à¤¸ पर काम नहीं करती, इसलिठआपको यह चेतावनी दिख रही है. <ph name="BEGIN_LEARN_MORE_LINK" />ज़à¥à¤¯à¤¾à¤¦à¤¾ जानें<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">पà¥à¤°à¤¿à¤‚ट करें</translation>
+<translation id="1432187715652018471">यह पेज, सेवा हैंडलर इंसà¥à¤Ÿà¥‰à¤² करना चाहता है.</translation>
<translation id="1432581352905426595">सरà¥à¤š इंजन पà¥à¤°à¤¬à¤‚धित करें</translation>
<translation id="1436185428532214179">साइट, आपके डिवाइस पर फ़ाइलों या फ़ोलà¥à¤¡à¤° में बदलाव करने की अनà¥à¤®à¤¤à¤¿ मांग सकती है</translation>
<translation id="1442386063175183758">दायां गेट फ़ोलà¥à¤¡</translation>
@@ -181,6 +187,12 @@
<translation id="1483493594462132177">भेजें</translation>
<translation id="1484290072879560759">शिपिंग पता चà¥à¤¨à¥‡à¤‚</translation>
<translation id="1492194039220927094">नीतियां भेजें:</translation>
+<translation id="149293076951187737">Chrome में खोले गठसभी गà¥à¤ªà¥à¤¤ टैब बंद करने पर, इन टैब में हà¥à¤ˆ आपकी गतिविधि का डेटा इस डिवाइस से हटा दिया जाता है:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />बà¥à¤°à¤¾à¤‰à¤œà¤¼à¤¿à¤‚ग गतिविधि<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />खोज इतिहास<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />फ़ॉरà¥à¤® में डाली गई जानकारी<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">टैब पर वापस जाà¤à¤‚</translation>
<translation id="1501859676467574491">अपने Google खाते में मौजूद कारà¥à¤¡ दिखाà¤à¤‚</translation>
<translation id="1507202001669085618">&lt;p&gt;अगर आप à¤à¤¸à¥‡ वाई-फ़ाई पोरà¥à¤Ÿà¤² का इसà¥à¤¤à¥‡à¤®à¤¾à¤² कर रहे हैं, जिसमें ऑनलाइन होने से पहले साइन इन ज़रूरी है, तो आपको यह गड़बड़ी दिखाई देगी.&lt;/p&gt;
@@ -208,6 +220,8 @@
<translation id="1559572115229829303">&lt;p&gt;<ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> से निजी कनेकà¥â€à¤¶à¤¨ जोड़ा नहीं जा सकता कà¥â€à¤¯à¥‹à¤‚कि आपके डिवाइस की तारीख और समय (<ph name="DATE_AND_TIME" />) गलत है.&lt;/p&gt;
&lt;p&gt;कृपया तारीख और समय को &lt;strong&gt;सेटिंग&lt;/strong&gt; à¤à¤ªà¥à¤²à¤¿à¤•à¥‡à¤¶à¤¨ के &lt;strong&gt;सामानà¥â€à¤¯&lt;/strong&gt; सेकà¥à¤¶à¤¨ से à¤à¤¡à¤œà¤¸à¥â€à¤Ÿ करें.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">à¤à¤¡à¤®à¤¿à¤¨, <ph name="DATE" /> को <ph name="TIME" /> बजे आपके डिवाइस को रीसà¥à¤Ÿà¤¾à¤°à¥à¤Ÿ करेगा</translation>
+<translation id="156703335097561114">नेटवरà¥à¤• से जà¥à¤¡à¤¼à¥€ जानकारी जैसे कि पते, इंटरफ़ेस का कॉनà¥à¥žà¤¿à¤—रेशन, और कनेकà¥à¤¶à¤¨ की कà¥à¤µà¤¾à¤²à¤¿à¤Ÿà¥€</translation>
<translation id="1567040042588613346">यह नीति उमà¥à¤®à¥€à¤¦ के मà¥à¤¤à¤¾à¤¬à¤¿à¤• काम कर रही है. हालांकि, किसी दूसरी जगह à¤à¤¸à¤¾ ही मान सेट किया गया है और उसकी जगह इस नीति को लागू कर दिया गया है.</translation>
<translation id="1569487616857761740">खतà¥à¤® होने की तारीख डालें</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@
<translation id="1583429793053364125">इस वेबपेज को दिखाने के दौरान कà¥à¤› गड़बड़ी हà¥à¤ˆ है.</translation>
<translation id="1586541204584340881">आपने कौनसे à¤à¤•à¥à¤¸à¤Ÿà¥‡à¤‚शन इंसà¥à¤Ÿà¥‰à¤² किठहैं</translation>
<translation id="1588438908519853928">सामानà¥à¤¯</translation>
+<translation id="1589050138437146318">ARCore इंसà¥à¤Ÿà¥‰à¤² करें?</translation>
<translation id="1592005682883173041">सà¥à¤¥à¤¾à¤¨à¥€à¤¯ डेटा à¤à¤•à¥à¤¸à¥‡à¤¸</translation>
<translation id="1594030484168838125">चà¥à¤¨à¥‡à¤‚</translation>
<translation id="160851722280695521">Chrome में Dino Run गेम चलाà¤à¤‚</translation>
@@ -255,7 +270,7 @@
<ph name="POLICY_NAME" /> को <ph name="VALUE" /> पर सेट नहीं किया गया है.</translation>
<translation id="1712552549805331520"><ph name="URL" /> आपके सà¥à¤¥à¤¾à¤¨à¥€à¤¯ कंपà¥à¤¯à¥‚टर पर हमेशा के लिठडेटा संगà¥à¤°à¤¹à¤¿à¤¤ करना चाहता है</translation>
<translation id="1713628304598226412">टà¥à¤°à¥‡ 2</translation>
-<translation id="1715874602234207">à¤à¤«à¤¼</translation>
+<translation id="1715874602234207">शà¥à¤•à¥à¤°</translation>
<translation id="1717218214683051432">मोशन सेंसर</translation>
<translation id="1717494416764505390">मेलबॉकà¥à¤¸ 3</translation>
<translation id="1718029547804390981">à¤à¤¨à¥‹à¤Ÿà¥‡à¤Ÿ करने के लिठदसà¥à¤¤à¤¾à¤µà¥‡à¤œà¤¼ बहà¥à¤¤ बड़ा है</translation>
@@ -284,6 +299,7 @@
यह हेडर गलत है. इसलिà¤, यह बà¥à¤°à¤¾à¤‰à¤œà¤¼à¤° को <ph name="SITE" /> के लिठआपके अनà¥à¤°à¥‹à¤§ पर कारà¥à¤°à¤µà¤¾à¤ˆ
करने से रोकता है. साइट ऑपरेटर, साइट की सà¥à¤°à¤•à¥à¤·à¤¾ और दूसरी
पà¥à¤°à¥‰à¤ªà¤°à¥à¤Ÿà¥€ को कॉनà¥à¤«à¤¼à¤¿à¤—र करने के लिà¤, मूल नीतियों का इसà¥à¤¤à¥‡à¤®à¤¾à¤² कर सकते हैं.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Chromium में गà¥à¤ªà¥à¤¤ मोड की सà¥à¤µà¤¿à¤§à¤¾ के बारे में ज़à¥à¤¯à¤¾à¤¦à¤¾ जानें<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372"> खोले गठटैब, यहां दिखाई देंगे</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -360,7 +376,7 @@
<translation id="204357726431741734">अपने Google खाते में सेव किठगठपासवरà¥à¤¡ इसà¥à¤¤à¥‡à¤®à¤¾à¤² करने के लिठसाइन इन करें</translation>
<translation id="2053111141626950936"><ph name="LANGUAGE" /> भाषा के पेजों का अनà¥à¤µà¤¾à¤¦ नहीं किया जाà¤à¤—ा.</translation>
<translation id="2053373601901562871">{NUM_DAYS,plural, =0{यह कंटà¥à¤°à¥‹à¤² चालू होने और सà¥à¤Ÿà¥‡à¤Ÿà¤¸ à¤à¤•à¥à¤Ÿà¤¿à¤µ होने पर, Chrome यह देखता है कि आपकी हाल की बà¥à¤°à¤¾à¤‰à¤œà¤¼à¤¿à¤‚ग गतिविधि, किस बड़े गà¥à¤°à¥à¤ª या "समानता रखने वाले लोगों" से काफ़ी हद तक मिलती है. विजà¥à¤žà¤¾à¤ªà¤¨ देने वाले, गà¥à¤°à¥à¤ª के लिठविजà¥à¤žà¤¾à¤ªà¤¨à¥‹à¤‚ को चà¥à¤¨ सकते हैं. साथ ही, आपकी बà¥à¤°à¤¾à¤‰à¤œà¤¼à¤¿à¤‚ग गतिविधि आपके डिवाइस पर गोपनीय रखी जाती है. आपका गà¥à¤°à¥à¤ª हर दिन अपडेट किया जाता है.}=1{यह कंटà¥à¤°à¥‹à¤² चालू होने और सà¥à¤Ÿà¥‡à¤Ÿà¤¸ à¤à¤•à¥à¤Ÿà¤¿à¤µ होने पर, Chrome यह देखता है कि आपकी हाल की बà¥à¤°à¤¾à¤‰à¤œà¤¼à¤¿à¤‚ग गतिविधि, किस बड़े गà¥à¤°à¥à¤ª या "समानता रखने वाले लोगों" से काफ़ी हद तक मिलती है. विजà¥à¤žà¤¾à¤ªà¤¨ देने वाले, गà¥à¤°à¥à¤ª के लिठविजà¥à¤žà¤¾à¤ªà¤¨à¥‹à¤‚ को चà¥à¤¨ सकते हैं. साथ ही, आपकी बà¥à¤°à¤¾à¤‰à¤œà¤¼à¤¿à¤‚ग गतिविधि आपके डिवाइस पर गोपनीय रखी जाती है. आपका गà¥à¤°à¥à¤ª हर दिन अपडेट किया जाता है.}one{यह कंटà¥à¤°à¥‹à¤² चालू होने और सà¥à¤Ÿà¥‡à¤Ÿà¤¸ à¤à¤•à¥à¤Ÿà¤¿à¤µ होने पर, Chrome यह देखता है कि आपकी हाल की बà¥à¤°à¤¾à¤‰à¤œà¤¼à¤¿à¤‚ग गतिविधि, किस बड़े गà¥à¤°à¥à¤ª या "समानता रखने वाले लोगों" से काफ़ी हद तक मिलती है. विजà¥à¤žà¤¾à¤ªà¤¨ देने वाले, गà¥à¤°à¥à¤ª के लिठविजà¥à¤žà¤¾à¤ªà¤¨à¥‹à¤‚ को चà¥à¤¨ सकते हैं. साथ ही, आपकी बà¥à¤°à¤¾à¤‰à¤œà¤¼à¤¿à¤‚ग गतिविधि आपके डिवाइस पर गोपनीय रखी जाती है. आपका गà¥à¤°à¥à¤ª हर {NUM_DAYS} दिन में अपडेट किया जाता है.}other{यह कंटà¥à¤°à¥‹à¤² चालू होने और सà¥à¤Ÿà¥‡à¤Ÿà¤¸ à¤à¤•à¥à¤Ÿà¤¿à¤µ होने पर, Chrome यह देखता है कि आपकी हाल की बà¥à¤°à¤¾à¤‰à¤œà¤¼à¤¿à¤‚ग गतिविधि, किस बड़े गà¥à¤°à¥à¤ª या "समानता रखने वाले लोगों" से काफ़ी हद तक मिलती है. विजà¥à¤žà¤¾à¤ªà¤¨ देने वाले, गà¥à¤°à¥à¤ª के लिठविजà¥à¤žà¤¾à¤ªà¤¨à¥‹à¤‚ को चà¥à¤¨ सकते हैं. साथ ही, आपकी बà¥à¤°à¤¾à¤‰à¤œà¤¼à¤¿à¤‚ग गतिविधि आपके डिवाइस पर गोपनीय रखी जाती है. आपका गà¥à¤°à¥à¤ª हर {NUM_DAYS} दिन में अपडेट किया जाता है.}}</translation>
-<translation id="2053553514270667976">ज़िप कोड</translation>
+<translation id="2053553514270667976">ज़िप कोड</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 सà¥à¤à¤¾à¤µ}one{# सà¥à¤à¤¾à¤µ}other{# सà¥à¤à¤¾à¤µ}}</translation>
<translation id="2071156619270205202">इस कारà¥à¤¡ को वरà¥à¤šà¥à¤…ल कारà¥à¤¡ के तौर पर इसà¥à¤¤à¥‡à¤®à¤¾à¤² नहीं किया जा सकता.</translation>
<translation id="2071692954027939183">सूचनाओं को अपने-आप बà¥à¤²à¥‰à¤• कर दिया गया, कà¥à¤¯à¥‹à¤‚कि आम तौर पर आप उनà¥à¤¹à¥‡à¤‚ अनà¥à¤®à¤¤à¤¿ नहीं देते हैं</translation>
@@ -411,6 +427,7 @@
<translation id="22081806969704220">टà¥à¤°à¥‡ 3</translation>
<translation id="2212735316055980242">नीति नहीं मिली</translation>
<translation id="2213606439339815911">पà¥à¤°à¤µà¤¿à¤·à¥à¤Ÿà¤¿à¤¯à¤¾à¤‚ फ़ेच की जा रही हैं...</translation>
+<translation id="2213612003795704869">पेज पà¥à¤°à¤¿à¤‚ट कर दिया गया</translation>
<translation id="2215727959747642672">फ़ाइल में बदलाव करना</translation>
<translation id="2218879909401188352"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> पर इस समय मौजूद हमलावर à¤à¤¸à¥‡ खतरनाक à¤à¤ªà¥à¤²à¤¿à¤•à¥‡à¤¶à¤¨ इंसà¥à¤Ÿà¥‰à¤² कर सकते हैं जो आपके डिवाइस को नà¥à¤•à¤¸à¤¾à¤¨ पहà¥à¤‚चा सकते हैं और आपके मोबाइल बिल में अनजाने खरà¥à¤šà¥‡ जोड़ सकते हैं या आपकी वà¥â€à¤¯à¤•à¥â€à¤¤à¤¿à¤—त जानकारी चà¥à¤°à¤¾ सकते हैं. <ph name="BEGIN_LEARN_MORE_LINK" />ज़à¥à¤¯à¤¾à¤¦à¤¾ जानें<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">इंटरनेट कनेकà¥à¤¶à¤¨ नहीं है</translation>
@@ -420,6 +437,7 @@
<translation id="2248949050832152960">WebAuthn का इसà¥à¤¤à¥‡à¤®à¤¾à¤² करें</translation>
<translation id="2250931979407627383">बाईं ओर à¤à¤œà¤¼Â à¤¸à¥à¤Ÿà¤¿à¤š</translation>
<translation id="225207911366869382">यह मान इस नीति के लिठहटा दिया गया है.</translation>
+<translation id="2256115617011615191">अभी पà¥à¤¨à¤ƒ पà¥à¤°à¤¾à¤°à¤‚भ करें</translation>
<translation id="2258928405015593961">खतà¥à¤® हाेने की तारीख डालें और फिर से काेशिश करें</translation>
<translation id="225943865679747347">गड़बड़ी कोड: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">HTTP गड़बड़ी</translation>
@@ -447,6 +465,7 @@
<translation id="2337852623177822836">वह सेटिंग जिसे आपका वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤• नियंतà¥à¤°à¤¿à¤¤ करता है</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> यà¥à¤—à¥à¤®à¤¿à¤¤ करना चाहता है</translation>
<translation id="2346319942568447007">आपकी कॉपी की हà¥à¤ˆ इमेज</translation>
+<translation id="2350796302381711542"><ph name="HANDLER_HOSTNAME" /> को <ph name="REPLACED_HANDLER_TITLE" /> के बजाय सभी <ph name="PROTOCOL" /> लिंक खोलने दें?</translation>
<translation id="2354001756790975382">अनà¥à¤¯ बà¥à¤•à¤®à¤¾à¤°à¥à¤•</translation>
<translation id="2354430244986887761">Google सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ बà¥à¤°à¤¾à¤‰à¤œà¤¼à¤¿à¤‚ग को हाल में <ph name="SITE" /> पर <ph name="BEGIN_LINK" />नà¥à¤•à¤¸à¤¾à¤¨ पहà¥à¤‚चाने वाले à¤à¤ªà¥à¤²à¤¿à¤•à¥‡à¤¶à¤¨ मिले हैं<ph name="END_LINK" />.</translation>
<translation id="2355395290879513365">आप इस साइट पर जिन चितà¥à¤°à¥‹à¤‚ को देख रहे हैं, हो सकता है कि वे हमलावरों को दिखाई दें और हमलावर उनà¥à¤¹à¥‡à¤‚ बदलने के लिठआपको भà¥à¤°à¤®à¤¿à¤¤ करें.</translation>
@@ -472,6 +491,7 @@
<translation id="2413528052993050574">यह सरà¥à¤µà¤° यह पà¥à¤°à¤®à¤¾à¤£à¤¿à¤¤ नहीं कर सका कि यह <ph name="DOMAIN" />; इसका सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° निरसà¥à¤¤ कर दिया गया है. à¤à¤¸à¤¾ गलत कॉनà¥à¤«à¤¼à¤¿à¤—रेशन के कारण या किसी आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¤¾ दà¥à¤µà¤¾à¤°à¤¾ आपके कनेकà¥à¤¶à¤¨ में अवरोध डालने के कारण हो सकता है.</translation>
<translation id="2414886740292270097">गहरा</translation>
<translation id="2430968933669123598">Google खाते को मैनेज करें, Google खाते में अपनी जानकारी, निजता, और सà¥à¤°à¤•à¥à¤·à¤¾ को मैनेज करने के लिठEnter बनाà¤à¤‚</translation>
+<translation id="2436186046335138073"><ph name="HANDLER_HOSTNAME" /> को सभी <ph name="PROTOCOL" /> लिंक खोलने दें?</translation>
<translation id="2438874542388153331">दाईं ओर कà¥à¤µà¤¾à¤¡ पंच</translation>
<translation id="2450021089947420533">'Chrome इतिहास' में आपकी गतिविधियां</translation>
<translation id="2463739503403862330">भरें</translation>
@@ -479,6 +499,7 @@
<translation id="2465655957518002998">डिलीवरी का तरीका चà¥à¤¨à¥‡à¤‚</translation>
<translation id="2465688316154986572">सà¥à¤Ÿà¥‡à¤ªà¤²</translation>
<translation id="2465914000209955735">आपने Chrome में जो फ़ाइलें डाउनलोड की हैं उनà¥à¤¹à¥‡à¤‚ मैनेज करें</translation>
+<translation id="2466004615675155314">वेब से जानकारी दिखाता है</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />नेटवरà¥à¤• निदान चलाकर देखें<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">1-से-N के कà¥à¤°à¤® में</translation>
<translation id="2470767536994572628">जब आप वीडियो के ऊपर टेकà¥à¤¸à¥à¤Ÿ, लिंक वगैरह में बदलाव करते हैं, तो दसà¥à¤¤à¤¾à¤µà¥‡à¥›, सिंगल पेज वà¥à¤¯à¥‚ और अपने मूल रोटेशन पर वापस चला जाà¤à¤—ा</translation>
@@ -499,6 +520,7 @@
<translation id="2523886232349826891">सिरà¥à¤«à¤¼ इस डिवाइस पर सेव किया गया</translation>
<translation id="2524461107774643265">ज़à¥à¤¯à¤¾à¤¦à¤¾ जानकारी जोड़ें</translation>
<translation id="2529899080962247600">इस फ़ीलà¥à¤¡ में <ph name="MAX_ITEMS_LIMIT" /> से ज़à¥à¤¯à¤¾à¤¦à¤¾ à¤à¤‚टà¥à¤°à¥€ नहीं हो सकती. इसके बाद हà¥à¤ˆ सभी à¤à¤‚टà¥à¤°à¥€ को नज़रअंदाज़ किया जाà¤à¤—ा.</translation>
+<translation id="2535585790302968248">निजी तौर पर बà¥à¤°à¤¾à¤‰à¤œà¤¼ करने के लिà¤, à¤à¤• नया गà¥à¤ªà¥à¤¤ टैब खोलें</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{और 1 और वà¥à¤¯à¤•à¥à¤¤à¤¿}one{और # और लोग}other{और # और लोग}}</translation>
<translation id="2536110899380797252">पता जोड़ें</translation>
<translation id="2539524384386349900">पता लगाà¤à¤‚</translation>
@@ -524,7 +546,14 @@
<translation id="2597378329261239068">यह दसà¥à¤¤à¤¾à¤µà¥‡à¤œà¤¼ पासवरà¥à¤¡ सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ है. कृपया पासवरà¥à¤¡ डालें.</translation>
<translation id="2609632851001447353">विविधताà¤à¤‚</translation>
<translation id="2610561535971892504">कà¥à¤²à¤¿à¤• टू कॉपी</translation>
+<translation id="2617988307566202237">Chrome यहां बताई गई जानकारी को <ph name="BEGIN_EMPHASIS" />सेव नहीं करेगा<ph name="END_EMPHASIS" />:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />आपका बà¥à¤°à¤¾à¤‰à¤œà¤¼à¤¿à¤‚ग इतिहास
+ <ph name="LIST_ITEM" />कà¥à¤•à¥€ और साइट डेटा
+ <ph name="LIST_ITEM" />फ़ॉरà¥à¤® में डाली गई जानकारी
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">सी10 (à¤à¤¨à¥à¤µà¥‡à¤²à¤ª)</translation>
+<translation id="2623663032199728144">साइट, आपकी सà¥à¤•à¥à¤°à¥€à¤¨ की जानकारी इसà¥à¤¤à¥‡à¤®à¤¾à¤² करने की अनà¥à¤®à¤¤à¤¿ मांग सकती है</translation>
<translation id="2625385379895617796">आपकी घड़ी आगे है</translation>
<translation id="262745152991669301">साइट, यूà¤à¤¸à¤¬à¥€ डिवाइसों से कनेकà¥à¤Ÿ करने की अनà¥à¤®à¤¤à¤¿ मांग सकती है</translation>
<translation id="2629325967560697240">Chrome की सबसे बेहतर सà¥à¤°à¤•à¥à¤·à¤¾ पाने के लिà¤, <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />बेहतर सà¥à¤°à¤•à¥à¤·à¤¾ की सà¥à¤µà¤¿à¤§à¤¾ चालू करें<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -558,6 +587,7 @@
<translation id="2709516037105925701">ऑटोमैटिक भरना</translation>
<translation id="2713444072780614174">सफ़ेद</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />, Chrome की सेटिंग में पैसे चà¥à¤•à¤¾à¤¨à¥‡ से जà¥à¤¡à¤¼à¥€ जानकारी और कà¥à¤°à¥‡à¤¡à¤¿à¤Ÿ कारà¥à¤¡ की जानकारी पà¥à¤°à¤¬à¤‚धित करने के लिà¤, पहले Tab और फिर Enter दबाà¤à¤‚</translation>
+<translation id="271663710482723385">फ़à¥à¤² सà¥à¤•à¥à¤°à¥€à¤¨ से बाहर निकलने के लिà¤, |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| को दबाà¤à¤‚</translation>
<translation id="2721148159707890343">अनà¥à¤°à¥‹à¤§ कामयाब रहा</translation>
<translation id="2723669454293168317">Chrome की सेटिंग में, सà¥à¤°à¤•à¥à¤·à¤¾ जांच करें</translation>
<translation id="2726001110728089263">साइड टà¥à¤°à¥‡</translation>
@@ -588,6 +618,7 @@
<translation id="2850739647070081192">नà¥à¤¯à¥‹à¤¤à¤¾ (à¤à¤¨à¥à¤µà¥‡à¤²à¤ª)</translation>
<translation id="2856444702002559011">हो सकता है कि हमलावर <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> से आपकी जानकारी (जैसे- पासवरà¥à¤¡, मैसेज या कà¥à¤°à¥‡à¤¡à¤¿à¤Ÿ कारà¥à¤¡ वगैरह) चà¥à¤°à¤¾à¤¨à¥‡ की कोशिश कर रहे हों. <ph name="BEGIN_LEARN_MORE_LINK" />ज़à¥à¤¯à¤¾à¤¦à¤¾ जानें<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">इस साइट में तंग करने वाले या गà¥à¤®à¤°à¤¾à¤¹ करने वाले विजà¥à¤žà¤¾à¤ªà¤¨ दिखाई देते हैं.</translation>
+<translation id="286512204874376891">वरà¥à¤šà¥à¤…ल कारà¥à¤¡ आपके असली कारà¥à¤¡ की पहचान ज़ाहिर नहीं होने देता है. इससे, आपको धोखाधड़ी से बचने में मदद मिलती है. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">दोसà¥à¤¤à¤¾à¤¨à¤¾</translation>
<translation id="2876489322757410363">किसी बाहरी à¤à¤ªà¥à¤²à¤¿à¤•à¥‡à¤¶à¤¨ के ज़रिठपैसे चà¥à¤•à¤¾à¤¨à¥‡ के लिठगà¥à¤ªà¥à¤¤ मोड छोड़ रहे हैं. कà¥à¤¯à¤¾ आप यह मोड बंद करना चाहते हैं?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />, Chrome की सेटिंग में सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ बà¥à¤°à¤¾à¤‰à¤œà¤¼à¤¿à¤‚ग वगैरह को मैनेज करने के लिà¤, पहले Tab और फिर Enter दबाà¤à¤‚</translation>
@@ -612,6 +643,7 @@
<translation id="2930577230479659665">हर कॉपी के बाद टà¥à¤°à¤¿à¤® करें</translation>
<translation id="2932085390869194046">पासवरà¥à¤¡ सà¥à¤à¤¾à¤à¤‚...</translation>
<translation id="2934466151127459956">सरकारी-पतà¥à¤°</translation>
+<translation id="2938225289965773019"><ph name="PROTOCOL" /> लिंक खोलें</translation>
<translation id="2941952326391522266">यह सरà¥à¤µà¤° यह पà¥à¤°à¤®à¤¾à¤£à¤¿à¤¤ नहीं कर सका कि यह <ph name="DOMAIN" /> है; इसका सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° <ph name="DOMAIN2" /> की ओर से है. à¤à¤¸à¤¾ गलत कॉनà¥à¤«à¤¼à¤¿à¤—रेशन के कारण या किसी आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¤¾ दà¥à¤µà¤¾à¤°à¤¾ आपके कनेकà¥à¤¶à¤¨ में अवरोध डालने के कारण हो सकता है.</translation>
<translation id="2943895734390379394">अपलोड करने का समय:</translation>
<translation id="2948083400971632585">आप किसी कनेकà¥à¤¶à¤¨ के लिठकॉनà¥à¤«à¤¼à¤¿à¤—र की गई किसी भी पà¥à¤°à¥‰à¤•à¥à¤¸à¥€ को सेटिंग पेज से बंद कर सकते हैं.</translation>
@@ -644,6 +676,7 @@
<translation id="3037605927509011580">हे भगवान!</translation>
<translation id="3041612393474885105">पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° जानकारी</translation>
<translation id="3044034790304486808">अपनी रिसरà¥à¤š फिर से शà¥à¤°à¥‚ करें</translation>
+<translation id="305162504811187366">Chrome रिमोट डेसà¥à¤•à¤Ÿà¥‰à¤ª का इतिहास, जिसमें टाइमसà¥à¤Ÿà¥ˆà¤‚प, होसà¥à¤Ÿ, और कà¥à¤²à¤¾à¤‡à¤‚ट सेशन आईडी शामिल हैं</translation>
<translation id="3060227939791841287">सी9 (à¤à¤¨à¥à¤µà¥‡à¤²à¤ª)</translation>
<translation id="3061707000357573562">पैच सेवा</translation>
<translation id="306573536155379004">गेम शà¥à¤°à¥‚ हो गया.</translation>
@@ -683,6 +716,7 @@
<translation id="3197136577151645743">साइट, यह जानकारी मांग सकती है कि आप इस डिवाइस का इसà¥à¤¤à¥‡à¤®à¤¾à¤² कब करते हैं</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />, Chrome की सेटिंग में, आपने जो जानकारी सिंक की है उसे मैनेज करने के लिà¤, पहले Tab और फिर Enter दबाà¤à¤‚</translation>
<translation id="320323717674993345">भà¥à¤—तान रदà¥à¤¦ करें</translation>
+<translation id="3203366800380907218">वेब से</translation>
<translation id="3207960819495026254">बà¥à¤•à¤®à¤¾à¤°à¥à¤• किया गया</translation>
<translation id="3209034400446768650">पेज पर शà¥à¤²à¥à¤• लिया जा सकता है</translation>
<translation id="3212581601480735796"><ph name="HOSTNAME" /> पर की जा रही आपकी गतिविधि पर नज़र रखी जा रही है</translation>
@@ -699,10 +733,12 @@
<translation id="3234666976984236645">इस साइट पर हमेशा महतà¥â€à¤µà¤ªà¥‚रà¥à¤£ सामगà¥à¤°à¥€ का पता लगाà¤à¤‚</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />, अपने बà¥à¤°à¤¾à¤‰à¤œà¤¼à¤° का लà¥à¤• पसंद के मà¥à¤¤à¤¾à¤¬à¤¿à¤• बनाने के लिà¤, पहले Tab और फिर Enter दबाà¤à¤‚</translation>
<translation id="3240791268468473923">मेल नहीं खाने वाले पेमेंट कà¥à¤°à¥‡à¤¡à¥‡à¤‚शियल की शीट खà¥à¤²à¥€ है</translation>
+<translation id="324180406144491771">“<ph name="HOST_NAME" />†के लिंक बà¥à¤²à¥‰à¤• किठगठहैं</translation>
<translation id="3249845759089040423">शानदार</translation>
<translation id="3252266817569339921">फ़à¥à¤°à¤¾à¤‚सीसी</translation>
<translation id="3257954757204451555">इस जानकारी के पीछे कौन है?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />, Google Calendar में जलà¥à¤¦à¥€ से नया इवेंट बनाने के लिà¤, पहले Tab दबाà¤à¤‚ और फिर Enter दबाà¤à¤‚</translation>
+<translation id="3261488570342242926">वरà¥à¤šà¥à¤…ल कारà¥à¤¡ के बारे में जानें</translation>
<translation id="3264837738038045344">Chrome की सेटिंग के बटन को मैनेज करें, Chrome की सेटिंग पर जाने के लिà¤, Enter दबाà¤à¤‚</translation>
<translation id="3266793032086590337">मान (मेल नहीं खा रहा)</translation>
<translation id="3268451620468152448">खà¥à¤²à¥‡ सतà¥à¤°</translation>
@@ -716,6 +752,7 @@
<translation id="3288238092761586174">आपके पेमेंट की पà¥à¤·à¥à¤Ÿà¤¿ करने के लिà¤, <ph name="URL" /> को अतिरिकà¥à¤¤ कदम उठाने पड़ सकते हैं</translation>
<translation id="3293642807462928945"><ph name="POLICY_NAME" /> नीति के बारे में ज़à¥à¤¯à¤¾à¤¦à¤¾ जानें</translation>
<translation id="3295444047715739395">Chrome की सेटिंग में अपने पासवरà¥à¤¡ देखें और पà¥à¤°à¤¬à¤‚धित करें</translation>
+<translation id="3303795387212510132">कà¥à¤¯à¤¾ आप <ph name="PROTOCOL_SCHEME" /> लिंक खोलने के लिà¤, à¤à¤ªà¥à¤²à¤¿à¤•à¥‡à¤¶à¤¨ को अनà¥à¤®à¤¤à¤¿ देना चाहते हैं?</translation>
<translation id="3303855915957856445">कोई खोज नतीजे नहीं मिले</translation>
<translation id="3304073249511302126">बà¥à¤²à¥‚टूथ सà¥à¤•à¥ˆà¤¨ किया जा रहा है</translation>
<translation id="3308006649705061278">संगठनातà¥à¤®à¤• इकाई (OU)</translation>
@@ -729,12 +766,6 @@
<translation id="3345782426586609320">आंखें</translation>
<translation id="3355823806454867987">पà¥à¤°à¥‰à¤•à¥à¤¸à¥€ सेटिंग बदलें...</translation>
<translation id="3360103848165129075">पैसे चà¥à¤•à¤¾à¤¨à¥‡ की हैंडलर शीट</translation>
-<translation id="3361596688432910856">Chrome नीचे दी गई जानकारी को <ph name="BEGIN_EMPHASIS" />सेव नहीं करेगा<ph name="END_EMPHASIS" />:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />आपका बà¥à¤°à¤¾à¤‰à¤œà¤¼à¤¿à¤‚ग इतिहास
- <ph name="LIST_ITEM" />कà¥à¤•à¥€ और साइट डेटा
- <ph name="LIST_ITEM" />फ़ॉरà¥à¤® में डाली गई जानकारी
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">इस नीति को हटाई गई <ph name="OLD_POLICY" /> नीति से अपने आप कॉपी किया गया था. आपको इसके बजाय, इस नीति का इसà¥à¤¤à¥‡à¤®à¤¾à¤² करना चाहिà¤.</translation>
<translation id="3364869320075768271"><ph name="URL" /> आपका वरà¥à¤šà¥à¤…ल रिà¤à¤²à¤¿à¤Ÿà¥€ वाला डिवाइस और डेटा इसà¥à¤¤à¥‡à¤®à¤¾à¤² करना चाहता है</translation>
<translation id="3366477098757335611">कारà¥à¤¡ देखें</translation>
@@ -817,7 +848,6 @@
<translation id="3587738293690942763">मिडल</translation>
<translation id="3592413004129370115">इटैलियन (à¤à¤¨à¥à¤µà¥‡à¤²à¤ª)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{आप अपना पासवरà¥à¤¡ कभी भी रीसेट कर सकते हैं. नठगà¥à¤°à¥à¤ª से जà¥à¤¡à¤¼à¤¨à¥‡ में करीब-करीब à¤à¤• दिन लगता है.}=1{आप अपना पासवरà¥à¤¡ कभी भी रीसेट कर सकते हैं. नठगà¥à¤°à¥à¤ª से जà¥à¤¡à¤¼à¤¨à¥‡ में करीब-करीब à¤à¤• दिन लगता है.}one{आप अपना पासवरà¥à¤¡ कभी भी रीसेट कर सकते हैं. नठगà¥à¤°à¥à¤ª से जà¥à¤¡à¤¼à¤¨à¥‡ में {NUM_DAYS} दिन लगता है.}other{आप अपना पासवरà¥à¤¡ कभी भी रीसेट कर सकते हैं. नठगà¥à¤°à¥à¤ª से जà¥à¤¡à¤¼à¤¨à¥‡ में {NUM_DAYS} दिन लगते हैं.}}</translation>
-<translation id="3596012367874587041">à¤à¤ªà¥à¤²à¤¿à¤•à¥‡à¤¶à¤¨ की सेटिंग</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">आपके à¤à¤¡à¤®à¤¿à¤¨ ने à¤à¤ªà¥à¤²à¤¿à¤•à¥‡à¤¶à¤¨ को बà¥à¤²à¥‰à¤• कर दिया है</translation>
<translation id="3608932978122581043">फ़ीड ओरिà¤à¤‚टेशन</translation>
@@ -860,6 +890,7 @@
<translation id="370972442370243704">'Chrome इतिहास' में, अपनी गतिविधियां देखने की सà¥à¤µà¤¿à¤§à¤¾ चालू करें</translation>
<translation id="3711895659073496551">निलंबित</translation>
<translation id="3712624925041724820">लाइसेंस खतà¥à¤® हो गà¤</translation>
+<translation id="3714633008798122362">वेब कैलेंडर</translation>
<translation id="3714780639079136834">मोबाइल डेटा या वाई-फ़ाई चालू करें</translation>
<translation id="3715597595485130451">वाई-फ़ाई से कनेकà¥à¤Ÿ करें</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />पà¥à¤°à¥‰à¤•à¥à¤¸à¥€, फायरवॉल और डीà¤à¤¨à¤à¤¸ कॉनà¥à¥žà¤¿à¤—रेशन की जाà¤à¤š करें<ph name="END_LINK" /></translation>
@@ -921,6 +952,7 @@
<translation id="3906954721959377182">टैबलेट</translation>
<translation id="3909477809443608991"><ph name="URL" /> सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ सामगà¥à¤°à¥€ चलाना चाहता है . Google आपके डिवाइस की पहचान की पà¥à¤·à¥à¤Ÿà¤¿ कर सकता है और यह साइट उसे à¤à¤•à¥à¤¸à¥‡à¤¸ कर सकती है.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">असà¥à¤µà¥€à¤•à¤¾à¤° करें</translation>
<translation id="3939773374150895049">कà¥à¤¯à¤¾ आप कारà¥à¤¡ वेरीफ़िकेशन कोड (सीवीसी) के बजाय WebAuthn का इसà¥à¤¤à¥‡à¤®à¤¾à¤² करना चाहते हैं?</translation>
<translation id="3946209740501886391">इस साइट पर हमेशा पूछें</translation>
<translation id="3947595700203588284">साइट, MIDI डिवाइसों से कनेकà¥à¤Ÿ करने की अनà¥à¤®à¤¤à¤¿ मांग सकती है</translation>
@@ -942,6 +974,7 @@
<translation id="3990250421422698716">जोग ऑफ़सेट</translation>
<translation id="3996311196211510766">साइट <ph name="ORIGIN" /> ने यह अनà¥à¤°à¥‹à¤§ किया है कि इसके सभी अनà¥à¤°à¥‹à¤§à¥‹à¤‚ पर
मूल नीति लागू होती है, लेकिन अभी यह नीति लागू नहीं की जा सकती.</translation>
+<translation id="4009243425692662128">पà¥à¤°à¤¿à¤‚ट किठजाने वाले पेजों के कॉनà¥à¤Ÿà¥‡à¤‚ट को, विशà¥à¤²à¥‡à¤·à¤£ के लिठGoogle Cloud या तीसरे पकà¥à¤· की कंपनियों को भेजा जाता है. उदाहरण के लिà¤, इसे संवेदनशील डेटा की जांच के लिठसà¥à¤•à¥ˆà¤¨ किया जा सकता है.</translation>
<translation id="4010758435855888356">कà¥à¤¯à¤¾ आप Chromium को डिवाइस का सà¥à¤Ÿà¥‹à¤°à¥‡à¤œ à¤à¤•à¥à¤¸à¥‡à¤¸ करने की अनà¥à¤®à¤¤à¤¿ देना चाहते हैं?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{पीडीà¤à¤«à¤¼ दसà¥à¤¤à¤¾à¤µà¥‡à¤œà¤¼ में {COUNT}पेज है}one{पीडीà¤à¤«à¤¼ दसà¥à¤¤à¤¾à¤µà¥‡à¤œà¤¼ में {COUNT}पेज है}other{पीडीà¤à¤«à¤¼ दसà¥à¤¤à¤¾à¤µà¥‡à¤œà¤¼ में {COUNT}पेज हैं}}</translation>
<translation id="4023431997072828269">यह फ़ॉरà¥à¤® किसी à¤à¤¸à¥‡ इंटरनेट कनेकà¥à¤¶à¤¨ की मदद से सबमिट किया जा रहा है जो सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ नहीं है, इसलिठआपकी जानकारी दूसरे लोग भी देख सकेंगे.</translation>
@@ -1036,6 +1069,7 @@
<translation id="4250680216510889253">नहीं</translation>
<translation id="4253168017788158739">नोट</translation>
<translation id="425582637250725228">हो सकता है कि किठगठबदलाव सेव ना हों.</translation>
+<translation id="425869179292622354">वरà¥à¤šà¥à¤…ल कारà¥à¤¡ की मदद से इसे और सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ बनाà¤à¤‚?</translation>
<translation id="4258748452823770588">खराब हसà¥à¤¤à¤¾à¤•à¥à¤·à¤°</translation>
<translation id="4261046003697461417">सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ दसà¥à¤¤à¤¾à¤µà¥‡à¤œà¤¼à¥‹à¤‚ को à¤à¤¨à¥‹à¤Ÿà¥‡à¤Ÿ नहीं किया जा सकता</translation>
<translation id="4265872034478892965">आपके वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤• ने अनà¥à¤®à¤¤à¤¿ दी है</translation>
@@ -1098,6 +1132,7 @@
<translation id="4434045419905280838">पॉप-अप और रीडायरेकà¥à¤Ÿ</translation>
<translation id="4435702339979719576">पोसà¥à¤Ÿà¤•à¤¾à¤°à¥à¤¡)</translation>
<translation id="443673843213245140">पà¥à¤°à¥‰à¤•à¥â€à¤¸à¥€ का उपयोग अकà¥à¤·à¤® है लेकिन कोई सà¥â€à¤ªà¤·à¥à¤Ÿ पà¥à¤°à¥‰à¤•à¥â€à¤¸à¥€ कॉनà¥à¥žà¤¿à¤—रेशन दरà¥à¤œ किया गया है.</translation>
+<translation id="4441832193888514600">अनदेखा किया गया है, कà¥à¤¯à¥‹à¤‚कि इस नीति को सिरà¥à¥ž कà¥à¤²à¤¾à¤‰à¤¡ की उपयोगकरà¥à¤¤à¤¾ नीति के तौर पर सेट किया जा सकता है.</translation>
<translation id="4450893287417543264">फिर से न दिखाà¤à¤‚</translation>
<translation id="4451135742916150903">साइट, à¤à¤šà¤†à¤ˆà¤¡à¥€ डिवाइसों से कनेकà¥à¤Ÿ करने की अनà¥à¤®à¤¤à¤¿ मांग सकती है</translation>
<translation id="4452328064229197696">आपने अभी जो पासवरà¥à¤¡ इसà¥à¤¤à¥‡à¤®à¤¾à¤² किया है वह लीक हो चà¥à¤•à¤¾ है. Google के पासवरà¥à¤¡ मैनेजर का सà¥à¤à¤¾à¤µ है कि आप सेव किठगठपासवरà¥à¤¡ की जांच करें. इस तरह आपके खाते सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ रहेंगे.</translation>
@@ -1153,6 +1188,7 @@
<translation id="4628948037717959914">फ़ोटो</translation>
<translation id="4631649115723685955">पैसे चà¥à¤•à¤¾à¤¨à¥‡ पर कैशबैक मिलेगा</translation>
<translation id="4636930964841734540">जानकारी</translation>
+<translation id="4638670630777875591">Chromium में गà¥à¤ªà¥à¤¤ मोड</translation>
<translation id="464342062220857295">खोज सà¥à¤µà¤¿à¤§à¤¾à¤à¤‚</translation>
<translation id="4644670975240021822">दूसरी तरफ़ उलटा करके रखें</translation>
<translation id="4646534391647090355">मà¥à¤à¥‡ अभी वहां ले जाà¤à¤‚</translation>
@@ -1173,6 +1209,7 @@
<translation id="4708268264240856090">आपका कनेकà¥à¤¶à¤¨ बाधित था</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Windows नेटवरà¥à¤• निदान चलाकर देखें<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426"><ph name="USERNAME" /> का पासवरà¥à¤¡</translation>
<translation id="4724144314178270921">साइट, आपके कà¥à¤²à¤¿à¤ªà¤¬à¥‹à¤°à¥à¤¡ पर टेकà¥à¤¸à¥à¤Ÿ पढ़ने और इमेज देखने की अनà¥à¤®à¤¤à¤¿ मांग सकती है</translation>
<translation id="4726672564094551039">नीतियां फिर से लोड करें</translation>
<translation id="4728558894243024398">पà¥à¤²à¥‡à¤Ÿà¤«à¤¼à¥‰à¤°à¥à¤®</translation>
@@ -1194,6 +1231,7 @@
<translation id="4757993714154412917">आपने अभी जिस साइट पर अपना पासवरà¥à¤¡ डाला है वह सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ नहीं है. अपने खातों को सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ करने के लिà¤, Chromium का सà¥à¤à¤¾à¤µ है कि आप सेव किठगठपासवरà¥à¤¡ की जांच करें.</translation>
<translation id="4758311279753947758">संपरà¥à¤• जानकारी जोड़ें</translation>
<translation id="4761104368405085019">अपना माइकà¥à¤°à¥‹à¤«à¤¼à¥‹à¤¨ उपयोग करें</translation>
+<translation id="4761869838909035636">Chrome की सà¥à¤°à¤•à¥à¤·à¤¾ जांच करें</translation>
<translation id="4764776831041365478"><ph name="URL" /> पर मौजूद वेबपेज संभवतः असà¥à¤¥à¤¾à¤¯à¥€ रूप से बंद है या उसे सà¥à¤¥à¤¾à¤¯à¥€ रूप से किसी नठवेब पते पर ले जाया गया है.</translation>
<translation id="4766713847338118463">नीचे की ओर डà¥à¤¯à¥à¤à¤² सà¥à¤Ÿà¥‡à¤ªà¤²</translation>
<translation id="4771973620359291008">अजà¥à¤žà¤¾à¤¤ गड़बड़ी आई.</translation>
@@ -1214,12 +1252,6 @@
<translation id="4819347708020428563">कà¥à¤¯à¤¾ आप डिफ़ॉलà¥à¤Ÿ वà¥à¤¯à¥‚ में वीडियो के ऊपर टेकà¥à¤¸à¥à¤Ÿ, लिंक वगैरह में बदलाव करना चाहते हैं?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />, जलà¥à¤¦à¥€ से नई Google शीट बनाने के लिà¤, पहले Tab दबाà¤à¤‚ और फिर Enter दबाà¤à¤‚</translation>
<translation id="4825507807291741242">दमदार</translation>
-<translation id="4827402517081186284">गà¥à¤ªà¥à¤¤ मोड में आप ऑनलाइन दिखते हैं:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />जब आप साइटों पर जाते हैं, तो उनà¥à¤¹à¥‡à¤‚ पता चलता है<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />नौकरी देने वाली कंपनियां या सà¥à¤•à¥‚ल, बà¥à¤°à¤¾à¤‰à¤œà¤¼à¤¿à¤‚ग गतिविधि को टà¥à¤°à¥ˆà¤• कर सकते हैं<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />इंटरनेट सेवा देने वाली कंपनियां, वेब टà¥à¤°à¥ˆà¤«à¤¼à¤¿à¤• की निगरानी कर सकती हैं<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">सà¥à¤°à¤•à¥à¤·à¤¾ चेतावनियां चालू करें</translation>
<translation id="4838327282952368871">खà¥à¤µà¤¾à¤¬ जैसा</translation>
<translation id="4840250757394056958">अपना 'Chrome इतिहास' देखें</translation>
@@ -1231,12 +1263,12 @@
<translation id="4854362297993841467">वितरण का यह तरीका उपलबà¥à¤§ नहीं है. कोई दूसरा तरीका आज़माà¤à¤‚.</translation>
<translation id="4854853140771946034">Google Keep में जलà¥à¤¦à¥€ से नया नोट बनाà¤à¤‚</translation>
<translation id="485902285759009870">कोड की पà¥à¤·à¥à¤Ÿà¤¿ की जा रही है...</translation>
+<translation id="4866506163384898554">अपना करà¥à¤¸à¤° दिखाने के लिà¤, |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| को दबाà¤à¤‚</translation>
<translation id="4876188919622883022">सरल बनाया गया वà¥à¤¯à¥‚</translation>
<translation id="4876305945144899064">कोई उपयोगकरà¥à¤¤à¤¾ नाम नहीं</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{कोई नहीं}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}one{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831"><ph name="TEXT" /> खोज</translation>
<translation id="4879491255372875719">अपने आप (डिफ़ॉलà¥à¤Ÿ)</translation>
-<translation id="4879725228911483934">यह साइट, विंडो को खोलकर आपकी सà¥à¤•à¥à¤°à¥€à¤¨ पर लगाना चाहती है</translation>
<translation id="4880827082731008257">खोज इतिहास</translation>
<translation id="4881695831933465202">खोलें</translation>
<translation id="4885256590493466218">चेकआउट के दौरान <ph name="CARD_DETAIL" /> से पैसे चà¥à¤•à¤¾à¤à¤‚</translation>
@@ -1245,6 +1277,7 @@
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">नौवां रोल</translation>
<translation id="4901778704868714008">सेव करें...</translation>
+<translation id="4905659621780993806">आपका à¤à¤¡à¤®à¤¿à¤¨ <ph name="DATE" /> को <ph name="TIME" /> पर आपका डिवाइस अपने-आप रीसà¥à¤Ÿà¤¾à¤°à¥à¤Ÿ करेगा. डिवाइस के रीसà¥à¤Ÿà¤¾à¤°à¥à¤Ÿ होने से पहले, खà¥à¤²à¥‡ हà¥à¤ सभी आइटम सेव कर लें.</translation>
<translation id="4913987521957242411">सबसे ऊपर बाईं ओर पंच</translation>
<translation id="4918221908152712722"><ph name="APP_NAME" /> इंसà¥à¤Ÿà¥‰à¤² करें (डाउनलोड करने की ज़रूरत नहीं है)</translation>
<translation id="4923459931733593730">भà¥à¤—तान</translation>
@@ -1253,6 +1286,7 @@
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, खोजने के लिठTab के बाद Enter दबाà¤à¤‚</translation>
<translation id="4930153903256238152">ज़à¥à¤¯à¤¾à¤¦à¤¾ कà¥à¤·à¤®à¤¤à¤¾</translation>
+<translation id="4940163644868678279">Chrome में गà¥à¤ªà¥à¤¤ मोड</translation>
<translation id="4943872375798546930">कोई परिणाम नहीं</translation>
<translation id="4950898438188848926">'टैब' बदलने का बटन, नठटैब पर जाने के लिठEnter दबाà¤à¤‚, <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="495170559598752135">कà¥à¤°à¤¿à¤¯à¤¾à¤à¤‚</translation>
@@ -1262,6 +1296,7 @@
<translation id="4968522289500246572">यह à¤à¤ªà¥à¤²à¤¿à¤•à¥‡à¤¶à¤¨, मोबाइल के लिठडिज़ाइन किया गया है और हो सकता है कि इसका डिसपà¥à¤²à¥‡, डिवाइस के विंडो साइज़ के हिसाब से न बदले. इस à¤à¤ªà¥à¤²à¤¿à¤•à¥‡à¤¶à¤¨ को इसà¥à¤¤à¥‡à¤®à¤¾à¤² करते समय आपको समसà¥à¤¯à¤¾à¤“ं का सामना करना पड़ सकता है या इसे रीसà¥à¤Ÿà¤¾à¤°à¥à¤Ÿ करना पड़ सकता है.</translation>
<translation id="4969341057194253438">रिकॉरà¥à¤¡à¤¿à¤‚ग मिटाà¤à¤‚</translation>
<translation id="4973922308112707173">सबसे ऊपर डà¥à¤¯à¥à¤à¤² पंच</translation>
+<translation id="4976702386844183910">पिछली बार <ph name="DATE" /> को देखा गया</translation>
<translation id="4984088539114770594">कà¥à¤¯à¤¾ आप माइकà¥à¤°à¥‹à¤«à¤¼à¥‹à¤¨ का इसà¥à¤¤à¥‡à¤®à¤¾à¤² करना चाहते हैं?</translation>
<translation id="4984339528288761049">पीआरसी5 (à¤à¤¨à¥à¤µà¥‡à¤²à¤ª)</translation>
<translation id="4989163558385430922">सभी देखें</translation>
@@ -1323,6 +1358,7 @@
<translation id="5138227688689900538">कम दिखाà¤à¤‚</translation>
<translation id="5145883236150621069">नीति पà¥à¤°à¤¤à¤¿à¤¸à¤¾à¤¦ में गड़बड़ी कोड मौजूद है</translation>
<translation id="5146995429444047494"><ph name="ORIGIN" /> के लिठसूचनाओं को बà¥à¤²à¥‰à¤• किया गया है</translation>
+<translation id="514704532284964975"><ph name="URL" /> को इस बात की अनà¥à¤®à¤¤à¤¿ चाहिठकि जब आप अपने फ़ोन से à¤à¤¨à¤à¤«à¤¼à¤¸à¥€ की सà¥à¤µà¤¿à¤§à¤¾ वाले डिवाइसों पर टैप करें, तब वह उन पर मौजूद जानकारी देख सके और उसमें बदलाव कर सके.</translation>
<translation id="5148809049217731050">सीधा करके रखें</translation>
<translation id="515292512908731282">सी4 (à¤à¤¨à¥à¤µà¥‡à¤²à¤ª)</translation>
<translation id="5158275234811857234">कवर</translation>
@@ -1347,6 +1383,7 @@
<translation id="5215116848420601511">Google Pay का इसà¥à¤¤à¥‡à¤®à¤¾à¤² करने वाले भà¥à¤—तान के तरीके और पते</translation>
<translation id="5215363486134917902">फ़ोलियो-à¤à¤¸à¤ªà¥€</translation>
<translation id="521659676233207110">टà¥à¤°à¥‡ 13</translation>
+<translation id="5216942107514965959">साइट पर पिछली बार आज गà¤</translation>
<translation id="5222812217790122047">ईमेल आवशà¥à¤¯à¤• है</translation>
<translation id="5230733896359313003">शिपिंग पता</translation>
<translation id="5230815978613972521">बी8</translation>
@@ -1367,7 +1404,6 @@
<translation id="5283044957620376778">बी1</translation>
<translation id="5284295735376057059">दसà¥à¤¤à¤¾à¤µà¥‡à¥› की जानकारी</translation>
<translation id="528468243742722775">खतà¥à¤®</translation>
-<translation id="5284909709419567258">नेटवरà¥à¤• के पते</translation>
<translation id="5285570108065881030">सेव किठगठसभी पासवरà¥à¤¡ दिखाà¤à¤‚</translation>
<translation id="5287240709317226393">कà¥à¤•à¥€ दिखाà¤à¤‚</translation>
<translation id="5287456746628258573">यह साइट à¤à¤• पà¥à¤°à¤¾à¤¨à¥‡ सà¥à¤°à¤•à¥à¤·à¤¾ कॉनà¥à¤«à¤¼à¤¿à¤—रेशन का इसà¥à¤¤à¥‡à¤®à¤¾à¤² करती है. इस वजह से, साइट पर भेजी जाने वाली आपकी जानकारी (उदाहरण के लिà¤, पासवरà¥à¤¡ या कà¥à¤°à¥‡à¤¡à¤¿à¤Ÿ कारà¥à¤¡ नंबर वगैरह) को कोई और देख सकता है.</translation>
@@ -1451,6 +1487,7 @@
<translation id="5556459405103347317">फिर लोड करें</translation>
<translation id="5560088892362098740">समयसीमा समापà¥à¤¤à¤¿ तारीख</translation>
<translation id="55635442646131152">दसà¥à¤¤à¤¾à¤µà¥‡à¤œà¤¼ की आउटलाइन</translation>
+<translation id="5565613213060953222">गà¥à¤ªà¥à¤¤ टैब खोलें</translation>
<translation id="5565735124758917034">सकà¥à¤°à¤¿à¤¯</translation>
<translation id="5570825185877910964">खाते की सà¥à¤°à¤•à¥à¤·à¤¾ करें</translation>
<translation id="5571083550517324815">इस पते से पिक अप नहीं किया जा सकता. कोई दूसरा पता चà¥à¤¨à¥‡à¤‚.</translation>
@@ -1533,6 +1570,7 @@
<translation id="5869522115854928033">सेव किठगठपासवरà¥à¤¡</translation>
<translation id="5873013647450402046">बैंक आपकी पहचान की पà¥à¤·à¥à¤Ÿà¤¿ करना चाहता है.</translation>
<translation id="5887400589839399685">कारà¥à¤¡ सेव किया गया</translation>
+<translation id="5887687176710214216">साइट पर पिछली बार कल गà¤</translation>
<translation id="5895138241574237353">फिर से पà¥à¤°à¤¾à¤°à¤‚भ करें</translation>
<translation id="5895187275912066135">जारी करने की तारीख</translation>
<translation id="5901630391730855834">पीला</translation>
@@ -1546,6 +1584,7 @@
<translation id="5921639886840618607">कारà¥à¤¡ को Google खाते में सेव करें?</translation>
<translation id="5922853866070715753">करीब-करीब हो गया है</translation>
<translation id="5932224571077948991">साइट में तंग करने वाले या गà¥à¤®à¤°à¤¾à¤¹ करने वाले विजà¥à¤žà¤¾à¤ªà¤¨ दिखाई देते हैं</translation>
+<translation id="5938153366081463283">वरà¥à¤šà¥à¤…ल कारà¥à¤¡ जोड़ें</translation>
<translation id="5938793338444039872">टà¥à¤°à¥‰à¤¯</translation>
<translation id="5946937721014915347"><ph name="SITE_NAME" /> को खोला जा रहा है…</translation>
<translation id="5951495562196540101">उपभोकà¥à¤¤à¤¾ खाते (पैकेज किया गया लाइसेंस मौजूद है) के साथ नामांकन नहीं कर सकते.</translation>
@@ -1610,6 +1649,7 @@
<translation id="6120179357481664955">कà¥à¤¯à¤¾ आप चाहते हैं कि हम आपका UPI आईडी रखें?</translation>
<translation id="6124432979022149706">Chrome Enterprise Connectors</translation>
<translation id="6127379762771434464">आइटम निकाला गया</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Chrome में गà¥à¤ªà¥à¤¤ मोड की सà¥à¤µà¤¿à¤§à¤¾ के बारे में ज़à¥à¤¯à¤¾à¤¦à¤¾ जानें<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">सभी केबल जांचें और आपके उपयोग किठजा रहे सभी राउटर, मॉडेम या अनà¥à¤¯ नेटवरà¥à¤•
डिवाइस को 'फिर चालू करें'.</translation>
<translation id="614940544461990577">यह आज़माकर देखें:</translation>
@@ -1622,7 +1662,6 @@
<translation id="6169916984152623906">अब आप निजी रूप से बà¥à¤°à¤¾à¤‰à¤œà¤¼ कर सकते हैं और इस डिवाइस का उपयोग करने वाले दूसरे लोगों को आपकी गतिविधि दिखाई नहीं देगी. लेकिन डाउनलोड और बà¥à¤•à¤®à¤¾à¤°à¥à¤• सेव होंगे.</translation>
<translation id="6177128806592000436">इस साइट से आपका कनेकà¥â€à¤¶à¤¨ सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ नहीं है</translation>
<translation id="6180316780098470077">बार-बार कोशिश किठजाने के बीच का समय</translation>
-<translation id="619448280891863779">साइट, विंडो को खोलकर आपकी सà¥à¤•à¥à¤°à¥€à¤¨ पर लगाने के लिठपूछ सकती है</translation>
<translation id="6196640612572343990">तीसरे पकà¥à¤· की कà¥à¤•à¥€ बà¥à¤²à¥‰à¤• करें</translation>
<translation id="6203231073485539293">अपना इंटरनेट कनेकà¥à¤¶à¤¨ जांचे</translation>
<translation id="6218753634732582820">कà¥à¤°à¥‹à¤®à¤¿à¤¯à¤® से पता निकालें?</translation>
@@ -1645,7 +1684,7 @@
<translation id="6272383483618007430">Google अपडेट</translation>
<translation id="6276112860590028508">आपकी रीडिंग लिसà¥à¤Ÿ के पेज यहां दिखाई देंगे</translation>
<translation id="627746635834430766">अगली बार तेज़ी से भà¥à¤—तान करने के लिà¤, अपने कारà¥à¤¡ और बिलिंग पते को अपने Google खाते में सेव करें.</translation>
-<translation id="6279098320682980337">वरà¥à¤šà¥à¤…ल कारà¥à¤¡ नंबर नहीं भरा गया? कारà¥à¤¡ का बà¥à¤¯à¥Œà¤°à¤¾ कॉपी करने के लिठउस पर कà¥à¤²à¤¿à¤• करें</translation>
+<translation id="6279183038361895380">अपना करà¥à¤¸à¤° दिखाने के लिठ|<ph name="ACCELERATOR" />| दबाà¤à¤‚</translation>
<translation id="6280223929691119688">इस पते पर वितरित नहीं किया जा सकता. कोई दूसरा पता चà¥à¤¨à¥‡à¤‚.</translation>
<translation id="6282194474023008486">पोसà¥à¤Ÿà¤² कोड</translation>
<translation id="6285507000506177184">'Chrome में डाउनलोड मैनेज करें' बटन. आपने Chrome में जो फ़ाइलें डाउनलोड की हैं उनà¥à¤¹à¥‡à¤‚ मैनेज करने के लिà¤, Enter दबाà¤à¤‚</translation>
@@ -1653,6 +1692,7 @@
<translation id="6290238015253830360">आपके सà¥à¤à¤¾à¤ हà¥à¤ लेख यहां दिखाई देते हैं</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{आपका डिवाइस अभी रीसà¥à¤Ÿà¤¾à¤°à¥à¤Ÿ होगा}=1{आपका डिवाइस 1 सेकंड में रीसà¥à¤Ÿà¤¾à¤°à¥à¤Ÿ होगा}one{आपका डिवाइस # सेकंड में रीसà¥à¤Ÿà¤¾à¤°à¥à¤Ÿ होगा}other{आपका डिवाइस # सेकंड में रीसà¥à¤Ÿà¤¾à¤°à¥à¤Ÿ होगा}}</translation>
<translation id="6302269476990306341">'Chrome में Google Assistant' को रोका जा रहा है</translation>
<translation id="6305205051461490394"><ph name="URL" /> तक नहीं पहà¥à¤‚चा जा सकता.</translation>
<translation id="6312113039770857350">वेबपेज उपलबà¥à¤§ नहीं है</translation>
@@ -1726,6 +1766,7 @@
<translation id="6529602333819889595">मिटाना &amp;फिर से करें</translation>
<translation id="6545864417968258051">बà¥à¤²à¥‚टूथ सà¥à¤•à¥ˆà¤¨ करना</translation>
<translation id="6547208576736763147">बाईं ओर डà¥à¤¯à¥à¤à¤² पंच</translation>
+<translation id="6554732001434021288">साइट पर पिछली बार <ph name="NUM_DAYS" /> दिन पहले गà¤</translation>
<translation id="6556866813142980365">फिर से करें</translation>
<translation id="6569060085658103619">आप à¤à¤• à¤à¤•à¥à¤¸à¤Ÿà¥‡à¤‚शन पेज देख रहे हैं</translation>
<translation id="6573200754375280815">दाईं ओर डà¥à¤¯à¥à¤à¤² पंच</translation>
@@ -1786,7 +1827,6 @@
<translation id="6757797048963528358">आपका डिवाइस निषà¥à¤•à¥à¤°à¤¿à¤¯ हो गया है.</translation>
<translation id="6767985426384634228">कà¥à¤¯à¤¾ आप पता अपडेट करना चाहते हैं?</translation>
<translation id="6768213884286397650">हगाकी (पोसà¥à¤Ÿà¤•à¤¾à¤°à¥à¤¡)</translation>
-<translation id="6774185088257932239">गà¥à¤ªà¥à¤¤ मोड के बारे में <ph name="BEGIN_LINK" />ज़à¥à¤¯à¤¾à¤¦à¤¾ जानें<ph name="END_LINK" /></translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">बैंगनी</translation>
<translation id="6786747875388722282">à¤à¤•à¥â€à¤¸à¤Ÿà¥‡à¤‚शन</translation>
@@ -1870,7 +1910,6 @@
<translation id="706295145388601875">Chrome की सेटिंग में वेब पते जोड़ें और मैनेज करें</translation>
<translation id="7064851114919012435">संपरà¥à¤• जानकारी</translation>
<translation id="7068733155164172741"><ph name="OTP_LENGTH" />-अंकों वाला कोड डालें</translation>
-<translation id="7070090581017165256">इस साइट के बारे में</translation>
<translation id="70705239631109039">आपका कनेकà¥à¤¶à¤¨ पूरी तरह सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ नहीं है</translation>
<translation id="7075452647191940183">अनà¥à¤°à¥‹à¤§ में बहà¥à¤¤ ज़à¥à¤¯à¤¾à¤¦à¤¾ डेटा भेजा गया है</translation>
<translation id="7079718277001814089">इस साइट में मैलवेयर है</translation>
@@ -1887,6 +1926,12 @@
<translation id="7111012039238467737">(मानà¥à¤¯)</translation>
<translation id="7118618213916969306">कà¥à¤²à¤¿à¤ªà¤¬à¥‹à¤°à¥à¤¡ यूआरà¤à¤², <ph name="SHORT_URL" /> खोजें</translation>
<translation id="7119414471315195487">दूसरे टैब या पà¥à¤°à¥‹à¤—à¥à¤°à¤¾à¤® बंद करें</translation>
+<translation id="7129355289156517987">Chromium में खोले गठसभी गà¥à¤ªà¥à¤¤ टैब बंद करने पर, इन टैब में हà¥à¤ˆ आपकी गतिविधि का डेटा इस डिवाइस से हटा दिया जाता है:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />बà¥à¤°à¤¾à¤‰à¤œà¤¼à¤¿à¤‚ग गतिविधि<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />खोज इतिहास<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />फ़ॉरà¥à¤® में डाली गई जानकारी<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">इस पते पर शिप नहीं किया जा सकता. कोई दूसरा पता चà¥à¤¨à¥‡à¤‚.</translation>
<translation id="7132939140423847331">आपके à¤à¤¡à¤®à¤¿à¤¨ ने इस डेटा को कॉपी किठजाने पर रोक लगाई है.</translation>
<translation id="7135130955892390533">सà¥à¤¥à¤¿à¤¤à¤¿ दिखाà¤à¤‚</translation>
@@ -1909,6 +1954,7 @@
<translation id="7192203810768312527"><ph name="SIZE" /> जगह खाली करता है. आपकी अगली विज़िट पर कà¥à¤› साइटें ज़à¥à¤¯à¤¾à¤¦à¤¾ धीमे लोड हो सकती हैं.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">आपका à¤à¤¡à¤®à¤¿à¤¨ यह देख सकता है:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, निजी तौर पर बà¥à¤°à¤¾à¤‰à¤œà¤¼ करने के लिà¤, पहले Tab और फिर Enter दबाकर à¤à¤• नया गà¥à¤ªà¥à¤¤ टैब खोलें</translation>
<translation id="7202346780273620635">लेटर-à¤à¤•à¥à¤¸à¥à¤Ÿà¥à¤°à¤¾</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> सà¥à¤°à¤•à¥à¤·à¤¾ मानकों का पालन नहीं करता.</translation>
<translation id="7210993021468939304">कंटेनर के अंदर Linux गतिविधि कर सकते हैं और Linux à¤à¤ªà¥à¤²à¤¿à¤•à¥‡à¤¶à¤¨ इंसà¥à¤Ÿà¥‰à¤² करके चला सकते हैं</translation>
@@ -1940,13 +1986,15 @@
<translation id="7304562222803846232">Google खाते की निजता सेटिंग मैनेज करें</translation>
<translation id="7305756307268530424">धीरे-धीरे शà¥à¤°à¥‚ करें</translation>
<translation id="7308436126008021607">बैकगà¥à¤°à¤¾à¤‰à¤‚ड सिंक</translation>
+<translation id="7310392214323165548">डिवाइस जलà¥à¤¦ ही रीसà¥à¤Ÿà¤¾à¤°à¥à¤Ÿ होगा</translation>
<translation id="7319430975418800333">à¤3</translation>
-<translation id="7320336641823683070">कनेकà¥à¤¶à¤¨ संबंधी सहायता</translation>
+<translation id="7320336641823683070">कनेकà¥à¤¶à¤¨ से जà¥à¤¡à¤¼à¥€ सहायता</translation>
<translation id="7323804146520582233">"<ph name="SECTION" />" सेकà¥à¤¶à¤¨ को छिपाà¤à¤‚</translation>
<translation id="733354035281974745">डिवाइस का सà¥à¤¥à¤¾à¤¨à¥€à¤¯ खाता बदलें</translation>
<translation id="7334320624316649418">&amp;पà¥à¤¨: कà¥à¤°à¤®à¤¿à¤¤ करना फिर से करें</translation>
<translation id="7335157162773372339">साइट, आपके कैमरे का इसà¥à¤¤à¥‡à¤®à¤¾à¤² करने की अनà¥à¤®à¤¤à¤¿ मांग सकती है</translation>
<translation id="7337248890521463931">और लाइनें दिखाà¤à¤‚</translation>
+<translation id="7337418456231055214">वरà¥à¤šà¥à¤…ल कारà¥à¤¡ नंबर नहीं भरा गया? कारà¥à¤¡ की जानकारी कॉपी करने के लिà¤, उस पर कà¥à¤²à¤¿à¤• करें. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">आपके पà¥à¤²à¥‡à¤Ÿà¤«à¤¼à¥‰à¤°à¥à¤® पर उपलबà¥à¤§ नहीं है.</translation>
<translation id="733923710415886693">पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° पारदरà¥à¤¶à¤¿à¤¤à¤¾ के माधà¥à¤¯à¤® से सरà¥à¤µà¤° के पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° को पà¥à¤°à¤•à¤Ÿ नहीं किया गया.</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1969,6 +2017,7 @@
<translation id="7378627244592794276">नहीं</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">लागू नहीं</translation>
+<translation id="7388594495505979117">{0,plural, =1{आपका डिवाइस 1 मिनट में रीसà¥à¤Ÿà¤¾à¤°à¥à¤Ÿ होगा}one{आपका डिवाइस # मिनट में रीसà¥à¤Ÿà¤¾à¤°à¥à¤Ÿ होगा}other{आपका डिवाइस # मिनट में रीसà¥à¤Ÿà¤¾à¤°à¥à¤Ÿ होगा}}</translation>
<translation id="7390545607259442187">कारà¥à¤¡ की पà¥à¤·à¥à¤Ÿà¤¿ करें</translation>
<translation id="7392089738299859607">पता अपडेट करें</translation>
<translation id="7399802613464275309">सà¥à¤°à¤•à¥à¤·à¤¾ जांच</translation>
@@ -2005,6 +2054,12 @@
<translation id="7485870689360869515">कोई डेटा नहीं मिला</translation>
<translation id="7495528107193238112">इस कॉनà¥à¤Ÿà¥‡à¤‚ट को बà¥à¤²à¥‰à¤• कर दिया गया है. समसà¥à¤¯à¤¾ को ठीक करने के लिà¤, साइट के मालिक से संपरà¥à¤• करें.</translation>
<translation id="7497998058912824456">दसà¥à¤¤à¤¾à¤µà¥‡à¤œà¤¼ बनाने के लिठबटन, जलà¥à¤¦à¥€ से नया Google दसà¥à¤¤à¤¾à¤µà¥‡à¤œà¤¼ बनाने के लिठEnter दबाà¤à¤‚</translation>
+<translation id="7506488012654002225">Chromium यहां बताई गई जानकारी को <ph name="BEGIN_EMPHASIS" />सेव नहीं करेगा<ph name="END_EMPHASIS" />:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />आपका बà¥à¤°à¤¾à¤‰à¤œà¤¼à¤¿à¤‚ग इतिहास
+ <ph name="LIST_ITEM" />कà¥à¤•à¥€ और साइट डेटा
+ <ph name="LIST_ITEM" />फ़ॉरà¥à¤® में डाली गई जानकारी
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">वापस लौटाया हà¥à¤† नीति डिवाइस आईडी खाली है या उसका मिलान वरà¥à¤¤à¤®à¤¾à¤¨ डिवाइस आईडी से नहीं होता है</translation>
<translation id="7508870219247277067">à¤à¤µà¥‹à¤•à¥ˆà¤¡à¥‹ हरा</translation>
<translation id="7511955381719512146">आप जिस वाई-फ़ाई का उपयोग कर रहे हैं, उसके लिठआपको <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> पर जाने की ज़रूरत पड़ सकती है.</translation>
@@ -2118,7 +2173,6 @@
<translation id="7813600968533626083">Chrome से फ़ॉरà¥à¤® सà¥à¤à¤¾à¤µ को निकालें?</translation>
<translation id="781440967107097262">कà¥à¤¯à¤¾ आप कà¥à¤²à¤¿à¤ªà¤¬à¥‹à¤°à¥à¤¡ को शेयर करना चाहते हैं?</translation>
<translation id="7815407501681723534">'<ph name="SEARCH_STRING" />' के लिठ<ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> मिले</translation>
-<translation id="782125616001965242">इस साइट के बारे में जानकारी दिखाà¤à¤‚</translation>
<translation id="782886543891417279">आप जिस वाई-फ़ाई का उपयोग कर रहे हैं (<ph name="WIFI_NAME" />) आपको उसके लॉगिन पेज पर जाने की ज़रूरत पड़ सकती है.</translation>
<translation id="7836231406687464395">पोसà¥à¤Ÿà¤«à¤¼à¤¿à¤•à¥à¤¸ (à¤à¤¨à¥à¤µà¥‡à¤²à¤ª)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{कोई नहीं}=1{à¤à¤• à¤à¤ªà¥à¤²à¤¿à¤•à¥‡à¤¶à¤¨ (<ph name="EXAMPLE_APP_1" />)}=2{दो à¤à¤ªà¥à¤²à¤¿à¤•à¥‡à¤¶à¤¨ (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}one{# à¤à¤ªà¥à¤²à¤¿à¤•à¥‡à¤¶à¤¨ (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}other{# à¤à¤ªà¥à¤²à¤¿à¤•à¥‡à¤¶à¤¨ (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}}</translation>
@@ -2135,7 +2189,6 @@
<translation id="7888575728750733395">पà¥à¤°à¤¿à¤‚ट रेंडरिंग इंटेंट</translation>
<translation id="7894280532028510793">अगर सà¥à¤ªà¥‡à¤²à¤¿à¤‚ग सही है, तो <ph name="BEGIN_LINK" />Network Diagnostics à¤à¤ªà¥à¤²à¤¿à¤•à¥‡à¤¶à¤¨ चलाकर देखें<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">सी3 (à¤à¤¨à¥à¤µà¥‡à¤²à¤ª)</translation>
-<translation id="7931318309563332511">अजà¥à¤žà¤¾à¤¤</translation>
<translation id="793209273132572360">कà¥à¤¯à¤¾ आप पता अपडेट करना चाहते हैं?</translation>
<translation id="7932579305932748336">कोट</translation>
<translation id="79338296614623784">मानà¥à¤¯ फ़ोन नंबर डालें</translation>
@@ -2160,13 +2213,14 @@
<translation id="7976214039405368314">बहà¥à¤¤ सारे अनà¥à¤°à¥‹à¤§</translation>
<translation id="7977538094055660992">आउटपà¥à¤Ÿ डिवाइस</translation>
<translation id="7977894662897852582">ईडीपी</translation>
+<translation id="7981260203882740562">इससे जोड़ा गया है</translation>
<translation id="798134797138789862">साइट, वरà¥à¤šà¥à¤…ल रिà¤à¤²à¤¿à¤Ÿà¥€ डिवाइस और डेटा का इसà¥à¤¤à¥‡à¤®à¤¾à¤² करने की अनà¥à¤®à¤¤à¤¿ मांग सकती है</translation>
<translation id="7984945080620862648">आप इस समय <ph name="SITE" /> पर विज़िट नहीं कर सकते हैं कà¥à¤¯à¥‹à¤‚कि वेबसाइट ने à¤à¤¸à¥‡ अवà¥à¤¯à¤µà¤¸à¥à¤¥à¤¿à¤¤ पà¥à¤°à¤®à¤¾à¤£à¤¿à¤•à¤¤à¤¾ भेजे हैं जिनà¥à¤¹à¥‡à¤‚ Chrome संसाधित नहीं कर सकता. नेटवरà¥à¤• की तà¥à¤°à¥à¤Ÿà¤¿à¤¯à¤¾à¤‚ और हमले आमतौर पर असà¥à¤¥à¤¾à¤¯à¥€ होते हैं, इसलिठसंभवत: यह पेज बाद में काम करेगा.</translation>
-<translation id="79859296434321399">'बà¥à¥€ हà¥à¤ˆ वासà¥à¤¤à¤µà¤¿à¤•à¤¤à¤¾' की सामगà¥à¤°à¥€ देखने के लिà¤, ARCore इंसà¥à¤Ÿà¥‰à¤² करें</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">बाइंड</translation>
<translation id="7992044431894087211"><ph name="APPLICATION_TITLE" /> के साथ फिर से सà¥à¤•à¥à¤°à¥€à¤¨ शेयर की जा रही है</translation>
<translation id="7995512525968007366">बताया नहीं गया है</translation>
+<translation id="7998269595945679889">गà¥à¤ªà¥à¤¤ टैब वाला बटन खोलें और à¤à¤• नया गà¥à¤ªà¥à¤¤ टैब खोलकर निजी तौर पर बà¥à¤°à¤¾à¤‰à¤œà¤¼ करने के लिà¤, Enter दबाà¤à¤‚</translation>
<translation id="800218591365569300">जगह खाली करने के लिठदूसरे टैब या पà¥à¤°à¥‹à¤—à¥à¤°à¤¾à¤® बंद करके देखें.</translation>
<translation id="8004582292198964060">बà¥à¤°à¤¾à¤‰à¤œà¤¼à¤°</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{इस कारà¥à¤¡ और इसके बिलिंग पते को सेव किया जाà¤à¤—ा. <ph name="USER_EMAIL" /> में साइन इन रहने पर आप इसका इसà¥à¤¤à¥‡à¤®à¤¾à¤² कर पाà¤à¤‚गे.}one{ये कारà¥à¤¡ और इनके बिलिंग पते सेव किठजाà¤à¤‚गे. <ph name="USER_EMAIL" /> में साइन इन रहने पर आप उनका इसà¥à¤¤à¥‡à¤®à¤¾à¤² कर पाà¤à¤‚गे.}other{ये कारà¥à¤¡ और इनके बिलिंग पते सेव किठजाà¤à¤‚गे. <ph name="USER_EMAIL" /> में साइन इन रहने पर आप उनका इसà¥à¤¤à¥‡à¤®à¤¾à¤² कर पाà¤à¤‚गे.}}</translation>
@@ -2226,6 +2280,7 @@
<translation id="8202370299023114387">विरोध</translation>
<translation id="8206978196348664717">पीआरसी4 (à¤à¤¨à¥à¤µà¥‡à¤²à¤ª)</translation>
<translation id="8211406090763984747">कनेकà¥à¤¶à¤¨ सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ है</translation>
+<translation id="8217240300496046857">साइटें उन कà¥à¤•à¥€ का इसà¥à¤¤à¥‡à¤®à¤¾à¤² नहीं कर सकतीं जिनसे वेब पर आपको टà¥à¤°à¥ˆà¤• किया जा सकता है. हो सकता है कि कà¥à¤› साइटों पर सà¥à¤µà¤¿à¤§à¤¾à¤à¤‚ ठीक से काम न करें.</translation>
<translation id="8218327578424803826">सौंपा गया सà¥â€à¤¥à¤¾à¤¨:</translation>
<translation id="8220146938470311105">सी7/सी6 (à¤à¤¨à¥à¤µà¥‡à¤²à¤ª)</translation>
<translation id="8225771182978767009">जिस वà¥à¤¯à¤•à¥à¤¤à¤¿ ने इस कंपà¥à¤¯à¥‚टर को सेट किया है, उसने इस साइट को बà¥à¤²à¥‰à¤• करना चà¥à¤¨à¤¾ है.</translation>
@@ -2266,14 +2321,9 @@
<translation id="830498451218851433">फ़ोलà¥à¤¡ हालà¥à¥ž</translation>
<translation id="8307358339886459768">छोटे आकार वाली फ़ोटो</translation>
<translation id="8307888238279532626">इंसà¥à¤Ÿà¥‰à¤² किठगठà¤à¤ªà¥à¤²à¤¿à¤•à¥‡à¤¶à¤¨ और उनका कितनी बार इसà¥à¤¤à¥‡à¤®à¤¾à¤² किया जाता है</translation>
+<translation id="8317207217658302555">ARCore को अपडेट करें?</translation>
<translation id="831997045666694187">शाम</translation>
<translation id="8321476692217554900">सूचनाà¤à¤‚</translation>
-<translation id="8328484624016508118">सभी गà¥à¤ªà¥à¤¤ टैब बंद करने के बाद, Chrome इन चीज़ों को मिटाता है:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />इस डिवाइस से आपकी बà¥à¤°à¤¾à¤‰à¤œà¤¼à¤¿à¤‚ग गतिविधि<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />इस डिवाइस से आपका खोज इतिहास<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />फ़ॉरà¥à¤® में डाली गई जानकारी<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489"><ph name="HOST_NAME" /> का à¤à¤•à¥à¤¸à¥‡à¤¸ देने से मना किया गया था</translation>
<translation id="833262891116910667">हाइलाइट करें</translation>
<translation id="8339163506404995330"><ph name="LANGUAGE" /> भाषा के पेज का अनà¥à¤µà¤¾à¤¦ नहीं किया जाà¤à¤—ा</translation>
@@ -2325,6 +2375,7 @@
<translation id="8507227106804027148">कमांड लाइन</translation>
<translation id="8508648098325802031">सरà¥à¤š आइकॉन</translation>
<translation id="8511402995811232419">कà¥à¤•à¥€ मैनेज करें</translation>
+<translation id="8519753333133776369">à¤à¤¸à¤¾ à¤à¤šà¤†à¤ˆà¤¡à¥€ डिवाइस जिसे à¤à¤¡à¤®à¤¿à¤¨ ने अनà¥à¤®à¤¤à¤¿ दी है</translation>
<translation id="8522552481199248698">Chrome से आप अपने Google खाते की सà¥à¤°à¤•à¥à¤·à¤¾ कर सकते हैं और अपना पासवरà¥à¤¡ बदल सकते हैं.</translation>
<translation id="8530813470445476232">Chrome की सेटिंग में अपना बà¥à¤°à¤¾à¤‰à¤œà¤¼à¤¿à¤‚ग इतिहास, कà¥à¤•à¥€, कैश मेमोरी वगैरह मिटाà¤à¤‚</translation>
<translation id="8533619373899488139">&lt;strong&gt;chrome://policy&lt;/strong&gt; पर जाकर, बà¥à¤²à¥‰à¤• किठगठयूआरà¤à¤² की सूची और à¤à¤¸à¥€ नीतियां देखें जिनà¥à¤¹à¥‡à¤‚ आपके à¤à¤¡à¤®à¤¿à¤¨ ने लागू किया है.</translation>
@@ -2336,7 +2387,6 @@
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{अनà¥à¤®à¤¤à¤¿ रीसेट करें}one{अनà¥à¤®à¤¤à¤¿ रीसेट करें}other{अनà¥à¤®à¤¤à¤¿à¤¯à¤¾à¤‚ रीसेट करें}}</translation>
<translation id="8555010941760982128">चेकआउट के समय इस कोड का इसà¥à¤¤à¥‡à¤®à¤¾à¤² करें</translation>
<translation id="8557066899867184262">कारà¥à¤¡ वेरीफ़िकेशन कोड (सीवीसी) आपके कारà¥à¤¡ के पीछे मौजूद होता है.</translation>
-<translation id="8558485628462305855">'बà¥à¥€ हà¥à¤ˆ वासà¥à¤¤à¤µà¤¿à¤•à¤¤à¤¾' की सामगà¥à¤°à¥€ देखने के लिà¤, ARCore अपडेट करें</translation>
<translation id="8559762987265718583"><ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> से à¤à¤• निजी कनेकà¥â€à¤¶à¤¨ सà¥â€à¤¥à¤¾à¤ªà¤¿à¤¤ नहीं किया जा सकता कà¥â€à¤¯à¥‹à¤‚कि आपके डिवाइस का तारीख और समय (<ph name="DATE_AND_TIME" />) गलत है.</translation>
<translation id="8564182942834072828">अलग-अलग दसà¥à¤¤à¤¾à¤µà¥‡à¤œà¤¼/बिना कà¥à¤°à¤® के लगाई गई कॉपी</translation>
<translation id="8564985650692024650">अगर आपने अपने <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> पासवरà¥à¤¡ का दूसरी साइटों पर दोबारा इसà¥à¤¤à¥‡à¤®à¤¾à¤² किया है, तो कà¥à¤°à¥‹à¤®à¤¿à¤¯à¤® आपको उसे रीसेट करने का सà¥à¤à¤¾à¤µ देता है.</translation>
@@ -2356,6 +2406,7 @@
<translation id="865032292777205197">मोशन सेंसर</translation>
<translation id="8663226718884576429">ऑरà¥à¤¡à¤° की खास बातें, <ph name="TOTAL_LABEL" />, ज़à¥à¤¯à¤¾à¤¦à¤¾ जानकारी</translation>
<translation id="8666678546361132282">अंगà¥à¤°à¥‡à¤œà¤¼à¥€</translation>
+<translation id="8669306706049782872">विंडो खोलने और उनà¥à¤¹à¥‡à¤‚ पà¥à¤²à¥‡à¤¸ करने के लिà¤, यह साइट आपकी सà¥à¤•à¥à¤°à¥€à¤¨ की जानकारी का इसà¥à¤¤à¥‡à¤®à¤¾à¤² करेगी</translation>
<translation id="867224526087042813">हसà¥à¤¤à¤¾à¤•à¥à¤·à¤°</translation>
<translation id="8676424191133491403">बिना देरी के</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, उतà¥à¤¤à¤°, <ph name="ANSWER" /></translation>
@@ -2382,6 +2433,7 @@
<translation id="8731544501227493793">'पासवरà¥à¤¡ पà¥à¤°à¤¬à¤‚धित करें' बटन, Chrome की सेटिंग में अपने पासवरà¥à¤¡ देखने और पà¥à¤°à¤¬à¤‚धित करने के लिठEnter दबाà¤à¤‚</translation>
<translation id="8734529307927223492">आपके <ph name="DEVICE_TYPE" /> को <ph name="MANAGER" /> पà¥à¤°à¤¬à¤‚धित करता है</translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, निजी रूप से बà¥à¤°à¤¾à¤‰à¤œà¤¼ करने के लिà¤, पहले Tab और फिर Enter दबाकर à¤à¤• नई गà¥à¤ªà¥à¤¤ विंडो खोलें</translation>
+<translation id="8737685506611670901"><ph name="REPLACED_HANDLER_TITLE" /> के बजाय <ph name="PROTOCOL" /> लिंक खोलें</translation>
<translation id="8738058698779197622">सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ कनेकà¥â€à¤¶à¤¨ सà¥â€à¤¥à¤¾à¤ªà¤¿à¤¤ करने के लिà¤, आपकी घड़ी को ठीक से सेट किठजाने की आवशà¥â€à¤¯à¤•à¤¤à¤¾ है. à¤à¤¸à¤¾ इसलिठकà¥â€à¤¯à¥‹à¤‚कि वेबसाइटों दà¥à¤µà¤¾à¤°à¤¾ सà¥â€à¤µà¤¯à¤‚ की पहचान करने के लिठउपयोग किठजाने वाले पà¥à¤°à¤®à¤¾à¤£ पतà¥à¤° केवल विशिषà¥â€à¤Ÿ समयावधियों के लिठही मानà¥â€à¤¯ होते हैं. चूंकि आपके डिवाइस की घड़ी गलत है, इसलिठकà¥à¤°à¥‹à¤®à¤¿à¤¯à¤® इन पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤°à¥‹à¤‚ को सतà¥â€à¤¯à¤¾à¤ªà¤¿à¤¤ नहीं कर सकता.</translation>
<translation id="8740359287975076522"><ph name="HOST_NAME" /> का &lt;abbr id="dnsDefinition"&gt;DNS पता&lt;/abbr&gt; नहीं पाया जा सका. समसà¥à¤¯à¤¾ का निदान किया जा रहा है.</translation>
<translation id="8742371904523228557"><ph name="ORIGIN" /> के लिठआपका कोड <ph name="ONE_TIME_CODE" /> है</translation>
@@ -2409,6 +2461,7 @@
<translation id="883848425547221593">अनà¥à¤¯ बà¥à¤•à¤®à¤¾à¤°à¥à¤•</translation>
<translation id="884264119367021077">शिपिंग पता</translation>
<translation id="884923133447025588">कोई निरसà¥à¤¤à¥€à¤•à¤°à¤£ पà¥à¤°à¤•à¥à¤°à¤¿à¤¯à¤¾ नहीं पाई गई.</translation>
+<translation id="8849262850971482943">अतिरिकà¥à¤¤ सà¥à¤°à¤•à¥à¤·à¤¾ के लिठअपना वरà¥à¤šà¥à¤…ल कारà¥à¤¡ इसà¥à¤¤à¥‡à¤®à¤¾à¤² करें</translation>
<translation id="885730110891505394">Google के साथ शेयर करना</translation>
<translation id="8858065207712248076">अगर आपने अपने <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> पासवरà¥à¤¡ का दूसरी साइटों पर दोबारा इसà¥à¤¤à¥‡à¤®à¤¾à¤² किया है, तो Chrome आपको उसे रीसेट करने का सà¥à¤à¤¾à¤µ देता है.</translation>
<translation id="885906927438988819">अगर सà¥à¤ªà¥‡à¤²à¤¿à¤‚ग सही है, तो <ph name="BEGIN_LINK" />Windows नेटवरà¥à¤• डायगà¥à¤¨à¥‹à¤¸à¥à¤Ÿà¤¿à¤•à¥à¤¸ टूल चलाकर देखें<ph name="END_LINK" />.</translation>
@@ -2458,6 +2511,7 @@
<translation id="9004367719664099443">वीआर सेशन चल रहा है</translation>
<translation id="9005998258318286617">PDF दसà¥à¤¤à¤¾à¤µà¥‡à¥› लोड नहीं किया जा सका.</translation>
<translation id="9008201768610948239">धà¥à¤¯à¤¾à¤¨ न दें</translation>
+<translation id="901834265349196618">ईमेल</translation>
<translation id="9020200922353704812">कारà¥à¤¡ बिलिंग पता ज़रूरी है</translation>
<translation id="9020542370529661692">इस पेज का <ph name="TARGET_LANGUAGE" /> में अनà¥à¤µà¤¾à¤¦ कर दिया गया है</translation>
<translation id="9020742383383852663">à¤8</translation>
@@ -2506,6 +2560,7 @@
<translation id="9150045010208374699">अपना कैमरा उपयोग करें</translation>
<translation id="9150685862434908345">आपका à¤à¤¡à¤®à¤¿à¤¨ किसी दूसरे डिवाइस से आपके बà¥à¤°à¤¾à¤‰à¤œà¤¼à¤° का सेटअप बदल सकता है. इस डिवाइस की गतिविधि को भी Chrome से बाहर पà¥à¤°à¤¬à¤‚धित किया जा सकता है. <ph name="BEGIN_LINK" />ज़à¥à¤¯à¤¾à¤¦à¤¾ जानें<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">अपडेट किया गया</translation>
+<translation id="9155211586651734179">सहायक ऑडियो डिवाइस अटैच किठगà¤</translation>
<translation id="9157595877708044936">सेट अप कर रहा है...</translation>
<translation id="9158625974267017556">सी6 (à¤à¤¨à¥à¤µà¥‡à¤²à¤ª)</translation>
<translation id="9164029392738894042">बेहतर बनाने के लिठदी गई सलाह की जांच करना</translation>
diff --git a/chromium/components/strings/components_strings_hr.xtb b/chromium/components/strings/components_strings_hr.xtb
index 5aad5b82f74..bbcdd040a87 100644
--- a/chromium/components/strings/components_strings_hr.xtb
+++ b/chromium/components/strings/components_strings_hr.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">Prikaži pojedinosti</translation>
<translation id="1030706264415084469"><ph name="URL" /> želi trajno pohraniti veliku koliÄinu podataka na vaÅ¡ ureÄ‘aj</translation>
<translation id="1032854598605920125">Zakretanje u smjeru kazaljke na satu</translation>
+<translation id="1033329911862281889">Anonimni naÄin rada ne Äini vas nevidljivim na internetu:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Web-lokacije i usluge koje one upotrebljavaju mogu vidjeti posjete.<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Poslodavci ili Å¡kole mogu pratiti aktivnost pregledavanja.<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Davatelji internetskih usluga mogu nadzirati web-promet.<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">IskljuÄi</translation>
<translation id="1036982837258183574">Pritisnite |<ph name="ACCELERATOR" />| da biste zatvorili prikaz na cijelom zaslonu</translation>
<translation id="1038106730571050514">Prikaži prijedloge</translation>
<translation id="1038842779957582377">nepoznati naziv</translation>
<translation id="1041998700806130099">Poruka o radnom listu</translation>
<translation id="1048785276086539861">Kad uredite napomene, dokument će se vratiti na prikaz pojedinaÄne stranice</translation>
-<translation id="1049743911850919806">Anonimno</translation>
<translation id="1050038467049342496">Zatvorite ostale aplikacije</translation>
<translation id="1055184225775184556">&amp;Poništi dodavanje</translation>
<translation id="1056898198331236512">Upozorenje</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">Predmemorija pravila ispravna je</translation>
<translation id="1130564665089811311">Gumb Prevedi stranicu, pritisnite Enter da biste preveli ovu stranicu s Google prevoditeljem</translation>
<translation id="1131264053432022307">Slika koju ste kopirali</translation>
+<translation id="1142846828089312304">Blokiraj kolaÄiće trećih strana u anonimnom naÄinu</translation>
<translation id="1150979032973867961">Poslužitelj nije mogao dokazati da je <ph name="DOMAIN" />; operativni sustav vaÅ¡eg raÄunala smatra da njegov sigurnosni certifikat nije pouzdan. To može biti uzrokovano pogreÅ¡nom konfiguracijom ili napadom na vaÅ¡u vezu.</translation>
<translation id="1151972924205500581">Potrebna je zaporka</translation>
<translation id="1156303062776767266">Gledate lokalnu ili dijeljenu datoteku</translation>
@@ -64,7 +70,6 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="1178581264944972037">Pauziraj</translation>
<translation id="1181037720776840403">Ukloni</translation>
<translation id="1186201132766001848">Provjeri zaporke</translation>
-<translation id="1195210374336998651">Otvorite postavke aplikacije</translation>
<translation id="1195558154361252544">Obavijesti su automatski blokirane za sve web-lokacije osim za one koje dopustite</translation>
<translation id="1197088940767939838">NaranÄasta</translation>
<translation id="1201402288615127009">Dalje</translation>
@@ -111,7 +116,7 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="1307966114820526988">Ukinute znaÄajke</translation>
<translation id="1308113895091915999">Dostupna je ponuda</translation>
<translation id="1312803275555673949">Koji to dokazi podržavaju?</translation>
-<translation id="131405271941274527"><ph name="URL" /> želi slati i primati informacije kad telefonom dodirnete NFC uređaj</translation>
+<translation id="1314311879718644478">Gledajte sadržaj u proširenoj stvarnosti</translation>
<translation id="1314509827145471431">Uvez s desne strane</translation>
<translation id="1318023360584041678">Spremljeno u grupu kartica</translation>
<translation id="1319245136674974084">Ne pitaj ponovno za ovu aplikaciju</translation>
@@ -161,6 +166,7 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="142858679511221695">Korisnik oblaka</translation>
<translation id="1428729058023778569">Upozorenje vam se prikazuje jer ova web-lokacija ne podržava HTTPS. <ph name="BEGIN_LEARN_MORE_LINK" />Saznajte više<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">Ispis</translation>
+<translation id="1432187715652018471">Ova stranica želi instalirati rukovatelja usluge.</translation>
<translation id="1432581352905426595">Upravljaj tražilicama</translation>
<translation id="1436185428532214179">Može tražiti dopuštenje za uređivanje datoteka i mapa na vašem uređaju</translation>
<translation id="1442386063175183758">Presavijanje s desne strane u obliku prozora</translation>
@@ -181,6 +187,12 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="1483493594462132177">Pošalji</translation>
<translation id="1484290072879560759">Odaberite adresu za dostavu</translation>
<translation id="1492194039220927094">Push slanje pravila:</translation>
+<translation id="149293076951187737">Kad zatvorite sve anonimne kartice Chromea, s uređaja s brišu vaše aktivnosti u tim karticama:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />aktivnost pregledavanja<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />povijest pretraživanja<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />podaci uneseni u obrasce.<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">Natrag na karticu</translation>
<translation id="1501859676467574491">Prikaži kartice s Google raÄuna</translation>
<translation id="1507202001669085618">&lt;p&gt;Ta će se pogreška prikazati ako upotrebljavate Wi-Fi portal na koji se morate prijaviti da biste se povezali s internetom.&lt;/p&gt;
@@ -208,6 +220,8 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="1559572115229829303">&lt;p&gt;Sigurna veza s domenom <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> ne može se uspostaviti jer datum i vrijeme na ureÄ‘aju (<ph name="DATE_AND_TIME" />) nisu toÄni.&lt;/p&gt;
&lt;p&gt;Prilagodite datum i vrijeme putem odjeljka &lt;strong&gt;Općenito&lt;/strong&gt; u aplikaciji &lt;strong&gt;Postavke&lt;/strong&gt;.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">Administrator će ponovo pokrenuti vaš uređaj u <ph name="TIME" /> <ph name="DATE" /></translation>
+<translation id="156703335097561114">Podaci o mreži kao Å¡to su adrese, konfiguracija suÄelja i kvaliteta veze</translation>
<translation id="1567040042588613346">Pravilo funkcionira kako je predviđeno, ali na drugoj lokaciji postavljena je ista vrijednost koju ovo pravilo nasljeđuje.</translation>
<translation id="1569487616857761740">Unesite datum isteka</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="1583429793053364125">Nešto nije u redu s prikazivanjem ove web-stranice.</translation>
<translation id="1586541204584340881">koja ste proširenja instalirali</translation>
<translation id="1588438908519853928">UobiÄajeno</translation>
+<translation id="1589050138437146318">Instalirati ARCore?</translation>
<translation id="1592005682883173041">Pristup lokalnim podacima</translation>
<translation id="1594030484168838125">Odaberi</translation>
<translation id="160851722280695521">Igrajte igru Dino Run u Chromeu</translation>
@@ -254,7 +269,7 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="1711234383449478798">Zanemareno jer pravilo <ph name="POLICY_NAME" /> nije postavljeno na <ph name="VALUE" />.</translation>
<translation id="1712552549805331520"><ph name="URL" /> želi trajno pohraniti podatke na vaÅ¡e lokalno raÄunalo</translation>
<translation id="1713628304598226412">Ladica 2</translation>
-<translation id="1715874602234207">F</translation>
+<translation id="1715874602234207">P</translation>
<translation id="1717218214683051432">Senzori kretanja</translation>
<translation id="1717494416764505390">Izlazni spremnik s odjeljcima 3</translation>
<translation id="1718029547804390981">Dokument je prevelik za dodavanje bilješki</translation>
@@ -283,6 +298,7 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
zaglavlje nije ispravno, što onemogućuje ispunjavanje
vašeg zahtjeva u pregledniku za web-lokaciju <ph name="SITE" />. Operatori web-lokacije mogu koristiti
izvorna pravila radi konfiguracije zaštite i drugih svojstava web-lokacije.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Saznajte viÅ¡e o anonimnom naÄinu u Chromiumu<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">Ovdje se prikazuju vaše otvorene kartice</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -347,7 +363,7 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="2003709556000175978">Poništite zaporku odmah</translation>
<translation id="2003775180883135320">Četverostruko bušenje pri vrhu</translation>
<translation id="201174227998721785">Dopuštenjima i podacima koji se pohranjuju na web-lokacijama možete upravljati u postavkama Chromea</translation>
-<translation id="2019607688127825327">Gumb Upravljaj postavkama pristupaÄnosti, pritisnite Enter da biste prilagodili svoje alate za pristupaÄnost u postavkama Chromea</translation>
+<translation id="2019607688127825327">Gumb Upravljajte postavkama pristupaÄnosti, pritisnite Enter da biste prilagodili svoje alate za pristupaÄnost u postavkama Chromea</translation>
<translation id="2025115093177348061">Proširena stvarnost</translation>
<translation id="2025186561304664664">Proxy je postavljen na automatsko konfiguriranje.</translation>
<translation id="2025891858974379949">Nesiguran sadržaj</translation>
@@ -359,7 +375,7 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="204357726431741734">Prijavite se kako biste upotrebljavali zaporke spremljene na Google raÄunu</translation>
<translation id="2053111141626950936">Neće se prevoditi <ph name="LANGUAGE" />.</translation>
<translation id="2053373601901562871">{NUM_DAYS,plural, =0{Kada je ta kontrola ukljuÄena i status je aktivan, Chrome odreÄ‘uje kojoj je velikoj grupi ljudi, odnosno skupini, vaÅ¡a nedavna aktivnost pregledavanja najsliÄnija. OglaÅ¡ivaÄi mogu odabrati oglase za tu grupu, a vaÅ¡a aktivnost pregledavanja ostaje privatna na vaÅ¡em ureÄ‘aju. VaÅ¡a se grupa ažurira svaki dan.}=1{Kada je ta kontrola ukljuÄena i status je aktivan, Chrome odreÄ‘uje kojoj je velikoj grupi ljudi, odnosno skupini, vaÅ¡a nedavna aktivnost pregledavanja najsliÄnija. OglaÅ¡ivaÄi mogu odabrati oglase za tu grupu, a vaÅ¡a aktivnost pregledavanja ostaje privatna na vaÅ¡em ureÄ‘aju. VaÅ¡a se grupa ažurira svaki dan.}one{Kada je ta kontrola ukljuÄena i status je aktivan, Chrome odreÄ‘uje kojoj je velikoj grupi ljudi, odnosno skupini, vaÅ¡a nedavna aktivnost pregledavanja najsliÄnija. OglaÅ¡ivaÄi mogu odabrati oglase za tu grupu, a vaÅ¡a aktivnost pregledavanja ostaje privatna na vaÅ¡em ureÄ‘aju. VaÅ¡a se grupa ažurira svaki {NUM_DAYS} dan.}few{Kada je ta kontrola ukljuÄena i status je aktivan, Chrome odreÄ‘uje kojoj je velikoj grupi ljudi, odnosno skupini, vaÅ¡a nedavna aktivnost pregledavanja najsliÄnija. OglaÅ¡ivaÄi mogu odabrati oglase za tu grupu, a vaÅ¡a aktivnost pregledavanja ostaje privatna na vaÅ¡em ureÄ‘aju. VaÅ¡a se grupa ažurira svaka {NUM_DAYS} dana.}other{Kada je ta kontrola ukljuÄena i status je aktivan, Chrome odreÄ‘uje kojoj je velikoj grupi ljudi, odnosno skupini, vaÅ¡a nedavna aktivnost pregledavanja najsliÄnija. OglaÅ¡ivaÄi mogu odabrati oglase za tu grupu, a vaÅ¡a aktivnost pregledavanja ostaje privatna na vaÅ¡em ureÄ‘aju. VaÅ¡a se grupa ažurira svakih {NUM_DAYS} dana.}}</translation>
-<translation id="2053553514270667976">ZIP kôd</translation>
+<translation id="2053553514270667976">Poštanski broj</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 prijedlog}one{# prijedlog}few{# prijedloga}other{# prijedloga}}</translation>
<translation id="2071156619270205202">Ova kartica ne ispunjava kriterije za broj virtualne kartice.</translation>
<translation id="2071692954027939183">Obavijesti su automatski blokirane jer ih obiÄno ne dopuÅ¡tate</translation>
@@ -410,6 +426,7 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="22081806969704220">Ladica 3</translation>
<translation id="2212735316055980242">Pravilo nije pronađeno</translation>
<translation id="2213606439339815911">Dohvaćanje unosa...</translation>
+<translation id="2213612003795704869">Stranica je ispisana</translation>
<translation id="2215727959747642672">Uređivanje datoteke</translation>
<translation id="2218879909401188352">NapadaÄi koji su trenutaÄno na web-lokaciji <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> mogli bi instalirati opasne aplikacije koje će oÅ¡tetiti ureÄ‘aj, dodati skrivene troÅ¡kove na raÄun za mobilne usluge ili ukrasti vaÅ¡e osobne podatke. <ph name="BEGIN_LEARN_MORE_LINK" />Saznajte viÅ¡e<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">Nema interneta</translation>
@@ -419,6 +436,7 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="2248949050832152960">Koristi WebAuthn</translation>
<translation id="2250931979407627383">Rubni Å¡av s lijeve strane</translation>
<translation id="225207911366869382">Ta je vrijednost obustavljena za to pravilo.</translation>
+<translation id="2256115617011615191">Ponovo pokreni sad</translation>
<translation id="2258928405015593961">Unesite datum isteka u budućnosti i pokušajte ponovo</translation>
<translation id="225943865679747347">Kôd pogreške: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">HTTP pogreška</translation>
@@ -446,6 +464,7 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="2337852623177822836">Postavkom upravlja administrator</translation>
<translation id="2340263603246777781">Web-lokacija <ph name="ORIGIN" /> želi se upariti</translation>
<translation id="2346319942568447007">Slika koju ste kopirali</translation>
+<translation id="2350796302381711542">Želite li dopustiti da <ph name="HANDLER_HOSTNAME" /> otvori sve veze protokola <ph name="PROTOCOL" /> umjesto da to uÄini <ph name="REPLACED_HANDLER_TITLE" />?</translation>
<translation id="2354001756790975382">Druge oznake</translation>
<translation id="2354430244986887761">Google sigurno pregledavanje nedavno je <ph name="BEGIN_LINK" />pronašlo štetne aplikacije<ph name="END_LINK" /> na web-lokaciji <ph name="SITE" />.</translation>
<translation id="2355395290879513365">NapadaÄi možda mogu vidjeti slike koje gledate na ovoj web-lokaciji i izmijeniti ih kako bi vas prevarili.</translation>
@@ -471,6 +490,7 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="2413528052993050574">Poslužitelj nije mogao dokazati da je <ph name="DOMAIN" />; njegov sigurnosni certifikat možda je opozvan. To može biti uzrokovano pogrešnom konfiguracijom ili napadom na vašu vezu.</translation>
<translation id="2414886740292270097">Tamno</translation>
<translation id="2430968933669123598">Upravljajte Google raÄunom, pritisnite Enter da biste upravljali podacima, privatnošću i sigurnošću na svojem Google raÄunu</translation>
+<translation id="2436186046335138073">Želite li dopustiti da <ph name="HANDLER_HOSTNAME" /> otvori sve veze protokola <ph name="PROTOCOL" />?</translation>
<translation id="2438874542388153331">Četverostruko bušenje s desne strane</translation>
<translation id="2450021089947420533">Putovanja</translation>
<translation id="2463739503403862330">Ispuni</translation>
@@ -478,6 +498,7 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="2465655957518002998">Odaberite naÄin isporuke</translation>
<translation id="2465688316154986572">Spajanje</translation>
<translation id="2465914000209955735">Upravljajte datotekama koje ste preuzeli u Chromeu</translation>
+<translation id="2466004615675155314">Prikaži informacije s weba</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />pokrenuti Mrežnu dijagnostiku<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">Redoslijedom 1 do N</translation>
<translation id="2470767536994572628">Kad uredite napomene, dokument će se vratiti na prikaz pojedinaÄne stranice i izvorno usmjerenje</translation>
@@ -498,6 +519,7 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="2523886232349826891">Sprema se samo na ovom uređaju</translation>
<translation id="2524461107774643265">Dodajte još podataka</translation>
<translation id="2529899080962247600">Broj unosa u ovom polju ne smije biti veći od <ph name="MAX_ITEMS_LIMIT" />. Svi će se daljnji unosi zanemariti.</translation>
+<translation id="2535585790302968248">Otvorite novu anonimnu karticu da biste pregledavali privatno</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{i još jedan sudionik}one{i još #}few{i još #}other{i još #}}</translation>
<translation id="2536110899380797252">Dodaj adresu</translation>
<translation id="2539524384386349900">Otkrij</translation>
@@ -513,7 +535,7 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="2556876185419854533">&amp;Poništi uređivanje</translation>
<translation id="2570734079541893434">Upravljajte postavkama</translation>
<translation id="257674075312929031">Grupa</translation>
-<translation id="2576880857912732701">Gumb Upravljaj sigurnosnim postavkama, pritisnite Enter da biste upravljali sigurnim pregledavanjem i drugim znaÄajkama u postavkama Chromea</translation>
+<translation id="2576880857912732701">Gumb Upravljajte sigurnosnim postavkama, pritisnite Enter da biste upravljali sigurnim pregledavanjem i drugim znaÄajkama u postavkama Chromea</translation>
<translation id="2586657967955657006">Međuspremnik</translation>
<translation id="2587730715158995865">IzdavaÄ: <ph name="ARTICLE_PUBLISHER" />. ProÄitajte ovaj Älanak i joÅ¡ <ph name="OTHER_ARTICLE_COUNT" />.</translation>
<translation id="2587841377698384444">ID API-ja direktorija:</translation>
@@ -523,7 +545,14 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="2597378329261239068">Ovaj je dokument zaštićen zaporkom. Unesite zaporku.</translation>
<translation id="2609632851001447353">Varijacije</translation>
<translation id="2610561535971892504">Klik za kopiranje</translation>
+<translation id="2617988307566202237">Chrome <ph name="BEGIN_EMPHASIS" />neće spremati<ph name="END_EMPHASIS" /> sljedeće podatke:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />vašu povijest pregledavanja
+ <ph name="LIST_ITEM" />kolaÄiće i podatke web-lokacija
+ <ph name="LIST_ITEM" />podatke koje unesete u obrasce.
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (omotnica)</translation>
+<translation id="2623663032199728144">Može tražiti dopuštenje za upotrebu podataka o zaslonima</translation>
<translation id="2625385379895617796">Sat ide unaprijed</translation>
<translation id="262745152991669301">Može tražiti dopuštenje za povezivanje s USB uređajima</translation>
<translation id="2629325967560697240">Da biste dobili najviÅ¡u Chromeovu razinu sigurnosti, <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />ukljuÄite poboljÅ¡anu zaÅ¡titu<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -557,6 +586,7 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="2709516037105925701">Automatsko popunjavanje</translation>
<translation id="2713444072780614174">Bijela</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />, pritisnite Tab, a zatim Enter da biste upravljali podacima o plaćanju i kreditnoj kartici u postavkama Chromea</translation>
+<translation id="271663710482723385">Pritisnite |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| da biste zatvorili prikaz na cijelom zaslonu.</translation>
<translation id="2721148159707890343">Zahtjev je uspio</translation>
<translation id="2723669454293168317">Izvršite sigurnosnu provjeru u postavkama Chromea</translation>
<translation id="2726001110728089263">BoÄna ladica</translation>
@@ -587,6 +617,7 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="2850739647070081192">Invite (omotnica)</translation>
<translation id="2856444702002559011">NapadaÄi možda pokuÅ¡avaju ukrasti vaÅ¡e podatke s web-lokacije <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (na primjer zaporke, poruke ili brojeve kreditnih kartica). <ph name="BEGIN_LEARN_MORE_LINK" />Saznajte viÅ¡e<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">Ova web-lokacija prikazuje ometajuće ili obmanjujuće oglase.</translation>
+<translation id="286512204874376891">Virtualna kartica skriva vašu stvarnu karticu kako bi vas bolje zaštitila od potencijalne prijevare. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">Prijateljski</translation>
<translation id="2876489322757410363">NapuÅ¡tate anonimni naÄin rada da biste platili putem vanjske aplikacije. Želite li nastaviti?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />, pritisnite Tab, a zatim Enter da biste upravljali sigurnim pregledavanjem i drugim znaÄajkama u postavkama Chromea</translation>
@@ -611,6 +642,7 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="2930577230479659665">Obreži nakon svake kopije</translation>
<translation id="2932085390869194046">Predloži zaporku…</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019">otvoriti veze za <ph name="PROTOCOL" /></translation>
<translation id="2941952326391522266">Poslužitelj nije mogao dokazati da je <ph name="DOMAIN" />; njegov je sigurnosni certifikat s domene <ph name="DOMAIN2" />. To može biti uzrokovano pogrešnom konfiguracijom ili napadom na vašu vezu.</translation>
<translation id="2943895734390379394">Vrijeme prijenosa:</translation>
<translation id="2948083400971632585">Možete onemogućiti sve proxyje konfigurirane za vezu sa stranice postavki.</translation>
@@ -643,6 +675,7 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="3037605927509011580">O, ne!</translation>
<translation id="3041612393474885105">Podaci o certifikatu</translation>
<translation id="3044034790304486808">Nastavite istraživanje</translation>
+<translation id="305162504811187366">Povijest Udaljene radne povrÅ¡ine Chrome, ukljuÄujući vremenske oznake, hostove i ID-jeve klijentskih sesija</translation>
<translation id="3060227939791841287">C9 (omotnica)</translation>
<translation id="3061707000357573562">Usluga zakrpe</translation>
<translation id="306573536155379004">Igra je pokrenuta.</translation>
@@ -683,6 +716,7 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="3197136577151645743">Može tražiti dopuštenje da zna kad aktivno koristite ovaj uređaj</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />, pritisnite Tab, a zatim Enter da biste u postavkama Chromea upravljali time koji će se podaci sinkronizirati</translation>
<translation id="320323717674993345">Otkaži plaćanje</translation>
+<translation id="3203366800380907218">S weba</translation>
<translation id="3207960819495026254">OznaÄeno</translation>
<translation id="3209034400446768650">Stranica se možda naplaćuje</translation>
<translation id="3212581601480735796">Prati se vaša aktivnost na web-lokaciji <ph name="HOSTNAME" /></translation>
@@ -699,11 +733,13 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="3234666976984236645">Uvijek otkrivaj važan sadržaj na ovoj web-lokaciji</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />, pritisnite Tab, a zatim Enter da biste prilagodili izgled preglednika</translation>
<translation id="3240791268468473923">Otvoren je list obavijesti da nema podudarnih vjerodajnica za sigurno plaćanje</translation>
+<translation id="324180406144491771">Veze hosta <ph name="HOST_NAME" /> su blokirane</translation>
<translation id="3249845759089040423">Živopisno</translation>
<translation id="3252266817569339921">Francuski</translation>
<translation id="3257954757204451555">Tko stoji iza ovih podataka?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />, pritisnite Tab, a zatim Enter da biste brzo izradili novi događaj u Google kalendaru</translation>
-<translation id="3264837738038045344">Gumb Upravljaj postavkama Chromea, pritisnite Enter da biste otvorili svoje postavke u Chromeu</translation>
+<translation id="3261488570342242926">Saznajte više o virtualnim karticama</translation>
+<translation id="3264837738038045344">Gumb Upravljajte postavkama Chromea, pritisnite Enter da biste otvorili svoje postavke u Chromeu</translation>
<translation id="3266793032086590337">Vrijednost (sukob)</translation>
<translation id="3268451620468152448">Otvorene kartice</translation>
<translation id="3270847123878663523">&amp;Poništi promjenu rasporeda</translation>
@@ -716,6 +752,7 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="3288238092761586174"><ph name="URL" /> možda treba izvršiti dodatne korake za potvrdu plaćanja</translation>
<translation id="3293642807462928945">Saznajte više o pravilu <ph name="POLICY_NAME" /></translation>
<translation id="3295444047715739395">Pregled zaporki u postavkama Chromea i upravljanje njima</translation>
+<translation id="3303795387212510132">Želite li dopustiti aplikaciji da otvara <ph name="PROTOCOL_SCHEME" /> veze?</translation>
<translation id="3303855915957856445">Nisu pronađeni rezultati pretraživanja</translation>
<translation id="3304073249511302126">traženje Bluetootha</translation>
<translation id="3308006649705061278">Organizacijska jedinica (OU)</translation>
@@ -729,12 +766,6 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="3345782426586609320">OÄi</translation>
<translation id="3355823806454867987">Promijeni proxy postavke...</translation>
<translation id="3360103848165129075">List rukovatelja plaćanjima</translation>
-<translation id="3361596688432910856">Chrome <ph name="BEGIN_EMPHASIS" />neće spremati<ph name="END_EMPHASIS" /> sljedeće informacije:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />vašu povijest pregledavanja
- <ph name="LIST_ITEM" />kolaÄiće i podatke o web-lokacijama
- <ph name="LIST_ITEM" />informacije koje unesete u obrasce.
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">Pravilo je automatski kopirano iz ukinutog pravila <ph name="OLD_POLICY" />. Trebali biste koristiti ovo pravilo.</translation>
<translation id="3364869320075768271"><ph name="URL" /> želi koristiti vaš uređaj i podatke virtualne stvarnosti</translation>
<translation id="3366477098757335611">Prikaži kartice</translation>
@@ -817,7 +848,6 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="3587738293690942763">Srednji</translation>
<translation id="3592413004129370115">Italian (omotnica)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{Grupu uvijek možete poništiti. Za pridruživanje novoj grupi potreban je otprilike jedan dan.}=1{Grupu uvijek možete poništiti. Za pridruživanje novoj grupi potreban je otprilike jedan dan.}one{Grupu uvijek možete poništiti. Za pridruživanje novoj grupi potreban je {NUM_DAYS} dan.}few{Grupu uvijek možete poništiti. Za pridruživanje novoj grupi potrebna su {NUM_DAYS} dana.}other{Grupu uvijek možete poništiti. Za pridruživanje novoj grupi potrebno je {NUM_DAYS} dana.}}</translation>
-<translation id="3596012367874587041">Postavke aplikacije</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">Administrator je blokirao aplikaciju</translation>
<translation id="3608932978122581043">Usmjerenje umetanja</translation>
@@ -859,6 +889,7 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="370972442370243704">UkljuÄite putovanja</translation>
<translation id="3711895659073496551">Obustavi</translation>
<translation id="3712624925041724820">Licence su potrošene</translation>
+<translation id="3714633008798122362">web-kalendar</translation>
<translation id="3714780639079136834">ukljuÄite mobilne podatke ili Wi-Fi</translation>
<translation id="3715597595485130451">Povezivanje s Wi-Fi mrežom</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />provjerite proxy, vatrozid i konfiguraciju DNS-a<ph name="END_LINK" /></translation>
@@ -920,6 +951,7 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="3906954721959377182">Tablet</translation>
<translation id="3909477809443608991"><ph name="URL" /> želi reproducirati zaštićeni sadržaj. Google će potvrditi identitet vašeg uređaja i ta će mu web-lokacija moći pristupiti.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">Odbij</translation>
<translation id="3939773374150895049">Želite li koristiti WebAuthn umjesto CVC-a?</translation>
<translation id="3946209740501886391">Uvijek pitaj na ovoj web-lokaciji</translation>
<translation id="3947595700203588284">Može tražiti dopuštenje za povezivanje s MIDI uređajima</translation>
@@ -941,6 +973,7 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="3990250421422698716">Pomak u naÄinu rada Jog</translation>
<translation id="3996311196211510766">Web-lokacija <ph name="ORIGIN" /> zatražila je da se izvorno pravilo
primjenjuje na sve zahtjeve za nju, no to se pravilo trenutaÄno ne može primijeniti.</translation>
+<translation id="4009243425692662128">Sadržaj stranica koje ispisujete šalje se na analizu Google Cloudu ili trećim stranama. Na primjer, može se pregledati radi otkrivanja osjetljivih podataka.</translation>
<translation id="4010758435855888356">Želite li dopustiti pristup pohrani?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{PDF dokument koji sadrži {COUNT} stranicu}one{PDF dokument koji sadrži {COUNT} stranicu}few{PDF dokument koji sadrži {COUNT} stranice}other{PDF dokument koji sadrži {COUNT} stranica}}</translation>
<translation id="4023431997072828269">Budući da se ovaj obrazac šalje vezom koja nije sigurna, vaši će podaci biti vidljivi drugima.</translation>
@@ -1036,6 +1069,7 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="4250680216510889253">Ne</translation>
<translation id="4253168017788158739">Napomena</translation>
<translation id="425582637250725228">Unesene promjene ne mogu se spremiti.</translation>
+<translation id="425869179292622354">Želite li bolje zaštiti svoju karticu pomoću virtualne kartice?</translation>
<translation id="4258748452823770588">Potpis nije valjan</translation>
<translation id="4261046003697461417">Dodavanje bilješke zaštićenim dokumentima nije moguće</translation>
<translation id="4265872034478892965">Dopustio administrator</translation>
@@ -1098,6 +1132,7 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="4434045419905280838">SkoÄni prozori i preusmjeravanja</translation>
<translation id="4435702339979719576">Dopisnica)</translation>
<translation id="443673843213245140">Upotreba proxy poslužitelja onemogućena je, ali odreÄ‘ena je izriÄita konfiguracija proxy poslužitelja.</translation>
+<translation id="4441832193888514600">Zanemareno jer se pravilo može postaviti samo kao korisniÄko pravilo oblaka.</translation>
<translation id="4450893287417543264">Ne prikazuj ponovo</translation>
<translation id="4451135742916150903">Može tražiti dopuštenje za povezivanje s HID uređajima</translation>
<translation id="4452328064229197696">Zaporka koju ste upravo upotrijebili otkrivena je u povredi podataka. Radi zaÅ¡tite vaÅ¡ih raÄuna Google upravitelj zaporki preporuÄuje da provjerite svoje spremljene zaporke.</translation>
@@ -1153,6 +1188,7 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="4628948037717959914">Fotografija</translation>
<translation id="4631649115723685955">Povezano s gotovinskim povratom</translation>
<translation id="4636930964841734540">Informacije</translation>
+<translation id="4638670630777875591">Anonimni naÄin u Chromiumu</translation>
<translation id="464342062220857295">ZnaÄajke pretraživanja</translation>
<translation id="4644670975240021822">Suprotnim redoslijedom prema dolje</translation>
<translation id="4646534391647090355">Otvori odmah</translation>
@@ -1173,6 +1209,7 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="4708268264240856090">Veza je prekinuta</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />pokrenuti Mrežnu dijagnostiku sustava Windows<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426">Zaporka za <ph name="USERNAME" /></translation>
<translation id="4724144314178270921">Može tražiti dopuštenje da vidi tekst i slike u vašem međuspremniku</translation>
<translation id="4726672564094551039">Ponovo uÄitaj pravila</translation>
<translation id="4728558894243024398">Platforma</translation>
@@ -1194,6 +1231,7 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="4757993714154412917">Upravo ste unijeli zaporku na obmanjujućoj web-lokaciji. Da bi zaÅ¡titio vaÅ¡e raÄune, Chromium preporuÄuje da provjerite spremljene zaporke.</translation>
<translation id="4758311279753947758">Dodaj pod. za kontakt</translation>
<translation id="4761104368405085019">upotrijebiti vaš mikrofon</translation>
+<translation id="4761869838909035636">Pokreni Chromeovu sigurnosnu provjeru</translation>
<translation id="4764776831041365478">Web-stranica na adresi <ph name="URL" /> možda privremeno nije dostupna ili je trajno preseljena na novu web-adresu.</translation>
<translation id="4766713847338118463">Dvostruko spajanje pri dnu</translation>
<translation id="4771973620359291008">Došlo je do nepoznate pogreške.</translation>
@@ -1214,12 +1252,6 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="4819347708020428563">Želite li urediti napomene u zadanom prikazu?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />, pritisnite Tab, a zatim Enter da biste brzo izradili novu Google tablicu</translation>
<translation id="4825507807291741242">Snažno</translation>
-<translation id="4827402517081186284">Anonimni naÄin rada ne Äini vas nevidljivim na internetu:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />web-lokacije znaju kada ih posjećujete<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />poslodavci ili škole mogu pratiti vašu aktivnost pregledavanja<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />davatelji internetskih usluga mogu nadzirati web-promet<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">UkljuÄite upozorenja</translation>
<translation id="4838327282952368871">Sanjivo</translation>
<translation id="4840250757394056958">Pregledaj povijest na Chromeu</translation>
@@ -1231,12 +1263,12 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="4854362297993841467">Taj naÄin dostave nije dostupan. PokuÅ¡ajte s nekim drugim naÄinom.</translation>
<translation id="4854853140771946034">Brzo izradite novu bilješku u Google Keepu</translation>
<translation id="485902285759009870">Potvrđivanje koda...</translation>
+<translation id="4866506163384898554">Pritisnite |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| da bi se prikazao pokazivaÄ</translation>
<translation id="4876188919622883022">Pojednostavljeni prikaz</translation>
<translation id="4876305945144899064">Nema korisniÄkog imena</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{Ništa}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}one{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}few{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831">Pretraživanje <ph name="TEXT" /></translation>
<translation id="4879491255372875719">Automatski (zadano)</translation>
-<translation id="4879725228911483934">otvarati i postavljati prozore na vašim zaslonima</translation>
<translation id="4880827082731008257">Pretraži povijest</translation>
<translation id="4881695831933465202">Otvori</translation>
<translation id="4885256590493466218">Platite karticom <ph name="CARD_DETAIL" /> prilikom naplate</translation>
@@ -1245,6 +1277,7 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">Deveti kolut</translation>
<translation id="4901778704868714008">Spremi...</translation>
+<translation id="4905659621780993806">Administrator će automatski ponovo pokrenuti vaš uređaj u <ph name="TIME" /> <ph name="DATE" />. Spremite sve otvorene stavke prije nego što se uređaj ponovno pokrene.</translation>
<translation id="4913987521957242411">Bušenje pri vrhu lijevo</translation>
<translation id="4918221908152712722">Instalirajte aplikaciju <ph name="APP_NAME" /> (preuzimanje nije potrebno)</translation>
<translation id="4923459931733593730">Plaćanje</translation>
@@ -1253,6 +1286,7 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, pritisnite Tab, a zatim Enter da biste pretražili</translation>
<translation id="4930153903256238152">Veliki kapacitet</translation>
+<translation id="4940163644868678279">Anonimni naÄin u Chromeu</translation>
<translation id="4943872375798546930">Nema rezultata</translation>
<translation id="4950898438188848926">Gumb za promjenu kartice, pritisnite Enter za prebacivanje na otvorenu karticu, <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="495170559598752135">Radnje</translation>
@@ -1262,6 +1296,7 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="4968522289500246572">Ova je aplikacija izraÄ‘ena za mobilne ureÄ‘aje i možda neće dobro promijeniti veliÄinu. Aplikacija može imati poteÅ¡koća ili se može pokrenuti ponovo.</translation>
<translation id="4969341057194253438">Izbriši snimku</translation>
<translation id="4973922308112707173">Dvostruko bušenje pri vrhu</translation>
+<translation id="4976702386844183910">Posljednji posjet bio je <ph name="DATE" /></translation>
<translation id="4984088539114770594">Koristiti mikrofon?</translation>
<translation id="4984339528288761049">Prc5 (omotnica)</translation>
<translation id="4989163558385430922">Prikaži sve</translation>
@@ -1323,6 +1358,7 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="5138227688689900538">Pokaži manje</translation>
<translation id="5145883236150621069">Odgovor na pravilo sadrži kôd pogreške</translation>
<translation id="5146995429444047494">Blokirane su obavijesti za <ph name="ORIGIN" /></translation>
+<translation id="514704532284964975"><ph name="URL" /> želi vidjeti i promijeniti podatke na NFC uređajima koje dodirnete svojim telefonom</translation>
<translation id="5148809049217731050">Prema gore</translation>
<translation id="515292512908731282">C4 (omotnica)</translation>
<translation id="5158275234811857234">Naslovnica</translation>
@@ -1347,6 +1383,7 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="5215116848420601511">NaÄini plaćanja i adrese s Google Paya</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">Ladica 13</translation>
+<translation id="5216942107514965959">Posljednji posjet bio je danas</translation>
<translation id="5222812217790122047">E-pošta (obavezno)</translation>
<translation id="5230733896359313003">Adresa za dostavu</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1367,7 +1404,6 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">Svojstva dokumenta</translation>
<translation id="528468243742722775">Završi</translation>
-<translation id="5284909709419567258">Mrežne adrese</translation>
<translation id="5285570108065881030">Prikaži sve spremljene zaporke</translation>
<translation id="5287240709317226393">Pokaži kolaÄiće</translation>
<translation id="5287456746628258573">Ta web-lokacija upotrebljava zastarjelu sigurnosnu konfiguraciju, pa bi vaši podaci (na primjer zaporke ili brojevi kreditnih kartica) mogli biti otkriveni kad se šalju na nju.</translation>
@@ -1451,6 +1487,7 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="5556459405103347317">Ponovno uÄitaj</translation>
<translation id="5560088892362098740">Datum isteka</translation>
<translation id="55635442646131152">Struktura dokumenta</translation>
+<translation id="5565613213060953222">Otvori anonimnu karticu</translation>
<translation id="5565735124758917034">Aktivno</translation>
<translation id="5570825185877910964">ZaÅ¡titite raÄun</translation>
<translation id="5571083550517324815">Preuzimanje na toj adresi nije moguće. Odaberite drugu adresu.</translation>
@@ -1533,6 +1570,7 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="5869522115854928033">Spremljene zaporke</translation>
<translation id="5873013647450402046">Vaša banka želi potvrditi vaš identitet.</translation>
<translation id="5887400589839399685">Kartica je spremljena</translation>
+<translation id="5887687176710214216">Posljednji posjet bio je juÄer</translation>
<translation id="5895138241574237353">Ponovno pokreni</translation>
<translation id="5895187275912066135">Izdano</translation>
<translation id="5901630391730855834">Žuta</translation>
@@ -1546,6 +1584,7 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="5921639886840618607">Želite li spremiti karticu na Google raÄun?</translation>
<translation id="5922853866070715753">Skoro gotovo</translation>
<translation id="5932224571077948991">Web-lokacija prikazuje ometajuće ili obmanjujuće oglase</translation>
+<translation id="5938153366081463283">Dodajte virtualnu karticu</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347">Otvaranje web-lokacije <ph name="SITE_NAME" />…</translation>
<translation id="5951495562196540101">Prijava s raÄunom potroÅ¡aÄa nije moguća (dostupna je paketna licenca).</translation>
@@ -1610,6 +1649,7 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="6120179357481664955">Upamtiti vaš UPI ID?</translation>
<translation id="6124432979022149706">PrikljuÄci za Chrome za poduzeća</translation>
<translation id="6127379762771434464">Stavka je uklonjena</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Saznajte viÅ¡e o anonimnom naÄinu u Chromeu<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">Provjerite kabele i ponovo pokrenite usmjerivaÄe, modeme ili druge mrežne
uređaje koje možda upotrebljavate.</translation>
<translation id="614940544461990577">Pokušajte sljedeće:</translation>
@@ -1622,7 +1662,6 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="6169916984152623906">Sada možete pregledavati privatno i ostali korisnici ovog uređaja neće vidjeti vaše aktivnosti. No spremit će se preuzimanja i oznake.</translation>
<translation id="6177128806592000436">Veza s web-lokacijom nije sigurna</translation>
<translation id="6180316780098470077">Interval između ponovnih pokušaja</translation>
-<translation id="619448280891863779">Može tražiti dopuštenje za otvaranje i postavljanje prozora na zaslone</translation>
<translation id="6196640612572343990">Blokiraj kolaÄiće trećih strana</translation>
<translation id="6203231073485539293">Provjerite internetsku vezu</translation>
<translation id="6218753634732582820">Želite li ukloniti adresu iz Chromiuma?</translation>
@@ -1645,7 +1684,7 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="6272383483618007430">Google ažuriranje</translation>
<translation id="6276112860590028508">Ovdje se prikazuju stranice s vaÅ¡eg popisa za Äitanje</translation>
<translation id="627746635834430766">Da biste sljedeći put platili brže, karticu i adresu za naplatu spremite na svoj Google raÄun.</translation>
-<translation id="6279098320682980337">Broj virtualne kartice nije ispunjen? Kliknite podatke o kartici da biste kopirali</translation>
+<translation id="6279183038361895380">Pritisnite |<ph name="ACCELERATOR" />| da bi se prikazao pokazivaÄ</translation>
<translation id="6280223929691119688">Dostava na tu adresu nije moguća. Odaberite drugu adresu.</translation>
<translation id="6282194474023008486">Poštanski broj</translation>
<translation id="6285507000506177184">Gumb Upravljaj preuzimanjima u Chromeu, pritisnite Enter da biste upravljali datotekama koje ste preuzeli u Chromeu</translation>
@@ -1653,6 +1692,7 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="6290238015253830360">Ovdje će se prikazivati predloženi Älanci</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{Vaš će se uređaj sada ponovno pokrenuti}=1{Vaš će se uređaj ponovno pokrenuti za 1 sekundu}one{Vaš će se uređaj ponovno pokrenuti za # sekundu}few{Vaš će se uređaj ponovno pokrenuti za # sekunde}other{Vaš će se uređaj ponovno pokrenuti za # sekundi}}</translation>
<translation id="6302269476990306341">Zaustavljanje Google asistenta u Chromeu</translation>
<translation id="6305205051461490394">Web-lokacija <ph name="URL" /> nije dostupna.</translation>
<translation id="6312113039770857350">Web-stranica nije dostupna</translation>
@@ -1726,6 +1766,7 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="6529602333819889595">&amp;Ponovi brisanje</translation>
<translation id="6545864417968258051">Traženje Bluetootha</translation>
<translation id="6547208576736763147">Dvostruko bušenje s lijeve strane</translation>
+<translation id="6554732001434021288">Posljednji posjet bio je prije <ph name="NUM_DAYS" /> dana</translation>
<translation id="6556866813142980365">Ponovi</translation>
<translation id="6569060085658103619">Gledate stranicu proširenja</translation>
<translation id="6573200754375280815">Dvostruko bušenje s desne strane</translation>
@@ -1786,7 +1827,6 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="6757797048963528358">Uređaj je u stanju mirovanja.</translation>
<translation id="6767985426384634228">Želite li ažurirati adresu?</translation>
<translation id="6768213884286397650">Hagaki (dopisnica)</translation>
-<translation id="6774185088257932239"><ph name="BEGIN_LINK" />Saznajte viÅ¡e<ph name="END_LINK" /> o anonimnom naÄinu rada</translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">LjubiÄasta</translation>
<translation id="6786747875388722282">Proširenja</translation>
@@ -1870,7 +1910,6 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="706295145388601875">Dodajte adrese i upravljajte njima u postavkama Chromea</translation>
<translation id="7064851114919012435">Podaci za kontakt</translation>
<translation id="7068733155164172741">Unesite <ph name="OTP_LENGTH" />-znamenkasti kôd</translation>
-<translation id="7070090581017165256">O ovoj web-lokaciji</translation>
<translation id="70705239631109039">Vaša veza nije posve sigurna</translation>
<translation id="7075452647191940183">Zahtjev je prevelik</translation>
<translation id="7079718277001814089">Ova web-lokacija sadrži zlonamjerni softver</translation>
@@ -1887,6 +1926,12 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="7111012039238467737">(Važeći)</translation>
<translation id="7118618213916969306">Traženje URL-a u međuspremniku, <ph name="SHORT_URL" /></translation>
<translation id="7119414471315195487">Zatvorite ostale kartice ili programe</translation>
+<translation id="7129355289156517987">Kad zatvorite sve anonimne kartice Chromiuma, s uređaja s brišu vaše aktivnosti u tim karticama:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />aktivnost pregledavanja<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />povijest pretraživanja<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />podaci uneseni u obrasce.<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">Dostava na tu adresu nije moguća. Odaberite drugu adresu.</translation>
<translation id="7132939140423847331">Vaš je administrator zabranio kopiranje tih podataka.</translation>
<translation id="7135130955892390533">Prikaži status</translation>
@@ -1909,6 +1954,7 @@ To će u suprotnom biti onemogućeno na temelju vaših postavki privatnosti. To
<translation id="7192203810768312527">Oslobodit će se <ph name="SIZE" />. Neke bi se web-lokacije pri sljedećem otvaranju mogle sporije uÄitavati.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">Vaš administrator može vidjeti:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, pritisnite Tab, a zatim Enter da biste otvorili novu anonimnu karticu i pregledavali u privatnosti</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423">Host <ph name="HOST_NAME" /> ne pridržava se sigurnosnih standarda.</translation>
<translation id="7210993021468939304">aktivnost Linuxa unutar spremnika i može instalirati i pokrenuti Linuxove aplikacije unutar spremnika</translation>
@@ -1940,6 +1986,7 @@ Dodatne pojedinosti:
<translation id="7304562222803846232">Upravljajte postavkama privatnosti Google raÄuna</translation>
<translation id="7305756307268530424">Pokreni sporije</translation>
<translation id="7308436126008021607">sinkronizacija u pozadini</translation>
+<translation id="7310392214323165548">Uređaj će se pokrenuti ponovo vrlo brzo</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">Pomoć za povezivanje</translation>
<translation id="7323804146520582233">Sakrijte odjeljak "<ph name="SECTION" />"</translation>
@@ -1947,6 +1994,7 @@ Dodatne pojedinosti:
<translation id="7334320624316649418">&amp;Ponovi promjenu rasporeda</translation>
<translation id="7335157162773372339">Može tražiti dopuštenje za upotrebu kamere</translation>
<translation id="7337248890521463931">Prikaži više redaka</translation>
+<translation id="7337418456231055214">Broj virtualne kartice nije ispunjen? Kliknite podatke o kartici da biste kopirali. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">Nije dostupno na vašoj platformi.</translation>
<translation id="733923710415886693">Certifikat poslužitelja nije otkriven putem Transparentnosti certifikata.</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1969,6 +2017,7 @@ Dodatne pojedinosti:
<translation id="7378627244592794276">Ne</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">Nije primjenjivo</translation>
+<translation id="7388594495505979117">{0,plural, =1{Vaš će se uređaj ponovno pokrenuti za 1 minutu}one{Vaš će se uređaj ponovno pokrenuti za # minutu}few{Vaš će se uređaj ponovno pokrenuti za # minute}other{Vaš će se uređaj ponovno pokrenuti za # minuta}}</translation>
<translation id="7390545607259442187">Potvrda kartice</translation>
<translation id="7392089738299859607">Ažurirajte adresu</translation>
<translation id="7399802613464275309">Sigurnosna provjera</translation>
@@ -2005,6 +2054,12 @@ Dodatne pojedinosti:
<translation id="7485870689360869515">Nema pronađenih podataka.</translation>
<translation id="7495528107193238112">Ovaj je sadržaj blokiran. Obratite se vlasniku web-lokacije da biste riješili problem.</translation>
<translation id="7497998058912824456">Gumb Izradite dokument, pritisnite Enter da biste brzo izradili novi Google dokument</translation>
+<translation id="7506488012654002225">Chromium <ph name="BEGIN_EMPHASIS" />neće spremati<ph name="END_EMPHASIS" /> sljedeće podatke:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />vašu povijest pregledavanja
+ <ph name="LIST_ITEM" />kolaÄiće i podatke web-lokacija
+ <ph name="LIST_ITEM" />podatke koje unesete u obrasce.
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">Vraćeni ID ureÄ‘aja pravila prazan je ili ne odgovara trenutaÄnom ID-u ureÄ‘aja</translation>
<translation id="7508870219247277067">Zelenožuta</translation>
<translation id="7511955381719512146">Za Wi-Fi koji upotrebljavate možda ćete morati posjetiti stranicu <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
@@ -2118,7 +2173,6 @@ Dodatne pojedinosti:
<translation id="7813600968533626083">Želite li s Chromea ukloniti prijedlog za obrasce?</translation>
<translation id="781440967107097262">Dijeliti međuspremnik?</translation>
<translation id="7815407501681723534">Pronađeno <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> za "<ph name="SEARCH_STRING" />"</translation>
-<translation id="782125616001965242">Prikaži informacije o ovoj web-lokaciji</translation>
<translation id="782886543891417279">Za Wi-Fi koji upotrebljavate (<ph name="WIFI_NAME" />) možda ćete morati posjetiti stranicu za prijavu.</translation>
<translation id="7836231406687464395">Postfix (omotnica)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{Ništa}=1{1 aplikacija (<ph name="EXAMPLE_APP_1" />)}=2{2 aplikacije (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}one{# aplikacija (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}few{# aplikacije (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}other{# aplikacija (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}}</translation>
@@ -2135,7 +2189,6 @@ Dodatne pojedinosti:
<translation id="7888575728750733395">Namjera generiranja ispisa</translation>
<translation id="7894280532028510793">Ako nema pravopisnih pogrešaka, <ph name="BEGIN_LINK" />pokušajte pokrenuti Mrežnu dijagnostiku<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (omotnica)</translation>
-<translation id="7931318309563332511">Nepoznato</translation>
<translation id="793209273132572360">Želite li ažurirati adresu?</translation>
<translation id="7932579305932748336">Omot</translation>
<translation id="79338296614623784">Unesite važeći telefonski broj</translation>
@@ -2160,13 +2213,14 @@ Dodatne pojedinosti:
<translation id="7976214039405368314">Previše zahtjeva</translation>
<translation id="7977538094055660992">Izlazni uređaj</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">Povezano s</translation>
<translation id="798134797138789862">Može tražiti dopuštenje za upotrebu uređaja i podataka virtualne stvarnosti</translation>
<translation id="7984945080620862648">TrenutaÄno ne možete posjetiti <ph name="SITE" /> jer je web-lokacija poslala kodirane vjerodajnice koje Chrome ne može obraditi. Mrežne pogreÅ¡ke i napadi uglavnom su privremeni, tako da će ta stranica vjerojatno kasnije funkcionirati.</translation>
-<translation id="79859296434321399">Za prikaz sadržaja proširene stvarnosti instalirajte ARCore</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">Uvez</translation>
<translation id="7992044431894087211">Dijeljenje zaslona s aplikacijom <ph name="APPLICATION_TITLE" /> je nastavljeno</translation>
<translation id="7995512525968007366">Nije navedeno</translation>
+<translation id="7998269595945679889">Pritisnite gumb Otvori anonimnu karticu, pritisnite Enter da biste otvorili novu anonimnu karticu za pregledavanje u privatnosti</translation>
<translation id="800218591365569300">Pokušajte zatvoriti ostale kartice ili programe da biste oslobodili memoriju.</translation>
<translation id="8004582292198964060">Preglednik</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{Ova kartica i njezina adresa za naplatu spremit će se. Moći ćete plaćati njome kada ste prijavljeni na raÄun <ph name="USER_EMAIL" />.}one{Ove kartice i njihove adrese za naplatu spremit će se. Moći ćete plaćati njima kada ste prijavljeni na raÄun <ph name="USER_EMAIL" />.}few{Ove kartice i njihove adrese za naplatu spremit će se. Moći ćete plaćati njima kada ste prijavljeni na raÄun <ph name="USER_EMAIL" />.}other{Ove kartice i njihove adrese za naplatu spremit će se. Moći ćete plaćati njima kada ste prijavljeni na raÄun <ph name="USER_EMAIL" />.}}</translation>
@@ -2226,6 +2280,7 @@ Dodatne pojedinosti:
<translation id="8202370299023114387">Sukob</translation>
<translation id="8206978196348664717">Prc4 (omotnica)</translation>
<translation id="8211406090763984747">Veza je sigurna</translation>
+<translation id="8217240300496046857">Web-lokacije ne mogu upotrebljavati kolaÄiće koji vas prate na webu. ZnaÄajke na nekim web-lokacijama mogu prestati funkcionirati.</translation>
<translation id="8218327578424803826">Dodijeljena lokacija:</translation>
<translation id="8220146938470311105">C7/C6 (omotnica)</translation>
<translation id="8225771182978767009">Osoba koja je postavila raÄunalo blokirala je tu web-lokaciju.</translation>
@@ -2266,14 +2321,9 @@ Dodatne pojedinosti:
<translation id="830498451218851433">Presavijanje napola</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">koje su aplikacije instalirane i kako se Äesto upotrebljavaju</translation>
+<translation id="8317207217658302555">Ažurirati ARCore?</translation>
<translation id="831997045666694187">NaveÄer</translation>
<translation id="8321476692217554900">obavijesti</translation>
-<translation id="8328484624016508118">Nakon zatvaranja svih anonimnih kartica Chrome briše:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />vašu aktivnost pregledavanja na ovom uređaju<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />vašu povijest pretraživanja na ovom uređaju<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />podatke unesene u obrasce<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489">Pristup hostu <ph name="HOST_NAME" /> je odbijen</translation>
<translation id="833262891116910667">Istakni</translation>
<translation id="8339163506404995330">Neće se prevoditi <ph name="LANGUAGE" /></translation>
@@ -2325,6 +2375,7 @@ Dodatne pojedinosti:
<translation id="8507227106804027148">Naredbeni redak</translation>
<translation id="8508648098325802031">Ikona pretraživanja</translation>
<translation id="8511402995811232419">Upravljajte kolaÄićima</translation>
+<translation id="8519753333133776369">HID uređaj koji dopušta vaš administrator</translation>
<translation id="8522552481199248698">Chrome vam može pomoći da zaÅ¡titite svoj Google raÄun i promijenite zaporku.</translation>
<translation id="8530813470445476232">IzbriÅ¡ite povijest pregledavanja, kolaÄiće, predmemoriju i joÅ¡ mnogo toga u postavkama Chromea</translation>
<translation id="8533619373899488139">Posjetite &lt;strong&gt;chrome://policy&lt;/strong&gt; da biste vidjeli popis blokiranih URL-ova i druga pravila koja je postavio vaš administrator sustava.</translation>
@@ -2336,7 +2387,6 @@ Dodatne pojedinosti:
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{Poništi dopuštenje}one{Poništi dopuštenja}few{Poništi dopuštenja}other{Poništi dopuštenja}}</translation>
<translation id="8555010941760982128">Ovaj kôd primijenite pri naplati</translation>
<translation id="8557066899867184262">CVC možete pronaći na poleđini kartice.</translation>
-<translation id="8558485628462305855">Za prikaz sadržaja proširene stvarnosti ažurirajte ARCore</translation>
<translation id="8559762987265718583">Sigurnu vezu s domenom <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> nije moguće uspostaviti jer datum i vrijeme (<ph name="DATE_AND_TIME" />) na vaÅ¡em ureÄ‘aju nisu toÄni.</translation>
<translation id="8564182942834072828">Zasebni dokumenti/nerazvrstani primjerci</translation>
<translation id="8564985650692024650">Chromium preporuÄuje poniÅ¡tavanje zaporke za organizaciju <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> ako ste je upotrebljavali za druge web-lokacije.</translation>
@@ -2356,6 +2406,7 @@ Dodatne pojedinosti:
<translation id="865032292777205197">senzori kretanja</translation>
<translation id="8663226718884576429">Sažetak narudžbe, <ph name="TOTAL_LABEL" />, više pojedinosti</translation>
<translation id="8666678546361132282">Engleski</translation>
+<translation id="8669306706049782872">Prozore možete otvarati i postavljati pomoću podataka o zaslonima</translation>
<translation id="867224526087042813">Potpis</translation>
<translation id="8676424191133491403">Bez odgode</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, odgovor, <ph name="ANSWER" /></translation>
@@ -2382,6 +2433,7 @@ Dodatne pojedinosti:
<translation id="8731544501227493793">Gumb Upravljajte zaporkama, pritisnite Enter da biste vidjeli zaporke u Chromeovim postavkama i upravljali njima</translation>
<translation id="8734529307927223492">Vašim uređajem <ph name="DEVICE_TYPE" /> upravlja <ph name="MANAGER" /></translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, pritisnite Tab, a zatim Enter da biste otvorili novi anonimni prozor i pregledavali u privatnosti</translation>
+<translation id="8737685506611670901">otvoriti veze za protokol <ph name="PROTOCOL" /> umjesto <ph name="REPLACED_HANDLER_TITLE" /></translation>
<translation id="8738058698779197622">Za uspostavu sigurne veze sat mora biti toÄno postavljen. To je zato Å¡to certifikati koje web-lokacije upotrebljavaju za meÄ‘usobnu identifikaciju vrijede samo odreÄ‘eno vrijeme. Budući da sat na vaÅ¡em ureÄ‘aju nije toÄan, Chromium ne može potvrditi te certifikate.</translation>
<translation id="8740359287975076522">&lt;abbr id="dnsDefinition"&gt;DNS adresa&lt;/abbr&gt; hosta <ph name="HOST_NAME" /> nije pronađena. U tijeku je dijagnosticiranje problema.</translation>
<translation id="8742371904523228557"><ph name="ONE_TIME_CODE" /> je vaš kôd za <ph name="ORIGIN" /></translation>
@@ -2409,6 +2461,7 @@ Dodatne pojedinosti:
<translation id="883848425547221593">Druge oznake</translation>
<translation id="884264119367021077">Adresa za dostavu</translation>
<translation id="884923133447025588">Nije pronađen mehanizam za opoziv.</translation>
+<translation id="8849262850971482943">Koristite virtualnu karticu radi dodatne sigurnosti</translation>
<translation id="885730110891505394">Dijeljenje s Googleom</translation>
<translation id="8858065207712248076">Chrome preporuÄuje poniÅ¡tavanje zaporke za organizaciju <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> ako ste je upotrebljavali za druge web-lokacije.</translation>
<translation id="885906927438988819">Ako nema pravopisnih pogrešaka, <ph name="BEGIN_LINK" />pokušajte pokrenuti Mrežnu dijagnostiku sustava Windows<ph name="END_LINK" />.</translation>
@@ -2458,6 +2511,7 @@ Dodatne pojedinosti:
<translation id="9004367719664099443">U tijeku je VR sesija</translation>
<translation id="9005998258318286617">UÄitavanje PDF dokumenta nije uspjelo.</translation>
<translation id="9008201768610948239">Zanemari</translation>
+<translation id="901834265349196618">e-pošta</translation>
<translation id="9020200922353704812">Potrebna je adresa za naplatu kartice</translation>
<translation id="9020542370529661692">Ova je stranica prevedena na <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9020742383383852663">A8</translation>
@@ -2507,6 +2561,7 @@ i netoÄne vjerodajnice. To može znaÄiti da se neki napadaÄ pokuÅ¡ava predsta
<translation id="9150045010208374699">upotrijebiti vašu kameru</translation>
<translation id="9150685862434908345">Vaš administrator može daljinski promijeniti postavke preglednika. Aktivnostima na ovom uređaju može se upravljati i izvan Chromea. <ph name="BEGIN_LINK" />Saznajte više<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">Ažurirano</translation>
+<translation id="9155211586651734179">prikljuÄene periferne audioureÄ‘aje</translation>
<translation id="9157595877708044936">Postavljanje...</translation>
<translation id="9158625974267017556">C6 (omotnica)</translation>
<translation id="9164029392738894042">Provjera toÄnosti</translation>
diff --git a/chromium/components/strings/components_strings_hu.xtb b/chromium/components/strings/components_strings_hu.xtb
index b9ab1772827..eeff2d83565 100644
--- a/chromium/components/strings/components_strings_hu.xtb
+++ b/chromium/components/strings/components_strings_hu.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">Részletek megtekintése</translation>
<translation id="1030706264415084469">A(z) <ph name="URL" /> webhely állandó jelleggel nagy méretű adatokat szeretne tárolni az eszközön</translation>
<translation id="1032854598605920125">Forgatás jobbra</translation>
+<translation id="1033329911862281889">Az inkognitó mód nem teszi Önt láthatatlanná az interneten:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />a webhelyek és az általuk használt szolgáltatások láthatják, hogy felkereste őket;<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />a munkáltatók vagy az iskolák nyomon követhetik a böngészési tevékenységeket;<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />az internetszolgáltatók figyelhetik az internetes forgalmat.<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">Kikapcsolás</translation>
<translation id="1036982837258183574">A teljes képernyős nézetből való kilépéshez nyomja meg a következő billentyűt: |<ph name="ACCELERATOR" />|</translation>
<translation id="1038106730571050514">Javaslatok megjelenítése</translation>
<translation id="1038842779957582377">Ismeretlen név</translation>
<translation id="1041998700806130099">Munkalapi üzenet</translation>
<translation id="1048785276086539861">A jelölések szerkesztésekor a dokumentum visszaáll egyoldalas nézetre.</translation>
-<translation id="1049743911850919806">Inkognitó mód</translation>
<translation id="1050038467049342496">Zárja be a többi alkalmazást</translation>
<translation id="1055184225775184556">&amp;Hozzáadás visszavonása</translation>
<translation id="1056898198331236512">Figyelmeztetés</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">Irányelv-gyorsítótár OK</translation>
<translation id="1130564665089811311">Oldal lefordítása gomb, az Enter billentyű megnyomásával lefordíttathatja ezt az oldalt a Google Fordító segítségével</translation>
<translation id="1131264053432022307">Vágólapra másolt kép</translation>
+<translation id="1142846828089312304">Harmadik felektől származó cookie-k letiltása inkognitó módban</translation>
<translation id="1150979032973867961">A szerver nem tudta bizonyítani, hogy valóban a(z) <ph name="DOMAIN" /> domainbe tartozik; biztonsági tanúsítványa az Ön számítógépének operációs rendszere szerint nem megbízható. Ennek oka lehet konfigurációs hiba, vagy hogy egy támadó eltérítette az Ön kapcsolódását.</translation>
<translation id="1151972924205500581">Jelszó szükséges</translation>
<translation id="1156303062776767266">Helyi vagy megosztott fájlt tekint meg</translation>
@@ -64,13 +70,12 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="1178581264944972037">Szünet</translation>
<translation id="1181037720776840403">Eltávolítás</translation>
<translation id="1186201132766001848">Jelszavak ellenőrzése</translation>
-<translation id="1195210374336998651">Ugrás az alkalmazás beállításaihoz</translation>
<translation id="1195558154361252544">Az Ön által engedélyezett webhelyek kivételével a böngésző automatikusan letiltja az értesítéseket</translation>
<translation id="1197088940767939838">Narancssárga</translation>
<translation id="1201402288615127009">Tovább</translation>
<translation id="1201895884277373915">Továbbiak erről a webhelyről</translation>
<translation id="1206967143813997005">Hibás alapértelmezett aláírás</translation>
-<translation id="1209206284964581585">Elrejtés most</translation>
+<translation id="1209206284964581585">Elrejtés ideiglenesen</translation>
<translation id="1209221128712833642">Űrlap létrehozása gomb, nyomja meg az Enter billentyűt új űrlap gyors létrehozásához a Google Űrlapok szolgáltatással</translation>
<translation id="121201262018556460">Megpróbálta elérni a(z) <ph name="DOMAIN" /> webhelyet, de a szerver egy gyenge kulccsal rendelkező tanúsítványt adott. Egy támadó feltörhette a privát kulcsot, és lehet, hogy a szerver nem a várt kiszolgáló (lehet, hogy Ön egy támadóval kommunikál).</translation>
<translation id="1219129156119358924">Rendszerbiztonság</translation>
@@ -111,7 +116,7 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="1307966114820526988">Elavult funkciók</translation>
<translation id="1308113895091915999">Ajánlat áll rendelkezésre</translation>
<translation id="1312803275555673949">Milyen bizonyíték támasztja alá?</translation>
-<translation id="131405271941274527">A(z) <ph name="URL" /> adatokat akar küldeni, amikor Ön rákoppint telefonjára egy NFC-eszközön</translation>
+<translation id="1314311879718644478">Kiterjesztett valóságot használó tartalmak megtekintése</translation>
<translation id="1314509827145471431">Kötés a jobb oldalon</translation>
<translation id="1318023360584041678">Lapcsoportba mentve</translation>
<translation id="1319245136674974084">Ne legyen több kérdés ennél az alkalmazásnál</translation>
@@ -161,6 +166,7 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="142858679511221695">Felhőalapú szolgáltatás – felhasználó</translation>
<translation id="1428729058023778569">Azért látja ezt a figyelmeztetést, mert ez a webhely nem támogatja a HTTPS-t. <ph name="BEGIN_LEARN_MORE_LINK" />További információ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1430915738399379752">Nyomtatás</translation>
+<translation id="1432187715652018471">Ez az oldal szolgáltatáskezelőt kíván telepíteni.</translation>
<translation id="1432581352905426595">Keresőmotorok beállítása</translation>
<translation id="1436185428532214179">Engedélyt kérhet arra, hogy szerkeszthesse az Ön eszközén található fájlokat és mappákat</translation>
<translation id="1442386063175183758">Jobb oldalon kihajtható</translation>
@@ -181,6 +187,12 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="1483493594462132177">Küldés</translation>
<translation id="1484290072879560759">Szállítási cím kiválasztása</translation>
<translation id="1492194039220927094">Irányelvek leküldése:</translation>
+<translation id="149293076951187737">Amikor bezárja a Chrome összes inkognitó lapját, az érintett lapokon végzett tevékenységei, így akövetkezők is törlődnek erről az eszközről:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />böngészési tevékenységek;<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />keresési előzmények;<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />űrlapokon megadott információk.<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">Vissza a lapra</translation>
<translation id="1501859676467574491">Jelenítsen meg kártyákat az Ön Google-fiókjából</translation>
<translation id="1507202001669085618">&lt;p&gt;Ez a hiba akkor fordul elő, ha olyan Wi-Fi-portált használ, amely bejelentkezést igényel, mielőtt kapcsolódna az internethez.&lt;/p&gt;
@@ -208,6 +220,8 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="1559572115229829303">&lt;p&gt;Nem hozható létre privát kapcsolat a következővel: <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />, mert az eszköz dátum- és időbeállítása helytelen (<ph name="DATE_AND_TIME" />).&lt;/p&gt;
&lt;p&gt;Módosítsa a dátumot és az idÅ‘t a &lt;strong&gt;Beállítások&lt;/strong&gt; alkalmazás &lt;strong&gt;Ãltalános&lt;/strong&gt; részében.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">Adminisztrátora a következő időpontban újra fogja indítani az eszközét: <ph name="DATE" />, <ph name="TIME" /></translation>
+<translation id="156703335097561114">Hálózati információk, többek között címek, a kezelőfelület beállításai és a kapcsolat minősége</translation>
<translation id="1567040042588613346">A házirend az elvárt módon működik, de valahol máshol ugyanaz az érték van beállítva, amelyet felülír ez a házirend.</translation>
<translation id="1569487616857761740">Adja meg a lejárat dátumát</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="1583429793053364125">Valami nem sikerült a weboldal megjelenítése során.</translation>
<translation id="1586541204584340881">Ön milyen bővítményeket telepített.</translation>
<translation id="1588438908519853928">Normál</translation>
+<translation id="1589050138437146318">Biztosan telepíti az ARCore platformot?</translation>
<translation id="1592005682883173041">Helyi adatok elérése</translation>
<translation id="1594030484168838125">Kiválaszt</translation>
<translation id="160851722280695521">A Dino Run játék elindítása a Chrome-ban</translation>
@@ -283,6 +298,7 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
fejléc formátuma azonban nem megfelelő, így a böngésző nem tudja teljesíteni
a(z) <ph name="SITE" /> webhelyre irányuló kérelmet. Az eredetházirendek segítségével
a webhelyek üzemeltetői a webhely biztonsági és egyéb tulajdonságait konfigurálhatják.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />További információ a Chromium inkognitó módjáról<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">A megnyitott lapok helye</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -410,6 +426,7 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="22081806969704220">3. tálca</translation>
<translation id="2212735316055980242">Nem találhatók irányelvek</translation>
<translation id="2213606439339815911">Bejegyzések lekérése...</translation>
+<translation id="2213612003795704869">Oldal kinyomtatva</translation>
<translation id="2215727959747642672">Fájlszerkesztés</translation>
<translation id="2218879909401188352">A(z) <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> webhelyen lévő támadók veszélyes alkalmazásokat telepíthetnek, amelyek károsíthatják eszközét, rejtett költségeket okozhatnak a mobiltelefon-számlán, vagy ellophatják személyes adatait. <ph name="BEGIN_LEARN_MORE_LINK" />További információ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2224337661447660594">Nincs internet</translation>
@@ -419,6 +436,7 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="2248949050832152960">WebAuthn használata</translation>
<translation id="2250931979407627383">Éltűzés a bal oldalon</translation>
<translation id="225207911366869382">Ez az érték elavult ennél a házirendnél.</translation>
+<translation id="2256115617011615191">Újraindítás most</translation>
<translation id="2258928405015593961">Jövőbeli lejárati dátumot adjon meg, majd próbálja újra.</translation>
<translation id="225943865679747347">Hibakód: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">HTTP hiba</translation>
@@ -446,6 +464,7 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="2337852623177822836">A beállítást a rendszergazda szabályozza</translation>
<translation id="2340263603246777781">A(z) <ph name="ORIGIN" /> párosítást szeretne végrehajtani</translation>
<translation id="2346319942568447007">Vágólapra másolt kép</translation>
+<translation id="2350796302381711542">Engedélyezi az összes <ph name="PROTOCOL" /> link megnyitását a(z) <ph name="HANDLER_HOSTNAME" /> számára a(z) <ph name="REPLACED_HANDLER_TITLE" /> helyett?</translation>
<translation id="2354001756790975382">További könyvjelzők</translation>
<translation id="2354430244986887761">A Google Biztonságos Böngészés funkciója nemrég <ph name="BEGIN_LINK" />kártékony alkalmazásokat talált<ph name="END_LINK" /> a(z) <ph name="SITE" /> webhelyen.</translation>
<translation id="2355395290879513365">A felhasználók esetleg láthatják a webhelyen éppen megtekintett képeit, és a képeket módosítva félrevezethetik Önt.</translation>
@@ -471,6 +490,7 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="2413528052993050574">A szerver nem tudta bizonyítani, hogy valóban a(z) <ph name="DOMAIN" /> domainbe tartozik; biztonsági tanúsítványát visszavonhatták. Ennek oka lehet konfigurációs hiba, vagy hogy egy támadó eltérítette az Ön kapcsolódását.</translation>
<translation id="2414886740292270097">Sötét</translation>
<translation id="2430968933669123598">Google-fiók kezelése, nyomja meg az Enter billentyűt az adatai, az adatvédelem és a biztonság kezeléséhez a Google-fiókjában</translation>
+<translation id="2436186046335138073">Engedélyezi az összes <ph name="PROTOCOL" /> link megnyitását a(z) <ph name="HANDLER_HOSTNAME" /> számára?</translation>
<translation id="2438874542388153331">Négy lyuk a jobb oldalon</translation>
<translation id="2450021089947420533">Utazások</translation>
<translation id="2463739503403862330">Kitöltés</translation>
@@ -478,6 +498,7 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="2465655957518002998">Kézbesítési mód kiválasztása</translation>
<translation id="2465688316154986572">Kapocs</translation>
<translation id="2465914000209955735">Kezelheti a Chrome-ban letöltött fájlokat.</translation>
+<translation id="2466004615675155314">Az internetről származó információk megjelenítése</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Hálózati diagnosztika futtatása<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">„1 az N-hez†sorrend</translation>
<translation id="2470767536994572628">A jelölések szerkesztésekor a dokumentum visszaáll egyoldalas nézetbe és az eredeti tájolásba.</translation>
@@ -498,6 +519,7 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="2523886232349826891">Csak erre az eszközre mentve</translation>
<translation id="2524461107774643265">További adatok hozzáadása</translation>
<translation id="2529899080962247600">Ebben a mezőben legfeljebb <ph name="MAX_ITEMS_LIMIT" /> bejegyzés szerepelhet. A további bejegyzéseket figyelmen kívül hagyja a rendszer.</translation>
+<translation id="2535585790302968248">Privát böngészéshez nyisson új inkognitó lapot</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{és 1 további}other{és # további}}</translation>
<translation id="2536110899380797252">Cím hozzáadása</translation>
<translation id="2539524384386349900">Felismerés</translation>
@@ -523,7 +545,14 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="2597378329261239068">Ez a dokumentum jelszóval védett. Kérjük, adja meg a jelszót.</translation>
<translation id="2609632851001447353">Változatok</translation>
<translation id="2610561535971892504">Kattintson a másoláshoz</translation>
+<translation id="2617988307566202237">A Chrome <ph name="BEGIN_EMPHASIS" />nem menti<ph name="END_EMPHASIS" /> a következő adatokat:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />böngészési előzmények;
+ <ph name="LIST_ITEM" />cookie-k és webhelyadatok;
+ <ph name="LIST_ITEM" />űrlapokon megadott információk.
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (boríték)</translation>
+<translation id="2623663032199728144">Rákérdezhet a képernyőkön található információk használatára</translation>
<translation id="2625385379895617796">Az órája siet</translation>
<translation id="262745152991669301">Engedélyt kérhet az USB-eszközökhöz való csatlakozásra</translation>
<translation id="2629325967560697240">A Chrome legmagasabb szintű biztonságának eléréséhez <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />kapcsolja be a speciális védelmet<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -557,6 +586,7 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="2709516037105925701">Automatikus kitöltés</translation>
<translation id="2713444072780614174">Fehér</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />, nyomja le a Tab, majd az Enter billentyűt a fizetési és hitelkártyaadatoknak a Chrome beállításaiban való kezeléséhez</translation>
+<translation id="271663710482723385">A teljes képernyős módból való kilépéshez nyomja le a következő billentyűkombinációt: |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />|</translation>
<translation id="2721148159707890343">Sikeres kérés</translation>
<translation id="2723669454293168317">Biztonsági ellenőrzés futtatása a Chrome-beállításokban</translation>
<translation id="2726001110728089263">Oldalsó tálca</translation>
@@ -587,6 +617,7 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="2850739647070081192">Invite (boríték)</translation>
<translation id="2856444702002559011">A támadók megpróbálhatják ellopni a(z) <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> webhelyen lévő adatait (például jelszavait, üzeneteit és hitelkártyaadatait). <ph name="BEGIN_LEARN_MORE_LINK" />További információ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2859806420264540918">Ez a webhely tolakodó vagy félrevezető hirdetéseket jelenít meg.</translation>
+<translation id="286512204874376891">A virtuális kártya álcázza a tényleges kártyáját, így segíthet az esetleges csalások elleni védekezésben. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">Barátságos</translation>
<translation id="2876489322757410363">Az inkognitó mód elhagyása külső alkalmazással történő fizetéshez. Folytatja?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />. Nyomja le a Tab, majd az Enter billentyűt a Biztonságos Böngészés és más funkciók Chrome-beállítások közötti kezeléséhez.</translation>
@@ -611,6 +642,7 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="2930577230479659665">Vágás minden példány után</translation>
<translation id="2932085390869194046">Jelszó ajánlása…</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019"><ph name="PROTOCOL" /> linkek megnyitása</translation>
<translation id="2941952326391522266">A szerver nem tudta bizonyítani, hogy valóban a(z) <ph name="DOMAIN" /> domainbe tartozik; biztonsági tanúsítványa a következőről származik: <ph name="DOMAIN2" />. Ennek oka lehet konfigurációs hiba, vagy hogy egy támadó eltérítette az Ön kapcsolódását.</translation>
<translation id="2943895734390379394">Feltöltés ideje:</translation>
<translation id="2948083400971632585">Bármelyik kapcsolatlétesítésre használt proxyt letilthatja a beállítások oldalon.</translation>
@@ -643,6 +675,7 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="3037605927509011580">A manóba!</translation>
<translation id="3041612393474885105">Tanúsítvány adatai</translation>
<translation id="3044034790304486808">Keresés folytatása</translation>
+<translation id="305162504811187366">A Chrome távoliasztal-szolgáltatás előzményei, beleértve az időbélyegeket, a gazdagépeket és az ügyfelek munkamenet-azonosítóit is</translation>
<translation id="3060227939791841287">C9 (boríték)</translation>
<translation id="3061707000357573562">Javítókészlet szolgáltatás</translation>
<translation id="306573536155379004">A játék elindult.</translation>
@@ -681,6 +714,7 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="3197136577151645743">Engedélyt kérhet annak észlelésére, hogy Ön mikor használja aktívan az eszközt</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />. Nyomja le a Tab, majd az Enter billentyűt az adatok szinkronizálásának Chrome-beállítások közötti kezeléséhez.</translation>
<translation id="320323717674993345">Fizetés visszavonása</translation>
+<translation id="3203366800380907218">Az internetről</translation>
<translation id="3207960819495026254">Könyvjelző rögzítve</translation>
<translation id="3209034400446768650">Az oldal díjat számíthat fel</translation>
<translation id="3212581601480735796">Figyelik a(z) <ph name="HOSTNAME" /> webhelyen végzett tevékenységeit</translation>
@@ -697,10 +731,12 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="3234666976984236645">Mindig észlelje a fontos tartalmat ezen a webhelyen</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />. Nyomja le a Tab, majd az Enter billentyűt a böngésző megjelenésének személyre szabásához.</translation>
<translation id="3240791268468473923">A biztonságos fizetés hitelesítési adataihoz tartozó nem egyező hitelesítési adatok űrlapja megnyitva</translation>
+<translation id="324180406144491771">A(z) „<ph name="HOST_NAME" />†linkjei le vannak tiltva</translation>
<translation id="3249845759089040423">Izgalmas</translation>
<translation id="3252266817569339921">francia</translation>
<translation id="3257954757204451555">Kitől származik ez az információ?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />, tartsa lenyomva a Tab billentyűt, majd nyomja meg az Enter billentyűt új esemény gyors létrehozásához a Google Naptár szolgáltatással</translation>
+<translation id="3261488570342242926">További információ a virtuális kártyákról</translation>
<translation id="3264837738038045344">A Chrome beállításainak kezelése gomb. Nyomja le az Enter gombot a Chrome beállításainak megnyitásához.</translation>
<translation id="3266793032086590337">Érték (ütközés)</translation>
<translation id="3268451620468152448">Megnyitott lapok</translation>
@@ -714,6 +750,7 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="3288238092761586174">Előfordulhat, hogy a(z) <ph name="URL" /> webhelynek további lépések megtételére van szüksége az Ön fizetésének ellenőrzéséhez.</translation>
<translation id="3293642807462928945">További információ a(z) <ph name="POLICY_NAME" /> házirendről</translation>
<translation id="3295444047715739395">Jelszavait a Chrome-beállítások között tekintheti meg és kezelheti</translation>
+<translation id="3303795387212510132">Engedélyezi az alkalmazásnak, hogy <ph name="PROTOCOL_SCHEME" />-linkeket nyisson meg?</translation>
<translation id="3303855915957856445">Nincs találat</translation>
<translation id="3304073249511302126">Bluetooth-alapú keresés</translation>
<translation id="3308006649705061278">Szervezeti egység (OU)</translation>
@@ -727,12 +764,6 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="3345782426586609320">Szem</translation>
<translation id="3355823806454867987">Proxybeállítások módosítása...</translation>
<translation id="3360103848165129075">Fizetési információk munkalapja</translation>
-<translation id="3361596688432910856">A Chrome <ph name="BEGIN_EMPHASIS" />nem menti<ph name="END_EMPHASIS" /> a következő adatokat:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Böngészési előzmények
- <ph name="LIST_ITEM" />Cookie-k és webhelyadatok
- <ph name="LIST_ITEM" />Å°rlapokon megadott adatok
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">Ezt a házirendet a rendszer automatikusan másolta át a megszüntetett <ph name="OLD_POLICY" /> házirendből. Használja ezt a házirendet.</translation>
<translation id="3364869320075768271">A(z) <ph name="URL" /> webhely használni szeretné az Ön virtuálisvalóság-eszközeit és -adatait</translation>
<translation id="3366477098757335611">Kártyák megtekintése</translation>
@@ -815,7 +846,6 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="3587738293690942763">Közép</translation>
<translation id="3592413004129370115">Italian (boríték)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{Csoportját bármikor visszaállíthatja. Az új csoporthoz való csatlakozás körülbelül egy napig tart.}=1{Csoportját bármikor visszaállíthatja. Az új csoporthoz való csatlakozás körülbelül egy napig tart.}other{Csoportját bármikor visszaállíthatja. Az új csoporthoz való csatlakozás körülbelül {NUM_DAYS} napig tart.}}</translation>
-<translation id="3596012367874587041">Alkalmazásbeállítások</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">A rendszergazda letiltotta az alkalmazást</translation>
<translation id="3608932978122581043">Adagolás tájolása</translation>
@@ -858,6 +888,7 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="370972442370243704">Utazások bekapcsolása</translation>
<translation id="3711895659073496551">Felfüggesztés</translation>
<translation id="3712624925041724820">Az engedélyek elfogytak</translation>
+<translation id="3714633008798122362">internetes naptár</translation>
<translation id="3714780639079136834">A mobiladatok vagy a Wi-Fi bekapcsolása</translation>
<translation id="3715597595485130451">Csatlakozás Wi-Fi-hálózathoz</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />A proxy, a tűzfal és a DNS-konfiguráció ellenőrzése<ph name="END_LINK" /></translation>
@@ -919,6 +950,7 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="3906954721959377182">Táblagép</translation>
<translation id="3909477809443608991">A(z) <ph name="URL" /> védett tartalmat szeretne lejátszani. Miután a Google azonosítja az eszközt, hozzáférést adhat a webhely számára.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">Megtagadás</translation>
<translation id="3939773374150895049">A WebAuthn szolgáltatást szeretné használni a CVC helyett?</translation>
<translation id="3946209740501886391">Mindig kérdezze meg ezen a webhelyen</translation>
<translation id="3947595700203588284">Engedélyt kérhet a MIDI-eszközökhöz való csatlakozásra</translation>
@@ -940,6 +972,7 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="3990250421422698716">Példányok eltolása</translation>
<translation id="3996311196211510766">A(z) <ph name="ORIGIN" /> webhely egy adott eredetházirend alkalmazását kérte
az összes kérésére, de ez a házirend jelenleg nem alkalmazható.</translation>
+<translation id="4009243425692662128">A böngésző elemzés céljából a Google Cloudnak vagy harmadik feleknek továbbítja a kinyomtatott oldalak tartalmát. A Google Cloud vagy a harmadik fél például bizalmas adatokat kereshet a szövegekben.</translation>
<translation id="4010758435855888356">Engedélyezi a tárhelyhozzáférést?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{{COUNT} oldalból álló PDF-dokumentum}other{{COUNT} oldalból álló PDF-dokumentum}}</translation>
<translation id="4023431997072828269">Mivel az űrlap beküldéséhez nem biztonságos kapcsolatot használ, az Ön adatait mások is láthatják majd.</translation>
@@ -1034,6 +1067,7 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="4250680216510889253">Nem</translation>
<translation id="4253168017788158739">Jegyzet</translation>
<translation id="425582637250725228">Előfordulhat, hogy módosításait nem menti a rendszer.</translation>
+<translation id="425869179292622354">Szeretné fokozni a biztonságát virtuális kártyával?</translation>
<translation id="4258748452823770588">Rossz aláírás</translation>
<translation id="4261046003697461417">A védett dokumentumoknál nem lehetséges a jegyzetelés</translation>
<translation id="4265872034478892965">A rendszergazda engedélyezte</translation>
@@ -1096,6 +1130,7 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="4434045419905280838">Előugró ablakok és átirányítások</translation>
<translation id="4435702339979719576">képeslap)</translation>
<translation id="443673843213245140">A proxy használata le van tiltva, de kifejezett proxykonfiguráció van megadva.</translation>
+<translation id="4441832193888514600">Figyelmen kívül hagyva, mert a szabályzatot csak felhőalapú felhasználói szabályzatként lehet beállítani.</translation>
<translation id="4450893287417543264">Ne jelenjen meg többé</translation>
<translation id="4451135742916150903">Engedélyt kérhet a HID-eszközökhöz való csatlakozásra</translation>
<translation id="4452328064229197696">Kiderült, hogy a most használt jelszava adatvédelmi incidensben volt érintett. Fiókjai biztonságának megőrzése érdekében a Google Jelszókezelő a mentett jelszavak ellenőrzését javasolja.</translation>
@@ -1151,6 +1186,7 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="4628948037717959914">Fénykép</translation>
<translation id="4631649115723685955">Pénzvisszatérítéssel összekapcsolva</translation>
<translation id="4636930964841734540">Információ</translation>
+<translation id="4638670630777875591">Inkognitó a Chromiumban</translation>
<translation id="464342062220857295">Funkciók keresése</translation>
<translation id="4644670975240021822">Fordított sorrend, lefelé fordítva</translation>
<translation id="4646534391647090355">Megnézem most</translation>
@@ -1171,6 +1207,7 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="4708268264240856090">Kapcsolata megszakadt</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />A Windows Hálózati diagnosztika futtatása<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426">A(z) <ph name="USERNAME" /> felhasználónévhez tartozó jelszó</translation>
<translation id="4724144314178270921">Engedélyt kérhet arra, hogy lássa a vágólapon szereplő szöveget és képeket</translation>
<translation id="4726672564094551039">Házirendek újratöltése</translation>
<translation id="4728558894243024398">Platform</translation>
@@ -1192,6 +1229,7 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="4757993714154412917">Megtévesztő webhelyen adta meg jelszavát. Fiókjai védelmében a Chromium azt javasolja, hogy ellenőrizze mentett jelszavait.</translation>
<translation id="4758311279753947758">Névjegyadatok hozzáadása</translation>
<translation id="4761104368405085019">Mikrofon használata</translation>
+<translation id="4761869838909035636">A Chrome biztonsági ellenőrzésének futtatása</translation>
<translation id="4764776831041365478">A <ph name="URL" /> weboldal ideiglenesen nem érhető el, vagy véglegesen új címre költözött.</translation>
<translation id="4766713847338118463">Kettő kapocs alul</translation>
<translation id="4771973620359291008">Ismeretlen hiba történt.</translation>
@@ -1212,12 +1250,6 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="4819347708020428563">Szeretné a jelöléseket az alapértelmezett nézetben szerkeszteni?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />, tartsa lenyomva a Tab billentyűt, majd nyomja meg az Enter billentyűt új Google-táblázat gyors létrehozásához</translation>
<translation id="4825507807291741242">Erőteljes</translation>
-<translation id="4827402517081186284">Az inkognitó mód nem teszi Önt láthatatlanná az interneten:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />A webhelyek tudják, amikor Ön felkeresi őket<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />A munkáltatók vagy az iskolák nyomon követhetik a böngészési tevékenységeket<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Az internetszolgáltatók figyelhetik az internetes forgalmat<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">Figyelmeztetések bekapcsolása</translation>
<translation id="4838327282952368871">Ãlmodozó</translation>
<translation id="4840250757394056958">Chrome-előzmények megtekintése</translation>
@@ -1229,12 +1261,12 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="4854362297993841467">Ez a kézbesítési mód nem áll rendelkezésre. Próbálkozzon másik móddal.</translation>
<translation id="4854853140771946034">Új jegyzet gyors létrehozása a Google Keep szolgáltatással</translation>
<translation id="485902285759009870">Kód ellenőrzése…</translation>
+<translation id="4866506163384898554">A kurzor megjelenítéséhez nyomja le a következő billentyűkombinációt: |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />|</translation>
<translation id="4876188919622883022">Egyszerűsített nézet</translation>
<translation id="4876305945144899064">Nincs felhasználónév</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{Nincs}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831"><ph name="TEXT" /> keresése</translation>
<translation id="4879491255372875719">Automatikus (alapértelmezett)</translation>
-<translation id="4879725228911483934">Megnyitni az ablakokat és elhelyezni őket a képernyőkön</translation>
<translation id="4880827082731008257">Keresés az előzmények között</translation>
<translation id="4881695831933465202">Megnyitás</translation>
<translation id="4885256590493466218">Fizetés a(z) <ph name="CARD_DETAIL" /> kártyával</translation>
@@ -1243,6 +1275,7 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" /> és <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">9. tekercs</translation>
<translation id="4901778704868714008">Mentés…</translation>
+<translation id="4905659621780993806">Rendszergazdája a következő időpontban automatikusan újra fogja indítani az eszközét: <ph name="DATE" /> <ph name="TIME" />. Az eszköz újraindítása előtt mentse az összes megnyitott elemet.</translation>
<translation id="4913987521957242411">Lyuk balra fent</translation>
<translation id="4918221908152712722"><ph name="APP_NAME" /> telepítése (nincs szükség letöltésre)</translation>
<translation id="4923459931733593730">Fizetés</translation>
@@ -1251,6 +1284,7 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="4926340098269537727"><ph name="TOTAL_MATCHCOUNT" />/<ph name="ACTIVE_MATCH" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, a kereséshez nyomja le a Tab, majd az Enter gombot</translation>
<translation id="4930153903256238152">Nagy kapacitás</translation>
+<translation id="4940163644868678279">Inkognitó a Chrome-ban</translation>
<translation id="4943872375798546930">Nincs találat</translation>
<translation id="4950898438188848926">Lapváltó gomb. Nyomja meg az Entert a következő megnyitott lapra való váltáshoz: <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="495170559598752135">Műveletek</translation>
@@ -1260,6 +1294,7 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="4968522289500246572">Ez az alkalmazás mobileszközökre készült, átméretezése nem feltétlenül működik megfelelően. Az alkalmazásnál problémák merülhetnek fel, esetleges újraindítása szükséges.</translation>
<translation id="4969341057194253438">Felvétel törlése</translation>
<translation id="4973922308112707173">Két lyuk felül</translation>
+<translation id="4976702386844183910">Utolsó látogatás: <ph name="DATE" /></translation>
<translation id="4984088539114770594">Engedélyezi a mikrofon használatát?</translation>
<translation id="4984339528288761049">Prc5 (boríték)</translation>
<translation id="4989163558385430922">Összes megtekintése</translation>
@@ -1321,6 +1356,7 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="5138227688689900538">Kevesebb megjelenítése</translation>
<translation id="5145883236150621069">Az irányelv válasza hibakódot tartalmaz</translation>
<translation id="5146995429444047494">A(z) <ph name="ORIGIN" /> értesítései le vannak tiltva</translation>
+<translation id="514704532284964975">A(z) <ph name="URL" /> szeretné megtekinteni az eszközéhez érintett NFC-eszközökön található információkat, és információkat cserélni az ilyen eszközökkel</translation>
<translation id="5148809049217731050">Felfelé fordítva</translation>
<translation id="515292512908731282">C4 (boríték)</translation>
<translation id="5158275234811857234">Borító</translation>
@@ -1345,6 +1381,7 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="5215116848420601511">A Google Pay szolgáltatásban használt fizetési módok és címek</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">13. tálca</translation>
+<translation id="5216942107514965959">Utolsó látogatás: ma</translation>
<translation id="5222812217790122047">Az e-mail-cím megadása kötelező</translation>
<translation id="5230733896359313003">Szállítási cím</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1365,7 +1402,6 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">Dokumentum tulajdonságai</translation>
<translation id="528468243742722775">Befejezés</translation>
-<translation id="5284909709419567258">Hálózati címek</translation>
<translation id="5285570108065881030">Az összes mentett jelszó megjelenítése</translation>
<translation id="5287240709317226393">Cookie-k megjelenítése</translation>
<translation id="5287456746628258573">Ez a webhely elavult biztonsági konfigurációt használ, ezért előfordulhat, hogy mások látják az Ön adatait (például jelszavait vagy hitelkártyaszámait), amikor elküldi őket a webhelynek.</translation>
@@ -1449,6 +1485,7 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="5556459405103347317">Újratöltés</translation>
<translation id="5560088892362098740">Lejárati dátum</translation>
<translation id="55635442646131152">Dokumentumvázlat</translation>
+<translation id="5565613213060953222">Inkognitó lap megnyitása</translation>
<translation id="5565735124758917034">Aktív</translation>
<translation id="5570825185877910964">Fiók védelme</translation>
<translation id="5571083550517324815">Ezen a címen nem lehetséges az átvétel. Válasszon másik címet.</translation>
@@ -1531,6 +1568,7 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="5869522115854928033">Mentett jelszavak</translation>
<translation id="5873013647450402046">Bankja szeretné, ha megerősítené személyazonosságát.</translation>
<translation id="5887400589839399685">Kártya elmentve</translation>
+<translation id="5887687176710214216">Utolsó látogatás: tegnap</translation>
<translation id="5895138241574237353">Újraindítás</translation>
<translation id="5895187275912066135">Kiállítva</translation>
<translation id="5901630391730855834">Sárga</translation>
@@ -1544,6 +1582,7 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="5921639886840618607">Menti a kártyát a Google-fiókjába?</translation>
<translation id="5922853866070715753">Majdnem kész</translation>
<translation id="5932224571077948991">A webhely tolakodó vagy félrevezető hirdetéseket jelenít meg</translation>
+<translation id="5938153366081463283">Hozzáadhat virtuális kártyát</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347">A(z) <ph name="SITE_NAME" /> megnyitása…</translation>
<translation id="5951495562196540101">Fogyasztói fiókkal nem lehet regisztrálni (a csomaghoz tartozik licenc is).</translation>
@@ -1608,6 +1647,7 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="6120179357481664955">Emlékszik UPI-azonosítójára?</translation>
<translation id="6124432979022149706">Chrome Enterprise csatlakozási szoftverek</translation>
<translation id="6127379762771434464">Elem eltávolítva</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />További információ a Chrome inkognitó módjáról<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">Ellenőrizze a kábeleket, majd indítsa újra a routert, modemet vagy más
hálózati eszközt, amelyet használ.</translation>
<translation id="614940544461990577">Próbálja ki a következőket:</translation>
@@ -1620,7 +1660,6 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="6169916984152623906">Most privát módon böngészhet, így az eszközt használó többi személy nem láthatja az Ön tevékenységeit. A letöltéseket és a könyvjelzőket azonban menti a rendszer.</translation>
<translation id="6177128806592000436">Kapcsolata a webhellyel nem biztonságos</translation>
<translation id="6180316780098470077">Újrapróbálkozások közötti idő</translation>
-<translation id="619448280891863779">Engedélyt kérhet ablakok megnyitására és elhelyezésére a képernyőn</translation>
<translation id="6196640612572343990">Harmadik féltől származó cookie-k letiltása</translation>
<translation id="6203231073485539293">Ellenőrizze az internetkapcsolatot</translation>
<translation id="6218753634732582820">Eltávolítja a címet a Chromiumból?</translation>
@@ -1643,7 +1682,7 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="6272383483618007430">Google Frissítés</translation>
<translation id="6276112860590028508">Az olvasási listájának adatai itt jelennek meg</translation>
<translation id="627746635834430766">A következő alkalommal gyorsabban fizethet, ha Google-fiókjába menti kártyáját és számlázási címét.</translation>
-<translation id="6279098320682980337">Nincs kitöltve a virtuális kártya száma? Kattintson a másolni kívánt kártyaadatokra</translation>
+<translation id="6279183038361895380">Az egérmutató megjelenítéséhez nyomja meg a következő billentyűt: |<ph name="ACCELERATOR" />|</translation>
<translation id="6280223929691119688">Erre a címre nem lehetséges a kézbesítés. Válasszon másik címet.</translation>
<translation id="6282194474023008486">Irányítószám</translation>
<translation id="6285507000506177184">Letöltések kezelése a Chrome-ban gomb. Nyomja le az Enter billentyűt a Chrome-ban letöltött fájlok kezeléséhez.</translation>
@@ -1651,6 +1690,7 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="6290238015253830360">A javasolt cikkek helye</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{Eszköze most újraindul}=1{Eszköze 1 másodperc múlva újraindul}other{Eszköze # másodperc múlva újraindul}}</translation>
<translation id="6302269476990306341">A Google Segéd a Chrome-ban szolgáltatás leáll</translation>
<translation id="6305205051461490394">A(z) <ph name="URL" /> nem érhető el.</translation>
<translation id="6312113039770857350">A weboldal nem érhető el</translation>
@@ -1724,6 +1764,7 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="6529602333819889595">&amp;Törlés újra</translation>
<translation id="6545864417968258051">Bluetooth-alapú keresés</translation>
<translation id="6547208576736763147">Kettő lyuk a bal oldalon</translation>
+<translation id="6554732001434021288">Utolsó látogatás: <ph name="NUM_DAYS" /> napja</translation>
<translation id="6556866813142980365">Újra</translation>
<translation id="6569060085658103619">Jelenleg bővítményoldalt tekint meg</translation>
<translation id="6573200754375280815">Kettő lyuk a jobb oldalon</translation>
@@ -1784,7 +1825,6 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="6757797048963528358">Eszköze alvó üzemmódba váltott.</translation>
<translation id="6767985426384634228">Frissíti a címet?</translation>
<translation id="6768213884286397650">Hagaki (képeslap)</translation>
-<translation id="6774185088257932239"><ph name="BEGIN_LINK" />További információ<ph name="END_LINK" /> az inkognitó módról.</translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">Ibolyaszín</translation>
<translation id="6786747875388722282">Bővítmények</translation>
@@ -1868,7 +1908,6 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="706295145388601875">Címek hozzáadása és kezelése a Chrome-beállítások között</translation>
<translation id="7064851114919012435">Kapcsolatfelvételi adatok</translation>
<translation id="7068733155164172741">Adja meg a kapott, <ph name="OTP_LENGTH" /> számjegyből álló kódot</translation>
-<translation id="7070090581017165256">A webhelyről</translation>
<translation id="70705239631109039">Kapcsolata nem teljesen biztonságos</translation>
<translation id="7075452647191940183">A kérés túl nagy</translation>
<translation id="7079718277001814089">A webhely rosszindulatú programokat tartalmaz</translation>
@@ -1885,6 +1924,12 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="7111012039238467737">(Érvényes)</translation>
<translation id="7118618213916969306">Vágólapon lévő URL, <ph name="SHORT_URL" /> keresése</translation>
<translation id="7119414471315195487">Zárja be a többi lapot vagy programot</translation>
+<translation id="7129355289156517987">Amikor bezárja a Chromium összes inkognitó lapját, az érintett lapokon végzett tevékenységei, így a következők is törlődnek erről az eszközről:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />böngészési tevékenységek;<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />keresési előzmények;<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />űrlapokon megadott információk.<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">Erre a címre nem lehetséges a szállítás. Válasszon másik címet.</translation>
<translation id="7132939140423847331">A rendszergazda nem engedélyezi az adatok másolását.</translation>
<translation id="7135130955892390533">Ãllapot megjelenítése</translation>
@@ -1907,6 +1952,7 @@ Ezt egyéb esetben letiltják az Ön adatvédelmi beállításai. Az engedélyez
<translation id="7192203810768312527"><ph name="SIZE" /> szabadul fel. Előfordulhat, hogy bizonyos oldalak lassabban töltődnek be, amikor legközelebb felkeresi őket.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">Rendszergazdája a következőket láthatja:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, nyomja le a Tab, majd az Enter billentyűt új inkognitó lap megnyitásához, ahol privát módon böngészhet</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423">A(z) <ph name="HOST_NAME" /> nem felel meg a biztonsági szabványoknak.</translation>
<translation id="7210993021468939304">A tárolóban végzett linuxos tevékenység megtekintése, valamint Linux-alkalmazások telepítése és futtatása a tárolóban</translation>
@@ -1938,6 +1984,7 @@ További részletek:
<translation id="7304562222803846232">A Google-fiók adatvédelmi beállításainak kezelése</translation>
<translation id="7305756307268530424">Indítás lassabban</translation>
<translation id="7308436126008021607">szinkronizálás a háttérben</translation>
+<translation id="7310392214323165548">Az eszköz hamarosan újraindul</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">Segítség a kapcsolódáshoz</translation>
<translation id="7323804146520582233">A(z) „<ph name="SECTION" />†szakasz elrejtése</translation>
@@ -1945,6 +1992,7 @@ További részletek:
<translation id="7334320624316649418">&amp;Ãtrendezés újra</translation>
<translation id="7335157162773372339">Hozzáférést kérhet a kamerához</translation>
<translation id="7337248890521463931">Több sor megjelenítése</translation>
+<translation id="7337418456231055214">Nincs kitöltve a virtuális kártya száma? Kattintson a másolni kívánt kártyaadatokra. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">Nem áll rendelkezésre ezen a platformon.</translation>
<translation id="733923710415886693">A szerver tanúsítványát nem A tanúsítványok átláthatósága keretrendszeren keresztül hozták nyilvánosságra.</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1967,6 +2015,7 @@ További részletek:
<translation id="7378627244592794276">Nem</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">–</translation>
+<translation id="7388594495505979117">{0,plural, =1{Eszköze 1 perc múlva újraindul}other{Eszköze # perc múlva újraindul}}</translation>
<translation id="7390545607259442187">Kártya igazolása</translation>
<translation id="7392089738299859607">Cím frissítése</translation>
<translation id="7399802613464275309">Biztonsági ellenőrzés</translation>
@@ -2003,6 +2052,12 @@ További részletek:
<translation id="7485870689360869515">Nem található adat.</translation>
<translation id="7495528107193238112">Ez a tartalom le van tiltva. Vegye fel a kapcsolatot a webhely tulajdonosával a probléma elhárításához.</translation>
<translation id="7497998058912824456">Dokumentum létrehozása gomb, nyomja meg az Enter billentyűt egy új Google-dokumentum gyors létrehozásához</translation>
+<translation id="7506488012654002225">A Chromium <ph name="BEGIN_EMPHASIS" />nem menti<ph name="END_EMPHASIS" /> a következő adatokat:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />böngészési előzmények;
+ <ph name="LIST_ITEM" />cookie-k és webhelyadatok;
+ <ph name="LIST_ITEM" />űrlapokon megadott információk.
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">A visszakapott házirend eszközazonosítója üres, vagy nem felel meg a jelenlegi eszközazonosítónak</translation>
<translation id="7508870219247277067">Avokádózöld</translation>
<translation id="7511955381719512146">Az Ön által használt Wi-Fi-hálózat megkövetelheti a(z) <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> felkeresését.</translation>
@@ -2116,7 +2171,6 @@ További részletek:
<translation id="7813600968533626083">Eltávolítja a javaslatot a Chrome-ból?</translation>
<translation id="781440967107097262">Engedélyezi a vágólap megosztását?</translation>
<translation id="7815407501681723534"><ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> található a(z) „<ph name="SEARCH_STRING" />†kifejezésre</translation>
-<translation id="782125616001965242">Információ megjelenítése erről a webhelyről</translation>
<translation id="782886543891417279">Az Ön által használt Wi-Fi-hálózat (<ph name="WIFI_NAME" />) megkövetelheti a bejelentkezést a bejelentkezési oldalán.</translation>
<translation id="7836231406687464395">Postfix (boríték)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{Nincs}=1{1 alkalmazás (<ph name="EXAMPLE_APP_1" />)}=2{2 alkalmazás (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}other{# alkalmazás (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" /> <ph name="AND_MORE" />)}}</translation>
@@ -2133,7 +2187,6 @@ További részletek:
<translation id="7888575728750733395">Nyomatmegjelenítési szándék</translation>
<translation id="7894280532028510793">Ha helyesen írta, <ph name="BEGIN_LINK" />próbálkozzon a hálózati diagnosztika futtatásával<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (boríték)</translation>
-<translation id="7931318309563332511">Ismeretlen</translation>
<translation id="793209273132572360">Frissíti a címet?</translation>
<translation id="7932579305932748336">Bevonat</translation>
<translation id="79338296614623784">Érvényes telefonszámot adjon meg</translation>
@@ -2158,13 +2211,14 @@ További részletek:
<translation id="7976214039405368314">Túl sok kérelem</translation>
<translation id="7977538094055660992">Kimeneti eszköz</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">Összekapcsolva a következővel:</translation>
<translation id="798134797138789862">Hozzáférést kérhet a virtuálisvalóság-eszközökhöz és -adatokhoz</translation>
<translation id="7984945080620862648">Pillanatnyilag nem tudja felkeresni a(z) <ph name="SITE" /> webhelyet, mivel a webhely olyan titkosított hitelesítő adatokat küldött, amelyeket a Chrome nem tud feldolgozni. A hálózati hibák és támadások rendszerint átmenetiek, ezért az említett oldal később valószínűleg már működni fog.</translation>
-<translation id="79859296434321399">A kiterjesztett valósággal kapcsolatos tartalmak megtekintéséhez telepítse az ARCore-t</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">Kötés</translation>
<translation id="7992044431894087211">Képernyőmegosztás folytatva a(z) <ph name="APPLICATION_TITLE" /> alkalmazással</translation>
<translation id="7995512525968007366">Nincs megadva</translation>
+<translation id="7998269595945679889">Inkognitó lap megnyitása gomb, nyomja meg az Enter billentyűt új inkognitó lap megnyitásához, ahol privát módon böngészhet</translation>
<translation id="800218591365569300">Próbáljon meg bezárni más lapokat vagy programokat memória felszabadítása céljából.</translation>
<translation id="8004582292198964060">Böngésző</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{A kártyát és a számlázási címet elmentjük. Az adatok kéznél lesznek, amíg <ph name="USER_EMAIL" /> e-mail-című fiókját használja.}other{A kártyákat és a számlázási címeket elmentjük. Az adatok kéznél lesznek, amíg <ph name="USER_EMAIL" /> e-mail-című fiókját használja.}}</translation>
@@ -2224,6 +2278,7 @@ További részletek:
<translation id="8202370299023114387">Ütközés</translation>
<translation id="8206978196348664717">Prc4 (boríték)</translation>
<translation id="8211406090763984747">A kapcsolat biztonságos</translation>
+<translation id="8217240300496046857">A webhelyek nem tudnak olyan cookie-kat használni, amelyek nyomon követik tevékenységeit az interneten. Előfordulhat, hogy bizonyos webhelyek funkciói nem működnek majd megfelelően.</translation>
<translation id="8218327578424803826">Hozzárendelt helyszín:</translation>
<translation id="8220146938470311105">C7/C6 (boríték)</translation>
<translation id="8225771182978767009">A számítógépet beállító személy a webhely letiltása mellett döntött.</translation>
@@ -2264,14 +2319,9 @@ További részletek:
<translation id="830498451218851433">Félbehajtás</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">Telepített alkalmazások és a használatuk gyakorisága</translation>
+<translation id="8317207217658302555">Biztosan frissíti az ARCore platformot?</translation>
<translation id="831997045666694187">Este</translation>
<translation id="8321476692217554900">értesítések</translation>
-<translation id="8328484624016508118">Az összes inkognitó lap bezárása után a Chrome törli a következőket:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Az Ön ezen az eszközön végzett böngészési tevékenységeit<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Az Ön ezen az eszközön található keresési előzményeit<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Az űrlapokon megadott adatokat<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489">A hozzáférés megtagadva a következőhöz: <ph name="HOST_NAME" /></translation>
<translation id="833262891116910667">Kiemelés</translation>
<translation id="8339163506404995330">A(z) <ph name="LANGUAGE" /> nyelvű oldalak nem lesznek lefordítva</translation>
@@ -2323,6 +2373,7 @@ További részletek:
<translation id="8507227106804027148">Parancssor</translation>
<translation id="8508648098325802031">Keresés ikon</translation>
<translation id="8511402995811232419">Cookie-k kezelése</translation>
+<translation id="8519753333133776369">Rendszergazda által engedélyezett HID-eszköz</translation>
<translation id="8522552481199248698">A Chrome segíthet a Google-fiók védelmében és a jelszó módosításában.</translation>
<translation id="8530813470445476232">A böngészési előzmények, a cookie-k, a gyorsítótár és egyebek törlése a Chrome-beállítások között</translation>
<translation id="8533619373899488139">A &lt;strong&gt;chrome://policy&lt;/strong&gt; oldalon láthatja a rendszergazda által letiltott URL-ek és a beállított egyéb kötelező irányelvek listáját.</translation>
@@ -2334,7 +2385,6 @@ További részletek:
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{Engedély visszaállítása}other{Engedélyek visszaállítása}}</translation>
<translation id="8555010941760982128">Adja meg ezt a kódot a fizetésnél:</translation>
<translation id="8557066899867184262">A CVC-kód a kártya hátulján található.</translation>
-<translation id="8558485628462305855">A kiterjesztett valósággal kapcsolatos tartalmak megtekintéséhez frissítse az ARCore-t</translation>
<translation id="8559762987265718583">Nem hozható létre privát kapcsolat a következővel: <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />, mert az eszköz dátum- és időbeállítása helytelen (<ph name="DATE_AND_TIME" />).</translation>
<translation id="8564182942834072828">Különálló dokumentumok/Nem szétválogatott másolatok</translation>
<translation id="8564985650692024650">A Chromium azt javasolja, hogy adjon meg új <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" />-jelszót a régi helyett, ha azt más webhelyeken is használta.</translation>
@@ -2354,6 +2404,7 @@ További részletek:
<translation id="865032292777205197">mozgásérzékelők</translation>
<translation id="8663226718884576429">Rendelés-összefoglaló, <ph name="TOTAL_LABEL" />, További részletek</translation>
<translation id="8666678546361132282">angol</translation>
+<translation id="8669306706049782872">A képernyőkön található információk használata ablakok megnyitásához és elhelyezéséhez</translation>
<translation id="867224526087042813">Aláírás</translation>
<translation id="8676424191133491403">Nincs késleltetés</translation>
<translation id="8680536109547170164"><ph name="QUERY" />. A válasz: <ph name="ANSWER" /></translation>
@@ -2380,6 +2431,7 @@ További részletek:
<translation id="8731544501227493793">Jelszavak kezelése gomb, nyomja meg az Enter billentyűt a jelszavaknak a Chrome beállításaiban való megtekintéséhez és kezeléséhez</translation>
<translation id="8734529307927223492"><ph name="DEVICE_TYPE" /> eszközét a(z) <ph name="MANAGER" /> kezeli</translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, nyomja le a Tab, majd az Enter billentyűt új inkognitó ablak megnyitásához, amelyben privát módon böngészhet</translation>
+<translation id="8737685506611670901"><ph name="PROTOCOL" /> linkek megnyitása a(z) <ph name="REPLACED_HANDLER_TITLE" /> helyett</translation>
<translation id="8738058698779197622">Biztonságos kapcsolat létrehozásához az órát pontosan be kell állítani. Ez azért szükséges, mert a webhelyek által az azonosításukra használt tanúsítványok csak adott ideig érvényesek. Mivel az eszköz órája nem pontos, a Chromium nem tudja ellenőrizni ezeket a tanúsítványokat.</translation>
<translation id="8740359287975076522">A(z) <ph name="HOST_NAME" /> &lt;abbr id="dnsDefinition"&gt;DNS-címe&lt;/abbr&gt; nem található. A probléma diagnosztizálása folyamatban van.</translation>
<translation id="8742371904523228557">A(z) <ph name="ORIGIN" /> webhelyhez tartozó kód a következő: <ph name="ONE_TIME_CODE" /></translation>
@@ -2407,6 +2459,7 @@ További részletek:
<translation id="883848425547221593">Egyéb könyvjelzők</translation>
<translation id="884264119367021077">Szállítási cím</translation>
<translation id="884923133447025588">Nem található visszavonási mechanizmus.</translation>
+<translation id="8849262850971482943">Használja virtuális kártyáját a plusz biztonság érdekében</translation>
<translation id="885730110891505394">Megosztás a Google-lal</translation>
<translation id="8858065207712248076">A Chrome azt javasolja, hogy adjon meg új <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" />-jelszót a régi helyett, ha azt más webhelyeken is használta.</translation>
<translation id="885906927438988819">Ha helyesen írta, <ph name="BEGIN_LINK" />próbálkozzon a Windows hálózati diagnosztikájának futtatásával<ph name="END_LINK" />.</translation>
@@ -2456,6 +2509,7 @@ További részletek:
<translation id="9004367719664099443">VR-munkamenet folyamatban</translation>
<translation id="9005998258318286617">A PDF-dokumentum betöltése sikertelen.</translation>
<translation id="9008201768610948239">Mellőzés</translation>
+<translation id="901834265349196618">e-mail</translation>
<translation id="9020200922353704812">A hitelkártyához tartozó számlázási cím megadása kötelező</translation>
<translation id="9020542370529661692">Az oldalt lefordítottuk <ph name="TARGET_LANGUAGE" /> nyelvre.</translation>
<translation id="9020742383383852663">A8</translation>
@@ -2504,6 +2558,7 @@ További részletek:
<translation id="9150045010208374699">Kamera használata</translation>
<translation id="9150685862434908345">A rendszergazda távolról módosítani tudja a böngészőbeállításokat. Az is lehetséges, hogy az eszközön végzett tevékenységeket a Chrome-on kívülről felügyelik. <ph name="BEGIN_LINK" />További információ<ph name="END_LINK" />.</translation>
<translation id="9154194610265714752">Frissítve</translation>
+<translation id="9155211586651734179">Csatlakoztatott hangperifériák</translation>
<translation id="9157595877708044936">Előkészítés...</translation>
<translation id="9158625974267017556">C6 (boríték)</translation>
<translation id="9164029392738894042">Pontosság ellenőrzése</translation>
diff --git a/chromium/components/strings/components_strings_hy.xtb b/chromium/components/strings/components_strings_hy.xtb
index 9583f7890fa..fec6169c944 100644
--- a/chromium/components/strings/components_strings_hy.xtb
+++ b/chromium/components/strings/components_strings_hy.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">Ô´Õ«Õ¿Õ¥Õ¬ Õ´Õ¡Õ¶Ö€Õ¡Õ´Õ¡Õ½Õ¶Õ¥Ö€Õ¨</translation>
<translation id="1030706264415084469"><ph name="URL" /> Õ¯Õ¡ÕµÖ„Õ¶ Õ¸Ö‚Õ¦Õ¸Ö‚Õ´ Õ§ Õ±Õ¥Ö€ Õ½Õ¡Ö€Ö„Õ¸Ö‚Õ´ Õ´Õ¥Õ® Õ®Õ¡Õ¾Õ¡Õ¬Õ¸Õ¾ Õ¿Õ¾ÕµÕ¡Õ¬Õ¶Õ¥Ö€ Õ´Õ·Õ¿Õ¡ÕºÕ¥Õ½ ÕºÕ¡Õ°Õ¥Õ¬</translation>
<translation id="1032854598605920125">ÕŠÕ¿Õ¿Õ¥Õ¬ ÕªÕ¡Õ´Õ¡ÖÕ¸Ö‚ÕµÖÕ« Õ½Õ¬Õ¡Ö„Õ« Õ¸Ö‚Õ²Õ²Õ¸Ö‚Õ©ÕµÕ¡Õ´Õ¢</translation>
+<translation id="1033329911862281889">Ô»Õ¶Õ¯Õ¸Õ£Õ¶Õ«Õ¿Õ¸ Õ¼Õ¥ÕªÕ«Õ´Õ¨ Õ¹Õ« Õ¯Õ¡Ö€Õ¸Õ² Õ±Õ¥Õ¦ Õ¬Õ«Õ¸Õ¾Õ«Õ¶ Õ¡Õ¶Õ¿Õ¥Õ½Õ¡Õ¶Õ¥Õ¬Õ« Õ¤Õ¡Ö€Õ±Õ¶Õ¥Õ¬ Õ°Õ¡Õ´Õ¡ÖÕ¡Õ¶ÖÕ¸Ö‚Õ´, Õ´Õ¡Õ½Õ¶Õ¡Õ¾Õ¸Ö€Õ¡ÕºÕ¥Õ½Õ
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Õ¡ÕµÖÕ¥Õ¬Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¨ Õ¯Õ¡Ö€Õ¸Õ² Õ¥Õ¶ Õ¿Õ¥Õ½Õ¡Õ¶Õ¥Õ¬Õ« Õ¬Õ«Õ¶Õ¥Õ¬ Õ¯Õ¡ÕµÖ„Õ¥Ö€Õ«Õ¶ Ö‡ Õ¤Ö€Õ¡Õ¶Ö Õ¯Õ¸Õ²Õ´Õ«Ö Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¾Õ¸Õ² Õ®Õ¡Õ¼Õ¡ÕµÕ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ«Õ¶,<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Õ£Õ¸Ö€Õ®Õ¡Õ¿Õ¸Ö‚Õ¶Õ¥Ö€Õ¨ Ö‡ Õ¸Ö‚Õ½Õ¸Ö‚Õ´Õ¶Õ¡Õ¯Õ¡Õ¶ Õ°Õ¡Õ½Õ¿Õ¡Õ¿Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¨ Õ¯Õ¡Ö€Õ¸Õ² Õ¥Õ¶ Õ°Õ¥Õ¿Õ¡Õ£Õ®Õ¥Õ¬ Õ£Õ¸Ö€Õ®Õ¸Õ²Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¨ Õ¤Õ«Õ¿Õ¡Ö€Õ¯Õ«Õ¹Õ¸Ö‚Õ´,<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Õ«Õ¶Õ¿Õ¥Ö€Õ¶Õ¥Õ¿ ÕºÖ€Õ¸Õ¾Õ¡ÕµÕ¤Õ¥Ö€Õ¶Õ¥Ö€Õ¨ Õ¯Õ¡Ö€Õ¸Õ² Õ¥Õ¶ Õ°Õ¥Õ¿Ö‡Õ¥Õ¬ Õ¾Õ¥Õ¢ Õ©Ö€Õ¡Ö†Õ«Õ¯Õ«Õ¶Ö‰<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">Ô±Õ¶Õ»Õ¡Õ¿Õ¥Õ¬</translation>
<translation id="1036982837258183574">Ô¼Õ«Õ¡Õ§Õ¯Ö€Õ¡Õ¶ Õ¼Õ¥ÕªÕ«Õ´Õ«Ö Õ¤Õ¸Ö‚Ö€Õ½ Õ£Õ¡Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€ Õ½Õ¥Õ²Õ´Õ¥Ö„ |<ph name="ACCELERATOR" />|</translation>
<translation id="1038106730571050514">Õ‘Õ¸Ö‚ÖÕ¡Õ¤Ö€Õ¥Õ¬ Õ¡Õ¼Õ¡Õ»Õ¡Ö€Õ¯Õ¶Õ¥Ö€Õ¨</translation>
<translation id="1038842779957582377">Õ¡Õ¶Õ°Õ¡ÕµÕ¿ Õ¡Õ¶Õ¸Ö‚Õ¶</translation>
<translation id="1041998700806130099">Õ€Õ¡Õ²Õ¸Ö€Õ¤Õ¡Õ£Ö€Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶ Õ¡Õ¼Õ¡Õ»Õ¡Õ¤Ö€Õ¡Õ¶Ö„Õ« Õ©Õ¥Ö€Õ©Õ« Õ¾Ö€Õ¡</translation>
<translation id="1048785276086539861">ÔµÖ€Õ¢ Õ¤Õ¸Ö‚Ö„ Õ­Õ´Õ¢Õ¡Õ£Ö€Õ¥Ö„ Õ®Õ¡Õ¶Õ¸Õ©Õ¡Õ£Ö€Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¨, ÖƒÕ¡Õ½Õ¿Õ¡Õ©Õ¸Ö‚Õ²Õ©Õ¨ Õ¯ÖÕ¸Ö‚ÖÕ¡Õ¤Ö€Õ¾Õ« Õ´Õ¥Õ¯ Õ§Õ»Õ¸Õ¾</translation>
-<translation id="1049743911850919806">Ô»Õ¶Õ¯Õ¸Õ£Õ¶Õ«Õ¿Õ¸</translation>
<translation id="1050038467049342496">Õ“Õ¡Õ¯Õ¥Ö„ Õ´ÕµÕ¸Ö‚Õ½ Õ°Õ¡Õ¾Õ¥Õ¬Õ¾Õ¡Õ®Õ¶Õ¥Ö€Õ¨</translation>
<translation id="1055184225775184556">&amp;Õ€Õ¥Õ¿Õ¡Ö€Õ¯Õ¥Õ¬ Õ°Õ¡Õ¾Õ¥Õ¬Õ¸Ö‚Õ´Õ¨</translation>
<translation id="1056898198331236512">Ô¶Õ£Õ¸Ö‚Õ·Õ¡ÖÕ¸Ö‚Õ´</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">Õ”Õ¡Õ²Õ¡Ö„Õ¡Õ¯Õ¡Õ¶Õ¸Ö‚Õ©ÕµÕ¡Õ¶ Ö„Õ¥Õ·Õ¸Ö‚Õ´ Õ½Õ­Õ¡Õ¬Õ¶Õ¥Ö€ Õ¹Õ¥Õ¶ Õ£Õ¿Õ¶Õ¾Õ¥Õ¬</translation>
<translation id="1130564665089811311">«Թարգմանել էջը» կոճակ։ Այս էջը Google Translate-ով թարգմանելու համար սեղմեք Enter։</translation>
<translation id="1131264053432022307">ÕÕ¥Ö€ ÕºÕ¡Õ¿Õ³Õ¥Õ¶Õ¡Õ® ÕºÕ¡Õ¿Õ¯Õ¥Ö€Õ¨</translation>
+<translation id="1142846828089312304">Ô±Ö€Õ£Õ¥Õ¬Õ¡ÖƒÕ¡Õ¯Õ¥Õ¬ Õ¯Õ¸Õ²Õ´Õ¶Õ¡Õ¯Õ« Õ¯Õ¡ÕµÖ„Õ¥Ö€Õ« Ö„Õ¸Ö‚Ö„Õ«Õ¶Õ¥Ö€Õ¨ Õ«Õ¶Õ¯Õ¸Õ£Õ¶Õ«Õ¿Õ¸ Õ¼Õ¥ÕªÕ«Õ´Õ¸Ö‚Õ´</translation>
<translation id="1150979032973867961">Ô±ÕµÕ½ Õ½Õ¥Ö€Õ¾Õ¥Ö€Õ¨ Õ¹Õ« Õ¯Õ¡Ö€Õ¸Õ² Õ¡ÕºÕ¡ÖÕ¸Ö‚ÖÕ¥Õ¬, Õ¸Ö€ <ph name="DOMAIN" /> Õ§: ÕÕ¥Ö€ Õ°Õ¡Õ´Õ¡Õ¯Õ¡Ö€Õ£Õ¹Õ« Ö…ÕºÕ¥Ö€Õ¡ÖÕ«Õ¸Õ¶ Õ°Õ¡Õ´Õ¡Õ¯Õ¡Ö€Õ£Õ¨ Õ¹Õ« Õ¾Õ½Õ¿Õ¡Õ°Õ¸Ö‚Õ´ Õ¤Ö€Õ¡ Õ¡Õ¶Õ¾Õ¿Õ¡Õ¶Õ£Õ¸Ö‚Õ©ÕµÕ¡Õ¶ Õ¾Õ¯Õ¡ÕµÕ¡Õ¯Õ¡Õ¶Õ«Õ¶: ÕŠÕ¡Õ¿Õ³Õ¡Õ¼Õ¨ Õ¯Õ¡Ö€Õ¸Õ² Õ§ Õ¬Õ«Õ¶Õ¥Õ¬ Õ½Õ­Õ¡Õ¬ Õ¯Õ¡Õ¦Õ´Õ¡Õ±Ö‡Õ¸Ö‚Õ´Õ¨ Õ¯Õ¡Õ´ Õ¯Õ¡ÕºÕ¡Õ¯ÖÕ´Õ¡Õ¶ Õ­Õ¡ÖƒÕ¡Õ¶Õ¸Ö‚Õ´Õ¨ Õ°Õ¡Ö€Õ±Õ¡Õ¯Õ¾Õ¸Õ²Õ« Õ¯Õ¸Õ²Õ´Õ«Ö:</translation>
<translation id="1151972924205500581">ÕŠÕ¡Õ°Õ¡Õ¶Õ»Õ¾Õ¸Ö‚Õ´ Õ§ Õ£Õ¡Õ²Õ¿Õ¶Õ¡Õ¢Õ¡Õ¼</translation>
<translation id="1156303062776767266">Ô´Õ¸Ö‚Ö„ Õ¿Õ¥Õ²Õ¡ÕµÕ«Õ¶ Õ¯Õ¡Õ´ Õ¨Õ¶Õ¤Õ°Õ¡Õ¶Õ¸Ö‚Ö€ Ö†Õ¡ÕµÕ¬ Õ¥Ö„ Õ¤Õ«Õ¿Õ¸Ö‚Õ´</translation>
@@ -64,7 +70,6 @@
<translation id="1178581264944972037">Ô´Õ¡Õ¤Õ¡Ö€</translation>
<translation id="1181037720776840403">Õ‹Õ¶Õ»Õ¥Õ¬</translation>
<translation id="1186201132766001848">ÕÕ¿Õ¸Ö‚Õ£Õ¥Õ¬ Õ£Õ¡Õ²Õ¿Õ¶Õ¡Õ¢Õ¡Õ¼Õ¥Ö€Õ¨</translation>
-<translation id="1195210374336998651">Ô±Õ¶ÖÕ¶Õ¥Õ¬ Õ°Õ¡Õ¾Õ¥Õ¬Õ¾Õ¡Õ®Õ« Õ¯Õ¡Ö€Õ£Õ¡Õ¾Õ¸Ö€Õ¸Ö‚Õ´Õ¶Õ¥Ö€</translation>
<translation id="1195558154361252544">Ô²Õ¡ÖÕ« Õ±Õ¥Ö€ Õ¶Õ·Õ¡Õ® Õ¯Õ¡ÕµÖ„Õ¥Ö€Õ«ÖÕ Õ´Õ¶Õ¡ÖÕ¡Õ® Õ¢Õ¸Õ¬Õ¸Ö€ Õ¯Õ¡ÕµÖ„Õ¥Ö€Õ« Õ°Õ¡Õ´Õ¡Ö€ Õ®Õ¡Õ¶Õ¸Ö‚ÖÕ¸Ö‚Õ´Õ¶Õ¥Ö€Õ¶ Õ¡Õ¾Õ¿Õ¸Õ´Õ¡Õ¿ Õ¡Ö€Õ£Õ¥Õ¬Õ¡ÖƒÕ¡Õ¯Õ¾Õ¸Ö‚Õ´ Õ¥Õ¶:</translation>
<translation id="1197088940767939838">Õ†Õ¡Ö€Õ¶Õ»Õ¡Õ£Õ¸Ö‚ÕµÕ¶</translation>
<translation id="1201402288615127009">Õ€Õ¡Õ»Õ¸Ö€Õ¤Õ¨</translation>
@@ -111,7 +116,7 @@
<translation id="1307966114820526988">Õ€Õ¶Õ¡ÖÕ¡Õ® Õ£Õ¸Ö€Õ®Õ¡Õ¼Õ¸Ö‚ÕµÕ©Õ¶Õ¥Ö€</translation>
<translation id="1308113895091915999">Ô±Õ¼Õ¯Õ¡ Õ¡Õ¼Õ¡Õ»Õ¡Ö€Õ¯</translation>
<translation id="1312803275555673949">Ô»Õ¶Õ¹Õ¸ÕžÕ¾ Õ§ Õ¤Õ¡ Õ°Õ¡Õ½Õ¿Õ¡Õ¿Õ¾Õ¸Ö‚Õ´</translation>
-<translation id="131405271941274527"><ph name="URL" /> Õ¯Õ¡ÕµÖ„Õ¨ Õ©Õ¸Ö‚ÕµÕ¬Õ¿Õ¾Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶ Õ§ Õ­Õ¶Õ¤Ö€Õ¸Ö‚Õ´Õ NFC-Õ« Õ´Õ«Õ»Õ¸ÖÕ¸Õ¾ Õ¿Õ¾ÕµÕ¡Õ¬Õ¶Õ¥Ö€ ÖƒÕ¸Õ­Õ¡Õ¶Õ¡Õ¯Õ¥Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€Ö‰</translation>
+<translation id="1314311879718644478">Ô´Õ«Õ¿Õ¥Õ¬ Õ¢Õ¸Õ¾Õ¡Õ¶Õ¤Õ¡Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¨ Õ¬Ö€Õ¡ÖÕ¾Õ¡Õ® Õ«Ö€Õ¡Õ¯Õ¡Õ¶Õ¸Ö‚Õ©ÕµÕ¡Õ¶ Õ¼Õ¥ÕªÕ«Õ´Õ¸Ö‚Õ´</translation>
<translation id="1314509827145471431">Ô±Õ´Ö€Õ¡Õ¯Õ¡Ö€ Õ¡Õ» Õ¯Õ¸Õ²Õ´Õ¸Ö‚Õ´</translation>
<translation id="1318023360584041678">ÕŠÕ¡Õ°Õ¾Õ¥Õ¬ Õ§ Õ¶Õ¥Ö€Õ¤Õ«Ö€Õ¶Õ¥Ö€Õ« Õ­Õ´Õ¢Õ¸Ö‚Õ´</translation>
<translation id="1319245136674974084">Ô±ÕµÕ¬Ö‡Õ½ Õ¹Õ°Õ¡Ö€ÖÕ¶Õ¥Õ¬ Õ¡ÕµÕ½ Õ°Õ¡Õ¾Õ¥Õ¬Õ¾Õ¡Õ®Õ« Õ°Õ¡Õ´Õ¡Ö€</translation>
@@ -161,6 +166,7 @@
<translation id="142858679511221695">Ô±Õ´ÕºÕ« Ö…Õ£Õ¿Õ¡Õ¿Õ¥Ö€</translation>
<translation id="1428729058023778569">Ô´Õ¸Ö‚Ö„ Õ¿Õ¥Õ½Õ¶Õ¸Ö‚Õ´ Õ¥Ö„ Õ¡ÕµÕ½ Õ¶Õ¡Õ­Õ¡Õ¦Õ£Õ¸Ö‚Õ·Õ¡ÖÕ¸Ö‚Õ´Õ¨, Ö„Õ¡Õ¶Õ« Õ¸Ö€ Õ¯Õ¡ÕµÖ„Õ¨ Õ¹Õ« Õ¡Õ»Õ¡Õ¯ÖÕ¸Ö‚Õ´ HTTPS-Õ¨Ö‰ <ph name="BEGIN_LEARN_MORE_LINK" />Ô»Õ´Õ¡Õ¶Õ¡Õ¬ Õ¡Õ¾Õ¥Õ¬Õ«Õ¶<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">ÕÕºÕ¸Ö‚Õ´</translation>
+<translation id="1432187715652018471">Ô·Õ»Õ¨ Õ®Õ¡Õ¼Õ¡ÕµÕ¸Ö‚Õ©ÕµÕ¡Õ¶ Õ´Õ·Õ¡Õ¯Õ«Õ¹ Õ§ Õ¸Ö‚Õ¦Õ¸Ö‚Õ´ Õ¿Õ¥Õ²Õ¡Õ¤Ö€Õ¥Õ¬Ö‰</translation>
<translation id="1432581352905426595">Ô¿Õ¡Õ¼Õ¡Õ¾Õ¡Ö€Õ¥Õ¬ Õ¸Ö€Õ¸Õ¶Õ´Õ¡Õ¶ Õ°Õ¡Õ´Õ¡Õ¯Õ¡Ö€Õ£Õ¥Ö€Õ¨</translation>
<translation id="1436185428532214179">Ô¿Õ¡Ö€Õ¸Õ² Õ§ Õ°Õ¡ÕµÖÕ¥Õ¬ Õ±Õ¥Ö€ Õ½Õ¡Ö€Ö„Õ« Ö†Õ¡ÕµÕ¬Õ¥Ö€Õ¶ Õ¸Ö‚ ÕºÕ¡Õ¶Õ¡Õ¯Õ¶Õ¥Ö€Õ¨ ÖƒÕ¸ÖƒÕ¸Õ­Õ¥Õ¬Õ¸Ö‚ Õ©Õ¸Ö‚ÕµÕ¬Õ¿Õ¾Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶</translation>
<translation id="1442386063175183758">Ô±Õ» Ö„Õ¡Õ¼Õ¸Ö€Õ¤Õ« Õ®Õ¡Õ¬Õ¸Ö‚Õ´</translation>
@@ -181,6 +187,12 @@
<translation id="1483493594462132177">ÕˆÖ‚Õ²Õ¡Ö€Õ¯Õ¥Õ¬</translation>
<translation id="1484290072879560759">Ô¸Õ¶Õ¿Ö€Õ¥Ö„ Õ¡Õ¼Õ¡Ö„Õ´Õ¡Õ¶ Õ°Õ¡Õ½ÖÕ¥Õ¶</translation>
<translation id="1492194039220927094">Ô¿Õ¡Õ¶Õ¸Õ¶Õ¶Õ¥Ö€Õ« Õ´Õ²Õ¸Ö‚Õ´Õ</translation>
+<translation id="149293076951187737">ÔµÖ€Õ¢ ÖƒÕ¡Õ¯Õ¥Ö„ Chrome-Õ« Õ¢Õ¸Õ¬Õ¸Ö€ Õ«Õ¶Õ¯Õ¸Õ£Õ¶Õ«Õ¿Õ¸ Õ¶Õ¥Ö€Õ¤Õ«Ö€Õ¶Õ¥Ö€Õ¨, Õ¡ÕµÕ½ Õ½Õ¡Ö€Ö„Õ«Ö Õ¯Õ°Õ¥Õ¼Õ¡ÖÕ¾Õ¥Õ¶ Õ¡ÕµÕ¤ Õ¶Õ¥Ö€Õ¤Õ«Ö€Õ¶Õ¥Ö€Õ¸Ö‚Õ´ Õ±Õ¥Ö€ Õ¯Õ¡Õ¿Õ¡Ö€Õ¡Õ® Õ£Õ¸Ö€Õ®Õ¸Õ²Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¨, Õ¡ÕµÕ¤ Õ©Õ¾Õ¸Ö‚Õ´Õ
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Õ£Õ¸Ö€Õ®Õ¸Õ²Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¨ Õ¤Õ«Õ¿Õ¡Ö€Õ¯Õ«Õ¹Õ¸Ö‚Õ´,<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Õ¸Ö€Õ¸Õ¶Õ¸Ö‚Õ´Õ¶Õ¥Ö€Õ« ÕºÕ¡Õ¿Õ´Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¨,<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Õ±Ö‡Õ¥Ö€Õ¸Ö‚Õ´ Õ¬Ö€Õ¡ÖÕ¾Õ¡Õ® Õ¿Õ¥Õ²Õ¥Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¨Ö‰<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">ÕŽÕ¥Ö€Õ¡Õ¤Õ¡Õ¼Õ¶Õ¡Õ¬ Õ¶Õ¥Ö€Õ¤Õ«Ö€</translation>
<translation id="1501859676467574491">Õ‘Õ¸Ö‚ÖÕ¡Õ¤Ö€Õ¥Ö„ Ö„Õ¡Ö€Õ¿Õ¥Ö€ Õ±Õ¥Ö€ Google Õ°Õ¡Õ·Õ¾Õ«Ö</translation>
<translation id="1507202001669085618">&lt;p&gt;Ô±ÕµÕ½ Õ½Õ­Õ¡Õ¬Õ¨ Õ¯ÖÕ¸Ö‚ÖÕ¡Õ¤Ö€Õ¾Õ«, Õ¥Õ©Õ¥ Õ¤Õ¸Ö‚Ö„ Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¸Ö‚Õ´ Õ¥Ö„ Wi-Fi ÕºÕ¸Ö€Õ¿Õ¡Õ¬, Õ¸Ö€Õ¿Õ¥Õ² ÖÕ¡Õ¶ÖÕ«Õ¶ Õ´Õ«Õ¡Õ¶Õ¡Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€ Õ¡Õ¶Õ°Ö€Õ¡ÕªÕ¥Õ·Õ¿ Õ§ Õ´Õ¿Õ¶Õ¥Õ¬ Õ°Õ¡Õ·Õ«Õ¾Ö‰&lt;/p&gt;
@@ -208,6 +220,8 @@
<translation id="1559572115229829303">&lt;p&gt;Õ‰Õ°Õ¡Õ»Õ¸Õ²Õ¾Õ¥Ö Õ´Õ¡Õ½Õ¶Õ¡Õ¾Õ¸Ö€ Õ¯Õ¡ÕºÕ¡Õ¯ÖÕ¸Ö‚Õ´ Õ°Õ¡Õ½Õ¿Õ¡Õ¿Õ¥Õ¬ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> Õ¿Õ«Ö€Õ¸Ö‚ÕµÕ©Õ« Õ°Õ¥Õ¿, Ö„Õ¡Õ¶Õ« Õ¸Ö€ Õ±Õ¥Ö€ Õ½Õ¡Ö€Ö„Õ« Õ¡Õ´Õ½Õ¡Õ©Õ«Õ¾Õ¨ Ö‡ ÕªÕ¡Õ´Õ¨ (<ph name="DATE_AND_TIME" />) Õ½Õ­Õ¡Õ¬ Õ¥Õ¶:&lt;/p&gt;
&lt;p&gt;ÕˆÖ‚Õ²Õ²Õ¥Ö„ Õ¡Õ´Õ½Õ¡Õ©Õ«Õ¾Õ¨ Ö‡ ÕªÕ¡Õ´Õ¨ &lt;strong&gt;Ô¿Õ¡Ö€Õ£Õ¡Õ¾Õ¸Ö€Õ¸Ö‚Õ´Õ¶Õ¥Ö€&lt;/strong&gt; Õ°Õ¡Õ¾Õ¥Õ¬Õ¾Õ¡Õ®Õ« &lt;strong&gt;Ô¸Õ¶Õ¤Õ°Õ¡Õ¶Õ¸Ö‚Ö€&lt;/strong&gt; Õ¢Õ¡ÕªÕ¶Õ¸Ö‚Õ´:&lt;/p&gt;</translation>
+<translation id="1559839503761818503">ÕÕ¥Ö€ Õ¡Õ¤Õ´Õ«Õ¶Õ«Õ½Õ¿Ö€Õ¡Õ¿Õ¸Ö€Õ¨ Õ¯Õ¾Õ¥Ö€Õ¡Õ£Õ¸Ö€Õ®Õ¡Ö€Õ¯Õ« Õ½Õ¡Ö€Ö„Õ¨ <ph name="DATE" />, <ph name="TIME" /></translation>
+<translation id="156703335097561114">Õ‘Õ¡Õ¶ÖÕ¡ÕµÕ«Õ¶ Õ¿Õ¥Õ²Õ¥Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¨, Ö…Ö€Õ«Õ¶Õ¡Õ¯Õ Õ°Õ¡Õ½ÖÕ¥Õ¶Õ¥Ö€Õ¨, Õ´Õ«Õ»Õ¥Ö€Õ¥Õ½Õ« Õ¯Õ¡Ö€Õ£Õ¡Õ¾Õ¸Ö€Õ¸Ö‚Õ´Õ¶Õ¥Ö€Õ¨ Ö‡ Õ¯Õ¡ÕºÕ« Õ¸Ö€Õ¡Õ¯Õ¨</translation>
<translation id="1567040042588613346">Ô±ÕµÕ½ Õ¯Õ¡Õ¶Õ¸Õ¶Õ¨ ÕºÕ¡Õ¿Õ·Õ¡Õ³ Õ¯Õ¥Ö€ÕºÕ¸Õ¾ Õ¡Õ·Õ­Õ¡Õ¿Õ¸Ö‚Õ´ Õ§, Õ½Õ¡Õ¯Õ¡ÕµÕ¶ Õ´Õ«Ö‡Õ¶Õ¸Ö‚ÕµÕ¶ Õ¡Ö€ÕªÕ¥Ö„Õ¨ Õ½Õ¡Õ°Õ´Õ¡Õ¶Õ¾Õ¡Õ® Õ§ Õ¡ÕµÕ¬ Õ¿Õ¥Õ²Õ¸Ö‚Õ´ Ö‡ ÖƒÕ¸Õ­Õ¡Ö€Õ«Õ¶Õ¾Õ¸Ö‚Õ´ Õ§ Õ¯Õ¡Õ¶Õ¸Õ¶Õ« Õ¯Õ¸Õ²Õ´Õ«ÖÖ‰</translation>
<translation id="1569487616857761740">Õ„Õ¸Ö‚Õ¿Ö„Õ¡Õ£Ö€Õ¥Ö„ Õ£Õ¸Ö€Õ®Õ¸Õ²Õ¸Ö‚Õ©ÕµÕ¡Õ¶ ÕªÕ¡Õ´Õ¯Õ¥Õ¿Õ¨</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@
<translation id="1583429793053364125">Õ‰Õ°Õ¡Õ»Õ¸Õ²Õ¾Õ¥Ö Õ¢Õ¡ÖÕ¥Õ¬ Õ¾Õ¥Õ¢Õ§Õ»Õ¨:</translation>
<translation id="1586541204584340881">Ô»Õ¶Õ¹ Õ¨Õ¶Õ¤Õ¬Õ¡ÕµÕ¶Õ¸Ö‚Õ´Õ¶Õ¥Ö€ Õ¥Ö„ Õ¤Õ¸Ö‚Ö„ Õ¿Õ¥Õ²Õ¡Õ¤Ö€Õ¥Õ¬</translation>
<translation id="1588438908519853928">ÕÕ¸Õ¾Õ¸Ö€Õ¡Õ¯Õ¡Õ¶</translation>
+<translation id="1589050138437146318">ÕÕ¥Õ²Õ¡Õ¤Ö€Õ¥ÕžÕ¬ ARCore-Õ¨</translation>
<translation id="1592005682883173041">ÕÕ¥Õ²Õ¡ÕµÕ«Õ¶ Õ¿Õ¾ÕµÕ¡Õ¬Õ¶Õ¥Ö€Õ« Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¸Ö‚Õ´</translation>
<translation id="1594030484168838125">Ô¸Õ¶Õ¿Ö€Õ¥Õ¬</translation>
<translation id="160851722280695521">Ô½Õ¡Õ²Õ¡Õ¬ Dino Run Õ­Õ¡Õ²Õ¨ Chrome-Õ¸Ö‚Õ´</translation>
@@ -254,7 +269,7 @@
<translation id="1711234383449478798">Ô±Õ¶Õ¿Õ¥Õ½Õ¾Õ¡Õ® Õ§, Ö„Õ¡Õ¶Õ« Õ¸Ö€ <ph name="POLICY_NAME" /> Õ¯Õ¡Õ¶Õ¸Õ¶Õ« Õ°Õ¡Õ´Õ¡Ö€ Õ½Õ¡Õ°Õ´Õ¡Õ¶Õ¾Õ¡Õ® Õ¹Õ§ <ph name="VALUE" /> Õ¡Ö€ÕªÕ¥Ö„Õ¨Ö‰</translation>
<translation id="1712552549805331520"><ph name="URL" /> Õ¯Õ¡ÕµÖ„Õ¶ Õ¸Ö‚Õ¦Õ¸Ö‚Õ´ Õ§ Õ±Õ¥Ö€ Õ°Õ¡Õ´Õ¡Õ¯Õ¡Ö€Õ£Õ¹Õ¸Ö‚Õ´ Õ¿Õ¾ÕµÕ¡Õ¬Õ¶Õ¥Ö€ Õ´Õ·Õ¿Õ¡ÕºÕ¥Õ½ ÕºÕ¡Õ°Õ¥Õ¬</translation>
<translation id="1713628304598226412">Ô´Õ¡Ö€Õ¡Õ¯ 2</translation>
-<translation id="1715874602234207">F</translation>
+<translation id="1715874602234207">ÕˆÖ‚</translation>
<translation id="1717218214683051432">Õ‡Õ¡Ö€ÕªÕ´Õ¡Õ¶ Õ¿Õ¾Õ«Õ¹Õ¶Õ¥Ö€</translation>
<translation id="1717494416764505390">Õ“Õ¸Õ½Õ¿Õ¡Ö€Õ¯Õ² 3</translation>
<translation id="1718029547804390981">Õ€Õ¶Õ¡Ö€Õ¡Õ¾Õ¸Ö€ Õ¹Õ§ Õ®Õ¡Õ¶Õ¸Õ©Õ¡Õ£Ö€Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶ Õ¡Õ¾Õ¥Õ¬Õ¡ÖÕ¶Õ¥Õ¬, Ö„Õ¡Õ¶Õ« Õ¸Ö€ ÖƒÕ¡Õ½Õ¿Õ¡Õ©Õ¸Ö‚Õ²Õ©Õ¨ Õ¹Õ¡ÖƒÕ¡Õ¦Õ¡Õ¶Ö Õ´Õ¥Õ® Õ§Ö‰</translation>
@@ -283,6 +298,7 @@
Õ¾Õ¥Ö€Õ¶Õ¡Õ£Ö€Õ« Õ¯Õ¡Õ¦Õ´Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¨ Õ½Õ­Õ¡Õ¬ Õ§, Õ«Õ¶Õ¹Õ¨ Õ©Õ¸Ö‚ÕµÕ¬ Õ¹Õ« Õ¿Õ¡Õ¬Õ«Õ½ Õ¤Õ«Õ¿Õ¡Ö€Õ¯Õ«Õ¹Õ«Õ¶ Õ¯Õ¡Õ¿Õ¡Ö€Õ¥Õ¬
<ph name="SITE" /> Õ¯Õ¡ÕµÖ„Õ« Õ±Õ¥Ö€ Õ°Õ¡Ö€ÖÕ¸Ö‚Õ´Õ¨Ö‰ ÕÕ¯Õ¦Õ¢Õ¶Õ¡Õ¯Õ¡Õ¶ Õ¯Õ¡Õ¶Õ¸Õ¶Õ¶Õ¥Ö€Õ¨ Õ¯Õ¡Ö€Õ¸Õ² Õ¥Õ¶ Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¾Õ¥Õ¬
Õ¯Õ¡ÕµÖ„Õ¥Ö€Õ« Ö…ÕºÕ¥Ö€Õ¡Õ¿Õ¸Ö€Õ¶Õ¥Ö€Õ« Õ¯Õ¸Õ²Õ´Õ«Ö Õ¯Õ¡ÕµÖ„Õ« Õ¿Õ¡Ö€Õ¡Õ¿Õ¥Õ½Õ¡Õ¯ ÕºÕ¡Ö€Õ¡Õ´Õ¥Õ¿Ö€Õ¥Ö€Õ« Ö‡ Õ¡Õ¶Õ¾Õ¿Õ¡Õ¶Õ£Õ¸Ö‚Õ©ÕµÕ¡Õ¶ Õ¯Õ¡Ö€Õ£Õ¡Õ¾Õ¸Ö€Õ¸Ö‚Õ´Õ¶Õ¥Ö€Õ« Õ°Õ¡Õ´Õ¡Ö€Ö‰</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Ô»Õ´Õ¡Õ¶Õ¡Õ¬ Õ¡Õ¾Õ¥Õ¬Õ«Õ¶ Chromium-Õ« Õ«Õ¶Õ¯Õ¸Õ£Õ¶Õ«Õ¿Õ¸ Õ¼Õ¥ÕªÕ«Õ´Õ« Õ´Õ¡Õ½Õ«Õ¶<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">ÕÕ¥Ö€ Õ¢Õ¡ÖÕ¾Õ¡Õ® Õ¶Õ¥Ö€Õ¤Õ«Ö€Õ¶Õ¥Ö€Õ¨ Õ¯ÖÕ¸Ö‚ÖÕ¡Õ¤Ö€Õ¾Õ¥Õ¶ Õ¡ÕµÕ½Õ¿Õ¥Õ²</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -410,6 +426,7 @@
<translation id="22081806969704220">Ô´Õ¡Ö€Õ¡Õ¯ 3</translation>
<translation id="2212735316055980242">Ô¿Õ¡Õ¶Õ¸Õ¶Õ¨ Õ¹Õ£Õ¿Õ¶Õ¾Õ¥Ö</translation>
<translation id="2213606439339815911">Գրառումները քաշվում են…</translation>
+<translation id="2213612003795704869">Ô·Õ»Õ¨ Õ¿ÕºÕ¾Õ¡Õ® Õ§</translation>
<translation id="2215727959747642672">Õ–Õ¡ÕµÕ¬Õ« ÖƒÕ¸ÖƒÕ¸Õ­Õ¸Ö‚Õ´</translation>
<translation id="2218879909401188352">Õ€Õ¡Ö€Õ±Õ¡Õ¯Õ¾Õ¸Õ²Õ¶Õ¥Ö€Õ¨, Õ¸Ö€Õ¸Õ¶Ö„ Õ¶Õ¥Ö€Õ¯Õ¡ÕµÕ¸Ö‚Õ´Õ½ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> Õ¯Õ¡ÕµÖ„Õ¸Ö‚Õ´ Õ¥Õ¶, Õ¯Õ¡Ö€Õ¸Õ² Õ¥Õ¶ Õ¿Õ¥Õ²Õ¡Õ¤Ö€Õ¥Õ¬ Õ±Õ¥Ö€ Õ½Õ¡Ö€Ö„Õ¨ Õ¾Õ¶Õ¡Õ½Õ¸Õ² Õ°Õ¡Õ¾Õ¥Õ¬Õ¾Õ¡Õ®Õ¶Õ¥Ö€, Õ¡Õ¾Õ¥Õ¬Õ¡ÖÕ¶Õ¥Õ¬ Õ¢Õ»Õ»Õ¡ÕµÕ«Õ¶ Õ¯Õ¡ÕºÕ« Õ®Õ¡Õ­Õ½Õ¥Ö€Õ¨ Õ¯Õ¡Õ´ Õ°Õ¡ÖƒÕ·Õ¿Õ¡Õ¯Õ¥Õ¬ Õ±Õ¥Ö€ Õ¡Õ¶Õ±Õ¶Õ¡Õ¯Õ¡Õ¶ Õ¿Õ¾ÕµÕ¡Õ¬Õ¶Õ¥Ö€Õ¨Ö‰ <ph name="BEGIN_LEARN_MORE_LINK" />Ô»Õ´Õ¡Õ¶Õ¡Õ¬ Õ¡Õ¾Õ¥Õ¬Õ«Õ¶<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">Ô»Õ¶Õ¿Õ¥Ö€Õ¶Õ¥Õ¿ Õ¯Õ¡Õº Õ¹Õ¯Õ¡</translation>
@@ -419,6 +436,7 @@
<translation id="2248949050832152960">Õ•Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¥Õ¬ WebAuthn</translation>
<translation id="2250931979407627383">ÕÕ¡Õ­ Õ¥Õ¦Ö€Õ¡Õ¯Õ¡Ö€</translation>
<translation id="225207911366869382">Ô±ÕµÕ½ Õ¡Ö€ÕªÕ¥Ö„Õ¨ Õ¿Õ¾ÕµÕ¡Õ¬ Õ¯Õ¡Õ¶Õ¸Õ¶Õ« Õ°Õ¡Õ´Õ¡Ö€ Õ¡ÕµÕ¬Ö‡Õ½ Õ¹Õ« Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¾Õ¸Ö‚Õ´:</translation>
+<translation id="2256115617011615191">ÕŽÕ¥Ö€Õ¡Õ£Õ¸Ö€Õ®Õ¡Ö€Õ¯Õ¥Õ¬ Õ°Õ«Õ´Õ¡</translation>
<translation id="2258928405015593961">Õ„Õ¸Ö‚Õ¿Ö„Õ¡Õ£Ö€Õ¥Ö„ Õ¾Õ¡Õ¾Õ¥Ö€Õ¡Õ¯Õ¡Õ¶Õ¸Ö‚Õ©ÕµÕ¡Õ¶ ÕªÕ¡Õ´Õ¯Õ¥Õ¿Õ¨ (Õ¡ÕµÕ¶ ÕºÕ¥Õ¿Ö„ Õ§ Õ¬Õ«Õ¶Õ« Õ¡ÕºÕ¡Õ£Õ¡ÕµÕ¸Ö‚Õ´) Ö‡ Õ¶Õ¸Ö€Õ«Ö ÖƒÕ¸Ö€Õ±Õ¥Ö„</translation>
<translation id="225943865679747347">ÕÕ­Õ¡Õ¬Õ« Õ¯Õ¸Õ¤` <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">HTTP-Õ« Õ½Õ­Õ¡Õ¬</translation>
@@ -446,6 +464,7 @@
<translation id="2337852623177822836">Ô¿Õ¡Ö€Õ£Õ¡Õ¾Õ¸Ö€Õ¸Ö‚Õ´Õ¨ Õ¾Õ¥Ö€Õ¡Õ°Õ½Õ¯Õ¾Õ¸Ö‚Õ´ Õ§ Õ±Õ¥Ö€ Õ¡Õ¤Õ´Õ«Õ¶Õ«Õ½Õ¿Ö€Õ¡Õ¿Õ¸Ö€Õ« Õ¯Õ¸Õ²Õ´Õ«Ö</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> Õ¯Õ¡ÕµÖ„Õ¶ Õ¸Ö‚Õ¦Õ¸Ö‚Õ´ Õ§ Õ¦Õ¸Ö‚Õ£Õ¡Õ¯ÖÕ¾Õ¥Õ¬</translation>
<translation id="2346319942568447007">ÕÕ¥Ö€ ÕºÕ¡Õ¿Õ³Õ¥Õ¶Õ¡Õ® ÕºÕ¡Õ¿Õ¯Õ¥Ö€Õ¨</translation>
+<translation id="2350796302381711542">Ô¹Õ¸Ö‚ÕµÕ¬Õ¡Õ¿Ö€Õ¥ÕžÕ¬ <ph name="HANDLER_HOSTNAME" />-Õ«Õ¶ Õ¢Õ¡ÖÕ¥Õ¬ <ph name="PROTOCOL" /> Õ°Õ¡Õ²Õ¸Ö€Õ¤Õ¡Õ¯Õ¡Ö€Õ£Õ« Õ¢Õ¸Õ¬Õ¸Ö€ Õ°Õ²Õ¸Ö‚Õ´Õ¶Õ¥Ö€Õ¨ <ph name="REPLACED_HANDLER_TITLE" />-Õ« ÖƒÕ¸Õ­Õ¡Ö€Õ¥Õ¶:</translation>
<translation id="2354001756790975382">Ô±ÕµÕ¬ Õ§Õ»Õ¡Õ¶Õ«Õ·Õ¶Õ¥Ö€</translation>
<translation id="2354430244986887761">Google Ô±ÕºÕ¡Õ°Õ¸Õ¾ Õ¤Õ«Õ¿Õ¡Ö€Õ¯Õ¸Ö‚Õ´Õ¨ Õ¾Õ¥Ö€Õ»Õ¥Ö€Õ½ <ph name="BEGIN_LINK" />Õ¾Õ¶Õ¡Õ½Õ¡Ö€Õ¡Ö€ Õ°Õ¡Õ¾Õ¥Õ¬Õ¾Õ¡Õ®Õ¶Õ¥Ö€ Õ§ Õ°Õ¡ÕµÕ¿Õ¶Õ¡Õ¢Õ¥Ö€Õ¥Õ¬<ph name="END_LINK" /> <ph name="SITE" /> Õ¯Õ¡ÕµÖ„Õ¸Ö‚Õ´:</translation>
<translation id="2355395290879513365">Õ€Õ¡Ö€Õ±Õ¡Õ¯Õ¾Õ¸Õ²Õ¶Õ¥Ö€Õ¨ Õ¯Õ¡Ö€Õ¸Õ² Õ¥Õ¶ Õ¿Õ¥Õ½Õ¶Õ¥Õ¬ ÕºÕ¡Õ¿Õ¯Õ¥Ö€Õ¶Õ¥Ö€Õ¨, Õ¸Ö€Õ¸Õ¶Ö„ Õ¤Õ«Õ¿Õ¸Ö‚Õ´ Õ¥Ö„, Ö‡ Õ­Õ¡Õ¢Õ¥Õ¬ Õ±Õ¥Õ¦` Õ¤Ö€Õ¡Õ¶Ö„ Õ±Ö‡Õ¡ÖƒÕ¸Õ­Õ¥Õ¬Õ¸Õ¾:</translation>
@@ -471,6 +490,7 @@
<translation id="2413528052993050574">Ô±ÕµÕ½ Õ½Õ¥Ö€Õ¾Õ¥Ö€Õ¨ Õ¹Õ« Õ¯Õ¡Ö€Õ¸Õ² Õ¡ÕºÕ¡ÖÕ¸Ö‚ÖÕ¥Õ¬, Õ¸Ö€ <ph name="DOMAIN" /> Õ§: Ô´Ö€Õ¡ Õ¡Õ¶Õ¾Õ¿Õ¡Õ¶Õ£Õ¸Ö‚Õ©ÕµÕ¡Õ¶ Õ¾Õ¯Õ¡ÕµÕ¡Õ¯Õ¡Õ¶Õ¨, Õ°Õ¡Õ¾Õ¡Õ¶Õ¡Õ¢Õ¡Ö€, Õ°Õ¥Õ¿ Õ§ Õ¯Õ¡Õ¶Õ¹Õ¾Õ¥Õ¬: ÕŠÕ¡Õ¿Õ³Õ¡Õ¼Õ¨ Õ¯Õ¡Ö€Õ¸Õ² Õ§ Õ¬Õ«Õ¶Õ¥Õ¬ Õ½Õ­Õ¡Õ¬ Õ¯Õ¡Õ¦Õ´Õ¡Õ±Ö‡Õ¸Ö‚Õ´Õ¨ Õ¯Õ¡Õ´ Õ¯Õ¡ÕºÕ¡Õ¯ÖÕ´Õ¡Õ¶ Õ­Õ¡ÖƒÕ¡Õ¶Õ¸Ö‚Õ´Õ¨ Õ°Õ¡Ö€Õ±Õ¡Õ¯Õ¾Õ¸Õ²Õ« Õ¯Õ¸Õ²Õ´Õ«Ö:</translation>
<translation id="2414886740292270097">Õ„Õ¸Ö‚Õ£</translation>
<translation id="2430968933669123598">Ô¿Õ¡Õ¼Õ¡Õ¾Õ¡Ö€Õ¥Õ¬ Google Õ°Õ¡Õ·Õ«Õ¾Õ¨Ö‰ Google Õ°Õ¡Õ·Õ¾Õ¸Ö‚Õ´ Õ±Õ¥Ö€ Õ¿Õ¾ÕµÕ¡Õ¬Õ¶Õ¥Ö€Õ¨, Õ£Õ¡Õ²Õ¿Õ¶Õ«Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶ Õ¸Ö‚ Õ¡Õ¶Õ¾Õ¿Õ¡Õ¶Õ£Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¨ Õ¯Õ¡Õ¼Õ¡Õ¾Õ¡Ö€Õ¥Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€ Õ½Õ¥Õ²Õ´Õ¥Ö„ EnterÖ‰</translation>
+<translation id="2436186046335138073">Ô¹Õ¸Ö‚ÕµÕ¬Õ¡Õ¿Ö€Õ¥ÕžÕ¬ <ph name="HANDLER_HOSTNAME" />-Õ«Õ¶ Õ¢Õ¡ÖÕ¥Õ¬ <ph name="PROTOCOL" /> Õ°Õ¡Õ²Õ¸Ö€Õ¤Õ¡Õ¯Õ¡Ö€Õ£Õ« Õ¢Õ¸Õ¬Õ¸Ö€ Õ°Õ²Õ¸Ö‚Õ´Õ¶Õ¥Ö€Õ¨:</translation>
<translation id="2438874542388153331">Õ‰Õ¸Ö€Õ½ Õ¡Õ¶ÖÖ„ Õ¡Õ» Õ¯Õ¸Õ²Õ´Õ¸Ö‚Õ´</translation>
<translation id="2450021089947420533">Ô±ÕµÖÕ¥Õ¬Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€</translation>
<translation id="2463739503403862330">Ô¼Ö€Õ¡ÖÕ¶Õ¥Õ¬</translation>
@@ -478,6 +498,7 @@
<translation id="2465655957518002998">Ô¸Õ¶Õ¿Ö€Õ¥Ö„ Õ¡Õ¼Õ¡Ö„Õ´Õ¡Õ¶ Õ¥Õ²Õ¡Õ¶Õ¡Õ¯Õ¨</translation>
<translation id="2465688316154986572">Ô±Õ´Ö€Õ¡Õ¯</translation>
<translation id="2465914000209955735">Ô¿Õ¡Õ¼Õ¡Õ¾Õ¡Ö€Õ¥Õ¬ Chrome-Õ¸Ö‚Õ´ Õ±Õ¥Ö€ Õ¶Õ¥Ö€Õ¢Õ¥Õ¼Õ¶Õ¡Õ® Ö†Õ¡ÕµÕ¬Õ¥Ö€Õ¨</translation>
+<translation id="2466004615675155314">Õ‘Õ¸Ö‚ÕµÖ Õ¿Õ¡Õ¬ Õ¿Õ¥Õ²Õ¥Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€ Õ°Õ¡Õ´Õ¡ÖÕ¡Õ¶ÖÕ«Ö</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Ô³Õ¸Ö€Õ®Õ¡Ö€Õ¯Õ¥Õ¬ ÖÕ¡Õ¶ÖÕ« Õ¡Õ­Õ¿Õ¸Ö€Õ¸Õ·Õ¸Ö‚Õ´Õ¨<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">1-Õ«Ö N Õ°Õ¥Ö€Õ©Õ¡Õ¯Õ¡Õ¶Õ¸Ö‚Õ©ÕµÕ¡Õ´Õ¢</translation>
<translation id="2470767536994572628">ÔµÖ€Õ¢ Õ¤Õ¸Ö‚Ö„ Õ­Õ´Õ¢Õ¡Õ£Ö€Õ¥Ö„ Õ®Õ¡Õ¶Õ¸Õ©Õ¡Õ£Ö€Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¨, ÖƒÕ¡Õ½Õ¿Õ¡Õ©Õ¸Ö‚Õ²Õ©Õ¨ Õ¯ÖÕ¸Ö‚ÖÕ¡Õ¤Ö€Õ¾Õ« Õ´Õ¥Õ¯ Õ§Õ»Õ¸Õ¾ Ö‡ Õ«Ö€ Õ½Õ¯Õ¦Õ¢Õ¶Õ¡Õ¯Õ¡Õ¶ Õ¤Õ«Ö€Ö„Õ¸Õ¾</translation>
@@ -498,6 +519,7 @@
<translation id="2523886232349826891">Ô¿ÕºÕ¡Õ°Õ¾Õ« Õ´Õ«Õ¡ÕµÕ¶ Õ¡ÕµÕ½ Õ½Õ¡Ö€Ö„Õ¸Ö‚Õ´</translation>
<translation id="2524461107774643265">Ô±Õ¾Õ¥Õ¬Õ¡ÖÖ€Õ¥Ö„ Õ¬Ö€Õ¡ÖÕ¸Ö‚ÖÕ«Õ¹ Õ¿Õ¥Õ²Õ¥Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€</translation>
<translation id="2529899080962247600">Ô±ÕµÕ½ Õ¤Õ¡Õ·Õ¿Õ¸Ö‚Õ´ Õ£Ö€Õ¡Õ¼Õ¸Ö‚Õ´Õ¶Õ¥Ö€Õ« Õ¡Õ¼Õ¡Õ¾Õ¥Õ¬Õ¡Õ£Õ¸Ö‚ÕµÕ¶ Ö„Õ¡Õ¶Õ¡Õ¯Õ¨Õ <ph name="MAX_ITEMS_LIMIT" />: Ô±Õ¾Õ¥Õ¬ Õ£Ö€Õ¡Õ¼Õ¸Ö‚Õ´Õ¶Õ¥Ö€Õ¨ Õ¯Õ¡Õ¶Õ¿Õ¥Õ½Õ¾Õ¥Õ¶:</translation>
+<translation id="2535585790302968248">Ô²Õ¡ÖÕ¥Ö„ Õ¶Õ¸Ö€ Õ«Õ¶Õ¯Õ¸Õ£Õ¶Õ«Õ¿Õ¸ Õ¶Õ¥Ö€Õ¤Õ«Ö€, Õ¸Ö€ÕºÕ¥Õ½Õ¦Õ« Õ¡ÕµÖÕ¥Õ¬Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ« ÕºÕ¡Õ¿Õ´Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¨ Õ¹ÕºÕ¡Õ°Õ¾Õ«</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{Õ¸Ö‚ Ö‡Õ½ 1 Õ¿Õ«Ö€Õ¸Ö‚ÕµÕ©}one{Õ¸Ö‚ Ö‡Õ½ # Õ¿Õ«Ö€Õ¸Ö‚ÕµÕ©}other{Õ¸Ö‚ Ö‡Õ½ # Õ¿Õ«Ö€Õ¸Ö‚ÕµÕ©}}</translation>
<translation id="2536110899380797252">Ô±Õ¾Õ¥Õ¬Õ¡ÖÕ¶Õ¥Õ¬ Õ°Õ¡Õ½ÖÕ¥</translation>
<translation id="2539524384386349900">ÕƒÕ¡Õ¶Õ¡Õ¹Õ¥Õ¬</translation>
@@ -523,7 +545,14 @@
<translation id="2597378329261239068">Ô±ÕµÕ½ ÖƒÕ¡Õ½Õ¿Õ¡Õ©Õ¸Ö‚Õ²Õ©Õ¨ Õ£Õ¡Õ²Õ¿Õ¶Õ¡Õ¢Õ¡Õ¼Õ¸Õ¾ ÕºÕ¡Õ·Õ¿ÕºÕ¡Õ¶Õ¾Õ¡Õ® Õ§: Õ„Õ¸Ö‚Õ¿Ö„Õ¡Õ£Ö€Õ¥Ö„ Õ£Õ¡Õ²Õ¿Õ¶Õ¡Õ¢Õ¡Õ¼Õ¨:</translation>
<translation id="2609632851001447353">ÕÕ¡Ö€Õ¢Õ¥Ö€Õ¡Õ¯Õ¶Õ¥Ö€</translation>
<translation id="2610561535971892504">ÕÕ¥Õ²Õ´Õ¥Õ¬Õ ÕºÕ¡Õ¿Õ³Õ¥Õ¶Õ¥Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€</translation>
+<translation id="2617988307566202237">Chrome-Õ¸Ö‚Õ´ <ph name="BEGIN_EMPHASIS" />Õ¹Õ¥Õ¶ ÕºÕ¡Õ°Õ¾Õ«<ph name="END_EMPHASIS" />Õ
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Õ±Õ¥Ö€ Õ¡ÕµÖÕ¥Õ¬Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ« ÕºÕ¡Õ¿Õ´Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¨,
+ <ph name="LIST_ITEM" />Ö„Õ¸Ö‚Ö„Õ«Õ¶Õ¥Ö€Õ¶ Õ¸Ö‚ Õ¯Õ¡ÕµÖ„Õ¥Ö€Õ« Õ¿Õ¾ÕµÕ¡Õ¬Õ¶Õ¥Ö€Õ¨,
+ <ph name="LIST_ITEM" />Õ±Ö‡Õ¥Ö€Õ¸Ö‚Õ´ Õ¬Ö€Õ¡ÖÕ¾Õ¡Õ® Õ¿Õ¥Õ²Õ¥Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¨Ö‰
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (Õ®Ö€Õ¡Ö€)</translation>
+<translation id="2623663032199728144">Ô¿Õ¡Ö€Õ¸Õ² Õ§ Õ±Õ¥Ö€ Õ§Õ¯Ö€Õ¡Õ¶Õ¶Õ¥Ö€Õ« Õ´Õ¡Õ½Õ«Õ¶ Õ¿Õ¥Õ²Õ¥Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¶ Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¥Õ¬Õ¸Ö‚ Õ©Õ¸Ö‚ÕµÕ¬Õ¿Õ¾Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶ Õ°Õ¡ÕµÖÕ¥Õ¬</translation>
<translation id="2625385379895617796">ÕÕ¥Ö€ ÕªÕ¡Õ´Õ¡ÖÕ¸Ö‚ÕµÖÕ¨ Õ¡Õ¼Õ¡Õ» Õ§ Õ¨Õ¶Õ¯Õ¥Õ¬</translation>
<translation id="262745152991669301">Ô¿Õ¡Ö€Õ¸Õ² Õ§ Õ°Õ¡ÕµÖÕ¥Õ¬ USB Õ½Õ¡Ö€Ö„Õ¥Ö€Õ«Õ¶ Õ´Õ«Õ¡Õ¶Õ¡Õ¬Õ¸Ö‚ Õ©Õ¸Ö‚ÕµÕ¬Õ¿Õ¾Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶</translation>
<translation id="2629325967560697240">Chrome-Õ« Õ¬Õ¡Õ¾Õ¡Õ£Õ¸Ö‚ÕµÕ¶ ÕºÕ¡Õ·Õ¿ÕºÕ¡Õ¶Õ¸Ö‚Õ©ÕµÕ¡Õ¶ Õ°Õ¡Õ´Õ¡Õ¯Õ¡Ö€Õ£Õ¥Ö€Õ¶ Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¥Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€ <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />Õ´Õ«Õ¡ÖÖ€Õ¥Ö„ Õ¬Ö€Õ¡ÖÕ¸Ö‚ÖÕ«Õ¹ ÕºÕ¡Õ·Õ¿ÕºÕ¡Õ¶Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¨<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -557,6 +586,7 @@
<translation id="2709516037105925701">Ô»Õ¶Ö„Õ¶Õ¡Õ¬ÖÕ¸Ö‚Õ´</translation>
<translation id="2713444072780614174">ÕÕºÕ«Õ¿Õ¡Õ¯</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />Ö‰ ÕÕ¥Ö€ Õ¾Õ³Õ¡Ö€Õ¸Ö‚Õ´Õ¶Õ¥Ö€Õ¨ Ö‡ Õ¾Õ¡Ö€Õ¯Õ¡ÕµÕ«Õ¶ Ö„Õ¡Ö€Õ¿Õ¥Ö€Õ« Õ¿Õ¾ÕµÕ¡Õ¬Õ¶Õ¥Ö€Õ¨ Chrome-Õ« Õ¯Õ¡Ö€Õ£Õ¡Õ¾Õ¸Ö€Õ¸Ö‚Õ´Õ¶Õ¥Ö€Õ¸Ö‚Õ´ Õ¯Õ¡Õ¼Õ¡Õ¾Õ¡Ö€Õ¥Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€ Õ½Õ¥Õ²Õ´Õ¥Ö„ Tab, Õ¡ÕºÕ¡Õ EnterÖ‰</translation>
+<translation id="271663710482723385">Ô¼Õ«Õ¡Õ§Õ¯Ö€Õ¡Õ¶ Õ¼Õ¥ÕªÕ«Õ´Õ«Ö Õ¤Õ¸Ö‚Ö€Õ½ Õ£Õ¡Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€ Õ½Õ¥Õ²Õ´Õ¥Ö„ |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />|</translation>
<translation id="2721148159707890343">Õ€Õ¡Ö€ÖÕ¸Ö‚Õ´Õ¨ Õ°Õ¡Õ»Õ¸Õ²Õ¾Õ¥Ö</translation>
<translation id="2723669454293168317">Ô±Õ¶ÖÕ¥Ö„ Õ¡Õ¶Õ¾Õ¿Õ¡Õ¶Õ£Õ¸Ö‚Õ©ÕµÕ¡Õ¶ Õ½Õ¿Õ¸Ö‚Õ£Õ¸Ö‚Õ´ Chrome-Õ« Õ¯Õ¡Ö€Õ£Õ¡Õ¾Õ¸Ö€Õ¸Ö‚Õ´Õ¶Õ¥Ö€Õ¸Ö‚Õ´</translation>
<translation id="2726001110728089263">Ô¿Õ¸Õ²Õ¡ÕµÕ«Õ¶ Õ¤Õ¡Ö€Õ¡Õ¯</translation>
@@ -587,6 +617,7 @@
<translation id="2850739647070081192">Invite (Õ®Ö€Õ¡Ö€)</translation>
<translation id="2856444702002559011">Õ€Õ¡Ö€Õ±Õ¡Õ¯Õ¾Õ¸Õ²Õ¶Õ¥Ö€Õ¨ Õ¯Õ¡Ö€Õ¸Õ² Õ¥Õ¶ Õ°Õ¡ÖƒÕ·Õ¿Õ¡Õ¯Õ¥Õ¬ Õ±Õ¥Ö€ Õ¿Õ¥Õ²Õ¥Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¨ (Ö…Ö€Õ«Õ¶Õ¡Õ¯Õ Õ£Õ¡Õ²Õ¿Õ¶Õ¡Õ¢Õ¡Õ¼Õ¥Ö€Õ¨, Õ¶Õ¡Õ´Õ¡Õ¯Õ¶Õ¥Ö€Õ¨ Õ¯Õ¡Õ´ Õ¾Õ¡Ö€Õ¯Õ¡ÕµÕ«Õ¶ Ö„Õ¡Ö€Õ¿Õ¥Ö€Õ¨) <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> Õ¯Õ¡ÕµÖ„Õ«ÖÖ‰ <ph name="BEGIN_LEARN_MORE_LINK" />Ô»Õ´Õ¡Õ¶Õ¡Õ¬ Õ¡Õ¾Õ¥Õ¬Õ«Õ¶<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">Ô±ÕµÕ½ Õ¯Õ¡ÕµÖ„Õ¨ Õ°Õ¸Õ£Õ¶Õ¥ÖÕ¶Õ¸Õ² Õ¯Õ¡Õ´ Õ´Õ¸Õ¬Õ¸Ö€Õ¥ÖÕ¶Õ¸Õ² Õ£Õ¸Õ¾Õ¡Õ¦Õ¤ Õ§ ÖÕ¸Ö‚ÖÕ¡Õ¤Ö€Õ¸Ö‚Õ´Ö‰</translation>
+<translation id="286512204874376891">ÕŽÕ«Ö€Õ¿Õ¸Ö‚Õ¡Õ¬ Ö„Õ¡Ö€Õ¿Õ¨ Õ©Õ¡Ö„ÖÕ¶Õ¸Ö‚Õ´ Õ§ Õ±Õ¥Ö€ Õ«Ö€Õ¡Õ¯Õ¡Õ¶ Ö„Õ¡Ö€Õ¿Õ¨Õ Ö…Õ£Õ¶Õ¥Õ¬Õ¸Õ¾ ÕºÕ¡Õ·Õ¿ÕºÕ¡Õ¶Õ¥Õ¬ Õ±Õ¥Õ¦ Õ°Õ¶Õ¡Ö€Õ¡Õ¾Õ¸Ö€ Õ­Õ¡Ö€Õ¤Õ¡Õ­Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ«ÖÖ‰ <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">Ô¸Õ¶Õ¯Õ¥Ö€Õ¡Õ¯Õ¡Õ¶</translation>
<translation id="2876489322757410363">Ô´Õ¸Ö‚Ö„ Õ¤Õ¸Ö‚Ö€Õ½ Õ¯Õ£Õ¡Ö„ Õ«Õ¶Õ¯Õ¸Õ£Õ¶Õ«Õ¿Õ¸ Õ¼Õ¥ÕªÕ«Õ´Õ«ÖÕ Õ¡Ö€Õ¿Õ¡Ö„Õ«Õ¶ Õ°Õ¡Õ¾Õ¥Õ¬Õ¾Õ¡Õ®Õ¸Ö‚Õ´ Õ¾Õ³Õ¡Ö€Õ¸Ö‚Õ´ Õ¯Õ¡Õ¿Õ¡Ö€Õ¥Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€Ö‰ Õ‡Õ¡Ö€Õ¸Ö‚Õ¶Õ¡Õ¯Õ¥ÕžÕ¬Ö‰</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />Ö‰ Chrome-Õ« Õ¯Õ¡Ö€Õ£Õ¡Õ¾Õ¸Ö€Õ¸Ö‚Õ´Õ¶Õ¥Ö€Õ¸Ö‚Õ´ Ô±ÕºÕ¡Õ°Õ¸Õ¾ Õ¤Õ«Õ¿Õ¡Ö€Õ¯Õ¸Ö‚Õ´Õ¨ Ö‡ Õ¡ÕµÕ¬ ÕºÕ¡Ö€Õ¡Õ´Õ¥Õ¿Ö€Õ¥Ö€ Õ¯Õ¡Õ¼Õ¡Õ¾Õ¡Ö€Õ¥Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€ Õ½Õ¥Õ²Õ´Õ¥Ö„ Tab, Õ¡ÕºÕ¡Õ EnterÖ‰</translation>
@@ -611,6 +642,7 @@
<translation id="2930577230479659665">Ô¿Õ¿Ö€Õ¥Õ¬ ÕµÕ¸Ö‚Ö€Õ¡Ö„Õ¡Õ¶Õ¹ÕµÕ¸Ö‚Ö€ Ö…Ö€Õ«Õ¶Õ¡Õ¯Õ«Ö Õ°Õ¥Õ¿Õ¸</translation>
<translation id="2932085390869194046">ÕÕ¿Õ¥Õ²Õ®Õ¥Õ¬ գաղտնաբառ…</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019">Ô²Õ¡ÖÕ¥Õ¬ <ph name="PROTOCOL" /> Õ°Õ²Õ¸Ö‚Õ´Õ¶Õ¥Ö€Õ¨</translation>
<translation id="2941952326391522266">Ô±ÕµÕ½ Õ½Õ¥Ö€Õ¾Õ¥Ö€Õ¨ Õ¹Õ« Õ¯Õ¡Ö€Õ¸Õ² Õ¡ÕºÕ¡ÖÕ¸Ö‚ÖÕ¥Õ¬, Õ¸Ö€ <ph name="DOMAIN" /> Õ§: Ô´Ö€Õ¡ Õ¡Õ¶Õ¾Õ¿Õ¡Õ¶Õ£Õ¸Ö‚Õ©ÕµÕ¡Õ¶ Õ¾Õ¯Õ¡ÕµÕ¡Õ¯Õ¡Õ¶Õ¨ <ph name="DOMAIN2" />-Õ«Ö Õ§: ÕŠÕ¡Õ¿Õ³Õ¡Õ¼Õ¨ Õ¯Õ¡Ö€Õ¸Õ² Õ§ Õ¬Õ«Õ¶Õ¥Õ¬ Õ½Õ­Õ¡Õ¬ Õ¯Õ¡Õ¦Õ´Õ¡Õ±Ö‡Õ¸Ö‚Õ´Õ¨ Õ¯Õ¡Õ´ Õ¯Õ¡ÕºÕ¡Õ¯ÖÕ´Õ¡Õ¶ Õ­Õ¡ÖƒÕ¡Õ¶Õ¸Ö‚Õ´Õ¨ Õ°Õ¡Ö€Õ±Õ¡Õ¯Õ¾Õ¸Õ²Õ« Õ¯Õ¸Õ²Õ´Õ«Ö:</translation>
<translation id="2943895734390379394">ÕŽÕ¥Ö€Õ¢Õ¥Õ¼Õ¶Õ´Õ¡Õ¶ Ö…Ö€Õ¨ Ö‡ ÕªÕ¡Õ´Õ¨Õ</translation>
<translation id="2948083400971632585">Ô´Õ¸Ö‚Ö„ Õ¯Õ¡Ö€Õ¸Õ² Õ¥Ö„ Õ¡Õ¶Õ»Õ¡Õ¿Õ¥Õ¬ Õ¯Õ¡ÕºÕ¡Õ¯ÖÕ´Õ¡Õ¶ Õ°Õ¡Õ´Õ¡Ö€ Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¾Õ¸Õ² ÕºÖ€Õ¸Ö„Õ½Õ«-Õ½Õ¥Ö€Õ¾Õ¥Ö€Õ¶Õ¥Ö€Õ¨ Õ¶Õ¥Ö€Õ¨ Õ¯Õ¡Ö€Õ£Õ¡Õ¾Õ¸Ö€Õ¸Ö‚Õ´Õ¶Õ¥Ö€Õ« Õ§Õ»Õ«Ö:</translation>
@@ -643,6 +675,7 @@
<translation id="3037605927509011580">ÕŽÕ¡Õ›Õµ</translation>
<translation id="3041612393474885105">ÕŽÕ¯Õ¡ÕµÕ¡Õ£Ö€Õ« Õ¿Õ¥Õ²Õ¥Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¨</translation>
<translation id="3044034790304486808">Õ‡Õ¡Ö€Õ¸Ö‚Õ¶Õ¡Õ¯Õ¥Õ¬ Õ¸Ö€Õ¸Õ¶Õ¸Ö‚Õ´Õ¨</translation>
+<translation id="305162504811187366">Chrome Õ°Õ¥Õ¼Õ¡Õ¯Õ¡ Õ¡Õ·Õ­Õ¡Õ¿Õ¡Õ½Õ¥Õ²Õ¡Õ¶Õ« ÕºÕ¡Õ¿Õ´Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¨, Õ¡ÕµÕ¤ Õ©Õ¾Õ¸Ö‚Õ´Õ ÕªÕ¡Õ´Õ¡Õ¤Ö€Õ¸Õ·Õ´Õ¶Õ¥Ö€Õ¨, Õ­Õ¶Õ¡Õ´Õ¸Ö€Õ¤Õ¶Õ¥Ö€Õ¨ Ö‡ Õ½ÕºÕ¡Õ½Õ¡Õ¼Õ¸Ö‚Õ¶Õ¥Ö€Õ« Õ¡Õ·Õ­Õ¡Õ¿Õ¡Õ·Ö€Õ»Õ¡Õ¶Õ¶Õ¥Ö€Õ« Õ¶Õ¸Ö‚ÕµÕ¶Õ¡ÖÕ¸Ö‚ÖÕ«Õ¹Õ¶Õ¥Ö€Õ¨</translation>
<translation id="3060227939791841287">C9 (Õ®Ö€Õ¡Ö€)</translation>
<translation id="3061707000357573562">Ô½Õ¸ÖÕ¥Õ¬Õ«Õ¸Ö‚Õ©ÕµÕ¡Õ¶ Õ·Õ¿Õ¯Õ¸Ö‚Õ´</translation>
<translation id="306573536155379004">Ô½Õ¡Õ²Õ¨ Õ½Õ¯Õ½Õ¾Õ¡Õ® Õ§Ö‰</translation>
@@ -673,9 +706,9 @@
<translation id="3162559335345991374">Ô±Õ¶Õ¬Õ¡Ö€ Õ¯Õ¡ÕºÕ¨, Õ¸Ö€Õ«Ö Ö…Õ£Õ¿Õ¾Õ¸Ö‚Õ´ Õ¥Ö„, Õ¯Õ¡Ö€Õ¸Õ² Õ§ ÕºÕ¡Õ°Õ¡Õ¶Õ»Õ¥Õ¬, Õ¸Ö€ÕºÕ¥Õ½Õ¦Õ« Õ¤Õ¸Ö‚Ö„ Õ¡ÕµÖÕ¥Õ¬Õ¥Ö„ Õ¶Ö€Õ¡ Õ´Õ¸Ö‚Õ¿Ö„Õ« Õ§Õ»Õ¨:</translation>
<translation id="3169472444629675720">Discover</translation>
<translation id="3174168572213147020">Ô¿Õ²Õ¦Õ«</translation>
-<translation id="3176929007561373547">ÕÕ¿Õ¸Ö‚Õ£Õ¥Ö„ Õ±Õ¥Ö€ Õ´Õ«Õ»Õ¶Õ¸Ö€Õ¤ Õ½Õ¥Ö€Õ¾Õ¥Ö€Õ« Õ¯Õ¡Ö€Õ£Õ¡Õ¾Õ¸Ö€Õ¸Ö‚Õ´Õ¶Õ¥Ö€Õ¨ Õ¯Õ¡Õ´ Õ¯Õ¡ÕºÕ¾Õ¥Ö„
+<translation id="3176929007561373547">ÕÕ¿Õ¸Ö‚Õ£Õ¥Ö„ Õ±Õ¥Ö€ ÕºÖ€Õ¸Ö„Õ½Õ« Õ½Õ¥Ö€Õ¾Õ¥Ö€Õ« Õ¯Õ¡Ö€Õ£Õ¡Õ¾Õ¸Ö€Õ¸Ö‚Õ´Õ¶Õ¥Ö€Õ¨ Õ¯Õ¡Õ´ Õ¯Õ¡ÕºÕ¾Õ¥Ö„
ÖÕ¡Õ¶ÖÕ« Õ¡Õ¤Õ´Õ«Õ¶Õ«Õ½Õ¿Ö€Õ¡Õ¿Õ¸Ö€Õ« Õ°Õ¥Õ¿, Õ¸Ö€ÕºÕ¥Õ½Õ¦Õ« Õ°Õ¡Õ´Õ¸Õ¦Õ¾Õ¥Ö„, Õ¸Ö€
- Õ´Õ«Õ»Õ¶Õ¸Ö€Õ¤ Õ½Õ¥Ö€Õ¾Õ¥Ö€Õ¶ Õ¡Õ·Õ­Õ¡Õ¿Õ¸Ö‚Õ´ Õ§: ÔµÕ©Õ¥ Õ¹Õ¥Ö„ Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¸Ö‚Õ´ Õ´Õ«Õ»Õ¶Õ¸Ö€Õ¤ Õ½Õ¥Ö€Õ¾Õ¥Ö€`
+ ÕºÖ€Õ¸Ö„Õ½Õ« Õ½Õ¥Ö€Õ¾Õ¥Ö€Õ¶ Õ¡Õ·Õ­Õ¡Õ¿Õ¸Ö‚Õ´ Õ§: ÔµÕ©Õ¥ Õ¹Õ¥Ö„ Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¸Ö‚Õ´ ÕºÖ€Õ¸Ö„Õ½Õ« Õ½Õ¥Ö€Õ¾Õ¥Ö€`
<ph name="PLATFORM_TEXT" /></translation>
<translation id="317878711435188021">ÕÕ¥Õ²Õ¥Õ¯Õ¡Õ¶Õ¡Õ¬, Õ¥Ö€Õ¢ Õ¤Õ¸Ö‚Ö„ Õ¡Õ¯Õ¿Õ«Õ¾Õ¸Ö€Õ¥Õ¶ Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¸Ö‚Õ´ Õ¥Ö„ Õ¡ÕµÕ½ Õ½Õ¡Ö€Ö„Õ¨</translation>
<translation id="3194737229810486521"><ph name="URL" /> Õ¯Õ¡ÕµÖ„Õ¶ Õ¸Ö‚Õ¦Õ¸Ö‚Õ´ Õ§ Õ±Õ¥Ö€ Õ½Õ¡Ö€Ö„Õ¸Ö‚Õ´ Õ´Õ¥Õ® Õ®Õ¡Õ¾Õ¡Õ¬Õ¸Õ¾ Õ¿Õ¾ÕµÕ¡Õ¬Õ¶Õ¥Ö€ Õ´Õ·Õ¿Õ¡ÕºÕ¥Õ½ ÕºÕ¡Õ°Õ¥Õ¬</translation>
@@ -683,6 +716,7 @@
<translation id="3197136577151645743">Ô¿Õ¡Ö€Õ¸Õ² Õ§ Õ°Õ¡ÕµÖÕ¥Õ¬ Õ©Õ¸Ö‚ÕµÕ¬Õ¿Õ¾Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ Õ¿Õ¥Õ²Õ¥Õ¯Õ¡Õ¶Õ¡Õ¬Õ¸Ö‚, Õ¥Ö€Õ¢ Õ¤Õ¸Ö‚Ö„ Õ¡Õ¯Õ¿Õ«Õ¾Õ¸Ö€Õ¥Õ¶ Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¸Ö‚Õ´ Õ¥Ö„ Õ±Õ¥Ö€ Õ½Õ¡Ö€Ö„Õ¨</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />Ö‰ Õ€Õ¡Õ´Õ¡ÕªÕ¡Õ´Õ¡ÖÕ¾Õ¸Õ² Õ¿Õ¥Õ²Õ¥Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¨ Chrome-Õ« Õ¯Õ¡Ö€Õ£Õ¡Õ¾Õ¸Ö€Õ¸Ö‚Õ´Õ¶Õ¥Ö€Õ¸Ö‚Õ´ Õ¯Õ¡Õ¼Õ¡Õ¾Õ¡Ö€Õ¥Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€ Õ½Õ¥Õ²Õ´Õ¥Ö„ Tab, Õ¡ÕºÕ¡Õ EnterÖ‰</translation>
<translation id="320323717674993345">Õ‰Õ¥Õ²Õ¡Ö€Õ¯Õ¥Õ¬ Õ¾Õ³Õ¡Ö€Õ¸Ö‚Õ´Õ¨</translation>
+<translation id="3203366800380907218">Õ€Õ¡Õ´Õ¡ÖÕ¡Õ¶ÖÕ«Ö</translation>
<translation id="3207960819495026254">Ô·Õ»Õ¡Õ¶Õ·Õ¾Õ¡Õ® Õ§</translation>
<translation id="3209034400446768650">Ô±ÕµÕ½ Õ§Õ»Õ¨ Õ¯Õ¡Ö€Õ¸Õ² Õ§ Õ£Õ¸Ö‚Õ´Õ¡Ö€ Õ£Õ¡Õ¶Õ±Õ¥Õ¬ Õ±Õ¥Õ¦Õ¶Õ«Ö</translation>
<translation id="3212581601480735796">ÕÕ¥Ö€ Õ£Õ¸Ö€Õ®Õ¸Õ²Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¨ <ph name="HOSTNAME" /> Õ¯Õ¡ÕµÖ„Õ¸Ö‚Õ´ Õ°Õ¥Õ¿Õ¡Õ£Õ®Õ¾Õ¸Ö‚Õ´ Õ¥Õ¶</translation>
@@ -699,10 +733,12 @@
<translation id="3234666976984236645">Õ„Õ«Õ·Õ¿ Õ°Õ¡Õ¿Õ¯Õ¸Ö€Õ¸Õ·Õ¥Õ¬ Õ¯Õ¡Ö€Ö‡Õ¸Ö€ Õ¢Õ¸Õ¾Õ¡Õ¶Õ¤Õ¡Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¨ Õ¡ÕµÕ½ Õ¯Õ¡ÕµÖ„Õ¸Ö‚Õ´</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />Ö‰ Ô´Õ«Õ¿Õ¡Ö€Õ¯Õ«Õ¹Õ« Õ¿Õ¥Õ½Ö„Õ¨ Õ¯Õ¡Ö€Õ£Õ¡Õ¾Õ¸Ö€Õ¥Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€ Õ½Õ¥Õ²Õ´Õ¥Ö„ Tab, Õ¡ÕºÕ¡Õ EnterÖ‰</translation>
<translation id="3240791268468473923">Ô²Õ¡ÖÕ¾Õ¥Õ¬ Õ§ ÕºÕ¡Õ¿Õ¸Ö‚Õ°Õ¡Õ¶, Õ¸Ö€Õ¨ ÖÕ¸Ö‚ÖÕ¡Õ¤Ö€Õ¸Ö‚Õ´ Õ§ Õ¡Õ¶Õ¾Õ¿Õ¡Õ¶Õ£ Õ¾Õ³Õ¡Ö€Õ´Õ¡Õ¶ Õ¿Õ¾ÕµÕ¡Õ¬Õ¶Õ¥Ö€Õ« Õ¡Õ¶Õ°Õ¡Õ´Õ¡ÕºÕ¡Õ¿Õ¡Õ½Õ­Õ¡Õ¶Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¨ Õ¿Õ¾ÕµÕ¡Õ¬Õ¶Õ¥Ö€Õ« Õ¡Õ²ÕµÕ¸Ö‚Õ½Õ¡Õ¯Õ« Õ°Õ¥Õ¿</translation>
+<translation id="324180406144491771">«<ph name="HOST_NAME" />» հղումներն արգելափակված են</translation>
<translation id="3249845759089040423">Õ†Õ¸Ö€Õ¡Õ±Ö‡</translation>
<translation id="3252266817569339921">Õ–Ö€Õ¡Õ¶Õ½Õ«Õ¡Õ¯Õ¡Õ¶</translation>
<translation id="3257954757204451555">ÕˆÕžÕ¾ Õ§ Õ¿Ö€Õ¡Õ´Õ¡Õ¤Ö€Õ¥Õ¬ Õ¡ÕµÕ½ Õ¿Õ¥Õ²Õ¥Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¨</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />Ö‰ Google Õ•Ö€Õ¡ÖÕ¸Ö‚ÕµÖÕ¸Ö‚Õ´ Õ¡Ö€Õ¡Õ£ Õ´Õ«Õ»Õ¸ÖÕ¡Õ¼Õ¸Ö‚Õ´ Õ½Õ¿Õ¥Õ²Õ®Õ¥Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€ Õ½Õ¥Õ²Õ´Õ¥Ö„ Tab, Õ¡ÕºÕ¡Õ EnterÖ‰</translation>
+<translation id="3261488570342242926">Ô»Õ´Õ¡Õ¶Õ¡Õ¬ Õ¡Õ¾Õ¥Õ¬Õ«Õ¶ Õ¾Õ«Ö€Õ¿Õ¸Ö‚Õ¡Õ¬ Ö„Õ¡Ö€Õ¿Õ¥Ö€Õ« Õ´Õ¡Õ½Õ«Õ¶</translation>
<translation id="3264837738038045344">«Կառավարել Chrome-Õ« կարգավորումները» Õ¯Õ¸Õ³Õ¡Õ¯Ö‰ ÕÕ¥Õ²Õ´Õ¥Ö„ EnterÕ Chrome-Õ« Õ¯Õ¡Ö€Õ£Õ¡Õ¾Õ¸Ö€Õ¸Ö‚Õ´Õ¶Õ¥Ö€ Õ¡Õ¶ÖÕ¶Õ¥Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€</translation>
<translation id="3266793032086590337">Ô±Ö€ÕªÕ¥Ö„Õ¨ (Õ°Õ¡Õ¯Õ¡Õ½Õ¡Õ¯Õ¡Õ¶)</translation>
<translation id="3268451620468152448">Ô²Õ¡Ö Õ¶Õ¥Ö€Õ¤Õ«Ö€Õ¶Õ¥Ö€Õ¨</translation>
@@ -716,6 +752,7 @@
<translation id="3288238092761586174"><ph name="URL" /> Õ¯Õ¡ÕµÖ„Õ¨ Õ¯Õ¡Ö€Õ¸Õ² Õ§ Õ¬Ö€Õ¡ÖÕ¸Ö‚ÖÕ«Õ¹ Ö„Õ¡ÕµÕ¬Õ¥Ö€ Õ¯Õ¡Õ¿Õ¡Ö€Õ¥Õ¬Õ Õ±Õ¥Ö€ Õ¾Õ³Õ¡Ö€Õ¸Ö‚Õ´Õ¨ Õ°Õ¡Õ½Õ¿Õ¡Õ¿Õ¥Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€</translation>
<translation id="3293642807462928945">Ô»Õ´Õ¡Õ¶Õ¡Õ¬ Õ¡Õ¾Õ¥Õ¬Õ«Õ¶ <ph name="POLICY_NAME" /> Õ¯Õ¡Õ¶Õ¸Õ¶Õ« Õ´Õ¡Õ½Õ«Õ¶</translation>
<translation id="3295444047715739395">Ô´Õ«Õ¿Õ¥Ö„ Ö‡ Õ¯Õ¡Õ¼Õ¡Õ¾Õ¡Ö€Õ¥Ö„ Õ±Õ¥Ö€ Õ£Õ¡Õ²Õ¿Õ¶Õ¡Õ¢Õ¡Õ¼Õ¥Ö€Õ¨ Chrome-Õ« Õ¯Õ¡Ö€Õ£Õ¡Õ¾Õ¸Ö€Õ¸Ö‚Õ´Õ¶Õ¥Ö€Õ¸Ö‚Õ´</translation>
+<translation id="3303795387212510132">Ô¹Õ¸Ö‚ÕµÕ¬Õ¡Õ¿Ö€Õ¥ÕžÕ¬ Õ°Õ¡Õ¾Õ¥Õ¬Õ¾Õ¡Õ®Õ«Õ¶ Õ¢Õ¡ÖÕ¥Õ¬ <ph name="PROTOCOL_SCHEME" /> Õ°Õ²Õ¸Ö‚Õ´Õ¶Õ¥Ö€Õ¨</translation>
<translation id="3303855915957856445">ÕˆÖ€Õ¸Õ¶Õ´Õ¡Õ¶ Õ¡Ö€Õ¤ÕµÕ¸Ö‚Õ¶Ö„Õ¶Õ¥Ö€ Õ¹Õ¯Õ¡Õ¶</translation>
<translation id="3304073249511302126">bluetooth Õ½Õ¡Ö€Ö„Õ¥Ö€Õ« Õ¸Ö€Õ¸Õ¶Õ¸Ö‚Õ´</translation>
<translation id="3308006649705061278">ÕÕ¿Õ¸Ö€Õ¡Õ¢Õ¡ÕªÕ¡Õ¶Õ¸Ö‚Õ´ (OU)</translation>
@@ -729,12 +766,6 @@
<translation id="3345782426586609320">Ô±Õ¹Ö„Õ¥Ö€</translation>
<translation id="3355823806454867987">Փոխել պրոքսի-սերվերի կարգավորումները…</translation>
<translation id="3360103848165129075">ÕŽÕ³Õ¡Ö€Õ´Õ¡Õ¶ Õ´Õ·Õ¡Õ¯Õ´Õ¡Õ¶ Õ©Õ¥Ö€Õ©</translation>
-<translation id="3361596688432910856">Chrome-Õ¸Ö‚Õ´ <ph name="BEGIN_EMPHASIS" />Õ¹Õ¥Õ¶ ÕºÕ¡Õ°Õ¾Õ«<ph name="END_EMPHASIS" />Õ
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Õ±Õ¥Ö€ Õ¡ÕµÖÕ¥Õ¬Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ« ÕºÕ¡Õ¿Õ´Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¨,
- <ph name="LIST_ITEM" />Ö„Õ¸Ö‚Ö„Õ«Õ¶Õ¥Ö€Õ¶ Õ¸Ö‚ Õ¯Õ¡ÕµÖ„Õ¥Ö€Õ« Õ¿Õ¾ÕµÕ¡Õ¬Õ¶Õ¥Ö€Õ¨,
- <ph name="LIST_ITEM" />Õ±Ö‡Õ¥Ö€Õ¸Ö‚Õ´ Õ¬Ö€Õ¡ÖÖ€Õ¡Õ® Õ¿Õ¥Õ²Õ¥Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¨Ö‰
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">Ô±ÕµÕ½ Õ¯Õ¡Õ¶Õ¸Õ¶Õ¶ Õ¡Õ¾Õ¿Õ¸Õ´Õ¡Õ¿ ÕºÕ¡Õ¿Õ³Õ¥Õ¶Õ¾Õ¥Õ¬ Õ§ <ph name="OLD_POLICY" /> Õ¯Õ¡Õ¶Õ¸Õ¶Õ«Ö, Õ¸Ö€Õ¶ Õ¡Ö€Õ¤Õ¥Õ¶ Õ°Õ¶Õ¡ÖÕ¥Õ¬ Õ§Ö‰ ÕŽÕ¥Ö€Õ»Õ«Õ¶Õ«Õ½ ÖƒÕ¸Õ­Õ¡Ö€Õ¥Õ¶ Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¥Ö„ Õ¡ÕµÕ½ Õ¯Õ¡Õ¶Õ¸Õ¶Õ¨Ö‰</translation>
<translation id="3364869320075768271"><ph name="URL" /> Õ¯Õ¡ÕµÖ„Õ¶ Õ¸Ö‚Õ¦Õ¸Ö‚Õ´ Õ§ Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¥Õ¬ Õ¾Õ«Ö€Õ¿Õ¸Ö‚Õ¡Õ¬ Õ«Ö€Õ¡Õ¯Õ¡Õ¶Õ¸Ö‚Õ©ÕµÕ¡Õ¶ Õ±Õ¥Ö€ Õ½Õ¡Ö€Ö„Õ¥Ö€Õ¶ Õ¸Ö‚ Õ¿Õ¾ÕµÕ¡Õ¬Õ¶Õ¥Ö€Õ¨</translation>
<translation id="3366477098757335611">Ô´Õ«Õ¿Õ¥Õ¬ Ö„Õ¡Ö€Õ¿Õ¥Ö€Õ¨</translation>
@@ -817,7 +848,6 @@
<translation id="3587738293690942763">Õ„Õ«Õ»Õ«Õ¶</translation>
<translation id="3592413004129370115">Italian (Õ®Ö€Õ¡Ö€)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{Ô´Õ¸Ö‚Ö„ ÖÕ¡Õ¶Õ¯Õ¡ÖÕ¡Õ® ÕªÕ¡Õ´Õ¡Õ¶Õ¡Õ¯ Õ¯Õ¡Ö€Õ¸Õ² Õ¥Ö„ Õ¦Ö€Õ¸ÕµÕ¡ÖÕ¶Õ¥Õ¬ Õ±Õ¥Ö€ Õ­Õ´Õ¢Õ« Õ¯Õ¡Ö€Õ£Õ¡Õ¾Õ¸Ö€Õ¸Ö‚Õ´Õ¶Õ¥Ö€Õ¨Ö‰ Ô½Õ´Õ¢Õ«Õ¶ Õ´Õ«Õ¡Õ¶Õ¡Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€ Õ´Õ¸Õ¿ Õ´Õ¥Õ¯ Ö…Ö€ Õ§ ÕºÕ¡Õ°Õ¡Õ¶Õ»Õ¾Õ¸Ö‚Õ´Ö‰}=1{Ô´Õ¸Ö‚Ö„ ÖÕ¡Õ¶Õ¯Õ¡ÖÕ¡Õ® ÕªÕ¡Õ´Õ¡Õ¶Õ¡Õ¯ Õ¯Õ¡Ö€Õ¸Õ² Õ¥Ö„ Õ¦Ö€Õ¸ÕµÕ¡ÖÕ¶Õ¥Õ¬ Õ±Õ¥Ö€ Õ­Õ´Õ¢Õ« Õ¯Õ¡Ö€Õ£Õ¡Õ¾Õ¸Ö€Õ¸Ö‚Õ´Õ¶Õ¥Ö€Õ¨Ö‰ Ô½Õ´Õ¢Õ«Õ¶ Õ´Õ«Õ¡Õ¶Õ¡Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€ Õ´Õ¸Õ¿ Õ´Õ¥Õ¯ Ö…Ö€ Õ§ ÕºÕ¡Õ°Õ¡Õ¶Õ»Õ¾Õ¸Ö‚Õ´Ö‰}one{Ô´Õ¸Ö‚Ö„ ÖÕ¡Õ¶Õ¯Õ¡ÖÕ¡Õ® ÕªÕ¡Õ´Õ¡Õ¶Õ¡Õ¯ Õ¯Õ¡Ö€Õ¸Õ² Õ¥Ö„ Õ¦Ö€Õ¸ÕµÕ¡ÖÕ¶Õ¥Õ¬ Õ±Õ¥Ö€ Õ­Õ´Õ¢Õ« Õ¯Õ¡Ö€Õ£Õ¡Õ¾Õ¸Ö€Õ¸Ö‚Õ´Õ¶Õ¥Ö€Õ¨Ö‰ Ô½Õ´Õ¢Õ«Õ¶ Õ´Õ«Õ¡Õ¶Õ¡Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€ Õ´Õ¸Õ¿ {NUM_DAYS} Ö…Ö€ Õ§ ÕºÕ¡Õ°Õ¡Õ¶Õ»Õ¾Õ¸Ö‚Õ´Ö‰}other{Ô´Õ¸Ö‚Ö„ ÖÕ¡Õ¶Õ¯Õ¡ÖÕ¡Õ® ÕªÕ¡Õ´Õ¡Õ¶Õ¡Õ¯ Õ¯Õ¡Ö€Õ¸Õ² Õ¥Ö„ Õ¦Ö€Õ¸ÕµÕ¡ÖÕ¶Õ¥Õ¬ Õ±Õ¥Ö€ Õ­Õ´Õ¢Õ« Õ¯Õ¡Ö€Õ£Õ¡Õ¾Õ¸Ö€Õ¸Ö‚Õ´Õ¶Õ¥Ö€Õ¨Ö‰ Ô½Õ´Õ¢Õ«Õ¶ Õ´Õ«Õ¡Õ¶Õ¡Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€ Õ´Õ¸Õ¿ {NUM_DAYS} Ö…Ö€ Õ§ ÕºÕ¡Õ°Õ¡Õ¶Õ»Õ¾Õ¸Ö‚Õ´Ö‰}}</translation>
-<translation id="3596012367874587041">Õ€Õ¡Õ¾Õ¥Õ¬Õ¾Õ¡Õ®Õ« Õ¯Õ¡Ö€Õ£Õ¡Õ¾Õ¸Ö€Õ¸Ö‚Õ´Õ¶Õ¥Ö€</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">ÕÕ¥Ö€ Õ¡Õ¤Õ´Õ«Õ¶Õ«Õ½Õ¿Ö€Õ¡Õ¿Õ¸Ö€Õ¶ Õ¡Ö€Õ£Õ¥Õ¬Õ¡ÖƒÕ¡Õ¯Õ¥Õ¬ Õ§ Õ°Õ¡Õ¾Õ¥Õ¬Õ¾Õ¡Õ®Õ¨</translation>
<translation id="3608932978122581043">Õ†Õ·Õ¥Õ¬ Õ¤Õ«Ö€Ö„Õ¨</translation>
@@ -860,10 +890,11 @@
<translation id="370972442370243704">Õ„Õ«Õ¡ÖÕ¶Õ¥Õ¬ Ô±ÕµÖÕ¥Õ¬Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¨</translation>
<translation id="3711895659073496551">Ô±Õ¶Õ£Õ¸Ö€Õ®Õ¸Ö‚Õ¶ Õ¼Õ¥ÕªÕ«Õ´</translation>
<translation id="3712624925041724820">Ô¼Õ«ÖÕ¥Õ¶Õ¦Õ«Õ¡Õ¶Õ¥Ö€ Õ¡ÕµÕ¬Ö‡Õ½ Õ¹Õ¯Õ¡Õ¶</translation>
+<translation id="3714633008798122362">Õ¾Õ¥Õ¢ Ö…Ö€Õ¡ÖÕ¸Ö‚ÕµÖ</translation>
<translation id="3714780639079136834">Õ„Õ«Õ¡ÖÕ¶Õ¥Õ¬ Õ¢Õ»Õ»Õ¡ÕµÕ«Õ¶ Õ«Õ¶Õ¿Õ¥Ö€Õ¶Õ¥Õ¿Õ¨ Õ¯Õ¡Õ´ Wi-Fi-Õ¨</translation>
<translation id="3715597595485130451">Ô¿Õ¡ÕºÕ¡Õ¯ÖÕ¾Õ¥Õ¬ Õ¡Õ¶Õ¬Õ¡Ö€ Õ¯Õ¡ÕºÕ«Õ¶</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />ÕÕ¿Õ¸Ö‚Õ£Õ¥Õ¬ ÕºÖ€Õ¸Ö„Õ½Õ«-Õ½Õ¥Ö€Õ¾Õ¥Ö€Õ«, Õ°Ö€Õ¡ÕºÕ¡Õ¿Õ« Ö‡ DNS-Õ« Õ¯Õ¡Õ¦Õ´Õ¡Õ±Ö‡Õ¸Ö‚Õ´Õ¨<ph name="END_LINK" /></translation>
-<translation id="372429172604983730">ÕÕ­Õ¡Õ¬Õ« ÕºÕ¡Õ¿Õ³Õ¡Õ¼ Õ¯Õ¡Ö€Õ¸Õ² Õ§ Õ¬Õ«Õ¶Õ¥Õ¬ Õ°Õ¡Õ¯Õ¡Õ¾Õ«Ö€Õ¸Ö‚Õ½Õ¡ÕµÕ«Õ¶ Õ®Ö€Õ¡Õ£Õ«Ö€Õ¨, Õ°Ö€Õ¡ÕºÕ¡Õ¿Õ¨, Õ¾Õ¥Õ¢ Õ¢Õ¸Õ¾Õ¡Õ¶Õ¤Õ¡Õ¯Õ¸Ö‚Õ©ÕµÕ¡Õ¶ Õ¦Õ¿Õ´Õ¡Õ¶ Õ¯Õ¡Õ´ Õ´Õ«Õ»Õ¶Õ¸Ö€Õ¤ Õ½Õ¥Ö€Õ¾Õ¥Ö€Õ« Õ®Ö€Õ¡Õ£Ö€Õ¥Ö€Õ¨:</translation>
+<translation id="372429172604983730">ÕÕ­Õ¡Õ¬Õ« ÕºÕ¡Õ¿Õ³Õ¡Õ¼ Õ¯Õ¡Ö€Õ¸Õ² Õ§ Õ¬Õ«Õ¶Õ¥Õ¬ Õ°Õ¡Õ¯Õ¡Õ¾Õ«Ö€Õ¸Ö‚Õ½Õ¡ÕµÕ«Õ¶ Õ®Ö€Õ¡Õ£Õ«Ö€Õ¨, Õ°Ö€Õ¡ÕºÕ¡Õ¿Õ¨, Õ¾Õ¥Õ¢ Õ¢Õ¸Õ¾Õ¡Õ¶Õ¤Õ¡Õ¯Õ¸Ö‚Õ©ÕµÕ¡Õ¶ Õ¦Õ¿Õ´Õ¡Õ¶ Õ¯Õ¡Õ´ ÕºÖ€Õ¸Ö„Õ½Õ« Õ½Õ¥Ö€Õ¾Õ¥Ö€Õ« Õ®Ö€Õ¡Õ£Ö€Õ¥Ö€Õ¨:</translation>
<translation id="3727101516080730231"><ph name="CREATE_GOOGLE_SLIDE_FOCUSED_FRIENDLY_MATCH_TEXT" />Ö‰ ÕÕ¬Õ¡ÕµÕ¤Õ¶Õ¥Ö€Õ¸Ö‚Õ´ Õ¡Ö€Õ¡Õ£ Google Õ¶Õ¥Ö€Õ¯Õ¡ÕµÕ¡ÖÕ¸Ö‚Õ´ Õ½Õ¿Õ¥Õ²Õ®Õ¥Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€ Õ½Õ¥Õ²Õ´Õ¥Ö„ Tab, Õ¡ÕºÕ¡Õ EnterÖ‰</translation>
<translation id="373042150751172459">B4 (Õ®Ö€Õ¡Ö€)</translation>
<translation id="3736520371357197498">ÔµÕ©Õ¥ Õ¤Õ¸Ö‚Ö„ Õ°Õ¡Õ½Õ¯Õ¡Õ¶Õ¸Ö‚Õ´ Õ¥Ö„ Õ±Õ¥Õ¦ Õ½ÕºÕ¡Õ¼Õ¶Õ¡ÖÕ¸Õ² Õ¾Õ¿Õ¡Õ¶Õ£Õ¨, Õ¡ÕºÕ¡ Õ¯Õ¡Ö€Õ¸Õ² Õ¥Ö„ Õ¶Õ¡Õ­Ö„Õ¡Õ¶ Õ¾Õ¿Õ¡Õ¶Õ£Õ¡Õ¾Õ¸Ö€ Õ®Ö€Õ¡Õ£Ö€Õ¥Ö€Õ« Õ°Õ¥Õ¼Õ¡ÖÕ¶Õ¥Õ¬Õ¨ <ph name="BEGIN_LINK" />Õ¡ÕµÖÕ¥Õ¬Õ¥Õ¬ Õ¡ÕµÕ½ Õ¸Õ¹ Õ¡ÕºÕ¡Õ°Õ¸Õ¾ Õ¯Õ¡ÕµÖ„Õ¨<ph name="END_LINK" />:</translation>
@@ -896,7 +927,7 @@
<translation id="3807873520724684969">ÕŽÕ¶Õ¡Õ½Õ¡Õ¢Õ¥Ö€ Õ¢Õ¸Õ¾Õ¡Õ¶Õ¤Õ¡Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶ Õ¡Ö€Õ£Õ¥Õ¬Õ¡ÖƒÕ¡Õ¯Õ¾Õ¡Õ® Õ§Ö‰</translation>
<translation id="3810973564298564668">Ô¿Õ¡Õ¼Õ¡Õ¾Õ¡Ö€Õ¥Õ¬</translation>
<translation id="3816482573645936981">Ô±Ö€ÕªÕ¥Ö„Õ¨ (ÖƒÕ¸Õ­Õ¡Ö€Õ«Õ¶Õ¾Õ¡Õ® Õ§)</translation>
-<translation id="382518646247711829">Եթե օգտագործում եք միջնորդ սերվեր…</translation>
+<translation id="382518646247711829">Եթե օգտագործում եք պրոքսի սերվեր…</translation>
<translation id="3827112369919217609">Ô²Õ¡ÖÕ¡Ö€Õ±Õ¡Õ¯</translation>
<translation id="3827475930221174051">Ô¸Õ½Õ¿ «<ph name="SEARCH_TERM" />» Õ°Õ¡Ö€ÖÕ´Õ¡Õ¶Õ¶ Õ¡Õ¼Õ¶Õ¹Õ¾Õ¸Õ² Õ£Õ¸Ö€Õ®Õ¸Õ²Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ« Õ¿Õ¾ÕµÕ¡Õ¬Õ¶Õ¥Ö€Õ«</translation>
<translation id="3828924085048779000">Ô±Õ¶ÖÕ¡Õ¢Õ¡Õ¼Õ« Õ¤Õ¡Õ·Õ¿Õ¨ Õ¹Õ« Õ¯Õ¡Ö€Õ¸Õ² Õ¤Õ¡Õ¿Õ¡Ö€Õ¯ Õ¬Õ«Õ¶Õ¥Õ¬:</translation>
@@ -921,6 +952,7 @@
<translation id="3906954721959377182">ÕŠÕ¬Õ¡Õ¶Õ·Õ¥Õ¿</translation>
<translation id="3909477809443608991"><ph name="URL" />-Õ¶ Õ¸Ö‚Õ¦Õ¸Ö‚Õ´ Õ§ Õ¶Õ¾Õ¡Õ£Õ¡Ö€Õ¯Õ¥Õ¬ ÕºÕ¡Õ·Õ¿ÕºÕ¡Õ¶Õ¾Õ¡Õ® Õ¢Õ¸Õ¾Õ¡Õ¶Õ¤Õ¡Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¨Ö‰ Google-Õ¨ Õ¯Õ½Õ¿Õ¸Ö‚Õ£Õ« Õ±Õ¥Ö€ Õ½Õ¡Ö€Ö„Õ¨, Ö‡ Õ¡ÕµÕ¶ Õ¯Õ¡Ö€Õ¸Õ² Õ§ Õ°Õ¡Õ½Õ¡Õ¶Õ¥Õ¬Õ« Õ¤Õ¡Õ¼Õ¶Õ¡Õ¬ Õ¡ÕµÕ½ Õ¯Õ¡ÕµÖ„Õ«Õ¶Ö‰</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">Õ„Õ¥Ö€ÕªÕ¥Õ¬</translation>
<translation id="3939773374150895049">Õ•Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¥ÕžÕ¬ WebAuthnÕ CVC-Õ« ÖƒÕ¸Õ­Õ¡Ö€Õ¥Õ¶</translation>
<translation id="3946209740501886391">Õ„Õ«Õ·Õ¿ Õ°Õ¡Ö€ÖÕ¶Õ¥Õ¬ Õ¡ÕµÕ½ Õ¯Õ¡ÕµÖ„Õ¸Ö‚Õ´</translation>
<translation id="3947595700203588284">Ô¿Õ¡Ö€Õ¸Õ² Õ§ Õ°Õ¡ÕµÖÕ¥Õ¬ MIDI Õ½Õ¡Ö€Ö„Õ¥Ö€Õ«Õ¶ Õ´Õ«Õ¡Õ¶Õ¡Õ¬Õ¸Ö‚ Õ©Õ¸Ö‚ÕµÕ¬Õ¿Õ¾Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶</translation>
@@ -942,6 +974,7 @@
<translation id="3990250421422698716">Ô±Õ½Õ¿Õ«Õ³Õ¡Õ¶Õ¡Õ¯Õ¡Õ¶ Õ¿Õ¥Õ²Õ¡Õ·Õ¡Ö€Õª</translation>
<translation id="3996311196211510766"><ph name="ORIGIN" /> Õ¯Õ¡ÕµÖ„Õ¨ ÕºÕ¡Õ°Õ¡Õ¶Õ»Õ¸Ö‚Õ´ Õ§, Õ¸Ö€ Õ½Õ¯Õ¦Õ¢Õ¶Õ¡Õ¯Õ¡Õ¶ Õ¯Õ¡Õ¶Õ¸Õ¶Õ¨
Õ¯Õ«Ö€Õ¡Õ¼Õ¾Õ« Õ«Ö€ Õ¢Õ¸Õ¬Õ¸Ö€ Õ°Õ¡Ö€ÖÕ¸Ö‚Õ´Õ¶Õ¥Ö€Õ« Õ¶Õ¯Õ¡Õ¿Õ´Õ¡Õ´Õ¢, Õ¢Õ¡ÕµÖ Õ¡ÕµÕ½ Õ¯Õ¡Õ¶Õ¸Õ¶Õ¶ Õ¡ÕµÕªÕ´ Õ°Õ¶Õ¡Ö€Õ¡Õ¾Õ¸Ö€ Õ¹Õ§ Õ¯Õ«Ö€Õ¡Õ¼Õ¥Õ¬Ö‰</translation>
+<translation id="4009243425692662128">ÕÕ¥Ö€ Õ¿ÕºÕ¡Õ® Õ§Õ»Õ¥Ö€Õ« Õ¢Õ¸Õ¾Õ¡Õ¶Õ¤Õ¡Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¨ Õ¾Õ¥Ö€Õ¬Õ¸Ö‚Õ®Õ¸Ö‚Õ©ÕµÕ¡Õ¶ Õ¶ÕºÕ¡Õ¿Õ¡Õ¯Õ¸Õ¾ Õ¸Ö‚Õ²Õ¡Ö€Õ¯Õ¾Õ¸Ö‚Õ´ Õ§ Google Cloud Õ¯Õ¡Õ´ Õ¥Ö€Ö€Õ¸Ö€Õ¤ Õ¯Õ¸Õ²Õ´Õ¥Ö€Õ«Ö‰ Õ•Ö€Õ«Õ¶Õ¡Õ¯Õ Õ¯Õ¡Ö€Õ¸Õ² Õ§ Õ½Õ¿Õ¸Ö‚Õ£Õ¾Õ¥Õ¬ Õ£Õ¡Õ²Õ¿Õ¶Õ« Õ¿Õ¾ÕµÕ¡Õ¬Õ¶Õ¥Ö€Õ« Õ¡Õ¼Õ¯Õ¡ÕµÕ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¨Ö‰</translation>
<translation id="4010758435855888356">Ô¹Õ¸Ö‚ÕµÕ¬Õ¡Õ¿Ö€Õ¥ÕžÕ¬ Õ°Õ«Õ·Õ¸Õ²Õ¸Ö‚Õ©ÕµÕ¡Õ¶ Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¸Ö‚Õ´Õ¨</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{{COUNT}-Õ§Õ»Õ¡Õ¶Õ¸Ö PDF ÖƒÕ¡Õ½Õ¿Õ¡Õ©Õ¸Ö‚Õ²Õ©}one{{COUNT}-Õ§Õ»Õ¡Õ¶Õ¸Ö PDF ÖƒÕ¡Õ½Õ¿Õ¡Õ©Õ¸Ö‚Õ²Õ©}other{{COUNT}-Õ§Õ»Õ¡Õ¶Õ¸Ö PDF ÖƒÕ¡Õ½Õ¿Õ¡Õ©Õ¸Ö‚Õ²Õ©}}</translation>
<translation id="4023431997072828269">Õ”Õ¡Õ¶Õ« Õ¸Ö€ Õ¡ÕµÕ½ Õ±Ö‡Õ¨ Õ¸Õ¹ Õ¡ÕºÕ¡Õ°Õ¸Õ¾ Õ¯Õ¡Õº Õ§ Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¸Ö‚Õ´, Õ±Õ¥Ö€ Õ¿Õ¥Õ²Õ¥Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¨ Õ¿Õ¥Õ½Õ¡Õ¶Õ¥Õ¬Õ« Õ¯Õ¬Õ«Õ¶Õ¥Õ¶ Õ¢Õ¸Õ¬Õ¸Ö€Õ«Õ¶Ö‰</translation>
@@ -1036,6 +1069,7 @@
<translation id="4250680216510889253">ÕˆÕ¹</translation>
<translation id="4253168017788158739">Õ†Õ·Õ¸Ö‚Õ´</translation>
<translation id="425582637250725228">ÕÕ¥Ö€ Õ¯Õ¡Õ¿Õ¡Ö€Õ¡Õ® ÖƒÕ¸ÖƒÕ¸Õ­Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¨ Õ°Õ¶Õ¡Ö€Õ¡Õ¾Õ¸Ö€ Õ§ Õ¹ÕºÕ¡Õ°ÕºÕ¡Õ¶Õ¾Õ¥Õ¶Ö‰</translation>
+<translation id="425869179292622354">ÕˆÖ‚Õ¦Õ¸ÕžÖ‚Õ´ Õ¥Ö„, Õ¸Ö€ Õ¡ÕµÕ¶ Õ¡Õ¾Õ¥Õ¬Õ« Õ¡ÕºÕ¡Õ°Õ¸Õ¾ Õ¬Õ«Õ¶Õ« Õ¾Õ«Ö€Õ¿Õ¸Ö‚Õ¡Õ¬ Ö„Õ¡Ö€Õ¿Õ« Õ·Õ¶Õ¸Ö€Õ°Õ«Õ¾</translation>
<translation id="4258748452823770588">ÕÕ­Õ¡Õ¬ Õ½Õ¿Õ¸Ö€Õ¡Õ£Ö€Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶</translation>
<translation id="4261046003697461417">ÕŠÕ¡Õ·Õ¿ÕºÕ¡Õ¶Õ¾Õ¡Õ® ÖƒÕ¡Õ½Õ¿Õ¡Õ©Õ²Õ©Õ¥Ö€Õ¸Ö‚Õ´ Õ°Õ¶Õ¡Ö€Õ¡Õ¾Õ¸Ö€ Õ¹Õ§ Õ®Õ¡Õ¶Õ¸Õ©Õ¡Õ£Ö€Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶ Õ¡Õ¾Õ¥Õ¬Õ¡ÖÕ¶Õ¥Õ¬</translation>
<translation id="4265872034478892965">Ô¹Õ¸Ö‚ÕµÕ¬Õ¡Õ¿Ö€Õ¾Õ¥Õ¬ Õ§ Õ±Õ¥Ö€ Õ¡Õ¤Õ´Õ«Õ¶Õ«Õ½Õ¿Ö€Õ¡Õ¿Õ¸Ö€Õ« Õ¯Õ¸Õ²Õ´Õ«Ö</translation>
@@ -1098,6 +1132,7 @@
<translation id="4434045419905280838">ÔµÕ¬Õ¶Õ¸Õ² ÕºÕ¡Õ¿Õ¸Ö‚Õ°Õ¡Õ¶Õ¶Õ¥Ö€ Ö‡ Õ¾Õ¥Ö€Õ¡Õ°Õ²Õ¸Ö‚Õ´</translation>
<translation id="4435702339979719576">Postcard)</translation>
<translation id="443673843213245140">ÕŠÖ€Õ¸Ö„Õ½Õ«-Õ½Õ¥Ö€Õ¾Õ¥Ö€Õ« Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¸Ö‚Õ´Õ¶ Õ¡Õ¶Õ»Õ¡Õ¿Õ¾Õ¡Õ® Õ§, Õ¢Õ¡ÕµÖ Õ°Õ¡Õ¿Õ¯Õ¸Ö€Õ¸Õ·Õ¾Õ¡Õ® Õ§ Õ¸Ö‚Õ²Õ²Õ¡Õ¯Õ« Õ¯Õ¡Õ¦Õ´Õ¡Õ±Ö‡Õ¸Ö‚Õ´:</translation>
+<translation id="4441832193888514600">Ô±Õ¶Õ¿Õ¥Õ½Õ¾Õ¸Ö‚Õ´ Õ§, Ö„Õ¡Õ¶Õ« Õ¸Ö€ Õ¡ÕµÕ½ Õ¯Õ¡Õ¶Õ¸Õ¶Õ¨ Õ¯Õ¡Ö€Õ¥Õ¬Õ« Õ§ Õ¯Õ¡Ö€Õ£Õ¡Õ¾Õ¸Ö€Õ¥Õ¬ Õ´Õ«Õ¡ÕµÕ¶ Õ¡Õ´ÕºÕ« Õ´Õ¡Õ¯Õ¡Ö€Õ¤Õ¡Õ¯Õ¸Ö‚Õ´Ö‰</translation>
<translation id="4450893287417543264">Ô±ÕµÕ¬Ö‡Õ½ ÖÕ¸Ö‚ÕµÖ Õ¹Õ¿Õ¡Õ¬</translation>
<translation id="4451135742916150903">Ô¿Õ¡Ö€Õ¸Õ² Õ§ Õ°Õ¡ÕµÖÕ¥Õ¬ HID Õ½Õ¡Ö€Ö„Õ¥Ö€Õ«Õ¶ Õ´Õ«Õ¡Õ¶Õ¡Õ¬Õ¸Ö‚ Õ©Õ¸Ö‚ÕµÕ¬Õ¿Õ¾Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶</translation>
<translation id="4452328064229197696">Ô³Õ¡Õ²Õ¿Õ¶Õ¡Õ¢Õ¡Õ¼Õ¨, Õ¸Ö€ Õ°Õ¥Õ¶Ö Õ¶Õ¸Ö€ Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¥ÖÕ«Ö„, Õ¯Õ¸Õ¿Ö€Õ¾Õ¥Õ¬ Õ§ Õ¿Õ¾ÕµÕ¡Õ¬Õ¶Õ¥Ö€Õ« Õ¡Ö€Õ¿Õ¡Õ°Õ¸Õ½Ö„Õ« ÕºÕ¡Õ¿Õ³Õ¡Õ¼Õ¸Õ¾Ö‰ ÕÕ¥Ö€ Õ°Õ¡Õ·Õ«Õ¾Õ¶Õ¥Ö€Õ¨ ÕºÕ¡Õ·Õ¿ÕºÕ¡Õ¶Õ¥Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€ Google Ô³Õ¡Õ²Õ¿Õ¶Õ¡Õ¢Õ¡Õ¼Õ¥Ö€Õ« Õ¯Õ¡Õ¼Õ¡Õ¾Õ¡Ö€Õ«Õ¹Õ¨ Õ­Õ¸Ö€Õ°Õ¸Ö‚Ö€Õ¤ Õ§ Õ¿Õ¡Õ¬Õ«Õ½ Õ½Õ¿Õ¸Ö‚Õ£Õ¥Õ¬ ÕºÕ¡Õ°Õ¾Õ¡Õ® Õ£Õ¡Õ²Õ¿Õ¶Õ¡Õ¢Õ¡Õ¼Õ¥Ö€Õ¨Ö‰</translation>
@@ -1153,6 +1188,7 @@
<translation id="4628948037717959914">Ô¼Õ¸Ö‚Õ½Õ¡Õ¶Õ¯Õ¡Ö€</translation>
<translation id="4631649115723685955">Õ”Õ¥Õ·Õ¢Õ¥Ö„Õ¸Õ¾</translation>
<translation id="4636930964841734540">ÕÕ¥Õ²Õ¥Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€</translation>
+<translation id="4638670630777875591">Ô»Õ¶Õ¯Õ¸Õ£Õ¶Õ«Õ¿Õ¸ Õ¼Õ¥ÕªÕ«Õ´Õ¨ Chromium-Õ¸Ö‚Õ´</translation>
<translation id="464342062220857295">ÕˆÖ€Õ¸Õ¶Õ´Õ¡Õ¶ Õ£Õ¸Ö€Õ®Õ¡Õ¼Õ¸Ö‚ÕµÕ©Õ¶Õ¥Ö€</translation>
<translation id="4644670975240021822">Õ€Õ¡Õ¯Õ¡Õ¼Õ¡Õ¯ Õ°Õ¥Ö€Õ©Õ¡Õ¯Õ¡Õ¶Õ¸Ö‚Õ©ÕµÕ¡Õ´Õ¢Õ Õ¥Ö€Õ¥Õ½Õ« Õ¯Õ¸Õ²Õ´Õ¸Õ¾ Õ¶Õ¥Ö€Ö„Ö‡</translation>
<translation id="4646534391647090355">Ô±Õ¶ÖÕ¶Õ¥Õ¬ Õ°Õ«Õ´Õ¡</translation>
@@ -1173,6 +1209,7 @@
<translation id="4708268264240856090">ÕÕ¥Ö€ Õ¯Õ¡ÕºÕ¶ Õ¨Õ¶Õ¤Õ°Õ¡Õ¿Õ¾Õ¥Õ¬ Õ§</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Ô³Õ¸Ö€Õ®Õ¡Ö€Õ¯Õ¥Õ¬ Windows-Õ« ÖÕ¡Õ¶ÖÕ« Õ¡Õ­Õ¿Õ¸Ö€Õ¸Õ·Õ¸Ö‚Õ´Õ¨<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426">Ô³Õ¡Õ²Õ¿Õ¶Õ¡Õ¢Õ¡Õ¼ <ph name="USERNAME" />-Õ« Õ°Õ¡Õ´Õ¡Ö€</translation>
<translation id="4724144314178270921">Ô¿Õ¡Ö€Õ¸Õ² Õ§ Õ°Õ¡ÕµÖÕ¥Õ¬ Õ½Õ¥Õ²Õ´Õ¡Õ¿Õ¡Õ­Õ¿Õ¡Õ¯Õ«Õ¶ ÕºÕ¡Õ¿Õ³Õ¥Õ¶Õ¾Õ¡Õ® Õ¿Õ¥Ö„Õ½Õ¿Õ¶ Õ¸Ö‚ ÕºÕ¡Õ¿Õ¯Õ¥Ö€Õ¶Õ¥Ö€Õ¨ Õ¤Õ«Õ¿Õ¥Õ¬Õ¸Ö‚ Õ©Õ¸Ö‚ÕµÕ¬Õ¿Õ¾Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶</translation>
<translation id="4726672564094551039">ÕŽÕ¥Ö€Õ¡Õ¢Õ¥Õ¼Õ¶Õ¥Õ¬ Õ¯Õ¡Õ¶Õ¸Õ¶Õ¶Õ¥Ö€Õ¨</translation>
<translation id="4728558894243024398">Õ€Õ¥Õ¶Ö„</translation>
@@ -1194,6 +1231,7 @@
<translation id="4757993714154412917">Ô´Õ¸Ö‚Ö„ Õ°Õ¥Õ¶Ö Õ¶Õ¸Ö€ Õ´Õ¸Ö‚Õ¿Ö„Õ¡Õ£Ö€Õ¥ÖÕ«Ö„ Õ±Õ¥Ö€ Õ£Õ¡Õ²Õ¿Õ¶Õ¡Õ¢Õ¡Õ¼Õ¨ Õ¯Õ¡Õ½Õ¯Õ¡Õ®Õ¥Õ¬Õ« Õ¯Õ¡ÕµÖ„Õ¸Ö‚Õ´Ö‰ ÕÕ¥Ö€ Õ°Õ¡Õ·Õ«Õ¾Õ¶Õ¥Ö€Õ« ÕºÕ¡Õ·Õ¿ÕºÕ¡Õ¶Õ¸Ö‚Õ©ÕµÕ¡Õ¶ Õ¶Õ¯Õ¡Õ¿Õ¡Õ¼Õ¸Ö‚Õ´Õ¶Õ¥Ö€Õ¸Õ¾Õ Chrome-Õ¨ Õ­Õ¸Ö€Õ°Õ¸Ö‚Ö€Õ¤ Õ§ Õ¿Õ¡Õ¬Õ«Õ½ Õ¡Õ¶Õ°Õ¡ÕºÕ¡Õ² Õ½Õ¿Õ¸Ö‚Õ£Õ¥Õ¬ ÕºÕ¡Õ°Õ¾Õ¡Õ® Õ£Õ¡Õ²Õ¿Õ¶Õ¡Õ¢Õ¡Õ¼Õ¥Ö€Õ« Õ¡Õ¶Õ¾Õ¿Õ¡Õ¶Õ£Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¨Ö‰</translation>
<translation id="4758311279753947758">Ô±Õ¾Õ¥Õ¬Õ¡ÖÕ¶Õ¥Õ¬ Õ¯Õ¸Õ¶Õ¿Õ¡Õ¯Õ¿Õ¡ÕµÕ«Õ¶ Õ¿Õ¾ÕµÕ¡Õ¬Õ¶Õ¥Ö€</translation>
<translation id="4761104368405085019">Õ•Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¥Õ¬ Õ­Õ¸Õ½Õ¡ÖƒÕ¸Õ²Õ¨</translation>
+<translation id="4761869838909035636">Ô±Õ¶ÖÕ¶Õ¥Õ¬ Chrome-Õ« Õ¡Õ¶Õ¾Õ¿Õ¡Õ¶Õ£Õ¸Ö‚Õ©ÕµÕ¡Õ¶ Õ½Õ¿Õ¸Ö‚Õ£Õ¸Ö‚Õ´</translation>
<translation id="4764776831041365478">Õ€Õ¶Õ¡Ö€Õ¡Õ¾Õ¸Ö€ Õ§, <ph name="URL" />-Õ« Õ¾Õ¥Õ¢Õ§Õ»Õ¨ ÕªÕ¡Õ´Õ¡Õ¶Õ¡Õ¯Õ¡Õ¾Õ¸Ö€Õ¡ÕºÕ¥Õ½ Õ®Õ¡Õ¶Ö€Õ¡Õ¢Õ¥Õ¼Õ¶Õ¾Õ¡Õ® Õ§ Õ¯Õ¡Õ´ Õ´Õ·Õ¿Õ¡ÕºÕ¥Õ½ Õ¿Õ¥Õ²Õ¡ÖƒÕ¸Õ­Õ¾Õ¥Õ¬ Õ§ Õ¶Õ¸Ö€ Õ°Õ¡Õ½ÖÕ¥Õ¸Õ¾:</translation>
<translation id="4766713847338118463">ÔµÖ€Õ¯Õ¸Ö‚ Õ¡Õ´Ö€Õ¡Õ¯ Õ¶Õ¥Ö€Ö„Ö‡Õ¸Ö‚Õ´</translation>
<translation id="4771973620359291008">Ô±Õ¶Õ°Õ¡ÕµÕ¿ Õ½Õ­Õ¡Õ¬ Õ§ Õ¿Õ¥Õ²Õ« Õ¸Ö‚Õ¶Õ¥ÖÕ¥Õ¬:</translation>
@@ -1214,12 +1252,6 @@
<translation id="4819347708020428563">Ô½Õ´Õ¢Õ¡Õ£Ö€Õ¥ÕžÕ¬ Õ®Õ¡Õ¶Õ¸Õ©Õ¡Õ£Ö€Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¨ Õ¯Õ¡Õ¶Õ­Õ¡Õ¤Ö€Õ¾Õ¡Õ® Õ¤Õ«Õ¿Õ¡Õ¯Õ¥Ö€ÕºÕ¸Ö‚Õ´</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />Ö‰ Ô±Ö€Õ¡Õ£ Google Õ¡Õ²ÕµÕ¸Ö‚Õ½Õ¡Õ¯ Õ½Õ¿Õ¥Õ²Õ®Õ¥Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€ Õ½Õ¥Õ²Õ´Õ¥Ö„ Tab, Õ¡ÕºÕ¡Õ EnterÖ‰</translation>
<translation id="4825507807291741242">Õ€Õ¦Õ¸Ö€</translation>
-<translation id="4827402517081186284">Ô»Õ¶Õ¯Õ¸Õ£Õ¶Õ«Õ¿Õ¸ Õ¼Õ¥ÕªÕ«Õ´Õ¨ Õ¹Õ« Õ¯Õ¡Ö€Õ¸Õ² Õ±Õ¥Õ¦ Õ¬Õ«Õ¸Õ¾Õ«Õ¶ Õ¡Õ¶Õ¿Õ¥Õ½Õ¡Õ¶Õ¥Õ¬Õ« Õ¤Õ¡Ö€Õ±Õ¶Õ¥Õ¬ Õ°Õ¡Õ´Õ¡ÖÕ¡Õ¶Öում․
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Ô¿Õ¡ÕµÖ„Õ¥Ö€Õ¨ Õ¿Õ¥Õ²Õ¥Õ¯Õ¡Õ¶Õ¸Ö‚Õ´ Õ¥Õ¶ Õ±Õ¥Ö€ Õ¡ÕµÖÕ¥Õ¬Õ¸Ö‚Õ©ÕµÕ¡Õ¶ Õ´Õ¡Õ½Õ«Õ¶<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Ô³Õ¸Ö€Õ®Õ¡Õ¿Õ¸Ö‚Õ¶Õ¥Ö€Õ¨ Ö‡ Õ¸Ö‚Õ½Õ¸Ö‚Õ´Õ¶Õ¡Õ¯Õ¡Õ¶ Õ°Õ¡Õ½Õ¿Õ¡Õ¿Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¨ Õ¯Õ¡Ö€Õ¸Õ² Õ¥Õ¶ Õ°Õ¥Õ¿Õ¡Õ£Õ®Õ¥Õ¬ Õ£Õ¸Ö€Õ®Õ¸Õ²Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¨ Õ¤Õ«Õ¿Õ¡Ö€Õ¯Õ«Õ¹Õ¸Ö‚Õ´<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Ô»Õ¶Õ¿Õ¥Ö€Õ¶Õ¥Õ¿ ÕºÖ€Õ¸Õ¾Õ¡ÕµÕ¤Õ¥Ö€Õ¶Õ¥Ö€Õ¨ Õ¯Õ¡Ö€Õ¸Õ² Õ¥Õ¶ Õ°Õ¥Õ¿Ö‡Õ¥Õ¬ Õ¾Õ¥Õ¢ Õ©Ö€Õ¡Ö†Õ«Õ¯Õ«Õ¶<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">Õ„Õ«Õ¡ÖÕ¶Õ¥Õ¬ Õ¦Õ£Õ¸Ö‚Õ·Õ¡ÖÕ¸Ö‚Õ´Õ¶Õ¥Ö€Õ¨</translation>
<translation id="4838327282952368871">ÔµÖ€Õ¡Õ¦Õ¡ÕµÕ«Õ¶</translation>
<translation id="4840250757394056958">Ô´Õ«Õ¿Õ¥Õ¬ Chrome-Õ« ÕºÕ¡Õ¿Õ´Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¨</translation>
@@ -1231,12 +1263,12 @@
<translation id="4854362297993841467">Ô±Õ¼Õ¡Ö„Õ´Õ¡Õ¶ Õ¿Õ¾ÕµÕ¡Õ¬ Õ¥Õ²Õ¡Õ¶Õ¡Õ¯Õ¨ Õ°Õ¡Õ½Õ¡Õ¶Õ¥Õ¬Õ« Õ¹Õ§: Ô¸Õ¶Õ¿Ö€Õ¥Ö„ Õ¡ÕµÕ¬ Õ¥Õ²Õ¡Õ¶Õ¡Õ¯:</translation>
<translation id="4854853140771946034">Ô±Ö€Õ¡Õ£ Õ½Õ¿Õ¥Õ²Õ®Õ¥Õ¬ Õ¶Õ·Õ¸Ö‚Õ´ Google Keep-Õ¸Ö‚Õ´</translation>
<translation id="485902285759009870">Կոդը ստուգվում է…</translation>
+<translation id="4866506163384898554">Õ†Õ·Õ¸Ö€Õ¤Õ¨ ÖÕ¸Ö‚ÕµÖ Õ¿Õ¡Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€ Õ½Õ¥Õ²Õ´Õ¥Ö„ |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />|</translation>
<translation id="4876188919622883022">ÕŠÕ¡Ö€Õ¦Õ¥ÖÕ¾Õ¡Õ® Õ¤Õ«Õ¿Õ¡Õ¯Õ¥Ö€Õº</translation>
<translation id="4876305945144899064">Õ•Õ£Õ¿Õ¡Õ¶Õ¸Ö‚Õ¶Õ¨ Õ¶Õ·Õ¾Õ¡Õ® Õ¹Õ§</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{Õ‰Õ¯Õ¡}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}one{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831">Որոնել «<ph name="TEXT" />»</translation>
<translation id="4879491255372875719">Ô±Õ¾Õ¿Õ¸Õ´Õ¡Õ¿ (Õ¯Õ¡Õ¶Õ­Õ¡Õ¤Ö€Õ¾Õ¡Õ®)</translation>
-<translation id="4879725228911483934">Ô²Õ¡ÖÕ¥Õ¬ Ö‡ Õ¿Õ¥Õ²Õ¡Õ¯Õ¡ÕµÕ¥Õ¬ ÕºÕ¡Õ¿Õ¸Ö‚Õ°Õ¡Õ¶Õ¶Õ¥Ö€Õ¨ Õ±Õ¥Ö€ Õ§Õ¯Ö€Õ¡Õ¶Õ¶Õ¥Ö€Õ«Õ¶</translation>
<translation id="4880827082731008257">ÕˆÖ€Õ¸Õ¶Õ¥Õ¬ ÕºÕ¡Õ¿Õ´Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¸Ö‚Õ´</translation>
<translation id="4881695831933465202">Ô²Õ¡ÖÕ¥Õ¬</translation>
<translation id="4885256590493466218">ÕŽÕ³Õ¡Ö€Õ¥Ö„ <ph name="CARD_DETAIL" /> Ö„Õ¡Ö€Õ¿Õ« Õ´Õ«Õ»Õ¸ÖÕ¸Õ¾</translation>
@@ -1245,6 +1277,7 @@
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">Ô»Õ¶Õ¶Õ¥Ö€Õ¸Ö€Õ¤ Õ£Õ¬Õ¡Õ¶Õ¡ÖƒÕ¡Õ©Õ¥Õ©</translation>
<translation id="4901778704868714008">Պահել…</translation>
+<translation id="4905659621780993806">Ô±Õ¤Õ´Õ«Õ¶Õ«Õ½Õ¿Ö€Õ¡Õ¿Õ¸Ö€Õ¶ Õ¡Õ¾Õ¿Õ¸Õ´Õ¡Õ¿ Õ¯Õ¾Õ¥Ö€Õ¡Õ£Õ¸Ö€Õ®Õ¡Ö€Õ¯Õ« Õ½Õ¡Ö€Ö„Õ¨Õ <ph name="DATE" />, <ph name="TIME" />Ö‰ ÕŠÕ¡Õ°Õ¥Ö„ Õ¢Õ¸Õ¬Õ¸Ö€ Õ¢Õ¡ÖÕ¾Õ¡Õ® Õ¿Õ¡Ö€Ö€Õ¥Ö€Õ¨ Õ´Õ«Õ¶Õ¹Ö‡ Õ½Õ¡Ö€Ö„Õ« Õ¾Õ¥Ö€Õ¡Õ£Õ¸Ö€Õ®Õ¡Ö€Õ¯Õ¸Ö‚Õ´Õ¨Ö‰</translation>
<translation id="4913987521957242411">Ô±Õ¶ÖÖ„ Õ¾Õ¥Ö€Ö‡Õ« Õ±Õ¡Õ­ Õ¯Õ¸Õ²Õ´Õ¸Ö‚Õ´</translation>
<translation id="4918221908152712722">ÕÕ¥Õ²Õ¡Õ¤Ö€Õ¥Ö„ <ph name="APP_NAME" /> Õ°Õ¡Õ¾Õ¥Õ¬Õ¾Õ¡Õ®Õ¨ (Õ¶Õ¥Ö€Õ¢Õ¥Õ¼Õ¶Õ¸Ö‚Õ´ Õ¹Õ« ÕºÕ¡Õ°Õ¡Õ¶Õ»Õ¾Õ¸Ö‚Õ´)</translation>
<translation id="4923459931733593730">ÕŽÕ³Õ¡Ö€Õ¸Ö‚Õ´</translation>
@@ -1253,6 +1286,7 @@
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />Ö‰ ÕˆÖ€Õ¸Õ¶Õ¥Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€ Õ½Õ¥Õ²Õ´Õ¥Ö„ Tab, Õ¡ÕºÕ¡Õ Enter</translation>
<translation id="4930153903256238152">Õ„Õ¥Õ® Õ¿Õ¡Ö€Õ¸Õ²Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶</translation>
+<translation id="4940163644868678279">Ô»Õ¶Õ¯Õ¸Õ£Õ¶Õ«Õ¿Õ¸ Õ¼Õ¥ÕªÕ«Õ´Õ¨ Chrome-Õ¸Ö‚Õ´</translation>
<translation id="4943872375798546930">Ô±Ö€Õ¤ÕµÕ¸Ö‚Õ¶Ö„Õ¶Õ¥Ö€ Õ¹Õ¯Õ¡Õ¶</translation>
<translation id="4950898438188848926">Õ†Õ¥Ö€Õ¤Õ«Ö€Õ¶Õ¥Ö€Õ« Õ´Õ«Õ»Ö‡ Õ¡Õ¶ÖÕ´Õ¡Õ¶ Õ¯Õ¸Õ³Õ¡Õ¯Ö‰ Ô²Õ¡ÖÕ¾Õ¡Õ® Õ¶Õ¥Ö€Õ¤Õ«Ö€Õ«Õ¶ (<ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" />) Õ¡Õ¶ÖÕ¶Õ¥Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€ Õ½Õ¥Õ²Õ´Õ¥Ö„ «Enter»։</translation>
<translation id="495170559598752135">Ô³Õ¸Ö€Õ®Õ¸Õ²Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€</translation>
@@ -1263,6 +1297,7 @@
<translation id="4969341057194253438">Õ‹Õ¶Õ»Õ¥Õ¬ Õ¿Õ¥Õ½Õ¡Õ£Ö€Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¨
</translation>
<translation id="4973922308112707173">ÔµÖ€Õ¯Õ¸Ö‚ Õ¡Õ¶ÖÖ„ Õ¾Õ¥Ö€Ö‡Õ¸Ö‚Õ´</translation>
+<translation id="4976702386844183910">ÕŽÕ¥Ö€Õ»Õ«Õ¶ Õ¡ÕµÖÕ¥Õ¬Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¨Õ <ph name="DATE" /></translation>
<translation id="4984088539114770594">Õ•Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¥ÕžÕ¬ Õ­Õ¸Õ½Õ¡ÖƒÕ¸Õ²Õ¨</translation>
<translation id="4984339528288761049">Prc5 (Õ®Ö€Õ¡Ö€)</translation>
<translation id="4989163558385430922">ÕÕ¥Õ½Õ¶Õ¥Õ¬ Õ¢Õ¸Õ¬Õ¸Ö€Õ¨</translation>
@@ -1324,6 +1359,7 @@
<translation id="5138227688689900538">Õ‘Õ¸Ö‚ÕµÖ Õ¿Õ¡Õ¬ Õ¡Õ¾Õ¥Õ¬Õ« Ö„Õ«Õ¹</translation>
<translation id="5145883236150621069">Õ”Õ¡Õ²Õ¡Ö„Õ¡Õ¯Õ¡Õ¶Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶ Õ½Õ¿Õ¸Ö‚Õ£Õ¥Õ¬Õ«Õ½ Õ½Õ­Õ¡Õ¬Õ« Õ¯Õ¸Õ¤ Õ§ Õ¾Õ¥Ö€Õ¡Õ¤Õ¡Ö€Õ±Õ¾Õ¥Õ¬</translation>
<translation id="5146995429444047494"><ph name="ORIGIN" /> Õ¯Õ¡ÕµÖ„Õ« Õ®Õ¡Õ¶Õ¸Ö‚ÖÕ¸Ö‚Õ´Õ¶Õ¥Ö€Õ¶ Õ¡Ö€Õ£Õ¥Õ¬Õ¡ÖƒÕ¡Õ¯Õ¾Õ¡Õ® Õ¥Õ¶</translation>
+<translation id="514704532284964975">Ô¿Õ¡ÕµÖ„Õ«Õ¶ (<ph name="URL" />) Õ¡Õ¶Õ°Ö€Õ¡ÕªÕ¥Õ·Õ¿ Õ§ Õ¿Õ¥Õ½Õ¶Õ¥Õ¬ Ö‡ ÖƒÕ¸ÖƒÕ¸Õ­Õ¥Õ¬ Õ¿Õ¥Õ²Õ¥Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¨ NFC Õ½Õ¡Ö€Ö„Õ¥Ö€Õ¸Ö‚Õ´, Õ¸Ö€Õ¸Õ¶Ö Õ°ÕºÕ¸Ö‚Õ´ Õ¥Ö„ Õ±Õ¥Ö€ Õ°Õ¥Õ¼Õ¡Õ­Õ¸Õ½Õ¸Õ¾</translation>
<translation id="5148809049217731050">ÔµÖ€Õ¥Õ½Õ« Õ¯Õ¸Õ²Õ´Õ¸Õ¾ Õ¾Õ¥Ö€Ö‡</translation>
<translation id="515292512908731282">C4 (Õ®Ö€Õ¡Ö€)</translation>
<translation id="5158275234811857234">Õ‡Õ¡ÕºÕ«Õ¯</translation>
@@ -1348,6 +1384,7 @@
<translation id="5215116848420601511">ÕŽÕ³Õ¡Ö€Õ´Õ¡Õ¶ Õ¥Õ²Õ¡Õ¶Õ¡Õ¯Õ¶Õ¥Ö€ Õ¸Ö‚ Õ°Õ¡Õ½ÖÕ¥Õ¶Õ¥Ö€ Google Pay-Õ«Ö</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">Ô´Õ¡Ö€Õ¡Õ¯ 13</translation>
+<translation id="5216942107514965959">ÕŽÕ¥Ö€Õ»Õ«Õ¶ Õ¡ÕµÖÕ¥Õ¬Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¨Õ Õ¡ÕµÕ½Ö…Ö€</translation>
<translation id="5222812217790122047">Էլ․ Õ°Õ¡Õ½ÖÕ¥Õ¶ ÕºÕ¡Ö€Õ¿Õ¡Õ¤Õ«Ö€ Õ§</translation>
<translation id="5230733896359313003">Ô±Õ¼Õ¡Ö„Õ´Õ¡Õ¶ Õ°Õ¡Õ½ÖÕ¥</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1368,7 +1405,6 @@
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">Õ“Õ¡Õ½Õ¿Õ¡Õ©Õ²Õ©Õ« ÕºÕ¡Ö€Õ¡Õ´Õ¥Õ¿Ö€Õ¥Ö€</translation>
<translation id="528468243742722775">ÕŽÕ¥Ö€Õ»</translation>
-<translation id="5284909709419567258">Õ‘Õ¡Õ¶ÖÕ¡ÕµÕ«Õ¶ Õ°Õ¡Õ½ÖÕ¥Õ¶Õ¥Ö€</translation>
<translation id="5285570108065881030">Õ‘Õ¸Ö‚ÖÕ¡Õ¤Ö€Õ¥Õ¬ Õ¢Õ¸Õ¬Õ¸Ö€ ÕºÕ¡Õ°Õ¾Õ¡Õ® Õ£Õ¡Õ²Õ¿Õ¶Õ¡Õ¢Õ¡Õ¼Õ¥Ö€Õ¨</translation>
<translation id="5287240709317226393">Õ‘Õ¸Ö‚ÕµÖ Õ¿Õ¡Õ¬ Ö„Õ¸Ö‚Ö„Õ«Õ¶Õ¥Ö€Õ¨</translation>
<translation id="5287456746628258573">Ô±ÕµÕ½ Õ¯Õ¡ÕµÖ„Õ¶ Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¸Ö‚Õ´ Õ§ Õ¡Õ¶Õ¾Õ¿Õ¡Õ¶Õ£Õ¸Ö‚Õ©ÕµÕ¡Õ¶ Õ°Õ¶Õ¡ÖÕ¡Õ® Õ¯Õ¡Õ¦Õ´Õ¡Õ±Ö‡Õ¸Ö‚Õ´, Õ«Õ¶Õ¹Õ« Õ°Õ¥Õ¿Ö‡Õ¡Õ¶Ö„Õ¸Õ¾ Õ±Õ¥Ö€ Õ¿Õ¥Õ²Õ¥Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¨ (Ö…Ö€.` Õ£Õ¡Õ²Õ¿Õ¶Õ¡Õ¢Õ¡Õ¼Õ¥Ö€Õ¨ Õ¯Õ¡Õ´ Õ¾Õ¡Ö€Õ¯Õ¡ÕµÕ«Õ¶ Ö„Õ¡Ö€Õ¿Õ« Õ¿Õ¾ÕµÕ¡Õ¬Õ¶Õ¥Ö€Õ¨) Õ¡ÕµÕ½ Õ¯Õ¡ÕµÖ„Õ¸Ö‚Õ´ Õ¬Ö€Õ¡ÖÕ¶Õ¥Õ¬Õ«Õ½ Õ¯Õ¡Ö€Õ¸Õ² Õ¥Õ¶ Õ¢Õ¡ÖÕ¡Õ°Õ¡ÕµÕ¿Õ¾Õ¥Õ¬Ö‰</translation>
@@ -1452,6 +1488,7 @@
<translation id="5556459405103347317">ÕŽÕ¥Ö€Õ¡Õ¢Õ¥Õ¼Õ¶Õ¥Õ¬</translation>
<translation id="5560088892362098740">Ô³Õ¸Ö€Õ®Õ¸Õ²Õ¸Ö‚Õ©ÕµÕ¡Õ¶ ÕªÕ¡Õ´Õ¯Õ¥Õ¿Õ« Õ½ÕºÕ¡Õ¼Õ´Õ¡Õ¶ Õ¡Õ´Õ½Õ¡Õ©Õ«Õ¾Õ¨</translation>
<translation id="55635442646131152">Õ“Õ¡Õ½Õ¿Õ¡Õ©Õ²Õ©Õ« Õ¯Õ¡Õ¼Õ¸Ö‚ÖÕ¾Õ¡Õ®Ö„Õ¨</translation>
+<translation id="5565613213060953222">Ô²Õ¡ÖÕ¥Õ¬ Õ«Õ¶Õ¯Õ¸Õ£Õ¶Õ«Õ¿Õ¸ Õ¶Õ¥Ö€Õ¤Õ«Ö€</translation>
<translation id="5565735124758917034">Ô±Õ¯Õ¿Õ«Õ¾ Õ§</translation>
<translation id="5570825185877910964">ÕŠÕ¡Õ·Õ¿ÕºÕ¡Õ¶Õ¥Õ¬ Õ°Õ¡Õ·Õ«Õ¾Õ¨</translation>
<translation id="5571083550517324815">ÕÕ¾ÕµÕ¡Õ¬ Õ°Õ¡Õ½ÖÕ¥Õ«Ö Õ¡Õ¼Õ¡Ö„Õ´Õ¡Õ¶ Õ¨Õ¶Õ¤Õ¸Ö‚Õ¶Õ¸Ö‚Õ´ Õ°Õ¶Õ¡Ö€Õ¡Õ¾Õ¸Ö€ Õ¹Õ§: Ô¸Õ¶Õ¿Ö€Õ¥Ö„ Õ¡ÕµÕ¬ Õ°Õ¡Õ½ÖÕ¥:</translation>
@@ -1534,6 +1571,7 @@
<translation id="5869522115854928033">ÕŠÕ¡Õ°Õ¾Õ¡Õ® Õ£Õ¡Õ²Õ¿Õ¶Õ¡Õ¢Õ¡Õ¼Õ¥Ö€</translation>
<translation id="5873013647450402046">ÕÕ¥Ö€ Õ¢Õ¡Õ¶Õ¯Õ¨ ÕºÕ¥Õ¿Ö„ Õ§ Õ°Õ¡Õ½Õ¿Õ¡Õ¿Õ« Õ±Õ¥Ö€ Õ«Õ¶Ö„Õ¶Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¨Ö‰</translation>
<translation id="5887400589839399685">Õ”Õ¡Ö€Õ¿Õ¨ ÕºÕ¡Õ°Õ¾Õ¥Ö</translation>
+<translation id="5887687176710214216">ÕŽÕ¥Ö€Õ»Õ«Õ¶ Õ¡ÕµÖÕ¥Õ¬Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¨Õ Õ¥Ö€Õ¥Õ¯</translation>
<translation id="5895138241574237353">ÕŽÕ¥Ö€Õ¡Õ£Õ¸Ö€Õ®Õ¡Ö€Õ¯Õ¥Õ¬</translation>
<translation id="5895187275912066135">Ô¹Õ¸Õ²Õ¡Ö€Õ¯Õ¾Õ¡Õ® Õ§Õ</translation>
<translation id="5901630391730855834">Ô´Õ¥Õ²Õ«Õ¶</translation>
@@ -1547,6 +1585,7 @@
<translation id="5921639886840618607">ÕŠÕ¡Õ°Õ¥ÕžÕ¬ Ö„Õ¡Ö€Õ¿Õ¨ Google Õ°Õ¡Õ·Õ¾Õ¸Ö‚Õ´</translation>
<translation id="5922853866070715753">Ô³Ö€Õ¥Õ©Õ¥ ÕºÕ¡Õ¿Ö€Õ¡Õ½Õ¿ Õ§</translation>
<translation id="5932224571077948991">Ô¿Õ¡ÕµÖ„Õ¨ Õ°Õ¸Õ£Õ¶Õ¥ÖÕ¶Õ¸Õ² Õ¯Õ¡Õ´ Õ´Õ¸Õ¬Õ¸Ö€Õ¥ÖÕ¶Õ¸Õ² Õ£Õ¸Õ¾Õ¡Õ¦Õ¤ Õ§ ÖÕ¸Ö‚ÖÕ¡Õ¤Ö€Õ¸Ö‚Õ´</translation>
+<translation id="5938153366081463283">Ô±Õ¾Õ¥Õ¬Õ¡ÖÖ€Õ¥Ö„ Õ¾Õ«Ö€Õ¿Õ¸Ö‚Õ¡Õ¬ Ö„Õ¡Ö€Õ¿</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347">Ô²Õ¡ÖÕ¾Õ¸Ö‚Õ´ Õ§ <ph name="SITE_NAME" /> կայքը…</translation>
<translation id="5951495562196540101">Õ€Õ¶Õ¡Ö€Õ¡Õ¾Õ¸Ö€ Õ¹Õ§ Õ£Ö€Õ¡Õ¶ÖÕ¾Õ¥Õ¬ Õ½Õ¸Õ¾Õ¸Ö€Õ¡Õ¯Õ¡Õ¶ Õ°Õ¡Õ·Õ¾Õ¸Õ¾ (Õ°Õ¡Õ½Õ¡Õ¶Õ¥Õ¬Õ« Õ§ ÖƒÕ¡Õ©Õ¥Õ©Õ¸Õ¾ Õ¡Ö€Õ¿Õ¸Õ¶Õ¡Õ£Õ«Ö€)Ö‰</translation>
@@ -1611,6 +1650,7 @@
<translation id="6120179357481664955">Õ€Õ«Õ·Õ¸ÕžÖ‚Õ´ Õ¥Ö„ Õ±Õ¥Ö€ UPI ID-Õ¶</translation>
<translation id="6124432979022149706">Chrome Enterprise-Õ« Õ´Õ«Õ¡Õ¯ÖÕ«Õ¹Õ¶Õ¥Ö€</translation>
<translation id="6127379762771434464">ÕÕ¡Ö€Ö€Õ¨ Õ°Õ¥Õ¼Õ¡ÖÕ¾Õ¥Ö</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Ô»Õ´Õ¡Õ¶Õ¡Õ¬ Õ¡Õ¾Õ¥Õ¬Õ«Õ¶ Chrome-Õ« Õ«Õ¶Õ¯Õ¸Õ£Õ¶Õ«Õ¿Õ¸ Õ¼Õ¥ÕªÕ«Õ´Õ« Õ´Õ¡Õ½Õ«Õ¶<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">ÕÕ¿Õ¸Ö‚Õ£Õ¥Ö„ Õ¢Õ¸Õ¬Õ¸Ö€ Õ´Õ¡Õ¬Õ¸Ö‚Õ­Õ¶Õ¥Ö€Õ¨ Ö‡ Õ¾Õ¥Ö€Õ¡Õ¢Õ¥Õ¼Õ¶Õ¥Ö„ Õ¥Ö€Õ©Õ¸Ö‚Õ²Õ«Õ¹Õ¶Õ¥Ö€Õ¨, Õ´Õ¸Õ¤Õ¥Õ´Õ¶Õ¥Ö€Õ¨ Õ¯Õ¡Õ´ Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¾Õ¸Õ²
Õ¡ÕµÕ¬ ÖÕ¡Õ¶ÖÕ¡ÕµÕ«Õ¶ Õ½Õ¡Ö€Ö„Õ¥Ö€Õ¨:</translation>
<translation id="614940544461990577">Õ“Õ¸Ö€Õ±Õ¥Ö„Õ</translation>
@@ -1623,7 +1663,6 @@
<translation id="6169916984152623906">Ô»Õ¶Õ¯Õ¸Õ£Õ¶Õ«Õ¿Õ¸ Õ¼Õ¥ÕªÕ«Õ´Õ¸Ö‚Õ´ Õ±Õ¥Ö€ Õ£Õ¸Ö€Õ®Õ¸Õ²Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¨ Õ¿Õ¥Õ½Õ¡Õ¶Õ¥Õ¬Õ« Õ¹Õ¥Õ¶ Õ¬Õ«Õ¶Õ« Õ¡ÕµÕ½ Õ½Õ¡Ö€Ö„Õ« Õ´ÕµÕ¸Ö‚Õ½ Ö…Õ£Õ¿Õ¡Õ¿Õ¥Ö€Õ¥Ö€Õ«Õ¶: ÕÕ¡Õ¯Õ¡ÕµÕ¶ Õ¶Õ¥Ö€Õ¢Õ¥Õ¼Õ¶Õ¸Ö‚Õ´Õ¶Õ¥Ö€Õ¶ Õ¸Ö‚ Õ§Õ»Õ¡Õ¶Õ«Õ·Õ¶Õ¥Ö€Õ¨ Õ¯ÕºÕ¡Õ°Õ¾Õ¥Õ¶Ö‰</translation>
<translation id="6177128806592000436">Ô¿Õ¡ÕµÖ„Õ«Õ¶ Õ¯Õ¡ÕºÕ¡Õ¯ÖÕ¸Ö‚Õ´Õ¨ ÕºÕ¡Õ·Õ¿ÕºÕ¡Õ¶Õ¾Õ¡Õ® Õ¹Õ§</translation>
<translation id="6180316780098470077">Ô¿Ö€Õ¯Õ¶Õ¸Ö‚Õ©ÕµÕ¡Õ¶ Õ´Õ«Õ»Õ¡Õ¯Õ¡ÕµÖ„</translation>
-<translation id="619448280891863779">Ô¿Õ¡Ö€Õ¸Õ² Õ§ Õ°Õ¡ÕµÖÕ¥Õ¬ Õ§Õ¯Ö€Õ¡Õ¶Õ¶Õ¥Ö€Õ«Õ¶ ÕºÕ¡Õ¿Õ¸Ö‚Õ°Õ¡Õ¶Õ¶Õ¥Ö€ Õ¢Õ¡ÖÕ¥Õ¬Õ¸Ö‚ Ö‡ Õ¿Õ¥Õ²Õ¡Õ¤Ö€Õ¥Õ¬Õ¸Ö‚ Õ©Õ¸Ö‚ÕµÕ¬Õ¿Õ¾Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶</translation>
<translation id="6196640612572343990">Ô±Ö€Õ£Õ¥Õ¬Õ¡ÖƒÕ¡Õ¯Õ¥Õ¬ Õ¥Ö€Ö€Õ¸Ö€Õ¤ Õ¯Õ¸Õ²Õ´Õ« Ö„Õ¸Ö‚Ö„Õ«Õ¶Õ¥Ö€Õ¨</translation>
<translation id="6203231073485539293">ÕÕ¿Õ¸Ö‚Õ£Õ¥Ö„ Õ°Õ¡Õ´Õ¡ÖÕ¡Õ¶ÖÕ« Õ¯Õ¡ÕºÕ¡Õ¯ÖÕ¸Ö‚Õ´Õ¨</translation>
<translation id="6218753634732582820">Õ€Õ¥Õ¼Õ¡ÖÕ¶Õ¥ÕžÕ¬ Õ°Õ¡Õ½ÖÕ¥Õ¶ Chromium-Õ«Ö:</translation>
@@ -1646,7 +1685,7 @@
<translation id="6272383483618007430">Google Update</translation>
<translation id="6276112860590028508">ÕÕ¥Ö€ Õ¨Õ¶Õ©Õ¥Ö€ÖÕ¡Õ¶Õ¸Ö‚Õ©ÕµÕ¡Õ¶ ÖÕ¡Õ¶Õ¯Õ« Õ§Õ»Õ¥Ö€Õ¨ Õ¯ÖÕ¸Ö‚ÖÕ¡Õ¤Ö€Õ¾Õ¥Õ¶ Õ¡ÕµÕ½Õ¿Õ¥Õ²</translation>
<translation id="627746635834430766">Õ€Õ¡Õ»Õ¸Ö€Õ¤ Õ¡Õ¶Õ£Õ¡Õ´ Õ¡Õ¾Õ¥Õ¬Õ« Õ¡Ö€Õ¡Õ£ Õ¾Õ³Õ¡Ö€Õ¥Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€ ÕºÕ¡Õ°Õ¥Ö„ Õ±Õ¥Ö€ Ö„Õ¡Ö€Õ¿Õ¨ Ö‡ Õ¾Õ³Õ¡Ö€Õ¡ÕµÕ«Õ¶ Õ°Õ¡Õ½ÖÕ¥Õ¶ Google Õ°Õ¡Õ·Õ¾Õ¸Ö‚Õ´:</translation>
-<translation id="6279098320682980337">ÕŽÕ«Ö€Õ¿Õ¸Ö‚Õ¡Õ¬ Ö„Õ¡Ö€Õ¿Õ« Õ°Õ¡Õ´Õ¡Ö€Õ¨ Õ¹Õ«Õž Õ¬Ö€Õ¡ÖÕ¾Õ¥Õ¬Ö‰ ÕÕ¥Õ²Õ´Õ¥Ö„ Ö„Õ¡Ö€Õ¿Õ« Õ¿Õ¾ÕµÕ¡Õ¬Õ¶Õ¥Ö€Õ« Õ¾Ö€Õ¡Õ Õ¤Ö€Õ¡Õ¶Ö„ ÕºÕ¡Õ¿Õ³Õ¥Õ¶Õ¥Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€Ö‰</translation>
+<translation id="6279183038361895380">Õ†Õ·Õ¸Ö€Õ¤Õ¨ ÖÕ¸Ö‚ÖÕ¡Õ¤Ö€Õ¥Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€ Õ½Õ¥Õ²Õ´Õ¥Ö„ |<ph name="ACCELERATOR" />|</translation>
<translation id="6280223929691119688">Ô±ÕµÕ½ Õ°Õ¡Õ½ÖÕ¥Õ¸Õ¾ Õ°Õ¶Õ¡Ö€Õ¡Õ¾Õ¸Ö€ Õ¹Õ§ Õ¡Õ¼Õ¡Ö„Õ¥Õ¬: Ô¸Õ¶Õ¿Ö€Õ¥Ö„ Õ¡ÕµÕ¬ Õ°Õ¡Õ½ÖÕ¥:</translation>
<translation id="6282194474023008486">Õ“Õ¸Õ½Õ¿Õ¡ÕµÕ«Õ¶ Õ¤Õ¡Õ½Õ«Õ¹</translation>
<translation id="6285507000506177184">«Կառավարել Õ¶Õ¥Ö€Õ¢Õ¥Õ¼Õ¶Õ¸Ö‚Õ´Õ¶Õ¥Ö€Õ¨ Chrome-ում» Õ¯Õ¸Õ³Õ¡Õ¯Ö‰ ÕÕ¥Õ²Õ´Õ¥Ö„ EnterÕ Chrome-Õ¸Ö‚Õ´ Õ±Õ¥Ö€ Õ¶Õ¥Ö€Õ¢Õ¥Õ¼Õ¶Õ¡Õ® Ö†Õ¡ÕµÕ¬Õ¥Ö€Õ¨ Õ¯Õ¡Õ¼Õ¡Õ¾Õ¡Ö€Õ¥Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€Ö‰</translation>
@@ -1654,6 +1693,7 @@
<translation id="6290238015253830360">Ô±ÕµÕ½Õ¿Õ¥Õ² Õ¯ÖÕ¸Ö‚ÖÕ¡Õ¤Ö€Õ¾Õ¥Õ¶ Õ¡Õ¼Õ¡Õ»Õ¡Ö€Õ¯Õ¾Õ¸Õ² Õ°Õ¸Õ¤Õ¾Õ¡Õ®Õ¶Õ¥Ö€Õ¨</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC Õ¯Õ¸Õ¤Õ</translation>
+<translation id="6300452962057769623">{0,plural, =0{ÕÕ¡Ö€Ö„Õ¨ Õ°Õ«Õ´Õ¡ Õ¯Õ¾Õ¥Ö€Õ¡Õ£Õ¸Ö€Õ®Õ¡Ö€Õ¯Õ¾Õ«}=1{ÕÕ¡Ö€Ö„Õ¨ Õ¯Õ¾Õ¥Ö€Õ¡Õ£Õ¸Ö€Õ®Õ¡Ö€Õ¯Õ¾Õ« 1 Õ¾Õ¡ÕµÖ€Õ¯ÕµÕ¡Õ¶Õ«Ö}one{ÕÕ¡Ö€Ö„Õ¨ Õ¯Õ¾Õ¥Ö€Õ¡Õ£Õ¸Ö€Õ®Õ¡Ö€Õ¯Õ¾Õ« # Õ¾Õ¡ÕµÖ€Õ¯ÕµÕ¡Õ¶Õ«Ö}other{ÕÕ¡Ö€Ö„Õ¨ Õ¯Õ¾Õ¥Ö€Õ¡Õ£Õ¸Ö€Õ®Õ¡Ö€Õ¯Õ¾Õ« # Õ¾Õ¡ÕµÖ€Õ¯ÕµÕ¡Õ¶Õ«Ö}}</translation>
<translation id="6302269476990306341">Google Õ•Õ£Õ¶Õ¡Õ¯Õ¡Õ¶Õ¨ Chrome-Õ¸Ö‚Õ´ Õ¯Õ¡Õ¶Õ»Õ¡Õ¿Õ¾Õ«</translation>
<translation id="6305205051461490394"><ph name="URL" />-Õ¶ Õ¡Õ¶Õ°Õ¡Õ½Õ¡Õ¶Õ¥Õ¬Õ« Õ§:</translation>
<translation id="6312113039770857350">Ô¿Õ¡ÕµÖ„Õ§Õ»Õ¶ Õ¡Õ¶Õ°Õ¡Õ½Õ¡Õ¶Õ¥Õ¬Õ« Õ§</translation>
@@ -1727,6 +1767,7 @@
<translation id="6529602333819889595">&amp;ÕŽÕ¥Ö€Õ¡Ö€Õ¯Õ¥Õ¬ Õ»Õ¶Õ»Õ¸Ö‚Õ´Õ¨</translation>
<translation id="6545864417968258051">Bluetooth Õ½Õ¡Ö€Ö„Õ¥Ö€Õ« Õ¸Ö€Õ¸Õ¶Õ¸Ö‚Õ´</translation>
<translation id="6547208576736763147">ÔµÖ€Õ¯Õ¸Ö‚ Õ¡Õ¶ÖÖ„ Õ±Õ¡Õ­ Õ¯Õ¸Õ²Õ´Õ¸Ö‚Õ´</translation>
+<translation id="6554732001434021288">ÕŽÕ¥Ö€Õ»Õ«Õ¶ Õ¡ÕµÖÕ¥Õ¬Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¨Õ <ph name="NUM_DAYS" /> Ö…Ö€ Õ¡Õ¼Õ¡Õ»</translation>
<translation id="6556866813142980365">Ô¿Ö€Õ¯Õ¶Õ¥Õ¬</translation>
<translation id="6569060085658103619">Ô´Õ¸Ö‚Ö„ Õ¤Õ«Õ¿Õ¸Ö‚Õ´ Õ¥Ö„ Õ¨Õ¶Õ¤Õ¬Õ¡ÕµÕ¶Õ´Õ¡Õ¶ Õ§Õ»Õ¨</translation>
<translation id="6573200754375280815">ÔµÖ€Õ¯Õ¸Ö‚ Õ¡Õ¶ÖÖ„ Õ¡Õ» Õ¯Õ¸Õ²Õ´Õ¸Ö‚Õ´</translation>
@@ -1774,7 +1815,7 @@
<translation id="6710213216561001401">Õ†Õ¡Õ­Õ¸Ö€Õ¤Õ¨</translation>
<translation id="6710594484020273272">&lt;Õ„Õ¸Ö‚Õ¿Ö„Õ¡Õ£Ö€Õ¥Ö„ Õ¸Ö€Õ¸Õ¶Õ´Õ¡Õ¶ Õ°Õ¡Ö€ÖÕ¸Ö‚Õ´Õ¨&gt;</translation>
<translation id="671076103358959139">Ô³Ö€Õ¡Õ¶ÖÕ´Õ¡Õ¶ Õ©Õ¸Ö„Õ¥Õ¶Õ</translation>
-<translation id="6711464428925977395">Õ„Õ«Õ»Õ¶Õ¸Ö€Õ¤ Õ½Õ¥Ö€Õ¾Õ¥Ö€Õ« Õ°Õ¥Õ¿ Õ«Õ¶Õ¹-Õ¸Ö€ Õ¢Õ¡Õ¶ Õ¡ÕµÕ¶ Õ¹Õ§, Õ¯Õ¡Õ´ Õ°Õ¡Õ½ÖÕ¥Õ¶ Õ½Õ­Õ¡Õ¬ Õ§:</translation>
+<translation id="6711464428925977395">ÕŠÖ€Õ¸Ö„Õ½Õ« Õ½Õ¥Ö€Õ¾Õ¥Ö€Õ« Õ°Õ¥Õ¿ Õ«Õ¶Õ¹-Õ¸Ö€ Õ¢Õ¡Õ¶ Õ¡ÕµÕ¶ Õ¹Õ§, Õ¯Õ¡Õ´ Õ°Õ¡Õ½ÖÕ¥Õ¶ Õ½Õ­Õ¡Õ¬ Õ§:</translation>
<translation id="6716672519412350405"><ph name="URL" /> Õ¯Õ¡ÕµÖ„Õ¶ Õ¸Ö‚Õ¦Õ¸Ö‚Õ´ Õ§ Õ½Õ¿Õ¥Õ²Õ®Õ¥Õ¬ Õ±Õ¥Ö€ Õ·Ö€Õ»Õ¡Õ¯Õ¡ÕµÖ„Õ« Õ¥Õ¼Õ¡Õ¹Õ¡Öƒ Ö„Õ¡Ö€Õ¿Õ¥Õ¦Õ¨ Ö‡ Õ°Õ¥Õ¿Õ¡Õ£Õ®Õ¥Õ¬ Õ¿Õ¥Õ½Õ¡Õ­ÖÕ«Õ¯Õ« Õ¤Õ«Ö€Ö„Õ¨</translation>
<translation id="6718612893943028815">Õ•Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¥ÕžÕ¬ Õ¿Õ¥Õ½Õ¡Õ­ÖÕ«Õ¯Õ¨</translation>
<translation id="6721678857435001674">ÕÕ¥Õ½Õ¶Õ¥Õ¬ Õ¡Õ¶Õ¾Õ¿Õ¡Õ¶Õ£Õ¸Ö‚Õ©ÕµÕ¡Õ¶ Õ¢Õ¡Õ¶Õ¡Õ¬Õ¸Ö‚ Õ¡Ö€Õ¿Õ¡Õ¤Ö€Õ¸Õ²Õ« Ö‡ Õ´Õ¸Õ¤Õ¥Õ¬Õ« Õ¡Õ¶Õ¸Ö‚Õ¶Õ¨</translation>
@@ -1787,7 +1828,6 @@
<translation id="6757797048963528358">ÕÕ¥Ö€ Õ½Õ¡Ö€Ö„Õ¨ Õ´Õ¿Õ¥Õ¬ Õ§ Ö„Õ¶Õ« Õ¼Õ¥ÕªÕ«Õ´:</translation>
<translation id="6767985426384634228">Ô¹Õ¡Ö€Õ´Õ¡ÖÕ¶Õ¥ÕžÕ¬ Õ°Õ¡Õ½ÖÕ¥Õ¶</translation>
<translation id="6768213884286397650">Hagaki (Õ¢Õ¡ÖÕ«Õ¯)</translation>
-<translation id="6774185088257932239"><ph name="BEGIN_LINK" />Ô»Õ´Õ¡Õ¶Õ¡Õ¬ Õ¡Õ¾Õ¥Õ¬Õ«Õ¶<ph name="END_LINK" /> Õ«Õ¶Õ¯Õ¸Õ£Õ¶Õ«Õ¿Õ¸ Õ¼Õ¥ÕªÕ«Õ´Õ« Õ´Õ¡Õ½Õ«Õ¶</translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">Ô²Õ¡Ö Õ´Õ¡Õ¶Õ¸Ö‚Õ·Õ¡Õ¯Õ¡Õ£Õ¸Ö‚ÕµÕ¶</translation>
<translation id="6786747875388722282">Ô¸Õ¶Õ¤Õ¬Õ¡ÕµÕ¶Õ¸Ö‚Õ´Õ¶Õ¥Ö€</translation>
@@ -1871,7 +1911,6 @@
<translation id="706295145388601875">Ô±Õ¾Õ¥Õ¬Õ¡ÖÖ€Õ¥Ö„ Õ°Õ¡Õ½ÖÕ¥Õ¶Õ¥Ö€ Ö‡ Õ¯Õ¡Õ¼Õ¡Õ¾Õ¡Ö€Õ¥Ö„ Õ¤Ö€Õ¡Õ¶Ö„ Chrome-Õ« Õ¯Õ¡Ö€Õ£Õ¡Õ¾Õ¸Ö€Õ¸Ö‚Õ´Õ¶Õ¥Ö€Õ¸Ö‚Õ´</translation>
<translation id="7064851114919012435">Ô¿Õ¸Õ¶Õ¿Õ¡Õ¯Õ¿Õ¡ÕµÕ«Õ¶ Õ¿Õ¾ÕµÕ¡Õ¬Õ¶Õ¥Ö€</translation>
<translation id="7068733155164172741">Õ„Õ¸Ö‚Õ¿Ö„Õ¡Õ£Ö€Õ¥Ö„ <ph name="OTP_LENGTH" /> Õ©Õ¾Õ¡Õ¶Õ·Õ¡Õ¶Õ«Ö Õ¢Õ¡Õ²Õ¯Õ¡ÖÕ¡Õ® Õ¯Õ¸Õ¤Õ¨</translation>
-<translation id="7070090581017165256">Ô±ÕµÕ½ Õ¯Õ¡ÕµÖ„Õ« Õ´Õ¡Õ½Õ«Õ¶</translation>
<translation id="70705239631109039">ÕÕ¥Ö€ Õ¯Õ¡ÕºÕ¨ Õ¬Õ«Õ¡Ö€ÕªÕ¥Ö„ ÕºÕ¡Õ·Õ¿ÕºÕ¡Õ¶Õ¾Õ¡Õ® Õ¹Õ§</translation>
<translation id="7075452647191940183">Õ€Õ¡Ö€ÖÕ¸Ö‚Õ´Õ¨ Õ¹Õ¡ÖƒÕ¡Õ¦Õ¡Õ¶Ö Õ´Õ¥Õ® Õ§</translation>
<translation id="7079718277001814089">Ô±ÕµÕ½ Õ¯Õ¡ÕµÖ„Õ¨ Õ¾Õ¶Õ¡Õ½Õ¡Õ¢Õ¥Ö€ Õ®Ö€Õ¡Õ£Õ«Ö€ Õ§ ÕºÕ¡Ö€Õ¸Ö‚Õ¶Õ¡Õ¯Õ¸Ö‚Õ´</translation>
@@ -1888,6 +1927,12 @@
<translation id="7111012039238467737">(Õ¾Õ¡Õ¾Õ¥Ö€)</translation>
<translation id="7118618213916969306">ÕÕ¥Õ²Õ´Õ¡Õ¿Õ¡Õ­Õ¿Õ¡Õ¯Õ«Õ¶ ÕºÕ¡Õ°Õ¾Õ¡Õ® URL-Õ« Õ¸Ö€Õ¸Õ¶Õ¸Ö‚Õ´, <ph name="SHORT_URL" /></translation>
<translation id="7119414471315195487">Õ“Õ¡Õ¯Õ¥Ö„ Õ´ÕµÕ¸Ö‚Õ½ Õ¶Õ¥Ö€Õ¤Õ«Ö€Õ¶Õ¥Ö€Õ¶ Õ¸Ö‚ Õ®Ö€Õ¡Õ£Ö€Õ¥Ö€Õ¨</translation>
+<translation id="7129355289156517987">ÔµÖ€Õ¢ ÖƒÕ¡Õ¯Õ¥Ö„ Chromium-Õ« Õ¢Õ¸Õ¬Õ¸Ö€ Õ«Õ¶Õ¯Õ¸Õ£Õ¶Õ«Õ¿Õ¸ Õ¶Õ¥Ö€Õ¤Õ«Ö€Õ¶Õ¥Ö€Õ¨, Õ¡ÕµÕ½ Õ½Õ¡Ö€Ö„Õ«Ö Õ¯Õ°Õ¥Õ¼Õ¡ÖÕ¾Õ¥Õ¶ Õ¡ÕµÕ¤ Õ¶Õ¥Ö€Õ¤Õ«Ö€Õ¶Õ¥Ö€Õ¸Ö‚Õ´ Õ±Õ¥Ö€ Õ¯Õ¡Õ¿Õ¡Ö€Õ¡Õ® Õ£Õ¸Ö€Õ®Õ¸Õ²Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¨, Õ¡ÕµÕ¤ Õ©Õ¾Õ¸Ö‚Õ´Õ
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Õ£Õ¸Ö€Õ®Õ¸Õ²Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¨ Õ¤Õ«Õ¿Õ¡Ö€Õ¯Õ«Õ¹Õ¸Ö‚Õ´,<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Õ¸Ö€Õ¸Õ¶Õ¸Ö‚Õ´Õ¶Õ¥Ö€Õ« ÕºÕ¡Õ¿Õ´Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¨,<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Õ±Ö‡Õ¥Ö€Õ¸Ö‚Õ´ Õ¬Ö€Õ¡ÖÕ¾Õ¡Õ® Õ¿Õ¥Õ²Õ¥Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¨Ö‰<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">Ô±ÕµÕ½ Õ°Õ¡Õ½ÖÕ¥Õ¸Õ¾ Õ°Õ¶Õ¡Ö€Õ¡Õ¾Õ¸Ö€ Õ¹Õ§ Õ¡Õ¼Õ¡Ö„Õ¥Õ¬: Ô¸Õ¶Õ¿Ö€Õ¥Ö„ Õ¡ÕµÕ¬ Õ°Õ¡Õ½ÖÕ¥:</translation>
<translation id="7132939140423847331">ÕÕ¥Ö€ Õ¡Õ¤Õ´Õ«Õ¶Õ«Õ½Õ¿Ö€Õ¡Õ¿Õ¸Ö€Õ¶ Õ¡Ö€Õ£Õ¥Õ¬Õ¥Õ¬ Õ§ Õ¡ÕµÕ½ Õ¿Õ¾ÕµÕ¡Õ¬Õ¶Õ¥Ö€Õ« ÕºÕ¡Õ¿Õ³Õ¥Õ¶Õ¸Ö‚Õ´Õ¨Ö‰</translation>
<translation id="7135130955892390533">Õ‘Õ¸Ö‚ÖÕ¡Õ¤Ö€Õ¥Õ¬ Õ¯Õ¡Ö€Õ£Õ¡Õ¾Õ«Õ³Õ¡Õ¯Õ¨</translation>
@@ -1910,6 +1955,7 @@
<translation id="7192203810768312527">Ô¿Õ¡Õ¦Õ¡Õ¿Õ¾Õ« <ph name="SIZE" /> Õ¿Õ¡Ö€Õ¡Õ®Ö„Ö‰ Ô´Ö€Õ¡Õ¶Õ«Ö Õ°Õ¥Õ¿Õ¸ Õ¸Ö€Õ¸Õ· Õ¯Õ¡ÕµÖ„Õ¥Ö€ Õ°Õ¶Õ¡Ö€Õ¡Õ¾Õ¸Ö€ Õ§Õ Õ¡Õ¾Õ¥Õ¬Õ« Õ¤Õ¡Õ¶Õ¤Õ¡Õ² Õ¢Õ¥Õ¼Õ¶Õ¾Õ¥Õ¶Ö‰</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">ÕÕ¥Ö€ Õ¡Õ¤Õ´Õ«Õ¶Õ«Õ½Õ¿Ö€Õ¡Õ¿Õ¸Ö€Õ¨ Õ¯Õ¡Ö€Õ¸Õ² Õ§ Õ¿Õ¥Õ½Õ¶Õ¥Õ¬Õ</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />Ö‰ Õ†Õ¸Ö€ Õ«Õ¶Õ¯Õ¸Õ£Õ¶Õ«Õ¿Õ¸ Õ¶Õ¥Ö€Õ¤Õ«Ö€ Õ¢Õ¡ÖÕ¥Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€ Õ½Õ¥Õ²Õ´Õ¥Ö„ Tab, Õ¡ÕºÕ¡Õ EnterÖ‰</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" />-Õ¨ Õ¹Õ« Õ°Õ¥Õ¿Ö‡Õ¸Ö‚Õ´ Õ¡Õ¶Õ¾Õ¿Õ¡Õ¶Õ£Õ¸Ö‚Õ©ÕµÕ¡Õ¶ Õ¹Õ¡ÖƒÕ¸Ö€Õ¸Õ·Õ«Õ¹Õ¶Õ¥Ö€Õ«Õ¶:</translation>
<translation id="7210993021468939304">ÕÕ¥Õ½Õ¶Õ¸Ö‚Õ´ Õ§ Ô¼Õ«Õ¶Õ¸Ö‚Ö„Õ½Õ« Õ£Õ¸Ö€Õ®Õ¸Õ²Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¨ Õ¯Õ¸Õ¶Õ¿Õ¥ÕµÕ¶Õ¥Ö€Õ¸Ö‚Õ´ Ö‡ Õ¯Õ¡Ö€Õ¸Õ² Õ§ Õ¿Õ¥Õ²Õ¡Õ¤Ö€Õ¥Õ¬ Õ¸Ö‚ Õ£Õ¸Ö€Õ®Õ¡Ö€Õ¯Õ¥Õ¬ Ô¼Õ«Õ¶Õ¸Ö‚Ö„Õ½Õ« Õ°Õ¡Õ¾Õ¥Õ¬Õ¾Õ¡Õ®Õ¶Õ¥Ö€ Õ¯Õ¸Õ¶Õ¿Õ¥ÕµÕ¶Õ¥Ö€Õ«Ö</translation>
@@ -1941,6 +1987,7 @@
<translation id="7304562222803846232">Ô¿Õ¡Õ¼Õ¡Õ¾Õ¡Ö€Õ¥Õ¬ Google Õ°Õ¡Õ·Õ¾Õ« Õ£Õ¡Õ²Õ¿Õ¶Õ«Õ¸Ö‚Õ©ÕµÕ¡Õ¶ Õ¯Õ¡Ö€Õ£Õ¡Õ¾Õ¸Ö€Õ¸Ö‚Õ´Õ¶Õ¥Ö€Õ¨</translation>
<translation id="7305756307268530424">Ô³Õ¸Ö€Õ®Õ¡Ö€Õ¯Õ¥Õ¬ Õ¡Õ¾Õ¥Õ¬Õ« Õ¤Õ¡Õ¶Õ¤Õ¡Õ²</translation>
<translation id="7308436126008021607">Ö†Õ¸Õ¶Õ¡ÕµÕ«Õ¶ Õ°Õ¡Õ´Õ¡ÕªÕ¡Õ´Õ¡ÖÕ¸Ö‚Õ´</translation>
+<translation id="7310392214323165548">ÕÕ¡Ö€Ö„Õ¨ Õ·Õ¸Ö‚Õ¿Õ¸Õ¾ Õ¯Õ¾Õ¥Ö€Õ¡Õ£Õ¸Ö€Õ®Õ¡Ö€Õ¯Õ¾Õ«</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">Õ•Õ£Õ¶Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶ Õ¯Õ¡ÕºÕ« Õ­Õ¶Õ¤Õ«Ö€Õ¶Õ¥Ö€Õ« Õ¤Õ¥ÕºÖ„Õ¸Ö‚Õ´</translation>
<translation id="7323804146520582233">Ô¹Õ¡Ö„ÖÕ¶Õ¥Õ¬ «<ph name="SECTION" />» Õ¢Õ¡ÕªÕ«Õ¶Õ¨</translation>
@@ -1948,6 +1995,7 @@
<translation id="7334320624316649418">&amp;ÕŽÕ¥Ö€Õ¡Ö€Õ¯Õ¥Õ¬ Õ¾Õ¥Ö€Õ¡Õ¤Õ¡Õ½Õ¡Õ¾Õ¸Ö€Õ¸Ö‚Õ´Õ¨</translation>
<translation id="7335157162773372339">Ô¿Õ¡Ö€Õ¸Õ² Õ§ Õ°Õ¡ÕµÖÕ¥Õ¬ Õ¿Õ¥Õ½Õ¡Õ­ÖÕ«Õ¯Õ¶ Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¥Õ¬Õ¸Ö‚ Õ©Õ¸Ö‚ÕµÕ¬Õ¿Õ¾Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶</translation>
<translation id="7337248890521463931">Õ‘Õ¸Ö‚ÕµÖ Õ¿Õ¡Õ¬ Õ¡Õ¾Õ¥Õ¬Õ« Õ·Õ¡Õ¿ Õ¿Õ¸Õ²Õ¥Ö€</translation>
+<translation id="7337418456231055214">ÕŽÕ«Ö€Õ¿Õ¸Ö‚Õ¡Õ¬ Ö„Õ¡Ö€Õ¿Õ« Õ°Õ¡Õ´Õ¡Ö€Õ¨ Õ¹Õ«Õž Õ¬Ö€Õ¡ÖÕ¾Õ¥Õ¬Ö‰ ÕÕ¥Õ²Õ´Õ¥Ö„ Ö„Õ¡Ö€Õ¿Õ« Õ¿Õ¾ÕµÕ¡Õ¬Õ¶Õ¥Ö€Õ« Õ¾Ö€Õ¡Õ Õ¤Ö€Õ¡Õ¶Ö„ ÕºÕ¡Õ¿Õ³Õ¥Õ¶Õ¥Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€Ö‰ <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">Õ€Õ¡Õ½Õ¡Õ¶Õ¥Õ¬Õ« Õ¹Õ§ Õ±Õ¥Ö€ Õ°Õ¡Ö€Õ©Õ¡Õ¯Õ¸Ö‚Õ´:</translation>
<translation id="733923710415886693">ÕÕ¥Ö€Õ¾Õ¥Ö€Õ« Õ¾Õ¯Õ¡ÕµÕ¡Õ£Õ«Ö€Õ¨ Õ¹Õ« Õ¢Õ¡ÖÕ¡Õ°Õ¡ÕµÕ¿Õ¾Õ¥Õ¬ «Վկայագրերի Õ©Õ¡ÖƒÕ¡Õ¶Öիկություն» Õ¯Õ¡Õ¶Õ¸Õ¶Õ« Õ´Õ«Õ»Õ¸ÖÕ¸Õ¾:</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1970,6 +2018,7 @@
<translation id="7378627244592794276">ÕˆÕ¹ Õ°Õ«Õ´Õ¡</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">Ô¿Õ«Ö€Õ¡Õ¼Õ¥Õ¬Õ« Õ¹Õ§</translation>
+<translation id="7388594495505979117">{0,plural, =1{ÕÕ¡Ö€Ö„Õ¨ Õ¯Õ¾Õ¥Ö€Õ¡Õ£Õ¸Ö€Õ®Õ¡Ö€Õ¯Õ¾Õ« 1 Ö€Õ¸ÕºÕ¥Õ«Ö}one{ÕÕ¡Ö€Ö„Õ¨ Õ¯Õ¾Õ¥Ö€Õ¡Õ£Õ¸Ö€Õ®Õ¡Ö€Õ¯Õ¾Õ« # Ö€Õ¸ÕºÕ¥Õ«Ö}other{ÕÕ¡Ö€Ö„Õ¨ Õ¯Õ¾Õ¥Ö€Õ¡Õ£Õ¸Ö€Õ®Õ¡Ö€Õ¯Õ¾Õ« # Ö€Õ¸ÕºÕ¥Õ«Ö}}</translation>
<translation id="7390545607259442187">Õ”Õ¡Ö€Õ¿Õ« Õ°Õ¡Õ½Õ¿Õ¡Õ¿Õ¸Ö‚Õ´</translation>
<translation id="7392089738299859607">Ô¹Õ¡Ö€Õ´Õ¡ÖÕ¶Õ¥Õ¬ Õ°Õ¡Õ½ÖÕ¥Õ¶</translation>
<translation id="7399802613464275309">Ô±Õ¶Õ¾Õ¿Õ¡Õ¶Õ£Õ¸Ö‚Õ©ÕµÕ¡Õ¶ Õ½Õ¿Õ¸Ö‚Õ£Õ¸Ö‚Õ´</translation>
@@ -2006,6 +2055,12 @@
<translation id="7485870689360869515">ÕÕ¾ÕµÕ¡Õ¬Õ¶Õ¥Ö€ Õ¹Õ¥Õ¶ Õ£Õ¿Õ¶Õ¾Õ¥Õ¬:</translation>
<translation id="7495528107193238112">Ô±ÕµÕ½ Õ¢Õ¸Õ¾Õ¡Õ¶Õ¤Õ¡Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶ Õ¡Ö€Õ£Õ¥Õ¬Õ¡ÖƒÕ¡Õ¯Õ¾Õ¡Õ® Õ§Ö‰ Ô½Õ¶Õ¤Õ«Ö€Õ¨ Õ¾Õ¥Ö€Õ¡ÖÕ¶Õ¥Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€ Õ¤Õ«Õ´Õ¥Ö„ Õ¯Õ¡ÕµÖ„Õ« Õ½Õ¥ÖƒÕ¡Õ¯Õ¡Õ¶Õ¡Õ¿Õ«Ö€Õ¸Õ»Õ¨Ö‰</translation>
<translation id="7497998058912824456">«ÕÕ¿Õ¥Õ²Õ®Õ¥Õ¬ փաստաթուղթ» Õ¯Õ¸Õ³Õ¡Õ¯Ö‰ Ô±Ö€Õ¡Õ£ Google ÖƒÕ¡Õ½Õ¿Õ¡Õ©Õ¸Ö‚Õ²Õ© Õ½Õ¿Õ¥Õ²Õ®Õ¥Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€ Õ½Õ¥Õ²Õ´Õ¥Ö„ EnterÖ‰</translation>
+<translation id="7506488012654002225">Chromium-Õ¸Ö‚Õ´ <ph name="BEGIN_EMPHASIS" />Õ¹Õ¥Õ¶ ÕºÕ¡Õ°Õ¾Õ«<ph name="END_EMPHASIS" />Õ
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Õ±Õ¥Ö€ Õ¡ÕµÖÕ¥Õ¬Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ« ÕºÕ¡Õ¿Õ´Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¨,
+ <ph name="LIST_ITEM" />Ö„Õ¸Ö‚Ö„Õ«Õ¶Õ¥Ö€Õ¶ Õ¸Ö‚ Õ¯Õ¡ÕµÖ„Õ¥Ö€Õ« Õ¿Õ¾ÕµÕ¡Õ¬Õ¶Õ¥Ö€Õ¨,
+ <ph name="LIST_ITEM" />Õ±Ö‡Õ¥Ö€Õ¸Ö‚Õ´ Õ¬Ö€Õ¡ÖÕ¾Õ¡Õ® Õ¿Õ¥Õ²Õ¥Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¨Ö‰
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">ÕÕ¡Ö€Ö„Õ« Õ¾Õ¥Ö€Õ¡Õ¤Õ¡Ö€Õ±Õ¾Õ¡Õ® Õ¯Õ¡Õ¶Õ¸Õ¶Õ« ID-Õ¶ Õ¤Õ¡Õ¿Õ¡Ö€Õ¯ Õ§ Õ¯Õ¡Õ´ Õ¹Õ« Õ°Õ¡Õ´Õ¡ÕºÕ¡Õ¿Õ¡Õ½Õ­Õ¡Õ¶Õ¸Ö‚Õ´ Õ¨Õ¶Õ©Õ¡ÖÕ«Õ¯ ID-Õ«Õ¶</translation>
<translation id="7508870219247277067">Ô±Õ¾Õ¸Õ¯Õ¡Õ¤Õ¸ÕµÕ« Õ¯Õ¡Õ¶Õ¡Õ¹</translation>
<translation id="7511955381719512146">Ô±Õ¶Õ¬Õ¡Ö€ Õ¯Õ¡ÕºÕ¨, Õ¸Ö€Õ«Ö Ö…Õ£Õ¿Õ¾Õ¸Ö‚Õ´ Õ¥Ö„, Õ¯Õ¡Ö€Õ¸Õ² Õ§ ÕºÕ¡Õ°Õ¡Õ¶Õ»Õ¥Õ¬, Õ¸Ö€ÕºÕ¥Õ½Õ¦Õ« Õ¤Õ¸Ö‚Ö„ Õ¡ÕµÖÕ¥Õ¬Õ¥Ö„ <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />:</translation>
@@ -2119,7 +2174,6 @@
<translation id="7813600968533626083">Õ€Õ¥Õ¼Õ¡ÖÕ¶Õ¥ÕžÕ¬ Chrome-Õ« Õ¡Õ¼Õ¡Õ»Õ¡Ö€Õ¯Õ¶Õ¥Ö€Õ«Ö:</translation>
<translation id="781440967107097262">Ô¿Õ«Õ½Õ¾Õ¥ÕžÕ¬ Õ½Õ¥Õ²Õ´Õ¡Õ¿Õ¡Õ­Õ¿Õ¡Õ¯Õ¸Õ¾</translation>
<translation id="7815407501681723534">«<ph name="SEARCH_STRING" />» Õ°Õ¡Ö€ÖÕ¸Ö‚Õ´Õ¸Õ¾ Õ¸Ö€Õ¸Õ¶Õ´Õ¡Õ¶ Õ¡Ö€Õ¤ÕµÕ¸Ö‚Õ¶Ö„Õ¸Ö‚Õ´ Õ£Õ¿Õ¶Õ¾Õ¥Õ¬ Õ§ <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /></translation>
-<translation id="782125616001965242">Õ‘Õ¸Ö‚ÖÕ¡Õ¤Ö€Õ¥Õ¬ Õ¿Õ¥Õ²Õ¥Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€ Õ¡ÕµÕ½ Õ¯Õ¡ÕµÖ„Õ« Õ´Õ¡Õ½Õ«Õ¶</translation>
<translation id="782886543891417279">Ô±Õ¶Õ¬Õ¡Ö€ Õ¯Õ¡ÕºÕ¨ (<ph name="WIFI_NAME" />), Õ¸Ö€Õ«Ö Ö…Õ£Õ¿Õ¾Õ¸Ö‚Õ´ Õ¥Ö„, Õ¯Õ¡Ö€Õ¸Õ² Õ§ ÕºÕ¡Õ°Õ¡Õ¶Õ»Õ¥Õ¬, Õ¸Ö€ÕºÕ¥Õ½Õ¦Õ« Õ¤Õ¸Ö‚Ö„ Õ¡ÕµÖÕ¥Õ¬Õ¥Ö„ Õ¶Ö€Õ¡ Õ´Õ¸Ö‚Õ¿Ö„Õ« Õ§Õ»Õ¨:</translation>
<translation id="7836231406687464395">Postfix (Õ®Ö€Õ¡Ö€)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{Õ‰Õ¯Õ¡}=1{1 Õ°Õ¡Õ¾Õ¥Õ¬Õ¾Õ¡Õ® (<ph name="EXAMPLE_APP_1" />)}=2{2 Õ°Õ¡Õ¾Õ¥Õ¬Õ¾Õ¡Õ® (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}one{# Õ°Õ¡Õ¾Õ¥Õ¬Õ¾Õ¡Õ® (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}other{# Õ°Õ¡Õ¾Õ¥Õ¬Õ¾Õ¡Õ® (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}}</translation>
@@ -2136,7 +2190,6 @@
<translation id="7888575728750733395">Ô³Õ¸Ö‚ÕµÕ¶Õ¥Ö€Õ¨ Õ¾Õ¥Ö€Õ¡Õ°Õ¡Õ·Õ¾Õ¥Õ¬Õ¸Ö‚ Õ¥Õ²Õ¡Õ¶Õ¡Õ¯ Õ¿ÕºÕ´Õ¡Õ¶ Õ°Õ¡Õ´Õ¡Ö€</translation>
<translation id="7894280532028510793">ÔµÕ©Õ¥ Õ¿Õ¡Õ¼Õ¡Õ½Õ­Õ¡Õ¬ Õ¹Õ¯Õ¡, <ph name="BEGIN_LINK" />Õ£Õ¸Ö€Õ®Õ¡Ö€Õ¯Õ¥Ö„ ÖÕ¡Õ¶ÖÕ« Õ¤Õ«Õ¡Õ£Õ¶Õ¸Õ½Õ¿Õ«Õ¯Õ¡Õ¶<ph name="END_LINK" />Ö‰</translation>
<translation id="7904208859782148177">C3 (Õ®Ö€Õ¡Ö€)</translation>
-<translation id="7931318309563332511">Ô±Õ¶Õ°Õ¡ÕµÕ¿</translation>
<translation id="793209273132572360">Ô¹Õ¡Ö€Õ´Õ¡ÖÕ¶Õ¥ÕžÕ¬ Õ°Õ¡Õ½ÖÕ¥Õ¶</translation>
<translation id="7932579305932748336">Ô¾Õ¡Õ®Õ¯Õ¸Ö‚ÕµÕ©</translation>
<translation id="79338296614623784">Õ„Õ¸Ö‚Õ¿Ö„Õ¡Õ£Ö€Õ¥Ö„ Õ¾Õ¡Õ¾Õ¥Ö€ Õ°Õ¥Õ¼Õ¡Õ­Õ¸Õ½Õ¡Õ°Õ¡Õ´Õ¡Ö€</translation>
@@ -2161,13 +2214,14 @@
<translation id="7976214039405368314">Õ‰Õ¡ÖƒÕ¡Õ¦Õ¡Õ¶Ö Õ·Õ¡Õ¿ Õ°Õ¡Ö€ÖÕ¸Ö‚Õ´Õ¶Õ¥Ö€</translation>
<translation id="7977538094055660992">Ô±Ö€Õ¿Õ¡Õ®Õ´Õ¡Õ¶ Õ½Õ¡Ö€Ö„</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">Ô¿Õ¡ÕºÕ¾Õ¡Õ® Õ§ Õ°Õ¥Õ¿Ö‡ÕµÕ¡Õ¬ Ö„Õ¡Ö€Õ¿Õ« Õ°Õ¥Õ¿Õ</translation>
<translation id="798134797138789862">Ô¿Õ¡Ö€Õ¸Õ² Õ§ Õ°Õ¡ÕµÖÕ¥Õ¬ Õ¾Õ«Ö€Õ¿Õ¸Ö‚Õ¡Õ¬ Õ«Ö€Õ¡Õ¯Õ¡Õ¶Õ¸Ö‚Õ©ÕµÕ¡Õ¶ Õ±Õ¥Ö€ Õ½Õ¡Ö€Ö„Õ¥Ö€Õ¶ Õ¸Ö‚ Õ¿Õ¾ÕµÕ¡Õ¬Õ¶Õ¥Ö€Õ¨ Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¥Õ¬Õ¸Ö‚ Õ©Õ¸Ö‚ÕµÕ¬Õ¿Õ¾Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶</translation>
<translation id="7984945080620862648">Ô±ÕµÕ½ ÕºÕ¡Õ°Õ«Õ¶ Õ¹Õ¥Ö„ Õ¯Õ¡Ö€Õ¸Õ² Õ¡ÕµÖÕ¥Õ¬Õ¥Õ¬ <ph name="SITE" />, Ö„Õ¡Õ¶Õ« Õ¸Ö€ Õ¯Õ¡ÕµÖ„Õ¨ Õ¯Õ¸Õ¤Õ¡Õ¾Õ¸Ö€Õ¾Õ¡Õ® Õ°Õ¡Õ¾Õ¡Õ¿Õ¡Ö€Õ´Õ¡Õ£Ö€Õ¥Ö€ Õ§ Õ¸Ö‚Õ²Õ¡Ö€Õ¯Õ¥Õ¬, Õ¸Ö€Õ¸Õ¶Ö„ Chrome-Õ¨ Õ¹Õ« Õ¯Õ¡Ö€Õ¸Õ² Õ´Õ·Õ¡Õ¯Õ¥Õ¬: Õ‘Õ¡Õ¶ÖÕ¡ÕµÕ«Õ¶ Õ½Õ­Õ¡Õ¬Õ¶Õ¥Ö€Õ¶ Õ¸Ö‚ Õ°Õ¡Ö€Õ±Õ¡Õ¯Õ¸Ö‚Õ´Õ¶Õ¥Ö€Õ¨ Õ½Õ¸Õ¾Õ¸Ö€Õ¡Õ¢Õ¡Ö€ ÕªÕ¡Õ´Õ¡Õ¶Õ¡Õ¯Õ¡Õ¾Õ¸Ö€ Õ¢Õ¶Õ¸Ö‚ÕµÕ© Õ¥Õ¶ Õ¯Ö€Õ¸Ö‚Õ´, Õ¸Ö‚Õ½Õ¿Õ«, Õ°Õ¡Õ¾Õ¡Õ¶Õ¡Õ¢Õ¡Ö€, Õ¡ÕµÕ½ Õ§Õ»Õ¨ Õ´Õ¡Õ¿Õ¹Õ¥Õ¬Õ« Õ¯Õ¬Õ«Õ¶Õ« Õ¡Õ¾Õ¥Õ¬Õ« Õ¸Ö‚Õ·:</translation>
-<translation id="79859296434321399">Ô¼Ö€Õ¡ÖÕ¾Õ¡Õ® Õ«Ö€Õ¡Õ¯Õ¡Õ¶Õ¸Ö‚Õ©ÕµÕ¡Õ¶ Õ¼Õ¥ÕªÕ«Õ´Õ¸Ö‚Õ´ Õ¢Õ¸Õ¾Õ¡Õ¶Õ¤Õ¡Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¨ Õ¤Õ«Õ¿Õ¥Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€ Õ¿Õ¥Õ²Õ¡Õ¤Ö€Õ¥Ö„ ARCore Õ°Õ¡Õ¾Õ¥Õ¬Õ¾Õ¡Õ®Õ¨</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">Ô±Õ´Ö€Õ¡Õ¯Õ¡Ö€</translation>
<translation id="7992044431894087211">Ô·Õ¯Ö€Õ¡Õ¶Õ« ÖÕ¸Ö‚ÖÕ¡Õ¤Ö€Õ¸Ö‚Õ´Õ¨ <ph name="APPLICATION_TITLE" /> Õ°Õ¡Õ¾Õ¥Õ¬Õ¾Õ¡Õ®Õ«Õ¶ Õ¾Õ¥Ö€Õ¡Õ¯Õ¡Õ¶Õ£Õ¶Õ¾Õ¥Õ¬ Õ§</translation>
<translation id="7995512525968007366">Õ†Õ·Õ¾Õ¡Õ® Õ¹Õ§</translation>
+<translation id="7998269595945679889">«ԲաÖÕ¥Õ¬ Õ«Õ¶Õ¯Õ¸Õ£Õ¶Õ«Õ¿Õ¸ ներդիր» Õ¯Õ¸Õ³Õ¡Õ¯Ö‰ ÕÕ¥Õ²Õ´Õ¥Ö„ EnterÕ Õ¶Õ¸Ö€ Õ«Õ¶Õ¯Õ¸Õ£Õ¶Õ«Õ¿Õ¸ Õ¶Õ¥Ö€Õ¤Õ«Ö€ Õ¢Õ¡ÖÕ¥Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€Ö‰</translation>
<translation id="800218591365569300">Õ“Õ¡Õ¯Õ¥Ö„ Õ´ÕµÕ¸Ö‚Õ½ Õ¶Õ¥Ö€Õ¤Õ«Ö€Õ¶Õ¥Ö€Õ¶ Õ¸Ö‚ Õ®Ö€Õ¡Õ£Ö€Õ¥Ö€Õ¨Õ Õ¿Õ¡Ö€Õ¡Õ®Ö„ Õ¡Õ¦Õ¡Õ¿Õ¥Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€:</translation>
<translation id="8004582292198964060">Ô´Õ«Õ¿Õ¡Ö€Õ¯Õ«Õ¹</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{Ô±ÕµÕ½ Ö„Õ¡Ö€Õ¿Õ« Õ¿Õ¾ÕµÕ¡Õ¬Õ¶Õ¥Ö€Õ¨ Ö‡ Õ¾Õ³Õ¡Ö€Õ¡ÕµÕ«Õ¶ Õ°Õ¡Õ½ÖÕ¥Õ¶ Õ¯ÕºÕ¡Õ°Õ¾Õ¥Õ¶: Ô´Õ¸Ö‚Ö„ Õ¯Õ¯Õ¡Ö€Õ¸Õ²Õ¡Õ¶Õ¡Ö„ Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¥Õ¬ Ö„Õ¡Ö€Õ¿Õ¨, Õ¥Ö€Õ¢ Õ´Õ¿Õ¶Õ¥Ö„ <ph name="USER_EMAIL" /> Õ°Õ¡Õ·Õ«Õ¾:}one{Ô±ÕµÕ½ Ö„Õ¡Ö€Õ¿Õ« Õ¿Õ¾ÕµÕ¡Õ¬Õ¶Õ¥Ö€Õ¨ Ö‡ Õ¾Õ³Õ¡Ö€Õ¡ÕµÕ«Õ¶ Õ°Õ¡Õ½ÖÕ¥Õ¶ Õ¯ÕºÕ¡Õ°Õ¾Õ¥Õ¶: Ô´Õ¸Ö‚Ö„ Õ¯Õ¯Õ¡Ö€Õ¸Õ²Õ¡Õ¶Õ¡Ö„ Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¥Õ¬ Ö„Õ¡Ö€Õ¿Õ¨, Õ¥Ö€Õ¢ Õ´Õ¿Õ¶Õ¥Ö„ <ph name="USER_EMAIL" /> Õ°Õ¡Õ·Õ«Õ¾:}other{Ô±ÕµÕ½ Ö„Õ¡Ö€Õ¿Õ¥Ö€Õ« Õ¿Õ¾ÕµÕ¡Õ¬Õ¶Õ¥Ö€Õ¨ Ö‡ Õ¾Õ³Õ¡Ö€Õ¡ÕµÕ«Õ¶ Õ°Õ¡Õ½ÖÕ¥Õ¶Õ¥Ö€Õ¨ Õ¯ÕºÕ¡Õ°Õ¾Õ¥Õ¶: Ô´Õ¸Ö‚Ö„ Õ¯Õ¯Õ¡Ö€Õ¸Õ²Õ¡Õ¶Õ¡Ö„ Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¥Õ¬ Ö„Õ¡Ö€Õ¿Õ¥Ö€Õ¨, Õ¥Ö€Õ¢ Õ´Õ¿Õ¶Õ¥Ö„ <ph name="USER_EMAIL" /> Õ°Õ¡Õ·Õ«Õ¾:}}</translation>
@@ -2227,6 +2281,7 @@
<translation id="8202370299023114387">Õ€Õ¡Õ¯Õ¡Õ½Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶</translation>
<translation id="8206978196348664717">Prc4 (Õ®Ö€Õ¡Ö€)</translation>
<translation id="8211406090763984747">Ô¿Õ¡ÕºÕ¶ Õ¡Õ¶Õ¾Õ¿Õ¡Õ¶Õ£ Õ§</translation>
+<translation id="8217240300496046857">Ô¿Õ¡ÕµÖ„Õ¥Ö€Õ¨ Õ¹Õ¥Õ¶ Õ¯Õ¡Ö€Õ¸Õ² Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¥Õ¬ Ö„Õ¸Ö‚Ö„Õ«Õ¶Õ¥Ö€Õ¨, Õ¸Ö€Õ¸Õ¶Ö Õ´Õ«Õ»Õ¸ÖÕ¸Õ¾ Õ°Õ¥Õ¿Õ¡Õ£Õ®Õ¾Õ¸Ö‚Õ´ Õ¥Õ¶ Õ±Õ¥Ö€ Õ£Õ¸Ö€Õ®Õ¸Õ²Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¨ Õ°Õ¡Õ´Õ¡ÖÕ¡Õ¶ÖÕ¸Ö‚Õ´Ö‰ ÕˆÖ€Õ¸Õ· Õ¯Õ¡ÕµÖ„Õ¥Ö€Õ¸Ö‚Õ´ Õ£Õ¸Ö€Õ®Õ¡Õ¼Õ¸Ö‚ÕµÕ©Õ¶Õ¥Ö€Õ¨ Õ¯Õ¡Ö€Õ¸Õ² Õ¥Õ¶ Õ¹Õ¡Õ·Õ­Õ¡Õ¿Õ¥Õ¬Ö‰</translation>
<translation id="8218327578424803826">Õ†Õ·Õ¡Õ¶Õ¡Õ¯Õ¾Õ¡Õ® Õ¿Õ¥Õ²Õ¡Õ¤Ö€Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ</translation>
<translation id="8220146938470311105">C7/C6 (Õ®Ö€Õ¡Ö€)</translation>
<translation id="8225771182978767009">Ô±Õ¶Õ±Õ¶, Õ¸Õ¾ Õ¯Õ¡Ö€Õ£Õ¡Õ¾Õ¸Ö€Õ¥Õ¬ Õ§ Õ¡ÕµÕ½ Õ°Õ¡Õ´Õ¡Õ¯Õ¡Ö€Õ£Õ«Õ¹Õ¨, Õ¶Õ·Õ¥Õ¬ Õ§, Õ¸Ö€ÕºÕ¥Õ½Õ¦Õ« Õ¡ÕµÕ½ Õ¯Õ¡ÕµÖ„Õ¶ Õ¡Ö€Õ£Õ¥Õ¬Õ¡ÖƒÕ¡Õ¯Õ¾Õ«:</translation>
@@ -2267,14 +2322,9 @@
<translation id="830498451218851433">Ô¾Õ¡Õ¬Õ¸Ö‚Õ´ Õ¯Õ«Õ½Õ¸Õ¾ Õ¹Õ¡Öƒ</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">ÕÕ¥Õ²Õ¡Õ¤Ö€Õ¾Õ¡Õ® Õ°Õ¡Õ¾Õ¥Õ¬Õ¾Õ¡Õ®Õ¶Õ¥Ö€Õ¨ Ö‡ Õ¤Ö€Õ¡Õ¶Ö Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ´Õ¡Õ¶ Õ°Õ¡Õ³Õ¡Õ­Õ¡Õ¯Õ¡Õ¶Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¨</translation>
+<translation id="8317207217658302555">Ô¹Õ¡Ö€Õ´Õ¡ÖÕ¶Õ¥ÕžÕ¬ ARCore-Õ¨</translation>
<translation id="831997045666694187">Õ„Õ«Õ¶Õ¹Ö‡ Õ¥Ö€Õ¥Õ¯Õ¸</translation>
<translation id="8321476692217554900">Õ®Õ¡Õ¶Õ¸Ö‚ÖÕ¸Ö‚Õ´Õ¶Õ¥Ö€</translation>
-<translation id="8328484624016508118">ÔµÖ€Õ¢ Õ¤Õ¸Ö‚Ö„ ÖƒÕ¡Õ¯Õ¥Ö„ Õ¢Õ¸Õ¬Õ¸Ö€ Õ«Õ¶Õ¯Õ¸Õ£Õ¶Õ«Õ¿Õ¸ Õ¶Õ¥Ö€Õ¤Õ«Ö€Õ¶Õ¥Ö€Õ¨, Chrome-Õ¸Ö‚Õ´ Õ¯Õ»Õ¶Õ»Õ¾Õ¥Õ¶Õ
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Ô±ÕµÕ½ Õ½Õ¡Ö€Ö„Õ« Õ¤Õ«Õ¿Õ¡Ö€Õ¯Õ«Õ¹Õ¸Ö‚Õ´ Õ±Õ¥Ö€ Õ¯Õ¡Õ¿Õ¡Ö€Õ¡Õ® Õ£Õ¸Ö€Õ®Õ¸Õ²Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¨<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Ô±ÕµÕ½ Õ½Õ¡Ö€Ö„Õ¸Ö‚Õ´ Õ±Õ¥Ö€ Õ¯Õ¡Õ¿Õ¡Ö€Õ¡Õ® Õ¸Ö€Õ¸Õ¶Õ¸Ö‚Õ´Õ¶Õ¥Ö€Õ« ÕºÕ¡Õ´Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¨<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />ÕÖ‡Õ¥Ö€Õ¸Ö‚Õ´ Õ´Õ¸Ö‚Õ¿Ö„Õ¡Õ£Ö€Õ¾Õ¡Õ® Õ¿Õ¥Õ²Õ¥Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¨<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489"><ph name="HOST_NAME" /> Õ´Õ¸Ö‚Õ¿Ö„Õ¨ Õ´Õ¥Ö€ÕªÕ¾Õ¥Õ¬ Õ§</translation>
<translation id="833262891116910667">Õ†Õ·Õ¥Õ¬</translation>
<translation id="8339163506404995330"><ph name="LANGUAGE" /> Õ§Õ»Õ¥Ö€Õ¨ Õ¹Õ¥Õ¶ Õ©Õ¡Ö€Õ£Õ´Õ¡Õ¶Õ¾Õ«</translation>
@@ -2326,6 +2376,7 @@
<translation id="8507227106804027148">Õ€Ö€Õ¡Õ´Õ¡Õ¶Õ¡Õ¿Õ¸Õ²</translation>
<translation id="8508648098325802031">ÕˆÖ€Õ¸Õ¶Õ´Õ¡Õ¶ ÕºÕ¡Õ¿Õ¯Õ¥Ö€Õ¡Õ¯</translation>
<translation id="8511402995811232419">Ô¿Õ¡Õ¼Õ¡Õ¾Õ¡Ö€Õ¥Õ¬ Ö„Õ¸Ö‚Ö„Õ«Õ¶Õ¥Ö€Õ¨</translation>
+<translation id="8519753333133776369">HID Õ½Õ¡Ö€Ö„Õ¨ Õ©Õ¸Ö‚ÕµÕ¬Õ¡Õ¿Ö€Õ¾Õ¡Õ® Õ§ Õ±Õ¥Ö€ Õ¡Õ¤Õ´Õ«Õ¶Õ«Õ½Õ¿Ö€Õ¡Õ¿Õ¸Ö€Õ« Õ¯Õ¸Õ²Õ´Õ«Ö</translation>
<translation id="8522552481199248698">Chrome-Õ¨ Õ¯Ö…Õ£Õ¶Õ« ÕºÕ¡Õ·Õ¿ÕºÕ¡Õ¶Õ¥Õ¬ Õ±Õ¥Ö€ Google Õ°Õ¡Õ·Õ«Õ¾Õ¨ Ö‡ ÖƒÕ¸Õ­Õ¥Õ¬ Õ£Õ¡Õ²Õ¿Õ¶Õ¡Õ¢Õ¡Õ¼Õ¨Ö‰</translation>
<translation id="8530813470445476232">Õ‹Õ¶Õ»Õ¥Ö„ Õ±Õ¥Ö€ Õ¡ÕµÖÕ¥Õ¬Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ« ÕºÕ¡Õ¿Õ´Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¨, Ö„Õ¸Ö‚Ö„Õ«Õ¶Õ¥Ö€Õ¨, Ö„Õ¥Õ·Õ¨ Ö‡ Õ¡ÕµÕ¬ Õ¿Õ¾ÕµÕ¡Õ¬Õ¶Õ¥Ö€ Chrome-Õ« Õ¯Õ¡Ö€Õ£Õ¡Õ¾Õ¸Ö€Õ¸Ö‚Õ´Õ¶Õ¥Ö€Õ¸Ö‚Õ´</translation>
<translation id="8533619373899488139">Ô±Ö€Õ£Õ¥Õ¬Õ¡ÖƒÕ¡Õ¯Õ¾Õ¡Õ® URL-Õ¶Õ¥Ö€Õ« ÖÕ¸Ö‚ÖÕ¡Õ¯Õ¨ Ö‡ Õ±Õ¥Ö€ Õ°Õ¡Õ´Õ¡Õ¯Õ¡Ö€Õ£Õ« Õ¡Õ¤Õ´Õ«Õ¶Õ«Õ½Õ¿Ö€Õ¡Õ¿Õ¸Ö€Õ« Õ¯Õ¸Õ²Õ´Õ«Ö Õ¯Õ«Ö€Õ¡Õ¼Õ¾Õ¡Õ® Õ´ÕµÕ¸Ö‚Õ½ Õ¯Õ¡Õ¶Õ¸Õ¶Õ¶Õ¥Ö€Õ¨ Õ¿Õ¥Õ½Õ¶Õ¥Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€ Õ¡ÕµÖÕ¥Õ¬Õ¥Ö„ &lt;strong&gt;chrome://policy&lt;/strong&gt;Ö‰</translation>
@@ -2337,7 +2388,6 @@
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{Ô¶Ö€Õ¸ÕµÕ¡ÖÕ¶Õ¥Õ¬ Õ©Õ¸Ö‚ÕµÕ¬Õ¿Õ¾Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¨}one{Ô¶Ö€Õ¸ÕµÕ¡ÖÕ¶Õ¥Õ¬ Õ©Õ¸Ö‚ÕµÕ¬Õ¿Õ¾Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¨}other{Ô¶Ö€Õ¸ÕµÕ¡ÖÕ¶Õ¥Õ¬ Õ©Õ¸Ö‚ÕµÕ¬Õ¿Õ¾Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¨}}</translation>
<translation id="8555010941760982128">Õ•Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¥Ö„ Õ¡ÕµÕ½ Õ¯Õ¸Õ¤Õ¨ Õ¾Õ³Õ¡Ö€Õ´Õ¡Õ¶ ÕªÕ¡Õ´Õ¡Õ¶Õ¡Õ¯</translation>
<translation id="8557066899867184262">CVC Õ¯Õ¸Õ¤Õ¨ Õ£Ö€Õ¾Õ¡Õ® Õ§ Ö„Õ¡Ö€Õ¿Õ« Õ°Õ¡Õ¯Õ¡Õ¼Õ¡Õ¯ Õ¯Õ¸Õ²Õ´Õ¸Ö‚Õ´Ö‰</translation>
-<translation id="8558485628462305855">Ô¼Ö€Õ¡ÖÕ¾Õ¡Õ® Õ«Ö€Õ¡Õ¯Õ¡Õ¶Õ¸Ö‚Õ©ÕµÕ¡Õ¶ Õ¼Õ¥ÕªÕ«Õ´Õ¸Ö‚Õ´ Õ¢Õ¸Õ¾Õ¡Õ¶Õ¤Õ¡Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¨ Õ¤Õ«Õ¿Õ¥Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€ Õ©Õ¡Ö€Õ´Õ¡ÖÖ€Õ¥Ö„ ARCore Õ°Õ¡Õ¾Õ¥Õ¬Õ¾Õ¡Õ®Õ¨</translation>
<translation id="8559762987265718583"><ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />-Õ« Õ°Õ¥Õ¿ Õ¯Õ¡ÕºÕ¡Õ¯ÖÕ¸Ö‚Õ´ Õ¹Õ« Õ¯Õ¡Ö€Õ¸Õ² Õ°Õ¡Õ½Õ¿Õ¡Õ¿Õ¾Õ¥Õ¬, Ö„Õ¡Õ¶Õ« Õ¸Ö€ Õ±Õ¥Ö€ Õ½Õ¡Ö€Ö„Õ« Õ¡Õ´Õ½Õ¡Õ©Õ«Õ¾Õ¨ Ö‡ ÕªÕ¡Õ´Õ¨ (<ph name="DATE_AND_TIME" />) Õ½Õ­Õ¡Õ¬ Õ§:</translation>
<translation id="8564182942834072828">Õ„Õ« Ö„Õ¡Õ¶Õ« ÖƒÕ¡Õ½Õ¿Õ¡Õ©Õ¸Ö‚Õ²Õ©/Õ¹Õ¡Õ¼Õ¡Õ¶Õ±Õ¶Õ¡ÖÕ¾Õ¡Õ® ÕºÕ¡Õ¿Õ³Õ¥Õ¶Õ¶Õ¥Ö€</translation>
<translation id="8564985650692024650">Ô½Õ¸Ö€Õ°Õ¸Ö‚Ö€Õ¤ Õ¥Õ¶Ö„ Õ¿Õ¡Õ¬Õ«Õ½ Õ¾Õ¥Ö€Õ¡Õ¯Õ¡ÕµÕ¥Õ¬ <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" />-Õ« Õ±Õ¥Ö€ Õ£Õ¡Õ²Õ¿Õ¶Õ¡Õ¢Õ¡Õ¼Õ¨, Õ¥Õ©Õ¥ Õ¡ÕµÕ¶ Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¥Õ¬ Õ¥Ö„ Õ¡ÕµÕ¬ Õ¯Õ¡ÕµÖ„Õ¥Ö€Õ¸Ö‚Õ´:</translation>
@@ -2356,6 +2406,7 @@
<translation id="865032292777205197">Õ·Õ¡Ö€ÕªÕ´Õ¡Õ¶ Õ¿Õ¾Õ«Õ¹Õ¶Õ¥Ö€</translation>
<translation id="8663226718884576429">ÕÕ¥Õ²Õ¥Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶ ÕºÕ¡Õ¿Õ¾Õ¥Ö€Õ« Õ´Õ¡Õ½Õ«Õ¶, <ph name="TOTAL_LABEL" />, Õ´Õ¡Õ¶Ö€Õ¡Õ´Õ¡Õ½Õ¶Õ¥Ö€</translation>
<translation id="8666678546361132282">Ô±Õ¶Õ£Õ¬Õ«Õ¡Õ¯Õ¡Õ¶</translation>
+<translation id="8669306706049782872">Õ•Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¥Õ¬ Õ±Õ¥Ö€ Õ§Õ¯Ö€Õ¡Õ¶Õ¶Õ¥Ö€Õ« Õ´Õ¡Õ½Õ«Õ¶ Õ¿Õ¥Õ²Õ¥Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¨Õ ÕºÕ¡Õ¿Õ¸Ö‚Õ°Õ¡Õ¶Õ¶Õ¥Ö€ Õ¢Õ¡ÖÕ¥Õ¬Õ¸Ö‚ Ö‡ Õ¿Õ¥Õ²Õ¡Õ¯Õ¡ÕµÕ¥Õ¬Õ¸Ö‚ Õ¶ÕºÕ¡Õ¿Õ¡Õ¯Õ¸Õ¾</translation>
<translation id="867224526087042813">ÕÕ¿Õ¸Ö€Õ¡Õ£Ö€Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶</translation>
<translation id="8676424191133491403">Ô±Õ¼Õ¡Õ¶Ö Õ°Õ¥Õ¿Õ¡Õ±Õ£Õ´Õ¡Õ¶</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, ÕºÕ¡Õ¿Õ¡Õ½Õ­Õ¡Õ¶, <ph name="ANSWER" /></translation>
@@ -2382,6 +2433,7 @@
<translation id="8731544501227493793">«Կառավարել գաղտնաբառերը» կոճակ։ Chrome-ի կարգավորումներում գաղտնաբառերը դիտելու և կառավարելու համար սեղմեք Enter։</translation>
<translation id="8734529307927223492">ÕÕ¥Ö€ <ph name="DEVICE_TYPE" /> Õ½Õ¡Ö€Ö„Õ¨ Õ¯Õ¡Õ¼Õ¡Õ¾Õ¡Ö€Õ¾Õ¸Ö‚Õ´ Õ§ <ph name="MANAGER" />-Õ« Õ¯Õ¸Õ²Õ´Õ«Ö</translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />Ö‰ Õ†Õ¸Ö€ Õ«Õ¶Õ¯Õ¸Õ£Õ¶Õ«Õ¿Õ¸ ÕºÕ¡Õ¿Õ¸Ö‚Õ°Õ¡Õ¶ Õ¢Õ¡ÖÕ¥Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€ Õ½Õ¥Õ²Õ´Õ¥Ö„ Tab, Õ¡ÕºÕ¡Õ EnterÖ‰</translation>
+<translation id="8737685506611670901">Ô²Õ¡ÖÕ¥Õ¬ <ph name="PROTOCOL" /> -Õ« Õ°Õ²Õ¸Ö‚Õ´Õ¶Õ¥Ö€Õ¨ <ph name="REPLACED_HANDLER_TITLE" />-Õ« ÖƒÕ¸Õ­Õ¡Ö€Õ¥Õ¶</translation>
<translation id="8738058698779197622">Ô±Õ¶Õ¾Õ¿Õ¡Õ¶Õ£ Õ¯Õ¡ÕºÕ¡Õ¯ÖÕ¸Ö‚Õ´ Õ°Õ¡Õ½Õ¿Õ¡Õ¿Õ¥Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€ Õ±Õ¥Ö€ ÕªÕ¡Õ´Õ¡ÖÕ¸Ö‚ÕµÖÕ¨ ÕºÕ¥Õ¿Ö„ Õ§ Õ³Õ«Õ·Õ¿ Õ¯Õ¡Ö€Õ£Õ¡Õ¾Õ¸Ö€Õ¾Õ¡Õ® Õ¬Õ«Õ¶Õ«: ÕŠÕ¡Õ¿Õ³Õ¡Õ¼Õ¶ Õ¡ÕµÕ¶ Õ§, Õ¸Ö€ Õ¾Õ¯Õ¡ÕµÕ¡Õ£Ö€Õ¥Ö€Õ¨, Õ¸Ö€Õ¸Õ¶Ö„ Õ¯Õ¡ÕµÖ„Õ¥Ö€Õ¶ Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¸Ö‚Õ´ Õ¥Õ¶ Õ«Ö€Õ¥Õ¶Ö Õ¶Õ¸Ö‚ÕµÕ¶Õ¡Õ¯Õ¡Õ¶Õ¡ÖÕ¶Õ¥Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€, Õ¾Õ¡Õ¾Õ¥Ö€ Õ¥Õ¶ Õ¬Õ«Õ¶Õ¸Ö‚Õ´ Õ´Õ«Õ¡ÕµÕ¶ Õ¸Ö€Õ¸Õ·Õ¡Õ¯Õ« ÕªÕ¡Õ´Õ¡Õ¶Õ¡Õ¯Õ¡Õ°Õ¡Õ¿Õ¾Õ¡Õ®Õ« Õ¨Õ¶Õ©Õ¡ÖÖ„Õ¸Ö‚Õ´: Õ”Õ¡Õ¶Õ« Õ¸Ö€ Õ±Õ¥Ö€ Õ½Õ¡Ö€Ö„Õ« ÕªÕ¡Õ´Õ¡ÖÕ¸Ö‚ÕµÖÕ¨ Õ½Õ­Õ¡Õ¬ Õ§, Chromium-Õ¨ Õ¹Õ« Õ¯Õ¡Ö€Õ¸Õ² Õ½Õ¿Õ¸Ö‚Õ£Õ¥Õ¬ Õ¡ÕµÕ½ Õ¾Õ¯Õ¡ÕµÕ¡Õ£Ö€Õ¥Ö€Õ¨:</translation>
<translation id="8740359287975076522"><ph name="HOST_NAME" />-Õ« &lt;abbr id="dnsDefinition"&gt;DNS Õ°Õ¡Õ½ÖÕ¥Õ¶&lt;/abbr&gt; Õ¹Õ°Õ¡Õ»Õ¸Õ²Õ¾Õ¥Ö Õ£Õ¿Õ¶Õ¥Õ¬: Ô¿Õ¡Õ¿Õ¡Ö€Õ¾Õ¸Ö‚Õ´ Õ§ Õ­Õ¶Õ¤Ö€Õ« Õ¡Õ­Õ¿Õ¸Ö€Õ¸Õ·Õ¸Ö‚Õ´:</translation>
<translation id="8742371904523228557"><ph name="ORIGIN" /> Õ¯Õ¡ÕµÖ„Õ« Õ±Õ¥Ö€ Õ¯Õ¸Õ¤Õ¨Õ <ph name="ONE_TIME_CODE" /></translation>
@@ -2409,6 +2461,7 @@
<translation id="883848425547221593">Ô±ÕµÕ¬ Õ§Õ»Õ¡Õ¶Õ«Õ·Õ¶Õ¥Ö€</translation>
<translation id="884264119367021077">Ô±Õ¼Õ¡Ö„Õ´Õ¡Õ¶ Õ°Õ¡Õ½ÖÕ¥</translation>
<translation id="884923133447025588">Õ€Õ¥Õ¿Õ¯Õ¡Õ¶Õ¹Õ´Õ¡Õ¶ Õ´Õ¥Õ­Õ¡Õ¶Õ«Õ¦Õ´ Õ¹Õ« Õ°Õ¡ÕµÕ¿Õ¶Õ¡Õ¢Õ¥Ö€Õ¾Õ¥Õ¬:</translation>
+<translation id="8849262850971482943">Ô±Õ¾Õ¥Õ¬Õ¡ÖÕ¾Õ¡Õ® Õ¡Õ¶Õ¾Õ¿Õ¡Õ¶Õ£Õ¸Ö‚Õ©ÕµÕ¡Õ¶ Õ¯Õ¡Ö€Õ£Õ¡Õ¾Õ¸Ö€Õ´Õ¡Õ¶ Õ°Õ¡Õ´Õ¡Ö€ Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¥Ö„ Õ±Õ¥Ö€ Õ¾Õ«Ö€Õ¿Õ¸Ö‚Õ¡Õ¬ Ö„Õ¡Ö€Õ¿Õ¨</translation>
<translation id="885730110891505394">Õ€Õ¡Õ´Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¸Ö‚Õ´ Google-Õ« Õ°Õ¥Õ¿</translation>
<translation id="8858065207712248076">Ô½Õ¸Ö€Õ°Õ¸Ö‚Ö€Õ¤ Õ¥Õ¶Ö„ Õ¿Õ¡Õ¬Õ«Õ½ Õ¾Õ¥Ö€Õ¡Õ¯Õ¡ÕµÕ¥Õ¬ <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" />-Õ« Õ±Õ¥Ö€ Õ£Õ¡Õ²Õ¿Õ¶Õ¡Õ¢Õ¡Õ¼Õ¨, Õ¥Õ©Õ¥ Õ¡ÕµÕ¶ Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¥Õ¬ Õ¥Ö„ Õ¡ÕµÕ¬ Õ¯Õ¡ÕµÖ„Õ¥Ö€Õ¸Ö‚Õ´:</translation>
<translation id="885906927438988819">ÔµÕ©Õ¥ Õ¿Õ¡Õ¼Õ¡Õ½Õ­Õ¡Õ¬ Õ¹Õ¯Õ¡, <ph name="BEGIN_LINK" />Õ£Õ¸Ö€Õ®Õ¡Ö€Õ¯Õ¥Ö„ Windows-Õ« ÖÕ¡Õ¶ÖÕ« Õ¤Õ«Õ¡Õ£Õ¶Õ¸Õ½Õ¿Õ«Õ¯Õ¡Õ¶<ph name="END_LINK" />Ö‰</translation>
@@ -2453,11 +2506,12 @@
<translation id="899688752321268742"><ph name="URL" /> Õ¯Õ¡ÕµÖ„Õ¶ Õ¸Ö‚Õ¦Õ¸Ö‚Õ´ Õ§ Õ¿Õ¥Õ²Õ¥Õ¯Õ¡Õ¶Õ¡Õ¬, Õ¥Ö€Õ¢ Õ¤Õ¸Ö‚Ö„ Õ¡Õ¯Õ¿Õ«Õ¾Õ¸Ö€Õ¥Õ¶ Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¸Ö‚Õ´ Õ¥Ö„ Õ¡ÕµÕ½ Õ½Õ¡Ö€Ö„Õ¨</translation>
<translation id="8996941253935762404">Ô¿Õ¡ÕµÖ„Õ¨, Õ¸Ö€Õ¨ ÕºÕ¡Õ¿Ö€Õ¡Õ½Õ¿Õ¾Õ¸Ö‚Õ´ Õ¥Ö„ Õ¡ÕµÖÕ¥Õ¬Õ¥Õ¬, ÕºÕ¡Ö€Õ¸Ö‚Õ¶Õ¡Õ¯Õ¸Ö‚Õ´ Õ§ Õ¾Õ¶Õ¡Õ½Õ¡Õ¢Õ¥Ö€ Õ®Ö€Õ¡Õ£Ö€Õ¥Ö€</translation>
<translation id="8997023839087525404">ÕÕ¥Ö€Õ¾Õ¥Ö€Õ¨ Õ¶Õ¥Ö€Õ¯Õ¡ÕµÕ¡ÖÖ€Õ¥Õ¬ Õ§ Õ´Õ« Õ¾Õ¯Õ¡ÕµÕ¡Õ£Õ«Ö€, Õ¸Ö€Õ¨ «Վկայագրերի Õ©Õ¡ÖƒÕ¡Õ¶Öիկություն» Õ¯Õ¡Õ¶Õ¸Õ¶Õ« Õ´Õ«Õ»Õ¸ÖÕ¸Õ¾ Õ°Ö€Õ¡ÕºÕ¡Ö€Õ¡Õ¯Õ¡ÕµÕ¶Õ¸Ö€Õ¥Õ¶ Õ¹Õ« Õ¢Õ¡ÖÕ¡Õ°Õ¡ÕµÕ¿Õ¾Õ¥Õ¬: ÕˆÖ€Õ¸Õ· Õ¾Õ¯Õ¡ÕµÕ¡Õ£Ö€Õ¥Ö€Õ« Õ°Õ¡Õ´Õ¡Ö€ Õ½Õ¡ ÕºÕ¡Ö€Õ¿Õ¡Õ¤Õ«Ö€ ÕºÕ¡ÕµÕ´Õ¡Õ¶ Õ§, Õ¸Ö€ÕºÕ¥Õ½Õ¦Õ« Õ¤Ö€Õ¡Õ¶Ö„ Õ¬Õ«Õ¶Õ¥Õ¶ Õ¾Õ½Õ¿Õ¡Õ°Õ¥Õ¬Õ« Ö‡ ÕºÕ¡Õ·Õ¿ÕºÕ¡Õ¶Õ¥Õ¶ Õ°Õ¡Ö€Õ±Õ¡Õ¯Õ¾Õ¸Õ²Õ¶Õ¥Ö€Õ«Ö:</translation>
-<translation id="9001074447101275817"><ph name="DOMAIN" /> Õ´Õ«Õ»Õ¶Õ¸Ö€Õ¤ Õ½Õ¥Ö€Õ¾Õ¥Ö€Õ« Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ´Õ¡Õ¶ Õ°Õ¡Õ´Õ¡Ö€ Õ¡Õ¶Õ°Ö€Õ¡ÕªÕ¥Õ·Õ¿ Õ§ Õ´Õ¸Ö‚Õ¿Ö„Õ¡Õ£Ö€Õ¥Õ¬ Ö…Õ£Õ¿Õ¡Õ¶Õ¸Ö‚Õ¶ Ö‡ Õ£Õ¡Õ²Õ¿Õ¶Õ¡Õ¢Õ¡Õ¼:</translation>
+<translation id="9001074447101275817"><ph name="DOMAIN" /> ÕºÖ€Õ¸Ö„Õ½Õ« Õ½Õ¥Ö€Õ¾Õ¥Ö€Õ« Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ´Õ¡Õ¶ Õ°Õ¡Õ´Õ¡Ö€ Õ¡Õ¶Õ°Ö€Õ¡ÕªÕ¥Õ·Õ¿ Õ§ Õ´Õ¸Ö‚Õ¿Ö„Õ¡Õ£Ö€Õ¥Õ¬ Ö…Õ£Õ¿Õ¡Õ¶Õ¸Ö‚Õ¶ Ö‡ Õ£Õ¡Õ²Õ¿Õ¶Õ¡Õ¢Õ¡Õ¼:</translation>
<translation id="9001963517402879850">Õ‘Õ¡Õ¿Õ¯Õ¥Õ›Ö„Ö‰</translation>
<translation id="9004367719664099443">VR Õ¡Õ·Õ­Õ¡Õ¿Õ¡Õ·Ö€Õ»Õ¡Õ¶Õ¶ Õ¡Õ¯Õ¿Õ«Õ¾ Õ§</translation>
<translation id="9005998258318286617">Õ‰Õ°Õ¡Õ»Õ¸Õ²Õ¾Õ¥Ö Õ¢Õ¥Õ¼Õ¶Õ¥Õ¬ PDF ÖƒÕ¡Õ½Õ¿Õ¡Õ©Õ¸Ö‚Õ²Õ©Õ¨Ö‰</translation>
<translation id="9008201768610948239">Ô±Õ¶Õ¿Õ¥Õ½Õ¥Õ¬</translation>
+<translation id="901834265349196618">Õ§Õ¬ÖƒÕ¸Õ½Õ¿</translation>
<translation id="9020200922353704812">Ô±Õ¶Õ°Ö€Õ¡ÕªÕ¥Õ·Õ¿ Õ§ Õ¶Õ·Õ¥Õ¬ Ö„Õ¡Ö€Õ¿Õ« Õ¾Õ³Õ¡Ö€Õ¡ÕµÕ«Õ¶ Õ°Õ¡Õ½ÖÕ¥Õ¶</translation>
<translation id="9020542370529661692">Ô±ÕµÕ½ Õ§Õ»Õ¨ Õ©Õ¡Ö€Õ£Õ´Õ¡Õ¶Õ¾Õ¥Õ¬ Õ§ <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9020742383383852663">A8</translation>
@@ -2506,6 +2560,7 @@
<translation id="9150045010208374699">Õ•Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¥Õ¬ Õ¿Õ¥Õ½Õ¡Õ­ÖÕ«Õ¯Õ¨</translation>
<translation id="9150685862434908345">ÕÕ¥Ö€ Õ¡Õ¤Õ´Õ«Õ¶Õ«Õ½Õ¿Ö€Õ¡Õ¿Õ¸Ö€Õ¨ Õ¯Õ¡Ö€Õ¸Õ² Õ§ Õ°Õ¥Õ¼Õ¡Õ¯Õ¡ ÖƒÕ¸Õ­Õ¥Õ¬ Õ±Õ¥Ö€ Õ¤Õ«Õ¿Õ¡Ö€Õ¯Õ«Õ¹Õ« Õ¯Õ¡Ö€Õ£Õ¡Õ¾Õ¸Ö€Õ¸Ö‚Õ´Õ¶Õ¥Ö€Õ¨Ö‰ ÕÕ¡Ö€Ö„Õ¸Ö‚Õ´ Õ¡Ö€Õ¾Õ¸Õ² Õ£Õ¸Ö€Õ®Õ¸Õ²Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¨ Õ¶Õ¸Ö‚ÕµÕ¶ÕºÕ¥Õ½ Õ¯Õ¡Ö€Õ¸Õ² Õ¥Õ¶ Õ¯Õ¡Õ¼Õ¡Õ¾Õ¡Ö€Õ¾Õ¥Õ¬ Chrome-Õ«Ö Õ¤Õ¸Ö‚Ö€Õ½Ö‰ <ph name="BEGIN_LINK" />Ô»Õ´Õ¡Õ¶Õ¡Õ¬ Õ¡Õ¾Õ¥Õ¬Õ«Õ¶<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">Ô¹Õ¡Ö€Õ´Õ¡ÖÕ¾Õ¡Õ® Õ§</translation>
+<translation id="9155211586651734179">Ô¿ÖÕ¾Õ¡Õ® Õ¡Õ¸Ö‚Õ¤Õ«Õ¸ Õ½Õ¡Ö€Ö„Õ¥Ö€Õ¨</translation>
<translation id="9157595877708044936">Õեղակայում…</translation>
<translation id="9158625974267017556">C6 (Õ®Ö€Õ¡Ö€)</translation>
<translation id="9164029392738894042">ÕƒÕ·Õ£Ö€Õ¿Õ¸Ö‚Õ©ÕµÕ¡Õ¶ Õ½Õ¿Õ¸Ö‚Õ£Õ¸Ö‚Õ´</translation>
diff --git a/chromium/components/strings/components_strings_id.xtb b/chromium/components/strings/components_strings_id.xtb
index eb33218ffa3..b72599b2285 100644
--- a/chromium/components/strings/components_strings_id.xtb
+++ b/chromium/components/strings/components_strings_id.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">Lihat detail</translation>
<translation id="1030706264415084469"><ph name="URL" /> ingin menyimpan data berukuran besar di perangkat Anda secara permanen</translation>
<translation id="1032854598605920125">Putar searah jarum jam</translation>
+<translation id="1033329911862281889">Mode Samaran tidak membuat Anda tidak terlihat secara online:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Situs dan layanan yang digunakan situs tersebut dapat melihat kunjungan<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Perusahaan atau sekolah dapat melacak aktivitas penjelajahan<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Internet service provider dapat memantau traffic web<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">Matikan</translation>
<translation id="1036982837258183574">Tekan |<ph name="ACCELERATOR" />| untuk keluar dari mode layar penuh</translation>
<translation id="1038106730571050514">Tampilkan saran</translation>
<translation id="1038842779957582377">nama tidak diketahui</translation>
<translation id="1041998700806130099">Pesan lembar tugas</translation>
<translation id="1048785276086539861">Jika Anda mengedit anotasi, dokumen ini akan kembali ke tampilan satu halaman</translation>
-<translation id="1049743911850919806">Samaran</translation>
<translation id="1050038467049342496">Tutup aplikasi lain</translation>
<translation id="1055184225775184556">&amp;Urungkan Penambahan</translation>
<translation id="1056898198331236512">Peringatan</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">Cache kebijakan Oke</translation>
<translation id="1130564665089811311">Tombol Terjemahkan halaman, tekan Enter untuk menerjemahkan halaman ini dengan Google Terjemahan</translation>
<translation id="1131264053432022307">Gambar yang Anda Salin</translation>
+<translation id="1142846828089312304">Blokir cookie pihak ketiga dalam mode Samaran</translation>
<translation id="1150979032973867961">Server ini tidak dapat membuktikan bahwa ini adalah <ph name="DOMAIN" />; sertifikat keamanannya tidak dipercaya oleh sistem operasi komputer Anda. Hal ini dapat disebabkan oleh kesalahan konfigurasi atau penyerang memotong sambungan Anda.</translation>
<translation id="1151972924205500581">Sandi wajib ada</translation>
<translation id="1156303062776767266">Anda melihat file lokal atau bersama</translation>
@@ -64,7 +70,6 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="1178581264944972037">Jeda</translation>
<translation id="1181037720776840403">Hapus</translation>
<translation id="1186201132766001848">Periksa Sandi</translation>
-<translation id="1195210374336998651">Buka setelan aplikasi</translation>
<translation id="1195558154361252544">Notifikasi otomatis diblokir untuk semua situs kecuali situs yang Anda izinkan</translation>
<translation id="1197088940767939838">Oranye</translation>
<translation id="1201402288615127009">Berikutnya</translation>
@@ -111,7 +116,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="1307966114820526988">Fitur yang Tidak Digunakan Lagi</translation>
<translation id="1308113895091915999">Penawaran tersedia</translation>
<translation id="1312803275555673949">Bukti apa yang mendukungnya?</translation>
-<translation id="131405271941274527"><ph name="URL" /> ingin mengirim dan menerima info saat Anda mengetukkan ponsel pada perangkat NFC</translation>
+<translation id="1314311879718644478">Lihat konten augmented reality</translation>
<translation id="1314509827145471431">Jilid di kanan</translation>
<translation id="1318023360584041678">Disimpan di grup tab</translation>
<translation id="1319245136674974084">Jangan tanya lagi untuk aplikasi ini</translation>
@@ -161,6 +166,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="142858679511221695">Pengguna cloud</translation>
<translation id="1428729058023778569">Anda melihat peringatan ini karena situs ini tidak mendukung HTTPS. <ph name="BEGIN_LEARN_MORE_LINK" />Pelajari lebih lanjut<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">Cetak</translation>
+<translation id="1432187715652018471">Halaman ingin menginstal pengendali layanan.</translation>
<translation id="1432581352905426595">Kelola mesin telusur</translation>
<translation id="1436185428532214179">Dapat meminta untuk mengedit file dan folder di perangkat Anda</translation>
<translation id="1442386063175183758">Lipatan format gate di kanan</translation>
@@ -181,6 +187,12 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="1483493594462132177">Kirim</translation>
<translation id="1484290072879560759">Pilih Alamat Pengiriman</translation>
<translation id="1492194039220927094">Push kebijakan:</translation>
+<translation id="149293076951187737">Jika Anda menutup semua tab Samaran Chrome, aktivitas Anda di tab tersebut akan dihapus dari perangkat ini:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Aktivitas penjelajahan<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Histori penelusuran<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Informasi yang dimasukkan dalam formulir<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">Kembali ke tab</translation>
<translation id="1501859676467574491">Tampilkan kartu dari Akun Google Anda</translation>
<translation id="1507202001669085618">&lt;p&gt;Anda akan melihat error ini jika menggunakan portal Wi-Fi yang mengharuskan Anda login sebelum terhubung online.&lt;/p&gt;
@@ -208,6 +220,8 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="1559572115229829303">&lt;p&gt;Sambungan pribadi ke <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> tidak dapat dibuat karena tanggal dan waktu (<ph name="DATE_AND_TIME" />) perangkat Anda tidak benar.&lt;/p&gt;
&lt;p&gt;Sesuaikan tanggal dan waktu dari bagian &lt;strong&gt;Umum&lt;/strong&gt; aplikasi &lt;strong&gt;Setelan&lt;/strong&gt;.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">Administrator akan memulai ulang perangkat pada <ph name="DATE" /> pukul <ph name="TIME" /></translation>
+<translation id="156703335097561114">Informasi jaringan seperti alamat, konfigurasi antarmuka, dan kualitas koneksi</translation>
<translation id="1567040042588613346">Kebijakan ini berfungsi sebagaimana mestinya, tetapi nilai yang sama disetel di sumber lain dan digantikan oleh kebijakan ini.</translation>
<translation id="1569487616857761740">Masukkan tanggal habis masa berlaku</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="1583429793053364125">Terjadi masalah sewaktu menampilkan halaman web ini.</translation>
<translation id="1586541204584340881">Ekstensi yang telah Anda instal</translation>
<translation id="1588438908519853928">Normal</translation>
+<translation id="1589050138437146318">Instal ARCore?</translation>
<translation id="1592005682883173041">Akses Data Lokal</translation>
<translation id="1594030484168838125">Pilih</translation>
<translation id="160851722280695521">Mainkan game Dino Run di Chrome</translation>
@@ -254,7 +269,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="1711234383449478798">Diabaikan karena <ph name="POLICY_NAME" /> tidak disetel ke <ph name="VALUE" />.</translation>
<translation id="1712552549805331520"><ph name="URL" /> ingin menyimpan data di komputer lokal Anda secara permanen</translation>
<translation id="1713628304598226412">Baki 2</translation>
-<translation id="1715874602234207">F</translation>
+<translation id="1715874602234207">J</translation>
<translation id="1717218214683051432">Sensor gerakan</translation>
<translation id="1717494416764505390">Kotak surat 3</translation>
<translation id="1718029547804390981">Dokumen terlalu besar untuk dianotasi</translation>
@@ -279,6 +294,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="1763864636252898013">Server ini tidak dapat membuktikan bahwa ini adalah <ph name="DOMAIN" />; sertifikat keamanannya tidak dipercaya oleh sistem operasi perangkat Anda. Hal ini dapat disebabkan oleh kesalahan konfigurasi atau penyerang memotong sambungan Anda.</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Coba jalankan Diagnostik Jaringan Windows<ph name="END_LINK" />.</translation>
<translation id="1772163372082567643">Server yang akan Anda akses, <ph name="ORIGIN" />, telah menetapkan header yang mengharuskan kebijakan asal diterapkan ke semua permintaan yang ditujukan kepadanya. Namun, format header tersebut salah, yang membuat browser tidak dapat memenuhi permintaan Anda untuk <ph name="SITE" />. Kebijakan asal dapat digunakan oleh operator situs guna mengonfigurasi keamanan dan properti lainnya untuk sebuah situs.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Pelajari mode Samaran di Chromium lebih lanjut<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">Tab yang terbuka muncul di sini</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -406,6 +422,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="22081806969704220">Baki 3</translation>
<translation id="2212735316055980242">Kebijakan tidak ditemukan</translation>
<translation id="2213606439339815911">Mengambil entri...</translation>
+<translation id="2213612003795704869">Halaman dicetak</translation>
<translation id="2215727959747642672">Pengeditan file</translation>
<translation id="2218879909401188352">Penyerang yang saat ini berada di <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> mungkin berusaha menginstal aplikasi berbahaya yang dapat merusak perangkat, menambahkan biaya tersembunyi ke tagihan seluler, atau mencuri informasi pribadi Anda. <ph name="BEGIN_LEARN_MORE_LINK" />Pelajari lebih lanjut<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">Tidak ada internet</translation>
@@ -415,6 +432,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="2248949050832152960">Gunakan WebAuthn</translation>
<translation id="2250931979407627383">Jahitan tepi di kiri</translation>
<translation id="225207911366869382">Nilai ini sudah usang untuk kebijakan ini.</translation>
+<translation id="2256115617011615191">Mulai ulang sekarang</translation>
<translation id="2258928405015593961">Masukkan tanggal habis masa berlaku yang ada di masa mendatang dan coba lagi</translation>
<translation id="225943865679747347">Kode kesalahan: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">Kesalahan HTTP</translation>
@@ -442,6 +460,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="2337852623177822836">Setelan dikontrol oleh administrator Anda</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> ingin menyandingkan</translation>
<translation id="2346319942568447007">Gambar yang Anda salin</translation>
+<translation id="2350796302381711542">Izinkan <ph name="HANDLER_HOSTNAME" /> untuk membuka semua link <ph name="PROTOCOL" /> sebagai ganti <ph name="REPLACED_HANDLER_TITLE" />?</translation>
<translation id="2354001756790975382">Bookmark lain</translation>
<translation id="2354430244986887761">Baru-baru ini, Google Safe Browsing <ph name="BEGIN_LINK" />menemukan aplikasi berbahaya<ph name="END_LINK" /> di <ph name="SITE" />.</translation>
<translation id="2355395290879513365">Penyerang mungkin dapat melihat gambar yang sedang Anda lihat di situs dan mengelabui Anda dengan memodifikasinya.</translation>
@@ -467,6 +486,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="2413528052993050574">Server ini tidak dapat membuktikan bahwa ini adalah <ph name="DOMAIN" />; sertifikat keamanannya mungkin dicabut. Hal ini dapat disebabkan oleh kesalahan konfigurasi atau penyerang memotong sambungan Anda.</translation>
<translation id="2414886740292270097">Gelap</translation>
<translation id="2430968933669123598">Kelola Akun Google, tekan Enter untuk mengelola info, privasi, dan keamanan di Akun Google Anda</translation>
+<translation id="2436186046335138073">Izinkan <ph name="HANDLER_HOSTNAME" /> membuka semua link <ph name="PROTOCOL" />?</translation>
<translation id="2438874542388153331">Empat lubang di kanan</translation>
<translation id="2450021089947420533">Perjalanan</translation>
<translation id="2463739503403862330">Isi</translation>
@@ -474,6 +494,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="2465655957518002998">Pilih Metode Pengiriman</translation>
<translation id="2465688316154986572">Jepretan</translation>
<translation id="2465914000209955735">Kelola file yang telah Anda download di Chrome</translation>
+<translation id="2466004615675155314">Tampilkan informasi dari web</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Jalankan Diagnostik Jaringan<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">Urutan 1-ke-N</translation>
<translation id="2470767536994572628">Jika Anda mengedit anotasi, dokumen ini akan kembali ke tampilan satu halaman dan rotasi aslinya</translation>
@@ -494,6 +515,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="2523886232349826891">Hanya disimpan di perangkat ini</translation>
<translation id="2524461107774643265">Tambahkan Informasi Lainnya</translation>
<translation id="2529899080962247600">Kolom ini tidak boleh memiliki lebih dari <ph name="MAX_ITEMS_LIMIT" /> entri. Semua entri berikutnya akan diabaikan.</translation>
+<translation id="2535585790302968248">Buka tab Samaran baru untuk menjelajah secara pribadi</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{dan 1 lainnya}other{dan # lainnya}}</translation>
<translation id="2536110899380797252">Tambahkan Alamat</translation>
<translation id="2539524384386349900">Deteksi</translation>
@@ -519,7 +541,14 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="2597378329261239068">Dokumen ini dilindungi sandi. Masukkan sandi.</translation>
<translation id="2609632851001447353">Variasi</translation>
<translation id="2610561535971892504">Klik untuk menyalin</translation>
+<translation id="2617988307566202237">Chrome <ph name="BEGIN_EMPHASIS" />tidak akan menyimpan<ph name="END_EMPHASIS" /> informasi berikut:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Histori penjelajahan Anda
+ <ph name="LIST_ITEM" />Cookie dan data situs
+ <ph name="LIST_ITEM" />Informasi yang dimasukkan dalam formulir
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (Amplop)</translation>
+<translation id="2623663032199728144">Dapat meminta untuk menggunakan info tentang layar Anda</translation>
<translation id="2625385379895617796">Setelan jam terlalu cepat</translation>
<translation id="262745152991669301">Dapat meminta untuk terhubung ke perangkat USB</translation>
<translation id="2629325967560697240">Untuk mendapatkan tingkat keamanan tertinggi Chrome, <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />aktifkan perlindungan yang ditingkatkan<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -553,6 +582,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="2709516037105925701">Isi-Otomatis</translation>
<translation id="2713444072780614174">Putih</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />, tekan Tab lalu Enter untuk mengelola info pembayaran dan kartu kredit di setelan Chrome</translation>
+<translation id="271663710482723385">Tekan |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| untuk keluar dari mode layar penuh</translation>
<translation id="2721148159707890343">Permintaan berhasil</translation>
<translation id="2723669454293168317">Jalankan pemeriksaan keamanan di setelan Chrome</translation>
<translation id="2726001110728089263">Baki Samping</translation>
@@ -583,6 +613,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="2850739647070081192">Invite (Envelope)</translation>
<translation id="2856444702002559011">Penyerang mungkin berusaha mencuri informasi Anda dari <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (misalnya, sandi, pesan, atau kartu kredit). <ph name="BEGIN_LEARN_MORE_LINK" />Pelajari lebih lanjut<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">Situs ini menampilkan iklan yang mengganggu atau menyesatkan.</translation>
+<translation id="286512204874376891">Kartu virtual menyamarkan kartu Anda yang sebenarnya untuk membantu melindungi Anda dari kemungkinan penipuan. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">Bersahabat</translation>
<translation id="2876489322757410363">Keluar dari mode Samaran untuk membayar melalui aplikasi eksternal. Lanjutkan?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />, tekan Tab lalu Enter untuk mengelola Safe Browsing dan lainnya di setelan Chrome</translation>
@@ -607,6 +638,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="2930577230479659665">Trim setelah setiap set tercetak</translation>
<translation id="2932085390869194046">Sarankan Sandi...</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019">Membuka link <ph name="PROTOCOL" /></translation>
<translation id="2941952326391522266">Server ini tidak dapat membuktikan bahwa ini adalah <ph name="DOMAIN" />; sertifikat keamanannya dari <ph name="DOMAIN2" />. Hal ini disebabkan oleh kesalahan konfigurasi atau penyerang memotong sambungan Anda.</translation>
<translation id="2943895734390379394">Waktu Upload:</translation>
<translation id="2948083400971632585">Anda dapat menonaktifkan proxy apa pun yang dikonfigurasi untuk sambungan dari halaman setelan.</translation>
@@ -639,6 +671,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="3037605927509011580">Yah!</translation>
<translation id="3041612393474885105">Informasi Sertifikat</translation>
<translation id="3044034790304486808">Lanjutkan pencarian Anda</translation>
+<translation id="305162504811187366">Histori Chrome Desktop Jarak Jauh, termasuk stempel waktu, host, dan ID sesi klien</translation>
<translation id="3060227939791841287">C9 (Envelope)</translation>
<translation id="3061707000357573562">Layanan Patch</translation>
<translation id="306573536155379004">Game dimulai.</translation>
@@ -679,6 +712,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="3197136577151645743">Dapat meminta untuk mengetahui saat Anda aktif menggunakan perangkat ini</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />, tekan Tab lalu Enter untuk mengelola info apa saja yang Anda sinkronkan di setelan Chrome</translation>
<translation id="320323717674993345">Batalkan Pembayaran</translation>
+<translation id="3203366800380907218">Dari web</translation>
<translation id="3207960819495026254">Diberi bookmark</translation>
<translation id="3209034400446768650">Halaman mungkin dikenakan biaya</translation>
<translation id="3212581601480735796">Aktivitas Anda di <ph name="HOSTNAME" /> sedang dipantau</translation>
@@ -695,10 +729,12 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="3234666976984236645">Selalu deteksi konten penting di situs ini</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />, Tekan tab lalu Enter untuk menyesuaikan tampilan browser Anda</translation>
<translation id="3240791268468473923">Sheet tidak ada kredensial yang cocok untuk Kredensial pembayaran aman terbuka</translation>
+<translation id="324180406144491771">Link “<ph name="HOST_NAME" />†diblokir</translation>
<translation id="3249845759089040423">Groovy</translation>
<translation id="3252266817569339921">Prancis</translation>
<translation id="3257954757204451555">Siapa yang memberikan informasi ini?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />, tekan Tab lalu Enter untuk membuat acara baru di Google Kalender dengan cepat</translation>
+<translation id="3261488570342242926">Pelajari kartu virtual</translation>
<translation id="3264837738038045344">Tombol Kelola setelan Chrome, tekan Enter untuk membuka setelan Chrome Anda</translation>
<translation id="3266793032086590337">Nilai (bertentangan)</translation>
<translation id="3268451620468152448">Tab Terbuka</translation>
@@ -712,6 +748,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="3288238092761586174"><ph name="URL" /> mungkin perlu melakukan langkah tambahan untuk memverifikasi pembayaran Anda</translation>
<translation id="3293642807462928945">Pelajari lebih lanjut tentang kebijakan <ph name="POLICY_NAME" /></translation>
<translation id="3295444047715739395">Lihat dan kelola sandi Anda di setelan Chrome</translation>
+<translation id="3303795387212510132">Izinkan aplikasi untuk membuka link <ph name="PROTOCOL_SCHEME" />?</translation>
<translation id="3303855915957856445">Hasil penelusuran tidak ditemukan</translation>
<translation id="3304073249511302126">pemindaian bluetooth</translation>
<translation id="3308006649705061278">Unit Organisasi (OU)</translation>
@@ -725,12 +762,6 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="3345782426586609320">Mata</translation>
<translation id="3355823806454867987">Ubah setelan proxy...</translation>
<translation id="3360103848165129075">Lembar handler pembayaran</translation>
-<translation id="3361596688432910856">Chrome <ph name="BEGIN_EMPHASIS" />tidak akan menyimpan<ph name="END_EMPHASIS" /> informasi berikut:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Histori penjelajahan Anda
- <ph name="LIST_ITEM" />Cookie dan data situs
- <ph name="LIST_ITEM" />Informasi yang dimasukkan dalam formulir
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">Kebijakan ini otomatis disalin dari kebijakan <ph name="OLD_POLICY" /> yang tidak digunakan lagi. Sebaiknya Anda menggunakan kebijakan ini.</translation>
<translation id="3364869320075768271"><ph name="URL" /> ingin menggunakan perangkat dan data virtual reality Anda</translation>
<translation id="3366477098757335611">Lihat kartu</translation>
@@ -812,7 +843,6 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="3587738293690942763">Tengah</translation>
<translation id="3592413004129370115">Italian (Envelope)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{Anda dapat mereset grup kapan saja. Perlu waktu sekitar 1 hari untuk bergabung ke grup baru.}=1{Anda dapat mereset grup kapan saja. Perlu waktu sekitar 1 hari untuk bergabung ke grup baru.}other{Anda dapat mereset grup kapan saja. Perlu waktu sekitar {NUM_DAYS} hari untuk bergabung ke grup baru.}}</translation>
-<translation id="3596012367874587041">Setelan aplikasi</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">Aplikasi diblokir oleh administrator Anda</translation>
<translation id="3608932978122581043">Feed orientasi</translation>
@@ -855,6 +885,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="370972442370243704">Aktifkan Perjalanan</translation>
<translation id="3711895659073496551">Tangguhkan</translation>
<translation id="3712624925041724820">Lisensi habis</translation>
+<translation id="3714633008798122362">kalender web</translation>
<translation id="3714780639079136834">Aktifkan data seluler atau Wi-Fi</translation>
<translation id="3715597595485130451">Menghubungkan ke jaringan Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Periksa proxy, firewall, dan konfigurasi DNS<ph name="END_LINK" /></translation>
@@ -916,6 +947,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="3906954721959377182">Tablet</translation>
<translation id="3909477809443608991"><ph name="URL" /> ingin memutar konten yang dilindungi. Identitas perangkat Anda akan diverifikasi oleh Google dan akan dapat diakses oleh situs ini.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">Tolak</translation>
<translation id="3939773374150895049">Gunakan WebAuthn dan bukan CVC?</translation>
<translation id="3946209740501886391">Selalu tanyakan pada situs ini</translation>
<translation id="3947595700203588284">Dapat meminta untuk terhubung ke perangkat MIDI</translation>
@@ -936,6 +968,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="3987940399970879459">Kurang dari 1 MB</translation>
<translation id="3990250421422698716">Jog offset</translation>
<translation id="3996311196211510766"><ph name="ORIGIN" /> situs telah meminta kebijakan asal agar diterapkan ke semua permintaan yang ditujukan kepadanya, tetapi kebijakan ini tidak dapat diterapkan untuk saat ini.</translation>
+<translation id="4009243425692662128">Konten halaman yang Anda cetak akan dikirim ke Google Cloud atau pihak ketiga untuk dianalisis. Misalnya, teks mungkin dipindai untuk mendeteksi data sensitif.</translation>
<translation id="4010758435855888356">Izinkan akses penyimpanan?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{Dokumen PDF berisi {COUNT} halaman}other{Dokumen PDF berisi {COUNT} halaman}}</translation>
<translation id="4023431997072828269">Karena formulir ini dikirim menggunakan koneksi yang tidak aman, informasi Anda akan dapat dilihat oleh pengguna lain.</translation>
@@ -1026,6 +1059,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="4250680216510889253">Tidak</translation>
<translation id="4253168017788158739">Catatan</translation>
<translation id="425582637250725228">Perubahan yang Anda lakukan mungkin tidak disimpan.</translation>
+<translation id="425869179292622354">Jadikan kartu lebih aman dengan kartu virtual?</translation>
<translation id="4258748452823770588">Tanda tangan salah</translation>
<translation id="4261046003697461417">Dokumen yang dilindungi tidak dapat dianotasi</translation>
<translation id="4265872034478892965">Diizinkan oleh administrator</translation>
@@ -1088,6 +1122,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="4434045419905280838">Pop-up dan pengalihan</translation>
<translation id="4435702339979719576">Postcard)</translation>
<translation id="443673843213245140">Penggunaan proxy dinonaktifkan tetapi konfigurasi proxy yang eksplisit ditentukan.</translation>
+<translation id="4441832193888514600">Diabaikan karena kebijakan ini hanya dapat disetel sebagai kebijakan pengguna cloud.</translation>
<translation id="4450893287417543264">Jangan tampilkan lagi</translation>
<translation id="4451135742916150903">Dapat meminta untuk terhubung ke perangkat HID</translation>
<translation id="4452328064229197696">Sandi yang baru saja Anda gunakan terekspos dalam pelanggaran data. Untuk mengamankan akun Anda, Pengelola Sandi Google merekomendasikan untuk memeriksa sandi tersimpan Anda.</translation>
@@ -1143,6 +1178,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="4628948037717959914">Foto</translation>
<translation id="4631649115723685955">Disertai cashback</translation>
<translation id="4636930964841734540">Info</translation>
+<translation id="4638670630777875591">Mode Samaran di Chromium</translation>
<translation id="464342062220857295">Fitur penelusuran</translation>
<translation id="4644670975240021822">Urutan yang berkebalikan menghadap ke bawah</translation>
<translation id="4646534391647090355">Buka Download sekarang</translation>
@@ -1163,6 +1199,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="4708268264240856090">Koneksi Anda terganggu</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Jalankan Diagnostik Jaringan Windows<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426">Sandi untuk <ph name="USERNAME" /></translation>
<translation id="4724144314178270921">Dapat meminta untuk melihat teks dan gambar di papan klip Anda</translation>
<translation id="4726672564094551039">Muat ulang kebijakan</translation>
<translation id="4728558894243024398">Platform</translation>
@@ -1184,6 +1221,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="4757993714154412917">Anda baru saja memasukkan sandi ke situs penipuan. Untuk mengamankan akun Anda, Chromium merekomendasikan pemeriksaan sandi tersimpan Anda.</translation>
<translation id="4758311279753947758">Tambahkan info kontak</translation>
<translation id="4761104368405085019">Menggunakan mikrofon Anda</translation>
+<translation id="4761869838909035636">Jalankan Pemeriksaan Keamanan Chrome</translation>
<translation id="4764776831041365478">Halaman web di <ph name="URL" /> mungkin sedang tidak aktif untuk sementara atau dipindahkan secara permanen ke alamat web baru.</translation>
<translation id="4766713847338118463">Dua jepretan di bawah</translation>
<translation id="4771973620359291008">Terjadi kesalahan yang tidak diketahui.</translation>
@@ -1204,12 +1242,6 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="4819347708020428563">Edit anotasi dalam tampilan default?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />, tekan Tab lalu Enter untuk membuat Spreadsheet Google baru dengan cepat</translation>
<translation id="4825507807291741242">Kuat</translation>
-<translation id="4827402517081186284">Mode Samaran tidak membuat Anda tidak terlihat secara online:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Situs mengetahui saat Anda membukanya<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Perusahaan atau sekolah dapat melacak aktivitas penjelajahan<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Internet service provider dapat memantau traffic web<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">Aktifkan peringatan</translation>
<translation id="4838327282952368871">Sangat Indah</translation>
<translation id="4840250757394056958">Lihat histori Chrome Anda</translation>
@@ -1221,12 +1253,12 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="4854362297993841467">Metode pengiriman tidak tersedia. Coba metode lain.</translation>
<translation id="4854853140771946034">Buat catatan baru di Google Keep dengan cepat</translation>
<translation id="485902285759009870">Memverifikasi kode ...</translation>
+<translation id="4866506163384898554">Tekan |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| untuk menampilkan kursor</translation>
<translation id="4876188919622883022">Tampilan sederhana</translation>
<translation id="4876305945144899064">Tidak ada nama pengguna</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{Tidak ada}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831">Penelusuran <ph name="TEXT" /></translation>
<translation id="4879491255372875719">Otomatis (default)</translation>
-<translation id="4879725228911483934">Membuka dan menempatkan jendela di layar Anda</translation>
<translation id="4880827082731008257">Telusuri histori</translation>
<translation id="4881695831933465202">Buka</translation>
<translation id="4885256590493466218">Bayar dengan <ph name="CARD_DETAIL" /> saat checkout</translation>
@@ -1235,6 +1267,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">Rol Kesembilan</translation>
<translation id="4901778704868714008">Simpan...</translation>
+<translation id="4905659621780993806">Administrator akan memulai ulang perangkat Anda secara otomatis pada <ph name="DATE" /> pukul <ph name="TIME" />. Simpan item yang terbuka sebelum perangkat dimulai ulang.</translation>
<translation id="4913987521957242411">Lubang di kiri atas</translation>
<translation id="4918221908152712722">Instal <ph name="APP_NAME" /> (tidak perlu didownload)</translation>
<translation id="4923459931733593730">Pembayaran</translation>
@@ -1243,6 +1276,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, tekan Tab lalu Enter untuk menelusuri</translation>
<translation id="4930153903256238152">Kapasitas besar</translation>
+<translation id="4940163644868678279">Mode Samaran di Chrome</translation>
<translation id="4943872375798546930">Tidak ada hasil</translation>
<translation id="4950898438188848926">Tombol beralih tab, tekan Enter untuk beralih ke tab yang terbuka, <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="495170559598752135">Tindakan</translation>
@@ -1252,6 +1286,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="4968522289500246572">Aplikasi ini didesain untuk perangkat seluler dan perubahan ukurannya mungkin tidak sesuai. Perangkat dapat mengalami masalah atau dimulai ulang.</translation>
<translation id="4969341057194253438">Hapus rekaman</translation>
<translation id="4973922308112707173">Dua lubang di atas</translation>
+<translation id="4976702386844183910">Terakhir dibuka <ph name="DATE" /></translation>
<translation id="4984088539114770594">Gunakan mikrofon?</translation>
<translation id="4984339528288761049">Prc5 (Envelope)</translation>
<translation id="4989163558385430922">Lihat semua</translation>
@@ -1313,6 +1348,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="5138227688689900538">Tampilkan lebih sedikit</translation>
<translation id="5145883236150621069">Ada kode kesalahan dalam tanggapan kebijakan</translation>
<translation id="5146995429444047494">Notifikasi untuk <ph name="ORIGIN" /> diblokir</translation>
+<translation id="514704532284964975"><ph name="URL" /> ingin melihat dan mengubah informasi di perangkat NFC yang Anda tempelkan ke ponsel</translation>
<translation id="5148809049217731050">Menghadap ke atas</translation>
<translation id="515292512908731282">C4 (Envelope)</translation>
<translation id="5158275234811857234">Sampul</translation>
@@ -1337,6 +1373,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="5215116848420601511">Metode pembayaran dan alamat yang menggunakan Google Pay</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">Baki 13</translation>
+<translation id="5216942107514965959">Terakhir dibuka hari ini</translation>
<translation id="5222812217790122047">Email wajib diisi</translation>
<translation id="5230733896359313003">Alamat Pengiriman</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1357,7 +1394,6 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">Properti dokumen</translation>
<translation id="528468243742722775">Berakhir</translation>
-<translation id="5284909709419567258">Alamat jaringan</translation>
<translation id="5285570108065881030">Tampilkan semua sandi tersimpan</translation>
<translation id="5287240709317226393">Tampilkan cookie</translation>
<translation id="5287456746628258573">Situs ini menggunakan konfigurasi keamanan yang telah habis masa berlakunya, yang dapat mengekspos informasi Anda (misalnya, sandi atau nomor kartu kredit) saat dikirimkan ke situs ini.</translation>
@@ -1441,6 +1477,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="5556459405103347317">Muat ulang</translation>
<translation id="5560088892362098740">Tanggal Habis Masa Berlaku</translation>
<translation id="55635442646131152">Kerangka dokumen</translation>
+<translation id="5565613213060953222">Buka tab Samaran</translation>
<translation id="5565735124758917034">Aktif</translation>
<translation id="5570825185877910964">Lindungi akun</translation>
<translation id="5571083550517324815">Tidak dapat mengambil dari alamat ini. Pilih alamat lain.</translation>
@@ -1523,6 +1560,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="5869522115854928033">Sandi tersimpan</translation>
<translation id="5873013647450402046">Bank Anda ingin memastikan bahwa ini memang Anda.</translation>
<translation id="5887400589839399685">Kartu disimpan</translation>
+<translation id="5887687176710214216">Terakhir dibuka kemarin</translation>
<translation id="5895138241574237353">Mulai Ulang</translation>
<translation id="5895187275912066135">Diterbitkan Pada</translation>
<translation id="5901630391730855834">Kuning</translation>
@@ -1536,6 +1574,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="5921639886840618607">Simpan kartu ke Akun Google?</translation>
<translation id="5922853866070715753">Hampir selesai</translation>
<translation id="5932224571077948991">Situs menampilkan iklan yang mengganggu atau menyesatkan</translation>
+<translation id="5938153366081463283">Tambahkan kartu virtual</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347">Membuka <ph name="SITE_NAME" />…</translation>
<translation id="5951495562196540101">Tidak dapat mendaftar dengan akun konsumen (tersedia paket lisensi).</translation>
@@ -1600,6 +1639,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="6120179357481664955">Ingat ID UPI Anda?</translation>
<translation id="6124432979022149706">Chrome Enterprise Connectors</translation>
<translation id="6127379762771434464">Item dihapus</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Pelajari mode Samaran di Chrome lebih lanjut<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">Periksa semua kabel dan boot ulang router, modem, atau perangkat
jaringan lain yang mungkin Anda gunakan.</translation>
<translation id="614940544461990577">Coba:</translation>
@@ -1612,7 +1652,6 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="6169916984152623906">Anda kini dapat mengakses secara rahasia, dan orang lain yang menggunakan perangkat ini tidak akan melihat aktivitas Anda. Namun, hasil download dan bookmark akan disimpan.</translation>
<translation id="6177128806592000436">Sambungan Anda ke situs ini tidak aman</translation>
<translation id="6180316780098470077">Interval percobaan ulang</translation>
-<translation id="619448280891863779">Dapat meminta untuk membuka dan menempatkan jendela di layar Anda</translation>
<translation id="6196640612572343990">Blokir cookie pihak ketiga</translation>
<translation id="6203231073485539293">Periksa koneksi internet Anda</translation>
<translation id="6218753634732582820">Hapus alamat dari Chromium?</translation>
@@ -1635,7 +1674,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="6272383483618007430">Google Update</translation>
<translation id="6276112860590028508">Halaman dari daftar bacaan Anda muncul di sini</translation>
<translation id="627746635834430766">Untuk membayar lebih cepat di pembelian selanjutnya, simpan kartu dan alamat penagihan ke Akun Google Anda.</translation>
-<translation id="6279098320682980337">Nomor kartu virtual tidak diisi? Klik detail kartu untuk menyalinnya</translation>
+<translation id="6279183038361895380">Tekan |<ph name="ACCELERATOR" />| untuk menampilkan kursor</translation>
<translation id="6280223929691119688">Tidak dapat mengirim ke alamat ini. Pilih alamat lain.</translation>
<translation id="6282194474023008486">Kode pos</translation>
<translation id="6285507000506177184">Tombol Kelola download di Chrome, tekan Enter untuk mengelola file yang telah Anda download di Chrome</translation>
@@ -1643,6 +1682,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="6290238015253830360">Artikel yang disarankan ditampilkan di sini</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{Perangkat akan dimulai ulang sekarang}=1{Perangkat akan dimulai ulang dalam 1 detik}other{Perangkat akan dimulai ulang dalam # detik}}</translation>
<translation id="6302269476990306341">Asisten Google di Chrome sedang dihentikan</translation>
<translation id="6305205051461490394"><ph name="URL" /> tidak dapat dijangkau.</translation>
<translation id="6312113039770857350">Halaman web tidak tersedia</translation>
@@ -1716,6 +1756,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="6529602333819889595">&amp;Ulangi Penghapusan</translation>
<translation id="6545864417968258051">Pemindaian Bluetooth</translation>
<translation id="6547208576736763147">Dua lubang di kiri</translation>
+<translation id="6554732001434021288">Terakhir dibuka <ph name="NUM_DAYS" /> hari lalu</translation>
<translation id="6556866813142980365">Urungkan</translation>
<translation id="6569060085658103619">Anda melihat halaman ekstensi</translation>
<translation id="6573200754375280815">Dua lubang di kanan</translation>
@@ -1776,7 +1817,6 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="6757797048963528358">Perangkat Anda sedang dalam mode tidur.</translation>
<translation id="6767985426384634228">Perbarui Alamat?</translation>
<translation id="6768213884286397650">Hagaki (Postcard)</translation>
-<translation id="6774185088257932239"><ph name="BEGIN_LINK" />Pelajari lebih lanjut<ph name="END_LINK" /> mode Samaran</translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">Violet</translation>
<translation id="6786747875388722282">Ekstensi</translation>
@@ -1860,7 +1900,6 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="706295145388601875">Tambahkan dan kelola alamat di setelan Chrome</translation>
<translation id="7064851114919012435">Info kontak</translation>
<translation id="7068733155164172741">Masukkan kode <ph name="OTP_LENGTH" /> digit</translation>
-<translation id="7070090581017165256">Tentang situs ini</translation>
<translation id="70705239631109039">Koneksi Anda tidak sepenuhnya aman</translation>
<translation id="7075452647191940183">Permintaan terlalu besar</translation>
<translation id="7079718277001814089">Situs ini berisi malware</translation>
@@ -1877,6 +1916,12 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="7111012039238467737">(Valid)</translation>
<translation id="7118618213916969306">Telusuri URL papan klip, <ph name="SHORT_URL" /></translation>
<translation id="7119414471315195487">Tutup tab atau program lain</translation>
+<translation id="7129355289156517987">Jika Anda menutup semua tab Samaran Chromium, aktivitas Anda di tab tersebut akan dihapus dari perangkat ini:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Aktivitas penjelajahan<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Histori penelusuran<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Informasi yang dimasukkan dalam formulir<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">Tidak dapat mengirim ke alamat ini. Pilih alamat lain.</translation>
<translation id="7132939140423847331">Admin Anda telah melarang data ini disalin.</translation>
<translation id="7135130955892390533">Tampilkan status</translation>
@@ -1899,6 +1944,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="7192203810768312527">Sediakan ruang sebesar <ph name="SIZE" />. Sebagian situs mungkin dimuat lebih lambat pada kunjungan Anda berikutnya.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">Administrator dapat melihat:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, tekan Tab lalu Enter untuk membuka tab Samaran baru dan menjelajah secara pribadi</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> tidak mematuhi standar keamanan.</translation>
<translation id="7210993021468939304">Aktivitas Linux berada dalam penampung, dan dapat menginstal dan menjalankan aplikasi Linux di dalam penampung</translation>
@@ -1928,6 +1974,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="7304562222803846232">Kelola setelan privasi Akun Google</translation>
<translation id="7305756307268530424">Mulai lebih lambat</translation>
<translation id="7308436126008021607">sinkronisasi latar belakang</translation>
+<translation id="7310392214323165548">Perangkat akan segera dimulai ulang</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">Bantuan Koneksi</translation>
<translation id="7323804146520582233">Sembunyikan bagian "<ph name="SECTION" />"</translation>
@@ -1935,6 +1982,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="7334320624316649418">&amp;Ulangi pengaturan ulang</translation>
<translation id="7335157162773372339">Dapat meminta untuk menggunakan kamera Anda</translation>
<translation id="7337248890521463931">Tampilkan lebih banyak baris</translation>
+<translation id="7337418456231055214">Nomor kartu virtual tidak diisi? Klik detail kartu untuk menyalinnya. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">Tidak tersedia di platform Anda.</translation>
<translation id="733923710415886693">Sertifikat server tidak diungkapkan melalui Transparansi Sertifikat.</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1957,6 +2005,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="7378627244592794276">Tidak</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">Tidak berlaku</translation>
+<translation id="7388594495505979117">{0,plural, =1{Perangkat Anda akan dimulai ulang dalam 1 menit}other{Perangkat Anda akan dimulai ulang dalam # menit}}</translation>
<translation id="7390545607259442187">Konfirmasi Kartu</translation>
<translation id="7392089738299859607">Perbarui Alamat</translation>
<translation id="7399802613464275309">Pemeriksaan Keamanan</translation>
@@ -1993,6 +2042,12 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="7485870689360869515">Tidak ada data yang ditemukan.</translation>
<translation id="7495528107193238112">Konten ini diblokir. Hubungi pemilik situs untuk memperbaiki masalah.</translation>
<translation id="7497998058912824456">Tombol Buat dokumen, tekan Enter untuk membuat Dokumen Google baru dengan cepat</translation>
+<translation id="7506488012654002225">Chromium <ph name="BEGIN_EMPHASIS" />tidak akan menyimpan<ph name="END_EMPHASIS" /> informasi berikut:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Histori penjelajahan Anda
+ <ph name="LIST_ITEM" />Cookie dan data situs
+ <ph name="LIST_ITEM" />Informasi yang dimasukkan dalam formulir
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">ID perangkat kebijakan yang dikembalikan kosong atau tidak cocok dengan ID perangkat saat ini</translation>
<translation id="7508870219247277067">Hijau Avokad</translation>
<translation id="7511955381719512146">Wi-Fi yang digunakan mungkin mewajibkan Anda mengunjungi <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
@@ -2106,7 +2161,6 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="7813600968533626083">Hapus sebagai saran dari Chrome?</translation>
<translation id="781440967107097262">Bagikan papan klip?</translation>
<translation id="7815407501681723534">Ditemukan <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> hasil untuk '<ph name="SEARCH_STRING" />'</translation>
-<translation id="782125616001965242">Tampilkan informasi tentang situs ini</translation>
<translation id="782886543891417279">Wi-Fi yang digunakan (<ph name="WIFI_NAME" />) mungkin mewajibkan Anda mengunjungi halaman masuknya.</translation>
<translation id="7836231406687464395">Postfix (Envelope)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{Tidak ada}=1{1 aplikasi (<ph name="EXAMPLE_APP_1" />)}=2{2 aplikasi (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}other{# aplikasi (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}}</translation>
@@ -2123,7 +2177,6 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="7888575728750733395">Intent rendering cetak</translation>
<translation id="7894280532028510793">Jika ejaan sudah benar, <ph name="BEGIN_LINK" />coba jalankan Diagnostik Jaringan<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (Envelope)</translation>
-<translation id="7931318309563332511">Tidak dikenal</translation>
<translation id="793209273132572360">Perbarui alamat?</translation>
<translation id="7932579305932748336">Lapisan</translation>
<translation id="79338296614623784">Masukkan nomor telepon yang valid</translation>
@@ -2148,13 +2201,14 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="7976214039405368314">Terlalu banyak permintaan</translation>
<translation id="7977538094055660992">Perangkat keluaran</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">Ditautkan dengan</translation>
<translation id="798134797138789862">Dapat meminta untuk menggunakan perangkat dan data virtual reality</translation>
<translation id="7984945080620862648">Anda tidak dapat mengunjungi <ph name="SITE" /> saat ini karena situs web tersebut mengirim kredensial kacau yang tidak dapat diproses oleh Chrome. Kesalahan jaringan dan serangan biasanya bersifat sementara, jadi halaman ini mungkin akan bekerja nanti.</translation>
-<translation id="79859296434321399">Untuk melihat konten augmented reality, instal ARCore</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">Jilid</translation>
<translation id="7992044431894087211">Berbagi layar dengan <ph name="APPLICATION_TITLE" /> dilanjutkan</translation>
<translation id="7995512525968007366">Tidak Ditentukan</translation>
+<translation id="7998269595945679889">Tombol Buka tab Samaran, tekan Enter untuk membuka tab Samaran baru dan menjelajah secara pribadi</translation>
<translation id="800218591365569300">Coba tutup tab atau program lain untuk mengosongkan memori.</translation>
<translation id="8004582292198964060">Browser</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{Kartu ini dan alamat penagihannya akan disimpan. Anda dapat menggunakannya saat login ke <ph name="USER_EMAIL" />.}other{Semua kartu ini dan alamat penagihannya akan disimpan. Anda dapat menggunakannya saat login ke <ph name="USER_EMAIL" />.}}</translation>
@@ -2214,6 +2268,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="8202370299023114387">Konflik</translation>
<translation id="8206978196348664717">Prc4 (Envelope)</translation>
<translation id="8211406090763984747">Koneksi aman</translation>
+<translation id="8217240300496046857">Situs tidak dapat menggunakan cookie yang melacak Anda di seluruh web. Fitur di beberapa situs mungkin tidak berfungsi.</translation>
<translation id="8218327578424803826">Lokasi yang Ditetapkan:</translation>
<translation id="8220146938470311105">C7/C6 (Envelope)</translation>
<translation id="8225771182978767009">Orang yang menyiapkan komputer ini telah memilih untuk memblokir situs ini.</translation>
@@ -2254,14 +2309,9 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="830498451218851433">Lipatan setengah</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">Aplikasi yang diinstal dan seberapa sering digunakan</translation>
+<translation id="8317207217658302555">Update ARCore?</translation>
<translation id="831997045666694187">Sore</translation>
<translation id="8321476692217554900">notifikasi</translation>
-<translation id="8328484624016508118">Setelah semua tab Samaran ditutup, Chrome akan menghapus:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Aktivitas penjelajahan Anda dari perangkat ini<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Histori penelusuran Anda di perangkat ini<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Informasi yang dimasukkan ke formulir web<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489">Akses ke <ph name="HOST_NAME" /> ditolak</translation>
<translation id="833262891116910667">Sorotan</translation>
<translation id="8339163506404995330">Halaman dalam bahasa <ph name="LANGUAGE" /> tidak akan diterjemahkan</translation>
@@ -2311,6 +2361,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="8507227106804027148">Command line</translation>
<translation id="8508648098325802031">Ikon penelusuran</translation>
<translation id="8511402995811232419">Kelola cookie</translation>
+<translation id="8519753333133776369">Perangkat HID yang diizinkan oleh administrator Anda</translation>
<translation id="8522552481199248698">Chrome dapat membantu Anda melindungi Akun Google dan mengubah sandi Anda.</translation>
<translation id="8530813470445476232">Hapus histori penjelajahan, cookie, cache, dan lainnya di setelan Chrome</translation>
<translation id="8533619373899488139">Buka &lt;strong&gt;chrome://policy&lt;/strong&gt; untuk melihat daftar URL yang diblokir dan kebijakan lainnya yang diterapkan oleh administrator sistem Anda.</translation>
@@ -2322,7 +2373,6 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{Reset izin}other{Reset izin}}</translation>
<translation id="8555010941760982128">Gunakan kode ini saat checkout</translation>
<translation id="8557066899867184262">CVC terletak di bagian belakang kartu Anda.</translation>
-<translation id="8558485628462305855">Untuk melihat konten augmented reality, update ARCore</translation>
<translation id="8559762987265718583">Sambungan pribadi ke <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> tidak dapat dibuat karena tanggal dan waktu (<ph name="DATE_AND_TIME" />) perangkat tidak benar.</translation>
<translation id="8564182942834072828">Dokumen terpisah/Salinan tidak tersusun</translation>
<translation id="8564985650692024650">Chromium menyarankan untuk menyetel ulang sandi <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> jika Anda juga menggunakannya di situs lain.</translation>
@@ -2341,6 +2391,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="865032292777205197">sensor gerakan</translation>
<translation id="8663226718884576429">Ringkasan Pesanan, <ph name="TOTAL_LABEL" />, Detail Selengkapnya</translation>
<translation id="8666678546361132282">Inggris</translation>
+<translation id="8669306706049782872">Menggunakan info tentang layar Anda untuk membuka dan menempatkan jendela</translation>
<translation id="867224526087042813">Tanda Tangan</translation>
<translation id="8676424191133491403">Tanpa penundaan</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, dengan jawaban, <ph name="ANSWER" /></translation>
@@ -2367,6 +2418,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="8731544501227493793">Tombol Kelola sandi, tekan Enter untuk melihat dan mengelola sandi di setelan Chrome</translation>
<translation id="8734529307927223492"><ph name="DEVICE_TYPE" /> Anda dikelola oleh <ph name="MANAGER" /></translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, tekan Tab lalu Enter untuk membuka jendela Samaran baru dan menjelajah secara pribadi</translation>
+<translation id="8737685506611670901">Membuka link <ph name="PROTOCOL" /> sebagai ganti <ph name="REPLACED_HANDLER_TITLE" /></translation>
<translation id="8738058698779197622">Untuk membuat sambungan aman, jam perlu disetel dengan benar. Hal ini karena sertifikat yang digunakan situs web untuk mengidentifikasi situs web tersebut hanya valid untuk jangka waktu tertentu. Karena jam perangkat tidak benar, Chromium tidak dapat memverifikasi sertifikat ini.</translation>
<translation id="8740359287975076522">&lt;abbr id="dnsDefinition"&gt;Alamat DNS&lt;/abbr&gt; <ph name="HOST_NAME" /> tidak dapat ditemukan. Mendiagnosis masalah.</translation>
<translation id="8742371904523228557"><ph name="ONE_TIME_CODE" /> adalah kode Anda untuk <ph name="ORIGIN" /></translation>
@@ -2394,6 +2446,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="883848425547221593">Bookmark Lain</translation>
<translation id="884264119367021077">Alamat pengiriman</translation>
<translation id="884923133447025588">Tidak ditemukan mekanisme pembatalan.</translation>
+<translation id="8849262850971482943">Gunakan kartu virtual Anda untuk keamanan tambahan</translation>
<translation id="885730110891505394">Berbagi dengan Google</translation>
<translation id="8858065207712248076">Chrome menyarankan untuk menyetel ulang sandi <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> jika Anda juga menggunakannya di situs lain.</translation>
<translation id="885906927438988819">Jika ejaan sudah benar, <ph name="BEGIN_LINK" />coba jalankan Diagnostik Jaringan Windows<ph name="END_LINK" />.</translation>
@@ -2443,6 +2496,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="9004367719664099443">Sesi VR sedang berlangsung</translation>
<translation id="9005998258318286617">Gagal memuat dokumen PDF.</translation>
<translation id="9008201768610948239">Abaikan</translation>
+<translation id="901834265349196618">email</translation>
<translation id="9020200922353704812">Perlu alamat penagihan kartu</translation>
<translation id="9020542370529661692">Halaman ini telah diterjemahkan ke <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9020742383383852663">A8</translation>
@@ -2491,6 +2545,7 @@ Jika tidak, ini akan diblokir oleh setelan privasi Anda. Ini akan memungkinkan k
<translation id="9150045010208374699">Menggunakan kamera Anda</translation>
<translation id="9150685862434908345">Administrator dapat mengubah penyiapan browser Anda dari jarak jauh. Aktivitas di perangkat ini juga dapat dikelola di luar Chrome. <ph name="BEGIN_LINK" />Pelajari lebih lanjut<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">Diperbarui</translation>
+<translation id="9155211586651734179">Periferal audio yang terpasang</translation>
<translation id="9157595877708044936">Menyiapkan...</translation>
<translation id="9158625974267017556">C6 (Envelope)</translation>
<translation id="9164029392738894042">Pemeriksaan Akurasi</translation>
diff --git a/chromium/components/strings/components_strings_is.xtb b/chromium/components/strings/components_strings_is.xtb
index 01da2b270fa..36e4288012f 100644
--- a/chromium/components/strings/components_strings_is.xtb
+++ b/chromium/components/strings/components_strings_is.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">Sjá upplýsingar</translation>
<translation id="1030706264415084469"><ph name="URL" /> vill fá að geyma mikið magn gagna varanlega í tækinu þínu</translation>
<translation id="1032854598605920125">Snúa réttsælis</translation>
+<translation id="1033329911862281889">Huliðsstilling gerir þig ekki ósýnilega(n) á netinu:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Vefsvæði og þjónusturnar sem þau nota fá upplýsingar um heimsóknir<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Vinnuveitendur eða skólar geta rakið vafranotkun<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Netþjónustur geta fylgst með netumferð<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">Slökkva</translation>
<translation id="1036982837258183574">Ãttu á |<ph name="ACCELERATOR" />| til að hætta birtingu á öllum skjánum</translation>
<translation id="1038106730571050514">Sýna tillögur</translation>
<translation id="1038842779957582377">óþekkt heiti</translation>
<translation id="1041998700806130099">Skilaboð vinnslublaðs</translation>
<translation id="1048785276086539861">Þegar þú breytir textaskýringum fer þetta skjal aftur í einnar síðu snið</translation>
-<translation id="1049743911850919806">Fara huldu höfðu</translation>
<translation id="1050038467049342496">Lokaðu öðrum forritum</translation>
<translation id="1055184225775184556">Aft&amp;urkalla nýtt bókamerki</translation>
<translation id="1056898198331236512">Viðvörun</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">Skyndiminni reglu í lagi</translation>
<translation id="1130564665089811311">Hnappurinn Þýða síðu, ýttu á Enter til að þýða þessa síðu með Google Translate</translation>
<translation id="1131264053432022307">Myndir sem þú afritaðir</translation>
+<translation id="1142846828089312304">Loka á fótspor þriðju aðila í huliðsstillingu</translation>
<translation id="1150979032973867961">Þessi þjónn gat ekki sannað að hann væri <ph name="DOMAIN" />; stýrikerfi tölvunnar treystir ekki öryggisvottorðinu hans. Þetta kann að orsakast af vanstillingu eða tölvuþrjóti sem komist hefur inn í tenginguna.</translation>
<translation id="1151972924205500581">Aðgangsorðs krafist</translation>
<translation id="1156303062776767266">Þú ert að skoða staðbundna eða samnýtta skrá</translation>
@@ -64,7 +70,6 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="1178581264944972037">Gera hlé</translation>
<translation id="1181037720776840403">Fjarlægja</translation>
<translation id="1186201132766001848">Yfirfara aðgangsorð</translation>
-<translation id="1195210374336998651">Opna forritastillingar</translation>
<translation id="1195558154361252544">Sjálfkrafa er lokað á tilkynningar fyrir öll vefsvæði nema þau sem þú hefur gefið leyfi</translation>
<translation id="1197088940767939838">Appelsínugulur</translation>
<translation id="1201402288615127009">Ãfram</translation>
@@ -111,7 +116,7 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="1307966114820526988">Úreldir eiginleikar</translation>
<translation id="1308113895091915999">Tilboð til staðar</translation>
<translation id="1312803275555673949">Hvaða sannanir styðja þetta?</translation>
-<translation id="131405271941274527"><ph name="URL" /> vill senda og taka við upplýsingum þegar þú ýtir á símann í NTC-tæki</translation>
+<translation id="1314311879718644478">Skoða efni aukins veruleika</translation>
<translation id="1314509827145471431">Binda hægra megin</translation>
<translation id="1318023360584041678">Vistað í flipahópi</translation>
<translation id="1319245136674974084">Ekki spyrja aftur fyrir þetta forrit</translation>
@@ -161,6 +166,7 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="142858679511221695">Notandi í skýi</translation>
<translation id="1428729058023778569">Þessi viðvörun birtist vegna þess að þetta vefsvæði styður ekki HTTPS. <ph name="BEGIN_LEARN_MORE_LINK" />Nánar<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">Prenta</translation>
+<translation id="1432187715652018471">síða vill setja upp þjónustuhjálparforrit.</translation>
<translation id="1432581352905426595">Stjórna leitarvélum</translation>
<translation id="1436185428532214179">Getur beðið um leyfi til að breyta skrám og möppum í tækinu þínu</translation>
<translation id="1442386063175183758">Túristabrot hægra megin</translation>
@@ -181,6 +187,12 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="1483493594462132177">Senda</translation>
<translation id="1484290072879560759">Velja heimilisfang til sendingar</translation>
<translation id="1492194039220927094">Sending reglna:</translation>
+<translation id="149293076951187737">Þegar þú lokar öllum huliðsflipum í Chrome er virkni þín á þessum flipum hreinsuð úr tækinu:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Vafranotkun<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Leitarferill<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Upplýsingar sem eru færðar inn í eyðublöð<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">Aftur á flipa</translation>
<translation id="1501859676467574491">Sýna kort af Google reikningnum þínum</translation>
<translation id="1507202001669085618">&lt;p&gt;Þú sérð þessa villu ef þú notar Wi-Fi gátt sem þú þarft að skrá þig inn á áður en þú tengist internetinu.&lt;/p&gt;
@@ -208,6 +220,8 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="1559572115229829303">&lt;p&gt;Ekki er hægt að koma á lokaðri tengingu við <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> vegna þess að dag- og tímasetning tækisins (<ph name="DATE_AND_TIME" />) er röng.&lt;/p&gt;
&lt;p&gt;Stilltu dagsetningu og tíma í hlutanum &lt;strong&gt;Almennt&lt;/strong&gt; í forritinu &lt;strong&gt;Stillingar&lt;/strong&gt;.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">Stjórnandinn þinn endurræsir tækið klukkan <ph name="TIME" /> <ph name="DATE" /></translation>
+<translation id="156703335097561114">Upplýsingar um netkerfi á borð við vefföng, stillingar viðmóts og gæði tengingar</translation>
<translation id="1567040042588613346">Þessi regla virkar sem skyldi en sama gildi er stillt annars staðar og þessi regla leysir það af hólmi.</translation>
<translation id="1569487616857761740">Sláðu inn lokadagsetningu</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="1583429793053364125">Eitthvað fór úrskeiðis við að birta þessa vefsíðu.</translation>
<translation id="1586541204584340881">Hvaða viðbætur þú hefur sett upp</translation>
<translation id="1588438908519853928">Venjuleg</translation>
+<translation id="1589050138437146318">Setja upp ARCore?</translation>
<translation id="1592005682883173041">Aðgangur að staðbundnum gögnum</translation>
<translation id="1594030484168838125">Velja</translation>
<translation id="160851722280695521">Spila Dino Run-leikinn í Chrome</translation>
@@ -283,6 +298,7 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
hausinn er gallaður, sem kemur í veg fyrir að vafrinn geti uppfyllt
beiðni þína fyrir <ph name="SITE" />. Notendur síðu geta notað upprunareglur
til að stilla öryggi og aðra eiginleika síðu.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Nánar um huliðsstillingu í Chromium<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">Opnir flipar birtast hér</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -410,6 +426,7 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="22081806969704220">Bakki 3</translation>
<translation id="2212735316055980242">Regla fannst ekki</translation>
<translation id="2213606439339815911">Sækir færslur...</translation>
+<translation id="2213612003795704869">Síða er prentuð</translation>
<translation id="2215727959747642672">Skráarvinnsla</translation>
<translation id="2218879909401188352">Tölvuþrjótar sem eru á <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> núna gætu sett upp hættuleg forrit sem skaða tækið þitt, setja faldar færslur á símreikninginn þinn eða stela persónuupplýsingunum þínum. <ph name="BEGIN_LEARN_MORE_LINK" />Frekari upplýsingar<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">Engin nettenging</translation>
@@ -419,6 +436,7 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="2248949050832152960">Nota WebAuthn</translation>
<translation id="2250931979407627383">Saumur vinstra megin</translation>
<translation id="225207911366869382">Þetta gildi er úrelt fyrir þessa reglu.</translation>
+<translation id="2256115617011615191">Endurræsa núna</translation>
<translation id="2258928405015593961">Sláðu inn lokadagsetningu í framtíðinni og reyndu aftur</translation>
<translation id="225943865679747347">Villukóði: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">HTTP-villa</translation>
@@ -446,6 +464,7 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="2337852623177822836">Kerfisstjóri stýrir þessari stillingu</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> vill parast</translation>
<translation id="2346319942568447007">Mynd sem þú afritaðir</translation>
+<translation id="2350796302381711542">Leyfa <ph name="HANDLER_HOSTNAME" /> að opna alla <ph name="PROTOCOL" />-tengla í stað <ph name="REPLACED_HANDLER_TITLE" />?</translation>
<translation id="2354001756790975382">Önnur bókamerki</translation>
<translation id="2354430244986887761">Örugg vefnotkun Google <ph name="BEGIN_LINK" />fann skaðleg forrit<ph name="END_LINK" /> á <ph name="SITE" /> nýlega.</translation>
<translation id="2355395290879513365">Tölvuþrjótar gætu séð myndirnar sem þú skoðar á þessu vefsvæði og gabbað þig með því að breyta þeim.</translation>
@@ -471,6 +490,7 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="2413528052993050574">Þessi þjónn gat ekki sannað að hann væri <ph name="DOMAIN" />; öryggisvottorð hans gæti hafa verið afturkallað. Þetta kann að orsakast af vanstillingu eða tölvuþrjóti sem komist hefur inn í tenginguna.</translation>
<translation id="2414886740292270097">Dökkt</translation>
<translation id="2430968933669123598">Stjórnaðu Google reikningnum þínum, ýttu á Enter til að stjórna upplýsingum, persónuvernd og öryggi á Google reikningnum þínum</translation>
+<translation id="2436186046335138073">Leyfa <ph name="HANDLER_HOSTNAME" /> að opna alla <ph name="PROTOCOL" />-tengla?</translation>
<translation id="2438874542388153331">Fjögur göt hægra megin</translation>
<translation id="2450021089947420533">Ferðir</translation>
<translation id="2463739503403862330">Fylla út</translation>
@@ -478,6 +498,7 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="2465655957518002998">Velja afhendingarmáta</translation>
<translation id="2465688316154986572">Hefti</translation>
<translation id="2465914000209955735">Stjórna skrám sem þú hefur sótt í Chrome</translation>
+<translation id="2466004615675155314">Birta upplýsingar af vefnum</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Keyrir netgreiningu<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">Röðun 1 til N</translation>
<translation id="2470767536994572628">Þegar þú breytir textaskýringum fer þetta skjal aftur í einnar síðu snið og upprunalega stöðu</translation>
@@ -498,6 +519,7 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="2523886232349826891">Aðeins vistað í þessu tæki</translation>
<translation id="2524461107774643265">Bæta við fleiri upplýsingum</translation>
<translation id="2529899080962247600">Þessi reitur á ekki að innihalda fleiri en <ph name="MAX_ITEMS_LIMIT" /> færslur. Allar frekari færslur verða hunsaðar.</translation>
+<translation id="2535585790302968248">Opnaðu nýjan huliðsflipa til að fara huldu höfði</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{og 1 í viðbót}one{og # í viðbót}other{og # í viðbót}}</translation>
<translation id="2536110899380797252">Bæta við heimilisfangi</translation>
<translation id="2539524384386349900">Greina</translation>
@@ -523,7 +545,14 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="2597378329261239068">Þetta skjal er varið með aðgangsorði. Sláðu inn aðgangsorð.</translation>
<translation id="2609632851001447353">Tilbrigði</translation>
<translation id="2610561535971892504">Smelltu til að afrita</translation>
+<translation id="2617988307566202237">Chrome <ph name="BEGIN_EMPHASIS" />vistar ekki<ph name="END_EMPHASIS" /> eftirfarandi upplýsingar:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Vafraferilinn þinn
+ <ph name="LIST_ITEM" />Fótspor og gögn vefsvæða
+ <ph name="LIST_ITEM" />Upplýsingar sem eru færðar inn í eyðublöð
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (umslag)</translation>
+<translation id="2623663032199728144">Má biðja um að nota upplýsingar um skjáina þína</translation>
<translation id="2625385379895617796">Klukkan þín er á undan</translation>
<translation id="262745152991669301">Getur beðið um að tengjast við USB-tæki</translation>
<translation id="2629325967560697240">Til að fá mesta öryggi sem Chrome býður upp á skaltu <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />kveikja á aukinni vörn<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -557,6 +586,7 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="2709516037105925701">Sjálfvirk útfylling</translation>
<translation id="2713444072780614174">Hvítur</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />, ýttu á Tab og svo Enter til að stjórna greiðslu- og kreditkortaupplýsingum í stillingum Chrome</translation>
+<translation id="271663710482723385">Ãttu á |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| til að hætta birtingu á öllum skjánum</translation>
<translation id="2721148159707890343">Beiðni tókst</translation>
<translation id="2723669454293168317">Keyra öryggisathugun í stillingum Chrome</translation>
<translation id="2726001110728089263">Hliðarbakki</translation>
@@ -587,6 +617,7 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="2850739647070081192">Invite (umslag)</translation>
<translation id="2856444702002559011">Tölvuþrjótar gætu verið að reyna að stela upplýsingum þínum frá <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (til dæmis aðgangsorðum, skilaboðum eða kreditkortum). <ph name="BEGIN_LEARN_MORE_LINK" />Frekari upplýsingar<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">Þetta vefsvæði sýnir ágengar eða villandi auglýsingar.</translation>
+<translation id="286512204874376891">Sýndarkort dulbýr raunverulega kortið þitt og hjálpar þannig til við að koma í veg fyrir svik. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">Vinalegt</translation>
<translation id="2876489322757410363">Slekkur á huliðsstillingu til að greiða með öðru forriti. Halda áfram?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />, ýttu á dálkalykilinn (Tab) og svo Enter til að stjórna öruggri vefskoðun og fleiru í stillingum Chrome</translation>
@@ -611,6 +642,7 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="2930577230479659665">Klippa eftir hvert eintak</translation>
<translation id="2932085390869194046">Tillaga að aðgangsorði...</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019">Opna tengla fyrir <ph name="PROTOCOL" /></translation>
<translation id="2941952326391522266">Þessi þjónn gat ekki sannað að hann væri <ph name="DOMAIN" />; öryggisvottorð hans er frá <ph name="DOMAIN2" />. Þetta kann að orsakast af vanstillingu eða tölvuþrjóti sem komist hefur inn í tenginguna.</translation>
<translation id="2943895734390379394">Tími sendingar:</translation>
<translation id="2948083400971632585">Þú getur gert hvaða proxy-þjón sem stilltur er fyrir tengingu óvirkan á stillingasíðunni.</translation>
@@ -643,6 +675,7 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="3037605927509011580">Rækallinn!</translation>
<translation id="3041612393474885105">Upplýsingar um vottorð</translation>
<translation id="3044034790304486808">Halda rannsókninni áfram</translation>
+<translation id="305162504811187366">Feril fjarstjórnunar tölvu í Chrome, þ.m.t. tímastimpla, hýsla og auðkenni biðlaralota</translation>
<translation id="3060227939791841287">C9 (umslag)</translation>
<translation id="3061707000357573562">Plástraþjónusta</translation>
<translation id="306573536155379004">Leikur hafinn.</translation>
@@ -683,6 +716,7 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="3197136577151645743">Getur beðið um að fá að vita hvenær þú ert að nota tækið</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />, ýttu á dálkalykilinn (Tab) og svo „Enter“ til að opna stillingar Chrome og stjórna því hvaða upplýsingar þú samstillir</translation>
<translation id="320323717674993345">Hætta við greiðslu</translation>
+<translation id="3203366800380907218">Af vefnum</translation>
<translation id="3207960819495026254">à bókamerkjum</translation>
<translation id="3209034400446768650">Síðan kann að rukka gjald</translation>
<translation id="3212581601480735796">Fylgst er með virkni þinni á <ph name="HOSTNAME" /></translation>
@@ -699,10 +733,12 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="3234666976984236645">Greina alltaf mikilvægt efni á þessu vefsvæði</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />, ýttu á dálkalykilinn (Tab) og svo Enter til að sérstilla útlit vafrans</translation>
<translation id="3240791268468473923">Skilríki öruggrar greiðslu — tilkynningasíða um engin samsvarandi skilríki var opnuð</translation>
+<translation id="324180406144491771">Lokað er á „<ph name="HOST_NAME" />“ tengla</translation>
<translation id="3249845759089040423">Mergjað</translation>
<translation id="3252266817569339921">Franskt</translation>
<translation id="3257954757204451555">Hver birti þessar upplýsingar?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />, ýttu á Tab og svo Enter til að búa til nýjan viðburð í Google dagatali á skjótan hátt</translation>
+<translation id="3261488570342242926">Nánar um sýndarkort</translation>
<translation id="3264837738038045344">Hnappur til að stjórna stillingum Chrome, ýttu á Enter til að opna stillingar Chrome</translation>
<translation id="3266793032086590337">Gildi (skörun)</translation>
<translation id="3268451620468152448">Opna flipa</translation>
@@ -716,6 +752,7 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="3288238092761586174"><ph name="URL" /> þarf hugsanlega að framkvæma viðbótarskref til að staðfesta greiðsluna frá þér</translation>
<translation id="3293642807462928945">Frekari upplýsingar um regluna „<ph name="POLICY_NAME" />“</translation>
<translation id="3295444047715739395">Skoða og stjórna aðgangsorðunum þínum í stillingum Chrome</translation>
+<translation id="3303795387212510132">Leyfa forritinu að opna <ph name="PROTOCOL_SCHEME" /> tengla?</translation>
<translation id="3303855915957856445">Engar leitarniðurstöður fundust</translation>
<translation id="3304073249511302126">Bluetooth-leit</translation>
<translation id="3308006649705061278">Skipulagseining (OU)</translation>
@@ -729,12 +766,6 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="3345782426586609320">Augu</translation>
<translation id="3355823806454867987">Breyta proxy-stillingum...</translation>
<translation id="3360103848165129075">Greiðsluhjálparforrit</translation>
-<translation id="3361596688432910856">Chrome <ph name="BEGIN_EMPHASIS" />mun ekki vista<ph name="END_EMPHASIS" /> eftirfarandi upplýsingar:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Vafraferilinn þinn
- <ph name="LIST_ITEM" />Fótspor og vefsvæðagögn
- <ph name="LIST_ITEM" />Upplýsingar sem eru færðar í eyðublöð
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">Þessi regla var sjálfkrafa afrituð úr úreltu <ph name="OLD_POLICY" /> reglunni. Þú ættir að nota þessa reglu í staðinn.</translation>
<translation id="3364869320075768271"><ph name="URL" /> vill fá að nota sýndarveruleikatæki og -gögn</translation>
<translation id="3366477098757335611">Skoða kort</translation>
@@ -817,7 +848,6 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="3587738293690942763">Miðja</translation>
<translation id="3592413004129370115">Italian (umslag)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{Þú getur endurstillt hópinn þinn hvenær sem er. Það tekur um einn dag að ganga í nýjan hóp.}=1{Þú getur endurstillt hópinn þinn hvenær sem er. Það tekur um einn dag að ganga í nýjan hóp.}one{Þú getur endurstillt hópinn þinn hvenær sem er. Það tekur {NUM_DAYS} dag að ganga í nýjan hóp.}other{Þú getur endurstillt hópinn þinn hvenær sem er. Það tekur {NUM_DAYS} daga að ganga í nýjan hóp.}}</translation>
-<translation id="3596012367874587041">Forritastillingar</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">Kerfisstjóri hefur lokað á þetta forrit</translation>
<translation id="3608932978122581043">Inntaksstefna</translation>
@@ -860,6 +890,7 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="370972442370243704">Kveikja á ferðum</translation>
<translation id="3711895659073496551">Biðstaða</translation>
<translation id="3712624925041724820">Leyfi uppurin</translation>
+<translation id="3714633008798122362">vefdagatal</translation>
<translation id="3714780639079136834">Kveikja á farsímagögnum eða Wi-Fi</translation>
<translation id="3715597595485130451">Tengstu við Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Athuga staðgengilsþjóninn, eldvegginn og DNS-stillingarnar<ph name="END_LINK" /></translation>
@@ -921,6 +952,7 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="3906954721959377182">Spjaldtölva</translation>
<translation id="3909477809443608991"><ph name="URL" /> vill spila varið efni. Auðkenni tækisins verður staðfest af Google og þetta vefsvæði kann að fá aðgang að því.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">Hafna</translation>
<translation id="3939773374150895049">Nota WebAuthn í stað CVC-númers?</translation>
<translation id="3946209740501886391">Alltaf spyrja á þessu vefsvæði</translation>
<translation id="3947595700203588284">Geta beðið um að fá að tengjast MIDI-tækjum</translation>
@@ -942,6 +974,7 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="3990250421422698716">Jöfnuð offsetprentun</translation>
<translation id="3996311196211510766">Vefsvæðið <ph name="ORIGIN" /> hefur beðið um að upprunaregla
gildi fyrir allar beiðnir þess, en ekki er hægt að nota þessa reglu eins og er.</translation>
+<translation id="4009243425692662128">Efni síðna sem þú prentar er sent til Google Cloud eða þriðju aðila til greiningar. Þær gætu til dæmis verið skannaðar í leit að viðkvæmum upplýsingum.</translation>
<translation id="4010758435855888356">Veita aðgang að geymslurými?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{PDF-skjal með {COUNT} síðu}one{PDF-skjal með {COUNT} síðu}other{PDF-skjal með {COUNT} síðum}}</translation>
<translation id="4023431997072828269">Þar sem þetta eyðublað er sent með tengingu sem er ekki örugg verða upplýsingarnar þínar sýnilegar öðrum.</translation>
@@ -1036,6 +1069,7 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="4250680216510889253">Nei</translation>
<translation id="4253168017788158739">Athugasemd</translation>
<translation id="425582637250725228">Hugsanlegt er að breytingarnar þínar séu ekki vistaðar.</translation>
+<translation id="425869179292622354">Auka öryggið með sýndarkorti?</translation>
<translation id="4258748452823770588">Röng undirskrift</translation>
<translation id="4261046003697461417">Ekki er hægt að skrifa skýringar á varin skjöl</translation>
<translation id="4265872034478892965">Heimilað af kerfisstjóra þínum</translation>
@@ -1098,6 +1132,7 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="4434045419905280838">Sprettigluggar og framsendingar</translation>
<translation id="4435702339979719576">póstkort)</translation>
<translation id="443673843213245140">Slökkt er á notkun proxy-þjóns en sérstök proxy-stilling er tilgreind.</translation>
+<translation id="4441832193888514600">Hunsað vegna þess að aðeins er hægt að stilla regluna sem notendareglu í skýi.</translation>
<translation id="4450893287417543264">Ekki sýna þetta aftur</translation>
<translation id="4451135742916150903">Getur beðið um að tengjast HID-tækjum</translation>
<translation id="4452328064229197696">Aðgangsorðið sem þú varst að nota fannst nýverið í öryggisbroti. Aðgangsorðastjórnun Google mælir með að þú athugir vistuð aðgangsorð til að tryggja öryggi reikninganna þinna.</translation>
@@ -1153,6 +1188,7 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="4628948037717959914">Mynd</translation>
<translation id="4631649115723685955">Fjárvildarkerfi tengt</translation>
<translation id="4636930964841734540">Upplýsingar</translation>
+<translation id="4638670630777875591">Huliðsstilling í Chromium</translation>
<translation id="464342062220857295">Leitareiginleikar</translation>
<translation id="4644670975240021822">Öfug röð, snýr niður</translation>
<translation id="4646534391647090355">Fara þangað núna</translation>
@@ -1173,6 +1209,7 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="4708268264240856090">Tengingin þín var rofin</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Keyrir Windows-netgreiningu<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426">Aðgangsorð fyrir <ph name="USERNAME" /></translation>
<translation id="4724144314178270921">Getur beðið um að sjá texta og myndir á klippiborðinu</translation>
<translation id="4726672564094551039">Endurhlaða reglur</translation>
<translation id="4728558894243024398">Kerfi</translation>
@@ -1194,6 +1231,7 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="4757993714154412917">Þú gafst upp aðgangsorðið þitt á svindlsíðu. Chromium mælir með því að þú athugir vistuðu aðgangsorðin þín núna til að tryggja öryggi reikninganna þinna.</translation>
<translation id="4758311279753947758">Bæta við samskiptaupplýsingum</translation>
<translation id="4761104368405085019">Nota hljóðnemann</translation>
+<translation id="4761869838909035636">Keyra öryggisathugun í Chrome</translation>
<translation id="4764776831041365478">Vefsíðan á <ph name="URL" /> gæti legið niðri tímabundið eða gæti hafa verið flutt varanlega á annað veffang.</translation>
<translation id="4766713847338118463">Tvö hefti neðst</translation>
<translation id="4771973620359291008">Óþekkt villa kom upp.</translation>
@@ -1214,12 +1252,6 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="4819347708020428563">Breyta textaskýringum í sjálfgefnu sniði?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />, ýttu á Tab og svo Enter til að búa til nýjan Google töflureikni á skjótan hátt</translation>
<translation id="4825507807291741242">Kraftmikið</translation>
-<translation id="4827402517081186284">Huliðsstilling gerir þig ekki ósýnilega(n) á netinu:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Vefsvæði vita þegar þú opnar þau<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Vinnuveitendur eða skólar geta rakið vafranotkun<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Netþjónustur kunna að fylgjast með netumferð<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">Kveikja á viðvörunum</translation>
<translation id="4838327282952368871">Draumkennt</translation>
<translation id="4840250757394056958">Skoða Chrome ferilinn þinn</translation>
@@ -1231,12 +1263,12 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="4854362297993841467">Þessi sendingarmáti er ekki í boði. Prófaðu að velja annan valkost.</translation>
<translation id="4854853140771946034">Búa til nýja glósu í Google Keep á skjótan hátt</translation>
<translation id="485902285759009870">Staðfestir kóða...</translation>
+<translation id="4866506163384898554">Ãttu á |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| til að sýna bendilinn</translation>
<translation id="4876188919622883022">Einfaldað yfirlit</translation>
<translation id="4876305945144899064">Ekkert notandanafn</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{Ekkert}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}one{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831"><ph name="TEXT" />-leit</translation>
<translation id="4879491255372875719">Sjálfvirkt (sjálfgildi)</translation>
-<translation id="4879725228911483934">Opna og setja glugga á skjáinn</translation>
<translation id="4880827082731008257">Leitarferill</translation>
<translation id="4881695831933465202">Opna</translation>
<translation id="4885256590493466218">Greiddu með <ph name="CARD_DETAIL" /> þegar þú gengur frá kaupunum</translation>
@@ -1245,6 +1277,7 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">Níunda rúlla</translation>
<translation id="4901778704868714008">Vista...</translation>
+<translation id="4905659621780993806">Stjórnandinn mun endurræsa tækið þitt sjálfkrafa kl. <ph name="TIME" /> <ph name="DATE" />. Vistaðu opin atriði áður en tækið verður endurræst.</translation>
<translation id="4913987521957242411">Hefti efst vinstra megin</translation>
<translation id="4918221908152712722">Settu upp <ph name="APP_NAME" /> (ekkert niðurhal)</translation>
<translation id="4923459931733593730">Greiðslumáti</translation>
@@ -1253,6 +1286,7 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, ýttu á Tab og svo Enter til að leita</translation>
<translation id="4930153903256238152">Stór bakki</translation>
+<translation id="4940163644868678279">Huliðsstilling í Chrome</translation>
<translation id="4943872375798546930">Engar niðurstöður</translation>
<translation id="4950898438188848926">Hnappur til að skipta um flipa; ýttu á færslulykilinn til að skipta yfir í opinn flipa, <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="495170559598752135">Aðgerðir</translation>
@@ -1262,6 +1296,7 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="4968522289500246572">Þetta forrit er hannað fyrir snjalltæki og óvíst er að breytingar á stærð komi vel út. Vandamál gætu komið upp í forritinu eða endurræsing þess gæti átt sér stað.</translation>
<translation id="4969341057194253438">Eyða upptöku</translation>
<translation id="4973922308112707173">Tvö göt efst</translation>
+<translation id="4976702386844183910">Síðast skoðað <ph name="DATE" /></translation>
<translation id="4984088539114770594">Nota hljóðnema?</translation>
<translation id="4984339528288761049">Prc5 (umslag)</translation>
<translation id="4989163558385430922">Sjá allt</translation>
@@ -1323,6 +1358,7 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="5138227688689900538">Sýna minna</translation>
<translation id="5145883236150621069">Villukóði til staðar í stefnusvari</translation>
<translation id="5146995429444047494">Lokað er fyrir tilkynningar fyrir <ph name="ORIGIN" /></translation>
+<translation id="514704532284964975"><ph name="URL" /> vill sjá og breyta upplýsingum í NFC-tækjum sem þú notar símann þinn á</translation>
<translation id="5148809049217731050">Snýr upp</translation>
<translation id="515292512908731282">C4 (umslag)</translation>
<translation id="5158275234811857234">Forsíða</translation>
@@ -1347,6 +1383,7 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="5215116848420601511">Greiðslumátar og heimilisföng sem nota Google Pay</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">Bakki 13</translation>
+<translation id="5216942107514965959">Síðast opnað í dag</translation>
<translation id="5222812217790122047">Netfang er nauðsynlegt</translation>
<translation id="5230733896359313003">Sendingarheimilisfang</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1367,7 +1404,6 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">Eiginleikar skjals</translation>
<translation id="528468243742722775">Ljúka</translation>
-<translation id="5284909709419567258">Vistföng netkerfa</translation>
<translation id="5285570108065881030">Sýna öll vistuð aðgangsorð</translation>
<translation id="5287240709317226393">Sýna fótspor</translation>
<translation id="5287456746628258573">Þetta vefsvæði notar úrelta öryggisstillingu sem gæti sett upplýsingar þínar í hættu (til dæmis aðgangsorð eða kreditkortanúmer) þegar þær eru sendar til vefsvæðisins.</translation>
@@ -1451,6 +1487,7 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="5556459405103347317">Endurhlaða</translation>
<translation id="5560088892362098740">Lokadagsetning</translation>
<translation id="55635442646131152">Uppsetning skjals</translation>
+<translation id="5565613213060953222">Opna huliðsflipa</translation>
<translation id="5565735124758917034">Virkt</translation>
<translation id="5570825185877910964">Vernda reikning</translation>
<translation id="5571083550517324815">Ekki er hægt að sækja frá þessu heimilisfangi. Veldu annað heimilisfang.</translation>
@@ -1533,6 +1570,7 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="5869522115854928033">Vistuð aðgangsorð</translation>
<translation id="5873013647450402046">Bankinn þinn vill staðfesta að um þig sé að ræða.</translation>
<translation id="5887400589839399685">Kort vistað</translation>
+<translation id="5887687176710214216">Síðast opnað í gær</translation>
<translation id="5895138241574237353">Endurræsa</translation>
<translation id="5895187275912066135">Gefið út</translation>
<translation id="5901630391730855834">Gulur</translation>
@@ -1546,6 +1584,7 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="5921639886840618607">Viltu vista kortið á Google reikningnum?</translation>
<translation id="5922853866070715753">Næstum búið</translation>
<translation id="5932224571077948991">Vefsvæðið sýnir ágengar eða villandi auglýsingar.</translation>
+<translation id="5938153366081463283">Bæta við sýndarkorti</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347">Opnar <ph name="SITE_NAME" />…</translation>
<translation id="5951495562196540101">Þú getur ekki skráð þig með almennum reikningi (pakkaleyfi í boði).</translation>
@@ -1610,6 +1649,7 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="6120179357481664955">Muna eftir UPI-auðkenni?</translation>
<translation id="6124432979022149706">Chrome Enterprise Connectors</translation>
<translation id="6127379762771434464">Atriði fjarlægt</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Nánar um huliðsstillingu í Chrome<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">Kannaðu allar snúrur og endurræstu beina, mótöld og önnur
nettæki sem þú kannt að vera að nota.</translation>
<translation id="614940544461990577">Prófaðu að:</translation>
@@ -1622,7 +1662,6 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="6169916984152623906">Nú geturðu vafrað í næði og aðrir notendur tækisins geta ekki séð það sem þú gerir. Niðurhal og bókamerki eru hinsvegar vistuð.</translation>
<translation id="6177128806592000436">Tenging þín við þetta vefsvæði er ekki örugg</translation>
<translation id="6180316780098470077">Tími milli tilrauna</translation>
-<translation id="619448280891863779">Geta beðið um að opna og koma gluggum fyrir á skjánum</translation>
<translation id="6196640612572343990">Loka á fótspor frá þriðja aðila</translation>
<translation id="6203231073485539293">Athugaðu internettenginguna</translation>
<translation id="6218753634732582820">Fjarlægja netfang úr Chromium?</translation>
@@ -1645,7 +1684,7 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="6272383483618007430">Google uppfærslur</translation>
<translation id="6276112860590028508">Síður úr leslistanum þínum birtast hér</translation>
<translation id="627746635834430766">Til að greiða hraðar næst geturðu vistað kortið og heimilisfang greiðanda á Google reikningnum.</translation>
-<translation id="6279098320682980337">Var sýndarkortsnúmerið ekki útfyllt? Smelltu á upplýsingar kortsins til að afrita</translation>
+<translation id="6279183038361895380">Ãttu á |<ph name="ACCELERATOR" />| til að sýna bendilinn</translation>
<translation id="6280223929691119688">Ekki er hægt að senda á þetta heimilisfang. Veldu annað heimilisfang.</translation>
<translation id="6282194474023008486">Póstnúmer</translation>
<translation id="6285507000506177184">Hnappur til að stjórna niðurhali í Chrome, ýttu á Enter til að stjórna skrám sem þú hefur sótt í Chrome</translation>
@@ -1653,6 +1692,7 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="6290238015253830360">Tillögur að greinum birtast hér</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{Tækið verður endurræst núna}=1{Tækið verður endurræst eftir 1 sekúndu}one{Tækið verður endurræst eftir # sekúndu}other{Tækið verður endurræst eftir # sekúndur}}</translation>
<translation id="6302269476990306341">Google hjálpari í Chrome stoppar</translation>
<translation id="6305205051461490394">Ekki næst í <ph name="URL" />.</translation>
<translation id="6312113039770857350">Vefsíðan er ekki tiltæk</translation>
@@ -1726,6 +1766,7 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="6529602333819889595">Endu&amp;rtaka eyðingu</translation>
<translation id="6545864417968258051">Bluetooth-leit</translation>
<translation id="6547208576736763147">Tvö göt vinstra megin</translation>
+<translation id="6554732001434021288">Síðast opnað fyrir <ph name="NUM_DAYS" /> dögum</translation>
<translation id="6556866813142980365">Endurgera</translation>
<translation id="6569060085658103619">Þú ert að skoða viðbótarsíðu</translation>
<translation id="6573200754375280815">Tvö göt hægra megin</translation>
@@ -1786,7 +1827,6 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="6757797048963528358">Tækið þitt fór að sofa.</translation>
<translation id="6767985426384634228">Uppfæra heimilisfang?</translation>
<translation id="6768213884286397650">Hagaki (póstkort)</translation>
-<translation id="6774185088257932239"><ph name="BEGIN_LINK" />Nánar<ph name="END_LINK" /> um huliðsstillingu</translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">Fjólublár</translation>
<translation id="6786747875388722282">Viðbætur</translation>
@@ -1870,7 +1910,6 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="706295145388601875">Bættu við og hafðu umsjón með vefslóðum í stillingum Chrome</translation>
<translation id="7064851114919012435">Samskiptaupplýsingar</translation>
<translation id="7068733155164172741">Sláðu inn <ph name="OTP_LENGTH" /> stafa kóða</translation>
-<translation id="7070090581017165256">Um þetta vefsvæði</translation>
<translation id="70705239631109039">Tengingin er ekki alveg örugg</translation>
<translation id="7075452647191940183">Beiðnin er of stór</translation>
<translation id="7079718277001814089">Þetta vefsvæði inniheldur spilliforrit</translation>
@@ -1887,6 +1926,12 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="7111012039238467737">(gilt)</translation>
<translation id="7118618213916969306">Leita að vefslóð á klippiborði, <ph name="SHORT_URL" /></translation>
<translation id="7119414471315195487">Lokaðu öðrum flipum eða forritum</translation>
+<translation id="7129355289156517987">Þegar þú lokar öllum huliðsflipum í Chromium er virkni þín á þessum flipum hreinsuð úr tækinu:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Vafranotkun<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Leitarferill<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Upplýsingar sem eru færðar inn í eyðublöð<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">Ekki er hægt að senda á þetta heimilisfang. Veldu annað heimilisfang.</translation>
<translation id="7132939140423847331">Stjórnandi hefur bannað afritun þessara gagna.</translation>
<translation id="7135130955892390533">Sýna stöðu</translation>
@@ -1909,6 +1954,7 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="7192203810768312527">Losar <ph name="SIZE" />. Lengri tíma gæti tekið að sækja sum vefsvæði þegar þú heimsækir þau næst.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">Kerfisstjórinn þinn getur séð:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, ýttu á dálkalykilinn (Tab) og svo Enter til að opna nýjan huliðsflipa og fara huldu höfði</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> uppfyllir ekki öryggiskröfur.</translation>
<translation id="7210993021468939304">Virkni innan Linux-rammans og getur sett upp og keyrt Linux-forrit innan rammans</translation>
@@ -1940,6 +1986,7 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="7304562222803846232">Stjórna persónuverndarstillingum Google reikningsins</translation>
<translation id="7305756307268530424">Ræsa hægari útgáfu</translation>
<translation id="7308436126008021607">samstillingu í bakgrunni</translation>
+<translation id="7310392214323165548">Tækið verður endurræst bráðlega</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">Tengingarhjálp</translation>
<translation id="7323804146520582233">Fela hlutann „<ph name="SECTION" />“</translation>
@@ -1947,6 +1994,7 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="7334320624316649418">Endu&amp;rtaka nýja röðun</translation>
<translation id="7335157162773372339">Getur beðið um að nota myndavélina</translation>
<translation id="7337248890521463931">Sýna fleiri línur</translation>
+<translation id="7337418456231055214">Var sýndarkortsnúmerið ekki útfyllt? Smelltu á upplýsingar kortsins til að afrita. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">Ekki í boði fyrir stýrikerfið þitt.</translation>
<translation id="733923710415886693">Vottorð vefþjóns var ekki birt í gegnum gagnsæi vottorðs.</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1969,6 +2017,7 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="7378627244592794276">Neibb</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">à ekki við</translation>
+<translation id="7388594495505979117">{0,plural, =1{Tækið verður endurræst eftir 1 mínútu}one{Tækið verður endurræst eftir # mínútu}other{Tækið verður endurræst eftir # mínútur}}</translation>
<translation id="7390545607259442187">Staðfesta kort</translation>
<translation id="7392089738299859607">Uppfæra heimilisfang</translation>
<translation id="7399802613464275309">Öryggisathugun</translation>
@@ -2005,6 +2054,12 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="7485870689360869515">Engin gögn fundust.</translation>
<translation id="7495528107193238112">Þetta efni er á bannlista. Hafðu samband við eiganda vefsvæðisins til að lagfæra vandamálið.</translation>
<translation id="7497998058912824456">Hnappurinn „Búa til skjal“, ýttu á Enter til að búa til nýtt Google skjal á skjótan hátt</translation>
+<translation id="7506488012654002225">Chromium <ph name="BEGIN_EMPHASIS" />vistar ekki<ph name="END_EMPHASIS" /> eftirfarandi upplýsingar:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Vafraferilinn þinn
+ <ph name="LIST_ITEM" />Fótspor og gögn vefsvæða
+ <ph name="LIST_ITEM" />Upplýsingar sem eru færðar inn í eyðublöð
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">Tækisauðkenni stefnu sem skilað var er autt eða stemmir ekki við núverandi tækisauðkenni</translation>
<translation id="7508870219247277067">Lárperugrænn</translation>
<translation id="7511955381719512146">Wi-Fi netið sem þú notar kann að fara fram á að þú farir á <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
@@ -2118,7 +2173,6 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="7813600968533626083">Fjarlægja eyðublaðstillögu úr Chrome?</translation>
<translation id="781440967107097262">Deila klippiborði?</translation>
<translation id="7815407501681723534"><ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> fundust fyrir „<ph name="SEARCH_STRING" />“.</translation>
-<translation id="782125616001965242">Sýna upplýsingar um þetta vefsvæði</translation>
<translation id="782886543891417279">Wi-Fi netið sem þú notar (<ph name="WIFI_NAME" />) kann að fara fram á að þú farir á innskráningarsíðu þess.</translation>
<translation id="7836231406687464395">Postfix (umslag)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{Ekkert}=1{1 forrit (<ph name="EXAMPLE_APP_1" />)}=2{2 forrit (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}one{# forrit (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}other{# forrit (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}}</translation>
@@ -2135,7 +2189,6 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="7888575728750733395">Tilgangur myndsetningar</translation>
<translation id="7894280532028510793">Ef stafsetningin er rétt skaltu <ph name="BEGIN_LINK" />prófa að keyra bilanaleit á netkerfi<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (umslag)</translation>
-<translation id="7931318309563332511">Óþekkt</translation>
<translation id="793209273132572360">Uppfæra heimilisfang?</translation>
<translation id="7932579305932748336">Kápa</translation>
<translation id="79338296614623784">Færðu inn gilt símanúmer</translation>
@@ -2160,13 +2213,14 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="7976214039405368314">Of margar beiðnir</translation>
<translation id="7977538094055660992">Úttakstæki</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">Tengt við</translation>
<translation id="798134797138789862">Getur beðið um leyfi til að nota sýndarveruleikatæki og -gögn</translation>
<translation id="7984945080620862648">Þú getur ekki heimsótt <ph name="SITE" /> í augnablikinu vegna þess að vefsvæðið sendi rugluð skilríki sem Chrome getur ekki unnið úr. Netvillur og árásir eru yfirleitt tímabundnar og því mun þessi síða líklega virka síðar.</translation>
-<translation id="79859296434321399">Til að skoða efni aukins veruleika skaltu setja upp ARCore</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">Binda</translation>
<translation id="7992044431894087211">Skjádeilingu með <ph name="APPLICATION_TITLE" /> var haldið áfram</translation>
<translation id="7995512525968007366">Ekki tilgreint</translation>
+<translation id="7998269595945679889">Hnappurinn „Opna huliðsglugga“, ýttu á Enter til að opna nýjan huliðsglugga og fara huldu höfði</translation>
<translation id="800218591365569300">Prófaðu að loka öðrum forritum til að losa um minni.</translation>
<translation id="8004582292198964060">Vafri</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{Þetta kort og heimilisfang greiðanda verða vistuð. Þú getur notað kortið þegar þú hefur skráð þig inn á <ph name="USER_EMAIL" />.}one{Þessi kort og heimilisföng greiðanda verða vistuð. Þú getur notað kortin þegar þú hefur skráð þig inn á <ph name="USER_EMAIL" />.}other{Þessi kort og heimilisföng greiðanda verða vistuð. Þú getur notað kortin þegar þú hefur skráð þig inn á <ph name="USER_EMAIL" />.}}</translation>
@@ -2226,6 +2280,7 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="8202370299023114387">Skörun</translation>
<translation id="8206978196348664717">Prc4 (umslag)</translation>
<translation id="8211406090763984747">Tengingin er örugg</translation>
+<translation id="8217240300496046857">Vefsvæði geta ekki notað fótspor sem rekja virkni þína á vefnum. Ekki er víst að allir eiginleikar á öllum vefsvæðum virki.</translation>
<translation id="8218327578424803826">Úthlutuð staðsetning:</translation>
<translation id="8220146938470311105">C7/C6 (umslag)</translation>
<translation id="8225771182978767009">Sá sem setti upp þessa tölvu valdi að loka fyrir þetta vefsvæði.</translation>
@@ -2266,14 +2321,9 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="830498451218851433">Brotið í miðju</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">Uppsett forrit og hversu oft þau eru notuð</translation>
+<translation id="8317207217658302555">Uppfæra ARCore?</translation>
<translation id="831997045666694187">Kvöld</translation>
<translation id="8321476692217554900">tilkynningar</translation>
-<translation id="8328484624016508118">Chrome hreinsar eftirfarandi um leið og öllum huliðsflipum er lokað:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Vafranotkun þína í þessu tæki<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Leitarferil þinn þessu tæki<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Upplýsingar sem slegnar voru inn á eyðublöð<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489">Ekki fæst aðgangur að <ph name="HOST_NAME" /></translation>
<translation id="833262891116910667">Auðkenna</translation>
<translation id="8339163506404995330">Síður á þessu tungumáli verða ekki þýddar: <ph name="LANGUAGE" /></translation>
@@ -2325,6 +2375,7 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="8507227106804027148">Skipanalína</translation>
<translation id="8508648098325802031">Leitartákn</translation>
<translation id="8511402995811232419">Stjórna fótsporum</translation>
+<translation id="8519753333133776369">HID-tæki heimilað af stjórnanda</translation>
<translation id="8522552481199248698">Chrome getur hjálpað þér að vernda Google reikninginn þinn og breyta aðgangsorðinu.</translation>
<translation id="8530813470445476232">Hreinsaðu vafraferilinn þinn, fótspor, skyndiminni og fleira í stillingum Chrome</translation>
<translation id="8533619373899488139">Opnaðu &lt;strong&gt;chrome://policy&lt;/strong&gt; til að sjá vefslóðir á bannlista og aðrar reglur sem kerfisstjórinn þinn setur.</translation>
@@ -2336,7 +2387,6 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{Endurstilla heimild}one{Endurstilla heimild}other{Endurstilla heimildir}}</translation>
<translation id="8555010941760982128">Notaðu þennan kóða við greiðslu</translation>
<translation id="8557066899867184262">CVC-númer er aftan á kortinu.</translation>
-<translation id="8558485628462305855">Til að skoða efni aukins veruleika skaltu uppfæra ARCore</translation>
<translation id="8559762987265718583">Ekki er hægt að koma á lokaðri tengingu við <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> vegna þess að dag- og tímasetning tækisins (<ph name="DATE_AND_TIME" />) er röng.</translation>
<translation id="8564182942834072828">Aðskilin skjöl / ekki samröðuð eintök</translation>
<translation id="8564985650692024650">Chromium mælir með því að þú endurstillir aðgangsorðið fyrir <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> ef þú notaðir það einnig á öðrum síðum.</translation>
@@ -2355,6 +2405,7 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="865032292777205197">hreyfiskynjara</translation>
<translation id="8663226718884576429">Yfirlit pöntunar, <ph name="TOTAL_LABEL" />, frekari upplýsingar</translation>
<translation id="8666678546361132282">Enska</translation>
+<translation id="8669306706049782872">Nota upplýsingar um skjái til að opna og staðsetja glugga</translation>
<translation id="867224526087042813">Undirskrift</translation>
<translation id="8676424191133491403">Engin töf</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, svar, <ph name="ANSWER" /></translation>
@@ -2381,6 +2432,7 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="8731544501227493793">Hnappurinn Stjórna aðgangsorðum, ýttu á Enter til að skoða og stjórna aðgangsorðunum þínum í stillingum Chrome</translation>
<translation id="8734529307927223492"><ph name="DEVICE_TYPE" /> er í umsjón <ph name="MANAGER" /></translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, ýttu á Tab og svo Enter til að opna nýjan huliðsglugga og fara huldu höfði</translation>
+<translation id="8737685506611670901">Opna tengla fyrir <ph name="PROTOCOL" /> í staðinn fyrir <ph name="REPLACED_HANDLER_TITLE" /></translation>
<translation id="8738058698779197622">Klukka tölvunnar þarf að vera rétt til að hægt sé að koma á öruggri nettengingu. Þetta er vegna þess að vottorðin sem vefsvæði nota til að auðkenna sig eru aðeins gild í tiltekinn tíma. Chromium getur ekki kannað vottorðin þar sem klukka tækisins er röng.</translation>
<translation id="8740359287975076522">&lt;abbr id="dnsDefinition"&gt;DNS-slóð&lt;/abbr&gt; <ph name="HOST_NAME" /> fannst ekki. Vandamálið er í greiningu.</translation>
<translation id="8742371904523228557"><ph name="ONE_TIME_CODE" /> er kóðinn þinn fyrir <ph name="ORIGIN" /></translation>
@@ -2408,6 +2460,7 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="883848425547221593">Önnur bókamerki</translation>
<translation id="884264119367021077">Sendingarheimilisfang</translation>
<translation id="884923133447025588">Engin afturköllunarleið fannst.</translation>
+<translation id="8849262850971482943">Notaðu sýndarkortið þitt til að auka öryggi</translation>
<translation id="885730110891505394">Deilir með Google</translation>
<translation id="8858065207712248076">Chrome mælir með því að þú endurstillir aðgangsorðið fyrir <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> ef þú notaðir það einnig á öðrum síðum.</translation>
<translation id="885906927438988819">Ef stafsetningin er rétt skaltu <ph name="BEGIN_LINK" />prófa að keyra bilanaleit á netkerfi í Windows<ph name="END_LINK" />.</translation>
@@ -2457,6 +2510,7 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="9004367719664099443">VR-lota í gangi</translation>
<translation id="9005998258318286617">Mistókst að hlaða PDF-skjal.</translation>
<translation id="9008201768610948239">Hunsa</translation>
+<translation id="901834265349196618">tölvupóstur</translation>
<translation id="9020200922353704812">Heimilisfangs kortagreiðanda er krafist</translation>
<translation id="9020542370529661692">Þessi síða var þýdd yfir á <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9020742383383852663">A8</translation>
@@ -2505,6 +2559,7 @@ Ef þú gerir það ekki loka persónuverndarstillingar þínar á þennan aðga
<translation id="9150045010208374699">Nota myndavélina þína</translation>
<translation id="9150685862434908345">Kerfisstjórinn þinn getur breytt uppsetningu vafrans með fjartengingu. Virkni þinni í þessu tæki er einnig hægt að stjórna utan Chrome. <ph name="BEGIN_LINK" />Frekari upplýsingar<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">Uppfært</translation>
+<translation id="9155211586651734179">Tengd hljóðjaðartæki</translation>
<translation id="9157595877708044936">Setur upp...</translation>
<translation id="9158625974267017556">C6 (umslag)</translation>
<translation id="9164029392738894042">Nákvæmnisathugun</translation>
diff --git a/chromium/components/strings/components_strings_it.xtb b/chromium/components/strings/components_strings_it.xtb
index cbe4acd23af..83f9d030e51 100644
--- a/chromium/components/strings/components_strings_it.xtb
+++ b/chromium/components/strings/components_strings_it.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">Scopri i dettagli</translation>
<translation id="1030706264415084469"><ph name="URL" /> vuole memorizzare in modo definitivo grandi quantità di dati sul dispositivo</translation>
<translation id="1032854598605920125">Ruota in senso orario</translation>
+<translation id="1033329911862281889">La modalità di navigazione in incognito non ti rende invisibile online:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />I siti e i servizi che utilizzano possono rilevare le visite<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Datori di lavoro o scuole possono monitorare l'attività di navigazione<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />I provider di servizi Internet possono monitorare il traffico web<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">Disattiva</translation>
<translation id="1036982837258183574">Premi |<ph name="ACCELERATOR" />| per uscire dalla modalità a schermo intero</translation>
<translation id="1038106730571050514">Mostra suggerimenti</translation>
<translation id="1038842779957582377">nome sconosciuto</translation>
<translation id="1041998700806130099">Messaggio foglio di lavoro</translation>
<translation id="1048785276086539861">Quando modifichi le annotazioni, questo documento torna alla visualizzazione a pagina singola</translation>
-<translation id="1049743911850919806">In incognito</translation>
<translation id="1050038467049342496">Chiudi altre app</translation>
<translation id="1055184225775184556">&amp;Annulla aggiunta</translation>
<translation id="1056898198331236512">Avviso</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">Cache dei criteri integra</translation>
<translation id="1130564665089811311">Pulsante Traduci pagina, premi Invio per tradurre questa pagina con Google Traduttore</translation>
<translation id="1131264053432022307">Immagine copiata</translation>
+<translation id="1142846828089312304">Blocca cookie di terze parti nella modalità di navigazione in incognito</translation>
<translation id="1150979032973867961">Questo server non è riuscito a dimostrare che si tratta di <ph name="DOMAIN" />; il relativo certificato di sicurezza non è considerato attendibile dal sistema operativo del computer. Il problema potrebbe essere dovuto a un'errata configurazione o a un malintenzionato che intercetta la connessione.</translation>
<translation id="1151972924205500581">Password obbligatoria</translation>
<translation id="1156303062776767266">È visualizzato un file locale o condiviso</translation>
@@ -64,7 +70,6 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="1178581264944972037">Pausa</translation>
<translation id="1181037720776840403">Rimuovi</translation>
<translation id="1186201132766001848">Controlla password</translation>
-<translation id="1195210374336998651">Vai alle impostazioni dell'app</translation>
<translation id="1195558154361252544">Le notifiche vengono bloccate automaticamente per tutti i siti, tranne per quelli che consenti tu</translation>
<translation id="1197088940767939838">Arancione</translation>
<translation id="1201402288615127009">Avanti</translation>
@@ -111,7 +116,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="1307966114820526988">Funzionalità obsolete</translation>
<translation id="1308113895091915999">Offerta disponibile</translation>
<translation id="1312803275555673949">Quali prove ci sono a supporto?</translation>
-<translation id="131405271941274527"><ph name="URL" /> vuole inviare e ricevere informazioni su un dispositivo NFC quando tocchi il tuo telefono</translation>
+<translation id="1314311879718644478">Visualizza contenuti di realtà aumentata</translation>
<translation id="1314509827145471431">Rilegatura a destra</translation>
<translation id="1318023360584041678">Salvato nel gruppo di schede</translation>
<translation id="1319245136674974084">Non chiedere più per questa app</translation>
@@ -161,6 +166,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="142858679511221695">Utente Cloud</translation>
<translation id="1428729058023778569">Questo avviso è stato visualizzato perché il sito non supporta HTTPS. <ph name="BEGIN_LEARN_MORE_LINK" />Scopri di più<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">Stampa</translation>
+<translation id="1432187715652018471">La pagina vuole installare un gestore di servizi.</translation>
<translation id="1432581352905426595">Gestisci motori di ricerca</translation>
<translation id="1436185428532214179">Può chiedere di modificare file o cartelle sul dispositivo</translation>
<translation id="1442386063175183758">Piegatura a finestra a destra</translation>
@@ -181,6 +187,12 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="1483493594462132177">Invia</translation>
<translation id="1484290072879560759">Scegli l'indirizzo di spedizione</translation>
<translation id="1492194039220927094">Push dei criteri:</translation>
+<translation id="149293076951187737">Quando chiudi tutte le schede di navigazione in incognito di Chrome, la tua attività nelle schede viene cancellata da questo dispositivo:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Attività di navigazione<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Cronologia delle ricerche<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Informazioni inserite nei moduli<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">Torna alla scheda</translation>
<translation id="1501859676467574491">Mostra le carte dall'Account Google</translation>
<translation id="1507202001669085618">&lt;p&gt;Vedrai questo errore se stai utilizzando un portale Wi-Fi che richiede l'accesso per poterti connettere a Internet.&lt;/p&gt;
@@ -208,6 +220,8 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="1559572115229829303">&lt;p&gt;Impossibile stabilire una connessione privata con il sito <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> perché data e ora del dispositivo (<ph name="DATE_AND_TIME" />) non sono corrette.&lt;/p&gt;
&lt;p&gt;Regola data e ora nella sezione &lt;strong&gt;Generali&lt;/strong&gt; dell'app &lt;strong&gt;Impostazioni&lt;/strong&gt;.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">L'amministratore riavvierà il tuo dispositivo alle ore <ph name="TIME" /> del giorno <ph name="DATE" /></translation>
+<translation id="156703335097561114">Le informazioni di rete, come indirizzi, configurazione di interfaccia e qualità della connessione</translation>
<translation id="1567040042588613346">Questo criterio funziona come previsto, ma altrove è impostato lo stesso valore, che viene sostituito da questo criterio.</translation>
<translation id="1569487616857761740">Inserisci data di scadenza</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="1583429793053364125">Si è verificato un problema durante la visualizzazione della pagina web.</translation>
<translation id="1586541204584340881">Le estensioni che hai installato</translation>
<translation id="1588438908519853928">Normale</translation>
+<translation id="1589050138437146318">Vuoi installare ARCore?</translation>
<translation id="1592005682883173041">Accesso ai dati locali</translation>
<translation id="1594030484168838125">Scegli</translation>
<translation id="160851722280695521">Gioca a Dino in Chrome</translation>
@@ -249,7 +264,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="1699570257714336246">Mancano informazioni</translation>
<translation id="1703835215927279855">Letter</translation>
<translation id="1706625117072057435">Livelli di zoom</translation>
-<translation id="1706954506755087368">{1,plural, =1{Questo server non è riuscito a verificare che si tratti di <ph name="DOMAIN" />; il relativo certificato di sicurezza potrebbe essere attivo da domani. Il problema potrebbe essere dovuto a un'errata configurazione o a un malintenzionato che intercetta la connessione.}one{This server could not prove that it is <ph name="DOMAIN" />; its security certificate is supposedly from # days in the future. This may be caused by a misconfiguration or an attacker intercepting your connection.}other{Questo server non è riuscito a verificare che si tratti di <ph name="DOMAIN" />; il relativo certificato di sicurezza potrebbe essere attivo tra # giorni. Il problema potrebbe essere dovuto a un'errata configurazione o a un malintenzionato che intercetta la connessione.}}</translation>
+<translation id="1706954506755087368">{1,plural, =1{Questo server non è riuscito a verificare che si tratti di <ph name="DOMAIN" />; il relativo certificato di sicurezza potrebbe essere attivo da domani. Il problema potrebbe essere dovuto a un'errata configurazione o a un malintenzionato che intercetta la connessione.}other{Questo server non è riuscito a verificare che si tratti di <ph name="DOMAIN" />; il relativo certificato di sicurezza potrebbe essere attivo tra # giorni. Il problema potrebbe essere dovuto a un'errata configurazione o a un malintenzionato che intercetta la connessione.}}</translation>
<translation id="1710259589646384581">Sistema operativo</translation>
<translation id="1711234383449478798">Criterio ignorato perché il criterio <ph name="POLICY_NAME" /> non è impostato su <ph name="VALUE" />.</translation>
<translation id="1712552549805331520"><ph name="URL" /> vuole memorizzare in modo definitivo i dati sul computer locale</translation>
@@ -283,6 +298,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
l'intestazione non è in formato corretto e impedisce al browser di soddisfare
la tua richiesta per <ph name="SITE" />. I criteri di origine possono essere usati dagli
operatori del sito per configurare la sicurezza e altre proprietà del sito.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Scopri di più sulla modalità di navigazione in incognito in Chromium<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">Le tue schede aperte vengono visualizzate qui</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -314,7 +330,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="1883255238294161206">Comprimi elenco</translation>
<translation id="1890171020361705182">Gioco Dino. Un dinosauro pixelato corre in un ambiente desolato schivando cactus e pterodattili. Quando senti un segnale acustico, tocca per saltare gli ostacoli.</translation>
<translation id="1898423065542865115">Filtri</translation>
-<translation id="1901443836186977402">{1,plural, =1{Questo server non è riuscito a dimostrare che si tratta di <ph name="DOMAIN" />; il relativo certificato di sicurezza è scaduto nel corso delle ultime 24 ore. Il problema potrebbe essere dovuto a un'errata configurazione o a un malintenzionato che intercetta la connessione. L'orologio del computer è attualmente impostato su <ph name="CURRENT_DATE" />. È corretto? Se è sbagliato, devi regolare l'orologio di sistema e aggiornare la pagina.}one{Questo server non è riuscito a verificare che si tratti di <ph name="DOMAIN" />; il relativo certificato di sicurezza è scaduto # giorni fa. Il problema potrebbe essere dovuto a un'errata configurazione o a un malintenzionato che intercetta la connessione. L'orologio del computer è attualmente impostato su <ph name="CURRENT_DATE" />. È corretto? Se è sbagliato, devi regolare l'orologio di sistema e aggiornare la pagina.}other{Questo server non è riuscito a verificare che si tratti di <ph name="DOMAIN" />; il relativo certificato di sicurezza è scaduto # giorni fa. Il problema potrebbe essere dovuto a un'errata configurazione o a un malintenzionato che intercetta la connessione. L'orologio del computer è attualmente impostato su <ph name="CURRENT_DATE" />. È corretto? Se è sbagliato, devi regolare l'orologio di sistema e aggiornare la pagina.}}</translation>
+<translation id="1901443836186977402">{1,plural, =1{Questo server non è riuscito a dimostrare che si tratta di <ph name="DOMAIN" />; il relativo certificato di sicurezza è scaduto nel corso delle ultime 24 ore. Il problema potrebbe essere dovuto a un'errata configurazione o a un malintenzionato che intercetta la connessione. L'orologio del computer è attualmente impostato su <ph name="CURRENT_DATE" />. È corretto? Se è sbagliato, devi regolare l'orologio di sistema e aggiornare la pagina.}other{Questo server non è riuscito a verificare che si tratti di <ph name="DOMAIN" />; il relativo certificato di sicurezza è scaduto # giorni fa. Il problema potrebbe essere dovuto a un'errata configurazione o a un malintenzionato che intercetta la connessione. L'orologio del computer è attualmente impostato su <ph name="CURRENT_DATE" />. È corretto? Se è sbagliato, devi regolare l'orologio di sistema e aggiornare la pagina.}}</translation>
<translation id="1902576642799138955">Periodo di validità</translation>
<translation id="1906155288650175567">Pulsante Crea nota, premi Invio per creare rapidamente una nuova nota in Google Keep</translation>
<translation id="1908217026282415406">Uso e movimento della videocamera</translation>
@@ -324,7 +340,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="1916770123977586577">Ricarica la pagina per applicare le impostazioni aggiornate a questo sito</translation>
<translation id="1919345977826869612">Annunci</translation>
<translation id="1919367280705858090">Assistenza per un messaggio di errore specifico</translation>
-<translation id="192020519938775529">{COUNT,plural, =0{Nessuno}=1{1 sito}one{# sites}other{# siti}}</translation>
+<translation id="192020519938775529">{COUNT,plural, =0{Nessuno}=1{1 sito}other{# siti}}</translation>
<translation id="1923390796829649802">Pulsante Gestisci le impostazioni di accessibilità, premi Invio per personalizzare i tuoi strumenti di accessibilità nelle impostazioni di Chrome OS.</translation>
<translation id="1924727005275031552">Nuovi</translation>
<translation id="1927439593081478069">Pulsante Esegui il controllo di sicurezza di Chrome, premi Invio per eseguire il controllo di sicurezza nelle impostazioni di Chrome</translation>
@@ -343,7 +359,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="1988881251331415125">Se l'ortografia è corretta, <ph name="BEGIN_LINK" />prova a eseguire lo strumento Diagnostica della connettività<ph name="END_LINK" />.</translation>
<translation id="1992331125980284532">JIS B3</translation>
<translation id="1997484222658892567"><ph name="URL" /> vuole memorizzare in modo definitivo grandi quantità di dati sul computer locale</translation>
-<translation id="2001146170449793414">{COUNT,plural, =1{e un'altra}one{and # more}other{e altre #}}</translation>
+<translation id="2001146170449793414">{COUNT,plural, =1{e un'altra}other{e altre #}}</translation>
<translation id="2003709556000175978">Reimposta ora la password</translation>
<translation id="2003775180883135320">Perforatura quadrupla in alto</translation>
<translation id="201174227998721785">Gestisci le autorizzazioni e i dati memorizzati sui siti nelle impostazioni di Chrome</translation>
@@ -358,9 +374,9 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="2042213636306070719">Vassoio 7</translation>
<translation id="204357726431741734">Accedi per usare le password salvate nel tuo Account Google</translation>
<translation id="2053111141626950936">Le pagine in <ph name="LANGUAGE" /> non verranno tradotte.</translation>
-<translation id="2053373601901562871">{NUM_DAYS,plural, =0{Quando questo controllo è attivato e lo stato è attivo, Chrome stabilisce a quale "coorte" (un gruppo numeroso di utenti) è più simile la tua attività di navigazione. Gli inserzionisti possono selezionare gli annunci per il gruppo e la tua attività di navigazione rimane privata sul tuo dispositivo. Il tuo gruppo viene aggiornato ogni giorno.}=1{Quando questo controllo è attivato e lo stato è attivo, Chrome stabilisce a quale "coorte" (un gruppo numeroso di utenti) è più simile la tua attività di navigazione. Gli inserzionisti possono selezionare gli annunci per il gruppo e la tua attività di navigazione rimane privata sul tuo dispositivo. Il tuo gruppo viene aggiornato ogni giorno.}one{Quando questo controllo è attivato e lo stato è attivo, Chrome stabilisce a quale "coorte" (un gruppo numeroso di utenti) è più simile la tua attività di navigazione. Gli inserzionisti possono selezionare gli annunci per il gruppo e la tua attività di navigazione rimane privata sul tuo dispositivo. Il tuo gruppo viene aggiornato ogni {NUM_DAYS} giorno}other{Quando questo controllo è attivato e lo stato è attivo, Chrome stabilisce a quale "coorte" (un gruppo numeroso di utenti) è più simile la tua attività di navigazione. Gli inserzionisti possono selezionare gli annunci per il gruppo e la tua attività di navigazione rimane privata sul tuo dispositivo. Il tuo gruppo viene aggiornato ogni {NUM_DAYS} giorni}}</translation>
-<translation id="2053553514270667976">ZIP</translation>
-<translation id="2064691555167957331">{COUNT,plural, =1{1 suggerimento}one{# suggestions}other{# suggerimenti}}</translation>
+<translation id="2053373601901562871">{NUM_DAYS,plural, =0{Quando questo controllo è attivato e lo stato è attivo, Chrome stabilisce a quale "coorte" (un gruppo numeroso di utenti) è più simile la tua attività di navigazione. Gli inserzionisti possono selezionare gli annunci per il gruppo e la tua attività di navigazione rimane privata sul tuo dispositivo. Il tuo gruppo viene aggiornato ogni giorno.}=1{Quando questo controllo è attivato e lo stato è attivo, Chrome stabilisce a quale "coorte" (un gruppo numeroso di utenti) è più simile la tua attività di navigazione. Gli inserzionisti possono selezionare gli annunci per il gruppo e la tua attività di navigazione rimane privata sul tuo dispositivo. Il tuo gruppo viene aggiornato ogni giorno.}other{Quando questo controllo è attivato e lo stato è attivo, Chrome stabilisce a quale "coorte" (un gruppo numeroso di utenti) è più simile la tua attività di navigazione. Gli inserzionisti possono selezionare gli annunci per il gruppo e la tua attività di navigazione rimane privata sul tuo dispositivo. Il tuo gruppo viene aggiornato ogni {NUM_DAYS} giorni}}</translation>
+<translation id="2053553514270667976">Codice postale</translation>
+<translation id="2064691555167957331">{COUNT,plural, =1{1 suggerimento}other{# suggerimenti}}</translation>
<translation id="2071156619270205202">Questa carta non è idonea per un numero di carta virtuale.</translation>
<translation id="2071692954027939183">Le notifiche sono state automaticamente bloccate perché solitamente non le consenti</translation>
<translation id="2079545284768500474">Annulla</translation>
@@ -402,7 +418,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="2169984857010174799">Kaku2 (Envelope)</translation>
<translation id="2181821976797666341">Criteri</translation>
<translation id="2183608646556468874">Numero di telefono</translation>
-<translation id="2184405333245229118">{COUNT,plural, =1{1 indirizzo}one{# addresses}other{# indirizzi}}</translation>
+<translation id="2184405333245229118">{COUNT,plural, =1{1 indirizzo}other{# indirizzi}}</translation>
<translation id="2187317261103489799">Rileva (predefinita)</translation>
<translation id="2188375229972301266">Perforatura multipla in basso</translation>
<translation id="2188852899391513400">La password appena usata è stata compromessa nell'ambito di una violazione dei dati. Per proteggere i tuoi account, Gestore delle password di Google consiglia di cambiarla subito e poi di controllare le password salvate.</translation>
@@ -410,6 +426,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="22081806969704220">Vassoio 3</translation>
<translation id="2212735316055980242">Criterio non trovato</translation>
<translation id="2213606439339815911">Recupero voci...</translation>
+<translation id="2213612003795704869">La pagina è stampata</translation>
<translation id="2215727959747642672">Modifica del file</translation>
<translation id="2218879909401188352">Gli utenti malintenzionati attualmente presenti sul sito <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> potrebbero installare app pericolose che danneggiano il tuo dispositivo, generano addebiti nascosti sul tuo credito telefonico o si impossessano dei tuoi dati personali. <ph name="BEGIN_LEARN_MORE_LINK" />Ulteriori informazioni<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">Nessuna connessione a Internet</translation>
@@ -419,6 +436,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="2248949050832152960">Usa WebAuthn</translation>
<translation id="2250931979407627383">Impuntura a sinistra</translation>
<translation id="225207911366869382">Il valore specificato per la norma è obsoleto.</translation>
+<translation id="2256115617011615191">Riavvia adesso</translation>
<translation id="2258928405015593961">Inserisci una data di scadenza nel futuro e riprova</translation>
<translation id="225943865679747347">Codice di errore: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">Errore HTTP</translation>
@@ -446,12 +464,13 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="2337852623177822836">Impostazione controllata dall'amministratore</translation>
<translation id="2340263603246777781">Il sito <ph name="ORIGIN" /> desidera accoppiarsi</translation>
<translation id="2346319942568447007">Immagine copiata</translation>
+<translation id="2350796302381711542">Consentire a <ph name="HANDLER_HOSTNAME" /> di aprire tutti i link <ph name="PROTOCOL" /> al posto di <ph name="REPLACED_HANDLER_TITLE" />?</translation>
<translation id="2354001756790975382">Altri Preferiti</translation>
<translation id="2354430244986887761">La funzione Navigazione sicura di Google ha recentemente <ph name="BEGIN_LINK" />rilevato app dannose<ph name="END_LINK" /> sul sito <ph name="SITE" />.</translation>
<translation id="2355395290879513365">Gli utenti malintenzionati potrebbero riuscire a vedere le immagini che visualizzi in questo sito e ingannarti modificandole.</translation>
<translation id="2356070529366658676">Chiedi</translation>
<translation id="2357481397660644965">Il tuo dispositivo è gestito da <ph name="DEVICE_MANAGER" /> e il tuo account da <ph name="ACCOUNT_MANAGER" />.</translation>
-<translation id="2359347814217202136">{NUM_DAYS,plural, =0{Tra meno di un giorno}=1{Tra un giorno}one{Tra {NUM_DAYS} giorno}other{Tra {NUM_DAYS} giorni}}</translation>
+<translation id="2359347814217202136">{NUM_DAYS,plural, =0{Tra meno di un giorno}=1{Tra un giorno}other{Tra {NUM_DAYS} giorni}}</translation>
<translation id="2359629602545592467">Multiple</translation>
<translation id="2359808026110333948">Continua</translation>
<translation id="236340516568226369">Menu di attivazione/disattivazione ridimensionamento</translation>
@@ -471,6 +490,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="2413528052993050574">Questo server non è riuscito a dimostrare che si tratta di <ph name="DOMAIN" />; il relativo certificato di sicurezza potrebbe essere revocato. Il problema potrebbe essere dovuto a un'errata configurazione o a un malintenzionato che intercetta la connessione.</translation>
<translation id="2414886740292270097">Scuro</translation>
<translation id="2430968933669123598">Gestisci l'Account Google, premi Invio per gestire le tue informazioni, la privacy e la sicurezza nel tuo Account Google</translation>
+<translation id="2436186046335138073">Consentire a <ph name="HANDLER_HOSTNAME" /> di aprire tutti i link <ph name="PROTOCOL" />?</translation>
<translation id="2438874542388153331">Perforatura quadrupla a destra</translation>
<translation id="2450021089947420533">Percorsi</translation>
<translation id="2463739503403862330">Compila</translation>
@@ -478,6 +498,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="2465655957518002998">Scegli il metodo di consegna</translation>
<translation id="2465688316154986572">Pinzatura</translation>
<translation id="2465914000209955735">Gestisci i file che hai scaricato in Chrome</translation>
+<translation id="2466004615675155314">Mostra informazioni dal Web</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Eseguire lo strumento Diagnostica di rete<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">Ordine da 1 a N</translation>
<translation id="2470767536994572628">Quando modifichi le annotazioni, questo documento torna alla visualizzazione a pagina singola e alla sua rotazione originale</translation>
@@ -498,7 +519,8 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="2523886232349826891">Salvataggio effettuato solo su questo dispositivo</translation>
<translation id="2524461107774643265">Aggiungi altre informazioni</translation>
<translation id="2529899080962247600">Questo campo non deve avere più di <ph name="MAX_ITEMS_LIMIT" /> voci. Tutte le voci in più verranno ignorate.</translation>
-<translation id="2535659140340599600">{COUNT,plural, =1{e 1 altro}one{e altro #}other{e altro #}}</translation>
+<translation id="2535585790302968248">Apri una nuova scheda di navigazione in incognito per navigare in privato</translation>
+<translation id="2535659140340599600">{COUNT,plural, =1{e 1 altro}other{e altro #}}</translation>
<translation id="2536110899380797252">Aggiungi indirizzo</translation>
<translation id="2539524384386349900">Rileva</translation>
<translation id="2540701853218677861">Cronologia di accessi/uscite del dispositivo, inclusi timestamp e tentativi non riusciti</translation>
@@ -512,7 +534,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="2553853292994445426">Controlla le impostazioni del sistema DNS sicuro. Potresti avere configurato un server DNS sicuro con il quale non è possibile stabilire connessioni.</translation>
<translation id="2556876185419854533">&amp;Annulla modifica</translation>
<translation id="2570734079541893434">Gestisci impostazioni</translation>
-<translation id="257674075312929031">Raggruppa</translation>
+<translation id="257674075312929031">Gruppo</translation>
<translation id="2576880857912732701">Pulsante Gestisci le impostazioni di sicurezza, premi Invio per gestire la funzionalità Navigazione sicura e altre opzioni nelle impostazioni di Chrome</translation>
<translation id="2586657967955657006">Appunti</translation>
<translation id="2587730715158995865">Da <ph name="ARTICLE_PUBLISHER" />. Leggi questo e altri <ph name="OTHER_ARTICLE_COUNT" /> articoli.</translation>
@@ -523,7 +545,14 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="2597378329261239068">Questo documento è protetto da password. Inserisci una password.</translation>
<translation id="2609632851001447353">Varianti</translation>
<translation id="2610561535971892504">Fai clic per copiare</translation>
+<translation id="2617988307566202237">Chrome <ph name="BEGIN_EMPHASIS" />non salverà<ph name="END_EMPHASIS" /> le seguenti informazioni:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Cronologia di navigazione
+ <ph name="LIST_ITEM" />Cookie e dati dei siti
+ <ph name="LIST_ITEM" />Informazioni inserite nei moduli
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (Envelope)</translation>
+<translation id="2623663032199728144">Può chiedere di usare informazioni sui tuoi schermi</translation>
<translation id="2625385379895617796">L'orologio è avanti</translation>
<translation id="262745152991669301">Può chiedere di connettersi ai dispositivi USB</translation>
<translation id="2629325967560697240">Per il massimo livello di sicurezza di Chrome, <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />attiva la protezione avanzata<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -536,7 +565,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="2653659639078652383">Invia</translation>
<translation id="2659491813326907275">Personalizza i tuoi strumenti di accessibilità nelle impostazioni di Chrome OS</translation>
<translation id="2660779039299703961">Evento</translation>
-<translation id="2664887757054927933">{COUNT,plural, =0{Nessuna}=1{1 password per <ph name="DOMAIN_LIST" />}=2{2 password per <ph name="DOMAIN_LIST" />}one{# password per <ph name="DOMAIN_LIST" />}other{# password per <ph name="DOMAIN_LIST" />}}</translation>
+<translation id="2664887757054927933">{COUNT,plural, =0{Nessuna}=1{1 password per <ph name="DOMAIN_LIST" />}=2{2 password per <ph name="DOMAIN_LIST" />}other{# password per <ph name="DOMAIN_LIST" />}}</translation>
<translation id="2666092431469916601">In alto</translation>
<translation id="2666117266261740852">Chiudi altre schede o app</translation>
<translation id="2672201172023654893">Il tuo browser non è gestito.</translation>
@@ -557,6 +586,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="2709516037105925701">Compilazione automatica</translation>
<translation id="2713444072780614174">Bianco</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />, premi Tab poi Invio per gestire i tuoi pagamenti e i dati delle carte di credito nelle impostazioni di Chrome</translation>
+<translation id="271663710482723385">Premi |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| per uscire dalla modalità a schermo intero</translation>
<translation id="2721148159707890343">Richiesta riuscita</translation>
<translation id="2723669454293168317">Esegui un controllo di sicurezza nelle impostazioni di Chrome</translation>
<translation id="2726001110728089263">Vassoio laterale</translation>
@@ -587,6 +617,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="2850739647070081192">Invite (Envelope)</translation>
<translation id="2856444702002559011">Gli utenti malintenzionati potrebbero provare a carpire le tue informazioni da <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (ad esempio, password, messaggi o carte di credito). <ph name="BEGIN_LEARN_MORE_LINK" />Ulteriori informazioni<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">Questo sito mostra annunci invasivi o fuorvianti.</translation>
+<translation id="286512204874376891">Una carta virtuale nasconde la tua carta effettiva per proteggerti meglio da potenziali attività fraudolente. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">Amichevole</translation>
<translation id="2876489322757410363">Per procedere al pagamento tramite un'applicazione esterna, uscirai dalla modalità di navigazione in incognito. Continuare?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />, premi Tab e poi Invio per gestire la funzionalità Navigazione sicura e altre opzioni nelle impostazioni di Chrome</translation>
@@ -607,10 +638,11 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="2922350208395188000">Il certificato del server non può essere verificato.</translation>
<translation id="2925673989565098301">Metodo di consegna</translation>
<translation id="2928905813689894207">Indirizzo di fatturazione</translation>
-<translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> e <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> altro}one{<ph name="SHIPPING_ADDRESS_PREVIEW" /> and <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> more}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> e altri <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}}</translation>
+<translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> e <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> altro}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> e altri <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}}</translation>
<translation id="2930577230479659665">Taglia dopo la stampa di ciascuna copia</translation>
<translation id="2932085390869194046">Suggerisci password...</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019">Aprire i link <ph name="PROTOCOL" /></translation>
<translation id="2941952326391522266">Questo server non è riuscito a dimostrare che si tratta di <ph name="DOMAIN" />; il relativo certificato di sicurezza proviene da <ph name="DOMAIN2" />. Il problema potrebbe essere dovuto a un'errata configurazione o a un malintenzionato che intercetta la connessione.</translation>
<translation id="2943895734390379394">Ora di caricamento:</translation>
<translation id="2948083400971632585">Puoi disattivare tutti i proxy configurati per una connessione dalla pagina delle impostazioni.</translation>
@@ -643,6 +675,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="3037605927509011580">Uffa!</translation>
<translation id="3041612393474885105">Informazioni certificato</translation>
<translation id="3044034790304486808">Riprendi la ricerca</translation>
+<translation id="305162504811187366">Cronologia di Chrome Remote Desktop, inclusi timestamp, host e ID sessione client</translation>
<translation id="3060227939791841287">C9 (Envelope)</translation>
<translation id="3061707000357573562">Servizio di applicazione patch</translation>
<translation id="306573536155379004">Gioco iniziato.</translation>
@@ -662,7 +695,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="3120730422813725195">Elo</translation>
<translation id="31207688938192855"><ph name="BEGIN_LINK" />Prova a eseguire lo strumento Diagnostica della connettività<ph name="END_LINK" />.</translation>
<translation id="3121994479408824897">Vai a <ph name="DOMAIN" /></translation>
-<translation id="3137507986424712703">{COUNT,plural, =0{Nessuno}=1{dati di accesso per 1 account}one{sign-in data for # accounts}other{dati di accesso per # account}}</translation>
+<translation id="3137507986424712703">{COUNT,plural, =0{Nessuno}=1{dati di accesso per 1 account}other{dati di accesso per # account}}</translation>
<translation id="3145945101586104090">Decodifica della risposta non riuscita</translation>
<translation id="3150653042067488994">Errore temporaneo del server</translation>
<translation id="3154506275960390542">Questa pagina include un modulo che potrebbe non essere inviato in modo sicuro. I dati inviati possono essere visualizzati da altri durante il transito o potrebbero essere modificati da un utente malintenzionato al fine di modificare i dati ricevuti dal server.</translation>
@@ -680,6 +713,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="3197136577151645743">Può chiedere di sapere quando stai utilizzando attivamente questo dispositivo</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />, premi Tab e poi Invio per gestire le informazioni da sincronizzare nelle impostazioni di Chrome</translation>
<translation id="320323717674993345">Annulla pagamento</translation>
+<translation id="3203366800380907218">Dal Web</translation>
<translation id="3207960819495026254">Aggiunto ai preferiti</translation>
<translation id="3209034400446768650">La pagina potrebbe addebitare denaro</translation>
<translation id="3212581601480735796">La tua attività su <ph name="HOSTNAME" /> è monitorata</translation>
@@ -696,10 +730,12 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="3234666976984236645">Rileva sempre contenuti importanti di questo sito</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />, premi Tab poi Invio per personalizzare l'aspetto del browser</translation>
<translation id="3240791268468473923">Le credenziali per il pagamento sicuro non corrispondono: riquadro inferiore aperto</translation>
+<translation id="324180406144491771">I link "<ph name="HOST_NAME" />" sono bloccati</translation>
<translation id="3249845759089040423">Alla moda</translation>
<translation id="3252266817569339921">Francese</translation>
<translation id="3257954757204451555">Chi c'è dietro a questa informazione?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />, premi Tab e poi Invio per creare rapidamente un nuovo evento in Google Calendar</translation>
+<translation id="3261488570342242926">Scopri di più sulle carte virtuali</translation>
<translation id="3264837738038045344">Pulsante Gestisci le impostazioni di Chrome, premi Invio per visitare le tue impostazioni di Chrome</translation>
<translation id="3266793032086590337">Valore (conflitto)</translation>
<translation id="3268451620468152448">Schede aperte</translation>
@@ -713,6 +749,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="3288238092761586174"><ph name="URL" /> potrebbe dover effettuare altri passaggi per verificare il pagamento</translation>
<translation id="3293642807462928945">Scopri di più sulla norma <ph name="POLICY_NAME" /></translation>
<translation id="3295444047715739395">Visualizza e gestisci le tue password nelle impostazioni di Chrome</translation>
+<translation id="3303795387212510132">Consentire all'app di aprire i link <ph name="PROTOCOL_SCHEME" />?</translation>
<translation id="3303855915957856445">Nessun risultato di ricerca trovato</translation>
<translation id="3304073249511302126">scansione Bluetooth</translation>
<translation id="3308006649705061278">Unità organizzativa (OU)</translation>
@@ -726,12 +763,6 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="3345782426586609320">Occhi</translation>
<translation id="3355823806454867987">Modifica impostazioni proxy...</translation>
<translation id="3360103848165129075">Foglio per la gestione dei pagamenti</translation>
-<translation id="3361596688432910856">Chrome <ph name="BEGIN_EMPHASIS" />non salverà<ph name="END_EMPHASIS" /> le seguenti informazioni:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Cronologia di navigazione
- <ph name="LIST_ITEM" />Cookie e dati dei siti
- <ph name="LIST_ITEM" />Informazioni inserite nei moduli
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">Questa norma è stata copiata automaticamente dalla norma obsoleta <ph name="OLD_POLICY" />. Dovresti usare invece questa norma.</translation>
<translation id="3364869320075768271"><ph name="URL" /> vorrebbe usare i dati e dispositivi per realtà virtuale</translation>
<translation id="3366477098757335611">Visualizza le carte</translation>
@@ -795,7 +826,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="3518941727116570328">Gestione di più oggetti</translation>
<translation id="3528171143076753409">Il certificato del server non è affidabile.</translation>
<translation id="3528485271872257980">Marrone scuro</translation>
-<translation id="3530944546672790857">{COUNT,plural, =0{Almeno 1 elemento sui dispositivi sincronizzati}=1{1 elemento (e altri sui dispositivi sincronizzati)}one{# items (and more on synced devices)}other{# elementi (e altri sui dispositivi sincronizzati)}}</translation>
+<translation id="3530944546672790857">{COUNT,plural, =0{Almeno 1 elemento sui dispositivi sincronizzati}=1{1 elemento (e altri sui dispositivi sincronizzati)}other{# elementi (e altri sui dispositivi sincronizzati)}}</translation>
<translation id="3531780078352352885">Fogli di lavoro</translation>
<translation id="3532844647053365774"><ph name="HOST" /> vuole usare il microfono</translation>
<translation id="3533328374079021623">Mailbox 5</translation>
@@ -813,8 +844,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="3586931643579894722">Nascondi dettagli</translation>
<translation id="3587738293690942763">Medio</translation>
<translation id="3592413004129370115">Italian (Envelope)</translation>
-<translation id="3595699422137460894">{NUM_DAYS,plural, =0{Puoi reimpostare il tuo gruppo in qualsiasi momento. Ci vorrà circa un giorno per unirsi a un nuovo gruppo.}=1{Puoi reimpostare il tuo gruppo in qualsiasi momento. Ci vorrà circa un giorno per unirsi a un nuovo gruppo.}one{Puoi reimpostare il tuo gruppo in qualsiasi momento. Ci vorrà {NUM_DAYS} giorno per unirsi a un nuovo gruppo.}other{Puoi reimpostare il tuo gruppo in qualsiasi momento. Ci vorranno {NUM_DAYS} giorni per unirsi a un nuovo gruppo.}}</translation>
-<translation id="3596012367874587041">Impostazioni app</translation>
+<translation id="3595699422137460894">{NUM_DAYS,plural, =0{Puoi reimpostare il tuo gruppo in qualsiasi momento. Ci vorrà circa un giorno per unirsi a un nuovo gruppo.}=1{Puoi reimpostare il tuo gruppo in qualsiasi momento. Ci vorrà circa un giorno per unirsi a un nuovo gruppo.}other{Puoi reimpostare il tuo gruppo in qualsiasi momento. Ci vorranno {NUM_DAYS} giorni per unirsi a un nuovo gruppo.}}</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">Applicazione bloccata dal tuo amministratore</translation>
<translation id="3608932978122581043">Fornisci orientamento</translation>
@@ -857,6 +887,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="370972442370243704">Attiva i percorsi</translation>
<translation id="3711895659073496551">Sospensione</translation>
<translation id="3712624925041724820">Licenze esaurite</translation>
+<translation id="3714633008798122362">Calendario web</translation>
<translation id="3714780639079136834">Attivare la rete dati mobile o Wi-Fi</translation>
<translation id="3715597595485130451">Collegati alla rete Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Controllare la configurazione del proxy, firewall e DNS<ph name="END_LINK" /></translation>
@@ -918,6 +949,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="3906954721959377182">Tablet</translation>
<translation id="3909477809443608991"><ph name="URL" /> chiede di riprodurre contenuti protetti. Google verificherà l'identità del tuo dispositivo e questo sito potrebbe avervi accesso.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">Non consentire</translation>
<translation id="3939773374150895049">Usare WebAuthn anziché CVC?</translation>
<translation id="3946209740501886391">Chiedi sempre su questo sito</translation>
<translation id="3947595700203588284">Può chiedere di connettersi ai dispositivi MIDI</translation>
@@ -930,7 +962,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="3962859241508114581">Traccia precedente</translation>
<translation id="3963721102035795474">Modalità Reader</translation>
<translation id="3963837677003247395">Continuare manualmente?</translation>
-<translation id="3964661563329879394">{COUNT,plural, =0{Nessuno}=1{Di 1 sito }one{From # sites }other{Di # siti }}</translation>
+<translation id="3964661563329879394">{COUNT,plural, =0{Nessuno}=1{Di 1 sito }other{Di # siti }}</translation>
<translation id="3969052498612555048">Non riesci a trovare il codice? <ph name="BEGIN_LINK" />Ricevi nuovo codice<ph name="END_LINK" /></translation>
<translation id="397105322502079400">Calcolo in corso...</translation>
<translation id="3973234410852337861"><ph name="HOST_NAME" /> è bloccato</translation>
@@ -939,8 +971,9 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="3990250421422698716">Offset jog</translation>
<translation id="3996311196211510766">Il sito <ph name="ORIGIN" /> ha richiesto l'applicazione di un criterio di origine
a tutte le richieste indirizzate a esso, ma questo criterio al momento non può essere applicato.</translation>
+<translation id="4009243425692662128">I contenuti delle pagine che stampi vengono inviati a Google Cloud o a terze parti per essere analizzati. Ad esempio, potrebbero essere sottoposti a scansione alla ricerca di dati sensibili.</translation>
<translation id="4010758435855888356">Vuoi consentire l'accesso allo spazio di archiviazione?</translation>
-<translation id="4014128326099193693">{COUNT,plural, =1{Documento PDF contenente {COUNT} pagina}one{Documento PDF contenente {COUNT} pagine}other{Documento PDF contenente {COUNT} pagine}}</translation>
+<translation id="4014128326099193693">{COUNT,plural, =1{Documento PDF contenente {COUNT} pagina}other{Documento PDF contenente {COUNT} pagine}}</translation>
<translation id="4023431997072828269">Le tue informazioni saranno visibili agli altri utenti perché il modulo verrà inviato tramite una connessione non sicura.</translation>
<translation id="4025913568718019429">Pulsante Gestisci le impostazioni sulla privacy di Google, premi Invio per andare alle impostazioni sulla privacy del tuo Account Google.</translation>
<translation id="4030383055268325496">&amp;Annulla aggiunta</translation>
@@ -974,14 +1007,14 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="4121428309786185360">Scade in data</translation>
<translation id="4123572138124678573">Tripla perforatura in basso</translation>
<translation id="4127575959421463246">Stai cercando i flag di Chrome OS? Visita la pagina</translation>
-<translation id="4129401438321186435">{COUNT,plural, =1{1 altro}one{# others}other{# altri}}</translation>
+<translation id="4129401438321186435">{COUNT,plural, =1{1 altro}other{# altri}}</translation>
<translation id="4130226655945681476">Controllare i cavi di rete, il modem e il router</translation>
<translation id="4134123981501319574">Crea documento</translation>
<translation id="413544239732274901">Scopri di più</translation>
<translation id="4142935452406587478">Vassoio 10</translation>
<translation id="4148925816941278100">American Express</translation>
<translation id="4151403195736952345">Utilizza impostazioni predefinite globali (Rileva)</translation>
-<translation id="4152318981910038897">{COUNT,plural, =1{Pagina 1}one{Pagina {COUNT}}other{Pagina {COUNT}}}</translation>
+<translation id="4152318981910038897">{COUNT,plural, =1{Pagina 1}other{Pagina {COUNT}}}</translation>
<translation id="4154664944169082762">Impronte digitali</translation>
<translation id="4159784952369912983">Viola</translation>
<translation id="4165986682804962316">Impostazioni sito</translation>
@@ -989,7 +1022,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="4171489848299289778"><ph name="RESULT_MODIFIED_DATE" /> - <ph name="RESULT_OWNER" /> - <ph name="RESULT_PRODUCT_SOURCE" /></translation>
<translation id="4172051516777682613">Mostra sempre</translation>
<translation id="4173315687471669144">Foolscap</translation>
-<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{<ph name="ITEM_COUNT" /> altro elemento}one{<ph name="ITEM_COUNT" /> more items}other{Altri <ph name="ITEM_COUNT" /> elementi}}</translation>
+<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{<ph name="ITEM_COUNT" /> altro elemento}other{Altri <ph name="ITEM_COUNT" /> elementi}}</translation>
<translation id="4176463684765177261">Disattivato</translation>
<translation id="4179515394835346607"><ph name="ROW_NAME" /> <ph name="ROW_CONTENT" /></translation>
<translation id="4194250254487269611">Al momento non è possibile salvare la carta</translation>
@@ -1033,6 +1066,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="4250680216510889253">No</translation>
<translation id="4253168017788158739">Nota</translation>
<translation id="425582637250725228">Le modifiche apportate potrebbero non essere salvate.</translation>
+<translation id="425869179292622354">Vuoi renderla più sicura con una carta virtuale?</translation>
<translation id="4258748452823770588">Firma errata</translation>
<translation id="4261046003697461417">Non è possibile inserire annotazioni nei documenti protetti</translation>
<translation id="4265872034478892965">Consentita dall'amministratore</translation>
@@ -1040,7 +1074,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="4275830172053184480">Riavvia il dispositivo</translation>
<translation id="4277028893293644418">Reimposta password</translation>
<translation id="4278390842282768270">Consenti</translation>
-<translation id="428639260510061158">{NUM_CARDS,plural, =1{Questa carta è stata salvata nel tuo Account Google}one{Queste carte sono state salvate nel tuo Account Google}other{Queste carte sono state salvate nel tuo Account Google}}</translation>
+<translation id="428639260510061158">{NUM_CARDS,plural, =1{Questa carta è stata salvata nel tuo Account Google}other{Queste carte sono state salvate nel tuo Account Google}}</translation>
<translation id="4287885627794386150">Funzionalità idonea per la prova, ma non attiva</translation>
<translation id="4297502707443874121">Miniatura della pagina <ph name="THUMBNAIL_PAGE" /></translation>
<translation id="42981349822642051">Espandi</translation>
@@ -1095,6 +1129,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="4434045419905280838">Popup e reindirizzamenti</translation>
<translation id="4435702339979719576">Postcard)</translation>
<translation id="443673843213245140">L'utilizzo di un proxy è stato disattivato ma è stata specificata una configurazione proxy esplicita.</translation>
+<translation id="4441832193888514600">Ignorato perché il criterio può essere impostato solo da un utente cloud.</translation>
<translation id="4450893287417543264">Non mostrare più</translation>
<translation id="4451135742916150903">Può chiedere di connettersi ai dispositivi HID</translation>
<translation id="4452328064229197696">La password appena usata è stata compromessa nell'ambito di una violazione dei dati. Per proteggere i tuoi account, Gestore delle password di Google consiglia di controllare le password salvate.</translation>
@@ -1150,6 +1185,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="4628948037717959914">Foto</translation>
<translation id="4631649115723685955">Rimborso collegato</translation>
<translation id="4636930964841734540">Info</translation>
+<translation id="4638670630777875591">Modalità di navigazione in incognito in Chromium</translation>
<translation id="464342062220857295">Funzionalità di ricerca</translation>
<translation id="4644670975240021822">Ordine inverso a faccia in giù</translation>
<translation id="4646534391647090355">Vai subito</translation>
@@ -1170,6 +1206,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="4708268264240856090">La connessione è stata interrotta</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Eseguire lo strumento Diagnostica di rete Windows<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426">Password di <ph name="USERNAME" /></translation>
<translation id="4724144314178270921">Può chiedere di vedere testo e immagini negli appunti</translation>
<translation id="4726672564094551039">Ricarica criteri</translation>
<translation id="4728558894243024398">Piattaforma</translation>
@@ -1191,10 +1228,11 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="4757993714154412917">Hai appena inserito la tua password su un sito ingannevole. Per proteggere i tuoi account, Chromium ti consiglia di controllare le password salvate.</translation>
<translation id="4758311279753947758">Aggiungi informazioni di contatto</translation>
<translation id="4761104368405085019">Utilizzare il microfono</translation>
+<translation id="4761869838909035636">Esegui il controllo di sicurezza di Chrome</translation>
<translation id="4764776831041365478">La pagina web all'indirizzo <ph name="URL" /> potrebbe essere temporaneamente non disponibile oppure è stata permanentemente spostata a un nuovo indirizzo web.</translation>
<translation id="4766713847338118463">Doppia pinzatura in basso</translation>
<translation id="4771973620359291008">Si è verificato un errore sconosciuto.</translation>
-<translation id="477945296921629067">{NUM_POPUPS,plural, =1{Popup bloccato}one{# pop-ups blocked}other{# popup bloccati}}</translation>
+<translation id="477945296921629067">{NUM_POPUPS,plural, =1{Popup bloccato}other{# popup bloccati}}</translation>
<translation id="4780366598804516005">Mailbox 1</translation>
<translation id="4785376858512657294">Gestisci l'Account Google</translation>
<translation id="4785689107224900852">Passa a questa scheda</translation>
@@ -1211,12 +1249,6 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="4819347708020428563">Vuoi modificare le annotazioni nella visualizzazione predefinita?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />, premi Tab e poi Invio per creare rapidamente un nuovo foglio Google</translation>
<translation id="4825507807291741242">Potente</translation>
-<translation id="4827402517081186284">La modalità di navigazione in incognito non ti rende invisibile online:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />I siti rilevano la tua visita<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Datori di lavoro o scuole possono monitorare l'attività di navigazione<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />I provider di servizi Internet possono monitorare il traffico web<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">Attiva gli avvisi</translation>
<translation id="4838327282952368871">Surreale</translation>
<translation id="4840250757394056958">Visualizza la tua cronologia di Chrome</translation>
@@ -1228,12 +1260,12 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="4854362297993841467">Questo metodo di consegna non è disponibile. Prova un metodo diverso.</translation>
<translation id="4854853140771946034">Crea rapidamente una nuova nota in Google Keep</translation>
<translation id="485902285759009870">Verifica del codice in corso…</translation>
+<translation id="4866506163384898554">Premi |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| per mostrare il cursore</translation>
<translation id="4876188919622883022">Visualizzazione semplificata</translation>
<translation id="4876305945144899064">Nessun nome utente</translation>
-<translation id="4877083676943085827">{COUNT,plural, =0{Nessuna}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}one{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}}</translation>
+<translation id="4877083676943085827">{COUNT,plural, =0{Nessuna}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831">Ricerca di <ph name="TEXT" /></translation>
<translation id="4879491255372875719">Automatica (impostazione predefinita)</translation>
-<translation id="4879725228911483934">Aprire finestre e posizionarle sugli schermi</translation>
<translation id="4880827082731008257">Cerca nella cronologia</translation>
<translation id="4881695831933465202">Apri</translation>
<translation id="4885256590493466218">Paga con <ph name="CARD_DETAIL" /> al momento del pagamento</translation>
@@ -1242,6 +1274,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">Nono rullo</translation>
<translation id="4901778704868714008">Salva…</translation>
+<translation id="4905659621780993806">L'amministratore riavvierà il tuo dispositivo automaticamente alle ore <ph name="TIME" /> del giorno <ph name="DATE" />. Salva gli eventuali elementi aperti prima che il dispositivo si riavvii.</translation>
<translation id="4913987521957242411">Perforatura in alto a sinistra</translation>
<translation id="4918221908152712722">Installa <ph name="APP_NAME" /> (non è richiesto alcun download)</translation>
<translation id="4923459931733593730">Pagamento</translation>
@@ -1250,6 +1283,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, premi Tab poi Invio per cercare</translation>
<translation id="4930153903256238152">Capacità elevata</translation>
+<translation id="4940163644868678279">Modalità di navigazione in incognito in Chrome</translation>
<translation id="4943872375798546930">Nessun risultato</translation>
<translation id="4950898438188848926">Pulsante per cambiare scheda, premi INVIO per passare alla scheda aperta, <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="495170559598752135">Azioni</translation>
@@ -1259,6 +1293,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="4968522289500246572">Questa app è stata progettata per dispositivi mobili e il relativo ridimensionamento potrebbe non avvenire correttamente. L'app potrebbe riavviarsi o presentare problemi.</translation>
<translation id="4969341057194253438">Elimina la registrazione</translation>
<translation id="4973922308112707173">Perforatura doppia in alto</translation>
+<translation id="4976702386844183910">Ultima visita: <ph name="DATE" /></translation>
<translation id="4984088539114770594">Usare il microfono?</translation>
<translation id="4984339528288761049">Prc5 (Envelope)</translation>
<translation id="4989163558385430922">Mostra tutto</translation>
@@ -1285,12 +1320,12 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="5040262127954254034">Privacy</translation>
<translation id="5043480802608081735">Link copiato</translation>
<translation id="5045550434625856497">Password non corretta</translation>
-<translation id="5056425809654826431">{NUM_FILES,plural, =1{Per inviare questo file tramite Condivisione nelle vicinanze, libera spazio (<ph name="DISK_SPACE_SIZE" />) sul tuo dispositivo}one{Per inviare questo file tramite Condivisione nelle vicinanze, libera spazio (<ph name="DISK_SPACE_SIZE" />) sul tuo dispositivo}other{Per inviare questi file tramite Condivisione nelle vicinanze, libera spazio (<ph name="DISK_SPACE_SIZE" />) sul tuo dispositivo}}</translation>
+<translation id="5056425809654826431">{NUM_FILES,plural, =1{Per inviare questo file tramite Condivisione nelle vicinanze, libera spazio (<ph name="DISK_SPACE_SIZE" />) sul tuo dispositivo}other{Per inviare questi file tramite Condivisione nelle vicinanze, libera spazio (<ph name="DISK_SPACE_SIZE" />) sul tuo dispositivo}}</translation>
<translation id="5056549851600133418">Articoli per te</translation>
<translation id="5061227663725596739">Forse cercavi: <ph name="LOOKALIKE_DOMAIN" /></translation>
<translation id="5066056036849835175">Cronologia di stampa</translation>
<translation id="5068524481479508725">A10</translation>
-<translation id="5068778127327928576">{NUM_COOKIES,plural, =1{(1 in uso)}one{(# in uso)}other{(# in uso)}}</translation>
+<translation id="5068778127327928576">{NUM_COOKIES,plural, =1{(1 in uso)}other{(# in uso)}}</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />Controllare l'indirizzo proxy<ph name="END_LINK" /></translation>
<translation id="5070838744279127212">Decimo rullo</translation>
<translation id="507130231501693183">Mailbox 4</translation>
@@ -1320,6 +1355,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="5138227688689900538">Mostra meno</translation>
<translation id="5145883236150621069">Codice di errore presente nella risposta del criterio</translation>
<translation id="5146995429444047494">Le notifiche per il sito <ph name="ORIGIN" /> sono bloccate</translation>
+<translation id="514704532284964975"><ph name="URL" /> vuole vedere e modificare informazioni su dispositivi NFC che avvicini al telefono</translation>
<translation id="5148809049217731050">A faccia in su</translation>
<translation id="515292512908731282">C4 (Envelope)</translation>
<translation id="5158275234811857234">Copertina</translation>
@@ -1344,6 +1380,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="5215116848420601511">Metodi di pagamento e indirizzi che utilizzano Google Pay</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">Vassoio 13</translation>
+<translation id="5216942107514965959">Ultima visita: oggi</translation>
<translation id="5222812217790122047">Email obbligatoria</translation>
<translation id="5230733896359313003">Indirizzo di spedizione</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1364,7 +1401,6 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">Proprietà documento</translation>
<translation id="528468243742722775">Fine</translation>
-<translation id="5284909709419567258">Indirizzi di rete</translation>
<translation id="5285570108065881030">Mostra tutte le password salvate</translation>
<translation id="5287240709317226393">Mostra cookie</translation>
<translation id="5287456746628258573">Le tue informazioni (ad esempio password o numeri di carte di credito) potrebbero essere a rischio, poiché questo sito utilizza una configurazione di sicurezza obsoleta.</translation>
@@ -1416,7 +1452,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="5452270690849572955">Impossibile trovare la pagina <ph name="HOST_NAME" /></translation>
<translation id="5455374756549232013">Timestamp del criterio errato</translation>
<translation id="5457113250005438886">Non validi</translation>
-<translation id="5458150163479425638">{CONTACT,plural, =0{<ph name="CONTACT_PREVIEW" />}=1{<ph name="CONTACT_PREVIEW" /> e <ph name="NUMBER_OF_ADDITIONAL_CONTACTS" /> altro}one{<ph name="CONTACT_PREVIEW" /> and <ph name="NUMBER_OF_ADDITIONAL_CONTACTS" /> more}other{<ph name="CONTACT_PREVIEW" /> e altri <ph name="NUMBER_OF_ADDITIONAL_CONTACTS" />}}</translation>
+<translation id="5458150163479425638">{CONTACT,plural, =0{<ph name="CONTACT_PREVIEW" />}=1{<ph name="CONTACT_PREVIEW" /> e <ph name="NUMBER_OF_ADDITIONAL_CONTACTS" /> altro}other{<ph name="CONTACT_PREVIEW" /> e altri <ph name="NUMBER_OF_ADDITIONAL_CONTACTS" />}}</translation>
<translation id="5463625433003343978">Ricerca di dispositivi in corso…</translation>
<translation id="5469868506864199649">Italiano</translation>
<translation id="5470861586879999274">&amp;Ripeti modifica</translation>
@@ -1448,6 +1484,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="5556459405103347317">Ricarica</translation>
<translation id="5560088892362098740">Data di scadenza</translation>
<translation id="55635442646131152">Struttura documento</translation>
+<translation id="5565613213060953222">Apri scheda di navigazione in incognito</translation>
<translation id="5565735124758917034">Attivo</translation>
<translation id="5570825185877910964">Proteggi account</translation>
<translation id="5571083550517324815">Impossibile ritirare dall'indirizzo specificato. Seleziona un indirizzo diverso.</translation>
@@ -1494,9 +1531,9 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="5720705177508910913">Utente corrente</translation>
<translation id="5728056243719941842">C5 (Envelope)</translation>
<translation id="5730040223043577876">Chrome ti consiglia di reimpostare la password, se l'hai utilizzata su altri siti.</translation>
-<translation id="5737183892635480227">{NUM_CARDS,plural, =1{Salva la carta nel tuo Account Google}one{Salva carte nel tuo Account Google}other{Salva carte nel tuo Account Google}}</translation>
+<translation id="5737183892635480227">{NUM_CARDS,plural, =1{Salva la carta nel tuo Account Google}other{Salva carte nel tuo Account Google}}</translation>
<translation id="5745733273847572235">Può chiedere la tua posizione</translation>
-<translation id="5745980000221562234">{NUM_CARDS,plural, =1{Usa un numero virtuale per questa carta}one{Seleziona una carta}other{Seleziona una carta}}</translation>
+<translation id="5745980000221562234">{NUM_CARDS,plural, =1{Usa un numero virtuale per questa carta}other{Seleziona una carta}}</translation>
<translation id="5759751709240058861">Usare e spostare la videocamera</translation>
<translation id="5763042198335101085">Inserisci un indirizzo email valido</translation>
<translation id="5765072501007116331">Seleziona un indirizzo per conoscere i requisiti e i metodi di consegna</translation>
@@ -1516,7 +1553,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="5812947184178430888">Quando Chrome segnala eventi di sicurezza, i dati corrispondenti agli eventi vengono inviati al tuo amministratore. Tali dati possono includere URL delle pagine visitate in Chrome, metadati o nomi dei file e il nome utente che usi per accedere alle applicazioni basate sul Web, al tuo dispositivo e a Chrome.</translation>
<translation id="5813119285467412249">&amp;Ripeti aggiunta</translation>
<translation id="5817918615728894473">Accoppia</translation>
-<translation id="5824687817967109979">{NUM_CARDS,plural, =1{Gli importi dei pagamenti che effettuerai verranno addebitati su questa carta, ma il numero effettivo della carta non verrà condiviso con questo sito. Per maggiore sicurezza verrà generato un codice CVC temporaneo.}one{Gli importi dei pagamenti che effettuerai verranno addebitati sulla carta selezionata, ma il numero effettivo della carta non verrà condiviso con questo sito. Per maggiore sicurezza verrà generato un codice CVC temporaneo.}other{Gli importi dei pagamenti che effettuerai verranno addebitati sulla carta selezionata, ma il numero effettivo della carta non verrà condiviso con questo sito. Per maggiore sicurezza verrà generato un codice CVC temporaneo.}}</translation>
+<translation id="5824687817967109979">{NUM_CARDS,plural, =1{Gli importi dei pagamenti che effettuerai verranno addebitati su questa carta, ma il numero effettivo della carta non verrà condiviso con questo sito. Per maggiore sicurezza verrà generato un codice CVC temporaneo.}other{Gli importi dei pagamenti che effettuerai verranno addebitati sulla carta selezionata, ma il numero effettivo della carta non verrà condiviso con questo sito. Per maggiore sicurezza verrà generato un codice CVC temporaneo.}}</translation>
<translation id="5826507051599432481">Nome comune (CN)</translation>
<translation id="5830698870816298009">uso e movimento della videocamera</translation>
<translation id="5838278095973806738">Non dovresti inserire dati sensibili in questo sito (ad esempio password o carte di credito) perché potrebbero essere intercettati da utenti malintenzionati.</translation>
@@ -1530,6 +1567,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="5869522115854928033">Password salvate</translation>
<translation id="5873013647450402046">La tua banca vuole confermare la tua identità.</translation>
<translation id="5887400589839399685">Carta salvata</translation>
+<translation id="5887687176710214216">Ultima visita: ieri</translation>
<translation id="5895138241574237353">Riavvia</translation>
<translation id="5895187275912066135">Emesso in data</translation>
<translation id="5901630391730855834">Giallo</translation>
@@ -1538,11 +1576,12 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="5908541034548427511"><ph name="TYPE_1" /> (sincronizzati)</translation>
<translation id="59174027418879706">Attivato</translation>
<translation id="5919090499915321845">B10</translation>
-<translation id="5920262536204764679">{NUM_COOKIES,plural, =1{1 in uso}one{# in use}other{# in uso}}</translation>
+<translation id="5920262536204764679">{NUM_COOKIES,plural, =1{1 in uso}other{# in uso}}</translation>
<translation id="5921185718311485855">On</translation>
<translation id="5921639886840618607">Vuoi salvare la carta nell'Account Google?</translation>
<translation id="5922853866070715753">Hai quasi finito.</translation>
<translation id="5932224571077948991">Il sito mostra annunci invasivi o fuorvianti</translation>
+<translation id="5938153366081463283">Aggiungi carta virtuale</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347">Apertura di <ph name="SITE_NAME" />…</translation>
<translation id="5951495562196540101">Impossibile effettuare la registrazione con l'account consumer (è disponibile la licenza inclusa).</translation>
@@ -1607,6 +1646,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="6120179357481664955">Ricordi il tuo ID UPI?</translation>
<translation id="6124432979022149706">Connettori di Chrome Enterprise</translation>
<translation id="6127379762771434464">Elemento rimosso</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Scopri di più sulla modalità di navigazione in incognito in Chrome<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">Controlla eventuali cavi e riavvia eventuali router, modem o altri dispositivi di rete in uso.</translation>
<translation id="614940544461990577">Prova a:</translation>
<translation id="6150036310511284407">Tripla perforatura a sinistra</translation>
@@ -1618,7 +1658,6 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="6169916984152623906">Ora puoi navigare in privato. Le altre persone che usano questo dispositivo non vedranno le tue attività, ma i download e i preferiti verranno salvati.</translation>
<translation id="6177128806592000436">La tua connessione a questo sito non è sicura</translation>
<translation id="6180316780098470077">Intervallo tra tentativi</translation>
-<translation id="619448280891863779">Può chiedere di aprire e posizionare le finestre sugli schermi</translation>
<translation id="6196640612572343990">Blocca cookie di terze parti</translation>
<translation id="6203231073485539293">Controlla la connessione a Internet</translation>
<translation id="6218753634732582820">Rimuovere l'indirizzo da Chromium?</translation>
@@ -1641,7 +1680,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="6272383483618007430">Google Update</translation>
<translation id="6276112860590028508">Le pagine del tuo elenco di lettura vengono visualizzate qui</translation>
<translation id="627746635834430766">Per pagare più velocemente la prossima volta, salva la carta e l'indirizzo di fatturazione sul tuo Account Google.</translation>
-<translation id="6279098320682980337">Il numero della carta virtuale non è stato compilato? Fai clic sui dettagli della carta per copiarli</translation>
+<translation id="6279183038361895380">Premi |<ph name="ACCELERATOR" />| per mostrare il puntatore</translation>
<translation id="6280223929691119688">Impossibile consegnare all'indirizzo specificato. Seleziona un indirizzo diverso.</translation>
<translation id="6282194474023008486">Codice postale</translation>
<translation id="6285507000506177184">Pulsante Gestisci i download in Chrome, premi Invio per gestire i file che hai scaricato in Chrome</translation>
@@ -1649,6 +1688,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="6290238015253830360">Gli articoli suggeriti vengono visualizzati qui</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{Il tuo dispositivo verrà riavviato adesso}=1{Il tuo dispositivo verrà riavviato tra 1 secondo}other{Il tuo dispositivo verrà riavviato tra # secondi}}</translation>
<translation id="6302269476990306341">Interruzione dell'Assistente Google in Chrome</translation>
<translation id="6305205051461490394"><ph name="URL" /> non è raggiungibile.</translation>
<translation id="6312113039770857350">Pagina web non disponibile</translation>
@@ -1662,7 +1702,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="6337534724793800597">Filtra i criteri per nome</translation>
<translation id="6340739886198108203">Il criterio dell'amministratore sconsiglia l'acquisizione di screenshot o registrazioni quando sono visibili contenuti riservati:</translation>
<translation id="6349101878882523185">Installa <ph name="APP_NAME" /></translation>
-<translation id="6353505687280762741">{COUNT,plural, =0{Nessuna}=1{1 password per <ph name="DOMAIN_LIST" /> (sincronizzata)}=2{2 password per <ph name="DOMAIN_LIST" /> (sincronizzate)}one{# password per <ph name="DOMAIN_LIST" /> (sincronizzate)}other{# password per (<ph name="DOMAIN_LIST" />, sincronizzate)}}</translation>
+<translation id="6353505687280762741">{COUNT,plural, =0{Nessuna}=1{1 password per <ph name="DOMAIN_LIST" /> (sincronizzata)}=2{2 password per <ph name="DOMAIN_LIST" /> (sincronizzate)}other{# password per (<ph name="DOMAIN_LIST" />, sincronizzate)}}</translation>
<translation id="6355392890578844978">Questo browser non è gestito da un'azienda o da un'altra organizzazione. L'attività svolta su questo dispositivo potrebbe essere gestita al di fuori di Chromium. <ph name="BEGIN_LINK" />Scopri di più<ph name="END_LINK" /></translation>
<translation id="6358450015545214790">Che cosa significano?</translation>
<translation id="6361757823711327522">B7</translation>
@@ -1671,7 +1711,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="6377268785556383139">1 risultato per "<ph name="SEARCH_TEXT" />"</translation>
<translation id="6380497234672085559">A0</translation>
<translation id="6383221683286411806">Potrebbe essere applicato un addebito.</translation>
-<translation id="6386120369904791316">{COUNT,plural, =1{1 altro suggerimento}one{# other suggestions}other{# altri suggerimenti}}</translation>
+<translation id="6386120369904791316">{COUNT,plural, =1{1 altro suggerimento}other{# altri suggerimenti}}</translation>
<translation id="6387645831795005740">A volte i malintenzionati imitano i siti modificando leggermente e in modo poco evidente l'URL.</translation>
<translation id="6389470377220713856">Nome sulla carta</translation>
<translation id="6390200185239044127">Piegatura a Z a metà</translation>
@@ -1722,6 +1762,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="6529602333819889595">&amp;Ripeti eliminazione</translation>
<translation id="6545864417968258051">Scansione Bluetooth</translation>
<translation id="6547208576736763147">Perforatura doppia a sinistra</translation>
+<translation id="6554732001434021288">Ultima visita: <ph name="NUM_DAYS" /> giorni fa</translation>
<translation id="6556866813142980365">Ripeti</translation>
<translation id="6569060085658103619">È visualizzata la pagina di un'estensione</translation>
<translation id="6573200754375280815">Perforatura doppia a destra</translation>
@@ -1744,7 +1785,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="663260587451432563">JIS B4</translation>
<translation id="6643016212128521049">Cancella</translation>
<translation id="6645291930348198241">Accedere a cookie e dati del sito.</translation>
-<translation id="6646269444027925224">{COUNT,plural, =0{Nessuno}=1{Da 1 sito (non verrai disconnesso dal tuo Account Google)}one{From # sites (you won't be signed out of your Google Account)}other{Da # siti (non verrai disconnesso dal tuo Account Google)}}</translation>
+<translation id="6646269444027925224">{COUNT,plural, =0{Nessuno}=1{Da 1 sito (non verrai disconnesso dal tuo Account Google)}other{Da # siti (non verrai disconnesso dal tuo Account Google)}}</translation>
<translation id="6648459603387803038">L'amministratore può modificare da remoto la configurazione del browser. L'attività svolta su questo dispositivo potrebbe essere gestita anche al di fuori di Chrome.</translation>
<translation id="6648524591329069940">Carattere serif</translation>
<translation id="6651270836885078973">Gestiti da:</translation>
@@ -1782,7 +1823,6 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="6757797048963528358">Il dispositivo è entrato in modalità sospensione.</translation>
<translation id="6767985426384634228">Vuoi aggiornare l'indirizzo?</translation>
<translation id="6768213884286397650">Hagaki (Postcard)</translation>
-<translation id="6774185088257932239"><ph name="BEGIN_LINK" />Scopri di più<ph name="END_LINK" /> sulla modalità di navigazione in incognito</translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">Lilla</translation>
<translation id="6786747875388722282">Estensioni</translation>
@@ -1859,14 +1899,13 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="7031646650991750659">Le app Google Play che hai installato</translation>
<translation id="7038063300915481831"><ph name="MANAGE_GOOGLE_PRIVACY_FOCUSED_FRIENDLY_MATCH_TEXT" />, premi Tab poi Invio per gestire le impostazioni sulla privacy del tuo Account Google.</translation>
<translation id="7050187094878475250">Hai tentato di visitare il sito <ph name="DOMAIN" />, ma il server ha presentato un certificato con periodo di validità troppo lungo per poter essere ritenuto attendibile.</translation>
-<translation id="705310974202322020">{NUM_CARDS,plural, =1{Al momento questa carta non può essere salvata}one{Al momento queste carte non possono essere salvate}other{Al momento queste carte non possono essere salvate}}</translation>
+<translation id="705310974202322020">{NUM_CARDS,plural, =1{Al momento questa carta non può essere salvata}other{Al momento queste carte non possono essere salvate}}</translation>
<translation id="7053983685419859001">Blocca</translation>
<translation id="7058163556978339998"><ph name="BROWSER" /> ha verificato che <ph name="ISSUER" />ha rilasciato il certificato di questo sito web.</translation>
<translation id="7062635574500127092">Verde petrolio</translation>
<translation id="706295145388601875">Aggiungi e gestisci indirizzi nelle impostazioni di Chrome</translation>
<translation id="7064851114919012435">Informazioni di contatto</translation>
<translation id="7068733155164172741">Inserisci il codice di <ph name="OTP_LENGTH" /> cifre</translation>
-<translation id="7070090581017165256">Informazioni su questo sito</translation>
<translation id="70705239631109039">La connessione non è completamente sicura</translation>
<translation id="7075452647191940183">La richiesta è troppo grande</translation>
<translation id="7079718277001814089">Questo sito contiene malware</translation>
@@ -1883,6 +1922,12 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="7111012039238467737">(Valido)</translation>
<translation id="7118618213916969306">Cerca URL dagli appunti, <ph name="SHORT_URL" /></translation>
<translation id="7119414471315195487">Chiudi altri programmi o schede</translation>
+<translation id="7129355289156517987">Quando chiudi tutte le schede di navigazione in incognito di Chromium, la tua attività nelle schede viene cancellata da questo dispositivo:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Attività di navigazione<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Cronologia delle ricerche<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Informazioni inserite nei moduli<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">Impossibile spedire all'indirizzo specificato. Seleziona un indirizzo diverso.</translation>
<translation id="7132939140423847331">Il tuo amministratore ha impedito la copia di questi dati.</translation>
<translation id="7135130955892390533">Mostra stato</translation>
@@ -1891,12 +1936,12 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="7139892792842608322">Vassoio principale</translation>
<translation id="714064300541049402">Spostamento X lato 2 immagine</translation>
<translation id="7152423860607593928">Number-14 (Envelope)</translation>
-<translation id="7153549335910886479">{PAYMENT_METHOD,plural, =0{<ph name="PAYMENT_METHOD_PREVIEW" />}=1{<ph name="PAYMENT_METHOD_PREVIEW" /> e <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> altro}one{<ph name="PAYMENT_METHOD_PREVIEW" /> and <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> more}other{<ph name="PAYMENT_METHOD_PREVIEW" /> e altri <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}}</translation>
+<translation id="7153549335910886479">{PAYMENT_METHOD,plural, =0{<ph name="PAYMENT_METHOD_PREVIEW" />}=1{<ph name="PAYMENT_METHOD_PREVIEW" /> e <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> altro}other{<ph name="PAYMENT_METHOD_PREVIEW" /> e altri <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}}</translation>
<translation id="7153618581592392745">Lavanda</translation>
<translation id="7156870133441232244">È richiesto l'aggiornamento del server a TLS 1.2 o versione successiva.</translation>
<translation id="717330890047184534">ID GAIA:</translation>
<translation id="7174545416324379297">Uniti</translation>
-<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" /> e <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> altra}one{<ph name="SHIPPING_OPTION_PREVIEW" /> and <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> more}other{<ph name="SHIPPING_OPTION_PREVIEW" /> e altre <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}}</translation>
+<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" /> e <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> altra}other{<ph name="SHIPPING_OPTION_PREVIEW" /> e altre <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}}</translation>
<translation id="7179323680825933600">Salva e compila i metodi di pagamento</translation>
<translation id="7180611975245234373">Aggiorna</translation>
<translation id="7181261019481237103">Apri finestra di navigazione in incognito</translation>
@@ -1905,6 +1950,7 @@ In caso contrario l'uso sarà bloccato dalle impostazioni sulla privacy. I conte
<translation id="7192203810768312527">Consente di liberare <ph name="SIZE" />. Alcuni siti potrebbero caricarsi più lentamente alla prossima visita.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">L'amministratore è in grado di vedere:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, premi Tab poi Invio per aprire una nuova scheda di navigazione in incognito per navigare in privato</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> non è conforme agli standard di sicurezza.</translation>
<translation id="7210993021468939304">Attività Linux all'interno del container; possono installare ed eseguire app Linux all'interno del container</translation>
@@ -1936,6 +1982,7 @@ Ulteriori dettagli:
<translation id="7304562222803846232">Gestisci le impostazioni sulla privacy del tuo Account Google</translation>
<translation id="7305756307268530424">Inizia più lentamente</translation>
<translation id="7308436126008021607">sincronizzazione in background</translation>
+<translation id="7310392214323165548">Il dispositivo verrà riavviato a breve</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">Guida alla connessione</translation>
<translation id="7323804146520582233">Nascondi la sezione "<ph name="SECTION" />"</translation>
@@ -1943,6 +1990,7 @@ Ulteriori dettagli:
<translation id="7334320624316649418">&amp;Ripeti ridisposizione</translation>
<translation id="7335157162773372339">Può richiedere l'autorizzazione per utilizzare la videocamera</translation>
<translation id="7337248890521463931">Mostra più righe</translation>
+<translation id="7337418456231055214">Il numero della carta virtuale non è stato compilato? Fai clic sui dettagli della carta per copiarli. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">Non disponibile sulla piattaforma in uso.</translation>
<translation id="733923710415886693">Il certificato del server non è stato reso pubblico tramite Certificate Transparency.</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1965,6 +2013,7 @@ Ulteriori dettagli:
<translation id="7378627244592794276">No</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">Non applicabile</translation>
+<translation id="7388594495505979117">{0,plural, =1{Il tuo dispositivo verrà riavviato tra 1 minuto}other{Il tuo dispositivo verrà riavviato tra # minuti}}</translation>
<translation id="7390545607259442187">Conferma della carta</translation>
<translation id="7392089738299859607">Aggiorna indirizzo</translation>
<translation id="7399802613464275309">Controllo sicurezza</translation>
@@ -2001,6 +2050,12 @@ Ulteriori dettagli:
<translation id="7485870689360869515">Nessun dato trovato.</translation>
<translation id="7495528107193238112">Questi contenuti sono bloccati. Contatta il proprietario del sito per risolvere il problema.</translation>
<translation id="7497998058912824456">Pulsante Crea documento, premi Invio per creare rapidamente un nuovo documento Google</translation>
+<translation id="7506488012654002225">Chromium <ph name="BEGIN_EMPHASIS" />non salverà<ph name="END_EMPHASIS" /> le seguenti informazioni:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Cronologia di navigazione
+ <ph name="LIST_ITEM" />Cookie e dati dei siti
+ <ph name="LIST_ITEM" />Informazioni inserite nei moduli
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">L'ID dispositivo della norma restituito è vuoto o non corrisponde all'ID dispositivo corrente</translation>
<translation id="7508870219247277067">Verde pisello</translation>
<translation id="7511955381719512146">La rete Wi-Fi in uso potrebbe richiedere la visita della pagina <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
@@ -2048,7 +2103,7 @@ Ulteriori dettagli:
<translation id="762844065391966283">Un oggetto alla volta</translation>
<translation id="7633909222644580952">Dati sulle prestazioni e report sugli arresti anomali</translation>
<translation id="7637571805876720304">Rimuovere la carta di credito da Chromium?</translation>
-<translation id="7637586430889951925">{COUNT,plural, =0{Nessuna}=1{1 password nel tuo account (per <ph name="DOMAIN_LIST" />)}one{# password nel tuo account (per <ph name="DOMAIN_LIST" />)}other{# password nel tuo account (per <ph name="DOMAIN_LIST" />)}}</translation>
+<translation id="7637586430889951925">{COUNT,plural, =0{Nessuna}=1{1 password nel tuo account (per <ph name="DOMAIN_LIST" />)}other{# password nel tuo account (per <ph name="DOMAIN_LIST" />)}}</translation>
<translation id="7638605456503525968">Porte seriali</translation>
<translation id="7639968568612851608">Grigio scuro</translation>
<translation id="7647206758853451655">Qualità di stampa</translation>
@@ -2064,7 +2119,7 @@ Ulteriori dettagli:
<translation id="7667346355482952095">Il token della norma restituito è vuoto o non corrisponde al token corrente</translation>
<translation id="7668654391829183341">Dispositivo sconosciuto</translation>
<translation id="7669271284792375604">I malintenzionati su questo sito potrebbero cercare di indurti con l'inganno a installare programmi che danneggiano la tua navigazione (ad esempio cambiando la tua pagina iniziale o mostrando annunci extra sui siti che visiti).</translation>
-<translation id="7669907849388166732">{COUNT,plural, =1{Azioni intraprese con dati segnalati come riservati (1 azione dall'accesso). <ph name="BEGIN_LINK" />Scopri di più<ph name="END_LINK" />}one{Azioni intraprese con dati segnalati come riservati (# azione dall'accesso). <ph name="BEGIN_LINK" />Scopri di più<ph name="END_LINK" />}other{Azioni intraprese con dati segnalati come riservati (# azioni dall'accesso). <ph name="BEGIN_LINK" />Scopri di più<ph name="END_LINK" />}}</translation>
+<translation id="7669907849388166732">{COUNT,plural, =1{Azioni intraprese con dati segnalati come riservati (1 azione dall'accesso). <ph name="BEGIN_LINK" />Scopri di più<ph name="END_LINK" />}other{Azioni intraprese con dati segnalati come riservati (# azioni dall'accesso). <ph name="BEGIN_LINK" />Scopri di più<ph name="END_LINK" />}}</translation>
<translation id="7673278391011283842">Mailbox 6</translation>
<translation id="7676643023259824263">Cerca testo negli appunti, <ph name="TEXT" /></translation>
<translation id="7679367271685653708">Visualizza e gestisci la tua cronologia di navigazione nelle impostazioni di Chrome</translation>
@@ -2114,10 +2169,9 @@ Ulteriori dettagli:
<translation id="7813600968533626083">Rimuovere il suggerimento per i moduli da Chrome?</translation>
<translation id="781440967107097262">Condividere gli appunti?</translation>
<translation id="7815407501681723534"><ph name="SEARCH_RESULTS" /> per "<ph name="SEARCH_STRING" />": <ph name="NUMBER_OF_RESULTS" /></translation>
-<translation id="782125616001965242">Mostra informazioni su questo sito</translation>
<translation id="782886543891417279">La rete Wi-Fi in uso (<ph name="WIFI_NAME" />) potrebbe richiedere la visita della relativa pagina di accesso.</translation>
<translation id="7836231406687464395">Postfix (Envelope)</translation>
-<translation id="7844689747373518809">{COUNT,plural, =0{Nessuna}=1{1 app (<ph name="EXAMPLE_APP_1" />)}=2{2 app (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}one{# app (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}other{# app (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}}</translation>
+<translation id="7844689747373518809">{COUNT,plural, =0{Nessuna}=1{1 app (<ph name="EXAMPLE_APP_1" />)}=2{2 app (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}other{# app (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}}</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7862185352068345852">Vuoi uscire dal sito?</translation>
<translation id="7865448901209910068">Massima velocità</translation>
@@ -2131,7 +2185,6 @@ Ulteriori dettagli:
<translation id="7888575728750733395">Stampa intent di rendering</translation>
<translation id="7894280532028510793">Se l'ortografia è corretta, <ph name="BEGIN_LINK" />prova a eseguire lo strumento Diagnostica di rete<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (Envelope)</translation>
-<translation id="7931318309563332511">Sconosciuta</translation>
<translation id="793209273132572360">Vuoi aggiornare l'indirizzo?</translation>
<translation id="7932579305932748336">Rivestimento</translation>
<translation id="79338296614623784">Inserisci un numero di telefono valido</translation>
@@ -2156,16 +2209,17 @@ Ulteriori dettagli:
<translation id="7976214039405368314">Numero eccessivo di richieste</translation>
<translation id="7977538094055660992">Dispositivo di uscita</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">Collegata con</translation>
<translation id="798134797138789862">Può chiedere di usare dati e dispositivi per realtà virtuale</translation>
<translation id="7984945080620862648">Al momento non puoi visitare il sito web <ph name="SITE" /> perché ha inviato strane credenziali che Chrome non riesce a elaborare. In genere gli errori di rete e gli attacchi sono temporanei, pertanto questa pagina potrebbe funzionare più tardi.</translation>
-<translation id="79859296434321399">Per visualizzare i contenuti di realtà aumentata, installa ARCore</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">Rilegatura</translation>
<translation id="7992044431894087211">La condivisione dello schermo con <ph name="APPLICATION_TITLE" /> è stata ripristinata</translation>
<translation id="7995512525968007366">Non specificato</translation>
+<translation id="7998269595945679889">Pulsante Apri scheda di navigazione in incognito, premi Invio per aprire una nuova scheda di navigazione in incognito per navigare in privato</translation>
<translation id="800218591365569300">Prova a chiudere altri programmi o schede per liberare spazio in memoria.</translation>
<translation id="8004582292198964060">Browser</translation>
-<translation id="8012116502927253373">{NUM_CARDS,plural, =1{Questa carta e il relativo indirizzo di fatturazione verranno salvati. Potrai usarla dopo aver eseguito l'accesso all'account <ph name="USER_EMAIL" />.}one{Queste carte e i relativi indirizzi di fatturazione verranno salvati. Potrai usarle dopo aver eseguito l'accesso all'account <ph name="USER_EMAIL" />.}other{Queste carte e i relativi indirizzi di fatturazione verranno salvati. Potrai usarle dopo aver eseguito l'accesso all'account <ph name="USER_EMAIL" />.}}</translation>
+<translation id="8012116502927253373">{NUM_CARDS,plural, =1{Questa carta e il relativo indirizzo di fatturazione verranno salvati. Potrai usarla dopo aver eseguito l'accesso all'account <ph name="USER_EMAIL" />.}other{Queste carte e i relativi indirizzi di fatturazione verranno salvati. Potrai usarle dopo aver eseguito l'accesso all'account <ph name="USER_EMAIL" />.}}</translation>
<translation id="8025119109950072390">I malintenzionati su questo sito potrebbero indurti con l'inganno a effettuare operazioni pericolose, come installare software o fornire i tuoi dati personali (ad esempio password, numeri di telefono o carte di credito).</translation>
<translation id="8026334261755873520">Cancella dati di navigazione</translation>
<translation id="8027077570865220386">Vassoio 15</translation>
@@ -2222,6 +2276,7 @@ Ulteriori dettagli:
<translation id="8202370299023114387">Conflitto</translation>
<translation id="8206978196348664717">Prc4 (Envelope)</translation>
<translation id="8211406090763984747">La connessione è sicura</translation>
+<translation id="8217240300496046857">I siti non possono utilizzare i cookie che monitorano la tua attività sul Web. Le funzionalità su alcuni siti potrebbero non essere disponibili.</translation>
<translation id="8218327578424803826">Posizione assegnata:</translation>
<translation id="8220146938470311105">C7/C6 (Busta)</translation>
<translation id="8225771182978767009">La persona che ha configurato il computer ha deciso di bloccare questo sito.</translation>
@@ -2262,14 +2317,9 @@ Ulteriori dettagli:
<translation id="830498451218851433">Piegatura a metà</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">App installate e frequenza di utilizzo</translation>
+<translation id="8317207217658302555">Vuoi aggiornare ARCore?</translation>
<translation id="831997045666694187">Sera</translation>
<translation id="8321476692217554900">notifiche</translation>
-<translation id="8328484624016508118">Dopo aver chiuso tutte le schede di navigazione in incognito, Chrome cancella:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />L'attività di navigazione da questo dispositivo<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />La cronologia delle ricerche da questo dispositivo<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Le informazioni inserite nei moduli<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489">Accesso a <ph name="HOST_NAME" /> negato</translation>
<translation id="833262891116910667">Evidenzia</translation>
<translation id="8339163506404995330">Le pagine in <ph name="LANGUAGE" /> non verranno tradotte</translation>
@@ -2307,7 +2357,7 @@ Ulteriori dettagli:
<translation id="8449836157089738489">Apri tutto in un nuovo gruppo di schede</translation>
<translation id="8457125768502047971">Indeterminato</translation>
<translation id="8461694314515752532">Cripta i dati sincronizzati con la tua passphrase di sincronizzazione</translation>
-<translation id="8466379296835108687">{COUNT,plural, =1{1 carta di credito}one{# credit cards}other{# carte di credito}}</translation>
+<translation id="8466379296835108687">{COUNT,plural, =1{1 carta di credito}other{# carte di credito}}</translation>
<translation id="8473863474539038330">Indirizzi e altro</translation>
<translation id="8474910779563686872">Mostra i dettagli dello sviluppatore</translation>
<translation id="8479754468255770962">Pinzatura in basso a sinistra</translation>
@@ -2321,6 +2371,7 @@ Ulteriori dettagli:
<translation id="8507227106804027148">Riga di comando</translation>
<translation id="8508648098325802031">Icona Ricerca</translation>
<translation id="8511402995811232419">Gestisci i cookie</translation>
+<translation id="8519753333133776369">Dispositivo HID consentito dal tuo amministratore</translation>
<translation id="8522552481199248698">Chrome può aiutarti a proteggere il tuo Account Google e a modificare la password.</translation>
<translation id="8530813470445476232">Cancella la cronologia di navigazione e i cookie, svuota la cache e altro ancora nelle impostazioni di Chrome</translation>
<translation id="8533619373899488139">Visita &lt;strong&gt;chrome://policy&lt;/strong&gt; per visualizzare l'elenco di URL bloccati e altri criteri applicati dall'amministratore di sistema.
@@ -2330,10 +2381,9 @@ Ulteriori dettagli:
<translation id="8542014550340843547">Tripla pinzatura in basso</translation>
<translation id="8543181531796978784">Puoi <ph name="BEGIN_ERROR_LINK" />segnalare un problema di rilevamento<ph name="END_ERROR_LINK" /> oppure, se sei consapevole dei rischi per la tua sicurezza, <ph name="BEGIN_LINK" />visita questo sito non sicuro<ph name="END_LINK" />.</translation>
<translation id="8554010658308662631">Carica altro</translation>
-<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{Reimposta l'autorizzazione}one{Reimposta l'autorizzazione}other{Reimposta le autorizzazioni}}</translation>
+<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{Reimposta l'autorizzazione}other{Reimposta le autorizzazioni}}</translation>
<translation id="8555010941760982128">Utilizza questo codice al momento del pagamento</translation>
<translation id="8557066899867184262">Il codice CVC si trova sul lato posteriore della carta.</translation>
-<translation id="8558485628462305855">Per visualizzare i contenuti di realtà aumentata, aggiorna ARCore</translation>
<translation id="8559762987265718583">Impossibile stabilire una connessione privata con il sito <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> perché data e ora del dispositivo (<ph name="DATE_AND_TIME" />) sono sbagliate.</translation>
<translation id="8564182942834072828">Documenti separati/Copie non fascicolate</translation>
<translation id="8564985650692024650">Chromium ti consiglia di reimpostare la password di <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" />, se l'hai utilizzata su altri siti.</translation>
@@ -2352,6 +2402,7 @@ Ulteriori dettagli:
<translation id="865032292777205197">sensori di movimento</translation>
<translation id="8663226718884576429">Riepilogo ordine, <ph name="TOTAL_LABEL" />, altri dettagli</translation>
<translation id="8666678546361132282">Inglese</translation>
+<translation id="8669306706049782872">Usare informazioni sui tuoi schermi per aprire e posizionare finestre</translation>
<translation id="867224526087042813">Firma</translation>
<translation id="8676424191133491403">Nessun ritardo</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, risposta, <ph name="ANSWER" /></translation>
@@ -2378,6 +2429,7 @@ Ulteriori dettagli:
<translation id="8731544501227493793">Pulsante Gestisci password, premi Invio per visualizzare e gestire le tue password nelle impostazioni di Chrome</translation>
<translation id="8734529307927223492">Il tuo dispositivo <ph name="DEVICE_TYPE" /> è gestito da <ph name="MANAGER" /></translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, premi Tab poi Invio per aprire una nuova finestra di navigazione in incognito per navigare in privato</translation>
+<translation id="8737685506611670901">Aprire link <ph name="PROTOCOL" /> anziché <ph name="REPLACED_HANDLER_TITLE" /></translation>
<translation id="8738058698779197622">Per poter stabilire una connessione protetta, l'orologio deve essere impostato correttamente perché i certificati utilizzati dai siti web per identificarsi sono validi soltanto per determinati periodi di tempo. L'orologio del dispositivo è sbagliato, pertanto Chromium non può verificare i certificati.</translation>
<translation id="8740359287975076522">Impossibile trovare l'&lt;abbr id="dnsDefinition"&gt;indirizzo DNS&lt;/abbr&gt; di <ph name="HOST_NAME" />. Stiamo analizzando il problema.</translation>
<translation id="8742371904523228557"><ph name="ONE_TIME_CODE" /> è il tuo codice per <ph name="ORIGIN" /></translation>
@@ -2405,6 +2457,7 @@ Ulteriori dettagli:
<translation id="883848425547221593">Altri Preferiti</translation>
<translation id="884264119367021077">Indirizzo di spedizione</translation>
<translation id="884923133447025588">Nessun sistema di revoca trovato.</translation>
+<translation id="8849262850971482943">Usa la carta virtuale per una maggiore sicurezza</translation>
<translation id="885730110891505394">Condivisione con Google</translation>
<translation id="8858065207712248076">Chrome ti consiglia di reimpostare la password di <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" />, se l'hai utilizzata su altri siti.</translation>
<translation id="885906927438988819">Se l'ortografia è corretta, <ph name="BEGIN_LINK" />prova a eseguire lo strumento Diagnostica di rete Windows<ph name="END_LINK" />.</translation>
@@ -2454,6 +2507,7 @@ Ulteriori dettagli:
<translation id="9004367719664099443">Sessione VR in corso</translation>
<translation id="9005998258318286617">Impossibile caricare il documento PDF.</translation>
<translation id="9008201768610948239">Ignora</translation>
+<translation id="901834265349196618">email</translation>
<translation id="9020200922353704812">Indirizzo di fatturazione della carta obbligatorio</translation>
<translation id="9020542370529661692">Questa pagina è stata tradotta in <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9020742383383852663">A8</translation>
@@ -2502,6 +2556,7 @@ Ulteriori dettagli:
<translation id="9150045010208374699">Utilizzare la fotocamera</translation>
<translation id="9150685862434908345">L'amministratore può modificare da remoto la configurazione del browser. L'attività svolta su questo dispositivo potrebbe essere gestita anche al di fuori di Chrome. <ph name="BEGIN_LINK" />Ulteriori informazioni<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">Aggiornato</translation>
+<translation id="9155211586651734179">Periferiche audio collegate</translation>
<translation id="9157595877708044936">Configurazione in corso...</translation>
<translation id="9158625974267017556">C6 (Envelope)</translation>
<translation id="9164029392738894042">Controllo accuratezza</translation>
@@ -2540,7 +2595,7 @@ Ulteriori dettagli:
<translation id="962484866189421427">Questi contenuti potrebbero installare app ingannevoli che si spacciano per qualcos'altro o raccolgono dati che potrebbero essere usati per monitorare la tua attività. <ph name="BEGIN_LINK" />Mostra comunque<ph name="END_LINK" /></translation>
<translation id="969892804517981540">Build ufficiale</translation>
<translation id="973773823069644502">Aggiungi l'indirizzo di consegna</translation>
-<translation id="975560348586398090">{COUNT,plural, =0{Nessuno}=1{1 elemento}one{# items}other{# elementi}}</translation>
+<translation id="975560348586398090">{COUNT,plural, =0{Nessuno}=1{1 elemento}other{# elementi}}</translation>
<translation id="981121421437150478">Offline</translation>
<translation id="984275831282074731">Metodi di pagamento</translation>
<translation id="985199708454569384">&lt;p&gt;Vedrai questo errore se la data e l'ora del dispositivo mobile o del computer non sono esatte.&lt;/p&gt;
diff --git a/chromium/components/strings/components_strings_iw.xtb b/chromium/components/strings/components_strings_iw.xtb
index 7f8e547a4f9..813199236bf 100644
--- a/chromium/components/strings/components_strings_iw.xtb
+++ b/chromium/components/strings/components_strings_iw.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">לפרטי×</translation>
<translation id="1030706264415084469"><ph name="URL" /> רוצה ל×חסן ב×ופן קבוע כמות גדולה של × ×ª×•× ×™× ×‘×ž×›×©×™×¨ שלך</translation>
<translation id="1032854598605920125">סיבוב בכיוון השעון</translation>
+<translation id="1033329911862281889">המצב הפרטי ×œ× ×ž×¡×ª×™×¨ ×ותך לגמרי ב×ינטרנט:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />××ª×¨×™× ×•×”×©×™×¨×•×ª×™× ×©×‘×”× × ×¢×©×” שימוש ×™×•×“×¢×™× ×©×‘×™×§×¨×ª בה×<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />×ž×¢×¡×™×§×™× ×•×ž×•×¡×“×•×ª ×œ×™×ž×•×“×™× ×™×›×•×œ×™× ×œ×¢×§×•×‘ ×חר פעילות הגלישה שלך<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />יכול להיות שספקי ×ינטרנט יעקבו ×חר תנועת הגולשי×<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">כיבוי</translation>
<translation id="1036982837258183574">יש ללחוץ על |<ph name="ACCELERATOR" />| כדי לצ×ת ממסך מל×</translation>
<translation id="1038106730571050514">הצגת הצעות</translation>
<translation id="1038842779957582377">×©× ×œ× ×™×“×•×¢</translation>
<translation id="1041998700806130099">הודעה לגבי גיליון עבודות</translation>
<translation id="1048785276086539861">המסמך הזה יחזור לתצוגת דף יחיד בזמן עריכת ההערות</translation>
-<translation id="1049743911850919806">גלישה פרטית</translation>
<translation id="1050038467049342496">סגירת ×פליקציות ×חרות</translation>
<translation id="1055184225775184556">&amp;ביטול הוספה</translation>
<translation id="1056898198331236512">×זהרה</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">המטמון של המדיניות תקין</translation>
<translation id="1130564665089811311">â€×”לחצן '×ª×¨×’×•× ×”×“×£', יש ללחוץ על Enter כדי ×œ×ª×¨×’× ×ת הדף ×”×–×” ב×מצעות Google Translate</translation>
<translation id="1131264053432022307">תמונה שהעתקת</translation>
+<translation id="1142846828089312304">â€×—סימת קובצי cookie של צד שלישי במצב ×נונימי</translation>
<translation id="1150979032973867961">השרת ×”×–×” ×œ× ×”×¦×œ×™×— להוכיח ×©×”×•× <ph name="DOMAIN" />. ×ישור ×”×בטחה שלו ×œ× × ×—×©×‘ כמהימן על ידי מערכת ההפעלה של המחשב. ייתכן שהסיבה לכך ×”×™× ×ª×¦×•×¨×” שגויה ×ו תוקף המיירט ×ת החיבור שלך.</translation>
<translation id="1151972924205500581">נדרשת סיסמה</translation>
<translation id="1156303062776767266">מוצג לך קובץ מקומי ×ו משותף</translation>
@@ -64,7 +70,6 @@
<translation id="1178581264944972037">השהיה</translation>
<translation id="1181037720776840403">הסרה</translation>
<translation id="1186201132766001848">בדיקת הסיסמ×ות</translation>
-<translation id="1195210374336998651">להגדרות ×”×פליקציה</translation>
<translation id="1195558154361252544">הצגת ההודעות חסומה ב×ופן ×וטומטי בכל ×”×תרי×, מלבד ×”××ª×¨×™× ×©×‘×”× ×”×™× ×ושרה</translation>
<translation id="1197088940767939838">כתו×</translation>
<translation id="1201402288615127009">הב×</translation>
@@ -111,7 +116,7 @@
<translation id="1307966114820526988">תכונות שהוצ×ו משימוש</translation>
<translation id="1308113895091915999">הצעה זמינה</translation>
<translation id="1312803275555673949">×”×× ×§×™×™×ž×•×ª ר×יות תומכות?</translation>
-<translation id="131405271941274527">â€<ph name="URL" /> רוצה לשלוח ולקבל מידע ×חרי כל הקשה של מספר הטלפון שלך במכשיר NFC</translation>
+<translation id="1314311879718644478">הצגת תוכן של מצי×ות רבודה</translation>
<translation id="1314509827145471431">כריכה בקצה הימני</translation>
<translation id="1318023360584041678">הפריט נשמר בקבוצת הכרטיסיות</translation>
<translation id="1319245136674974084">×œ× ×¦×¨×™×š לש×ול יותר לגבי ×”×פליקציה הזו</translation>
@@ -161,6 +166,7 @@
<translation id="142858679511221695">משתמש בענן</translation>
<translation id="1428729058023778569">â€×”×זהרה הזו מוצגת לך ×›×™ ×”×תר ×”×–×” ×œ× ×ª×•×ž×š ב-HTTPS. <ph name="BEGIN_LEARN_MORE_LINK" />מידע נוסף<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">הדפסה</translation>
+<translation id="1432187715652018471">â€×”תקבלה מהדף ×”×–×” בקשה להתקין handler של שירות.</translation>
<translation id="1432581352905426595">ניהול מנועי חיפוש</translation>
<translation id="1436185428532214179">×”×תר יכול לבקש הרש××” לערוך ×§×‘×¦×™× ×•×ª×™×§×™×•×ª במכשיר</translation>
<translation id="1442386063175183758">כנף ימנית בקיפול</translation>
@@ -181,6 +187,12 @@
<translation id="1483493594462132177">שליחה</translation>
<translation id="1484290072879560759">בחירת כתובת למשלוח</translation>
<translation id="1492194039220927094">דחיפת מדיניות:</translation>
+<translation id="149293076951187737">â€×¢× הסגירה של כל הכרטיסיות הפרטיות ב-Chrome, הפעילות שלך בכרטיסיות הב×ות נמחקת מהמכשיר ×”×–×”:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />פעילות הגלישה<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />היסטוריית החיפושי×<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />מידע שהוזן בטפסי×<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">חזרה לכרטיסייה</translation>
<translation id="1501859676467574491">â€×”צגת ×›×¨×˜×™×¡×™× ×ž×—×©×‘×•×Ÿ Google שלך</translation>
<translation id="1507202001669085618">â€&lt;p&gt;השגי××” הזו תוצג ×× ×ž×©×ª×ž×©×™× ×‘×¤×•×¨×˜×œ Wi-Fi שבו צריך להיכנס לחשבון לפני התחברות לרשת.&lt;/p&gt;
@@ -208,6 +220,8 @@
<translation id="1559572115229829303">â€&lt;p&gt;×œ× × ×™×ª×Ÿ ליצור חיבור פרטי ×ל <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> ×ž×©×•× ×©×”×ª×ריך והשעה במכשיר שלך (<ph name="DATE_AND_TIME" />) שגויי×.&lt;/p&gt;
&lt;p&gt;יש לשנות ×ת הת×ריך והשעה בקטע &lt;strong&gt;כללי&lt;/strong&gt; ב×פליקציה &lt;strong&gt;הגדרות&lt;/strong&gt;â€.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">המכשיר יופעל מחדש על ידי ×”×דמין בשעה <ph name="TIME" /> בת×ריך <ph name="DATE" /></translation>
+<translation id="156703335097561114">מידע שקשור לרשת, כמו כתובות, הגדרת הממשק ו×יכות החיבור.</translation>
<translation id="1567040042588613346">המדיניות הזו פועלת כמו שצריך ×בל הוגדר ערך ×–×”×” ×‘×ž×§×•× ×חר שמוחלף על ידי המדיניות הזו.</translation>
<translation id="1569487616857761740">יש להזין ת×ריך תפוגה</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@
<translation id="1583429793053364125">משהו השתבש בעת הצגת דף ×ינטרנט ×–×”.</translation>
<translation id="1586541204584340881">×ילו ×ª×•×¡×¤×™× ×”×ª×§× ×ª.</translation>
<translation id="1588438908519853928">רגיל</translation>
+<translation id="1589050138437146318">â€×œ×”תקין ×ת ARCore?</translation>
<translation id="1592005682883173041">גישה ×œ× ×ª×•× ×™× ×ž×§×•×ž×™×™×</translation>
<translation id="1594030484168838125">בחירה</translation>
<translation id="160851722280695521">â€×”פעלת המשחק Dino Run ב-Chrome</translation>
@@ -254,7 +269,7 @@
<translation id="1711234383449478798">×ין התייחסות למדיניות ×›×™ ×œ× ×”×•×’×“×¨ הערך <ph name="VALUE" /> ב-<ph name="POLICY_NAME" />.</translation>
<translation id="1712552549805331520"><ph name="URL" /> רוצה ל×חסן × ×ª×•× ×™× ×‘×ž×—×©×‘ המקומי שלך ב×ופן קבוע</translation>
<translation id="1713628304598226412">מגש 2</translation>
-<translation id="1715874602234207">F</translation>
+<translation id="1715874602234207">ו'</translation>
<translation id="1717218214683051432">חיישני תנועה</translation>
<translation id="1717494416764505390">תיבת דו×ר 3</translation>
<translation id="1718029547804390981">המסמך גדול מדי ×•×œ× × ×™×ª×Ÿ להוסיף לו הערות</translation>
@@ -283,6 +298,7 @@
פורמט הכותרת שגוי, ולכן הדפדפן ×œ× ×™×›×•×œ למל×
×ת הבקשה שלך בשביל <ph name="SITE" />. מפעילי ××ª×¨×™× ×™×›×•×œ×™× ×œ×”×©×ª×ž×© במדיניות מקור
כדי להגדיר מ×פייני ×בטחה ומ××¤×™×™× ×™× ××—×¨×™× ×¢×‘×•×¨ ×תר מסוי×.</translation>
+<translation id="1774592222195216949">â€<ph name="BEGIN_LINK" />מידע נוסף על מצב פרטי ב-Chromium<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">×›×ן מופיעות הכרטיסיות שפתחת</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -410,6 +426,7 @@
<translation id="22081806969704220">מגש 3</translation>
<translation id="2212735316055980242">×œ× × ×ž×¦××” מדיניות</translation>
<translation id="2213606439339815911">מ×חזר רשומות...</translation>
+<translation id="2213612003795704869">הדף מודפס</translation>
<translation id="2215727959747642672">עריכת קובץ</translation>
<translation id="2218879909401188352">×ª×•×§×¤×™× ×©×ž×©×ª×ž×©×™× ×¢×›×©×™×• ב-<ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ×¢×œ×•×œ×™× ×œ×”×ª×§×™×Ÿ ×פליקציות מסוכנות ×•×œ×’×¨×•× × ×–×§ למכשיר שלך, להגדיל ×ת ×”×—×™×•×‘×™× ×©×œ×š על החבילה לנייד ×ו לגנוב ×ת המידע ×”×ישי שלך. <ph name="BEGIN_LEARN_MORE_LINK" />מידע נוסף<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">×ין ×ינטרנט</translation>
@@ -419,6 +436,7 @@
<translation id="2248949050832152960">â€×©×™×ž×•×© ב-WebAuthn</translation>
<translation id="2250931979407627383">הידוק קצוות בצד שמ×ל</translation>
<translation id="225207911366869382">ערך ×–×” ×”×•×¦× ×ž×©×™×ž×•×© עבור מדיניות זו.</translation>
+<translation id="2256115617011615191">יש להפעיל מחדש כעת</translation>
<translation id="2258928405015593961">צריך להזין ת×ריך תפוגה עתידי ולנסות שוב</translation>
<translation id="225943865679747347">קוד שגי××”: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">â€×©×’×™×ת HTTP</translation>
@@ -446,6 +464,7 @@
<translation id="2337852623177822836">ההגדרה נשלטת על-ידי מנהל המערכת</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> רוצה לבצע הת×מה ×¢×</translation>
<translation id="2346319942568447007">תמונה שהעתקת</translation>
+<translation id="2350796302381711542">×”×× ×œ×פשר ל-<ph name="HANDLER_HOSTNAME" /> לפתוח ×ת כל קישורי <ph name="PROTOCOL" /> ×‘×ž×§×•× ×ת <ph name="REPLACED_HANDLER_TITLE" />?</translation>
<translation id="2354001756790975382">סימניות ×חרות</translation>
<translation id="2354430244986887761">â€×”תכונה 'גלישה בטוחה' של Google <ph name="BEGIN_LINK" />מצ××” ל×חרונה ×פליקציות מזיקות<ph name="END_LINK" /> ב×תר <ph name="SITE" />.</translation>
<translation id="2355395290879513365">ייתכן ×©×ª×•×§×¤×™× ×™×•×›×œ×• לר×ות ×ת התמונות שבהן צפית ב×תר ×–×”, ול×חר מכן ×”× ×™× ×¡×• להונות ×ותך על ידי שינוי התמונות.</translation>
@@ -471,6 +490,7 @@
<translation id="2413528052993050574">השרת ×”×–×” ×œ× ×”×¦×œ×™×— להוכיח ×©×”×•× <ph name="DOMAIN" />. ייתכן ש×ישור ×”×בטחה שלו בוטל. הסיבה לכך עשויה להיות הגדרה שגויה ×ו תוקף המיירט ×ת החיבור שלך.</translation>
<translation id="2414886740292270097">×›×”×”</translation>
<translation id="2430968933669123598">â€× ×™×”ול חשבון Google, צריך להקיש על Enter כדי לנהל ×ת המידע, הפרטיות וה×בטחה בחשבון Google</translation>
+<translation id="2436186046335138073">×”×× ×œ×פשר ל-<ph name="HANDLER_HOSTNAME" /> לפתוח ×ת כל קישורי <ph name="PROTOCOL" />?</translation>
<translation id="2438874542388153331">4 × ×™×§×•×‘×™× ×‘×¦×“ ימין</translation>
<translation id="2450021089947420533">תהליכי×</translation>
<translation id="2463739503403862330">מילוי</translation>
@@ -478,6 +498,7 @@
<translation id="2465655957518002998">בחירת שיטת מסירה</translation>
<translation id="2465688316154986572">סיכת הידוק</translation>
<translation id="2465914000209955735">â€× ×™×”ול ×”×§×‘×¦×™× ×©×”×•×¨×“×ª ב-Chrome</translation>
+<translation id="2466004615675155314">הצגת מידע מה×ינטרנט</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />להפעיל ×ת ×בחון הרשת<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">â€×¡×“ר מ-1 עד N</translation>
<translation id="2470767536994572628">המסמך הזה יחזור לתצוגת דף יחיד ולמצב הסיבוב המקורי שלו בזמן עריכת ההערות</translation>
@@ -498,6 +519,7 @@
<translation id="2523886232349826891">הכרטיס יישמר רק במכשיר הזה</translation>
<translation id="2524461107774643265">הוספת עוד מידע</translation>
<translation id="2529899080962247600">השדה ×”×–×” יכול לכלול עד <ph name="MAX_ITEMS_LIMIT" /> רשומות. המערכת ×ª×ª×¢×œ× ×ž×¨×©×•×ž×•×ª נוספות.</translation>
+<translation id="2535585790302968248">כדי לגלוש ב×ופן פרטי, יש לפתוח כרטיסייה פרטית חדשה</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{ודומיין ×חד נוסף}two{ו-# ×“×•×ž×™×™× ×™× × ×•×¡×¤×™×}many{ו-# ×“×•×ž×™×™× ×™× × ×•×¡×¤×™×}other{ו-# ×“×•×ž×™×™× ×™× × ×•×¡×¤×™×}}</translation>
<translation id="2536110899380797252">הוספת כתובת</translation>
<translation id="2539524384386349900">×–×”×”</translation>
@@ -523,7 +545,14 @@
<translation id="2597378329261239068">מסמך ×–×” מוגן ב×מצעות סיסמה. יש להזין סיסמה.</translation>
<translation id="2609632851001447353">ורי×ציות</translation>
<translation id="2610561535971892504">לחיצה להעתקה</translation>
+<translation id="2617988307566202237">â€Chrome <ph name="BEGIN_EMPHASIS" />×œ× ×™×©×ž×•×¨<ph name="END_EMPHASIS" /> ×ת ×”× ×ª×•× ×™× ×”×‘××™×:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />היסטוריית הגלישה שלך
+ <ph name="LIST_ITEM" />קובצי cookie ונתוני ×תרי×
+ <ph name="LIST_ITEM" />מידע שהוזן בטפסי×
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (Envelope)‎</translation>
+<translation id="2623663032199728144">×”×תר יכול לבקש הרש××” להשתמש במידע לגבי ×”×ž×¡×›×™× ×©×œ×š</translation>
<translation id="2625385379895617796">השעון שלך מקדי×</translation>
<translation id="262745152991669301">â€×”×תר יכול לבקש הרש××” להתחבר ×ל התקני USB</translation>
<translation id="2629325967560697240">â€×›×“×™ ליהנות מ×בטחה ברמה הגבוהה ביותר ב-Chrome, יש <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />להפעיל ×ת ×”×”×’× ×” המשופרת<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -557,6 +586,7 @@
<translation id="2709516037105925701">מילוי ×וטומטי</translation>
<translation id="2713444072780614174">לבן</translation>
<translation id="2715612312510870559">â€<ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />, יש להקיש על Tab ו××– על Enter כדי לנהל ×ת ×”×ª×©×œ×•×ž×™× ×•×ת פרטי כרטיס ×”×שר××™ שלך בהגדרות Chrome</translation>
+<translation id="271663710482723385">צריך ללחוץ על |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| כדי לצ×ת מהמסך המל×</translation>
<translation id="2721148159707890343">הבקשה בוצעה בהצלחה</translation>
<translation id="2723669454293168317">â€×”רצה של בדיקת ×בטחה בהגדרות Chrome</translation>
<translation id="2726001110728089263">מגש צידי</translation>
@@ -587,6 +617,7 @@
<translation id="2850739647070081192">Invite (Envelope)‎</translation>
<translation id="2856444702002559011">ייתכן ×©×ª×•×§×¤×™× ×ž× ×¡×™× ×œ×’× ×•×‘ ×ת ×”×¤×¨×˜×™× ×©×œ×š מה×תר <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (לדוגמה, סיסמ×ות, הודעות ×ו כרטיסי ×שר××™). <ph name="BEGIN_LEARN_MORE_LINK" />מידע נוסף<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">ב×תר ×”×–×” מוצגות מודעות מפריעות ×ו מטעות.</translation>
+<translation id="286512204874376891">כרטיס וירטו×לי מסווה ×ת הכרטיס בפועל כדי לעזור להגן עליך מפני תרמיות פוטנצי×ליות. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">ידידותי</translation>
<translation id="2876489322757410363">בחרת לצ×ת מהמצב ×”×נונימי כדי ×œ×©×œ× ×‘×מצעות ×פליקציה חיצונית. להמשיך?</translation>
<translation id="2876949457278336305">â€<ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />, ×œ×•×—×¦×™× ×¢×œ Tab ו××– על Enter כדי לנהל ×ת הגלישה הבטוחה ועוד בהגדרות Chrome</translation>
@@ -611,6 +642,7 @@
<translation id="2930577230479659665">חיתוך ×חרי כל עותק</translation>
<translation id="2932085390869194046">הצעת סיסמה...</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019">לפתוח קישורי <ph name="PROTOCOL" /></translation>
<translation id="2941952326391522266">השרת ×”×–×” ×œ× ×”×¦×œ×™×— להוכיח ×©×”×•× <ph name="DOMAIN" />. ×ישור ×”×בטחה שלו ×”×•× ×ž-<ph name="DOMAIN2" />. ייתכן שהסיבה לכך ×”×™× ×ª×¦×•×¨×” שגויה ×ו תוקף המיירט ×ת החיבור שלך.</translation>
<translation id="2943895734390379394">זמן העל××”:</translation>
<translation id="2948083400971632585">â€× ×™×ª×Ÿ להשבית כל שרת proxy המוגדר לחיבור מדף ההגדרות.</translation>
@@ -643,6 +675,7 @@
<translation id="3037605927509011580">×וי, ל×!</translation>
<translation id="3041612393474885105">פרטי ×ישור</translation>
<translation id="3044034790304486808">המשך החקירה</translation>
+<translation id="305162504811187366">â€×”היסטוריה של Chrome Remote Desktop, כולל חותמות זמן, מ××¨×—×™× ×•×ž×–×”×™ ×¡×©× ×™× ×©×œ לקוחות</translation>
<translation id="3060227939791841287">C9 (Envelope)‎</translation>
<translation id="3061707000357573562">שירות תיקון</translation>
<translation id="306573536155379004">המשחק התחיל.</translation>
@@ -683,6 +716,7 @@
<translation id="3197136577151645743">×”×תר יכול לבקש הרש××” לש×ול מתי ×ת/×” משתמש/ת בפועל במכשיר</translation>
<translation id="3202497928925179914">â€<ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />, יש להקיש על Tab ו××– על Enter כדי לקבוע ××™×–×” מידע יסונכרן בהגדרות Chrome</translation>
<translation id="320323717674993345">ביטול תשלו×</translation>
+<translation id="3203366800380907218">מה×ינטרנט</translation>
<translation id="3207960819495026254">מסומן בסימנייה</translation>
<translation id="3209034400446768650">כניסה לדף עשויה להיות כרוכה בתשלו×</translation>
<translation id="3212581601480735796">הפעילות שלך ב-<ph name="HOSTNAME" /> מנוטרת</translation>
@@ -699,10 +733,12 @@
<translation id="3234666976984236645">×–×”×” תמיד תוכן חשוב ב×תר ×–×”</translation>
<translation id="3240683217920639535">â€<ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />, ×ž×§×™×©×™× ×¢×œ Tab ו××– על Enter כדי להת××™× ×ישית ×ת מר××” הדפדפן</translation>
<translation id="3240791268468473923">הגיליון '×ין הת×מה בין פרטי הכניסה לפרטי הכניסה ×œ×ª×©×œ×•× ×ž×ובטח' פתוח</translation>
+<translation id="324180406144491771">×§×™×©×•×¨×™× ×©×œ “<ph name="HOST_NAME" />†חסומי×</translation>
<translation id="3249845759089040423">מגניב</translation>
<translation id="3252266817569339921">צרפתית</translation>
<translation id="3257954757204451555">מהו מקור המידע הזה?</translation>
<translation id="3259648571731540213">â€<ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />, ×ž×§×™×©×™× ×¢×œ Tab ו××– על Enter כדי ליצור במהירות ×ירוע חדש ביומן Google</translation>
+<translation id="3261488570342242926">מידע על ×›×¨×˜×™×¡×™× ×•×™×¨×˜×•×ליי×</translation>
<translation id="3264837738038045344">â€×”לחצן לניהול הגדרות Chrome, ×ž×§×™×©×™× ×¢×œ Enter כדי להיכנס להגדרות Chrome</translation>
<translation id="3266793032086590337">ערך (התנגשות)</translation>
<translation id="3268451620468152448">כרטיסיות פתוחות</translation>
@@ -716,6 +752,7 @@
<translation id="3288238092761586174">ייתכן שיידרשו ×©×œ×‘×™× × ×•×¡×¤×™× ×œ×ימות ×”×ª×©×œ×•× ×©×œ×š על ידי <ph name="URL" /></translation>
<translation id="3293642807462928945">מידע נוסף על המדיניות <ph name="POLICY_NAME" /></translation>
<translation id="3295444047715739395">â€×”צגה וניהול של הסיסמ×ות שלך בהגדרות Chrome</translation>
+<translation id="3303795387212510132">ל×שר ל×פליקציה לפתוח קישורי <ph name="PROTOCOL_SCHEME" />?</translation>
<translation id="3303855915957856445">×œ× × ×ž×¦×ו תוצ×ות חיפוש</translation>
<translation id="3304073249511302126">â€×¡×¨×™×§×ª Bluetooth</translation>
<translation id="3308006649705061278">â€×™×—ידה ×רגונית (OU)</translation>
@@ -729,12 +766,6 @@
<translation id="3345782426586609320">×¢×™× ×™×™×</translation>
<translation id="3355823806454867987">â€×©×™× ×•×™ הגדרות שרת Proxy...</translation>
<translation id="3360103848165129075">גיליון פרטי התשלו×</translation>
-<translation id="3361596688432910856">â€Chrome <ph name="BEGIN_EMPHASIS" />×œ× ×™×©×ž×•×¨<ph name="END_EMPHASIS" /> ×ת המידע הב×:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />היסטוריית הגלישה שלך
- <ph name="LIST_ITEM" />קובצי Cookie ונתוני ×תרי×
- <ph name="LIST_ITEM" />מידע שהוזן בטפסי×
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">המדיניות הזו הועתקה ב×ופן ×וטומטי ממדיניות <ph name="OLD_POLICY" /> שהוצ××” משימוש. צריך להשתמש במדיניות הזו במקומה.</translation>
<translation id="3364869320075768271"><ph name="URL" /> רוצה להשתמש במכשיר המצי×ות המדומה ובנתוני המצי×ות המדומה שלך</translation>
<translation id="3366477098757335611">הצגת כרטיסי×</translation>
@@ -817,7 +848,6 @@
<translation id="3587738293690942763">×מצעי</translation>
<translation id="3592413004129370115">Italian (Envelope)‎</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{ניתן ל×פס ×ת הקבוצה מתי שרוצי×. הצטרפות לקבוצה חדשה נמשכת סביב ×™×•× ×חד.}=1{ניתן ל×פס ×ת הקבוצה מתי שרוצי×. הצטרפות לקבוצה חדשה נמשכת סביב ×™×•× ×חד.}two{ניתן ל×פס ×ת הקבוצה מתי שרוצי×. הצטרפות לקבוצה חדשה נמשכת סביב ×™×•×ž×™×™× ({NUM_DAYS}).}many{ניתן ל×פס ×ת הקבוצה מתי שרוצי×. הצטרפות לקבוצה חדשה נמשכת סביב {NUM_DAYS} ימי×.}other{ניתן ל×פס ×ת הקבוצה מתי שרוצי×. הצטרפות לקבוצה חדשה נמשכת סביב {NUM_DAYS} ימי×.}}</translation>
-<translation id="3596012367874587041">הגדרות ×”×פליקציה</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">×”×פליקציה נחסמה על ידי מנהל המערכת</translation>
<translation id="3608932978122581043">כיוון הזנה</translation>
@@ -860,6 +890,7 @@
<translation id="370972442370243704">הפעלת התהליכי×</translation>
<translation id="3711895659073496551">השהיה</translation>
<translation id="3712624925041724820">×ין מספיק רישיונות</translation>
+<translation id="3714633008798122362">יומן ×ינטרנט</translation>
<translation id="3714780639079136834">â€×œ×”פעיל ×ת חבילת הגלישה ×ו ×ת ×”-Wi-Fi</translation>
<translation id="3715597595485130451">â€×”תחברות ל-Wi-Fi</translation>
<translation id="3717027428350673159">â€<ph name="BEGIN_LINK" />לבדוק ×ת תצורת ×”-DNS, חומת ×”×ש ושרת ×”-Proxy<ph name="END_LINK" /></translation>
@@ -921,6 +952,7 @@
<translation id="3906954721959377182">ט×בלט</translation>
<translation id="3909477809443608991">â€<ph name="URL" /> רוצה להציג תוכן מוגן. הזהות של המכשיר שלך ת×ומת על ידי Google ול×תר תהיה גישה ×ליה.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">דחייה</translation>
<translation id="3939773374150895049">â€×”×× ×œ×”×©×ª×ž×© ב-WebAuthn ×‘×ž×§×•× ×‘-CVC?</translation>
<translation id="3946209740501886391">יש לש×ול תמיד ב×תר ×”×–×”</translation>
<translation id="3947595700203588284">â€×”×תר יכול לבקש הרש××” להתחבר ×ל מכשירי MIDI</translation>
@@ -942,6 +974,7 @@
<translation id="3990250421422698716">היסט הלשונית</translation>
<translation id="3996311196211510766">×”×תר <ph name="ORIGIN" /> ביקש להחיל מדיניות מקור
על כל הבקשות הנשלחות ×ליו, ×בל ×œ× × ×™×ª×Ÿ כרגע להחיל ×ת המדיניות הזו.</translation>
+<translation id="4009243425692662128">â€×”תוכן של ×”×“×¤×™× ×”×ž×•×“×¤×¡×™× × ×©×œ×— ל-Google Cloud ×ו ×œ×¦×“×“×™× ×©×œ×™×©×™×™× ×œ×¦×•×¨×š ניתוח. לדוגמה, יכול להיות שהטקסט יעבור סריקה כדי ל×תר מידע ×ישי רגיש.</translation>
<translation id="4010758435855888356">ל×פשר ×ת הגישה ל×חסון?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{â€×ž×¡×ž×š ×”-PDF מכיל דף ×חד ({COUNT})}two{â€×ž×¡×ž×š ×”-PDF מכיל {COUNT} דפי×}many{â€×ž×¡×ž×š ×”-PDF מכיל {COUNT} דפי×}other{â€×ž×¡×ž×š ×”-PDF מכיל {COUNT} דפי×}}</translation>
<translation id="4023431997072828269">שליחת הטופס ×”×–×” מתבצעת דרך חיבור ש×ינו מ×ובטח, לכן המידע שלך ×™×”×™×” גלוי ל×חרי×.</translation>
@@ -1034,6 +1067,7 @@
<translation id="4250680216510889253">ל×</translation>
<translation id="4253168017788158739">הערה</translation>
<translation id="425582637250725228">ייתכן ×©×”×©×™× ×•×™×™× ×©×‘×™×¦×¢×ª ×œ× ×™×™×©×ž×¨×•.</translation>
+<translation id="425869179292622354">רוצה לשפר ×ת ×”×בטחה בעזרת כרטיס וירטו×לי?</translation>
<translation id="4258748452823770588">חתימה שגויה</translation>
<translation id="4261046003697461417">×œ× × ×™×ª×Ÿ להוסיף הערות ×œ×ž×¡×ž×›×™× ×ž×•×’× ×™×</translation>
<translation id="4265872034478892965">×ושרה על-ידי מנהל המערכת</translation>
@@ -1096,6 +1130,7 @@
<translation id="4434045419905280838">חלונות ×§×•×¤×¦×™× ×•×”×¤× ×™×•×ª ×וטומטיות</translation>
<translation id="4435702339979719576">Postcard)‎</translation>
<translation id="443673843213245140">â€×”שימוש בשרת Proxy הושבת, ×ך צוינה תצורת שרת Proxy מפורשת.</translation>
+<translation id="4441832193888514600">המערכת מתעלמת מהמדיניות ×›×™ ניתן להגדיר ×ותה רק כמדיניות משתמש בענן.</translation>
<translation id="4450893287417543264">×ין להציג שוב</translation>
<translation id="4451135742916150903">â€×”×תר יכול לבקש הרש××” להתחבר למכשירי HID</translation>
<translation id="4452328064229197696">â€×”סיסמה שבה השתמשת עכשיו ×ותרה בפרצה ב×בטחת מידע. כדי להגן על החשבונות שלך, לפי מנהל הסיסמ×ות של Google, מומלץ לבדוק ×ת הסיסמ×ות השמורות שלך.</translation>
@@ -1151,6 +1186,7 @@
<translation id="4628948037717959914">תמונה</translation>
<translation id="4631649115723685955">הק×שבק מקושר</translation>
<translation id="4636930964841734540">מידע</translation>
+<translation id="4638670630777875591">â€×ž×¦×‘ פרטי ב-Chromium</translation>
<translation id="464342062220857295">תכונות חיפוש</translation>
<translation id="4644670975240021822">בסדר הפוך ×¢× ×”×¤× ×™× ×›×œ×¤×™ מטה</translation>
<translation id="4646534391647090355">×× ×™ רוצה לעבור ×œ×©× ×¢×›×©×™×•</translation>
@@ -1171,6 +1207,7 @@
<translation id="4708268264240856090">החיבור נקטע</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131">â€<ph name="BEGIN_LINK" />מפעיל ×ת ×בחון הרשת של Windows<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426">הסיסמה של <ph name="USERNAME" /></translation>
<translation id="4724144314178270921">×”×תר יכול לבקש הרש××” לר×ות טקסט ותמונות בלוח העריכה</translation>
<translation id="4726672564094551039">טעינת המדיניות מחדש</translation>
<translation id="4728558894243024398">פלטפורמה</translation>
@@ -1192,6 +1229,7 @@
<translation id="4757993714154412917">â€×”זנת כרגע ×ת הסיסמה שלך ב×תר מטעה. כדי להגן על החשבונות שלך, ההמלצה של Chromium ×”×™× ×œ×‘×“×•×§ ×ת הסיסמ×ות השמורות.</translation>
<translation id="4758311279753947758">הוספת ×¤×¨×˜×™× ×œ×™×¦×™×¨×ª קשר</translation>
<translation id="4761104368405085019">להשתמש במיקרופון</translation>
+<translation id="4761869838909035636">â€×”רצה של בדיקת ×בטחה ב-Chrome</translation>
<translation id="4764776831041365478">ייתכן שדף ×”×ינטרנט בכתובת <ph name="URL" /> ×ינו פעיל זמנית, ×ו שהועבר לכתובת ×ינטרנט חדשה לצמיתות.</translation>
<translation id="4766713847338118463">שתי סיכות הידוק בחלק התחתון</translation>
<translation id="4771973620359291008">â€×ירעה שגי××” ×œ× ×ž×•×›×¨×ª.
@@ -1216,12 +1254,6 @@ Del</translation>
<translation id="4819347708020428563">לערוך ×ת ההערות בתצוגת ברירת מחדל?</translation>
<translation id="4825496307559726072">â€<ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />, ×ž×§×™×©×™× ×¢×œ Tab ו××– על Enter כדי ליצור במהירות גיליון ×לקטרוני חדש ב-Google Sheets</translation>
<translation id="4825507807291741242">עוצמתי</translation>
-<translation id="4827402517081186284">המצב ×”×נונימי ×œ× ×ž×¡×ª×™×¨ ×ותך לגמרי ב×ינטרנט:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />××ª×¨×™× ×™×•×“×¢×™× ×©×‘×™×§×¨×ª בה×<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />×ž×¢×¡×™×§×™× ×•×ž×•×¡×“×•×ª ×œ×™×ž×•×“×™× ×™×›×•×œ×™× ×œ×¢×§×•×‘ ×חר פעילות הגלישה שלך<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />יכול להיות שספקי ×ינטרנט יעקבו ×חר תנועת הגולשי×<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">הפעלת ×”×זהרות</translation>
<translation id="4838327282952368871">חלומי</translation>
<translation id="4840250757394056958">â€×”צגת ההיסטוריה ב-Chrome</translation>
@@ -1233,12 +1265,12 @@ Del</translation>
<translation id="4854362297993841467">שיטת המסירה הזו ××™× ×” זמינה. עליך לבחור שיטה ×חרת.</translation>
<translation id="4854853140771946034">â€×™×¦×™×¨×ª הערה חדשה ב-Google Keep במהירות</translation>
<translation id="485902285759009870">הקוד בתהליך ×ימות…</translation>
+<translation id="4866506163384898554">צריך להקיש על |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| כדי להציג ×ת הסמן</translation>
<translation id="4876188919622883022">תצוגה נקייה</translation>
<translation id="4876305945144899064">×ין ×©× ×ž×©×ª×ž×©</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{×ין}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}many{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831"><ph name="TEXT" /> - חיפוש</translation>
<translation id="4879491255372875719">×וטומטי (ברירת מחדל)</translation>
-<translation id="4879725228911483934">לפתוח ×•×œ×ž×§× ×—×œ×•× ×•×ª ×‘×ž×¡×›×™× ×©×œ×š</translation>
<translation id="4880827082731008257">חיפוש בהיסטוריה</translation>
<translation id="4881695831933465202">פתיחה</translation>
<translation id="4885256590493466218">×ª×©×œ×•× ×‘×§×•×¤×” ×¢× <ph name="CARD_DETAIL" /></translation>
@@ -1247,6 +1279,7 @@ Del</translation>
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">הגליל התשיעי</translation>
<translation id="4901778704868714008">שמירה...</translation>
+<translation id="4905659621780993806">המכשיר יופעל מחדש ב×ופן ×וטומטי על ידי ×”×דמין בשעה <ph name="TIME" /> בת×ריך <ph name="DATE" />. יש לשמור ×¤×¨×™×˜×™× ×¤×ª×•×—×™× ×œ×¤× ×™ ההפעלה מחדש של המכשיר.</translation>
<translation id="4913987521957242411">ניקוב בפינה השמ×לית העליונה</translation>
<translation id="4918221908152712722">התקנת <ph name="APP_NAME" /> (×œ× ×“×¨×•×©×” הורדה)</translation>
<translation id="4923459931733593730">תשלו×</translation>
@@ -1255,6 +1288,7 @@ Del</translation>
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101">â€<ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, יש להקיש על Tab ו××– על Enter כדי לחפש</translation>
<translation id="4930153903256238152">קיבולת גבוהה</translation>
+<translation id="4940163644868678279">â€×ž×¦×‘ פרטי ב-Chrome</translation>
<translation id="4943872375798546930">×ין תוצ×ות</translation>
<translation id="4950898438188848926">â€×œ×—צן החלפת כרטיסיות, יש להקיש על Enter כדי לעבור לכרטיסייה הפתוחה, <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="495170559598752135">פעולות</translation>
@@ -1264,6 +1298,7 @@ Del</translation>
<translation id="4968522289500246572">×”×פליקציה מיועדת לנייד וייתכן ששינוי הגודל שלה ×œ× ×™×¤×¢×œ כר×וי. עשויות להיות בעיות ב×פליקציה ×ו ×©×”×™× ×ª×•×¤×¢×œ מחדש.</translation>
<translation id="4969341057194253438">מחיקת ההקלטה</translation>
<translation id="4973922308112707173">שני × ×™×§×•×‘×™× ×‘×—×œ×§ העליון</translation>
+<translation id="4976702386844183910">הכניסה ×”×חרונה: <ph name="DATE" /></translation>
<translation id="4984088539114770594">להשתמש במיקרופון?</translation>
<translation id="4984339528288761049">Prc5 (Envelope)‎</translation>
<translation id="4989163558385430922">×× ×™ רוצה לר×ות הכול</translation>
@@ -1325,6 +1360,7 @@ Del</translation>
<translation id="5138227688689900538">פחות מידע</translation>
<translation id="5145883236150621069">×§×™×™× ×§×•×“ שגי××” בתגובת המדיניות</translation>
<translation id="5146995429444047494">התר×ות של <ph name="ORIGIN" /> נחסמו</translation>
+<translation id="514704532284964975">â€× ×©×œ×—×” בקשה מהכתובת <ph name="URL" /> לר×ות ולשנות מידע במכשירי NFC בזמן ההקשה בטלפון</translation>
<translation id="5148809049217731050">×¤× ×™× ×›×œ×¤×™ מעלה</translation>
<translation id="515292512908731282">C4 (Envelope)‎</translation>
<translation id="5158275234811857234">שער</translation>
@@ -1349,6 +1385,7 @@ Del</translation>
<translation id="5215116848420601511">â€×מצעי ×ª×©×œ×•× ×•×›×ª×•×‘×•×ª שנשמרו ב-Google Pay</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">מגש 13</translation>
+<translation id="5216942107514965959">הכניסה ×”×חרונה בוצעה היו×</translation>
<translation id="5222812217790122047">×ימייל (חובה)</translation>
<translation id="5230733896359313003">כתובת למשלוח</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1369,7 +1406,6 @@ Del</translation>
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">מ×פייני המסמך</translation>
<translation id="528468243742722775">סיו×</translation>
-<translation id="5284909709419567258">כתובות רשת</translation>
<translation id="5285570108065881030">הצגת כל הסיסמ×ות השמורות</translation>
<translation id="5287240709317226393">â€×”צגת קובצי Cookie</translation>
<translation id="5287456746628258573">×”×תר ×”×–×” משתמש בהגדרת ×בטחה מיושנת, שעלולה לחשוף ×ת המידע שלך (למשל, סיסמ×ות ×ו ×ž×¡×¤×¨×™× ×©×œ כרטיס ×שר××™) ×›×©×”×•× × ×©×œ×— ל×תר ×–×”.</translation>
@@ -1454,6 +1490,7 @@ Del</translation>
<translation id="5556459405103347317">טעינה מחדש</translation>
<translation id="5560088892362098740">ת×ריך תפוגה</translation>
<translation id="55635442646131152">ר×שי ×”×¤×¨×§×™× ×©×œ המסמך</translation>
+<translation id="5565613213060953222">פתיחת כרטיסייה פרטית</translation>
<translation id="5565735124758917034">פעילה</translation>
<translation id="5570825185877910964">הגנה על החשבון</translation>
<translation id="5571083550517324815">×œ× × ×™×ª×Ÿ לבצע ×יסוף מהכתובת הזו. עליך לבחור כתובת ×חרת.</translation>
@@ -1536,6 +1573,7 @@ Del</translation>
<translation id="5869522115854928033">סיסמ×ות שמורות</translation>
<translation id="5873013647450402046">הבנק שלך רוצה ל×מת ×ת זהותך.</translation>
<translation id="5887400589839399685">הכרטיס נשמר</translation>
+<translation id="5887687176710214216">הכניסה ×”×חרונה בוצעה ×תמול</translation>
<translation id="5895138241574237353">הפעלה מחדש</translation>
<translation id="5895187275912066135">הונפק בת×ריך</translation>
<translation id="5901630391730855834">צהוב</translation>
@@ -1549,6 +1587,7 @@ Del</translation>
<translation id="5921639886840618607">â€×œ×©×ž×•×¨ ×ת הכרטיס בחשבון Google?</translation>
<translation id="5922853866070715753">עוד רגע מסיימי×</translation>
<translation id="5932224571077948991">ב×תר מוצגות מודעות מפריעות ×ו מטעות</translation>
+<translation id="5938153366081463283">הוספת כרטיס וירטו×לי</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347">פתיחה של <ph name="SITE_NAME" />…</translation>
<translation id="5951495562196540101">××™ ×פשר ×œ×”×™×¨×©× ×‘×מצעות חשבון פרטי (יש רישיון משויך זמין).</translation>
@@ -1613,6 +1652,7 @@ Del</translation>
<translation id="6120179357481664955">â€×ž×–×”×” UPI שלך זכור לך?</translation>
<translation id="6124432979022149706">â€×ž×—×‘×¨×™× ×©×œ Chrome Enterprise</translation>
<translation id="6127379762771434464">הפריט הוסר</translation>
+<translation id="6132161237766805930">â€<ph name="BEGIN_LINK" />מידע נוסף על מצב פרטי ב-Chrome<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">יש לבדוק ×ת ×”×›×‘×œ×™× ×•×œ×”×¤×¢×™×œ מחדש ×ת הנתבי×, ×”×ž×•×“×ž×™× ×•×©×ר התקני הרשת
×©×ž×©×ª×ž×©×™× ×‘×”×.</translation>
<translation id="614940544461990577">כד××™ לנסות:</translation>
@@ -1625,7 +1665,6 @@ Del</translation>
<translation id="6169916984152623906">עכשיו ב×פשרותך לגלוש ב×ופן פרטי, ו×× ×©×™× ××—×¨×™× ×©×ž×©×ª×ž×©×™× ×‘×ž×›×©×™×¨ ×”×–×” ×œ× ×™×¨×ו ×ת הפעילות שלך. ×¢× ×–×ת, עדיין תתבצע שמירה של הורדות וסימניות.</translation>
<translation id="6177128806592000436">החיבור שלך ל×תר ×”×–×” ×œ× ×ž×ובטח</translation>
<translation id="6180316780098470077">מרווח בין ניסיונות חוזרי×</translation>
-<translation id="619448280891863779">×”×תר יכול לבקש הרש××” לפתוח ×•×œ×ž×§× ×—×œ×•× ×•×ª ×‘×ž×¡×›×™× ×©×œ×š</translation>
<translation id="6196640612572343990">â€×—סימת קובצי Cookie של צד שלישי</translation>
<translation id="6203231073485539293">בדיקת חיבור ×”×ינטרנט</translation>
<translation id="6218753634732582820">â€×”×× ×œ×”×¡×™×¨ מ-Chromium ×ת הכתובת?</translation>
@@ -1648,7 +1687,7 @@ Del</translation>
<translation id="6272383483618007430">â€×¢×“כוני Google</translation>
<translation id="6276112860590028508">×“×¤×™× ×ž×¨×©×™×ž×ª הקרי××” שלך ×ž×•×¤×™×¢×™× ×›×ן</translation>
<translation id="627746635834430766">â€×›×“×™ ×œ×©×œ× ×ž×”×¨ יותר ×‘×¤×¢× ×”×‘××”, ×פשר לשמור בחשבון Google ×ת פרטי הכרטיס ו×ת הכתובת לחיוב.</translation>
-<translation id="6279098320682980337">מספר הכרטיס הווירטו×לי ×œ× ×”×•×–×Ÿ? ×œ×•×—×¦×™× ×¢×œ פרטי הכרטיס כדי להעתיק</translation>
+<translation id="6279183038361895380">יש להקיש על |<ph name="ACCELERATOR" />| כדי להציג ×ת הסמן</translation>
<translation id="6280223929691119688">×œ× × ×™×ª×Ÿ לבצע מסירה בכתובת זו. עליך לבחור כתובת ×חרת.</translation>
<translation id="6282194474023008486">מיקוד</translation>
<translation id="6285507000506177184">â€×”לחצן לניהול הורדות ב-Chrome, ×ž×§×™×©×™× ×¢×œ Enter לניהול ×”×§×‘×¦×™× ×©×”×•×¨×“×ª ב-Chrome</translation>
@@ -1656,6 +1695,7 @@ Del</translation>
<translation id="6290238015253830360">הצעות של מ××ž×¨×™× ×¢×‘×•×¨×š מופיעות ×›×ן</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{המכשיר יופעל מחדש עכשיו}=1{המכשיר יופעל מחדש בתוך שנייה}two{המכשיר יופעל מחדש בתוך # שניות}many{המכשיר יופעל מחדש בתוך # שניות}other{המכשיר יופעל מחדש בתוך # שניות}}</translation>
<translation id="6302269476990306341">â€Google Assistant מופסקת ב-Chrome</translation>
<translation id="6305205051461490394">×œ× × ×™×ª×Ÿ לגשת ×ל <ph name="URL" />.</translation>
<translation id="6312113039770857350">דף ×”×ינטרנט ×ינו זמין</translation>
@@ -1729,6 +1769,7 @@ Del</translation>
<translation id="6529602333819889595">&amp;ביצוע מחדש של מחיקה</translation>
<translation id="6545864417968258051">â€×¡×¨×™×§×ª Bluetooth</translation>
<translation id="6547208576736763147">שני × ×™×§×•×‘×™× ×‘×¦×“ שמ×ל</translation>
+<translation id="6554732001434021288">הביקור ×”×חרון התבצע לפני <ph name="NUM_DAYS" /> ימי×</translation>
<translation id="6556866813142980365">ביצוע מחדש</translation>
<translation id="6569060085658103619">זהו דף של תוסף</translation>
<translation id="6573200754375280815">שני × ×™×§×•×‘×™× ×‘×¦×“ ימין</translation>
@@ -1789,7 +1830,6 @@ Del</translation>
<translation id="6757797048963528358">המכשיר עבר למצב שינה.</translation>
<translation id="6767985426384634228">לעדכן ×ת הכתובת?</translation>
<translation id="6768213884286397650">Hagaki (Postcard)‎</translation>
-<translation id="6774185088257932239"><ph name="BEGIN_LINK" />מידע נוסף<ph name="END_LINK" /> על המצב ×”×נונימי</translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">סגול סיגלית</translation>
<translation id="6786747875388722282">תוספי×</translation>
@@ -1873,7 +1913,6 @@ Del</translation>
<translation id="706295145388601875">â€× ×™×ª×Ÿ להוסיף ולנהל כתובות בהגדרות Chrome</translation>
<translation id="7064851114919012435">×¤×¨×˜×™× ×œ×™×¦×™×¨×ª קשר</translation>
<translation id="7068733155164172741">יש להזין קוד בן <ph name="OTP_LENGTH" /> ספרות</translation>
-<translation id="7070090581017165256">מידע על ×”×תר ×”×–×”</translation>
<translation id="70705239631109039">החיבור שלך ×œ× ×ž×ובטח לחלוטין</translation>
<translation id="7075452647191940183">הבקשה גדולה מדי</translation>
<translation id="7079718277001814089">×”×תר ×”×–×” מכיל תוכנה זדונית</translation>
@@ -1890,6 +1929,12 @@ Del</translation>
<translation id="7111012039238467737">(חוקי)</translation>
<translation id="7118618213916969306">â€×—יפוש כתובת ×”-URL שהועתקה ללוח, <ph name="SHORT_URL" /></translation>
<translation id="7119414471315195487">סגירת כרטיסיות ×ו תוכניות ×חרות</translation>
+<translation id="7129355289156517987">â€×¢× הסגירה של כל הכרטיסיות הפרטיות ב-Chromium, הפעילות שלך בכרטיסיות הב×ות נמחקת מהמכשיר ×”×–×”:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />פעילות הגלישה<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />היסטוריית החיפושי×<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />מידע שהוזן בטפסי×<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">×œ× × ×™×ª×Ÿ לבצע משלוח לכתובת הזו. עליך לבחור כתובת ×חרת.</translation>
<translation id="7132939140423847331">מנהל המערכת שלך ×סר על העתקת ×”× ×ª×•× ×™× ×”×לה.</translation>
<translation id="7135130955892390533">הצגת סטטוס</translation>
@@ -1912,6 +1957,7 @@ Del</translation>
<translation id="7192203810768312527">פינוי של <ph name="SIZE" /> מהנפח. תיתכן טעינה ×יטית יותר של ××ª×¨×™× ×ž×¡×•×™×ž×™× ×‘×‘×™×§×•×¨ ×”×‘× ×©×œ×š.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">מנהל המערכת יכול לר×ות:</translation>
+<translation id="7202217080450895452">â€<ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, יש להקיש על Tab ו××– על Enter כדי לפתוח כרטיסייה פרטית חדשה לגלישה ב×ופן פרטי</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> ×œ× ×¤×•×¢×œ בהת×× ×œ×ª×§× ×™ ×”×בטחה.</translation>
<translation id="7210993021468939304">â€×§×™×™×ž×ª פעילות של Linux בתוך המ×גר וניתן להתקין ולהפעיל ×פליקציות של Linux בתוך המ×גר</translation>
@@ -1943,6 +1989,7 @@ Del</translation>
<translation id="7304562222803846232">â€× ×™×”ול הגדרות הפרטיות בחשבון Google</translation>
<translation id="7305756307268530424">התחלה ×יטית יותר</translation>
<translation id="7308436126008021607">סנכרון ברקע</translation>
+<translation id="7310392214323165548">המכשיר יופעל מחדש בקרוב</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">עזרה בחיבור</translation>
<translation id="7323804146520582233">הסתרת הקטע "<ph name="SECTION" />"</translation>
@@ -1950,6 +1997,7 @@ Del</translation>
<translation id="7334320624316649418">&amp;ביצוע מחדש של שינוי סדר</translation>
<translation id="7335157162773372339">×”×תר יכול לבקש הרש××” להשתמש במצלמה</translation>
<translation id="7337248890521463931">×× ×™ רוצה לר×ות יותר שורות</translation>
+<translation id="7337418456231055214">מספר הכרטיס הווירטו×לי ×œ× ×”×•×–×Ÿ? ×œ×•×—×¦×™× ×¢×œ פרטי הכרטיס כדי להעתיק. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">×œ× ×–×ž×™×Ÿ בפלטפורמה שלך.</translation>
<translation id="733923710415886693">×ישור השרת ×œ× × ×—×©×£ דרך 'שקיפות ×ישורי×'.</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1972,6 +2020,7 @@ Del</translation>
<translation id="7378627244592794276">ל×</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">×œ× ×¨×œ×•×•× ×˜×™</translation>
+<translation id="7388594495505979117">{0,plural, =1{המכשיר יופעל מחדש בתוך דקה}two{המכשיר יופעל מחדש בתוך # דקות}many{המכשיר יופעל מחדש בתוך # דקות}other{המכשיר יופעל מחדש בתוך # דקות}}</translation>
<translation id="7390545607259442187">×ישור הכרטיס</translation>
<translation id="7392089738299859607">עדכון הכתובת</translation>
<translation id="7399802613464275309">בדיקת ×בטחה</translation>
@@ -2008,6 +2057,12 @@ Del</translation>
<translation id="7485870689360869515">×œ× × ×ž×¦×ו נתוני×.</translation>
<translation id="7495528107193238112">התוכן ×”×–×” חסו×. יש לפנות ×ל ×”×‘×¢×œ×™× ×©×œ ×”×תר כדי לפתור ×ת הבעיה.</translation>
<translation id="7497998058912824456">â€×œ×—צן ליצירת מסמך, ×ž×§×™×©×™× ×¢×œ Enter כדי ליצור במהירות מסמך ב-Google Docs</translation>
+<translation id="7506488012654002225">â€Chromium <ph name="BEGIN_EMPHASIS" />×œ× ×™×©×ž×•×¨<ph name="END_EMPHASIS" /> ×ת המידע הב×:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />היסטוריית הגלישה שלך
+ <ph name="LIST_ITEM" />קובצי Cookie ונתוני ×תרי×
+ <ph name="LIST_ITEM" />מידע שהוזן בטפסי×
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">מזהה המכשיר במדיניות שהוחזר ריק ×ו ש×ינו תו×× ×ת מזהה המכשיר הנוכחי</translation>
<translation id="7508870219247277067">ירוק ×בוקדו</translation>
<translation id="7511955381719512146">â€×™×™×ª×›×Ÿ שהשימוש ברשת ×”-Wi-Fi ידרוש ממך להיכנס ל-<ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
@@ -2121,7 +2176,6 @@ Del</translation>
<translation id="7813600968533626083">â€×”×× ×œ×”×¡×™×¨ מ-Chrome הצעות בשביל טפסי×?</translation>
<translation id="781440967107097262">לשתף ×ת הלוח?</translation>
<translation id="7815407501681723534">נמצ×ו <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> ×‘× ×•×©× '<ph name="SEARCH_STRING" />'</translation>
-<translation id="782125616001965242">הצגת מידע על ×”×תר ×”×–×”</translation>
<translation id="782886543891417279">â€×™×™×ª×›×Ÿ שרשת ×”-Wi-Fi דורשת כניסה לדף ההתחברות שלה. (<ph name="WIFI_NAME" />).</translation>
<translation id="7836231406687464395">Postfix (Envelope)‎</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{לל×}=1{×פליקציה ×חת (<ph name="EXAMPLE_APP_1" />)}=2{2 ×פליקציות (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}many{# ×פליקציות (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" /> <ph name="AND_MORE" />)}other{# ×פליקציות (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" /> <ph name="AND_MORE" />)}}</translation>
@@ -2138,7 +2192,6 @@ Del</translation>
<translation id="7888575728750733395">â€Rendering Intent בהדפסה</translation>
<translation id="7894280532028510793">×× ×”×יות תקין, <ph name="BEGIN_LINK" />יש לנסות להפעיל ×ת ×בחון הרשת<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (Envelope)‎</translation>
-<translation id="7931318309563332511">×œ× ×™×“×•×¢</translation>
<translation id="793209273132572360">לעדכן ×ת הכתובת?</translation>
<translation id="7932579305932748336">ציפוי</translation>
<translation id="79338296614623784">עליך להזין מספר טלפון חוקי</translation>
@@ -2163,13 +2216,14 @@ Del</translation>
<translation id="7976214039405368314">יותר מדי בקשות</translation>
<translation id="7977538094055660992">מכשיר פלט</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">יש קישור ×ל</translation>
<translation id="798134797138789862">×”×תר יכול לבקש הרש××” להשתמש ×‘× ×ª×•× ×™× ×•×‘×ž×›×©×™×¨×™× ×©×œ מצי×ות מדומה</translation>
<translation id="7984945080620862648">â€×œ× ניתן לבקר כעת ב×תר <ph name="SITE" /> מכיוון שה×תר שלח ××™×©×•×¨×™× ×ž×©×•×‘×©×™× ×©-Chrome ×ינו יכול לעבד. שגי×ות רשת ותקיפות מתרחשות בדרך כלל לזמן מוגבל, כך שסביר להניח שדף ×–×” יפעל מ×וחר יותר.</translation>
-<translation id="79859296434321399">â€×›×“×™ להציג תוכן של מצי×ות רבודה, צריך להתקין ×ת ARCore</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">כריכה</translation>
<translation id="7992044431894087211">שיתוף המסך ב×מצעות <ph name="APPLICATION_TITLE" /> ממשיך</translation>
<translation id="7995512525968007366">×œ× ×¦×•×™×Ÿ</translation>
+<translation id="7998269595945679889">â€×œ×—צן לפתיחת כרטיסייה פרטית, צריך להקיש על Enter כדי לפתוח כרטיסייה פרטית חדשה ולגלוש ב×ופן פרטי</translation>
<translation id="800218591365569300">מומלץ לסגור כרטיסיות ×ו תוכניות ×חרות וכך לפנות ×ž×§×•× ×‘×–×™×›×¨×•×Ÿ.</translation>
<translation id="8004582292198964060">דפדפן</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{הכרטיס ×”×–×” יישמר יחד ×¢× ×”×›×ª×•×‘×ª שלו לחיוב. ית×פשר לך להשתמש בו ל×חר התחברות ×ל <ph name="USER_EMAIL" />.}two{×”×›×¨×˜×™×¡×™× ×”×לה יישמרו יחד ×¢× ×”×›×ª×•×‘×•×ª ×©×œ×”× ×œ×—×™×•×‘. ית×פשר לך להשתמש ×‘×”× ×œ×חר התחברות ×ל <ph name="USER_EMAIL" />.}many{×”×›×¨×˜×™×¡×™× ×”×לה יישמרו יחד ×¢× ×”×›×ª×•×‘×•×ª ×©×œ×”× ×œ×—×™×•×‘. ית×פשר לך להשתמש ×‘×”× ×œ×חר התחברות ×ל <ph name="USER_EMAIL" />.}other{×”×›×¨×˜×™×¡×™× ×”×לה יישמרו יחד ×¢× ×”×›×ª×•×‘×•×ª ×©×œ×”× ×œ×—×™×•×‘. ית×פשר לך להשתמש ×‘×”× ×œ×חר התחברות ×ל <ph name="USER_EMAIL" />.}}</translation>
@@ -2229,6 +2283,7 @@ Del</translation>
<translation id="8202370299023114387">התנגשות</translation>
<translation id="8206978196348664717">Prc4 (Envelope)‎</translation>
<translation id="8211406090763984747">החיבור מ×ובטח</translation>
+<translation id="8217240300496046857">â€××ª×¨×™× ×œ× ×™×›×•×œ×™× ×œ×”×©×ª×ž×© בקובצי cookie ×©×¢×•×§×‘×™× ×חריך ב×ינטרנט. ייתכן שתכונות ב××ª×¨×™× ×ž×¡×•×™×ž×™× ×œ× ×™×¤×¢×œ×• כר×וי.</translation>
<translation id="8218327578424803826">×ž×™×§×•× ×ž×•×§×¦×”:</translation>
<translation id="8220146938470311105">C7/C6 (Envelope)‎</translation>
<translation id="8225771182978767009">המשתמש שהגדיר ×ת המחשב ×”×–×” בחר ×œ×—×¡×•× ×ת ×”×תר ×”×–×”.</translation>
@@ -2269,14 +2324,9 @@ Del</translation>
<translation id="830498451218851433">קיפול ב×מצע</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">×ת ×”×פליקציות המותקנות ו×ת תדירות השימוש בהן.</translation>
+<translation id="8317207217658302555">â€×œ×¢×“כן ×ת ARCore?</translation>
<translation id="831997045666694187">ערב</translation>
<translation id="8321476692217554900">התר×ות</translation>
-<translation id="8328484624016508118">â€×חרי ×©×¡×•×’×¨×™× ×ת כל הכרטיסיות במצב ×נונימי, יימחקו בדפדפן Chrome:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />פעילות הגלישה מהמכשיר הזה<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />היסטוריית ×”×—×™×¤×•×©×™× ×©×œ×š מהמכשיר ×”×–×”<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />המידע שהוזן בטפסי×<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489">×ין גישה ×ל <ph name="HOST_NAME" /></translation>
<translation id="833262891116910667">הדגשה</translation>
<translation id="8339163506404995330">×“×¤×™× ×‘<ph name="LANGUAGE" /> ×œ× ×™×ª×•×¨×’×ž×•</translation>
@@ -2328,6 +2378,7 @@ Del</translation>
<translation id="8507227106804027148">שורת פקודה</translation>
<translation id="8508648098325802031">סמל החיפוש</translation>
<translation id="8511402995811232419">â€× ×™×”ול קובצי Cookie</translation>
+<translation id="8519753333133776369">â€×ž×›×©×™×¨ HID ש×ושר על ידי ×”×דמין</translation>
<translation id="8522552481199248698">â€×‘עזרת Chrome ×פשר להגן על חשבון Google ולשנות ×ת הסיסמה.</translation>
<translation id="8530813470445476232">â€×‘הגדרות Chrome, ניתן לנקות ×ת היסטוריית הגלישה, ×ת קובצי ×”-cookie, ×ת המטמון ועוד</translation>
<translation id="8533619373899488139">â€×‘כתובת &lt;strong&gt;chrome://policy&lt;/strong&gt; מוצגת רשימה של כתובות ××ª×¨×™× ×©× ×—×¡×ž×• ×•×ª×§× ×•× ×™× ××—×¨×™× ×©× ××›×¤×™× ×¢×œ ידי מנהל המערכת.</translation>
@@ -2339,7 +2390,6 @@ Del</translation>
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{×יפוס ההרש××”}two{×יפוס ההרש×ות}many{×יפוס ההרש×ות}other{×יפוס ההרש×ות}}</translation>
<translation id="8555010941760982128">צריך להזין ×ת הקוד ×”×–×” בקופה</translation>
<translation id="8557066899867184262">קוד ×”×ימות × ×ž×¦× ×‘×’×‘ הכרטיס.</translation>
-<translation id="8558485628462305855">â€×›×“×™ להציג תוכן של מצי×ות רבודה, צריך לעדכן ×ת ARCore</translation>
<translation id="8559762987265718583">×œ× × ×™×ª×Ÿ ליצור חיבור פרטי ×ל <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> מפני שהת×ריך והשעה (<ph name="DATE_AND_TIME" />) במכשיר שלך שגויי×.</translation>
<translation id="8564182942834072828">×ž×¡×ž×›×™× × ×¤×¨×“×™×/×¢×•×ª×§×™× ×œ× ×ž×¡×•×“×¨×™×</translation>
<translation id="8564985650692024650">â€×× ×”×–× ×ª ×ת הסיסמה של <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> ב××ª×¨×™× ×חרי×, ההמלצה של Chromium ×”×™× ×œ×פס ×ותה.</translation>
@@ -2358,6 +2408,7 @@ Del</translation>
<translation id="865032292777205197">חיישני תנועה</translation>
<translation id="8663226718884576429">×¡×™×›×•× ×”×–×ž× ×”, <ph name="TOTAL_LABEL" />, ×¤×¨×˜×™× × ×•×¡×¤×™×</translation>
<translation id="8666678546361132282">×נגלית</translation>
+<translation id="8669306706049782872">להשתמש במידע לגבי ×”×ž×¡×›×™× ×©×œ×š כדי לפתוח ולהציב חלונות</translation>
<translation id="867224526087042813">חתימה</translation>
<translation id="8676424191133491403">×œ×œ× ×¢×™×›×•×‘</translation>
<translation id="8680536109547170164"><ph name="QUERY" /> , תשובה, <ph name="ANSWER" /></translation>
@@ -2384,6 +2435,7 @@ Del</translation>
<translation id="8731544501227493793">â€×”לחצן 'ניהול סיסמ×ות', יש להקיש על Enter כדי להציג ולנהל ×ת הסיסמ×ות בהגדרות Chrome</translation>
<translation id="8734529307927223492">ה-<ph name="DEVICE_TYPE" /> מנוהל על-ידי <ph name="MANAGER" /></translation>
<translation id="8737134861345396036">â€<ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, יש להקיש על Tab ו××– על Enter כדי לפתוח חלון ×נונימי חדש לגלישה פרטית</translation>
+<translation id="8737685506611670901">פתיחת קישורי <ph name="PROTOCOL" /> ×‘×ž×§×•× <ph name="REPLACED_HANDLER_TITLE" /></translation>
<translation id="8738058698779197622">â€×›×“×™ ליצור חיבור מ×ובטח, השעון צריך להיות מוגדר כהלכה. הסיבה לכך ×”×™× ×©×”××™×©×•×¨×™× ×©×‘×”× ××ª×¨×™× ×ž×©×ª×ž×©×™× ×›×“×™ לזהות ×ת ×¢×¦×ž× ×ª×§×¤×™× ×¨×§ למשך פרקי זמן מסוימי×. מ×חר שהשעון במכשיר שלך שגוי, Chromium ×œ× ×™×›×•×œ ל×מת ×ת ×”××™×©×•×¨×™× ×”×לו.</translation>
<translation id="8740359287975076522">â€×œ× ניתן ×”×™×” ×œ×ž×¦×•× ×ת &lt;abbr id="dnsDefinition"&gt;כתובת ×”-DNS&lt;/abbr&gt; של <ph name="HOST_NAME" />. מ×בחן ×ת הבעיה.</translation>
<translation id="8742371904523228557"><ph name="ONE_TIME_CODE" /> ×”×•× ×”×§×•×“ שלך בשביל <ph name="ORIGIN" /></translation>
@@ -2411,6 +2463,7 @@ Del</translation>
<translation id="883848425547221593">סימניות ×חרות</translation>
<translation id="884264119367021077">כתובת למשלוח</translation>
<translation id="884923133447025588">×œ× × ×ž×¦× ×ž× ×’× ×•×Ÿ ביטול</translation>
+<translation id="8849262850971482943">כדי להגביר ×ת רמת ×”×בטחה, יש להשתמש בכרטיס וירטו×לי</translation>
<translation id="885730110891505394">â€×©×™×ª×•×£ ×¢× Google</translation>
<translation id="8858065207712248076">â€×× ×”×–× ×ª ×ת הסיסמה של <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> ב××ª×¨×™× ×חרי×, ההמלצה של Chrome ×”×™× ×œ×פס ×ותה.</translation>
<translation id="885906927438988819">â€×× ×”×יות תקין, <ph name="BEGIN_LINK" />יש לנסות להפעיל ×ת ×בחון הרשת של Windows<ph name="END_LINK" />.</translation>
@@ -2460,6 +2513,7 @@ Del</translation>
<translation id="9004367719664099443">â€×™×© עכשיו סשן VR פעיל</translation>
<translation id="9005998258318286617">â€×”טעינה של מסמך ×”-PDF נכשלה.</translation>
<translation id="9008201768610948239">סגירה</translation>
+<translation id="901834265349196618">×ימייל</translation>
<translation id="9020200922353704812">יש להזין ×ת הכתובת לחיוב של הכרטיס</translation>
<translation id="9020542370529661692">הדף ×”×–×” ×ª×•×¨×’× ×œ<ph name="TARGET_LANGUAGE" /></translation>
<translation id="9020742383383852663">A8</translation>
@@ -2508,6 +2562,7 @@ Del</translation>
<translation id="9150045010208374699">להשתמש במצלמה</translation>
<translation id="9150685862434908345">â€×ž× ×”ל המערכת יכול לשנות ×ת הגדרת הדפדפן שלך מרחוק. בנוסף, ניתן לנהל ×ת הפעילות במכשיר ×”×–×” מחוץ ל-Chrome. <ph name="BEGIN_LINK" />מידע נוסף<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">עודכן</translation>
+<translation id="9155211586651734179">ציוד ×”×ודיו הההיקפי מחובר</translation>
<translation id="9157595877708044936">ההגדרה מתבצעת...</translation>
<translation id="9158625974267017556">C6 (Envelope)‎</translation>
<translation id="9164029392738894042">בדיקת דיוק</translation>
diff --git a/chromium/components/strings/components_strings_ja.xtb b/chromium/components/strings/components_strings_ja.xtb
index 6125aefac42..6da3e414894 100644
--- a/chromium/components/strings/components_strings_ja.xtb
+++ b/chromium/components/strings/components_strings_ja.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">詳細を表示</translation>
<translation id="1030706264415084469"><ph name="URL" /> ã‹ã‚‰ã€ãƒ‡ãƒã‚¤ã‚¹ã«å¤§ããªãƒ‡ãƒ¼ã‚¿ã‚’永続的ã«ä¿å­˜ã™ã‚‹è¨±å¯ã‚’求ã‚られã¦ã„ã¾ã™</translation>
<translation id="1032854598605920125">時計回りã«å›žè»¢</translation>
+<translation id="1033329911862281889">シークレット モードを使用ã—ã¦ã‚‚ã€ã‚ªãƒ³ãƒ©ã‚¤ãƒ³ä¸Šã«ã¾ã£ãŸã記録ãŒæ®‹ã‚‰ãªã„ã‚ã‘ã§ã¯ã‚ã‚Šã¾ã›ã‚“。
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />利用ã—ãŸã‚µã‚¤ãƒˆã‚„サービスã«ã¯ã‚¢ã‚¯ã‚»ã‚¹ã—ãŸã“ã¨ãŒçŸ¥ã‚‰ã‚Œã‚‹å ´åˆãŒã‚ã‚Šã¾ã™<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />雇用主や教育機関ãŒé–²è¦§ã‚¢ã‚¯ãƒ†ã‚£ãƒ“ティを追跡ã—ã¦ã„ã‚‹å ´åˆãŒã‚ã‚Šã¾ã™<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />インターãƒãƒƒãƒˆ サービス プロãƒã‚¤ãƒ€ãŒã‚¦ã‚§ãƒ– トラフィックを監視ã—ã¦ã„ã‚‹å ´åˆãŒã‚ã‚Šã¾ã™<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">オフã«ã™ã‚‹</translation>
<translation id="1036982837258183574">全画é¢è¡¨ç¤ºã‚’終了ã™ã‚‹ã«ã¯ |<ph name="ACCELERATOR" />| を押ã—ã¾ã™</translation>
<translation id="1038106730571050514">候補を表示ã™ã‚‹</translation>
<translation id="1038842779957582377">ä¸æ˜Žãªåå‰</translation>
<translation id="1041998700806130099">ジョブシート メッセージ</translation>
<translation id="1048785276086539861">メモを編集ã™ã‚‹ã¨ã€ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆã¯å˜ä¸€ãƒšãƒ¼ã‚¸è¡¨ç¤ºã«æˆ»ã‚Šã¾ã™</translation>
-<translation id="1049743911850919806">シークレット モード</translation>
<translation id="1050038467049342496">ä»–ã®ã‚¢ãƒ—リを終了ã™ã‚‹</translation>
<translation id="1055184225775184556">追加ã®å–り消ã—(&amp;U)</translation>
<translation id="1056898198331236512">警告</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">ãƒãƒªã‚·ãƒ¼ キャッシュã¯æ­£å¸¸ã§ã™</translation>
<translation id="1130564665089811311">ページを翻訳ã™ã‚‹ãƒœã‚¿ãƒ³ã§ã™ã€‚Enter キーを押ã™ã¨ Google 翻訳を使用ã—ã¦ã“ã®ãƒšãƒ¼ã‚¸ã‚’翻訳ã—ã¾ã™</translation>
<translation id="1131264053432022307">コピーã—ãŸç”»åƒ</translation>
+<translation id="1142846828089312304">シークレット モードã§ã‚µãƒ¼ãƒ‰ãƒ‘ーティ㮠Cookie をブロックã™ã‚‹</translation>
<translation id="1150979032973867961">ã“ã®ã‚µãƒ¼ãƒãƒ¼ãŒ <ph name="DOMAIN" /> ã§ã‚ã‚‹ã“ã¨ã‚’確èªã§ãã¾ã›ã‚“ã§ã—ãŸã€‚ã“ã®ã‚µãƒ¼ãƒãƒ¼ã®ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£è¨¼æ˜Žæ›¸ã¯ã€ã”使用ã®ãƒ‘ソコンã®ã‚ªãƒšãƒ¬ãƒ¼ãƒ†ã‚£ãƒ³ã‚° システムã«ã‚ˆã£ã¦ä¿¡é ¼ã•ã‚Œã¦ã„ã‚‹ã‚‚ã®ã§ã¯ã‚ã‚Šã¾ã›ã‚“。原因ã¨ã—ã¦ã¯ã€ä¸é©åˆ‡ãªè¨­å®šã‚„ã€æ‚ªæ„ã®ã‚るユーザーã«ã‚ˆã‚‹æŽ¥ç¶šå¦¨å®³ãŒè€ƒãˆã‚‰ã‚Œã¾ã™ã€‚</translation>
<translation id="1151972924205500581">パスワードを入力ã—ã¦ãã ã•ã„</translation>
<translation id="1156303062776767266">ローカル ファイルã¾ãŸã¯å…±æœ‰ãƒ•ã‚¡ã‚¤ãƒ«ã‚’表示ã—ã¦ã„ã¾ã™</translation>
@@ -64,7 +70,6 @@
<translation id="1178581264944972037">一時åœæ­¢</translation>
<translation id="1181037720776840403">削除</translation>
<translation id="1186201132766001848">パスワードを確èª</translation>
-<translation id="1195210374336998651">アプリã®è¨­å®šã«ç§»å‹•</translation>
<translation id="1195558154361252544">許å¯ã—ãŸã‚µã‚¤ãƒˆã‚’除ãã™ã¹ã¦ã®ã‚µã‚¤ãƒˆã§é€šçŸ¥ã‚’自動的ã«ãƒ–ロックã—ã¾ã™</translation>
<translation id="1197088940767939838">オレンジ</translation>
<translation id="1201402288615127009">次ã¸</translation>
@@ -111,7 +116,7 @@
<translation id="1307966114820526988">サãƒãƒ¼ãƒˆçµ‚了ã®æ©Ÿèƒ½</translation>
<translation id="1308113895091915999">使用å¯èƒ½ãªã‚¯ãƒ¼ãƒãƒ³</translation>
<translation id="1312803275555673949">ãれを支æŒã™ã‚‹è¨¼æ‹ ã¯ä½•ã§ã™ã‹ï¼Ÿ</translation>
-<translation id="131405271941274527"><ph name="URL" /> ãŒã€NFC æ­è¼‰ã®ã‚¹ãƒžãƒ¼ãƒˆãƒ•ã‚©ãƒ³ã‚’タップã—ã¦æƒ…報をé€å—ä¿¡ã™ã‚‹ã‚ˆã†æ±‚ã‚ã¦ã„ã¾ã™</translation>
+<translation id="1314311879718644478">æ‹¡å¼µç¾å®Ÿã‚³ãƒ³ãƒ†ãƒ³ãƒ„を表示ã—ã¾ã™</translation>
<translation id="1314509827145471431">製本(å³ç¶´ã˜ï¼‰</translation>
<translation id="1318023360584041678">タブグループã«ä¿å­˜æ¸ˆã¿</translation>
<translation id="1319245136674974084">ã“ã®ã‚¢ãƒ—リã§ã¯æ¬¡å›žã‹ã‚‰è¡¨ç¤ºã—ãªã„</translation>
@@ -161,6 +166,7 @@
<translation id="142858679511221695">クラウド ユーザー</translation>
<translation id="1428729058023778569">ã“ã®è­¦å‘Šã¯ã€ã‚µã‚¤ãƒˆãŒ HTTPS ã«å¯¾å¿œã—ã¦ã„ãªã„å ´åˆã«è¡¨ç¤ºã•ã‚Œã¾ã™ã€‚<ph name="BEGIN_LEARN_MORE_LINK" />詳細<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">å°åˆ·</translation>
+<translation id="1432187715652018471">ã“ã®ãƒšãƒ¼ã‚¸ã¯ã‚µãƒ¼ãƒ“ス ãƒãƒ³ãƒ‰ãƒ©ã®ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã‚’求ã‚ã¦ã„ã¾ã™ã€‚</translation>
<translation id="1432581352905426595">検索エンジンã®ç®¡ç†</translation>
<translation id="1436185428532214179">デãƒã‚¤ã‚¹ã®ãƒ•ã‚¡ã‚¤ãƒ«ã‚„フォルダã®ç·¨é›†ã‚’è¦æ±‚ã§ãã‚‹</translation>
<translation id="1442386063175183758">å³è¦³éŸ³æŠ˜ã‚Š</translation>
@@ -181,6 +187,12 @@
<translation id="1483493594462132177">é€ä¿¡</translation>
<translation id="1484290072879560759">é…é€å…ˆä½æ‰€ã‚’é¸æŠž</translation>
<translation id="1492194039220927094">ãƒãƒªã‚·ãƒ¼ã®ãƒ—ッシュ:</translation>
+<translation id="149293076951187737">Chrome ã®ã‚·ãƒ¼ã‚¯ãƒ¬ãƒƒãƒˆ タブをã™ã¹ã¦é–‰ã˜ã‚‹ã¨ã€ã‚·ãƒ¼ã‚¯ãƒ¬ãƒƒãƒˆ タブã§ã®ä»¥ä¸‹ã®ã‚¢ã‚¯ãƒ†ã‚£ãƒ“ティãŒã“ã®ãƒ‡ãƒã‚¤ã‚¹ã‹ã‚‰å‰Šé™¤ã•ã‚Œã¾ã™ã€‚
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />閲覧アクティビティ<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />検索履歴<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />フォームã«å…¥åŠ›ã•ã‚ŒãŸæƒ…å ±<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">タブã«æˆ»ã‚‹</translation>
<translation id="1501859676467574491">Google アカウントã«ä¿å­˜ã—ãŸã‚«ãƒ¼ãƒ‰ã‚’表示</translation>
<translation id="1507202001669085618">&lt;p&gt;インターãƒãƒƒãƒˆã«æŽ¥ç¶šã™ã‚‹ãŸã‚ã« Wi-Fi ãƒãƒ¼ã‚¿ãƒ«ã¸ã®ãƒ­ã‚°ã‚¤ãƒ³ãŒå¿…è¦ãªå ´åˆã¯ã€ã“ã®ã‚¨ãƒ©ãƒ¼ãŒè¡¨ç¤ºã•ã‚Œã¾ã™ã€‚&lt;/p&gt;
@@ -208,6 +220,8 @@
<translation id="1559572115229829303">&lt;p&gt;デãƒã‚¤ã‚¹ã®æ—¥æ™‚(<ph name="DATE_AND_TIME" />)ãŒæ­£ã—ããªã„ãŸã‚ã€<ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> ã¸ã®ãƒ—ライベート接続を確立ã§ãã¾ã›ã‚“。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;設定&lt;/strong&gt;アプリ㮠[&lt;strong&gt;全般&lt;/strong&gt;] セクションã§æ—¥æ™‚を調整ã—ã¦ãã ã•ã„。&lt;/p&gt;</translation>
+<translation id="1559839503761818503">ãŠä½¿ã„ã®ãƒ‡ãƒã‚¤ã‚¹ã¯ <ph name="DATE" /> æ—¥ <ph name="TIME" /> 時ã«ç®¡ç†è€…ã«ã‚ˆã£ã¦å†èµ·å‹•ã•ã‚Œã¾ã™</translation>
+<translation id="156703335097561114">ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯æƒ…報(アドレスã€ã‚¤ãƒ³ã‚¿ãƒ¼ãƒ•ã‚§ãƒ¼ã‚¹è¨­å®šã€æŽ¥ç¶šå“質ãªã©ï¼‰</translation>
<translation id="1567040042588613346">ã“ã®ãƒãƒªã‚·ãƒ¼ã¯æƒ³å®šã©ãŠã‚Šå‹•ä½œã—ã¦ã„ã¾ã™ãŒã€åŒã˜å€¤ãŒè¨­å®šã•ã‚Œã¦ã„る別ã®ãƒãƒªã‚·ãƒ¼ãŒå„ªå…ˆã•ã‚Œã¦ã„ã¾ã™ã€‚</translation>
<translation id="1569487616857761740">有効期é™ã®å…¥åŠ›</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@
<translation id="1583429793053364125">ã“ã®ã‚¦ã‚§ãƒ–ページã®è¡¨ç¤ºä¸­ã«å•é¡ŒãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚</translation>
<translation id="1586541204584340881">インストールã—ãŸæ‹¡å¼µæ©Ÿèƒ½</translation>
<translation id="1588438908519853928">ノーマル</translation>
+<translation id="1589050138437146318">ARCore をインストールã—ã¾ã™ã‹ï¼Ÿ</translation>
<translation id="1592005682883173041">ローカルデータã¸ã®ã‚¢ã‚¯ã‚»ã‚¹</translation>
<translation id="1594030484168838125">é¸æŠž</translation>
<translation id="160851722280695521">Chrome 㧠Dino Run ゲームをプレイã—ã¾ã™</translation>
@@ -254,7 +269,7 @@
<translation id="1711234383449478798"><ph name="POLICY_NAME" /> ㌠<ph name="VALUE" /> ã«è¨­å®šã•ã‚Œã¦ã„ãªã„ãŸã‚無視ã•ã‚Œã¾ã—ãŸã€‚</translation>
<translation id="1712552549805331520"><ph name="URL" /> ã‹ã‚‰ã€ãƒ­ãƒ¼ã‚«ãƒ«ã®ãƒ‘ソコンã«ãƒ‡ãƒ¼ã‚¿ã‚’永続的ã«ä¿å­˜ã™ã‚‹è¨±å¯ã‚’求ã‚られã¦ã„ã¾ã™</translation>
<translation id="1713628304598226412">トレイ 2</translation>
-<translation id="1715874602234207">F</translation>
+<translation id="1715874602234207">金</translation>
<translation id="1717218214683051432">モーション センサー</translation>
<translation id="1717494416764505390">用紙å—ã‘ 3</translation>
<translation id="1718029547804390981">ドキュメントã®ã‚µã‚¤ã‚ºãŒå¤§ãã™ãŽã‚‹ãŸã‚注釈を追加ã§ãã¾ã›ã‚“</translation>
@@ -279,6 +294,7 @@
<translation id="1763864636252898013">ã“ã®ã‚µãƒ¼ãƒãƒ¼ãŒ <ph name="DOMAIN" /> ã§ã‚ã‚‹ã“ã¨ã‚’確èªã§ãã¾ã›ã‚“ã§ã—ãŸã€‚ã“ã®ã‚µãƒ¼ãƒãƒ¼ã®ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£è¨¼æ˜Žæ›¸ã¯ã€ã”使用ã®ãƒ‡ãƒã‚¤ã‚¹ã®ã‚ªãƒšãƒ¬ãƒ¼ãƒ†ã‚£ãƒ³ã‚° システムã«ã‚ˆã£ã¦ä¿¡é ¼ã•ã‚Œã¦ã„ã‚‹ã‚‚ã®ã§ã¯ã‚ã‚Šã¾ã›ã‚“。原因ã¨ã—ã¦ã¯ã€ä¸é©åˆ‡ãªè¨­å®šã‚„ã€æ‚ªæ„ã®ã‚るユーザーã«ã‚ˆã‚‹æŽ¥ç¶šå¦¨å®³ãŒè€ƒãˆã‚‰ã‚Œã¾ã™ã€‚</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Windows ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯è¨ºæ–­ãƒ„ールを実行ã—ã¦ã¿ã¦ãã ã•ã„<ph name="END_LINK" />。</translation>
<translation id="1772163372082567643">アクセスã—ã¦ã„るサーãƒãƒ¼ <ph name="ORIGIN" /> ã§ã¯ã€ã‚µãƒ¼ãƒãƒ¼ã¸ã®ã™ã¹ã¦ã®ãƒªã‚¯ã‚¨ã‚¹ãƒˆã«ã‚ªãƒªã‚¸ãƒ³ ãƒãƒªã‚·ãƒ¼ã‚’é©ç”¨ã™ã‚‹ã“ã¨ã‚’求ã‚るヘッダーãŒè¨­å®šã•ã‚Œã¦ã„ã¾ã™ãŒã€ãƒ˜ãƒƒãƒ€ãƒ¼ã®å½¢å¼ãŒæ­£ã—ããªã„ãŸã‚ã€ãƒ–ラウザ㯠<ph name="SITE" /> ã®ãƒªã‚¯ã‚¨ã‚¹ãƒˆã‚’満ãŸã™ã“ã¨ãŒã§ãã¾ã›ã‚“。オリジン ãƒãƒªã‚·ãƒ¼ã¯ã€ã‚µã‚¤ãƒˆã®ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£ã‚„ãã®ä»–ã®ãƒ—ロパティを設定ã™ã‚‹ç›®çš„ã§ãƒ‘ブリッシャーãŒä½¿ç”¨ã™ã‚‹ã‚‚ã®ã§ã™ã€‚</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Chromium ã®ã‚·ãƒ¼ã‚¯ãƒ¬ãƒƒãƒˆ モードã«ã¤ã„ã¦<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">最近開ã„ãŸã‚¿ãƒ–ãŒã“ã“ã«è¡¨ç¤ºã•ã‚Œã¾ã™</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -406,6 +422,7 @@
<translation id="22081806969704220">トレイ 3</translation>
<translation id="2212735316055980242">ãƒãƒªã‚·ãƒ¼ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“</translation>
<translation id="2213606439339815911">エントリをå–å¾—ã—ã¦ã„ã¾ã™...</translation>
+<translation id="2213612003795704869">ページãŒå°åˆ·ã•ã‚Œã¾ã—ãŸ</translation>
<translation id="2215727959747642672">ファイルã®ç·¨é›†</translation>
<translation id="2218879909401188352"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ã§ã¯ç¾åœ¨ã€æ‚ªæ„ã®ã‚るユーザーã«ã‚ˆã£ã¦å±é™ºãªã‚¢ãƒ—リ(デãƒã‚¤ã‚¹ã«å•é¡Œã‚’生ã˜ã•ã›ãŸã‚Šã€ãƒ¢ãƒã‚¤ãƒ«åˆ©ç”¨æ–™ã«ä¸æ˜Žçž­ãªè«‹æ±‚を加ãˆãŸã‚Šã€å€‹äººæƒ…報を抜ãå–ã£ãŸã‚Šã™ã‚‹ã‚¢ãƒ—リ)ãŒã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã•ã‚Œã‚‹å¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™ã€‚<ph name="BEGIN_LEARN_MORE_LINK" />詳細<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">インターãƒãƒƒãƒˆã«æŽ¥ç¶šã•ã‚Œã¦ã„ã¾ã›ã‚“</translation>
@@ -415,6 +432,7 @@
<translation id="2248949050832152960">WebAuthn を使用</translation>
<translation id="2250931979407627383">端綴ã˜ï¼ˆå·¦ï¼‰</translation>
<translation id="225207911366869382">ã“ã®å€¤ã¯ã€ã“ã®ãƒãƒªã‚·ãƒ¼ã§ã¯ã‚µãƒãƒ¼ãƒˆãŒçµ‚了ã—ã¦ã„ã¾ã™ã€‚</translation>
+<translation id="2256115617011615191">今ã™ãå†èµ·å‹•</translation>
<translation id="2258928405015593961">有効期é™ã«å°†æ¥ã®æ—¥ä»˜ã‚’入力ã—ã¦ã€ã‚‚ã†ä¸€åº¦ã‚„ã‚Šç›´ã—ã¦ãã ã•ã„</translation>
<translation id="225943865679747347">エラー コード: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">HTTP エラーã§ã™</translation>
@@ -442,6 +460,7 @@
<translation id="2337852623177822836">管ç†è€…ãŒæŒ‡å®šã™ã‚‹è¨­å®š</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> ãŒãƒšã‚¢è¨­å®šã‚’è¦æ±‚ã—ã¦ã„ã¾ã™</translation>
<translation id="2346319942568447007">コピーã—ãŸç”»åƒ</translation>
+<translation id="2350796302381711542">ã™ã¹ã¦ã® <ph name="PROTOCOL" /> リンクを <ph name="REPLACED_HANDLER_TITLE" /> ã§ã¯ãªã <ph name="HANDLER_HOSTNAME" /> ã§é–‹ãã¾ã™ã‹ï¼Ÿ</translation>
<translation id="2354001756790975382">ãã®ä»–ã®ãƒ–ックマーク</translation>
<translation id="2354430244986887761"><ph name="SITE" /> ã§ã¯æœ€è¿‘ã€Google セーフ ブラウジングã«ã‚ˆã‚Š<ph name="BEGIN_LINK" />有害ãªã‚¢ãƒ—リãŒæ¤œå‡º<ph name="END_LINK" />ã•ã‚Œã¾ã—ãŸã€‚</translation>
<translation id="2355395290879513365">ã“ã®ã‚µã‚¤ãƒˆã§ç›®ã«ã™ã‚‹ç”»åƒã¯ã€æ‚ªæ„ã®ã‚るユーザーã«ã‚ˆã£ã¦å·®ã—替ãˆã‚‰ã‚ŒãŸã‚‚ã®ã§ã‚ã‚‹å¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™ã€‚</translation>
@@ -467,6 +486,7 @@
<translation id="2413528052993050574">ã“ã®ã‚µãƒ¼ãƒãƒ¼ãŒ <ph name="DOMAIN" /> ã§ã‚ã‚‹ã“ã¨ã‚’確èªã§ãã¾ã›ã‚“ã§ã—ãŸã€‚ã“ã®ã‚µãƒ¼ãƒãƒ¼ã®ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£è¨¼æ˜Žæ›¸ã¯å–り消ã•ã‚Œã¦ã„ã‚‹å¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™ã€‚原因ã¨ã—ã¦ã¯ã€ä¸é©åˆ‡ãªè¨­å®šã‚„ã€æ‚ªæ„ã®ã‚るユーザーã«ã‚ˆã‚‹æŽ¥ç¶šå¦¨å®³ãŒè€ƒãˆã‚‰ã‚Œã¾ã™ã€‚</translation>
<translation id="2414886740292270097">æš—</translation>
<translation id="2430968933669123598">[Google アカウントを管ç†] ボタンã§ã™ã€‚Enter キーを押ã™ã¨ã€Google アカウントã§æƒ…å ±ã€ãƒ—ライãƒã‚·ãƒ¼ã€ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£ã‚’管ç†ã—ã¾ã™</translation>
+<translation id="2436186046335138073">ã™ã¹ã¦ã® <ph name="PROTOCOL" /> リンクを <ph name="HANDLER_HOSTNAME" /> ã§é–‹ãã¾ã™ã‹ï¼Ÿ</translation>
<translation id="2438874542388153331">4 穴パンãƒï¼ˆå³ï¼‰</translation>
<translation id="2450021089947420533">ジャーニー</translation>
<translation id="2463739503403862330">入力ã™ã‚‹</translation>
@@ -474,6 +494,7 @@
<translation id="2465655957518002998">é…é”方法をé¸æŠž</translation>
<translation id="2465688316154986572">ステープル</translation>
<translation id="2465914000209955735">Chrome ã§ãƒ€ã‚¦ãƒ³ãƒ­ãƒ¼ãƒ‰ã—ãŸãƒ•ã‚¡ã‚¤ãƒ«ã‚’管ç†ã—ã¾ã™</translation>
+<translation id="2466004615675155314">ウェブã®æƒ…報を表示ã—ã¾ã™</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯è¨ºæ–­ãƒ„ールを実行ã™ã‚‹<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">1~N ã®é †</translation>
<translation id="2470767536994572628">メモを編集ã™ã‚‹ã¨ã€ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆã¯å˜ä¸€ãƒšãƒ¼ã‚¸è¡¨ç¤ºã§å…ƒã®å‘ãã«æˆ»ã‚Šã¾ã™</translation>
@@ -494,6 +515,7 @@
<translation id="2523886232349826891">カードã¯ã“ã®ãƒ‡ãƒã‚¤ã‚¹ã®ã¿ã«ä¿å­˜ã•ã‚Œã¾ã™</translation>
<translation id="2524461107774643265">ãã®ä»–ã®æƒ…å ±ã®è¿½åŠ </translation>
<translation id="2529899080962247600">ã“ã®ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã§æŒ‡å®šã§ãるエントリ㯠<ph name="MAX_ITEMS_LIMIT" /> 件ã¾ã§ã§ã™ã€‚ãれ以é™ã®ã‚¨ãƒ³ãƒˆãƒªã¯ã™ã¹ã¦ç„¡è¦–ã•ã‚Œã¾ã™ã€‚</translation>
+<translation id="2535585790302968248">æ–°ã—ã„シークレット タブを開ã„ã¦ã‚·ãƒ¼ã‚¯ãƒ¬ãƒƒãƒˆ モードã§ãƒ–ラウジングã—ã¾ã™</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{ã€ä»– 1 件}other{ã€ä»– # 件}}</translation>
<translation id="2536110899380797252">ä½æ‰€ã‚’追加</translation>
<translation id="2539524384386349900">検出</translation>
@@ -519,7 +541,14 @@
<translation id="2597378329261239068">ã“ã®ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆã¯ãƒ‘スワードã§ä¿è­·ã•ã‚Œã¦ã„ã¾ã™ã€‚パスワードを入力ã—ã¦ãã ã•ã„。</translation>
<translation id="2609632851001447353">ãƒãƒªã‚¨ãƒ¼ã‚·ãƒ§ãƒ³</translation>
<translation id="2610561535971892504">クリックã—ã¦ã‚³ãƒ”ー</translation>
+<translation id="2617988307566202237">Chrome ã«ã¯ã€æ¬¡ã®æƒ…å ±ã¯<ph name="BEGIN_EMPHASIS" />ä¿å­˜ã•ã‚Œã¾ã›ã‚“<ph name="END_EMPHASIS" />。
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />閲覧履歴
+ <ph name="LIST_ITEM" />Cookie ã¨ã‚µã‚¤ãƒˆãƒ‡ãƒ¼ã‚¿
+ <ph name="LIST_ITEM" />フォームã«å…¥åŠ›ã—ãŸæƒ…å ±
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10(å°ç­’)</translation>
+<translation id="2623663032199728144">ç”»é¢ã«é–¢ã™ã‚‹æƒ…å ±ã®ä½¿ç”¨ã‚’è¦æ±‚ã§ãã‚‹</translation>
<translation id="2625385379895617796">時計ãŒé€²ã‚“ã§ã„ã¾ã™</translation>
<translation id="262745152991669301">USB デãƒã‚¤ã‚¹ã¸ã®æŽ¥ç¶šã‚’è¦æ±‚ã§ãã‚‹</translation>
<translation id="2629325967560697240">Chrome ã®æœ€é«˜ãƒ¬ãƒ™ãƒ«ã®ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£ã§ä¿è­·ã™ã‚‹ã«ã¯ã€<ph name="BEGIN_ENHANCED_PROTECTION_LINK" />ä¿è­·å¼·åŒ–機能を有効ã«ã—ã¦ãã ã•ã„<ph name="END_ENHANCED_PROTECTION_LINK" />。</translation>
@@ -553,6 +582,7 @@
<translation id="2709516037105925701">自動入力</translation>
<translation id="2713444072780614174">白</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" /> ã§ã™ã€‚Tab キーã€Enter キーã®é †ã«æŠ¼ã™ã¨ã€Chrome ã®è¨­å®šã§ãŠæ”¯æ‰•ã„ã¨ã‚¯ãƒ¬ã‚¸ãƒƒãƒˆ カードã®æƒ…報を管ç†ã—ã¾ã™</translation>
+<translation id="271663710482723385">全画é¢è¡¨ç¤ºã‚’終了ã™ã‚‹ã«ã¯ |<ph name="ACCELERATOR1" />|+|<ph name="ACCELERATOR2" />| を押ã—ã¾ã™</translation>
<translation id="2721148159707890343">リクエストを正常ã«é€ä¿¡ã—ã¾ã—ãŸ</translation>
<translation id="2723669454293168317">Chrome ã®è¨­å®šã§å®‰å…¨ç¢ºèªã‚’実行</translation>
<translation id="2726001110728089263">サイドトレイ</translation>
@@ -583,6 +613,7 @@
<translation id="2850739647070081192">Invite(å°ç­’)</translation>
<translation id="2856444702002559011"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ã§ã¯ã€æ‚ªæ„ã®ã‚るユーザーã«ã‚ˆã£ã¦ã€ãƒ‘スワードã€ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã€ã‚¯ãƒ¬ã‚¸ãƒƒãƒˆ カードãªã©ã®æƒ…å ±ãŒç›—ã¾ã‚Œã‚‹å¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™ã€‚<ph name="BEGIN_LEARN_MORE_LINK" />詳細<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">ã“ã®ã‚µã‚¤ãƒˆã§ã¯ç…©ã‚ã—ã„広告ã¾ãŸã¯èª¤è§£ã‚’æ‹›ã広告ãŒè¡¨ç¤ºã•ã‚Œã¾ã™ã€‚</translation>
+<translation id="286512204874376891">仮想カードã¯ã€å®Ÿéš›ã®ã‚«ãƒ¼ãƒ‰ã®ä»£ã‚ã‚Šã¨ã—ã¦æ©Ÿèƒ½ã—ã€ä¸æ­£è¡Œç‚ºã‹ã‚‰ä¿è­·ã—ã¾ã™ã€‚<ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">フレンドリー</translation>
<translation id="2876489322757410363">外部アプリケーションを経由ã—ãŸãŠæ”¯æ‰•ã„ã®å‡¦ç†ã«é€²ã‚€ãŸã‚ã€ã‚·ãƒ¼ã‚¯ãƒ¬ãƒƒãƒˆ モードを解除ã—ã¾ã™ã€‚続行ã—ã¾ã™ã‹ï¼Ÿ</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" /> ã§ã™ã€‚Tabã€Enter キーã®é †ã«æŠ¼ã™ã¨ã€Chrome ã®è¨­å®šã§ã‚»ãƒ¼ãƒ• ブラウジングãªã©ã‚’管ç†ã§ãã¾ã™</translation>
@@ -607,6 +638,7 @@
<translation id="2930577230479659665">トリミング(コピーå˜ä½ï¼‰</translation>
<translation id="2932085390869194046">パスワードを自動生æˆ...</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019">「<ph name="PROTOCOL" />ã€ãƒªãƒ³ã‚¯ã‚’é–‹ã</translation>
<translation id="2941952326391522266">ã“ã®ã‚µãƒ¼ãƒãƒ¼ãŒ <ph name="DOMAIN" /> ã§ã‚ã‚‹ã“ã¨ã‚’確èªã§ãã¾ã›ã‚“ã§ã—ãŸã€‚ã“ã®ã‚µãƒ¼ãƒãƒ¼ã®ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£è¨¼æ˜Žæ›¸ã¯ <ph name="DOMAIN2" /> ã‹ã‚‰ç™ºè¡Œã•ã‚Œã¦ã„ã¾ã™ã€‚原因ã¨ã—ã¦ã¯ã€ä¸é©åˆ‡ãªè¨­å®šã‚„ã€æ‚ªæ„ã®ã‚るユーザーã«ã‚ˆã‚‹æŽ¥ç¶šå¦¨å®³ãŒè€ƒãˆã‚‰ã‚Œã¾ã™ã€‚</translation>
<translation id="2943895734390379394">アップロード時刻:</translation>
<translation id="2948083400971632585">接続用ã«è¨­å®šã•ã‚ŒãŸãƒ—ロキシã¯ã€è¨­å®šãƒšãƒ¼ã‚¸ã§ç„¡åŠ¹ã«ã§ãã¾ã™ã€‚</translation>
@@ -639,6 +671,7 @@
<translation id="3037605927509011580">エラー</translation>
<translation id="3041612393474885105">証明書情報</translation>
<translation id="3044034790304486808">リサーãƒã‚’å†é–‹</translation>
+<translation id="305162504811187366">Chrome リモート デスクトップã®å±¥æ­´ï¼ˆã‚¿ã‚¤ãƒ ã‚¹ã‚¿ãƒ³ãƒ—ã€ãƒ›ã‚¹ãƒˆã€ã‚¯ãƒ©ã‚¤ã‚¢ãƒ³ãƒˆ セッション ID ã‚’å«ã‚€ï¼‰</translation>
<translation id="3060227939791841287">C9(å°ç­’)</translation>
<translation id="3061707000357573562">サービスã¸ã®ãƒ‘ッãƒã®é©ç”¨</translation>
<translation id="306573536155379004">ゲームを開始ã—ã¾ã—ãŸã€‚</translation>
@@ -679,6 +712,7 @@
<translation id="3197136577151645743">ã“ã®ãƒ‡ãƒã‚¤ã‚¹ã®ã‚¢ã‚¯ãƒ†ã‚£ãƒ–状態ã®æ¤œå‡ºã‚’è¦æ±‚ã§ãã‚‹</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" /> ã§ã™ã€‚Tab キーã€Enter キーã®é †ã«æŠ¼ã—ã¦ã€Chrome ã®è¨­å®šã§åŒæœŸã™ã‚‹æƒ…報を管ç†ã—ã¾ã™</translation>
<translation id="320323717674993345">支払ã„をキャンセル</translation>
+<translation id="3203366800380907218">ウェブã‹ã‚‰</translation>
<translation id="3207960819495026254">ブックマークã—ã¾ã—ãŸ</translation>
<translation id="3209034400446768650">ã“ã®ãƒšãƒ¼ã‚¸ã§ã¯æ–™é‡‘ãŒè«‹æ±‚ã•ã‚Œã‚‹å¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™</translation>
<translation id="3212581601480735796"><ph name="HOSTNAME" /> ã§ã®ã‚¢ã‚¯ãƒ†ã‚£ãƒ“ティã¯ç›£è¦–ã•ã‚Œã¦ã„ã¾ã™</translation>
@@ -695,10 +729,12 @@
<translation id="3234666976984236645">ã“ã®ã‚µã‚¤ãƒˆã®é‡è¦ãªã‚³ãƒ³ãƒ†ãƒ³ãƒ„を常ã«æ¤œå‡º</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" /> ã§ã™ã€‚Tabã€Enter キーã®é †ã«æŠ¼ã™ã¨ã€ãƒ–ラウザã®ãƒ‡ã‚¶ã‚¤ãƒ³ã‚’カスタマイズã§ãã¾ã™</translation>
<translation id="3240791268468473923">ä¿è­·ã•ã‚ŒãŸãŠæ”¯æ‰•ã„èªè¨¼æƒ…報(èªè¨¼æƒ…å ±ã®ä¸€è‡´ãªã—)シートãŒé–‹ã„ã¦ã„ã¾ã™</translation>
+<translation id="324180406144491771">「<ph name="HOST_NAME" />ã€ãƒªãƒ³ã‚¯ã¯ãƒ–ロックã•ã‚Œã¦ã„ã¾ã™</translation>
<translation id="3249845759089040423">グルービー</translation>
<translation id="3252266817569339921">フランス語</translation>
<translation id="3257954757204451555">ã“ã®æƒ…å ±ã®èƒŒå¾Œã«ã„ã‚‹ã®ã¯èª°ã§ã™ã‹ï¼Ÿ</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" /> ã§ã™ã€‚Tab キーã€Enter キーã®é †ã«æŠ¼ã™ã¨ã€Google カレンダーã§æ–°ã—ã„イベントをã™ã°ã‚„ã作æˆã—ã¾ã™</translation>
+<translation id="3261488570342242926">仮想カードã«ã¤ã„ã¦</translation>
<translation id="3264837738038045344">[Chrome ã®è¨­å®šã‚’管ç†] ボタンã§ã™ã€‚Enter キーを押ã™ã¨ Chrome ã®è¨­å®šã«ç§»å‹•ã—ã¾ã™</translation>
<translation id="3266793032086590337">値(競åˆï¼‰</translation>
<translation id="3268451620468152448">é–‹ã„ã¦ã„るタブ</translation>
@@ -712,6 +748,7 @@
<translation id="3288238092761586174">ãŠå®¢æ§˜ã®ãŠæ”¯æ‰•ã„情報を検証ã™ã‚‹ãŸã‚ã€<ph name="URL" /> ã¯è¿½åŠ ã®æ‰‹é †ã‚’å¿…è¦ã¨ã™ã‚‹å ´åˆãŒã‚ã‚Šã¾ã™</translation>
<translation id="3293642807462928945"><ph name="POLICY_NAME" /> ãƒãƒªã‚·ãƒ¼ã®è©³ç´°</translation>
<translation id="3295444047715739395">Chrome ã®è¨­å®šã§ãƒ‘スワードを表示ã€ç®¡ç†ã™ã‚‹</translation>
+<translation id="3303795387212510132">アプリ㫠<ph name="PROTOCOL_SCHEME" /> リンクã®è¡¨ç¤ºã‚’許å¯ã—ã¾ã™ã‹ï¼Ÿ</translation>
<translation id="3303855915957856445">一致ã™ã‚‹çµæžœã¯è¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸ</translation>
<translation id="3304073249511302126">Bluetooth ã®ã‚¹ã‚­ãƒ£ãƒ³</translation>
<translation id="3308006649705061278">組織å˜ä½ï¼ˆOU)</translation>
@@ -725,12 +762,6 @@
<translation id="3345782426586609320">ç›®</translation>
<translation id="3355823806454867987">プロキシ設定ã®å¤‰æ›´...</translation>
<translation id="3360103848165129075">支払ã„ãƒãƒ³ãƒ‰ãƒ©ã®ã‚·ãƒ¼ãƒˆ</translation>
-<translation id="3361596688432910856">Chrome ã«ã¯ã€æ¬¡ã®æƒ…å ±ã¯<ph name="BEGIN_EMPHASIS" />ä¿å­˜ã•ã‚Œã¾ã›ã‚“。<ph name="END_EMPHASIS" />
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />閲覧履歴
- <ph name="LIST_ITEM" />Cookie ã¨ã‚µã‚¤ãƒˆãƒ‡ãƒ¼ã‚¿
- <ph name="LIST_ITEM" />フォームã«å…¥åŠ›ã—ãŸæƒ…å ±
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">ã“ã®ãƒãƒªã‚·ãƒ¼ã¯ã€ã‚µãƒãƒ¼ãƒˆãŒçµ‚了ã—㟠<ph name="OLD_POLICY" /> ãƒãƒªã‚·ãƒ¼ã‹ã‚‰è‡ªå‹•çš„ã«ã‚³ãƒ”ーã•ã‚Œã¾ã—ãŸã€‚今後ã¯ã“ã®ãƒãƒªã‚·ãƒ¼ã‚’使用ã—ã¦ãã ã•ã„。</translation>
<translation id="3364869320075768271"><ph name="URL" /> ã‹ã‚‰ã€ãƒãƒ¼ãƒãƒ£ãƒ« リアリティ デãƒã‚¤ã‚¹ã¨ãƒ‡ãƒ¼ã‚¿ã®ä½¿ç”¨è¨±å¯ã‚’求ã‚られã¦ã„ã¾ã™</translation>
<translation id="3366477098757335611">カードを表示</translation>
@@ -813,7 +844,6 @@
<translation id="3587738293690942763">中</translation>
<translation id="3592413004129370115">Italian(å°ç­’)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{グループã¯ã„ã¤ã§ã‚‚リセットã§ãã¾ã™ã€‚æ–°ã—ã„グループã«åˆ†é¡žã•ã‚Œã‚‹ã¾ã§ã«ã¯ç´„ 1 æ—¥ã‹ã‹ã‚Šã¾ã™ã€‚}=1{グループã¯ã„ã¤ã§ã‚‚リセットã§ãã¾ã™ã€‚æ–°ã—ã„グループã«åˆ†é¡žã•ã‚Œã‚‹ã¾ã§ã«ã¯ç´„ 1 æ—¥ã‹ã‹ã‚Šã¾ã™ã€‚}other{グループã¯ã„ã¤ã§ã‚‚リセットã§ãã¾ã™ã€‚æ–°ã—ã„グループã«åˆ†é¡žã•ã‚Œã‚‹ã¾ã§ã«ã¯ {NUM_DAYS} æ—¥ã‹ã‹ã‚Šã¾ã™ã€‚}}</translation>
-<translation id="3596012367874587041">アプリã®è¨­å®š</translation>
<translation id="3600246354004376029"><ph name="TITLE" />ã€<ph name="DOMAIN" />ã€<ph name="TIME" /></translation>
<translation id="3603507503523709">アプリケーションã¯ç®¡ç†è€…ã«ã‚ˆã£ã¦ãƒ–ロックã•ã‚Œã¦ã„ã¾ã™</translation>
<translation id="3608932978122581043">給紙方å‘</translation>
@@ -856,6 +886,7 @@
<translation id="370972442370243704">ジャーニーをオンã«ã™ã‚‹</translation>
<translation id="3711895659073496551">åœæ­¢ã™ã‚‹</translation>
<translation id="3712624925041724820">ライセンスを使ã„切りã¾ã—ãŸ</translation>
+<translation id="3714633008798122362">ウェブ カレンダー</translation>
<translation id="3714780639079136834">モãƒã‚¤ãƒ«ãƒ‡ãƒ¼ã‚¿ã¾ãŸã¯ Wi-Fi を有効ã«ã™ã‚‹</translation>
<translation id="3715597595485130451">Wi-Fi 接続</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />プロキシã€ãƒ•ã‚¡ã‚¤ã‚¢ã‚¦ã‚©ãƒ¼ãƒ«ã€DNS ã®è¨­å®šã‚’確èªã™ã‚‹<ph name="END_LINK" /></translation>
@@ -917,6 +948,7 @@
<translation id="3906954721959377182">タブレット</translation>
<translation id="3909477809443608991"><ph name="URL" /> ãŒä¿è­·ã•ã‚ŒãŸã‚³ãƒ³ãƒ†ãƒ³ãƒ„ã®å†ç”Ÿã‚’è¦æ±‚ã—ã¦ã„ã¾ã™ã€‚デãƒã‚¤ã‚¹ã®èªè¨¼æƒ…報㌠Google ã«ã‚ˆã£ã¦ç¢ºèªã•ã‚Œã€ã“ã®ã‚µã‚¤ãƒˆã«ã‚ˆã‚‹èªè¨¼æƒ…å ±ã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ãŒè¨±å¯ã•ã‚Œã¾ã™ã€‚</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">æ‹’å¦</translation>
<translation id="3939773374150895049">CVC ã®ä»£ã‚ã‚Šã« WebAuthn を使用ã—ã¾ã™ã‹ï¼Ÿ</translation>
<translation id="3946209740501886391">ã“ã®ã‚µã‚¤ãƒˆã§ã¯å¸¸ã«ç¢ºèª</translation>
<translation id="3947595700203588284">MIDI デãƒã‚¤ã‚¹ã¸ã®æŽ¥ç¶šã‚’è¦æ±‚ã§ãã‚‹</translation>
@@ -937,6 +969,7 @@
<translation id="3987940399970879459">1 MB 未満</translation>
<translation id="3990250421422698716">ジョグ オフセット</translation>
<translation id="3996311196211510766">サイト <ph name="ORIGIN" /> ã§ã¯ã€ã‚µã‚¤ãƒˆã¸ã®ã™ã¹ã¦ã®ãƒªã‚¯ã‚¨ã‚¹ãƒˆã«ã‚ªãƒªã‚¸ãƒ³ ãƒãƒªã‚·ãƒ¼ã®é©ç”¨ã‚’求ã‚ã¦ã„ã¾ã™ãŒã€ã“ã®ãƒãƒªã‚·ãƒ¼ã¯ç¾åœ¨é©ç”¨ã™ã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“。</translation>
+<translation id="4009243425692662128">å°åˆ·ã™ã‚‹ãƒšãƒ¼ã‚¸ã®ã‚³ãƒ³ãƒ†ãƒ³ãƒ„ã¯åˆ†æžã®ãŸã‚ Google Cloud ã¾ãŸã¯ç¬¬ä¸‰è€…ã«é€ä¿¡ã•ã‚Œã¾ã™ã€‚ãŸã¨ãˆã°ã€æ©Ÿå¯†ãƒ‡ãƒ¼ã‚¿ãŒãªã„ã‹ã‚¹ã‚­ãƒ£ãƒ³ã•ã‚Œã¾ã™ã€‚</translation>
<translation id="4010758435855888356">ストレージã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ã‚’許å¯ã—ã¾ã™ã‹ï¼Ÿ</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{{COUNT} ページ㮠PDF ドキュメント}other{{COUNT} ページ㮠PDF ドキュメント}}</translation>
<translation id="4023431997072828269">ã“ã®ãƒ•ã‚©ãƒ¼ãƒ ã¯å®‰å…¨ã§ã¯ãªã„接続を使用ã—ã¦é€ä¿¡ã•ã‚Œã¦ã„ã‚‹ãŸã‚ã€æƒ…å ±ãŒä»–人ã«èª­ã¿å–られるå¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™ã€‚</translation>
@@ -1027,6 +1060,7 @@
<translation id="4250680216510889253">ã„ã„ãˆ</translation>
<translation id="4253168017788158739">メモ</translation>
<translation id="425582637250725228">è¡Œã£ãŸå¤‰æ›´ãŒä¿å­˜ã•ã‚Œãªã„å¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™ã€‚</translation>
+<translation id="425869179292622354">仮想カードã§ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£ã‚’高ã‚ã¾ã™ã‹ï¼Ÿ</translation>
<translation id="4258748452823770588">ç½²åãŒä¸é©åˆ‡ã§ã™</translation>
<translation id="4261046003697461417">ä¿è­·ã•ã‚ŒãŸãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆã«æ³¨é‡ˆã‚’追加ã™ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“</translation>
<translation id="4265872034478892965">管ç†è€…ã«ã‚ˆã£ã¦è¨±å¯</translation>
@@ -1089,6 +1123,7 @@
<translation id="4434045419905280838">ãƒãƒƒãƒ—アップã¨ãƒªãƒ€ã‚¤ãƒ¬ã‚¯ãƒˆ</translation>
<translation id="4435702339979719576">ãƒã‚¹ãƒˆã‚«ãƒ¼ãƒ‰</translation>
<translation id="443673843213245140">プロキシã®ä½¿ç”¨ã¯ç„¡åŠ¹ã§ã™ãŒã€ãƒ—ロキシã®è¨­å®šãŒæ˜Žç¤ºçš„ã«æŒ‡å®šã•ã‚Œã¦ã„ã¾ã™ã€‚</translation>
+<translation id="4441832193888514600">ãƒãƒªã‚·ãƒ¼ã¯ã€ã‚¯ãƒ©ã‚¦ãƒ‰ ユーザー ãƒãƒªã‚·ãƒ¼ã¨ã—ã¦ã®ã¿è¨­å®šå¯èƒ½ãªãŸã‚無視ã•ã‚Œã¾ã—ãŸã€‚</translation>
<translation id="4450893287417543264">次回ã‹ã‚‰è¡¨ç¤ºã—ãªã„</translation>
<translation id="4451135742916150903">HID デãƒã‚¤ã‚¹ã¸ã®æŽ¥ç¶šã‚’è¦æ±‚ã§ãã‚‹</translation>
<translation id="4452328064229197696">ãŸã£ãŸä»Šä½¿ç”¨ã—ãŸãƒ‘スワードãŒãƒ‡ãƒ¼ã‚¿ä¾µå®³ã§æ¤œå‡ºã•ã‚Œã¾ã—ãŸã€‚Google パスワード マãƒãƒ¼ã‚¸ãƒ£ãƒ¼ã§ã¯ã€ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã‚’ä¿è­·ã™ã‚‹ãŸã‚ã«ä¿å­˜ã—ãŸãƒ‘スワードを確èªã™ã‚‹ã“ã¨ã‚’ãŠã™ã™ã‚ã—ã¾ã™ã€‚</translation>
@@ -1144,6 +1179,7 @@
<translation id="4628948037717959914">写真</translation>
<translation id="4631649115723685955">キャッシュãƒãƒƒã‚¯ã‚’リンクã—ã¾ã—ãŸ</translation>
<translation id="4636930964841734540">情報</translation>
+<translation id="4638670630777875591">Chromium ã®ã‚·ãƒ¼ã‚¯ãƒ¬ãƒƒãƒˆ モード</translation>
<translation id="464342062220857295">検索機能</translation>
<translation id="4644670975240021822">逆ã®é †åºï¼ˆä¸‹å‘ã)</translation>
<translation id="4646534391647090355">今ã™ã表示</translation>
@@ -1164,6 +1200,7 @@
<translation id="4708268264240856090">接続ãŒä¸­æ–­ã•ã‚Œã¾ã—ãŸ</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Windows ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯è¨ºæ–­ãƒ„ールを実行ã™ã‚‹<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426"><ph name="USERNAME" /> ã®ãƒ‘スワード</translation>
<translation id="4724144314178270921">クリップボード内ã®ãƒ†ã‚­ã‚¹ãƒˆã‚„ç”»åƒã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ã‚’è¦æ±‚ã§ãã‚‹</translation>
<translation id="4726672564094551039">ãƒãƒªã‚·ãƒ¼ã‚’å†èª­ã¿è¾¼ã¿</translation>
<translation id="4728558894243024398">プラットフォーム</translation>
@@ -1185,6 +1222,7 @@
<translation id="4757993714154412917">å½ã®ã‚µã‚¤ãƒˆã§ãƒ‘スワードを入力ã—ã¾ã—ãŸã€‚アカウントをä¿è­·ã™ã‚‹ãŸã‚ã€ä¿å­˜ã—ãŸãƒ‘スワードをã™ãã«ç¢ºèªã™ã‚‹ã“ã¨ã‚’ãŠã™ã™ã‚ã—ã¾ã™ã€‚</translation>
<translation id="4758311279753947758">連絡先情報を追加</translation>
<translation id="4761104368405085019">マイクを使用ã™ã‚‹</translation>
+<translation id="4761869838909035636">Chrome ã®å®‰å…¨ç¢ºèªã‚’実行</translation>
<translation id="4764776831041365478"><ph name="URL" /> ã®ã‚¦ã‚§ãƒ–ページã¯ä¸€æ™‚çš„ã«åœæ­¢ã—ã¦ã„ã‚‹ã‹ã€æ–°ã—ã„ウェブアドレスã«ç§»å‹•ã—ãŸå¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™ã€‚</translation>
<translation id="4766713847338118463">2 ã‹æ‰€ã®ã‚¹ãƒ†ãƒ¼ãƒ—ル(下)</translation>
<translation id="4771973620359291008">ä¸æ˜Žãªã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚</translation>
@@ -1205,12 +1243,6 @@
<translation id="4819347708020428563">デフォルト表示ã§ãƒ¡ãƒ¢ã‚’編集ã—ã¾ã™ã‹ï¼Ÿ</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" /> ã§ã™ã€‚Tab キーã€Enter キーã®é †ã«æŠ¼ã™ã¨ã€æ–°ã—ã„ Google スプレッドシートをã™ã°ã‚„ã作æˆã—ã¾ã™</translation>
<translation id="4825507807291741242">パワフル</translation>
-<translation id="4827402517081186284">シークレット モードを使用ã—ã¦ã‚‚ã€ã‚ªãƒ³ãƒ©ã‚¤ãƒ³ä¸Šã«ã¾ã£ãŸã記録ãŒæ®‹ã‚‰ãªã„ã‚ã‘ã§ã¯ã‚ã‚Šã¾ã›ã‚“。
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />サイトã«ã¯ã‚¢ã‚¯ã‚»ã‚¹ã—ãŸã“ã¨ãŒçŸ¥ã‚‰ã‚Œã¾ã™<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />雇用主や教育機関ã§é–²è¦§ã‚¢ã‚¯ãƒ†ã‚£ãƒ“ティを追跡ã—ã¦ã„ã‚‹å ´åˆãŒã‚ã‚Šã¾ã™<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />インターãƒãƒƒãƒˆ サービス プロãƒã‚¤ãƒ€ã§ã‚¦ã‚§ãƒ– トラフィックを監視ã—ã¦ã„ã‚‹ã“ã¨ãŒã‚ã‚Šã¾ã™<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">警告をオンã«ã™ã‚‹</translation>
<translation id="4838327282952368871">ドリーミー</translation>
<translation id="4840250757394056958">Chrome 履歴を表示</translation>
@@ -1222,12 +1254,12 @@
<translation id="4854362297993841467">ã“ã®é…é”方法ã¯ã”利用ã„ãŸã ã‘ã¾ã›ã‚“。別ã®æ–¹æ³•ã‚’é¸æŠžã—ã¦ãã ã•ã„。</translation>
<translation id="4854853140771946034">Google Keep ã§æ–°ã—ã„メモをã™ã°ã‚„ã作æˆã—ã¾ã™</translation>
<translation id="485902285759009870">コードを確èªã—ã¦ã„ã¾ã™...</translation>
+<translation id="4866506163384898554">カーソルを表示ã™ã‚‹ã«ã¯ |<ph name="ACCELERATOR1" />|+|<ph name="ACCELERATOR2" />| を押ã—ã¾ã™</translation>
<translation id="4876188919622883022">簡易表示</translation>
<translation id="4876305945144899064">ユーザーåãŒæŒ‡å®šã•ã‚Œã¦ã„ã¾ã›ã‚“</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{ãªã—}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />ã€<ph name="EXAMPLE_DOMAIN_2" />}other{<ph name="EXAMPLE_DOMAIN_1" />ã€<ph name="EXAMPLE_DOMAIN_2" />ã€<ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831"><ph name="TEXT" /> を検索</translation>
<translation id="4879491255372875719">自動(デフォルト)</translation>
-<translation id="4879725228911483934">ç”»é¢ä¸Šã«ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã‚’é–‹ã„ã¦é…ç½®ã™ã‚‹</translation>
<translation id="4880827082731008257">履歴を検索</translation>
<translation id="4881695831933465202">é–‹ã</translation>
<translation id="4885256590493466218">ã”購入手続ãã®éš›ã« <ph name="CARD_DETAIL" /> ã§æ”¯æ‰•ã„ã¾ã™</translation>
@@ -1236,6 +1268,7 @@
<translation id="4895877746940133817"><ph name="TYPE_1" />ã€<ph name="TYPE_2" />ã€<ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">ロール 9</translation>
<translation id="4901778704868714008">ä¿å­˜...</translation>
+<translation id="4905659621780993806">デãƒã‚¤ã‚¹ã¯ <ph name="DATE" /> <ph name="TIME" /> ã«ç®¡ç†è€…ã«ã‚ˆã£ã¦è‡ªå‹•çš„ã«å†èµ·å‹•ã•ã‚Œã¾ã™ã€‚デãƒã‚¤ã‚¹ãŒå†èµ·å‹•ã•ã‚Œã‚‹å‰ã«ã€é–‹ã„ã¦ã„ã‚‹ã™ã¹ã¦ã®ã‚¢ã‚¤ãƒ†ãƒ ã‚’ä¿å­˜ã—ã¦ãã ã•ã„。</translation>
<translation id="4913987521957242411">パンãƒï¼ˆå·¦ä¸Šï¼‰</translation>
<translation id="4918221908152712722"><ph name="APP_NAME" /> をインストール(ダウンロードã¯ä¸è¦ã§ã™ï¼‰</translation>
<translation id="4923459931733593730">ãŠæ”¯æ‰•ã„</translation>
@@ -1244,6 +1277,7 @@
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" /> / <ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" /> ã§ã™ã€‚Tab キーã€Enter キーã®é †ã«æŠ¼ã™ã¨æ¤œç´¢ã—ã¾ã™</translation>
<translation id="4930153903256238152">大容é‡</translation>
+<translation id="4940163644868678279">Chrome ã®ã‚·ãƒ¼ã‚¯ãƒ¬ãƒƒãƒˆ モード</translation>
<translation id="4943872375798546930">çµæžœã¯ã‚ã‚Šã¾ã›ã‚“</translation>
<translation id="4950898438188848926">タブã®åˆ‡ã‚Šæ›¿ãˆãƒœã‚¿ãƒ³ã§ã™ã€‚Enter キーを押ã™ã¨é–‹ã„ã¦ã„るタブ「<ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" />ã€ã«åˆ‡ã‚Šæ›¿ã‚ã‚Šã¾ã™</translation>
<translation id="495170559598752135">æ“作</translation>
@@ -1253,6 +1287,7 @@
<translation id="4968522289500246572">ã“ã®ã‚¢ãƒ—リã¯ãƒ¢ãƒã‚¤ãƒ«å‘ã‘ã«è¨­è¨ˆã•ã‚Œã¦ã„ã‚‹ãŸã‚ã€é©åˆ‡ã«ã‚µã‚¤ã‚ºå¤‰æ›´ã•ã‚Œãªã„å¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™ã€‚アプリã«å•é¡ŒãŒç”Ÿã˜ãŸã‚Šã€å†èµ·å‹•ã—ãŸã‚Šã™ã‚‹ã“ã¨ãŒã‚ã‚Šã¾ã™ã€‚</translation>
<translation id="4969341057194253438">録画を削除</translation>
<translation id="4973922308112707173">2 穴パンãƒï¼ˆä¸Šï¼‰</translation>
+<translation id="4976702386844183910">最終アクセス日: <ph name="DATE" /></translation>
<translation id="4984088539114770594">マイクを使用ã—ã¾ã™ã‹ï¼Ÿ</translation>
<translation id="4984339528288761049">Prc5(å°ç­’)</translation>
<translation id="4989163558385430922">ã™ã¹ã¦è¡¨ç¤º</translation>
@@ -1314,6 +1349,7 @@
<translation id="5138227688689900538">一部を表示</translation>
<translation id="5145883236150621069">ãƒãƒªã‚·ãƒ¼å¿œç­”内ã«ã‚¨ãƒ©ãƒ¼ コードãŒã‚ã‚Šã¾ã™</translation>
<translation id="5146995429444047494"><ph name="ORIGIN" /> ã®é€šçŸ¥ã‚’ブロックã—ã¾ã—ãŸ</translation>
+<translation id="514704532284964975"><ph name="URL" /> ãŒã€ã‚¹ãƒžãƒ¼ãƒˆãƒ•ã‚©ãƒ³ã§ã‚¿ãƒƒãƒ—ã—㟠NFC デãƒã‚¤ã‚¹ã®æƒ…報をå‚ç…§ãŠã‚ˆã³å¤‰æ›´ã—よã†ã¨ã—ã¦ã„ã¾ã™</translation>
<translation id="5148809049217731050">上å‘ã</translation>
<translation id="515292512908731282">C4(å°ç­’)</translation>
<translation id="5158275234811857234">表紙</translation>
@@ -1338,6 +1374,7 @@
<translation id="5215116848420601511">Google Pay ã®ãŠæ”¯æ‰•ã„方法ã¨ä½æ‰€</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">トレイ 13</translation>
+<translation id="5216942107514965959">最終アクセス日: 今日</translation>
<translation id="5222812217790122047">メールアドレスã¯å¿…é ˆã§ã™</translation>
<translation id="5230733896359313003">é…é€å…ˆä½æ‰€</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1358,7 +1395,6 @@
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">ドキュメント プロパティ</translation>
<translation id="528468243742722775">終了</translation>
-<translation id="5284909709419567258">ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ アドレス</translation>
<translation id="5285570108065881030">ä¿å­˜ã—ãŸãƒ‘スワードをã™ã¹ã¦è¡¨ç¤º</translation>
<translation id="5287240709317226393">Cookie を表示</translation>
<translation id="5287456746628258573">ã“ã®ã‚µã‚¤ãƒˆã§ã¯å¤ã„セキュリティ設定を使用ã—ã¦ã„ã¾ã™ã€‚ã“ã®ã‚µã‚¤ãƒˆã«ãƒ‘スワードやクレジット カード番å·ãªã©ã®æƒ…報をé€ä¿¡ã™ã‚‹ã¨æµå‡ºã™ã‚‹æã‚ŒãŒã‚ã‚Šã¾ã™ã€‚</translation>
@@ -1442,6 +1478,7 @@
<translation id="5556459405103347317">å†èª­ã¿è¾¼ã¿</translation>
<translation id="5560088892362098740">有効期é™</translation>
<translation id="55635442646131152">ドキュメントã®æ¦‚è¦</translation>
+<translation id="5565613213060953222">シークレット タブを開ã</translation>
<translation id="5565735124758917034">有効</translation>
<translation id="5570825185877910964">アカウントをä¿è­·</translation>
<translation id="5571083550517324815">ã“ã®ä½æ‰€ã§ã®å—ã‘å–ã‚Šã¯ã§ãã¾ã›ã‚“。別ã®ä½æ‰€ã‚’é¸æŠžã—ã¦ãã ã•ã„。</translation>
@@ -1524,6 +1561,7 @@
<translation id="5869522115854928033">ä¿å­˜ã—ãŸãƒ‘スワード</translation>
<translation id="5873013647450402046">ã”利用ã®éŠ€è¡Œã¾ãŸã¯ã‚«ãƒ¼ãƒ‰ç™ºè¡Œä¼šç¤¾ãŒæœ¬äººç¢ºèªã‚’求ã‚ã¦ã„ã¾ã™ã€‚</translation>
<translation id="5887400589839399685">カードãŒä¿å­˜ã•ã‚Œã¾ã—ãŸ</translation>
+<translation id="5887687176710214216">最終アクセス日: 昨日</translation>
<translation id="5895138241574237353">å†èµ·å‹•</translation>
<translation id="5895187275912066135">発行日</translation>
<translation id="5901630391730855834">黄</translation>
@@ -1537,6 +1575,7 @@
<translation id="5921639886840618607">カードを Google アカウントã«ä¿å­˜ã—ã¾ã™ã‹ï¼Ÿ</translation>
<translation id="5922853866070715753">ã»ã¼å®Œäº†ã§ã™</translation>
<translation id="5932224571077948991">ã“ã®ã‚µã‚¤ãƒˆã§ã¯ç…©ã‚ã—ã„広告や誤解を招ã広告ãŒè¡¨ç¤ºã•ã‚Œã¾ã™</translation>
+<translation id="5938153366081463283">仮想カードを追加ã™ã‚‹</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347"><ph name="SITE_NAME" /> ã‚’é–‹ã„ã¦ã„ã¾ã™â€¦</translation>
<translation id="5951495562196540101">一般ユーザーå‘ã‘アカウントã§ã¯ç™»éŒ²ã§ãã¾ã›ã‚“(ライセンス パッケージãŒåˆ©ç”¨å¯èƒ½ã§ã™ï¼‰ã€‚</translation>
@@ -1601,6 +1640,7 @@
<translation id="6120179357481664955">UPI ID ã‚’ä¿å­˜ã—ã¾ã™ã‹ï¼Ÿ</translation>
<translation id="6124432979022149706">Chrome Enterprise Connector</translation>
<translation id="6127379762771434464">アイテムを削除ã—ã¾ã—ãŸ</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Chrome ã®ã‚·ãƒ¼ã‚¯ãƒ¬ãƒƒãƒˆ モードã«ã¤ã„ã¦<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">ケーブルを確èªã—ã€ä½¿ç”¨ã—ã¦ã„ã‚‹ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ デãƒã‚¤ã‚¹ï¼ˆãƒ«ãƒ¼ã‚¿ãƒ¼ã€ãƒ¢ãƒ‡ãƒ ãªã©ï¼‰ã‚’
å†èµ·å‹•ã—ã¦ãã ã•ã„。</translation>
<translation id="614940544461990577">次をãŠè©¦ã—ãã ã•ã„</translation>
@@ -1613,7 +1653,6 @@
<translation id="6169916984152623906">ç¾åœ¨ã€ã‚·ãƒ¼ã‚¯ãƒ¬ãƒƒãƒˆ モードã§é–²è¦§ã—ã¦ã„ã¾ã™ã€‚ã‚ãªãŸã®ã‚¢ã‚¯ãƒ†ã‚£ãƒ“ティã¯ã€ã“ã®ãƒ‡ãƒã‚¤ã‚¹ã‚’利用ã™ã‚‹ä»–ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã«ã¯è¡¨ç¤ºã•ã‚Œã¾ã›ã‚“。ãŸã ã—ã€ãƒ€ã‚¦ãƒ³ãƒ­ãƒ¼ãƒ‰ã—ãŸãƒ•ã‚¡ã‚¤ãƒ«ã¨ãƒ–ックマークã¯é€šå¸¸ã©ãŠã‚Šä¿å­˜ã•ã‚Œã¾ã™ã€‚</translation>
<translation id="6177128806592000436">ã“ã®ã‚µã‚¤ãƒˆã¸ã®æŽ¥ç¶šã¯ä¿è­·ã•ã‚Œã¦ã„ã¾ã›ã‚“</translation>
<translation id="6180316780098470077">å†è©¦è¡Œã®é–“éš”</translation>
-<translation id="619448280891863779">ç”»é¢ä¸Šã«ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã‚’é–‹ã„ã¦é…ç½®ã™ã‚‹ã‚ˆã†è¦æ±‚ã§ãã‚‹</translation>
<translation id="6196640612572343990">サードパーティ㮠Cookie をブロックã™ã‚‹</translation>
<translation id="6203231073485539293">インターãƒãƒƒãƒˆæŽ¥ç¶šã‚’確èªã—ã¦ãã ã•ã„</translation>
<translation id="6218753634732582820">Chromium ã‹ã‚‰ã‚¢ãƒ‰ãƒ¬ã‚¹ã‚’削除ã—ã¦ã‚‚よã‚ã—ã„ã§ã™ã‹ï¼Ÿ</translation>
@@ -1636,7 +1675,7 @@
<translation id="6272383483618007430">Google Update</translation>
<translation id="6276112860590028508">リーディング リストã«ç™»éŒ²ã•ã‚ŒãŸãƒšãƒ¼ã‚¸ãŒã“ã“ã«è¡¨ç¤ºã•ã‚Œã¾ã™</translation>
<translation id="627746635834430766">カードã¨è«‹æ±‚å…ˆä½æ‰€ã‚’ Google アカウントã«ä¿å­˜ã™ã‚‹ã¨ã€æ¬¡å›žã®ãŠæ”¯æ‰•ã„ãŒç°¡å˜ã«ãªã‚Šã¾ã™ã€‚</translation>
-<translation id="6279098320682980337">仮想カード番å·ãŒå…¥åŠ›ã•ã‚Œãªã„å ´åˆã¯ã€ã‚«ãƒ¼ãƒ‰æƒ…報をクリックã—ã¦ã‚³ãƒ”ーã—ã¦ãã ã•ã„</translation>
+<translation id="6279183038361895380">カーソルを表示ã™ã‚‹ã«ã¯ |<ph name="ACCELERATOR" />| を押ã—ã¾ã™</translation>
<translation id="6280223929691119688">ã“ã®ä½æ‰€ã«ã¯é…é”ã§ãã¾ã›ã‚“。別ã®ä½æ‰€ã‚’é¸æŠžã—ã¦ãã ã•ã„。</translation>
<translation id="6282194474023008486">郵便番å·</translation>
<translation id="6285507000506177184">[Chrome ã§ã®ãƒ€ã‚¦ãƒ³ãƒ­ãƒ¼ãƒ‰ã‚’管ç†] ボタンã§ã™ã€‚Enter キーを押ã™ã¨ã€Chrome ã§ãƒ€ã‚¦ãƒ³ãƒ­ãƒ¼ãƒ‰ã—ãŸãƒ•ã‚¡ã‚¤ãƒ«ã‚’管ç†ã§ãã¾ã™</translation>
@@ -1644,6 +1683,7 @@
<translation id="6290238015253830360">ãŠã™ã™ã‚ã®è¨˜äº‹ãŒã“ã“ã«è¡¨ç¤ºã•ã‚Œã¾ã™</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{デãƒã‚¤ã‚¹ã¯ä»Šã™ãå†èµ·å‹•ã•ã‚Œã¾ã™}=1{デãƒã‚¤ã‚¹ã¯ 1 秒後ã«å†èµ·å‹•ã•ã‚Œã¾ã™}other{デãƒã‚¤ã‚¹ã¯ # 秒後ã«å†èµ·å‹•ã•ã‚Œã¾ã™}}</translation>
<translation id="6302269476990306341">Chrome ã® Google アシスタントをåœæ­¢ã—ã¦ã„ã¾ã™</translation>
<translation id="6305205051461490394"><ph name="URL" /> ã«ã‚¢ã‚¯ã‚»ã‚¹ã§ãã¾ã›ã‚“。</translation>
<translation id="6312113039770857350">ウェブページã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ä¸å¯</translation>
@@ -1717,6 +1757,7 @@
<translation id="6529602333819889595">削除ã®ã‚„ã‚Šç›´ã—(&amp;R)</translation>
<translation id="6545864417968258051">Bluetooth ã®ã‚¹ã‚­ãƒ£ãƒ³</translation>
<translation id="6547208576736763147">2 穴パンãƒï¼ˆå·¦ï¼‰</translation>
+<translation id="6554732001434021288">最終アクセス日: <ph name="NUM_DAYS" /> æ—¥å‰</translation>
<translation id="6556866813142980365">ã‚„ã‚Šç›´ã™</translation>
<translation id="6569060085658103619">拡張機能ã®ãƒšãƒ¼ã‚¸ã‚’表示ã—ã¦ã„ã¾ã™</translation>
<translation id="6573200754375280815">2 穴パンãƒï¼ˆå³ï¼‰</translation>
@@ -1777,7 +1818,6 @@
<translation id="6757797048963528358">デãƒã‚¤ã‚¹ãŒã‚¹ãƒªãƒ¼ãƒ—状態ã§ã™ã€‚</translation>
<translation id="6767985426384634228">ä½æ‰€ã‚’æ›´æ–°ã—ã¾ã™ã‹ï¼Ÿ</translation>
<translation id="6768213884286397650">ã¯ãŒã</translation>
-<translation id="6774185088257932239"><ph name="BEGIN_LINK" />シークレット モードã«ã¤ã„ã¦<ph name="END_LINK" /></translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">ãƒã‚¤ã‚ªãƒ¬ãƒƒãƒˆ</translation>
<translation id="6786747875388722282">拡張機能</translation>
@@ -1861,7 +1901,6 @@
<translation id="706295145388601875">Chrome ã®è¨­å®šã§ä½æ‰€ã‚’追加ã€ç®¡ç†ã™ã‚‹</translation>
<translation id="7064851114919012435">連絡先情報</translation>
<translation id="7068733155164172741"><ph name="OTP_LENGTH" /> æ¡ã®ã‚³ãƒ¼ãƒ‰ã‚’入力ã—ã¦ãã ã•ã„</translation>
-<translation id="7070090581017165256">ã“ã®ã‚µã‚¤ãƒˆã«ã¤ã„ã¦</translation>
<translation id="70705239631109039">接続ã¯å®Œå…¨ã«ã¯ä¿è­·ã•ã‚Œã¦ã„ã¾ã›ã‚“</translation>
<translation id="7075452647191940183">リクエストãŒå¤§ãã™ãŽã¾ã™</translation>
<translation id="7079718277001814089">ã“ã®ã‚µã‚¤ãƒˆã«ã¯ä¸æ­£ãªã‚½ãƒ•ãƒˆã‚¦ã‚§ã‚¢ãŒå«ã¾ã‚Œã¦ã„ã¾ã™</translation>
@@ -1878,6 +1917,12 @@
<translation id="7111012039238467737">(有効)</translation>
<translation id="7118618213916969306">クリップボードã«ã‚ã‚‹ URL(<ph name="SHORT_URL" />)を検索ã—ã¾ã™</translation>
<translation id="7119414471315195487">ä»–ã®ã‚¿ãƒ–やプログラムを閉ã˜ã‚‹</translation>
+<translation id="7129355289156517987">Chromium ã®ã‚·ãƒ¼ã‚¯ãƒ¬ãƒƒãƒˆ タブをã™ã¹ã¦é–‰ã˜ã‚‹ã¨ã€ã‚·ãƒ¼ã‚¯ãƒ¬ãƒƒãƒˆ タブã§ã®ä»¥ä¸‹ã®ã‚¢ã‚¯ãƒ†ã‚£ãƒ“ティãŒã“ã®ãƒ‡ãƒã‚¤ã‚¹ã‹ã‚‰å‰Šé™¤ã•ã‚Œã¾ã™ã€‚
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />閲覧アクティビティ<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />検索履歴<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />フォームã«å…¥åŠ›ã•ã‚ŒãŸæƒ…å ±<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">ã“ã®ä½æ‰€ã«ã¯é…é€ã§ãã¾ã›ã‚“。別ã®ä½æ‰€ã‚’é¸æŠžã—ã¦ãã ã•ã„。</translation>
<translation id="7132939140423847331">ã“ã®ãƒ‡ãƒ¼ã‚¿ã®ã‚³ãƒ”ーã¯ç®¡ç†è€…ã«ã‚ˆã£ã¦ç¦æ­¢ã•ã‚Œã¦ã„ã¾ã™ã€‚</translation>
<translation id="7135130955892390533">ステータスを表示</translation>
@@ -1900,6 +1945,7 @@
<translation id="7192203810768312527"><ph name="SIZE" /> を解放ã—ã¾ã™ã€‚サイトã«ã‚ˆã£ã¦ã¯ã€æ¬¡å›žã‚¢ã‚¯ã‚»ã‚¹ã™ã‚‹éš›ã«èª­ã¿è¾¼ã¿ãŒã“ã‚Œã¾ã§ã‚ˆã‚Šé…ããªã‚‹å¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™ã€‚</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">管ç†è€…ã¯ã€ä»¥ä¸‹ã®æƒ…報を確èªã§ãã¾ã™ã€‚</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" /> ã§ã™ã€‚Tab キーã€Enter キーã®é †ã«æŠ¼ã™ã¨ã€æ–°ã—ã„シークレット タブを開ã„ã¦ã‚·ãƒ¼ã‚¯ãƒ¬ãƒƒãƒˆ モードã§ãƒ–ラウジングã—ã¾ã™</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> ã§ã¯ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£è¦æ ¼ãŒéµå®ˆã•ã‚Œã¦ã„ã¾ã›ã‚“。</translation>
<translation id="7210993021468939304">コンテナ内㮠Linux アクティビティã€ã‚³ãƒ³ãƒ†ãƒŠå†…ã§ã® Linux アプリã®ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã¨å®Ÿè¡Œ</translation>
@@ -1931,6 +1977,7 @@
<translation id="7304562222803846232">Google アカウントã®ãƒ—ライãƒã‚·ãƒ¼è¨­å®šã‚’管ç†ã™ã‚‹</translation>
<translation id="7305756307268530424">低速ã‹ã‚‰é–‹å§‹</translation>
<translation id="7308436126008021607">ãƒãƒƒã‚¯ã‚°ãƒ©ã‚¦ãƒ³ãƒ‰åŒæœŸ</translation>
+<translation id="7310392214323165548">é–“ã‚‚ãªãデãƒã‚¤ã‚¹ãŒå†èµ·å‹•ã—ã¾ã™</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">接続ã«é–¢ã™ã‚‹ãƒ˜ãƒ«ãƒ—</translation>
<translation id="7323804146520582233">「<ph name="SECTION" />ã€ã‚»ã‚¯ã‚·ãƒ§ãƒ³ã‚’éžè¡¨ç¤ºã«ã™ã‚‹</translation>
@@ -1938,6 +1985,7 @@
<translation id="7334320624316649418">é †åºå¤‰æ›´ã®ã‚„ã‚Šç›´ã—(&amp;R)</translation>
<translation id="7335157162773372339">カメラã®ä½¿ç”¨ã‚’è¦æ±‚ã§ãã‚‹</translation>
<translation id="7337248890521463931">表示ã™ã‚‹è¡Œæ•°ã‚’増やã™</translation>
+<translation id="7337418456231055214">仮想カード番å·ãŒå…¥åŠ›ã•ã‚Œãªã„å ´åˆã¯ã€ã‚«ãƒ¼ãƒ‰æƒ…報をクリックã—ã¦ã‚³ãƒ”ーã—ã¦ãã ã•ã„。<ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">ç¾åœ¨ã®ãƒ—ラットフォームã§ã¯ã”利用ã„ãŸã ã‘ã¾ã›ã‚“。</translation>
<translation id="733923710415886693">サーãƒãƒ¼ã®è¨¼æ˜Žæ›¸ã¯ã€è¨¼æ˜Žæ›¸ã®é€æ˜Žæ€§ãƒãƒªã‚·ãƒ¼ã‚’介ã—ã¦å…¬é–‹ã•ã‚Œã¦ã„ã¾ã›ã‚“。</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1960,6 +2008,7 @@
<translation id="7378627244592794276">ã„ã„ãˆ</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">対象外ã§ã™</translation>
+<translation id="7388594495505979117">{0,plural, =1{デãƒã‚¤ã‚¹ã¯ 1 分後ã«å†èµ·å‹•ã•ã‚Œã¾ã™}other{デãƒã‚¤ã‚¹ã¯ # 分後ã«å†èµ·å‹•ã•ã‚Œã¾ã™}}</translation>
<translation id="7390545607259442187">カードã®ç¢ºèª</translation>
<translation id="7392089738299859607">ä½æ‰€ã‚’æ›´æ–°</translation>
<translation id="7399802613464275309">安全確èª</translation>
@@ -1996,6 +2045,12 @@
<translation id="7485870689360869515">データãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。</translation>
<translation id="7495528107193238112">ã“ã®ã‚³ãƒ³ãƒ†ãƒ³ãƒ„ã¯ãƒ–ロックã•ã‚Œã¾ã—ãŸã€‚サイト所有者ã«é€£çµ¡ã—ã¦å•é¡Œã‚’解決ã—ã¦ãã ã•ã„。</translation>
<translation id="7497998058912824456">[ドキュメントを作æˆ] ボタンã§ã™ã€‚Enter キーを押ã™ã¨ã€æ–°ã—ã„ Google ドキュメントをã™ã°ã‚„ã作æˆã—ã¾ã™</translation>
+<translation id="7506488012654002225">Chrome ã«ã¯ã€æ¬¡ã®æƒ…å ±ã¯<ph name="BEGIN_EMPHASIS" />ä¿å­˜ã•ã‚Œã¾ã›ã‚“<ph name="END_EMPHASIS" />。
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />閲覧履歴
+ <ph name="LIST_ITEM" />Cookie ã¨ã‚µã‚¤ãƒˆãƒ‡ãƒ¼ã‚¿
+ <ph name="LIST_ITEM" />フォームã«å…¥åŠ›ã—ãŸæƒ…å ±
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">è¿”ã•ã‚ŒãŸãƒãƒªã‚·ãƒ¼ã®ãƒ‡ãƒã‚¤ã‚¹ ID ãŒç©ºã§ã‚ã‚‹ã‹ã€ç¾åœ¨ã®ãƒ‡ãƒã‚¤ã‚¹ ID ã¨ä¸€è‡´ã—ã¾ã›ã‚“</translation>
<translation id="7508870219247277067">アボカド グリーン</translation>
<translation id="7511955381719512146">ã”利用㮠Wi-Fi ã§ã¯ã€<ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> ã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ãŒå¿…è¦ãªå¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™ã€‚</translation>
@@ -2109,7 +2164,6 @@
<translation id="7813600968533626083">Chrome ã‹ã‚‰å€™è£œã‚’削除ã—ã¦ã‚‚よã‚ã—ã„ã§ã™ã‹ï¼Ÿ</translation>
<translation id="781440967107097262">クリップボードを共有ã—ã¾ã™ã‹ï¼Ÿ</translation>
<translation id="7815407501681723534">「<ph name="SEARCH_STRING" />ã€ã«å¯¾ã— <ph name="NUMBER_OF_RESULTS" /> 件㮠<ph name="SEARCH_RESULTS" />ãŒè¦‹ã¤ã‹ã‚Šã¾ã—ãŸ</translation>
-<translation id="782125616001965242">ã“ã®ã‚µã‚¤ãƒˆã®æƒ…報を表示ã—ã¾ã™</translation>
<translation id="782886543891417279">ã”利用㮠Wi-Fi(<ph name="WIFI_NAME" />)ã§ã¯ã€ãƒ­ã‚°ã‚¤ãƒ³ãƒšãƒ¼ã‚¸ã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ãŒå¿…è¦ãªå¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™ã€‚</translation>
<translation id="7836231406687464395">Postfix(å°ç­’)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{ãªã—}=1{1 個ã®ã‚¢ãƒ—リ(<ph name="EXAMPLE_APP_1" />)}=2{2 個ã®ã‚¢ãƒ—リ(<ph name="EXAMPLE_APP_1" />ã€<ph name="EXAMPLE_APP_2" />)}other{# 個ã®ã‚¢ãƒ—リ(<ph name="EXAMPLE_APP_1" />ã€<ph name="EXAMPLE_APP_2" />ã€<ph name="AND_MORE" />)}}</translation>
@@ -2126,7 +2180,6 @@
<translation id="7888575728750733395">å°åˆ·æ™‚ã®ãƒ¬ãƒ³ãƒ€ãƒªãƒ³ã‚° インテント</translation>
<translation id="7894280532028510793">タイプミスã§ãªã„å ´åˆã¯ã€<ph name="BEGIN_LINK" />ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯è¨ºæ–­ã‚’ãŠè©¦ã—ãã ã•ã„<ph name="END_LINK" />。</translation>
<translation id="7904208859782148177">C3(å°ç­’)</translation>
-<translation id="7931318309563332511">ä¸æ˜Ž</translation>
<translation id="793209273132572360">ä½æ‰€ã‚’æ›´æ–°ã—ã¾ã™ã‹ï¼Ÿ</translation>
<translation id="7932579305932748336">コーティング</translation>
<translation id="79338296614623784">有効ãªé›»è©±ç•ªå·ã‚’入力ã—ã¦ãã ã•ã„</translation>
@@ -2151,13 +2204,14 @@
<translation id="7976214039405368314">リクエストãŒå¤šã™ãŽã¾ã™</translation>
<translation id="7977538094055660992">出力デãƒã‚¤ã‚¹</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">リンクã•ã‚Œã¾ã—ãŸ:</translation>
<translation id="798134797138789862">ãƒãƒ¼ãƒãƒ£ãƒ« リアリティ デãƒã‚¤ã‚¹ã¨ãƒ‡ãƒ¼ã‚¿ã®ä½¿ç”¨ã‚’è¦æ±‚ã§ãã‚‹</translation>
<translation id="7984945080620862648"><ph name="SITE" /> ã‹ã‚‰ã€Chrome ã§å‡¦ç†ã§ããªã„スクランブル化ã•ã‚ŒãŸèªè¨¼æƒ…å ±ãŒè¿”ã•ã‚ŒãŸãŸã‚ã€ç¾åœ¨ã“ã®ã‚µã‚¤ãƒˆã«ã¯ã‚¢ã‚¯ã‚»ã‚¹ã§ãã¾ã›ã‚“。通常ã€ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ エラーやä¸æ­£ãªæ“作ã¯ä¸€æ™‚çš„ãªã‚‚ã®ã§ã™ã€‚å°‘ã—時間をãŠãã¨ã€ã¾ãŸãƒšãƒ¼ã‚¸ã«ã‚¢ã‚¯ã‚»ã‚¹ã§ãるよã†ã«ãªã‚‹å¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™ã€‚</translation>
-<translation id="79859296434321399">æ‹¡å¼µç¾å®Ÿï¼ˆAR)コンテンツを表示ã™ã‚‹ã«ã¯ ARCore をインストールã—ã¦ãã ã•ã„</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">製本</translation>
<translation id="7992044431894087211"><ph name="APPLICATION_TITLE" /> ã¨ã®ç”»é¢å…±æœ‰ãŒå†é–‹ã•ã‚Œã¾ã—ãŸ</translation>
<translation id="7995512525968007366">指定ãªã—</translation>
+<translation id="7998269595945679889">シークレット タブを開ãボタンã§ã™ã€‚Enter キーを押ã™ã¨ã€æ–°ã—ã„シークレット タブを開ã„ã¦ã‚·ãƒ¼ã‚¯ãƒ¬ãƒƒãƒˆ モードã§ãƒ–ラウジングã—ã¾ã™</translation>
<translation id="800218591365569300">メモリを解放ã™ã‚‹ãŸã‚ã«ã€ä»–ã®ã‚¿ãƒ–やプログラムを閉ã˜ã¦ã¿ã¦ãã ã•ã„。</translation>
<translation id="8004582292198964060">ブラウザ</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{ã“ã®ã‚«ãƒ¼ãƒ‰ã¨è«‹æ±‚å…ˆä½æ‰€ã¯ä¿å­˜ã•ã‚Œã€<ph name="USER_EMAIL" /> ã«ãƒ­ã‚°ã‚¤ãƒ³ã™ã‚‹ã¨ä½¿ç”¨ã§ãã¾ã™ã€‚}other{ã“れらã®ã‚«ãƒ¼ãƒ‰ã¨è«‹æ±‚å…ˆä½æ‰€ã¯ä¿å­˜ã•ã‚Œã€<ph name="USER_EMAIL" /> ã«ãƒ­ã‚°ã‚¤ãƒ³ã™ã‚‹ã¨ä½¿ç”¨ã§ãã¾ã™ã€‚}}</translation>
@@ -2217,6 +2271,7 @@
<translation id="8202370299023114387">競åˆ</translation>
<translation id="8206978196348664717">Prc4(å°ç­’)</translation>
<translation id="8211406090763984747">ã“ã®æŽ¥ç¶šã¯ä¿è­·ã•ã‚Œã¦ã„ã¾ã™</translation>
+<translation id="8217240300496046857">サイト㯠Cookie を使用ã—ã¦ã‚ãªãŸã‚’ウェブ上ã§ãƒˆãƒ©ãƒƒã‚­ãƒ³ã‚°ã§ãã¾ã›ã‚“。一部サイトã®æ©Ÿèƒ½ãŒä½¿ç”¨ã§ããªããªã‚‹å¯èƒ½æ€§ã‚‚ã‚ã‚Šã¾ã™ã€‚</translation>
<translation id="8218327578424803826">割り当ã¦ã‚‰ã‚ŒãŸå ´æ‰€:</translation>
<translation id="8220146938470311105">C7 / C6(å°ç­’)</translation>
<translation id="8225771182978767009">ã“ã®ã‚µã‚¤ãƒˆã¯ã€ã“ã®ãƒ‘ソコンを設定ã—ãŸãƒ¦ãƒ¼ã‚¶ãƒ¼ã«ã‚ˆã£ã¦ãƒ–ロックã•ã‚Œã¦ã„ã¾ã™ã€‚</translation>
@@ -2257,14 +2312,9 @@
<translation id="830498451218851433">2 ã¤æŠ˜ã‚Š</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">インストールã—ãŸã‚¢ãƒ—リã¨ä½¿ç”¨é »åº¦</translation>
+<translation id="8317207217658302555">ARCore ã‚’æ›´æ–°ã—ã¾ã™ã‹ï¼Ÿ</translation>
<translation id="831997045666694187">夕方</translation>
<translation id="8321476692217554900">通知</translation>
-<translation id="8328484624016508118">ã™ã¹ã¦ã®ã‚·ãƒ¼ã‚¯ãƒ¬ãƒƒãƒˆ タブを閉ã˜ã‚‹ã¨ã€Chrome ã§ä»¥ä¸‹ã®ãƒ‡ãƒ¼ã‚¿ãŒå‰Šé™¤ã•ã‚Œã¾ã™ã€‚
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />ã“ã®ãƒ‡ãƒã‚¤ã‚¹ã§ã®é–²è¦§ã‚¢ã‚¯ãƒ†ã‚£ãƒ“ティ<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />ã“ã®ãƒ‡ãƒã‚¤ã‚¹ã§ã®æ¤œç´¢å±¥æ­´<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />フォームã«å…¥åŠ›ã—ãŸæƒ…å ±<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489"><ph name="HOST_NAME" /> ã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ãŒæ‹’å¦ã•ã‚Œã¾ã—ãŸ</translation>
<translation id="833262891116910667">ãƒã‚¤ãƒ©ã‚¤ãƒˆè¡¨ç¤º</translation>
<translation id="8339163506404995330"><ph name="LANGUAGE" />ã®ãƒšãƒ¼ã‚¸ã¯ç¿»è¨³ã•ã‚Œã¾ã›ã‚“</translation>
@@ -2316,6 +2366,7 @@
<translation id="8507227106804027148">コマンドライン</translation>
<translation id="8508648098325802031">検索アイコン</translation>
<translation id="8511402995811232419">Cookie を管ç†ã™ã‚‹</translation>
+<translation id="8519753333133776369">管ç†è€…ãŒè¨±å¯ã—㟠HID デãƒã‚¤ã‚¹</translation>
<translation id="8522552481199248698">Chrome ã«ã¯ Google アカウントã®ä¿è­·ã¨ãƒ‘スワードã®å¤‰æ›´ã‚’サãƒãƒ¼ãƒˆã™ã‚‹æ©Ÿèƒ½ãŒã‚ã‚Šã¾ã™ã€‚</translation>
<translation id="8530813470445476232">Chrome ã®è¨­å®šã§é–²è¦§å±¥æ­´ã€Cookieã€ã‚­ãƒ£ãƒƒã‚·ãƒ¥ãªã©ã‚’消去ã™ã‚‹</translation>
<translation id="8533619373899488139">&lt;strong&gt;chrome://policy&lt;/strong&gt; ã§ã€ãƒ–ロックã•ã‚ŒãŸ URL ã®ãƒªã‚¹ãƒˆã¨ã‚·ã‚¹ãƒ†ãƒ ç®¡ç†è€…ãŒè¨­å®šã—ãŸä»–ã®ãƒãƒªã‚·ãƒ¼ã‚’確èªã§ãã¾ã™ã€‚</translation>
@@ -2327,7 +2378,6 @@
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{権é™ã‚’リセット}other{権é™ã‚’リセット}}</translation>
<translation id="8555010941760982128">ã”購入手続ã時ã«ã“ã®ã‚³ãƒ¼ãƒ‰ã‚’使用</translation>
<translation id="8557066899867184262">CVC ã¯ã‚«ãƒ¼ãƒ‰ã®è£é¢ã«è¨˜è¼‰ã•ã‚Œã¦ã„ã¾ã™ã€‚</translation>
-<translation id="8558485628462305855">æ‹¡å¼µç¾å®Ÿï¼ˆAR)コンテンツを表示ã™ã‚‹ã«ã¯ ARCore ã‚’æ›´æ–°ã—ã¦ãã ã•ã„</translation>
<translation id="8559762987265718583">デãƒã‚¤ã‚¹ã®æ—¥æ™‚(<ph name="DATE_AND_TIME" />)ãŒæ­£ã—ããªã„ãŸã‚ã€<ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> ã¸ã®ãƒ—ライベート接続を確立ã§ãã¾ã›ã‚“。</translation>
<translation id="8564182942834072828">個別ã®ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆï¼ˆä¸åˆã„ãªã—)</translation>
<translation id="8564985650692024650"><ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> パスワードを他ã®ã‚µã‚¤ãƒˆã§å†ä½¿ç”¨ã—ãŸå ´åˆã€Chromium ã§ã¯ãƒ‘スワードã®å†è¨­å®šã‚’促ã™ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ãŒè¡¨ç¤ºã•ã‚Œã¾ã™ã€‚</translation>
@@ -2347,6 +2397,7 @@
<translation id="865032292777205197">モーション センサー</translation>
<translation id="8663226718884576429">ã”注文ã®æ¦‚è¦ã€<ph name="TOTAL_LABEL" />ã€ãã®ä»–ã®è©³ç´°</translation>
<translation id="8666678546361132282">英語</translation>
+<translation id="8669306706049782872">ç”»é¢ã«é–¢ã™ã‚‹æƒ…報を基ã«ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã‚’é–‹ã„ã¦é…ç½®ã™ã‚‹</translation>
<translation id="867224526087042813">ç½²å</translation>
<translation id="8676424191133491403">今ã™ã</translation>
<translation id="8680536109547170164">「<ph name="QUERY" />ã€ã«å¯¾ã™ã‚‹ç­”ãˆ: 「<ph name="ANSWER" />ã€</translation>
@@ -2373,6 +2424,7 @@
<translation id="8731544501227493793">パスワードを管ç†ã™ã‚‹ãƒœã‚¿ãƒ³ã§ã™ã€‚Enter キーを押ã™ã¨ Chrome ã®è¨­å®šã§ãƒ‘スワードを表示ã€ç®¡ç†ã—ã¾ã™</translation>
<translation id="8734529307927223492">ã“ã® <ph name="DEVICE_TYPE" /> 㯠<ph name="MANAGER" /> ã«ã‚ˆã£ã¦ç®¡ç†ã•ã‚Œã¦ã„ã¾ã™</translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" /> ã§ã™ã€‚Tab キーã€Enter キーã®é †ã«æŠ¼ã™ã¨ã€æ–°ã—ã„シークレット ウィンドウを開ã„ã¦ã‚·ãƒ¼ã‚¯ãƒ¬ãƒƒãƒˆ モードã§ãƒ–ラウジングã—ã¾ã™</translation>
+<translation id="8737685506611670901"><ph name="REPLACED_HANDLER_TITLE" /> ã®ä»£ã‚ã‚Šã«ã€Œ<ph name="PROTOCOL" />ã€ãƒªãƒ³ã‚¯ã‚’é–‹ã</translation>
<translation id="8738058698779197622">安全ãªæŽ¥ç¶šã‚’確立ã™ã‚‹ã«ã¯æ™‚計ãŒæ­£ã—ã設定ã•ã‚Œã¦ã„ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚ã“ã®ç†ç”±ã¯ã€æœ¬ç‰©ã®ã‚¦ã‚§ãƒ–サイトã§ã‚ã‚‹ã“ã¨ã‚’示ã™ãŸã‚ã«ã‚¦ã‚§ãƒ–サイトã§ä½¿ç”¨ã•ã‚Œã‚‹è¨¼æ˜Žæ›¸ã«ã¯ã€æœ‰åŠ¹æœŸé–“(発効日時ã¨å¤±åŠ¹æ—¥æ™‚)ãŒè¨­å®šã•ã‚Œã¦ã„ã‚‹ãŸã‚ã§ã™ã€‚デãƒã‚¤ã‚¹ã®æ™‚計ãŒæ­£ã—ããªã„ãŸã‚ã€Chromium ã§ã¯ã“れらã®è¨¼æ˜Žæ›¸ã‚’確èªã§ãã¾ã›ã‚“。</translation>
<translation id="8740359287975076522"><ph name="HOST_NAME" /> ã® &lt;abbr id="dnsDefinition"&gt;DNS アドレス&lt;/abbr&gt;ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸã€‚å•é¡Œã‚’診断ã—ã¦ã„ã¾ã™ã€‚</translation>
<translation id="8742371904523228557"><ph name="ORIGIN" /> ã®ã‚³ãƒ¼ãƒ‰ã¯ã€Œ<ph name="ONE_TIME_CODE" />ã€ã§ã™</translation>
@@ -2400,6 +2452,7 @@
<translation id="883848425547221593">ãã®ä»–ã®ãƒ–ックマーク</translation>
<translation id="884264119367021077">é…é€å…ˆä½æ‰€</translation>
<translation id="884923133447025588">å–り消ã—機構ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。</translation>
+<translation id="8849262850971482943">セキュリティを強化ã™ã‚‹ã«ã¯ä»®æƒ³ã‚«ãƒ¼ãƒ‰ã‚’使用ã—ã¦ãã ã•ã„</translation>
<translation id="885730110891505394">Google ã¨ã®å…±æœ‰</translation>
<translation id="8858065207712248076"><ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> パスワードを他ã®ã‚µã‚¤ãƒˆã§å†ä½¿ç”¨ã—ãŸå ´åˆã€Chrome ã§ã¯ãƒ‘スワードã®å†è¨­å®šã‚’促ã™ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ãŒè¡¨ç¤ºã•ã‚Œã¾ã™ã€‚</translation>
<translation id="885906927438988819">タイプミスã§ãªã„å ´åˆã¯ã€<ph name="BEGIN_LINK" />Windows ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯è¨ºæ–­ã‚’ãŠè©¦ã—ãã ã•ã„<ph name="END_LINK" />。</translation>
@@ -2449,6 +2502,7 @@
<translation id="9004367719664099443">VR セッションãŒé€²è¡Œä¸­</translation>
<translation id="9005998258318286617">PDF ドキュメントを読ã¿è¾¼ã‚ã¾ã›ã‚“ã§ã—ãŸã€‚</translation>
<translation id="9008201768610948239">無視ã™ã‚‹</translation>
+<translation id="901834265349196618">メール</translation>
<translation id="9020200922353704812">カードã®è«‹æ±‚å…ˆä½æ‰€ã‚’入力ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™</translation>
<translation id="9020542370529661692">ã“ã®ãƒšãƒ¼ã‚¸ã¯<ph name="TARGET_LANGUAGE" />ã«ç¿»è¨³ã•ã‚Œã¦ã„ã¾ã™</translation>
<translation id="9020742383383852663">A8</translation>
@@ -2497,6 +2551,7 @@
<translation id="9150045010208374699">カメラを使用ã™ã‚‹</translation>
<translation id="9150685862434908345">管ç†è€…ã¯ãƒ–ラウザã®è¨­å®šã‚’リモートã§å¤‰æ›´ã§ãã¾ã™ã€‚ã“ã®ãƒ‡ãƒã‚¤ã‚¹ã§ã®ã‚¢ã‚¯ãƒ†ã‚£ãƒ“ティã¯ã€Chrome 以外ã§ã‚‚管ç†ã•ã‚Œã¦ã„ã‚‹å¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™ã€‚<ph name="BEGIN_LINK" />詳細<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">更新完了</translation>
+<translation id="9155211586651734179">接続ã•ã‚ŒãŸã‚ªãƒ¼ãƒ‡ã‚£ã‚ªå‘¨è¾ºæ©Ÿå™¨</translation>
<translation id="9157595877708044936">セットアップ中...</translation>
<translation id="9158625974267017556">C6(å°ç­’)</translation>
<translation id="9164029392738894042">正確性ãƒã‚§ãƒƒã‚¯</translation>
diff --git a/chromium/components/strings/components_strings_ka.xtb b/chromium/components/strings/components_strings_ka.xtb
index 17b82e0c4b9..3355b7c6090 100644
--- a/chromium/components/strings/components_strings_ka.xtb
+++ b/chromium/components/strings/components_strings_ka.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">დეტáƒáƒšáƒ”ბის ნáƒáƒ®áƒ•áƒ</translation>
<translation id="1030706264415084469"><ph name="URL" /> ითხáƒáƒ•áƒ¡ თქვენს მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘áƒáƒ–ე დიდი მáƒáƒªáƒ£áƒšáƒáƒ‘ის მáƒáƒœáƒáƒªáƒ”მების სáƒáƒ›áƒ£áƒ“áƒáƒ›áƒáƒ“ შენáƒáƒ®áƒ•áƒ˜áƒ¡ ნებáƒáƒ áƒ—ვáƒáƒ¡</translation>
<translation id="1032854598605920125">სáƒáƒáƒ—ის ისრის მიმáƒáƒ áƒ—ულებით შემáƒáƒ¢áƒ áƒ˜áƒáƒšáƒ”ბáƒ</translation>
+<translation id="1033329911862281889">ინკáƒáƒ’ნიტრრეჟიმი იმáƒáƒ¡ áƒáƒ  ნიშნáƒáƒ•áƒ¡, რáƒáƒ› უჩინáƒáƒ áƒ˜ იქნებით áƒáƒœáƒšáƒáƒ˜áƒœ:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />სáƒáƒ˜áƒ¢áƒ”ბს დრსერვისებს ეცáƒáƒ“ინებáƒáƒ— მáƒáƒ—ი მáƒáƒœáƒáƒ®áƒ£áƒšáƒ”ბის áƒáƒœ მáƒáƒ—ით სáƒáƒ áƒ’ებლáƒáƒ‘ის შესáƒáƒ®áƒ”ბ<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />დáƒáƒ›áƒ¡áƒáƒ¥áƒ›áƒ”ბლებს áƒáƒœ სáƒáƒ¡áƒ¬áƒáƒ•áƒšáƒ”ბლებს შეუძლიáƒáƒ— ვების დáƒáƒ—ვáƒáƒšáƒ˜áƒ”რების áƒáƒ¥áƒ¢áƒ˜áƒ•áƒáƒ‘ის გáƒáƒ™áƒáƒœáƒ¢áƒ áƒáƒšáƒ”ბáƒ<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ინტერნეტ-პრáƒáƒ•áƒáƒ˜áƒ“ერებს შეუძლიáƒáƒ— ვებტრáƒáƒ¤áƒ˜áƒ™áƒ˜áƒ¡ მáƒáƒœáƒ˜áƒ¢áƒáƒ áƒ˜áƒœáƒ’ი<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">გáƒáƒ›áƒáƒ áƒ—ვáƒ</translation>
<translation id="1036982837258183574">სრულეკრáƒáƒœáƒ˜áƒáƒœáƒ˜ რეჟიმიდáƒáƒœ გáƒáƒ›áƒáƒ¡áƒáƒ¡áƒ•áƒšáƒ”ლáƒáƒ“, დáƒáƒáƒ­áƒ˜áƒ áƒ”თ კლáƒáƒ•áƒ˜áƒ¨áƒ–ე |<ph name="ACCELERATOR" />|</translation>
<translation id="1038106730571050514">შეთáƒáƒ•áƒáƒ–ებების ჩვენებáƒ</translation>
<translation id="1038842779957582377">უცნáƒáƒ‘ი სáƒáƒ®áƒ”ლი</translation>
<translation id="1041998700806130099">დáƒáƒ•áƒáƒšáƒ”ბáƒáƒ—რფურცლის შეტყáƒáƒ‘ინებáƒ</translation>
<translation id="1048785276086539861">áƒáƒœáƒáƒ¢áƒáƒªáƒ˜áƒ”ბის რედáƒáƒ¥áƒ¢áƒ˜áƒ áƒ”ბისáƒáƒ¡ ეს დáƒáƒ™áƒ£áƒ›áƒ”ნტი დáƒáƒ‘რუნდებრერთგვერდიáƒáƒœ ხედზე</translation>
-<translation id="1049743911850919806">ინკáƒáƒ’ნიტáƒ</translation>
<translation id="1050038467049342496">სხვრáƒáƒžáƒ”ბის დáƒáƒ®áƒ£áƒ áƒ•áƒ</translation>
<translation id="1055184225775184556">დრდáƒáƒ‘რუნებáƒ-დáƒáƒ›áƒáƒ¢áƒ”ბáƒ</translation>
<translation id="1056898198331236512">გáƒáƒ¤áƒ áƒ—ხილებáƒ</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">წესის ქეში OK</translation>
<translation id="1130564665089811311">გვერდის თáƒáƒ áƒ’მნის ღილáƒáƒ™áƒ˜, áƒáƒ› გვერდის Google Translate-ით სáƒáƒ—áƒáƒ áƒ’მნáƒáƒ“ დáƒáƒáƒ­áƒ˜áƒ áƒ”თ კლáƒáƒ•áƒ˜áƒ¨áƒ¡ Enter</translation>
<translation id="1131264053432022307">თქვენ მიერ კáƒáƒžáƒ˜áƒ áƒ”ბული სურáƒáƒ—ი</translation>
+<translation id="1142846828089312304">მესáƒáƒ›áƒ” მხáƒáƒ áƒ˜áƒ¡ ქუქი-ჩáƒáƒœáƒáƒ¬áƒ”რების დáƒáƒ‘ლáƒáƒ™áƒ•áƒ ინკáƒáƒ’ნიტრრეჟიმში</translation>
<translation id="1150979032973867961">ეს სერვერი ვერ áƒáƒ›áƒ¢áƒ™áƒ˜áƒªáƒ”ბს, რáƒáƒ› ის áƒáƒ áƒ˜áƒ¡ <ph name="DOMAIN" />; მისი უსáƒáƒ¤áƒ áƒ—ხáƒáƒ”ბის სერთიფიკáƒáƒ¢áƒ˜ áƒáƒ  ენდáƒáƒ‘რთქვენი კáƒáƒ›áƒžáƒ˜áƒ£áƒ¢áƒ”რის áƒáƒžáƒ”რáƒáƒªáƒ˜áƒ£áƒš სისტემáƒáƒ¡. ეს შეიძლებრიყáƒáƒ¡ გáƒáƒ›áƒáƒ¬áƒ•áƒ”ული áƒáƒ áƒáƒ¡áƒ¬áƒáƒ áƒ˜ კáƒáƒœáƒ¤áƒ˜áƒ’ურáƒáƒªáƒ˜áƒ˜áƒ— áƒáƒœ თáƒáƒ•áƒ“áƒáƒ›áƒ¡áƒ®áƒ›áƒ”ლის მიერ თქვენი კáƒáƒ•áƒ¨áƒ˜áƒ áƒ˜áƒ¡ გáƒáƒ“áƒáƒ­áƒ áƒ˜áƒ—.</translation>
<translation id="1151972924205500581">სáƒáƒ­áƒ˜áƒ áƒáƒ პáƒáƒ áƒáƒšáƒ˜</translation>
<translation id="1156303062776767266">თქვენ áƒáƒ—ვáƒáƒšáƒ˜áƒ”რებთ áƒáƒ“გილáƒáƒ‘რივ áƒáƒœ გáƒáƒ–იáƒáƒ áƒ”ბულ ფáƒáƒ˜áƒšáƒ¡</translation>
@@ -64,7 +70,6 @@
<translation id="1178581264944972037">პáƒáƒ£áƒ–áƒ</translation>
<translation id="1181037720776840403">áƒáƒ›áƒáƒ¨áƒšáƒ</translation>
<translation id="1186201132766001848">პáƒáƒ áƒáƒšáƒ”ბის შემáƒáƒ¬áƒ›áƒ”ბáƒ</translation>
-<translation id="1195210374336998651">áƒáƒžáƒ˜áƒ¡ პáƒáƒ áƒáƒ›áƒ”ტრებზე გáƒáƒ“áƒáƒ¡áƒ•áƒšáƒ</translation>
<translation id="1195558154361252544">შეტყáƒáƒ‘ინებები áƒáƒ•áƒ¢áƒáƒ›áƒáƒ¢áƒ£áƒ áƒáƒ“ დáƒáƒ‘ლáƒáƒ™áƒ˜áƒšáƒ˜áƒ ყველრსáƒáƒ˜áƒ¢áƒ˜áƒ¡áƒ—ვის, გáƒáƒ áƒ“რთქვენ მიერ დáƒáƒ¨áƒ•áƒ”ბულისáƒ</translation>
<translation id="1197088940767939838">ნáƒáƒ áƒ˜áƒœáƒ¯áƒ˜áƒ¡áƒ¤áƒ”რი</translation>
<translation id="1201402288615127009">შემდეგი</translation>
@@ -111,7 +116,7 @@
<translation id="1307966114820526988">მáƒáƒ«áƒ•áƒ”ლებული ფუნქციები</translation>
<translation id="1308113895091915999">ხელმისáƒáƒ¬áƒ•áƒ“áƒáƒ›áƒ˜áƒ შემáƒáƒ—áƒáƒ•áƒáƒ–ებáƒ</translation>
<translation id="1312803275555673949">რრáƒáƒ¡áƒáƒ‘უთებს?</translation>
-<translation id="131405271941274527"><ph name="URL" /> ითხáƒáƒ•áƒ¡ ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ˜áƒ¡ გáƒáƒ’ზáƒáƒ•áƒœáƒáƒ¡/მიღებáƒáƒ¡ NFC მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘áƒáƒ–ე თქვენს ტელეფáƒáƒœáƒ–ე შეხებისáƒáƒ¡</translation>
+<translation id="1314311879718644478">áƒáƒ£áƒ’მენტური რეáƒáƒšáƒáƒ‘ის კáƒáƒœáƒ¢áƒ”ნტის ნáƒáƒ®áƒ•áƒ</translation>
<translation id="1314509827145471431">áƒáƒ™áƒ˜áƒœáƒ«áƒ•áƒ მáƒáƒ áƒ¯áƒ•áƒœáƒ˜áƒ•</translation>
<translation id="1318023360584041678">შენáƒáƒ®áƒ£áƒšáƒ˜áƒ ჩáƒáƒœáƒáƒ áƒ—ების ჯგუფში</translation>
<translation id="1319245136674974084">áƒáƒ› áƒáƒžáƒ˜áƒ¡áƒ—ვის áƒáƒ¦áƒáƒ áƒáƒ¡áƒáƒ“ეს კითხვáƒ</translation>
@@ -161,6 +166,7 @@
<translation id="142858679511221695">ღრუბლის მáƒáƒ›áƒ®áƒ›áƒáƒ áƒ”ბელი</translation>
<translation id="1428729058023778569">áƒáƒ› გáƒáƒ¤áƒ áƒ—ხილებáƒáƒ¡ ხედáƒáƒ•áƒ— იმიტáƒáƒ›, რáƒáƒ› áƒáƒ› სáƒáƒ˜áƒ¢áƒ˜áƒ¡ მიერ HTTPS მხáƒáƒ áƒ“áƒáƒ£áƒ­áƒ”რელიáƒ. <ph name="BEGIN_LEARN_MORE_LINK" />შეიტყვეთ მეტი<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">ბეჭდვáƒ</translation>
+<translation id="1432187715652018471">გვერდს სურს სერვისის დáƒáƒ›áƒ›áƒ£áƒ¨áƒáƒ•áƒ”ბლის ინსტáƒáƒšáƒáƒªáƒ˜áƒ.</translation>
<translation id="1432581352905426595">სáƒáƒ«áƒ˜áƒ”ბრსისტემების მáƒáƒ áƒ—ვáƒ</translation>
<translation id="1436185428532214179">შეუძლირთქვენს მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘áƒáƒ–ე áƒáƒ áƒ¡áƒ”ბული ფáƒáƒ˜áƒšáƒ”ბისრდრსáƒáƒ¥áƒáƒ¦áƒáƒšáƒ“ეების რედáƒáƒ¥áƒ¢áƒ˜áƒ áƒ”ბის თხáƒáƒ•áƒœáƒ</translation>
<translation id="1442386063175183758">მáƒáƒ áƒ¯áƒ•áƒœáƒ˜áƒ• დáƒáƒ™áƒ”ცვრჭიშკრის ფáƒáƒ áƒ›áƒ˜áƒ—</translation>
@@ -181,6 +187,12 @@
<translation id="1483493594462132177">გáƒáƒ’ზáƒáƒ•áƒœáƒ</translation>
<translation id="1484290072879560759">მიწáƒáƒ“ების მისáƒáƒ›áƒáƒ áƒ—ის áƒáƒ áƒ©áƒ”ვáƒ</translation>
<translation id="1492194039220927094">წესების გáƒáƒ“მáƒáƒ¢áƒáƒœáƒ:</translation>
+<translation id="149293076951187737">Chrome-ის ყველრინკáƒáƒ’ნიტრჩáƒáƒœáƒáƒ áƒ—ის დáƒáƒ®áƒ£áƒ áƒ•áƒ˜áƒ¡ შემდეგ თქვენი áƒáƒ¥áƒ¢áƒ˜áƒ•áƒáƒ‘რáƒáƒ› ჩáƒáƒœáƒáƒ áƒ—ებში áƒáƒ› მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘იდáƒáƒœ წáƒáƒ˜áƒ¨áƒšáƒ”ბáƒ:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />დáƒáƒ—ვáƒáƒšáƒ˜áƒ”რების áƒáƒ¥áƒ¢áƒ˜áƒ•áƒáƒ‘áƒ<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ძიების ისტáƒáƒ áƒ˜áƒ<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ფáƒáƒ áƒ›áƒ”ბში მითითებული ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">ჩáƒáƒœáƒáƒ áƒ—ზე დáƒáƒ‘რუნებáƒ</translation>
<translation id="1501859676467574491">Google áƒáƒœáƒ’áƒáƒ áƒ˜áƒ¨áƒ¨áƒ˜ შენáƒáƒ®áƒ£áƒšáƒ˜ ბáƒáƒ áƒáƒ—ების ჩვენებáƒ</translation>
<translation id="1507202001669085618">&lt;p&gt;áƒáƒ› ტიპის შეცდáƒáƒ›áƒ˜áƒ¡ შესáƒáƒ®áƒ”ბ შეტყáƒáƒ‘ინებáƒáƒ¡ დáƒáƒ˜áƒœáƒáƒ®áƒáƒ•áƒ— იმ შემთხვევáƒáƒ¨áƒ˜, თუ ისეთ Wi-Fi პáƒáƒ áƒ¢áƒáƒšáƒ¡ იყენებთ, რáƒáƒ›áƒ”ლიც მáƒáƒ˜áƒ—ხáƒáƒ•áƒ¡ სისტემáƒáƒ¨áƒ˜ შესვლáƒáƒ¡ ინტერნეტ-კáƒáƒ•áƒ¨áƒ˜áƒ áƒ˜áƒ¡ უზრუნველსáƒáƒ§áƒáƒ¤áƒáƒ“.&lt;/p&gt;
@@ -208,6 +220,8 @@
<translation id="1559572115229829303">&lt;p&gt;<ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />-თáƒáƒœ პირáƒáƒ“ი კáƒáƒ•áƒ¨áƒ˜áƒ áƒ˜ ვერ მყáƒáƒ áƒ“ებáƒ, რáƒáƒ“გáƒáƒœ თქვენი მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘ის თáƒáƒ áƒ˜áƒ¦áƒ˜ დრდრრ(<ph name="DATE_AND_TIME" />) áƒáƒ áƒáƒ¡áƒ¬áƒáƒ áƒ˜áƒ.&lt;/p&gt;
&lt;p&gt;გთხáƒáƒ•áƒ—, გáƒáƒáƒ¡áƒ¬áƒáƒ áƒáƒ— თáƒáƒ áƒ˜áƒ¦áƒ˜ დრდრრ&lt;strong&gt;პáƒáƒ áƒáƒ›áƒ”ტრების&lt;/strong&gt; áƒáƒžáƒ˜áƒ¡ სექციიდáƒáƒœ &lt;strong&gt;ზáƒáƒ’áƒáƒ“ი&lt;/strong&gt;.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">თქვენი áƒáƒ“მინისტრáƒáƒ¢áƒáƒ áƒ˜ გáƒáƒ“áƒáƒ¢áƒ•áƒ˜áƒ áƒ—áƒáƒ•áƒ¡ თქვენს მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘áƒáƒ¡ <ph name="DATE" />-ის <ph name="TIME" />-ზე</translation>
+<translation id="156703335097561114">ქსელთáƒáƒœ დáƒáƒ™áƒáƒ•áƒ¨áƒ˜áƒ áƒ”ბული ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ, რáƒáƒ’áƒáƒ áƒ˜áƒªáƒáƒ, მáƒáƒ’áƒáƒšáƒ˜áƒ—áƒáƒ“, მისáƒáƒ›áƒáƒ áƒ—ები, ინტერფეისის კáƒáƒœáƒ¤áƒ˜áƒ’ურáƒáƒªáƒ˜áƒ დრკáƒáƒ•áƒ¨áƒ˜áƒ áƒ˜áƒ¡ ხáƒáƒ áƒ˜áƒ¡áƒ®áƒ˜</translation>
<translation id="1567040042588613346">ეს წესები სáƒáƒ—áƒáƒœáƒáƒ“áƒáƒ“ მუშáƒáƒáƒ‘ს, თუმცრსხვáƒáƒ’áƒáƒœ დáƒáƒ§áƒ”ნებულირიგივე მნიშვნელáƒáƒ‘áƒ, რáƒáƒ›áƒ”ლსáƒáƒª ეს წესები áƒáƒœáƒáƒªáƒ•áƒšáƒ”ბს.</translation>
<translation id="1569487616857761740">შეიყვáƒáƒœáƒ”თ მáƒáƒ¥áƒ›áƒ”დების ვáƒáƒ“ის გáƒáƒ¡áƒ•áƒšáƒ˜áƒ¡ თáƒáƒ áƒ˜áƒ¦áƒ˜</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@
<translation id="1583429793053364125">áƒáƒ› ვებგვერდის ჩვენებისáƒáƒ¡ პრáƒáƒ‘ლემრწáƒáƒ áƒ›áƒáƒ˜áƒ¥áƒ›áƒœáƒ.</translation>
<translation id="1586541204584340881">თქვენ მიერ დáƒáƒ˜áƒœáƒ¡áƒ¢áƒáƒšáƒ˜áƒ áƒ”ბული გáƒáƒ¤áƒáƒ áƒ—áƒáƒ”ბები</translation>
<translation id="1588438908519853928">ნáƒáƒ áƒ›áƒáƒšáƒ£áƒ áƒ˜</translation>
+<translation id="1589050138437146318">გსურთ, დáƒáƒáƒ˜áƒœáƒ¡áƒ¢áƒáƒšáƒ˜áƒ áƒáƒ— ARCore?</translation>
<translation id="1592005682883173041">áƒáƒ“გილáƒáƒ‘რივ მáƒáƒœáƒáƒªáƒ”მებზე წვდáƒáƒ›áƒ</translation>
<translation id="1594030484168838125">áƒáƒ áƒ©áƒ”ვáƒ</translation>
<translation id="160851722280695521">დინáƒáƒ–áƒáƒ•áƒ áƒ˜áƒ¡ გáƒáƒ áƒ‘ენის თáƒáƒ›áƒáƒ¨áƒ˜áƒ¡ თáƒáƒ›áƒáƒ¨áƒ˜ Chrome-ში</translation>
@@ -254,7 +269,7 @@
<translation id="1711234383449478798">იგნáƒáƒ áƒ˜áƒ áƒ”ბულიáƒ, რáƒáƒ“გáƒáƒœ <ph name="POLICY_NAME" />-ის მნიშვნელáƒáƒ‘რáƒáƒ  áƒáƒ áƒ˜áƒ¡ <ph name="VALUE" />.</translation>
<translation id="1712552549805331520"><ph name="URL" /> ითხáƒáƒ•áƒ¡ თქვენს áƒáƒ“გილáƒáƒ‘რივ კáƒáƒ›áƒžáƒ˜áƒ£áƒ¢áƒ”რზე მáƒáƒœáƒáƒªáƒ”მების სáƒáƒ›áƒ£áƒ“áƒáƒ›áƒáƒ“ შენáƒáƒ®áƒ•áƒ˜áƒ¡ ნებáƒáƒ áƒ—ვáƒáƒ¡</translation>
<translation id="1713628304598226412">ლáƒáƒœáƒ’áƒáƒ áƒ˜ 2</translation>
-<translation id="1715874602234207">F</translation>
+<translation id="1715874602234207">პ</translation>
<translation id="1717218214683051432">მáƒáƒ«áƒ áƒáƒáƒ‘ის სენსáƒáƒ áƒ”ბი</translation>
<translation id="1717494416764505390">სáƒáƒ¤áƒáƒ¡áƒ¢áƒ ყუთი 3</translation>
<translation id="1718029547804390981">დáƒáƒ™áƒ£áƒ›áƒ”ნტი áƒáƒœáƒáƒ¢áƒ˜áƒ áƒ”ბისთვის მეტისმეტáƒáƒ“ დიდიáƒ</translation>
@@ -279,6 +294,7 @@
<translation id="1763864636252898013">ეს ს ერვერი ვერ áƒáƒ›áƒ¢áƒ™áƒ˜áƒªáƒ”ბს, რáƒáƒ› ის áƒáƒ áƒ˜áƒ¡ <ph name="DOMAIN" />; მისი უსáƒáƒ¤áƒ áƒ—ხáƒáƒ”ბის სერთიფიკáƒáƒ¢áƒ˜ áƒáƒ  ენდáƒáƒ‘რთქვენი მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘ის áƒáƒžáƒ”რáƒáƒªáƒ˜áƒ£áƒš სისტემáƒáƒ¡. ეს შეიძლებრიყáƒáƒ¡ გáƒáƒ›áƒáƒ¬áƒ•áƒ”ული áƒáƒ áƒáƒ¡áƒ¬áƒáƒ áƒ˜ კáƒáƒœáƒ¤áƒ˜áƒ’ურáƒáƒªáƒ˜áƒ˜áƒ— áƒáƒœ თáƒáƒ•áƒ“áƒáƒ›áƒ¡áƒ®áƒ›áƒ”ლის მიერ თქვენი კáƒáƒ•áƒ¨áƒ˜áƒ áƒ˜áƒ¡ გáƒáƒ“áƒáƒ­áƒ áƒ˜áƒ—.</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />სცáƒáƒ“ეთ Windows-ის ქსელის დიáƒáƒ’ნáƒáƒ¡áƒ¢áƒ˜áƒ™áƒ˜áƒ¡ ხელსáƒáƒ¬áƒ§áƒáƒ¡ გáƒáƒ¨áƒ•áƒ”ბáƒ<ph name="END_LINK" />.</translation>
<translation id="1772163372082567643">სერვერმáƒ, რáƒáƒ›áƒ”ლზე გáƒáƒ“áƒáƒ¡áƒ•áƒšáƒáƒ¡áƒáƒª ცდილáƒáƒ‘თ (<ph name="ORIGIN" />), დáƒáƒáƒ§áƒ”ნრსáƒáƒ—áƒáƒ£áƒ áƒ˜, რáƒáƒ›áƒšáƒ˜áƒ¡áƒáƒ“მი ყველრმიმáƒáƒ áƒ—ვáƒáƒª სáƒáƒ­áƒ˜áƒ áƒáƒ”ბს წყáƒáƒ áƒáƒ¡ წესების გáƒáƒ›áƒáƒ§áƒ”ნებáƒáƒ¡. სáƒáƒ›áƒ¬áƒ£áƒ®áƒáƒ áƒáƒ“, სáƒáƒ—áƒáƒ£áƒ áƒ˜ áƒáƒ áƒáƒ¡áƒ¬áƒáƒ áƒáƒ“ ფáƒáƒ áƒ›áƒ£áƒšáƒ˜áƒ áƒ”ბულიáƒ, რის გáƒáƒ›áƒáƒª ბრáƒáƒ£áƒ–ერი <ph name="SITE" />-თáƒáƒœ დáƒáƒ™áƒáƒ•áƒ¨áƒ˜áƒ áƒ”ბულ თქვენს მáƒáƒ—ხáƒáƒ•áƒœáƒáƒ¡ ვერ áƒáƒ¡áƒ áƒ£áƒšáƒ”ბს. წყáƒáƒ áƒáƒ¡ წესების მეშვეáƒáƒ‘ით სáƒáƒ˜áƒ¢áƒ”ბის áƒáƒžáƒ”რáƒáƒ¢áƒáƒ áƒ”ბს შეუძლიáƒáƒ— áƒáƒ›áƒ თუ იმ სáƒáƒ˜áƒ¢áƒ˜áƒ¡ უსáƒáƒ¤áƒ áƒ—ხáƒáƒ”ბისრდრსხვრმáƒáƒ®áƒáƒ¡áƒ˜áƒáƒ—ებლების კáƒáƒœáƒ¤áƒ˜áƒ’ურáƒáƒªáƒ˜áƒ.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />შეიტყვეთ მეტი ინკáƒáƒ’ნიტრრეჟიმის შესáƒáƒ®áƒ”ბ Chromium-ში<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">áƒáƒ¥ გáƒáƒ›áƒáƒ©áƒœáƒ“ებრთქვენი გáƒáƒ®áƒ¡áƒœáƒ˜áƒšáƒ˜ ჩáƒáƒœáƒáƒ áƒ—ები</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -406,6 +422,7 @@
<translation id="22081806969704220">ლáƒáƒœáƒ’áƒáƒ áƒ˜ 3</translation>
<translation id="2212735316055980242">წესი ვერ მáƒáƒ˜áƒ«áƒ”ბნáƒ</translation>
<translation id="2213606439339815911">ჩáƒáƒœáƒáƒ¬áƒ”რების შერჩევáƒâ€¦</translation>
+<translation id="2213612003795704869">გვერდი áƒáƒ›áƒáƒ˜áƒ‘ეჭდáƒ</translation>
<translation id="2215727959747642672">ფáƒáƒ˜áƒšáƒ”ბის რედáƒáƒ¥áƒ¢áƒ˜áƒ áƒ”ბáƒ</translation>
<translation id="2218879909401188352"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />-ზე შეტევის შედეგáƒáƒ“ თქვენს მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘áƒáƒ–ე შეიძლებრდáƒáƒ˜áƒœáƒ¡áƒ¢áƒáƒšáƒ˜áƒ áƒ“ეს სáƒáƒ®áƒ˜áƒ¤áƒáƒ—რáƒáƒžáƒ”ბი, რáƒáƒ›áƒšáƒ”ბსáƒáƒª შეუძლირთქვენი მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘ის დáƒáƒ–იáƒáƒœáƒ”ბáƒ, მáƒáƒ‘ილური სერვისის სáƒáƒ¤áƒáƒ¡áƒ£áƒ áƒ˜áƒ¡ ფáƒáƒ áƒ£áƒšáƒáƒ“ გáƒáƒ–რდრთუ პერსáƒáƒœáƒáƒšáƒ£áƒ áƒ˜ ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ˜áƒ¡ მáƒáƒžáƒáƒ áƒ•áƒ. <ph name="BEGIN_LEARN_MORE_LINK" />შეიტყვეთ მეტი<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">ინტერნეტ-კáƒáƒ•áƒ¨áƒ˜áƒ áƒ˜ áƒáƒ  áƒáƒ áƒ˜áƒ¡</translation>
@@ -415,6 +432,7 @@
<translation id="2248949050832152960">WebAuthn-ის გáƒáƒ›áƒáƒ§áƒ”ნებáƒ</translation>
<translation id="2250931979407627383">კიდეების მიკერებრმáƒáƒ áƒªáƒ®áƒœáƒ˜áƒ•</translation>
<translation id="225207911366869382">áƒáƒ› პáƒáƒšáƒ˜áƒ¢áƒ˜áƒ™áƒ˜áƒ¡áƒáƒ—ვის ეს ღირებულებრუáƒáƒ áƒ§áƒáƒ¤áƒ˜áƒšáƒ˜áƒ.</translation>
+<translation id="2256115617011615191">áƒáƒ®áƒšáƒáƒ•áƒ” გáƒáƒ“áƒáƒ¢áƒ•áƒ˜áƒ áƒ—ვáƒ</translation>
<translation id="2258928405015593961">შეიყვáƒáƒœáƒ”თ მáƒáƒ¥áƒ›áƒ”დების ვáƒáƒ“ის გáƒáƒ¡áƒ•áƒšáƒ˜áƒ¡ თáƒáƒ áƒ˜áƒ¦áƒ˜, რáƒáƒ›áƒ”ლიც მáƒáƒ›áƒáƒ•áƒáƒšáƒ¨áƒ˜áƒ დრცáƒáƒ“ეთ ხელáƒáƒ®áƒšáƒ</translation>
<translation id="225943865679747347">შეცდáƒáƒ›áƒ˜áƒ¡ კáƒáƒ“ი: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">HTTP შეცდáƒáƒ›áƒ</translation>
@@ -442,6 +460,7 @@
<translation id="2337852623177822836">პáƒáƒ áƒáƒ›áƒ”ტრს áƒáƒ™áƒáƒœáƒ¢áƒ áƒáƒšáƒ”ბს თქვენი áƒáƒ“მინისტრáƒáƒ¢áƒáƒ áƒ˜</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> დáƒáƒ¬áƒ§áƒ•áƒ˜áƒšáƒ”ბáƒáƒ¡ ითხáƒáƒ•áƒ¡</translation>
<translation id="2346319942568447007">თქვენ მიერ კáƒáƒžáƒ˜áƒ áƒ”ბული სურáƒáƒ—ი</translation>
+<translation id="2350796302381711542">დáƒáƒ•áƒ áƒ—áƒáƒ— ნებáƒÂ <ph name="HANDLER_HOSTNAME" />-ს, გáƒáƒ®áƒ¡áƒœáƒáƒ¡ ყველრ<ph name="PROTOCOL" /> ბმული <ph name="REPLACED_HANDLER_TITLE" />-ის ნáƒáƒªáƒ•áƒšáƒáƒ“?</translation>
<translation id="2354001756790975382">სხვრსáƒáƒœáƒ˜áƒ¨áƒœáƒ”ები</translation>
<translation id="2354430244986887761">Google Safe Browsing-მრáƒáƒ®áƒšáƒáƒ®áƒáƒœ <ph name="BEGIN_LINK" />áƒáƒ¦áƒ›áƒáƒáƒ©áƒ˜áƒœáƒ სáƒáƒ–იáƒáƒœáƒ áƒáƒžáƒ”ბი<ph name="END_LINK" /> სáƒáƒ˜áƒ¢áƒ–ე: <ph name="SITE" />.</translation>
<translation id="2355395290879513365">თáƒáƒ•áƒ“áƒáƒ›áƒ¡áƒ®áƒ›áƒ”ლებს შეუძლიáƒáƒ— იმ სურáƒáƒ—ების ნáƒáƒ®áƒ•áƒ, რáƒáƒ›áƒšáƒ”ბსáƒáƒª áƒáƒ› სáƒáƒ˜áƒ¢áƒ–ე áƒáƒ—ვáƒáƒšáƒ˜áƒ”რებთ, დრმáƒáƒ—ი შეცვლის მეშვეáƒáƒ‘ით, თქვენი შეცდáƒáƒ›áƒáƒ¨áƒ˜ შეყვáƒáƒœáƒ.</translation>
@@ -467,6 +486,7 @@
<translation id="2413528052993050574">ეს სერვერი ვერ áƒáƒ›áƒ¢áƒ™áƒ˜áƒªáƒ”ბს რáƒáƒ› ის áƒáƒ áƒ˜áƒ¡ <ph name="DOMAIN" />; მისი უსáƒáƒ¤áƒ áƒ—ხáƒáƒ”ბის სერთიფიკáƒáƒ¢áƒ˜ შესáƒáƒ«áƒšáƒáƒ გáƒáƒ£áƒ¥áƒ›áƒ”ბულიáƒ. ეს შეიძლებრიყáƒáƒ¡ გáƒáƒ›áƒáƒ¬áƒ•áƒ”ული áƒáƒ áƒáƒ¡áƒ¬áƒáƒ áƒ˜ კáƒáƒœáƒ¤áƒ˜áƒ’ურáƒáƒªáƒ˜áƒ˜áƒ— áƒáƒœ თáƒáƒ•áƒ“áƒáƒ›áƒ¡áƒ®áƒ›áƒ”ლის მიერ თქვენი კáƒáƒ•áƒ¨áƒ˜áƒ áƒ˜áƒ¡ გáƒáƒ“áƒáƒ­áƒ áƒ˜áƒ—.</translation>
<translation id="2414886740292270097">მუქი</translation>
<translation id="2430968933669123598">Google áƒáƒœáƒ’áƒáƒ áƒ˜áƒ¨áƒ˜áƒ¡ მáƒáƒ áƒ—ვáƒ, თქვენს Google áƒáƒœáƒ’áƒáƒ áƒ˜áƒ¨áƒ¨áƒ˜ თქვენი ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ˜áƒ¡, კáƒáƒœáƒ¤áƒ˜áƒ“ენციáƒáƒšáƒ£áƒ áƒáƒ‘ისრდრუსáƒáƒ¤áƒ áƒ—ხáƒáƒ”ბის სáƒáƒ›áƒáƒ áƒ—áƒáƒ•áƒáƒ“ დáƒáƒáƒ­áƒ˜áƒ áƒ”თ კლáƒáƒ•áƒ˜áƒ¨áƒ¡ Enter</translation>
+<translation id="2436186046335138073">დáƒáƒ•áƒ áƒ—áƒáƒ— ნებრ<ph name="HANDLER_HOSTNAME" />-ს, გáƒáƒ®áƒ¡áƒœáƒáƒ¡ ყველრ<ph name="PROTOCOL" /> ბმული?</translation>
<translation id="2438874542388153331">áƒáƒ—ხმáƒáƒ’áƒáƒ“ გáƒáƒ®áƒ•áƒ áƒ”ტრმáƒáƒ áƒ¯áƒ•áƒœáƒ˜áƒ•</translation>
<translation id="2450021089947420533">პრáƒáƒªáƒ”სები</translation>
<translation id="2463739503403862330">შევსებáƒ</translation>
@@ -474,6 +494,7 @@
<translation id="2465655957518002998">მიწáƒáƒ“ების მეთáƒáƒ“ის áƒáƒ áƒ©áƒ”ვáƒ</translation>
<translation id="2465688316154986572">დáƒáƒ¡áƒ¢áƒ”პლერებáƒ</translation>
<translation id="2465914000209955735">Chrome-ის მეშვეáƒáƒ‘ით ჩáƒáƒ›áƒáƒ¢áƒ•áƒ˜áƒ áƒ—ული ფáƒáƒ˜áƒšáƒ”ბის მáƒáƒ áƒ—ვáƒ</translation>
+<translation id="2466004615675155314">ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ˜áƒ¡ ჩვენებრვებიდáƒáƒœ</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />ქსელის დიáƒáƒ’ნáƒáƒ¡áƒ¢áƒ˜áƒ™áƒ˜áƒ¡ ხელსáƒáƒ¬áƒ§áƒáƒ¡ გáƒáƒ¨áƒ•áƒ”ბáƒ<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">მიმდევრáƒáƒ‘რ1-დáƒáƒœ N-მდე</translation>
<translation id="2470767536994572628">áƒáƒœáƒáƒ¢áƒáƒªáƒ˜áƒ”ბის რედáƒáƒ¥áƒ¢áƒ˜áƒ áƒ”ბისáƒáƒ¡ ეს დáƒáƒ™áƒ£áƒ›áƒ”ნტი დáƒáƒ‘რუნდებრერთგვერდიáƒáƒœ ხედზე დრშეტრიáƒáƒšáƒ“ებრთáƒáƒ•áƒ“áƒáƒžáƒ˜áƒ áƒ•áƒ”ლი ვერსიის მიხედვით</translation>
@@ -494,6 +515,7 @@
<translation id="2523886232349826891">შეინáƒáƒ®áƒ”ბრმხáƒáƒšáƒáƒ“ áƒáƒ› მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘áƒáƒ–ე</translation>
<translation id="2524461107774643265">მიუთითეთ დáƒáƒ›áƒáƒ¢áƒ”ბითი ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ</translation>
<translation id="2529899080962247600">áƒáƒ› ველში <ph name="MAX_ITEMS_LIMIT" />-ზე მეტი ჩáƒáƒœáƒáƒ¬áƒ”რი áƒáƒ  უნდრიყáƒáƒ¡. შემდგáƒáƒ›áƒ˜ ჩáƒáƒœáƒáƒ¬áƒ”რები იგნáƒáƒ áƒ˜áƒ áƒ”ბული იქნებáƒ.</translation>
+<translation id="2535585790302968248">ვების კáƒáƒœáƒ¤áƒ˜áƒ“ენციáƒáƒšáƒ£áƒ áƒáƒ“ დáƒáƒ¡áƒáƒ—ვáƒáƒšáƒ˜áƒ”რებლáƒáƒ“ გáƒáƒ®áƒ¡áƒ”ნით áƒáƒ®áƒáƒšáƒ˜ ინკáƒáƒ’ნიტრჩáƒáƒœáƒáƒ áƒ—ი</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{დრ1 სხვáƒ}other{დრ# სხვáƒ}}</translation>
<translation id="2536110899380797252">მისáƒáƒ›áƒáƒ áƒ—ის დáƒáƒ›áƒáƒ¢áƒ”ბáƒ</translation>
<translation id="2539524384386349900">áƒáƒ›áƒáƒªáƒœáƒáƒ‘áƒ</translation>
@@ -519,7 +541,14 @@
<translation id="2597378329261239068">ეს დáƒáƒ™áƒ£áƒ›áƒ”ნტი დáƒáƒªáƒ£áƒšáƒ˜áƒ პáƒáƒ áƒáƒšáƒ˜áƒ—. შეიყვáƒáƒœáƒ”თ პáƒáƒ áƒáƒšáƒ˜.</translation>
<translation id="2609632851001447353">ვáƒáƒ áƒ˜áƒáƒªáƒ˜áƒ”ბი</translation>
<translation id="2610561535971892504">დáƒáƒáƒ¬áƒ™áƒáƒžáƒ£áƒœáƒ”თ დáƒáƒ¡áƒáƒ™áƒáƒžáƒ˜áƒ áƒ”ბლáƒáƒ“</translation>
+<translation id="2617988307566202237">Chrome-ის მიერ <ph name="BEGIN_EMPHASIS" />áƒáƒ  შეინáƒáƒ®áƒ”ბáƒ<ph name="END_EMPHASIS" /> შემდეგი ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />დáƒáƒ—ვáƒáƒšáƒ˜áƒ”რების ისტáƒáƒ áƒ˜áƒ
+ <ph name="LIST_ITEM" />ქუქი-ჩáƒáƒœáƒáƒ¬áƒ”რები დრსáƒáƒ˜áƒ¢áƒ”ბის მáƒáƒœáƒáƒªáƒ”მები
+ <ph name="LIST_ITEM" />ფáƒáƒ áƒ›áƒ”ბში მითითებული ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (კáƒáƒœáƒ•áƒ”რტი)</translation>
+<translation id="2623663032199728144">შეიძლებრგთხáƒáƒ•áƒáƒ— თქვენი ეკრáƒáƒœáƒ”ბის შესáƒáƒ®áƒ”ბ ინფრმáƒáƒªáƒ˜áƒ˜áƒ¡ გáƒáƒ›áƒáƒ§áƒ”ნებáƒ</translation>
<translation id="2625385379895617796">თქვენი სáƒáƒáƒ—ი წინáƒáƒ</translation>
<translation id="262745152991669301">შეუძლირUSB-მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘ებთáƒáƒœ დáƒáƒ™áƒáƒ•áƒ¨áƒ˜áƒ áƒ”ბის თხáƒáƒ•áƒœáƒ</translation>
<translation id="2629325967560697240">Chrome-ის უსáƒáƒ¤áƒ áƒ—ხáƒáƒ”ბის ყველáƒáƒ–ე ძლიერი ფუნქციებით სáƒáƒ áƒ’ებლáƒáƒ‘ისთვის <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />ჩáƒáƒ áƒ—ეთ გáƒáƒ«áƒšáƒ˜áƒ”რებული დáƒáƒªáƒ•áƒ<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -553,6 +582,7 @@
<translation id="2709516037105925701">áƒáƒ•áƒ¢áƒáƒ›áƒáƒ¢áƒ£áƒ áƒ˜ შევსებáƒ</translation>
<translation id="2713444072780614174">თეთრი</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />, Chrome-ის პáƒáƒ áƒáƒ›áƒ”ტრებიდáƒáƒœ სáƒáƒ’áƒáƒ“áƒáƒ®áƒ“რდრსáƒáƒ™áƒ áƒ”დიტრბáƒáƒ áƒáƒ—ების ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ˜áƒ¡ სáƒáƒ›áƒáƒ áƒ—áƒáƒ•áƒáƒ“ დáƒáƒáƒ­áƒ˜áƒ áƒ”თ კლáƒáƒ•áƒ˜áƒ¨áƒ¡ Tab, შემდეგ კი Enter-ს</translation>
+<translation id="271663710482723385">სრულეკრáƒáƒœáƒ˜áƒáƒœáƒ˜ რეჟიმიდáƒáƒœ გáƒáƒ›áƒáƒ¡áƒáƒ¡áƒ•áƒšáƒ”ლáƒáƒ“, დáƒáƒáƒ­áƒ˜áƒ áƒ”თ კლáƒáƒ•áƒ˜áƒ¨áƒ”ბზე |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />|</translation>
<translation id="2721148159707890343">მáƒáƒ—ხáƒáƒ•áƒœáƒ წáƒáƒ áƒ›áƒáƒ¢áƒ”ბით გáƒáƒœáƒ®áƒáƒ áƒªáƒ˜áƒ”ლდáƒ</translation>
<translation id="2723669454293168317">გáƒáƒ£áƒ¨áƒ•áƒ˜áƒ— უსáƒáƒ¤áƒ áƒ—ხáƒáƒ”ბის შემáƒáƒ¬áƒ›áƒ”ბრChrome-ის პáƒáƒ áƒáƒ›áƒ”ტრებიდáƒáƒœ</translation>
<translation id="2726001110728089263">გვერდითი ლáƒáƒœáƒ’áƒáƒ áƒ˜</translation>
@@ -583,6 +613,7 @@
<translation id="2850739647070081192">Invite (კáƒáƒœáƒ•áƒ”რტი)</translation>
<translation id="2856444702002559011">თáƒáƒ•áƒ“áƒáƒ›áƒ¡áƒ®áƒ›áƒ”ლები შეიძლებრცáƒáƒ“áƒáƒœ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />-დáƒáƒœ თქვენი ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ˜áƒ¡ მáƒáƒžáƒáƒ áƒ•áƒ (მáƒáƒ’áƒáƒšáƒ˜áƒ—áƒáƒ“, პáƒáƒ áƒáƒšáƒ”ბის, შეტყáƒáƒ‘ინებების áƒáƒœ სáƒáƒ™áƒ áƒ”დიტრბáƒáƒ áƒáƒ—ების მáƒáƒœáƒáƒªáƒ”მების). <ph name="BEGIN_LEARN_MORE_LINK" />შეიტყვეთ მეტი<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">áƒáƒ› სáƒáƒ˜áƒ¢áƒ–ე ნáƒáƒ©áƒ•áƒ”ნებირმáƒáƒ›áƒáƒ‘ეზრებელი áƒáƒœ შეცდáƒáƒ›áƒáƒ¨áƒ˜ შემყვáƒáƒœáƒ˜ რეკლáƒáƒ›áƒ.</translation>
+<translation id="286512204874376891">ვირტუáƒáƒšáƒ£áƒ áƒ˜ ბáƒáƒ áƒáƒ—ი შენიღბáƒáƒ•áƒ¡ თქვენს რეáƒáƒšáƒ£áƒ  ბáƒáƒ áƒáƒ—ს, რáƒáƒª დáƒáƒ’იცáƒáƒ•áƒ— თáƒáƒ¦áƒšáƒ˜áƒ—áƒáƒ‘ის პáƒáƒ¢áƒ”ნციური შემთხვევებისგáƒáƒœ. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">მეგáƒáƒ‘რული</translation>
<translation id="2876489322757410363">გáƒáƒ áƒ” áƒáƒžáƒšáƒ˜áƒ™áƒáƒªáƒ˜áƒ˜áƒ— გáƒáƒ“áƒáƒ®áƒ“ის შემთხვევáƒáƒ¨áƒ˜, ინკáƒáƒ’ნიტრრეჟიმიდáƒáƒœ გáƒáƒ®áƒ•áƒáƒšáƒ—. გსურთ გáƒáƒ’რძელებáƒ?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />, Safe Browsing-ისრდრსხვრფუნქციების Chrome-ის პáƒáƒ áƒáƒ›áƒ”ტრებიდáƒáƒœ სáƒáƒ›áƒáƒ áƒ—áƒáƒ•áƒáƒ“ დáƒáƒáƒ­áƒ˜áƒ áƒ”თ კლáƒáƒ•áƒ˜áƒ¨áƒ¡ Tab, შემდეგ კი Enter-ს</translation>
@@ -607,6 +638,7 @@
<translation id="2930577230479659665">შემáƒáƒ­áƒ áƒ თითáƒáƒ”ული áƒáƒ¡áƒšáƒ˜áƒ¡ შემდეგ</translation>
<translation id="2932085390869194046">პáƒáƒ áƒáƒšáƒ˜áƒ¡ შემáƒáƒ—áƒáƒ•áƒáƒ–ებáƒâ€¦</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019"><ph name="PROTOCOL" />-ის ბმულების გáƒáƒ®áƒ¡áƒœáƒ</translation>
<translation id="2941952326391522266">ეს სერვერი ვერ áƒáƒ›áƒ¢áƒ™áƒ˜áƒªáƒ”ბს, რáƒáƒ› ის áƒáƒ áƒ˜áƒ¡ <ph name="DOMAIN" />; მისი უსáƒáƒ¤áƒ áƒ—ხáƒáƒ”ბის სერტიფიკáƒáƒ¢áƒ˜ áƒáƒ áƒ˜áƒ¡ <ph name="DOMAIN2" /> .-დáƒáƒœ. ეს შეიძლებრიყáƒáƒ¡ გáƒáƒ›áƒáƒ¬áƒ•áƒ”ული áƒáƒ áƒáƒ¡áƒ¬áƒáƒ áƒ˜ კáƒáƒœáƒ¤áƒ˜áƒ’ურáƒáƒªáƒ˜áƒ˜áƒ— áƒáƒœ თáƒáƒ•áƒ“áƒáƒ›áƒ¡áƒ®áƒ›áƒ”ლის მიერ თქვენი კáƒáƒ•áƒ¨áƒ˜áƒ áƒ˜áƒ¡ გáƒáƒ“áƒáƒ­áƒ áƒ˜áƒ—.</translation>
<translation id="2943895734390379394">áƒáƒ¢áƒ•áƒ˜áƒ áƒ—ვის დრáƒ:</translation>
<translation id="2948083400971632585">კáƒáƒ•áƒ¨áƒ˜áƒ áƒ”ბისთვის დáƒáƒ§áƒ”ნებული ნებისმიერი პრáƒáƒ¥áƒ¡áƒ˜áƒ¡ გáƒáƒ›áƒáƒ áƒ—ვრშესáƒáƒ«áƒšáƒ”ბელირპáƒáƒ áƒáƒ›áƒ”ტრების გვერდიდáƒáƒœ.</translation>
@@ -639,6 +671,7 @@
<translation id="3037605927509011580">უი, ხáƒáƒ áƒ•áƒ”ზი!</translation>
<translation id="3041612393474885105">სერტიფიკáƒáƒ¢áƒ˜áƒ¡ ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ</translation>
<translation id="3044034790304486808">თქვენი კვლევის გáƒáƒ’რძელებáƒ</translation>
+<translation id="305162504811187366">Chrome-ის დისტáƒáƒœáƒªáƒ˜áƒ£áƒ áƒ˜ სáƒáƒ›áƒ£áƒ¨áƒáƒ დáƒáƒ¤áƒ˜áƒ¡ ისტáƒáƒ áƒ˜áƒ, მáƒáƒ— შáƒáƒ áƒ˜áƒ¡ დრáƒáƒ˜áƒ¡ áƒáƒœáƒáƒ‘ეჭდები, ჰáƒáƒ¡áƒ¢áƒ”ბი დრკლიენტთრსესიების ID-ები</translation>
<translation id="3060227939791841287">C9 (კáƒáƒœáƒ•áƒ”რტი)</translation>
<translation id="3061707000357573562">ჩáƒáƒ¡áƒ¬áƒáƒ áƒ”ბის სერვისი</translation>
<translation id="306573536155379004">თáƒáƒ›áƒáƒ¨áƒ˜ დáƒáƒ˜áƒ¬áƒ§áƒ.</translation>
@@ -679,6 +712,7 @@
<translation id="3197136577151645743">შეუძლირითხáƒáƒ•áƒáƒ¡, რáƒáƒ› გáƒáƒ˜áƒ’áƒáƒ¡, რáƒáƒ“ის იყენებთ áƒáƒ¥áƒ¢áƒ˜áƒ£áƒ áƒáƒ“ áƒáƒ› მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘áƒáƒ¡</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />, თქვენ მიერ სინქრáƒáƒœáƒ˜áƒ–ებული ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ˜áƒ¡ Chrome-ის პáƒáƒ áƒáƒ›áƒ”ტრებიდáƒáƒœ სáƒáƒ›áƒáƒ áƒ—áƒáƒ•áƒáƒ“ დáƒáƒáƒ­áƒ˜áƒ áƒ”თ კლáƒáƒ•áƒ˜áƒ¨áƒ¡ Tab, შემდეგ კი Enter-ს</translation>
<translation id="320323717674993345">გáƒáƒ“áƒáƒ®áƒ“ის გáƒáƒ£áƒ¥áƒ›áƒ”ბáƒ</translation>
+<translation id="3203366800380907218">ვებიდáƒáƒœ</translation>
<translation id="3207960819495026254">ჩáƒáƒœáƒ˜áƒ¨áƒœáƒ£áƒšáƒ˜áƒ</translation>
<translation id="3209034400446768650">გვერდმრშეიძლებრდáƒáƒ’áƒáƒ™áƒ˜áƒ¡áƒ áƒáƒ— თáƒáƒœáƒ®áƒ˜áƒ¡ გáƒáƒ“áƒáƒ®áƒ“áƒ</translation>
<translation id="3212581601480735796"><ph name="HOSTNAME" />-ზე თქვენი áƒáƒ¥áƒ¢áƒ˜áƒ•áƒáƒ‘რმáƒáƒœáƒ˜áƒ¢áƒáƒ áƒ˜áƒœáƒ’ის ქვეშáƒáƒ</translation>
@@ -695,10 +729,12 @@
<translation id="3234666976984236645">áƒáƒ› სáƒáƒ˜áƒ¢áƒ–ე ყáƒáƒ•áƒ”ლთვის áƒáƒ¦áƒ›áƒáƒáƒ©áƒ˜áƒœáƒáƒ¡ მნიშვნელáƒáƒ•áƒáƒœáƒ˜ შინáƒáƒáƒ áƒ¡áƒ˜</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />, თქვენი ბრáƒáƒ£áƒ–ერის იერსáƒáƒ®áƒ˜áƒ¡ მáƒáƒ¡áƒáƒ áƒ’ებáƒáƒ“ დáƒáƒáƒ­áƒ˜áƒ áƒ”თ კლáƒáƒ•áƒ˜áƒ¨áƒ¡ Tab, შემდეგ კი Enter-ს</translation>
<translation id="3240791268468473923">უსáƒáƒ¤áƒ áƒ—ხრგáƒáƒ“áƒáƒ®áƒ“ისთვის სáƒáƒ­áƒ˜áƒ áƒ áƒáƒ•áƒ¢áƒáƒ áƒ˜áƒ–áƒáƒªáƒ˜áƒ˜áƒ¡ მáƒáƒœáƒáƒªáƒ”მების áƒáƒ áƒáƒ áƒ¡áƒ”ბáƒáƒ‘ის ფურცელი გáƒáƒ®áƒ¡áƒœáƒ˜áƒšáƒ˜áƒ</translation>
+<translation id="324180406144491771">„<ph name="HOST_NAME" />“-ის ბმულები დáƒáƒ‘ლáƒáƒ™áƒ˜áƒšáƒ˜áƒ</translation>
<translation id="3249845759089040423">სáƒáƒ¡áƒ˜áƒáƒ›áƒáƒ•áƒœáƒ</translation>
<translation id="3252266817569339921">ფრáƒáƒœáƒ’ული</translation>
<translation id="3257954757204451555">ვის დგáƒáƒ¡ áƒáƒ› ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ˜áƒ¡ უკáƒáƒœ?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />, Google Calendar-ში áƒáƒ®áƒáƒšáƒ˜ მáƒáƒ•áƒšáƒ”ნის სწრáƒáƒ¤áƒáƒ“ შესáƒáƒ¥áƒ›áƒœáƒ”ლáƒáƒ“ დáƒáƒáƒ­áƒ˜áƒ áƒ”თ კლáƒáƒ•áƒ˜áƒ¨áƒ¡ Tab, შემდეგ კი Enter-ს</translation>
+<translation id="3261488570342242926">შეიტყვეთ ვირტუáƒáƒšáƒ£áƒ áƒ˜ ბáƒáƒ áƒáƒ—ების შესáƒáƒ®áƒ”ბ</translation>
<translation id="3264837738038045344">Chrome-ის პáƒáƒ áƒáƒ›áƒ”ტრების მáƒáƒ áƒ—ვის ღილáƒáƒ™áƒ˜, Chrome პáƒáƒ áƒáƒ›áƒ”ტრებზე გáƒáƒ“áƒáƒ¡áƒáƒ¡áƒ•áƒšáƒ”ლáƒáƒ“ დáƒáƒáƒ­áƒ˜áƒ áƒ”თ კლáƒáƒ•áƒ˜áƒ¨áƒ¡ Enter</translation>
<translation id="3266793032086590337">მნიშვნელáƒáƒ‘რ(კáƒáƒœáƒ¤áƒšáƒ˜áƒ¥áƒ¢áƒ¨áƒ˜)</translation>
<translation id="3268451620468152448">გáƒáƒ®áƒ¡áƒœáƒ˜áƒšáƒ˜ ჩáƒáƒœáƒáƒ áƒ—ები</translation>
@@ -712,6 +748,7 @@
<translation id="3288238092761586174"><ph name="URL" />, შესáƒáƒ«áƒšáƒáƒ, სáƒáƒ­áƒ˜áƒ áƒáƒ”ბდეს დáƒáƒ›áƒáƒ¢áƒ”ბითი ნáƒáƒ‘იჯების გáƒáƒ•áƒšáƒáƒ¡ გáƒáƒ“áƒáƒ®áƒ“ის დáƒáƒ¡áƒáƒ“áƒáƒ¡áƒ¢áƒ£áƒ áƒ”ბლáƒáƒ“</translation>
<translation id="3293642807462928945">შეიტყვეთ მეტი „<ph name="POLICY_NAME" />“ წესების შესáƒáƒ®áƒ”ბ</translation>
<translation id="3295444047715739395">იხილეთ თქვენი პáƒáƒ áƒáƒšáƒ”ბი დრმáƒáƒ áƒ—ეთ ისინი Chrome-ის პáƒáƒ áƒáƒ›áƒ”ტრებიდáƒáƒœ</translation>
+<translation id="3303795387212510132">áƒáƒ«áƒšáƒ”ვს უფლებáƒáƒ¡ áƒáƒžáƒ¡, გáƒáƒ®áƒ¡áƒœáƒáƒ¡ <ph name="PROTOCOL_SCHEME" /> ბმულები?</translation>
<translation id="3303855915957856445">ძიების შედეგები ვერ მáƒáƒ˜áƒ«áƒ”ბნáƒ</translation>
<translation id="3304073249511302126">Bluetooth სკáƒáƒœáƒ˜áƒ áƒ”ბáƒ</translation>
<translation id="3308006649705061278">áƒáƒ áƒ’áƒáƒœáƒ˜áƒ–áƒáƒªáƒ˜áƒ£áƒšáƒ˜ ერთეული (OU)</translation>
@@ -725,12 +762,6 @@
<translation id="3345782426586609320">თვáƒáƒšáƒ”ბი</translation>
<translation id="3355823806454867987">პრáƒáƒ¥áƒ¡áƒ˜áƒ¡ პáƒáƒ áƒáƒ›áƒ”ტრების შეცვლáƒâ€¦</translation>
<translation id="3360103848165129075">გáƒáƒ“áƒáƒ®áƒ“ების დáƒáƒ›áƒ›áƒ£áƒ¨áƒáƒ•áƒ”ბლის გვერდი</translation>
-<translation id="3361596688432910856">Chrome-ის მიერ <ph name="BEGIN_EMPHASIS" />áƒáƒ  შეინáƒáƒ®áƒ”ბáƒ<ph name="END_EMPHASIS" /> შემდეგი ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />დáƒáƒ—ვáƒáƒšáƒ˜áƒ”რების ისტáƒáƒ áƒ˜áƒ
- <ph name="LIST_ITEM" />ქუქი-ჩáƒáƒœáƒáƒ¬áƒ”რები დრსáƒáƒ˜áƒ¢áƒ”ბის მáƒáƒœáƒáƒªáƒ”მები
- <ph name="LIST_ITEM" />ფáƒáƒ áƒ›áƒ”ბში მითითებული ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">ეს წესები áƒáƒ•áƒ¢áƒáƒ›áƒáƒ¢áƒ£áƒ áƒáƒ“ დáƒáƒ™áƒáƒžáƒ˜áƒ áƒ“რმáƒáƒ«áƒ•áƒ”ლებული „<ph name="OLD_POLICY" />“ წესებიდáƒáƒœ. სáƒáƒœáƒáƒªáƒ•áƒšáƒáƒ“ უნდრგáƒáƒ›áƒáƒ˜áƒ§áƒ”ნáƒáƒ— ეს წესები.</translation>
<translation id="3364869320075768271"><ph name="URL" /> ითხáƒáƒ•áƒ¡ ვირტუáƒáƒšáƒ£áƒ áƒ˜ რეáƒáƒšáƒáƒ‘ის მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘ისრდრმáƒáƒœáƒáƒªáƒ”მების გáƒáƒ›áƒáƒ§áƒ”ნების ნებáƒáƒ áƒ—ვáƒáƒ¡</translation>
<translation id="3366477098757335611">ბáƒáƒ áƒáƒ—ების ნáƒáƒ®áƒ•áƒ</translation>
@@ -813,7 +844,6 @@
<translation id="3587738293690942763">შუáƒ</translation>
<translation id="3592413004129370115">Italian (კáƒáƒœáƒ•áƒ”რტი)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{თქვენი ჯგუფის გáƒáƒ“áƒáƒ§áƒ”ნებრნებისმიერ დრáƒáƒ¡ შეგიძლიáƒáƒ—. áƒáƒ®áƒáƒš ჯგუფში გáƒáƒ¬áƒ”ვრიáƒáƒœáƒ”ბს დáƒáƒáƒ®áƒšáƒáƒ”ბით ერთი დღე სჭირდებáƒ.}=1{თქვენი ჯგუფის გáƒáƒ“áƒáƒ§áƒ”ნებრნებისმიერ დრáƒáƒ¡ შეგიძლიáƒáƒ—. áƒáƒ®áƒáƒš ჯგუფში გáƒáƒ¬áƒ”ვრიáƒáƒœáƒ”ბს დáƒáƒáƒ®áƒšáƒáƒ”ბით ერთი დღე სჭირდებáƒ.}other{თქვენი ჯგუფის გáƒáƒ“áƒáƒ§áƒ”ნებრნებისმიერ დრáƒáƒ¡ შეგიძლიáƒáƒ—. áƒáƒ®áƒáƒš ჯგუფში გáƒáƒ¬áƒ”ვრიáƒáƒœáƒ”ბს დáƒáƒáƒ®áƒšáƒáƒ”ბით {NUM_DAYS} დღე სჭირდებáƒ.}}</translation>
-<translation id="3596012367874587041">áƒáƒžáƒ˜áƒ¡ პáƒáƒ áƒáƒ›áƒ”ტრები</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">áƒáƒžáƒšáƒ˜áƒ™áƒáƒªáƒ˜áƒ დáƒáƒ‘ლáƒáƒ™áƒ˜áƒšáƒ˜áƒ თქვენი áƒáƒ“მინისტრáƒáƒ¢áƒáƒ áƒ˜áƒ¡ მიერ</translation>
<translation id="3608932978122581043">მიწáƒáƒ“ების áƒáƒ áƒ˜áƒ”ნტáƒáƒªáƒ˜áƒ</translation>
@@ -856,6 +886,7 @@
<translation id="370972442370243704">პრáƒáƒªáƒ”სების ჩáƒáƒ áƒ—ვáƒ</translation>
<translation id="3711895659073496551">შეჩერებáƒ</translation>
<translation id="3712624925041724820">ლიცენზიები áƒáƒ›áƒáƒ¬áƒ£áƒ áƒ£áƒšáƒ˜áƒ</translation>
+<translation id="3714633008798122362">ვებ კáƒáƒšáƒ”ნდáƒáƒ áƒ˜</translation>
<translation id="3714780639079136834">მáƒáƒ‘ილური ინტერნეტის áƒáƒœ Wi-Fi-ს ჩáƒáƒ áƒ—ვáƒ</translation>
<translation id="3715597595485130451">Wi-Fi-სთáƒáƒœ დáƒáƒ™áƒáƒ•áƒ¨áƒ˜áƒ áƒ”ბáƒ</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />პრáƒáƒ¥áƒ¡áƒ˜áƒ¡, ქსელის დáƒáƒªáƒ•áƒ˜áƒ¡áƒ დრDNS-ის კáƒáƒœáƒ¤áƒ˜áƒ’ურáƒáƒªáƒ˜áƒ˜áƒ¡ შემáƒáƒ¬áƒ›áƒ”ბáƒ<ph name="END_LINK" /></translation>
@@ -917,6 +948,7 @@
<translation id="3906954721959377182">ტáƒáƒ‘ლეტი</translation>
<translation id="3909477809443608991"><ph name="URL" /> ითხáƒáƒ•áƒ¡ დáƒáƒªáƒ£áƒšáƒ˜ კáƒáƒœáƒ¢áƒ”ნტის დáƒáƒ™áƒ•áƒ áƒáƒ¡. Google გáƒáƒœáƒáƒ®áƒáƒ áƒªáƒ˜áƒ”ლებს თქვენი მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘ის იდენტიფიკáƒáƒªáƒ˜áƒáƒ¡, ხáƒáƒšáƒ áƒáƒ› ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒáƒ–ე წვდáƒáƒ›áƒ შეიძლებრჰქáƒáƒœáƒ“ეს áƒáƒ› სáƒáƒ˜áƒ¢áƒ¡áƒáƒª.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">უáƒáƒ áƒ§áƒáƒ¤áƒ</translation>
<translation id="3939773374150895049">გსურთ გáƒáƒ›áƒáƒ˜áƒ§áƒ”ნáƒáƒ— WebAuthn ნáƒáƒªáƒ•áƒšáƒáƒ“ CVC-ისáƒ?</translation>
<translation id="3946209740501886391">ყáƒáƒ•áƒ”ლთვის შეკითხვრáƒáƒ› სáƒáƒ˜áƒ¢áƒ–ე</translation>
<translation id="3947595700203588284">შეუძლირMIDI-მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘ებთáƒáƒœ დáƒáƒ™áƒáƒ•áƒ¨áƒ˜áƒ áƒ”ბის თხáƒáƒ•áƒœáƒ</translation>
@@ -937,6 +969,7 @@
<translation id="3987940399970879459">1 მბáƒáƒ˜áƒ¢áƒ–ე ნáƒáƒ™áƒšáƒ”ბი</translation>
<translation id="3990250421422698716">კიდის წáƒáƒœáƒáƒªáƒ•áƒšáƒ”ბáƒ</translation>
<translation id="3996311196211510766">სáƒáƒ˜áƒ¢áƒ›áƒ (<ph name="ORIGIN" />) მáƒáƒ˜áƒ—ხáƒáƒ•áƒ წყáƒáƒ áƒáƒ¡ წესების მისáƒáƒ“áƒáƒ’ებრმის მიმáƒáƒ áƒ— ყველრმáƒáƒ—ხáƒáƒ•áƒœáƒ˜áƒ¡áƒ—ვის, თუმცრáƒáƒ› წესების მისáƒáƒ“áƒáƒ’ებრáƒáƒ›áƒŸáƒáƒ›áƒáƒ“ ვერ ხერხდებáƒ.</translation>
+<translation id="4009243425692662128">თქვენ მიერ áƒáƒ›áƒáƒ‘ეჭდილი გვერდების კáƒáƒœáƒ¢áƒ”ნტი, áƒáƒœáƒáƒšáƒ˜áƒ–ის მიზნით, იგზáƒáƒ•áƒœáƒ”ბრGoogle Cloud-ში áƒáƒœ მესáƒáƒ›áƒ” მხáƒáƒ áƒ”სთáƒáƒœ. მáƒáƒ’áƒáƒšáƒ˜áƒ—áƒáƒ“, შესáƒáƒ«áƒšáƒáƒ, შესრულდეს გვერდების სკáƒáƒœáƒ˜áƒ áƒ”ბრსენსიტიური მáƒáƒœáƒáƒªáƒ”მების áƒáƒ¦áƒ›áƒáƒ©áƒ”ნის მიზნით.</translation>
<translation id="4010758435855888356">გსურთ მეხსიერებáƒáƒ–ე წვდáƒáƒ›áƒ˜áƒ¡ დáƒáƒ¨áƒ•áƒ”ბáƒ?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{PDF დáƒáƒ™áƒ£áƒ›áƒ”ნტი, რáƒáƒ›áƒ”ლიც შეიცáƒáƒ•áƒ¡ {COUNT} გვერდს}other{PDF დáƒáƒ™áƒ£áƒ›áƒ”ნტი, რáƒáƒ›áƒ”ლიც შეიცáƒáƒ•áƒ¡ {COUNT} გვერდს}}</translation>
<translation id="4023431997072828269">ვინáƒáƒ˜áƒ“áƒáƒœ ეს ფáƒáƒ áƒ›áƒ იგზáƒáƒ•áƒœáƒ”ბრდáƒáƒ£áƒªáƒ•áƒ”ლი კáƒáƒ•áƒ¨áƒ˜áƒ áƒ˜áƒ—, თქვენი ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ ხილული იქნებრსხვებისთვის.</translation>
@@ -1027,6 +1060,7 @@
<translation id="4250680216510889253">áƒáƒ áƒ</translation>
<translation id="4253168017788158739">შენიშვნáƒ</translation>
<translation id="425582637250725228">თქვენ მიერ გáƒáƒœáƒ®áƒáƒ áƒªáƒ˜áƒ”ლებული ცვლილებები შეიძლებრáƒáƒ  შეინáƒáƒ®áƒáƒ¡.</translation>
+<translation id="425869179292622354">გსურთ, ის უფრრუსáƒáƒ¤áƒ áƒ—ხáƒáƒ“ áƒáƒ¥áƒªáƒ˜áƒáƒ— ვირტუáƒáƒšáƒ£áƒ áƒ˜ ბáƒáƒ áƒáƒ—ის მეშვეáƒáƒ‘ით?</translation>
<translation id="4258748452823770588">ცუდი ხელმáƒáƒ¬áƒ”რáƒ</translation>
<translation id="4261046003697461417">დáƒáƒªáƒ£áƒšáƒ˜ დáƒáƒ™áƒ£áƒ›áƒ”ნტების áƒáƒœáƒáƒ¢áƒ˜áƒ áƒ”ბრვერ მáƒáƒ®áƒ”რხდებáƒ</translation>
<translation id="4265872034478892965">დáƒáƒ¨áƒ•áƒ”ბულირთქვენი áƒáƒ“მინისტრáƒáƒ¢áƒáƒ áƒ˜áƒ¡ მიერ</translation>
@@ -1089,6 +1123,7 @@
<translation id="4434045419905280838">áƒáƒ›áƒáƒ›áƒ®. ფáƒáƒœáƒ¯áƒ áƒ”ბი/გáƒáƒ“áƒáƒ›áƒ˜áƒ¡áƒáƒ›áƒáƒ áƒ—ებáƒ</translation>
<translation id="4435702339979719576">ღირბáƒáƒ áƒáƒ—ი)</translation>
<translation id="443673843213245140">პრáƒáƒ¥áƒ¡áƒ˜áƒ¡ გáƒáƒ›áƒáƒ§áƒ”ნებრგáƒáƒ›áƒáƒ áƒ—ულიáƒ, მáƒáƒ’რáƒáƒ› მითითებულირპრáƒáƒ¥áƒ¡áƒ˜áƒ¡ დეტáƒáƒšáƒ£áƒ áƒ˜ კáƒáƒœáƒ¤áƒ˜áƒ’ურáƒáƒªáƒ˜áƒ.</translation>
+<translation id="4441832193888514600">იგნáƒáƒ áƒ˜áƒ áƒ”ბულიáƒ, რáƒáƒ“გáƒáƒœ წესების გáƒáƒœáƒ¡áƒáƒ–ღვრრშესáƒáƒ«áƒšáƒ”ბელირმხáƒáƒšáƒáƒ“ ღრუბლáƒáƒ•áƒáƒœ სáƒáƒ›áƒáƒ›áƒ®áƒ›áƒáƒ áƒ”ბლრწესების სáƒáƒ®áƒ˜áƒ—.</translation>
<translation id="4450893287417543264">áƒáƒ¦áƒáƒ  გáƒáƒ›áƒáƒ©áƒœáƒ“ეს</translation>
<translation id="4451135742916150903">შეუძლირHID-მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘ებთáƒáƒœ დáƒáƒ™áƒáƒ•áƒ¨áƒ˜áƒ áƒ”ბის თხáƒáƒ•áƒœáƒ</translation>
<translation id="4452328064229197696">თქვენ მიერ áƒáƒ®áƒšáƒáƒ®áƒáƒœ გáƒáƒ›áƒáƒ§áƒ”ნებული პáƒáƒ áƒáƒšáƒ˜ ნáƒáƒžáƒáƒ•áƒœáƒ˜áƒ გáƒáƒŸáƒáƒœáƒ˜áƒš მáƒáƒœáƒáƒªáƒ”მებში. თქვენი áƒáƒœáƒ’áƒáƒ áƒ˜áƒ¨áƒ˜áƒ¡ დáƒáƒªáƒ•áƒ˜áƒ¡ მიზნით, Google პáƒáƒ áƒáƒšáƒ”ბის მმáƒáƒ áƒ—ველი გირჩევთ, შეáƒáƒ›áƒáƒ¬áƒ›áƒáƒ— თქვენი შენáƒáƒ®áƒ£áƒšáƒ˜ პáƒáƒ áƒáƒšáƒ”ბი.</translation>
@@ -1144,6 +1179,7 @@
<translation id="4628948037717959914">ფáƒáƒ¢áƒ</translation>
<translation id="4631649115723685955">ქეშბექი მიბმულიáƒ</translation>
<translation id="4636930964841734540">ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ</translation>
+<translation id="4638670630777875591">ინკáƒáƒ’ნიტრრეჟიმი Chromium-ში</translation>
<translation id="464342062220857295">ძიების ფუნქციები</translation>
<translation id="4644670975240021822">უკუმიმდევრáƒáƒ‘რნáƒáƒ‘ეჭდი მხáƒáƒ áƒ˜áƒ— დáƒáƒ¦áƒ›áƒ</translation>
<translation id="4646534391647090355">áƒáƒ®áƒšáƒáƒ•áƒ” გáƒáƒ“áƒáƒ¡áƒ•áƒšáƒ</translation>
@@ -1164,6 +1200,7 @@
<translation id="4708268264240856090">თქვენი კáƒáƒ•áƒ¨áƒ˜áƒ áƒ˜ შეფერხდáƒ</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Windows-ის ქსელის დიáƒáƒ’ნáƒáƒ¡áƒ¢áƒ˜áƒ™áƒ˜áƒ¡ ხელსáƒáƒ¬áƒ§áƒáƒ¡ გáƒáƒ¨áƒ•áƒ”ბáƒ<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426"><ph name="USERNAME" />-ის პáƒáƒ áƒáƒšáƒ˜</translation>
<translation id="4724144314178270921">შეუძლირთქვენს გáƒáƒªáƒ•áƒšáƒ˜áƒ¡ ბუფერში áƒáƒ áƒ¡áƒ”ბული ტექსტისრდრსურáƒáƒ—ების ნáƒáƒ®áƒ•áƒ˜áƒ¡ თხáƒáƒ•áƒœáƒ</translation>
<translation id="4726672564094551039">წესების ხელáƒáƒ®áƒšáƒ ჩáƒáƒ¢áƒ•áƒ˜áƒ áƒ—ვáƒ</translation>
<translation id="4728558894243024398">პლáƒáƒ¢áƒ¤áƒáƒ áƒ›áƒ</translation>
@@ -1185,6 +1222,7 @@
<translation id="4757993714154412917">თქვენ ეს-ესáƒáƒ შეიყვáƒáƒœáƒ”თ პáƒáƒ áƒáƒšáƒ˜ შეცდáƒáƒ›áƒáƒ¨áƒ˜ შემყვáƒáƒœ სáƒáƒ˜áƒ¢áƒ–ე. თქვენი áƒáƒœáƒ’áƒáƒ áƒ˜áƒ¨áƒ”ბის დáƒáƒªáƒ•áƒ˜áƒ¡ მიზნით, Chromium გირჩევთ, შეáƒáƒ›áƒáƒ¬áƒ›áƒáƒ— თქვენი შენáƒáƒ®áƒ£áƒšáƒ˜ პáƒáƒ áƒáƒšáƒ”ბი.</translation>
<translation id="4758311279753947758">სáƒáƒ™áƒáƒœáƒ¢áƒáƒ¥áƒ¢áƒ ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ˜áƒ¡ დáƒáƒ›áƒáƒ¢áƒ”ბáƒ</translation>
<translation id="4761104368405085019">გáƒáƒ›áƒáƒ˜áƒ§áƒ”ნეთ თქვენი მიკრáƒáƒ¤áƒáƒœáƒ˜</translation>
+<translation id="4761869838909035636">Chrome-ის უსáƒáƒ¤áƒ áƒ—ხáƒáƒ”ბის შემáƒáƒ¬áƒ›áƒ”ბის გáƒáƒ¨áƒ•áƒ”ბáƒ</translation>
<translation id="4764776831041365478">ვებგვერდი <ph name="URL" />-ზე შეიძლებრდრáƒáƒ”ბით იყáƒáƒ¡ მწყáƒáƒ‘რიდáƒáƒœ გáƒáƒ›áƒáƒ¡áƒ£áƒšáƒ˜ áƒáƒœ შეიძლებრის სáƒáƒ›áƒ£áƒ“áƒáƒ›áƒáƒ“ გáƒáƒ“áƒáƒ•áƒ˜áƒ“რáƒáƒ®áƒáƒš ვებ მისáƒáƒ›áƒáƒ áƒ—ზე.</translation>
<translation id="4766713847338118463">áƒáƒ áƒ›áƒáƒ’áƒáƒ“ დáƒáƒ¡áƒ¢áƒ”პლერებრქვემáƒáƒ—</translation>
<translation id="4771973620359291008">დáƒáƒ¤áƒ˜áƒ¥áƒ¡áƒ˜áƒ áƒ“რუცნáƒáƒ‘ი შეცდáƒáƒ›áƒ.</translation>
@@ -1205,12 +1243,6 @@
<translation id="4819347708020428563">გსურთ áƒáƒœáƒáƒ¢áƒáƒªáƒ˜áƒ”ბის რედáƒáƒ¥áƒ¢áƒ˜áƒ áƒ”ბრნáƒáƒ’ულისხმევ ხედში?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />, áƒáƒ®áƒáƒšáƒ˜ Google Sheet-ის სწრáƒáƒ¤áƒáƒ“ შესáƒáƒ¥áƒ›áƒœáƒ”ლáƒáƒ“ დáƒáƒáƒ­áƒ˜áƒ áƒ”თ კლáƒáƒ•áƒ˜áƒ¨áƒ¡ Tab, შემდეგ კი Enter-ს</translation>
<translation id="4825507807291741242">ძლიერი</translation>
-<translation id="4827402517081186284">ინკáƒáƒ’ნიტრრეჟიმი áƒáƒ  ნიშნáƒáƒ•áƒ¡, რáƒáƒ› áƒáƒœáƒšáƒáƒ˜áƒœ უჩინáƒáƒ áƒ˜ ხáƒáƒ áƒ—:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />სáƒáƒ˜áƒ¢áƒ”ბმრიცის, რáƒáƒ“ის სტუმრáƒáƒ‘თ<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />დáƒáƒ›áƒ¡áƒáƒ¥áƒ›áƒ”ბლებს áƒáƒœ სáƒáƒ¡áƒ¬áƒáƒ•áƒšáƒ”ბლებს შეუძლიáƒáƒ— ვების დáƒáƒ—ვáƒáƒšáƒ˜áƒ”რების áƒáƒ¥áƒ¢áƒ˜áƒ•áƒáƒ‘ის გáƒáƒ™áƒáƒœáƒ¢áƒ áƒáƒšáƒ”ბáƒ<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />ინტერნეტპრáƒáƒ•áƒáƒ˜áƒ“ერებს შეუძლირვებტრáƒáƒ¤áƒ˜áƒ™áƒ˜áƒ¡ მáƒáƒœáƒ˜áƒ¢áƒáƒ áƒ˜áƒœáƒ’ი<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">გáƒáƒ¤áƒ áƒ—ხილებების ჩáƒáƒ áƒ—ვáƒ</translation>
<translation id="4838327282952368871">áƒáƒ áƒáƒáƒ›áƒ¥áƒ•áƒ”ყნიური</translation>
<translation id="4840250757394056958">თქვენი Chrome-ის ისტáƒáƒ áƒ˜áƒ˜áƒ¡ ნáƒáƒ®áƒ•áƒ</translation>
@@ -1222,12 +1254,12 @@
<translation id="4854362297993841467">მიწáƒáƒ“ების ეს მეთáƒáƒ“ი მიუწვდáƒáƒ›áƒ”ლიáƒ. ცáƒáƒ“ეთ სხვრვáƒáƒ áƒ˜áƒáƒœáƒ¢áƒ˜.</translation>
<translation id="4854853140771946034">Google Keep-ში áƒáƒ®áƒáƒšáƒ˜ ჩáƒáƒœáƒ˜áƒ¨áƒ•áƒœáƒ˜áƒ¡ სწრáƒáƒ¤áƒáƒ“ შექმნáƒ</translation>
<translation id="485902285759009870">მიმდინáƒáƒ áƒ”áƒáƒ‘ს კáƒáƒ“ის დáƒáƒ“áƒáƒ¡áƒ¢áƒ£áƒ áƒ”ბáƒ...</translation>
+<translation id="4866506163384898554">კურსáƒáƒ áƒ˜áƒ¡ სáƒáƒ©áƒ•áƒ”ნებლáƒáƒ“ დáƒáƒáƒ­áƒ˜áƒ áƒ”თ კლáƒáƒ•áƒ˜áƒ¨áƒ”ბზე |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />|</translation>
<translation id="4876188919622883022">გáƒáƒ›áƒáƒ áƒ¢áƒ˜áƒ•áƒ”ბული ხედი</translation>
<translation id="4876305945144899064">მáƒáƒ›áƒ®áƒ›áƒáƒ áƒ”ბლის სáƒáƒ®áƒ”ლის გáƒáƒ áƒ”შე</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{áƒáƒ áƒªáƒ”რთი}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831">„<ph name="TEXT" />“-ის ძიებáƒ</translation>
<translation id="4879491255372875719">áƒáƒ•áƒ¢áƒáƒ›áƒáƒ¢áƒ£áƒ áƒ˜ (ნáƒáƒ’ულისხმევი)</translation>
-<translation id="4879725228911483934">თქვენს ეკრáƒáƒœáƒ”ბზე ფáƒáƒœáƒ¯áƒ áƒ”ბის გáƒáƒ®áƒ¡áƒœáƒ დრგáƒáƒœáƒšáƒáƒ’ებáƒ</translation>
<translation id="4880827082731008257">ძიების ისტáƒáƒ áƒ˜áƒ</translation>
<translation id="4881695831933465202">გáƒáƒ®áƒ¡áƒœáƒ</translation>
<translation id="4885256590493466218">áƒáƒœáƒ’áƒáƒ áƒ˜áƒ¨áƒ¡áƒ¬áƒáƒ áƒ”ბისáƒáƒ¡ გáƒáƒ“áƒáƒ˜áƒ®áƒáƒ“ეთ <ph name="CARD_DETAIL" />-ით</translation>
@@ -1236,6 +1268,7 @@
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">მეცხრე რულáƒáƒœáƒ˜</translation>
<translation id="4901778704868714008">შენáƒáƒ®áƒ•áƒ...</translation>
+<translation id="4905659621780993806">თქვენი áƒáƒ“მინისტრáƒáƒ¢áƒáƒ áƒ˜ áƒáƒ•áƒ¢áƒáƒ›áƒáƒ¢áƒ£áƒ áƒáƒ“ გáƒáƒ“áƒáƒ¢áƒ•áƒ˜áƒ áƒ—áƒáƒ•áƒ¡ თქვენს მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘áƒáƒ¡ <ph name="DATE" />-ის <ph name="TIME" />-ზე. მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘ის გáƒáƒ“áƒáƒ¢áƒ•áƒ˜áƒ áƒ—ვáƒáƒ›áƒ“ე შეინáƒáƒ®áƒ”თ გáƒáƒ®áƒ¡áƒœáƒ˜áƒšáƒ˜ ერთეულები.</translation>
<translation id="4913987521957242411">ზედრმáƒáƒ áƒªáƒ®áƒ”ნრნáƒáƒ¬áƒ˜áƒšáƒ˜áƒ¡ გáƒáƒ®áƒ•áƒ áƒ”ტáƒ</translation>
<translation id="4918221908152712722">დáƒáƒáƒ˜áƒœáƒ¡áƒ¢áƒáƒšáƒ˜áƒ áƒ”თ <ph name="APP_NAME" /> (ჩáƒáƒ›áƒáƒ¢áƒ•áƒ˜áƒ áƒ—ვრáƒáƒ£áƒªáƒ˜áƒšáƒ”ბელი áƒáƒ  áƒáƒ áƒ˜áƒ¡)</translation>
<translation id="4923459931733593730">გáƒáƒ“áƒáƒ®áƒ“áƒ</translation>
@@ -1244,6 +1277,7 @@
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" />-დáƒáƒœ</translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, მáƒáƒ¡áƒáƒ«áƒ˜áƒ”ბლáƒáƒ“ დáƒáƒáƒ­áƒ˜áƒ áƒ”თ Tab-ს, შემდეგ Enter-ს</translation>
<translation id="4930153903256238152">დიდი მáƒáƒªáƒ£áƒšáƒáƒ‘ის</translation>
+<translation id="4940163644868678279">ინკáƒáƒ’ნიტრრეჟიმი Chrome-ში</translation>
<translation id="4943872375798546930">შედეგები áƒáƒ  áƒáƒ áƒ˜áƒ¡</translation>
<translation id="4950898438188848926">ჩáƒáƒœáƒáƒ áƒ—ის გáƒáƒ“áƒáƒ áƒ—ვის ღილáƒáƒ™áƒ˜, áƒáƒ› ჩáƒáƒœáƒáƒ áƒ—ზე გáƒáƒ“áƒáƒ¡áƒáƒ áƒ—ველáƒáƒ“ დáƒáƒáƒ­áƒ˜áƒ áƒ”თ კლáƒáƒ•áƒ˜áƒ¨áƒ¡ „Enter“, <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="495170559598752135">ქმედებები</translation>
@@ -1253,6 +1287,7 @@
<translation id="4968522289500246572">ეს áƒáƒžáƒ˜ შექმნილირმáƒáƒ‘ილურისთვის დრშესáƒáƒ«áƒšáƒáƒ, ზáƒáƒ›áƒ áƒáƒ áƒáƒ¡áƒáƒ—áƒáƒœáƒáƒ“áƒáƒ“ შეეცვáƒáƒšáƒáƒ¡. მáƒáƒ¡áƒáƒšáƒáƒ“ნელიáƒ, áƒáƒžáƒ¡ პრáƒáƒ‘ლემები წáƒáƒ áƒ›áƒáƒ”ქმნáƒáƒ¡ áƒáƒœ ხელáƒáƒ®áƒšáƒ გáƒáƒ”შვáƒáƒ¡.</translation>
<translation id="4969341057194253438">ჩáƒáƒœáƒáƒ¬áƒ”რის წáƒáƒ¨áƒšáƒ</translation>
<translation id="4973922308112707173">áƒáƒ áƒ›áƒáƒ’áƒáƒ“ გáƒáƒ®áƒ•áƒ áƒ”ტრზემáƒáƒ—</translation>
+<translation id="4976702386844183910">ბáƒáƒšáƒ ვიზიტი: <ph name="DATE" /></translation>
<translation id="4984088539114770594">გსურთ მიკრáƒáƒ¤áƒáƒœáƒ˜áƒ¡ გáƒáƒ›áƒáƒ§áƒ”ნებáƒ?</translation>
<translation id="4984339528288761049">Prc5 (კáƒáƒœáƒ•áƒ”რტი)</translation>
<translation id="4989163558385430922">ყველáƒáƒ¡ ნáƒáƒ®áƒ•áƒ</translation>
@@ -1314,6 +1349,7 @@
<translation id="5138227688689900538">ნáƒáƒ™áƒšáƒ”ბის ჩვენებáƒ</translation>
<translation id="5145883236150621069">წესის პáƒáƒ¡áƒ£áƒ®áƒ¨áƒ˜ შეცდáƒáƒ›áƒ˜áƒ¡ კáƒáƒ“იáƒ</translation>
<translation id="5146995429444047494">შეტყáƒáƒ‘ინებები დáƒáƒ‘ლáƒáƒ™áƒ˜áƒšáƒ˜áƒ <ph name="ORIGIN" />-ისთვის</translation>
+<translation id="514704532284964975"><ph name="URL" />-ს სურს ჰქáƒáƒœáƒ“ეს წვდáƒáƒ›áƒ დრშეცვáƒáƒšáƒáƒ¡ ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ NFC მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘ებზე, რáƒáƒ›áƒšáƒ”ბსáƒáƒª ტელეფáƒáƒœáƒ˜áƒ¡ მეშვეáƒáƒ‘ით მიუერთდით</translation>
<translation id="5148809049217731050">ნáƒáƒ‘ეჭდი მხáƒáƒ áƒ˜áƒ— áƒáƒ¦áƒ›áƒ</translation>
<translation id="515292512908731282">C4 (კáƒáƒœáƒ•áƒ”რტი)</translation>
<translation id="5158275234811857234">ყდáƒ</translation>
@@ -1338,6 +1374,7 @@
<translation id="5215116848420601511">გáƒáƒ“áƒáƒ®áƒ“ის მეთáƒáƒ“ები დრმისáƒáƒ›áƒáƒ áƒ—ები Google Pay-დáƒáƒœ</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">ლáƒáƒœáƒ’áƒáƒ áƒ˜ 13</translation>
+<translation id="5216942107514965959">ბáƒáƒšáƒ ვიზიტი იყრდღეს</translation>
<translation id="5222812217790122047">áƒáƒ£áƒªáƒ˜áƒšáƒ”ბელირელფáƒáƒ¡áƒ¢áƒ˜áƒ¡ მითითებáƒ</translation>
<translation id="5230733896359313003">მიწáƒáƒ“ების მისáƒáƒ›áƒáƒ áƒ—ი</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1358,7 +1395,6 @@
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">დáƒáƒ™áƒ£áƒ›áƒ”ნტის მáƒáƒ®áƒáƒ¡áƒ˜áƒáƒ—ებლები</translation>
<translation id="528468243742722775">დáƒáƒ¡áƒáƒ¡áƒ áƒ£áƒšáƒ˜</translation>
-<translation id="5284909709419567258">ქსელის მისáƒáƒ›áƒáƒ áƒ—ები</translation>
<translation id="5285570108065881030">ყველრშენáƒáƒ®áƒ£áƒšáƒ˜ პáƒáƒ áƒáƒšáƒ˜áƒ¡ ჩვენებáƒ</translation>
<translation id="5287240709317226393">ქუქი-ჩáƒáƒœáƒáƒ¬áƒ”რების ჩვენებáƒ</translation>
<translation id="5287456746628258573">ეს სáƒáƒ˜áƒ¢áƒ˜ იყენებს უსáƒáƒ¤áƒ áƒ—ხáƒáƒ”ბის მáƒáƒ«áƒ•áƒ”ლებულ კáƒáƒœáƒ¤áƒ˜áƒ’ურáƒáƒªáƒ˜áƒáƒ¡, რáƒáƒ›áƒ”ლმáƒáƒª შეიძლებრგáƒáƒáƒ›áƒŸáƒ¦áƒáƒ•áƒœáƒáƒ¡ მისთვის გáƒáƒ’ზáƒáƒ•áƒœáƒ˜áƒšáƒ˜ თქვენი ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ (მáƒáƒ’áƒáƒšáƒ˜áƒ—áƒáƒ“, პáƒáƒ áƒáƒšáƒ”ბი áƒáƒœ სáƒáƒ™áƒ áƒ”დიტრბáƒáƒ áƒáƒ—ების ნáƒáƒ›áƒ áƒ”ბი).</translation>
@@ -1442,6 +1478,7 @@
<translation id="5556459405103347317">ხელáƒáƒ®áƒšáƒ ჩáƒáƒ¢áƒ•áƒ˜áƒ áƒ—ვáƒ</translation>
<translation id="5560088892362098740">მáƒáƒ¥áƒ›áƒ”დების ვáƒáƒ“ის გáƒáƒ¡áƒ•áƒšáƒ˜áƒ¡ თáƒáƒ áƒ˜áƒ¦áƒ˜</translation>
<translation id="55635442646131152">დáƒáƒ™áƒ£áƒ›áƒ”ნტის სტრუქტურáƒ</translation>
+<translation id="5565613213060953222">ინკáƒáƒ’ნიტრჩáƒáƒœáƒáƒ áƒ—ის გáƒáƒ®áƒ¡áƒœáƒ</translation>
<translation id="5565735124758917034">áƒáƒ¥áƒ¢áƒ˜áƒ£áƒ áƒ˜</translation>
<translation id="5570825185877910964">დáƒáƒ˜áƒªáƒáƒ•áƒ˜áƒ— áƒáƒœáƒ’áƒáƒ áƒ˜áƒ¨áƒ˜</translation>
<translation id="5571083550517324815">áƒáƒ› მისáƒáƒ›áƒáƒ áƒ—იდáƒáƒœ წáƒáƒ›áƒáƒ¦áƒ”ბრვერ მáƒáƒ®áƒ”რხდებáƒ. áƒáƒ˜áƒ áƒ©áƒ˜áƒ”თ სხვრმისáƒáƒ›áƒáƒ áƒ—ი.</translation>
@@ -1524,6 +1561,7 @@
<translation id="5869522115854928033">შენáƒáƒ®áƒ£áƒšáƒ˜ პáƒáƒ áƒáƒšáƒ”ბი</translation>
<translation id="5873013647450402046">თქვენს ბáƒáƒœáƒ™áƒ¡ სურს, დáƒáƒáƒ“áƒáƒ¡áƒ¢áƒ£áƒ áƒáƒ¡, რáƒáƒ› ეს ნáƒáƒ›áƒ“ვილáƒáƒ“ თქვენ ხáƒáƒ áƒ—.</translation>
<translation id="5887400589839399685">ბáƒáƒ áƒáƒ—ი შენáƒáƒ®áƒ£áƒšáƒ˜áƒ</translation>
+<translation id="5887687176710214216">ბáƒáƒšáƒ ვიზიტი იყრგუშინ</translation>
<translation id="5895138241574237353">გáƒáƒ“áƒáƒ¢áƒ•áƒ˜áƒ áƒ—ვáƒ</translation>
<translation id="5895187275912066135">გáƒáƒªáƒ”მულიáƒ</translation>
<translation id="5901630391730855834">ყვითელი</translation>
@@ -1537,6 +1575,7 @@
<translation id="5921639886840618607">გსურთ ბáƒáƒ áƒáƒ—ის შენáƒáƒ®áƒ•áƒ Google áƒáƒœáƒ’áƒáƒ áƒ˜áƒ¨áƒ¨áƒ˜?</translation>
<translation id="5922853866070715753">თითქმის მზáƒáƒ“áƒáƒ</translation>
<translation id="5932224571077948991">სáƒáƒ˜áƒ¢áƒ–ე ნáƒáƒ©áƒ•áƒ”ნებირმáƒáƒ›áƒáƒ‘ეზრებელი áƒáƒœ შეცდáƒáƒ›áƒáƒ¨áƒ˜ შემყვáƒáƒœáƒ˜ რეკლáƒáƒ›áƒ</translation>
+<translation id="5938153366081463283">დáƒáƒáƒ›áƒáƒ¢áƒ”თ ვირტუáƒáƒšáƒ£áƒ áƒ˜ ბáƒáƒ áƒáƒ—ი</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347">მიმდინáƒáƒ áƒ”áƒáƒ‘ს <ph name="SITE_NAME" />-ის გáƒáƒ®áƒ¡áƒœáƒâ€¦</translation>
<translation id="5951495562196540101">მáƒáƒ›áƒ®áƒ›áƒáƒ áƒ”ბლის áƒáƒœáƒ’áƒáƒ áƒ˜áƒ¨áƒ˜áƒ— რეგისტრáƒáƒªáƒ˜áƒ ვერ ხერხდებრ(ხელმისáƒáƒ¬áƒ•áƒ“áƒáƒ›áƒ˜áƒ პáƒáƒ™áƒ”ტური ლიცენზიáƒ).</translation>
@@ -1601,6 +1640,7 @@
<translation id="6120179357481664955">გსურთ თქვენი UPI ID-ს დáƒáƒ›áƒáƒ®áƒ¡áƒáƒ•áƒ áƒ”ბáƒ?</translation>
<translation id="6124432979022149706">Chrome Enterprise მáƒáƒ”რთებლები</translation>
<translation id="6127379762771434464">ერთეული áƒáƒ›áƒáƒ˜áƒ¨áƒáƒšáƒ</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />შეიტყვეთ მეტი ინკáƒáƒ’ნიტრრეჟიმის შესáƒáƒ®áƒ”ბ Chrome-ში<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">შეáƒáƒ›áƒáƒ¬áƒ›áƒ”თ კáƒáƒ‘ელები დრგáƒáƒ“áƒáƒ¢áƒ•áƒ˜áƒ áƒ—ეთ ყველრრáƒáƒ£áƒ¢áƒ”რი, მáƒáƒ“ემი áƒáƒœ
სხვრქსელური მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘áƒ, რáƒáƒ›áƒ”ლსáƒáƒª იყენებთ.</translation>
<translation id="614940544461990577">ცáƒáƒ“ეთ:</translation>
@@ -1613,7 +1653,6 @@
<translation id="6169916984152623906">áƒáƒ®áƒšáƒ ვების დáƒáƒ—ვáƒáƒšáƒ˜áƒ”რებრკáƒáƒœáƒ¤áƒ˜áƒ“ენციáƒáƒšáƒ£áƒ áƒáƒ“ შეგიძლიáƒáƒ—, რáƒáƒª ნიშნáƒáƒ•áƒ¡, რáƒáƒ› áƒáƒ› მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘ის სხვრმáƒáƒ›áƒ®áƒ›áƒáƒ áƒ”ბლები თქვენს áƒáƒ¥áƒ¢áƒ˜áƒ•áƒáƒ‘áƒáƒ¡ ვერ იხილáƒáƒ•áƒ”ნ. მიუხედáƒáƒ•áƒáƒ“ áƒáƒ›áƒ˜áƒ¡áƒ, ჩáƒáƒ›áƒáƒ¢áƒ•áƒ˜áƒ áƒ—ული ფáƒáƒ˜áƒšáƒ”ბი დრსáƒáƒœáƒ˜áƒ¨áƒœáƒ”ები მáƒáƒ˜áƒœáƒª შეინáƒáƒ®áƒ”ბáƒ.</translation>
<translation id="6177128806592000436">თქვენი კáƒáƒ•áƒ¨áƒ˜áƒ áƒ˜ áƒáƒ› სáƒáƒ˜áƒ¢áƒ—áƒáƒœ დáƒáƒªáƒ£áƒšáƒ˜ áƒáƒ  áƒáƒ áƒ˜áƒ¡</translation>
<translation id="6180316780098470077">ხელáƒáƒ®áƒšáƒ მცდელáƒáƒ‘ის ინტერვáƒáƒšáƒ˜</translation>
-<translation id="619448280891863779">შეუძლირთქვენს ეკრáƒáƒœáƒ”ბზე ფáƒáƒœáƒ¯áƒ áƒ”ბის გáƒáƒ®áƒ¡áƒœáƒ˜áƒ¡áƒ დრგáƒáƒœáƒšáƒáƒ’ების თხáƒáƒ•áƒœáƒ</translation>
<translation id="6196640612572343990">მესáƒáƒ›áƒ” მხáƒáƒ áƒ˜áƒ¡ ქუქი-ჩáƒáƒœáƒáƒ¬áƒ”რების დáƒáƒ‘ლáƒáƒ™áƒ•áƒ</translation>
<translation id="6203231073485539293">შეáƒáƒ›áƒáƒ¬áƒ›áƒ”თ თქვენი ინტერნეტ კáƒáƒ•áƒ¨áƒ˜áƒ áƒ˜</translation>
<translation id="6218753634732582820">áƒáƒ›áƒáƒ˜áƒ¨áƒáƒšáƒáƒ¡ მისáƒáƒ›áƒáƒ áƒ—ი Chromium-იდáƒáƒœ?</translation>
@@ -1636,7 +1675,7 @@
<translation id="6272383483618007430">Google გáƒáƒœáƒáƒ®áƒšáƒ”ბáƒ</translation>
<translation id="6276112860590028508">áƒáƒ¥ გáƒáƒ›áƒáƒ©áƒœáƒ“ებრგვერდები თქვენი სáƒáƒ™áƒ˜áƒ—ხáƒáƒ•áƒ˜ სიიდáƒáƒœ</translation>
<translation id="627746635834430766">შემდგáƒáƒ›áƒ˜ გáƒáƒ“áƒáƒ®áƒ“ების დáƒáƒ¡áƒáƒ©áƒ¥áƒáƒ áƒ”ბლáƒáƒ“ შეგიძლიáƒáƒ— შეინáƒáƒ®áƒáƒ— თქვენი ბáƒáƒ áƒáƒ—ის მáƒáƒœáƒáƒªáƒ”მები დრბილინგის მისáƒáƒ›áƒáƒ áƒ—ი თქვენს Google áƒáƒœáƒ’áƒáƒ áƒ˜áƒ¨áƒ¨áƒ˜.</translation>
-<translation id="6279098320682980337">ვირტუáƒáƒšáƒ£áƒ áƒ˜ ბáƒáƒ áƒáƒ—ის ნáƒáƒ›áƒ”რი áƒáƒ  áƒáƒ áƒ˜áƒ¡ შევსებული? კáƒáƒžáƒ˜áƒ áƒ”ბისთვის შეეხეთ ბáƒáƒ áƒáƒ—ის დეტáƒáƒšáƒ”ბს</translation>
+<translation id="6279183038361895380">კურსáƒáƒ áƒ˜áƒ¡ სáƒáƒ©áƒ•áƒ”ნებლáƒáƒ“, დáƒáƒáƒ­áƒ˜áƒ áƒ”თ კლáƒáƒ•áƒ˜áƒ¨áƒ–ე |<ph name="ACCELERATOR" />|</translation>
<translation id="6280223929691119688">áƒáƒ› მისáƒáƒ›áƒáƒ áƒ—ზე მიწáƒáƒ“ებრვერ მáƒáƒ®áƒ”რხდებáƒ. áƒáƒ˜áƒ áƒ©áƒ˜áƒ”თ სხვრმისáƒáƒ›áƒáƒ áƒ—ი.</translation>
<translation id="6282194474023008486">სáƒáƒ¤áƒáƒ¡áƒ¢áƒ კáƒáƒ“ი</translation>
<translation id="6285507000506177184">Chrome-ის მეშვეáƒáƒ‘ით ჩáƒáƒ›áƒáƒ¢áƒ•áƒ˜áƒ áƒ—ული ფáƒáƒ˜áƒšáƒ”ბის მáƒáƒ áƒ—ვის ღილáƒáƒ™áƒ˜, Chrome-ის მეშვეáƒáƒ‘ით ჩáƒáƒ›áƒáƒ¢áƒ•áƒ˜áƒ áƒ—ული ფáƒáƒ˜áƒšáƒ”ბის სáƒáƒ›áƒáƒ áƒ—áƒáƒ•áƒáƒ“ დáƒáƒáƒ­áƒ˜áƒ áƒ”თ კლáƒáƒ•áƒ˜áƒ¨áƒ¡ Enter</translation>
@@ -1644,6 +1683,7 @@
<translation id="6290238015253830360">áƒáƒ¥ გáƒáƒ›áƒáƒ©áƒœáƒ“ებრთქვენთვის შემáƒáƒ—áƒáƒ•áƒáƒ–ებული სტáƒáƒ¢áƒ˜áƒ”ბი</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">ბáƒáƒ áƒáƒ—ის დáƒáƒ“áƒáƒ¡áƒ¢áƒ£áƒ áƒ”ბის კáƒáƒ“ი (CVC):</translation>
+<translation id="6300452962057769623">{0,plural, =0{თქვენი მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘რáƒáƒ®áƒšáƒ გáƒáƒ“áƒáƒ˜áƒ¢áƒ•áƒ˜áƒ áƒ—ებáƒ}=1{თქვენი მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘რგáƒáƒ“áƒáƒ˜áƒ¢áƒ•áƒ˜áƒ áƒ—ებრ1 წáƒáƒ›áƒ¨áƒ˜}other{თქვენი მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘რგáƒáƒ“áƒáƒ˜áƒ¢áƒ•áƒ˜áƒ áƒ—ებრ# წáƒáƒ›áƒ¨áƒ˜}}</translation>
<translation id="6302269476990306341">Google áƒáƒ¡áƒ˜áƒ¡áƒ¢áƒ”ნტი Chrome-ში წყვეტს მუშáƒáƒáƒ‘áƒáƒ¡</translation>
<translation id="6305205051461490394"><ph name="URL" /> მიუწვდáƒáƒ›áƒ”ლიáƒ.</translation>
<translation id="6312113039770857350">ვებგვერდი მიუწვდáƒáƒ›áƒ”ლიáƒ</translation>
@@ -1717,6 +1757,7 @@
<translation id="6529602333819889595">წáƒáƒ¨áƒšáƒ˜áƒ¡ &amp;გáƒáƒ›áƒ”áƒáƒ áƒ”ბáƒ</translation>
<translation id="6545864417968258051">Bluetooth სკáƒáƒœáƒ˜áƒ áƒ”ბáƒ</translation>
<translation id="6547208576736763147">áƒáƒ áƒ›áƒáƒ’áƒáƒ“ გáƒáƒ®áƒ•áƒ áƒ”ტრმáƒáƒ áƒªáƒ®áƒœáƒ˜áƒ•</translation>
+<translation id="6554732001434021288">ბáƒáƒšáƒ ვიზიტი იყრ<ph name="NUM_DAYS" /> დღის წინ</translation>
<translation id="6556866813142980365">გáƒáƒ›áƒ”áƒáƒ áƒ”ბáƒ</translation>
<translation id="6569060085658103619">თქვენ áƒáƒ—ვáƒáƒšáƒ˜áƒ”რებთ გáƒáƒ¤áƒáƒ áƒ—áƒáƒ”ბის გვერდს</translation>
<translation id="6573200754375280815">áƒáƒ áƒ›áƒáƒ’áƒáƒ“ გáƒáƒ®áƒ•áƒ áƒ”ტრმáƒáƒ áƒ¯áƒ•áƒœáƒ˜áƒ•</translation>
@@ -1777,7 +1818,6 @@
<translation id="6757797048963528358">თქვენი მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘რძილის რეჟიმზე გáƒáƒ“áƒáƒ•áƒ˜áƒ“áƒ.</translation>
<translation id="6767985426384634228">გსურთ, გáƒáƒœáƒáƒáƒ®áƒšáƒáƒ— მისáƒáƒ›áƒáƒ áƒ—ი?</translation>
<translation id="6768213884286397650">Hagaki (ღირბáƒáƒ áƒáƒ—ი)</translation>
-<translation id="6774185088257932239"><ph name="BEGIN_LINK" />შეიტყვეთ მეტი<ph name="END_LINK" /> ინკáƒáƒ’ნიტრრეჟიმის შესáƒáƒ®áƒ”ბ</translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">იისფერი</translation>
<translation id="6786747875388722282">გáƒáƒ¤áƒáƒ áƒ—áƒáƒ”ბები</translation>
@@ -1861,7 +1901,6 @@
<translation id="706295145388601875">მისáƒáƒ›áƒáƒ áƒ—ების დáƒáƒ›áƒáƒ¢áƒ”ბრდრმáƒáƒ áƒ—ვრChrome-ის პáƒáƒ áƒáƒ›áƒ”ტრებიდáƒáƒœ</translation>
<translation id="7064851114919012435">სáƒáƒ™áƒáƒœáƒ¢áƒáƒ¥áƒ¢áƒ ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ</translation>
<translation id="7068733155164172741">შეიყვáƒáƒœáƒ”თ <ph name="OTP_LENGTH" />-ციფრიáƒáƒœáƒ˜ კáƒáƒ“ი</translation>
-<translation id="7070090581017165256">áƒáƒ› სáƒáƒ˜áƒ¢áƒ˜áƒ¡ შესáƒáƒ®áƒ”ბ</translation>
<translation id="70705239631109039">თქვენი კáƒáƒ•áƒ¨áƒ˜áƒ áƒ˜ სრულáƒáƒ“ დáƒáƒªáƒ£áƒšáƒ˜ áƒáƒ  áƒáƒ áƒ˜áƒ¡</translation>
<translation id="7075452647191940183">მáƒáƒ—ხáƒáƒ•áƒœáƒ მეტისმეტáƒáƒ“ დიდიáƒ</translation>
<translation id="7079718277001814089">ეს სáƒáƒ˜áƒ¢áƒ˜ მáƒáƒ•áƒœáƒ” პრáƒáƒ’რáƒáƒ›áƒ”ბს შეიცáƒáƒ•áƒ¡</translation>
@@ -1878,6 +1917,12 @@
<translation id="7111012039238467737">(სწáƒáƒ áƒ˜áƒ)</translation>
<translation id="7118618213916969306">გáƒáƒªáƒ•áƒšáƒ˜áƒ¡ ბუფერში URL-ის ძიებáƒ, <ph name="SHORT_URL" /></translation>
<translation id="7119414471315195487">სხვრჩáƒáƒœáƒáƒ áƒ—ების áƒáƒœ პრáƒáƒ’რáƒáƒ›áƒ”ბის დáƒáƒ®áƒ£áƒ áƒ•áƒ</translation>
+<translation id="7129355289156517987">Chromium-ის ყველრინკáƒáƒ’ნიტრჩáƒáƒœáƒáƒ áƒ—ის დáƒáƒ®áƒ£áƒ áƒ•áƒ˜áƒ¡ შემდეგ თქვენი áƒáƒ¥áƒ¢áƒ˜áƒ•áƒáƒ‘რáƒáƒ› ჩáƒáƒœáƒáƒ áƒ—ებში áƒáƒ› მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘იდáƒáƒœ წáƒáƒ˜áƒ¨áƒšáƒ”ბáƒ:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />დáƒáƒ—ვáƒáƒšáƒ˜áƒ”რების áƒáƒ¥áƒ¢áƒ˜áƒ•áƒáƒ‘áƒ<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ძიების ისტáƒáƒ áƒ˜áƒ<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ფáƒáƒ áƒ›áƒ”ბში მითითებული ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">áƒáƒ› მისáƒáƒ›áƒáƒ áƒ—ზე გáƒáƒ’ზáƒáƒ•áƒœáƒ ვერ მáƒáƒ®áƒ”რხდებáƒ. áƒáƒ˜áƒ áƒ©áƒ˜áƒ”თ სხვრმისáƒáƒ›áƒáƒ áƒ—ი.</translation>
<translation id="7132939140423847331">თქვენი áƒáƒ“მინისტრáƒáƒ¢áƒáƒ áƒ˜ კრძáƒáƒšáƒáƒ•áƒ¡ áƒáƒ› მáƒáƒœáƒáƒªáƒ”მთრკáƒáƒžáƒ˜áƒ áƒ”ბáƒáƒ¡.</translation>
<translation id="7135130955892390533">სტáƒáƒ¢áƒ£áƒ¡áƒ˜áƒ¡ ჩვენებáƒ</translation>
@@ -1900,6 +1945,7 @@
<translation id="7192203810768312527">გáƒáƒ›áƒáƒ—áƒáƒ•áƒ˜áƒ¡áƒ£áƒ¤áƒšáƒ“ებრ<ph name="SIZE" />. ზáƒáƒ’იერთი სáƒáƒ˜áƒ¢áƒ˜ შემდეგი მáƒáƒœáƒáƒ®áƒ£áƒšáƒ”ბისáƒáƒ¡ შეიძლებრუფრრნელრჩáƒáƒ˜áƒ¢áƒ•áƒ˜áƒ áƒ—áƒáƒ¡.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">თქვენს áƒáƒ“მინისტრáƒáƒ¢áƒáƒ áƒ¡ შეუძლირნáƒáƒ®áƒáƒ¡:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, ვების კáƒáƒœáƒ¤áƒ˜áƒ“ენციáƒáƒšáƒ£áƒ áƒáƒ“ დáƒáƒ—ვáƒáƒšáƒ˜áƒ”რებისთვის áƒáƒ®áƒáƒšáƒ˜ ინკáƒáƒ’ნიტრჩáƒáƒœáƒáƒ áƒ—ის გáƒáƒ¡áƒáƒ®áƒ¡áƒœáƒ”ლáƒáƒ“ დáƒáƒáƒ­áƒ˜áƒ áƒ”თ კლáƒáƒ•áƒ˜áƒ¨áƒ¡ Tab, შემდეგ კი Enter-ს</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> áƒáƒ  áƒáƒ™áƒ›áƒáƒ§áƒáƒ¤áƒ˜áƒšáƒ”ბს უსáƒáƒ¤áƒ áƒ—ხáƒáƒ”ბის სტáƒáƒœáƒ“áƒáƒ áƒ¢áƒ”ბს.</translation>
<translation id="7210993021468939304">შეუძლირკáƒáƒœáƒ¢áƒ”ინერის შიგნით Linux-ის áƒáƒ¥áƒ¢áƒ˜áƒ•áƒáƒ‘ის ნáƒáƒ®áƒ•áƒ დრLinux áƒáƒžáƒ”ბის ინსტáƒáƒšáƒáƒªáƒ˜áƒ/გáƒáƒ¨áƒ•áƒ”ბáƒ</translation>
@@ -1931,6 +1977,7 @@
<translation id="7304562222803846232">Google áƒáƒœáƒ’áƒáƒ áƒ˜áƒ¨áƒ˜áƒ¡ კáƒáƒœáƒ¤áƒ˜áƒ“ენციáƒáƒšáƒ£áƒ áƒáƒ‘ის პáƒáƒ áƒáƒ›áƒ”ტრების მáƒáƒ áƒ—ვáƒ</translation>
<translation id="7305756307268530424">უფრრნელრგáƒáƒ¨áƒ•áƒ”ბáƒ</translation>
<translation id="7308436126008021607">ფáƒáƒœáƒ£áƒ áƒ˜ სინქრáƒáƒœáƒ˜áƒ–áƒáƒªáƒ˜áƒ</translation>
+<translation id="7310392214323165548">მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘რძáƒáƒšáƒ˜áƒáƒœ მáƒáƒšáƒ” გáƒáƒ“áƒáƒ˜áƒ¢áƒ•áƒ˜áƒ áƒ—ებáƒ</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">კáƒáƒ•áƒ¨áƒ˜áƒ áƒ—áƒáƒœ დáƒáƒ™áƒáƒ•áƒ¨áƒ˜áƒ áƒ”ბული დáƒáƒ®áƒ›áƒáƒ áƒ”ბáƒ</translation>
<translation id="7323804146520582233">სექციის „<ph name="SECTION" />“ დáƒáƒ›áƒáƒšáƒ•áƒ</translation>
@@ -1938,6 +1985,7 @@
<translation id="7334320624316649418">გáƒáƒ“áƒáƒšáƒáƒ’ების &amp;გáƒáƒ›áƒ”áƒáƒ áƒ”ბáƒ</translation>
<translation id="7335157162773372339">შეუძლირთქვენი კáƒáƒ›áƒ”რის გáƒáƒ›áƒáƒ§áƒ”ნების თხáƒáƒ•áƒœáƒ</translation>
<translation id="7337248890521463931">მეტი ხáƒáƒ–ის ჩვენებáƒ</translation>
+<translation id="7337418456231055214">ვირტუáƒáƒšáƒ£áƒ áƒ˜ ბáƒáƒ áƒáƒ—ის ნáƒáƒ›áƒ”რი áƒáƒ  áƒáƒ áƒ˜áƒ¡ შევსებული? კáƒáƒžáƒ˜áƒ áƒ”ბისთვის შეეხეთ ბáƒáƒ áƒáƒ—ის დეტáƒáƒšáƒ”ბს. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">მიუწვდáƒáƒ›áƒ”ლირთქვენი პლáƒáƒ¢áƒ¤áƒáƒ áƒ›áƒ˜áƒ¡áƒ—ვის.</translation>
<translation id="733923710415886693">სერვერის სერტიფიკáƒáƒ¢áƒ˜áƒ¡ გáƒáƒ›áƒáƒ¥áƒ•áƒ”ყნებრსერტიფიკáƒáƒ¢áƒ—რგáƒáƒ›áƒ­áƒ•áƒ˜áƒ áƒ•áƒáƒšáƒáƒ‘ის შესáƒáƒ®áƒ”ბ წესების შესáƒáƒ‘áƒáƒ›áƒ˜áƒ¡áƒáƒ“ áƒáƒ  მáƒáƒ›áƒ®áƒ“áƒáƒ áƒ.</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1960,6 +2008,7 @@
<translation id="7378627244592794276">áƒáƒ áƒ</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">áƒáƒ  მიესáƒáƒ“áƒáƒ’ებáƒ</translation>
+<translation id="7388594495505979117">{0,plural, =1{თქვენი მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘რგáƒáƒ“áƒáƒ˜áƒ¢áƒ•áƒ˜áƒ áƒ—ებრ1 წუთში}other{თქვენი მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘რგáƒáƒ“áƒáƒ˜áƒ¢áƒ•áƒ˜áƒ áƒ—ებრ# წუთში}}</translation>
<translation id="7390545607259442187">დáƒáƒáƒ“áƒáƒ¡áƒ¢áƒ£áƒ áƒ”თ ბáƒáƒ áƒáƒ—ი</translation>
<translation id="7392089738299859607">მისáƒáƒ›áƒáƒ áƒ—ის გáƒáƒœáƒáƒ®áƒšáƒ”ბáƒ</translation>
<translation id="7399802613464275309">უსáƒáƒ¤áƒ áƒ—ხáƒáƒ”ბის შემáƒáƒ¬áƒ›áƒ”ბáƒ</translation>
@@ -1996,6 +2045,12 @@
<translation id="7485870689360869515">მáƒáƒœáƒáƒªáƒ”მები ვერ მáƒáƒ˜áƒ«áƒ”ბნáƒ.</translation>
<translation id="7495528107193238112">ეს კáƒáƒœáƒ¢áƒ”ნტი დáƒáƒ‘ლáƒáƒ™áƒ˜áƒšáƒ˜áƒ. დáƒáƒ£áƒ™áƒáƒ•áƒ¨áƒ˜áƒ áƒ“ით სáƒáƒ˜áƒ¢áƒ˜áƒ¡ მფლáƒáƒ‘ელს áƒáƒ› პრáƒáƒ‘ლემის მáƒáƒ¡áƒáƒ’ვáƒáƒ áƒ”ბლáƒáƒ“.</translation>
<translation id="7497998058912824456">დáƒáƒ™áƒ£áƒ›áƒ”ნტის შექმნის ღილáƒáƒ™áƒ˜, áƒáƒ®áƒáƒšáƒ˜ Google Doc-ის სწრáƒáƒ¤áƒáƒ“ შესáƒáƒ¥áƒ›áƒœáƒ”ლáƒáƒ“ დáƒáƒáƒ­áƒ˜áƒ áƒ”თ კლáƒáƒ•áƒ˜áƒ¨áƒ¡ Enter</translation>
+<translation id="7506488012654002225">Chromium-ის მიერ <ph name="BEGIN_EMPHASIS" />áƒáƒ  შეინáƒáƒ®áƒ”ბáƒ<ph name="END_EMPHASIS" /> შემდეგი ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />დáƒáƒ—ვáƒáƒšáƒ˜áƒ”რების ისტáƒáƒ áƒ˜áƒ
+ <ph name="LIST_ITEM" />ქუქი-ჩáƒáƒœáƒáƒ¬áƒ”რები დრსáƒáƒ˜áƒ¢áƒ”ბის მáƒáƒœáƒáƒªáƒ”მები
+ <ph name="LIST_ITEM" />ფáƒáƒ áƒ›áƒ”ბში მითითებული ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">წესების დáƒáƒ‘რუნებული მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘ის ID ცáƒáƒ áƒ˜áƒ”ლირáƒáƒœ áƒáƒ›áƒŸáƒáƒ›áƒ˜áƒœáƒ“ელ მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘ის ID-ს áƒáƒ  ემთხვევáƒ</translation>
<translation id="7508870219247277067">áƒáƒ•áƒáƒ™áƒáƒ“áƒáƒ¡áƒ¤áƒ”რი</translation>
<translation id="7511955381719512146">Wi-Fi-მ, რáƒáƒ›áƒ”ლსáƒáƒª თქვენ იყენებთ შეიძლებრმáƒáƒ˜áƒ—ხáƒáƒ•áƒáƒ¡ თქვენ სტუმრáƒáƒ‘რ<ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
@@ -2109,7 +2164,6 @@
<translation id="7813600968533626083">áƒáƒ›áƒáƒ˜áƒ¨áƒáƒšáƒáƒ¡ ფáƒáƒ áƒ›áƒ”ბისთვის გáƒáƒœáƒ™áƒ£áƒ—ვნილი შემáƒáƒ—áƒáƒ•áƒáƒ–ებრChrome-იდáƒáƒœ?</translation>
<translation id="781440967107097262">გსურთ გáƒáƒªáƒ•áƒšáƒ˜áƒ¡ ბუფერის გáƒáƒ–იáƒáƒ áƒ”ბáƒ?</translation>
<translation id="7815407501681723534">მáƒáƒ—ხáƒáƒ•áƒœáƒáƒ–ე „<ph name="SEARCH_STRING" />“ მáƒáƒ˜áƒ«áƒ”ბნრ<ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /></translation>
-<translation id="782125616001965242">áƒáƒ› სáƒáƒ˜áƒ¢áƒ˜áƒ¡ შესáƒáƒ®áƒ”ბ ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ˜áƒ¡ ჩვენებáƒ</translation>
<translation id="782886543891417279">Wi-Fi-მ, რáƒáƒ›áƒ”ლსáƒáƒª თქვენ იყენებთ (<ph name="WIFI_NAME" />) შეიძლებრმáƒáƒ˜áƒ—ხáƒáƒ•áƒáƒ¡ თქვენი სტუმრáƒáƒ‘რმის áƒáƒ•áƒ¢áƒáƒ áƒ˜áƒ–áƒáƒªáƒ˜áƒ˜áƒ¡ გვერდზე.</translation>
<translation id="7836231406687464395">Postfix (კáƒáƒœáƒ•áƒ”რტი)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{áƒáƒ áƒªáƒ”რთი}=1{1 áƒáƒžáƒ˜ (<ph name="EXAMPLE_APP_1" />)}=2{2 áƒáƒžáƒ˜ (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}other{# áƒáƒžáƒ˜ (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" /> <ph name="AND_MORE" />)}}</translation>
@@ -2126,7 +2180,6 @@
<translation id="7888575728750733395">ბეჭდვის რენდერის სქემáƒ</translation>
<translation id="7894280532028510793">თუ სწáƒáƒ áƒáƒ“ áƒáƒ áƒ˜áƒ¡ áƒáƒ™áƒ áƒ”ფილი, <ph name="BEGIN_LINK" />ცáƒáƒ“ეთ ქსელის დიáƒáƒ’ნáƒáƒ¡áƒ¢áƒ˜áƒ™áƒ<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (კáƒáƒœáƒ•áƒ”რტი)</translation>
-<translation id="7931318309563332511">უცნáƒáƒ‘ი</translation>
<translation id="793209273132572360">გსურთ მისáƒáƒ›áƒáƒ áƒ—ის გáƒáƒœáƒáƒ®áƒšáƒ”ბáƒ?</translation>
<translation id="7932579305932748336">ფენით დáƒáƒ¤áƒáƒ áƒ•áƒ</translation>
<translation id="79338296614623784">შეიყვáƒáƒœáƒ”თ სწáƒáƒ áƒ˜ ტელეფáƒáƒœáƒ˜áƒ¡ ნáƒáƒ›áƒ”რი</translation>
@@ -2151,13 +2204,14 @@
<translation id="7976214039405368314">ზედმეტáƒáƒ“ ბევრი მáƒáƒ—ხáƒáƒ•áƒœáƒáƒ</translation>
<translation id="7977538094055660992">გáƒáƒ›áƒáƒ¢áƒáƒœáƒ˜áƒ¡ მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘áƒ</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">მიბმულირშემდეგთáƒáƒœ:</translation>
<translation id="798134797138789862">შეუძლირვირტუáƒáƒšáƒ£áƒ áƒ˜ რეáƒáƒšáƒáƒ‘ის მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘ებისრდრმáƒáƒœáƒáƒªáƒ”მების გáƒáƒ›áƒáƒ§áƒ”ნების თხáƒáƒ•áƒœáƒ</translation>
<translation id="7984945080620862648"><ph name="SITE" /> სáƒáƒ˜áƒ¢áƒ–ე შესვლრáƒáƒ›áƒŸáƒáƒ›áƒáƒ“ შეუძლებელიáƒ, რáƒáƒ“გáƒáƒœ ვებსáƒáƒ˜áƒ¢áƒ›áƒ გáƒáƒ›áƒáƒ’ზáƒáƒ•áƒœáƒ დáƒáƒ–იáƒáƒœáƒ”ბული მტკიცებულებები, რáƒáƒ›áƒ”ლთრწáƒáƒ™áƒ˜áƒ—ხვáƒáƒ¡ Chrome ვერ áƒáƒ®áƒ”რხებს. ქსელური შეცდáƒáƒ›áƒ”ბი დრშეტევები, ჩვეულებრივ, დრáƒáƒ”ბითიáƒ, áƒáƒ›áƒ˜áƒ¢áƒáƒ› მáƒáƒ’ვიáƒáƒœáƒ”ბით ეს გვერდი შეიძლებრáƒáƒ›áƒ£áƒ¨áƒáƒ•áƒ“ეს.</translation>
-<translation id="79859296434321399">áƒáƒ£áƒ’მენტური რეáƒáƒšáƒáƒ‘ის კáƒáƒœáƒ¢áƒ”ნტის სáƒáƒœáƒáƒ®áƒáƒ•áƒáƒ“ დáƒáƒáƒ˜áƒœáƒ¡áƒ¢áƒáƒšáƒ˜áƒ áƒ”თ ARCore</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">áƒáƒ™áƒ˜áƒœáƒ«áƒ•áƒ</translation>
<translation id="7992044431894087211">ეკრáƒáƒœáƒ˜áƒ¡ <ph name="APPLICATION_TITLE" />-თáƒáƒœ გáƒáƒ–იáƒáƒ áƒ”ბრáƒáƒ¦áƒ“გენილიáƒ</translation>
<translation id="7995512525968007366">áƒáƒ  áƒáƒ áƒ˜áƒ¡ მითითებული</translation>
+<translation id="7998269595945679889">áƒáƒ®áƒáƒšáƒ˜ ინკáƒáƒ’ნიტრჩáƒáƒœáƒáƒ áƒ—ის გáƒáƒ®áƒ¡áƒœáƒ˜áƒ¡ ღილáƒáƒ™áƒ˜, ვების კáƒáƒœáƒ¤áƒ˜áƒ“ენციáƒáƒšáƒ£áƒ áƒáƒ“ დáƒáƒ—ვáƒáƒšáƒ˜áƒ”რებისთვის áƒáƒ®áƒáƒšáƒ˜ ინკáƒáƒ’ნიტრჩáƒáƒœáƒáƒ áƒ—ის გáƒáƒ¡áƒáƒ®áƒ¡áƒœáƒ”ლáƒáƒ“ დáƒáƒáƒ­áƒ˜áƒ áƒ”თ შეყვáƒáƒœáƒ˜áƒ¡ ღილáƒáƒ™áƒ¡</translation>
<translation id="800218591365569300">მეხსიერების გáƒáƒ›áƒáƒ¡áƒáƒ—áƒáƒ•áƒ˜áƒ¡áƒ£áƒ¤áƒšáƒ”ბლáƒáƒ“ ცáƒáƒ“ეთ სხვრჩáƒáƒœáƒáƒ áƒ—ების áƒáƒœ პრáƒáƒ’რáƒáƒ›áƒ”ბის დáƒáƒ®áƒ£áƒ áƒ•áƒ.</translation>
<translation id="8004582292198964060">ბრáƒáƒ£áƒ–ერი</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{ეს ბáƒáƒ áƒáƒ—ი დრმისი ბილინგის მისáƒáƒ›áƒáƒ áƒ—ი შეინáƒáƒ®áƒ”ბáƒ. მის გáƒáƒ›áƒáƒ§áƒ”ნებáƒáƒ¡ შეძლებთ, რáƒáƒªáƒ შესული იქნებით <ph name="USER_EMAIL" />-ში.}other{ეს ბáƒáƒ áƒáƒ—ები დრმáƒáƒ—ი ბილინგის მისáƒáƒ›áƒáƒ áƒ—ები შეინáƒáƒ®áƒ”ბáƒ. მáƒáƒ— გáƒáƒ›áƒáƒ§áƒ”ნებáƒáƒ¡ შეძლებთ, რáƒáƒªáƒ შესული იქნებით <ph name="USER_EMAIL" />-ში.}}</translation>
@@ -2217,6 +2271,7 @@
<translation id="8202370299023114387">კáƒáƒœáƒ¤áƒšáƒ˜áƒ¥áƒ¢áƒ˜</translation>
<translation id="8206978196348664717">Prc4 (კáƒáƒœáƒ•áƒ”რტი)</translation>
<translation id="8211406090763984747">კáƒáƒ•áƒ¨áƒ˜áƒ áƒ˜ დáƒáƒªáƒ£áƒšáƒ˜áƒ</translation>
+<translation id="8217240300496046857">სáƒáƒ˜áƒ¢áƒ”ბი ვერ გáƒáƒ›áƒáƒ˜áƒ§áƒ”ნებს ქუქი-ჩáƒáƒœáƒáƒ¬áƒ”რებს ვებში თქვენთვის თვáƒáƒšáƒ˜áƒ¡ მისáƒáƒ“ევნებლáƒáƒ“. ზáƒáƒ’იერთი სáƒáƒ˜áƒ¢áƒ˜áƒ¡ ფუნქციებმრშეიძლებრáƒáƒ áƒáƒ¡áƒáƒ—áƒáƒœáƒáƒ“áƒáƒ“ იმუშáƒáƒáƒ¡.</translation>
<translation id="8218327578424803826">მიმáƒáƒ’რებული მდებáƒáƒ áƒ”áƒáƒ‘áƒ:</translation>
<translation id="8220146938470311105">C7/C6 (კáƒáƒœáƒ•áƒ”რტი)</translation>
<translation id="8225771182978767009">პირáƒáƒ•áƒœáƒ”ბáƒáƒ›, რáƒáƒ›áƒ”ლმáƒáƒª ეს კáƒáƒ›áƒžáƒ˜áƒ£áƒ¢áƒ”რი გáƒáƒ›áƒáƒ áƒ—áƒ, áƒáƒ› სáƒáƒ˜áƒ¢áƒ˜áƒ¡ დáƒáƒ‘ლáƒáƒ™áƒ•áƒ áƒáƒ˜áƒ áƒ©áƒ˜áƒ.</translation>
@@ -2257,14 +2312,9 @@
<translation id="830498451218851433">დáƒáƒ™áƒ”ცვრნáƒáƒ®áƒ”ვრáƒáƒ“</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">დáƒáƒ˜áƒœáƒ¡áƒ¢áƒáƒšáƒ˜áƒ áƒ”ბული áƒáƒžáƒ”ბი დრმáƒáƒ—ი გáƒáƒ›áƒáƒ§áƒ”ნების სიხშირე</translation>
+<translation id="8317207217658302555">გსურთ, გáƒáƒœáƒáƒáƒ®áƒšáƒáƒ— ARCore?</translation>
<translation id="831997045666694187">სáƒáƒ¦áƒáƒ›áƒ</translation>
<translation id="8321476692217554900">შეტყáƒáƒ‘ინებები</translation>
-<translation id="8328484624016508118">ყველრინკáƒáƒ’ნიტრჩáƒáƒœáƒáƒ áƒ—ის დáƒáƒ®áƒ£áƒ áƒ•áƒ˜áƒ¡ შემდეგ Chrome-ის მიერ გáƒáƒ¡áƒ£áƒ¤áƒ—áƒáƒ•áƒ“ებáƒ:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />ვების დáƒáƒ—ვáƒáƒšáƒ˜áƒ”რებáƒáƒ¡áƒ—áƒáƒœ დáƒáƒ™áƒáƒ•áƒ¨áƒ˜áƒ áƒ”ბული თქვენი áƒáƒ¥áƒ¢áƒ˜áƒ•áƒáƒ‘რáƒáƒ› მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘áƒáƒ–ე<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />თქვენი ძიების ისტáƒáƒ áƒ˜áƒ áƒáƒ› მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘áƒáƒ–ე<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />თქვენ მიერ ფáƒáƒ áƒ›áƒ”ბში შეყვáƒáƒœáƒ˜áƒšáƒ˜ ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489"><ph name="HOST_NAME" />-ზე წვდáƒáƒ›áƒ áƒáƒ™áƒ áƒ«áƒáƒšáƒ£áƒšáƒ˜áƒ</translation>
<translation id="833262891116910667">გáƒáƒ›áƒáƒ§áƒáƒ¤áƒ</translation>
<translation id="8339163506404995330"><ph name="LANGUAGE" /> გვერდები áƒáƒ  ითáƒáƒ áƒ’მნებáƒ</translation>
@@ -2316,6 +2366,7 @@
<translation id="8507227106804027148">ბრძáƒáƒœáƒ”ბáƒáƒ—რსტრიქáƒáƒœáƒ˜</translation>
<translation id="8508648098325802031">ძიების ხáƒáƒ¢áƒ£áƒšáƒ</translation>
<translation id="8511402995811232419">ქუქი-ჩáƒáƒœáƒáƒ¬áƒ”რების მáƒáƒ áƒ—ვáƒ</translation>
+<translation id="8519753333133776369">HID მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘რდáƒáƒ¨áƒ•áƒ”ბულირთქვენი áƒáƒ“მინისტრáƒáƒ¢áƒáƒ áƒ˜áƒ¡ მიერ</translation>
<translation id="8522552481199248698">Chrome-ს შეუძლირდáƒáƒ’ეხმáƒáƒ áƒáƒ— თქვენი Google áƒáƒœáƒ’áƒáƒ áƒ˜áƒ¨áƒ˜áƒ¡ დáƒáƒªáƒ•áƒáƒ¨áƒ˜ დრპáƒáƒ áƒáƒšáƒ˜áƒ¡ შეცვლáƒáƒ¨áƒ˜.</translation>
<translation id="8530813470445476232">გáƒáƒáƒ¡áƒ£áƒ¤áƒ—áƒáƒ•áƒ”თ დáƒáƒ—ვáƒáƒšáƒ˜áƒ”რების ისტáƒáƒ áƒ˜áƒ, ქუქი-ჩáƒáƒœáƒáƒ¬áƒ”რები, ქეში დრსხვრკáƒáƒœáƒ¢áƒ”ნტი Chrome-ის პáƒáƒ áƒáƒ›áƒ”ტრებიდáƒáƒœ</translation>
<translation id="8533619373899488139">ეწვიეთ გვერდს &lt;strong&gt;chrome://policy&lt;/strong&gt; დáƒáƒ‘ლáƒáƒ™áƒ˜áƒšáƒ˜ URL-ების სáƒáƒœáƒáƒ®áƒáƒ•áƒáƒ“ დრáƒáƒ“მინისტრáƒáƒ¢áƒáƒ áƒ˜áƒ¡ მიერ გáƒáƒáƒ¥áƒ¢áƒ˜áƒ£áƒ áƒ”ბული სხვრწესების დáƒáƒ¡áƒáƒ—ვáƒáƒšáƒ˜áƒ”რებლáƒáƒ“.</translation>
@@ -2327,7 +2378,6 @@
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{ნებáƒáƒ áƒ—ვის გáƒáƒ“áƒáƒ§áƒ”ნებáƒ}other{ნებáƒáƒ áƒ—ვების გáƒáƒ“áƒáƒ§áƒ”ნებáƒ}}</translation>
<translation id="8555010941760982128">გáƒáƒ›áƒáƒ˜áƒ§áƒ”ნეთ ეს კáƒáƒ“ი შეკვეთის გáƒáƒ¤áƒáƒ áƒ›áƒ”ბისáƒáƒ¡</translation>
<translation id="8557066899867184262">CVC მითითებულირთქვენი ბáƒáƒ áƒáƒ—ის უკáƒáƒœáƒ ნáƒáƒ¬áƒ˜áƒšáƒ–ე.</translation>
-<translation id="8558485628462305855">áƒáƒ£áƒ’მენტური რეáƒáƒšáƒáƒ‘ის კáƒáƒœáƒ¢áƒ”ნტის სáƒáƒœáƒáƒ®áƒáƒ•áƒáƒ“ გáƒáƒœáƒáƒáƒ®áƒšáƒ”თ ARCore</translation>
<translation id="8559762987265718583"><ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />-თáƒáƒœ პირáƒáƒ“ი კáƒáƒ•áƒ¨áƒ˜áƒ áƒ˜áƒ¡ დáƒáƒ›áƒ§áƒáƒ áƒ”ბრშეუძლებელიáƒ, რáƒáƒ“გáƒáƒœ თქვენი მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘ის თáƒáƒ áƒ˜áƒ¦áƒ˜ დრდრáƒÂ (<ph name="DATE_AND_TIME" />) áƒáƒ áƒáƒ¡áƒ¬áƒáƒ áƒ˜áƒ.</translation>
<translation id="8564182942834072828">სხვáƒáƒ“áƒáƒ¡áƒ®áƒ•áƒ დáƒáƒ™áƒ£áƒ›áƒ”ნტი/შეურჩეველი áƒáƒ¡áƒšáƒ”ბი</translation>
<translation id="8564985650692024650">Chromium გირჩევთ, გáƒáƒ“áƒáƒáƒ§áƒ”ნáƒáƒ— <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" />-ის პáƒáƒ áƒáƒšáƒ˜, თუ მáƒáƒ¡ სხვრსáƒáƒ˜áƒ¢áƒ”ბზეც იყენებთ.</translation>
@@ -2346,6 +2396,7 @@
<translation id="865032292777205197">მáƒáƒ«áƒ áƒáƒáƒ‘ის სენსáƒáƒ áƒ”ბი</translation>
<translation id="8663226718884576429">შეკვეთის რეზიუმე, <ph name="TOTAL_LABEL" />, დáƒáƒ›áƒáƒ¢áƒ”ბითი ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ</translation>
<translation id="8666678546361132282">ინგლისური</translation>
+<translation id="8669306706049782872">გáƒáƒ›áƒáƒ˜áƒ§áƒ”ნáƒáƒ¡ ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ თქვენი ეკრáƒáƒœáƒ”ბის შესáƒáƒ®áƒ”ბ ფáƒáƒœáƒ¯áƒ áƒ”ბის გáƒáƒ¡áƒáƒ¦áƒ”ბáƒáƒ“ დრგáƒáƒœáƒ¡áƒáƒ—áƒáƒ•áƒ¡áƒ”ბლáƒáƒ“</translation>
<translation id="867224526087042813">ხელმáƒáƒ¬áƒ”რáƒ</translation>
<translation id="8676424191133491403">დáƒáƒ§áƒáƒ•áƒœáƒ”ბის გáƒáƒ áƒ”შე</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, პáƒáƒ¡áƒ£áƒ®áƒ˜, <ph name="ANSWER" /></translation>
@@ -2372,6 +2423,7 @@
<translation id="8731544501227493793">პáƒáƒ áƒáƒšáƒ”ბის მáƒáƒ áƒ—ვის ღილáƒáƒ™áƒ˜, Chrome-ის პáƒáƒ áƒáƒ›áƒ”ტრებიდáƒáƒœ თქვენი პáƒáƒ áƒáƒšáƒ”ბის სáƒáƒœáƒáƒ®áƒáƒ•áƒáƒ“ დრსáƒáƒ›áƒáƒ áƒ—áƒáƒ•áƒáƒ“ დáƒáƒáƒ­áƒ˜áƒ áƒ”თ კლáƒáƒ•áƒ˜áƒ¨áƒ¡ Enter</translation>
<translation id="8734529307927223492">თქვენი <ph name="DEVICE_TYPE" /> იმáƒáƒ áƒ—ებრ<ph name="MANAGER" />-ის მიერ</translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, ვების კáƒáƒœáƒ¤áƒ˜áƒ“ენციáƒáƒšáƒ£áƒ áƒáƒ“ დáƒáƒ¡áƒáƒ—ვáƒáƒšáƒ˜áƒ”რებლáƒáƒ“ áƒáƒ®áƒáƒšáƒ˜ ინკáƒáƒ’ნიტრფáƒáƒœáƒ¯áƒ áƒ˜áƒ¡ გáƒáƒ¡áƒáƒ®áƒ¡áƒœáƒ”ლáƒáƒ“ დáƒáƒáƒ­áƒ˜áƒ áƒ”თ კლáƒáƒ•áƒ˜áƒ¨áƒ¡ Tab, შემდეგ კი Enter-ს</translation>
+<translation id="8737685506611670901"><ph name="REPLACED_HANDLER_TITLE" />-ის ნáƒáƒªáƒ•áƒšáƒáƒ“, <ph name="PROTOCOL" />-ის ბმულების გáƒáƒ®áƒ¡áƒœáƒ</translation>
<translation id="8738058698779197622">უსáƒáƒ¤áƒ áƒ—ხრკáƒáƒ•áƒ¨áƒ˜áƒ áƒ˜áƒ¡ დáƒáƒ¡áƒáƒ›áƒ§áƒáƒ áƒ”ბლáƒáƒ“, სáƒáƒ­áƒ˜áƒ áƒáƒ სáƒáƒáƒ—ის გáƒáƒ¡áƒ¬áƒáƒ áƒ”ბáƒ. áƒáƒ›áƒ˜áƒ¡ მიზეზირის, რáƒáƒ› სერტიფიკáƒáƒ¢áƒ”ბი, რáƒáƒ›áƒšáƒ”ბსáƒáƒª ვებსáƒáƒ˜áƒ¢áƒ”ბი იყენებენ იდენტიფიცირების მიზნით, მáƒáƒ¥áƒ›áƒ”დებს მხáƒáƒšáƒáƒ“ გáƒáƒ áƒ™áƒ•áƒ”ული პერიáƒáƒ“ის გáƒáƒœáƒ›áƒáƒ•áƒšáƒáƒ‘áƒáƒ¨áƒ˜. რáƒáƒ“გáƒáƒœ თქვენი მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘ის სáƒáƒáƒ—ი áƒáƒ áƒáƒ¡áƒ¬áƒáƒ áƒ˜áƒ, Chromium ვერ დáƒáƒáƒ“áƒáƒ¡áƒ¢áƒ£áƒ áƒ”ბს áƒáƒ› სერტიფიკáƒáƒ¢áƒ”ბს.</translation>
<translation id="8740359287975076522"><ph name="HOST_NAME" />-ის &lt;abbr id="dnsDefinition"&gt;DNS მისáƒáƒ›áƒáƒ áƒ—ი&lt;/abbr&gt; ვერ მáƒáƒ˜áƒ«áƒ”ბნáƒ. მიმდინáƒáƒ áƒ”áƒáƒ‘ს პრáƒáƒ‘ლემის დიáƒáƒ’ნáƒáƒ¡áƒ¢áƒ˜áƒ™áƒ.</translation>
<translation id="8742371904523228557"><ph name="ONE_TIME_CODE" /> áƒáƒ áƒ˜áƒ¡ თქვენი კáƒáƒ“ი <ph name="ORIGIN" />-ისთვის</translation>
@@ -2399,6 +2451,7 @@
<translation id="883848425547221593">სხვრსáƒáƒœáƒ˜áƒ¨áƒœáƒ”ები</translation>
<translation id="884264119367021077">მიწáƒáƒ“ების მისáƒáƒ›áƒáƒ áƒ—ი</translation>
<translation id="884923133447025588">გáƒáƒ£áƒ¥áƒ›áƒ”ბის მექáƒáƒœáƒ˜áƒ–მის პáƒáƒ•áƒœáƒ ვერ მáƒáƒ®áƒ”რხდáƒ.</translation>
+<translation id="8849262850971482943">დáƒáƒ›áƒáƒ¢áƒ”ბითი უსáƒáƒ¤áƒ áƒ—ხáƒáƒ”ბისთვის გáƒáƒ›áƒáƒ˜áƒ§áƒ”ნეთ თქვენი ვირტუáƒáƒšáƒ£áƒ áƒ˜ ბáƒáƒ áƒáƒ—ი</translation>
<translation id="885730110891505394">Google-თáƒáƒœ გáƒáƒ–იáƒáƒ áƒ”ბáƒ</translation>
<translation id="8858065207712248076">Chrome გირჩევთ, გáƒáƒ“áƒáƒáƒ§áƒ”ნáƒáƒ— <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" />-ის პáƒáƒ áƒáƒšáƒ˜, თუ მáƒáƒ¡ სხვრსáƒáƒ˜áƒ¢áƒ”ბზეც იყენებთ.</translation>
<translation id="885906927438988819">თუ სწáƒáƒ áƒáƒ“ áƒáƒ áƒ˜áƒ¡ áƒáƒ™áƒ áƒ”ფილი, <ph name="BEGIN_LINK" />ცáƒáƒ“ეთ Windows-ის ქსელის დიáƒáƒ’ნáƒáƒ¡áƒ¢áƒ˜áƒ™áƒ<ph name="END_LINK" />.</translation>
@@ -2448,6 +2501,7 @@
<translation id="9004367719664099443">VR სესირáƒáƒ¥áƒ¢áƒ˜áƒ£áƒ áƒ˜áƒ</translation>
<translation id="9005998258318286617">PDF დáƒáƒ™áƒ£áƒ›áƒ”ნტი ვერ ჩáƒáƒ˜áƒ¢áƒ•áƒ˜áƒ áƒ—áƒ.</translation>
<translation id="9008201768610948239">იგნáƒáƒ áƒ˜áƒ áƒ”ბáƒ</translation>
+<translation id="901834265349196618">ელფáƒáƒ¡áƒ¢áƒ</translation>
<translation id="9020200922353704812">ბáƒáƒ áƒáƒ—ის ბილინგის მისáƒáƒ›áƒáƒ áƒ—ი áƒáƒ£áƒªáƒ˜áƒšáƒ”ბელიáƒ</translation>
<translation id="9020542370529661692">ეს გვერდი გáƒáƒ“áƒáƒ—áƒáƒ áƒ’მნილირáƒáƒ› ენáƒáƒ–ე: <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9020742383383852663">A8</translation>
@@ -2496,6 +2550,7 @@
<translation id="9150045010208374699">გáƒáƒ›áƒáƒ˜áƒ§áƒ”ნეთ თქვენი კáƒáƒ›áƒ”რáƒ</translation>
<translation id="9150685862434908345">თქვენს áƒáƒ“მინისტრáƒáƒ¢áƒáƒ áƒ¡ დისტáƒáƒœáƒªáƒ˜áƒ£áƒ áƒáƒ“ შეუძლირბრáƒáƒ£áƒ–ერის დáƒáƒ§áƒ”ნებული პáƒáƒ áƒáƒ›áƒ”ტრების შეცვლáƒ. áƒáƒ› მáƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘áƒáƒ–ე áƒáƒ¥áƒ¢áƒ˜áƒ•áƒáƒ‘რშეიძლებრიმáƒáƒ áƒ—ებáƒáƒ“ეს Chrome-ს მიღმáƒáƒª. <ph name="BEGIN_LINK" />შეიტყვეთ მეტი<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">გáƒáƒœáƒáƒ®áƒšáƒ”ბული</translation>
+<translation id="9155211586651734179">მიერთებული პერიფერიული áƒáƒ£áƒ“იáƒáƒ›áƒáƒ¬áƒ§áƒáƒ‘ილáƒáƒ‘ები</translation>
<translation id="9157595877708044936">დáƒáƒ§áƒ”ნებáƒâ€¦</translation>
<translation id="9158625974267017556">C6 (კáƒáƒœáƒ•áƒ”რტი)</translation>
<translation id="9164029392738894042">სიზუსტის შემáƒáƒ¬áƒ›áƒ”ბáƒ</translation>
diff --git a/chromium/components/strings/components_strings_kk.xtb b/chromium/components/strings/components_strings_kk.xtb
index b3aff87dda2..9cc60cbe890 100644
--- a/chromium/components/strings/components_strings_kk.xtb
+++ b/chromium/components/strings/components_strings_kk.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">Деректерді көру</translation>
<translation id="1030706264415084469"><ph name="URL" /> үлкен көлемді деректерді құрылғыңызда біржола ÑақтағыÑÑ‹ келеді</translation>
<translation id="1032854598605920125">Сағат тілінің бағытымен бұру</translation>
+<translation id="1033329911862281889">Инкогнито режимі интернеттегі Ñ–Ñ-әрекетіңізді жаÑырмайды:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Ñайттар мен қызметтер кірген әрекеттерді тіркейді.<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Ð¶Ò±Ð¼Ñ‹Ñ Ð±ÐµÑ€ÑƒÑˆÑ–Ð»ÐµÑ€ мен білім беру мекемелерінің әкімшілері браузерді қолдану мәліметін қадағалай алады.<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />интернет провайдерлері трафикті бақылай алады.<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">Өшіру</translation>
<translation id="1036982837258183574">Толық Ñкран режимінен шығу үшін |<ph name="ACCELERATOR" />| пернеÑін баÑыңыз</translation>
<translation id="1038106730571050514">Ò°ÑыныÑтарды көрÑету</translation>
<translation id="1038842779957582377">белгіÑіз ат</translation>
<translation id="1041998700806130099">ТапÑырма парағының хабарламаÑÑ‹</translation>
<translation id="1048785276086539861">ÐннотациÑларды өзгерткен кезде, бұл құжат бір беттік көрініÑке ауыÑады.</translation>
-<translation id="1049743911850919806">Инкогнито</translation>
<translation id="1050038467049342496">БаÑқа қолданбаларды жабу</translation>
<translation id="1055184225775184556">&amp;ҚоÑуды болдырмау</translation>
<translation id="1056898198331236512">ЕÑкерту</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">СаÑÑат кÑші жарамды</translation>
<translation id="1130564665089811311">"Бетті аудару" түймеÑÑ–. ОÑÑ‹ бетті Google Translate арқылы аудару үшін Enter пернеÑін баÑыңыз.</translation>
<translation id="1131264053432022307">Көшірілген Ñурет</translation>
+<translation id="1142846828089312304">Инкогнито режимінде үшінші тараптың cookie файлдарын бөгеу</translation>
<translation id="1150979032973867961">Бұл Ñервер оның <ph name="DOMAIN" /> екендігін дәлелдей алмайды; оның қауіпÑіздік Ñертификатын компьютеріңіздің операциÑлық жүйеÑÑ– раÑтамаған. Бұған ÐºÐ¾Ð½Ñ„Ð¸Ð³ÑƒÑ€Ð°Ñ†Ð¸Ñ Ð°Ò›Ð°ÑƒÐ»Ñ‹Ò“Ñ‹ немеÑе қаÑкүнемнің қоÑылымыңызды тоқтатуы Ñебеп болуы мүмкін.</translation>
<translation id="1151972924205500581">ÒšÒ±Ð¿Ð¸Ñ Ñөз қажет</translation>
<translation id="1156303062776767266">Жергілікті немеÑе ортақ файлды көрудеÑіз</translation>
@@ -64,7 +70,6 @@
<translation id="1178581264944972037">Кідірту</translation>
<translation id="1181037720776840403">Өшіру</translation>
<translation id="1186201132766001848">ÒšÒ±Ð¿Ð¸Ñ Ñөздерді текÑеру</translation>
-<translation id="1195210374336998651">Қолданба параметрлеріне өту</translation>
<translation id="1195558154361252544">Сіз Ñ€Ò±Ò›Ñат еткеннен баÑқа Ñайттар үшін хабарландырулар автоматты түрде бөгелді.</translation>
<translation id="1197088940767939838">Қызғылт Ñары</translation>
<translation id="1201402288615127009">КелеÑÑ–</translation>
@@ -111,7 +116,7 @@
<translation id="1307966114820526988">ЕÑкі функциÑлар</translation>
<translation id="1308113895091915999">Ò°ÑÑ‹Ð½Ñ‹Ñ Ò›Ð¾Ð»Ð¶ÐµÑ‚Ñ–Ð¼Ð´Ñ–</translation>
<translation id="1312803275555673949">Оған қандай дәлел бар?</translation>
-<translation id="131405271941274527">NFC құрылғыңыздағы телефоныңызды түрткенде, <ph name="URL" /> ақпарат алмаÑуға Ñ€Ò±Ò›Ñат Ñұрайды.</translation>
+<translation id="1314311879718644478">Толықтырылған шындық мазмұнын көру</translation>
<translation id="1314509827145471431">Оң жақты байлау</translation>
<translation id="1318023360584041678">Қойынды тобында Ñақталған</translation>
<translation id="1319245136674974084">Бұдан былай бұл қолданба үшін ÑұралмаÑын</translation>
@@ -161,6 +166,7 @@
<translation id="142858679511221695">Бұлт пайдаланушыÑÑ‹</translation>
<translation id="1428729058023778569">Бұл Ñайт HTTPS қолдамайды, Ñондықтан оÑÑ‹ хабарландыруды көріп тұрÑыз. <ph name="BEGIN_LEARN_MORE_LINK" />Толығырақ<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">БаÑып шығару</translation>
+<translation id="1432187715652018471">Бет қызмет өңдегішін орнатпақ.</translation>
<translation id="1432581352905426595">Іздеу жүйелерін баÑқару</translation>
<translation id="1436185428532214179">Құрылғыңыздағы файлдар мен қалталарды өзгертуге Ñ€Ò±Ò›Ñат Ñұрай алады.</translation>
<translation id="1442386063175183758">Оң жағын қақпа тәрізді бүктеу</translation>
@@ -181,6 +187,12 @@
<translation id="1483493594462132177">Жіберу</translation>
<translation id="1484290072879560759">Жөнелту мекенжайын таңдау</translation>
<translation id="1492194039220927094">Жаңа ÑаÑÑаттар туралы хабарландыру:</translation>
+<translation id="149293076951187737">Chrome Iраузерінің барлық инкогнито қойындыларын жапқан кезде, Ñол қойындылардағы әрекеттеріңіз құрылғыдан өшіріледі:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />браузерді қолдану мәліметі;<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />іздеу тарихы;<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />үлгілерге енгізілген ақпарат.<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">Қойындыға оралу</translation>
<translation id="1501859676467574491">Google аккаунтына Ñақталған карталар көрÑетілÑін</translation>
<translation id="1507202001669085618">&lt;p&gt;Интернетке кірерде аккаунтқа кіру Ñұралатын Wi-Fi порталын пайдаланған кезде, оÑÑ‹ қате шығады.&lt;/p&gt;
@@ -208,6 +220,8 @@
<translation id="1559572115229829303">&lt;p&gt;<ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> Ò›Ò±Ð¿Ð¸Ñ Ð±Ð°Ð¹Ð»Ð°Ð½Ñ‹Ñын орнату мүмкін емеÑ, Ñебебі құрылғыларыңыздағы күн мен уақыт (<ph name="DATE_AND_TIME" />) Ð´Ò±Ñ€Ñ‹Ñ ÐµÐ¼ÐµÑ.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Параметрлер&lt;/strong&gt; қолданбаÑының &lt;strong&gt;Жалпы&lt;/strong&gt; бөліміндегі күн мен уақытты реттеңіз.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">Әкімші құрылғыңызды өшіріп қоÑатын уақыт: <ph name="DATE" /> <ph name="TIME" /></translation>
+<translation id="156703335097561114">Мекенжайлар, Ð¸Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñ ÐºÐ¾Ð½Ñ„Ð¸Ð³ÑƒÑ€Ð°Ñ†Ð¸ÑÑÑ‹ және Ð±Ð°Ð¹Ð»Ð°Ð½Ñ‹Ñ ÑапаÑÑ‹ ÑиÑқты желі ақпараты</translation>
<translation id="1567040042588613346">Бұл ÑаÑÑат ойдағыдай Ð¶Ò±Ð¼Ñ‹Ñ Ñ–Ñтеуде, бірақ баÑқа жерде оÑÑ‹ ÑаÑÑат бойынша ауыÑтырылатын тап оÑындай мән орнатылған.</translation>
<translation id="1569487616857761740">Жарамдылық мерзімін енгізіңіз.</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@
<translation id="1583429793053364125">Бұл веб-бетті көрÑету кезінде қате кетті.</translation>
<translation id="1586541204584340881">қай кеңейтімдерді орнатқаныңызды;</translation>
<translation id="1588438908519853928">Қалыпты</translation>
+<translation id="1589050138437146318">ARCore орнатылÑын ба?</translation>
<translation id="1592005682883173041">Жергілікті деректерге кіру</translation>
<translation id="1594030484168838125">Таңдау</translation>
<translation id="160851722280695521">Chrome-да Dino Run ойынын ойнау</translation>
@@ -254,7 +269,7 @@
<translation id="1711234383449478798">Еленбеді, Ñебебі <ph name="POLICY_NAME" /> ÑаÑÑатына <ph name="VALUE" /> мәні орнатылмаған.</translation>
<translation id="1712552549805331520"><ph name="URL" /> деректерді жергілікті компьютеріңізде біржола ÑақтағыÑÑ‹ келеді</translation>
<translation id="1713628304598226412">2-науа</translation>
-<translation id="1715874602234207">F</translation>
+<translation id="1715874602234207">Жм</translation>
<translation id="1717218214683051432">ÒšÐ¾Ð·Ò“Ð°Ð»Ñ‹Ñ Ð´Ð°Ñ‚Ñ‡Ð¸ÐºÑ‚ÐµÑ€Ñ–</translation>
<translation id="1717494416764505390">3-ші пошта жәшігі</translation>
<translation id="1718029547804390981">ÐÐ½Ð½Ð¾Ñ‚Ð°Ñ†Ð¸Ñ Ò›Ð¾Ñуға құжат өлшемі өте үлкен.</translation>
@@ -283,6 +298,7 @@
атауының пішіні өзгерген, бұл — браузердің <ph name="SITE" /> Ñайтына берілген Ñұрауларды толтыруына
жол бермейді. Сайттың қауіпÑіздік параметрлері мен
баÑқа Ñипаттарын конфигурациÑлау үшін Ñайт операторлары түпнұÑқа ÑаÑÑаттарын қолдануы мүмкін.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Chromium браузеріндегі инкогнито режимі туралы толығырақ<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">Ðшық қойынды оÑÑ‹ жерден шығады</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -410,6 +426,7 @@
<translation id="22081806969704220">3-науа</translation>
<translation id="2212735316055980242">СаÑÑат табылмады</translation>
<translation id="2213606439339815911">Жазбалар алынуда…</translation>
+<translation id="2213612003795704869">Бет баÑып шығарылды.</translation>
<translation id="2215727959747642672">Файлды өңдеу</translation>
<translation id="2218879909401188352">Ðғымдағы <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> Ñайтындағы шабуылдаушылар құрылғыңызға зақым келтіретін қауіпті қолданбаларды орнатуы, мобильді шотқа жаÑырын ақыларды қоÑуы немеÑе жеке ақпаратты ұрлауы мүмкін. <ph name="BEGIN_LEARN_MORE_LINK" />Толығырақ<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">Интернет жоқ</translation>
@@ -419,6 +436,7 @@
<translation id="2248949050832152960">WebAuthn пайдалану</translation>
<translation id="2250931979407627383">Сол жақ жиегін тігу</translation>
<translation id="225207911366869382">Бұл ÑаÑÑат үшін бұл мән Ò±Ñынылмаған.</translation>
+<translation id="2256115617011615191">Қазір қайта Ñ–Ñке қоÑу</translation>
<translation id="2258928405015593961">Мерзімнің аÑқталатын күнін енгізіп, қайталап көріңіз.</translation>
<translation id="225943865679747347">Қате коды: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">HTTP қатеÑÑ–</translation>
@@ -446,6 +464,7 @@
<translation id="2337852623177822836">Әкімші баÑқаратын параметр</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> Ñайты жұптаÑқыÑÑ‹ келеді</translation>
<translation id="2346319942568447007">Көшірілген Ñурет</translation>
+<translation id="2350796302381711542"><ph name="HANDLER_HOSTNAME" /> хоÑтына <ph name="REPLACED_HANDLER_TITLE" /> орнына барлық <ph name="PROTOCOL" /> Ñілтемелерін ашуға Ñ€Ò±Ò›Ñат береÑіз бе?</translation>
<translation id="2354001756790975382">БаÑқа бетбелгілер</translation>
<translation id="2354430244986887761">Жақында Google Safe Browsing <ph name="SITE" /> Ñайтынан <ph name="BEGIN_LINK" /> зиÑнды қолданбаларды тапты<ph name="END_LINK" />.</translation>
<translation id="2355395290879513365">Шабуылдаушылар бұл Ñайтта көріп жатқан кеÑкіндеріңізді біліп, оларды өзгерту арқылы Ñізді алдауы мүмкін.</translation>
@@ -471,6 +490,7 @@
<translation id="2413528052993050574">Бұл Ñервер өзінің <ph name="DOMAIN" /> екенін дәлелдей алмады; оның қауіпÑіздік Ñертификаты қайтарып алынған болуы мүмкін. Бұл Ð´Ò±Ñ€Ñ‹Ñ ÐºÐ¾Ð½Ñ„Ð¸Ð³ÑƒÑ€Ð°Ñ†Ð¸Ñланбағаннан немеÑе зиÑнды бағдарламаның байланыÑқа кедергі келтіргенінен болуы мүмкін.</translation>
<translation id="2414886740292270097">Күңгірт</translation>
<translation id="2430968933669123598">Google аккаунтын баÑқару, Google аккаунтыңыздағы ақпаратты, құпиÑлылықты және қауіпÑіздікті баÑқару үшін Enter пернеÑін баÑыңыз.</translation>
+<translation id="2436186046335138073"><ph name="HANDLER_HOSTNAME" /> хоÑтына <ph name="PROTOCOL" /> Ñілтемелерін ашуға Ñ€Ò±Ò›Ñат береÑіз бе?</translation>
<translation id="2438874542388153331">Оң жағын төрт рет теÑу</translation>
<translation id="2450021089947420533">Journeys</translation>
<translation id="2463739503403862330">Толтыру</translation>
@@ -478,6 +498,7 @@
<translation id="2465655957518002998">Жеткізу әдіÑін таңдау</translation>
<translation id="2465688316154986572">ҚапÑыру</translation>
<translation id="2465914000209955735">Chrome браузерінде жүктеп алған файлдарды баÑқару</translation>
+<translation id="2466004615675155314">Интернеттен алынған ақпаратты көрÑету</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Network Diagnostics құралын қоÑу<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">1 баÑтап N дейінгі ретпен</translation>
<translation id="2470767536994572628">ÐннотациÑларды өзгерткен кезде, бұл құжат бір беттік көрініÑке ауыÑады және баÑтапқыдағыдай бұрылып тұрады.</translation>
@@ -498,6 +519,7 @@
<translation id="2523886232349826891">Тек оÑÑ‹ құрылғыда Ñақталады</translation>
<translation id="2524461107774643265">ҚоÑымша ақпарат енгізу</translation>
<translation id="2529899080962247600">Бұл өріÑтегі жазбалардың макÑималды Ñаны: <ph name="MAX_ITEMS_LIMIT" />. Қалған жазбалар еленбейтін болады.</translation>
+<translation id="2535585790302968248">ÒšÒ±Ð¿Ð¸Ñ ÑˆÐ°Ñ€Ð»Ð°Ñƒ үшін жаңа инкогнито қойындыÑын ашыңыз.</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{және тағы 1}other{және тағы #}}</translation>
<translation id="2536110899380797252">Мекенжай енгізу</translation>
<translation id="2539524384386349900">Ðнықтау</translation>
@@ -523,7 +545,14 @@
<translation id="2597378329261239068">Бұл құжат Ò›Ò±Ð¿Ð¸Ñ Ñөзбен қорғалған. ÒšÒ±Ð¿Ð¸Ñ Ñөзді енгізіңіз.</translation>
<translation id="2609632851001447353">ÐÒ±Ñқалар</translation>
<translation id="2610561535971892504">БаÑып көшіру</translation>
+<translation id="2617988307566202237">Chrome келеÑÑ– ақпаратты <ph name="BEGIN_EMPHASIS" />Ñақтамайды<ph name="END_EMPHASIS" />:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />браузерді қолдану тарихы;
+ <ph name="LIST_ITEM" />cookie файлдары және Ñайт деректері;
+ <ph name="LIST_ITEM" />үлгілерге енгізілген ақпарат.
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (Envelope)</translation>
+<translation id="2623663032199728144">Экрандар туралы ақпаратты пайдалануға Ñ€Ò±Ò›Ñат Ñұрай алады.</translation>
<translation id="2625385379895617796">Сағатыңыз алда</translation>
<translation id="262745152991669301">USB құрылғыларына қоÑылуға Ñ€Ò±Ò›Ñат Ñұрайды</translation>
<translation id="2629325967560697240">Chrome-ның ең жоғарғы деңгейдегі қауіпÑіздігіне ие болу үшін <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />жақÑартылған қорғаныÑÑ‚Ñ‹<ph name="END_ENHANCED_PROTECTION_LINK" /> қоÑыңыз.</translation>
@@ -557,6 +586,7 @@
<translation id="2709516037105925701">Ðвтотолтыру</translation>
<translation id="2713444072780614174">ÐÒ›</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />. Chrome параметрлерінде төлемдеріңіз және неÑиелік картаңыз туралы ақпаратты баÑқару үшін Tab, одан кейін Enter пернеÑін баÑыңыз.</translation>
+<translation id="271663710482723385">Толық Ñкран режимінен шығу үшін |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| пернелерін баÑыңыз.</translation>
<translation id="2721148159707890343">Сұрау Ñәтті жіберілді</translation>
<translation id="2723669454293168317">Chrome параметрлерінен қауіпÑіздік текÑеріÑін Ñ–Ñке қоÑу</translation>
<translation id="2726001110728089263">Бүйірлік науа</translation>
@@ -587,6 +617,7 @@
<translation id="2850739647070081192">Invite (Envelope)</translation>
<translation id="2856444702002559011"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> Ñайтындағы шабуылдаушылар ақпаратыңызды (мыÑалы, Ò›Ò±Ð¿Ð¸Ñ Ñөздер, хабарлар немеÑе неÑиелік карталар) ұрлауға әрекет етуі мүмкін.<ph name="BEGIN_LEARN_MORE_LINK" />Толығырақ<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">Бұл Ñайтта мазалайтын немеÑе жалған ақпаратты жарнамалар көрÑетіледі.</translation>
+<translation id="286512204874376891">Виртуалды карта қолданыÑтағы картаны алаÑқтықтан қорғауға көмектеÑеді. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">ÐÒ› ниетті</translation>
<translation id="2876489322757410363">Сыртқы қолданба арқылы төлеу үшін инкогнито режимінен шығаÑыз. ЖалғаÑтыру керек пе?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />. Chrome параметрлерінен Safe Browsing және Ñ‚.б. баÑқару үшін Tab, ÑоÑын Enter пернеÑін баÑыңыз.</translation>
@@ -611,6 +642,7 @@
<translation id="2930577230479659665">Әр көшірмеден кейін кеÑу</translation>
<translation id="2932085390869194046">ÒšÒ±Ð¿Ð¸Ñ Ñөз жаÑау...</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019"><ph name="PROTOCOL" /> Ñілтемелерін ашу</translation>
<translation id="2941952326391522266">Бұл Ñервер өзінің <ph name="DOMAIN" /> екенін дәлелдей алмады; оның қауіпÑіздік Ñертификаты <ph name="DOMAIN2" /> доменінен алынған. Бұл Ð´Ò±Ñ€Ñ‹Ñ ÐºÐ¾Ð½Ñ„Ð¸Ð³ÑƒÑ€Ð°Ñ†Ð¸Ñланбағаннан немеÑе зиÑнды бағдарламаның байланыÑқа кедергі келтіргенінен болуы мүмкін.</translation>
<translation id="2943895734390379394">Жүктеп Ñалу уақыты:</translation>
<translation id="2948083400971632585">Сіз параметрлер бетінен қоÑылым үшін реттелген кез келген прокÑилерді өшіре алаÑыз.</translation>
@@ -643,6 +675,7 @@
<translation id="3037605927509011580">Қап!</translation>
<translation id="3041612393474885105">Сертификат ақпараты</translation>
<translation id="3044034790304486808">Іздеуді жалғаÑтыру</translation>
+<translation id="305162504811187366">Chrome Remote Desktop тарихы, Ñоның ішінде уақыт белгілері, хоÑтар мен клиент ÑеанÑының идентификаторлары</translation>
<translation id="3060227939791841287">C9 (Envelope)</translation>
<translation id="3061707000357573562">Қызметті түзету</translation>
<translation id="306573536155379004">Ойын баÑталды.</translation>
@@ -682,6 +715,7 @@
<translation id="3197136577151645743">ОÑÑ‹ құрылғыны қашан белÑенді пайдаланатыныңыз туралы білу үшін Ñұрай алады</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />, Chrome параметрлеріне кіріп, Ñинхрондалатын ақпаратты баÑқару үшін Tab, ÑоÑын Enter пернелерін баÑыңыз.</translation>
<translation id="320323717674993345">Төлемнен Ð±Ð°Ñ Ñ‚Ð°Ñ€Ñ‚Ñƒ</translation>
+<translation id="3203366800380907218">Интернеттен</translation>
<translation id="3207960819495026254">Бетбелгі қойылған</translation>
<translation id="3209034400446768650">Бұл бет ақылы болуы мүмкін</translation>
<translation id="3212581601480735796"><ph name="HOSTNAME" /> хоÑтында әрекетіңіз бақыланады</translation>
@@ -698,10 +732,12 @@
<translation id="3234666976984236645">Әрқашан оÑÑ‹ Ñайттағы маңызды мазмұнды анықтау</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />. Браузер көрініÑін реттеу үшін Tab, ÑоÑын Enter пернеÑін баÑыңыз.</translation>
<translation id="3240791268468473923">ҚауіпÑіз төлемге арналған деректердің ÑÓ™Ð¹ÐºÐµÑ ÐºÐµÐ»Ð¼ÐµÐ¹Ñ‚Ñ–Ð½Ð´Ñ–Ð³Ñ– көрÑетілген парақ ашылды.</translation>
+<translation id="324180406144491771">"<ph name="HOST_NAME" />" Ñілтемелері бөгелген</translation>
<translation id="3249845759089040423">Заманауи</translation>
<translation id="3252266817569339921">француз</translation>
<translation id="3257954757204451555">Бұл ақпараттың артында кім тұр?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />, Google Calendar-да жылдам жаңа Ñ–Ñ-шара жаÑау үшін Tab, Ñодан кейін Enter пернеÑін баÑыңыз.</translation>
+<translation id="3261488570342242926">Виртуалды карта туралы толығырақ</translation>
<translation id="3264837738038045344">Chrome параметрлерін баÑқару түймеÑÑ–, Chrome параметрлеріне өту үшін Enter пернеÑін баÑыңыз.</translation>
<translation id="3266793032086590337">Мән (қарама-қайшы)</translation>
<translation id="3268451620468152448">Ðшық қойындылар</translation>
@@ -715,6 +751,7 @@
<translation id="3288238092761586174">Төлеміңізді раÑтау үшін <ph name="URL" /> қоÑымша қадамдар орындауы қажет.</translation>
<translation id="3293642807462928945"><ph name="POLICY_NAME" /> ÑаÑÑаты туралы қоÑымша ақпарат</translation>
<translation id="3295444047715739395">Chrome параметрлерінде Ò›Ò±Ð¿Ð¸Ñ Ñөздерді көріңіз және баÑқарыңыз.</translation>
+<translation id="3303795387212510132">Қолданбаға <ph name="PROTOCOL_SCHEME" /> Ñілтемелерін ашуға Ñ€Ò±Ò›Ñат берілÑін бе?</translation>
<translation id="3303855915957856445">Іздеу нәтижелері табылмады</translation>
<translation id="3304073249511302126">Bluetooth құрылғыларын іздеу</translation>
<translation id="3308006649705061278">Ұйымдық бірлік (OU)</translation>
@@ -728,12 +765,6 @@
<translation id="3345782426586609320">Көз</translation>
<translation id="3355823806454867987">ПрокÑи параметрлерін өзгерту…</translation>
<translation id="3360103848165129075">Төлем өңдегіш парағы</translation>
-<translation id="3361596688432910856">Chrome-да <ph name="BEGIN_EMPHASIS" />Ñақталмайтын<ph name="END_EMPHASIS" /> ақпараттар:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Шолу тарихыңыз
- <ph name="LIST_ITEM" />"Cookie" файлдары мен Ñайт деректері
- <ph name="LIST_ITEM" />Пішіндерге енгізілген ақпарат
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">Бұл ÑаÑÑат еÑкі <ph name="OLD_POLICY" /> ÑаÑÑатынан автоматты түрде көшірілді. Орнына оÑÑ‹ ÑаÑÑатты пайдаланғаныңыз жөн.</translation>
<translation id="3364869320075768271">Сайт (<ph name="URL" />) виртуалды шындық құрылғыÑын және деректерді пайдалануға Ñ€Ò±Ò›Ñат Ñұрайды.</translation>
<translation id="3366477098757335611">Карталарды көру</translation>
@@ -816,7 +847,6 @@
<translation id="3587738293690942763">ОртаÑÑ‹</translation>
<translation id="3592413004129370115">Italian (Envelope)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{Топ параметрлерін кез келген уақытта баÑтапқы күйге қайтара алаÑыз. Жаңа топқа қоÑылу шамамен бір күн алады.}=1{Топ параметрлерін кез келген уақытта баÑтапқы күйге қайтара алаÑыз. Жаңа топқа қоÑылу шамамен бір күн алады.}other{Топ параметрлерін кез келген уақытта баÑтапқы күйге қайтара алаÑыз. Жаңа топқа қоÑылу шамамен {NUM_DAYS} күн алады.}}</translation>
-<translation id="3596012367874587041">Қолданба параметрлері</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">Қолданбаны әкімші бөгеген</translation>
<translation id="3608932978122581043">Беру бағыты</translation>
@@ -859,6 +889,7 @@
<translation id="370972442370243704">Journeys функциÑÑын қоÑу</translation>
<translation id="3711895659073496551">Уақытша тоқтату</translation>
<translation id="3712624925041724820">ЛицензиÑлар аÑқталды</translation>
+<translation id="3714633008798122362">веб-күнтізбе</translation>
<translation id="3714780639079136834">Мобильдік деректерді немеÑе Wi-Fi желіÑін қоÑу</translation>
<translation id="3715597595485130451">Wi-Fi желіÑіне қоÑылу</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />ПрокÑиді, брандмауÑрді және DNS конфигурациÑÑын текÑеру<ph name="END_LINK" /></translation>
@@ -920,6 +951,7 @@
<translation id="3906954721959377182">Планшет</translation>
<translation id="3909477809443608991"><ph name="URL" /> қорғалған мазмұнды ойнатқыÑÑ‹ келеді. Google құрылғыңыздың идентификаторын раÑтағаннан кейін барып, Ñайт мазмұнды пайдалана алады.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">Тыйым Ñалу</translation>
<translation id="3939773374150895049">CVC орнына WebAuthn қолданаÑыз ба?</translation>
<translation id="3946209740501886391">ОÑÑ‹ Ñайтта әрқашан ÑұралÑын</translation>
<translation id="3947595700203588284">MIDI құрылғыларына қоÑылуға Ñ€Ò±Ò›Ñат Ñұрайды</translation>
@@ -941,6 +973,7 @@
<translation id="3990250421422698716">Бірқалыпты Ñ‹Ò“Ñ‹Ñу</translation>
<translation id="3996311196211510766"><ph name="ORIGIN" /> Ñайты өзінің барлық Ñұрауына түпнұÑқа ÑаÑÑатын
қолдануын талап етті, бірақ бұл ÑаÑÑатты дәл қазір қолдану мүмкін емеÑ.</translation>
+<translation id="4009243425692662128">Сіз баÑып шығаратын беттердің мазмұны талдау үшін Google Cloud қызметіне немеÑе үшінші тараптарға жіберіледі. МыÑалы, онда Ò›Ò±Ð¿Ð¸Ñ Ð´ÐµÑ€ÐµÐºÑ‚ÐµÑ€Ð´Ñ–Ò£ бар-жоғы текÑерілуі мүмкін.</translation>
<translation id="4010758435855888356">Жадты пайдалануға Ñ€Ò±Ò›Ñат берілÑін бе?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{{COUNT} беттік PDF құжаты}other{{COUNT} беттік PDF құжаты}}</translation>
<translation id="4023431997072828269">Бұл үлгі қорғалмаған Ð±Ð°Ð¹Ð»Ð°Ð½Ñ‹Ñ Ð°Ñ€Ò›Ñ‹Ð»Ñ‹ жіберілгендіктен, ақпаратыңыз баÑқаларға көрінетін болады.</translation>
@@ -1035,6 +1068,7 @@
<translation id="4250680216510889253">Жоқ</translation>
<translation id="4253168017788158739">ЕÑкертпе</translation>
<translation id="425582637250725228">Енгізілген өзгертулер Ñақталмауы мүмкін.</translation>
+<translation id="425869179292622354">ҚауіпÑіздік виртуалды картамен күшейтілÑін бе?</translation>
<translation id="4258748452823770588">Қолтаңба жарамÑыз</translation>
<translation id="4261046003697461417">Қорғалған құжаттарға Ð°Ð½Ð½Ð¾Ñ‚Ð°Ñ†Ð¸Ñ Ò›Ð¾Ñу мүмкін емеÑ.</translation>
<translation id="4265872034478892965">Әкімші Ñ€Ò±Ò›Ñат берген</translation>
@@ -1097,6 +1131,7 @@
<translation id="4434045419905280838">Қалқымалы терезе және бағыттау</translation>
<translation id="4435702339979719576">Postcard)</translation>
<translation id="443673843213245140">ПрокÑиді пайдалану өшірілген, бірақ айқын прокÑи конфигурациÑÑÑ‹ көрÑетілген.</translation>
+<translation id="4441832193888514600">Еленбеді, Ñебебі ÑаÑÑат бұлт пайдаланушыÑÑ‹ ÑаÑÑаты ретінде ғана орнатылады.</translation>
<translation id="4450893287417543264">Қайта көрÑетілмеÑін</translation>
<translation id="4451135742916150903">HID құрылғыларына қоÑылуға Ñ€Ò±Ò›Ñат Ñұрайды</translation>
<translation id="4452328064229197696">Сіз жаңа ғана қолданған Ò›Ò±Ð¿Ð¸Ñ Ñөз деректердің қолды болуы Ñалдарынан Ð¶Ð°Ñ€Ð¸Ñ ÐµÑ‚Ñ–Ð»Ð´Ñ–. Ðккаунттарыңызды қорғау үшін Google ÒšÒ±Ð¿Ð¸Ñ Ñөздер реттегіші Ñақталған Ò›Ò±Ð¿Ð¸Ñ Ñөздеріңізді текÑеруді Ò±Ñынады.</translation>
@@ -1152,6 +1187,7 @@
<translation id="4628948037717959914">ФотоÑурет</translation>
<translation id="4631649115723685955">БайланыÑтырылған кешбÑк</translation>
<translation id="4636930964841734540">Ðқпарат</translation>
+<translation id="4638670630777875591">Chromium браузеріндегі инкогнито режимі</translation>
<translation id="464342062220857295">Іздеу функциÑлары</translation>
<translation id="4644670975240021822">Кері ретпен артқы жағында</translation>
<translation id="4646534391647090355">Қазір өту</translation>
@@ -1172,6 +1208,7 @@
<translation id="4708268264240856090">Ð‘Ð°Ð¹Ð»Ð°Ð½Ñ‹Ñ Ò¯Ð·Ñ–Ð»Ð´Ñ–</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Windows Network Diagnostics құралын қоÑу<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426"><ph name="USERNAME" /> Ò›Ò±Ð¿Ð¸Ñ Ñөзі</translation>
<translation id="4724144314178270921">Буфердегі мәтін мен кеÑкіндерді көруге Ñ€Ò±Ò›Ñат Ñұрай алады</translation>
<translation id="4726672564094551039">СаÑÑаттарды қайта жүктеу</translation>
<translation id="4728558894243024398">Платформа</translation>
@@ -1193,6 +1230,7 @@
<translation id="4757993714154412917">Жаңа ғана Ò›Ò±Ð¿Ð¸Ñ Ñөзіңізді жалған Ñайтқа енгіздіңіз. Ðккаунттарыңызды қорғау үшін Chromium Ñақталған Ò›Ò±Ð¿Ð¸Ñ Ñөздеріңізді текÑеруді Ò±Ñынады.</translation>
<translation id="4758311279753947758">Контакт ақпаратын қоÑу</translation>
<translation id="4761104368405085019">Микрофоныңызды пайдалану</translation>
+<translation id="4761869838909035636">Chrome қауіпÑіздік шараÑын Ñ–Ñке қоÑу</translation>
<translation id="4764776831041365478"><ph name="URL" /> мекенжайындағы веб-бет уақытша Ñ–Ñтен шыққан немеÑе тұрақты түрде баÑқа мекенжайға көшкен болуы мүмкін.</translation>
<translation id="4766713847338118463">Төменгі жағын екі рет қапÑыру</translation>
<translation id="4771973620359291008">БелгіÑіз қате орын алды.</translation>
@@ -1213,12 +1251,6 @@
<translation id="4819347708020428563">ÐннотациÑларды әдепкі көрініÑте өзгерту керек пе?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />, жаңа Google парағын жылдам жаÑау үшін Tab, Ñодан кейін Enter пернеÑін баÑыңыз.</translation>
<translation id="4825507807291741242">Қуатты</translation>
-<translation id="4827402517081186284">Инкогнито режимі интернеттегі Ñ–Ñ-әрекетіңізді жаÑырмайды:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Сайттар қашан кіргеніңізді біледі.<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Ð–Ò±Ð¼Ñ‹Ñ Ð±ÐµÑ€ÑƒÑˆÑ–Ð»ÐµÑ€ немеÑе мектептер браузерді қолдану мәліметін қарай алады.<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Интернет провайдерлері трафикті бақылай алады.<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">Хабарландыруларды қоÑу</translation>
<translation id="4838327282952368871">Ðрманшыл</translation>
<translation id="4840250757394056958">Chrome тарихын көру</translation>
@@ -1230,12 +1262,12 @@
<translation id="4854362297993841467">Бұл жеткізу әдіÑÑ– қолжетімді емеÑ. БаÑқа әдіÑÑ‚Ñ– қолданып көріңіз.</translation>
<translation id="4854853140771946034">Google Keep-те жылдам жаңа еÑкертпе жаÑау</translation>
<translation id="485902285759009870">Код текÑерілуде…</translation>
+<translation id="4866506163384898554">КурÑорды көрÑету үшін |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| пернелерін баÑыңыз.</translation>
<translation id="4876188919622883022">Қарапайым көрініÑ</translation>
<translation id="4876305945144899064">Пайдаланушы аты жоқ</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{Жоқ}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831"><ph name="TEXT" /> іздеу</translation>
<translation id="4879491255372875719">Ðвтоматты (әдепкі)</translation>
-<translation id="4879725228911483934">Терезелерді ашу және Ñкрандарда орналаÑтыру</translation>
<translation id="4880827082731008257">Тарихтан іздеу</translation>
<translation id="4881695831933465202">Ðшу</translation>
<translation id="4885256590493466218">ТапÑырыÑÑ‚Ñ‹ Ñ€Ó™Ñімдегенде, <ph name="CARD_DETAIL" /> картаÑымен төлеңіз.</translation>
@@ -1244,6 +1276,7 @@
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">Тоғызыншы орам</translation>
<translation id="4901778704868714008">Сақтау...</translation>
+<translation id="4905659621780993806">Әкімші құрылғыңызды автоматты түрде қайта қоÑатын уақыт: <ph name="DATE" /> <ph name="TIME" />. Құрылғыны қайта қоÑÐ¿Ð°Ñ Ð±Ò±Ñ€Ñ‹Ð½, барлық ашық Ñлементті Ñақтаңыз.</translation>
<translation id="4913987521957242411">Жоғарғы Ñол жақты теÑу</translation>
<translation id="4918221908152712722"><ph name="APP_NAME" /> қолданбаÑын орнатыңыз (жүктеп алудың қажеті жоқ).</translation>
<translation id="4923459931733593730">Төлем</translation>
@@ -1252,6 +1285,7 @@
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />. Іздеу үшін алдымен Tab, одан кейін Enter пернеÑін баÑыңыз.</translation>
<translation id="4930153903256238152">Үлкен Ñыйымдылық</translation>
+<translation id="4940163644868678279">Chrome браузеріндегі инкогнито режимі</translation>
<translation id="4943872375798546930">ÐәтижеÑіз</translation>
<translation id="4950898438188848926">Қойынды ауыÑтыру түймеÑÑ–: ашық қойындыға ауыÑу үшін Enter пернеÑін баÑыңыз, <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="495170559598752135">Әрекеттер</translation>
@@ -1261,6 +1295,7 @@
<translation id="4968522289500246572">Бұл қолданба мобильдік құрылғыға арналған. Өлшемін өзгерту кезінде қолданба Ð´Ò±Ñ€Ñ‹Ñ Ð¶Ò±Ð¼Ñ‹Ñ Ñ–Ñтемеуі немеÑе өшіп қоÑылуы мүмкін.</translation>
<translation id="4969341057194253438">Жазбаны жою</translation>
<translation id="4973922308112707173">Жоғарғы жағын екі рет теÑу</translation>
+<translation id="4976702386844183910">Cоңғы кіру: <ph name="DATE" /></translation>
<translation id="4984088539114770594">Микрофон пайдаланылÑын ба?</translation>
<translation id="4984339528288761049">Prc5 (Envelope)</translation>
<translation id="4989163558385430922">Барлығын көру</translation>
@@ -1322,6 +1357,7 @@
<translation id="5138227688689900538">Жию</translation>
<translation id="5145883236150621069">Қате коды ÑаÑÑат жауабында көрÑетіледі</translation>
<translation id="5146995429444047494"><ph name="ORIGIN" /> Ñайты үшін хабарландырулар бөгелді</translation>
+<translation id="514704532284964975"><ph name="URL" /> Ñайты телефоныңызбен түрткен NFC құрылғылары туралы ақпаратты көргіÑÑ– және өзгерткіÑÑ– келеді.</translation>
<translation id="5148809049217731050">Жоғары қарату</translation>
<translation id="515292512908731282">C4 (Envelope)</translation>
<translation id="5158275234811857234">Мұқаба</translation>
@@ -1346,6 +1382,7 @@
<translation id="5215116848420601511">Google Pay қызметін пайдаланатын төлеу әдіÑтері және мекенжайлар</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">13-науа</translation>
+<translation id="5216942107514965959">Соңғы кіру: бүгін</translation>
<translation id="5222812217790122047">Электрондық пошта мекенжайы көрÑетілуі қажет</translation>
<translation id="5230733896359313003">Жеткізу мекенжайы</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1366,7 +1403,6 @@
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">Құжаттың Ñипаттары</translation>
<translation id="528468243742722775">Соңы</translation>
-<translation id="5284909709419567258">Желі мекенжайлары</translation>
<translation id="5285570108065881030">Барлық Ñақталған Ò›Ò±Ð¿Ð¸Ñ Ñөздерді көрÑету</translation>
<translation id="5287240709317226393">Cookie файлдарын көрÑету</translation>
<translation id="5287456746628258573">Бұл Ñайттың қауіпÑіздік конфигурациÑÑÑ‹ еÑкірген. Сайтқа мәліметтер (мыÑалы, Ò›Ò±Ð¿Ð¸Ñ Ñөздер немеÑе неÑиелік карта нөмірлері) жіберілгенде, шабуылдаушылар оларды пайдалануы мүмкін.</translation>
@@ -1450,6 +1486,7 @@
<translation id="5556459405103347317">Қайта жүктеу</translation>
<translation id="5560088892362098740">Мерзімі бітетін күні</translation>
<translation id="55635442646131152">Тақырыптар тізімдемеÑÑ–</translation>
+<translation id="5565613213060953222">Инкогнито қойындыÑын ашу</translation>
<translation id="5565735124758917034">БелÑенді</translation>
<translation id="5570825185877910964">Ðккаунтты қорғау</translation>
<translation id="5571083550517324815">Бұл мекенжайдан таңдалмайды. БаÑқа мекенжайды таңдаңыз.</translation>
@@ -1532,6 +1569,7 @@
<translation id="5869522115854928033">Сақталған Ò›Ò±Ð¿Ð¸Ñ Ñөздер</translation>
<translation id="5873013647450402046">Банк жеке баÑыңызды раÑтауды Ñұрайды.</translation>
<translation id="5887400589839399685">Карта Ñақталды</translation>
+<translation id="5887687176710214216">Соңғы кіру: кеше</translation>
<translation id="5895138241574237353">Қайта Ñ–Ñке қоÑу</translation>
<translation id="5895187275912066135">Шығарылған күні</translation>
<translation id="5901630391730855834">Сары</translation>
@@ -1545,6 +1583,7 @@
<translation id="5921639886840618607">Картаны Google аккаунтына Ñақтау қажет пе?</translation>
<translation id="5922853866070715753">ÐÑқтап қалдыңыз</translation>
<translation id="5932224571077948991">Сайтта мазалайтын не жалған ақпаратты жарнамалар көрÑетіледі</translation>
+<translation id="5938153366081463283">Виртуалды карта қоÑыңыз.</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347"><ph name="SITE_NAME" /> ашылуда…</translation>
<translation id="5951495562196540101">Тұтынушының аккаунтымен тіркеу мүмкін ÐµÐ¼ÐµÑ (Ð»Ð¸Ñ†ÐµÐ½Ð·Ð¸Ñ Ð¿Ð°ÐºÐµÑ‚Ñ– бар).</translation>
@@ -1609,6 +1648,7 @@
<translation id="6120179357481664955">UPI идентификаторы ÑақталÑын ба?</translation>
<translation id="6124432979022149706">Chrome Enterprise Connectors</translation>
<translation id="6127379762771434464">Элемент жойылған</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Chrome браузеріндегі инкогнито режимі туралы толығырақ<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">Барлық кабельдерді текÑеріп, пайдаланып отырған кез
келген роутерлерді, модемдерді немеÑе баÑқа желі құрылғыларын қайта жүктеңіз.</translation>
<translation id="614940544461990577">Орындап көріңіз:</translation>
@@ -1621,7 +1661,6 @@
<translation id="6169916984152623906">Қазір инкогнито режимінде қарап шығуыңызға болады, ал оÑÑ‹ құрылғыны пайдаланатын баÑқа адамдар әрекетіңізді көрмейді. Бірақ жүктеп алынған материалдар мен бетбелгілер Ñақталады.</translation>
<translation id="6177128806592000436">Бұл Ñайтпен байланыÑыңыз қауіпÑіз емеÑ</translation>
<translation id="6180316780098470077">Қайталау аралығы</translation>
-<translation id="619448280891863779">Терезелерді ашуды және Ñкрандарға орналаÑтыруды Ñұрай алады</translation>
<translation id="6196640612572343990">Үшінші тарап cookie файлдарын бөгеу</translation>
<translation id="6203231073485539293">Интернет байланыÑын текÑеріңіз</translation>
<translation id="6218753634732582820">Мекенжайды Chromium жүйеÑінен алып таÑтау керек пе?</translation>
@@ -1644,7 +1683,7 @@
<translation id="6272383483618007430">Google Update</translation>
<translation id="6276112860590028508">Оқу тізіміндегі беттер оÑÑ‹ жерге шығады</translation>
<translation id="627746635834430766">КелеÑіде жылдамырақ төлеу үшін картаны және төлем мекенжайын Google аккаунтына Ñақтаңыз.</translation>
-<translation id="6279098320682980337">Виртуалды карта нөмірі толтырылмаған ба? Көшірілетін карта мәліметтерін баÑыңыз.</translation>
+<translation id="6279183038361895380">КурÑорды көрÑету үшін |<ph name="ACCELERATOR" />| баÑыңыз</translation>
<translation id="6280223929691119688">Бұл мекенжайға жеткізілмейді. БаÑқа мекенжайды таңдаңыз.</translation>
<translation id="6282194474023008486">Пошта индекÑÑ–</translation>
<translation id="6285507000506177184">"Chrome браузерінде жүктеп алынған файлдарды баÑқару" түймеÑÑ–. Chrome браузерінде жүктеп алған файлдарыңызды баÑқару үшін Enter пернеÑін баÑыңыз.</translation>
@@ -1652,6 +1691,7 @@
<translation id="6290238015253830360">Сізге Ò±Ñынылған мақалалар оÑÑ‹ жерге шығады.</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{Құрылғыңыз қазір қайта қоÑылады}=1{Құрылғыңыз 1 Ñекундтан кейін қайта қоÑылады}other{Құрылғыңыз # Ñекундтан кейін қайта қоÑылады}}</translation>
<translation id="6302269476990306341">Chrome браузеріндегі Google Assistant тоқтатылуда</translation>
<translation id="6305205051461490394"><ph name="URL" /> мекенжайына кіру мүмкін емеÑ.</translation>
<translation id="6312113039770857350">Веб-бет қол жетімді емеÑ</translation>
@@ -1725,6 +1765,7 @@
<translation id="6529602333819889595">Жоюды &amp;қайталау</translation>
<translation id="6545864417968258051">Bluetooth құрылғыларын іздеу</translation>
<translation id="6547208576736763147">Сол жағын екі рет теÑу</translation>
+<translation id="6554732001434021288">Соңғы кіру: <ph name="NUM_DAYS" /> күн бұрын</translation>
<translation id="6556866813142980365">Қайта орындау</translation>
<translation id="6569060085658103619">Кеңейтім бетін көрудеÑіз</translation>
<translation id="6573200754375280815">Оң жағын екі рет теÑу</translation>
@@ -1785,7 +1826,6 @@
<translation id="6757797048963528358">Құрылғы ұйқы күйіне өтті.</translation>
<translation id="6767985426384634228">Мекенжайды жаңарту керек пе?</translation>
<translation id="6768213884286397650">Hagaki (Postcard)</translation>
-<translation id="6774185088257932239">Инкогнито туралы <ph name="BEGIN_LINK" />толығырақ<ph name="END_LINK" /></translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">Ðқшыл күлгін</translation>
<translation id="6786747875388722282">Кеңейтімдер</translation>
@@ -1869,7 +1909,6 @@
<translation id="706295145388601875">Chrome параметрлері арқылы мекенжайларды қоÑу және баÑқару</translation>
<translation id="7064851114919012435">Ð‘Ð°Ð¹Ð»Ð°Ð½Ñ‹Ñ Ð°Ò›Ð¿Ð°Ñ€Ð°Ñ‚Ñ‹</translation>
<translation id="7068733155164172741"><ph name="OTP_LENGTH" /> цифрлық кодты енгізіңіз</translation>
-<translation id="7070090581017165256">ОÑÑ‹ Ñайт туралы</translation>
<translation id="70705239631109039">БайланыÑыңыз толықтай қауіпÑіз емеÑ</translation>
<translation id="7075452647191940183">Сұрау өлшемі өте үлкен.</translation>
<translation id="7079718277001814089">Бұл Ñайтта зиÑнды бағдарлама бар</translation>
@@ -1886,6 +1925,12 @@
<translation id="7111012039238467737">(жарамды)</translation>
<translation id="7118618213916969306">Буфердегі URL ÑілтемеÑін (<ph name="SHORT_URL" />) іздеу</translation>
<translation id="7119414471315195487">БаÑқа қойындыларды не бағдарламаларды жабу</translation>
+<translation id="7129355289156517987">Chromium браузерінің барлық инкогнито қойындыларын жапқан кезде, Ñол қойындылардағы әрекеттеріңіз құрылғыдан өшіріледі:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />браузерді қолдану мәліметі;<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />іздеу тарихы;<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />үлгілерге енгізілген ақпарат.<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">Бұл мекенжайға жөнелтілмейді. БаÑқа мекенжайды таңдаңыз.</translation>
<translation id="7132939140423847331">Әкімші бұл деректің көшірілуіне тыйым Ñалды.</translation>
<translation id="7135130955892390533">Күйін көрÑету</translation>
@@ -1908,6 +1953,7 @@
<translation id="7192203810768312527"><ph name="SIZE" /> дейін боÑатады. Кейбір Ñайттар келеÑÑ– рет кірген кезіңізде баÑу жүктелуі мүмкін.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">Әкімші келеÑілерді көреді:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />. Жаңа инкогнито қойындыÑын ашу үшін Tab, одан кейін Enter пернеÑін баÑыңыз.</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> қауіпÑіздік Ñтандарттарына Ñай емеÑ.</translation>
<translation id="7210993021468939304">Linux-Ñ‚Ñ–Ò£ контейнердегі әрекетін көреді, Ñондай-ақ контейнерден Linux қолданбаларын орната және Ñ–Ñке қоÑа алады.</translation>
@@ -1939,6 +1985,7 @@
<translation id="7304562222803846232">Google аккаунтының құпиÑлылық параметрлерін баÑқару</translation>
<translation id="7305756307268530424">БаÑуырақ жылдамдықпен баÑтау</translation>
<translation id="7308436126008021607">фондық Ñинхрондау</translation>
+<translation id="7310392214323165548">Құрылғы Ñәлден Ñоң өшіп, қайта қоÑылады.</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">Ð‘Ð°Ð¹Ð»Ð°Ð½Ñ‹Ñ Ð°Ð½Ñ‹Ò›Ñ‚Ð°Ð¼Ð°ÑÑ‹</translation>
<translation id="7323804146520582233">"<ph name="SECTION" />" бөлімін жаÑыру</translation>
@@ -1946,6 +1993,7 @@
<translation id="7334320624316649418">&amp;Қайта ретке келтіруді қайталау</translation>
<translation id="7335157162773372339">Камераңызды қолдануға Ñ€Ò±Ò›Ñат Ñұрай алады</translation>
<translation id="7337248890521463931">Жолдарды көбірек көрÑету</translation>
+<translation id="7337418456231055214">Виртуалды карта нөмірі толтырылмаған ба? Көшірілетін карта мәліметтерін баÑыңыз. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">Сіздің платформаңызда қолжетімді емеÑ.</translation>
<translation id="733923710415886693">Сервер Ñертификаты Сертификат айқындығы ÑаÑÑатымен ашылмады.</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1968,6 +2016,7 @@
<translation id="7378627244592794276">Жоқ</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">ҚатыÑÑ‚Ñ‹ емеÑ</translation>
+<translation id="7388594495505979117">{0,plural, =1{Құрылғыңыз 1 минуттан кейін қайта қоÑылады}other{Құрылғыңыз # минуттан кейін қайта қоÑылады}}</translation>
<translation id="7390545607259442187">Картаны раÑтау</translation>
<translation id="7392089738299859607">Мекенжайды жаңарту</translation>
<translation id="7399802613464275309">ҚауіпÑіздік шараÑÑ‹</translation>
@@ -2004,6 +2053,12 @@
<translation id="7485870689360869515">Деректер табылмады.</translation>
<translation id="7495528107193238112">Бұл мазмұн бөгелген. МәÑелені шешу үшін Ñайт иеÑімен Ð±Ð°Ð¹Ð»Ð°Ð½Ñ‹Ñ Ð¾Ñ€Ð½Ð°Ñ‚Ñ‹Ò£Ñ‹Ð·.</translation>
<translation id="7497998058912824456">"Құжат жаÑау" түймеÑÑ–, жаңа Google құжатын жылдам жаÑау үшін Enter пернеÑін баÑыңыз.</translation>
+<translation id="7506488012654002225">Chromium келеÑÑ– ақпаратты <ph name="BEGIN_EMPHASIS" />Ñақтамайды<ph name="END_EMPHASIS" />:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />браузерді қолдану тарихы;
+ <ph name="LIST_ITEM" />cookie файлдары және Ñайт деректері;
+ <ph name="LIST_ITEM" />үлгілерге енгізілген ақпарат.
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">Қайтарылған құрылғының Ñервердегі идентификаторы Ð±Ð¾Ñ Ð½ÐµÐ¼ÐµÑе оның ағымдағы идентификаторына ÑÓ™Ð¹ÐºÐµÑ ÐºÐµÐ»Ð¼ÐµÐ¹Ð´Ñ–</translation>
<translation id="7508870219247277067">Қою жаÑыл</translation>
<translation id="7511955381719512146">Пайдаланып жатқан Wi-Fi Ñізден <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> ÑілтемеÑіне кіруді Ñұрауы мүмкін.</translation>
@@ -2117,7 +2172,6 @@
<translation id="7813600968533626083">Chrome браузерінен форма Ò±ÑыныÑын өшіру қажет пе?</translation>
<translation id="781440967107097262">Буфер бөліÑілÑін бе?</translation>
<translation id="7815407501681723534">"<ph name="SEARCH_STRING" />" үшін <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> табылды</translation>
-<translation id="782125616001965242">ОÑÑ‹ Ñайт туралы ақпарат көрÑетіледі.</translation>
<translation id="782886543891417279">Сіз пайдаланып жатқан Wi-Fi (<ph name="WIFI_NAME" />) желіÑÑ– оның кіру бетіне кіруіңізді талап етеді.</translation>
<translation id="7836231406687464395">Postfix (Envelope)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{Жоқ}=1{1 қолданба (<ph name="EXAMPLE_APP_1" />)}=2{2 қолданба (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}other{# қолданба (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}}</translation>
@@ -2134,7 +2188,6 @@
<translation id="7888575728750733395">БаÑып шығарудың рендеринг мақÑаты</translation>
<translation id="7894280532028510793">Ð”Ò±Ñ€Ñ‹Ñ Ð¶Ð°Ð·Ñ‹Ð»Ò“Ð°Ð½ болÑа, <ph name="BEGIN_LINK" />Network Diagnostics құралын Ñ–Ñке қоÑып көріңіз<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (Envelope)</translation>
-<translation id="7931318309563332511">БелгіÑіз</translation>
<translation id="793209273132572360">Мекенжайды жаңарту керек пе?</translation>
<translation id="7932579305932748336">Қаптау</translation>
<translation id="79338296614623784">Ð”Ò±Ñ€Ñ‹Ñ Ñ‚ÐµÐ»ÐµÑ„Ð¾Ð½ нөмірін енгізіңіз</translation>
@@ -2159,13 +2212,14 @@
<translation id="7976214039405368314">Сұраулар Ñаны өте көп.</translation>
<translation id="7977538094055660992">Шығару құрылғыÑÑ‹</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">КелеÑімен байланыÑтырылды:</translation>
<translation id="798134797138789862">Виртуалды шындық құрылғыларын және деректерді пайдалануға Ñ€Ò±Ò›Ñат Ñұрай алады.</translation>
<translation id="7984945080620862648">Қазір <ph name="SITE" /> Ñайтына кіру мүмкін емеÑ, Ñебебі веб-Ñайт Chrome өңдей алмайтын шифрланған еÑептік деректерді жіберді. Желі қателері мен шабуылдары әдетте уақытша болғандықтан, бұл бет кейінірек Ð¶Ò±Ð¼Ñ‹Ñ Ñ–Ñтеуі мүмкін.</translation>
-<translation id="79859296434321399">Толықтырылған шындық мазмұнын көру үшін ARCore платформаÑын орнатыңыз</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">Байлау</translation>
<translation id="7992044431894087211"><ph name="APPLICATION_TITLE" /> веб-Ñайтына Ñкранды көрÑету жалғаÑтырылды.</translation>
<translation id="7995512525968007366">КөрÑетілмеген</translation>
+<translation id="7998269595945679889">"Инкогнито қойындыÑын ашу" түймеÑÑ–. Жаңа инкогнито қойындыÑын ашу үшін Enter пернеÑін баÑыңыз.</translation>
<translation id="800218591365569300">Жадты боÑату үшін баÑқа қойындылары не бағдарламаларды жауып көріңіз</translation>
<translation id="8004582292198964060">Браузер</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{ОÑÑ‹ карта мен оның төлем мекенжайы Ñақталады. Оны <ph name="USER_EMAIL" /> аккаунтына кірген кезде пайдалана алаÑыз.}other{ОÑÑ‹ карталар мен олардың төлем мекенжайлары Ñақталады. Оларды <ph name="USER_EMAIL" /> аккаунтына кірген кезде пайдалана алаÑыз.}}</translation>
@@ -2225,6 +2279,7 @@
<translation id="8202370299023114387">Қайшылық</translation>
<translation id="8206978196348664717">Prc4 (Envelope)</translation>
<translation id="8211406090763984747">ҚауіпÑіз байланыÑ</translation>
+<translation id="8217240300496046857">Сайттар Ñізді интернетте қадағалайтын cookie файлдарын пайдалана алмайды. Кейбір Ñайттың функциÑлары Ð¶Ò±Ð¼Ñ‹Ñ Ñ–Ñтемеуі мүмкін.</translation>
<translation id="8218327578424803826">Тағайындалған орын:</translation>
<translation id="8220146938470311105">C7/C6 (Envelope)</translation>
<translation id="8225771182978767009">Бұл компьютерді орнатқан адам оÑÑ‹ Ñайтты бөгеуді ұйғарды.</translation>
@@ -2265,14 +2320,9 @@
<translation id="830498451218851433">Жартылай бүктеу</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">Орнатылған қолданбалар және олардың пайдаланылу жиілігі</translation>
+<translation id="8317207217658302555">ARCore жаңартылÑын ба?</translation>
<translation id="831997045666694187">Кеш</translation>
<translation id="8321476692217554900">хабарландырулар</translation>
-<translation id="8328484624016508118">Барлық инкогнито қойындыcÑ‹ жабылғанда, Chrome келеÑілерді жоÑды:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />оÑÑ‹ құрылғыдағы браузерді қолдану мәліметі;<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />оÑÑ‹ құрылғыдағы іздеу тарихы;<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />үлгілерге енгізілген ақпарат.<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489"><ph name="HOST_NAME" /> Ñайтына кіруге тыйым Ñалынған</translation>
<translation id="833262891116910667">Бөлектеу</translation>
<translation id="8339163506404995330"><ph name="LANGUAGE" /> тіліндегі беттер аударылмайды</translation>
@@ -2324,6 +2374,7 @@
<translation id="8507227106804027148">Пәрмен жолы</translation>
<translation id="8508648098325802031">Іздеу белгішеÑÑ–</translation>
<translation id="8511402995811232419">Cookie файлдарын баÑқару</translation>
+<translation id="8519753333133776369">Әкімші Ñ€Ò±Ò›Ñат берген HID құрылғыÑÑ‹</translation>
<translation id="8522552481199248698">Chrome браузері Google аккаунтыңызды қорғауға және Ò›Ò±Ð¿Ð¸Ñ Ñөзіңізді өзгертуге көмектеÑеді.</translation>
<translation id="8530813470445476232">Chrome параметрлерінен браузерді қолдану тарихын, cookie файлдарын, кÑшті және Ñ‚.б. деректерді өшіріңіз.</translation>
<translation id="8533619373899488139">Тыйым Ñалынған URL мекенжайларын және жүйе әкімшіÑÑ– енгізген баÑқа ÑаÑÑаттар тізімін қарау үшін &lt;strong&gt;chrome://policy&lt;/strong&gt; бетіне кіріңіз.</translation>
@@ -2335,7 +2386,6 @@
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{РұқÑатты баÑтапқы күйіне қайтару}other{РұқÑаттарды баÑтапқы күйіне қайтару}}</translation>
<translation id="8555010941760982128">Төлеу кезінде оÑÑ‹ коды пайдаланыңыз</translation>
<translation id="8557066899867184262">CVC коды картаңыздың артқы жағында орналаÑқан.</translation>
-<translation id="8558485628462305855">Толықтырылған шындық мазмұнын көру үшін ARCore платформаÑын жаңартыңыз</translation>
<translation id="8559762987265718583"><ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> доменімен жеке Ð±Ð°Ð¹Ð»Ð°Ð½Ñ‹Ñ Ð¾Ñ€Ð½Ð°Ñ‚Ñƒ мүмкін емеÑ, Ñебебі құрылғыңыздың күні мен уақыты (<ph name="DATE_AND_TIME" />) Ð´Ò±Ñ€Ñ‹Ñ ÐµÐ¼ÐµÑ.</translation>
<translation id="8564182942834072828">Бөлек құжаттар/реттелмеген көшірмелер</translation>
<translation id="8564985650692024650">Chromium баÑқа Ñайттарда пайдаланылған <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> Ò›Ò±Ð¿Ð¸Ñ Ñөзін қайта орнатуды Ò±Ñынады.</translation>
@@ -2354,6 +2404,7 @@
<translation id="865032292777205197">Ò›Ð¾Ð·Ò“Ð°Ð»Ñ‹Ñ Ð´Ð°Ñ‚Ñ‡Ð¸ÐºÑ‚ÐµÑ€Ñ–</translation>
<translation id="8663226718884576429">ТапÑÑ‹Ñ€Ñ‹Ñ Ò›Ð¾Ñ€Ñ‹Ñ‚Ñ‹Ð½Ð´Ñ‹ÑÑ‹, <ph name="TOTAL_LABEL" />, толығырақ деректер</translation>
<translation id="8666678546361132282">ағылшын</translation>
+<translation id="8669306706049782872">Терезелерді ашып, орналаÑтыру үшін Ñкрандар туралы ақпаратты пайдалану</translation>
<translation id="867224526087042813">Қолтаңба</translation>
<translation id="8676424191133491403">ÐšÑ–Ð´Ñ–Ñ€Ñ–Ñ Ð¶Ð¾Ò›</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, жауап, <ph name="ANSWER" /></translation>
@@ -2380,6 +2431,7 @@
<translation id="8731544501227493793">"ÒšÒ±Ð¿Ð¸Ñ Ñөздерді баÑқару" түймеÑÑ–. Chrome параметрлерінде Ò›Ò±Ð¿Ð¸Ñ Ñөздеріңізді көру және баÑқару үшін Enter пернеÑін баÑыңыз.</translation>
<translation id="8734529307927223492"><ph name="DEVICE_TYPE" /> құрылғыңызды <ph name="MANAGER" /> баÑқарады</translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />. Жаңа инкогнито терезеÑін ашу үшін Tab, одан кейін Enter пернеÑін баÑыңыз.</translation>
+<translation id="8737685506611670901"><ph name="REPLACED_HANDLER_TITLE" /> орнына <ph name="PROTOCOL" /> Ñілтемелерін ашу</translation>
<translation id="8738058698779197622">ҚауіпÑіз Ð±Ð°Ð¹Ð»Ð°Ð½Ñ‹Ñ Ð¾Ñ€Ð½Ð°Ñ‚Ñƒ үшін Ñағатыңыз Ð´Ò±Ñ€Ñ‹Ñ Ð¾Ñ€Ð½Ð°Ñ‚Ñ‹Ð»ÑƒÑ‹ қажет. Себебі веб-Ñайттар өзін анықтау үшін пайдаланатын Ñертификаттар көрÑетілген уақыт мерзімінде ғана жарамды. Құрылғыңыздың Ñағаты Ð´Ò±Ñ€Ñ‹Ñ ÐµÐ¼ÐµÑ Ð±Ð¾Ð»Ò“Ð°Ð½Ð´Ñ‹Ò›Ñ‚Ð°Ð½, Chromium бұл Ñертификаттарды раÑтай алмайды.</translation>
<translation id="8740359287975076522"><ph name="HOST_NAME" /> &lt;abbr id="dnsDefinition"&gt;DNS мекенжайы&lt;/abbr&gt; табылмады. МәÑеле анықталуда.</translation>
<translation id="8742371904523228557"><ph name="ONE_TIME_CODE" /> – <ph name="ORIGIN" /> Ñайтына арналған код</translation>
@@ -2407,6 +2459,7 @@
<translation id="883848425547221593">БаÑқа бетбелгілер</translation>
<translation id="884264119367021077">Жөнелту мекенжайы</translation>
<translation id="884923133447025588">Қайтарып алу механизмі табылмады.</translation>
+<translation id="8849262850971482943">ҚауіпÑіздікті арттыру үшін виртуалды картаны пайдаланыңыз.</translation>
<translation id="885730110891505394">Google-мен бөліÑу</translation>
<translation id="8858065207712248076">Chrome баÑқа Ñайттарда пайдаланылған <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> Ò›Ò±Ð¿Ð¸Ñ Ñөзін қайта орнатуды Ò±Ñынады.</translation>
<translation id="885906927438988819">Ð”Ò±Ñ€Ñ‹Ñ Ð¶Ð°Ð·Ñ‹Ð»Ò“Ð°Ð½ болÑа, <ph name="BEGIN_LINK" />Windows Network Diagnostics құралын Ñ–Ñке қоÑып көріңіз<ph name="END_LINK" />.</translation>
@@ -2456,6 +2509,7 @@
<translation id="9004367719664099443">VR ÑеанÑÑ‹ жүруде</translation>
<translation id="9005998258318286617">PDF құжаты жүктелмеді</translation>
<translation id="9008201768610948239">Елемеу</translation>
+<translation id="901834265349196618">Ñлектрондық пошта</translation>
<translation id="9020200922353704812">Картаның төлем мекенжайы қажет</translation>
<translation id="9020542370529661692">Бұл бет <ph name="TARGET_LANGUAGE" /> тіліне аударылды</translation>
<translation id="9020742383383852663">A8</translation>
@@ -2504,6 +2558,7 @@
<translation id="9150045010208374699">Камераңызды пайдалану</translation>
<translation id="9150685862434908345">Браузер реттеуді әкімші қашықтан өзгерте алады. Сонымен қатар құрылғыдағы әрекеттерді Chrome браузерінен Ñ‚Ñ‹Ñ Ð±Ð°Ñқаруға болады. <ph name="BEGIN_LINK" />Толығырақ<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">Жаңартылды</translation>
+<translation id="9155211586651734179">Жалғанған перифериÑлық аудиоқұрылғылар</translation>
<translation id="9157595877708044936">Орнатылуда…</translation>
<translation id="9158625974267017556">C6 (Envelope)</translation>
<translation id="9164029392738894042">Дәлдікті текÑеру</translation>
diff --git a/chromium/components/strings/components_strings_km.xtb b/chromium/components/strings/components_strings_km.xtb
index 7a0534eea37..e92b7d24789 100644
--- a/chromium/components/strings/components_strings_km.xtb
+++ b/chromium/components/strings/components_strings_km.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">មើលពáŸážáŸŒáž˜áž¶áž“លម្អិáž</translation>
<translation id="1030706264415084469"><ph name="URL" /> ចង់ផ្ទុក​ទិន្ននáŸáž™â€‹áž‘ំហំធំ​នៅលើ​ឧបករណáŸâ€‹ážšáž”ស់អ្នក​ជា​អចិន្ážáŸ’រៃយáŸ</translation>
<translation id="1032854598605920125">បង្វិលážáž¶áž˜áž‘្រនិចនាឡិកា</translation>
+<translation id="1033329911862281889">មុážáž„ារឯកជន​មិនមែនធ្វើឱ្យគáŸâ€‹áž˜áž¾áž›áž˜áž·áž“ឃើញអ្នក​នៅលើអ៊ីនធឺណិážáž‘áŸáŸ–
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />áž‚áŸáž áž‘ំពáŸážš និងសáŸážœáž¶áž€áž˜áŸ’មដែលពួកគáŸáž”្រើអាចមើលឃើញការចូលមើល<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />និយោជក ឬសាលារៀន​អាចážáž¶áž˜ážŠáž¶áž“​សកម្មភាព​រុករក​ážáž¶áž˜áž¢áŸŠáž¸áž“ធឺណិáž<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ក្រុមហ៊ុន​ផ្ដល់​សáŸážœáž¶áž€áž˜áŸ’ម​អ៊ីនធឺណិážâ€‹áž¢áž¶áž…áž–áž·áž“áž·ážáŸ’áž™ážáž¶áž˜ážŠáž¶áž“​ចរាចរណáŸáž”ណ្ដាញ<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">បិទ</translation>
<translation id="1036982837258183574">ចុច |<ph name="ACCELERATOR" />| ដើម្បីចáŸáž‰áž–ីមុážáž„ារអáŸáž€áŸ’រង់ពáŸáž‰</translation>
<translation id="1038106730571050514">បង្ហាញ​ការណែនាំ</translation>
<translation id="1038842779957582377">ឈ្មោះមិនស្គាល់</translation>
<translation id="1041998700806130099">សារអំពី​សន្លឹកកិច្ចការ</translation>
<translation id="1048785276086539861">នៅពáŸáž›â€‹áž¢áŸ’នក​កែចំណារ ឯកសារនáŸáŸ‡â€‹áž“ឹងážáŸ’រឡប់ទៅ​ការមើល​ទំពáŸážšâ€‹áž‘ោលវិញ</translation>
-<translation id="1049743911850919806">អនាមិក</translation>
<translation id="1050038467049342496">បិទ​កម្មវិធី​ផ្សáŸáž„ទៀáž</translation>
<translation id="1055184225775184556">បកក្រោយការបន្ážáŸ‚ម</translation>
<translation id="1056898198331236512">ការព្រមាន</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">ស្ážáž¶áž“ភាពឃ្លាំងសម្ងាážáŸ‹áž‚ោលការណáŸáž˜áž¶áž“ភាពប្រក្រážáž¸</translation>
<translation id="1130564665089811311">ប៊ូážáž»áž„ "បកប្រែទំពáŸážš" ចុច "Enter" ដើម្បីបកប្រែទំពáŸážšáž“áŸáŸ‡ážŠáŸ„យប្រើ Google បកប្រែ</translation>
<translation id="1131264053432022307">រូបភាព​ដែលអ្នកបានចម្លង</translation>
+<translation id="1142846828089312304">ទប់ស្កាážáŸ‹â€‹ážáž¼áž‚ីភាគីទីបីក្នុងមុážáž„ារឯកជន</translation>
<translation id="1150979032973867961">ម៉ាស៊ីនមáŸáž“áŸáŸ‡áž˜áž·áž“អាចបង្ហាញážáž¶ážœáž¶áž‡áž¶ <ph name="DOMAIN" /> ទ០វិញ្ញាបនបáŸážáŸ’រសុវážáŸ’ážáž·áž—ាពរបស់វា
មិនážáŸ’រូវបានជឿ៌ជាក់ដោយប្រពáŸáž“្ធប្រážáž·áž”ážáŸ’ážáž·áž€áž¶ážšáž€áž»áŸ†áž–្យូទáŸážšážšáž”ស់អ្នកទáŸáŸ” áž“áŸáŸ‡áž¢áž¶áž…បណ្ážáž¶áž›áž˜áž€áž–ីការកំណážáŸ‹áž˜áž·áž“ážáŸ’រឹមážáŸ’រូវ ឬមានការស្ទាក់ការភ្ជាប់របស់អ្នកពីអ្នកវាយប្រហារ។</translation>
<translation id="1151972924205500581">ážáž˜áŸ’រូវឲ្យមានពាក្យសម្ងាážáŸ‹</translation>
@@ -65,7 +71,6 @@
<translation id="1178581264944972037">ផ្អាក</translation>
<translation id="1181037720776840403">ដកចáŸáž‰</translation>
<translation id="1186201132766001848">áž–áž·áž“áž·ážáŸ’យពាក្យសម្ងាážáŸ‹</translation>
-<translation id="1195210374336998651">ចូលទៅកាន់​ការកំណážáŸ‹áž€áž˜áŸ’មវិធី</translation>
<translation id="1195558154361252544">ការជូនដំណឹង​ážáŸ’រូវបានទប់ស្កាážáŸ‹â€‹ážŠáŸ„យស្វáŸáž™áž”្រវážáŸ’ážáž·â€‹ážŸáž˜áŸ’រាប់គáŸáž áž‘ំពáŸážšâ€‹áž‘ាំងអស់ លើកលែងážáŸ‚​គáŸáž áž‘ំពáŸážšâ€‹ážŠáŸ‚លអ្នក​អនុញ្ញាážâ€‹áž”៉ុណ្ណោះ</translation>
<translation id="1197088940767939838">ទឹក​ក្រូច</translation>
<translation id="1201402288615127009">បន្ទាប់</translation>
@@ -112,7 +117,7 @@
<translation id="1307966114820526988">មុážáž„ារ​ដែលបាន​បញ្ឈប់</translation>
<translation id="1308113895091915999">មាន​ការផ្ដល់ជូន</translation>
<translation id="1312803275555673949">ážáž¾áž˜áž¶áž“​ភស្ážáž»ážáž¶áž„អ្វី​សម្រាប់គាំទ្រវា?</translation>
-<translation id="131405271941274527"><ph name="URL" /> ចង់ផ្ញើ និង​ទទួលពáŸážáŸŒáž˜áž¶áž“ នៅពáŸáž›â€‹áž¢áŸ’នកចុច​ទូរសព្ទ​របស់អ្នក នៅលើ​ឧបករណ០NFC</translation>
+<translation id="1314311879718644478">មើលážáŸ’លឹមសារ AR</translation>
<translation id="1314509827145471431">ភ្ជាប់​ážáž¶áž„ស្ដាំ</translation>
<translation id="1318023360584041678">បានរក្សាទុក​នៅក្នុង​ក្រុមផ្ទាំង</translation>
<translation id="1319245136674974084">កុំ​​សួរ​ទៀážâ€‹ážŸáž˜áŸ’រាប់​កម្មវិធី​នáŸáŸ‡</translation>
@@ -162,6 +167,7 @@
<translation id="142858679511221695">អ្នកប្រើប្រាស់ពពក</translation>
<translation id="1428729058023778569">អ្នកមើលឃើញ​ការព្រមាននáŸáŸ‡ ដោយសារ​គáŸáž áž‘ំពáŸážšáž“áŸáŸ‡â€‹áž˜áž·áž“ស្គាល់ HTTPS áž‘áŸáŸ” <ph name="BEGIN_LEARN_MORE_LINK" />ស្វែងយល់បន្ážáŸ‚ម<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">បោះពុម្ព</translation>
+<translation id="1432187715652018471">ទំពáŸážšáž…ង់​ដំឡើងឧបករណáŸâ€‹ážŠáŸ„ះស្រាយសáŸážœáž¶áž€áž˜áŸ’ម។</translation>
<translation id="1432581352905426595">គ្រប់គ្រងម៉ាស៊ីនស្វែងរក</translation>
<translation id="1436185428532214179">អាចស្នើសុំ​កែឯកសារ áž“áž·áž„ážážâ€‹áž“ៅក្នុងឧបករណáŸâ€‹ážšáž”ស់អ្នក</translation>
<translation id="1442386063175183758">áž”ážáŸ‹áž—្ជិážâ€‹áž•áŸ’ទាំង​ážáž¶áž„ស្ដាំ</translation>
@@ -182,6 +188,12 @@
<translation id="1483493594462132177">ផ្ញើ</translation>
<translation id="1484290072879560759">ជ្រើសរើសអាសយដ្ឋាន​ដឹក​ជញ្ជូន</translation>
<translation id="1492194039220927094">ការជំរុញ​គោលការណáŸáŸ–</translation>
+<translation id="149293076951187737">នៅពáŸáž›áž¢áŸ’នកបិទផ្ទាំងឯកជន Chrome ទាំងអស់ សកម្មភាពរបស់អ្នកនៅក្នុងផ្ទាំងទាំងនោះážáŸ’រូវបានសម្អាážáž…áŸáž‰áž–ីឧបករណáŸáž“áŸáŸ‡áŸ–
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />សកម្មភាព​រុករក​ážáž¶áž˜áž¢áŸŠáž¸áž“ធឺណិáž<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ប្រវážáŸ’ážáž·â€‹ážŸáŸ’វែងរក<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />áž–áŸážáŸŒáž˜áž¶áž“ដែលបានបញ្ចូលក្នុងទម្រង់បែបបទ<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">ážáŸ’រឡប់ទៅ​ផ្ទាំងវិញ</translation>
<translation id="1501859676467574491">បង្ហាញកាážáž–ីគណនី Google របស់អ្នក</translation>
<translation id="1507202001669085618">&lt;p&gt;អ្នកនឹង​មើលឃើញ​បញ្ហានáŸáŸ‡ ប្រសិនបើ​អ្នកកំពុង​ប្រើច្រក​ចូល​ Wi-Fi ដែលអ្នក​ážáŸ’រូវážáŸ‚ចុះឈ្មោះចូល មុនពáŸáž›â€‹ážŠáŸ‚លអ្នកអាច​ភ្ជាប់អ៊ីន​ធឺណិážáŸ”&lt;/p&gt;
@@ -209,6 +221,8 @@
<translation id="1559572115229829303">&lt;p&gt;ការážáž—្ជាប់ជាលក្ážážŽáŸˆáž¯áž€áž‡áž“ទៅ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> មិនអាចធ្វើឡើងបានទ០ពីព្រោះកាលបរិច្ឆáŸáž‘ និងម៉ោងឧបករណáŸážšáž”ស់អ្នក (<ph name="DATE_AND_TIME" />) មិនážáŸ’រឹមážáŸ’រូវ។&lt;/p&gt;
&lt;p&gt;សូមកែសម្រួលកាលបរិច្ឆáŸáž‘ និងម៉ោងចáŸáž‰áž–ីផ្នែក&lt;strong&gt;ទូទៅ&lt;/strong&gt;នៃកម្មវិធី&lt;strong&gt;ការកំណážáŸ‹&lt;/strong&gt;។&lt;/p&gt;</translation>
+<translation id="1559839503761818503">អ្នកគ្រប់គ្រងរបស់អ្នកនឹងចាប់ផ្ដើមឧបករណáŸážšáž”ស់អ្នកឡើងវិញនៅម៉ោង <ph name="TIME" /> នៅážáŸ’ងៃទី <ph name="DATE" /></translation>
+<translation id="156703335097561114">áž–áŸážáŸŒáž˜áž¶áž“បណ្ដាញដូចជា អាសយដ្ឋាន ការកំណážáŸ‹ážšáž…នាសម្ពáŸáž“្ធផ្ទៃ និងគុណភាព​នៃការážáž—្ជាប់ជាដើម</translation>
<translation id="1567040042588613346">គោលការណáŸáž“áŸáŸ‡â€‹áž€áŸ†áž–ុងដំណើរការ​ដូចការរំពឹងទុក ប៉ុន្ážáŸ‚​ážáž˜áŸ’លៃដូចគ្នា​ážáŸ’រូវបាន​កំណážáŸ‹áž“ៅ​កន្លែងផ្សáŸáž„ និង​ážáŸ’រូវបាន​ជំនួសដោយ​គោលការណáŸáž“áŸáŸ‡áŸ”</translation>
<translation id="1569487616857761740">បញ្ចូលកាល​បរិច្ឆáŸáž‘​ផុážâ€‹áž€áŸ†ážŽážáŸ‹</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -216,6 +230,7 @@
<translation id="1583429793053364125">មានបញ្ហាអ្វីមួយកើážáž¡áž¾áž„ ážážŽáŸˆáž–áŸáž›áž€áŸ†áž–ុងបង្ហាញគáŸáž áž‘ំពáŸážšáž“áŸáŸ‡</translation>
<translation id="1586541204584340881">ážáž¶ážáž¾áž€áž˜áŸ’មវិធីបន្ážáŸ‚មណាážáŸ’លះដែលអ្នកបានដំឡើង</translation>
<translation id="1588438908519853928">ធម្មážáž¶</translation>
+<translation id="1589050138437146318">ដំឡើង ARCore ឬ?</translation>
<translation id="1592005682883173041">ការចូលប្រើទិន្ននáŸáž™áž˜áž¼áž›ážŠáŸ’ឋាន</translation>
<translation id="1594030484168838125">ជ្រើសរើស</translation>
<translation id="160851722280695521">áž›áŸáž„ហ្គáŸáž˜ážŠáž¶áž™ážŽáž¼ážŸáŸážšážáŸ‹áž“ៅក្នុង Chrome</translation>
@@ -285,6 +300,7 @@
ផ្នែកក្បាលនោះមានទម្រង់មិនážáŸ’រឹមážáŸ’រូវ ដែលជាហáŸážáž»áž’្វើឱ្យកម្មវិធីរុករកážáž¶áž˜áž¢áŸŠáž¸áž“ធឺណិážáž˜áž·áž“អាចបំពáŸáž‰
ážáž¶áž˜ážŸáŸ†ážŽáž¾ážšáž”ស់អ្នកសម្រាប់ <ph name="SITE" />។ ប្រážáž·áž”ážáŸ’ážáž·áž€ážšâ€‹áž‚áŸáž áž‘ំពáŸážšâ€‹áž¢áž¶áž…ប្រើ
គោលការណáŸâ€‹ážŠáž¾áž˜ ដើម្បីកំណážáŸ‹â€‹ážšáž…នាសម្ពáŸáž“្ធ​សុវážáŸ’ážáž·áž—ាព និង​លក្ážážŽážŸáž˜áŸ’áž”ážáŸ’ážáž·â€‹áž•áŸ’សáŸáž„ទៀážâ€‹ážŸáž˜áŸ’រាប់​គáŸáž áž‘ំពáŸážšâ€‹áŸ”</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />ស្វែងយល់បន្ážáŸ‚មអំពីមុážáž„ារឯកជននៅក្នុង Chromium<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">ផ្ទាំង​ដែល​អ្នកបានបើកបង្ហាញ​នៅ​ទីនáŸáŸ‡</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -412,6 +428,7 @@
<translation id="22081806969704220">ទម្រទី 3</translation>
<translation id="2212735316055980242">គោលការណáŸáž˜áž·áž“ážáŸ’រូវបានរកឃើញទáŸ</translation>
<translation id="2213606439339815911">កំពុងនាំយកធាážáž»...</translation>
+<translation id="2213612003795704869">ទំពáŸážšážáŸ’រូវបានបោះពុម្ព</translation>
<translation id="2215727959747642672">ការកែឯកសារ</translation>
<translation id="2218879909401188352">ážáŸ’មីៗនáŸáŸ‡â€‹áž¢áŸ’នក​វាយ​ប្រហារ​នៅលើ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> អាច​ដំឡើង​កម្មវិធី​ដែល​មាន​គ្រោះážáŸ’នាក់​ដែល​អាច​ប៉ះពាល់​ដល់ឧបករណáŸážšáž”ស់អ្នក បន្ážáŸ‚ម​ការចំណាយ​ទៅក្នុង​វិក្កយបážáŸ’រ​សáŸážœáž¶â€‹áž‘ូរសព្ទ​ចលáŸážâ€‹ážŠáŸ„យ​មិន​ឲ្យ​អ្នកដឹង ឬ​លួច​ពáŸážáŸŒáž˜áž¶áž“​ផ្ទាល់ážáŸ’លួន​របស់​អ្នក។ <ph name="BEGIN_LEARN_MORE_LINK" />ស្វែងយល់​បន្ážáŸ‚ម<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">គ្មាន​អ៊ីនធឺណិážáž‘áŸ</translation>
@@ -421,6 +438,7 @@
<translation id="2248949050832152960">ប្រើ WebAuthn</translation>
<translation id="2250931979407627383">ដáŸážšáž‚ែម​ážáž¶áž„ឆ្វáŸáž„</translation>
<translation id="225207911366869382">ážáž˜áŸ’លៃនáŸáŸ‡ážáŸ’រូវបានបដិសáŸáž’សម្រាប់គោលការណáŸáž“áŸáŸ‡áŸ”</translation>
+<translation id="2256115617011615191">ចាប់ផ្ដើមឡើងវិញឥឡូវនáŸáŸ‡</translation>
<translation id="2258928405015593961">បញ្ចូល​កាលបរិច្ឆáŸáž‘​ផុážáž€áŸ†ážŽážáŸ‹â€‹áž€áŸ’នុងពáŸáž›â€‹áž¢áž“ាគហរួច​ព្យាយាម​ម្ដងទៀáž</translation>
<translation id="225943865679747347">កំហុសឆ្គងលáŸážáž€áž¼ážŠáŸ– <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">កំហុសឆ្គង HTTP</translation>
@@ -448,6 +466,7 @@
<translation id="2337852623177822836">ការកំណážáŸ‹â€‹áž‚្រប់គ្រង​ដោយ​អ្នកគ្រប់គ្រង​របស់អ្នក</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> ចង់ផ្គូផ្គង</translation>
<translation id="2346319942568447007">រូបភាព​ដែលអ្នក​បានចម្លង</translation>
+<translation id="2350796302381711542">អនុញ្ញាážáž²áŸ’áž™ <ph name="HANDLER_HOSTNAME" /> បើក <ph name="PROTOCOL" /> ážáŸ†ážŽáž‘ាំងអស់ជំនួសឲ្យ <ph name="REPLACED_HANDLER_TITLE" />?</translation>
<translation id="2354001756790975382">ចំណាំផ្សáŸáž„ទៀáž</translation>
<translation id="2354430244986887761">ážáŸ’មីៗនáŸáŸ‡áž€áž¶ážšážšáž»áž€ážšáž€ážŠáŸ„យសុវážáŸ’ážáž·áž—ាពលើ Google <ph name="BEGIN_LINK" />បានរកឃើញកម្មវិធីបង្កគ្រោះážáŸ’នាក់<ph name="END_LINK" /> នៅលើ <ph name="SITE" /> ។</translation>
<translation id="2355395290879513365">អ្នកវាយប្រហារអាចនឹងមើលឃើញរូបភាពដែលអ្នកកំពុងមើលនៅលើគáŸáž áž‘ំពáŸážšáž“áŸáŸ‡ និងបញ្ឆោážáž¢áŸ’នកដោយធ្វើការកែសម្រួលពួកវា។</translation>
@@ -474,6 +493,7 @@
អាចážáŸ’រូវបានបញ្ឈប់សុពលភាព។ áž“áŸáŸ‡áž¢áž¶áž…បណ្ážáž¶áž›áž˜áž€áž–ីការកំណážáŸ‹áž˜áž·áž“ážáŸ’រឹមážáŸ’រូវ ឬមានការស្ទាក់ការភ្ជាប់របស់អ្នកពីអ្នកវាយប្រហារ។</translation>
<translation id="2414886740292270097">áž„áž„áž¹áž</translation>
<translation id="2430968933669123598">គ្រប់គ្រង​គណនី Google, ចុច Enter ដើម្បីគ្រប់គ្រង​ពáŸážáŸŒáž˜áž¶áž“ ឯកជនភាព និង​សុវážáŸ’ážáž·áž—ាព​របស់អ្នក​នៅក្នុង​គណនី Google របស់អ្នក</translation>
+<translation id="2436186046335138073">អនុញ្ញាហ<ph name="HANDLER_HOSTNAME" /> ឲ្យបើក <ph name="PROTOCOL" /> ážáŸ†ážŽáž‘ាំងអស់?</translation>
<translation id="2438874542388153331">ចោះ​បួនរន្ធ​ážáž¶áž„ស្ដាំ</translation>
<translation id="2450021089947420533">ការស្វែងរក</translation>
<translation id="2463739503403862330">បំពáŸáž‰</translation>
@@ -481,6 +501,7 @@
<translation id="2465655957518002998">ជ្រើសរើស​មធ្យោបាយ​ចែកចាយ</translation>
<translation id="2465688316154986572">កិប</translation>
<translation id="2465914000209955735">គ្រប់គ្រងឯកសារ​ដែលអ្នកបាន​ទាញយកនៅក្នុង Chrome</translation>
+<translation id="2466004615675155314">បង្ហាញពáŸážáŸŒáž˜áž¶áž“​ពីបណ្ដាញ</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />កំពុងដំណើរការការវិភាគបណ្ážáž¶áž‰<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">លំដាប់លំដោយ 1-to-N</translation>
<translation id="2470767536994572628">នៅពáŸáž›â€‹áž¢áŸ’នក​កែចំណារ ឯកសារ​នáŸáŸ‡â€‹áž“ឹងážáŸ’រឡប់ទៅ​ការមើល​ទំពáŸážšâ€‹áž‘ោល និង​ការបង្វិលដើម​របស់វា​វិញ</translation>
@@ -501,6 +522,7 @@
<translation id="2523886232349826891">បានរក្សាទុក​នៅលើážáŸ‚ឧបករណáŸáž“áŸáŸ‡â€‹áž”៉ុណ្ណោះ</translation>
<translation id="2524461107774643265">បញ្ចូល​ពáŸážáŸŒáž˜áž¶áž“​បន្ážáŸ‚ម</translation>
<translation id="2529899080962247600">កន្លែងបញ្ចូលនáŸáŸ‡â€‹áž˜áž·áž“​គួរមានច្រើនជាង <ph name="MAX_ITEMS_LIMIT" /> ធាážáž»â€‹áž‘áŸáŸ” ធាážáž»áž‘ាំងអស់​ដែលលើសពីនáŸáŸ‡â€‹áž“ឹងមិនážáŸ’រូវបាន​អើពើទáŸáŸ”</translation>
+<translation id="2535585790302968248">បើក​ផ្ទាំងឯកជនážáŸ’មី ដើម្បីរុករក​ជាលក្ážážŽáŸˆáž¯áž€áž‡áž“</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{áž“áž·áž„ 1 ​ទៀáž}other{áž“áž·áž„ # ទៀáž}}</translation>
<translation id="2536110899380797252">បញ្ចូល​អាសយដ្ឋាន</translation>
<translation id="2539524384386349900">ស្វែងរក</translation>
@@ -526,7 +548,14 @@
<translation id="2597378329261239068">ឯកសារនáŸáŸ‡ážáŸ’រូវបានការពារដោយពាក្យសម្ងាážáŸ‹áŸ” សូមបញ្ចូលពាក្យសម្ងាážáŸ‹áŸ”</translation>
<translation id="2609632851001447353">បំរែបម្រួល</translation>
<translation id="2610561535971892504">ចុច​ដើម្បី​ចម្លង</translation>
+<translation id="2617988307566202237">Chrome <ph name="BEGIN_EMPHASIS" />នឹង​មិន​រក្សាទុក<ph name="END_EMPHASIS" />áž–áŸážáŸŒáž˜áž¶áž“​ážáž¶áž„ក្រោម​ទáŸáŸ–
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ប្រវážáŸ’ážáž·â€‹ážšáž»áž€ážšáž€â€‹ážáž¶áž˜áž¢áŸŠáž¸áž“ធឺណិážâ€‹ážšáž”ស់អ្នក
+ <ph name="LIST_ITEM" />ážáž¼áž‚ី និង​ទិន្ននáŸáž™â€‹áž‚áŸáž áž‘ំពáŸážš
+ <ph name="LIST_ITEM" />áž–áŸážáŸŒáž˜áž¶áž“​ដែលបាន​បញ្ចូល​ក្នុង​ទម្រង់​បែបបទ
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (ស្រោម​សំបុážáŸ’ážš)</translation>
+<translation id="2623663032199728144">អាចស្នើសុំប្រើ​ពáŸážáŸŒáž˜áž¶áž“អំពី​អáŸáž€áŸ’រង់​របស់អ្នក</translation>
<translation id="2625385379895617796">ម៉ោងរបស់អ្នកដើរលឿន</translation>
<translation id="262745152991669301">អាចស្នើសុំភ្ជាប់​ជាមួយ​ឧបករណ០USB</translation>
<translation id="2629325967560697240">ដើម្បីទទួលបានកម្រិážážŸáž»ážœážáŸ’ážáž·áž—ាពážáŸ’ពស់បំផុážážšáž”ស់ Chrome <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />សូមបើកការការពារ​ដែលប្រសើរជាងមុន<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -560,6 +589,7 @@
<translation id="2709516037105925701">បំពáŸáž‰ážŸáŸ’ážœáŸáž™áž”្រវážáŸ’ážáž·</translation>
<translation id="2713444072780614174">ស</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />, ចុច "Tab" រួចចុច "Enter" ដើម្បីគ្រប់គ្រងការបង់ប្រាក់ áž“áž·áž„áž–áŸážáŸŒáž˜áž¶áž“បណ្ណឥណទានរបស់អ្នក​នៅក្នុងការកំណážáŸ‹ Chrome</translation>
+<translation id="271663710482723385">ចុច |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| ដើម្បីចáŸáž‰áž–ីមុážáž„ារអáŸáž€áŸ’រង់ពáŸáž‰</translation>
<translation id="2721148159707890343">សំណើរបានជោគជáŸáž™</translation>
<translation id="2723669454293168317">ដំណើរការ​ការពិនិážáŸ’យ​សុវážáŸ’ážáž·áž—ាព​នៅក្នុងការកំណážáŸ‹ Chrome</translation>
<translation id="2726001110728089263">ទម្រចំហៀង</translation>
@@ -590,6 +620,7 @@
<translation id="2850739647070081192">Invite (ស្រោម​សំបុážáŸ’ážš)</translation>
<translation id="2856444702002559011">អ្នក​វាយ​ប្រហារ​ប្រហែល​ជាកំពុង​លួចយក​ពáŸážáŸŒáž˜áž¶áž“​របស់អ្នក​ពី <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (ឧទាហរណáŸáŸ– ពាក្យសម្ងាážáŸ‹ សារ ឬបណ្ណឥណទាន)។ <ph name="BEGIN_LEARN_MORE_LINK" />ស្វែងយល់បន្ážáŸ‚ម<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">áž‚áŸáž áž‘ំពáŸážšâ€‹áž“áŸáŸ‡áž”ង្ហាញ​ការផ្សាយពាណិជ្ជកម្ម​ដែលនាំឱ្យយល់ច្រឡំ ឬរំážáž¶áž“។</translation>
+<translation id="286512204874376891">កាážáž“ិម្មិážáž€áŸ’លែងធ្វើជា​កាážáž–áž·ážáž”្រាកដ​របស់អ្នក ដើម្បីជួយការពារអ្នក​ពីការគៃបន្លំ​ដែលអាចកើážáž˜áž¶áž“។ <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">លក្ážážŽáŸˆâ€‹áž˜áž·ážáŸ’ážáž—ាព</translation>
<translation id="2876489322757410363">កំពុង​ចាកចáŸáž‰áž–ី​មុážáž„ារ​ឯកជន ដើម្បីបង់ប្រាក់​ážáž¶áž˜ážšáž™áŸˆâ€‹áž€áž˜áŸ’មវិធី​ážáž¶áž„ក្រៅ។ បន្ážáž¬áž‘áŸ?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />, ចុច Tab រួចចុច Enter ដើម្បីគ្រប់គ្រងការរុករក​ដោយសុវážáŸ’ážáž·áž—ាពរបស់អ្នក និងអ្វីៗជាច្រើនទៀážáž“ៅក្នុងការកំណážáŸ‹ Chrome</translation>
@@ -614,6 +645,7 @@
<translation id="2930577230479659665">ážáž˜áŸ’រឹម​បន្ទាប់ពី​ច្បាប់ចម្លង​នីមួយៗ</translation>
<translation id="2932085390869194046">ណែនាំ​ពាក្យសម្ងាážáŸ‹...</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019">បើកážáŸ†ážŽ <ph name="PROTOCOL" /></translation>
<translation id="2941952326391522266">ម៉ាស៊ីនមáŸáž“áŸáŸ‡áž˜áž·áž“អាចបង្ហាញážáž¶ážœáž¶áž‡áž¶ <ph name="DOMAIN" /> ទ០វិញ្ញាបនបáŸážáŸ’រសុវážáŸ’ážáž·áž—ាពរបស់វាមកពី <ph name="DOMAIN2" />។ áž“áŸáŸ‡áž¢áž¶áž…បណ្ážáž¶áž›áž˜áž€áž–ីការកំណážáŸ‹áž˜áž·áž“ážáŸ’រឹមážáŸ’រូវ ឬមានការស្ទាក់ការភ្ជាប់របស់អ្នកពីអ្នកវាយប្រហារ។</translation>
<translation id="2943895734390379394">áž–áŸáž›â€‹ážœáŸáž›áž¶áž”ង្ហោះ៖</translation>
<translation id="2948083400971632585">អ្នកអាចបិទដំណើរការប្រូកស៊ីណាមួយដែលបានកំណážáŸ‹ážŸáž˜áŸ’រាប់ការភ្ជាប់ ពីទំពáŸážšáž€áž¶ážšáž€áŸ†ážŽážáŸ‹áŸ”</translation>
@@ -646,6 +678,7 @@
<translation id="3037605927509011580">អូយ ទក់!</translation>
<translation id="3041612393474885105">áž–áŸážáŸŒáž˜áž¶áž“វិញ្ញាបនបáŸážáŸ’ážš</translation>
<translation id="3044034790304486808">បន្ážâ€‹áž€áž¶ážšážŸáŸ’វែងរក​របស់អ្នក</translation>
+<translation id="305162504811187366">ប្រវážáŸ’ážáž· Chrome Remote Desktop រួមទាំង​លáŸážážŸáž˜áŸ’គាល់វគ្គ​នៃកម្មវិធីភ្ញៀវ ម៉ាស៊ីន áž“áž·áž„áž–áŸáž›ážœáŸáž›áž¶</translation>
<translation id="3060227939791841287">C9 (ស្រោម​សំបុážáŸ’ážš)</translation>
<translation id="3061707000357573562">Patch Service</translation>
<translation id="306573536155379004">ហ្គáŸáž˜â€‹áž”ានចាប់ផ្ដើម។</translation>
@@ -686,6 +719,7 @@
<translation id="3197136577151645743">អាចសួរដើម្បីដឹងážáž¶ នៅពáŸáž›ážŽáž¶ážŠáŸ‚ល​អ្នកកំពុងប្រើ​ឧបករណáŸáž“áŸáŸ‡â€‹áž™áŸ‰áž¶áž„សកម្ម</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />, ចុច "Tab" រួចចុច "Enter" ដើម្បីគ្រប់គ្រងážáž¶áž–áŸážáŸŒáž˜áž¶áž“អ្វីដែលអ្នកធ្វើសមកាលកម្មនៅក្នុងការកំណážáŸ‹ Chrome</translation>
<translation id="320323717674993345">បោះបង់ការ​បង់ប្រាក់</translation>
+<translation id="3203366800380907218">​ពី​បណ្ážáž¶áž‰</translation>
<translation id="3207960819495026254">បានចំណាំ</translation>
<translation id="3209034400446768650">ទំពáŸážšáž¢áž¶áž…​នឹង​គិážáž”្រាក់</translation>
<translation id="3212581601480735796">សកម្មភាព​របស់អ្នក​នៅលើ <ph name="HOSTNAME" /> កំពុងážáŸ’រូវ​បានឃ្លាំមើល</translation>
@@ -702,10 +736,12 @@
<translation id="3234666976984236645">ážáŸ‚áž„ážáŸ‚ចាប់យកមាážáž·áž€áž¶ážŸáŸ†ážáž¶áž“់ជានិច្ចនៅលើគáŸáž áž‘ំពáŸážšáž“áŸáŸ‡</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />, ចុច tab រួចចុច Enter ដើម្បីប្ដូរ​រូបរាងនៃ​កម្មវិធីរុករកážáž¶áž˜áž¢áŸŠáž¸áž“ធឺណិážâ€‹ážšáž”ស់អ្នក​ážáž¶áž˜áž”ំណង</translation>
<translation id="3240791268468473923">សន្លឹក​ពáŸážáŸŒáž˜áž¶áž“ផ្ទៀងផ្ទាážáŸ‹â€‹áž€áž¶ážšáž”ង់ប្រាក់​មានសុវážáŸ’ážáž·áž—ាព ដែលគ្មានពáŸážáŸŒáž˜áž¶áž“ផ្ទៀងផ្ទាážáŸ‹â€‹ážáŸ’រូវគ្នា​ážáŸ’រូវបានបើក</translation>
+<translation id="324180406144491771">ážáŸ†ážŽ “<ph name="HOST_NAME" />†ážáŸ’រូវបាន​ទប់ស្កាážáŸ‹</translation>
<translation id="3249845759089040423">ទាន់​សមáŸáž™</translation>
<translation id="3252266817569339921">ភាសាបារាំង</translation>
<translation id="3257954757204451555">ážáž¾áž“រណា​នៅពីក្រោយ​ពáŸážáŸŒáž˜áž¶áž“áž“áŸáŸ‡?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />, ចុច Tab រួចចុច Enter ដើម្បីបង្កើážâ€‹áž–្រឹážáŸ’ážáž·áž€áž¶ážšážŽáŸážáŸ’មី​នៅក្នុង Google ប្រážáž·áž‘ិន​បានរហáŸážŸ</translation>
+<translation id="3261488570342242926">ស្វែងយល់អំពីកាážáž“ិម្មិáž</translation>
<translation id="3264837738038045344">ប៊ូážáž»áž„ "គ្រប់គ្រង​ការកំណážáŸ‹ Chrome" ចុច "Enter" ដើម្បីចូលទៅកាន់​ការកំណážáŸ‹ Chrome របស់អ្នក</translation>
<translation id="3266793032086590337">ážáž˜áŸ’លៃ (ជាន់គ្នា)</translation>
<translation id="3268451620468152448">បើកផ្ទាំង</translation>
@@ -719,6 +755,7 @@
<translation id="3288238092761586174"><ph name="URL" /> អាចážáŸ’រូវអនុវážáŸ’ážâ€‹áž‡áŸ†áž áž¶áž“បន្ážáŸ‚ម ដើម្បីផ្ទៀងផ្ទាážáŸ‹â€‹áž€áž¶ážšáž”ង់ប្រាក់​របស់អ្នក</translation>
<translation id="3293642807462928945">ស្វែង​យល់បន្ážáŸ‚ម​អំពី​គោលការណ០<ph name="POLICY_NAME" /></translation>
<translation id="3295444047715739395">មើល និងគ្រប់គ្រង​ពាក្យសម្ងាážáŸ‹ážšáž”ស់អ្នក​នៅក្នុងការកំណážáŸ‹ Chrome</translation>
+<translation id="3303795387212510132">អនុញ្ញាážâ€‹áž±áŸ’យកម្មវិធី​បើកážáŸ†ážŽ <ph name="PROTOCOL_SCHEME" /> ដែរទáŸ?</translation>
<translation id="3303855915957856445">រកមិនឃើញលទ្ធផលស្វែងរកទáŸ</translation>
<translation id="3304073249511302126">ការស្កáŸáž“​ប៊្លូធូស</translation>
<translation id="3308006649705061278">ក្រុមអង្គភាព (OU)</translation>
@@ -732,12 +769,6 @@
<translation id="3345782426586609320">ភ្នែក</translation>
<translation id="3355823806454867987">ប្ážáž¼ážšáž€áž¶ážšáž€áŸ†ážŽážáŸ‹áž”្រូកស៊ី...</translation>
<translation id="3360103848165129075">សន្លឹក​កម្មវិធីគ្រប់គ្រង​ការបង់ប្រាក់</translation>
-<translation id="3361596688432910856">Chrome <ph name="BEGIN_EMPHASIS" />នឹងមិនរក្សាទុក<ph name="END_EMPHASIS" />áž–áŸážáŸŒáž˜áž¶áž“ážáž¶áž„ក្រោមទáŸáŸ–
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />ប្រវážáŸ’ážáž·ážšáž»áž€ážšáž€ážšáž”ស់អ្នក
- <ph name="LIST_ITEM" />ážáž¼áž‚ី និងទិន្ននáŸáž™áž‘ំពáŸážš
- <ph name="LIST_ITEM" />áž–áŸážáŸŒáž˜áž¶áž“ដែលបានបញ្ចូលក្នុងទម្រង់
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">គោលការណáŸâ€‹áž“áŸáŸ‡â€‹ážáŸ’រូវបាន​ចម្លង​ដោយស្វáŸáž™áž”្រវážáŸ’ážáž·â€‹áž–ី​គោលការណ០<ph name="OLD_POLICY" /> ដែលបាន​បញ្ឈប់។ អ្នក​គួរážáŸ‚​ប្រើ​គោលការណáŸâ€‹áž“áŸáŸ‡â€‹áž‡áŸ†áž“ួសវិញ។</translation>
<translation id="3364869320075768271"><ph name="URL" /> ចង់ប្រើ​ទិន្ននáŸáž™ និង​ឧបករណ០VR របស់អ្នក</translation>
<translation id="3366477098757335611">មើលកាáž</translation>
@@ -820,7 +851,6 @@
<translation id="3587738293690942763">កណ្ážáž¶áž›</translation>
<translation id="3592413004129370115">Italian (ស្រោម​សំបុážáŸ’ážš)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{អ្នកអាច​កំណážáŸ‹â€‹áž€áŸ’រុមរបស់អ្នក​ឡើងវិញ​បានគ្រប់ពáŸáž›áŸ” ចំណាយពáŸáž›áž”្រហែលមួយážáŸ’ងៃ ដើម្បីចូលរួមក្រុមážáŸ’មី។}=1{អ្នកអាច​កំណážáŸ‹â€‹áž€áŸ’រុមរបស់អ្នក​ឡើងវិញ​បានគ្រប់ពáŸáž›áŸ” ចំណាយពáŸáž›áž”្រហែលមួយážáŸ’ងៃ ដើម្បីចូលរួមក្រុមážáŸ’មី។}other{អ្នកអាច​កំណážáŸ‹â€‹áž€áŸ’រុមរបស់អ្នក​ឡើងវិញ​បានគ្រប់ពáŸáž›áŸ” ចំណាយពáŸáž›áž”្រហែល {NUM_DAYS} ážáŸ’ងៃ ដើម្បីចូលរួមក្រុមážáŸ’មី។}}</translation>
-<translation id="3596012367874587041">ការកំណážáŸ‹áž€áž˜áŸ’មវិធី</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">កម្មវិធី​ដែលទប់ស្កាážáŸ‹â€‹ážŠáŸ„យ​អ្នកគ្រប់គ្រង​របស់អ្នក</translation>
<translation id="3608932978122581043">កំណážáŸ‹áž‘ិស</translation>
@@ -863,6 +893,7 @@
<translation id="370972442370243704">បើកការស្វែងរក</translation>
<translation id="3711895659073496551">បញ្ឈប់</translation>
<translation id="3712624925041724820">អស់អាជ្ញាបáŸážŽáŸ’ណ</translation>
+<translation id="3714633008798122362">ប្រážáž·áž‘áž·áž“áž‚áŸáž áž‘ំពáŸážš</translation>
<translation id="3714780639079136834">បើកទិន្ននáŸáž™áž…áž›áŸáž ឬ Wi-Fi</translation>
<translation id="3715597595485130451">ភ្ជាប់ទៅ Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />áž–áž·áž“áž·ážáŸ’យការកំណážáŸ‹ážšáž…នាសម្ពáŸáž“្ធប្រូកស៊ី firewall áž“áž·áž„ DNS<ph name="END_LINK" /></translation>
@@ -924,6 +955,7 @@
<translation id="3906954721959377182">ážáŸáž”្លáŸáž</translation>
<translation id="3909477809443608991"><ph name="URL" /> ចង់ចាក់ážáŸ’លឹមសារ​ដែលមានការ​ការពារ។ អážáŸ’ážážŸáž‰áŸ’ញាណ​ឧបករណáŸážšáž”ស់អ្នក​នឹងážáŸ’រូវផ្ទៀងផ្ទាážáŸ‹â€‹ážŠáŸ„áž™ Google ហើយអាចនឹង​ážáŸ’រូវបានចូលប្រើ​ដោយគáŸáž áž‘ំពáŸážšáž“áŸáŸ‡áŸ”</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">បដិសáŸáž’</translation>
<translation id="3939773374150895049">ប្រើ WebAuthn ជំនួសឱ្យ CVC?</translation>
<translation id="3946209740501886391">សួរជានិច្ចនៅលើគáŸáž áž‘ំពáŸážšáž“áŸáŸ‡</translation>
<translation id="3947595700203588284">អាចស្នើសុំភ្ជាប់ជាមួយឧបករណ០MIDI</translation>
@@ -945,6 +977,7 @@
<translation id="3990250421422698716">គម្លាážážšáž»áž‰</translation>
<translation id="3996311196211510766">áž‚áŸáž áž‘ំពáŸážš <ph name="ORIGIN" /> បានស្នើសុំឱ្យ​អនុវážáŸ’ážâ€‹áž‚ោលការណáŸâ€‹ážŠáž¾áž˜
ចំពោះ​គ្រប់សំណើ​មក​កាន់​វា ប៉ុន្ážáŸ‚​គោលការណáŸáž“áŸáŸ‡áž˜áž·áž“អាច​អនុវážáŸ’ážâ€‹áž”ាន​ទáŸáž€áŸ’នុងពáŸáž›áž”ច្ចុប្បន្ន។</translation>
+<translation id="4009243425692662128">ážáŸ’លឹមសារក្នុងទំពáŸážšážŠáŸ‚លអ្នកបោះពុម្ពážáŸ’រូវបានផ្ញើទៅ Google Cloud ឬភាគីទីបីដើម្បីវិភាគ។ ឧទាហរណ០ážáŸ’លឹមសារនោះ​អាចážáŸ’រូវបាន​ស្កáŸáž“ ដើម្បីរកមើល​ទិន្ននáŸáž™â€‹ážšážŸáž¾áž”​។</translation>
<translation id="4010758435855888356">អនុញ្ញាážâ€‹áž±áŸ’យចូលប្រើ​ទំហំផ្ទុក​ដែរទáŸ?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{ឯកសារ PDF ដែលមាន {COUNT} ទំពáŸážš}other{ឯកសារ PDF ដែលមាន {COUNT} ទំពáŸážš}}</translation>
<translation id="4023431997072828269">អ្នកដទៃនឹង​អាចមើលឃើញ​ពáŸážáŸŒáž˜áž¶áž“របស់អ្នក ដោយសារ​ទម្រង់បែបបទនáŸáŸ‡â€‹áž€áŸ†áž–ុងážáŸ’រូវបាន​ដាក់បញ្ជូន ដោយប្រើ​ការážáž—្ជាប់​ដែលមិនមាន​សុវážáŸ’ážáž·áž—ាព។</translation>
@@ -1039,6 +1072,7 @@
<translation id="4250680216510889253">áž‘áŸ</translation>
<translation id="4253168017788158739">កំណážáŸ‹ážáŸ’រា</translation>
<translation id="425582637250725228">ការផ្លាស់ប្ážáž¼ážšážŠáŸ‚លអ្នកបានធ្វើប្រហែលជាមិនបានរក្សាទុកទáŸ</translation>
+<translation id="425869179292622354">ធ្វើឱ្យវាកាន់ážáŸ‚​មានសុវážáŸ’ážáž·áž—ាព​ដោយប្រើកាážáž“ិម្មិážáž¬?</translation>
<translation id="4258748452823770588">áž áŸážáŸ’ážáž›áŸážáž¶áž˜áž·áž“ល្អ</translation>
<translation id="4261046003697461417">មិនអាចដាក់​ចំណារលើឯកសារ​ដែលážáŸ’រូវបានការពារនោះ​ទáŸ</translation>
<translation id="4265872034478892965">អនុញ្ញាážážŠáŸ„យអ្នកគ្រប់គ្រងរបស់អ្នក</translation>
@@ -1102,6 +1136,7 @@
<translation id="4434045419905280838">ផ្ទាំងផុស​ និង​ការ​បញ្ជូន​បន្áž</translation>
<translation id="4435702339979719576">បណ្ណប្រៃសណីយáŸ)</translation>
<translation id="443673843213245140">ការប្រើប្រូកស៊ីážáŸ’រូវបានបិទដំណើរការ ប៉ុន្ážáŸ‚ការកំណážáŸ‹áž”្រូកស៊ីដែលច្បាស់លាស់ážáŸ’រូវបានបញ្ជាក់។</translation>
+<translation id="4441832193888514600">បានមិនអើពើ ដោយសារអាចកំណážáŸ‹â€‹áž‚ោលការណáŸâ€‹áž‡áž¶áž‚ោលការណáŸâ€‹áž¢áŸ’នកប្រើប្រាស់ពពក​ážáŸ‚ប៉ុណ្ណោះ។</translation>
<translation id="4450893287417543264">កុំបង្ហាញម្ដងទៀáž</translation>
<translation id="4451135742916150903">អាចស្នើសុំ​ភ្ជាប់ជាមួយ​ឧបករណ០HID</translation>
<translation id="4452328064229197696">ពាក្យសម្ងាážáŸ‹ážŠáŸ‚លអ្នកទើបážáŸ‚ប្រើážáŸ’រូវបានរកឃើញនៅក្នុងការបែកធ្លាយទិន្ននáŸáž™áŸ” ដើម្បីការពារសុវážáŸ’ážáž·áž—ាពគណនីរបស់អ្នក កម្មវិធីគ្រប់គ្រងពាក្យសម្ងាážáŸ‹ Google ណែនាំឱ្យពិនិážáŸ’យមើលពាក្យសម្ងាážáŸ‹ážŠáŸ‚លអ្នកបានរក្សាទុក។</translation>
@@ -1157,6 +1192,7 @@
<translation id="4628948037717959914">រូបážáž</translation>
<translation id="4631649115723685955">បានភ្ជាប់​ការទទួល​បានប្រាក់​មកវិញ</translation>
<translation id="4636930964841734540">áž–áŸážáŸŒáž˜áž¶áž“</translation>
+<translation id="4638670630777875591">មុážáž„ារឯកជននៅក្នុង Chromium</translation>
<translation id="464342062220857295">ស្វែងរក​មុážáž„ារ</translation>
<translation id="4644670975240021822">ផ្កាប់ចុះ​ážáž¶áž˜áž›áŸ†ážŠáž¶áž”់លំដោយ​បញ្ច្រាស</translation>
<translation id="4646534391647090355">នាំážáŸ’ញុំទៅទីនោះឥឡូវនáŸáŸ‡</translation>
@@ -1177,6 +1213,7 @@
<translation id="4708268264240856090">ការážáž—្ជាប់របស់អ្នកមានការរំážáž¶áž“</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />កំពុងដំណើរការការវិភាគបណ្ážáž¶áž‰ Windows<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426">ពាក្យ​សម្ងាážáŸ‹â€‹ážŸáž˜áŸ’រាប់ <ph name="USERNAME" /></translation>
<translation id="4724144314178270921">អាចស្នើសុំ​មើលអážáŸ’ážáž”áž‘ និងរូបភាព​នៅក្នុងឃ្លីបបážâ€‹ážšáž”ស់អ្នក</translation>
<translation id="4726672564094551039">ដំណើរការគោលការណáŸáž¡áž¾áž„វិញ</translation>
<translation id="4728558894243024398">អង្គប្រážáž·áž”ážáŸ’ážáž·áž€áž¶ážš</translation>
@@ -1198,6 +1235,7 @@
<translation id="4757993714154412917">អ្នកទើបážáŸ‚​បានបញ្ចូល​ពាក្យសម្ងាážáŸ‹â€‹ážšáž”ស់អ្នក​នៅលើ​គáŸáž áž‘ំពáŸážšáž”ញ្ឆោážáŸ” ដើម្បី​រក្សាសុវážáŸ’ážáž·áž—ាព​គណនី​របស់អ្នក Chromium សូមណែនាំឱ្យ​ពិនិážáŸ’យមើល​ពាក្យសម្ងាážáŸ‹â€‹ážŠáŸ‚លអ្នកបានរក្សាទុក។</translation>
<translation id="4758311279753947758">បន្ážáŸ‚មពáŸážáŸŒáž˜áž¶áž“ទំនាក់ទំនង</translation>
<translation id="4761104368405085019">ប្រើម៉ៃក្រូហ្វូនរបស់អ្នក</translation>
+<translation id="4761869838909035636">ដំណើរការ​ការពិនិážáŸ’យ​សុវážáŸ’ážáž·áž—ាព Chrome</translation>
<translation id="4764776831041365478">áž‚áŸáž áž‘ំពáŸážšáž“ៅ <ph name="URL" /> អាចមិនដំណើរការបណ្ážáŸ„ះអាសន្ន ឬវាអាចážáŸ’រូវបានផ្លាស់ទីទៅអាសយដ្ឋានគáŸáž áž‘ំពáŸážšážáŸ’មី។</translation>
<translation id="4766713847338118463">កិប​ពីរគ្រាប់​ážáž¶áž„ក្រោម</translation>
<translation id="4771973620359291008">កំហុសឆ្គងមិនស្គាល់បានកើážáž¡áž¾áž„។</translation>
@@ -1218,12 +1256,6 @@
<translation id="4819347708020428563">កែចំណារនៅក្នុងទិដ្ឋភាពលំនាំដើមឬ?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />, ចុច Tab រួចចុច Enter ដើម្បី​បង្កើážâ€‹áž”ញ្ជី Google ážáŸ’មីបានរហáŸážŸ</translation>
<translation id="4825507807291741242">មាន​ឥទ្ធិពល​ážáŸ’លាំង</translation>
-<translation id="4827402517081186284">មុážáž„ារឯកជន​មិនមែនធ្វើឱ្យគáŸâ€‹áž˜áž¾áž›áž˜áž·áž“ឃើញអ្នក​នៅលើអ៊ីនធឺណិážáž“ោះទáŸáŸ–
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />áž‚áŸáž áž‘ំពáŸážšáž“ានា​ដឹងážáž¶áž–áŸáž›ážŽáž¶â€‹ážŠáŸ‚លអ្នកចូលមើល​គáŸáž áž‘ំពáŸážšáž‘ាំងនោះ<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />និយោជក ឬសាលារៀន​អាចážáž¶áž˜ážŠáž¶áž“​សកម្មភាព​រុករក​ážáž¶áž˜áž¢áŸŠáž¸áž“ធឺណិáž<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />ក្រុមហ៊ុន​ផ្ដល់​សáŸážœáž¶áž€áž˜áŸ’ម​អ៊ីនធឺណិážâ€‹áž¢áž¶áž…áž–áž·áž“áž·ážáŸ’áž™ážáž¶áž˜ážŠáž¶áž“​ចរាចរណáŸáž”ណ្ដាញ<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">បើក​ការព្រមាន</translation>
<translation id="4838327282952368871">ដូចក្ដី​សុបិន</translation>
<translation id="4840250757394056958">មើលប្រវážáŸ’ážáž· Chrome របស់អ្នក</translation>
@@ -1235,12 +1267,12 @@
<translation id="4854362297993841467">មិនមានមធ្យោបាយ​ដឹកជញ្ជូនផ្ទាល់នáŸáŸ‡áž‘áŸáŸ” សូមសាកល្បងមធ្យោបាយផ្សáŸáž„។</translation>
<translation id="4854853140771946034">បង្កើážâ€‹áž€áŸ†ážŽážáŸ‹áž…ំណាំážáŸ’មី​នៅក្នុង Google Keep បានរហáŸážŸ</translation>
<translation id="485902285759009870">កំពុង​ផ្ទៀង​ផ្ទាážáŸ‹â€‹â€‹áž›áŸážâ€‹áž€áž¼ážŠ...</translation>
+<translation id="4866506163384898554">ចុច |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| ដើម្បីបង្ហាញទស្សនáŸáž‘្រនិច​របស់អ្នក</translation>
<translation id="4876188919622883022">​ទិដ្ឋភាព​សាមញ្ញ</translation>
<translation id="4876305945144899064">គ្មាន​ឈ្មោះ​អ្នកប្រើប្រាស់​ទáŸ</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{គ្មាន}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831">ការស្វែងរក <ph name="TEXT" /></translation>
<translation id="4879491255372875719">ស្វáŸáž™áž”្រវážáŸ’ážáž· (លំនាំដើម)</translation>
-<translation id="4879725228911483934">បើក និង​ដាក់​វិនដូ​នៅលើ​អáŸáž€áŸ’រង់​របស់អ្នក</translation>
<translation id="4880827082731008257">ប្រវážáŸ’ážáž·ážŸáŸ’វែងរក</translation>
<translation id="4881695831933465202">បើក</translation>
<translation id="4885256590493466218">បង់ប្រាក់ដោយប្រើ <ph name="CARD_DETAIL" /> នៅពáŸáž›áž”ង់ប្រាក់ចáŸáž‰</translation>
@@ -1249,6 +1281,7 @@
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">ដុំទីប្រាំបួន</translation>
<translation id="4901778704868714008">រក្សាទុក...</translation>
+<translation id="4905659621780993806">អ្នកគ្រប់គ្រងរបស់អ្នកនឹងចាប់ផ្ដើមឧបករណáŸážšáž”ស់អ្នកឡើងវិញដោយស្វáŸáž™áž”្រវážáŸ’ážáž·áž“ៅម៉ោង <ph name="TIME" /> នៅážáŸ’ងៃទី <ph name="DATE" />។ សូមរក្សាទុកធាážáž»áž‘ាំងឡាយដែលបើក មុនពáŸáž›áž§áž”ករណáŸážšáž”ស់អ្នកចាប់ផ្ដើមឡើងវិញ។</translation>
<translation id="4913987521957242411">ចោះ​ážáž¶áž„លើ​ផ្នែកážáž¶áž„ឆ្វáŸáž„</translation>
<translation id="4918221908152712722">ដំឡើង <ph name="APP_NAME" /> (មិនážáž˜áŸ’រូវ​ឱ្យទាញយកទáŸ)</translation>
<translation id="4923459931733593730">ការបង់ប្រាក់</translation>
@@ -1257,6 +1290,7 @@
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, សូមចុច Tab បន្ទាប់មក Enter ដើម្បីស្វែងរក</translation>
<translation id="4930153903256238152">ទំហំផ្ទុកធំ</translation>
+<translation id="4940163644868678279">មុážáž„ារឯកជននៅក្នុង Chrome</translation>
<translation id="4943872375798546930">គ្មានលទ្ធផលទáŸ</translation>
<translation id="4950898438188848926">ចុច​ប៊ូážáž»áž„ប្ដូរ រួចចុច "Enter" ដើម្បី​ប្ដូរទៅ​ផ្ទាំងបើក <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="495170559598752135">សកម្មភាព</translation>
@@ -1266,6 +1300,7 @@
<translation id="4968522289500246572">កម្មវិធីនáŸáŸ‡ážáŸ’រូវបានបង្កើážáž¡áž¾áž„សម្រាប់ឧបករណáŸáž…áž›áŸáž ហើយប្រហែលជាមិនអាចប្ដូរទំហំ​បានល្អទáŸáŸ” កម្មវិធីនáŸáŸ‡áž¢áž¶áž…មានបញ្ហា ឬចាប់ផ្ដើមឡើងវិញ។</translation>
<translation id="4969341057194253438">លុបការážáž</translation>
<translation id="4973922308112707173">ចោះ​ពីររន្ធ​ážáž¶áž„លើ</translation>
+<translation id="4976702386844183910">បានចូល​មើល​លើកចុង​ក្រោយនៅážáŸ’ងៃទី <ph name="DATE" /></translation>
<translation id="4984088539114770594">ប្រើមីក្រូហ្វូនឬ?</translation>
<translation id="4984339528288761049">Prc5 (ស្រោម​សំបុážáŸ’ážš)</translation>
<translation id="4989163558385430922">មើល​ទាំងអស់</translation>
@@ -1327,6 +1362,7 @@
<translation id="5138227688689900538">បង្ហាញ​ážáž·áž…</translation>
<translation id="5145883236150621069">áž›áŸážáž€áž¼ážŠáž€áŸ†áž áž»ážŸáž†áŸ’គងបង្ហាញនៅក្នុងការឆ្លើយážáž”គោលការណáŸ</translation>
<translation id="5146995429444047494">ការជូនដំណឹង​សម្រាប់ <ph name="ORIGIN" /> ážáŸ’រូវបានទប់ស្កាážáŸ‹</translation>
+<translation id="514704532284964975"><ph name="URL" /> ចង់មើលឃើញ និងផ្លាស់ប្ដូរពáŸážáŸŒáž˜áž¶áž“នៅលើឧបករណ០NFC ដែលអ្នកចុចដោយប្រើទូរសព្ទរបស់អ្នក</translation>
<translation id="5148809049217731050">ផ្ងារឡើង</translation>
<translation id="515292512908731282">C4 (ស្រោម​សំបុážáŸ’ážš)</translation>
<translation id="5158275234811857234">គម្រប</translation>
@@ -1351,6 +1387,7 @@
<translation id="5215116848420601511">វិធី​បង់ប្រាក់ និង​អាសយដ្ឋាន​ដែលប្រើ Google Pay</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">ទម្រទី 13</translation>
+<translation id="5216942107514965959">បានចូលមើល​លើកចុងក្រោយ​នៅážáŸ’ងៃនáŸáŸ‡</translation>
<translation id="5222812217790122047">ážáž˜áŸ’រូវ​ឲ្យ​មាន​អ៊ីមែល</translation>
<translation id="5230733896359313003">អាសយដ្ឋាន​ដឹក​ជញ្ជូន</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1371,7 +1408,6 @@
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">លក្ážážŽáŸˆážŸáž˜áŸ’áž”ážáŸ’ážáž·â€‹ážšáž”ស់ឯកសារ</translation>
<translation id="528468243742722775">បញ្ចប់</translation>
-<translation id="5284909709419567258">អាសយដ្ឋាន​បណ្ដាញ</translation>
<translation id="5285570108065881030">បង្ហាញពាក្យសម្ងាážáŸ‹â€‹áž‘ាំងអស់​ដែលបានរក្សាទុក</translation>
<translation id="5287240709317226393">បង្ហាញ​ážáž¼áž‚ី</translation>
<translation id="5287456746628258573">áž‚áŸáž áž‘ំពáŸážšâ€‹áž“áŸáŸ‡â€‹áž”្រើ​ការកំណážáŸ‹â€‹ážšáž…នាសម្ពáŸáž“្ធ​សុវážáŸ’ážáž·áž—ាព​ដែល​ហួសសមáŸáž™ ដែលជាហáŸážáž»â€‹áž¢áž¶áž…ធ្វើឱ្យ​បែកធ្លាយ​ពáŸážáŸŒáž˜áž¶áž“​របស់អ្នក (ឧទាហរណ០ពាក្យសម្ងាážáŸ‹ áž›áŸážâ€‹áž”ណ្ណ​ឥណទាន) នៅពáŸáž›â€‹áž•áŸ’ញើ​ទៅ​គáŸáž áž‘ំពáŸážšâ€‹áž“áŸáŸ‡áŸ”</translation>
@@ -1455,6 +1491,7 @@
<translation id="5556459405103347317">ដំណើរការឡើងវិញ</translation>
<translation id="5560088892362098740">កាលបរិច្ឆáŸáž‘​ផុážáž€áŸ†ážŽážáŸ‹</translation>
<translation id="55635442646131152">គ្រោង​ឯកសារ</translation>
+<translation id="5565613213060953222">បើកផ្ទាំងឯកជន</translation>
<translation id="5565735124758917034">សកម្ម</translation>
<translation id="5570825185877910964">ការពារ​គណនី</translation>
<translation id="5571083550517324815">មិនអាចទៅយកពីអាសយដ្ឋាននáŸáŸ‡áž”ានទáŸáŸ” សូមជ្រើសរើសអាសយដ្ឋានផ្សáŸáž„។</translation>
@@ -1537,6 +1574,7 @@
<translation id="5869522115854928033">ពាក្យសម្ងាážáŸ‹ážŠáŸ‚លបានរក្សាទុក</translation>
<translation id="5873013647450402046">ធនាគារ​របស់អ្នក​ចង់បញ្ជាក់ážáž¶ áž–áž·ážáž‡áž¶áž¢áŸ’នក។</translation>
<translation id="5887400589839399685">បានរក្សាទុក​កាáž</translation>
+<translation id="5887687176710214216">បានចូលមើល​លើកចុងក្រោយ​កាលពីម្សិលមិញ</translation>
<translation id="5895138241574237353">ចាប់ផ្ážáž¾áž˜áž¡áž¾áž„វិញ</translation>
<translation id="5895187275912066135">áž…áŸáž‰áž“ៅážáŸ’ងៃទី</translation>
<translation id="5901630391730855834">លឿង</translation>
@@ -1550,6 +1588,7 @@
<translation id="5921639886840618607">រក្សាទុក​កាážâ€‹áž‘ៅក្នុង​គណនី Google ?</translation>
<translation id="5922853866070715753">ជិážâ€‹ážšáž½áž…រាល់​ហើយ</translation>
<translation id="5932224571077948991">áž‚áŸáž áž‘ំពáŸážšâ€‹áž”ង្ហាញ​ការផ្សាយពាណិជ្ជកម្ម​ដែលនាំឱ្យយល់ច្រឡំ ឬរំážáž¶áž“</translation>
+<translation id="5938153366081463283">បញ្ចូល​កាážáž“ិម្មិáž</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347">កំពុងបើក <ph name="SITE_NAME" />…</translation>
<translation id="5951495562196540101">មិន​អាច​ចុះឈ្មោះ​ដោយប្រើគណនី​អ្នក​ប្រើប្រាស់​បានទ០(មាន​អាជ្ញាបណ្ណ​ពាក់ពáŸáž“្ធ)។</translation>
@@ -1614,6 +1653,7 @@
<translation id="6120179357481664955">ចងចាំ​លáŸážážŸáž˜áŸ’គាល់ UPI របស់អ្នក​ដែរទáŸâ€‹?</translation>
<translation id="6124432979022149706">កម្មវិធីភ្ជាប់ Chrome Enterprise</translation>
<translation id="6127379762771434464">ធាážáž»ážáŸ’រូវបានយកចáŸáž‰</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />ស្វែងយល់បន្ážáŸ‚មអំពីមុážáž„ារឯកជននៅក្នុង Chrome<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">áž–áž·áž“áž·ážáŸ’áž™ážáŸ’សែបណ្ážáž¶áž‰ បិទបើករ៉ោážáž‘áŸážš ម៉ូឌែម ឬឧបករណáŸáž”ណ្ážáž¶áž‰áž•áŸ’សáŸáž„ទៀáž
ដែលអ្នកកំពុងប្រើប្រាស់។</translation>
<translation id="614940544461990577">សាកល្បង៖</translation>
@@ -1626,7 +1666,6 @@
<translation id="6169916984152623906">ឥឡូវនáŸáŸ‡ អ្នកអាចធ្វើការរុករកជាលក្ážážŽáŸˆáž¯áž€áž‡áž“បានហើយ ដូច្នáŸáŸ‡áž¢áŸ’នកផ្សáŸáž„ទៀážážŠáŸ‚លប្រើឧបករណáŸáž“áŸáŸ‡áž“ឹងមើលមិនឃើញសកម្មភាពរបស់អ្នកទáŸáŸ” ទោះជាយ៉ាងណាក្ážáž¸ ឯកសារទាញយក និងចំណាំនឹងážáŸ’រូវបានរក្សាទុក។</translation>
<translation id="6177128806592000436">ការážáž—្ជាប់របស់អ្នកទៅគáŸáž áž‘ំពáŸážšáž“áŸáŸ‡áž˜áž·áž“មានសុវážáŸ’ážáž·áž—ាពទáŸ</translation>
<translation id="6180316780098470077">ចន្លោះ​ពáŸáž›áž“ៃ​ការព្យាយាមម្ដងទៀáž</translation>
-<translation id="619448280891863779">អាចស្នើសុំបើក និង​ដាក់​វិនដូ​នៅលើ​អáŸáž€áŸ’រង់​របស់អ្នក</translation>
<translation id="6196640612572343990">រារាំង​ážáž¼áž‚ី​ភាគី​ទីបី</translation>
<translation id="6203231073485539293">áž–áž·áž“áž·ážáŸ’យការភ្ជាប់អ៊ីនធឺណិážážšáž”ស់អ្នក</translation>
<translation id="6218753634732582820">យកអាសយដ្ឋានចáŸáž‰áž–ី Chromium ឬ?</translation>
@@ -1649,7 +1688,7 @@
<translation id="6272383483618007430">Google បច្ចុប្បន្នភាព</translation>
<translation id="6276112860590028508">ទំពáŸážšâ€‹áž–ីបញ្ជីអាន​របស់​អ្នក​បង្ហាញ​នៅ​ទីនáŸáŸ‡</translation>
<translation id="627746635834430766">ដើម្បី​បង់ប្រាក់​លឿន​ជាងនáŸáŸ‡â€‹áž“ៅពáŸáž›â€‹áž€áŸ’រោយ សូម​រក្សា​ទុកបណ្ណ និង​អាសយដ្ឋាន​ចáŸáž‰â€‹ážœáž·áž€áŸ’កយបážáŸ’រ​របស់អ្នក​ទៅក្នុង​គណនី Google របស់​អ្នក។</translation>
-<translation id="6279098320682980337">មិនបាន​បំពáŸáž‰â€‹áž›áŸážáž€áž¶ážâ€‹áž“ិម្មិážáž˜áŸ‚áž“áž‘áŸ? សូមចុច​ពáŸážáŸŒáž˜áž¶áž“លម្អិážâ€‹áž¢áŸ†áž–ីកាហដើម្បីចម្លង</translation>
+<translation id="6279183038361895380">ចុច |<ph name="ACCELERATOR" />| ដើម្បីបង្ហាញទស្សនáŸáž‘្រនិចរបស់អ្នក</translation>
<translation id="6280223929691119688">មិនអាចដឹកជញ្ជូនផ្ទាល់ទៅអាសយដ្ឋាននáŸáŸ‡áž”ានទáŸáŸ” សូមជ្រើសរើសអាសយដ្ឋានផ្សáŸáž„។</translation>
<translation id="6282194474023008486">áž›áŸážáž€áž¼ážŠáž”្រៃសណីយáŸ</translation>
<translation id="6285507000506177184">ប៊ូážáž»áž„ "គ្រប់គ្រង​ការទាញយកនៅក្នុង Chrome" ចុច Enter ដើម្បីគ្រប់គ្រង​ឯកសារដែលអ្នក​បានទាញយកនៅក្នុង Chrome</translation>
@@ -1657,6 +1696,7 @@
<translation id="6290238015253830360">អážáŸ’ážáž”ទដែលបានផ្ážáž›áŸ‹áž™áŸ„បល់របស់អ្នកបង្ហាញនៅទីនáŸáŸ‡</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC៖</translation>
+<translation id="6300452962057769623">{0,plural, =0{ឧបករណáŸážšáž”ស់អ្នកនឹងចាប់ផ្ដើមឡើងវិញឥឡូវនáŸáŸ‡}=1{ឧបករណáŸážšáž”ស់អ្នកនឹងចាប់ផ្ដើមឡើងវិញក្នុងរយៈពáŸáž› 1 វិនាទីទៀáž}other{ឧបករណáŸážšáž”ស់អ្នកនឹងចាប់ផ្ដើមឡើងវិញក្នុងរយៈពáŸáž› # វិនាទីទៀáž}}</translation>
<translation id="6302269476990306341">ការបញ្ឈប់ Google ជំនួយការនៅក្នុង Chrome</translation>
<translation id="6305205051461490394"><ph name="URL" /> មិនអាចភ្ជាប់បានទáŸ</translation>
<translation id="6312113039770857350">áž‚áŸáž áž‘ំពáŸážšáž˜áž·áž“អាចប្រើបានទáŸ</translation>
@@ -1730,6 +1770,7 @@
<translation id="6529602333819889595">ធ្វើការលុបវិញ</translation>
<translation id="6545864417968258051">ការស្កáŸáž“ប៊្លូធូស</translation>
<translation id="6547208576736763147">ចោះ​ពីររន្ធ​ážáž¶áž„ឆ្វáŸáž„</translation>
+<translation id="6554732001434021288">បានចូលមើល​លើកចុងក្រោយ​កាលពី <ph name="NUM_DAYS" /> ážáŸ’ងៃមុន</translation>
<translation id="6556866813142980365">ធ្វើវិញ</translation>
<translation id="6569060085658103619">អ្នក​កំពុងមើល​ទំពáŸážšâ€‹áž€áž˜áŸ’មវិធី​បន្ážáŸ‚ម</translation>
<translation id="6573200754375280815">ចោះ​ពីររន្ធ​ážáž¶áž„ស្ដាំ</translation>
@@ -1790,7 +1831,6 @@
<translation id="6757797048963528358">ឧបករណáŸážšáž”ស់អ្នកបានដáŸáž€áž áž¾áž™</translation>
<translation id="6767985426384634228">ធ្វើបច្ចុប្បន្នភាព​អាសយដ្ឋាន​ឬ?</translation>
<translation id="6768213884286397650">Hagaki (បណ្ណប្រៃសណីយáŸ)</translation>
-<translation id="6774185088257932239"><ph name="BEGIN_LINK" />ស្វែងយល់​បន្ážáŸ‚ម<ph name="END_LINK" />អំពី​មុážáž„ារ​ឯកជន</translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">ស្វាយ</translation>
<translation id="6786747875388722282">កម្មវិធីបន្ážáŸ‚ម</translation>
@@ -1874,7 +1914,6 @@
<translation id="706295145388601875">បញ្ចូល និងគ្រប់គ្រងអាសយដ្ឋាននៅក្នុងការកំណážáŸ‹ Chrome</translation>
<translation id="7064851114919012435">áž–áŸážáŸŒáž˜áž¶áž“ទំនាក់ទំនង</translation>
<translation id="7068733155164172741">បញ្ចូលលáŸážáž€áž¼ážŠ <ph name="OTP_LENGTH" /> ážáŸ’ទង់</translation>
-<translation id="7070090581017165256">អំពីគáŸáž áž‘ំពáŸážšáž“áŸáŸ‡</translation>
<translation id="70705239631109039">ការážáž—្ជាប់របស់អ្នក​មិនមានសុវážáŸ’ážáž·áž—ាពពáŸáž‰áž›áŸáž‰áž‘áŸ</translation>
<translation id="7075452647191940183">សំណើមាន​ទំហំធំពáŸáž€</translation>
<translation id="7079718277001814089">ទំពáŸážšáž“áŸáŸ‡áž˜áž¶áž“ផ្ទុកមáŸážšáŸ„áž‚</translation>
@@ -1891,6 +1930,12 @@
<translation id="7111012039238467737">(មាន​សុពល​ភាព)</translation>
<translation id="7118618213916969306">ស្វែងរក URL ឃ្លីបបáž, <ph name="SHORT_URL" /></translation>
<translation id="7119414471315195487">បិទផ្ទាំង ឬកម្មវិធីផ្សáŸáž„ទៀáž</translation>
+<translation id="7129355289156517987">នៅពáŸáž›áž¢áŸ’នកបិទផ្ទាំងឯកជន Chromium ទាំងអស់ សកម្មភាពរបស់អ្នកនៅក្នុងផ្ទាំងទាំងនោះážáŸ’រូវបានសម្អាážáž…áŸáž‰áž–ីឧបករណáŸáž“áŸáŸ‡áŸ–
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />សកម្មភាព​រុករក​ážáž¶áž˜áž¢áŸŠáž¸áž“ធឺណិáž<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ប្រវážáŸ’ážáž·â€‹ážŸáŸ’វែងរក<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />áž–áŸážáŸŒáž˜áž¶áž“ដែលបានបញ្ចូលក្នុងទម្រង់បែបបទ<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">មិនអាចដឹកជញ្ជូនážáž¶áž˜áž”្រៃសណីយáŸáž‘ៅអាសយដ្ឋាននáŸáŸ‡áž”ានទáŸáŸ” សូមជ្រើសរើសអាសយដ្ឋានផ្សáŸáž„។</translation>
<translation id="7132939140423847331">អ្នកគ្រប់គ្រង​របស់អ្នក​បានហាមឃាážáŸ‹â€‹áž˜áž·áž“ឱ្យ​ចម្លងទិន្ននáŸáž™áž“áŸáŸ‡áŸ”</translation>
<translation id="7135130955892390533">បង្ហាញ​ស្ážáž¶áž“ភាព</translation>
@@ -1913,6 +1958,7 @@
<translation id="7192203810768312527">បង្កើន​ទំហំផ្ទុក <ph name="SIZE" /> ។ ទំពáŸážšâ€‹áž˜áž½áž™áž…ំនួន​អាចផ្ទុកយឺážáž‡áž¶áž„មុន នៅពáŸáž›ážŠáŸ‚លអ្នកចូលលើកក្រោយ។</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">អ្នកគ្រប់គ្រង​របស់អ្នកអាច​មើលឃើញ៖</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, ចុច "Tab" រួចចុច "Enter" ដើម្បីបើក​ផ្ទាំងឯកជនážáŸ’មី ដើម្បីរុករកជាលក្ážážŽáŸˆáž¯áž€áž‡áž“</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> មិនážáŸ’រូវážáž¶áž˜áž”ទដ្ឋានសុវážáŸ’ážáž·áž—ាពទáŸ</translation>
<translation id="7210993021468939304">សកម្មភាព Linux នៅក្នុង​ទម្រង់ផ្ទុក និងអាចដំឡើង និងដំណើរការ​កម្មវិធី Linux នៅក្នុងទម្រង់ផ្ទុក</translation>
@@ -1944,6 +1990,7 @@
<translation id="7304562222803846232">គ្រប់គ្រង​ការកំណážáŸ‹â€‹áž¯áž€áž‡áž“ភាព​គណនី Google</translation>
<translation id="7305756307268530424">ចាប់ផ្ដើម​ក្នុងល្បឿន​កាន់ážáŸ‚យឺáž</translation>
<translation id="7308436126008021607">សមកាលកម្ម​ផ្ទៃážáž¶áž„ក្រោយ</translation>
+<translation id="7310392214323165548">ឧបករណáŸáž“ឹងចាប់ផ្ដើមឡើងវិញឆាប់ៗនáŸáŸ‡</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">ជំនួយ​ការážáž—្ជាប់</translation>
<translation id="7323804146520582233">លាក់​ផ្នែក "<ph name="SECTION" />"</translation>
@@ -1951,6 +1998,7 @@
<translation id="7334320624316649418">ធ្វើការážáž˜áŸ’រៀបឡើងវិញ</translation>
<translation id="7335157162773372339">អាច​ស្នើសុំប្រើ​កាមáŸážšáŸ‰áž¶â€‹ážšáž”ស់អ្នក</translation>
<translation id="7337248890521463931">បង្ហាញបន្ទាážáŸ‹áž…្រើនជាងនáŸáŸ‡</translation>
+<translation id="7337418456231055214">មិនបាន​បំពáŸáž‰â€‹áž›áŸážáž€áž¶ážâ€‹áž“ិម្មិážáž˜áŸ‚áž“áž‘áŸ? សូមចុច​ពáŸážáŸŒáž˜áž¶áž“លម្អិážâ€‹áž¢áŸ†áž–ីកាហដើម្បីចម្លង។ <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">មិនមាន​នៅលើ​ប្រពáŸáž“្ធ​របស់អ្នក​ទáŸáŸ”</translation>
<translation id="733923710415886693">វិញ្ញាបនបážáŸ’រម៉ាស៊ីនមáŸáž˜áž·áž“ážáŸ’រូវបានបង្ហាញឲ្យដឹងážáž¶áž˜ážšáž™áŸˆáž‚ោលការណáŸážáž˜áŸ’លាភាពវិញ្ញាបនបážáŸ’រ។</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1973,6 +2021,7 @@
<translation id="7378627244592794276">áž‘áŸ</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">មិនអាច​អនុវážáŸ’ážáž”ាន</translation>
+<translation id="7388594495505979117">{0,plural, =1{ឧបករណáŸážšáž”ស់អ្នកនឹងចាប់ផ្ដើមឡើងវិញក្នុងរយៈពáŸáž› 1 នាទីទៀáž}other{ឧបករណáŸážšáž”ស់អ្នកនឹងចាប់ផ្ដើមឡើងវិញក្នុងរយៈពáŸáž› # នាទីទៀáž}}</translation>
<translation id="7390545607259442187">បញ្ជាក់កាáž</translation>
<translation id="7392089738299859607">ធ្វើ​បច្ចុប្បន្នភាព​អាសយដ្ឋាន​</translation>
<translation id="7399802613464275309">ការពិនិážáŸ’យ​សុវážáŸ’ážáž·áž—ាព</translation>
@@ -2009,6 +2058,12 @@
<translation id="7485870689360869515">គ្មានទិន្ននáŸáž™ážáŸ’រូវបានរកឃើញទáŸáŸ”</translation>
<translation id="7495528107193238112">ážáŸ’លឹមសារ​នáŸáŸ‡â€‹ážáŸ’រូវបាន​ទប់ស្កាážáŸ‹â€‹áŸ” សូមទាក់ទង​ម្ចាស់​គáŸáž áž‘ំពáŸážš ដើម្បី​ដោះស្រាយ​បញ្ហានáŸáŸ‡â€‹áŸ”</translation>
<translation id="7497998058912824456">ប៊ូážáž»áž„​បង្កើážáž¯áž€ážŸáž¶ážš ចុច Enter ដើម្បីបង្កើážâ€‹áž¯áž€ážŸáž¶ážš Google ážáŸ’មីបានរហáŸážŸ</translation>
+<translation id="7506488012654002225">Chromium <ph name="BEGIN_EMPHASIS" />នឹងមិនរក្សាទុក<ph name="END_EMPHASIS" />áž–áŸážáŸŒáž˜áž¶áž“ážáž¶áž„ក្រោមទáŸáŸ–
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ប្រវážáŸ’ážáž·ážšáž»áž€ážšáž€ážšáž”ស់អ្នក
+ <ph name="LIST_ITEM" />ážáž¼áž‚ី និងទិន្ននáŸáž™áž‘ំពáŸážš
+ <ph name="LIST_ITEM" />áž–áŸážáŸŒáž˜áž¶áž“ដែលបានបញ្ចូលក្នុងទម្រង់បែបបទ
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">áž›áŸážážŸáž˜áŸ’គាល់ឧបករណáŸáž‚ោលការណáŸáž”្រគល់ážáŸ’រឡប់វិញគឺទទ០ឬមិនážáŸ’រូវគ្នាជាមួយលáŸážážŸáž˜áŸ’គាល់ឧបករណáŸáž”ច្ចុប្បន្ន</translation>
<translation id="7508870219247277067">បៃážáž„ážáŸ’ចី</translation>
<translation id="7511955381719512146">Wi-Fi ដែលអ្នកកំពុងប្រើអាចážáž˜áŸ’រូវឲ្យអ្នកទៅកាន់ <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />។</translation>
@@ -2123,7 +2178,6 @@
<translation id="7813600968533626083">យកការណែនាំលើបែបបទចáŸáž‰áž–ី Chrome?</translation>
<translation id="781440967107097262">ចែករំលែកឃ្លីបបážáž¬?</translation>
<translation id="7815407501681723534">បានរកឃើញ <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> សម្រាប់ '<ph name="SEARCH_STRING" />'</translation>
-<translation id="782125616001965242">បង្ហាញពáŸážáŸŒáž˜áž¶áž“អំពីគáŸáž áž‘ំពáŸážšáž“áŸáŸ‡</translation>
<translation id="782886543891417279">Wi-Fi ដែលអ្នកកំពុងប្រើ (<ph name="WIFI_NAME" />) អាចážáž˜áŸ’រូវឲ្យអ្នកទៅកាន់ទំពáŸážšáž…ុះឈ្មោះរបស់វា។</translation>
<translation id="7836231406687464395">Postfix (ស្រោម​សំបុážáŸ’ážš)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{គ្មាន}=1{កម្មវិធី 1 (<ph name="EXAMPLE_APP_1" />)}=2{កម្មវិធី 2 (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}other{កម្មវិធី # (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}}</translation>
@@ -2140,7 +2194,6 @@
<translation id="7888575728750733395">áž…áŸážáž“ានៃ​ការបំប្លែង​ការបោះពុម្ព</translation>
<translation id="7894280532028510793">ប្រសិនបើ​អក្ážážšáž¶ážœáž·ážšáž»áž‘្ធគឺážáŸ’រឹមážáŸ’រូវ <ph name="BEGIN_LINK" />សូមសាកល្បង​ដំណើរការ​ការវិភាគបណ្ដាញ<ph name="END_LINK" />។</translation>
<translation id="7904208859782148177">C3 (ស្រោម​សំបុážáŸ’ážš)</translation>
-<translation id="7931318309563332511">មិនស្គាល់</translation>
<translation id="793209273132572360">ធ្វើបច្ចុប្បន្នភាព​អាសយដ្ឋាន​ដែរទ�</translation>
<translation id="7932579305932748336">ស្រោប</translation>
<translation id="79338296614623784">បញ្ចូលលáŸážáž‘ូរសព្ទដែលážáŸ’រឹមážáŸ’រូវ</translation>
@@ -2165,14 +2218,15 @@
<translation id="7976214039405368314">សំណើច្រើនពáŸáž€</translation>
<translation id="7977538094055660992">ឧបករណáŸáž“ៃធាážáž»áž”ញ្ចáŸáž‰</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">ភ្ជាប់​ជាមួយ</translation>
<translation id="798134797138789862">អាចស្នើសុំ​ប្រើទិន្ននáŸáž™ និងឧបករណ០VR</translation>
<translation id="7984945080620862648">អ្នកមិនអាចទៅកាន់ <ph name="SITE" /> ឥឡូវនáŸáŸ‡áž‘០ពីព្រោះគáŸáž áž‘ំពáŸážšážšáž”ស់អ្នកបានផ្ញើអážáŸ’ážážŸáž‰áŸ’ញាណសម្គាល់រញáŸážšáž‰áŸƒážŠáŸ‚áž› Chrome មិនអាចដំណើរការបាន។ ជាធម្មážáž¶áž€áŸ†áž áž»ážŸáž†áŸ’គងបណ្ážáž¶áž‰
និងការវាយប្រហារជារឿងបណ្ណោះអាសន្ន ដូច្នáŸáŸ‡áž‘ំពáŸážšáž“áŸáŸ‡áž“ឹងអាចដំណើរពáŸáž›áž€áŸ’រោយ។</translation>
-<translation id="79859296434321399">ដើម្បី​មើលážáŸ’លឹមសារ AR សូមដំឡើង ARCore</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">ភ្ជាប់</translation>
<translation id="7992044431894087211">ការបង្ហាញអáŸáž€áŸ’រង់​ជាមួយ <ph name="APPLICATION_TITLE" /> ážáŸ’រូវបានបន្áž</translation>
<translation id="7995512525968007366">មិនបានបញ្ជាក់</translation>
+<translation id="7998269595945679889">បើកប៊ូážáž»áž„ផ្ទាំងឯកជន រួចចុច "Enter" ដើម្បីបើកផ្ទាំងឯកជនážáŸ’មី ដើម្បីរុករកជាលក្ážážŽáŸˆáž¯áž€áž‡áž“</translation>
<translation id="800218591365569300">សាកល្បងបិទផ្ទាំង ឬកម្មវិធីផ្សáŸáž„ទៀហដើម្បីបង្កើនទំហំអង្គចងចាំ។</translation>
<translation id="8004582292198964060">កម្មវិធីរុករក</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{បណ្ណនáŸáŸ‡ និងអាសយដ្ឋានចáŸáž‰â€‹ážœáž·áž€áŸ’កយបážáŸ’ážážšáž”ស់វានឹងážáŸ’រូវ​បានរក្សាទុក។ អ្នកនឹង​អាចប្រើបណ្ណនáŸáŸ‡ នៅពáŸáž›â€‹áž…ូលគណនី <ph name="USER_EMAIL" /> ។}other{បណ្ណ​ទាំងនáŸáŸ‡ និងអាសយដ្ឋាន​ចáŸáž‰ážœáž·áž€áŸ’កយបážáŸ’រ​របស់ពួកវានឹងážáŸ’រូវបានរក្សាទុក។ អ្នកនឹង​អាចប្រើបណ្ណទាំងនáŸáŸ‡ នៅពáŸáž›â€‹áž…ូលគណនី <ph name="USER_EMAIL" /> ។}}</translation>
@@ -2232,6 +2286,7 @@
<translation id="8202370299023114387">​ជាន់​គ្នា</translation>
<translation id="8206978196348664717">Prc4 (ស្រោម​សំបុážáŸ’ážš)</translation>
<translation id="8211406090763984747">ការážáž—្ជាប់មានសុវážáŸ’ážáž·áž—ាព</translation>
+<translation id="8217240300496046857">áž‚áŸáž áž‘ំពáŸážšâ€‹áž˜áž·áž“​អាចប្រើ​ážáž¼áž‚ី ដែលážáž¶áž˜ážŠáž¶áž“​អ្នក​នៅលើអ៊ីនធឺណិážáž”ានទáŸáŸ” មុážáž„ារ​នៅលើ​គáŸáž áž‘ំពáŸážšâ€‹áž˜áž½áž™áž…ំនួន​អាចដំណើរការ​មិន​ážáŸ’រឹមážáŸ’រូវ។</translation>
<translation id="8218327578424803826">ទីážáž¶áŸ†áž„ដែលបានកំណážáŸ‹áŸ–</translation>
<translation id="8220146938470311105">C7/C6 (ស្រោម​សំបុážáŸ’ážš)</translation>
<translation id="8225771182978767009">អ្នកដែលដំឡើងកុំព្យូទáŸážšáž“áŸáŸ‡áž”ានជ្រើសយកការរារាំងគáŸáž áž‘ំពáŸážšáž“áŸáŸ‡</translation>
@@ -2272,14 +2327,9 @@
<translation id="830498451218851433">áž”ážáŸ‹â€‹áž–ាក់កណ្ដាល</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">កម្មវិធី​ដែលបានដំឡើង និងភាពញឹកញាប់​នៃការប្រើប្រាស់កម្មវិធីទាំងនោះ</translation>
+<translation id="8317207217658302555">ដំឡើងកំណែ ARCore ឬ?</translation>
<translation id="831997045666694187">ល្ងាច</translation>
<translation id="8321476692217554900">ការជូន​ដំណឹង</translation>
-<translation id="8328484624016508118">បន្ទាប់ពីបិទ​ផ្ទាំងឯកជន​ទាំងអស់ Chrome នឹងសម្អាážáŸ–
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />សកម្មភាព​រុករក​ážáž¶áž˜áž¢áŸŠáž¸áž“ធឺណិážâ€‹ážšáž”ស់អ្នកចáŸáž‰áž–ី​ឧបករណáŸáž“áŸáŸ‡<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />ប្រវážáŸ’ážáž·â€‹ážŸáŸ’វែងរករបស់អ្នកចáŸáž‰áž–ី​ឧបករណáŸáž“áŸáŸ‡<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />áž–áŸážáŸŒáž˜áž¶áž“ដែលបានបញ្ចូល​ក្នុងទម្រង់​បែបបទនានា<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489">បានបដិសáŸáž’ការចូលប្រើ <ph name="HOST_NAME" /></translation>
<translation id="833262891116910667">រំលáŸáž…</translation>
<translation id="8339163506404995330">ទំពáŸážšáž‡áž¶áž—ាសា <ph name="LANGUAGE" /> នឹងមិនážáŸ’រូវបានបកប្រែទáŸ</translation>
@@ -2331,6 +2381,7 @@
<translation id="8507227106804027148">ជួរពាក្យបញ្ជា</translation>
<translation id="8508648098325802031">រូប​ស្វែងរក</translation>
<translation id="8511402995811232419">គ្រប់គ្រងážáž¼áž‚ី</translation>
+<translation id="8519753333133776369">ឧបករណ០HID ážáŸ’រូវបានអនុញ្ញាážážŠáŸ„យអ្នកគ្រប់គ្រងរបស់អ្នក</translation>
<translation id="8522552481199248698">Chrome អាច​ជួយ​អ្នក​ក្នុងការការពារ​គណនី Google និង​ផ្លាស់ប្ដូរ​ពាក្យសម្ងាážáŸ‹â€‹ážšáž”ស់អ្នក​។</translation>
<translation id="8530813470445476232">សម្អាážáž”្រវážáŸ’ážáž·â€‹ážšáž»áž€ážšáž€â€‹ážáž¶áž˜áž¢áŸŠáž¸áž“ធឺណិហážáž¼áž‚ី ឃ្លាំងផ្ទុកទិន្ននáŸáž™ážšáž”ស់អ្នក និងអ្វីៗជាច្រើនទៀážâ€‹áž“ៅក្នុង​ការកំណážáŸ‹ Chrome</translation>
<translation id="8533619373899488139">សូមចូលទៅកាន់ &lt;strong&gt;chrome://policy&lt;/strong&gt; ដើម្បីមើល​បញ្ជី URL ដែលបាន​ទប់ស្កាážáŸ‹ និងគោលការណáŸâ€‹áž•áŸ’សáŸáž„ទៀហដែលបានអនុវážáŸ’ážâ€‹ážŠáŸ„យអ្នកគ្រប់គ្រងប្រពáŸáž“្ធ​របស់អ្នក។</translation>
@@ -2342,7 +2393,6 @@
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{កំណážáŸ‹áž€áž¶ážšáž¢áž“ុញ្ញាážáž¡áž¾áž„វិញ}other{កំណážáŸ‹áž€áž¶ážšáž¢áž“ុញ្ញាážáž¡áž¾áž„វិញ}}</translation>
<translation id="8555010941760982128">ប្រើប្រាស់លáŸážâ€‹áž€áž¼ážŠâ€‹áž“áŸáŸ‡â€‹áž“ៅ​ពáŸáž›â€‹áž‚áž·ážâ€‹áž›áž»áž™</translation>
<translation id="8557066899867184262">CVC ស្ážáž·ážâ€‹áž“ៅក្រោយ​បណ្ណ​របស់អ្នក។</translation>
-<translation id="8558485628462305855">ដើម្បី​មើលážáŸ’លឹមសារ AR សូមដំឡើងជំនាន់ ARCore</translation>
<translation id="8559762987265718583">ការភ្ជាប់ឯកជនទៅ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> មិនអាចធ្វើឡើងទ០ពីព្រោះកាលបរិច្ឆáŸáž‘ និងម៉ោងឧបករណáŸážšáž”ស់អ្នក (<ph name="DATE_AND_TIME" />)មិនážáŸ’រឹមážáŸ’រូវ។</translation>
<translation id="8564182942834072828">ឯកសារ​ដាច់ដោយឡែក/ច្បាប់ចម្លង​ដាច់ដោយឡែក</translation>
<translation id="8564985650692024650">Chromium ណែនាំឱ្យ​កំណážáŸ‹â€‹áž–ាក្យសម្ងាážáŸ‹ <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> របស់អ្នក​ឡើងវិញ ប្រសិនបើ​អ្នកបាន​ប្រើ​វាម្ážáž„ទៀážâ€‹áž“ៅលើ​ទំពáŸážšáž•áŸ’សáŸáž„។</translation>
@@ -2361,6 +2411,7 @@
<translation id="865032292777205197">ឧបករណáŸâ€‹áž…ាប់ចលនា</translation>
<translation id="8663226718884576429">ការ​សង្ážáŸáž”​អំពី​ការបញ្ជាទិញ, <ph name="TOTAL_LABEL" />, áž–áŸážáŸŒáž˜áž¶áž“​លម្អិážâ€‹áž”ន្ážáŸ‚ម</translation>
<translation id="8666678546361132282">ភាសាអង់គ្លáŸážŸ</translation>
+<translation id="8669306706049782872">ប្រើពáŸážáŸŒáž˜áž¶áž“​អំពីអáŸáž€áŸ’រង់​របស់អ្នក​ដើម្បីបើក និងដាក់​វិនដូ</translation>
<translation id="867224526087042813">áž ážáŸ’ážáž›áŸážáž¶</translation>
<translation id="8676424191133491403">គ្មាន​ការ​ពន្យារពáŸáž›</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, ចមើ្លយ៖ <ph name="ANSWER" /></translation>
@@ -2387,6 +2438,7 @@
<translation id="8731544501227493793">ប៊ូážáž»áž„ "គ្រប់គ្រងពាក្យសម្ងាážáŸ‹" ចុច "Enter" ដើម្បីមើល និងគ្រប់គ្រងពាក្យសម្ងាážáŸ‹ážšáž”ស់អ្នកនៅក្នុងការកំណážáŸ‹ Chrome</translation>
<translation id="8734529307927223492"><ph name="DEVICE_TYPE" /> របស់​អ្នក​ស្ážáž·ážáž€áŸ’រោម​ការគ្រប់គ្រង​របស់ <ph name="MANAGER" /></translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, ចុច "Tab" រួចចុច "Enter" ដើម្បីបើក​ផ្ទាំងឯកជនážáŸ’មី ដើម្បីរុករកជាលក្ážážŽáŸˆáž¯áž€áž‡áž“</translation>
+<translation id="8737685506611670901">បើកážáŸ†ážŽ <ph name="PROTOCOL" /> ជំនួសឲ្យ <ph name="REPLACED_HANDLER_TITLE" /></translation>
<translation id="8738058698779197622">ដើម្បីបង្កើážáž€áž¶ážšáž—្ជាប់ដែលមានសុវážáŸ’ážáž·áž—ាព ម៉ោងរបស់អ្នកážáŸ’រូវបានážáŸ‚កំណážáŸ‹áž²áŸ’áž™ážáŸ’រឹមážáŸ’រូវ។ ដោយសារážáŸ‚វិញ្ញាបនបážáŸ’រដែលគáŸáž áž‘ំពáŸážšáž”្រើដើម្បីកំណážáŸ‹áž¢ážáŸ’ážážŸáž‰áŸ’ញាណážáŸ’លួនវាមានសុពលភាពážáŸ’រឹមចន្លោះរយៈពáŸáž›áž˜áž½áž™áž”៉ុណ្ណោះ។ ដោយសារážáŸ‚ម៉ោងឧបករណáŸážšáž”ស់អ្នកមិនážáŸ’រឹមážáŸ’រូវ Chromium មិនអាចផ្ទៀងផ្ទាážáŸ‹ážœáž·áž‰áŸ’ញាបនបážáŸ’រទាំងនáŸáŸ‡áž‘áŸáŸ”</translation>
<translation id="8740359287975076522">រកមិនឃើញអាសយដ្ឋាន &lt;abbr id="dnsDefinition"&gt;DNS របស់<ph name="HOST_NAME" />&lt;/abbr&gt; áž‘áŸáŸ” កំពុងវិភាគរកបញ្ហា។</translation>
<translation id="8742371904523228557"><ph name="ONE_TIME_CODE" /> គឺជាលáŸážáž€áž¼ážŠâ€‹ážšáž”ស់អ្នកសម្រាប់ <ph name="ORIGIN" /></translation>
@@ -2414,6 +2466,7 @@
<translation id="883848425547221593">ចំណាំផ្សáŸáž„ទៀáž</translation>
<translation id="884264119367021077">អាសយដ្ឋានដឹកជញ្ជូនទៅ</translation>
<translation id="884923133447025588">គ្មានយន្ážáž€áž¶ážšáž€áž¶ážšáž”ញ្ឈប់សុពលភាពážáŸ’រូវបានរកឃើញទáŸáŸ”</translation>
+<translation id="8849262850971482943">ប្រើកាážáž“ិម្មិážážšáž”ស់អ្នក ដើម្បីទទួលបានសុវážáŸ’ážáž·áž—ាពបន្ážáŸ‚ម</translation>
<translation id="885730110891505394">ការចែករំលែកជាមួយ Google</translation>
<translation id="8858065207712248076">Chrome ណែនាំឱ្យ​កំណážáŸ‹â€‹áž–ាក្យសម្ងាážáŸ‹ <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> របស់អ្នក​ឡើងវិញ ប្រសិនបើ​អ្នកបាន​ប្រើ​វា​ម្ážáž„ទៀážâ€‹áž“ៅលើ​ទំពáŸážšáž•áŸ’សáŸáž„។</translation>
<translation id="885906927438988819">ប្រសិនបើ​អក្ážážšáž¶ážœáž·ážšáž»áž‘្ធគឺážáŸ’រឹមážáŸ’រូវ <ph name="BEGIN_LINK" />សូមសាកល្បង​ដំណើរការ​ការវិភាគបណ្ដាញ Windows<ph name="END_LINK" />។</translation>
@@ -2463,6 +2516,7 @@
<translation id="9004367719664099443">VR កំពុង​ដំណើរការ</translation>
<translation id="9005998258318286617">មិនអាចផ្ទុកឯកសារ PDF បានទáŸáŸ”</translation>
<translation id="9008201768610948239">មិនអើពើ</translation>
+<translation id="901834265349196618">អ៊ីម៉ែល</translation>
<translation id="9020200922353704812">ážáž˜áŸ’រូវ​ឲ្យមាន​អាសយដ្ឋាន​ចáŸáž‰ážœáž·áž€áŸ’កយបážáŸ’រសម្រាប់បណ្ណ</translation>
<translation id="9020542370529661692">áž‚áŸáž áž‘ំពáŸážšáž“áŸáŸ‡ážáŸ’រូវបានបកប្រែទៅ <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9020742383383852663">A8</translation>
@@ -2511,6 +2565,7 @@
<translation id="9150045010208374699">ប្រើកាមáŸážšáŸ‰áž¶ážšáž”ស់អ្នក</translation>
<translation id="9150685862434908345">អ្នកគ្រប់គ្រង​របស់អ្នក​អាចប្ដូរ​ការរៀបចំ​កម្មវិធីរុករកážáž¶áž˜áž¢áŸŠáž¸áž“ធឺណិážâ€‹ážšáž”ស់អ្នក​ពីចម្ងាយបាន។ សកម្មភាព​នៅលើឧបករណáŸáž“áŸáŸ‡â€‹áž€áŸáž¢áž¶áž…ážáŸ’រូវបាន​គ្រប់គ្រងក្រៅពី Chrome ផងដែរ។ <ph name="BEGIN_LINK" />ស្វែងយល់បន្ážáŸ‚ម<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">បានធ្វើបច្ចុប្បន្នភាព</translation>
+<translation id="9155211586651734179">បានភ្ជាប់ឧបករណáŸážŸáŸ†áž¡áŸáž„ážáž¶áž„ក្រៅ</translation>
<translation id="9157595877708044936">កំពុងážáŸ†áž¡áž¾áž„...</translation>
<translation id="9158625974267017556">C6 (ស្រោម​សំបុážáŸ’ážš)</translation>
<translation id="9164029392738894042">ការពិនិážáŸ’យមើល​ភាពážáŸ’រឹមážáŸ’រូវ</translation>
diff --git a/chromium/components/strings/components_strings_kn.xtb b/chromium/components/strings/components_strings_kn.xtb
index da418c9758e..eeed6df396d 100644
--- a/chromium/components/strings/components_strings_kn.xtb
+++ b/chromium/components/strings/components_strings_kn.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">ವಿವರಗಳನà³à²¨à³ ನೋಡಿ</translation>
<translation id="1030706264415084469">ನಿಮà³à²® ಸಾಧನದಲà³à²²à²¿ ದೊಡà³à²¡ ಪà³à²°à²®à²¾à²£à²¦ ಡೇಟಾವನà³à²¨à³ ಶಾಶà³à²µà²¤à²µà²¾à²—ಿ ಸಂಗà³à²°à²¹à²£à³† ಮಾಡಲೠ<ph name="URL" /> ಬಯಸà³à²¤à³à²¤à²¦à³†</translation>
<translation id="1032854598605920125">ಪà³à²°à²¦à²•à³à²·à²¿à²£à²¾à²•à²¾à²°à²¦à²²à³à²²à²¿ ತಿರà³à²—ಿಸà³</translation>
+<translation id="1033329911862281889">ಅದೃಶà³à²¯ ಮೋಡೠನೀವೠಆನà³â€Œà²²à³ˆà²¨à³â€Œà²¨à²²à³à²²à²¿ ಅಗೋಚರವಾಗಿರà³à²µà²‚ತೆ ಮಾಡà³à²µà³à²¦à²¿à²²à³à²²:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ಸೈಟà³â€Œà²—ಳಿಗೆ ಭೇಟಿ ನೀಡà³à²µà²µà²°à³ ಮತà³à²¤à³ ಅವರೠಬಳಸà³à²µ ಸೇವೆಗಳನà³à²¨à³ ವೀಕà³à²·à²¿à²¸à²¬à²¹à³à²¦à³<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ಉದà³à²¯à³‹à²—ದಾತರೠಅಥವಾ ಶಾಲೆಗಳೠಬà³à²°à³Œà²¸à²¿à²‚ಗೠಚಟà³à²µà²Ÿà²¿à²•à³†à²¯à²¨à³à²¨à³ ಟà³à²°à³à²¯à²¾à²•à³ ಮಾಡಬಹà³à²¦à³<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ಇಂಟರà³à²¨à³†à²Ÿà³ ಸೇವೆ ಒದಗಿಸà³à²µà²µà²°à³ ವೆಬೠಟà³à²°à²¾à²«à²¿à²•à³ ಅನà³à²¨à³ ಮೇಲà³à²µà²¿à²šà²¾à²°à²£à³† ಮಾಡಬಹà³à²¦à³<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">ಆಫೠಮಾಡà³</translation>
<translation id="1036982837258183574">ಪೂರà³à²£à²ªà²°à²¦à³†à²¯à²¿à²‚ದ ನಿರà³à²—ಮಿಸಲೠ|<ph name="ACCELERATOR" />| ಒತà³à²¤à²¿à²°à²¿</translation>
<translation id="1038106730571050514">ಸಲಹೆಗಳನà³à²¨à³ ತೋರಿಸಿ</translation>
<translation id="1038842779957582377">ಆಜà³à²žà²¾à²¤ ಹೆಸರà³</translation>
<translation id="1041998700806130099">ಜಾಬೠಶೀಟೠಸಂದೇಶ</translation>
<translation id="1048785276086539861">ನೀವೠಟಿಪà³à²ªà²£à²¿à²—ಳನà³à²¨à³ ಎಡಿಟೠಮಾಡಿದಾಗ, ಈ ಡಾಕà³à²¯à³à²®à³†à²‚ಟೠಒಂದೇ ಪà³à²Ÿà²¦ ವೀಕà³à²·à²£à³†à²—ೆ ಹಿಂತಿರà³à²—à³à²¤à³à²¤à²¦à³†</translation>
-<translation id="1049743911850919806">ಅದೃಶà³à²¯</translation>
<translation id="1050038467049342496">ಇತರ ಅಪà³à²²à²¿à²•à³‡à²¶à²¨à³â€à²—ಳನà³à²¨à³ ಮà³à²šà³à²šà²¿</translation>
<translation id="1055184225775184556">&amp;ಸೇರಿಸà³à²µà³à²¦à²¨à³à²¨à³ ರದà³à²¦à³à²—ೊಳಿಸಿ</translation>
<translation id="1056898198331236512">ಎಚà³à²šà²°à²¿à²•à³†</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">ನೀತಿಯ ಕà³à²¯à²¾à²·à³ ಸರಿಯಾಗಿದೆ</translation>
<translation id="1130564665089811311">ಪà³à²Ÿ ಅನà³à²µà²¾à²¦à²¿à²¸à²¿ ಬಟನà³, ಈ ಪà³à²Ÿà²µà²¨à³à²¨à³ Google Translate ನೊಂದಿಗೆ ಅನà³à²µà²¾à²¦à²¿à²¸à²²à³ Enter ಒತà³à²¤à²¿à²°à²¿</translation>
<translation id="1131264053432022307">ನೀವೠನಕಲಿಸಿದ ಚಿತà³à²°</translation>
+<translation id="1142846828089312304">ಅದೃಶà³à²¯ ಮೋಡà³â€Œà²¨à²²à³à²²à²¿ ಥರà³à²¡à³-ಪಾರà³à²Ÿà²¿ ಕà³à²•à³€à²—ಳನà³à²¨à³ ನಿರà³à²¬à²‚ಧಿಸಿ</translation>
<translation id="1150979032973867961">ಈ ಸರà³à²µà²°à³ <ph name="DOMAIN" /> ಆಗಿದೆ ಎಂಬà³à²¦à²¨à³à²¨à³ ಸಾಬೀತà³à²ªà²¡à²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¾à²—ಲಿಲà³à²²; ಅದರ ಸà³à²°à²•à³à²·à²¤à²¾ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà³ ನಿಮà³à²® ಸಾಧನದ ಆಪರೇಟಿಂಗೠಸಿಸà³à²Ÿà²‚‌ ಪà³à²°à²•à²¾à²° ವಿಶà³à²µà²¾à²¸à²¾à²°à³à²¹à²µà²¾à²—ಿಲà³à²². ಇದೠತಪà³à²ªà³ ಕಾನà³à²«à²¿à²—ರೇಶನà³â€Œà²¨à²¿à²‚ದ ಅಥವಾ ಆಕà³à²°à²®à²£à²•à²¾à²°à²°à³ ನಿಮà³à²® ಸಂಪರà³à²•à²¦à²²à³à²²à²¿ ಒಳನà³à²¸à³à²³à²¿à²°à³à²µà³à²¦à²°à²¿à²‚ದ ಆಗಿರಬಹà³à²¦à³.</translation>
<translation id="1151972924205500581">ಪಾಸà³â€Œà²µà²°à³à²¡à³ ಅಗತà³à²¯à²µà²¿à²¦à³†</translation>
<translation id="1156303062776767266">ನೀವೠಸà³à²¥à²³à³€à²¯ ಅಥವಾ ಹಂಚಿದ ಫೈಲà³â€Œ ಅನà³à²¨à³ ವೀಕà³à²·à²¿à²¸à³à²¤à³à²¤à²¿à²¦à³à²¦à³€à²°à²¿</translation>
@@ -64,7 +70,6 @@
<translation id="1178581264944972037">ವಿರಾಮ</translation>
<translation id="1181037720776840403">ತೆಗೆದà³à²¹à²¾à²•à³</translation>
<translation id="1186201132766001848">ಪಾಸà³â€Œà²µà²°à³à²¡à³â€Œà²—ಳನà³à²¨à³ ಪರಿಶೀಲಿಸಿ</translation>
-<translation id="1195210374336998651">ಆà³à²¯à²ªà³ ಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳಿಗೆ ಹೋಗಿ</translation>
<translation id="1195558154361252544">ನೀವೠಅನà³à²®à²¤à²¿à²¸à²¿à²°à³à²µ ಸೈಟà³â€Œà²—ಳನà³à²¨à³ ಹೊರತà³à²ªà²¡à²¿à²¸à²¿, ಉಳಿದ ಎಲà³à²²à²¾ ಸೈಟà³â€Œà²—ಳಿಂದ ಬರà³à²µ ಅಧಿಸೂಚನೆಗಳನà³à²¨à³ ನಿರà³à²¬à²‚ಧಿಸಲಾಗಿದೆ</translation>
<translation id="1197088940767939838">ಕಿತà³à²¤à²³à³†</translation>
<translation id="1201402288615127009">ಮà³à²‚ದೆ</translation>
@@ -111,7 +116,7 @@
<translation id="1307966114820526988">ತೆಗೆದà³à²¹à²¾à²•à²²à²¾à²¦ ವೈಶಿಷà³à²Ÿà³à²¯à²—ಳà³</translation>
<translation id="1308113895091915999">ಕೊಡà³à²—ೆಯೠಲಭà³à²¯à²µà²¿à²¦à³†</translation>
<translation id="1312803275555673949">ಇದನà³à²¨à³ ಯಾವ ಪà³à²°à²¾à²µà³† ಬೆಂಬಲಿಸà³à²¤à³à²¤à²¦à³†?</translation>
-<translation id="131405271941274527">ನಿಮà³à²® ಫೋನೠಅನà³à²¨à³ NFC ಸಾಧನವೊಂದರ ಮೇಲೆ ನೀವೠಟà³à²¯à²¾à²ªà³ ಮಾಡಿದಾಗ, <ph name="URL" /> ಮಾಹಿತಿಯನà³à²¨à³ ಕಳà³à²¹à²¿à²¸à²²à³ ಮತà³à²¤à³ ಸà³à²µà³€à²•à²°à²¿à²¸à²²à³ ಬಯಸà³à²¤à³à²¤à²¦à³†</translation>
+<translation id="1314311879718644478">ಆಗà³â€Œà²®à³†à²‚ಟೆಡೠರಿಯಾಲಿಟಿ ವಿಷಯವನà³à²¨à³ ವೀಕà³à²·à²¿à²¸à²¿</translation>
<translation id="1314509827145471431">ಬಲಗಡೆ ಬೈಂಡೠಮಾಡಿ</translation>
<translation id="1318023360584041678">ಟà³à²¯à²¾à²¬à³ ಗà³à²°à³‚ಪà³â€Œà²¨à²²à³à²²à²¿ ಉಳಿಸಲಾಗಿದೆ</translation>
<translation id="1319245136674974084">ಈ ಆà³à²¯à²ªà³â€Œà²—ಾಗಿ ಪà³à²¨à²ƒ ಕೇಳಬೇಡಿ</translation>
@@ -161,6 +166,7 @@
<translation id="142858679511221695">ಕà³à²²à³Œà²¡à³ ಬಳಕೆದಾರರà³</translation>
<translation id="1428729058023778569">ಈ ಸೈಟೠHTTPS ಅನà³à²¨à³ ಬೆಂಬಲಿಸದ ಕಾರಣ, ನೀವೠಈ ಎಚà³à²šà²°à²¿à²•à³†à²¯à²¨à³à²¨à³ ನೋಡà³à²¤à³à²¤à²¿à²¦à³à²¦à³€à²°à²¿. <ph name="BEGIN_LEARN_MORE_LINK" />ಇನà³à²¨à²·à³à²Ÿà³ ತಿಳಿಯಿರಿ<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">ಮà³à²¦à³à²°à²¿à²¸à³</translation>
+<translation id="1432187715652018471">ಈ ಪà³à²Ÿ ಸೇವೆಯ ನಿರà³à²µà²¾à²¹à²•à²µà²¨à³à²¨à³ ಸೇರಿಸಲೠಬಯಸà³à²¤à³à²¤à²¿à²¦à³†.</translation>
<translation id="1432581352905426595">ಹà³à²¡à³à²•à²¾à²Ÿà²¦ ಇಂಜಿನà³â€Œà²—ಳನà³à²¨à³ ನಿರà³à²µà²¹à²¿à²¸à²¿</translation>
<translation id="1436185428532214179">ನಿಮà³à²® ಸಾಧನದಲà³à²²à²¿à²¨ ಫೈಲà³â€Œà²—ಳೠಮತà³à²¤à³ ಫೋಲà³à²¡à²°à³â€Œà²—ಳನà³à²¨à³ ಎಡಿಟೠಮಾಡಲೠಕೇಳಬಹà³à²¦à³</translation>
<translation id="1442386063175183758">ಬಲಭಾಗದ ಗೇಟೠಅನà³à²¨à³ ಮಡಿಸಿ</translation>
@@ -181,6 +187,12 @@
<translation id="1483493594462132177">ಕಳà³à²¹à²¿à²¸à³</translation>
<translation id="1484290072879560759">ಶಿಪà³à²ªà²¿à²‚ಗೠವಿಳಾಸವನà³à²¨à³ ಆರಿಸಿ</translation>
<translation id="1492194039220927094">ಕಾರà³à²¯à²¨à³€à²¤à²¿à²—ಳನà³à²¨à³ ಪà³à²¶à³ ಮಾಡà³à²µ ಕà³à²°à²¿à²¯à³†:</translation>
+<translation id="149293076951187737">ನೀವೠಎಲà³à²²à²¾ Chrome ಅದೃಶà³à²¯ ಟà³à²¯à²¾à²¬à³â€Œà²—ಳನà³à²¨à³ ಮà³à²šà³à²šà²¿à²¦ ನಂತರ, ಆ ಟà³à²¯à²¾à²¬à³â€Œà²—ಳಲà³à²²à²¿à²¨ ನಿಮà³à²® ಚಟà³à²µà²Ÿà²¿à²•à³†à²¯à²¨à³à²¨à³ ಈ ಸಾಧನದಿಂದ ತೆರವà³à²—ೊಳಿಸಲಾಗà³à²¤à³à²¤à²¦à³†:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ಬà³à²°à³Œà²¸à²¿à²‚ಗೠಚಟà³à²µà²Ÿà²¿à²•à³†<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ಹà³à²¡à³à²•à²¾à²Ÿà²¦ ಇತಿಹಾಸ<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ಫಾರà³à²®à³â€Œà²—ಳಲà³à²²à²¿ ನಮೂದಿಸಿದ ಮಾಹಿತಿ<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">ಟà³à²¯à²¾à²¬à³â€Œà²—ೆ ಮರಳಿ</translation>
<translation id="1501859676467574491">ನಿಮà³à²® Google ಖಾತೆಯಲà³à²²à²¿à²°à³à²µ ಕಾರà³à²¡à³â€Œà²—ಳನà³à²¨à³ ತೋರಿಸಿ</translation>
<translation id="1507202001669085618">&lt;p&gt;ನೀವೠಆನà³â€Œà²²à³ˆà²¨à³ ಪà³à²°à²µà³‡à²¶à²¿à²¸à³à²µ ಮೊದಲೠಸೈನà³â€Œ ಇನà³â€Œ ಮಾಡಬೇಕಾದ ವೈ-ಫೈ ಪೋರà³à²Ÿà²²à³ ಅನà³à²¨à³ ಬಳಸà³à²¤à³à²¤à²¿à²¦à³à²¦à²°à³† ಈ ದೋಷವನà³à²¨à³ ಕಾಣà³à²¤à³à²¤à³€à²°à²¿.&lt;/p&gt; &lt;p&gt;ನೀವೠತೆರೆಯಲೠಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à³à²¤à³à²¤à²¿à²°à³à²µ ಪà³à²Ÿà²¦à²²à³à²²à²¿ ದೋಷವನà³à²¨à³ ಸರಿಪಡಿಸಲೠ&lt;strong&gt;ಸಂಪರà³à²•à²¿à²¸à²¿&lt;/strong&gt; ಅನà³à²¨à³ ಕà³à²²à²¿à²•à³â€Œ ಮಾಡಿ.&lt;/p&gt;</translation>
@@ -207,6 +219,8 @@
<translation id="1559572115229829303">&lt;p&gt;ನಿಮà³à²® ಸಾಧನದ ದಿನಾಂಕ ಮತà³à²¤à³ ಸಮಯ (<ph name="DATE_AND_TIME" />) ತಪà³à²ªà²¾à²—ಿರà³à²µ ಕಾರಣ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> ಗೆ ಖಾಸಗಿ ಸಂಪರà³à²•à²µà²¨à³à²¨à³ ಸà³à²¥à²¾à²ªà²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¾à²—à³à²µà³à²¦à²¿à²²à³à²².&lt;/p&gt;
&lt;p&gt;ದಯವಿಟà³à²Ÿà³ ಅಪà³à²²à²¿à²•à³‡à²¶à²¨à³â€Œà²¨ &lt;strong&gt;ಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳà³&lt;/strong&gt; ವಿಭಾಗದ &lt;strong&gt;ಸಾಮಾನà³à²¯&lt;/strong&gt; ದಿಂದ ದಿನಾಂಕ ಮತà³à²¤à³ ಸಮಯವನà³à²¨à³ ಹೊಂದಿಸಿ.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">ನಿಮà³à²® ನಿರà³à²µà²¾à²¹à²•à²°à³ <ph name="DATE" /> ರಂದೠ<ph name="TIME" /> ಸಮಯಕà³à²•à³† ನಿಮà³à²® ಸಾಧನವನà³à²¨à³ ಮರà³à²ªà³à²°à²¾à²°à²‚ಭಿಸà³à²¤à³à²¤à²¾à²°à³†</translation>
+<translation id="156703335097561114">ವಿಳಾಸಗಳà³, ಇಂಟರೠಫೇಸೠಕಾನà³à²«à²¿à²—ರೇಶನೠಮತà³à²¤à³ ಕನೆಕà³à²·à²¨à³ ಗà³à²£à²®à²Ÿà³à²Ÿà²¦à²‚ತಹ ನೆಟà³â€Œà²µà²°à³à²•à²¿à²‚ಗೠಮಾಹಿತಿ</translation>
<translation id="1567040042588613346">ಈ ನೀತಿಯೠಉದà³à²¦à³‡à²¶à²¿à²¸à²¿à²¦à²‚ತೆ ಕಾರà³à²¯à²¨à²¿à²°à³à²µà²¹à²¿à²¸à³à²¤à³à²¤à²¿à²¦à³†, ಆದರೆ ಅದೇ ಮೌಲà³à²¯à²µà²¨à³à²¨à³ ಬೇರೆಡೆ ಹೊಂದಿಸಲಾಗಿದೆ ಮತà³à²¤à³ ಅದೠಈ ನೀತಿಯನà³à²¨à³ ರದà³à²¦à³à²—ೊಳಿಸà³à²¤à³à²¤à²¦à³†.</translation>
<translation id="1569487616857761740">ಅವಧಿ ಮà³à²—ಿಯà³à²µ ದಿನಾಂಕವನà³à²¨à³ ನಮೂದಿಸಿ</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -214,6 +228,7 @@
<translation id="1583429793053364125">ಈ ವೆಬà³â€Œà²ªà³à²Ÿà²µà²¨à³à²¨à³ ಪà³à²°à²¦à²°à³à²¶à²¿à²¸à³à²µà²¾à²— ಯಾವà³à²¦à³‹ ತಪà³à²ªà³ ಸಂಭವಿಸಿದೆ.</translation>
<translation id="1586541204584340881">ನೀವೠಯಾವ ವಿಸà³à²¤à²°à²£à³†à²—ಳನà³à²¨à³ ಇನà³â€Œà²¸à³à²Ÿà²¾à²²à³ ಮಾಡಿದà³à²¦à³€à²°à²¿</translation>
<translation id="1588438908519853928">ಸಾಮಾನà³à²¯</translation>
+<translation id="1589050138437146318">ARCore ಅನà³à²¨à³ ಇನà³â€Œà²¸à³à²Ÿà²¾à²²à³ ಮಾಡಬೇಕೆ?</translation>
<translation id="1592005682883173041">ಸà³à²¥à²³à³€à²¯ ಡೇಟಾ ಪà³à²°à²µà³‡à²¶</translation>
<translation id="1594030484168838125">ಆರಿಸಿ</translation>
<translation id="160851722280695521">Chrome ನಲà³à²²à²¿ Dino Run ಆಟವನà³à²¨à³ ಆಡಿ</translation>
@@ -281,6 +296,7 @@
ಸೆಟೠಮಾಡಿದೆ ಹಾಗೂ ತನà³à²¨ ಎಲà³à²²à²¾ ವಿನಂತಿಗಳಿಗೆ ಮೂಲ ಕಾರà³à²¯à²¨à³€à²¤à²¿à²¯à²¨à³à²¨à³ ಅನà³à²µà²¯à²¿à²¸à²²à³ ವಿನಂತಿಸಿದೆ. ಆದರೆ,
ಹೆಡರೠಫೈಲೠವಿರೂಪಗೊಂಡಿದೆ, <ph name="SITE" /> ಅನà³à²¨à³ ಪà³à²°à²µà³‡à²¶à²¿à²¸à²²à³ ನಿಮà³à²® ವಿನಂತಿಯನà³à²¨à³
ಬà³à²°à³Œà²¸à²°à³ ಪೂರೈಸದಂತೆ ತಡೆಯà³à²¤à³à²¤à²¦à³†. ಸೈಟà³â€Œ ಒಂದಕà³à²•à²¾à²—ಿ ಸà³à²°à²•à³à²·à²¤à³† ಮತà³à²¤à³ ಇತರ ಗà³à²£à²²à²•à³à²·à²£à²—ಳನà³à²¨à³ ಕಾನà³à²«à²¿à²—ರೠಮಾಡಲೠಸೈಟೠಆಪರೇಟರà³â€Œà²—ಳೠಮೂಲ ಕಾರà³à²¯à²¨à³€à²¤à²¿à²—ಳನà³à²¨à³ ಬಳಸಬಹà³à²¦à³.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Chromium ನಲà³à²²à²¿ ಅದೃಶà³à²¯ ಮೋಡೠಕà³à²°à²¿à²¤à³ ಇನà³à²¨à²·à³à²Ÿà³ ತಿಳಿಯಿರಿ<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">ನಿಮà³à²® ತೆರೆಯಲಾದ ಟà³à²¯à²¾à²¬à³â€Œà²—ಳೠಇಲà³à²²à²¿ ಗೋಚರಿಸà³à²¤à³à²¤à²¦à³†</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -408,6 +424,7 @@
<translation id="22081806969704220">ಟà³à²°à³‡ 3</translation>
<translation id="2212735316055980242">ನೀತಿ ಕಂಡೠಬಂದಿಲà³à²²</translation>
<translation id="2213606439339815911">ನಮೂದà³à²—ಳನà³à²¨à³ ಪಡೆಯಲಾಗà³à²¤à³à²¤à²¿à²¦à³†...</translation>
+<translation id="2213612003795704869">ಪà³à²Ÿà²µà²¨à³à²¨à³ ಪà³à²°à²¿à²‚ಟೠಮಾಡಲಾಗಿದೆ</translation>
<translation id="2215727959747642672">ಫೈಲೠಎಡಿಟೠಮಾಡà³à²µà²¿à²•à³†</translation>
<translation id="2218879909401188352">ದಾಳಿಕೋರರೠಪà³à²°à²¸à³à²¤à³à²¤ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ನಲà³à²²à²¿à²¦à³à²¦à²¾à²°à³† ಮತà³à²¤à³ ನಿಮà³à²® ಸಾಧನಕà³à²•à³† ಹಾನಿಯನà³à²¨à³à²‚ಟೠಮಾಡà³à²µ ಅಪಾಯಕಾರಿ ಅಪà³à²²à²¿à²•à³‡à²¶à²¨à³â€Œà²—ಳನà³à²¨à³ ಇನà³â€Œà²¸à³à²Ÿà²¾à²²à³ ಮಾಡಬಹà³à²¦à³, ನಿಮà³à²® ಮೊಬೈಲೠಬಿಲà³â€Œà²—ೆ ಮರೆಮಾಡಿದ ಶà³à²²à³à²•à²—ಳನà³à²¨à³ ಸೇರಿಸಬಹà³à²¦à³, ಅಥವಾ ನಿಮà³à²® ವೈಯಕà³à²¤à²¿à²• ಮಾಹಿತಿಯನà³à²¨à³ ಕದಿಯಬಹà³à²¦à³. <ph name="BEGIN_LEARN_MORE_LINK" />ಇನà³à²¨à²·à³à²Ÿà³ ತಿಳಿಯಿರಿ<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">ಇಂಟರà³à²¨à³†à²Ÿà³ ಇಲà³à²²</translation>
@@ -417,6 +434,7 @@
<translation id="2248949050832152960">WebAuthn ಬಳಸಿ</translation>
<translation id="2250931979407627383">ಎಡಭಾಗದ ಅಂಚನà³à²¨à³ ಹೊಲಿಯಿರಿ</translation>
<translation id="225207911366869382">ಈ ನೀತಿಗಾಗಿ ಈ ಮೌಲà³à²¯à²µà²¨à³à²¨à³ ಅಸಮà³à²®à²¤à²¿à²¸à²²à²¾à²—ಿದೆ.</translation>
+<translation id="2256115617011615191">ಈಗ ಮರà³à²ªà³à²°à²¾à²°à²‚ಭಿಸà³</translation>
<translation id="2258928405015593961">ಭವಿಷà³à²¯à²¦ ಅವಧಿ ಮà³à²—ಿಯà³à²µ ದಿನಾಂಕವನà³à²¨à³ ನಮೂದಿಸಿ ಮತà³à²¤à³ ಪà³à²¨à²ƒ ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿</translation>
<translation id="225943865679747347">ದೋಷ ಕೋಡà³: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">HTTP ದೋಷ</translation>
@@ -444,6 +462,7 @@
<translation id="2337852623177822836">ನಿಮà³à²® ನಿರà³à²µà²¾à²¹à²•à²¦à²¿à²‚ದ ಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳನà³à²¨à³ ನಿಯಂತà³à²°à²¿à²¸à²²à²¾à²—ಿದೆ</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> ಜೋಡಿಸಲೠಬಯಸà³à²¤à³à²¤à²¦à³†</translation>
<translation id="2346319942568447007">ನೀವೠನಕಲಿಸಿದ ಚಿತà³à²°</translation>
+<translation id="2350796302381711542"><ph name="REPLACED_HANDLER_TITLE" /> ನ ಬದಲಿಗೆ ಎಲà³à²²à²¾ <ph name="PROTOCOL" /> ಲಿಂಕà³â€Œà²—ಳನà³à²¨à³ ತೆರೆಯಲೠ<ph name="HANDLER_HOSTNAME" /> ಗೆ ಅನà³à²®à²¤à²¿à²¸à³à²µà³à²¦à³‡?</translation>
<translation id="2354001756790975382">ಇತರ ಬà³à²•à³â€Œà²®à²¾à²°à³à²•à³â€Œà²—ಳà³</translation>
<translation id="2354430244986887761">Google ಸà³à²°à²•à³à²·à²¿à²¤ ಬà³à²°à³Œà²¸à²¿à²‚ಗà³â€Œ ಇತà³à²¤à³€à²šà²¿à²—ೆ <ph name="SITE" /> ನಲà³à²²à²¿ <ph name="BEGIN_LINK" />ಹಾನಿಕಾರಕ ಪà³à²°à³‹à²—à³à²°à²¾à²‚ಗಳನà³à²¨à³ ಕಂಡà³à²¹à²¿à²¡à²¿à²¦à²¿à²¦à³†<ph name="END_LINK" />.</translation>
<translation id="2355395290879513365">ಈ ಸೈಟà³â€Œà²¨à²²à³à²²à²¿ ನೀವೠನೋಡà³à²¤à³à²¤à²¿à²°à³à²µ ಚಿತà³à²°à²—ಳನà³à²¨à³ ವೀಕà³à²·à²¿à²¸à²²à³ ಮತà³à²¤à³ ಅವà³à²—ಳನà³à²¨à³ ಮಾರà³à²ªà²¡à²¿à²¸à³à²µ ಮೂಲಕ ನಿಮà³à²®à²¨à³à²¨à³ ವಂಚಿಸಲೠದಾಳಿಕೋರರಿಗೆ ಸಾಧà³à²¯à²µà²¾à²—à³à²¤à³à²¤à²¿à²°à²¬à²¹à³à²¦à³.</translation>
@@ -469,6 +488,7 @@
<translation id="2413528052993050574">ಈ ಸರà³à²µà²°à³ <ph name="DOMAIN" /> ಆಗಿದೆ ಎಂಬà³à²¦à²¨à³à²¨à³ ಸಾಬೀತà³à²ªà²¡à²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¾à²—ಲಿಲà³à²²; ಅದರ ಸà³à²°à²•à³à²·à²¤à²¾ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà²¨à³à²¨à³ ಹಿಂತೆಗೆದà³à²•à³Šà²³à³à²³à²²à²¾à²—ಿರಬಹà³à²¦à³. ಇದೠತಪà³à²ªà³ ಕಾನà³à²«à²¿à²—ರೇಶನà³â€Œà²¨à²¿à²‚ದ ಅಥವಾ ಆಕà³à²°à²®à²£à²•à²¾à²°à²°à³ ನಿಮà³à²® ಸಂಪರà³à²•à²¦à²²à³à²²à²¿ ಒಳನà³à²¸à³à²³à²¿à²°à³à²µà³à²¦à²°à²¿à²‚ದ ಆಗಿರಬಹà³à²¦à³.</translation>
<translation id="2414886740292270097">ಗಾಢ</translation>
<translation id="2430968933669123598">Google ಖಾತೆಯನà³à²¨à³ ನಿರà³à²µà²¹à²¿à²¸à²¿, ನಿಮà³à²® Google ಖಾತೆಯಲà³à²²à²¿ ನಿಮà³à²® ಮಾಹಿತಿ, ಗೌಪà³à²¯à²¤à³† ಮತà³à²¤à³ ಸà³à²°à²•à³à²·à²¤à³†à²¯à²¨à³à²¨à³ ನಿರà³à²µà²¹à²¿à²¸à²²à³ Enter ಒತà³à²¤à²¿</translation>
+<translation id="2436186046335138073"><ph name="PROTOCOL" /> ಎಲà³à²²à²¾ ಲಿಂಕà³â€Œà²—ಳನà³à²¨à³ ತೆರೆಯಲೠ<ph name="HANDLER_HOSTNAME" /> ಗೆ ಅನà³à²®à²¤à²¿à²¸à³à²µà³à²¦à³‡?</translation>
<translation id="2438874542388153331">ಬಲಭಾಗದಲà³à²²à²¿ ನಾಲà³à²•à³ ತೂತà³à²—ಳನà³à²¨à³ ಮಾಡಿ</translation>
<translation id="2450021089947420533">ಪà³à²°à²¯à²¾à²£à²—ಳà³</translation>
<translation id="2463739503403862330">ಭರà³à²¤à²¿ ಮಾಡà³</translation>
@@ -476,6 +496,7 @@
<translation id="2465655957518002998">ವಿತರಣೆ ವಿಧಾನವನà³à²¨à³ ಆರಿಸಿ</translation>
<translation id="2465688316154986572">ಸà³à²Ÿà³‡à²ªà²²à³ ಮಾಡಿ</translation>
<translation id="2465914000209955735">ನೀವೠChrome ನಲà³à²²à²¿ ಡೌನà³â€Œà²²à³‹à²¡à³ ಮಾಡಿದ ಫೈಲà³â€Œà²—ಳನà³à²¨à³ ನಿರà³à²µà²¹à²¿à²¸à²¿</translation>
+<translation id="2466004615675155314">ವೆಬà³â€Œà²¨à²¿à²‚ದ ಇನà³à²¨à²·à³à²Ÿà³ ಮಾಹಿತಿಯನà³à²¨à³ ತೋರಿಸಿ</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />ನೆಟà³â€Œà²µà²°à³à²•à³ ಡಯಾಗà³à²¨à²¾à²¸à³à²Ÿà²¿à²•à³à²¸à³â€Œ ರನೠಆಗà³à²¤à³à²¤à²¿à²¦à³†<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">1-ಇಂದ-N ಆರà³à²¡à²°à³</translation>
<translation id="2470767536994572628">ನೀವೠಟಿಪà³à²ªà²£à²¿à²—ಳನà³à²¨à³ ಎಡಿಟೠಮಾಡಿದಾಗ, ಈ ಡಾಕà³à²¯à³à²®à³†à²‚ಟೠಒಂದೇ ಪà³à²Ÿà²¦ ವೀಕà³à²·à²£à³†à²—ೆ ಮತà³à²¤à³ ತನà³à²¨ ಮೂಲ ರೊಟೇಶನೠಸà³à²¥à²¾à²¨à²•à³à²•à³† ಮರಳà³à²¤à³à²¤à²¦à³†</translation>
@@ -496,6 +517,7 @@
<translation id="2523886232349826891">ಈ ಸಾಧನದಲà³à²²à²¿ ಮಾತà³à²° ಉಳಿಸಲಾಗಿದೆ</translation>
<translation id="2524461107774643265">ಇನà³à²¨à²·à³à²Ÿà³ ಮಾಹಿತಿಯನà³à²¨à³ ಸೇರಿಸಿ</translation>
<translation id="2529899080962247600">ಈ ಕà³à²·à³‡à²¤à³à²°à²µà³ <ph name="MAX_ITEMS_LIMIT" /> ಕà³à²•à²¿à²‚ತ ಹೆಚà³à²šà²¿à²¨ ನಮೂದà³à²—ಳನà³à²¨à³ ಹೊಂದಿರà³à²µà²‚ತಿಲà³à²². ಮà³à²‚ದಿನ ಎಲà³à²²à²¾ ನಮೂದà³à²—ಳನà³à²¨à³ ನಿರà³à²²à²•à³à²·à²¿à²¸à²²à²¾à²—à³à²¤à³à²¤à²¦à³†.</translation>
+<translation id="2535585790302968248">ಖಾಸಗಿಯಾಗಿ ಬà³à²°à³Œà²¸à³ ಮಾಡಲೠಹೊಸ ಅಜà³à²žà²¾à²¤ ಟà³à²¯à²¾à²¬à³ ತೆರೆಯಿರಿ</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{ಮತà³à²¤à³ ಇನà³à²¨à³‚ 1}one{ಮತà³à²¤à³ ಇನà³à²¨à³‚ #}other{ಮತà³à²¤à³ ಇನà³à²¨à³‚ #}}</translation>
<translation id="2536110899380797252">ವಿಳಾಸವನà³à²¨à³ ಸೇರಿಸಿ</translation>
<translation id="2539524384386349900">ಪತà³à²¤à³† ಮಾಡà³</translation>
@@ -521,7 +543,14 @@
<translation id="2597378329261239068">ಈ ಡಾಕà³à²¯à³à²®à³†à²‚ಟà³â€Œ ಅನà³à²¨à³ ಪಾಸà³â€Œà²µà²°à³à²¡à³â€Œà²¨à²¿à²‚ದ ರಕà³à²·à²¿à²¸à²²à²¾à²—ಿದೆ. ದಯವಿಟà³à²Ÿà³ ಪಾಸà³â€Œà²µà²°à³à²¡à³ ಅನà³à²¨à³ ನಮೂದಿಸಿ.</translation>
<translation id="2609632851001447353">ಪರಿವರà³à²¤à²¨à³†à²—ಳà³</translation>
<translation id="2610561535971892504">ನಕಲಿಸಲೠಕà³à²²à²¿à²•à³ ಮಾಡಿ</translation>
+<translation id="2617988307566202237">ಈ ಕೆಳಗಿನ ಮಾಹಿತಿಯನà³à²¨à³ Chrome <ph name="BEGIN_EMPHASIS" />ಉಳಿಸà³à²µà³à²¦à²¿à²²à³à²²<ph name="END_EMPHASIS" />:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ನಿಮà³à²® ಬà³à²°à³Œà²¸à²¿à²‚ಗೠಇತಿಹಾಸ
+ <ph name="LIST_ITEM" />ಕà³à²•à³€à²—ಳೠಮತà³à²¤à³ ಸೈಟೠಡೇಟಾ
+ <ph name="LIST_ITEM" />ಫಾರà³à²®à³â€Œà²—ಳಲà³à²²à²¿ ನಮೂದಿಸಿದ ಮಾಹಿತಿ
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (Envelope)</translation>
+<translation id="2623663032199728144">ನಿಮà³à²® ಸà³à²•à³à²°à³€à²¨à³â€Œà²—ಳ ಕà³à²°à²¿à²¤à²¾à²¦ ಮಾಹಿತಿಯನà³à²¨à³ ಬಳಸಲೠಕೇಳಬಹà³à²¦à³</translation>
<translation id="2625385379895617796">ನಿಮà³à²® ಗಡಿಯಾರವೠಮà³à²‚ದೆ ಇದೆ</translation>
<translation id="262745152991669301">USB ಸಾಧನಗಳಿಗೆ ಕನೆಕà³à²Ÿà³ ಮಾಡಲೠಕೇಳಬಹà³à²¦à³</translation>
<translation id="2629325967560697240">Chrome ನ ಉನà³à²¨à²¤ ಮಟà³à²Ÿà²¦ ಸà³à²°à²•à³à²·à²¤à³†à²¯à²¨à³à²¨à³ ಪಡೆಯಲà³, <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />ವರà³à²§à²¿à²¤ ಸà³à²°à²•à³à²·à²¤à³†à²¯à²¨à³à²¨à³ ಆನೠಮಾಡಿ<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -555,6 +584,7 @@
<translation id="2709516037105925701">ಸà³à²µà²¯à²‚ತà³à²‚ಬà³à²µà²¿à²•à³†</translation>
<translation id="2713444072780614174">ಬಿಳಿ</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />, Chrome ಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳಲà³à²²à²¿ ನಿಮà³à²® ಪಾವತಿಗಳೠಮತà³à²¤à³ ಕà³à²°à³†à²¡à²¿à²Ÿà³ ಕಾರà³à²¡à³ ಮಾಹಿತಿಯನà³à²¨à³ ನಿರà³à²µà²¹à²¿à²¸à²²à³ Tab ಒತà³à²¤à²¿, ನಂತರ Enter ಒತà³à²¤à²¿.</translation>
+<translation id="271663710482723385">ಪೂರà³à²£ ಸà³à²•à³à²°à³€à²¨à³â€Œà²¨à²¿à²‚ದ ನಿರà³à²—ಮಿಸಲೠ|<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| ಒತà³à²¤à²¿à²°à²¿</translation>
<translation id="2721148159707890343">ವಿನಂತಿಯನà³à²¨à³ ಯಶಸà³à²µà²¿à²—ೊಳಿಸಲಾಗಿದೆ</translation>
<translation id="2723669454293168317">Chrome ಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳಲà³à²²à²¿ ಸà³à²°à²•à³à²·à²¤à³†à²¯ ಪರಿಶೀಲನೆಯನà³à²¨à³ ರನೠಮಾಡಿ</translation>
<translation id="2726001110728089263">ಪಕà³à²•à²¦ ಟà³à²°à³‡</translation>
@@ -585,6 +615,7 @@
<translation id="2850739647070081192">Invite (Envelope)</translation>
<translation id="2856444702002559011">ದಾಳಿಕೋರರೠ<ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ನಿಂದ ನಿಮà³à²® ಮಾಹಿತಿಯನà³à²¨à³ ಕದಿಯಲೠಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à³à²¤à³à²¤à²¿à²°à²¬à²¹à³à²¦à³ (ಉದಾಹರಣೆಗೆ, ಪಾಸà³â€Œà²µà²°à³à²¡à³â€Œà²—ಳà³, ಸಂದೇಶಗಳೠಅಥವಾ ಕà³à²°à³†à²¡à²¿à²Ÿà³ ಕಾರà³à²¡à³â€Œà²—ಳà³). <ph name="BEGIN_LEARN_MORE_LINK" />ಇನà³à²¨à²·à³à²Ÿà³ ತಿಳಿಯಿರಿ<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">ಅತಿಕà³à²°à²®à²£à²•à²¾à²°à²¿à²¯à²¾à²—ಿರà³à²µ ಅಥವಾ ತಪà³à²ªà³à²¦à²¾à²°à²¿à²—ೆಳೆಯà³à²µ ಜಾಹೀರಾತà³à²—ಳನà³à²¨à³ ಈ ಸೈಟೠತೋರಿಸà³à²¤à³à²¤à²¦à³†.</translation>
+<translation id="286512204874376891">ವರà³à²šà³à²µà²²à³ ಕಾರà³à²¡à³ ಸಂಭಾವà³à²¯ ವಂಚನೆಯಿಂದ ನಿಮà³à²®à²¨à³à²¨à³ ರಕà³à²·à²¿à²¸à²²à³ ನಿಮà³à²® ನಿಜವಾದ ಕಾರà³à²¡à³â€Œà²—ೆ ಮಾರà³à²µà³‡à²· ತೊಡಿಸà³à²¤à³à²¤à²¦à³†. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">ಸೌಹಾರà³à²¦</translation>
<translation id="2876489322757410363">ಬಾಹà³à²¯ ಅಪà³à²²à²¿à²•à³‡à²¶à²¨à³â€Œâ€Œ ಮೂಲಕ ಪಾವತಿಸಲೠಅಜà³à²žà²¾à²¤ ಮೋಡà³â€Œâ€Œ ತೊರೆಯಲಾಗà³à²¤à³à²¤à²¿à²¦à³†. ಮà³à²‚ದà³à²µà²°à²¿à²¸à²¬à³‡à²•à³†?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />, Chrome ಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳಲà³à²²à²¿ ನಿಮà³à²® ಸà³à²°à²•à³à²·à²¿à²¤ ಬà³à²°à³Œà²¸à²¿à²‚ಗೠಮತà³à²¤à³ ಇನà³à²¨à²·à³à²Ÿà²¨à³à²¨à³ ನಿರà³à²µà²¹à²¿à²¸à²²à³ Tab ಒತà³à²¤à²¿, ನಂತರ Enter ಒತà³à²¤à²¿à²°à²¿</translation>
@@ -609,6 +640,7 @@
<translation id="2930577230479659665">ಪà³à²°à²¤à²¿ ಮà³à²¦à³à²°à²£à²ªà³à²°à²¤à²¿à²¯ ನಂತರ ಟà³à²°à²¿à²®à³ ಮಾಡಿ</translation>
<translation id="2932085390869194046">ಪಾಸà³â€Œà²µà²°à³à²¡à³ ಅನà³à²¨à³ ಸೂಚಿಸಿ...</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019"><ph name="PROTOCOL" /> ಲಿಂಕà³â€Œà²—ಳನà³à²¨à³ ತೆರೆಯಿರಿ</translation>
<translation id="2941952326391522266">ಈ ಸರà³à²µà²°à³ <ph name="DOMAIN" /> ಆಗಿದೆ ಎಂಬà³à²¦à²¨à³à²¨à³ ಸಾಬೀತà³à²ªà²¡à²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¾à²—ಲಿಲà³à²²; ಅದರ ಸà³à²°à²•à³à²·à²¤à²¾ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà³ <ph name="DOMAIN2" /> ದಿಂದ ಆಗಿದೆ. ಇದೠತಪà³à²ªà³ ಕಾನà³à²«à²¿à²—ರೇಶನà³â€Œà²¨à²¿à²‚ದ ಅಥವಾ ಆಕà³à²°à²®à²£à²•à²¾à²°à²°à³ ನಿಮà³à²® ಸಂಪರà³à²•à²¦à²²à³à²²à²¿ ಒಳನà³à²¸à³à²³à²¿à²°à³à²µà³à²¦à²°à²¿à²‚ದ ಆಗಿರಬಹà³à²¦à³.</translation>
<translation id="2943895734390379394">ಅಪà³â€Œà²²à³‹à²¡à³ ಮಾಡಿದ ಸಮಯ:</translation>
<translation id="2948083400971632585">ಸಂಪರà³à²•à²•à³à²•à²¾à²—ಿ ಕಾನà³à²«à²¿à²—ರೠಮಾಡಲಾಗಿರà³à²µ ಯಾವà³à²¦à³‡ ಪà³à²°à²¾à²•à³à²¸à²¿à²—ಳನà³à²¨à³ ನೀವೠಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳ ಪà³à²Ÿà²¦à²¿à²‚ದ ನಿಷà³à²•à³à²°à²¿à²¯à²—ೊಳಿಸಬಹà³à²¦à³.</translation>
@@ -641,6 +673,7 @@
<translation id="3037605927509011580">ಓಹà³, ಹೋಯà³à²¤à³!</translation>
<translation id="3041612393474885105">ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²° ಮಾಹಿತಿ</translation>
<translation id="3044034790304486808">ನಿಮà³à²® ಸಂಶೋಧನೆಯನà³à²¨à³ ಪà³à²¨à²°à²¾à²°à²‚ಭಿಸಿ</translation>
+<translation id="305162504811187366">ಟೈಮà³â€Œà²¸à³à²Ÿà³à²¯à²¾à²‚ಪà³â€Œà²—ಳà³, ಹೋಸà³à²Ÿà³â€Œà²—ಳೠಮತà³à²¤à³ ಕà³à²²à³ˆà²‚ಟೠಸೆಷನೠà²à²¡à²¿à²—ಳೠಸೇರಿದಂತೆ Chrome ರಿಮೋಟೠಡೆಸà³à²•à³â€Œà²Ÿà²¾à²ªà³ ಇತಿಹಾಸ</translation>
<translation id="3060227939791841287">C9 (Envelope)</translation>
<translation id="3061707000357573562">ಪà³à²¯à²¾à²šà³ ಸೇವೆ</translation>
<translation id="306573536155379004">ಗೇಮೠಪà³à²°à²¾à²°à²‚ಭವಾಗಿದೆ.</translation>
@@ -679,6 +712,7 @@
<translation id="3197136577151645743">ನೀವೠಈ ಸಾಧನವನà³à²¨à³ ಸಕà³à²°à²¿à²¯à²µà²¾à²—ಿ ಬಳಸà³à²¤à³à²¤à²¿à²°à³à²µà²¾à²— ತಿಳಿದà³à²•à³Šà²³à³à²³à²²à³ ಕೇಳಬಹà³à²¦à³</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />, Chrome ಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳಲà³à²²à²¿ ನೀವೠಯಾವ ಮಾಹಿತಿಯನà³à²¨à³ ಸಿಂಕೠಮಾಡà³à²¤à³à²¤à³€à²°à²¿ ಎಂಬà³à²¦à²¨à³à²¨à³ ನಿರà³à²µà²¹à²¿à²¸à²²à³ Tab ಒತà³à²¤à²¿, ನಂತರ Enter ಒತà³à²¤à²¿</translation>
<translation id="320323717674993345">ಪಾವತಿಯನà³à²¨à³ ರದà³à²¦à³à²®à²¾à²¡à²¿</translation>
+<translation id="3203366800380907218">ವೆಬà³â€Œà²¨à²¿à²‚ದ</translation>
<translation id="3207960819495026254">ಬà³à²•à³â€Œà²®à²¾à²°à³à²•à³â€Œ ಮಾಡಲಾಗಿದೆ</translation>
<translation id="3209034400446768650">ಈ ಪà³à²Ÿà²µà³, ಶà³à²²à³à²• ವಿಧಿಸಬಹà³à²¦à³</translation>
<translation id="3212581601480735796"><ph name="HOSTNAME" /> ನಲà³à²²à²¿ ನಿಮà³à²® ಚಟà³à²µà²Ÿà²¿à²•à³†à²¯ ಮೇಲೆ ನಿಗಾ ಇಡಲಾಗà³à²¤à³à²¤à²¿à²¦à³†</translation>
@@ -695,10 +729,12 @@
<translation id="3234666976984236645">ಈ ಸೈಟà³â€Œà²¨à²²à³à²²à²¿ ಯಾವಾಗೂ ಮà³à²–à³à²¯ ವಿಷಯವನà³à²¨à³ ಹà³à²¡à³à²•à²¿</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />, ನಿಮà³à²® ಬà³à²°à³Œà²¸à²°à³â€Œà²¨ ನೋಟವನà³à²¨à³ ಕಸà³à²Ÿà²®à³ˆà²¸à³ ಮಾಡಲೠTab ಒತà³à²¤à²¿, ನಂತರ Enter ಒತà³à²¤à²¿à²°à²¿</translation>
<translation id="3240791268468473923">ಸà³à²°à²•à³à²·à²¿à²¤ ಪಾವತಿ ರà³à²œà³à²µà²¾à²¤à²¿à²—ೆ ಹೊಂದಾಣಿಕೆಯಾಗà³à²µ ಯಾವà³à²¦à³‡ ರà³à²œà³à²µà²¾à²¤à³ ಶೀಟೠಅನà³à²¨à³ ತೆರೆಯಲಾಗಿಲà³à²²</translation>
+<translation id="324180406144491771">“<ph name="HOST_NAME" />†ಲಿಂಕà³â€Œà²—ಳನà³à²¨à³ ನಿರà³à²¬à²‚ಧಿಸಲಾಗಿದೆ</translation>
<translation id="3249845759089040423">ಗà³à²°à³‚ವಿ</translation>
<translation id="3252266817569339921">ಫà³à²°à³†à²‚ಚà³</translation>
<translation id="3257954757204451555">ಈ ಮಾಹಿತಿಯ ಹಿಂದೆ ಯಾರಿದà³à²¦à²¾à²°à³†?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />, Google Calendar ನಲà³à²²à²¿ ಹೊಸ ಈವೆಂಟೠಅನà³à²¨à³ ತà³à²µà²°à²¿à²¤à²µà²¾à²—ಿ ರಚಿಸಲೠTab ಒತà³à²¤à²¿, ನಂತರ Enter ಒತà³à²¤à²¿</translation>
+<translation id="3261488570342242926">ವರà³à²šà³à²µà²²à³ ಕಾರà³à²¡à³â€Œà²—ಳ ಕà³à²°à²¿à²¤à³ ಇನà³à²¨à²·à³à²Ÿà³ ತಿಳಿಯಿರಿ</translation>
<translation id="3264837738038045344">Chrome ಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳ ಬಟನೠಅನà³à²¨à³ ನಿರà³à²µà²¹à²¿à²¸à²¿, ನಿಮà³à²® Chrome ಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳಿಗೆ ಭೇಟಿ ನೀಡಲೠEnter ಒತà³à²¤à²¿</translation>
<translation id="3266793032086590337">ಮೌಲà³à²¯ (ಸಂಘರà³à²· ಇರà³à²µà³à²¦à³)</translation>
<translation id="3268451620468152448">ತೆರೆದ ಟà³à²¯à²¾à²¬à³â€Œà²—ಳà³</translation>
@@ -712,6 +748,7 @@
<translation id="3288238092761586174">ನಿಮà³à²® ಪಾವತಿಯನà³à²¨à³ ಪರಿಶೀಲಿಸಲೠ<ph name="URL" /> ಗೆ ಹೆಚà³à²šà³à²µà²°à²¿ ಹಂತಗಳನà³à²¨à³ ಅನà³à²¸à²°à²¿à²¸à²¬à³‡à²•à²¾à²—ಬಹà³à²¦à³</translation>
<translation id="3293642807462928945"><ph name="POLICY_NAME" /> ಕಾರà³à²¯à²¨à³€à²¤à²¿à²¯ ಕà³à²°à²¿à²¤à³ ಇನà³à²¨à²·à³à²Ÿà³ ತಿಳಿದà³à²•à³Šà²³à³à²³à²¿</translation>
<translation id="3295444047715739395">Chrome ಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳಲà³à²²à²¿ ನಿಮà³à²® ಪಾಸà³â€Œà²µà²°à³à²¡à³â€Œà²—ಳನà³à²¨à³ ವೀಕà³à²·à²¿à²¸à²¿ ಮತà³à²¤à³ ನಿರà³à²µà²¹à²¿à²¸à²¿</translation>
+<translation id="3303795387212510132"><ph name="PROTOCOL_SCHEME" /> ಲಿಂಕà³â€Œà²—ಳನà³à²¨à³ ತೆರೆಯಲೠಆà³à²¯à²ªà³â€Œà²—ೆ ಅನà³à²®à²¤à²¿à²¸à²¬à³‡à²•à³†?</translation>
<translation id="3303855915957856445">ಯಾವà³à²¦à³‡ ಹà³à²¡à³à²•à²¾à²Ÿ ಫಲಿತಾಂಶಗಳೠಕಂಡà³à²¬à²‚ದಿಲà³à²²</translation>
<translation id="3304073249511302126">ಬà³à²²à³‚ಟೂತೠಸà³à²•à³à²¯à²¾à²¨à²¿à²‚ಗà³</translation>
<translation id="3308006649705061278">ಸಂಸà³à²¥à³† ಘಟಕ (OU)</translation>
@@ -725,12 +762,6 @@
<translation id="3345782426586609320">ಕಣà³à²£à³à²—ಳà³</translation>
<translation id="3355823806454867987">ಪà³à²°à²¾à²•à³à²¸à²¿ ಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳನà³à²¨à³ ಬದಲಿಸಿ...</translation>
<translation id="3360103848165129075">ಪಾವತಿ ಹà³à²¯à²¾à²‚ಡà³â€Œà²²à²°à³ ಶೀಟà³</translation>
-<translation id="3361596688432910856">ಈ ಕೆಳಗಿನ ಮಾಹಿತಿಯನà³à²¨à³ Chrome <ph name="BEGIN_EMPHASIS" />ಉಳಿಸà³à²µà³à²¦à²¿à²²à³à²²<ph name="END_EMPHASIS" />:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />ನಿಮà³à²® ಬà³à²°à³Œà²¸à²¿à²‚ಗೠಇತಿಹಾಸ
- <ph name="LIST_ITEM" />ಕà³à²•à³€à²¸à³ ಮತà³à²¤à³ ಸೈಟೠಡೇಟಾ
- <ph name="LIST_ITEM" />ಫಾರà³à²®à³â€Œà²—ಳಲà³à²²à²¿ ನಮೂದಿಸಿದ ಮಾಹಿತಿ
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">ತಡೆಹಿಡಿಯಲಾಗಿರà³à²µ <ph name="OLD_POLICY" /> ಕಾರà³à²¯à²¨à³€à²¤à²¿à²¯à²¿à²‚ದ, ಈ ಕಾರà³à²¯à²¨à³€à²¤à²¿à²¯à²¨à³à²¨à³ ಸà³à²µà²¯à²‚ಚಾಲಿತವಾಗಿ ನಕಲಿಸಲಾಗಿದೆ. ಅದರ ಬದಲಿಗೆ, ನೀವೠಇದನà³à²¨à³ ಬಳಸಬೇಕà³.</translation>
<translation id="3364869320075768271">ನಿಮà³à²® ವರà³à²šà³à²µà²²à³ ರಿಯಾಲಿಟಿ ಸಾಧನ ಮತà³à²¤à³ ಡೇಟಾವನà³à²¨à³ <ph name="URL" /> ಬಳಸಲೠಬಯಸà³à²¤à³à²¤à²¿à²¦à³†</translation>
<translation id="3366477098757335611">ಕಾರà³à²¡à³â€Œà²—ಳನà³à²¨à³ ವೀಕà³à²·à²¿à²¸à²¿</translation>
@@ -813,7 +844,6 @@
<translation id="3587738293690942763">ಮಧà³à²¯à²®</translation>
<translation id="3592413004129370115">Italian (Envelope)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{ನೀವೠಯಾವಾಗ ಬೇಕಾದರೂ ನಿಮà³à²® ಗà³à²‚ಪನà³à²¨à³ ರೀಸೆಟೠಮಾಡಬಹà³à²¦à³. ಹೊಸ ಗà³à²‚ಪಿಗೆ ಸೇರà³à²ªà²¡à³†à²—ೊಳà³à²³à²²à³ ಒಂದೠದಿನದ ಸಮಯವನà³à²¨à³ ತೆಗೆದà³à²•à³Šà²³à³à²³à³à²¤à³à²¤à²¦à³†.}=1{ನೀವೠಯಾವಾಗ ಬೇಕಾದರೂ ನಿಮà³à²® ಗà³à²‚ಪನà³à²¨à³ ರೀಸೆಟೠಮಾಡಬಹà³à²¦à³. ಹೊಸ ಗà³à²‚ಪಿಗೆ ಸೇರà³à²ªà²¡à³†à²—ೊಳà³à²³à²²à³ ಒಂದೠದಿನದ ಸಮಯವನà³à²¨à³ ತೆಗೆದà³à²•à³Šà²³à³à²³à³à²¤à³à²¤à²¦à³†.}one{ನೀವೠಯಾವಾಗ ಬೇಕಾದರೂ ನಿಮà³à²® ಗà³à²‚ಪನà³à²¨à³ ರೀಸೆಟೠಮಾಡಬಹà³à²¦à³. ಹೊಸ ಗà³à²‚ಪಿಗೆ ಸೇರà³à²ªà²¡à³†à²—ೊಳà³à²³à²²à³ {NUM_DAYS} ದಿನಗಳ ಸಮಯವನà³à²¨à³ ತೆಗೆದà³à²•à³Šà²³à³à²³à³à²¤à³à²¤à²¦à³†.}other{ನೀವೠಯಾವಾಗ ಬೇಕಾದರೂ ನಿಮà³à²® ಗà³à²‚ಪನà³à²¨à³ ರೀಸೆಟೠಮಾಡಬಹà³à²¦à³. ಹೊಸ ಗà³à²‚ಪಿಗೆ ಸೇರà³à²ªà²¡à³†à²—ೊಳà³à²³à²²à³ {NUM_DAYS} ದಿನಗಳ ಸಮಯವನà³à²¨à³ ತೆಗೆದà³à²•à³Šà²³à³à²³à³à²¤à³à²¤à²¦à³†.}}</translation>
-<translation id="3596012367874587041">ಆà³à²¯à²ªà³ ಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳà³</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">ನಿಮà³à²® ನಿರà³à²µà²¾à²¹à²•à²°à³ ಅಪà³à²²à²¿à²•à³‡à²¶à²¨à³ ಅನà³à²¨à³ ನಿರà³à²¬à²‚ಧಿಸಿದà³à²¦à²¾à²°à³†</translation>
<translation id="3608932978122581043">ಫೀಡೠಓರಿಯಂಟೇಶನà³</translation>
@@ -855,6 +885,7 @@
<translation id="370972442370243704">ಪà³à²°à²¯à²¾à²£à²—ಳನà³à²¨à³ ಆನೠಮಾಡಿ</translation>
<translation id="3711895659073496551">ಅಮಾನತà³</translation>
<translation id="3712624925041724820">ಪರವಾನಗಿಗಳೠಬರಿದಾಗಿವೆ</translation>
+<translation id="3714633008798122362">ವೆಬೠಕà³à²¯à²¾à²²à³†à²‚ಡರà³</translation>
<translation id="3714780639079136834">ಮೊಬೈಲೠಡೇಟಾ ಅಥವಾ ವೈ-ಫೈ ಆನೠಮಾಡಲಾಗà³à²¤à³à²¤à²¿à²¦à³†</translation>
<translation id="3715597595485130451">ವೈ-ಫೈಗೆ ಸಂಪರà³à²•à²¿à²¸à²¿</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />ಪà³à²°à²¾à²•à³à²¸à²¿, ಫೈರà³â€Œà²µà²¾à²²à³ ಮತà³à²¤à³ DNS ಕಾನà³à²«à²¿à²—ರೇಶನà³â€Œâ€Œ ಪರಿಶೀಲಿಸಲಾಗà³à²¤à³à²¤à²¿à²¦à³†<ph name="END_LINK" /></translation>
@@ -916,6 +947,7 @@
<translation id="3906954721959377182">ಟà³à²¯à²¾à²¬à³à²²à³†à²Ÿà³</translation>
<translation id="3909477809443608991"><ph name="URL" />, ಸಂರಕà³à²·à²¿à²¤ ವಿಷಯವನà³à²¨à³ ಪà³à²²à³‡ ಮಾಡಲೠಬಯಸà³à²¤à³à²¤à²¦à³†. ನಿಮà³à²® ಸಾಧನದ ಗà³à²°à³à²¤à²¨à³à²¨à³ Google ಪರಿಶೀಲಿಸà³à²¤à³à²¤à²¦à³† ಮತà³à²¤à³ ಅದಕà³à²•à³† ಈ ಸೈಟೠಪà³à²°à²µà³‡à²¶ ಪಡೆಯಬಹà³à²¦à³.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">ನಿರಾಕರಿಸಿ</translation>
<translation id="3939773374150895049">CVC ಬದಲಿಗೆ WebAuthn ಬಳಸà³à²µà²¿à²°à²¾?</translation>
<translation id="3946209740501886391">ಯಾವಾಗಲೂ ಈ ಸೈಟà³â€Œà²¨à²²à³à²²à²¿ ಕೇಳಿ</translation>
<translation id="3947595700203588284">MIDI ಸಾಧನಗಳಿಗೆ ಕನೆಕà³à²Ÿà³ ಮಾಡಲೠಕೇಳಬಹà³à²¦à³</translation>
@@ -936,6 +968,7 @@
<translation id="3987940399970879459">1 MB ಗಿಂತ ಕಡಿಮೆ</translation>
<translation id="3990250421422698716">ಜಾಗೠಆಫà³â€Œà²¸à³†à²Ÿà³</translation>
<translation id="3996311196211510766"><ph name="ORIGIN" /> ಸೈಟೠತನà³à²¨ ಎಲà³à²²à²¾ ವಿನಂತಿಗಳಿಗೆ ಮೂಲ ಕಾರà³à²¯à²¨à³€à²¤à²¿à²¯à³Šà²‚ದನà³à²¨à³ ಅನà³à²µà²¯à²¿à²¸à²²à³ ವಿನಂತಿಸಿದೆ, ಆದರೆ ಈ ಕಾರà³à²¯à²¨à³€à²¤à²¿à²¯à²¨à³à²¨à³ ಪà³à²°à²¸à³à²¤à³à²¤à²µà²¾à²—ಿ ಅನà³à²µà²¯à²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¾à²—à³à²µà³à²¦à²¿à²²à³à²².</translation>
+<translation id="4009243425692662128">ನೀವೠಪà³à²°à²¿à²‚ಟೠಮಾಡà³à²µ ಪà³à²Ÿà²—ಳ ವಿಷಯವನà³à²¨à³ ವಿಶà³à²²à³‡à²·à²£à³†à²—ಾಗಿ Google ಕà³à²²à³Œà²¡à³â€Œ ಅಥವಾ ಮೂರನೇ ವà³à²¯à²•à³à²¤à²¿à²—ಳಿಗೆ ಕಳà³à²¹à²¿à²¸à²²à²¾à²—à³à²¤à³à²¤à²¦à³†. ಉದಾಹರಣೆಗೆ, ಸೂಕà³à²·à³à²®à²µà²¾à²¦ ವೈಯಕà³à²¤à²¿à²• ಡೇಟಾವನà³à²¨à³ ಪತà³à²¤à³†à²¹à²šà³à²šà²²à³ ಅದನà³à²¨à³ ಸà³à²•à³à²¯à²¾à²¨à³ ಮಾಡಬಹà³à²¦à³.</translation>
<translation id="4010758435855888356">ಸಂಗà³à²°à²¹à²£à³†à²¯à²¨à³à²¨à³ ಪà³à²°à²µà³†à³•à²¶à²¿à²¸à²²à³ ಅನà³à²®à²¤à²¿à²¸à²¬à³‡à²•à³†?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{PDF ಡಾಕà³à²¯à³à²®à³†à²‚ಟà³, {COUNT} ಪà³à²Ÿà²µà²¨à³à²¨à³ ಒಳಗೊಂಡಿದೆ}one{PDF ಡಾಕà³à²¯à³à²®à³†à²‚ಟà³, {COUNT} ಪà³à²Ÿà²—ಳನà³à²¨à³ ಒಳಗೊಂಡಿದೆ}other{PDF ಡಾಕà³à²¯à³à²®à³†à²‚ಟà³, {COUNT} ಪà³à²Ÿà²—ಳನà³à²¨à³ ಒಳಗೊಂಡಿದೆ}}</translation>
<translation id="4023431997072828269">ಸà³à²°à²•à³à²·à²¿à²¤à²µà²²à³à²²à²¦ ಕನೆಕà³à²·à²¨à³ ಅನà³à²¨à³ ಬಳಸಿ ಈ ಫಾರà³à²®à³ ಅನà³à²¨à³ ಸಲà³à²²à²¿à²¸à³à²¤à³à²¤à²¿à²°à³à²µà³à²¦à²°à²¿à²‚ದ, ನಿಮà³à²® ಮಾಹಿತಿಯೠಇತರರಿಗೆ ಗೋಚರಿಸà³à²¤à³à²¤à²¦à³†.</translation>
@@ -1026,6 +1059,7 @@
<translation id="4250680216510889253">ಇಲà³à²²</translation>
<translation id="4253168017788158739">ಟಿಪà³à²ªà²£à²¿</translation>
<translation id="425582637250725228">ನೀವೠಮಾಡಿದ ಬದಲಾವಣೆಗಳನà³à²¨à³ ಉಳಿಸಲಾಗದೇ ಇರಬಹà³à²¦à³.</translation>
+<translation id="425869179292622354">ವರà³à²šà³à²µà²²à³ ಕಾರà³à²¡à³â€Œà²¨ ಮೂಲಕ ಅದನà³à²¨à³ ಮತà³à²¤à²·à³à²Ÿà³ ಸà³à²°à²•à³à²·à²¿à²¤à²µà²¾à²—ಿಸಬೇಕೇ?</translation>
<translation id="4258748452823770588">ತಪà³à²ªà²¾à²¦ ಸಹಿ</translation>
<translation id="4261046003697461417">ಸಂರಕà³à²·à²¿à²¤ ಡಾಕà³à²¯à³à²®à³†à²‚ಟà³â€Œà²—ಳನà³à²¨à³ ಟಿಪà³à²ªà²£à²¿ ಮಾಡಲೠಸಾಧà³à²¯à²µà²¿à²²à³à²²</translation>
<translation id="4265872034478892965">ನಿಮà³à²® ನಿರà³à²µà²¾à²¹à²•à²°à²¿à²‚ದ ಅನà³à²®à²¤à²¿à²¸à²²à²¾à²—ಿದೆ</translation>
@@ -1088,6 +1122,7 @@
<translation id="4434045419905280838">ಪಾಪà³-ಅಪà³â€Œà²—ಳೠಹಾಗೂ ಮರà³à²¨à²¿à²°à³à²¦à³‡à²¶à²¨à²—ಳà³</translation>
<translation id="4435702339979719576">Postcard)</translation>
<translation id="443673843213245140">ಪà³à²°à²¾à²•à³à²¸à²¿à²¯ ಬಳಕೆಯನà³à²¨à³ ನಿಷà³à²•à³à²°à²¿à²¯à²—ೊಳಿಸಲಾಗಿದೆ ಆದರೆ ಬಹಿರಂಗ ಪà³à²°à²¾à²•à³à²¸à²¿ ಕಾನà³à²«à²¿à²—ರೇಶನೠಅನà³à²¨à³ ನಿರà³à²¦à²¿à²·à³à²Ÿà²ªà²¡à²¿à²¸à²²à²¾à²—ಿದೆ.</translation>
+<translation id="4441832193888514600">ನೀತಿಯನà³à²¨à³ ಕà³à²²à³Œà²¡à³ ಬಳಕೆದಾರರ ನೀತಿಯಾಗಿ ಮಾತà³à²°à²µà³‡ ಹೊಂದಿಸಬಹà³à²¦à²¾à²—ಿದೆ, ಆದà³à²¦à²°à²¿à²‚ದ ನಿರà³à²²à²•à³à²·à²¿à²¸à²²à²¾à²—ಿದೆ.</translation>
<translation id="4450893287417543264">ಮತà³à²¤à³Šà²®à³à²®à³† ತೋರಿಸಬೇಡಿ</translation>
<translation id="4451135742916150903">HID ಸಾಧನಗಳಿಗೆ ಕನೆಕà³à²Ÿà³ ಮಾಡಲೠಕೇಳಬಹà³à²¦à³</translation>
<translation id="4452328064229197696">ನೀವೠಈಗಷà³à²Ÿà³‡ ಬಳಸಿದ ಪಾಸà³â€Œà²µà²°à³à²¡à³ ಡೇಟಾ ಉಲà³à²²à²‚ಘನೆಯಲà³à²²à²¿ ಕಂಡà³à²¬à²‚ದಿದೆ. ನಿಮà³à²® ಖಾತೆಗಳನà³à²¨à³ ಸà³à²°à²•à³à²·à²¿à²¤à²µà²¾à²—ಿರಿಸಲà³, Google ಪಾಸà³â€Œà²µà²°à³à²¡à³ ನಿರà³à²µà²¾à²¹à²•à²µà³ ನಿಮà³à²® ಉಳಿಸಿದ ಪಾಸà³â€Œà²µà²°à³à²¡à³â€Œà²—ಳನà³à²¨à³ ಪರಿಶೀಲಿಸಲೠಶಿಫಾರಸೠಮಾಡà³à²¤à³à²¤à²¦à³†.</translation>
@@ -1143,6 +1178,7 @@
<translation id="4628948037717959914">ಫೋಟೋ</translation>
<translation id="4631649115723685955">ಕà³à²¯à²¾à²¶à³â€Œà²¬à³à²¯à²¾à²•à³ ಲಿಂಕೠಮಾಡಲಾಗಿದೆ</translation>
<translation id="4636930964841734540">ಮಾಹಿತಿ</translation>
+<translation id="4638670630777875591">Chromium ನಲà³à²²à²¿ ಅದೃಶà³à²¯ ಮೋಡà³</translation>
<translation id="464342062220857295">ವೈಶಿಷà³à²Ÿà³à²¯à²—ಳನà³à²¨à³ ಹà³à²¡à³à²•à²¿</translation>
<translation id="4644670975240021822">ಹಿಮà³à²®à³à²– ಆರà³à²¡à²°à³ ಮà³à²– ಕೆಳಗೆ</translation>
<translation id="4646534391647090355">ನನà³à²¨à²¨à³à²¨à³ ಈಗ ಅಲà³à²²à²¿à²—ೆ ಕರೆದೊಯà³à²¯à²¿à²°à²¿</translation>
@@ -1163,6 +1199,7 @@
<translation id="4708268264240856090">ನಿಮà³à²® ಸಂಪರà³à²•à²•à³à²•à³† ಅಡà³à²¡à²¿à²¯à²¾à²—ಿದೆ</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Windows ನೆಟà³â€Œà²µà²°à³à²•à³ ಡಯಾಗà³à²¨à²¾à²¸à³à²Ÿà²¿à²•à³à²¸à³ ರನೠಮಾಡಲಾಗà³à²¤à³à²¤à²¿à²¦à³†<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426"><ph name="USERNAME" /> ಗಾಗಿ ಪಾಸà³â€Œà²µà²°à³à²¡à³</translation>
<translation id="4724144314178270921">ನಿಮà³à²® ಕà³à²²à²¿à²ªà³â€Œà²¬à³‹à²°à³à²¡à³â€Œà²¨à²²à³à²²à²¿ ಪಠà³à²¯ ಮತà³à²¤à³ ಚಿತà³à²°à²—ಳನà³à²¨à³ ನೋಡಲೠಕೇಳಬಹà³à²¦à³</translation>
<translation id="4726672564094551039">ನೀತಿಗಳನà³à²¨à³ ಮರà³à²²à³‹à²¡à³ ಮಾಡಿ</translation>
<translation id="4728558894243024398">ಪà³à²²à²¾à²Ÿà³â€Œà²«à²¾à²°à³à²®à³</translation>
@@ -1184,6 +1221,7 @@
<translation id="4757993714154412917">ನೀವೠಈಗಷà³à²Ÿà³‡ ವಂಚನೆ ಮಾಡà³à²µ ಸೈಟà³â€Œà²¨à²²à³à²²à²¿ ನಿಮà³à²® ಪಾಸà³â€Œà²µà²°à³à²¡à³ ಅನà³à²¨à³ ನಮೂದಿಸಿದà³à²¦à³€à²°à²¿. ನಿಮà³à²® ಖಾತೆಗಳನà³à²¨à³ ಭದà³à²°à²ªà²¡à²¿à²¸à²²à³, ನಿಮà³à²® ಉಳಿಸಿದ ಪಾಸà³â€Œà²µà²°à³à²¡à³â€Œà²—ಳನà³à²¨à³ ಪರಿಶೀಲಿಸಲೠChromium ಶಿಫಾರಸೠಮಾಡà³à²¤à³à²¤à²¦à³†.</translation>
<translation id="4758311279753947758">ಸಂಪರà³à²• ಮಾಹಿತಿಯನà³à²¨à³ ಸೇರಿಸಿ</translation>
<translation id="4761104368405085019">ನಿಮà³à²® ಮೈಕà³à²°à³Šà²«à³‹à²¨à³ ಅನà³à²¨à³ ಬಳಸಿ</translation>
+<translation id="4761869838909035636">Chrome ಸà³à²°à²•à³à²·à²¤à³†à²¯ ಪರಿಶೀಲನೆಯನà³à²¨à³ ರನೠಮಾಡಿ</translation>
<translation id="4764776831041365478"><ph name="URL" /> ನಲà³à²²à²¿à²°à³à²µ ವೆಬà³â€Œà²ªà³à²Ÿà²µà³ ತಾತà³à²•à²¾à²²à²¿à²•à²µà²¾à²—ಿ ಕಾರà³à²¯à²¨à²¿à²°à³à²µà²¹à²¿à²¸à²¦à³‡ ಇರಬಹà³à²¦à³ ಅಥವಾ ಅದನà³à²¨à³ ಶಾಶà³à²µà²¤à²µà²¾à²—ಿ ಹೊಸ ವೆಬೠವಿಳಾಸಕà³à²•à³† ಸರಿಸಲಾಗಿರಬಹà³à²¦à³.</translation>
<translation id="4766713847338118463">ಕೆಳಭಾಗದಲà³à²²à²¿ ಎರಡೠಸà³à²Ÿà³‡à²ªà²²à³ ಹಾಕಿ</translation>
<translation id="4771973620359291008">ಅಪರಿಚಿತ ದೋಷವೊಂದೠಎದà³à²°à²¾à²—ಿದೆ.</translation>
@@ -1204,12 +1242,6 @@
<translation id="4819347708020428563">ಡೀಫಾಲà³à²Ÿà³ ವೀಕà³à²·à²£à³†à²¯à²²à³à²²à²¿ ಟಿಪà³à²ªà²£à²¿à²—ಳನà³à²¨à³ ಎಡಿಟೠಮಾಡಬೇಕೆ?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />, ಹೊಸ Google Sheet ಅನà³à²¨à³ ತà³à²µà²°à²¿à²¤à²µà²¾à²—ಿ ರಚಿಸಲೠTab ಒತà³à²¤à²¿, ನಂತರ Enter ಒತà³à²¤à²¿</translation>
<translation id="4825507807291741242">ಪà³à²°à²¬à²²</translation>
-<translation id="4827402517081186284">ಅಜà³à²žà²¾à²¤ ಮೋಡೠನೀವೠಆನà³â€Œà²²à³ˆà²¨à³â€Œà²¨à²²à³à²²à²¿ ಅಗೋಚರವಾಗಿರà³à²µà²‚ತೆ ಮಾಡà³à²µà³à²¦à²¿à²²à³à²²:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />ನೀವೠಸೈಟà³â€Œà²—ಳಿಗೆ ಭೇಟಿ ನೀಡಿದಾಗ ಅವà³à²—ಳಿಗೆ ತಿಳಿಯà³à²¤à³à²¤à²¦à³†<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />ಉದà³à²¯à³‹à²—ದಾತರೠಅಥವಾ ಶಾಲೆಗಳೠಬà³à²°à³Œà²¸à²¿à²‚ಗೠಚಟà³à²µà²Ÿà²¿à²•à³†à²¯à²¨à³à²¨à³ ಟà³à²°à³à²¯à²¾à²•à³ ಮಾಡಬಹà³à²¦à³<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />ಇಂಟರà³à²¨à³†à²Ÿà³ ಸೇವೆ ಒದಗಿಸà³à²µà²µà²°à³ ವೆಬೠಟà³à²°à²¾à²«à²¿à²•à³ ಅನà³à²¨à³ ಮೇಲà³à²µà²¿à²šà²¾à²°à²£à³† ಮಾಡಬಹà³à²¦à³<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">ಎಚà³à²šà²°à²¿à²•à³†à²—ಳನà³à²¨à³ ಆನೠಮಾಡಿ</translation>
<translation id="4838327282952368871">ಕನಸà³</translation>
<translation id="4840250757394056958">ನಿಮà³à²® Chrome ಇತಿಹಾಸವನà³à²¨à³ ವೀಕà³à²·à²¿à²¸à²¿</translation>
@@ -1221,12 +1253,12 @@
<translation id="4854362297993841467">ಈ ವಿತರಣೆಯ ವಿಧಾನ ಲಭà³à²¯à²µà²¿à²²à³à²². ಬೇರೊಂದೠವಿಧಾನವನà³à²¨à³ ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿.</translation>
<translation id="4854853140771946034">Google Keep ನಲà³à²²à²¿ ಹೊಸ ಟಿಪà³à²ªà²£à²¿à²¯à²¨à³à²¨à³ ತà³à²µà²°à²¿à²¤à²µà²¾à²—ಿ ರಚಿಸಿ</translation>
<translation id="485902285759009870">ಕೋಡೠಪರಿಶೀಲಿಸಲಾಗà³à²¤à³à²¤à²¿à²¦à³†...</translation>
+<translation id="4866506163384898554">ನಿಮà³à²® ಕರà³à²¸à²°à³ ತೋರಿಸಲೠ|<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| ಒತà³à²¤à²¿à²°à²¿</translation>
<translation id="4876188919622883022">ಸರಳೀಕೃತ ವೀಕà³à²·à²£à³†</translation>
<translation id="4876305945144899064">ಯಾವà³à²¦à³‡ ಬಳಕೆದಾರರ ಹೆಸರಿಲà³à²²</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{ಒಂದೂ ಇಲà³à²²}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}one{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831"><ph name="TEXT" /> ಹà³à²¡à³à²•à²¾à²Ÿ</translation>
<translation id="4879491255372875719">ಸà³à²µà²¯à²‚ಚಾಲಿತ (ಡಿಫಾಲà³à²Ÿà³)</translation>
-<translation id="4879725228911483934">ವಿಂಡೋಗಳನà³à²¨à³ ತೆರೆಯಿರಿ ಮತà³à²¤à³ ನಿಮà³à²® ಸà³à²•à³à²°à³€à²¨à³â€Œà²—ಳ ಮೇಲೆ ಇರಿಸಿ</translation>
<translation id="4880827082731008257">ಹà³à²¡à³à²•à²¾à²Ÿ ಇತಿಹಾಸ</translation>
<translation id="4881695831933465202">ತೆರೆ</translation>
<translation id="4885256590493466218">ಚೆಕà³à²”ಟà³â€Œà²¨à²²à³à²²à²¿ <ph name="CARD_DETAIL" /> ಮೂಲಕ ಪಾವತಿಸಿ</translation>
@@ -1235,6 +1267,7 @@
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">ಒಂಭತà³à²¤à²¨à³‡ ರೋಲà³</translation>
<translation id="4901778704868714008">ಉಳಿಸಿ...</translation>
+<translation id="4905659621780993806">ನಿಮà³à²® ನಿರà³à²µà²¾à²¹à²•à²°à³ <ph name="DATE" /> ರಂದೠ<ph name="TIME" /> ಸಮಯಕà³à²•à³† ನಿಮà³à²® ಸಾಧನವನà³à²¨à³ ಸà³à²µà²¯à²‚ಚಾಲಿತವಾಗಿ ಮರà³à²ªà³à²°à²¾à²°à²‚ಭಿಸà³à²¤à³à²¤à²¾à²°à³†. ನಿಮà³à²® ಸಾಧನ ಮರà³à²ªà³à²°à²¾à²°à²‚ಭವಾಗà³à²µ ಮೊದಲೠಯಾವà³à²¦à³‡ ತೆರೆದಿರà³à²µ à²à²Ÿà²‚ಗಳನà³à²¨à³ ಉಳಿಸಿ.</translation>
<translation id="4913987521957242411">ಮೇಲಿನ ಎಡಭಾಗದಲà³à²²à²¿ ತೂತೠಮಾಡಿ</translation>
<translation id="4918221908152712722"><ph name="APP_NAME" /> ಆà³à²¯à²ªà³ ಅನà³à²¨à³ ಇನà³â€Œà²¸à³à²Ÿà²¾à²²à³â€Œ ಮಾಡಿ (ಡೌನà³â€Œà²²à³‹à²¡à³â€Œ ಮಾಡà³à²µ ಅಗತà³à²¯à²µà²¿à²²à³à²²)</translation>
<translation id="4923459931733593730">ಪಾವತಿ</translation>
@@ -1243,6 +1276,7 @@
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, ಹà³à²¡à³à²•à²²à³ ಟà³à²¯à²¾à²¬à³ ಒತà³à²¤à²¿ ನಂತರ ನಮೂದಿಸಿ</translation>
<translation id="4930153903256238152">ದೊಡà³à²¡ ಸಾಮರà³à²¥à³à²¯</translation>
+<translation id="4940163644868678279">Chrome ನಲà³à²²à²¿ ಅದೃಶà³à²¯ ಮೋಡà³</translation>
<translation id="4943872375798546930">ಯಾವà³à²¦à³‡ ಫಲಿತಾಂಶಗಳಿಲà³à²²</translation>
<translation id="4950898438188848926">ಟà³à²¯à²¾à²¬à³ ಬದಲಿಸà³à²µ ಬಟನà³, ತೆರೆದಿರà³à²µ ಟà³à²¯à²¾à²¬à³, <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /> ಗೆ ಬದಲಾಯಿಸಲೠEnter ಒತà³à²¤à²¿à²°à²¿</translation>
<translation id="495170559598752135">ಕà³à²°à²¿à²¯à³†à²—ಳà³</translation>
@@ -1252,6 +1286,7 @@
<translation id="4968522289500246572">ಈ ಆà³à²¯à²ªà³ ಅನà³à²¨à³ ಮೊಬೈಲà³â€Œà²—ಾಗಿ ವಿನà³à²¯à²¾à²¸à²—ೊಳಿಸಲಾಗಿದೆ ಮತà³à²¤à³ ಸರಿಯಾಗಿ ಮರà³à²—ಾತà³à²°à²—ೊಳಿಸಲೠಸಾಧà³à²¯à²µà²¾à²—ದಿರಬಹà³à²¦à³. ಆà³à²¯à²ªà³ ಸಮಸà³à²¯à³†à²—ಳನà³à²¨à³ ಎದà³à²°à²¿à²¸à²¬à²¹à³à²¦à³ ಅಥವಾ ಮರà³à²ªà³à²°à²¾à²°à²‚ಭಿಸಬಹà³à²¦à³.</translation>
<translation id="4969341057194253438">ರೆಕಾರà³à²¡à²¿à²‚ಗೠಅನà³à²¨à³ ಅಳಿಸಿ</translation>
<translation id="4973922308112707173">ಮೇಲà³à²­à²¾à²—ದಲà³à²²à²¿ ಎರಡೠತೂತà³à²—ಳನà³à²¨à³ ಮಾಡಿ</translation>
+<translation id="4976702386844183910">ಕೊನೆಯದಾಗಿ <ph name="DATE" /> ರಂದೠಭೇಟಿ ನೀಡಲಾಗಿದೆ</translation>
<translation id="4984088539114770594">ಮೈಕà³à²°à³‹à²«à³‹à²¨à³ ಅನà³à²¨à³ ಬಳಸà³à²µà³à²¦à³‡?</translation>
<translation id="4984339528288761049">Prc5 (Envelope)</translation>
<translation id="4989163558385430922">ಎಲà³à²²à²µà²¨à³à²¨à³‚ ನೋಡಿ</translation>
@@ -1313,6 +1348,7 @@
<translation id="5138227688689900538">ಕಡಿಮೆ ತೋರಿಸಿ</translation>
<translation id="5145883236150621069">ನೀತಿ ಪà³à²°à²¤à²¿à²•à³à²°à²¿à²¯à³†à²¯à²²à³à²²à²¿ ದೋಷದ ಕೋಡೠಅಸà³à²¤à²¿à²¤à³à²µà²¦à²²à³à²²à²¿à²¦à³†</translation>
<translation id="5146995429444047494"><ph name="ORIGIN" /> ಗಾಗಿ ಅಧಿಸೂಚನೆಗಳನà³à²¨à³ ನಿರà³à²¬à²‚ಧಿಸಲಾಗಿದೆ</translation>
+<translation id="514704532284964975">ನಿಮà³à²® ಫೋನà³â€Œà²¨ ಮೂಲಕ ನೀವೠಟà³à²¯à²¾à²ªà³ ಮಾಡà³à²µ NFC ಸಾಧನಗಳಲà³à²²à²¿à²¨ ಮಾಹಿತಿಯನà³à²¨à³ ವೀಕà³à²·à²¿à²¸à²²à³ ಮತà³à²¤à³ ಬದಲಾಯಿಸಲೠ<ph name="URL" /> ಬಯಸà³à²¤à³à²¤à²¦à³†</translation>
<translation id="5148809049217731050">ಮà³à²– ಮೇಲಕà³à²•à³†</translation>
<translation id="515292512908731282">C4 (Envelope)</translation>
<translation id="5158275234811857234">ಕವರà³</translation>
@@ -1337,6 +1373,7 @@
<translation id="5215116848420601511">Google Pay ಅನà³à²¨à³ ಬಳಸà³à²µ ಪಾವತಿ ವಿಧಾನಗಳೠಮತà³à²¤à³ ವಿಳಾಸಗಳà³</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">ಟà³à²°à³‡ 13</translation>
+<translation id="5216942107514965959">ಇಂದೠಕೊನೆಯಾದಾಗಿ ಭೇಟಿ ನೀಡಲಾಗಿದೆ</translation>
<translation id="5222812217790122047">ಇಮೇಲೠಅಗತà³à²¯à²µà²¿à²¦à³†</translation>
<translation id="5230733896359313003">ಶಿಪà³à²ªà²¿à²‚ಗೠವಿಳಾಸ</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1357,7 +1394,6 @@
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">ಡಾಕà³à²¯à³à²®à³†à²‚ಟà³â€Œ ಗà³à²£à²²à²•à³à²·à²£à²—ಳà³</translation>
<translation id="528468243742722775">ಅಂತà³à²¯</translation>
-<translation id="5284909709419567258">ನೆಟà³â€Œà²µà²°à³à²•à³ ವಿಳಾಸಗಳà³</translation>
<translation id="5285570108065881030">ಉಳಿಸಿದ ಎಲà³à²² ಪಾಸà³â€Œà²µà²°à³à²¡à³â€Œà²—ಳನà³à²¨à³ ತೋರಿಸಿ</translation>
<translation id="5287240709317226393">ಕà³à²•à³€à²¸à³ ಅನà³à²¨à³ ತೋರಿಸಿ</translation>
<translation id="5287456746628258573">ಈ ಸೈಟೠಹಳೆಯ ಸà³à²°à²•à³à²·à²¤à²¾ ಕಾನà³à²«à²¿à²—ರೇಶನೠಅನà³à²¨à³ ಬಳಸà³à²¤à³à²¤à²¦à³†, ಇದೠನಿಮà³à²® ಮಾಹಿತಿಯನà³à²¨à³ ಈ ಸೈಟà³â€Œà²—ೆ ಕಳà³à²¹à²¿à²¸à²¿à²¦à²¾à²— ಅದನà³à²¨à³ (ಉದಾಹರಣೆಗೆ, ಪಾಸà³â€Œà²µà²°à³à²¡à³â€Œà²—ಳೠಅಥವಾ ಕà³à²°à³†à²¡à²¿à²Ÿà³ ಕಾರà³à²¡à³ ಸಂಖà³à²¯à³†à²—ಳà³) ಬಹಿರಂಗಪಡಿಸಬಹà³à²¦à³.</translation>
@@ -1441,6 +1477,7 @@
<translation id="5556459405103347317">ಮರà³à²²à³‹à²¡à³â€Œ</translation>
<translation id="5560088892362098740">ಅವಧಿ ಮà³à²—ಿಯà³à²µ ದಿನಾಂಕ</translation>
<translation id="55635442646131152">ಡಾಕà³à²¯à³à²®à³†à²‚ಟà³â€Œ ಔಟà³â€Œà²²à³ˆà²¨à³â€Œ</translation>
+<translation id="5565613213060953222">ಅಜà³à²žà²¾à²¤ ಟà³à²¯à²¾à²¬à³ ತೆರೆಯಿರಿ</translation>
<translation id="5565735124758917034">ಸಕà³à²°à²¿à²¯</translation>
<translation id="5570825185877910964">ಖಾತೆಯನà³à²¨à³ ಸಂರಕà³à²·à²¿à²¸à²¿</translation>
<translation id="5571083550517324815">ಈ ವಿಳಾಸದಿಂದ ಪಿಕಪೠಮಾಡಲೠಸಾಧà³à²¯à²µà²¿à²²à³à²². ಬೇರೊಂದೠವಿಳಾಸವನà³à²¨à³ ಆಯà³à²•à³† ಮಾಡಿ.</translation>
@@ -1523,6 +1560,7 @@
<translation id="5869522115854928033">ಉಳಿಸಲಾದ ಪಾಸà³â€Œà²µà²°à³à²¡à³â€Œà²—ಳà³</translation>
<translation id="5873013647450402046">ಇದೠನೀವೇ ಎಂದೠದೃಢೀಕರಿಸಲೠನಿಮà³à²® ಬà³à²¯à²¾à²‚ಕೠಬಯಸà³à²¤à³à²¤à²¦à³†.</translation>
<translation id="5887400589839399685">ಕಾರà³à²¡à³ ಉಳಿಸಲಾಗಿದೆ</translation>
+<translation id="5887687176710214216">ಕೊನೆಯದಾಗಿ ನಿನà³à²¨à³† ಭೇಟಿ ನೀಡಲಾಗಿದೆ</translation>
<translation id="5895138241574237353">ಮರà³à²ªà³à²°à²¾à²°à²‚ಭಿಸಿ</translation>
<translation id="5895187275912066135">ರಂದೠನೀಡಲಾಗಿದೆ</translation>
<translation id="5901630391730855834">ಹಳದಿ</translation>
@@ -1536,6 +1574,7 @@
<translation id="5921639886840618607">Google ಖಾತೆಯಲà³à²²à²¿ ಕಾರà³à²¡à³ ಅನà³à²¨à³ ಉಳಿಸಬೇಕೇ?</translation>
<translation id="5922853866070715753">ಬಹà³à²¤à³‡à²• ಮà³à²—ಿದಿದೆ</translation>
<translation id="5932224571077948991">ಅತಿಕà³à²°à²®à²£à²•à²¾à²°à²¿à²¯à²¾à²—ಿರà³à²µ ಅಥವಾ ತಪà³à²ªà³à²¦à²¾à²°à²¿à²—ೆಳೆಯà³à²µ ಜಾಹೀರಾತà³à²—ಳನà³à²¨à³ ಸೈಟೠತೋರಿಸà³à²¤à³à²¤à²¦à³†</translation>
+<translation id="5938153366081463283">ವರà³à²šà³à²µà²²à³ ಕಾರà³à²¡à³ ಅನà³à²¨à³ ಸೇರಿಸಿ</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347"><ph name="SITE_NAME" /> ತೆರೆಯಲಾಗà³à²¤à³à²¤à²¿à²¦à³†â€¦</translation>
<translation id="5951495562196540101">ಗà³à²°à²¾à²¹à²•à²° ಖಾತೆಯ ಮೂಲಕ ನೋಂದಣಿ ಮಾಡಲೠಸಾಧà³à²¯à²µà²¿à²²à³à²² (ಪà³à²¯à²¾à²•à³‡à²œà³ ಮಾಡಲಾದ ಪರವಾನಗಿ ಲಭà³à²¯à²µà²¿à²¦à³†).</translation>
@@ -1600,6 +1639,7 @@
<translation id="6120179357481664955">ನಿಮà³à²® UPI à²à²¡à²¿ ನೆನಪಿದೆಯೇ?</translation>
<translation id="6124432979022149706">Chrome ಎಂಟರà³â€Œà²ªà³à²°à³ˆà²¸à³ ಕನೆಕà³à²Ÿà²°à³â€Œà²—ಳà³</translation>
<translation id="6127379762771434464">à²à²Ÿà²‚ ತೆಗೆದà³à²¹à²¾à²•à²²à²¾à²—ಿದೆ</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Chrome ನಲà³à²²à²¿ ಅದೃಶà³à²¯ ಮೋಡೠಕà³à²°à²¿à²¤à³ ಇನà³à²¨à²·à³à²Ÿà³ ತಿಳಿಯಿರಿ<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">ಯಾವà³à²¦à³‡ ಕೇಬಲà³â€Œà²—ಳನà³à²¨à³ ಪರಿಶೀಲಿಸಿ. ನೀವೠಬಳಸà³à²¤à³à²¤à²¿à²°à²¬à²¹à³à²¦à²¾à²¦ ಯಾವà³à²¦à³‡ ರೂಟರà³â€Œà²—ಳà³, ಮೋಡೆಮà³â€Œà²—ಳೠಅಥವಾ ಇತರ ನೆಟà³â€Œà²µà²°à³à²•à³ ಸಾಧನಗಳನà³à²¨à³ ರೀಬೂಟೠಮಾಡಿ.</translation>
<translation id="614940544461990577">ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿:</translation>
<translation id="6150036310511284407">ಎಡಭಾಗದಲà³à²²à²¿ ಮೂರೠತೂತà³à²—ಳನà³à²¨à³ ಮಾಡಿ</translation>
@@ -1611,7 +1651,6 @@
<translation id="6169916984152623906">ನೀವೀಗ ಖಾಸಗಿಯಾಗಿ ಬà³à²°à³Œà²¸à³ ಮಾಡಬಹà³à²¦à³. ಈ ಸಾಧನವನà³à²¨à³ ಬಳಸà³à²µ ಬೇರೆ ಯಾರಿಗೂ ನಿಮà³à²® ಚಟà³à²µà²Ÿà²¿à²•à³† ಕಾಣಿಸà³à²µà³à²¦à²¿à²²à³à²². ಆದರೂ, ಡೌನà³â€Œà²²à³‹à²¡à³â€Œà²—ಳೠಮತà³à²¤à³ ಬà³à²•à³â€Œà²®à²¾à²°à³à²•à³â€Œà²—ಳೠಉಳಿದಿರà³à²¤à³à²¤à²µà³†.</translation>
<translation id="6177128806592000436">ಈ ಸೈಟà³â€Œà²—ೆ ನಿಮà³à²® ಸಂಪರà³à²•à²µà³ ಸà³à²°à²•à³à²·à²¿à²¤à²µà²¾à²—ಿಲà³à²²</translation>
<translation id="6180316780098470077">ಮರà³à²ªà³à²°à²¯à²¤à³à²¨à²¦ ಮಧà³à²¯à²‚ತರ</translation>
-<translation id="619448280891863779">ನಿಮà³à²® ಸà³à²•à³à²°à³€à²¨à³â€Œà²—ಳಲà³à²²à²¿ ವಿಂಡೋಗಳನà³à²¨à³ ತೆರೆಯಲೠಮತà³à²¤à³ ಇರಿಸಲೠಕೇಳಬಹà³à²¦à³</translation>
<translation id="6196640612572343990">ಥರà³à²¡à³ ಪಾರà³à²Ÿà²¿ ಕà³à²•à³€à²—ಳನà³à²¨à³ ನಿರà³à²¬à²‚ಧಿಸಿ</translation>
<translation id="6203231073485539293">ನಿಮà³à²® ಇಂಟರà³à²¨à³†à²Ÿà³ ಸಂಪರà³à²•à²µà²¨à³à²¨à³ ಪರಿಶೀಲಿಸಿ</translation>
<translation id="6218753634732582820">Chromium ನಿಂದ ವಿಳಾಸವನà³à²¨à³ ತೆಗೆದà³à²¹à²¾à²•à³à²µà³à²¦à³‡?</translation>
@@ -1634,7 +1673,7 @@
<translation id="6272383483618007430">Google ಅಪà³â€à²¡à³‡à²Ÿà³</translation>
<translation id="6276112860590028508">ನಿಮà³à²® ಓದà³à²µ ಪಟà³à²Ÿà²¿à²¯ ಪà³à²Ÿà²—ಳೠಇಲà³à²²à²¿ ಕಾಣಿಸಿಕೊಳà³à²³à³à²¤à³à²¤à²µà³†</translation>
<translation id="627746635834430766">ಮà³à²‚ದಿನ ಬಾರಿ ವೇಗವಾಗಿ ಪಾವತಿಸಲà³, ನಿಮà³à²® ಕಾರà³à²¡à³â€Œ ಮತà³à²¤à³ ಬಿಲà³à²²à²¿à²‚ಗೠವಿಳಾಸವನà³à²¨à³ ನಿಮà³à²® Google ಖಾತೆಯಲà³à²²à²¿ ಉಳಿಸಿ.</translation>
-<translation id="6279098320682980337">ವರà³à²šà³à²µà²²à³ ಕಾರà³à²¡à³ ಸಂಖà³à²¯à³†à²¯à²¨à³à²¨à³ ಭರà³à²¤à²¿ ಮಾಡಿಲà³à²²à²µà³‡? ಕಾರà³à²¡à³ ವಿವರಗಳನà³à²¨à³ ನಕಲಿಸಲೠಕà³à²²à²¿à²•à³ ಮಾಡಿ</translation>
+<translation id="6279183038361895380">ನಿಮà³à²® ಕರà³à²¸à²°à³ ತೋರಿಸಲೠ|<ph name="ACCELERATOR" />| ಒತà³à²¤à²¿</translation>
<translation id="6280223929691119688">ಈ ವಿಳಾಸಕà³à²•à³† ತಲà³à²ªà²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¿à²²à³à²². ಬೇರೊಂದೠವಿಳಾಸವನà³à²¨à³ ಆಯà³à²•à³† ಮಾಡಿ.</translation>
<translation id="6282194474023008486">ಪೋಸà³à²Ÿà²²à³ ಕೋಡà³</translation>
<translation id="6285507000506177184">Chrome ಬಟನà³â€Œà²¨à²²à³à²²à²¿ ಡೌನà³â€Œà²²à³‹à²¡à³â€Œà²—ಳನà³à²¨à³ ನಿರà³à²µà²¹à²¿à²¸à²¿, ನೀವೠChrome ನಲà³à²²à²¿ ಡೌನà³â€Œà²²à³‹à²¡à³ ಮಾಡಿರà³à²µ ಫೈಲà³â€Œà²—ಳನà³à²¨à³ ನಿರà³à²µà²¹à²¿à²¸à²²à³ Enter ಒತà³à²¤à²¿à²°à²¿</translation>
@@ -1642,7 +1681,8 @@
<translation id="6290238015253830360">ನೀವೠಸಲಹೆ ನೀಡಿರà³à²µ ಲೇಖನಗಳೠಇಲà³à²²à²¿ ಕಾಣಿಸಿಕೊಳà³à²³à³à²¤à³à²¤à²µà³†</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
-<translation id="6302269476990306341">Chrome ನಲà³à²²à²¿à²¨ Google ಅಸಿಸà³à²Ÿà³†à²‚ಟೠನಿಲà³à²²à³à²¤à³à²¤à²¿à²¦à³†</translation>
+<translation id="6300452962057769623">{0,plural, =0{ನಿಮà³à²® ಸಾಧನವೠಈಗ ಮರà³à²ªà³à²°à²¾à²°à²‚ಭವಾಗà³à²¤à³à²¤à²¦à³†}=1{ನಿಮà³à²® ಸಾಧನವೠ1 ಸೆಕೆಂಡà³â€Œà²¨à²²à³à²²à²¿ ಮರà³à²ªà³à²°à²¾à²°à²‚ಭವಾಗà³à²¤à³à²¤à²¦à³†}one{ನಿಮà³à²® ಸಾಧನವೠ# ಸೆಕೆಂಡà³â€Œà²—ಳಲà³à²²à²¿ ಮರà³à²ªà³à²°à²¾à²°à²‚ಭವಾಗà³à²¤à³à²¤à²¦à³†}other{ನಿಮà³à²® ಸಾಧನವೠ# ಸೆಕೆಂಡà³â€Œà²—ಳಲà³à²²à²¿ ಮರà³à²ªà³à²°à²¾à²°à²‚ಭವಾಗà³à²¤à³à²¤à²¦à³†}}</translation>
+<translation id="6302269476990306341">Chrome ನಲà³à²²à²¿à²¨ Google Assistant ನಿಲà³à²²à³à²¤à³à²¤à²¿à²¦à³†</translation>
<translation id="6305205051461490394"><ph name="URL" /> ತಲà³à²ªà²²à²¾à²—à³à²µà³à²¦à²¿à²²à³à²².</translation>
<translation id="6312113039770857350">ವೆಬà³â€Œà²ªà³à²Ÿ ಲಭà³à²¯à²µà²¿à²²à³à²²</translation>
<translation id="63172326633386613">ಪà³à²°à²µà³‡à²¶à²¿à²¸à³à²µà²¿à²•à³† ಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳನà³à²¨à³ ನಿರà³à²µà²¹à²¿à²¸à²¿</translation>
@@ -1715,6 +1755,7 @@
<translation id="6529602333819889595">&amp;ಅಳಿಸà³à²µà³à²¦à²¨à³à²¨à³ ಮತà³à²¤à³†à²®à²¾à²¡à³</translation>
<translation id="6545864417968258051">ಬà³à²²à³‚ಟೂತೠಸà³à²•à³à²¯à²¾à²¨à²¿à²‚ಗà³</translation>
<translation id="6547208576736763147">ಎಡಭಾಗದಲà³à²²à²¿ ಎರಡೠತೂತà³à²—ಳನà³à²¨à³ ಮಾಡಿ</translation>
+<translation id="6554732001434021288">ಕೊನೆಯದಾಗಿ <ph name="NUM_DAYS" /> ದಿನಗಳ ಹಿಂದೆ ಭೇಟಿ ನೀಡಲಾಗಿದೆ</translation>
<translation id="6556866813142980365">ಪà³à²¨à²ƒ ಮಾಡà³</translation>
<translation id="6569060085658103619">ನೀವೠವಿಸà³à²¤à²°à²£à³† ಪà³à²Ÿà²µà²¨à³à²¨à³ ವೀಕà³à²·à²¿à²¸à³à²¤à³à²¤à²¿à²°à³à²µà²¿à²°à²¿</translation>
<translation id="6573200754375280815">ಬಲಭಾಗದಲà³à²²à²¿ ಎರಡೠತೂತà³à²—ಳನà³à²¨à³ ಮಾಡಿ</translation>
@@ -1775,7 +1816,6 @@
<translation id="6757797048963528358">ನಿಮà³à²® ಸಾಧನವೠನಿದà³à²°à²¾à²µà²¸à³à²¥à³†à²—ೆ ಹೋಗಿದೆ.</translation>
<translation id="6767985426384634228">ವಿಳಾಸ ಅಪà³â€Œà²¡à³‡à²Ÿà³ ಮಾಡಬೇಕೇ?</translation>
<translation id="6768213884286397650">Hagaki (Postcard)</translation>
-<translation id="6774185088257932239">ಅಜà³à²žà²¾à²¤ ಮೋಡೠಕà³à²°à²¿à²¤à³ <ph name="BEGIN_LINK" />ಇನà³à²¨à²·à³à²Ÿà³ ತಿಳಿಯಿರಿ<ph name="END_LINK" /></translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">ನೇರಳೆ</translation>
<translation id="6786747875388722282">ವಿಸà³à²¤à²°à²£à³†à²—ಳà³</translation>
@@ -1859,7 +1899,6 @@
<translation id="706295145388601875">Chrome ಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳಲà³à²²à²¿ ವಿಳಾಸಗಳನà³à²¨à³ ಸೇರಿಸಿ ಮತà³à²¤à³ ನಿರà³à²µà²¹à²¿à²¸à²¿</translation>
<translation id="7064851114919012435">ಸಂಪರà³à²• ಮಾಹಿತಿ</translation>
<translation id="7068733155164172741"><ph name="OTP_LENGTH" />-ಅಂಕಿಯ ಕೋಡೠನಮೂದಿಸಿ</translation>
-<translation id="7070090581017165256">ಈ ಸೈಟೠಕà³à²°à²¿à²¤à³</translation>
<translation id="70705239631109039">ನಿಮà³à²® ಕನೆಕà³à²·à²¨à³ ಪೂರà³à²£ ಸà³à²°à²•à³à²·à²¤à³†à²¯à²¨à³à²¨à³ ಹೊಂದಿಲà³à²²</translation>
<translation id="7075452647191940183">ವಿನಂತಿಯೠತೀರಾ ದೊಡà³à²¡à²¦à²¾à²—ಿದೆ</translation>
<translation id="7079718277001814089">ಈ ಸೈಟೠಮಾಲà³â€Œâ€Œà²µà³‡à²°à³ ಹೊಂದಿದೆ</translation>
@@ -1876,6 +1915,12 @@
<translation id="7111012039238467737">(ಮಾನà³à²¯à²µà²¾à²—ಿದೆ)</translation>
<translation id="7118618213916969306">ಕà³à²²à²¿à²ªà³â€Œà²¬à³‹à²°à³à²¡à³ URL ಗಾಗಿ ಹà³à²¡à³à²•à²¿, <ph name="SHORT_URL" /></translation>
<translation id="7119414471315195487">ಇತರ ಟà³à²¯à²¾à²¬à³â€Œà²—ಳನà³à²¨à³ ಅಥವಾ ಪà³à²°à³‹à²—à³à²°à²¾à²‚ಗಳನà³à²¨à³ ಮà³à²šà³à²šà²¿</translation>
+<translation id="7129355289156517987">ನೀವೠಎಲà³à²²à²¾ Chromium ಅದೃಶà³à²¯ ಟà³à²¯à²¾à²¬à³â€Œà²—ಳನà³à²¨à³ ಮà³à²šà³à²šà²¿à²¦ ನಂತರ, ಆ ಟà³à²¯à²¾à²¬à³â€Œà²—ಳಲà³à²²à²¿à²¨ ನಿಮà³à²® ಚಟà³à²µà²Ÿà²¿à²•à³†à²¯à²¨à³à²¨à³ ಈ ಸಾಧನದಿಂದ ತೆರವà³à²—ೊಳಿಸಲಾಗà³à²¤à³à²¤à²¦à³†:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ಬà³à²°à³Œà²¸à²¿à²‚ಗೠಚಟà³à²µà²Ÿà²¿à²•à³†<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ಹà³à²¡à³à²•à²¾à²Ÿà²¦ ಇತಿಹಾಸ<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ಫಾರà³à²®à³â€Œà²—ಳಲà³à²²à²¿ ನಮೂದಿಸಿದ ಮಾಹಿತಿ<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">ಈ ವಿಳಾಸಕà³à²•à³† ರವಾನಿಸಲೠಸಾಧà³à²¯à²µà²¿à²²à³à²². ಬೇರೊಂದೠವಿಳಾಸವನà³à²¨à³ ಆಯà³à²•à³† ಮಾಡಿ.</translation>
<translation id="7132939140423847331">ನಿಮà³à²® ನಿರà³à²µà²¾à²¹à²•à²°à³ ಈ ಡೇಟಾವನà³à²¨à³ ನಕಲಿಸದಂತೆ ನಿಷೇಧಿಸಿದà³à²¦à²¾à²°à³†.</translation>
<translation id="7135130955892390533">ಕಾರà³à²¯à²¨à³€à²¤à²¿ ಸà³à²¥à²¿à²¤à²¿à²¯à²¨à³à²¨à³ ತೋರಿಸಿ</translation>
@@ -1898,6 +1943,7 @@
<translation id="7192203810768312527"><ph name="SIZE" /> ತೆಗೆದà³à²¹à²¾à²•à²¿. ನಿಮà³à²® ನಂತರದ ಭೇಟಿಯ ಸಮಯದಲà³à²²à²¿ ಕೆಲವೠಸೈಟà³â€Œà²—ಳೠನಿಧಾನವಾಗಿ ಲೋಡೠಆಗಬಹà³à²¦à³.</translation>
<translation id="719464814642662924">ವೀಸಾ</translation>
<translation id="7201591969684833065">ನಿಮà³à²® ನಿರà³à²µà²¾à²¹à²•à²°à³ ಇವà³à²—ಳನà³à²¨à³ ನೋಡಬಹà³à²¦à³:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, ಖಾಸಗಿಯಾಗಿ ಬà³à²°à³Œà²¸à³ ಮಾಡಲೠಹೊಸ ಅಜà³à²žà²¾à²¤ ಟà³à²¯à²¾à²¬à³ ಒಂದನà³à²¨à³ ತೆರೆಯಲà³, Tab ಒತà³à²¤à²¿à²°à²¿, ನಂತರ Enter ಒತà³à²¤à²¿à²°à²¿</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> ಭದà³à²°à²¤à³† ಮಾನದಂಡಗಳನà³à²¨à³ ಅನà³à²¸à²°à²¿à²¸à³à²¤à³à²¤à²¿à²²à³à²².</translation>
<translation id="7210993021468939304">ಕಂಟೇನರà³â€Œà²¨à²²à³à²²à²¿ Linux ಚಟà³à²µà²Ÿà²¿à²•à³† ಮತà³à²¤à³ ಕಂಟೇನರà³â€Œà²¨à²²à³à²²à²¿ ಇನà³â€Œà²¸à³à²Ÿà²¾à²²à³ ಮಾಡಬಹà³à²¦à²¾à²¦ ಮತà³à²¤à³ ರನೠಮಾಡಬಹà³à²¦à²¾à²¦ Linux ಆà³à²¯à²ªà³â€Œà²—ಳà³</translation>
@@ -1929,6 +1975,7 @@
<translation id="7304562222803846232">Google ಖಾತೆಯ ಗೌಪà³à²¯à²¤à³† ಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳನà³à²¨à³ ನಿರà³à²µà²¹à²¿à²¸à²¿</translation>
<translation id="7305756307268530424">ನಿಧಾನವಾಗಿ ಪà³à²°à²¾à²°à²‚ಭಿಸಿ</translation>
<translation id="7308436126008021607">ಹಿನà³à²¨à³†à²²à³† ಸಿಂಕà³</translation>
+<translation id="7310392214323165548">ಸಾಧನವನà³à²¨à³ ಶೀಘà³à²°à²¦à²²à³à²²à³‡ ಮರà³à²ªà³à²°à²¾à²°à²‚ಭಿಸಲಾಗà³à²µà³à²¦à³</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">ಸಂಪರà³à²• ಸಹಾಯ</translation>
<translation id="7323804146520582233">ಈ "<ph name="SECTION" />" ವಿಭಾಗವನà³à²¨à³ ಮರೆಮಾಡಿ</translation>
@@ -1936,6 +1983,7 @@
<translation id="7334320624316649418">&amp;ಮರà³à²•à³à²°à²®à²—ೊಳಿಸà³à²µà³à²¦à²¨à³à²¨à³ ಮತà³à²¤à³†à²®à²¾à²¡à³</translation>
<translation id="7335157162773372339">ನಿಮà³à²® ಕà³à²¯à²¾à²®à²°à²¾ ಬಳಸಲೠಕೇಳಬಹà³à²¦à³</translation>
<translation id="7337248890521463931">ಇನà³à²¨à²·à³à²Ÿà³ ಸಾಲà³à²—ಳನà³à²¨à³ ತೋರಿಸಿ</translation>
+<translation id="7337418456231055214">ವರà³à²šà³à²µà²²à³ ಕಾರà³à²¡à³ ಸಂಖà³à²¯à³†à²¯à²¨à³à²¨à³ ತà³à²‚ಬಿಸಿಲà³à²²à²µà³‡? ಕಾರà³à²¡à³ ವಿವರಗಳನà³à²¨à³ ನಕಲಿಸಲೠಕà³à²²à²¿à²•à³ ಮಾಡಿ. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">ನಿಮà³à²® ಪà³à²²à²¾à²Ÿà³â€Œà²«à²¾à²°à³à²®à³â€Œà²¨à²²à³à²²à²¿ ಲಭà³à²¯à²µà²¿à²²à³à²².</translation>
<translation id="733923710415886693">ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²° ಪಾರದರà³à²¶à²•à²¤à³†à²¯ ಮೂಲಕ ಸರà³à²µà²°à³ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà²¨à³à²¨à³ ಬಹಿರಂಗಪಡಿಸಲಾಗಿಲà³à²².</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1958,6 +2006,7 @@
<translation id="7378627244592794276">ಬೇಡ</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">ಅನà³à²µà²¯à²¿à²¸à³à²µà³à²¦à²¿à²²à³à²²</translation>
+<translation id="7388594495505979117">{0,plural, =1{ನಿಮà³à²® ಸಾಧನವೠ1 ನಿಮಿಷದಲà³à²²à²¿ ಮರà³à²ªà³à²°à²¾à²°à²‚ಭವಾಗà³à²¤à³à²¤à²¦à³†}one{ನಿಮà³à²® ಸಾಧನವೠ# ನಿಮಿಷಗಳಲà³à²²à²¿ ಮರà³à²ªà³à²°à²¾à²°à²‚ಭವಾಗà³à²¤à³à²¤à²¦à³†}other{ನಿಮà³à²® ಸಾಧನವೠ# ನಿಮಿಷಗಳಲà³à²²à²¿ ಮರà³à²ªà³à²°à²¾à²°à²‚ಭವಾಗà³à²¤à³à²¤à²¦à³†}}</translation>
<translation id="7390545607259442187">ಕಾರà³à²¡à³ ಅನà³à²¨à³ ದೃಢೀಕರಿಸಿ</translation>
<translation id="7392089738299859607">ವಿಳಾಸವನà³à²¨à³ ಅಪà³â€Œà²¡à³‡à²Ÿà³ ಮಾಡಿ</translation>
<translation id="7399802613464275309">ಸà³à²°à²•à³à²·à²¤à³†à²¯ ಪರಿಶೀಲನೆ</translation>
@@ -1993,6 +2042,12 @@
<translation id="7485870689360869515">ಯಾವà³à²¦à³‡ ಡೇಟಾ ಕಂಡà³à²¬à²‚ದಿಲà³à²².</translation>
<translation id="7495528107193238112">ಈ ವಿಷಯವನà³à²¨à³ ನಿರà³à²¬à²‚ಧಿಸಲಾಗಿದೆ. ಸಮಸà³à²¯à³†à²¯à²¨à³à²¨à³ ಪರಿಹರಿಸಲೠಸೈಟೠಮಾಲೀಕರನà³à²¨à³ ಸಂಪರà³à²•à²¿à²¸à²¿.</translation>
<translation id="7497998058912824456">Doc ರಚಿಸಿ ಬಟನà³, ಹೊಸ Google Doc ಅನà³à²¨à³ ತà³à²µà²°à²¿à²¤à²µà²¾à²—ಿ ರಚಿಸಲೠEnter ಒತà³à²¤à²¿</translation>
+<translation id="7506488012654002225">ಈ ಕೆಳಗಿನ ಮಾಹಿತಿಯನà³à²¨à³ Chromium <ph name="BEGIN_EMPHASIS" />ಉಳಿಸà³à²µà³à²¦à²¿à²²à³à²²<ph name="END_EMPHASIS" />:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ನಿಮà³à²® ಬà³à²°à³Œà²¸à²¿à²‚ಗೠಇತಿಹಾಸ
+ <ph name="LIST_ITEM" />ಕà³à²•à³€à²—ಳೠಮತà³à²¤à³ ಸೈಟೠಡೇಟಾ
+ <ph name="LIST_ITEM" />ಫಾರà³à²®à³â€Œà²—ಳಲà³à²²à²¿ ನಮೂದಿಸಿದ ಮಾಹಿತಿ
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">ಹಿಂತಿರà³à²—ಿಸಲಾದ ನೀತಿಯ ಸಾಧನ à²à²¡à²¿ ಖಾಲಿ ಇದೆ ಅಥವಾ ಪà³à²°à²¸à³à²¤à³à²¤ ಸಾಧನ à²à²¡à²¿à²—ೆ ಹೊಂದಾಣಿಕೆಯಾಗà³à²µà³à²¦à²¿à²²à³à²²</translation>
<translation id="7508870219247277067">ಅವಕಾಡೊ ಹಸಿರà³</translation>
<translation id="7511955381719512146">ನೀವೠಬಳಸà³à²¤à³à²¤à²¿à²°à³à²µ ವೈ-ಫೈಗೆ ನೀವೠ<ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> ಅನà³à²¨à³ ಭೇಟಿ ನೀಡà³à²µ ಅಗತà³à²¯à²µà²¿à²¦à³†.</translation>
@@ -2106,7 +2161,6 @@
<translation id="7813600968533626083">Chrome ನಿಂದ ಫಾರà³à²®à³ ಸಲಹೆಯನà³à²¨à³ ತೆಗೆದà³à²¹à²¾à²•à³à²µà³à²¦à³‡?</translation>
<translation id="781440967107097262">ಕà³à²²à²¿à²ªà³â€Œà²¬à³‹à²°à³à²¡à³ ಅನà³à²¨à³ ಹಂಚಿಕೊಳà³à²³à³à²µà³à²¦à³‡?</translation>
<translation id="7815407501681723534"><ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> ಗೆ '<ph name="SEARCH_STRING" />' ಕಂಡà³à²¬à²‚ದಿದೆ</translation>
-<translation id="782125616001965242">ಈ ಸೈಟೠಕà³à²°à²¿à²¤à³ ಮಾಹಿತಿಯನà³à²¨à³ ತೋರಿಸಿ</translation>
<translation id="782886543891417279">ನೀವೠಬಳಸà³à²¤à³à²¤à²¿à²°à³à²µ ವೈ-ಫೈ (<ph name="WIFI_NAME" />) ಅದರ ಲಾಗಿನೠಪà³à²Ÿà²•à³à²•à³† ನೀವೠಭೇಟಿ ನೀಡà³à²µ ಅಗತà³à²¯à²µà²¿à²¦à³†.</translation>
<translation id="7836231406687464395">Postfix (Envelope)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{ಒಂದೂ ಇಲà³à²²}=1{1 ಆà³à²¯à²ªà³ (<ph name="EXAMPLE_APP_1" />)}=2{2 ಆà³à²¯à²ªà³â€Œà²—ಳೠ(<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}one{# ಆà³à²¯à²ªà³â€Œà²—ಳೠ(<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}other{# ಆà³à²¯à²ªà³â€Œà²—ಳೠ(<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}}</translation>
@@ -2123,7 +2177,6 @@
<translation id="7888575728750733395">ಪà³à²°à²¿à²‚ಟೠಸಲà³à²²à²¿à²•à³† ಉದà³à²¦à³‡à²¶</translation>
<translation id="7894280532028510793">ಕಾಗà³à²£à²¿à²¤ ಸರಿಯಾಗಿದà³à²¦à²°à³†, <ph name="BEGIN_LINK" />ನೆಟà³â€Œà²µà²°à³à²•à³ ಡಯಾಗà³à²¨à²¾à²¸à³à²Ÿà²¿à²•à³à²¸à³â€Œâ€Œ ರನೠಮಾಡಿ ನೋಡಿ<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (Envelope)</translation>
-<translation id="7931318309563332511">ಅಪರಿಚಿತ</translation>
<translation id="793209273132572360">ವಿಳಾಸವನà³à²¨à³ ಅಪà³â€Œà²¡à³‡à²Ÿà³ ಮಾಡಬೇಕೆ?</translation>
<translation id="7932579305932748336">ಹಚà³à²šà³</translation>
<translation id="79338296614623784">ಮಾನà³à²¯à²µà²¾à²¦ ಫೋನೠಸಂಖà³à²¯à³†à²¯à²¨à³à²¨à³ ನಮೂದಿಸಿ</translation>
@@ -2148,13 +2201,14 @@
<translation id="7976214039405368314">ಅತೀ ಹೆಚà³à²šà³ ವಿನಂತಿಗಳà³</translation>
<translation id="7977538094055660992">ಔಟà³â€Œà²ªà³à²Ÿà³ ಸಾಧನ</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">ಇದರೊಂದಿಗೆ ಲಿಂಕà³â€Œ ಮಾಡಲಾಗಿದೆ</translation>
<translation id="798134797138789862">ವರà³à²šà³à²µà²²à³ ರಿಯಾಲಿಟಿ ಸಾಧನಗಳೠಮತà³à²¤à³ ಡೇಟಾವನà³à²¨à³ ಬಳಸಲೠಕೇಳಬಹà³à²¦à³</translation>
<translation id="7984945080620862648">ನೀವೠಸದà³à²¯à²•à³à²•à³† <ph name="SITE" /> ಗೆ ಭೇಟಿ ನೀಡಲೠಸಾಧà³à²¯à²µà²¿à²²à³à²². à²à²•à³†à²‚ದರೆ, Chrome ಪà³à²°à²•à³à²°à²¿à²¯à³†à²—ೊಳಿಸಲೠಸಾಧà³à²¯à²µà²¿à²²à³à²²à²¦ ಸಂಘರà³à²·à²¨à³€à²¯ ರà³à²œà³à²µà²¾à²¤à³à²—ಳನà³à²¨à³ ವೆಬà³â€Œà²¸à³ˆà²Ÿà³ ಕಳà³à²¹à²¿à²¸à²¿à²¦à³†. ನೆಟà³â€Œà²µà²°à³à²•à³ ದೋಷಗಳೠಮತà³à²¤à³ ಆಕà³à²°à²®à²£à²—ಳೠತಾತà³à²•à²¾à²²à²¿à²•à²µà²¾à²—ಿರà³à²¤à³à²¤à²µà³†, ಹೀಗಾಗಿ ಈ ಪà³à²Ÿà²µà³ ಸà³à²µà²²à³à²ª ಸಮಯದ ನಂತರ ಕಾರà³à²¯ ನಿರà³à²µà²¹à²¿à²¸à²¬à²¹à³à²¦à³.</translation>
-<translation id="79859296434321399">ವರà³à²§à²¿à²¤ ನೈಜತೆಯ ವಿಷಯವನà³à²¨à³ ವೀಕà³à²·à²¿à²¸à²²à³, ARCore ಅನà³à²¨à³ ಇನà³â€Œà²¸à³à²Ÿà²¾à²²à³ ಮಾಡಿ</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">ಬೈಂಡೠಮಾಡಿ</translation>
<translation id="7992044431894087211"><ph name="APPLICATION_TITLE" /> ಜೊತೆ ಸà³à²•à³à²°à³€à²¨à³â€Œâ€Œ ಹಂಚಿಕೊಳà³à²³à³à²µà³à²¦à²¨à³à²¨à³ ಪà³à²¨à²°à²¾à²°à²‚ಭಿಸಲಾಗಿದೆ</translation>
<translation id="7995512525968007366">ನಿರà³à²¦à²¿à²·à³à²Ÿà²ªà²¡à²¿à²¸à²²à²¾à²—ಿಲà³à²²</translation>
+<translation id="7998269595945679889">ಅಜà³à²žà²¾à²¤ ಟà³à²¯à²¾à²¬à³ ಬಟನೠತೆರೆಯಿರಿ, ಖಾಸಗಿಯಾಗಿ ಬà³à²°à³Œà²¸à³ ಮಾಡಲೠಹೊಸ ಅಜà³à²žà²¾à²¤ ಟà³à²¯à²¾à²¬à³ ತೆರೆಯಲೠEnter ಒತà³à²¤à²¿à²°à²¿</translation>
<translation id="800218591365569300">ಮೆಮೊರಿ ಮà³à²•à³à²¤à²—ೊಳಿಸಲೠಇತರ ಟà³à²¯à²¾à²¬à³â€Œà²—ಳನà³à²¨à³ ಅಥವಾ ಪà³à²°à³‹à²—à³à²°à²¾à²‚ಗಳನà³à²¨à³ ಮà³à²šà³à²šà²²à³ ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿.</translation>
<translation id="8004582292198964060">ಬà³à²°à³Œà²¸à²°à³</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{ಈ ಕಾರà³à²¡à³ ಮತà³à²¤à³ ಅದರ ಬಿಲà³à²²à²¿à²‚ಗೠವಿಳಾಸವನà³à²¨à³ ಉಳಿಸಲಾಗà³à²¤à³à²¤à²¦à³†. ನೀವೠ<ph name="USER_EMAIL" /> ಗೆ ಸೈನೠಇನೠಮಾಡಿದಾಗ ಅದನà³à²¨à³ ಬಳಸಲೠನಿಮಗೆ ಸಾಧà³à²¯à²µà²¾à²—à³à²¤à³à²¤à²¦à³†.}one{ಈ ಕಾರà³à²¡à³â€Œà²—ಳೠಮತà³à²¤à³ ಅವà³à²—ಳ ಬಿಲà³à²²à²¿à²‚ಗೠವಿಳಾಸಗಳನà³à²¨à³ ಉಳಿಸಲಾಗà³à²¤à³à²¤à²¦à³†. ನೀವೠ<ph name="USER_EMAIL" /> ಗೆ ಸೈನೠಇನೠಮಾಡಿದಾಗ ಅವà³à²—ಳನà³à²¨à³ ಬಳಸಲೠನಿಮಗೆ ಸಾಧà³à²¯à²µà²¾à²—à³à²¤à³à²¤à²¦à³†.}other{ಈ ಕಾರà³à²¡à³â€Œà²—ಳೠಮತà³à²¤à³ ಅವà³à²—ಳ ಬಿಲà³à²²à²¿à²‚ಗೠವಿಳಾಸಗಳನà³à²¨à³ ಉಳಿಸಲಾಗà³à²¤à³à²¤à²¦à³†. ನೀವೠ<ph name="USER_EMAIL" /> ಗೆ ಸೈನೠಇನೠಮಾಡಿದಾಗ ಅವà³à²—ಳನà³à²¨à³ ಬಳಸಲೠನಿಮಗೆ ಸಾಧà³à²¯à²µà²¾à²—à³à²¤à³à²¤à²¦à³†.}}</translation>
@@ -2214,6 +2268,7 @@
<translation id="8202370299023114387">ಸಂಘರà³à²·</translation>
<translation id="8206978196348664717">Prc4 (Envelope)</translation>
<translation id="8211406090763984747">ಸಂಪರà³à²• ಸà³à²°à²•à³à²·à²¿à²¤à²µà²¾à²—ಿದೆ</translation>
+<translation id="8217240300496046857">ವೆಬà³â€Œà²¨à²¾à²¦à³à²¯à²‚ತ ನಿಮà³à²®à²¨à³à²¨à³ ಟà³à²°à³à²¯à²¾à²•à³ ಮಾಡà³à²µ ಕà³à²•à³€à²—ಳನà³à²¨à³ ವೆಬà³â€Œà²¸à³ˆà²Ÿà³â€Œà²—ಳೠಬಳಸಲೠಸಾಧà³à²¯à²µà²¿à²²à³à²². ಸೈಟà³â€Œà²—ಳಲà³à²²à²¿à²¨ ಕೆಲವೠವೈಶಿಷà³à²Ÿà³à²¯à²—ಳೠಕಾರà³à²¯à²¨à²¿à²°à³à²µà²¹à²¿à²¸à³à²µà³à²¦à²¨à³à²¨à³ ನಿಲà³à²²à²¿à²¸à²¬à²¹à³à²¦à³.</translation>
<translation id="8218327578424803826">ನಿಯೋಜಿಸಲಾದ ಸà³à²¥à²³:</translation>
<translation id="8220146938470311105">C7/C6 (Envelope)</translation>
<translation id="8225771182978767009">ಈ ಕಂಪà³à²¯à³‚ಟರೠಹೊಂದಿಸಿರà³à²µ ವà³à²¯à²•à³à²¤à²¿à²¯à³ ಈ ಸೈಟೠನಿರà³à²¬à²‚ಧಿಸಲೠಆಯà³à²•à³†à²®à²¾à²¡à²¿à²¦à³à²¦à²¾à²°à³†.</translation>
@@ -2254,14 +2309,9 @@
<translation id="830498451218851433">ಅರà³à²§ ಮಡಿಸಿ</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">ಇನà³â€â€à²¸à³à²Ÿà²¾à²²à³ ಮಾಡಿರà³à²µ ಆà³à²¯à²ªà³â€Œà²—ಳೠಮತà³à²¤à³ ಅವà³à²—ಳನà³à²¨à³ ಎಷà³à²Ÿà³ ಬಾರಿ ಬಳಸಿರà³à²µà³à²¦à³</translation>
+<translation id="8317207217658302555">ARCore ಅನà³à²¨à³ ಅಪà³â€Œà²¡à³‡à²Ÿà³ ಮಾಡಬೇಕೆ?</translation>
<translation id="831997045666694187">ಸಂಜೆ</translation>
<translation id="8321476692217554900">ಅಧಿಸೂಚನೆಗಳà³</translation>
-<translation id="8328484624016508118">ಎಲà³à²²à²¾ ಅಜà³à²žà²¾à²¤ ಟà³à²¯à²¾à²¬à³â€Œà²—ಳನà³à²¨à³ ಮà³à²šà³à²šà²¿à²¦ ನಂತರ, Chrome ಇವà³à²—ಳನà³à²¨à³ ತೆರವà³à²—ೊಳಿಸà³à²¤à³à²¤à²¦à³†:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />ಈ ಸಾಧನದಲà³à²²à²¿à²¨ ನಿಮà³à²® ಬà³à²°à³Œà²¸à²¿à²‚ಗೠಚಟà³à²µà²Ÿà²¿à²•à³†<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />ಈ ಸಾಧನದಲà³à²²à²¿à²¨ ನಿಮà³à²® ಹà³à²¡à³à²•à²¾à²Ÿà²¦ ಇತಿಹಾಸ<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />ಫಾರà³à²®à³â€Œà²—ಳಲà³à²²à²¿ ನಮೂದಿಸಿದ ಮಾಹಿತಿ<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489"><ph name="HOST_NAME" /> ಗೆ ಪà³à²°à²µà³‡à²¶à²µà²¨à³à²¨à³ ನಿರಾಕರಿಸಲಾಗಿದೆ</translation>
<translation id="833262891116910667">ಹೈಲೈಟೠಮಾಡಿ</translation>
<translation id="8339163506404995330"><ph name="LANGUAGE" /> ನಲà³à²²à²¿à²¨ ಪà³à²Ÿà²—ಳನà³à²¨à³ ಅನà³à²µà²¾à²¦ ಮಾಡಲಾಗà³à²µà³à²¦à²¿à²²à³à²²</translation>
@@ -2313,6 +2363,7 @@
<translation id="8507227106804027148">ಕಮಾಂಡೠಸಾಲà³</translation>
<translation id="8508648098325802031">ಹà³à²¡à³à²•à²¾à²Ÿà²¦ à²à²•à²¾à²¨à³</translation>
<translation id="8511402995811232419">ಕà³à²•à³€à²—ಳನà³à²¨à³ ನಿರà³à²µà²¹à²¿à²¸à²¿</translation>
+<translation id="8519753333133776369">ನಿಮà³à²® ನಿರà³à²µà²¾à²¹à²•à²°à³ HID ಸಾಧನವನà³à²¨à³ ಅನà³à²®à²¤à²¿à²¸à²¿à²¦à³à²¦à²¾à²°à³†</translation>
<translation id="8522552481199248698">ನಿಮà³à²® Google ಖಾತೆಯನà³à²¨à³ ಸಂರಕà³à²·à²¿à²¸à²²à³ ಮತà³à²¤à³ ನಿಮà³à²® ಪಾಸà³â€Œà²µà²°à³à²¡à³ ಅನà³à²¨à³ ಬದಲಾಯಿಸಲೠChrome ಸಹಾಯ ಮಾಡಬಲà³à²²à²¦à³.</translation>
<translation id="8530813470445476232">Chrome ಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳಲà³à²²à²¿ ನಿಮà³à²® ಬà³à²°à³Œà²¸à²¿à²‚ಗೠಇತಿಹಾಸ, ಕà³à²•à³€à²—ಳà³, ಕà³à²¯à²¾à²·à³ ಮತà³à²¤à³ ಇನà³à²¨à²·à³à²Ÿà²µà³à²—ಳನà³à²¨à³ ತೆರವà³à²—ೊಳಿಸಿ</translation>
<translation id="8533619373899488139">ನಿಮà³à²® ಸಿಸà³à²Ÿà²®à³ ನಿರà³à²µà²¾à²¹à²•à²°à³ ನಿರà³à²¬à²‚ಧಿಸಿರà³à²µ URLಗಳ ಪಟà³à²Ÿà²¿ ಮತà³à²¤à³ ಜಾರಿಗೊಳಿಸಿರà³à²µ ಇತರ ನೀತಿಗಳನà³à²¨à³ ವೀಕà³à²·à²¿à²¸à²²à³ &lt;strong&gt;chrome://policy&lt;/strong&gt; ಗೆ ಭೇಟಿ ನೀಡಿ.</translation>
@@ -2324,7 +2375,6 @@
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{ಅನà³à²®à²¤à²¿à²¯à²¨à³à²¨à³ ರೀಸೆಟೠಮಾಡಿ}one{ಅನà³à²®à²¤à²¿à²—ಳನà³à²¨à³ ರೀಸೆಟೠಮಾಡಿ}other{ಅನà³à²®à²¤à²¿à²—ಳನà³à²¨à³ ರೀಸೆಟೠಮಾಡಿ}}</translation>
<translation id="8555010941760982128">ಚೆಕà³â€Œà²”ಟà³â€Œà²¨à²²à³à²²à²¿ ಈ ಕೋಡೠಅನà³à²¨à³ ಬಳಸಿ</translation>
<translation id="8557066899867184262">ನಿಮà³à²® ಕಾರà³à²¡à³ ಹಿಂಬದಿಯಲà³à²²à²¿ CVC ಇರà³à²¤à³à²¤à²¦à³†.</translation>
-<translation id="8558485628462305855">ವರà³à²§à²¿à²¤ ನೈಜತೆಯ ವಿಷಯವನà³à²¨à³ ವೀಕà³à²·à²¿à²¸à²²à³, ARCore ಅನà³à²¨à³ ಅಪà³â€Œà²¡à³‡à²Ÿà³ ಮಾಡಿ</translation>
<translation id="8559762987265718583"><ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> ಗೆ ಖಾಸಗಿ ಸಂಪರà³à²•à²µà²¨à³à²¨à³ ಸà³à²¥à²¾à²ªà²¿à²¸à²²à³ ಸಾಧà³à²¯à²µà²¿à²²à³à²² à²à²•à³†à²‚ದರೆ ನಿಮà³à²® ಸಾಧನದ ದಿನಾಂಕ ಮತà³à²¤à³ ಸಮಯ (<ph name="DATE_AND_TIME" />) ತಪà³à²ªà²¾à²—ಿದೆ.</translation>
<translation id="8564182942834072828">ಪà³à²°à²¤à³à²¯à³‡à²• ಡಾಕà³à²¯à³à²®à³†à²‚ಟà³â€Œà²—ಳà³/ಸಂಯೋಜಿಸದ ಪà³à²°à²¤à²¿à²—ಳà³</translation>
<translation id="8564985650692024650">ನೀವೠಇತರ ಸೈಟà³â€Œà²—ಳಲà³à²²à²¿ ಪಾಸà³â€Œà²µà²°à³à²¡à³â€Œ ಅನà³à²¨à³ ಮರà³à²¬à²³à²•à³† ಮಾಡಿದà³à²¦à²²à³à²²à²¿ ನಿಮà³à²® <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> ಪಾಸವರà³à²¡à³ ಅನà³à²¨à³ ಮರà³à²¹à³Šà²‚ದಿಸಲೠChromium ಶಿಫಾರಸೠಮಾಡà³à²¤à³à²¤à²¦à³†.</translation>
@@ -2344,6 +2394,7 @@
<translation id="865032292777205197">ಮೋಷನೠಸೆನà³à²¸à²°à³â€Œà²—ಳà³</translation>
<translation id="8663226718884576429">ಆರà³à²¡à²°à³ ಸಾರಾಂಶ, <ph name="TOTAL_LABEL" />, ಹೆಚà³à²šà²¿à²¨ ವಿವರಗಳà³</translation>
<translation id="8666678546361132282">ಇಂಗà³à²²à²¿à²·à³</translation>
+<translation id="8669306706049782872">ವಿಂಡೋಗಳನà³à²¨à³ ತೆರೆಯಲೠಮತà³à²¤à³ ಇರಿಸಲೠನಿಮà³à²® ಸà³à²•à³à²°à³€à²¨à³â€Œà²—ಳ ಕà³à²°à²¿à²¤à²¾à²¦ ಮಾಹಿತಿಯನà³à²¨à³ ಬಳಸಿ</translation>
<translation id="867224526087042813">ಸಹಿ</translation>
<translation id="8676424191133491403">ಯಾವà³à²¦à³‡ ವಿಳಂಬವಿಲà³à²²</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, ಉತà³à²¤à²°, <ph name="ANSWER" /></translation>
@@ -2370,6 +2421,7 @@
<translation id="8731544501227493793">ಪಾಸà³â€Œà²µà²°à³à²¡à³â€Œà²—ಳ ಬಟನೠಅನà³à²¨à³ ನಿರà³à²µà²¹à²¿à²¸à²¿, ನಿಮà³à²® ಪಾಸà³â€Œà²µà²°à³à²¡à³â€Œà²—ಳನà³à²¨à³ Chrome ಸೆಟà³à²Ÿà²¿à²‚ಗà³â€Œà²—ಳಲà³à²²à²¿ ವೀಕà³à²·à²¿à²¸à²²à³ ಮತà³à²¤à³ ನಿರà³à²µà²¹à²¿à²¸à²²à³ ಎಂಟರೠಒತà³à²¤à²¿à²°à²¿</translation>
<translation id="8734529307927223492">ನಿಮà³à²® <ph name="DEVICE_TYPE" /> ಸಾಧನವನà³à²¨à³ <ph name="MANAGER" /> ನಿರà³à²µà²¹à²¿à²¸à³à²¤à³à²¤à²¦à³†</translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, ಖಾಸಗಿಯಾಗಿ ಬà³à²°à³Œà²¸à³ ಮಾಡಲೠಹೊಸ ಅಜà³à²žà²¾à²¤ ವಿಂಡೋ ಒಂದನà³à²¨à³ ತೆರೆಯಲà³, Tab ಒತà³à²¤à²¿, ನಂತರ Enter ಒತà³à²¤à²¿</translation>
+<translation id="8737685506611670901"><ph name="REPLACED_HANDLER_TITLE" /> ಬದಲಾಗಿ <ph name="PROTOCOL" /> ಲಿಂಕà³â€Œà²—ಳನà³à²¨à³ ತೆರೆಯಿರಿ</translation>
<translation id="8738058698779197622">ಸà³à²°à²•à³à²·à²¿à²¤ ಸಂಪರà³à²•à²µà²¨à³à²¨à³ ಸà³à²¥à²¾à²ªà²¿à²¸à²²à³, ನಿಮà³à²® ಗಡಿಯಾರವನà³à²¨à³ ಸರಿಯಾಗಿ ಹೊಂದಿಸà³à²µ ಅಗತà³à²¯à²µà²¿à²¦à³†. ವೆಬà³â€Œà²¸à³ˆà²Ÿà³â€Œà²—ಳೠತಮà³à²®à²¨à³à²¨à³ ಗà³à²°à³à²¤à²¿à²¸à²²à³ ಬಳಸà³à²µ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²—ಳೠಸಮಯದ ನಿರà³à²¦à²¿à²·à³à²Ÿ ಅವಧಿಗಳಲà³à²²à²¿ ಮಾತà³à²° ಮಾನà³à²¯à²µà²¾à²—ಿರà³à²µ ಕಾರಣ ಹೀಗಾಗà³à²¤à³à²¤à²¦à³†. ನಿಮà³à²® ಸಾಧನದ ಗಡಿಯಾರವೠತಪà³à²ªà²¾à²—ಿರà³à²µ ಕಾರಣ, Chromium ಗೆ ಈ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²—ಳನà³à²¨à³ ಪರಿಶೀಲಿಸಲೠಸಾಧà³à²¯à²µà²¿à²²à³à²².</translation>
<translation id="8740359287975076522"><ph name="HOST_NAME" /> ನ &lt;abbr id="dnsDefinition"&gt;DNS ವಿಳಾಸ&lt;/abbr&gt; ಕಂಡà³à²¬à²°à²²à²¿à²²à³à²². ಸಮಸà³à²¯à³†à²¯à²¨à³à²¨à³ ಪತà³à²¤à³†à²¹à²šà³à²šà²²à²¾à²—à³à²¤à³à²¤à²¿à²¦à³†.</translation>
<translation id="8742371904523228557"><ph name="ORIGIN" /> ಗಾಗಿ ನಿಮà³à²® ಕೋಡೠ<ph name="ONE_TIME_CODE" /> ಆಗಿದೆ</translation>
@@ -2397,6 +2449,7 @@
<translation id="883848425547221593">ಇತರ ಬà³à²•à³â€Œà²®à²¾à²°à³à²•à³â€Œà²—ಳà³:</translation>
<translation id="884264119367021077">ಶಿಪà³à²ªà²¿à²‚ಗà³â€Œ ವಿಳಾಸ</translation>
<translation id="884923133447025588">ವಿಫಲವಾದ ಕಾರà³à²¯à²¤à²‚ತà³à²° ಪತà³à²¤à³†à²¯à²¾à²—ಿಲà³à²².</translation>
+<translation id="8849262850971482943">ಹೆಚà³à²šà²¿à²¨ ಸà³à²°à²•à³à²·à²¤à³†à²—ಾಗಿ ನಿಮà³à²® ವರà³à²šà³à²µà²²à³ ಕಾರà³à²¡à³ ಅನà³à²¨à³ ಬಳಸಿ</translation>
<translation id="885730110891505394">Google ಜೊತೆಗೆ ಹಂಚಿಕೊಳà³à²³à³à²µà³à²¦à³</translation>
<translation id="8858065207712248076">ನೀವೠಇತರ ಸೈಟà³â€Œà²—ಳಲà³à²²à²¿ ಪಾಸà³â€Œà²µà²°à³à²¡à³â€Œ ಅನà³à²¨à³ ಮರà³à²¬à²³à²•à³† ಮಾಡಿದà³à²¦à²²à³à²²à²¿ Chrome ನಿಮà³à²® <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> ಪಾಸವರà³à²¡à³ ಅನà³à²¨à³ ಮರà³à²¹à³Šà²‚ದಿಸಲೠಶಿಫಾರಸೠಮಾಡà³à²¤à³à²¤à²¦à³†.</translation>
<translation id="885906927438988819">ಕಾಗà³à²£à²¿à²¤ ಸರಿಯಾಗಿದà³à²¦à²°à³†, <ph name="BEGIN_LINK" />Windows ನೆಟà³â€Œà²µà²°à³à²•à³ ಡಯಾಗà³à²¨à²¾à²¸à³à²Ÿà²¿à²•à³à²¸à³â€Œâ€Œ ರನೠಮಾಡಿ ನೋಡಿ<ph name="END_LINK" />.</translation>
@@ -2446,6 +2499,7 @@
<translation id="9004367719664099443">VR ಸೆಶನೠಪà³à²°à²—ತಿಯಲà³à²²à²¿à²¦à³†</translation>
<translation id="9005998258318286617">PDF ಡಾಕà³à²¯à³à²®à³†à²‚ಟೠಅನà³à²¨à³ ಲೋಡೠಮಾಡಲೠವಿಫಲವಾಗಿದೆ.</translation>
<translation id="9008201768610948239">ನಿರà³à²²à²•à³à²·à²¿à²¸à²¿</translation>
+<translation id="901834265349196618">ಇಮೇಲà³</translation>
<translation id="9020200922353704812">ಕಾರà³à²¡à³â€Œ ಬಿಲà³à²²à²¿à²‚ಗೠವಿಳಾಸದ ಅಗತà³à²¯à²µà²¿à²¦à³†</translation>
<translation id="9020542370529661692">ಈ ಪà³à²Ÿà²µà²¨à³à²¨à³ <ph name="TARGET_LANGUAGE" /> ಗೆ ಅನà³à²µà²¾à²¦à²¿à²¸à²²à²¾à²—ಿದೆ</translation>
<translation id="9020742383383852663">A8</translation>
@@ -2494,6 +2548,7 @@
<translation id="9150045010208374699">ನಿಮà³à²® ಕà³à²¯à²¾à²®à²°à²¾à²µà²¨à³à²¨à³ ಬಳಸಿ</translation>
<translation id="9150685862434908345">ನಿಮà³à²® ನಿರà³à²µà²¾à²¹à²•à²°à³ ದೂರದಿಂದಲೇ ನಿಮà³à²® ಬà³à²°à³Œà²¸à²°à³ ಸೆಟಪೠಅನà³à²¨à³ ಬದಲಾಯಿಸಬಹà³à²¦à³. ಈ ಸಾಧನದಲà³à²²à²¿à²¨ ಚಟà³à²µà²Ÿà²¿à²•à³†à²¯à²¨à³à²¨à³ Chrome ನಿಂದ ಹೊರಗೂ ನಿರà³à²µà²¹à²¿à²¸à²¬à²¹à³à²¦à³. <ph name="BEGIN_LINK" />ಇನà³à²¨à²·à³à²Ÿà³ ತಿಳಿಯಿರಿ<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">ಅಪà³â€Œà²¡à³‡à²Ÿà³â€Œ ಮಾಡಲಾಗಿದೆ</translation>
+<translation id="9155211586651734179">ಆಡಿಯೊ ಬಾಹà³à²¯à³‹à²ªà²•à²°à²£à²—ಳನà³à²¨à³ ಲಗತà³à²¤à²¿à²¸à²²à²¾à²—ಿದೆ</translation>
<translation id="9157595877708044936">ಹೊಂದಿಸಲಾಗà³à²¤à³à²¤à²¿à²¦à³†...</translation>
<translation id="9158625974267017556">C6 (Envelope)</translation>
<translation id="9164029392738894042">ನಿಖರತೆಯ ಪರಿಶೀಲನೆ</translation>
diff --git a/chromium/components/strings/components_strings_ko.xtb b/chromium/components/strings/components_strings_ko.xtb
index 696be5a21c1..53871bfffcc 100644
--- a/chromium/components/strings/components_strings_ko.xtb
+++ b/chromium/components/strings/components_strings_ko.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">세부정보 보기</translation>
<translation id="1030706264415084469"><ph name="URL" />ì—ì„œ ë‚´ ê¸°ê¸°ì— ëŒ€ìš©ëŸ‰ ë°ì´í„°ë¥¼ ì˜êµ¬ 저장하려고 합니다</translation>
<translation id="1032854598605920125">시계 방향으로 회전</translation>
+<translation id="1033329911862281889">ì‹œí¬ë¦¿ 모드를 ì‚¬ìš©í•´ë„ ë‚˜ì˜ ì˜¨ë¼ì¸ 활ë™ì´ 완전히 비공개로 유지ë˜ì§€ëŠ” 않습니다.
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />사ì´íŠ¸ ë° ì‚¬ì´íŠ¸ 서비스ì—ì„œ ë‚˜ì˜ ë°©ë¬¸ ì‚¬ì‹¤ì„ ì•Œ 수 있습니다.<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ì§ìž¥ ë˜ëŠ” í•™êµì—ì„œ íƒìƒ‰ 활ë™ì„ 추ì í•  수 있습니다.<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ì¸í„°ë„· 서비스 제공업체(ISP)ì—ì„œ 웹 íŠ¸ëž˜í”½ì„ ëª¨ë‹ˆí„°ë§í•  수 있습니다.<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">사용 중지</translation>
<translation id="1036982837258183574">ì „ì²´í™”ë©´ì„ ì¢…ë£Œí•˜ë ¤ë©´ |<ph name="ACCELERATOR" />|ì„(를) 누르세요.</translation>
<translation id="1038106730571050514">추천 보기</translation>
<translation id="1038842779957582377">ì•Œ 수 없는 ì´ë¦„</translation>
<translation id="1041998700806130099">작업 시트 메시지</translation>
<translation id="1048785276086539861">주ì„ì„ ìˆ˜ì •í•˜ë©´ 문서가 ë‹¨ì¼ íŽ˜ì´ì§€ ë·°ë¡œ ëŒì•„갑니다.</translation>
-<translation id="1049743911850919806">ì‹œí¬ë¦¿ 모드</translation>
<translation id="1050038467049342496">다른 앱 닫기</translation>
<translation id="1055184225775184556">추가 실행 취소(&amp;U)</translation>
<translation id="1056898198331236512">경고</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">ì •ì±… ìºì‹œ 확ì¸</translation>
<translation id="1130564665089811311">페ì´ì§€ 번역 버튼, Google 번역으로 ì´ íŽ˜ì´ì§€ë¥¼ 번역하려면 Enter 누르기</translation>
<translation id="1131264053432022307">복사한 ì´ë¯¸ì§€</translation>
+<translation id="1142846828089312304">ì‹œí¬ë¦¿ 모드ì—ì„œ 서드 파티 쿠키 차단</translation>
<translation id="1150979032973867961">ì´ ì„œë²„ê°€ <ph name="DOMAIN" />ìž„ì„ ìž…ì¦í•  수 없으며 ì»´í“¨í„°ì˜ ìš´ì˜ì²´ì œì—ì„œ 신뢰하는 보안 ì¸ì¦ì„œê°€ 아닙니다. 서버를 잘못 설정했거나 불법 사용ìžê°€ ì—°ê²°ì„ ê°€ë¡œì±„ê³  있기 ë•Œë¬¸ì¼ ìˆ˜ 있습니다.</translation>
<translation id="1151972924205500581">비밀번호를 입력해야 합니다.</translation>
<translation id="1156303062776767266">í‘œì‹œëœ íŒŒì¼ì€ 로컬 ë˜ëŠ” 공유 파ì¼ìž…니다.</translation>
@@ -64,7 +70,6 @@
<translation id="1178581264944972037">ì¼ì‹œì¤‘지</translation>
<translation id="1181037720776840403">삭제</translation>
<translation id="1186201132766001848">비밀번호 확ì¸</translation>
-<translation id="1195210374336998651">앱 설정으로 ì´ë™</translation>
<translation id="1195558154361252544">허용한 사ì´íŠ¸ë¥¼ 제외한 모든 사ì´íŠ¸ì˜ ì•Œë¦¼ì´ ìžë™ìœ¼ë¡œ 차단ë©ë‹ˆë‹¤.</translation>
<translation id="1197088940767939838">오렌지색</translation>
<translation id="1201402288615127009">다ìŒ</translation>
@@ -111,7 +116,7 @@
<translation id="1307966114820526988">ì§€ì› ì¤‘ë‹¨ 기능</translation>
<translation id="1308113895091915999">ì´ìš© 가능한 혜íƒ</translation>
<translation id="1312803275555673949">어떤 근거가 있나요?</translation>
-<translation id="131405271941274527">NFC ê¸°ê¸°ì— íœ´ëŒ€ì „í™”ë¥¼ 갖다 댈 ë•Œ <ph name="URL" />ì—ì„œ 정보를 ë³´ë‚´ê³  받으려고 합니다.</translation>
+<translation id="1314311879718644478">ì¦ê°• 현실 콘í…츠 보기</translation>
<translation id="1314509827145471431">오른쪽 ë°”ì¸ë“œ</translation>
<translation id="1318023360584041678">탭 ê·¸ë£¹ì— ì €ìž¥ë¨</translation>
<translation id="1319245136674974084">ì´ ì•±ì— ëŒ€í•´ 다시 묻지 ì•ŠìŒ</translation>
@@ -161,6 +166,7 @@
<translation id="142858679511221695">Cloud 사용ìž</translation>
<translation id="1428729058023778569">ì´ ì‚¬ì´íŠ¸ì—ì„œ HTTPS를 지ì›í•˜ì§€ 않기 ë•Œë¬¸ì— ê²½ê³ ê°€ 표시ë˜ì—ˆìŠµë‹ˆë‹¤. <ph name="BEGIN_LEARN_MORE_LINK" />ìžì„¸ížˆ 알아보기<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">ì¸ì‡„</translation>
+<translation id="1432187715652018471">페ì´ì§€ì—ì„œ 서비스 핸들러를 설치하려고 합니다.</translation>
<translation id="1432581352905426595">검색엔진 관리</translation>
<translation id="1436185428532214179">ê¸°ê¸°ì˜ íŒŒì¼ ë° í´ë” ìˆ˜ì •ì„ ìš”ì²­í•  수 있ìŒ</translation>
<translation id="1442386063175183758">오른쪽 게ì´íŠ¸ í´ë“œ</translation>
@@ -181,6 +187,12 @@
<translation id="1483493594462132177">보내기</translation>
<translation id="1484290072879560759">배송지 주소 ì„ íƒ</translation>
<translation id="1492194039220927094">정책 푸시:</translation>
+<translation id="149293076951187737">Chrome ì‹œí¬ë¦¿ íƒ­ì„ ëª¨ë‘ ë‹«ìœ¼ë©´ 기기ì—ì„œ ë‹¤ìŒ íƒ­ì˜ í™œë™ì´ ì‚­ì œë©ë‹ˆë‹¤.
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />íƒìƒ‰ 활ë™<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />검색 기ë¡<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ì–‘ì‹ì— ìž…ë ¥ëœ ì •ë³´<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">탭으로 ëŒì•„가기</translation>
<translation id="1501859676467574491">Google ê³„ì •ì— ì €ìž¥ëœ ì¹´ë“œ 표시</translation>
<translation id="1507202001669085618">&lt;p&gt;온ë¼ì¸ì— ì ‘ì†í•˜ê¸° 위해 로그ì¸í•´ì•¼ 하는 Wi-Fi í¬í„¸ì„ 사용하면 ì´ ì˜¤ë¥˜ê°€ 표시ë©ë‹ˆë‹¤.&lt;/p&gt;
@@ -208,6 +220,8 @@
<translation id="1559572115229829303">&lt;p&gt;ê¸°ê¸°ì˜ ë‚ ì§œì™€ 시간(<ph name="DATE_AND_TIME" />)ì´ ìž˜ëª»ë˜ì–´ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />ì— ë¹„ê³µê°œë¡œ ì—°ê²°í•  수 없습니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;설정&lt;/strong&gt; ì•±ì˜ &lt;strong&gt;ì¼ë°˜&lt;/strong&gt; 섹션ì—ì„œ 날짜와 ì‹œê°„ì„ ë§žì¶”ì„¸ìš”.&lt;/p&gt;</translation>
+<translation id="1559839503761818503"><ph name="DATE" /> <ph name="TIME" />ì— ê´€ë¦¬ìžê°€ 기기를 다시 시작합니다.</translation>
+<translation id="156703335097561114">주소, ì¸í„°íŽ˜ì´ìŠ¤ 구성, ì—°ê²° 품질 ë“±ì˜ ë„¤íŠ¸ì›Œí‚¹ ì •ë³´</translation>
<translation id="1567040042588613346">ì´ ì •ì±…ì€ ì •ìƒ ìž‘ë™ ì¤‘ì´ë‚˜ 다른 ìœ„ì¹˜ì— ê°™ì€ ê°’ì´ ì„¤ì •ë˜ì—ˆìœ¼ë¯€ë¡œ ì´ ì •ì±…ì— ì˜í•´ 대체ë˜ì—ˆìŠµë‹ˆë‹¤.</translation>
<translation id="1569487616857761740">ë§Œë£Œì¼ ìž…ë ¥</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@
<translation id="1583429793053364125">ì´ ì›¹íŽ˜ì´ì§€ë¥¼ 표시하는 ë„중 문제가 ë°œìƒí–ˆìŠµë‹ˆë‹¤.</translation>
<translation id="1586541204584340881">내가 설치한 확장 프로그램</translation>
<translation id="1588438908519853928">ì¼ë°˜</translation>
+<translation id="1589050138437146318">ARCore를 설치하시겠습니까?</translation>
<translation id="1592005682883173041">로컬 ë°ì´í„° 액세스</translation>
<translation id="1594030484168838125">ì„ íƒ</translation>
<translation id="160851722280695521">Chrome 공룡 게임 플레ì´</translation>
@@ -279,6 +294,7 @@
<translation id="1763864636252898013">ì´ ì„œë²„ê°€ <ph name="DOMAIN" />ìž„ì„ ìž…ì¦í•  수 없으며 ê¸°ê¸°ì˜ ìš´ì˜ì²´ì œì—ì„œ 신뢰하는 보안 ì¸ì¦ì„œê°€ 아닙니다. 서버를 잘못 설정했거나 불법 사용ìžê°€ ì—°ê²°ì„ ê°€ë¡œì±„ê³  있기 ë•Œë¬¸ì¼ ìˆ˜ 있습니다.</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Windows ë„¤íŠ¸ì›Œí¬ ì§„ë‹¨ í”„ë¡œê·¸ëž¨ì„ ì‹¤í–‰<ph name="END_LINK" />í•´ 보세요.</translation>
<translation id="1772163372082567643">ëŒ€ìƒ ì„œë²„ì¸ <ph name="ORIGIN" />ì—ì„œ í—¤ë”를 설정하여 서버로 전송ë˜ëŠ” 모든 ìš”ì²­ì— ì¶œì²˜ ì •ì±…ì„ ì ìš©í•˜ë„ë¡ ìš”ì²­í–ˆìŠµë‹ˆë‹¤. 하지만 í—¤ë”ì˜ í˜•ì‹ì´ 잘못ë˜ì–´ 브ë¼ìš°ì €ì—ì„œ <ph name="SITE" />ì— ê´€í•œ ìš”ì²­ì„ ì²˜ë¦¬í•  수 없습니다. 사ì´íŠ¸ ìš´ì˜ìžëŠ” 출처 ì •ì±…ì„ ì‚¬ìš©í•´ 사ì´íŠ¸ì˜ 보안 ë° ê¸°íƒ€ ì†ì„±ì„ 구성할 수 있습니다.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Chromium ì‹œí¬ë¦¿ 모드 ìžì„¸ížˆ 알아보기<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">열린 íƒ­ì´ ì—¬ê¸°ì— í‘œì‹œë©ë‹ˆë‹¤.</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -406,6 +422,7 @@
<translation id="22081806969704220">íŠ¸ë ˆì´ 3</translation>
<translation id="2212735316055980242">ì •ì±…ì„ ì°¾ì„ ìˆ˜ ì—†ìŒ</translation>
<translation id="2213606439339815911">í•­ëª©ì„ ê°€ì ¸ì˜¤ëŠ” 중...</translation>
+<translation id="2213612003795704869">페ì´ì§€ê°€ ì¸ì‡„ë¨</translation>
<translation id="2215727959747642672">íŒŒì¼ ìˆ˜ì •</translation>
<translation id="2218879909401188352">현재 <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />ì˜ ê³µê²©ìžê°€ 기기를 ì†ìƒì‹œí‚¤ê±°ë‚˜, ëª¨ë°”ì¼ ìš”ê¸ˆì— ëª°ëž˜ 추가 ìš”ê¸ˆì„ ë¶€ê³¼í•˜ê±°ë‚˜, ê°œì¸ì •ë³´ë¥¼ ë„용하는 위험한 ì•±ì„ ì„¤ì¹˜í•  ìˆ˜ë„ ìžˆìŠµë‹ˆë‹¤. <ph name="BEGIN_LEARN_MORE_LINK" />ìžì„¸ížˆ 알아보기<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">ì¸í„°ë„· ì—°ê²° ì—†ìŒ</translation>
@@ -415,6 +432,7 @@
<translation id="2248949050832152960">WebAuthn 사용</translation>
<translation id="2250931979407627383">왼쪽 ì—지 스티치</translation>
<translation id="225207911366869382">ì´ ê°’ì€ ì´ ì •ì±…ì— ì‚¬ìš©ë˜ì§€ 않습니다.</translation>
+<translation id="2256115617011615191">지금 다시 시작</translation>
<translation id="2258928405015593961">만료ì¼ì„ 오늘 ì´í›„ë¡œ 입력하고 다시 ì‹œë„í•´ 보세요.</translation>
<translation id="225943865679747347">오류 코드: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">HTTP 오류</translation>
@@ -442,6 +460,7 @@
<translation id="2337852623177822836">관리ìžê°€ 제어하는 설정</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" />ì—ì„œ 페어ë§í•˜ë ¤ê³  함</translation>
<translation id="2346319942568447007">복사한 ì´ë¯¸ì§€</translation>
+<translation id="2350796302381711542"><ph name="HANDLER_HOSTNAME" />ì—ì„œ <ph name="REPLACED_HANDLER_TITLE" /> 대신 모든 <ph name="PROTOCOL" /> ë§í¬ë¥¼ ì—´ë„ë¡ í—ˆìš©í•˜ì‹œê² ìŠµë‹ˆê¹Œ?</translation>
<translation id="2354001756790975382">기타 ë¶ë§ˆí¬</translation>
<translation id="2354430244986887761">Google 세ì´í”„ 브ë¼ìš°ì§•ì´ 최근 <ph name="SITE" />ì—ì„œ <ph name="BEGIN_LINK" />유해한 ì•±ì„ ë°œê²¬<ph name="END_LINK" />했습니다.</translation>
<translation id="2355395290879513365">공격ìžëŠ” 사용ìžê°€ ì´ ì‚¬ì´íŠ¸ì—ì„œ ë³´ê³  있는 ì´ë¯¸ì§€ë¥¼ ë³¼ 수 있으며 ì´ë¯¸ì§€ë¥¼ 수정하여 사용ìžë¥¼ ì†ì¼ 수 있습니다.</translation>
@@ -467,6 +486,7 @@
<translation id="2413528052993050574">ì´ ì„œë²„ê°€ <ph name="DOMAIN" />ìž„ì„ ìž…ì¦í•  수 없으며 ì„œë²„ì˜ ë³´ì•ˆ ì¸ì¦ì„œê°€ ì·¨ì†Œë  ìˆ˜ 있습니다. 서버를 잘못 설정했거나 불법 사용ìžê°€ ì—°ê²°ì„ ê°€ë¡œì±„ê³  있기 ë•Œë¬¸ì¼ ìˆ˜ 있습니다.</translation>
<translation id="2414886740292270097">어둡게</translation>
<translation id="2430968933669123598">Google 계정 관리, Enter를 눌러 Google 계정ì—ì„œ ì •ë³´, ê°œì¸ ì •ë³´ 보호 ë° ë³´ì•ˆ 설정 관리</translation>
+<translation id="2436186046335138073"><ph name="HANDLER_HOSTNAME" />ì—ì„œ 모든 <ph name="PROTOCOL" /> ë§í¬ë¥¼ ì—´ë„ë¡ í—ˆìš©í•˜ì‹œê² ìŠµë‹ˆê¹Œ?</translation>
<translation id="2438874542388153331">오른쪽 4공 펀칭</translation>
<translation id="2450021089947420533">íƒìƒ‰ 여정</translation>
<translation id="2463739503403862330">ìž…ë ¥</translation>
@@ -474,6 +494,7 @@
<translation id="2465655957518002998">배달 방법 ì„ íƒ</translation>
<translation id="2465688316154986572">스테ì´í”Œ</translation>
<translation id="2465914000209955735">Chromeì—ì„œ 다운로드한 íŒŒì¼ ê´€ë¦¬</translation>
+<translation id="2466004615675155314">웹ì—ì„œ ì°¾ì€ ì •ë³´ 표시</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />ë„¤íŠ¸ì›Œí¬ ì§„ë‹¨ 프로그램 실행<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">1-to-N 순서</translation>
<translation id="2470767536994572628">주ì„ì„ ìˆ˜ì •í•˜ë©´ 문서가 ì›ëž˜ ë°©í–¥ì˜ ë‹¨ì¼ íŽ˜ì´ì§€ ë·°ë¡œ ëŒì•„갑니다.</translation>
@@ -494,6 +515,7 @@
<translation id="2523886232349826891">ì´ ê¸°ê¸°ì—만 저장ë¨</translation>
<translation id="2524461107774643265">ìžì„¸í•œ ì •ë³´ 추가</translation>
<translation id="2529899080962247600">ìž…ë ¥ëž€ì— í•­ëª©ì´ <ph name="MAX_ITEMS_LIMIT" />ê°œ 넘게 있으면 안 ë©ë‹ˆë‹¤. ì´í›„ í•­ëª©ì€ ëª¨ë‘ ë¬´ì‹œë©ë‹ˆë‹¤.</translation>
+<translation id="2535585790302968248">비공개로 íƒìƒ‰í•˜ë ¤ë©´ 새 ì‹œí¬ë¦¿ íƒ­ì„ ì—¬ì„¸ìš”.</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{외 1개}other{외 #개}}</translation>
<translation id="2536110899380797252">주소 추가</translation>
<translation id="2539524384386349900">ê°ì§€</translation>
@@ -519,7 +541,14 @@
<translation id="2597378329261239068">문서가 비밀번호로 보호ë˜ê³  있습니다. 비밀번호를 입력하세요.</translation>
<translation id="2609632851001447353">유사 버전</translation>
<translation id="2610561535971892504">í´ë¦­í•˜ì—¬ 복사</translation>
+<translation id="2617988307566202237">Chromeì—서는 ë‹¤ìŒ ì •ë³´ë¥¼ <ph name="BEGIN_EMPHASIS" />저장하지 않습니다<ph name="END_EMPHASIS" />.
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />방문 기ë¡
+ <ph name="LIST_ITEM" />쿠키 ë° ì‚¬ì´íŠ¸ ë°ì´í„°
+ <ph name="LIST_ITEM" />ì–‘ì‹ì— ìž…ë ¥ëœ ì •ë³´
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10(봉투)</translation>
+<translation id="2623663032199728144">í™”ë©´ì— ê´€í•œ ì •ë³´ ì‚¬ìš©ì„ ìš”ì²­í•  수 있ìŒ</translation>
<translation id="2625385379895617796">ì‹œê°„ì´ ë„ˆë¬´ 먼 미래로 설정ë˜ì–´ 있습니다.</translation>
<translation id="262745152991669301">USB ê¸°ê¸°ì— ì—°ê²°í•˜ë„ë¡ ìš”ì²­í•  수 있ìŒ</translation>
<translation id="2629325967560697240">Chromeì—ì„œ 가장 강력한 보안 ê¸°ëŠ¥ì„ ì‚¬ìš©í•˜ë ¤ë©´ <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />í–¥ìƒëœ 보호 모드를 사용 설정<ph name="END_ENHANCED_PROTECTION_LINK" />하세요.</translation>
@@ -553,6 +582,7 @@
<translation id="2709516037105925701">ìžë™ 완성</translation>
<translation id="2713444072780614174">í°ìƒ‰</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />, Chrome 설정ì—ì„œ ê²°ì œ ë° ì‹ ìš©ì¹´ë“œ 정보를 관리하려면 Tabì„ ëˆ„ë¥¸ ë‹¤ìŒ Enter 누르기</translation>
+<translation id="271663710482723385">ì „ì²´í™”ë©´ì„ ì¢…ë£Œí•˜ë ¤ë©´ |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| 키를 누르세요.</translation>
<translation id="2721148159707890343">요청 성공</translation>
<translation id="2723669454293168317">Chrome ì„¤ì •ì˜ ì•ˆì „ í™•ì¸ ì‹¤í–‰</translation>
<translation id="2726001110728089263">측면 트레ì´</translation>
@@ -583,6 +613,7 @@
<translation id="2850739647070081192">Invite(봉투)</translation>
<translation id="2856444702002559011">공격ìžê°€ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />ì—ì„œ ì •ë³´(예: 비밀번호, 메시지, ì‹ ìš©ì¹´ë“œ 등)를 ë„용하려고 ì‹œë„ ì¤‘ì¼ ìˆ˜ 있습니다. <ph name="BEGIN_LEARN_MORE_LINK" />ìžì„¸ížˆ 알아보기<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">ì´ ì‚¬ì´íŠ¸ì—서는 ë°©í•´ê°€ ë˜ê±°ë‚˜ 사용ìžë¥¼ 현혹하는 광고를 표시합니다.</translation>
+<translation id="286512204874376891">ê°€ìƒ ì¹´ë“œëŠ” 실제 카드를 숨겨서 사기 ìœ„í—˜ì„ ì¤„ì—¬ì¤ë‹ˆë‹¤. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">친근함</translation>
<translation id="2876489322757410363">ì‹œí¬ë¦¿ 모드를 종료하고 외부 애플리케ì´ì…˜ì—ì„œ 결제합니다. 계ì†í•˜ì‹œê² ìŠµë‹ˆê¹Œ?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />, Chrome 설정ì—ì„œ 세ì´í”„ 브ë¼ìš°ì§• ë“±ì„ ê´€ë¦¬í•˜ë ¤ë©´ Tabê³¼ Enter를 차례로 누르세요</translation>
@@ -607,6 +638,7 @@
<translation id="2930577230479659665">ê° ì‚¬ë³¸ ë’¤ì— íŠ¸ë¦¼</translation>
<translation id="2932085390869194046">비밀번호 추천...</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019"><ph name="PROTOCOL" /> ë§í¬ 열기</translation>
<translation id="2941952326391522266">ì´ ì„œë²„ê°€ <ph name="DOMAIN" />ìž„ì„ ìž…ì¦í•  수 없으며 ì„œë²„ì˜ ë³´ì•ˆ ì¸ì¦ì„œê°€ <ph name="DOMAIN2" />ì—ì„œ 제공한 것입니다. 서버를 잘못 설정했거나 불법 사용ìžê°€ ì—°ê²°ì„ ê°€ë¡œì±„ê³  있기 ë•Œë¬¸ì¼ ìˆ˜ 있습니다.</translation>
<translation id="2943895734390379394">업로드 시간:</translation>
<translation id="2948083400971632585">설정 페ì´ì§€ì˜ ì—°ê²°ì„ êµ¬ì„±í•˜ëŠ” 프ë¡ì‹œë¥¼ 사용 중지할 수 있습니다.</translation>
@@ -639,6 +671,7 @@
<translation id="3037605927509011580">ì•—, ì´ëŸ°!</translation>
<translation id="3041612393474885105">ì¸ì¦ì„œ ì •ë³´</translation>
<translation id="3044034790304486808">검색 계ì†</translation>
+<translation id="305162504811187366">타임스탬프, 호스트, í´ë¼ì´ì–¸íŠ¸ 세션 ID를 í¬í•¨í•œ Chrome ì›ê²© ë°ìŠ¤í¬í†± 기ë¡</translation>
<translation id="3060227939791841287">C9(봉투)</translation>
<translation id="3061707000357573562">서비스 패치</translation>
<translation id="306573536155379004">ê²Œìž„ì´ ì‹œìž‘ë˜ì—ˆìŠµë‹ˆë‹¤.</translation>
@@ -679,6 +712,7 @@
<translation id="3197136577151645743">사용ìžê°€ 현재 ì´ ê¸°ê¸°ë¥¼ 사용 중ì¸ì§€ 확ì¸ì„ 요청할 수 있ìŒ</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />, Tabì„ ëˆ„ë¥¸ ë‹¤ìŒ Enter를 눌러 Chrome 설정ì—ì„œ ë‚´ê°€ ë™ê¸°í™”하는 ì •ë³´ 관리</translation>
<translation id="320323717674993345">결제 취소</translation>
+<translation id="3203366800380907218">웹ì—ì„œ ì°¾ì€ ì •ë³´</translation>
<translation id="3207960819495026254">ë¶ë§ˆí¬ì— 추가ë¨</translation>
<translation id="3209034400446768650">페ì´ì§€ì—ì„œ ìš”ê¸ˆì„ ì²­êµ¬í•  수 있ìŒ</translation>
<translation id="3212581601480735796"><ph name="HOSTNAME" />ì—ì„œì˜ í™œë™ì´ 모니터ë§ë˜ê³  있ìŒ</translation>
@@ -695,10 +729,12 @@
<translation id="3234666976984236645">ì´ ì‚¬ì´íŠ¸ì—ì„œ 중요한 콘í…츠 í•­ìƒ ê°ì§€</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />, 브ë¼ìš°ì € 테마를 맞춤설정하려면 Tabê³¼ Enter를 차례로 누르세요</translation>
<translation id="3240791268468473923">ì¼ì¹˜í•˜ëŠ” ê²°ì œ ì‚¬ìš©ìž ì¸ì¦ ì •ë³´ 시트가 없는 보안 ê²°ì œ ì‚¬ìš©ìž ì¸ì¦ ì •ë³´ 열림</translation>
+<translation id="324180406144491771">“<ph name="HOST_NAME" />†ë§í¬ê°€ 차단ë˜ì—ˆìŠµë‹ˆë‹¤</translation>
<translation id="3249845759089040423">그루브</translation>
<translation id="3252266817569339921">프랑스어</translation>
<translation id="3257954757204451555">ì´ ì •ë³´ëŠ” 누가 제공했나요?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />, Tabì„ ëˆ„ë¥¸ ë‹¤ìŒ Enter를 눌러 Google Calendarì—ì„œ 빠르게 새 ì¼ì • 만들기</translation>
+<translation id="3261488570342242926">ê°€ìƒ ì¹´ë“œ ìžì„¸ížˆ 알아보기</translation>
<translation id="3264837738038045344">Chrome 설정 관리 버튼, Enter를 눌러 Chrome 설정으로 ì´ë™</translation>
<translation id="3266793032086590337">ê°’(충ëŒ)</translation>
<translation id="3268451620468152448">열린 탭</translation>
@@ -712,6 +748,7 @@
<translation id="3288238092761586174">ê²°ì œ ì¸ì¦ì„ 위해 <ph name="URL" />ì—ì„œ 추가 단계를 진행해야 í•  수 있습니다.</translation>
<translation id="3293642807462928945"><ph name="POLICY_NAME" /> ì •ì±…ì— ê´€í•´ ìžì„¸ížˆ 알아보기</translation>
<translation id="3295444047715739395">Chrome 설정ì—ì„œ 비밀번호를 확ì¸í•˜ê³  관리하세요.</translation>
+<translation id="3303795387212510132">앱ì—ì„œ <ph name="PROTOCOL_SCHEME" /> ë§í¬ë¥¼ ì—´ë„ë¡ í—ˆìš©í•˜ì‹œê² ìŠµë‹ˆê¹Œ?</translation>
<translation id="3303855915957856445">검색결과 ì—†ìŒ</translation>
<translation id="3304073249511302126">블루투스 검색</translation>
<translation id="3308006649705061278">ì¡°ì§ êµ¬ì„± 단위(OU)</translation>
@@ -725,12 +762,6 @@
<translation id="3345782426586609320">눈</translation>
<translation id="3355823806454867987">프ë¡ì‹œ 설정 변경...</translation>
<translation id="3360103848165129075">결제 핸들러 시트</translation>
-<translation id="3361596688432910856">Chromeì— ë‹¤ìŒ ì •ë³´ê°€ <ph name="BEGIN_EMPHASIS" />저장ë˜ì§€ 않습니다<ph name="END_EMPHASIS" />.
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />방문 기ë¡
- <ph name="LIST_ITEM" />쿠키 ë° ì‚¬ì´íŠ¸ ë°ì´í„°
- <ph name="LIST_ITEM" />ì–‘ì‹ì— 입력한 ì •ë³´
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">ì´ ì •ì±…ì€ ì§€ì› ì¤‘ë‹¨ëœ <ph name="OLD_POLICY" /> ì •ì±…ì—ì„œ ìžë™ìœ¼ë¡œ 복사ë˜ì—ˆìŠµë‹ˆë‹¤. ì´ ì •ì±…ì„ ëŒ€ì‹  사용해야 합니다.</translation>
<translation id="3364869320075768271"><ph name="URL" />ì—ì„œ ê°€ìƒ í˜„ì‹¤ 기기 ë° ë°ì´í„°ë¥¼ 사용하려고 합니다.</translation>
<translation id="3366477098757335611">카드 보기</translation>
@@ -813,7 +844,6 @@
<translation id="3587738293690942763">보통</translation>
<translation id="3592413004129370115">Italian(봉투)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{언제든지 ê·¸ë£¹ì„ ìž¬ì„¤ì •í•  수 있습니다. 새 ê·¸ë£¹ì— ì°¸ì—¬í•˜ëŠ” ë° í•˜ë£¨ ì •ë„ê°€ 소요ë©ë‹ˆë‹¤.}=1{언제든지 ê·¸ë£¹ì„ ìž¬ì„¤ì •í•  수 있습니다. 새 ê·¸ë£¹ì— ì°¸ì—¬í•˜ëŠ” ë° í•˜ë£¨ ì •ë„ê°€ 소요ë©ë‹ˆë‹¤.}other{언제든지 ê·¸ë£¹ì„ ìž¬ì„¤ì •í•  수 있습니다. 새 ê·¸ë£¹ì— ì°¸ì—¬í•˜ëŠ” ë° {NUM_DAYS}ì¼ì´ 소요ë©ë‹ˆë‹¤.}}</translation>
-<translation id="3596012367874587041">앱 설정</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">관리ìžê°€ 차단한 애플리케ì´ì…˜</translation>
<translation id="3608932978122581043">ì¢…ì´ ê³µê¸‰ ë°©í–¥</translation>
@@ -856,6 +886,7 @@
<translation id="370972442370243704">íƒìƒ‰ 여정 사용 설정</translation>
<translation id="3711895659073496551">ì¼ì‹œì¤‘지</translation>
<translation id="3712624925041724820">ë¼ì´ì„ ìŠ¤ 만료ë¨</translation>
+<translation id="3714633008798122362">웹 캘린ë”</translation>
<translation id="3714780639079136834">ëª¨ë°”ì¼ ë°ì´í„° ë˜ëŠ” Wi-Fi 사용 설정</translation>
<translation id="3715597595485130451">Wi-Fi ì—°ê²°</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />프ë¡ì‹œ, 방화벽, DNS 설정 확ì¸<ph name="END_LINK" /></translation>
@@ -917,6 +948,7 @@
<translation id="3906954721959377182">태블릿</translation>
<translation id="3909477809443608991"><ph name="URL" />ì—ì„œ ë³´í˜¸ëœ ì½˜í…츠를 재ìƒí•˜ë ¤ê³  합니다. Googleì—ì„œ ì´ ê¸°ê¸°ì˜ ì‹ ì›ì„ 확ì¸í•˜ë©° ì´ ì‚¬ì´íŠ¸ì—ì„œ ì´ ê¸°ê¸°ì— ì•¡ì„¸ìŠ¤í•  수 있습니다.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">거부</translation>
<translation id="3939773374150895049">CVC 대신 WebAuthnì„ ì‚¬ìš©í•˜ì‹œê² ìŠµë‹ˆê¹Œ?</translation>
<translation id="3946209740501886391">ì´ ì‚¬ì´íŠ¸ì—ì„œ í•­ìƒ ë¬¼ì–´ë³´ê¸°</translation>
<translation id="3947595700203588284">MIDI ê¸°ê¸°ì— ì—°ê²°í•˜ë„ë¡ ìš”ì²­í•  수 있ìŒ</translation>
@@ -937,6 +969,7 @@
<translation id="3987940399970879459">1MB 미만</translation>
<translation id="3990250421422698716">조그 오프셋</translation>
<translation id="3996311196211510766">사ì´íŠ¸ <ph name="ORIGIN" />ì—ì„œ 모든 ìš”ì²­ì— ì¶œì²˜ ì •ì±…ì„ ì ìš©í•˜ë„ë¡ ìš”ì²­í–ˆìœ¼ë‚˜ ì´ ì •ì±…ì€ í˜„ìž¬ ì ìš©í•  수 없습니다.</translation>
+<translation id="4009243425692662128">ì¸ì‡„하는 페ì´ì§€ì˜ 콘í…츠가 분ì„ì„ ìœ„í•´ Google Cloud ë˜ëŠ” 타사로 전송ë©ë‹ˆë‹¤. 예를 들어, 민ê°í•œ 정보를 찾기 위해 í…스트를 스캔할 수 있습니다.</translation>
<translation id="4010758435855888356">저장소 액세스 ê¶Œí•œì„ í—ˆìš©í•˜ì‹œê² ìŠµë‹ˆê¹Œ?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{{COUNT}페ì´ì§€ë¡œ ì´ë£¨ì–´ì§„ PDF 문서}other{{COUNT}페ì´ì§€ë¡œ ì´ë£¨ì–´ì§„ PDF 문서}}</translation>
<translation id="4023431997072828269">안전하지 ì•Šì€ ì—°ê²°ì„ í†µí•´ ì´ ì–‘ì‹ì´ 제출ë˜ë¯€ë¡œ ë‚´ ì •ë³´ê°€ 다른 사용ìžì—게 표시ë©ë‹ˆë‹¤.</translation>
@@ -1027,6 +1060,7 @@
<translation id="4250680216510889253">아니요</translation>
<translation id="4253168017788158739">메모</translation>
<translation id="425582637250725228">ë³€ê²½ì‚¬í•­ì´ ì €ìž¥ë˜ì§€ ì•Šì„ ìˆ˜ 있습니다.</translation>
+<translation id="425869179292622354">ê°€ìƒ ì¹´ë“œë¡œ ë” ì•ˆì „í•˜ê²Œ 만들까요?</translation>
<translation id="4258748452823770588">ìž˜ëª»ëœ ì„œëª…</translation>
<translation id="4261046003697461417">ë³´í˜¸ëœ ë¬¸ì„œì—는 주ì„ì„ ë‹¬ 수 없습니다.</translation>
<translation id="4265872034478892965">관리ìžê°€ 허용함</translation>
@@ -1089,6 +1123,7 @@
<translation id="4434045419905280838">íŒì—… ë° ë¦¬ë””ë ‰ì…˜</translation>
<translation id="4435702339979719576">엽서)</translation>
<translation id="443673843213245140">프ë¡ì‹œ ì‚¬ìš©ì€ ì¤‘ì§€ë˜ì—ˆì§€ë§Œ ëª…ì‹œì  í”„ë¡ì‹œ ì„¤ì •ì´ ì§€ì •ë˜ì–´ 있습니다.</translation>
+<translation id="4441832193888514600">í´ë¼ìš°ë“œ ì‚¬ìš©ìž ì •ì±…ìœ¼ë¡œë§Œ 설정할 수 있는 ì •ì±…ì´ë¯€ë¡œ 무시ë˜ì—ˆìŠµë‹ˆë‹¤.</translation>
<translation id="4450893287417543264">다시 표시하지 ì•ŠìŒ</translation>
<translation id="4451135742916150903">HID ê¸°ê¸°ì— ì—°ê²°í•˜ë„ë¡ ìš”ì²­í•  수 있ìŒ</translation>
<translation id="4452328064229197696">방금 사용한 비밀번호가 ì •ë³´ 유출로 ì¸í•´ ë…¸ì¶œëœ ê²ƒìœ¼ë¡œ 확ì¸ë©ë‹ˆë‹¤. ê³„ì •ì„ ë³´í˜¸í•˜ê¸° 위해 Google 비밀번호 관리ìžì—ì„œ ì €ìž¥ëœ ë¹„ë°€ë²ˆí˜¸ë¥¼ 확ì¸í•˜ì‹œê¸° ë°”ëžë‹ˆë‹¤.</translation>
@@ -1144,6 +1179,7 @@
<translation id="4628948037717959914">사진</translation>
<translation id="4631649115723685955">ìºì‹œë°± ì—°ê²°ë¨</translation>
<translation id="4636930964841734540">ì •ë³´</translation>
+<translation id="4638670630777875591">Chromium ì‹œí¬ë¦¿ 모드</translation>
<translation id="464342062220857295">검색 기능</translation>
<translation id="4644670975240021822">역순으로 ì¸ì‡„ë©´ì´ ì•„ëž˜ë¥¼ 향하게</translation>
<translation id="4646534391647090355">지금 ì´ë™</translation>
@@ -1164,6 +1200,7 @@
<translation id="4708268264240856090">ì—°ê²°ì´ ëŠê¹€</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Windows ë„¤íŠ¸ì›Œí¬ ì§„ë‹¨ 프로그램 실행<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426"><ph name="USERNAME" />ì˜ ë¹„ë°€ë²ˆí˜¸</translation>
<translation id="4724144314178270921">í´ë¦½ë³´ë“œì˜ í…스트와 ì´ë¯¸ì§€ 확ì¸ì„ 요청할 수 있ìŒ</translation>
<translation id="4726672564094551039">정책 새로고침</translation>
<translation id="4728558894243024398">플랫í¼</translation>
@@ -1185,6 +1222,7 @@
<translation id="4757993714154412917">사기성 사ì´íŠ¸ì— 비밀번호를 입력했습니다. ê³„ì •ì„ ì•ˆì „í•˜ê²Œ 보호하려면 ì €ìž¥ëœ ë¹„ë°€ë²ˆí˜¸ë¥¼ 확ì¸í•´ 보시기 ë°”ëžë‹ˆë‹¤.</translation>
<translation id="4758311279753947758">ì—°ë½ì²˜ ì •ë³´ 추가</translation>
<translation id="4761104368405085019">마ì´í¬ 사용</translation>
+<translation id="4761869838909035636">Chrome 안전 í™•ì¸ ì‹¤í–‰</translation>
<translation id="4764776831041365478"><ph name="URL" />ì˜ ì›¹íŽ˜ì´ì§€ê°€ ì¼ì‹œì ìœ¼ë¡œ 다운ë˜ì—ˆê±°ë‚˜ 새 웹 주소로 완전히 ì´ë™í–ˆì„ 수 있습니다.</translation>
<translation id="4766713847338118463">하단 듀얼 스테ì´í”Œ</translation>
<translation id="4771973620359291008">ì•Œ 수 없는 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤.</translation>
@@ -1205,12 +1243,6 @@
<translation id="4819347708020428563">기본 ë·°ì—ì„œ 주ì„ì„ ìˆ˜ì •í• ê¹Œìš”?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />, Tabì„ ëˆ„ë¥¸ ë‹¤ìŒ Enter를 눌러 빠르게 새 Google 시트 만들기</translation>
<translation id="4825507807291741242">강력함</translation>
-<translation id="4827402517081186284">ì‹œí¬ë¦¿ 모드를 ì‚¬ìš©í•´ë„ ë‚˜ì˜ ì˜¨ë¼ì¸ 활ë™ì´ 완전히 비공개로 유지ë˜ì§€ëŠ” 않습니다.
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />사ì´íŠ¸ì—ì„œ ë‚´ê°€ 방문했는지 ì•Œ 수 있습니다.<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />ì§ìž¥ ë˜ëŠ” í•™êµì—ì„œ íƒìƒ‰ 활ë™ì„ 추ì í•  수 있습니다.<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />ì¸í„°ë„· 서비스 제공업체ì—ì„œ 웹 íŠ¸ëž˜í”½ì„ ëª¨ë‹ˆí„°ë§í•  수 있습니다.<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">경고 켜기</translation>
<translation id="4838327282952368871">꿈</translation>
<translation id="4840250757394056958">Chrome 방문 ê¸°ë¡ ë³´ê¸°</translation>
@@ -1222,12 +1254,12 @@
<translation id="4854362297993841467">사용할 수 없는 배달 방법입니다. 다른 ë°©ë²•ì„ ì„ íƒí•˜ì„¸ìš”.</translation>
<translation id="4854853140771946034">Google Keepì—ì„œ 빠르게 새 메모 만들기</translation>
<translation id="485902285759009870">코드 ì¸ì¦ 중...</translation>
+<translation id="4866506163384898554">커서를 표시하려면 |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| 키를 누르세요.</translation>
<translation id="4876188919622883022">간단히 보기</translation>
<translation id="4876305945144899064">ì‚¬ìš©ìž ì´ë¦„ ì—†ìŒ</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{ì—†ìŒ}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831"><ph name="TEXT" /> 검색</translation>
<translation id="4879491255372875719">ìžë™(기본값)</translation>
-<translation id="4879725228911483934">화면ì—ì„œ ì°½ì„ ì—´ê³  배치합니다.</translation>
<translation id="4880827082731008257">ê¸°ë¡ ê²€ìƒ‰</translation>
<translation id="4881695831933465202">열기</translation>
<translation id="4885256590493466218">결제 시 <ph name="CARD_DETAIL" /> 사용</translation>
@@ -1236,6 +1268,7 @@
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">9번째 롤</translation>
<translation id="4901778704868714008">저장...</translation>
+<translation id="4905659621780993806">관리ìžê°€ <ph name="DATE" /> <ph name="TIME" />ì— ê¸°ê¸°ë¥¼ ìžë™ìœ¼ë¡œ 다시 시작합니다. 기기가 다시 시작ë˜ê¸° ì „ì— ì‹¤í–‰ ì¤‘ì¸ í•­ëª©ì„ ì €ìž¥í•˜ì„¸ìš”.</translation>
<translation id="4913987521957242411">왼쪽 ìƒë‹¨ 펀칭</translation>
<translation id="4918221908152712722"><ph name="APP_NAME" /> 설치(다운로드 í•„ìš” ì—†ìŒ)</translation>
<translation id="4923459931733593730">결제</translation>
@@ -1244,6 +1277,7 @@
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, Tabì„ ëˆ„ë¥¸ ë‹¤ìŒ Enter를 눌러 검색</translation>
<translation id="4930153903256238152">대용량</translation>
+<translation id="4940163644868678279">Chrome ì‹œí¬ë¦¿ 모드</translation>
<translation id="4943872375798546930">검색결과가 없습니다.</translation>
<translation id="4950898438188848926">탭 전환 버튼, <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /> 열린 탭으로 전환하려면 Enter를 누르세요</translation>
<translation id="495170559598752135">ìž‘ì—…</translation>
@@ -1253,6 +1287,7 @@
<translation id="4968522289500246572">모바ì¼ìš© 앱ì´ë¯€ë¡œ í¬ê¸°ê°€ 제대로 ì¡°ì ˆë˜ì§€ ì•Šì„ ìˆ˜ë„ ìžˆìŠµë‹ˆë‹¤. 문제가 ë°œìƒí•˜ê±°ë‚˜ ì•±ì´ ë‹¤ì‹œ ì‹œìž‘ë  ìˆ˜ 있습니다.</translation>
<translation id="4969341057194253438">ë…¹ìŒ íŒŒì¼ ì‚­ì œ</translation>
<translation id="4973922308112707173">ìƒë‹¨ 2ê³µ 펀칭</translation>
+<translation id="4976702386844183910">최근 방문: <ph name="DATE" /></translation>
<translation id="4984088539114770594">마ì´í¬ë¥¼ 사용하시겠습니까?</translation>
<translation id="4984339528288761049">Prc5(봉투)</translation>
<translation id="4989163558385430922">ëª¨ë‘ ë³´ê¸°</translation>
@@ -1314,6 +1349,7 @@
<translation id="5138227688689900538">간략히</translation>
<translation id="5145883236150621069">ì •ì±… ì‘ë‹µì— ì˜¤ë¥˜ 코드가 í¬í•¨ë˜ì–´ 있ìŒ</translation>
<translation id="5146995429444047494"><ph name="ORIGIN" /> ì•Œë¦¼ì´ ì°¨ë‹¨ë¨</translation>
+<translation id="514704532284964975"><ph name="URL" />ì—ì„œ 휴대전화로 탭하는 NFC ê¸°ê¸°ì˜ ì •ë³´ë¥¼ ë³´ê³  변경하려고 합니다.</translation>
<translation id="5148809049217731050">ì¸ì‡„ë©´ì´ ìœ„ë¡œ</translation>
<translation id="515292512908731282">C4(봉투)</translation>
<translation id="5158275234811857234">표지</translation>
@@ -1338,6 +1374,7 @@
<translation id="5215116848420601511">Google Payì— ì‚¬ìš©ë˜ëŠ” ê²°ì œ 수단 ë° ì£¼ì†Œ</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">íŠ¸ë ˆì´ 13</translation>
+<translation id="5216942107514965959">최근 방문: 오늘</translation>
<translation id="5222812217790122047">ì´ë©”ì¼ì€ 필수입니다.</translation>
<translation id="5230733896359313003">배송지 주소</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1358,7 +1395,6 @@
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">문서 ì†ì„±</translation>
<translation id="528468243742722775">종료</translation>
-<translation id="5284909709419567258">ë„¤íŠ¸ì›Œí¬ ì£¼ì†Œ</translation>
<translation id="5285570108065881030">ì €ìž¥ëœ ë¹„ë°€ë²ˆí˜¸ ëª¨ë‘ í‘œì‹œ</translation>
<translation id="5287240709317226393">쿠키 표시</translation>
<translation id="5287456746628258573">ì´ ì‚¬ì´íŠ¸ì—서는 ì˜¤ëž˜ëœ ë³´ì•ˆ êµ¬ì„±ì„ ì‚¬ìš©í•˜ë¯€ë¡œ ì •ë³´(예: 비밀번호나 ì‹ ìš©ì¹´ë“œ 번호)를 ì´ ì‚¬ì´íŠ¸ë¡œ 전송할 경우 ì •ë³´ê°€ ìœ ì¶œë  ìˆ˜ë„ ìžˆìŠµë‹ˆë‹¤.</translation>
@@ -1442,6 +1478,7 @@
<translation id="5556459405103347317">새로고침</translation>
<translation id="5560088892362098740">만료ì¼</translation>
<translation id="55635442646131152">문서 개요</translation>
+<translation id="5565613213060953222">ì‹œí¬ë¦¿ 탭 열기</translation>
<translation id="5565735124758917034">활성</translation>
<translation id="5570825185877910964">계정 보호</translation>
<translation id="5571083550517324815">ì´ ì£¼ì†Œì—ì„œ 수령할 수 없습니다. 다른 주소를 ì„ íƒí•˜ì„¸ìš”.</translation>
@@ -1524,6 +1561,7 @@
<translation id="5869522115854928033">ì €ìž¥ëœ ë¹„ë°€ë²ˆí˜¸</translation>
<translation id="5873013647450402046">ì€í–‰ì—ì„œ ë³¸ì¸ í™•ì¸ì„ 요청합니다.</translation>
<translation id="5887400589839399685">ì €ìž¥ëœ ì¹´ë“œ</translation>
+<translation id="5887687176710214216">최근 방문: 어제</translation>
<translation id="5895138241574237353">다시 시작</translation>
<translation id="5895187275912066135">발급ì¼:</translation>
<translation id="5901630391730855834">노란색</translation>
@@ -1537,6 +1575,7 @@
<translation id="5921639886840618607">카드를 Google ê³„ì •ì— ì €ìž¥í•˜ì‹œê² ìŠµë‹ˆê¹Œ?</translation>
<translation id="5922853866070715753">ê±°ì˜ ì™„ë£Œë˜ì—ˆìŠµë‹ˆë‹¤</translation>
<translation id="5932224571077948991">사ì´íŠ¸ì—ì„œ ë°©í•´ê°€ ë˜ê±°ë‚˜ 사용ìžë¥¼ 현혹하는 광고를 표시함</translation>
+<translation id="5938153366081463283">ê°€ìƒ ì¹´ë“œ 추가</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347"><ph name="SITE_NAME" /> 여는 중…</translation>
<translation id="5951495562196540101">ì¼ë°˜ 계정으로 등ë¡í•  수 없습니다(패키지 ë¼ì´ì„ ìŠ¤ 사용 가능).</translation>
@@ -1601,6 +1640,7 @@
<translation id="6120179357481664955">UPI ID를 저장하시겠습니까?</translation>
<translation id="6124432979022149706">Chrome Enterprise Connectors</translation>
<translation id="6127379762771434464">항목 ì‚­ì œë¨</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Chrome ì‹œí¬ë¦¿ 모드 ìžì„¸ížˆ 알아보기<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">ì¼€ì´ë¸”ì„ í™•ì¸í•˜ê³  사용 ì¤‘ì¸ ë¼ìš°í„°, 모뎀 ë˜ëŠ” 기타 ë„¤íŠ¸ì›Œí¬ ê¸°ê¸°ë¥¼
재부팅하시기 ë°”ëžë‹ˆë‹¤.</translation>
<translation id="614940544461990577">ë‹¤ìŒ ë°©ë²•ì„ ì‹œë„í•´ 보세요.</translation>
@@ -1613,7 +1653,6 @@
<translation id="6169916984152623906">ì´ì œ 비공개로 ì¸í„°ë„·ì„ 사용할 수 있으며, ì´ ê¸°ê¸°ë¥¼ 사용하는 다른 사용ìžê°€ ë‚´ 활ë™ì„ ë³¼ 수 없습니다. 하지만 다운로드한 항목과 ë¶ë§ˆí¬ëŠ” 저장ë©ë‹ˆë‹¤.</translation>
<translation id="6177128806592000436">ì´ ì‚¬ì´íŠ¸ëŠ” 보안 ì—°ê²°(HTTPS)ì´ ì‚¬ìš©ë˜ì§€ 않았습니다.</translation>
<translation id="6180316780098470077">ìž¬ì‹œë„ ê°„ê²©</translation>
-<translation id="619448280891863779">화면ì—ì„œ ì°½ì„ ì—´ì–´ í™”ë©´ì— ë°°ì¹˜í•˜ë„ë¡ ìš”ì²­í•  수 있ìŒ</translation>
<translation id="6196640612572343990">타사 쿠키 차단</translation>
<translation id="6203231073485539293">ì¸í„°ë„· ì—°ê²°ì„ í™•ì¸í•˜ì„¸ìš”.</translation>
<translation id="6218753634732582820">Chromiumì—ì„œ 주소를 삭제하시겠습니까?</translation>
@@ -1636,7 +1675,7 @@
<translation id="6272383483618007430">Google ì—…ë°ì´íŠ¸</translation>
<translation id="6276112860590028508">ì½ê¸° 목ë¡ì˜ 페ì´ì§€ê°€ ì—¬ê¸°ì— í‘œì‹œë©ë‹ˆë‹¤.</translation>
<translation id="627746635834430766">다ìŒë²ˆì— ë” ë¹ ë¥´ê²Œ 결제할 수 있ë„ë¡ Google ê³„ì •ì— ì¹´ë“œì™€ 청구서 수신 주소를 저장하세요.</translation>
-<translation id="6279098320682980337">ê°€ìƒ ì¹´ë“œ 번호가 ìžë™ 완성ë˜ì§€ 않았나요? 복사할 ì¹´ë“œ 세부정보를 í´ë¦­í•˜ì„¸ìš”.</translation>
+<translation id="6279183038361895380">|<ph name="ACCELERATOR" />|ì„(를) 눌러 커서 표시</translation>
<translation id="6280223929691119688">ì´ ì£¼ì†Œë¡œ 배달할 수 없습니다. 다른 주소를 ì„ íƒí•˜ì„¸ìš”.</translation>
<translation id="6282194474023008486">우편번호</translation>
<translation id="6285507000506177184">Chrome 다운로드 관리 버튼, Chromeì—ì„œ 다운로드한 파ì¼ì„ 관리하려면 Enter를 누르세요</translation>
@@ -1644,6 +1683,7 @@
<translation id="6290238015253830360">추천 콘í…츠가 ì—¬ê¸°ì— í‘œì‹œë©ë‹ˆë‹¤.</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{지금 기기가 다시 시작ë©ë‹ˆë‹¤}=1{1ì´ˆ í›„ì— ê¸°ê¸°ê°€ 다시 시작ë©ë‹ˆë‹¤}other{#ì´ˆ í›„ì— ê¸°ê¸°ê°€ 다시 시작ë©ë‹ˆë‹¤}}</translation>
<translation id="6302269476990306341">Chromeì˜ Google 어시스턴트 중지하는 중</translation>
<translation id="6305205051461490394"><ph name="URL" />ì— ì—°ê²°í•  수 없습니다.</translation>
<translation id="6312113039770857350">웹페ì´ì§€ë¥¼ 사용할 수 ì—†ìŒ</translation>
@@ -1717,6 +1757,7 @@
<translation id="6529602333819889595">삭제 다시 실행(&amp;R)</translation>
<translation id="6545864417968258051">블루투스 검색</translation>
<translation id="6547208576736763147">왼쪽 2공 펀칭</translation>
+<translation id="6554732001434021288">최근 방문: <ph name="NUM_DAYS" />ì¼ ì „</translation>
<translation id="6556866813142980365">다시실행</translation>
<translation id="6569060085658103619">확장 프로그램 페ì´ì§€ë¥¼ 보는 중</translation>
<translation id="6573200754375280815">오른쪽 2공 펀칭</translation>
@@ -1777,7 +1818,6 @@
<translation id="6757797048963528358">기기가 절전 모드 ìƒíƒœìž…니다.</translation>
<translation id="6767985426384634228">주소를 ì—…ë°ì´íŠ¸í•˜ì‹œê² ìŠµë‹ˆê¹Œ?</translation>
<translation id="6768213884286397650">Hagaki(엽서)</translation>
-<translation id="6774185088257932239">ì‹œí¬ë¦¿ ëª¨ë“œì— ê´€í•´ <ph name="BEGIN_LINK" />ìžì„¸ížˆ 알아보기<ph name="END_LINK" /></translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">ë³´ë¼ìƒ‰</translation>
<translation id="6786747875388722282">확장 프로그램</translation>
@@ -1861,7 +1901,6 @@
<translation id="706295145388601875">Chrome 설정ì—ì„œ 주소 추가 ë° ê´€ë¦¬</translation>
<translation id="7064851114919012435">ì—°ë½ì²˜ ì •ë³´</translation>
<translation id="7068733155164172741"><ph name="OTP_LENGTH" />ìžë¦¬ 코드 ìž…ë ¥</translation>
-<translation id="7070090581017165256">사ì´íŠ¸ ì •ë³´</translation>
<translation id="70705239631109039">ì—°ê²°ì˜ ë³´ì•ˆì´ ì™„ë²½í•˜ì§€ ì•ŠìŒ</translation>
<translation id="7075452647191940183">ìš”ì²­ì´ ë„ˆë¬´ í¼</translation>
<translation id="7079718277001814089">ì´ ì‚¬ì´íŠ¸ì— 멀웨어가 있습니다.</translation>
@@ -1878,6 +1917,12 @@
<translation id="7111012039238467737">(유효)</translation>
<translation id="7118618213916969306">í´ë¦½ë³´ë“œ URL <ph name="SHORT_URL" /> 검색</translation>
<translation id="7119414471315195487">다른 탭 ë˜ëŠ” 프로그램 닫기</translation>
+<translation id="7129355289156517987">Chromium ì‹œí¬ë¦¿ íƒ­ì„ ëª¨ë‘ ë‹«ìœ¼ë©´ 기기ì—ì„œ ë‹¤ìŒ íƒ­ì˜ í™œë™ì´ ì‚­ì œë©ë‹ˆë‹¤.
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />íƒìƒ‰ 활ë™<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />검색 기ë¡<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ì–‘ì‹ì— ìž…ë ¥ëœ ì •ë³´<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">ì´ ì£¼ì†Œë¡œ 배송할 수 없습니다. 다른 주소를 ì„ íƒí•˜ì„¸ìš”.</translation>
<translation id="7132939140423847331">관리ìžê°€ 복사를 금지한 ë°ì´í„°ìž…니다.</translation>
<translation id="7135130955892390533">ìƒíƒœ 보기</translation>
@@ -1900,6 +1945,7 @@
<translation id="7192203810768312527"><ph name="SIZE" />ì˜ ì €ìž¥ìš©ëŸ‰ì„ í™•ë³´í•©ë‹ˆë‹¤. ì¼ë¶€ 사ì´íŠ¸ëŠ” 다ìŒì— 방문할 ë•Œ 로드 ì†ë„ê°€ ëŠë ¤ì§ˆ ìˆ˜ë„ ìžˆìŠµë‹ˆë‹¤.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">관리ìžê°€ ë³¼ 수 있는 í•­ëª©ì€ ë‹¤ìŒê³¼ 같습니다.</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, 새 ì‹œí¬ë¦¿ íƒ­ì„ ì—´ì–´ 비공개로 íƒìƒ‰í•˜ë ¤ë©´ Tabì„ ëˆ„ë¥¸ ë‹¤ìŒ Enter 누르기</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" />ì—ì„œ 보안 ê¸°ì¤€ì„ ì¤€ìˆ˜í•˜ì§€ 않습니다.</translation>
<translation id="7210993021468939304">컨테ì´ë„ˆ ë‚´ Linux í™œë™ ë° ì»¨í…Œì´ë„ˆ ë‚´ì—ì„œ Linux 앱 설치 ë° ì‹¤í–‰ 가능</translation>
@@ -1931,6 +1977,7 @@
<translation id="7304562222803846232">Google 계정 ê°œì¸ ì •ë³´ 보호 설정 관리</translation>
<translation id="7305756307268530424">ëŠë¦° ì†ë„ë¡œ 시작</translation>
<translation id="7308436126008021607">백그ë¼ìš´ë“œ ë™ê¸°í™”</translation>
+<translation id="7310392214323165548">기기가 곧 다시 시작ë©ë‹ˆë‹¤</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">ì—°ê²° ë„움ë§</translation>
<translation id="7323804146520582233">‘<ph name="SECTION" />’ 섹션 숨기기</translation>
@@ -1938,6 +1985,7 @@
<translation id="7334320624316649418">재정렬 다시 실행(&amp;R)</translation>
<translation id="7335157162773372339">ì¹´ë©”ë¼ ì‚¬ìš©ì„ ìš”ì²­í•  수 있ìŒ</translation>
<translation id="7337248890521463931">ìžë§‰ 펼치기</translation>
+<translation id="7337418456231055214">ê°€ìƒ ì¹´ë“œ 번호가 ìžë™ 완성ë˜ì§€ 않았나요? 복사할 ì¹´ë“œ 세부정보를 í´ë¦­í•˜ì„¸ìš”. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">사용 ì¤‘ì¸ í”Œëž«í¼ì—서는 제공ë˜ì§€ 않습니다.</translation>
<translation id="733923710415886693">서버 ì¸ì¦ì„œê°€ ì¸ì¦ì„œ 투명성 ì •ì±…ì„ ì‚¬ìš©í•˜ì—¬ 공개ë˜ì§€ 않았습니다.</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1960,6 +2008,7 @@
<translation id="7378627244592794276">안함</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">해당 사항 ì—†ìŒ</translation>
+<translation id="7388594495505979117">{0,plural, =1{1분 í›„ì— ê¸°ê¸°ê°€ 다시 시작ë©ë‹ˆë‹¤}other{#분 í›„ì— ê¸°ê¸°ê°€ 다시 시작ë©ë‹ˆë‹¤}}</translation>
<translation id="7390545607259442187">ì¹´ë“œ 확ì¸</translation>
<translation id="7392089738299859607">주소 ì—…ë°ì´íŠ¸</translation>
<translation id="7399802613464275309">안전 확ì¸</translation>
@@ -1995,6 +2044,12 @@
<translation id="7485870689360869515">ë°ì´í„° ì—†ìŒ</translation>
<translation id="7495528107193238112">ì´ ì½˜í…츠는 차단ë˜ì–´ 있습니다. 문제를 해결하려면 사ì´íŠ¸ 소유ìžì—게 문ì˜í•˜ì„¸ìš”.</translation>
<translation id="7497998058912824456">문서 만들기 버튼, Enter를 눌러 빠르게 새 Google 문서 만들기</translation>
+<translation id="7506488012654002225">Chromiumì—서는 ë‹¤ìŒ ì •ë³´ë¥¼ <ph name="BEGIN_EMPHASIS" />저장하지 않습니다<ph name="END_EMPHASIS" />.
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />방문 기ë¡
+ <ph name="LIST_ITEM" />쿠키 ë° ì‚¬ì´íŠ¸ ë°ì´í„°
+ <ph name="LIST_ITEM" />ì–‘ì‹ì— ìž…ë ¥ëœ ì •ë³´
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">ë°˜í™˜ëœ ì •ì±… 기기 IDê°€ 비었거나 현재 기기 ID와 ì¼ì¹˜í•˜ì§€ ì•ŠìŒ</translation>
<translation id="7508870219247277067">ì•„ë³´ì¹´ë„ ë…¹ìƒ‰</translation>
<translation id="7511955381719512146">사용 ì¤‘ì¸ Wi-Fiì—ì„œ <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> ë°©ë¬¸ì„ ìš”ì²­í•  수 있습니다.</translation>
@@ -2108,7 +2163,6 @@
<translation id="7813600968533626083">Chromeì—ì„œ 추천검색어를 삭제하시겠습니까?</translation>
<translation id="781440967107097262">í´ë¦½ë³´ë“œë¥¼ 공유하시겠습니까?</translation>
<translation id="7815407501681723534">'<ph name="SEARCH_STRING" />'ì— ëŒ€í•´ <ph name="SEARCH_RESULTS" /> <ph name="NUMBER_OF_RESULTS" />ê°œì˜ ê²€ìƒ‰ 결과를 찾았습니다.</translation>
-<translation id="782125616001965242">ì´ ì‚¬ì´íŠ¸ì— 관한 ì •ë³´ 표시</translation>
<translation id="782886543891417279">사용 ì¤‘ì¸ Wi-Fi(<ph name="WIFI_NAME" />)ì—ì„œ ë¡œê·¸ì¸ íŽ˜ì´ì§€ ë°©ë¬¸ì„ ìš”ì²­í•  수 있습니다.</translation>
<translation id="7836231406687464395">Postfix(봉투)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{ì—†ìŒ}=1{앱 1ê°œ(<ph name="EXAMPLE_APP_1" />)}=2{앱 2ê°œ(<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}other{앱 #ê°œ(<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}}</translation>
@@ -2125,7 +2179,6 @@
<translation id="7888575728750733395">ì¸ì‡„ ë Œë”ë§ ì¸í…트</translation>
<translation id="7894280532028510793">ì² ìžê°€ 올바르다면 <ph name="BEGIN_LINK" />ë„¤íŠ¸ì›Œí¬ ì§„ë‹¨ì„ ì‹¤í–‰<ph name="END_LINK" />í•´ 보세요.</translation>
<translation id="7904208859782148177">C3(봉투)</translation>
-<translation id="7931318309563332511">ì•Œ 수 ì—†ìŒ</translation>
<translation id="793209273132572360">주소를 ì—…ë°ì´íŠ¸í•˜ì‹œê² ìŠµë‹ˆê¹Œ?</translation>
<translation id="7932579305932748336">코팅</translation>
<translation id="79338296614623784">올바른 전화번호를 입력하세요.</translation>
@@ -2150,13 +2203,14 @@
<translation id="7976214039405368314">요청 횟수가 너무 많ìŒ</translation>
<translation id="7977538094055660992">출력 기기</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">ë‹¤ìŒ ì¹´ë“œì™€ ì—°ê²°ë¨</translation>
<translation id="798134797138789862">ê°€ìƒ í˜„ì‹¤ 기기 ë° ë°ì´í„°ì˜ ì‚¬ìš©ì„ ìš”ì²­í•  수 있ìŒ</translation>
<translation id="7984945080620862648">현재 <ph name="SITE" />ì—ì„œ Chromeì´ ì²˜ë¦¬í•  수 없는 ì•”í˜¸í™”ëœ ìžê²©ì¦ëª… 정보를 전송했기 ë•Œë¬¸ì— ë°©ë¬¸í•  수 없습니다. ë„¤íŠ¸ì›Œí¬ ì˜¤ë¥˜ì™€ ê³µê²©ì€ ëŒ€ë¶€ë¶„ ì¼ì‹œì ì´ë¯€ë¡œ ìž ì‹œ 후 페ì´ì§€ê°€ ì •ìƒí™”ë  ê²ƒìž…ë‹ˆë‹¤.</translation>
-<translation id="79859296434321399">ì¦ê°• 현실 콘í…츠를 보려면 ARCore를 설치하세요.</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">ë°”ì¸ë“œ</translation>
<translation id="7992044431894087211"><ph name="APPLICATION_TITLE" />ê³¼(와)ì˜ í™”ë©´ 공유가 재개ë˜ì—ˆìŠµë‹ˆë‹¤.</translation>
<translation id="7995512525968007366">지정ë˜ì§€ ì•ŠìŒ</translation>
+<translation id="7998269595945679889">ì‹œí¬ë¦¿ 탭 열기 버튼, 새 ì‹œí¬ë¦¿ íƒ­ì„ ì—´ì–´ 비공개로 íƒìƒ‰í•˜ë ¤ë©´ Enter 누르기</translation>
<translation id="800218591365569300">다른 탭ì´ë‚˜ í”„ë¡œê·¸ëž¨ì„ ì¢…ë£Œí•˜ì—¬ 메모리를 확보하세요.</translation>
<translation id="8004582292198964060">브ë¼ìš°ì €</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{ì´ ì¹´ë“œì™€ 청구서 수신 주소가 저장ë©ë‹ˆë‹¤. <ph name="USER_EMAIL" /> 계정으로 로그ì¸í•˜ë©´ 카드를 사용할 수 있습니다.}other{ì´ ì¹´ë“œì™€ 청구서 수신 주소가 저장ë©ë‹ˆë‹¤. <ph name="USER_EMAIL" /> 계정으로 로그ì¸í•˜ë©´ 카드를 사용할 수 있습니다.}}</translation>
@@ -2216,6 +2270,7 @@
<translation id="8202370299023114387">충ëŒ</translation>
<translation id="8206978196348664717">Prc4(봉투)</translation>
<translation id="8211406090763984747">ì´ ì‚¬ì´íŠ¸ëŠ” 보안 ì—°ê²°(HTTPS)ì´ ì‚¬ìš©ë˜ì—ˆìŠµë‹ˆë‹¤.</translation>
+<translation id="8217240300496046857">사ì´íŠ¸ì—ì„œ 웹 ì „ë°˜ì— ê±¸ì³ ì‚¬ìš©ìžë¥¼ 추ì í•˜ëŠ” 쿠키를 사용할 수 없습니다. ì¼ë¶€ 사ì´íŠ¸ì—서는 ê¸°ëŠ¥ì´ ìž‘ë™í•˜ì§€ ì•Šì„ ìˆ˜ 있습니다.</translation>
<translation id="8218327578424803826">ì§€ì •ëœ ìœ„ì¹˜:</translation>
<translation id="8220146938470311105">C7/C6(봉투)</translation>
<translation id="8225771182978767009">컴퓨터를 설정한 사용ìžê°€ ì´ ì‚¬ì´íŠ¸ë¥¼ 차단했습니다.</translation>
@@ -2256,14 +2311,9 @@
<translation id="830498451218851433">í´ë“œ 하프</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">ì„¤ì¹˜ëœ ì•± ë° ì•±ì˜ ì‚¬ìš© 빈ë„</translation>
+<translation id="8317207217658302555">ARCore를 ì—…ë°ì´íŠ¸í•˜ì‹œê² ìŠµë‹ˆê¹Œ?</translation>
<translation id="831997045666694187">ì €ë…</translation>
<translation id="8321476692217554900">알림</translation>
-<translation id="8328484624016508118">모든 ì‹œí¬ë¦¿ íƒ­ì„ ì¢…ë£Œí•˜ë©´ Chromeì—ì„œ ë‹¤ìŒ í•­ëª©ì„ ì‚­ì œí•©ë‹ˆë‹¤.
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />ê¸°ê¸°ì˜ íƒìƒ‰ 활ë™<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />ê¸°ê¸°ì˜ ê²€ìƒ‰ 기ë¡<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />ì–‘ì‹ì— ìž…ë ¥ëœ ì •ë³´<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489"><ph name="HOST_NAME" />ì— ëŒ€í•œ 액세스가 거부ë¨</translation>
<translation id="833262891116910667">강조표시</translation>
<translation id="8339163506404995330"><ph name="LANGUAGE" />ë¡œ ëœ íŽ˜ì´ì§€ë¥¼ 번역하지 않습니다.</translation>
@@ -2315,6 +2365,7 @@
<translation id="8507227106804027148">명령줄</translation>
<translation id="8508648098325802031">검색 ì•„ì´ì½˜</translation>
<translation id="8511402995811232419">쿠키 관리</translation>
+<translation id="8519753333133776369">관리ìžê°€ 허용한 HID 기기</translation>
<translation id="8522552481199248698">Chromeì„ í†µí•´ Google ê³„ì •ì„ ë³´í˜¸í•˜ê³  비밀번호를 변경할 수 있습니다.</translation>
<translation id="8530813470445476232">Chrome 설정ì—ì„œ 방문 기ë¡, 쿠키, ìºì‹œ ë“±ì„ ì‚­ì œí•˜ì„¸ìš”.</translation>
<translation id="8533619373899488139">ì°¨ë‹¨ëœ URL ë° ì‹œìŠ¤í…œ 관리ìžê°€ 설정한 기타 ì •ì±… 목ë¡ì„ 확ì¸í•˜ë ¤ë©´ &lt;strong&gt;chrome://policy&lt;/strong&gt;를 방문하세요.</translation>
@@ -2326,7 +2377,6 @@
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{권한 재설정}other{권한 재설정}}</translation>
<translation id="8555010941760982128">ê²°ì œ ì‹œ ë‹¤ìŒ ì½”ë“œë¥¼ 사용하세요</translation>
<translation id="8557066899867184262">CVC는 ì¹´ë“œ ë’·ë©´ì— ìžˆìŠµë‹ˆë‹¤.</translation>
-<translation id="8558485628462305855">ì¦ê°• 현실 콘í…츠를 보려면 ARCore를 ì—…ë°ì´íŠ¸í•˜ì„¸ìš”.</translation>
<translation id="8559762987265718583">ê¸°ê¸°ì˜ ë‚ ì§œì™€ 시간(<ph name="DATE_AND_TIME" />)ì´ ìž˜ëª»ë˜ì–´ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />ì— ëŒ€í•œ 비공개 ì—°ê²°ì„ ì„¤ì •í•  수 없습니다.</translation>
<translation id="8564182942834072828">ë³„ë„ ë¬¸ì„œ/모으지 ì•Šì€ ì‚¬ë³¸</translation>
<translation id="8564985650692024650">다른 사ì´íŠ¸ì—ì„œ 비밀번호를 재사용했다면 <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> 비밀번호를 재설정하는 ê²ƒì´ ì¢‹ìŠµë‹ˆë‹¤.</translation>
@@ -2345,6 +2395,7 @@
<translation id="865032292777205197">움ì§ìž„ ê°ì§€ 센서</translation>
<translation id="8663226718884576429">주문 요약, <ph name="TOTAL_LABEL" />, 세부정보 ë”보기</translation>
<translation id="8666678546361132282">ì˜ì–´</translation>
+<translation id="8669306706049782872">í™”ë©´ì— ê´€í•œ 정보를 사용하여 ì°½ì„ ì—´ê³  배치합니다.</translation>
<translation id="867224526087042813">서명</translation>
<translation id="8676424191133491403">지연 ì—†ìŒ</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, 답변, <ph name="ANSWER" /></translation>
@@ -2371,6 +2422,7 @@
<translation id="8731544501227493793">비밀번호 관리 버튼, Chrome 설정ì—ì„œ 비밀번호를 확ì¸í•˜ê³  관리하려면 Enter 누르기</translation>
<translation id="8734529307927223492">ë‚´ <ph name="DEVICE_TYPE" />ì€(는) <ph name="MANAGER" />ì—ì„œ 관리합니다</translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, 새 ì‹œí¬ë¦¿ ì°½ì„ ì—´ì–´ 비공개ì ìœ¼ë¡œ íƒìƒ‰í•˜ë ¤ë©´ Tabì„ ëˆ„ë¥¸ ë‹¤ìŒ Enter 누르기</translation>
+<translation id="8737685506611670901"><ph name="REPLACED_HANDLER_TITLE" /> 대신 <ph name="PROTOCOL" /> ë§í¬ 열기</translation>
<translation id="8738058698779197622">보안 ì—°ê²°ì„ ì„¤ì •í•˜ë ¤ë©´ 시계가 올바로 설정ë˜ì–´ 있어야 합니다. 웹사ì´íŠ¸ê°€ ìžì‹ ì„ ì‹ë³„하는 ë° ì‚¬ìš©í•˜ëŠ” ì¸ì¦ì„œê°€ 특정 기간ì—만 유효하기 때문입니다. ê¸°ê¸°ì˜ ì‹œê³„ê°€ 잘못 설정ë˜ì–´ Chromiumì—ì„œ ì´ ì¸ì¦ì„œë¥¼ 확ì¸í•  수 없습니다.</translation>
<translation id="8740359287975076522"><ph name="HOST_NAME" />ì˜ &lt;abbr id="dnsDefinition"&gt;DNS 주소&lt;/abbr&gt;를 ì°¾ì„ ìˆ˜ 없습니다. 문제를 진단하는 중입니다.</translation>
<translation id="8742371904523228557"><ph name="ORIGIN" /> 코드는 <ph name="ONE_TIME_CODE" />입니다.</translation>
@@ -2398,6 +2450,7 @@
<translation id="883848425547221593">기타 ë¶ë§ˆí¬</translation>
<translation id="884264119367021077">배송지 주소</translation>
<translation id="884923133447025588">í기 ë§¤ì»¤ë‹ˆì¦˜ì„ ì°¾ì„ ìˆ˜ 없습니다.</translation>
+<translation id="8849262850971482943">보안 강화를 위해 ê°€ìƒ ì¹´ë“œ 사용하기</translation>
<translation id="885730110891505394">Google과 공유</translation>
<translation id="8858065207712248076">다른 사ì´íŠ¸ì—ì„œ 비밀번호를 재사용했다면 <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> 비밀번호를 재설정하는 ê²ƒì´ ì¢‹ìŠµë‹ˆë‹¤.</translation>
<translation id="885906927438988819">ì² ìžê°€ 올바르다면 <ph name="BEGIN_LINK" />Windows ë„¤íŠ¸ì›Œí¬ ì§„ë‹¨ì„ ì‹¤í–‰<ph name="END_LINK" />í•´ 보세요.</translation>
@@ -2447,6 +2500,7 @@
<translation id="9004367719664099443">VR 세션 진행 중</translation>
<translation id="9005998258318286617">PDF 문서를 로드하지 못했습니다.</translation>
<translation id="9008201768610948239">무시</translation>
+<translation id="901834265349196618">ì´ë©”ì¼</translation>
<translation id="9020200922353704812">카드 청구서 수신 주소가 필요함</translation>
<translation id="9020542370529661692">ì´ íŽ˜ì´ì§€ëŠ” <ph name="TARGET_LANGUAGE" />ë¡œ 번역ë˜ì—ˆìŠµë‹ˆë‹¤.</translation>
<translation id="9020742383383852663">A8</translation>
@@ -2495,6 +2549,7 @@
<translation id="9150045010208374699">ì¹´ë©”ë¼ ì‚¬ìš©</translation>
<translation id="9150685862434908345">관리ìžê°€ ì›ê²©ìœ¼ë¡œ 브ë¼ìš°ì € ì„¤ì •ì„ ë³€ê²½í•  수 있습니다. ì´ ê¸°ê¸°ì˜ í™œë™ì€ Chrome 외부ì—ì„œë„ ê´€ë¦¬í•  수 있습니다. <ph name="BEGIN_LINK" />ìžì„¸ížˆ 알아보기<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">ì—…ë°ì´íŠ¸ë¨</translation>
+<translation id="9155211586651734179">ì—°ê²°ëœ ì˜¤ë””ì˜¤ 주변기기</translation>
<translation id="9157595877708044936">설정 중...</translation>
<translation id="9158625974267017556">C6(봉투)</translation>
<translation id="9164029392738894042">정확성 검사</translation>
diff --git a/chromium/components/strings/components_strings_ky.xtb b/chromium/components/strings/components_strings_ky.xtb
index be887e8d45e..e8cb6ec9514 100644
--- a/chromium/components/strings/components_strings_ky.xtb
+++ b/chromium/components/strings/components_strings_ky.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">Чоо-жайын көрүү</translation>
<translation id="1030706264415084469"><ph name="URL" /> түзмөгүңүзгө көлөмдүү дайындарды биротоло Ñактаганы жатат</translation>
<translation id="1032854598605920125">Сааттын жебеÑи боюнча айландыруу</translation>
+<translation id="1033329911862281889">Жашыруун режимде айрым аракеттериңиз көрүнөт:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Ðлар колдонгон Ñайттар жана кызматтар киргениңизди билип турушат<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Жумуш берүүчүлөр же окуу жайлар көрүлгөн вебÑайттарга көз Ñала алышат<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Интернет кызматын жабдуучулар веб трафикти көзөмөлдөй алышат<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">Өчүрүү</translation>
<translation id="1036982837258183574">Толук Ñкрандан чыгуу үчүн |<ph name="ACCELERATOR" />| баÑкычын баÑыңыз</translation>
<translation id="1038106730571050514">Сунуштарды көрÑÓ©Ñ‚Ò¯Ò¯</translation>
<translation id="1038842779957582377">белгиÑиз ат</translation>
<translation id="1041998700806130099">Жумуш барагынын билдирүүÑÒ¯</translation>
<translation id="1048785276086539861">ÐннотациÑларды түзөтүүдө бул документ бир бет көрүнүшүнө кайтып келет</translation>
-<translation id="1049743911850919806">Жашыруун</translation>
<translation id="1050038467049342496">Башка колдонмолорду жабуу</translation>
<translation id="1055184225775184556">Кошууну &amp;жаÑабоо</translation>
<translation id="1056898198331236512">ЭÑкертүү</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">СаÑÑат кеши OK</translation>
<translation id="1130564665089811311">Баракты которуу баÑкычы, бул баракты Google Котормочу менен которуу үчүн, Enter баÑкычын баÑыңыз</translation>
<translation id="1131264053432022307">Сиз көчүргөн Ñүрөт</translation>
+<translation id="1142846828089312304">Жашыруун режимде үчүнчү тараптын cookie файлдарын бөгөттөө</translation>
<translation id="1150979032973867961">Бул Ñервер <ph name="DOMAIN" /> Ñкендигин далилдей алган жок; Ñебеби компьютериңиздин иш тутуму коопÑуздук таÑтыктамаÑына ишенбейт. Мындай көйгөй туура ÑÐ¼ÐµÑ ÐºÐ¾Ð½Ñ„Ð¸Ð³ÑƒÑ€Ð°Ñ†Ð¸Ñ Ð¼ÐµÐ½ÐµÐ½ шартталышы мүмкүн же туташууңузга чабуулчу кийлигишип жатат.</translation>
<translation id="1151972924205500581">СырÑөз талап кылынат</translation>
<translation id="1156303062776767266">Жергиликтүү же бөлүшүлгөн файлды көрүп жатаÑыз</translation>
@@ -64,7 +70,6 @@
<translation id="1178581264944972037">Бир азга токтотуу</translation>
<translation id="1181037720776840403">Ðлып Ñалуу</translation>
<translation id="1186201132766001848">СырÑөздөрдү текшерүү</translation>
-<translation id="1195210374336998651">Колдонмонун жөндөөлөрүнө өтүү</translation>
<translation id="1195558154361252544">Билдирмелер өзүңүз белгилеген Ñайттардан тышкары бардык Ñайттар үчүн автоматтык түрдө бөгөттөлгөн</translation>
<translation id="1197088940767939838">Кызгылт Ñары</translation>
<translation id="1201402288615127009">Кийинки</translation>
@@ -111,7 +116,7 @@
<translation id="1307966114820526988">Жоюлган функциÑлар</translation>
<translation id="1308113895091915999">Сунуш бар</translation>
<translation id="1312803275555673949">Кандай далили бар?</translation>
-<translation id="131405271941274527">NFC түзмөгүндө телефонуңузду таптаганда <ph name="URL" /> маалыматты жөнөтүүгө жана алууга урукÑат Ñурап жатат</translation>
+<translation id="1314311879718644478">Кошумчаланган чындык контентин көрүү</translation>
<translation id="1314509827145471431">Оң жагын байлоо</translation>
<translation id="1318023360584041678">Өтмөктөр тобунда Ñакталды</translation>
<translation id="1319245136674974084">Бул карточка Ñкинчи ÑуралбаÑын</translation>
@@ -161,6 +166,7 @@
<translation id="142858679511221695">Булуттагы колдонуучу</translation>
<translation id="1428729058023778569">Бул ÑÑкертүүнү көрүп жатÑаңыз, бул Ñайтта HTTPS колдоого алынбайт. <ph name="BEGIN_LEARN_MORE_LINK" />Кеңири маалымат<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">БаÑып чыгаруу</translation>
+<translation id="1432187715652018471">баракча кызматты иштеткичти орноткону жатат.</translation>
<translation id="1432581352905426595">Издөө каражаттарын башкаруу</translation>
<translation id="1436185428532214179">Түзмөгүңүздөгү файлдарды жана папкаларды түзөтүүгө урукÑат Ñурай алат</translation>
<translation id="1442386063175183758">Оң бүктөлүшүн чаптоо</translation>
@@ -181,6 +187,12 @@
<translation id="1483493594462132177">Жөнтүү</translation>
<translation id="1484290072879560759">Жөнөтүү дарегин тандоо</translation>
<translation id="1492194039220927094">СаÑÑаттарды колдонуу:</translation>
+<translation id="149293076951187737">Chrome'догу бардык жашыруун өтмөктөр жабылÑа, ал өтмөктөрдөгү аракеттериңиз бул түзмөктөн өчүрүлөт:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Көрүлгөн вебÑайттар<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Издөө таржымалы<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Формаларга киргизилген маалымат<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">Өтмөккө кайтуу</translation>
<translation id="1501859676467574491">Google аккаунтуңуздагы карталарды көрÑÓ©Ñ‚Ò¯Ò¯</translation>
<translation id="1507202001669085618">&lt;p&gt;Бул ката Интернетке туташуудан мурда кирүүнү талап кылган Wi-Fi порталын колдонгондо көрүнөт.&lt;/p&gt;
@@ -208,6 +220,8 @@
<translation id="1559572115229829303">&lt;p&gt;Түзмөгүңүздүн күнү жана убакыты (<ph name="DATE_AND_TIME" />) туура ÑÐ¼ÐµÑ Ð±Ð¾Ð»Ð³Ð¾Ð½Ð´ÑƒÐºÑ‚Ð°Ð½, <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> менен ÐºÑƒÐ¿ÑƒÑ Ñ‚ÑƒÑ‚Ð°ÑˆÑƒÑƒ мүмкүн болбой жатат.&lt;/p&gt;
&lt;p&gt;Күн менен убакытты &lt;strong&gt;Жөндөөлөр&lt;/strong&gt; колдонмоÑунун &lt;strong&gt;Жалпы&lt;/strong&gt; бөлүмүнөн тууралаңыз.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">ÐдминиÑтраторуңуз түзмөктү <ph name="DATE" /> күнү Ñаат <ph name="TIME" /> өчүрүп күйгүзөт</translation>
+<translation id="156703335097561114">Даректер, Ð¸Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñ ÐºÐ¾Ð½Ñ„Ð¸Ð³ÑƒÑ€Ð°Ñ†Ð¸ÑÑÑ‹ жана байланыштын Ñапаты ÑÑ‹Ñктуу тармак маалыматы</translation>
<translation id="1567040042588613346">Бул ÑаÑÑат талаптагыдай иштеп жатат, бирок ал башка жерде коюлган окшош мааниге алмаштырып койду.</translation>
<translation id="1569487616857761740">ÐаÑÑ‹Ñ ÐºÐ°Ñ€Ñ‚Ð°Ñынын жарамдуулук мөөнөтүн киргизиңиз</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@
<translation id="1583429793053364125">Бул веб-баракча жүктөлүп жатканда бир жерден ката кетти.</translation>
<translation id="1586541204584340881">КайÑÑ‹ кеңейтүүлөрдү орнотуп алдыңыз</translation>
<translation id="1588438908519853928">КадыреÑе</translation>
+<translation id="1589050138437146318">ARCore орнотулÑунбу?</translation>
<translation id="1592005682883173041">Жергиликтүү дайындарга мүмкүнчүлүк алуу</translation>
<translation id="1594030484168838125">Тандоо</translation>
<translation id="160851722280695521">Dino Run оюнун Chrome'до ойноо</translation>
@@ -254,7 +269,7 @@
<translation id="1711234383449478798">Четке кагылды, анткени <ph name="POLICY_NAME" /> <ph name="VALUE" /> деп коюлган ÑмеÑ.</translation>
<translation id="1712552549805331520"><ph name="URL" /> компьютериңизге дайындарды биротоло Ñактаганы жатат</translation>
<translation id="1713628304598226412">2-түпкүч</translation>
-<translation id="1715874602234207">F</translation>
+<translation id="1715874602234207">Жм</translation>
<translation id="1717218214683051432">Кыймыл ÑенÑорлору</translation>
<translation id="1717494416764505390">3-Ñлектрондук каттар кутуÑу</translation>
<translation id="1718029547804390981">Документ Ó©Ñ‚Ó© чоң, андыктан ÐÐ½Ð½Ð¾Ñ‚Ð°Ñ†Ð¸Ñ Ñ€ÐµÐ¶Ð¸Ð¼Ð¸Ð½Ð´Ðµ түзөтүүгө болбойт.</translation>
@@ -283,6 +298,7 @@
аталыш бузук болгондуктан, Ñерепчи <ph name="SITE" /> Ñайты үчүн коюлган өтүнүчтү
аткара албайт. Баштапкы ÑаÑÑаттар
Ñайттын операторлору тарабынан Ñайттын коопÑуздугун жана башка каÑиеттерин конфигурациÑлоо үчүн колдонулат.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Chromium'дагы жашыруун өтмөк жөнүндө кеңири маалымат<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0 (1030mm x 1456mm)</translation>
<translation id="1787142507584202372">Ðчылган өтмөктөр бул жерде көрүнөт</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -410,6 +426,7 @@
<translation id="22081806969704220">3-түпкүч</translation>
<translation id="2212735316055980242">СаÑÑат табылган жок</translation>
<translation id="2213606439339815911">Жазуулар алынууда…</translation>
+<translation id="2213612003795704869">Барак баÑылып чыгарылды</translation>
<translation id="2215727959747642672">Файл түзөтүү</translation>
<translation id="2218879909401188352">Учурда <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> Ñайтындагы чабуулчулар түзмөгүңүзгө зыÑн келтирүүчү колдонмолорду орнотуп, мобилдик ÑÑебиңизге жашыруун төлөмдөрдү кошуп же жеке маалыматыңызды уурдашы мүмкүн. <ph name="BEGIN_LEARN_MORE_LINK" />Кеңири маалымат<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">Интернет жок</translation>
@@ -419,6 +436,7 @@
<translation id="2248949050832152960">WebAuthn функциÑÑын колдонуу</translation>
<translation id="2250931979407627383">Сол жаккы бурчун жамоо</translation>
<translation id="225207911366869382">Бул маани бул ÑаÑÑат үчүн Ñунушталбайт.</translation>
+<translation id="2256115617011615191">Ðзыр өчүрүп күйгүзүү</translation>
<translation id="2258928405015593961">Мөөнөтү аÑктаган келечектеги күндү көрÑөтүп, кайталап көрүңүз</translation>
<translation id="225943865679747347">Ката коду: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">HTTP катаÑÑ‹</translation>
@@ -446,6 +464,7 @@
<translation id="2337852623177822836">Жөндөөнү админиÑтраторуңуз башкарат</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> жупташканы жатат</translation>
<translation id="2346319942568447007">Сиз көчүргөн Ñүрөт</translation>
+<translation id="2350796302381711542"><ph name="HANDLER_HOSTNAME" /> <ph name="REPLACED_HANDLER_TITLE" /> ордуна <ph name="PROTOCOL" /> бардык шилтемелерин ача берÑинби?</translation>
<translation id="2354001756790975382">Башка кыÑтармалар</translation>
<translation id="2354430244986887761">Google КоопÑуз Ñерептөө тутуму жакында <ph name="SITE" /> Ñайтында <ph name="BEGIN_LINK" />зыÑнкеч колдонмолорду тапты<ph name="END_LINK" />.</translation>
<translation id="2355395290879513365">Сиз бул Ñайтта көрүп жаткан Ñүрөттөрдү чабуулчулар да көрүп алып, Ñүрөттөрдү өзгөртүп, Ñизди алдашы да мүмкүн.</translation>
@@ -471,6 +490,7 @@
<translation id="2413528052993050574">Бул Ñервер <ph name="DOMAIN" /> Ñкендигин далилдей алган жок; Ñебеби анын коопÑуздук таÑтыктамаÑÑ‹ жокко чыгарылган окшойт. Мындай көйгөй туура ÑÐ¼ÐµÑ ÐºÐ¾Ð½Ñ„Ð¸Ð³ÑƒÑ€Ð°Ñ†Ð¸Ñ Ð¼ÐµÐ½ÐµÐ½ шартталышы мүмкүн же туташууңузга чабуулчу кийлигишип жатат.</translation>
<translation id="2414886740292270097">Кочкул</translation>
<translation id="2430968933669123598">Google аккаунтун башкаруу. Маалыматты, купуÑлыкты жана коопÑуздукту Google аккаунтуңузда башкаруу үчүн Enter баÑкычын баÑыңыз</translation>
+<translation id="2436186046335138073"><ph name="HANDLER_HOSTNAME" /> бардык <ph name="PROTOCOL" /> шилтемелерин ача берÑинби?</translation>
<translation id="2438874542388153331">Оң жагын төрт жолу тешүү</translation>
<translation id="2450021089947420533">СаÑкаттар</translation>
<translation id="2463739503403862330">Толтуруу</translation>
@@ -478,6 +498,7 @@
<translation id="2465655957518002998">Жеткирүү ыкмаÑын тандоо</translation>
<translation id="2465688316154986572">Илмек</translation>
<translation id="2465914000209955735">Chrome'до жүктөлүп алынган файлдарды башкаруу</translation>
+<translation id="2466004615675155314">Интернеттен алынган маалыматты көрÑÓ©Ñ‚Ò¯Ò¯</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Тармак мүчүлүштүгүн аныктоону иштетиңиз<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">1–N ирети</translation>
<translation id="2470767536994572628">ÐннотациÑларды түзөтүүдө бул документ бир бет көрүнүшүнө жана өзүнүн түпнуÑка айланууÑуна кайтып келет</translation>
@@ -498,6 +519,7 @@
<translation id="2523886232349826891">Ушул түзмөккө гана Ñакталды</translation>
<translation id="2524461107774643265">Көбүрөөк маалымат кошуу</translation>
<translation id="2529899080962247600">Бул талаага киргизилген маанилердин Ñаны <ph name="MAX_ITEMS_LIMIT" /> ашпашы керек. Бардык андан кийинки жазмалар четке кагылат.</translation>
+<translation id="2535585790302968248">Жаңы Жашыруун өтмөктү ачып, ÐºÑƒÐ¿ÑƒÑ Ñерептеңиз</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{жана дагы 1}other{жана дагы #}}</translation>
<translation id="2536110899380797252">Дарегин кошуу</translation>
<translation id="2539524384386349900">Ðныктоо</translation>
@@ -523,7 +545,14 @@
<translation id="2597378329261239068">Бул документ ÑÑ‹Ñ€Ñөз менен корголгон. СырÑөздү киргизиңиз.</translation>
<translation id="2609632851001447353">Варианттар</translation>
<translation id="2610561535971892504">Көчүрүү үчүн чыкылдатыңыз</translation>
+<translation id="2617988307566202237">Chrome төмөнкү маалыматты <ph name="BEGIN_EMPHASIS" />Ñактабайт<ph name="END_EMPHASIS" />:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Көргөн вебÑайттарыңыз
+ <ph name="LIST_ITEM" />Cookie файлдары жана Ñайттагы маалымат
+ <ph name="LIST_ITEM" />Формаларга киргизилген маалымат
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (Конверт)</translation>
+<translation id="2623663032199728144">Экрандар тууралуу маалыматты колдонууну Ñурана албайт</translation>
<translation id="2625385379895617796">Саатыңыз алдыда</translation>
<translation id="262745152991669301">USB түзмөктөргө туташууга урукÑат Ñурай алат</translation>
<translation id="2629325967560697240">Chrome’ду жогорку деңгÑÑлде коопÑуздандыруу үчүн <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />өркүндөтүлгөн коргоону күйгүзүңүз<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -557,6 +586,7 @@
<translation id="2709516037105925701">Ðвтотолтуруу</translation>
<translation id="2713444072780614174">Ðк</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />. Chrome'дун жөндөөлөрүнө өтүп, төлөмдөрдү жана наÑÑ‹Ñ ÐºÐ°Ñ€Ñ‚Ð¾Ñ‡ÐºÐ°Ñынын маалыматын башкаруу үчүн, Tab, андан Ñоң Enter баÑкычтарын баÑыңыз</translation>
+<translation id="271663710482723385">Толук Ñкран режиминен чыгуу үчүн |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| баÑкычтарын баÑыңыз</translation>
<translation id="2721148159707890343">Сурам аткарылды</translation>
<translation id="2723669454293168317">Chrome жөндөөлөрүнөн коопÑуздукту текшериңиз</translation>
<translation id="2726001110728089263">Капталкы түпкүч</translation>
@@ -587,6 +617,7 @@
<translation id="2850739647070081192">Invite (Конверт)</translation>
<translation id="2856444702002559011">Чабуулчулар <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> дарегинен маалыматыңызды (миÑалы, ÑÑ‹Ñ€Ñөздөр, билдирүүлөр же наÑÑ‹Ñ ÐºÐ°Ñ€Ñ‚Ð°Ð»Ð°Ñ€Ñ‹) уурдоого аракет кылып жатышы мүмкүн. <ph name="BEGIN_LEARN_MORE_LINK" />Кеңири маалымат<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">Бул Ñайт тажатма же адаштыруучу жарнамаларды көрÑөтүп жатат.</translation>
+<translation id="286512204874376891">Шылуундуктан коргоого жардам берүү үчүн виртуалдык карта чыныгы картаңыздын маалыматын жашырат. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">Ынак</translation>
<translation id="2876489322757410363">Тышкы колдонмо аркылуу төлөө үчүн жашыруун режимден чыкканы жатаÑыз. Уланта береÑизби?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />, Chrome жөндөөлөрүнөн КоопÑуз Ñерептөөнү жана башка нерÑелерди башкаруу үчүн Tab, андан Ñоң Enter баÑкычын баÑыңыз</translation>
@@ -611,6 +642,7 @@
<translation id="2930577230479659665">ÐÑ€ бир көчүрүүдөн кийин кыркуу</translation>
<translation id="2932085390869194046">СырÑөз ÑунушталÑын…</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019"><ph name="PROTOCOL" /> шилтемелерин ачуу</translation>
<translation id="2941952326391522266">Бул Ñервер <ph name="DOMAIN" /> Ñкендигин далилдей алган жок; Ñебеби анын коопÑуздук таÑтыктамаÑÑ‹ бул жерден <ph name="DOMAIN2" /> алынган. Мындай көйгөй туура ÑÐ¼ÐµÑ ÐºÐ¾Ð½Ñ„Ð¸Ð³ÑƒÑ€Ð°Ñ†Ð¸Ñ Ð¼ÐµÐ½ÐµÐ½ шартталышы мүмкүн же туташууңузга чабуулчу кийлигишип жатат.</translation>
<translation id="2943895734390379394">Жүктөп берүү убакыты:</translation>
<translation id="2948083400971632585">Жөндөөлөр бетинен туташат деп конфигурациÑланган бардык прокÑилерди өчүрүп койÑоңуз болот.</translation>
@@ -643,6 +675,7 @@
<translation id="3037605927509011580">Ðтаңдын көрү!</translation>
<translation id="3041612393474885105">ТаÑтыктама маалыматы</translation>
<translation id="3044034790304486808">Изилдөөнү улантуу</translation>
+<translation id="305162504811187366">Chrome ÐлыÑкы иштактанын таржымалы, анын ичинде убакыт белгилери, хоÑттор жана кардарлардын ÑеанÑтарынын идентификаторлору</translation>
<translation id="3060227939791841287">C9 (Конверт)</translation>
<translation id="3061707000357573562">Оңдоо кызматы</translation>
<translation id="306573536155379004">Оюн башталды.</translation>
@@ -683,6 +716,7 @@
<translation id="3197136577151645743">Түзмөктү активдүү колдонуп жатканыңыз тууралуу маалыматты Ñурай алат</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />, Chrome жөндөөлөрүнөн шайкештирилген маалыматты башкаруу үчүн Tab, андан Ñоң Enter баÑкычын баÑыңыз</translation>
<translation id="320323717674993345">Төлөмдү жокко чыгаруу</translation>
+<translation id="3203366800380907218">Интернеттен алынды</translation>
<translation id="3207960819495026254">КыÑтармаланды</translation>
<translation id="3209034400446768650">Барак төлөм өндүрүшү мүмкүн</translation>
<translation id="3212581601480735796"><ph name="HOSTNAME" /> Ñайтындагы аракеттериңиз көзөмөлдөнүүдө</translation>
@@ -699,10 +733,12 @@
<translation id="3234666976984236645">Бул Ñайттагы маанилүү мазмун ар дайым аныкталÑын</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />, Ñерепчинин көрүнүшүн ыңгайлаштыруу үчүн Tab, андан кийин Enter баÑкычын баÑыңыз</translation>
<translation id="3240791268468473923">КоопÑуз төлөө үчүн дал келбеген ÑÑептик дайындар барагы ачылды</translation>
+<translation id="324180406144491771">"<ph name="HOST_NAME" />" шилтемелери бөгөттөлдү</translation>
<translation id="3249845759089040423">Көркөм</translation>
<translation id="3252266817569339921">Французча</translation>
<translation id="3257954757204451555">Бул маалыматты ким берди?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />, Google Жылнаамада жаңы иш-чараны тез түзүү Tab, андан кийин Enter баÑкычын баÑыңыз</translation>
+<translation id="3261488570342242926">Виртуалдык карталар жөнүндө маалымат алыңыз</translation>
<translation id="3264837738038045344">"Chrome жөндөөлөрүн башкаруу" баÑкычы, Chrome жөндөөлөрүнө баш багуу үчүн Enter баÑкычын баÑыңыз</translation>
<translation id="3266793032086590337">Маани (карама-каршы)</translation>
<translation id="3268451620468152448">Ðчык өтмөктөр</translation>
@@ -716,6 +752,7 @@
<translation id="3288238092761586174">Төлөмүңүздү ыраÑтоо үчүн <ph name="URL" /> кошумча кадамдарды аткарышы керек</translation>
<translation id="3293642807462928945"><ph name="POLICY_NAME" /> ÑаÑÑаты жөнүндө кеңири маалымат</translation>
<translation id="3295444047715739395">СырÑөздөрүңүздү Chrome'дун жөндөөлөрүндө көрүп, башкарыңыз</translation>
+<translation id="3303795387212510132">Колдонмого <ph name="PROTOCOL_SCHEME" /> шилтемелерин ачууга урукÑат берилÑинби?</translation>
<translation id="3303855915957856445">Эч нерÑе табылган жок</translation>
<translation id="3304073249511302126">bluetooth түзмөктөрүн издөө</translation>
<translation id="3308006649705061278">Уюмдук бирдик (OU)</translation>
@@ -729,12 +766,6 @@
<translation id="3345782426586609320">Көз</translation>
<translation id="3355823806454867987">ПрокÑи жөндөөлөрүн өзгөртүү…</translation>
<translation id="3360103848165129075">Төлөм иштетүү барагы</translation>
-<translation id="3361596688432910856">Chrome'до төмөнкү маалымат<ph name="BEGIN_EMPHASIS" />Ñактабайт<ph name="END_EMPHASIS" />:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Серептөө таржымалыңыз
- <ph name="LIST_ITEM" />Кукилер жана Ñайттардын дайындары
- <ph name="LIST_ITEM" />Формаларга киргизилген маалымат
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">Бул ÑаÑÑаттын мааниÑи жоюлган <ph name="OLD_POLICY" /> ÑаÑÑатынан автоматтык түрдө көчүрүлдү. Ðнын ордуна бул ÑаÑÑатты колдонуңуз.</translation>
<translation id="3364869320075768271"><ph name="URL" /> виртуалдык чындык түзмөктөрүңүздү жана дайын-даректериңизди колдонууга урукÑат Ñурап жатат</translation>
<translation id="3366477098757335611">Карталарды көрүү</translation>
@@ -816,7 +847,6 @@
<translation id="3587738293690942763">Орто</translation>
<translation id="3592413004129370115">Italian (Конверт)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{Тобуңузду каалаган убакта баштапкы абалга келтирÑеңиз болот. Жаңы топко кошулуу үчүн 1 күндөй убакыт кетет.}=1{Тобуңузду каалаган убакта баштапкы абалга келтирÑеңиз болот. Жаңы топко кошулуу үчүн 1 күндөй убакыт кетет.}other{Тобуңузду каалаган убакта баштапкы абалга келтирÑеңиз болот. Жаңы топко кошулуу үчүн {NUM_DAYS} күндөй убакыт кетет.}}</translation>
-<translation id="3596012367874587041">Колдонмонун жөндөөлөрү</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">Колдонмо админиÑтраторуңуз тарабынан бөгөттөлдү</translation>
<translation id="3608932978122581043">Түрмөктүн багыты</translation>
@@ -859,6 +889,7 @@
<translation id="370972442370243704">СаÑкаттарды күйгүзүү</translation>
<translation id="3711895659073496551">Токтото туруу</translation>
<translation id="3712624925041724820">УрукÑаттамалар ÑÑкирди</translation>
+<translation id="3714633008798122362">желе жылнаамаÑÑ‹</translation>
<translation id="3714780639079136834">Мобилдик Интернетти же Wi-Fi'ды күйгүзүп көрүңүз</translation>
<translation id="3715597595485130451">Wi-Fi'га туташуу</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />ПрокÑи, брандауÑÑ€ жана DNS конфигурациÑÑын текшерип көрүңүз<ph name="END_LINK" /></translation>
@@ -920,6 +951,7 @@
<translation id="3906954721959377182">Планшет</translation>
<translation id="3909477809443608991"><ph name="URL" /> Ñайтында корголгон мазмун ойнотулганы жатат. Түзмөгүңүздүн аныктыгы Google аркылуу текшерилет жана ага ушул Ñайт кире алат.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">Четке кагуу</translation>
<translation id="3939773374150895049">CVC'нин ордуна WebAuthn колдонулÑунбу?</translation>
<translation id="3946209740501886391">Бул Ñайтта ар дайым ÑуралÑын</translation>
<translation id="3947595700203588284">MIDI түзмөктөрүнө туташууга урукÑат Ñурай алат</translation>
@@ -941,6 +973,7 @@
<translation id="3990250421422698716">ОффÑеттик баÑып чыгаруу</translation>
<translation id="3996311196211510766"><ph name="ORIGIN" /> Ñайты бардык кирүү Ñурамдары үчүн баштапкы ÑаÑÑаты
колдонулÑун деп Ñуранды, бирок бул ÑаÑÑатты учурда колдонууга болбойт.</translation>
+<translation id="4009243425692662128">БаÑып чыгарган барактардагы нерÑелер тууралуу маалымат талдоо үчүн Google Булутка же үчүнчү тараптарга жөнөтүлөт. МиÑалы, анда ÐºÑƒÐ¿ÑƒÑ Ð¼Ð°Ð°Ð»Ñ‹Ð¼Ð°Ñ‚Ñ‚Ñ‹Ð½ болууÑу текшерилет.</translation>
<translation id="4010758435855888356">Сактагычты колдонууга урукÑат береÑизби?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{{COUNT} беттен турган PDF документи}other{{COUNT} беттен турган PDF документи}}</translation>
<translation id="4023431997072828269">Форманы тапшырууда кооптуу байланыш колдонулуп жаткандыктан, маалыматыңыз башкаларга көрүнүп турат.</translation>
@@ -1035,6 +1068,7 @@
<translation id="4250680216510889253">Жок</translation>
<translation id="4253168017788158739">ЭÑкертме</translation>
<translation id="425582637250725228">Киргизген өзгөртүүлөрүңүз Ñакталбай калышы мүмкүн.</translation>
+<translation id="425869179292622354">Ðнын коопÑуздугун виртуалдык картанын жардамы менен бекемдейÑизби?</translation>
<translation id="4258748452823770588">Ðачар колтамга</translation>
<translation id="4261046003697461417">Корголгон документтерде ÐÐ½Ð½Ð¾Ñ‚Ð°Ñ†Ð¸Ñ Ñ€ÐµÐ¶Ð¸Ð¼Ð¸ иштебейт</translation>
<translation id="4265872034478892965">ÐдминиÑтраторуңуз урукÑат берген</translation>
@@ -1097,6 +1131,7 @@
<translation id="4434045419905280838">Калкыма терезелер жана багыттоолор</translation>
<translation id="4435702339979719576">Ðчык кат)</translation>
<translation id="443673843213245140">ПрокÑи пайдалануу мүмкүнчүлүгү өчүрүлгөнү менен, ачык-айкын прокÑи конфигурациÑÑÑ‹ белгиленген.</translation>
+<translation id="4441832193888514600">Четке кагылды, анткени ÑаÑÑатты булуттагы колдонуучулар үчүн ÑаÑÑат катары гана коюуга болот.</translation>
<translation id="4450893287417543264">Экинчи көрүнбөÑүн</translation>
<translation id="4451135742916150903">HID түзмөктөрүнө туташууга урукÑат Ñурай алат</translation>
<translation id="4452328064229197696">Жаңы Ñле колдонгон ÑÑ‹Ñ€Ñөзүңүздү кимдир бирөө билип алганы аныкталды. Ðккаунттарыңыздын коопÑуздугун коргоо үчүн Google'дун СырÑөздөрдү башкаргычы Ñакталган ÑÑ‹Ñ€Ñөздөрүңүздү текшерүүнү Ñунуштайт.</translation>
@@ -1152,6 +1187,7 @@
<translation id="4628948037717959914">Сүрөт</translation>
<translation id="4631649115723685955">КешбÑк байланыштырылды</translation>
<translation id="4636930964841734540">Маалымат</translation>
+<translation id="4638670630777875591">Chromium'дагы жашыруун өтмөк</translation>
<translation id="464342062220857295">ФункциÑларды издөө</translation>
<translation id="4644670975240021822">ТеÑкери иретте алдыңкы бетин ылдый каратып</translation>
<translation id="4646534391647090355">Ðзыр көрүнÑүн</translation>
@@ -1172,6 +1208,7 @@
<translation id="4708268264240856090">Туташууңуз үзгүлтүккө учурады</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Windows Тармак мүчүлүштүгүн аныктоону иштетиңиз<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426"><ph name="USERNAME" /> дарегинин ÑÑ‹Ñ€Ñөзү</translation>
<translation id="4724144314178270921">Ðлмашуу буфериңиздеги текÑÑ‚ менен Ñүрөттөрдү көрүүгө урукÑат Ñурай алат</translation>
<translation id="4726672564094551039">СаÑÑаттарды кайра жүктөө</translation>
<translation id="4728558894243024398">Платформа</translation>
@@ -1193,6 +1230,7 @@
<translation id="4757993714154412917">СырÑөзүңүздү жаңы Ñле кооптуу Ñайтта киргиздиңиз. Ðккаунттарыңызды коргоо үчүн Chromium Ñакталган ÑÑ‹Ñ€Ñөздөрүңүздү текшерүүнү Ñунуштайт.</translation>
<translation id="4758311279753947758">Байланыш маалыматын кошуу</translation>
<translation id="4761104368405085019">Микрофонуңузду колдонуңуз</translation>
+<translation id="4761869838909035636">Chrome'дун коопÑуздугун текшерүү</translation>
<translation id="4764776831041365478"><ph name="URL" /> дарегиндеги веб-баракча убактылуу иштебейт же жаңы веб дарекке биротоло көчүрүлгөн окшойт.</translation>
<translation id="4766713847338118463">Төмөн жагын Ñки жолу илмек менен бекитүү</translation>
<translation id="4771973620359291008">БелгиÑиз ката кетти.</translation>
@@ -1213,12 +1251,6 @@
<translation id="4819347708020428563">ÐнаннотациÑларды демейки көрүнүштө түзөтөÑүзбү?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />, жаңы Google таблицаÑын тез түзүү үчүн Tab, андан кийин Enter баÑкычын баÑыңыз</translation>
<translation id="4825507807291741242">Күчтүү</translation>
-<translation id="4827402517081186284">Жашыруун режимде айрым аракеттериңиз көрүнөт:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Сайттар киргениңизди билип турушат<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Жумуш берүүчүлөр же окуу жайлар колдонуучулардын Ñерепчидеги аракеттерине көз Ñала алышат<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Интернет кызматын жабдуучулар веб трафикти көзөмөлдөй алышат<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">ЭÑкертүүлөрдү күйгүзүү</translation>
<translation id="4838327282952368871">КыÑлкеч</translation>
<translation id="4840250757394056958">Chrome'до көрүлгөн вебÑайттарды көрүү</translation>
@@ -1230,12 +1262,12 @@
<translation id="4854362297993841467">Жеткирүүнүн мындай ыкмаÑÑ‹ мүмкүн ÑмеÑ. Башка ыкмаÑын байкап көрүңүз.</translation>
<translation id="4854853140771946034">Google Keep'те жаңы ÑÑкертмени тез жазуу</translation>
<translation id="485902285759009870">Код текшерилүүдө…</translation>
+<translation id="4866506163384898554">КурÑорду көрÑÓ©Ñ‚Ò¯Ò¯ үчүн |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| баÑкычтарын баÑыңыз</translation>
<translation id="4876188919622883022">Жөнөкөйлөштүрүлгөн көрүнүш</translation>
<translation id="4876305945144899064">Колдонуучунун аты жок</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{Жок}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831"><ph name="TEXT" /> деп издөө</translation>
<translation id="4879491255372875719">Ðвтоматтык (демейки)</translation>
-<translation id="4879725228911483934">Терезелерди ачып, Ñкрандарыңызга жайгаштырыңыз</translation>
<translation id="4880827082731008257">Издөө таржымалы</translation>
<translation id="4881695831933465202">Ðчуу</translation>
<translation id="4885256590493466218"><ph name="CARD_DETAIL" /> картаÑÑ‹ менен төлөңүз</translation>
@@ -1244,6 +1276,7 @@
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">Тогузунчу барабан</translation>
<translation id="4901778704868714008">Сактоо…</translation>
+<translation id="4905659621780993806">ÐдминиÑтраторуңуз түзмөктү <ph name="DATE" /> Ñаат <ph name="TIME" /> автоматтык түрдө өчүрүп күйгүзөт. Түзмөк өчүрүлүп күйгүзүлгөнгө чейин ачылып турган нерÑелерди Ñактаңыз.</translation>
<translation id="4913987521957242411">Жогорку Ñол жагын тешүү</translation>
<translation id="4918221908152712722"><ph name="APP_NAME" /> колдонмоÑун орнотуу (жүктөп алуунун кереги жок)</translation>
<translation id="4923459931733593730">Төлөм</translation>
@@ -1252,6 +1285,7 @@
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />. Издөө үчүн Tab, андан Ñоң Enter баÑкычтарын баÑыңыз</translation>
<translation id="4930153903256238152">Сыйымдуулугу чоң</translation>
+<translation id="4940163644868678279">Chrome'догу жашыруун өтмөк</translation>
<translation id="4943872375798546930">Ðатыйжалар жок</translation>
<translation id="4950898438188848926">Өтмөктү которуштуруу баÑкычы. Ðчык өтмөккө Ó©Ñ‚Ò¯Ò¯ үчүн, "Enter" баÑкычын баÑыңыз, <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="495170559598752135">Ðракеттер</translation>
@@ -1261,6 +1295,7 @@
<translation id="4968522289500246572">Бул колдонмо мобилдик түзмөк үчүн түзүлгөндүктөн, өлчөмү туура өзгөрбөшү мүмкүн. Колдонмодо маÑелелер келип чыгышы же өчүп күйүшү мүмкүн.</translation>
<translation id="4969341057194253438">Жаздырууну өчүрүү</translation>
<translation id="4973922308112707173">Жогорку жагын Ñки жолу тешүү</translation>
+<translation id="4976702386844183910">Ðкыркы жолу кирген: <ph name="DATE" /></translation>
<translation id="4984088539114770594">Микрофон колдонулÑунбу?</translation>
<translation id="4984339528288761049">Prc5 (Конверт)</translation>
<translation id="4989163558385430922">Баарын көрүү</translation>
@@ -1322,6 +1357,7 @@
<translation id="5138227688689900538">Ðзыраак көрÑÓ©Ñ‚Ò¯Ò¯</translation>
<translation id="5145883236150621069">СаÑÑат жообунда ката коду бар</translation>
<translation id="5146995429444047494"><ph name="ORIGIN" /> үчүн билдирмелер бөгөттөлдү</translation>
+<translation id="514704532284964975"><ph name="URL" /> телефонуңузда таптаган NFC түзмөктөрүндөгү маалыматты көрүп жана өзгөрткүÑÒ¯ келет</translation>
<translation id="5148809049217731050">Өйдө каратып</translation>
<translation id="515292512908731282">C4 (Конверт)</translation>
<translation id="5158275234811857234">Мукаба</translation>
@@ -1346,6 +1382,7 @@
<translation id="5215116848420601511">Google Pay'ди колдонгон төлөм ыкмалары жана даректер</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">13-түпкүч</translation>
+<translation id="5216942107514965959">Бүгүн акыркы жолу кирген</translation>
<translation id="5222812217790122047">Электрондук почта дареги талап кылынат</translation>
<translation id="5230733896359313003">Жөнөтүү дареги</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1366,7 +1403,6 @@
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">Документтин мүнөздөмөлөрү</translation>
<translation id="528468243742722775">Бүтүрүү</translation>
-<translation id="5284909709419567258">Тармактын даректери</translation>
<translation id="5285570108065881030">Бардык Ñакталган ÑÑ‹Ñ€Ñөздөрдү көрÑÓ©Ñ‚Ò¯Ò¯</translation>
<translation id="5287240709317226393">Кукилерди көрÑÓ©Ñ‚Ò¯Ò¯</translation>
<translation id="5287456746628258573">Бул Ñайт ÑÑкирген коопÑуздук конфигурациÑÑын колдонуп жатат. Маалыматыңыз (миÑалы, ÑÑ‹Ñ€Ñөздөр же наÑÑ‹Ñ ÐºÐ°Ñ€Ñ‚Ð°Ð»Ð°Ñ€Ñ‹Ð½Ñ‹Ð½ номерлер) ушул Ñайтка жөнөтүлгөндө ачык көрүнүп калышы мүмкүн.</translation>
@@ -1450,6 +1486,7 @@
<translation id="5556459405103347317">Кайра жүктөө</translation>
<translation id="5560088892362098740">Мөөнөтү аÑктай турган күн</translation>
<translation id="55635442646131152">Документтин түзүлүшү</translation>
+<translation id="5565613213060953222">Жашыруун өтмөктү ачуу</translation>
<translation id="5565735124758917034">Жигердүү</translation>
<translation id="5570825185877910964">Ðккаунттун коопÑуздугун коргоо</translation>
<translation id="5571083550517324815">Бул даректен алып кетүү мүмкүн ÑмеÑ. Башка дарек тандаңыз.</translation>
@@ -1532,6 +1569,7 @@
<translation id="5869522115854928033">Сакталган ÑÑ‹Ñ€Ñөздөр</translation>
<translation id="5873013647450402046">Банк аныктыгыңызды текшергени жатат.</translation>
<translation id="5887400589839399685">Карта Ñакталды</translation>
+<translation id="5887687176710214216">КечÑÑ Ð°ÐºÑ‹Ñ€ÐºÑ‹ жолу кирген</translation>
<translation id="5895138241574237353">Өчүрүп күйгүзүү</translation>
<translation id="5895187275912066135">Берилген күнү</translation>
<translation id="5901630391730855834">Сары</translation>
@@ -1545,6 +1583,7 @@
<translation id="5921639886840618607">Карта Google аккаунтуңузда ÑакталÑынбы?</translation>
<translation id="5922853866070715753">Бүткөнү калды</translation>
<translation id="5932224571077948991">Сайт тажатма же адаштыруучу жарнамаларды көрÑөтүп жатат</translation>
+<translation id="5938153366081463283">Виртуалдык картаны кошуу</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347"><ph name="SITE_NAME" /> ачылууда…</translation>
<translation id="5951495562196540101">Ðккаунт түзмөктүн урукÑаттамаÑына дал келбегендиктен аны менен катталууга болбойт.</translation>
@@ -1609,6 +1648,7 @@
<translation id="6120179357481664955">UPI идентификаторуңуз ÑакталÑынбы?</translation>
<translation id="6124432979022149706">Chrome Enterprise туташтыргычтары</translation>
<translation id="6127379762771434464">ÐерÑе өчүрүлдү</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Chrome'догу жашыруун өтмөк жөнүндө кеңири маалымат<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">Колдонулуп жаткан кабелдерди текшерип, роутер, модем жана башка
тармак түзмөктөрүн өчүрүп-күйгүзүңүз.</translation>
<translation id="614940544461990577">Төмөнкүлөрдү кылып көрүңүз:</translation>
@@ -1621,7 +1661,6 @@
<translation id="6169916984152623906">Жашыруун режимдеги аракеттериңиз ушул түзмөктүн башка колдонуучуларына көрүнбөйт. Бирок жүктөп алынган файлдар жана кыÑтармалар Ñакталып кала берет.</translation>
<translation id="6177128806592000436">Бул Ñайтка туташуу коопÑуз ÑмеÑ</translation>
<translation id="6180316780098470077">Кайталоолордун интервалы</translation>
-<translation id="619448280891863779">Терезени ачып, Ñкрандарыңызга жайгаштырууга урукÑат Ñурай алат</translation>
<translation id="6196640612572343990">Үчүнчү жактын кукилери бөгөттөлÑүн</translation>
<translation id="6203231073485539293">Интернет туташууңузду текшериңиз</translation>
<translation id="6218753634732582820">Дарек Chromium'дан алынып ÑалынÑынбы?</translation>
@@ -1644,7 +1683,7 @@
<translation id="6272383483618007430">Google Update</translation>
<translation id="6276112860590028508">Окуу тизмеңиздеги барактар бул жерде көрүнөт</translation>
<translation id="627746635834430766">Кийинки жолу тезирÑÑк төлөө үчүн картаңыз менен ÑÑептешүү дарегин Google аккаунтуңузга Ñактап коюңуз.</translation>
-<translation id="6279098320682980337">Виртуалдык картанын номери киргизилген жокпу? Көчүрүү үчүн картанын чоо-жайын чыкылдатыңыз</translation>
+<translation id="6279183038361895380">КурÑоруңузду көрÑÓ©Ñ‚Ò¯Ò¯ үчүн |<ph name="ACCELERATOR" />| дегенди баÑыңыз</translation>
<translation id="6280223929691119688">Бул дарекке жеткирүү мүмкүн ÑмеÑ. Башка дарек тандаңыз.</translation>
<translation id="6282194474023008486">Почта индекÑи</translation>
<translation id="6285507000506177184">"Chrome'до жүктөлүп алынгандарды башкаруу" баÑкычы, Chrome'до жүктөлүп алынган файлдарды башкаруу үчүн Enter баÑкычын баÑыңыз</translation>
@@ -1652,6 +1691,7 @@
<translation id="6290238015253830360">Сунушталган макалалар ушул жерде көрүнөт</translation>
<translation id="6293309776179964942">JIS B5 (182mm x 257mm)</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{Түзмөгүңүз азыр өчүрүлүп күйгүзүлөт}=1{Түзмөгүңүз 1 Ñекунддан кийин өчүрүлүп күйгүзүлөт}other{Түзмөгүңүз # Ñекунддан кийин өчүрүлүп күйгүзүлөт}}</translation>
<translation id="6302269476990306341">Chrome'догу Google Жардамчы токтотулууда</translation>
<translation id="6305205051461490394"><ph name="URL" /> Ñайты жеткиликÑиз.</translation>
<translation id="6312113039770857350">Веб-баракча жеткиликтүү ÑмеÑ</translation>
@@ -1725,6 +1765,7 @@
<translation id="6529602333819889595">Жок кылууну &amp;кайталоо</translation>
<translation id="6545864417968258051">Bluetooth түзмөктөрүн издөө</translation>
<translation id="6547208576736763147">Муштум менен Ñол жакка Ñки жолу уруу</translation>
+<translation id="6554732001434021288">Ðкыркы жолу <ph name="NUM_DAYS" /> күн мурун кирген</translation>
<translation id="6556866813142980365">Кайталоо</translation>
<translation id="6569060085658103619">Кеңейтүү баракчаÑын карап жатаÑыз</translation>
<translation id="6573200754375280815">Оң жагын Ñки жолу тешүү</translation>
@@ -1785,7 +1826,6 @@
<translation id="6757797048963528358">Түзмөгүңүз уктап калды.</translation>
<translation id="6767985426384634228">Дарек жаңыртылÑынбы?</translation>
<translation id="6768213884286397650">Hagaki (Ðчык кат)</translation>
-<translation id="6774185088257932239">Жашыруун режим жөнүндө <ph name="BEGIN_LINK" />кеңири маалымат<ph name="END_LINK" /></translation>
<translation id="6775759552199460396">JIS B2 (515mm x 728mm)</translation>
<translation id="67862343314499040">Кызгылт көк</translation>
<translation id="6786747875388722282">Кеңейтүүлөр</translation>
@@ -1869,7 +1909,6 @@
<translation id="706295145388601875">Chrome жөндөөлөрүнөн даректерди кошуу жана башкаруу</translation>
<translation id="7064851114919012435">Байланыш маалыматы</translation>
<translation id="7068733155164172741"><ph name="OTP_LENGTH" /> орундуу кодду киргизиңиз</translation>
-<translation id="7070090581017165256">Ушул Ñайт жөнүндө</translation>
<translation id="70705239631109039">Туташуу толугу менен коопÑуз ÑмеÑ</translation>
<translation id="7075452647191940183">Сурамдын көлөмү өтө чоң</translation>
<translation id="7079718277001814089">Бул Ñайтта кеÑепеттүү программа бар</translation>
@@ -1886,6 +1925,12 @@
<translation id="7111012039238467737">(Жарактуу)</translation>
<translation id="7118618213916969306">Ðлмашуу буферинин URL'ин издөө, <ph name="SHORT_URL" /></translation>
<translation id="7119414471315195487">Башка өтмөктөрдү жана программаларды жабыңыз</translation>
+<translation id="7129355289156517987">Chromium'дагы бардык жашыруун өтмөктөр жабылÑа, ал өтмөктөрдөгү аракеттериңиз бул түзмөктөн өчүрүлөт:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Көрүлгөн вебÑайттар<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Издөө таржымалы<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Формаларга киргизилген маалымат<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">Бул дарекке жөнөтүү мүмкүн ÑмеÑ. Башка дарек тандаңыз.</translation>
<translation id="7132939140423847331">ÐдминиÑтратор бул маалыматты көчүрүүгө тыюу Ñалды.</translation>
<translation id="7135130955892390533">Ðбалын көрÑÓ©Ñ‚Ò¯Ò¯</translation>
@@ -1908,6 +1953,7 @@
<translation id="7192203810768312527"><ph name="SIZE" /> орун бошотулат. Кийинки жолу киргениңизде, айрым Ñайттар жайыраак жүктөлүшү мүмкүн.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">ÐдминиÑтраторуңуз төмөнкүлөрдү көрөт:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />. ÐšÑƒÐ¿ÑƒÑ ÐºÐ°Ñ€Ð°Ð¿ чыкканга жашыруун өтмөктү ачуу үчүн Tab, андан Ñоң Enter баÑкычын баÑыңыз</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> Ñайты коопÑуздук Ñтандарттарына жооп бербейт.</translation>
<translation id="7210993021468939304">Контейнердеги Linux аракеттери Linux колдонмолорун контейнердин алкагында орнотуп, иштете алышат</translation>
@@ -1939,6 +1985,7 @@
<translation id="7304562222803846232">Google аккаунтунун купуÑлык жөндөөлөрүн башкаруу</translation>
<translation id="7305756307268530424">Жайдан баштоо</translation>
<translation id="7308436126008021607">фондо шайкештирүү</translation>
+<translation id="7310392214323165548">Түзмөк бир аздан кийин өчүп күйөт</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">Туташуу боюнча жардам алуу</translation>
<translation id="7323804146520582233">"<ph name="SECTION" />" бөлүгүн жашыруу</translation>
@@ -1946,6 +1993,7 @@
<translation id="7334320624316649418">Иреттештирүүнү &amp;кайталоо</translation>
<translation id="7335157162773372339">Камераңызды колдонууга урукÑат Ñурай алат</translation>
<translation id="7337248890521463931">Көбүрөөк көрÑÓ©Ñ‚Ò¯Ò¯</translation>
+<translation id="7337418456231055214">Виртуалдык картанын номери киргизилген жокпу? Көчүрүү үчүн картанын чоо-жайын чыкылдатыңыз. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">Сиздин платформада жеткиликÑиз.</translation>
<translation id="733923710415886693">Сервердин таÑтыктамаÑÑ‹ "ТаÑтыктаманын тунуктук ÑаÑÑаты" аркылуу ачыкка чыгарылган ÑмеÑ.</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1968,6 +2016,7 @@
<translation id="7378627244592794276">Жок</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">Колдонулбайт</translation>
+<translation id="7388594495505979117">{0,plural, =1{Түзмөгүңүз 1 мүнөттөн кийин өчүрүлүп күйгүзүлөт}other{Түзмөгүңүз # мүнөттөн кийин өчүрүлүп күйгүзүлөт}}</translation>
<translation id="7390545607259442187">Карточканы текшерүү</translation>
<translation id="7392089738299859607">Даректи жаңыртуу</translation>
<translation id="7399802613464275309">КоопÑуздукту текшерүү</translation>
@@ -2004,6 +2053,12 @@
<translation id="7485870689360869515">Дайындар табылган жок.</translation>
<translation id="7495528107193238112">Бул мазмун бөгөттөлгөн. Көйгөйдү чечүү үчүн Ñайттын ÑÑÑине байланышыңыз.</translation>
<translation id="7497998058912824456">Google документин түзүү баÑкычы. Жаңы Google документин тез түзүү үчүн Enter баÑкычын баÑыңыз</translation>
+<translation id="7506488012654002225">Chromium төмөнкү маалыматты <ph name="BEGIN_EMPHASIS" />Ñактабайт<ph name="END_EMPHASIS" />:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Көргөн вебÑайттарыңыз
+ <ph name="LIST_ITEM" />Cookie файлдары жана Ñайттагы маалымат
+ <ph name="LIST_ITEM" />Формаларга киргизилген маалымат
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">Кайтарылган ÑаÑÑат түзмөгүнүн id'Ñи бош же учурдагы түзмөктүн id'Ñине дал келбейт</translation>
<translation id="7508870219247277067">Жашыл (авокадо)</translation>
<translation id="7511955381719512146">Сиз колдонуп жаткан Wi-Fi <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> дарегине өтүшүңүздү талап кылышы мүмкүн.</translation>
@@ -2117,7 +2172,6 @@
<translation id="7813600968533626083">Форма Ñунушу Chrome'дон алынып ÑалынÑынбы?</translation>
<translation id="781440967107097262">Буфер бөлүшүлÑүнбү?</translation>
<translation id="7815407501681723534">"<ph name="SEARCH_STRING" />" боюнча <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> табылды.</translation>
-<translation id="782125616001965242">Бул Ñайт жөнүндө маалыматты көрүү</translation>
<translation id="782886543891417279">Сиз колдонуп жаткан Wi-Fi (<ph name="WIFI_NAME" />), башкы кирүү барагына өтүшүңүздү талап кылышы мүмкүн.</translation>
<translation id="7836231406687464395">Postfix (Конверт)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{Эч бири}=1{1 колдонмо (<ph name="EXAMPLE_APP_1" />)}=2{2 колдонмо (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}other{# колдонмо (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}}</translation>
@@ -2134,7 +2188,6 @@
<translation id="7888575728750733395">БаÑып чыгаруу аралыгы</translation>
<translation id="7894280532028510793">Эгер туура жазылÑа, <ph name="BEGIN_LINK" />Тармактагы мүчүлүштүктөрдү аныктоону<ph name="END_LINK" /> иштетип көрүңүз.</translation>
<translation id="7904208859782148177">C3 (Конверт)</translation>
-<translation id="7931318309563332511">БелгиÑиз</translation>
<translation id="793209273132572360">Дарек жаңыртылÑынбы?</translation>
<translation id="7932579305932748336">Пальто</translation>
<translation id="79338296614623784">Жарактуу телефон номерин киргизиңиз</translation>
@@ -2159,13 +2212,14 @@
<translation id="7976214039405368314">Өтүнүчтөр өтө көп жөнөтүлдү</translation>
<translation id="7977538094055660992">Чыгаруу түзмөгү</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">Төмөнкү менен байланышкан</translation>
<translation id="798134797138789862">Виртуалдык чындык түзмөктөрүн жана маалыматтарды колдонууга урукÑат Ñурай алат</translation>
<translation id="7984945080620862648"><ph name="SITE" /> Ñайтына кире албайÑыз, анткени вебÑайт Chrome иштете албаган шифрленген далдаштырма дайындарын жөнөттү. Тармак каталары жана бузукулар адатта убактылуу көйгөй болгондуктан, бул бет кийинчерÑÑк иштеп калышы мүмкүн.</translation>
-<translation id="79859296434321399">Кошумчаланган чындыкты көрүү үчүн ARCore кызматын орнотуңуз</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">Байлоо</translation>
<translation id="7992044431894087211"><ph name="APPLICATION_TITLE" /> колдонмоÑу менен Ñкранды бөлүшүү улантылды</translation>
<translation id="7995512525968007366">Белгиленген ÑмеÑ</translation>
+<translation id="7998269595945679889">Жашыруун өтмөк баÑкычын баÑыңыз. Жаңы жашыруун өтмөктү ачып, интернетти коопÑуз чабыттоо үчүн Enter баÑкычын баÑыңыз</translation>
<translation id="800218591365569300">ЭÑтутумду бошотуу үчүн башка өтмөктөрдү же программаларды жаап көрүңүз.</translation>
<translation id="8004582292198964060">Серепчи</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{Бул карта жана анын ÑÑептешүү дареги Ñакталат. Ðны <ph name="USER_EMAIL" /> аккаунтуна киргенде колдоно алаÑыз.}other{Бул карталар жана алардын ÑÑептешүү даректери Ñакталат. Ðларды <ph name="USER_EMAIL" /> аккаунтуна киргенде колдоно алаÑыз.}}</translation>
@@ -2225,6 +2279,7 @@
<translation id="8202370299023114387">Дал келбеÑтик</translation>
<translation id="8206978196348664717">Prc4 (Конверт)</translation>
<translation id="8211406090763984747">Туташуу коопÑуз</translation>
+<translation id="8217240300496046857">Сайттар Интернеттеги аракеттериңизге көз Ñалган cookie файлдарын колдоно албайт. ФункциÑлар айрым Ñайттарда туура иштебеши мүмкүн.</translation>
<translation id="8218327578424803826">Дайындалган жайгашкан жер:</translation>
<translation id="8220146938470311105">C7/C6 (Конверт)</translation>
<translation id="8225771182978767009">Бул компьютерди жөндөгөн адам ушул Ñайтты бөгөттөп Ñалган.</translation>
@@ -2265,14 +2320,9 @@
<translation id="830498451218851433">Жарымынан бүктөө</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">Орнотулган колдонмолор жана алар канчалык көп колдонулат</translation>
+<translation id="8317207217658302555">ARCore жаңыртылÑынбы?</translation>
<translation id="831997045666694187">Кече</translation>
<translation id="8321476692217554900">билдирмелер</translation>
-<translation id="8328484624016508118">Жашыруун өтмөктөрдүн баары жабылгандан кийин, Chrome төмөнкүлөрдү тазалайт:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Ушул түзмөктөгү вебÑайтта жаÑаган аракеттериңизди<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Ушул түзмөктө издеген нерÑелериңизди<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Формаларга киргизилген маалыматтарды<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489"><ph name="HOST_NAME" /> Ñайтына кирүү мүмкүнчүлүгү четке кагылды</translation>
<translation id="833262891116910667">Бөлүп көрÑÓ©Ñ‚Ò¯Ò¯</translation>
<translation id="8339163506404995330"><ph name="LANGUAGE" /> тилиндеги барактар которулбайт</translation>
@@ -2324,6 +2374,7 @@
<translation id="8507227106804027148">Буйрук Ñабы</translation>
<translation id="8508648098325802031">Издөө ÑүрөтчөÑÒ¯</translation>
<translation id="8511402995811232419">Cookie файлдарын башкаруу</translation>
+<translation id="8519753333133776369">ÐдминиÑтраторуңуз урукÑат берген HID түзмөгү</translation>
<translation id="8522552481199248698">Chrome Google аккаунтуңуздун коопÑуздугун коргоп, ÑÑ‹Ñ€Ñөзүңүздү өзгөртүүгө жардам берет.</translation>
<translation id="8530813470445476232">Chrome'дун жөндөөлөрүнө өтүп, Ñерептөө таржымалын, cookie файлдарын, кÑштерди жана башкаларды өчүрүңүз</translation>
<translation id="8533619373899488139">Бөгөттөлгөн URL'дерди жана тутум админиÑтраторуңуз ишке киргизген ÑаÑÑаттарды көрүү үчүн &lt;strong&gt;chrome://policy&lt;/strong&gt; дарегине кириңиз.</translation>
@@ -2335,7 +2386,6 @@
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{УрукÑатты баштапкы абалга келтирүү}other{УрукÑаттарды баштапкы абалга келтирүү}}</translation>
<translation id="8555010941760982128">Бул кодду Ñатып алган нерÑелериңиздин акыÑын төлөп жатканда колдонуңуз</translation>
<translation id="8557066899867184262">CVC карточкаңыздын артында жайгашкан.</translation>
-<translation id="8558485628462305855">Кошумчаланган чындыкты көрүү үчүн ARCore кызматын жаңыртыңыз</translation>
<translation id="8559762987265718583">Түзмөгүңүздүн күнү жана убакыты (<ph name="DATE_AND_TIME" />) туура ÑÐ¼ÐµÑ Ð±Ð¾Ð»Ð³Ð¾Ð½Ð´ÑƒÐºÑ‚Ð°Ð½, <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> менен ÐºÑƒÐ¿ÑƒÑ Ñ‚ÑƒÑ‚Ð°ÑˆÑƒÑƒ мүмкүн болбой жатат.</translation>
<translation id="8564182942834072828">Өзүнчө документ/Иреттелбеген көчүрмөлөр</translation>
<translation id="8564985650692024650"><ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> ÑÑ‹Ñ€Ñөзүңүздү башка Ñайттарда колдонгон болÑоңуз, Chromium аны өзгөртүүнү Ñунуштайт.</translation>
@@ -2354,6 +2404,7 @@
<translation id="865032292777205197">кыймыл ÑенÑорлору</translation>
<translation id="8663226718884576429">Буйрутма тууралуу маалымат, <ph name="TOTAL_LABEL" />, Толук маалымат</translation>
<translation id="8666678546361132282">ÐнглиÑче</translation>
+<translation id="8669306706049782872">Терезелерди ачып, Ñкранга жайгаштыруу үчүн Ñкрандар тууралуу маалыматты колдонуу</translation>
<translation id="867224526087042813">Колтамга</translation>
<translation id="8676424191133491403">Дароо</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, жооп, <ph name="ANSWER" /></translation>
@@ -2379,7 +2430,8 @@
<translation id="8730621377337864115">Бүттү</translation>
<translation id="8731544501227493793">СырÑөздөрдү башкаруу баÑкычы. Chrome'дун жөндөөлөрүнө өтүп, ÑÑ‹Ñ€Ñөздөрдү көрүү жана башкаруу үчүн, Enter баÑкычын баÑыңыз</translation>
<translation id="8734529307927223492"><ph name="DEVICE_TYPE" /> түзмөгүңүз <ph name="MANAGER" /> тарабынан башкарылууда</translation>
-<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />. ÐšÑƒÐ¿ÑƒÑ ÐºÐ°Ñ€Ð°Ð¿ чыкканга жашыруун терезе ачуу үчүн, Tab, андан Ñоң Enter баÑкычын баÑыңыз</translation>
+<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />. ÐšÑƒÐ¿ÑƒÑ ÐºÐ°Ñ€Ð°Ð¿ чыкканга жашыруун терезе ачуу үчүн Tab, андан Ñоң Enter баÑкычын баÑыңыз</translation>
+<translation id="8737685506611670901"><ph name="REPLACED_HANDLER_TITLE" /> ордуна <ph name="PROTOCOL" /> шилтемелерин ачуу</translation>
<translation id="8738058698779197622">КоопÑуз туташууну орнотуу үчүн, Ñаатыңыз туура коюлушу керек. Себеби вебÑайттардын аныктыгын текшере турган таÑтыктамалар белгилүү бир убакыт аралыгында гана жарактуу болот. Түзмөгүңүздүн Ñааты туура ÑÐ¼ÐµÑ Ð±Ð¾Ð»Ð³Ð¾Ð½Ð´ÑƒÐºÑ‚Ð°Ð½, Chromium бул таÑтыктамаларды текшере албайт.</translation>
<translation id="8740359287975076522"><ph name="HOST_NAME" /> Ñайтынын &lt;abbr id="dnsDefinition"&gt;DNS дареги&lt;/abbr&gt; табылбай койду. Көйгөйдүн Ñебеби аныкталууда.</translation>
<translation id="8742371904523228557"><ph name="ONE_TIME_CODE" /> - бул <ph name="ORIGIN" /> үчүн кодуңуз</translation>
@@ -2407,6 +2459,7 @@
<translation id="883848425547221593">Башка кыÑтармалар</translation>
<translation id="884264119367021077">Жеткирүү дареги</translation>
<translation id="884923133447025588">Жоюу механизми табылган жок.</translation>
+<translation id="8849262850971482943">Кошумча коопÑуздук үчүн виртуалдык картаңызды колдонуңуз</translation>
<translation id="885730110891505394">Google менен бөлүшүү</translation>
<translation id="8858065207712248076"><ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> ÑÑ‹Ñ€Ñөзүңүздү башка Ñайттарда колдонгон болÑоңуз, Chrome аны өзгөртүүнү Ñунуштайт.</translation>
<translation id="885906927438988819">Эгер туура жазылÑа, <ph name="BEGIN_LINK" />Windows тармагындагы мүчүлүштүктөрдү аныктоону<ph name="END_LINK" /> иштетип көрүңүз.</translation>
@@ -2456,6 +2509,7 @@
<translation id="9004367719664099443">VR ÑеанÑÑ‹ жүрүүдө</translation>
<translation id="9005998258318286617">PDF документи жүктөлбөй калды.</translation>
<translation id="9008201768610948239">Этибарга албоо</translation>
+<translation id="901834265349196618">Ñлектрондук почта</translation>
<translation id="9020200922353704812">Карточканын төлөм дареги талап кылынат</translation>
<translation id="9020542370529661692">Бул бет <ph name="TARGET_LANGUAGE" /> тилине которулду</translation>
<translation id="9020742383383852663">A8</translation>
@@ -2504,6 +2558,7 @@
<translation id="9150045010208374699">Камераңызды колдонуңуз</translation>
<translation id="9150685862434908345">ÐдминиÑтраторуңуз Ñерепчини алыÑтан жөндөй алат. Бул түзмөктө аткарылган аракеттер Chrome'дон тышкары да башкарылышы мүмкүн. <ph name="BEGIN_LINK" />Кеңири маалымат<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">Жаңыртылды</translation>
+<translation id="9155211586651734179">Ðудио түзмөктүн көмөкчү жабдыктары тиркелди</translation>
<translation id="9157595877708044936">Орнотууда…</translation>
<translation id="9158625974267017556">C6 (Конверт)</translation>
<translation id="9164029392738894042">Тактыгын текшерүү</translation>
diff --git a/chromium/components/strings/components_strings_lo.xtb b/chromium/components/strings/components_strings_lo.xtb
index de6cc301731..399318153d2 100644
--- a/chromium/components/strings/components_strings_lo.xtb
+++ b/chromium/components/strings/components_strings_lo.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">ເບິ່ງລາàºàº¥àº°àº­àº½àº”</translation>
<translation id="1030706264415084469"><ph name="URL" /> ຕ້ອງàºàº²àº™à»€àºàº±àºšàº‚à»à»‰àº¡àº¹àº™àº‚ະໜາດໃຫàºà»ˆà»„ວ້ໃນອຸປະàºàº­àº™àº‚ອງທ່ານຢ່າງຖາວອນ</translation>
<translation id="1032854598605920125">à»àº¸àº™àº•àº²àº¡à»€àº‚ັມໂມງ</translation>
+<translation id="1033329911862281889">ໂà»àº”ບà»à»ˆà»€àº›àºµàº”ເຜີàºàº•àº»àº§àº•àº»àº™àºšà»à»ˆà»„ດ້ເຮັດໃຫ້ທ່ານຫາàºàº•àº»àº§à»„ດ້ໃນເວລາອອນລາàº:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ເວັບໄຊ à»àº¥àº° ບà»àº¥àº´àºàº²àº™àº—ີ່ເຂົາເຈົ້າໃຊ້ຈະສາມາດເບິ່ງເຫັນàºàº²àº™à»€àº‚ົ້າເບິ່ງ<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ນາàºàºˆà»‰àº²àº‡ ຫຼື ໂຮງຮຽນສາມາດຕິດຕາມàºàº²àº™à»€àº„ື່ອນໄຫວàºàº²àº™àº—່ອງເວັບ<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ຜູ້ໃຫ້ບà»àº¥àº´àºàº²àº™àº­àº´àº™à»€àº•àºµà»€àº™àº±àº”ສາມາດເàºàº»à»‰àº²àºªàº±àº‡à»€àºàº”ທຣາບຟິàºà»€àº§àº±àºš<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">ປິດ</translation>
<translation id="1036982837258183574">àºàº»àº” |<ph name="ACCELERATOR" />| ເພື່ອອອàºàºˆàº²àºà»€àº•àº±àº¡àºˆà»</translation>
<translation id="1038106730571050514">ສະà»àº”ງàºàº²àº™à»àº™àº°àº™àº³</translation>
<translation id="1038842779957582377">ຊື່ບà»à»ˆàº®àº¹à»‰àºˆàº±àº</translation>
<translation id="1041998700806130099">ຂà»à»‰àº„ວາມà»àºœà»ˆàº™àº§àº½àº</translation>
<translation id="1048785276086539861">ເມື່ອທ່ານà»àºà»‰à»„ຂຄຳອະທິບາàºàº„ວາມເຫັນດ ເອàºàº°àºªàº²àº™àº™àºµà»‰àºˆàº°àºàº±àºšà»„ປເປັນມຸມມອງà»àºšàºšà»œà»‰àº²àº”ຽວ</translation>
-<translation id="1049743911850919806">ບà»à»ˆâ€‹à»€àºœàºµàºâ€‹àº•àº»àº§àº•àº»àº™</translation>
<translation id="1050038467049342496">ປິດà»àº­àº±àºšàº­àº·à»ˆàº™</translation>
<translation id="1055184225775184556">ປ່ຽນ​ຄືນຄà»àº²àºªàº±à»ˆàº‡à»€àºžàºµà»ˆàº¡</translation>
<translation id="1056898198331236512">ຄà»àº²à»€àº•àº·àº­àº™</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">à»àº„ຊ໌ນະໂàºàºšàº²àºà»ƒàºŠà»‰à»„ດ້</translation>
<translation id="1130564665089811311">ປຸ່ມà»àº›à»œà»‰àº², àºàº»àº” Enter ເພື່ອà»àº›à»œà»‰àº²àº™àºµà»‰àº”້ວຠGoogle à»àº›àºžàº²àºªàº²</translation>
<translation id="1131264053432022307">ຮູບພາບທີ່ທ່ານສຳເນົາ</translation>
+<translation id="1142846828089312304">ບລັອàºàº„ຸàºàºàºµà»‰àºžàº²àºàºªà»ˆàº§àº™àº—ີສາມໃນໂà»àº”ບà»à»ˆà»€àº›àºµàº”ເຜີàºàº•àº»àº§àº•àº»àº™</translation>
<translation id="1150979032973867961">ເຊີບເວີນີ້ບà»à»ˆàºªàº²àº¡àº²àº”ພິສູດໄດ້ວ່າ ມັນà»àº¡à»ˆàº™ <ph name="DOMAIN" />; ໃບຢັ້ງຢືນຄວາມປອດໄພຂອງມັນບà»à»ˆà»„ດ້ຮັບàºàº²àº™à»€àºŠàº·à»ˆàº­à»àº±à»‰àº™à»‚ດàºàº¥àº°àºšàº»àºšàºàº²àº™àº”à»àº²à»€àº™àºµàº™àº‡àº²àº™àº‚ອງຄອມພິວເຕີຂອງທ່ານ. ອັນນີ້ອາດຈະເຮັດໃຫ້ເàºàºµàº”ມີàºàº²àº™àº›àº±àºšàº•àº±à»‰àº‡àº„່າຜິດ ຫຼືຜູ້ໂຈມຕີອາດຈະດັàºà»€àº­àº»àº²àºàº²àº™à»€àºŠàº·à»ˆàº­àº¡àº•à»à»ˆàº‚ອງທ່ານ.</translation>
<translation id="1151972924205500581">ຕ້ອງມີລະ​ຫັດ​ຜ່ານ​</translation>
<translation id="1156303062776767266">ທ່ານàºàº³àº¥àº±àº‡à»€àºšàº´à»ˆàº‡à»„ຟລ໌ພາàºà»ƒàº™à»€àº„ື່ອງ ຫຼື ໄຟລ໌ທີ່à»àºšà»ˆàº‡àº›àº±àº™</translation>
@@ -64,7 +70,6 @@
<translation id="1178581264944972037">ຢຸດຊົ່ວຄາວ</translation>
<translation id="1181037720776840403">ລຶບອອàº</translation>
<translation id="1186201132766001848">àºàº§àº”ເບິ່ງລະຫັດຜ່ານ</translation>
-<translation id="1195210374336998651">ໄປຫາàºàº²àº™àº•àº±à»‰àº‡àº„່າà»àº­àº±àºš</translation>
<translation id="1195558154361252544">àºàº²àº™à»àºˆà»‰àº‡à»€àº•àº·àº­àº™àº–ືàºàºšàº¥àº±àº­àºà»„ວ້ໂດàºàº­àº±àº”ຕະໂນມັດສຳລັບເວັບໄຊທັງà»àº»àº” àºàº»àºà»€àº§àº±à»‰àº™à»€àº§àº±àºšà»„ຊທີ່ທ່ານອະນຸàºàº²àº”</translation>
<translation id="1197088940767939838">ສີà»àº²àºàºà»‰àº½àº‡</translation>
<translation id="1201402288615127009">ຕà»à»ˆà»„ປ</translation>
@@ -111,7 +116,7 @@
<translation id="1307966114820526988">ຄຸນສົມບັດທີ່ເຊົາຮອງຮັບà»àº¥à»‰àº§</translation>
<translation id="1308113895091915999">ມີຂà»à»‰àºªàº°à»€à»œàºµ</translation>
<translation id="1312803275555673949">ມີຫຼັàºàº–ານໃດສະໜັບສະໜຸນມັນ?</translation>
-<translation id="131405271941274527"><ph name="URL" /> ຕ້ອງàºàº²àº™àºªàº»à»ˆàº‡ à»àº¥àº° ຮັບຂà»à»‰àº¡àº¹àº™à»€àº¡àº·à»ˆàº­àº—່ານà»àº•àº°à»‚ທລະສັບຂອງທ່ານໃນອຸປະàºàº­àº™ NFC</translation>
+<translation id="1314311879718644478">ເບິ່ງເນື້ອຫາອາàºàº´àº§à»€àº¡àº±àº™ ຣີອາລິຕີ</translation>
<translation id="1314509827145471431">ຫàºàº´àºšà»€àº«àº¼àº±à»‰àº¡à»€àºšàº·à»‰àº­àº‡àº‚ວາ</translation>
<translation id="1318023360584041678">ບັນທຶàºà»ƒàº™àºàº¸à»ˆàº¡à»àº–ບà»àº¥à»‰àº§</translation>
<translation id="1319245136674974084">ບà»à»ˆàº•à»‰àº­àº‡àº–າມອີàºàºªàº³àº¥àº±àºšà»àº­àº±àºšàº™àºµà»‰</translation>
@@ -161,6 +166,7 @@
<translation id="142858679511221695">ຜູ້ໃຊ້ຄລາວ</translation>
<translation id="1428729058023778569">ທ່ານເຫັນຄຳເຕືອນນີ້ເນື່ອງຈາàºà»€àº§àº±àºšà»„ຊນີ້ບà»à»ˆàº®àº­àº‡àº®àº±àºš HTTPS. <ph name="BEGIN_LEARN_MORE_LINK" />ສຶàºàºªàº²à»€àºžàºµà»ˆàº¡à»€àº•àºµàº¡<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">ພິມ</translation>
+<translation id="1432187715652018471">ໜ້າຕ້ອງàºàº²àº™àº•àº´àº”ຕັ້ງຕົວຈັດàºàº²àº™â€‹àºšà»â€‹àº¥àº´â€‹àºàº²àº™â€‹.</translation>
<translation id="1432581352905426595">ຈັດàºàº²àº™à»‚ປຣà»àºàº£àº¡àºŠàº­àºàº«àº²</translation>
<translation id="1436185428532214179">ສາມາດຂà»à»àºà»‰à»„ຂໄຟລ໌ à»àº¥àº° ໂຟນເດີຢູ່ອຸປະàºàº­àº™àº‚ອງທ່ານ</translation>
<translation id="1442386063175183758">ພັບທົບເບື້ອງຂວາ</translation>
@@ -181,6 +187,12 @@
<translation id="1483493594462132177">ສົ່ງ</translation>
<translation id="1484290072879560759">ເລືອàºàº—ີ່ຢູ່àºàº²àº™àºˆàº±àº”ສົ່ງ</translation>
<translation id="1492194039220927094">àºàº²àº™à»àºˆà»‰àº‡à»€àº•àº·àº­àº™àº™àº°à»‚àºàºšàº²àº:</translation>
+<translation id="149293076951187737">ເມື່ອທ່ານປິດà»àº–ບ​ບà»à»ˆà»€àº›àºµàº”ເຜີàºàº•àº»àº§àº•àº»àº™ Chrome ທັງà»àº»àº”ໄວ້à»àº¥à»‰àº§, àºàº²àº™à»€àº„ື່ອນໄຫວຂອງທ່ານໃນà»àº–ບເຫຼົ່ານັ້ນຈະຖືàºàº¥àº¶àºšàº¥à»‰àº²àº‡àº­àº­àºàºˆàº²àºàº­àº¸àº›àº°àºàº­àº™àº™àºµà»‰:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />àºàº²àº™à»€àº„ື່ອນໄຫວàºàº²àº™àº—່ອງເວັບ<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ປະ​ຫວັດ​àºàº²àº™â€‹àºŠàº­àºàº«àº²<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ຂà»à»‰àº¡àº¹àº™àº—ີ່ລະບຸໄວ້ໃນà»àºšàºšàºŸàº­àº¡àº•à»ˆàº²àº‡à»†<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">àºàº±àºšàº„ືນຫາà»àº–ບ</translation>
<translation id="1501859676467574491">ສະà»àº”ງບັດຈາàºàºšàº±àº™àºŠàºµ Google ຂອງທ່ານ</translation>
<translation id="1507202001669085618">&lt;p&gt;ທ່ານຈະເຫັນຂà»à»‰àºœàº´àº”ພາດນີ້ຖ້າທ່ານàºàº³àº¥àº±àº‡à»ƒàºŠà»‰à»œà»‰àº²à»€àº§àº±àºš Wi-Fi ບ່ອນທີ່ທ່ານຈຳເປັນຕ້ອງເຂົ້າສູ່ລະບົບàºà»ˆàº­àº™àº—ີ່ທ່ານຈະສາມາດອອນລາàºà»„ດ້.&lt;/p&gt;
@@ -208,6 +220,8 @@
<translation id="1559572115229829303">&lt;p&gt;ບà»à»ˆâ€‹àºªàº²â€‹àº¡àº²àº”​ຕັ້ງ​àºàº²àº™â€‹à»€àºŠàº·à»ˆàº­àº¡â€‹àº•à»à»ˆâ€‹àºªà»ˆàº§àº™â€‹àº•àº»àº§â€‹àºàº±àºš <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> ໄດ້ ເພາະ​ວ່າ​ວັນ​ທີ à»àº¥àº° ​ເວ​ລາ​ອຸ​ປະ​àºàº­àº™â€‹àº‚ອງ​ທ່ານ (<ph name="DATE_AND_TIME" />) ບà»à»ˆâ€‹àº–ືàºâ€‹àº•à»‰àº­àº‡.&lt;/p&gt;
&lt;p&gt;àºàº°â€‹àº¥àº¸â€‹àº™àº²â€‹àº›àº±àºšâ€‹àº§àº±àº™â€‹àº—ີ à»àº¥àº°â€‹à»€àº§â€‹àº¥àº²â€‹àºˆàº²àºàºžàº²àº &lt;strong&gt;ທົ່ວ​ໄປl&lt;/strong&gt; ຂອງ​à»àº­àº±àºš &lt;strong&gt;àºàº²àº™â€‹àº•àº±à»‰àº‡â€‹àº„່າ&lt;/strong&gt;.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">ຜູ້ເບິ່ງà»àºàº‡àº¥àº°àºšàº»àºšàº‚ອງທ່ານຈະຣີສະຕາດອຸປະàºàº­àº™àº‚ອງທ່ານເວລາ <ph name="TIME" /> ໃນ <ph name="DATE" /></translation>
+<translation id="156703335097561114">ຂà»à»‰àº¡àº¹àº™àº”້ານເຄືອຂ່າຠເຊັ່ນ: ທີ່ຢູ່, àºàº²àº™àº•àº±à»‰àº‡àº„່າສ່ວນຕິດຕà»à»ˆ à»àº¥àº° ຄຸນນະພາບàºàº²àº™à»€àºŠàº·à»ˆàº­àº¡àº•à»à»ˆ</translation>
<translation id="1567040042588613346">ນະໂàºàºšàº²àºàº™àºµà»‰àºàº³àº¥àº±àº‡à»€àº®àº±àº”ວຽàºàº•àº²àº¡àº—ີ່àºàº³àº™àº»àº”ໄວ້ à»àº•à»ˆàº¡àºµàºàº²àº™àº•àº±à»‰àº‡àº„່າດຽວàºàº±àº™àº¢àº¹à»ˆàºšà»ˆàº­àº™àº­àº·à»ˆàº™ à»àº¥àº° ນະໂàºàºšàº²àºàº™àºµà»‰àºàº³àº¥àº±àº‡à»àº—ນທີ່ມັນ.</translation>
<translation id="1569487616857761740">ປ້ອນວັນທີà»àº»àº”ອາàºàº¸</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@
<translation id="1583429793053364125">ມີບາງອັນຜິດພາດ ໃນຂະນະທີ່àºà»àº²àº¥àº±àº‡àºªàº°à»àº”ງໜ້າ​ເວັບນີ້.</translation>
<translation id="1586541204584340881">ສ່ວນຂະຫàºàº²àºàº—ີ່ທ່ານຕິດຕັ້ງ</translation>
<translation id="1588438908519853928">ປົàºâ€‹àºàº°â€‹àº•àº´</translation>
+<translation id="1589050138437146318">ຕິດຕັ້ງ ARCore ບ�</translation>
<translation id="1592005682883173041">àºàº²àº™à»€àº‚ົ້າເຖິງຂà»à»‰àº¡àº¹àº™àºžàº²àºà»ƒàº™à»€àº„ື່ອງ</translation>
<translation id="1594030484168838125">ເລືອàº</translation>
<translation id="160851722280695521">ຫຼິ້ນເàºàº¡ Dino Run ໃນ Chrome</translation>
@@ -283,6 +298,7 @@
ສ່ວນຫົວດັ່ງàºà»ˆàº²àº§àº¡àºµàº®àº¹àºšà»àºšàºšàºšà»à»ˆàº–ືàºàº•à»‰àº­àº‡, ເຊິ່ງເຮັດໃຫ້ໂປຣà»àºàº£àº¡àº—່ອງເວັບດຳເນີນàºàº²àº™àº•àº²àº¡
ຄຳຂà»àº‚ອງທ່ານສຳລັບ <ph name="SITE" /> ບà»à»ˆà»„ດ້. ນະໂàºàºšàº²àºàº•àº»à»‰àº™àº—າງສາມາດໃຊ້ໄດ້ໂດàº
ຜູ້ໃຫ້ບà»àº¥àº´àºàº²àº™à»€àº§àº±àºšà»„ຊເພື່ອàºàº³àº™àº»àº”ຄ່າຄວາມປອດໄພ à»àº¥àº° ຄຸນລັàºàºªàº°àº™àº°àº­àº·à»ˆàº™à»†àºªàº³àº¥àº±àºšà»€àº§àº±àºšà»„ຊ.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />ສຶàºàºªàº²à»€àºžàºµà»ˆàº¡à»€àº•àºµàº¡àºà»ˆàº½àº§àºàº±àºšà»‚à»àº”ບà»à»ˆà»€àº›àºµàº”ເຜີàºàº•àº»àº§àº•àº»àº™à»ƒàº™ Chromium<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">à»àº–ບທີ່ເປີດຢູ່ຂອງທ່ານປາàºàº»àº”ຢູ່ບ່ອນນີ້</translation>
<translation id="1791429645902722292">ລັອàºâ€‹àº­àº±àº”​ສະ​ລິ​àºàº° Google</translation>
@@ -410,6 +426,7 @@
<translation id="22081806969704220">ຖາດ 3</translation>
<translation id="2212735316055980242">ບà»à»ˆàºžàº»àºšàº™àº°â€‹à»‚àºâ€‹àºšàº²àºâ€‹</translation>
<translation id="2213606439339815911">àºà»àº²àº¥àº±àº‡à»€àº­àº»àº²àºàº²àº™àº›à»‰àº­àº™à»€àº‚ົ້າ...</translation>
+<translation id="2213612003795704869">ພິມໜ້າà»àº¥à»‰àº§</translation>
<translation id="2215727959747642672">àºàº²àº™à»àºà»‰à»„ຂໄຟລ໌</translation>
<translation id="2218879909401188352">ຜູ້ໂຈມຕີເຊິ່ງໃນປັດຈຸບັນຢູ່ໃນ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ສາມາດຕິດຕັ້ງà»àº­àº±àºšàº­àº±àº™àº•àº°àº¥àº²àºàº—ີ່ເຮັດໃຫ້ອຸປະàºàº­àº™àº‚ອງທ່ານເສàºàº«àº²àºà»„ດ້, ເພີ່ມàºàº²àº™àº„ິດຄ່າທີ່ເຊື່ອງໄວ້ໃສ່ໃບບິນມືຖືຂອງທ່ານ ຫຼື ລັàºà»€àº­àº»àº²àº‚à»à»‰àº¡àº¹àº™àºªà»ˆàº§àº™àº‚ອງທ່ານ. <ph name="BEGIN_LEARN_MORE_LINK" />ສຶàºàºªàº²à»€àºžàºµà»ˆàº¡à»€àº•àºµàº¡<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">ບà»à»ˆàº¡àºµàº­àº´àº™à»€àº•àºµà»€àº™àº±àº”</translation>
@@ -419,6 +436,7 @@
<translation id="2248949050832152960">ໃຊ້ WebAuthn</translation>
<translation id="2250931979407627383">ຫàºàº´àºšàº‚ອບເບື້ອງຂວາ</translation>
<translation id="225207911366869382">ຄ່ານີ້ຖືàºàº„ັດຄ້ານສà»àº²â€‹àº¥àº±àºšâ€‹àº™àº°â€‹à»‚àºâ€‹àºšàº²àºâ€‹àº™àºµà»‰â€‹.</translation>
+<translation id="2256115617011615191">ເລີ່ມລະບົບໃà»à»ˆàº”ຽວນີ້</translation>
<translation id="2258928405015593961">ປ້ອນວັນທີà»àº»àº”ອາàºàº¸à»ƒàº™àº­àº°àº™àº²àº„ົດ à»àº¥à»‰àº§àº¥àº­àº‡à»ƒà»à»ˆ</translation>
<translation id="225943865679747347">ລະຫັດຜິດພາດ: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">ຄວາມ​ຜິດ​ພາດ HTTP</translation>
@@ -446,6 +464,7 @@
<translation id="2337852623177822836">àºàº²àº™àº•àº±à»‰àº‡àº„່າທີ່ຄວບຄຸມໂດàºàºœàº¹à»‰à»€àºšàº´à»ˆàº‡à»àºàº‡àº¥àº°àºšàº»àºšàº‚ອງທ່ານ</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> ຕ້ອງàºàº²àº™àºˆàº±àºšàº„ູ່</translation>
<translation id="2346319942568447007">ຮູບພາບທີ່ທ່ານສຳເນົາ</translation>
+<translation id="2350796302381711542">ອະນຸàºàº²àº”ໃຫ້ <ph name="HANDLER_HOSTNAME" /> ເປີດທຸຠ<ph name="PROTOCOL" /> ລິ້ງà»àº—ນ <ph name="REPLACED_HANDLER_TITLE" /> ບà»?</translation>
<translation id="2354001756790975382">ບຸàºàº¡àº²àºàºªà»Œàº­àº·à»ˆàº™à»†</translation>
<translation id="2354430244986887761">Google Safe Browsing <ph name="BEGIN_LINK" />ພົບໂປຣà»àºàº£àº¡àº­àº±àº™àº•àº°àº¥àº²àº<ph name="END_LINK" /> ຢູ່ໃນ <ph name="SITE" />ເມື່ອບà»à»ˆàº”ົນມານີ້.</translation>
<translation id="2355395290879513365">ຜູ້ໂຈມຕີອາດຈະສາມາດເຫັນຮູບພາບທີ່ທ່ານàºàº³àº¥àº±àº‡à»€àºšàº´à»ˆàº‡àº¢àº¹à»ˆà»ƒàº™à»€àº§àº±àºšà»„ຊນີ້ à»àº¥àº° ຫຼອàºàº¥àº§àº‡àº—່ານໂດàºàºàº²àº™àº”ັດà»àº›àº‡àº®àº¹àºšàºžàº²àºšà»€àº«àº¼àº»à»ˆàº²àº™àº±à»‰àº™.</translation>
@@ -471,6 +490,7 @@
<translation id="2413528052993050574">ເຊີບເວີນີ້ບà»à»ˆàºªàº²àº¡àº²àº”ພິສູດໄດ້ວ່າ ມັນà»àº¡à»ˆàº™ <ph name="DOMAIN" />; ໃບຢັ້ງຢືນຄວາມປອດໄພຂອງມັນອາດຈະຖືàºàº–ອນຄືນà»àº¥à»‰àº§. ອັນນີ້ອາດຈະເຮັດໃຫ້ເàºàºµàº”ມີàºàº²àº™àº›àº±àºšàº•àº±à»‰àº‡àº„່າຜິດ ຫຼືຜູ້ໂຈມຕີອາດຈະດັàºà»€àº­àº»àº²àºàº²àº™à»€àºŠàº·à»ˆàº­àº¡àº•à»à»ˆàº‚ອງທ່ານ.</translation>
<translation id="2414886740292270097">ມືດ</translation>
<translation id="2430968933669123598">ຈັດàºàº²àº™àºšàº±àº™àºŠàºµ Google, àºàº»àº” Enter ເພື່ອຈັດàºàº²àº™àº‚à»à»‰àº¡àº¹àº™, ຄວາມເປັນສ່ວນຕົວ à»àº¥àº° ຄວາມປອດໄພຂອງທ່ານໃນບັນຊີ Google ທ່ານ</translation>
+<translation id="2436186046335138073">ອະນຸàºàº²àº”ໃຫ້ <ph name="HANDLER_HOSTNAME" /> ເປີດທຸàºàº¥àº´à»‰àº‡ <ph name="PROTOCOL" /> ບà»?</translation>
<translation id="2438874542388153331">ເຈາະຮູຢູ່ເບື້ອງຂວາສີ່ຮູ</translation>
<translation id="2450021089947420533">ບັນທຶàº</translation>
<translation id="2463739503403862330">ຕື່ມຂà»à»‰àº¡àº¹àº™</translation>
@@ -478,6 +498,7 @@
<translation id="2465655957518002998">ເລືອàºàº§àº´àº—ີàºàº²àº™àºˆàº±àº”ສົ່ງ</translation>
<translation id="2465688316154986572">àºàº°àº«àº¼àº±àºšà»€àºŸàºµ</translation>
<translation id="2465914000209955735">ຈັດàºàº²àº™à»„ຟລ໌ທີ່ທ່ານດາວໂຫຼດໄວ້ໃນ Chrome</translation>
+<translation id="2466004615675155314">ສະà»àº”ງຂà»à»‰àº¡àº¹àº™â€‹àºˆàº²àºâ€‹à»€àº§àº±àºšâ€‹à»„ຊ</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />àºàº³àº¥àº±àº‡à»€àº›àºµàº”ໃຊ້ Network Diagnostics<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">ລຳດັບ 1 ເຖິງ N</translation>
<translation id="2470767536994572628">ເມື່ອທ່ານà»àºà»‰à»„ຂຄຳອະທິບາàºàº„ວາມເຫັນດ ເອàºàº°àºªàº²àº™àº™àºµà»‰àºˆàº°àºàº±àºšà»„ປເປັນມຸມມອງà»àºšàºšà»œà»‰àº²àº”ຽວ à»àº¥àº° àºàº±àºšà»„ປໃຊ້àºàº²àº™à»àº¸àº™à»àºšàºšà»€àº”ີມຂອງມັນ</translation>
@@ -498,6 +519,7 @@
<translation id="2523886232349826891">ບັນທຶàºà»„ວ້ໃນອຸປະàºàº­àº™àº™àºµà»‰à»€àº—ົ່ານັ້ນ</translation>
<translation id="2524461107774643265">ເພີ່ມຂà»à»‰àº¡àº¹àº™à»€àºžàºµà»ˆàº¡à»€àº•àºµàº¡</translation>
<translation id="2529899080962247600">ຊ່ອງຂà»à»‰àº¡àº¹àº™àº™àºµà»‰àºšà»à»ˆàº„ວນມີຫຼາàºàºàº§à»ˆàº² <ph name="MAX_ITEMS_LIMIT" /> ລາàºàºàº²àº™. ລາàºàºàº²àº™à»€àºžàºµà»ˆàº¡à»€àº•àºµàº¡àº—ັງà»àº»àº”ຈະຖືàºàº¥àº°à»€àº§àº±à»‰àº™.</translation>
+<translation id="2535585790302968248">ເປີດà»àº–ບທີ່ບà»à»ˆà»€àº›àºµàº”ເຜີàºàº•àº»àº§àº•àº»àº™à»ƒà»à»ˆà»€àºžàº·à»ˆàº­àº—່ອງເວັບà»àºšàºšàºªà»ˆàº§àº™àº•àº»àº§</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{à»àº¥àº° ອີຠ1 ລາàºàºàº²àº™}other{à»àº¥àº° ອີຠ# ລາàºàºàº²àº™}}</translation>
<translation id="2536110899380797252">ເພີ່ມທີ່ຢູ່</translation>
<translation id="2539524384386349900">àºàº§àº”ຫາ</translation>
@@ -523,7 +545,14 @@
<translation id="2597378329261239068">ເອàºàº°àºªàº²àº™àº™àºµà»‰àº¡àºµàº¥àº°àº«àº±àº”ຜ່ານປ້ອງàºàº±àº™à»„ວ້. àºàº°àº¥àº¸àº™àº²à»ƒàºªà»ˆàº¥àº°àº«àº±àº”ຜ່ານ.</translation>
<translation id="2609632851001447353">àºàº²àº™â€‹àº›à»ˆàº½àº™â€‹à»àº›àº‡</translation>
<translation id="2610561535971892504">ຄລິàºà»€àºžàº·à»ˆàº­àºªàº³à»€àº™àº»àº²</translation>
+<translation id="2617988307566202237">Chrome <ph name="BEGIN_EMPHASIS" />ຈະບà»à»ˆàºšàº±àº™àº—ຶàº<ph name="END_EMPHASIS" /> ຂà»à»‰àº¡àº¹àº™àº•à»à»ˆà»„ປນີ້:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ປະຫວັດàºàº²àº™àº—່ອງເວັບຂອງທ່ານ
+ <ph name="LIST_ITEM" />ຄຸàºàºàºµà»‰ à»àº¥àº° ຂà»à»‰àº¡àº¹àº™à»€àº§àº±àºšà»„ຊ
+ <ph name="LIST_ITEM" />ຂà»à»‰àº¡àº¹àº™àº—ີ່ປ້ອນໃສ່à»àºšàºšàºŸàº­àº¡àº•à»ˆàº²àº‡à»†
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (ຊອງຈົດà»àº²àº)</translation>
+<translation id="2623663032199728144">ສາມາດຖາມເພື່ອໃຊ້ຂà»à»‰àº¡àº¹àº™àºà»ˆàº½àº§àºàº±àºšà»œà»‰àº²àºˆà»àº‚ອງທ່ານໄດ້</translation>
<translation id="2625385379895617796">ໂມງ​ຂອ​ງ​ທ່ານ​ໄວ</translation>
<translation id="262745152991669301">ສາມາດຂà»à»€àºŠàº·à»ˆàº­àº¡àº•à»à»ˆàº«àº²àº­àº¸àº›àº°àºàº­àº™ USB ໄດ້</translation>
<translation id="2629325967560697240">ເພື່ອຮັບຄວາມປອດໄພລະດັບສູງສຸດຂອງ Chrome, <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />àºàº°àº¥àº¸àº™àº²à»€àº›àºµàº”àºàº²àº™àº›àº»àºàº›à»‰àº­àº‡àº—ີ່ປັບປຸງດີຂຶ້ນà»àº¥à»‰àº§<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -557,6 +586,7 @@
<translation id="2709516037105925701">ຕື່ມອັດຕະໂນມັດ</translation>
<translation id="2713444072780614174">ສີ​ຂາວ</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />, àºàº»àº”à»àº–ບ ຈາàºàº™àº±à»‰àº™àºàº»àº” Enter ເພື່ອຈັດàºàº²àº™àºàº²àº™àºˆà»ˆàº²àºà»€àº‡àº´àº™ à»àº¥àº° ຂà»à»‰àº¡àº¹àº™àºšàº±àº”ເຄຣດິດຂອງທ່ານໃນàºàº²àº™àº•àº±à»‰àº‡àº„່າ Chrome</translation>
+<translation id="271663710482723385">àºàº»àº” |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| ເພື່ອອອàºà»‚à»àº”ຈາàºà»€àº•àº±àº¡àºˆà»</translation>
<translation id="2721148159707890343">àºàº²àº™â€‹àº®à»‰àº­àº‡â€‹àº‚à»â€‹àºªà»àº²â€‹à»€àº¥àº±àº”</translation>
<translation id="2723669454293168317">ເປີດໃຊ້àºàº²àº™àºàº§àº”ສອບຄວາມປອດໄພໃນàºàº²àº™àº•àº±à»‰àº‡àº„່າ Chrome</translation>
<translation id="2726001110728089263">ຖາດຂ້າງ</translation>
@@ -587,6 +617,7 @@
<translation id="2850739647070081192">Invite (ຊອງຈົດà»àº²àº)</translation>
<translation id="2856444702002559011">ຜູ້ໂຈມຕີອາດຈະàºàº³àº¥àº±àº‡àºžàº°àºàº²àºàº²àº¡àº¥àº±àºà»€àº­àº»àº²àº‚à»à»‰àº¡àº¹àº™àº‚ອງທ່ານຈາຠ<ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (ຕົວຢ່າງ: ລະຫັດຜ່ານ, ຂà»à»‰àº„ວາມ ຫຼື ບັດເຄຣດິດ). <ph name="BEGIN_LEARN_MORE_LINK" />ສຶàºàºªàº²à»€àºžàºµà»ˆàº¡à»€àº•àºµàº¡<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">ເວັບໄຊນີ້ສະà»àº”ງໂຄສະນາທີ່ລົບàºàº§àº™ ຫຼື ຫຼອàºàº¥àº§àº‡.</translation>
+<translation id="286512204874376891">ບັດສະເà»àº·àº­àº™àºˆàº°àº›àº­àº¡à»àº›àº‡àºšàº±àº”à»àº—້ຂອງທ່ານເພື່ອຊ່ວàºàº›àº»àºàº›à»‰àº­àº‡àº—່ານຈາàºàº„ວາມສ່ຽງໃນàºàº²àº™àºªà»à»‰à»‚àºàº‡. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">ເປັນມິດ</translation>
<translation id="2876489322757410363">àºàº³àº¥àº±àº‡àº­àº­àºàºˆàº²àºà»‚à»àº”ບà»à»ˆà»€àº›àºµàº”ເຜີàºàº•àº»àº§àº•àº»àº™à»€àºžàº·à»ˆàº­àºˆà»ˆàº²àºàºœà»ˆàº²àº™à»àº­àº±àºšàºžàº¥àº´à»€àº„ຊັນພາàºàº™àº­àº ສືບຕà»à»ˆàºšà»?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />, àºàº»àº” Tab ຈາàºàº™àº±à»‰àº™àºàº»àº” Enter ເພື່ອຈັດàºàº²àº™ Safe Browsing ຂອງທ່ານ à»àº¥àº° ອື່ນໆໃນàºàº²àº™àº•àº±à»‰àº‡àº„່າ Chrome</translation>
@@ -611,6 +642,7 @@
<translation id="2930577230479659665">ຕັດອອàºàº«àº¼àº±àº‡àºˆàº²àºàºªàº³à»€àº™àº»àº²à»àº•à»ˆàº¥àº°àºªàº°àºšàº±àºš</translation>
<translation id="2932085390869194046">à»àº™àº°àº™àº³àº¥àº°àº«àº±àº”ຜ່ານ...</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019">ເປີດ​ລິ້ງ <ph name="PROTOCOL" /></translation>
<translation id="2941952326391522266">ເຊີບເວີນີ້ບà»à»ˆàºªàº²àº¡àº²àº”ພິສູດໄດ້ວ່າ ມັນà»àº¡à»ˆàº™ <ph name="DOMAIN" />; ໃບຢັ້ງຢືນຄວາມປອດໄພຂອງມັນມາຈາຠ<ph name="DOMAIN2" />. ອັນນີ້ອາດຈະເຮັດໃຫ້ເàºàºµàº”ມີàºàº²àº™àº›àº±àºšàº•àº±à»‰àº‡àº„່າຜິດ ຫຼືຜູ້ໂຈມຕີອາດຈະດັàºà»€àº­àº»àº²àºàº²àº™à»€àºŠàº·à»ˆàº­àº¡àº•à»à»ˆàº‚ອງທ່ານ.</translation>
<translation id="2943895734390379394">ເວລາອັບໂຫຼດ:</translation>
<translation id="2948083400971632585">ທ່ານສາມາດປິດໃຊ້ງານພຣັອàºàºŠàºµà»ƒàº”ໜຶ່ງທີ່ໄດ້ປັບຕັ້ງຄ່າສà»àº²àº¥àº±àºšàºàº²àº™à»€àºŠàº·à»ˆàº­àº¡àº•à»à»ˆàºˆàº²àºà»œà»‰àº²àºàº²àº™àº•àº±à»‰àº‡àº„່າ.</translation>
@@ -643,6 +675,7 @@
<translation id="3037605927509011580">ອ່າ, ຖ່າàºàº®àº¹àºš!</translation>
<translation id="3041612393474885105">ຂà»à»‰àº¡àº¹àº™à»ƒàºšàº¢àº±à»‰àº‡àº¢àº·àº™</translation>
<translation id="3044034790304486808">ສືບຕà»à»ˆàºšàº±àº™àº—ຶàºàº‚ອງທ່ານ</translation>
+<translation id="305162504811187366">ປະຫວັດ Chrome Remote Desktop, ຮວມທັງເວລາ, ID ເຊດຊັນຂອງໂຮສ à»àº¥àº° ລູàºàº‚່າàº</translation>
<translation id="3060227939791841287">C9 (ຊອງຈົດà»àº²àº)</translation>
<translation id="3061707000357573562">àºàº²àº™àºšà»àº¥àº´àºàº²àº™à»àºà»‰àºšàº±àº™àº«àº²</translation>
<translation id="306573536155379004">ເລີ່ມເàºàº¡à»àº¥à»‰àº§.</translation>
@@ -683,6 +716,7 @@
<translation id="3197136577151645743">ສາມາດຂà»àº‚à»à»‰àº¡àº¹àº™àº§à»ˆàº²àº—່ານàºàº³àº¥àº±àº‡à»ƒàºŠà»‰àº­àº¸àº›àº°àºàº­àº™àº™àºµà»‰àº¢à»ˆàº²àº‡àº•à»à»ˆà»€àº™àº·à»ˆàº­àº‡àº•àº­àº™à»ƒàº”</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />, àºàº»àº” Tab ຈາàºàº™àº±à»‰àº™àºàº»àº” Enter ເພື່ອຈັດàºàº²àº™àº§à»ˆàº²àº‚à»à»‰àº¡àº¹àº™à»ƒàº”ທີ່ທ່ານຈະຊິ້ງຂà»à»‰àº¡àº¹àº™à»ƒàº™àºàº²àº™àº•àº±à»‰àº‡àº„່າ Chrome</translation>
<translation id="320323717674993345">àºàº»àºà»€àº¥àºµàºàºàº²àº™àºˆà»ˆàº²àºà»€àº‡àº´àº™</translation>
+<translation id="3203366800380907218">​ຈາàºâ€‹à»€àº§àº±àºšâ€‹à»„ຊ</translation>
<translation id="3207960819495026254">ໃສ່ບຸàºâ€‹àº¡àº²àºâ€‹à»Œâ€‹à»àº¥à»‰àº§</translation>
<translation id="3209034400446768650">ໜ້າອາດຈະຮຽàºà»€àºàº±àºšà»€àº‡àº´àº™</translation>
<translation id="3212581601480735796">àºàº³àº¥àº±àº‡àº¡àºµàºàº²àº™àº•àº´àº”ຕາມເບິ່ງàºàº²àº™à»€àº„ື່ອນໄຫວຂອງທ່ານໃນ <ph name="HOSTNAME" /></translation>
@@ -699,10 +733,12 @@
<translation id="3234666976984236645">àºàº§àº”​ຫາ​ເນື້ອ​ໃນ​ສຳ​ຄັນ​ຢູ່​ເທິງ​ເວັບ​ໄຊ​ທ໌​ນີ້​ທຸàºâ€‹àº„ັ້ງ</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />, àºàº»àº” tab ຈາàºàº™àº±à»‰àº™àºàº»àº” Enter ເພື່ອປັບà»àº•à»ˆàº‡à»œà»‰àº²àº•àº²àº‚ອງໂປຣà»àºàº£àº¡àº—່ອງເວັບທ່ານ</translation>
<translation id="3240791268468473923">ເປີດຊີດຂà»à»‰àº¡àº¹àº™àºàº²àº™à»€àº‚ົ້າສູ່ລະບົບàºàº²àº™àºˆà»ˆàº²àºà»€àº‡àº´àº™àº—ີ່ປອດໄພທີ່ບà»à»ˆàº¡àºµàº‚à»à»‰àº¡àº¹àº™àºàº²àº™à»€àº‚ົ້າສູ່ລະບົບທີ່àºàº»àº‡àºàº±àº™à»àº¥à»‰àº§</translation>
+<translation id="324180406144491771">ລິ້ງ “<ph name="HOST_NAME" />†ຖືàºàºšàº¥àº±àº­àºà»„ວ້à»àº¥à»‰àº§</translation>
<translation id="3249845759089040423">àºàº£àº¹àºŸàºµ</translation>
<translation id="3252266817569339921">ພາສາàºàº£àº±à»ˆàº‡</translation>
<translation id="3257954757204451555">ໃຜຢູ່ເບື້ອງຫຼັງຂà»à»‰àº¡àº¹àº™àº™àºµà»‰?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />, àºàº»àº” Tab ຈາàºàº™àº±à»‰àº™àºàº»àº” Enter ເພື່ອສ້າງນັດà»àº²àºà»ƒà»à»ˆà»ƒàº™ Google ປະຕິທິນໄດ້ຢ່າງວ່ອງໄວ</translation>
+<translation id="3261488570342242926">ສຶàºàºªàº²àºà»ˆàº½àº§àºàº±àºšàºšàº±àº”ສະເà»àº·àº­àº™</translation>
<translation id="3264837738038045344">ປຸ່ມຈັດàºàº²àº™àºàº²àº™àº•àº±à»‰àº‡àº„່າ Chrome, àºàº»àº” Enter ເພື່ອເຂົ້າàºàº²àº™àº•àº±à»‰àº‡àº„່າ Chrome ຂອງທ່ານ</translation>
<translation id="3266793032086590337">ຄ່າ (ຂັດà»àºà»ˆàº‡)</translation>
<translation id="3268451620468152448">ເປີດ​à»àº–ບ</translation>
@@ -716,6 +752,7 @@
<translation id="3288238092761586174"><ph name="URL" /> ອາດຕ້ອງເຮັດຂັ້ນຕອນເພີ່ມເຕີມເພື່ອຢັ້ງຢືນàºàº²àº™àºˆà»ˆàº²àºà»€àº‡àº´àº™àº‚ອງທ່ານ</translation>
<translation id="3293642807462928945">ສຶàºàºªàº²à»€àºžàºµà»ˆàº¡à»€àº•àºµàº¡àºà»ˆàº½àº§àºàº±àºšàº™àº°à»‚àºàºšàº²àº <ph name="POLICY_NAME" /></translation>
<translation id="3295444047715739395">ເບິ່ງ à»àº¥àº° ຈັດàºàº²àº™àº¥àº°àº«àº±àº”ຜ່ານຂອງທ່ານໃນàºàº²àº™àº•àº±à»‰àº‡àº„່າ Chrome</translation>
+<translation id="3303795387212510132">ອະນຸàºàº²àº”à»àº­àº±àºšà»ƒàº«à»‰à»€àº›àºµàº”ລິ້ງ <ph name="PROTOCOL_SCHEME" /> ໄດ້ບà»?</translation>
<translation id="3303855915957856445">ບà»à»ˆàºžàº»àºšàºœàº»àº™àºàº²àº™àºŠàº­àºàº«àº²à»ƒàº”ໆ</translation>
<translation id="3304073249511302126">àºàº²àº™àºªàº°à»àºàº™ Bluetooth</translation>
<translation id="3308006649705061278">ໜ່ວàºàº‡àº²àº™àºàº²àº™àºˆàº±àº”ຕັ້ງ (OU)</translation>
@@ -729,12 +766,6 @@
<translation id="3345782426586609320">​ຕາ</translation>
<translation id="3355823806454867987">ປ່ຽນàºàº²àº™àº•àº±à»‰àº‡àº„່າພຣັອàºàºŠàºµ...</translation>
<translation id="3360103848165129075">à»àºœà»ˆàº™àº§àº½àºàº‚ອງເຄື່ອງຈັດàºàº²àº™àºàº²àº™àºŠàº³àº¥àº°à»€àº‡àº´àº™</translation>
-<translation id="3361596688432910856">Chrome <ph name="BEGIN_EMPHASIS" />ຈະບà»à»ˆàºšàº±àº™àº—ຶàº<ph name="END_EMPHASIS" /> ຂà»à»‰àº¡àº¹àº™àº•à»à»ˆà»„ປນີ້:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />ປະຫວັດàºàº²àº™àº—່ອງເວັບຂອງທ່ານ
- <ph name="LIST_ITEM" />ຄຸàºàºàºµà»‰ à»àº¥àº° ຂà»à»‰àº¡àº¹àº™à»€àº§àº±àºšà»„ຊ
- <ph name="LIST_ITEM" />ຂà»à»‰àº¡àº¹àº™àº—ີ່ປ້ອນໃສ່à»àºšàºšàºŸàº­àº¡àº•à»ˆàº²àº‡à»†
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">ນະໂàºàºšàº²àºàº™àºµà»‰àº–ືàºàºªàº³à»€àº™àº»àº²à»‚ດàºàº­àº±àº”ຕະໂນມັດຈາàºàº™àº°à»‚àºàºšàº²àº <ph name="OLD_POLICY" /> ທີ່ເຊົາຮອງຮັບà»àº¥à»‰àº§. ທ່ານຄວນໃຊ້ນະໂàºàºšàº²àºàº™àºµà»‰à»àº—ນ.</translation>
<translation id="3364869320075768271"><ph name="URL" /> ຕ້ອງàºàº²àº™à»ƒàºŠà»‰àº­àº¸àº›àº°àºàº­àº™ à»àº¥àº° ຂà»à»‰àº¡àº¹àº™à»€àº§àºµàºŠàº»àº§ ຣິອາລິຕີ</translation>
<translation id="3366477098757335611">ເບິ່ງບັດ</translation>
@@ -817,7 +848,6 @@
<translation id="3587738293690942763">ເຄິ່ງàºàº²àº‡</translation>
<translation id="3592413004129370115">Italian (ຊອງຈົດà»àº²àº)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{ທ່ານສາມາດຣີເຊັດàºàº¸à»ˆàº¡àº‚ອງທ່ານຕອນໃດàºà»à»„ດ້. ມັນໃຊ້ເວລາປະມານໜຶ່ງມື້ເພື່ອເຂົ້າຮ່ວມàºàº¸à»ˆàº¡à»ƒà»à»ˆ.}=1{ທ່ານສາມາດຣີເຊັດàºàº¸à»ˆàº¡àº‚ອງທ່ານຕອນໃດàºà»à»„ດ້. ມັນໃຊ້ເວລາປະມານໜຶ່ງມື້ເພື່ອເຂົ້າຮ່ວມàºàº¸à»ˆàº¡à»ƒà»à»ˆ.}other{ທ່ານສາມາດຣີເຊັດàºàº¸à»ˆàº¡àº‚ອງທ່ານຕອນໃດàºà»à»„ດ້. ມັນໃຊ້ເວລາປະມານ {NUM_DAYS} ມື້ເພື່ອເຂົ້າຮ່ວມàºàº¸à»ˆàº¡à»ƒà»à»ˆ.}}</translation>
-<translation id="3596012367874587041">àºàº²àº™àº•àº±à»‰àº‡àº„່າà»àº­àº±àºš</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">ຜູ້ເບິ່ງà»àºàº‡àº¥àº°àºšàº»àºšàº‚ອງທ່ານໄດ້ບລັອàºà»àº­àº±àºšàºžàº¥àº´à»€àº„ຊັນ</translation>
<translation id="3608932978122581043">ປ້ອນເຈ້àºàº•àº²àº¡àº—ິດທາງ</translation>
@@ -860,6 +890,7 @@
<translation id="370972442370243704">ເປີດໃຊ້ບັນທຶàº</translation>
<translation id="3711895659073496551">ໂຈະ</translation>
<translation id="3712624925041724820">àºàº²àº™àº­àº°â€‹àº™àº¸â€‹àºàº²àº”​ໃຊ້à»àº»àº”à»àº¥à»‰àº§</translation>
+<translation id="3714633008798122362">ປະ​ຕິ​ທິນ​ເວັບ​</translation>
<translation id="3714780639079136834">àºàº³àº¥àº±àº‡à»€àº›àºµàº”ຂà»à»‰àº¡àº¹àº™à»€àº„ືອຂ່າàºàº¡àº·àº–ື ຫຼື Wi-Fi</translation>
<translation id="3715597595485130451">​ເຊື່ອມ​ຕà»à»ˆàºàº±àºš Wi​-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />àºàº³àº¥àº±àº‡àºàº§àº”ເບິ່ງàºàº²àº™àº•àº±à»‰àº‡àº„່າພຣັອàºàºŠàºµ, ໄຟລ໌ວ໠à»àº¥àº° DNS<ph name="END_LINK" /></translation>
@@ -921,6 +952,7 @@
<translation id="3906954721959377182">à»àº—ັບເລັດ</translation>
<translation id="3909477809443608991"><ph name="URL" /> ຕ້ອງàºàº²àº™àº«àº¼àº´à»‰àº™à»€àº™àº·à»‰àº­àº«àº²àº—ີ່ມີàºàº²àº™àº›àº»àºàº›à»‰àº­àº‡à»„ວ້. ຕົວຕົນຂອງອຸປະàºàº­àº™àº‚ອງທ່ານຈະຖືàºàº¢àº±à»‰àº‡àº¢àº·àº™à»‚ດຠGoogle à»àº¥àº° ອາດຈະເຂົ້າເຖິງໄດ້ໂດàºà»€àº§àº±àºšà»„ຊນີ້.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">ປະຕິເສດ</translation>
<translation id="3939773374150895049">ໃຊ້ WebAuthn à»àº—ນ CVC ບà»?</translation>
<translation id="3946209740501886391">ຖາມໃນເວັບໄຊນີ້ທຸàºà»€àº—ື່ອ</translation>
<translation id="3947595700203588284">ສາມາດຂà»à»€àºŠàº·à»ˆàº­àº¡àº•à»à»ˆàºàº±àºšàº­àº¸àº›àº°àºàº­àº™ MIDI ໄດ້</translation>
@@ -942,6 +974,7 @@
<translation id="3990250421422698716">àºàº²àº™àºŠàº»àº”ເຊີàºàºžàº·à»‰àº™àºœàº´àº§àº—ີ່ບà»à»ˆàºªàº°à»à»à»ˆàº²àºªàº°à»€à»àºµ</translation>
<translation id="3996311196211510766">ເວັບໄຊ <ph name="ORIGIN" /> ໄດ້ຂà»à»ƒàº«à»‰àº™àº³à»ƒàºŠà»‰àº™àº°à»‚àºàºšàº²àº
ຕົ້ນທາງàºàº±àºšàº„ຳຂà»àº‚ອງມັນທັງà»àº»àº”, à»àº•à»ˆàº¥àº°àºšàº»àºšàºšà»à»ˆàºªàº²àº¡àº²àº”ນຳໃຊ້ນະໂàºàºšàº²àºàº™àºµà»‰à»„ດ້ໃນປັດຈຸບັນນີ້.</translation>
+<translation id="4009243425692662128">ເນື້ອຫາຂອງໜ້າທີ່ທ່ານພິມà»àº¡à»ˆàº™àº–ືàºàºªàº»à»ˆàº‡à»„ປໃຫ້ Google Cloud ຫຼື ພາàºàºªà»ˆàº§àº™àº—ີສາມວິເຄາະ. ຕົວຢ່າງ: ມັນອາດຖືàºàºªàº°à»àºàº™àº«àº²àº‚à»à»‰àº¡àº¹àº™àº¥àº°àº­àº½àº”ອ່ອນ.</translation>
<translation id="4010758435855888356">ອະນຸàºàº²àº”àºàº²àº™à»€àº‚ົ້າເຖິງບ່ອນຈັດເàºàº±àºšàº‚à»à»‰àº¡àº¹àº™àºšà»?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{ເອàºàº°àºªàº²àº™ PDF ທີ່ປະàºàº­àºšàº¡àºµ {COUNT} ໜ້າ}other{ເອàºàº°àºªàº²àº™ PDF ທີ່ປະàºàº­àºšàº¡àºµ {COUNT} ໜ້າ}}</translation>
<translation id="4023431997072828269">ເພາະວ່າà»àºšàºšàºŸàº­àº¡àº™àºµà»‰àºàº³àº¥àº±àº‡àº–ືàºàºªàº»à»ˆàº‡à»‚ດàºà»ƒàºŠà»‰àºàº²àº™à»€àºŠàº·à»ˆàº­àº¡àº•à»à»ˆàº—ີ່ບà»à»ˆàº›àº­àº”ໄພ, ຄົນອື່ນຈຶ່ງສາມາດເຫັນຂà»à»‰àº¡àº¹àº™àº‚ອງທ່ານໄດ້.</translation>
@@ -1036,6 +1069,7 @@
<translation id="4250680216510889253">ບà»à»ˆà»àº¡à»ˆàº™</translation>
<translation id="4253168017788158739">ບັນທຶàº</translation>
<translation id="425582637250725228">àºàº²àº™àº›à»ˆàº½àº™à»àº›àº‡àº—ີ່ທ່ານເຮັດອາດຈະບà»à»ˆàº–ືàºàºšàº±àº™àº—ຶàºà»„ວ້.</translation>
+<translation id="425869179292622354">ເຮັດໃຫ້ມັນປອດໄພàºàº´à»ˆàº‡àº‚ຶ້ນດ້ວàºàºšàº±àº”ສະເà»àº·àº­àº™àºšà»?</translation>
<translation id="4258748452823770588">ລາàºâ€‹à»€àºŠàº±àº™â€‹àºšà»à»ˆâ€‹àº”ີ</translation>
<translation id="4261046003697461417">ບà»à»ˆàºªàº²àº¡àº²àº”ຂຽນອະທິບາàºàº„à»àº²à»€àº«àº±àº™à»ƒàºªà»ˆà»€àº­àºàº°àºªàº²àº™àº—ີ່ໄດ້ຮັບàºàº²àº™àº›àº»àºàº›à»‰àº­àº‡à»„ດ້</translation>
<translation id="4265872034478892965">ອະນຸàºàº²àº”ໂດàºàºœàº¹à»‰à»€àºšàº´à»ˆàº‡à»àºàº‡àº¥àº°àºšàº»àºšàº‚ອງທ່ານ</translation>
@@ -1098,6 +1132,7 @@
<translation id="4434045419905280838">ປັອບອັບ à»àº¥àº° àºàº²àº™àº›à»ˆàº½àº™à»€àºªàº±à»‰àº™àº—າງ</translation>
<translation id="4435702339979719576">ໂພສàºàº²àº”)</translation>
<translation id="443673843213245140">àºàº²àº™à»ƒàºŠà»‰àºžàº£àº±àº­àºàºŠàºµàº›àº´àº”ໃຊ້ງານà»àº¥à»‰àº§ à»àº•à»ˆàºàº²àº™àº›àº±àºšàº•àº±à»‰àº‡àºžàº£àº±àº­àºàºŠàºµàºˆàº°à»àºˆà»‰àº‡à»„ດ້ຮັບàºàº²àº™àº¥àº°àºšàº¸.</translation>
+<translation id="4441832193888514600">ຖືàºà»€àºžàºµàºà»€àºªàºµàºà»€àº™àº·à»ˆàº­àº‡àºˆàº²àºàºªàº²àº¡àº²àº”ຕັ້ງນະໂàºàºšàº²àºà»€àº›àº±àº™àº™àº°à»‚àºàºšàº²àºàºœàº¹à»‰à»ƒàºŠà»‰àº„ລາວເທົ່ານັ້ນ.</translation>
<translation id="4450893287417543264">ຢ່າສະà»àº”ງອີàº</translation>
<translation id="4451135742916150903">ສາມາດຂà»à»€àºŠàº·à»ˆàº­àº¡àº•à»à»ˆàº«àº²àº­àº¸àº›àº°àºàº­àº™ HID ໄດ້</translation>
<translation id="4452328064229197696">ພົບລະຫັດຜ່ານທີ່ທ່ານຫາàºà»à»ƒàºŠà»‰àº™àº±à»‰àº™à»ƒàº™àºàº²àº™àº®àº»à»ˆàº§à»„ຫຼຂà»à»‰àº¡àº¹àº™. ເພື່ອຮັàºàºªàº²àº„ວາມປອດໄພໃຫ້ບັນຊີຂອງທ່ານ, ຕົວຈັດàºàº²àº™àº¥àº°àº«àº±àº”ຜ່ານ Google à»àº™àº°àº™àº³à»ƒàº«à»‰àºàº§àº”ສອບລະຫັດຜ່ານທີ່ບັນທຶàºà»„ວ້ຂອງທ່ານ.</translation>
@@ -1153,6 +1188,7 @@
<translation id="4628948037717959914">ຮູບຖ່າàº</translation>
<translation id="4631649115723685955">ເຊື່ອມໂàºàº‡à»€àº‡àº´àº™àº„ືນà»àº¥à»‰àº§</translation>
<translation id="4636930964841734540">ຂà»à»‰â€‹àº¡àº¹àº™</translation>
+<translation id="4638670630777875591">ໂà»àº”ບà»à»ˆà»€àº›àºµàº”ເຜີàºàº•àº»àº§àº•àº»àº™à»ƒàº™ Chromium</translation>
<translation id="464342062220857295">ຄຸນສົມບັດàºàº²àº™àºŠàº­àºàº«àº²</translation>
<translation id="4644670975240021822">ລຳດັບàºà»‰àº­àº™àºàº±àºšàº‚ວ້າມໜ້າລົງ</translation>
<translation id="4646534391647090355">ນຳຂ້ອàºà»„ປທີ່ນັ້ນຕອນນີ້ເລີàº</translation>
@@ -1173,6 +1209,7 @@
<translation id="4708268264240856090">àºàº²àº™à»€àºŠàº·à»ˆàº­àº¡àº•à»à»ˆàº‚ອງທ່ານຖືàºàº‚ັດຈັງຫວະ</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />àºàº³àº¥àº±àº‡à»€àº›àºµàº”ໃຊ້ Windows Network Diagnostics<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426">ລະຫັດຜ່ານສຳລັບ <ph name="USERNAME" /></translation>
<translation id="4724144314178270921">ສາມາດຂà»à»€àºšàº´à»ˆàº‡àº‚à»à»‰àº„ວາມ à»àº¥àº° ຮູບຢູ່ຄລິບບອດຂອງທ່ານ</translation>
<translation id="4726672564094551039">ໂຫຼດນະ​ໂàºâ€‹àºšàº²àºàº„ືນໃà»à»ˆ</translation>
<translation id="4728558894243024398">ເວທີ</translation>
@@ -1194,6 +1231,7 @@
<translation id="4757993714154412917">ທ່ານຫາàºà»àº›à»‰àº­àº™àº¥àº°àº«àº±àº”ຜ່ານຂອງທ່ານໃສ່ເວັບໄຊຫຼອàºàº¥àº§àº‡. ເພື່ອຮັàºàºªàº²àº„ວາມປອດໄພບັນຊີຂອງທ່ານ, Chromium à»àº™àº°àº™àº³à»ƒàº«à»‰àºàº§àº”ສອບລະຫັດຜ່ານທີ່ທ່ານບັນທຶàºà»„ວ້.</translation>
<translation id="4758311279753947758">ເພີ່ມຂà»à»‰àº¡àº¹àº™àº•àº´àº”ຕà»à»ˆ</translation>
<translation id="4761104368405085019">ໃຊ້ໄມໂຄຣໂຟນຂອງທ່ານ</translation>
+<translation id="4761869838909035636">ເປີດໃຊ້àºàº²àº™àºàº§àº”ສອບຄວາມປອດໄພ Chrome</translation>
<translation id="4764776831041365478">ໜ້າເວັບຢູ່ທີ່ <ph name="URL" /> ອາດຈະໃຊ້ບà»à»ˆà»„ດ້ຊົ່ວຄາວ ຫຼືມັນອາດຈະໄດ້àºà»‰àº²àºàº­àº­àºà»„ປໃສ່ທີ່ຢູ່ເວັບໃà»à»ˆàº–າວອນà»àº¥à»‰àº§.</translation>
<translation id="4766713847338118463">ໜີບàºàº°àº«àº¼àº±àºšà»€àºŸàºµàº¢àº¹à»ˆàº¥àº¸à»ˆàº¡àºªàº¸àº”ສອງເທື່ອ</translation>
<translation id="4771973620359291008">ເàºàºµàº”ຄວາມຜິດພາດທີ່ບà»à»ˆàº®àº¹à»‰àºˆàº±àº.</translation>
@@ -1214,12 +1252,6 @@
<translation id="4819347708020428563">à»àºà»‰à»„ຂຄຳອະທິບາàºàº„ວາມເຫັນໃນມຸມມອງເລີ່ມຕົ້ນບà»?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />, àºàº»àº” Tab ຈາàºàº™àº±à»‰àº™àºàº»àº” Enter ເພື່ອສ້າງ Google Sheet ໃà»à»ˆà»„ດ້ຢ່າງວ່ອງໄວ</translation>
<translation id="4825507807291741242">ຊົງພະລັງ</translation>
-<translation id="4827402517081186284">ໂà»àº”ບà»à»ˆà»€àº›àºµàº”ເຜີàºàº•àº»àº§àº•àº»àº™àºšà»à»ˆà»„ດ້ເຮັດໃຫ້ທ່ານຫາàºàº•àº»àº§à»„ດ້ໃນເວລາອອນລາàº:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />ເວັບໄຊຕ່າງໆຮູ້ວ່າທ່ານເຂົ້າເບິ່ງຕອນໃດ<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />ນາàºàºˆà»‰àº²àº‡ ຫຼື ໂຮງຮຽນສາມາດຕິດຕາມàºàº²àº™à»€àº„ື່ອນໄຫວàºàº²àº™àº—່ອງເວັບໄດ້<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />ຜູ້ໃຫ້ບà»àº¥àº´àºàº²àº™àº­àº´àº™à»€àº•àºµà»€àº™àº±àº”ອາດຕິດຕາມທຣາບຟິàºà»€àº§àº±àºšà»„ດ້<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">ເປີດໃຊ້ຄຳເຕືອນ</translation>
<translation id="4838327282952368871">ຊວນàºàº±àº™</translation>
<translation id="4840250757394056958">ເບິ່ງປະຫວັດ Chrome ຂອງທ່ານ</translation>
@@ -1231,12 +1263,12 @@
<translation id="4854362297993841467">ວິທີàºàº²àº™àºªàº»à»ˆàº‡àº™àºµà»‰àºšà»à»ˆàºªàº²àº¡àº²àº”ໃຊ້ໄດ້. ລອງວິທີອື່ນ.</translation>
<translation id="4854853140771946034">ສ້າງບັນທຶàºà»ƒà»à»ˆà»ƒàº™ Google Keep ໄດ້ຢ່າງງ່າàºàº”າàº</translation>
<translation id="485902285759009870">àºàº³àº¥àº±àº‡àº¢àº±à»‰àº‡àº¢àº·àº™àº¥àº°àº«àº±àº”...</translation>
+<translation id="4866506163384898554">àºàº»àº” |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| ເພື່ອສະà»àº”ງເຄີເຊີຂອງທ່ານ</translation>
<translation id="4876188919622883022">ມຸມມອງງ່າàºàº”າàº</translation>
<translation id="4876305945144899064">ບà»à»ˆàº¡àºµàºŠàº·à»ˆàºœàº¹à»‰à»ƒàºŠà»‰</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{ບà»à»ˆàº¡àºµ}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831">ຊອàºàº«àº² <ph name="TEXT" /></translation>
<translation id="4879491255372875719">ອັດຕະໂນມັດ (ຄ່າເລີ່ມຕົ້ນ)</translation>
-<translation id="4879725228911483934">ເປີດ à»àº¥àº° ວາງໜ້າຈà»à»„ວ້ໃສ່ໃນໜ້າຈà»àº‚ອງທ່ານ</translation>
<translation id="4880827082731008257">ຄົ້ນຫາປະຫວັດ</translation>
<translation id="4881695831933465202">ເປີດ</translation>
<translation id="4885256590493466218">ຈ່າàºàº”້ວຠ<ph name="CARD_DETAIL" /> ຢູ່ຈຸດຈ່າàºà»€àº‡àº´àº™</translation>
@@ -1245,6 +1277,7 @@
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">ມ້ວນທີເàºàº»à»‰àº²</translation>
<translation id="4901778704868714008">ບັນທຶàº...</translation>
+<translation id="4905659621780993806">ຜູ້ເບິ່ງà»àºàº‡àº¥àº°àºšàº»àºšàº‚ອງທ່ານຈະຣີສະຕາດອຸປະàºàº­àº™àº‚ອງທ່ານໂດàºàº­àº±àº”ຕະໂນມັດເວລາ <ph name="TIME" /> ໃນ <ph name="DATE" />. àºàº°àº¥àº¸àº™àº²àºšàº±àº™àº—ຶàºàº¥àº²àºàºàº²àº™àº—ີ່ເປີດໄວ້àºà»ˆàº­àº™àº­àº¸àº›àº°àºàº­àº™àº‚ອງທ່ານຈະຣີສະຕາດ.</translation>
<translation id="4913987521957242411">ເຈາະຮູຢູ່ເທິງສຸດເບື້ອງຊ້າàº</translation>
<translation id="4918221908152712722">ຕິດຕັ້ງ <ph name="APP_NAME" /> (ບà»à»ˆàºˆà»àº²à»€àº›àº±àº™àº•à»‰àº­àº‡àº”າວໂຫຼດ)</translation>
<translation id="4923459931733593730">àºàº²àº™àºˆà»ˆàº²àºà»€àº‡àº´àº™</translation>
@@ -1253,6 +1286,7 @@
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, àºàº»àº” Tab ຈາàºàº™àº±à»‰àº™ Enter ເພື່ອຊອàºàº«àº²</translation>
<translation id="4930153903256238152">ຄວາມຈຸຫຼາàº</translation>
+<translation id="4940163644868678279">ໂà»àº”ບà»à»ˆà»€àº›àºµàº”ເຜີàºàº•àº»àº§àº•àº»àº™à»ƒàº™ Chrome</translation>
<translation id="4943872375798546930">ບà»à»ˆâ€‹àº¡àºµâ€‹àºœàº»àº™â€‹à»„ດ້​ຮັບ</translation>
<translation id="4950898438188848926">à»àº•àº°àº›àº¸à»ˆàº¡àºªàº°àº«àº¼àº±àºš, àºàº»àº” Enter ເພື່ອປ່ຽນເປັນà»àº–ບທີ່ເປີດຢູ່, <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="495170559598752135">àºàº²àº™àºàº°àº—à»àº²</translation>
@@ -1262,6 +1296,7 @@
<translation id="4968522289500246572">à»àº­àº±àºšàº™àºµà»‰àº–ືàºàº­àº­àºà»àºšàºšàº¡àº²àºªàº³àº¥àº±àºšàº¡àº·àº–ື à»àº¥àº° ອາດບà»à»ˆàºªàº²àº¡àº²àº”ປັບຂະໜາດໄດ້ດີ. à»àº­àº±àºšàº­àº²àº”ປະສົບບັນຫາ ຫຼື ຣີສະຕາດໄດ້.</translation>
<translation id="4969341057194253438">ລຶບàºàº²àº™àºšàº±àº™àº—ຶàºàº­àº­àº</translation>
<translation id="4973922308112707173">ເຈາະຮູຢູ່ເທິງສຸດສອງຮູ</translation>
+<translation id="4976702386844183910">ເຂົ້າເບິ່ງຫຼ້າສຸດ <ph name="DATE" /></translation>
<translation id="4984088539114770594">ໃຊ້ໄມໂຄຣໂຟນບ�</translation>
<translation id="4984339528288761049">Prc5 (ຊອງຈົດà»àº²àº)</translation>
<translation id="4989163558385430922">ເບິ່ງທັງà»àº»àº”</translation>
@@ -1323,6 +1358,7 @@
<translation id="5138227688689900538">ຫàºà»à»‰àº¥àº»àº‡</translation>
<translation id="5145883236150621069">ລະຫັດຄວາມຜິດພາດມີຢູ່ໃນàºàº²àº™àº•àº­àºšàº®àº±àºšàº™àº°à»‚àºàºšàº²àº</translation>
<translation id="5146995429444047494">àºàº²àº™à»àºˆà»‰àº‡à»€àº•àº·àº­àº™àºªàº³àº¥àº±àºš <ph name="ORIGIN" /> ຖືàºàºšàº¥àº±àº­àºà»„ວ້</translation>
+<translation id="514704532284964975"><ph name="URL" /> ຕ້ອງàºàº²àº™à»€àºšàº´à»ˆàº‡ à»àº¥àº° ປ່ຽນຂà»à»‰àº¡àº¹àº™àº¢àº¹à»ˆàº­àº¸àº›àº°àºàº­àº™ NFC ທີ່ທ່ານà»àº•àº°àº”້ວàºà»‚ທລະສັບຂອງທ່ານ</translation>
<translation id="5148809049217731050">ປີ້ນໜ້າຂຶ້ນ</translation>
<translation id="515292512908731282">C4 (ຊອງຈົດà»àº²àº)</translation>
<translation id="5158275234811857234">ໜ້າປົàº</translation>
@@ -1347,6 +1383,7 @@
<translation id="5215116848420601511">ວິທີàºàº²àº™àºˆà»ˆàº²àºà»€àº‡àº´àº™ à»àº¥àº° ທີ່ຢູ່ທີ່ໃຊ້ Google Pay</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">ຖາດ 13</translation>
+<translation id="5216942107514965959">ເຂົ້າເບິ່ງມື້ນີ້</translation>
<translation id="5222812217790122047">ຈຳເປັນຕ້ອງມີອີເມວ</translation>
<translation id="5230733896359313003">ທີ່ຢູ່ຈັດສົ່ງ</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1367,7 +1404,6 @@
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">ຄຸນລັàºàºªàº°àº™àº°àº‚ອງເອàºàº°àºªàº²àº™</translation>
<translation id="528468243742722775">ສິ້ນສຸດ</translation>
-<translation id="5284909709419567258">ທີ່ຢູ່ເຄືອຂ່າàº</translation>
<translation id="5285570108065881030">ສະà»àº”ງລະຫັດຜ່ານທີ່ບັນທຶàºà»„ວ້ທັງà»àº»àº”</translation>
<translation id="5287240709317226393">ສະà»àº”ງຄຸàºàºàºµà»‰</translation>
<translation id="5287456746628258573">ເວັບໄຊນີ້ໃຊ້àºàº²àº™àºàº³àº™àº»àº”ຄ່າຄວາມປອດໄພທີ່ເàºàº»à»ˆàº²à»àº¥à»‰àº§, ເຊິ່ງອາດຈະເຮັດໃຫ້ຂà»à»‰àº¡àº¹àº™àº‚ອງທ່ານມີຄວາມສ່ຽງ (ຕົວຢ່າງ: ລະຫັດຜ່ານ ຫຼື ເລàºàºšàº±àº”ເຄຣດິດ) ເມື່ອມັນຖືàºàºªàº»à»ˆàº‡à»ƒàº«à»‰à»€àº§àº±àºšà»„ຊນີ້.</translation>
@@ -1451,6 +1487,7 @@
<translation id="5556459405103347317">ໂຫຼດຄືນໃà»à»ˆ</translation>
<translation id="5560088892362098740">ວັນທີà»àº»àº”ອາàºàº¸</translation>
<translation id="55635442646131152">ໂຄງຮ່າງເອàºàº°àºªàº²àº™</translation>
+<translation id="5565613213060953222">ເປີດà»àº–ບ​ບà»à»ˆà»€àº›àºµàº”ເຜີàºàº•àº»àº§àº•àº»àº™</translation>
<translation id="5565735124758917034">ເປີດຢູ່</translation>
<translation id="5570825185877910964">ປົàºàº›à»‰àº­àº‡àºšàº±àº™àºŠàºµ</translation>
<translation id="5571083550517324815">ບà»à»ˆàºªàº²àº¡àº²àº”ຮັບເອົາເຄື່ອງຈາàºàº—ີ່ຢູ່ນີ້ໄດ້. ເລືອàºàº—ີ່ຢູ່ອື່ນ.</translation>
@@ -1533,6 +1570,7 @@
<translation id="5869522115854928033">ລະ​ຫັດ​ຜ່ານ​ທີ່ບັນທຶàºà»„ວ້</translation>
<translation id="5873013647450402046">ທະນາຄານຂອງທ່ານຕ້ອງàºàº²àº™àº¢àº·àº™àº¢àº±àº™àº§à»ˆàº²à»àº¡à»ˆàº™àº—່ານà»àº—້.</translation>
<translation id="5887400589839399685">ບັນທຶàºàºšàº±àº”ໄວ້à»àº¥à»‰àº§</translation>
+<translation id="5887687176710214216">ເຂົ້າເບິ່ງຫຼ້າສຸດມື້ວານນີ້</translation>
<translation id="5895138241574237353">ເລີ່ມຕົ້ນໃà»à»ˆ</translation>
<translation id="5895187275912066135">ອອàºà»ƒàº«à»‰</translation>
<translation id="5901630391730855834">ສີ​ເຫຼືອງ</translation>
@@ -1546,6 +1584,7 @@
<translation id="5921639886840618607">ບັນທຶàºàºšàº±àº”ໄວ້ໃນບັນຊີ Google ບà»?</translation>
<translation id="5922853866070715753">ເàºàº·àº­àºšàºªàº³à»€àº¥àº±àº”à»àº¥à»‰àº§</translation>
<translation id="5932224571077948991">ເວັບໄຊສະà»àº”ງໂຄສະນາທີ່ລົບàºàº§àº™ ຫຼື ຫຼອàºàº¥àº§àº‡</translation>
+<translation id="5938153366081463283">ເພີ່ມບັດສະເà»àº·àº­àº™</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347">àºàº³àº¥àº±àº‡à»€àº›àºµàº” <ph name="SITE_NAME" />…</translation>
<translation id="5951495562196540101">ບà»à»ˆàºªàº²àº¡àº²àº”ລົງທະບຽນດ້ວàºàºšàº±àº™àºŠàºµàºœàº¹à»‰àºŠàº»àº¡à»ƒàºŠà»‰à»„ດ້ (ມີໃບອະນຸàºàº²àº”à»àºšàºšà»àºžàº±àºà»€àºàº”).</translation>
@@ -1610,6 +1649,7 @@
<translation id="6120179357481664955">ຈື່ UPI ID ຂອງທ່ານໄວ້ບ�</translation>
<translation id="6124432979022149706">ເຄື່ອງມືເຊື່ອມຕà»à»ˆ Chrome Enterprise</translation>
<translation id="6127379762771434464">ລຶບລາàºàºàº²àº™àº­àº­àºà»àº¥à»‰àº§</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />ສຶàºàºªàº²à»€àºžàºµà»ˆàº¡à»€àº•àºµàº¡àºà»ˆàº½àº§àºàº±àºšà»‚à»àº”ບà»à»ˆà»€àº›àºµàº”ເຜີàºàº•àº»àº§àº•àº»àº™à»ƒàº™ Chrome<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">àºàº§àº”ເບິ່ງສາàºà»„ຟ à»àº¥àº°àº›àº´àº”ເປີດເຣົາເຕີ, ໂມເດັມ, ຫຼືອຸປະàºàº­àº™à»€àº„ືອຂ່າàº
ທີ່ທ່ານອາດàºàº³àº¥àº±àº‡à»ƒàºŠà»‰àº¢àº¹à»ˆàº„ືນໃà»à»ˆ.</translation>
<translation id="614940544461990577">ລອງ:</translation>
@@ -1622,7 +1662,6 @@
<translation id="6169916984152623906">ຕອນນີ້ທ່ານສາມາດທ່ອງເວັບà»àºšàºšàºªà»ˆàº§àº™àº•àº»àº§à»„ດ້à»àº¥à»‰àº§ à»àº¥àº° ຄົນອື່ນທີ່ໃຊ້ອຸປະàºàº­àº™àº™àºµà»‰àºˆàº°àºšà»à»ˆà»€àº«àº±àº™àºàº²àº™à»€àº„ື່ອນໄຫວຂອງທ່ານ. à»àº™àº§à»ƒàº”àºà»àº•àº²àº¡, àºàº²àº™àº”າວໂຫຼດ à»àº¥àº° ບຸàºàº¡àº²àºàºˆàº°àº–ືàºàºšàº±àº™àº—ຶàºà»„ວ້.</translation>
<translation id="6177128806592000436">àºàº²àº™à»€àºŠàº·à»ˆàº­àº¡àº•à»à»ˆàº‚ອງທ່ານàºàº±àºšà»€àº§àº±àºšà»„ຊນີ້ບà»à»ˆàº›àº­àº”ໄພ</translation>
<translation id="6180316780098470077">ຊ່ວງຫ່າງລະຫວ່າງàºàº²àº™àº¥àº­àº‡à»ƒà»à»ˆà»àº•à»ˆàº¥àº°àº„ັ້ງ</translation>
-<translation id="619448280891863779">ສາມາດຈà»à»€àº›àºµàº” à»àº¥àº° ວາງໜ້າຈà»àº•à»ˆàº²àº‡à»†àº¢àº¹à»ˆà»œà»‰àº²àºˆà»àº‚ອງທ່ານໄດ້</translation>
<translation id="6196640612572343990">ບລັອàºàº„ຸàºàºàºµà»‰àºžàº²àºàºªà»ˆàº§àº™àº—ີສາມ</translation>
<translation id="6203231073485539293">àºàº§àº”ເບິ່ງàºàº²àº™à»€àºŠàº·à»ˆàº­àº¡àº•à»à»ˆàº­àº´àº™à»€àº•àºµà»€àº™àº±àº”ຂອງທ່ານ.</translation>
<translation id="6218753634732582820">ເອົາ​ທີ່​ຢູ່​ອອàºâ€‹â€‹àºˆàº²àº Chromium ບà»?</translation>
@@ -1645,7 +1684,7 @@
<translation id="6272383483618007430">Google Update</translation>
<translation id="6276112860590028508">ໜ້າຈາàºàº¥àº²àºàºàº²àº™àº—ີ່ຈະອ່ານຂອງທ່ານປາàºàº»àº”ຢູ່ບ່ອນນີ້</translation>
<translation id="627746635834430766">ເພື່ອຈ່າàºà»„ດ້ໄວàºàº§à»ˆàº²à»ƒàº™àº„ັ້ງຕà»à»ˆà»„ປ, àºàº°àº¥àº¸àº™àº²àºšàº±àº™àº—ຶàºàºšàº±àº” à»àº¥àº° ທີ່ຢູ່ຮຽàºà»€àºàº±àºšà»€àº‡àº´àº™àº‚ອງທ່ານໄວ້ໃນບັນຊີ Google ຂອງທ່ານ.</translation>
-<translation id="6279098320682980337">ບà»à»ˆà»„ດ້ໃສ່à»àº²àºà»€àº¥àºàºšàº±àº”ສະເà»àº·àº­àº™àºšà»? àºàº°àº¥àº¸àº™àº²àº„ລິàºàº¥àº²àºàº¥àº°àº­àº½àº”ບັດເພື່ອສຳເນົາ</translation>
+<translation id="6279183038361895380">àºàº»àº” |<ph name="ACCELERATOR" />| ເພື່ອສະà»àº”ງເຄີເຊີຂອງທ່ານ</translation>
<translation id="6280223929691119688">ບà»à»ˆàºªàº²àº¡àº²àº”ສົ່ງຫາທີ່ຢູ່ນີ້ໄດ້. àºàº°àº¥àº¸àº™àº²à»€àº¥àº·àº­àºàº—ີ່ຢູ່ອື່ນ.</translation>
<translation id="6282194474023008486">ລະຫັດໄປສະນີ</translation>
<translation id="6285507000506177184">ປຸ່ມຈັດàºàº²àº™àºàº²àº™àº”າວໂຫຼດໃນ Chrome, àºàº»àº” Enter ເພື່ອຈັດàºàº²àº™à»„ຟລ໌ທີ່ທ່ານດາວໂຫຼດມາà»àº¥à»‰àº§à»ƒàº™ Chrome</translation>
@@ -1653,6 +1692,7 @@
<translation id="6290238015253830360">ບົດຄວາມທີ່à»àº™àº°àº™àº³àº‚ອງທ່ານຈະປາàºàº»àº”ຢູ່ບ່ອນນີ້</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{ຕອນນີ້ຈະຣີສະຕາດອຸປະàºàº­àº™àº‚ອງທ່ານà»àº¥à»‰àº§}=1{ອຸປະàºàº­àº™àº‚ອງທ່ານຈະຣີສະຕາດໃນ 1 ວິນາທີ}other{ອຸປະàºàº­àº™àº‚ອງທ່ານຈະຣີສະຕາດໃນ # ວິນາທີ}}</translation>
<translation id="6302269476990306341">àºàº³àº¥àº±àº‡àº¢àº¸àº”ຜູ້ຊ່ວຠGoogle ໃນ Chrome</translation>
<translation id="6305205051461490394"><ph name="URL" /> ບà»à»ˆàºªàº²àº¡àº²àº”ເຂົ້າເຖິງໄດ້</translation>
<translation id="6312113039770857350">ບà»à»ˆâ€‹àº¡àºµâ€‹à»œà»‰àº²â€‹à»€àº§àº±àºšâ€‹àº¢àº¹à»ˆ</translation>
@@ -1726,6 +1766,7 @@
<translation id="6529602333819889595">ເຮັດຄືນຄà»àº²àºªàº±à»ˆàº‡àº¥àº¶àºš</translation>
<translation id="6545864417968258051">àºàº²àº™àºªàº°à»àºàº™ Bluetooth</translation>
<translation id="6547208576736763147">ເຈາະຮູເບື້ອງຊ້າàºàºªàº­àº‡àº®àº¹</translation>
+<translation id="6554732001434021288">ເຂົ້າເບິ່ງຫຼ້າສຸດ <ph name="NUM_DAYS" /> ມື້àºà»ˆàº­àº™</translation>
<translation id="6556866813142980365">ເຮັດຄືນ</translation>
<translation id="6569060085658103619">ທ່ານàºàº³àº¥àº±àº‡à»€àºšàº´à»ˆàº‡à»œà»‰àº²àºªà»ˆàº§àº™àº‚ະຫàºàº²àº</translation>
<translation id="6573200754375280815">ເຈາະຮູຢູ່ເບື້ອງຂວາສອງຮູ</translation>
@@ -1786,7 +1827,6 @@
<translation id="6757797048963528358">ອຸປະàºàº­àº™àº‚ອງທ່ານໄດ້ເຂົ້າສູ່ໂà»àº”ນອນຫຼັບà»àº¥à»‰àº§.</translation>
<translation id="6767985426384634228">ອັບເດດທີ່ຢູ່ບ�</translation>
<translation id="6768213884286397650">Hagaki (ໂພສàºàº²àº”)</translation>
-<translation id="6774185088257932239"><ph name="BEGIN_LINK" />ສຶàºàºªàº²à»€àºžàºµà»ˆàº¡à»€àº•àºµàº¡<ph name="END_LINK" /> àºà»ˆàº½àº§àºàº±àºšà»‚à»àº”ບà»à»ˆà»€àº›àºµàº”ເຜີàºàº•àº»àº§àº•àº»àº™</translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">ສີມ່ວງ</translation>
<translation id="6786747875388722282">ສ່ວນຂະຫàºàº²àº</translation>
@@ -1870,7 +1910,6 @@
<translation id="706295145388601875">ເພີ່ມ à»àº¥àº° ຈັດàºàº²àº™àº—ີ່ຢູ່ໃນàºàº²àº™àº•àº±à»‰àº‡àº„່າ Chrome</translation>
<translation id="7064851114919012435">ຂà»à»‰â€‹àº¡àº¹àº™â€‹àº•àº´àº”​ຕà»à»ˆ</translation>
<translation id="7068733155164172741">ລະບຸລະຫັດ <ph name="OTP_LENGTH" /> ຕົວເລàº</translation>
-<translation id="7070090581017165256">àºà»ˆàº½àº§àºàº±àºšà»€àº§àº±àºšà»„ຊນີ້</translation>
<translation id="70705239631109039">àºàº²àº™à»€àºŠàº·à»ˆàº­àº¡àº•à»à»ˆàº‚ອງທ່ານບà»à»ˆàº›àº­àº”ໄພຢ່າງສົມບູນ</translation>
<translation id="7075452647191940183">ຄຳຂà»à»ƒàº«àºà»ˆà»€àºàºµàº™à»„ປ</translation>
<translation id="7079718277001814089">ເວັບໄຊນີ້ປະàºàº­àºšàº¡àºµàº¡àº²àº¥à»àº§</translation>
@@ -1887,6 +1926,12 @@
<translation id="7111012039238467737">(ໃຊ້ໄດ້)</translation>
<translation id="7118618213916969306">ຊອàºàº«àº² URL ຄລິບບອດ, <ph name="SHORT_URL" /></translation>
<translation id="7119414471315195487">ປິດà»àº–ບ ຫຼື ໂປຣà»àºàº£àº¡àº­àº·à»ˆàº™</translation>
+<translation id="7129355289156517987">ເມື່ອທ່ານປິດà»àº–ບ​ບà»à»ˆà»€àº›àºµàº”ເຜີàºàº•àº»àº§àº•àº»àº™ Chromium ທັງà»àº»àº”ໄວ້à»àº¥à»‰àº§, àºàº²àº™à»€àº„ື່ອນໄຫວຂອງທ່ານໃນà»àº–ບເຫຼົ່ານັ້ນຈະຖືàºàº¥àº¶àºšàº¥à»‰àº²àº‡àº­àº­àºàºˆàº²àºàº­àº¸àº›àº°àºàº­àº™àº™àºµà»‰:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />àºàº²àº™à»€àº„ື່ອນໄຫວàºàº²àº™àº—່ອງເວັບ<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ປະ​ຫວັດ​àºàº²àº™â€‹àºŠàº­àºàº«àº²<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ຂà»à»‰àº¡àº¹àº™àº—ີ່ລະບຸໄວ້ໃນà»àºšàºšàºŸàº­àº¡àº•à»ˆàº²àº‡à»†<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">ບà»à»ˆàºªàº²àº¡àº²àº”ຈັດສົ່ງຫາທີ່ຢູ່ນີ້ໄດ້. àºàº°àº¥àº¸àº™àº²à»€àº¥àº·àº­àºàº—ີ່ຢູ່ອື່ນ.</translation>
<translation id="7132939140423847331">ຜູ້ເບິ່ງà»àºàº‡àº‚ອງທ່ານຫ້າມບà»à»ˆà»ƒàº«à»‰àºªàº³à»€àº™àº»àº²àº‚à»à»‰àº¡àº¹àº™àº™àºµà»‰.</translation>
<translation id="7135130955892390533">ສະà»àº”ງສະຖານະ</translation>
@@ -1909,6 +1954,7 @@
<translation id="7192203810768312527">ຂະຫàºàº²àº <ph name="SIZE" />. ບາງເວັບໄຊອາດຈະໂຫຼດຊ້າàºàº§à»ˆàº²à»ƒàº™àº„ັ້ງຕà»à»ˆà»„ປທີ່ທ່ານເຂົ້າເບິ່ງ.</translation>
<translation id="719464814642662924">ວີ​ຊາ</translation>
<translation id="7201591969684833065">ຜູ້ເບິ່ງà»àºàº‡àº¥àº°àºšàº»àºšàº‚ອງທ່ານສາມາດເຫັນ:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, àºàº»àº” Tab ຈາàºàº™àº±à»‰àº™ Enter ເພື່ອເປີດà»àº–ບທີ່ບà»à»ˆà»€àº›àºµàº”ເຜີàºàº•àº»àº§àº•àº»àº™à»ƒà»à»ˆà»€àºžàº·à»ˆàº­àºŠàº­àºàº«àº²à»àºšàºšàºªà»ˆàº§àº™àº•àº»àº§</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> ບà»à»ˆàº›àº°àº•àº´àºšàº±àº”ຕາມມາດຕະຖານຄວາມປອດໄພ.</translation>
<translation id="7210993021468939304">àºàº²àº™à»€àº„ື່ອນໄຫວ Linux ພາàºà»ƒàº™àºà»ˆàº­àº‡àºšàº±àº™àºˆàº¸ à»àº¥àº° ສາມາດຕິດຕັ້ງ à»àº¥àº° ເປີດໃຊ້à»àº­àº±àºš Linux ພາàºà»ƒàº™àºà»ˆàº­àº‡àºšàº±àº™àºˆàº¸à»„ດ້</translation>
@@ -1940,6 +1986,7 @@
<translation id="7304562222803846232">ຈັດàºàº²àº™àºàº²àº™àº•àº±à»‰àº‡àº„່າຄວາມເປັນສ່ວນຕົວບັນຊີ Google</translation>
<translation id="7305756307268530424">ເລີ່ມຊ້າລົງ</translation>
<translation id="7308436126008021607">àºàº²àº™àºŠàº´à»‰àº‡àº‚à»à»‰àº¡àº¹àº™à»ƒàº™àºžàº·à»‰àº™àº«àº¼àº±àº‡</translation>
+<translation id="7310392214323165548">ອຸປະàºàº­àº™àºˆàº°àº£àºµàºªàº°àº•àº²àº”ໃນອີàºàºšà»à»ˆàº”ົນນີ້</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">ຄວາມຊ່ວàºà»€àº«àº¼àº·àº­àºà»ˆàº½àº§àºàº±àºšàºàº²àº™à»€àºŠàº·à»ˆàº­àº¡àº•à»à»ˆ</translation>
<translation id="7323804146520582233">ເຊື່ອງຂà»à»‰ "<ph name="SECTION" />"</translation>
@@ -1947,6 +1994,7 @@
<translation id="7334320624316649418">ເຮັດຄືນຄà»àº²àºªàº±à»ˆàº‡àºˆàº±àº”ລà»àº²àº”ັບຄືນ</translation>
<translation id="7335157162773372339">ສາມາດຂà»à»ƒàºŠà»‰àºà»‰àº­àº‡àº–່າàºàº®àº¹àºšàº‚ອງທ່ານ</translation>
<translation id="7337248890521463931">ສະà»àº”ງà»àº–ວເພີ່ມເຕີມ</translation>
+<translation id="7337418456231055214">ບà»à»ˆà»„ດ້ໃສ່à»àº²àºà»€àº¥àºàºšàº±àº”ສະເà»àº·àº­àº™àºšà»? àºàº°àº¥àº¸àº™àº²àº„ລິàºàº¥àº²àºàº¥àº°àº­àº½àº”ບັດເພື່ອສຳເນົາ. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">ບà»à»ˆàºªàº²àº¡àº²àº”ໃຊ້ໄດ້ໃນà»àºžàº¥àº±àº”ຟອມຂອງທ່ານ.</translation>
<translation id="733923710415886693">ໃບຢັ້ງຢືນຂອງເຊີບເວີບà»à»ˆàº–ືàºà»€àº›àºµàº”ເຜີàºàºœà»ˆàº²àº™àº™àº°à»‚àºàºšàº²àºàº„ວາມໂປ່ງໃສຂອງໃບຢັ້ງຢືນ.</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1969,6 +2017,7 @@
<translation id="7378627244592794276">ບà»à»ˆà»àº¡à»ˆàº™</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">ບà»à»ˆàºà»ˆàº½àº§àº‚້ອງ</translation>
+<translation id="7388594495505979117">{0,plural, =1{ອຸປະàºàº­àº™àº‚ອງທ່ານຈະຣີສະຕາດໃນ 1 ນາທີ}other{ອຸປະàºàº­àº™àº‚ອງທ່ານຈະຣີສະຕາດໃນ # ນາທີ}}</translation>
<translation id="7390545607259442187">ຢືນຢັນບັດ</translation>
<translation id="7392089738299859607">ອັບເດດທີ່ຢູ່</translation>
<translation id="7399802613464275309">àºàº§àº”ສອບຄວາມປອດໄພ</translation>
@@ -2005,6 +2054,12 @@
<translation id="7485870689360869515">ບà»à»ˆàºžàº»àºšàº‚à»à»‰â€‹àº¡àº¹àº™â€‹.</translation>
<translation id="7495528107193238112">ເນື້ອຫານີ້ຖືàºàºšàº¥àº±àº­àºà»„ວ້. ຕິດຕà»à»ˆà»€àºˆàº»à»‰àº²àº‚ອງເວັບໄຊເພື່ອà»àºà»‰à»„ຂບັນຫາ.</translation>
<translation id="7497998058912824456">ປຸ່ມສ້າງເອàºàº°àºªàº²àº™, àºàº»àº” Enter ເພື່ອສ້າງ Google Doc ໃà»à»ˆà»„ດ້ຢ່າງວ່ອງໄວ</translation>
+<translation id="7506488012654002225">Chromium <ph name="BEGIN_EMPHASIS" />ຈະບà»à»ˆàºšàº±àº™àº—ຶàº<ph name="END_EMPHASIS" /> ຂà»à»‰àº¡àº¹àº™àº•à»à»ˆà»„ປນີ້:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ປະຫວັດàºàº²àº™àº—່ອງເວັບຂອງທ່ານ
+ <ph name="LIST_ITEM" />ຄຸàºàºàºµà»‰ à»àº¥àº° ຂà»à»‰àº¡àº¹àº™à»€àº§àº±àºšà»„ຊ
+ <ph name="LIST_ITEM" />ຂà»à»‰àº¡àº¹àº™àº—ີ່ປ້ອນໃສ່à»àºšàºšàºŸàº­àº¡àº•à»ˆàº²àº‡à»†
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">id ອຸປະàºàº­àº™àº™àº°à»‚àºàºšàº²àºàº«àº§à»ˆàº²àº‡à»€àº›àº»à»ˆàº² ຫຼື ບà»à»ˆàºàº»àº‡àºàº±àºš id ອຸປະàºàº­àº™àº›àº±àº”ຈຸບັນ</translation>
<translation id="7508870219247277067">ສີ​ຂຽວ​ອາ​ໂວ​àºàº²â€‹à»‚ດ</translation>
<translation id="7511955381719512146">Wi-Fi ທີ່​ທ່ານ​àºàº³â€‹àº¥àº±àº‡â€‹à»ƒàºŠà»‰â€‹àº¢àº¹à»ˆ (WIFI_NAME) ອາດ​ຈະ​ຕ້ອງ​àºàº²àº™â€‹à»ƒàº«à»‰â€‹àº—່ານ​ເຂົ້າ​ເບິ່ງ <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
@@ -2118,7 +2173,6 @@
<translation id="7813600968533626083">ເອົາ​àºàº²àº™â€‹à»àº™àº°â€‹àº™àº³â€‹à»àºšàºšâ€‹àºŸàº­àº¡â€‹àº­àº­àºâ€‹à»„ປ​ຈາຠChrome ບà»?</translation>
<translation id="781440967107097262">à»àºšà»ˆàº‡àº›àº±àº™àº„ລິບບອດບà»?</translation>
<translation id="7815407501681723534">ພົບ <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> ສຳລັບ '<ph name="SEARCH_STRING" />'</translation>
-<translation id="782125616001965242">ສະà»àº”ງຂà»à»‰àº¡àº¹àº™àºà»ˆàº½àº§àºàº±àºšà»€àº§àº±àºšà»„ຊນີ້</translation>
<translation id="782886543891417279">Wi-Fi ທີ່​ທ່ານ​àºàº³â€‹àº¥àº±àº‡â€‹à»ƒàºŠà»‰â€‹àº¢àº¹à»ˆ (<ph name="WIFI_NAME" />) ອາດ​ຈະ​ຕ້ອງ​àºàº²àº™â€‹à»ƒàº«à»‰â€‹àº—່ານ​ເຂົ້າ​ຫາໜ້າລັອàºàº­àº´àº™â€‹à»€àº‚ົ້າ​​ລະ​ບົບ​ຂອງ​ມັນ.</translation>
<translation id="7836231406687464395">Postfix (ຊອງຈົດà»àº²àº)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{ບà»à»ˆàº¡àºµ}=1{1 à»àº­àº±àºš (<ph name="EXAMPLE_APP_1" />)}=2{2 à»àº­àº±àºš (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}other{# à»àº­àº±àºš (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}}</translation>
@@ -2135,7 +2189,6 @@
<translation id="7888575728750733395">àºàº»àº™à»„àºàº›àº°àºªàº²àº™àºàº²àº™àºªàº°à»àº”ງພາບàºàº²àº™àºžàº´àº¡</translation>
<translation id="7894280532028510793">ຖ້າàºàº²àº™àºªàº°àºàº»àº”ຄຳຖືàºàº•à»‰àº­àº‡, <ph name="BEGIN_LINK" />ລອງເປີດໃຊ້ Network Diagnostics<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (ຊອງຈົດà»àº²àº)</translation>
-<translation id="7931318309563332511">ບà»à»ˆàº®àº¹à»‰àºˆàº±àº</translation>
<translation id="793209273132572360">ອັບເດດທີ່ຢູ່ບ�</translation>
<translation id="7932579305932748336">ເຄືອບ</translation>
<translation id="79338296614623784">ປ້ອນເບີໂທລະສັບທີ່ຖືàºàº•à»‰àº­àº‡</translation>
@@ -2160,13 +2213,14 @@
<translation id="7976214039405368314">ມີàºàº²àº™àº®à»‰àº­àº‡àº‚à»àº«àº¼àº²àºà»€àºàºµàº™à»„ປ</translation>
<translation id="7977538094055660992">ອຸປະàºàº­àº™à»€àºˆà»‰àºàº­àº­àº</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">ເຊື່ອມຕà»à»ˆàº«àº²</translation>
<translation id="798134797138789862">ສາມາດຂà»à»ƒàºŠà»‰àº­àº¸àº›àº°àºàº­àº™à»€àº§àºµàºŠàº»àº§ ຣິອາລິຕີ à»àº¥àº° ຂà»à»‰àº¡àº¹àº™</translation>
<translation id="7984945080620862648">ທ່ານບà»à»ˆàºªàº²àº¡àº²àº”ເຂົ້າເບິ່ງ <ph name="SITE" /> ໄດ້ດຽວນີ້ ເພາະວ່າເວັບໄຊທ໌ໄດ້ສົ່ງàºàº²àº™àº¢àº±à»‰àº‡àº¢àº·àº™àº¥àº»àºšàºàº§àº™àº—ີ່ Chrome ບà»à»ˆàºªàº²àº¡àº²àº”ປະມວນຜົນໄດ້. ໂດàºàº›àº»àºàºàº°àº•àº´àº™àº±à»‰àº™ ຄວາມຂັດຂ້ອງຂອງເຄືອຂ່າຠà»àº¥àº°àºàº²àº™à»‚ຈມຕີເຄືອຂ່າàºàºˆàº°àºŠàº»à»ˆàº§àº„າວເທົ່ານັ້ນ, ດັ່ງນັ້ນ ໜ້ານີ້ອາດຈະàºàº±àºšàº¡àº²à»ƒàºŠà»‰àº‡àº²àº™à»„ດ້ໃນພາàºàº«àº¼àº±àº‡.</translation>
-<translation id="79859296434321399">ເພື່ອເບິ່ງເນື້ອຫາອາàºàº´àº§à»€àº¡àº±àº™ ຣີອາລິຕີ, àºàº°àº¥àº¸àº™àº²àº•àº´àº”ຕັ້ງ ARCore àºà»ˆàº­àº™</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">ຫບິບເຫຼັ້ມ</translation>
<translation id="7992044431894087211">ສືບຕà»à»ˆàºàº²àº™à»àºšà»ˆàº‡àº›àº±àº™à»œà»‰àº²àºˆà»àºàº±àºš <ph name="APPLICATION_TITLE" /> à»àº¥à»‰àº§</translation>
<translation id="7995512525968007366">ບà»à»ˆâ€‹à»„ດ້ລະ​ບຸ</translation>
+<translation id="7998269595945679889">ປຸ່ມເປີດà»àº–ບທີ່ບà»à»ˆà»€àº›àºµàº”ເຜີàºàº•àº»àº§àº•àº»àº™, àºàº»àº” Enter ເພື່ອເປີດà»àº–ບທີ່ບà»à»ˆà»€àº›àºµàº”ເຜີàºàº•àº»àº§àº•àº»àº™à»ƒà»à»ˆà»€àºžàº·à»ˆàº­àº—່ອງເວັບà»àºšàºšàºªà»ˆàº§àº™àº•àº»àº§</translation>
<translation id="800218591365569300">ລອງປິດà»àº–ບ ຫຼື ໂປຣà»àºàº£àº¡àº­àº·à»ˆàº™à»€àºžàº·à»ˆàº­àº‚ະຫàºàº²àºàº„ວາມຈຳ.</translation>
<translation id="8004582292198964060">ບຣາວ​ເຊີ</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{ບັດນີ້ à»àº¥àº° ທີ່ຢູ່ຮຽàºà»€àºàº±àºšà»€àº‡àº´àº™àº‚ອງມັນຈະຖືàºàºšàº±àº™àº—ຶàºà»„ວ້. ທ່ານຈະສາມາດໃຊ້ມັນໄດ້ໃນເວລາເຂົ້າສູ່ລະບົບ <ph name="USER_EMAIL" />.}other{ບັດເຫຼົ່ານີ້ à»àº¥àº° ທີ່ຢູ່ຮຽàºà»€àºàº±àºšà»€àº‡àº´àº™àº‚ອງພວàºàº¡àº±àº™àºˆàº°àº–ືàºàºšàº±àº™àº—ຶàºà»„ວ້. ທ່ານຈະສາມາດໃຊ້ພວàºàº¡àº±àº™à»„ດ້ໃນເວລາເຂົ້າສູ່ລະບົບ <ph name="USER_EMAIL" />.}}</translation>
@@ -2226,6 +2280,7 @@
<translation id="8202370299023114387">ຂັດà»àºà»ˆàº‡</translation>
<translation id="8206978196348664717">Prc4 (ຊອງຈົດà»àº²àº)</translation>
<translation id="8211406090763984747">àºàº²àº™à»€àºŠàº·à»ˆàº­àº¡àº•à»à»ˆàº›àº­àº”ໄພດີ</translation>
+<translation id="8217240300496046857">ເວັບໄຊບà»à»ˆàºªàº²àº¡àº²àº”ໃຊ້ຄຸàºàºàºµà»‰àº—ີ່ຕິດຕາມທ່ານຢູ່ເວັບໄຊໄດ້. ຄຸນສົມບັດໃນບາງເວັບໄຊອາດບà»à»ˆà»€àº®àº±àº”ວຽàº.</translation>
<translation id="8218327578424803826">ທີ່​ຕັ້ງ​ທີ່​àºàº³â€‹àº™àº»àº”​ໃຫ້</translation>
<translation id="8220146938470311105">C7/C6 (ຊອງຈົດà»àº²àº)</translation>
<translation id="8225771182978767009">ບຸàºàº„ົນຜູ້ທີ່ຕັ້ງຄ່າຄອມພິວເຕີນີ້ໄດ້ເລືອàºàºšàº¥àº±àº­àºà»€àº§àº±àºšà»„ຊນີ້ໄວ້.</translation>
@@ -2266,14 +2321,9 @@
<translation id="830498451218851433">ພັບເຄິ່ງ</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">à»àº­àº±àºšàº—ີ່ຕິດຕັ້ງ à»àº¥àº° ມີàºàº²àº™àº™àº³à»ƒàºŠà»‰àºžàº§àºàº¡àº±àº™à»€àº¥àº·à»‰àº­àºà»†àºªà»à»ˆàº²à»ƒàº”</translation>
+<translation id="8317207217658302555">ອັບເດດ ARCore ບ�</translation>
<translation id="831997045666694187">ຕອນà»àº¥àº‡</translation>
<translation id="8321476692217554900">àºàº²àº™à»àºˆà»‰àº‡à»€àº•àº·àº­àº™</translation>
-<translation id="8328484624016508118">ຫຼັງຈາàºàºàº²àº™àº›àº´àº”à»àº–ບ​ບà»à»ˆà»€àº›àºµàº”ເຜີàºàº•àº»àº§àº•àº»àº™àº—ັງà»àº»àº”à»àº¥à»‰àº§, Chrome ຈະລຶບລ້າງ:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />àºàº²àº™à»€àº„ື່ອນໄຫວàºàº²àº™àº—່ອງເວັບຂອງທ່ານຈາàºàº­àº¸àº›àº°àºàº­àº™àº™àºµà»‰<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />ປະ​ຫວັດ​àºàº²àº™â€‹àºŠàº­àºàº«àº²àº‚ອງທ່ານຈາàºàº­àº¸àº›àº°àºàº­àº™àº™àºµà»‰<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />ຂà»à»‰àº¡àº¹àº™àº—ີ່ລະບຸໃສ່ໃນà»àºšàºšàºŸàº­àº¡àº•à»ˆàº²àº‡à»†<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489">àºàº²àº™à»€àº‚ົ້າເຖິງ <ph name="HOST_NAME" /> ຖືàºàº›àº°àº•àº´à»€àºªàº”à»àº¥à»‰àº§</translation>
<translation id="833262891116910667">ໄຮໄລ</translation>
<translation id="8339163506404995330">ໜ້າຕ່າງໆໃນ <ph name="LANGUAGE" /> ຈະບà»à»ˆàº–ືàºà»àº›</translation>
@@ -2325,6 +2375,7 @@
<translation id="8507227106804027148">à»àº–ວຄà»àº²àºªàº±à»ˆàº‡</translation>
<translation id="8508648098325802031">ໄອຄອນຊອàºàº«àº²</translation>
<translation id="8511402995811232419">ຈັດàºàº²àº™àº„ຸàºàºàºµà»‰</translation>
+<translation id="8519753333133776369">ຜູ້ເບິ່ງà»àºàº‡àº‚ອງທ່ານອະນຸàºàº²àº”ອຸປະàºàº­àº™ HID à»àº¥à»‰àº§</translation>
<translation id="8522552481199248698">Chrome ສາມາດຊ່ວàºàº—່ານປົàºàº›à»‰àº­àº‡àºšàº±àº™àºŠàºµ Google ຂອງທ່ານ à»àº¥àº° ປ່ຽນລະຫັດຜ່ານຂອງທ່ານໄດ້.</translation>
<translation id="8530813470445476232">ລຶບລ້າງປະຫວັດàºàº²àº™àº—່ອງເວັບ, ຄຸàºàºàºµà»‰, à»àº„ສ à»àº¥àº° ອື່ນໆອີàºà»ƒàº™àºàº²àº™àº•àº±à»‰àº‡àº„່າ Chrome</translation>
<translation id="8533619373899488139">ເຂົ້າຫາ &lt;strong&gt;chrome://policy&lt;/strong&gt; ເພື່ອເບິ່ງລາàºàºŠàº·à»ˆàº‚ອງ URL ທີ່ຖືàºàºšàº¥àº±àº­àºà»„ວ້ à»àº¥àº° ນະໂàºàºšàº²àºàº­àº·à»ˆàº™àº—ີ່ຜູ້ຄວບຄຸມລະບົບຂອງທ່ານບັງຄັບໃຊ້.</translation>
@@ -2336,7 +2387,6 @@
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{ຣີເຊັດàºàº²àº™àº­àº°àº™àº¸àºàº²àº”}other{ຣີເຊັດàºàº²àº™àº­àº°àº™àº¸àºàº²àº”}}</translation>
<translation id="8555010941760982128">ໃຊ້ລະຫັດນີ້ເພື່ອຈ່າàºà»€àº‡àº´àº™</translation>
<translation id="8557066899867184262">ມີ CVC ຢູ່ຫຼັງບັດຂອງທ່ານ.</translation>
-<translation id="8558485628462305855">ເພື່ອເບິ່ງເນື້ອຫາອາàºàº´àº§à»€àº¡àº±àº™ ຣີອາລິຕີ, àºàº°àº¥àº¸àº™àº²àº­àº±àºšà»€àº”ດ ARCore</translation>
<translation id="8559762987265718583">ບà»à»ˆâ€‹àºªàº²â€‹àº¡àº²àº”​ຕັ້ງ​àºàº²àº™â€‹à»€àºŠàº·à»ˆàº­àº¡â€‹àº•à»à»ˆâ€‹àºªà»ˆàº§àº™â€‹àº•àº»àº§â€‹àºàº±àºš <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> ໄດ້ ເພາະ​ວ່າ​ວັນ​ທີ à»àº¥àº°â€‹à»€àº§â€‹àº¥àº²â€‹àº­àº¸â€‹àº›àº°â€‹àºàº­àº™â€‹àº‚ອງ​ທ່ານ (<ph name="DATE_AND_TIME" />) ບà»à»ˆâ€‹àº–ືàºâ€‹àº•à»‰àº­àº‡.</translation>
<translation id="8564182942834072828">ເອàºàº°àºªàº²àº™à»àºàºàºàº±àº™/ບà»à»ˆà»„ດ້ຈັດຊຸດສຳເນົາ</translation>
<translation id="8564985650692024650">Chromium à»àº™àº°àº™àº³à»ƒàº«à»‰àº£àºµà»€àºŠàº±àº”ລະຫັດຜ່ານ <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> ຂອງທ່ານ ຖ້າທ່ານນຳມັນມາໃຊ້ໃà»à»ˆà»ƒàº™à»€àº§àº±àºšà»„ຊອື່ນ.</translation>
@@ -2355,6 +2405,7 @@
<translation id="865032292777205197">ເຊັນàºàº§àº”ຈັບàºàº²àº™à»€àº„ື່ອນໄຫວ</translation>
<translation id="8663226718884576429">ສັງຮວມຄຳສັ່ງຊື້, <ph name="TOTAL_LABEL" />, ລາàºàº¥àº°àº­àº½àº”ເພີ່ມເຕີມ</translation>
<translation id="8666678546361132282">ພາສາອັງàºàº´àº”</translation>
+<translation id="8669306706049782872">ໃຊ້ຂà»à»‰àº¡àº¹àº™àºà»ˆàº½àº§àºàº±àºšà»œà»‰àº²àºˆà»àº‚ອງທ່ານເພື່ອເປີດ à»àº¥àº° ວາງໜ້າຈà»àº•à»ˆàº²àº‡à»†</translation>
<translation id="867224526087042813">ລາàºà»€àºŠàº±àº™</translation>
<translation id="8676424191133491403">ບà»à»ˆà»œà»ˆàº§àº‡à»€àº§àº¥àº²</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, ຄຳ​ຕອບ, <ph name="ANSWER" /></translation>
@@ -2381,6 +2432,7 @@
<translation id="8731544501227493793">ປຸ່ມຈັດàºàº²àº™àº¥àº°àº«àº±àº”ຜ່ານ, àºàº»àº” Enter ເພື່ອເບິ່ງ à»àº¥àº° ຈັດàºàº²àº™àº¥àº°àº«àº±àº”ຜ່ານຂອງທ່ານໃນàºàº²àº™àº•àº±à»‰àº‡àº„່າ Chrome</translation>
<translation id="8734529307927223492"><ph name="DEVICE_TYPE" /> ຂອງທ່ານຖືàºàºˆàº±àº”àºàº²àº™à»‚ດຠ<ph name="MANAGER" /></translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, àºàº»àº”à»àº–ບ ຈາàºàº™àº±à»‰àº™ Enter ເພື່ອເປີດໜ້າຈà»àº—ີ່ບà»à»ˆà»€àº›àºµàº”ເຜີàºàº•àº»àº§àº•àº»àº™à»ƒà»à»ˆà»€àºžàº·à»ˆàº­àºŠàº­àº«àº²à»àºšàºšà»€àº›àº±àº™àºªà»ˆàº§àº™àº•àº»àº§</translation>
+<translation id="8737685506611670901">ເປີດ <ph name="PROTOCOL" /> ລິ້ງ​à»àº—ນ <ph name="REPLACED_HANDLER_TITLE" /></translation>
<translation id="8738058698779197622">ເພື່ອ​ຕັ້ງ​àºàº²àº™â€‹à»€àºŠàº·à»ˆàº­àº¡â€‹àº•à»à»ˆâ€‹àº—ີ່​ປອດ​ໄພ, ຈຳ​ເປັນ​ຕ້ອງ​ໄດ້​ຕັ້ງ​ໂມງ​ຂອງ​ທ່ານ​ໃຫ້​ຖືàºâ€‹àº•à»‰àº­àº‡. ອັນ​ນີ້​ເພາະ​ວ່າ​ໃບ​ຢັ້ງ​ຢືນ​ທີ່​ເວັບ​ໄຊ​ທ໌​ໃຊ້​ລະ​ບຸ​ຕົວ​ມັນ​ເອງ​à»àº¡à»ˆàº™â€‹àºˆàº°â€‹à»ƒàºŠà»‰â€‹à»„ດ້​ເປັນ​ໄລ​àºàº°â€‹à»€àº§â€‹àº¥àº²â€‹àºªàº°â€‹à»€àºžàº²àº°â€‹à»€àº—ົ່າ​ນັ້ນ. ເນື່ອງ​ຈາàºâ€‹à»‚ມງ​ຂອງ​ອຸ​ປະ​àºàº­àº™â€‹àº‚ອງ​ທ່ານ​ບà»à»ˆâ€‹àº–ືàºâ€‹àº•à»‰àº­àº‡, Chromium ບà»à»ˆâ€‹àºªàº²â€‹àº¡àº²àº”àºàº§àº”​ສອບ​ໃບ​ຢັ້ງ​ຢືນ​ເຫຼົ່າ​ນີ້​ໄດ້.</translation>
<translation id="8740359287975076522">ບà»à»ˆàºªàº²àº¡àº²àº”ຊອàºàºžàº»àºš &lt;abbr id="dnsDefinition"&gt;ທີ່ຢູ່ DNS&lt;/abbr&gt; ຂອງ <ph name="HOST_NAME" /> ໄດ້. àºàº³àº¥àº±àº‡àº§àº´à»€àº„າະບັນຫາຢູ່.</translation>
<translation id="8742371904523228557"><ph name="ONE_TIME_CODE" /> à»àº¡à»ˆàº™àº¥àº°àº«àº±àº”ສຳລັບ <ph name="ORIGIN" /> ຂອງທ່ານ</translation>
@@ -2408,6 +2460,7 @@
<translation id="883848425547221593">ບຸàºàº¡àº²àºàºªà»Œàº­àº·à»ˆàº™à»†</translation>
<translation id="884264119367021077">ທີ່​ຢູ່​ຈັດສົ່ງ</translation>
<translation id="884923133447025588">ບà»à»ˆàºžàº»àºšàºàº»àº™à»„àºàºàº²àº™àº–ອນຄືນ.</translation>
+<translation id="8849262850971482943">ໃຊ້ບັດສະເà»àº·àº­àº™àº‚ອງທ່ານເພື່ອເພີ່ມຄວາມປອດໄພ</translation>
<translation id="885730110891505394">àºàº²àº™à»àºšà»ˆàº‡àº›àº±àº™àºàº±àºš Google</translation>
<translation id="8858065207712248076">Chrome à»àº™àº°àº™àº³à»ƒàº«à»‰àº£àºµà»€àºŠàº±àº”ລະຫັດຜ່ານ <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> ຂອງທ່ານ ຖ້າທ່ານນຳມັນມາໃຊ້ໃà»à»ˆà»ƒàº™à»€àº§àº±àºšà»„ຊອື່ນ.</translation>
<translation id="885906927438988819">ຖ້າàºàº²àº™àºªàº°àºàº»àº”ຄຳຖືàºàº•à»‰àº­àº‡, <ph name="BEGIN_LINK" />ລອງເປີດໃຊ້ Windows Network Diagnostics<ph name="END_LINK" />.</translation>
@@ -2457,6 +2510,7 @@
<translation id="9004367719664099443">ເຊດຊັນ VR ພວມດຳເນີນຢູ່</translation>
<translation id="9005998258318286617">ໂຫຼດເອàºàº°àºªàº²àº™ PDF ບà»à»ˆàºªàº³à»€àº¥àº±àº”.</translation>
<translation id="9008201768610948239">ບà»à»ˆàºªàº»àº™à»ƒàºˆ</translation>
+<translation id="901834265349196618">ອີເມວ</translation>
<translation id="9020200922353704812">ຈຳເປັນຕ້ອງມີທີ່ຢູ່ຮຽàºà»€àºàº±àºšà»€àº‡àº´àº™àºªàº³àº¥àº±àºšàºšàº±àº”</translation>
<translation id="9020542370529661692">ໜ້ານີ້ຖືàºà»‚ອນໄປຫາ <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9020742383383852663">A8</translation>
@@ -2505,6 +2559,7 @@
<translation id="9150045010208374699">ໃຊ້​àºà»‰àº­àº‡â€‹àº–່າàºâ€‹àº®àº¹àºšâ€‹àº‚ອງ​ທ່ານ</translation>
<translation id="9150685862434908345">ຜູ້ເບິ່ງà»àºàº‡àº¥àº°àºšàº»àºšàº‚ອງທ່ານສາມາດປ່ຽນàºàº²àº™àº•àº±à»‰àº‡àº„່າໂປຣà»àºàº£àº¡àº—່ອງເວັບຂອງທ່ານຈາàºàº—າງໄàºà»„ດ້. àºàº²àº™à»€àº„ື່ອນໄຫວໃນອຸປະàºàº­àº™àº™àºµà»‰àº­àº²àº”ຈະຖືàºàºˆàº±àº”àºàº²àº™àº¢àº¹à»ˆàº™àº­àº Chrome ໄດ້ເຊັ່ນàºàº±àº™. <ph name="BEGIN_LINK" />ສຶàºàºªàº²à»€àºžàºµà»ˆàº¡à»€àº•àºµàº¡<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">ອັບເດດà»àº¥à»‰àº§</translation>
+<translation id="9155211586651734179">ອຸປະàºàº­àº™àº•à»à»ˆàºžà»ˆàº§àº‡àºªàº½àº‡àº—ີ່ເຊື່ອມຕà»à»ˆà»„ວ້</translation>
<translation id="9157595877708044936">àºà»àº²àº¥àº±àº‡â€‹àº•àº±à»‰àº‡...</translation>
<translation id="9158625974267017556">C6 (ຊອງຈົດà»àº²àº)</translation>
<translation id="9164029392738894042">àºàº§àº”ສອບຄວາມຖືàºàº•à»‰àº­àº‡</translation>
diff --git a/chromium/components/strings/components_strings_lt.xtb b/chromium/components/strings/components_strings_lt.xtb
index 99608a40055..3b61e6d69b0 100644
--- a/chromium/components/strings/components_strings_lt.xtb
+++ b/chromium/components/strings/components_strings_lt.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">Žr. išsamią informaciją</translation>
<translation id="1030706264415084469"><ph name="URL" /> prašo leidimo nuolat saugoti daug duomenų įrenginyje</translation>
<translation id="1032854598605920125">Pasukti pagal laikrodžio rodyklę</translation>
+<translation id="1033329911862281889">Naudodami inkognito režimą netampate nematomi internete:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />svetainėse ir jų naudojamose paslaugose gali būti rodomi apsilankymai;<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />darbdaviai ar mokyklos gali stebėti naršymo veiklą;<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />interneto paslaugų teikėjai gali stebėti žiniatinklio srautą.<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">IÅ¡jungti</translation>
<translation id="1036982837258183574">Paspauskite |<ph name="ACCELERATOR" />|, kad išeitumėte iš viso ekrano režimo</translation>
<translation id="1038106730571050514">Rodyti pasiūlymus</translation>
<translation id="1038842779957582377">nežinomas pavadinimas</translation>
<translation id="1041998700806130099">Užduoties lapo pranešimas</translation>
<translation id="1048785276086539861">Kai redaguosite komentarus, bus pateikta šio dokumento vieno puslapio peržiūra</translation>
-<translation id="1049743911850919806">Inkognito</translation>
<translation id="1050038467049342496">Uždarykite kitas programas</translation>
<translation id="1055184225775184556">&amp;Anuliuoti pridÄ—jimÄ…</translation>
<translation id="1056898198331236512">Įspėjimas</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">Gera politikos talpykla</translation>
<translation id="1130564665089811311">Mygtukas „Versti puslapį“, paspauskite „Enter“, kad Å¡is puslapis bÅ«tų verÄiamas naudojant „Google“ vertÄ—jÄ…</translation>
<translation id="1131264053432022307">Nukopijuotas vaizdas</translation>
+<translation id="1142846828089312304">Blokuoti treÄiųjų Å¡alių slapukus inkognito režimu</translation>
<translation id="1150979032973867961">Šiam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; jo saugos sertifikatas nėra patikimas kompiuterio operacinei sistemai. Taip gali nutikti dėl netinkamos konfigūracijos ar dėl ryšį pertraukusio užgrobėjo.</translation>
<translation id="1151972924205500581">Būtinas slaptažodis</translation>
<translation id="1156303062776767266">Peržiūrite vietinį arba bendrinamą failą</translation>
@@ -64,7 +70,6 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="1178581264944972037">Pristabdyti</translation>
<translation id="1181037720776840403">Pašalinti</translation>
<translation id="1186201132766001848">Patikrinti slaptažodžius</translation>
-<translation id="1195210374336998651">Eiti į programos nustatymus</translation>
<translation id="1195558154361252544">Pranešimai automatiškai blokuojami visose svetainėse, išskyrus svetaines, kuriose leidote rodyti</translation>
<translation id="1197088940767939838">Oranžinė</translation>
<translation id="1201402288615127009">Kitas</translation>
@@ -111,7 +116,7 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="1307966114820526988">Nebenaudojamos funkcijos</translation>
<translation id="1308113895091915999">Yra galiojantis pasiūlymas</translation>
<translation id="1312803275555673949">Kokie įrodymai pateikti?</translation>
-<translation id="131405271941274527"><ph name="URL" /> nori siųsti ir gauti informacijÄ…, kai palieÄiate telefonÄ… ALR įrenginyje</translation>
+<translation id="1314311879718644478">Žr. išplėstosios realybės turinį</translation>
<translation id="1314509827145471431">Įrišimas dešinėje</translation>
<translation id="1318023360584041678">Išsaugota skirtukų grupėje</translation>
<translation id="1319245136674974084">Daugiau neklausti dÄ—l Å¡ios programos</translation>
@@ -161,6 +166,7 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="142858679511221695">„Cloud“ naudotojas</translation>
<translation id="1428729058023778569">Matote šį įspėjimą, nes ši svetainė nepalaiko HTTPS. <ph name="BEGIN_LEARN_MORE_LINK" />Sužinokite daugiau<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">Spausdinti</translation>
+<translation id="1432187715652018471">puslapis prašo leidimo įdiegti paslaugos doroklę.</translation>
<translation id="1432581352905426595">Tvarkyti paieškos sistemas</translation>
<translation id="1436185428532214179">Gali būti prašoma redaguoti failus ir aplankus jūsų įrenginyje</translation>
<translation id="1442386063175183758">Atvartas dešinėje</translation>
@@ -181,6 +187,12 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="1483493594462132177">Siųsti</translation>
<translation id="1484290072879560759">Pasirinkti pristatymo adresÄ…</translation>
<translation id="1492194039220927094">Politikos gavimas:</translation>
+<translation id="149293076951187737">Kai uždarote visus „Chrome“ inkognito skirtukus, iš šio įrenginio išvaloma jūsų veikla toliau nurodytuose skirtukuose.
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Naršymo veikla<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Paieškos istorija<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Formose įvesta informacija<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">Atgal į skirtuką</translation>
<translation id="1501859676467574491">Rodyti korteles iš „Google“ paskyros</translation>
<translation id="1507202001669085618">&lt;p&gt;Ši klaida rodoma, jei naudojate „Wi-Fi“ portalą, prie kurio reikia prisijungti, kad galėtumėte naudotis internetu.&lt;/p&gt;
@@ -208,6 +220,8 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="1559572115229829303">&lt;p&gt;Nepavyksta užmegzti privataus ryšio su <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />, nes įrenginio data ir laikas (<ph name="DATE_AND_TIME" />) yra netinkami.&lt;/p&gt;
&lt;p&gt;Koreguokite datÄ… ir laikÄ… programos &lt;strong&gt;Settings&lt;/strong&gt; skiltyje &lt;strong&gt;General&lt;/strong&gt;.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">Jūsų administratorius paleis jūsų įrenginį iš naujo <ph name="TIME" />, <ph name="DATE" /></translation>
+<translation id="156703335097561114">Tinklų informacija, pvz., adresai, sąsajos konfigūracija ir ryšio kokybė</translation>
<translation id="1567040042588613346">Å i politika veikia, kaip numatyta, bet ta pati vertÄ— yra nustatyta kitur ir jÄ… pakeiÄia Å¡i politika.</translation>
<translation id="1569487616857761740">Įveskite galiojimo laiko pabaigos datą</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="1583429793053364125">Rodant šį tinklalapį įvyko nenumatyta klaida.</translation>
<translation id="1586541204584340881">Kuriuos plėtinius įdiegėte</translation>
<translation id="1588438908519853928">Įprastas</translation>
+<translation id="1589050138437146318">Įdiegti „ARCore“?</translation>
<translation id="1592005682883173041">Prieiga prie vietinių duomenų</translation>
<translation id="1594030484168838125">Pasirinkti</translation>
<translation id="160851722280695521">Žaisti žaidimą „Dino Run“ naršyklėje „Chrome“</translation>
@@ -283,6 +298,7 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
antraštė netinkamai suformatuota, todėl naršyklė negali įvykdyti
<ph name="SITE" /> užklausos. Pradinę politiką gali naudoti
svetainių operatoriai, siekdami konfigūruoti svetainės saugą ir kitas nuosavybes.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Sužinokite daugiau apie inkognito režimą naršyklėje „Chromium“<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">Atidaryti skirtukai bus rodomi Äia</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -410,6 +426,7 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="22081806969704220">3 dÄ—klas</translation>
<translation id="2212735316055980242">Politika nerasta</translation>
<translation id="2213606439339815911">Gaunami įrašai...</translation>
+<translation id="2213612003795704869">Puslapis atspausdintas</translation>
<translation id="2215727959747642672">Failo redagavimas</translation>
<translation id="2218879909401188352">Šiuo metu užpuolikai svetainėje <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> gali įdiegti pavojingų programų, kurios gali būti žalingos įrenginiui, atlikti nepageidaujamų veiksmų, dėl kurių padidės mobiliojo telefono sąskaita, arba pavogti asmens informaciją. <ph name="BEGIN_LEARN_MORE_LINK" />Sužinokite daugiau<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">Nėra interneto ryšio</translation>
@@ -419,6 +436,7 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="2248949050832152960">Naudoti „WebAuthn“</translation>
<translation id="2250931979407627383">Kraštų sukabinimas kairėje</translation>
<translation id="225207911366869382">Pagal Å¡iÄ… politikÄ… Å¡i vertÄ— nepatvirtinta.</translation>
+<translation id="2256115617011615191">Paleisti iš naujo dabar</translation>
<translation id="2258928405015593961">Įveskite galiojimo laiko pabaigos datą, kuri yra ateityje, ir bandykite dar kartą</translation>
<translation id="225943865679747347">Klaidos kodas: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">HTTP klaida</translation>
@@ -446,6 +464,7 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="2337852623177822836">NustatymÄ… valdo administratorius</translation>
<translation id="2340263603246777781">Svetainė <ph name="ORIGIN" /> nori būti susieta su</translation>
<translation id="2346319942568447007">Nukopijuotas vaizdas</translation>
+<translation id="2350796302381711542">Leisti „<ph name="HANDLER_HOSTNAME" />“ atidaryti visas <ph name="PROTOCOL" /> nuorodas vietoje „<ph name="REPLACED_HANDLER_TITLE" />“?</translation>
<translation id="2354001756790975382">Kitos žymės</translation>
<translation id="2354430244986887761">„Google“ saugaus naršymo technologija svetainėje <ph name="SITE" /> neseniai <ph name="BEGIN_LINK" />aptiko kenkėjiškų programų<ph name="END_LINK" />.</translation>
<translation id="2355395290879513365">Užpuolikai galbūt galės matyti, kuriuos šios svetainės vaizdus peržiūrite, ir juos pakeis siekdami jus suklaidinti.</translation>
@@ -471,6 +490,7 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="2413528052993050574">Šiam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; jo saugos sertifikatas gali būti atšauktas. Taip gali nutikti dėl netinkamos konfigūracijos ar dėl ryšį pertraukusio užgrobėjo.</translation>
<translation id="2414886740292270097">Tamsi</translation>
<translation id="2430968933669123598">Mygtukas „Tvarkyti „Google“ paskyrą“ – paspauskite klavišą „Enter“, jei norite tvarkyti savo informaciją, privatumo ir saugos nustatymus „Google“ paskyroje</translation>
+<translation id="2436186046335138073">Leisti „<ph name="HANDLER_HOSTNAME" />“ atidaryti visas <ph name="PROTOCOL" /> nuorodas?</translation>
<translation id="2438874542388153331">Keturios skylės dešinėje</translation>
<translation id="2450021089947420533">Atlikti veiksmai</translation>
<translation id="2463739503403862330">Užpildyti</translation>
@@ -478,6 +498,7 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="2465655957518002998">Pasirinkti pristatymo metodÄ…</translation>
<translation id="2465688316154986572">Susegimas sankabÄ—lÄ—mis</translation>
<translation id="2465914000209955735">Tvarkykite failus, kuriuos atsisiuntėte naršyklėje „Chrome“</translation>
+<translation id="2466004615675155314">Rodyti informaciją iš žiniatinklio</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Paleistas įrankis „Windows Network Diagnostics“<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">Tvarka: nuo 1 iki N</translation>
<translation id="2470767536994572628">Kai redaguosite komentarus, bus pateikta šio dokumento vieno puslapio peržiūra arba pradinis pasukimas</translation>
@@ -498,6 +519,7 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="2523886232349826891">Išsaugota tik šiame įrenginyje</translation>
<translation id="2524461107774643265">Daugiau informacijos pridÄ—jimas</translation>
<translation id="2529899080962247600">Šiame lauke gali būti ne daugiau nei <ph name="MAX_ITEMS_LIMIT" /> įraš. Į visus kitus įrašus nebus atsižvelgiama.</translation>
+<translation id="2535585790302968248">NarÅ¡ykite privaÄiai, atidarÄ™ naujÄ… inkognito skirtukÄ…</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{ir dar 1}one{ir dar #}few{ir dar #}many{ir dar #}other{ir dar #}}</translation>
<translation id="2536110899380797252">PridÄ—ti adresÄ…</translation>
<translation id="2539524384386349900">Aptikti</translation>
@@ -523,7 +545,14 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="2597378329261239068">Šis dokumentas apsaugotas slaptažodžiu. Įveskite slaptažodį.</translation>
<translation id="2609632851001447353">Variantai</translation>
<translation id="2610561535971892504">SpustelÄ—kite, jei norite kopijuoti</translation>
+<translation id="2617988307566202237">„Chrome“ <ph name="BEGIN_EMPHASIS" />nesaugos<ph name="END_EMPHASIS" /> šios informacijos:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />naršymo istorijos;
+ <ph name="LIST_ITEM" />slapukų ir svetainių duomenų;
+ <ph name="LIST_ITEM" />formose įvestos informacijos.
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (vokas)</translation>
+<translation id="2623663032199728144">Gali prašyti naudoti informaciją apie ekranus</translation>
<translation id="2625385379895617796">Jūsų laikrodis skuba</translation>
<translation id="262745152991669301">Gali būti prašoma prisijungti prie USB įrenginių</translation>
<translation id="2629325967560697240">Jei norite, kad bÅ«tų užtikrinta aukÅ¡Äiausio lygio „Chrome“ sauga, <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />įjunkite sustiprintÄ… apsaugÄ…<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -557,6 +586,7 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="2709516037105925701">Automatinis pildymas</translation>
<translation id="2713444072780614174">Balta</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />, paspauskite tabuliavimo klavišą, tada – „Enter“, jei norite tvarkyti mokėjimus ir kredito kortelę „Chrome“ nustatymuose</translation>
+<translation id="271663710482723385">Jei norite išeiti iš viso ekrano režimo, paspauskite |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />|</translation>
<translation id="2721148159707890343">Užklausa sėkminga</translation>
<translation id="2723669454293168317">Paleiskite saugos patikrą „Chrome“ nustatymuose</translation>
<translation id="2726001110728089263">Å oninis dÄ—klas</translation>
@@ -587,6 +617,7 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="2850739647070081192">„Invite“ (vokas)</translation>
<translation id="2856444702002559011">Užpuolikai gali bandyti pavogti jūsų informaciją iš <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (pvz., slaptažodžius, pranešimus ar kredito kortelių duomenis). <ph name="BEGIN_LEARN_MORE_LINK" />Sužinokite daugiau<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">Å ioje svetainÄ—je rodomi nepageidaujami arba klaidinantys skelbimai.</translation>
+<translation id="286512204874376891">Virtuali kortelė maskuoja tikrąją kortelę, kad padėtų apsaugoti jus nuo galimų apgaulių. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">Draugiška</translation>
<translation id="2876489322757410363">Išjungiate inkognito režimą, kad galėtumėte sumokėti naudodami išorinę programą. Tęsti?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />; paspauskite tabuliavimo klavišą, tada „Enter“, jei norite tvarkyti Saugaus naršymo ir kitus duomenis „Chrome“ nustatymuose</translation>
@@ -611,6 +642,7 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="2930577230479659665">Apkarpymas po kiekvienos kopijos</translation>
<translation id="2932085390869194046">Siūlyti slaptažodį...</translation>
<translation id="2934466151127459956">Oficialus laiškas</translation>
+<translation id="2938225289965773019">Atidaryti „<ph name="PROTOCOL" />“ nuorodas</translation>
<translation id="2941952326391522266">Šiam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; jo saugos sertifikatas yra iš <ph name="DOMAIN2" />. Taip gali nutikti dėl netinkamos konfigūracijos ar dėl ryšį pertraukusio užgrobėjo.</translation>
<translation id="2943895734390379394">Įkėlimo laikas:</translation>
<translation id="2948083400971632585">Galite neleisti visų tarpinių serverių, jungimasis prie kurių sukonfigūruotas nustatymų puslapyje.</translation>
@@ -643,6 +675,7 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="3037605927509011580">Oi!</translation>
<translation id="3041612393474885105">Sertifikato informacija</translation>
<translation id="3044034790304486808">Tęsti tyrimą</translation>
+<translation id="305162504811187366">„Chrome“ nuotolinio kompiuterio valdymo istorija, įskaitant laiko žymes, prieglobas ir klientų seansų ID</translation>
<translation id="3060227939791841287">C9 (vokas)</translation>
<translation id="3061707000357573562">Pataisos paslauga</translation>
<translation id="306573536155379004">Žaidimas prasidėjo.</translation>
@@ -684,6 +717,7 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="3197136577151645743">Gali būti prašoma leisti sužinoti, kada aktyviai naudojate įrenginį</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />; paspauskite tabuliavimo klavišą, tada „Enter“, jei norite tvarkyti sinchronizuojamą informaciją „Chrome“ nustatymuose</translation>
<translation id="320323717674993345">Atšaukti mokėjimą</translation>
+<translation id="3203366800380907218">Iš žiniatinklio</translation>
<translation id="3207960819495026254">Pažymėta</translation>
<translation id="3209034400446768650">Puslapyje galite būti apmokestinti</translation>
<translation id="3212581601480735796">Jūsų veikla <ph name="HOSTNAME" /> stebima</translation>
@@ -700,10 +734,12 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="3234666976984236645">Visada aptikti svarbų turinį šioje svetainėje</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />; paspauskite tabuliavimo klavišą, tada – „Enter“, jei norite tinkinti naršyklės išvaizdą</translation>
<translation id="3240791268468473923">Saugaus mokÄ—jimo prisijungimo duomenų lapas, informuojantis, kad atitinkanÄių prisijungimo duomenų nerasta, atidarytas</translation>
+<translation id="324180406144491771">„<ph name="HOST_NAME" />“ nuorodos užblokuotos</translation>
<translation id="3249845759089040423">Klasiška</translation>
<translation id="3252266817569339921">Prancūzų</translation>
<translation id="3257954757204451555">IÅ¡ kur Å¡i informacija?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />, paspauskite tabuliavimo klavišą, tada – „Enter“, jei norite greitai sukurti naują „Google“ kalendoriaus įvykį</translation>
+<translation id="3261488570342242926">Sužinokite daugiau apie virtualias korteles</translation>
<translation id="3264837738038045344">„Chrome“ nustatymų tvarkymo mygtukas; paspauskite „Enter“, kad apsilankytumėte „Chrome“ nustatymų skiltyje.</translation>
<translation id="3266793032086590337">VertÄ— (nesuderinama)</translation>
<translation id="3268451620468152448">Atidaryti skirtukai</translation>
@@ -717,6 +753,7 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="3288238092761586174"><ph name="URL" /> gali reikėti imtis papildomų veiksmų, kad patvirtintų jūsų mokėjimą</translation>
<translation id="3293642807462928945">Sužinokite daugiau apie „<ph name="POLICY_NAME" />“ politiką</translation>
<translation id="3295444047715739395">Peržiūrėkite ir tvarkykite slaptažodžius „Chrome“ nustatymuose</translation>
+<translation id="3303795387212510132">Leisti programai atidaryti „<ph name="PROTOCOL_SCHEME" />“ nuorodas?</translation>
<translation id="3303855915957856445">Nerasta jokių paieškos rezultatų</translation>
<translation id="3304073249511302126">„Bluetooth“ nuskaitymas</translation>
<translation id="3308006649705061278">Organizacinis vienetas (angl. „Organizational Unit“) (OU)</translation>
@@ -730,12 +767,6 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="3345782426586609320">Akys</translation>
<translation id="3355823806454867987">Pakeisti įgaliotojo serverio nustatymus...</translation>
<translation id="3360103848165129075">MokÄ—jimo doroklÄ—s lapas</translation>
-<translation id="3361596688432910856">„Chrome“ <ph name="BEGIN_EMPHASIS" />nesaugos<ph name="END_EMPHASIS" /> šios informacijos:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />naršymo istorijos;
- <ph name="LIST_ITEM" />slapukų ir svetainių duomenų;
- <ph name="LIST_ITEM" />formose įvestos informacijos.
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">Ši politika automatiškai nukopijuota iš nebenaudojamos politikos „<ph name="OLD_POLICY" />“. Turėtumėte naudoti šią politiką vietoj senosios.</translation>
<translation id="3364869320075768271"><ph name="URL" /> nori naudoti jūsų virtualiosios realybės įrenginį ir duomenis</translation>
<translation id="3366477098757335611">Peržiūrėti korteles</translation>
@@ -818,7 +849,6 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="3587738293690942763">Vidurys</translation>
<translation id="3592413004129370115">„Italian“ (vokas)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{Grupę bet kuriuo metu galite nustatyti iš naujo. Prisijungimas prie naujos grupės užtruks maždaug dieną.}=1{Grupę bet kuriuo metu galite nustatyti iš naujo. Prisijungimas prie naujos grupės užtruks maždaug dieną.}one{Grupę bet kuriuo metu galite nustatyti iš naujo. Prisijungimas prie naujos grupės užtruks {NUM_DAYS} dieną.}few{Grupę bet kuriuo metu galite nustatyti iš naujo. Prisijungimas prie naujos grupės užtruks {NUM_DAYS} dienas.}many{Grupę bet kuriuo metu galite nustatyti iš naujo. Prisijungimas prie naujos grupės užtruks {NUM_DAYS} dienos.}other{Grupę bet kuriuo metu galite nustatyti iš naujo. Prisijungimas prie naujos grupės užtruks {NUM_DAYS} dienų.}}</translation>
-<translation id="3596012367874587041">Programos nustatymai</translation>
<translation id="3600246354004376029">„<ph name="TITLE" />“, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">Programą užblokavo administratorius</translation>
<translation id="3608932978122581043">Pateikti orientacijÄ…</translation>
@@ -861,6 +891,7 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="370972442370243704">Įjungti atliktus veiksmus</translation>
<translation id="3711895659073496551">Laikinai sustabdyti</translation>
<translation id="3712624925041724820">Licencijos baigÄ—si</translation>
+<translation id="3714633008798122362">žiniatinklio kalendorius</translation>
<translation id="3714780639079136834">Įjungti mobiliojo ryšio duomenis arba „Wi-Fi“</translation>
<translation id="3715597595485130451">Prisijungimas prie „Wi-Fi“</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Patikrinti tarpinio serverio, užkardos ir DNS konfigūraciją<ph name="END_LINK" /></translation>
@@ -922,6 +953,7 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="3906954721959377182">Planšetinis kompiuteris</translation>
<translation id="3909477809443608991"><ph name="URL" /> nori paleisti saugomą turinį Įrenginio tapatybę patvirtins „Google“ ir įrenginį galės pasiekti ši svetainė.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">Uždrausti</translation>
<translation id="3939773374150895049">Naudoti „WebAuthn“ vietoj CVC?</translation>
<translation id="3946209740501886391">Visada klausti Å¡ioje svetainÄ—je</translation>
<translation id="3947595700203588284">Gali būti prašoma prisijungti prie MIDI įrenginių</translation>
@@ -943,6 +975,7 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="3990250421422698716">Kopijų atskyrimas</translation>
<translation id="3996311196211510766">Svetainė <ph name="ORIGIN" /> pateikė užklausą taikyti pradinę politiką
visoms jos užklausoms, bet šiuo metu šios politikos taikyti negalima.</translation>
+<translation id="4009243425692662128">Spausdinamų puslapių turinys siunÄiamas į „Google Cloud“ arba treÄiosioms Å¡alims analizuoti. Pavyzdžiui, tekstas gali bÅ«ti nuskaitytas, ar jame nÄ—ra neskelbtinų duomenų.</translation>
<translation id="4010758435855888356">Suteikti prieigÄ… prie saugyklos?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{PDF dokumente yra {COUNT} puslapis}one{PDF dokumente yra {COUNT} puslapis}few{PDF dokumente yra {COUNT} puslapiai}many{PDF dokumente yra {COUNT} puslapio}other{PDF dokumente yra {COUNT} puslapių}}</translation>
<translation id="4023431997072828269">Kadangi ši forma teikiama naudojant nesaugų ryšį, jūsų informacija bus matoma kitiems.</translation>
@@ -1037,6 +1070,7 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="4250680216510889253">Ne</translation>
<translation id="4253168017788158739">Pastaba</translation>
<translation id="425582637250725228">Atlikti pakeitimai gali nebūti išsaugoti.</translation>
+<translation id="425869179292622354">Labiau apsaugoti naudojant virtualiÄ… kortelÄ™?</translation>
<translation id="4258748452823770588">Netinkamas parašas</translation>
<translation id="4261046003697461417">Negalima rašyti komentarų apsaugotuose dokumentuose</translation>
<translation id="4265872034478892965">Leidžia jūsų administratorius</translation>
@@ -1099,6 +1133,7 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="4434045419905280838">IÅ¡Å¡ok. langai ir peradresavimai</translation>
<translation id="4435702339979719576">Atvirukas</translation>
<translation id="443673843213245140">Įgaliotojo serverio naudojimas neleidžiamas, bet nurodyta aiški įgaliotojo serverio konfigūracija.</translation>
+<translation id="4441832193888514600">Nepaisoma, nes politika gali būti nustatyta tik kaip debesies naudotojo politika.</translation>
<translation id="4450893287417543264">Daugiau neberodyti</translation>
<translation id="4451135742916150903">Gali būti prašoma prisijungti prie HID įrenginių</translation>
<translation id="4452328064229197696">Slaptažodis, kurį ką tik naudojote, buvo atskleistas įvykus duomenų saugos pažeidimui. Siekiant užtikrinti paskyrų saugumą, „Google“ slaptažodžių tvarkytuvė rekomenduoja patikrinti išsaugotus slaptažodžius.</translation>
@@ -1154,6 +1189,7 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="4628948037717959914">Nuotrauka</translation>
<translation id="4631649115723685955">Grynųjų grąžinimas susietas</translation>
<translation id="4636930964841734540">Informacija</translation>
+<translation id="4638670630777875591">Inkognito režimas naršyklėje „Chromium“</translation>
<translation id="464342062220857295">Paieškos funkcijos</translation>
<translation id="4644670975240021822">AtvirkÅ¡tine tvarka, gerÄ…ja puse į apaÄiÄ…</translation>
<translation id="4646534391647090355">Eiti dabar</translation>
@@ -1174,6 +1210,7 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="4708268264240856090">Ryšys nutrauktas</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Paleistas įrankis „Windows Network Diagnostics“<ph name="END_LINK" />.</translation>
+<translation id="4722735765955348426"><ph name="USERNAME" /> slaptažodis</translation>
<translation id="4724144314178270921">Gali būti prašoma peržiūrėti tekstą ir vaizdus jūsų iškarpinėje</translation>
<translation id="4726672564094551039">Iš naujo įkelti politiką</translation>
<translation id="4728558894243024398">Platforma</translation>
@@ -1195,6 +1232,7 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="4757993714154412917">Ką tik savo slaptažodį įvedėte apgaulingoje svetainėje. Kad apsaugotumėte paskyras, „Chromium“ rekomenduoja patikrinti išsaugotus slaptažodžius.</translation>
<translation id="4758311279753947758">PridÄ—ti kontaktinÄ™ informacijÄ…</translation>
<translation id="4761104368405085019">Naudoti mikrofonÄ…</translation>
+<translation id="4761869838909035636">Paleisti „Chrome“ Saugos patikrą</translation>
<translation id="4764776831041365478">Tinklalapis šiuo adresu <ph name="URL" /> gali laikinai neveikti arba visam laikui būti perkeltas kitu žiniatinklio adresu.</translation>
<translation id="4766713847338118463">Dvi sankabÄ—lÄ—s apaÄioje</translation>
<translation id="4771973620359291008">Įvyko nežinoma klaida.</translation>
@@ -1215,12 +1253,6 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="4819347708020428563">Redaguoti komentarus numatytajame rodinyje?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />, paspauskite tabuliavimo klaviÅ¡Ä…, tada – „Enter“, jei norite greitai sukurti naujÄ… „Google“ skaiÄiuoklÄ™</translation>
<translation id="4825507807291741242">Veiksminga</translation>
-<translation id="4827402517081186284">Naudodami inkognito režimą netampate nematomi internete:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />svetainės žino, kada apsilankote;<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />darbdaviai ar mokyklos gali stebėti naršymo veiklą;<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />interneto paslaugų teikėjai galistebėti žiniatinklio srautą.<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">Įjungti įspėjimus</translation>
<translation id="4838327282952368871">Svajinga</translation>
<translation id="4840250757394056958">Peržiūrėti „Chrome“ istoriją</translation>
@@ -1232,12 +1264,12 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="4854362297993841467">Å is pristatymo metodas nepasiekiamas. IÅ¡bandykite kitÄ… metodÄ….</translation>
<translation id="4854853140771946034">Greitai sukurkite naują „Google Keep“ užrašą</translation>
<translation id="485902285759009870">Patvirtinamas kodas...</translation>
+<translation id="4866506163384898554">Paspauskite |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />, kad būtų rodomas žymeklis</translation>
<translation id="4876188919622883022">Supaprastintas rodinys</translation>
<translation id="4876305945144899064">NÄ—ra naudotojo vardo</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{NÄ—ra}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}one{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}few{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}many{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831">„<ph name="TEXT" />“ paieška</translation>
<translation id="4879491255372875719">Automatinis (numatytasis)</translation>
-<translation id="4879725228911483934">Atidaryti ir nustatyti langus ekranuose</translation>
<translation id="4880827082731008257">Ieškoti istorijoje</translation>
<translation id="4881695831933465202">Atidaryti</translation>
<translation id="4885256590493466218">MokÄ—ti naudojant <ph name="CARD_DETAIL" /> atsiskaitant</translation>
@@ -1246,6 +1278,7 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">Devintas ritinÄ—lis</translation>
<translation id="4901778704868714008">IÅ¡saugoti...</translation>
+<translation id="4905659621780993806">Jūsų administratorius automatiškai paleis jūsų įrenginį iš naujo <ph name="TIME" />, <ph name="DATE" />. Išsaugokite visus atidarytus elementus, prieš paleidžiant įrenginį iš naujo.</translation>
<translation id="4913987521957242411">Skylė viršuje kairėje</translation>
<translation id="4918221908152712722">Įdiekite „<ph name="APP_NAME" />“ (nereikia atsisiųsti)</translation>
<translation id="4923459931733593730">MokÄ—jimas</translation>
@@ -1254,6 +1287,7 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" /> / <ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, norėdami ieškoti paspauskite skirtuką, tada – „Enter“</translation>
<translation id="4930153903256238152">DidelÄ— talpa</translation>
+<translation id="4940163644868678279">Inkognito režimas naršyklėje „Chrome“</translation>
<translation id="4943872375798546930">Rezultatų nėra</translation>
<translation id="4950898438188848926">Skirtuko perjungimo mygtukas. Paspauskite „Enter“, kad perjungtumėte į atidarytą skirtuką „<ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" />“</translation>
<translation id="495170559598752135">Veiksmai</translation>
@@ -1263,6 +1297,7 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="4968522289500246572">Ši programa sukurta mobiliesiems įrenginiams, todėl jos dydis gali būti pakeistas netinkamai. Programoje gali kilti problemų arba ji gali būti paleista iš naujo.</translation>
<translation id="4969341057194253438">Ištrinti įrašą</translation>
<translation id="4973922308112707173">Dvi skylės viršuje</translation>
+<translation id="4976702386844183910">Paskutinį kartą lankytasi <ph name="DATE" /></translation>
<translation id="4984088539114770594">Naudoti mikrofonÄ…?</translation>
<translation id="4984339528288761049">„Prc5“ (vokas)</translation>
<translation id="4989163558385430922">Žr. viską</translation>
@@ -1324,6 +1359,7 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="5138227688689900538">Rodyti mažiau</translation>
<translation id="5145883236150621069">Politikos atsakyme yra klaidos kodas</translation>
<translation id="5146995429444047494"><ph name="ORIGIN" /> pranešimai užblokuoti</translation>
+<translation id="514704532284964975"><ph name="URL" /> nori peržiÅ«rÄ—ti ir keisti informacijÄ… NFC įrenginiuose, kuriÄ… palieÄiate telefonu</translation>
<translation id="5148809049217731050">Gerąja puse į viršų</translation>
<translation id="515292512908731282">C4 (vokas)</translation>
<translation id="5158275234811857234">Viršelis</translation>
@@ -1348,6 +1384,7 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="5215116848420601511">„Google Pay“ naudojami mokėjimo metodai ir adresai</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">Tryliktas dÄ—klas</translation>
+<translation id="5216942107514965959">Paskutinį kartą lankytasi šiandien</translation>
<translation id="5222812217790122047">Būtina nurodyti el. paštą</translation>
<translation id="5230733896359313003">Pristatymo adresas</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1368,7 +1405,6 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">Dokumento ypatybÄ—s</translation>
<translation id="528468243742722775">Baigti</translation>
-<translation id="5284909709419567258">Tinklų adresai</translation>
<translation id="5285570108065881030">Rodyti visus išsaugotus slaptažodžius</translation>
<translation id="5287240709317226393">Rodyti slapukus</translation>
<translation id="5287456746628258573">Å ioje svetainÄ—je naudojama pasenusi saugos konfigÅ«racija, todÄ—l gali bÅ«ti atskleista į Å¡iÄ… svetainÄ™ siunÄiama informacija (pvz., slaptažodžiai ar kredito kortelių numeriai).</translation>
@@ -1452,6 +1488,7 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="5556459405103347317">Įkelti iš naujo</translation>
<translation id="5560088892362098740">Galiojimo laiko pabaigos data</translation>
<translation id="55635442646131152">Dokumento eskizas</translation>
+<translation id="5565613213060953222">Atidaryti inkognito skirtukÄ…</translation>
<translation id="5565735124758917034">Aktyvus</translation>
<translation id="5570825185877910964">Apsaugoti paskyrÄ…</translation>
<translation id="5571083550517324815">Negalima paimti Å¡iuo adresu. Pasirinkite kitÄ… adresÄ….</translation>
@@ -1534,6 +1571,7 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="5869522115854928033">Išsaugoti slaptažodžiai</translation>
<translation id="5873013647450402046">Bankas nori, kad patvirtintumÄ—te savo tapatybÄ™.</translation>
<translation id="5887400589839399685">Kortelė išsaugota</translation>
+<translation id="5887687176710214216">Paskutinį kartą lankytasi vakar</translation>
<translation id="5895138241574237353">Paleisti iš naujo</translation>
<translation id="5895187275912066135">IÅ¡duota</translation>
<translation id="5901630391730855834">Geltona</translation>
@@ -1547,6 +1585,7 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="5921639886840618607">Išsaugoti kortelę „Google“ paskyroje?</translation>
<translation id="5922853866070715753">Beveik atlikta</translation>
<translation id="5932224571077948991">SvetainÄ—je rodomi nepageidaujami arba klaidinantys skelbimai</translation>
+<translation id="5938153366081463283">PridÄ—kite virtualiÄ… kortelÄ™</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347">Atidaroma „<ph name="SITE_NAME" />“…</translation>
<translation id="5951495562196540101">Nepavyko prisiregistruoti su kliento paskyra (galima įsigyti licencijos paketą).</translation>
@@ -1611,6 +1650,7 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="6120179357481664955">Prisiminti UPI ID?</translation>
<translation id="6124432979022149706">Chrome Enterprise Connectors</translation>
<translation id="6127379762771434464">Elementas pašalintas</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Sužinokite daugiau apie inkognito režimą naršyklėje „Chrome“<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">Patikrinkite laidus ir iš naujo paleiskite maršruto parinktuvus, modemus ar kitus
naudojamus tinklo įrenginius.</translation>
<translation id="614940544461990577">Pabandykite atlikti toliau nurodytus veiksmus.</translation>
@@ -1623,7 +1663,6 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="6169916984152623906">Dabar galite narÅ¡yti privaÄiai, o kiti šį įrenginį naudojantys žmonÄ—s nematys jÅ«sų veiklos. TaÄiau atsisiuntimai ir žymÄ—s bus iÅ¡saugoti.</translation>
<translation id="6177128806592000436">Ryšys su šia svetaine nėra saugus</translation>
<translation id="6180316780098470077">Pakartotinio bandymo intervalas</translation>
-<translation id="619448280891863779">Gali būti prašoma atidaryti ir įdėti langų jūsų ekranuose</translation>
<translation id="6196640612572343990">Blokuoti treÄiosios Å¡alies slapukus</translation>
<translation id="6203231073485539293">Patikrinkite interneto ryšį</translation>
<translation id="6218753634732582820">Pašalinti adresą iš „Chromium“?</translation>
@@ -1646,7 +1685,7 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="6272383483618007430">„Google“ naujinys</translation>
<translation id="6276112860590028508">Čia rodomi puslapiai iš skaitymo sąrašo</translation>
<translation id="627746635834430766">Kad kitÄ… kartÄ… galÄ—tumÄ—te greiÄiau atlikti mokÄ—jimÄ…, iÅ¡saugokite kortelÄ™ ir atsiskaitymo adresÄ… „Google“ paskyroje.</translation>
-<translation id="6279098320682980337">Virtualios kortelės numeris neįvestas? Spustelėkite norimą kopijuoti išsamią kortelės informaciją</translation>
+<translation id="6279183038361895380">Paspauskite |<ph name="ACCELERATOR" />|, kad būtų rodomas žymeklis</translation>
<translation id="6280223929691119688">Negalima pristatyti Å¡iuo adresu. Pasirinkite kitÄ… adresÄ….</translation>
<translation id="6282194474023008486">Pašto kodas</translation>
<translation id="6285507000506177184">Mygtukas „Tvarkyti atsisiuntimus naršyklėje „Chrome“; paspauskite „Enter“, jei norite tvarkyti failus, kuriuos atsisiuntėte naršyklėje „Chrome“</translation>
@@ -1654,6 +1693,7 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="6290238015253830360">JÅ«sų pasiÅ«lyti straipsniai rodomi Äia</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">KortelÄ—s patvirtinimo kodas CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{Jūsų įrenginys dabar bus paleistas iš naujo}=1{Jūsų įrenginys bus paleistas iš naujo po vienos sekundės}one{Jūsų įrenginys bus paleistas iš naujo po # sekundės}few{Jūsų įrenginys bus paleistas iš naujo po # sekundžių}many{Jūsų įrenginys bus paleistas iš naujo po # sekundės}other{Jūsų įrenginys bus paleistas iš naujo po # sekundžių}}</translation>
<translation id="6302269476990306341">„Google“ padėjėjas sistemoje „Chrome“ sustabdomas</translation>
<translation id="6305205051461490394"><ph name="URL" /> nepasiekiama.</translation>
<translation id="6312113039770857350">Tinklalapis nepasiekiamas</translation>
@@ -1727,6 +1767,7 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="6529602333819889595">&amp;IÅ¡trinti dar kartÄ…</translation>
<translation id="6545864417968258051">„Bluetooth“ nuskaitymas</translation>
<translation id="6547208576736763147">Dvi skylÄ—s kairÄ—je</translation>
+<translation id="6554732001434021288">Paskutinį kartą lankytasi prieš <ph name="NUM_DAYS" /> d.</translation>
<translation id="6556866813142980365">Grąžinti</translation>
<translation id="6569060085658103619">Peržiūrite plėtinio puslapį</translation>
<translation id="6573200754375280815">Dvi skylės dešinėje</translation>
@@ -1787,7 +1828,6 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="6757797048963528358">Įjungta įrenginio miego būsena.</translation>
<translation id="6767985426384634228">Atnaujinti adresÄ…?</translation>
<translation id="6768213884286397650">„Hagaki“ (atvirukas)</translation>
-<translation id="6774185088257932239"><ph name="BEGIN_LINK" />Sužinokite daugiau<ph name="END_LINK" /> apie inkognito režimą.</translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">VioletinÄ—</translation>
<translation id="6786747875388722282">PlÄ—tiniai</translation>
@@ -1871,7 +1911,6 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="706295145388601875">Pridėkite ir tvarkykite adresus „Chrome“ nustatymuose</translation>
<translation id="7064851114919012435">KontaktinÄ— informacija</translation>
<translation id="7068733155164172741">Įveskite <ph name="OTP_LENGTH" /> skaitm. kodą</translation>
-<translation id="7070090581017165256">Apie Å¡iÄ… svetainÄ™</translation>
<translation id="70705239631109039">Jūsų ryšys nėra visiškai saugus</translation>
<translation id="7075452647191940183">Užklausa per didelė</translation>
<translation id="7079718277001814089">Šioje svetainėje yra kenkėjiškų programų</translation>
@@ -1888,6 +1927,12 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="7111012039238467737">(tinkamas)</translation>
<translation id="7118618213916969306">Ieškoti iškarpinės URL, <ph name="SHORT_URL" /></translation>
<translation id="7119414471315195487">Uždarykite kitus skirtukus ir programas</translation>
+<translation id="7129355289156517987">Kai uždarote visus „Chromium“ inkognito skirtukus, iš šio įrenginio išvaloma jūsų veikia toliau nurodytuose skirtukuose.
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Naršymo veikla<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Paieškos istorija<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Formose įvesta informacija<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">Negalima pristatyti Å¡iuo adresu. Pasirinkite kitÄ… adresÄ….</translation>
<translation id="7132939140423847331">Jūsų administratorius uždraudė kopijuoti šiuos duomenis.</translation>
<translation id="7135130955892390533">Rodyti būseną</translation>
@@ -1910,6 +1955,7 @@ Kitu atveju tai bus užblokuota pagal jūsų privatumo nustatymus. Taip turinys,
<translation id="7192203810768312527">Atlaisvina <ph name="SIZE" />. Per kitÄ… jÅ«sų apsilankymÄ… kai kurios svetainÄ—s gali bÅ«ti įkeliamos lÄ—Äiau.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">Administratorius gali peržiūrėti:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, paspauskite tabuliavimo klavišą, tada – „Enter“, kad būtų atidarytas naujas privataus naršymo inkognito skirtukas</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> nesilaikoma saugos standartų.</translation>
<translation id="7210993021468939304">„Linux“ veikla sudėtiniame rodinyje; ir gali įdiegti ir paleisti „Linux“ programas sudėtiniame rodinyje</translation>
@@ -1941,6 +1987,7 @@ Papildoma išsami informacija:
<translation id="7304562222803846232">Tvarkyti „Google“ paskyros privatumo nustatymus</translation>
<translation id="7305756307268530424">PradÄ—ti lÄ—Äiau</translation>
<translation id="7308436126008021607">fono sinchronizavimas</translation>
+<translation id="7310392214323165548">Įrenginys netrukus bus paleistas iš naujo</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">Su ryšiu susijusi pagalba</translation>
<translation id="7323804146520582233">Slėpti skiltį „<ph name="SECTION" />“</translation>
@@ -1948,6 +1995,7 @@ Papildoma išsami informacija:
<translation id="7334320624316649418">&amp;Pertvarkyti dar kartÄ…</translation>
<translation id="7335157162773372339">Gali būti prašoma naudoti fotoaparatą</translation>
<translation id="7337248890521463931">Rodyti daugiau eiluÄių</translation>
+<translation id="7337418456231055214">Virtualios kortelės numeris neįvestas? Spustelėkite išsamią kortelės informaciją, kad nukopijuotumėte. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">Nepasiekiama jūsų platformoje.</translation>
<translation id="733923710415886693">Serverio sertifikatas nebuvo atskleistas taikant sertifikato skaidrumÄ….</translation>
<translation id="734600844861828519">11 x 15</translation>
@@ -1970,6 +2018,7 @@ Papildoma išsami informacija:
<translation id="7378627244592794276">Ne</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">Netaikoma</translation>
+<translation id="7388594495505979117">{0,plural, =1{Ä®renginys bus paleistas iÅ¡ naujo po vienos minutÄ—s}one{Ä®renginys bus paleistas iÅ¡ naujo po # minutÄ—s}few{Ä®renginys bus paleistas iÅ¡ naujo po # minuÄių}many{Ä®renginys bus paleistas iÅ¡ naujo po # minutÄ—s}other{Ä®renginys bus paleistas iÅ¡ naujo po # minuÄių}}</translation>
<translation id="7390545607259442187">KortelÄ—s patvirtinimas</translation>
<translation id="7392089738299859607">Adreso atnaujinimas</translation>
<translation id="7399802613464275309">Saugos patikra</translation>
@@ -2006,6 +2055,12 @@ Papildoma išsami informacija:
<translation id="7485870689360869515">Nerasta jokių duomenų.</translation>
<translation id="7495528107193238112">Šis turinys užblokuotas. Susisiekite su svetainės savininku, kad išspręstų problemą.</translation>
<translation id="7497998058912824456">Mygtukas „Sukurti dokumentą“ – paspauskite klavišą „Enter“, jei norite greitai sukurti naują „Google“ dokumentą</translation>
+<translation id="7506488012654002225">„Chromium“ <ph name="BEGIN_EMPHASIS" />nesaugos<ph name="END_EMPHASIS" /> šios informacijos:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />naršymo istorijos;
+ <ph name="LIST_ITEM" />slapukų ir svetainių duomenų;
+ <ph name="LIST_ITEM" />formose įvestos informacijos.
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">Sugrąžinto politikos įrenginio ID nenurodytas arba neatitinka dabartinio įrenginio ID</translation>
<translation id="7508870219247277067">Avokado žalia</translation>
<translation id="7511955381719512146">Naudojant šį „Wi-Fi“ tinklą gali būti prašoma apsilankyti <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
@@ -2119,7 +2174,6 @@ Papildoma išsami informacija:
<translation id="7813600968533626083">Pašalinti formos pasiūlymą iš „Chrome“?</translation>
<translation id="781440967107097262">Bendrinti iškarpinę?</translation>
<translation id="7815407501681723534">Pagal terminą „<ph name="SEARCH_STRING" />“ surasta tiek <ph name="SEARCH_RESULTS" />: <ph name="NUMBER_OF_RESULTS" /></translation>
-<translation id="782125616001965242">Rodyti informacijÄ… apie Å¡iÄ… svetainÄ™</translation>
<translation id="782886543891417279">Naudojant šį „Wi-Fi“ tinklą („<ph name="WIFI_NAME" />“) gali būti prašoma apsilankyti prisijungimo puslapyje.</translation>
<translation id="7836231406687464395">„Postfix“ (vokas)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{Nėra}=1{1 programa („<ph name="EXAMPLE_APP_1" />“)}=2{2 programos („<ph name="EXAMPLE_APP_1" />“, „<ph name="EXAMPLE_APP_2" />“)}one{# programa („<ph name="EXAMPLE_APP_1" />“, „<ph name="EXAMPLE_APP_2" />“ <ph name="AND_MORE" />)}few{# programos („<ph name="EXAMPLE_APP_1" />“, „<ph name="EXAMPLE_APP_2" />“ <ph name="AND_MORE" />)}many{# programos („<ph name="EXAMPLE_APP_1" />“, „<ph name="EXAMPLE_APP_2" />“ <ph name="AND_MORE" />)}other{# programų („<ph name="EXAMPLE_APP_1" />“, „<ph name="EXAMPLE_APP_2" />“ <ph name="AND_MORE" />)}}</translation>
@@ -2136,7 +2190,6 @@ Papildoma išsami informacija:
<translation id="7888575728750733395">Spausdinimo pateikimo tikslas</translation>
<translation id="7894280532028510793">Jei parašyta tinkamai, <ph name="BEGIN_LINK" />pabandykite paleisti tinklo diagnostiką<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (vokas)</translation>
-<translation id="7931318309563332511">Nežinoma</translation>
<translation id="793209273132572360">Atnaujinti adresÄ…?</translation>
<translation id="7932579305932748336">Danga</translation>
<translation id="79338296614623784">Įveskite tinkamą telefono numerį</translation>
@@ -2161,13 +2214,14 @@ Papildoma išsami informacija:
<translation id="7976214039405368314">Per daug užklausų</translation>
<translation id="7977538094055660992">Išvesties įrenginys</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">Susieta su</translation>
<translation id="798134797138789862">Gali būti prašoma naudoti virtualiosios realybės įrenginius ir duomenis</translation>
<translation id="7984945080620862648">Negalite dabar apsilankyti svetainėje <ph name="SITE" />, nes ji atsiuntė užšifruotus prisijungimo duomenis, kurių „Chrome“ negali apdoroti. Tinklo klaidos ir užpuolimai dažniausiai yra laikini, todėl šis puslapis vėliau tikriausiai veiks.</translation>
-<translation id="79859296434321399">Norėdami peržiūrėti išplėstosios realybės turinį įdiekite „ARCore“</translation>
<translation id="7986319120639858961">„<ph name="CARD_TITLE" />“ <ph name="TIME" /> <ph name="BOOKMARKED" /> „<ph name="TITLE" />“ <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">Įrišimas</translation>
<translation id="7992044431894087211">Ekrano bendrinimas su „<ph name="APPLICATION_TITLE" />“ tęsiamas</translation>
<translation id="7995512525968007366">Nenurodytas</translation>
+<translation id="7998269595945679889">Atidarykite inkognito skirtuką, paspauskite „Enter“, kad būtų atidarytas naujas privataus naršymo inkognito skirtukas</translation>
<translation id="800218591365569300">Pabandykite uždaryti skirtukus arba kitas programas, kad atlaisvintumėte atminties.</translation>
<translation id="8004582292198964060">Naršyklė</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{Ši kortelė ir jos atsiskaitymo adresas bus išsaugoti. Ją galėsite naudoti prisijungę prie <ph name="USER_EMAIL" />.}one{Šios kortelės ir jų atsiskaitymo adresai bus išsaugoti. Jas galėsite naudoti prisijungę prie <ph name="USER_EMAIL" />.}few{Šios kortelės ir jų atsiskaitymo adresai bus išsaugoti. Jas galėsite naudoti prisijungę prie <ph name="USER_EMAIL" />.}many{Šios kortelės ir jų atsiskaitymo adresai bus išsaugoti. Jas galėsite naudoti prisijungę prie <ph name="USER_EMAIL" />.}other{Šios kortelės ir jų atsiskaitymo adresai bus išsaugoti. Jas galėsite naudoti prisijungę prie <ph name="USER_EMAIL" />.}}</translation>
@@ -2227,6 +2281,7 @@ Papildoma išsami informacija:
<translation id="8202370299023114387">Konfliktas</translation>
<translation id="8206978196348664717">„Prc4“ (vokas)</translation>
<translation id="8211406090763984747">Ryšys saugus</translation>
+<translation id="8217240300496046857">SvetainÄ—s negali naudoti slapukų, stebinÄių jus žiniatinklyje. Funkcijos gali neveikti tam tikrose svetainÄ—se.</translation>
<translation id="8218327578424803826">Priskirta vieta:</translation>
<translation id="8220146938470311105">C7 / C6 (vokas)</translation>
<translation id="8225771182978767009">Šį kompiuterį nustatęs asmuo pasirinko blokuoti šią svetainę.</translation>
@@ -2267,14 +2322,9 @@ Papildoma išsami informacija:
<translation id="830498451218851433">Perlenkimas per pusÄ™</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">Įdiegtos programos ir kaip dažnai jos naudojamos</translation>
+<translation id="8317207217658302555">Atnaujinti „ARCore“?</translation>
<translation id="831997045666694187">Vakaras</translation>
<translation id="8321476692217554900">pranešimai</translation>
-<translation id="8328484624016508118">Uždarius visus inkognito skirtukus, „Chrome“ išvalo:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />naršymo veiklą iš šio įrenginio;<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />paieškos istoriją iš šio įrenginio;<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />formose įvestą informaciją.<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489">Prieiga prie <ph name="HOST_NAME" /> atmesta</translation>
<translation id="833262891116910667">Paryškinti</translation>
<translation id="8339163506404995330">Puslapiai, paraÅ¡yti <ph name="LANGUAGE" />, verÄiami nebus</translation>
@@ -2326,6 +2376,7 @@ Papildoma išsami informacija:
<translation id="8507227106804027148">Komandos eilutÄ—</translation>
<translation id="8508648098325802031">Paieškos piktograma</translation>
<translation id="8511402995811232419">Tvarkyti slapukus</translation>
+<translation id="8519753333133776369">Administratorius leidžia naudoti HID įrenginį</translation>
<translation id="8522552481199248698">„Chrome“ gali padėti apsaugoti „Google“ paskyrą ir pakeisti slaptažodį.</translation>
<translation id="8530813470445476232">Išvalykite naršymo istoriją, slapukus, talpyklą ir kita „Chrome“ nustatymuose</translation>
<translation id="8533619373899488139">Apsilankykite adresu &lt;strong&gt;chrome://policy&lt;/strong&gt;, kad peržiūrėtumėte užblokuotų URL sąrašą ir kitą politiką, kurią taiko sistemos administratoriaus.</translation>
@@ -2337,7 +2388,6 @@ Papildoma išsami informacija:
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{IÅ¡ naujo nustatyti leidimÄ…}one{IÅ¡ naujo nustatyti leidimus}few{IÅ¡ naujo nustatyti leidimus}many{IÅ¡ naujo nustatyti leidimus}other{IÅ¡ naujo nustatyti leidimus}}</translation>
<translation id="8555010941760982128">Naudokite šį kodą atsiskaitydami</translation>
<translation id="8557066899867184262">KortelÄ—s saugos kodas (CVC) nurodytas kitoje kortelÄ—s pusÄ—je.</translation>
-<translation id="8558485628462305855">Norėdami peržiūrėti išplėstosios realybės turinį atnaujinkite „ARCore“</translation>
<translation id="8559762987265718583">Nepavyksta užmegzti privataus ryšio su <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />, nes įrenginio data ir laikas (<ph name="DATE_AND_TIME" />) yra netinkami.</translation>
<translation id="8564182942834072828">Atskiras dokumentas / nesugretintos kopijos</translation>
<translation id="8564985650692024650">„Chromium“ rekomenduoja iš naujo nustatyti <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> slaptažodį, jei naudojate jį kitose svetainėse.</translation>
@@ -2357,6 +2407,7 @@ Papildoma išsami informacija:
<translation id="865032292777205197">judesio jutikliai</translation>
<translation id="8663226718884576429">Užsakymo suvestinė, <ph name="TOTAL_LABEL" />, daugiau informacijos</translation>
<translation id="8666678546361132282">Anglų</translation>
+<translation id="8669306706049782872">Naudoti informaciją apie ekranus, kad būtų galima atidaryti ir įdėti langų</translation>
<translation id="867224526087042813">Parašas</translation>
<translation id="8676424191133491403">Be delsos</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, atsakymas, <ph name="ANSWER" /></translation>
@@ -2383,6 +2434,7 @@ Papildoma išsami informacija:
<translation id="8731544501227493793">Mygtukas „Tvarkyti slaptažodžius“, paspauskite „Enter“, jei norite peržiūrėti ir tvarkyti slaptažodžius „Chrome“ nustatymuose</translation>
<translation id="8734529307927223492">Jūsų „<ph name="DEVICE_TYPE" />“ tvarko <ph name="MANAGER" /></translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, paspauskite tabuliavimo klavišą, tada – „Enter“, kad būtų atidarytas naujas privataus naršymo inkognito langas</translation>
+<translation id="8737685506611670901">Atidaryti „<ph name="PROTOCOL" />“ nuorodas vietoje „<ph name="REPLACED_HANDLER_TITLE" />“</translation>
<translation id="8738058698779197622">Jei norite užmegzti saugų ryšį, turėsite tinkamai nustatyti laikrodį. To reikalaujama todėl, kad svetainių tapatybei įrodyti naudojami sertifikatai galioja tik tam tikrą laikotarpį. Kadangi įrenginio laikrodis nustatytas netinkamai, „Chromium“ negali tinkamai patvirtinti sertifikatų.</translation>
<translation id="8740359287975076522">Nepavyko rasti <ph name="HOST_NAME" /> &lt;abbr id="dnsDefinition"&gt;DNS adreso&lt;/abbr&gt;. Nustatoma problema.</translation>
<translation id="8742371904523228557"><ph name="ONE_TIME_CODE" /> yra kodas, skirtas svetainei <ph name="ORIGIN" /></translation>
@@ -2410,6 +2462,7 @@ Papildoma išsami informacija:
<translation id="883848425547221593">Kitos žymės</translation>
<translation id="884264119367021077">Siuntimo adresas</translation>
<translation id="884923133447025588">Nerasta atšaukimo mechanizmo.</translation>
+<translation id="8849262850971482943">Naudokite virtualią kortelę didesnei saugai užtikrinti</translation>
<translation id="885730110891505394">Bendrinimas su „Google“</translation>
<translation id="8858065207712248076">„Chrome“ rekomenduoja iš naujo nustatyti <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> slaptažodį, jei naudojate jį kitose svetainėse.</translation>
<translation id="885906927438988819">Jei parašyta tinkamai, <ph name="BEGIN_LINK" />pabandykite paleisti „Windows“ tinklo diagnostiką<ph name="END_LINK" />.</translation>
@@ -2459,6 +2512,7 @@ Papildoma išsami informacija:
<translation id="9004367719664099443">Vyksta VR sesija</translation>
<translation id="9005998258318286617">PDF dokumento įkelti nepavyko.</translation>
<translation id="9008201768610948239">Nepaisyti</translation>
+<translation id="901834265349196618">El. paštas</translation>
<translation id="9020200922353704812">BÅ«tina pateikti kortelÄ—s atsiskaitymo adresÄ…</translation>
<translation id="9020542370529661692">Šis puslapis išverstas į <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9020742383383852663">A8</translation>
@@ -2507,6 +2561,7 @@ Papildoma išsami informacija:
<translation id="9150045010208374699">Naudoti kamerÄ…</translation>
<translation id="9150685862434908345">Administratorius gali nuotoliniu būdu keisti naršyklės sąranką. Veiklą šiame įrenginyje taip pat galima tvarkyti ne naršyklėje „Chrome“. <ph name="BEGIN_LINK" />Sužinokite daugiau<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">Atnaujinta</translation>
+<translation id="9155211586651734179">Pridėti garso įrenginiai</translation>
<translation id="9157595877708044936">Nustatoma...</translation>
<translation id="9158625974267017556">C6 (vokas)</translation>
<translation id="9164029392738894042">Tikslumo patikra</translation>
diff --git a/chromium/components/strings/components_strings_lv.xtb b/chromium/components/strings/components_strings_lv.xtb
index 818883350b1..c966a67aedb 100644
--- a/chromium/components/strings/components_strings_lv.xtb
+++ b/chromium/components/strings/components_strings_lv.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">SkatÄ«t informÄciju</translation>
<translation id="1030706264415084469">VietnÄ“ <ph name="URL" /> tika pieprasÄ«ta atļauja pastÄvÄ«gi glabÄt jÅ«su ierÄ«cÄ“ lielu datu apjomu.</translation>
<translation id="1032854598605920125">Pagriezt pulksteņrÄdÄ«tÄju kustÄ«bas virzienÄ</translation>
+<translation id="1033329911862281889">Inkognito režīms nenozīmē, ka jūs tiešsaistē būsiet neredzams:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />vietnes un to izmantotie pakalpojumi var redzēt jūsu apmeklējumus;<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />darba devÄ“ji vai mÄcÄ«bu iestÄdes var izsekot pÄrlÅ«koÅ¡anas darbÄ«bas;<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />interneta pakalpojumu sniedzēji var uzraudzīt tīmekļa datplūsmu.<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">Izslēgt</translation>
<translation id="1036982837258183574">Lai izietu no pilnekrÄna režīma, nospiediet |<ph name="ACCELERATOR" />|.</translation>
<translation id="1038106730571050514">RÄdÄ«t ieteikumus</translation>
<translation id="1038842779957582377">nezinÄms nosaukums</translation>
<translation id="1041998700806130099">Uzdevuma lapas ziņojums</translation>
<translation id="1048785276086539861">Ja rediģēsiet piezÄ«mes, dokuments atkal pÄries vienas lapas skatÄ.</translation>
-<translation id="1049743911850919806">Inkognito</translation>
<translation id="1050038467049342496">Aizveriet citas lietotnes</translation>
<translation id="1055184225775184556">&amp;Pievienošanas atsaukšana</translation>
<translation id="1056898198331236512">BrÄ«dinÄjums</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">Politikas keÅ¡atmiņa ir labÄ stÄvoklÄ«.</translation>
<translation id="1130564665089811311">Poga “Tulkot lapuâ€. Lai pÄrtulkotu Å¡o lapu, izmantojot Google tulkotÄju, nospiediet ievadÄ«Å¡anas taustiņu.</translation>
<translation id="1131264053432022307">Kopētais attēls</translation>
+<translation id="1142846828089312304">Inkognito režīmÄ bloÄ·Ä“t treÅ¡o puÅ¡u sÄ«kfailus</translation>
<translation id="1150979032973867961">Å is serveris nevarÄ“ja pierÄdÄ«t, ka Å¡Ä« ir vietne <ph name="DOMAIN" />; tÄs droÅ¡Ä«bas sertifikÄts netiek uzskatÄ«ts par uzticamu jÅ«su datora operÄ“tÄjsistÄ“mÄ. IespÄ“jams, tas ir nepareizas konfigurÄcijas dēļ vai arÄ« kÄds ir ļaunprÄtÄ«gi izmantojis jÅ«su savienojumu.</translation>
<translation id="1151972924205500581">Nepieciešama parole</translation>
<translation id="1156303062776767266">JÅ«s skatÄt vietÄ“ju vai kopÄ«gotu failu</translation>
@@ -64,7 +70,6 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="1178581264944972037">Pauzēt</translation>
<translation id="1181037720776840403">Noņemt</translation>
<translation id="1186201132766001848">PÄrbaudÄ«t paroles</translation>
-<translation id="1195210374336998651">PÄriet uz lietotnes iestatÄ«jumiem</translation>
<translation id="1195558154361252544">Paziņojumi tiek automÄtiski bloÄ·Ä“ti visÄs vietnÄ“s, izņemot tÄs, kurÄs atļÄvÄt to rÄdÄ«Å¡anu.</translation>
<translation id="1197088940767939838">Oranža</translation>
<translation id="1201402288615127009">TÄlÄk</translation>
@@ -111,7 +116,7 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="1307966114820526988">Funkcijas, kuru darbÄ«ba ir pÄrtraukta</translation>
<translation id="1308113895091915999">Pieejams piedÄvÄjums</translation>
<translation id="1312803275555673949">KÄda informÄcija to pierÄda?</translation>
-<translation id="131405271941274527"><ph name="URL" /> vÄ“las sÅ«tÄ«t un saņemt informÄciju, kad ar tÄlruni pieskaraties NFC ierÄ«cei</translation>
+<translation id="1314311879718644478">Skatiet papildinÄtÄs realitÄtes saturu</translation>
<translation id="1314509827145471431">IesÄ“jums labajÄ pusÄ“</translation>
<translation id="1318023360584041678">SaglabÄts ciļņu grupÄ</translation>
<translation id="1319245136674974084">Vairs nejautÄt par Å¡o lietotni</translation>
@@ -161,6 +166,7 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="142858679511221695">MÄkoņa lietotÄjs</translation>
<translation id="1428729058023778569">Å is brÄ«dinÄjums tiek rÄdÄ«ts, jo Å¡ajÄ vietnÄ“ netiek atbalstÄ«ts HTTPS. <ph name="BEGIN_LEARN_MORE_LINK" />Uzziniet vairÄk<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="1430915738399379752">DrukÄt</translation>
+<translation id="1432187715652018471">lapa vÄ“las instalÄ“t pakalpojumu apdarinÄtÄju.</translation>
<translation id="1432581352905426595">PÄrvaldÄ«t meklÄ“jumprogrammas</translation>
<translation id="1436185428532214179">Var pieprasīt atļauju rediģēt failus un mapes jūsu ierīcē</translation>
<translation id="1442386063175183758">Abpusējs locījums pa labi</translation>
@@ -181,6 +187,12 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="1483493594462132177">Sūtīt</translation>
<translation id="1484290072879560759">Izvēlēties nosūtīšanas adresi</translation>
<translation id="1492194039220927094">Politiku informatīvie ziņojumi:</translation>
+<translation id="149293076951187737">Kad aizvÄ“rsiet visas Chrome inkognito cilnes, no Å¡Ä«s ierÄ«ces tiks notÄ«rÄ«tas Å¡ajÄs cilnÄ“s veiktÄs darbÄ«bas:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />pÄrlÅ«koÅ¡anas darbÄ«bas;<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />meklēšanas vēsture;<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />veidlapÄs ievadÄ«tÄ informÄcija.<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">Atgriezties cilnē</translation>
<translation id="1501859676467574491">RÄdÄ« kartes no mana Google konta</translation>
<translation id="1507202001669085618">&lt;p&gt;Å is kļūdas ziņojums tiek rÄdÄ«ts, ja izmantojat Wi-Fi portÄlu, kurÄ ir jÄpierakstÄs, lai varÄ“tu pÄriet tieÅ¡saistÄ“.&lt;/p&gt;
@@ -208,6 +220,8 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="1559572115229829303">&lt;p&gt;Nevar izveidot privÄtu savienojumu ar <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />, jo jÅ«su ierÄ«ces datums un laiks (<ph name="DATE_AND_TIME" />) nav pareizi.&lt;/p&gt;
&lt;p&gt;LÅ«dzu, koriģējiet datumu un laiku lietotnes &lt;strong&gt;IestatÄ«jumi&lt;/strong&gt; sadaÄ¼Ä &lt;strong&gt;VispÄrÄ«gi&lt;/strong&gt;.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">JÅ«su administrators restartÄ“s jÅ«su ierÄ«ci plkst. <ph name="TIME" /> Å¡ÄdÄ datumÄ: <ph name="DATE" />.</translation>
+<translation id="156703335097561114">TÄ«kloÅ¡anas informÄcija, piemÄ“ram, adreses, saskarnes konfigurÄcija, savienojuma kvalitÄte</translation>
<translation id="1567040042588613346">Å Ä« politika darbojas, kÄ paredzÄ“ts, taÄu citur ir iestatÄ«ta tÄda pati vÄ“rtÄ«ba, kas tiek ignorÄ“ta Å¡Ä«s politikas dēļ.</translation>
<translation id="1569487616857761740">Ievadīt derīguma termiņu</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="1583429793053364125">Å Ä«s tÄ«mekļa lapas rÄdÄ«Å¡anas laikÄ radÄs kļūda.</translation>
<translation id="1586541204584340881">Kurus paplaÅ¡inÄjumus esat instalÄ“jis</translation>
<translation id="1588438908519853928">Parasts</translation>
+<translation id="1589050138437146318">Vai instalēt ARCore?</translation>
<translation id="1592005682883173041">Piekļuve lokÄlajiem datiem</translation>
<translation id="1594030484168838125">Izvēlēties</translation>
<translation id="160851722280695521">SpÄ“lÄ“t dinozaura skrieÅ¡anas spÄ“li pÄrlÅ«kÄ Chrome</translation>
@@ -254,7 +269,7 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="1711234383449478798">IgnorÄ“ta, jo politikai “<ph name="POLICY_NAME" />†nav iestatÄ«ta vÄ“rtÄ«ba “<ph name="VALUE" />â€.</translation>
<translation id="1712552549805331520">VietnÄ“ <ph name="URL" /> tika pieprasÄ«ta atļauja pastÄvÄ«gi glabÄt datus lokÄlajÄ datorÄ.</translation>
<translation id="1713628304598226412">2. paplÄte</translation>
-<translation id="1715874602234207">F</translation>
+<translation id="1715874602234207">P</translation>
<translation id="1717218214683051432">Kustību sensori</translation>
<translation id="1717494416764505390">3. pastkaste</translation>
<translation id="1718029547804390981">Dokuments ir pÄrÄk liels, tÄdēļ tam nevar pievienot piezÄ«mes</translation>
@@ -283,6 +298,7 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
galvene ir nepareizi izveidota, kas neļauj pÄrlÅ«kam izpildÄ«t
jūsu pieprasījumu vietnei <ph name="SITE" />. Vietņu operatori var izmantot
izcelsmes politikas, lai konfigurētu drošību un citus vietnes rekvizītus.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />UzzinÄt vairÄk par inkognito režīmu pÄrlÅ«kÄ Chromium<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">Å eit tiks parÄdÄ«tas jÅ«su atvÄ“rtÄs cilnes</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -410,6 +426,7 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="22081806969704220">3. paplÄte</translation>
<translation id="2212735316055980242">Politika netika atrasta.</translation>
<translation id="2213606439339815911">Notiek ierakstu ienešana...</translation>
+<translation id="2213612003795704869">Lapa ir izdrukÄta</translation>
<translation id="2215727959747642672">Faila rediģēšana</translation>
<translation id="2218879909401188352">UzbrucÄ“ji vietnÄ“ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> varÄ“tu instalÄ“t bÄ«stamas lietotnes, kas bojÄ jÅ«su ierÄ«ci, rada slÄ“ptas izmaksas mobilÄ tÄlruņa rÄ“Ä·inÄ vai zog jÅ«su personas informÄciju. <ph name="BEGIN_LEARN_MORE_LINK" />Uzziniet vairÄk<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2224337661447660594">Nav interneta savienojuma</translation>
@@ -419,6 +436,7 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="2248949050832152960">Izmantot WebAuthn</translation>
<translation id="2250931979407627383">Malu saÅ¡uvums kreisajÄ pusÄ“</translation>
<translation id="225207911366869382">Šī vērtība vairs netiek atbalstīta šai politikai.</translation>
+<translation id="2256115617011615191">Restartēt tūlīt</translation>
<translation id="2258928405015593961">Ievadiet derÄ«guma termiņu, kas ir nÄkotnÄ“, un mÄ“Ä£iniet vÄ“lreiz.</translation>
<translation id="225943865679747347">Kļūdas kods: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">HTTP kļūda</translation>
@@ -446,6 +464,7 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="2337852623177822836">Iestatījumu kontrolē jūsu administrators</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> vÄ“las savienot pÄrÄ«</translation>
<translation id="2346319942568447007">Kopētais attēls</translation>
+<translation id="2350796302381711542">Vai ļaut <ph name="HANDLER_HOSTNAME" /> atvÄ“rt visas <ph name="PROTOCOL" /> saites <ph name="REPLACED_HANDLER_TITLE" /> vietÄ?</translation>
<translation id="2354001756790975382">Citas grÄmatzÄ«mes</translation>
<translation id="2354430244986887761">Izmantojot Google droÅ¡o pÄrlÅ«koÅ¡anu, nesen <ph name="BEGIN_LINK" />tika atrastas kaitÄ«gas lietotnes<ph name="END_LINK" /> vietnÄ“ <ph name="SITE" />.</translation>
<translation id="2355395290879513365">UzbrucÄ“ji var skatÄ«t attÄ“lus, kurus skatÄt Å¡ajÄ vietnÄ“, un apmÄnÄ«t jÅ«s, pÄrveidojot Å¡os attÄ“lus.</translation>
@@ -471,6 +490,7 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="2413528052993050574">Å is serveris nevarÄ“ja pierÄdÄ«t, ka Å¡Ä« ir vietne <ph name="DOMAIN" />; tÄs droÅ¡Ä«bas sertifikÄts, iespÄ“jams, ir atsaukts. IespÄ“jams, tas ir nepareizas konfigurÄcijas dēļ vai arÄ« kÄds ir ļaunprÄtÄ«gi izmantojis jÅ«su savienojumu.</translation>
<translation id="2414886740292270097">Tumšs</translation>
<translation id="2430968933669123598">Google konta pÄrvaldÄ«ba. Lai pÄrvaldÄ«tu savu informÄciju, konfidencialitÄti un droÅ¡Ä«bu savÄ Google kontÄ, nospiediet taustiņu Enter.</translation>
+<translation id="2436186046335138073">Vai atļaut <ph name="HANDLER_HOSTNAME" /> atvērt visas <ph name="PROTOCOL" /> saites?</translation>
<translation id="2438874542388153331">ÄŒetri caurumi labajÄ pusÄ“</translation>
<translation id="2450021089947420533">Meklēšanas ceļi</translation>
<translation id="2463739503403862330">Aizpildīt</translation>
@@ -478,6 +498,7 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="2465655957518002998">IzvÄ“lÄ“ties piegÄdes veidu</translation>
<translation id="2465688316154986572">Skavojums</translation>
<translation id="2465914000209955735">PÄrvaldÄ«t pÄrlÅ«kÄ Chrome lejupielÄdÄ“tos failus</translation>
+<translation id="2466004615675155314">RÄdÄ«t informÄciju no tÄ«mekļa</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Palaist tīkla diagnostiku<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">Secība: no 1 līdz N</translation>
<translation id="2470767536994572628">Ja rediģēsiet piezÄ«mes, dokuments atkal pÄries vienas lapas skatÄ un rotÄcija tiks atiestatÄ«ta.</translation>
@@ -498,6 +519,7 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="2523886232349826891">Tiks saglabÄta tikai Å¡ajÄ ierÄ«cÄ“</translation>
<translation id="2524461107774643265">Papildu informÄcijas pievienoÅ¡ana</translation>
<translation id="2529899080962247600">Å ajÄ laukÄ drÄ«kst bÅ«t ne vairÄk kÄ <ph name="MAX_ITEMS_LIMIT" /> ierakstu. Visi turpmÄkie ieraksti tiks ignorÄ“ti.</translation>
+<translation id="2535585790302968248">AtvÄ“rt jaunu inkognito cilni privÄtai pÄrlÅ«koÅ¡anai</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{un vēl 1}zero{un vēl #}one{un vēl #}other{un vēl #}}</translation>
<translation id="2536110899380797252">Pievienot adresi</translation>
<translation id="2539524384386349900">Noteikt</translation>
@@ -523,7 +545,14 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="2597378329261239068">Å is dokuments ir aizsargÄts ar paroli. LÅ«dzu, ievadiet paroli.</translation>
<translation id="2609632851001447353">Varianti</translation>
<translation id="2610561535971892504">NoklikÅ¡Ä·inÄt, lai kopÄ“tu</translation>
+<translation id="2617988307566202237">PÄrlÅ«kÄ Chrome <ph name="BEGIN_EMPHASIS" />netiks saglabÄta<ph name="END_EMPHASIS" /> Å¡Äda informÄcija:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />jÅ«su pÄrlÅ«koÅ¡anas vÄ“sture;
+ <ph name="LIST_ITEM" />sīkfaili un vietņu dati;
+ <ph name="LIST_ITEM" />veidlapÄs ievadÄ«tÄ informÄcija.
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (aploksne)</translation>
+<translation id="2623663032199728144">Var pieprasÄ«t atļauju izmantot informÄciju par jÅ«su ekrÄniem</translation>
<translation id="2625385379895617796">NorÄdÄ«tais laiks ir pÄrÄk tÄlu nÄkotnÄ“</translation>
<translation id="262745152991669301">Var pieprasīt atļauju veidot savienojumu ar USB ierīcēm</translation>
<translation id="2629325967560697240">Lai pÄrlÅ«kprogrammÄ Chrome izmantotu visaugstÄko droÅ¡Ä«bas lÄ«meni, <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />ieslÄ“dziet uzlaboto aizsardzÄ«bu<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -557,6 +586,7 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="2709516037105925701">AutomÄtiskÄ aizpilde</translation>
<translation id="2713444072780614174">Balta</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />. Lai pÄrvaldÄ«tu savus maksÄjumus un kredÄ«tkarÅ¡u informÄciju Chrome iestatÄ«jumos, nospiediet tabulÄ“Å¡anas taustiņu un pÄ“c tam — ievadÄ«Å¡anas taustiņu.</translation>
+<translation id="271663710482723385">Nospiediet |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />|, lai izietu no pilnekrÄna režīma.</translation>
<translation id="2721148159707890343">Pieprasījums bija veiksmīgs.</translation>
<translation id="2723669454293168317">Veiciet droÅ¡Ä«bas pÄrbaudi Chrome iestatÄ«jumos.</translation>
<translation id="2726001110728089263">SÄnu paplÄte</translation>
@@ -587,6 +617,7 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="2850739647070081192">Invite (aploksne)</translation>
<translation id="2856444702002559011">IespÄ“jams, uzbrucÄ“ji mÄ“Ä£ina nozagt jÅ«su informÄciju no vietnes <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (piemÄ“ram, paroles, ziņojumus vai kredÄ«tkarÅ¡u datus). <ph name="BEGIN_LEARN_MORE_LINK" />Uzziniet vairÄk<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="2859806420264540918">Å ajÄ vietnÄ“ tiek rÄdÄ«tas traucÄ“joÅ¡as vai maldinoÅ¡as reklÄmas.</translation>
+<translation id="286512204874376891">VirtuÄla karte nomaskÄ“ jÅ«su patieso karti, lai efektÄ«vÄk aizsargÄtu jÅ«s pret iespÄ“jamu krÄpÅ¡anu. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">Draudzīga</translation>
<translation id="2876489322757410363">Ja maksÄÅ¡anai tiks izmantota ÄrÄ“ja lietojumprogramma, tiks aizvÄ“rts inkognito režīms. Vai turpinÄt?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />. Lai Chrome iestatÄ«jumos pÄrvaldÄ«tu funkciju “DroÅ¡a pÄrlÅ«koÅ¡ana†un citas funkcijas, nospiediet tabulÄ“Å¡anas taustiņu un pÄ“c tam — taustiņu Enter.</translation>
@@ -611,6 +642,7 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="2930577230479659665">Apgriešana pēc katras kopijas</translation>
<translation id="2932085390869194046">Ieteikt paroli...</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019">atvērt <ph name="PROTOCOL" /> saites</translation>
<translation id="2941952326391522266">Å is serveris nevarÄ“ja pierÄdÄ«t, ka Å¡Ä« ir vietne <ph name="DOMAIN" />; tÄs droÅ¡Ä«bas sertifikÄts ir saistÄ«ts ar domÄ“nu <ph name="DOMAIN2" />. IespÄ“jams, tas ir nepareizas konfigurÄcijas dēļ vai arÄ« kÄds ir ļaunprÄtÄ«gi izmantojis jÅ«su savienojumu.</translation>
<translation id="2943895734390379394">AugÅ¡upielÄdes laiks:</translation>
<translation id="2948083400971632585">IestatÄ«jumu lapÄ varat atspÄ“jot jebkurus starpniekserverus, kas konfigurÄ“ti savienojuma izveidei.</translation>
@@ -643,6 +675,7 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="3037605927509011580">Cilnes avÄrija.</translation>
<translation id="3041612393474885105">SertifikÄta informÄcija</translation>
<translation id="3044034790304486808">AtsÄkt izpÄ“ti</translation>
+<translation id="305162504811187366">Chrome attÄlÄs darbvirsmas vÄ“sture, tostarp laikspiedoli, saimniekdatori un klientu sesiju identifikatori</translation>
<translation id="3060227939791841287">C9 (aploksne)</translation>
<translation id="3061707000357573562">IelÄpu pakalpojums</translation>
<translation id="306573536155379004">SpÄ“le sÄkta.</translation>
@@ -683,6 +716,7 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="3197136577151645743">Var pieprasÄ«t informÄciju par to, kad jÅ«s aktÄ«vi lietojat Å¡o ierÄ«ci</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />: nospiediet tabulÄ“Å¡anas taustiņu un pÄ“c tam — ievadÄ«Å¡anas taustiņu, lai Chrome iestatÄ«jumos pÄrvaldÄ«tu, kÄda informÄcija tiek sinhronizÄ“ta.</translation>
<translation id="320323717674993345">Atcelt maksÄjumu</translation>
+<translation id="3203366800380907218">No tīmekļa</translation>
<translation id="3207960819495026254">AtzÄ«mÄ“ts kÄ grÄmatzÄ«me</translation>
<translation id="3209034400446768650">LapÄ var tikt iekasÄ“ta nauda</translation>
<translation id="3212581601480735796">JÅ«su veiktÄs darbÄ«bas pakalpojumÄ <ph name="HOSTNAME" /> tiek uzraudzÄ«tas</translation>
@@ -699,10 +733,12 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="3234666976984236645">VienmÄ“r noteikt nozÄ«mÄ«gu saturu Å¡ajÄ vietnÄ“</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />. Lai pielÄgotu pÄrlÅ«ka izskatu, nospiediet tabulÄ“Å¡anas taustiņu un pÄ“c tam — taustiņu Enter.</translation>
<translation id="3240791268468473923">Ir atvÄ“rta lapa ar akreditÄcijas datiem, kas neatbilst droÅ¡u maksÄjumu akreditÄcijas datiem</translation>
+<translation id="324180406144491771">“<ph name="HOST_NAME" />†saites ir bloķētas</translation>
<translation id="3249845759089040423">Moderna</translation>
<translation id="3252266817569339921">FranÄu valoda</translation>
<translation id="3257954757204451555">Kas ir Å¡Ä«s informÄcijas avots?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />. Lai Ätri izveidotu jaunu pasÄkumu Google kalendÄrÄ, nospiediet tabulÄ“Å¡anas taustiņu un pÄ“c tam — taustiņu Enter.</translation>
+<translation id="3261488570342242926">UzzinÄt vairÄk par virtuÄlajÄm kartÄ“m</translation>
<translation id="3264837738038045344">Poga Chrome iestatÄ«jumu pÄrvaldÄ«bai, lai apmeklÄ“tu Chrome iestatÄ«jumus, nospiediet taustiņu Enter</translation>
<translation id="3266793032086590337">Vērtība (konfliktē)</translation>
<translation id="3268451620468152448">AtvÄ“rtÄs cilnes</translation>
@@ -716,6 +752,7 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="3288238092761586174">IespÄ“jams, vietnÄ“ <ph name="URL" /> bÅ«s jÄveic papildu darbÄ«bas, lai apstiprinÄtu maksÄjumu.</translation>
<translation id="3293642807462928945">UzzinÄt vairÄk par politiku <ph name="POLICY_NAME" /></translation>
<translation id="3295444047715739395">Skatiet un pÄrvaldiet savas paroles Chrome iestatÄ«jumos.</translation>
+<translation id="3303795387212510132">Vai atļaut lietotnē atvērt <ph name="PROTOCOL_SCHEME" /> saites?</translation>
<translation id="3303855915957856445">Netika atrasts neviens meklÄ“Å¡anas rezultÄts.</translation>
<translation id="3304073249511302126">Bluetooth meklēšana</translation>
<translation id="3308006649705061278">OrganizacionÄlÄ vienÄ«ba (OU)</translation>
@@ -729,12 +766,6 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="3345782426586609320">Acis</translation>
<translation id="3355823806454867987">Mainīt starpniekservera iestatījumus...</translation>
<translation id="3360103848165129075">MaksÄjumu apstrÄdÄtÄja lapa</translation>
-<translation id="3361596688432910856">PÄrlÅ«kÄ Chrome <ph name="BEGIN_EMPHASIS" />netiks saglabÄta<ph name="END_EMPHASIS" /> Å¡Äda informÄcija:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />jÅ«su pÄrlÅ«koÅ¡anas vÄ“sture;
- <ph name="LIST_ITEM" />sīkfaili un vietņu dati;
- <ph name="LIST_ITEM" />veidlapÄs ievadÄ«tÄ informÄcija.
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">Å Ä« politika tika automÄtiski kopÄ“ta no novecojuÅ¡Äs <ph name="OLD_POLICY" /> politikas. Jums vajadzÄ“tu izmantot Å¡o politiku.</translation>
<translation id="3364869320075768271">Vietne <ph name="URL" /> vÄ“las izmantot jÅ«su virtuÄlÄs realitÄtes ierÄ«ci un datus.</translation>
<translation id="3366477098757335611">Skatīt kartes</translation>
@@ -817,7 +848,6 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="3587738293690942763">vidējais</translation>
<translation id="3592413004129370115">Italian (aploksne)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{JebkurÄ laikÄ varat atiestatÄ«t grupu. PievienoÅ¡anÄs jaunai grupai var ilgt aptuveni dienu.}=1{JebkurÄ laikÄ varat atiestatÄ«t grupu. PievienoÅ¡anÄs jaunai grupai var ilgt aptuveni dienu.}zero{JebkurÄ laikÄ varat atiestatÄ«t grupu. PievienoÅ¡anÄs jaunai grupai var ilgt {NUM_DAYS} dienas.}one{JebkurÄ laikÄ varat atiestatÄ«t grupu. PievienoÅ¡anÄs jaunai grupai var ilgt {NUM_DAYS} dienu.}other{JebkurÄ laikÄ varat atiestatÄ«t grupu. PievienoÅ¡anÄs jaunai grupai var ilgt {NUM_DAYS} dienas.}}</translation>
-<translation id="3596012367874587041">Lietotnes iestatījumi</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">Lietojumprogrammu bloķēja jūsu administrators</translation>
<translation id="3608932978122581043">Padeves virziens</translation>
@@ -859,6 +889,7 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="370972442370243704">Ieslēgt funkciju Meklēšanas ceļi</translation>
<translation id="3711895659073496551">Darbības apturēšana</translation>
<translation id="3712624925041724820">Nav pietiekami daudz licenÄu.</translation>
+<translation id="3714633008798122362">tÄ«mekļa kalendÄrs</translation>
<translation id="3714780639079136834">Ieslēdziet mobilo datu savienojumu vai Wi-Fi.</translation>
<translation id="3715597595485130451">Savienojuma izveide ar Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />PÄrbaudiet starpniekserveri, ugunsmÅ«ri un DNS konfigurÄciju<ph name="END_LINK" />.</translation>
@@ -920,6 +951,7 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="3906954721959377182">Planšetdators</translation>
<translation id="3909477809443608991">Vietne <ph name="URL" /> vÄ“las atskaņot aizsargÄtu saturu. JÅ«su ierÄ«ces identitÄti pÄrbaudÄ«s Google, un tai var piekļūt Å¡Ä« vietne.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">Neatļaut</translation>
<translation id="3939773374150895049">Vai vēlaties izmantot WebAuthn, nevis CVC?</translation>
<translation id="3946209740501886391">VienmÄ“r jautÄt Å¡ajÄ vietnÄ“</translation>
<translation id="3947595700203588284">Var pieprasīt atļauju veidot savienojumu ar MIDI ierīcēm</translation>
@@ -941,6 +973,7 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="3990250421422698716">Ofseta izlÄ«dzinÄÅ¡ana</translation>
<translation id="3996311196211510766">Vietne <ph name="ORIGIN" /> ir pieprasījusi, lai izcelsmes politika attiektos uz visu
tÄs pieprasÄ«jumu, taÄu Å¡obrÄ«d Å¡o politiku nevar piemÄ“rot.</translation>
+<translation id="4009243425692662128">JÅ«su izdrukÄto lapu saturs tiek nosÅ«tÄ«ts uz Google Cloud vai treÅ¡ajÄm pusÄ“m, lai veiktu analÄ«zi. PiemÄ“ram, saturs var tikt pÄrmeklÄ“ts, lai konstatÄ“tu, vai tajÄ ir ietverti sensitÄ«vi dati.</translation>
<translation id="4010758435855888356">Vai atļaut piekļuvi krÄtuvei?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{PDF dokumentÄ ir {COUNT} lapa}zero{PDF dokumentÄ ir {COUNT} lapas}one{PDF dokumentÄ ir {COUNT} lapa}other{PDF dokumentÄ ir {COUNT} lapas}}</translation>
<translation id="4023431997072828269">TÄ kÄ Å¡Ä« veidlapa tiek iesniegta, izmantojot nedroÅ¡u savienojumu, jÅ«su informÄcija bÅ«s redzama citÄm personÄm.</translation>
@@ -1035,6 +1068,7 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="4250680216510889253">NÄ“</translation>
<translation id="4253168017788158739">Piezīme</translation>
<translation id="425582637250725228">VeiktÄs izmaiņas, iespÄ“jams, netiks saglabÄtas.</translation>
+<translation id="425869179292622354">Vai vÄ“laties uzlabot droÅ¡Ä«bu, izmantojot virtuÄlu karti?</translation>
<translation id="4258748452823770588">Paraksts nav derīgs.</translation>
<translation id="4261046003697461417">AizsargÄtiem dokumentiem nevar pievienot piezÄ«mes</translation>
<translation id="4265872034478892965">AtļÄva jÅ«su administrators</translation>
@@ -1097,6 +1131,7 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="4434045419905280838">Uznirstošie elem. un novirzīšana</translation>
<translation id="4435702339979719576">Pastkarte)</translation>
<translation id="443673843213245140">Starpniekservera lietoÅ¡ana ir atspÄ“jota, bet ir norÄdÄ«ta atklÄta starpniekservera konfigurÄcija.</translation>
+<translation id="4441832193888514600">IgnorÄ“ta, jo Å¡o politiku var iestatÄ«t tikai kÄ mÄkoņa lietotÄja politiku.</translation>
<translation id="4450893287417543264">Vairs nerÄdÄ«t</translation>
<translation id="4451135742916150903">Var pieprasīt atļauju veidot savienojumu ar HID ierīcēm</translation>
<translation id="4452328064229197696">Nupat izmantotÄ parole ir atklÄta datu aizsardzÄ«bas pÄrkÄpuma dēļ. Lai aizsargÄtu kontus, Google paroļu pÄrvaldnieks iesaka pÄrbaudÄ«t saglabÄtÄs paroles.</translation>
@@ -1152,6 +1187,7 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="4628948037717959914">Fotoattēls</translation>
<translation id="4631649115723685955">Saistīta skaidras naudas atmaksa</translation>
<translation id="4636930964841734540">InformÄcija</translation>
+<translation id="4638670630777875591">Inkognito režīms pÄrlÅ«kÄ Chromium</translation>
<translation id="464342062220857295">Meklēšanas funkcijas</translation>
<translation id="4644670975240021822">Pretēja secība, virspuse uz leju</translation>
<translation id="4646534391647090355">Doties uz turieni tagad</translation>
@@ -1172,6 +1208,7 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="4708268264240856090">Savienojums tika pÄrtraukts</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Palaist Windows tīkla diagnostiku<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426">Parole lietotÄjvÄrdam <ph name="USERNAME" /></translation>
<translation id="4724144314178270921">Var pieprasīt atļauju skatīt tekstu un attēlus jūsu starpliktuvē</translation>
<translation id="4726672564094551039">AtkÄrtoti ielÄdÄ“t politikas</translation>
<translation id="4728558894243024398">Platforma</translation>
@@ -1193,6 +1230,7 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="4757993714154412917">JÅ«s tikko ievadÄ«jÄt savu paroli maldinoÅ¡Ä vietnÄ“. Chromium ieteikums jÅ«su kontu aizsardzÄ«bai: pÄrbaudiet saglabÄtÄs paroles.</translation>
<translation id="4758311279753947758">Pievienot kontaktinformÄciju</translation>
<translation id="4761104368405085019">Izmantot jūsu mikrofonu</translation>
+<translation id="4761869838909035636">Veikt Chrome droÅ¡Ä«bas pÄrbaudi</translation>
<translation id="4764776831041365478">TÄ«mekļa lapa vietnÄ“ <ph name="URL" /> var Ä«slaicÄ«gi nebÅ«t pieejama, vai tÄ var bÅ«t pÄrvietota uz jaunu tÄ«mekļa adresi.</translation>
<translation id="4766713847338118463">Dubults skavojums apakÅ¡daļÄ</translation>
<translation id="4771973620359291008">RadÄs nezinÄma kļūda.</translation>
@@ -1213,12 +1251,6 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="4819347708020428563">Vai vÄ“laties rediģēt piezÄ«mes noklusÄ“juma skatÄ?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />. Lai Ätri izveidotu jaunu Google izklÄjlapu, nospiediet tabulÄ“Å¡anas taustiņu un pÄ“c tam — taustiņu Enter.</translation>
<translation id="4825507807291741242">Efektīva</translation>
-<translation id="4827402517081186284">Inkognito režīms nenozīmē, ka jūs tiešsaistē būsiet neredzams.
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Vietņu īpašnieki zina, vai jūs apmeklējat viņu vietnes.<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Darba devÄ“ji vai mÄcÄ«bu iestÄdes var uzskaitÄ«t pÄrlÅ«koÅ¡anas darbÄ«bas.<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Interneta pakalpojumu sniedzēji var uzraudzīt tīmekļa datplūsmu.<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">IeslÄ“gt brÄ«dinÄjumus</translation>
<translation id="4838327282952368871">Mierīga</translation>
<translation id="4840250757394056958">Skatīt Chrome vēsturi</translation>
@@ -1230,12 +1262,12 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="4854362297993841467">Å is piegÄdes veids nav pieejams. IzmÄ“Ä£iniet citu veidu.</translation>
<translation id="4854853140771946034">Ātri izveidot jaunu piezīmi lietotnē Google Keep</translation>
<translation id="485902285759009870">Notiek koda verificēšana…</translation>
+<translation id="4866506163384898554">Nospiediet |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />|, lai parÄdÄ«tu kursoru.</translation>
<translation id="4876188919622883022">VienkÄrÅ¡otais skats</translation>
<translation id="4876305945144899064">Nav lietotÄjvÄrda</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{Nav}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}zero{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}one{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831">Teksta “<ph name="TEXT" />†meklēšana</translation>
<translation id="4879491255372875719">AutomÄtiski (noklusÄ“jums)</translation>
-<translation id="4879725228911483934">AtvÄ“rt un izvietot logus jÅ«su ekrÄnos</translation>
<translation id="4880827082731008257">Meklēšanas vēsture</translation>
<translation id="4881695831933465202">Atvērt</translation>
<translation id="4885256590493466218">MaksÄjiet ar karti <ph name="CARD_DETAIL" /></translation>
@@ -1244,6 +1276,7 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">Devītais rullis</translation>
<translation id="4901778704868714008">SaglabÄt...</translation>
+<translation id="4905659621780993806">JÅ«su administrators automÄtiski restartÄ“s jÅ«su ierÄ«ci plkst. <ph name="TIME" /> Å¡ÄdÄ datumÄ: <ph name="DATE" />. SaglabÄjiet visus atvÄ“rtos failus, pirms ierÄ«ce tiek restartÄ“ta.</translation>
<translation id="4913987521957242411">Caurums augÅ¡Ä“jÄ kreisajÄ malÄ</translation>
<translation id="4918221908152712722">InstalÄ“jiet lietotni <ph name="APP_NAME" /> (nav nepiecieÅ¡ama lejupielÄde)</translation>
<translation id="4923459931733593730">MaksÄjums</translation>
@@ -1252,6 +1285,7 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, lai meklētu, nospiediet tabulēšanas taustiņu un pēc tam taustiņu Enter</translation>
<translation id="4930153903256238152">Liela ietilpība</translation>
+<translation id="4940163644868678279">Inkognito režīms pÄrlÅ«kÄ Chrome</translation>
<translation id="4943872375798546930">Nav rezultÄtu</translation>
<translation id="4950898438188848926">Ciļņu pÄrslÄ“gÅ¡anas poga. Nospiediet ievadÄ«Å¡anas taustiņu, lai pÄrslÄ“gtos uz atvÄ“rto cilni, <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" />.</translation>
<translation id="495170559598752135">Darbības</translation>
@@ -1261,6 +1295,7 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="4968522289500246572">Å Ä« lietotne ir paredzÄ“ta mobilajÄm ierÄ«cÄ“m, un tÄs lielumu, iespÄ“jams, nevarÄ“s atbilstoÅ¡i mainÄ«t. LietotnÄ“ var rasties problÄ“mas, vai tÄ var tikt restartÄ“ta.</translation>
<translation id="4969341057194253438">Dzēst ierakstu</translation>
<translation id="4973922308112707173">Divi caurumi augÅ¡daļÄ</translation>
+<translation id="4976702386844183910">Pēdējoreiz apmeklēta: <ph name="DATE" /></translation>
<translation id="4984088539114770594">Vai lietot mikrofonu?</translation>
<translation id="4984339528288761049">Prc5 (aploksne)</translation>
<translation id="4989163558385430922">Skatīt visu</translation>
@@ -1322,6 +1357,7 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="5138227688689900538">RÄdÄ«t mazÄk</translation>
<translation id="5145883236150621069">Politikas atbildē ir kļūdas kods.</translation>
<translation id="5146995429444047494">Vietnes <ph name="ORIGIN" /> paziņojumi ir bloķēti</translation>
+<translation id="514704532284964975"><ph name="URL" /> pieprasa atļauju piekļūt informÄcijai un to mainÄ«t NFC ierÄ«cÄ“s, kuru nosaukumiem tÄlrunÄ« pieskaraties</translation>
<translation id="5148809049217731050">Ar virspusi uz augšu</translation>
<translation id="515292512908731282">C4 (aploksne)</translation>
<translation id="5158275234811857234">VÄks</translation>
@@ -1346,6 +1382,7 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="5215116848420601511">Adreses un maksÄjumu veidi, kuros tiek izmantots pakalpojums Google Pay</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">13. paplÄte</translation>
+<translation id="5216942107514965959">Pēdējoreiz apmeklēta šodien</translation>
<translation id="5222812217790122047">JÄnorÄda e-pasta adrese.</translation>
<translation id="5230733896359313003">PiegÄdes adrese</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1366,7 +1403,6 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">Dokumenta rekvizīti</translation>
<translation id="528468243742722775">Beigas</translation>
-<translation id="5284909709419567258">TÄ«kla adreses</translation>
<translation id="5285570108065881030">RÄdÄ«t visas saglabÄtÄs paroles</translation>
<translation id="5287240709317226393">RÄdÄ«t sÄ«kfailus</translation>
<translation id="5287456746628258573">Å ajÄ vietnÄ“ tiek izmantota novecojusi droÅ¡Ä«bas konfigurÄcija, tÄdēļ var tikt atklÄta jÅ«su informÄcija (piemÄ“ram, paroles vai kredÄ«tkarÅ¡u numuri), kad tÄ tiek nosÅ«tÄ«ta uz Å¡o vietni.</translation>
@@ -1450,6 +1486,7 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="5556459405103347317">PÄrlÄdÄ“t</translation>
<translation id="5560088892362098740">Derīguma termiņš</translation>
<translation id="55635442646131152">Dokumenta struktūrskats</translation>
+<translation id="5565613213060953222">Atvērt inkognito cilni</translation>
<translation id="5565735124758917034">Aktīvs</translation>
<translation id="5570825185877910964">AizsargÄt kontu</translation>
<translation id="5571083550517324815">Nevar saņemt sÅ«tÄ«jumu Å¡ajÄ adresÄ“. Atlasiet citu adresi.</translation>
@@ -1532,6 +1569,7 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="5869522115854928033">SaglabÄtÄs paroles</translation>
<translation id="5873013647450402046">Banka vÄ“las apstiprinÄt jÅ«su identitÄti</translation>
<translation id="5887400589839399685">KartÄ«te ir saglabÄta</translation>
+<translation id="5887687176710214216">Pēdējoreiz apmeklēta vakar</translation>
<translation id="5895138241574237353">Restartēt</translation>
<translation id="5895187275912066135">Izsniegšanas datums</translation>
<translation id="5901630391730855834">Dzeltena</translation>
@@ -1545,6 +1583,7 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="5921639886840618607">Vai saglabÄt kartes datus Google kontÄ?</translation>
<translation id="5922853866070715753">Gandrīz pabeigts</translation>
<translation id="5932224571077948991">VietnÄ“ tiek rÄdÄ«tas traucÄ“joÅ¡as vai maldinoÅ¡as reklÄmas</translation>
+<translation id="5938153366081463283">Pievienojiet virtuÄlu karti</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347">Notiek vietnes <ph name="SITE_NAME" /> atvēršana...</translation>
<translation id="5951495562196540101">NeizdevÄs reÄ£istrÄ“t, izmantojot patÄ“rÄ“tÄja kontu (pieejama komplektÄ iekļauta licence).</translation>
@@ -1609,6 +1648,7 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="6120179357481664955">Vai iegaumēt jūsu UPI ID?</translation>
<translation id="6124432979022149706">Chrome Enterprise savienotÄji</translation>
<translation id="6127379762771434464">Vienums ir noņemts</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />UzzinÄt vairÄk par inkognito režīmu pÄrlÅ«kÄ Chrome<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">PÄrbaudiet vadus un atkÄrtoti palaidiet marÅ¡rutÄ“tÄjus, modemus vai citas
izmantotÄs tÄ«kla ierÄ«ces.</translation>
<translation id="614940544461990577">Veiciet tÄlÄk norÄdÄ«tÄs darbÄ«bas.</translation>
@@ -1621,7 +1661,6 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="6169916984152623906">Tagad varat privÄti pÄrlÅ«kot saturu, un citas personas, kas izmanto Å¡o ierÄ«ci, nevarÄ“s redzÄ“t jÅ«su darbÄ«bas. TomÄ“r lejupielÄdes un grÄmatzÄ«mes tiks saglabÄtas.</translation>
<translation id="6177128806592000436">Savienojums ar šo vietni nav drošs.</translation>
<translation id="6180316780098470077">IntervÄls starp atkÄrtotiem mÄ“Ä£inÄjumiem</translation>
-<translation id="619448280891863779">Var pieprasÄ«t atļauju atvÄ“rt un izvietot logus jÅ«su ekrÄnos</translation>
<translation id="6196640612572343990">Bloķēt trešo pušu sīkfailus</translation>
<translation id="6203231073485539293">Interneta savienojuma pÄrbaude</translation>
<translation id="6218753634732582820">Vai noņemt adresi no pÄrlÅ«ka Chromium?</translation>
@@ -1644,7 +1683,7 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="6272383483618007430">Google atjauninÄjums</translation>
<translation id="6276112860590028508">Å eit tiek rÄdÄ«tas lasÄ«Å¡anas sarakstÄ esoÅ¡Äs lapas</translation>
<translation id="627746635834430766">Lai nÄkamreiz veiktu maksÄjumu ÄtrÄk, saglabÄjiet kartes datus un norÄ“Ä·inu adresi savÄ Google kontÄ.</translation>
-<translation id="6279098320682980337">Vai nav ievadÄ«ts virtuÄlÄs kartes numurs? NoklikÅ¡Ä·iniet uz kartes informÄcijas, lai to kopÄ“tu.</translation>
+<translation id="6279183038361895380">Lai tiktu parÄdÄ«ts kursors, nospiediet |<ph name="ACCELERATOR" />|</translation>
<translation id="6280223929691119688">Nevar piegÄdÄt uz Å¡o adresi. Atlasiet citu adresi.</translation>
<translation id="6282194474023008486">Pasta indekss</translation>
<translation id="6285507000506177184">Poga lejupielÄžu pÄrvaldÄ«bai pÄrlÅ«kÄ Chrome. Lai pÄrvaldÄ«tu pÄrlÅ«kÄ Chrome lejupielÄdÄ“tos failus, nospiediet taustiņu Enter.</translation>
@@ -1652,6 +1691,7 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="6290238015253830360">Ieteiktie raksti tiek parÄdÄ«ti Å¡eit</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{Jūsu ierīce tiks restartēta tūlīt}=1{Jūsu ierīce tiks restartēta pēc 1 sekundes}zero{Jūsu ierīce tiks restartēta # sekundēm}one{Jūsu ierīce tiks restartēta # sekundes}other{Jūsu ierīce tiks restartēta # sekundēm}}</translation>
<translation id="6302269476990306341">Tiek pÄrtraukta Google asistenta darbÄ«ba pÄrlÅ«kprogrammÄ Chrome.</translation>
<translation id="6305205051461490394">Vietne <ph name="URL" /> nav sasniedzama.</translation>
<translation id="6312113039770857350">Tīmekļa lapa nav pieejama</translation>
@@ -1725,6 +1765,7 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="6529602333819889595">&amp;Dzēšanas atsaukuma atcelšana</translation>
<translation id="6545864417968258051">Bluetooth meklēšana</translation>
<translation id="6547208576736763147">Divi caurumi kreisajÄ pusÄ“</translation>
+<translation id="6554732001434021288">PÄ“dÄ“joreiz apmeklÄ“ta pirms <ph name="NUM_DAYS" /> dienÄm</translation>
<translation id="6556866813142980365">Atcelt atsaukšanu</translation>
<translation id="6569060085658103619">JÅ«s skatÄt paplaÅ¡inÄjumu lapu.</translation>
<translation id="6573200754375280815">Divi caurumi labajÄ pusÄ“</translation>
@@ -1766,7 +1807,7 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="6689249931105087298">Relatīva, ar melno punktu saspiešanu</translation>
<translation id="6689271823431384964">PÄrlÅ«kprogrammÄ Chrome tiek piedÄvÄts saglabÄt jÅ«su kartes Google kontÄ, jo esat pierakstÄ«jies. Varat mainÄ«t Å¡o darbÄ«bu iestatÄ«jumos. Kartes Ä«paÅ¡nieka vÄrds tiek iegÅ«ts no jÅ«su konta.</translation>
<translation id="6694681292321232194"><ph name="FIND_MY_PHONE_FOCUSED_FRIENDLY_MATCH_TEXT" />. Lai atrastu savu ierÄ«ci Google kontÄ, nospiediet tabulÄ“Å¡anas taustiņu un pÄ“c tam — taustiņu Enter.</translation>
-<translation id="6696588630955820014">Cilnes kopÄ«goÅ¡anas poga. Lai kopÄ«gotu Å¡o cilni, piemÄ“ram, kopÄ«gojot saiti, izveidojot ÄtrÄs atbildes kodu, sÄkot apraidi vai citÄ veidÄ, nospiediet taustiņu Enter.</translation>
+<translation id="6696588630955820014">Cilnes kopÄ«goÅ¡anas poga. Lai kopÄ«gotu Å¡o cilni, piemÄ“ram, kopÄ«gojot saiti, izveidojot kvadrÄtkodu, sÄkot apraidi vai citÄ veidÄ, nospiediet taustiņu Enter.</translation>
<translation id="6698381487523150993">Izveidots:</translation>
<translation id="6702919718839027939">PrezentÄcija</translation>
<translation id="6710213216561001401">Iepriekšējais</translation>
@@ -1785,7 +1826,6 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="6757797048963528358">IerÄ«ce tika pÄrslÄ“gta miega režīmÄ.</translation>
<translation id="6767985426384634228">Vai atjauninÄt adresi?</translation>
<translation id="6768213884286397650">Hagaki (pastkarte)</translation>
-<translation id="6774185088257932239"><ph name="BEGIN_LINK" />Uzziniet vairÄk<ph name="END_LINK" /> par inkognito režīmu.</translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">Violeta</translation>
<translation id="6786747875388722282">PaplaÅ¡inÄjumi</translation>
@@ -1869,7 +1909,6 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="706295145388601875">Chrome iestatÄ«jumos pievienojiet un pÄrvaldiet adreses.</translation>
<translation id="7064851114919012435">KontaktinformÄcija</translation>
<translation id="7068733155164172741">Ievadiet <ph name="OTP_LENGTH" /> ciparu kodu</translation>
-<translation id="7070090581017165256">Par Å¡o vietni</translation>
<translation id="70705239631109039">Jūsu savienojums nav pilnīgi drošs</translation>
<translation id="7075452647191940183">PieprasÄ«jums ir pÄrÄk liels</translation>
<translation id="7079718277001814089">Å Ä« vietne satur ļaunprÄtÄ«gu programmatÅ«ru</translation>
@@ -1886,6 +1925,12 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="7111012039238467737">(derīgs)</translation>
<translation id="7118618213916969306">Meklēt starpliktuves URL, <ph name="SHORT_URL" /></translation>
<translation id="7119414471315195487">Aizveriet citas cilnes vai programmas</translation>
+<translation id="7129355289156517987">Kad aizvÄ“rsiet visas Chromium inkognito cilnes, no Å¡Ä«s ierÄ«ces tiks notÄ«rÄ«tas Å¡ajÄs cilnÄ“s veiktÄs darbÄ«bas:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />pÄrlÅ«koÅ¡anas darbÄ«bas;<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />meklēšanas vēsture;<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />veidlapÄs ievadÄ«tÄ informÄcija.<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">Nevar nosūtīt uz šo adresi. Atlasiet citu adresi.</translation>
<translation id="7132939140423847331">Jūsu administrators ir aizliedzis šo datu kopēšanu.</translation>
<translation id="7135130955892390533">RÄdÄ«t statusu</translation>
@@ -1908,6 +1953,7 @@ PretÄ“jÄ gadÄ«jumÄ Å¡Ä« iespÄ“ja bÅ«tu liegta saskaÅ†Ä ar jÅ«su konfidenciali
<translation id="7192203810768312527">Tiks atbrÄ«vota vieta: <ph name="SIZE" />. IespÄ“jams, nÄkamajÄ apmeklÄ“juma reizÄ“ dažas vietnes tiks ielÄdÄ“tas lÄ“nÄk.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">Administrators var redzēt:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />. Lai privÄtai pÄrlÅ«koÅ¡anai atvÄ“rtu inkognito cilni, nospiediet tabulÄ“Å¡anas taustiņu un pÄ“c tam — taustiņu Enter.</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> neatbilst drošības standartiem.</translation>
<translation id="7210993021468939304">Linux darbÄ«ba konteinerÄ; var instalÄ“t un palaist Linux lietotnes konteinerÄ</translation>
@@ -1939,6 +1985,7 @@ Papildu informÄcija:
<translation id="7304562222803846232">PÄrvaldÄ«t Google konta konfidencialitÄtes iestatÄ«jumus</translation>
<translation id="7305756307268530424">SÄkt lÄ“nÄk</translation>
<translation id="7308436126008021607">sinhronizÄcija fonÄ</translation>
+<translation id="7310392214323165548">Ierīce ļoti drīz tiks restartēta</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">Savienojuma palīdzība</translation>
<translation id="7323804146520582233">PaslÄ“pt sadaļu “<ph name="SECTION" />â€</translation>
@@ -1946,6 +1993,7 @@ Papildu informÄcija:
<translation id="7334320624316649418">&amp;Atcelt pÄrkÄrtoÅ¡anas atsaukÅ¡anu</translation>
<translation id="7335157162773372339">Var pieprasīt atļauju izmantot jūsu kameru</translation>
<translation id="7337248890521463931">RÄdÄ«t vairÄk rindu</translation>
+<translation id="7337418456231055214">Vai nav ievadÄ«ts virtuÄlÄs kartes numurs? NoklikÅ¡Ä·iniet uz kartes informÄcijas, lai to kopÄ“tu. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">Nav pieejams jÅ«su platformÄ.</translation>
<translation id="733923710415886693">Servera sertifikÄts netika atklÄts, izmantojot sertifikÄta pÄrredzamÄ«bu.</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1968,11 +2016,12 @@ Papildu informÄcija:
<translation id="7378627244592794276">NÄ“</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">Nav piemērojams</translation>
+<translation id="7388594495505979117">{0,plural, =1{Jūsu ierīce tiks restartēta pēc 1 minūtes}zero{Jūsu ierīce tiks restartēta pēc # minūtēm}one{Jūsu ierīce tiks restartēta pēc # minūtes}other{Jūsu ierīce tiks restartēta pēc # minūtēm}}</translation>
<translation id="7390545607259442187">Kartes apstiprinÄÅ¡ana</translation>
<translation id="7392089738299859607">Adreses atjauninÄÅ¡ana</translation>
<translation id="7399802613464275309">DroÅ¡Ä«bas pÄrbaude</translation>
<translation id="7400418766976504921">URL</translation>
-<translation id="7403392780200267761">KopÄ«gojiet Å¡o cilni, piemÄ“ram, kopÄ«gojot saiti, izveidojot ÄtrÄs atbildes kodu, sÄkot apraidi vai citÄ veidÄ.</translation>
+<translation id="7403392780200267761">KopÄ«gojiet Å¡o cilni, piemÄ“ram, kopÄ«gojot saiti, izveidojot kvadrÄtkodu, sÄkot apraidi vai citÄ veidÄ.</translation>
<translation id="7403591733719184120">JÅ«su <ph name="DEVICE_NAME" /> ierÄ«ce tiek pÄrvaldÄ«ta</translation>
<translation id="7407424307057130981">&lt;p&gt;Å Ä« kļūda tiek rÄdÄ«ta, ja Windows datorÄ ir instalÄ“ta Superfish programmatÅ«ra.&lt;/p&gt;
&lt;p&gt;Lai Ä«slaicÄ«gi atspÄ“jotu Å¡o programmatÅ«ru un piekļūtu tÄ«meklim, veiciet tÄlÄk minÄ“tÄs darbÄ«bas. Jums bÅ«s nepiecieÅ¡amas administratora privilÄ“Ä£ijas.&lt;/p&gt;
@@ -2004,6 +2053,12 @@ Papildu informÄcija:
<translation id="7485870689360869515">Dati netika atrasti.</translation>
<translation id="7495528107193238112">Šis saturs ir bloķēts. Lai novērstu problēmu, sazinieties ar vietnes īpašnieku.</translation>
<translation id="7497998058912824456">Dokumenta izveides poga. Lai Ätri izveidotu jaunu Google dokumentu, nospiediet taustiņu Enter.</translation>
+<translation id="7506488012654002225">PÄrlÅ«kÄ Chromium <ph name="BEGIN_EMPHASIS" />netiks saglabÄta<ph name="END_EMPHASIS" /> Å¡Äda informÄcija:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />jÅ«su pÄrlÅ«koÅ¡anas vÄ“sture;
+ <ph name="LIST_ITEM" />sīkfaili un vietņu dati;
+ <ph name="LIST_ITEM" />veidlapÄs ievadÄ«tÄ informÄcija.
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">Atgrieztais politikas ierīces ID ir tukšs vai neatbilst pašreizējam ierīces ID.</translation>
<translation id="7508870219247277067">Avokado zaļa</translation>
<translation id="7511955381719512146">IespÄ“jams, izmantotajÄ Wi-Fi tÄ«klÄ tiks pieprasÄ«ts apmeklÄ“t vietni <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
@@ -2117,7 +2172,6 @@ Papildu informÄcija:
<translation id="7813600968533626083">Vai noņemt veidlapas ieteikumu no pÄrlÅ«ka Chrome?</translation>
<translation id="781440967107097262">Vai kopīgot starpliktuvi?</translation>
<translation id="7815407501681723534">MeklÄ“jot pÄ“c virknes “<ph name="SEARCH_STRING" />â€, tika atrasti <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /></translation>
-<translation id="782125616001965242">RÄdÄ«t informÄciju par Å¡o vietni</translation>
<translation id="782886543891417279">IespÄ“jams, izmantotajÄ Wi-Fi tÄ«klÄ (<ph name="WIFI_NAME" />) tiks pieprasÄ«ts apmeklÄ“t pieteikÅ¡anÄs lapu.</translation>
<translation id="7836231406687464395">Postfix (aploksne)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{Nav}=1{1 lietotne (<ph name="EXAMPLE_APP_1" />)}=2{2 lietotnes (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}zero{# lietotnes (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" /> <ph name="AND_MORE" />)}one{# lietotne (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" /> <ph name="AND_MORE" />)}other{# lietotnes (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" /> <ph name="AND_MORE" />)}}</translation>
@@ -2134,7 +2188,6 @@ Papildu informÄcija:
<translation id="7888575728750733395">DrukÄÅ¡anas krÄsu atveide</translation>
<translation id="7894280532028510793">Ja nav pareizrakstības kļūdu, <ph name="BEGIN_LINK" />mēģiniet palaist tīkla diagnostiku<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (aploksne)</translation>
-<translation id="7931318309563332511">NezinÄma</translation>
<translation id="793209273132572360">Vai atjauninÄt adresi?</translation>
<translation id="7932579305932748336">PÄrklÄjums</translation>
<translation id="79338296614623784">Ievadiet derÄ«gu tÄlruņa numuru</translation>
@@ -2159,13 +2212,14 @@ Papildu informÄcija:
<translation id="7976214039405368314">PÄrÄk daudz pieprasÄ«jumu</translation>
<translation id="7977538094055660992">Izvades ierīce</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">Saistīta ar</translation>
<translation id="798134797138789862">Var pieprasÄ«t atļauju izmantot virtuÄlÄs realitÄtes ierÄ«ces un datus</translation>
<translation id="7984945080620862648">PaÅ¡laik nevarat apmeklÄ“t vietni <ph name="SITE" />, jo tÄ nosÅ«tÄ«ja bojÄtus akreditÄcijas datus, ko nevar apstrÄdÄt pÄrlÅ«kÄ Chrome. TÄ«kla kļūdas un uzbrukumi parasti ir Ä«slaicÄ«gi, tÄpÄ“c Å¡Ä« lapa vÄ“lÄk, visticamÄk, darbosies.</translation>
-<translation id="79859296434321399">Lai skatÄ«tu papildinÄtÄs realitÄtes saturu, instalÄ“jiet ARCore</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" />, <ph name="BOOKMARKED" />, <ph name="TITLE" />, <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">Iesējums</translation>
<translation id="7992044431894087211">EkrÄna kopÄ«goÅ¡ana ar lietojumprogrammu <ph name="APPLICATION_TITLE" /> ir atsÄkta.</translation>
<translation id="7995512525968007366">Nav norÄdÄ«ts</translation>
+<translation id="7998269595945679889">Poga “AtvÄ“rt inkognito cilniâ€. Lai privÄtai pÄrlÅ«koÅ¡anai atvÄ“rtu jaunu inkognito cilni, nospiediet taustiņu Enter.</translation>
<translation id="800218591365569300">Aizveriet citas cilnes vai programmas, lai atbrÄ«votu vietu atmiņÄ.</translation>
<translation id="8004582292198964060">PÄrlÅ«kprogramma</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{Å Ä« karte un tÄs norÄ“Ä·inu adrese tiks saglabÄta. JÅ«s varÄ“siet to izmantot, kad bÅ«siet pierakstÄ«jies kontÄ <ph name="USER_EMAIL" />.}zero{Å Ä«s kartes un to norÄ“Ä·inu adreses tiks saglabÄtas. JÅ«s varÄ“siet tÄs izmantot, kad bÅ«siet pierakstÄ«jies kontÄ <ph name="USER_EMAIL" />.}one{Å Ä«s kartes un to norÄ“Ä·inu adreses tiks saglabÄtas. JÅ«s varÄ“siet tÄs izmantot, kad bÅ«siet pierakstÄ«jies kontÄ <ph name="USER_EMAIL" />.}other{Å Ä«s kartes un to norÄ“Ä·inu adreses tiks saglabÄtas. JÅ«s varÄ“siet tÄs izmantot, kad bÅ«siet pierakstÄ«jies kontÄ <ph name="USER_EMAIL" />.}}</translation>
@@ -2225,6 +2279,7 @@ Papildu informÄcija:
<translation id="8202370299023114387">Konflikts</translation>
<translation id="8206978196348664717">Prc4 (aploksne)</translation>
<translation id="8211406090763984747">Savienojums ir drošs</translation>
+<translation id="8217240300496046857">Vietnes nevar izmantot sÄ«kfailus, kas izseko jÅ«su darbÄ«bas tÄ«meklÄ«. NoteiktÄs vietnÄ“s funkcijas var nedarboties.</translation>
<translation id="8218327578424803826">PieÅ¡Ä·irtÄ atraÅ¡anÄs vieta:</translation>
<translation id="8220146938470311105">C7/C6 (aploksne)</translation>
<translation id="8225771182978767009">Persona, kura iestatÄ«ja Å¡o datoru, izvÄ“lÄ“jÄs bloÄ·Ä“t Å¡o vietni.</translation>
@@ -2265,14 +2320,9 @@ Papildu informÄcija:
<translation id="830498451218851433">Locījums uz pusēm</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">InstalÄ“tÄs lietotnes un to izmantoÅ¡anas biežums</translation>
+<translation id="8317207217658302555">Vai atjauninÄt ARCore?</translation>
<translation id="831997045666694187">VakarÄ</translation>
<translation id="8321476692217554900">paziņojumi</translation>
-<translation id="8328484624016508118">Kad visas inkognito cilnes tiek aizvÄ“rtas, pÄrlÅ«kÄ Chrome tiek notÄ«rÄ«ti Å¡Ädi dati:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />pÄrlÅ«koÅ¡anas darbÄ«bas no Å¡Ä«s ierÄ«ces;<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />meklēšanas vēsture no šīs ierīces;<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />veidlapÄs ievadÄ«tÄ informÄcija.<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489">Piekļuve vietnei <ph name="HOST_NAME" /> tika noraidīta</translation>
<translation id="833262891116910667">Atzīmēt</translation>
<translation id="8339163506404995330">Lapas Å¡ÄdÄ valodÄ: <ph name="LANGUAGE" /> netiks tulkotas.</translation>
@@ -2324,6 +2374,7 @@ Papildu informÄcija:
<translation id="8507227106804027148">Komandrinda</translation>
<translation id="8508648098325802031">Meklēšanas ikona</translation>
<translation id="8511402995811232419">PÄrvaldÄ«t sÄ«kfailus</translation>
+<translation id="8519753333133776369">HID ierÄ«ce, ko atļÄva jÅ«su administrators</translation>
<translation id="8522552481199248698">Chrome var palÄ«dzÄ“t jums aizsargÄt jÅ«su Google kontu un nomainÄ«t paroli.</translation>
<translation id="8530813470445476232">NotÄ«riet savu pÄrlÅ«koÅ¡anas vÄ“sturi, sÄ«kfailus, keÅ¡atmiņu un citus datus Chrome iestatÄ«jumos.</translation>
<translation id="8533619373899488139">ApmeklÄ“jiet vietni &lt;strong&gt;chrome://policy&lt;/strong&gt;, lai skatÄ«tu bloÄ·Ä“to URL sarakstu, kÄ arÄ« citas politikas, ko noteicis sistÄ“mas administrators.</translation>
@@ -2335,7 +2386,6 @@ Papildu informÄcija:
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{Atiestatīt atļauju}zero{Atiestatīt atļaujas}one{Atiestatīt atļaujas}other{Atiestatīt atļaujas}}</translation>
<translation id="8555010941760982128">Norēķinoties izmantojiet šo kodu</translation>
<translation id="8557066899867184262">CVC kods ir norÄdÄ«ts jÅ«su kartes aizmugurÄ“.</translation>
-<translation id="8558485628462305855">Lai skatÄ«tu papildinÄtÄs realitÄtes saturu, atjauniniet ARCore</translation>
<translation id="8559762987265718583">Nevar izveidot privÄtu savienojumu ar <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />, jo jÅ«su ierÄ«ces datums un laiks (<ph name="DATE_AND_TIME" />) nav pareizs.</translation>
<translation id="8564182942834072828">AtseviÅ¡Ä·i dokumenti/nesakÄrtotu lapu kopijas</translation>
<translation id="8564985650692024650">Chromium iesaka atiestatÄ«t jÅ«su <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> paroli, ja izmantojÄt to citÄs vietnÄ“s.</translation>
@@ -2355,6 +2405,7 @@ Papildu informÄcija:
<translation id="865032292777205197">kustību sensori</translation>
<translation id="8663226718884576429">Pasūtījuma kopsavilkums, <ph name="TOTAL_LABEL" />, citi dati</translation>
<translation id="8666678546361132282">Angļu valoda</translation>
+<translation id="8669306706049782872">Izmantot informÄciju par jÅ«su ekrÄniem, lai atvÄ“rtu un izvietotu logus</translation>
<translation id="867224526087042813">Iespiedloksne</translation>
<translation id="8676424191133491403">Bez aizkaves</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, atbilde, <ph name="ANSWER" /></translation>
@@ -2381,6 +2432,7 @@ Papildu informÄcija:
<translation id="8731544501227493793">Poga “PÄrvaldÄ«t parolesâ€. Lai skatÄ«tu un pÄrvaldÄ«tu paroles Chrome iestatÄ«jumos, nospiediet ievadÄ«Å¡anas taustiņu.</translation>
<translation id="8734529307927223492">JÅ«su <ph name="DEVICE_TYPE" /> ierÄ«ci pÄrvalda <ph name="MANAGER" /></translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />. Lai privÄtai pÄrlÅ«koÅ¡anai atvÄ“rtu inkognito režīma logu, nospiediet tabulÄ“Å¡anas taustiņu un pÄ“c tam — ievadÄ«Å¡anas taustiņu.</translation>
+<translation id="8737685506611670901">atvērt <ph name="PROTOCOL" /> saites, nevis <ph name="REPLACED_HANDLER_TITLE" /></translation>
<translation id="8738058698779197622">Lai izveidotu droÅ¡u savienojumu, ir jÄiestata pareizs pulksteņa laiks. Tas ir nepiecieÅ¡ams, jo sertifikÄti, kurus vietnes izmanto, lai tiktu identificÄ“tas, ir derÄ«gi tikai noteiktos laika periodos. TÄ kÄ jÅ«su ierÄ«ces pulkstenis nav pareizi iestatÄ«ts, Chromium nevar verificÄ“t Å¡os sertifikÄtus.</translation>
<translation id="8740359287975076522">Nevarēja atrast <ph name="HOST_NAME" /> &lt;abbr id="dnsDefinition"&gt;DNS adresi&lt;/abbr&gt;. Notiek problēmas diagnosticēšana.</translation>
<translation id="8742371904523228557"><ph name="ONE_TIME_CODE" /> ir jūsu kods vietnei <ph name="ORIGIN" />.</translation>
@@ -2408,6 +2460,7 @@ Papildu informÄcija:
<translation id="883848425547221593">Citas grÄmatzÄ«mes</translation>
<translation id="884264119367021077">PiegÄdes adrese</translation>
<translation id="884923133447025588">Nav atrasts atsaukÅ¡anas mehÄnisms.</translation>
+<translation id="8849262850971482943">Papildu droÅ¡Ä«bai izmantojiet virtuÄlo karti</translation>
<translation id="885730110891505394">Kopīgošana ar Google</translation>
<translation id="8858065207712248076">Chrome iesaka atiestatÄ«t jÅ«su <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> paroli, ja izmantojÄt to citÄs vietnÄ“s.</translation>
<translation id="885906927438988819">Ja nav pareizrakstības kļūdu, <ph name="BEGIN_LINK" />mēģiniet palaist Windows tīkla diagnostiku<ph name="END_LINK" />.</translation>
@@ -2457,10 +2510,11 @@ Papildu informÄcija:
<translation id="9004367719664099443">Notiek VR sesija</translation>
<translation id="9005998258318286617">NeizdevÄs ielÄdÄ“t PDF dokumentu.</translation>
<translation id="9008201768610948239">Ignorēt</translation>
+<translation id="901834265349196618">e-pasts</translation>
<translation id="9020200922353704812">JÄnorÄda kartes norÄ“Ä·inu adrese</translation>
<translation id="9020542370529661692">Å Ä« lapa ir tulkota <ph name="TARGET_LANGUAGE" /> valodÄ.</translation>
<translation id="9020742383383852663">A8</translation>
-<translation id="9021429684248523859"><ph name="SHARE_THIS_PAGE_FOCUSED_FRIENDLY_MATCH_TEXT" />. Lai kopÄ«gotu Å¡o cilni, piemÄ“ram, kopÄ«gojot saiti, izveidojot ÄtrÄs atbildes kodu, sÄkot apraidi vai citÄ veidÄ, nospiediet tabulÄ“Å¡anas taustiņu un pÄ“c tam — taustiņu Enter.</translation>
+<translation id="9021429684248523859"><ph name="SHARE_THIS_PAGE_FOCUSED_FRIENDLY_MATCH_TEXT" />. Lai kopÄ«gotu Å¡o cilni, piemÄ“ram, kopÄ«gojot saiti, izveidojot kvadrÄtkodu, sÄkot apraidi vai citÄ veidÄ, nospiediet tabulÄ“Å¡anas taustiņu un pÄ“c tam — taustiņu Enter.</translation>
<translation id="9025348182339809926">(nederīgs)</translation>
<translation id="9030265603405983977">VienkrÄsaina</translation>
<translation id="9035022520814077154">Drošības kļūda</translation>
@@ -2505,6 +2559,7 @@ Papildu informÄcija:
<translation id="9150045010208374699">Izmantot jūsu videokameru</translation>
<translation id="9150685862434908345">JÅ«su administrators var attÄlinÄti mainÄ«t jÅ«su pÄrlÅ«ka iestatÄ«jumus. DarbÄ«bu Å¡ajÄ ierÄ«cÄ“ var pÄrvaldÄ«t arÄ« Ärpus Chrome. <ph name="BEGIN_LINK" />UzzinÄt vairÄk<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">AtjauninÄts</translation>
+<translation id="9155211586651734179">PievienotÄs perifÄ“rÄs audio ierÄ«ces</translation>
<translation id="9157595877708044936">Notiek uzstÄdÄ«Å¡ana...</translation>
<translation id="9158625974267017556">C6 (aploksne)</translation>
<translation id="9164029392738894042">PrecizitÄtes pÄrbaude</translation>
diff --git a/chromium/components/strings/components_strings_mk.xtb b/chromium/components/strings/components_strings_mk.xtb
index 88b823b3913..8bd71817cef 100644
--- a/chromium/components/strings/components_strings_mk.xtb
+++ b/chromium/components/strings/components_strings_mk.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">Прикажи детали</translation>
<translation id="1030706264415084469"><ph name="URL" /> Ñака трајно да Ñкладира податоци на вашиот уред</translation>
<translation id="1032854598605920125">Ротирај надеÑно</translation>
+<translation id="1033329911862281889">Со „Инкогнито“ не Ñтанувате невидливи онлајн:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Ñајтовите и уÑлугите што Ñе кориÑтат може да ги видат поÑетите<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />работодавачите или училиштата може да ја Ñледат вашата активноÑÑ‚ од прелиÑтувањето<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />интернет-операторите може да го Ñледат Ñообраќајот на интернет<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">ИÑклучи</translation>
<translation id="1036982837258183574">ПритиÑнете |<ph name="ACCELERATOR" />| за да излезете од цел екран</translation>
<translation id="1038106730571050514">Прикажувај предлози</translation>
<translation id="1038842779957582377">непознато име</translation>
<translation id="1041998700806130099">Порака на работниот лиÑÑ‚</translation>
<translation id="1048785276086539861">Кога ќе ги изменувате прибелешките, документов ќе Ñе врати на приказ на една Ñтраница</translation>
-<translation id="1049743911850919806">Инкогнито</translation>
<translation id="1050038467049342496">Затворете ги другите апликации</translation>
<translation id="1055184225775184556">&amp;Врати додавање</translation>
<translation id="1056898198331236512">Предупредување</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">Кешот на политиката е во ред</translation>
<translation id="1130564665089811311">Копче „Преведи ја Ñтраницата“, притиÑнете Enter за да ја преведете Ñтраницава Ñо „Преведи на Google“</translation>
<translation id="1131264053432022307">Сликата што ја копиравте</translation>
+<translation id="1142846828089312304">Блокирајте колачиња од трети Ñтрани во „Инкогнито“</translation>
<translation id="1150979032973867961">Серверот не може да докаже дека е <ph name="DOMAIN" />; oперативниот ÑиÑтем на компјутерот не му верува на неговиот безбедноÑен Ñертификат. Тоа може да Ñе должи на погрешна конфигурација или на напаѓач што го преÑретнува поврзувањето.</translation>
<translation id="1151972924205500581">Потребна е лозинка</translation>
<translation id="1156303062776767266">Прегледувате локална или Ñподелена датотека</translation>
@@ -64,7 +70,6 @@
<translation id="1178581264944972037">Пауза</translation>
<translation id="1181037720776840403">ОтÑтрани</translation>
<translation id="1186201132766001848">Провери ги лозинките</translation>
-<translation id="1195210374336998651">Одете во поÑтаките за апликацијата</translation>
<translation id="1195558154361252544">ИзвеÑтувањата Ñе автоматÑки блокирани за Ñите Ñајтови, оÑвен за оние за коишто Ñте ги дозволиле</translation>
<translation id="1197088940767939838">Портокалова</translation>
<translation id="1201402288615127009">Следно</translation>
@@ -111,7 +116,7 @@
<translation id="1307966114820526988">Ðеподдржани функции</translation>
<translation id="1308113895091915999">ДоÑтапна понуда</translation>
<translation id="1312803275555673949">Има докази како поддршка на ова?</translation>
-<translation id="131405271941274527"><ph name="URL" /> Ñака да иÑпраќа и прима информации кога ќе го допрете телефонот врз уред Ñо NFC</translation>
+<translation id="1314311879718644478">Прегледајте ги Ñодржините за проширена реалноÑÑ‚</translation>
<translation id="1314509827145471431">Врзување деÑно</translation>
<translation id="1318023360584041678">Зачувано во група картички</translation>
<translation id="1319245136674974084">Ðе прашувај повторно за апликацијава</translation>
@@ -161,6 +166,7 @@
<translation id="142858679511221695">КориÑник во облакот</translation>
<translation id="1428729058023778569">Ја гледате опоменава бидејќи Ñајтов не поддржува HTTPS. <ph name="BEGIN_LEARN_MORE_LINK" />Дознајте повеќе<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">Печати</translation>
+<translation id="1432187715652018471">Ñтраница Ñака да инÑталира ракувач на уÑлуги.</translation>
<translation id="1432581352905426595">Управувајте Ñо пребарувачи</translation>
<translation id="1436185428532214179">Може да прашува за да изменува датотеки и папки на уредот</translation>
<translation id="1442386063175183758">ДеÑно превиткување како брошура</translation>
@@ -181,6 +187,12 @@
<translation id="1483493594462132177">ИÑпрати</translation>
<translation id="1484290072879560759">Изберете адреÑа за иÑпорака</translation>
<translation id="1492194039220927094">Туркање на правилата:</translation>
+<translation id="149293076951187737">Кога ќе ги затворите Ñите картички „Инкогнито“ на Chrome, вашата активноÑÑ‚ во тие картички Ñе брише од уредов:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />активноÑÑ‚ од прелиÑтувањето<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />иÑторија на пребарување<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />податоци внеÑени во формулари<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">Ðазад на картичката</translation>
<translation id="1501859676467574491">Прикажувај картички од Ñметката на Google</translation>
<translation id="1507202001669085618">&lt;p&gt;Грешкава ќе ја видите ако кориÑтите Wi-Fi портал каде што мора да Ñе најавите пред да може да отидете онлајн.&lt;/p&gt;
@@ -208,6 +220,8 @@
<translation id="1559572115229829303">&lt;p&gt;Ðе може да Ñе воÑпоÑтави приватна врÑка Ñо <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> бидејќи датумот и времето на вашиот уред (<ph name="DATE_AND_TIME" />) Ñе погрешни.&lt;/p&gt;
&lt;p&gt;ПриÑпоÑобете ги датумот и времето во делот &lt;strong&gt;Општо&lt;/strong&gt; на апликацијата &lt;strong&gt;ПоÑтавки&lt;/strong&gt;.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">Вашиот админиÑтратор ќе го реÑтартира вашиот уред во <ph name="TIME" /> на <ph name="DATE" /></translation>
+<translation id="156703335097561114">Мрежните податоци, како што Ñе адреÑите, конфигурацијата на интерфејÑот и квалитетот на врÑката</translation>
<translation id="1567040042588613346">Правилово работи како што е предвидено, но иÑтата вредноÑÑ‚ е поÑтавена некаде на друго меÑто и е заменета од правилово.</translation>
<translation id="1569487616857761740">ВнеÑете датум на иÑтекување</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@
<translation id="1583429793053364125">Ðешто тргна наопаку при прикажувањето на оваа веб-Ñтраница.</translation>
<translation id="1586541204584340881">кои екÑтензии Ñте ги инÑталирале</translation>
<translation id="1588438908519853928">Ðормален</translation>
+<translation id="1589050138437146318">Да Ñе инÑталира ARCore?</translation>
<translation id="1592005682883173041">Локален приÑтап до податоците</translation>
<translation id="1594030484168838125">Избери</translation>
<translation id="160851722280695521">Играјте ја играта „Трчање на диноÑауруÑот“ во Chrome</translation>
@@ -283,6 +298,7 @@
наÑловот е лошо форматиран, што го Ñпречува прелиÑтувачот да го иÑполни
вашето барање за <ph name="SITE" />. Операторите на Ñајтови може да ги кориÑтат правилата за потекло
за конфигурирање на безбедноÑта и другите ÑвојÑтва за Ñајтот.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Дознајте повеќе за „Инкогнито“ во Chromium<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">Отворените картички Ñе појавуваат тука</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -410,6 +426,7 @@
<translation id="22081806969704220">Фиока 3</translation>
<translation id="2212735316055980242">Политиката не е пронајдена</translation>
<translation id="2213606439339815911">Земање запиÑи...</translation>
+<translation id="2213612003795704869">Страницата е иÑпечатена</translation>
<translation id="2215727959747642672">Изменување датотеки</translation>
<translation id="2218879909401188352">Ðапаѓачите што Ñе моментално на <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> може да инÑталираат опаÑни апликации што го оштетуваат вашиот уред, да додаваат Ñкриени трошоци на Ñметката за мобилниот телефон или да крадат лични информации. <ph name="BEGIN_LEARN_MORE_LINK" />Дознајте повеќе<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">Ðема интернет</translation>
@@ -419,6 +436,7 @@
<translation id="2248949050832152960">КориÑти WebAuthn</translation>
<translation id="2250931979407627383">Шиење на работ лево</translation>
<translation id="225207911366869382">Оваа вредноÑÑ‚ е заÑтарена за ова правило.</translation>
+<translation id="2256115617011615191">РеÑтартирај Ñега</translation>
<translation id="2258928405015593961">ВнеÑете датум на иÑтекување во иднина и обидете Ñе повторно</translation>
<translation id="225943865679747347">Код на грешка: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">HTTP грешка</translation>
@@ -446,6 +464,7 @@
<translation id="2337852623177822836">ПоÑтавка што ја контролира админиÑтраторот</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> Ñака да Ñе Ñпари</translation>
<translation id="2346319942568447007">Сликата што ја копиравте</translation>
+<translation id="2350796302381711542">Ќе дозволите <ph name="HANDLER_HOSTNAME" /> да ги отвори Ñите <ph name="PROTOCOL" /> врÑки намеÑто <ph name="REPLACED_HANDLER_TITLE" />?</translation>
<translation id="2354001756790975382">Други обележувачи</translation>
<translation id="2354430244986887761">Google Safe Browsing неодамна <ph name="BEGIN_LINK" />најде штетни апликации<ph name="END_LINK" /> на <ph name="SITE" />.</translation>
<translation id="2355395290879513365">Ðапаѓачите можеби ќе можат да ги видат Ñликите што ги гледате на Ñајтов и да ве измамат Ñо тоа што ќе ги модифицираат.</translation>
@@ -471,6 +490,7 @@
<translation id="2413528052993050574">Серверот не може да докаже дека е <ph name="DOMAIN" />; можеби неговиот безбедноÑен Ñертификат е повлечен. Тоа може да Ñе должи на погрешна конфигурација или на напаѓач што го преÑретнува поврзувањето.</translation>
<translation id="2414886740292270097">Темна</translation>
<translation id="2430968933669123598">Управувајте Ñо Ñметката на Google, притиÑнете го копчето Enter за да управувате Ñо податоците, приватноÑта и безбедноÑта на вашата Ñметка на Google</translation>
+<translation id="2436186046335138073">Ќе дозволите <ph name="HANDLER_HOSTNAME" /> да ги отвори Ñите врÑки на <ph name="PROTOCOL" />?</translation>
<translation id="2438874542388153331">Четири дупки деÑно</translation>
<translation id="2450021089947420533">Патувања</translation>
<translation id="2463739503403862330">Пополни</translation>
@@ -478,6 +498,7 @@
<translation id="2465655957518002998">Изберете начин на доÑтава</translation>
<translation id="2465688316154986572">Спојување</translation>
<translation id="2465914000209955735">Управувајте Ñо датотеките што Ñте ги презеле во Chrome</translation>
+<translation id="2466004615675155314">Прикажи информации од интернет</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />да извршите дијагноÑтика на мрежата<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">РедоÑлед 1-до-N</translation>
<translation id="2470767536994572628">Кога ќе ги изменувате прибелешките, документов ќе Ñе врати на приказ на една Ñтраница и на Ñвојата оригинална ротација</translation>
@@ -498,6 +519,7 @@
<translation id="2523886232349826891">Зачувано Ñамо на овој уред</translation>
<translation id="2524461107774643265">Додајте повеќе информации</translation>
<translation id="2529899080962247600">Полево не треба да има повеќе од <ph name="MAX_ITEMS_LIMIT" /> запиÑи. Сите понатамошни запиÑи ќе Ñе игнорираат.</translation>
+<translation id="2535585790302968248">Отворете нова картичка „Инкогнито“ за да прелиÑтувате приватно</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{и уште 1}one{и уште #}other{и уште #}}</translation>
<translation id="2536110899380797252">Додајте адреÑа</translation>
<translation id="2539524384386349900">Откриј</translation>
@@ -523,7 +545,14 @@
<translation id="2597378329261239068">Овој документ е заштитен Ñо лозинка. ВнеÑете лозинка.</translation>
<translation id="2609632851001447353">Варијации</translation>
<translation id="2610561535971892504">Кликнете за копирање</translation>
+<translation id="2617988307566202237">Chrome <ph name="BEGIN_EMPHASIS" />нема да ги зачувува<ph name="END_EMPHASIS" /> Ñледниве податоци:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />вашата иÑторија на прелиÑтувањето
+ <ph name="LIST_ITEM" />колачиња и податоци од Ñајтовите
+ <ph name="LIST_ITEM" />податоци внеÑени во формулари
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (плик)</translation>
+<translation id="2623663032199728144">Може да ве прашува дали да Ñе кориÑтат податоците за вашите екрани</translation>
<translation id="2625385379895617796">Вашиот чаÑовник е напред</translation>
<translation id="262745152991669301">Може да прашува за да Ñе поврзува Ñо USB-уреди</translation>
<translation id="2629325967560697240">За да го добиете навиÑокото ниво на безбедноÑÑ‚ на Chrome, <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />вклучете ја „Подобрената заштита“<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -557,6 +586,7 @@
<translation id="2709516037105925701">ÐвтоматÑко пополнување</translation>
<translation id="2713444072780614174">Бела</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />, притиÑнете Tab, а потоа Enter за да управувате Ñо податоците за плаќањата и кредитната картичка во поÑтавките за Chrome</translation>
+<translation id="271663710482723385">ПритиÑнете |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| за да излезете од цел екран</translation>
<translation id="2721148159707890343">Барањето е уÑпешно</translation>
<translation id="2723669454293168317">Извршете безбедноÑна проверка во поÑтавките за Chrome</translation>
<translation id="2726001110728089263">Странична фиока</translation>
@@ -587,6 +617,7 @@
<translation id="2850739647070081192">Invite (плик)</translation>
<translation id="2856444702002559011">Ðапаѓачите можеби Ñе обидуваат да ги украдат вашите информации од <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (на пример, лозинки, пораки или кредитни картички). <ph name="BEGIN_LEARN_MORE_LINK" />Дознајте повеќе<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">Сајтов прикажува нападни или лажни реклами.</translation>
+<translation id="286512204874376891">Виртуелната картичка ја маÑкира вашата актуелна картичка за да ја заштити од потенцијална измама. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">ПријателÑки</translation>
<translation id="2876489322757410363">Ќе излезете од режимот „Инкогнито“ за да платите преку надворешна апликација. Дали Ñакате да продолжите?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />, притиÑнете Tab, па Enter за да управувате Ñо безбедното прелиÑтување и друго во поÑтавките за Chrome</translation>
@@ -611,6 +642,7 @@
<translation id="2930577230479659665">Кратење по Ñекој примерок</translation>
<translation id="2932085390869194046">Предложете лозинка…</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019">Отвори <ph name="PROTOCOL" /> врÑки</translation>
<translation id="2941952326391522266">Серверот не може да докаже дека е <ph name="DOMAIN" />; неговиот Ñертификат е од <ph name="DOMAIN2" />. Тоа може да Ñе должи на погрешна конфигурација или на напаѓач што го преÑретнува поврзувањето.</translation>
<translation id="2943895734390379394">Време на прикачување:</translation>
<translation id="2948083400971632585">Може да ги оневозможите прокÑијата конфигурирани за врÑка од Ñтраницата поÑтавки.</translation>
@@ -643,6 +675,7 @@
<translation id="3037605927509011580">По ѓаволите!</translation>
<translation id="3041612393474885105">Информации за Ñертификат</translation>
<translation id="3044034790304486808">Продолжете Ñо иÑтражувањето</translation>
+<translation id="305162504811187366">ИÑторија на „ПриÑтап оддалеку за Chrome“, вклучително временÑки печати, хоÑтови и ID на ÑеÑии на клиент</translation>
<translation id="3060227939791841287">C9 (плик)</translation>
<translation id="3061707000357573562">УÑлуга за поправање грешки</translation>
<translation id="306573536155379004">Играта започна.</translation>
@@ -683,6 +716,7 @@
<translation id="3197136577151645743">Може да прашува за да знае кога активно го кориÑтите уредов</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />, притиÑнете Tab, па Enter за да управувате Ñо податоците коишто Ñе Ñинхронизираат во поÑтавките за Chrome</translation>
<translation id="320323717674993345">Откажи го плаќањето</translation>
+<translation id="3203366800380907218">Од интернет</translation>
<translation id="3207960819495026254">Обележано</translation>
<translation id="3209034400446768650">Страницата може да наплаќа</translation>
<translation id="3212581601480735796">Вашата активноÑÑ‚ на <ph name="HOSTNAME" /> Ñе набљудува</translation>
@@ -699,10 +733,12 @@
<translation id="3234666976984236645">Секогаш откривај важна Ñодржина на оваа локација</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />, притиÑнете Tab, а потоа Enter за да го приÑпоÑобите изгледот на прелиÑтувачот</translation>
<translation id="3240791268468473923">ЛиÑтот што означува дека нема акредитив што Ñе Ñовпаѓа за акредитивот за безбедно плаќање е отворен</translation>
+<translation id="324180406144491771">Линковите до „<ph name="HOST_NAME" />“ Ñе блокирани</translation>
<translation id="3249845759089040423">Модерен</translation>
<translation id="3252266817569339921">француÑки</translation>
<translation id="3257954757204451555">Кој Ñтои зад информацииве?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />, притиÑнете го копчето Tab, а потоа копчето Enter за да набрзина Ñоздадете нов наÑтан во „Календар на Google“</translation>
+<translation id="3261488570342242926">Дознајте за виртуелните картички</translation>
<translation id="3264837738038045344">Управувајте Ñо поÑтавките за Chrome, притиÑнете Enter за да одите во поÑтавките за Chrome</translation>
<translation id="3266793032086590337">ВредноÑÑ‚ (конфликт)</translation>
<translation id="3268451620468152448">Отворени картички</translation>
@@ -716,6 +752,7 @@
<translation id="3288238092761586174"><ph name="URL" /> можеби ќе треба да преземе дополнителни чекори за да го потврди вашето плаќање</translation>
<translation id="3293642807462928945">Дознајте повеќе за правилото <ph name="POLICY_NAME" /></translation>
<translation id="3295444047715739395">Прегледајте ги и управувајте Ñо лозинките во поÑтавките за Chrome</translation>
+<translation id="3303795387212510132">Дозволувате апликацијата да ги отвори линковите за <ph name="PROTOCOL_SCHEME" />?</translation>
<translation id="3303855915957856445">Ðе Ñе пронајдени резултати од пребарувањето</translation>
<translation id="3304073249511302126">Ñкенирање за Bluetooth</translation>
<translation id="3308006649705061278">ОрганизациÑка единица (ОУ)</translation>
@@ -729,12 +766,6 @@
<translation id="3345782426586609320">Очи</translation>
<translation id="3355823806454867987">Промени прокÑи-поÑтавки...</translation>
<translation id="3360103848165129075">ЛиÑÑ‚ на ракувачот Ñо плаќања</translation>
-<translation id="3361596688432910856">Chrome <ph name="BEGIN_EMPHASIS" />нема да ги зачува<ph name="END_EMPHASIS" /> Ñледниве информации:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />иÑторијата на прелиÑтување
- <ph name="LIST_ITEM" />колачињата и податоците за локацијата
- <ph name="LIST_ITEM" />внеÑените информации во формуларите
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">Правилово беше автоматÑки копирано од неподдржаното правило <ph name="OLD_POLICY" />. ÐамеÑто него, треба да го кориÑтите ова правило.</translation>
<translation id="3364869320075768271"><ph name="URL" /> Ñака да ги кориÑти уредот и податоците за виртуелна реалноÑÑ‚</translation>
<translation id="3366477098757335611">Прикажи ги картичките</translation>
@@ -817,7 +848,6 @@
<translation id="3587738293690942763">Средна</translation>
<translation id="3592413004129370115">Italian (плик)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{Може да ја реÑтирате групата во Ñекое време. Потребен е околу еден ден за да Ñе придружите на нова група.}=1{Може да ја реÑтирате групата во Ñекое време. Потребен е околу еден ден за да Ñе придружите на нова група.}one{Може да ја реÑтирате групата во Ñекое време. Потребен е околу {NUM_DAYS} ден за да Ñе придружите на нова група.}other{Може да ја реÑтирате групата во Ñекое време. Потребни Ñе околу {NUM_DAYS} дена за да Ñе придружите на нова група.}}</translation>
-<translation id="3596012367874587041">ПоÑтавки за апликацијата</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">ÐдминиÑтраторот ја блокирал апликацијата</translation>
<translation id="3608932978122581043">Одржи ја ориентацијата</translation>
@@ -860,6 +890,7 @@
<translation id="370972442370243704">Вклучи „Патувања“</translation>
<translation id="3711895659073496551">СуÑпендирај</translation>
<translation id="3712624925041724820">ИÑцрпени лиценци</translation>
+<translation id="3714633008798122362">веб-календар</translation>
<translation id="3714780639079136834">Да вклучите мобилен интернет или Wi-Fi</translation>
<translation id="3715597595485130451">Поврзете Ñе Ñо Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Да ги проверите прокÑито, заштитниот ѕид и DNS-конфигурацијата<ph name="END_LINK" /></translation>
@@ -921,6 +952,7 @@
<translation id="3906954721959377182">Таблет</translation>
<translation id="3909477809443608991"><ph name="URL" /> Ñака да пушти заштитени Ñодржини. Google ќе го потврди идентитетот на вашиот уред, а Ñајтов ќе може да приÑтапи до него.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">Одбиј</translation>
<translation id="3939773374150895049">Да Ñе кориÑти WebAuthn намеÑто CVC?</translation>
<translation id="3946209740501886391">Прашувај Ñекогаш на овој Ñајт</translation>
<translation id="3947595700203588284">Може да прашува за да Ñе поврзува Ñо MIDI-уреди</translation>
@@ -942,6 +974,7 @@
<translation id="3990250421422698716">ОфÑет превиткување</translation>
<translation id="3996311196211510766">Сајтот <ph name="ORIGIN" /> побарал да Ñе применува правило за потекло
за Ñите барања до него, но ова правило не може да Ñе примени во моментов.</translation>
+<translation id="4009243425692662128">Содржините на Ñтраниците што ги печатите Ñе иÑпраќаат на Google Cloud или трети Ñтрани за анализа. Ðа пример, можеби ќе Ñе Ñкенираат за да Ñе провери дали Ñодржат чувÑтвителни податоци.</translation>
<translation id="4010758435855888356">Да Ñе дозволи приÑтап до капацитетот?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{PDF-документ Ñо {COUNT} Ñтраница}one{PDF-документ Ñо {COUNT} Ñтраница}other{PDF-документ Ñо {COUNT} Ñтраници}}</translation>
<translation id="4023431997072828269">Бидејќи формуларов Ñе иÑпраќа преку врÑка што не е безбедна, вашите податоци ќе бидат видливи за другите.</translation>
@@ -1036,6 +1069,7 @@
<translation id="4250680216510889253">Ðе</translation>
<translation id="4253168017788158739">Забелешка</translation>
<translation id="425582637250725228">Измените што ги направивте можеби нема да Ñе зачуваат.</translation>
+<translation id="425869179292622354">Дали Ñакате поголема безбедноÑÑ‚ Ñо виртуелна картичка?</translation>
<translation id="4258748452823770588">Лош потпиÑ</translation>
<translation id="4261046003697461417">Ðе може да Ñе Ñтави прибелешка на заштитени документи</translation>
<translation id="4265872034478892965">Дозволено од админиÑтраторот</translation>
@@ -1098,6 +1132,7 @@
<translation id="4434045419905280838">Скокачки прозорци/пренаÑочувања</translation>
<translation id="4435702339979719576">Разгледница)</translation>
<translation id="443673843213245140">Оневозможена е употребата на прокÑи, но одредена е опширна конфигурација на прокÑи.</translation>
+<translation id="4441832193888514600">Игнорирано бидејќи правилото може да Ñе поÑтави Ñамо како политика за кориÑници во облак.</translation>
<translation id="4450893287417543264">Ðе прикажувај повторно</translation>
<translation id="4451135742916150903">Може да прашува за да Ñе поврзува Ñо HID-уреди</translation>
<translation id="4452328064229197696">Отркиено е дека лозинката која штотуку ја употребивте е меѓу лозинките откриени при упад во податоците. За да ја задржите безбедноÑта на Ñметките, „Управникот Ñо лозинки на Google“ препорачува да ги проверите зачуваните лозинки.</translation>
@@ -1153,6 +1188,7 @@
<translation id="4628948037717959914">Фотографија</translation>
<translation id="4631649115723685955">Со поврат на готовина</translation>
<translation id="4636930964841734540">Информации</translation>
+<translation id="4638670630777875591">„Инкогнито“ во Chromium</translation>
<translation id="464342062220857295">Функции за пребарување</translation>
<translation id="4644670975240021822">Обратен редоÑлед Ñо лицето надолу</translation>
<translation id="4646534391647090355">ОднеÑи ме таму Ñега</translation>
@@ -1173,6 +1209,7 @@
<translation id="4708268264240856090">Ð’Ñ€Ñката беше прекината</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />да извршите дијагноÑтика на мрежата на Windows<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426">Лозинка за <ph name="USERNAME" /></translation>
<translation id="4724144314178270921">Може да прашува за да гледа текÑÑ‚ и Ñлики од привремената меморија</translation>
<translation id="4726672564094551039">Повторно вчитување политики</translation>
<translation id="4728558894243024398">Платформа</translation>
@@ -1194,6 +1231,7 @@
<translation id="4757993714154412917">Тукушто ја внеÑовте Ñвојата лозинка на измамнички Ñајт. За да ги заштитите Ñметките, Chromium ви препорачува да ги проверите зачуваните лозинки.</translation>
<translation id="4758311279753947758">Додај информации за контакт</translation>
<translation id="4761104368405085019">КориÑтете го микрофонот</translation>
+<translation id="4761869838909035636">Изврши безбедноÑна проверка во Chrome</translation>
<translation id="4764776831041365478">Веб-локацијата на <ph name="URL" /> можеби привремено не работи или можеби е трајно премеÑтена на нова веб-адреÑа.</translation>
<translation id="4766713847338118463">Двојно Ñпојување долу</translation>
<translation id="4771973620359291008">Се појави непозната грешка.</translation>
@@ -1214,12 +1252,6 @@
<translation id="4819347708020428563">Сакате ли да ги измените прибелешките во Ñтандарден приказ?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />, притиÑнете го копчето Tab, а потоа копчето Enter за да набрзина Ñоздадете нова табела на Google</translation>
<translation id="4825507807291741242">Моќен</translation>
-<translation id="4827402517081186284">Со „Инкогнито“ не Ñтанувате невидливи онлајн:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Ñајтовите знаат кога ги поÑетувате<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />работодавачите или училиштата може да ја Ñледат вашата активноÑÑ‚ од прелиÑтувањето<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />интернет-операторите може да го Ñледат Ñообраќајот на интернет<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">Вклучи опомени</translation>
<translation id="4838327282952368871">Ðереален</translation>
<translation id="4840250757394056958">Прикажи ја иÑторијата на Chrome</translation>
@@ -1231,12 +1263,12 @@
<translation id="4854362297993841467">Овој метод за доÑтавување не е доÑтапен. Изберете друг.</translation>
<translation id="4854853140771946034">Ðабрзина Ñоздајте нова белешка во Google Keep</translation>
<translation id="485902285759009870">Се потврдува кодот…</translation>
+<translation id="4866506163384898554">ПритиÑнете |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| за да Ñе прикаже курÑорот</translation>
<translation id="4876188919622883022">ПоедноÑтавен приказ</translation>
<translation id="4876305945144899064">Ðема кориÑничко име</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{Ðиеден}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}one{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831">Пребарување <ph name="TEXT" /></translation>
<translation id="4879491255372875719">ÐвтоматÑки (Ñтандардно)</translation>
-<translation id="4879725228911483934">Отвора и поÑтавува прозорци на вашиот екран</translation>
<translation id="4880827082731008257">ИÑторија на пребарување</translation>
<translation id="4881695831933465202">Отвори</translation>
<translation id="4885256590493466218">Платете Ñо <ph name="CARD_DETAIL" /> при наплатата</translation>
@@ -1245,6 +1277,7 @@
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">Деветта ролна</translation>
<translation id="4901778704868714008">Зачувај…</translation>
+<translation id="4905659621780993806">Вашиот админиÑтратор ќе го реÑтартира уредот автоматÑки во <ph name="TIME" /> на <ph name="DATE" /> Зачувајте ги отворените Ñтавки пред да Ñе реÑтартира уредот.</translation>
<translation id="4913987521957242411">Дупка горе лево</translation>
<translation id="4918221908152712722">ИнÑталирајте ја <ph name="APP_NAME" /> (не е потребно преземање)</translation>
<translation id="4923459931733593730">Плаќање</translation>
@@ -1253,6 +1286,7 @@
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, притиÑнете Tab, а потоа Enter за да пребарувате</translation>
<translation id="4930153903256238152">Голем капацитет</translation>
+<translation id="4940163644868678279">„Инкогнито“ во Chrome</translation>
<translation id="4943872375798546930">Ðема резултати</translation>
<translation id="4950898438188848926">Копче за префрлање помеѓу картички, притиÑнете Enter за да Ñе префрлите на отворената картичка, <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="495170559598752135">ДејÑтва</translation>
@@ -1262,6 +1296,7 @@
<translation id="4968522289500246572">Ðпликацијава е дизајнирана за мобилен уред и можеби нема добро да ја промени големината. Ðпликацијата може да има проблеми или да Ñе реÑтартира.</translation>
<translation id="4969341057194253438">Избриши ја Ñнимката</translation>
<translation id="4973922308112707173">Две дупки горе</translation>
+<translation id="4976702386844183910">ПоÑледно поÑетено на <ph name="DATE" /></translation>
<translation id="4984088539114770594">Да Ñе кориÑти микрофонот?</translation>
<translation id="4984339528288761049">Prc5 (плик)</translation>
<translation id="4989163558385430922">Прикажи ги Ñите</translation>
@@ -1323,6 +1358,7 @@
<translation id="5138227688689900538">Прикажи помалку</translation>
<translation id="5145883236150621069">ПриÑутен е код на грешка во одговорот на правилото</translation>
<translation id="5146995429444047494">ИзвеÑтувањата за <ph name="ORIGIN" /> Ñе блокирани</translation>
+<translation id="514704532284964975"><ph name="URL" /> Ñака да гледа и менува податоци на NFC-уреди што ги допирате Ñо вашиот телефон</translation>
<translation id="5148809049217731050">Со лицето нагоре</translation>
<translation id="515292512908731282">C4 (плик)</translation>
<translation id="5158275234811857234">Корица</translation>
@@ -1347,6 +1383,7 @@
<translation id="5215116848420601511">Ðачини на плаќање и адреÑи преку Google Pay</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">Фиока 13</translation>
+<translation id="5216942107514965959">ПоÑледно поÑетено денеÑ</translation>
<translation id="5222812217790122047">Потребна е е-пошта</translation>
<translation id="5230733896359313003">ÐдреÑа за иÑпорака</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1367,7 +1404,6 @@
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">СвојÑтва на документот</translation>
<translation id="528468243742722775">Крај</translation>
-<translation id="5284909709419567258">Мрежни адреÑи</translation>
<translation id="5285570108065881030">Прикажи ги Ñите зачувани лозинки</translation>
<translation id="5287240709317226393">Прикажете ги колачињата</translation>
<translation id="5287456746628258573">Сајтов кориÑти заÑтарена конфигурација за безбедноÑÑ‚, што може да ги изложи вашите информации (на пример, лозинките или броевите на кредитните картички) кога Ñе иÑпраќаат на овој Ñајт.</translation>
@@ -1451,6 +1487,7 @@
<translation id="5556459405103347317">Повторно вчитај</translation>
<translation id="5560088892362098740">Датум на иÑтекување</translation>
<translation id="55635442646131152">Преглед на документ</translation>
+<translation id="5565613213060953222">Отвори картичка „Инкогнито“</translation>
<translation id="5565735124758917034">Ðктивно</translation>
<translation id="5570825185877910964">Заштити ја Ñметката</translation>
<translation id="5571083550517324815">Ðе може да Ñе подигне од оваа адреÑа. Изберете друга.</translation>
@@ -1533,6 +1570,7 @@
<translation id="5869522115854928033">Зачувани лозинки</translation>
<translation id="5873013647450402046">Вашата банка Ñака да потврди дека Ñте вие.</translation>
<translation id="5887400589839399685">Картичката е зачувана</translation>
+<translation id="5887687176710214216">ПоÑледно поÑетено вчера</translation>
<translation id="5895138241574237353">РеÑтартирај</translation>
<translation id="5895187275912066135">Издадено на</translation>
<translation id="5901630391730855834">Жолта боја</translation>
@@ -1546,6 +1584,7 @@
<translation id="5921639886840618607">Да Ñе зачува картичката на Ñметката на Google?</translation>
<translation id="5922853866070715753">РечиÑи готово</translation>
<translation id="5932224571077948991">Сајтот прикажува нападни или лажни реклами</translation>
+<translation id="5938153366081463283">Додајте виртуелна картичка</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347">Се отвора <ph name="SITE_NAME" />…</translation>
<translation id="5951495562196540101">Ðе може да Ñе региÑтрирате Ñо Ñметка на потрошувач (доÑтапна е вклучена лиценца).</translation>
@@ -1610,6 +1649,7 @@
<translation id="6120179357481664955">Да Ñе запомни ID за UPI?</translation>
<translation id="6124432979022149706">Chrome Enterprise Connectors</translation>
<translation id="6127379762771434464">Ставката е отÑтранета</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Дознајте повеќе за „Инкогнито“ во Chrome<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">Проверете ги каблите и реÑтартирајте ги рутерите, модемите или другите мрежни
уреди што ги кориÑтите.</translation>
<translation id="614940544461990577">Обидете Ñе:</translation>
@@ -1622,7 +1662,6 @@
<translation id="6169916984152623906">Сега може да прелиÑтувате приватно, а другите луѓе кои го кориÑтат уредов нема да ја видат вашата активноÑÑ‚. Сепак, преземањата и обележувачите ќе Ñе зачуваат.</translation>
<translation id="6177128806592000436">Ð’Ñ€Ñката Ñо овој Ñајт не е безбедна</translation>
<translation id="6180316780098470077">Обиди Ñе повторно Ñо интервалот</translation>
-<translation id="619448280891863779">Може да прашува за да отвора и поÑтавува прозорци на екраните</translation>
<translation id="6196640612572343990">Блокирај колачиња од трети лица</translation>
<translation id="6203231073485539293">Проверете го поврзувањето на интернет</translation>
<translation id="6218753634732582820">Да Ñе отÑтрани адреÑата од Chromium?</translation>
@@ -1645,7 +1684,7 @@
<translation id="6272383483618007430">Ðжурирање од Google</translation>
<translation id="6276112860590028508">Страниците од ÑпиÑокот за читање Ñе појавуваат тука</translation>
<translation id="627746635834430766">За да платите побрзо Ñледниот пат, зачувајте ја картичката и адреÑата за наплата на вашата Ñметка на Google.</translation>
-<translation id="6279098320682980337">Ðе е пополнет бројот на виртуелна картичка? Кликнете на деталите за картичка за да Ñе иÑкопираат</translation>
+<translation id="6279183038361895380">ПритиÑнете |<ph name="ACCELERATOR" />| за да Ñе покаже покажувачот</translation>
<translation id="6280223929691119688">Ðе може да Ñе доÑтави на оваа адреÑа. Изберете друга.</translation>
<translation id="6282194474023008486">ПоштенÑки број</translation>
<translation id="6285507000506177184">Копче „Управувајте Ñо преземањата во Chrome“, притиÑнете Enter за да управувате Ñо датотеките што Ñте ги презеле во Chrome</translation>
@@ -1653,6 +1692,7 @@
<translation id="6290238015253830360">Предложените Ñтатии ќе Ñе појавуваат тука</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{Уредот ќе Ñе реÑтартира Ñега}=1{Уредот ќе Ñе реÑтартира за 1 Ñекунда}one{Уредот ќе Ñе реÑтартира за # Ñекунда}other{Уредот ќе Ñе реÑтартира за # Ñекунди}}</translation>
<translation id="6302269476990306341">Се запира „Помошникот на Google“ во Chrome</translation>
<translation id="6305205051461490394"><ph name="URL" /> е недоÑтапна.</translation>
<translation id="6312113039770857350">Веб-Ñтраницата не е доÑтапна</translation>
@@ -1726,6 +1766,7 @@
<translation id="6529602333819889595">&amp;Повтори бришење</translation>
<translation id="6545864417968258051">Скенирање за Bluetooth</translation>
<translation id="6547208576736763147">Две дупки лево</translation>
+<translation id="6554732001434021288">ПоÑледно поÑетено пред <ph name="NUM_DAYS" /> дена</translation>
<translation id="6556866813142980365">Повтори</translation>
<translation id="6569060085658103619">Гледате Ñтраница Ñо екÑтензии</translation>
<translation id="6573200754375280815">Две дупки деÑно</translation>
@@ -1740,7 +1781,7 @@
<translation id="6596325263575161958">Опции за шифрирање</translation>
<translation id="6609880536175561541">Prc7 (плик)</translation>
<translation id="6615297766614333076">Фиока за Ñкладирање 2</translation>
-<translation id="6624427990725312378">Информации за контакт</translation>
+<translation id="6624427990725312378">Податоци за контакт</translation>
<translation id="6626291197371920147">Додајте валиден број на картичка</translation>
<translation id="6628463337424475685">Пребарување на <ph name="ENGINE" /></translation>
<translation id="6630043285902923878">Се бараат USB-уреди…</translation>
@@ -1786,7 +1827,6 @@
<translation id="6757797048963528358">Уредот е во режим на Ñпиење.</translation>
<translation id="6767985426384634228">Да Ñе ажурира адреÑата?</translation>
<translation id="6768213884286397650">Hagaki (разгледница)</translation>
-<translation id="6774185088257932239"><ph name="BEGIN_LINK" />Дознајте повеќе<ph name="END_LINK" /> за „Инкогнито“</translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">Виолетова</translation>
<translation id="6786747875388722282">ÐаÑтавки</translation>
@@ -1868,9 +1908,8 @@
<translation id="7058163556978339998"><ph name="BROWSER" /> потврди дека <ph name="ISSUER" /> го издал Ñертификатот за веб-Ñајтов.</translation>
<translation id="7062635574500127092">Синозелена</translation>
<translation id="706295145388601875">Додавајте и управувајте Ñо адреÑи во поÑтавките за Chrome</translation>
-<translation id="7064851114919012435">Информации за контакт</translation>
+<translation id="7064851114919012435">Податоци за контакт</translation>
<translation id="7068733155164172741">ВнеÑете го <ph name="OTP_LENGTH" />-цифрениот код</translation>
-<translation id="7070090581017165256">За Ñајтов</translation>
<translation id="70705239631109039">Вашата врÑка не е потполно безбедна</translation>
<translation id="7075452647191940183">Барањето е предолго</translation>
<translation id="7079718277001814089">Сајтов Ñодржи злонамерен Ñофтвер</translation>
@@ -1887,6 +1926,12 @@
<translation id="7111012039238467737">(Важечки)</translation>
<translation id="7118618213916969306">Пребарајте URL-адреÑа во привремената меморија, <ph name="SHORT_URL" /></translation>
<translation id="7119414471315195487">Затворете ги другите картички или програми</translation>
+<translation id="7129355289156517987">Кога ќе ги затворите Ñите картички „Инкогнито“ на Chromium, вашата активноÑÑ‚ во тие картички Ñе брише од уредов:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />активноÑÑ‚ од прелиÑтувањето<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />иÑторија на пребарување<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />податоци внеÑени во формулари<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">Ðе може да Ñе иÑпорача на оваа адреÑа. Изберете друга.</translation>
<translation id="7132939140423847331">ÐдминиÑтраторот забранил копирање на податоциве.</translation>
<translation id="7135130955892390533">Прикажи го ÑтатуÑот</translation>
@@ -1909,6 +1954,7 @@
<translation id="7192203810768312527">Ќе оÑлободи <ph name="SIZE" />. Ðекои Ñајтови може да Ñе вчитуваат побавно при вашата Ñледна поÑета.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">ÐдминиÑтраторот може да гледа:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, притиÑнете Tab, а потоа Enter за да отворите нова картичка „Инкогнито“ и да прелиÑтувате приватно</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> не Ñе придржува до Ñтандардите за безбедноÑÑ‚.</translation>
<translation id="7210993021468939304">ÐктивноÑта на Linux во рамките на контејнерот и може да инÑталира и извршува апликации на Linux во рамките на контејнерот</translation>
@@ -1940,6 +1986,7 @@
<translation id="7304562222803846232">Управувајте Ñо поÑтавките за приватноÑÑ‚ на вашата Ñметка на Google</translation>
<translation id="7305756307268530424">Стартувај побавно</translation>
<translation id="7308436126008021607">Ñинхронизација во заднина</translation>
+<translation id="7310392214323165548">Уредот ќе Ñе реÑтартира наÑкоро</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">Помош за поврзување</translation>
<translation id="7323804146520582233">Сокриј го делот „<ph name="SECTION" />“</translation>
@@ -1947,6 +1994,7 @@
<translation id="7334320624316649418">&amp;Повтори преуредување</translation>
<translation id="7335157162773372339">Може да прашува за да ја кориÑти камерата</translation>
<translation id="7337248890521463931">Прикажи повеќе редови</translation>
+<translation id="7337418456231055214">Ðе е пополнет бројот на виртуелната картичка? Кликнете на деталите за картичка за да Ñе копираат. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">Ðе е доÑтапен на вашата платформа.</translation>
<translation id="733923710415886693">Сертификатот на Ñерверот не е откриен преку ТранÑпарентноÑÑ‚ на Ñертификати.</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1969,6 +2017,7 @@
<translation id="7378627244592794276">Ðе</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">Ðе е применливо</translation>
+<translation id="7388594495505979117">{0,plural, =1{Уредот ќе Ñе реÑтартира за 1 минута}one{Уредот ќе Ñе реÑтартира за # минута}other{Уредот ќе Ñе реÑтартира за # минути}}</translation>
<translation id="7390545607259442187">Потврдете ја картичката</translation>
<translation id="7392089738299859607">Ðжурирајте ја адреÑата</translation>
<translation id="7399802613464275309">Проверка на безбедноÑта</translation>
@@ -2005,6 +2054,12 @@
<translation id="7485870689360869515">Ðе Ñе пронајдени податоци.</translation>
<translation id="7495528107193238112">Содржинава е блокирана. Контактирајте Ñо ÑопÑтвеникот на Ñајтот за поправка на проблемот.</translation>
<translation id="7497998058912824456">Копче за Ñоздавање документ, притиÑнете го копчето Enter за да набрзина Ñоздадете нов документ на Google</translation>
+<translation id="7506488012654002225">Chromium <ph name="BEGIN_EMPHASIS" />нема да ги зачувува<ph name="END_EMPHASIS" /> Ñледниве податоци:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />вашата иÑторија на прелиÑтувањето
+ <ph name="LIST_ITEM" />колачиња и податоци од Ñајтовите
+ <ph name="LIST_ITEM" />податоци внеÑени во формулари
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">Вратениот id на уредот на правилото е празен или не ÑоодветÑтвува Ñо тековниот id на уредот</translation>
<translation id="7508870219247277067">Зелена како авокадо</translation>
<translation id="7511955381719512146">Wi-Fi што го кориÑтите може да бара да ја поÑетите Ñтраницата <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
@@ -2118,7 +2173,6 @@
<translation id="7813600968533626083">ОтÑтрани ги предлозите за формулари од Chrome?</translation>
<translation id="781440967107097262">Да Ñе Ñподели привремената меморија?</translation>
<translation id="7815407501681723534">Пронајдени Ñе <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> за „<ph name="SEARCH_STRING" />“</translation>
-<translation id="782125616001965242">Прикажи информации за Ñајтов</translation>
<translation id="782886543891417279">Wi-Fi што го кориÑтите (<ph name="WIFI_NAME" />) може да бара да ја поÑетите Ñтраницата за најавување.</translation>
<translation id="7836231406687464395">Postfix (плик)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{Ðишто}=1{1 апликација (<ph name="EXAMPLE_APP_1" />)}=2{2 апликации (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}one{# апликација (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}other{# апликации (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}}</translation>
@@ -2135,7 +2189,6 @@
<translation id="7888575728750733395">Ðамера за прикажување на печатењето</translation>
<translation id="7894280532028510793">Ðко правопиÑот е точен, <ph name="BEGIN_LINK" />извршете дијагноÑтика на мрежата<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (плик)</translation>
-<translation id="7931318309563332511">Ðепознат</translation>
<translation id="793209273132572360">Да Ñе ажурира адреÑата?</translation>
<translation id="7932579305932748336">Омот</translation>
<translation id="79338296614623784">ВнеÑете важечки телефонÑки број</translation>
@@ -2160,13 +2213,14 @@
<translation id="7976214039405368314">Премногу барања</translation>
<translation id="7977538094055660992">Излезен уред</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">Поврзана Ñо</translation>
<translation id="798134797138789862">Може да прашува за да ги кориÑти податоците и уредите Ñо виртуелна реалноÑÑ‚</translation>
<translation id="7984945080620862648">Ðе може Ñега да го поÑетите <ph name="SITE" /> затоа што веб-локацијата иÑпрати измешани акредитации што Chrome не може да ги обработи. Мрежните грешки и напади обично Ñе привремени, така што Ñтраницата веројатно ќе работи подоцна.</translation>
-<translation id="79859296434321399">За да прегледувате Ñодржини во проширена реалноÑÑ‚, инÑталирајте го ARCore</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">Врзување</translation>
<translation id="7992044431894087211">Споделувањето екран Ñо <ph name="APPLICATION_TITLE" /> продолжи</translation>
<translation id="7995512525968007366">Ðе е наведено</translation>
+<translation id="7998269595945679889">Копче „Отвори картичка Инкогнито“, притиÑнете Enter за да отворите нова картичка „Инкогнито“ и да прелиÑтувате приватно</translation>
<translation id="800218591365569300">Обидете Ñе да ги затворите другите картички или програми за да оÑлободите меморија.</translation>
<translation id="8004582292198964060">ПрелиÑтувач</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{Картичкава и нејзината адреÑа за наплата ќе Ñе зачуваат. Ќе може да ја кориÑтите кога ќе Ñе најавите на <ph name="USER_EMAIL" />.}one{Картичкиве и нивните адреÑи за наплата ќе Ñе зачуваат. Ќе може да ги кориÑтите кога ќе Ñе најавите на <ph name="USER_EMAIL" />.}other{Картичкиве и нивните адреÑи за наплата ќе Ñе зачуваат. Ќе може да ги кориÑтите кога ќе Ñе најавите на <ph name="USER_EMAIL" />.}}</translation>
@@ -2226,6 +2280,7 @@
<translation id="8202370299023114387">Конфликт</translation>
<translation id="8206978196348664717">Prc4 (плик)</translation>
<translation id="8211406090763984747">Ð’Ñ€Ñката е безбедна</translation>
+<translation id="8217240300496046857">Сајтовите не можe да кориÑтат колачиња што ве Ñледат на интернет Функциите на некои Ñајтови можеби нема да работат.</translation>
<translation id="8218327578424803826">Доделена локација:</translation>
<translation id="8220146938470311105">C7/C6 (плик)</translation>
<translation id="8225771182978767009">Лицето кое го поÑтавило компјутерот избрало да Ñе блокира Ñајтов.</translation>
@@ -2266,14 +2321,9 @@
<translation id="830498451218851433">Превиткување на половина</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">ИнÑталирани апликации и колку чеÑто Ñе кориÑтат</translation>
+<translation id="8317207217658302555">Да Ñе ажурира ARCore?</translation>
<translation id="831997045666694187">Приквечер</translation>
<translation id="8321476692217554900">извеÑтувања</translation>
-<translation id="8328484624016508118">Откако ќе ги затворите Ñите картички „Инкогнито“, Chrome ги брише:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />активноÑта од прелиÑтувањето од уредов<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />иÑторијата на пребарување од уредов<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />податоците внеÑени во формулари<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489">ПриÑтапот до <ph name="HOST_NAME" /> беше одбиен</translation>
<translation id="833262891116910667">ÐаглаÑување</translation>
<translation id="8339163506404995330">Страниците на <ph name="LANGUAGE" /> нема да Ñе преведуваат</translation>
@@ -2325,6 +2375,7 @@
<translation id="8507227106804027148">Командна линија</translation>
<translation id="8508648098325802031">Икона за пребарување</translation>
<translation id="8511402995811232419">Управувај Ñо колачињата</translation>
+<translation id="8519753333133776369">HID-уред дозволен од вашиот админиÑтратор</translation>
<translation id="8522552481199248698">Chrome може да ви помогне да ја заштитите Ñметката на Google и да ја промените лозинката.</translation>
<translation id="8530813470445476232">Избришете ја иÑторијата на прелиÑтување, колачињата, кешот и друго во поÑтавките за Chrome</translation>
<translation id="8533619373899488139">Одете на &lt;strong&gt;chrome://policy&lt;/strong&gt; за да го видите ÑпиÑокот Ñо блокирани URL-адреÑи, како и други правила што ги наметнал ÑиÑтемÑкиот админиÑтратор.</translation>
@@ -2336,7 +2387,6 @@
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{РеÑетирај ја дозволата}one{РеÑетирај ги дозволите}other{РеÑетирај ги дозволите}}</translation>
<translation id="8555010941760982128">КориÑтете го кодов при наплатата</translation>
<translation id="8557066899867184262">CVC-бројот Ñе наоѓа на задната Ñтрана на картичката.</translation>
-<translation id="8558485628462305855">За да прегледувате Ñодржини во проширена реалноÑÑ‚, ажурирајте го ARCore</translation>
<translation id="8559762987265718583">Ðе може да Ñе воÑпоÑтави приватна врÑка до <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> бидејќи датумот и времето на вашиот уред (<ph name="DATE_AND_TIME" />) Ñе погрешни.</translation>
<translation id="8564182942834072828">Одделни документи/неподредени примероци</translation>
<translation id="8564985650692024650">Chromium препорачува реÑетирање на лозинката за <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> ако повторно Ñте ја употребиле на други Ñајтови.</translation>
@@ -2355,6 +2405,7 @@
<translation id="865032292777205197">Ñензори за движење</translation>
<translation id="8663226718884576429">Краток преглед на нарачка, <ph name="TOTAL_LABEL" />, повеќе детали</translation>
<translation id="8666678546361132282">англиÑки</translation>
+<translation id="8669306706049782872">КориÑтење податоци за вашите екрани за отворање и поÑтавување прозорци</translation>
<translation id="867224526087042813">ПотпиÑ</translation>
<translation id="8676424191133491403">Без одложување</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, одговор, <ph name="ANSWER" /></translation>
@@ -2381,6 +2432,7 @@
<translation id="8731544501227493793">Копче „Управувајте Ñо лозинките“, притиÑнете Enter за да ги прегледувате и да управувате Ñо вашите лозинки во поÑтавките за Chrome</translation>
<translation id="8734529307927223492"><ph name="MANAGER" /> управува Ñо вашиот <ph name="DEVICE_TYPE" /></translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, притиÑнете Tab, а потоа Enter за да отворите нов прозорец „Инкогнито“ и да прелиÑтувате приватно</translation>
+<translation id="8737685506611670901">Отвори <ph name="PROTOCOL" /> врÑки намеÑто <ph name="REPLACED_HANDLER_TITLE" /></translation>
<translation id="8738058698779197622">За воÑпоÑтавување безбедна врÑка, вашиот чаÑовник треба да биде правилно поÑтавен. Ова е така затоа што Ñертификатите кои веб-локациите ги кориÑтат за да Ñе идентификуваат важат Ñамо определени периоди на време. Бидејќи чаÑовникот на вашиот уред не е точен, Chromium не може да ги потврди овие Ñертификати.</translation>
<translation id="8740359287975076522">&lt;abbr id="dnsDefinition"&gt;DNS-адреÑата&lt;/abbr&gt; на <ph name="HOST_NAME" /> не може да Ñе пронајде. Го дијагноÑтицираме проблемот.</translation>
<translation id="8742371904523228557"><ph name="ONE_TIME_CODE" /> е вашиот код за <ph name="ORIGIN" /></translation>
@@ -2408,6 +2460,7 @@
<translation id="883848425547221593">Други обележувачи</translation>
<translation id="884264119367021077">ÐдреÑа на иÑпорака</translation>
<translation id="884923133447025588">Ðе Ñе најде механизам за отповикување.</translation>
+<translation id="8849262850971482943">КориÑтете ја виртуелната картичка за дополнителна безбедноÑÑ‚</translation>
<translation id="885730110891505394">Споделување Ñо Google</translation>
<translation id="8858065207712248076">Chrome препорачува реÑетирање на лозинката за <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> ако повторно Ñте ја употребиле на други Ñајтови.</translation>
<translation id="885906927438988819">Ðко правопиÑот е точен, <ph name="BEGIN_LINK" />извршете дијагноÑтика на мрежата на Windows<ph name="END_LINK" />.</translation>
@@ -2457,6 +2510,7 @@
<translation id="9004367719664099443">Во тек е ÑеÑија за VR</translation>
<translation id="9005998258318286617">Ðе уÑпеа да Ñе вчита PDF-документот.</translation>
<translation id="9008201768610948239">Игнорирај</translation>
+<translation id="901834265349196618">е-пошта</translation>
<translation id="9020200922353704812">ÐдреÑата за наплата на картичката е задолжителна</translation>
<translation id="9020542370529661692">Страницава е преведена на <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9020742383383852663">A8</translation>
@@ -2505,6 +2559,7 @@
<translation id="9150045010208374699">КориÑти ја камерата</translation>
<translation id="9150685862434908345">ÐдминиÑтраторот може да го промени поÑтавувањето на прелиÑтувачот далечинÑки. ÐктивноÑта на уредов може да Ñе управува и надвор од Chrome. <ph name="BEGIN_LINK" />Дознајте повеќе<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">Ðжурно</translation>
+<translation id="9155211586651734179">Поврзани периферни уреди за аудио</translation>
<translation id="9157595877708044936">Се поÑтавува…</translation>
<translation id="9158625974267017556">C6 (плик)</translation>
<translation id="9164029392738894042">Проверка на прецизноÑта</translation>
diff --git a/chromium/components/strings/components_strings_ml.xtb b/chromium/components/strings/components_strings_ml.xtb
index 6f8c6f8c1bb..65300730871 100644
--- a/chromium/components/strings/components_strings_ml.xtb
+++ b/chromium/components/strings/components_strings_ml.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">വിശദാംശങàµà´™àµ¾ കാണàµà´•</translation>
<translation id="1030706264415084469">നിങàµà´™à´³àµà´Ÿàµ† ഉപകരണതàµà´¤à´¿àµ½ ശാശàµà´µà´¤à´®à´¾à´¯à´¿ വലിയ അളവിൽ ഡാറàµà´± സംഭരികàµà´•à´¾à´¨àµâ€ <ph name="URL" />ആഗàµà´°à´¹à´¿à´•àµà´•àµà´¨àµà´¨àµ</translation>
<translation id="1032854598605920125">ഘടികാരദിശയിൽ‌ തിരികàµà´•àµà´•</translation>
+<translation id="1033329911862281889">അദൃശàµà´¯ മോഡൠനിങàµà´™à´³àµ† ഓൺലൈനിൽ അദൃശàµà´¯à´®à´¾à´•àµà´•àµà´¨àµà´¨à´¿à´²àµà´²:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />à´…à´µ ഉപയോഗികàµà´•àµà´¨àµà´¨ സൈറàµà´±àµà´•àµ¾à´•àµà´•àµà´‚ സേവനങàµà´™àµ¾à´•àµà´•àµà´‚ സനàµà´¦àµ¼à´¶à´¨à´™àµà´™àµ¾ കാണാനാകàµà´‚<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />തൊഴിലàµà´Ÿà´®à´•àµ¾à´•àµà´•àµ‹ à´¸àµà´•àµ‚à´³àµà´•àµ¾à´•àµà´•àµ‹ à´¬àµà´°àµ—സിംഗൠആകàµà´±àµà´±à´¿à´µà´¿à´±àµà´±à´¿ à´Ÿàµà´°à´¾à´•àµà´•àµ ചെയàµà´¯à´¾à´¨à´¾à´•àµà´‚<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ഇനàµà´±àµ¼à´¨àµ†à´±àµà´±àµ സേവന ദാതാകàµà´•àµ¾à´•àµà´•àµ വെബൠടàµà´°à´¾à´«à´¿à´•àµ നിരീകàµà´·à´¿à´•àµà´•à´¾à´¨à´¾à´•àµà´‚<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">ഓഫാകàµà´•àµà´•</translation>
<translation id="1036982837258183574">പൂർണàµà´£ à´¸àµâ€Œà´•àµà´°àµ€à´¨à´¿àµ½ നിനàµà´¨àµ à´ªàµà´±à´¤àµà´¤àµà´•à´Ÿà´•àµà´•à´¾àµ» |<ph name="ACCELERATOR" />| അമർതàµà´¤àµà´•</translation>
<translation id="1038106730571050514">നിർദàµà´¦àµ‡à´¶à´™àµà´™àµ¾ കാണികàµà´•àµà´•</translation>
<translation id="1038842779957582377">à´…à´œàµà´žà´¾à´¤ നാമം</translation>
<translation id="1041998700806130099">ജോബൠഷീറàµà´±àµ സനàµà´¦àµ‡à´¶à´‚</translation>
<translation id="1048785276086539861">നിങàµà´™àµ¾ à´•àµà´±à´¿à´ªàµà´ªàµà´•àµ¾ à´Žà´¡à´¿à´±àµà´±àµ ചെയàµà´¯àµà´®àµà´ªàµ‹àµ¾, à´ˆ ഡോകàµà´¯àµà´®àµ†à´¨àµà´±àµ à´’à´±àµà´± പേജൠകാഴàµà´šà´¯à´¿à´²àµ‡à´•àµà´•àµ മടങàµà´™àµà´¨àµà´¨àµ</translation>
-<translation id="1049743911850919806">ആളàµâ€â€Œà´®à´¾à´±à´¾à´Ÿàµà´Ÿà´‚</translation>
<translation id="1050038467049342496">മറàµà´±àµ ആപàµà´ªàµà´•àµ¾ à´…à´Ÿà´¯àµâ€Œà´•àµà´•àµà´•</translation>
<translation id="1055184225775184556">&amp;ചേർതàµà´¤à´¤àµ പഴയപടിയാകàµà´•àµà´•</translation>
<translation id="1056898198331236512">à´®àµà´¨àµà´¨à´±à´¿à´¯à´¿à´ªàµà´ªàµ</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">നയ കാഷെ ശരി</translation>
<translation id="1130564665089811311">'പേജൠവിവർതàµà´¤à´¨à´‚ ചെയàµà´¯àµà´•' ബടàµà´Ÿàµº, Google Translate ഉപയോഗിചàµà´šàµ à´ˆ പേജൠവിവർതàµà´¤à´¨à´‚ ചെയàµà´¯à´¾àµ» 'Enter' അമർതàµà´¤àµà´•</translation>
<translation id="1131264053432022307">നിങàµà´™àµ¾ പകർതàµà´¤à´¿à´¯ à´šà´¿à´¤àµà´°à´‚</translation>
+<translation id="1142846828089312304">അദൃശàµà´¯ മോഡിൽ മൂനàµà´¨à´¾à´‚ à´•à´•àµà´·à´¿ à´•àµà´•àµà´•à´¿à´•àµ¾ à´¬àµà´²àµ‹à´•àµà´•àµ ചെയàµà´¯àµà´•</translation>
<translation id="1150979032973867961">à´ˆ സെർവറിനൠഅതൠ<ph name="DOMAIN" /> ആണെനàµà´¨àµ തെളിയികàµà´•à´¾à´¨à´¾à´¯à´¿à´²àµà´²; അതിനàµà´±àµ† à´¸àµà´°à´•àµà´· സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±à´¿à´¨àµ† നിങàµà´™à´³àµà´Ÿàµ† à´•à´®àµà´ªàµà´¯àµ‚à´Ÿàµà´Ÿà´±à´¿à´¨àµà´±àµ† à´“à´ªàµà´ªà´±àµ‡à´±àµà´±à´¿à´‚ഗൠസിസàµâ€Œà´±àµà´±à´¤àµà´¤à´¿à´¨àµ പരിചയമിലàµà´². തെറàµà´±à´¾à´¯ കോൺഫിഗറേഷൻ കാരണമോ ഒരൠഅകàµà´°à´®à´£à´•à´¾à´°à´¿ നിങàµà´™à´³àµà´Ÿàµ† കണകàµà´·à´¨àµ† തടസàµà´¸à´ªàµà´ªàµ†à´Ÿàµà´¤àµà´¤àµà´¨àµà´¨à´¤àµ കൊണàµà´Ÿàµ‹ ആയിരികàµà´•à´¾à´‚ ഇതൠസംഭവിചàµà´šà´¤àµ.</translation>
<translation id="1151972924205500581">പാസàµâ€à´µàµ‡à´¡àµ ആവശàµà´¯à´®à´¾à´£àµ</translation>
<translation id="1156303062776767266">ലോകàµà´•àµ½ à´…à´²àµà´²àµ†à´™àµà´•à´¿àµ½ പങàµà´•à´¿à´Ÿàµà´Ÿ ഫയൽ ആണൠനിങàµà´™àµ¾ കാണàµà´¨àµà´¨à´¤àµ</translation>
@@ -64,7 +70,6 @@
<translation id="1178581264944972037">താൽകàµà´•à´¾à´²à´¿à´•à´®à´¾à´¯à´¿ നിർതàµà´¤àµà´•</translation>
<translation id="1181037720776840403">നീകàµà´•à´‚ചെയàµà´¯àµ‚</translation>
<translation id="1186201132766001848">പാസàµâ€Œà´µàµ‡à´¡àµ പരിശോധികàµà´•àµ‚</translation>
-<translation id="1195210374336998651">ആപàµà´ªàµ à´•àµà´°à´®àµ€à´•à´°à´£à´¤àµà´¤à´¿à´²àµ‡à´•àµà´•àµ പോകàµà´•</translation>
<translation id="1195558154361252544">നിങàµà´™àµ¾ à´…à´¨àµà´µà´¦à´¿à´•àµà´•àµà´¨àµà´¨ സൈറàµà´±àµà´•àµ¾à´•àµà´•àµ ഒഴികെ മറàµà´±àµ à´Žà´²àµà´²à´¾ സൈറàµà´±àµà´•àµ¾à´•àµà´•àµà´‚ അറിയിപàµà´ªàµà´•àµ¾ à´¸àµà´µà´¯à´®àµ‡à´µ à´¬àµà´²àµ‹à´•àµà´•àµ ചെയàµâ€Œà´¤à´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨àµ</translation>
<translation id="1197088940767939838">ഓറഞàµà´šàµ</translation>
<translation id="1201402288615127009">à´…à´Ÿàµà´¤àµà´¤à´¤àµ</translation>
@@ -111,7 +116,7 @@
<translation id="1307966114820526988">അവസാനിപàµà´ªà´¿à´šàµà´š ഫീചàµà´šà´±àµà´•àµ¾</translation>
<translation id="1308113895091915999">ഓഫർ ലഭàµà´¯à´®à´¾à´£àµ</translation>
<translation id="1312803275555673949">ഇതിനെ പിനàµà´¤àµà´£à´¯àµà´•àµà´•àµà´¨àµà´¨ തെളിവàµà´•àµ¾ à´Žà´¨àµà´¤àµŠà´•àµà´•àµ†à´¯à´¾à´£àµ?</translation>
-<translation id="131405271941274527">ഒരൠNFC ഉപകരണതàµà´¤à´¿àµ½ നിങàµà´™à´³àµà´Ÿàµ† ഫോൺ ടാപàµà´ªàµ ചെയàµà´¯àµà´®àµà´ªàµ‹àµ¾ വിവരങàµà´™àµ¾ അയയàµà´•àµà´•à´¾à´¨àµà´‚ à´¸àµà´µàµ€à´•à´°à´¿à´•àµà´•à´¾à´¨àµà´‚ <ph name="URL" /> താൽപàµà´ªà´°àµà´¯à´ªàµà´ªàµ†à´Ÿàµà´¨àµà´¨àµ</translation>
+<translation id="1314311879718644478">à´…à´¨àµà´¬à´¨àµà´§à´¯à´¾à´¥à´¾àµ¼à´¤àµà´¥àµà´¯ ഉളàµà´³à´Ÿà´•àµà´•à´‚ കാണàµà´•</translation>
<translation id="1314509827145471431">വലതàµà´µà´¶à´¤àµà´¤àµ ബൈൻഡൠചെയàµà´¯àµà´•</translation>
<translation id="1318023360584041678">ടാബൠഗàµà´°àµ‚à´ªàµà´ªà´¿àµ½ സംരകàµà´·à´¿à´šàµà´šàµ</translation>
<translation id="1319245136674974084">à´ˆ ആപàµà´ªà´¿àµ½ വീണàµà´Ÿàµà´‚ ആവശàµà´¯à´ªàµà´ªàµ†à´Ÿà´°àµà´¤àµ</translation>
@@ -161,6 +166,7 @@
<translation id="142858679511221695">à´•àµà´²àµ—ഡൠഉപയോകàµà´¤à´¾à´µàµ</translation>
<translation id="1428729058023778569">à´ˆ സൈറàµà´±àµ HTTPS പിനàµà´¤àµà´£à´¯àµâ€Œà´•àµà´•à´¾à´¤àµà´¤à´¤à´¿à´¨à´¾à´²à´¾à´£àµ നിങàµà´™àµ¾ à´ˆ à´®àµà´¨àµà´¨à´±à´¿à´¯à´¿à´ªàµà´ªàµ കാണàµà´¨àµà´¨à´¤àµ. <ph name="BEGIN_LEARN_MORE_LINK" />കൂടàµà´¤à´²à´±à´¿à´¯àµà´•<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">à´ªàµà´°à´¿à´¨àµà´±àµ ചെയàµà´¯àµà´•</translation>
+<translation id="1432187715652018471">സേവനം കൈകാരàµà´¯à´‚ ചെയàµà´¯àµà´¨àµà´¨ സംവിധാനം ഇൻസàµà´±àµà´±à´¾àµ¾ ചെയàµà´¯à´¾àµ» à´ˆ പേജൠതാൽപàµà´ªà´°àµà´¯à´ªàµà´ªàµ†à´Ÿàµà´¨àµà´¨àµ.</translation>
<translation id="1432581352905426595">തിരയൽ യനàµà´¤àµà´°à´‚ മാനേജൠചെയàµà´¯àµà´•</translation>
<translation id="1436185428532214179">നിങàµà´™à´³àµà´Ÿàµ† ഉപകരണതàµà´¤à´¿à´²àµ† ഫയലàµà´•à´³àµà´‚ ഫോൾഡറàµà´•à´³àµà´‚ à´Žà´¡à´¿à´±àµà´±àµ ചെയàµà´¯à´¾àµ» ആവശàµà´¯à´ªàµà´ªàµ†à´Ÿà´¾à´‚</translation>
<translation id="1442386063175183758">റൈറàµà´±àµ ഗേറàµà´±àµ മടകàµà´•àµ</translation>
@@ -181,6 +187,12 @@
<translation id="1483493594462132177">അയയàµâ€Œà´•àµà´•àµà´•</translation>
<translation id="1484290072879560759">à´·à´¿à´ªàµà´ªà´¿à´‚ഗൠവിലാസം തിരഞàµà´žàµ†à´Ÿàµà´•àµà´•àµà´•</translation>
<translation id="1492194039220927094">നയങàµà´™àµ¾ à´ªàµà´·àµ ചെയàµà´¯àµ½:</translation>
+<translation id="149293076951187737">Chrome-à´²àµà´³àµà´³ à´®àµà´´àµà´µàµ» അദൃശàµà´¯ ടാബàµà´•à´³àµà´‚ നിങàµà´™àµ¾ à´…à´Ÿà´¯àµà´•àµà´•àµà´®àµà´ªàµ‹àµ¾ à´† ടാബàµà´•à´³à´¿à´²àµ† നിങàµà´™à´³àµà´Ÿàµ† ആകàµà´±àµà´±à´¿à´µà´¿à´±àµà´±à´¿ à´ˆ ഉപകരണതàµà´¤à´¿àµ½ നിനàµà´¨àµ മായàµà´•àµà´•àµà´¨àµà´¨àµ:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />à´¬àµà´°àµ—സിംഗൠആകàµà´±àµà´±à´¿à´µà´¿à´±àµà´±à´¿<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />തിരയൽ à´šà´°à´¿à´¤àµà´°à´‚<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ഫോമàµà´•à´³à´¿àµ½ നൽകàµà´¨àµà´¨ വിവരങàµà´™àµ¾<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">ടാബിലേകàµà´•àµ മടങàµà´™àµà´•</translation>
<translation id="1501859676467574491">നിങàµà´™à´³àµà´Ÿàµ† Google à´…à´•àµà´•àµ—à´£àµà´Ÿà´¿àµ½ നിനàµà´¨àµ കാർഡàµà´•àµ¾ കാണികàµà´•àµà´•</translation>
<translation id="1507202001669085618">&lt;p&gt;ഓൺലൈൻ ആകàµà´¨àµà´¨à´¤à´¿à´¨àµ സൈൻ ഇൻ ചെയàµà´¯àµ‡à´£àµà´Ÿà´¿ വരàµà´¨àµà´¨ ഒരൠവൈഫൈ പോർടàµà´Ÿà´²à´¾à´£àµ നിങàµà´™àµ¾ ഉപയോഗികàµà´•àµà´¨àµà´¨à´¤àµ†à´™àµà´•à´¿àµ½, നിങàµà´™àµ¾ à´ˆ പിശകൠകാണàµà´‚.&lt;/p&gt;
@@ -208,6 +220,8 @@
<translation id="1559572115229829303">&lt;p&gt;നിങàµà´™à´³àµà´Ÿàµ† ഉപകരണതàµà´¤à´¿à´¨àµà´±àµ† തീയതിയàµà´‚ സമയവàµà´‚ (<ph name="DATE_AND_TIME" />) തെറàµà´±à´¾à´¯à´¤à´¿à´¨à´¾àµ½ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> à´Žà´¨àµà´¨à´¤à´¿à´²àµ‡à´•àµà´•àµ ഒരൠസàµà´µà´•à´¾à´°àµà´¯ കണകàµà´·àµ» à´¸àµà´¥à´¾à´ªà´¿à´•àµà´•à´¾à´¨à´¾à´•à´¿à´²àµà´².&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;à´•àµà´°à´®àµ€à´•à´°à´£&lt;/strong&gt; ആപàµà´ªà´¿à´¨àµà´±àµ† &lt;strong&gt;പൊതàµà´µà´¾à´¯à´µ&lt;/strong&gt; വിഭാഗതàµà´¤à´¿àµ½ നിനàµà´¨àµ തീയതിയàµà´‚ സമയവàµà´‚ à´•àµà´°à´®àµ€à´•à´°à´¿à´•àµà´•àµà´•.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">നിങàµà´™à´³àµà´Ÿàµ† à´…à´¡àµâ€Œà´®à´¿àµ» നിങàµà´™à´³àµà´Ÿàµ† ഉപകരണം <ph name="DATE" />, <ph name="TIME" />-നൠറീസàµà´±àµà´±à´¾àµ¼à´Ÿàµà´Ÿàµ ചെയàµà´¯àµà´‚</translation>
+<translation id="156703335097561114">വിലാസങàµà´™àµ¾, ഇനàµà´±àµ¼à´«àµ‡à´¸àµ കോൺഫിഗറേഷൻ, കണകàµà´·àµ» നിലവാരം à´Žà´¨àµà´¨à´¿à´µ പോലàµà´³àµà´³ നെറàµà´±àµâ€Œà´µàµ¼à´•àµà´•à´¿à´‚ഗൠവിവരങàµà´™àµ¾</translation>
<translation id="1567040042588613346">à´ˆ നയം ഉദàµà´¦àµ‡à´¶à´¿à´šàµà´šà´¤àµ പോലെ à´ªàµà´°à´µàµ¼à´¤àµà´¤à´¿à´•àµà´•àµà´¨àµà´¨àµà´£àµà´Ÿàµ, à´Žà´¨àµà´¨à´¾àµ½ മറàµà´±àµŠà´°àµ ഉറവിടതàµà´¤à´¿àµ½ അതേ മൂലàµà´¯à´‚ സജàµà´œàµ€à´•à´°à´¿à´šàµà´šà´¤à´¿à´¨àµ† à´¤àµà´Ÿàµ¼à´¨àµà´¨àµ à´ˆ നയതàµà´¤à´¿à´¨àµ പകരം മറàµà´±àµŠà´¨àµà´¨àµ സജീവമായി.</translation>
<translation id="1569487616857761740">കാലഹരണപàµà´ªàµ†à´Ÿàµà´¨àµà´¨ തീയതി നൽകàµà´•</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@
<translation id="1583429793053364125">à´ˆ വെബàµâ€Œà´ªàµ‡à´œàµ à´ªàµà´°à´¦àµ¼à´¶à´¿à´ªàµà´ªà´¿à´•àµà´•àµà´®àµà´ªàµ‹àµ¾ à´Žà´¨àµà´¤àµ‹ à´•àµà´´à´ªàµà´ªà´‚ സംഭവിചàµà´šàµ.</translation>
<translation id="1586541204584340881">à´à´¤àµŠà´•àµà´•àµ† വിപàµà´²àµ€à´•à´°à´£à´™àµà´™àµ¾ നിങàµà´™àµ¾ ഇൻസàµâ€Œà´±àµà´±à´¾àµ¾ ചെയàµà´¤à´¿à´Ÿàµà´Ÿàµà´£àµà´Ÿàµ à´Žà´¨àµà´¨à´¤àµ</translation>
<translation id="1588438908519853928">സാധാരണം</translation>
+<translation id="1589050138437146318">ARCore ഇൻസàµà´±àµà´±à´¾àµ¾ ചെയàµà´¯à´£àµ‹?</translation>
<translation id="1592005682883173041">à´ªàµà´°à´¾à´¦àµ‡à´¶à´¿à´• ഡാറàµà´± ആകàµâ€Œà´¸à´¸àµ</translation>
<translation id="1594030484168838125">തിരഞàµà´žàµ†à´Ÿàµà´•àµà´•àµà´•</translation>
<translation id="160851722280695521">Chrome-ൽ ദിനോസർ റൺ ഗെയിം കളികàµà´•àµà´•</translation>
@@ -282,6 +297,7 @@
തലകàµà´•àµ†à´Ÿàµà´Ÿàµ സജàµà´œàµ€à´•à´°à´¿à´šàµà´šà´¿à´Ÿàµà´Ÿàµà´£àµà´Ÿàµ. à´Žà´¨àµà´¨à´¾àµ½
ശരിയായ രീതിയിൽ തലകàµà´•àµ†à´Ÿàµà´Ÿàµ സജàµà´œàµ€à´•à´°à´¿à´•àµà´•à´¾à´¤àµà´¤à´¤à´¿à´¨à´¾àµ½,
<ph name="SITE" /> à´Žà´¨àµà´¨à´¤à´¿à´¨àµà´³àµà´³ നിങàµà´™à´³àµà´Ÿàµ† à´…à´­àµà´¯àµ¼à´¤àµà´¥à´¨ പൂർതàµà´¤àµ€à´•à´°à´¿à´•àµà´•à´¾àµ» à´¬àµà´°àµ—സറിനൠകഴിയàµà´¨àµà´¨à´¿à´²àµà´². ഒരൠസൈറàµà´±à´¿à´¨àµà´±àµ† à´¸àµà´°à´•àµà´·à´¯àµà´‚ മറàµà´±àµ à´ªàµà´°àµ‹à´ªàµà´ªàµ¼à´Ÿàµà´Ÿà´¿à´•à´³àµà´‚ കോൺഫിഗർ ചെയàµà´¯à´¾àµ» സൈറàµà´±àµ à´“à´ªàµà´ªà´±àµ‡à´±àµà´±àµ¼à´®à´¾àµ¼à´•àµà´•àµ ഉറവിട നയങàµà´™àµ¾ ഉപയോഗികàµà´•à´¾à´¨à´¾à´µàµà´‚.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Chromium-ലെ അദൃശàµà´¯ മോഡിനെ à´•àµà´±à´¿à´šàµà´šàµ കൂടàµà´¤à´²à´±à´¿à´¯àµà´•<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">നിങàµà´™àµ¾ നിലവിൽ à´¤àµà´±à´¨àµà´¨à´¿à´Ÿàµà´Ÿàµà´³àµà´³ ടാബàµà´•àµ¾ ഇവിടെ ദൃശàµà´¯à´®à´¾à´•àµà´‚</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -409,6 +425,7 @@
<translation id="22081806969704220">à´Ÿàµà´°àµ‡ 3</translation>
<translation id="2212735316055980242">നയം à´•à´£àµà´Ÿàµ†à´¤àµà´¤à´¿à´¯à´¿à´²àµà´²</translation>
<translation id="2213606439339815911">എൻടàµà´°à´¿à´•àµ¾ ലഭàµà´¯à´®à´¾à´•àµà´•àµà´¨àµà´¨àµ...</translation>
+<translation id="2213612003795704869">പേജൠപàµà´°à´¿à´¨àµà´±àµ ചെയàµà´¤à´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨àµ</translation>
<translation id="2215727959747642672">ഫയൽ à´Žà´¡à´¿à´±àµà´±àµ ചെയàµà´¯àµ½</translation>
<translation id="2218879909401188352">നിലവിൽ {<ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> à´Žà´¨àµà´¨à´¤à´¿à´²àµà´³àµà´³ à´…à´•àµà´°à´®à´¿à´•àµ¾à´•àµà´•àµ നിങàµà´™à´³àµà´Ÿàµ† ഉപകരണം കേടàµà´µà´°àµà´¤àµà´¤àµà´¨àµà´¨ ആപàµà´ªàµà´•àµ¾ ഇൻസàµâ€Œà´±àµà´±à´¾àµ¾ ചെയàµà´¯à´¾à´¨àµ‹ മൊബൈൽ ബിലàµà´²à´¿à´²àµ‡à´•àµà´•àµ നിങàµà´™à´³à´±à´¿à´¯à´¾à´¤àµ† നിരകàµà´•àµà´•àµ¾ ചേർകàµà´•à´¾à´¨àµ‹ നിങàµà´™à´³àµà´Ÿàµ† à´µàµà´¯à´•àµà´¤à´¿à´ªà´°à´®à´¾à´¯ വിവരങàµà´™àµ¾ മോഷàµâ€Œà´Ÿà´¿à´•àµà´•à´¾à´¨àµ‹ à´•à´´à´¿à´¯àµà´‚. <ph name="BEGIN_LEARN_MORE_LINK" />കൂടàµà´¤à´²à´±à´¿à´¯àµà´•<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">ഇനàµà´±àµ¼à´¨àµ†à´±àµà´±àµ ഇലàµà´²</translation>
@@ -418,6 +435,7 @@
<translation id="2248949050832152960">WebAuthn ഉപയോഗികàµà´•àµà´•</translation>
<translation id="2250931979407627383">ഇടതàµà´µà´¶à´¤àµà´¤àµ അരികൠകൂടàµà´Ÿà´¿à´šàµà´šàµ‡àµ¼à´•àµà´•àµ½</translation>
<translation id="225207911366869382">à´ˆ നയതàµà´¤à´¿àµ½à´¨à´¿à´¨àµà´¨àµ à´ˆ മൂലàµà´¯à´‚ ഇലàµà´²à´¾à´¤à´¾à´•àµà´•à´¿.</translation>
+<translation id="2256115617011615191">ഇപàµà´ªàµ‹àµ¾ വീണàµà´Ÿàµà´‚ ആരംഭികàµà´•àµà´•</translation>
<translation id="2258928405015593961">ഭാവിയിലെ കാലഹരണപàµà´ªàµ†à´Ÿàµà´¨àµà´¨ തീയതി നൽകിയ ശേഷം വീണàµà´Ÿàµà´‚ à´¶àµà´°à´®à´¿à´•àµà´•àµà´•</translation>
<translation id="225943865679747347">പിശകൠകോഡàµ: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">HTTP പിശകàµ</translation>
@@ -445,6 +463,7 @@
<translation id="2337852623177822836">à´•àµà´°à´®àµ€à´•à´°à´£à´‚ നിയനàµà´¤àµà´°à´¿à´•àµà´•àµà´¨àµà´¨à´¤àµ നിങàµà´™à´³àµà´Ÿàµ† à´…à´¡àµâ€Œà´®à´¿à´¨à´¿à´¸àµâ€Œà´Ÿàµà´°àµ‡à´±àµà´±à´±à´¾à´£àµ</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> ജോടിയാകàµà´•à´¾àµ» താൽപàµà´ªà´°àµà´¯à´ªàµà´ªàµ†à´Ÿàµà´¨àµà´¨àµ</translation>
<translation id="2346319942568447007">നിങàµà´™àµ¾ പകർതàµà´¤à´¿à´¯ à´šà´¿à´¤àµà´°à´‚</translation>
+<translation id="2350796302381711542"><ph name="REPLACED_HANDLER_TITLE" /> à´Žà´¨àµà´¨à´¤à´¿à´¨àµà´ªà´•à´°à´‚ à´Žà´²àµà´²à´¾ <ph name="PROTOCOL" /> ലിങàµà´•àµà´•à´³àµà´‚ à´¤àµà´±à´•àµà´•à´¾àµ» <ph name="HANDLER_HOSTNAME" /> à´Žà´¨àµà´¨à´¤à´¿à´¨àµ† à´…à´¨àµà´µà´¦à´¿à´•àµà´•à´£àµ‹?</translation>
<translation id="2354001756790975382">മറàµà´±àµ à´¬àµà´•àµâ€Œà´®à´¾à´°àµâ€à´•àµà´•àµà´•à´³àµâ€</translation>
<translation id="2354430244986887761">Google à´¸àµà´°à´•àµà´·à´¿à´¤ à´¬àµà´°àµ—സിംഗൠഈയിടെ <ph name="SITE" /> à´Žà´¨àµà´¨à´¤à´¿àµ½ <ph name="BEGIN_LINK" />ദോഷകരമായ ആപàµà´ªàµà´•àµ¾ à´•à´£àµà´Ÿàµ†à´¤àµà´¤à´¿<ph name="END_LINK" />.</translation>
<translation id="2355395290879513365">നിങàµà´™àµ¾ à´ˆ സൈറàµà´±à´¿àµ½ തിരയàµà´¨àµà´¨ à´šà´¿à´¤àµà´°à´™àµà´™àµ¾ കാണാനàµà´‚ അവയിൽ മാറàµà´±à´‚ വരàµà´¤àµà´¤à´¿ നിങàµà´™à´³àµ† കബളിപàµà´ªà´¿à´•àµà´•à´¾à´¨àµà´‚ à´…à´•àµà´°à´®à´•à´¾à´°à´¿à´•àµ¾à´•àµà´•àµ à´•à´´à´¿à´žàµà´žàµ‡à´•àµà´•à´¾à´‚.</translation>
@@ -470,6 +489,7 @@
<translation id="2413528052993050574">à´ˆ സെർവറിനൠഅതൠ<ph name="DOMAIN" /> ആണെനàµà´¨àµ തെളിയികàµà´•à´¾à´¨à´¾à´¯à´¿à´²àµà´²; സെർവറിനàµà´±àµ† à´¸àµà´°à´•àµà´·à´¾ സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ റദàµà´¦à´¾à´•àµà´•à´¿à´¯à´¿à´°à´¿à´•àµà´•à´¾à´‚. തെറàµà´±à´¾à´¯ കോൺഫിഗറേഷൻ കാരണമോ ഒരൠഅകàµà´°à´®à´£à´•à´¾à´°à´¿ നിങàµà´™à´³àµà´Ÿàµ† കണകàµà´·à´¨àµ† തടസàµà´¸à´ªàµà´ªàµ†à´Ÿàµà´¤àµà´¤àµà´¨àµà´¨à´¤àµ കൊണàµà´Ÿàµ‹ ആയിരികàµà´•à´¾à´‚ ഇതൠസംഭവിചàµà´šà´¤àµ.</translation>
<translation id="2414886740292270097">ഇരàµà´£àµà´Ÿà´¤àµ</translation>
<translation id="2430968933669123598">Google à´…à´•àµà´•àµ—à´£àµà´Ÿàµ മാനേജൠചെയàµà´¯àµà´•, നിങàµà´™à´³àµà´Ÿàµ† Google à´…à´•àµà´•àµ—à´£àµà´Ÿà´¿à´²àµ† വിവരങàµà´™à´³àµà´‚ à´¸àµà´µà´•à´¾à´°àµà´¯à´¤à´¯àµà´‚ à´¸àµà´°à´•àµà´·à´¯àµà´‚ മാനേജൠചെയàµà´¯à´¾àµ» Enter അമർതàµà´¤àµà´•</translation>
+<translation id="2436186046335138073">à´Žà´²àµà´²à´¾ <ph name="PROTOCOL" /> ലിങàµà´•àµà´•à´³àµà´‚ à´¤àµà´±à´•àµà´•à´¾àµ» <ph name="HANDLER_HOSTNAME" /> à´Žà´¨àµà´¨à´¤à´¿à´¨àµ† à´…à´¨àµà´µà´¦à´¿à´•àµà´•à´£àµ‹?</translation>
<translation id="2438874542388153331">വലതàµà´µà´¶à´¤àµà´¤àµ നാലൠതവണ പഞàµà´šàµ ചെയàµà´¯àµà´•</translation>
<translation id="2450021089947420533">ജേർണികൾ</translation>
<translation id="2463739503403862330">പൂരിപàµà´ªà´¿à´•àµà´•àµà´•</translation>
@@ -477,6 +497,7 @@
<translation id="2465655957518002998">ഡെലിവറി രീതി തിരഞàµà´žàµ†à´Ÿàµà´•àµà´•àµà´•</translation>
<translation id="2465688316154986572">à´¸àµâ€Œà´±àµà´±àµ‡à´ªàµà´ªà´¿àµ¾ ചെയàµà´¯àµà´•</translation>
<translation id="2465914000209955735">Chrome-ൽ നിങàµà´™àµ¾ ഡൗൺലോഡൠചെയàµà´¤à´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨ ഫയലàµà´•àµ¾ മാനേജൠചെയàµà´¯àµà´•</translation>
+<translation id="2466004615675155314">വെബിൽ നിനàµà´¨àµà´³àµà´³ വിവരങàµà´™àµ¾ കാണികàµà´•àµà´•</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />നെറàµà´±àµâ€Œà´µàµ¼à´•àµà´•àµ ഡയഗണോസàµâ€Œà´±àµà´±à´¿à´•àµâ€Œà´¸àµ റൺ ചെയàµà´¯àµà´¨àµà´¨àµ<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">1-N à´•àµà´°à´®à´¤àµà´¤à´¿àµ½</translation>
<translation id="2470767536994572628">നിങàµà´™àµ¾ à´•àµà´±à´¿à´ªàµà´ªàµà´•àµ¾ à´Žà´¡à´¿à´±àµà´±àµ ചെയàµà´¯àµà´®àµà´ªàµ‹àµ¾, à´ˆ ഡോകàµà´¯àµà´®àµ†à´¨àµà´±àµ à´’à´±àµà´± പേജൠകാഴàµà´šà´¯à´¿à´²àµ‡à´•àµà´•àµà´‚ അതിനàµà´±àµ† ഒറിജിനൽ റൊടàµà´Ÿàµ‡à´·à´¨à´¿à´²àµ‡à´•àµà´•àµà´‚ മടങàµà´™àµà´¨àµà´¨àµ</translation>
@@ -497,6 +518,7 @@
<translation id="2523886232349826891">à´ˆ ഉപകരണതàµà´¤à´¿àµ½ മാതàµà´°à´‚ സംരകàµà´·à´¿à´•àµà´•à´ªàµà´ªàµ†à´Ÿàµà´‚</translation>
<translation id="2524461107774643265">കൂടàµà´¤àµ½ വിവരങàµà´™àµ¾ ചേർകàµà´•àµà´•</translation>
<translation id="2529899080962247600">à´ˆ ഫീൽഡിൽ <ph name="MAX_ITEMS_LIMIT" />-ൽ കൂടàµà´¤àµ½ എൻ‌ടàµà´°à´¿à´•àµ¾ ഉണàµà´Ÿà´¾à´•à´°àµà´¤àµ. à´¤àµà´Ÿàµ¼à´¨àµà´¨àµà´³àµà´³ à´Žà´²àµà´²à´¾ എൻ‌ടàµà´°à´¿à´•à´³àµà´‚ നിരസികàµà´•àµà´‚.</translation>
+<translation id="2535585790302968248">à´¸àµà´µà´•à´¾à´°àµà´¯à´®à´¾à´¯à´¿ à´¬àµà´°àµ—സൠചെയàµà´¯à´¾àµ» à´ªàµà´¤à´¿à´¯ അദൃശàµà´¯ ടാബൠതàµà´±à´•àµà´•àµà´•</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{à´Žà´¨àµà´¨à´¤àµà´‚ മറàµà´±àµŠà´°àµ†à´£àµà´£à´µàµà´‚}other{à´Žà´¨àµà´¨à´¤àµà´‚ മറàµà´±àµ # à´Žà´£àµà´£à´µàµà´‚}}</translation>
<translation id="2536110899380797252">വിലാസം ചേർകàµà´•àµà´•</translation>
<translation id="2539524384386349900">à´•à´£àµà´Ÿàµ†à´¤àµà´¤àµà´•</translation>
@@ -522,7 +544,14 @@
<translation id="2597378329261239068">à´ˆ à´ªàµà´°à´®à´¾à´£à´‚ പാസàµâ€Œà´µàµ‡à´¡àµ പരിരകàµà´·à´¿à´¤à´®à´¾à´£àµ. പാസàµâ€Œà´µàµ‡à´¡àµ നലàµâ€â€Œà´•àµà´•.</translation>
<translation id="2609632851001447353">വേരിയേഷനàµà´•àµ¾</translation>
<translation id="2610561535971892504">പകർതàµà´¤à´¾àµ» à´•àµà´²à´¿à´•àµà´•àµ ചെയàµà´¯àµà´•</translation>
+<translation id="2617988307566202237">ഇനിപàµà´ªà´±à´¯àµà´¨àµà´¨ വിവരങàµà´™àµ¾ Chrome <ph name="BEGIN_EMPHASIS" />സംരകàµà´·à´¿à´•àµà´•à´¿à´²àµà´²<ph name="END_EMPHASIS" />:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />നിങàµà´™à´³àµà´Ÿàµ† à´¬àµà´°àµ—സിംഗൠചരിതàµà´°à´‚
+ <ph name="LIST_ITEM" />à´•àµà´•àµà´•à´¿à´•à´³àµà´‚ സൈറàµà´±àµ ഡാറàµà´±à´¯àµà´‚
+ <ph name="LIST_ITEM" />ഫോമàµà´•à´³à´¿àµ½ നൽകàµà´¨àµà´¨ വിവരങàµà´™àµ¾
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (എൻവലപàµà´ªàµ)</translation>
+<translation id="2623663032199728144">നിങàµà´™à´³àµà´Ÿàµ† à´¸àµà´•àµà´°àµ€à´¨àµà´•à´³àµà´Ÿàµ† വിവരങàµà´™àµ¾ ഉപയോഗികàµà´•à´¾àµ» ആവശàµà´¯à´ªàµà´ªàµ†à´Ÿà´¾à´‚</translation>
<translation id="2625385379895617796">നിങàµà´™à´³àµà´Ÿàµ† à´•àµà´²àµ‹à´•àµà´•àµ വളരെ à´®àµà´®àµà´ªà´¿à´²à´¾à´£àµ</translation>
<translation id="262745152991669301">USB ഉപകരണങàµà´™àµ¾ കണകàµà´±àµà´±àµ ചെയàµà´¯à´¾àµ» ആവശàµà´¯à´ªàµà´ªàµ†à´Ÿà´¾à´‚</translation>
<translation id="2629325967560697240">Chrome-à´¨àµà´±àµ† à´à´±àµà´±à´µàµà´‚ ഉയർനàµà´¨ à´¸àµà´°à´•àµà´· നേടാൻ, <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />മെചàµà´šà´ªàµà´ªàµ†à´Ÿàµà´¤àµà´¤à´¿à´¯ പരിരകàµà´· ഓണാകàµà´•àµà´•<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -556,6 +585,7 @@
<translation id="2709516037105925701">à´¸àµà´µà´¯à´®àµ‡à´µ പൂരിപàµà´ªà´¿à´•àµà´•àµ½</translation>
<translation id="2713444072780614174">വെളàµà´³</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />, Chrome à´•àµà´°à´®àµ€à´•à´°à´£à´¤àµà´¤à´¿àµ½ നിങàµà´™à´³àµà´Ÿàµ† പേയàµâ€Œà´®àµ†à´¨àµà´±àµà´•à´³àµà´‚ à´•àµà´°àµ†à´¡à´¿à´±àµà´±àµ കാർഡൠവിവരങàµà´™à´³àµà´‚ മാനേജൠചെയàµà´¯à´¾àµ» 'Tab' അമർതàµà´¤àµà´•, à´¤àµà´Ÿàµ¼à´¨àµà´¨àµ 'Enter' അമർതàµà´¤àµà´•</translation>
+<translation id="271663710482723385">പൂർണàµà´£ à´¸àµà´•àµà´°àµ€à´¨à´¿àµ½ നിനàµà´¨àµ à´ªàµà´±à´¤àµà´¤àµà´•à´Ÿà´•àµà´•à´¾àµ» |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| അമർതàµà´¤àµà´•</translation>
<translation id="2721148159707890343">à´…à´­àµà´¯àµ¼à´¤àµà´¥à´¨ വിജയിചàµà´šàµ</translation>
<translation id="2723669454293168317">Chrome à´•àµà´°à´®àµ€à´•à´°à´£à´¤àµà´¤à´¿àµ½ à´¸àµà´°à´•àµà´·à´¾ പരിശോധന റൺ ചെയàµà´¯àµà´•</translation>
<translation id="2726001110728089263">വശതàµà´¤àµà´³àµà´³ à´Ÿàµà´°àµ‡</translation>
@@ -586,6 +616,7 @@
<translation id="2850739647070081192">à´•àµà´·à´£à´‚ (എൻവലപàµà´ªàµ)</translation>
<translation id="2856444702002559011"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> à´Žà´¨àµà´¨à´¤à´¿àµ½ നിനàµà´¨àµ നിങàµà´™à´³àµà´Ÿàµ† വിവരം മോഷàµâ€Œà´Ÿà´¿à´•àµà´•à´¾àµ» à´…à´•àµà´°à´®à´¿à´•àµ¾ à´¶àµà´°à´®à´¿à´•àµà´•àµà´¨àµà´¨àµà´£àµà´Ÿà´¾à´µà´¾à´‚ (ഉദാഹരണതàµà´¤à´¿à´¨àµ, പാസàµâ€Œà´µàµ‡à´¡àµà´•àµ¾, സനàµà´¦àµ‡à´¶à´™àµà´™àµ¾, à´…à´²àµà´²àµ†à´™àµà´•à´¿àµ½ à´•àµà´°àµ†à´¡à´¿à´±àµà´±àµ കാർഡàµà´•àµ¾). <ph name="BEGIN_LEARN_MORE_LINK" />കൂടàµà´¤à´²à´±à´¿à´¯àµà´•<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">à´ˆ സൈറàµà´±àµ, അനാവശàµà´¯à´®àµ‹ തെറàµà´±à´¿à´¦àµà´§à´°à´¿à´ªàµà´ªà´¿à´•àµà´•àµà´¨àµà´¨à´¤àµ‹ ആയ പരസàµà´¯à´™àµà´™àµ¾ കാണികàµà´•àµà´¨àµà´¨àµ.</translation>
+<translation id="286512204874376891">വഞàµà´šà´¿à´•àµà´•à´ªàµà´ªàµ†à´Ÿà´¾à´¨àµà´³àµà´³ സാധàµà´¯à´¤à´•à´³à´¿àµ½ നിനàµà´¨àµ നിങàµà´™à´³àµ† പരിരകàµà´·à´¿à´•àµà´•àµà´¨àµà´¨à´¤à´¿à´¨àµ വെർചàµà´µàµ½ കാർഡൠനിങàµà´™à´³àµà´Ÿàµ† യഥാർതàµà´¥ കാർഡൠവിവരങàµà´™àµ¾ മറയàµà´•àµà´•àµà´¨àµà´¨àµ. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">സൗഹാർദàµà´¦à´ªà´°à´‚</translation>
<translation id="2876489322757410363">ബാഹàµà´¯ ആപàµà´ªàµ വഴി പണമടയàµâ€Œà´•àµà´•à´¾àµ» അദൃശàµà´¯ മോഡിൽ നിനàµà´¨àµ à´ªàµà´±à´¤àµà´¤àµà´•à´Ÿà´•àµà´•àµà´¨àµà´¨àµ. à´¤àµà´Ÿà´°à´£àµ‹?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />, Chrome à´•àµà´°à´®àµ€à´•à´°à´£à´¤àµà´¤à´¿àµ½ നിങàµà´™à´³àµà´Ÿàµ† à´¸àµà´°à´•àµà´·à´¿à´¤ à´¬àµà´°àµ—സിംഗàµà´‚ മറàµà´±àµà´‚ മാനേജൠചെയàµà´¯à´¾àµ» Tab അമർതàµà´¤àµà´•, à´¤àµà´Ÿàµ¼à´¨àµà´¨àµ Enter അമർതàµà´¤àµà´•</translation>
@@ -610,6 +641,7 @@
<translation id="2930577230479659665">ഓരോ പകർപàµà´ªà´¿à´¨àµ ശേഷവàµà´‚ à´Ÿàµà´°à´¿à´‚ ചെയàµà´¯àµà´•</translation>
<translation id="2932085390869194046">പാസàµâ€Œà´µàµ‡à´¡àµ നിർദàµà´¦àµ‡à´¶à´¿à´•àµà´•àµà´•...</translation>
<translation id="2934466151127459956">ഗവൺമെൻàµà´±àµ-ലെറàµà´±àµ¼</translation>
+<translation id="2938225289965773019"><ph name="PROTOCOL" /> ലിങàµà´•àµà´•àµ¾ à´¤àµà´±à´•àµà´•àµà´•</translation>
<translation id="2941952326391522266">à´ˆ സെർവറിനൠഅതൠ<ph name="DOMAIN" /> ആണെനàµà´¨àµ തെളിയികàµà´•à´¾à´¨à´¾à´¯à´¿à´²àµà´²; <ph name="DOMAIN2" /> à´Žà´¨àµà´¨à´¤à´¿àµ½ നിനàµà´¨àµà´³àµà´³à´¤à´¾à´£àµ അതിനàµà´±àµ† à´¸àµà´°à´•àµà´·à´¾ സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ. തെറàµà´±à´¾à´¯ കോൺഫിഗറേഷൻ കാരണമോ ഒരൠഅകàµà´°à´®à´£à´•à´¾à´°à´¿ നിങàµà´™à´³àµà´Ÿàµ† കണകàµà´·à´¨àµ† തടസàµà´¸à´ªàµà´ªàµ†à´Ÿàµà´¤àµà´¤àµà´¨àµà´¨à´¤àµ കൊണàµà´Ÿàµ‹ ആയിരികàµà´•à´¾à´‚ ഇതൠസംഭവിചàµà´šà´¤àµ.</translation>
<translation id="2943895734390379394">à´…à´ªàµâ€Œà´²àµ‹à´¡àµ ചെയàµà´¤ സമയം:</translation>
<translation id="2948083400971632585">കണകàµà´·à´¨à´¾à´¯à´¿ കോൺഫിഗർ ചെയàµâ€Œà´¤ à´à´¤àµŠà´°àµ à´ªàµà´°àµ‹à´•àµâ€Œà´¸à´¿à´•à´³àµà´‚ à´•àµà´°à´®àµ€à´•à´°à´£à´™àµà´™àµ¾ പേജിൽ നിനàµà´¨àµ നിങàµà´™àµ¾à´•àµà´•àµ à´ªàµà´°à´µàµ¼à´¤àµà´¤à´¨à´°à´¹à´¿à´¤à´®à´¾à´•àµà´•à´¾à´¨à´¾à´•àµà´‚.</translation>
@@ -642,6 +674,7 @@
<translation id="3037605927509011580">à´•à´·àµà´Ÿà´‚!</translation>
<translation id="3041612393474885105">സരàµâ€â€Œà´Ÿàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ വിവരങàµà´™à´³àµâ€â€Œ</translation>
<translation id="3044034790304486808">നിങàµà´™à´³àµà´Ÿàµ† തിരയൽ à´ªàµà´¨à´°à´¾à´°à´‚à´­à´¿à´•àµà´•àµà´•</translation>
+<translation id="305162504811187366">Chrome വിദൂര ഡെസàµâ€Œà´•àµâ€Œà´Ÿàµ‹à´ªàµà´ªàµ à´šà´°à´¿à´¤àµà´°à´‚, ടൈംസàµà´±àµà´±à´¾à´®àµà´ªàµà´•à´³àµà´‚ ഹോസàµà´±àµà´±àµà´•à´³àµà´‚ à´•àµà´²à´¯à´¨àµà´±àµ സെഷൻ à´à´¡à´¿à´•à´³àµà´‚ ഉൾപàµà´ªàµ†à´Ÿàµ†</translation>
<translation id="3060227939791841287">C9 (എൻവലപàµà´ªàµ)</translation>
<translation id="3061707000357573562">പാചàµà´šàµ സേവനം</translation>
<translation id="306573536155379004">ഗെയിം ആരംഭിചàµà´šàµ.</translation>
@@ -681,6 +714,7 @@
<translation id="3197136577151645743">നിങàµà´™àµ¾ സജീവമായി ഉപകരണം ഉപയോഗികàµà´•àµà´¨àµà´¨à´¤àµ à´Žà´ªàµà´ªàµ‹à´´à´¾à´£àµ†à´¨àµà´¨àµ അറിയാൻ ആവശàµà´¯à´ªàµà´ªàµ†à´Ÿà´¾à´‚</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />, Chrome à´•àµà´°à´®àµ€à´•à´°à´£à´¤àµà´¤à´¿àµ½ നിങàµà´™àµ¾ സമനàµà´µà´¯à´¿à´ªàµà´ªà´¿à´•àµà´•àµà´¨àµà´¨ വിവരങàµà´™àµ¾ മാനേജൠചെയàµà´¯à´¾àµ» 'Tab' അമർതàµà´¤à´¿à´¯ ശേഷം 'Enter' അമർതàµà´¤àµà´•</translation>
<translation id="320323717674993345">പേയàµâ€Œà´®àµ†à´¨àµà´±àµ റദàµà´¦à´¾à´•àµà´•àµà´•</translation>
+<translation id="3203366800380907218">വെബിൽ നിനàµà´¨àµ</translation>
<translation id="3207960819495026254">à´¬àµà´•àµà´•àµâ€Œà´®à´¾àµ¼à´•àµà´•àµà´šàµ†à´¯àµâ€Œà´¤àµ</translation>
<translation id="3209034400446768650">പേജൠപണം ഈടാകàµà´•à´¿à´¯àµ‡à´•àµà´•à´¾à´‚</translation>
<translation id="3212581601480735796"><ph name="HOSTNAME" /> à´Žà´¨àµà´¨à´¤à´¿à´²àµà´³àµà´³ നിങàµà´™à´³àµà´Ÿàµ† ആകàµà´±àµà´±à´¿à´µà´¿à´±àµà´±à´¿ നിരീകàµà´·à´£à´¤àµà´¤à´¿à´²à´¾à´£àµ</translation>
@@ -697,10 +731,12 @@
<translation id="3234666976984236645">à´ˆ സൈറàµà´±à´¿àµ½ à´Žà´ªàµà´ªàµ‹à´´àµà´‚ à´ªàµà´°à´§à´¾à´¨ ഉളàµà´³à´Ÿà´•àµà´•à´‚ à´•à´£àµà´Ÿàµ†à´¤àµà´¤àµà´•</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />, നിങàµà´™à´³àµà´Ÿàµ† à´¬àµà´°àµ—സറിനàµà´±àµ† രൂപം ഇഷàµà´Ÿà´¾à´¨àµà´¸àµƒà´¤à´®à´¾à´•àµà´•à´¾àµ» Tab അമർതàµà´¤àµà´•, à´¤àµà´Ÿàµ¼à´¨àµà´¨àµ Enter അമർതàµà´¤àµà´•</translation>
<translation id="3240791268468473923">à´¸àµà´°à´•àµà´·à´¿à´¤à´®à´¾à´¯ പേയàµâ€Œà´®àµ†à´¨àµà´±àµ à´•àµà´°àµ†à´¡àµ»à´·àµà´¯à´²àµà´®à´¾à´¯à´¿ പൊരàµà´¤àµà´¤à´®à´¿à´²àµà´²à´¾à´¤àµà´¤ à´•àµà´°àµ†à´¡àµ»à´·àµà´¯àµ½ ഷീറàµà´±àµ à´¤àµà´±à´¨àµà´¨àµ</translation>
+<translation id="324180406144491771">“<ph name="HOST_NAME" />†ലിങàµà´•àµà´•àµ¾ à´¬àµà´²àµ‹à´•àµà´•àµ ചെയàµà´¤à´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨àµ</translation>
<translation id="3249845759089040423">à´—àµà´°àµ‚വി</translation>
<translation id="3252266817569339921">à´«àµà´°à´žàµà´šàµ</translation>
<translation id="3257954757204451555">ആരാണൠഈ വിവരങàµà´™àµ¾ നൽകിയതàµ?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />, Google Calendar-ൽ à´ªàµà´¤à´¿à´¯àµŠà´°àµ ഇവനàµà´±àµ വേഗതàµà´¤à´¿àµ½ സൃഷàµà´Ÿà´¿à´•àµà´•à´¾àµ» Enter അമർതàµà´¤àµà´•</translation>
+<translation id="3261488570342242926">വെർചàµà´µàµ½ കാർഡàµà´•à´³àµ†à´•àµà´•àµà´±à´¿à´šàµà´šàµ അറിയàµà´•</translation>
<translation id="3264837738038045344">Chrome à´•àµà´°à´®àµ€à´•à´°à´£à´‚ മാനേജൠചെയàµà´¯àµà´• ബടàµà´Ÿàµº, നിങàµà´™à´³àµà´Ÿàµ† Chrome à´•àµà´°à´®àµ€à´•à´°à´£à´‚ സനàµà´¦àµ¼à´¶à´¿à´•àµà´•à´¾àµ» Enter അമർതàµà´¤àµà´•</translation>
<translation id="3266793032086590337">മൂലàµà´¯à´‚ (വൈരàµà´¦àµà´§àµà´¯à´‚)</translation>
<translation id="3268451620468152448">à´“à´ªàµà´ªàµº ടാബàµà´•àµ¾</translation>
@@ -714,6 +750,7 @@
<translation id="3288238092761586174">നിങàµà´™à´³àµà´Ÿàµ† പേയàµà´®àµ†à´¨àµà´±àµ പരിശോധിചàµà´šàµà´±à´ªàµà´ªà´¿à´•àµà´•à´¾àµ» <ph name="URL" /> അധിക നടപടികൾ à´¸àµà´µàµ€à´•à´°à´¿à´•àµà´•àµ‡à´£àµà´Ÿà´¤à´¾à´¯à´¿ വനàµà´¨àµ‡à´•àµà´•à´¾à´‚</translation>
<translation id="3293642807462928945"><ph name="POLICY_NAME" /> നയതàµà´¤àµ† à´•àµà´±à´¿à´šàµà´šàµ കൂടàµà´¤à´²à´±à´¿à´¯àµà´•</translation>
<translation id="3295444047715739395">Chrome à´•àµà´°à´®àµ€à´•à´°à´£à´¤àµà´¤à´¿àµ½ നിങàµà´™à´³àµà´Ÿàµ† പാസàµâ€Œà´µàµ‡à´¡àµà´•àµ¾ കാണàµà´•, മാനേജൠചെയàµà´¯àµà´•</translation>
+<translation id="3303795387212510132"><ph name="PROTOCOL_SCHEME" /> ലിങàµà´•àµà´•àµ¾ à´¤àµà´±à´•àµà´•à´¾àµ» ആപàµà´ªà´¿à´¨àµ† à´…à´¨àµà´µà´¦à´¿à´•àµà´•à´£àµ‹?</translation>
<translation id="3303855915957856445">തിരയൽ ഫലങàµà´™à´³àµŠà´¨àµà´¨àµà´‚ à´•à´£àµà´Ÿàµ†à´¤àµà´¤à´¿à´¯à´¿à´²àµà´²</translation>
<translation id="3304073249511302126">Bluetooth à´¸àµâ€Œà´•à´¾à´¨à´¿à´‚à´—àµ</translation>
<translation id="3308006649705061278">à´“à´°àµâ€â€Œà´—നൈസേഷണലàµâ€â€Œ യൂണിറàµà´±àµ (OU)</translation>
@@ -727,12 +764,6 @@
<translation id="3345782426586609320">à´•à´£àµà´£àµà´•àµ¾</translation>
<translation id="3355823806454867987">à´ªàµà´°àµ‹à´•àµà´¸à´¿ à´•àµà´°à´®àµ€à´•à´°à´£à´™àµà´™à´³àµâ€ മാറàµà´±àµà´•...</translation>
<translation id="3360103848165129075">പേയàµà´®àµ†à´¨àµà´±àµ കൈകാരàµà´¯à´‚ ചെയàµà´¯àµà´¨àµà´¨ ഷീറàµà´±àµ</translation>
-<translation id="3361596688432910856">Chrome ഇനിപàµà´ªà´±à´¯àµà´¨àµà´¨ വിവരങàµà´™àµ¾ <ph name="BEGIN_EMPHASIS" />സംരകàµà´·à´¿à´•àµà´•à´¿à´²àµà´²<ph name="END_EMPHASIS" />:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />നിങàµà´™à´³àµà´Ÿàµ† à´¬àµà´°àµ—സിംഗൠചരിതàµà´°à´‚
- <ph name="LIST_ITEM" />à´•àµà´•àµà´•à´¿à´•à´³àµà´‚ സൈറàµà´±àµ ഡാറàµà´±à´¯àµà´‚
- <ph name="LIST_ITEM" />ഫോമàµà´•à´³à´¿àµ½ നൽകàµà´¨àµà´¨ വിവരങàµà´™àµ¾
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">അവസാനിപàµà´ªà´¿à´šàµà´š <ph name="OLD_POLICY" /> നയതàµà´¤à´¿àµ½ നിനàµà´¨àµ à´¸àµà´µà´¯à´®àµ‡à´µ പകർതàµà´¤à´¿à´¯à´¤à´¾à´£àµ à´ˆ നയം. പകരം à´ˆ നയം ഉപയോഗികàµà´•à´£à´‚.</translation>
<translation id="3364869320075768271">നിങàµà´™à´³àµà´Ÿàµ† വെർചàµà´µàµ½ റിയാലിറàµà´±à´¿ ഉപകരണങàµà´™à´³àµà´‚ ഡാറàµà´±à´¯àµà´‚ ഉപയോഗികàµà´•à´¾àµ» <ph name="URL" /> ആഗàµà´°à´¹à´¿à´•àµà´•àµà´¨àµà´¨àµ</translation>
<translation id="3366477098757335611">കാർഡàµà´•àµ¾ കാണàµà´•</translation>
@@ -815,7 +846,6 @@
<translation id="3587738293690942763">മദàµà´§àµà´¯à´‚</translation>
<translation id="3592413004129370115">ഇറàµà´±à´¾à´²à´¿à´¯àµ» (എൻവലപàµà´ªàµ)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{നിങàµà´™à´³àµà´Ÿàµ† à´—àµà´°àµ‚à´ªàµà´ªàµ à´à´¤àµà´¸à´®à´¯à´¤àµà´¤àµà´‚ റീസെറàµà´±àµ ചെയàµà´¯à´¾à´‚. à´ªàµà´¤à´¿à´¯ à´—àµà´°àµ‚à´ªàµà´ªà´¿àµ½ ചേരാൻ ഒരൠദിവസമെടàµà´•àµà´•àµà´‚.}=1{നിങàµà´™à´³àµà´Ÿàµ† à´—àµà´°àµ‚à´ªàµà´ªàµ à´à´¤àµà´¸à´®à´¯à´¤àµà´¤àµà´‚ റീസെറàµà´±àµ ചെയàµà´¯à´¾à´‚. à´ªàµà´¤à´¿à´¯ à´—àµà´°àµ‚à´ªàµà´ªà´¿àµ½ ചേരാൻ ഒരൠദിവസമെടàµà´•àµà´•àµà´‚.}other{നിങàµà´™à´³àµà´Ÿàµ† à´—àµà´°àµ‚à´ªàµà´ªàµ à´à´¤àµà´¸à´®à´¯à´¤àµà´¤àµà´‚ റീസെറàµà´±àµ ചെയàµà´¯à´¾à´‚. à´ªàµà´¤à´¿à´¯ à´—àµà´°àµ‚à´ªàµà´ªà´¿àµ½ ചേരാൻ {NUM_DAYS} ദിവസമെടàµà´•àµà´•àµà´‚.}}</translation>
-<translation id="3596012367874587041">ആപàµà´ªàµ à´•àµà´°à´®àµ€à´•à´°à´£à´‚</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">ആപàµà´ªàµ നിങàµà´™à´³àµà´Ÿàµ† à´…à´¡àµâ€Œà´®à´¿àµ» à´¬àµà´²àµ‹à´•àµà´•àµ ചെയàµâ€Œà´¤à´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨àµ</translation>
<translation id="3608932978122581043">ഓറിയനàµà´±àµ‡à´·àµ» ഫീഡൠചെയàµà´¯àµà´•</translation>
@@ -858,6 +888,7 @@
<translation id="370972442370243704">ജേർണികൾ ഓണാകàµà´•àµà´•</translation>
<translation id="3711895659073496551">താൽകàµà´•à´¾à´²à´¿à´•à´®à´¾à´¯à´¿ റദàµà´¦à´¾à´•àµà´•àµà´•</translation>
<translation id="3712624925041724820">ലൈസൻസàµà´•àµ¾ കാലഹരണപàµà´ªàµ†à´Ÿàµà´Ÿàµ</translation>
+<translation id="3714633008798122362">വെബൠകലണàµà´Ÿàµ¼</translation>
<translation id="3714780639079136834">മൊബൈൽ ഡാറàµà´± à´…à´²àµà´²àµ†à´™àµà´•à´¿àµ½ Wi-Fi ഓണാകàµà´•àµà´¨àµà´¨àµ</translation>
<translation id="3715597595485130451">Wi-Fi-യിലേകàµà´•àµ കണകàµà´±àµà´±àµà´šàµ†à´¯àµà´¯àµà´•</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />à´ªàµà´°àµ‹à´•àµâ€Œà´¸à´¿à´¯àµà´‚ ഫയർവാളàµà´‚ DNS കോൺഫിഗറേഷനàµà´‚ പരിശോധികàµà´•àµà´¨àµà´¨àµ<ph name="END_LINK" /></translation>
@@ -919,6 +950,7 @@
<translation id="3906954721959377182">ടാബàµâ€Œà´²àµ†à´±àµà´±àµ</translation>
<translation id="3909477809443608991">പരിരകàµà´·à´¿à´¤ ഉളàµà´³à´Ÿà´•àµà´•à´‚ à´ªàµà´²àµ‡ ചെയàµà´¯à´¾àµ» <ph name="URL" /> താൽപàµà´ªà´°àµà´¯à´ªàµà´ªàµ†à´Ÿàµà´¨àµà´¨àµ. നിങàµà´™à´³àµà´Ÿàµ† ഉപകരണതàµà´¤à´¿à´¨àµâ€à´±àµ† à´à´¡à´¨àµâ€à´±à´¿à´±àµà´±à´¿ Google പരിശോധിചàµà´šàµà´±à´ªàµà´ªà´¿à´•àµà´•àµà´‚, à´ˆ സൈറàµà´±àµ ആകàµâ€Œà´¸à´¸àµ ചെയàµà´¯à´¾à´¨à´¾à´¯àµ‡à´•àµà´•à´¾à´‚.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">നിരസികàµà´•àµ‚</translation>
<translation id="3939773374150895049">CVC-à´¯àµà´•àµà´•àµ പകരം WebAuthn ഉപയോഗികàµà´•à´£àµ‹?</translation>
<translation id="3946209740501886391">à´ˆ സൈറàµà´±à´¿àµ½ à´Žà´²àµà´²à´¾à´¯àµâ€Œà´ªàµà´ªàµ‹à´´àµà´‚ ചോദികàµà´•àµà´•</translation>
<translation id="3947595700203588284">MIDI ഉപകരണങàµà´™à´³à´¿à´²àµ‡à´•àµà´•àµ കണകàµâ€Œà´±àµà´±àµ ചെയàµà´¯à´¾àµ» ആവശàµà´¯à´ªàµà´ªàµ†à´Ÿà´¾à´‚</translation>
@@ -940,6 +972,7 @@
<translation id="3990250421422698716">ജോഗൠഓഫàµâ€Œà´¸àµ†à´±àµà´±àµ</translation>
<translation id="3996311196211510766"><ph name="ORIGIN" /> à´Žà´¨àµà´¨ സൈറàµà´±à´¿à´²àµ‡à´•àµà´•àµà´³àµà´³ à´Žà´²àµà´²à´¾ à´…à´­àµà´¯àµ¼à´¤àµà´¥à´¨à´•àµ¾à´•àµà´•àµà´‚ ഒരൠഉറവിട നയം
ബാധകമാകàµà´®àµ†à´¨àµà´¨àµ ഇതൠഅഭàµà´¯àµ¼à´¤àµà´¥à´¿à´šàµà´šà´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨àµ, à´Žà´¨àµà´¨à´¾àµ½ à´ˆ നയം ഇപàµà´ªàµ‹àµ¾ ബാധകമാകàµà´•à´¾à´¨à´¾à´µà´¿à´²àµà´².</translation>
+<translation id="4009243425692662128">നിങàµà´™àµ¾ à´ªàµà´°à´¿à´¨àµà´±àµ ചെയàµà´¯àµà´¨àµà´¨ പേജàµà´•à´³àµà´Ÿàµ† ഉളàµà´³à´Ÿà´•àµà´•à´‚, വിശകലനം ചെയàµà´¯à´¾àµ» Google à´•àµà´²àµ—ഡിനോ മൂനàµà´¨à´¾à´‚ à´•à´•àµà´·à´¿à´•àµ¾à´•àµà´•àµ‹ അയയàµà´•àµà´•àµà´‚. ഉദാഹരണതàµà´¤à´¿à´¨àµ, സെൻസിറàµà´±àµ€à´µà´¾à´¯à´¿à´Ÿàµà´Ÿàµà´³àµà´³ à´µàµà´¯à´•àµà´¤à´¿à´ªà´°à´®à´¾à´¯ ഡാറàµà´± ഉണàµà´Ÿàµ‹à´¯àµ†à´¨àµà´¨à´±à´¿à´¯à´¾àµ» ഇതൠസàµâ€Œà´•à´¾àµ» ചെയàµâ€Œà´¤àµ‡à´•àµà´•à´¾à´‚.</translation>
<translation id="4010758435855888356">à´¸àµà´±àµà´±àµ‹à´±àµ‡à´œàµ ആകàµâ€Œà´¸à´¸à´¿à´¨àµà´³àµà´³ à´…à´¨àµà´®à´¤à´¿ നൽകണോ?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{{COUNT} പേജàµà´³àµà´³ PDF ഡോകàµà´¯àµà´®àµ†à´¨àµà´±àµ}other{{COUNT} പേജàµà´•à´³àµà´³àµà´³ PDF ഡോകàµà´¯àµà´®àµ†à´¨àµà´±àµ}}</translation>
<translation id="4023431997072828269">à´¸àµà´°à´•àµà´·à´¿à´¤à´®à´²àµà´²à´¾à´¤àµà´¤ ഒരൠകണകàµà´·àµ» ഉപയോഗിചàµà´šàµ à´ˆ ഫോം സമർപàµà´ªà´¿à´•àµà´•àµà´¨àµà´¨à´¤à´¿à´¨à´¾àµ½, നിങàµà´™à´³àµà´Ÿàµ† വിവരങàµà´™àµ¾ മറàµà´±àµà´³àµà´³à´µàµ¼à´•àµà´•àµ കാണാനാകàµà´‚.</translation>
@@ -1032,6 +1065,7 @@
<translation id="4250680216510889253">ഇലàµà´²</translation>
<translation id="4253168017788158739">à´•àµà´±à´¿à´ªàµà´ªàµ</translation>
<translation id="425582637250725228">നിങàµà´™àµ¾ വരàµà´¤àµà´¤à´¿à´¯ മാറàµà´±à´™àµà´™àµ¾ സംരകàµà´·à´¿à´•àµà´•à´ªàµà´ªàµ†à´Ÿàµà´Ÿà´¿à´°à´¿à´•àµà´•à´¾à´¨à´¿à´Ÿà´¯à´¿à´²àµà´².</translation>
+<translation id="425869179292622354">വെർചàµà´µàµ½ കാർഡൠഉപയോഗിചàµà´šàµ ഇതൠകൂടàµà´¤àµ½ à´¸àµà´°à´•àµà´·à´¿à´¤à´®à´¾à´•àµà´•à´£àµ‹?</translation>
<translation id="4258748452823770588">മോശം സിഗàµâ€Œà´¨àµ‡à´šàµà´šàµ¼</translation>
<translation id="4261046003697461417">സംരകàµà´·à´¿à´šàµà´šà´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨ ഡോകàµà´¯àµà´®àµ†àµ»àµà´±àµà´•àµ¾ അനോടàµà´Ÿàµ‡à´±àµà´±àµ ചെയàµà´¯à´¾à´¨à´¾à´µà´¿à´²àµà´²</translation>
<translation id="4265872034478892965">നിങàµà´™à´³àµà´Ÿàµ† à´…à´¡àµâ€Œà´®à´¿à´¨à´¿à´Ÿàµà´°àµ‡à´±àµà´±àµ¼ à´…à´¨àµà´µà´¦à´¿à´šàµà´šà´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨àµ</translation>
@@ -1094,6 +1128,7 @@
<translation id="4434045419905280838">പോപàµ-à´…à´ªàµà´ªàµà´•à´³àµà´‚ റീഡയറകàµâ€Œà´±àµà´±àµà´•à´³àµà´‚</translation>
<translation id="4435702339979719576">പോസàµâ€Œà´±àµà´±àµâ€Œ കാർഡàµ)</translation>
<translation id="443673843213245140">à´ªàµà´°àµ‹à´•àµâ€Œà´¸à´¿ ഉപയോഗം à´…à´ªàµà´°à´¾à´ªàµâ€Œà´¤à´®à´¾à´•àµà´•à´¿ പകàµà´·àµ† ഒരൠവàµà´¯à´•àµà´¤à´®à´¾à´¯ à´ªàµà´°àµ‹à´•àµâ€Œà´¸à´¿ കോൺഫിഗറേഷൻ നിർദàµà´¦àµ‡à´¶à´¿à´šàµà´šàµ.</translation>
+<translation id="4441832193888514600">à´•àµà´²àµ—ഡൠഉപയോകàµà´¤àµƒ നയം ആയി മാതàµà´°à´®àµ‡ നയം സജàµà´œàµ€à´•à´°à´¿à´•àµà´•à´¾à´¨à´¾à´•àµ‚ à´Žà´¨àµà´¨à´¤à´¿à´¨à´¾àµ½ അവഗണികàµà´•àµ‚.</translation>
<translation id="4450893287417543264">വീണàµà´Ÿàµà´‚ കാണികàµà´•à´°àµà´¤àµ</translation>
<translation id="4451135742916150903">HID ഉപകരണങàµà´™à´³à´¿à´²àµ‡à´•àµà´•àµ കണകàµâ€Œà´±àµà´±àµ ചെയàµà´¯à´¾àµ» ആവശàµà´¯à´ªàµà´ªàµ†à´Ÿà´¾à´‚</translation>
<translation id="4452328064229197696">നിങàµà´™àµ¾ ഇപàµà´ªàµ‹àµ¾ ഉപയോഗിചàµà´š പാസàµâ€Œà´µàµ‡à´¡àµ ഡാറàµà´±à´¾ ലംഘനതàµà´¤à´¿àµ½ à´•à´£àµà´Ÿàµ†à´¤àµà´¤à´¿à´¯à´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨àµ. നിങàµà´™à´³àµà´Ÿàµ† à´…à´•àµà´•àµ—à´£àµà´Ÿàµà´•àµ¾ à´¸àµà´°à´•àµà´·à´¿à´¤à´®à´¾à´•àµà´•à´¾àµ», സംരകàµà´·à´¿à´šàµà´š പാസàµâ€Œà´µàµ‡à´¡àµà´•àµ¾ പരിശോധികàµà´•à´¾àµ» Google പാസàµâ€Œà´µàµ‡à´¡àµ മാനേജർ നിർദàµà´¦àµ‡à´¶à´¿à´•àµà´•àµà´¨àµà´¨àµ.</translation>
@@ -1149,6 +1184,7 @@
<translation id="4628948037717959914">ഫോടàµà´Ÿàµ‹</translation>
<translation id="4631649115723685955">à´•àµà´¯à´¾à´·àµ ബാകàµà´•àµ ലിങàµà´•àµ ചെയàµâ€Œà´¤àµ</translation>
<translation id="4636930964841734540">വിവരം</translation>
+<translation id="4638670630777875591">Chromium-ലെ അദൃശàµà´¯ മോഡàµ</translation>
<translation id="464342062220857295">തിരയൽ ഫീചàµà´šà´±àµà´•àµ¾</translation>
<translation id="4644670975240021822">വിപരീത à´•àµà´°à´®à´¤àµà´¤à´¿àµ½ ഫേസൠഡൗൺ</translation>
<translation id="4646534391647090355">à´Žà´¨àµà´¨àµ† ഇപàµà´ªàµ‹àµ¾ അവിടെയെതàµà´¤à´¿à´•àµà´•àµ‚</translation>
@@ -1169,6 +1205,7 @@
<translation id="4708268264240856090">നിങàµà´™à´³àµà´Ÿàµ† കണകàµà´·àµ» തടസàµà´¸à´ªàµà´ªàµ†à´Ÿàµà´Ÿàµ</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Windows നെറàµà´±àµâ€Œà´µàµ¼à´•àµà´•àµ ഡയഗണോസàµâ€Œà´±àµà´±à´¿à´•àµâ€Œà´¸àµ റൺ ചെയàµà´¯àµà´¨àµà´¨àµ<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426"><ph name="USERNAME" /> à´Žà´¨àµà´¨à´¤à´¿à´¨àµà´³àµà´³ പാസàµâ€Œà´µàµ‡à´¡àµ</translation>
<translation id="4724144314178270921">നിങàµà´™à´³àµà´Ÿàµ† à´•àµà´²à´¿à´ªàµà´ªàµà´¬àµ‹àµ¼à´¡à´¿à´²àµ† ടെകàµâ€Œà´¸àµà´±àµà´±àµà´‚ à´šà´¿à´¤àµà´°à´™àµà´™à´³àµà´‚ കാണാൻ ആവശàµà´¯à´ªàµà´ªàµ†à´Ÿà´¾à´‚</translation>
<translation id="4726672564094551039">നയങàµà´™àµ¾ വീണàµà´Ÿàµà´‚ ലോഡൠചെയàµà´¯àµà´•</translation>
<translation id="4728558894243024398">à´ªàµà´²à´¾à´±àµà´±àµà´«àµ‹à´‚</translation>
@@ -1190,6 +1227,7 @@
<translation id="4757993714154412917">വഞàµà´šà´¨à´¾à´ªà´°à´®à´¾à´¯ സൈറàµà´±à´¿àµ½ നിങàµà´™àµ¾ ഇപàµà´ªàµ‹àµ¾ പാസàµâ€à´µàµ‡à´¡àµ നൽകി. à´…à´•àµà´•àµ—à´£àµà´Ÿàµà´•àµ¾ à´¸àµà´°à´•àµà´·à´¿à´¤à´®à´¾à´•àµà´•à´¾àµ», നിങàµà´™à´³àµà´Ÿàµ† സംരകàµà´·à´¿à´šàµà´š പാസàµâ€Œà´µàµ‡à´¡àµà´•àµ¾ ഇപàµà´ªàµ‹àµ¾ തനàµà´¨àµ† പരിശോധികàµà´•à´¾àµ» Chromium നിർദàµà´¦àµ‡à´¶à´¿à´•àµà´•àµà´¨àµà´¨àµ.</translation>
<translation id="4758311279753947758">കോൺടാകàµà´±àµà´±àµ വിവരങàµà´™àµ¾ ചേർകàµà´•àµà´•</translation>
<translation id="4761104368405085019">നിങàµà´™à´³àµà´Ÿàµ† മൈകàµà´°àµ‹à´«àµ‹àµº ഉപയോഗികàµà´•àµà´•</translation>
+<translation id="4761869838909035636">Chrome à´¸àµà´°à´•àµà´·à´¾ പരിശോധന റൺ ചെയàµà´¯àµà´•</translation>
<translation id="4764776831041365478"><ph name="URL" /> ലെ വെബàµâ€Œà´ªàµ‡à´œàµ താലàµâ€â€Œà´•àµà´•à´¾à´²à´¿à´•à´®à´¾à´¯à´¿ à´ªàµà´°à´µà´°àµâ€â€Œà´¤àµà´¤à´¨à´°à´¹à´¿à´¤à´®à´¾à´¯à´¿à´°à´¿à´•àµà´•à´¾à´‚, à´…à´²àµà´²àµ†à´™àµà´•à´¿à´²àµâ€â€Œ ഒരൠപàµà´¤à´¿à´¯ വെബൠവിലാസതàµà´¤à´¿à´²àµ‡à´•àµà´•àµ ശാശàµà´µà´¤à´®à´¾à´¯à´¿ നീകàµà´•à´‚ചെയàµà´¯à´ªàµà´ªàµ†à´Ÿàµà´Ÿà´¿à´°à´¿à´•àµà´•à´¾à´‚.</translation>
<translation id="4766713847338118463">താഴെ ഇരടàµà´Ÿ à´¸àµâ€Œà´±àµà´±àµ‡à´ªàµà´ªà´¿àµ¾ ചെയàµà´¯àµà´•</translation>
<translation id="4771973620359291008">ഒരൠഅജàµà´žà´¾à´¤ പിശകൠസംഭവിചàµà´šàµ.</translation>
@@ -1210,12 +1248,6 @@
<translation id="4819347708020428563">ഡിഫോൾടàµà´Ÿàµ കാഴàµâ€Œà´šà´¯à´¿àµ½ à´•àµà´±à´¿à´ªàµà´ªàµà´•àµ¾ à´Žà´¡à´¿à´±àµà´±àµ ചെയàµà´¯à´£àµ‹?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />, à´ªàµà´¤à´¿à´¯àµŠà´°àµ Google ഷീറàµà´±àµ വേഗതàµà´¤à´¿àµ½ സൃഷàµà´Ÿà´¿à´•àµà´•à´¾àµ» Tab അമർതàµà´¤àµà´•, à´¤àµà´Ÿàµ¼à´¨àµà´¨àµ Enter അമർതàµà´¤àµà´•</translation>
<translation id="4825507807291741242">ശകàµà´¤à´®à´¾à´¯à´¤àµ</translation>
-<translation id="4827402517081186284">അദൃശàµà´¯ മോഡൠനിങàµà´™à´³àµ† ഓൺലൈനിൽ അദൃശàµà´¯à´®à´¾à´•àµà´•àµà´¨àµà´¨à´¿à´²àµà´²:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />നിങàµà´™àµ¾ സനàµà´¦àµ¼à´¶à´¿à´•àµà´•àµà´®àµà´ªàµ‹àµ¾ സൈറàµà´±àµà´•àµ¾à´•àµà´•àµ അതൠഅറിയാനാകàµà´‚<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />തൊഴിലàµà´Ÿà´®à´•àµ¾à´•àµà´•àµ‹ à´¸àµà´•àµ‚à´³àµà´•àµ¾à´•àµà´•àµ‹ à´¬àµà´°àµ—സിംഗൠആകàµà´±àµà´±à´¿à´µà´¿à´±àµà´±à´¿ à´Ÿàµà´°à´¾à´•àµà´•àµ ചെയàµà´¯à´¾à´¨à´¾à´•àµà´‚<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />ഇനàµà´±àµ¼à´¨àµ†à´±àµà´±àµ സേവന ദാതാകàµà´•àµ¾ വെബൠടàµà´°à´¾à´«à´¿à´•àµ നിരീകàµà´·à´¿à´šàµà´šàµ‡à´•àµà´•à´¾à´‚<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">à´®àµà´¨àµà´¨à´±à´¿à´¯à´¿à´ªàµà´ªàµà´•àµ¾ ഓണാകàµà´•àµà´•</translation>
<translation id="4838327282952368871">മനോരാജàµà´¯à´¤àµà´¤à´¿àµ½ à´®àµà´´àµà´•à´¿à´¯à´¤àµ</translation>
<translation id="4840250757394056958">നിങàµà´™à´³àµà´Ÿàµ† Chrome à´šà´°à´¿à´¤àµà´°à´‚ കാണàµà´•</translation>
@@ -1227,12 +1259,12 @@
<translation id="4854362297993841467">à´ˆ ഡെലിവറി രീതി ലഭàµà´¯à´®à´²àµà´². മറàµà´±àµŠà´°àµ രീതി പരീകàµà´·à´¿à´•àµà´•àµà´•.</translation>
<translation id="4854853140771946034">Google Keep-ൽ à´ªàµà´¤à´¿à´¯àµŠà´°àµ à´•àµà´±à´¿à´ªàµà´ªàµ വേഗതàµà´¤à´¿àµ½ സൃഷàµà´Ÿà´¿à´•àµà´•àµà´•</translation>
<translation id="485902285759009870">കോഡൠപരിശോധിചàµà´šàµà´±à´ªàµà´ªà´¿à´•àµà´•àµà´¨àµà´¨àµ...</translation>
+<translation id="4866506163384898554">നിങàµà´™à´³àµà´Ÿàµ† à´•à´´àµâ€Œà´¸àµ¼ കാണികàµà´•à´¾àµ» |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| അമർതàµà´¤àµà´•</translation>
<translation id="4876188919622883022">ലളിതവൽകàµà´•à´°à´¿à´šàµà´š കാഴàµà´šàµà´š</translation>
<translation id="4876305945144899064">ഉപയോകàµà´¤àµƒà´¨à´¾à´®à´®à´¿à´²àµà´²</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{à´’à´¨àµà´¨àµà´®à´¿à´²àµà´²}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831"><ph name="TEXT" /> തിരയàµà´•</translation>
<translation id="4879491255372875719">à´¸àµà´µà´®àµ‡à´§à´¯à´¾ (ഡിഫോൾടàµà´Ÿàµ)</translation>
-<translation id="4879725228911483934">നിങàµà´™à´³àµà´Ÿàµ† വിൻഡോ à´¤àµà´±à´¨àµà´¨àµ à´¸àµà´•àµà´°àµ€à´¨à´¿àµ½ വെയàµà´•àµà´•à´£à´®àµ†à´¨àµà´¨àµà´£àµà´Ÿàµ</translation>
<translation id="4880827082731008257">തിരയൽ à´šà´°à´¿à´¤àµà´°à´‚</translation>
<translation id="4881695831933465202">à´¤àµà´±à´•àµà´•àµà´•</translation>
<translation id="4885256590493466218">ചെകàµà´•àµâ€Œà´”à´Ÿàµà´Ÿàµ ചെയàµà´¯àµà´®àµà´ªàµ‹àµ¾ <ph name="CARD_DETAIL" /> ഉപയോഗിചàµà´šàµ പണമടയàµâ€Œà´•àµà´•àµà´•</translation>
@@ -1241,6 +1273,7 @@
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">ഒൻപതാമതàµà´¤àµ† റോൾ</translation>
<translation id="4901778704868714008">സംരകàµà´·à´¿à´•àµà´•àµà´•...</translation>
+<translation id="4905659621780993806">നിങàµà´™à´³àµà´Ÿàµ† à´…à´¡àµâ€Œà´®à´¿àµ» നിങàµà´™à´³àµà´Ÿàµ† ഉപകരണം <ph name="DATE" />, <ph name="TIME" />-നൠറീസàµà´±àµà´±à´¾àµ¼à´Ÿàµà´Ÿàµ ചെയàµà´¯àµà´‚. നിങàµà´™à´³àµà´Ÿàµ† ഉപകരണം റീസàµà´±àµà´±à´¾àµ¼à´Ÿàµà´Ÿàµ ചെയàµà´¯àµà´¨àµà´¨à´¤à´¿à´¨àµ à´®àµà´®àµà´ªàµ à´¤àµà´±à´¨àµà´¨à´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨ ഇനങàµà´™à´³àµ†à´²àµà´²à´¾à´‚ സംരകàµà´·à´¿à´•àµà´•àµà´•.</translation>
<translation id="4913987521957242411">à´®àµà´•à´³à´¿àµ½ ഇടതàµà´µà´¶à´¤àµà´¤àµ പഞàµà´šàµ ചെയàµà´¯àµà´•</translation>
<translation id="4918221908152712722"><ph name="APP_NAME" /> ഇൻസàµà´±àµà´±à´¾àµ¾ ചെയàµà´¯àµà´• (ഡൗൺലോഡൠചെയàµà´¯àµ‡à´£àµà´Ÿà´¤à´¿à´²àµà´²)</translation>
<translation id="4923459931733593730">പേയàµâ€Œà´®àµ†à´¨àµà´±àµ രീതി</translation>
@@ -1249,6 +1282,7 @@
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, തിരയാൻ 'Tab' അമർതàµà´¤àµà´•, à´¤àµà´Ÿàµ¼à´¨àµà´¨àµ 'Enter' അമർതàµà´¤àµà´•</translation>
<translation id="4930153903256238152">ഉയർനàµà´¨ ശേഷി</translation>
+<translation id="4940163644868678279">Chrome-ലെ അദൃശàµà´¯ മോഡàµ</translation>
<translation id="4943872375798546930">ഫലങàµà´™à´³àµŠà´¨àµà´¨àµà´®à´¿à´²àµà´²</translation>
<translation id="4950898438188848926">ടാബൠമാറാനàµà´³àµà´³ ബടàµà´Ÿàµº, à´¤àµà´±à´¨àµà´¨à´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨ ടാബായ <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /> à´Žà´¨àµà´¨à´¤à´¿à´²àµ‡à´•àµà´•àµ മാറാൻ എൻàµà´±àµ¼ അമർതàµà´¤àµà´•</translation>
<translation id="495170559598752135">à´ªàµà´°à´µà´°àµâ€à´¤àµà´¤à´¨à´™àµà´™à´³àµâ€</translation>
@@ -1258,6 +1292,7 @@
<translation id="4968522289500246572">à´ˆ ആപàµà´ªàµ മൊബൈലിനായി രൂപകൽപàµà´ªà´¨ ചെയàµà´¤à´¤à´¾à´£àµ, അതിനàµà´±àµ† വലàµà´ªàµà´ªà´‚ ഉദàµà´¦àµ‡à´¶à´¿à´•àµà´•àµà´¨àµà´¨ രീതിയിൽ മാറàµà´±à´¾àµ» à´•à´´à´¿à´žàµà´žàµ‡à´•àµà´•à´¿à´²àµà´². ആപàµà´ªà´¿à´¨àµ à´ªàµà´°à´¶àµà´¨à´™àµà´™àµ¾ നേരിടàµà´Ÿàµ‡à´•àµà´•à´¾à´‚ à´…à´²àµà´²àµ†à´™àµà´•à´¿àµ½ അതൠറീസàµà´±àµà´±à´¾àµ¼à´Ÿàµà´Ÿàµ ചെയàµà´¤àµ‡à´•àµà´•à´¾à´‚.</translation>
<translation id="4969341057194253438">റെകàµà´•àµ‡à´¾àµ¼à´¡à´¿à´‚ഗൠഇലàµà´²à´¾à´¤à´¾à´•àµà´•àµà´•</translation>
<translation id="4973922308112707173">à´®àµà´•à´³à´¿àµ½ ഇരടàµà´Ÿ പഞàµà´šàµ ചെയàµà´¯àµà´•</translation>
+<translation id="4976702386844183910">അവസാനം സനàµà´¦àµ¼à´¶à´¿à´šàµà´šà´¤àµ <ph name="DATE" />-നൠആണàµ</translation>
<translation id="4984088539114770594">മൈകàµà´°àµ‹à´«àµ‹àµº ഉപയോഗികàµà´•à´£àµ‹?</translation>
<translation id="4984339528288761049">Prc5 (എൻവലപàµà´ªàµ)</translation>
<translation id="4989163558385430922">à´Žà´²àµà´²à´¾à´‚ കാണàµà´•</translation>
@@ -1319,6 +1354,7 @@
<translation id="5138227688689900538">à´•àµà´±à´šàµà´šàµ കാണികàµà´•àµà´•</translation>
<translation id="5145883236150621069">നയ à´ªàµà´°à´¤à´¿à´•à´°à´£à´¤àµà´¤à´¿àµ½ പിശകൠകോഡൠഉണàµà´Ÿàµ</translation>
<translation id="5146995429444047494"><ph name="ORIGIN" /> à´Žà´¨àµà´¨à´¤à´¿à´¨àµà´±àµ† അറിയിപàµà´ªàµà´•àµ¾ à´¬àµà´²àµ‹à´•àµà´•àµ ചെയàµâ€Œà´¤à´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨àµ</translation>
+<translation id="514704532284964975">നിങàµà´™à´³àµà´Ÿàµ† ഫോൺ ഉപയോഗിചàµà´šàµ ടാപàµà´ªàµ ചെയàµà´¯àµà´¨àµà´¨ NFC ഉപകരണങàµà´™à´³à´¿à´²àµ† വിവരങàµà´™àµ¾ കാണാനàµà´‚ അവയിൽ മാറàµà´±à´‚ വരàµà´¤àµà´¤à´¾à´¨àµà´‚ <ph name="URL" /> താൽപàµà´ªà´°àµà´¯à´ªàµà´ªàµ†à´Ÿàµà´¨àµà´¨àµ</translation>
<translation id="5148809049217731050">ഫേസൠഅപàµà´ªàµ</translation>
<translation id="515292512908731282">C4 (എൻവലപàµà´ªàµ)</translation>
<translation id="5158275234811857234">കവർ</translation>
@@ -1343,6 +1379,7 @@
<translation id="5215116848420601511">Google Pay ഉപയോഗികàµà´•àµà´¨àµà´¨ വിലാസങàµà´™à´³àµà´‚ പേയàµà´®àµ†à´¨àµà´±àµ രീതികളàµà´‚</translation>
<translation id="5215363486134917902">ഫോളിയോ-Sp</translation>
<translation id="521659676233207110">à´Ÿàµà´°àµ‡ 13</translation>
+<translation id="5216942107514965959">അവസാനം സനàµà´¦àµ¼à´¶à´¿à´šàµà´šà´¤àµ ഇനàµà´¨à´¾à´£àµ</translation>
<translation id="5222812217790122047">ഇമെയിൽ ആവശàµà´¯à´®à´¾à´£àµ</translation>
<translation id="5230733896359313003">à´·à´¿à´ªàµà´ªà´¿à´‚ഗൠവിലാസം</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1363,7 +1400,6 @@
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">ഡോകàµà´¯àµà´®àµ†à´¨àµà´±àµ à´ªàµà´°àµ‹à´ªàµà´ªàµ¼à´Ÿàµà´Ÿà´¿à´•àµ¾</translation>
<translation id="528468243742722775">അവസാനിപàµà´ªà´¿à´•àµà´•àµà´•</translation>
-<translation id="5284909709419567258">നെറàµà´±àµâ€Œà´µàµ¼à´•àµà´•àµ വിലാസങàµà´™àµ¾</translation>
<translation id="5285570108065881030">സംരകàµà´·à´¿à´šàµà´š à´Žà´²àµà´²à´¾ പാസàµâ€Œà´µàµ‡à´¡àµà´•à´³àµà´‚ കാണികàµà´•àµà´•</translation>
<translation id="5287240709317226393">à´•àµà´•àµà´•à´¿à´•à´³àµâ€ കാണികàµà´•àµà´•</translation>
<translation id="5287456746628258573">കാലഹരണപàµà´ªàµ†à´Ÿàµà´Ÿ à´¸àµà´°à´•àµà´·à´¾ കോൺഫിഗറേഷൻ ആണൠഈ സെെറàµà´±àµ ഉപയോഗികàµà´•àµà´¨àµà´¨à´¤àµ, അതിനാൽ നിങàµà´™à´³àµà´Ÿàµ† വിവരങàµà´™àµ¾ (ഉദാഹരണതàµà´¤à´¿à´¨àµ, പാസàµâ€Œà´µàµ‡à´¡àµà´•à´³àµ‹ à´•àµà´°àµ†à´¡à´¿à´±àµà´±àµ കാർഡൠനമàµà´ªà´±àµà´•à´³àµ‹) à´ˆ സൈറàµà´±à´¿à´²àµ‡à´•àµà´•àµ അയചàµà´šà´¾àµ½ à´…à´µ à´ªàµà´°à´¦àµ¼à´¶à´¿à´ªàµà´ªà´¿à´•àµà´•à´ªàµà´ªàµ†à´Ÿàµà´Ÿàµ‡à´•àµà´•à´¾à´‚.</translation>
@@ -1447,6 +1483,7 @@
<translation id="5556459405103347317">വീണàµà´Ÿàµà´‚ ലോഡൠചെയàµà´¯àµà´•</translation>
<translation id="5560088892362098740">കാലഹരണപàµà´ªàµ†à´Ÿà´²àµâ€ തീയതി</translation>
<translation id="55635442646131152">ഡോകàµà´¯àµà´®àµ†à´¨àµà´±à´¿à´¨àµà´±àµ† ഔടàµà´Ÿàµâ€Œà´²àµˆàµ»</translation>
+<translation id="5565613213060953222">അദൃശàµà´¯ ടാബൠതàµà´±à´•àµà´•àµà´•</translation>
<translation id="5565735124758917034">സജീവമാണàµ</translation>
<translation id="5570825185877910964">à´…à´•àµà´•àµ—à´£àµà´Ÿàµ പരിരകàµà´·à´¿à´•àµà´•àµà´•</translation>
<translation id="5571083550517324815">à´ˆ വിലാസതàµà´¤à´¿àµ½ നിനàµà´¨àµ പികàµà´•àµà´…à´ªàµà´ªàµ ചെയàµà´¯à´¾àµ» കഴിയിലàµà´². മറàµà´±àµŠà´°àµ വിലാസം തിരഞàµà´žàµ†à´Ÿàµà´•àµà´•àµà´•.</translation>
@@ -1529,6 +1566,7 @@
<translation id="5869522115854928033">സംരകàµà´·à´¿à´šàµà´š പാസàµâ€Œà´µàµ‡à´¡àµà´•à´³àµâ€</translation>
<translation id="5873013647450402046">ഇതൠനിങàµà´™àµ¾ തനàµà´¨àµ†à´¯à´¾à´£àµ†à´¨àµà´¨àµ ബാങàµà´•à´¿à´¨àµ à´¸àµà´¥à´¿à´°àµ€à´•à´°à´¿à´•àµà´•àµ‡à´£àµà´Ÿà´¤àµà´£àµà´Ÿàµ.</translation>
<translation id="5887400589839399685">കാർഡൠസംരകàµà´·à´¿à´šàµà´šàµ</translation>
+<translation id="5887687176710214216">അവസാനം സനàµà´¦àµ¼à´¶à´¿à´šàµà´šà´¤àµ ഇനàµà´¨à´²àµ†à´¯à´¾à´£àµ</translation>
<translation id="5895138241574237353">à´ªàµà´¨à´°à´¾à´°à´‚à´­à´¿à´•àµà´•àµà´•</translation>
<translation id="5895187275912066135">ഇനിപàµà´ªà´±à´¯àµà´¨àµà´¨à´¦à´¿à´µà´¸à´‚ നലàµâ€â€Œà´•à´¿</translation>
<translation id="5901630391730855834">മഞàµà´ž</translation>
@@ -1542,6 +1580,7 @@
<translation id="5921639886840618607">Google à´…à´•àµà´•àµ—à´£àµà´Ÿà´¿àµ½ കാർഡൠസംരകàµà´·à´¿à´•àµà´•à´£àµ‹?</translation>
<translation id="5922853866070715753">à´à´¤à´¾à´£àµà´Ÿàµ പൂർതàµà´¤à´¿à´¯à´¾à´¯à´¿</translation>
<translation id="5932224571077948991">അനാവശàµà´¯à´®àµ‹ തെറàµà´±à´¿à´¦àµà´§à´°à´¿à´ªàµà´ªà´¿à´•àµà´•àµà´¨àµà´¨à´¤àµ‹ ആയ പരസàµà´¯à´™àµà´™à´³àµâ€ കാണികàµà´•àµà´¨àµà´¨ സൈറàµà´±àµ</translation>
+<translation id="5938153366081463283">വെർചàµà´µàµ½ കാർഡൠചേർകàµà´•àµà´•</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347"><ph name="SITE_NAME" /> à´¤àµà´±à´•àµà´•àµà´¨àµà´¨àµâ€¦</translation>
<translation id="5951495562196540101">ഉപയോകàµà´¤àµƒ à´…à´•àµà´•àµ—à´£àµà´Ÿàµ ഉപയോഗിചàµà´šàµ എൻറോൾ ചെയàµà´¯à´¾à´¨à´¾à´µà´¿à´²àµà´² (പാകàµà´•àµ‡à´œàµ ചെയàµâ€Œà´¤ ലൈസൻസൠലഭàµà´¯à´®à´¾à´£àµ).</translation>
@@ -1606,6 +1645,7 @@
<translation id="6120179357481664955">നിങàµà´™à´³àµà´Ÿàµ† UPI à´à´¡à´¿ ഓർമàµà´®à´¯àµà´£àµà´Ÿàµ‹?</translation>
<translation id="6124432979022149706">Chrome à´Žà´¨àµà´±àµ¼à´ªàµà´°àµˆà´¸àµ കണകàµà´±àµà´±à´±àµà´•àµ¾</translation>
<translation id="6127379762771434464">ഇനം നീകàµà´•à´‚ചെയàµâ€Œà´¤àµ</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Chrome-ലെ അദൃശàµà´¯ മോഡിനെ à´•àµà´±à´¿à´šàµà´šàµ കൂടàµà´¤à´²à´±à´¿à´¯àµà´•<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">à´Žà´²àµà´²à´¾ കേബിളàµà´•à´³àµà´‚ പരിശോധികàµà´•àµà´• à´’à´ªàµà´ªà´‚ à´à´¤àµ†à´™àµà´•à´¿à´²àµà´‚ റൂടàµà´Ÿà´±àµà´•àµ¾, മോഡങàµà´™àµ¾ നിങàµà´™àµ¾ ഉപയോഗികàµà´•à´¾à´¨à´¿à´Ÿà´¯àµà´³àµà´³
മറàµà´±àµ നെറàµà´±àµâ€Œà´µàµ¼à´•àµà´•àµ ഉപകരണങàµà´™àµ¾ à´Žà´¨àµà´¨à´¿à´µ റീബൂടàµà´Ÿàµ ചെയàµà´¯àµà´•.</translation>
<translation id="614940544461990577">പരീകàµà´·à´¿à´šàµà´šàµà´¨àµ‹à´•àµà´•àµ‚:</translation>
@@ -1618,7 +1658,6 @@
<translation id="6169916984152623906">നിങàµà´™àµ¾à´•àµà´•à´¿à´ªàµà´ªàµ‹àµ¾ à´¸àµà´µà´•à´¾à´°àµà´¯à´®à´¾à´¯à´¿ à´¬àµà´°àµ—സൠചെയàµà´¯à´¾à´‚, à´ˆ ഉപകരണം ഉപയോഗികàµà´•àµà´¨àµà´¨ മറàµà´±àµ ആളàµà´•àµ¾à´•àµà´•àµ നിങàµà´™à´³àµà´Ÿàµ† ആകàµâ€Œà´±àµà´±à´¿à´µà´¿à´±àµà´±à´¿ കാണാനാവിലàµà´². à´Žà´¨àµà´¨à´¾àµ½ ഡൗൺലോഡàµà´•à´³àµà´‚ à´¬àµà´•àµà´•àµâ€Œà´®à´¾àµ¼à´•àµà´•àµà´•à´³àµà´‚ സംരകàµà´·à´¿à´•àµà´•à´ªàµà´ªàµ†à´Ÿàµà´‚.</translation>
<translation id="6177128806592000436">à´ˆ സൈറàµà´±à´¿à´²àµ‡à´•àµà´•àµà´³àµà´³ നിങàµà´™à´³àµà´Ÿàµ† കണകàµà´·àµ» à´¸àµà´°à´•àµà´·à´¿à´¤à´®à´²àµà´²</translation>
<translation id="6180316780098470077">വീണàµà´Ÿàµà´‚ à´¶àµà´°à´®à´¿à´•àµà´•àµà´¨àµà´¨à´¤à´¿à´¨àµà´³àµà´³ ഇടവേള</translation>
-<translation id="619448280891863779">നിങàµà´™à´³àµà´Ÿàµ† à´¸àµà´•àµà´°àµ€à´¨àµà´•à´³à´¿àµ½ വിൻഡോകൾ à´¤àµà´±à´¨àµà´¨àµ വയàµà´•àµà´•à´¾àµ» ആവശàµà´¯à´ªàµà´ªàµ†à´Ÿà´¾à´‚</translation>
<translation id="6196640612572343990">മൂനàµà´¨à´¾à´‚ à´•à´•àµà´·à´¿ à´•àµà´•àµà´•à´¿à´•à´³àµâ€ à´¬àµà´²àµ‹à´•àµà´•àµà´šàµ†à´¯àµà´¯àµà´•</translation>
<translation id="6203231073485539293">നിങàµà´™à´³àµà´Ÿàµ† ഇനàµà´±àµ¼à´¨àµ†à´±àµà´±àµ കണകàµà´·àµ» പരിശോധികàµà´•àµà´•</translation>
<translation id="6218753634732582820">Chromium-à´¤àµà´¤à´¿àµ½ നിനàµà´¨àµ വിലാസം നീകàµà´•à´‚ചെയàµà´¯à´£àµ‹?</translation>
@@ -1641,7 +1680,7 @@
<translation id="6272383483618007430">Google à´…à´ªàµà´¡àµ‡à´±àµà´±àµ</translation>
<translation id="6276112860590028508">നിങàµà´™à´³àµà´Ÿàµ† വായന പടàµà´Ÿà´¿à´•à´¯à´¿àµ½ നിനàµà´¨àµà´³àµà´³ പേജàµà´•àµ¾ ഇവിടെ ദൃശൃമാകàµà´‚</translation>
<translation id="627746635834430766">à´…à´Ÿàµà´¤àµà´¤ à´ªàµà´°à´¾à´µà´¶àµà´¯à´‚ വേഗതàµà´¤à´¿àµ½ പണമടയàµà´•àµà´•à´¾àµ», നിങàµà´™à´³àµà´Ÿàµ† Google à´…à´•àµà´•àµ—à´£àµà´Ÿà´¿àµ½ à´ˆ കാർഡàµà´‚ ബിലàµà´²à´¿à´‚ഗൠവിലാസവàµà´‚ സംരകàµà´·à´¿à´•àµà´•àµà´•.</translation>
-<translation id="6279098320682980337">വെർചàµà´µàµ½ കാർഡൠനമàµà´ªàµ¼ പൂരിപàµà´ªà´¿à´šàµà´šà´¿à´Ÿàµà´Ÿà´¿à´²àµà´²àµ‡? പകർതàµà´¤à´¾àµ» കാർഡൠവിശദാംശങàµà´™àµ¾ à´•àµà´²à´¿à´•àµà´•àµ ചെയàµà´¯àµà´•</translation>
+<translation id="6279183038361895380">നിങàµà´™à´³àµà´Ÿàµ† à´•à´´àµâ€Œà´¸àµ¼ കാണികàµà´•à´¾àµ» |<ph name="ACCELERATOR" />| അമർതàµà´¤àµà´•</translation>
<translation id="6280223929691119688">à´ˆ വിലാസതàµà´¤à´¿à´²àµ‡à´•àµà´•àµ ഡെലിവറി ചെയàµà´¯à´¾àµ» കഴിയിലàµà´². മറàµà´±àµŠà´°àµ വിലാസം തിരഞàµà´žàµ†à´Ÿàµà´•àµà´•àµà´•.</translation>
<translation id="6282194474023008486">തപാലàµâ€ കോഡàµ</translation>
<translation id="6285507000506177184">'Chrome-ൽ ഡൗൺലോഡàµà´•àµ¾ മാനേജൠചെയàµà´¯àµà´•' ബടàµà´Ÿàµº, Chrome-ൽ നിങàµà´™àµ¾ ഡൗൺലോഡൠചെയàµà´¤à´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨ ഫയലàµà´•àµ¾ മാനേജൠചെയàµà´¯à´¾àµ» Enter അമർതàµà´¤àµà´•</translation>
@@ -1649,6 +1688,7 @@
<translation id="6290238015253830360">നിങàµà´™à´³àµà´Ÿàµ† നിർദàµà´¦àµ‡à´¶à´¿à´šàµà´š ലേഖനങàµà´™àµ¾ ഇവിടെ ദൃശàµà´¯à´®à´¾à´•àµà´‚</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{നിങàµà´™à´³àµà´Ÿàµ† ഉപകരണം ഇപàµà´ªàµ‹àµ¾ റീസàµà´±àµà´±à´¾àµ¼à´Ÿàµà´Ÿàµ ചെയàµà´¯àµà´‚}=1{നിങàµà´™à´³àµà´Ÿàµ† ഉപകരണം 1 സെകàµà´•àµ»à´¡à´¿àµ½ റീസàµà´±àµà´±à´¾àµ¼à´Ÿàµà´Ÿàµ ചെയàµà´¯àµà´‚}other{നിങàµà´™à´³àµà´Ÿàµ† ഉപകരണം # സെകàµà´•àµ»à´¡à´¿àµ½ റീസàµà´±àµà´±à´¾àµ¼à´Ÿàµà´Ÿàµ ചെയàµà´¯àµà´‚}}</translation>
<translation id="6302269476990306341">Chrome à´¸àµà´µà´®àµ‡à´§à´¯à´¾ പൂരിപàµà´ªà´¿à´•àµà´•àµ½ നിർതàµà´¤àµà´¨àµà´¨à´¤à´¿à´²àµ† Google അസിസàµâ€Œà´±àµà´±à´¨àµà´±àµ സാനàµà´¨à´¿à´§àµà´¯à´‚</translation>
<translation id="6305205051461490394"><ph name="URL" /> ലഭàµà´¯à´®à´²àµà´².</translation>
<translation id="6312113039770857350">വെബàµà´ªàµ‡à´œàµ ലഭàµà´¯à´®à´²àµà´²</translation>
@@ -1722,6 +1762,7 @@
<translation id="6529602333819889595">&amp;ഇലàµà´²à´¾à´¤à´¾à´•àµà´•àµà´¨àµà´¨à´¤àµ വീണàµà´Ÿàµà´‚ ചെയàµà´¯àµà´•</translation>
<translation id="6545864417968258051">Bluetooth à´¸àµâ€Œà´•à´¾à´¨à´¿à´‚à´—àµ</translation>
<translation id="6547208576736763147">ഇടതàµà´µà´¶à´¤àµà´¤àµ ഇരടàµà´Ÿ പഞàµà´šàµ ചെയàµà´¯àµà´•</translation>
+<translation id="6554732001434021288">അവസാനം സനàµà´¦àµ¼à´¶à´¿à´šàµà´šà´¤àµ <ph name="NUM_DAYS" /> ദിവസം à´®àµà´®àµà´ªà´¾à´¯à´¿à´°àµà´¨àµà´¨àµ</translation>
<translation id="6556866813142980365">വീണàµà´Ÿàµà´‚ ചെയàµà´¯àµà´•</translation>
<translation id="6569060085658103619">നിങàµà´™àµ¾ ഒരൠവിപàµà´²àµ€à´•à´°à´£ പേജാണൠകാണàµà´¨àµà´¨à´¤àµ</translation>
<translation id="6573200754375280815">വലതàµà´µà´¶à´¤àµà´¤àµ ഇരടàµà´Ÿ പഞàµà´šàµ ചെയàµà´¯àµà´•</translation>
@@ -1782,7 +1823,6 @@
<translation id="6757797048963528358">നിങàµà´™à´³àµà´Ÿàµ† ഉപകരണം à´¸àµà´²àµ€à´ªàµà´ªàµ മോഡിലായി</translation>
<translation id="6767985426384634228">വിലാസം à´…à´ªàµà´¡àµ‡à´±àµà´±àµ ചെയàµà´¯à´£àµ‹?</translation>
<translation id="6768213884286397650">ഹഗാകàµà´•à´¿ (പോസàµâ€Œà´±àµà´±àµâ€Œà´•à´¾àµ¼à´¡àµ)</translation>
-<translation id="6774185088257932239">അദൃശàµà´¯ മോഡിനെ à´•àµà´±à´¿à´šàµà´šàµ <ph name="BEGIN_LINK" />കൂടàµà´¤à´²à´±à´¿à´¯àµà´•<ph name="END_LINK" /></translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">വയലറàµà´±àµ</translation>
<translation id="6786747875388722282">വിപàµà´²àµ€à´•à´°à´£à´™àµà´™à´³àµâ€</translation>
@@ -1866,7 +1906,6 @@
<translation id="706295145388601875">Chrome à´•àµà´°à´®àµ€à´•à´°à´£à´¤àµà´¤à´¿àµ½ വിലാസങàµà´™àµ¾ ചേർകàµà´•àµà´•, മാനേജൠചെയàµà´¯àµà´•</translation>
<translation id="7064851114919012435">കോണàµâ€à´Ÿà´¾à´•àµà´±àµà´±àµ വിവരം</translation>
<translation id="7068733155164172741"><ph name="OTP_LENGTH" />-à´…à´•àµà´• കോഡൠനൽകàµà´•</translation>
-<translation id="7070090581017165256">à´ˆ സൈറàµà´±à´¿à´¨àµ† à´•àµà´±à´¿à´šàµà´šàµ</translation>
<translation id="70705239631109039">നിങàµà´™à´³àµà´Ÿàµ† കണകàµà´·àµ» പൂർണàµà´£à´®à´¾à´¯àµà´‚ à´¸àµà´°à´•àµà´·à´¿à´¤à´®à´²àµà´²</translation>
<translation id="7075452647191940183">à´…à´­àµà´¯àµ¼à´¤àµà´¥à´¨ വളരെ വലàµà´¤à´¾à´£àµ</translation>
<translation id="7079718277001814089">à´ˆ സൈറàµà´±à´¿àµ½ മാൽവെയർ à´…à´Ÿà´™àµà´™à´¿à´¯à´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨àµ</translation>
@@ -1883,6 +1922,12 @@
<translation id="7111012039238467737">(സാധàµà´¤à´¯àµà´³àµà´³à´¤àµ)</translation>
<translation id="7118618213916969306">à´•àµà´²à´¿à´ªàµà´ªàµà´¬àµ‹àµ¼à´¡àµ URL-à´¨àµà´³àµà´³ തിരയൽ, <ph name="SHORT_URL" /></translation>
<translation id="7119414471315195487">മറàµà´±àµ ടാബàµà´•à´³àµ‹ à´ªàµà´°àµ‹à´—àµà´°à´¾à´®àµà´•à´³àµ‹ à´…à´Ÿà´¯àµâ€Œà´•àµà´•àµà´•</translation>
+<translation id="7129355289156517987">Chromium-à´²àµà´³àµà´³ à´®àµà´´àµà´µàµ» അദൃശàµà´¯ ടാബàµà´•à´³àµà´‚ നിങàµà´™àµ¾ à´…à´Ÿà´¯àµà´•àµà´•àµà´®àµà´ªàµ‹àµ¾ à´† ടാബàµà´•à´³à´¿à´²àµ† നിങàµà´™à´³àµà´Ÿàµ† ആകàµà´±àµà´±à´¿à´µà´¿à´±àµà´±à´¿ à´ˆ ഉപകരണതàµà´¤à´¿àµ½ നിനàµà´¨àµ മായàµà´•àµà´•àµà´¨àµà´¨àµ:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />à´¬àµà´°àµ—സിംഗൠആകàµà´±àµà´±à´¿à´µà´¿à´±àµà´±à´¿<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />തിരയൽ à´šà´°à´¿à´¤àµà´°à´‚<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ഫോമàµà´•à´³à´¿àµ½ നൽകàµà´¨àµà´¨ വിവരങàµà´™àµ¾<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">à´ˆ വിലാസതàµà´¤à´¿à´²àµ‡à´•àµà´•àµ à´·à´¿à´ªàµà´ªàµ ചെയàµà´¯à´¾àµ» കഴിയിലàµà´². മറàµà´±àµŠà´°àµ വിലാസം തിരഞàµà´žàµ†à´Ÿàµà´•àµà´•àµà´•.</translation>
<translation id="7132939140423847331">à´ˆ ഡാറàµà´± പകർതàµà´¤àµà´¨àµà´¨à´¤àµ നിങàµà´™à´³àµà´Ÿàµ† à´…à´¡àµâ€Œà´®à´¿àµ» നിരോധിചàµà´šà´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨àµ.</translation>
<translation id="7135130955892390533">à´¸àµâ€Œà´±àµà´±à´¾à´±àµà´±à´¸àµ കാണികàµà´•àµà´•</translation>
@@ -1905,6 +1950,7 @@
<translation id="7192203810768312527"><ph name="SIZE" /> ലാഭികàµà´•àµà´•. നിങàµà´™à´³àµà´Ÿàµ† à´…à´Ÿàµà´¤àµà´¤ സനàµà´¦àµ¼à´¶à´¨à´¤àµà´¤à´¿àµ½ à´šà´¿à´² സൈറàµà´±àµà´•àµ¾ സാവധാനതàµà´¤à´¿àµ½ ലോഡായേകàµà´•à´¾à´‚.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">നിങàµà´™à´³àµà´Ÿàµ† à´…à´¡àµâ€Œà´®à´¿à´¨à´¿à´¸àµâ€Œà´Ÿàµà´°àµ‡à´±àµà´±àµ¼à´•àµà´•àµ ഇവ കാണാനാകàµà´‚:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, à´¸àµà´µà´•à´¾à´°àµà´¯à´®à´¾à´¯à´¿ à´¬àµà´°àµ—സൠചെയàµà´¯à´¾àµ» à´ªàµà´¤à´¿à´¯ അദൃശàµà´¯ ടാബൠതàµà´±à´•àµà´•àµà´¨àµà´¨à´¤à´¿à´¨àµ 'Tab' അമർതàµà´¤àµà´•, à´¤àµà´Ÿàµ¼à´¨àµà´¨àµ 'Enter' അമർതàµà´¤àµà´•</translation>
<translation id="7202346780273620635">ലെറàµà´±àµ¼-അധികം</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" />, à´¸àµà´°à´•àµà´·à´¾ മാനദണàµà´¡à´™àµà´™àµ¾ പാലികàµà´•àµà´¨àµà´¨à´¿à´²àµà´².</translation>
<translation id="7210993021468939304">à´•à´£àµà´Ÿàµ†à´¯àµâ€Œà´¨à´±à´¿à´¨àµà´³àµà´³à´¿à´²àµ† Linux ആകàµâ€Œà´±àµà´±à´¿à´µà´¿à´±àµà´±à´¿, കൂടാതെ à´•à´£àµà´Ÿàµ†à´¯àµâ€Œà´¨à´±à´¿à´¨àµà´³àµà´³à´¿àµ½ Linux ആപàµà´ªàµà´•àµ¾ ഇൻസàµâ€Œà´±àµà´±à´¾àµ¾ ചെയàµà´¯à´¾à´¨àµà´‚ റൺ ചെയàµà´¯à´¾à´¨àµà´‚ à´•à´´à´¿à´¯àµà´‚</translation>
@@ -1936,6 +1982,7 @@
<translation id="7304562222803846232">Google à´…à´•àµà´•àµ—à´£àµà´Ÿàµ à´¸àµà´µà´•à´¾à´°àµà´¯à´¤à´¾ à´•àµà´°à´®àµ€à´•à´°à´£à´‚ മാനേജൠചെയàµà´¯àµà´•</translation>
<translation id="7305756307268530424">à´•àµà´±à´žàµà´ž വേഗതയിൽ ആരംഭികàµà´•àµà´•</translation>
<translation id="7308436126008021607">പശàµà´šà´¾à´¤àµà´¤à´²à´‚ സമനàµà´µà´¯à´¿à´ªàµà´ªà´¿à´•àµà´•àµ½</translation>
+<translation id="7310392214323165548">ഉപകരണം ഉടൻ റീസàµà´±àµà´±à´¾àµ¼à´Ÿàµà´Ÿàµ ചെയàµà´¯àµà´‚</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">കണകàµà´·àµ» സഹായം</translation>
<translation id="7323804146520582233">"<ph name="SECTION" />" വിഭാഗം മറയàµà´•àµà´•àµà´•</translation>
@@ -1943,6 +1990,7 @@
<translation id="7334320624316649418">&amp;à´ªàµà´¨à´ƒà´•àµà´°à´®àµ€à´•à´°à´¿à´•àµà´•àµà´¨àµà´¨à´¤àµ വീണàµà´Ÿàµà´‚ ചെയàµà´¯àµà´•</translation>
<translation id="7335157162773372339">നിങàµà´™à´³àµà´Ÿàµ† à´•àµà´¯à´¾à´®à´± ഉപയോഗികàµà´•à´¾àµ» ആവശàµà´¯à´ªàµà´ªàµ†à´Ÿà´¾à´‚</translation>
<translation id="7337248890521463931">കൂടàµà´¤àµ½ വരികൾ കാണികàµà´•àµà´•</translation>
+<translation id="7337418456231055214">വെർചàµà´µàµ½ കാർഡൠനമàµà´ªàµ¼ പൂരിപàµà´ªà´¿à´šàµà´šà´¿à´Ÿàµà´Ÿà´¿à´²àµà´²àµ‡? പകർതàµà´¤à´¾àµ» കാർഡൠവിശദാംശങàµà´™àµ¾ à´•àµà´²à´¿à´•àµà´•àµ ചെയàµà´¯àµà´•. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">നിങàµà´™à´³àµà´Ÿàµ† à´ªàµà´²à´¾à´±àµà´±àµâ€Œà´«àµ‹à´®à´¿àµ½ ലഭàµà´¯à´®à´²àµà´².</translation>
<translation id="733923710415886693">സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ à´¸àµà´¤à´¾à´°àµà´¯à´¤à´¯à´¿à´²àµ‚ടെ സെർവറàµà´Ÿàµ† സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµ വെളിപàµà´ªàµ†à´Ÿàµà´¤àµà´¤à´¿à´¯à´¿à´Ÿàµà´Ÿà´¿à´²àµà´².</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1965,6 +2013,7 @@
<translation id="7378627244592794276">വേണàµà´Ÿ</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">ബാധകമലàµà´²</translation>
+<translation id="7388594495505979117">{0,plural, =1{നിങàµà´™à´³àµà´Ÿàµ† ഉപകരണം 1 മിനിറàµà´±à´¿àµ½ റീസàµà´±àµà´±à´¾àµ¼à´Ÿàµà´Ÿàµ ചെയàµà´¯àµà´‚}other{നിങàµà´™à´³àµà´Ÿàµ† ഉപകരണം # മിനിറàµà´±à´¿àµ½ റീസàµà´±àµà´±à´¾àµ¼à´Ÿàµà´Ÿàµ ചെയàµà´¯àµà´‚}}</translation>
<translation id="7390545607259442187">കാർഡൠസàµà´¥à´¿à´°àµ€à´•à´°à´¿à´•àµà´•àµà´•</translation>
<translation id="7392089738299859607">വിലാസം à´…à´ªàµà´¡àµ‡à´±àµà´±àµ ചെയàµà´¯àµà´•</translation>
<translation id="7399802613464275309">à´¸àµà´°à´•àµà´·à´¾ പരിശോധന</translation>
@@ -1999,6 +2048,12 @@
<translation id="7485870689360869515">ഡാറàµà´±à´•à´³àµŠà´¨àµà´¨àµà´‚ à´•à´£àµà´Ÿàµ†à´¤àµà´¤à´¿à´¯à´¿à´²àµà´².</translation>
<translation id="7495528107193238112">à´ˆ ഉളàµà´³à´Ÿà´•àµà´•à´‚ à´¬àµà´²àµ‹à´•àµà´•àµ ചെയàµâ€Œà´¤à´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨àµ. à´ªàµà´°à´¶àµâ€Œà´¨à´‚ പരിഹരികàµà´•à´¾àµ» സൈറàµà´±à´¿à´¨àµà´±àµ† ഉടമയàµà´®à´¾à´¯à´¿ ബനàµà´§à´ªàµà´ªàµ†à´Ÿàµà´•.</translation>
<translation id="7497998058912824456">'ഡോകൠസൃഷàµà´Ÿà´¿à´•àµà´•àµà´•' ബടàµà´Ÿàµº, à´ªàµà´¤à´¿à´¯àµŠà´°àµ Google ഡോകൠവേഗതàµà´¤à´¿àµ½ സൃഷàµà´Ÿà´¿à´•àµà´•à´¾àµ» Enter അമർതàµà´¤àµà´•</translation>
+<translation id="7506488012654002225">ഇനിപàµà´ªà´±à´¯àµà´¨àµà´¨ വിവരങàµà´™àµ¾ Chromium <ph name="BEGIN_EMPHASIS" />സംരകàµà´·à´¿à´•àµà´•à´¿à´²àµà´²<ph name="END_EMPHASIS" />:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />നിങàµà´™à´³àµà´Ÿàµ† à´¬àµà´°àµ—സിംഗൠചരിതàµà´°à´‚
+ <ph name="LIST_ITEM" />à´•àµà´•àµà´•à´¿à´•à´³àµà´‚ സൈറàµà´±àµ ഡാറàµà´±à´¯àµà´‚
+ <ph name="LIST_ITEM" />ഫോമàµà´•à´³à´¿àµ½ നൽകàµà´¨àµà´¨ വിവരങàµà´™àµ¾
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">നൽകിയ നയ ഉപകരണ à´à´¡à´¿ ശൂനàµà´¯à´®à´¾à´£àµ à´…à´²àµà´²àµ†à´™àµà´•à´¿àµ½ നിലവിലെ ഉപകരണ à´à´¡à´¿à´¯àµà´®à´¾à´¯à´¿ യോജികàµà´•àµà´¨àµà´¨à´¿à´²àµà´²</translation>
<translation id="7508870219247277067">അവകàµà´•à´¾à´¡àµ‹ പചàµà´š</translation>
<translation id="7511955381719512146">നിങàµà´™àµ¾ ഉപയോഗികàµà´•àµà´¨àµà´¨ Wi-Fi <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> സനàµà´¦àµ¼à´¶à´¿à´•àµà´•à´¾àµ» നിങàµà´™à´³àµ‹à´Ÿàµ ആവശàµà´¯à´ªàµà´ªàµ†à´Ÿà´¾à´‚.</translation>
@@ -2112,7 +2167,6 @@
<translation id="7813600968533626083">Chrome-ൽ നിനàµà´¨àµà´³àµà´³ നിർദàµà´¦àµ‡à´¶à´‚ നീകàµà´•à´‚ചെയàµà´¯à´£àµ‹?</translation>
<translation id="781440967107097262">à´•àµà´²à´¿à´ªàµà´ªàµà´¬àµ‹àµ¼à´¡àµ പങàµà´•à´¿à´Ÿà´£àµ‹?</translation>
<translation id="7815407501681723534">'<ph name="SEARCH_STRING" />' à´Žà´¨àµà´¨à´¤à´¿à´¨àµà´±àµ† <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> à´•à´£àµà´Ÿàµ</translation>
-<translation id="782125616001965242">à´ˆ സൈറàµà´±à´¿à´¨àµ† à´•àµà´±à´¿à´šàµà´šàµà´³àµà´³ വിവരങàµà´™àµ¾ കാണികàµà´•àµà´•</translation>
<translation id="782886543891417279">നിങàµà´™àµ¾ ഉപയോഗികàµà´•àµà´¨àµà´¨ Wi-Fi (<ph name="WIFI_NAME" />) അതിനàµà´±àµ† ലോഗിൻ പേജൠസനàµà´¦àµ¼à´¶à´¿à´•àµà´•à´¾àµ» ആവശàµà´¯à´ªàµà´ªàµ†à´Ÿà´¾à´‚.</translation>
<translation id="7836231406687464395">പോസàµâ€Œà´±àµà´±àµà´«à´¿à´•àµâ€Œà´¸àµ (എൻവലപàµà´ªàµ)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{à´’à´¨àµà´¨àµà´®à´¿à´²àµà´²}=1{ഒരൠആപàµà´ªàµ (<ph name="EXAMPLE_APP_1" />)}=2{2 ആപàµà´ªàµà´•àµ¾ (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}other{# ആപàµà´ªàµà´•àµ¾ (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}}</translation>
@@ -2129,7 +2183,6 @@
<translation id="7888575728750733395">à´ªàµà´°à´¿à´¨àµà´±àµ റെൻഡറിംഗൠഇനàµà´±à´¨àµà´±àµ</translation>
<translation id="7894280532028510793">à´…à´•àµà´·à´°à´™àµà´™àµ¾ ശരിയാണെങàµà´•à´¿àµ½ <ph name="BEGIN_LINK" /> നെറàµà´±àµâ€Œà´µàµ¼à´•àµà´•àµ ഡയഗണോസàµâ€Œà´±àµà´±à´¿à´•àµâ€Œà´¸àµ റൺ ചെയàµâ€Œà´¤àµà´¨àµ‹à´•àµà´•àµ‚<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (എൻവലപàµà´ªàµ)</translation>
-<translation id="7931318309563332511">അറിഞàµà´žàµà´•àµ‚ടാതàµà´¤à´¤àµ</translation>
<translation id="793209273132572360">വിലാസം à´…à´ªàµà´¡àµ‡à´±àµà´±àµ ചെയàµà´¯à´£àµ‹?</translation>
<translation id="7932579305932748336">കോടàµà´Ÿàµ</translation>
<translation id="79338296614623784">ശരിയായ ഒരൠഫോൺ നമàµà´ªàµ¼ നൽകàµà´•</translation>
@@ -2154,13 +2207,14 @@
<translation id="7976214039405368314">നിരവധി à´…à´­àµà´¯àµ¼à´¤àµà´¥à´¨à´•àµ¾</translation>
<translation id="7977538094055660992">ഔടàµà´Ÿàµà´ªàµà´Ÿàµà´Ÿàµ ഉപകരണം</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">ഇതàµà´®à´¾à´¯à´¿ ലിങàµà´•àµ ചെയàµâ€Œà´¤àµ</translation>
<translation id="798134797138789862">വെർചàµà´µàµ½ റിയാലിറàµà´±à´¿ ഉപകരണങàµà´™à´³àµà´‚ ഡാറàµà´±à´¯àµà´‚ ഉപയോഗികàµà´•à´¾àµ» ആവശàµà´¯à´ªàµà´ªàµ†à´Ÿà´¾à´‚</translation>
<translation id="7984945080620862648">Chrome-നൠപàµà´°àµ‹à´¸à´¸àµà´¸àµà´šàµ†à´¯àµà´¯à´¾à´¨à´¾à´•à´¾à´¤àµà´¤ രൂപമാറàµà´±à´‚ വരàµà´¤àµà´¤à´¿à´¯ à´•àµà´°àµ†à´¡àµ»à´·àµà´¯à´²àµà´•àµ¾ വെബàµà´¸àµˆà´±àµà´±àµ അയയàµà´•àµà´•àµà´¨àµà´¨à´¤à´¿à´¨à´¾àµ½ നിങàµà´™àµ¾à´•àµà´•à´¿à´ªàµà´ªàµ‹àµ¾ <ph name="SITE" /> സനàµà´¦àµ¼à´¶à´¿à´•àµà´•à´¾à´¨à´¾à´•à´¿à´²àµà´².നെറàµà´±àµâ€Œà´µàµ¼à´•àµà´•àµ പിശകàµà´•à´³àµà´‚ ആകàµà´°à´®à´£à´™àµà´™à´³àµà´‚ സാധാരണയായി താൽകàµà´•à´¾à´²à´¿à´•à´®à´¾à´¯à´¤à´¿à´¨à´¾àµ½ à´ˆ പേജൠമികàµà´•à´µà´¾à´±àµà´‚ പിനàµà´¨àµ€à´Ÿàµ à´ªàµà´°à´µàµ¼à´¤àµà´¤à´¿à´•àµà´•àµà´‚.</translation>
-<translation id="79859296434321399">à´…à´¨àµà´¬à´¨àµà´§ യാഥാർതàµà´¥àµà´¯ ഉളàµà´³à´Ÿà´•àµà´•à´‚ കാണാൻ, ARCore ഇൻസàµâ€Œà´±àµà´±à´¾àµ¾ ചെയàµà´¯àµ‚</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">ബൈൻഡൠചെയàµà´¯àµà´•</translation>
<translation id="7992044431894087211"><ph name="APPLICATION_TITLE" /> à´Žà´¨àµà´¨à´¤àµà´®à´¾à´¯à´¿ à´¸àµà´•àµà´°àµ€àµ» പങàµà´•à´¿à´Ÿàµ½ à´ªàµà´¨à´°à´¾à´°à´‚à´­à´¿à´šàµà´šàµ</translation>
<translation id="7995512525968007366">à´µàµà´¯à´•àµà´¤à´®à´¾à´•àµà´•à´¿à´¯à´¿à´Ÿàµà´Ÿà´¿à´²àµà´²</translation>
+<translation id="7998269595945679889">'അദൃശàµà´¯ ടാബൠതàµà´±à´•àµà´•àµà´•' ബടàµà´Ÿàµº, à´¸àµà´µà´•à´¾à´°àµà´¯à´®à´¾à´¯à´¿ à´¬àµà´°àµ—സൠചെയàµà´¯à´¾àµ» à´ªàµà´¤à´¿à´¯ അദൃശàµà´¯ ടാബൠതàµà´±à´•àµà´•à´¾àµ» 'Enter' അമർതàµà´¤àµà´•</translation>
<translation id="800218591365569300">ഇടം സൃഷàµâ€Œà´Ÿà´¿à´•àµà´•à´¾àµ» മറàµà´±àµ ടാബàµà´•à´³àµ‹ à´ªàµà´°àµ‹à´—àµà´°à´¾à´®àµà´•à´³àµ‹ à´…à´Ÿà´¯àµâ€Œà´•àµà´•àµà´¨àµà´¨à´¤àµ പരീകàµà´·à´¿à´•àµà´•àµ‚.</translation>
<translation id="8004582292198964060">à´¬àµà´°àµ—സരàµâ€</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{à´ˆ കാർഡàµà´‚ അവയàµà´Ÿàµ† ബിലàµà´²à´¿à´‚ഗൠവിലാസവàµà´‚ സംരകàµà´·à´¿à´•àµà´•à´ªàµà´ªàµ†à´Ÿàµà´‚. നിങàµà´™àµ¾ <ph name="USER_EMAIL" /> à´Žà´¨àµà´¨à´¤à´¿à´²àµ‡à´•àµà´•àµ സൈൻ ഇൻ ചെയàµâ€Œà´¤à´¿à´°à´¿à´•àµà´•àµà´®àµà´ªàµ‹àµ¾ അതൠഉപയോഗികàµà´•à´¾à´¨à´¾à´•àµà´‚.}other{à´ˆ കാർഡàµà´•à´³àµà´‚ അവയàµà´Ÿàµ† ബിലàµà´²à´¿à´‚ഗൠവിലാസങàµà´™à´³àµà´‚ സംരകàµà´·à´¿à´•àµà´•à´ªàµà´ªàµ†à´Ÿàµà´‚. നിങàµà´™àµ¾ <ph name="USER_EMAIL" /> à´Žà´¨àµà´¨à´¤à´¿à´²àµ‡à´•àµà´•àµ സൈൻ ഇൻ ചെയàµâ€Œà´¤à´¿à´°à´¿à´•àµà´•àµà´®àµà´ªàµ‹àµ¾ à´…à´µ ഉപയോഗികàµà´•à´¾à´¨à´¾à´•àµà´‚.}}</translation>
@@ -2220,6 +2274,7 @@
<translation id="8202370299023114387">പൊരàµà´¤àµà´¤à´•àµà´•àµ‡à´Ÿàµ</translation>
<translation id="8206978196348664717">Prc4 (എൻവലപàµà´ªàµ)</translation>
<translation id="8211406090763984747">കണകàµà´·àµ» à´¸àµà´°à´•àµà´·à´¿à´¤à´®à´¾à´£àµ</translation>
+<translation id="8217240300496046857">വെബിലàµà´Ÿà´¨àµ€à´³à´‚ നിങàµà´™à´³àµ† à´Ÿàµà´°à´¾à´•àµà´•àµ ചെയàµà´¯àµà´¨àµà´¨ à´•àµà´•àµà´•à´¿à´•àµ¾ ഉപയോഗികàµà´•à´¾àµ» സെെറàµà´±àµà´•àµ¾à´•àµà´•à´¾à´•à´¿à´²àµà´². à´šà´¿à´² സൈറàµà´±àµà´•à´³à´¿à´²àµ† ഫീചàµà´šà´±àµà´•à´³àµà´Ÿàµ† à´ªàµà´°à´µàµ¼à´¤àµà´¤à´¨à´‚ തടസàµà´¸à´ªàµà´ªàµ†à´Ÿàµà´Ÿàµ‡à´•àµà´•à´¾à´‚.</translation>
<translation id="8218327578424803826">നൽകിയിരികàµà´•àµà´¨àµà´¨ ലൊകàµà´•àµ‡à´·àµ»:</translation>
<translation id="8220146938470311105">C7/C6 (എൻവലപàµà´ªàµ)</translation>
<translation id="8225771182978767009">à´ˆ à´•à´®àµà´ªàµà´¯àµ‚à´Ÿàµà´Ÿàµ¼ സജàµà´œà´®à´¾à´•àµà´•à´¿à´¯ à´µàµà´¯à´•àµà´¤à´¿, à´ˆ സൈറàµà´±àµ à´¬àµà´²àµ‹à´•àµà´•àµ ചെയàµà´¯à´¾àµ» തീരàµà´®à´¾à´¨à´¿à´šàµà´šà´¿à´°àµà´¨àµà´¨àµ.</translation>
@@ -2260,14 +2315,9 @@
<translation id="830498451218851433">പകàµà´¤à´¿à´¯à´¾à´¯à´¿ മടകàµà´•àµà´•</translation>
<translation id="8307358339886459768">ചെറിയ-ഫോടàµà´Ÿàµ‹</translation>
<translation id="8307888238279532626">ആപàµà´ªàµà´•àµ¾ ഇൻസàµâ€Œà´±àµà´±à´¾àµ¾ ചെയàµà´¤à´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨àµ, à´…à´µ à´Žà´¤àµà´° തവണ ഉപയോഗികàµà´•àµà´¨àµà´¨àµ</translation>
+<translation id="8317207217658302555">ARCore à´…à´ªàµà´¡àµ‡à´±àµà´±àµ ചെയàµà´¯à´£àµ‹?</translation>
<translation id="831997045666694187">വൈകàµà´¨àµà´¨àµ‡à´°à´‚</translation>
<translation id="8321476692217554900">അറിയിപàµà´ªàµà´•àµ¾</translation>
-<translation id="8328484624016508118">à´Žà´²àµà´²à´¾ അദൃശàµà´¯ ടാബàµà´•à´³àµà´‚ à´…à´Ÿà´šàµà´šà´¤à´¿à´¨àµà´¶àµ‡à´·à´‚, Chrome ഇവ മായàµà´•àµà´•àµà´¨àµà´¨àµ:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />à´ˆ ഉപകരണതàµà´¤à´¿àµ½ നിനàµà´¨àµà´³àµà´³ നിങàµà´™à´³àµà´Ÿàµ† à´¬àµà´°àµ—സിംഗൠആകàµà´±àµà´±à´¿à´µà´¿à´±àµà´±à´¿<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />à´ˆ ഉപകരണതàµà´¤à´¿àµ½ നിനàµà´¨àµà´³àµà´³ നിങàµà´™à´³àµà´Ÿàµ† തിരയൽ à´šà´°à´¿à´¤àµà´°à´‚<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />ഫോമàµà´•à´³à´¿àµ½ നൽകിയ വിവരങàµà´™àµ¾<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489"><ph name="HOST_NAME" /> ഹോസàµâ€Œà´±àµà´±à´¿à´²àµ‡à´•àµà´•àµà´³àµà´³ ആകàµâ€Œà´¸à´¸àµ നിരസിചàµà´šàµ</translation>
<translation id="833262891116910667">ഹൈലൈറàµà´±àµ ചെയàµà´¯àµà´•</translation>
<translation id="8339163506404995330"><ph name="LANGUAGE" /> ഭാഷയിലàµà´³àµà´³ പേജàµà´•àµ¾ വിവർതàµà´¤à´¨à´‚ ചെയàµà´¯à´¿à´²àµà´²</translation>
@@ -2319,6 +2369,7 @@
<translation id="8507227106804027148">കമാനàµâ€à´¡àµ ലൈനàµâ€â€Œ</translation>
<translation id="8508648098325802031">തിരയൽ à´à´•àµà´•àµº</translation>
<translation id="8511402995811232419">à´•àµà´•àµà´•à´¿à´•àµ¾ മാനേജൠചെയàµà´¯àµà´•</translation>
+<translation id="8519753333133776369">നിങàµà´™à´³àµà´Ÿàµ† à´…à´¡àµâ€Œà´®à´¿àµ» à´…à´¨àµà´µà´¦à´¿à´šàµà´šà´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨ HID ഉപകരണം</translation>
<translation id="8522552481199248698">നിങàµà´™à´³àµà´Ÿàµ† Google à´…à´•àµà´•àµ—à´£àµà´Ÿàµ പരിരകàµà´·à´¿à´•àµà´•à´¾à´¨àµà´‚ പാസàµâ€Œà´µàµ‡à´¡àµ മാറàµà´±à´¾à´¨àµà´‚ Chrome സഹായികàµà´•àµà´‚.</translation>
<translation id="8530813470445476232">Chrome à´•àµà´°à´®àµ€à´•à´°à´£à´¤àµà´¤à´¿àµ½ നിങàµà´™à´³àµà´Ÿàµ† à´¬àµà´°àµ—സിംഗൠചരിതàµà´°à´µàµà´‚ à´•àµà´•àµà´•à´¿à´•à´³àµà´‚ കാഷെയàµà´‚ മറàµà´±àµà´‚ മായàµâ€Œà´•àµà´•àµà´•</translation>
<translation id="8533619373899488139">à´¬àµà´²àµ‹à´•àµà´•àµ ചെയàµà´¤ URL-à´•à´³àµà´Ÿàµ† ലിസàµà´±àµà´±àµà´‚ നിങàµà´™à´³àµà´Ÿàµ† സിസàµà´±àµà´±à´‚ à´…à´¡àµâ€Œà´®à´¿àµ» നടപàµà´ªà´¿à´²à´¾à´•àµà´•à´¿à´¯ മറàµà´±àµ നയങàµà´™à´³àµà´‚ കാണàµà´¨àµà´¨à´¤à´¿à´¨àµ &lt;strong&gt;chrome://policy&lt;/strong&gt; സനàµà´¦àµ¼à´¶à´¿à´•àµà´•àµà´•.</translation>
@@ -2330,7 +2381,6 @@
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{à´…à´¨àµà´®à´¤à´¿ റീസെറàµà´±àµ ചെയàµà´¯àµà´•}other{à´…à´¨àµà´®à´¤à´¿à´•àµ¾ റീസെറàµà´±àµ ചെയàµà´¯àµà´•}}</translation>
<translation id="8555010941760982128">ചെകàµà´•àµ—à´Ÿàµà´Ÿàµ ചെയàµà´¯àµà´®àµà´ªàµ‹àµ¾ à´ˆ കോഡൠഉപയോഗികàµà´•àµà´•</translation>
<translation id="8557066899867184262">കാർഡിനൠപിനàµà´¨à´¿à´²à´¾à´£àµ CVC രേഖപàµà´ªàµ†à´Ÿàµà´¤àµà´¤à´¿à´¯à´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨à´¤àµ.</translation>
-<translation id="8558485628462305855">à´…à´¨àµà´¬à´¨àµà´§ യാഥാർതàµà´¥àµà´¯ ഉളàµà´³à´Ÿà´•àµà´•à´‚ കാണാൻ, ARCore à´…à´ªàµâ€Œà´¡àµ‡à´±àµà´±àµ ചെയàµà´¯àµ‚</translation>
<translation id="8559762987265718583">നിങàµà´™à´³àµà´Ÿàµ† ഉപകരണതàµà´¤à´¿à´¨àµà´±àµ† തീയതിയàµà´‚ സമയവàµà´‚ (<ph name="DATE_AND_TIME" />) തെറàµà´±à´¾à´¯à´¤à´¿à´¨à´¾àµ½ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> à´Žà´¨àµà´¨à´¤à´¿à´²àµ‡à´•àµà´•àµà´³àµà´³ à´¸àµà´µà´•à´¾à´°àµà´¯ കണകàµà´·àµ» à´¸àµà´¥à´¾à´ªà´¿à´•àµà´•à´¾à´¨à´¾à´µà´¿à´²àµà´².</translation>
<translation id="8564182942834072828">വെവàµà´µàµ‡à´±àµ† ഡോകàµà´¯àµà´®àµ†à´¨àµà´±àµà´•àµ¾/à´•àµà´°à´®à´¤àµà´¤à´¿à´²à´²àµà´²à´¾à´¤àµà´¤ പകർപàµà´ªàµà´•àµ¾</translation>
<translation id="8564985650692024650">മറàµà´±àµ സൈറàµà´±àµà´•à´³à´¿àµ½ നിങàµà´™àµ¾ <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> പാസàµâ€Œà´µàµ‡à´¡àµ à´ªàµà´¨à´°àµà´ªà´¯àµ‹à´—à´¿à´šàµà´šà´¿à´Ÿàµà´Ÿàµà´£àµà´Ÿàµ†à´™àµà´•à´¿àµ½, അതൠറീസെറàµà´±àµ ചെയàµà´¯à´¾àµ» Chromium à´¶àµà´ªà´¾àµ¼â€Œà´¶ ചെയàµà´¯àµà´¨àµà´¨àµ.</translation>
@@ -2349,6 +2399,7 @@
<translation id="865032292777205197">മോഷൻ സെൻസറàµà´•àµ¾</translation>
<translation id="8663226718884576429">ഓർഡർ സംഗàµà´°à´¹à´‚, <ph name="TOTAL_LABEL" />, കൂടàµà´¤àµ½ വിശദാംശങàµà´™àµ¾</translation>
<translation id="8666678546361132282">ഇംഗàµà´²àµ€à´·àµ</translation>
+<translation id="8669306706049782872">വിൻഡോകൾ à´¤àµà´±à´¨àµà´¨àµ വയàµà´•àµà´•à´¾àµ» നിങàµà´™à´³àµà´Ÿàµ† à´¸àµà´•àµà´°àµ€à´¨àµà´•à´³àµà´Ÿàµ† വിവരങàµà´™àµ¾ ഉപയോഗികàµà´•àµà´•</translation>
<translation id="867224526087042813">à´’à´ªàµà´ªàµ</translation>
<translation id="8676424191133491403">കാലതാമസമിലàµà´²</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, ഉതàµà´¤à´°à´‚, <ph name="ANSWER" /></translation>
@@ -2375,6 +2426,7 @@
<translation id="8731544501227493793">'പാസàµâ€Œà´µàµ‡à´¡àµà´•àµ¾ മാനേജൠചെയàµà´¯àµà´•' ബടàµà´Ÿàµº, Chrome à´•àµà´°à´®àµ€à´•à´°à´£à´¤àµà´¤à´¿àµ½ നിങàµà´™à´³àµà´Ÿàµ† പാസàµâ€Œà´µàµ‡à´¡àµà´•àµ¾ കാണാനàµà´‚ മാനേജൠചെയàµà´¯à´¾à´¨àµà´‚ 'Enter' അമർതàµà´¤àµà´•</translation>
<translation id="8734529307927223492">നിങàµà´™à´³àµà´Ÿàµ† <ph name="DEVICE_TYPE" /> മാനേജൠചെയàµà´¯àµà´¨àµà´¨à´¤àµ <ph name="MANAGER" /> ആണàµ</translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, à´¸àµà´µà´•à´¾à´°àµà´¯à´®à´¾à´¯à´¿ à´¬àµà´°àµ—സൠചെയàµà´¯à´¾àµ» ഒരൠപàµà´¤à´¿à´¯ അദൃശàµà´¯ വിൻഡോ à´¤àµà´±à´•àµà´•àµà´¨àµà´¨à´¤à´¿à´¨àµ, 'Tab' അമർതàµà´¤àµà´•, à´¤àµà´Ÿàµ¼à´¨àµà´¨àµ 'Enter' അമർതàµà´¤àµà´•</translation>
+<translation id="8737685506611670901"><ph name="REPLACED_HANDLER_TITLE" /> à´Žà´¨àµà´¨à´¤à´¿à´¨àµ പകരം <ph name="PROTOCOL" /> ലിങàµà´•àµà´•àµ¾ à´¤àµà´±à´•àµà´•àµà´•</translation>
<translation id="8738058698779197622">à´¸àµà´°à´•àµà´·à´¿à´¤ കണകàµà´·àµ» à´¸àµà´¥à´¾à´ªà´¿à´•àµà´•àµà´¨àµà´¨à´¤à´¿à´¨àµ, നിങàµà´™à´³àµà´Ÿàµ† à´•àµà´²àµ‹à´•àµà´•àµ ശരിയായി സജàµà´œàµ€à´•à´°à´¿à´•àµà´•àµ‡à´£àµà´Ÿà´¤àµà´£àµà´Ÿàµ. വെബàµâ€Œà´¸àµˆà´±àµà´±àµà´•àµ¾ à´¸àµà´µà´¯à´‚ തിരിചàµà´šà´±à´¿à´¯àµà´¨àµà´¨à´¤à´¿à´¨àµ ഉപയോഗികàµà´•àµà´¨àµà´¨ സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµà´•àµ¾, നിർദàµà´¦à´¿à´·àµâ€Œà´Ÿ സമയ പരിധിയàµâ€Œà´•àµà´•àµ മാതàµà´°à´®à´¾à´¯à´¿ സാധàµà´¤à´¯àµà´³àµà´³à´¤à´¿à´¨à´¾à´²à´¾à´£à´¿à´¤àµ. നിങàµà´™à´³àµà´Ÿàµ† ഉപകരണതàµà´¤à´¿à´¨àµà´±àµ† à´•àµà´²àµ‹à´•àµà´•àµ തെറàµà´±à´¾à´¯à´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨à´¤à´¿à´¨à´¾àµ½, Chromium-നൠഈ സർടàµà´Ÿà´¿à´«à´¿à´•àµà´•à´±àµà´±àµà´•àµ¾ പരിശോധിചàµà´šàµà´±à´ªàµà´ªà´¿à´•àµà´•à´¾à´¨à´¾à´µà´¿à´²àµà´².</translation>
<translation id="8740359287975076522"><ph name="HOST_NAME" /> ഹോസàµâ€Œà´±àµà´±à´¿à´¨àµâ€à´±àµ† &lt;abbr id="dnsDefinition"&gt;DNS വിലാസം&lt;/abbr&gt; à´•à´£àµà´Ÿàµ†à´¤àµà´¤à´¾à´¨à´¾à´¯à´¿à´²àµà´². à´ªàµà´°à´¶àµâ€Œà´¨à´‚ നിർണàµà´£à´¯à´¿à´•àµà´•àµà´¨àµà´¨àµ.</translation>
<translation id="8742371904523228557"><ph name="ORIGIN" /> à´Žà´¨àµà´¨à´¤à´¿à´¨àµà´±àµ† നിങàµà´™à´³àµà´Ÿàµ† കോഡൠ<ph name="ONE_TIME_CODE" /> ആണàµ</translation>
@@ -2402,6 +2454,7 @@
<translation id="883848425547221593">മറàµà´±àµà´³àµà´³ à´¬àµà´•àµà´•àµâ€Œà´®à´¾à´°àµâ€â€Œà´•àµà´•àµà´•à´³àµâ€â€Œ</translation>
<translation id="884264119367021077">à´·à´¿à´ªàµà´ªà´¿à´‚ഗൠവിലാസം</translation>
<translation id="884923133447025588">അസാധàµà´µà´¾à´•àµà´•à´²àµâ€ à´ªàµà´°à´µà´°àµâ€à´¤àµà´¤à´¨à´‚ à´•à´£àµà´Ÿàµ†à´¤àµà´¤à´¿à´¯à´¿à´Ÿàµà´Ÿà´¿à´²àµà´².</translation>
+<translation id="8849262850971482943">അധിക à´¸àµà´°à´•àµà´·à´¯àµâ€Œà´•àµà´•àµ നിങàµà´™à´³àµà´Ÿàµ† വെർചàµà´µàµ½ കാർഡൠഉപയോഗികàµà´•àµà´•</translation>
<translation id="885730110891505394">Google-മായി പങàµà´•à´¿à´Ÿàµà´¨àµà´¨àµ</translation>
<translation id="8858065207712248076">മറàµà´±àµ സൈറàµà´±àµà´•à´³à´¿àµ½ നിങàµà´™àµ¾ <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> പാസàµâ€Œà´µàµ‡à´¡àµ à´ªàµà´¨à´°àµà´ªà´¯àµ‹à´—à´¿à´šàµà´šà´¿à´Ÿàµà´Ÿàµà´£àµà´Ÿàµ†à´™àµà´•à´¿àµ½, അതൠപàµà´¨à´ƒà´¸à´œàµà´œàµ€à´•à´°à´¿à´•àµà´•à´¾àµ» Chrome à´¶àµà´ªà´¾àµ¼â€Œà´¶ ചെയàµà´¯àµà´¨àµà´¨àµ.</translation>
<translation id="885906927438988819">à´…à´•àµà´·à´°à´™àµà´™àµ¾ ശരിയാണെങàµà´•à´¿àµ½, <ph name="BEGIN_LINK" />Windows നെറàµà´±àµâ€Œà´µàµ¼à´•àµà´•àµ ഡയഗണോസàµâ€Œà´±àµà´±à´¿à´•àµâ€Œà´¸àµ റൺ ചെയàµâ€Œà´¤àµà´¨àµ‹à´•àµà´•àµ‚<ph name="END_LINK" />.</translation>
@@ -2451,6 +2504,7 @@
<translation id="9004367719664099443">VR സെഷൻ à´ªàµà´°àµ‹à´—മികàµà´•àµà´¨àµà´¨àµ</translation>
<translation id="9005998258318286617">PDF ഡോകàµà´¯àµà´®àµ†à´¨àµà´±àµ ലോഡൠചെയàµà´¯à´¾à´¨à´¾à´¯à´¿à´²àµà´².</translation>
<translation id="9008201768610948239">അവഗണികàµà´•àµà´•</translation>
+<translation id="901834265349196618">ഇമെയിലàµâ€</translation>
<translation id="9020200922353704812">കാർഡൠബിലàµà´²à´¿à´‚ഗൠവിലാസം ആവശàµà´¯à´®à´¾à´£àµ</translation>
<translation id="9020542370529661692">à´ˆ പേജൠ<ph name="TARGET_LANGUAGE" />-ലേകàµà´•àµ വിവർതàµà´¤à´¨à´‚ ചെയàµâ€Œà´¤àµ</translation>
<translation id="9020742383383852663">A8</translation>
@@ -2499,6 +2553,7 @@
<translation id="9150045010208374699">നിങàµà´™à´³àµà´Ÿàµ† à´•àµà´¯à´¾à´®à´± ഉപയോഗികàµà´•àµà´•</translation>
<translation id="9150685862434908345">നിങàµà´™à´³àµà´Ÿàµ† à´…à´¡àµâ€Œà´®à´¿à´¨àµ വിദൂരമായി à´¬àµà´°àµ—സർ സജàµà´œàµ€à´•à´°à´£à´‚ മാറàµà´±à´¾à´¨à´¾à´•àµà´‚. à´ˆ ഉപകരണതàµà´¤à´¿à´²àµ† ആകàµâ€Œà´±àµà´±à´¿à´µà´¿à´±àµà´±à´¿ Chrome-നൠപàµà´±à´¤àµà´¤àµà´‚ മാനേജൠചെയàµà´¤àµ‡à´•àµà´•à´¾à´‚. <ph name="BEGIN_LINK" />കൂടàµà´¤à´²à´±à´¿à´¯àµà´•<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">à´…à´ªàµâ€Œà´¡àµ‡à´±àµà´±àµ ചെയàµâ€Œà´¤àµ</translation>
+<translation id="9155211586651734179">à´…à´±àµà´±à´¾à´šàµà´šàµ ചെയàµà´¤ ഓഡിയോ പെരിഫറലàµà´•àµ¾</translation>
<translation id="9157595877708044936">സജàµà´œàµ€à´•à´°à´¿à´•àµà´•àµà´¨àµà´¨àµ...</translation>
<translation id="9158625974267017556">C6 (എൻവലപàµà´ªàµ)</translation>
<translation id="9164029392738894042">കൃതàµà´¯à´¤à´¾ പരിശോധന</translation>
diff --git a/chromium/components/strings/components_strings_mn.xtb b/chromium/components/strings/components_strings_mn.xtb
index c108eb9fb95..dcdee03c2f6 100644
--- a/chromium/components/strings/components_strings_mn.xtb
+++ b/chromium/components/strings/components_strings_mn.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">ДÑлгÑÑ€Ñнгүйг харах</translation>
<translation id="1030706264415084469"><ph name="URL" /> таны төхөөрөмжид том Ñ…ÑмжÑÑний өгөгдлийг бүрмөÑөн хадгалах Ñ…Ò¯ÑÑлтÑй байна</translation>
<translation id="1032854598605920125">Цагийн зүүний дагуу ÑргүүлÑÑ…</translation>
+<translation id="1033329911862281889">Ðууцлалтай горим нь таныг онлайн үед үл харагддаг болгохгүй:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Сайт болон Ñ‚Ñдний ашигладаг үйлчилгÑÑ Ð½ÑŒ зочилÑон харилцан үйлдлийг харах боломжтой<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Ðжил олгогч ÑÑвÑл Ñургууль хөтчийн үйл ажиллагааг Ñ…Ñнах боломжтой<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ИнтернÑÑ‚ үйлчилгÑÑ Ð½Ð¸Ð¹Ð»Ò¯Ò¯Ð»Ñгч вебийн ачааллыг Ñ…Ñнах боломжтой<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">Унтраа</translation>
<translation id="1036982837258183574">БүтÑн дÑлгÑцÑÑÑ Ð³Ð°Ñ€Ð°Ñ… бол |<ph name="ACCELERATOR" />|-г дарна уу</translation>
<translation id="1038106730571050514">Зөвлөмжүүдийг харуулах</translation>
<translation id="1038842779957582377">үл мÑдÑгдÑÑ… нÑÑ€</translation>
<translation id="1041998700806130099">Ðжлын Ñ…Ò¯ÑнÑгтийн меÑÑеж</translation>
<translation id="1048785276086539861">Та Ñ‚ÑмдÑглÑгÑÑг заÑах үед ÑÐ½Ñ Ð´Ð¾ÐºÑƒÐ¼ÐµÐ½Ñ‚ нÑг хуудÑаар харах руу буцна</translation>
-<translation id="1049743911850919806">Ðууцлал</translation>
<translation id="1050038467049342496">БуÑад аппыг хаах</translation>
<translation id="1055184225775184556">&amp; ÐÑмÑÑ… үйлдлийг буцаах</translation>
<translation id="1056898198331236512">Ðнхааруулга</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">Тохиргооны кÑш болж байна</translation>
<translation id="1130564665089811311">Ð¥ÑƒÑƒÐ´Ð°Ñ Ð¾Ñ€Ñ‡ÑƒÑƒÐ»Ð°Ñ… товч, ÑÐ½Ñ Ñ…ÑƒÑƒÐ´Ñыг Google Орчуулагчаар орчуулахын тулд Enter дарна уу</translation>
<translation id="1131264053432022307">Таны хуулÑан зураг</translation>
+<translation id="1142846828089312304">Ðууцлалтай горимд гуравдагч талын күүкиг блоклох</translation>
<translation id="1150979032973867961">Ð­Ð½Ñ Ñервер нь <ph name="DOMAIN" />-аа баталж чадÑангүй; учир нь ÑнÑÑ…Ò¯Ò¯ Ñертификатыг таны компьютерийн үйлдлийн ÑиÑтем дÑмждÑггүй. Ð­Ð½Ñ Ð½ÑŒ тохиргоо буруу хийгдÑÑнÑÑÑ ÑÑвÑл халдагч таны холболтонд Ñаад учруулж Ð±Ð°Ð¹Ð³Ð°Ð°Ð³Ð°Ð°Ñ ÑˆÐ°Ð»Ñ‚Ð³Ð°Ð°Ð»Ð¶ болох юм.</translation>
<translation id="1151972924205500581">Ðууц үг шаардлагатай</translation>
<translation id="1156303062776767266">Та дотоод ÑÑвÑл хуваалцÑан файлыг харж байна</translation>
@@ -64,7 +70,6 @@
<translation id="1178581264944972037">Түр зогÑоох</translation>
<translation id="1181037720776840403">ХаÑах</translation>
<translation id="1186201132766001848">Ðууц үгийг шалгах</translation>
-<translation id="1195210374336998651">Ðппын тохиргоо руу очно уу</translation>
<translation id="1195558154361252544">Таны зөвшөөрөх ÑÐ°Ð¹Ñ‚Ð°Ð°Ñ Ð±ÑƒÑад бүх Ñайтын мÑдÑгдлийг автоматаар хориглоно</translation>
<translation id="1197088940767939838">Улбар шар</translation>
<translation id="1201402288615127009">Дараагийнх</translation>
@@ -111,7 +116,7 @@
<translation id="1307966114820526988">ХуучирÑан онцлог</translation>
<translation id="1308113895091915999">Боломжит Ñаналууд</translation>
<translation id="1312803275555673949">Үүнийг Ñмар нотолгоо дÑмждÑг вÑ?</translation>
-<translation id="131405271941274527">Таныг NFC төхөөрөмж дÑÑÑ€ утÑаараа товших үед <ph name="URL" /> нь мÑдÑÑлÑл илгÑÑÑ…, хүлÑÑн авах Ñ…Ò¯ÑÑлтÑй байна</translation>
+<translation id="1314311879718644478">ӨргөтгөÑөн бодит орчны контентыг үзÑÑ…</translation>
<translation id="1314509827145471431">Баруун ирмÑг дагуу үдÑж хавтаÑлах</translation>
<translation id="1318023360584041678">Табын бүлÑгт хадгалÑан</translation>
<translation id="1319245136674974084">Ð­Ð½Ñ Ð°Ð¿Ð¿Ð°Ð´ дахин бүү аÑуу</translation>
@@ -161,6 +166,7 @@
<translation id="142858679511221695">Үүлний Ñ…ÑÑ€ÑглÑгч</translation>
<translation id="1428729058023778569">Ð­Ð½Ñ Ñайт HTTPS-г дÑмждÑггүй тул та ÑÐ½Ñ Ñануулгыг харж байна. <ph name="BEGIN_LEARN_MORE_LINK" />ÐÑмÑлт мÑдÑÑлÑл авах<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">Ð¥ÑвлÑÑ…</translation>
+<translation id="1432187715652018471">Ñ…ÑƒÑƒÐ´Ð°Ñ Ò¯Ð¹Ð»Ñ‡Ð¸Ð»Ð³ÑÑ Ð·Ð¾Ñ…Ð¸Ñ†ÑƒÑƒÐ»Ð°Ð³Ñ‡Ð¸Ð¹Ð³ Ñуулгахыг Ñ…Ò¯ÑÑж байна.</translation>
<translation id="1432581352905426595">Хайлтын ÑиÑтемийг удирдах</translation>
<translation id="1436185428532214179">Таны төхөөрөмж дÑÑрх файлууд ÑÑвÑл фолдеруудыг заÑахыг Ñ…Ò¯ÑÑÑ… боломжтой</translation>
<translation id="1442386063175183758">Доод Ñ…ÑÑгийг дотогш нь нугалж ÑвхÑÑ… баруун хаалган нугалаа</translation>
@@ -181,6 +187,12 @@
<translation id="1483493594462132177">ИлгÑÑÑ…</translation>
<translation id="1484290072879560759">ТÑÑвÑрлÑлтийн хаÑг Ñонгох</translation>
<translation id="1492194039220927094">Удирдамжийн Ñ…ÑÑ€ÑгжүүлÑлт:</translation>
+<translation id="149293076951187737">Таныг Chrome-н бүх нууцлалтай табыг хаах үед таны Ñ‚ÑдгÑÑÑ€ таб дахь үйл ажиллагааг ÑÐ½Ñ Ñ‚Ó©Ñ…Ó©Ó©Ñ€Ó©Ð¼Ð¶Ó©Ó©Ñ Ð°Ñ€Ð¸Ð»Ð³Ð°Ð½Ð°:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Хөтчийн үйл ажиллагаа<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Хайлтын түүх<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />МаÑгтад оруулÑан мÑдÑÑлÑл<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">Таб руу буцах</translation>
<translation id="1501859676467574491">Google БүртгÑлÑÑÑÑÑ ÐºÐ°Ñ€Ñ‚ харуулах</translation>
<translation id="1507202001669085618">&lt;p&gt;Ð¥ÑÑ€Ñв та онлайн болохооÑоо өмнө нÑвтрÑÑ… шаардлагатай Wi-Fi портал ашиглаж байгаа бол Ñ‚ÑƒÑ Ð°Ð»Ð´Ð°Ð°Ð³ харах болно.&lt;/p&gt;
@@ -208,6 +220,8 @@
<translation id="1559572115229829303">&lt;p&gt;Таны төхөөрөмжийн огноо, цаг (<ph name="DATE_AND_TIME" /> буруу Ð±Ð°Ð¹Ð³Ð°Ð°Ð³Ð°Ð°Ñ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />-н хувийн холболтыг Ò¯Ò¯ÑгÑж чадахгүй байна.&lt;/p&gt;
&lt;p&gt;Та &lt;strong&gt;Settings&lt;/strong&gt; апп-ын &lt;strong&gt;General&lt;/strong&gt; Ñ…ÑÑÑгт огноо, цагийг өөрчлөнө Ò¯Ò¯.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">Танай админиÑтратор төхөөрөмжийг тань <ph name="DATE" />-н <ph name="TIME" />-д дахин ÑхлүүлнÑ</translation>
+<translation id="156703335097561114">ХаÑг, харагдах байдлын тохиргоо, холболтын чанар зÑÑ€Ñг ÑүлжÑÑний мÑдÑÑлÑл</translation>
<translation id="1567040042588613346">Ð­Ð½Ñ Ð±Ð¾Ð´Ð»Ð¾Ð³Ð¾ нь Ñ…Ñвийн ажиллаж байгаа Ñ…Ñдий ч ижил утгыг Ó©Ó©Ñ€ газар тохируулÑан бөгөөд ÑÐ½Ñ Ð±Ð¾Ð´Ð»Ð¾Ð³Ð¾Ð¾Ñ€ хүчингүй болгоÑон байна.</translation>
<translation id="1569487616857761740">ДууÑах огноог оруулна уу</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@
<translation id="1583429793053364125">ЭнÑÑ…Ò¯Ò¯ веб хуудÑыг харуулахад Ñмар нÑгÑн алдаа гарлаа.</translation>
<translation id="1586541204584340881">Таны Ñмар өргөтгөл ÑуулгаÑан болох</translation>
<translation id="1588438908519853928">Ð¥Ñвийн</translation>
+<translation id="1589050138437146318">ARCore-г Ñуулгах уу?</translation>
<translation id="1592005682883173041">Суурин өгөгдлийн хандалт</translation>
<translation id="1594030484168838125">Сонгох</translation>
<translation id="160851722280695521">Chrome-д Dino Run тоглоомыг тоглох</translation>
@@ -254,7 +269,7 @@
<translation id="1711234383449478798"><ph name="POLICY_NAME" />-г <ph name="VALUE" /> гÑж тохируулаагүй тул үл Ñ…ÑÑ€ÑгÑÑÑн.</translation>
<translation id="1712552549805331520"><ph name="URL" /> таны дотоод компьютерт өгөгдлийг бүрмөÑөн хадгалах Ñ…Ò¯ÑÑлтÑй байна</translation>
<translation id="1713628304598226412">Гарах цааÑны тавиур 2</translation>
-<translation id="1715874602234207">F</translation>
+<translation id="1715874602234207">Ба</translation>
<translation id="1717218214683051432">Хөдөлгөөн мÑдрÑгч</translation>
<translation id="1717494416764505390">Шуудангийн хайрцаг 3</translation>
<translation id="1718029547804390981">Документ дÑÑÑ€ Ñ‚ÑмдÑглÑгÑÑ Ñ…Ð¸Ð¹Ñ…Ñд Ñ…ÑÑ‚ том байна</translation>
@@ -283,6 +298,7 @@
толгой Ñ…ÑÑÑг нь гÑмтÑÑн тул
<ph name="SITE" />-д зочлох таны Ñ…Ò¯ÑÑлтийг гүйцÑтгÑÑ…Ñд хөтчид Ñаад болж байна. ҮндÑÑн удирдамжийг
Ñайтад зориулж аюулгүй байдал болон буÑад шинж чанарыг тохируулахад Ñайтын оператор ашиглаж болно.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Chromium дахь Ðууцлалтай горимын талаар нÑмÑлт мÑдÑÑлÑл авах<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">Таны нÑÑлттÑй таб Ñнд харагдана</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -410,6 +426,7 @@
<translation id="22081806969704220">Гарах цааÑны тавиур 3</translation>
<translation id="2212735316055980242">Тохиргоо олдÑонгүй</translation>
<translation id="2213606439339815911">Оролтыг оруулж байна...</translation>
+<translation id="2213612003795704869">ХуудÑыг Ñ…ÑвлÑÑÑн</translation>
<translation id="2215727959747642672">Файл заÑах</translation>
<translation id="2218879909401188352"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />-н халдагчид таны төхөөрөмжийг гÑмтÑÑж болзошгүй аюултай апп Ñуулгах, таны мобайл тооцоонд нÑмÑлт төлбөр гаргах, таны хувийн мÑдÑÑллийг хулгайлах боломжтой. <ph name="BEGIN_LEARN_MORE_LINK" />ДÑлгÑÑ€Ñнгүй үзÑÑ…<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">ИнтернÑÑ‚ алга</translation>
@@ -419,6 +436,7 @@
<translation id="2248949050832152960">WebAuthn ашиглах</translation>
<translation id="2250931979407627383">Зүүн ирмÑгийг нь нийлүүлж үдÑÑ…</translation>
<translation id="225207911366869382">Ð­Ð½Ñ Ð±Ð¾Ð´Ð»Ð¾Ð³Ñ‹Ð½ хувьд ÑнÑÑ…Ò¯Ò¯ утга нь хуучирÑан байна.</translation>
+<translation id="2256115617011615191">Одоо дахин ÑÑ…Ð»Ò¯Ò¯Ð»Ð½Ñ Ò¯Ò¯</translation>
<translation id="2258928405015593961">ИрÑÑдүйд дууÑах огноо оруулаад дахин оролдоно уу</translation>
<translation id="225943865679747347">Ðлдааны код: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">HTTP алдаа</translation>
@@ -446,6 +464,7 @@
<translation id="2337852623177822836">Тохируулгыг таны админиÑтратор Ñ…Ñнадаг</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> холбогдох Ñ…Ò¯ÑÑлтÑй байна</translation>
<translation id="2346319942568447007">Таны хуулÑан зураг</translation>
+<translation id="2350796302381711542"><ph name="REPLACED_HANDLER_TITLE" />-ний оронд <ph name="HANDLER_HOSTNAME" />-д бүх <ph name="PROTOCOL" /> холбооÑыг нÑÑÑ… зөвшөөрөл олгох?</translation>
<translation id="2354001756790975382">БуÑад хайлтын жагÑаалтууд</translation>
<translation id="2354430244986887761">Google-н Ðюулгүй хайлт нь ÑаÑхан <ph name="SITE" />-Ñ <ph name="BEGIN_LINK" />гÑмтÑл Ò¯Ò¯ÑгÑж болох апп илрүүллÑÑ<ph name="END_LINK" />.</translation>
<translation id="2355395290879513365">Халдагч таны ÑÐ½Ñ ÑÐ°Ð¹Ñ‚Ð°Ð°Ñ Ñ…Ð°Ñ€Ð¶ буй зургийг харах бөгөөд Ñ‚ÑдгÑÑрийг өөрчлөх замаар таныг хуурч болзошгүй.</translation>
@@ -471,6 +490,7 @@
<translation id="2413528052993050574">Ð­Ð½Ñ Ñервер нь <ph name="DOMAIN" />-аа баталж чадÑангүй; хамгаалалтын Ñертификат хүчингүй болÑон байж болзошгүй. Ð­Ð½Ñ Ð½ÑŒ тохиргоо буруу хийгдÑÑнÑÑÑ ÑÑвÑл халдагч таны холболтон Ñаад учруулж байж болох юм.</translation>
<translation id="2414886740292270097">Хар</translation>
<translation id="2430968933669123598">Google БүртгÑл удирдах товчлуур, Google БүртгÑлийнхÑÑ Ð¼ÑдÑÑлÑл, нууцлал болон аюулгүй байдлыг удирдахын тулд Enter дÑÑÑ€ дарна уу</translation>
+<translation id="2436186046335138073"><ph name="HANDLER_HOSTNAME" />-д бүх <ph name="PROTOCOL" /> холбооÑыг нÑÑÑ… зөвшөөрлийг олгох уу?</translation>
<translation id="2438874542388153331">Баруун ирмÑг дагуу дөрвөн нүх цоолох</translation>
<translation id="2450021089947420533">ÐÑллууд</translation>
<translation id="2463739503403862330">Бөглөх</translation>
@@ -478,6 +498,7 @@
<translation id="2465655957518002998">ХүртгÑлтийн арга Ñонгох</translation>
<translation id="2465688316154986572">ҮдÑÑ…</translation>
<translation id="2465914000209955735">Chrome-д татÑан файлуудаа удирдана уу</translation>
+<translation id="2466004615675155314">Ð’ÑбÑÑÑ Ð¼ÑдÑÑлÑл харуулах</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />СүлжÑÑний оношилгоог ажиллуулж байна<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">1-Ñ N хүртÑлх дараалал</translation>
<translation id="2470767536994572628">Та Ñ‚ÑмдÑглÑгÑÑг заÑах үед ÑÐ½Ñ Ð´Ð¾ÐºÑƒÐ¼ÐµÐ½Ñ‚ нÑг хуудÑаар харах горим болон анхны ÑргүүлÑлт рүүгÑÑ Ð±ÑƒÑ†Ð½Ð°</translation>
@@ -498,6 +519,7 @@
<translation id="2523886232349826891">Зөвхөн ÑÐ½Ñ Ñ‚Ó©Ñ…Ó©Ó©Ñ€Ó©Ð¼Ð¶ дÑÑÑ€ хадгалÑан</translation>
<translation id="2524461107774643265">ДÑлгÑÑ€Ñнгүй мÑдÑÑлÑл нÑмÑÑ…</translation>
<translation id="2529899080962247600">Ð­Ð½Ñ Ñ‚Ð°Ð»Ð±Ð°Ñ€ нь <ph name="MAX_ITEMS_LIMIT" />-Ñ Ð¾Ð»Ð¾Ð½ оролттой байж болохгүй. Цаашдын бүх оролтыг үл Ñ…ÑÑ€ÑгÑÑнÑ.</translation>
+<translation id="2535585790302968248">Ðууцлалтайгаар үзÑхийн тулд ÑˆÐ¸Ð½Ñ Ðууцлалтай таб нÑÑÐ½Ñ Ò¯Ò¯</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{болон буÑад 1}other{болон буÑад #}}</translation>
<translation id="2536110899380797252">ХаÑг нÑмÑÑ…</translation>
<translation id="2539524384386349900">ИлрүүлÑÑ…</translation>
@@ -523,7 +545,14 @@
<translation id="2597378329261239068">ЭнÑÑ…Ò¯Ò¯ баримт бичиг нь нууц үгÑÑÑ€ хамгаалагдÑан. Ðууц үгÑÑ Ð¾Ñ€ÑƒÑƒÐ»Ð½Ð° уу.</translation>
<translation id="2609632851001447353">Хувилбарууд</translation>
<translation id="2610561535971892504">Хуулахын тулд товшино уу</translation>
+<translation id="2617988307566202237">Chrome нь дараах мÑдÑÑллийг <ph name="BEGIN_EMPHASIS" />хадгалахгүй<ph name="END_EMPHASIS" />:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Таны хөтчийн түүх
+ <ph name="LIST_ITEM" />Күүки болон Ñайтын өгөгдөл
+ <ph name="LIST_ITEM" />МаÑгтад оруулÑан мÑдÑÑлÑл
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (Дугтуй)</translation>
+<translation id="2623663032199728144">Таны дÑлгÑцийн талаарх мÑдÑÑллийг ашиглахыг Ñ…Ò¯ÑÑÑ… боломжтой</translation>
<translation id="2625385379895617796">Таны цаг түрүүлж Ñвж байна.</translation>
<translation id="262745152991669301">USB төхөөрөмжүүдÑд холбогдохыг Ñ…Ò¯ÑÑÑ… боломжтой</translation>
<translation id="2629325967560697240">Chrome-н хамгийн дÑÑд түвшний аюулгүй байдлыг авахын тулд <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />ÑайжруулÑан хамгаалалтыг аÑаана уу<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -557,6 +586,7 @@
<translation id="2709516037105925701">Ðвтоматаар бөглөх</translation>
<translation id="2713444072780614174">Цагаан</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />, Chrome-н тохиргоон дÑÑÑ€ төлбөр болон кредит картынхаа мÑдÑÑллийг удирдахын тулд ÑхлÑÑд Таб дÑÑÑ€, дараа нь Enter дарна уу</translation>
+<translation id="271663710482723385">БүтÑн дÑлгÑцÑÑÑ Ð³Ð°Ñ€Ð°Ñ…Ñ‹Ð½ тулд |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| дÑÑÑ€ дарна уу</translation>
<translation id="2721148159707890343">Ð¥Ò¯ÑÑлт амжилттай боллоо.</translation>
<translation id="2723669454293168317">Chrome-н тохиргоонд аюулгүй байдлын шалгалтыг ажиллуулна уу</translation>
<translation id="2726001110728089263">Хажуугийн тавиур</translation>
@@ -587,6 +617,7 @@
<translation id="2850739647070081192">Урилга (Дугтуй)</translation>
<translation id="2856444702002559011">Халдагчид <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />-Ñ Ñ‚Ð°Ð½Ñ‹ нууц үг, меÑÑеж, кредит карт зÑÑ€Ñг мÑдÑÑллийг хулгайлахаар оролдож байж болзошгүй. <ph name="BEGIN_LEARN_MORE_LINK" />ДÑлгÑÑ€Ñнгүй үзÑÑ…<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">Ð­Ð½Ñ Ñайт төвөгтÑй ÑÑвÑл хуурамч зар харуулдаг.</translation>
+<translation id="286512204874376891">Виртуал карт нь таныг болзошгүй Ð·Ð°Ð»Ð¸Ð»Ð°Ð½Ð³Ð°Ð°Ñ Ñ…Ð°Ð¼Ð³Ð°Ð°Ð»Ð°Ñ…Ð°Ð´ туÑлахын тулд таны жинхÑÐ½Ñ ÐºÐ°Ñ€Ñ‚Ñ‹Ð³ далдалдаг. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">ÐÓ©Ñ…Ó©Ñ€Ñөг</translation>
<translation id="2876489322757410363">Гадны аппликÑйшнÑÑÑ€ төлбөр төлөхийн тулд Ðууцлалтай Ð³Ð¾Ñ€Ð¸Ð¼Ð¾Ð¾Ñ Ð³Ð°Ñ€Ñ‡ байна. ҮргÑлжлүүлÑÑ… Ò¯Ò¯?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />. Chrome-н тохиргоонд Ðюулгүй үзÑÑ… болон буÑад тохиргоогоо удирдахын тулд Tab, дараа нь Enter дÑÑÑ€ дарна уу</translation>
@@ -611,6 +642,7 @@
<translation id="2930577230479659665">Хуулбар бүрийн дараа тайрах</translation>
<translation id="2932085390869194046">Ðууц үг Ñанал болгох...</translation>
<translation id="2934466151127459956">ЗаÑгийн газрын-Захидал</translation>
+<translation id="2938225289965773019"><ph name="PROTOCOL" /> холбооÑуудыг нÑÑÑ…</translation>
<translation id="2941952326391522266">Ð­Ð½Ñ Ñервер нь <ph name="DOMAIN" />-аа баталж чадÑангүй; <ph name="DOMAIN2" />-ÑÑÑ Ñ…Ð°Ð¼Ð³Ð°Ð°Ð»Ð°Ð»Ñ‚Ñ‹Ð½ Ñертификатаа авÑан байна. Ð­Ð½Ñ Ð½ÑŒ тохиргоо буруу хийгдÑÑнÑÑÑ ÑÑвÑл халдагч таны холболтонд Ñаад учруулж байж болох юм.</translation>
<translation id="2943895734390379394">БайршуулÑан цаг:</translation>
<translation id="2948083400971632585">Та тохиргооны хуудаÑÐ½Ð°Ð°Ñ Ñ…Ð¾Ð»Ð±Ð¾Ð»Ñ‚Ð¾Ð½Ð´ зориулÑан тохируулга нь хийгдÑÑн аливаа төлөөллийн тохиргоог идÑвхгүй болгох боломжтой.</translation>
@@ -643,6 +675,7 @@
<translation id="3037605927509011580">Aw, Snap!</translation>
<translation id="3041612393474885105">ГÑрчилгÑÑний мÑдÑÑлÑл</translation>
<translation id="3044034790304486808">Судалгаагаа үргÑлжлүүлÑÑ…</translation>
+<translation id="305162504811187366">Хугацаа Ñ‚ÑмдÑглÑгч, хоÑÑ‚ болон клиентийн харилцан үйлдлийн ID зÑргийг багтааÑан Chrome Remote Desktop-н түүх</translation>
<translation id="3060227939791841287">C9 (Дугтуй)</translation>
<translation id="3061707000357573562">Patch үйлчилгÑÑ</translation>
<translation id="306573536155379004">Тоглоом ÑÑ…ÑллÑÑ.</translation>
@@ -683,6 +716,7 @@
<translation id="3197136577151645743">Таныг ÑÐ½Ñ Ñ‚Ó©Ñ…Ó©Ó©Ñ€Ó©Ð¼Ð¶Ð¸Ð¹Ð³ Ñ…ÑзÑÑ Ð¸Ð´ÑвхтÑй ашиглаж буйг мÑдÑхийг Ñ…Ò¯ÑÑÑ… боломжтой</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />. Chrome-н тохиргоонд Ñмар мÑдÑÑлÑл Ñинк хийхÑÑ ÑƒÐ´Ð¸Ñ€Ð´Ð°Ñ…Ñ‹Ð½ тулд Tab, дараа нь Enter дÑÑÑ€ дарна уу</translation>
<translation id="320323717674993345">Төлбөрийг цуцлах</translation>
+<translation id="3203366800380907218">ВебÑÑÑ</translation>
<translation id="3207960819495026254">Хавчуурга хадгалагдÑан</translation>
<translation id="3209034400446768650">Ð¥ÑƒÑƒÐ´Ð°Ñ Ñ‚Ó©Ð»Ð±Ó©Ñ€ нÑÑ…Ñмжилж болзошгүй</translation>
<translation id="3212581601480735796"><ph name="HOSTNAME" /> дÑÑрх таны үйл ажиллагааг Ñ…Ñнаж байна</translation>
@@ -700,10 +734,12 @@
<translation id="3234666976984236645">Чухал агуулга бүхий мÑдÑÑллийг үргÑлж илрүүлÑÑ…</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />, Хөтчийнхөө харагдах байдлыг өөрчлөхийн тулд tab, дараа нь Enter дÑÑÑ€ дарна уу</translation>
<translation id="3240791268468473923">Тохирох мандат үнÑмлÑхгүй аюулгүй төлбөрийн мандат үнÑмлÑхийн Ñ…Ò¯ÑнÑгтийг нÑÑÑÑн</translation>
+<translation id="324180406144491771">“<ph name="HOST_NAME" />†холбооÑууд блоклоÑон байна</translation>
<translation id="3249845759089040423">ДÑгжин</translation>
<translation id="3252266817569339921">Франц</translation>
<translation id="3257954757204451555">Ð­Ð½Ñ Ð¼ÑдÑÑллийн ард Ñ…Ñн байгаа вÑ?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />, Google Календарьт ÑˆÐ¸Ð½Ñ Ò¯Ð¹Ð» Ñвдал шуурхай Ò¯Ò¯ÑгÑхийн тулд ÑхлÑÑд Tab, дараа нь Enter дÑÑÑ€ дарна уу</translation>
+<translation id="3261488570342242926">Виртуал картын талаар мÑдÑж авах</translation>
<translation id="3264837738038045344">Chrome-н тохиргоог удирдах товчлуур, Chrome-н тохиргоондоо зочлохын тулд Enter дÑÑÑ€ дарна уу</translation>
<translation id="3266793032086590337">Утга (зөрчил)</translation>
<translation id="3268451620468152448">Цонхнуудыг нÑÑÑ…</translation>
@@ -717,6 +753,7 @@
<translation id="3288238092761586174"><ph name="URL" /> таны төлбөрийг баталгаажуулахын тулд нÑмÑлт алхмыг хийх шаардлагатай байж магадгүй</translation>
<translation id="3293642807462928945"><ph name="POLICY_NAME" /> удирдамжийн талаар дÑлгÑÑ€Ñнгүй үзÑÑ…</translation>
<translation id="3295444047715739395">Chrome-н тохиргоо дÑÑÑ€ÑÑÑ Ð½ÑƒÑƒÑ† үгÑÑÑ Ñ…Ð°Ñ€Ð°Ñ…, удирдах</translation>
+<translation id="3303795387212510132">Ðппуудыг <ph name="PROTOCOL_SCHEME" />-н холбооÑыг нÑÑхийг зөвшөөрөх Ò¯Ò¯?</translation>
<translation id="3303855915957856445">Хайлтын илÑрц олдÑонгүй</translation>
<translation id="3304073249511302126">bluetooth Ñкан хийх</translation>
<translation id="3308006649705061278">Байгууллагын нÑгж (БÐ)</translation>
@@ -730,12 +767,6 @@
<translation id="3345782426586609320">Ðүд</translation>
<translation id="3355823806454867987">ПрокÑи-ийн тохиргоонуудыг өөрчлөх ...</translation>
<translation id="3360103848165129075">Төлбөр хариуцагчийн Ñ…Ò¯ÑнÑгт</translation>
-<translation id="3361596688432910856">Chrome дараах мÑдÑÑллийг <ph name="BEGIN_EMPHASIS" />хадгалахгүй<ph name="END_EMPHASIS" />:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Таны хөтчийн түүх
- <ph name="LIST_ITEM" />Күүки, Ñайтын өгөгдөл
- <ph name="LIST_ITEM" />МаÑгтад оруулÑан мÑдÑÑлÑл
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">Ð­Ð½Ñ ÑƒÐ´Ð¸Ñ€Ð´Ð°Ð¼Ð¶Ð¸Ð¹Ð³ зогÑооÑон <ph name="OLD_POLICY" /> ÑƒÐ´Ð¸Ñ€Ð´Ð°Ð¼Ð¶Ð°Ð°Ñ Ð°Ð²Ñ‚Ð¾Ð¼Ð°Ñ‚Ð°Ð°Ñ€ хуулÑан байна. Та оронд нь ÑÐ½Ñ ÑƒÐ´Ð¸Ñ€Ð´Ð°Ð¼Ð¶Ð¸Ð¹Ð³ ашиглавал зохино.</translation>
<translation id="3364869320075768271"><ph name="URL" /> нь таны виртуал бодит байдлын төхөөрөмж болон өгөгдлийг ашиглах Ñ…Ò¯ÑÑлтÑй байна</translation>
<translation id="3366477098757335611">Картыг харах</translation>
@@ -818,7 +849,6 @@
<translation id="3587738293690942763">Дунд</translation>
<translation id="3592413004129370115">Итали (Дугтуй)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{Та бүлгÑÑ Ñ…Ò¯ÑÑÑн үедÑÑ ÑˆÐ¸Ð½ÑчлÑÑ… боломжтой. Ð¨Ð¸Ð½Ñ Ð±Ò¯Ð»Ñгт нÑгдÑÑ…Ñд ойролцоогоор 1 өдөр зарцуулдаг.}=1{Та бүлгÑÑ Ñ…Ò¯ÑÑÑн үедÑÑ ÑˆÐ¸Ð½ÑчлÑÑ… боломжтой. Ð¨Ð¸Ð½Ñ Ð±Ò¯Ð»Ñгт нÑгдÑÑ…Ñд ойролцоогоор 1 өдөр зарцуулдаг.}other{Та бүлгÑÑ Ñ…Ò¯ÑÑÑн үедÑÑ ÑˆÐ¸Ð½ÑчлÑÑ… боломжтой. Ð¨Ð¸Ð½Ñ Ð±Ò¯Ð»Ñгт нÑгдÑÑ…Ñд ойролцоогоор {NUM_DAYS} өдөр зарцуулдаг.}}</translation>
-<translation id="3596012367874587041">Aппын тохиргоо</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">ÐдминиÑтратор аппликÑйшнийг блоклоÑон</translation>
<translation id="3608932978122581043">ЧиглÑлийг заах</translation>
@@ -861,6 +891,7 @@
<translation id="370972442370243704">ÐÑллуудыг аÑаах</translation>
<translation id="3711895659073496551">Түр зогÑоох</translation>
<translation id="3712624925041724820">Лицензийг цуцалÑан</translation>
+<translation id="3714633008798122362">веб календарь</translation>
<translation id="3714780639079136834">Мобайл дата, ÑÑвÑл Wi-Fi-г аÑааж байна</translation>
<translation id="3715597595485130451">Wi-Fi-д холбогдох</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />ПрокÑи, галт хана болон DNS оновчилгоог шалгаж байна<ph name="END_LINK" /></translation>
@@ -922,6 +953,7 @@
<translation id="3906954721959377182">Таблет</translation>
<translation id="3909477809443608991"><ph name="URL" /> хамгаалагдÑан контент тоглуулах Ñ…Ò¯ÑÑлтÑй байна. Таны төхөөрөмжийн таниулбарыг Google-Ñ Ð±Ð°Ñ‚Ð°Ð»Ð³Ð°Ð°Ð¶ÑƒÑƒÐ»Ð°Ñ… бөгөөд үүнд ÑÐ½Ñ ÑÐ°Ð¹Ñ‚Ð°Ð°Ñ Ñ…Ð°Ð½Ð´Ð°Ð¶ болзошгүй.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">Татгалзах</translation>
<translation id="3939773374150895049">Карт баталгаажуулалтын кодын оронд WebAuthn-г ашиглах уу?</translation>
<translation id="3946209740501886391">Ð­Ð½Ñ ÑÐ°Ð¹Ñ‚Ð°Ð°Ñ Ò¯Ñ€Ð³Ñлж аÑуух</translation>
<translation id="3947595700203588284">MIDI төхөөрөмжүүдÑд холбогдохыг Ñ…Ò¯ÑÑÑ… боломжтой</translation>
@@ -943,6 +975,7 @@
<translation id="3990250421422698716">ШилжүүлÑн байрлуулах оффÑет</translation>
<translation id="3996311196211510766"><ph name="ORIGIN" /> Ñайт үндÑÑн удирдамжийг
бүх Ñ…Ò¯ÑÑлтдÑÑ Ñ…ÑÑ€ÑгжүүлÑÑ… Ñ…Ò¯ÑÑлт тавьÑан Ñ…Ñдий ч ÑÐ½Ñ ÑƒÐ´Ð¸Ñ€Ð´Ð°Ð¼Ð¶Ð¸Ð¹Ð³ одоогоор Ñ…ÑÑ€ÑгжүүлÑÑ… боломжгүй байна.</translation>
+<translation id="4009243425692662128">Таы Ñ…ÑвлÑÑ… хуудаÑны контентыг задлан шинжлүүлÑÑ…ÑÑÑ€ Google Cloud ÑÑвÑл гуравдагч тал руу илгÑÑнÑ. ЖишÑÑ Ð½ÑŒ үүнд ÑмзÑг өгөгдөл байгаа ÑÑÑхийг Ñкан хийж болзошгүй.</translation>
<translation id="4010758435855888356">Хадгалах Ñанд хандахыг зөвшөөрөх Ò¯Ò¯?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{{COUNT} хуудаÑтай PDF форматтай документ}other{{COUNT} хуудаÑтай PDF форматтай документ}}</translation>
<translation id="4023431997072828269">Ð­Ð½Ñ Ð¼Ð°Ñгтыг аюулгүй байдлыг хангаагүй холболт ашиглан илгÑÑж байгаа тул таны мÑдÑÑлÑл буÑдад харагдана.</translation>
@@ -1037,6 +1070,7 @@
<translation id="4250680216510889253">Үгүй</translation>
<translation id="4253168017788158739">Тайлбар</translation>
<translation id="425582637250725228">Таны хийÑÑн өөрчлөлтийг хадгалаагүй байж болзошгүй.</translation>
+<translation id="425869179292622354">Үүнийг виртуал картаар илүү аюулгүй болгох уу?</translation>
<translation id="4258748452823770588">Хангалтгүй гарын Ò¯ÑÑг</translation>
<translation id="4261046003697461417">ХамгаалагдÑан документ дÑÑÑ€ Ñ‚ÑмдÑглÑгÑÑ Ñ…Ð¸Ð¹Ñ… боломжгүй</translation>
<translation id="4265872034478892965">Таны админиÑтратор зөвшөөрÑөн</translation>
@@ -1099,6 +1133,7 @@
<translation id="4434045419905280838">Попап болон дахин чиглүүлÑлт</translation>
<translation id="4435702339979719576">Ил захидал)</translation>
<translation id="443673843213245140">Орлон ашиглах Ñрхийг хааÑан байгаа боловч тодорхой түвшинд орлон ашиглах тохиргоог туÑгаÑан байна.</translation>
+<translation id="4441832193888514600">Бодлогыг зөвхөн үүлний Ñ…ÑÑ€ÑглÑгчийн бодлого байдлаар тохируулах боломжтой тул үл Ñ…ÑÑ€ÑгÑÑÑн.</translation>
<translation id="4450893287417543264">Дахиж бүү харуул</translation>
<translation id="4451135742916150903">HID төхөөрөмжүүдÑд холбогдохыг Ñ…Ò¯ÑÑÑ… боломжтой</translation>
<translation id="4452328064229197696">Таны дөнгөж ÑÐ°Ñ Ð°ÑˆÐ¸Ð³Ð»Ð°Ñан нууц үгийг өгөгдлийн Ð·Ó©Ñ€Ñ‡Ð»Ó©Ó©Ñ Ð¾Ð»Ð»Ð¾Ð¾. Таны бүртгÑлүүдийг хамгаалахын тулд Google-н Ðууц үгний менежер нь хадгалÑан нууц үгнүүдÑÑ ÑˆÐ°Ð»Ð³Ð°Ñ…Ñ‹Ð³ зөвлөж байна.</translation>
@@ -1154,6 +1189,7 @@
<translation id="4628948037717959914">Зураг</translation>
<translation id="4631649115723685955">БÑлÑн мөнгө олгох маÑгтыг холбоÑон</translation>
<translation id="4636930964841734540">ÐœÑдÑÑлÑл</translation>
+<translation id="4638670630777875591">Chromium дахь Ðууцлалтай горим</translation>
<translation id="464342062220857295">Онцлогийг хайх</translation>
<translation id="4644670975240021822">ÐүүрÑÑÑ€ нь доош харуулж, хуудаÑны урвуу дарааллаар</translation>
<translation id="4646534391647090355">Одоо намайг тийшÑÑ Ð°Ð²Ð°Ð°Ñ‡</translation>
@@ -1174,6 +1210,7 @@
<translation id="4708268264240856090">Таны холболт таÑарлаа</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Windows ÑүлжÑÑний оношилгоог ажиллуулж байна<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426"><ph name="USERNAME" />-н нууц үг</translation>
<translation id="4724144314178270921">Таны түр Ñанах ойн текÑÑ‚ болон зургийг харахыг Ñ…Ò¯ÑÑÑ… боломжтой</translation>
<translation id="4726672564094551039">Тохиргоог дахин ачаалах</translation>
<translation id="4728558894243024398">Платформ</translation>
@@ -1195,6 +1232,7 @@
<translation id="4757993714154412917">Та дөнгөж ÑÐ°Ñ ÑÑжигтÑй Ñайтад нууц үгÑÑ Ð¾Ñ€ÑƒÑƒÐ»Ð»Ð°Ð°. БүртгÑлүүдÑÑ Ñ…Ð°Ð¼Ð³Ð°Ð°Ð»Ð°Ñ…Ñ‹Ð½ тулд Chromium хадгалÑан нууц үгнүүдÑÑ ÑˆÐ°Ð»Ð³Ð°Ñ…Ñ‹Ð³ зөвлөж байна.</translation>
<translation id="4758311279753947758">Харилцагчийн мÑдÑÑлÑл нÑмÑÑ…</translation>
<translation id="4761104368405085019">Микрофоноо ашигла</translation>
+<translation id="4761869838909035636">Chrome-н Ðюулгүй байдлын шалгалтыг ажиллуулах</translation>
<translation id="4764776831041365478"><ph name="URL" /> Ñ…Ð¾Ð»Ð±Ð¾Ð¾Ñ Ð±Ò¯Ñ…Ð¸Ð¹ веб Ñ…ÑƒÑƒÐ´Ð°Ñ Ð½ÑŒ түр хугацаагаар ажиллахгүй ÑÑвÑл ÑˆÐ¸Ð½Ñ Ð²ÐµÐ± хаÑгтай болÑон байна.</translation>
<translation id="4766713847338118463">Доод буланд хоёр удаа үдÑÑ…</translation>
<translation id="4771973620359291008">Үл мÑдÑгдÑÑ… алдаа гарлаа.</translation>
@@ -1215,12 +1253,6 @@
<translation id="4819347708020428563">ТÑмдÑглÑгÑÑг өгөгдмөлөөр харахаар заÑах уу?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />, Ð¨Ð¸Ð½Ñ Google Ð¥Ò¯ÑнÑгт шуурхай Ò¯Ò¯ÑгÑхийн тулд ÑхлÑÑд Tab, дараа нь Enter дÑÑÑ€ дарна уу</translation>
<translation id="4825507807291741242">ХүчирхÑг</translation>
-<translation id="4827402517081186284">Ðууцлалтай горим таныг онлайн үед үл харагддаг болгохгүй:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Сайт таныг үүнд зочилж байгааг мÑднÑ<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Ðжил олгогч ÑÑвÑл Ñургууль хөтчийн үйл ажиллагааг Ñ…Ñнах боломжтой<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />ИнтернÑÑ‚ үйлчилгÑÑ Ð½Ð¸Ð¹Ð»Ò¯Ò¯Ð»Ñгч вебийн ачааллыг Ñ…Ñнаж магадгүй<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">Сануулгыг аÑаах</translation>
<translation id="4838327282952368871">Зүүд шиг</translation>
<translation id="4840250757394056958">Chrome-н түүхÑÑ Ò¯Ð·ÑÑ…</translation>
@@ -1232,12 +1264,12 @@
<translation id="4854362297993841467">ХүргÑлтийн ÑÐ½Ñ Ð°Ñ€Ð³Ð° боломжгүй тул Ó©Ó©Ñ€ арга Ñонгоно уу.</translation>
<translation id="4854853140771946034">Google Keep-д ÑˆÐ¸Ð½Ñ Ñ‚ÑмдÑглÑл шуурхай Ò¯Ò¯ÑгÑÑÑ€Ñй</translation>
<translation id="485902285759009870">Кодыг баталгаажуулж байна...</translation>
+<translation id="4866506163384898554">КурÑороо харуулахын тулд |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| дÑÑÑ€ дарна уу</translation>
<translation id="4876188919622883022">Ð¥ÑлбаршуулÑан харагдац</translation>
<translation id="4876305945144899064">Ð¥ÑÑ€ÑглÑгчийн нÑÑ€ алга</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{Байхгүй}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831"><ph name="TEXT" />-н хайлт</translation>
<translation id="4879491255372875719">Ðвтомат (өгөгдмөл)</translation>
-<translation id="4879725228911483934">ДÑлгÑц дÑÑÑ€ÑÑ Ñ†Ð¾Ð½Ñ… нÑÑж, байрлуулах</translation>
<translation id="4880827082731008257">Түүхийг хайх</translation>
<translation id="4881695831933465202">ÐÑÑÑ…</translation>
<translation id="4885256590493466218">Тооцоо хийхдÑÑ <ph name="CARD_DETAIL" />-Ñ€ төлөөрÑй</translation>
@@ -1246,6 +1278,7 @@
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">Ð•Ñ Ð´ÑÑ… хуйлмал</translation>
<translation id="4901778704868714008">Хадгалах...</translation>
+<translation id="4905659621780993806">Танай админиÑтратор төхөөрөмжийг тань <ph name="DATE" />-н <ph name="TIME" />-д автоматаар дахин ÑхлүүлнÑ. Таны төхөөрөмж дахин ÑхлÑÑ…ÑÑÑ Ó©Ð¼Ð½Ó© нÑÑлттÑй байгаа аливаа зүйлÑийг хадгална уу.</translation>
<translation id="4913987521957242411">Зүүн дÑÑд буланд нÑг нүх цоолох</translation>
<translation id="4918221908152712722"><ph name="APP_NAME" />-г Ñуулгах (татаж авах шаардлагагүй)</translation>
<translation id="4923459931733593730">Төлбөр</translation>
@@ -1254,6 +1287,7 @@
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, хайхын тулд Таб дÑÑÑ€, дараа нь Enter дарна уу</translation>
<translation id="4930153903256238152">Их багтаамжтай</translation>
+<translation id="4940163644868678279">Chrome дахь Ðууцлалтай горим</translation>
<translation id="4943872375798546930">ИлÑрц байхгүй байна</translation>
<translation id="4950898438188848926">Таб ÑÑлгÑÑ… товчлуур, нÑÑлттÑй таб <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /> руу ÑÑлгÑхийн тулд Enter дÑÑÑ€ дарна уу</translation>
<translation id="495170559598752135">Ðвах арга Ñ…ÑмжÑÑ</translation>
@@ -1263,6 +1297,7 @@
<translation id="4968522289500246572">Ð­Ð½Ñ Ð°Ð¿Ð¿ мобайлд зориулагдÑан бөгөөд үүний Ñ…ÑмжÑÑ Ñайн өөрчлөгдөхгүй байж магадгүй. Ð­Ð½Ñ Ð°Ð¿Ð¿ аÑуудалтай тулгарч ÑÑвÑл дахин ÑÑ…Ñлж магадгүй.</translation>
<translation id="4969341057194253438">БичлÑгийг уÑтгах</translation>
<translation id="4973922308112707173">ДÑÑд буланд хоёр нүх цоолох</translation>
+<translation id="4976702386844183910">Хамгийн Ñүүлд <ph name="DATE" />-д зочилÑон</translation>
<translation id="4984088539114770594">Микрофон ашиглах уу?</translation>
<translation id="4984339528288761049">Prc5 (Дугтуй)</translation>
<translation id="4989163558385430922">Бүгдийг харах</translation>
@@ -1324,6 +1359,7 @@
<translation id="5138227688689900538">Хураангуйлж харуулах</translation>
<translation id="5145883236150621069">удирдамжийн хариулт дахь алдааны код</translation>
<translation id="5146995429444047494"><ph name="ORIGIN" />-н мÑдÑгдлийг хориглоÑон</translation>
+<translation id="514704532284964975"><ph name="URL" /> таны утÑаараа товшÑон NFC төхөөрөмжүүд дÑÑрх мÑдÑÑллийг харах болон өөрчлөхийг Ñ…Ò¯ÑÑж байна</translation>
<translation id="5148809049217731050">ÐүүрÑÑÑ€ нь дÑÑш харуулÑан</translation>
<translation id="515292512908731282">C4 (Дугтуй)</translation>
<translation id="5158275234811857234">Ковер</translation>
@@ -1348,6 +1384,7 @@
<translation id="5215116848420601511">Google Pay-г ашиглаж буй төлбөрийн Ñ…ÑÑ€ÑгÑÑл болон хаÑг</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">Тавиур 13</translation>
+<translation id="5216942107514965959">Хамгийн Ñүүлд өнөөдөр зочилÑон</translation>
<translation id="5222812217790122047">ИмÑйл шаардлагатай</translation>
<translation id="5230733896359313003">ХүргÑлтийн хаÑг</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1368,7 +1405,6 @@
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">Документын төлөв байдал</translation>
<translation id="528468243742722775">ТөгÑгөл</translation>
-<translation id="5284909709419567258">СүлжÑÑний хаÑг</translation>
<translation id="5285570108065881030">Бүх хадгалÑан нууц үгийг харуулах</translation>
<translation id="5287240709317226393">Күүки харуулах</translation>
<translation id="5287456746628258573">Ð­Ð½Ñ Ñайт нь аюулгүй байдлын хуучирÑан тохируулгыг ашиглаж байгаа бөгөөд ÑÐ½Ñ Ð½ÑŒ таны мÑдÑÑллийг (жишÑÑлбÑл, нууц үг ÑÑвÑл кредит картын дугаар) уг Ñайт руу илгÑÑÑ… үед ил болгож болзошгүй.</translation>
@@ -1452,6 +1488,7 @@
<translation id="5556459405103347317">Дахин ачаал</translation>
<translation id="5560088892362098740">ДууÑах огноо</translation>
<translation id="55635442646131152">Баримт бичгийн тойм</translation>
+<translation id="5565613213060953222">Ðууцлалтай табыг нÑÑÑ…</translation>
<translation id="5565735124758917034">ИдÑвхтÑй</translation>
<translation id="5570825185877910964">БүртгÑлийг хамгаалах</translation>
<translation id="5571083550517324815">Ð­Ð½Ñ Ñ…Ð°ÑÐ³Ð°Ð°Ñ Ð°Ð²Ð°Ñ… боломжгүй тул Ó©Ó©Ñ€ хаÑг Ñонгоно уу.</translation>
@@ -1534,6 +1571,7 @@
<translation id="5869522115854928033">ХадгалагдÑан нууц үг</translation>
<translation id="5873013647450402046">Таны банк таныг мөн болохыг баталгаажуулахыг Ñ…Ò¯ÑÑж байна.</translation>
<translation id="5887400589839399685">Картыг хадгалÑан</translation>
+<translation id="5887687176710214216">Хамгийн Ñүүлд өчигдөр зочилÑон</translation>
<translation id="5895138241574237353">Дахин аÑаах</translation>
<translation id="5895187275912066135">ГаргаÑан огноо</translation>
<translation id="5901630391730855834">Шар</translation>
@@ -1547,6 +1585,7 @@
<translation id="5921639886840618607">Картыг Google Account-д хадгалах уу?</translation>
<translation id="5922853866070715753">Бараг дууÑлаа</translation>
<translation id="5932224571077948991">Сайт төвөгтÑй ÑÑвÑл хуурамч зар харуулдаг</translation>
+<translation id="5938153366081463283">Виртуал карт нÑÐ¼Ð½Ñ Ò¯Ò¯</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347"><ph name="SITE_NAME" />-г нÑÑж байна…</translation>
<translation id="5951495562196540101">Ð¥ÑÑ€ÑглÑгчийн бүртгÑлÑÑÑ€ бүртгүүлÑÑ… боломжгүй (багцалÑан лиценз боломжтой).</translation>
@@ -1611,6 +1650,7 @@
<translation id="6120179357481664955">UPI ID-гаа Ñанаж байна уу?</translation>
<translation id="6124432979022149706">Chrome байгууллагын холбогч</translation>
<translation id="6127379762771434464">Хамгийн их зочилÑон вÑбÑайтуудыг уÑтгаÑан</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Chrome дахь Ðууцлалтай горимын талаар нÑмÑлт мÑдÑÑлÑл авах<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">Ðшиглаж байгаа кабелаа шалгаÑны дараагаар рутер, модем ÑÑвÑл буÑад ÑүлжÑÑний төхөөрөмжөө дахин ачааллана уу.</translation>
<translation id="614940544461990577">Оролдож үзÑÑ…:</translation>
<translation id="6150036310511284407">Зүүн ирмÑг дагуу гурван нүх цоолох</translation>
@@ -1622,7 +1662,6 @@
<translation id="6169916984152623906">Ta одоо хувийн хайлт хийж болох ба ÑÐ½Ñ Ñ‚Ó©Ñ…Ó©Ó©Ñ€Ó©Ð¼Ð¶Ð¸Ð¹Ð³ ашигладаг буÑад Ñ…Ò¯Ð¼Ò¯Ò¯Ñ Ñ‚Ð°Ð½Ñ‹ ажиллагааг харахгүй. ГÑхдÑÑ Ñ‚Ð°Ñ‚Ð°Ð¶ авÑан файл, хавчуурга хадгалагдана.</translation>
<translation id="6177128806592000436">Ð­Ð½Ñ Ñайтын холболт аюултай байна</translation>
<translation id="6180316780098470077">Дахин оролдлого хоорондох интервал</translation>
-<translation id="619448280891863779">Таны дÑлгÑц дÑÑÑ€ цонх нÑÑÑ… болон байрлуулахыг Ñ…Ò¯ÑÑÑ… боломжтой</translation>
<translation id="6196640612572343990">Гуравдагч талын күүкиг блоклох</translation>
<translation id="6203231073485539293">Та интернÑтийн холболтоо шалгана уу</translation>
<translation id="6218753634732582820">ХаÑгийг Chromium-Ñ ÑƒÑтгах уу?</translation>
@@ -1645,7 +1684,7 @@
<translation id="6272383483618007430">Google ШинÑчлÑл</translation>
<translation id="6276112860590028508">Таны унших жагÑаалтын Ñ…ÑƒÑƒÐ´Ð°Ñ Ñнд харагдана</translation>
<translation id="627746635834430766">Дараагийн удаа төлбөрөө хурдан төлөхийн тулд Google БүртгÑлдÑÑ ÐºÐ°Ñ€Ñ‚ болон тооцооны хаÑгаа хадгална уу.</translation>
-<translation id="6279098320682980337">Виртуал картын дугаарыг бөглөөгүй байна уу? Хуулахын тулд картын дÑлгÑÑ€Ñнгүйг товшино уу</translation>
+<translation id="6279183038361895380">КурÑороо харуулахын тулд |<ph name="ACCELERATOR" />|-г дарна уу</translation>
<translation id="6280223929691119688">Ð­Ð½Ñ Ñ…Ð°Ñг руу хүргÑÑ… боломжгүй тул Ó©Ó©Ñ€ хаÑг Ñонгоно уу.</translation>
<translation id="6282194474023008486">Шуудангийн код</translation>
<translation id="6285507000506177184">Chrome-д таталтуудыг удирдах товчлуур, Chrome-д татÑан файлуудаа удирдахын тулд Enter дÑÑÑ€ дарна уу</translation>
@@ -1653,6 +1692,7 @@
<translation id="6290238015253830360">Таны Ñанал болгоÑон нийтлÑл Ñнд харагдана</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{Таны төхөөрөмжийг одоо ÑхлүүлнÑ}=1{Таны төхөөрөмжийг 1 Ñекундийн дараа ÑхлүүлнÑ}other{Таны төхөөрөмжийг # Ñекундийн дараа ÑхлүүлнÑ}}</translation>
<translation id="6302269476990306341">Chrome-н Google ТуÑлахыг зогÑоож байна</translation>
<translation id="6305205051461490394"><ph name="URL" />-г ашиглах боломжгүй байна.</translation>
<translation id="6312113039770857350">Веб Ñ…ÑƒÑƒÐ´Ð°Ñ Ð±Ð¾Ð»Ð¾Ð¼Ð¶Ð³Ò¯Ð¹ байна</translation>
@@ -1726,6 +1766,7 @@
<translation id="6529602333819889595">&amp; УÑтгах үйлдлийг дахин хийх</translation>
<translation id="6545864417968258051">Bluetooth Ñкан хийх</translation>
<translation id="6547208576736763147">Зүүн ирмÑг дагуу хоёр нүх цоолох</translation>
+<translation id="6554732001434021288">Хамгийн Ñүүлд <ph name="NUM_DAYS" /> хоногийн өмнө зочилÑон</translation>
<translation id="6556866813142980365">Дахин хийх</translation>
<translation id="6569060085658103619">Та өргөтгөлийн хуудÑыг харж байна.</translation>
<translation id="6573200754375280815">Баруун ирмÑг дагуу хоёр нүх цоолох</translation>
@@ -1786,7 +1827,6 @@
<translation id="6757797048963528358">Таны төхөөрөмж идÑвхгүй болÑон байна.</translation>
<translation id="6767985426384634228">ХаÑгийг шинÑчлÑÑ… Ò¯Ò¯?</translation>
<translation id="6768213884286397650">Хагаки (Ил захидал)</translation>
-<translation id="6774185088257932239">Ðууцлалтай горимын талаар <ph name="BEGIN_LINK" />нÑмÑлт мÑдÑÑлÑл авах<ph name="END_LINK" /></translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">Ðил Ñ…Ó©Ñ… Ñгаан</translation>
<translation id="6786747875388722282">Өргөтгөлүүд</translation>
@@ -1870,7 +1910,6 @@
<translation id="706295145388601875">Chrome-н тохиргоонд хаÑг нÑмж мөн удирдана уу</translation>
<translation id="7064851114919012435">Харилцагчийн мÑдÑÑлÑл</translation>
<translation id="7068733155164172741"><ph name="OTP_LENGTH" /> оронтой кодыг оруулна уу</translation>
-<translation id="7070090581017165256">Ð­Ð½Ñ Ñайтын талаар</translation>
<translation id="70705239631109039">Таны холболт бүрÑн аюулгүй биш байна</translation>
<translation id="7075452647191940183">Ð¥Ò¯ÑÑлт Ñ…ÑÑ‚ том байна</translation>
<translation id="7079718277001814089">Ð­Ð½Ñ Ñайт хортой код агуулж байна</translation>
@@ -1887,6 +1926,12 @@
<translation id="7111012039238467737">(ХүчинтÑй)</translation>
<translation id="7118618213916969306">Түр Ñанах ойн URL болох <ph name="SHORT_URL" />-г хайх</translation>
<translation id="7119414471315195487">БуÑад таб, ÑÑвÑл программыг хаах</translation>
+<translation id="7129355289156517987">Таныг Chromium-н бүх нууцлалтай табыг хаах үед таны Ñ‚ÑдгÑÑÑ€ таб дахь үйл ажиллагааг ÑÐ½Ñ Ñ‚Ó©Ñ…Ó©Ó©Ñ€Ó©Ð¼Ð¶Ó©Ó©Ñ Ð°Ñ€Ð¸Ð»Ð³Ð°Ð½Ð°:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Хөтчийн үйл ажиллагаа<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Хайлтын түүх<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />МаÑгтад оруулÑан мÑдÑÑлÑл<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">Ð­Ð½Ñ Ñ…Ð°Ñг руу хүргÑÑ… боломжгүй тул Ó©Ó©Ñ€ хаÑг Ñонгоно уу.</translation>
<translation id="7132939140423847331">Таны админ ÑÐ½Ñ Ó©Ð³Ó©Ð³Ð´Ð»Ð¸Ð¹Ð³ хуулахыг хориглоÑон.</translation>
<translation id="7135130955892390533">Төлөвийг харуулах</translation>
@@ -1909,6 +1954,7 @@
<translation id="7192203810768312527"><ph name="SIZE" />-н зай гаргана уу. Зарим Ñайтад зочлох үед удаан ачаалж болзошгүй.</translation>
<translation id="719464814642662924">Виз</translation>
<translation id="7201591969684833065">Таны админ дараахыг харах боломжтой:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, Ðууцлалтайгаар үзÑхийн тулд ÑˆÐ¸Ð½Ñ Ðууцлалтай табыг ÑхлÑÑд Tab, дараа нь Enter дÑÑÑ€ дарж нÑÑÐ½Ñ Ò¯Ò¯</translation>
<translation id="7202346780273620635">Захидал-Том</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> нь аюулгүй байдлын Ñтандартыг дагахгүй байна.</translation>
<translation id="7210993021468939304">Контейнер дахь Linux-н үйл ажиллагаа болон Linux аппуудыг контейнерт Ñуулгах болон ажиллуулах боломжтой</translation>
@@ -1940,6 +1986,7 @@
<translation id="7304562222803846232">Google БүртгÑлийн нууцлалын тохиргоог удирдах</translation>
<translation id="7305756307268530424">Илүү удаанаар ÑхлүүлÑÑ…</translation>
<translation id="7308436126008021607">ард Ñинк хийх</translation>
+<translation id="7310392214323165548">Төхөөрөмжийг тун удахгүй дахин ÑхлүүлнÑ</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">Холболтын туÑламж</translation>
<translation id="7323804146520582233">"<ph name="SECTION" />" Ñ…ÑÑгийг нуух</translation>
@@ -1947,6 +1994,7 @@
<translation id="7334320624316649418">&amp; Дахин ÑÑ€ÑмбÑлÑÑ… үйлдлийг дахин хийх</translation>
<translation id="7335157162773372339">Таны камерыг ашиглахыг Ñ…Ò¯ÑÑÑ… боломжтой</translation>
<translation id="7337248890521463931">Илүү олон мөр харуулах</translation>
+<translation id="7337418456231055214">Виртуал картын дугаарыг бөглөөгүй байна уу? Хуулахын тулд картын дÑлгÑÑ€Ñнгүйг товшино уу. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">Таны платформд боломжгүй.</translation>
<translation id="733923710415886693">Серверийн Ñертификатыг Сертификатын ил тод байдлаар ил тод болгоогүй.</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1969,6 +2017,7 @@
<translation id="7378627244592794276">Үгүй</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">Тохирохгүй</translation>
+<translation id="7388594495505979117">{0,plural, =1{Таны төхөөрөмжийг 1 минутын дараа дахин ÑхлүүлнÑ}other{Таны төхөөрөмжийг # минутын дараа дахин ÑхлүүлнÑ}}</translation>
<translation id="7390545607259442187">Карт баталгаажуулах</translation>
<translation id="7392089738299859607">ХаÑгийг шинÑчлÑÑ…</translation>
<translation id="7399802613464275309">Ðюулгүй байдлын шалгалт</translation>
@@ -2005,6 +2054,12 @@
<translation id="7485870689360869515">ÐœÑдÑÑлÑл байхгүй байна.</translation>
<translation id="7495528107193238112">Ð­Ð½Ñ ÐºÐ¾Ð½Ñ‚ÐµÐ½Ñ‚Ñ‹Ð³ блоклоÑон байна. ÐÑуудлыг шийдвÑрлÑхийн тулд Ñайтын өмчлөгчтÑй холбогдоно уу.</translation>
<translation id="7497998058912824456">Документ Ò¯Ò¯ÑгÑÑ… товчлуур, ÑˆÐ¸Ð½Ñ Google Док шуурхай Ò¯Ò¯ÑгÑхийн тулд Enter дÑÑÑ€ дарна уу</translation>
+<translation id="7506488012654002225">Chromium нь дараах мÑдÑÑллийг <ph name="BEGIN_EMPHASIS" />хадгалахгүй<ph name="END_EMPHASIS" />:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Таны хөтчийн түүх
+ <ph name="LIST_ITEM" />Күүки болон Ñайтын өгөгдөл
+ <ph name="LIST_ITEM" />МаÑгтад оруулÑан мÑдÑÑлÑл
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">БуцааÑан удирдамжийн төхөөрөмжийн id хооÑон, ÑÑвÑл одоогийн төхөөрөмжийн id-тай тохирохгүй байна</translation>
<translation id="7508870219247277067">Ðвокадо ногоон</translation>
<translation id="7511955381719512146">Таны ашиглаж буй Wi-Fi ÑүлжÑÑ Ñ‚Ð°Ð½Ñ‹Ð³Â <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />-д нÑвтрÑхийг шаардах магадлалтай.</translation>
@@ -2118,7 +2173,6 @@
<translation id="7813600968533626083">Chrome-Ð¾Ð¾Ñ Ñанал болгож буй зүйлийг уÑтгах уу?</translation>
<translation id="781440967107097262">Түр Ñанах ойг хуваалцах уу?</translation>
<translation id="7815407501681723534">'<ph name="SEARCH_STRING" />'-н <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> олдÑон</translation>
-<translation id="782125616001965242">Ð­Ð½Ñ Ñайтын талаарх мÑдÑÑллийг харуулах</translation>
<translation id="782886543891417279">Таны ашиглаж буй Wi-Fi (<ph name="WIFI_NAME" />) ÑүлжÑÑ Ñ‚Ð°Ð½Ñ‹Ð³ нÑвтрÑÑ… хуудаÑÑ‚ орохыг шаардах магадлалтай.</translation>
<translation id="7836231406687464395">Postfix (Дугтуй)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{Байхгүй}=1{1 апп (<ph name="EXAMPLE_APP_1" />)}=2{2 апп (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}other{# апп (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}}</translation>
@@ -2135,7 +2189,6 @@
<translation id="7888575728750733395">Ð¥ÑвлÑÑ…Ñд өнгө буулгах тодорхойлолт</translation>
<translation id="7894280532028510793">Ð¥ÑÑ€Ñв алдаагүй, зөв бичÑÑн бол <ph name="BEGIN_LINK" />СүлжÑÑний оношилгоог ажиллуулж Ò¯Ð·Ð½Ñ Ò¯Ò¯<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (Дугтуй)</translation>
-<translation id="7931318309563332511">Тодорхойгүй</translation>
<translation id="793209273132572360">ХаÑгийг шинÑчлÑÑ… Ò¯Ò¯?</translation>
<translation id="7932579305932748336">Хамгаалалтын өнгөлгөө хийх</translation>
<translation id="79338296614623784">Зөв утаÑны дугаар оруулна уу</translation>
@@ -2160,13 +2213,14 @@
<translation id="7976214039405368314">Ð¥ÑÑ‚ олон Ñ…Ò¯ÑÑлт</translation>
<translation id="7977538094055660992">Гаралтын төхөөрөмж</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">Дараахад холбоÑон</translation>
<translation id="798134797138789862">Виртуал бодит байдлын төхөөрөмжүүд болон өгөгдлийг ашиглахыг Ñ…Ò¯ÑÑÑ… боломжтой</translation>
<translation id="7984945080620862648">Та ÑнÑÑ…Ò¯Ò¯ <ph name="SITE" />-д хандах боломжгүй байна. Учир нь вебÑайт Ñмх замбараагүй мÑдÑÑлÑл илгÑÑÑÑн тул Chrome ÑÐ½Ñ Ð¼ÑдÑÑллийг боловÑруулах боломжгүй байна. СүлжÑÑний алдаа болон халдлага нь ихÑвчлÑн түр зуурынх байдаг бөгөөд ÑÐ½Ñ Ñ…ÑƒÑƒÐ´Ð°Ñ Ñ…ÑÑÑг хугацааны дараа ажиллаж болох юм.</translation>
-<translation id="79859296434321399">ӨргөтгөÑөн бодит орчны (ÐR) агуулга харахын тулд ARCore-г Ñуулгана уу</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">ҮдÑж хавтаÑлах</translation>
<translation id="7992044431894087211"><ph name="APPLICATION_TITLE" />-тай дÑлгÑц хуваалцахыг үргÑлжлүүлÑÑн</translation>
<translation id="7995512525968007366">Зааж өгөөгүй</translation>
+<translation id="7998269595945679889">Ðууцлалтай табыг нÑÑÑ… товчлуур, нууцлалтайгаар үзÑхийн тулд ÑˆÐ¸Ð½Ñ Ðууцлалтай табыг Enter дÑÑÑ€ дарж нÑÑÐ½Ñ Ò¯Ò¯</translation>
<translation id="800218591365569300">Санах ойн багтаамжийг нÑмÑгдүүлÑхийн тулд буÑад таб, ÑÑвÑл программыг хаана уу.</translation>
<translation id="8004582292198964060">Хөтөч</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{Ð­Ð½Ñ ÐºÐ°Ñ€Ñ‚ болон үүний тооцооны хаÑгийг хадгална. Та үүнийг <ph name="USER_EMAIL" />-д нÑвтÑÑ€ÑÑн үедÑÑ Ð°ÑˆÐ¸Ð³Ð»Ð°Ñ… боломжтой болно.}other{ЭдгÑÑÑ€ карт болон ÑдгÑÑрийн тооцооны хаÑгийг хадгална. Та ÑдгÑÑрийг <ph name="USER_EMAIL" />-д нÑвтÑÑ€ÑÑн үедÑÑ Ð°ÑˆÐ¸Ð³Ð»Ð°Ñ… боломжтой болно.}}</translation>
@@ -2226,6 +2280,7 @@
<translation id="8202370299023114387">Зөрчил</translation>
<translation id="8206978196348664717">Prc4 (Дугтуй)</translation>
<translation id="8211406090763984747">Холболт аюулгүй байна</translation>
+<translation id="8217240300496046857">Сайтууд таныг веб дÑÑÑ€ Ñ…Ñнадаг күүкиг ашиглах боломжгүй. Зарим Ñайтын онцлогууд ажиллахгүй байж болзошгүй.</translation>
<translation id="8218327578424803826">ЗааÑан байршил:</translation>
<translation id="8220146938470311105">C7/C6 (Дугтуй)</translation>
<translation id="8225771182978767009">Ð­Ð½Ñ ÐºÐ¾Ð¼Ð¿ÑŒÑŽÑ‚ÐµÑ€Ð¸Ð¹Ð³ тохиуулÑан хүн ÑÐ½Ñ Ñайтыг блоклоÑон байна.</translation>
@@ -2266,14 +2321,9 @@
<translation id="830498451218851433">Ð¥Ð°Ð³Ð°Ñ Ð½ÑƒÐ³Ð°Ð»Ð°Ð°</translation>
<translation id="8307358339886459768">Жижиг-Зураг</translation>
<translation id="8307888238279532626">СуулгаÑан аппууд болон Ñ‚ÑдгÑÑрийг ашигладаг давтамж</translation>
+<translation id="8317207217658302555">ARCore-г шинÑчлÑÑ… Ò¯Ò¯?</translation>
<translation id="831997045666694187">ҮдÑш</translation>
<translation id="8321476692217554900">мÑдÑгдÑл</translation>
-<translation id="8328484624016508118">Бүх нууцлалтай табыг хааÑны дараа Chrome дараахыг арилгана:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Ð­Ð½Ñ Ñ‚Ó©Ñ…Ó©Ó©Ñ€Ó©Ð¼Ð¶Ó©Ó©Ñ Ñ‚Ð°Ð½Ñ‹ хөтчийн үйл ажиллагаа<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Ð­Ð½Ñ Ñ‚Ó©Ñ…Ó©Ó©Ñ€Ó©Ð¼Ð¶Ó©Ó©Ñ Ñ‚Ð°Ð½Ñ‹ хайлт<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />МаÑгтад оруулÑан мÑдÑÑлÑл<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489"><ph name="HOST_NAME" />-н хандах Ñ…Ò¯ÑÑлтийг зөвшөөрÑөнгүй</translation>
<translation id="833262891116910667">Тодруулах</translation>
<translation id="8339163506404995330"><ph name="LANGUAGE" /> Ñ…Ñл дÑÑрх хуудÑыг орчуулахгүй</translation>
@@ -2325,6 +2375,7 @@
<translation id="8507227106804027148">Тушаалын мөр</translation>
<translation id="8508648098325802031">Хайлтын Ð´Ò¯Ñ€Ñ Ñ‚ÑмдÑг</translation>
<translation id="8511402995811232419">Күүки удирдах</translation>
+<translation id="8519753333133776369">Танай админиÑтраторын зөвшөөрÑөн HID төхөөрөмж</translation>
<translation id="8522552481199248698">Chrome танд Google БүртгÑлÑÑ Ñ…Ð°Ð¼Ð³Ð°Ð°Ð»Ð°Ñ… болон нууц үгÑÑ Ñолиход туÑлах боломжтой.</translation>
<translation id="8530813470445476232">Chrome Ñ‚Ð¾Ñ…Ð¸Ñ€Ð³Ð¾Ð¾Ð½Ð¾Ð¾Ñ Ñ…Ó©Ñ‚Ñ‡Ð¸Ð¹Ð½ түүх, күүки, завÑрын Ñанах ой болон буÑад зүйлийг уÑтгах</translation>
<translation id="8533619373899488139">СиÑтемийн админиÑтраторынхаа Ñ…ÑÑ€ÑгжүүлдÑг блоклоÑон URL-үүдийн болон буÑад удирдамжийн жагÑаалтыг харахын тулд &lt;strong&gt; chrome://policy&lt;/strong&gt;-д зочилно уу.</translation>
@@ -2336,7 +2387,6 @@
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{Зөвшөөрлийг шинÑчлÑÑ…}other{Зөвшөөрлүүдийг шинÑчлÑÑ…}}</translation>
<translation id="8555010941760982128">Тооцоо хийхдÑÑ ÑÐ½Ñ ÐºÐ¾Ð´Ñ‹Ð³ ашиглаарай</translation>
<translation id="8557066899867184262">Карт баталгаажуулалтын код таны картын ард байрладаг.</translation>
-<translation id="8558485628462305855">ӨргөтгөÑөн бодит орчны (AR) агуулга харахын тулд ARCore-г шинÑÑ‡Ð¸Ð»Ð½Ñ Ò¯Ò¯</translation>
<translation id="8559762987265718583"><ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> руу таны төхөөрөмжийн он Ñар өдөр, цаг <ph name="DATE_AND_TIME" /> ) буруу байгаа ÑƒÑ‡Ñ€Ð°Ð°Ñ Ñ…ÑƒÐ²Ð¸Ð¹Ð½ холболт Ò¯Ò¯ÑгÑж болохгүй байна.</translation>
<translation id="8564182942834072828">ТуÑдаа документ/ЗÑÑ€ÑгцүүлÑÑгүй хувь</translation>
<translation id="8564985650692024650">Ð¥ÑÑ€Ñв та <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" />-н нууц үгийг буÑад Ñайтад дахин ашиглаÑан бол Chromium-Ñ Ò¯Ò¯Ð½Ð¸Ð¹Ð³ шинÑчлÑхийг зөвлөж байна.</translation>
@@ -2355,6 +2405,7 @@
<translation id="865032292777205197">хөдөлгөөн мÑдрÑгч</translation>
<translation id="8663226718884576429">Захиалгын дүн, <ph name="TOTAL_LABEL" />, ДÑлгÑÑ€Ñнгүй</translation>
<translation id="8666678546361132282">Ðнгли Ñ…Ñл</translation>
+<translation id="8669306706049782872">Таны дÑлгÑцийн талаарх мÑдÑÑллийг цонх нÑÑÑ… болон байрлуулахад ашиглах</translation>
<translation id="867224526087042813">Гарын Ò¯ÑÑг</translation>
<translation id="8676424191133491403">ХүлÑÑхгүй</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, хариулт, <ph name="ANSWER" /></translation>
@@ -2381,6 +2432,7 @@
<translation id="8731544501227493793">Ðууц үг удирдах товч, Chrome-н тохиргоон дÑÑÑ€ нууц үгÑÑ Ñ…Ð°Ñ€Ð°Ñ…, удирдахын тулд Enter дарна уу</translation>
<translation id="8734529307927223492">Таны <ph name="DEVICE_TYPE" />-г <ph name="MANAGER" /> удирддаг</translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, нууцлалтайгаар үзÑхдÑÑ Ðууцлалтай цонх шинÑÑÑ€ нÑÑхийн тулд ÑхлÑÑд Таб дÑÑÑ€, дараа нь Enter дарна уу</translation>
+<translation id="8737685506611670901"><ph name="PROTOCOL" /> холбооÑуудыг <ph name="REPLACED_HANDLER_TITLE" />-ний оронд нÑÑÑ…</translation>
<translation id="8738058698779197622">Ðайдвартай аюулгүй холболт бий болгохын тулд та цагаа зөв тохируулах Ñ…ÑÑ€ÑгтÑй. Учир нь веб хуудÑуудын Ó©Ó©Ñ€Ñдийгөө таниулахад ашигладаг гÑрчилгÑÑ Ð½ÑŒ тодорхой хугацаанд л хүчинтÑй байдаг юм. Таны төхөөрөмжийн цаг буруу байгаа тохиолдолд Chromium нь ÑдгÑÑÑ€ гÑрчилгÑÑнүүдийг баталгаажуулж чадахгүй.</translation>
<translation id="8740359287975076522"><ph name="HOST_NAME" />-н &lt;abbr id="dnsDefinition"&gt;DNS хаÑг&lt;/abbr&gt; олдÑонгүй. Ðлдааг шалгаж байна.</translation>
<translation id="8742371904523228557"><ph name="ONE_TIME_CODE" /> бол <ph name="ORIGIN" />-д зориулÑан таны код</translation>
@@ -2408,6 +2460,7 @@
<translation id="883848425547221593">БуÑад хадгалагдÑан хуудÑууд</translation>
<translation id="884264119367021077">ИлгÑÑÑ… хаÑг</translation>
<translation id="884923133447025588">Хүчингүй болгох арга олдÑонгүй.</translation>
+<translation id="8849262850971482943">ÐÑмÑлт аюулгүй байдлын үүднÑÑÑ Ð²Ð¸Ñ€Ñ‚ÑƒÐ°Ð» картаа ашиглана уу</translation>
<translation id="885730110891505394">Google-Ñ‚Ñй хуваалцаж байна</translation>
<translation id="8858065207712248076">Ð¥ÑÑ€Ñв та <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" />-н нууц үгийг буÑад Ñайтад дахин ашиглаÑан бол Chrome-Ñ Ò¯Ò¯Ð½Ð¸Ð¹Ð³ шинÑчлÑхийг зөвлөж байна.</translation>
<translation id="885906927438988819">Ð¥ÑÑ€Ñв алдаагүй, зөв бичÑÑн бол <ph name="BEGIN_LINK" />Windows-н ÑүлжÑÑний оношилгоог ажиллуулж Ò¯Ð·Ð½Ñ Ò¯Ò¯<ph name="END_LINK" />.</translation>
@@ -2457,6 +2510,7 @@
<translation id="9004367719664099443">Виртуал орчны (VR) харилцан үйлдлийг хийж байна</translation>
<translation id="9005998258318286617">PDF документыг ачаалж чадÑангүй.</translation>
<translation id="9008201768610948239">ÐлгаÑ</translation>
+<translation id="901834265349196618">и-мÑйл</translation>
<translation id="9020200922353704812">Картын нÑÑ…ÑмжлÑлийн хаÑг шаардлагатай</translation>
<translation id="9020542370529661692">Ð­Ð½Ñ Ñ…ÑƒÑƒÐ´Ñыг <ph name="TARGET_LANGUAGE" /> руу хөрвүүлÑÑн байна.</translation>
<translation id="9020742383383852663">A8</translation>
@@ -2505,6 +2559,7 @@
<translation id="9150045010208374699">Та камераа ашиглана уу</translation>
<translation id="9150685862434908345">Таны админиÑтратор таны хөтчийн тохируулгыг алÑÐ°Ð°Ñ Ó©Ó©Ñ€Ñ‡Ð¸Ð»Ð¶ болно. Ð­Ð½Ñ Ñ‚Ó©Ñ…Ó©Ó©Ñ€Ó©Ð¼Ð¶ дÑÑрх үйл ажиллагааг мөн Chrome-Ñ Ð³Ð°Ð´ÑƒÑƒÑ€ удирддаг байж болзошгүй. <ph name="BEGIN_LINK" />ÐÑмÑлт мÑдÑÑлÑл авах<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">ШинÑчилÑÑн</translation>
+<translation id="9155211586651734179">Ðудионы нÑмÑлт Ñ…ÑÑ€ÑгÑлийг залгаÑан</translation>
<translation id="9157595877708044936">Тохиргоог хийж байна ...</translation>
<translation id="9158625974267017556">C6 (Дугтуй)</translation>
<translation id="9164029392738894042">Ðарийвчлалын шалгалт</translation>
diff --git a/chromium/components/strings/components_strings_mr.xtb b/chromium/components/strings/components_strings_mr.xtb
index 3cd6b9bb562..4dcfcc8e254 100644
--- a/chromium/components/strings/components_strings_mr.xtb
+++ b/chromium/components/strings/components_strings_mr.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">तपशील पहा</translation>
<translation id="1030706264415084469"><ph name="URL" /> ला तà¥à¤®à¤šà¥à¤¯à¤¾ डिवà¥à¤¹à¤¾à¤‡à¤¸à¤µà¤° मोठà¥à¤¯à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤¾à¤µà¤° डेटा कायमचा सà¥à¤Ÿà¥‹à¤…र करायचा आहे</translation>
<translation id="1032854598605920125">घडà¥à¤¯à¤¾à¤³à¤¾à¤šà¥à¤¯à¤¾ दिशेने फिरवा</translation>
+<translation id="1033329911862281889">गà¥à¤ªà¥à¤¤ मोडमà¥à¤³à¥‡ तà¥à¤®à¤šà¥‡ ऑनलाइन असà¥à¤¤à¤¿à¤¤à¥à¤µ नाहीसे होत नाही:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ते वापरत असलेलà¥à¤¯à¤¾ साइट आणि सेवा भेटी पाहू शकतात<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />नियोकà¥à¤¤à¥‡ किंवा शाळा बà¥à¤°à¤¾à¤‰à¤à¤¿à¤‚ग अâ€à¥…कà¥à¤Ÿà¤¿à¤µà¥à¤¹à¤¿à¤Ÿà¥€à¤šà¤¾ माग ठेवू शकतात<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />इंटरनेट सेवा पà¥à¤°à¤µà¤ à¤¾à¤¦à¤¾à¤° हे वेब टà¥à¤°à¥…फिकवर लकà¥à¤· ठेऊ शकतात<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">बंद करा</translation>
<translation id="1036982837258183574">संपूरà¥à¤£ सà¥à¤•à¥à¤°à¥€à¤¨à¤®à¤§à¥‚न बाहेर पडणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ |<ph name="ACCELERATOR" />| दाबा</translation>
<translation id="1038106730571050514">सूचना दाखवा</translation>
<translation id="1038842779957582377">अजà¥à¤žà¤¾à¤¤ नाव</translation>
<translation id="1041998700806130099">जॉब पतà¥à¤°à¤•à¤¾à¤šà¤¾ मेसेज</translation>
<translation id="1048785276086539861">तà¥à¤®à¥à¤¹à¥€ भाषà¥à¤¯à¥‡ संपादित करता तेवà¥à¤¹à¤¾ हा दसà¥à¤¤à¤à¤µà¤œ à¤à¤•à¤² पेजवà¥à¤¹à¥à¤¯à¥‚वर परत येईल</translation>
-<translation id="1049743911850919806">गà¥à¤ªà¥à¤¤</translation>
<translation id="1050038467049342496">अनà¥à¤¯ ॲपà¥à¤¸ बंद करा</translation>
<translation id="1055184225775184556">&amp;जोडा पूरà¥à¤µà¤µà¤¤ करा</translation>
<translation id="1056898198331236512">चेतावणी</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">धोरण कॅशे ठीक</translation>
<translation id="1130564665089811311">पेजचे भाषांतर करा बटण, Google Translate वापरून या पेजचे भाषांतर करणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ Enter दाबा</translation>
<translation id="1131264053432022307">तà¥à¤®à¥à¤¹à¥€ कॉपी केलेली इमेज</translation>
+<translation id="1142846828089312304">गà¥à¤ªà¥à¤¤ मोडमधील तृतीय पकà¥à¤· कà¥à¤•à¥€ बà¥à¤²à¥‰à¤• करा</translation>
<translation id="1150979032973867961">हा सरà¥à¤µà¥à¤¹à¤° हे <ph name="DOMAIN" /> असलà¥à¤¯à¤¾à¤šà¥‡ सिदà¥à¤§ करू शकला नाही; तà¥à¤¯à¤¾à¤šà¥‡ सà¥à¤°à¤•à¥à¤·à¤¿à¤¤à¤¤à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° तà¥à¤®à¤šà¥à¤¯à¤¾ कॉंपà¥à¤¯à¥à¤Ÿà¤°à¤šà¥à¤¯à¤¾ ऑपरेटिंग पà¥à¤°à¤£à¤¾à¤²à¥€à¤¦à¥à¤µà¤¾à¤°à¥‡ विशà¥à¤µà¤¸à¤¨à¥€à¤¯ नाही. हे कदाचित à¤à¤•à¤¾ चà¥à¤•à¥€à¤šà¥à¤¯à¤¾ कॉनà¥à¤«à¤¿à¤—रेशनमà¥à¤³à¥‡ किंवा आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥à¤¯à¤¾à¤¨à¥‡ तà¥à¤®à¤šà¥‡ कनेकà¥à¤¶à¤¨ आंतरखंडित केलà¥à¤¯à¤¾à¤®à¥à¤³à¥‡ à¤à¤¾à¤²à¥‡ असू शकते.</translation>
<translation id="1151972924205500581">पासवरà¥à¤¡ आवशà¥à¤¯à¤•</translation>
<translation id="1156303062776767266">तà¥à¤®à¥à¤¹à¥€ सà¥à¤¥à¤¾à¤¨à¤¿à¤• किंवा शेअर केलेली फाइल पाहत आहात</translation>
@@ -64,7 +70,6 @@
<translation id="1178581264944972037">विराम दà¥à¤¯à¤¾</translation>
<translation id="1181037720776840403">काढून टाका</translation>
<translation id="1186201132766001848">पासवरà¥à¤¡ तपासा</translation>
-<translation id="1195210374336998651">अâ€à¥…प सेटिंगà¥à¤œà¤µà¤° जा</translation>
<translation id="1195558154361252544">तà¥à¤®à¥à¤¹à¥€ अनà¥à¤®à¤¤à¥€ दिलेली साइट वगळता सरà¥à¤µ साइटसाठी सूचना आपोआप बà¥à¤²à¥‰à¤• केलà¥à¤¯à¤¾ आहेत</translation>
<translation id="1197088940767939838">नारिंगी</translation>
<translation id="1201402288615127009">पà¥à¤¢à¥€à¤²</translation>
@@ -111,7 +116,7 @@
<translation id="1307966114820526988">कालबाहà¥à¤¯ à¤à¤¾à¤²à¥‡à¤²à¥€ वैशिषà¥â€à¤Ÿà¥à¤¯à¥‡</translation>
<translation id="1308113895091915999">ऑफर उपलबà¥à¤§ आहे</translation>
<translation id="1312803275555673949">यासाठी काय पà¥à¤°à¤¾à¤µà¤¾ आहे?</translation>
-<translation id="131405271941274527">तà¥à¤®à¥à¤¹à¥€ तà¥à¤®à¤šà¤¾ फोन NFC डिवà¥à¤¹à¤¾à¤‡à¤¸à¤µà¤° टॅप करता तेवà¥à¤¹à¤¾ <ph name="URL" /> ला माहिती पाठवायची आणि मिळवायची असते</translation>
+<translation id="1314311879718644478">ऑगमेंटेड रीअâ€à¥…लिटी आशय पहा</translation>
<translation id="1314509827145471431">बाइंड राइट</translation>
<translation id="1318023360584041678">टॅबचà¥à¤¯à¤¾ गटामधà¥à¤¯à¥‡ सेवà¥à¤¹ केला</translation>
<translation id="1319245136674974084">या अâ€à¥…पसाठी पà¥à¤¨à¥â€à¤¹à¤¾ विचारू नका</translation>
@@ -161,6 +166,7 @@
<translation id="142858679511221695">कà¥à¤²à¤¾à¤‰à¤¡ वापरकरà¥à¤¤à¤¾</translation>
<translation id="1428729058023778569">ही साइट HTTPS ला सपोरà¥à¤Ÿ करत नसलà¥à¤¯à¤¾à¤®à¥à¤³à¥‡ तà¥à¤®à¥à¤¹à¤¾à¤²à¤¾ ही चेतावणी दिसत आहे. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जाणून घà¥à¤¯à¤¾<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">पà¥à¤°à¤¿à¤‚ट</translation>
+<translation id="1432187715652018471">पेजला सेवा हà¤à¤¡à¤²à¤° इंसà¥à¤Ÿà¥‰à¤² करायचा आहे.</translation>
<translation id="1432581352905426595">शोध इंजीन वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¿à¤¤ करा</translation>
<translation id="1436185428532214179">तà¥à¤®à¤šà¥à¤¯à¤¾ डिवà¥à¤¹à¤¾à¤‡à¤¸à¤µà¤°à¥€à¤² फाइल आणि फोलà¥à¤¡à¤° संपादित करणà¥à¤¯à¤¾à¤šà¥€ विनंती करू शकते</translation>
<translation id="1442386063175183758">राइट गेट फोलà¥à¤¡</translation>
@@ -181,6 +187,12 @@
<translation id="1483493594462132177">पाठवा</translation>
<translation id="1484290072879560759">पाठवणà¥à¤¯à¤¾à¤šà¤¾ पतà¥à¤¤à¤¾ निवडा</translation>
<translation id="1492194039220927094">धोरणे पà¥à¤¢à¥‡ ढकला:</translation>
+<translation id="149293076951187737">तà¥à¤®à¥à¤¹à¥€ Chrome मधील सरà¥à¤µ गà¥à¤ªà¥à¤¤ टॅब बंद करता, तेवà¥à¤¹à¤¾ तà¥à¤¯à¤¾ टॅबमधील तà¥à¤®à¤šà¥€ अâ€à¥…कà¥à¤Ÿà¤¿à¤µà¥à¤¹à¤¿à¤Ÿà¥€ ही या डिवà¥à¤¹à¤¾à¤‡à¤¸à¤µà¤°à¥‚न साफ केली जाते:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />बà¥à¤°à¤¾à¤‰à¤à¤¿à¤‚ग अâ€à¥…कà¥à¤Ÿà¤¿à¤µà¥à¤¹à¤¿à¤Ÿà¥€<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />शोध इतिहास<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />फॉरà¥à¤®à¤®à¤§à¥à¤¯à¥‡ à¤à¤‚टर केलेली माहिती<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">टॅबवर परत</translation>
<translation id="1501859676467574491">तà¥à¤®à¤šà¥à¤¯à¤¾ Google खातà¥à¤¯à¤¾à¤µà¤°à¥€à¤² कारà¥à¤¡à¥‡ दाखवा</translation>
<translation id="1507202001669085618">&lt;p&gt;ऑनलाइन येणà¥à¤¯à¤¾à¤ªà¥‚रà¥à¤µà¥€ तà¥à¤®à¥à¤¹à¤¾à¤²à¤¾ साइन इन करावे लागेल अशी वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾ असलेले वाय-फाय पोरà¥à¤Ÿà¤² वापरत असलà¥à¤¯à¤¾à¤¸ तà¥à¤®à¥à¤¹à¤¾à¤²à¤¾ ही à¤à¤°à¤° दिसून येईल.&lt;/p&gt;
@@ -208,6 +220,8 @@
<translation id="1559572115229829303">&lt;p&gt;आपलà¥à¤¯à¤¾ डिवà¥à¤¹à¤¾à¤‡à¤¸à¤šà¥€ तारीख आणि वेळ (<ph name="DATE_AND_TIME" />) चà¥à¤•à¥€à¤šà¥€ असलà¥à¤¯à¤¾à¤®à¥à¤³à¥‡ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> सह खाजगी कनेकà¥à¤¶à¤¨ इंसà¥à¤Ÿà¥‰à¤² केले जाऊ शकत नाही.&lt;/p&gt;
&lt;p&gt;कृपया &lt;strong&gt;सेटिंगà¥à¤œ&lt;/strong&gt; ॲपचà¥à¤¯à¤¾ &lt;strong&gt;सरà¥à¤µà¤¸à¤¾à¤§à¤¾à¤°à¤£&lt;/strong&gt; विभागातील तारीख आणि वेळ समायोजित करा.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">तà¥à¤®à¤šà¤¾ अâ€à¥…डमिनिसà¥à¤Ÿà¥à¤°à¥‡à¤Ÿà¤° तà¥à¤®à¤šà¥‡ डिवà¥à¤¹à¤¾à¤‡à¤¸ <ph name="DATE" /> रोजी <ph name="TIME" /> वाजता रीसà¥à¤Ÿà¤¾à¤°à¥à¤Ÿ करेल</translation>
+<translation id="156703335097561114">पतà¥à¤¤à¥‡, इंटरफेस कॉंफिगरेशन आणि कनेकà¥à¤¶à¤¨ गà¥à¤£à¤µà¤¤à¥à¤¤à¤¾ यांसारखी नेटवरà¥à¤•à¤¿à¤‚ग माहिती</translation>
<translation id="1567040042588613346">हे धोरण अपेकà¥à¤·à¥‡à¤¨à¥à¤¸à¤¾à¤° काम करत आहे पण, कà¥à¤ à¥‡à¤¤à¤°à¥€ समान मूलà¥à¤¯ सेट केले आहे आणि हे धोरण ते मूलà¥à¤¯ अधिगà¥à¤°à¤¹à¤¿à¤¤ करत आहे.</translation>
<translation id="1569487616857761740">à¤à¤•à¥à¤¸à¥à¤ªà¤¾à¤¯à¤°à¥€à¤šà¥€ तारीख à¤à¤‚टर करा</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@
<translation id="1583429793053364125">हे वेबपेज पà¥à¤°à¤¦à¤°à¥à¤¶à¤¿à¤¤ करताना काहीतरी चूक à¤à¤¾à¤²à¥€.</translation>
<translation id="1586541204584340881">तà¥à¤®à¥à¤¹à¥€ कोणती à¤à¤•à¥à¤¸à¥à¤Ÿà¥‡à¤‚शन इंसà¥à¤Ÿà¥‰à¤² केली आहेत</translation>
<translation id="1588438908519853928">सामानà¥à¤¯</translation>
+<translation id="1589050138437146318">ARCore इंसà¥à¤Ÿà¥‰à¤² करायचे आहे का?</translation>
<translation id="1592005682883173041">सà¥à¤¥à¤¾à¤¨à¤¿à¤• डेटा ॲकà¥à¤¸à¥‡à¤¸</translation>
<translation id="1594030484168838125">निवडा</translation>
<translation id="160851722280695521">Chrome मधà¥à¤¯à¥‡ Dino Run गेम खेळा</translation>
@@ -283,6 +298,7 @@
हेडर विकृत à¤à¤¾à¤²à¥‡à¤²à¥‡ आहे, जà¥à¤¯à¤¾à¤®à¥à¤³à¥‡ बà¥à¤°à¤¾à¤‰à¤à¤°à¤²à¤¾
तà¥à¤®à¤šà¥à¤¯à¤¾ <ph name="SITE" /> साठीचà¥à¤¯à¤¾ विनंतीची पूरà¥à¤¤à¤¤à¤¾ करणà¥à¤¯à¤¾à¤ªà¤¾à¤¸à¥‚न रोखले जात आहे. साइटची सà¥à¤°à¤•à¥à¤·à¤¿à¤¤à¤¤à¤¾
आणि इतर मालमतà¥à¤¤à¤¾ काà¤à¤«à¤¿à¤—र करणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ साइट ऑपरेटरकडून मूळ धोरणे वापरली जाऊ शकतात.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Chromium मधील गà¥à¤ªà¥à¤¤ मोड याबदà¥à¤¦à¤² अधिक जाणून घà¥à¤¯à¤¾<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">तà¥à¤®à¤šà¥‡ खà¥à¤²à¥‡ टॅब येथे दिसतात</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -359,7 +375,7 @@
<translation id="204357726431741734">तà¥à¤®à¤šà¥à¤¯à¤¾ Google खाते मधà¥à¤¯à¥‡ सेवà¥à¤¹ केलेले पासवरà¥à¤¡ वापरणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ साइन इन करा</translation>
<translation id="2053111141626950936"><ph name="LANGUAGE" />मधील पेज भाषांतरीत केले जाणार नाहीत.</translation>
<translation id="2053373601901562871">{NUM_DAYS,plural, =0{When this control is on and the status is active, Chrome determines which large group of people, or "cohort," your recent browsing activity is most similar to. Advertisers can select ads for the group and your browsing activity is kept private on your device. Your group is updated every day.}=1{हे नियंतà¥à¤°à¤£ सà¥à¤°à¥‚ असते आणि तà¥à¤¯à¤¾à¤šà¥‡ सà¥à¤Ÿà¥‡à¤Ÿà¤¸ अâ€à¥…कà¥à¤Ÿà¤¿à¤µà¥à¤¹ असते तेवà¥à¤¹à¤¾, तà¥à¤®à¤šà¥€ अलीकडील बà¥à¤°à¤¾à¤‰à¤à¤¿à¤‚ग अâ€à¥…कà¥à¤Ÿà¤¿à¤µà¥à¤¹à¤¿à¤Ÿà¥€ ही लोकांचà¥à¤¯à¤¾ कोणतà¥à¤¯à¤¾ मोठà¥à¤¯à¤¾ गटासारखी किंवा "समूह" यासारखी आहे हे Chrome निशà¥à¤šà¤¿à¤¤ करते. जाहिरातदार हे गटासाठी जाहिराती निवडू शकतात आणि तà¥à¤®à¤šà¥€ बà¥à¤°à¤¾à¤‰à¤à¤¿à¤‚ग अâ€à¥…कà¥à¤Ÿà¤¿à¤µà¥à¤¹à¤¿à¤Ÿà¥€ तà¥à¤®à¤šà¥à¤¯à¤¾ डिवà¥à¤¹à¤¾à¤‡à¤¸à¤µà¤° खाजगी ठेवली जाते. तà¥à¤®à¤šà¤¾ गट दररोज अपडेट केला जातो.}other{हे नियंतà¥à¤°à¤£ सà¥à¤°à¥‚ असते आणि तà¥à¤¯à¤¾à¤šà¥‡ सà¥à¤Ÿà¥‡à¤Ÿà¤¸ अâ€à¥…कà¥à¤Ÿà¤¿à¤µà¥à¤¹ असते तेवà¥à¤¹à¤¾, तà¥à¤®à¤šà¥€ अलीकडील बà¥à¤°à¤¾à¤‰à¤à¤¿à¤‚ग अâ€à¥…कà¥à¤Ÿà¤¿à¤µà¥à¤¹à¤¿à¤Ÿà¥€ ही लोकांचà¥à¤¯à¤¾ कोणतà¥à¤¯à¤¾ मोठà¥à¤¯à¤¾ गटासारखी किंवा "समूह" यासारखी आहे हे Chrome निशà¥à¤šà¤¿à¤¤ करते. जाहिरातदार हे गटासाठी जाहिराती निवडू शकतात आणि तà¥à¤®à¤šà¥€ बà¥à¤°à¤¾à¤‰à¤à¤¿à¤‚ग अâ€à¥…कà¥à¤Ÿà¤¿à¤µà¥à¤¹à¤¿à¤Ÿà¥€ तà¥à¤®à¤šà¥à¤¯à¤¾ डिवà¥à¤¹à¤¾à¤‡à¤¸à¤µà¤° खाजगी ठेवली जाते. तà¥à¤®à¤šà¤¾ गट दर {NUM_DAYS} दिवसांनी अपडेट केला जातो.}}</translation>
-<translation id="2053553514270667976">पिनकोड</translation>
+<translation id="2053553514270667976">पिन कोड</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 सूचना}other{# सूचना}}</translation>
<translation id="2071156619270205202">हे कारà¥à¤¡ वà¥à¤¹à¤°à¥à¤šà¥à¤¯à¥à¤…ल कारà¥à¤¡ नंबरसाठी पातà¥à¤° नाही.</translation>
<translation id="2071692954027939183">सूचना आपोआप बà¥à¤²à¥‰à¤• केलà¥à¤¯à¤¾ होतà¥à¤¯à¤¾ कारण तà¥à¤®à¥à¤¹à¥€ सहसा तà¥à¤¯à¤¾à¤‚ना अनà¥à¤®à¤¤à¥€ देत नाही</translation>
@@ -410,6 +426,7 @@
<translation id="22081806969704220">टà¥à¤°à¥‡ ३</translation>
<translation id="2212735316055980242">धोरण आढळले नाही</translation>
<translation id="2213606439339815911">à¤à¤‚टà¥à¤°à¥€ आणत आहे...</translation>
+<translation id="2213612003795704869">पेज पà¥à¤°à¤¿à¤‚ट केले आहे</translation>
<translation id="2215727959747642672">फाइलचे संपादन</translation>
<translation id="2218879909401188352">सधà¥à¤¯à¤¾ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />वर असलेले आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¤¾ तà¥à¤®à¤šà¥à¤¯à¤¾ डिवà¥à¤¹à¤¾à¤‡à¤¸à¤²à¤¾ हानी पोहोचवणारे धोकादायक ॲप इंसà¥à¤Ÿà¥‰à¤² करू शकतात, तà¥à¤®à¤šà¥à¤¯à¤¾ मोबाइल बिलामधà¥à¤¯à¥‡ लपलेले शà¥à¤²à¥à¤• जोडू शकतात किंवा तà¥à¤®à¤šà¥€ वैयकà¥à¤¤à¤¿à¤• माहिती चोरू शकतात. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जाणून घà¥à¤¯à¤¾<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">इंटरनेट नाही</translation>
@@ -419,6 +436,7 @@
<translation id="2248949050832152960">WebAuthn वापरा</translation>
<translation id="2250931979407627383">à¤à¤œ सà¥à¤Ÿà¤¿à¤š लेफà¥à¤Ÿ</translation>
<translation id="225207911366869382">हे मूलà¥à¤¯ या धोरणासाठी नापसंत करणà¥â€à¤¯à¤¾à¤¤ आले आहे.</translation>
+<translation id="2256115617011615191">आता रीसà¥à¤Ÿà¤¾à¤°à¥à¤Ÿ करा</translation>
<translation id="2258928405015593961">भविषà¥à¤¯à¤¾à¤¤à¥€à¤² à¤à¤•à¥à¤¸à¥à¤ªà¤¾à¤¯à¤°à¥‡à¤¶à¤¨ तारीख à¤à¤‚टर करा आणि पà¥à¤¨à¥à¤¹à¤¾ पà¥à¤°à¤¯à¤¤à¥à¤¨ करा</translation>
<translation id="225943865679747347">à¤à¤°à¤° कोड: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">HTTP à¤à¤°à¤°</translation>
@@ -446,6 +464,7 @@
<translation id="2337852623177822836">सेटिंग तà¥à¤®à¤šà¥à¤¯à¤¾ ॲडमिनिसà¥à¤Ÿà¥à¤°à¥‡à¤Ÿà¤°à¤¨à¥‡ नियंतà¥à¤°à¤¿à¤¤ केलेले आहे</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> जोडू इचà¥à¤›à¤¿à¤¤à¥‡</translation>
<translation id="2346319942568447007">तà¥à¤®à¥à¤¹à¥€ कॉपी केलेली इमेज</translation>
+<translation id="2350796302381711542"><ph name="HANDLER_HOSTNAME" /> ला <ph name="REPLACED_HANDLER_TITLE" /> à¤à¤µà¤œà¥€ सरà¥à¤µ <ph name="PROTOCOL" /> लिंक उघडणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ अनà¥à¤®à¤¤à¥€ दà¥à¤¯à¤¾à¤¯à¤šà¥€?</translation>
<translation id="2354001756790975382">इतर बà¥à¤•à¤®à¤¾à¤°à¥à¤•</translation>
<translation id="2354430244986887761">Google सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ बà¥à¤°à¤¾à¤‰à¤à¤¿à¤‚गला अलीकडे <ph name="SITE" />मधà¥à¤¯à¥‡ <ph name="BEGIN_LINK" />हानिकारक ॲपà¥à¤¸ सापडले<ph name="END_LINK" />.</translation>
<translation id="2355395290879513365">तà¥à¤®à¥à¤¹à¥€ या साइटवर पाहत असलेलà¥à¤¯à¤¾ इमेज पाहणà¥à¤¯à¤¾à¤¸ आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥‡ सकà¥à¤·à¤® असू शकतात आणि तà¥à¤¯à¤¾à¤¤ सà¥à¤§à¤¾à¤°à¤£à¤¾ करून तà¥à¤®à¤šà¥€ फसवणूक करू शकतात.</translation>
@@ -471,6 +490,7 @@
<translation id="2413528052993050574">हा सरà¥à¤µà¥à¤¹à¤° हे <ph name="DOMAIN" /> असलà¥à¤¯à¤¾à¤šà¥‡ सिदà¥à¤§ करू शकला नाही; तà¥à¤¯à¤¾à¤šà¥‡ सà¥à¤°à¤•à¥à¤·à¤¿à¤¤à¤¤à¤¾ सरà¥à¤Ÿà¤¿à¤«à¤¿à¤•à¥‡à¤Ÿ कदाचित रदà¥à¤¦ केले असू शकते. हे कदाचित à¤à¤•à¤¾ चà¥à¤•à¥€à¤šà¥à¤¯à¤¾ कॉंफिगरेशनमà¥à¤³à¥‡ किंवा हलà¥à¤²à¥‡à¤–ोराने तà¥à¤®à¤šà¥‡ कनेकà¥à¤¶à¤¨ इंटरसेपà¥à¤Ÿ केलà¥à¤¯à¤¾à¤®à¥à¤³à¥‡ à¤à¤¾à¤²à¥‡ असू शकते.</translation>
<translation id="2414886740292270097">गडद</translation>
<translation id="2430968933669123598">Google खाते वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¿à¤¤ करा, तà¥à¤®à¤šà¥à¤¯à¤¾ Google खाते मधà¥à¤¯à¥‡ तà¥à¤®à¤šà¥€ माहिती, गोपनीयता आणि सà¥à¤°à¤•à¥à¤·à¤¾ वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¿à¤¤ करणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ à¤à¤‚टर दाबा</translation>
+<translation id="2436186046335138073"><ph name="HANDLER_HOSTNAME" /> ला सरà¥à¤µ <ph name="PROTOCOL" /> लिंक उघडणà¥à¤¯à¤¾à¤šà¥€ अनà¥à¤®à¤¤à¥€ दà¥à¤¯à¤¾à¤¯à¤šà¥€?</translation>
<translation id="2438874542388153331">कà¥à¤µà¤¾à¤¡ पंच राइट</translation>
<translation id="2450021089947420533">पà¥à¤°à¤µà¤¾à¤¸</translation>
<translation id="2463739503403862330">भरून टाका</translation>
@@ -478,6 +498,7 @@
<translation id="2465655957518002998">वितरणाची पदà¥à¤§à¤¤ निवडा</translation>
<translation id="2465688316154986572">सà¥à¤Ÿà¥‡à¤ªà¤²</translation>
<translation id="2465914000209955735">तà¥à¤®à¥à¤¹à¥€ Chrome मधà¥à¤¯à¥‡ डाउनलोड केलेलà¥à¤¯à¤¾ फाइल वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¿à¤¤ करा</translation>
+<translation id="2466004615675155314">वेबवरील माहिती दाखवा</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />नेटवरà¥à¤• निदान चालविणे<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">१ ते à¤à¤¨ कà¥à¤°à¤®</translation>
<translation id="2470767536994572628">तà¥à¤®à¥à¤¹à¥€ भाषà¥à¤¯à¥‡ संपादित करता तेवà¥à¤¹à¤¾ हा दसà¥à¤¤à¤à¤µà¤œ à¤à¤•à¤² पेजवà¥à¤¹à¥à¤¯à¥‚वर आणि तà¥à¤¯à¤¾à¤šà¥à¤¯à¤¾ मूळ रोटेशनवर परत येईल</translation>
@@ -498,6 +519,7 @@
<translation id="2523886232349826891">फकà¥à¤¤ या डिवà¥à¤¹à¤¾à¤‡à¤¸à¤µà¤° सेवà¥à¤¹ केले जाईल</translation>
<translation id="2524461107774643265">अधिक माहिती जोडा</translation>
<translation id="2529899080962247600">या भागात <ph name="MAX_ITEMS_LIMIT" /> पेकà¥à¤·à¤¾ जासà¥à¤¤ नोंदी असू शकत नाहीत. उरलेलà¥à¤¯à¤¾ सरà¥à¤µ नोंदी दà¥à¤°à¥à¤²à¤•à¥à¤·à¤¿à¤¤ केलà¥à¤¯à¤¾ जातील.</translation>
+<translation id="2535585790302968248">खाजगीरीतà¥à¤¯à¤¾ बà¥à¤°à¤¾à¤‰à¤ करणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ नवीन गà¥à¤ªà¥à¤¤ टॅब उघडा</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{आणि आणखी à¤à¤•}other{आणि आणखी #}}</translation>
<translation id="2536110899380797252">पतà¥à¤¤à¤¾ जोडा</translation>
<translation id="2539524384386349900">शोधा</translation>
@@ -523,7 +545,14 @@
<translation id="2597378329261239068">हा दसà¥à¤¤à¤à¤µà¤œ पासवरà¥à¤¡ संरकà¥à¤·à¤¿à¤¤ आहे. कृपया पासवरà¥à¤¡ à¤à¤‚टर करा.</translation>
<translation id="2609632851001447353">तफावत</translation>
<translation id="2610561535971892504">कॉपी करणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ कà¥à¤²à¤¿à¤• करा</translation>
+<translation id="2617988307566202237">Chrome पà¥à¤¢à¥€à¤² माहिती <ph name="BEGIN_EMPHASIS" />सेवà¥à¤¹ करणार नाही<ph name="END_EMPHASIS" />:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />तà¥à¤®à¤šà¤¾ बà¥à¤°à¤¾à¤‰à¤à¤¿à¤‚ग इतिहास
+ <ph name="LIST_ITEM" />कà¥à¤•à¥€ आणि साइट डेटा
+ <ph name="LIST_ITEM" />फॉरà¥à¤®à¤®à¤§à¥à¤¯à¥‡ à¤à¤‚टर केलेली माहिती
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (Envelope)</translation>
+<translation id="2623663032199728144">तà¥à¤®à¤šà¥à¤¯à¤¾ सà¥à¤•à¥à¤°à¥€à¤¨à¤¶à¥€ संबंधित माहिती वापरणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ विचारू शकते</translation>
<translation id="2625385379895617796">तà¥à¤®à¤šà¥‡ घडà¥à¤¯à¤¾à¤³ पà¥à¤¢à¥‡ आहे</translation>
<translation id="262745152991669301">USB डिवà¥à¤¹à¤¾à¤‡à¤¸à¤¶à¥€ कनेकà¥à¤Ÿ करणà¥à¤¯à¤¾à¤šà¥€ विनंती करू शकते</translation>
<translation id="2629325967560697240">Chrome ची सरà¥à¤µà¥‹à¤¤à¥à¤¤à¤® सà¥à¤°à¤•à¥à¤·à¤¿à¤¤à¤¤à¤¾ मिळवणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€, <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />सà¥à¤§à¤¾à¤°à¤¿à¤¤ केलेली सà¥à¤°à¤•à¥à¤·à¤¿à¤¤à¤¤à¤¾ सà¥à¤°à¥‚ करा<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -557,6 +586,7 @@
<translation id="2709516037105925701">ऑटोफिल</translation>
<translation id="2713444072780614174">पांढरा</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />, Chrome सेटिंगà¥à¤œà¤®à¤§à¥à¤¯à¥‡ तà¥à¤®à¤šà¥€ पेमेंट आणि कà¥à¤°à¥‡à¤¡à¤¿à¤Ÿ कारà¥à¤¡ माहिती वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¿à¤¤ करणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ टॅब आणि तà¥à¤¯à¤¾à¤¨à¤‚तर à¤à¤‚टर दाबा</translation>
+<translation id="271663710482723385">फà¥à¤² सà¥à¤•à¥à¤°à¥€à¤¨à¤®à¤§à¥‚न बाहेर पडणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| दाबा</translation>
<translation id="2721148159707890343">विनंती यशसà¥à¤µà¥€</translation>
<translation id="2723669454293168317">Chrome सेटिंगà¥à¤œà¤®à¤§à¥à¤¯à¥‡ सà¥à¤°à¤•à¥à¤·à¤¿à¤¤à¤¤à¤¾ तपासणी रन करा</translation>
<translation id="2726001110728089263">बाजूचा टà¥à¤°à¥‡</translation>
@@ -587,6 +617,7 @@
<translation id="2850739647070081192">Invite (Envelope)</translation>
<translation id="2856444702002559011">हलà¥à¤²à¥‡à¤–ोर कदाचित तà¥à¤®à¤šà¥€ माहिती (उदाहरणारà¥à¤¥ पासवरà¥à¤¡, संदेश किंवा कà¥à¤°à¥‡à¤¡à¤¿à¤Ÿ कारà¥à¤¡) <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> मधून चोरणà¥à¤¯à¤¾à¤šà¤¾ पà¥à¤°à¤¯à¤¤à¥à¤¨ करत असतील. <ph name="BEGIN_LEARN_MORE_LINK" />आणखी जाणून घà¥à¤¯à¤¾<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">ही साइट अनाहूत किंवा दिशाभूल करणाऱà¥à¤¯à¤¾ जाहिराती दाखवते.</translation>
+<translation id="286512204874376891">संभावà¥à¤¯ घोटाळà¥à¤¯à¤¾à¤ªà¤¾à¤¸à¥‚न तà¥à¤®à¤šà¥‡ संरकà¥à¤·à¤£ करणà¥à¤¯à¤¾à¤¤ मदत करणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€, वà¥à¤¹à¤°à¥à¤šà¥à¤¯à¥à¤…ल कारà¥à¤¡ तà¥à¤®à¤šà¥à¤¯à¤¾ मूळ कारà¥à¤¡à¤šà¥€ ओळख लपवते.<ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">मैतà¥à¤°à¥€à¤ªà¥‚रà¥à¤£</translation>
<translation id="2876489322757410363">बाहà¥à¤¯ ॲपà¥à¤²à¤¿à¤•à¥‡à¤¶à¤¨à¤®à¤¾à¤°à¥à¤«à¤¤ पेमेंट करणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ गà¥à¤ªà¥à¤¤ मोडमधून बाहेर पडत आहे. पà¥à¤¢à¥‡ सà¥à¤°à¥‚ ठेवायचे आहे का?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />, Chrome सेटिंगà¥à¤œà¤®à¤§à¥à¤¯à¥‡ तà¥à¤®à¤šà¥‡ सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ बà¥à¤°à¤¾à¤‰à¤à¤¿à¤‚ग आणि आणखी बरेच काही वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¿à¤¤ करणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ टॅब व तà¥à¤¯à¤¾à¤¨à¤‚तर à¤à¤‚टर दाबा</translation>
@@ -611,6 +642,7 @@
<translation id="2930577230479659665">पà¥à¤°à¤¤à¥à¤¯à¥‡à¤• पà¥à¤°à¤¤à¥€à¤¨à¤‚तर टà¥à¤°à¤¿à¤® करा</translation>
<translation id="2932085390869194046">पासवरà¥à¤¡ सà¥à¤šà¤µà¤¾...</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019"><ph name="PROTOCOL" /> लिंक उघडा</translation>
<translation id="2941952326391522266">हा सरà¥à¤µà¥à¤¹à¤° हे <ph name="DOMAIN" /> असलà¥à¤¯à¤¾à¤šà¥‡ सिदà¥à¤§ करू शकला नाही; तà¥à¤¯à¤¾à¤šà¥‡ सà¥à¤°à¤•à¥à¤·à¤¿à¤¤à¤¤à¤¾ सरà¥à¤Ÿà¤¿à¤«à¤¿à¤•à¥‡à¤Ÿ <ph name="DOMAIN2" /> वरील आहे. हे कदाचित à¤à¤•à¤¾ चà¥à¤•à¥€à¤šà¥à¤¯à¤¾ कॉंफिगरेशनमà¥à¤³à¥‡ किंवा हलà¥à¤²à¥‡à¤–ोराने तà¥à¤®à¤šà¥‡ कनेकà¥à¤¶à¤¨ इंटरसेपà¥à¤Ÿ केलà¥à¤¯à¤¾à¤®à¥à¤³à¥‡ à¤à¤¾à¤²à¥‡ असू शकते.</translation>
<translation id="2943895734390379394">अपलोड करणà¥à¤¯à¤¾à¤šà¥€ वेळ:</translation>
<translation id="2948083400971632585">तà¥à¤®à¥à¤¹à¥‡ सेटिंगà¥à¤œ पेजवरून à¤à¤•à¤¾ कनेकà¥à¤¶à¤¨à¤¸à¤¾à¤ à¥€ कॉंफिगर केलेले कोणतà¥à¤¯à¤¾à¤¹à¥€ पà¥à¤°à¥‰à¤•à¥à¤¸à¥€ अकà¥à¤·à¤® करू शकता.</translation>
@@ -643,6 +675,7 @@
<translation id="3037605927509011580">चà¥à¤šà¤•!</translation>
<translation id="3041612393474885105">सरà¥à¤Ÿà¤¿à¤«à¤¿à¤•à¥‡à¤Ÿ माहिती</translation>
<translation id="3044034790304486808">तà¥à¤®à¤šà¥‡ संशोधन पà¥à¤¨à¥à¤¹à¤¾ सà¥à¤°à¥‚ करा</translation>
+<translation id="305162504811187366">टाइमसà¥à¤Ÿà¥…ंप, होसà¥à¤Ÿ आणि कà¥à¤²à¤¾à¤¯à¤‚ट सेशन आयडी यांचà¥à¤¯à¤¾ समावेशासह Chrome रिमोट डेसà¥à¤•à¤Ÿà¥‰à¤ª इतिहास</translation>
<translation id="3060227939791841287">C9 (Envelope)</translation>
<translation id="3061707000357573562">पॅच सेवा</translation>
<translation id="306573536155379004">गेमला सà¥à¤°à¥à¤µà¤¾à¤¤ à¤à¤¾à¤²à¥€.</translation>
@@ -683,6 +716,7 @@
<translation id="3197136577151645743">तà¥à¤®à¥à¤¹à¥€ हे डिवà¥à¤¹à¤¾à¤‡à¤¸ सकà¥à¤°à¤¿à¤¯à¤ªà¤£à¥‡ कधी वापरता तà¥à¤¯à¤¾à¤¬à¤¦à¥à¤¦à¤² जाणून घेणà¥à¤¯à¤¾à¤šà¥€ विनंती करू शकते</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />, Chrome सेटिंगà¥à¤œà¤®à¤§à¥à¤¯à¥‡ तà¥à¤®à¥à¤¹à¥€ कोणती माहिती सिंक करता ते वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¿à¤¤ करणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ टॅब आणि तà¥à¤¯à¤¾à¤¨à¤‚तर à¤à¤‚टर दाबा</translation>
<translation id="320323717674993345">पेमेंट रदà¥à¤¦ करा</translation>
+<translation id="3203366800380907218">वेबवरील</translation>
<translation id="3207960819495026254">बà¥à¤•à¤®à¤¾à¤°à¥à¤• केलेली</translation>
<translation id="3209034400446768650">पेज कदाचित शà¥à¤²à¥à¤• आकारू शकते</translation>
<translation id="3212581601480735796">तà¥à¤®à¤šà¥à¤¯à¤¾ <ph name="HOSTNAME" /> वरील अâ€à¥…कà¥à¤Ÿà¤¿à¤µà¥à¤¹à¤¿à¤Ÿà¥€à¤šà¥‡ परीकà¥à¤·à¤£ केले जात आहे</translation>
@@ -699,10 +733,12 @@
<translation id="3234666976984236645">नेहमी या साइटवर महतà¥à¤¤à¥à¤µà¤¾à¤šà¤¾ आशय शोधा</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />, तà¥à¤®à¤šà¥à¤¯à¤¾ बà¥à¤°à¤¾à¤‰à¤à¤°à¤šà¥‡ रूप कसà¥à¤Ÿà¤®à¤¾à¤‡à¤ करणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ टॅब आणि तà¥à¤¯à¤¾à¤¨à¤‚तर à¤à¤‚टर दाबा</translation>
<translation id="3240791268468473923">सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ पेमेंट कà¥à¤°à¥‡à¤¡à¥‡à¤‚शियल याची जà¥à¤³à¤£à¤¾à¤°à¥‡ कोणतेही कà¥à¤°à¥‡à¤¡à¥‡à¤‚शियल नाही ही शीट उघडली आहे</translation>
+<translation id="324180406144491771">“<ph name="HOST_NAME" />†लिंक बà¥à¤²à¥‰à¤• केलà¥à¤¯à¤¾ आहेत</translation>
<translation id="3249845759089040423">आधà¥à¤¨à¤¿à¤•</translation>
<translation id="3252266817569339921">फà¥à¤°à¥‡à¤‚च</translation>
<translation id="3257954757204451555">ही माहिती कोणी पà¥à¤°à¤µà¤²à¥€ आहे?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />, Google Calendar मधà¥à¤¯à¥‡ नवीन इवà¥â€à¤¹à¥‡à¤‚ट à¤à¤Ÿà¤ªà¤Ÿ तयार करणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ टॅब आणि तà¥à¤¯à¤¾à¤¨à¤‚तर à¤à¤‚टर दाबा</translation>
+<translation id="3261488570342242926">वà¥à¤¹à¤°à¥à¤šà¥à¤¯à¥à¤…ल कारà¥à¤¡à¤¬à¤¦à¥à¤¦à¤² जाणून घà¥à¤¯à¤¾</translation>
<translation id="3264837738038045344">Chrome सेटिंगà¥à¤œ वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¿à¤¤ करा बटण, तà¥à¤®à¤šà¥à¤¯à¤¾ Chrome सेटिंगà¥à¤œà¤¨à¤¾ भेट देणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€, à¤à¤‚टर दाबा</translation>
<translation id="3266793032086590337">मूलà¥à¤¯ (परसà¥à¤ªà¤°à¤µà¤¿à¤°à¥‹à¤§à¥€)</translation>
<translation id="3268451620468152448">उघडे Tabs</translation>
@@ -716,6 +752,7 @@
<translation id="3288238092761586174">तà¥à¤®à¤šà¥à¤¯à¤¾ पेमेंटची पडताळणी करणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ <ph name="URL" /> ने अतिरिकà¥à¤¤ पावले उचलणे आवशà¥à¤¯à¤• असू शकते</translation>
<translation id="3293642807462928945"><ph name="POLICY_NAME" /> धोरणांबदà¥à¤¦à¤² अधिक जाणून घà¥à¤¯à¤¾</translation>
<translation id="3295444047715739395">Chrome सेटिंगà¥à¤œà¤®à¤§à¥à¤¯à¥‡ तà¥à¤®à¤šà¥‡ पासवरà¥à¤¡ पहा आणि वà¥â€à¤¯à¤µà¤¸à¥â€à¤¥à¤¾à¤ªà¤¿à¤¤ करा</translation>
+<translation id="3303795387212510132">अâ€à¥…पला <ph name="PROTOCOL_SCHEME" /> लिंक उघडणà¥à¤¯à¤¾à¤šà¥€ अनà¥à¤®à¤¤à¥€ दà¥à¤¯à¤¾à¤¯à¤šà¥€ आहे का?</translation>
<translation id="3303855915957856445">कोणतेही शोध परिणाम आढळले नाहीत</translation>
<translation id="3304073249511302126">बà¥à¤²à¥‚टूथ सà¥à¤•à¥…न करणे</translation>
<translation id="3308006649705061278">संसà¥à¤¥à¤¾à¤¤à¥à¤®à¤• à¤à¤•à¤• (OU)</translation>
@@ -729,12 +766,6 @@
<translation id="3345782426586609320">डोळे</translation>
<translation id="3355823806454867987">पà¥à¤°à¥‰à¤•à¥à¤¸à¥€ सेटिंगà¥à¤œ बदला...</translation>
<translation id="3360103848165129075">पेमेंट हà¤à¤¡à¤²à¤° शीट</translation>
-<translation id="3361596688432910856">Chrome पà¥à¤¢à¥€à¤² माहिती <ph name="BEGIN_EMPHASIS" />सेवà¥à¤¹ करणार नाही<ph name="END_EMPHASIS" />:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />तà¥à¤®à¤šà¤¾ बà¥à¤°à¤¾à¤‰à¤à¤¿à¤‚ग इतिहास
- <ph name="LIST_ITEM" />कà¥à¤•à¥€ आणि साइट डेटा
- <ph name="LIST_ITEM" />फॉरà¥à¤®à¤®à¤§à¥à¤¯à¥‡ टाकलेली माहिती
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">हे धोरण कालबाहà¥à¤¯ à¤à¤¾à¤²à¥‡à¤²à¥à¤¯à¤¾ <ph name="OLD_POLICY" /> धोरणावरून आपोआप कॉपी केले गेले. तà¥à¤®à¥à¤¹à¥€ तà¥à¤¯à¤¾à¤à¤µà¤œà¥€ हे धोरण वापरले पाहिजे.</translation>
<translation id="3364869320075768271"><ph name="URL" /> ला तà¥à¤®à¤šà¥‡ आभासी वासà¥à¤¤à¤µà¤¿à¤•à¤¤à¤¾ डिवà¥à¤¹à¤¾à¤‡à¤¸ आणि डेटा वापरायचा आहे</translation>
<translation id="3366477098757335611">कारà¥à¤¡à¥‡ पहा</translation>
@@ -816,7 +847,6 @@
<translation id="3587738293690942763">मधà¥à¤¯</translation>
<translation id="3592413004129370115">Italian (Envelope)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{You can reset your group at any time. It takes about a day to join a new group.}=1{तà¥à¤®à¥à¤¹à¥€ तà¥à¤®à¤šà¤¾ गट कधीही रीसेट करू शकता. नवीन गटामधà¥à¤¯à¥‡ सामील होणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ à¤à¤• दिवस लागू शकतो.}other{तà¥à¤®à¥à¤¹à¥€ तà¥à¤®à¤šà¤¾ गट कधीही रीसेट करू शकता. नवीन गटामधà¥à¤¯à¥‡ सामील होणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ {NUM_DAYS} दिवस लागू शकतात.}}</translation>
-<translation id="3596012367874587041">अâ€à¥…प सेटिंगà¥à¤œ</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">तà¥à¤®à¤šà¥à¤¯à¤¾ अâ€à¥…डमिनिसà¥à¤Ÿà¥à¤°à¥‡à¤Ÿà¤°à¤¨à¥‡ अâ€à¥…पà¥à¤²à¤¿à¤•à¥‡à¤¶à¤¨ बà¥à¤²à¥‰à¤• केले आहे</translation>
<translation id="3608932978122581043">ओरिà¤à¤‚टेशन फीड करा</translation>
@@ -859,6 +889,7 @@
<translation id="370972442370243704">पà¥à¤°à¤µà¤¾à¤¸ सà¥à¤°à¥‚ करा</translation>
<translation id="3711895659073496551">निलंबन</translation>
<translation id="3712624925041724820">परवाने संपà¥à¤·à¥à¤Ÿà¤¾à¤¤</translation>
+<translation id="3714633008798122362">वेब कॅलेंडर</translation>
<translation id="3714780639079136834">मोबाइल डेटा किंवा वाय-फाय सà¥à¤°à¥‚ करणे</translation>
<translation id="3715597595485130451">वाय-फाय वर कनेकà¥à¤Ÿ करा</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />पà¥à¤°à¥‰à¤•à¥à¤¸à¥€, फायरवॉल आणि DNS कॉंफिगरेशन तपासणे<ph name="END_LINK" /></translation>
@@ -920,6 +951,7 @@
<translation id="3906954721959377182">टॅबलेट</translation>
<translation id="3909477809443608991"><ph name="URL" /> ला संरकà¥à¤·à¤¿à¤¤Â à¤†à¤¶à¤¯Â à¤ªà¥à¤²à¥‡Â à¤•à¤°à¤¾à¤¯à¤šà¤¾Â à¤†à¤¹à¥‡. तà¥à¤®à¤šà¥à¤¯à¤¾Â à¤¡à¤¿à¤µà¥à¤¹à¤¾à¤‡à¤¸à¤šà¥à¤¯à¤¾ ओळखीची Google कडून पडताळणी केली जाईल आणि कदाचित या साइटकडून अâ€à¥…कà¥à¤¸à¥‡à¤¸Â à¤•à¥‡à¤²à¥€Â à¤œà¤¾à¤ˆà¤².</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">नकार दà¥à¤¯à¤¾</translation>
<translation id="3939773374150895049">CVC à¤à¤µà¤œà¥€ WebAuthn वापरायचे का?</translation>
<translation id="3946209740501886391">नेहमी या साइटवर विचारा</translation>
<translation id="3947595700203588284">MIDI डिवà¥à¤¹à¤¾à¤‡à¤¸à¤¶à¥€ कनेकà¥à¤Ÿ करणà¥à¤¯à¤¾à¤šà¥€ विनंती करू शकते</translation>
@@ -941,6 +973,7 @@
<translation id="3990250421422698716">जॉग ऑफसेट</translation>
<translation id="3996311196211510766">साइटने <ph name="ORIGIN" /> विनंती केली आहे की, मूळ धोरण
तà¥à¤¯à¤¾à¤šà¥à¤¯à¤¾ सरà¥à¤µ विनंतà¥à¤¯à¤¾à¤‚वर लागू होईल पण हे धोरण सधà¥à¤¯à¤¾ लागू केले जाऊ शकत नाही.</translation>
+<translation id="4009243425692662128">तà¥à¤®à¥à¤¹à¥€ पà¥à¤°à¤¿à¤‚ट करता तà¥à¤¯à¤¾ पेजचा आशय विशà¥à¤²à¥‡à¤·à¤£à¤¾à¤¸à¤¾à¤ à¥€ Google कà¥à¤²à¤¾à¤‰à¤¡ किंवा तृतीय पकà¥à¤·à¤¾à¤‚ना पाठवला जातो. उदाहरणारà¥à¤¥, तो संवेदनशील डेटासाठी सà¥à¤•à¥…न केला जाऊ शकतो.</translation>
<translation id="4010758435855888356">सà¥à¤Ÿà¥‹à¤°à¥‡à¤œ अâ€à¥…कà¥à¤¸à¥‡à¤¸ करणà¥à¤¯à¤¾à¤šà¥€ अनà¥à¤®à¤¤à¥€ दà¥à¤¯à¤¾à¤¯à¤šà¥€ का?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{PDF दसà¥à¤¤à¤à¤µà¤œà¤¾à¤®à¤§à¥à¤¯à¥‡ {COUNT} पेज आहे}other{PDF दसà¥à¤¤à¤à¤µà¤œà¤¾à¤®à¤§à¥à¤¯à¥‡ {COUNT} पेज आहेत}}</translation>
<translation id="4023431997072828269">हा फॉरà¥à¤® सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ नसलेले कनेकà¥à¤¶à¤¨ वापरून सबमिट केलà¥à¤¯à¤¾à¤®à¥à¤³à¥‡, तà¥à¤®à¤šà¥€ माहिती इतरांना दिसू शकते.</translation>
@@ -1035,6 +1068,7 @@
<translation id="4250680216510889253">नाही</translation>
<translation id="4253168017788158739">टीप</translation>
<translation id="425582637250725228">तà¥à¤®à¥à¤¹à¥€ केलेले बदल कदाचित सेवà¥à¤¹ केले जाणार नाहीत.</translation>
+<translation id="425869179292622354">वà¥à¤¹à¤°à¥à¤šà¥à¤¯à¥à¤…ल कारà¥à¤¡à¤¸à¤¹ ते आणखी सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ करायचे आहे का?</translation>
<translation id="4258748452823770588">खराब सà¥à¤µà¤¾à¤•à¥à¤·à¤°à¥€</translation>
<translation id="4261046003697461417">संरकà¥à¤·à¤¿à¤¤ दसà¥à¤¤à¤à¤µà¤œà¤®à¤§à¥à¤¯à¥‡ भाषà¥à¤¯ केले जाऊ शकत नाही</translation>
<translation id="4265872034478892965">तà¥à¤®à¤šà¥à¤¯à¤¾ ॲडमिनिसà¥à¤Ÿà¥à¤°à¥‡à¤Ÿà¤°à¤•à¤¡à¥‚न परवानगी असलेले</translation>
@@ -1097,6 +1131,7 @@
<translation id="4434045419905280838">पॉप-अप आणि रीडिरेकà¥à¤Ÿ</translation>
<translation id="4435702339979719576">Postcard)</translation>
<translation id="443673843213245140">पà¥à¤°à¥‰à¤•à¥à¤¸à¥€à¤šà¤¾ वापर अकà¥à¤·à¤® करणà¥â€à¤¯à¤¾à¤¤ आला आहे पण à¤à¤• सà¥à¤¸à¥à¤ªà¤·à¥â€à¤Ÿ पà¥à¤°à¥‰à¤•à¥à¤¸à¥€ कॉनà¥â€à¤«à¤¿à¤—रेशन निरà¥à¤¦à¤¿à¤·à¥â€à¤Ÿ करणà¥â€à¤¯à¤¾à¤¤ आले आहे.</translation>
+<translation id="4441832193888514600">दà¥à¤°à¥à¤²à¤•à¥à¤· केले आहे, कारण हे धोरण फकà¥à¤¤ कà¥à¤²à¤¾à¤‰à¤¡ वापरकरà¥à¤¤à¤¾ धोरण मà¥à¤¹à¤£à¥‚न सेट केले जाऊ शकते.</translation>
<translation id="4450893287417543264">पà¥à¤¨à¥à¤¹à¤¾ दाखवू नका</translation>
<translation id="4451135742916150903">HID डिवà¥à¤¹à¤¾à¤‡à¤¸à¤¶à¥€ कनेकà¥à¤Ÿ करणà¥à¤¯à¤¾à¤šà¥€ विनंती करू शकते</translation>
<translation id="4452328064229197696">तà¥à¤®à¥à¤¹à¥€ नà¥à¤•à¤¤à¤¾à¤š वापरलेला पासवरà¥à¤¡ डेटा भंगामधà¥à¤¯à¥‡ आढळला होता. तà¥à¤®à¤šà¥€ खाती सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ करणà¥à¤¯à¤¾à¤¸à¤¾à¤ , Google पासवरà¥à¤¡ वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤• तà¥à¤®à¤šà¥‡ सेवà¥à¤¹ केलेले पासवरà¥à¤¡ तपासणà¥à¤¯à¤¾à¤šà¥€ शिफारस करतो.</translation>
@@ -1152,6 +1187,7 @@
<translation id="4628948037717959914">फोटो</translation>
<translation id="4631649115723685955">कॅशबॅक लिंक केला</translation>
<translation id="4636930964841734540">माहिती</translation>
+<translation id="4638670630777875591">Chromium मधील गà¥à¤ªà¥à¤¤ मोड</translation>
<translation id="464342062220857295">शोध वैशिषà¥à¤Ÿà¥à¤¯à¥‡</translation>
<translation id="4644670975240021822">उलटà¥à¤¯à¤¾ कà¥à¤°à¤®à¤¾à¤¨à¥‡ फेस डाउन</translation>
<translation id="4646534391647090355">आता मला तेथे घेऊन जा</translation>
@@ -1172,6 +1208,7 @@
<translation id="4708268264240856090">आपलà¥à¤¯à¤¾ कनेकà¥à¤¶à¤¨à¤®à¤§à¥à¤¯à¥‡ वà¥à¤¯à¤¤à¥à¤¯à¤¯ आला</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Windows नेटवरà¥à¤• निदान चालविणे<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426"><ph name="USERNAME" /> साठी पासवरà¥à¤¡</translation>
<translation id="4724144314178270921">तà¥à¤®à¤šà¥à¤¯à¤¾ कà¥à¤²à¤¿à¤ªà¤¬à¥‹à¤°à¥à¤¡à¤µà¤°à¥€à¤² मजकूर आणि इमेज पाहणà¥à¤¯à¤¾à¤šà¥€ विनंती करू शकते</translation>
<translation id="4726672564094551039">धोरणे रीलोड करा</translation>
<translation id="4728558894243024398">पà¥à¤²à¥…टफॉरà¥à¤®</translation>
@@ -1193,6 +1230,7 @@
<translation id="4757993714154412917">तà¥à¤®à¥à¤¹à¥€ आताच à¤à¤•à¤¾ फसवà¥à¤¯à¤¾ साइटवर तà¥à¤®à¤šà¤¾ पासवरà¥à¤¡ à¤à¤‚टर केला. तà¥à¤®à¤šà¥€ खाती सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ करणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€, Chromium तà¥à¤®à¤šà¥‡ सेवà¥à¤¹ केलेले पासवरà¥à¤¡ तपासणà¥à¤¯à¤¾à¤šà¥€ शिफारस करते.</translation>
<translation id="4758311279753947758">संपरà¥à¤• माहिती जोडा</translation>
<translation id="4761104368405085019">तà¥à¤®à¤šà¤¾ मायकà¥à¤°à¥‹à¤«à¥‹à¤¨ वापरा</translation>
+<translation id="4761869838909035636">Chrome सà¥à¤°à¤•à¥à¤·à¤¿à¤¤à¤¤à¤¾ तपासणी रन करा</translation>
<translation id="4764776831041365478"><ph name="URL" /> येथील वेबपेज कदाचित तातà¥à¤ªà¥à¤°à¤¤à¥‡ बंद आहे किंवा ते कदाचित कायमचे नवीन वेब पतà¥à¤¤à¥à¤¯à¤¾à¤µà¤° हलवले आहे.</translation>
<translation id="4766713847338118463">डà¥à¤¯à¥à¤…ल सà¥à¤Ÿà¥‡à¤ªà¤² बॉटम</translation>
<translation id="4771973620359291008">à¤à¤• अजà¥à¤žà¤¾à¤¤ à¤à¤°à¤° आली आहे.</translation>
@@ -1213,12 +1251,6 @@
<translation id="4819347708020428563">भाषà¥à¤¯à¥‡ डीफॉलà¥à¤Ÿ वà¥à¤¹à¥à¤¯à¥‚मधà¥à¤¯à¥‡ संपादित करायची आहेत का?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />, नवीन Google शीट à¤à¤Ÿà¤ªà¤Ÿ तयार करणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ टॅब आणि तà¥à¤¯à¤¾à¤¨à¤‚तर à¤à¤‚टर दाबा</translation>
<translation id="4825507807291741242">पà¥à¤°à¤­à¤¾à¤µà¥€</translation>
-<translation id="4827402517081186284">गà¥à¤ªà¥à¤¤ मोड तà¥à¤®à¥à¤¹à¤¾à¤²à¤¾ ऑनलाइन अदृशà¥à¤¯ करत नाही:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />तà¥à¤®à¥à¤¹à¥€ साइटना भेट दिलà¥à¤¯à¤¾à¤¸, तà¥à¤¯à¤¾à¤‚ना समजते<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />नियोकà¥à¤¤à¥‡ किंवा शाळा बà¥à¤°à¤¾à¤‰à¤à¤¿à¤‚ग अâ€à¥…कà¥à¤Ÿà¤¿à¤µà¥à¤¹à¤¿à¤Ÿà¥€ टà¥à¤°à¥…क करू शकतात<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />इंटरनेट सेवा पà¥à¤°à¤µà¤ à¤¾à¤¦à¤¾à¤° वेब टà¥à¤°à¥…फिकचे निरीकà¥à¤·à¤£ करू शकतात<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">चेतावणà¥à¤¯à¤¾ सà¥à¤°à¥‚ करा</translation>
<translation id="4838327282952368871">सà¥à¤µà¤ªà¥à¤¨à¤µà¤¤</translation>
<translation id="4840250757394056958">तà¥à¤®à¤šà¤¾ Chrome इतिहास पहा</translation>
@@ -1230,12 +1262,12 @@
<translation id="4854362297993841467">ही वितरण पदà¥à¤§à¤¤ उपलबà¥à¤§ नाही. वेगळी पदà¥à¤§à¤¤ वापरून पहा.</translation>
<translation id="4854853140771946034">Google Keep मधà¥à¤¯à¥‡ नवीन टीप à¤à¤Ÿà¤ªà¤Ÿ तयार करा</translation>
<translation id="485902285759009870">कोडची पडताळणी करत आहे...</translation>
+<translation id="4866506163384898554">तà¥à¤®à¤šà¤¾ करà¥à¤¸à¤° दाखवणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| दाबा</translation>
<translation id="4876188919622883022">सिंपà¥à¤²à¤¿à¤«à¤¾à¤‡à¤¡ वà¥à¤¹à¥à¤¯à¥‚</translation>
<translation id="4876305945144899064">वापरकरà¥à¤¤à¤¾ नाव नाही</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{काहीही नाही}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831"><ph name="TEXT" /> शोधा</translation>
<translation id="4879491255372875719">आपोआप (डीफॉलà¥à¤Ÿ)</translation>
-<translation id="4879725228911483934">तà¥à¤®à¤šà¥à¤¯à¤¾ सà¥à¤•à¥à¤°à¥€à¤¨à¤µà¤° विंडो उघडा आणि ठेवा</translation>
<translation id="4880827082731008257">इतिहास शोध</translation>
<translation id="4881695831933465202">उघडा</translation>
<translation id="4885256590493466218">चेकआउट करताना <ph name="CARD_DETAIL" /> वापरून पेमेंट करा</translation>
@@ -1244,6 +1276,7 @@
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">नववा रोल</translation>
<translation id="4901778704868714008">सेवà¥à¤¹ करा…</translation>
+<translation id="4905659621780993806">तà¥à¤®à¤šà¤¾ अâ€à¥…डमिनिसà¥à¤Ÿà¥à¤°à¥‡à¤Ÿà¤° तà¥à¤®à¤šà¥‡ डिवà¥à¤¹à¤¾à¤‡à¤¸ <ph name="DATE" /> रोजी <ph name="TIME" /> वाजता आपोआप रीसà¥à¤Ÿà¤¾à¤°à¥à¤Ÿ करेल. तà¥à¤®à¤šà¥‡ डिवà¥à¤¹à¤¾à¤‡à¤¸ रीसà¥à¤Ÿà¤¾à¤°à¥à¤Ÿ होणà¥à¤¯à¤¾à¤ªà¥‚रà¥à¤µà¥€ कोणतेही खà¥à¤²à¥‡ आयटम सेवà¥à¤¹ करा.</translation>
<translation id="4913987521957242411">पंच टॉप लेफà¥à¤Ÿ</translation>
<translation id="4918221908152712722"><ph name="APP_NAME" /> इंसà¥à¤Ÿà¥‰à¤² करा (डाउनलोड करणà¥à¤¯à¤¾à¤šà¥€ आवशà¥à¤¯à¤•à¤¤à¤¾ नाही)</translation>
<translation id="4923459931733593730">पेमेंट</translation>
@@ -1252,6 +1285,7 @@
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, शोधणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ टॅब आणि तà¥à¤¯à¤¾à¤¨à¤‚तर à¤à¤‚टर दाबा</translation>
<translation id="4930153903256238152">जासà¥à¤¤ कà¥à¤·à¤®à¤¤à¤¾</translation>
+<translation id="4940163644868678279">Chrome मधील गà¥à¤ªà¥à¤¤ मोड</translation>
<translation id="4943872375798546930">परिणाम नाहीत</translation>
<translation id="4950898438188848926">टॅब सà¥à¤µà¤¿à¤šÂ à¤¬à¤Ÿà¤£, उघडà¥à¤¯à¤¾Â à¤Ÿà¥…बवर सà¥à¤µà¤¿à¤šÂ à¤•à¤°à¤£à¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ à¤à¤‚टर दाबा, <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="495170559598752135">कà¥à¤°à¤¿à¤¯à¤¾</translation>
@@ -1261,6 +1295,7 @@
<translation id="4968522289500246572">हे ॲप मोबाइलसाठी डिà¤à¤¾à¤‡à¤¨ केले असून योगà¥à¤¯à¤ªà¥à¤°à¤•à¤¾à¤°à¥‡ आकार बदलू शकणार नाही. अâ€à¥…पमधà¥à¤¯à¥‡ समसà¥à¤¯à¤¾ येऊ शकतात किंवा ते रीसà¥à¤Ÿà¤¾à¤°à¥à¤Ÿ होऊ शकते.</translation>
<translation id="4969341057194253438">रेकॉरà¥à¤¡à¤¿à¤‚ग हटवा</translation>
<translation id="4973922308112707173">डà¥à¤¯à¥à¤…ल पंच टॉप</translation>
+<translation id="4976702386844183910"><ph name="DATE" /> रोजी शेवटची भेट दिली</translation>
<translation id="4984088539114770594">मायकà¥à¤°à¥‹à¤«à¥‹à¤¨ वापरायचा का?</translation>
<translation id="4984339528288761049">Prc5 (Envelope)</translation>
<translation id="4989163558385430922">सरà¥à¤µ पहा</translation>
@@ -1322,6 +1357,7 @@
<translation id="5138227688689900538">कमी दाखवा</translation>
<translation id="5145883236150621069">धोरण पà¥à¤°à¤¤à¤¿à¤¸à¤¾à¤¦à¤¾à¤®à¤§à¥à¤¯à¥‡ à¤à¤°à¤° कोड असà¥à¤¤à¤¿à¤¤à¥à¤µà¤¾à¤¤ आहे</translation>
<translation id="5146995429444047494"><ph name="ORIGIN" />साठीचà¥à¤¯à¤¾ सूचना बà¥à¤²à¥‰à¤• केलेलà¥à¤¯à¤¾ आहेत</translation>
+<translation id="514704532284964975">तà¥à¤®à¥à¤¹à¥€ तà¥à¤®à¤šà¤¾ फोन वापरून टॅप केलेलà¥à¤¯à¤¾ NFC डिवà¥à¤¹à¤¾à¤‡à¤¸à¤µà¤°à¥€à¤² माहिती <ph name="URL" /> ला पाहायची आणि बदलायची आहे</translation>
<translation id="5148809049217731050">फेस अप</translation>
<translation id="515292512908731282">C4 (Envelope)</translation>
<translation id="5158275234811857234">कवà¥à¤¹à¤°</translation>
@@ -1346,6 +1382,7 @@
<translation id="5215116848420601511">Google Pay वापरून पेमेंट पदà¥à¤§à¤¤à¥€ आणि पतà¥à¤¤à¥‡</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">टà¥à¤°à¥‡ १३</translation>
+<translation id="5216942107514965959">आज शेवटची भेट दिली</translation>
<translation id="5222812217790122047">ईमेल आवशà¥à¤¯à¤• आहे</translation>
<translation id="5230733896359313003">पाठविणà¥à¤¯à¤¾à¤šà¤¾ पतà¥à¤¤à¤¾</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1366,7 +1403,6 @@
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">दसà¥à¤¤à¤à¤µà¤œ गà¥à¤£à¤§à¤°à¥à¤®</translation>
<translation id="528468243742722775">बंद करा</translation>
-<translation id="5284909709419567258">नेटवरà¥à¤• पतà¥à¤¤à¥‡</translation>
<translation id="5285570108065881030">सरà¥à¤µ सेवà¥à¤¹ केलेले पासवरà¥à¤¡ दाखवा</translation>
<translation id="5287240709317226393">कà¥à¤•à¥€à¤œ दाखवा</translation>
<translation id="5287456746628258573">ही साइट कालबाहà¥à¤¯ à¤à¤¾à¤²à¥‡à¤²à¥€ सà¥à¤°à¤•à¥à¤·à¤¿à¤¤à¤¤à¤¾ काà¤à¤«à¤¿à¤—रेशन वापरत आहे जà¥à¤¯à¤¾à¤®à¥à¤³à¥‡ कदाचित तà¥à¤®à¤šà¥€ माहिती (उदाहरणारà¥à¤¥, पासवरà¥à¤¡ किंवा कà¥à¤°à¥‡à¤¡à¤¿à¤Ÿ कारà¥à¤¡ कà¥à¤°à¤®à¤¾à¤‚क) या साइटला पाठवताना ती उघड होऊ शकते.</translation>
@@ -1450,6 +1486,7 @@
<translation id="5556459405103347317">रीलोड करा</translation>
<translation id="5560088892362098740">à¤à¤•à¥à¤¸à¤ªà¤¾à¤¯à¤° होणà¥à¤¯à¤¾à¤šà¥€ तारीख</translation>
<translation id="55635442646131152">दसà¥à¤¤à¤à¤µà¤œ आउटलाइन</translation>
+<translation id="5565613213060953222">गà¥à¤ªà¥à¤¤ टॅब उघडा</translation>
<translation id="5565735124758917034">सकà¥à¤°à¤¿à¤¯</translation>
<translation id="5570825185877910964">खातà¥à¤¯à¤¾à¤šà¥‡ संरकà¥à¤·à¤£ करा</translation>
<translation id="5571083550517324815">या पतà¥à¤¤à¥à¤¯à¤¾à¤µà¤°à¥‚न पिक अप करू शकत नाही. वेगळा पतà¥à¤¤à¤¾ निवडा.</translation>
@@ -1532,6 +1569,7 @@
<translation id="5869522115854928033">सेवà¥à¤¹ केलेले पासवरà¥à¤¡</translation>
<translation id="5873013647450402046">हे तà¥à¤®à¥à¤¹à¥€à¤š असलà¥à¤¯à¤¾à¤šà¥‡ तà¥à¤®à¤šà¥à¤¯à¤¾ बॅंकला कंफरà¥à¤® करायचे आहे.</translation>
<translation id="5887400589839399685">कारà¥à¤¡ सेवà¥à¤¹ केले</translation>
+<translation id="5887687176710214216">काल शेवटची भेट दिली</translation>
<translation id="5895138241574237353">रीसà¥à¤Ÿà¤¾à¤°à¥à¤Ÿ करा</translation>
<translation id="5895187275912066135">रोजी जारी केले</translation>
<translation id="5901630391730855834">पिवळा</translation>
@@ -1545,6 +1583,7 @@
<translation id="5921639886840618607">Google खातà¥à¤¯à¤¾à¤¤ कारà¥à¤¡ सेवà¥à¤¹ करायचे?</translation>
<translation id="5922853866070715753">जवळजवळ पूरà¥à¤£ à¤à¤¾à¤²à¥‡</translation>
<translation id="5932224571077948991">साइट अनाहूत किंवा दिशाभूल करणाऱà¥à¤¯à¤¾ जाहिराती दाखवते</translation>
+<translation id="5938153366081463283">वà¥à¤¹à¤°à¥à¤šà¥à¤¯à¥à¤…ल कारà¥à¤¡ जोडा</translation>
<translation id="5938793338444039872">टà¥à¤°à¥‰à¤¯</translation>
<translation id="5946937721014915347"><ph name="SITE_NAME" /> उघडत आहे…</translation>
<translation id="5951495562196540101">उपभोकà¥à¤¤à¤¾ खातà¥à¤¯à¤¾à¤¨à¥‡ नोंदणी करू शकत नाही (पॅकेज केलेला परवाना उपलबà¥à¤§).</translation>
@@ -1609,6 +1648,7 @@
<translation id="6120179357481664955">तà¥à¤®à¤šà¤¾ UPI आयडी लकà¥à¤·à¤¾à¤¤ ठेवायचा आहे का?</translation>
<translation id="6124432979022149706">Chrome à¤à¤‚टरपà¥à¤°à¤¾à¤‡à¤ कनेकà¥à¤Ÿà¤°</translation>
<translation id="6127379762771434464">आयटम काढला</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Chrome मधील गà¥à¤ªà¥à¤¤ मोडबदà¥à¤¦à¤² अधिक जाणून घà¥à¤¯à¤¾<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">कोणतà¥à¤¯à¤¾à¤¹à¥€ केबल तपासा आणि कोणतेही राउटर, मोडेम किंवा तà¥à¤®à¥à¤¹à¥€
वापरत असलेले
अनà¥à¤¯ नेटवरà¥à¤• डिवà¥à¤¹à¤¾à¤‡à¤¸à¥‡à¤¸ रीबूट करा.</translation>
@@ -1622,7 +1662,6 @@
<translation id="6169916984152623906">आता तà¥à¤®à¥à¤¹à¥€ खाजगीरितà¥à¤¯à¤¾ बà¥à¤°à¤¾à¤‰à¤ करू शकता आणि हे डिवà¥à¤¹à¤¾à¤‡à¤¸ वापरणारे इतर लोक तà¥à¤®à¤šà¥‡ कà¥à¤°à¤¿à¤¯à¤¾à¤•à¤²à¤¾à¤ª पाहू शकणार नाहीत. तथापि, डाउनलोड आणि बà¥à¤•à¤®à¤¾à¤°à¥à¤• सेवà¥à¤¹ केले जातील.</translation>
<translation id="6177128806592000436">या साइटवरील तà¥à¤®à¤šà¥‡ कनेकà¥à¤¶à¤¨ सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ नाही</translation>
<translation id="6180316780098470077">दोन पà¥à¤°à¤¯à¤¤à¥à¤¨à¤¾à¤‚मधील मधà¥à¤¯à¤¾à¤‚तर</translation>
-<translation id="619448280891863779">तà¥à¤®à¤šà¥à¤¯à¤¾ सà¥à¤•à¥à¤°à¥€à¤¨à¤µà¤° विंडो उघडणà¥à¤¯à¤¾à¤šà¥€ आणि ठेवणà¥à¤¯à¤¾à¤šà¥€ विनंती करू शकते</translation>
<translation id="6196640612572343990">तृतीय-पकà¥à¤· कà¥à¤•à¥€à¤œ अवरोधित करा</translation>
<translation id="6203231073485539293">तà¥à¤®à¤šà¥‡ इंटरनेट कनेकà¥à¤¶à¤¨ तपासा</translation>
<translation id="6218753634732582820">Chromium वरून पतà¥à¤¤à¤¾ काढून टाकायचा?</translation>
@@ -1645,7 +1684,7 @@
<translation id="6272383483618007430">Google Update</translation>
<translation id="6276112860590028508">आपलà¥à¤¯à¤¾ वाचन सूचीमधील पेज येथे दिसतात</translation>
<translation id="627746635834430766">पà¥à¤¢à¥€à¤² वेळी जलद पेमेंट देणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€, तà¥à¤®à¤šà¥à¤¯à¤¾ Google खातà¥à¤¯à¤¾à¤µà¤° तà¥à¤®à¤šà¥‡ कारà¥à¤¡ आणि बिलिंग पतà¥à¤¤à¤¾ सेवà¥à¤¹ करा.</translation>
-<translation id="6279098320682980337">वà¥à¤¹à¤°à¥à¤šà¥à¤¯à¥à¤…ल कारà¥à¤¡ नंबर भरला नाही का? कॉपी करणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ कारà¥à¤¡à¤šà¥à¤¯à¤¾ तपशिलांवर कà¥à¤²à¤¿à¤• करा</translation>
+<translation id="6279183038361895380">तà¥à¤®à¤šà¤¾ करà¥à¤¸à¤° दरà¥à¤¶à¤µà¤¿à¤£à¥â€à¤¯à¤¾à¤¸à¤¾à¤ à¥€ |<ph name="ACCELERATOR" />| दाबा</translation>
<translation id="6280223929691119688">या पतà¥à¤¤à¥à¤¯à¤¾à¤µà¤° देऊ शकत नाही. वेगळा पतà¥à¤¤à¤¾ निवडा.</translation>
<translation id="6282194474023008486">पोसà¥à¤Ÿà¤² कोड</translation>
<translation id="6285507000506177184">Chrome मधील डाउनलोड वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¿à¤¤ करा बटण, तà¥à¤®à¥à¤¹à¥€ Chrome मधà¥à¤¯à¥‡ डाउनलोड केलेलà¥à¤¯à¤¾ फाइल वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¿à¤¤ करणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€, à¤à¤‚टर दाबा</translation>
@@ -1653,6 +1692,7 @@
<translation id="6290238015253830360">तà¥à¤®à¥à¤¹à¥€ सà¥à¤šà¤µà¤¿à¤²à¥‡à¤²à¥‡ लेख येथे दिसतील</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{Your device will restart now}=1{तà¥à¤®à¤šà¥‡ डिवà¥à¤¹à¤¾à¤‡à¤¸ à¤à¤•à¤¾ सेकंदामधà¥à¤¯à¥‡ रीसà¥à¤Ÿà¤¾à¤°à¥à¤Ÿ होईल}other{तà¥à¤®à¤šà¥‡ डिवà¥à¤¹à¤¾à¤‡à¤¸ # सेकंदांमधà¥à¤¯à¥‡ रीसà¥à¤Ÿà¤¾à¤°à¥à¤Ÿ होईल}}</translation>
<translation id="6302269476990306341">Chrome मधील Google असिसà¥à¤Ÿà¤‚ट थांबत आहे</translation>
<translation id="6305205051461490394"><ph name="URL" /> आवाकà¥à¤¯à¤¾à¤¬à¤¾à¤¹à¥‡à¤° आहे.</translation>
<translation id="6312113039770857350">वेबपेज उपलबà¥à¤§ नाही</translation>
@@ -1726,6 +1766,7 @@
<translation id="6529602333819889595">&amp;पà¥à¤¨à¥à¤¹à¤¾ करा हटवा</translation>
<translation id="6545864417968258051">बà¥à¤²à¥‚टूथ सà¥à¤•à¥…न करत आहे</translation>
<translation id="6547208576736763147">डà¥à¤¯à¥à¤…ल पंच लेफà¥à¤Ÿ</translation>
+<translation id="6554732001434021288"><ph name="NUM_DAYS" /> दिवसांपूरà¥à¤µà¥€ शेवटची भेट दिली</translation>
<translation id="6556866813142980365">पà¥à¤¨à¥à¤¹à¤¾ करा</translation>
<translation id="6569060085658103619">तà¥à¤®à¥à¤¹à¥€ à¤à¤• à¤à¤•à¥à¤¸à¥à¤Ÿà¥‡à¤‚शन पेज पाहत आहात</translation>
<translation id="6573200754375280815">डà¥à¤¯à¥à¤…ल पंच राइट</translation>
@@ -1786,7 +1827,6 @@
<translation id="6757797048963528358">तà¥à¤®à¤šà¥‡ डिवà¥à¤¹à¤¾à¤‡à¤¸ निषà¥à¤•à¥à¤°à¥€à¤¯ à¤à¤¾à¤²à¥‡.</translation>
<translation id="6767985426384634228">पतà¥à¤¤à¤¾ अपडेट करायचा आहे का?</translation>
<translation id="6768213884286397650">Hagaki (Postcard)</translation>
-<translation id="6774185088257932239">गà¥à¤ªà¥à¤¤ मोडविषयी <ph name="BEGIN_LINK" />अधिक जाणून घà¥à¤¯à¤¾<ph name="END_LINK" /></translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">जांभळा</translation>
<translation id="6786747875388722282">विसà¥à¤¤à¤¾à¤°</translation>
@@ -1870,7 +1910,6 @@
<translation id="706295145388601875">Chrome सेटिंगà¥à¤œà¤®à¤§à¥à¤¯à¥‡ ॲडà¥à¤°à¥‡à¤¸ जोडा आणि वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¿à¤¤ करा</translation>
<translation id="7064851114919012435">संपरà¥à¤• माहिती</translation>
<translation id="7068733155164172741"><ph name="OTP_LENGTH" /> - अंकी कोड à¤à¤‚टर करा</translation>
-<translation id="7070090581017165256">या साइटविषयी</translation>
<translation id="70705239631109039">तà¥à¤®à¤šà¥‡ कनेकà¥à¤¶à¤¨ पूरà¥à¤£à¤ªà¤£à¥‡ सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ नाही</translation>
<translation id="7075452647191940183">विनंती खूपच मोठी आहे</translation>
<translation id="7079718277001814089">या साइटमधà¥à¤¯à¥‡ मालवेअर आहे</translation>
@@ -1887,6 +1926,12 @@
<translation id="7111012039238467737">(वैध)</translation>
<translation id="7118618213916969306">कà¥à¤²à¤¿à¤ªà¤¬à¥‹à¤°à¥à¤¡ URL, <ph name="SHORT_URL" /> शोधा</translation>
<translation id="7119414471315195487">अनà¥à¤¯ टॅब आणि पà¥à¤°à¥‹à¤—à¥à¤°à¤¾à¤® बंद करा</translation>
+<translation id="7129355289156517987">तà¥à¤®à¥à¤¹à¥€ Chromium मधील सरà¥à¤µ गà¥à¤ªà¥à¤¤ टॅब बंद करता, तेवà¥à¤¹à¤¾ तà¥à¤¯à¤¾ टॅबमधील तà¥à¤®à¤šà¥€ अâ€à¥…कà¥à¤Ÿà¤¿à¤µà¥à¤¹à¤¿à¤Ÿà¥€ ही या डिवà¥à¤¹à¤¾à¤‡à¤¸à¤µà¤°à¥‚न साफ केली जाते:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />बà¥à¤°à¤¾à¤‰à¤à¤¿à¤‚ग अâ€à¥…कà¥à¤Ÿà¤¿à¤µà¥à¤¹à¤¿à¤Ÿà¥€<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />शोध इतिहास<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />फॉरà¥à¤®à¤®à¤§à¥à¤¯à¥‡ à¤à¤‚टर केलेली माहिती<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">या पतà¥à¤¤à¥à¤¯à¤¾à¤µà¤° पाठवू शकत नाही. वेगळा पतà¥à¤¤à¤¾ निवडा.</translation>
<translation id="7132939140423847331">तà¥à¤®à¤šà¥à¤¯à¤¾ ॲडमिनने हा डेटा कॉपी करणà¥à¤¯à¤¾à¤ªà¤¾à¤¸à¥‚न पà¥à¤°à¤¤à¤¿à¤¬à¤‚धित केले आहे.</translation>
<translation id="7135130955892390533">सà¥à¤¥à¤¿à¤¤à¥€ दाखवा</translation>
@@ -1909,6 +1954,7 @@
<translation id="7192203810768312527"><ph name="SIZE" /> जागा मोकळी करते. काही साइट तà¥à¤®à¤šà¥à¤¯à¤¾ पà¥à¤¢à¥€à¤² भेटीचà¥à¤¯à¤¾ वेळी आणखी धीमà¥à¤¯à¤¾ गतीने लोड होऊ शकतात.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">तà¥à¤®à¤šà¤¾ अâ€à¥…डमिनिसà¥à¤Ÿà¥à¤°à¥‡à¤Ÿà¤° हे पाहू शकतो:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, खाजगीरीतà¥à¤¯à¤¾ बà¥à¤°à¤¾à¤‰à¤ करणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ नवीन गà¥à¤ªà¥à¤¤ टॅब उघडणà¥à¤¯à¤¾à¤•à¤°à¤¿à¤¤à¤¾ टॅब आणि तà¥à¤¯à¤¾à¤¨à¤‚तर à¤à¤‚टर दाबा</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> नी सà¥à¤°à¤•à¥à¤·à¤¿à¤¤à¤¤à¤¾ मानकांचे पालन केले नाही.</translation>
<translation id="7210993021468939304">कंटेनरमधील Linux अâ€à¥…कà¥à¤Ÿà¤¿à¤µà¥à¤¹à¤¿à¤Ÿà¥€ आणि कंटेनरमधà¥à¤¯à¥‡ Linux अâ€à¥…पà¥à¤¸ इंसà¥à¤Ÿà¥‰à¤² आणि रन करू शकते</translation>
@@ -1940,6 +1986,7 @@
<translation id="7304562222803846232">Google खाते ची गोपनीयता सेटिंगà¥à¤œ वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¿à¤¤ करा</translation>
<translation id="7305756307268530424">धीमà¥à¤¯à¤¾ गतीने सà¥à¤°à¥‚ करा</translation>
<translation id="7308436126008021607">बॅकगà¥à¤°à¤¾à¤‰à¤‚ड सिंक</translation>
+<translation id="7310392214323165548">डिवà¥à¤¹à¤¾à¤‡à¤¸ लवकरच रीसà¥à¤Ÿà¤¾à¤°à¥à¤Ÿ होईल</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">कनेकà¥à¤¶à¤¨ मदत</translation>
<translation id="7323804146520582233">"<ph name="SECTION" />" विभाग लपवा</translation>
@@ -1947,6 +1994,7 @@
<translation id="7334320624316649418">&amp;पà¥à¤¨à¤°à¥à¤•à¥à¤°à¤®à¤¿à¤¤ करा पà¥à¤¨à¥à¤¹à¤¾ करा</translation>
<translation id="7335157162773372339">तà¥à¤®à¤šà¤¾ कॅमेरा वापरणà¥à¤¯à¤¾à¤šà¥€ विनंती करू शकते</translation>
<translation id="7337248890521463931">आणखी रेषा दाखवा</translation>
+<translation id="7337418456231055214">वà¥à¤¹à¤°à¥à¤šà¥à¤¯à¥à¤…ल कारà¥à¤¡ नंबर भरला नाही का? कॉपी करणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ कारà¥à¤¡à¤šà¥à¤¯à¤¾ तपशिलांवर कà¥à¤²à¤¿à¤• करा. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">तà¥à¤®à¤šà¥à¤¯à¤¾ पà¥à¤²à¥…टफॉरà¥à¤®à¤µà¤° उपलबà¥à¤§ नाही.</translation>
<translation id="733923710415886693">सरà¥à¤Ÿà¤¿à¤«à¤¿à¤•à¥‡à¤Ÿ पारदरà¥à¤¶à¤•à¤¤à¥‡à¤…ंतरà¥à¤—त सरà¥à¤µà¥à¤¹à¤°à¤šà¥‡ सरà¥à¤Ÿà¤¿à¤«à¤¿à¤•à¥‡à¤Ÿ उघड केले नाही.</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1969,6 +2017,7 @@
<translation id="7378627244592794276">नाही</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">लागू नाही</translation>
+<translation id="7388594495505979117">{0,plural, =1{तà¥à¤®à¤šà¥‡ डिवà¥à¤¹à¤¾à¤‡à¤¸ à¤à¤•à¤¾ मिनिटामधà¥à¤¯à¥‡ रीसà¥à¤Ÿà¤¾à¤°à¥à¤Ÿ होईल}other{तà¥à¤®à¤šà¥‡ डिवà¥à¤¹à¤¾à¤‡à¤¸ # मिनिटांमधà¥à¤¯à¥‡ रीसà¥à¤Ÿà¤¾à¤°à¥à¤Ÿ होईल}}</translation>
<translation id="7390545607259442187">कारà¥à¤¡à¤šà¥€ पà¥à¤·à¥à¤Ÿà¥€ करा</translation>
<translation id="7392089738299859607">पतà¥à¤¤à¤¾ अपडेट करा</translation>
<translation id="7399802613464275309">सà¥à¤°à¤•à¥à¤·à¤¿à¤¤à¤¤à¤¾ तपासणी</translation>
@@ -2005,6 +2054,12 @@
<translation id="7485870689360869515">डेटा आढळला नाही.</translation>
<translation id="7495528107193238112">हा आशय बà¥à¤²à¥‰à¤• केला गेला आहे. समसà¥à¤¯à¥‡à¤šà¥‡ निराकरण करणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ साइटचà¥à¤¯à¤¾ मालकाशी संपरà¥à¤• साधा.</translation>
<translation id="7497998058912824456">दसà¥à¤¤à¤à¤µà¤œ तयार करा बटण, नवीन Google दसà¥à¤¤à¤à¤µà¤œ à¤à¤Ÿà¤ªà¤Ÿ तयार करणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ à¤à¤‚टर दाबा</translation>
+<translation id="7506488012654002225">Chromium हे पà¥à¤¢à¥€à¤² माहिती <ph name="BEGIN_EMPHASIS" />सेवà¥à¤¹ करणार नाही<ph name="END_EMPHASIS" />:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />तà¥à¤®à¤šà¤¾ बà¥à¤°à¤¾à¤‰à¤à¤¿à¤‚ग इतिहास
+ <ph name="LIST_ITEM" />कà¥à¤•à¥€ आणि साइट डेटा
+ <ph name="LIST_ITEM" />फॉरà¥à¤®à¤®à¤§à¥à¤¯à¥‡ à¤à¤‚टर केलेली माहिती
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">परत केलेला धोरण डिवà¥à¤¹à¤¾à¤‡à¤¸ आयडी रिकà¥à¤¤ आहे किंवा वरà¥à¤¤à¤®à¤¾à¤¨ डिवà¥à¤¹à¤¾à¤‡à¤¸ आयडी शी जà¥à¤³à¤¤ नाही</translation>
<translation id="7508870219247277067">हिरवे पिवळे</translation>
<translation id="7511955381719512146">तà¥à¤®à¥à¤¹à¥€ वापरत असलेलà¥à¤¯à¤¾ वाय-फाय ला तà¥à¤®à¥à¤¹à¥€ <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> ला भेट देणà¥à¤¯à¤¾à¤šà¥€ आवशà¥à¤¯à¤•à¤¤à¤¾ असू शकते.</translation>
@@ -2118,7 +2173,6 @@
<translation id="7813600968533626083">Chrome मधून सूचना फॉरà¥à¤® काढून टाकायचा?</translation>
<translation id="781440967107097262">कà¥à¤²à¤¿à¤ªà¤¬à¥‹à¤°à¥à¤¡ शेअर करायचा का?</translation>
<translation id="7815407501681723534">'<ph name="SEARCH_STRING" />' साठी <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> सापडले</translation>
-<translation id="782125616001965242">या साइटविषयीची माहिती दाखवा</translation>
<translation id="782886543891417279">तà¥à¤®à¥à¤¹à¥€ वापरत असलेलà¥à¤¯à¤¾ (<ph name="WIFI_NAME" />) वाय-फाय चà¥à¤¯à¤¾ लॉग इन पेजला तà¥à¤®à¥à¤¹à¤¾à¤²à¤¾ भेट देणà¥à¤¯à¤¾à¤šà¥€ आवशà¥à¤¯à¤•à¤¤à¤¾ असू शकते.</translation>
<translation id="7836231406687464395">Postfix (Envelope)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{काहीही नाही}=1{à¤à¤• अâ€à¥…प <ph name="EXAMPLE_APP_1" />}=2{२ अâ€à¥…पà¥à¤¸ <ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />}other{# अâ€à¥…पà¥à¤¸ <ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />}}</translation>
@@ -2135,7 +2189,6 @@
<translation id="7888575728750733395">पà¥à¤°à¤¸à¥à¤¤à¥à¤¤à¥€à¤•à¤°à¤£ इंटेंट पà¥à¤°à¤¿à¤‚ट करा</translation>
<translation id="7894280532028510793">शबà¥à¤¦à¤²à¥‡à¤–न योगà¥à¤¯ असलà¥à¤¯à¤¾à¤¸, <ph name="BEGIN_LINK" />नेटवरà¥à¤• निदान रन करून पहा<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (Envelope)</translation>
-<translation id="7931318309563332511">अनोळखी</translation>
<translation id="793209273132572360">पतà¥à¤¤à¤¾ अपडेट करायचा आहे का?</translation>
<translation id="7932579305932748336">कोट</translation>
<translation id="79338296614623784">वैध फोन नंबर à¤à¤‚टर करा</translation>
@@ -2160,13 +2213,14 @@
<translation id="7976214039405368314">खूप जासà¥à¤¤ विनंतà¥à¤¯à¤¾</translation>
<translation id="7977538094055660992">आउटपà¥à¤Ÿ डिवà¥à¤¹à¤¾à¤‡à¤¸</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">यासह लिंक केलेले</translation>
<translation id="798134797138789862">आभासी वासà¥à¤¤à¤µà¤¿à¤•à¤¤à¤¾ डिवà¥à¤¹à¤¾à¤‡à¤¸ आणि डेटा वापरणà¥à¤¯à¤¾à¤šà¥€ विनंती करू शकते</translation>
<translation id="7984945080620862648">Chrome पà¥à¤°à¤•à¥à¤°à¤¿à¤¯à¤¾ करू शकत नसलेले न समजणारे कà¥à¤°à¥‡à¤¡à¥‡à¤¨à¥à¤¶à¤¿à¤¯à¤² वेबसाइटने पाठविलà¥à¤¯à¤¾à¤®à¥à¤³à¥‡ तà¥à¤®à¥à¤¹à¥€ आतà¥à¤¤à¤¾ <ph name="SITE" /> ला भेट देऊ शकत नाही. नेटवरà¥à¤• à¤à¤°à¤° आणि आकà¥à¤°à¤®à¤£à¤•à¤°à¥à¤¤à¥‡ सामानà¥à¤¯à¤¤à¤ƒ तातà¥à¤ªà¥à¤°à¤¤à¥‡ असतात, यामà¥à¤³à¥‡ हे पृषà¥à¤  कदाचित नंतर कारà¥à¤¯ करेल.</translation>
-<translation id="79859296434321399">ऑगमेंटेड रीअâ€à¥…लिटी आशय पाहणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€, ARCore इंसà¥à¤Ÿà¥‰à¤² करा</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">बाइंड</translation>
<translation id="7992044431894087211"><ph name="APPLICATION_TITLE" /> सोबत सà¥à¤•à¥à¤°à¥€à¤¨ शेअर करणे पà¥à¤¨à¥à¤¹à¤¾ सà¥à¤°à¥‚ केले</translation>
<translation id="7995512525968007366">नमूद केलेले नाही</translation>
+<translation id="7998269595945679889">गà¥à¤ªà¥à¤¤ टॅब उघडा बटण, खाजगीरीतà¥à¤¯à¤¾ बà¥à¤°à¤¾à¤‰à¤ करणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ नवीन गà¥à¤ªà¥à¤¤ टॅब उघडणà¥à¤¯à¤¾à¤•à¤°à¤¿à¤¤à¤¾ à¤à¤‚टर दाबा</translation>
<translation id="800218591365569300">मेमरी मोकळी करणà¥â€à¤¯à¤¾à¤¸à¤¾à¤ à¥€ अनà¥à¤¯ टॅब किंवा पà¥à¤°à¥‹à¤—à¥à¤°à¤¾à¤® बंद करून पहा.</translation>
<translation id="8004582292198964060">बà¥à¤°à¤¾à¤‰à¤à¤°</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{हे कारà¥à¤¡ आणि तà¥à¤¯à¤¾à¤šà¤¾ बिलिंग पतà¥à¤¤à¤¾ सेवà¥à¤¹ केला जाईल. <ph name="USER_EMAIL" /> मधà¥à¤¯à¥‡Â à¤¸à¤¾à¤‡à¤¨Â à¤‡à¤¨Â à¤•à¥‡à¤²à¥‡à¤²à¥‡Â à¤…सताना तà¥à¤®à¥à¤¹à¥€Â à¤¤à¥‡Â à¤µà¤¾à¤ªà¤°à¥‚ शकाल.}other{ही कारà¥à¤¡à¥‡ आणि तà¥à¤¯à¤¾à¤‚चे बिलिंग पतà¥à¤¤à¥‡ सेवà¥à¤¹ केले जातील. <ph name="USER_EMAIL" /> मधà¥à¤¯à¥‡Â à¤¸à¤¾à¤‡à¤¨Â à¤‡à¤¨Â à¤•à¥‡à¤²à¥‡à¤²à¥‡Â à¤…सताना तà¥à¤®à¥à¤¹à¥€Â à¤¤à¥€Â à¤µà¤¾à¤ªà¤°à¥‚ शकाल.}}</translation>
@@ -2226,6 +2280,7 @@
<translation id="8202370299023114387">विरोध</translation>
<translation id="8206978196348664717">Prc4 (Envelope)</translation>
<translation id="8211406090763984747">कनेकà¥à¤¶à¤¨ सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ आहे</translation>
+<translation id="8217240300496046857">साइट या तà¥à¤®à¤šà¤¾ संपूरà¥à¤£ वेबवर माग ठेवणाऱà¥à¤¯à¤¾ कà¥à¤•à¥€ वापरू शकत नाहीत. काही साइटवरील वैशिषà¥à¤Ÿà¥à¤¯à¤¾à¤‚मधà¥à¤¯à¥‡ खंड पडू शकतो.</translation>
<translation id="8218327578424803826">नियà¥à¤•à¥à¤¤ केलेले सà¥à¤¥à¤¾à¤¨:</translation>
<translation id="8220146938470311105">C7/C6 (Envelope)</translation>
<translation id="8225771182978767009">जà¥à¤¯à¤¾ वà¥à¤¯à¤•à¥à¤¤à¥€à¤¨à¥‡ हा कॉंपà¥à¤¯à¥à¤Ÿà¤° सेट केला तà¥à¤¯à¤¾ वà¥à¤¯à¤•à¥à¤¤à¥€à¤¨à¥‡ ही साइट बà¥à¤²à¥‰à¤• करणà¥à¤¯à¤¾à¤šà¥‡ निवडले आहे.</translation>
@@ -2266,14 +2321,9 @@
<translation id="830498451218851433">फोलà¥à¤¡ हाफ</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">इंसà¥à¤Ÿà¥‰à¤² केलेली अâ€à¥…पà¥à¤¸ आणि ती किती वेळा वापरली जातात</translation>
+<translation id="8317207217658302555">ARCore अपडेट करायचे आहे का?</translation>
<translation id="831997045666694187">संधà¥à¤¯à¤¾à¤•à¤¾à¤³à¥€</translation>
<translation id="8321476692217554900">सूचना</translation>
-<translation id="8328484624016508118">सरà¥à¤µ गà¥à¤ªà¥à¤¤ टॅब बंद केलà¥à¤¯à¤¾à¤¨à¤‚तर, Chrome हे साफ करते:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />या डिवà¥à¤¹à¤¾à¤‡à¤¸à¤µà¤°à¥€à¤² तà¥à¤®à¤šà¥€ बà¥à¤°à¤¾à¤‰à¤à¤¿à¤‚ग अâ€à¥…कà¥à¤Ÿà¤¿à¤µà¥à¤¹à¤¿à¤Ÿà¥€<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />या डिवà¥à¤¹à¤¾à¤‡à¤¸à¤µà¤°à¥€à¤² तà¥à¤®à¤šà¤¾ शोध इतिहास<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />फॉरà¥à¤®à¤®à¤§à¥à¤¯à¥‡ à¤à¤‚टर केलेली माहिती<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489"><ph name="HOST_NAME" /> चा ॲकà¥à¤¸à¥‡à¤¸ नाकारला</translation>
<translation id="833262891116910667">हायलाइट</translation>
<translation id="8339163506404995330"><ph name="LANGUAGE" />मधील पेज भाषांतरीत केले जाणार नाही</translation>
@@ -2325,6 +2375,7 @@
<translation id="8507227106804027148">कमांड लाइन</translation>
<translation id="8508648098325802031">शोध आयकन</translation>
<translation id="8511402995811232419">कà¥à¤•à¥€ वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¿à¤¤ करा</translation>
+<translation id="8519753333133776369">तà¥à¤®à¤šà¥à¤¯à¤¾ अâ€à¥…डमिनिसà¥à¤Ÿà¥à¤°à¥‡à¤Ÿà¤°à¤¨à¥‡ अनà¥à¤®à¤¤à¥€ दिलेले HID डिवà¥à¤¹à¤¾à¤‡à¤¸</translation>
<translation id="8522552481199248698">तà¥à¤®à¤šà¥à¤¯à¤¾ Google खातà¥à¤¯à¤¾à¤šà¥‡ संरकà¥à¤·à¤£ करणà¥à¤¯à¤¾à¤¤ आणि तà¥à¤®à¤šà¤¾ पासवरà¥à¤¡ बदलणà¥à¤¯à¤¾à¤¤ Chrome तà¥à¤®à¥à¤¹à¤¾à¤²à¤¾ मदत करू शकते.</translation>
<translation id="8530813470445476232">Chrome सेटिंगà¥à¤œà¤®à¤§à¥€à¤² तà¥à¤®à¤šà¤¾ बà¥à¤°à¤¾à¤‰à¤à¤¿à¤‚ग इतिहास, कà¥à¤•à¥€, कॅशे आणि बरेच काही साफ करा</translation>
<translation id="8533619373899488139">तà¥à¤®à¤šà¥à¤¯à¤¾ सिसà¥à¤Ÿà¤® अâ€à¥…डमिनिसà¥à¤Ÿà¥à¤°à¥‡à¤Ÿà¤°à¤¦à¥à¤µà¤¾à¤°à¥‡ बà¥à¤²à¥‰à¤• केलेलà¥à¤¯à¤¾ URL आणि लागू केलेली इतर धोरणे पाहणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ &lt;strong&gt;chrome://policy&lt;/strong&gt; ला भेट दà¥à¤¯à¤¾.</translation>
@@ -2336,7 +2387,6 @@
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{परवानगी रीसेट करा}other{परवानगà¥à¤¯à¤¾ रीसेट करा}}</translation>
<translation id="8555010941760982128">चेकआउट करताना हा कोड वापरा</translation>
<translation id="8557066899867184262">CVV तà¥à¤®à¤šà¥à¤¯à¤¾ कारà¥à¤¡à¤¾à¤šà¥à¤¯à¤¾ मागील बाजूस दिलेला असतो.</translation>
-<translation id="8558485628462305855">ऑगमेंटेड रीअâ€à¥…लिटी आशय पाहणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€, ARCore अपडेट करा</translation>
<translation id="8559762987265718583">आपलà¥à¤¯à¤¾ डिवà¥à¤¹à¤¾à¤‡à¤¸à¤šà¥€ तारीख आणि वेळ (<ph name="DATE_AND_TIME" />) चà¥à¤•à¥€à¤šà¥€ असलà¥à¤¯à¤¾à¤¨à¥‡ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> सह खाजगी कनेकà¥à¤¶à¤¨ इंसà¥à¤Ÿà¥‰à¤² केले जाऊ शकले नाही.</translation>
<translation id="8564182942834072828">वेगळे केलेले दसà¥à¤¤à¤à¤µà¤œ/संकलित न केलेलà¥à¤¯à¤¾ पà¥à¤°à¤¤à¥€</translation>
<translation id="8564985650692024650">जर तà¥à¤®à¥à¤¹à¥€ तà¥à¤®à¤šà¥à¤¯à¤¾ <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> पासवरà¥à¤¡à¤šà¤¾ इतर साइटवर पà¥à¤¨à¥à¤¹à¤¾ वापर केला असेल तर Chromium तà¥à¤®à¥à¤¹à¤¾à¤²à¤¾ तो रीसेट करणà¥à¤¯à¤¾à¤šà¥€ शिफारस करतो.</translation>
@@ -2355,6 +2405,7 @@
<translation id="865032292777205197">मोशन सेनà¥à¤¸à¤°</translation>
<translation id="8663226718884576429">ऑरà¥à¤¡à¤° सारांश, <ph name="TOTAL_LABEL" />, आणखी तपशील</translation>
<translation id="8666678546361132282">इंगà¥à¤°à¤œà¥€</translation>
+<translation id="8669306706049782872">विंडो उघडणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ आणि तà¥à¤¯à¤¾à¤‚चे सà¥à¤¥à¤¾à¤¨ नियोजित करणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ तà¥à¤®à¤šà¥à¤¯à¤¾ सà¥à¤•à¥à¤°à¥€à¤¨à¤¶à¥€ संबंधित माहिती वापरा</translation>
<translation id="867224526087042813">सà¥à¤µà¤¾à¤•à¥à¤·à¤°à¥€</translation>
<translation id="8676424191133491403">विलंब नाही</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, उतà¥à¤¤à¤°, <ph name="ANSWER" /></translation>
@@ -2381,6 +2432,7 @@
<translation id="8731544501227493793">पासवरà¥à¤¡ वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¿à¤¤ करा बटण, पाहणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ Enter दाबा आणि Chrome सेटिंगà¥à¤œà¤®à¤§à¥à¤¯à¥‡ तà¥à¤®à¤šà¥‡ पासवरà¥à¤¡ वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¿à¤¤ करा</translation>
<translation id="8734529307927223492">तà¥à¤®à¤šà¥‡ <ph name="DEVICE_TYPE" /> <ph name="MANAGER" /> दà¥à¤µà¤¾à¤°à¥‡ वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¿à¤¤ केले आहे</translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, खाजगीरीतà¥à¤¯à¤¾ बà¥à¤°à¤¾à¤‰à¤ करणà¥à¤¯à¤¾à¤¸à¤¾à¤ à¥€ नवीन गà¥à¤ªà¥à¤¤ विंडो उघडणà¥à¤¯à¤¾à¤•à¤°à¤¿à¤¤à¤¾ टॅब आणि तà¥à¤¯à¤¾à¤¨à¤‚तर à¤à¤‚टर दाबा</translation>
+<translation id="8737685506611670901"><ph name="REPLACED_HANDLER_TITLE" /> à¤à¤µà¤œà¥€ <ph name="PROTOCOL" /> लिंक उघडा</translation>
<translation id="8738058698779197622">à¤à¤• सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ कनेकà¥â€à¤¶à¤¨ सà¥â€à¤¥à¤¾à¤ªà¤¿à¤¤ करणà¥â€à¤¯à¤¾à¤ªà¥‚रà¥à¤µà¥€, तà¥à¤®à¤šà¥‡ घडà¥â€à¤¯à¤¾à¤³ योगà¥à¤¯à¤°à¤¿à¤¤à¥à¤¯à¤¾ सेट केले असणे आवशà¥à¤¯à¤• आहे. कारण वेबसाइट तà¥à¤¯à¤¾à¤‚ना सà¥â€à¤µà¤¤:ला ओळखणà¥â€à¤¯à¤¾à¤¸à¤¾à¤ à¥€ वापरलेली ती सरà¥à¤Ÿà¤¿à¤«à¤¿à¤•à¥‡à¤Ÿà¥‡ केवळ नमूद केलेलà¥â€à¤¯à¤¾ कालावधीसाठी वैध असतात. तà¥à¤®à¤šà¥à¤¯à¤¾ डिवà¥â€à¤¹à¤¾à¤‡à¤¸à¤šà¥‡ घडà¥â€à¤¯à¤¾à¤³ चà¥à¤•à¥€à¤šà¥‡ असलà¥â€à¤¯à¤¾à¤®à¥à¤³à¥‡, Chromium ला सरà¥à¤Ÿà¤¿à¤«à¤¿à¤•à¥‡à¤Ÿà¥‡ पडताळणी करता आले नाही.</translation>
<translation id="8740359287975076522"><ph name="HOST_NAME" />चा &lt;abbr id="dnsDefinition"&gt;DNS पतà¥à¤¤à¤¾&lt;/abbr&gt; शोधणे शकà¥à¤¯ à¤à¤¾à¤²à¥‡ नाही. समसà¥à¤¯à¥‡à¤šà¥‡ निराकरण करीत आहे.</translation>
<translation id="8742371904523228557"><ph name="ONE_TIME_CODE" /> हा तà¥à¤®à¤šà¤¾ <ph name="ORIGIN" />साठीचा कोड आहे</translation>
@@ -2408,6 +2460,7 @@
<translation id="883848425547221593">अनà¥à¤¯ बà¥à¤•à¤®à¤¾à¤°à¥à¤•</translation>
<translation id="884264119367021077">वहनावळ पतà¥à¤¤à¤¾</translation>
<translation id="884923133447025588">कोणतीही निरसà¥à¤¤ करणà¥à¤¯à¤¾à¤šà¥€ पà¥à¤°à¤£à¤¾à¤²à¥€ आढळली नाही.</translation>
+<translation id="8849262850971482943">अतिरिकà¥à¤¤ सà¥à¤°à¤•à¥à¤·à¥‡à¤¸à¤¾à¤ à¥€ तà¥à¤®à¤šà¥‡ वà¥à¤¹à¤°à¥à¤šà¥à¤¯à¥à¤…ल कारà¥à¤¡ वापरा</translation>
<translation id="885730110891505394">Google सह सामायिकरण</translation>
<translation id="8858065207712248076">जर तà¥à¤®à¥à¤¹à¥€ तà¥à¤®à¤šà¥à¤¯à¤¾ <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> पासवरà¥à¤¡à¤šà¤¾ इतर साइटवर पà¥à¤¨à¥à¤¹à¤¾ वापर केला असेल तर Chrome तà¥à¤®à¥à¤¹à¤¾à¤²à¤¾ तो रीसेट करणà¥à¤¯à¤¾à¤šà¥€ शिफारस करतो.</translation>
<translation id="885906927438988819">शबà¥à¤¦à¤²à¥‡à¤–न योगà¥à¤¯ असलà¥à¤¯à¤¾à¤¸, <ph name="BEGIN_LINK" />Windows नेटवरà¥à¤• निदान रन करून पहा<ph name="END_LINK" />.</translation>
@@ -2457,6 +2510,7 @@
<translation id="9004367719664099443">VR सेशन पà¥à¤°à¤—तीपथावर आहे</translation>
<translation id="9005998258318286617">पीडीà¤à¤« दसà¥à¤¤à¤à¤µà¤œ लोड करणà¥à¤¯à¤¾à¤¤ अपयश आले.</translation>
<translation id="9008201768610948239">दà¥à¤°à¥à¤²à¤•à¥à¤· करा</translation>
+<translation id="901834265349196618">ईमेल</translation>
<translation id="9020200922353704812">कारà¥à¤¡ बिलिंग पतà¥à¤¤à¤¾ आवशà¥à¤¯à¤• आहे</translation>
<translation id="9020542370529661692">हे पृषà¥à¤  <ph name="TARGET_LANGUAGE" /> मधà¥à¤¯à¥‡ भाषांतरित केले गेले आहे.</translation>
<translation id="9020742383383852663">A8</translation>
@@ -2505,6 +2559,7 @@
<translation id="9150045010208374699">तà¥à¤®à¤šà¤¾ कॅमेरा वापरा</translation>
<translation id="9150685862434908345">तà¥à¤®à¤šà¤¾ अâ€à¥…डमिनिसà¥à¤Ÿà¥à¤°à¥‡à¤Ÿà¤° तà¥à¤®à¤šà¥à¤¯à¤¾ बà¥à¤°à¤¾à¤‰à¤à¤°à¤šà¤¾ सेटअप रिमोट पदà¥à¤§à¤¤à¥€à¤¨à¥‡ बदलू शकतो. या डिवà¥à¤¹à¤¾à¤‡à¤¸à¤µà¤°à¥€à¤² अâ€à¥…कà¥à¤Ÿà¤¿à¤µà¥à¤¹à¤¿à¤Ÿà¥€ Chrome चà¥à¤¯à¤¾ बाहेरदेखील वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¿à¤¤ केलेली असू शकते. <ph name="BEGIN_LINK" />अधिक जाणून घà¥à¤¯à¤¾<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">अपडेट केलेले</translation>
+<translation id="9155211586651734179">ऑडिओ उपकरणे कनेकà¥à¤Ÿ केली</translation>
<translation id="9157595877708044936">सेट अप करीत आहे...</translation>
<translation id="9158625974267017556">C6 (Envelope)C6 (Envelope)</translation>
<translation id="9164029392738894042">अचूकतेची तपासणी</translation>
diff --git a/chromium/components/strings/components_strings_ms.xtb b/chromium/components/strings/components_strings_ms.xtb
index c06634279e0..860b9923778 100644
--- a/chromium/components/strings/components_strings_ms.xtb
+++ b/chromium/components/strings/components_strings_ms.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">Lihat butiran</translation>
<translation id="1030706264415084469"><ph name="URL" /> mahu menyimpan data bersaiz besar pada peranti anda secara kekal</translation>
<translation id="1032854598605920125">Putar ikut arah jam</translation>
+<translation id="1033329911862281889">Inkognito tidak menjadikan anda halimunan dalam talian:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Laman dan perkhidmatan yang mereka gunakan boleh melihat lawatan<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Majikan atau institusi pengajian boleh menjejak aktiviti penyemakan imbas<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Penyedia perkhidmatan Internet boleh memantau trafik web<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">Matikan</translation>
<translation id="1036982837258183574">Tekan |<ph name="ACCELERATOR" />| untuk keluar daripada skrin penuh</translation>
<translation id="1038106730571050514">Tunjukkan cadangan</translation>
<translation id="1038842779957582377">nama tidak diketahui</translation>
<translation id="1041998700806130099">Mesej helaian tugas</translation>
<translation id="1048785276086539861">Apabila anda mengedit anotasi, dokumen ini akan kembali kepada paparan satu halaman</translation>
-<translation id="1049743911850919806">Inkognito</translation>
<translation id="1050038467049342496">Tutup apl lain</translation>
<translation id="1055184225775184556">&amp;Buat Asal Tambahkan</translation>
<translation id="1056898198331236512">Amaran</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">Cache dasar OK</translation>
<translation id="1130564665089811311">Butang terjemah halaman, tekan Enter untuk menterjemah halaman ini dengan Google Terjemah</translation>
<translation id="1131264053432022307">Imej yang Anda Salin</translation>
+<translation id="1142846828089312304">Sekat kuki pihak ketiga dalam Inkognito</translation>
<translation id="1150979032973867961">Pelayan ini tidak dapat membuktikan bahawa domainnya ialah <ph name="DOMAIN" />; sijil keselamatannya tidak dipercayai oleh sistem pengendalian komputer anda. Ini mungkin disebabkan oleh kesilapan konfigurasi atau penyerang yang memintasi sambungan anda.</translation>
<translation id="1151972924205500581">Kata laluan diperlukan</translation>
<translation id="1156303062776767266">Anda sedang melihat fail setempat atau yang dikongsi</translation>
@@ -64,7 +70,6 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="1178581264944972037">Jeda</translation>
<translation id="1181037720776840403">Alih keluar</translation>
<translation id="1186201132766001848">Semak Kata Laluan</translation>
-<translation id="1195210374336998651">Pergi ke tetapan apl</translation>
<translation id="1195558154361252544">Pemberitahuan disekat secara automatik untuk semua tapak kecuali tapak yang anda benarkan</translation>
<translation id="1197088940767939838">Oren</translation>
<translation id="1201402288615127009">Seterusnya</translation>
@@ -111,7 +116,7 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="1307966114820526988">Ciri yang Ditamatkan</translation>
<translation id="1308113895091915999">Tawaran tersedia</translation>
<translation id="1312803275555673949">Apakah bukti yang menyokongnya?</translation>
-<translation id="131405271941274527"><ph name="URL" /> mahu menghantar dan menerima maklumat apabila anda mengetik telefon anda pada peranti NFC</translation>
+<translation id="1314311879718644478">Lihat kandungan realiti terimbuh</translation>
<translation id="1314509827145471431">Ikatan kanan</translation>
<translation id="1318023360584041678">Disimpan dalam kumpulan tab</translation>
<translation id="1319245136674974084">Jangan tanya lagi untuk apl ini</translation>
@@ -161,6 +166,7 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="142858679511221695">Pengguna awan</translation>
<translation id="1428729058023778569">Anda melihat amaran ini kerana laman ini tidak menyokong HTTPS. <ph name="BEGIN_LEARN_MORE_LINK" />Ketahui lebih lanjut<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">Cetak</translation>
+<translation id="1432187715652018471">halaman mahu memasang pengendali perkhidmatan.</translation>
<translation id="1432581352905426595">Urus enjin carian</translation>
<translation id="1436185428532214179">Boleh meminta untuk mengedit fail dan folder pada peranti anda</translation>
<translation id="1442386063175183758">Lipatan pintu kanan</translation>
@@ -181,6 +187,12 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="1483493594462132177">Hantar</translation>
<translation id="1484290072879560759">Pilih Alamat Pengiriman</translation>
<translation id="1492194039220927094">Penolakan dasar:</translation>
+<translation id="149293076951187737">Apabila anda menutup semua tab Inkognito Chrome, aktiviti anda dalam tab tersebut dikosongkan daripada peranti ini:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Aktiviti penyemakan imbas<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Sejarah carian<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Maklumat yang dimasukkan dalam borang<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">Kembali ke tab</translation>
<translation id="1501859676467574491">Tunjukkan kad daripada Akaun Google anda</translation>
<translation id="1507202001669085618">&lt;p&gt;Anda akan melihat ralat ini jika menggunakan portal Wi-Fi yang menghendaki anda untuk log masuk sebelum boleh masuk dalam talian.&lt;/p&gt;
@@ -208,6 +220,8 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="1559572115229829303">&lt;p&gt;Sambungan peribadi ke <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> tidak boleh diwujudkan kerana tarikh dan masa peranti anda (<ph name="DATE_AND_TIME" />) tidak betul.&lt;/p&gt;
&lt;p&gt;Sila laraskan tarikh dan masa daripada bahagian &lt;strong&gt;Umum&lt;/strong&gt; bagi apl &lt;strong&gt;Tetapan&lt;/strong&gt;.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">Pentadbir anda akan memulakan semula peranti anda pada <ph name="DATE" /> jam <ph name="TIME" /></translation>
+<translation id="156703335097561114">Maklumat rangkaian seperti alamat, konfigurasi antara muka dan kualiti sambungan</translation>
<translation id="1567040042588613346">Dasar ini berfungsi seperti yang diharapkan tetapi nilai yang sama ditetapkan di tempat lain dan digantikan oleh dasar ini.</translation>
<translation id="1569487616857761740">Masukkan tarikh tamat tempoh</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="1583429793053364125">Kesilapan berlaku semasa memaparkan halaman web ini.</translation>
<translation id="1586541204584340881">Sambungan yang telah anda pasang</translation>
<translation id="1588438908519853928">Biasa</translation>
+<translation id="1589050138437146318">Pasang ARCore?</translation>
<translation id="1592005682883173041">Akses Data Setempat</translation>
<translation id="1594030484168838125">Pilih</translation>
<translation id="160851722280695521">Main permainan Dino Run dalam Chrome</translation>
@@ -254,7 +269,7 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="1711234383449478798">Diabaikan kerana <ph name="POLICY_NAME" /> tidak ditetapkan kepada <ph name="VALUE" />.</translation>
<translation id="1712552549805331520"><ph name="URL" /> mahu menyimpan data pada komputer setempat anda secara kekal</translation>
<translation id="1713628304598226412">Dulang 2</translation>
-<translation id="1715874602234207">F</translation>
+<translation id="1715874602234207">J</translation>
<translation id="1717218214683051432">Penderia gerakan</translation>
<translation id="1717494416764505390">Peti mel 3</translation>
<translation id="1718029547804390981">Dokumen terlalu besar untuk dianotasikan</translation>
@@ -283,6 +298,7 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
pengepala tersebut telah rosak dan menghalang penyemak imbas daripada memenuhi
permintaan anda untuk <ph name="SITE" />. Dasar asal boleh digunakan oleh
pengendali tapak untuk mengkonfigurasi keselamatan dan sifat lain bagi tapak.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Ketahui lebih lanjut tentang Inkognito dalam Chromium<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">Tab yang dibuka dipaparkan di sini</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -410,6 +426,7 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="22081806969704220">Dulang 3</translation>
<translation id="2212735316055980242">Dasar tidak dijumpai</translation>
<translation id="2213606439339815911">Mengambil entri…</translation>
+<translation id="2213612003795704869">Halaman dicetak</translation>
<translation id="2215727959747642672">Pengeditan fail</translation>
<translation id="2218879909401188352">Penyerang yang berada di <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> boleh memasang apl berbahaya yang boleh merosakkan peranti anda, menambahkan caj yang tersembunyi pada bil mudah alih anda atau mencuri maklumat peribadi anda. <ph name="BEGIN_LEARN_MORE_LINK" />Ketahui lebih lanjut<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">Tiada Internet</translation>
@@ -419,6 +436,7 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="2248949050832152960">Gunakan WebAuthn</translation>
<translation id="2250931979407627383">Jahitan tepi kiri</translation>
<translation id="225207911366869382">Nilai ini tidak lagi digunakan untuk dasar ini.</translation>
+<translation id="2256115617011615191">Mulakan semula sekarang</translation>
<translation id="2258928405015593961">Masukkan tarikh tamat tempoh pada masa hadapan dan cuba lagi</translation>
<translation id="225943865679747347">Kod ralat: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">Ralat HTTP</translation>
@@ -446,6 +464,7 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="2337852623177822836">Tetapan dikawal oleh pentadbir anda</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> mahu digandingkan</translation>
<translation id="2346319942568447007">Imej yang anda salin</translation>
+<translation id="2350796302381711542">Benarkan <ph name="HANDLER_HOSTNAME" /> untuk membuka semua <ph name="PROTOCOL" /> pautan dan bukannya <ph name="REPLACED_HANDLER_TITLE" />?</translation>
<translation id="2354001756790975382">Penanda halaman lain</translation>
<translation id="2354430244986887761">Penyemakan Imbas Selamat Google <ph name="BEGIN_LINK" />menemui apl yang memudaratkan<ph name="END_LINK" /> di <ph name="SITE" /> baru-baru ini.</translation>
<translation id="2355395290879513365">Penyerang mungkin dapat melihat imej yang anda lihat di tapak ini dan menipu anda dengan mengubah suainya.</translation>
@@ -471,6 +490,7 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="2413528052993050574">Pelayan ini tidak dapat membuktikan bahawa domainnya ialah <ph name="DOMAIN" />; sijil keselamatannya mungkin dibatalkan. Ini mungkin disebabkan oleh kesilapan konfigurasi atau penyerang yang memintasi sambungan anda.</translation>
<translation id="2414886740292270097">Gelap</translation>
<translation id="2430968933669123598">Urus Google Account, tekan kekunci Enter untuk mengurus maklumat, privasi dan keselamatan anda dalam Google Account</translation>
+<translation id="2436186046335138073">Benarkan <ph name="HANDLER_HOSTNAME" /> untuk membuka semua <ph name="PROTOCOL" /> pautan?</translation>
<translation id="2438874542388153331">Empat tebukan kanan</translation>
<translation id="2450021089947420533">Perjalanan</translation>
<translation id="2463739503403862330">Isi</translation>
@@ -478,6 +498,7 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="2465655957518002998">Pilih Kaedah Penghantaran</translation>
<translation id="2465688316154986572">Kokot</translation>
<translation id="2465914000209955735">Urus fail yang telah anda muat turun dalam Chrome</translation>
+<translation id="2466004615675155314">Tunjukkan maklumat daripada web</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Jalankan Diagnostik Rangkaian<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">Susunan 1-ke-N</translation>
<translation id="2470767536994572628">Apabila anda mengedit anotasi, dokumen ini akan kembali kepada paparan satu halaman dan putaran asalnya</translation>
@@ -498,6 +519,7 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="2523886232349826891">Disimpan pada peranti ini sahaja</translation>
<translation id="2524461107774643265">Tambahkan Maklumat Lanjut</translation>
<translation id="2529899080962247600">Medan ini tidak boleh mengandungi lebih daripada <ph name="MAX_ITEMS_LIMIT" /> entri. Semua entri berikutnya akan diabaikan.</translation>
+<translation id="2535585790302968248">Buka tab Inkognito baharu untuk menyemak imbas secara peribadi</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{dan 1 lagi}other{dan # lagi}}</translation>
<translation id="2536110899380797252">Tambahkan Alamat</translation>
<translation id="2539524384386349900">Kesan</translation>
@@ -523,7 +545,14 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="2597378329261239068">Dokumen ini dilindungi kata laluan. Sila masukkan kata laluan.</translation>
<translation id="2609632851001447353">Variasi</translation>
<translation id="2610561535971892504">Klik untuk menyalin</translation>
+<translation id="2617988307566202237">Chrome <ph name="BEGIN_EMPHASIS" />tidak akan menyimpan<ph name="END_EMPHASIS" /> maklumat berikut:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Sejarah penyemakan imbas anda
+ <ph name="LIST_ITEM" />Kuki dan data laman
+ <ph name="LIST_ITEM" />Maklumat yang dimasukkan dalam borang
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (Sampul Surat)</translation>
+<translation id="2623663032199728144">Boleh meminta untuk menggunakan maklumat tentang skrin anda</translation>
<translation id="2625385379895617796">Jam anda lebih awal</translation>
<translation id="262745152991669301">Boleh meminta untuk menyambung kepada peranti USB</translation>
<translation id="2629325967560697240">Untuk mendapatkan tahap keselamatan tertinggi Chrome, <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />hidupkan perlindungan dipertingkatkan<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -557,6 +586,7 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="2709516037105925701">Autoisi</translation>
<translation id="2713444072780614174">Putih</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />, tekan Tab kemudian Enter untuk menguruskan maklumat kad kredit dan pembayaran anda dalam tetapan Chrome</translation>
+<translation id="271663710482723385">Tekan |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| untuk keluar daripada skrin penuh</translation>
<translation id="2721148159707890343">Permintaan berjaya</translation>
<translation id="2723669454293168317">Jalankan semakan keselamatan dalam tetapan Chrome</translation>
<translation id="2726001110728089263">Dulang Sisi</translation>
@@ -587,6 +617,7 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="2850739647070081192">Jemputan (Sampul Surat)</translation>
<translation id="2856444702002559011">Penyerang mungkin akan cuba mencuri maklumat anda daripada <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (contohnya, kata laluan, mesej atau kad kredit). <ph name="BEGIN_LEARN_MORE_LINK" />Ketahui lebih lanjut<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">Tapak ini menyiarkan iklan yang mengganggu atau mengelirukan.</translation>
+<translation id="286512204874376891">Kad maya menggantikan kad sebenar anda untuk melindungi anda daripada kemungkinan penipuan. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">Mesra</translation>
<translation id="2876489322757410363">Meninggalkan mod Inkognito untuk membuat bayaran melalui aplikasi luar. Teruskan?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />, tekan Tab kemudian Enter untuk mengurus Penyemakan Imbas Selamat anda dan pelbagai lagi dalam tetapan Chrome</translation>
@@ -611,6 +642,7 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="2930577230479659665">Pangkas selepas setiap salinan</translation>
<translation id="2932085390869194046">Cadangkan Kata Laluan...</translation>
<translation id="2934466151127459956">Surat-Kerajaan</translation>
+<translation id="2938225289965773019">Buka pautan <ph name="PROTOCOL" /></translation>
<translation id="2941952326391522266">Pelayan ini tidak dapat membuktikan bahawa domainnya ialah <ph name="DOMAIN" />; sijil keselamatannya adalah dari <ph name="DOMAIN2" />. Ini mungkin disebabkan oleh kesilapan konfigurasi atau penyerang yang memintasi sambungan anda.</translation>
<translation id="2943895734390379394">Masa Muat Naik:</translation>
<translation id="2948083400971632585">Anda boleh melumpuhkan sebarang proksi yang dikonfigurasi untuk sambungan dari halaman tetapan.</translation>
@@ -643,6 +675,7 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="3037605927509011580">Oh, Tidak!</translation>
<translation id="3041612393474885105">Maklumat Sijil</translation>
<translation id="3044034790304486808">Sambung semula penyelidikan anda</translation>
+<translation id="305162504811187366">Sejarah Desktop Jauh Chrome, termasuk cap masa, hos dan ID sesi pelanggan</translation>
<translation id="3060227939791841287">C9 (Sampul Surat)</translation>
<translation id="3061707000357573562">Perkhidmatan Tampung</translation>
<translation id="306573536155379004">Permainan dimulakan.</translation>
@@ -683,6 +716,7 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="3197136577151645743">Boleh meminta untuk mengetahui waktu anda menggunakan peranti ini dengan aktif</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />, tekan Tab kemudian Enter untuk mengurus maklumat yang anda segerakkan dalam tetapan Chrome</translation>
<translation id="320323717674993345">Batal Pembayaran</translation>
+<translation id="3203366800380907218">Daripada web</translation>
<translation id="3207960819495026254">Ditandai halaman</translation>
<translation id="3209034400446768650">Halaman mungkin mengenakan bayaran berbentuk wang</translation>
<translation id="3212581601480735796">Aktiviti anda pada <ph name="HOSTNAME" /> sedang dipantau</translation>
@@ -699,10 +733,12 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="3234666976984236645">Sentiasa kesan kandungan penting di laman web ini</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />, Tekan tab kemudian Enter untuk menyesuaikan rupa penyemak imbas anda</translation>
<translation id="3240791268468473923">Bukti kelayakan pembayaran selamat tiada helaian bukti kelayakan yang sepadan dibuka</translation>
+<translation id="324180406144491771">Pautan “<ph name="HOST_NAME" />†disekat</translation>
<translation id="3249845759089040423">Groovy</translation>
<translation id="3252266817569339921">Bahasa Perancis</translation>
<translation id="3257954757204451555">Siapakah di sebalik maklumat ini?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />, tekan kekunci Tab kemudian Enter untuk membuat acara baharu dalam Google Calendar dengan pantas</translation>
+<translation id="3261488570342242926">Ketahui tentang kad maya</translation>
<translation id="3264837738038045344">Butang urus tetapan Chrome, tekan Enter untuk melawati tetapan Chrome anda</translation>
<translation id="3266793032086590337">Nilai (konflik)</translation>
<translation id="3268451620468152448">Tab Terbuka</translation>
@@ -716,6 +752,7 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="3288238092761586174"><ph name="URL" /> mungkin perlu mengambil langkah tambahan untuk mengesahkan pembayaran anda</translation>
<translation id="3293642807462928945">Ketahui lebih lanjut tentang dasar <ph name="POLICY_NAME" /></translation>
<translation id="3295444047715739395">Lihat dan urus kata laluan anda dalam tetapan Chrome</translation>
+<translation id="3303795387212510132">Benarkan apl membuka pautan <ph name="PROTOCOL_SCHEME" />?</translation>
<translation id="3303855915957856445">Tiada hasil carian ditemui</translation>
<translation id="3304073249511302126">pengimbasan bluetooth</translation>
<translation id="3308006649705061278">Unit Organisasi (OU)</translation>
@@ -729,12 +766,6 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="3345782426586609320">Mata</translation>
<translation id="3355823806454867987">Tukar tetapan proksi...</translation>
<translation id="3360103848165129075">Helaian pengendali pembayaran</translation>
-<translation id="3361596688432910856">Chrome <ph name="BEGIN_EMPHASIS" />tidak akan menyimpan<ph name="END_EMPHASIS" /> maklumat berikut:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Sejarah semak imbas anda
- <ph name="LIST_ITEM" />Kuki dan data tapak
- <ph name="LIST_ITEM" />Maklumat yang dimasukkan dalam borang
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">Dasar ini disalin secara automatik daripada dasar <ph name="OLD_POLICY" /> yang telah ditamatkan. Anda harus menggunakan dasar ini sebagai ganti.</translation>
<translation id="3364869320075768271"><ph name="URL" /> mahu menggunakan peranti dan data realiti maya anda</translation>
<translation id="3366477098757335611">Lihat kad</translation>
@@ -817,7 +848,6 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="3587738293690942763">Tengah</translation>
<translation id="3592413004129370115">Itali (Sampul Surat)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{Anda boleh menetapkan semula kumpulan anda pada bila-bila masa. Proses menyertai kumpulan baharu mengambil masa kira-kira sehari.}=1{Anda boleh menetapkan semula kumpulan anda pada bila-bila masa. Proses menyertai kumpulan baharu mengambil masa kira-kira sehari.}other{Anda boleh menetapkan semula kumpulan anda pada bila-bila masa. Proses menyertai kumpulan baharu mengambil masa kira-kira {NUM_DAYS} hari.}}</translation>
-<translation id="3596012367874587041">Tetapan apl</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">Aplikasi disekat oleh pentadbir anda</translation>
<translation id="3608932978122581043">Orientasi suapan</translation>
@@ -861,6 +891,7 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="370972442370243704">Hidupkan Perjalanan</translation>
<translation id="3711895659073496551">Gantung</translation>
<translation id="3712624925041724820">Kehabisan lesen</translation>
+<translation id="3714633008798122362">kalendar web</translation>
<translation id="3714780639079136834">Menghidupkan data mudah alih atau Wi-Fi</translation>
<translation id="3715597595485130451">Sambung ke Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Menyemak proksi, tembok api dan konfigurasi DNS<ph name="END_LINK" /></translation>
@@ -922,6 +953,7 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="3906954721959377182">Tablet</translation>
<translation id="3909477809443608991"><ph name="URL" /> mahu memainkan kandungan yang dilindungi. Identiti peranti anda akan disahkan oleh Google dan mungkin diakses oleh tapak ini.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">Nafikan</translation>
<translation id="3939773374150895049">Gunakan WebAuthn dan bukan CVC?</translation>
<translation id="3946209740501886391">Sentiasa tanya pada tapak ini</translation>
<translation id="3947595700203588284">Boleh meminta untuk menyambung kepada peranti MIDI</translation>
@@ -943,6 +975,7 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="3990250421422698716">Ofset jog</translation>
<translation id="3996311196211510766"><ph name="ORIGIN" /> tapak telah meminta dasar asal
dikenakan pada semua permintaan yang diterima, tetapi dasar ini tidak dapat dikenakan pada masa ini.</translation>
+<translation id="4009243425692662128">Kandungan halaman yang anda cetak dihantar ke Google Cloud atau pihak ketiga untuk analisis. Contohnya, teks itu mungkin diimbas untuk mencari data sensitif.</translation>
<translation id="4010758435855888356">Benarkan akses storan?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{Dokumen PDF mengandungi {COUNT} halaman}other{Dokumen PDF mengandungi {COUNT} halaman}}</translation>
<translation id="4023431997072828269">Oleh sebab borang ini diserahkan menggunakan sambungan yang tidak selamat, maklumat anda akan dapat dilihat oleh orang lain.</translation>
@@ -1037,6 +1070,7 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="4250680216510889253">Tidak</translation>
<translation id="4253168017788158739">Nota</translation>
<translation id="425582637250725228">Perubahan yang anda buat mungkin tidak disimpan.</translation>
+<translation id="425869179292622354">Jadikannya lebih selamat dengan kad maya?</translation>
<translation id="4258748452823770588">Tandatangan tidak elok</translation>
<translation id="4261046003697461417">Dokumen yang dilindungi tidak boleh dianotasikan</translation>
<translation id="4265872034478892965">Dibenarkan oleh pentadbir anda</translation>
@@ -1099,6 +1133,7 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="4434045419905280838">Tetingkap timbul dan ubah hala</translation>
<translation id="4435702339979719576">Poskad)</translation>
<translation id="443673843213245140">Penggunaan proksi dilumpuhkan tetapi konfigurasi proksi yang jelas dinyatakan.</translation>
+<translation id="4441832193888514600">Diabaikan kerana dasar itu hanya boleh ditetapkan sebagai dasar pengguna awan.</translation>
<translation id="4450893287417543264">Jangan tunjukkan lagi</translation>
<translation id="4451135742916150903">Boleh meminta untuk menyambung kepada peranti HID</translation>
<translation id="4452328064229197696">Kata laluan yang baru sahaja anda gunakan telah ditemukan dalam pelanggaran data. Untuk melindungi akaun anda, Pengurus Kata Laluan Google mengesyorkan agar anda menyemak kata laluan yang disimpan.</translation>
@@ -1154,6 +1189,7 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="4628948037717959914">Foto</translation>
<translation id="4631649115723685955">Pulangan tunai dipautkan</translation>
<translation id="4636930964841734540">Maklumat</translation>
+<translation id="4638670630777875591">Inkognito dalam Chromium</translation>
<translation id="464342062220857295">Ciri carian</translation>
<translation id="4644670975240021822">Susunan terbalik menghadap ke bawah</translation>
<translation id="4646534391647090355">Bawa saya ke sana sekarang</translation>
@@ -1174,6 +1210,7 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="4708268264240856090">Sambungan anda tergendala</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Jalankan Diagnostik Rangkaian Windows<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426">Kata laluan untuk <ph name="USERNAME" /></translation>
<translation id="4724144314178270921">Boleh meminta untuk melihat teks dan imej pada papan keratan anda</translation>
<translation id="4726672564094551039">Muat semula dasar</translation>
<translation id="4728558894243024398">Platform</translation>
@@ -1195,6 +1232,7 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="4757993714154412917">Anda baru sahaja memasukkan kata laluan pada laman yang menipu. Untuk melindungi akaun anda, Chromium mengesyorkan agar anda menyemak kata laluan anda yang disimpan.</translation>
<translation id="4758311279753947758">Tambahkan maklumat hubungan</translation>
<translation id="4761104368405085019">Gunakan mikrofon anda</translation>
+<translation id="4761869838909035636">Jalankan Semakan Keselamatan Chrome</translation>
<translation id="4764776831041365478">Laman web di <ph name="URL" /> mungkin tergendala buat sementara waktu atau ia mungkin dpindahkan secara kekal ke alamat web baharu.</translation>
<translation id="4766713847338118463">Dua kokot bawah</translation>
<translation id="4771973620359291008">Ralat tidak diketahui telah berlaku.</translation>
@@ -1215,12 +1253,6 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="4819347708020428563">Edit anotasi dalam paparan lalai?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />, tekan kekunci Tab kemudian Enter untuk membuat Google Sheet baharu dengan pantas</translation>
<translation id="4825507807291741242">Berkuasa</translation>
-<translation id="4827402517081186284">Inkognito tidak menjadikan anda halimunan dalam talian:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Laman tahu apabila anda melawati laman tersebut<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Majikan atau institusi pengajian boleh menjejak aktiviti penyemakan imbas<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Penyedia perkhidmatan Internet mungkin memantau trafik web<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">Hidupkan amaran</translation>
<translation id="4838327282952368871">Berangan</translation>
<translation id="4840250757394056958">Lihat sejarah Chrome anda</translation>
@@ -1232,12 +1264,12 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="4854362297993841467">Kaedah penghantaran ini tidak tersedia. Cuba kaedah lain.</translation>
<translation id="4854853140771946034">Buat nota baharu dalam Google Keep dengan pantas</translation>
<translation id="485902285759009870">Mengesahkan kod...</translation>
+<translation id="4866506163384898554">Tekan |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| untuk memaparkan kursor anda</translation>
<translation id="4876188919622883022">Paparan ringkas</translation>
<translation id="4876305945144899064">Tiada nama pengguna</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{Tiada}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831">Carian <ph name="TEXT" /></translation>
<translation id="4879491255372875719">Automatik (lalai)</translation>
-<translation id="4879725228911483934">Buka dan letakkan tetingkap pada skrin anda</translation>
<translation id="4880827082731008257">Sejarah carian</translation>
<translation id="4881695831933465202">Buka</translation>
<translation id="4885256590493466218">Buat bayaran menggunakan <ph name="CARD_DETAIL" /> semasa daftar keluar</translation>
@@ -1246,6 +1278,7 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">Gulungan Kesembilan</translation>
<translation id="4901778704868714008">Simpan...</translation>
+<translation id="4905659621780993806">Pentadbir anda akan memulakan semula peranti anda pada <ph name="DATE" /> jam <ph name="TIME" /> secara automatik. Simpan sebarang item terbuka sebelum peranti anda dimulakan semula.</translation>
<translation id="4913987521957242411">Tebukan atas sebelah kiri</translation>
<translation id="4918221908152712722">Pasang <ph name="APP_NAME" /> (tidak perlu dimuat turun)</translation>
<translation id="4923459931733593730">Pembayaran</translation>
@@ -1254,6 +1287,7 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, tekan Tab kemudian Enter untuk mencari</translation>
<translation id="4930153903256238152">Kapasiti besar</translation>
+<translation id="4940163644868678279">Inkognito dalam Chrome</translation>
<translation id="4943872375798546930">Tiada hasil carian</translation>
<translation id="4950898438188848926">Butang peralihan tab, tekan Enter untuk beralih ke tab yang terbuka, <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="495170559598752135">Tindakan</translation>
@@ -1263,6 +1297,7 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="4968522289500246572">Apl ini direka bentuk untuk peranti mudah alih dan mungkin tidak dapat diubah saiz dengan betul. Apl ini mungkin mengalami isu atau dimulakan semula.</translation>
<translation id="4969341057194253438">Padamkan rakaman</translation>
<translation id="4973922308112707173">Dua tebukan atas</translation>
+<translation id="4976702386844183910">Terakhir dilawati <ph name="DATE" /></translation>
<translation id="4984088539114770594">Gunakan mikrofon?</translation>
<translation id="4984339528288761049">Prc5 (Sampul Surat)</translation>
<translation id="4989163558385430922">Lihat semua</translation>
@@ -1324,6 +1359,7 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="5138227688689900538">Tunjukkan kurang</translation>
<translation id="5145883236150621069">Terdapat kod ralat dalam balasan dasar</translation>
<translation id="5146995429444047494">Pemberitahuan untuk <ph name="ORIGIN" /> disekat</translation>
+<translation id="514704532284964975"><ph name="URL" /> mahu melihat dan menukar maklumat pada peranti NFC yang anda ketik dengan telefon anda</translation>
<translation id="5148809049217731050">Menghadap ke atas</translation>
<translation id="515292512908731282">C4 (Sampul Surat)</translation>
<translation id="5158275234811857234">Muka depan</translation>
@@ -1348,6 +1384,7 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="5215116848420601511">Kaedah pembayaran dan alamat yang menggunakan Google Pay</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">Dulang 13</translation>
+<translation id="5216942107514965959">Terakhir dilawati hari ini</translation>
<translation id="5222812217790122047">E-mel diperlukan</translation>
<translation id="5230733896359313003">Alamat Penghantaran</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1368,7 +1405,6 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">Sifat dokumen</translation>
<translation id="528468243742722775">End</translation>
-<translation id="5284909709419567258">Alamat rangkaian</translation>
<translation id="5285570108065881030">Tunjukkan semua kata laluan yang disimpan</translation>
<translation id="5287240709317226393">Tunjukkan kuki</translation>
<translation id="5287456746628258573">Tapak ini menggunakan konfigurasi keselamatan yang sudah lapuk, yang mungkin mendedahkan maklumat anda (contohnya, kata laluan atau nombor kad kredit) apabila dihantar ke tapak ini.</translation>
@@ -1452,6 +1488,7 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="5556459405103347317">Muat Semula</translation>
<translation id="5560088892362098740">Tarikh Tamat Tempoh</translation>
<translation id="55635442646131152">Rangka dokumen</translation>
+<translation id="5565613213060953222">Buka tap Inkognito</translation>
<translation id="5565735124758917034">Aktif</translation>
<translation id="5570825185877910964">Lindungi akaun</translation>
<translation id="5571083550517324815">Tidak boleh mengambil dari alamat ini. Pilih alamat lain.</translation>
@@ -1534,6 +1571,7 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="5869522115854928033">Kata laluan disimpan</translation>
<translation id="5873013647450402046">Bank anda mahu mengesahkan identiti anda.</translation>
<translation id="5887400589839399685">Kad disimpan</translation>
+<translation id="5887687176710214216">Terakhir dilawati semalam</translation>
<translation id="5895138241574237353">Mulakan Semula</translation>
<translation id="5895187275912066135">Dikeluarkan Pada</translation>
<translation id="5901630391730855834">Kuning</translation>
@@ -1547,6 +1585,7 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="5921639886840618607">Simpan kad ke Akaun Google?</translation>
<translation id="5922853866070715753">Hampir selesai</translation>
<translation id="5932224571077948991">Tapak menyiarkan iklan yang mengganggu atau mengelirukan</translation>
+<translation id="5938153366081463283">Tambah kad maya</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347">Membuka <ph name="SITE_NAME" />…</translation>
<translation id="5951495562196540101">Tidak dapat mendaftar dengan akaun pengguna (lesen berpakej tersedia).</translation>
@@ -1611,6 +1650,7 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="6120179357481664955">Ingat ID UPI anda?</translation>
<translation id="6124432979022149706">Chrome Enterprise Connectors</translation>
<translation id="6127379762771434464">Item dialih keluar</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Ketahui lebih lanjut tentang Inkognito dalam Chrome<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">Periksa mana-mana kabel dan but semula mana-mana penghala, modem atau peranti
rangkaian lain yang mungkin anda gunakan.</translation>
<translation id="614940544461990577">Cuba:</translation>
@@ -1623,7 +1663,6 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="6169916984152623906">Kini, anda boleh menyemak imbas secara sulit dan orang lain yang menggunakan peranti ini tidak akan melihat aktiviti anda. Namun begitu, muat turun dan penanda halaman akan disimpan.</translation>
<translation id="6177128806592000436">Sambungan anda ke tapak ini tidak selamat</translation>
<translation id="6180316780098470077">Selang cubaan semula</translation>
-<translation id="619448280891863779">Boleh meminta untuk membuka dan meletakkan tetingkap pada skrin anda</translation>
<translation id="6196640612572343990">Sekat kuki pihak ketiga</translation>
<translation id="6203231073485539293">Semak sambungan Internet anda</translation>
<translation id="6218753634732582820">Alih keluar alamat daripada Chromium?</translation>
@@ -1646,7 +1685,7 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="6272383483618007430">Kemas Kini Google</translation>
<translation id="6276112860590028508">Halaman daripada senarai bacaan anda dipaparkan di sini</translation>
<translation id="627746635834430766">Untuk membayar dengan lebih cepat selepas ini, simpan kad dan alamat pengebilan anda ke Akaun Google.</translation>
-<translation id="6279098320682980337">Nombor kad maya tidak diisikan? Klik butiran kad untuk disalin</translation>
+<translation id="6279183038361895380">Tekan |<ph name="ACCELERATOR" />| untuk memaparkan kursor anda</translation>
<translation id="6280223929691119688">Tidak dapat menghantar ke alamat ini. Pilih alamat lain.</translation>
<translation id="6282194474023008486">Poskod</translation>
<translation id="6285507000506177184">Butang urus muat turun dalam Chrome, tekan Enter untuk mengurus fail yang telah anda muat turun dalam Chrome</translation>
@@ -1654,6 +1693,7 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="6290238015253830360">Artikel cadangan anda dipaparkan di sini</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{Peranti anda akan dimulakan semula sekarang}=1{Peranti anda akan dimulakan semula dalam masa 1 saat}other{Peranti anda akan dimulakan semula dalam masa # saat}}</translation>
<translation id="6302269476990306341">Google Assistant dalam Chrome berhenti</translation>
<translation id="6305205051461490394"><ph name="URL" /> tidak dapat dicapai.</translation>
<translation id="6312113039770857350">Halaman web tidak tersedia</translation>
@@ -1727,6 +1767,7 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="6529602333819889595">&amp;Buat Semula Pemadaman</translation>
<translation id="6545864417968258051">Pengimbasan Bluetooth</translation>
<translation id="6547208576736763147">Dua tebukan kiri</translation>
+<translation id="6554732001434021288">Terakhir dilawati <ph name="NUM_DAYS" /> hari yang lalu</translation>
<translation id="6556866813142980365">Buat semula</translation>
<translation id="6569060085658103619">Anda sedang melihat halaman sambungan</translation>
<translation id="6573200754375280815">Dua tebukan kanan</translation>
@@ -1787,7 +1828,6 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="6757797048963528358">Peranti anda tidak aktif.</translation>
<translation id="6767985426384634228">Kemas Kini Alamat?</translation>
<translation id="6768213884286397650">Hagaki (Poskad)</translation>
-<translation id="6774185088257932239"><ph name="BEGIN_LINK" />Ketahui lebih lanjut<ph name="END_LINK" /> tentang Inkognito</translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">Ungu Lembayung</translation>
<translation id="6786747875388722282">Pelanjutan</translation>
@@ -1871,7 +1911,6 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="706295145388601875">Tambah dan urus alamat dalam tetapan Chrome</translation>
<translation id="7064851114919012435">Maklumat hubungan</translation>
<translation id="7068733155164172741">Masukkan kod <ph name="OTP_LENGTH" /> digit</translation>
-<translation id="7070090581017165256">Perihal laman ini</translation>
<translation id="70705239631109039">Sambungan anda tidak selamat sepenuhnya</translation>
<translation id="7075452647191940183">Permintaan terlalu besar</translation>
<translation id="7079718277001814089">Tapak ini mengandungi perisian hasad</translation>
@@ -1888,6 +1927,12 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="7111012039238467737">(Sah)</translation>
<translation id="7118618213916969306">Cari URL papan keratan, <ph name="SHORT_URL" /></translation>
<translation id="7119414471315195487">Tutup tab atau atur cara lain</translation>
+<translation id="7129355289156517987">Apabila anda menutup semua tab Inkognito Chromium, aktiviti anda dalam tab tersebut dikosongkan daripada peranti ini:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Aktiviti penyemakan imbas<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Sejarah carian<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Maklumat yang dimasukkan dalam borang<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">Tidak dapat menghantar ke alamat ini. Pilih alamat lain.</translation>
<translation id="7132939140423847331">Pentadbir anda telah melarang data ini daripada disalin.</translation>
<translation id="7135130955892390533">Tunjukkan status</translation>
@@ -1910,6 +1955,7 @@ Jika tidak, ini akan disekat oleh tetapan privasi anda. Kebenaran ini akan membo
<translation id="7192203810768312527">Mengosongkan <ph name="SIZE" />. Sesetengah tapak mungkin dimuatkan dengan perlahan pada lawatan anda yang seterusnya.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">Pentadbir anda dapat melihat:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, tekan Tab kemudian Enter untuk membuka tab Inkognito baharu untuk semak imbas secara peribadi</translation>
<translation id="7202346780273620635">Surat-Ekstra</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> tidak mematuhi piawaian keselamatan.</translation>
<translation id="7210993021468939304">Aktiviti Linux dalam bekas dan boleh memasang serta menjalankan apl Linux dalam bekas</translation>
@@ -1941,6 +1987,7 @@ Butiran tambahan:
<translation id="7304562222803846232">Urus tetapan privasi Google Account</translation>
<translation id="7305756307268530424">Mulakan lebih perlahan</translation>
<translation id="7308436126008021607">penyegerakan latar belakang</translation>
+<translation id="7310392214323165548">Peranti akan dimulakan semula tidak lama lagi</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">Bantuan Sambungan</translation>
<translation id="7323804146520582233">Sembunyikan bahagian "<ph name="SECTION" />"</translation>
@@ -1948,6 +1995,7 @@ Butiran tambahan:
<translation id="7334320624316649418">&amp;Buat semula susun semula</translation>
<translation id="7335157162773372339">Boleh meminta untuk menggunakan kamera anda</translation>
<translation id="7337248890521463931">Tunjukkan lagi baris</translation>
+<translation id="7337418456231055214">Nombor kad maya tidak diisikan? Klik butiran kad untuk disalin. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">Tidak tersedia pada platform anda.</translation>
<translation id="733923710415886693">Sijil pelayan tidak didedahkan melalui Ketelusan Sijil.</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1970,6 +2018,7 @@ Butiran tambahan:
<translation id="7378627244592794276">Tidak</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">Tidak berkenaan</translation>
+<translation id="7388594495505979117">{0,plural, =1{Peranti anda akan dimulakan semula dalam masa 1 minit}other{Peranti anda akan dimulakan semula dalam masa # minit}}</translation>
<translation id="7390545607259442187">Sahkan Kad</translation>
<translation id="7392089738299859607">Kemas Kini Alamat</translation>
<translation id="7399802613464275309">Semakan Keselamatan</translation>
@@ -2006,6 +2055,12 @@ Butiran tambahan:
<translation id="7485870689360869515">Tiada data dijumpai.</translation>
<translation id="7495528107193238112">Kandungan ini disekat. Hubungi pemilik tapak untuk menyelesaikan isu ini.</translation>
<translation id="7497998058912824456">Butang buat dokumen, tekan kekunci Enter untuk membuat Google Docs baharu dengan pantas</translation>
+<translation id="7506488012654002225">Chromium <ph name="BEGIN_EMPHASIS" />tidak akan menyimpan<ph name="END_EMPHASIS" /> maklumat berikut:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Sejarah penyemakan imbas anda
+ <ph name="LIST_ITEM" />Kuki dan data laman
+ <ph name="LIST_ITEM" />Maklumat yang dimasukkan dalam borang
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">Id peranti yang dikembalikan kosong atau tidak sepadan dengan id peranti semasa</translation>
<translation id="7508870219247277067">Hijau Avokado</translation>
<translation id="7511955381719512146">Wi-Fi yang anda gunakan mungkin memerlukan anda untuk melawat <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
@@ -2119,7 +2174,6 @@ Butiran tambahan:
<translation id="7813600968533626083">Alih keluar cadangan borang daripada Chrome?</translation>
<translation id="781440967107097262">Kongsi papan keratan?</translation>
<translation id="7815407501681723534">Menemui <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> untuk '<ph name="SEARCH_STRING" />'</translation>
-<translation id="782125616001965242">Tunjukkan maklumat tentang laman ini</translation>
<translation id="782886543891417279">Wi-Fi yang anda gunakan (<ph name="WIFI_NAME" />) mungkin memerlukan anda melawat halaman log masuknya.</translation>
<translation id="7836231406687464395">Postfix (Sampul Surat)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{Tiada}=1{1 apl (<ph name="EXAMPLE_APP_1" />)}=2{2 apl (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}other{# apl (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}}</translation>
@@ -2136,7 +2190,6 @@ Butiran tambahan:
<translation id="7888575728750733395">Niat pemaparan cetakan</translation>
<translation id="7894280532028510793">Jika ejaan sudah betul, <ph name="BEGIN_LINK" />cuba jalankan Diagnostik Rangkaian<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (Sampul Surat)</translation>
-<translation id="7931318309563332511">Tidak diketahui</translation>
<translation id="793209273132572360">Kemas kini alamat?</translation>
<translation id="7932579305932748336">Kot</translation>
<translation id="79338296614623784">Masukkan nombor telefon yang sah</translation>
@@ -2161,13 +2214,14 @@ Butiran tambahan:
<translation id="7976214039405368314">Terlalu banyak permintaan</translation>
<translation id="7977538094055660992">Peranti output</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">Dipautkan dengan</translation>
<translation id="798134797138789862">Boleh meminta untuk menggunakan peranti dan data realiti maya</translation>
<translation id="7984945080620862648">Anda tidak boleh melawati <ph name="SITE" /> sekarang kerana laman web ini menghantar bukti kelayakan yang dicampuradukkan yang tidak boleh diproses oleh Chrome. Ralat rangkaian dan serangan biasanya bersifat sementara oleh itu, halaman ini mungkin akan berfungsi sebentar lagi.</translation>
-<translation id="79859296434321399">Untuk melihat kandungan realiti tambahan, pasang ARCore</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">Ikatan</translation>
<translation id="7992044431894087211">Perkongsian skrin dengan <ph name="APPLICATION_TITLE" /> telah disambung semula</translation>
<translation id="7995512525968007366">Tidak Ditentukan</translation>
+<translation id="7998269595945679889">Buka butang tab Inkognito, tekan Enter untuk membuka tab Inkognito baharu untuk menyemak imbas secara peribadi</translation>
<translation id="800218591365569300">Cuba tutup tab atau atur cara lain untuk mengosongkan memori.</translation>
<translation id="8004582292198964060">Penyemak Imbas</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{Kad ini dan alamat pengebilannya akan disimpan. Anda akan dapat menggunakan kad ini apabila anda log masuk ke <ph name="USER_EMAIL" />.}other{Kad ini dan alamat pengebilannya akan disimpan. Anda akan dapat menggunakan kad ini apabila anda log masuk ke <ph name="USER_EMAIL" />.}}</translation>
@@ -2227,6 +2281,7 @@ Butiran tambahan:
<translation id="8202370299023114387">Konflik</translation>
<translation id="8206978196348664717">Prc4 (Sampul Surat)</translation>
<translation id="8211406090763984747">Sambungan selamat</translation>
+<translation id="8217240300496046857">Laman tidak dapat menggunakan kuki untuk menjejaki anda merentas web. Ciri pada sesetengah laman mungkin rosak.</translation>
<translation id="8218327578424803826">Lokasi yang Ditentukan:</translation>
<translation id="8220146938470311105">C7/C6 (Sampul Surat)</translation>
<translation id="8225771182978767009">Orang yang menyediakan komputer ini telah memilih untuk menyekat tapak ini.</translation>
@@ -2267,14 +2322,9 @@ Butiran tambahan:
<translation id="830498451218851433">Lipat dua</translation>
<translation id="8307358339886459768">Foto-Kecil</translation>
<translation id="8307888238279532626">Apl yang dipasang dan kekerapan apl itu digunakan</translation>
+<translation id="8317207217658302555">Kemas kini ARCore?</translation>
<translation id="831997045666694187">Petang</translation>
<translation id="8321476692217554900">pemberitahuan</translation>
-<translation id="8328484624016508118">Selepas menutup semua tab Inkognito, Chrome akan mengosongkan:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Aktiviti penyemakan imbas anda daripada peranti ini<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Sejarah carian anda daripada peranti ini<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Maklumat yang dimasukkan dalam borang<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489">Akses ke <ph name="HOST_NAME" /> dinafikan</translation>
<translation id="833262891116910667">Serlahkan</translation>
<translation id="8339163506404995330">Halaman dalam <ph name="LANGUAGE" /> tidak akan diterjemahkan</translation>
@@ -2326,6 +2376,7 @@ Butiran tambahan:
<translation id="8507227106804027148">Baris perintah</translation>
<translation id="8508648098325802031">Ikon Carian</translation>
<translation id="8511402995811232419">Urus kuki</translation>
+<translation id="8519753333133776369">Peranti HID yang dibenarkan oleh pentadbir anda</translation>
<translation id="8522552481199248698">Chrome boleh membantu anda melindungi Akaun Google anda dan menukar kata laluan anda.</translation>
<translation id="8530813470445476232">Kosongkan sejarah penyemakan imbas, kuki, cache dan pelbagai lagi dalam tetapan Chrome</translation>
<translation id="8533619373899488139">Lawati &lt;strong&gt;chrome://policy&lt;/strong&gt; untuk melihat senarai URL yang disekat dan dasar lain yang dikuatkuasakan oleh pentadbir sistem anda.</translation>
@@ -2337,7 +2388,6 @@ Butiran tambahan:
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{Tetapkan semula kebenaran}other{Tetapkan semula kebenaran}}</translation>
<translation id="8555010941760982128">Gunakan kod ini semasa semak keluar</translation>
<translation id="8557066899867184262">CVC terletak di belakang kad anda.</translation>
-<translation id="8558485628462305855">Untuk melihat kandungan realiti tambahan, kemas kini ARCore</translation>
<translation id="8559762987265718583">Sambungan peribadi ke <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> tidak boleh diwujudkan kerana tarikh dan masa peranti anda (<ph name="DATE_AND_TIME" />) tidak betul.</translation>
<translation id="8564182942834072828">Dokumen berasingan/Salinan berasingan</translation>
<translation id="8564985650692024650">Chromium mengesyorkan penetapan semula kata laluan <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> jika anda menggunakan semula kata laluan itu di tapak lain.</translation>
@@ -2357,6 +2407,7 @@ Butiran tambahan:
<translation id="865032292777205197">penderia gerakan</translation>
<translation id="8663226718884576429">Ringkasan Pesanan, <ph name="TOTAL_LABEL" />, Butiran Lanjut</translation>
<translation id="8666678546361132282">Bahasa Inggeris</translation>
+<translation id="8669306706049782872">Gunakan maklumat tentang skrin anda untuk membuka dan meletakkan tetingkap</translation>
<translation id="867224526087042813">Tandatangan</translation>
<translation id="8676424191133491403">Tiada kelewatan</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, jawapan, <ph name="ANSWER" /></translation>
@@ -2383,6 +2434,7 @@ Butiran tambahan:
<translation id="8731544501227493793">Urus butang kata laluan, tekan Enter untuk melihat dan mengurus kata laluan anda dalam tetapan Chrome</translation>
<translation id="8734529307927223492"><ph name="DEVICE_TYPE" /> anda diurus oleh <ph name="MANAGER" /></translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, tekan Tab kemudian Enter untuk membuka tetingkap Inkognito baharu untuk semak imbas secara peribadi</translation>
+<translation id="8737685506611670901">Buka pautan <ph name="PROTOCOL" /> dan bukannya <ph name="REPLACED_HANDLER_TITLE" /></translation>
<translation id="8738058698779197622">Untuk mewujudkan sambungan yang selamat, jam anda perlu ditetapkan dengan betul. Ini kerana sijil yang digunakan oleh laman web untuk mengenal pastinya hanya sah untuk tempoh masa yang tertentu. Memandangkan jam peranti anda tidak betul, Chromium tidak boleh mengesahkan sijil-sijil ini.</translation>
<translation id="8740359287975076522">&lt;abbr id="dnsDefinition"&gt;Alamat DNS&lt;/abbr&gt; <ph name="HOST_NAME" /> tidak ditemui. Masalah sedang didiagnosis.</translation>
<translation id="8742371904523228557"><ph name="ONE_TIME_CODE" /> ialah kod anda untuk <ph name="ORIGIN" /></translation>
@@ -2410,6 +2462,7 @@ Butiran tambahan:
<translation id="883848425547221593">Penanda Halaman Lain</translation>
<translation id="884264119367021077">Alamat penghantaran</translation>
<translation id="884923133447025588">Tiada mekanisme pembatalan dijumpai.</translation>
+<translation id="8849262850971482943">Gunakan kad maya anda untuk mendapatkan keselamatan tambahan</translation>
<translation id="885730110891505394">Berkongsi dengan Google</translation>
<translation id="8858065207712248076">Chrome mengesyorkan penetapan semula kata laluan <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> jika anda menggunakan semula kata laluan itu di tapak lain.</translation>
<translation id="885906927438988819">Jika ejaan sudah betul, <ph name="BEGIN_LINK" />cuba jalankan Diagnostik Rangkaian Windows<ph name="END_LINK" />.</translation>
@@ -2459,6 +2512,7 @@ Butiran tambahan:
<translation id="9004367719664099443">Sesi VR sedang berlangsung</translation>
<translation id="9005998258318286617">Gagal memuatkan dokumen PDF.</translation>
<translation id="9008201768610948239">Abaikan</translation>
+<translation id="901834265349196618">e-mel</translation>
<translation id="9020200922353704812">Alamat pengebilan kad diperlukan</translation>
<translation id="9020542370529661692">Halaman ini telah diterjemahkan kepada <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9020742383383852663">A8</translation>
@@ -2507,6 +2561,7 @@ Butiran tambahan:
<translation id="9150045010208374699">Gunakan kamera anda</translation>
<translation id="9150685862434908345">Pentadbir anda boleh menukar persediaan penyemak imbas anda dari jauh. Aktiviti pada peranti ini mungkin turut diurus di luar Chrome. <ph name="BEGIN_LINK" />Ketahui lebih lanjut<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">Dikemas kini</translation>
+<translation id="9155211586651734179">Persisian audio dilampirkan</translation>
<translation id="9157595877708044936">Menyediakan...</translation>
<translation id="9158625974267017556">C6 (Sampul Surat)</translation>
<translation id="9164029392738894042">Semakan Ketepatan</translation>
diff --git a/chromium/components/strings/components_strings_my.xtb b/chromium/components/strings/components_strings_my.xtb
index 9c3d7df4bb4..09a63d8d912 100644
--- a/chromium/components/strings/components_strings_my.xtb
+++ b/chromium/components/strings/components_strings_my.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">အသေးစိá€á€ºá€¡á€á€»á€€á€ºá€™á€»á€¬á€¸ ကြည့်ရန်</translation>
<translation id="1030706264415084469"><ph name="URL" /> သည် ကြီးမားသည့်ဒေá€á€¬á€™á€»á€¬á€¸á€€á€­á€¯ သင့်စက်á€á€½á€„် အမြဲá€á€™á€ºá€¸á€žá€­á€¯á€œá€¾á€±á€¬á€„်လိုသည်</translation>
<translation id="1032854598605920125">လက်ယာရစ် လှည့်ရန်</translation>
+<translation id="1033329911862281889">ရုပ်ဖျက်မုဒ်က အွန်လိုင်းပေါ်á€á€½á€„် သင့်ကိုမမြင်ရအောင် မလုပ်နိုင်ပါ-
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />á€á€˜á€ºá€†á€­á€¯á€€á€ºá€”ှင့် á€á€”်ဆောင်မှုများက á€á€„်ကြည့်မှုများကို သိနိုင်သည်<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />အလုပ်ရှင် (သို့) ကျောင်းများက ကြည့်ရှုá€á€¼á€„်းများကို á€á€¼á€±á€›á€¬á€á€¶á€”ိုင်သည်<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />အင်á€á€¬á€”က်á€á€”်ဆောင်မှုပေးသူများက á€á€˜á€ºá€’ေá€á€¬á€…ီးဆင်းမှုကို စောင့်ကြည့်နိုင်သည်<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">ပိá€á€ºá€›á€”်</translation>
<translation id="1036982837258183574">မျက်နှာပြင်အပြည့်ဖွင့်á€á€¼á€„်းမှ ထွက်ရန် |<ph name="ACCELERATOR" />| ကိုနှိပ်ပါ</translation>
<translation id="1038106730571050514">အကြံပြုá€á€»á€€á€ºá€™á€»á€¬á€¸ ပြရန်</translation>
<translation id="1038842779957582377">မသိရ အမည်</translation>
<translation id="1041998700806130099">အလုပ် စာမျက်နှာ မက်ဆေ့ဂျ်</translation>
<translation id="1048785276086539861">မှá€á€ºá€á€»á€€á€ºá€™á€»á€¬á€¸á€á€Šá€ºá€¸á€–ြá€á€ºá€•á€«á€€ ဤမှá€á€ºá€á€™á€ºá€¸á€žá€Šá€º စာမျက်နှာá€á€…်á€á€¯á€á€Šá€ºá€¸á€žá€­á€¯á€· ပြန်ပြောင်းသွားမည်</translation>
-<translation id="1049743911850919806">ရုပ်ဖျက်</translation>
<translation id="1050038467049342496">အá€á€¼á€¬á€¸ အက်ပ်များကို ပိá€á€ºá€•á€«</translation>
<translation id="1055184225775184556">&amp;ထည့်ပေးမှု á€á€…်ဆင့်နောက်ပြန်ရန်</translation>
<translation id="1056898198331236512">သá€á€­á€•á€±á€¸á€á€»á€€á€º</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">ပေါ်လစီ ကက်ရှ်အိုကေ</translation>
<translation id="1130564665089811311">စာမျက်နှာဘာသာပြန်ရန်á€á€œá€¯á€á€ºáŠ ဤစာမျက်နှာကို Google Translate ဖြင့်ဘာသာပြန်ရန် Enter နှိပ်ပါ</translation>
<translation id="1131264053432022307">သင်မိá€á€¹á€á€°á€€á€°á€¸á€‘ားသော ပုံ</translation>
+<translation id="1142846828089312304">ရုပ်ဖျက်မုဒ်á€á€½á€„် ပြင်ပကုမ္ပá€á€®á€€á€½á€á€ºá€€á€®á€¸á€™á€»á€¬á€¸á€€á€­á€¯ ပိá€á€ºá€‘ားရန်</translation>
<translation id="1150979032973867961">ဒီဆာဗာက <ph name="DOMAIN" /> ဖြစ်á€á€¬á€€á€­á€¯ သက်သေထူ မပြနိုင်á€á€²á€·á€•á€«áŠ áŽá€„်းá လုံá€á€¼á€¯á€¶á€›á€±á€¸ လက်မှá€á€ºá€€á€­á€¯ သင့်ကွန်ပျူá€á€¬á လည်ပá€á€ºá€™á€¾á€¯ စနစ် ဘက်မှ မယုံကြည်ပါዠဖွဲ့စည်းစီစဉ်မှု အမှားကြောင့် သို့မဟုá€á€º á€á€­á€¯á€€á€ºá€á€­á€¯á€€á€ºá€œá€­á€¯á€žá€°á€€ သင်á á€á€»á€­á€á€ºá€†á€€á€ºá€™á€¾á€¯á€€á€­á€¯ ကြားဖြá€á€ºá€šá€°á€”ေá ထိုသို့ ဖြစ်လာနိုင်á€á€²á€·á€•á€«á€žá€Šá€ºá‹</translation>
<translation id="1151972924205500581">စကားá€á€¾á€€á€º လိုအပ်</translation>
<translation id="1156303062776767266">သင်သည် စက်အá€á€½á€„်း သို့မဟုá€á€º မျှá€á€±á€‘ားသည့် ဖိုင်ကို ကြည့်နေသည်</translation>
@@ -64,7 +70,6 @@
<translation id="1178581264944972037">ဆိုင်းငံ့ထားရန်</translation>
<translation id="1181037720776840403">ဖယ်ရှားရန်</translation>
<translation id="1186201132766001848">စကားá€á€¾á€€á€ºá€™á€»á€¬á€¸ စစ်ဆေးရန်</translation>
-<translation id="1195210374336998651">အက်ပ်ဆက်á€á€„်များသို့ သွားရန်</translation>
<translation id="1195558154361252544">သင်á€á€½á€„့်ပြုထားသည့် á€á€˜á€ºá€†á€­á€¯á€€á€ºá€™á€»á€¬á€¸á€¡á€á€½á€€á€ºá€™á€¾á€œá€½á€²á အကြောင်းကြားá€á€»á€€á€ºá€™á€»á€¬á€¸á€€á€­á€¯ အလိုအလျောက် ပိá€á€ºá€‘ားသည်</translation>
<translation id="1197088940767939838">လိမ္မော်ရောင်</translation>
<translation id="1201402288615127009">ရှေ့သို့</translation>
@@ -111,7 +116,7 @@
<translation id="1307966114820526988">ရပ်ဆိုင်းထားသော á€á€”်ဆောင်မှုများ</translation>
<translation id="1308113895091915999">ရရှိနိုင်သော ကမ်းလှမ်းá€á€»á€€á€º</translation>
<translation id="1312803275555673949">လက်á€á€¶á€”ိုင်စရာ ဘာအထောက်အထား ရှိပါသလဲá‹</translation>
-<translation id="131405271941274527">သင့်ဖုန်းကို NFC စက်á€á€…်á€á€¯á€¡á€•á€±á€«á€º á€á€­á€¯á€·á€œá€­á€¯á€€á€ºá€žá€Šá€ºá€·á€¡á€á€« <ph name="URL" /> သည် အá€á€»á€€á€ºá€¡á€œá€€á€º ပို့á€á€¼á€„်းနှင့် လက်á€á€¶á€á€¼á€„်းá€á€­á€¯á€· ပြုလုပ်လိုသည်</translation>
+<translation id="1314311879718644478">လွန်ကဲပကá€á€­á€¡á€žá€½á€„် အကြောင်းအရာများကို ကြည့်ပါ</translation>
<translation id="1314509827145471431">ညာဘက်á€á€½á€„် á€á€½á€²á€á€»á€¯á€•á€ºá€›á€”်</translation>
<translation id="1318023360584041678">á€á€˜á€ºá€¡á€¯á€•á€ºá€…ုá€á€½á€„် သိမ်းထားသည်</translation>
<translation id="1319245136674974084">ဤအက်ပ်အá€á€½á€€á€º ထပ်မမေးပါနှင့်</translation>
@@ -161,6 +166,7 @@
<translation id="142858679511221695">Cloud အသုံးပြုသူ</translation>
<translation id="1428729058023778569">ဤá€á€˜á€ºá€†á€­á€¯á€€á€ºá€žá€Šá€º HTTPS မပံ့ပိုးသည့်အá€á€½á€€á€º ဤသá€á€­á€•á€±á€¸á€á€»á€€á€ºá€€á€­á€¯ မြင်နေရá€á€¼á€„်းဖြစ်သည်ዠ<ph name="BEGIN_LEARN_MORE_LINK" />ပိုမိုလေ့လာရန်<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">ပရင့်</translation>
+<translation id="1432187715652018471">စာမျက်နှာက á€á€”်ဆောင်မှု စီမံသူအား ထည့်သွင်းလိုသည်á‹</translation>
<translation id="1432581352905426595">ရှာဖွေမှုအင်ဂျင်များကို စီမံá€á€”့်á€á€½á€²á€›á€”်</translation>
<translation id="1436185428532214179">သင့်စက်ပေါ်ရှိ ဖိုင်နှင့် ဖိုင်á€á€½á€²á€™á€»á€¬á€¸ á€á€Šá€ºá€¸á€–ြá€á€ºá€›á€”် á€á€½á€„့်á€á€±á€¬á€„်းနိုင်သည်</translation>
<translation id="1442386063175183758">ညာá€á€¶á€á€«á€¸á€›á€½á€€á€ºá€•á€¯á€¶á€…ံ á€á€±á€«á€€á€ºá€›á€”်</translation>
@@ -181,6 +187,12 @@
<translation id="1483493594462132177">ပို့ရန်</translation>
<translation id="1484290072879560759">ပစ္စည်းပို့ရမည့်လိပ်စာ ရွေးရန်</translation>
<translation id="1492194039220927094">မူá€á€«á€’များ ထည့်သွင်းရန်-</translation>
+<translation id="149293076951187737">Chrome ရုပ်ဖျက်á€á€˜á€ºá€¡á€¬á€¸á€œá€¯á€¶á€¸ ပိá€á€ºá€œá€­á€¯á€€á€ºá€žá€±á€¬á€¡á€á€« ထိုá€á€˜á€ºá€™á€»á€¬á€¸á€›á€¾á€­ သင့်လုပ်ဆောင်á€á€»á€€á€ºá€€á€­á€¯ ဤစက်မှ ဖျက်လိုက်မည်-
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ကြည့်ရှုá€á€¼á€„်းများ<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ရှာဖွေမှá€á€ºá€á€™á€ºá€¸<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ဖောင်များá€á€½á€„်ထည့်ထားသော အá€á€»á€€á€ºá€¡á€œá€€á€º<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">á€á€˜á€ºá€žá€­á€¯á€· ပြန်သွားရန်</translation>
<translation id="1501859676467574491">သင့် Google အကောင့်မှ ကá€á€ºá€™á€»á€¬á€¸á€€á€­á€¯ ပြရန်</translation>
<translation id="1507202001669085618">&lt;p&gt;အွန်လိုင်း မရရှိမီ လက်မှá€á€ºá€‘ိုးá€á€„်ရသည့် Wi-Fi ပေါ်á€á€šá€ºá€€á€­á€¯ အသုံးပြုသည့်အá€á€« ဤအမှားကို á€á€½á€±á€·á€›á€•á€«á€™á€Šá€ºá‹&lt;/p&gt;
@@ -208,6 +220,8 @@
<translation id="1559572115229829303">&lt;p&gt;သင့်ကိရိယာá ရက်စွဲ နှင့် အá€á€»á€­á€”် (<ph name="DATE_AND_TIME" />)မှာ မမှန်ကန်သောကြောင့် <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> သို့ ကိုယ်ပိုင် á€á€»á€­á€á€ºá€†á€€á€ºá€™á€¾á€¯á€€á€­á€¯ ပြုလုပ်မရနိုင်ပါá‹&lt;/p&gt;
&lt;p&gt;ကျေးဇူးပြုပြီး ရက်စွဲ နှင့် အá€á€»á€­á€”်ကို &lt;strong&gt;ဆက်á€á€„်များ&lt;/strong&gt; အက်ပ်á &lt;strong&gt;အထွေထွေ&lt;/strong&gt; ကá€á€¹á€á€‘ဲá€á€½á€„် ညှိပါá‹&lt;/p&gt;</translation>
+<translation id="1559839503761818503">သင့်စီမံá€á€”့်á€á€½á€²á€žá€°á€€ စက်ကို <ph name="DATE" />አ<ph name="TIME" /> á€á€½á€„် ပြန်စပါမည်</translation>
+<translation id="156703335097561114">á€á€˜á€ºá€œá€­á€•á€ºá€…ာများአအင်á€á€¬á€–ေ့စ် စီစဉ်သá€á€ºá€™á€¾á€á€ºá€á€»á€€á€ºá€”ှင့် á€á€»á€­á€á€ºá€†á€€á€ºá€™á€¾á€¯ အရည်အသွေးကဲ့သို့ ကွန်ရက်အá€á€»á€€á€ºá€¡á€œá€€á€ºá€™á€»á€¬á€¸</translation>
<translation id="1567040042588613346">ဤမူá€á€«á€’သည် သá€á€ºá€™á€¾á€á€ºá€‘ားသည့်အá€á€­á€¯á€„်း အလုပ်လုပ်နေသော်လည်း á€á€°á€Šá€®á€žá€±á€¬á€á€”်ဖိုးကို á€á€…်နေရာá€á€½á€„် သá€á€ºá€™á€¾á€á€ºá€‘ားပြီး ဤမူá€á€«á€’က အစားထိုးထားသည်á‹</translation>
<translation id="1569487616857761740">သက်á€á€™á€ºá€¸á€€á€¯á€”်ဆုံးရက် ထည့်ပါ</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@
<translation id="1583429793053364125">ဤá€á€˜á€ºá€†á€­á€¯á€€á€ºá€¡á€¬á€¸ ပြသစဉ် á€á€…်á€á€¯á€á€¯ မှားသွားáá‹</translation>
<translation id="1586541204584340881">သင်ထည့်သွင်းထားသည့် နောက်ဆက်á€á€½á€²á€™á€»á€¬á€¸</translation>
<translation id="1588438908519853928">ပုံမှန်</translation>
+<translation id="1589050138437146318">ARCore ထည့်သွင်းမလားá‹</translation>
<translation id="1592005682883173041">စက်အá€á€½á€„်းဒေá€á€¬ အသုံးပြုမှု</translation>
<translation id="1594030484168838125">ရွေးá€á€»á€šá€ºá€›á€”်</translation>
<translation id="160851722280695521">Chrome á€á€½á€„် Dino Run ဂိမ်းကစားရန်</translation>
@@ -284,6 +299,7 @@
á€á€±á€«á€„်းစဉ်ပုံစံပျက်ယွင်းနေသောကြောင့် ဘရောင်ဇာက <ph name="SITE" /> အá€á€½á€€á€º
သင်áá€á€±á€¬á€„်းဆိုá€á€»á€€á€ºá€€á€­á€¯ မဖြည့်ဆည်းနိုင်ပါዠá€á€˜á€ºá€†á€­á€¯á€€á€ºá€á€…်á€á€¯á€¡á€á€½á€€á€º လုံá€á€¼á€¯á€¶á€›á€±á€¸á€”ှင့် အá€á€¼á€¬á€¸á€žá€á€ºá€™á€¾á€á€ºá€á€»á€€á€ºá€™á€»á€¬á€¸á€€á€­á€¯
စီစဉ်သá€á€ºá€™á€¾á€á€ºá€›á€”် á€á€˜á€ºá€†á€­á€¯á€€á€º အော်ပရေá€á€¬á€™á€»á€¬á€¸á€€ ရင်းမြစ် မူá€á€«á€’များကို အသုံးပြုနိုင်ပါသည်á‹</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Chromium ရှိ ရုပ်ဖျက်မုဒ်အကြောင်း ပိုမိုလေ့လာရန်<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">သင်ဖွင့်ထားသည့်á€á€˜á€ºá€™á€»á€¬á€¸ ဤနေရာá€á€½á€„် ပေါ်ပါမည်</translation>
<translation id="1791429645902722292">Google ကစမá€á€ºá€žá€±á€¬á€·á€á€á€º</translation>
@@ -334,7 +350,7 @@
<translation id="1947454675006758438">ညာဘက်ထိပ်á€á€½á€„် á€á€»á€¯á€•á€ºá€…က်ဖြင့် á€á€»á€¯á€•á€ºá€›á€”်</translation>
<translation id="1956486093533522234">သင်áစက်ကို ရှာá€á€¼á€„်းአလုံá€á€¼á€¯á€¶á€¡á€±á€¬á€„်လုပ်á€á€¼á€„်း (သို့) ဖျက်á€á€¼á€„်းá€á€­á€¯á€· ပြုလုပ်နိုင်သည်</translation>
<translation id="1958218078413065209">သင်á အမြင့်ဆုံးရမှá€á€ºá€™á€¾á€¬ <ph name="SCORE" /> ဖြစ်သည်á‹</translation>
-<translation id="1959001866257244765"><ph name="BEGIN_WHITEPAPER_LINK" />သင်á€á€„်ကြည့်သည့် စာမျက်နှာအá€á€»á€­á€¯á€·á URL များአကန့်သá€á€ºá€‘ားသည့် စနစ်အá€á€»á€€á€ºá€¡á€œá€€á€ºá€™á€»á€¬á€¸á€”ှင့် အá€á€»á€­á€¯á€·á€žá€±á€¬á€…ာမျက်နှာပါ အကြောင်းအရာများ<ph name="END_WHITEPAPER_LINK" /> ကို Google သို့ ပို့ပေးá€á€¼á€„်းဖြင့် လူá€á€­á€¯á€„်းအá€á€½á€€á€º á€á€˜á€ºá€•á€±á€«á€ºá€á€½á€„် လုံá€á€¼á€¯á€¶á€›á€±á€¸ ကောင်းမွန်လာအောင် ကူညီပါዠ<ph name="BEGIN_PRIVACY_PAGE_LINK" />ပုဂ္ဂိုလ်ရေးဆိုင်ရာ မူá€á€«á€’<ph name="END_PRIVACY_PAGE_LINK" /></translation>
+<translation id="1959001866257244765"><ph name="BEGIN_WHITEPAPER_LINK" />သင်á€á€„်ကြည့်သည့် စာမျက်နှာအá€á€»á€­á€¯á€·á URL များአကန့်သá€á€ºá€‘ားသည့် စနစ်အá€á€»á€€á€ºá€¡á€œá€€á€ºá€™á€»á€¬á€¸á€”ှင့် အá€á€»á€­á€¯á€·á€žá€±á€¬á€…ာမျက်နှာပါ အကြောင်းအရာများ<ph name="END_WHITEPAPER_LINK" /> ကို Google သို့ ပို့ပေးá€á€¼á€„်းဖြင့် လူá€á€­á€¯á€„်းအá€á€½á€€á€º á€á€˜á€ºá€•á€±á€«á€ºá€á€½á€„် လုံá€á€¼á€¯á€¶á€›á€±á€¸ ကောင်းမွန်လာအောင် ကူညီပါዠ<ph name="BEGIN_PRIVACY_PAGE_LINK" />ကိုယ်ရေးအá€á€»á€€á€ºá€¡á€œá€€á€º မူá€á€«á€’<ph name="END_PRIVACY_PAGE_LINK" /></translation>
<translation id="1962204205936693436"><ph name="DOMAIN" /> စာညှပ်များ</translation>
<translation id="1973335181906896915">နံပါá€á€ºá€…ဉ်စီမှု အမှား</translation>
<translation id="1974060860693918893">အဆင့်မြင့်</translation>
@@ -411,6 +427,7 @@
<translation id="22081806969704220">ဗန်း áƒ</translation>
<translation id="2212735316055980242">ပေါ်လစီမá€á€½á€±á€·á€•á€«</translation>
<translation id="2213606439339815911">ထည့်သွင်းမှုများကို ရယူနေ...</translation>
+<translation id="2213612003795704869">စာမျက်နှာကို ပုံနှိပ်ထုá€á€ºá€œá€­á€¯á€€á€ºá€žá€Šá€º</translation>
<translation id="2215727959747642672">ဖိုင်á€á€Šá€ºá€¸á€–ြá€á€ºá€á€¼á€„်း</translation>
<translation id="2218879909401188352"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ရှိ လက်ရှိá€á€­á€¯á€€á€ºá€á€­á€¯á€€á€ºá€žá€°á€™á€»á€¬á€¸á€žá€Šá€º သင့်စက်ပစ္စည်းကို ပျက်စီးစေနိုင်သည့် အန္á€á€›á€¬á€šá€ºá€›á€¾á€­á€žá€±á€¬á€¡á€€á€ºá€•á€ºá€™á€»á€¬á€¸ ထည့်သွင်းá€á€¼á€„်းአဖုန်းá€á€„ွေပိုမိုကုန်ကျစေá€á€¼á€„်း သို့မဟုá€á€º သင်á ကိုယ်ရေးကိုယ်á€á€¬ အá€á€»á€€á€ºá€¡á€œá€€á€ºá€™á€»á€¬á€¸á€€á€­á€¯ á€á€­á€¯á€¸á€šá€°á€á€¼á€„်းá€á€­á€¯á€· ပြုလုပ်နိုင်ပါသည်ዠ<ph name="BEGIN_LEARN_MORE_LINK" />ပိုမိုလေ့လာရန်<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">အင်á€á€¬á€”က် မရှိပါ</translation>
@@ -420,6 +437,7 @@
<translation id="2248949050832152960">WebAuthn အသုံးပြုရန်</translation>
<translation id="2250931979407627383">ဘယ်ဘက်အစွန်းá€á€½á€„် အပ်á€á€»á€Šá€ºá€–ြင့်á€á€»á€¯á€•á€ºá€›á€”်</translation>
<translation id="225207911366869382">ဤပေါ်လစီအá€á€½á€€á€º ဤá€á€”်ဖိုးအား ပယ်ဖျက်ထားသည်á‹</translation>
+<translation id="2256115617011615191">ယá€á€¯ ပြန်လည်စပါ</translation>
<translation id="2258928405015593961">သက်á€á€™á€ºá€¸á€€á€¯á€”်ရက်ကို အနာဂá€á€ºá€›á€€á€ºá€…ွဲ ထည့်သွင်းပြီး ထပ်စမ်းကြည့်ပါ</translation>
<translation id="225943865679747347">အမှား ကုဒ်: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">HTTP အမှား</translation>
@@ -447,6 +465,7 @@
<translation id="2337852623177822836">သင်á စီမံá€á€”့်á€á€½á€²á€žá€°á€€ ထိန်းá€á€»á€¯á€•á€ºá€‘ားသော ဆက်á€á€„်</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> သည် á€á€½á€²á€á€»á€­á€á€ºá€œá€­á€¯á€•á€«á€žá€Šá€º</translation>
<translation id="2346319942568447007">သင်မိá€á€¹á€á€°á€€á€°á€¸á€‘ားသော ပုံ</translation>
+<translation id="2350796302381711542"><ph name="HANDLER_HOSTNAME" /> အား <ph name="REPLACED_HANDLER_TITLE" /> အစား လင့်များ <ph name="PROTOCOL" /> အားလုံးကို ဖွင့်á€á€½á€„့် ပြုရမလား?</translation>
<translation id="2354001756790975382">အá€á€¼á€¬á€¸ စာညှပ်များ</translation>
<translation id="2354430244986887761">လုံá€á€¼á€¯á€¶á€…ွာအသုံးပြုသည့် Google á€á€”်ဆောင်မှုသည် မကြာမီက <ph name="SITE" /> á€á€½á€„် <ph name="BEGIN_LINK" />အန္á€á€›á€¬á€šá€ºá€›á€¾á€­á€žá€Šá€·á€º ပရိုဂရမ်များကို á€á€½á€±á€·á€›á€¾á€­á€á€²á€·á€•á€«á€žá€Šá€º<ph name="END_LINK" />á‹</translation>
<translation id="2355395290879513365">á€á€­á€¯á€€á€ºá€á€­á€¯á€€á€ºá€žá€°á€™á€»á€¬á€¸á€€ ဤá€á€˜á€ºá€†á€­á€¯á€€á€ºá€á€½á€„် သင်ကြည့်နေသော ပုံများကို မြင်နိုင်á áŽá€„်းá€á€­á€¯á€·á€€á€­á€¯ ပြင်ဆင်á€á€¼á€„်းဖြင့် သင့်ကို လှည့်စားနိုင်ပါသည်á‹</translation>
@@ -472,6 +491,7 @@
<translation id="2413528052993050574">ဒီဆာဗာက <ph name="DOMAIN" /> ဖြစ်á€á€¬á€€á€­á€¯ သက်သေထူ မပြနိုင်á€á€²á€·á€•á€«áŠ áŽá€„်းá လုံá€á€¼á€¯á€¶á€›á€±á€¸ လက်မှá€á€ºá€€á€­á€¯ ရုပ်သိမ်းá€á€²á€·á€á€¬ ဖြစ်နိုင်သည်ዠဖွဲ့စည်းစီစဉ်မှု အမှားကြောင့် သို့မဟုá€á€º á€á€­á€¯á€€á€ºá€á€­á€¯á€€á€ºá€œá€­á€¯á€žá€°á€€ သင်á á€á€»á€­á€á€ºá€†á€€á€ºá€™á€¾á€¯á€€á€­á€¯ ကြားဖြá€á€ºá€šá€°á€”ေá ထိုသို့ ဖြစ်လာနိုင်á€á€²á€·á€•á€«á€žá€Šá€ºá‹</translation>
<translation id="2414886740292270097">အမှောင်</translation>
<translation id="2430968933669123598">Google Account စီမံရန်አသင်á Google Account á€á€½á€„် သင့်အá€á€»á€€á€ºá€¡á€œá€€á€ºáŠ ပုဂ္ဂိုလ်ရေးနှင့် လုံá€á€¼á€¯á€¶á€›á€±á€¸á€†á€­á€¯á€„်ရာများကို စီမံရန် Enter á€á€œá€¯á€á€º နှိပ်ပါ</translation>
+<translation id="2436186046335138073">လင့် <ph name="PROTOCOL" /> အားလုံးကို <ph name="HANDLER_HOSTNAME" />အား ဖွင့်á€á€½á€„့် ပြုမလား?</translation>
<translation id="2438874542388153331">ညာဘက်á€á€½á€„် လေးá€á€»á€€á€ºá€–ောက်ရန်</translation>
<translation id="2450021089947420533">á€á€›á€®á€¸á€…ဉ်များ</translation>
<translation id="2463739503403862330">ဖြည့်သွင်းရန်</translation>
@@ -479,6 +499,7 @@
<translation id="2465655957518002998">ပေးပို့ရမည့်နည်းလမ်း ရွေးရန်</translation>
<translation id="2465688316154986572">á€á€»á€¯á€•á€ºá€…က်ဖြင့် á€á€»á€¯á€•á€ºá€›á€”်</translation>
<translation id="2465914000209955735">Chrome á€á€½á€„် သင် ဒေါင်းလုဒ်လုပ်á€á€²á€·á€žá€Šá€·á€ºá€–ိုင်များကို စီမံပါ</translation>
+<translation id="2466004615675155314">á€á€˜á€ºá€•á€±á€«á€ºá€™á€¾á€¡á€á€»á€€á€ºá€¡á€œá€€á€º ပြပါ</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />ကွန်ရက်ပြဿနာရှာဖွေမှု ပြုလုပ်ပါ<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">á မှ N သို့ အစီအစဉ်</translation>
<translation id="2470767536994572628">မှá€á€ºá€á€»á€€á€ºá€™á€»á€¬á€¸á€á€Šá€ºá€¸á€–ြá€á€ºá€•á€«á€€ ဤမှá€á€ºá€á€™á€ºá€¸á€žá€Šá€º စာမျက်နှာá€á€…်á€á€¯á€á€Šá€ºá€¸á€žá€­á€¯á€· ပြန်ပြောင်းပြီး áŽá€„်းá မူရင်းအနေအထားသို့ ပြန်လှည့်သွားမည်</translation>
@@ -499,6 +520,7 @@
<translation id="2523886232349826891">ဤစက်á€á€½á€„်သာ သိမ်းထားသည်</translation>
<translation id="2524461107774643265">နောက်ထပ် အá€á€»á€€á€ºá€¡á€œá€€á€ºá€™á€»á€¬á€¸á€€á€­á€¯ ထည့်á€á€¼á€„်း</translation>
<translation id="2529899080962247600">ဤအကွက်á€á€½á€„် ထည့်သွင်းမှု <ph name="MAX_ITEMS_LIMIT" /> á€á€¯á€‘က်မပိုရပါዠနောက်ထပ် ထည့်သွင်းမှုအားလုံးကို လျစ်လျူရှုပါမည်á‹</translation>
+<translation id="2535585790302968248">သီးသန့်ကြည့်ရှုရန် ရုပ်ဖျက်á€á€˜á€º အသစ်á€á€…်á€á€¯á€–ွင့်နိုင်သည်</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{နှင့် နောက်ထပ် á á€á€¯}other{နှင့် နောက်ထပ် # á€á€¯}}</translation>
<translation id="2536110899380797252">လိပ်စာထည့်ရန်</translation>
<translation id="2539524384386349900">ရှာကြည့်ရန်</translation>
@@ -528,7 +550,14 @@
<translation id="2597378329261239068">ဒီစာá€á€™á€ºá€¸á€€á€­á€¯ စကားá€á€¾á€€á€ºá€–ြင့် ကာကွယ်ထားသည်ዠကျေးဇူးပြုပြီး စကားá€á€¾á€€á€º ရိုက်ထည့်ပါá‹</translation>
<translation id="2609632851001447353">မူကွဲများ</translation>
<translation id="2610561535971892504">မိá€á€¹á€á€°á€€á€°á€¸á€›á€”် နှိပ်ပါ</translation>
+<translation id="2617988307566202237">Chrome သည် အောက်ပါအá€á€»á€€á€ºá€¡á€œá€€á€ºá€™á€»á€¬á€¸á€€á€­á€¯ <ph name="BEGIN_EMPHASIS" />သိမ်းမည်မဟုá€á€ºá€•á€«<ph name="END_EMPHASIS" />-
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />သင်á ကြည့်ရှုá€á€¼á€„်းမှá€á€ºá€á€™á€ºá€¸
+ <ph name="LIST_ITEM" />ကွá€á€ºá€€á€®á€¸á€”ှင့် á€á€˜á€ºá€†á€­á€¯á€€á€ºá€’ေá€á€¬
+ <ph name="LIST_ITEM" />ဖောင်များá€á€½á€„်ထည့်ထားသော အá€á€»á€€á€ºá€¡á€œá€€á€º
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (စာအိá€á€º)</translation>
+<translation id="2623663032199728144">သင့်ဖန်သားပြင်အá€á€»á€€á€ºá€¡á€œá€€á€ºá€€á€­á€¯ သုံးရန် á€á€½á€„့်á€á€±á€¬á€„်းနိုင်သည်</translation>
<translation id="2625385379895617796">သင်á နာရီမှာ စောနေ</translation>
<translation id="262745152991669301">USB ကိရိယာများနှင့် á€á€»á€­á€á€ºá€†á€€á€ºá€›á€”် á€á€½á€„့်á€á€±á€¬á€„်းနိုင်သည်</translation>
<translation id="2629325967560697240">Chrome á အမြင့်ဆုံးလုံá€á€¼á€¯á€¶á€›á€±á€¸ ရရှိရန် <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />အဆင့်မြှင့်á€á€„်ထားသော ကာကွယ်မှုကို ဖွင့်ပါ<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -559,9 +588,10 @@
<translation id="2704283930420550640">á€á€”်ဖိုးမှာ ပုံစံá€á€»á€‘ားမှု မကိုင်ညီပါá‹</translation>
<translation id="2704606927547763573">ကူးယူပြီးပါပြီ</translation>
<translation id="2705137772291741111">သိမ်းဆည်းá€á€²á€·á€žá€Šá€·á€º (ယာယီသိမ်းဆည်းထားသည့်) မိá€á€¹á€á€°á€€á€­á€¯ ဖá€á€ºá€™á€›á€•á€«á‹</translation>
-<translation id="2709516037105925701">အလိုလျောက် ဖြည့်စွက်</translation>
+<translation id="2709516037105925701">အလိုအလျောက် ဖြည့်စွက်</translation>
<translation id="2713444072780614174">အဖြူ</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />አChrome ဆက်á€á€„်များá€á€½á€„် ငွေပေးá€á€»á€±á€™á€¾á€¯á€™á€»á€¬á€¸á€”ှင့် á€á€›á€€á€ºá€’စ်ကá€á€º အá€á€»á€€á€ºá€¡á€œá€€á€ºá€€á€­á€¯ စီမံရန် Tab နှိပ်ပြီးနောက် Enter နှိပ်ပါ</translation>
+<translation id="271663710482723385">ဖန်သားပြင်အပြည့်မှ ထွက်ရန် |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| နှိပ်ပါ</translation>
<translation id="2721148159707890343">á€á€±á€¬á€„်းဆိုá€á€»á€€á€º အောင်မြင်ပါသည်</translation>
<translation id="2723669454293168317">Chrome ဆက်á€á€„်များá€á€½á€„် လုံá€á€¼á€¯á€¶á€›á€±á€¸ စစ်ဆေးမှု လုပ်ဆောင်ပါ</translation>
<translation id="2726001110728089263">ဘေးဗန်း</translation>
@@ -592,6 +622,7 @@
<translation id="2850739647070081192">ဖိá€á€ºá€…ာ (စာအိá€á€º)</translation>
<translation id="2856444702002559011">á€á€­á€¯á€€á€ºá€á€­á€¯á€€á€ºá€žá€°á€™á€»á€¬á€¸á€€ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ရှိ သင်áအá€á€»á€€á€ºá€¡á€œá€€á€ºá€™á€»á€¬á€¸á€€á€­á€¯ á€á€­á€¯á€¸á€šá€°á€›á€”် ကြိုးပမ်းနိုင်ပါသည် (ဥပမာ- စကားá€á€¾á€€á€ºáŠ မက်ဆေ့ဂျ်နှင့် á€á€›á€€á€ºá€’စ်ကá€á€º အá€á€»á€€á€ºá€¡á€œá€€á€ºá€™á€»á€¬á€¸)á‹ <ph name="BEGIN_LEARN_MORE_LINK" />ပိုမိုလေ့လာရန်<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">ဤá€á€˜á€ºá€†á€­á€¯á€€á€ºá€€ စိá€á€ºá€¡á€”ှောင့်အယှက်ဖြစ်စေသော (သို့) အထင်အမြင်မှားစေသော ကြော်ငြာများကို ပြသည်á‹</translation>
+<translation id="286512204874376891">လိမ်လည်မှုကာကွယ်နိုင်ရန် ပကá€á€­á€¡á€žá€½á€„်ကá€á€ºá€€ သင့်ကá€á€ºá€¡á€…စ်ကို ရုပ်ဖျက်ပေးသည်ዠ<ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">နှစ်လိုဖွယ်</translation>
<translation id="2876489322757410363">ပြင်ပအပလီကေးရှင်းဖြင့် ငွေပေးá€á€»á€±á€›á€”် ရုပ်ဖျက်မုဒ်မှ ထွက်နေသည်ዠရှေ့ဆက်မလားá‹</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />አChrome ဆက်á€á€„်များá€á€½á€„် သင်á ‘လုံá€á€¼á€¯á€¶á€…ွာ ကြည့်ရှုá€á€¼á€„်း’ နှင့် အá€á€¼á€¬á€¸á€¡á€›á€¬á€™á€»á€¬á€¸á€€á€­á€¯á€…ီမံရန် á€á€˜á€ºá€”ှိပ်ပြီးနောက် Enter နှိပ်ပါ</translation>
@@ -616,6 +647,7 @@
<translation id="2930577230479659665">မိá€á€¹á€á€°á€á€…်á€á€¯á€•á€¼á€®á€¸á€œá€»á€¾á€„် ဖြá€á€ºá€‘ုá€á€ºá€›á€”်</translation>
<translation id="2932085390869194046">စကားá€á€¾á€€á€º အကြံပြုပါ…</translation>
<translation id="2934466151127459956">အစိုးရရုံးသုံး Letter စာရွက်</translation>
+<translation id="2938225289965773019"><ph name="PROTOCOL" /> လင့်များ ဖွင့်ရန်</translation>
<translation id="2941952326391522266">ဒီဆာဗာက <ph name="DOMAIN" /> ဖြစ်á€á€¬á€€á€­á€¯ သက်သေထူ မပြနိုင်á€á€²á€·á€•á€«áŠ áŽá€„်းá လုံá€á€¼á€¯á€¶á€›á€±á€¸ လက်မှá€á€ºá€™á€¾á€¬<ph name="DOMAIN2" />ထံမှ ဖြစ်သည်ዠဖွဲ့စည်းစီစဉ်မှု အမှားကြောင့် သို့မဟုá€á€º á€á€­á€¯á€€á€ºá€á€­á€¯á€€á€ºá€œá€­á€¯á€žá€°á€€ သင်á á€á€»á€­á€á€ºá€†á€€á€ºá€™á€¾á€¯á€€á€­á€¯ ကြားဖြá€á€ºá€šá€°á€”ေá ထိုသို့ ဖြစ်လာနိုင်á€á€²á€·á€•á€«á€žá€Šá€ºá‹</translation>
<translation id="2943895734390379394">အပ်လုဒ်လုပ်á€á€»á€­á€”်-</translation>
<translation id="2948083400971632585">ကြိုá€á€„်ပြင်ဆင်á€á€¼á€„်း စာမျက်နှာမှ á€á€»á€­á€á€ºá€†á€€á€ºá€™á€¾á€¯á€á€…်á€á€¯á€¡á€á€½á€€á€º ပရောက်စီပြုပြင်á€á€»á€€á€ºá€™á€»á€¬á€¸á€¡á€¬á€¸ ပိá€á€ºá€”ိုင်သည်á‹</translation>
@@ -648,6 +680,7 @@
<translation id="3037605927509011580">အောአလက်ဖျောက်!</translation>
<translation id="3041612393474885105">အသိမှá€á€ºá€•á€¼á€¯ လက်မှá€á€º အá€á€»á€€á€ºá€¡á€œá€€á€º</translation>
<translation id="3044034790304486808">သင့်လေ့လာမှုကို ဆက်လုပ်ရန်</translation>
+<translation id="305162504811187366">အá€á€»á€­á€”်ဖော်ပြá€á€»á€€á€ºáŠ ဆာဗာပင်ရင်းနှင့် ကလိုင်းယင့်စက်ရှင် id များအပါအá€á€„် ‘Chrome အá€á€±á€¸á€‘ိန်း ဒက်စ်á€á€±á€¬á€·â€™ မှá€á€ºá€á€™á€ºá€¸</translation>
<translation id="3060227939791841287">C9 (စာအိá€á€º)</translation>
<translation id="3061707000357573562">ပြင်ဆင်á€á€¼á€„်း á€á€”်ဆောင်မှု</translation>
<translation id="306573536155379004">ဂိမ်းစá€á€„်ပါပြီá‹</translation>
@@ -685,6 +718,7 @@
<translation id="3197136577151645743">သင့်ကိရိယာသုံးနေá€á€»á€­á€”်ကို သိရန် á€á€½á€„့်á€á€±á€¬á€„်းနိုင်သည်</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />አChrome ဆက်á€á€„်များá€á€½á€„် သင်စင့်á€á€ºá€œá€¯á€•á€ºá€žá€±á€¬ အá€á€»á€€á€ºá€¡á€œá€€á€ºá€™á€»á€¬á€¸á€€á€­á€¯ စီမံရန် ‘á€á€˜á€ºá€á€œá€¯á€á€ºâ€™ နှိပ်ပြီးနောက် Enter နှိပ်ပါ</translation>
<translation id="320323717674993345">ငွေပေးá€á€»á€±á€™á€¾á€¯á€€á€­á€¯ ပယ်ဖျက်ရန်</translation>
+<translation id="3203366800380907218">á€á€˜á€ºá€•á€±á€«á€ºá€™á€¾</translation>
<translation id="3207960819495026254">ဘွá€á€ºá€™á€€á€ºá€œá€¯á€•á€ºá€•á€¼á€®á€¸á</translation>
<translation id="3209034400446768650">စာမျက်နှာသည် ငွေကုန်ကျမှုများ ဖြစ်စေနိုင်သည်</translation>
<translation id="3212581601480735796"><ph name="HOSTNAME" /> ရှိ သင့်လုပ်ဆောင်á€á€»á€€á€ºá€€á€­á€¯ စောင့်ကြည့်နေသည်</translation>
@@ -701,10 +735,12 @@
<translation id="3234666976984236645">ဤအင်á€á€¬á€”က်စာမျက်နှာ‌ပေါ်á€á€½á€„် အရေးကြီး‌သော မာá€á€­á€€á€¬á€™á€»á€¬á€¸á€€á€­á€¯ အစဉ် ထောက်လှမ်းပါ</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />አá€á€˜á€ºá€”ှိပ်ပြီးနောက် Enter နှိပ်á ဘရောင်ဇာáအသွင်ကို စိá€á€ºá€€á€¼á€­á€¯á€€á€ºá€•á€¼á€„်ပါ</translation>
<translation id="3240791268468473923">ကိုက်ညီမှုရှိသည့် လုံá€á€¼á€¯á€¶á€žá€±á€¬á€•á€±á€¸á€á€»á€±á€™á€¾á€¯á€¡á€‘ောက်အထားဆိုင်ရာ စာရွက်မဖွင့်ထားပါ</translation>
+<translation id="324180406144491771">“<ph name="HOST_NAME" />†လင့်á€á€ºá€™á€»á€¬á€¸á€€á€­á€¯ ပိá€á€ºá€‘ားသည်</translation>
<translation id="3249845759089040423">မိမိမိုက်မိုက်</translation>
<translation id="3252266817569339921">ပြင်သစ်</translation>
<translation id="3257954757204451555">ဤအá€á€»á€€á€ºá€¡á€œá€€á€ºá€€á€­á€¯ ဘယ်ကရသလဲá‹</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />አGoogle Calendar á€á€½á€„် အစီအစဉ်အသစ် အမြန်ပြုလုပ်ရန် ‘á€á€˜á€ºâ€™ နှိပ်ပြီးနောက် Enter á€á€œá€¯á€á€º နှိပ်ပါ</translation>
+<translation id="3261488570342242926">ပကá€á€­á€¡á€žá€½á€„်ကá€á€ºá€™á€»á€¬á€¸á€¡á€€á€¼á€±á€¬á€„်း လေ့လာရန်</translation>
<translation id="3264837738038045344">Chrome ဆက်á€á€„်များ စီမံရန်á€á€œá€¯á€á€ºáŠ သင့် Chrome ဆက်á€á€„်များကို á€á€„်ကြည့်ရန် Enter á€á€œá€¯á€á€º နှိပ်ပါ</translation>
<translation id="3266793032086590337">á€á€”်ဖိုး (ကွဲလွဲသည်)</translation>
<translation id="3268451620468152448">á€á€²á€˜á€ºá€™á€»á€¬á€¸ ဖွင့်ရန်</translation>
@@ -718,6 +754,7 @@
<translation id="3288238092761586174">သင့်ပေးá€á€»á€±á€™á€¾á€¯á€€á€­á€¯ အá€á€Šá€ºá€•á€¼á€¯á€›á€”်အá€á€½á€€á€º <ph name="URL" /> က နောက်ထပ်အဆင့်များ လုပ်ဆောင်ရန် လိုအပ်နိုင်သည်</translation>
<translation id="3293642807462928945"><ph name="POLICY_NAME" /> မူá€á€«á€’အကြောင်း ပိုမိုလေ့လာပါ</translation>
<translation id="3295444047715739395">Chrome ဆက်á€á€„်များá€á€½á€„် သင့်စကားá€á€¾á€€á€ºá€™á€»á€¬á€¸á€€á€­á€¯ ကြည့်ရှုစီမံပါ</translation>
+<translation id="3303795387212510132"><ph name="PROTOCOL_SCHEME" /> လင့်á€á€ºá€™á€»á€¬á€¸á€–ွင့်ရန် အက်ပ်ကိုá€á€½á€„့်ပြုမလားá‹</translation>
<translation id="3303855915957856445">မည်သည့်ရှာဖွေမှု ရလဒ်မျှ မá€á€½á€±á€·á€•á€«</translation>
<translation id="3304073249511302126">ဘလူးá€á€¯á€žá€º ရှာဖွေá€á€¼á€„်း</translation>
<translation id="3308006649705061278">အဖွဲ့အစည်းဆိုင်ရာ ယူနစ် (OU)</translation>
@@ -731,12 +768,6 @@
<translation id="3345782426586609320">မျက်လုံး</translation>
<translation id="3355823806454867987">ပရောက်စီ ဆက်á€á€„်များ ပြောင်းရန်...</translation>
<translation id="3360103848165129075">ငွေပေးá€á€»á€±á€™á€¾á€¯ ကိုင်á€á€½á€šá€ºá€žá€Šá€ºá€·á€…နစ်စာမျက်နှာ</translation>
-<translation id="3361596688432910856">Chrome သည် အောက်ပါ အá€á€»á€€á€ºá€¡á€œá€€á€ºá€™á€»á€¬á€¸á€€á€­á€¯ <ph name="BEGIN_EMPHASIS" />သိမ်းဆည်းမည်မဟုá€á€ºá€•á€«<ph name="END_EMPHASIS" />−
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />သင်á အင်á€á€¬á€”က်အသုံးပြုမှု မှá€á€ºá€á€™á€ºá€¸
- <ph name="LIST_ITEM" />ကွá€á€ºá€€á€®á€¸á€”ှင့် á€á€˜á€ºá€†á€­á€¯á€€á€ºá€’ေá€á€¬á€™á€»á€¬á€¸
- <ph name="LIST_ITEM" />ဖောင်များá€á€½á€„် ထည့်သွင်းထားသည့် အá€á€»á€€á€ºá€¡á€œá€€á€ºá€™á€»á€¬á€¸
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">အသုံးမပြုá€á€±á€¬á€·á€žá€±á€¬ <ph name="OLD_POLICY" /> မူá€á€«á€’မှ ဤမူá€á€«á€’ကို အလိုအလျောက် မိá€á€¹á€á€°á€€á€°á€¸á€‘ားပါသည်ዠáŽá€„်းအစား ဤမူá€á€«á€’ကို အသုံးပြုရပါမည်á‹</translation>
<translation id="3364869320075768271"><ph name="URL" /> က သင်áပကá€á€­á€¡á€žá€½á€„်စက်နှင့် ဒေá€á€¬á€™á€»á€¬á€¸á€€á€­á€¯ အသုံးပြုလိုသည်</translation>
<translation id="3366477098757335611">ကá€á€ºá€™á€»á€¬á€¸á€€á€­á€¯ ကြည့်ရန်</translation>
@@ -818,7 +849,6 @@
<translation id="3587738293690942763">အလယ်အလá€á€º</translation>
<translation id="3592413004129370115">အီá€á€œá€® (စာအိá€á€º)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{သင့်အဖွဲ့ကို အá€á€»á€­á€”်မရွေး ပြင်ဆင်သá€á€ºá€™á€¾á€á€ºá€”ိုင်သည်ዠအဖွဲ့သစ်á€á€½á€„်ပါá€á€„်ရန် á€á€…်ရက် ကြာမြင့်သည်á‹}=1{သင့်အဖွဲ့ကို အá€á€»á€­á€”်မရွေး ပြင်ဆင်သá€á€ºá€™á€¾á€á€ºá€”ိုင်သည်ዠအဖွဲ့သစ်á€á€½á€„်ပါá€á€„်ရန် á€á€…်ရက် ကြာမြင့်သည်á‹}other{သင့်အဖွဲ့ကို အá€á€»á€­á€”်မရွေး ပြင်ဆင်သá€á€ºá€™á€¾á€á€ºá€”ိုင်သည်ዠအဖွဲ့သစ်á€á€½á€„်ပါá€á€„်ရန် {NUM_DAYS} ရက် ကြာမြင့်သည်á‹}}</translation>
-<translation id="3596012367874587041">အက်ပ်ဆက်á€á€„်များ</translation>
<translation id="3600246354004376029"><ph name="TITLE" />አ<ph name="DOMAIN" />አ<ph name="TIME" /></translation>
<translation id="3603507503523709">သင့်စီမံá€á€”့်á€á€½á€²á€žá€°á€€ ပိá€á€ºá€‘ားသည့် အပလီကေးရှင်း</translation>
<translation id="3608932978122581043">ဖိဒ်အနေအထား</translation>
@@ -860,6 +890,7 @@
<translation id="370972442370243704">‘á€á€›á€®á€¸á€…ဉ်များ’ ဖွင့်ရန်</translation>
<translation id="3711895659073496551">ဆိုင်းငံ့ထားရန်</translation>
<translation id="3712624925041724820">လိုင်စင်များ ကုန်ဆုံးသွားပြီ</translation>
+<translation id="3714633008798122362">á€á€˜á€º ပြက္á€á€’ိန်</translation>
<translation id="3714780639079136834">မိုဘိုင်းဒေá€á€¬ သို့မဟုá€á€º Wi-Fi ကိုဖွင့်နေသည်</translation>
<translation id="3715597595485130451">Wi-Fi á€á€»á€­á€á€ºá€†á€€á€ºá€›á€”်</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />ပရောက်စီአfirewall နှင့် DNS ပြင်ဆင်သá€á€ºá€™á€¾á€á€ºá€™á€¾á€¯á€€á€­á€¯ စစ်ဆေးနေသည်<ph name="END_LINK" /></translation>
@@ -867,7 +898,7 @@
<translation id="3727101516080730231"><ph name="CREATE_GOOGLE_SLIDE_FOCUSED_FRIENDLY_MATCH_TEXT" />አSlides á€á€½á€„် Google á€á€„်ပြမှုအသစ် အမြန်ပြုလုပ်ရန် ‘á€á€˜á€ºâ€™ နှိပ်ပြီးနောက် Enter á€á€œá€¯á€á€º နှိပ်ပါ</translation>
<translation id="373042150751172459">B4 (စာအိá€á€º)</translation>
<translation id="3736520371357197498">သင်က သင့်အá€á€½á€€á€º ရှိနိုင်သည့် အန္á€á€›á€¬á€šá€ºá€™á€»á€¬á€¸á€€á€­á€¯ နားလည် ဆိုလျှင်አသင်သည် <ph name="BEGIN_LINK" />မလုံá€á€¼á€¯á€¶á€žá€±á€¬ ဆိုက်ကို<ph name="END_LINK" /> အန္á€á€›á€¬á€šá€º ရှိကြသည့် ပရိုဂရမ်များကို ဖယ်ရှားပေးမှု မá€á€­á€¯á€„်á€á€„် á€á€„်ကြည့်နိုင်ပါသည်á‹</translation>
-<translation id="3738166223076830879">သင်á ဘရောင်ဇာကို သင့်စီမံá€á€”့်á€á€½á€²á€žá€°á€€ စီမံá€á€”့်á€á€½á€²á€‘ားပါသည်á‹</translation>
+<translation id="3738166223076830879">သင်á ဘရောင်ဇာကို သင့်ကြီးကြပ်သူက စီမံá€á€”့်á€á€½á€²á€‘ားပါသည်á‹</translation>
<translation id="3744111561329211289">နောက်á€á€¶á€á€½á€„် စင့်á€á€ºá€œá€¯á€•á€ºá€á€¼á€„်း</translation>
<translation id="3744899669254331632">á€á€€á€ºá€˜á€ºá€†á€­á€¯á€€á€ºá€€ ဗလုံးဗထွေး ပို့လိုက်သည့် အထောက်အထားများကို Chromium ဖက်မှ စီမံဆောင်ရွက် မရနိုင်သောကြောင့် သင်သည် <ph name="SITE" /> ကို ယá€á€¯á€á€»á€€á€ºá€á€»á€„်း á€á€„်မရနိုင်ပါዠကွန်ရက် အမှားများ နှင့် á€á€­á€¯á€€á€ºá€á€­á€¯á€€á€ºá€™á€¾á€¯á€™á€»á€¬á€¸á€™á€¾á€¬ ယာယီမျှသာ ဖြစ်ကြá€á€¬á€™á€­á€¯á€·á€œá€­á€¯á€·áŠ ဒီစာမျက်နှာသည် နောက်ပိုင်းမှာ အလုပ်လုပ်နိုင်ပါမည်á‹</translation>
<translation id="3745099705178523657">အá€á€Šá€ºá€•á€¼á€¯á€•á€¼á€®á€¸á€”ောက် သင်á Google အကောင့်ရှိ ကဒ်အသေးစိá€á€º အá€á€»á€€á€ºá€¡á€œá€€á€ºá€™á€»á€¬á€¸á€€á€­á€¯ ဤဆိုက်အား မျှá€á€±á€žá€½á€¬á€¸á€•á€«á€™á€Šá€ºá‹</translation>
@@ -908,7 +939,7 @@
<translation id="385051799172605136">နောက်သို့</translation>
<translation id="3858027520442213535">ရက်စွဲ နှင့် အá€á€»á€­á€”်ကို မွမ်းမံပါ</translation>
<translation id="3858860766373142691">အမည်</translation>
-<translation id="3879224246272917991">CPU/RAM အသုံးပြုမှုနှင့် ကွန်ပျူá€á€¬á€†á€­á€¯á€„်ရာစက်ပစ္စည်း သá€á€ºá€™á€¾á€á€ºá€á€»á€€á€ºá€™á€»á€¬á€¸á€€á€²á€·á€žá€­á€¯á€· စက်á ကိန်းဂá€á€”်းစာရင်းများ</translation>
+<translation id="3879224246272917991">CPU/RAM အသုံးပြုမှုနှင့် ဟာ့ဒ်á€á€² သá€á€ºá€™á€¾á€á€ºá€á€»á€€á€ºá€™á€»á€¬á€¸á€€á€²á€·á€žá€­á€¯á€· စက်á ကိန်းဂá€á€”်းစာရင်းများ</translation>
<translation id="3881478300875776315">စာကြောင်းလျှော့áပြရန်</translation>
<translation id="3884278016824448484">စက်ပစ္စည်း မည်သူမည်á€á€«á€–ြစ်ကြောင်း အသိမှá€á€ºá€•á€¼á€¯á€žá€° ရှုပ်ထွေးနေ</translation>
<translation id="3885155851504623709">နယ်​မြေ</translation>
@@ -921,6 +952,7 @@
<translation id="3906954721959377182">á€á€€á€ºá€˜á€œá€€á€º</translation>
<translation id="3909477809443608991"><ph name="URL" /> က ကာကွယ်ထားသည့် အကြောင်းအရာကို ဖွင့်လိုသည်ዠသင့်စက်á အထောက်အထားကို Google က အá€á€Šá€ºá€•á€¼á€¯á€™á€Šá€º ဖြစ်ပြီး ဤá€á€˜á€ºá€†á€­á€¯á€€á€ºá€€ á€á€„်သုံးá€á€½á€„့်ရနိုင်ပါသည်á‹</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">ငြင်းပယ်</translation>
<translation id="3939773374150895049">CVC အစား WebAuthn သုံးမလားá‹</translation>
<translation id="3946209740501886391">ဤဆိုက်ပေါ်á€á€½á€„် အမြဲမေးပါ</translation>
<translation id="3947595700203588284">MIDI ကိရိယာများသို့ á€á€»á€­á€á€ºá€†á€€á€ºá€›á€”် á€á€½á€„့်á€á€±á€¬á€„်းနိုင်သည်</translation>
@@ -942,6 +974,7 @@
<translation id="3990250421422698716">လည်ပá€á€ºá€™á€¾á€¯ á€á€»á€­á€”်ညှိရန်</translation>
<translation id="3996311196211510766">á€á€˜á€ºá€†á€­á€¯á€€á€º <ph name="ORIGIN" /> က áŽá€„်းáá€á€±á€¬á€„်းဆိုá€á€»á€€á€º အားလုံးသို့
ရင်းမြစ်မူá€á€«á€’ ထည့်သွင်းရန် သá€á€ºá€™á€¾á€á€ºá€‘ားသော်လည်း လက်ရှိá€á€½á€„် ဤမူá€á€«á€’ကို ထည့်သွင်းáမရပါá‹</translation>
+<translation id="4009243425692662128">သင်ပုံနှိပ်ထုá€á€ºá€œá€­á€¯á€€á€ºá€žá€±á€¬ စာမျက်နှာများáအကြောင်းအရာကို စိá€á€ºá€–ြာလေ့လာရန် Google Cloud (သို့) ပြင်ပအဖွဲ့အစည်းသို့ ပို့လိုက်သည်ዠဥပမာ သá€á€­á€‘ားရမည့်ဒေá€á€¬ ရှိአမရှိ áŽá€„်းကို စစ်ဆေးနိုင်သည်á‹</translation>
<translation id="4010758435855888356">သိုလှောင်á€á€”်းကို သုံးá€á€½á€„့်ပြုမလားá‹</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{စာမျက်နှာ {COUNT} မျက်နှာ ပါá€á€„်သော PDF မှá€á€ºá€á€™á€ºá€¸}other{စာမျက်နှာ {COUNT} မျက်နှာ ပါá€á€„်သော PDF မှá€á€ºá€á€™á€ºá€¸}}</translation>
<translation id="4023431997072828269">မလုံá€á€¼á€¯á€¶á€žá€±á€¬á€á€»á€­á€á€ºá€†á€€á€ºá€™á€¾á€¯á€€á€­á€¯ အသုံးပြုပြီး ဤဖောင်ကိုပေးပို့ထားသဖြင့် အá€á€¼á€¬á€¸á€žá€°á€™á€»á€¬á€¸á€€ သင့်အá€á€»á€€á€ºá€¡á€œá€€á€ºá€™á€»á€¬á€¸á€€á€­á€¯ မြင်နိုင်သည်á‹</translation>
@@ -1037,6 +1070,7 @@
<translation id="4250680216510889253">No</translation>
<translation id="4253168017788158739">မှá€á€ºá€á€»á€€á€º</translation>
<translation id="425582637250725228">သင်ပြုလုပ်á€á€²á€·á€žá€Šá€·á€º ပြောင်းလဲá€á€»á€€á€ºá€™á€»á€¬á€¸á€€á€­á€¯ သိမ်းဆည်းမည်မဟုá€á€ºá€•á€«á‹</translation>
+<translation id="425869179292622354">ပကá€á€­á€¡á€žá€½á€„်ကá€á€ºá€–ြင့် ပိုမိုလုံá€á€¼á€¯á€¶á€¡á€±á€¬á€„် လုပ်မလားá‹</translation>
<translation id="4258748452823770588">ဆိုးရွားသည့် လက်မှá€á€º</translation>
<translation id="4261046003697461417">ကာကွယ်ထားသော မှá€á€ºá€á€™á€ºá€¸á€–ိုင်များကို မှá€á€ºá€á€»á€€á€ºá€•á€±á€¸á မရပါ</translation>
<translation id="4265872034478892965">သင်á စီမံá€á€”့်á€á€½á€²á€žá€°á€€ á€á€½á€„့်ပြုထားá€á€¼á€„်းဖြစ်သည်</translation>
@@ -1099,6 +1133,7 @@
<translation id="4434045419905280838">ပေါ့ပ်အပ်နှင့် á€á€…်ဆင့်ညွှန်á€á€»á€€á€º</translation>
<translation id="4435702339979719576">ပို့စ်ကá€á€º)</translation>
<translation id="443673843213245140">ပရောက်စီ သုံးရန်ပိá€á€ºá€‘ားသော်လည်း á€á€­á€€á€»á€žá€Šá€ºá€· ပရောက်စီ စီစဉ်ဖွဲ့စည်းမှုကို သá€á€ºá€™á€¾á€á€ºá€‘ားသည်á‹</translation>
+<translation id="4441832193888514600">မူá€á€«á€’ကို cloud အသုံးပြုသူလိုက်နာရမည့် မူá€á€«á€’အဖြစ်သာ သá€á€ºá€™á€¾á€á€ºá€”ိုင်သောကြောင့် လျစ်လျူရှုထားသည်á‹</translation>
<translation id="4450893287417543264">ထပ်မပြပါနှင့်</translation>
<translation id="4451135742916150903">HID ကိရိယာများနှင့် á€á€»á€­á€á€ºá€†á€€á€ºá€›á€”် á€á€½á€„့်á€á€±á€¬á€„်းနိုင်သည်</translation>
<translation id="4452328064229197696">သင်သုံးလိုက်သောစကားá€á€¾á€€á€ºá€€á€­á€¯ ဒေá€á€¬á€€á€»á€­á€¯á€¸á€•á€±á€«á€€á€ºá€™á€¾á€¯á€á€½á€„် á€á€½á€±á€·á€›á€¾á€­á€‘ားသည်ዠသင့်အကောင့်များကို လုံá€á€¼á€¯á€¶á€…ေရန် ‘Google စကားá€á€¾á€€á€ºá€™á€”်နေဂျာ’ က သင်သိမ်းထားသော စကားá€á€¾á€€á€ºá€™á€»á€¬á€¸á€€á€­á€¯ စစ်ဆေးရန် အကြံပြုပါသည်á‹</translation>
@@ -1154,6 +1189,7 @@
<translation id="4628948037717959914">ဓာá€á€ºá€•á€¯á€¶</translation>
<translation id="4631649115723685955">ငွေပြန်ပေးá€á€¼á€„်းကို လင့်á€á€ºá€á€»á€­á€á€ºá€‘ားသည်</translation>
<translation id="4636930964841734540">အá€á€»á€€á€ºá€¡á€œá€€á€º</translation>
+<translation id="4638670630777875591">Chromium ရှိ ရုပ်ဖျက်မုဒ်</translation>
<translation id="464342062220857295">ရှာဖွေရေး á€á€”်ဆောင်မှုများ</translation>
<translation id="4644670975240021822">ပြောင်းပြန်အစဉ်ဖြင့် မှောက်ထားရန်</translation>
<translation id="4646534391647090355">ထိုနေရာသို့ ယá€á€¯á€žá€½á€¬á€¸á€›á€”်</translation>
@@ -1174,6 +1210,7 @@
<translation id="4708268264240856090">သင့်á€á€»á€­á€á€ºá€†á€€á€ºá€™á€¾á€¯ ကြားá€á€„်စွá€á€ºá€–က်á€á€¼á€„်း á€á€¶á€á€²á€·á€›á€•á€«á€žá€Šá€º</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />á€á€„်းဒိုးကွန်ရက်ပြဿနာရှာဖွေမှု ပြုလုပ်ပါ<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426"><ph name="USERNAME" /> အá€á€½á€€á€º စကားá€á€¾á€€á€º</translation>
<translation id="4724144314178270921">သင့်ကလစ်ဘုá€á€ºá€›á€¾á€­ စာသားနှင့် ရုပ်ပုံများကြည့်ရန် á€á€½á€„့်á€á€±á€¬á€„်းနိုင်သည်</translation>
<translation id="4726672564094551039">မူá€á€«á€’များကို ပြန်á€á€„်ရန်</translation>
<translation id="4728558894243024398">ပလက်ဖောင်</translation>
@@ -1195,6 +1232,7 @@
<translation id="4757993714154412917">လှည့်ဖြားá€á€á€ºá€žá€±á€¬ á€á€˜á€ºá€†á€­á€¯á€€á€ºá€á€…်á€á€¯á€á€½á€„် သင့်စကားá€á€¾á€€á€ºá€€á€­á€¯ သင်က ယá€á€¯á€œá€±á€¸á€á€½á€„် ထည့်လိုက်သည်ዠအကောင့်များ လုံá€á€¼á€¯á€¶á€…ေရန်အá€á€½á€€á€º သင်သိမ်းထားသည့် စကားá€á€¾á€€á€ºá€™á€»á€¬á€¸á€€á€­á€¯ စစ်ဆေးရန် Chromium ကအကြုံပြုပါသည်á‹</translation>
<translation id="4758311279753947758">ဆက်သွယ်ရန်အá€á€»á€€á€ºá€¡á€œá€€á€º ထည့်ရန်</translation>
<translation id="4761104368405085019">သင့်မိုက်á€á€›á€­á€¯á€–ုန်းကို အသုံးပြုရန်</translation>
+<translation id="4761869838909035636">‘Chrome လုံá€á€¼á€¯á€¶á€›á€±á€¸ စစ်ဆေးမှု’ လုပ်ဆောင်ရန်</translation>
<translation id="4764776831041365478"><ph name="URL" /> ပေါ်က á€á€˜á€ºá€…ာမျက်နှာမှ ယာယီ ဒေါင်းနေá€á€¬ ဖြစ်နိုင်သည် သို့မဟုá€á€º áŽá€„်းသည် á€á€˜á€º လိပ်စာ သစ်ဆီသို့ ထာá€á€› ရွှေ့ပြောင်းသွားá€á€¬ ဖြစ်နိုင်သည်á‹</translation>
<translation id="4766713847338118463">အောက်á€á€¼á€±á€á€½á€„် á€á€»á€¯á€•á€ºá€…က်ဖြင့် နှစ်á€á€»á€€á€ºá€á€»á€¯á€•á€ºá€›á€”်</translation>
<translation id="4771973620359291008">မသိရသည့် မှားယွင်းမှုá€á€…်á€á€¯ ဖြစ်á€á€²á€·á€žá€Šá€ºá‹</translation>
@@ -1215,12 +1253,6 @@
<translation id="4819347708020428563">မှá€á€ºá€á€»á€€á€ºá€™á€»á€¬á€¸á€€á€­á€¯ မူရင်းမြင်ကွင်းá€á€½á€„် á€á€Šá€ºá€¸á€–ြá€á€ºá€™á€œá€¬á€¸á‹</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />አGoogle Sheet အသစ် အမြန်ပြုလုပ်ရန် ‘á€á€˜á€ºâ€™ နှိပ်ပြီးနောက် Enter á€á€œá€¯á€á€º နှိပ်ပါ</translation>
<translation id="4825507807291741242">စွမ်းအားပြည့်</translation>
-<translation id="4827402517081186284">ရုပ်ဖျက်မုဒ်က အွန်လိုင်းပေါ်á€á€½á€„် သင့်ကိုမမြင်ရအောင် မလုပ်နိုင်ပါ-
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />သင်á€á€„်ကြည့်နေသည်ကို á€á€˜á€ºá€†á€­á€¯á€€á€ºá€™á€»á€¬á€¸á€€ သိနိုင်သည်<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />အလုပ်ရှင် (သို့) ကျောင်းများက ကြည့်ရှုá€á€¼á€„်းများကို á€á€¼á€±á€›á€¬á€á€¶á€”ိုင်သည်<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />အင်á€á€¬á€”က်á€á€”်ဆောင်မှုပေးသူများက ကွန်ရက်ဒေá€á€¬á€…ီးဆင်းမှုကို စောင့်ကြည့်နေနိုင်သည်<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">သá€á€­á€•á€±á€¸á€á€»á€€á€ºá€™á€»á€¬á€¸ ဖွင့်ရန်</translation>
<translation id="4838327282952368871">အိပ်မက်ဆန်ဆန်</translation>
<translation id="4840250757394056958">သင့် ‘Chrome မှá€á€ºá€á€™á€ºá€¸â€™ ကို ကြည့်ရန်</translation>
@@ -1232,12 +1264,12 @@
<translation id="4854362297993841467">ဤပစ္စည်းပို့á€á€¼á€„်းနည်းလမ်းသည် မရနိုင်ပါዠအá€á€¼á€¬á€¸á€”ည်းလမ်းá€á€…်á€á€¯á€€á€­á€¯ ရွေးပါá‹</translation>
<translation id="4854853140771946034">Google Keep á€á€½á€„် မှá€á€ºá€…ုအသစ် အမြန်ပြုလုပ်ရန်</translation>
<translation id="485902285759009870">ကုဒ်ကို စိစစ်နေသည်...</translation>
+<translation id="4866506163384898554">သင်áကာဆာကို ပြရန် |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| နှိပ်ပါ</translation>
<translation id="4876188919622883022">ရိုးရှင်းသည့် မြင်ကွင်း</translation>
<translation id="4876305945144899064">အသုံးပြုသူအမည် မရှိ</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{မရှိ}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />አ<ph name="EXAMPLE_DOMAIN_2" />}other{<ph name="EXAMPLE_DOMAIN_1" />አ<ph name="EXAMPLE_DOMAIN_2" />አ<ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831"><ph name="TEXT" /> ရှာဖွေမှု</translation>
<translation id="4879491255372875719">အလိုအလျောက် (မူရင်း)</translation>
-<translation id="4879725228911483934">သင့်ဖန်သားပြင်များá€á€½á€„် á€á€„်းဒိုးများ ဖွင့်ပြီး နေရာá€á€»á€‘ားá€á€¼á€„်း</translation>
<translation id="4880827082731008257">ရှာဖွေမှု မှá€á€ºá€á€™á€ºá€¸</translation>
<translation id="4881695831933465202">ဖွင့်</translation>
<translation id="4885256590493466218">ငွေရှင်းသည့်နေရာá€á€½á€„် <ph name="CARD_DETAIL" /> ဖြင့် ပေးá€á€»á€±á€•á€«</translation>
@@ -1246,6 +1278,7 @@
<translation id="4895877746940133817"><ph name="TYPE_1" />አ<ph name="TYPE_2" />አ<ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">ကိုးá€á€¯á€™á€¼á€±á€¬á€€á€ºá€¡á€œá€­á€•á€º</translation>
<translation id="4901778704868714008">သိမ်းရန်...</translation>
+<translation id="4905659621780993806">သင့်စီမံá€á€”့်á€á€½á€²á€žá€°á€€ စက်ကို <ph name="DATE" />አ<ph name="TIME" /> á€á€½á€„် အလိုအလျောက်ပြန်စမည်ዠဖွင့်ထားသောဖိုင်အားလုံး သင့်စက်ပြန်မစမီ သိမ်းပါá‹</translation>
<translation id="4913987521957242411">ဘယ်ဘက်ထိပ်á€á€½á€„် ဖောက်ရန်</translation>
<translation id="4918221908152712722"><ph name="APP_NAME" /> ကို ထည့်သွင်းပါ (ဒေါင်းလုဒ်လုပ်ရန် မလိုပါ)</translation>
<translation id="4923459931733593730">ငွေပေးá€á€»á€±á€™á€¾á€¯</translation>
@@ -1254,6 +1287,7 @@
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />አTab ကိုနှိပ်ပြီးနောက် Enter နှိပ်á ရှာဖွေပါ</translation>
<translation id="4930153903256238152">သိုလှောင်နိုင်မှု မြင့်သည်</translation>
+<translation id="4940163644868678279">Chrome ရှိ ရုပ်ဖျက်မုဒ်</translation>
<translation id="4943872375798546930">ရလဒ်မရှိပါ</translation>
<translation id="4950898438188848926">á€á€˜á€ºá€•á€¼á€±á€¬á€„်းရန်á€á€œá€¯á€á€ºáŠ ပွင့်နေသောá€á€˜á€º <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /> သို့ ပြောင်းရန် Enter ကို နှိပ်ပါ</translation>
<translation id="495170559598752135">လုပ်ဆောင်á€á€»á€€á€ºá€™á€»á€¬á€¸</translation>
@@ -1263,6 +1297,7 @@
<translation id="4968522289500246572">ဤအက်ပ်ကို မိုဘိုင်းအá€á€½á€€á€º ထုá€á€ºá€œá€¯á€•á€ºá€‘ားသဖြင့် ကောင်းစွာ အရွယ်အစားပြန်ပြင်နိုင်မည် မဟုá€á€ºá€•á€«á‹ အက်ပ်á€á€½á€„် ပြဿနာများ ဖြစ်နိုင်သည် (သို့) ပြန်စနိုင်သည်á‹</translation>
<translation id="4969341057194253438">ဖမ်းယူမှုဖိုင်ကို ဖျက်ရန်</translation>
<translation id="4973922308112707173">ထိပ်á€á€½á€„် နှစ်á€á€»á€€á€ºá€–ောက်ရန်</translation>
+<translation id="4976702386844183910"><ph name="DATE" /> က နောက်ဆုံး á€á€„်ကြည့်ထားသည်</translation>
<translation id="4984088539114770594">မိုက်á€á€›á€­á€¯á€–ုန်းကို အသုံးပြုမလားá‹</translation>
<translation id="4984339528288761049">Prc5 (စာအိá€á€º)</translation>
<translation id="4989163558385430922">အားလုံး ကြည့်ရန်</translation>
@@ -1324,6 +1359,7 @@
<translation id="5138227688689900538">လျှော့ပြရန်</translation>
<translation id="5145883236150621069">ပေါ်လစီá€á€¯á€¶á€·á€•á€¼á€”်မှုá€á€½á€„် အမှားကုဒ်ရှိသည်á‹</translation>
<translation id="5146995429444047494"><ph name="ORIGIN" /> အá€á€½á€€á€º အကြောင်းကြားá€á€»á€€á€ºá€™á€»á€¬á€¸ ပိá€á€ºá€‘ားသည်</translation>
+<translation id="514704532284964975"><ph name="URL" /> က သင့်ဖုန်းဖြင့်á€á€­á€¯á€·á€žá€±á€¬ NFC စက်ပစ္စည်းများရှိ အá€á€»á€€á€ºá€¡á€œá€€á€ºá€™á€»á€¬á€¸á€€á€­á€¯ ကြည့်ကာ ပြောင်းလဲလိုပါသည်</translation>
<translation id="5148809049217731050">အပေါ်လှန်ထားရန်</translation>
<translation id="515292512908731282">C4 (စာအိá€á€º)</translation>
<translation id="5158275234811857234">မျက်နှာဖုံး</translation>
@@ -1348,6 +1384,7 @@
<translation id="5215116848420601511">Google Pay ကို သုံးထားသော ငွေပေးá€á€»á€±á€”ည်းလမ်းနှင့် လိပ်စာများ</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">ဗန်း ááƒ</translation>
+<translation id="5216942107514965959">ယနေ့ နောက်ဆုံး á€á€„်ကြည့်ထားသည်</translation>
<translation id="5222812217790122047">အီးမေးလ် လိုအပ်သည်</translation>
<translation id="5230733896359313003">ပစ္စည်းပို့ရမည့်လိပ်စာ</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1368,7 +1405,6 @@
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">မှá€á€ºá€á€™á€ºá€¸ သá€á€ºá€™á€¾á€á€ºá€á€»á€€á€ºá€™á€»á€¬á€¸</translation>
<translation id="528468243742722775">အဆုံး</translation>
-<translation id="5284909709419567258">ကွန်ရက် လိပ်စာများ</translation>
<translation id="5285570108065881030">သိမ်းထားသော စကားá€á€¾á€€á€ºá€™á€»á€¬á€¸á€¡á€¬á€¸á€œá€¯á€¶á€¸á€€á€­á€¯ ပြရန်</translation>
<translation id="5287240709317226393">ကွá€á€ºá€€á€®á€¸á€™á€»á€¬á€¸ ပြရန်</translation>
<translation id="5287456746628258573">ဤá€á€˜á€ºá€†á€­á€¯á€€á€ºá€žá€Šá€º လုံá€á€¼á€¯á€¶á€›á€±á€¸ စီစဉ်သá€á€ºá€™á€¾á€á€ºá€á€»á€€á€ºá€¡á€Ÿá€±á€¬á€„်းကို အသုံးပြုထားသည့်အá€á€½á€€á€º áŽá€„်းá€á€­á€¯á€·á€€á€­á€¯ ဤá€á€˜á€ºá€†á€­á€¯á€€á€ºá€žá€­á€¯á€· ပို့သည့်အá€á€« သင့်အá€á€»á€€á€ºá€¡á€œá€€á€ºá€™á€»á€¬á€¸ ပေါက်ကြားသွားနိုင်ပါသည် (ဥပမာ စကားá€á€¾á€€á€ºá€™á€»á€¬á€¸á€”ှင့် á€á€›á€€á€ºá€’စ်ကá€á€ºá€”ံပါá€á€ºá€™á€»á€¬á€¸)á‹</translation>
@@ -1452,6 +1488,7 @@
<translation id="5556459405103347317">ပြန်á€á€„်ရန်</translation>
<translation id="5560088892362098740">သက်á€á€™á€ºá€¸ ကုန်ဆုံးမည့်ရက်</translation>
<translation id="55635442646131152">မှá€á€ºá€á€™á€ºá€¸ အကြမ်းဖော်ပြá€á€»á€€á€º</translation>
+<translation id="5565613213060953222">ရုပ်ဖျက်á€á€˜á€ºá€–ွင့်ရန်</translation>
<translation id="5565735124758917034">အသက်á€á€„်နေ</translation>
<translation id="5570825185877910964">အကောင့်ကို ကာကွယ်ရန်</translation>
<translation id="5571083550517324815">ဤလိပ်စာမှ ပစ္စည်းထုá€á€ºá€šá€°áမရပါዠအá€á€¼á€¬á€¸á€œá€­á€•á€ºá€…ာá€á€…်á€á€¯á€€á€­á€¯ ရွေးပါá‹</translation>
@@ -1534,6 +1571,7 @@
<translation id="5869522115854928033">သိမ်းဆည်းထားသည့် စကားá€á€¾á€€á€ºá€™á€»á€¬á€¸</translation>
<translation id="5873013647450402046">သင်ဖြစ်ကြောင်း သင့်ဘá€á€ºá€€ အá€á€Šá€ºá€•á€¼á€¯á€œá€­á€¯á€žá€Šá€º</translation>
<translation id="5887400589839399685">ကá€á€ºá€€á€­á€¯ သိမ်းပြီးပါပြီ</translation>
+<translation id="5887687176710214216">မနေ့က နောက်ဆုံး á€á€„်ကြည့်ထားသည်</translation>
<translation id="5895138241574237353">ပြန်စá€á€„်မည</translation>
<translation id="5895187275912066135">ထုá€á€ºá€•á€±á€¸ ရက်</translation>
<translation id="5901630391730855834">အáါရောင်</translation>
@@ -1547,6 +1585,7 @@
<translation id="5921639886840618607">ကá€á€ºá€€á€­á€¯ Google အကောင့်သို့ သိမ်းလိုပါသလားá‹</translation>
<translation id="5922853866070715753">ပြီးလုနီးပါပြီ</translation>
<translation id="5932224571077948991">á€á€˜á€ºá€†á€­á€¯á€€á€ºá€€ စိá€á€ºá€¡á€”ှောင့်အယှက်ဖြစ်စေသော (သို့) အထင်အမြင်မှားစေသော ကြော်ငြာများကို ပြသည်</translation>
+<translation id="5938153366081463283">ပကá€á€­á€¡á€žá€½á€„်ကá€á€º ထည့်ရန်</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347"><ph name="SITE_NAME" /> ကို ဖွင့်နေသည်…</translation>
<translation id="5951495562196540101">အသုံးပြုသူ အကောင့်ဖြင့် စာရင်းသွင်းá မရပါ (ပက်ကေ့á€á€»á€ºá€œá€¯á€•á€ºá€‘ားသော လိုင်စင်ကို ရနိုင်သည်)á‹</translation>
@@ -1611,6 +1650,7 @@
<translation id="6120179357481664955">သင့် UPI ID ကို မှá€á€ºá€™á€­á€•á€«á€žá€œá€¬á€¸á‹</translation>
<translation id="6124432979022149706">Chrome လုပ်ငန်းသုံး á€á€»á€­á€á€ºá€†á€€á€ºá€žá€Šá€ºá€·á€€á€­á€›á€­á€šá€¬á€™á€»á€¬á€¸</translation>
<translation id="6127379762771434464">အကြောင်းအရာကို ဖယ်ရှားလိုက်ပါပြီ</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Chrome ရှိ ရုပ်ဖျက်မုဒ်အကြောင်း ပိုမိုလေ့လာရန်<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">သင်အသုံးပြုနေသည့် ရောက်á€á€¬á€™á€»á€¬á€¸áŠ မိုဒမ်းများአသို့မဟုá€á€º အá€á€¼á€¬á€¸á€€á€½á€”်ယက်စက်ပစ္စည်းများနှင့် ကြိုးများကို စစ်ဆေးပါá‹</translation>
<translation id="614940544461990577">စမ်းကြည့်ပါ −</translation>
<translation id="6150036310511284407">ဘယ်ဘက်á€á€½á€„် သုံးá€á€»á€€á€ºá€–ောက်ရန်</translation>
@@ -1622,7 +1662,6 @@
<translation id="6169916984152623906">ယá€á€¯á€†á€­á€¯á€œá€»á€¾á€„် á€á€˜á€ºá€…ာမျက်နှာများကို သင်á€á€…်ဦးá€á€Šá€ºá€¸á€žá€®á€¸á€žá€”့် ဖွင့်ကြည့်နိုင်ပြီဖြစ်ပြီး ဤစက်ပစ္စည်းကို အသုံးပြုသော အá€á€¼á€¬á€¸á€žá€°á€™á€»á€¬á€¸á€€ သင်áလုပ်ဆောင်á€á€»á€€á€ºá€€á€­á€¯ မြင်နိုင်á€á€±á€¬á€·á€™á€Šá€ºá€™á€Ÿá€¯á€á€ºá€•á€«á‹ သို့သော်လည်း ဒေါင်းလုဒ်လုပ်ထားသည့်အရာနှင့် လိပ်စာများကိုမူ သိမ်းဆည်ထားပါမည်á‹</translation>
<translation id="6177128806592000436">ဤá€á€˜á€ºá€†á€­á€¯á€€á€ºá€žá€­á€¯á€· သင်áá€á€»á€­á€á€ºá€†á€€á€ºá€‘ားမှုသည် လုံá€á€¼á€¯á€¶á€™á€¾á€¯á€™á€›á€¾á€­á€•á€«</translation>
<translation id="6180316780098470077">ပြန်စမ်းá€á€»á€­á€”် ကြားကာလ</translation>
-<translation id="619448280891863779">သင့်ဖန်သားပြင်များá€á€½á€„် á€á€„်းဒိုးများ ဖွင့်ပြီး နေရာá€á€»á€‘ားရန် á€á€½á€„့်á€á€±á€¬á€„်းနိုင်သည်</translation>
<translation id="6196640612572343990">ပြင်ပကုမ္ပá€á€®á€€á€½á€á€ºá€€á€®á€¸á€™á€»á€¬á€¸á€€á€­á€¯ ပိá€á€ºá€†á€­á€¯á€·á€™á€Šá€º</translation>
<translation id="6203231073485539293">သင့်အင်á€á€¬á€”က် á€á€»á€­á€á€ºá€†á€€á€ºá€™á€¾á€¯á€€á€­á€¯ စစ်ပါ</translation>
<translation id="6218753634732582820">Chromium ထဲမှ လိပ်စာကို ဖယ်ရှားရမလားá‹</translation>
@@ -1645,7 +1684,7 @@
<translation id="6272383483618007430">Google Update</translation>
<translation id="6276112860590028508">ဖá€á€ºá€›á€”်စာရင်းမှ စာမျက်နှာများကို ဤနေရာá€á€½á€„် á€á€½á€±á€·á€›á€•á€«á€™á€Šá€º</translation>
<translation id="627746635834430766">နောင်á€á€½á€„် မြန်ဆန်စွာပေးá€á€»á€±á€”ိုင်ရန် သင်áကá€á€ºá€”ှင့် ငွေá€á€±á€¬á€„်းá€á€¶á€œá€½á€¾á€¬á€•á€­á€¯á€·á€žá€±á€¬ လိပ်စာကို သင့် Google အကောင့်á€á€½á€„် သိမ်းပါá‹</translation>
-<translation id="6279098320682980337">ပကá€á€­á€¡á€žá€½á€„်ကá€á€º နံပါá€á€º ဖြည့်မထားဘူးလားዠမိá€á€¹á€á€°á€€á€°á€¸á€›á€”် ကá€á€ºá€¡á€žá€±á€¸á€…ိá€á€ºá€¡á€á€»á€€á€ºá€™á€»á€¬á€¸á€€á€­á€¯ နှိပ်ပါ</translation>
+<translation id="6279183038361895380">သင်á ညွှန်းမြားကို ပြပေးရန် |<ph name="ACCELERATOR" />ကို နှိပ်ပါ</translation>
<translation id="6280223929691119688">ဤလိပ်စာသို့ ပို့áမရပါዠအá€á€¼á€¬á€¸á€œá€­á€•á€ºá€…ာá€á€…်á€á€¯á€€á€­á€¯ ရွေးပါá‹</translation>
<translation id="6282194474023008486">စာပို့သင်္ကေá€</translation>
<translation id="6285507000506177184">Chrome á€á€½á€„် ဒေါင်းလုဒ်များ စီမံရန်á€á€œá€¯á€á€ºáŠ Chrome á€á€½á€„် ဒေါင်းလုဒ်လုပ်á€á€²á€·á€žá€Šá€·á€ºá€–ိုင်များကို စီမံရန် Enter နှိပ်ပါ</translation>
@@ -1653,6 +1692,7 @@
<translation id="6290238015253830360">သင်အကြံပြုထားသည့် ဆောင်းပါးများ ဤနေရာá€á€½á€„် ပေါ်ပါမည်</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC-</translation>
+<translation id="6300452962057769623">{0,plural, =0{သင့်စက်ကို ယá€á€¯á€•á€¼á€”်စမည်}=1{သင့်စက်ကို 1 စက္ကန့်အá€á€½á€„်း ပြန်စမည်}other{သင့်စက်ကို # စက္ကန့်အá€á€½á€„်း ပြန်စမည်}}</translation>
<translation id="6302269476990306341">Chrome အá€á€½á€„်းရှိ Google Assistant ရပ်á€á€”့်နေသည်</translation>
<translation id="6305205051461490394"><ph name="URL" /> ကိုဆက်သွယ်áမရနိုင်ပါá‹</translation>
<translation id="6312113039770857350">á€á€˜á€ºá€…ာမျက်နှာ မရှိ</translation>
@@ -1726,6 +1766,7 @@
<translation id="6529602333819889595">&amp;ဖျက်ရန်ကို ပြန်လုပ်ရန်</translation>
<translation id="6545864417968258051">ဘလူးá€á€¯á€žá€º ရှာဖွေá€á€¼á€„်း</translation>
<translation id="6547208576736763147">ဘယ်ဘက်á€á€½á€„် နှစ်á€á€»á€€á€ºá€–ောက်ရန်</translation>
+<translation id="6554732001434021288">ပြီးá€á€²á€·á€žá€±á€¬ <ph name="NUM_DAYS" /> ရက်က နောက်ဆုံး á€á€„်ကြည့်ထားသည်</translation>
<translation id="6556866813142980365">ပြန်လုပ်ရန်</translation>
<translation id="6569060085658103619">သင်သည် နောက်ဆက်á€á€½á€²á€…ာမျက်နှာကို ကြည့်ရှုနေá€á€¼á€„်းဖြစ်သည်</translation>
<translation id="6573200754375280815">ညာဘက်á€á€½á€„် နှစ်á€á€»á€€á€ºá€–ောက်ရန်</translation>
@@ -1786,7 +1827,6 @@
<translation id="6757797048963528358">သင့်စက်ပစ္စည်း အိပ်ပျော်သွားပါသည်á‹</translation>
<translation id="6767985426384634228">လိပ်စာ အပ်ဒိá€á€ºá€œá€¯á€•á€ºá€™á€œá€¬á€¸á‹</translation>
<translation id="6768213884286397650">ဟာဂကိ (ပို့စ်ကá€á€º)</translation>
-<translation id="6774185088257932239">ရုပ်ဖျက်မုဒ်အကြောင်း <ph name="BEGIN_LINK" />ပိုမိုလေ့လာရန်<ph name="END_LINK" /></translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">á€á€›á€™á€ºá€¸á€•á€¼á€¬</translation>
<translation id="6786747875388722282">အိá€á€ºá€…á€á€”်းရှင်းများ</translation>
@@ -1870,7 +1910,6 @@
<translation id="706295145388601875">Chrome ဆက်á€á€„်များá€á€½á€„် လိပ်စာများထည့်ရန်နှင့် စီမံရန်</translation>
<translation id="7064851114919012435">ဆက်သွယ်ရန်အá€á€»á€€á€ºá€¡á€œá€€á€º</translation>
<translation id="7068733155164172741">ဂá€á€”်း-<ph name="OTP_LENGTH" /> လုံးပါကုဒ် ထည့်ပါ</translation>
-<translation id="7070090581017165256">ဤá€á€˜á€ºá€†á€­á€¯á€€á€ºá€¡á€€á€¼á€±á€¬á€„်း</translation>
<translation id="70705239631109039">သင့်á€á€»á€­á€á€ºá€†á€€á€ºá€™á€¾á€¯á€žá€Šá€º လုံá€á€¼á€¯á€¶á€™á€¾á€¯á€¡á€•á€¼á€Šá€·á€ºá€¡á€á€™á€›á€¾á€­á€•á€«</translation>
<translation id="7075452647191940183">á€á€±á€¬á€„်းဆိုá€á€»á€€á€º အလွန်ကြီးနေသည်</translation>
<translation id="7079718277001814089">ဤဆိုက်á€á€½á€„် မဲလ်á€á€² ပါá€á€„်ပါသည်</translation>
@@ -1887,6 +1926,12 @@
<translation id="7111012039238467737">(မှန်ကန်သည်)</translation>
<translation id="7118618213916969306">ကလစ်ဘုá€á€º URL <ph name="SHORT_URL" /> အá€á€½á€€á€º ရှာဖွေမှု</translation>
<translation id="7119414471315195487">အá€á€¼á€¬á€¸á€á€˜á€º သို့မဟုá€á€º ပရိုဂရမ်များကို ပိá€á€ºá€•á€«</translation>
+<translation id="7129355289156517987">Chromium ရုပ်ဖျက်á€á€˜á€ºá€¡á€¬á€¸á€œá€¯á€¶á€¸ ပိá€á€ºá€œá€­á€¯á€€á€ºá€žá€±á€¬á€¡á€á€« ထိုá€á€˜á€ºá€™á€»á€¬á€¸á€›á€¾á€­ သင့်လုပ်ဆောင်á€á€»á€€á€ºá€€á€­á€¯ ဤစက်မှ ဖျက်လိုက်မည်-
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ကြည့်ရှုá€á€¼á€„်းများ<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ရှာဖွေမှá€á€ºá€á€™á€ºá€¸<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ဖောင်များá€á€½á€„်ထည့်ထားသော အá€á€»á€€á€ºá€¡á€œá€€á€º<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">ဤလိပ်စာသို့ ပို့áမရပါዠအá€á€¼á€¬á€¸á€œá€­á€•á€ºá€…ာá€á€…်á€á€¯á€€á€­á€¯ ရွေးပါá‹</translation>
<translation id="7132939140423847331">ဤဒေá€á€¬á€€á€°á€¸á€šá€°á€á€¼á€„်းကို သင့်စီမံá€á€”့်á€á€½á€²á€žá€°á€€ á€á€¬á€¸á€™á€¼á€…်ထားသည်á‹</translation>
<translation id="7135130955892390533">အá€á€¼á€±á€¡á€”ေ ပြရန်</translation>
@@ -1909,6 +1954,7 @@
<translation id="7192203810768312527"><ph name="SIZE" /> နေရာလွá€á€ºá€¡á€±á€¬á€„်လုပ်ပါዠနောက်á€á€…်ကြိမ် á€á€„်ကြည့်သည့်အá€á€«á€á€½á€„် အá€á€»á€­á€¯á€·á€á€˜á€ºá€†á€­á€¯á€€á€ºá€™á€»á€¬á€¸á€€ ပိုနှေးနေနိုင်ပါသည်á‹</translation>
<translation id="719464814642662924">ဗီဇာ</translation>
<translation id="7201591969684833065">သင့်စီမံá€á€”့်á€á€½á€²á€žá€°á€™á€»á€¬á€¸á€€ အောက်ပါá€á€­á€¯á€·á€€á€­á€¯ မြင်နိုင်သည်-</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />አTab နှိပ်ပြီး Enter á€á€œá€¯á€á€ºá€”ှိပ်á ရုပ်ဖျက်á€á€˜á€ºá€¡á€žá€…်á€á€½á€„် သီးသန့်ကြည့်ရှုနိုင်သည်</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> သည်လုံá€á€¼á€¯á€¶á€›á€±á€¸ စံနှုန်းများကို လိုက်နာမှုမရှိပါá‹</translation>
<translation id="7210993021468939304">ကွန်á€á€­á€”်နာအá€á€½á€„်းရှိ Linux လုပ်ဆောင်á€á€»á€€á€ºá€€á€­á€¯ ကြည့်နိုင်ပြီး ကွန်á€á€­á€”်နာအá€á€½á€„်းá€á€½á€„် Linux အက်ပ်များကို ထည့်သွင်းနိုင်አလုပ်ဆောင်နိုင်သည်</translation>
@@ -1941,6 +1987,7 @@
<translation id="7304562222803846232">Google Account ကိုယ်ရေးအá€á€»á€€á€ºá€¡á€œá€€á€ºá€œá€¯á€¶á€á€¼á€¯á€¶á€™á€¾á€¯ ဆက်á€á€„်များကို စီမံရန်</translation>
<translation id="7305756307268530424">ဂိမ်းအနှေး စá€á€„်ရန်</translation>
<translation id="7308436126008021607">နောက်á€á€¶á€á€½á€„်စင့်á€á€ºá€œá€¯á€•á€ºá€á€¼á€„်း</translation>
+<translation id="7310392214323165548">များမကြာမီ စက် ပြန်စပါမည်</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">á€á€»á€­á€á€ºá€†á€€á€ºá€™á€¾á€¯ အကူအညီ</translation>
<translation id="7323804146520582233">"<ph name="SECTION" />" ကá€á€¹á€á€€á€­á€¯ á€á€¾á€€á€ºá€›á€”်</translation>
@@ -1948,6 +1995,7 @@
<translation id="7334320624316649418">&amp;ပြန်စီမှုကို ပြန်လုပ်ရန်</translation>
<translation id="7335157162773372339">သင့်ကင်မရာသုံးရန် á€á€½á€„့်á€á€±á€¬á€„်းနိုင်သည်</translation>
<translation id="7337248890521463931">စာကြောင်းပိုပြရန်</translation>
+<translation id="7337418456231055214">ပကá€á€­á€¡á€žá€½á€„်ကá€á€º နံပါá€á€º ဖြည့်မထားဘူးလားዠမိá€á€¹á€á€°á€€á€°á€¸á€›á€”် ကá€á€ºá€¡á€žá€±á€¸á€…ိá€á€ºá€¡á€á€»á€€á€ºá€™á€»á€¬á€¸á€€á€­á€¯ နှိပ်နိုင်သည်ዠ<ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">သင်အသုံးပြုနေသည့်စနစ်အá€á€½á€€á€º မရနိုင်ပါá‹</translation>
<translation id="733923710415886693">ဆာဗာáအသိအမှá€á€ºá€•á€¼á€¯á€œá€€á€ºá€™á€¾á€á€ºá€€á€­á€¯ အသိအမှá€á€ºá€•á€¼á€¯á€œá€€á€ºá€™á€¾á€á€ºá€•á€½á€„့်လင်းမြင်သာရှိမှုမှá€á€…်ဆင့် ဖော်ပြထားá€á€¼á€„်း မရှိပါá‹</translation>
<translation id="734600844861828519">ááxáá…</translation>
@@ -1970,6 +2018,7 @@
<translation id="7378627244592794276">မဟုá€á€ºá€•á€«</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">မသက်ဆိုင်ပါ</translation>
+<translation id="7388594495505979117">{0,plural, =1{သင်áစက်သည် 1 မိနစ်အá€á€½á€„်း ပြန်စမည်}other{သင်áစက်သည် # မိနစ်အá€á€½á€„်း ပြန်စမည်}}</translation>
<translation id="7390545607259442187">ကဒ်ကို အá€á€Šá€ºá€•á€¼á€¯á€•á€«</translation>
<translation id="7392089738299859607">လိပ်စာ အပ်ဒိá€á€ºá€œá€¯á€•á€ºá€•á€«</translation>
<translation id="7399802613464275309">လုံá€á€¼á€¯á€¶á€›á€±á€¸ စစ်ဆေးမှု</translation>
@@ -2006,6 +2055,12 @@
<translation id="7485870689360869515">ဒေá€á€¬ မá€á€½á€±á€·á€›á€•á€«á‹</translation>
<translation id="7495528107193238112">ဤအကြောင်းအရာကို ပိá€á€ºá€‘ားသည်ዠပြဿနာကို ဖြေရှင်းရန် á€á€˜á€ºá€†á€­á€¯á€€á€ºá€•á€­á€¯á€„်ရှင်ကို ဆက်သွယ်ပါá‹</translation>
<translation id="7497998058912824456">Doc ပြုလုပ်ရန် á€á€œá€¯á€á€ºáŠ Google Doc အသစ် အမြန်ပြုလုပ်ရန် Enter á€á€œá€¯á€á€º နှိပ်ပါ</translation>
+<translation id="7506488012654002225">Chromium သည် အောက်ပါအá€á€»á€€á€ºá€¡á€œá€€á€ºá€™á€»á€¬á€¸á€€á€­á€¯ <ph name="BEGIN_EMPHASIS" />သိမ်းမည်မဟုá€á€ºá€•á€«<ph name="END_EMPHASIS" />-
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />သင်á ကြည့်ရှုá€á€¼á€„်းမှá€á€ºá€á€™á€ºá€¸
+ <ph name="LIST_ITEM" />ကွá€á€ºá€€á€®á€¸á€”ှင့် á€á€˜á€ºá€†á€­á€¯á€€á€ºá€’ေá€á€¬
+ <ph name="LIST_ITEM" />ဖောင်များá€á€½á€„်ထည့်ထားသော အá€á€»á€€á€ºá€¡á€œá€€á€º
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">ပစ္စည်းပြန်ပို့နိုင်သည့် မူá€á€«á€’ဆိုင်ရာကိရိယာအိုင်ဒီသည် ကွက်လပ်ဖြစ်နေပါသည် သို့မဟုá€á€º လက်ရှိကိရိယာအိုင်ဒီနှင့် ကိုက်ညီမှုမရှိပါ</translation>
<translation id="7508870219247277067">ထောပá€á€ºá€žá€®á€¸á€…ိမ်း</translation>
<translation id="7511955381719512146">သင်အသုံးပြုနေသော Wi-Fi သည် <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />သို့ သင်သွားရောက်ကြည့်ရှုရန် လိုအပ်စေလိမ့်မည်á‹</translation>
@@ -2119,7 +2174,6 @@
<translation id="7813600968533626083">Chrome မှပုံစံ အကြံပြုမှုများ ဖယ်ရှားမလား?</translation>
<translation id="781440967107097262">ကလစ်ဘုá€á€º မျှá€á€±á€™á€œá€¬á€¸á‹</translation>
<translation id="7815407501681723534">'<ph name="SEARCH_STRING" />' အá€á€½á€€á€º <ph name="SEARCH_RESULTS" /> <ph name="NUMBER_OF_RESULTS" /> á€á€¯ á€á€½á€±á€·á€‘ားသည်</translation>
-<translation id="782125616001965242">ဤá€á€˜á€ºá€†á€­á€¯á€€á€ºá€¡á€€á€¼á€±á€¬á€„်း အá€á€»á€€á€ºá€¡á€œá€€á€ºá€™á€»á€¬á€¸ ပြရန်</translation>
<translation id="782886543891417279">သင်အသုံးပြုနေသော Wi-Fi ( <ph name="WIFI_NAME" /> ) á login စာမျက်နှာသို့ သင်သွားရောက်ကြည့်ရှုရန် လိုမည်á‹</translation>
<translation id="7836231406687464395">Postfix (စာအိá€á€º)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{မရှိ}=1{အက်ပ် á á€á€¯ (<ph name="EXAMPLE_APP_1" />)}=2{အက်ပ် á‚ á€á€¯ (<ph name="EXAMPLE_APP_1" />አ<ph name="EXAMPLE_APP_2" />)}other{အက်ပ် # á€á€¯ (<ph name="EXAMPLE_APP_1" />አ<ph name="EXAMPLE_APP_2" />አ<ph name="AND_MORE" />)}}</translation>
@@ -2136,7 +2190,6 @@
<translation id="7888575728750733395">ပုံနှိပ်မှုဆိုင်ရာ ပြင်ဆင်မှု ရည်ရွယ်á€á€»á€€á€º</translation>
<translation id="7894280532028510793">စာလုံးပေါင်း မှန်ကန်ပါက <ph name="BEGIN_LINK" />ကွန်ရက် အမှားရှာဖွေမှုများပြုလုပ်ရန် ကြိုးစားကြည့်ပါ<ph name="END_LINK" />á‹</translation>
<translation id="7904208859782148177">C3 (စာအိá€á€º)</translation>
-<translation id="7931318309563332511">အမျိုးအမည်မသိ</translation>
<translation id="793209273132572360">လိပ်စာ အပ်ဒိá€á€ºá€œá€¯á€•á€ºá€™á€œá€¬á€¸á‹</translation>
<translation id="7932579305932748336">အလွှာအုပ်ရန်</translation>
<translation id="79338296614623784">မှန်ကန်သောဖုန်းနံပါá€á€ºá€€á€­á€¯ ထည့်ပါ</translation>
@@ -2161,14 +2214,15 @@
<translation id="7976214039405368314">á€á€±á€¬á€„်းဆိုမှုများ များလွန်းနေသည်</translation>
<translation id="7977538094055660992">ထုá€á€ºá€šá€°á€™á€Šá€·á€ºá€…က်</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">áŽá€„်းနှင့် လင့်á€á€ºá€á€»á€­á€á€ºá€‘ားသည်</translation>
<translation id="798134797138789862">ပကá€á€­á€¡á€žá€½á€„် စက်နှင့် ဒေá€á€¬á€™á€»á€¬á€¸ သုံးရန် á€á€½á€„့်á€á€±á€¬á€„်းနိုင်သည်</translation>
<translation id="7984945080620862648">á€á€€á€ºá€˜á€ºá€†á€­á€¯á€€á€ºá€€ ပို့ပေးá€á€²á€·á€žá€Šá€ºá€· စိá€á€ºá€á€»á€›á€žá€Šá€ºá€· အá€á€»á€€á€ºá€¡á€œá€€á€ºá€™á€»á€¬á€¸á€™á€¾á€¬ ရောနှောနေá Chrome အနေနှင့် စီမံလုပ်ကိုင် မရသောကြောင့် သင်သည် <ph name="SITE" />ကို ယá€á€¯á€á€»á€€á€ºá€á€»á€„်း á€á€„်ကြည့် မရနိုင်ပါዠကွန်ရက် အမှားများ နှင့် á€á€­á€¯á€€á€ºá€á€­á€¯á€€á€ºá€™á€¾á€¯á€™á€»á€¬á€¸á€™á€¾á€¬ အများအားဖြင့် á€á€á€šá€¬á€šá€®á€•á€«áŠ သို့ဖြစ်á ဒီစာမျက်နှာသည်
နောက်ပိုင်းá€á€½á€„် အလုပ်လုပ် နိုင်ဖွယ် ရှိပါသည်á‹</translation>
-<translation id="79859296434321399">လွန်ကဲပကá€á€­á€¡á€žá€½á€„်ကို ကြည့်ရန် ARCore ကို ထည့်ပါ</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">á€á€½á€²á€á€»á€¯á€•á€ºá€›á€”်</translation>
<translation id="7992044431894087211"><ph name="APPLICATION_TITLE" /> အား မျက်နှာပြင်မျှá€á€±á€á€¼á€„်းကို ဆက်လုပ်ထားသည်</translation>
<translation id="7995512525968007366">သá€á€ºá€™á€¾á€á€ºá€™á€‘ားပါ</translation>
+<translation id="7998269595945679889">ရုပ်ဖျက်á€á€˜á€ºá€á€œá€¯á€á€ºá€€á€­á€¯ ဖွင့်ပါዠရုပ်ဖျက်á€á€˜á€ºá€¡á€žá€…်á€á€…်á€á€¯á€–ြင့် သီးသန့်ကြည့်ရှုနိုင်ရန် Enter á€á€œá€¯á€á€ºá€”ှိပ်ပါ</translation>
<translation id="800218591365569300">မှá€á€ºá€‰á€¬á€á€ºá€”ေရာလွá€á€ºá€›á€›á€¾á€­á€…ေရန် á€á€˜á€º သို့မဟုá€á€º ပရိုဂရမ်များကို ပိá€á€ºá€€á€¼á€Šá€·á€ºá€•á€«á‹</translation>
<translation id="8004582292198964060">ဘရောင်ဇာ</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{ဤကá€á€ºá€”ှင့် áŽá€„်းáငွေá€á€±á€¬á€„်းá€á€¶á€™á€¾á€¯ လိပ်စာကို သိမ်းဆည်းသွားပါမည်ዠ<ph name="USER_EMAIL" /> သို့ လက်မှá€á€ºá€‘ိုးá€á€„်ထားသည့်အá€á€« သင်အသုံးပြုနိုင်ပါမည်á‹}other{ဤကá€á€ºá€™á€»á€¬á€¸á€”ှင့် áŽá€„်းá€á€­á€¯á€·á ငွေá€á€±á€¬á€„်းá€á€¶á€™á€¾á€¯ လိပ်စာများကို သိမ်းဆည်းသွားပါမည်ዠ<ph name="USER_EMAIL" /> သို့ လက်မှá€á€ºá€‘ိုးá€á€„်ထားသည့်အá€á€« áŽá€„်းá€á€­á€¯á€·á€€á€­á€¯ သင်အသုံးပြုနိုင်ပါမည်á‹}}</translation>
@@ -2228,6 +2282,7 @@
<translation id="8202370299023114387">ပြဿနာ</translation>
<translation id="8206978196348664717">Prc4 (စာအိá€á€º)</translation>
<translation id="8211406090763984747">á€á€»á€­á€á€ºá€†á€€á€ºá€™á€¾á€¯á€žá€Šá€º လုံá€á€¼á€¯á€¶á€•á€«á€žá€Šá€º</translation>
+<translation id="8217240300496046857">á€á€˜á€ºá€•á€±á€«á€ºá€á€½á€„် သင့်အားá€á€¼á€±á€›á€¬á€á€¶á€žá€Šá€ºá€· ကွá€á€ºá€€á€®á€¸á€™á€»á€¬á€¸á€€á€­á€¯ á€á€˜á€ºá€†á€­á€¯á€€á€ºá€™á€»á€¬á€¸á€€ အသုံးမပြုနိုင်ပါዠအá€á€»á€­á€¯á€·á€á€˜á€ºá€†á€­á€¯á€€á€ºá€™á€»á€¬á€¸á€•á€±á€«á€ºá€›á€¾á€­ á€á€”်ဆောင်မှုများ ရပ်သွားနိုင်သည်á‹</translation>
<translation id="8218327578424803826">သá€á€ºá€™á€¾á€á€ºá€‘ားသော á€á€Šá€ºá€”ေရာ-</translation>
<translation id="8220146938470311105">C7/C6 (စာအိá€á€º)</translation>
<translation id="8225771182978767009">ဤကွန်ပျူá€á€¬á€€á€­á€¯ á€á€•á€ºá€†á€„်á€á€²á€·á€žá€°á€žá€Šá€º ဤဆိုက်ကိုပိá€á€ºá€†á€­á€¯á€·á€›á€”် ဆုံးဖြá€á€ºá€á€²á€·á€žá€Šá€ºá‹</translation>
@@ -2268,14 +2323,9 @@
<translation id="830498451218851433">á€á€…်á€á€€á€º á€á€±á€«á€€á€ºá€›á€”်</translation>
<translation id="8307358339886459768">ဓာá€á€ºá€•á€¯á€¶ အသေး</translation>
<translation id="8307888238279532626">ထည့်သွင်းထားသော အက်ပ်များနှင့် áŽá€„်းá€á€­á€¯á€·á€€á€­á€¯ မည်မျှá€á€…်ကြိမ် အသုံးပြုပုံ</translation>
+<translation id="8317207217658302555">ARCore ကို အပ်ဒိá€á€ºá€œá€¯á€•á€ºá€™á€œá€¬á€¸á‹</translation>
<translation id="831997045666694187">ညနေ</translation>
<translation id="8321476692217554900">အကြောင်းကြားá€á€»á€€á€ºá€™á€»á€¬á€¸</translation>
-<translation id="8328484624016508118">ရုပ်ဖျက်á€á€˜á€ºá€¡á€¬á€¸á€œá€¯á€¶á€¸ ပိá€á€ºá€•á€¼á€®á€¸á€á€»á€­á€”်á€á€½á€„် Chrome က အောက်ပါá€á€­á€¯á€·á€€á€­á€¯á€›á€¾á€„်းလင်းမည်-
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />ဤစက်ရှိ ကြည့်ရှုမှုများ<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />ဤစက်ရှိ ရှာဖွေမှá€á€ºá€á€™á€ºá€¸á€™á€»á€¬á€¸<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />ဖောင်များá€á€½á€„် ထည့်သွင်းသည့်အá€á€»á€€á€ºá€¡á€œá€€á€ºá€™á€»á€¬á€¸<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489"><ph name="HOST_NAME" /> အားအသုံးပြုá€á€½á€„့် ပယ်á€á€»á€á€¶á€á€²á€·á€›á€•á€«á€žá€Šá€º</translation>
<translation id="833262891116910667">အထူးအသားပေး ဖော်ပြá€á€»á€€á€º</translation>
<translation id="8339163506404995330"><ph name="LANGUAGE" /> ဘာသာဖြင့် စာမျက်နှာများကို ဘာသာပြန်သွားပါမည်</translation>
@@ -2327,6 +2377,7 @@
<translation id="8507227106804027148">ညွှန်ကြားá€á€»á€€á€º လိုင်း</translation>
<translation id="8508648098325802031">ရှာဖွေမှု သင်္ကေá€</translation>
<translation id="8511402995811232419">ကွá€á€ºá€€á€®á€¸á€™á€»á€¬á€¸ စီမံရန်</translation>
+<translation id="8519753333133776369">HID စက်ကို သင့်စီမံá€á€”့်á€á€½á€²á€žá€°á€€ á€á€½á€„့်ပြုထားသည်</translation>
<translation id="8522552481199248698">Chrome က သင်á Google အကောင့်ကို ကာကွယ်ရန်နှင့် စကားá€á€¾á€€á€ºá€•á€¼á€±á€¬á€„်းရန် ကူညီနိုင်ပါသည်á‹</translation>
<translation id="8530813470445476232">Chrome ဆက်á€á€„်များá€á€½á€„် ကြည့်ရှုá€á€¼á€„်းမှá€á€ºá€á€™á€ºá€¸áŠ ကွá€á€ºá€€á€®á€¸á€™á€»á€¬á€¸áŠ ကက်ရှ်နှင့် အá€á€¼á€¬á€¸á€¡á€›á€¬á€™á€»á€¬á€¸á€€á€­á€¯ ရှင်းပါ</translation>
<translation id="8533619373899488139">သင်á စနစ်စီမံá€á€”့်á€á€½á€²á€žá€°á€€ ပြဋ္ဌာန်းထားသည့် အá€á€¼á€¬á€¸ မူá€á€«á€’များနှင့် ပိá€á€ºá€‘ားသော URL များစာရင်းကို ကြည့်ရန် &lt;strong&gt;chrome://policy&lt;/strong&gt; သို့ á€á€„်ကြည့်ပါá‹</translation>
@@ -2338,7 +2389,6 @@
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{á€á€½á€„့်ပြုá€á€»á€€á€º ပြင်ဆင်သá€á€ºá€™á€¾á€á€ºá€›á€”်}other{á€á€½á€„့်ပြုá€á€»á€€á€ºá€™á€»á€¬á€¸ ပြင်ဆင်သá€á€ºá€™á€¾á€á€ºá€›á€”်}}</translation>
<translation id="8555010941760982128">ငွေရှင်းသည့်အá€á€« ဤကုဒ်ကို သုံးပါ</translation>
<translation id="8557066899867184262">CVC သည် သင့်ကဒ်အနောက်ဘက်á€á€¼á€™á€ºá€¸á€á€½á€„် ရှိသည်á‹</translation>
-<translation id="8558485628462305855">လွန်ကဲပကá€á€­á€¡á€žá€½á€„်ကို ကြည့်ရန် ARCore ကို အပ်ဒိá€á€ºá€œá€¯á€•á€ºá€•á€«</translation>
<translation id="8559762987265718583">သင့်ကိရိယာá ရက်စွဲ နှင့် အá€á€»á€­á€”် (<ph name="DATE_AND_TIME" />)မှာ မမှန်á <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> ထံသို့ ကိုယ်ရေး á€á€»á€­á€á€ºá€†á€€á€ºá€™á€¾á€¯á€€á€­á€¯ ထူထောင်မရနိုင်ပါá‹</translation>
<translation id="8564182942834072828">သီးá€á€¼á€¬á€¸ စာရွက်စာá€á€™á€ºá€¸á€™á€»á€¬á€¸/စုစည်းစီစဉ်မထားသော မိá€á€¹á€á€°á€™á€»á€¬á€¸</translation>
<translation id="8564985650692024650">အá€á€¼á€¬á€¸á€á€˜á€ºá€†á€­á€¯á€€á€ºá€™á€»á€¬á€¸á€á€½á€„် သင်á <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> စကားá€á€¾á€€á€ºá€€á€­á€¯ ပြန်သုံးထားပါက áŽá€„်းကို ပြင်ဆင်သá€á€ºá€™á€¾á€á€ºá€›á€”် Chromium က အကြံပြုပါသည်á‹</translation>
@@ -2357,6 +2407,7 @@
<translation id="865032292777205197">လှုပ်ရှားမှု အာရုံá€á€¶á€…နစ်များ</translation>
<translation id="8663226718884576429">မှာယူမှု အနှစ်á€á€»á€¯á€•á€ºáŠ <ph name="TOTAL_LABEL" />አနောက်ထပ် အသေးစိá€á€ºá€¡á€á€»á€€á€ºá€¡á€œá€€á€ºá€™á€»á€¬á€¸</translation>
<translation id="8666678546361132282">အင်္ဂလိပ်</translation>
+<translation id="8669306706049782872">á€á€„်းဒိုးများဖွင့်ပြီး နေရာá€á€»á€‘ားရန် သင့်ဖန်သားပြင်အá€á€»á€€á€ºá€¡á€œá€€á€ºá€€á€­á€¯ အသုံးပြုá€á€¼á€„်း</translation>
<translation id="867224526087042813">လက်မှá€á€º</translation>
<translation id="8676424191133491403">မနှောင့်နှေးရ</translation>
<translation id="8680536109547170164"><ph name="QUERY" /> ဖြေကြားပါአ<ph name="ANSWER" /></translation>
@@ -2383,6 +2434,7 @@
<translation id="8731544501227493793">စကားá€á€¾á€€á€ºá€…ီမံရန်á€á€œá€¯á€á€ºáŠ သင့်စကားá€á€¾á€€á€ºá€™á€»á€¬á€¸á€€á€­á€¯ Chrome ဆက်á€á€„်များá€á€½á€„် ကြည့်ရှုရန်နှင့် စီမံရန် Enter နှိပ်ပါ</translation>
<translation id="8734529307927223492">သင်á <ph name="DEVICE_TYPE" /> ကို <ph name="MANAGER" /> က စီမံá€á€”့်á€á€½á€²á€žá€Šá€º</translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />አTab နှိပ်ပြီးနောက် Enter နှိပ်á ရုပ်ဖျက်á€á€„်းဒိုးသစ်á€á€½á€„် သီးသန့်ဖွင့်ကြည့်ပါ</translation>
+<translation id="8737685506611670901"><ph name="PROTOCOL" /> လင့်များအား <ph name="REPLACED_HANDLER_TITLE" /> အစား ဖွင့်ရန်</translation>
<translation id="8738058698779197622">စိá€á€ºá€á€»á€›á€žá€Šá€ºá€· á€á€»á€­á€á€ºá€†á€€á€ºá€™á€¾á€¯á€€á€­á€¯ ထူထောင်ရန်አသင့်နာရီကို မှန်ကန်စွာ သá€á€ºá€™á€¾á€á€ºá€•á€±á€¸á€›á€”် လိုအပ်သည်ዠá€á€€á€ºá€˜á€ºá€†á€­á€¯á€€á€ºá€™á€»á€¬á€¸á€€ မိမိကိုမိမိ သက်သေထူရန် အသုံးပြုကြသည့် လက်မှá€á€ºá€™á€»á€¬á€¸á€™á€¾á€¬ သá€á€ºá€™á€¾á€á€ºá€‘ားသည့် အá€á€»á€­á€”်ကာလ အá€á€½á€„်းမှာသာ သက်á€á€™á€ºá€¸á€›á€¾á€­á€€á€¼á ဖြစ်ပါသည်ዠသင့်ကိရိယာá နာရီá€á€»á€­á€”် မမှန်သောကြောင့်አChromium က ထိုလက်မှá€á€ºá€™á€»á€¬á€¸á€€á€­á€¯ စိစစ်မရနိုင်ပါá‹</translation>
<translation id="8740359287975076522"><ph name="HOST_NAME" />á &lt;abbr id="dnsDefinition"&gt;DNS လိပ်စာ&lt;/abbr&gt; ကိုရှာမá€á€½á€±á€·á€•á€«á‹ ပြဿနာကို အဖြေရှာနေပါသည်á‹</translation>
<translation id="8742371904523228557"><ph name="ONE_TIME_CODE" /> သည် <ph name="ORIGIN" /> အá€á€½á€€á€º သင်áကုဒ်ဖြစ်သည်</translation>
@@ -2410,6 +2462,7 @@
<translation id="883848425547221593">အá€á€¼á€¬á€¸ စာညှပ်များ</translation>
<translation id="884264119367021077">ပို့ဆောင်ရမည့် လိပ်စာ</translation>
<translation id="884923133447025588">ရုá€á€ºá€žá€­á€™á€ºá€¸á€á€¼á€„်း စက်ကိရိယာ မá€á€½á€±á€·á€•á€«á‹</translation>
+<translation id="8849262850971482943">ထပ်ဆောင်းလုံá€á€¼á€¯á€¶á€›á€±á€¸á€¡á€á€½á€€á€º သင်áပကá€á€­á€¡á€žá€½á€„်ကá€á€º သုံးပါ</translation>
<translation id="885730110891505394">Google ဖြင့်မျှá€á€±á€á€¼á€„်း</translation>
<translation id="8858065207712248076">အá€á€¼á€¬á€¸á€á€˜á€ºá€†á€­á€¯á€€á€ºá€™á€»á€¬á€¸á€á€½á€„် သင်á <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> စကားá€á€¾á€€á€ºá€€á€­á€¯ ပြန်သုံးထားပါက áŽá€„်းကို ပြင်ဆင်သá€á€ºá€™á€¾á€á€ºá€›á€”် Chrome က အကြံပြုပါသည်á‹</translation>
<translation id="885906927438988819">စာလုံးပေါင်း မှန်ကန်ပါက <ph name="BEGIN_LINK" />á€á€„်းဒိုးကွန်ရက် အမှားရှာဖွေမှုများပြုလုပ်ရန် ကြိုးစားကြည့်ပါ<ph name="END_LINK" />á‹</translation>
@@ -2459,6 +2512,7 @@
<translation id="9004367719664099443">VR စက်ရှင် ဖွင့်ထားသည်</translation>
<translation id="9005998258318286617">PDF ဖိုင်ကို ဖွင့်áမရပါ</translation>
<translation id="9008201768610948239">လျစ်လျူရှုရန်</translation>
+<translation id="901834265349196618">အီးမေးလ်</translation>
<translation id="9020200922353704812">ကá€á€ºá€„ွေá€á€±á€¬á€„်းá€á€¶á€œá€½á€¾á€¬á€•á€­á€¯á€·á€›á€”် လိပ်စာလိုအပ်ပါသည်</translation>
<translation id="9020542370529661692">ဒီစာမျက်နှာကို <ph name="TARGET_LANGUAGE" />သို့ ဘာသာပြန်ပေးá€á€²á€·á€žá€Šá€ºá‹</translation>
<translation id="9020742383383852663">A8</translation>
@@ -2507,6 +2561,7 @@
<translation id="9150045010208374699">သင့်ကင်မရာအား အသုံးပြုမည်</translation>
<translation id="9150685862434908345">သင့်စီမံá€á€”့်á€á€½á€²á€žá€°á€€ သင်áဘရောင်ဇာ စနစ်ထည့်သွင်းမှုကို အá€á€±á€¸á€™á€¾ ပြောင်းလဲနိုင်ပါသည်ዠဤစက်ပေါ်ရှိ လုပ်ဆောင်á€á€»á€€á€ºá€™á€»á€¬á€¸á€€á€­á€¯á€œá€Šá€ºá€¸ Chrome ပြင်ပမှ စီမံá€á€”့်á€á€½á€²á€‘ားá€á€¼á€„်း ဖြစ်နိုင်သည်ዠ<ph name="BEGIN_LINK" />ပိုမိုလေ့လာရန်<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">မွမ်းမံပြီး</translation>
+<translation id="9155211586651734179">á€á€½á€²á€á€»á€­á€á€ºá€‘ားသည့် အသံဆိုင်ရာá€á€»á€­á€á€ºá€†á€€á€ºá€•á€…္စည်းများ</translation>
<translation id="9157595877708044936">စဖွင့်သá€á€ºá€™á€¾á€á€ºá€”ေ...</translation>
<translation id="9158625974267017556">C6 (စာအိá€á€º)</translation>
<translation id="9164029392738894042">á€á€­á€€á€»á€™á€¾á€¯ စစ်ဆေးá€á€¼á€„်း</translation>
diff --git a/chromium/components/strings/components_strings_ne.xtb b/chromium/components/strings/components_strings_ne.xtb
index 6ab6d377d9c..7afc8822c6d 100644
--- a/chromium/components/strings/components_strings_ne.xtb
+++ b/chromium/components/strings/components_strings_ne.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">विवरणहरू हेरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="1030706264415084469"><ph name="URL" /> तपाईंको डिभाइसमा सà¥à¤¥à¤¾à¤¯à¥€ रूपमा ठà¥à¤²à¥‹ परिमाणको डेटा भणà¥à¤¡à¤¾à¤°à¤£ गरà¥à¤¨ चाहनà¥à¤›</translation>
<translation id="1032854598605920125">घडीको दिशामा घà¥à¤®à¤¾à¤‰à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
+<translation id="1033329911862281889">इनà¥à¤•à¥‹à¤—à¥à¤¨à¤¿à¤Ÿà¥‹ मोडले तपाईंलाई अनलाइन दà¥à¤¨à¤¿à¤¯à¤¾à¤à¤®à¤¾ अदृशà¥à¤¯ बनाउà¤à¤¦à¥ˆà¤¨:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />तपाईंले कà¥à¤¨à¥ˆ साइट खोलà¥à¤¦à¤¾ सो साइटले पà¥à¤°à¤¯à¥‹à¤— गरà¥à¤¨à¥‡ साइट तथा सेवाहरूले थाहा पाउà¤à¤›à¤¨à¥<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />रोजगारदाता वा विदà¥à¤¯à¤¾à¤²à¤¯à¤²à¥‡ बà¥à¤°à¤¾à¤‰à¤œà¤° पà¥à¤°à¤¯à¥‹à¤— गरी गरिà¤à¤•à¥‹ कà¥à¤°à¤¿à¤¯à¤¾à¤•à¤²à¤¾à¤ªà¤¸à¤®à¥à¤¬à¤¨à¥à¤§à¥€ विवरण हेरà¥à¤¨ सकà¥à¤›à¤¨à¥<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />इनà¥à¤Ÿà¤°à¤¨à¥‡à¤Ÿ सेवा पà¥à¤°à¤¦à¤¾à¤¯à¤•à¤¹à¤°à¥‚ले वेब टà¥à¤°à¤¾à¤«à¤¿à¤•à¤•à¥‹ निरीकà¥à¤·à¤£ गरà¥à¤¨ सकà¥à¤›à¤¨à¥<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">निसà¥à¤•à¥ƒà¤¯ पारà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="1036982837258183574">पूरà¥à¤£ सà¥à¤•à¥à¤°à¤¿à¤¨à¤¬à¤¾à¤Ÿ बाहिर निसà¥à¤•à¤¨à¤•à¤¾ लागि <ph name="ACCELERATOR" /> लाई थिचà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="1038106730571050514">सà¥à¤à¤¾à¤µà¤¹à¤°à¥‚ देखाइयोसà¥</translation>
<translation id="1038842779957582377">अजà¥à¤žà¤¾à¤¤ नाम</translation>
<translation id="1041998700806130099">कारà¥à¤¯ पानासमà¥à¤¬à¤¨à¥à¤§à¥€ सनà¥à¤¦à¥‡à¤¶</translation>
<translation id="1048785276086539861">तपाईंले à¤à¤¨à¥‹à¤Ÿà¥‡à¤¸à¤¨à¤¹à¤°à¥‚ समà¥à¤ªà¤¾à¤¦à¤¨ गरà¥à¤¦à¤¾ सà¥à¤•à¥à¤°à¤¿à¤¨à¤®à¤¾ यो कागजातको à¤à¤‰à¤Ÿà¤¾ मातà¥à¤° पृषà¥à¤  देखिने छ</translation>
-<translation id="1049743911850919806">इनà¥à¤•à¥‹à¤—à¥à¤¨à¤¿à¤Ÿà¥‹</translation>
<translation id="1050038467049342496">अनà¥à¤¯ à¤à¤ªà¤¹à¤°à¥‚ बनà¥à¤¦ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="1055184225775184556">&amp;पूरà¥à¤µà¤¸à¥à¤¥à¤¿à¤¤à¤¿à¤®à¤¾ फरà¥à¤•à¤¾à¤‰à¤¨à¥à¤¹à¥‹à¤¸à¥ थपà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="1056898198331236512">चेतावनी</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">नीति कà¥à¤¯à¤¾à¤¸ ठिक छ</translation>
<translation id="1130564665089811311">'पृषà¥à¤  अनà¥à¤µà¤¾à¤¦ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥' नामक बटन, Google अनà¥à¤µà¤¾à¤¦à¤• पà¥à¤°à¤¯à¥‹à¤— गरी यो पृषà¥à¤  अनà¥à¤µà¤¾à¤¦ गरà¥à¤¨ Enter थिचà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="1131264053432022307">तपाईंले पà¥à¤°à¤¤à¤¿à¤²à¤¿à¤ªà¤¿ गरà¥à¤¨à¥à¤­à¤à¤•à¥‹ छवि</translation>
+<translation id="1142846828089312304">इनà¥à¤•à¥‹à¤—à¥à¤¨à¤¿à¤Ÿà¥‹ मोडमा तेसà¥à¤°à¥‹ पकà¥à¤·à¥€à¤¯ कà¥à¤•à¥€ बà¥à¤²à¤• गरियोसà¥</translation>
<translation id="1150979032973867961">यो सरà¥à¤­à¤° हो भनेर पà¥à¤°à¤®à¤¾à¤£à¤¿à¤¤ गरà¥à¤¨ सकेन <ph name="DOMAIN" />; यसको सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤°à¤²à¤¾à¤ˆ तपाईंको कमà¥à¤ªà¥à¤¯à¥à¤Ÿà¤°à¤•à¥‹ अपरेटिङ सिसà¥à¤Ÿà¤®à¤²à¥‡ विशà¥à¤µà¤¾à¤¸ गरेन। यो à¤à¤• गलत कनà¥à¤«à¤¿à¤—à¥à¤°à¥‡à¤¸à¤¨ वा तपाईंको जडान अवरोध गरà¥à¤¨ खोजà¥à¤¨à¥‡ आकà¥à¤°à¤®à¤£à¤•à¤¾à¤°à¥€à¤•à¥‹ हà¥à¤¨à¤¸à¤•à¥à¤›à¥¤</translation>
<translation id="1151972924205500581">पासवरà¥à¤¡ आवशà¥à¤¯à¤• छ</translation>
<translation id="1156303062776767266">तपाईं सà¥à¤¥à¤¾à¤¨à¥€à¤¯ वा साà¤à¤¾ फाइल हेरà¥à¤¦à¥ˆ हà¥à¤¨à¥à¤¹à¥à¤¨à¥à¤›</translation>
@@ -64,7 +70,6 @@
<translation id="1178581264944972037">पज गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="1181037720776840403">हटाउनà¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="1186201132766001848">पासवरà¥à¤¡à¤¹à¤°à¥‚को जाà¤à¤š गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
-<translation id="1195210374336998651">à¤à¤ªà¤•à¤¾ सेटिङमा जानà¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="1195558154361252544">तपाईंले अनà¥à¤®à¤¤à¤¿ दिà¤à¤•à¤¾ साइटबाहेक अनà¥à¤¯ सबै साइटका सूचनाहरूलाई सà¥à¤µà¤¤à¤ƒ रोक लगाइà¤à¤•à¥‹ छ</translation>
<translation id="1197088940767939838">सà¥à¤¨à¥à¤¤à¤²à¤¾ रङà¥à¤—</translation>
<translation id="1201402288615127009">अरà¥à¤•à¥‹</translation>
@@ -111,7 +116,7 @@
<translation id="1307966114820526988">चलà¥à¤¤à¥€à¤¬à¤¾à¤Ÿ हटाइà¤à¤•à¤¾ सà¥à¤µà¤¿à¤§à¤¾à¤¹à¤°à¥‚</translation>
<translation id="1308113895091915999">अफर उपलबà¥à¤§ छ</translation>
<translation id="1312803275555673949">यो कà¥à¤°à¤¾ सही छ भनी पà¥à¤·à¥à¤Ÿà¤¿ गरà¥à¤¨à¥‡ के पà¥à¤°à¤®à¤¾à¤£ छ?</translation>
-<translation id="131405271941274527"><ph name="URL" /> तपाईंले NFC यनà¥à¤¤à¥à¤°à¤¹à¤°à¥‚मा टà¥à¤¯à¤¾à¤ª गरà¥à¤¦à¤¾ जानकारी पठाउन तथा पà¥à¤°à¤¾à¤ªà¥à¤¤ गरà¥à¤¨ चाहनà¥à¤›</translation>
+<translation id="1314311879718644478">अगà¥à¤®à¥‡à¤¨à¥à¤Ÿà¥‡à¤¡ रियालिटीसमà¥à¤¬à¤¨à¥à¤§à¥€ सामगà¥à¤°à¥€ हेरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="1314509827145471431">दायाठबाइनà¥à¤¡</translation>
<translation id="1318023360584041678">टà¥à¤¯à¤¾à¤¬ समूहमा सेभ गरिà¤à¤•à¥‹ छ</translation>
<translation id="1319245136674974084">यो à¤à¤ªà¤•à¤¾ हकमा फेरि नसोधियोसà¥</translation>
@@ -161,6 +166,7 @@
<translation id="142858679511221695">कà¥à¤²à¤¾à¤‰à¤¡à¤•à¤¾ पà¥à¤°à¤¯à¥‹à¤—करà¥à¤¤à¤¾</translation>
<translation id="1428729058023778569">यो साइटमा HTTPS नचलà¥à¤¨à¥‡ भà¤à¤•à¤¾à¤²à¥‡ तपाईंलाई यो चेतावनी देखाइà¤à¤•à¥‹ हो। <ph name="BEGIN_LEARN_MORE_LINK" />थप जानà¥à¤¨à¥à¤¹à¥‹à¤¸à¥<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">पà¥à¤°à¤¿à¤¨à¥à¤Ÿ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
+<translation id="1432187715652018471">यो पेजले सरà¥à¤­à¤¿à¤¸ हà¥à¤¯à¤¾à¤¨à¥à¤¡à¥à¤²à¤° इनà¥à¤¸à¥à¤Ÿà¤² गरà¥à¤¨à¥‡ अनà¥à¤®à¤¤à¤¿ मागà¥à¤¦à¥ˆ छ।</translation>
<translation id="1432581352905426595">खोज इनà¥à¤œà¤¿à¤¨à¤¹à¤°à¥‚को वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¨ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="1436185428532214179">तपाईंको डिभाइसमा भà¤à¤•à¤¾ फाइल तथा फोलà¥à¤¡à¤°à¤¹à¤°à¥‚ समà¥à¤ªà¤¾à¤¦à¤¨ गरà¥à¤¨à¥‡ अनà¥à¤®à¤¤à¤¿ मागà¥à¤¨ सकà¥à¤›</translation>
<translation id="1442386063175183758">दायाठगेट फोलà¥à¤¡</translation>
@@ -181,6 +187,12 @@
<translation id="1483493594462132177">पठाउनà¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="1484290072879560759">ढà¥à¤µà¤¾à¤¨à¥€à¤•à¥‹ ठेगाना छनौट गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="1492194039220927094">नीतिहरू लागू गरà¥à¤¨à¥‡ कारà¥à¤¯:</translation>
+<translation id="149293076951187737">तपाईंले Chrome का सबै इनà¥à¤•à¥‹à¤—à¥à¤¨à¤¿à¤Ÿà¥‹ टà¥à¤¯à¤¾à¤¬à¤¹à¤°à¥‚ बनà¥à¤¦ गरà¥à¤¨à¥à¤­à¤¯à¥‹ भने तपाईंले ती टà¥à¤¯à¤¾à¤¬à¤®à¤¾ गरेका निमà¥à¤¨ कà¥à¤°à¤¿à¤¯à¤¾à¤•à¤²à¤¾à¤ª यो डिभाइसबाट मेटाइनà¥à¤›:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />बà¥à¤°à¤¾à¤‰à¤œà¤° पà¥à¤°à¤¯à¥‹à¤— गरी गरिà¤à¤•à¥‹ कà¥à¤°à¤¿à¤¯à¤¾à¤•à¤²à¤¾à¤ª<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />पहिला खोजेका कà¥à¤°à¤¾à¤¹à¤°à¥‚<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />फाराममा भरिà¤à¤•à¥‹ जानकारी<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">टà¥à¤¯à¤¾à¤¬à¤®à¤¾ फरà¥à¤•à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="1501859676467574491">आफà¥à¤¨à¥‹ Google खाताका कारà¥à¤¡à¤¹à¤°à¥‚ देखाउनà¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="1507202001669085618">&lt;p&gt;तपाईं अनलाइन हà¥à¤¨à¥ पूरà¥à¤µ साइन इन गरà¥à¤¨ परà¥à¤¨à¥‡à¤®à¤¾ Wi-Fi पोरà¥à¤Ÿà¤² पà¥à¤°à¤¯à¥‹à¤— गरà¥à¤¨à¥à¤­à¤à¤•à¥‹ खणà¥à¤¡à¤®à¤¾ तपाईंले यो तà¥à¤°à¥à¤Ÿà¤¿ देखà¥à¤¹à¥à¤¨à¥‡ छ।&lt;/p&gt;
@@ -208,6 +220,8 @@
<translation id="1559572115229829303">&lt;p&gt;<ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> सà¤à¤— निजी जडान सà¥à¤¥à¤¾à¤ªà¤¨à¤¾ गरà¥à¤¨ सकिà¤à¤¦à¥ˆà¤¨ किनकि तपाईà¤à¤•à¥‹ यनà¥à¤¤à¥à¤°à¤•à¥‹ मिति र समय (<ph name="DATE_AND_TIME" />) सही छैननà¥à¥¤&lt;/p&gt;
&lt;p&gt;कृपया मिति र समय मिलाउन &lt;strong&gt;सेटिङ&lt;/strong&gt; à¤à¤ªà¤•à¥‹ &lt;strong&gt;सामानà¥à¤¯&lt;/strong&gt; खणà¥à¤¡à¤®à¤¾ गई मिलाउनà¥à¤¹à¥‹à¤¸à¥à¥¤&lt;/p&gt;</translation>
+<translation id="1559839503761818503">तपाईंका à¤à¤¡à¥à¤®à¤¿à¤¨à¤²à¥‡ तपाईंको डिभाइस <ph name="DATE" />, <ph name="TIME" /> बजे रिसà¥à¤Ÿà¤¾à¤°à¥à¤Ÿ गरà¥à¤¨à¥‡ छनà¥</translation>
+<translation id="156703335097561114">ठेगाना, इनà¥à¤Ÿà¤°à¤«à¥‡à¤¸à¤•à¥‹ कनà¥à¤«à¤¿à¤—à¥à¤°à¥‡à¤¸à¤¨ र कनेकà¥à¤¸à¤¨à¤•à¥‹ गà¥à¤£à¤¸à¥à¤¤à¤°à¤²à¤—ायतका नेटवरà¥à¤•à¤¿à¤™à¤¸à¤®à¥à¤¬à¤¨à¥à¤§à¥€ जानकारी</translation>
<translation id="1567040042588613346">यो नीतिले सोचेअनà¥à¤¸à¤¾à¤° काम गरिरहेको छ तर à¤à¤‰à¤Ÿà¥ˆ मान अनà¥à¤¯à¤¤à¥à¤° तय गरिà¤à¤•à¤¾ कारण यस नीतिअनà¥à¤¸à¤¾à¤° उकà¥à¤¤ मानको साटो अरà¥à¤•à¥‹ मान लागू गरिà¤à¤•à¥‹ छ।</translation>
<translation id="1569487616857761740">मà¥à¤¯à¤¾à¤¦ सकिने मिति पà¥à¤°à¤µà¤¿à¤·à¥à¤Ÿà¤¿ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@
<translation id="1583429793053364125">यो वेबपृषà¥à¤  पà¥à¤°à¤¦à¤°à¥à¤¶à¤¨ गरà¥à¤¦à¤¾ कà¥à¤¨à¥ˆ तà¥à¤°à¥à¤Ÿà¥€ भयो।</translation>
<translation id="1586541204584340881">तपाईंले सà¥à¤¥à¤¾à¤ªà¤¨à¤¾ गरà¥à¤¨à¥à¤­à¤à¤•à¤¾ à¤à¤•à¥à¤¸à¥à¤Ÿà¥‡à¤¨à¥à¤¸à¤¨à¤¹à¤°à¥‚</translation>
<translation id="1588438908519853928">सामानà¥à¤¯</translation>
+<translation id="1589050138437146318">ARCore इनà¥à¤¸à¥à¤Ÿà¤² गरà¥à¤¨à¥‡ हो?</translation>
<translation id="1592005682883173041">सà¥à¤¥à¤¾à¤¨à¥€à¤¯ डेटा पहà¥à¤à¤š</translation>
<translation id="1594030484168838125">छनौट गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="160851722280695521">Chrome मा Dino Run गेम खेलà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
@@ -283,6 +298,7 @@
उकà¥à¤¤ हेडरको ढाà¤à¤šà¤¾ सही नभà¤à¤•à¤¾à¤²à¥‡ यसले बà¥à¤°à¤¾à¤‰à¤œà¤°à¤²à¤¾à¤ˆ
<ph name="SITE" /> का सनà¥à¤¦à¤°à¥à¤­à¤®à¤¾ तपाईंले गरà¥à¤¨à¥à¤­à¤à¤•à¥‹ अनà¥à¤°à¥‹à¤§ पूरा गरà¥à¤¨ दिà¤à¤¦à¥ˆà¤¨à¥¤ साइटका सञà¥à¤šà¤¾à¤²à¤•à¤¹à¤°à¥‚ कà¥à¤¨à¥ˆ साइटको सà¥à¤°à¤•à¥à¤·à¤¾ र
अनà¥à¤¯ विशेषता कनà¥à¤«à¤¿à¤—र गरà¥à¤¨à¥‡ पà¥à¤°à¤¯à¥‹à¤œà¤¨à¤•à¤¾ लागि मूल नीतिहरू पà¥à¤°à¤¯à¥‹à¤— गरà¥à¤¨ सकà¥à¤›à¤¨à¥à¥¤</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Chromium मा उपलबà¥à¤§ इनà¥à¤•à¥‹à¤—à¥à¤¨à¤¿à¤Ÿà¥‹ मोडका बारेमा थप जानà¥à¤¨à¥à¤¹à¥‹à¤¸à¥<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">तपाईंका खà¥à¤²à¤¾ टà¥à¤¯à¤¾à¤¬à¤¹à¤°à¥‚ यहाठदेखा परà¥à¤›à¤¨à¥</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -410,6 +426,7 @@
<translation id="22081806969704220">टà¥à¤°à¥‡ ३</translation>
<translation id="2212735316055980242">नीति फेला परेन</translation>
<translation id="2213606439339815911">पà¥à¤°à¤µà¤¿à¤·à¥à¤Ÿà¤¿à¤¹à¤°à¥‚ लà¥à¤¯à¤¾à¤‰à¤à¤¦à¥ˆ...</translation>
+<translation id="2213612003795704869">पेज पà¥à¤°à¤¿à¤¨à¥à¤Ÿ गरिà¤à¤•à¥‹ छ</translation>
<translation id="2215727959747642672">फाइल समà¥à¤ªà¤¾à¤¦à¤¨ गरà¥à¤¦à¥ˆ</translation>
<translation id="2218879909401188352">हाल <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> मा रहेका आकà¥à¤°à¤®à¤£à¤•à¤¾à¤°à¥€à¤¹à¤°à¥‚ले तपाईंको यनà¥à¤¤à¥à¤°à¤²à¤¾à¤ˆ नोकà¥à¤¸à¤¾à¤¨à¥€ पà¥à¤±à¥à¤¯à¤¾à¤‰à¤¨à¥‡, तपाईंको मोबाइल बिलमा नदेखिने शà¥à¤²à¥à¤• थपà¥à¤¨à¥‡ वा तपाईंको वà¥à¤¯à¤•à¥à¤¤à¤¿à¤—त जानकारी चोरà¥à¤¨à¥‡ जसà¥à¤¤à¤¾ खतरनाक à¤à¤ªà¤¹à¤°à¥‚ इनà¥à¤¸à¥à¤Ÿà¤² गरà¥à¤¨ सकà¥à¤›à¤¨à¥à¥¤ <ph name="BEGIN_LEARN_MORE_LINK" />थप जानà¥à¤¨à¥à¤¹à¥‹à¤¸à¥<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">इनà¥à¤Ÿà¤°à¤¨à¥‡à¤Ÿ छैन</translation>
@@ -419,6 +436,7 @@
<translation id="2248949050832152960">WebAuthn पà¥à¤°à¤¯à¥‹à¤— गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="2250931979407627383">बायाठकिनारमा सà¥à¤Ÿà¤¿à¤š</translation>
<translation id="225207911366869382">यस नीतिको लागि मूलà¥à¤¯ बेमनà¥à¤œà¥à¤°à¥€ गरिà¤à¤•à¥‹ छ।</translation>
+<translation id="2256115617011615191">अब फेरि सà¥à¤°à¥ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="2258928405015593961">मà¥à¤¯à¤¾à¤¦ सकिने मितिमा भविषà¥à¤¯à¤•à¥‹ मिति पà¥à¤°à¤µà¤¿à¤·à¥à¤Ÿà¤¿ गरी फेरि पà¥à¤°à¤¯à¤¾à¤¸ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="225943865679747347">तà¥à¤°à¥à¤Ÿà¤¿ कोड: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">HTTP तà¥à¤°à¥à¤Ÿà¤¿</translation>
@@ -446,6 +464,7 @@
<translation id="2337852623177822836">तपाईंको पà¥à¤°à¤¶à¤¾à¤¸à¤•à¤²à¥‡ नियनà¥à¤¤à¥à¤°à¤£ गरेको सेटिङ</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> जोडा बनाउन चाहनà¥à¤›</translation>
<translation id="2346319942568447007">तपाईंले पà¥à¤°à¤¤à¤¿à¤²à¤¿à¤ªà¤¿ गरà¥à¤¨à¥à¤­à¤à¤•à¥‹ छवि</translation>
+<translation id="2350796302381711542"><ph name="HANDLER_HOSTNAME" /> लाई <ph name="REPLACED_HANDLER_TITLE" /> को सटà¥à¤Ÿà¤¾à¤®à¤¾ सबै <ph name="PROTOCOL" /> लिङà¥à¤•à¤¹à¤°à¥‚ खोलà¥à¤¨à¥‡ अनà¥à¤®à¤¤à¤¿ दिनà¥à¤¹à¥‹à¤¸à¥ ?</translation>
<translation id="2354001756790975382">अनà¥à¤¯ बà¥à¤•à¤®à¤¾à¤°à¥à¤•à¤¹à¤°à¥‚</translation>
<translation id="2354430244986887761">Google सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ बà¥à¤°à¤¾à¤‰à¤œà¤¿à¤™à¤²à¥‡ हालै <ph name="SITE" /> मा <ph name="BEGIN_LINK" />हानिकारक à¤à¤ªà¤¹à¤°à¥‚ भेटà¥à¤Ÿà¤¾à¤¯à¥‹<ph name="END_LINK" />।</translation>
<translation id="2355395290879513365">आकà¥à¤°à¤®à¤£à¤•à¤¾à¤°à¥€à¤¹à¤°à¥‚ले यस साइटमा तपाईà¤à¤²à¥‡ हेरिरहनà¥à¤­à¤à¤•à¤¾ फोटो हेरà¥à¤¨ र तिनीहरूलाई परिमारà¥à¤œà¤¨ गरी तपाईà¤à¤²à¤¾à¤ˆ धोका दिन सकà¥à¤›à¤¨à¥à¥¤</translation>
@@ -471,6 +490,7 @@
<translation id="2413528052993050574">यो सरà¥à¤­à¤°à¤²à¥‡ यो <ph name="DOMAIN" /> को भनि पà¥à¤°à¤®à¤¾à¤£à¤¿à¤¤ गरà¥à¤¨ सकेन; यसको सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤°à¤²à¤¾à¤ˆ रदà¥à¤¦ गरिà¤à¤•à¥‹ हà¥à¤¨ सकà¥à¤›à¥¤ यो कà¥à¤¨à¥ˆ à¤à¤‰à¤Ÿà¤¾ मिसकनà¥à¤«à¤¿à¤—रेसन वा कà¥à¤¨à¥ˆ आकà¥à¤°à¤®à¤£à¤•à¤¾à¤°à¥€à¤²à¥‡ तपाईंको जडानमा गरेको हसà¥à¤¤à¤•à¥à¤·à¥‡à¤ªà¤•à¥‹ कारणले गरà¥à¤¦à¤¾ भà¤à¤•à¥‹ हà¥à¤¨ सकà¥à¤›à¥¤</translation>
<translation id="2414886740292270097">अà¤à¤§à¥à¤¯à¤¾à¤°à¥‹</translation>
<translation id="2430968933669123598">Google खाता वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¨ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥, आफà¥à¤¨à¥‹ Google खातामा गई तपाईंको जानकारी, गोपनीयता र सà¥à¤°à¤•à¥à¤·à¤¾à¤•à¥‹ वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¨ गरà¥à¤¨ Enter थिचà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
+<translation id="2436186046335138073"><ph name="HANDLER_HOSTNAME" /> लाई सबै <ph name="PROTOCOL" /> लिङà¥à¤•à¤¹à¤°à¥‚ खोलà¥à¤¨à¥‡ अनà¥à¤®à¤¤à¤¿ दिने?</translation>
<translation id="2438874542388153331">दायाà¤à¤¤à¤¿à¤° चार पà¥à¤µà¤¾à¤²</translation>
<translation id="2450021089947420533">Journeys</translation>
<translation id="2463739503403862330">पूरà¥à¤£ जानकारी भरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
@@ -478,6 +498,7 @@
<translation id="2465655957518002998">डेलिभरीको विधि छनौट गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="2465688316154986572">सà¥à¤Ÿà¤¿à¤š</translation>
<translation id="2465914000209955735">आफूले Chrome मा डाउनलोड गरेका फाइल वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¨ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
+<translation id="2466004615675155314">वेबबाट पà¥à¤°à¤¾à¤ªà¥à¤¤ जानकारी देखाउनà¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />नेटवरà¥à¤• समà¥à¤¬à¤¨à¥à¤§à¥€ निदान चलाà¤à¤° हेरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">१ देखि N समà¥à¤®à¤•à¥‹ कà¥à¤°à¤®</translation>
<translation id="2470767536994572628">तपाईंले à¤à¤¨à¥‹à¤Ÿà¥‡à¤¸à¤¨à¤¹à¤°à¥‚ समà¥à¤ªà¤¾à¤¦à¤¨ गरà¥à¤¦à¤¾ सà¥à¤•à¥à¤°à¤¿à¤¨à¤®à¤¾ यो कागजातको à¤à¤‰à¤Ÿà¤¾ मातà¥à¤° पृषà¥à¤  देखिने छ। साथै, यो कागजात सà¥à¤°à¥à¤®à¤¾ जतातिर फरà¥à¤•à¥‡à¤•à¥‹ थियो तà¥à¤¯à¤¤à¥ˆà¤¤à¤¿à¤° घà¥à¤®à¤¾à¤‡à¤¨à¥‡ छ</translation>
@@ -498,6 +519,7 @@
<translation id="2523886232349826891">यो डिभाइसमा भने यस कारà¥à¤¡à¤²à¤¾à¤ˆ अà¤à¥ˆ पनि सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ गरिनà¥à¤›</translation>
<translation id="2524461107774643265">थप जानकारी थपà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="2529899080962247600">यो फिलà¥à¤¡à¤®à¤¾ <ph name="MAX_ITEMS_LIMIT" /> भनà¥à¤¦à¤¾ बढी पà¥à¤°à¤µà¤¿à¤·à¥à¤Ÿà¤¿ हà¥à¤¨à¥ हà¥à¤à¤¦à¥ˆà¤¨à¥¤ थप सबै पà¥à¤°à¤µà¤¿à¤·à¥à¤Ÿà¤¿ बेवासà¥à¤¤à¤¾ गरिने छनà¥à¥¤</translation>
+<translation id="2535585790302968248">तपाईं गोपà¥à¤¯ रूपमा बà¥à¤°à¤¾à¤‰à¤œ गरà¥à¤¨ चाहनà¥à¤¹à¥à¤¨à¥à¤› भने नयाठइनà¥à¤•à¥‹à¤—à¥à¤¨à¤¿à¤Ÿà¥‹ टà¥à¤¯à¤¾à¤¬ खोलà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{र थप १}other{र थप #}}</translation>
<translation id="2536110899380797252">ठेगाना थपà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="2539524384386349900">पतà¥à¤¤à¤¾ लगाउनà¥à¤¹à¥‹à¤¸à¥</translation>
@@ -523,7 +545,14 @@
<translation id="2597378329261239068">यो कागजात पासवरà¥à¤¡ सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ छ। कृपया पासवरà¥à¤¡ पà¥à¤°à¤µà¤¿à¤·à¥à¤Ÿà¤¿ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥à¥¤</translation>
<translation id="2609632851001447353">विचरणहरू</translation>
<translation id="2610561535971892504">कà¥à¤²à¤¿à¤• टॠकपी</translation>
+<translation id="2617988307566202237">Chrome ले निमà¥à¤¨ जानकारी <ph name="BEGIN_EMPHASIS" />सेभ गरà¥à¤¨à¥‡ छैन<ph name="END_EMPHASIS" />:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />तपाईंको बà¥à¤°à¤¾à¤‰à¤œà¤¿à¤™ इतिहास
+ <ph name="LIST_ITEM" />कà¥à¤•à¥€ तथा साइट डेटा
+ <ph name="LIST_ITEM" />फारामहरूमा भरिà¤à¤•à¥‹ जानकारी
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (Envelope)</translation>
+<translation id="2623663032199728144">तपाईंका सà¥à¤•à¥à¤°à¤¿à¤¨à¤¹à¤°à¥‚का बारेमा जानकारी पà¥à¤°à¤¯à¥‹à¤— गरà¥à¤¨à¥‡ अनà¥à¤®à¤¤à¤¿ मागà¥à¤¨ सकà¥à¤›</translation>
<translation id="2625385379895617796">तपाईंको घडी धेरै छिटो छ</translation>
<translation id="262745152991669301">USB डिभाइसमा कनेकà¥à¤Ÿ गरà¥à¤¨à¥‡ अनà¥à¤®à¤¤à¤¿ मागà¥à¤¨ सकà¥à¤›</translation>
<translation id="2629325967560697240">Chrome को सबैभनà¥à¤¦à¤¾ उचà¥à¤š सà¥à¤¤à¤°à¤•à¥‹ सà¥à¤°à¤•à¥à¤·à¤¾ सà¥à¤µà¤¿à¤§à¤¾ पà¥à¤°à¤¯à¥‹à¤— गरà¥à¤¨ <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />परिषà¥à¤•à¥ƒà¤¤ सà¥à¤°à¤•à¥à¤·à¤¾<ph name="END_ENHANCED_PROTECTION_LINK" /> अन गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
@@ -557,6 +586,7 @@
<translation id="2709516037105925701">सà¥à¤µà¤¤:भरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="2713444072780614174">सेतो</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />, Chrome का सेटिङमा गई आफà¥à¤¨à¤¾ भà¥à¤•à¥à¤¤à¤¾à¤¨à¥€ तथा कà¥à¤°à¥‡à¤¡à¤¿à¤Ÿ कारà¥à¤¡à¤¸à¤®à¥à¤¬à¤¨à¥à¤§à¥€ जानकारी वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¿à¤¤ गरà¥à¤¨ Tab थिचà¥à¤¨à¥à¤¹à¥‹à¤¸à¥ अनि Enter थिचà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
+<translation id="271663710482723385">तपाईं फà¥à¤² सà¥à¤•à¥à¤°à¤¿à¤¨à¤¬à¤¾à¤Ÿ बाहिरिन चाहनà¥à¤¹à¥à¤¨à¥à¤› भने |<ph name="ACCELERATOR1" />| र |<ph name="ACCELERATOR2" />| की à¤à¤•à¥ˆ पटक थिचà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="2721148159707890343">अनà¥à¤°à¥‹à¤§ सफल भयो</translation>
<translation id="2723669454293168317">Chrome का सेटिङमा गई सà¥à¤°à¤•à¥à¤·à¤¿à¤¤à¤ªà¤¨à¤¾à¤•à¥‹ जाà¤à¤š गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="2726001110728089263">छेउको टà¥à¤°à¥‡</translation>
@@ -587,6 +617,7 @@
<translation id="2850739647070081192">Invite (Envelope)</translation>
<translation id="2856444702002559011">आकà¥à¤°à¤®à¤£à¤•à¤¾à¤°à¥€à¤¹à¤°à¥‚ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> बाट तपाईंको जानकारी (उदाहरणका लागि, पासवरà¥à¤¡, सनà¥à¤¦à¥‡à¤¶ वा कà¥à¤°à¥‡à¤¡à¤¿à¤Ÿ कारà¥à¤¡à¤¹à¤°à¥‚) चोरà¥à¤¨à¥‡ पà¥à¤°à¤¯à¤¾à¤¸ गरिरहेका हà¥à¤¨à¤¸à¤•à¥à¤›à¤¨à¥à¥¤ <ph name="BEGIN_LEARN_MORE_LINK" />थप जानà¥à¤¨à¥à¤¹à¥‹à¤¸à¥<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">यो साइटले हसà¥à¤¤à¤•à¥à¤·à¥‡à¤ªà¤•à¤¾à¤°à¥€ वा भà¥à¤°à¤¾à¤®à¤• विजà¥à¤žà¤¾à¤ªà¤¨à¤¹à¤°à¥‚ देखाउà¤à¤›à¥¤</translation>
+<translation id="286512204874376891">भरà¥à¤šà¥à¤…ल कारà¥à¤¡à¤²à¥‡ तपाईंलाई ठगीबाट जोगाउनका निमà¥à¤¤à¤¿ तपाईंको कारà¥à¤¡à¤•à¥‹ वासà¥à¤¤à¤µà¤¿à¤• जानकारी लà¥à¤•à¤¾à¤‰à¤à¤›à¥¤ <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">मैतà¥à¤°à¥€à¤ªà¥‚रà¥à¤£</translation>
<translation id="2876489322757410363">कà¥à¤¨à¥ˆ बाहà¥à¤¯ à¤à¤ªà¤®à¤¾à¤°à¥à¤«à¤¤ भà¥à¤•à¥à¤¤à¤¾à¤¨à¥€ गरà¥à¤¨ इनà¥à¤•à¥‹à¤—à¥à¤¨à¤¿à¤Ÿà¥‹ मोडबाट बाहिरिà¤à¤¦à¥ˆ हà¥à¤¨à¥à¤¹à¥à¤¨à¥à¤›à¥¤ जारी राखà¥à¤¨à¥‡ हो?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />, तपाईं Chrome का सेटिङमा गई Safe Browsing का सेटिङ तथा सà¥à¤°à¤•à¥à¤·à¤¾à¤¸à¤®à¥à¤¬à¤¨à¥à¤§à¥€ अनà¥à¤¯ सेटिङ मिलाउन चाहनà¥à¤¹à¥à¤¨à¥à¤› भने Tab थिचà¥à¤¨à¥à¤¹à¥‹à¤¸à¥ अनि Enter थिचà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
@@ -611,6 +642,7 @@
<translation id="2930577230479659665">हरेक पà¥à¤°à¤¤à¤¿à¤ªà¤›à¤¿ छाà¤à¤Ÿà¤•à¤¾à¤à¤Ÿ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="2932085390869194046">पासवरà¥à¤¡ सिफारिस गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥...</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019"><ph name="PROTOCOL" /> लिंकहरू खोलà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="2941952326391522266">यो सरà¥à¤­à¤°à¤²à¥‡ यो <ph name="DOMAIN" /> हो भनेर पà¥à¤°à¤®à¤¾à¤£à¤¿à¤¤ गरà¥à¤¨ सकेन; यसको सà¥à¤°à¤•à¥à¤·à¤¾ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° <ph name="DOMAIN2" /> बाट हो। यो à¤à¤• गलत कनà¥à¤«à¤¿à¤—à¥à¤°à¥‡à¤¸à¤¨ वा तपाईंको जडान अवरोध गरà¥à¤¨ खोजà¥à¤¨à¥‡ आकà¥à¤°à¤®à¤£à¤•à¤¾à¤°à¥€à¤•à¥‹ हà¥à¤¨à¤¸à¤•à¥à¤›à¥¤</translation>
<translation id="2943895734390379394">अपलोड गरिà¤à¤•à¥‹ समय:</translation>
<translation id="2948083400971632585">तपाइà¤à¤²à¥‡ सेटिङ पृषà¥à¤ à¤¹à¤°à¥‚बाट जडानको लागि विनà¥à¤¯à¤¾à¤¸ गरिà¤à¤•à¥‹ कà¥à¤¨à¥ˆ पनि पà¥à¤°à¥‹à¤•à¥à¤¸à¥€à¤¹à¤°à¥‚ असकà¥à¤·à¤® गरà¥à¤¨ सकà¥à¤¨à¥à¤¹à¥à¤¨à¥à¤›à¥¤</translation>
@@ -643,6 +675,7 @@
<translation id="3037605927509011580">हरे, सà¥à¤¨à¥à¤¯à¤¾à¤ª!</translation>
<translation id="3041612393474885105">पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° जानकारी</translation>
<translation id="3044034790304486808">आफà¥à¤¨à¥‹ खोज सà¥à¤šà¤¾à¤°à¥ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
+<translation id="305162504811187366">Chrome को रिमोट डेसà¥à¤•à¤Ÿà¤ªà¤¸à¤®à¥à¤¬à¤¨à¥à¤§à¥€ इतिहास (जसà¥à¤¤à¥ˆ, टाइमसà¥à¤Ÿà¥à¤¯à¤¾à¤®à¥à¤ª, होसà¥à¤Ÿ र कà¥à¤²à¤¾à¤‡à¤¨à¥à¤Ÿ सेसन ID)</translation>
<translation id="3060227939791841287">C9 (Envelope)</translation>
<translation id="3061707000357573562">पà¥à¤¯à¤¾à¤šà¤¸à¤®à¥à¤¬à¤¨à¥à¤§à¥€ सेवा</translation>
<translation id="306573536155379004">गेम सà¥à¤°à¥ भà¤à¤•à¥‹ छ।</translation>
@@ -680,6 +713,7 @@
<translation id="3197136577151645743">तपाईं यो डिभाइस चलाउà¤à¤¦à¥ˆ हà¥à¤¨à¥à¤¹à¥à¤¨à¥à¤› कि हà¥à¤¨à¥à¤¹à¥à¤¨à¥à¤¨ भनà¥à¤¨à¥‡ कà¥à¤°à¤¾à¤•à¥‹ जानकारी मागà¥à¤¨ सकà¥à¤›</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />, Chrome का सेटिङमा गई के कसà¥à¤¤à¤¾ जानकारी सिंक गरà¥à¤¨à¥‡ भनà¥à¤¨à¥‡ कà¥à¤°à¤¾ वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¨ गरà¥à¤¨ Tab थिचà¥à¤¨à¥à¤¹à¥‹à¤¸à¥ अनि Enter थिचà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="320323717674993345">भà¥à¤•à¥à¤¤à¤¾à¤¨à¥€ रदà¥à¤¦ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
+<translation id="3203366800380907218">वेबबाट पà¥à¤°à¤¾à¤ªà¥à¤¤</translation>
<translation id="3207960819495026254">बà¥à¤•à¤®à¤¾à¤°à¥à¤• लगाइयो</translation>
<translation id="3209034400446768650">यो पृषà¥à¤ à¤²à¥‡ शà¥à¤²à¥à¤• लिन सकà¥à¤›</translation>
<translation id="3212581601480735796">तपाईंले <ph name="HOSTNAME" /> मा गरà¥à¤¨à¥‡ कà¥à¤°à¤¿à¤¯à¤¾à¤•à¤²à¤¾à¤ªà¤®à¤¾à¤¥à¤¿ निगरानी गरिà¤à¤¦à¥ˆ छ</translation>
@@ -696,10 +730,12 @@
<translation id="3234666976984236645">सधैं यस साइटमा महतà¥à¤µà¤ªà¥‚रà¥à¤£ सामगà¥à¤°à¥€ पतà¥à¤¤à¤¾ लगाउनà¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />, तपाईं आफà¥à¤¨à¥‹ बà¥à¤°à¤¾à¤‰à¤œà¤°à¤•à¥‹ सà¥à¤µà¤°à¥‚प कसà¥à¤Ÿà¤®à¤¾à¤‡à¤œ गरà¥à¤¨ चाहनà¥à¤¹à¥à¤¨à¥à¤› भने Tab थिचà¥à¤¨à¥à¤¹à¥‹à¤¸à¥ अनि Enter थिचà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="3240791268468473923">कà¥à¤°à¤¿à¤¡à¥‡à¤¨à¥à¤¸à¤¿à¤¯à¤² सिटसà¤à¤— नमिलà¥à¤¨à¥‡ सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ भà¥à¤•à¥à¤¤à¤¾à¤¨à¥€ कà¥à¤°à¤¿à¤¡à¥‡à¤¨à¥à¤¸à¤¿à¤¯à¤² खोलियो</translation>
+<translation id="324180406144491771">“<ph name="HOST_NAME" />†का लिंकहरू बà¥à¤²à¤• गरिà¤à¤•à¤¾ छनà¥</translation>
<translation id="3249845759089040423">सानदार</translation>
<translation id="3252266817569339921">फà¥à¤°à¥‡à¤¨à¥à¤š</translation>
<translation id="3257954757204451555">यो जानकारी कसले उपलबà¥à¤§ गराà¤à¤•à¥‹ हो?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />, Google पातà¥à¤°à¥‹ पà¥à¤°à¤¯à¥‹à¤— गरी तà¥à¤°à¥à¤¨à¥à¤¤à¥ˆ नयाठकारà¥à¤¯à¤•à¥à¤°à¤® बनाउन Tab थिचà¥à¤¨à¥à¤¹à¥‹à¤¸à¥ अनि Enter थिचà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
+<translation id="3261488570342242926">भरà¥à¤šà¥à¤…ल कारà¥à¤¡à¤•à¤¾ बारेमा जानà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="3264837738038045344">Chrome का सेटिङ मिलाउनà¥à¤¹à¥‹à¤¸à¥ नामक बटन, Chrome मा आफूले तय गरेका सेटिङ हेरà¥à¤¨ Enter थिचà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="3266793032086590337">मान (बेमेल)</translation>
<translation id="3268451620468152448">टà¥à¤¯à¤¾à¤¬à¤¹à¤°à¥‚ खोलà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
@@ -713,6 +749,7 @@
<translation id="3288238092761586174"><ph name="URL" /> ले तपाईंको भà¥à¤•à¥à¤¤à¤¾à¤¨à¥€ पà¥à¤·à¥à¤Ÿà¤¿ गरà¥à¤¨à¤•à¤¾ निमà¥à¤¤à¤¿ अतिरिकà¥à¤¤ चरणहरू पूरा गरà¥à¤¨à¥ परà¥à¤¨à¥‡ हà¥à¤¨ सकà¥à¤›</translation>
<translation id="3293642807462928945"><ph name="POLICY_NAME" /> नीतिका बारेमा थप जानà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="3295444047715739395">Chrome बà¥à¤°à¤¾à¤‰à¤œà¤°à¤•à¤¾ सेटिङमा गई आफà¥à¤¨à¤¾ पासवरà¥à¤¡à¤¹à¤°à¥‚ हेरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥ तथा वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¨ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
+<translation id="3303795387212510132">à¤à¤ªà¤²à¤¾à¤ˆ <ph name="PROTOCOL_SCHEME" /> लिंकहरू खोलà¥à¤¨à¥‡ अनà¥à¤®à¤¤à¤¿ दिनà¥à¤¹à¥‹à¤¸à¥?</translation>
<translation id="3303855915957856445">खोजका परिणाम फेला परेननà¥</translation>
<translation id="3304073249511302126">बà¥à¤²à¥à¤Ÿà¥à¤¥ सà¥à¤•à¥à¤¯à¤¾à¤¨ गरà¥à¤¨à¥‡ सà¥à¤µà¤¿à¤§à¤¾</translation>
<translation id="3308006649705061278">सङà¥à¤—ठनातà¥à¤®à¤• à¤à¤•à¤¾à¤‡ (OU)</translation>
@@ -726,12 +763,6 @@
<translation id="3345782426586609320">आà¤à¤–ा</translation>
<translation id="3355823806454867987">पà¥à¤°à¥‹à¤•à¥à¤¸à¥€ सेटिङहरू परिवरà¥à¤¤à¤¨ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥...</translation>
<translation id="3360103848165129075">भà¥à¤•à¥à¤¤à¤¾à¤¨à¥€ हà¥à¤¯à¤¾à¤¨à¥à¤¡à¥à¤²à¤°à¤¸à¤®à¥à¤¬à¤¨à¥à¤§à¥€ पाना</translation>
-<translation id="3361596688432910856">Chrome ले निमà¥à¤¨ जानकारी <ph name="BEGIN_EMPHASIS" />सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ गरà¥à¤¨à¥‡à¤›à¥ˆà¤¨<ph name="END_EMPHASIS" />:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />तपाईंको बà¥à¤°à¤¾à¤‰à¤œà¤¿à¤™ इतिहास
- <ph name="LIST_ITEM" />कà¥à¤•à¥€à¤¹à¤°à¥‚ र साइटको डेटा
- <ph name="LIST_ITEM" />फारमहरूमा पà¥à¤°à¤µà¤¿à¤·à¥à¤Ÿ गरिà¤à¤•à¥‹ जानकारी
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">यो नीति पà¥à¤°à¤šà¤²à¤¨à¤¬à¤¾à¤Ÿ हटाइà¤à¤•à¥‹ <ph name="OLD_POLICY" /> नीतिबाट सà¥à¤µà¤¤à¤ƒ पà¥à¤°à¤¤à¤¿à¤²à¤¿à¤ªà¤¿ गरियो। तपाईंले उकà¥à¤¤ नीतिको साटो यो नीतिको पà¥à¤°à¤¯à¥‹à¤— गरà¥à¤¨à¥ परà¥à¤›à¥¤</translation>
<translation id="3364869320075768271"><ph name="URL" /> भरà¥à¤šà¥à¤…ल रियालिटी चलà¥à¤¨à¥‡ तपाईंको यनà¥à¤¤à¥à¤° र तà¥à¤¯à¤¸à¤®à¤¾ भà¤à¤•à¥‹ डेटा पà¥à¤°à¤¯à¥‹à¤— गरà¥à¤¨ चाहनà¥à¤›</translation>
<translation id="3366477098757335611">कारà¥à¤¡à¤¹à¤°à¥‚ हेरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
@@ -814,7 +845,6 @@
<translation id="3587738293690942763">मधà¥à¤¯ भाग</translation>
<translation id="3592413004129370115">Italian (Envelope)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{तपाईं जà¥à¤¨à¤¸à¥à¤•à¥ˆ बेला आफà¥à¤¨à¥‹ समूह रिसेट गरà¥à¤¨ सकà¥à¤¨à¥à¤¹à¥à¤¨à¥à¤›à¥¤ नयाठसमूहमा सामेल हà¥à¤¨ à¤à¤¨à¥à¤¡à¥ˆ à¤à¤• दिन लागà¥à¤›à¥¤}=1{तपाईं जà¥à¤¨à¤¸à¥à¤•à¥ˆ बेला आफà¥à¤¨à¥‹ समूह रिसेट गरà¥à¤¨ सकà¥à¤¨à¥à¤¹à¥à¤¨à¥à¤›à¥¤ नयाठसमूहमा सामेल हà¥à¤¨ à¤à¤¨à¥à¤¡à¥ˆ à¤à¤• दिन लागà¥à¤›à¥¤}other{तपाईं जà¥à¤¨à¤¸à¥à¤•à¥ˆ बेला आफà¥à¤¨à¥‹ समूह रिसेट गरà¥à¤¨ सकà¥à¤¨à¥à¤¹à¥à¤¨à¥à¤›à¥¤ नयाठसमूहमा सामेल हà¥à¤¨ à¤à¤¨à¥à¤¡à¥ˆ {NUM_DAYS} दिन लागà¥à¤›à¥¤}}</translation>
-<translation id="3596012367874587041">à¤à¤ªà¤•à¤¾ सेटिङ</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">तपाईंका पà¥à¤°à¤¶à¤¾à¤¸à¤•à¤²à¥‡ रोक लगाउनà¥à¤­à¤à¤•à¥‹ à¤à¤ª</translation>
<translation id="3608932978122581043">अभिमà¥à¤–ीकरण फिड गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
@@ -857,7 +887,8 @@
<translation id="370972442370243704">Journeys अन गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="3711895659073496551">निलमà¥à¤¬à¤¨</translation>
<translation id="3712624925041724820">इजाजतपतà¥à¤° निकास</translation>
-<translation id="3714780639079136834">मोबाइल डेटा वा Wi-Fi लाई सकà¥à¤°à¤¿à¤¯ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
+<translation id="3714633008798122362">वेब पातà¥à¤°à¥‹</translation>
+<translation id="3714780639079136834">मोबाइल डेटा वा Wi-Fi लाई अन गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="3715597595485130451">Wi-Fi मा कनेकà¥à¤Ÿ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />पà¥à¤°à¥‹à¤•à¥à¤¸à¥€, फायरवाल र DNS को कनà¥à¤«à¤¿à¤—रेसनलाई जाà¤à¤š गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥<ph name="END_LINK" /></translation>
<translation id="372429172604983730">यो तà¥à¤°à¥à¤Ÿà¤¿ उतà¥à¤ªà¤¨à¥à¤¨ गराउन सकà¥à¤¨à¥‡ à¤à¤ªà¤¹à¤°à¥‚मा à¤à¤¨à¥à¤Ÿà¤¿à¤­à¤¾à¤‡à¤°à¤¸, फायरवाल र वेब-फिलà¥à¤Ÿà¤° वा पà¥à¤°à¥‹à¤•à¥à¤¸à¥€ सफà¥à¤Ÿà¤µà¥‡à¤¯à¤° परà¥à¤¦à¤›à¤¨à¥à¥¤</translation>
@@ -877,7 +908,7 @@
<translation id="3765588406864124894">मेलबकà¥à¤¸ ९</translation>
<translation id="3767485424735936570">à¤à¤¡à¥à¤®à¤¿à¤¨à¤²à¥‡ तोकà¥à¤¨à¥à¤­à¤à¤•à¥‹ नीतिअनà¥à¤¸à¤¾à¤° यो सामगà¥à¤°à¥€ <ph name="VM_NAME" /> मा कपी र पेसà¥à¤Ÿ गरà¥à¤¨ सिफारिस गरिà¤à¤¦à¥ˆà¤¨</translation>
<translation id="377451872037045164"><ph name="CREATE_GOOGLE_KEEP_NOTE_FOCUSED_FRIENDLY_MATCH_TEXT" />, Google Keep पà¥à¤°à¤¯à¥‹à¤— गरी तà¥à¤°à¥à¤¨à¥à¤¤à¥ˆ नयाठटिपोट बनाउन Tab थिचà¥à¤¨à¥à¤¹à¥‹à¤¸à¥ अनि Enter थिचà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
-<translation id="3778403066972421603">तपाईं यो कारà¥à¤¡à¤²à¤¾à¤ˆ आफà¥à¤¨à¥‹ Google खाता र यस यनà¥à¤¤à¥à¤°à¤®à¤¾ सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ गरà¥à¤¨ चाहनà¥à¤¹à¥à¤¨à¥à¤›?</translation>
+<translation id="3778403066972421603">तपाईं यो कारà¥à¤¡à¤²à¤¾à¤ˆ आफà¥à¤¨à¥‹ Google खाता र यस डिभाइसमा सेभ गरà¥à¤¨ चाहनà¥à¤¹à¥à¤¨à¥à¤›?</translation>
<translation id="3780694243617746492">आउटपà¥à¤Ÿ बिन</translation>
<translation id="3781428340399460090">गाढा गà¥à¤²à¤¾à¤¬à¥€</translation>
<translation id="3783418713923659662">मासà¥à¤Ÿà¤°à¤•à¤¾à¤°à¥à¤¡</translation>
@@ -918,6 +949,7 @@
<translation id="3906954721959377182">टà¥à¤¯à¤¾à¤¬à¥à¤²à¥‡à¤Ÿ</translation>
<translation id="3909477809443608991"><ph name="URL" /> संरकà¥à¤·à¤¿à¤¤ सामगà¥à¤°à¥€ पà¥à¤²à¥‡ गरà¥à¤¨ चाहनà¥à¤›à¥¤ Google ले तपाईंको डिभाइसको पहिचान पà¥à¤·à¥à¤Ÿà¤¿ गरà¥à¤¨à¥‡ छ र यो साइटले उकà¥à¤¤ जानकारीमाथि पहà¥à¤à¤š राखà¥à¤¨ सकà¥à¤¨à¥‡ छ।</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">असà¥à¤µà¥€à¤•à¤¾à¤° गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="3939773374150895049">CVC को सटà¥à¤Ÿà¤¾à¤®à¤¾ WebAuthn पà¥à¤°à¤¯à¥‹à¤— गरà¥à¤¨à¥‡ हो?</translation>
<translation id="3946209740501886391">यस साइटमा सधैं सोधà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="3947595700203588284">MIDI डिभाइसहरूमा कनेकà¥à¤Ÿ हà¥à¤¨à¥‡ अनà¥à¤®à¤¤à¤¿ मागà¥à¤¨ सकà¥à¤›</translation>
@@ -939,6 +971,7 @@
<translation id="3990250421422698716">जग अफसेट</translation>
<translation id="3996311196211510766">यो साइट <ph name="ORIGIN" /> ले यसलाई गरिने सबै अनà¥à¤°à¥‹à¤§à¤¹à¤°à¥‚मा मूल नीति
लागू गरà¥à¤¨ अनà¥à¤°à¥‹à¤§ गरेको छ। तर अहिले यो नीति लागू गरà¥à¤¨ सकिà¤à¤¦à¥ˆà¤¨à¥¤</translation>
+<translation id="4009243425692662128">तपाईंले पà¥à¤°à¤¿à¤¨à¥à¤Ÿ गरà¥à¤¨à¥‡ पेजका सामगà¥à¤°à¥€ विशà¥à¤²à¥‡à¤·à¤£ गरà¥à¤¨à¥‡ पà¥à¤°à¤¯à¥‹à¤œà¤¨à¤•à¤¾ लागि Google कà¥à¤²à¤¾à¤‰à¤¡ वा तेसà¥à¤°à¥‹ पकà¥à¤·à¤•à¤¹à¤¾à¤ पठाइनà¥à¤›à¥¤ उदाहरणका लागि, उकà¥à¤¤ पाठमा संवेदनशील डेटा छ कि छैन भनी जाà¤à¤š गरिन सकà¥à¤›à¥¤</translation>
<translation id="4010758435855888356">भणà¥à¤¡à¤¾à¤°à¤£ पà¥à¤°à¤¯à¥‹à¤— गरà¥à¤¨à¥‡ अनà¥à¤®à¤¤à¤¿ दिने हो?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{{COUNT} पृषà¥à¤  भà¤à¤•à¥‹ PDF कागजात}other{{COUNT} पृषà¥à¤ à¤¹à¤°à¥‚ भà¤à¤•à¥‹ PDF कागजात}}</translation>
<translation id="4023431997072828269">असà¥à¤°à¤•à¥à¤·à¤¿à¤¤ इनà¥à¤Ÿà¤°à¤¨à¥‡à¤Ÿ पà¥à¤°à¤¯à¥‹à¤— गरेर यो फारम पेस गरिà¤à¤¦à¥ˆ गरेका हà¥à¤¨à¤¾à¤²à¥‡ अरूले तपाईंको जानकारी देखà¥à¤¨ सकà¥à¤¨à¥‡ छनà¥à¥¤</translation>
@@ -1032,6 +1065,7 @@
<translation id="4250680216510889253">होइन</translation>
<translation id="4253168017788158739">नोट</translation>
<translation id="425582637250725228">तपाईà¤à¤²à¥‡ गरà¥à¤¨à¥à¤­à¤à¤•à¤¾ परिवरà¥à¤¤à¤¨à¤¹à¤°à¥‚ सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ नहà¥à¤¨ सकà¥à¤›à¤¨à¥à¥¤</translation>
+<translation id="425869179292622354">भरà¥à¤šà¥à¤…ल कारà¥à¤¡ लिंक गरेर यो कारà¥à¤¡ थप सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ बनाउने हो?</translation>
<translation id="4258748452823770588">खराब हसà¥à¤¤à¤¾à¤•à¥à¤·à¤°</translation>
<translation id="4261046003697461417">सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ कागजातहरूमा à¤à¤¨à¥‹à¤Ÿà¥‡à¤¸à¤¨ गरà¥à¤¨ मिलà¥à¤¦à¥ˆà¤¨</translation>
<translation id="4265872034478892965">तपाईंका पà¥à¤°à¤¶à¤¾à¤¸à¤•à¤²à¥‡ अनà¥à¤®à¤¤à¤¿ दिनà¥à¤­à¤à¤•à¥‹</translation>
@@ -1094,6 +1128,7 @@
<translation id="4434045419905280838">पपअप तथा रिडिरेकà¥à¤Ÿà¤¹à¤°à¥‚</translation>
<translation id="4435702339979719576">Postcard)</translation>
<translation id="443673843213245140">पà¥à¤°à¥‹à¤•à¥à¤¸à¥€à¤•à¥‹ पà¥à¤°à¤¯à¥‹à¤— असकà¥à¤·à¤® गरिà¤à¤•à¥‹ छ तर à¤à¤• सà¥à¤¸à¥à¤ªà¤·à¥à¤Ÿ पà¥à¤°à¥‹à¤•à¥à¤¸à¥€ विनà¥à¤¯à¤¾à¤¸ तोकिà¤à¤•à¥‹ छ।</translation>
+<translation id="4441832193888514600">कà¥à¤²à¤¾à¤‰à¤¡à¤•à¤¾ पà¥à¤°à¤¯à¥‹à¤—करà¥à¤¤à¤¾à¤²à¥‡ मातà¥à¤° नीति तय गरà¥à¤¨ मिलà¥à¤¨à¥‡ भà¤à¤•à¤¾à¤²à¥‡ वेवासà¥à¤¤à¤¾ गरिà¤à¤•à¥‹ छ।</translation>
<translation id="4450893287417543264">फेरि नदेखाउनà¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="4451135742916150903">HID डिभाइसमा कनेकà¥à¤Ÿ गरà¥à¤¨à¥‡ अनà¥à¤®à¤¤à¤¿ मागà¥à¤¨ सकà¥à¤›</translation>
<translation id="4452328064229197696">तपाईंले भरà¥à¤–रै पà¥à¤°à¤¯à¥‹à¤— गरà¥à¤¨à¥à¤­à¤à¤•à¥‹ पासवरà¥à¤¡ चोरी भà¤à¤•à¥‹ डेटाको सङà¥à¤—à¥à¤°à¤¹à¤®à¤¾ भेटिà¤à¤•à¥‹ छ। Google पासवरà¥à¤¡ मà¥à¤¯à¤¾à¤¨à¥‡à¤œà¤°à¤²à¥‡ तपाईंका खाता सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ राखà¥à¤¨à¥‡ पà¥à¤°à¤¯à¥‹à¤œà¤¨à¤•à¤¾ लागि तपाईंले सेभ गरेका पासवरà¥à¤¡à¤¹à¤°à¥‚ सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ छनॠकि छैननॠजाà¤à¤šà¥à¤¨ सिफारिस गरà¥à¤›à¥¤</translation>
@@ -1149,6 +1184,7 @@
<translation id="4628948037717959914">तसà¥à¤¬à¤¿à¤°</translation>
<translation id="4631649115723685955">यो कारà¥à¤¡à¤®à¤¾à¤°à¥à¤«à¤¤ भà¥à¤•à¥à¤¤à¤¾à¤¨à¥€ गरà¥à¤¦à¤¾ कà¥à¤¯à¤¾à¤¸à¤¬à¥à¤¯à¤¾à¤• पाइनà¥à¤›</translation>
<translation id="4636930964841734540">जानकारी</translation>
+<translation id="4638670630777875591">Chromium मा उपलबà¥à¤§ इनà¥à¤•à¥‹à¤—à¥à¤¨à¤¿à¤Ÿà¥‹ मोड</translation>
<translation id="464342062220857295">खोजसमà¥à¤¬à¤¨à¥à¤§à¥€ सà¥à¤µà¤¿à¤§à¤¾à¤¹à¤°à¥‚</translation>
<translation id="4644670975240021822">विपरीत कà¥à¤°à¤® तर तलतिर फरà¥à¤•à¤¾à¤à¤°</translation>
<translation id="4646534391647090355">मलाई अहिले नै तà¥à¤¯à¤¹à¤¾à¤ लैजानà¥à¤¹à¥‹à¤¸à¥</translation>
@@ -1169,6 +1205,7 @@
<translation id="4708268264240856090">तपाईंको जडानमा अवरोध भयो</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Windows नेटवरà¥à¤• समà¥à¤¬à¤¨à¥à¤§à¥€ निदान चलाà¤à¤° हेरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426"><ph name="USERNAME" /> को पासवरà¥à¤¡</translation>
<translation id="4724144314178270921">तपाईंको कà¥à¤²à¤¿à¤ªà¤¬à¥‹à¤°à¥à¤¡à¤®à¤¾ भà¤à¤•à¤¾ पाठ तथा फोटोहरू हेरà¥à¤¨à¥‡ अनà¥à¤®à¤¤à¤¿ मागà¥à¤¨ सकà¥à¤›</translation>
<translation id="4726672564094551039">नीतिहरू पà¥à¤¨: लोड गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="4728558894243024398">पà¥à¤²à¥‡à¤Ÿà¤«à¤°à¥à¤®</translation>
@@ -1190,6 +1227,7 @@
<translation id="4757993714154412917">तपाईंले भरà¥à¤–रै कà¥à¤¨à¥ˆ असà¥à¤°à¤•à¥à¤·à¤¿à¤¤ साइटमा आफà¥à¤¨à¥‹ पासवरà¥à¤¡ हालà¥à¤¨à¥à¤­à¤à¤•à¥‹ छ। तपाईंका खाताहरूको सà¥à¤°à¤•à¥à¤·à¤¾à¤°à¥à¤¥ Chromium तपाईंलाई तपाईंका सेभ गरिà¤à¤•à¤¾ पासवरà¥à¤¡à¤¹à¤°à¥‚को जाà¤à¤š गरà¥à¤¨ सिफारिस गरà¥à¤›à¥¤</translation>
<translation id="4758311279753947758">समà¥à¤ªà¤°à¥à¤• बारे जानकारी थपà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="4761104368405085019">आफà¥à¤¨à¥‹ माइकà¥à¤°à¥‹à¤«à¥‹à¤¨ पà¥à¤°à¤¯à¥‹à¤— गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
+<translation id="4761869838909035636">Chrome को सà¥à¤°à¤•à¥à¤·à¤¾ जाà¤à¤š गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="4764776831041365478"><ph name="URL" /> को वेबपेज असà¥à¤¥à¤¾à¤¯à¥€ रूपमा बनà¥à¤¦ भà¤à¤•à¥‹ हà¥à¤¨ सकà¥à¤› वा तà¥à¤¯à¥‹ सà¥à¤¥à¤¾à¤¯à¥€ रूपमा à¤à¤‰à¤Ÿà¤¾ नयाठवेब ठेगानामा सरेको हà¥à¤¨ सकà¥à¤›à¥¤</translation>
<translation id="4766713847338118463">फेदमा दà¥à¤ˆ सà¥à¤Ÿà¤¿à¤š</translation>
<translation id="4771973620359291008">à¤à¤‰à¤Ÿà¤¾ अजà¥à¤žà¤¾à¤¤ तà¥à¤°à¥à¤Ÿà¤¿ देखापरà¥à¤¯à¥‹ ।</translation>
@@ -1210,12 +1248,6 @@
<translation id="4819347708020428563">à¤à¤¨à¥‹à¤Ÿà¥‡à¤¸à¤¨à¤¹à¤°à¥‚ डिफलà¥à¤Ÿ भà¥à¤¯à¥‚मा समà¥à¤ªà¤¾à¤¦à¤¨ गरà¥à¤¨à¥‡ हो?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />, Google Sheets पà¥à¤°à¤¯à¥‹à¤— गरी तà¥à¤°à¥à¤¨à¥à¤¤à¥ˆ नयाठपाना बनाउन Tab थिचà¥à¤¨à¥à¤¹à¥‹à¤¸à¥ अनि Enter थिचà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="4825507807291741242">शकà¥à¤¤à¤¿à¤¶à¤¾à¤²à¥€</translation>
-<translation id="4827402517081186284">इनà¥à¤•à¥‹à¤—à¥à¤¨à¤¿à¤Ÿà¥‹ मोडले तपाईंलाई अनलाइन दà¥à¤¨à¤¿à¤¯à¤¾à¤à¤®à¤¾ अदृशà¥à¤¯ बनाउà¤à¤¦à¥ˆà¤¨:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />तपाईंले कà¥à¤¨à¥ˆ साइट खोलà¥à¤¦à¤¾ सो साइटले थाहा पाउà¤à¤›<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />रोजगारदाता वा विदà¥à¤¯à¤¾à¤²à¤¯à¤²à¥‡ बà¥à¤°à¤¾à¤‰à¤œà¤° पà¥à¤°à¤¯à¥‹à¤— गरी गरिà¤à¤•à¥‹ कà¥à¤°à¤¿à¤¯à¤¾à¤•à¤²à¤¾à¤ªà¤¸à¤®à¥à¤¬à¤¨à¥à¤§à¥€ विवरण हेरà¥à¤¨ सकà¥à¤›à¤¨à¥<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />इनà¥à¤Ÿà¤°à¤¨à¥‡à¤Ÿ सेवा पà¥à¤°à¤¦à¤¾à¤¯à¤•à¤¹à¤°à¥‚ले वेब टà¥à¤°à¤¾à¤«à¤¿à¤•à¤•à¥‹ निरीकà¥à¤·à¤£ गरà¥à¤¨ सकà¥à¤›à¤¨à¥<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">चेतावनी देखाउने सà¥à¤µà¤¿à¤§à¤¾ अन गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="4838327282952368871">सà¥à¤µà¤ªà¥à¤¨à¤¿à¤²</translation>
<translation id="4840250757394056958">Chrome को बà¥à¤°à¤¾à¤‰à¤œà¤¿à¤™Â à¤‡à¤¤à¤¿à¤¹à¤¾à¤¸ हेरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
@@ -1227,12 +1259,12 @@
<translation id="4854362297993841467">डेलिभरीको यो विधि उपलबà¥à¤§ छैन। फरक विधि चयन गरà¥à¤¨à¥‡ पà¥à¤°à¤¯à¤¾à¤¸ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥à¥¤</translation>
<translation id="4854853140771946034">Google Keep पà¥à¤°à¤¯à¥‹à¤— गरी तà¥à¤°à¥à¤¨à¥à¤¤à¥ˆ नयाठटिपोट बनाउनà¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="485902285759009870">कोड पà¥à¤·à¥à¤Ÿà¤¿ गरिà¤à¤¦à¥ˆ छ...</translation>
+<translation id="4866506163384898554">तपाईं करà¥à¤¸à¤° देखाउन चाहनà¥à¤¹à¥à¤¨à¥à¤› भने |<ph name="ACCELERATOR1" />| र |<ph name="ACCELERATOR2" />| की à¤à¤•à¥ˆ पटक थिचà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="4876188919622883022">सरलीकृत हेराइको सà¥à¤µà¤¿à¤§à¤¾</translation>
<translation id="4876305945144899064">कà¥à¤¨à¥ˆ पनि पà¥à¤°à¤¯à¥‹à¤—करà¥à¤¤à¤¾ नाम छैन</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{कà¥à¤¨à¥ˆ पनि होइन}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831"><ph name="TEXT" /> को खोज</translation>
<translation id="4879491255372875719">सà¥à¤µà¤šà¤¾à¤²à¤¿à¤¤ (डिफलà¥à¤Ÿ)</translation>
-<translation id="4879725228911483934">तपाईंको सà¥à¤•à¥à¤°à¤¿à¤¨à¤®à¤¾ विनà¥à¤¡à¥‹ राखà¥à¤¨à¥‡ र तà¥à¤¯à¤¹à¤¾à¤ भà¤à¤•à¤¾ विनà¥à¤¡à¥‹ खोलà¥à¤¨à¥‡</translation>
<translation id="4880827082731008257">खोज इतिहास</translation>
<translation id="4881695831933465202">खोलà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="4885256590493466218">चेकआउटका बेला <ph name="CARD_DETAIL" /> पà¥à¤°à¤¯à¥‹à¤— गरी भà¥à¤•à¥à¤¤à¤¾à¤¨à¥€ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
@@ -1241,6 +1273,7 @@
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">नवौठरोल</translation>
<translation id="4901778704868714008">सेभ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥...</translation>
+<translation id="4905659621780993806">तपाईंका à¤à¤¡à¥à¤®à¤¿à¤¨à¤²à¥‡ तपाईंको डिभाइस <ph name="DATE" /> का दिन <ph name="TIME" /> बजे रिसà¥à¤Ÿà¤¾à¤°à¥à¤Ÿ गरà¥à¤¨à¥‡ छनà¥à¥¤ तपाईंको डिभाइस रिसà¥à¤Ÿà¤¾à¤°à¥à¤Ÿ हà¥à¤¨à¥à¤…घि खोलिà¤à¤•à¤¾ सबै वसà¥à¤¤à¥ सेभ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥à¥¤</translation>
<translation id="4913987521957242411">सिरानको बायाà¤à¤ªà¤Ÿà¥à¤Ÿà¤¿ पà¥à¤µà¤¾à¤²</translation>
<translation id="4918221908152712722"><ph name="APP_NAME" /> सà¥à¤¥à¤¾à¤ªà¤¨à¤¾ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥ (डाउनलोड गरिराखà¥à¤¨à¥ परà¥à¤¦à¥ˆà¤¨)</translation>
<translation id="4923459931733593730">भà¥à¤•à¥à¤¤à¤¾à¤¨à¥€</translation>
@@ -1249,6 +1282,7 @@
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, खोजà¥à¤¨à¤•à¤¾ लागि Tab थिचà¥à¤¨à¥à¤¹à¥‹à¤¸à¥ अनि Enter थिचà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="4930153903256238152">धेरै कà¥à¤·à¤®à¤¤à¤¾ भà¤à¤•à¥‹</translation>
+<translation id="4940163644868678279">Chrome मा उपलबà¥à¤§ इनà¥à¤•à¥‹à¤—à¥à¤¨à¤¿à¤Ÿà¥‹ मोड</translation>
<translation id="4943872375798546930">कà¥à¤¨à¥ˆ नतिजा छैन</translation>
<translation id="4950898438188848926">टà¥à¤¯à¤¾à¤¬ बदलà¥à¤¨à¥‡ बटन, खà¥à¤²à¤¾ रहेको टà¥à¤¯à¤¾à¤¬à¤®à¤¾ जान Enter थिचà¥à¤¨à¥à¤¹à¥‹à¤¸à¥, <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="495170559598752135">कारà¥à¤¯à¤¹à¤°à¥‚</translation>
@@ -1258,6 +1292,7 @@
<translation id="4968522289500246572">यो à¤à¤ª मोबाइलमा चलाउने पà¥à¤°à¤¯à¥‹à¤œà¤¨à¤²à¥‡ बनाइà¤à¤•à¥‹ हो र यसको आकार सही तरिकाले परिवरà¥à¤¤à¤¨ नहà¥à¤¨ सकà¥à¤›à¥¤ यो à¤à¤ªà¤®à¤¾ समसà¥à¤¯à¤¾ देखिन सकà¥à¤› वा यो à¤à¤ª आफैठरिसà¥à¤Ÿà¤¾à¤°à¥à¤Ÿ हà¥à¤¨ सकà¥à¤›à¥¤</translation>
<translation id="4969341057194253438">रेकरà¥à¤¡à¤¿à¤™ मेटाउनà¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="4973922308112707173">सिरानमा दà¥à¤ˆ पà¥à¤µà¤¾à¤²</translation>
+<translation id="4976702386844183910">पछिलà¥à¤²à¥‹ पटक खोलिà¤à¤•à¥‹ मिति: <ph name="DATE" /></translation>
<translation id="4984088539114770594">माइकà¥à¤°à¥‹à¤«à¥‹à¤¨ पà¥à¤°à¤¯à¥‹à¤— गरà¥à¤¨à¥‡ हो?</translation>
<translation id="4984339528288761049">Prc5 (Envelope)</translation>
<translation id="4989163558385430922">सबै हेरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
@@ -1312,13 +1347,14 @@
<translation id="5123063207673082822">सपà¥à¤¤à¤¾à¤¹à¤¾à¤¨à¥à¤¤</translation>
<translation id="5125394840236832993">B-Plus</translation>
<translation id="5126510351761255129">आफà¥à¤¨à¥‹ कारà¥à¤¡ पà¥à¤·à¥à¤Ÿà¤¿ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
-<translation id="512670116361803001"><ph name="APP_NAME" /> को आकार सही तरिकाले परिवरà¥à¤¤à¤¨ नहà¥à¤¨ सकà¥à¤›à¥¤ à¤à¤ªà¤®à¤¾ कà¥à¤¨à¥ˆ समसà¥à¤¯à¤¾ नआओसॠभनà¥à¤¨à¤¾à¤•à¤¾ खातिर विनà¥à¤¡à¥‹à¤•à¥‹ पूरà¥à¤µà¤¨à¤¿à¤°à¥à¤§à¤¾à¤°à¤¿à¤¤ आकार पà¥à¤°à¤¯à¥‹à¤— गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥à¥¤</translation>
+<translation id="512670116361803001"><ph name="APP_NAME" /> को आकार सही तरिकाले परिवरà¥à¤¤à¤¨ नहà¥à¤¨ सकà¥à¤›à¥¤ à¤à¤ªà¤®à¤¾ कà¥à¤¨à¥ˆ समसà¥à¤¯à¤¾ नआओसॠभनà¥à¤¨à¤¾à¤•à¤¾ लागि विनà¥à¤¡à¥‹à¤•à¥‹ पूरà¥à¤µà¤¨à¤¿à¤°à¥à¤§à¤¾à¤°à¤¿à¤¤ आकार पà¥à¤°à¤¯à¥‹à¤— गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥à¥¤</translation>
<translation id="5135404736266831032">ठेगानाहरू वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¿à¤¤ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥...</translation>
<translation id="5136841603454277753">सही कोड हालà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="5138014172396933048">भरà¥à¤šà¥à¤…ल कारà¥à¤¡ हाल उपलबà¥à¤§ छैन। कृपया आफà¥à¤¨à¥‹ बैंकमा समà¥à¤ªà¤°à¥à¤• गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="5138227688689900538">कम देखाउनà¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="5145883236150621069">नीति पà¥à¤°à¤¤à¤¿à¤•à¥à¤°à¤¿à¤¯à¤¾à¤®à¤¾ तà¥à¤°à¥à¤Ÿà¤¿ कोड समावेश छ</translation>
<translation id="5146995429444047494"><ph name="ORIGIN" /> का सूचनाहरूलाई रोक लगाइà¤à¤•à¥‹ छ</translation>
+<translation id="514704532284964975"><ph name="URL" /> ले तपाईंले आफà¥à¤¨à¥‹ फोनमारà¥à¤«à¤¤ टà¥à¤¯à¤¾à¤ª गरà¥à¤¨à¥‡ NFC डिभाइसमा भà¤à¤•à¤¾ जानकारी हेरà¥à¤¨à¥‡ तथा परिवरà¥à¤¤à¤¨ गरà¥à¤¨à¥‡ अनà¥à¤®à¤¤à¤¿ मागà¥à¤¦à¥ˆ छ</translation>
<translation id="5148809049217731050">माथितिर फरà¥à¤•à¥‡à¤•à¥‹</translation>
<translation id="515292512908731282">C4 (Envelope)</translation>
<translation id="5158275234811857234">आवरण</translation>
@@ -1343,6 +1379,7 @@
<translation id="5215116848420601511">Google Pay को पà¥à¤°à¤¯à¥‹à¤— गरà¥à¤¨à¥‡Â à¤­à¥à¤•à¥à¤¤à¤¾à¤¨à¥€ विधि र ठेगानाहरू</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">टà¥à¤°à¥‡ १३</translation>
+<translation id="5216942107514965959">पछिलà¥à¤²à¥‹ पटक आज खोलिà¤à¤•à¥‹</translation>
<translation id="5222812217790122047">इमेल आवशà¥à¤¯à¤• छ</translation>
<translation id="5230733896359313003">ढà¥à¤µà¤¾à¤¨à¥€à¤•à¥‹ ठेगाना</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1363,7 +1400,6 @@
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">डकà¥à¤®à¥‡à¤¨à¥à¤Ÿà¤•à¤¾ विशेषताहरू</translation>
<translation id="528468243742722775">समापà¥à¤¤</translation>
-<translation id="5284909709419567258">नेटवरà¥à¤•à¤•à¤¾ ठेगानाहरू</translation>
<translation id="5285570108065881030">सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ गरिà¤à¤•à¤¾ सबै पासवरà¥à¤¡à¤¹à¤°à¥‚ देखाउनà¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="5287240709317226393">कà¥à¤•à¥€à¤¹à¤°à¥‚ देखाउनà¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="5287456746628258573">यो साइटले à¤à¤‰à¤Ÿà¤¾ अदà¥à¤¯à¤¾à¤µà¤§à¤¿à¤• नभà¤à¤•à¥‹ सà¥à¤°à¤•à¥à¤·à¤¾ कनà¥à¤«à¤¿à¤—à¥à¤°à¥‡à¤¸à¤¨à¤•à¥‹ पà¥à¤°à¤¯à¥‹à¤— गरà¥à¤›, जसले तपाईंको जानकारी (उदाहरणका लागि, पासवरà¥à¤¡ वा कà¥à¤°à¥‡à¤¡à¤¿à¤Ÿ कारà¥à¤¡ नमà¥à¤¬à¤°) यस साइटमा पठाइà¤à¤¦à¤¾ देखाउन सकà¥à¤›à¥¤</translation>
@@ -1443,10 +1479,11 @@
<translation id="5541086400771735334">मेलबकà¥à¤¸ ७</translation>
<translation id="5541546772353173584">इमेल थपà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="5545756402275714221">तपाईंका लागि सà¥à¤à¤¾à¤µ दिइà¤à¤•à¤¾ लेखहरू</translation>
-<translation id="5552137475244467770">Chrome ले तपाईंका पासवरà¥à¤¡à¤¹à¤°à¥‚ अनलाइनमा पà¥à¤°à¤•à¤¾à¤¶à¤¿à¤¤ सूचीमा परेका छनॠकि छैननॠभनी आवधिक रूपमा जाà¤à¤š गरà¥à¤›à¥¤ यसो गरà¥à¤¦à¤¾, Google लगायत कसैले पनि तपाईंका पासवरà¥à¤¡ र पà¥à¤°à¤¯à¥‹à¤—करà¥à¤¤à¤¾ नामहरू पढà¥à¤¨ नसकूनॠभनà¥à¤¨à¤¾à¤•à¤¾ खातिर तिनलाई इनà¥à¤•à¥à¤°à¤¿à¤ªà¥à¤Ÿ गरिनà¥à¤›à¥¤</translation>
+<translation id="5552137475244467770">Chrome ले तपाईंका पासवरà¥à¤¡à¤¹à¤°à¥‚ अनलाइनमा पà¥à¤°à¤•à¤¾à¤¶à¤¿à¤¤ सूचीमा परेका छनॠकि छैननॠभनी आवधिक रूपमा जाà¤à¤š गरà¥à¤›à¥¤ यसो गरà¥à¤¦à¤¾, Google लगायत कसैले पनि तपाईंका पासवरà¥à¤¡ र पà¥à¤°à¤¯à¥‹à¤—करà¥à¤¤à¤¾ नामहरू पढà¥à¤¨ नसकूनॠभनà¥à¤¨à¤¾à¤•à¤¾ लागि तिनलाई इनà¥à¤•à¥à¤°à¤¿à¤ªà¥à¤Ÿ गरिनà¥à¤›à¥¤</translation>
<translation id="5556459405103347317">पà¥à¤¨: लोड गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="5560088892362098740">मà¥à¤¯à¤¾à¤¦ सकिने मिति</translation>
<translation id="55635442646131152">कागजातको रूपरेखा</translation>
+<translation id="5565613213060953222">इनà¥à¤•à¥‹à¤—à¥à¤¨à¤¿à¤Ÿà¥‹ टà¥à¤¯à¤¾à¤¬ खोलà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="5565735124758917034">सकà¥à¤°à¤¿à¤¯</translation>
<translation id="5570825185877910964">खाता सेभ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="5571083550517324815">यो ठेगानाबाट पिकअप गरà¥à¤¨ सकिà¤à¤¦à¥ˆà¤¨à¥¤ कà¥à¤¨à¥ˆ अरà¥à¤•à¥‹ ठेगाना चयन गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥à¥¤</translation>
@@ -1529,6 +1566,7 @@
<translation id="5869522115854928033">बचत गरिà¤à¤•à¤¾ पासवरà¥à¤¡à¤¹à¤°à¥‚</translation>
<translation id="5873013647450402046">तपाईंको बैंकले यो कारबाही गरà¥à¤¨ खोजà¥à¤¨à¥‡ वà¥à¤¯à¤•à¥à¤¤à¤¿ तपाईं नै हो भनà¥à¤¨à¥‡ कà¥à¤°à¤¾ पà¥à¤·à¥à¤Ÿà¤¿ गरà¥à¤¨ चाहनà¥à¤›à¥¤</translation>
<translation id="5887400589839399685">कारà¥à¤¡ सेभ गरियो</translation>
+<translation id="5887687176710214216">पछिलà¥à¤²à¥‹ पटक हिजो खोलिà¤à¤•à¥‹</translation>
<translation id="5895138241574237353">पà¥à¤¨: शà¥à¤°à¥‚ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="5895187275912066135">मा पà¥à¤°à¤•à¤¾à¤¶à¤¿à¤¤</translation>
<translation id="5901630391730855834">पहेà¤à¤²à¥‹</translation>
@@ -1542,6 +1580,7 @@
<translation id="5921639886840618607">कारà¥à¤¡à¤²à¤¾à¤ˆ Google खातामा सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ गरà¥à¤¨à¥‡ हो?</translation>
<translation id="5922853866070715753">लगभग सकियो</translation>
<translation id="5932224571077948991">यो साइटले हसà¥à¤¤à¤•à¥à¤·à¥‡à¤ªà¤•à¤¾à¤°à¥€ वा भà¥à¤°à¤¾à¤®à¤• विजà¥à¤žà¤¾à¤ªà¤¨à¤¹à¤°à¥‚ देखाउà¤à¤›</translation>
+<translation id="5938153366081463283">भरà¥à¤šà¥à¤…ल कारà¥à¤¡ लिंक गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347"><ph name="SITE_NAME" /> खोलिà¤à¤¦à¥ˆâ€¦</translation>
<translation id="5951495562196540101">उपभोकà¥à¤¤à¤¾à¤•à¥‹ खातामारà¥à¤«à¤¤ दरà¥à¤¤à¤¾ गरà¥à¤¨ सकिà¤à¤¦à¥ˆà¤¨ (पà¥à¤¯à¤¾à¤•à¥‡à¤œà¤¸à¤¹à¤¿à¤¤à¤•à¥‹ इजाजतपतà¥à¤° उपलबà¥à¤§ छ)।</translation>
@@ -1606,6 +1645,7 @@
<translation id="6120179357481664955">आफà¥à¤¨à¥‹ UPI ID समà¥à¤à¤¨à¥‡ हो?</translation>
<translation id="6124432979022149706">Chrome Enterprise का कनेकà¥à¤Ÿà¤°à¤¹à¤°à¥‚</translation>
<translation id="6127379762771434464">वसà¥à¤¤à¥à¤²à¤¾à¤ˆ हटाइयो</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Chrome मा उपलबà¥à¤§ इनà¥à¤•à¥‹à¤—à¥à¤¨à¤¿à¤Ÿà¥‹ मोडका बारेमा थप जानà¥à¤¨à¥à¤¹à¥‹à¤¸à¥<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">तपाइà¤à¤²à¥‡ पà¥à¤°à¤¯à¥‹à¤— गरिेहेको कà¥à¤¨à¥ˆ पनि केबà¥à¤²à¤¹à¤°à¥‚ जाà¤à¤šà¥à¤¨à¥à¤¹à¥‹à¤¸à¥ र कà¥à¤¨à¥ˆ पनि राउटरहरू, मोडेमहरू, वा अनà¥à¤¯
नेटवरà¥à¤• यनà¥à¤¤à¥à¤°à¤¹à¤°à¥‚ रिबà¥à¤Ÿ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥à¥¤</translation>
<translation id="614940544461990577">यसो गरी हेरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥:</translation>
@@ -1618,7 +1658,6 @@
<translation id="6169916984152623906">तपाईं अब निजी रूपमा बà¥à¤°à¤¾à¤‰à¤œ गरà¥à¤¨ सकà¥à¤¨à¥à¤¹à¥à¤¨à¥à¤› र यो डिभाइसको पà¥à¤°à¤¯à¥‹à¤— गरà¥à¤¨à¥‡ अनà¥à¤¯ वà¥à¤¯à¤•à¥à¤¤à¤¿à¤¹à¤°à¥‚ले तपाईंको कà¥à¤°à¤¿à¤¯à¤¾à¤•à¤²à¤¾à¤ª देखà¥à¤¨à¥‡ छैननà¥à¥¤ यदà¥à¤¯à¤ªà¤¿, तपाईंका डाउनलोड र बà¥à¤•à¤®à¤¾à¤°à¥à¤•à¤¹à¤°à¥‚ सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ गरिनेछनà¥à¥¤</translation>
<translation id="6177128806592000436">यस साइटमा तपाईà¤à¤•à¥‹ जडान सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ छैन</translation>
<translation id="6180316780098470077">पà¥à¤¨: पà¥à¤°à¤¯à¤¾à¤¸ गरà¥à¤¨ पाइने अनà¥à¤¤à¤°à¤¾à¤²</translation>
-<translation id="619448280891863779">तपाईंको डिभाइसका सà¥à¤•à¥à¤°à¤¿à¤¨à¤¹à¤°à¥‚मा विनà¥à¤¡à¥‹ राखà¥à¤¨à¥‡ र तà¥à¤¯à¤¹à¤¾à¤ भà¤à¤•à¤¾ विनà¥à¤¡à¥‹ खोलà¥à¤¨à¥‡ अनà¥à¤®à¤¤à¤¿ मागà¥à¤¨ सकà¥à¤›</translation>
<translation id="6196640612572343990">तेसà¥à¤°à¥‹ पकà¥à¤·à¥€à¤¯ कà¥à¤•à¥€à¤¹à¤°à¥‚माथि रोक लगाउनà¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="6203231073485539293">तपाइà¤à¤•à¥‹ इनà¥à¤Ÿà¤°à¤¨à¥‡à¤Ÿ जडान जाà¤à¤šà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="6218753634732582820">Chromium बाट ठेगाना हटाउने हो?</translation>
@@ -1641,7 +1680,7 @@
<translation id="6272383483618007430">Google अपडेट</translation>
<translation id="6276112860590028508">तपाईंको पाठà¥à¤¯ सूचीका पृषà¥à¤ à¤¹à¤°à¥‚ यहाठदेखिनà¥à¤›à¤¨à¥</translation>
<translation id="627746635834430766">अरà¥à¤•à¥‹ पटक अठछिटो भà¥à¤•à¥à¤¤à¤¾à¤¨à¥€ गरà¥à¤¨ आफà¥à¤¨à¥‹ Google खातामा आफà¥à¤¨à¥‹ कारà¥à¤¡ र बिलिङ ठेगाना सेभ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥à¥¤</translation>
-<translation id="6279098320682980337">भरà¥à¤šà¥à¤…ल कारà¥à¤¡ नमà¥à¤¬à¤° भरिà¤à¤•à¥‹ छैन? तपाईं कारà¥à¤¡à¤•à¤¾ विवरणहरू कपी गरà¥à¤¨ चाहनà¥à¤¹à¥à¤¨à¥à¤› भने तिनमा कà¥à¤²à¤¿à¤• गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
+<translation id="6279183038361895380">तपाईंको करà¥à¤¸à¤° देखाउन |<ph name="ACCELERATOR" />| लाई थिचà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="6280223929691119688">यो ठेगानामा डेलिभर गरà¥à¤¨ सकिà¤à¤¦à¥ˆà¤¨à¥¤ कà¥à¤¨à¥ˆ अरà¥à¤•à¥‹ ठेगाना चयन गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥à¥¤</translation>
<translation id="6282194474023008486">हà¥à¤²à¤¾à¤• कोड</translation>
<translation id="6285507000506177184">Chrome मा डाउनलोडहरू वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¨ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥, तपाईं आफूले Chrome मा डाउनलोड गरेका फाइल वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¨ गरà¥à¤¨ चाहनà¥à¤¹à¥à¤¨à¥à¤› भने Enter थिचà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
@@ -1649,6 +1688,7 @@
<translation id="6290238015253830360">तपाईंका सà¥à¤à¤¾à¤µ गरिà¤à¤•à¤¾ लेखहरू यहाठदेखिनà¥à¤›à¤¨à¥</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{तपाईंको डिभाइस अब रिसà¥à¤Ÿà¤¾à¤°à¥à¤Ÿ हà¥à¤¨à¥‡ छ}=1{तपाईंको डिभाइस १ सेकेनà¥à¤¡à¤®à¤¾ रिसà¥à¤Ÿà¤¾à¤°à¥à¤Ÿ हà¥à¤¨à¥‡ छ}other{तपाईंको डिभाइस # सेकेनà¥à¤¡à¤®à¤¾ रिसà¥à¤Ÿà¤¾à¤°à¥à¤Ÿ हà¥à¤¨à¥‡ छ}}</translation>
<translation id="6302269476990306341">Chrome को Google सहायक रोकिà¤à¤¦à¥ˆ छ</translation>
<translation id="6305205051461490394"><ph name="URL" /> पहà¥à¤à¤š गरà¥à¤¨ सकिà¤à¤¦à¥ˆà¤¨à¥¤</translation>
<translation id="6312113039770857350">वेबपृषà¥à¤  उपलबà¥à¤§ छैन</translation>
@@ -1722,6 +1762,7 @@
<translation id="6529602333819889595">मेटाउने कारà¥à¤¯ &amp;पà¥à¤¨: गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="6545864417968258051">बà¥à¤²à¥à¤Ÿà¥à¤¥ सà¥à¤•à¥à¤¯à¤¾à¤¨ गरà¥à¤¦à¥ˆ</translation>
<translation id="6547208576736763147">बायाà¤à¤ªà¤Ÿà¥à¤Ÿà¤¿ दà¥à¤ˆ पà¥à¤µà¤¾à¤²</translation>
+<translation id="6554732001434021288">पछिलà¥à¤²à¥‹ पटक <ph name="NUM_DAYS" /> दिनअघि खोलिà¤à¤•à¥‹</translation>
<translation id="6556866813142980365">फेरि गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="6569060085658103619">तपाईं à¤à¤‰à¤Ÿà¤¾ विसà¥à¤¤à¤¾à¤° समà¥à¤¬à¤¨à¥à¤§à¥€ पृषà¥à¤  हेरà¥à¤¦à¥ˆ हà¥à¤¨à¥à¤¹à¥à¤¨à¥à¤›</translation>
<translation id="6573200754375280815">दायाà¤à¤ªà¤Ÿà¥à¤Ÿà¤¿ दà¥à¤ˆ पà¥à¤µà¤¾à¤²</translation>
@@ -1782,7 +1823,6 @@
<translation id="6757797048963528358">तपाईंको यनà¥à¤¤à¥à¤° शयन अवसà¥à¤¥à¤¾à¤®à¤¾ गयो।</translation>
<translation id="6767985426384634228">ठेगाना बदलà¥à¤¨à¥‡ हो?</translation>
<translation id="6768213884286397650">Hagaki (Postcard)</translation>
-<translation id="6774185088257932239">इनà¥à¤•à¥‹à¤—à¥à¤¨à¤¿à¤Ÿà¥‹ मोडका बारेमा <ph name="BEGIN_LINK" />थप जानà¥à¤¨à¥à¤¹à¥‹à¤¸à¥<ph name="END_LINK" /></translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">हलà¥à¤•à¤¾ निलो</translation>
<translation id="6786747875388722282">विसà¥à¤¤à¤¾à¤°à¤¹à¤°à¥‚</translation>
@@ -1866,7 +1906,6 @@
<translation id="706295145388601875">Chrome का सेटिङमा गई ठेगानाहरू थपà¥à¤¨à¥à¤¹à¥‹à¤¸à¥ तथा वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¨ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="7064851114919012435">समà¥à¤ªà¤°à¥à¤• बारे जानकारी</translation>
<translation id="7068733155164172741"><ph name="OTP_LENGTH" /> अङà¥à¤•à¤•à¥‹ कोड हालà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
-<translation id="7070090581017165256">यो साइटका बारेमा जानकारी</translation>
<translation id="70705239631109039">तपाईंको इनà¥à¤Ÿà¤°à¤¨à¥‡à¤Ÿ पूरà¥à¤£ रूपमा सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ छैन</translation>
<translation id="7075452647191940183">अनà¥à¤°à¥‹à¤§ गरिà¤à¤•à¥‹ सामगà¥à¤°à¥€ धेरै ठà¥à¤²à¥‹ छ</translation>
<translation id="7079718277001814089">यस साइटमा मालवेयर छ</translation>
@@ -1883,6 +1922,12 @@
<translation id="7111012039238467737">(मानà¥à¤¯)</translation>
<translation id="7118618213916969306">कà¥à¤²à¤¿à¤ªà¤¬à¥‹à¤°à¥à¤¡à¤•à¥‹ URL <ph name="SHORT_URL" /> खोजà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="7119414471315195487">अनà¥à¤¯ टà¥à¤¯à¤¾à¤¬ वा कारà¥à¤¯à¤•à¥à¤°à¤®à¤¹à¤°à¥‚ बनà¥à¤¦ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
+<translation id="7129355289156517987">तपाईंले Chromium का सबै इनà¥à¤•à¥‹à¤—à¥à¤¨à¤¿à¤Ÿà¥‹ टà¥à¤¯à¤¾à¤¬à¤¹à¤°à¥‚ बनà¥à¤¦ गरà¥à¤¨à¥à¤­à¤¯à¥‹ भने तपाईंले ती टà¥à¤¯à¤¾à¤¬à¤®à¤¾ गरेका निमà¥à¤¨ कà¥à¤°à¤¿à¤¯à¤¾à¤•à¤²à¤¾à¤ª यो डिभाइसबाट मेटाइनà¥à¤›:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />बà¥à¤°à¤¾à¤‰à¤œà¤° पà¥à¤°à¤¯à¥‹à¤— गरी गरिà¤à¤•à¥‹ कà¥à¤°à¤¿à¤¯à¤¾à¤•à¤²à¤¾à¤ª<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />पहिला खोजेका कà¥à¤°à¤¾à¤¹à¤°à¥‚<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />फाराममा भरिà¤à¤•à¥‹ जानकारी<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">यो ठेगानामा ढà¥à¤µà¤¾à¤¨à¥€ गरà¥à¤¨ सकिà¤à¤¦à¥ˆà¤¨à¥¤ कà¥à¤¨à¥ˆ अरà¥à¤•à¥‹ ठेगाना चयन गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥à¥¤</translation>
<translation id="7132939140423847331">तपाईंका à¤à¤¡à¥à¤®à¤¿à¤¨à¤²à¥‡ लगाà¤à¤•à¥‹ पà¥à¤°à¤¤à¤¿à¤¬à¤¨à¥à¤§à¤•à¤¾ कारण यो डेटा कपी गरà¥à¤¨ मिलà¥à¤¦à¥ˆà¤¨à¥¤</translation>
<translation id="7135130955892390533">सà¥à¤¥à¤¿à¤¤à¤¿ देखाउनà¥à¤¹à¥‹à¤¸à¥</translation>
@@ -1905,6 +1950,7 @@
<translation id="7192203810768312527"><ph name="SIZE" /> ठाउठखाली गरà¥à¤¦à¤›à¥¤ तपाईं अरà¥à¤•à¥‹à¤ªà¤Ÿà¤• आउà¤à¤¦à¤¾ केही साइटहरू अठढिलोगरी लोड हà¥à¤¨à¤¸à¤•à¥à¤›à¤¨à¥à¥¤</translation>
<translation id="719464814642662924">भिषा</translation>
<translation id="7201591969684833065">तपाईंका पà¥à¤°à¤¶à¤¾à¤¸à¤• निमà¥à¤¨ कà¥à¤°à¤¾ हेरà¥à¤¨ सकà¥à¤¨à¥à¤¹à¥à¤¨à¥à¤›:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, तपाईं गोपà¥à¤¯ रूपमा बà¥à¤°à¤¾à¤‰à¤œ गरà¥à¤¨ चाहनà¥à¤¹à¥à¤¨à¥à¤› भने टà¥à¤¯à¤¾à¤¬ की अनि इनà¥à¤Ÿà¤° की थिचेर नयाठइनà¥à¤•à¥‹à¤—à¥à¤¨à¤¿à¤Ÿà¥‹ टà¥à¤¯à¤¾à¤¬ खोलà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> ले सà¥à¤°à¤•à¥à¤·à¤¾ मानहरूको पालना गरà¥à¤¦à¥ˆà¤¨à¥¤</translation>
<translation id="7210993021468939304">कनà¥à¤Ÿà¥‡à¤¨à¤° भितà¥à¤° Linux का कà¥à¤°à¤¿à¤¯à¤¾à¤•à¤²à¤¾à¤ª हेरà¥à¤¨ र कनà¥à¤Ÿà¥‡à¤¨à¤°à¤­à¤¿à¤¤à¥à¤° Linux à¤à¤ªà¤¹à¤°à¥‚ इनà¥à¤¸à¥à¤Ÿà¤² गरà¥à¤¨ र चलाउन सकà¥à¤›</translation>
@@ -1936,6 +1982,7 @@
<translation id="7304562222803846232">Google खाताका गोपनीयतासमà¥à¤¬à¤¨à¥à¤§à¥€ सेटिङ मिलाउनà¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="7305756307268530424">अठसà¥à¤¸à¥à¤¤ गतिमा सà¥à¤°à¥ गरियोसà¥</translation>
<translation id="7308436126008021607">बà¥à¤¯à¤¾à¤•à¤—à¥à¤°à¤¾à¤‰à¤¨à¥à¤¡à¤®à¤¾ सिंक गरà¥à¤¨à¥‡ सà¥à¤µà¤¿à¤§à¤¾</translation>
+<translation id="7310392214323165548">डिभाइस चाà¤à¤¡à¥ˆ रिसà¥à¤Ÿà¤¾à¤°à¥à¤Ÿ हà¥à¤¨à¥‡ छ</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">जडानसमà¥à¤¬à¤¨à¥à¤§à¥€ मदà¥à¤¦à¤¤</translation>
<translation id="7323804146520582233">"<ph name="SECTION" />" खणà¥à¤¡ लà¥à¤•à¤¾à¤‡à¤¯à¥‹à¤¸à¥</translation>
@@ -1943,6 +1990,7 @@
<translation id="7334320624316649418">कà¥à¤°à¤® परिवरà¥à¤¤à¤¨ &amp;पà¥à¤¨: गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="7335157162773372339">तपाईंको कà¥à¤¯à¤¾à¤®à¥‡à¤°à¤¾ पà¥à¤°à¤¯à¥‹à¤— गरà¥à¤¨à¥‡ अनà¥à¤®à¤¤à¤¿ मागà¥à¤¨ सकà¥à¤›</translation>
<translation id="7337248890521463931">थप हरफ देखाउनà¥à¤¹à¥‹à¤¸à¥</translation>
+<translation id="7337418456231055214">भरà¥à¤šà¥à¤…ल कारà¥à¤¡ नमà¥à¤¬à¤° भरिà¤à¤•à¥‹ छैन? आफूले कपी गरà¥à¤¨ चाहेका कारà¥à¤¡à¤¸à¤®à¥à¤¬à¤¨à¥à¤§à¥€ विवरणमा कà¥à¤²à¤¿à¤• गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥à¥¤ <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">तपाईंको पà¥à¤²à¥‡à¤Ÿà¤«à¤°à¥à¤®à¤®à¤¾ उपलबà¥à¤§ छैन।</translation>
<translation id="733923710415886693">पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤°à¤•à¥‹ पारदरà¥à¤¶à¤¿à¤¤à¤¾ नीति मारà¥à¤«à¤¤ सरà¥à¤­à¤°à¤•à¥‹ पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤°à¤•à¥‹ खà¥à¤²à¤¾à¤¸à¤¾ भà¤à¤¨à¥¤</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1965,6 +2013,7 @@
<translation id="7378627244592794276">होइन</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">लागू नहà¥à¤¨à¥‡</translation>
+<translation id="7388594495505979117">{0,plural, =1{तपाईंको डिभाइस १ मिनेटमा रिसà¥à¤Ÿà¤¾à¤°à¥à¤Ÿ हà¥à¤¨à¥‡ छ}other{तपाईंको डिभाइस # मिनेटमा रिसà¥à¤Ÿà¤¾à¤°à¥à¤Ÿ हà¥à¤¨à¥‡ छ}}</translation>
<translation id="7390545607259442187">कारà¥à¤¡à¤•à¥‹ पà¥à¤·à¥à¤Ÿà¤¿ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="7392089738299859607">ठेगाना परिवरà¥à¤¤à¤¨ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="7399802613464275309">सà¥à¤°à¤•à¥à¤·à¤¾ जाà¤à¤š</translation>
@@ -1972,7 +2021,7 @@
<translation id="7403392780200267761">लिंक सेयर गरेर, QR कोड बनाà¤à¤°, कासà¥à¤Ÿ गरेर वा अनà¥à¤¯ तरिकाले यो टà¥à¤¯à¤¾à¤¬ सेयर गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="7403591733719184120">तपाईंको <ph name="DEVICE_NAME" /> वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¿à¤¤ छ</translation>
<translation id="7407424307057130981">&lt;p&gt;आफà¥à¤¨à¥‹ Windows कमà¥à¤ªà¥à¤¯à¥à¤Ÿà¤°à¤®à¤¾ Superfish नामक सफà¥à¤Ÿà¤µà¥‡à¤¯à¤° भà¤à¤•à¥‹ खणà¥à¤¡à¤®à¤¾ तपाईं यो तà¥à¤°à¥à¤Ÿà¤¿ देखॠहà¥à¤¨à¥‡ छ।&lt;/p&gt;
- &lt;p&gt;तपाईं वेबमा जान सकà¥à¤¨à¥à¤¹à¥‹à¤¸à¥ भनà¥à¤¨à¤¾à¤•à¤¾ खातिर उकà¥à¤¤ सफà¥à¤Ÿà¤µà¥‡à¤¯à¤°à¤²à¤¾à¤ˆ असà¥à¤¥à¤¾à¤¯à¥€ रूपमा असकà¥à¤·à¤® पारà¥à¤¨ यी चरणहरूको पालना गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥â€Œà¥¤ यसका लागि तपाईंलाई पà¥à¤°à¤¶à¤¾à¤¸à¤•à¥€à¤¯ विशेषाधिकारहरू आवशà¥à¤¯à¤• परà¥à¤¨à¥‡ छ।&lt;/p&gt;
+ &lt;p&gt;तपाईं वेबमा जान सकà¥à¤¨à¥à¤¹à¥‹à¤¸à¥ भनà¥à¤¨à¤¾à¤•à¤¾ लागि उकà¥à¤¤ सफà¥à¤Ÿà¤µà¥‡à¤¯à¤°à¤²à¤¾à¤ˆ असà¥à¤¥à¤¾à¤¯à¥€ रूपमा असकà¥à¤·à¤® पारà¥à¤¨ यी चरणहरूको पालना गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥â€Œà¥¤ यसका लागि तपाईंलाई पà¥à¤°à¤¶à¤¾à¤¸à¤•à¥€à¤¯ विशेषाधिकारहरू आवशà¥à¤¯à¤• परà¥à¤¨à¥‡ छ।&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;सà¥à¤°à¥à¤µà¤¾à¤¤&lt;/strong&gt;, मेनà¥à¤®à¤¾ कà¥à¤²à¤¿à¤• गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥â€Œ, तà¥à¤¯à¤¸à¤ªà¤›à¤¿ &lt;strong&gt;"सà¥à¤¥à¤¾à¤¨à¥€à¤¯ सेवाहरू हेरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥"&lt;/strong&gt; खोजेर तà¥à¤¯à¤¸à¤²à¤¾à¤ˆ चयन गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥
&lt;li&gt;चयन गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥ &lt;strong&gt;VisualDiscovery&lt;/strong&gt;
@@ -2001,6 +2050,12 @@
<translation id="7485870689360869515">कà¥à¤¨à¥ˆà¤ªà¤¨à¤¿ डाटा भेटिà¤à¤¨à¥¤</translation>
<translation id="7495528107193238112">यो सामगà¥à¤°à¥€à¤²à¤¾à¤ˆ रोक लगाइà¤à¤•à¥‹ छ। यो समसà¥à¤¯à¤¾ समाधान गरà¥à¤¨ उकà¥à¤¤ साइटका मालिकसà¤à¤— समà¥à¤ªà¤°à¥à¤• गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥à¥¤</translation>
<translation id="7497998058912824456">"डकà¥à¤®à¥‡à¤¨à¥à¤Ÿ बनाउनà¥à¤¹à¥‹à¤¸à¥" नामक बटन, Google डकà¥à¤®à¥‡à¤¨à¥à¤Ÿ पà¥à¤°à¤¯à¥‹à¤— गरी तà¥à¤°à¥à¤¨à¥à¤¤à¥ˆ नयाठडकà¥à¤®à¥‡à¤¨à¥à¤Ÿ बनाउन Enter थिचà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
+<translation id="7506488012654002225">Chromium ले निमà¥à¤¨ जानकारी <ph name="BEGIN_EMPHASIS" />सेभ गरà¥à¤¨à¥‡ छैन<ph name="END_EMPHASIS" />:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />तपाईंको बà¥à¤°à¤¾à¤‰à¤œà¤¿à¤™ इतिहास
+ <ph name="LIST_ITEM" />कà¥à¤•à¥€ तथा साइट डेटा
+ <ph name="LIST_ITEM" />फारामहरूमा भरिà¤à¤•à¥‹ जानकारी
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">फिरà¥à¤¤à¤¾ गरिà¤à¤•à¥‹ नीति समà¥à¤¬à¤¨à¥à¤§à¥€ यनà¥à¤¤à¥à¤° खाली छ वा हालको यनà¥à¤¤à¥à¤°à¤•à¥‹ id सà¤à¤— मेल खाà¤à¤¦à¥ˆà¤¨</translation>
<translation id="7508870219247277067">गाढा हरियो</translation>
<translation id="7511955381719512146">तपाईà¤à¤²à¥‡ पà¥à¤°à¤¯à¥‹à¤— गरिरहनà¥à¤­à¤à¤•à¥‹ Wi-Fi लाई तपाईà¤à¤²à¥‡ <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> को भà¥à¤°à¤®à¤£ गरà¥à¤¨ आवशà¥à¤¯à¤•à¤¤à¤¾ हà¥à¤¨ सकà¥à¤›à¥¤</translation>
@@ -2114,7 +2169,6 @@
<translation id="7813600968533626083">Chrome बाट फारम सà¥à¤à¤¾à¤µ हटाउने हो?</translation>
<translation id="781440967107097262">कà¥à¤²à¤¿à¤ªà¤¬à¥‹à¤°à¥à¤¡ सेयर गरà¥à¤¨à¥‡ हो?</translation>
<translation id="7815407501681723534"><ph name="SEARCH_RESULTS" /> <ph name="SEARCH_STRING" />' का <ph name="NUMBER_OF_RESULTS" /> वटा परिणामहरू भेटिà¤</translation>
-<translation id="782125616001965242">यो साइटसमà¥à¤¬à¤¨à¥à¤§à¥€ जानकारी देखाइयोसà¥</translation>
<translation id="782886543891417279">तपाईà¤à¤²à¥‡ पà¥à¤°à¤¯à¥‹à¤— गरिरहनॠभà¤à¤•à¥‹ Wi-Fi (<ph name="WIFI_NAME" />) लाई तपाईà¤à¤²à¥‡ यसको लगइन पृषà¥à¤ à¤•à¥‹ भà¥à¤°à¤®à¤£ आवशà¥à¤¯à¤•à¤¤à¤¾ परà¥à¤¨ सकà¥à¤›à¥¤</translation>
<translation id="7836231406687464395">Postfix (Envelope)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{कà¥à¤¨à¥ˆ पनि होइन}=1{१ à¤à¤ª (<ph name="EXAMPLE_APP_1" />)}=2{२ à¤à¤ªà¤¹à¤°à¥‚ (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}other{# à¤à¤ªà¤¹à¤°à¥‚ (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}}</translation>
@@ -2131,7 +2185,6 @@
<translation id="7888575728750733395">पà¥à¤°à¤¿à¤¨à¥à¤Ÿà¤¿à¤™ रेनà¥à¤¡à¤° गरà¥à¤¨à¥‡ पà¥à¤°à¤•à¥à¤°à¤¿à¤¯à¤¾à¤•à¥‹ उदà¥à¤¦à¥‡à¤¶à¥à¤¯</translation>
<translation id="7894280532028510793">हिजà¥à¤œà¥‡ सही छ भने <ph name="BEGIN_LINK" />'नेटवरà¥à¤•à¤•à¤¾ डाइगोनà¥à¤¸à¥à¤Ÿà¤¿à¤•à¥à¤¸' चलाà¤à¤° हेरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥<ph name="END_LINK" />।</translation>
<translation id="7904208859782148177">C3 (Envelope)</translation>
-<translation id="7931318309563332511">अजà¥à¤žà¤¾à¤¤</translation>
<translation id="793209273132572360">ठेगाना बदलà¥à¤¨à¥‡ हो?</translation>
<translation id="7932579305932748336">कोट</translation>
<translation id="79338296614623784">मानà¥à¤¯ फोन नमà¥à¤¬à¤° पà¥à¤°à¤µà¤¿à¤·à¥à¤Ÿà¤¿ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
@@ -2156,13 +2209,14 @@
<translation id="7976214039405368314">अतà¥à¤¯à¤¨à¥à¤¤ धेरै पटक अनà¥à¤°à¥‹à¤§ गरियो</translation>
<translation id="7977538094055660992">आउटपà¥à¤Ÿ यनà¥à¤¤à¥à¤°</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">यो कारà¥à¤¡à¤¸à¤à¤— लिंक गरिà¤à¤•à¥‹ छ</translation>
<translation id="798134797138789862">भरà¥à¤šà¥à¤…ल रियालिटी चलà¥à¤¨à¥‡ डिभाइस र डेटा पà¥à¤°à¤¯à¥‹à¤— गरà¥à¤¨à¥‡ अनà¥à¤®à¤¤à¤¿ मागà¥à¤¨ सकà¥à¤›</translation>
<translation id="7984945080620862648">तपाईं अहिले नै <ph name="SITE" /> भà¥à¤°à¤®à¤£ गरà¥à¤¨ सकà¥à¤¨à¥à¤¹à¥à¤¨à¥à¤¨ किनभने वेबसाइटले सà¥à¤•à¥à¤°à¥‡à¤®à¥à¤¬à¤² गरिà¤à¤•à¤¾ पतà¥à¤¯à¤¾à¤°à¤ªà¤¤à¥à¤°à¤¹à¤°à¥‚ पठायो जसलाई Chrome ले पà¥à¤°à¤•à¥à¤°à¤¿à¤¯à¤¾à¤®à¤¾ लैजान सकà¥à¤¦à¥ˆà¤¨à¥¤ नेटवरà¥à¤• तà¥à¤°à¥à¤Ÿà¤¿à¤¹à¤°à¥‚ र आकà¥à¤°à¤®à¤£à¤¹à¤°à¥‚ पà¥à¤°à¤¾à¤¯: असà¥à¤¥à¤¾à¤¯à¥€ हà¥à¤¨à¥‡ गरà¥à¤¦à¤›à¤¨à¥, तà¥à¤¯à¤¸à¥ˆà¤²à¥‡ समà¥à¤­à¤µà¤¤: यो पृषà¥à¤ à¤²à¥‡ पछि कारà¥à¤¯ गरà¥à¤¨à¥‡ छ।</translation>
-<translation id="79859296434321399">अगà¥à¤®à¥‡à¤¨à¥à¤Ÿà¥‡à¤¡ रियालिटी सामगà¥à¤°à¥€ हेरà¥à¤¨ ARCore सà¥à¤¥à¤¾à¤ªà¤¨à¤¾ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">बाइनà¥à¤¡</translation>
<translation id="7992044431894087211"><ph name="APPLICATION_TITLE" /> सà¤à¤— सà¥à¤•à¥à¤°à¤¿à¤¨ सेयर गरà¥à¤¨à¥‡ कारà¥à¤¯ सà¥à¤šà¤¾à¤°à¥ भà¤à¤•à¥‹ छ</translation>
<translation id="7995512525968007366">तोकिà¤à¤•à¥‹ छैन</translation>
+<translation id="7998269595945679889">इनà¥à¤•à¥‹à¤—à¥à¤¨à¤¿à¤Ÿà¥‹ टà¥à¤¯à¤¾à¤¬ खोलà¥à¤¨à¥‡ बटन, तपाईं गोपà¥à¤¯ रूपमा बà¥à¤°à¤¾à¤‰à¤œ गरà¥à¤¨ चाहनà¥à¤¹à¥à¤¨à¥à¤› भने इनà¥à¤Ÿà¤° की थिचेर नयाठइनà¥à¤•à¥‹à¤—à¥à¤¨à¤¿à¤Ÿà¥‹ टà¥à¤¯à¤¾à¤¬ खोलà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="800218591365569300">मेमोरी खाली गरà¥à¤¨ अनà¥à¤¯ टà¥à¤¯à¤¾à¤¬ वा पà¥à¤°à¥‹à¤—à¥à¤°à¤¾à¤®à¤¹à¤°à¥‚ बनà¥à¤¦ गरी हेरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥à¥¤</translation>
<translation id="8004582292198964060">बà¥à¤°à¤¾à¤‰à¤œà¤°</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{यो कारà¥à¤¡ र यसको बिलिङ ठेगाना सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ गरिने छ। तपाईं <ph name="USER_EMAIL" /> मारà¥à¤«à¤¤ साइन इन हà¥à¤à¤¦à¤¾ यसको पà¥à¤°à¤¯à¥‹à¤— गरà¥à¤¨ सकà¥à¤¨à¥ हà¥à¤¨à¥‡ छ।}other{यी कारà¥à¤¡ र यिनका बिलिङ ठेगाना सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ गरिने छनà¥à¥¤ तपाईं <ph name="USER_EMAIL" /> मारà¥à¤«à¤¤ साइन इन हà¥à¤à¤¦à¤¾ यिनको पà¥à¤°à¤¯à¥‹à¤— गरà¥à¤¨ सकà¥à¤¨à¥ हà¥à¤¨à¥‡ छ।}}</translation>
@@ -2222,6 +2276,7 @@
<translation id="8202370299023114387">बेमेल</translation>
<translation id="8206978196348664717">Prc4 (Envelope)</translation>
<translation id="8211406090763984747">जडान सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ छ</translation>
+<translation id="8217240300496046857">साइटहरूले इनà¥à¤Ÿà¤°à¤¨à¥‡à¤Ÿà¤•à¥‹ दà¥à¤¨à¤¿à¤¯à¤¾à¤à¤®à¤¾ तपाईंका कà¥à¤°à¤¿à¤¯à¤¾à¤•à¤²à¤¾à¤ª टà¥à¤°à¥à¤¯à¤¾à¤• गरà¥à¤¨à¥‡ कà¥à¤•à¥€à¤¹à¤°à¥‚ पà¥à¤°à¤¯à¥‹à¤— गरà¥à¤¨ सकà¥à¤¦à¥ˆà¤¨à¤¨à¥à¥¤ तर केही साइटका सà¥à¤µà¤¿à¤§à¤¾à¤¹à¤°à¥‚ले काम नगरà¥à¤¨ सकà¥à¤›à¤¨à¥à¥¤</translation>
<translation id="8218327578424803826">तोकिà¤à¤•à¥‹ सà¥à¤¥à¤¾à¤¨:</translation>
<translation id="8220146938470311105">C7/C6 (Envelope)</translation>
<translation id="8225771182978767009">यो कमà¥à¤ªà¥à¤¯à¥à¤Ÿà¤° सेटअप गरà¥à¤¨à¥‡ वà¥à¤¯à¤•à¥à¤¤à¤¿à¤²à¥‡ यो साइटमाथि रोक लगाउने छनौट गरà¥à¤¨à¥à¤­à¤à¤•à¥‹ छ।</translation>
@@ -2262,14 +2317,9 @@
<translation id="830498451218851433">आधा फोलà¥à¤¡</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">इनà¥à¤¸à¥à¤Ÿà¤² गरिà¤à¤•à¤¾ à¤à¤ª र ती à¤à¤ª पà¥à¤°à¤¯à¥‹à¤— गरिने अनà¥à¤¤à¤°à¤¾à¤²</translation>
+<translation id="8317207217658302555">ARCore अपडेट गरà¥à¤¨à¥‡ हो?</translation>
<translation id="831997045666694187">साà¤à¤</translation>
<translation id="8321476692217554900">सूचनाहरू</translation>
-<translation id="8328484624016508118">तपाईंले सबै इनà¥à¤•à¥‹à¤—à¥à¤¨à¤¿à¤Ÿà¥‹ टà¥à¤¯à¤¾à¤¬ बनà¥à¤¦ गरेपछि Chrome ले:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />तपाईंले यो डिभाइसमा भà¤à¤•à¥‹ बà¥à¤°à¤¾à¤‰à¤œà¤°à¤®à¤¾à¤°à¥à¤«à¤¤ गरà¥à¤¨à¥à¤­à¤à¤•à¥‹ कà¥à¤°à¤¿à¤¯à¤¾à¤•à¤²à¤¾à¤ªà¤¸à¤®à¥à¤¬à¤¨à¥à¤§à¥€ विवरण मेटाउà¤à¤› <ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />यो डिभाइसबाट तपाईंको खोजसमà¥à¤¬à¤¨à¥à¤§à¥€ इतिहास मेटाउà¤à¤›<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />तपाईंले फारममा हालà¥à¤¨à¥à¤­à¤à¤•à¥‹ जानकारी मेटाउà¤à¤›<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489"><ph name="HOST_NAME" /> मा पहà¥à¤à¤š गरà¥à¤¨ असà¥à¤µà¥€à¤•à¥ƒà¤¤ भयो</translation>
<translation id="833262891116910667">हाइलाइट गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="8339163506404995330"><ph name="LANGUAGE" /> मा रहेका पृषà¥à¤ à¤¹à¤°à¥‚लाई अनà¥à¤µà¤¾à¤¦ गरिने छैन</translation>
@@ -2321,6 +2371,7 @@
<translation id="8507227106804027148">कमानà¥à¤¡ लाइन</translation>
<translation id="8508648098325802031">खोज आइकन</translation>
<translation id="8511402995811232419">कà¥à¤•à¥€à¤¹à¤°à¥‚ वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¨ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
+<translation id="8519753333133776369">तपाईंका à¤à¤¡à¥à¤®à¤¿à¤¨à¤²à¥‡ पà¥à¤°à¤¯à¥‹à¤— गरà¥à¤¨à¥‡ अनà¥à¤®à¤¤à¤¿ दिनà¥à¤­à¤à¤•à¥‹ HID डिभाइस</translation>
<translation id="8522552481199248698">Chrome ले तपाईंलाई आफà¥à¤¨à¥‹ Google खाता सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ गरà¥à¤¨ र आफà¥à¤¨à¥‹ पासवरà¥à¤¡ बदलà¥à¤¨ मदà¥à¤¦à¤¤ गरà¥à¤¨ सकà¥à¤›à¥¤</translation>
<translation id="8530813470445476232">Chrome का सेटिङमा गई आफà¥à¤¨à¥‹ बà¥à¤°à¤¾à¤‰à¤œà¤¿à¤™ इतिहास, कà¥à¤•à¥€, कà¥à¤¯à¤¾à¤¸ र अनà¥à¤¯ डेटा मेटाउनà¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="8533619373899488139">बà¥à¤²à¤• गरिà¤à¤•à¤¾ URL र तपाईंको पà¥à¤°à¤£à¤¾à¤²à¥€à¤•à¤¾ à¤à¤¡à¥à¤®à¤¿à¤¨à¤²à¥‡ लागू गरà¥à¤¨à¥à¤­à¤à¤•à¤¾ अनà¥à¤¯ नीतिहरूको सूची हेरà¥à¤¨ &lt;strong&gt;chrome://policy&lt;/strong&gt; मा जानà¥à¤¹à¥‹à¤¸à¥à¥¤</translation>
@@ -2332,7 +2383,6 @@
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{अनà¥à¤®à¤¤à¤¿ रिसेट गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥}other{अनà¥à¤®à¤¤à¤¿ रिसेट गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥}}</translation>
<translation id="8555010941760982128">चेक आउट गरà¥à¤¦à¤¾ यो कोड पà¥à¤°à¤¯à¥‹à¤— गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="8557066899867184262">उकà¥à¤¤ CVC तपाईंको कारà¥à¤¡à¤•à¥‹ पछाडितिर छ।</translation>
-<translation id="8558485628462305855">अगà¥à¤®à¥‡à¤¨à¥à¤Ÿà¥‡à¤¡ रियालिटी सामगà¥à¤°à¥€ हेरà¥à¤¨ ARCore अपडेट गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="8559762987265718583"><ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />मा à¤à¤‰à¤Ÿà¤¾ निजी जडान सà¥à¤¥à¤¾à¤ªà¤¨à¤¾ गरà¥à¤¨ सकà¥à¤¦à¥ˆà¤¨ किनकि तपाईà¤à¤•à¥‹ यनà¥à¤¤à¥à¤°à¤•à¥‹ मिति र समय <ph name="DATE_AND_TIME" /> गलत छनà¥à¥¤</translation>
<translation id="8564182942834072828">छà¥à¤Ÿà¥à¤Ÿà¤¾ छà¥à¤Ÿà¥à¤Ÿà¥ˆ कागजातहरू/कà¥à¤°à¤®à¤¬à¤¦à¥à¤§ नगरिà¤à¤•à¤¾ पà¥à¤°à¤¤à¤¿à¤¹à¤°à¥‚</translation>
<translation id="8564985650692024650">तपाईंले आफà¥à¤¨à¥‹ <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> को पासवरà¥à¤¡ अनà¥à¤¯ साइटहरूमा पà¥à¤¨à¤ƒ पà¥à¤°à¤¯à¥‹à¤— गरà¥à¤¨à¥à¤­à¤à¤•à¤¾ खणà¥à¤¡à¤®à¤¾ Chromium ले तपाईंलाई उकà¥à¤¤ पासवरà¥à¤¡ रिसेट गरà¥à¤¨ सिफारिस गरà¥à¤¦à¤›à¥¤</translation>
@@ -2351,6 +2401,7 @@
<translation id="865032292777205197">मोसन सेनà¥à¤¸à¤°à¤¹à¤°à¥‚</translation>
<translation id="8663226718884576429">अरà¥à¤¡à¤°à¤•à¥‹ सारांश, <ph name="TOTAL_LABEL" />, थप विवरण</translation>
<translation id="8666678546361132282">अङà¥à¤—à¥à¤°à¥‡à¤œà¥€</translation>
+<translation id="8669306706049782872">विनà¥à¤¡à¥‹à¤¹à¤°à¥‚ खोलà¥à¤¨à¥‡ र सà¥à¤•à¥à¤°à¤¿à¤¨à¤®à¤¾ ती विनà¥à¤¡à¥‹ राखà¥à¤¨à¥‡ पà¥à¤°à¤¯à¥‹à¤œà¤¨à¤•à¤¾ लागि तपाईंका सà¥à¤•à¥à¤°à¤¿à¤¨à¤¹à¤°à¥‚का बारेमा जानकारी पà¥à¤°à¤¯à¥‹à¤— गरà¥à¤¨</translation>
<translation id="867224526087042813">हसà¥à¤¤à¤¾à¤•à¥à¤·à¤°</translation>
<translation id="8676424191133491403">विलमà¥à¤¬à¤°à¤¹à¤¿à¤¤</translation>
<translation id="8680536109547170164"><ph name="QUERY" /> , उतà¥à¤¤à¤°, <ph name="ANSWER" /></translation>
@@ -2377,6 +2428,7 @@
<translation id="8731544501227493793">'पासवरà¥à¤¡à¤¹à¤°à¥‚ वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¿à¤¤ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥' नामक बटन, Chrome का सेटिङमा गई आफà¥à¤¨à¤¾ पासवरà¥à¤¡à¤¹à¤°à¥‚ हेरà¥à¤¨ तथा वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¿à¤¤ गरà¥à¤¨ Enter थिचà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="8734529307927223492"><ph name="MANAGER" /> ले तपाईंको <ph name="DEVICE_TYPE" /> वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¨ गरà¥à¤›</translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, गोपà¥à¤¯ रूपमा बà¥à¤°à¤¾à¤‰à¤œ गरà¥à¤¨à¤•à¤¾ निमà¥à¤¤à¤¿ नयाठइनà¥à¤•à¥‹à¤—à¥à¤¨à¤¿à¤Ÿà¥‹ विनà¥à¤¡à¥‹ खोलà¥à¤¨ Tab थिचà¥à¤¨à¥à¤¹à¥‹à¤¸à¥ अनि Enter थिचà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
+<translation id="8737685506611670901"><ph name="REPLACED_HANDLER_TITLE" /> को सटà¥à¤Ÿà¤¾à¤®à¤¾ <ph name="PROTOCOL" /> लिंक खोलà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="8738058698779197622">सà¥à¤°à¤•à¥à¤·à¤¿à¤¤ जडान सà¥à¤¥à¤¾à¤ªà¤¨à¤¾ गरà¥à¤¨, तपाईà¤à¤•à¥‹ घडी ठिक ढङà¥à¤—ले सेट गरà¥à¤¨ आवशà¥à¤¯à¤• छ। यो यसकारण हो किनकि वेबसाइटहरूले आफूलाई पहिचान गरà¥à¤¨ पà¥à¤°à¤¯à¥‹à¤— गरà¥à¤¨à¥‡ पà¥à¤°à¤®à¤¾à¤£ पतà¥à¤°à¤¹à¤°à¥‚ निशà¥à¤šà¤¿à¤¤ समयकालका लागि मातà¥à¤° वैध हà¥à¤¨à¥à¤›à¤¨à¥à¥¤ तपाईà¤à¤•à¥‹ यनà¥à¤¤à¥à¤°à¤•à¥‹ घडी सही नभà¤à¤•à¤¾ कारण कà¥à¤°à¥‹à¤®à¤¿à¤¯à¤®à¤²à¥‡ यी पà¥à¤°à¤®à¤¾à¤£à¤ªà¤¤à¥à¤° पà¥à¤°à¤®à¤¾à¤£à¥€à¤•à¤°à¤£ गरà¥à¤¨ सकà¥à¤¦à¥ˆà¤¨à¥¤</translation>
<translation id="8740359287975076522"><ph name="HOST_NAME" />’s &lt;abbr id="dnsDefinition"&gt;DNS ठेगाना&lt;/abbr&gt; फेला पारà¥à¤¨ सकिà¤à¤¨à¥¤ समसà¥à¤¯à¤¾à¤•à¥‹ निदान गरà¥à¤¦à¥ˆà¥¤</translation>
<translation id="8742371904523228557"><ph name="ORIGIN" /> का लागि तपाईंको कोड <ph name="ONE_TIME_CODE" /> हो</translation>
@@ -2404,6 +2456,7 @@
<translation id="883848425547221593">अनà¥à¤¯ बà¥à¤•à¤®à¤¾à¤°à¥à¤•à¤¹à¤°à¥‚</translation>
<translation id="884264119367021077">सिपिङ ठेगाना</translation>
<translation id="884923133447025588">कà¥à¤¨à¥ˆà¤ªà¤¨à¤¿ खणà¥à¤¡à¤¨ संयनà¥à¤¤à¥à¤° फेला परेन।</translation>
+<translation id="8849262850971482943">थप सà¥à¤°à¤•à¥à¤·à¤¾à¤•à¤¾ निमà¥à¤¤à¤¿ भरà¥à¤šà¥à¤…ल कारà¥à¤¡ पà¥à¤°à¤¯à¥‹à¤— गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="885730110891505394">Google सà¤à¤— साà¤à¥‡à¤¦à¤¾à¤°à¥€</translation>
<translation id="8858065207712248076">तपाईंले आफà¥à¤¨à¥‹ <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> को पासवरà¥à¤¡ अनà¥à¤¯ साइटहरूमा पà¥à¤¨à¤ƒ पà¥à¤°à¤¯à¥‹à¤— गरà¥à¤¨à¥à¤­à¤à¤•à¤¾ खणà¥à¤¡à¤®à¤¾ Chrome ले तपाईंलाई उकà¥à¤¤ पासवरà¥à¤¡ रिसेट गरà¥à¤¨ सिफारिस गरà¥à¤¦à¤›à¥¤</translation>
<translation id="885906927438988819">हिजà¥à¤œà¥‡ सही छ भने <ph name="BEGIN_LINK" />'Windows नेटवरà¥à¤•à¤•à¤¾ डाइगोनेसà¥à¤Ÿà¤¿à¤•à¥à¤¸' चलाà¤à¤° हेरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥<ph name="END_LINK" />।</translation>
@@ -2453,6 +2506,7 @@
<translation id="9004367719664099443">VR सतà¥à¤° जारी छ</translation>
<translation id="9005998258318286617">PDF कागजात लोड गरà¥à¤¨ सकिà¤à¤¨à¥¤</translation>
<translation id="9008201768610948239">बेवासà¥à¤¤à¤¾ गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
+<translation id="901834265349196618">इमेल</translation>
<translation id="9020200922353704812">कारà¥à¤¡à¤•à¥‹ बिलिङ ठेगाना आवशà¥à¤¯à¤• हà¥à¤¨à¥à¤›</translation>
<translation id="9020542370529661692">यो पृषà¥à¤ à¤²à¤¾à¤ˆ <ph name="TARGET_LANGUAGE" /> मा अनà¥à¤µà¤¾à¤¦ गरिà¤à¤•à¥‹ छ</translation>
<translation id="9020742383383852663">A8</translation>
@@ -2501,6 +2555,7 @@
<translation id="9150045010208374699">तपाइà¤à¤•à¥‹ कà¥à¤¯à¤¾à¤®à¥‡à¤°à¤¾ पà¥à¤°à¤¯à¥‹à¤— गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥</translation>
<translation id="9150685862434908345">तपाईंका पà¥à¤°à¤¶à¤¾à¤¸à¤• टाढैबाट तपाईंको बà¥à¤°à¤¾à¤‰à¤œà¤°à¤•à¥‹ सेटअप बदलà¥à¤¨ सकà¥à¤¨à¥à¤¹à¥à¤¨à¥à¤›à¥¤ यो डिभाइसका कà¥à¤°à¤¿à¤¯à¤¾à¤•à¤²à¤¾à¤ª Chrome बाहिरबाट पनि वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¨ गरà¥à¤¨ सकिनà¥à¤›à¥¤ <ph name="BEGIN_LINK" />थप जानà¥à¤¨à¥à¤¹à¥‹à¤¸à¥<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">अपडेट भयो</translation>
+<translation id="9155211586651734179">à¤à¤Ÿà¥à¤¯à¤¾à¤š गरिà¤à¤•à¤¾ अडियोसमà¥à¤¬à¤¨à¥à¤§à¥€ सहायक डिभाइसहरू</translation>
<translation id="9157595877708044936">सेटिङ गरà¥à¤¦à¥ˆ...</translation>
<translation id="9158625974267017556">C6 (Envelope)</translation>
<translation id="9164029392738894042">सटीकताको जाà¤à¤š</translation>
diff --git a/chromium/components/strings/components_strings_nl.xtb b/chromium/components/strings/components_strings_nl.xtb
index b9fc1dcd121..95409df84d7 100644
--- a/chromium/components/strings/components_strings_nl.xtb
+++ b/chromium/components/strings/components_strings_nl.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">Details bekijken</translation>
<translation id="1030706264415084469"><ph name="URL" /> wil grote gegevens permanent op je apparaat opslaan</translation>
<translation id="1032854598605920125">Rechtsom draaien</translation>
+<translation id="1033329911862281889">Incognito maakt je niet onzichtbaar online:
+<ph name="BEGIN_LIST" />
+<ph name="LIST_ITEM" />Sites en de services die ze gebruiken, kunnen bezoeken zien<ph name="END_LIST_ITEM" />
+<ph name="LIST_ITEM" />Werkgevers of scholen kunnen browse-activiteit bijhouden<ph name="END_LIST_ITEM" />
+<ph name="LIST_ITEM" />Internetproviders kunnen webverkeer monitoren<ph name="END_LIST_ITEM" />
+<ph name="END_LIST" /></translation>
<translation id="1036348656032585052">Uitzetten</translation>
<translation id="1036982837258183574">Druk op |<ph name="ACCELERATOR" />| om het volledige scherm te sluiten</translation>
<translation id="1038106730571050514">Suggesties bekijken</translation>
<translation id="1038842779957582377">onbekende naam</translation>
<translation id="1041998700806130099">Bericht voor taakblad</translation>
<translation id="1048785276086539861">Als je annotaties bewerkt, keert dit document terug naar een weergave op één pagina</translation>
-<translation id="1049743911850919806">Incognito</translation>
<translation id="1050038467049342496">Andere apps sluiten</translation>
<translation id="1055184225775184556">&amp;Toevoegen ongedaan maken</translation>
<translation id="1056898198331236512">Waarschuwing</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">Cachegeheugen van beleid is OK</translation>
<translation id="1130564665089811311">Knop 'Pagina vertalen'. Druk op Enter om deze pagina te vertalen met Google Translate.</translation>
<translation id="1131264053432022307">Afbeelding die je hebt gekopieerd</translation>
+<translation id="1142846828089312304">Cookies van derden blokkeren in incognito</translation>
<translation id="1150979032973867961">De server kan niet bewijzen dat dit <ph name="DOMAIN" /> is. Het beveiligingscertificaat van de server wordt niet vertrouwd door het besturingssysteem van je computer. Dit kan worden veroorzaakt door een verkeerde configuratie of een aanvaller die je verbinding onderschept.</translation>
<translation id="1151972924205500581">Wachtwoord vereist</translation>
<translation id="1156303062776767266">Je bekijkt een lokaal of gedeeld bestand</translation>
@@ -64,7 +70,6 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="1178581264944972037">Onderbreken</translation>
<translation id="1181037720776840403">Verwijderen</translation>
<translation id="1186201132766001848">Wachtwoorden controleren</translation>
-<translation id="1195210374336998651">Ga naar app-instellingen</translation>
<translation id="1195558154361252544">Meldingen zijn automatisch geblokkeerd voor alle sites, behalve de meldingen die je toestaat</translation>
<translation id="1197088940767939838">Oranje</translation>
<translation id="1201402288615127009">Volgende</translation>
@@ -111,7 +116,7 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="1307966114820526988">Verouderde functies</translation>
<translation id="1308113895091915999">Aanbieding beschikbaar</translation>
<translation id="1312803275555673949">Door welk bewijs wordt dit bevestigd?</translation>
-<translation id="131405271941274527"><ph name="URL" /> wil informatie sturen en ontvangen als je je telefoon tegen een NFC-apparaat houdt</translation>
+<translation id="1314311879718644478">Augmented reality-content bekijken</translation>
<translation id="1314509827145471431">Rechts inbinden</translation>
<translation id="1318023360584041678">Opgeslagen in tabbladgroep</translation>
<translation id="1319245136674974084">Niet meer vragen voor deze app</translation>
@@ -161,6 +166,7 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="142858679511221695">Cloud-gebruiker</translation>
<translation id="1428729058023778569">Je ziet deze waarschuwing omdat deze site geen HTTPS ondersteunt. <ph name="BEGIN_LEARN_MORE_LINK" />Meer informatie<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">Afdrukken</translation>
+<translation id="1432187715652018471">De pagina wil een servicehandler installeren.</translation>
<translation id="1432581352905426595">Zoekmachines beheren</translation>
<translation id="1436185428532214179">Kan vragen of deze site bestanden en mappen op je apparaat mag bewerken</translation>
<translation id="1442386063175183758">Gatefold rechts</translation>
@@ -181,6 +187,12 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="1483493594462132177">Verzenden</translation>
<translation id="1484290072879560759">Verzendadres kiezen</translation>
<translation id="1492194039220927094">Pushen van beleid:</translation>
+<translation id="149293076951187737">Als je alle Chrome-incognitotabbladen sluit, wordt je activiteit op die tabbladen van dit apparaat gewist:
+<ph name="BEGIN_LIST" />
+<ph name="LIST_ITEM" />Browse-activiteit<ph name="END_LIST_ITEM" />
+<ph name="LIST_ITEM" />Zoekgeschiedenis<ph name="END_LIST_ITEM" />
+<ph name="LIST_ITEM" />Informatie die je in formulieren hebt opgegeven<ph name="END_LIST_ITEM" />
+<ph name="END_LIST" /></translation>
<translation id="1495677929897281669">Terug naar tabblad</translation>
<translation id="1501859676467574491">Passen uit je Google-account bekijken</translation>
<translation id="1507202001669085618">&lt;p&gt;J​e ​zi​et​ d​ez​e ​fo​ut​ a​ls​ j​e ​ee​n ​wi​fi​-p​or​ta​l ​ge​br​ui​kt​ w​aa​ro​p ​je​ m​oe​t ​in​lo​gg​en​ v​oo​rd​at​ j​e ​on​li​ne​ k​un​t ​ga​an​.&lt;/p&gt;
@@ -208,13 +220,16 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="1559572115229829303">&lt;p&gt;Er kan geen privéverbinding met <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> tot stand worden gebracht, omdat de datum en tijd van je apparaat (<ph name="DATE_AND_TIME" />) onjuist zijn.&lt;/p&gt;
&lt;p&gt;Pas in het gedeelte &lt;strong&gt;Algemeen&lt;/strong&gt; van de app &lt;strong&gt;Instellingen&lt;/strong&gt; de datum en tijd aan.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">Je beheerder start je apparaat opnieuw op om <ph name="TIME" /> op <ph name="DATE" /></translation>
+<translation id="156703335097561114">Netwerkinformatie zoals adressen, interfaceconfiguratie en verbindingskwaliteit</translation>
<translation id="1567040042588613346">Dit beleid werkt zoals bedoeld, maar ergens anders is dezelfde waarde ingesteld die wordt vervangen door dit beleid.</translation>
<translation id="1569487616857761740">Vervaldatum invoeren</translation>
<translation id="1581080074034554886">CVC</translation>
<translation id="1583294866416602487">Plex</translation>
-<translation id="1583429793053364125">Er is iets misgegaan met het weergeven van deze webpagina.</translation>
+<translation id="1583429793053364125">Er is iets misgegaan met het bekijken van deze webpagina.</translation>
<translation id="1586541204584340881">Welke extensies je hebt geïnstalleerd</translation>
<translation id="1588438908519853928">Normaal</translation>
+<translation id="1589050138437146318">ARCore installeren?</translation>
<translation id="1592005682883173041">Lokale gegevenstoegang</translation>
<translation id="1594030484168838125">Kiezen</translation>
<translation id="160851722280695521">Speel de Dino Run-game in Chrome</translation>
@@ -254,7 +269,7 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="1711234383449478798">Genegeerd omdat <ph name="POLICY_NAME" /> niet is ingesteld op <ph name="VALUE" />.</translation>
<translation id="1712552549805331520"><ph name="URL" /> vraagt toestemming om permanent gegevens op je lokale computer op te slaan</translation>
<translation id="1713628304598226412">Lade 2</translation>
-<translation id="1715874602234207">F</translation>
+<translation id="1715874602234207">V</translation>
<translation id="1717218214683051432">Bewegingssensoren</translation>
<translation id="1717494416764505390">Mailbox 3</translation>
<translation id="1718029547804390981">Document is te groot om aantekeningen te maken</translation>
@@ -280,6 +295,7 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Voer Windows Netwerkcontrole uit<ph name="END_LINK" />.</translation>
<translation id="1772163372082567643">Voor de server waar je naartoe gaat (<ph name="ORIGIN" />), is een header ingesteld
die vereist dat een herkomstbeleid wordt toegepast op alle verzoeken aan de server. De header heeft echter een verkeerde indeling, waardoor de browser je verzoek voor <ph name="SITE" /> niet kan uitvoeren. Herkomstbeleidsregels kunnen worden gebruikt door site-operators om beveiliging en andere eigenschappen voor een site te configureren.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Meer informatie over incognito in Chromium<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">Je geopende tabbladen zie je hier</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -407,6 +423,7 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="22081806969704220">Lade 3</translation>
<translation id="2212735316055980242">Beleid niet gevonden</translation>
<translation id="2213606439339815911">Items ophalen…</translation>
+<translation id="2213612003795704869">Pagina is afgedrukt</translation>
<translation id="2215727959747642672">Bestanden bewerken</translation>
<translation id="2218879909401188352">Op <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> actieve cybercriminelen kunnen gevaarlijke apps installeren die je apparaat beschadigen, verborgen kosten toevoegen aan je mobiele telefoonrekening of je persoonlijke informatie stelen. <ph name="BEGIN_LEARN_MORE_LINK" />Meer informatie<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">Geen internet</translation>
@@ -416,6 +433,7 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="2248949050832152960">WebAuthn gebruiken</translation>
<translation id="2250931979407627383">Inbinden met nietjes links</translation>
<translation id="225207911366869382">Deze waarde is verouderd voor dit beleid.</translation>
+<translation id="2256115617011615191">Nu opnieuw starten</translation>
<translation id="2258928405015593961">Geef een vervaldatum op die in de toekomst ligt en probeer het opnieuw</translation>
<translation id="225943865679747347">Foutcode: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">HTTP-fout</translation>
@@ -443,6 +461,7 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="2337852623177822836">Instelling beheerd door je beheerder</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> wil koppelen</translation>
<translation id="2346319942568447007">Afbeelding die je hebt gekopieerd</translation>
+<translation id="2350796302381711542"><ph name="HANDLER_HOSTNAME" /> toestaan alle links voor <ph name="PROTOCOL" /> te openen in plaats van <ph name="REPLACED_HANDLER_TITLE" />?</translation>
<translation id="2354001756790975382">Andere bookmarks</translation>
<translation id="2354430244986887761">Google Safe Browsing heeft onlangs <ph name="BEGIN_LINK" />schadelijke apps gevonden<ph name="END_LINK" /> op <ph name="SITE" />.</translation>
<translation id="2355395290879513365">Aanvallers kunnen mogelijk de afbeeldingen zien die je op deze site bekijkt en je misleiden door de afbeeldingen aan te passen.</translation>
@@ -468,6 +487,7 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="2413528052993050574">De server kan niet bewijzen dat dit <ph name="DOMAIN" /> is. Het beveiligingscertificaat van de server is mogelijk ingetrokken. Dit kan worden veroorzaakt door een verkeerde configuratie of een aanvaller die je verbinding onderschept.</translation>
<translation id="2414886740292270097">Donker</translation>
<translation id="2430968933669123598">Google-account beheren, druk op Enter om je gegevens, privacy, en beveiliging te beheren in je Google-account</translation>
+<translation id="2436186046335138073"><ph name="HANDLER_HOSTNAME" /> toestaan alle links voor <ph name="PROTOCOL" /> te openen?</translation>
<translation id="2438874542388153331">Vier perforaties rechts</translation>
<translation id="2450021089947420533">Trajecten</translation>
<translation id="2463739503403862330">Invullen</translation>
@@ -475,6 +495,7 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="2465655957518002998">Bezorgingsmethode kiezen</translation>
<translation id="2465688316154986572">Nieten</translation>
<translation id="2465914000209955735">Bestanden beheren die je in Chrome hebt gedownload</translation>
+<translation id="2466004615675155314">Informatie van internet tonen</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Netwerkcontrole uitvoeren<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">Volgorde: van 1 naar N</translation>
<translation id="2470767536994572628">Als je annotaties bewerkt, keert dit document terug naar een weergave op één pagina en de oorspronkelijke paginastand</translation>
@@ -495,6 +516,7 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="2523886232349826891">Alleen opgeslagen op dit apparaat</translation>
<translation id="2524461107774643265">Meer informatie toevoegen</translation>
<translation id="2529899080962247600">Dit veld mag niet meer dan <ph name="MAX_ITEMS_LIMIT" /> items bevatten. Alle andere items worden genegeerd.</translation>
+<translation id="2535585790302968248">Een nieuw incognitotabblad openen om privé te browsen</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{en nog 1}other{en nog #}}</translation>
<translation id="2536110899380797252">Adres toevoegen</translation>
<translation id="2539524384386349900">Detecteren</translation>
@@ -520,7 +542,14 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="2597378329261239068">Dit document is beveiligd met een wachtwoord. Geef een wachtwoord op.</translation>
<translation id="2609632851001447353">Varianten</translation>
<translation id="2610561535971892504">Klik om te kopiëren</translation>
+<translation id="2617988307566202237">De volgende gegevens worden <ph name="BEGIN_EMPHASIS" />niet opgeslagen<ph name="END_EMPHASIS" /> in Chrome:
+<ph name="BEGIN_LIST" />
+<ph name="LIST_ITEM" />Je browsegeschiedenis
+<ph name="LIST_ITEM" />Cookies en sitegegevens
+<ph name="LIST_ITEM" />Informatie die je in formulieren hebt opgegeven
+<ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (envelop)</translation>
+<translation id="2623663032199728144">Kan vragen om informatie over je schermen te gebruiken</translation>
<translation id="2625385379895617796">Je klok loopt voor</translation>
<translation id="262745152991669301">Kan vragen of deze site verbinding mag maken met USB-apparaten</translation>
<translation id="2629325967560697240"><ph name="BEGIN_ENHANCED_PROTECTION_LINK" />Zet de geoptimaliseerde beveiliging aan<ph name="END_ENHANCED_PROTECTION_LINK" /> om het hoogste beveiligingsniveau van Chrome te gebruiken</translation>
@@ -554,6 +583,7 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="2709516037105925701">Automatisch invullen</translation>
<translation id="2713444072780614174">Wit</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />. Druk op Tab en vervolgens op Enter om je betalingen en creditcardgegevens te beheren in de Chrome-instellingen.</translation>
+<translation id="271663710482723385">Druk op |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| om het volledige scherm te sluiten</translation>
<translation id="2721148159707890343">Verzoek geslaagd</translation>
<translation id="2723669454293168317">Voer een veiligheidscheck uit in de Chrome-instellingen</translation>
<translation id="2726001110728089263">Zijlade</translation>
@@ -584,6 +614,7 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="2850739647070081192">Invite (envelop)</translation>
<translation id="2856444702002559011">Cybercriminelen proberen mogelijk je gegevens van <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> te stelen (bijvoorbeeld wachtwoorden, berichten of creditcardgegevens). <ph name="BEGIN_LEARN_MORE_LINK" />Meer informatie<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">Site toont opdringerige of misleidende advertenties.</translation>
+<translation id="286512204874376891">Een virtuele kaart vermomt je werkelijke kaart om je te beschermen tegen potentiële fraude. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">Vriendelijk</translation>
<translation id="2876489322757410363">Je verlaat de incognitomodus om te betalen via een externe app. Doorgaan?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />, druk op Tab en daarna op Enter om Safe Browsing en meer te beheren in de Chrome-instellingen</translation>
@@ -608,6 +639,7 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="2930577230479659665">Bijsnijden na elke kopie</translation>
<translation id="2932085390869194046">Wachtwoord voorstellen…</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019">Links voor <ph name="PROTOCOL" /> openen</translation>
<translation id="2941952326391522266">De server kan niet bewijzen dat dit <ph name="DOMAIN" /> is. Het beveiligingscertificaat van de server is afkomstig van <ph name="DOMAIN2" />. Dit kan worden veroorzaakt door een verkeerde configuratie of een aanvaller die je verbinding onderschept.</translation>
<translation id="2943895734390379394">Uploadtijd:</translation>
<translation id="2948083400971632585">Op de pagina met instellingen kun je proxyservers uitzetten die voor een verbinding zijn ingesteld.</translation>
@@ -640,6 +672,7 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="3037605927509011580">Asjemenou!</translation>
<translation id="3041612393474885105">Certificaatgegevens</translation>
<translation id="3044034790304486808">Je onderzoek hervatten</translation>
+<translation id="305162504811187366">Chrome Remote Desktop-geschiedenis, waaronder tijdstempels, hosts en clientsessie-ID's</translation>
<translation id="3060227939791841287">C9 (envelop)</translation>
<translation id="3061707000357573562">Patchservice</translation>
<translation id="306573536155379004">Game gestart.</translation>
@@ -677,6 +710,7 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="3197136577151645743">Kan vragen of deze site mag weten wanneer je dit apparaat actief gebruikt</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />, druk op Tab en daarna op Enter om de informatie die je synchroniseert te beheren in de Chrome-instellingen</translation>
<translation id="320323717674993345">Betaling annuleren</translation>
+<translation id="3203366800380907218">Van internet</translation>
<translation id="3207960819495026254">Toegevoegd aan 'Bookmarks'</translation>
<translation id="3209034400446768650">Pagina kan geld in rekening brengen</translation>
<translation id="3212581601480735796">Je activiteit op <ph name="HOSTNAME" /> wordt gecontroleerd</translation>
@@ -693,10 +727,12 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="3234666976984236645">Altijd belangrijke content op deze site detecteren</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />, druk op Tab en daarna op Enter om het uiterlijk van je browser aan te passen</translation>
<translation id="3240791268468473923">Pagina geopend waarop staat dat er geen overeenkomende inloggegevens zijn voor beveiligde betaling</translation>
+<translation id="324180406144491771">Links van <ph name="HOST_NAME" /> zijn geblokkeerd</translation>
<translation id="3249845759089040423">Groovy</translation>
<translation id="3252266817569339921">Frans</translation>
<translation id="3257954757204451555">Van wie heb je deze informatie?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />, druk op Tab en daarna op Enter om snel een nieuwe afspraak in Google Agenda te maken</translation>
+<translation id="3261488570342242926">Meer informatie over virtuele kaarten</translation>
<translation id="3264837738038045344">Knop 'Chrome-instellingen beheren', druk op Enter om naar je Chrome-instellingen te gaan</translation>
<translation id="3266793032086590337">Waarde (conflict)</translation>
<translation id="3268451620468152448">Geopende tabbladen</translation>
@@ -710,6 +746,7 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="3288238092761586174"><ph name="URL" /> moet mogelijk aanvullende stappen nemen om je betaling te verifiëren</translation>
<translation id="3293642807462928945">Meer informatie over het beleid <ph name="POLICY_NAME" /></translation>
<translation id="3295444047715739395">Je wachtwoorden bekijken en beheren in de Chrome-instellingen</translation>
+<translation id="3303795387212510132">App toestaan om <ph name="PROTOCOL_SCHEME" />-links te openen?</translation>
<translation id="3303855915957856445">Geen zoekresultaten gevonden</translation>
<translation id="3304073249511302126">bluetooth-scannen</translation>
<translation id="3308006649705061278">Organisatie-eenheid (OU)</translation>
@@ -723,12 +760,6 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="3345782426586609320">Ogen</translation>
<translation id="3355823806454867987">Proxyinstellingen wijzigen...</translation>
<translation id="3360103848165129075">Blad voor betalingshandler</translation>
-<translation id="3361596688432910856">De volgende gegevens worden <ph name="BEGIN_EMPHASIS" />niet opgeslagen<ph name="END_EMPHASIS" /> in Chrome:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Je browsegeschiedenis
- <ph name="LIST_ITEM" />Cookies en sitegegevens
- <ph name="LIST_ITEM" />Informatie die is opgegeven in formulieren
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">Dit beleid is automatisch gekopieerd uit het beëindigde beleid: <ph name="OLD_POLICY" />. Gebruik dit beleid in plaats van het oude.</translation>
<translation id="3364869320075768271"><ph name="URL" /> wil je virtualreality-apparaat en -gegevens gebruiken</translation>
<translation id="3366477098757335611">Passen bekijken</translation>
@@ -810,7 +841,6 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="3587738293690942763">Midden</translation>
<translation id="3592413004129370115">Italian (envelop)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{Je kunt je groep op elk moment resetten. Het duurt ongeveer 1 dag om aan een nieuwe groep deel te nemen.}=1{Je kunt je groep op elk moment resetten. Het duurt ongeveer 1 dag om aan een nieuwe groep deel te nemen.}other{Je kunt je groep op elk moment resetten. Het duurt {NUM_DAYS} dagen om aan een nieuwe groep deel te nemen.}}</translation>
-<translation id="3596012367874587041">App-instellingen</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">App geblokkeerd door je beheerder</translation>
<translation id="3608932978122581043">Invoerrichting</translation>
@@ -852,6 +882,7 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="370972442370243704">Traject aanzetten</translation>
<translation id="3711895659073496551">Onderbreken</translation>
<translation id="3712624925041724820">Licenties zijn verbruikt</translation>
+<translation id="3714633008798122362">online agenda</translation>
<translation id="3714780639079136834">Zet je mobiele data of wifi aan</translation>
<translation id="3715597595485130451">Verbinding maken met wifi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Controleer de proxy, firewall en DNS-configuratie<ph name="END_LINK" /></translation>
@@ -913,6 +944,7 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="3906954721959377182">Tablet</translation>
<translation id="3909477809443608991"><ph name="URL" /> wil beschermde content afspelen. De identiteit van je apparaat wordt geverifieerd door Google en is mogelijk toegankelijk voor deze site.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">Weigeren</translation>
<translation id="3939773374150895049">WebAuthn gebruiken in plaats van CVC?</translation>
<translation id="3946209740501886391">Altijd vragen op deze site</translation>
<translation id="3947595700203588284">Kan vragen of deze site verbinding mag maken met MIDI-apparaten</translation>
@@ -934,6 +966,7 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="3990250421422698716">Sorteren</translation>
<translation id="3996311196211510766">De site <ph name="ORIGIN" /> heeft gevraagd een herkomstbeleid
toe te passen op alle verzoeken aan de site, maar dit beleid kan momenteel niet worden toegepast.</translation>
+<translation id="4009243425692662128">De content van pagina's die je afdrukt, wordt naar Google Cloud of derden gestuurd voor analyse. De tekst kan bijvoorbeeld worden gescand op gevoelige gegevens of malware.</translation>
<translation id="4010758435855888356">Toegang tot opslag toestaan?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{Pdf-document met {COUNT} pagina}other{Pdf-document met {COUNT} pagina's}}</translation>
<translation id="4023431997072828269">Dit formulier wordt ingediend via een verbinding die niet beveiligd is. Hierdoor zijn je gegevens zichtbaar voor anderen.</translation>
@@ -1028,6 +1061,7 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="4250680216510889253">Nee</translation>
<translation id="4253168017788158739">Opmerking</translation>
<translation id="425582637250725228">Wijzigingen die je hebt aangebracht, worden mogelijk niet opgeslagen.</translation>
+<translation id="425869179292622354">Wil je deze kaart beter beveiligen met een virtuele kaart?</translation>
<translation id="4258748452823770588">Onjuiste handtekening</translation>
<translation id="4261046003697461417">Er kunnen geen aantekeningen worden gemaakt in beveiligde documenten</translation>
<translation id="4265872034478892965">Toegestaan door je beheerder</translation>
@@ -1090,6 +1124,7 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="4434045419905280838">Pop-ups en omleidingen</translation>
<translation id="4435702339979719576">Briefkaart</translation>
<translation id="443673843213245140">Er kan geen proxy worden gebruikt, maar er is wel een expliciete proxyconfiguratie opgegeven.</translation>
+<translation id="4441832193888514600">Genegeerd omdat het beleid alleen kan worden ingesteld als cloudgebruikersbeleid.</translation>
<translation id="4450893287417543264">Niet meer bekijken</translation>
<translation id="4451135742916150903">Kan vragen of deze site verbinding mag maken met HID-apparaten</translation>
<translation id="4452328064229197696">Het wachtwoord dat je net hebt gebruikt, is gevonden bij een gegevenslek. Google Wachtwoordmanager raadt je aan je opgeslagen wachtwoorden te checken om je accounts te beveiligen.</translation>
@@ -1145,6 +1180,7 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="4628948037717959914">Foto</translation>
<translation id="4631649115723685955">Cashback gekoppeld</translation>
<translation id="4636930964841734540">Info</translation>
+<translation id="4638670630777875591">Incognito in Chromium</translation>
<translation id="464342062220857295">Zoekfuncties</translation>
<translation id="4644670975240021822">Omgekeerde volgorde met de bedrukte zijde omlaag</translation>
<translation id="4646534391647090355">Breng me daar nu naartoe</translation>
@@ -1165,6 +1201,7 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="4708268264240856090">Je verbinding is onderbroken</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Windows Netwerkcontrole uitvoeren<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426">Wachtwoord voor <ph name="USERNAME" /></translation>
<translation id="4724144314178270921">Kan vragen of deze site tekst en afbeeldingen op je klembord mag bekijken</translation>
<translation id="4726672564094551039">Beleid opnieuw laden</translation>
<translation id="4728558894243024398">Platform</translation>
@@ -1186,6 +1223,7 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="4757993714154412917">Je hebt zojuist je wachtwoord opgegeven op een misleidende site. Chromium raadt je aan je opgeslagen wachtwoorden te checken om je accounts te beveiligen.</translation>
<translation id="4758311279753947758">Contactgegevens toevoegen</translation>
<translation id="4761104368405085019">Je microfoon gebruiken</translation>
+<translation id="4761869838909035636">Chrome-veiligheidscheck uitvoeren</translation>
<translation id="4764776831041365478"><ph name="URL" /> werkt even niet, of de pagina kan verhuisd zijn naar een nieuw webadres.</translation>
<translation id="4766713847338118463">Twee nietjes onder</translation>
<translation id="4771973620359291008">Er is een onbekende fout opgetreden.</translation>
@@ -1206,12 +1244,6 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="4819347708020428563">Annotaties bewerken in standaardweergave?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />, druk op Tab en daarna op Enter om snel een nieuwe Google-spreadsheet te maken</translation>
<translation id="4825507807291741242">Krachtig</translation>
-<translation id="4827402517081186284">Incognito maakt je niet onzichtbaar online:
-<ph name="BEGIN_LIST" />
-<ph name="LIST_ITEM" />Sites weten het als je ze bezoekt.<ph name="END_LIST_ITEM" />
-<ph name="LIST_ITEM" />Werkgevers of scholen kunnen browse-activiteit bijhouden.<ph name="END_LIST_ITEM" />
-<ph name="LIST_ITEM" />Internetproviders kunnen webverkeer monitoren.<ph name="END_LIST_ITEM" />
-<ph name="END_LIST" /></translation>
<translation id="483241715238664915">Waarschuwingen aanzetten</translation>
<translation id="4838327282952368871">Dromerig</translation>
<translation id="4840250757394056958">Je Chrome-geschiedenis bekijken</translation>
@@ -1223,12 +1255,12 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="4854362297993841467">Deze bezorgingsmethode is niet beschikbaar. Kies een andere methode.</translation>
<translation id="4854853140771946034">Snel een nieuwe notitie in Google Keep maken</translation>
<translation id="485902285759009870">Code verifiëren...</translation>
+<translation id="4866506163384898554">Druk op |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| om je cursor te tonen</translation>
<translation id="4876188919622883022">Vereenvoudigde weergave</translation>
<translation id="4876305945144899064">Geen gebruikersnaam</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{Geen}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831"><ph name="TEXT" /> zoeken</translation>
<translation id="4879491255372875719">Automatisch (standaard)</translation>
-<translation id="4879725228911483934">Vensters openen en plaatsen op je schermen</translation>
<translation id="4880827082731008257">Geschiedenis doorzoeken</translation>
<translation id="4881695831933465202">Openen</translation>
<translation id="4885256590493466218">Bij het afrekenen betalen met <ph name="CARD_DETAIL" /></translation>
@@ -1237,6 +1269,7 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">9e rol</translation>
<translation id="4901778704868714008">Opslaan…</translation>
+<translation id="4905659621780993806">Je beheerder start het apparaat op <ph name="DATE" /> om <ph name="TIME" /> automatisch opnieuw op. Sla alle geopende items op voordat je apparaat opnieuw wordt opgestart.</translation>
<translation id="4913987521957242411">Perforatie linksboven</translation>
<translation id="4918221908152712722"><ph name="APP_NAME" /> installeren (geen download vereist)</translation>
<translation id="4923459931733593730">Betaling</translation>
@@ -1245,6 +1278,7 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, druk op 'Tab' en vervolgens op 'Enter' om te zoeken</translation>
<translation id="4930153903256238152">Hoge capaciteit</translation>
+<translation id="4940163644868678279">Incognito in Chrome</translation>
<translation id="4943872375798546930">Geen resultaten</translation>
<translation id="4950898438188848926">Schakelknop voor tabbladen, druk op Enter om naar het geopende tabblad, <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" />, te schakelen</translation>
<translation id="495170559598752135">Acties</translation>
@@ -1254,6 +1288,7 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="4968522289500246572">Deze app is ontworpen voor mobiel en het formaat wordt misschien niet goed aangepast. De app kan problemen ondervinden of opnieuw opstarten.</translation>
<translation id="4969341057194253438">Opname verwijderen</translation>
<translation id="4973922308112707173">Twee perforaties boven</translation>
+<translation id="4976702386844183910">Laatst bezocht: <ph name="DATE" /></translation>
<translation id="4984088539114770594">Microfoon gebruiken?</translation>
<translation id="4984339528288761049">Prc5 (envelop)</translation>
<translation id="4989163558385430922">Alles bekijken</translation>
@@ -1315,6 +1350,7 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="5138227688689900538">Minder bekijken</translation>
<translation id="5145883236150621069">Foutcode aanwezig in de beleidsreactie</translation>
<translation id="5146995429444047494">Meldingen voor <ph name="ORIGIN" /> zijn geblokkeerd</translation>
+<translation id="514704532284964975"><ph name="URL" /> wil informatie zien en wijzigen op NFC-apparaten waarop je met je telefoon tikt</translation>
<translation id="5148809049217731050">Met de bedrukte zijde omhoog</translation>
<translation id="515292512908731282">C4 (envelop)</translation>
<translation id="5158275234811857234">Omslag</translation>
@@ -1339,6 +1375,7 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="5215116848420601511">Betaalmethoden en adressen die Google Pay gebruiken</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">Lade 13</translation>
+<translation id="5216942107514965959">Laatst bezocht: vandaag</translation>
<translation id="5222812217790122047">E-mailadres vereist</translation>
<translation id="5230733896359313003">Verzendadres</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1359,7 +1396,6 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">Documenteigenschappen</translation>
<translation id="528468243742722775">Beëindigen</translation>
-<translation id="5284909709419567258">Netwerkadressen</translation>
<translation id="5285570108065881030">Alle opgeslagen wachtwoorden bekijken</translation>
<translation id="5287240709317226393">Cookies bekijken</translation>
<translation id="5287456746628258573">Deze site gebruikt een verouderde beveiligingsconfiguratie, waardoor je gegevens (zoals wachtwoorden of creditcardnummers) openbaar kunnen worden gemaakt als ze naar deze site worden gestuurd.</translation>
@@ -1443,6 +1479,7 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="5556459405103347317">Opnieuw laden</translation>
<translation id="5560088892362098740">Vervaldatum</translation>
<translation id="55635442646131152">Documentoverzicht</translation>
+<translation id="5565613213060953222">Incognitotabblad openen</translation>
<translation id="5565735124758917034">Actief</translation>
<translation id="5570825185877910964">Account beschermen</translation>
<translation id="5571083550517324815">Kan niet ophalen van dit adres. Selecteer een ander adres.</translation>
@@ -1525,6 +1562,7 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="5869522115854928033">Opgeslagen wachtwoorden</translation>
<translation id="5873013647450402046">Je bank wil bevestigen dat jij het bent.</translation>
<translation id="5887400589839399685">Pas opgeslagen</translation>
+<translation id="5887687176710214216">Laatst bezocht: gisteren</translation>
<translation id="5895138241574237353">Opnieuw starten</translation>
<translation id="5895187275912066135">Verleend op</translation>
<translation id="5901630391730855834">Geel</translation>
@@ -1538,6 +1576,7 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="5921639886840618607">Pas opslaan in Google-account?</translation>
<translation id="5922853866070715753">Bijna klaar</translation>
<translation id="5932224571077948991">Site toont opdringerige of misleidende advertenties</translation>
+<translation id="5938153366081463283">Virtuele kaart toevoegen</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347"><ph name="SITE_NAME" /> openen…</translation>
<translation id="5951495562196540101">Kan consumentenaccount niet inschrijven (verpakte licentie beschikbaar).</translation>
@@ -1602,6 +1641,7 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="6120179357481664955">Weet je je UPI-ID nog?</translation>
<translation id="6124432979022149706">Chrome Enterprise-connectors</translation>
<translation id="6127379762771434464">Item verwijderd</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Meer informatie over incognito in Chrome<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">Controleer alle kabels en start alle routers, modems of andere netwerkapparaten die je gebruikt, opnieuw op.</translation>
<translation id="614940544461990577">Probeer dit eens:</translation>
<translation id="6150036310511284407">Drie perforaties links</translation>
@@ -1613,7 +1653,6 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="6169916984152623906">Je kunt nu privé browsen, zodat andere mensen die dit apparaat gebruiken, jouw activiteit niet kunnen zien. Downloads en bookmarks worden echter wel opgeslagen.</translation>
<translation id="6177128806592000436">Je verbinding met deze site is niet beveiligd</translation>
<translation id="6180316780098470077">Interval voor nieuwe poging</translation>
-<translation id="619448280891863779">Kan vragen of deze site vensters op je schermen mag openen en plaatsen</translation>
<translation id="6196640612572343990">Cookies van derden blokkeren</translation>
<translation id="6203231073485539293">Controleer je internetverbinding</translation>
<translation id="6218753634732582820">Adres verwijderen uit Chromium?</translation>
@@ -1636,7 +1675,7 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="6272383483618007430">Google Update</translation>
<translation id="6276112860590028508">Pagina's uit je leeslijst zie je hier</translation>
<translation id="627746635834430766">Sla je pas en factuuradres op in je Google-account zodat je de volgende keer sneller kunt betalen.</translation>
-<translation id="6279098320682980337">Virtueel kaartnummer niet ingevuld? Klik op kaartgegevens om ze te kopiëren.</translation>
+<translation id="6279183038361895380">Druk op |<ph name="ACCELERATOR" />| om je cursor te bekijken</translation>
<translation id="6280223929691119688">Kan niet bezorgen op dit adres. Selecteer een ander adres.</translation>
<translation id="6282194474023008486">Postcode</translation>
<translation id="6285507000506177184">De knop Downloads in Chrome beheren, druk op Enter om bestanden te beheren die je hebt gedownload in Chrome</translation>
@@ -1644,6 +1683,7 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="6290238015253830360">Je voorgestelde artikelen zie je hier</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{Je apparaat wordt nu opnieuw opgestart}=1{Je apparaat wordt over 1 seconde opnieuw opgestart}other{Je apparaat wordt over # seconden opnieuw opgestart}}</translation>
<translation id="6302269476990306341">De Google Assistent in Chrome wordt gestopt</translation>
<translation id="6305205051461490394"><ph name="URL" /> is niet bereikbaar.</translation>
<translation id="6312113039770857350">Webpagina niet beschikbaar</translation>
@@ -1717,6 +1757,7 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="6529602333819889595">&amp;Opnieuw verwijderen</translation>
<translation id="6545864417968258051">Bluetooth-scannen</translation>
<translation id="6547208576736763147">Twee perforaties links</translation>
+<translation id="6554732001434021288">Laatst bezocht: <ph name="NUM_DAYS" /> dagen geleden</translation>
<translation id="6556866813142980365">Opnieuw</translation>
<translation id="6569060085658103619">Je bekijkt een extensiepagina</translation>
<translation id="6573200754375280815">Twee perforaties rechts</translation>
@@ -1777,7 +1818,6 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="6757797048963528358">De slaapstand van je apparaat is geactiveerd.</translation>
<translation id="6767985426384634228">Adres updaten?</translation>
<translation id="6768213884286397650">Hagaki (briefkaart)</translation>
-<translation id="6774185088257932239"><ph name="BEGIN_LINK" />Meer informatie<ph name="END_LINK" /> over incognito</translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">Violet</translation>
<translation id="6786747875388722282">Extensies</translation>
@@ -1861,7 +1901,6 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="706295145388601875">Adressen toevoegen en beheren in de Chrome-instellingen</translation>
<translation id="7064851114919012435">Contactgegevens</translation>
<translation id="7068733155164172741">Geef de <ph name="OTP_LENGTH" />-cijferige code op</translation>
-<translation id="7070090581017165256">Over deze site</translation>
<translation id="70705239631109039">Je verbinding is niet volledig beveiligd</translation>
<translation id="7075452647191940183">Verzoek is te groot</translation>
<translation id="7079718277001814089">Deze site bevat malware</translation>
@@ -1878,6 +1917,12 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="7111012039238467737">(Geldig)</translation>
<translation id="7118618213916969306">Zoeken naar klembord-URL, <ph name="SHORT_URL" /></translation>
<translation id="7119414471315195487">Andere tabbladen of programma's sluiten</translation>
+<translation id="7129355289156517987">Als je alle Chromium-incognitotabbladen sluit, wordt je activiteit op die tabbladen van dit apparaat gewist:
+<ph name="BEGIN_LIST" />
+<ph name="LIST_ITEM" />Browse-activiteit<ph name="END_LIST_ITEM" />
+<ph name="LIST_ITEM" />Zoekgeschiedenis<ph name="END_LIST_ITEM" />
+<ph name="LIST_ITEM" />Informatie die je in formulieren hebt opgegeven<ph name="END_LIST_ITEM" />
+<ph name="END_LIST" /></translation>
<translation id="7129409597930077180">Kan niet verzenden naar dit adres. Selecteer een ander adres.</translation>
<translation id="7132939140423847331">Je beheerder heeft voorkomen dat deze gegevens worden gekopieerd.</translation>
<translation id="7135130955892390533">Status bekijken</translation>
@@ -1900,6 +1945,7 @@ Anders wordt dit geblokkeerd door je privacyinstellingen. Hierdoor werkt de cont
<translation id="7192203810768312527">Hiermee wordt <ph name="SIZE" /> vrijgemaakt. Sommige sites kunnen langzamer worden geladen wanneer je ze weer bezoekt.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">De beheerder kan het volgende zien:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />. Druk op Tab en daarna op Enter om een nieuw incognitotabblad te openen om privé te browsen.</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> voldoet niet aan de beveiligingsnormen.</translation>
<translation id="7210993021468939304">Linux-activiteit in de container, en kan Linux-apps in de container installeren en uitvoeren</translation>
@@ -1931,6 +1977,7 @@ Aanvullende informatie:
<translation id="7304562222803846232">Beheer de privacyinstellingen van je Google-account</translation>
<translation id="7305756307268530424">Langzamer starten</translation>
<translation id="7308436126008021607">synchronisatie op de achtergrond</translation>
+<translation id="7310392214323165548">Het apparaat wordt zeer binnenkort opnieuw opgestart</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">Hulp bij verbinding maken</translation>
<translation id="7323804146520582233">Het gedeelte '<ph name="SECTION" />' verbergen</translation>
@@ -1938,6 +1985,7 @@ Aanvullende informatie:
<translation id="7334320624316649418">&amp;Opnieuw volgorde wijzigen</translation>
<translation id="7335157162773372339">Kan vragen of deze site je camera mag gebruiken</translation>
<translation id="7337248890521463931">Meer regels bekijken</translation>
+<translation id="7337418456231055214">Virtueel kaartnummer niet ingevuld? Klik op de kaartgegevens om ze te kopiëren. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">Niet beschikbaar op je platform.</translation>
<translation id="733923710415886693">Het certificaat van de server is niet bekendgemaakt via Certificaattransparantie.</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1960,6 +2008,7 @@ Aanvullende informatie:
<translation id="7378627244592794276">Nee</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">Niet van toepassing</translation>
+<translation id="7388594495505979117">{0,plural, =1{Je apparaat wordt over 1 minuut opnieuw opgestart}other{Je apparaat wordt over # minuten opnieuw opgestart}}</translation>
<translation id="7390545607259442187">Creditcard bevestigen</translation>
<translation id="7392089738299859607">Adres updaten</translation>
<translation id="7399802613464275309">Veiligheidscheck</translation>
@@ -1996,6 +2045,12 @@ Aanvullende informatie:
<translation id="7485870689360869515">Geen gegevens gevonden.</translation>
<translation id="7495528107193238112">Deze content is geblokkeerd. Neem contact op met de site-eigenaar om het probleem op te lossen.</translation>
<translation id="7497998058912824456">Knop Document maken, druk op Enter om snel een nieuw Google-document te maken</translation>
+<translation id="7506488012654002225">De volgende gegevens worden <ph name="BEGIN_EMPHASIS" />niet opgeslagen<ph name="END_EMPHASIS" /> in Chromium:
+<ph name="BEGIN_LIST" />
+<ph name="LIST_ITEM" />Je browsegeschiedenis
+<ph name="LIST_ITEM" />Cookies en sitegegevens
+<ph name="LIST_ITEM" />Informatie die je in formulieren hebt opgegeven
+<ph name="END_LIST" /></translation>
<translation id="7508255263130623398">Geretourneerde apparaat-ID voor beleid is leeg of komt niet overeen met de huidige apparaat-ID</translation>
<translation id="7508870219247277067">Avocadogroen</translation>
<translation id="7511955381719512146">Het is mogelijk dat je <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> moet bezoeken van het wifi-netwerk dat je gebruikt.</translation>
@@ -2109,7 +2164,6 @@ Aanvullende informatie:
<translation id="7813600968533626083">Formuliersuggestie verwijderen uit Chrome?</translation>
<translation id="781440967107097262">Klembord delen?</translation>
<translation id="7815407501681723534"><ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> gevonden voor '<ph name="SEARCH_STRING" />'</translation>
-<translation id="782125616001965242">Informatie over deze site bekijken</translation>
<translation id="782886543891417279">Het is mogelijk dat je de inlogpagina moet bezoeken van het wifi-netwerk (<ph name="WIFI_NAME" />) dat je gebruikt.</translation>
<translation id="7836231406687464395">Postfix (envelop)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{Geen}=1{1 app (<ph name="EXAMPLE_APP_1" />)}=2{2 apps (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}other{# apps (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}}</translation>
@@ -2126,7 +2180,6 @@ Aanvullende informatie:
<translation id="7888575728750733395">Weergave-intentie voor afdrukken</translation>
<translation id="7894280532028510793">Als de spelling klopt, <ph name="BEGIN_LINK" />voer je een netwerkcontrole uit<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (envelop)</translation>
-<translation id="7931318309563332511">Onbekend</translation>
<translation id="793209273132572360">Adres updaten?</translation>
<translation id="7932579305932748336">Coaten</translation>
<translation id="79338296614623784">Geef een geldig telefoonnummer op</translation>
@@ -2151,13 +2204,14 @@ Aanvullende informatie:
<translation id="7976214039405368314">Te veel verzoeken</translation>
<translation id="7977538094055660992">Uitvoerapparaat</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">Gekoppeld aan</translation>
<translation id="798134797138789862">Kan vragen of deze site virtualreality-apparaten en -gegevens mag gebruiken</translation>
<translation id="7984945080620862648">Je kunt <ph name="SITE" /> op dit moment niet bezoeken, omdat de website gecodeerde verificatiegegevens heeft verzonden die niet door Chrome kunnen worden verwerkt. Netwerkfouten en aanvallen zijn doorgaans tijdelijk, dus deze pagina werkt later waarschijnlijk correct.</translation>
-<translation id="79859296434321399">Installeer ARCore om augmented reality-content te bekijken</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">Inbinden</translation>
<translation id="7992044431894087211">Scherm delen met <ph name="APPLICATION_TITLE" /> is hervat</translation>
<translation id="7995512525968007366">Niet opgegeven</translation>
+<translation id="7998269595945679889">Knop Incognitotabblad openen. Druk op Enter om een nieuw incognitotabblad te openen om privé te browsen.</translation>
<translation id="800218591365569300">Probeer andere tabbladen en programma's te sluiten om geheugen vrij te maken.</translation>
<translation id="8004582292198964060">Browser</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{Deze pas en het bijbehorende factuuradres worden opgeslagen. Je kunt deze gegevens gebruiken wanneer je bent ingelogd op <ph name="USER_EMAIL" />.}other{Deze passen en de bijbehorende factuuradressen worden opgeslagen. Je kunt deze gegevens gebruiken wanneer je bent ingelogd op <ph name="USER_EMAIL" />.}}</translation>
@@ -2217,6 +2271,7 @@ Aanvullende informatie:
<translation id="8202370299023114387">Conflict</translation>
<translation id="8206978196348664717">Prc4 (envelop)</translation>
<translation id="8211406090763984747">Verbinding is beveiligd</translation>
+<translation id="8217240300496046857">Sites kunnen geen cookies gebruiken die je volgen op internet. Functies op bepaalde sites werken mogelijk niet meer.</translation>
<translation id="8218327578424803826">Toegewezen locatie:</translation>
<translation id="8220146938470311105">C7/C6 (envelop)</translation>
<translation id="8225771182978767009">De persoon die deze computer heeft geconfigureerd, heeft deze site geblokkeerd.</translation>
@@ -2257,14 +2312,9 @@ Aanvullende informatie:
<translation id="830498451218851433">Enkele vouw</translation>
<translation id="8307358339886459768">Kleine foto</translation>
<translation id="8307888238279532626">Geïnstalleerde apps en hoe vaak ze zijn gebruikt</translation>
+<translation id="8317207217658302555">ARCore updaten?</translation>
<translation id="831997045666694187">Avond</translation>
<translation id="8321476692217554900">meldingen</translation>
-<translation id="8328484624016508118">Nadat je alle incognitotabbladen hebt gesloten, wist Chrome deze gegevens:
-<ph name="BEGIN_LIST" />
-<ph name="LIST_ITEM" />Je browse-activiteit vanaf dit apparaat.<ph name="END_LIST_ITEM" />
-<ph name="LIST_ITEM" />Je zoekgeschiedenis vanaf dit apparaat.<ph name="END_LIST_ITEM" />
-<ph name="LIST_ITEM" />Informatie die je in formulieren hebt ingevuld.<ph name="END_LIST_ITEM" />
-<ph name="END_LIST" /></translation>
<translation id="8332188693563227489">Toegang tot <ph name="HOST_NAME" /> is geweigerd</translation>
<translation id="833262891116910667">Markeren</translation>
<translation id="8339163506404995330">Pagina's in het <ph name="LANGUAGE" /> worden niet vertaald</translation>
@@ -2316,6 +2366,7 @@ Aanvullende informatie:
<translation id="8507227106804027148">Opdrachtregel</translation>
<translation id="8508648098325802031">Zoekpictogram</translation>
<translation id="8511402995811232419">Cookies beheren</translation>
+<translation id="8519753333133776369">HID-apparaat toegestaan door je beheerder</translation>
<translation id="8522552481199248698">Chrome kan je helpen je Google-account te beschermen en je wachtwoord te wijzigen.</translation>
<translation id="8530813470445476232">Je browsegeschiedenis, cookies, cache en meer wissen in de Chrome-instellingen</translation>
<translation id="8533619373899488139">Ga naar &lt;strong&gt;chrome://policy&lt;/strong&gt; om de lijst met geblokkeerde URL's en andere beleidsregels te bekijken die worden afgedwongen door je systeembeheerder.</translation>
@@ -2327,7 +2378,6 @@ Aanvullende informatie:
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{Recht resetten}other{Rechten resetten}}</translation>
<translation id="8555010941760982128">Gebruik deze code bij het betalen</translation>
<translation id="8557066899867184262">De CVC-code staat op de achterkant van je pas.</translation>
-<translation id="8558485628462305855">Update ARCore om augmented reality-content te bekijken</translation>
<translation id="8559762987265718583">Er kan geen privéverbinding met <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> tot stand worden gebracht, omdat de datum en tijd van je apparaat (<ph name="DATE_AND_TIME" />) onjuist zijn.</translation>
<translation id="8564182942834072828">Afzonderlijke documenten/ongesorteerde exemplaren</translation>
<translation id="8564985650692024650">Chromium raadt je aan het wachtwoord voor <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> opnieuw in te stellen als je het voor andere sites hebt hergebruikt.</translation>
@@ -2346,6 +2396,7 @@ Aanvullende informatie:
<translation id="865032292777205197">bewegingssensoren</translation>
<translation id="8663226718884576429">Besteloverzicht, <ph name="TOTAL_LABEL" />, meer informatie</translation>
<translation id="8666678546361132282">Engels</translation>
+<translation id="8669306706049782872">Informatie over je schermen gebruiken om vensters te openen en te plaatsen</translation>
<translation id="867224526087042813">Handtekening</translation>
<translation id="8676424191133491403">Geen vertraging</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, antwoord, <ph name="ANSWER" /></translation>
@@ -2372,6 +2423,7 @@ Aanvullende informatie:
<translation id="8731544501227493793">Knop 'Wachtwoorden beheren'. Druk op Enter om je wachtwoorden te bekijken en te beheren in de Chrome-instellingen.</translation>
<translation id="8734529307927223492">Je <ph name="DEVICE_TYPE" /> wordt beheerd door <ph name="MANAGER" /></translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />. Druk op Tab en vervolgens op Enter om een nieuw incognitovenster te openen om privé te browsen.</translation>
+<translation id="8737685506611670901">Links voor <ph name="PROTOCOL" /> openen in plaats van <ph name="REPLACED_HANDLER_TITLE" /></translation>
<translation id="8738058698779197622">Als je een beveiligde verbinding tot stand wilt brengen, moet je klok goed zijn ingesteld. Dit moet omdat de certificaten die deze websites gebruiken om zichzelf te identificeren, slechts gedurende bepaalde perioden geldig zijn. Aangezien de klok van je apparaat niet goed is ingesteld, kan Chromium deze certificaten niet verifiëren.</translation>
<translation id="8740359287975076522">Het &lt;abbr id="dnsDefinition"&gt;DNS-adres&lt;/abbr&gt; van <ph name="HOST_NAME" /> kan niet worden gevonden. Er wordt een diagnose van het probleem uitgevoerd.</translation>
<translation id="8742371904523228557">Je code voor <ph name="ORIGIN" /> is<ph name="ONE_TIME_CODE" />.</translation>
@@ -2399,6 +2451,7 @@ Aanvullende informatie:
<translation id="883848425547221593">Andere bookmarks</translation>
<translation id="884264119367021077">Verzendadres</translation>
<translation id="884923133447025588">Geen intrekkingsmechanisme gevonden.</translation>
+<translation id="8849262850971482943">Gebruik je virtuele kaart voor extra beveiliging</translation>
<translation id="885730110891505394">Delen met Google</translation>
<translation id="8858065207712248076">Chrome raadt je aan het wachtwoord voor <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> opnieuw in te stellen als je het voor andere sites hebt hergebruikt.</translation>
<translation id="885906927438988819">Als de spelling klopt, <ph name="BEGIN_LINK" />voer je een Windows-netwerkcontrole uit<ph name="END_LINK" />.</translation>
@@ -2448,6 +2501,7 @@ Aanvullende informatie:
<translation id="9004367719664099443">VR-sessie is bezig</translation>
<translation id="9005998258318286617">Kan pdf-document niet laden</translation>
<translation id="9008201768610948239">Negeren</translation>
+<translation id="901834265349196618">e-mail</translation>
<translation id="9020200922353704812">Factuuradres voor creditcard vereist</translation>
<translation id="9020542370529661692">Deze pagina is vertaald naar het <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9020742383383852663">A8</translation>
@@ -2496,6 +2550,7 @@ Aanvullende informatie:
<translation id="9150045010208374699">Je camera gebruiken</translation>
<translation id="9150685862434908345">Je beheerder kan je browserinstellingen op afstand wijzigen. Activiteit op dit apparaat kan ook buiten Chrome worden beheerd. <ph name="BEGIN_LINK" />Meer informatie<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">Bijgewerkt</translation>
+<translation id="9155211586651734179">Aangesloten audiorandapparaten</translation>
<translation id="9157595877708044936">Bezig met instellen...</translation>
<translation id="9158625974267017556">C6 (envelop)</translation>
<translation id="9164029392738894042">Nauwkeurigheidscheck</translation>
diff --git a/chromium/components/strings/components_strings_no.xtb b/chromium/components/strings/components_strings_no.xtb
index 921ed474932..5090e338dda 100644
--- a/chromium/components/strings/components_strings_no.xtb
+++ b/chromium/components/strings/components_strings_no.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">Se detaljer</translation>
<translation id="1030706264415084469"><ph name="URL" /> ber om å lagre store datamengder permanent på enheten din</translation>
<translation id="1032854598605920125">Rotér med klokken</translation>
+<translation id="1033329911862281889">Inkognito gjør deg ikke usynlig på nettet:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Nettsteder og tjenestene de bruker, kan se når du besøker dem<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Arbeidsgivere og skoler kan spore nettleseraktivitet<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Internettleverandører kan overvåke nettrafikk<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">Slå av</translation>
<translation id="1036982837258183574">Trykk på |<ph name="ACCELERATOR" />| for å avslutte fullskjerm</translation>
<translation id="1038106730571050514">Vis forslag</translation>
<translation id="1038842779957582377">ukjent navn</translation>
<translation id="1041998700806130099">Jobbarkmelding</translation>
<translation id="1048785276086539861">Når du redigerer annoteringer, går dette dokumentet tilbake til enkeltsidevisning</translation>
-<translation id="1049743911850919806">Inkognito</translation>
<translation id="1050038467049342496">Lukk andre apper</translation>
<translation id="1055184225775184556">&amp;Angre tilleggingen</translation>
<translation id="1056898198331236512">Advarsel</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">Bufferen for enhetsinnstillinger er OK</translation>
<translation id="1130564665089811311">Knappen «Oversett siden» – trykk på Enter for å oversette denne siden med Google Oversetter</translation>
<translation id="1131264053432022307">Bildet du kopierte</translation>
+<translation id="1142846828089312304">Blokkér informasjonskapsler fra tredjepart i inkognitomodus</translation>
<translation id="1150979032973867961">Denne tjeneren kunne ikke bevise at den er <ph name="DOMAIN" />. Sikkerhetssertifikatet til tjeneren er ikke klarert av datamaskinens operativsystem. Dette kan være forårsaket av en feilkonfigurering eller en angriper som avskjærer tilkoblingen din.</translation>
<translation id="1151972924205500581">Passord er påkrevd</translation>
<translation id="1156303062776767266">Du ser en lokal eller delt fil</translation>
@@ -64,7 +70,6 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="1178581264944972037">Stans midlertidig</translation>
<translation id="1181037720776840403">Fjern</translation>
<translation id="1186201132766001848">Kontrollér passordene</translation>
-<translation id="1195210374336998651">GÃ¥ til appinnstillinger</translation>
<translation id="1195558154361252544">Varsler blokkeres automatisk for alle nettsteder unntatt dem du tillater</translation>
<translation id="1197088940767939838">Oransje</translation>
<translation id="1201402288615127009">Neste</translation>
@@ -111,7 +116,7 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="1307966114820526988">Avviklede funksjoner</translation>
<translation id="1308113895091915999">Et tilbud er tilgjengelig</translation>
<translation id="1312803275555673949">Hvilke beviser finnes?</translation>
-<translation id="131405271941274527"><ph name="URL" /> vil sende og motta info når du berører NFC-enheter med telefonen</translation>
+<translation id="1314311879718644478">Se utvidet virkelighet-innhold</translation>
<translation id="1314509827145471431">Innbinding høyre</translation>
<translation id="1318023360584041678">Lagret i fanegruppe</translation>
<translation id="1319245136674974084">Ikke spør igjen for denne appen</translation>
@@ -161,6 +166,7 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="142858679511221695">Skybruker</translation>
<translation id="1428729058023778569">Du ser denne advarselen fordi dette nettstedet ikke støtter HTTPS. <ph name="BEGIN_LEARN_MORE_LINK" />Finn ut mer<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">Skriv ut</translation>
+<translation id="1432187715652018471">siden vil installere en tjenestebehandler</translation>
<translation id="1432581352905426595">Administrer søkemotorer</translation>
<translation id="1436185428532214179">Kan be om å få redigere filer og mapper på enheten</translation>
<translation id="1442386063175183758">Høyre vindusfals</translation>
@@ -181,6 +187,12 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="1483493594462132177">Send</translation>
<translation id="1484290072879560759">Velg leveringsadresse</translation>
<translation id="1492194039220927094">Push-levering av regler:</translation>
+<translation id="149293076951187737">Når du lukker alle inkognitofaner i Chrome, blir aktiviteten din på de aktuelle fanene fjernet fra enheten:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Nettleseraktivitet<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Søkelogg<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Informasjon du har lagt inn i skjemaer<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">Tilbake til fanen</translation>
<translation id="1501859676467574491">Vis kredittkort fra Google-kontoen din</translation>
<translation id="1507202001669085618">&lt;p&gt;Du ser denne feilmeldingen hvis du bruker en Wi-Fi-portal hvor du må logge på før du kommer deg på nettet.&lt;/p&gt;
@@ -208,6 +220,8 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="1559572115229829303">&lt;p&gt;Vi kan ikke opprette noen privat tilkobling til <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />, fordi datoen og klokkeslettet (<ph name="DATE_AND_TIME" />) på enheten din er feil.&lt;/p&gt;
&lt;p&gt;Juster datoen og klokkeslettet under &lt;strong&gt;Generelt&lt;/strong&gt; i &lt;strong&gt;Innstillinger&lt;/strong&gt;-appen.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">Administratoren din starter enheten din på nytt kl. <ph name="TIME" /> <ph name="DATE" /></translation>
+<translation id="156703335097561114">Nettverksinformasjon som adresser, grensesnittkonfigurasjon og tilkoblingskvalitet</translation>
<translation id="1567040042588613346">Denne regelen fungerer som den skal, men den samme verdien er angitt et annet sted og overstyres av denne regelen.</translation>
<translation id="1569487616857761740">Oppgi utløpsdato</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="1583429793053364125">Noe gikk galt da denne nettsiden skulle åpnes.</translation>
<translation id="1586541204584340881">hvilke utvidelser du har installert</translation>
<translation id="1588438908519853928">Normal</translation>
+<translation id="1589050138437146318">Vil du installere ARCore?</translation>
<translation id="1592005682883173041">Tilgang til lokale data</translation>
<translation id="1594030484168838125">Velg</translation>
<translation id="160851722280695521">Spill Dino Run-spillet i Chrome</translation>
@@ -283,6 +298,7 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
headeren har feil format, og dette forhindrer nettleseren fra å effektuere
forespørselen din til <ph name="SITE" />. Nettstedsoperatører kan bruke
opphavsregler til å konfigurere sikkerhet og andre egenskaper for nettsteder.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Finn ut mer om Inkognito i Chromium<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">De åpne fanene dine vises her</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -410,6 +426,7 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="22081806969704220">Skuff 3</translation>
<translation id="2212735316055980242">Innstillingene ble ikke funnet</translation>
<translation id="2213606439339815911">Henter oppføringer …</translation>
+<translation id="2213612003795704869">Siden er skrevet ut</translation>
<translation id="2215727959747642672">Filredigering</translation>
<translation id="2218879909401188352">Angripere som er på <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />, kan installere farlige apper som skader enheten din, legge til skjulte belastninger på mobilregningen din eller stjele personopplysningene dine. <ph name="BEGIN_LEARN_MORE_LINK" />Finn ut mer<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">Ingen nettilkobling</translation>
@@ -419,6 +436,7 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="2248949050832152960">Bruk WebAuthn</translation>
<translation id="2250931979407627383">Kantstifting venstre</translation>
<translation id="225207911366869382">Denne verdien er foreldet for denne innstillingen.</translation>
+<translation id="2256115617011615191">Start på nytt nå</translation>
<translation id="2258928405015593961">Oppgi en fremtidig utløpsdato, og prøv på nytt</translation>
<translation id="225943865679747347">Feilkode: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">HTTP-feil</translation>
@@ -446,6 +464,7 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="2337852623177822836">Innstillingen kontrolleres av administratoren din</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> vil koble til</translation>
<translation id="2346319942568447007">Bildet du kopierte</translation>
+<translation id="2350796302381711542">Vil du la <ph name="HANDLER_HOSTNAME" /> åpne alle <ph name="PROTOCOL" />-linker i stedet for <ph name="REPLACED_HANDLER_TITLE" />?</translation>
<translation id="2354001756790975382">Andre bokmerker</translation>
<translation id="2354430244986887761">Google Safe Browsing har nylig <ph name="BEGIN_LINK" />funnet skadelige apper<ph name="END_LINK" /> på <ph name="SITE" />.</translation>
<translation id="2355395290879513365">Angripere kan kanskje se bildene du ser på dette nettstedet, og lure deg ved å endre dem.</translation>
@@ -471,6 +490,7 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="2413528052993050574">Denne tjeneren kunne ikke bevise at den er <ph name="DOMAIN" />. Tjenerens sikkerhetssertifikat kan være trukket tilbake. Dette kan være forårsaket av en feilkonfigurering eller en angriper som avskjærer tilkoblingen din.</translation>
<translation id="2414886740292270097">Mørk</translation>
<translation id="2430968933669123598">Administrer Google-konto – trykk på Enter for å administrere informasjon, personvern og sikkerhet i Google-kontoen din</translation>
+<translation id="2436186046335138073">Vil du la <ph name="HANDLER_HOSTNAME" /> åpne alle <ph name="PROTOCOL" />-linker?</translation>
<translation id="2438874542388153331">Fire hull høyre</translation>
<translation id="2450021089947420533">Reiser</translation>
<translation id="2463739503403862330">Fyll ut</translation>
@@ -478,6 +498,7 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="2465655957518002998">Velg leveringsmåte</translation>
<translation id="2465688316154986572">Stift</translation>
<translation id="2465914000209955735">Administrer filer du har lastet ned i Chrome</translation>
+<translation id="2466004615675155314">Vis informasjon fra nettet</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Kjør Nettverksdiagnose<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">1-til-N-rekkefølge</translation>
<translation id="2470767536994572628">Når du redigerer annoteringer, går dette dokumentet tilbake til enkeltsidevisning og den opprinnelige rotasjonen</translation>
@@ -498,6 +519,7 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="2523886232349826891">Kun lagret på denne enheten</translation>
<translation id="2524461107774643265">Legg til mer informasjon</translation>
<translation id="2529899080962247600">Dette feltet skal ikke ha mer enn <ph name="MAX_ITEMS_LIMIT" /> oppføringer. Eventuelle oppføringer som overskrider dette, ignoreres.</translation>
+<translation id="2535585790302968248">Åpne en ny inkognitofane for å surfe privat</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{og 1 til}other{og # til}}</translation>
<translation id="2536110899380797252">Legg til adresse</translation>
<translation id="2539524384386349900">Oppdag</translation>
@@ -523,7 +545,14 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="2597378329261239068">Dette dokumentet er passordbeskyttet. Skriv inn et passord.</translation>
<translation id="2609632851001447353">Varianter</translation>
<translation id="2610561535971892504">Klikk for å kopiere</translation>
+<translation id="2617988307566202237">Chrome <ph name="BEGIN_EMPHASIS" />lagrer ikke<ph name="END_EMPHASIS" /> følgende informasjon:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Nettleserloggen din
+ <ph name="LIST_ITEM" />Informasjonskapsler og nettstedsdata
+ <ph name="LIST_ITEM" />Informasjon du legger inn i skjemaer
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (konvolutt)</translation>
+<translation id="2623663032199728144">kan be om å få bruke informasjon om skjermene dine</translation>
<translation id="2625385379895617796">Klokken går for fort</translation>
<translation id="262745152991669301">Kan be om å få koble til USB-enheter</translation>
<translation id="2629325967560697240">For å få det høyeste sikkerhetsnivået som Chrome tilbyr, <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />slå på økt beskyttelse<ph name="END_ENHANCED_PROTECTION_LINK" />.</translation>
@@ -557,6 +586,7 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="2709516037105925701">Autofyll</translation>
<translation id="2713444072780614174">Hvit</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" /> – trykk på Tab og deretter på Enter for å administrere betalingene og kredittkortopplysningene dine i Chrome-innstillingene</translation>
+<translation id="271663710482723385">Trykk på |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| for å avslutte fullskjerm</translation>
<translation id="2721148159707890343">Forespørselen var vellykket</translation>
<translation id="2723669454293168317">Kjør en sikkerhetssjekk i Chrome-innstillingene</translation>
<translation id="2726001110728089263">Sideskuff</translation>
@@ -587,6 +617,7 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="2850739647070081192">Invite (konvolutt)</translation>
<translation id="2856444702002559011">Det kan hende at angripere prøver å stjele informasjonen din fra <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (for eksempel passord, meldinger og kredittkortinformasjon). <ph name="BEGIN_LEARN_MORE_LINK" />Finn ut mer<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">Dette nettstedet viser forstyrrende eller villedende annonser.</translation>
+<translation id="286512204874376891">Et virtuelt kort skjuler det faktiske kortet ditt for å beskytte deg mot potensiell svindel. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">Vennskapelig</translation>
<translation id="2876489322757410363">Går ut av Inkognitomodus for å betale via en ekstern app. Vil du fortsette?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" /> – trykk på Tab og deretter på Enter for å administrere Safe Browsing med mer i Chrome-innstillingene</translation>
@@ -611,6 +642,7 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="2930577230479659665">Beskjær etter hver kopi</translation>
<translation id="2932085390869194046">Foreslå passord</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019">Ã¥pne linker til <ph name="PROTOCOL" /></translation>
<translation id="2941952326391522266">Denne tjeneren kunne ikke bevise at den er <ph name="DOMAIN" />. Tjenerens sikkerhetssertifikat er fra <ph name="DOMAIN2" />. Dette kan være forårsaket av en feilkonfigurering eller en angriper som avskjærer tilkoblingen din.</translation>
<translation id="2943895734390379394">Opplastingstidspunkt:</translation>
<translation id="2948083400971632585">PÃ¥ innstillingssiden kan du deaktivere eventuelle proxy-tjenere for tilkoblinger.</translation>
@@ -643,6 +675,7 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="3037605927509011580">Æsj!</translation>
<translation id="3041612393474885105">Sertifikatinformasjon</translation>
<translation id="3044034790304486808">Fortsett undersøkelsene</translation>
+<translation id="305162504811187366">loggen for Chrome Eksternt skrivebord, inkludert tidsstempler, verter og klientøkt-ID-er</translation>
<translation id="3060227939791841287">C9 (konvolutt)</translation>
<translation id="3061707000357573562">Feilrettingstjeneste</translation>
<translation id="306573536155379004">Spillet er startet.</translation>
@@ -683,6 +716,7 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="3197136577151645743">Kan be om å få vite når du bruker denne enheten aktivt</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" /> – trykk på Tab og deretter på Enter for å administrere hvilken informasjon du synkroniserer, i Chrome-innstillingene</translation>
<translation id="320323717674993345">Avbryt betalingen</translation>
+<translation id="3203366800380907218">Fra nettet</translation>
<translation id="3207960819495026254">Bokmerket</translation>
<translation id="3209034400446768650">Siden kan belaste deg for penger</translation>
<translation id="3212581601480735796">Aktiviteten din på <ph name="HOSTNAME" /> overvåkes</translation>
@@ -699,10 +733,12 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="3234666976984236645">Oppdag alltid viktig innhold på dette nettstedet</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" /> – trykk på Tab og deretter på Enter for å tilpasse nettleserens utseende</translation>
<translation id="3240791268468473923">Ark for sikker betalingslegitimasjon uten samsvarende legitimasjon er åpnet</translation>
+<translation id="324180406144491771">«<ph name="HOST_NAME" />»-linker er blokkert</translation>
<translation id="3249845759089040423">Groovy</translation>
<translation id="3252266817569339921">Fransk</translation>
<translation id="3257954757204451555">Hvem står bak denne informasjonen?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" /> – trykk på Tab og deretter på Enter for å opprette en ny hendelse i Google Kalender raskt</translation>
+<translation id="3261488570342242926">Finn ut mer om virtuelle kort</translation>
<translation id="3264837738038045344">Knappen «Administrer Chrome-innstillinger» – trykk på Enter for å åpne Chrome-innstillingene</translation>
<translation id="3266793032086590337">Verdi (konflikt)</translation>
<translation id="3268451620468152448">Ã…pne faner</translation>
@@ -716,6 +752,7 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="3288238092761586174"><ph name="URL" /> må kanskje utføre flere trinn for å bekrefte betalingen din</translation>
<translation id="3293642807462928945">Finn ut mer om regelen <ph name="POLICY_NAME" /></translation>
<translation id="3295444047715739395">Se og administrer passordene dine i Chrome-innstillingene</translation>
+<translation id="3303795387212510132">Vil du la appen åpne <ph name="PROTOCOL_SCHEME" />-linker?</translation>
<translation id="3303855915957856445">Søket ga ingen treff</translation>
<translation id="3304073249511302126">Bluetooth-skanning</translation>
<translation id="3308006649705061278">Organisasjonsenhet (OU)</translation>
@@ -729,12 +766,6 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="3345782426586609320">Øyne</translation>
<translation id="3355823806454867987">Endre innstillinger for proxy-tjener</translation>
<translation id="3360103848165129075">Ark for betalingsbehandling</translation>
-<translation id="3361596688432910856">Chrome <ph name="BEGIN_EMPHASIS" />lagrer ikke<ph name="END_EMPHASIS" />
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />nettleserloggen din
- <ph name="LIST_ITEM" />informasjonskapsler og nettstedsdata
- <ph name="LIST_ITEM" />informasjon du skriver inn i skjemaer
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">Denne regelen ble automatisk kopiert fra den avviklede regelen <ph name="OLD_POLICY" />. Du bør bruke denne regelen i stedet.</translation>
<translation id="3364869320075768271"><ph name="URL" /> vil bruke virtuell virkelighet-enheten din og -dataene dine</translation>
<translation id="3366477098757335611">Vis kort</translation>
@@ -817,7 +848,6 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="3587738293690942763">Midtre</translation>
<translation id="3592413004129370115">Italian (konvolutt)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{Du kan tilbakestille gruppen din når som helst. Det tar omtrent én dag å bli med i en ny gruppe.}=1{Du kan tilbakestille gruppen din når som helst. Det tar omtrent én dag å bli med i en ny gruppe.}other{Du kan tilbakestille gruppen din når som helst. Det tar omtrent {NUM_DAYS} dager å bli med i en ny gruppe.}}</translation>
-<translation id="3596012367874587041">Appinnstillinger</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">Programmet er blokkert av administratoren din</translation>
<translation id="3608932978122581043">Feed-retning</translation>
@@ -860,6 +890,7 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="370972442370243704">Slå på reiser</translation>
<translation id="3711895659073496551">Suspender</translation>
<translation id="3712624925041724820">Lisensene er oppbrukt</translation>
+<translation id="3714633008798122362">nettkalender</translation>
<translation id="3714780639079136834">Slå på mobildata eller Wi-Fi</translation>
<translation id="3715597595485130451">Tilkobling til Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Sjekk proxy-tjener-, brannmur- og DNS-konfigurasjonen<ph name="END_LINK" /></translation>
@@ -921,6 +952,7 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="3906954721959377182">Nettbrett</translation>
<translation id="3909477809443608991"><ph name="URL" /> ber om tillatelse til å spille beskyttet innhold. Identiteten til enheten din bekreftes av Google og kan bli gjort tilgjengelig for dette nettstedet.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">Ikke tillat</translation>
<translation id="3939773374150895049">Vil du bruke WebAuthn i stedet for CVC?</translation>
<translation id="3946209740501886391">Spør alltid på dette nettstedet</translation>
<translation id="3947595700203588284">Kan be om å få koble til MIDI-enheter</translation>
@@ -942,6 +974,7 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="3990250421422698716">Støtforskyvning</translation>
<translation id="3996311196211510766">Nettstedet <ph name="ORIGIN" /> har bedt om at en opphavsregel
skal gjelde for alle forespørsler som sendes til det, men denne regelen kan ikke tas i bruk akkurat nå.</translation>
+<translation id="4009243425692662128">Innholdet på sidene du skriver ut, blir sendt til Google Cloud eller tredjeparter for analyse. Sidene kan for eksempel bli skannet for sensitive data.</translation>
<translation id="4010758435855888356">Vil du gi lagringstilgang?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{PDF-dokument som inneholder {COUNT} side}other{PDF-dokument som inneholder {COUNT} sider}}</translation>
<translation id="4023431997072828269">Siden dette skjemaet blir sendt over en tilkobling som ikke er sikker, kommer informasjonen din til å være synlig for andre.</translation>
@@ -1036,6 +1069,7 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="4250680216510889253">Nei</translation>
<translation id="4253168017788158739">Merknad</translation>
<translation id="425582637250725228">Det kan hende endringene dine ikke er lagret.</translation>
+<translation id="425869179292622354">Vil du gjøre det sikrere med et virtuelt kort?</translation>
<translation id="4258748452823770588">DÃ¥rlig signatur</translation>
<translation id="4261046003697461417">Beskyttede dokumenter kan ikke annoteres</translation>
<translation id="4265872034478892965">Tillatt av administratoren din</translation>
@@ -1098,6 +1132,7 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="4434045419905280838">Forgrunnsvinduer/viderekoblinger</translation>
<translation id="4435702339979719576">postkort)</translation>
<translation id="443673843213245140">Bruk av proxy-tjener er deaktivert, men det er angitt en uttrykkelig proxy-tjenerkonfigurasjon.</translation>
+<translation id="4441832193888514600">Ignorert fordi regelen kun kan angis som brukerinnstillinger i nettskyen.</translation>
<translation id="4450893287417543264">Ikke vis igjen</translation>
<translation id="4451135742916150903">Kan be om å få koble til HID-enheter</translation>
<translation id="4452328064229197696">Passordet du nettopp brukte, er funnet i et databrudd. For å sikre kontoene dine anbefaler Google Passordlagring at du sjekker de lagrede passordene dine.</translation>
@@ -1153,6 +1188,7 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="4628948037717959914">Bilde</translation>
<translation id="4631649115723685955">Penger tilbake er tilknyttet</translation>
<translation id="4636930964841734540">Info</translation>
+<translation id="4638670630777875591">Inkognito i Chromium</translation>
<translation id="464342062220857295">Søkefunksjoner</translation>
<translation id="4644670975240021822">Motsatt rekkefølge – forsiden ned</translation>
<translation id="4646534391647090355">Gå dit nå</translation>
@@ -1173,6 +1209,7 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="4708268264240856090">Tilkoblingen ble avbrutt</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Kjør Windows Nettverksdiagnose<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426">Passord for <ph name="USERNAME" /></translation>
<translation id="4724144314178270921">Kan be om å få se tekst og bilder på utklippstavlen din</translation>
<translation id="4726672564094551039">Last inn retningslinjer på nytt</translation>
<translation id="4728558894243024398">Plattform</translation>
@@ -1194,6 +1231,7 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="4757993714154412917">Du har nettopp skrevet inn passordet ditt på et villedende nettsted. Chromium anbefaler at du sikrer kontoene dine ved å sjekke de lagrede passordene dine.</translation>
<translation id="4758311279753947758">Legg til kontaktinformasjon</translation>
<translation id="4761104368405085019">bruke mikrofonen din</translation>
+<translation id="4761869838909035636">Kjør Chrome-sikkerhetssjekk</translation>
<translation id="4764776831041365478">Det kan hende at nettsiden på <ph name="URL" /> er midlertidig nede eller flyttet permanent til en ny nettadresse.</translation>
<translation id="4766713847338118463">To stifter bunn</translation>
<translation id="4771973620359291008">Det har oppstått en ukjent feil.</translation>
@@ -1214,12 +1252,6 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="4819347708020428563">Vil du redigere annoteringer i standardvisningen?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" /> – trykk på Tab og deretter på Enter for å opprette et nytt Google-regneark raskt</translation>
<translation id="4825507807291741242">Kraftfull</translation>
-<translation id="4827402517081186284">Inkognito gjør deg ikke usynlig på nettet:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Nettsteder vet når du besøker dem.<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Arbeidsgivere og skoler kan spore nettleseraktivitet.<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Internettleverandører kan overvåke nettrafikk.<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">Slå på varsler</translation>
<translation id="4838327282952368871">Drømmende</translation>
<translation id="4840250757394056958">Se Chrome-loggen din</translation>
@@ -1231,12 +1263,12 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="4854362297993841467">Denne leveringsmetoden er ikke tilgjengelig. Prøv en annen metode.</translation>
<translation id="4854853140771946034">Opprett et nytt notat i Google Keep raskt</translation>
<translation id="485902285759009870">Bekrefter koden …</translation>
+<translation id="4866506163384898554">Trykk på |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| for å vise markøren</translation>
<translation id="4876188919622883022">Forenklet visning</translation>
<translation id="4876305945144899064">Uten brukernavn</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{Ingen}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831"><ph name="TEXT" />-søk</translation>
<translation id="4879491255372875719">Automatisk (standard)</translation>
-<translation id="4879725228911483934">åpne og plassere vinduer på skjermene dine</translation>
<translation id="4880827082731008257">Søk i loggen</translation>
<translation id="4881695831933465202">Ã…pne</translation>
<translation id="4885256590493466218">Betal med <ph name="CARD_DETAIL" /> i kassen</translation>
@@ -1245,6 +1277,7 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">Niende rull</translation>
<translation id="4901778704868714008">Lagre</translation>
+<translation id="4905659621780993806">Administratoren din starter enheten din på nytt automatisk kl. <ph name="TIME" /> <ph name="DATE" />. Lagre eventuelle åpne filer før enheten startes på nytt.</translation>
<translation id="4913987521957242411">Hull oppe til venstre</translation>
<translation id="4918221908152712722">Installer <ph name="APP_NAME" /> (ingen nedlasting nødvendig)</translation>
<translation id="4923459931733593730">Betaling</translation>
@@ -1253,6 +1286,7 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" /> – trykk på Tab og deretter på Enter for å søke</translation>
<translation id="4930153903256238152">Stor kapasitet</translation>
+<translation id="4940163644868678279">Inkognito i Chrome</translation>
<translation id="4943872375798546930">Ingen resultater</translation>
<translation id="4950898438188848926">Knappen for å bytte fane – trykk på Enter for å bytte til den åpne fanen, <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="495170559598752135">Handlinger</translation>
@@ -1262,6 +1296,7 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="4968522289500246572">Denne appen er designet for mobil, så det fungerer kanskje ikke så bra å endre størrelse på den. Det kan hende appen støter på problemer eller startes på nytt.</translation>
<translation id="4969341057194253438">Slett opptak</translation>
<translation id="4973922308112707173">To hull topp</translation>
+<translation id="4976702386844183910">Sist besøkt <ph name="DATE" /></translation>
<translation id="4984088539114770594">Vil du bruke mikrofonen?</translation>
<translation id="4984339528288761049">Prc5 (konvolutt)</translation>
<translation id="4989163558385430922">Se alle</translation>
@@ -1323,6 +1358,7 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="5138227688689900538">Vis færre</translation>
<translation id="5145883236150621069">Feilkode i responsen for enhetsinnstillinger</translation>
<translation id="5146995429444047494">Varsler for <ph name="ORIGIN" /> er blokkert</translation>
+<translation id="514704532284964975"><ph name="URL" /> vil se og endre informasjon på NFC-enheter du tæpper med telefonen</translation>
<translation id="5148809049217731050">Forsiden opp</translation>
<translation id="515292512908731282">C4 (konvolutt)</translation>
<translation id="5158275234811857234">Omslag</translation>
@@ -1347,6 +1383,7 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="5215116848420601511">Betalingsmåter og adresser som bruker Google Pay</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">Skuff 13</translation>
+<translation id="5216942107514965959">Sist besøkt i dag</translation>
<translation id="5222812217790122047">E-post er obligatorisk</translation>
<translation id="5230733896359313003">Leveringsadresse</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1367,7 +1404,6 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">Dokumentegenskaper</translation>
<translation id="528468243742722775">Avslutt</translation>
-<translation id="5284909709419567258">nettverksadresser</translation>
<translation id="5285570108065881030">Vis alle lagrede passord</translation>
<translation id="5287240709317226393">Vis informasjonskapsler</translation>
<translation id="5287456746628258573">Dette nettstedet bruker en utdatert sikkerhetskonfigurasjon, som betyr at informasjonen din (for eksempel passord eller kredittkortnumre) kan bli avslørt når den sendes til dette nettstedet.</translation>
@@ -1451,6 +1487,7 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="5556459405103347317">Last inn på nytt</translation>
<translation id="5560088892362098740">Utløpsdato</translation>
<translation id="55635442646131152">Dokumentoversikt</translation>
+<translation id="5565613213060953222">Ã…pne en inkognitofane</translation>
<translation id="5565735124758917034">Aktiv</translation>
<translation id="5570825185877910964">Beskytt kontoen</translation>
<translation id="5571083550517324815">Kan ikke hente på denne adressen. Velg en annen adresse.</translation>
@@ -1533,6 +1570,7 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="5869522115854928033">Lagrede passord</translation>
<translation id="5873013647450402046">Banken din vil bekrefte at det er deg.</translation>
<translation id="5887400589839399685">Kortet er lagret</translation>
+<translation id="5887687176710214216">Sist besøkt i går</translation>
<translation id="5895138241574237353">Start på nytt</translation>
<translation id="5895187275912066135">Utstedt</translation>
<translation id="5901630391730855834">Gul</translation>
@@ -1546,6 +1584,7 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="5921639886840618607">Vil du lagre kortet i Google-kontoen?</translation>
<translation id="5922853866070715753">Nesten ferdig</translation>
<translation id="5932224571077948991">Nettstedet viser forstyrrende eller villedende annonser</translation>
+<translation id="5938153366081463283">Legg til et virtuelt kort</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347">Åpner <ph name="SITE_NAME" /> …</translation>
<translation id="5951495562196540101">Kan ikke registrere med en forbrukerkonto (medfølgende lisens er tilgjengelig).</translation>
@@ -1610,6 +1649,7 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="6120179357481664955">Husker du UPI-ID-en din?</translation>
<translation id="6124432979022149706">Chrome Enterprise Connectors</translation>
<translation id="6127379762771434464">Elementet er fjernet</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Finn ut mer om Incognito i Chrome<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">Sjekk alle kabler, og start rutere, modemer eller andre nettverksenheter
du bruker, på nytt.</translation>
<translation id="614940544461990577">Prøv dette:</translation>
@@ -1622,7 +1662,6 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="6169916984152623906">NÃ¥ kan du surfe privat. Andre som bruker denne enheten, ser ikke aktiviteten din, men nedlastinger og bokmerker blir lagret.</translation>
<translation id="6177128806592000436">Tilkoblingen til dette nettstedet er ikke sikker</translation>
<translation id="6180316780098470077">Forsøksintervall</translation>
-<translation id="619448280891863779">Kan be om å få åpne og plassere vinduer på skjermene dine</translation>
<translation id="6196640612572343990">Blokkér informasjonskapsler fra tredjeparter</translation>
<translation id="6203231073485539293">Kontrollér Internett-tilkoblingen</translation>
<translation id="6218753634732582820">Vil du fjerne adressen fra Chromium?</translation>
@@ -1645,7 +1684,7 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="6272383483618007430">Google Oppdatering</translation>
<translation id="6276112860590028508">Sider fra leselisten din vises her</translation>
<translation id="627746635834430766">For å betale raskere neste gang, lagre kortet ditt og faktureringsadressen i Google-kontoen din.</translation>
-<translation id="6279098320682980337">Ble ikke det virtuelle kortnummeret fylt ut? Klikk på kortopplysningene for å kopiere dem</translation>
+<translation id="6279183038361895380">Trykk på |<ph name="ACCELERATOR" />| for å se markøren</translation>
<translation id="6280223929691119688">Kan ikke levere til denne adressen. Velg en annen adresse.</translation>
<translation id="6282194474023008486">Postnummer</translation>
<translation id="6285507000506177184">Knappen «Administrer nedlastinger i Chrome» – trykk på Enter for å administrere filer du har lastet ned i Chrome</translation>
@@ -1653,6 +1692,7 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="6290238015253830360">De foreslåtte artiklene dine vises her</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{Enheten startes på nytt nå}=1{Enheten startes på nytt om 1 sekund}other{Enheten startes på nytt om # sekunder}}</translation>
<translation id="6302269476990306341">Stopper Google-assistenten i Chrome</translation>
<translation id="6305205051461490394"><ph name="URL" /> er ikke tilgjengelig.</translation>
<translation id="6312113039770857350">Nettsiden er ikke tilgjengelig</translation>
@@ -1726,6 +1766,7 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="6529602333819889595">&amp;Slett likevel</translation>
<translation id="6545864417968258051">Bluetooth-skanning</translation>
<translation id="6547208576736763147">To hull venstre</translation>
+<translation id="6554732001434021288">Sist besøkt for <ph name="NUM_DAYS" /> dager siden</translation>
<translation id="6556866813142980365">Gjør om</translation>
<translation id="6569060085658103619">Du ser på en utvidelsesside</translation>
<translation id="6573200754375280815">To hull høyre</translation>
@@ -1786,7 +1827,6 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="6757797048963528358">Enheten din gikk inn i hvilemodus.</translation>
<translation id="6767985426384634228">Oppdatere adresse?</translation>
<translation id="6768213884286397650">Hagaki (postkort)</translation>
-<translation id="6774185088257932239"><ph name="BEGIN_LINK" />Finn ut mer<ph name="END_LINK" /> om Inkognito</translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">Fiolett</translation>
<translation id="6786747875388722282">Utvidelser</translation>
@@ -1870,7 +1910,6 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="706295145388601875">Legg til og administrer adresser i Chrome-innstillingene</translation>
<translation id="7064851114919012435">Kontaktinformasjon</translation>
<translation id="7068733155164172741">Skriv inn den <ph name="OTP_LENGTH" />-sifrede koden</translation>
-<translation id="7070090581017165256">Om dette nettstedet</translation>
<translation id="70705239631109039">Tilkoblingen er ikke helt sikker</translation>
<translation id="7075452647191940183">Forespørselen er for stor</translation>
<translation id="7079718277001814089">Dette nettstedet inneholder skadelig programvare</translation>
@@ -1887,6 +1926,12 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="7111012039238467737">(Gyldig)</translation>
<translation id="7118618213916969306">Søk etter nettadressen <ph name="SHORT_URL" /> på utklippstavlen</translation>
<translation id="7119414471315195487">Lukk andre faner eller programmer</translation>
+<translation id="7129355289156517987">Når du lukker alle inkognitofaner i Chromium, blir aktiviteten din på de aktuelle fanene fjernet fra enheten:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Nettleseraktivitet<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Søkelogg<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Informasjon du har lagt inn i skjemaer<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">Kan ikke sende til denne adressen. Velg en annen adresse.</translation>
<translation id="7132939140423847331">Administratoren din har forbudt kopiering av disse dataene.</translation>
<translation id="7135130955892390533">Vis statusen</translation>
@@ -1909,6 +1954,7 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="7192203810768312527">Frigjør <ph name="SIZE" />. Det kan hende noen nettsteder lastes inn tregere neste gang du besøker dem.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">Administratoren kan se</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" /> – trykk på Tab og deretter på Enter for å åpne en ny inkognitofane for privat surfing</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> retter seg ikke etter sikkerhetsstandardene.</translation>
<translation id="7210993021468939304">Linux-aktivitet i beholderen, og kan installere og kjøre Linux-apper i beholderen</translation>
@@ -1939,6 +1985,7 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="7304562222803846232">Administrer personverninnstillingene for Google-kontoen</translation>
<translation id="7305756307268530424">Start tregere</translation>
<translation id="7308436126008021607">bakgrunnssynkronisering</translation>
+<translation id="7310392214323165548">Enheten startes på nytt veldig snart</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">Tilkoblingshjelp</translation>
<translation id="7323804146520582233">Skjul «<ph name="SECTION" />»-delen</translation>
@@ -1946,6 +1993,7 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="7334320624316649418">&amp;Omorganiser likevel</translation>
<translation id="7335157162773372339">Kan be om å få bruke kameraet ditt</translation>
<translation id="7337248890521463931">Vis flere linjer</translation>
+<translation id="7337418456231055214">Ble ikke det virtuelle kortnummeret fylt ut? Klikk på kortopplysningene for å kopiere dem. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">Ikke tilgjengelig på plattformen din.</translation>
<translation id="733923710415886693">Tjenerens sertifikat er ikke vist i henhold til regelen for sertifikatåpenhet.</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1968,6 +2016,7 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="7378627244592794276">Nei takk</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">Ikke relevant</translation>
+<translation id="7388594495505979117">{0,plural, =1{Enheten din startes på nytt om 1 minutt}other{Enheten din startes på nytt om # minutter}}</translation>
<translation id="7390545607259442187">Bekreft kortet</translation>
<translation id="7392089738299859607">Oppdater adresse</translation>
<translation id="7399802613464275309">Sikkerhetssjekk</translation>
@@ -2004,6 +2053,12 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="7485870689360869515">Ingen data ble funnet.</translation>
<translation id="7495528107193238112">Dette innholdet er blokkert. Kontakt nettstedseieren for å løse problemet.</translation>
<translation id="7497998058912824456">Knappen «Opprett dokument» – trykk på Enter for å opprette et nytt Google-dokument raskt</translation>
+<translation id="7506488012654002225">Chromium <ph name="BEGIN_EMPHASIS" />lagrer ikke<ph name="END_EMPHASIS" /> følgende informasjon:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Nettleserloggen din
+ <ph name="LIST_ITEM" />Informasjonskapsler og nettstedsdata
+ <ph name="LIST_ITEM" />Informasjon du legger inn i skjemaer
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">Den returnerte enhets-ID-en for regelen er tom eller samsvarer ikke med den faktiske enhets-ID-en</translation>
<translation id="7508870219247277067">Avokadogrønn</translation>
<translation id="7511955381719512146">Det kan hende at Wi-Fi-nettverket du bruker, krever at du besøker <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
@@ -2117,7 +2172,6 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="7813600968533626083">Vil du fjerne skjemaforslaget fra Chrome?</translation>
<translation id="781440967107097262">Vil du dele utklippstavlen din?</translation>
<translation id="7815407501681723534">Fant <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> for «<ph name="SEARCH_STRING" />»</translation>
-<translation id="782125616001965242">Vis informasjon om dette nettstedet</translation>
<translation id="782886543891417279">Det kan hende at Wi-Fi-nettverket du bruker (<ph name="WIFI_NAME" />), krever at du besøker en påloggingsside.</translation>
<translation id="7836231406687464395">Postfix (konvolutt)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{Ingen}=1{1 app (<ph name="EXAMPLE_APP_1" />)}=2{2 apper (<ph name="EXAMPLE_APP_1" /> og <ph name="EXAMPLE_APP_2" />)}other{# apper (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" /> <ph name="AND_MORE" />)}}</translation>
@@ -2134,7 +2188,6 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="7888575728750733395">Gjengivelsesintensjon for utskrift</translation>
<translation id="7894280532028510793">Hvis stavemåten er korrekt, kan du <ph name="BEGIN_LINK" />prøve å kjøre Nettverksdiagnose<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (konvolutt)</translation>
-<translation id="7931318309563332511">Ukjent</translation>
<translation id="793209273132572360">Vil du oppdatere adressen?</translation>
<translation id="7932579305932748336">Belegg</translation>
<translation id="79338296614623784">Angi et gyldig telefonnummer</translation>
@@ -2159,13 +2212,14 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="7976214039405368314">For mange forespørsler</translation>
<translation id="7977538094055660992">Utskriftsenhet</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">Tilknyttet</translation>
<translation id="798134797138789862">Kan be om å få bruke virtuell virkelighet-enheter og -data</translation>
<translation id="7984945080620862648">Du kan ikke gå til <ph name="SITE" /> akkurat nå fordi nettstedet sendte kryptert legitimasjon som Chrome ikke kan behandle. Nettverksfeil og -angrep er som regel kortvarige, så denne siden fungerer nok igjen senere.</translation>
-<translation id="79859296434321399">Du må installere ARCore for å se innhold med utvidet virkelighet</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">Innbinding</translation>
<translation id="7992044431894087211">Skjermdeling med <ph name="APPLICATION_TITLE" /> er gjenopptatt</translation>
<translation id="7995512525968007366">Ikke spesifisert</translation>
+<translation id="7998269595945679889">Knappen «Åpne en inkognitofane» – trykk på Enter for å åpne en ny inkognitofane for privat surfing</translation>
<translation id="800218591365569300">Prøv å lukke andre faner eller programmer for å frigjøre minne.</translation>
<translation id="8004582292198964060">Nettleser</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{Dette kortet og den tilknyttede faktureringsadressen lagres. Du kan bruke det når du er logget på <ph name="USER_EMAIL" />.}other{Disse kortene og de tilknyttede faktureringsadressene lagres. Du kan bruke dem når du er logget på <ph name="USER_EMAIL" />.}}</translation>
@@ -2225,6 +2279,7 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="8202370299023114387">Konflikt</translation>
<translation id="8206978196348664717">Prc4 (konvolutt)</translation>
<translation id="8211406090763984747">Tilkoblingen er sikker</translation>
+<translation id="8217240300496046857">Nettsteder kan ikke bruke informasjonskapsler som sporer deg på nettet. Det kan hende at funksjoner på enkelte nettsteder slutter å fungere.</translation>
<translation id="8218327578424803826">Tilordnet posisjon:</translation>
<translation id="8220146938470311105">C7/C6 (konvolutt)</translation>
<translation id="8225771182978767009">Personen som konfigurerte denne datamaskinen, har valgt å blokkere dette nettstedet.</translation>
@@ -2265,14 +2320,9 @@ I motsatt fall blir dette blokkert av personverninnstillingene. Dette gjør at i
<translation id="830498451218851433">Halvfals</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">hvilke apper som er installert, og hvor ofte de brukes</translation>
+<translation id="8317207217658302555">Vil du oppdatere ARCore?</translation>
<translation id="831997045666694187">Kveld</translation>
<translation id="8321476692217554900">varsler</translation>
-<translation id="8328484624016508118">NÃ¥r du lukker alle inkognitofaner, sletter Chrome
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />nettleseraktiviteten din fra denne enheten<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />søkeloggen din fra denne enheten<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />informasjon du har skrevet inn i skjemaer<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489">Forsøket på å koble til <ph name="HOST_NAME" /> ble avvist</translation>
<translation id="833262891116910667">Fremhev</translation>
<translation id="8339163506404995330">Sider på <ph name="LANGUAGE" /> oversettes ikke</translation>
@@ -2324,6 +2374,7 @@ Mer informasjon:
<translation id="8507227106804027148">Kommandolinje</translation>
<translation id="8508648098325802031">Søkeikon</translation>
<translation id="8511402995811232419">Administrer informasjonskapsler</translation>
+<translation id="8519753333133776369">HID-enheten tillates av administratoren din</translation>
<translation id="8522552481199248698">Chrome kan hjelpe deg med å beskytte Google-kontoen din og endre passordet ditt.</translation>
<translation id="8530813470445476232">Tøm nettleserloggen, slett informasjonskapsler, tøm bufferen med mer i Chrome-innstillingene</translation>
<translation id="8533619373899488139">Gå til &lt;strong&gt;chrome://policy&lt;/strong&gt; for å se listen over blokkerte nettadresser og andre regler systemadministratoren din har fastsatt.</translation>
@@ -2335,7 +2386,6 @@ Mer informasjon:
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{Tilbakestill tillatelse}other{Tilbakestill tillatelser}}</translation>
<translation id="8555010941760982128">Bruk denne koden i kassen</translation>
<translation id="8557066899867184262">CVC-koden finner du på baksiden av kortet.</translation>
-<translation id="8558485628462305855">Du må oppdatere ARCore for å se innhold med utvidet virkelighet</translation>
<translation id="8559762987265718583">En privat tilkobling til <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> kunne ikke etableres fordi datoen og klokkeslettet (<ph name="DATE_AND_TIME" />) er feil på enheten.</translation>
<translation id="8564182942834072828">Separate dokumenter / ukollaterte eksemplarer</translation>
<translation id="8564985650692024650">Chromium anbefaler at du tilbakestiller passordet ditt for <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> hvis du også har brukt det på andre nettsteder.</translation>
@@ -2354,6 +2404,7 @@ Mer informasjon:
<translation id="865032292777205197">bevegelsessensorer</translation>
<translation id="8663226718884576429">Bestillingssammendrag, <ph name="TOTAL_LABEL" />, mer informasjon</translation>
<translation id="8666678546361132282">Engelsk</translation>
+<translation id="8669306706049782872">bruke informasjon om skjermene dine for å åpne og plassere vinduer</translation>
<translation id="867224526087042813">Signatur</translation>
<translation id="8676424191133491403">Uten forsinkelse</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, svar, <ph name="ANSWER" /></translation>
@@ -2374,12 +2425,13 @@ Mer informasjon:
<translation id="8719263113926255150"><ph name="ENTITY" />, <ph name="DESCRIPTION" />, søkeforslag</translation>
<translation id="8719528812645237045">Flere hull topp</translation>
<translation id="8723535127346307411">Skriv inn bekreftelseskoden</translation>
-<translation id="8725066075913043281">Prøv igjen</translation>
+<translation id="8725066075913043281">Prøv på nytt</translation>
<translation id="8726549941689275341">Sidestørrelse:</translation>
<translation id="8730621377337864115">Ferdig</translation>
<translation id="8731544501227493793">Knappen «Administrer passord» – trykk på Enter for å se og administrere passord i Chrome-innstillingene</translation>
<translation id="8734529307927223492"><ph name="DEVICE_TYPE" /> administreres av <ph name="MANAGER" /></translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" /> – trykk på Tab og deretter på Enter for å åpne et nytt inkognitovindu for privat surfing</translation>
+<translation id="8737685506611670901">Ã¥pne linker til <ph name="PROTOCOL" /> i stedet for <ph name="REPLACED_HANDLER_TITLE" /></translation>
<translation id="8738058698779197622">Klokken din må være riktig stilt for at du skal kunne opprette en sikker forbindelse. Sertifikatene som nettsteder bruker til å identifisere seg med, er nemlig bare gyldige i en viss tid. Siden enhetens klokke er feil, kan ikke Chromium kontrollere disse sertifikatene.</translation>
<translation id="8740359287975076522">&lt;abbr id="dnsDefinition"&gt;DNS-adressen&lt;/abbr&gt; til <ph name="HOST_NAME" /> ble ikke funnet. Problemet diagnostiseres.</translation>
<translation id="8742371904523228557"><ph name="ONE_TIME_CODE" /> er koden din for <ph name="ORIGIN" /></translation>
@@ -2407,6 +2459,7 @@ Mer informasjon:
<translation id="883848425547221593">Andre bokmerker</translation>
<translation id="884264119367021077">Leveringsadresse</translation>
<translation id="884923133447025588">Finner ingen tilbakekallingsmekanisme.</translation>
+<translation id="8849262850971482943">Bruk det virtuelle kortet ditt for ekstra sikkerhet</translation>
<translation id="885730110891505394">Deling med Google</translation>
<translation id="8858065207712248076">Chrome anbefaler at du tilbakestiller passordet ditt for <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> hvis du også har brukt det på andre nettsteder.</translation>
<translation id="885906927438988819">Hvis stavemåten er korrekt, kan du <ph name="BEGIN_LINK" />prøve å kjøre Windows Nettverksdiagnose<ph name="END_LINK" />.</translation>
@@ -2456,6 +2509,7 @@ Mer informasjon:
<translation id="9004367719664099443">En VR-økt pågår</translation>
<translation id="9005998258318286617">Kunne ikke laste inn PDF-dokumentet.</translation>
<translation id="9008201768610948239">Ignorer</translation>
+<translation id="901834265349196618">e-post</translation>
<translation id="9020200922353704812">Faktureringsadressen for kortet er obligatorisk</translation>
<translation id="9020542370529661692">Denne siden har blitt oversatt til <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9020742383383852663">A8</translation>
@@ -2504,6 +2558,7 @@ Mer informasjon:
<translation id="9150045010208374699">bruke kameraet ditt</translation>
<translation id="9150685862434908345">Administratoren kan endre nettleseroppsettet eksternt. Aktiviteten på denne enheten kan også bli administrert utenfor Chrome. <ph name="BEGIN_LINK" />Finn ut mer<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">Oppdatert</translation>
+<translation id="9155211586651734179">Eksterne lydenheter er tilkoblet</translation>
<translation id="9157595877708044936">Konfigurerer ...</translation>
<translation id="9158625974267017556">C6 (konvolutt)</translation>
<translation id="9164029392738894042">Nøyaktighetssjekk</translation>
diff --git a/chromium/components/strings/components_strings_or.xtb b/chromium/components/strings/components_strings_or.xtb
index ea686f312cb..0b2ae2205d2 100644
--- a/chromium/components/strings/components_strings_or.xtb
+++ b/chromium/components/strings/components_strings_or.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">ବିବରଣୀ ଦେଖନà­à¬¤à­</translation>
<translation id="1030706264415084469"><ph name="URL" /> ସà­à¬¥à¬¾à­Ÿà­€à¬°à­‚ପେ ଆପଣଙà­à¬•à¬° ଡିଭାଇସà­â€Œà¬°à­‡ ଅଧିକ ଡାଟା ଷà­à¬Ÿà­‹à¬°à­ କରିବାକୠଚାହà­à¬à¬›à¬¿</translation>
<translation id="1032854598605920125">ବାମରୠଡାହାଣକୠଘୂରାନà­à¬¤à­</translation>
+<translation id="1033329911862281889">ଇନକଗà­à¬¨à¬¿à¬Ÿà­‹ ମୋଡ ଆପଣଙà­à¬•à­ ଅନଲାଇନରେ ଅଦୃଶà­à­Ÿ କରେ ନାହିà¬:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ସାଇଟଗà­à­œà¬¿à¬•à­ ଭିଜିଟ କଲେ, ସାଇଟଗà­à¬¡à¬¼à¬¿à¬• à¬à¬¬à¬‚ ସେଗà­à¬¡à¬¼à¬¿à¬• ବà­à­Ÿà¬¬à¬¹à¬¾à¬° କରà­à¬¥à¬¿à¬¬à¬¾ ସେବାଗà­à¬¡à¬¼à¬¿à¬• à¬à¬¹à¬¾ ବିଷୟରେ ଜାଣିପାରନà­à¬¤à¬¿<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ନିଯà­à¬•à­à¬¤à¬¿à¬¦à¬¾à¬¤à¬¾ କିମà­à¬¬à¬¾ ସà­à¬•à­à¬²à¬—à­à¬¡à¬¼à¬¿à¬• ବà­à¬°à¬¾à¬‰à¬œà¬¿à¬‚ କାରà­à¬¯à­à­Ÿà¬•à¬³à¬¾à¬ªà¬•à­ ଟà­à¬°à¬¾à¬• କରିପାରିବେ<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ଇଣà­à¬Ÿà¬°à¬¨à­‡à¬Ÿ ସେବା ପà­à¬°à¬¦à¬¾à¬¨à¬•à¬¾à¬°à­€à¬—à­à­œà¬¿à¬• ୱେବ ଟà­à¬°à¬¾à¬«à¬¿à¬•à¬•à­ ମନିଟର କରିପାରନà­à¬¤à¬¿<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">ବନà­à¬¦ କରନà­à¬¤à­</translation>
<translation id="1036982837258183574">ପୂରà­à¬£à­à¬£ ସà­à¬•à­à¬°à¬¿à¬¨à­â€Œà¬°à­ ପà­à¬°à¬¸à­à¬¥à¬¾à¬¨ କରିବାକୠ|<ph name="ACCELERATOR" />| ଦବାନà­à¬¤à­</translation>
<translation id="1038106730571050514">ପରାମରà­à¬¶à¬—à­à­œà¬¿à¬• ଦେଖାନà­à¬¤à­</translation>
<translation id="1038842779957582377">ଅଜà­à¬žà¬¾à¬¤ ନାମ</translation>
<translation id="1041998700806130099">ଜବୠସିଟୠମେସେଜà­</translation>
<translation id="1048785276086539861">ଯେତେବେଳେ ଆପଣ à¬à¬¨à­‹à¬Ÿà­‡à¬¸à¬¨à¬—à­à­œà¬¿à¬•à­ à¬à¬¡à¬¿à¬Ÿà­ କରନà­à¬¤à¬¿, à¬à¬¹à¬¿ ଡକà­à­Ÿà­à¬®à­‡à¬£à­à¬Ÿ ସିଙà­à¬—ଲୠପେଜୠଭà­à­Ÿà­à¬•à­ ଫେରି ଆସିବ</translation>
-<translation id="1049743911850919806">ଇନà­â€Œà¬•à¬—à­à¬¨à¬¿à¬Ÿà­‹</translation>
<translation id="1050038467049342496">ଅନà­à­Ÿ ଆପà­â€ ବନà­à¬¦ କରନà­à¬¤à­</translation>
<translation id="1055184225775184556">ଯୋଗ କରାଯାଇଥିବା କାରà­à¬¯à­à­Ÿà¬•à­ &amp;ପୂରà­à¬¬à¬¬à¬¤à­ କରନà­à¬¤à­</translation>
<translation id="1056898198331236512">ଚେତାବନୀ</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">ନୀତି କେଚà­â€ ଠିକୠଅଛି</translation>
<translation id="1130564665089811311">"ପୃଷà­à¬ à¬¾ ଅନà­à¬¬à¬¾à¬¦ କରନà­à¬¤à­" ବଟନà­, Google Translate ବà­à­Ÿà¬¬à¬¹à¬¾à¬° କରି à¬à¬¹à¬¿ ପୃଷà­à¬ à¬¾à¬•à­ ଅନà­à¬¬à¬¾à¬¦ କରିବା ପାଇଠEnter ଦବାନà­à¬¤à­</translation>
<translation id="1131264053432022307">ଆପଣ ଯେଉଠଛବି କପି କରିଥିଲେ</translation>
+<translation id="1142846828089312304">ଇନକଗà­à¬¨à¬¿à¬Ÿà­‹ ମୋଡରେ ତୃତୀୟ ପକà­à¬· କà­à¬•à­€à¬—à­à¬¡à¬¼à¬¿à¬•à­ ବà­à¬²à¬• କରନà­à¬¤à­</translation>
<translation id="1150979032973867961">à¬à¬¹à¬¾ <ph name="DOMAIN" /> ଅଟେ ବୋଲି à¬à¬¹à¬¿ ସରà­à¬­à¬°à­ ପà­à¬°à¬®à¬¾à¬£ କରିପାରିଲା ନାହିà¬; à¬à¬¹à¬¾à¬° ସà­à¬°à¬•à­à¬·à¬¾ ସାରà­à¬Ÿà¬¿à¬«à¬¿à¬•à­‡à¬Ÿà­ ଆପଣଙà­à¬•à¬° କମà­à¬ªà­à­Ÿà­à¬Ÿà¬°à­â€Œà¬° ଅପରେଟିଂ ସିଷà­à¬Ÿà¬®à­ ଦà­à­±à¬¾à¬°à¬¾ ବିଶà­à­±à¬¸à¬¨à­€à­Ÿ ନà­à¬¹à­‡à¬à¥¤ à¬à¬¹à¬¾ ହà­à¬à¬¤ à¬à¬• ଭà­à¬² କନଫିଗà­â€Œà¬°à­‡à¬¸à¬¨à­ କିମà­à¬¬à¬¾ ଜଣେ ଆକà­à¬°à¬®à¬£à¬•à¬¾à¬°à­€ ଆପଣଙà­à¬•à¬° ସଂଯୋଗକୠପà­à¬°à¬¤à¬¿à¬°à­‹à¬§ କରà­à¬¥à¬¿à¬¬à¬¾ କାରଣରୠହୋଇଥାଇପାରେ।</translation>
<translation id="1151972924205500581">ପାସà­â€Œà­±à¬°à­à¬¡ ଆବଶà­à­Ÿà¬•</translation>
<translation id="1156303062776767266">ଆପଣ à¬à¬• ସà­à¬¥à¬¾à¬¨à­€à­Ÿ କିମà­à¬¬à¬¾ ସେୟାରà­â€ ହୋâ€à¬‡à¬¥à¬¿à¬¬à¬¾ ଫାଇଲà­â€Œ ଦେଖà­à¬›à¬¨à­à¬¤à¬¿</translation>
@@ -64,7 +70,6 @@
<translation id="1178581264944972037">ବିରତି</translation>
<translation id="1181037720776840403">କାଢ଼ି ଦିଅନà­à¬¤à­</translation>
<translation id="1186201132766001848">ପାସà­â€Œà­±à¬¾à¬°à­à¬¡à¬—à­à¬¡à¬¼à¬¿à¬•à­ ଯାଞà­à¬š କରନà­à¬¤à­</translation>
-<translation id="1195210374336998651">ଆପ ସେଟିଂସକୠଯାଆନà­à¬¤à­</translation>
<translation id="1195558154361252544">ଆପଣ ଅନà­à¬®à¬¤à¬¿ ଦେଇଥିବା ସାଇଟà­â€à¬—à­à­œà¬¿à¬• ବà­à­Ÿà¬¤à­€à¬¤ ସମସà­à¬¤ ସାଇଟà­â€Œà¬°à­‡ ବିଜà­à¬žà¬ªà­à¬¤à¬¿à¬—à­à­œà¬¿à¬•à­ ବà­à¬²à¬•à­ କରାଯାଇଛି</translation>
<translation id="1197088940767939838">କମଳା</translation>
<translation id="1201402288615127009">ପରବରà­à¬¤à­à¬¤à­€</translation>
@@ -111,7 +116,7 @@
<translation id="1307966114820526988">ଅଗà­à¬°à¬¾à¬¹à­à­Ÿ କରାଯାଇଥିବା ଫିଚରà­â€à¬—à­à­œà¬¿à¬•</translation>
<translation id="1308113895091915999">ଅଫର ଉପଲବà­à¬§ ଅଛି</translation>
<translation id="1312803275555673949">କେଉଠପà­à¬°à¬®à¬¾à¬£ à¬à¬¹à¬¾à¬•à­ ସମରà­à¬¥à¬¨ କରେ?</translation>
-<translation id="131405271941274527">à¬à¬• NFC ଡିଭାଇସà­â€Œà¬°à­‡ ଆପଣ ନିଜର ଫୋନୠଟାପୠକରିବା ପରେ <ph name="URL" /> ସୂଚନା ପଠାଇବାକୠତଥା ପà­à¬°à¬¾à¬ªà­à¬¤ କରିବାକୠଚାହେà¬</translation>
+<translation id="1314311879718644478">ଅଗମେଣà­à¬Ÿà­‡à¬¡ ରିଆଲିଟୀ ବିଷୟବସà­à¬¤à­à¬•à­ ଦେଖନà­à¬¤à­</translation>
<translation id="1314509827145471431">ଡାହାଣ ପଟରେ ବାଇଣà­à¬¡</translation>
<translation id="1318023360584041678">ଟାବ ଗୋଷà­à¬ à­€à¬°à­‡ ସେଭ କରାଯାଇଛି</translation>
<translation id="1319245136674974084">à¬à¬¹à¬¿ ଆପୠପାଇଠପà­à¬£à¬¿ ପଚାରନà­à¬¤à­ ନାହିà¬</translation>
@@ -161,6 +166,7 @@
<translation id="142858679511221695">କà­à¬²à¬¾à¬‰à¬¡ ଉପଯୋଗକରà­à¬¤à­à¬¤à¬¾</translation>
<translation id="1428729058023778569">à¬à¬¹à¬¿ ସାଇଟୠHTTPSକୠସମରà­à¬¥à¬¨ କରà­à¬¨à¬¥à¬¿à¬¬à¬¾ ଯୋଗà­à¬ ଆପଣ à¬à¬¹à¬¿ ଚେତାବନୀଟି ଦେଖà­à¬›à¬¨à­à¬¤à¬¿à¥¤ <ph name="BEGIN_LEARN_MORE_LINK" />ଅଧିକ ଜାଣନà­à¬¤à­<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">ପà­à¬°à¬¿à¬£à­à¬Ÿ କରନà­à¬¤à­</translation>
+<translation id="1432187715652018471">ପୃଷà­à¬ à¬¾à¬Ÿà¬¿ à¬à¬• ସେବା ହà­à­Ÿà¬¾à¬£à­à¬¡à¬²à¬° ଇନଷà­à¬Ÿà¬² କରିବାକୠଚାହà­à¬à¬›à¬¿à¥¤</translation>
<translation id="1432581352905426595">ସନà­à¬§à¬¾à¬¨ ଇଞà­à¬œà¬¿à¬¨à­â€Œà¬—à­à­œà¬¿à¬• ପରିଚାଳନା କରନà­à¬¤à­</translation>
<translation id="1436185428532214179">ଆପଣଙà­à¬• ଡିଭାଇସରେ ଫାଇଲୠଓ ଫୋଲà­à¬¡à¬°à¬—à­à­œà¬¿à¬• à¬à¬¡à¬¿à¬Ÿà­ କରିବାକୠସାଇଟୠପଚାରିପାରେ</translation>
<translation id="1442386063175183758">ଡାହାଣ ପଟରେ ଗେଟୠଫୋଲà­à¬¡</translation>
@@ -181,6 +187,12 @@
<translation id="1483493594462132177">ପଠାନà­à¬¤à­</translation>
<translation id="1484290072879560759">ସିପିଂ ଠିକଣା ବାଛନà­à¬¤à­</translation>
<translation id="1492194039220927094">ନୀତିଗà­à­œà¬¿à¬• ପà­à¬¸à­â€Œ କରନà­à¬¤à­:</translation>
+<translation id="149293076951187737">ଆପଣ ଯେତେବେଳେ ଇନକଗà­à¬¨à¬¿à¬Ÿà­‹ ମୋଡରେ ଥିବା ସମସà­à¬¤ Chrome ଟାବକୠବନà­à¬¦ କରନà­à¬¤à¬¿, ସେହି ଟାବଗà­à¬¡à¬¼à¬¿à¬•à¬°à­‡ ଆପଣଙà­à¬• କାରà­à¬¯à­à­Ÿà¬•à¬³à¬¾à¬ª à¬à¬¹à¬¿ ଡିଭାଇସରୠଖାଲି ହୋଇଯାà¬:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ବà­à¬°à¬¾à¬‰à¬œà¬¿à¬‚ କାରà­à¬¯à­à­Ÿà¬•à¬³à¬¾à¬ª<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ସନà­à¬§à¬¾à¬¨ ଇତିହାସ<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ଫରà­à¬®à¬—à­à­œà¬¿à¬•à¬°à­‡ ଲେଖାଯାଇଥିବା ସୂଚନା<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">ଟାବà­â€Œà¬•à­ ଫେରନà­à¬¤à­</translation>
<translation id="1501859676467574491">ଆପଣଙà­à¬•à¬° Google Accountରୠକାରà­à¬¡ ଦେଖାନà­à¬¤à­</translation>
<translation id="1507202001669085618">&lt;p&gt;ଆପଣ ଯଦି କୌଣସି ୱାଇ-ଫାଇ ପୋରà­à¬Ÿà¬¾à¬²à­ ବà­à­Ÿà¬¬à¬¹à¬¾à¬° କରà­à¬›à¬¨à­à¬¤à¬¿, ଯେଉà¬à¬ à¬¿ ଆପଣଙà­à¬•à­ ଅନà­â€Œà¬²à¬¾à¬‡à¬¨à­ ହେବା ପାଇଠସାଇନୠଇନୠକରିବାକୠହà­à¬, ତାହେଲେ ଆପଣ à¬à¬¹à¬¿ ତà­à¬°à­à¬Ÿà¬¿à¬•à­ ଦେଖିବେ।&lt;/p&gt;
@@ -208,6 +220,8 @@
<translation id="1559572115229829303">&lt;p&gt;<ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />କୠà¬à¬• ବà­à­Ÿà¬•à­à¬¤à¬¿à¬—ତ ସଂଯୋଗ ସà­à¬¥à¬¾à¬ªà¬¨ କରାଯାଇପାରିବ ନାହିଠକାରଣ, ଆପଣଙà­à¬• ଡିଭାଇସà­â€Œà¬° ତାରିଖ à¬à¬¬à¬‚ ସମୟ (<ph name="DATE_AND_TIME" />) ଭà­à¬² ଅଛି।&lt;/p&gt;
&lt;p&gt;ଦୟାକରି &lt;strong&gt;ସେଟିଂସà­&lt;/strong&gt; ଆପà­â€Œà¬° &lt;strong&gt;ସାଧାରଣ&lt;/strong&gt; ବିଭାଗରୠତାରିଖ à¬à¬¬à¬‚ ସମୟ ଆଡà­â€Œà¬œà¬·à­à¬Ÿ କରନà­à¬¤à­à¥¤&lt;/p&gt;</translation>
+<translation id="1559839503761818503">ଆପଣଙà­à¬• ଆଡମିନିଷà­à¬Ÿà­à¬°à­‡à¬Ÿà¬° ଆପଣଙà­à¬•à¬° ଡିଭାଇସକୠ<ph name="DATE" />ରେ <ph name="TIME" /> ବେଳେ ରିଷà­à¬Ÿà¬¾à¬°à­à¬Ÿ କରିବେ</translation>
+<translation id="156703335097561114">ଠିକଣା, ଇଣà­à¬Ÿà¬°à¬«à­‡à¬¸ କନଫିଗରେସନ à¬à¬¬à¬‚ ସଂଯୋଗର ଗà­à¬£à¬¬à¬¤à­à¬¤à¬¾ ପରି ନେଟୱାରà­à¬•à¬¿à¬‚ ସୂଚନା</translation>
<translation id="1567040042588613346">à¬à¬¹à¬¿ ନୀତି ଆଶାନà­à¬°à­‚ପ ଭାବେ କାରà­à¬¯à­à­Ÿ କରà­à¬›à¬¿ କିନà­à¬¤à­ ସମାନ ମୂଲà­à­Ÿ ଅନà­à­Ÿ କୌଣସି ସà­à¬¥à¬¾à¬¨à¬°à­‡ ସେଟୠକରାଯାଇଛି à¬à¬¬à¬‚ à¬à¬¹à¬¿ ନୀତି ଦà­à­±à¬¾à¬°à¬¾ ସà­à¬¥à¬¾à¬¨ ଅଧିକାର କରାଯାଇଛି।</translation>
<translation id="1569487616857761740">ମିଆଦ ଶେଷର ତାରିଖ ଲେଖନà­à¬¤à­</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@
<translation id="1583429793053364125">à¬à¬¹à¬¿ ୱେବୠପୃଷà­à¬ à¬¾à¬Ÿà¬¿ ପà­à¬°à¬¦à¬°à­à¬¶à¬¨ କରà­à¬¥à¬¿à¬¬à¬¾ ବେଳେ କିଛି ତà­à¬°à­à¬Ÿà¬¿ ହୋଇଛି।</translation>
<translation id="1586541204584340881">ଆପଣ କେଉଠà¬à¬•à­à¬¸à¬Ÿà­‡à¬¨à¬¸à¬¨à¬—à­à­œà¬¿à¬•à­ ଇନଷà­à¬Ÿà¬²à­ କରିଛନà­à¬¤à¬¿</translation>
<translation id="1588438908519853928">ସାଧାରଣ</translation>
+<translation id="1589050138437146318">ARCore ଇନଷà­à¬Ÿà¬² କରିବେ କି?</translation>
<translation id="1592005682883173041">ସà­à¬¥à¬¾à¬¨à­€à­Ÿ ଡାଟା ଆକà­à¬¸à­‡à¬¸à­</translation>
<translation id="1594030484168838125">ବାଛନà­à¬¤à­</translation>
<translation id="160851722280695521">Chromeରେ Dino Run ଗେମ ଖେଳନà­à¬¤à­</translation>
@@ -279,6 +294,7 @@
<translation id="1763864636252898013">à¬à¬¹à¬¿ ସରà­à¬­à¬°à­ à¬à¬¹à¬¾ ପà­à¬°à¬®à¬¾à¬£ କରିପାରିଲା ନାହିଠଯେ à¬à¬¹à¬¾ <ph name="DOMAIN" /> ଅଟେ; à¬à¬¹à¬¾à¬° ସà­à¬°à¬•à­à¬·à¬¾ ସାରà­à¬Ÿà¬¿à¬«à¬¿à¬•à­‡à¬Ÿà­ ଆପଣଙà­à¬•à¬° ଅପରେଟିଂ ସିଷà­à¬Ÿà¬®à­ ଦà­à­±à¬¾à¬°à¬¾ ବିଶà­à­±à¬¸à¬¨à­€à­Ÿ ନà­à¬¹à­‡à¬à¥¤ à¬à¬¹à¬¾ ହà­à¬à¬¤ à¬à¬• ଭà­à¬²à­ କନଫିଗà­â€â€à¬°à­‡à¬¸à¬¨à­ କିମà­à¬¬à¬¾ ଆପଣଙà­à¬•à¬° ସଂଯୋଗକୠପà­à¬°à¬¤à¬¿à¬°à­‹à¬§ କରà­à¬¥à¬¿à¬¬à¬¾ ଜଣେ ଆକà­à¬°à¬®à¬£à¬•à¬¾à¬°à­€à¬™à­à¬• କାରଣରୠହୋଇପାରେ।</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />ୱିଣà­à¬¡à­‹ ନେଟà­â€Œà­±à¬°à­à¬• ଡାଇଗà­à¬¨à­‹à¬·à­à¬Ÿà¬¿à¬•à­à¬¸ ଚଲେଇବାକୠଚେଷà­à¬Ÿà¬¾ କରନà­à¬¤à­<ph name="END_LINK" />।</translation>
<translation id="1772163372082567643">ଆପଣ ଯାଉଥିବା <ph name="ORIGIN" /> ସରà­à¬­à¬°à­, ଗୋଟିଠହେଡରୠସେଟୠକରିଛି, ଯାହା à¬à¬¹à¬¿ ସରà­à¬­à¬°à¬•à­ କରାଯାଇଥିବା ସମସà­à¬¤ ଅନà­à¬°à­‹à¬§à¬°à­‡ à¬à¬• ମୂଳ ନୀତି ଲାଗୠକରାଯିବା ଆବଶà­à­Ÿà¬• କରà­à¬›à¬¿à¥¤ କିନà­à¬¤à­ ହେଡରଟି ତà­à¬°à­à¬Ÿà¬¿à¬ªà­‚ରà­à¬£à­à¬£ ଅଟେ, ଯାହା <ph name="SITE" /> ପାଇଠଆପଣଙà­à¬• ଅନà­à¬°à­‹à¬§ ପୂରଣ କରିବାରୠବà­à¬°à¬¾à¬‰à¬œà¬°à¬•à­ ପà­à¬°à¬¤à¬¿à¬°à­‹à¬§ କରେ। କୌଣସି ସାଇଟର ସà­à¬°à¬•à­à¬·à¬¾ à¬à¬¬à¬‚ ଅନà­à­Ÿ ପà­à¬°à­‹à¬ªà¬°à­à¬Ÿà¬¿à¬—à­à¬¡à¬¼à¬¿à¬• କନଫିଗରୠକରିବାକୠସାଇଟୠଅପରେଟରମାନଙà­à¬• ଦà­à­±à¬¾à¬°à¬¾ ମୂଳ ନୀତିଗà­à­œà¬¿à¬• ବà­à­Ÿà¬¬à¬¹à¬¾à¬° କରାଯାଇପାରିବ।</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Chromiumରେ ଇନକଗà­à¬¨à¬¿à¬Ÿà­‹ ମୋଡ ବିଷୟରେ ଅଧିକ ଜାଣନà­à¬¤à­<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">ଆପଣଙà­à¬•à¬° ଖୋଲାଥିବା ଟାବà­â€Œà¬—à­à¬¡à¬¼à¬¿à¬• à¬à¬ à¬¾à¬°à­‡ ଦେଖାଯିବ</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -406,6 +422,7 @@
<translation id="22081806969704220">ଟà­à¬°à­‡ 3</translation>
<translation id="2212735316055980242">ନୀତି ମିଳିଲା ନାହିà¬</translation>
<translation id="2213606439339815911">ପà­à¬°à¬¬à¬¿à¬·à­à¬Ÿà¬—à­à­œà¬¿à¬•à­ ଅଣାଯାଉଛି...</translation>
+<translation id="2213612003795704869">ପୃଷà­à¬ à¬¾ ପà­à¬°à¬¿à¬£à­à¬Ÿ କରାଯାଇଛି</translation>
<translation id="2215727959747642672">ଫାଇଲୠà¬à¬¡à¬¿à¬Ÿà¬¿à¬‚</translation>
<translation id="2218879909401188352">ବରà­à¬¤à­à¬¤à¬®à¬¾à¬¨ ଆକà­à¬°à¬®à¬£à¬•à¬¾à¬°à­€à¬®à¬¾à¬¨à­‡ <ph name="BEGIN_BOLD" /><ph name="SITE" />ରେ<ph name="END_BOLD" /> ବିପଦପୂରà­à¬£à­à¬£ ଆପà­â€à¬—à­à­œà¬¿à¬•à­ ଇନà­â€à¬·à­à¬Ÿà¬²à­ କରିପାରନà­à¬¤à¬¿ ଯାହା, ଆପଣଙà­à¬• ଡିଭାଇସà­â€à¬° କà­à¬·à¬¤à¬¿ କରିପାରେ, ଆପଣଙà­à¬• ମୋବାଇଲୠବିଲà­â€â€à¬°à­‡ ଗà­à¬ªà­à¬¤ ଶà­à¬³à­à¬•à¬—à­à­œà¬¿à¬•à­ ଯୋଗ କରିପାରେ କିମà­à¬¬à¬¾ ଆପଣଙà­à¬•à¬° ବà­à­Ÿà¬•à­à¬¤à¬¿à¬—ତ ସୂଚନା ଚୋରି କରିପାରେ। <ph name="BEGIN_LEARN_MORE_LINK" />ଅଧିକ ଜାଣନà­à¬¤à­<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">କୌଣସି ଇଣà­à¬Ÿà¬°à­à¬¨à­‡à¬Ÿà­â€ ନାହିà¬</translation>
@@ -415,6 +432,7 @@
<translation id="2248949050832152960">WebAuthn ବà­à­Ÿà¬¬à¬¹à¬¾à¬° କରନà­à¬¤à­</translation>
<translation id="2250931979407627383">ବାମ ପଟରେ à¬à¬œà­ ଷà­à¬Ÿà¬¿à¬šà­</translation>
<translation id="225207911366869382">à¬à¬¹à¬¿ ମୂଲà­à­Ÿ, à¬à¬¹à¬¿ ନୀତି ପାଇଠଅଗà­à¬°à¬¾à¬¹à­à­Ÿ କରାଯାଇଛି।</translation>
+<translation id="2256115617011615191">ରିଷà­à¬Ÿà¬¾à¬°à­à¬Ÿ କରନà­à¬¤à­</translation>
<translation id="2258928405015593961">ଭବିଷà­à­Ÿà¬¤à¬°à­‡ à¬à¬• ମିଆଦ ଶେଷ ହେଉଥିବା ତାରିଖ ଲେଖନà­à¬¤à­ à¬à¬¬à¬‚ ପà­à¬£à¬¿ ଚେଷà­à¬Ÿà¬¾ କରନà­à¬¤à­</translation>
<translation id="225943865679747347">ତà­à¬°à­à¬Ÿà¬¿ କୋଡà­: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">HTTP ତà­à¬°à­à¬Ÿà¬¿</translation>
@@ -442,6 +460,7 @@
<translation id="2337852623177822836">ଆପଣଙà­à¬•à¬° ବà­à­Ÿà¬¬à¬¸à­à¬¥à¬¾à¬ªà¬•à¬™à­à¬• ଦà­à¬¬à¬¾à¬°à¬¾ ସେଟିଂ ନିୟନà­à¬¤à­à¬°à¬£ କରାଯାଇଛି</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> ପେୟାରୠକରିବାକୠଚାହà­à¬à¬›à¬¿</translation>
<translation id="2346319942568447007">ଆପଣ ଯେଉଠଛବି କପି କରିଥିଲେ</translation>
+<translation id="2350796302381711542"><ph name="REPLACED_HANDLER_TITLE" /> ପରିବରà­à¬¤à­à¬¤à­‡ ସମସà­à¬¤ <ph name="PROTOCOL" /> ଲିଙà­à¬•à­â€à¬—à­à­œà¬¿à¬•à­ ଖୋଲିବା ପାଇଠ<ph name="HANDLER_HOSTNAME" />କୠଅନà­à¬®à¬¤à¬¿ ଦେବେ କି?</translation>
<translation id="2354001756790975382">ଅନà­à­Ÿ ବà­à¬•à¬®à¬¾à¬°à­à¬•à¬¸à­</translation>
<translation id="2354430244986887761">Google ସେଫୠବà­à¬°à¬¾à¬‰à¬œà¬¿à¬‚କୠସମà­à¬ªà­à¬°à¬¤à¬¿ <ph name="SITE" />ରେ <ph name="BEGIN_LINK" />ହାନିକାରକ ଆପୠମିଳିଲା<ph name="END_LINK" />।</translation>
<translation id="2355395290879513365">ଆପଣ à¬à¬¹à¬¿ ସାଇଟà­â€Œà¬°à­‡ ଦେଖà­à¬¥à¬¿à¬¬à¬¾ ଛବିଗà­à­œà¬¿à¬•à­ ଆକà­à¬°à¬®à¬£à¬•à¬¾à¬°à­€ ଦେଖିବାରେ ସକà­à¬·à¬® ହୋâ€à¬‡à¬ªà¬¾à¬°à­‡ à¬à¬¬à¬‚ ସେଗà­à­œà¬¿à¬•à­ ସଂଶୋଧନ କରି ଆପଣଙà­à¬• ସହିତ ଛଳନା କରିପାରେ।</translation>
@@ -467,6 +486,7 @@
<translation id="2413528052993050574">à¬à¬¹à¬¿ ସରà­à¬­à¬°à­ à¬à¬¹à¬¾ ପà­à¬°à¬®à¬¾à¬£ କରିପାରିଲା ନାହିଠଯେ, à¬à¬¹à¬¾ à¬à¬• <ph name="DOMAIN" /> ଅଟେ; à¬à¬¹à¬¾à¬° ସà­à¬°à¬•à­à¬·à¬¾ ସାରà­à¬Ÿà¬¿à¬«à¬¿à¬•à­‡à¬Ÿà­ ପà­à¬°à¬¤à­à­Ÿà¬¾à¬¹à¬¾à¬° କରାଯାଇଥାଇପାରେ। à¬à¬¹à¬¾ à¬à¬• ଭà­à¬²à­ କନଫିଗà­â€à¬°à­‡à¬¸à¬¨à­ କିମà­à¬¬à¬¾ ଜଣେ ଆକà­à¬°à¬®à¬£à¬•à¬¾à¬°à­€ ଆପଣଙà­à¬•à¬° ସଂଯୋଗକୠପà­à¬°à¬¤à¬¿à¬°à­‹à¬§ କରà­à¬¥à¬¿à¬¬à¬¾ କାରଣରୠହୋଇପାରେ।</translation>
<translation id="2414886740292270097">ଗାà­</translation>
<translation id="2430968933669123598">Google ଆକାଉଣà­à¬Ÿ ପରିଚାଳନା କରନà­à¬¤à­, ଆପଣଙà­à¬• Google ଆକାଉଣà­à¬Ÿà¬°à­‡ ଆପଣଙà­à¬•à¬° ସୂଚନା, ଗୋପନୀୟତା à¬à¬¬à¬‚ ସà­à¬°à¬•à­à¬·à¬¾à¬•à­ ପରିଚାଳନା କରିବା ପାଇଠEnter ଦବାନà­à¬¤à­</translation>
+<translation id="2436186046335138073">ସମସà­à¬¤ <ph name="PROTOCOL" /> ଲିଙà­à¬•à­ ଖୋଲିବା ପାଇଠ<ph name="HANDLER_HOSTNAME" />କୠଅନà­à¬®à¬¤à¬¿ ଦେବେ?</translation>
<translation id="2438874542388153331">ଡାହାଣ ପଟରେ ଚାରୋଟି ପଞà­à¬šà­</translation>
<translation id="2450021089947420533">ସନà­à¬§à¬¾à¬¨à¬—à­à­œà¬¿à¬•</translation>
<translation id="2463739503403862330">ପୂରଣ କରନà­à¬¤à­</translation>
@@ -474,6 +494,7 @@
<translation id="2465655957518002998">ବିତରଣ ପଦà­à¬§à¬¤à¬¿ ବାଛନà­à¬¤à­</translation>
<translation id="2465688316154986572">ଷà­à¬Ÿà¬¾à¬ªà¬²à­</translation>
<translation id="2465914000209955735">ଆପଣ Chromeରେ ଡାଉନଲୋଡୠକରିଥିବା ଫାଇଲଗà­à¬¡à¬¼à¬¿à¬•à­ ପରିଚାଳନା କରନà­à¬¤à­</translation>
+<translation id="2466004615675155314">ୱେବରୠସୂଚନା ଦେଖାନà­à¬¤à­</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />ନେଟà­â€Œà­±à¬°à­à¬• ଡାà¬à¬—à­à¬¨à­‹à¬·à­à¬Ÿà¬¿à¬•à­â€ ଚାଲà­à¬›à¬¿<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">1-ରà­-N ଅରà­à¬¡à¬°à­</translation>
<translation id="2470767536994572628">ଆପଣ à¬à¬¨à­‹à¬Ÿà­‡à¬¸à¬¨à¬—à­à­œà¬¿à¬•à­ à¬à¬¡à¬¿à¬Ÿà­ କଲେ, à¬à¬¹à¬¿ ଡକà­à­Ÿà­à¬®à­‡à¬£à­à¬Ÿ ସିଙà­à¬—ଲୠପୃଷà­à¬ à¬¾ ଭà­à­Ÿà­ à¬à¬¬à¬‚ à¬à¬¹à¬¾à¬° ମୂଳ ରୋଟେସନକୠଫେରି ଆସିବ</translation>
@@ -494,6 +515,7 @@
<translation id="2523886232349826891">କେବଳ à¬à¬¹à¬¿ ଡିଭାଇସà­â€à¬°à­‡ ସେଭୠକରାଯାଇଛି</translation>
<translation id="2524461107774643265">ଅଧିକ ସୂଚନା ଯୋଗ କରନà­à¬¤à­</translation>
<translation id="2529899080962247600">à¬à¬¹à¬¿ ଫିଲà­à¬¡à¬°à­‡ <ph name="MAX_ITEMS_LIMIT" />ରୠଅଧିକ à¬à¬£à­à¬Ÿà­à¬°à¬¿ ରହିବା ଉଚିତ ନà­à¬¹à­‡à¬à¥¤ ସମସà­à¬¤ ପରବରà­à¬¤à­à¬¤à­€ à¬à¬£à­à¬Ÿà­à¬°à¬¿à¬•à­ ଅଣଦେଖା କରାଯିବ।</translation>
+<translation id="2535585790302968248">ବà­à­Ÿà¬•à­à¬¤à¬¿à¬—ତ ଭାବେ ବà­à¬°à¬¾à¬‰à¬œ କରିବାକୠà¬à¬• ନୂଆ ଇନକଗà­à¬¨à¬¿à¬Ÿà­‹ ଟାବ ଖୋଲନà­à¬¤à­</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{à¬à¬¬à¬‚ ଅଧିକ 1ଟି}other{à¬à¬¬à¬‚ ଅଧିକ #ଟି}}</translation>
<translation id="2536110899380797252">ଠିକଣା ଯୋଗ କରନà­à¬¤à­</translation>
<translation id="2539524384386349900">ଚିହà­à¬¨à¬Ÿ କରନà­à¬¤à­</translation>
@@ -519,7 +541,14 @@
<translation id="2597378329261239068">à¬à¬¹à¬¿ ଡକà­à­Ÿà­à¬®à­‡à¬£à­à¬Ÿ ପାସà­â€Œà­±à¬¾à¬°à­à¬¡ ଦà­à­±à¬¾à¬°à¬¾ ସà­à¬°à¬•à­à¬·à¬¿à¬¤ ଅଟେ। ଦୟାକରି ଗୋଟିଠପାସà­â€Œà­±à¬¾à¬°à­à¬¡ ଲେଖନà­à¬¤à­à¥¤</translation>
<translation id="2609632851001447353">ବିବିଧତା</translation>
<translation id="2610561535971892504">କପି କରିବାକୠକà­à¬²à¬¿à¬•à­ କରନà­à¬¤à­</translation>
+<translation id="2617988307566202237">Chrome ନିମà­à¬¨à­‹à¬•à­à¬¤ ସୂଚନାକୠ<ph name="BEGIN_EMPHASIS" />ସେଭ କରିବ ନାହିà¬<ph name="END_EMPHASIS" />:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ଆପଣଙà­à¬•à¬° ବà­à¬°à¬¾à¬‰à¬œà¬¿à¬‚ ଇତିହାସ
+ <ph name="LIST_ITEM" />କà­à¬•à­€ à¬à¬¬à¬‚ ସାଇଟ ଡାଟା
+ <ph name="LIST_ITEM" />ଫରà­à¬®à¬—à­à­œà¬¿à¬•à¬°à­‡ ଲେଖାଯାଇଥିବା ସୂଚନା
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (à¬à¬¨à¬­à¬²à¬ªà­)</translation>
+<translation id="2623663032199728144">ଆପଣଙà­à¬• ସà­à¬•à­à¬°à¬¿à¬¨ ବିଷୟରେ ଥିବା ସୂଚନାକୠବà­à­Ÿà¬¬à¬¹à¬¾à¬° କରିବା ନିମନà­à¬¤à­‡ ସାଇଟ ପଚାରିପାରେ</translation>
<translation id="2625385379895617796">ଆପଣଙà­à¬•à¬° ଘଣà­à¬Ÿà¬¾ ଆଗà­à¬† ଅଛି</translation>
<translation id="262745152991669301">USB ଡିଭାଇସଗà­à­œà¬¿à¬• ସହ ସଂଯୋଗ କରିବାକୠସାଇଟୠପଚାରିପାରେ</translation>
<translation id="2629325967560697240">Chromeର ସରà­à¬¬à­‹à¬šà­à¬š ସà­à¬¤à¬°à¬° ସà­à¬°à¬•à­à¬·à¬¾ ପାଇବାକà­, <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />ଉନà­à¬¨à¬¤ ସà­à¬°à¬•à­à¬·à¬¾ ଚାଲୠକରନà­à¬¤à­<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -553,6 +582,7 @@
<translation id="2709516037105925701">ସà­à­±à¬¤à¬ƒà¬ªà­‚ରଣ</translation>
<translation id="2713444072780614174">ଧଳା</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />, Chrome ସେଟିଂସରେ ଆପଣଙà­à¬• ପେମେଣà­à¬Ÿ à¬à¬¬à¬‚ କà­à¬°à­‡à¬¡à¬¿à¬Ÿà­ କାରà­à¬¡ ସୂଚନା ପରିଚାଳନା କରିବାକୠTab କରି Enter ଦବାନà­à¬¤à­</translation>
+<translation id="271663710482723385">ପୂରà­à¬£à­à¬£ ସà­à¬•à­à¬°à¬¿à¬¨à¬°à­ ବାହାରି ଯିବାକୠ|<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| ଦବାନà­à¬¤à­</translation>
<translation id="2721148159707890343">ଅନà­à¬°à­‹à¬§ ସଫଳ ହୋଇଛି</translation>
<translation id="2723669454293168317">Chrome ସେଟିଂସରେ à¬à¬• ସà­à¬°à¬•à­à¬·à¬¾ ଯାଞà­à¬š ଚଲାନà­à¬¤à­</translation>
<translation id="2726001110728089263">ସାଇଡୠଟà­à¬°à­‡</translation>
@@ -583,6 +613,7 @@
<translation id="2850739647070081192">ନିମନà­à¬¤à­à¬°à¬£ କରନà­à¬¤à­ (à¬à¬¨à¬­à¬²à¬ªà­)</translation>
<translation id="2856444702002559011">ଆକà­à¬°à¬®à¬£à¬•à¬¾à¬°à­€ ହà­à¬à¬¤ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />ରୠଆପଣଙà­à¬•à¬° ସୂଚନା ଚୋରାଇବାକୠଚେଷà­à¬Ÿà¬¾ କରିପାରନà­à¬¤à¬¿ (ଉଦାହରଣ ସà­à­±à¬°à­‚ପ, ପାସà­â€à­±à¬°à­à¬¡, ମେସେଜୠକିମà­à¬¬à¬¾ କà­à¬°à­‡à¬¡à¬¿à¬Ÿà­â€ କାରà­à¬¡)। <ph name="BEGIN_LEARN_MORE_LINK" />ଅଧିକ ଜାଣନà­à¬¤à­<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">à¬à¬¹à¬¿ ସାଇଟୠଅନଧିକାର ପà­à¬°à¬¬à­‡à¬¶ କରିଥିବା କିମà­à¬¬à¬¾ ବିଭà­à¬°à¬¾à¬¨à­à¬¤à¬¿à¬•à¬° ବିଜà­à¬žà¬¾à¬ªà¬¨ ପà­à¬°à¬¦à¬°à­à¬¶à¬¨ କରà­à¬›à¬¿à¥¤</translation>
+<translation id="286512204874376891">ଆପଣଙà­à¬•à­ ସମà­à¬­à¬¾à¬¬à­à­Ÿ ଠକାମୀରୠରକà­à¬·à¬¾ କରିବାରେ ସାହାଯà­à­Ÿ କରିବା ପାଇà¬, à¬à¬• ଭରà­à¬šà­à¬†à¬² କାରà­à¬¡ ଆପଣଙà­à¬• ପà­à¬°à¬•à­ƒà¬¤ କାରà­à¬¡à¬° ସୂଚନାକୠଲà­à¬šà¬¾à¬‡à¬¥à¬¾à¬à¥¤ <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">ବନà­à¬§à­à¬¤à­à¬µà¬ªà­‚ରà­à¬£à­à¬£</translation>
<translation id="2876489322757410363">à¬à¬• à¬à¬•à­à¬¸à¬Ÿà¬°à­à¬¨à¬²à­ ଆପà­à¬²à¬¿à¬•à­‡à¬¸à¬¨à­ ମାଧà­à­Ÿà¬®à¬°à­‡ ପେମେଣà­à¬Ÿ କରିବାକୠଇନକଗà­à¬¨à¬¿à¬Ÿà­‹ ମୋଡରୠବାହାରି ଯାଉଛନà­à¬¤à¬¿à¥¤ ଜାରି ରଖିବେ?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />, Chrome ସେଟିଂସରେ ଆପଣଙà­à¬• ସà­à¬°à¬•à­à¬·à¬¿à¬¤ ବà­à¬°à¬¾à¬‰à¬œà¬¿à¬‚ à¬à¬¬à¬‚ ଆହà­à¬°à¬¿ ଅନେକ କିଛି ପରିଚାଳନା କରିବାକୠTab କରି Enter ଦବାନà­à¬¤à­</translation>
@@ -607,6 +638,7 @@
<translation id="2930577230479659665">ପà­à¬°à¬¤à­à­Ÿà­‡à¬• କପି ପରେ ଟà­à¬°à¬¿à¬®à­ କରନà­à¬¤à­</translation>
<translation id="2932085390869194046">ପାସà­â€Œà­±à¬°à­à¬¡ ପà­à¬°à¬¸à­à¬¤à¬¾à¬¬ କରନà­à¬¤à­...</translation>
<translation id="2934466151127459956">ସରକାରୀ-ଚିଠି</translation>
+<translation id="2938225289965773019"><ph name="PROTOCOL" /> ଲିଙà­à¬•à­â€Œ ଖୋଲନà­à¬¤à­</translation>
<translation id="2941952326391522266">à¬à¬¹à¬¾ <ph name="DOMAIN" /> ଅଟେ ବୋଲି à¬à¬¹à¬¿ ସରà­à¬­à¬°à­ ପà­à¬°à¬®à¬¾à¬£ କରିପାରିଲା ନାହିà¬; à¬à¬¹à¬¾à¬° ସà­à¬°à¬•à­à¬·à¬¾ ସାରà­à¬Ÿà¬¿à¬«à¬¿à¬•à­‡à¬Ÿà­ <ph name="DOMAIN2" /> ତରଫରୠଅଟେ। à¬à¬¹à¬¾ à¬à¬• ଭà­à¬² କନଫିଗà­â€Œà¬°à­‡à¬¸à¬¨à­ କିମà­à¬¬à¬¾ ଜଣେ ଆକà­à¬°à¬®à¬£à¬•à¬¾à¬°à­€ ଆପଣଙà­à¬•à¬° ସଂଯୋଗକୠପà­à¬°à¬¤à¬¿à¬°à­‹à¬§ କରà­à¬¥à¬¿à¬¬à¬¾ ଯୋଗà­à¬ ହୋଇଥାଇପାରେ।</translation>
<translation id="2943895734390379394">ଅପଲୋଡୠସମୟ:</translation>
<translation id="2948083400971632585">ଆପଣ ସେଟିଂସୠପୃଷà­à¬ à¬¾à¬°à­ à¬à¬• ସଂଯୋଗ ପାଇଠକନà­â€à¬«à¬¿à¬—ରୠକରାଯାଇଥିବା କୌଣସି ପà­à¬°à¬•à­à¬¸à¬¿à¬•à­ ଅକà­à¬·à¬® କରିପାରିବେ।</translation>
@@ -639,6 +671,7 @@
<translation id="3037605927509011580">ଇସ!</translation>
<translation id="3041612393474885105">ସାରà­à¬Ÿà¬¿à¬«à¬¿à¬•à­‡à¬Ÿà­ ସୂଚନା</translation>
<translation id="3044034790304486808">ଆପଣଙà­à¬• ରିସରà­à¬šà­à¬š ପà­à¬£à¬¿ ଆରମà­à¬­ କରନà­à¬¤à­</translation>
+<translation id="305162504811187366">ଟାଇମଷà­à¬Ÿà¬¾à¬®à­à¬ª, ହୋଷà­à¬Ÿ à¬à¬¬à¬‚ କà­à¬²à¬¾à¬à¬£à­à¬Ÿ ସେସନ idଗà­à¬¡à¬¼à¬¿à¬• ସମେତ Chrome ରିମୋଟ ଡେସà­à¬•à¬Ÿà¬ª ଇତିହାସ</translation>
<translation id="3060227939791841287">C9 (à¬à¬¨à¬­à¬²à¬ªà­)</translation>
<translation id="3061707000357573562">ପà­à­Ÿà¬¾à¬šà­ ସେବା</translation>
<translation id="306573536155379004">ଗେମୠଆରମà­à¬­ ହୋଇଛି।</translation>
@@ -677,6 +710,7 @@
<translation id="3197136577151645743">ଆପଣ କେତେବେଳେ à¬à¬¹à¬¿ ଡିଭାଇସକୠସକà­à¬°à¬¿à­Ÿ ଭାବେ ବà­à­Ÿà¬¬à¬¹à¬¾à¬° କରà­à¬›à¬¨à­à¬¤à¬¿ ତାହା ଜାଣିବାକୠସାଇଟୠପଚାରିପାରେ</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />, Chrome ସେଟିଂସରେ ଆପଣ କେଉଠସୂଚନା ସିଙà­à¬•à­ କରନà­à¬¤à¬¿ ତାହା ପରିଚାଳନା କରିବାକୠTab କରି Enter ଦବାନà­à¬¤à­</translation>
<translation id="320323717674993345">ପେମେଣà­à¬Ÿ ବାତିଲୠକରନà­à¬¤à­</translation>
+<translation id="3203366800380907218">ୱେବରà­</translation>
<translation id="3207960819495026254">ବà­à¬•à­â€à¬®à¬¾à¬°à­à¬• କରାଯାଇଛି</translation>
<translation id="3209034400446768650">ପୃଷà­à¬ à¬¾ ଶà­à¬³à­à¬• ଲାଗୠହୋଇପାରେ</translation>
<translation id="3212581601480735796"><ph name="HOSTNAME" />ରେ ଆପଣଙà­à¬•à¬° କାରà­à¬¯à­à­Ÿà¬•à¬³à¬¾à¬ªà¬•à­ ନିରୀକà­à¬·à¬£ କରାଯାଉଛି</translation>
@@ -693,10 +727,12 @@
<translation id="3234666976984236645">ସରà­à¬¬à¬¦à¬¾ à¬à¬¹à¬¿ ସାଇଟà­â€â€à¬°à­‡ ଗà­à¬°à­à¬¤à­à­±à¬ªà­‚ରà­à¬£à­à¬£ ବିଷୟବସà­à¬¤à­ ଚିହà­à¬¨à¬Ÿ କରେ</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />, ଆପଣଙà­à¬• ବà­à¬°à¬¾à¬‰à¬œà¬°à¬° ଲà­à¬• କଷà­à¬Ÿà¬®à¬¾à¬‡à¬œ କରିବାକୠTab କରି Enter ଦବାନà­à¬¤à­</translation>
<translation id="3240791268468473923">ସà­à¬°à¬•à­à¬·à¬¿à¬¤ ପେମେଣà­à¬Ÿ କà­à¬°à­‡à¬¡à­‡à¬¨à¬¸à¬¿à¬†à¬²à­ ସହ ମେଳ ହେଉଥିବା କୌଣସି କà­à¬°à­‡à¬¡à­‡à¬¨à¬¸à¬¿à¬†à¬²à­ ସିଟୠଖୋଲାଯାଇନାହିà¬</translation>
+<translation id="324180406144491771">“<ph name="HOST_NAME" />†ଲିଙà­à¬•à¬—à­à¬¡à¬¼à¬¿à¬•à­ ବà­à¬²à¬• କରାଯାଇଛି</translation>
<translation id="3249845759089040423">ଗà­à¬°à­à¬­à¬¿</translation>
<translation id="3252266817569339921">ଫà­à¬°à­‡à¬žà­à¬š</translation>
<translation id="3257954757204451555">à¬à¬¹à¬¿ ସୂଚନା ପଛରେ କିଠଅଛନà­à¬¤à¬¿?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />, Google Calendarରେ ଶୀଘà­à¬° à¬à¬• ନୂଆ ଇଭେଣà­à¬Ÿ ତିଆରି କରିବାକୠTab କରି Enter ଦବାନà­à¬¤à­</translation>
+<translation id="3261488570342242926">ଭରà­à¬šà­à¬†à¬² କାରà­à¬¡ ବିଷୟରେ ଜାଣନà­à¬¤à­</translation>
<translation id="3264837738038045344">"Chrome ସେଟିଂସୠପରିଚାଳନା କରନà­à¬¤à­" ବଟନà­, ଆପଣଙà­à¬• Chrome ସେଟିଂସୠଭିଜିଟୠକରିବାକୠEnter ଦବାନà­à¬¤à­</translation>
<translation id="3266793032086590337">ମୂଲà­à­Ÿ (ବିବାଦରେ ଅଛି)</translation>
<translation id="3268451620468152448">ଖୋଲାଥିବା ଟାବà­â€Œà¬—à­à¬¡à¬¼à¬¿à¬•</translation>
@@ -710,6 +746,7 @@
<translation id="3288238092761586174">ଆପଣଙà­à¬• ପେମେଣà­à¬Ÿ ଯାଞà­à¬š କରିବା ପାଇଠ<ph name="URL" />କୠଅତିରିକà­à¬¤ ଷà­à¬Ÿà­‡à¬ªà­ ନେବାର ଆବଶà­à­Ÿà¬•à¬¤à¬¾ ହୋଇପାରେ</translation>
<translation id="3293642807462928945"><ph name="POLICY_NAME" /> ନୀତି ସମà­à¬µà¬¨à­à¬§à¬°à­‡ ଅଧିକ ଜାଣନà­à¬¤à­</translation>
<translation id="3295444047715739395">Chrome ସେଟିଂସରେ ଆପଣଙà­à¬• ପାସୱାରà­à¬¡à¬—à­à­œà¬¿à¬• ଦେଖନà­à¬¤à­ à¬à¬¬à¬‚ ପରିଚାଳନା କରନà­à¬¤à­</translation>
+<translation id="3303795387212510132"><ph name="PROTOCOL_SCHEME" /> ଲିଙà­à¬•à¬—à­à­œà¬¿à¬• ଖୋଲିବା ପାଇଠଆପକୠଅନà­à¬®à¬¤à¬¿ ଦେବେ?</translation>
<translation id="3303855915957856445">କୌଣସି ସନà­à¬§à¬¾à¬¨ ଫଳାଫଳଗà­à¬¡à¬¿à¬• ଖୋଜି ପାଇଲା ନାହିà¬</translation>
<translation id="3304073249511302126">ବà­à¬²à­à¬Ÿà­à¬¥à­ ସà­à¬•à¬¾à¬¨à¬¿à¬‚</translation>
<translation id="3308006649705061278">ସାଙà­à¬—ଠନିକ†ୟà­à¬¨à¬¿à¬Ÿà­â€Œ (OU)</translation>
@@ -723,12 +760,6 @@
<translation id="3345782426586609320">ଆଖି</translation>
<translation id="3355823806454867987">ପà­à¬°à­‹à¬•à­à¬¸à¬¿ ସେଟିଂସà­â€Œ ପରିବରà­à¬¤à­à¬¤à¬¨ କରନà­à¬¤à­...</translation>
<translation id="3360103848165129075">ପେମେଣà­à¬Ÿ ହà­à­Ÿà¬¾à¬£à­à¬¡à¬²à¬°à­ ସିଟà­</translation>
-<translation id="3361596688432910856">Chrome ନିମà­à¬¨à­‹à¬•à­à¬¤ ସୂଚନାକୠ<ph name="BEGIN_EMPHASIS" />ସେଭୠକରିବ ନାହିà¬<ph name="END_EMPHASIS" />:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />ଆପଣଙà­à¬•à¬° ବà­à¬°à¬¾à¬‰à¬œà¬¿à¬‚ ଇତିବୃତà­à¬¤à¬¿
- <ph name="LIST_ITEM" />କà­à¬•à­€ ଓ ସାଇଟୠଡାଟା
- <ph name="LIST_ITEM" />ଫରà­à¬®à¬°à­‡ ଲେଖାଯାଇଥିବା ସୂଚନା
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">à¬à¬¹à¬¿ ନୀତି ସà­à­±à¬šà¬¾à¬³à¬¿à¬¤ ଭାବେ ଅଗà­à¬°à¬¾à¬¹à­à­Ÿ କରାଯାଇଥିବା <ph name="OLD_POLICY" /> ନୀତିରୠକପି ହୋଇଥିଲା। à¬à¬¹à¬¾ ପରିବରà­à¬¤à­à¬¤à­‡ ଆପଣ à¬à¬¹à¬¿ ନୀତି ବà­à­Ÿà¬¬à¬¹à¬¾à¬° କରିବା ଉଚିତ।</translation>
<translation id="3364869320075768271"><ph name="URL" /> ଆପଣଙà­à¬•à¬° ଭରà­à¬šà­à¬†à¬²à­ ରିଆଲିଟୀ ଡିଭାଇସୠà¬à¬¬à¬‚ ଡାଟାକୠବà­à­Ÿà¬¬à¬¹à¬¾à¬° କରିବାକୠଚାହà­à¬à¬›à¬¿</translation>
<translation id="3366477098757335611">କାରà­à¬¡à¬—à­à­œà¬¿à¬• ଦେଖନà­à¬¤à­</translation>
@@ -811,7 +842,6 @@
<translation id="3587738293690942763">ମଧà­à­Ÿà¬®</translation>
<translation id="3592413004129370115">ଇଟାଲିଆନୠ(à¬à¬¨à¬­à¬²à¬ªà­)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{ଆପଣ ଯେ କୌଣସି ସମୟରେ ଆପଣଙà­à¬• ଗୋଷà­à¬ à­€ ରିସେଟୠକରିପାରିବେ। à¬à¬• ନୂଆ ଗୋଷà­à¬ à­€à¬°à­‡ ଯୋଗ ଦେବା ପାଇଠଗୋଟିଠଦିନ ସମୟ ଲାଗିଥାà¬à¥¤}=1{ଆପଣ ଯେ କୌଣସି ସମୟରେ ଆପଣଙà­à¬• ଗୋଷà­à¬ à­€ ରିସେଟୠକରିପାରିବେ। à¬à¬• ନୂଆ ଗୋଷà­à¬ à­€à¬°à­‡ ଯୋଗ ଦେବା ପାଇଠଗୋଟିଠଦିନ ସମୟ ଲାଗିଥାà¬à¥¤}other{ଆପଣ ଯେ କୌଣସି ସମୟରେ ଆପଣଙà­à¬• ଗୋଷà­à¬ à­€ ରିସେଟୠକରିପାରିବେ। à¬à¬• ନୂଆ ଗୋଷà­à¬ à­€à¬°à­‡ ଯୋଗ ଦେବା ପାଇଠ{NUM_DAYS} ଦିନ ସମୟ ଲାଗିଥାà¬à¥¤}}</translation>
-<translation id="3596012367874587041">ଆପ ସେଟିଂସ</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">ଆପଣଙà­à¬• ଆଡମିନିଷà­à¬Ÿà­à¬°à­‡à¬Ÿà¬°à¬™à­à¬• ଦà­à­±à¬¾à¬°à¬¾ ଆପà­à¬²à¬¿à¬•à­‡à¬¸à¬¨à­ ବà­à¬²à¬•à­ କରାଯାଇଛି</translation>
<translation id="3608932978122581043">ଫିଡୠଓରିà¬à¬£à­à¬Ÿà­‡à¬¸à¬¨à­</translation>
@@ -853,6 +883,7 @@
<translation id="370972442370243704">ସନà­à¬§à¬¾à¬¨à¬—à­à­œà¬¿à¬•à­ ଚାଲୠକରନà­à¬¤à­</translation>
<translation id="3711895659073496551">ନିଲମà­à¬¬à¬¨ କରନà­à¬¤à­</translation>
<translation id="3712624925041724820">ଲାଇସେନà­à¬¸à¬° ମିଆଦ ଶେଷ ହୋଇଛି</translation>
+<translation id="3714633008798122362">ୱେବୠକà­à­Ÿà¬¾à¬²à­‡à¬£à­à¬¡à¬°à­</translation>
<translation id="3714780639079136834">ମୋବାଇଲà­â€Œ ଡାଟା କିମà­à¬¬à¬¾ ୱାଇ-ଫାଇ ଚାଲୠକରନà­à¬¤à­</translation>
<translation id="3715597595485130451">ୱାଇ-ଫାଇ ସହ ସଂଯୋଗ କରନà­à¬¤à­</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />ପà­à¬°à­‹à¬•à­à¬¸à¬¿ ଓ ଫାୟାରୱାଲୠà¬à¬¬à¬‚ DNS କନà­â€Œà¬«à¬¿à¬—à­â€Œà¬°à­‡à¬¸à¬¨à­â€Œ ଯାଞà­à¬š ହେଉଛି<ph name="END_LINK" /></translation>
@@ -914,6 +945,7 @@
<translation id="3906954721959377182">ଟାବà­â€Œà¬²à­‡à¬Ÿà­</translation>
<translation id="3909477809443608991"><ph name="URL" /> ସà­à¬°à¬•à­à¬·à¬¿à¬¤ ବିଷୟବସà­à¬¤à­ ଚଳାଇବାକୠଚାହà­à¬à¬›à¬¿à¥¤ ଆପଣଙà­à¬•à¬° ଡିଭାଇସà­â€Œà¬° ପରିଚୟକୠGoogle ଦà­à­±à¬¾à¬°à¬¾ ଯାଞà­à¬š କରାଯିବ à¬à¬¬à¬‚ à¬à¬¹à¬¿ ସାଇଟୠଦà­à­±à¬¾à¬°à¬¾ ଆକà­à¬¸à­‡à¬¸à­ କରାଯାଇପାରେ।</translation>
<translation id="3909695131102177774"><ph name="LABEL" /><ph name="ERROR" /></translation>
+<translation id="3927932062596804919">ଅସà­à¬µà­€à¬•à¬¾à¬°</translation>
<translation id="3939773374150895049">CVC ପରିବରà­à¬¤à­à¬¤à­‡ WebAuthn ବà­à­Ÿà¬¬à¬¹à¬¾à¬° କରିବେ?</translation>
<translation id="3946209740501886391">ସରà­à¬¬à¬¦à¬¾ à¬à¬¹à¬¿ ସାଇଟà­â€Œà¬°à­‡ ପଚାରନà­à¬¤à­</translation>
<translation id="3947595700203588284">MIDI ଡିଭାଇସଗà­à­œà¬¿à¬• ସହ ସଂଯୋଗ କରିବାକୠସାଇଟୠପଚାରିପାରେ</translation>
@@ -934,6 +966,7 @@
<translation id="3987940399970879459">1 MBରୠକମୠଅଛି</translation>
<translation id="3990250421422698716">ଜଗୠଅଫà­â€Œà¬¸à­‡à¬Ÿà­</translation>
<translation id="3996311196211510766">à¬à¬‡ ସାଇଟକୠକରାଯାଇଥିବା ସମସà­à¬¤ ଅନà­à¬°à­‹à¬§à¬°à­‡ à¬à¬• ମୂଳ ନୀତି ଲାଗୠକରାଯାଉ ବୋଲି à¬à¬¹à¬¿ <ph name="ORIGIN" /> ସାଇଟୠଅନà­à¬°à­‹à¬§ କରିଛି, କିନà­à¬¤à­ ଠନୀତି ବରà­à¬¤à­à¬¤à¬®à¬¾à¬¨ ଲାଗୠକରାଯାଇପାରିବ ନାହିà¬à¥¤</translation>
+<translation id="4009243425692662128">ଆପଣ ପà­à¬°à¬¿à¬£à­à¬Ÿ କରà­à¬¥à¬¿à¬¬à¬¾ ପୃଷà­à¬ à¬¾à¬—à­à­œà¬¿à¬•à¬° ବିଷୟବସà­à¬¤à­ ବିଶà­à¬³à­‡à¬·à¬£ ପାଇଠGoogle Cloud କିମà­à¬¬à¬¾ ତୃତୀୟ ପକà­à¬·à¬—à­à­œà¬¿à¬•à­ ପଠାଯାà¬à¥¤ ଉଦାହରଣ ସà­à¬µà¬°à­‚ପ, à¬à¬¹à¬¾à¬•à­ ସମà­à¬¬à­‡à¬¦à¬¨à¬¶à­€à¬³ ଡାଟା ପାଇଠସà­à¬•à¬¾à¬¨ କରାଯାଇପାରେ।</translation>
<translation id="4010758435855888356">ଷà­à¬Ÿà­‹à¬°à­‡à¬œà­ ଆକà­à¬¸à­‡à¬¸à­ କରିବାର ଅନà­à¬®à¬¤à¬¿ ଦେବେ?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{{COUNT}ଟି ପୃଷà­à¬ à¬¾ ଥିବା PDF ଡକà­à­Ÿà­à¬®à­‡à¬£à­à¬Ÿ}other{{COUNT}ଟି ପୃଷà­à¬ à¬¾ ଥିବା PDF ଡକà­à­Ÿà­à¬®à­‡à¬£à­à¬Ÿ}}</translation>
<translation id="4023431997072828269">à¬à¬¹à¬¿ ଫରà­à¬®à¬Ÿà¬¿ à¬à¬• ଅସà­à¬°à¬•à­à¬·à¬¿à¬¤ ସଂଯୋଗ ବà­à­Ÿà¬¬à¬¹à¬¾à¬° କରି ଦାଖଲ କରାଯାଇଥିବା ଯୋଗà­à¬ ଆପଣଙà­à¬• ସୂଚନା ଅନà­à­Ÿà¬®à¬¾à¬¨à¬™à­à¬•à­ ଦୃଶà­à­Ÿà¬®à¬¾à¬¨ ହେବ।</translation>
@@ -1024,6 +1057,7 @@
<translation id="4250680216510889253">ନାହିà¬</translation>
<translation id="4253168017788158739">ନୋଟà­</translation>
<translation id="425582637250725228">ଆପଣ କରିଥିବା ପରିବରà­à¬¤à­à¬¤à¬¨à¬—à­à­œà¬¿à¬• ସେଭୠହୋଇନପାରେ।</translation>
+<translation id="425869179292622354">à¬à¬• ଭରà­à¬šà­à¬†à¬² କାରà­à¬¡ ମାଧà­à­Ÿà¬®à¬°à­‡ à¬à¬¹à¬¾à¬•à­ ଅଧିକ ସà­à¬°à¬•à­à¬·à¬¿à¬¤ କରିବେ?</translation>
<translation id="4258748452823770588">ଖରାପ ସà­à¬¬à¬¾à¬•à­à¬·à¬°</translation>
<translation id="4261046003697461417">ସà­à¬°à¬•à­à¬·à¬¿à¬¤ ଡକà­à­Ÿà­à¬®à­‡à¬£à­à¬Ÿà¬—à­à¬¡à¬¼à¬¿à¬• ବà­à­Ÿà¬¾à¬–à­à­Ÿà¬¾ କରାଯାଇପାରିବ ନାହିà¬</translation>
<translation id="4265872034478892965">ଆପଣଙà­à¬•à¬° ବà­à­Ÿà¬¬à¬¸à­à¬¥à¬¾à¬ªà¬•à¬™à­à¬• ଦà­à­±à¬¾à¬°à¬¾ ଅନà­à¬®à¬¤à¬¿ ପà­à¬°à¬¾à¬ªà­à¬¤</translation>
@@ -1086,6 +1120,7 @@
<translation id="4434045419905280838">ପପà­-ଅପୠà¬à¬¬à¬‚ ରିଡାଇରେକà­â€Œà¬Ÿ</translation>
<translation id="4435702339979719576">ପୋଷà­à¬Ÿà¬•à¬¾à¬°à­à¬¡)</translation>
<translation id="443673843213245140">à¬à¬• ପà­à¬°à­‹à¬•à­à¬¸à¬¿à¬° ବà­à­Ÿà¬¬à¬¹à¬¾à¬° ଅକà­à¬·à¬® କରାଯାଇଛି କିନà­à¬¤à­ à¬à¬• ସà­à¬¨à¬¿à¬°à­à¬¦à­à¬¦à¬¿à¬·à­à¬Ÿ ପà­à¬°à¬•à­à¬¸à¬¿ କନà­â€Œà¬«à¬¿à¬—à­â€Œà¬°à­‡à¬¸à¬¨à­ ନିରà­à¬¦à­à¬¦à¬¿à¬·à­à¬Ÿ କରାଯାଇଛି।</translation>
+<translation id="4441832193888514600">à¬à¬¹à¬¿ ନୀତିକୠକେବଳ à¬à¬• କà­à¬²à¬¾à¬‰à¬¡ ଉପଯୋଗକରà­à¬¤à­à¬¤à¬¾ ନୀତି ଭାବରେ ସେଟ କରାଯାଇପାରà­à¬¥à¬¿à¬¬à¬¾ ଯୋଗà­à¬ à¬à¬¹à¬¾à¬•à­ ଅଣଦେଖା କରାଯାଇଛି।</translation>
<translation id="4450893287417543264">ଆଉ ଦେଖାନà­à¬¤à­ ନାହିà¬</translation>
<translation id="4451135742916150903">HID ଡିଭାଇସଗà­à­œà¬¿à¬• ସହ ସଂଯୋଗ କରିବାକୠସାଇଟୠପଚାରିପାରେ</translation>
<translation id="4452328064229197696">ଆପଣ à¬à¬¬à­‡ ବà­à­Ÿà¬¬à¬¹à¬¾à¬° କରିଥିବା ପାସୱାରà­à¬¡ à¬à¬• ଡାଟା ଉଲà­à¬²à¬™à­à¬˜à¬¨à¬°à­‡ ମିଳିଛି। ଆପଣଙà­à¬• ଆକାଉଣà­à¬Ÿà¬—à­à­œà¬¿à¬•à­ ସà­à¬°à¬•à­à¬·à¬¿à¬¤ ରଖିବା ପାଇà¬, Google ପାସୱାରà­à¬¡ ମà­à­Ÿà¬¾à¬¨à­‡à¬œà¬° ଆପଣଙà­à¬• ଦà­à­±à¬¾à¬°à¬¾ ସେଭ କରାଯାଇଥିବା ପାସୱାରà­à¬¡à¬—à­à­œà¬¿à¬•à¬° ଯାଞà­à¬š କରିବାକୠସà­à¬ªà¬¾à¬°à¬¿à¬¶ କରେ।</translation>
@@ -1141,6 +1176,7 @@
<translation id="4628948037717959914">ଫଟୋ</translation>
<translation id="4631649115723685955">କà­à­Ÿà¬¾à¬¸à¬¬à­à­Ÿà¬¾à¬•à­ ଲିଙà­à¬•à­ କରାଯାଇଛି</translation>
<translation id="4636930964841734540">ସୂଚନା</translation>
+<translation id="4638670630777875591">Chromiumରେ ଇନକଗà­à¬¨à¬¿à¬Ÿà­‹ ମୋଡ</translation>
<translation id="464342062220857295">ଫିଚରà­â€à¬—à­à­œà¬¿à¬•à¬° ସନà­à¬§à¬¾à¬¨ କରନà­à¬¤à­</translation>
<translation id="4644670975240021822">ଓଲଟା ଅରà­à¬¡à¬°à¬°à­‡ ଫେସୠଡାଉନà­</translation>
<translation id="4646534391647090355">ମୋତେ ବରà­à¬¤à­à¬¤à¬®à¬¾à¬¨ ସେଠାକୠନେଇଚାଲନà­à¬¤à­</translation>
@@ -1161,6 +1197,7 @@
<translation id="4708268264240856090">ଆପଣଙà­à¬•à¬° ସଂଯୋଗରେ ବà­à­Ÿà¬¾à¬˜à¬¾à¬¤ ହୋâ€à¬‡à¬¥à¬¿à¬²à¬¾</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />ଚାଲà­à¬¥à¬¿à¬¬à¬¾ ୱିଣà­à¬¡à­‹ ନେଟà­â€Œà­±à¬°à­à¬• ଡାଇଗà­à¬¨à­‹à¬·à­à¬Ÿà¬¿à¬•à­à¬¸<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426"><ph name="USERNAME" />ଙà­à¬• ପାଇଠପାସà­â€Œà­±à¬°à­à¬¡</translation>
<translation id="4724144314178270921">ଆପଣଙà­à¬• କà­à¬²à¬¿à¬ªà¬¬à­‹à¬°à­à¬¡à¬°à­‡ ଥିବା ଟେକà­à¬¸à¬Ÿà­ à¬à¬¬à¬‚ ଛବିଗà­à­œà¬¿à¬• ଦେଖିବାକୠସାଇଟୠପଚାରିପାରେ</translation>
<translation id="4726672564094551039">ନୀତିଗà­à­œà¬¿à¬•à­ ପà­à¬¨à¬ƒ ଲୋଡୠକରନà­à¬¤à­</translation>
<translation id="4728558894243024398">ପà­à¬²à¬¾à¬Ÿà­â€Œà¬«à¬°à­à¬®</translation>
@@ -1182,6 +1219,7 @@
<translation id="4757993714154412917">ଆପଣ à¬à¬¬à­‡ à¬à¬• ପà­à¬°à¬¤à¬¾à¬°à¬£à¬¾à¬®à­‚ଳକ ସାଇଟରେ ଆପଣଙà­à¬• ପାସୱାରà­à¬¡ ଲେଖିଛନà­à¬¤à¬¿à¥¤ ଆପଣଙà­à¬• ଆକାଉଣà­à¬Ÿà¬—à­à¬¡à¬¼à¬¿à¬•à­ ସà­à¬°à¬•à­à¬·à¬¿à¬¤ କରିବା ପାଇà¬, Chromium ଆପଣଙà­à¬• ଦà­à­±à¬¾à¬°à¬¾ ସେଭ କରାଯାଇଥିବା ପାସୱାରà­à¬¡à¬—à­à­œà¬¿à¬•à¬° ଯାଞà­à¬š କରିବାକୠସà­à¬ªà¬¾à¬°à¬¿à¬¶ କରେ।</translation>
<translation id="4758311279753947758">ଯୋଗାଯୋଗ ସୂଚନା ଯୋଗ କରନà­à¬¤à­</translation>
<translation id="4761104368405085019">ଆପଣଙà­à¬•à¬° ମାଇକà­à¬°à­‹à¬«à­‹à¬¨à­ ବà­à­Ÿà¬¬à¬¹à¬¾à¬° କରନà­à¬¤à­</translation>
+<translation id="4761869838909035636">Chrome ସà­à¬°à¬•à­à¬·à¬¾ ଯାଞà­à¬š ଚଲାନà­à¬¤à­</translation>
<translation id="4764776831041365478"><ph name="URL" />ରେ ଥିବା ୱେବà­â€Œà¬ªà­ƒà¬·à­à¬ à¬¾à¬Ÿà¬¿ ଅସà­à¬¥à¬¾à­Ÿà­€à¬°à­‚ପେ ଡାଉନà­â€Œ ଥାଇପାରେ କିମà­à¬¬à¬¾ ସà­à¬¥à¬¾à­Ÿà­€à¬­à¬¾à¬¬à­‡ à¬à¬• ନୂତନ ୱେବୠଠିକଣାକୠସà­à¬¥à¬¾à¬¨à¬¾à¬¨à­à¬¤à¬° ହୋଇପାରେ।</translation>
<translation id="4766713847338118463">ତଳ ପଟରେ ଦà­à¬‡à¬Ÿà¬¿ ଷà­à¬Ÿà¬¾à¬ªà¬²à­</translation>
<translation id="4771973620359291008">à¬à¬• ଅଜà­à¬žà¬¾à¬¤ ତୃଟି ସଂଘଟିତ ହୋଇଅଛି ।</translation>
@@ -1202,12 +1240,6 @@
<translation id="4819347708020428563">ଡିଫଲà­à¬Ÿ ଭà­à­Ÿà­à¬°à­‡ à¬à¬¨à­‹à¬Ÿà­‡à¬¸à¬¨à¬—à­à­œà¬¿à¬•à­ à¬à¬¡à¬¿à¬Ÿà­ କରିବେ?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />, ଶୀଘà­à¬° à¬à¬• ନୂଆ Google Sheet ତିଆରି କରିବାକୠTab କରି Enter ଦବାନà­à¬¤à­</translation>
<translation id="4825507807291741242">ଶକà­à¬¤à¬¿à¬¶à¬¾à¬³à­€</translation>
-<translation id="4827402517081186284">ଇନକଗà­à¬¨à¬¿à¬Ÿà­‹ ଆପଣଙà­à¬•à­ ଅନଲାଇନରେ ଅଦୃଶà­à­Ÿ କରେ ନାହିà¬:
-<ph name="BEGIN_LIST" />
-<ph name="LIST_ITEM" />ଆପଣ ସାଇଟଗà­à­œà¬¿à¬•à­ ଭିଜିଟୠକଲେ ସେଗà­à­œà¬¿à¬• à¬à¬¹à¬¾ ବିଷୟରେ ଜାଣିପାରେ<ph name="END_LIST_ITEM" />
-<ph name="LIST_ITEM" />ନିଯà­à¬•à­à¬¤à¬¿à¬¦à¬¾à¬¤à¬¾ କିମà­à¬¬à¬¾ ସà­à¬•à­à¬²à­, ବà­à¬°à¬¾à¬‰à¬œà¬¿à¬‚ କାରà­à¬¯à­à­Ÿà¬•à¬³à¬¾à¬ªà¬•à­ ଟà­à¬°à¬¾à¬•à­ କରିପାରିବେ<ph name="END_LIST_ITEM" />
-<ph name="LIST_ITEM" />ଇଣà­à¬Ÿà¬°à¬¨à­‡à¬Ÿà­ ସେବା ପà­à¬°à¬¦à¬¾à¬¨à¬•à¬¾à¬°à­€à¬—à­à­œà¬¿à¬• ୱେବୠଟà­à¬°à¬¾à¬«à¬¿à¬•à¬•à­ ମନିଟରୠକରିପାରନà­à¬¤à¬¿<ph name="END_LIST_ITEM" />
-<ph name="END_LIST" /></translation>
<translation id="483241715238664915">ଚେତାବନୀ ଚାଲୠକରନà­à¬¤à­</translation>
<translation id="4838327282952368871">ଡà­à¬°à¬¿à¬®à¬¿</translation>
<translation id="4840250757394056958">ଆପଣଙà­à¬• Chrome ଇତିହାସ ଦେଖନà­à¬¤à­</translation>
@@ -1219,12 +1251,12 @@
<translation id="4854362297993841467">à¬à¬¹à¬¿ ବିତରଣ ପଦà­à¬§à¬¤à¬¿ ଉପଲବà­à¬§ ନାହିà¬à¥¤ à¬à¬• ଭିନà­à¬¨ ପଦà­à¬§à¬¤à¬¿ ଚେଷà­à¬ à¬¾ କରନà­à¬¤à­à¥¤</translation>
<translation id="4854853140771946034">Google Keepରେ ଶୀଘà­à¬° à¬à¬• ନୂଆ ନୋଟୠତିଆରି କରନà­à¬¤à­</translation>
<translation id="485902285759009870">କୋଡ ଯାଞà­à¬š କରାଯାଉଛି...</translation>
+<translation id="4866506163384898554">ଆପଣଙà­à¬• କରà­à¬¸à¬° ଦେଖାଇବାକୠ|<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| ଦବାନà­à¬¤à­</translation>
<translation id="4876188919622883022">ସରଳିକୃତ ଭà­à­Ÿà­</translation>
<translation id="4876305945144899064">କୌଣସି ଉପଯୋଗକରà­à¬¤à­à¬¤à¬¾à¬¨à¬¾à¬® ନାହିà¬</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{କିଛି ନାହିà¬}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831"><ph name="TEXT" /> ସନà­à¬§à¬¾à¬¨ କରନà­à¬¤à­</translation>
<translation id="4879491255372875719">ସà­à­±à¬šà¬¾à¬³à¬¿à¬¤ (ଡିଫଲà­à¬Ÿ)</translation>
-<translation id="4879725228911483934">ୱିଣà­à¬¡à­‹à¬—à­à¬¡à¬¼à¬¿à¬• ଖୋଲି ଆପଣଙà­à¬• ସà­à¬•à­à¬°à¬¿à¬¨à¬—à­à¬¡à¬¼à¬¿à¬•à¬°à­‡ ରଖନà­à¬¤à­</translation>
<translation id="4880827082731008257">ସନà­à¬§à¬¾à¬¨ ଇତିହାସ</translation>
<translation id="4881695831933465202">ଖୋଲନà­à¬¤à­</translation>
<translation id="4885256590493466218">ଚେକଆଉଟୠକରିବା ସମୟରେ <ph name="CARD_DETAIL" /> ମାଧà­à­Ÿà¬®à¬°à­‡ ପେମେଣà­à¬Ÿ କରନà­à¬¤à­</translation>
@@ -1233,6 +1265,7 @@
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">ନବମ ରୋଲà­</translation>
<translation id="4901778704868714008">ସେଭୠକରନà­à¬¤à­...</translation>
+<translation id="4905659621780993806">ଆପଣଙà­à¬• ଆଡମିନିଷà­à¬Ÿà­à¬°à­‡à¬Ÿà¬° ଆପଣଙà­à¬•à¬° ଡିଭାଇସକୠ<ph name="DATE" />ରେ <ph name="TIME" /> ବେଳେ ସà­à­±à¬šà¬¾à¬³à¬¿à¬¤ ଭାବେ ରିଷà­à¬Ÿà¬¾à¬°à­à¬Ÿ କରିବେ। ଆପଣଙà­à¬• ଡିଭାଇସ ରିଷà­à¬Ÿà¬¾à¬°à­à¬Ÿ ହେବା ପୂରà­à¬¬à¬°à­ ଖୋଲା ଥିବା ଯେ କୌଣସି ଆଇଟମକୠସେଭ କରନà­à¬¤à­à¥¤</translation>
<translation id="4913987521957242411">ଉପର ବାମ ପଟରେ ପଞà­à¬šà­</translation>
<translation id="4918221908152712722"><ph name="APP_NAME" /> ଇନà­â€à¬·à­à¬Ÿà¬²à­â€Œ କରନà­à¬¤à­ (ଡାଉନà­â€Œà¬²à­‹à¬¡à­â€Œà¬° ଆବଶà­à­Ÿà¬•à¬¤à¬¾ ନାହିà¬)</translation>
<translation id="4923459931733593730">ପେମେଣà­à¬Ÿ</translation>
@@ -1241,6 +1274,7 @@
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, ସନà­à¬§à¬¾à¬¨ କରିବାକୠTab ତାପରେ Enter ଦବାନà­à¬¤à­</translation>
<translation id="4930153903256238152">ଅଧିକ କà­à¬·à¬®à¬¤à¬¾à¬¸à¬®à­à¬ªà¬¨à­à¬¨</translation>
+<translation id="4940163644868678279">Chromeରେ ଇନକଗà­à¬¨à¬¿à¬Ÿà­‹</translation>
<translation id="4943872375798546930">କୌଣସି ଫଳାଫଳ ନାହିà¬</translation>
<translation id="4950898438188848926">ଟାବୠସà­à­±à¬¿à¬šà­ କରିବା ବଟନà­, ଖୋଲାଥିବା ଟାବà­â€à¬•à­ ଯିବା ପାଇଠEnter ଦବାନà­à¬¤à­, <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="495170559598752135">କାରà­à¬¯à­à­Ÿ</translation>
@@ -1250,6 +1284,7 @@
<translation id="4968522289500246572">à¬à¬¹à¬¿ ଆପକୠମୋବାଇଲ ପାଇଠଡିଜାଇନୠକରାଯାଇଛି à¬à¬¬à¬‚ à¬à¬¹à¬¾ ଭଲ ଭାବରେ ରିସାଇଜୠହୋଇନପାରେ। ଆପରେ ସମସà­à­Ÿà¬¾ ହୋଇପାରେ କିମà­à­±à¬¾ à¬à¬¹à¬¾ ରିଷà­à¬Ÿà¬¾à¬°à­à¬Ÿ ହୋଇପାରେ।</translation>
<translation id="4969341057194253438">ରେକରà­à¬¡à¬¿à¬‚ ଡିଲିଟ କରନà­à¬¤à­</translation>
<translation id="4973922308112707173">ଉପର ପଟରେ ଦà­à¬‡à¬Ÿà¬¿ ପଞà­à¬šà­</translation>
+<translation id="4976702386844183910">ଗତ ଥର <ph name="DATE" />ରେ ଭିଜିଟୠକରାଯାଇଛି</translation>
<translation id="4984088539114770594">ମାଇକà­à¬°à­‹à¬«à­‹à¬¨à­ ବà­à­Ÿà¬¬à¬¹à¬¾à¬° କରିବେ?</translation>
<translation id="4984339528288761049">Prc5 (à¬à¬¨à¬­à¬²à¬ªà­)</translation>
<translation id="4989163558385430922">ସବୠଦେଖନà­à¬¤à­</translation>
@@ -1311,6 +1346,7 @@
<translation id="5138227688689900538">ଅଳà­à¬ª ଦେଖାନà­à¬¤à­</translation>
<translation id="5145883236150621069">ନୀତି ପà­à¬°à¬¤à¬¿à¬•à­à¬°à¬¿à­Ÿà¬¾à¬°à­‡ ଥିବା ତà­à¬°à­à¬Ÿà¬¿à¬° କୋଡà­â€</translation>
<translation id="5146995429444047494">‘<ph name="ORIGIN" />’ ପାଇଠବିଜà­à¬žà¬ªà­à¬¤à¬¿à¬—à­à­œà¬¿à¬•à­ ବà­à¬²à¬•à­ କରାଯାଇଛି</translation>
+<translation id="514704532284964975"><ph name="URL" /> ଆପଣଙà­à¬• ଫୋନରେ ଆପଣ ଟାପ କରିଥିବା NFC ଡିଭାଇସଗà­à¬¡à¬¼à¬¿à¬•à¬°à­‡ ସୂଚନା ଦେଖିବା à¬à¬¬à¬‚ ପରିବରà­à¬¤à­à¬¤à¬¨ କରିବାକୠଚାହେà¬</translation>
<translation id="5148809049217731050">ଫେସୠଅପà­</translation>
<translation id="515292512908731282">C4 (à¬à¬¨à¬­à¬²à¬ªà­)</translation>
<translation id="5158275234811857234">କଭରà­</translation>
@@ -1335,6 +1371,7 @@
<translation id="5215116848420601511">Google Pay ବà­à­Ÿà¬¬à¬¹à¬¾à¬° କରà­à¬¥à¬¿à¬¬à¬¾ ପେମେଣà­à¬Ÿ ପଦà­à¬§à¬¤à¬¿ à¬à¬¬à¬‚ ଠିକଣାଗà­à¬¡à¬¼à¬¿à¬•</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">ଟà­à¬°à­‡ 13</translation>
+<translation id="5216942107514965959">ଆଜି ଶେଷ ଥର ଭିଜିଟୠକରାଯାଇଛି</translation>
<translation id="5222812217790122047">ଇମେଲà­â€Œà¬° ଆବଶà­à­Ÿà¬•à¬¤à¬¾ ଅଛି</translation>
<translation id="5230733896359313003">ସିପିଂ ଠିକଣା</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1355,7 +1392,6 @@
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">ଡକà­à­Ÿà­à¬®à­‡à¬£à­à¬Ÿà¬° ପà­à¬°à¬ªà¬°à­à¬Ÿà¬¿à¬—à­à­œà¬¿à¬•</translation>
<translation id="528468243742722775">ସମାପà­à¬¤ କରନà­à¬¤à­</translation>
-<translation id="5284909709419567258">ନେଟà­â€Œà­±à¬¾à¬°à­à¬• ଠିକଣାଗà­à­œà¬¿à¬•</translation>
<translation id="5285570108065881030">ସେଭୠଥିବା ସମସà­à¬¤ ପାସà­â€Œà­±à¬°à­à¬¡ ଦେଖାନà­à¬¤à­</translation>
<translation id="5287240709317226393">କà­à¬•à­€à¬—à­à¬¡à¬¿à¬•à­ ଦେଖାନà­à¬¤à­</translation>
<translation id="5287456746628258573">à¬à¬¹à¬¿ ସାଇଟୠà¬à¬• ପà­à¬°à­à¬£à¬¾ ସà­à¬°à¬•à­à¬·à¬¾ କନଫିଗà­â€â€à¬°à­‡à¬¸à¬¨à­ ବà­à­Ÿà¬¬à¬¹à¬¾à¬° କରେ, ଯାହା ହà­à¬à¬¤ ଆପଣଙà­à¬•à¬° ସୂଚନାକୠ(ଉଦାହରଣ ସà­à­±à¬°à­‚ପ, ପାସà­â€à­±à¬¾à¬°à­à¬¡ କିମà­à¬¬à¬¾ କà­à¬°à­‡à¬¡à¬¿à¬Ÿà­ କାରà­à¬¡ ନମà­à¬¬à¬°), à¬à¬¹à¬¿ ସାଇଟà­â€â€à¬°à­‡ ପଠାଯିବା ସମୟରେ ପà­à¬°à¬•à¬Ÿ କରିପାରେ।</translation>
@@ -1439,6 +1475,7 @@
<translation id="5556459405103347317">ପà­à¬¨à¬ƒ ଲୋଡୠକରନà­à¬¤à­</translation>
<translation id="5560088892362098740">ମିଆଦ ଶେଷ ହେଉଥିବା ତାରିଖ</translation>
<translation id="55635442646131152">ଡକà­à­Ÿà­à¬®à­‡à¬£à­à¬Ÿ ଆଉଟଲାଇନà­</translation>
+<translation id="5565613213060953222">ଇନକଗà­à¬¨à¬¿à¬Ÿà­‹ ଟାବ ଖୋଲନà­à¬¤à­</translation>
<translation id="5565735124758917034">ସକà­à¬°à¬¿à­Ÿ ଅଛି</translation>
<translation id="5570825185877910964">ଆକାଉଣà­à¬Ÿà¬° ସà­à¬°à¬•à­à¬·à¬¾ କରନà­à¬¤à­</translation>
<translation id="5571083550517324815">à¬à¬¹à¬¿ ଠିକଣାରୠପିକୠଅପୠକରିହେବ ନାହିà¬à¥¤ à¬à¬• ଭିନà­à¬¨ ଠିକଣା ଚୟନ କରନà­à¬¤à­à¥¤</translation>
@@ -1521,6 +1558,7 @@
<translation id="5869522115854928033">ସଞà­à¬šà¬¿à¬¤ ପାସୱାରà­à¬¡à¬¸à¬®à­‚ହ</translation>
<translation id="5873013647450402046">à¬à¬¹à¬¾ ଆପଣ ଅଟନà­à¬¤à¬¿ ବୋଲି ଆପଣଙà­à¬• ବà­à­Ÿà¬¾à¬™à­à¬• ସà­à¬¨à¬¿à¬¶à­à¬šà¬¿à¬¤ କରିବାକୠଚାହେà¬à¥¤</translation>
<translation id="5887400589839399685">ସେଭà­â€Œ ହୋଇଗଲା</translation>
+<translation id="5887687176710214216">ଗତକାଲି ଶେଷଥର ଭିଜିଟୠକରାଯାଇଛି</translation>
<translation id="5895138241574237353">ପà­à¬¨à¬ƒà¬†à¬°à¬®à­à¬­</translation>
<translation id="5895187275912066135">ଜାରି କରାଯାଇଥିବା ତାରିଖ</translation>
<translation id="5901630391730855834">ହଳଦିଆ</translation>
@@ -1534,6 +1572,7 @@
<translation id="5921639886840618607">Google ଆକାଉଣà­à¬Ÿà¬°à­‡ କାରà­à¬¡ ସେଭà­â€Œ କରିବେ?</translation>
<translation id="5922853866070715753">ପà­à¬°à¬¾à­Ÿ ହୋଇଗଲାଣି!</translation>
<translation id="5932224571077948991">ସାଇଟà­, ଅନଧିକାର ପà­à¬°à¬¬à­‡à¬¶ କରିଥିବା କିମà­à¬¬à¬¾ ବିଭà­à¬°à¬¾à¬¨à­à¬¤à¬¿à¬•à¬° ବିଜà­à¬žà¬¾à¬ªà¬¨ ଦେଖାଉଛି</translation>
+<translation id="5938153366081463283">ଭରà­à¬šà­à¬†à¬² କାରà­à¬¡ ଯୋଗ କରନà­à¬¤à­</translation>
<translation id="5938793338444039872">ଟà­à¬°à­Ÿ</translation>
<translation id="5946937721014915347"><ph name="SITE_NAME" /> ଖୋଲà­à¬›à¬¿â€¦</translation>
<translation id="5951495562196540101">ଉପଭୋକà­à¬¤à¬¾à¬™à­à¬• ଆକାଉଣà­à¬Ÿ (ପà­à­Ÿà¬¾à¬•à­‡à¬œà­â€Œ ହୋâ€à¬‡à¬¥à¬¿à¬¬à¬¾ ଲାଇସେନà­à¬¸ ଉପଲବà­à¬§ ଅଛି ) ନାମାଙà­à¬•à¬¨ କରାଯାଇପାରିବ ନାହିà¬à¥¤</translation>
@@ -1598,6 +1637,7 @@
<translation id="6120179357481664955">ଆପଣଙà­à¬•à¬° UPI ID ମନେ ଅଛି?</translation>
<translation id="6124432979022149706">Chrome à¬à¬£à­à¬Ÿà¬°à¬ªà­à¬°à¬¾à¬‡à¬œà­ କନେକà­à¬Ÿà¬°à¬—à­à­œà¬¿à¬•</translation>
<translation id="6127379762771434464">ଆଇଟମକୠକାà­à¬¿ ଦିଆଯାଇଛି</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Chromeରେ ଇନକଗà­à¬¨à¬¿à¬Ÿà­‹ ମୋଡ ବିଷୟରେ ଅଧିକ ଜାଣନà­à¬¤à­<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">ଯେକୌଣସି କେବଲà­â€Œ ଯାଞà­à¬š କରନà­à¬¤à­ à¬à¬¬à¬‚ ଆପଣଙà­à¬• ଦà­à­±à¬¾à¬°à¬¾ ବà­à­Ÿà¬¬à¬¹à¬¾à¬° କରାଯାଉଥିବା ଯେକୌଣସି ରାଉଟରà­â€Œ, ମୋଡେମà­â€ କିମà­à¬¬à¬¾ ଅନà­à­Ÿ ରାଉଟରà­â€Œ ରିବà­à¬Ÿà­â€Œ କରନà­à¬¤à­à¥¤</translation>
<translation id="614940544461990577">à¬à¬¹à¬¾à¬•à­ ପରଖନà­à¬¤à­:</translation>
<translation id="6150036310511284407">ବାମ ପଟରେ ତିନୋଟି ପଞà­à¬šà­</translation>
@@ -1609,7 +1649,6 @@
<translation id="6169916984152623906">à¬à¬¬à­‡ ଆପଣ ବà­à­Ÿà¬•à­à¬¤à¬¿à¬—ତ ଭାବେ ବà­à¬°à¬¾à¬‰à¬œà­ କରିପାରିବେ à¬à¬¬à¬‚ à¬à¬¹à¬¿ ଡିଭାଇସà­â€à¬•à­ ବà­à­Ÿà¬¬à¬¹à¬¾à¬° କରà­à¬¥à¬¿à¬¬à¬¾ ଅନà­à­Ÿ ଲୋକମାନେ ଆପଣଙà­à¬•à¬° ଗତିବିଧି ଦେଖିପାରିବେ ନାହିà¬à¥¤ ତେବେ, ଡାଉନà­â€â€à¬²à­‹à¬¡à­ ଓ ବà­à¬•à­â€à¬®à¬¾à¬°à­à¬•à¬—à­à­œà¬¿à¬• ସେଭୠକରାଯିବ।</translation>
<translation id="6177128806592000436">à¬à¬¹à¬¿ ସାଇଟà­â€Œà¬°à­‡ ଆପଣଙà­à¬•à¬° ସଂଯୋଗ ସà­à¬°à¬•à­à¬·à¬¿à¬¤ ନà­à¬¹à­‡à¬</translation>
<translation id="6180316780098470077">ପà­à¬£à¬¿ ଚେଷà­à¬Ÿà¬¾ କରିବା ଇଣà­à¬Ÿà¬°à¬­à¬¾à¬²à­</translation>
-<translation id="619448280891863779">ୱିଣà­à¬¡à­‹à¬—à­à­œà¬¿à¬•à­ ଖୋଲି ଆପଣଙà­à¬• ସà­à¬•à­à¬°à¬¿à¬¨à¬°à­‡ ସେଗà­à¬¡à¬¼à¬¿à¬• ରଖିବାକୠସାଇଟୠପଚାରିପାରେ</translation>
<translation id="6196640612572343990">ତୃତୀୟ ପକà­à¬· କà­à¬•à­€à¬—à­à­œà¬¿à¬•à­ ବà­à¬²à¬•à­ କରନà­à¬¤à­</translation>
<translation id="6203231073485539293">ଆପଣଙà­à¬•à¬° ଇଣà­à¬Ÿà¬°à­â€Œà¬¨à­‡à¬Ÿà­ ସଂଯୋଗକୠଯାଞà­à¬š କରନà­à¬¤à­</translation>
<translation id="6218753634732582820">Chromiumରୠଠିକଣା କାà­à¬¿ ଦେବେ?</translation>
@@ -1632,7 +1671,7 @@
<translation id="6272383483618007430">Google ଅପଡେଟà­</translation>
<translation id="6276112860590028508">ଆପଣ ପà­à¬¿à¬¥à¬¿à¬¬à¬¾ ତାଲିକାରୠପୃଷà­à¬ à¬¾à¬—à­à¬¡à¬¼à¬¿à¬• à¬à¬ à¬¾à¬°à­‡ ଦେଖାଯାà¬</translation>
<translation id="627746635834430766">ପରବରà­à¬¤à­à¬¤à­€ ସମୟରେ ପୈଠ ପà­à¬°à¬•à­à¬°à¬¿à­Ÿà¬¾à¬•à­ ଦà­à¬°à­à¬¤à¬¤à¬° କରିବା ପାଇଠଆପଣଙà­à¬•à¬° Google ଆକାଉଣà­à¬Ÿà¬°à­‡ ଆପଣଙà­à¬• କାରà­à¬¡ ଓ ବିଲିଂ ଠିକଣା ସେଭୠକରନà­à¬¤à­à¥¤</translation>
-<translation id="6279098320682980337">ଭରà­à¬šà­à¬†à¬² କାରà­à¬¡ ନମà­à¬¬à¬° ପୂରଣ କରାଯାଇନାହିà¬? କପି କରିବାକୠକାରà­à¬¡ ବିବରଣୀରେ କà­à¬²à¬¿à¬• କରନà­à¬¤à­</translation>
+<translation id="6279183038361895380">ଆପଣଙà­à¬•à¬° କରà­à¬¸à¬°à­â€Œ ଦେଖାଇବାକୠ|<ph name="ACCELERATOR" />| ଦବାନà­à¬¤à­</translation>
<translation id="6280223929691119688">à¬à¬¹à¬¿ ଠିକଣାକୠପହଞà­à¬šà¬¾à¬‡à¬ªà¬¾à¬°à¬¿à¬¬ ନାହିà¬à¥¤ à¬à¬• ଭିନà­à¬¨ ଠିକଣା ଚୟନ କରନà­à¬¤à­à¥¤</translation>
<translation id="6282194474023008486">ପୋଷà­à¬Ÿà¬¾à¬²à­ କୋଡà­</translation>
<translation id="6285507000506177184">"Chromeରେ ଡାଉନଲୋଡଗà­à¬¡à¬¼à¬¿à¬•à­ ପରିଚାଳନା କରନà­à¬¤à­" ବଟନ, Chromeରେ ଆପଣ ଡାଉନଲୋଡ କରିଥିବା ଫାଇଲଗà­à¬¡à¬¼à¬¿à¬•à­ ପରିଚାଳନା କରିବା ପାଇଠEnter ଦବାନà­à¬¤à­</translation>
@@ -1640,6 +1679,7 @@
<translation id="6290238015253830360">ଆପଣଙà­à¬• ଦà­à­±à¬¾à¬°à¬¾ ପରାମରà­à¬¶à¬¿à¬¤ ନିବନà­à¬§à¬—à­à­œà¬¿à¬• à¬à¬ à¬¾à¬°à­‡ ଦେଖାଯାà¬</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{ଆପଣଙà­à¬• ଡିଭାଇସ ବରà­à¬¤à­à¬¤à¬®à¬¾à¬¨ ରିଷà­à¬Ÿà¬¾à¬°à­à¬Ÿ ହେବ}=1{ଆପଣଙà­à¬• ଡିଭାଇସ 1 ସେକେଣà­à¬¡à¬°à­‡ ରିଷà­à¬Ÿà¬¾à¬°à­à¬Ÿ ହେବ}other{ଆପଣଙà­à¬• ଡିଭାଇସ # ସେକେଣà­à¬¡à¬°à­‡ ରିଷà­à¬Ÿà¬¾à¬°à­à¬Ÿ ହେବ}}</translation>
<translation id="6302269476990306341">Chromeରେ Google ଆସିଷà­à¬Ÿà¬¾à¬£à­à¬Ÿ ବନà­à¬¦ କରାଯାଇଛି</translation>
<translation id="6305205051461490394"><ph name="URL" />ରେ ପହଞà­à¬šà¬¿ ହେଉନାହିà¬à¥¤</translation>
<translation id="6312113039770857350">ୱେବୠପୃଷà­à¬ à¬¾ ଉପଲବà­à¬§ ନାହିà¬</translation>
@@ -1713,6 +1753,7 @@
<translation id="6529602333819889595">&amp;ଡିଲିଟà­â€Œà¬•à­ ରି-ଡୠକରନà­à¬¤à­</translation>
<translation id="6545864417968258051">ବà­à¬²à­à¬Ÿà­à¬¥à­ ସà­à¬•à¬¾à¬¨à¬¿à¬‚</translation>
<translation id="6547208576736763147">ବାମ ପଟରେ ଦà­à¬‡à¬Ÿà¬¿ ପଞà­à¬šà­</translation>
+<translation id="6554732001434021288">ଗତ ଥର <ph name="NUM_DAYS" /> ଦିନ ପୂରà­à¬¬à­‡ ଭିଜିଟୠକରାଯାଇଛି</translation>
<translation id="6556866813142980365">ରି-ଡୠକରନà­à¬¤à­</translation>
<translation id="6569060085658103619">ଆପଣ à¬à¬• à¬à¬•à­à¬¸à¬Ÿà­‡à¬¨à­â€Œà¬¸à¬¨à­ ପୃଷà­à¬ à¬¾ ଦେଖà­à¬›à¬¨à­à¬¤à¬¿</translation>
<translation id="6573200754375280815">ଡାହାଣ ପଟରେ ଦà­à¬‡à¬Ÿà¬¿ ପଞà­à¬šà­</translation>
@@ -1773,7 +1814,6 @@
<translation id="6757797048963528358">ଆପଣଙà­à¬•à¬° ଡିଭାଇସୠନିଷà­à¬•à­à¬°à¬¿à­Ÿ ହୋâ€à¬‡à¬¯à¬¾à¬‡à¬›à¬¿à¥¤</translation>
<translation id="6767985426384634228">ଠିକଣା ଅପଡ଼େଟୠକରିବେ?</translation>
<translation id="6768213884286397650">ହାଗାକି (ପୋଷà­à¬Ÿà¬•à¬¾à¬°à­à¬¡)</translation>
-<translation id="6774185088257932239">ଇନକଗà­à¬¨à¬¿à¬Ÿà­‹ ବିଷୟରେ <ph name="BEGIN_LINK" />ଅଧିକ ଜାଣନà­à¬¤à­<ph name="END_LINK" /></translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">ବାଇଗଣୀ</translation>
<translation id="6786747875388722282">ପରିବରà­à¬¦à­à¬§à¬¨</translation>
@@ -1857,7 +1897,6 @@
<translation id="706295145388601875">Chrome ସେଟିଂସରେ ଠିକଣାଗà­à­œà¬¿à¬•à­ ଯୋଗ କରି ପରିଚାଳନା କରନà­à¬¤à­</translation>
<translation id="7064851114919012435">ଯୋଗାଯୋଗ ସୂଚନା</translation>
<translation id="7068733155164172741"><ph name="OTP_LENGTH" />-ଅଙà­à¬• ବିଶିଷà­à¬Ÿ କୋଡ ଲେଖନà­à¬¤à­</translation>
-<translation id="7070090581017165256">à¬à¬¹à¬¿ ସାଇଟ ବିଷୟରେ</translation>
<translation id="70705239631109039">ଆପଣଙà­à¬•à¬° ସଂଯୋଗ ସମà­à¬ªà­‚ରà­à¬£à­à¬£à¬°à­‚ପେ ସà­à¬°à¬•à­à¬·à¬¿à¬¤ ନà­à¬¹à­‡à¬</translation>
<translation id="7075452647191940183">ଅନà­à¬°à­‹à¬§à¬Ÿà¬¿ ବହà­à¬¤ ଲମà­à¬¬à¬¾ ଅଟେ</translation>
<translation id="7079718277001814089">à¬à¬¹à¬¿ ସାଇଟà­â€Œà¬°à­‡ ମାଲà­â€Œà­±à­‡à¬°à­â€Œ ଅଛି।</translation>
@@ -1874,6 +1913,12 @@
<translation id="7111012039238467737">(ବୈଧ)</translation>
<translation id="7118618213916969306">କà­à¬²à¬¿à¬ªà­â€Œà¬¬à­‹à¬°à­à¬¡ URL, <ph name="SHORT_URL" />କୠଖୋଜନà­à¬¤à­</translation>
<translation id="7119414471315195487">ଅନà­à­Ÿ ଟାବୠକିମà­à­±à¬¾ କରà­à¬¯à­à­Ÿà¬•à­à¬°à¬®à¬—à­à¬¡à¬¼à¬¿à¬• ବନà­à¬¦ କରନà­à¬¤à­</translation>
+<translation id="7129355289156517987">ଆପଣ ଯେତେବେଳେ ଇନକଗà­à¬¨à¬¿à¬Ÿà­‹ ମୋଡରେ ଥିବା ସମସà­à¬¤ Chromium ଟାବକୠବନà­à¬¦ କରନà­à¬¤à¬¿, ସେହି ଟାବଗà­à¬¡à¬¼à¬¿à¬•à¬°à­‡ ଆପଣଙà­à¬• କାରà­à¬¯à­à­Ÿà¬•à¬³à¬¾à¬ª à¬à¬¹à¬¿ ଡିଭାଇସରୠଖାଲି ହୋଇଯାà¬:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ବà­à¬°à¬¾à¬‰à¬œà¬¿à¬‚ କାରà­à¬¯à­à­Ÿà¬•à¬³à¬¾à¬ª<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ସନà­à¬§à¬¾à¬¨ ଇତିହାସ<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ଫରà­à¬®à¬—à­à­œà¬¿à¬•à¬°à­‡ ଲେଖାଯାଇଥିବା ସୂଚନା<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">à¬à¬¹à¬¿ ଠିକଣାକୠପଠାଯାଇପାରିବ ନାହିà¬à¥¤ à¬à¬• ଭିନà­à¬¨ ଠିକଣା ଚୟନ କରନà­à¬¤à­à¥¤</translation>
<translation id="7132939140423847331">ଆପଣଙà­à¬• ଆଡମିନ à¬à¬¹à¬¿ ଡାଟାକୠକପି କରିବାରୠପà­à¬°à¬¤à¬¿à¬¬à¬¨à­à¬§à¬¿à¬¤ କରିଛନà­à¬¤à¬¿à¥¤</translation>
<translation id="7135130955892390533">ସà­à¬¥à¬¿à¬¤à¬¿ ଦେଖାନà­à¬¤à­</translation>
@@ -1896,6 +1941,7 @@
<translation id="7192203810768312527"><ph name="SIZE" /> ଜାଗା ଖାଲି କରିଥାà¬à¥¤ କିଛି ସାଇଟà­â€ ଆପଣଙà­à¬•à¬° ପରବରà­à¬¤à­à¬¤à­€ ଭà­à¬°à¬®à¬£ ସମୟରେ ଆହà­à¬°à¬¿ ଧୀରେ ଲୋଡୠହୋଇପାରନà­à¬¤à¬¿à¥¤</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">à¬à¬¹à¬¾ ଆପଣଙà­à¬•à¬° ଆଡà­â€Œà¬®à¬¿à¬¨à¬¿à¬·à­à¬Ÿà­à¬°à­‡à¬Ÿà¬°à­ ଦେଖିପାରିବେ:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, ବà­à­Ÿà¬•à­à¬¤à¬¿à¬—ତ ଭାବରେ ବà­à¬°à¬¾à¬‰à¬œ କରିବା ପାଇଠà¬à¬• ନୂଆ ଇନକଗà­à¬¨à¬¿à¬Ÿà­‹ ଟାବ ଖୋଲିବାକୠTab ତାପରେ Enter ଦବାନà­à¬¤à­</translation>
<translation id="7202346780273620635">ଲେଟରà­-à¬à¬•à­à¬¸à¬Ÿà­à¬°à¬¾</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> ସà­à¬°à¬•à­à¬·à¬¾ ମାନାଙà­à¬•à¬° ପାଳନ କରà­à¬¨à¬¾à¬¹à¬¿à¬à¥¤</translation>
<translation id="7210993021468939304">କଣà­à¬Ÿà­‡à¬¨à¬°à­ ମଧà­à­Ÿà¬°à­‡ Linux କାରà­à¬¯à­à­Ÿà¬•à¬³à¬¾à¬ª à¬à¬¬à¬‚ କଣà­à¬Ÿà­‡à¬¨à¬°à­ ମଧà­à­Ÿà¬°à­‡ Linux ଆପà­à¬¸ ଇନଷà­à¬Ÿà¬²à­ କରି ଚଲାଇପାରେ</translation>
@@ -1927,6 +1973,7 @@
<translation id="7304562222803846232">Google ଆକାଉଣà­à¬Ÿà¬° ଗୋପନୀୟତା ସେଟିଂସକୠପରିଚାଳନା କରନà­à¬¤à­</translation>
<translation id="7305756307268530424">ଧୀର ଗତିରେ ଆରମà­à¬­ କରନà­à¬¤à­</translation>
<translation id="7308436126008021607">ପୃଷà­à¬ à¬ªà¬Ÿ ସିଙà­à¬•à­</translation>
+<translation id="7310392214323165548">ଡିଭାଇସଟି ଅତି ଶୀଘà­à¬° ରିଷà­à¬Ÿà¬¾à¬°à­à¬Ÿ ହେବ</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">ସଂଯୋଗ ସହାୟତା</translation>
<translation id="7323804146520582233">"<ph name="SECTION" />" ବିଭାଗ ଲà­à¬šà¬¾à¬¨à­à¬¤à­</translation>
@@ -1934,6 +1981,7 @@
<translation id="7334320624316649418">&amp;ରି-ଡà­à¬•à­ ପà­à¬¨à¬ƒà¬•à­à¬°à¬®à¬°à­‡ ରଖନà­à¬¤à­</translation>
<translation id="7335157162773372339">ଆପଣଙà­à¬• କà­à­Ÿà¬¾à¬®à­‡à¬°à¬¾ ବà­à­Ÿà¬¬à¬¹à¬¾à¬° କରିବାକୠସାଇଟୠପଚାରିପାରେ</translation>
<translation id="7337248890521463931">ଅଧିକ ଲାଇନୠଦେଖାନà­à¬¤à­</translation>
+<translation id="7337418456231055214">ଭରà­à¬šà­à¬†à¬² କାରà­à¬¡ ନମà­à¬¬à¬° ପୂରଣ କରାଯାଇନାହିà¬? କପି କରିବାକୠକାରà­à¬¡ ବିବରଣୀରେ କà­à¬²à¬¿à¬• କରନà­à¬¤à­à¥¤ <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">ଆପଣଙà­à¬•à¬° ପà­à¬²à¬¾à¬Ÿà­â€Œà¬«à¬°à­à¬®à¬°à­‡ ଉପଲବà­à¬§ ନାହିà¬à¥¤</translation>
<translation id="733923710415886693">ସରà­à¬­à¬°à­â€à¬° ସାରà­à¬Ÿà¬¿à¬«à¬¿à¬•à­‡à¬Ÿà­, ସାରà­à¬Ÿà¬¿à¬«à¬¿à¬•à­‡à¬Ÿà­ ସà­à¬µà¬šà­à¬›à¬¤à¬¾ ମାଧà­à­Ÿà¬®à¬°à­‡ ପà­à¬°à¬•à¬¾à¬¶ କରାଯାଇନାହିà¬à¥¤</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1956,6 +2004,7 @@
<translation id="7378627244592794276">ନାହିà¬</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">ପà­à¬°à¬¯à­à¬œà­à­Ÿ ନà­à¬¹à­‡à¬</translation>
+<translation id="7388594495505979117">{0,plural, =1{ଆପଣଙà­à¬• ଡିଭାଇସ 1 ମିନିଟରେ ରିଷà­à¬Ÿà¬¾à¬°à­à¬Ÿ ହେବ}other{ଆପଣଙà­à¬• ଡିଭାଇସ # ମିନିଟରେ ରିଷà­à¬Ÿà¬¾à¬°à­à¬Ÿ ହେବ}}</translation>
<translation id="7390545607259442187">କାରà­à¬¡ ସà­à¬¨à¬¿à¬¶à­à¬šà¬¿à¬¤ କରନà­à¬¤à­</translation>
<translation id="7392089738299859607">ଠିକଣା ଅପଡେଟୠକରନà­à¬¤à­</translation>
<translation id="7399802613464275309">ସà­à¬°à¬•à­à¬·à¬¾ ଯାଞà­à¬š</translation>
@@ -1992,6 +2041,12 @@
<translation id="7485870689360869515">କୌଣସି ଡାଟା ମିଳିଲା ନାହିà¬à¥¤</translation>
<translation id="7495528107193238112">à¬à¬¹à¬¿ ବିଷୟବସà­à¬¤à­à¬•à­ ବà­à¬²à¬•à­ କରାଯାଇଛି। ସମସà­à­Ÿà¬¾à¬° ସମାଧାନ କରିବାକୠସାଇଟର ମାଲିକଙà­à¬• ସହ ଯୋଗାଯୋଗ କରନà­à¬¤à­à¥¤</translation>
<translation id="7497998058912824456">"ଡକà­à­Ÿà­à¬®à­‡à¬£à­à¬Ÿ ତିଆରି କରନà­à¬¤à­" ବଟନà­, ଶୀଘà­à¬° à¬à¬• ନୂଆ Google Doc ତିଆରି କରିବାକୠEnter ଦବାନà­à¬¤à­</translation>
+<translation id="7506488012654002225">Chromium ନିମà­à¬¨à­‹à¬•à­à¬¤ ସୂଚନାକୠ<ph name="BEGIN_EMPHASIS" />ସେଭ କରିବ ନାହିà¬<ph name="END_EMPHASIS" />:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ଆପଣଙà­à¬•à¬° ବà­à¬°à¬¾à¬‰à¬œà¬¿à¬‚ ଇତିହାସ
+ <ph name="LIST_ITEM" />କà­à¬•à­€ à¬à¬¬à¬‚ ସାଇଟ ଡାଟା
+ <ph name="LIST_ITEM" />ଫରà­à¬®à¬—à­à­œà¬¿à¬•à¬°à­‡ ଲେଖାଯାଇଥିବା ସୂଚନା
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">ଫେରସà­à¬¤ ନୀତି ଡିଭାଇସୠid ଖାଲି ଅଛି କିମà­à¬¬à¬¾ ବରà­à¬¤à­à¬¤à¬®à¬¾à¬¨à¬° ଡିଭାଇସୠid ସହିତ ମେଳ ହେଉନାହିà¬</translation>
<translation id="7508870219247277067">ଆଭୋକାଡୋ ସବà­à¬œ</translation>
<translation id="7511955381719512146">ଆପଣ ବà­à­Ÿà¬¬à¬¹à¬¾à¬° କରà­à¬¥à¬¿à¬¬à¬¾ ୱାଇ-ଫାଇ ପାଇଠଆପଣଙà­à¬•à­ <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.କୠଯିବାକୠପଡିପାରେ।</translation>
@@ -2105,7 +2160,6 @@
<translation id="7813600968533626083">Chromeରୠଫରà­à¬® ସମà­à¬¬à¬¨à­à¬§à¬¿à¬¤ ପରାମରà­à¬¶ କାà­à¬¿à¬¬à­‡?</translation>
<translation id="781440967107097262">କà­à¬²à¬¿à¬ªà¬¬à­‹à¬°à­à¬¡ ସେୟାରୠକରିବେ?</translation>
<translation id="7815407501681723534">'<ph name="SEARCH_STRING" />' ପାଇଠ<ph name="NUMBER_OF_RESULTS" />ଟି <ph name="SEARCH_RESULTS" /> ମିଳିଲା</translation>
-<translation id="782125616001965242">à¬à¬¹à¬¿ ସାଇଟ ବିଷୟରେ ସୂଚନା ଦେଖାନà­à¬¤à­</translation>
<translation id="782886543891417279">ଆପଣ ବà­à­Ÿà¬¬à¬¹à¬¾à¬° କରà­à¬¥à¬¿à¬¬à¬¾ ୱାଇଫାଇ (<ph name="WIFI_NAME" />) ପାଇà¬, ଆପଣଙà­à¬•à­ ହà­à¬à¬¤ à¬à¬¹à¬¾à¬° ଲଗà­â€Œà¬‡à¬¨à­ ପୃଷà­à¬ à¬¾à¬•à­ ଯିବାର ଆବଶà­à­Ÿà¬•à¬¤à¬¾ ଅଛି।</translation>
<translation id="7836231406687464395">Postfix (à¬à¬¨à¬­à¬²à¬ªà­)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{କିଛିନାହିà¬}=1{1ଟି ଆପୠ(<ph name="EXAMPLE_APP_1" />)}=2{2ଟି ଆପà­â€Œ (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}other{#ଟି ଆପà­â€Œ (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}}</translation>
@@ -2122,7 +2176,6 @@
<translation id="7888575728750733395">ପà­à¬°à¬¿à¬£à­à¬Ÿ ରେଣà­à¬¡à¬°à¬¿à¬‚ ଇଣà­à¬Ÿà­‡à¬£à­à¬Ÿ</translation>
<translation id="7894280532028510793">ଯଦି ବନାନ ସଠିକୠଅଛି, ତେବେ <ph name="BEGIN_LINK" />ନେଟୱାରà­à¬• ଡାà¬à¬—à­à¬¨à­‹à¬·à­à¬Ÿà¬¿à¬•à­à¬¸ ଚଲାଇବାକୠଚେଷà­à¬Ÿà¬¾ କରନà­à¬¤à­<ph name="END_LINK" />।</translation>
<translation id="7904208859782148177">C3 (à¬à¬¨à¬­à¬²à¬ªà­)</translation>
-<translation id="7931318309563332511">ଅଜଣା</translation>
<translation id="793209273132572360">ଠିକଣା ଅପଡ଼େଟୠକରିବେ?</translation>
<translation id="7932579305932748336">କୋଟà­</translation>
<translation id="79338296614623784">à¬à¬• ବୈଧ ଫୋନୠନମà­à¬µà¬°à­ ଲେଖନà­à¬¤à­</translation>
@@ -2147,13 +2200,14 @@
<translation id="7976214039405368314">ଅନେକଗà­à­œà¬¿à¬ ଅନà­à¬°à­‹à¬§</translation>
<translation id="7977538094055660992">ଆଉଟପà­à¬Ÿà­ ଡିଭାଇସà­</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">à¬à¬¹à¬¾ ସହ ଲିଙà­à¬• କରାଯାଇଛି</translation>
<translation id="798134797138789862">ଭରà­à¬šà­à¬†à¬²à­ ରିଆଲିଟୀ ଡିଭାଇସୠà¬à¬¬à¬‚ ଡାଟା ବà­à­Ÿà¬¬à¬¹à¬¾à¬° କରିବାକୠସାଇଟୠପଚାରିପାରେ</translation>
<translation id="7984945080620862648">ଆପଣ ବରà­à¬¤à­à¬¤à¬®à¬¾à¬¨ <ph name="SITE" />କୠଭିଜିଟୠକରିପାରିବେ ନାହିଠକାରଣ ୱେବସାଇଟୠସà­à¬•à­à¬°à­‡à¬®à­à¬¬à¬²à­ କରାଯାଇଥିବା କà­à¬°à­‡à¬¡à­‡à¬¨à­à¬¸à¬¿à¬†à¬²à¬—à­à­œà¬¿à¬•à­ ପଠାଇଛି ଯାହାକୠChrome ପà­à¬°à¬•à­à¬°à¬¿à­Ÿà¬¾à¬¨à­à­±à¬¿à¬¤ କରିପାରିବ ନାହିà¬à¥¤ ନେଟୱାରà­à¬• ତà­à¬°à­à¬Ÿà¬¿ ଓ ଆକà­à¬°à¬®à¬£ ସାଧାରଣତଃ ଅସà­à¬¥à¬¾à­Ÿà­€ ଅଟେ, ତେଣୠà¬à¬¹à¬¿ ପୃଷà­à¬ à¬¾ ସମà­à¬­à¬¬à¬¤à¬ƒ ପରେ କାମ କରିପାରେ।</translation>
-<translation id="79859296434321399">ବୃଦà­à¬§à¬¿ ହେଉଥିବା ବାସà­à¬¤à¬¬à¬¤à¬¾ ବିଷୟବସà­à¬¤à­ ଦେଖିବାକୠARCore ଇନà­â€Œà¬·à­à¬Ÿà¬²à­ କରନà­à¬¤à­</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">ବାଇଣà­à¬¡</translation>
<translation id="7992044431894087211"><ph name="APPLICATION_TITLE" /> ସହ ସà­à¬•à­à¬°à¬¿à¬¨à­ ସେୟାରିଂକୠପà­à¬£à¬¿ ଆରମà­à¬­ କରାଯାଇଛି</translation>
<translation id="7995512525968007366">ନିରà­à¬¦à­à¬¦à¬¿à¬·à­à¬Ÿ ହୋଇନାହିà¬</translation>
+<translation id="7998269595945679889">"ଇନକଗà­à¬¨à¬¿à¬Ÿà­‹ ଟାବ ଖୋଲନà­à¬¤à­" ବଟନ, ବà­à­Ÿà¬•à­à¬¤à¬¿à¬—ତ ଭାବେ ବà­à¬°à¬¾à¬‰à¬œ କରିବାକୠà¬à¬• ନୂଆ ଇନକଗà­à¬¨à¬¿à¬Ÿà­‹ ଟାବ ଖୋଲିବା ପାଇଠEnter ଦବାନà­à¬¤à­</translation>
<translation id="800218591365569300">ମେମୋରୀ ଖାଲି କରିବା ପାଇଠଅନà­à­Ÿà¬¾à¬¨à­à­Ÿ ଟାବୠବା ପà­à¬°à­‹à¬—à­à¬°à¬¾à¬®à­â€Œà¬—à­à¬¡à¬¼à¬¿à¬•à­ ବନà­à¬¦ କରିବାକୠଚେଷà­à¬Ÿà¬¾ କରନà­à¬¤à­à¥¤</translation>
<translation id="8004582292198964060">ବà­à¬°à¬¾à¬‰à¬œà¬°</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{à¬à¬¹à¬¿ କାରà­à¬¡ à¬à¬¬à¬‚ à¬à¬¹à¬¾à¬° ବିଲିଂ ଠିକଣା ସେଭà­â€Œ କରାଯିବ। <ph name="USER_EMAIL" />ରେ ସାଇନà­â€Œ ଇନà­â€Œ ରହିବା ଦà­à­±à¬¾à¬°à¬¾ ଆପଣ à¬à¬¹à¬¾à¬•à­ ବà­à­Ÿà¬¬à¬¹à¬¾à¬° କରିବାକୠସକà­à¬·à¬® ହେବେ।}other{à¬à¬¹à¬¿ କାରà­à¬¡à¬—à­à­œà¬¿à¬• à¬à¬¬à¬‚ ସେମାନଙà­à¬•à¬° ବିଲିଂ ଠିକଣାଗà­à­œà¬¿à¬• ସେଭà­â€Œ କରାଯିବ। <ph name="USER_EMAIL" />ରେ ସାଇନà­â€Œ ଇନà­â€Œ ରହିବା ଦà­à­±à¬¾à¬°à¬¾ ଆପଣ ସେଗà­à­œà¬¿à¬•à­ ବà­à­Ÿà¬¬à¬¹à¬¾à¬° କରିବାକୠସକà­à¬·à¬® ହେବେ।}}</translation>
@@ -2213,6 +2267,7 @@
<translation id="8202370299023114387">ବିବାଦ</translation>
<translation id="8206978196348664717">Prc4 (à¬à¬¨à¬­à¬²à¬ªà­)</translation>
<translation id="8211406090763984747">ସଂଯୋଗ ସà­à¬°à¬•à­à¬·à¬¿à¬¤ ଅଛି</translation>
+<translation id="8217240300496046857">ସାଇଟଗà­à­œà¬¿à¬• ସମଗà­à¬° ୱେବରେ ଆପଣଙà­à¬•à­ ଟà­à¬°à¬¾à¬• କରà­à¬¥à¬¿à¬¬à¬¾ କà­à¬•à­€à¬—à­à­œà¬¿à¬•à­ ବà­à­Ÿà¬¬à¬¹à¬¾à¬° କରିପାରିବ ନାହିà¬à¥¤ କିଛି ସାଇଟରେ ଫିଚରଗà­à¬¡à¬¼à¬¿à¬• ଠିକୠଭାବେ କାମ କରିନପାରେ।</translation>
<translation id="8218327578424803826">ହସà­à¬¤à¬¾à¬¨à­à¬¤à¬°à¬¿à¬¤ ଲୋକେସନà­:</translation>
<translation id="8220146938470311105">C7/C6 (à¬à¬¨à¬­à¬²à¬ªà­)</translation>
<translation id="8225771182978767009">ଯେଉଠବà­à­Ÿà¬•à­à¬¤à¬¿ à¬à¬¹à¬¿ କମà­à¬ªà­à­Ÿà­à¬Ÿà¬°à­â€Œ ସେଟà­â€ ଅପà­â€ କରିଛନà­à¬¤à¬¿, ସିଠà¬à¬¹à¬¿ ସାଇଟà­â€ ଅବରୋଧ କରିବାକୠବାଛିଛନà­à¬¤à¬¿à¥¤</translation>
@@ -2253,14 +2308,9 @@
<translation id="830498451218851433">ଅଧା ଫୋଲà­à¬¡ କରନà­à¬¤à­</translation>
<translation id="8307358339886459768">ଛୋଟ-ଫଟୋ</translation>
<translation id="8307888238279532626">ଇନଷà­à¬Ÿà¬²à­ କରାଯାଇଥିବା ଆପଗà­à­œà¬¿à¬• à¬à¬¬à¬‚ ସେଗà­à­œà¬¿à¬• କେତେ ଥର ବà­à­Ÿà¬¬à¬¹à¬¾à¬° କରାଯାଇଛି</translation>
+<translation id="8317207217658302555">ARCore ଅପଡେଟ କରିବେ କି?</translation>
<translation id="831997045666694187">ସନà­à¬§à­à­Ÿà¬¾</translation>
<translation id="8321476692217554900">ବିଜà­à¬žà¬ªà­à¬¤à¬¿à¬—à­à¬¡à¬¼à¬¿à¬•</translation>
-<translation id="8328484624016508118">ସମସà­à¬¤ ଇନକଗà­à¬¨à¬¿à¬Ÿà­‹ ଟାବକୠବନà­à¬¦ କରିବା ପରେ, Chrome à¬à¬¸à¬¬à­ ଖାଲି କରେ:
-<ph name="BEGIN_LIST" />
-<ph name="LIST_ITEM" />à¬à¬¹à¬¿ ଡିଭାଇସରୠଆପଣଙà­à¬• ବà­à¬°à¬¾à¬‰à¬œà¬¿à¬‚ କାରà­à¬¯à­à­Ÿà¬•à¬³à¬¾à¬ª<ph name="END_LIST_ITEM" />
-<ph name="LIST_ITEM" />à¬à¬¹à¬¿ ଡିଭାଇସରୠଆପଣଙà­à¬• ସନà­à¬§à¬¾à¬¨ ଇତିହାସ<ph name="END_LIST_ITEM" />
-<ph name="LIST_ITEM" />ଫରà­à¬®à¬—à­à­œà¬¿à¬•à¬°à­‡ ଲେଖାଯାଇଥିବା ସୂଚନା<ph name="END_LIST_ITEM" />
-<ph name="END_LIST" /></translation>
<translation id="8332188693563227489"><ph name="HOST_NAME" />କୠଆକà­à¬¸à­‡à¬¸à­â€Œ ପà­à¬°à¬¤à­à­Ÿà¬¾à¬–à­à­Ÿà¬¾à¬¨ କରାଯାଇଥିଲା</translation>
<translation id="833262891116910667">ହାଇଲାଇଟà­</translation>
<translation id="8339163506404995330"><ph name="LANGUAGE" /> ରେ ପୃଷà­à¬ à¬¾à¬—à­à­œà¬¿à¬• ଅନà­à¬¬à¬¾à¬¦ କରାଯିବନାହିà¬</translation>
@@ -2312,6 +2362,7 @@
<translation id="8507227106804027148">କମାଣà­à¬¡ ଲାଇନà­</translation>
<translation id="8508648098325802031">ଆଇକନà­â€Œ ଖୋଜନà­à¬¤à­</translation>
<translation id="8511402995811232419">କà­à¬•à­€à¬—à­à­œà¬¿à¬•à­ ପରିଚାଳନା କରନà­à¬¤à­</translation>
+<translation id="8519753333133776369">ଆପଣଙà­à¬• ଆଡମିନିଷà­à¬Ÿà­à¬°à­‡à¬Ÿà¬°à¬™à­à¬• ଦà­à­±à¬¾à¬°à¬¾ ଅନà­à¬®à¬¤à¬¿ ପà­à¬°à¬¾à¬ªà­à¬¤ HID ଡିଭାଇସ</translation>
<translation id="8522552481199248698">Chrome ଆପଣଙà­à¬•à­ ଆପଣଙà­à¬•à¬° Google ଆକାଉଣà­à¬Ÿà¬•à­ ସà­à¬°à¬•à­à¬·à¬¿à¬¤ ରଖିବା à¬à¬¬à¬‚ ଆପଣଙà­à¬•à¬° ପାସà­â€à­±à¬¾à¬°à­à¬¡ ବଦଳାଇବାରେ ସାହାଯà­à­Ÿ କରିପାରିବ।</translation>
<translation id="8530813470445476232">Chrome ସେଟିଂସରେ ଆପଣଙà­à¬• ବà­à¬°à¬¾à¬‰à¬œà¬¿à¬‚ ଇତିହାସ, କà­à¬•à­€, କà­à­Ÿà¬¾à¬¶à­ à¬à¬¬à¬‚ ଆହà­à¬°à¬¿ ଅନେକ କିଛି ଖାଲି କରନà­à¬¤à­</translation>
<translation id="8533619373899488139">ବà­à¬²à¬•à­ କରାଯାଇଥିବା URLଗà­à­œà¬¿à¬•à¬° ତାଲିକା à¬à¬¬à¬‚ ଆପଣଙà­à¬• ସିଷà­à¬Ÿà¬®à­ ଆଡମିନିଷà­à¬Ÿà­à¬°à­‡à¬Ÿà¬°à¬™à­à¬• ଦà­à¬µà¬¾à¬°à¬¾ ଲାଗୠକରାଯାଇଥିବା ଅନà­à­Ÿ ନୀତିଗà­à­œà¬¿à¬•à­ ଦେଖିବା ପାଇଠ&lt;strong&gt;chrome://policy&lt;/strong&gt; କୠଭିଜିଟୠକରନà­à¬¤à­à¥¤</translation>
@@ -2323,7 +2374,6 @@
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{ଅନà­à¬®à¬¤à¬¿à¬•à­ ରିସେଟୠକରନà­à¬¤à­}other{ଅନà­à¬®à¬¤à¬¿à¬—à­à­œà¬¿à¬•à­ ରିସେଟୠକରନà­à¬¤à­}}</translation>
<translation id="8555010941760982128">ଚେକଆଉଟ ସମୟରେ à¬à¬¹à¬¿ କୋଡକୠବà­à­Ÿà¬¬à¬¹à¬¾à¬° କରନà­à¬¤à­</translation>
<translation id="8557066899867184262">CVC ଆପଣଙà­à¬• କାରà­à¬¡à¬° ପଛପଟେ ଅଛି।</translation>
-<translation id="8558485628462305855">ବୃଦà­à¬§à¬¿ ହେଉଥିବା ବାସà­à¬¤à¬¬à¬¤à¬¾ ସମà­à¬¬à¬¨à­à¬§à¬¿à¬¤ ବିଷୟବସà­à¬¤à­ ଦେଖିବା ପାଇà¬, ARCore ଅପଡେଟୠକରନà­à¬¤à­</translation>
<translation id="8559762987265718583"><ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />କୠà¬à¬• ବà­à­Ÿà¬•à­à¬¤à¬¿à¬—ତ ସଂଯୋଗ ସà­à¬¥à¬¾à¬ªà¬¨ କରାଯାଇପାରିବ ନାହିଠକାରଣ, ଆପଣଙà­à¬• ଡିଭାଇସà­â€Œà¬° ତାରିଖ à¬à¬¬à¬‚ ସମୟ (<ph name="DATE_AND_TIME" />) ଭà­à¬² ଅଛି।</translation>
<translation id="8564182942834072828">ଅଲଗା ଡକà­à­Ÿà­à¬®à­‡à¬£à­à¬Ÿà¬—à­à¬¡à¬¼à¬¿à¬•/ସଂଗà­à¬°à¬¹ କରାଯାଇନଥିବା କପିଗà­à¬¡à¬¼à¬¿à¬•</translation>
<translation id="8564985650692024650">ଆପଣ ଯଦି ଆପଣଙà­à¬•à¬° <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> ପାସà­â€Œà­±à¬¾à¬°à­à¬¡à¬•à­ ଅନà­à­Ÿ ସାଇଟà­â€Œà¬—à­à¬¡à¬¼à¬¿à¬•à¬°à­‡ ପà­à¬¨à¬ƒ ବà­à­Ÿà¬¬à¬¹à¬¾à¬° କରିଛନà­à¬¤à¬¿, ତେବେ Chromium ଆପଣଙà­à¬•à­ à¬à¬¹à¬¿ ପାସà­â€Œà­±à¬¾à¬°à­à¬¡à¬•à­ ରିସେଟୠକରିବା ପାଇଠସà­à¬ªà¬¾à¬°à¬¿à¬¶ କରà­à¬›à¬¿à¥¤</translation>
@@ -2342,6 +2392,7 @@
<translation id="865032292777205197">ମୋସନୠସେନà­à¬¸à¬°à¬—à­à­œà¬¿à¬•</translation>
<translation id="8663226718884576429">ଅରà­à¬¡à¬° ସାରାଂଶ, <ph name="TOTAL_LABEL" />, ଅଧିକ ବିବରଣୀ</translation>
<translation id="8666678546361132282">ଇଂରାଜୀ</translation>
+<translation id="8669306706049782872">ୱିଣà­à¬¡à­‹à¬—à­à¬¡à¬¼à¬¿à¬•à­ ଖୋଲିବା à¬à¬¬à¬‚ ରଖିବା ପାଇà¬, ଆପଣଙà­à¬• ସà­à¬•à­à¬°à¬¿à¬¨ ବିଷୟରେ ଥିବା ସୂଚନାକୠବà­à­Ÿà¬¬à¬¹à¬¾à¬° କରନà­à¬¤à­</translation>
<translation id="867224526087042813">ଦସà­à¬¤à¬–ତ</translation>
<translation id="8676424191133491403">କୌଣସି ବିଳମà­à¬¬ ନାହିà¬</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, ଉତà­à¬¤à¬° ଦିଅନà­à¬¤à­, <ph name="ANSWER" /></translation>
@@ -2368,6 +2419,7 @@
<translation id="8731544501227493793">"ପାସୱାରà­à¬¡à¬—à­à¬¡à¬¼à¬¿à¬•à­ ପରିଚାଳନା କରନà­à¬¤à­" ବଟନà­, Chrome ସେଟିଂସରେ ପାସୱାରà­à¬¡à¬—à­à¬¡à¬¼à¬¿à¬•à­ ଦେଖିବା à¬à¬¬à¬‚ ପରିଚାଳନା କରିବା ପାଇଠEnter ଦବାନà­à¬¤à­</translation>
<translation id="8734529307927223492">ଆପଣଙà­à¬•à¬° <ph name="DEVICE_TYPE" />, <ph name="MANAGER" /> ଦà­à¬µà¬¾à¬°à¬¾ ପରିଚାଳିତ ହେଉଛି</translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, ବà­à­Ÿà¬•à­à¬¤à¬¿à¬—ତ ଭାବରେ ବà­à¬°à¬¾à¬‰à¬œà­ କରିବା ପାଇଠà¬à¬• ନୂଆ ଇନକଗà­à¬¨à¬¿à¬Ÿà­‹ ୱିଣà­à¬¡à­‹ ଖୋଲିବାକୠTab କରି Enter ଦବାନà­à¬¤à­</translation>
+<translation id="8737685506611670901"><ph name="REPLACED_HANDLER_TITLE" />ପରିବରà­à¬¤à­à¬¤à­‡ <ph name="PROTOCOL" /> ଲିଙà­à¬•à­ ଖୋଲନà­à¬¤à­</translation>
<translation id="8738058698779197622">à¬à¬• ସà­à¬°à¬•à­à¬·à¬¿à¬¤ ସଂଯୋଗ ପà­à¬°à¬¤à¬¿à¬·à­à¬ à¬¾ କରିବାକୠଆପଣଙà­à¬•à¬° ଘଣà­à¬Ÿà¬¾à¬•à­ ସଠିକୠଭାବେ ସେଟୠକରିବା ଆବଶà­à­Ÿà¬•à¥¤ à¬à¬¹à¬¾ à¬à¬ªà¬°à¬¿ କାରଣ ୱେବà­â€Œà¬¸à¬¾à¬‡à¬Ÿà­â€Œà¬—à­à­œà¬¿à¬• ଦà­à­±à¬¾à¬°à¬¾ ନିଜକୠଚିହà­à¬¨à¬Ÿ କରିବା ପାଇଠବà­à­Ÿà¬¬à¬¹à¬¾à¬° କରାଯାଉଥିବା ସାରà­à¬Ÿà¬¿à¬«à¬¿à¬•à­‡à¬Ÿà­â€ କେବଳ ନିରà­à¬¦à­à¬§à¬¿à¬·à­à¬Ÿ ସମୟର ଅବଧି ପାଇଠକେବଳ ବୈଧ ଅଟେ। ଯେହେତୠଡିଭାଇସà­â€Œà¬° ଘଣà­à¬Ÿà¬¾ ଭà­à¬²à­ ଅଛି, ତେଣୠChromium à¬à¬¹à¬¿ ସାରà­à¬Ÿà¬¿à¬«à¬¿à¬•à­‡à¬Ÿà­â€Œà¬—à­à­œà¬¿à¬•à­ ଯାଞà­à¬š କରିପାରିବ ନାହିà¬à¥¤</translation>
<translation id="8740359287975076522"><ph name="HOST_NAME" />’ର &lt;abbr id="dnsDefinition"&gt;DNS ଠିକଣା&lt;/abbr&gt; ମିଳିଲା ନାହିà¬à¥¤ ସମସà­à­Ÿ ଡାà¬à¬—à­à¬¨à­‹à¬œà­ ହେଉଛି।</translation>
<translation id="8742371904523228557"><ph name="ORIGIN" /> ପାଇଠ<ph name="ONE_TIME_CODE" /> ହେଉଛି ଆପଣଙà­à¬•à¬° କୋଡà­</translation>
@@ -2395,6 +2447,7 @@
<translation id="883848425547221593">ଅନà­à­Ÿ ବà­à¬•à­â€à¬®à¬¾à¬°à­à¬•</translation>
<translation id="884264119367021077">ସିପିଂ ଠିକଣା</translation>
<translation id="884923133447025588">କୌଣସି ନାକଚକରଣ ଯନà­à¬¤à­à¬°à¬•à­Œà¬¶à¬³ ଖୋଜି ପାଇଲା ନାହିଠ।</translation>
+<translation id="8849262850971482943">ଅଧିକ ସà­à¬°à¬•à­à¬·à¬¾ ପାଇଠଆପଣଙà­à¬• ଭରà­à¬šà­à¬†à¬²à­ କାରà­à¬¡ ବà­à­Ÿà¬¬à¬¹à¬¾à¬° କରନà­à¬¤à­</translation>
<translation id="885730110891505394">Google ସହିତ ସେୟାରୠକରାଯାଉଛି</translation>
<translation id="8858065207712248076">ଆପଣ ଯଦି ନିଜର <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> ପାସà­â€Œà­±à¬°à­à¬¡à¬•à­ ଅନà­à­Ÿ ୱେବà­â€Œà¬¸à¬¾à¬‡à¬Ÿà­â€Œà¬—à­à¬¡à¬¼à¬¿à¬•à¬°à­‡ ପà­à¬¨à¬ƒ ବà­à­Ÿà¬¬à¬¹à¬¾à¬° କରିଛନà­à¬¤à¬¿, ତେବେ Chrome ଆପଣଙà­à¬•à­ à¬à¬¹à¬¿ ପାସà­â€Œà­±à¬°à­à¬¡à¬•à­ ରିସେଟୠକରିବା ପାଇଠସà­à¬ªà¬¾à¬°à¬¿à¬¶ କରà­à¬›à¬¿à¥¤</translation>
<translation id="885906927438988819">ଯଦି ବନାନ ସଠିକୠଅଛି, ତେବେ <ph name="BEGIN_LINK" />Windows ନେଟୱାରà­à¬• ଡାà¬à¬—à­à¬¨à­‹à¬·à­à¬Ÿà¬¿à¬•à­à¬¸ ଚଲାଇବାକୠଚେଷà­à¬Ÿà¬¾ କରନà­à¬¤à­<ph name="END_LINK" />।</translation>
@@ -2444,6 +2497,7 @@
<translation id="9004367719664099443">VR ସମୟ ଅବଧି ପà­à¬°à¬•à­à¬°à¬¿à­Ÿà¬¾à¬°à¬¤ ଅଛି</translation>
<translation id="9005998258318286617">PDF ଡକà­à­Ÿà­à¬®à­‡à¬£à­à¬Ÿ ଲୋଡୠହେବାରେ ବିଫଳ ହେଲା।</translation>
<translation id="9008201768610948239">ଅଣଦେଖା କରନà­à¬¤à­</translation>
+<translation id="901834265349196618">ଇମେଲà­</translation>
<translation id="9020200922353704812">କାରà­à¬¡ ବିଲିଂ ଠିକଣା ଆବଶà­à­Ÿà¬•</translation>
<translation id="9020542370529661692">à¬à¬¹à¬¿ ପୃଷà­à¬ à¬¾ <ph name="TARGET_LANGUAGE" />ରେ ଅନà­à¬¬à¬¾à¬¦ କରାଯାଇଛି</translation>
<translation id="9020742383383852663">A8</translation>
@@ -2492,6 +2546,7 @@
<translation id="9150045010208374699">ଆପଣଙà­à¬•à¬° କà­à­Ÿà¬¾à¬®à­‡à¬°à¬¾ ବà­à­Ÿà¬¬à¬¹à¬¾à¬° କରନà­à¬¤à­</translation>
<translation id="9150685862434908345">ଆପଣଙà­à¬• ଆଡମିନିଷà­à¬Ÿà­à¬°à­‡à¬Ÿà¬°à­ ଆପଣଙà­à¬• ବà­à¬°à¬¾à¬‰à¬œà¬°à¬° ସେଟଅପକୠରିମୋଟୠଭାବରେ ବଦଳାଇ ପାରିବେ। à¬à¬¹à¬¿ ଡିଭାଇସରେ କରାଯାଉଥିବା କାରà­à¬¯à­à­Ÿà¬•à¬³à¬¾à¬ªà¬•à­ Chrome ବାହାରେ ମଧà­à­Ÿ ପରିଚାଳନା କରାଯାଇପାରେ। <ph name="BEGIN_LINK" />ଅଧିକ ଜାଣନà­à¬¤à­<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">ଅପà­â€Œà¬¡à­‡à¬Ÿà­â€ କରାଗଲା</translation>
+<translation id="9155211586651734179">ଆଟାଚ କରାଯାଇଥିବା ଅଡିଓ ପେରିଫେରାଲଗà­à­œà¬¿à¬•</translation>
<translation id="9157595877708044936">ସେଟà­â€â€à¬…ପୠକରାଯାଉଛି...</translation>
<translation id="9158625974267017556">C6 (à¬à¬¨à¬­à¬²à¬ªà­)</translation>
<translation id="9164029392738894042">ସଠିକତା ଯାଞà­à¬š</translation>
diff --git a/chromium/components/strings/components_strings_pa.xtb b/chromium/components/strings/components_strings_pa.xtb
index 665233af191..6eb13688986 100644
--- a/chromium/components/strings/components_strings_pa.xtb
+++ b/chromium/components/strings/components_strings_pa.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">ਵੇਰਵੇ ਦੇਖੋ</translation>
<translation id="1030706264415084469"><ph name="URL" /> ਦੀ ਤà©à¨¹à¨¾à¨¡à©‡ ਡੀਵਾਈਸ 'ਤੇ ਸਥਾਈ ਤੌਰ 'ਤੇ ਬਹà©à¨¤ ਜ਼ਿਆਦਾ ਡਾਟਾ ਸਟੋਰ ਕਰਨ ਦੀ ਇੱਛਾ ਹੈ</translation>
<translation id="1032854598605920125">ਕਲੌਕਵਾਈਜ ਰੋਟੇਟ ਕਰੋ</translation>
+<translation id="1033329911862281889">ਇਨਕੋਗਨਿਟੋ ਮੋਡ ਤà©à¨¹à¨¾à¨¨à©‚à©° ਆਨਲਾਈਨ ਅਦਿੱਖ ਨਹੀਂ ਬਣਾਉਂਦਾ:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ਉਨà©à¨¹à¨¾à¨‚ ਵੱਲੋਂ ਵਰਤੀਆਂ ਜਾਣ ਵਾਲੀਆਂ ਸਾਈਟਾਂ ਅਤੇ ਸੇਵਾਵਾਂ ਫੇਰੀਆਂ ਨੂੰ ਦੇਖ ਸਕਦੇ ਹਨ<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ਰà©à©›à¨—ਾਰਦਾਤੇ ਜਾਂ ਸਕੂਲ ਬà©à¨°à¨¾à¨Šà¨œà¨¼à¨¿à©°à¨— ਸਰਗਰਮੀ ਨੂੰ ਟਰੈਕ ਕਰ ਸਕਦੇ ਹਨ<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ਇੰਟਰਨੈੱਟ ਸੇਵਾ ਪà©à¨°à¨¦à¨¾à¨¨à¨• ਵੈੱਬ ਟਰੈਫ਼ਿਕ ਦੀ ਨਿਗਰਾਨੀ ਕਰ ਸਕਦੇ ਹਨ<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">ਬੰਦ ਕਰੋ</translation>
<translation id="1036982837258183574">ਪੂਰੀ ਸਕà©à¨°à©€à¨¨ ਤੋਂ ਬਾਹਰ ਜਾਣ ਲਈ |<ph name="ACCELERATOR" />| ਦਬਾਓ</translation>
<translation id="1038106730571050514">ਸà©à¨à¨¾à¨… ਦਿਖਾਓ</translation>
<translation id="1038842779957582377">ਅਗਿਆਤ ਨਾਮ</translation>
<translation id="1041998700806130099">ਕਾਰਵਾਈ ਸ਼ੀਟ ਸà©à¨¨à©‡à¨¹à¨¾</translation>
<translation id="1048785276086539861">ਜਦੋਂ ਤà©à¨¸à©€à¨‚ à¨à¨¨à©‹à¨Ÿà©‡à¨¶à¨¨à¨¾à¨‚ ਦਾ ਸੰਪਾਦਨ ਕਰਦੇ ਹੋ, ਤਾਂ ਇਹ ਦਸਤਾਵੇਜ਼ ਇਕਹਿਰੇ ਪੰਨਾ-ਦà©à¨°à¨¿à¨¶ 'ਤੇ ਵਾਪਸ ਆ ਜਾਵੇਗਾ</translation>
-<translation id="1049743911850919806">ਗà©à¨®à¨¨à¨¾à¨®</translation>
<translation id="1050038467049342496">ਦੂਜੀਆਂ à¨à¨ªà¨¾à¨‚ ਬੰਦ ਕਰੋ</translation>
<translation id="1055184225775184556">&amp;ਜੋੜੋ ਨੂੰ ਅਨਡੂ ਕਰੋ</translation>
<translation id="1056898198331236512">ਚਿਤਾਵਨੀ</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">ਨੀਤੀ ਕੈਸ਼ੇ OK</translation>
<translation id="1130564665089811311">'ਪੰਨੇ ਦਾ ਅਨà©à¨µà¨¾à¨¦ ਕਰੋ' ਬਟਨ, Google Translate ਨਾਲ ਇਸ ਪੰਨੇ ਦਾ ਅਨà©à¨µà¨¾à¨¦ ਕਰਨ ਲਈ Enter ਦਬਾਓ</translation>
<translation id="1131264053432022307">ਤà©à¨¹à¨¾à¨¡à©‡ ਵੱਲੋਂ ਕਾਪੀ ਕੀਤਾ ਚਿੱਤਰ</translation>
+<translation id="1142846828089312304">ਇਨਕੋਗਨਿਟੋ ਮੋਡ ਵਿੱਚ ਤੀਜੀ ਧਿਰ ਦੀਆਂ ਕà©à¨•à©€à¨œà¨¼ ਨੂੰ ਬਲਾਕ ਕਰੋ</translation>
<translation id="1150979032973867961">ਇਹ ਸਰਵਰ ਇਹ ਸਾਬਤ ਨਹੀਂ ਕਰ ਸਕਿਆ ਕਿ ਇਹ <ph name="DOMAIN" /> ਹੈ; ਇਸਦਾ ਸà©à¨°à©±à¨–ਿਆ ਪà©à¨°à¨®à¨¾à¨£-ਪੱਤਰ ਤà©à¨¹à¨¾à¨¡à©‡ ਕੰਪਿਊਟਰ ਦੇ ਓਪਰੇਟਿੰਗ ਸਿਸਟਮ ਵੱਲੋਂ ਭਰੋਸੇਯੋਗ ਨਹੀਂ ਹੈ। ਇਹ ਇੱਕ ਗਲਤ ਸੰਰੂਪਣ ਕਾਰਨ ਹੋ ਸਕਦਾ ਹੈ ਜਾਂ ਕੋਈ ਹਮਲਾਵਰ ਤà©à¨¹à¨¾à¨¡à©‡ ਕਨੈਕਸ਼ਨ ਨੂੰ ਰਾਹ ਵਿੱਚ ਰੋਕ ਰਿਹਾ ਹੈ।</translation>
<translation id="1151972924205500581">ਪਾਸਵਰਡ ਲੋੜੀਂਦਾ</translation>
<translation id="1156303062776767266">ਤà©à¨¸à©€à¨‚ ਸਥਾਨਕ ਜਾਂ ਸਾਂà¨à©€ ਕੀਤੀ ਗਈ ਫ਼ਾਈਲ ਦੇਖ ਰਹੇ ਹੋ</translation>
@@ -64,7 +70,6 @@
<translation id="1178581264944972037">ਰੋਕੋ</translation>
<translation id="1181037720776840403">ਹਟਾਓ</translation>
<translation id="1186201132766001848">ਪਾਸਵਰਡਾਂ ਦੀ ਜਾਂਚ ਕਰੋ</translation>
-<translation id="1195210374336998651">à¨à¨ª ਸੈਟਿੰਗਾਂ 'ਤੇ ਜਾਓ</translation>
<translation id="1195558154361252544">ਸੂਚਨਾਵਾਂ ਤà©à¨¹à¨¾à¨¡à©‡ ਵੱਲੋਂ ਇਜਾਜ਼ਤ ਦਿੱਤੀਆਂ ਸਾਈਟਾਂ ਨੂੰ ਛੱਡ ਕੇ ਸਾਰੀਆਂ ਸਾਈਟਾਂ ਲਈ ਸਵੈਚਲਿਤ ਤੌਰ 'ਤੇ ਬਲਾਕ ਕੀਤੀਆਂ ਜਾਂਦੀਆਂ ਹਨ</translation>
<translation id="1197088940767939838">ਸੰਤਰੀ</translation>
<translation id="1201402288615127009">ਅੱਗੇ</translation>
@@ -111,7 +116,7 @@
<translation id="1307966114820526988">ਨਾਪਸੰਦ ਕੀਤੀਆਂ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ</translation>
<translation id="1308113895091915999">ਪੇਸ਼ਕਸ਼ ਉਪਲਬਧ ਹੈ</translation>
<translation id="1312803275555673949">ਕਿਹੜਾ ਸਬੂਤ ਇਸ ਦਾ ਸਮਰਥਨ ਕਰਦਾ ਹੈ?</translation>
-<translation id="131405271941274527">ਜਦੋਂ ਤà©à¨¸à©€à¨‚ ਆਪਣੇ ਫ਼ੋਨ ਨੂੰ ਕਿਸੇ NFC ਡੀਵਾਈਸ 'ਤੇ ਟੈਪ ਕਰਦੇ ਹੋ ਤਾਂ <ph name="URL" /> ਜਾਣਕਾਰੀ ਭੇਜਣਾ ਅਤੇ ਪà©à¨°à¨¾à¨ªà¨¤ ਕਰਨਾ ਚਾਹà©à©°à¨¦à¨¾ ਹੈ</translation>
+<translation id="1314311879718644478">ਆਗਮੈਂਟਿਡ ਰਿà¨à¨²à¨¿à¨Ÿà©€ ਸੰਬੰਧੀ ਸਮੱਗਰੀ ਦੇਖੋ</translation>
<translation id="1314509827145471431">ਸੱਜੇ ਜਿਲਦਬੰਦ</translation>
<translation id="1318023360584041678">ਟੈਬ ਗਰà©à©±à¨ª ਵਿੱਚ ਰੱਖਿਅਤ ਕੀਤੀ ਗਈ</translation>
<translation id="1319245136674974084">ਇਸ à¨à¨ª ਲਈ ਦà©à¨¬à¨¾à¨°à¨¾ ਨਾ ਪà©à©±à¨›à©‹</translation>
@@ -161,6 +166,7 @@
<translation id="142858679511221695">ਕਲਾਊਡ ਵਰਤੋਂਕਾਰ</translation>
<translation id="1428729058023778569">ਤà©à¨¹à¨¾à¨¨à©‚à©° ਇਹ ਚਿਤਾਵਨੀ ਇਸ ਲਈ ਦਿਸ ਰਹੀ ਹੈ ਕਿਉਂਕਿ ਇਹ ਸਾਈਟ HTTPS ਦਾ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦੀ। <ph name="BEGIN_LEARN_MORE_LINK" />ਹੋਰ ਜਾਣੋ<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">ਪà©à¨°à¨¿à©°à¨Ÿ ਕਰੋ</translation>
+<translation id="1432187715652018471">ਪੰਨਾ ਕਿਸੇ ਸੇਵਾ ਹੈਂਡਲਰ ਨੂੰ ਸਥਾਪਤ ਕਰਨਾ ਚਾਹà©à©°à¨¦à¨¾ ਹੈ।</translation>
<translation id="1432581352905426595">ਖੋਜ ਇੰਜਣਾਂ ਦਾ ਪà©à¨°à¨¬à©°à¨§à¨¨ ਕਰੋ</translation>
<translation id="1436185428532214179">ਸਾਈਟ ਤà©à¨¹à¨¾à¨¡à©‡ ਡੀਵਾਈਸ ਵਿਚਲੀਆਂ ਫ਼ਾਈਲਾਂ ਅਤੇ ਫੋਲਡਰਾਂ ਦਾ ਸੰਪਾਦਨ ਕਰਨ ਲਈ ਪà©à©±à¨› ਸਕਦੀ ਹੈ</translation>
<translation id="1442386063175183758">ਸੱਜੇ ਪੱਲੇ ਵਾਲੀ ਤਹਿ</translation>
@@ -181,6 +187,12 @@
<translation id="1483493594462132177">ਭੇਜੋ</translation>
<translation id="1484290072879560759">ਸ਼ਿਪਿੰਗ ਪਤਾ ਚà©à¨£à©‹</translation>
<translation id="1492194039220927094">ਨੀਤੀਆਂ ਦਾ ਅਮਲੀਕਰਨ:</translation>
+<translation id="149293076951187737">ਜਦੋਂ ਤà©à¨¸à©€à¨‚ Chrome ਵਿੱਚ ਸਾਰੀਆਂ ਇਨਕੋਗਨਿਟੋ ਟੈਬਾਂ ਨੂੰ ਬੰਦ ਕਰਦੇ ਹੋ ਤਾਂ ਉਨà©à¨¹à¨¾à¨‚ ਟੈਬਾਂ ਵਿਚਲੀ ਤà©à¨¹à¨¾à¨¡à©€ ਸਰਗਰਮੀ ਨੂੰ ਇਸ ਡੀਵਾਈਸ ਤੋਂ ਕਲੀਅਰ ਕਰ ਦਿੱਤਾ ਜਾਂਦਾ ਹੈ:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ਬà©à¨°à¨¾à¨Šà¨œà¨¼à¨¿à©°à¨— ਸਰਗਰਮੀ<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ਖੋਜ ਇਤਿਹਾਸ<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ਫ਼ਾਰਮਾਂ ਵਿੱਚ ਦਾਖਲ ਕੀਤੀ ਜਾਣਕਾਰੀ<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">ਟੈਬ 'ਤੇ ਵਾਪਸ ਜਾਓ</translation>
<translation id="1501859676467574491">ਤà©à¨¹à¨¾à¨¡à©‡ Google ਖਾਤੇ ਤੋਂ ਕਾਰਡ ਦਿਖਾਓ</translation>
<translation id="1507202001669085618">&lt;p&gt;ਜੇਕਰ ਤà©à¨¸à©€à¨‚ ਵਾਈ-ਫਾਈ ਪੋਰਟਲ ਦੀ ਵਰਤੋਂ ਕਰ ਰਹੇ ਹੋ ਤਾਂ ਤà©à¨¹à¨¾à¨¨à©‚à©° ਇਹ ਗੜਬੜ ਦਿਖਾਈ ਦੇਵੇਗੀ ਜਿੱਥੇ ਤà©à¨¹à¨¾à¨¨à©‚à©° ਆਨਲਾਈਨ ਹੋਣ ਤੋਂ ਪਹਿਲਾਂ ਸਾਈਨ-ਇਨ ਕਰਨਾ ਪਵੇਗਾ।&lt;/p&gt;
@@ -208,6 +220,8 @@
<translation id="1559572115229829303">&lt;p&gt;<ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />ਨਾਲ ਇੱਕ ਨਿੱਜੀ ਕਨੈਕਸ਼ਨ ਨੂੰ ਸਥਾਪਿਤ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ ਕਿਉਂਕਿ ਤà©à¨¹à¨¾à¨¡à©€ ਡੀਵਾਈਸ ਦੀ ਮਿਤੀ ਅਤੇ ਸਮਾਂ (<ph name="DATE_AND_TIME" />) ਗ਼ਲਤ ਹੈ।&lt;/p&gt;
&lt;p&gt;ਕਿਰਪਾ ਕਰਕੇ &lt;strong&gt;ਸੈਟਿੰਗਾਂ&lt;/strong&gt; à¨à¨ª ਦੇ &lt;strong&gt;ਸਧਾਰਨ&lt;/strong&gt; ਭਾਗ ਤੋਂ ਮਿਤੀ ਅਤੇ ਸਮਾਂ ਅਨà©à¨•à©‚ਲਿਤ ਕਰੋ।&lt;/p&gt;</translation>
+<translation id="1559839503761818503">ਤà©à¨¹à¨¾à¨¡à¨¾ ਪà©à¨°à¨¸à¨¼à¨¾à¨¸à¨• <ph name="DATE" /> ਨੂੰ <ph name="TIME" /> ਵਜੇ ਤà©à¨¹à¨¾à¨¡à©‡ ਡੀਵਾਈਸ ਨੂੰ ਮà©à©œ-ਸ਼à©à¨°à©‚ ਕਰੇਗਾ</translation>
+<translation id="156703335097561114">ਨੈੱਟਵਰਕਿੰਗ ਜਾਣਕਾਰੀ ਜਿਵੇਂ ਕਿ ਪਤੇ, ਇੰਟਰਫੇਸ ਸੰਰੂਪਣ, ਅਤੇ ਕਨੈਕਸ਼ਨ ਗà©à¨£à¨µà©±à¨¤à¨¾</translation>
<translation id="1567040042588613346">ਇਹ ਨੀਤੀ ਉਮੀਦ ਮà©à¨¤à¨¾à¨¬à¨• ਕੰਮ ਕਰ ਰਹੀ ਹੈ ਪਰ ਸਮਾਨ ਮà©à©±à¨² ਕਿਸੇ ਹੋਰ ਥਾਂ 'ਤੇ ਸੈੱਟ ਹੈ ਅਤੇ ਇਸ ਨੀਤੀ ਵੱਲੋਂ ਪà©à¨°à¨¤à¨¿à¨¸à¨¥à¨¾à¨ªà¨¨ ਕੀਤਾ ਗਿਆ ਹੈ।</translation>
<translation id="1569487616857761740">ਮਿਆਦ ਮà©à©±à¨•à¨£ ਦੀ ਤਾਰੀਖ ਦਾਖਲ ਕਰੋ</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@
<translation id="1583429793053364125">ਇਹ ਵੈਬਸਫ਼ਾ ਪà©à¨°à¨¦à¨°à¨¶à¨¿à¨¤ ਕਰਦੇ ਸਮੇਂ ਕà©à¨ ਗ਼ਲਤ ਹੋਇਆ ਸੀ।</translation>
<translation id="1586541204584340881">ਤà©à¨¸à©€à¨‚ ਕਿਹੜੀਆਂ à¨à¨•à¨¸à¨Ÿà©ˆà¨‚ਸ਼ਨਾਂ ਸਥਾਪਤ ਕੀਤੀਆਂ ਹੋਈਆਂ ਹਨ</translation>
<translation id="1588438908519853928">ਸਧਾਰਨ</translation>
+<translation id="1589050138437146318">ਕੀ ARCore ਨੂੰ ਸਥਾਪਤ ਕਰਨਾ ਹੈ?</translation>
<translation id="1592005682883173041">ਸਥਾਨਕ ਡਾਟਾ ਪਹà©à©°à¨š</translation>
<translation id="1594030484168838125">ਚà©à¨£à©‹</translation>
<translation id="160851722280695521">Chrome ਵਿੱਚ Dino Run ਗੇਮ ਖੇਡੋ</translation>
@@ -279,6 +294,7 @@
<translation id="1763864636252898013">ਇਹ ਸਰਵਰ ਇਹ ਸਿੱਧ ਨਹੀਂ ਕਰ ਸਕਿਆ ਕਿ ਇਹ <ph name="DOMAIN" /> ਹੈ; ਇਸਦਾ ਸà©à¨°à©±à¨–ਿਆ ਪà©à¨°à¨®à¨¾à¨£-ਪੱਤਰ ਤà©à¨¹à¨¾à¨¡à©€ ਡਿਵਾਈਸ ਦੇ ਓਪਰੇਟਿੰਗ ਸਿਸਟਮ ਵੱਲੋਂ ਭਰੋਸੇਯੋਗ ਨਹੀਂ ਹੈ। ਇਸ ਦਾ ਕਾਰਨ ਗਲਤ ਸੰਰੂਪਣ ਹੋ ਸਕਦਾ ਹੈ ਜਾਂ ਕੋਈ ਹਮਲਾਵਰ ਤà©à¨¹à¨¾à¨¡à©‡ ਕਨੈਕਸ਼ਨ ਦੇ ਰਾਹ ਨੂੰ ਰੋਕ ਰਿਹਾ ਹੈ।</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Windows ਨੈੱਟਵਰਕ ਤਸ਼ਖੀਸਾਂ ਨੂੰ ਚਲਾਉਣ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰੋ<ph name="END_LINK" />।</translation>
<translation id="1772163372082567643">ਜਿਸ ਸਰਵਰ 'ਤੇ ਤà©à¨¸à©€à¨‚ ਜਾ ਰਹੇ ਹੋ, <ph name="ORIGIN" />, ਉਸਨੇ ਇੱਕ ਸਿਰਲੇਖ ਸੈੱਟ ਕੀਤਾ ਹੈ ਜਿਸ ਵਿੱਚ ਇਹ ਚੀਜ਼ ਲੋੜੀਂਦੀ ਹੈ ਕਿ ਮੂਲ ਨੀਤੀ ਨੂੰ ਇਸ 'ਤੇ ਕੀਤੀਆਂ ਗਈਆਂ ਸਾਰੀਆਂ ਬੇਨਤੀਆਂ 'ਤੇ ਲਾਗੂ ਕੀਤਾ ਜਾਂਦਾ ਹੈ। ਪਰ ਸਿਰਲੇਖ ਨà©à¨•à¨¸à¨¦à¨¾à¨° ਹੈ, ਜੋ ਬà©à¨°à¨¾à¨Šà¨œà¨¼à¨° ਨੂੰ <ph name="SITE" /> ਲਈ ਤà©à¨¹à¨¾à¨¡à©€ ਬੇਨਤੀ ਨੂੰ ਪੂਰਾ ਕਰਨ ਤੋਂ ਰੋਕਦਾ ਹੈ। ਮੂਲ ਸੰਬੰਧੀ ਨੀਤੀਆਂ ਨੂੰ ਕਿਸੇ ਸਾਈਟ ਦੀ ਸà©à¨°à©±à¨–ਿਆ ਅਤੇ ਹੋਰ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਦਾ ਸੰਰੂਪਣ ਕਰਨ ਲਈ ਸਾਈਟ ਓਪਰੇਟਰਾਂ ਵੱਲੋਂ ਵਰਤਿਆ ਜਾ ਸਕਦਾ ਹੈ।</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Chromium ਵਿੱਚ ਇਨਕੋਗਨਿਟੋ ਮੋਡ ਬਾਰੇ ਹੋਰ ਜਾਣੋ<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">ਤà©à¨¹à¨¾à¨¡à©‡ ਖà©à©±à¨²à©à¨¹à©‡ ਟੈਬ ਇੱਥੇ ਵਿਖਾਈ ਦੇਣਗੇ</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -406,6 +422,7 @@
<translation id="22081806969704220">ਟà©à¨°à©‡à¨… 3</translation>
<translation id="2212735316055980242">ਨੀਤੀ ਨਹੀਂ ਮਿਲੀ</translation>
<translation id="2213606439339815911">à¨à¨‚ਟਰੀਆਂ ਪà©à¨°à¨¾à¨ªà¨¤ ਕਰ ਰਿਹਾ ਹੈ...</translation>
+<translation id="2213612003795704869">ਪੰਨਾ ਪà©à¨°à¨¿à©°à¨Ÿ ਕੀਤਾ ਗਿਆ</translation>
<translation id="2215727959747642672">ਫ਼ਾਈਲ ਸੰਪਾਦਨ</translation>
<translation id="2218879909401188352">ਇਸ ਵੇਲੇ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> 'ਤੇ ਹਮਲਾਵਰ ਤà©à¨¹à¨¾à¨¡à©€ ਡੀਵਾਈਸ 'ਤੇ ਖਤਰਨਾਕ à¨à¨ªà¨¾à¨‚ ਨੂੰ ਸਥਾਪਤ ਕਰ ਸਕਦੇ ਹਨ, ਜੋ ਤà©à¨¹à¨¾à¨¡à©€ ਡੀਵਾਈਸ ਨੂੰ ਨà©à¨•à¨¸à¨¾à¨¨ ਪਹà©à©°à¨šà¨¾ ਸਕਦੀਆਂ ਹਨ, ਤà©à¨¹à¨¾à¨¡à©‡ ਮੋਬਾਈਲ ਬਿਲ ਵਿੱਚ ਗà©à©±à¨à©‡ ਖਰਚੇ ਸ਼ਾਮਲ ਕਰ ਸਕਦੀਆਂ ਹਨ, ਜਾਂ ਤà©à¨¹à¨¾à¨¡à©€ ਨਿੱਜੀ ਜਾਣਕਾਰੀ ਨੂੰ ਚੋਰੀ ਕਰ ਸਕਦੀਆਂ ਹਨ। <ph name="BEGIN_LEARN_MORE_LINK" />ਹੋਰ ਜਾਣੋ<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">ਇੰਟਰਨੈੱਟ ਨਹੀਂ</translation>
@@ -415,6 +432,7 @@
<translation id="2248949050832152960">WebAuthn ਨੂੰ ਵਰਤੋ</translation>
<translation id="2250931979407627383">ਖੱਬੇ ਕਿਨਾਰੇ ਤੋਂ ਸਿਲਾਈ</translation>
<translation id="225207911366869382">ਇਸ ਨੀਤੀ ਲਈ ਇਹ ਮà©à©±à¨² ਨਾਪਸੰਦ ਕੀਤਾ ਗਿਆ ਹੈ।</translation>
+<translation id="2256115617011615191">ਹà©à¨£ ਰੀਸਟਾਰਟ ਕਰੋ</translation>
<translation id="2258928405015593961">ਮਿਆਦ ਮà©à©±à¨•à¨£ ਦੀ ਭਵਿੱਖੀ ਤਾਰੀਖ ਦਾਖਲ ਕਰਕੇ ਦà©à¨¬à¨¾à¨°à¨¾ ਕੋਸ਼ਿਸ਼ ਕਰੋ</translation>
<translation id="225943865679747347">ਅਸ਼à©à©±à¨§ ਕੋਡ: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">HTTP ਗੜਬੜ</translation>
@@ -442,6 +460,7 @@
<translation id="2337852623177822836">ਸੈਟਿੰਗ ਤà©à¨¹à¨¾à¨¡à©‡ ਪà©à¨°à¨¶à¨¾à¨¸à¨• ਵੱਲੋਂ ਕੰਟਰੋਲ ਕੀਤੀ ਗਈ</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> ਜੋੜਾਬੱਧ ਕਰਨਾ ਚਾਹà©à©°à¨¦à©€ ਹੈ</translation>
<translation id="2346319942568447007">ਤà©à¨¹à¨¾à¨¡à©‡ ਵੱਲੋਂ ਕਾਪੀ ਕੀਤਾ ਚਿੱਤਰ</translation>
+<translation id="2350796302381711542">ਕੀ <ph name="HANDLER_HOSTNAME" /> ਨੂੰ <ph name="REPLACED_HANDLER_TITLE" /> ਦੀ ਬਜਾਠਸਾਰੇ <ph name="PROTOCOL" /> ਲਿੰਕ ਖੋਲà©à¨¹à¨£ ਦੀ ਆਗਿਆ ਦੇਣੀ ਹੈ?</translation>
<translation id="2354001756790975382">ਹੋਰ ਬà©à©±à¨•à¨®à¨¾à¨°à¨•</translation>
<translation id="2354430244986887761">ਹਾਲ ਹੀ ਵਿੱਚ Google ਸà©à¨°à©±à¨–ਿਆ ਬà©à¨°à¨¾à¨Šà¨œà¨¼à¨¿à©°à¨— ਨੂੰ <ph name="SITE" /> 'ਤੇ <ph name="BEGIN_LINK" />ਹਾਨੀਕਾਰਕ à¨à¨ªà¨¾à¨‚ ਮਿਲੀਆਂ ਹਨ<ph name="END_LINK" />।</translation>
<translation id="2355395290879513365">ਹੋ ਸਕਦਾ ਹੈ ਕਿ ਤà©à¨¹à¨¾à¨¡à©‡ ਵੱਲੋਂ ਇਸ ਸਾਈਟ 'ਤੇ ਵੇਖੇ ਜਾ ਰਹੇ ਚਿੱਤਰਾਂ ਨੂੰ ਹਮਲਾਵਰ ਵੀ ਦੇਖਣ ਦੇ ਯੋਗ ਹੋਣ ਅਤੇ ਉਹਨਾਂ ਚਿੱਤਰਾਂ ਨੂੰ ਸੋਧ ਕੇ ਉਹ ਤà©à¨¹à¨¾à¨¨à©‚à©° ਧੋਖਾ ਦੇ ਸਕਦੇ ਹਨ।</translation>
@@ -467,6 +486,7 @@
<translation id="2413528052993050574">ਇਹ ਸਰਵਰ ਇਹ ਸਿੱਧ ਨਹੀਂ ਕਰ ਸਕਿਆ ਕਿ ਇਹ <ph name="DOMAIN" /> ਹੈ; ਇਸਦਾ ਸà©à¨°à©±à¨–ਿਆ ਸਰਟੀਫਿਕੇਟ ਰੱਦ ਕੀਤਾ ਜਾ ਸਕਦਾ ਹੈ। ਇਸ ਦਾ ਕਾਰਨ ਗਲਤ ਸੰਰੂਪਣ ਹੋ ਸਕਦਾ ਹੈ ਜਾਂ ਕੋਈ ਹਮਲਾਵਰ ਤà©à¨¹à¨¾à¨¡à©‡ ਕਨੈਕਸ਼ਨ ਦੇ ਰਾਹ ਨੂੰ ਰੋਕ ਰਿਹਾ ਹੈ।</translation>
<translation id="2414886740292270097">ਡਾਰਕ</translation>
<translation id="2430968933669123598">Google ਖਾਤੇ ਦਾ ਪà©à¨°à¨¬à©°à¨§à¨¨ ਕਰੋ, ਆਪਣੇ Google ਖਾਤੇ ਵਿੱਚ ਆਪਣੀ ਜਾਣਕਾਰੀ, ਪਰਦੇਦਾਰੀ ਅਤੇ ਸà©à¨°à©±à¨–ਿਆ ਦਾ ਪà©à¨°à¨¬à©°à¨§à¨¨ ਕਰਨ ਲਈ Enter ਦਬਾਓ</translation>
+<translation id="2436186046335138073">ਕੀ <ph name="HANDLER_HOSTNAME" /> ਨੂੰ ਸਾਰੇ <ph name="PROTOCOL" /> ਲਿੰਕ ਖੋਲà©à¨¹à¨£ ਦੀ ਆਗਿਆ ਦੇਣੀ ਹੈ?</translation>
<translation id="2438874542388153331">ਸੱਜੇ ਪਾਸੇ ਚਾਰ ਮੋਰੀਆਂ</translation>
<translation id="2450021089947420533">ਖੋਜ ਸਫ਼ਰ</translation>
<translation id="2463739503403862330">ਭਰੋ</translation>
@@ -474,6 +494,7 @@
<translation id="2465655957518002998">ਡਿਲੀਵਰੀ ਵਿਧੀ ਚà©à¨£à©‹</translation>
<translation id="2465688316154986572">ਪਿੰਨ</translation>
<translation id="2465914000209955735">Chrome ਵਿੱਚ ਤà©à¨¹à¨¾à¨¡à©‡ ਵੱਲੋਂ ਡਾਊਨਲੋਡ ਕੀਤੀਆਂ ਫ਼ਾਈਲਾਂ ਦਾ ਪà©à¨°à¨¬à©°à¨§à¨¨ ਕਰੋ</translation>
+<translation id="2466004615675155314">ਵੈੱਬ ਤੋਂ ਜਾਣਕਾਰੀ ਦਿਖਾਓ</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />ਨੈੱਟਵਰਕ ਤਸ਼ਖੀਸਾਂ ਚਲਾਇਆ ਜਾ ਰਿਹਾ ਹੈ<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">1-ਤੋਂ-N ਕà©à¨°à¨®</translation>
<translation id="2470767536994572628">ਜਦੋਂ ਤà©à¨¸à©€à¨‚ à¨à¨¨à©‹à¨Ÿà©‡à¨¶à¨¨à¨¾à¨‚ ਦਾ ਸੰਪਾਦਨ ਕਰਦੇ ਹੋ, ਤਾਂ ਇਹ ਦਸਤਾਵੇਜ਼ ਇਕਹਿਰੇ ਪੰਨਾ-ਦà©à¨°à¨¿à¨¶ ਅਤੇ ਆਪਣੇ ਮੂਲ ਘà©à¨®à¨¾à¨… 'ਤੇ ਵਾਪਸ ਆ ਜਾਵੇਗਾ</translation>
@@ -494,6 +515,7 @@
<translation id="2523886232349826891">ਸਿਰਫ਼ ਇਸ ਡੀਵਾਈਸ 'ਤੇ ਰੱਖਿਅਤ ਕੀਤਾ ਗਿਆ</translation>
<translation id="2524461107774643265">ਹੋਰ ਜਾਣਕਾਰੀ ਸ਼ਾਮਲ ਕਰੋ</translation>
<translation id="2529899080962247600">ਇਸ ਖੇਤਰ ਵਿੱਚ <ph name="MAX_ITEMS_LIMIT" /> ਤੋਂ ਵੱਧ ਇੰਦਰਾਜ ਨਹੀਂ ਹੋਣੇ ਚਾਹੀਦੇ ਹਨ। ਅਗਲੇ ਸਾਰੇ ਇੰਦਰਾਜ ਅਣਡਿੱਠ ਕੀਤੇ ਜਾਣਗੇ।</translation>
+<translation id="2535585790302968248">ਨਿੱਜੀ ਤੌਰ 'ਤੇ ਬà©à¨°à¨¾à¨Šà¨œà¨¼ ਕਰਨ ਲਈ ਨਵੀਂ ਇਨਕੋਗਨਿਟੋ ਟੈਬ ਖੋਲà©à¨¹à©‹</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{ਅਤੇ 1 ਹੋਰ}one{ਅਤੇ # ਹੋਰ}other{ਅਤੇ # ਹੋਰ}}</translation>
<translation id="2536110899380797252">ਪਤਾ ਸ਼ਾਮਲ ਕਰੋ</translation>
<translation id="2539524384386349900">ਪਤਾ ਲਗਾਓ</translation>
@@ -519,7 +541,14 @@
<translation id="2597378329261239068">ਇਹ ਦਸਤਾਵੇਜ਼ ਪਾਸਵਰਡ ਰੱਖਿਅਤ ਹੈ। ਕਿਰਪਾ ਕਰਕੇ ਇੱਕ ਪਾਸਵਰਡ ਦਰਜ ਕਰੋ।</translation>
<translation id="2609632851001447353">ਵੈਰੀà¨à¨¶à©°à¨¸</translation>
<translation id="2610561535971892504">ਕਾਪੀ ਕਰਨ ਲਈ ਕਲਿੱਕ ਕਰੋ</translation>
+<translation id="2617988307566202237">Chrome ਅੱਗੇ ਦਿੱਤੀ ਜਾਣਕਾਰੀ ਨੂੰ <ph name="BEGIN_EMPHASIS" />ਰੱਖਿਅਤ ਨਹੀਂ ਕਰੇਗਾ<ph name="END_EMPHASIS" />:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ਤà©à¨¹à¨¾à¨¡à¨¾ ਬà©à¨°à¨¾à¨Šà¨œà¨¼à¨¿à©°à¨— ਇਤਿਹਾਸ
+ <ph name="LIST_ITEM" />ਕà©à¨•à©€à¨œà¨¼ ਅਤੇ ਸਾਈਟ ਡਾਟਾ
+ <ph name="LIST_ITEM" />ਫ਼ਾਰਮਾਂ ਵਿੱਚ ਦਾਖਲ ਕੀਤੀ ਜਾਣਕਾਰੀ
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (ਲਿਫ਼ਾਫ਼ਾ)</translation>
+<translation id="2623663032199728144">ਤà©à¨¹à¨¾à¨¡à©€à¨†à¨‚ ਸਕà©à¨°à©€à¨¨à¨¾à¨‚ ਬਾਰੇ ਜਾਣਕਾਰੀ ਵਰਤਣ ਲਈ ਇਜਾਜ਼ਤ ਮੰਗ ਸਕਦੀਆਂ ਹਨ</translation>
<translation id="2625385379895617796">ਤà©à¨¹à¨¾à¨¡à©€ ਘੜੀ ਅੱਗੇ ਹੈ</translation>
<translation id="262745152991669301">ਸਾਈਟ USB ਡੀਵਾਈਸਾਂ ਨਾਲ ਕਨੈਕਟ ਕਰਨ ਲਈ ਪà©à©±à¨› ਸਕਦੀ ਹੈ</translation>
<translation id="2629325967560697240">Chrome ਦੀ ਉੱਚਤਮ ਪੱਧਰ ਦੀ ਸà©à¨°à©±à¨–ਿਆ ਪà©à¨°à¨¾à¨ªà¨¤ ਕਰਨ ਲਈ, <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />ਵਿਸਤà©à¨°à¨¿à¨¤ ਸà©à¨°à©±à¨–ਿਆ ਨੂੰ ਚਾਲੂ ਕਰੋ<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -553,6 +582,7 @@
<translation id="2709516037105925701">ਆਟੋਫਿਲ</translation>
<translation id="2713444072780614174">ਸਫ਼ੈਦ</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />, Tab ਦਬਾਓ, ਫਿਰ Chrome ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਆਪਣੇ ਭà©à¨—ਤਾਨਾਂ ਅਤੇ ਕà©à¨°à©ˆà¨¡à¨¿à¨Ÿ ਕਾਰਡ ਜਾਣਕਾਰੀ ਦਾ ਪà©à¨°à¨¬à©°à¨§à¨¨ ਕਰਨ ਲਈ Enter ਦਬਾਓ</translation>
+<translation id="271663710482723385">ਪੂਰੀ ਸਕà©à¨°à©€à¨¨ ਤੋਂ ਬਾਹਰ ਜਾਣ ਲਈ |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| ਦਬਾਓ</translation>
<translation id="2721148159707890343">ਬੇਨਤੀ ਸਫਲ ਹੋਈ</translation>
<translation id="2723669454293168317">Chrome ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਸà©à¨°à©±à¨–ਿਆ ਜਾਂਚ ਚਲਾਓ</translation>
<translation id="2726001110728089263">ਸਾਈਡ ਟà©à¨°à©‡à¨…</translation>
@@ -583,6 +613,7 @@
<translation id="2850739647070081192">ਸੱਦਾ (ਲਿਫ਼ਾਫ਼ਾ)</translation>
<translation id="2856444702002559011">ਹਮਲਾਵਰ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ਤੋਂ ਤà©à¨¹à¨¾à¨¡à©€ ਜਾਣਕਾਰੀ ਨੂੰ ਚੋਰੀ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰ ਸਕਦੇ ਹਨ (ਉਦਾਹਰਨ ਲਈ, ਪਾਸਵਰਡ, ਸà©à¨¨à©‡à¨¹à©‡, ਜਾਂ ਕà©à¨°à©ˆà¨¡à¨¿à¨Ÿ ਕਾਰਡ)। <ph name="BEGIN_LEARN_MORE_LINK" />ਹੋਰ ਜਾਣੋ<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">ਇਹ ਸਾਈਟ ਦਖਲਅੰਦਾਜ਼ੀ ਜਾਂ ਗà©à¨®à¨°à¨¾à¨¹ ਕਰਨ ਵਾਲੇ ਵਿਗਿਆਪਨ ਦਿਖਾਉਂਦੀ ਹੈ।</translation>
+<translation id="286512204874376891">ਆਭਾਸੀ ਕਾਰਡ ਤà©à¨¹à¨¾à¨¨à©‚à©° ਸੰਭਾਵੀ ਧੋਖਾਧੜੀ ਤੋਂ ਬਚਾਉਣ ਵਿੱਚ ਮਦਦ ਕਰਨ ਲਈ ਤà©à¨¹à¨¾à¨¡à©‡ ਅਸਲ ਕਾਰਡ ਦਾ ਭੇਸ ਲੈਂਦਾ ਹੈ। <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">ਦੋਸਤਾਨਾ</translation>
<translation id="2876489322757410363">ਕਿਸੇ ਬਾਹਰੀ à¨à¨ªà¨²à©€à¨•à©‡à¨¸à¨¼à¨¨ ਰਾਹੀਂ ਭà©à¨—ਤਾਨ ਕਰਨ ਲਈ ਇਨਕੋਗਨਿਟੋ ਮੋਡ ਤੋਂ ਬਾਹਰ ਜਾਇਆ ਜਾ ਰਿਹਾ ਹੈ। ਕੀ ਜਾਰੀ ਰੱਖਣਾ ਹੈ?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />, Tab ਦਬਾ ਕੇ, ਫਿਰ Chrome ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਆਪਣੀ ਸà©à¨°à©±à¨–ਿਅਤ ਬà©à¨°à¨¾à¨Šà¨œà¨¼à¨¿à©°à¨— ਅਤੇ ਹੋਰ ਚੀਜ਼ਾਂ ਦਾ ਪà©à¨°à¨¬à©°à¨§à¨¨ ਕਰਨ ਲਈ Enter ਦਬਾਓ</translation>
@@ -607,6 +638,7 @@
<translation id="2930577230479659665">ਹਰ ਕਾਪੀ ਤੋਂ ਬਾਅਦ ਕਟਾਈ</translation>
<translation id="2932085390869194046">ਪਾਸਵਰਡ ਸà©à¨à¨¾à¨“...</translation>
<translation id="2934466151127459956">ਸਰਕਾਰੀ ਚਿੱਠੀ</translation>
+<translation id="2938225289965773019"><ph name="PROTOCOL" /> ਲਿੰਕ ਖੋਲà©à¨¹à©‹</translation>
<translation id="2941952326391522266">ਇਹ ਸਰਵਰ ਇਹ ਸਾਬਤ ਨਹੀਂ ਕਰ ਸਕਿਆ ਕਿ ਇਹ <ph name="DOMAIN" /> ਹੈ; ਇਸਦਾ ਸà©à¨°à©±à¨–ਿਆ ਪà©à¨°à¨®à¨¾à¨£-ਪੱਤਰ <ph name="DOMAIN2" /> ਵੱਲੋਂ ਹੈ। ਇਹ ਇੱਕ ਗਲਤ ਸੰਰੂਪਣ ਕਾਰਨ ਹੋ ਸਕਦਾ ਹੈ ਜਾਂ ਕੋਈ ਹਮਲਾਵਰ ਤà©à¨¹à¨¾à¨¡à©‡ ਕਨੈਕਸ਼ਨ ਨੂੰ ਰਾਹ ਵਿੱਚ ਰੋਕ ਰਿਹਾ ਹੈ।</translation>
<translation id="2943895734390379394">ਅੱਪਲੋਡ ਦਾ ਸਮਾਂ:</translation>
<translation id="2948083400971632585">ਤà©à¨¸à©€à¨‚ ਸੈਟਿੰਗਾਂ ਪੰਨੇ ਤੋਂ ਇੱਕ ਕਨੈਕਸ਼ਨ ਲਈ ਸੰਰੂਪਣ ਕੀਤੀਆਂ ਕੋਈ ਵੀ ਪà©à¨°à©Œà¨•à¨¸à©€à¨†à¨‚ ਨੂੰ ਅਸਮਰੱਥ ਬਣਾ ਸਕਦੇ ਹੋ।</translation>
@@ -639,6 +671,7 @@
<translation id="3037605927509011580">ਆਹ, ਸਨੈਪ!</translation>
<translation id="3041612393474885105">ਪà©à¨°à¨®à¨¾à¨£-ਪੱਤਰ ਬਾਰੇ ਜਾਣਕਾਰੀ</translation>
<translation id="3044034790304486808">ਆਪਣੀ ਖੋਜ ਨੂੰ ਮà©à©œ-ਚਾਲੂ ਕਰੋ</translation>
+<translation id="305162504811187366">ਟਾਈਮਸਟੈਂਪਾਂ, ਹੋਸਟਾਂ ਅਤੇ ਕਲਾਇੰਟ ਸੈਸ਼ਨ ਆਈਡੀਆਂ ਸਮੇਤ, Chrome ਰਿਮੋਟ ਡੈਸਕਟਾਪ ਦਾ ਇਤਿਹਾਸ</translation>
<translation id="3060227939791841287">C9 (ਲਿਫ਼ਾਫ਼ਾ)</translation>
<translation id="3061707000357573562">ਪੈਚ ਸੇਵਾ</translation>
<translation id="306573536155379004">ਗੇਮ ਸ਼à©à¨°à©‚ ਕੀਤੀ ਗਈ।</translation>
@@ -677,6 +710,7 @@
<translation id="3197136577151645743">ਸਾਈਟ ਤà©à¨¹à¨¾à¨¡à©‡ ਵੱਲੋਂ ਇਸ ਡੀਵਾਈਸ ਦੀ ਸਰਗਰਮੀ ਨਾਲ ਕੀਤੀ ਜਾ ਰਹੀ ਵਰਤੋਂ ਬਾਰੇ ਜਾਣਨ ਲਈ ਪà©à©±à¨› ਸਕਦੀ ਹੈ</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />, Tab ਦਬਾਓ, ਫਿਰ Chrome ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਤà©à¨¸à©€à¨‚ ਜਿਹੜੀ ਜਾਣਕਾਰੀ ਦਾ ਸਿੰਕ ਕਰਦੇ ਹੋ, ਇਸਦਾ ਪà©à¨°à¨¬à©°à¨§à¨¨ ਕਰਨ ਲਈ Enter ਦਬਾਓ</translation>
<translation id="320323717674993345">ਭà©à¨—ਤਾਨ ਰੱਦ ਕਰੋ</translation>
+<translation id="3203366800380907218">ਵੈੱਬ ਤੋਂ</translation>
<translation id="3207960819495026254">ਬà©à©±à¨•à¨®à¨¾à¨°à¨• ਕੀਤੇ</translation>
<translation id="3209034400446768650">ਸ਼ਾਇਦ ਪੰਨੇ ਵੱਲੋਂ ਖਰਚੇ ਲਠਜਾਣ</translation>
<translation id="3212581601480735796"><ph name="HOSTNAME" /> 'ਤੇ ਤà©à¨¹à¨¾à¨¡à©€ ਸਰਗਰਮੀ ਦੀ ਨਿਗਰਾਨੀ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ</translation>
@@ -693,10 +727,12 @@
<translation id="3234666976984236645">ਇਸ ਸਾਈਟ 'ਤੇ ਹਮੇਸ਼ਾਂ ਆਯਾਤ ਸਮੱਗਰੀ ਖੋਜੋ</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />, Tab ਦਬਾ ਕੇ, ਫਿਰ ਆਪਣੇ ਬà©à¨°à¨¾à¨Šà©›à¨° ਦੀ ਦਿੱਖ ਨੂੰ ਵਿਉਂਤਬੱਧ ਕਰਨ ਲਈ Enter ਦਬਾਓ</translation>
<translation id="3240791268468473923">ਭਗਤਾਨ ਕà©à¨°à©€à¨¡à©ˆà¨‚ਸ਼ੀਅਲ ਨੂੰ ਸà©à¨°à©±à¨–ਿਅਤ ਬਣਾਓ ਕੋਈ ਮੇਲ ਖਾਂਦੇ ਕà©à¨°à©€à¨¡à©ˆà¨‚ਸ਼ੀਅਲ ਸੰਬੰਧੀ ਸ਼ੀਟ ਖà©à©±à¨²à©à¨¹à©€ ਨਹੀਂ ਹੈ</translation>
+<translation id="324180406144491771">“<ph name="HOST_NAME" />†ਲਿੰਕਾਂ ਨੂੰ ਬਲਾਕ ਕੀਤਾ ਗਿਆ ਹੈ</translation>
<translation id="3249845759089040423">ਗਰੂਵੀ</translation>
<translation id="3252266817569339921">ਫਰੈਂਚ</translation>
<translation id="3257954757204451555">ਇਸ ਜਾਣਕਾਰੀ ਪਿੱਛੇ ਕੌਣ ਹੈ?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />, Google Calendar ਵਿੱਚ ਤੇਜ਼ੀ ਨਾਲ ਨਵਾਂ ਇਵੈਂਟ ਬਣਾਉਣ ਲਈ Tab ਦਬਾ ਕੇ ਫਿਰ Enter ਦਬਾਓ</translation>
+<translation id="3261488570342242926">ਆਭਾਸੀ ਕਾਰਡ ਬਾਰੇ ਜਾਣੋ</translation>
<translation id="3264837738038045344">'Chrome ਸੈਟਿੰਗਾਂ ਦਾ ਪà©à¨°à¨¬à©°à¨§à¨¨ ਕਰੋ' ਬਟਨ, ਆਪਣੀਆਂ Chrome ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਜਾਣ ਲਈ Enter ਦਬਾਓ</translation>
<translation id="3266793032086590337">ਮà©à©±à¨² (ਵਿਵਾਦ)</translation>
<translation id="3268451620468152448">ਟੈਬਸ ਖੋਲà©à¨¹à©‹</translation>
@@ -710,6 +746,7 @@
<translation id="3288238092761586174"><ph name="URL" /> ਨੂੰ ਤà©à¨¹à¨¾à¨¡à©‡ ਭà©à¨—ਤਾਨ ਦੀ ਪà©à¨¶à¨Ÿà©€ ਕਰਨ ਲਈ ਵਧੀਕ ਕਦਮ ਚà©à©±à¨•à¨£ ਦੀ ਲੋੜ ਪੈ ਸਕਦੀ ਹੈ</translation>
<translation id="3293642807462928945"><ph name="POLICY_NAME" /> ਨੀਤੀ ਬਾਰੇ ਹੋਰ ਜਾਣੋ</translation>
<translation id="3295444047715739395">Chrome ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਆਪਣੇ ਪਾਸਵਰਡ ਦੇਖੋ ਅਤੇ ਉਹਨਾਂ ਦਾ ਪà©à¨°à¨¬à©°à¨§à¨¨ ਕਰੋ</translation>
+<translation id="3303795387212510132">ਕੀ à¨à¨ª ਨੂੰ <ph name="PROTOCOL_SCHEME" /> ਲਿੰਕ ਖੋਲà©à¨¹à¨£ ਦੀ ਆਗਿਆ ਦੇਣੀ ਹੈ?</translation>
<translation id="3303855915957856445">ਕੋਈ ਖੋਜ ਨਤੀਜੇ ਨਹੀਂ ਮਿਲੇ</translation>
<translation id="3304073249511302126">ਬਲੂਟà©à©±à¨¥ ਸਕੈਨਿੰਗ</translation>
<translation id="3308006649705061278">ਸੰਸਥਾਈ ਯੂਨਿਟ (OU)</translation>
@@ -723,12 +760,6 @@
<translation id="3345782426586609320">ਅੱਖਾਂ</translation>
<translation id="3355823806454867987">ਪà©à¨°à©Œà¨•à¨¸à©€ ਸੈਟਿੰਗਾਂ ਬਦਲੋ...</translation>
<translation id="3360103848165129075">ਭà©à¨—ਤਾਨ ਹੈਂਡਲਰ ਸ਼ੀਟ</translation>
-<translation id="3361596688432910856">Chrome ਅੱਗੇ ਦਿੱਤੀ ਜਾਣਕਾਰੀ ਨੂੰ <ph name="BEGIN_EMPHASIS" />ਰੱਖਿਅਤ ਨਹੀਂ ਕਰੇਗਾ<ph name="END_EMPHASIS" />:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />ਤà©à¨¹à¨¾à¨¡à¨¾ ਬà©à¨°à¨¾à¨Šà¨œà¨¼à¨¿à©°à¨— ਇਤਿਹਾਸ
- <ph name="LIST_ITEM" />ਕà©à¨•à©€à¨œà¨¼ ਅਤੇ ਸਾਈਟ ਡਾਟਾ
- <ph name="LIST_ITEM" />ਫ਼ਾਰਮਾਂ ਵਿੱਚ ਦਾਖਲ ਕੀਤੀ ਜਾਣਕਾਰੀ
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">ਇਹ ਨੀਤੀ ਨਾਪਸੰਦ ਕੀਤੀ <ph name="OLD_POLICY" /> ਨੀਤੀ ਤੋਂ ਸਵੈਚਲਿਤ ਤੌਰ 'ਤੇ ਕਾਪੀ ਕੀਤੀ ਗਈ। ਤà©à¨¹à¨¾à¨¨à©‚à©° ਇਸਦੀ ਬਜਾਠਇਸ ਨੀਤੀ ਨੂੰ ਵਰਤਣਾ ਚਾਹੀਦਾ ਹੈ।</translation>
<translation id="3364869320075768271"><ph name="URL" /> ਦੀ ਤà©à¨¹à¨¾à¨¡à©‡ ਆਭਾਸੀ ਵਾਸਤਵਿਕਤਾ ਡੀਵਾਈਸ ਅਤੇ ਡਾਟੇ ਨੂੰ ਵਰਤਣ ਦੀ ਇੱਛਾ ਹੈ</translation>
<translation id="3366477098757335611">ਕਾਰਡ ਦੇਖੋ</translation>
@@ -811,7 +842,6 @@
<translation id="3587738293690942763">ਵਿਚਕਾਰ</translation>
<translation id="3592413004129370115">ਇਤਾਲਵੀ (ਲਿਫ਼ਾਫ਼ਾ)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{ਤà©à¨¸à©€à¨‚ ਕਿਸੇ ਵੀ ਸਮੇਂ ਆਪਣਾ ਗਰà©à©±à¨ª ਰੀਸੈੱਟ ਕਰ ਸਕਦੇ ਹੋ। ਇੱਕ ਨਵੇਂ ਗਰà©à©±à¨ª ਵਿੱਚ ਸ਼ਾਮਲ ਹੋਣ ਲਈ ਲਗਭਗ ਇੱਕ ਦਿਨ ਦਾ ਸਮਾਂ ਲੱਗਦਾ ਹੈ।}=1{ਤà©à¨¸à©€à¨‚ ਕਿਸੇ ਵੀ ਸਮੇਂ ਆਪਣਾ ਗਰà©à©±à¨ª ਰੀਸੈੱਟ ਕਰ ਸਕਦੇ ਹੋ। ਇੱਕ ਨਵੇਂ ਗਰà©à©±à¨ª ਵਿੱਚ ਸ਼ਾਮਲ ਹੋਣ ਲਈ ਲਗਭਗ ਇੱਕ ਦਿਨ ਦਾ ਸਮਾਂ ਲੱਗਦਾ ਹੈ।}other{ਤà©à¨¸à©€à¨‚ ਕਿਸੇ ਵੀ ਸਮੇਂ ਆਪਣਾ ਗਰà©à©±à¨ª ਰੀਸੈੱਟ ਕਰ ਸਕਦੇ ਹੋ। ਇੱਕ ਨਵੇਂ ਗਰà©à©±à¨ª ਵਿੱਚ ਸ਼ਾਮਲ ਹੋਣ ਲਈ ਲਗਭਗ {NUM_DAYS} ਦਿਨਾਂ ਦਾ ਸਮਾਂ ਲੱਗਦਾ ਹੈ।}}</translation>
-<translation id="3596012367874587041">à¨à¨ª ਸੈਟਿੰਗਾਂ</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">à¨à¨ªà¨²à©€à¨•à©‡à¨¸à¨¼à¨¨ ਨੂੰ ਤà©à¨¹à¨¾à¨¡à©‡ ਪà©à¨°à¨¸à¨¼à¨¾à¨¸à¨• ਵੱਲੋਂ ਬਲਾਕ ਕੀਤਾ ਗਿਆ</translation>
<translation id="3608932978122581043">ਦਿਸ਼ਾਮਾਨ ਫ਼ੀਡ ਕਰੋ</translation>
@@ -853,6 +883,7 @@
<translation id="370972442370243704">ਖੋਜ ਸਫ਼ਰ ਚਾਲੂ ਕਰੋ</translation>
<translation id="3711895659073496551">ਮà©à¨…ੱਤਲ</translation>
<translation id="3712624925041724820">ਲਸੰਸ ਸੱਖਣੇ ਕੀਤੇ</translation>
+<translation id="3714633008798122362">ਵੈਬ ਕੈਲੰਡਰ</translation>
<translation id="3714780639079136834">ਸੈਲਿਊਲਰ ਡਾਟਾ ਜਾਂ Wi-Fi ਨੂੰ ਚਾਲੂ ਕਰੋ</translation>
<translation id="3715597595485130451">ਵਾਈ-ਫਾਈ ਨਾਲ ਕਨੈਕਟ ਕਰੋ</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />ਪà©à¨°à©Œà¨•à¨¸à©€, ਫ਼ਾਇਰਵਾਲ, ਅਤੇ DNS ਸੰਰੂਪਣ ਦੀ ਜਾਂਚ ਕਰੋ<ph name="END_LINK" /></translation>
@@ -914,6 +945,7 @@
<translation id="3906954721959377182">ਟੈਬਲੈੱਟ</translation>
<translation id="3909477809443608991"><ph name="URL" /> ਸà©à¨°à©±à¨–ਿਅਤ ਕੀਤੀ ਸਮੱਗਰੀ ਚਲਾਉਣਾ ਚਾਹà©à©°à¨¦à©‡ ਹਨ। ਤà©à¨¹à¨¾à¨¡à©‡ ਡੀਵਾਈਸ ਦੀ ਪਛਾਣ ਨੂੰ Google ਵੱਲੋਂ ਪà©à¨°à¨®à¨¾à¨£à¨¿à¨¤ ਕੀਤਾ ਜਾਵੇਗਾ ਅਤੇ ਇਸ ਸਾਈਟ ਦà©à¨†à¨°à¨¾ ਇਸ ਤੱਕ ਪਹà©à©°à¨š ਕੀਤੀ ਜਾ ਸਕਦੀ ਹੈ।</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">ਅਸਵੀਕਾਰ ਕਰੋ</translation>
<translation id="3939773374150895049">ਕੀ CVC ਦੀ ਬਜਾਠWebAuthn ਨੂੰ ਵਰਤਣਾ ਹੈ?</translation>
<translation id="3946209740501886391">ਹਮੇਸ਼ਾ ਇਸ ਸਾਈਟ 'ਤੇ ਪà©à©±à¨›à©‹</translation>
<translation id="3947595700203588284">ਸਾਈਟ MIDI ਡੀਵਾਈਸਾਂ ਨਾਲ ਕਨੈਕਟ ਕਰਨ ਲਈ ਪà©à©±à¨› ਸਕਦੀ ਹੈ</translation>
@@ -934,6 +966,7 @@
<translation id="3987940399970879459">1 MB ਤੋਂ ਘੱਟ</translation>
<translation id="3990250421422698716">ਜੌਗ ਆਫ਼ਸੈੱਟ</translation>
<translation id="3996311196211510766">ਸਾਈਟ <ph name="ORIGIN" /> ਨੇ ਬੇਨਤੀ ਕੀਤੀ ਹੈ ਕਿ ਮੂਲ ਸੰਬੰਧੀ ਨੀਤੀ ਨੂੰ ਉਸ ਦੀਆਂ ਸਾਰੀਆਂ ਬੇਨਤੀਆਂ 'ਤੇ ਲਾਗੂ ਕੀਤਾ ਜਾਂਦਾ ਹੈ, ਪਰ ਇਸ ਨੀਤੀ ਨੂੰ ਫਿਲਹਾਲ ਲਾਗੂ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ।</translation>
+<translation id="4009243425692662128">ਤà©à¨¹à¨¾à¨¡à©‡ ਵੱਲੋਂ ਪà©à¨°à¨¿à©°à¨Ÿ ਕੀਤੇ ਗਠਪੰਨਿਆਂ ਦੀ ਸਮੱਗਰੀ ਨੂੰ ਵਿਸ਼ਲੇਸ਼ਣ ਲਈ Google ਕਲਾਊਡ ਜਾਂ ਤੀਜੀਆਂ ਧਿਰਾਂ ਨੂੰ ਭੇਜਿਆ ਜਾਂਦਾ ਹੈ। ਉਦਾਹਰਨ ਲਈ, ਇਸਨੂੰ ਸੰਵੇਦਨਸ਼ੀਲ ਡਾਟੇ ਲਈ ਸਕੈਨ ਕੀਤਾ ਜਾ ਸਕਦਾ ਹੈ।</translation>
<translation id="4010758435855888356">ਕੀ ਸਟੋਰੇਜ ਤੱਕ ਪਹà©à©°à¨š ਦੀ ਆਗਿਆ ਦੇਣੀ ਹੋ?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{PDF ਦਸਤਾਵੇਜ਼ ਵਿੱਚ {COUNT} ਪੰਨਾ ਹੈ}one{PDF ਦਸਤਾਵੇਜ਼ ਵਿੱਚ {COUNT} ਪੰਨਾ ਹੈ}other{PDF ਦਸਤਾਵੇਜ਼ ਵਿੱਚ {COUNT} ਪੰਨੇ ਹਨ}}</translation>
<translation id="4023431997072828269">ਕਿਉਂਕਿ ਇਸ ਫ਼ਾਰਮ ਨੂੰ ਅਜਿਹੇ ਕਨੈਕਸ਼ਨ ਦੀ ਵਰਤੋਂ ਨਾਲ ਸਪà©à¨°à¨¦ ਕੀਤਾ ਗਿਆ ਹੈ ਜੋ ਸà©à¨°à©±à¨–ਿਅਤ ਨਹੀਂ ਹੈ, ਤà©à¨¹à¨¾à¨¡à©€ ਜਾਣਕਾਰੀ ਹੋਰਾਂ ਨੂੰ ਦਿਸੇਗੀ।</translation>
@@ -1024,6 +1057,7 @@
<translation id="4250680216510889253">ਨਹੀਂ</translation>
<translation id="4253168017788158739">ਨੋਟ</translation>
<translation id="425582637250725228">ਹੋ ਸਕਦਾ ਹੈ ਕਿ ਤà©à¨¹à¨¾à¨¡à©‡ ਵੱਲੋਂ ਕੀਤੇ ਗਠਬਦਲਾਅ ਰੱਖਿਅਤ ਨਾ ਕੀਤੇ ਜਾਣ।</translation>
+<translation id="425869179292622354">ਕੀ ਇਸਨੂੰ ਆਭਾਸੀ ਕਾਰਡ ਨਾਲ ਹੋਰ ਸà©à¨°à©±à¨–ਿਅਤ ਬਣਾਉਣਾ ਹੈ?</translation>
<translation id="4258748452823770588">ਖ਼ਰਾਬ ਹਸਤਾਖਰ</translation>
<translation id="4261046003697461417">ਸà©à¨°à©±à¨–ਿਅਤ ਕੀਤੇ ਦਸਤਾਵੇਜ਼ਾਂ ਨੂੰ à¨à¨¨à©‹à¨Ÿà©‡à¨Ÿ ਨਹੀਂ ਕਰ ਸਕਦੇ</translation>
<translation id="4265872034478892965">ਤà©à¨¹à¨¾à¨¡à©‡ ਪà©à¨°à¨¶à¨¾à¨¸à¨• ਵੱਲੋਂ ਇਜਾਜ਼ਤ ਦਿੱਤੀ ਗਈ</translation>
@@ -1086,6 +1120,7 @@
<translation id="4434045419905280838">ਪੌਪ-ਅੱਪ ਅਤੇ ਰੀਡਾਇਰੈਕਟ</translation>
<translation id="4435702339979719576">ਪੋਸਟਕਾਰਡ)</translation>
<translation id="443673843213245140">ਇੱਕ ਪà©à¨°à©Œà¨•à¨¸à©€ ਦੀ ਵਰਤੋਂ ਅਸਮਰਥਿਤ ਹੈ ਪਰੰਤੂ ਇੱਕ ਸਪਸ਼ਟ ਪà©à¨°à©Œà¨•à¨¸à©€ ਕੌਂਫਿਗਰੇਸ਼ਨ ਨਿਸ਼ਚਿਤ ਹੈ।</translation>
+<translation id="4441832193888514600">ਅਣਡਿੱਠ ਕੀਤਾ ਗਿਆ ਕਿਉਂਕਿ ਨੀਤੀ ਨੂੰ ਸਿਰਫ਼ ਕਲਾਊਡ ਵਰਤੋਂਕਾਰ ਨੀਤੀ ਵਜੋਂ ਹੀ ਸੈੱਟ ਕੀਤਾ ਜਾ ਸਕਦਾ ਹੈ।</translation>
<translation id="4450893287417543264">ਦà©à¨¬à¨¾à¨°à¨¾ ਨਾ ਦਿਖਾਓ</translation>
<translation id="4451135742916150903">ਸਾਈਟ HID ਡੀਵਾਈਸਾਂ ਨਾਲ ਕਨੈਕਟ ਕਰਨ ਲਈ ਪà©à©±à¨› ਸਕਦੀ ਹੈ</translation>
<translation id="4452328064229197696">ਤà©à¨¹à¨¾à¨¡à©‡ ਵੱਲੋਂ ਹà©à¨£à©‡ ਹੀ ਵਰਤਿਆ ਗਿਆ ਪਾਸਵਰਡ ਡਾਟਾ ਉਲੰਘਣਾ ਵਿੱਚ ਮਿਲਿਆ ਸੀ। ਆਪਣੇ ਖਾਤਿਆਂ ਨੂੰ ਸà©à¨°à©±à¨–ਿਅਤ ਕਰਨ ਲਈ, Google ਪਾਸਵਰਡ ਪà©à¨°à¨¬à©°à¨§à¨• ਆਪਣੇ ਰੱਖਿਅਤ ਕੀਤੇ ਪਾਸਵਰਡਾਂ ਦੀ ਜਾਂਚ ਕਰਨ ਦੀ ਸਿਫ਼ਾਰਸ਼ ਕਰਦਾ ਹੈ।</translation>
@@ -1141,6 +1176,7 @@
<translation id="4628948037717959914">ਫ਼ੋਟੋ</translation>
<translation id="4631649115723685955">ਕੈਸ਼ਬੈਕ ਨੂੰ ਲਿੰਕ ਕੀਤਾ ਗਿਆ</translation>
<translation id="4636930964841734540">ਜਾਣਕਾਰੀ</translation>
+<translation id="4638670630777875591">Chromium ਵਿੱਚ ਇਨਕੋਗਨਿਟੋ ਮੋਡ</translation>
<translation id="464342062220857295">'ਖੋਜ' ਦੀਆਂ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ</translation>
<translation id="4644670975240021822">ਉਲਟੇ ਕà©à¨°à¨® ਵਿੱਚ ਪਾਸਾ ਹੇਠਾਂ ਕੀਤੇ ਹੋà¨</translation>
<translation id="4646534391647090355">ਮੈਨੂੰ ਹà©à¨£à©‡ ਉੱਥੇ ਲੈ ਜਾਓ</translation>
@@ -1161,6 +1197,7 @@
<translation id="4708268264240856090">ਤà©à¨¹à¨¾à¨¡à©‡ ਕਨੈਕਸ਼ਨ ਵਿੱਚ ਰà©à¨•à¨¾à¨µà¨Ÿ ਆਈ ਸੀ</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Windows ਨੈੱਟਵਰਕ ਤਸ਼ਖੀਸ ਚਲਾਇਆ ਜਾ ਰਿਹਾ ਹੈ<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426"><ph name="USERNAME" /> ਦਾ ਪਾਸਵਰਡ</translation>
<translation id="4724144314178270921">ਸਾਈਟ ਤà©à¨¹à¨¾à¨¡à©‡ ਕਲਿੱਪਬੋਰਡ 'ਤੇ ਲਿਖਤ ਅਤੇ ਚਿੱਤਰਾਂ ਨੂੰ ਦੇਖਣ ਲਈ ਪà©à©±à¨› ਸਕਦੀ ਹੈ</translation>
<translation id="4726672564094551039">ਨੀਤੀਆਂ ਰੀਲੋਡ ਕਰੋ</translation>
<translation id="4728558894243024398">ਪਲੇਟਫਾਰਮ</translation>
@@ -1182,6 +1219,7 @@
<translation id="4757993714154412917">ਤà©à¨¸à©€à¨‚ ਹà©à¨£à©‡-ਹà©à¨£à©‡ ਕਿਸੇ ਧੋਖੇਬਾਜ਼ ਸਾਈਟ 'ਤੇ ਆਪਣਾ ਪਾਸਵਰਡ ਦਾਖਲ ਕੀਤਾ ਹੈ। ਤà©à¨¹à¨¾à¨¡à©‡ ਖਾਤਿਆਂ ਨੂੰ ਸà©à¨°à©±à¨–ਿਅਤ ਕਰਨ ਲਈ, Chromium ਤà©à¨¹à¨¾à¨¡à©‡ ਰੱਖਿਅਤ ਕੀਤੇ ਪਾਸਵਰਡ ਦੀ ਹà©à¨£à©‡ ਜਾਂਚ ਕਰਨ ਦੀ ਸਿਫ਼ਾਰਸ਼ ਕਰਦਾ ਹੈ।</translation>
<translation id="4758311279753947758">ਸੰਪਰਕ ਜਾਣਕਾਰੀ ਸ਼ਾਮਲ ਕਰੋ</translation>
<translation id="4761104368405085019">ਆਪਣਾ ਮਾਈਕà©à¨°à©‹à¨«à©‹à¨¨ ਵਰਤੋ</translation>
+<translation id="4761869838909035636">Chrome ਸà©à¨°à©±à¨–ਿਆ ਜਾਂਚ ਚਲਾਓ</translation>
<translation id="4764776831041365478"><ph name="URL" /> ਤੇ ਵੈਬਪੇਜ ਅਸਥਾਈ ਤੌਰ ਤੇ ਹੌਲੀ ਹੋ ਸਕਦਾ ਹੈ ਜਾਂ ਇਹ ਸਥਾਈ ਤੌਰ ਤੇ ਕਿਸੇ ਨਵੇਂ ਵੈਬ ਪਤੇ ਤੇ ਮੂਵ ਹੋ ਗਿਆ ਹੋ ਸਕਦਾ ਹੈ।</translation>
<translation id="4766713847338118463">ਹੇਠਾਂ ਦੋ ਪਿੰਨਾਂ</translation>
<translation id="4771973620359291008">ਇੱਕ ਅਗਿਆਤ ਗੜਬੜ ਹੋਈ ਹੈ।</translation>
@@ -1202,12 +1240,6 @@
<translation id="4819347708020428563">ਕੀ ਪੂਰਵ-ਨਿਰਧਾਰਤ ਦà©à¨°à¨¿à¨¸à¨¼ ਵਿੱਚ à¨à¨¨à©‹à¨Ÿà©‡à¨¶à¨¨à¨¾à¨‚ ਦਾ ਸੰਪਾਦਨ ਕਰਨਾ ਹੈ?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />, ਤੇਜ਼ੀ ਨਾਲ ਨਵੀਂ Google ਸ਼ੀਟ ਬਣਾਉਣ ਲਈ Tab ਦਬਾ ਕੇ ਫਿਰ Enter ਦਬਾਓ</translation>
<translation id="4825507807291741242">ਸ਼ਕਤੀਸ਼ਾਲੀ</translation>
-<translation id="4827402517081186284">ਇਨਕੋਗਨਿਟੋ ਮੋਡ ਤà©à¨¹à¨¾à¨¨à©‚à©° ਆਨਲਾਈਨ ਅਦਿੱਖ ਨਹੀਂ ਬਣਾਉਂਦਾ:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />ਜਦੋਂ ਤà©à¨¸à©€à¨‚ ਸਾਈਟਾਂ 'ਤੇ ਜਾਂਦੇ ਹੋ, ਤਾਂ ਉਨà©à¨¹à¨¾à¨‚ ਨੂੰ ਇਸ ਬਾਰੇ ਪਤਾ ਲੱਗਦਾ ਹੈ<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />ਰà©à©›à¨—ਾਰਦਾਤੇ ਜਾਂ ਸਕੂਲ ਬà©à¨°à¨¾à¨Šà¨œà¨¼à¨¿à©°à¨— ਸਰਗਰਮੀ ਨੂੰ ਟਰੈਕ ਕਰ ਸਕਦੇ ਹਨ<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />ਇੰਟਰਨੈੱਟ ਸੇਵਾ ਪà©à¨°à¨¦à¨¾à¨¨à¨• ਵੈੱਬ ਟਰੈਫ਼ਿਕ ਨੂੰ ਮਾਨੀਟਰ ਕਰ ਸਕਦੇ ਹਨ<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">ਚਿਤਾਵਨੀਆਂ ਚਾਲੂ ਕਰੋ</translation>
<translation id="4838327282952368871">ਸà©à¨ªà¨¨à¨®à¨ˆ</translation>
<translation id="4840250757394056958">ਆਪਣਾ Chrome ਇਤਿਹਾਸ ਦੇਖੋ</translation>
@@ -1219,12 +1251,12 @@
<translation id="4854362297993841467">ਇਹ ਅਦਾਇਗੀ ਵਿਧੀ ਉਪਲਬਧ ਨਹੀਂ ਹੈ। ਕੋਈ ਵੱਖਰੀ ਵਿਧੀ ਅਜ਼ਮਾਓ।</translation>
<translation id="4854853140771946034">Google Keep ਵਿੱਚ ਤੇਜ਼ੀ ਨਾਲ ਨਵਾਂ ਨੋਟ-ਕਥਨ ਬਣਾਓ</translation>
<translation id="485902285759009870">ਕੋਡ ਦੀ ਪà©à¨¸à¨¼à¨Ÿà©€ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ...</translation>
+<translation id="4866506163384898554">ਆਪਣਾ ਕਰਸਰ ਦਿਖਾਉਣ ਲਈ |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| ਦਬਾਓ</translation>
<translation id="4876188919622883022">ਸਰਲੀਕਿਰਤ ਦà©à¨°à¨¿à¨¶</translation>
<translation id="4876305945144899064">ਕੋਈ ਵਰਤੋਂਕਾਰ ਨਾਮ ਨਹੀਂ</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{ਕੋਈ ਨਹੀਂ}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831"><ph name="TEXT" /> ਖੋਜ</translation>
<translation id="4879491255372875719">ਸਵੈਚਲਿਤ (ਪੂਰਵ-ਨਿਰਧਾਰਤ)</translation>
-<translation id="4879725228911483934">ਆਪਣੀਆਂ ਸਕà©à¨°à©€à¨¨à¨¾à¨‚ 'ਤੇ ਵਿੰਡੋ ਖੋਲà©à¨¹à©‹ ਅਤੇ ਉਸਨੂੰ ਰੱਖੋ</translation>
<translation id="4880827082731008257">ਖੋਜ ਇਤਿਹਾਸ</translation>
<translation id="4881695831933465202">ਖੋਲà©à¨¹à©‹</translation>
<translation id="4885256590493466218">ਚੈੱਕਆਊਟ ਕਰਨ ਵੇਲੇ <ph name="CARD_DETAIL" /> ਨਾਲ ਭà©à¨—ਤਾਨ ਕਰੋ</translation>
@@ -1233,6 +1265,7 @@
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">ਨੌਵਾਂ ਰੋਲ</translation>
<translation id="4901778704868714008">ਰੱਖਿਅਤ ਕਰੋ...</translation>
+<translation id="4905659621780993806">ਤà©à¨¹à¨¾à¨¡à¨¾ ਪà©à¨°à¨¸à¨¼à¨¾à¨¸à¨• <ph name="DATE" /> ਨੂੰ <ph name="TIME" /> ਵਜੇ ਤà©à¨¹à¨¾à¨¡à©‡ ਡੀਵਾਈਸ ਨੂੰ ਸਵੈਚਲਿਤ ਤੌਰ 'ਤੇ ਮà©à©œ-ਸ਼à©à¨°à©‚ ਕਰੇਗਾ। ਤà©à¨¹à¨¾à¨¡à©‡ ਡੀਵਾਈਸ ਦੇ ਮà©à©œ-ਸ਼à©à¨°à©‚ ਹੋਣ ਤੋਂ ਪਹਿਲਾਂ, ਖà©à©±à¨²à©€ ਹੋਈ ਕਿਸੇ ਵੀ ਆਈਟਮ ਨੂੰ ਰੱਖਿਅਤ ਕਰੋ।</translation>
<translation id="4913987521957242411">ਉੱਪਰ ਖੱਬੇ ਪਾਸੇ ਮੋਰੀ</translation>
<translation id="4918221908152712722"><ph name="APP_NAME" /> ਸਥਾਪਤ ਕਰੋ (ਕੋਈ ਡਾਊਨਲੋਡ ਲੋੜੀਂਦਾ ਨਹੀਂ ਹੈ)</translation>
<translation id="4923459931733593730">ਭà©à¨—ਤਾਨ ਵਿਧੀ</translation>
@@ -1241,6 +1274,7 @@
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, Tab ਦਬਾਓ, ਫਿਰ ਖੋਜ ਕਰਨ ਲਈ Enter ਦਬਾਓ</translation>
<translation id="4930153903256238152">ਵੱਧ ਸਮਰੱਥਾ</translation>
+<translation id="4940163644868678279">Chrome ਵਿੱਚ ਇਨਕੋਗਨਿਟੋ ਮੋਡ</translation>
<translation id="4943872375798546930">ਕੋਈ ਨਤੀਜੇ ਨਹੀਂ</translation>
<translation id="4950898438188848926">ਟੈਬ ਬਦਲਣ ਦਾ ਬਟਨ, ਖà©à©±à¨²à©à¨¹à©€ ਟੈਬ, <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /> 'ਤੇ ਜਾਣ ਲਈ à¨à¨‚ਟਰ ਦਬਾਓ</translation>
<translation id="495170559598752135">ਕਿਰਿਆਵਾਂ</translation>
@@ -1250,6 +1284,7 @@
<translation id="4968522289500246572">ਇਹ à¨à¨ª ਮੋਬਾਈਲ ਲਈ ਡਿਜ਼ਾਈਨ ਕੀਤੀ ਗਈ ਹੈ ਅਤੇ ਹੋ ਸਕਦਾ ਹੈ ਕਿ ਇਸਦਾ ਆਕਾਰ ਸਹੀ ਤਰੀਕੇ ਨਾਲ ਨਾ ਬਦਲੇ। à¨à¨ª ਵਿਚ ਸਮੱਸਿਆਵਾਂ ਆ ਸਕਦੀਆਂ ਹਨ ਜਾਂ ਮà©à©œ-ਸ਼à©à¨°à©‚ ਹੋ ਸਕਦੀ ਹੈ।</translation>
<translation id="4969341057194253438">ਰਿਕਾਰਡਿੰਗ ਨੂੰ ਮਿਟਾਓ</translation>
<translation id="4973922308112707173">ਉੱਪਰ ਦੋ ਮੋਰੀਆਂ</translation>
+<translation id="4976702386844183910">ਪਿਛਲੀ ਵਾਰ <ph name="DATE" /> ਨੂੰ ਦੇਖੀ ਗਈ</translation>
<translation id="4984088539114770594">ਕੀ ਮਾਈਕà©à¨°à©‹à¨«à¨¼à©‹à¨¨ ਵਰਤਣਾ ਹੈ?</translation>
<translation id="4984339528288761049">Prc5 (ਲਿਫ਼ਾਫ਼ਾ)</translation>
<translation id="4989163558385430922">ਸਭ ਦੇਖੋ</translation>
@@ -1311,6 +1346,7 @@
<translation id="5138227688689900538">ਘੱਟ ਦਿਖਾਓ</translation>
<translation id="5145883236150621069">ਨੀਤੀ ਜਵਾਬ ਵਿੱਚ ਗੜਬੜ ਕੋਡ ਹੈ</translation>
<translation id="5146995429444047494"><ph name="ORIGIN" /> ਦੀਆਂ ਸੂਚਨਾਵਾਂ ਬਲਾਕ ਹਨ</translation>
+<translation id="514704532284964975"><ph name="URL" /> ਨੂੰ ਉਨà©à¨¹à¨¾à¨‚ NFC ਡੀਵਾਈਸਾਂ 'ਤੇ ਜਾਣਕਾਰੀ ਦੇਖਣ ਅਤੇ ਬਦਲਣ ਦੀ ਇਜਾਜ਼ਤ ਚਾਹੀਦੀ ਹੈ ਜੋ ਤà©à¨¸à©€à¨‚ ਆਪਣੇ ਫ਼ੋਨ ਨਾਲ ਟੈਪ ਕਰਦੇ ਹੋ</translation>
<translation id="5148809049217731050">ਉੱਪਰ ਵੱਲ ਪਾਸਾ ਕੀਤੇ</translation>
<translation id="515292512908731282">C4 (ਲਿਫ਼ਾਫ਼ਾ)</translation>
<translation id="5158275234811857234">ਕਵਰ</translation>
@@ -1335,6 +1371,7 @@
<translation id="5215116848420601511">Google Pay ਦੀ ਵਰਤੋਂ ਕਰਨ ਵਾਲੀਆਂ ਭà©à¨—ਤਾਨ ਵਿਧੀਆਂ ਅਤੇ ਪਤੇ</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">ਟà©à¨°à©‡à¨… 13</translation>
+<translation id="5216942107514965959">ਪਿਛਲੀ ਵਾਰ ਅੱਜ ਦੇਖੀ ਗਈ</translation>
<translation id="5222812217790122047">ਈਮੇਲ ਲੋੜੀਂਦੀ ਹੈ</translation>
<translation id="5230733896359313003">ਸ਼ਿਪਿੰਗ ਪਤਾ</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1355,7 +1392,6 @@
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">ਦਸਤਾਵੇਜ਼ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ</translation>
<translation id="528468243742722775">ਸਮਾਪਤੀ</translation>
-<translation id="5284909709419567258">ਨੈੱਟਵਰਕ ਪਤੇ</translation>
<translation id="5285570108065881030">ਸਾਰੇ ਰੱਖਿਅਤ ਕੀਤੇ ਪਾਸਵਰਡ ਦਿਖਾਓ</translation>
<translation id="5287240709317226393">ਕà©à¨•à©€à¨œà¨¼ ਦਿਖਾਓ</translation>
<translation id="5287456746628258573">ਇਹ ਸਾਈਟ ਪà©à¨°à¨¾à¨£à©‡ ਸà©à¨°à©±à¨–ਿਆ ਸੰਰੂਪਣ ਦੀ ਵਰਤੋਂ ਕਰਦੀ ਹੈ, ਜਿਸ ਨਾਲ ਇਸ ਸਾਈਟ 'ਤੇ ਭੇਜੀ ਜਾਣ ਵਾਲੀ ਤà©à¨¹à¨¾à¨¡à©€ ਜਾਣਕਾਰੀ (ਉਦਾਹਰਨ ਲਈ, ਪਾਸਵਰਡ ਜਾਂ ਕà©à¨°à©ˆà¨¡à¨¿à¨Ÿ ਕਾਰਡ ਨੰਬਰ) ਪà©à¨°à¨—ਟ ਹੋ ਸਕਦੀ ਹੈ।</translation>
@@ -1439,6 +1475,7 @@
<translation id="5556459405103347317">ਰੀਲੋਡ ਕਰੋ</translation>
<translation id="5560088892362098740">ਮਿਆਦ ਸਮਾਪਤੀ ਦੀ ਮਿਤੀ</translation>
<translation id="55635442646131152">ਦਸਤਾਵੇਜ਼ ਰੂਪ-ਰੇਖਾ</translation>
+<translation id="5565613213060953222">ਇਨਕੋਗਨਿਟੋ ਟੈਬ ਖੋਲà©à¨¹à©‹</translation>
<translation id="5565735124758917034">ਸਕਿਰਿਆ</translation>
<translation id="5570825185877910964">ਖਾਤੇ ਦੀ ਸà©à¨°à©±à¨–ਿਆ ਕਰੋ</translation>
<translation id="5571083550517324815">ਇਸ ਪਤੇ ਤੋਂ ਪਿੱਕਅੱਪ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ। ਕਿਸੇ ਵੱਖਰੇ ਪਤੇ ਨੂੰ ਚà©à¨£à©‹à¥¤</translation>
@@ -1521,6 +1558,7 @@
<translation id="5869522115854928033">ਸà©à¨°à©±à¨–ਿਅਤ ਕੀਤੇ ਪਾਸਵਰਡ</translation>
<translation id="5873013647450402046">ਤà©à¨¹à¨¾à¨¡à¨¾ ਬੈਂਕ ਤਸਦੀਕ ਕਰਨਾ ਚਾਹà©à©°à¨¦à¨¾ ਹੈ ਕਿ ਇਹ ਤà©à¨¸à©€à¨‚ ਹੀ ਹੋ।</translation>
<translation id="5887400589839399685">ਕਾਰਡ ਰੱਖਿਅਤ ਕੀਤਾ ਗਿਆ</translation>
+<translation id="5887687176710214216">ਪਿਛਲੀ ਵਾਰ ਕੱਲà©à¨¹ ਦੇਖੀ ਗਈ</translation>
<translation id="5895138241574237353">ਰੀਸਟਾਰਟ ਕਰੋ</translation>
<translation id="5895187275912066135">ਨੂੰ ਜਾਰੀ ਕੀਤਾ</translation>
<translation id="5901630391730855834">ਪੀਲਾ</translation>
@@ -1534,6 +1572,7 @@
<translation id="5921639886840618607">ਕੀ ਕਾਰਡ ਨੂੰ Google ਖਾਤੇ ਵਿੱਚ ਰੱਖਿਅਤ ਕਰਨਾ ਹੈ?</translation>
<translation id="5922853866070715753">ਲਗਭਗ ਹੋ ਗਿਆ</translation>
<translation id="5932224571077948991">ਸਾਈਟ ਦਖਲਅੰਦਾਜ਼ੀ ਜਾਂ ਗà©à¨®à¨°à¨¾à¨¹ ਕਰਨ ਵਾਲੇ ਵਿਗਿਆਪਨ ਦਿਖਾਉਂਦੀ ਹੈ</translation>
+<translation id="5938153366081463283">ਆਭਾਸੀ ਕਾਰਡ ਸ਼ਾਮਲ ਕਰੋ</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347"><ph name="SITE_NAME" /> ਸਾਈਟ ਖà©à©±à¨²à©à¨¹ ਰਹੀ ਹੈ…</translation>
<translation id="5951495562196540101">ਖਪਤਕਾਰ ਖਾਤੇ ਨਾਲ ਦਰਜ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ (ਪੈਕੇਜਡ ਲਾਇਸੰਸ ਉਪਲਬਧ ਹਨ)।</translation>
@@ -1598,6 +1637,7 @@
<translation id="6120179357481664955">ਕੀ ਤà©à¨¹à¨¾à¨¨à©‚à©° ਆਪਣੀ UPI ਆਈਡੀ ਯਾਦ ਹੈ?</translation>
<translation id="6124432979022149706">Chrome à¨à¨‚ਟਰਪà©à¨°à¨¾à¨ˆà¨œà¨¼ ਕਨੈਕਟਰ</translation>
<translation id="6127379762771434464">ਆਈਟਮ ਹਟਾਈ ਗਈ</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Chrome ਵਿੱਚ ਇਨਕੋਗਨਿਟੋ ਮੋਡ ਬਾਰੇ ਹੋਰ ਜਾਣੋ<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">ਸਾਰੀਆਂ ਕੇਬਲਾਂ ਦੀ ਜਾਂਚ ਕਰੋ ਅਤੇ ਤà©à¨¹à¨¾à¨¡à©‡ ਵੱਲੋਂ ਵਰਤੇ ਜਾਣ ਵਾਲੇ ਕੋਈ ਵੀ ਰੂਟਰਾਂ, ਮਾਡਮਾਂ ਅਤੇ ਹੋਰ ਡੀਵਾਈਸਾਂ ਨੂੰ ਰੀਬੂਟ ਕਰੋ।</translation>
<translation id="614940544461990577">ਅਜ਼ਮਾਓ:</translation>
<translation id="6150036310511284407">ਖੱਬੇ ਤਿੰਨ ਮੋਰੀਆਂ</translation>
@@ -1609,7 +1649,6 @@
<translation id="6169916984152623906">ਹà©à¨£ ਤà©à¨¸à©€à¨‚ ਨਿੱਜੀ ਤੌਰ 'ਤੇ ਬà©à¨°à¨¾à¨Šà¨œà¨¼ ਕਰ ਸਕਦੇ ਹੋ, ਅਤੇ ਇਸ ਡੀਵਾਈਸ ਨੂੰ ਵਰਤਣ ਵਾਲੇ ਹੋਰ ਲੋਕਾਂ ਨੂੰ ਤà©à¨¹à¨¾à¨¡à©€ ਸਰਗਰਮੀ ਨਹੀਂ ਦਿਖਾਈ ਦੇਵੇਗੀ। ਹਾਲਾਂਕਿ, ਡਾਊਨਲੋਡ ਅਤੇ ਬà©à©±à¨•à¨®à¨¾à¨°à¨• ਰੱਖਿਅਤ ਕੀਤੇ ਜਾਣਗੇ।</translation>
<translation id="6177128806592000436">ਇਸ ਸਾਈਟ ਨਾਲ ਤà©à¨¹à¨¾à¨¡à¨¾ ਕਨੈਕਸ਼ਨ ਸà©à¨°à©±à¨–ਿਅਤ ਨਹੀਂ ਹੈ</translation>
<translation id="6180316780098470077">ਮà©à©œ-ਕੋਸ਼ਿਸ਼ ਅੰਤਰਾਲ</translation>
-<translation id="619448280891863779">ਸਾਈਟ ਤà©à¨¹à¨¾à¨¡à©€à¨†à¨‚ ਸਕà©à¨°à©€à¨¨à¨¾à¨‚ 'ਤੇ ਵਿੰਡੋ ਨੂੰ ਖੋਲà©à¨¹à¨£ ਅਤੇ ਉਸਨੂੰ ਰੱਖਣ ਲਈ ਪà©à©±à¨› ਸਕਦੀ ਹੈ</translation>
<translation id="6196640612572343990">ਤੀਜੀ-ਧਿਰ ਵਾਲੀਆਂ ਕà©à©±à¨•à©€à¨œà¨¼ ਨੂੰ ਬਲੌਕ ਕਰੋ</translation>
<translation id="6203231073485539293">ਆਪਣੇ ਇੰਟਰਨੈੱਟ ਕਨੈਕਸ਼ਨ ਦੀ ਜਾਂਚ ਕਰੋ</translation>
<translation id="6218753634732582820">ਕੀ Chromium ਤੋਂ ਪਤਾ ਮਿਟਾਉਣਾ ਹੈ?</translation>
@@ -1632,7 +1671,7 @@
<translation id="6272383483618007430">Google ਅੱਪਡੇਟ</translation>
<translation id="6276112860590028508">ਤà©à¨¹à¨¾à¨¡à©€ ਪੜà©à¨¹à¨¤ ਸੂਚੀ ਵਿੱਚੋਂ ਪੰਨੇ ਇੱਥੇ ਵਿਖਾਈ ਦੇਣਗੇ</translation>
<translation id="627746635834430766">ਅਗਲੀ ਵਾਰ ਵਧੇਰੇ ਤੇਜ਼ੀ ਨਾਲ ਭà©à¨—ਤਾਨ ਕਰਨ ਲਈ, ਆਪਣੇ ਕਾਰਡ ਅਤੇ ਬਿਲਿੰਗ ਪਤੇ ਨੂੰ ਆਪਣੇ Google ਖਾਤੇ ਵਿੱਚ ਰੱਖਿਅਤ ਕਰੋ।</translation>
-<translation id="6279098320682980337">ਕੀ ਆਭਾਸੀ ਕਾਰਡ ਨੰਬਰ ਭਰਿਆ ਨਹੀਂ ਗਿਆ? ਕਾਪੀ ਕਰਨ ਲਈ ਕਾਰਡ ਦੇ ਵੇਰਵਿਆਂ 'ਤੇ ਕਲਿੱਕ ਕਰੋ</translation>
+<translation id="6279183038361895380">ਆਪਣਾ ਕਰਸਰ ਵਿਖਾਉਣ ਲਈ |<ph name="ACCELERATOR" />| ਦਬਾਓ</translation>
<translation id="6280223929691119688">ਇਸ ਪਤੇ 'ਤੇ ਅਦਾਇਗੀ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ। ਕੋਈ ਵੱਖਰਾ ਪਤਾ ਚà©à¨£à©‹à¥¤</translation>
<translation id="6282194474023008486">ਡਾਕ ਕੋਡ</translation>
<translation id="6285507000506177184">'Chrome ਵਿੱਚ ਡਾਊਨਲੋਡਾਂ ਦਾ ਪà©à¨°à¨¬à©°à¨§à¨¨ ਕਰੋ' ਬਟਨ, Chrome ਵਿੱਚ ਤà©à¨¹à¨¾à¨¡à©‡ ਵੱਲੋਂ ਡਾਊਨਲੋਡ ਕੀਤੀਆਂ ਫ਼ਾਈਲਾਂ ਦਾ ਪà©à¨°à¨¬à©°à¨§à¨¨ ਕਰਨ ਲਈ Enter ਦਬਾਓ</translation>
@@ -1640,6 +1679,7 @@
<translation id="6290238015253830360">ਤà©à¨¹à¨¾à¨¡à©‡ ਸà©à¨à¨¾à¨ ਗਠਲੇਖ ਇੱਥੇ ਦਿਖਾਈ ਦੇਣਗੇ</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{ਤà©à¨¹à¨¾à¨¡à¨¾ ਡੀਵਾਈਸ ਹà©à¨£à©‡ ਮà©à©œ-ਸ਼à©à¨°à©‚ ਹੋਵੇਗਾ}=1{ਤà©à¨¹à¨¾à¨¡à¨¾ ਡੀਵਾਈਸ 1 ਸਕਿੰਟ ਵਿੱਚ ਮà©à©œ-ਸ਼à©à¨°à©‚ ਹੋਵੇਗਾ}other{ਤà©à¨¹à¨¾à¨¡à¨¾ ਡੀਵਾਈਸ # ਸਕਿੰਟਾਂ ਵਿੱਚ ਮà©à©œ-ਸ਼à©à¨°à©‚ ਹੋਵੇਗਾ}}</translation>
<translation id="6302269476990306341">Chrome ਵਿੱਚ Google Assistant ਨੂੰ ਬੰਦ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ</translation>
<translation id="6305205051461490394"><ph name="URL" /> ਪਹà©à©°à¨šà¨¯à©‹à¨— ਨਹੀਂ ਹੈ।</translation>
<translation id="6312113039770857350">ਵੈਬਸਫ਼ਾ ਉਪਲਬਧ ਨਹੀਂ ਹੈ</translation>
@@ -1713,6 +1753,7 @@
<translation id="6529602333819889595">&amp;ਮਿਟਾਠਗਠਨੂੰ ਮà©à©œ-ਓਹੀ ਕਰੋ</translation>
<translation id="6545864417968258051">ਬਲੂਟà©à©±à¨¥ ਸਕੈਨਿੰਗ</translation>
<translation id="6547208576736763147">ਖੱਬੇ ਪਾਸੇ ਦੋ ਮੋਰੀਆਂ</translation>
+<translation id="6554732001434021288">ਪਿਛਲੀ ਵਾਰ <ph name="NUM_DAYS" /> ਦਿਨ ਪਹਿਲਾਂ ਦੇਖੀ ਗਈ</translation>
<translation id="6556866813142980365">ਮà©à©œ-ਓਹੀ ਕਰੋ</translation>
<translation id="6569060085658103619">ਤà©à¨¸à©€à¨‚ ਇੱਕ à¨à¨•à¨¸à¨Ÿà©ˆà¨‚ਸ਼ਨ ਪੰਨਾ ਦੇਖ ਰਹੇ ਹੋ</translation>
<translation id="6573200754375280815">ਸੱਜੇ ਦੋ ਮੋਰੀਆਂ</translation>
@@ -1773,7 +1814,6 @@
<translation id="6757797048963528358">ਤà©à¨¹à¨¾à¨¡à©€ ਡੀਵਾਈਸ ਸਲੀਪ ਵਿੱਚ ਚਲੀ ਗਈ।</translation>
<translation id="6767985426384634228">ਕੀ ਪਤਾ ਅੱਪਡੇਟ ਕਰਨਾ ਚਾਹà©à©°à¨¦à©‡ ਹੋ?</translation>
<translation id="6768213884286397650">Hagaki (ਪੋਸਟਕਾਰਡ)</translation>
-<translation id="6774185088257932239">ਇਨਕੋਗਨਿਟੋ ਬਾਰੇ <ph name="BEGIN_LINK" />ਹੋਰ ਜਾਣੋ<ph name="END_LINK" /></translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">ਬੈਂਗਣੀ</translation>
<translation id="6786747875388722282">à¨à¨•à¨¸à¨Ÿà©ˆà¨‚ਸ਼ਨਾਂ</translation>
@@ -1857,7 +1897,6 @@
<translation id="706295145388601875">Chrome ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਪਤੇ ਸ਼ਾਮਲ ਕਰੋ ਅਤੇ ਉਹਨਾਂ ਦਾ ਪà©à¨°à¨¬à©°à¨§à¨¨ ਕਰੋ</translation>
<translation id="7064851114919012435">ਸੰਪਰਕ ਜਾਣਕਾਰੀ</translation>
<translation id="7068733155164172741"><ph name="OTP_LENGTH" />-ਅੰਕਾਂ ਦਾ ਕੋਡ ਦਾਖਲ ਕਰੋ</translation>
-<translation id="7070090581017165256">ਇਸ ਸਾਈਟ ਬਾਰੇ</translation>
<translation id="70705239631109039">ਤà©à¨¹à¨¾à¨¡à¨¾ ਕਨੈਕਸ਼ਨ ਪੂਰੀ ਤਰà©à¨¹à¨¾à¨‚ ਸà©à¨°à©±à¨–ਿਅਤ ਨਹੀਂ ਹੈ</translation>
<translation id="7075452647191940183">ਬੇਨਤੀ ਬਹà©à¨¤ ਜ਼ਿਆਦਾ ਵੱਡੀ ਹੈ</translation>
<translation id="7079718277001814089">ਇਸ ਸਾਈਟ ਵਿੱਚ ਮਾਲਵੇਅਰ ਸ਼ਾਮਲ ਹਨ</translation>
@@ -1874,6 +1913,12 @@
<translation id="7111012039238467737">(ਵੈਧ)</translation>
<translation id="7118618213916969306">ਕਲਿੱਪਬੋਰਡ URL, <ph name="SHORT_URL" /> ਖੋਜੋ</translation>
<translation id="7119414471315195487">ਦੂਜੀਆਂ ਟੈਬਾਂ ਜਾਂ ਪà©à¨°à©‹à¨—ਰਾਮਾਂ ਨੂੰ ਬੰਦ ਕਰੋ</translation>
+<translation id="7129355289156517987">ਜਦੋਂ ਤà©à¨¸à©€à¨‚ Chromium ਵਿੱਚ ਸਾਰੀਆਂ ਇਨਕੋਗਨਿਟੋ ਟੈਬਾਂ ਨੂੰ ਬੰਦ ਕਰਦੇ ਹੋ ਤਾਂ ਉਨà©à¨¹à¨¾à¨‚ ਟੈਬਾਂ ਵਿਚਲੀ ਤà©à¨¹à¨¾à¨¡à©€ ਸਰਗਰਮੀ ਨੂੰ ਇਸ ਡੀਵਾਈਸ ਤੋਂ ਕਲੀਅਰ ਕਰ ਦਿੱਤਾ ਜਾਂਦਾ ਹੈ:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ਬà©à¨°à¨¾à¨Šà¨œà¨¼à¨¿à©°à¨— ਸਰਗਰਮੀ<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ਖੋਜ ਇਤਿਹਾਸ<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ਫ਼ਾਰਮਾਂ ਵਿੱਚ ਦਾਖਲ ਕੀਤੀ ਜਾਣਕਾਰੀ<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">ਇਸ ਪਤੇ 'ਤੇ ਸ਼ਿਪ ਨਹੀਂ ਕਰ ਸਕਦੇ। ਕੋਈ ਵੱਖਰਾ ਪਤਾ ਚà©à¨£à©‹à¥¤</translation>
<translation id="7132939140423847331">ਤà©à¨¹à¨¾à¨¡à©‡ ਪà©à¨°à¨¶à¨¾à¨¸à¨• ਨੇ ਇਸ ਡਾਟੇ ਨੂੰ ਕਾਪੀ ਕੀਤੇ ਜਾਣ ਤੋਂ ਪà©à¨°à¨¤à¨¿à¨¬à©°à¨§à¨¿à¨¤ ਕੀਤਾ ਹੈ।</translation>
<translation id="7135130955892390533">ਸਥਿਤੀ ਦਿਖਾਓ</translation>
@@ -1896,6 +1941,7 @@
<translation id="7192203810768312527"><ph name="SIZE" /> ਜਗà©à¨¹à¨¾ ਖਾਲੀ ਕਰਦਾ ਹੈ। ਤà©à¨¹à¨¾à¨¡à©€ ਅਗਲੀ ਫੇਰੀ 'ਤੇ ਕà©à¨ ਸਾਈਟਾਂ ਵਧੇਰੇ ਹੌਲੀ ਲੋਡ ਹੋ ਸਕਦੀਆਂ ਹਨ।</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">ਤà©à¨¹à¨¾à¨¡à¨¾ ਪà©à¨°à¨¸à¨¼à¨¾à¨¸à¨• ਇਹ ਦੇਖ ਸਕਦਾ ਹੈ:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, Tab ਦਬਾਓ, ਫਿਰ ਨਿੱਜੀ ਤੌਰ 'ਤੇ ਬà©à¨°à¨¾à¨Šà¨œà¨¼ ਕਰਨ ਲਈ ਨਵੀਂ ਇਨਕੋਗਨਿਟੋ ਟੈਬ ਖੋਲà©à¨¹à¨£ ਵਾਸਤੇ Enter ਦਬਾਓ</translation>
<translation id="7202346780273620635">ਚਿੱਠੀ-ਵਾਧੂ</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> ਸà©à¨°à©±à¨–ਿਆ ਪੈਮਾਨਿਆਂ ਦੀ ਪਾਲਣਾ ਨਹੀਂ ਕਰਦਾ ਹੈ।</translation>
<translation id="7210993021468939304">ਕੰਟੇਨਰ ਵਿੱਚ Linux ਸਰਗਰਮੀ, ਅਤੇ ਕੰਨਟੇਨਰ ਵਿੱਚ Linux à¨à¨ªà¨¾à¨‚ ਨੂੰ ਸਥਾਪਤ ਕੀਤਾ ਅਤੇ ਚਲਾਇਆ ਜਾ ਸਕਦਾ ਹੈ</translation>
@@ -1927,6 +1973,7 @@
<translation id="7304562222803846232">Google ਖਾਤਾ ਪਰਦੇਦਾਰੀ ਸੈਟਿੰਗਾਂ ਦਾ ਪà©à¨°à¨¬à©°à¨§à¨¨ ਕਰੋ</translation>
<translation id="7305756307268530424">ਹੌਲੀ-ਹੌਲੀ ਸ਼à©à¨°à©‚ ਕਰੋ</translation>
<translation id="7308436126008021607">ਬੈਕਗà©à¨°à¨¾à¨Šà¨‚ਡ ਸਿੰਕ</translation>
+<translation id="7310392214323165548">ਡੀਵਾਈਸ ਜਲਦ ਹੀ ਮà©à©œ-ਸ਼à©à¨°à©‚ ਹੋਵੇਗਾ</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">ਕਨੈਕਸ਼ਨ ਸੰਬੰਧੀ ਮਦਦ</translation>
<translation id="7323804146520582233">"<ph name="SECTION" />" ਸੈਕਸ਼ਨ ਲà©à¨•à¨¾à¨“</translation>
@@ -1934,6 +1981,7 @@
<translation id="7334320624316649418">&amp;ਦà©à¨¬à¨¾à¨°à¨¾ ਕà©à¨°à¨® ਦੇਣ ਨੂੰ ਰੀਡੂ ਕਰੋ</translation>
<translation id="7335157162773372339">ਸਾਈਟ ਤà©à¨¹à¨¾à¨¡à¨¾ ਕੈਮਰਾ ਵਰਤਣ ਲਈ ਪà©à©±à¨› ਸਕਦੀ ਹੈ</translation>
<translation id="7337248890521463931">ਹੋਰ ਲਾਈਨਾਂ ਦਿਖਾਓ</translation>
+<translation id="7337418456231055214">ਕੀ ਆਭਾਸੀ ਕਾਰਡ ਨੰਬਰ ਭਰਿਆ ਨਹੀਂ ਗਿਆ? ਕਾਪੀ ਕਰਨ ਲਈ ਕਾਰਡ ਦੇ ਵੇਰਵਿਆਂ 'ਤੇ ਕਲਿੱਕ ਕਰੋ। <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">ਤà©à¨¹à¨¾à¨¡à©‡ ਪਲੇਟਫਾਰਮ 'ਤੇ ਉਪਲਬਧ ਨਹੀਂ ਹੈ।</translation>
<translation id="733923710415886693">ਸਰਵਰ ਦੇ ਪà©à¨°à¨®à¨¾à¨£-ਪੱਤਰ ਦਾ ਖà©à¨²à¨¾à¨¸à¨¾ ਪà©à¨°à¨®à¨¾à¨£-ਪੱਤਰ ਪਾਰਦਰਸ਼ਤਾ ਰਾਹੀਂ ਨਹੀਂ ਕੀਤਾ ਗਿਆ ਸੀ।</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1956,6 +2004,7 @@
<translation id="7378627244592794276">ਨੋਪ</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">ਲਾਗੂ ਨਹੀਂ</translation>
+<translation id="7388594495505979117">{0,plural, =1{ਤà©à¨¹à¨¾à¨¡à¨¾ ਡੀਵਾਈਸ 1 ਮਿੰਟ ਵਿੱਚ ਮà©à©œ-ਸ਼à©à¨°à©‚ ਹੋਵੇਗਾ}one{ਤà©à¨¹à¨¾à¨¡à¨¾ ਡੀਵਾਈਸ # ਮਿੰਟ ਵਿੱਚ ਮà©à©œ-ਸ਼à©à¨°à©‚ ਹੋਵੇਗਾ}other{ਤà©à¨¹à¨¾à¨¡à¨¾ ਡੀਵਾਈਸ # ਮਿੰਟਾਂ ਵਿੱਚ ਮà©à©œ-ਸ਼à©à¨°à©‚ ਹੋਵੇਗਾ}}</translation>
<translation id="7390545607259442187">ਕਾਰਡ ਦੀ ਪà©à¨¸à¨¼à¨Ÿà©€ ਕਰੋ</translation>
<translation id="7392089738299859607">ਪਤਾ ਅੱਪਡੇਟ ਕਰੋ</translation>
<translation id="7399802613464275309">ਸà©à¨°à©±à¨–ਿਆ ਜਾਂਚ</translation>
@@ -1992,6 +2041,12 @@
<translation id="7485870689360869515">ਕੋਈ ਡਾਟਾ ਨਹੀਂ ਮਿਲਿਆ।</translation>
<translation id="7495528107193238112">ਇਹ ਸਮੱਗਰੀ ਬਲਾਕ ਕੀਤੀ ਗਈ ਹੈ। ਸਮੱਸਿਆ ਨੂੰ ਠੀਕ ਕਰਨ ਲਈ ਸਾਈਟ ਦੇ ਮਾਲਕ ਨੂੰ ਸੰਪਰਕ ਕਰੋ।</translation>
<translation id="7497998058912824456">'ਡੌਕ ਬਣਾਓ' ਬਟਨ, ਤੇਜ਼ੀ ਨਾਲ ਨਵਾਂ Google ਡੌਕ ਬਣਾਉਣ ਲਈ Enter ਦਬਾਓ</translation>
+<translation id="7506488012654002225">Chromium ਅੱਗੇ ਦਿੱਤੀ ਜਾਣਕਾਰੀ ਨੂੰ <ph name="BEGIN_EMPHASIS" />ਰੱਖਿਅਤ ਨਹੀਂ ਕਰੇਗਾ<ph name="END_EMPHASIS" />:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ਤà©à¨¹à¨¾à¨¡à¨¾ ਬà©à¨°à¨¾à¨Šà¨œà¨¼à¨¿à©°à¨— ਇਤਿਹਾਸ
+ <ph name="LIST_ITEM" />ਕà©à¨•à©€à¨œà¨¼ ਅਤੇ ਸਾਈਟ ਡਾਟਾ
+ <ph name="LIST_ITEM" />ਫ਼ਾਰਮਾਂ ਵਿੱਚ ਦਾਖਲ ਕੀਤੀ ਜਾਣਕਾਰੀ
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">ਵਾਪਸੀ ਸੰਬੰਧੀ ਨੀਤੀ ਡੀਵਾਈਸ ਆਈ.ਡੀ. ਖਾਲੀ ਹੈ ਜਾਂ ਵਰਤਮਾਨ ਡੀਵਾਈਸ ਆਈ.ਡੀ. ਨਾਲ ਮੇਲ ਨਹੀਂ ਖਾਂਦੀ ਹੈ</translation>
<translation id="7508870219247277067">à¨à¨µà©‹à¨•à¨¾à¨¡à©‹ ਹਰਾ</translation>
<translation id="7511955381719512146">ਜੋ Wi-Fi ਤà©à¨¸à©€à¨‚ ਵਰਤ ਰਹੇ ਹੋ, ਉਸ ਲਈ ਤà©à¨¹à¨¾à¨¨à©‚à©° <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> ਤੇ ਵਿਜਿਟ ਕਰਨ ਦੀ ਲੋੜ ਹੋ ਸਕਦੀ ਹੈ।</translation>
@@ -2105,7 +2160,6 @@
<translation id="7813600968533626083">ਕੀ Chrome ਤੋਂ ਫ਼ਾਰਮ ਸੰਬੰਧੀ ਸà©à¨à¨¾à¨… ਨੂੰ ਮਿਟਾਉਣਾ ਹੈ?</translation>
<translation id="781440967107097262">ਕੀ ਕਲਿੱਪਬੋਰਡ ਨੂੰ ਸਾਂà¨à¨¾ ਕਰਨਾ ਹੈ?</translation>
<translation id="7815407501681723534">'<ph name="SEARCH_STRING" />' ਲਈ <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> ਮਿਲੇ</translation>
-<translation id="782125616001965242">ਇਸ ਸਾਈਟ ਬਾਰੇ ਜਾਣਕਾਰੀ ਦਿਖਾਓ</translation>
<translation id="782886543891417279">ਤà©à¨¹à¨¾à¨¡à©‡ ਵੱਲੋਂ ਵਰਤਿਆ ਜਾ ਰਿਹਾ ਵਾਈ-ਫਾਈ (<ph name="WIFI_NAME" />) ਇਹ ਚਾਹ ਸਕਦਾ ਹੈ ਕਿ ਤà©à¨¸à©€à¨‚ ਇਸਦੇ ਲੌਗ-ਇਨ ਪੰਨੇ 'ਤੇ ਜਾਓ।</translation>
<translation id="7836231406687464395">Postfix (ਲਿਫ਼ਾਫ਼ਾ)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{ਕੋਈ ਨਹੀਂ}=1{1 à¨à¨ª (<ph name="EXAMPLE_APP_1" />)}=2{2 à¨à¨ªà¨¾à¨‚ (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}other{# à¨à¨ªà¨¾à¨‚ (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}}</translation>
@@ -2122,7 +2176,6 @@
<translation id="7888575728750733395">ਰੈਂਡਰਿੰਗ ਇੰਟੈਂਟ ਨੂੰ ਪà©à¨°à¨¿à©°à¨Ÿ ਕਰੋ</translation>
<translation id="7894280532028510793">ਜੇ ਸ਼ਬਦ-ਜੋੜ ਸਹੀ ਹੈ, ਤਾਂ <ph name="BEGIN_LINK" />ਨੈੱਟਵਰਕ ਤਸ਼ਖੀਸਾਂ ਨੂੰ ਚਲਾ ਕੇ ਦੇਖੋ<ph name="END_LINK" />।</translation>
<translation id="7904208859782148177">C3 (ਲਿਫ਼ਾਫ਼ਾ)</translation>
-<translation id="7931318309563332511">ਅਗਿਆਤ</translation>
<translation id="793209273132572360">ਕੀ ਪਤਾ ਅੱਪਡੇਟ ਕਰਨਾ ਚਾਹà©à©°à¨¦à©‡ ਹੈ?</translation>
<translation id="7932579305932748336">ਕੋਟ</translation>
<translation id="79338296614623784">ਕੋਈ ਵੈਧ ਫ਼ੋਨ ਨੰਬਰ ਦਾਖਲ ਕਰੋ</translation>
@@ -2147,13 +2200,14 @@
<translation id="7976214039405368314">ਬਹà©à¨¤ ਸਾਰੀਆਂ ਬੇਨਤੀਆਂ</translation>
<translation id="7977538094055660992">ਆਊਟਪà©à©±à¨Ÿ ਡੀਵਾਈਸ</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">ਇਸ ਨਾਲ ਲਿੰਕ ਕੀਤਾ ਗਿਆ</translation>
<translation id="798134797138789862">ਸਾਈਟ ਆਭਾਸੀ ਵਾਸਤਵਿਕਤਾ ਵਾਲੇ ਡੀਵਾਈਸਾਂ ਅਤੇ ਡਾਟੇ ਨੂੰ ਵਰਤਣ ਲਈ ਪà©à©±à¨› ਸਕਦੀ ਹੈ</translation>
<translation id="7984945080620862648">ਤà©à¨¸à©€à¨‚ ਇਸ ਵੇਲੇ <ph name="SITE" /> ਤੇ ਵਿਜਿਟ ਨਹੀਂ ਕਰ ਸਕਦੇ ਕਿਉਂਕਿ ਵੈੱਬਸਾਈਟ ਨੇ ਸਕà©à¨°à©ˆà¨‚ਬਲ ਕੀਤੇ ਕà©à¨°à©ˆà¨¡à©ˆà¨‚ਸ਼ੀਅਲਸ ਭੇਜੇ ਸਨ ਜਿਹਨਾਂ ਨਾਲ Chrome ਪà©à¨°à¨•à¨¿à¨°à¨¿à¨† ਨਹੀਂ ਕਰ ਸਕਦਾ। ਨੈਟਵਰਕ ਅਸ਼à©à©±à¨§à©€à¨†à¨‚ ਅਤੇ ਹਮਲੇ ਆਮ ਤੌਰ ਤੇ ਅਸਥਾਈ ਹà©à©°à¨¦à©‡ ਹਨ, ਇਸਲਈ ਇਹ ਸਫ਼ਾ ਸ਼ਾਇਦ ਬਾਅਦ ਵਿੱਚ ਕੰਮ ਕਰੇਗਾ।</translation>
-<translation id="79859296434321399">ਸੰਵਰਧਿਤ ਵਾਸਤਵਿਕਤਾ ਵਾਲੀ ਸਮੱਗਰੀ ਦੇਖਣ ਲਈ, ARCore ਸਥਾਪਤ ਕਰੋ</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">ਜਿਲਦਬੰਦ</translation>
<translation id="7992044431894087211"><ph name="APPLICATION_TITLE" /> ਨਾਲ ਸਕà©à¨°à©€à¨¨ ਸਾਂà¨à¨¾à¨•à¨°à¨¨ ਨੂੰ ਮà©à©œ-ਚਾਲੂ ਕੀਤਾ ਗਿਆ</translation>
<translation id="7995512525968007366">ਨਿਰਦਿਸ਼ਟ ਨਹੀਂ ਕੀਤਾ</translation>
+<translation id="7998269595945679889">'ਇਨਕੋਗਨਿਟੋ ਟੈਬ ਖੋਲà©à¨¹à©‹' ਬਟਨ, ਨਿੱਜੀ ਤੌਰ 'ਤੇ ਬà©à¨°à¨¾à¨Šà¨œà¨¼ ਕਰਨ ਲਈ ਨਵੀਂ ਇਨਕੋਗਨਿਟੋ ਟੈਬ ਖੋਲà©à¨¹à¨£ ਵਾਸਤੇ Enter ਦਬਾਓ</translation>
<translation id="800218591365569300">ਮੈਮੋਰੀ ਖਾਲੀ ਕਰਨ ਲਈ ਦੂਜੀਆਂ ਟੈਬਾਂ ਜਾਂ ਪà©à¨°à©‹à¨—ਰਾਮਾਂ ਨੂੰ ਬੰਦ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰੋ।</translation>
<translation id="8004582292198964060">ਬà©à¨°à¨¾à¨Šà¨œà¨¼à¨°</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{ਇਸ ਕਾਰਡ ਅਤੇ ਇਸਦੇ ਬਿਲਿੰਗ ਪਤੇ ਨੂੰ ਰੱਖਿਅਤ ਕੀਤਾ ਜਾਵੇਗਾ। <ph name="USER_EMAIL" /> ਵਿੱਚ ਸਾਈਨ-ਇਨ ਹੋਣ 'ਤੇ ਤà©à¨¸à©€à¨‚ ਇਸ ਨੂੰ ਵਰਤ ਸਕੋਗੇ।}one{ਇਸ ਕਾਰਡ ਅਤੇ ਇਸਦੇ ਬਿਲਿੰਗ ਪਤੇ ਨੂੰ ਰੱਖਿਅਤ ਕੀਤਾ ਜਾਵੇਗਾ। <ph name="USER_EMAIL" /> ਵਿੱਚ ਸਾਈਨ-ਇਨ ਹੋਣ 'ਤੇ ਤà©à¨¸à©€à¨‚ ਇਸ ਨੂੰ ਵਰਤ ਸਕੋਗੇ।}other{ਇਹਨਾਂ ਕਾਰਡਾਂ ਅਤੇ ਇਹਨਾਂ ਦੇ ਬਿਲਿੰਗ ਪਤਿਆਂ ਨੂੰ ਰੱਖਿਅਤ ਕੀਤਾ ਜਾਵੇਗਾ। <ph name="USER_EMAIL" /> ਵਿੱਚ ਸਾਈਨ-ਇਨ ਹੋਣ 'ਤੇ ਤà©à¨¸à©€à¨‚ ਇਹਨਾਂ ਨੂੰ ਵਰਤ ਸਕੋਗੇ।}}</translation>
@@ -2213,6 +2267,7 @@
<translation id="8202370299023114387">ਵਿਵਾਦ</translation>
<translation id="8206978196348664717">Prc4 (ਲਿਫ਼ਾਫ਼ਾ)</translation>
<translation id="8211406090763984747">ਕਨੈਕਸ਼ਨ ਸà©à¨°à©±à¨–ਿਅਤ ਹੈ</translation>
+<translation id="8217240300496046857">ਸਾਈਟਾਂ ਉਨà©à¨¹à¨¾à¨‚ ਕà©à¨•à©€à¨œà¨¼ ਦੀ ਵਰਤੋਂ ਨਹੀਂ ਕਰ ਸਕਦੀਆਂ ਜੋ ਵੈੱਬ 'ਤੇ ਤà©à¨¹à¨¾à¨¨à©‚à©° ਟਰੈਕ ਕਰਦੀਆਂ ਹਨ। ਸ਼ਾਇਦ ਕà©à¨ ਸਾਈਟਾਂ 'ਤੇ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਠੀਕ ਤਰੀਕੇ ਨਾਲ ਕੰਮ ਨਾ ਕਰਨ।</translation>
<translation id="8218327578424803826">ਅਸਾਈਨ ਕੀਤਾ ਗਿਆ ਨਿਰਧਾਰਿਤ ਸਥਾਨ:</translation>
<translation id="8220146938470311105">C7/C6 (ਲਿਫ਼ਾਫ਼ਾ)</translation>
<translation id="8225771182978767009">ਜਿਸ ਵਿਅਕਤੀ ਨੇ ਇਸ ਕੰਪਿਊਟਰ ਦਾ ਸੈੱਟ ਅੱਪ ਕੀਤਾ ਹੈ ਉਸ ਵੱਲੋਂ ਇਸ ਸਾਈਟ ਨੂੰ ਬਲਾਕ ਕਰਨਾ ਚà©à¨£à¨¿à¨† ਗਿਆ ਹੈ।</translation>
@@ -2253,14 +2308,9 @@
<translation id="830498451218851433">ਅੱਧੀ ਤਹਿ</translation>
<translation id="8307358339886459768">ਛੋਟੀ-ਫ਼ੋਟੋ</translation>
<translation id="8307888238279532626">ਸਥਾਪਤ à¨à¨ªà¨¾à¨‚ ਅਤੇ à¨à¨ªà¨¾à¨‚ ਵਰਤਣ ਦਾ ਸਮਾਂ</translation>
+<translation id="8317207217658302555">ਕੀ ARCore ਨੂੰ ਅੱਪਡੇਟ ਕਰਨਾ ਹੈ?</translation>
<translation id="831997045666694187">ਸ਼ਾਮ</translation>
<translation id="8321476692217554900">ਸੂਚਨਾਵਾਂ</translation>
-<translation id="8328484624016508118">ਸਾਰੀਆਂ ਇਨਕੋਗਨਿਟੋ ਟੈਬਾਂ ਨੂੰ ਬੰਦ ਕਰਨ ਤੋਂ ਬਾਅਦ, Chrome ਇਨà©à¨¹à¨¾à¨‚ ਚੀਜ਼ਾਂ ਨੂੰ ਕਲੀਅਰ ਕਰਦਾ ਹੈ:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />ਇਸ ਡੀਵਾਈਸ ਤੋਂ ਤà©à¨¹à¨¾à¨¡à©€ ਬà©à¨°à¨¾à¨Šà¨œà¨¼à¨¿à©°à¨— ਸਰਗਰਮੀ<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />ਇਸ ਡੀਵਾਈਸ ਤੋਂ ਤà©à¨¹à¨¾à¨¡à¨¾ ਖੋਜ ਇਤਿਹਾਸ<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />ਫ਼ਾਰਮਾਂ ਵਿੱਚ ਦਾਖਲ ਕੀਤੀ ਜਾਣਕਾਰੀ<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489"><ph name="HOST_NAME" /> 'ਤੇ ਪਹà©à©°à¨š ਨੂੰ ਇਨਕਾਰਿਆ ਗਿਆ ਸੀ</translation>
<translation id="833262891116910667">ਉਜਾਗਰ ਕਰੋ</translation>
<translation id="8339163506404995330"><ph name="LANGUAGE" /> ਭਾਸ਼ਾ ਵਾਲੇ ਪੰਨਿਆਂ ਦਾ ਅਨà©à¨µà¨¾à¨¦ ਨਹੀਂ ਕੀਤਾ ਜਾਵੇਗਾ</translation>
@@ -2312,6 +2362,7 @@
<translation id="8507227106804027148">ਕਮਾਂਡ ਲਾਈਨ</translation>
<translation id="8508648098325802031">ਖੋਜ ਪà©à¨°à¨¤à©€à¨•</translation>
<translation id="8511402995811232419">ਕà©à¨•à©€à¨œà¨¼ ਦਾ ਪà©à¨°à¨¬à©°à¨§à¨¨ ਕਰੋ</translation>
+<translation id="8519753333133776369">ਤà©à¨¹à¨¾à¨¡à©‡ ਪà©à¨°à¨¶à¨¾à¨¸à¨• ਵੱਲੋਂ HID ਡੀਵਾਈਸ ਦੀ ਆਗਿਆ ਦਿੱਤੀ ਗਈ</translation>
<translation id="8522552481199248698">Chrome ਤà©à¨¹à¨¾à¨¡à©‡ Google ਖਾਤੇ ਦੀ ਸà©à¨°à©±à¨–ਿਆ ਕਰਨ ਅਤੇ ਪਾਸਵਰਡ ਬਦਲਣ ਵਿੱਚ ਤà©à¨¹à¨¾à¨¡à©€ ਮਦਦ ਕਰ ਸਕਦਾ ਹੈ।</translation>
<translation id="8530813470445476232">ਆਪਣੇ ਬà©à¨°à¨¾à¨Šà¨œà¨¼à¨¿à©°à¨— ਇਤਿਹਾਸ, ਕà©à¨•à©€à¨œà¨¼, ਕੈਸ਼ੇ ਅਤੇ ਹੋਰ ਚੀਜ਼ਾਂ ਨੂੰ Chrome ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਕਲੀਅਰ ਕਰੋ</translation>
<translation id="8533619373899488139">ਬਲਾਕ ਕੀਤੇ URL ਅਤੇ ਤà©à¨¹à¨¾à¨¡à©‡ ਸਿਸਟਮ ਪà©à¨°à¨¸à¨¼à¨¾à¨¸à¨• ਵੱਲੋਂ ਲਾਗੂ ਕੀਤੀਆਂ ਹੋਰ ਨੀਤੀਆਂ ਦੀ ਸੂਚੀ ਦੇਖਣ ਲਈ &lt;strong&gt;chrome://policy&lt;/strong&gt; 'ਤੇ ਜਾਓ।</translation>
@@ -2323,7 +2374,6 @@
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{ਇਜਾਜ਼ਤ ਨੂੰ ਰੀਸੈੱਟ ਕਰੋ}one{ਇਜਾਜ਼ਤ ਨੂੰ ਰੀਸੈੱਟ ਕਰੋ}other{ਇਜਾਜ਼ਤਾਂ ਨੂੰ ਰੀਸੈੱਟ ਕਰੋ}}</translation>
<translation id="8555010941760982128">ਚੈੱਕ-ਆਊਟ 'ਤੇ ਇਸ ਕੋਡ ਦੀ ਵਰਤੋਂ ਕਰੋ</translation>
<translation id="8557066899867184262">CVC ਤà©à¨¹à¨¾à¨¡à©‡ ਕਾਰਡ ਦੇ ਪਿੱਛੇ ਮੌਜੂਦ ਹੈ।</translation>
-<translation id="8558485628462305855">ਸੰਵਰਧਿਤ ਵਾਸਤਵਿਕਤਾ ਵਾਲੀ ਸਮੱਗਰੀ ਦੇਖਣ ਲਈ, ARCore ਅੱਪਡੇਟ ਕਰੋ</translation>
<translation id="8559762987265718583"><ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> ਨਾਲ ਇੱਕ ਨਿੱਜੀ ਕਨੈਕਸ਼ਨ ਨੂੰ ਸਥਾਪਿਤ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ ਕਿਉਂਕਿ ਤà©à¨¹à¨¾à¨¡à©€ ਡੀਵਾਈਸ ਦੀ ਤਾਰੀਖ ਅਤੇ ਸਮਾਂ (<ph name="DATE_AND_TIME" />) ਗ਼ਲਤ ਹੈ।</translation>
<translation id="8564182942834072828">ਵੱਖਰੇ ਦਸਤਾਵੇਜ਼/ਅਣਇਕੱਤਰ ਕਾਪੀਆਂ</translation>
<translation id="8564985650692024650">ਜੇਕਰ ਤà©à¨¸à©€à¨‚ ਆਪਣੇ <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> ਪਾਸਵਰਡ ਨੂੰ ਹੋਰ ਸਾਈਟਾਂ 'ਤੇ ਮà©à©œ ਵਰਤਿਆ ਹੈ, ਤਾਂ Chromium ਵੱਲੋਂ ਇਸਨੂੰ ਰੀਸੈੱਟ ਕਰਨ ਦੀ ਸਿਫ਼ਾਰਸ਼ ਕੀਤੀ ਜਾਂਦੀ ਹੈ।</translation>
@@ -2342,6 +2392,7 @@
<translation id="865032292777205197">ਮੋਸ਼ਨ ਸੈਂਸਰ</translation>
<translation id="8663226718884576429">ਆਰਡਰ ਸਾਰਾਂਸ਼, <ph name="TOTAL_LABEL" />, ਹੋਰ ਵੇਰਵੇ</translation>
<translation id="8666678546361132282">ਅੰਗਰੇਜ਼ੀ</translation>
+<translation id="8669306706049782872">ਵਿੰਡੋ ਨੂੰ ਖੋਲà©à¨¹à¨£ ਅਤੇ ਉਸਨੂੰ ਰੱਖਣ ਲਈ ਤà©à¨¹à¨¾à¨¡à©€à¨†à¨‚ ਸਕà©à¨°à©€à¨¨à¨¾à¨‚ ਬਾਰੇ ਜਾਣਕਾਰੀ ਵਰਤਣਾ ਚਾਹà©à©°à¨¦à©€ ਹੈ</translation>
<translation id="867224526087042813">ਹਸਤਾਖਰ</translation>
<translation id="8676424191133491403">ਕੋਈ ਦੇਰੀ ਨਹੀਂ</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, ਜਵਾਬ, <ph name="ANSWER" /></translation>
@@ -2368,6 +2419,7 @@
<translation id="8731544501227493793">'ਪਾਸਵਰਡ ਬਟਨ ਦਾ ਪà©à¨°à¨¬à©°à¨§à¨¨ ਕਰੋ' ਬਟਨ, Chrome ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਆਪਣੇ ਪਾਸਵਰਡ ਦੇਖਣ ਅਤੇ ਉਹਨਾਂ ਦਾ ਪà©à¨°à¨¬à©°à¨§à¨¨ ਕਰਨ ਲਈ Enter ਦਬਾਓ</translation>
<translation id="8734529307927223492">ਤà©à¨¹à¨¾à¨¡à©‡ <ph name="DEVICE_TYPE" /> ਦਾ ਪà©à¨°à¨¬à©°à¨§à¨¨ <ph name="MANAGER" /> ਵੱਲੋਂ ਕੀਤਾ ਜਾਂਦਾ ਹੈ</translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, Tab ਦਬਾਓ, ਫਿਰ ਨਿੱਜੀ ਤੌਰ 'ਤੇ ਬà©à¨°à¨¾à¨Šà¨œà¨¼ ਕਰਨ ਲਈ ਨਵੀਂ ਇਨਕੋਗਨਿਟੋ ਵਿੰਡੋ ਖੋਲà©à¨¹à¨£ ਵਾਸਤੇ Enter ਦਬਾਓ</translation>
+<translation id="8737685506611670901"><ph name="REPLACED_HANDLER_TITLE" /> ਦੀ ਬਜਾਠ<ph name="PROTOCOL" /> ਲਿੰਕਾਂ ਨੂੰ ਖੋਲà©à¨¹à©‹</translation>
<translation id="8738058698779197622">ਇੱਕ ਸà©à¨°à©±à¨–ਿਅਤ ਕਨੈਕਸ਼ਨ ਸਥਾਪਿਤ ਕਰਨ ਲਈ, ਤà©à¨¹à¨¾à¨¡à©€ ਘੜੀ ਨੂੰ ਸਹੀ ਢੰਗ ਨਾਲ ਸੈੱਟ ਕਰਨ ਦੀ ਲੋੜ ਹੈ। ਅਜਿਹਾ ਇਸ ਲਈ ਕਿਉਂਕਿ ਪà©à¨°à¨®à¨¾à¨£-ਪੱਤਰ, ਜਿਸਨੂੰ ਵੈੱਬਸਾਈਟਾਂ ਖà©à¨¦ ਦੀ ਪਛਾਣ ਕਰਨ ਲਈ ਵਰਤਦੀਆਂ ਹਨ, ਕੇਵਲ ਖ਼ਾਸ ਮਿਆਦ ਲਈ ਵੈਧ ਹà©à©°à¨¦à©‡ ਹਨ। ਕਿਉਂਕਿ ਤà©à¨¹à¨¾à¨¡à©€ ਡੀਵਾਈਸ ਦੀ ਘੜੀ ਦਾ ਸਮਾਂ ਗਲਤ ਹੈ, Chromium ਇਹਨਾਂ ਪà©à¨°à¨®à¨¾à¨£-ਪੱਤਰ ਦੀ ਜਾਂਚ ਨਹੀਂ ਕਰ ਸਕਦਾ।</translation>
<translation id="8740359287975076522"><ph name="HOST_NAME" /> ਦਾ &lt;abbr id="dnsDefinition"&gt;DNS ਪਤਾ&lt;/abbr&gt; ਨਹੀਂ ਮਿਲ ਸਕਿਆ। ਸਮੱਸਿਆ ਦਾ ਨਿਦਾਨ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ।</translation>
<translation id="8742371904523228557"><ph name="ORIGIN" /> ਲਈ <ph name="ONE_TIME_CODE" /> ਤà©à¨¹à¨¾à¨¡à¨¾ ਕੋਡ ਹੈ</translation>
@@ -2395,6 +2447,7 @@
<translation id="883848425547221593">ਹੋਰ ਬà©à©±à¨•à¨®à¨¾à¨°à¨•</translation>
<translation id="884264119367021077">ਸ਼ਿਪਿੰਗ ਪਤਾ</translation>
<translation id="884923133447025588">ਕੋਈ ਖੰਡਨ ਮਕੈਨਿਜ਼ਮ ਨਹੀਂ ਮਿਲਿਆ।</translation>
+<translation id="8849262850971482943">ਵਾਧੂ ਸà©à¨°à©±à¨–ਿਆ ਲਈ ਆਪਣੇ ਆਭਾਸੀ ਕਾਰਡ ਦੀ ਵਰਤੋਂ ਕਰੋ</translation>
<translation id="885730110891505394">Google ਨਾਲ ਸ਼ੇਅਰਿੰਗ</translation>
<translation id="8858065207712248076">ਜੇਕਰ ਤà©à¨¸à©€à¨‚ ਆਪਣੇ <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> ਪਾਸਵਰਡ ਨੂੰ ਹੋਰ ਸਾਈਟਾਂ 'ਤੇ ਮà©à©œ ਵਰਤਿਆ ਹੈ, ਤਾਂ Chrome ਵੱਲੋਂ ਇਸਨੂੰ ਰੀਸੈੱਟ ਕਰਨ ਦੀ ਸਿਫ਼ਾਰਸ਼ ਕੀਤੀ ਜਾਂਦੀ ਹੈ।</translation>
<translation id="885906927438988819">ਜੇ ਸ਼ਬਦ-ਜੋੜ ਸਹੀ ਹੈ, ਤਾਂ <ph name="BEGIN_LINK" />Windows ਨੈੱਟਵਰਕ ਤਸ਼ਖੀਸਾਂ ਨੂੰ ਚਲਾ ਕੇ ਦੇਖੋ<ph name="END_LINK" />।</translation>
@@ -2444,6 +2497,7 @@
<translation id="9004367719664099443">VR ਸੈਸ਼ਨ ਚੱਲ ਰਿਹਾ ਹੈ</translation>
<translation id="9005998258318286617">PDF ਦਸਤਾਵੇਜ਼ ਲੋਡ ਕਰਨਾ ਅਸਫਲ ਰਿਹਾ।</translation>
<translation id="9008201768610948239">ਅਣਡਿੱਠ ਕਰੋ</translation>
+<translation id="901834265349196618">ਈਮੇਲ</translation>
<translation id="9020200922353704812">ਕਾਰਡ ਬਿਲਿੰਗ ਪਤਾ ਲੋੜੀਂਦਾ ਹੈ</translation>
<translation id="9020542370529661692">ਇਸ ਸਫ਼ੇ ਦਾ ਅਨà©à¨µà¨¾à¨¦ <ph name="TARGET_LANGUAGE" /> ਵਿੱਚ ਕੀਤਾ ਗਿਆ ਹੈ।</translation>
<translation id="9020742383383852663">A8</translation>
@@ -2492,6 +2546,7 @@
<translation id="9150045010208374699">ਆਪਣਾ ਕੈਮਰਾ ਵਰਤੋ</translation>
<translation id="9150685862434908345">ਤà©à¨¹à¨¾à¨¡à¨¾ ਪà©à¨°à¨¸à¨¼à¨¾à¨¸à¨• ਦੂਰ-ਦà©à¨°à¨¾à¨¡à©‡ ਤੋਂ ਤà©à¨¹à¨¾à¨¡à©‡ ਬà©à¨°à¨¾à¨Šà¨œà¨¼à¨° ਸੈੱਟਅੱਪ ਨੂੰ ਬਦਲ ਸਕਦਾ ਹੈ। ਇਸ ਡੀਵਾਈਸ ਦੀ ਸਰਗਰਮੀ ਦਾ ਪà©à¨°à¨¬à©°à¨§à¨¨ Chrome ਤੋਂ ਬਾਹਰ ਵੀ ਕੀਤਾ ਜਾ ਸਕਦਾ ਹੈ। <ph name="BEGIN_LINK" />ਹੋਰ ਜਾਣੋ<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">ਅੱਪਡੇਟ ਕੀਤਾ</translation>
+<translation id="9155211586651734179">ਆਡੀਓ ਪੈਰੀਫੈਰਲ ਨੱਥੀ ਹਨ</translation>
<translation id="9157595877708044936">ਸੈਟ ਅਪ ਕਰ ਰਿਹਾ ਹੈ...</translation>
<translation id="9158625974267017556">C6 (ਲਿਫ਼ਾਫ਼ਾ)</translation>
<translation id="9164029392738894042">ਸਟੀਕਤਾ ਦੀ ਜਾਂਚ</translation>
diff --git a/chromium/components/strings/components_strings_pl.xtb b/chromium/components/strings/components_strings_pl.xtb
index cac91098989..8b1988cb49d 100644
--- a/chromium/components/strings/components_strings_pl.xtb
+++ b/chromium/components/strings/components_strings_pl.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">Zobacz szczegóły</translation>
<translation id="1030706264415084469"><ph name="URL" /> chce na stałe przechowywać dużą ilość danych na Twoim urządzeniu</translation>
<translation id="1032854598605920125">Obróć w prawo</translation>
+<translation id="1033329911862281889">Tryb incognito nie sprawia, że nie widać Cię w internecie:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />witryny i usługi otrzymują informacje o wizytach,<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />pracodawcy i szkolni administratorzy mogą sprawdzać Twoją aktywność związaną z przeglądaniem,<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />dostawcy usług internetowych mogą monitorować ruch w sieci.<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">Wyłącz</translation>
<translation id="1036982837258183574">Aby zamknąć pełny ekran, naciśnij |<ph name="ACCELERATOR" />|</translation>
<translation id="1038106730571050514">Pokaż sugestie</translation>
<translation id="1038842779957582377">nieznana nazwa</translation>
<translation id="1041998700806130099">Komunikat dotyczący arkusza zadań</translation>
<translation id="1048785276086539861">Gdy zmodyfikujesz adnotacje, dokument wróci do widoku jednej strony</translation>
-<translation id="1049743911850919806">Incognito</translation>
<translation id="1050038467049342496">Zamknij inne aplikacje</translation>
<translation id="1055184225775184556">&amp;Cofnij dodanie</translation>
<translation id="1056898198331236512">Ostrzeżenie</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">Pamięć podręczna zasad: OK</translation>
<translation id="1130564665089811311">Przycisk tłumaczenia strony. Naciśnij Enter, by Tłumacz Google przetłumaczył tę stronę.</translation>
<translation id="1131264053432022307">Skopiowany obraz</translation>
+<translation id="1142846828089312304">Blokuj pliki cookie innych firm w trybie incognito</translation>
<translation id="1150979032973867961">Ten serwer nie mógł udowodnić, że należy do <ph name="DOMAIN" />. Jego certyfikat bezpieczeństwa nie jest zaufany w systemie operacyjnym tego komputera. Może to być spowodowane błędną konfiguracją lub przechwyceniem połączenia przez atakującego.</translation>
<translation id="1151972924205500581">Wymagane hasło</translation>
<translation id="1156303062776767266">Przeglądasz plik lokalny lub udostępniony</translation>
@@ -64,7 +70,6 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="1178581264944972037">Wstrzymaj</translation>
<translation id="1181037720776840403">Usuń</translation>
<translation id="1186201132766001848">Sprawdź hasła</translation>
-<translation id="1195210374336998651">Otwórz ustawienia aplikacji</translation>
<translation id="1195558154361252544">Powiadomienia są automatycznie blokowane w przypadku wszystkich stron, chyba że na nie zezwolisz</translation>
<translation id="1197088940767939838">Pomarańczowy</translation>
<translation id="1201402288615127009">Dalej</translation>
@@ -111,7 +116,7 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="1307966114820526988">Funkcje wycofane</translation>
<translation id="1308113895091915999">Dostępna oferta</translation>
<translation id="1312803275555673949">Co o tym świadczy?</translation>
-<translation id="131405271941274527"><ph name="URL" /> chce wysyłać i odbierać informacje po dotknięciu telefonem urządzenia z NFC</translation>
+<translation id="1314311879718644478">Oglądaj treści rzeczywistości rozszerzonej</translation>
<translation id="1314509827145471431">Wiązanie przy prawej krawędzi</translation>
<translation id="1318023360584041678">Zapisano w grupie kart</translation>
<translation id="1319245136674974084">Nie pytaj ponownie dla tej aplikacji</translation>
@@ -161,6 +166,7 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="142858679511221695">Chmura – użytkownik</translation>
<translation id="1428729058023778569">Widzisz to ostrzeżenie, ponieważ ta witryna nie obsługuje HTTPS. <ph name="BEGIN_LEARN_MORE_LINK" />Więcej informacji<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">Drukuj</translation>
+<translation id="1432187715652018471">Strona chce zainstalować moduł do obsługiwania usługi.</translation>
<translation id="1432581352905426595">ZarzÄ…dzaj wyszukiwarkami</translation>
<translation id="1436185428532214179">Może prosić o zgodę na edytowanie plików i folderów na urządzeniu</translation>
<translation id="1442386063175183758">Składanie od dołu do środka</translation>
@@ -181,6 +187,12 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="1483493594462132177">Wyślij</translation>
<translation id="1484290072879560759">Wybierz adres wysyłki</translation>
<translation id="1492194039220927094">Przekazywanie zasad w trybie push:</translation>
+<translation id="149293076951187737">Gdy w Chrome zamkniesz wszystkie karty incognito, z urządzenia zostanie usunięta Twoja aktywność powiązana z nimi, w tym:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />aktywność związana z przeglądaniem,<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />historia wyszukiwania,<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />informacje wpisane w formularzach.<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">Wróć do karty</translation>
<translation id="1501859676467574491">Pokaż karty z konta Google</translation>
<translation id="1507202001669085618">&lt;p&gt;Ten komunikat pojawia się, jeśli do połączenia z internetem wymagane jest zalogowanie się w portalu Wi-Fi.&lt;/p&gt;
@@ -208,6 +220,8 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="1559572115229829303">&lt;p&gt;Nie można nawiązać prywatnego połączenia z <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />, bo data i godzina (<ph name="DATE_AND_TIME" />) ustawione na urządzeniu są nieprawidłowe.&lt;/p&gt;
&lt;p&gt;Popraw datę i godzinę w sekcji &lt;strong&gt;Ogólne&lt;/strong&gt; w aplikacji &lt;strong&gt;Ustawienia&lt;/strong&gt;.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">Administrator uruchomi urządzenie ponownie o <ph name="TIME" /> w dniu <ph name="DATE" /></translation>
+<translation id="156703335097561114">Dane sieciowe dotyczące adresów, konfiguracji interfejsu i jakości połączenia</translation>
<translation id="1567040042588613346">Ta zasada działa w oczekiwany sposób, ale zastąpiła tę samą wartość ustawioną w innym miejscu.</translation>
<translation id="1569487616857761740">Wpisz datę ważności</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,13 +229,14 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="1583429793053364125">Podczas wyświetlania strony wystąpił błąd.</translation>
<translation id="1586541204584340881">Zainstalowane przez Ciebie rozszerzenia</translation>
<translation id="1588438908519853928">Normalny</translation>
+<translation id="1589050138437146318">Zainstalować ARCore?</translation>
<translation id="1592005682883173041">Lokalny dostęp do danych</translation>
<translation id="1594030484168838125">Wybierz</translation>
<translation id="160851722280695521">Zagraj w grę Dino Run w Chrome</translation>
<translation id="161042844686301425">Cyjan</translation>
<translation id="1611101756749861742">Rolka 2</translation>
<translation id="1615402009686901181">Zasada administratora wyłącza zrzut ekranu, gdy widoczne są treści poufne</translation>
-<translation id="1620510694547887537">Aparat</translation>
+<translation id="1620510694547887537">Kamera</translation>
<translation id="1623104350909869708">Zapobiegaj wyświetlaniu dodatkowych okien dialogowych na tej stronie</translation>
<translation id="16338877384480380">Architecture-B</translation>
<translation id="1634828734222219955">Suma</translation>
@@ -279,6 +294,7 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="1763864636252898013">Ten serwer nie mógł udowodnić, że należy do <ph name="DOMAIN" />. Jego certyfikat bezpieczeństwa nie jest zaufany w systemie operacyjnym tego urządzenia. Może to być spowodowane błędną konfiguracją lub przechwyceniem połączenia przez atakującego.</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Uruchom DiagnostykÄ™ sieci systemu Windows<ph name="END_LINK" />.</translation>
<translation id="1772163372082567643">Serwer <ph name="ORIGIN" />, z którym chcesz się połączyć, ma ustawiony nagłówek z wymaganiem, by do wszystkich kierowanych do niego żądań stosować zasadę dotyczącą źródła. Jednak ten nagłówek ma nieprawidłowy format, przez co przeglądarka nie może zrealizować Twojego żądania dotyczącego strony <ph name="SITE" />. Zasady dotyczące źródła mogą stosować operatorzy stron internetowych, by skonfigurować zabezpieczenia i inne właściwości strony.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Więcej informacji o trybie incognito w Chromium<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">Tutaj pojawiajÄ… siÄ™ otwarte karty</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -406,6 +422,7 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="22081806969704220">Taca 3</translation>
<translation id="2212735316055980242">Nie znaleziono zasady</translation>
<translation id="2213606439339815911">Pobieram wpisy...</translation>
+<translation id="2213612003795704869">Strona została wydrukowana</translation>
<translation id="2215727959747642672">Edytowanie pliku</translation>
<translation id="2218879909401188352">Osoby obecnie atakujące stronę <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> mogą instalować niebezpieczne aplikacje, które mogą uszkodzić Twoje urządzenie, dodać ukryte opłaty do rachunku za usługi telefoniczne lub wykraść Twoje dane osobowe. <ph name="BEGIN_LEARN_MORE_LINK" />Więcej informacji<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">Brak internetu</translation>
@@ -415,6 +432,7 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="2248949050832152960">Używaj WebAuthn</translation>
<translation id="2250931979407627383">Zszywanie wzdłuż lewej krawędzi</translation>
<translation id="225207911366869382">Ta wartość tej zasady została wycofana.</translation>
+<translation id="2256115617011615191">Uruchom ponownie teraz</translation>
<translation id="2258928405015593961">Wpisz datę ważności przypadającą w przyszłości i spróbuj jeszcze raz</translation>
<translation id="225943865679747347">Kod błędu: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">BÅ‚Ä…d HTTP</translation>
@@ -442,6 +460,7 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="2337852623177822836">Ustawienie kontrolowane przez administratora</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> chce się sparować</translation>
<translation id="2346319942568447007">Skopiowany obraz</translation>
+<translation id="2350796302381711542">Zezwolić usłudze <ph name="HANDLER_HOSTNAME" /> na otwieranie wszystkich linków <ph name="PROTOCOL" /> zamiast usługi <ph name="REPLACED_HANDLER_TITLE" />?</translation>
<translation id="2354001756790975382">Inne zakładki</translation>
<translation id="2354430244986887761">Funkcja Bezpieczne przeglądanie Google niedawno <ph name="BEGIN_LINK" />wykryła szkodliwe aplikacje<ph name="END_LINK" /> na <ph name="SITE" />.</translation>
<translation id="2355395290879513365">Osoby dokonujące ataków mogą widzieć te same obrazy w witrynie co Ty i zmodyfikować je, by Cię oszukać.</translation>
@@ -467,6 +486,7 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="2413528052993050574">Ten serwer nie mógł udowodnić, że należy do <ph name="DOMAIN" />. Jego certyfikat bezpieczeństwa mógł zostać odwołany. Może to być spowodowane błędną konfiguracją lub przechwyceniem połączenia przez atakującego.</translation>
<translation id="2414886740292270097">Ciemny</translation>
<translation id="2430968933669123598">Zarządzaj kontem Google; naciśnij Enter, aby zarządzać swoimi danymi, prywatnością i bezpieczeństwem na koncie Google</translation>
+<translation id="2436186046335138073">Zezwolić usłudze <ph name="HANDLER_HOSTNAME" /> na otwieranie wszystkich linków <ph name="PROTOCOL" />?</translation>
<translation id="2438874542388153331">Cztery otwory po prawej</translation>
<translation id="2450021089947420533">Serie czynności</translation>
<translation id="2463739503403862330">Wpisz</translation>
@@ -474,6 +494,7 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="2465655957518002998">Wybierz metodÄ™ dostawy</translation>
<translation id="2465688316154986572">Zszywka</translation>
<translation id="2465914000209955735">Zarządzaj pobranymi plikami w Chrome</translation>
+<translation id="2466004615675155314">Pokaż informacje z sieci</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Uruchom diagnostykÄ™ sieci<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">Kolejność od 1 do N</translation>
<translation id="2470767536994572628">Gdy zmodyfikujesz adnotacje, dokument wróci do widoku jednej strony i pierwotnej orientacji</translation>
@@ -494,6 +515,7 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="2523886232349826891">Zapisana tylko na tym urzÄ…dzeniu</translation>
<translation id="2524461107774643265">Dodaj więcej informacji</translation>
<translation id="2529899080962247600">Maksymalna liczba wpisów w tym polu to <ph name="MAX_ITEMS_LIMIT" />. Wszystkie następne wpisy będą ignorowane.</translation>
+<translation id="2535585790302968248">Otwórz nową kartę incognito, aby przeglądać prywatnie</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{i jeszcze 1}few{i jeszcze #}many{i jeszcze #}other{i jeszcze #}}</translation>
<translation id="2536110899380797252">Dodaj adres</translation>
<translation id="2539524384386349900">Wykrywaj</translation>
@@ -519,7 +541,14 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="2597378329261239068">Ten dokument jest chroniony hasłem. Wprowadź hasło.</translation>
<translation id="2609632851001447353">Odmiany</translation>
<translation id="2610561535971892504">Kliknij, aby skopiować</translation>
+<translation id="2617988307566202237">W Chrome <ph name="BEGIN_EMPHASIS" />nie są zapisywane<ph name="END_EMPHASIS" /> te informacje:
+<ph name="BEGIN_LIST" />
+<ph name="LIST_ITEM" />Twoja historia przeglÄ…dania,
+<ph name="LIST_ITEM" />pliki cookie ani dane witryn,
+<ph name="LIST_ITEM" />informacje podane w formularzach.
+<ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (koperta)</translation>
+<translation id="2623663032199728144">Może prosić o zgodę na używanie informacji o ekranach</translation>
<translation id="2625385379895617796">Twój zegar się śpieszy</translation>
<translation id="262745152991669301">Może prosić o zgodę na połączenie z urządzeniami USB</translation>
<translation id="2629325967560697240">Aby korzystać z najwyższego poziomu zabezpieczeń Chrome, <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />włącz silniejszą ochronę<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -553,6 +582,7 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="2709516037105925701">Autouzupełnianie</translation>
<translation id="2713444072780614174">Biały</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />. Naciśnij Tab, a potem Enter, by zarządzać informacjami o płatnościach i danymi kart kredytowych w ustawieniach Chrome.</translation>
+<translation id="271663710482723385">Naciśnij |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />|, aby zamknąć pełny ekran</translation>
<translation id="2721148159707890343">Żądanie wykonane pomyślnie</translation>
<translation id="2723669454293168317">Uruchom kontrolę zabezpieczeń w ustawieniach Chrome</translation>
<translation id="2726001110728089263">Taca boczna</translation>
@@ -583,6 +613,7 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="2850739647070081192">Invite (koperta)</translation>
<translation id="2856444702002559011">Osoby atakujące mogą próbować wykraść Twoje informacje ze strony <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (na przykład hasła, wiadomości lub dane kart kredytowych). <ph name="BEGIN_LEARN_MORE_LINK" />Więcej informacji<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">Na tej stronie wyświetlają się uciążliwe lub wprowadzające w błąd reklamy.</translation>
+<translation id="286512204874376891">Karta wirtualna ukrywa Twoją prawdziwą kartę, aby chronić Cię przed oszustwami. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">Przyjazny</translation>
<translation id="2876489322757410363">Opuszczasz tryb incognito, aby zapłacić w aplikacji zewnętrznej. Czy chcesz kontynuować?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />; aby zarządzać Bezpiecznym przeglądaniem i innymi opcjami w ustawieniach Chrome, naciśnij Tab, a potem Enter</translation>
@@ -607,6 +638,7 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="2930577230479659665">Przycięcie po każdej kopii</translation>
<translation id="2932085390869194046">Zaproponuj hasło...</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019">Otwieranie linków protokołu <ph name="PROTOCOL" /></translation>
<translation id="2941952326391522266">Ten serwer nie mógł udowodnić, że należy do <ph name="DOMAIN" />. Jego certyfikat pochodzi z <ph name="DOMAIN2" />. Może to być spowodowane błędną konfiguracją lub przechwyceniem połączenia przez atakującego.</translation>
<translation id="2943895734390379394">Czas przesłania:</translation>
<translation id="2948083400971632585">Możesz wyłączyć dowolne serwery proxy skonfigurowane dla połączenia na stronie ustawień.</translation>
@@ -639,6 +671,7 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="3037605927509011580">Kurza twarz!</translation>
<translation id="3041612393474885105">Informacje o certyfikacie</translation>
<translation id="3044034790304486808">Wznów wyszukiwanie</translation>
+<translation id="305162504811187366">Historię Pulpitu zdalnego Chrome, w tym sygnatury czasowe, hostów oraz identyfikatory sesji klientów</translation>
<translation id="3060227939791841287">C9 (koperta)</translation>
<translation id="3061707000357573562">Zastosowanie poprawki do usługi</translation>
<translation id="306573536155379004">Gra się rozpoczęła.</translation>
@@ -679,6 +712,7 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="3197136577151645743">Może prosić o pozwolenie na sprawdzanie, kiedy używasz urządzenia</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />; aby zarządzać w ustawieniach Chrome informacjami, które mają być synchronizowane, naciśnij Tab, a potem Enter</translation>
<translation id="320323717674993345">Anuluj płatność</translation>
+<translation id="3203366800380907218">Z sieci</translation>
<translation id="3207960819495026254">Dodano do zakładek</translation>
<translation id="3209034400446768650">Strona może powodować naliczanie opłat</translation>
<translation id="3212581601480735796">Twoja aktywność związana z hostem <ph name="HOSTNAME" /> jest monitorowana</translation>
@@ -695,10 +729,12 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="3234666976984236645">Zawsze wykrywaj ważną treść na tej stronie</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />; aby dostosować wygląd przeglądarki, naciśnij Tab, a potem Enter.</translation>
<translation id="3240791268468473923">Arkusz dotyczący braku pasujących danych uwierzytelniających na potrzeby bezpiecznych płatności jest otwarty</translation>
+<translation id="324180406144491771">Linki „<ph name="HOST_NAME" />†są zablokowane</translation>
<translation id="3249845759089040423">Dynamiczny</translation>
<translation id="3252266817569339921">Francuski</translation>
<translation id="3257954757204451555">Od kogo pochodzi ta informacja?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />; naciśnij Tab, a potem Enter, aby szybko utworzyć nowe wydarzenie w Kalendarzu Google</translation>
+<translation id="3261488570342242926">Dowiedz się więcej o kartach wirtualnych</translation>
<translation id="3264837738038045344">Przycisk zarządzania ustawieniami Chrome; aby otworzyć ustawienia Chrome, naciśnij Enter</translation>
<translation id="3266793032086590337">Wartość (konflikt)</translation>
<translation id="3268451620468152448">Otwarte karty</translation>
@@ -712,6 +748,7 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="3288238092761586174">Weryfikacja Twojej płatności może wymagać od <ph name="URL" /> podjęcia dodatkowych działań</translation>
<translation id="3293642807462928945">Więcej informacji o zasadzie <ph name="POLICY_NAME" /></translation>
<translation id="3295444047715739395">Wyświetl hasła i zarządzaj nimi w ustawieniach Chrome</translation>
+<translation id="3303795387212510132">Zezwolić aplikacji na otwieranie linków <ph name="PROTOCOL_SCHEME" />?</translation>
<translation id="3303855915957856445">Brak wyników wyszukiwania</translation>
<translation id="3304073249511302126">skanowanie Bluetooth</translation>
<translation id="3308006649705061278">Jednostka organizacyjna (OU)</translation>
@@ -725,12 +762,6 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="3345782426586609320">Oczy</translation>
<translation id="3355823806454867987">Zmień ustawienia serwera proxy...</translation>
<translation id="3360103848165129075">Arkusz modułu do obsługi płatności</translation>
-<translation id="3361596688432910856">Chrome <ph name="BEGIN_EMPHASIS" />nie będzie zapisywać<ph name="END_EMPHASIS" />:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Twojej historii przeglÄ…dania;
- <ph name="LIST_ITEM" />plików cookie i danych ze stron internetowych;
- <ph name="LIST_ITEM" />informacji, które wpisujesz w formularzach.
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">Ta zasada została automatycznie skopiowana z wycofanej zasady <ph name="OLD_POLICY" />. Zalecamy używanie nowej zasady.</translation>
<translation id="3364869320075768271"><ph name="URL" /> chce używać Twojego urządzenia i danych rzeczywistości wirtualnej</translation>
<translation id="3366477098757335611">Wyświetl karty</translation>
@@ -813,7 +844,6 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="3587738293690942763">Åšredni</translation>
<translation id="3592413004129370115">Italian (koperta)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{Możesz zresetować grupę w dowolnym momencie. Dołączenie do nowej grupy trwa około 1 dnia.}=1{Możesz zresetować grupę w dowolnym momencie. Dołączenie do nowej grupy trwa około 1 dnia.}few{Możesz zresetować grupę w dowolnym momencie. Dołączenie do nowej grupy trwa około {NUM_DAYS} dni.}many{Możesz zresetować grupę w dowolnym momencie. Dołączenie do nowej grupy trwa około {NUM_DAYS} dni.}other{Możesz zresetować grupę w dowolnym momencie. Dołączenie do nowej grupy trwa około {NUM_DAYS} dnia.}}</translation>
-<translation id="3596012367874587041">Ustawienia aplikacji</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">Aplikacja zablokowana przez administratora</translation>
<translation id="3608932978122581043">Orientacja podajnika</translation>
@@ -856,6 +886,7 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="370972442370243704">Włącz Serie czynności</translation>
<translation id="3711895659073496551">Wstrzymaj</translation>
<translation id="3712624925041724820">Brak wolnych licencji</translation>
+<translation id="3714633008798122362">kalendarz sieciowy</translation>
<translation id="3714780639079136834">Włącz komórkową transmisję danych lub Wi-Fi</translation>
<translation id="3715597595485130451">Połączenie z siecią Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Sprawdź serwer proxy, zaporę sieciową i konfigurację DNS<ph name="END_LINK" /></translation>
@@ -917,6 +948,7 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="3906954721959377182">Tablet</translation>
<translation id="3909477809443608991"><ph name="URL" /> chce odtworzyć treść chronioną. Tożsamość Twojego urządzenia zostanie sprawdzona przez Google i może być dostępna dla tej strony.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">Odmawiaj</translation>
<translation id="3939773374150895049">Używać WebAuthn zamiast kodu CVC?</translation>
<translation id="3946209740501886391">Zawsze pytaj na tej stronie</translation>
<translation id="3947595700203588284">Może prosić o zgodę na połączenie z urządzeniami MIDI</translation>
@@ -937,6 +969,7 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="3987940399970879459">Mniej niż 1 MB</translation>
<translation id="3990250421422698716">Odsunięcie poszczególnych kopii</translation>
<translation id="3996311196211510766">Strona <ph name="ORIGIN" /> zażądała, by do wszystkich kierowanych do niej żądań stosować zasadę dotyczącą źródła, ale tej zasady nie można teraz zastosować.</translation>
+<translation id="4009243425692662128">Zawartość drukowanych stron jest wysyłana do Google Cloud lub innych firm w celu przeanalizowania. Może na przykład zostać przeskanowana w poszukiwaniu danych wrażliwych.</translation>
<translation id="4010758435855888356">Zezwolić na dostęp do pamięci?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{Dokument PDF zawierający {COUNT} stronę}few{Dokument PDF zawierający {COUNT} strony}many{Dokument PDF zawierający {COUNT} stron}other{Dokument PDF zawierający {COUNT} strony}}</translation>
<translation id="4023431997072828269">Twoje dane będą widoczne dla innych, ponieważ połączenie używane do przesłania formularza nie jest bezpieczne.</translation>
@@ -1027,6 +1060,7 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="4250680216510889253">Nie</translation>
<translation id="4253168017788158739">Uwaga</translation>
<translation id="425582637250725228">Wprowadzone zmiany mogą nie zostać zapisane.</translation>
+<translation id="425869179292622354">Zwiększyć jej bezpieczeństwo za pomocą karty wirtualnej?</translation>
<translation id="4258748452823770588">Nieprawidłowy podpis</translation>
<translation id="4261046003697461417">Nie można dodawać adnotacji do dokumentów chronionych</translation>
<translation id="4265872034478892965">Dozwolone przez administratora</translation>
@@ -1089,6 +1123,7 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="4434045419905280838">Pop-upy i przekierowania</translation>
<translation id="4435702339979719576">pocztówka)</translation>
<translation id="443673843213245140">Korzystanie z serwera proxy jest wyłączone, ale podano konfigurację proxy.</translation>
+<translation id="4441832193888514600">Ignorowana, ponieważ tę zasadę można skonfigurować wyłącznie jako dotyczącą użytkowników i obowiązującą w chmurze.</translation>
<translation id="4450893287417543264">Nie pokazuj ponownie</translation>
<translation id="4451135742916150903">Może prosić o zgodę na połączenie z urządzeniami HID</translation>
<translation id="4452328064229197696">Użyte właśnie hasło znaleźliśmy jako ujawnione w wyniku naruszenia bezpieczeństwa danych. Menedżer haseł Google zaleca sprawdzenie zapisanych haseł – pozwoli to zabezpieczyć Twoje konta.</translation>
@@ -1144,6 +1179,7 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="4628948037717959914">Zdjęcie</translation>
<translation id="4631649115723685955">Połączone ze zwrotem za zakupy</translation>
<translation id="4636930964841734540">Informacje</translation>
+<translation id="4638670630777875591">Tryb incognito w Chromium</translation>
<translation id="464342062220857295">Funkcje wyszukiwarki</translation>
<translation id="4644670975240021822">Odwrotna kolejność, strona do drukowania skierowana w dół</translation>
<translation id="4646534391647090355">Przejdź tam teraz</translation>
@@ -1164,6 +1200,7 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="4708268264240856090">Połączenie zostało przerwane</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Uruchom DiagnostykÄ™ sieci systemu Windows<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426">Hasło użytkownika <ph name="USERNAME" /></translation>
<translation id="4724144314178270921">Może prosić o dostęp do tekstu i obrazów w schowku</translation>
<translation id="4726672564094551039">Odśwież zasady</translation>
<translation id="4728558894243024398">Platforma</translation>
@@ -1185,6 +1222,7 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="4757993714154412917">Przed chwilą wpisano hasło na stronie wprowadzającej w błąd. Dla bezpieczeństwa Twoich kont Chromium zaleca sprawdzenie zapisanych haseł.</translation>
<translation id="4758311279753947758">Dodaj dane kontaktowe</translation>
<translation id="4761104368405085019">Korzystanie z Twojego mikrofonu</translation>
+<translation id="4761869838909035636">Uruchom kontrolę zabezpieczeń Chrome</translation>
<translation id="4764776831041365478">Strona internetowa pod adresem <ph name="URL" /> może być tymczasowo niedostępna lub została na stałe przeniesiona pod nowy adres internetowy.</translation>
<translation id="4766713847338118463">Dwie zszywki na dole</translation>
<translation id="4771973620359291008">Wystąpił nieznany błąd.</translation>
@@ -1205,12 +1243,6 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="4819347708020428563">Czy chcesz edytować adnotacje w widoku domyślnym?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />; naciśnij Tab, a potem Enter, aby szybko utworzyć nowy arkusz Google</translation>
<translation id="4825507807291741242">Intensywny</translation>
-<translation id="4827402517081186284">Tryb incognito nie czyni nikogo niewidzialnym w internecie:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Strony wiedzą, że je odwiedzasz.<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Pracodawcy lub szkolni administratorzy mogą sprawdzać Twoją aktywność związaną z przeglądaniem.<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Dostawcy usług internetowych mogą monitorować ruch w sieci.<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">Włącz ostrzeżenia</translation>
<translation id="4838327282952368871">Uroczy</translation>
<translation id="4840250757394056958">Wyświetl historię Chrome</translation>
@@ -1222,12 +1254,12 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="4854362297993841467">Ta metoda dostawy jest niedostępna. Wybierz inną.</translation>
<translation id="4854853140771946034">Szybko utwórz nową notatkę w Google Keep</translation>
<translation id="485902285759009870">WeryfikujÄ™ kod...</translation>
+<translation id="4866506163384898554">Naciśnij |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />|, aby wyświetlić kursor</translation>
<translation id="4876188919622883022">Widok uproszczony</translation>
<translation id="4876305945144899064">Brak nazwy użytkownika</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{Brak}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}few{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}many{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831">Wyszukiwanie ciÄ…gu <ph name="TEXT" /></translation>
<translation id="4879491255372875719">Automatycznie (domyślnie)</translation>
-<translation id="4879725228911483934">Otwierać i rozmieszczać okna na Twoich ekranach.</translation>
<translation id="4880827082731008257">Przeszukaj historiÄ™</translation>
<translation id="4881695831933465202">Otwórz</translation>
<translation id="4885256590493466218">Zapłać kartą <ph name="CARD_DETAIL" /></translation>
@@ -1236,6 +1268,7 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">Rolka 9</translation>
<translation id="4901778704868714008">Zapisz...</translation>
+<translation id="4905659621780993806">Administrator automatycznie uruchomi Twoje urządzenie ponownie <ph name="DATE" /> o <ph name="TIME" />. Zanim to się stanie, zapisz wszystkie otwarte elementy.</translation>
<translation id="4913987521957242411">Otwór w lewym górnym rogu</translation>
<translation id="4918221908152712722">Zainstaluj aplikacjÄ™ <ph name="APP_NAME" /> (nie wymaga pobrania)</translation>
<translation id="4923459931733593730">Płatność</translation>
@@ -1244,6 +1277,7 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />. Naciśnij Tab, a następnie Enter, by wyszukać.</translation>
<translation id="4930153903256238152">Duża pojemność</translation>
+<translation id="4940163644868678279">Tryb incognito w Chrome</translation>
<translation id="4943872375798546930">Brak wyników</translation>
<translation id="4950898438188848926">Przycisk przełączania kart. Naciśnij Enter, by przełączyć się na otwartą kartę, <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="495170559598752135">Czynności</translation>
@@ -1253,6 +1287,7 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="4968522289500246572">Ta aplikacja jest przeznaczona na urządzenia mobilne i po zmianie rozmiaru może sprawiać problemy. Może uruchamiać się ponownie lub działać nieprawidłowo.</translation>
<translation id="4969341057194253438">Usuń nagranie</translation>
<translation id="4973922308112707173">Dwa otwory u góry</translation>
+<translation id="4976702386844183910">Ostatnia wizyta <ph name="DATE" /></translation>
<translation id="4984088539114770594">Korzystać z mikrofonu?</translation>
<translation id="4984339528288761049">Prc5 (koperta)</translation>
<translation id="4989163558385430922">Pokaż wszystko</translation>
@@ -1314,6 +1349,7 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="5138227688689900538">Pokaż mniej</translation>
<translation id="5145883236150621069">W odebranej polityce znajduje się kod błędu</translation>
<translation id="5146995429444047494">Powiadomienia z <ph name="ORIGIN" /> są blokowane</translation>
+<translation id="514704532284964975">Strona <ph name="URL" /> chce odczytywać i zmieniać informacje na urządzeniach z funkcją NFC, do których zbliżasz telefon</translation>
<translation id="5148809049217731050">W górę</translation>
<translation id="515292512908731282">C4 (koperta)</translation>
<translation id="5158275234811857234">Okładka</translation>
@@ -1338,6 +1374,7 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="5215116848420601511">Formy płatności i adresy z Google Pay</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">Taca 13</translation>
+<translation id="5216942107514965959">Ostatnio używana dzisiaj</translation>
<translation id="5222812217790122047">E-mail jest wymagany</translation>
<translation id="5230733896359313003">Adres wysyłki</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1358,7 +1395,6 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">Właściwości dokumentu</translation>
<translation id="528468243742722775">Zakończ</translation>
-<translation id="5284909709419567258">Adresy sieciowe</translation>
<translation id="5285570108065881030">Pokaż wszystkie zapisane hasła</translation>
<translation id="5287240709317226393">Pokaż pliki cookie</translation>
<translation id="5287456746628258573">Ta strona używa nieaktualnej konfiguracji zabezpieczeń, co oznacza, że Twoje dane (np. hasła i numery kart kredytowych) mogą być zagrożone podczas przesyłania na tę stronę.</translation>
@@ -1442,6 +1478,7 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="5556459405103347317">Odśwież</translation>
<translation id="5560088892362098740">Data ważności</translation>
<translation id="55635442646131152">Konspekt dokumentu</translation>
+<translation id="5565613213060953222">Otwórz kartę incognito</translation>
<translation id="5565735124758917034">Aktywny</translation>
<translation id="5570825185877910964">Chroń konto</translation>
<translation id="5571083550517324815">Odbiór spod tego adresu jest niemożliwy. Wybierz inny adres.</translation>
@@ -1524,6 +1561,7 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="5869522115854928033">Zapisane hasła</translation>
<translation id="5873013647450402046">Bank chce potwierdzić Twoją tożsamość.</translation>
<translation id="5887400589839399685">Zapisano kartÄ™</translation>
+<translation id="5887687176710214216">Ostatnio używana wczoraj</translation>
<translation id="5895138241574237353">Uruchom ponownie</translation>
<translation id="5895187275912066135">Wystawiony dnia</translation>
<translation id="5901630391730855834">Żółty</translation>
@@ -1537,6 +1575,7 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="5921639886840618607">Zapisać kartę na koncie Google?</translation>
<translation id="5922853866070715753">Prawie gotowe</translation>
<translation id="5932224571077948991">Na tej stronie wyświetlają się uciążliwe lub wprowadzające w błąd reklamy</translation>
+<translation id="5938153366081463283">Dodaj kartÄ™ wirtualnÄ…</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347">Otwieram <ph name="SITE_NAME" />…</translation>
<translation id="5951495562196540101">Nie można zarejestrować się przy użyciu konta klienta (w pakiecie dostępna jest licencja).</translation>
@@ -1601,6 +1640,7 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="6120179357481664955">Zapamiętać Twój identyfikator UPI?</translation>
<translation id="6124432979022149706">Oprogramowanie sprzęgające Chrome Enterprise</translation>
<translation id="6127379762771434464">Element został usunięty</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Dowiedz się więcej o trybie incognito w Chrome<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">Sprawdź wszystkie kable i uruchom ponownie wszelkie używane routery, modemy
i inne urzÄ…dzenia sieciowe.</translation>
<translation id="614940544461990577">Wypróbuj te rozwiązania:</translation>
@@ -1613,7 +1653,6 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="6169916984152623906">Teraz możesz korzystać z internetu w trybie prywatnym. Inne osoby używające tego urządzenia nie zobaczą Twojej aktywności. Pamiętaj tylko, że zakładki i pobrane pliki są zapisywane.</translation>
<translation id="6177128806592000436">Twoje połączenie z tą witryną nie jest bezpieczne</translation>
<translation id="6180316780098470077">Interwał ponawiania</translation>
-<translation id="619448280891863779">Może prosić o zgodę na otwieranie i rozmieszczanie okien na Twoich ekranach</translation>
<translation id="6196640612572343990">Blokuj pliki cookie innych firm</translation>
<translation id="6203231073485539293">Sprawdź połączenie z internetem</translation>
<translation id="6218753634732582820">Usunąć ten adres z Chromium?</translation>
@@ -1636,7 +1675,7 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="6272383483618007430">Google Update</translation>
<translation id="6276112860590028508">Tu pojawiÄ… siÄ™ strony z Twojej listy Do przeczytania</translation>
<translation id="627746635834430766">Aby następnym razem zapłacić szybciej, zapisz kartę i adres rozliczeniowy na swoim koncie Google.</translation>
-<translation id="6279098320682980337">Nie uzupełniono numeru karty wirtualnej? Kliknij dane karty, które chcesz skopiować</translation>
+<translation id="6279183038361895380">Naciśnij |<ph name="ACCELERATOR" />|, by wyświetlić kursor</translation>
<translation id="6280223929691119688">Nie można dostarczyć pod ten adres. Wybierz inny.</translation>
<translation id="6282194474023008486">Kod pocztowy</translation>
<translation id="6285507000506177184">Przycisk Zarządzaj pobranymi plikami w Chrome; aby zarządzać pobranymi plikami w Chrome, naciśnij Enter</translation>
@@ -1644,6 +1683,7 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="6290238015253830360">Tutaj wyświetlą się proponowane artykuły</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">Kod CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{Twoje urządzenie uruchomi się ponownie teraz}=1{Twoje urządzenie uruchomi się ponownie za 1 sekundę}few{Twoje urządzenie uruchomi się ponownie za # sekundy}many{Twoje urządzenie uruchomi się ponownie za # sekund}other{Twoje urządzenie uruchomi się ponownie za # sekundy}}</translation>
<translation id="6302269476990306341">Wyłączam Asystenta Google w Chrome</translation>
<translation id="6305205051461490394">Strona <ph name="URL" /> jest nieosiÄ…galna.</translation>
<translation id="6312113039770857350">Strona internetowa jest niedostępna</translation>
@@ -1717,6 +1757,7 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="6529602333819889595">&amp;Ponów usunięcie</translation>
<translation id="6545864417968258051">Skanowanie Bluetooth</translation>
<translation id="6547208576736763147">Dwa otwory po lewej</translation>
+<translation id="6554732001434021288">Ostatnio używano <ph name="NUM_DAYS" /> dni temu</translation>
<translation id="6556866813142980365">Ponów</translation>
<translation id="6569060085658103619">PrzeglÄ…dasz stronÄ™ rozszerzenia</translation>
<translation id="6573200754375280815">Dwa otwory po prawej</translation>
@@ -1777,7 +1818,6 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="6757797048963528358">Twoje urządzenie przeszło w tryb uśpienia.</translation>
<translation id="6767985426384634228">Zmienić adres?</translation>
<translation id="6768213884286397650">Hagaki (pocztówka)</translation>
-<translation id="6774185088257932239"><ph name="BEGIN_LINK" />Więcej informacji<ph name="END_LINK" /> o trybie incognito</translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">Fioletowy</translation>
<translation id="6786747875388722282">Rozszerzenia</translation>
@@ -1861,7 +1901,6 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="706295145388601875">Dodaj adresy i zarządzaj nimi w ustawieniach Chrome</translation>
<translation id="7064851114919012435">Dane kontaktowe</translation>
<translation id="7068733155164172741">Wpisz <ph name="OTP_LENGTH" />-cyfrowy kod</translation>
-<translation id="7070090581017165256">O tej witrynie</translation>
<translation id="70705239631109039">Połączenie nie jest całkowicie bezpieczne</translation>
<translation id="7075452647191940183">Żądanie jest za duże</translation>
<translation id="7079718277001814089">Ta strona zawiera złośliwe oprogramowanie</translation>
@@ -1878,6 +1917,12 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="7111012039238467737">(Ważny)</translation>
<translation id="7118618213916969306">Wyszukaj URL ze schowka, <ph name="SHORT_URL" /></translation>
<translation id="7119414471315195487">Zamknij inne karty lub programy</translation>
+<translation id="7129355289156517987">Gdy w Chromium zamkniesz wszystkie karty incognito, z urządzenia zostanie usunięta Twoja aktywność powiązana z nimi, w tym:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />aktywność związana z przeglądaniem,<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />historia wyszukiwania,<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />informacje wpisane w formularzach.<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">Nie można wysłać pod ten adres. Wybierz inny.</translation>
<translation id="7132939140423847331">Administrator nie zezwala na kopiowanie tych danych.</translation>
<translation id="7135130955892390533">Wyświetlanie informacji o obecności</translation>
@@ -1900,6 +1945,7 @@ Jeśli się nie zgodzisz, zostaną one zablokowane ze względu na Twoje ustawien
<translation id="7192203810768312527">Zwolni się <ph name="SIZE" />. Podczas następnej wizyty niektóre strony mogą ładować się wolniej.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">Administrator może zobaczyć:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, naciśnij Tab, a potem Enter, aby otworzyć nową kartę incognito i przeglądać prywatnie</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423">Serwer <ph name="HOST_NAME" /> nie spełnia norm bezpieczeństwa.</translation>
<translation id="7210993021468939304">Wyświetlanie aktywności Linuksa w kontenerze oraz instalowanie i uruchamianie aplikacji Linuksa w kontenerze</translation>
@@ -1931,6 +1977,7 @@ Dodatkowe informacje:
<translation id="7304562222803846232">Zarządzaj ustawieniami prywatności konta Google</translation>
<translation id="7305756307268530424">Rozpocznij wolniej</translation>
<translation id="7308436126008021607">synchronizacja w tle</translation>
+<translation id="7310392214323165548">Urządzenie wkrótce uruchomi się ponownie</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">Pomoc dotycząca połączeń</translation>
<translation id="7323804146520582233">Ukryj sekcjÄ™ „<ph name="SECTION" />â€</translation>
@@ -1938,6 +1985,7 @@ Dodatkowe informacje:
<translation id="7334320624316649418">&amp;Ponów zmianę kolejności</translation>
<translation id="7335157162773372339">Może prosić o dostęp do kamery</translation>
<translation id="7337248890521463931">Pokaż więcej wierszy</translation>
+<translation id="7337418456231055214">Nie uzupełniono numeru karty wirtualnej? Kliknij dane karty, które chcesz skopiować. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">Niedostępny na Twojej platformie.</translation>
<translation id="733923710415886693">Certyfikat serwera nie został ujawniony przez protokół Certificate Transparency.</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1960,6 +2008,7 @@ Dodatkowe informacje:
<translation id="7378627244592794276">Nie</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">Nie dotyczy</translation>
+<translation id="7388594495505979117">{0,plural, =1{Twoje urządzenie uruchomi się ponownie za 1 minutę}few{Twoje urządzenie uruchomi się ponownie za # minuty}many{Twoje urządzenie uruchomi się ponownie za # minut}other{Twoje urządzenie uruchomi się ponownie za # minuty}}</translation>
<translation id="7390545607259442187">Potwierdź kartę</translation>
<translation id="7392089738299859607">Zmień adres</translation>
<translation id="7399802613464275309">Kontrola zabezpieczeń</translation>
@@ -1996,6 +2045,12 @@ Dodatkowe informacje:
<translation id="7485870689360869515">Nie znaleziono danych.</translation>
<translation id="7495528107193238112">Ta zawartość jest zablokowana. Aby rozwiązać problem, skontaktuj się z właścicielem witryny.</translation>
<translation id="7497998058912824456">Przycisk Utwórz dokument; naciśnij Enter, aby szybko utworzyć nowy dokument Google</translation>
+<translation id="7506488012654002225">W Chromium <ph name="BEGIN_EMPHASIS" />nie są zapisywane<ph name="END_EMPHASIS" /> te informacje:
+<ph name="BEGIN_LIST" />
+<ph name="LIST_ITEM" />Twoja historia przeglÄ…dania,
+<ph name="LIST_ITEM" />pliki cookie ani dane witryn,
+<ph name="LIST_ITEM" />informacje podane w formularzach.
+<ph name="END_LIST" /></translation>
<translation id="7508255263130623398">Zwrócony identyfikator urządzenia dla zasad jest pusty lub nie pasuje do bieżącego identyfikatora urządzenia</translation>
<translation id="7508870219247277067">Zielony awokado</translation>
<translation id="7511955381719512146">Sieć Wi-Fi, której używasz, może wymagać otwarcia strony <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
@@ -2109,7 +2164,6 @@ Dodatkowe informacje:
<translation id="7813600968533626083">Usunąć tę podpowiedź do formularza z Chrome?</translation>
<translation id="781440967107097262">Udostępnić schowek?</translation>
<translation id="7815407501681723534">Znalezione <ph name="SEARCH_RESULTS" /> dla zapytania „<ph name="SEARCH_STRING" />â€: <ph name="NUMBER_OF_RESULTS" /></translation>
-<translation id="782125616001965242">Pokaż informacje o tej witrynie</translation>
<translation id="782886543891417279">Sieć Wi-Fi (<ph name="WIFI_NAME" />), której używasz, może wymagać otwarcia strony logowania.</translation>
<translation id="7836231406687464395">Postfix (koperta)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{Brak}=1{Jedna aplikacja (<ph name="EXAMPLE_APP_1" />)}=2{Dwie aplikacje (<ph name="EXAMPLE_APP_1" /> i <ph name="EXAMPLE_APP_2" />)}few{# aplikacje (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" /> <ph name="AND_MORE" />)}many{# aplikacji (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" /> <ph name="AND_MORE" />)}other{# aplikacji (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" /> <ph name="AND_MORE" />)}}</translation>
@@ -2126,7 +2180,6 @@ Dodatkowe informacje:
<translation id="7888575728750733395">Intencja renderowania wydruku</translation>
<translation id="7894280532028510793">Jeśli pisownia jest poprawna, <ph name="BEGIN_LINK" />uruchom Diagnostykę sieci<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (koperta)</translation>
-<translation id="7931318309563332511">Nieznany</translation>
<translation id="793209273132572360">Zaktualizować adres?</translation>
<translation id="7932579305932748336">Powłoka</translation>
<translation id="79338296614623784">Wpisz prawidłowy numer telefonu</translation>
@@ -2151,13 +2204,14 @@ Dodatkowe informacje:
<translation id="7976214039405368314">Zbyt wiele żądań</translation>
<translation id="7977538094055660992">Urządzenie wyjściowe</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">Połączono z:</translation>
<translation id="798134797138789862">Może prosić o zgodę na używanie urządzeń i danych rzeczywistości wirtualnej</translation>
<translation id="7984945080620862648">Nie możesz teraz odwiedzić strony <ph name="SITE" />, bo wysłała ona zakodowane poświadczenia, których Chrome nie może przetworzyć. Błędy sieci i ataki są zazwyczaj przejściowe, więc prawdopodobnie strona będzie wkrótce działać.</translation>
-<translation id="79859296434321399">Aby oglądać treści rzeczywistości rozszerzonej, zainstaluj ARCore</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">WiÄ…zanie</translation>
<translation id="7992044431894087211">Udostępnianie ekranu w aplikacji <ph name="APPLICATION_TITLE" /> zostało wznowione</translation>
<translation id="7995512525968007366">Nie określono</translation>
+<translation id="7998269595945679889">Przycisk Otwórz kartę incognito; naciśnij Enter, aby otworzyć nową kartę incognito i przeglądać prywatnie</translation>
<translation id="800218591365569300">Zamknij inne karty lub programy, by zwolnić pamięć.</translation>
<translation id="8004582292198964060">PrzeglÄ…darka</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{Ta karta i jej adres rozliczeniowy zostaną zapisane. Możesz ich używać po zalogowaniu się na konto <ph name="USER_EMAIL" />.}few{Te karty i ich adresy rozliczeniowe zostaną zapisane. Możesz ich używać po zalogowaniu się na konto <ph name="USER_EMAIL" />.}many{Te karty i ich adresy rozliczeniowe zostaną zapisane. Możesz ich używać po zalogowaniu się na konto <ph name="USER_EMAIL" />.}other{Te karty i ich adresy rozliczeniowe zostaną zapisane. Możesz ich używać po zalogowaniu się na konto <ph name="USER_EMAIL" />.}}</translation>
@@ -2217,6 +2271,7 @@ Dodatkowe informacje:
<translation id="8202370299023114387">Konflikt</translation>
<translation id="8206978196348664717">Prc4 (koperta)</translation>
<translation id="8211406090763984747">Połączenie jest bezpieczne</translation>
+<translation id="8217240300496046857">Strony nie mogą używać plików cookie śledzących, co robisz w sieci. Funkcje niektórych stron mogą nie działać prawidłowo.</translation>
<translation id="8218327578424803826">Przypisana lokalizacja:</translation>
<translation id="8220146938470311105">C7/C6 (koperta)</translation>
<translation id="8225771182978767009">Administrator tego komputera zablokował tę witrynę.</translation>
@@ -2257,14 +2312,9 @@ Dodatkowe informacje:
<translation id="830498451218851433">Składanie w połowie</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">Zainstalowane aplikacje i częstotliwość ich użycia</translation>
+<translation id="8317207217658302555">Zaktualizować ARCore?</translation>
<translation id="831997045666694187">Wieczorem</translation>
<translation id="8321476692217554900">powiadomienia</translation>
-<translation id="8328484624016508118">Gdy zamkniesz wszystkie karty incognito, Chrome usunie:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Twoją aktywność związaną z przeglądaniem (z tego urządzenia),<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Twoją historię przeglądania (z tego urządzenia),<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />informacje wpisane w formularzach.<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489">Odmowa dostępu do <ph name="HOST_NAME" /></translation>
<translation id="833262891116910667">Podświetlenie</translation>
<translation id="8339163506404995330">Strony, których językiem jest <ph name="LANGUAGE" />, nie będą tłumaczone</translation>
@@ -2316,6 +2366,7 @@ Dodatkowe informacje:
<translation id="8507227106804027148">Wiersz poleceń</translation>
<translation id="8508648098325802031">Ikona wyszukiwania</translation>
<translation id="8511402995811232419">ZarzÄ…dzaj plikami cookie</translation>
+<translation id="8519753333133776369">UrzÄ…dzenie HID dozwolone przez administratora</translation>
<translation id="8522552481199248698">Chrome może Ci pomóc w zabezpieczeniu Twojego konta Google i zmianie hasła.</translation>
<translation id="8530813470445476232">Wyczyść historię przeglądania, pliki cookie, pamięć podręczną i inne dane w ustawieniach Chrome</translation>
<translation id="8533619373899488139">Wejdź na stronę &lt;strong&gt;chrome://policy&lt;/strong&gt;, by wyświetlić listę zablokowanych adresów URL oraz inne zasady egzekwowane przez administratora systemu.</translation>
@@ -2327,7 +2378,6 @@ Dodatkowe informacje:
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{Zresetuj uprawnienia}few{Zresetuj uprawnienia}many{Zresetuj uprawnienia}other{Zresetuj uprawnienia}}</translation>
<translation id="8555010941760982128">Użyj tego kodu w momencie płatności</translation>
<translation id="8557066899867184262">Kod CVC znajduje siÄ™ na odwrocie karty.</translation>
-<translation id="8558485628462305855">Aby oglądać treści rzeczywistości rozszerzonej, zaktualizuj ARCore</translation>
<translation id="8559762987265718583">Nie można nawiązać prywatnego połączenia z <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />, ponieważ data i godzina (<ph name="DATE_AND_TIME" />) ustawione na urządzeniu są nieprawidłowe.</translation>
<translation id="8564182942834072828">Oddzielne dokumenty / Kopie niesortowane</translation>
<translation id="8564985650692024650">Chromium zaleca zresetowanie hasła, którego używasz w: <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" />, jeśli zostało użyte na innej stronie.</translation>
@@ -2346,6 +2396,7 @@ Dodatkowe informacje:
<translation id="865032292777205197">czujniki ruchu</translation>
<translation id="8663226718884576429">Podsumowanie zamówienia, <ph name="TOTAL_LABEL" />, Szczegółowe informacje</translation>
<translation id="8666678546361132282">Angielski</translation>
+<translation id="8669306706049782872">korzystać z informacji o ekranach, aby otwierać i rozmieszczać okna</translation>
<translation id="867224526087042813">Podpis</translation>
<translation id="8676424191133491403">Bez opóźnienia</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, odpowiedź, <ph name="ANSWER" /></translation>
@@ -2372,6 +2423,7 @@ Dodatkowe informacje:
<translation id="8731544501227493793">Przycisk zarządzania hasłami. Naciśnij Enter, by wyświetlić hasła i zarządzać nimi w ustawieniach Chrome.</translation>
<translation id="8734529307927223492">Twoim urzÄ…dzeniem <ph name="DEVICE_TYPE" /> zarzÄ…dza <ph name="MANAGER" /></translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />. Naciśnij Tab, a potem Enter, by otworzyć nowe okno incognito i przeglądać prywatnie.</translation>
+<translation id="8737685506611670901">Otwieranie linków protokołu <ph name="PROTOCOL" /> zamiast modułu <ph name="REPLACED_HANDLER_TITLE" /></translation>
<translation id="8738058698779197622">Aby nawiązać bezpieczne połączenie, Twój zegar musi mieć ustawioną prawidłową godzinę. Jest to wymagane, ponieważ certyfikaty używane do identyfikacji stron internetowych są ważne tylko przez określony czas. Ponieważ zegar Twojego urządzenia nie jest ustawiony prawidłowo, Chromium nie może zweryfikować tych certyfikatów.</translation>
<translation id="8740359287975076522">Nie znaleziono &lt;abbr id="dnsDefinition"&gt;adresu DNS&lt;/abbr&gt; serwera <ph name="HOST_NAME" />. Diagnozujemy problem.</translation>
<translation id="8742371904523228557"><ph name="ONE_TIME_CODE" /> to Twój kod do <ph name="ORIGIN" /></translation>
@@ -2399,6 +2451,7 @@ Dodatkowe informacje:
<translation id="883848425547221593">Inne zakładki</translation>
<translation id="884264119367021077">Adres wysyłki</translation>
<translation id="884923133447025588">Nie znaleziono mechanizmu unieważniania.</translation>
+<translation id="8849262850971482943">Aby zwiększyć bezpieczeństwo, użyj karty wirtualnej</translation>
<translation id="885730110891505394">Udostępnianie Google</translation>
<translation id="8858065207712248076">Chrome zaleca zresetowanie hasła, którego używasz w: <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" />, jeśli zostało użyte na innej stronie.</translation>
<translation id="885906927438988819">Jeśli pisownia jest poprawna, <ph name="BEGIN_LINK" />uruchom Diagnostykę sieci systemu Windows<ph name="END_LINK" />.</translation>
@@ -2448,6 +2501,7 @@ Dodatkowe informacje:
<translation id="9004367719664099443">Trwa sesja VR</translation>
<translation id="9005998258318286617">Nie udało się wczytać dokumentu PDF.</translation>
<translation id="9008201768610948239">Ignoruj</translation>
+<translation id="901834265349196618">e-mail</translation>
<translation id="9020200922353704812">Wymagany jest adres rozliczeniowy karty kredytowej</translation>
<translation id="9020542370529661692">Ta strona została przetłumaczona na <ph name="TARGET_LANGUAGE" />.</translation>
<translation id="9020742383383852663">A8</translation>
@@ -2496,6 +2550,7 @@ Dodatkowe informacje:
<translation id="9150045010208374699">Korzystanie z Twojej kamery</translation>
<translation id="9150685862434908345">Administrator może zdalnie zmienić konfigurację przeglądarki. Aktywność na tym urządzeniu może być zarządzana również poza Chrome. <ph name="BEGIN_LINK" />Więcej informacji<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">Zaktualizowano</translation>
+<translation id="9155211586651734179">Podłączone urządzenia peryferyjne audio</translation>
<translation id="9157595877708044936">Konfigurowanie...</translation>
<translation id="9158625974267017556">C6 (koperta)</translation>
<translation id="9164029392738894042">Sprawdzenie dokładności</translation>
diff --git a/chromium/components/strings/components_strings_pt-BR.xtb b/chromium/components/strings/components_strings_pt-BR.xtb
index f1a046d4fca..80a8d47d1e6 100644
--- a/chromium/components/strings/components_strings_pt-BR.xtb
+++ b/chromium/components/strings/components_strings_pt-BR.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">Ver detalhes</translation>
<translation id="1030706264415084469"><ph name="URL" /> quer armazenar permanentemente um grande volume de dados no seu dispositivo</translation>
<translation id="1032854598605920125">Girar no sentido horário</translation>
+<translation id="1033329911862281889">Com a navegação anônima, você não fica invisível on-line:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Os sites e os serviços que eles usam podem ver acessos<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Empregadores ou escolas podem rastrear a navegação<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Provedores de acesso à Internet podem monitorar o tráfego da Web<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">Desativar</translation>
<translation id="1036982837258183574">Pressione |<ph name="ACCELERATOR" />| para sair do modo tela cheia</translation>
<translation id="1038106730571050514">Exibir sugestões</translation>
<translation id="1038842779957582377">nome desconhecido</translation>
<translation id="1041998700806130099">Mensagem de página de tarefa</translation>
<translation id="1048785276086539861">Quando você editar as anotações, este documento voltará à visualização de uma página</translation>
-<translation id="1049743911850919806">Modo anônimo</translation>
<translation id="1050038467049342496">Fechar outros apps</translation>
<translation id="1055184225775184556">&amp;Desfazer adicionar</translation>
<translation id="1056898198331236512">Aviso</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">Cache da política OK</translation>
<translation id="1130564665089811311">Botão "Traduzir página". Pressione "Enter" para traduzir a página com o Google Tradutor</translation>
<translation id="1131264053432022307">Imagem que você copiou</translation>
+<translation id="1142846828089312304">Bloquear cookies de terceiros na navegação anônima</translation>
<translation id="1150979032973867961">Este servidor não conseguiu provar que é <ph name="DOMAIN" />. O certificado de segurança não é confiável para o sistema operacional do seu computador. Isso pode ser causado por uma configuração incorreta ou pela interceptação da sua conexão por um invasor.</translation>
<translation id="1151972924205500581">Senha obrigatória</translation>
<translation id="1156303062776767266">Você está vendo um arquivo local ou compartilhado</translation>
@@ -64,7 +70,6 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="1178581264944972037">Pausar</translation>
<translation id="1181037720776840403">Remover</translation>
<translation id="1186201132766001848">Verificar senhas</translation>
-<translation id="1195210374336998651">Acessar as configurações do app</translation>
<translation id="1195558154361252544">As notificações são bloqueadas automaticamente para todos os sites, exceto aqueles que têm permissão</translation>
<translation id="1197088940767939838">Laranja</translation>
<translation id="1201402288615127009">Próxima</translation>
@@ -111,7 +116,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="1307966114820526988">Recursos obsoletos</translation>
<translation id="1308113895091915999">Oferta disponível</translation>
<translation id="1312803275555673949">Quais são as evidências?</translation>
-<translation id="131405271941274527"><ph name="URL" /> quer enviar e receber informações quando você encostar seu smartphone em um dispositivo NFC</translation>
+<translation id="1314311879718644478">Ver conteúdo de realidade aumentada</translation>
<translation id="1314509827145471431">Encadernação do lado direito</translation>
<translation id="1318023360584041678">Salvo no grupo de guias</translation>
<translation id="1319245136674974084">Não perguntar novamente para este app</translation>
@@ -161,6 +166,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="142858679511221695">Usuário na nuvem</translation>
<translation id="1428729058023778569">Este aviso está sendo exibido porque o site não é compatível com HTTPS. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">Imprimir</translation>
+<translation id="1432187715652018471">A página quer instalar um manipulador de serviço.</translation>
<translation id="1432581352905426595">Gerenciar mecanismos de pesquisa</translation>
<translation id="1436185428532214179">Pode pedir para editar arquivos e pastas no dispositivo</translation>
<translation id="1442386063175183758">Dobra janela à direita</translation>
@@ -181,6 +187,12 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="1483493594462132177">Enviar</translation>
<translation id="1484290072879560759">Escolher endereço de entrega</translation>
<translation id="1492194039220927094">Push de políticas:</translation>
+<translation id="149293076951187737">Ao fechar todas as guias anônimas do Chrome, suas atividades nelas vão ser apagadas deste dispositivo:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Atividade de navegação<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Histórico de pesquisa<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Informações inseridas em formulários<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">Voltar à guia</translation>
<translation id="1501859676467574491">Mostre os cartões salvos na Conta do Google</translation>
<translation id="1507202001669085618">&lt;p&gt;Você verá esse erro se estiver usando um portal Wi-Fi em que precise fazer login para poder se conectar.&lt;/p&gt;
@@ -208,6 +220,8 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="1559572115229829303">&lt;p&gt;Não é possível estabelecer uma conexão particular com <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> porque a data e hora do seu dispositivo (<ph name="DATE_AND_TIME" />) estão incorretas.&lt;/p&gt;
&lt;p&gt;Ajuste a data e hora na seção &lt;strong&gt;Geral&lt;/strong&gt; do aplicativo &lt;strong&gt;Config.&lt;/strong&gt;.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">O administrador vai reiniciar seu dispositivo em <ph name="DATE" />, <ph name="TIME" /></translation>
+<translation id="156703335097561114">Informações de rede, como endereços, configuração da interface e qualidade da conexão</translation>
<translation id="1567040042588613346">A política está funcionando da maneira esperada, mas o mesmo valor foi definido em outro lugar e foi substituído por esta política.</translation>
<translation id="1569487616857761740">Informar data de validade</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="1583429793053364125">Algo deu errado ao exibir esta página da Web.</translation>
<translation id="1586541204584340881">quais extensões você instalou;</translation>
<translation id="1588438908519853928">Normal</translation>
+<translation id="1589050138437146318">Instalar o ARCore?</translation>
<translation id="1592005682883173041">Acesso a dados locais</translation>
<translation id="1594030484168838125">Escolher</translation>
<translation id="160851722280695521">Iniciar o jogo do Dinossauro do Chrome</translation>
@@ -254,7 +269,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="1711234383449478798">Ignorada porque a política <ph name="POLICY_NAME" /> não está definida como <ph name="VALUE" />.</translation>
<translation id="1712552549805331520"><ph name="URL" /> quer armazenar dados no computador local</translation>
<translation id="1713628304598226412">Bandeja 2</translation>
-<translation id="1715874602234207">F</translation>
+<translation id="1715874602234207">S</translation>
<translation id="1717218214683051432">Sensores de movimento</translation>
<translation id="1717494416764505390">Caixa de e-mails 3</translation>
<translation id="1718029547804390981">O documento é grande demais para receber anotações</translation>
@@ -279,6 +294,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="1763864636252898013">Este servidor não conseguiu provar que é <ph name="DOMAIN" />. O certificado de segurança não é confiável para o sistema operacional do seu dispositivo. Isso pode ser causado por uma configuração incorreta ou pela interceptação da sua conexão por um invasor.</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Tente executar o Diagnóstico de Rede do Windows<ph name="END_LINK" />.</translation>
<translation id="1772163372082567643">O servidor que você acessará, <ph name="ORIGIN" />, definiu um cabeçalho solicitando que uma política de origem seja aplicada a todas as solicitações feitas a ele. No entanto, o cabeçalho está incorreto, o que impede que o navegador faça a solicitação para <ph name="SITE" />. Políticas de origem podem ser usadas por operadores para configurar a segurança e outras propriedades de um site.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Saiba mais sobre a navegação anônima no Chromium<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">Suas guias abertas são exibidas aqui</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -406,6 +422,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="22081806969704220">Bandeja 3</translation>
<translation id="2212735316055980242">Política não encontrada</translation>
<translation id="2213606439339815911">Buscando entradas...</translation>
+<translation id="2213612003795704869">A página foi impressa</translation>
<translation id="2215727959747642672">Edição de arquivo</translation>
<translation id="2218879909401188352">Os invasores que estão em <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> no momento podem instalar apps perigosos que danificam seu dispositivo, acrescentam cobranças ocultas junto à operadora ou roubam suas informações pessoais. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">Sem Internet</translation>
@@ -415,6 +432,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="2248949050832152960">Usar WebAuthn</translation>
<translation id="2250931979407627383">Costura no lado esquerdo</translation>
<translation id="225207911366869382">Este valor está obsoleto para esta política.</translation>
+<translation id="2256115617011615191">Reiniciar agora</translation>
<translation id="2258928405015593961">Insira uma data de validade no futuro e tente novamente</translation>
<translation id="225943865679747347">Código de erro: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">Erro HTTP</translation>
@@ -442,6 +460,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="2337852623177822836">Configuração controlada pelo administrador</translation>
<translation id="2340263603246777781">O <ph name="ORIGIN" /> deseja realizar o pareamento</translation>
<translation id="2346319942568447007">Imagem que você copiou</translation>
+<translation id="2350796302381711542">Permitir que <ph name="HANDLER_HOSTNAME" /> abra todos os links de <ph name="PROTOCOL" /> em vez de <ph name="REPLACED_HANDLER_TITLE" />?</translation>
<translation id="2354001756790975382">Outros favoritos</translation>
<translation id="2354430244986887761">Recentemente, o recurso "Navegação segura" do Google <ph name="BEGIN_LINK" />encontrou apps prejudiciais<ph name="END_LINK" /> em <ph name="SITE" />.</translation>
<translation id="2355395290879513365">É possível que invasores consigam ver as imagens que você está olhando nesse site e as modifiquem para enganar você.</translation>
@@ -467,6 +486,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="2413528052993050574">Este servidor não conseguiu provar que é <ph name="DOMAIN" />. O certificado de segurança pode ter sido revogado. Isso pode ser causado por uma configuração incorreta ou pela interceptação da sua conexão por um invasor.</translation>
<translation id="2414886740292270097">Escuro</translation>
<translation id="2430968933669123598">Gerenciar sua Conta do Google. Pressione Enter para gerenciar suas informações, sua privacidade e sua segurança na Conta do Google</translation>
+<translation id="2436186046335138073">Permitir que <ph name="HANDLER_HOSTNAME" /> abra todos os links de <ph name="PROTOCOL" />?</translation>
<translation id="2438874542388153331">Perfuração quádrupla no lado direito</translation>
<translation id="2450021089947420533">Jornadas</translation>
<translation id="2463739503403862330">Preencher</translation>
@@ -474,6 +494,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="2465655957518002998">Escolher método de entrega</translation>
<translation id="2465688316154986572">Grampear</translation>
<translation id="2465914000209955735">Gerenciar arquivos transferidos por download no Chrome</translation>
+<translation id="2466004615675155314">Mostrar informações da Web</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Executar o Diagnóstico de Rede<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">Ordem 1 a N</translation>
<translation id="2470767536994572628">Quando você editar as anotações, este documento voltará à visualização de uma página e à rotação original</translation>
@@ -494,6 +515,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="2523886232349826891">Salvo apenas neste dispositivo</translation>
<translation id="2524461107774643265">Adicione Mais Informações</translation>
<translation id="2529899080962247600">Esse campo não pode ter mais que <ph name="MAX_ITEMS_LIMIT" /> entradas. Todas as entradas futuras serão ignoradas.</translation>
+<translation id="2535585790302968248">Abra uma nova guia anônima para navegar com privacidade</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{e mais 1}one{e mais #}other{e mais #}}</translation>
<translation id="2536110899380797252">Adicionar Endereço</translation>
<translation id="2539524384386349900">Detectar</translation>
@@ -519,7 +541,14 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="2597378329261239068">Este documento está protegido por senha. Digite a senha.</translation>
<translation id="2609632851001447353">Variações</translation>
<translation id="2610561535971892504">Clique para copiar</translation>
+<translation id="2617988307566202237">O Chrome <ph name="BEGIN_EMPHASIS" />não vai salvar<ph name="END_EMPHASIS" /> estas informações:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Seu histórico de navegação
+ <ph name="LIST_ITEM" />Cookies e dados de sites
+ <ph name="LIST_ITEM" />Informações inseridas em formulários
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (Envelope)</translation>
+<translation id="2623663032199728144">Pode pedir para usar informações sobre suas telas</translation>
<translation id="2625385379895617796">Seu relógio está adiantado</translation>
<translation id="262745152991669301">Pode pedir para se conectar a dispositivos USB</translation>
<translation id="2629325967560697240">Para usar o nível mais alto de segurança do Chrome, <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />ative a proteção reforçada<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -553,6 +582,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="2709516037105925701">Preenchimento automático</translation>
<translation id="2713444072780614174">Branco</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />. Pressione "Tab" e depois "Enter" para gerenciar suas informações de pagamento e de cartão de crédito nas configurações do Chrome</translation>
+<translation id="271663710482723385">Pressione |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| para sair da tela cheia</translation>
<translation id="2721148159707890343">Solicitação bem-sucedida</translation>
<translation id="2723669454293168317">Executar uma confirmação de segurança nas configurações do Chrome</translation>
<translation id="2726001110728089263">Bandeja lateral</translation>
@@ -583,6 +613,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="2850739647070081192">Convite (Envelope)</translation>
<translation id="2856444702002559011">Invasores podem estar tentando roubar suas informações de <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (por exemplo, senhas, mensagens ou cartões de crédito). <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">Neste site, há exibição de anúncios invasivos ou enganosos</translation>
+<translation id="286512204874376891">O cartão virtual mascara o real para proteger você contra possíveis tentativas de fraude. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">Amigável</translation>
<translation id="2876489322757410363">Saindo do modo de navegação anônima para pagar usando um aplicativo externo. Continuar?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />. Pressione Tab e depois Enter para gerenciar o Navegação segura e muito mais nas configurações do Chrome</translation>
@@ -607,6 +638,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="2930577230479659665">Cortar depois de cada cópia</translation>
<translation id="2932085390869194046">Sugerir senha…</translation>
<translation id="2934466151127459956">Government Letter</translation>
+<translation id="2938225289965773019">Abrir links de <ph name="PROTOCOL" /></translation>
<translation id="2941952326391522266">Este servidor não conseguiu provar que é <ph name="DOMAIN" />. O certificado de segurança é de <ph name="DOMAIN2" />. Isso pode ser causado por uma configuração incorreta ou pela interceptação da sua conexão por um invasor.</translation>
<translation id="2943895734390379394">Tempo de upload:</translation>
<translation id="2948083400971632585">Na página "Configurações", você pode desativar quaisquer proxies configurados para uma conexão.</translation>
@@ -639,6 +671,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="3037605927509011580">Ah, não!</translation>
<translation id="3041612393474885105">Informações do certificado</translation>
<translation id="3044034790304486808">Retomar sua pesquisa</translation>
+<translation id="305162504811187366">o histórico da Ãrea de trabalho remota do Google Chrome, incluindo carimbos de data/hora, hosts e IDs de sessões de clientes.</translation>
<translation id="3060227939791841287">C9 (Envelope)</translation>
<translation id="3061707000357573562">Aplicar patch ao serviço</translation>
<translation id="306573536155379004">Jogo iniciado.</translation>
@@ -679,6 +712,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="3197136577151645743">Pode pedir para saber quando você está usando o dispositivo ativamente</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />. Pressione "Tab" e "Enter" para gerenciar quais informações são sincronizadas nas configurações do Chrome</translation>
<translation id="320323717674993345">Cancelar pagamento</translation>
+<translation id="3203366800380907218">Da Web</translation>
<translation id="3207960819495026254">Adicionado aos favoritos</translation>
<translation id="3209034400446768650">Esta página pode emitir cobranças em dinheiro</translation>
<translation id="3212581601480735796">Sua atividade em <ph name="HOSTNAME" /> está sendo monitorada</translation>
@@ -695,10 +729,12 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="3234666976984236645">Sempre detectar conteúdo importante neste site</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />. Pressione Tab e depois Enter para personalizar a aparência do navegador</translation>
<translation id="3240791268468473923">A página de credenciais para pagamento seguro sem correspondência está aberta</translation>
+<translation id="324180406144491771">Os links de “<ph name="HOST_NAME" />†são bloqueados</translation>
<translation id="3249845759089040423">Maravilhoso</translation>
<translation id="3252266817569339921">Francês</translation>
<translation id="3257954757204451555">Quem está por trás dessa informação?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />. Pressione Tab e depois Enter para criar rapidamente um novo evento no Google Agenda</translation>
+<translation id="3261488570342242926">Saiba mais sobre cartões virtuais</translation>
<translation id="3264837738038045344">Botão "Gerenciar configurações do Chrome". Pressione Enter para acessar as configurações do Chrome</translation>
<translation id="3266793032086590337">Valor (conflitante)</translation>
<translation id="3268451620468152448">Guias abertas</translation>
@@ -712,6 +748,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="3288238092761586174"><ph name="URL" /> poderá realizar outras etapas para verificar seu pagamento</translation>
<translation id="3293642807462928945">Saiba mais sobre a política <ph name="POLICY_NAME" /></translation>
<translation id="3295444047715739395">Veja e gerencie suas senhas nas configurações do Chrome</translation>
+<translation id="3303795387212510132">Permitir que o app abra links <ph name="PROTOCOL_SCHEME" />?</translation>
<translation id="3303855915957856445">Nenhum resultado de pesquisa encontrado</translation>
<translation id="3304073249511302126">verificação de Bluetooth</translation>
<translation id="3308006649705061278">Unidade organizacional (OU)</translation>
@@ -725,12 +762,6 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="3345782426586609320">Olhos</translation>
<translation id="3355823806454867987">Alterar configurações de proxy...</translation>
<translation id="3360103848165129075">Página do gerenciador de pagamento</translation>
-<translation id="3361596688432910856">O Chrome <ph name="BEGIN_EMPHASIS" />não salvará<ph name="END_EMPHASIS" /> as seguintes informações:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />seu histórico de navegação
- <ph name="LIST_ITEM" />cookies e dados de sites
- <ph name="LIST_ITEM" />informações fornecidas em formulários
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">Esta política foi copiada automaticamente da política <ph name="OLD_POLICY" /> obsoleta. Use esta política.</translation>
<translation id="3364869320075768271"><ph name="URL" /> quer usar seus dispositivos e dados de realidade virtual</translation>
<translation id="3366477098757335611">Ver cartões</translation>
@@ -813,7 +844,6 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="3587738293690942763">Meio</translation>
<translation id="3592413004129370115">Italian (Envelope)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{Você pode redefinir o grupo a qualquer momento. Leva cerca de um dia para fazer parte de um novo grupo.}=1{Você pode redefinir o grupo a qualquer momento. Leva cerca de um dia para fazer parte de um novo grupo.}one{Você pode redefinir o grupo a qualquer momento. Leva {NUM_DAYS} dia para fazer parte de um novo grupo.}other{Você pode redefinir o grupo a qualquer momento. Leva {NUM_DAYS} dias para fazer parte de um novo grupo.}}</translation>
-<translation id="3596012367874587041">Configurações do app</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">Aplicativo bloqueado pelo administrador</translation>
<translation id="3608932978122581043">Fornecer orientação</translation>
@@ -822,7 +852,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="361438452008624280">Entrada "<ph name="LANGUAGE_ID" />": idioma desconhecido ou não compatível.</translation>
<translation id="3614934205542186002"><ph name="RUN_CHROME_SAFETY_CHECK_FOCUSED_FRIENDLY_MATCH_TEXT" />. Pressione Tab e depois Enter para executar a confirmação de segurança nas configurações do Chrome</translation>
<translation id="3615877443314183785">Informe uma data de validade válida</translation>
-<translation id="36224234498066874">Limpar dados de navegação...</translation>
+<translation id="36224234498066874">Remover dados de navegação...</translation>
<translation id="362276910939193118">Mostrar histórico completo</translation>
<translation id="3630155396527302611">Se ele já estiver listado como um programa que tem permissão para acessar a rede, tente
removê-lo da lista e adicioná-lo novamente.</translation>
@@ -856,6 +886,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="370972442370243704">Ativar as jornadas</translation>
<translation id="3711895659073496551">Suspender</translation>
<translation id="3712624925041724820">Licenças esgotadas</translation>
+<translation id="3714633008798122362">agenda na web</translation>
<translation id="3714780639079136834">Ativar os dados da rede celular ou o Wi-Fi</translation>
<translation id="3715597595485130451">Conectar ao Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Verificar a configuração de DNS, proxy e firewall<ph name="END_LINK" /></translation>
@@ -917,6 +948,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="3906954721959377182">Tablet</translation>
<translation id="3909477809443608991">Solicitação para reproduzir conteúdo protegido feita por <ph name="URL" />. A identidade do seu dispositivo será verificada pelo Google e poderá ser acessada por esse site.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">Negar</translation>
<translation id="3939773374150895049">Usar WebAuthn em vez de CVC?</translation>
<translation id="3946209740501886391">Sempre perguntar neste site</translation>
<translation id="3947595700203588284">Pode pedir para se conectar a dispositivos MIDI</translation>
@@ -937,6 +969,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="3987940399970879459">Menos de 1 MB</translation>
<translation id="3990250421422698716">Ajustar desvio</translation>
<translation id="3996311196211510766">O site <ph name="ORIGIN" /> solicitou que uma política de origem seja aplicada a todas as solicitações feitas a ele, mas não é possível aplicá-la no momento.</translation>
+<translation id="4009243425692662128">O conteúdo das páginas que você imprime é enviado ao Google Cloud ou a terceiros para análise. Por exemplo, ele pode ser verificado em busca de dados sensíveis.</translation>
<translation id="4010758435855888356">Permitir acesso ao armazenamento?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{Documento PDF com {COUNT} página}one{Documento PDF com {COUNT} página}other{Documento PDF com {COUNT} páginas}}</translation>
<translation id="4023431997072828269">Como o formulário é enviado por uma conexão que não é segura, suas informações ficarão visíveis para outras pessoas.</translation>
@@ -1027,6 +1060,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="4250680216510889253">Não</translation>
<translation id="4253168017788158739">Nota</translation>
<translation id="425582637250725228">É possível que as alterações feitas não sejam salvas.</translation>
+<translation id="425869179292622354">Aumentar a segurança com um cartão virtual?</translation>
<translation id="4258748452823770588">Assinatura inválida</translation>
<translation id="4261046003697461417">Não é possível fazer anotações em documentos protegidos</translation>
<translation id="4265872034478892965">Permitido pelo administrador</translation>
@@ -1089,6 +1123,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="4434045419905280838">Pop-ups e redirecionamentos</translation>
<translation id="4435702339979719576">Postal</translation>
<translation id="443673843213245140">O uso de um proxy está desativado, mas uma configuração explícita de proxy é especificada.</translation>
+<translation id="4441832193888514600">Ignorada porque a política só pode ser definida como uma política do usuário em nuvem.</translation>
<translation id="4450893287417543264">Não mostrar novamente</translation>
<translation id="4451135742916150903">Pode pedir para se conectar a dispositivos HID</translation>
<translation id="4452328064229197696">A senha que você usou foi encontrada em uma violação de dados. Para proteger suas contas, o Gerenciador de senhas do Google recomenda que você revise suas senhas salvas.</translation>
@@ -1144,6 +1179,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="4628948037717959914">Foto</translation>
<translation id="4631649115723685955">Reembolso vinculado</translation>
<translation id="4636930964841734540">Informações</translation>
+<translation id="4638670630777875591">Navegação anônima no Chromium</translation>
<translation id="464342062220857295">Recursos de pesquisa</translation>
<translation id="4644670975240021822">Ordem reversa virada para baixo</translation>
<translation id="4646534391647090355">Acessar agora</translation>
@@ -1164,6 +1200,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="4708268264240856090">A conexão foi interrompida</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Executar o Diagnóstico de Rede do Windows<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426">Senha para <ph name="USERNAME" /></translation>
<translation id="4724144314178270921">Pode pedir para acessar texto e imagens na sua área de transferência</translation>
<translation id="4726672564094551039">Atualizar políticas</translation>
<translation id="4728558894243024398">Plataforma</translation>
@@ -1185,6 +1222,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="4757993714154412917">Você acabou de digitar sua senha em um site suspeito. Para proteger suas contas, o Chromium recomenda conferir as senhas salvas.</translation>
<translation id="4758311279753947758">Adicionar dados de contato</translation>
<translation id="4761104368405085019">Usar microfone</translation>
+<translation id="4761869838909035636">Executar a confirmação de segurança do Chrome</translation>
<translation id="4764776831041365478">A página <ph name="URL" /> pode estar temporariamente indisponível ou pode ter sido movida permanentemente para um novo endereço da Web.</translation>
<translation id="4766713847338118463">Dois grampos na parte inferior</translation>
<translation id="4771973620359291008">Ocorreu um erro desconhecido.</translation>
@@ -1205,29 +1243,23 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="4819347708020428563">Editar anotações na visualização padrão?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />. Pressione Tab e depois Enter para criar rapidamente um novo arquivo do Planilhas Google</translation>
<translation id="4825507807291741242">Intenso</translation>
-<translation id="4827402517081186284">Com a navegação anônima, você não fica invisível on-line.
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Sites sabem quando você os acessa<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Empregadores ou escolas podem rastrear a navegação<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Provedores de acesso à Internet podem monitorar o tráfego na Internet<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">Ativar avisos</translation>
<translation id="4838327282952368871">Sonho</translation>
<translation id="4840250757394056958">Ver seu histórico do Chrome</translation>
<translation id="484462545196658690">Automática</translation>
<translation id="4849865131988503897">Verificação de precisão</translation>
-<translation id="4850886885716139402">Visualizar</translation>
+<translation id="4850886885716139402">Ver</translation>
<translation id="485316830061041779">Alemão</translation>
<translation id="4853901935952445031">Este site não poderá usar a API U2F depois de fevereiro de 2022. Se o site for seu, faça mudanças para que ele use a API Web Authentication.</translation>
<translation id="4854362297993841467">Esse método de entrega não está disponível. Tente um método diferente.</translation>
<translation id="4854853140771946034">Criar rapidamente uma nova nota no Google Keep</translation>
<translation id="485902285759009870">Confirmando código...</translation>
+<translation id="4866506163384898554">Pressione |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| para mostrar o cursor</translation>
<translation id="4876188919622883022">Visualização simplificada</translation>
<translation id="4876305945144899064">Sem nome de usuário</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{Nenhuma}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}one{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831">Pesquisa sobre <ph name="TEXT" /></translation>
<translation id="4879491255372875719">Automático (padrão)</translation>
-<translation id="4879725228911483934">abrir e posicionar janelas nas suas telas.</translation>
<translation id="4880827082731008257">Histórico de pesquisa</translation>
<translation id="4881695831933465202">Abrir</translation>
<translation id="4885256590493466218">Pague com <ph name="CARD_DETAIL" /> na finalização da compra</translation>
@@ -1236,6 +1268,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">Nono rolo</translation>
<translation id="4901778704868714008">Salvar…</translation>
+<translation id="4905659621780993806">O administrador vai reiniciar seu dispositivo automaticamente em <ph name="DATE" />, <ph name="TIME" />. Salve os itens abertos antes que o dispositivo seja reiniciado.</translation>
<translation id="4913987521957242411">Perfuração na parte superior esquerda</translation>
<translation id="4918221908152712722">Instale o <ph name="APP_NAME" /> (nenhum download é necessário)</translation>
<translation id="4923459931733593730">Pagamento</translation>
@@ -1244,6 +1277,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />. Pressione "Tab" e "Enter" para pesquisar</translation>
<translation id="4930153903256238152">Grande capacidade</translation>
+<translation id="4940163644868678279">Navegação anônima no Chrome</translation>
<translation id="4943872375798546930">Nenhum resultado</translation>
<translation id="4950898438188848926">Botão de alternância de guia. Pressione Enter para alternar para a guia aberta, <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="495170559598752135">Ações</translation>
@@ -1253,6 +1287,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="4968522289500246572">Este app foi criado para dispositivos móveis e pode não ser redimensionado corretamente. Pode haver erros ou talvez o app seja reiniciado.</translation>
<translation id="4969341057194253438">Excluir gravação</translation>
<translation id="4973922308112707173">Perfuração dupla na parte superior</translation>
+<translation id="4976702386844183910">Última visita: <ph name="DATE" /></translation>
<translation id="4984088539114770594">Usar o microfone?</translation>
<translation id="4984339528288761049">Prc5 (Envelope)</translation>
<translation id="4989163558385430922">Ver tudo</translation>
@@ -1314,6 +1349,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="5138227688689900538">Mostrar menos</translation>
<translation id="5145883236150621069">Código de erro presente na resposta da política</translation>
<translation id="5146995429444047494">As notificações de <ph name="ORIGIN" /> estão bloqueadas</translation>
+<translation id="514704532284964975"><ph name="URL" /> quer ver e mudar informações em dispositivos NFC que você toca com seu smartphone</translation>
<translation id="5148809049217731050">Virada para cima</translation>
<translation id="515292512908731282">C4 (Envelope)</translation>
<translation id="5158275234811857234">Capa</translation>
@@ -1338,6 +1374,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="5215116848420601511">Formas de pagamento e endereços que usam o Google Pay</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">Bandeja 13</translation>
+<translation id="5216942107514965959">Última visita: hoje</translation>
<translation id="5222812217790122047">E-mail obrigatório</translation>
<translation id="5230733896359313003">Endereço de entrega</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1358,7 +1395,6 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">Propriedades do documento</translation>
<translation id="528468243742722775">Fim</translation>
-<translation id="5284909709419567258">Endereços de rede</translation>
<translation id="5285570108065881030">Mostrar todas as senhas salvas</translation>
<translation id="5287240709317226393">Mostrar cookies</translation>
<translation id="5287456746628258573">Este site usa uma configuração de segurança desatualizada que pode expor suas informações, como senhas ou números de cartão de crédito, quando elas forem enviadas para o site.</translation>
@@ -1400,7 +1436,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="5400836586163650660">Cinza</translation>
<translation id="540969355065856584">Este servidor não conseguiu provar que é <ph name="DOMAIN" />. O certificado de segurança dele não é válido no momento. Isso pode ser causado por uma configuração incorreta ou pela interceptação da sua conexão por um invasor.</translation>
<translation id="541416427766103491">Empilhador 4</translation>
-<translation id="5421136146218899937">Limpar dados de navegação...</translation>
+<translation id="5421136146218899937">Remover dados de navegação...</translation>
<translation id="5426179911063097041"><ph name="SITE" /> quer enviar notificações a você</translation>
<translation id="5428105026674456456">Espanhol</translation>
<translation id="5430298929874300616">Remover favorito</translation>
@@ -1431,7 +1467,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="5523118979700054094">Nome da política</translation>
<translation id="55293785478302737">Costurar borda</translation>
<translation id="553484882784876924">Prc6 (Envelope)</translation>
-<translation id="5535133333442455806">Botão "Limpar dados de navegação". Pressione "Enter" para limpar o histórico de navegação, os cookies, o cache e muito mais nas configurações do Chrome</translation>
+<translation id="5535133333442455806">Botão "Remover dados de navegação". Pressione "Enter" para limpar o histórico de navegação, os cookies, o cache e muito mais nas configurações do Chrome</translation>
<translation id="5536214594743852365">Mostrar a seção "<ph name="SECTION" />"</translation>
<translation id="5539243836947087108">Raft</translation>
<translation id="5540224163453853">Não foi possível encontrar o artigo solicitado.</translation>
@@ -1442,6 +1478,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="5556459405103347317">Recarregar</translation>
<translation id="5560088892362098740">Data de validade</translation>
<translation id="55635442646131152">Visualização do documento</translation>
+<translation id="5565613213060953222">Abrir guia anônima</translation>
<translation id="5565735124758917034">Ativo</translation>
<translation id="5570825185877910964">Proteger conta</translation>
<translation id="5571083550517324815">Não é possível fazer a retirada nesse endereço. Tente um endereço diferente.</translation>
@@ -1524,6 +1561,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="5869522115854928033">Senhas salvas</translation>
<translation id="5873013647450402046">O banco precisa confirmar sua identidade.</translation>
<translation id="5887400589839399685">Cartão salvo</translation>
+<translation id="5887687176710214216">Última visita: ontem</translation>
<translation id="5895138241574237353">Reiniciar</translation>
<translation id="5895187275912066135">Emitido em</translation>
<translation id="5901630391730855834">Amarelo</translation>
@@ -1537,6 +1575,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="5921639886840618607">Salvar cartão na Conta do Google?</translation>
<translation id="5922853866070715753">Quase pronto</translation>
<translation id="5932224571077948991">No site, há exibição de anúncios invasivos ou enganosos</translation>
+<translation id="5938153366081463283">Adicionar cartão virtual</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347">Abrindo <ph name="SITE_NAME" />…</translation>
<translation id="5951495562196540101">Não é possível fazer a inscrição com a conta pessoal (pacote de licença disponível).</translation>
@@ -1601,6 +1640,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="6120179357481664955">Lembrar código da UPI?</translation>
<translation id="6124432979022149706">Conectores do Chrome Enterprise</translation>
<translation id="6127379762771434464">Item removido</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Saiba mais sobre a navegação anônima no Chrome<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">Verifique todos os cabos e reinicie todos os roteadores, modens ou outros
dispositivos de rede que você estiver usando.</translation>
<translation id="614940544461990577">Tente:</translation>
@@ -1613,7 +1653,6 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="6169916984152623906">Agora você pode navegar com privacidade. Outras pessoas que usarem este dispositivo não verão sua atividade, mas os downloads e favoritos serão salvos.</translation>
<translation id="6177128806592000436">Sua conexão com esse site não é segura</translation>
<translation id="6180316780098470077">Intervalo entre novas tentativas</translation>
-<translation id="619448280891863779">Pode pedir para abrir e posicionar janelas nas suas telas</translation>
<translation id="6196640612572343990">Bloquear cookies de terceiros</translation>
<translation id="6203231073485539293">Verifique sua conexão com a Internet</translation>
<translation id="6218753634732582820">Remover endereço do Chromium?</translation>
@@ -1636,7 +1675,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="6272383483618007430">Google Update</translation>
<translation id="6276112860590028508">As páginas da sua lista de leitura são exibidas aqui</translation>
<translation id="627746635834430766">Para agilizar o pagamento na próxima vez, salve o cartão e o endereço de faturamento na sua Conta do Google.</translation>
-<translation id="6279098320682980337">O número do cartão virtual não foi preenchido? Clique nos detalhes do cartão para copiar</translation>
+<translation id="6279183038361895380">Pressione |<ph name="ACCELERATOR" />| para exibir seu cursor</translation>
<translation id="6280223929691119688">Não é possível entregar nesse endereço. Selecione um endereço diferente.</translation>
<translation id="6282194474023008486">CEP</translation>
<translation id="6285507000506177184">Botão "Gerenciar downloads no Chrome". Pressione Enter para gerenciar os arquivos transferidos por download no Chrome</translation>
@@ -1644,6 +1683,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="6290238015253830360">Os artigos sugeridos aparecerão aqui</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{Seu dispositivo será reiniciado agora}=1{Seu dispositivo será reiniciado em 1 segundo}one{Seu dispositivo será reiniciado em # segundo}other{Seu dispositivo será reiniciado em # segundos}}</translation>
<translation id="6302269476990306341">Parando o Google Assistente no Chrome</translation>
<translation id="6305205051461490394">Não é possível acessar <ph name="URL" />.</translation>
<translation id="6312113039770857350">Página da Web não disponível</translation>
@@ -1717,6 +1757,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="6529602333819889595">&amp;Refazer excluir</translation>
<translation id="6545864417968258051">Verificação de Bluetooth</translation>
<translation id="6547208576736763147">Perfuração dupla no lado esquerdo</translation>
+<translation id="6554732001434021288">Última visita: <ph name="NUM_DAYS" /> dias atrás</translation>
<translation id="6556866813142980365">Refazer</translation>
<translation id="6569060085658103619">Você está vendo uma página de extensões</translation>
<translation id="6573200754375280815">Perfuração dupla no lado direito</translation>
@@ -1751,7 +1792,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="6663846344464066639">Mãos juntas</translation>
<translation id="6665553082534466207">Perfuração tripla no lado direito</translation>
<translation id="6671697161687535275">Remover sugestão de formulário do Chromium?</translation>
-<translation id="6685834062052613830">Saia e conclua a configuração</translation>
+<translation id="6685834062052613830">Saia e termine a configuração</translation>
<translation id="6687335167692595844">Tamanho da fonte solicitado</translation>
<translation id="6688743156324860098">Atualizar…</translation>
<translation id="6688775486821967877">O cartão virtual não está disponível no momento. Tente novamente mais tarde</translation>
@@ -1777,7 +1818,6 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="6757797048963528358">O dispositivo entrou em modo de suspensão.</translation>
<translation id="6767985426384634228">Atualizar endereço?</translation>
<translation id="6768213884286397650">Hagaki (Postal)</translation>
-<translation id="6774185088257932239"><ph name="BEGIN_LINK" />Saiba mais<ph name="END_LINK" /> sobre a navegação anônima</translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">Violeta</translation>
<translation id="6786747875388722282">Extensões</translation>
@@ -1861,7 +1901,6 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="706295145388601875">Adicione e gerencie endereços nas configurações do Chrome</translation>
<translation id="7064851114919012435">Dados de contato</translation>
<translation id="7068733155164172741">Insira o código de <ph name="OTP_LENGTH" /> dígitos</translation>
-<translation id="7070090581017165256">Sobre este site</translation>
<translation id="70705239631109039">Sua conexão não é totalmente segura</translation>
<translation id="7075452647191940183">A solicitação é muito grande</translation>
<translation id="7079718277001814089">Este site contém malware</translation>
@@ -1878,6 +1917,12 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="7111012039238467737">(válido)</translation>
<translation id="7118618213916969306">Pesquisa o URL da área de transferência, <ph name="SHORT_URL" /></translation>
<translation id="7119414471315195487">Fechar outras guias ou programas</translation>
+<translation id="7129355289156517987">Ao fechar todas as guias anônimas do Chromium, suas atividades nelas vão ser apagadas deste dispositivo:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Atividade de navegação<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Histórico de pesquisa<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" /><ph name="END_LIST_ITEM" />Informações inseridas em formulários
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">Não é possível enviar para esse endereço. Selecione um endereço diferente.</translation>
<translation id="7132939140423847331">O administrador bloqueou a cópia destes dados.</translation>
<translation id="7135130955892390533">Mostrar status</translation>
@@ -1900,6 +1945,7 @@ Se não fizer isso, a permissão será bloqueada pelas configurações de privac
<translation id="7192203810768312527">Libera <ph name="SIZE" />. O carregamento de alguns sites pode ficar mais lento no seu próximo acesso.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">O administrador pode ver:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />: pressione "Tab" e depois "Enter" para abrir uma nova guia anônima e navegar com privacidade</translation>
<translation id="7202346780273620635">Letter Extra</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> não adere aos padrões de segurança.</translation>
<translation id="7210993021468939304">A atividade do Linux no contêiner, bem como instalar e executar apps do Linux no contêiner</translation>
@@ -1931,6 +1977,7 @@ Mais detalhes:
<translation id="7304562222803846232">Gerenciar configurações de privacidade da Conta do Google</translation>
<translation id="7305756307268530424">Iniciar mais devagar</translation>
<translation id="7308436126008021607">sincronização em segundo plano</translation>
+<translation id="7310392214323165548">O dispositivo será reiniciado em breve</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">Ajuda de conexão</translation>
<translation id="7323804146520582233">Ocultar a seção "<ph name="SECTION" />"</translation>
@@ -1938,6 +1985,7 @@ Mais detalhes:
<translation id="7334320624316649418">&amp;Refazer reordenar</translation>
<translation id="7335157162773372339">Pode pedir para usar a câmera</translation>
<translation id="7337248890521463931">Mostrar mais linhas</translation>
+<translation id="7337418456231055214">O número do cartão virtual não foi preenchido? Clique nos detalhes do cartão para copiar. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">Não está disponível na sua plataforma.</translation>
<translation id="733923710415886693">O certificado do servidor não foi divulgado por meio da Transparência dos certificados.</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1960,6 +2008,7 @@ Mais detalhes:
<translation id="7378627244592794276">Não</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">Não aplicável</translation>
+<translation id="7388594495505979117">{0,plural, =1{Seu dispositivo será reiniciado em 1 minuto}one{Seu dispositivo será reiniciado em # minuto}other{Seu dispositivo será reiniciado em # minutos}}</translation>
<translation id="7390545607259442187">Confirmar cartão</translation>
<translation id="7392089738299859607">Atualizar endereço</translation>
<translation id="7399802613464275309">Confirmação de segurança</translation>
@@ -1996,6 +2045,12 @@ Mais detalhes:
<translation id="7485870689360869515">Nenhum dado encontrado</translation>
<translation id="7495528107193238112">Este conteúdo está bloqueado. Entre em contato com o proprietário do site para corrigir o problema.</translation>
<translation id="7497998058912824456">Botão para criar um documento. Pressione Enter para criar rapidamente um novo arquivo do Documentos Google</translation>
+<translation id="7506488012654002225">O Chromium <ph name="BEGIN_EMPHASIS" />não vai salvar<ph name="END_EMPHASIS" /> estas informações:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Seu histórico de navegação
+ <ph name="LIST_ITEM" />Cookies e dados de sites
+ <ph name="LIST_ITEM" />Informações inseridas em formulários
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">O código do dispositivo da política retornado está em branco ou não corresponde ao código do dispositivo atual</translation>
<translation id="7508870219247277067">Verde-abacate</translation>
<translation id="7511955381719512146">O Wi-Fi que você está usando pode exigir a visita a <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
@@ -2109,7 +2164,6 @@ Mais detalhes:
<translation id="7813600968533626083">Remover sugestão de formulário do Chrome?</translation>
<translation id="781440967107097262">Compartilhar área de transferência?</translation>
<translation id="7815407501681723534">Localizados <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> para "<ph name="SEARCH_STRING" />"</translation>
-<translation id="782125616001965242">Mostrar informações sobre este site</translation>
<translation id="782886543891417279">O Wi-Fi que você está usando (<ph name="WIFI_NAME" />) pode exigir a visita a uma página de login.</translation>
<translation id="7836231406687464395">Postfix (Envelope)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{Nenhum}=1{1 app (<ph name="EXAMPLE_APP_1" />)}=2{2 apps (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}one{# app (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" /> <ph name="AND_MORE" />)}other{# apps (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" /> <ph name="AND_MORE" />)}}</translation>
@@ -2126,7 +2180,6 @@ Mais detalhes:
<translation id="7888575728750733395">Intent de renderização da impressão</translation>
<translation id="7894280532028510793">Se o endereço estiver correto, <ph name="BEGIN_LINK" />tente executar o Diagnóstico de Rede<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (Envelope)</translation>
-<translation id="7931318309563332511">Desconhecido</translation>
<translation id="793209273132572360">Atualizar endereço?</translation>
<translation id="7932579305932748336">Revestir</translation>
<translation id="79338296614623784">Informe um número de telefone válido</translation>
@@ -2146,23 +2199,24 @@ Mais detalhes:
<translation id="7962467575542381659">Computador da plataforma</translation>
<translation id="7966803981046576691">Tipo de conta da tarefa</translation>
<translation id="79682505114836835">O valor "<ph name="VALUE" />" é uma cor hexadecimal inválida.</translation>
-<translation id="7968982339740310781">Visualizar detalhes</translation>
+<translation id="7968982339740310781">Ver detalhes</translation>
<translation id="7970392640816874403">O que outras fontes dizem?</translation>
<translation id="7976214039405368314">Excesso de solicitações</translation>
<translation id="7977538094055660992">Dispositivo de saída</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">Vinculado ao</translation>
<translation id="798134797138789862">Pode pedir para usar dispositivos e dados de realidade virtual</translation>
<translation id="7984945080620862648">Não é possível acessar <ph name="SITE" /> no momento, porque o website enviou credenciais codificadas que o Google Chrome não pode processar. Ataques e erros de rede geralmente são temporários. Portanto, essa página provavelmente funcionará mais tarde.</translation>
-<translation id="79859296434321399">Para ver conteúdo de realidade aumentada, instale o ARCore</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">Encadernar</translation>
<translation id="7992044431894087211">O compartilhamento de tela com <ph name="APPLICATION_TITLE" /> foi retomado</translation>
<translation id="7995512525968007366">Não especificado</translation>
+<translation id="7998269595945679889">Botão "Abrir guia anônima": pressione "Enter" para abrir uma nova guia anônima e navegar com privacidade</translation>
<translation id="800218591365569300">Tente fechar outras guias ou programas para liberar memória.</translation>
<translation id="8004582292198964060">Navegador</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{Este cartão e o endereço de faturamento dele serão salvos. Você poderá usá-lo quando a conta <ph name="USER_EMAIL" /> estiver conectada.}one{Este cartão e o endereço de faturamento dele serão salvos. Você poderá usá-lo quando a conta <ph name="USER_EMAIL" /> estiver conectada.}other{Estes cartões e os endereços de faturamento deles serão salvos. Você poderá usá-los quando a conta <ph name="USER_EMAIL" /> estiver conectada.}}</translation>
<translation id="8025119109950072390">Invasores nesse site podem induzir você a fazer algo perigoso, como instalar um software ou revelar suas informações pessoais (por exemplo, senhas, números de telefone ou cartões de crédito).</translation>
-<translation id="8026334261755873520">Limpar dados de navegação</translation>
+<translation id="8026334261755873520">Remover dados de navegação</translation>
<translation id="8027077570865220386">Bandeja 15</translation>
<translation id="8028698320761417183"><ph name="CREATE_GOOGLE_FORM_FOCUSED_FRIENDLY_MATCH_TEXT" />. Pressione Tab e depois Enter para criar rapidamente um novo arquivo no Formulários Google</translation>
<translation id="8028960012888758725">Cortar ao término da impressão</translation>
@@ -2217,6 +2271,7 @@ Mais detalhes:
<translation id="8202370299023114387">Conflito</translation>
<translation id="8206978196348664717">Prc4 (Envelope)</translation>
<translation id="8211406090763984747">A conexão é segura</translation>
+<translation id="8217240300496046857">Os sites não podem usar cookies que rastreiem você pela Web. Os recursos de alguns sites podem falhar.</translation>
<translation id="8218327578424803826">Local designado:</translation>
<translation id="8220146938470311105">C7/C6 (Envelope)</translation>
<translation id="8225771182978767009">A pessoa que configurou este computador optou por bloquear esse site.</translation>
@@ -2257,14 +2312,9 @@ Mais detalhes:
<translation id="830498451218851433">Dobra simples</translation>
<translation id="8307358339886459768">Small photo</translation>
<translation id="8307888238279532626">Os apps instalados e a frequência de uso deles</translation>
+<translation id="8317207217658302555">Atualizar o ARCore?</translation>
<translation id="831997045666694187">Noite</translation>
<translation id="8321476692217554900">notificações</translation>
-<translation id="8328484624016508118">Após o fechamento de todas as guias anônimas, o Chrome apaga:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Sua atividade de navegação no dispositivo<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Seu histórico de pesquisa no dispositivo<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />As informações digitadas em formulários<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489">O acesso a <ph name="HOST_NAME" /> foi negado</translation>
<translation id="833262891116910667">Destacar</translation>
<translation id="8339163506404995330">Páginas em <ph name="LANGUAGE" /> não serão traduzidas</translation>
@@ -2316,6 +2366,7 @@ Mais detalhes:
<translation id="8507227106804027148">Linha de comando</translation>
<translation id="8508648098325802031">Ãcone de pesquisa</translation>
<translation id="8511402995811232419">Gerenciar cookies</translation>
+<translation id="8519753333133776369">Dispositivo HID permitido pelo administrador</translation>
<translation id="8522552481199248698">No Chrome, você pode receber ajuda para proteger sua Conta do Google e alterar sua senha.</translation>
<translation id="8530813470445476232">Limpe o histórico de navegação, os cookies, o cache e muito mais nas configurações do Chrome</translation>
<translation id="8533619373899488139">Visite &lt;strong&gt;chrome://policy&lt;/strong&gt; para ver a lista de URLs bloqueados e outras políticas aplicadas pelo administrador do seu sistema.</translation>
@@ -2327,7 +2378,6 @@ Mais detalhes:
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{Redefinir permissão}one{Redefinir permissão}other{Redefinir permissões}}</translation>
<translation id="8555010941760982128">Use este código ao finalizar a compra</translation>
<translation id="8557066899867184262">O CVC está localizado atrás do seu cartão.</translation>
-<translation id="8558485628462305855">Para ver conteúdo de realidade aumentada, atualize o ARCore</translation>
<translation id="8559762987265718583">Não é possível estabelecer uma conexão privada com <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />, porque a data e a hora do seu dispositivo (<ph name="DATE_AND_TIME" />) estão incorretas.</translation>
<translation id="8564182942834072828">Documentos separados/Cópias não reunidas</translation>
<translation id="8564985650692024650">O Chromium recomenda redefinir sua senha de <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> se você a reutilizou em outros sites.</translation>
@@ -2347,6 +2397,7 @@ Mais detalhes:
<translation id="865032292777205197">sensores de movimento</translation>
<translation id="8663226718884576429">Resumo do pedido, <ph name="TOTAL_LABEL" />, Mais detalhes</translation>
<translation id="8666678546361132282">Inglês</translation>
+<translation id="8669306706049782872">usar as informações das suas telas para abrir e posicionar janelas.</translation>
<translation id="867224526087042813">Assinatura</translation>
<translation id="8676424191133491403">Sem atraso</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, resposta, <ph name="ANSWER" /></translation>
@@ -2373,6 +2424,7 @@ Mais detalhes:
<translation id="8731544501227493793">Botão "Gerenciar senhas". Pressione "Enter" para ver e gerenciar suas senhas nas configurações do Chrome</translation>
<translation id="8734529307927223492">Seu <ph name="DEVICE_TYPE" /> é gerenciado por <ph name="MANAGER" /></translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />. Pressione "Tab" e depois "Enter" para abrir uma nova janela anônima e navegar com privacidade</translation>
+<translation id="8737685506611670901">Abrir links de <ph name="PROTOCOL" /> em vez de <ph name="REPLACED_HANDLER_TITLE" /></translation>
<translation id="8738058698779197622">Para estabelecer uma conexão segura, o relógio precisa ser ajustado corretamente. Isso ocorre porque os certificados que os websites usam para se identificar são válidos apenas por períodos específicos. Como o relógio do seu dispositivo está incorreto, o Chromium não pode verificar esses certificados.</translation>
<translation id="8740359287975076522">Não foi possível encontrar o &lt;abbr id="dnsDefinition"&gt;endereço DNS&lt;/abbr&gt; de <ph name="HOST_NAME" />. Diagnosticando o problema.</translation>
<translation id="8742371904523228557"><ph name="ONE_TIME_CODE" /> é seu código para <ph name="ORIGIN" /></translation>
@@ -2400,6 +2452,7 @@ Mais detalhes:
<translation id="883848425547221593">Outros favoritos</translation>
<translation id="884264119367021077">Endereço de entrega</translation>
<translation id="884923133447025588">Nenhum mecanismo de revogação encontrado.</translation>
+<translation id="8849262850971482943">Use seu cartão virtual para aumentar a segurança</translation>
<translation id="885730110891505394">Compartilhar com o Google</translation>
<translation id="8858065207712248076">O Chrome recomenda redefinir sua senha de <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> se você a reutilizou em outros sites.</translation>
<translation id="885906927438988819">Se o endereço estiver correto, <ph name="BEGIN_LINK" />tente executar o Diagnóstico de Rede do Windows<ph name="END_LINK" />.</translation>
@@ -2449,6 +2502,7 @@ Mais detalhes:
<translation id="9004367719664099443">Sessão de RV em andamento</translation>
<translation id="9005998258318286617">Falha ao carregar documento PDF.</translation>
<translation id="9008201768610948239">Ignorar</translation>
+<translation id="901834265349196618">e-mail</translation>
<translation id="9020200922353704812">O endereço de cobrança do cartão é obrigatório</translation>
<translation id="9020542370529661692">Esta página foi traduzida para <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9020742383383852663">A8</translation>
@@ -2498,6 +2552,7 @@ incomuns e incorretas. Isso pode acontecer quando um invasor está fingindo ser
<translation id="9150045010208374699">Usar câmera</translation>
<translation id="9150685862434908345">O administrador pode mudar as configurações do navegador remotamente. A atividade deste dispositivo também pode ser gerenciada fora do Chrome. <ph name="BEGIN_LINK" />Saiba mais<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">Atualizado</translation>
+<translation id="9155211586651734179">Periféricos de áudio conectados</translation>
<translation id="9157595877708044936">Configurando...</translation>
<translation id="9158625974267017556">C6 (Envelope)</translation>
<translation id="9164029392738894042">Verificação de precisão</translation>
diff --git a/chromium/components/strings/components_strings_pt-PT.xtb b/chromium/components/strings/components_strings_pt-PT.xtb
index ef99b6c5a31..d8712649c55 100644
--- a/chromium/components/strings/components_strings_pt-PT.xtb
+++ b/chromium/components/strings/components_strings_pt-PT.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">Veja detalhes</translation>
<translation id="1030706264415084469"><ph name="URL" /> pretende armazenar permanentemente dados de grandes dimensões no seu dispositivo.</translation>
<translation id="1032854598605920125">Rodar para a direita</translation>
+<translation id="1033329911862281889">A Navegação anónima não faz com que esteja invisível online:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Os sites e os serviços que estes utilizam podem ver as visitas<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Os empregadores ou as escolas podem monitorizar a atividade de navegação<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Os fornecedores de serviços de Internet podem monitorizar o tráfego da Web<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">Desativar</translation>
<translation id="1036982837258183574">Premir |<ph name="ACCELERATOR" />| para sair do ecrã inteiro</translation>
<translation id="1038106730571050514">Mostre as sugestões</translation>
<translation id="1038842779957582377">nome desconhecido</translation>
<translation id="1041998700806130099">Mensagem da folha da tarefa</translation>
<translation id="1048785276086539861">Quando edita anotações, este documento volta à vista de página única.</translation>
-<translation id="1049743911850919806">Navegação anónima</translation>
<translation id="1050038467049342496">Fechar outras aplicações</translation>
<translation id="1055184225775184556">&amp;Anular adição</translation>
<translation id="1056898198331236512">Aviso</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">Cache da política OK</translation>
<translation id="1130564665089811311">Botão Traduzir página; prima Enter para traduzir esta página com o Google Tradutor.</translation>
<translation id="1131264053432022307">Imagem que copiou</translation>
+<translation id="1142846828089312304">Bloquear cookies de terceiros na Navegação anónima</translation>
<translation id="1150979032973867961">Este servidor não conseguiu provar que é o domínio <ph name="DOMAIN" />; o sistema operativo do seu computador não confia no respetivo certificado de segurança. Isto pode ser o resultado de uma configuração incorreta ou de um invasor a intercetar a sua ligação.</translation>
<translation id="1151972924205500581">É necessária a palavra-passe</translation>
<translation id="1156303062776767266">Está a visualizar um ficheiro local ou partilhado</translation>
@@ -64,7 +70,6 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="1178581264944972037">Pausa</translation>
<translation id="1181037720776840403">Remover</translation>
<translation id="1186201132766001848">Verificar palavras-passe</translation>
-<translation id="1195210374336998651">Aceda às definições da app</translation>
<translation id="1195558154361252544">As notificações são bloqueadas automaticamente para todos os sites, exceto os que autorizar</translation>
<translation id="1197088940767939838">Laranja</translation>
<translation id="1201402288615127009">Seguinte</translation>
@@ -111,7 +116,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="1307966114820526988">Funcionalidades descontinuadas</translation>
<translation id="1308113895091915999">Oferta disponível</translation>
<translation id="1312803275555673949">Que provas existem?</translation>
-<translation id="131405271941274527"><ph name="URL" /> pretende enviar e receber informações quando toca no telemóvel num dispositivo NFC</translation>
+<translation id="1314311879718644478">Veja conteúdo de realidade aumentada</translation>
<translation id="1314509827145471431">Encadernar à direita</translation>
<translation id="1318023360584041678">Guardado no grupo de separadores</translation>
<translation id="1319245136674974084">Não voltar a perguntar para esta app</translation>
@@ -161,6 +166,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="142858679511221695">Utilizador da nuvem</translation>
<translation id="1428729058023778569">Está a ver este aviso porque o site não suporta HTTPS. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">Imprimir</translation>
+<translation id="1432187715652018471">A página quer instalar um controlador de serviço.</translation>
<translation id="1432581352905426595">Gerir motores de pesquisa</translation>
<translation id="1436185428532214179">Pode solicitar a edição de ficheiros e pastas no seu dispositivo</translation>
<translation id="1442386063175183758">Dobra simétrica à direita</translation>
@@ -181,6 +187,12 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="1483493594462132177">Enviar</translation>
<translation id="1484290072879560759">Escolher morada para envio</translation>
<translation id="1492194039220927094">Push das políticas:</translation>
+<translation id="149293076951187737">Quando fechar todos os separadores de navegação anónima do Chrome, a sua atividade nesses separadores será limpa neste dispositivo:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Atividade de navegação<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Histórico de pesquisas<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Informações introduzidas em formulários<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">Voltar ao separador</translation>
<translation id="1501859676467574491">Mostrar cartões da sua Conta Google</translation>
<translation id="1507202001669085618">&lt;p&gt;Este erro é apresentado se estiver a utilizar um portal Wi-Fi que requer que inicie sessão para poder aceder à Internet.&lt;/p&gt;
@@ -199,7 +211,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="1536390784834419204">Traduzir página</translation>
<translation id="1539840569003678498">Denúncia enviada:</translation>
<translation id="154408704832528245">Escolher endereço de entrega</translation>
-<translation id="1549470594296187301">É necessário ativar o JavaScript para utilizar esta funcionalidade.</translation>
+<translation id="1549470594296187301">É necessário ativar o JavaScript para usar esta funcionalidade.</translation>
<translation id="155039086686388498">Engineering-D</translation>
<translation id="1553358976309200471">Atualizar o Chrome</translation>
<translation id="1555130319947370107">Azul</translation>
@@ -208,6 +220,8 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="1559572115229829303">&lt;p&gt;Não é possível estabelecer uma ligação privada a <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />, porque a data e a hora (<ph name="DATE_AND_TIME" />) do seu dispositivo estão incorretas.&lt;/p&gt;
&lt;p&gt;Ajuste a data e a hora na secção &lt;strong&gt;Geral&lt;/strong&gt; da aplicação &lt;strong&gt;Definições&lt;/strong&gt;.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">O seu administrador vai reiniciar o dispositivo à(s) <ph name="TIME" /> de <ph name="DATE" /></translation>
+<translation id="156703335097561114">Informações de rede, tais como endereços, a configuração da interface e a qualidade da ligação</translation>
<translation id="1567040042588613346">Esta política está a funcionar conforme esperado, mas o mesmo valor está definido noutro local e foi substituído por esta política.</translation>
<translation id="1569487616857761740">Introduza a data de validade</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="1583429793053364125">Ocorreu um erro ao apresentar esta página Web.</translation>
<translation id="1586541204584340881">As extensões que instalou.</translation>
<translation id="1588438908519853928">Normal</translation>
+<translation id="1589050138437146318">Instalar o ARCore?</translation>
<translation id="1592005682883173041">Acesso aos dados locais</translation>
<translation id="1594030484168838125">Escolher</translation>
<translation id="160851722280695521">Jogue o Dino Run no Chrome</translation>
@@ -249,12 +264,12 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="1699570257714336246">Informações em falta</translation>
<translation id="1703835215927279855">Letter</translation>
<translation id="1706625117072057435">Níveis de zoom</translation>
-<translation id="1706954506755087368">{1,plural, =1{Este servidor não conseguiu provar que é <ph name="DOMAIN" />; o seu certificado de segurança é supostamente de amanhã. Isto pode ser o resultado de uma configuração incorreta ou de um invasor a intercetar a sua ligação.}one{This server could not prove that it is <ph name="DOMAIN" />; its security certificate is supposedly from # days in the future. This may be caused by a misconfiguration or an attacker intercepting your connection.}other{Este servidor não conseguiu provar que é <ph name="DOMAIN" />; a data do seu certificado de segurança é supostamente daqui a # dias. Isto pode ser o resultado de uma configuração incorreta ou de um invasor a intercetar a sua ligação.}}</translation>
+<translation id="1706954506755087368">{1,plural, =1{Este servidor não conseguiu provar que é <ph name="DOMAIN" />; o seu certificado de segurança é supostamente de amanhã. Isto pode ser o resultado de uma configuração incorreta ou de um invasor a intercetar a sua ligação.}other{Este servidor não conseguiu provar que é <ph name="DOMAIN" />; a data do seu certificado de segurança é supostamente daqui a # dias. Isto pode ser o resultado de uma configuração incorreta ou de um invasor a intercetar a sua ligação.}}</translation>
<translation id="1710259589646384581">SO</translation>
<translation id="1711234383449478798">Ignorada porque a política <ph name="POLICY_NAME" /> não está definida como <ph name="VALUE" />.</translation>
<translation id="1712552549805331520"><ph name="URL" /> pretende armazenar permanentemente os dados no seu computador local.</translation>
<translation id="1713628304598226412">Tabuleiro 2</translation>
-<translation id="1715874602234207">F</translation>
+<translation id="1715874602234207">S</translation>
<translation id="1717218214683051432">Sensores de movimento</translation>
<translation id="1717494416764505390">Caixa de correio 3</translation>
<translation id="1718029547804390981">O documento é demasiado grande para ser anotado.</translation>
@@ -283,6 +298,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
o cabeçalho está formatado incorretamente, o que impede que o navegador satisfaça
o seu pedido para <ph name="SITE" />. As políticas de origem podem ser utilizadas
pelos operadores de sites para configurar a segurança e outras propriedades de um site.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Saiba mais sobre a Navegação anónima no Chromium<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">Os separadores abertos aparecem aqui</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -314,7 +330,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="1883255238294161206">Fechar lista</translation>
<translation id="1890171020361705182">Jogo Dino. Um dinossauro pixelizado desvia-se de catos e de pterodáctilos enquanto corre numa paisagem deserta. Quando ouvir uma pista de áudio, toque para saltar sobre os obstáculos.</translation>
<translation id="1898423065542865115">Filtragem</translation>
-<translation id="1901443836186977402">{1,plural, =1{Este servidor não conseguiu provar que é o domínio <ph name="DOMAIN" />. O respetivo certificado de segurança expirou no último dia. Isto pode ser o resultado de uma configuração incorreta ou de um utilizador mal-intencionado que intercetou a sua ligação. O relógio do seu computador está atualmente definido para <ph name="CURRENT_DATE" />. Esta hora parece-lhe correta? Em caso negativo, corrija o relógio do sistema e, em seguida, atualize esta página.}one{Este servidor não conseguiu provar que é o domínio <ph name="DOMAIN" />. O respetivo certificado de segurança expirou há # dia(s). Isto pode ser o resultado de uma configuração incorreta ou de um invasor a intercetar a sua ligação. Atualmente, o relógio do computador está definido para <ph name="CURRENT_DATE" />. Esta hora parece-lhe correta? Em caso negativo, corrija o relógio do sistema e, em seguida, atualize esta página.}other{Este servidor não conseguiu provar que é o domínio <ph name="DOMAIN" />. O respetivo certificado de segurança expirou há # dias. Isto pode ser o resultado de uma configuração incorreta ou de um utilizador mal-intencionado que intercetou a sua ligação. O relógio do seu computador está atualmente definido para <ph name="CURRENT_DATE" />. Esta hora parece-lhe correta? Em caso negativo, corrija o relógio do sistema e, em seguida, atualize esta página.}}</translation>
+<translation id="1901443836186977402">{1,plural, =1{Este servidor não conseguiu provar que é o domínio <ph name="DOMAIN" />. O respetivo certificado de segurança expirou no último dia. Isto pode ser o resultado de uma configuração incorreta ou de um utilizador mal-intencionado que intercetou a sua ligação. O relógio do seu computador está atualmente definido para <ph name="CURRENT_DATE" />. Esta hora parece-lhe correta? Em caso negativo, corrija o relógio do sistema e, em seguida, atualize esta página.}other{Este servidor não conseguiu provar que é o domínio <ph name="DOMAIN" />. O respetivo certificado de segurança expirou há # dias. Isto pode ser o resultado de uma configuração incorreta ou de um utilizador mal-intencionado que intercetou a sua ligação. O relógio do seu computador está atualmente definido para <ph name="CURRENT_DATE" />. Esta hora parece-lhe correta? Em caso negativo, corrija o relógio do sistema e, em seguida, atualize esta página.}}</translation>
<translation id="1902576642799138955">Período de validade</translation>
<translation id="1906155288650175567">Botão Criar nota, prima Enter para criar rapidamente uma nova nota no Google Keep</translation>
<translation id="1908217026282415406">Utilização e movimento da câmara</translation>
@@ -324,7 +340,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="1916770123977586577">Para aplicar as definições atualizadas a este site, atualize esta página</translation>
<translation id="1919345977826869612">Anúncios</translation>
<translation id="1919367280705858090">Obter ajuda relativamente a uma mensagem de erro específica</translation>
-<translation id="192020519938775529">{COUNT,plural, =0{Nenhum}=1{1 site}one{# sites}other{# sites}}</translation>
+<translation id="192020519938775529">{COUNT,plural, =0{Nenhum}=1{1 site}other{# sites}}</translation>
<translation id="1923390796829649802">Botão Gerir definições de acessibilidade, Enter para personalizar as ferramentas de acessibilidade nas definições do Chrome OS</translation>
<translation id="1924727005275031552">Novo</translation>
<translation id="1927439593081478069">Botão Executar verificação de segurança do Chrome, prima Enter para executar a verificação de segurança nas definições do Chrome</translation>
@@ -343,7 +359,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="1988881251331415125">Se a ortografia estiver correta, <ph name="BEGIN_LINK" />experimente executar o Diagnóstico de conetividade<ph name="END_LINK" />.</translation>
<translation id="1992331125980284532">JIS B3</translation>
<translation id="1997484222658892567"><ph name="URL" /> pretende armazenar permanentemente dados de grandes dimensões no seu computador local.</translation>
-<translation id="2001146170449793414">{COUNT,plural, =1{e mais 1}one{and # more}other{e mais #}}</translation>
+<translation id="2001146170449793414">{COUNT,plural, =1{e mais 1}other{e mais #}}</translation>
<translation id="2003709556000175978">Repor a palavra-passe agora</translation>
<translation id="2003775180883135320">Perfuração quádrupla na parte superior</translation>
<translation id="201174227998721785">Faça a gestão das autorizações e dos dados armazenados em sites nas Definições do Chrome.</translation>
@@ -358,9 +374,9 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="2042213636306070719">Tabuleiro 7</translation>
<translation id="204357726431741734">Iniciar sessão para utilizar palavras-passe guardadas na sua Conta Google</translation>
<translation id="2053111141626950936">As páginas em <ph name="LANGUAGE" /> não serão traduzidas.</translation>
-<translation id="2053373601901562871">{NUM_DAYS,plural, =0{Quando este controlo está ativado e o estado está ativo, o Chrome determina a que grupo alargado de pessoas, ou "coorte", a sua atividade de navegação recente é mais semelhante. Os anunciantes podem selecionar anúncios para o grupo e a sua atividade de navegação permanece privada no seu dispositivo. O seu grupo é atualizado todos os dias.}=1{Quando este controlo está ativado e o estado está ativo, o Chrome determina a que grupo alargado de pessoas, ou "coorte", a sua atividade de navegação recente é mais semelhante. Os anunciantes podem selecionar anúncios para o grupo e a sua atividade de navegação permanece privada no seu dispositivo. O seu grupo é atualizado todos os dias.}one{Quando este controlo está ativado e o estado está ativo, o Chrome determina a que grupo alargado de pessoas, ou "coorte", a sua atividade de navegação recente é mais semelhante. Os anunciantes podem selecionar anúncios para o grupo e a sua atividade de navegação permanece privada no seu dispositivo. O seu grupo é atualizado a cada {NUM_DAYS} dia(s).}other{Quando este controlo está ativado e o estado está ativo, o Chrome determina a que grupo alargado de pessoas, ou "coorte", a sua atividade de navegação recente é mais semelhante. Os anunciantes podem selecionar anúncios para o grupo e a sua atividade de navegação permanece privada no seu dispositivo. O seu grupo é atualizado a cada {NUM_DAYS} dias.}}</translation>
+<translation id="2053373601901562871">{NUM_DAYS,plural, =0{Quando este controlo está ativado e o estado está ativo, o Chrome determina a que grupo alargado de pessoas, ou "coorte", a sua atividade de navegação recente é mais semelhante. Os anunciantes podem selecionar anúncios para o grupo e a sua atividade de navegação permanece privada no seu dispositivo. O seu grupo é atualizado todos os dias.}=1{Quando este controlo está ativado e o estado está ativo, o Chrome determina a que grupo alargado de pessoas, ou "coorte", a sua atividade de navegação recente é mais semelhante. Os anunciantes podem selecionar anúncios para o grupo e a sua atividade de navegação permanece privada no seu dispositivo. O seu grupo é atualizado todos os dias.}other{Quando este controlo está ativado e o estado está ativo, o Chrome determina a que grupo alargado de pessoas, ou "coorte", a sua atividade de navegação recente é mais semelhante. Os anunciantes podem selecionar anúncios para o grupo e a sua atividade de navegação permanece privada no seu dispositivo. O seu grupo é atualizado a cada {NUM_DAYS} dias.}}</translation>
<translation id="2053553514270667976">Código postal</translation>
-<translation id="2064691555167957331">{COUNT,plural, =1{1 sugestão}one{# suggestions}other{# sugestões}}</translation>
+<translation id="2064691555167957331">{COUNT,plural, =1{1 sugestão}other{# sugestões}}</translation>
<translation id="2071156619270205202">Este cartão não é elegível para um número de cartão virtual.</translation>
<translation id="2071692954027939183">As notificações foram automaticamente bloqueadas porque, geralmente, não as permite.</translation>
<translation id="2079545284768500474">Anular</translation>
@@ -402,7 +418,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="2169984857010174799">Kaku2 (Envelope)</translation>
<translation id="2181821976797666341">Políticas</translation>
<translation id="2183608646556468874">Número de telefone</translation>
-<translation id="2184405333245229118">{COUNT,plural, =1{1 endereço}one{# addresses}other{# endereços}}</translation>
+<translation id="2184405333245229118">{COUNT,plural, =1{1 endereço}other{# endereços}}</translation>
<translation id="2187317261103489799">Detetar (predefinição)</translation>
<translation id="2188375229972301266">Perfuração múltipla na parte inferior</translation>
<translation id="2188852899391513400">A palavra-passe que acabou de utilizar foi encontrada numa violação de dados. Para proteger as suas contas, o Gestor de palavras-passe da Google recomenda que a altere agora e, em seguida, verifique as suas palavras-passe guardadas.</translation>
@@ -410,6 +426,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="22081806969704220">Tabuleiro 3</translation>
<translation id="2212735316055980242">Política não encontrada</translation>
<translation id="2213606439339815911">A obter entradas...</translation>
+<translation id="2213612003795704869">A página foi impressa</translation>
<translation id="2215727959747642672">Edição de ficheiros</translation>
<translation id="2218879909401188352">Os utilizadores mal-intencionados que se encontram em <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> podem instalar aplicações perigosas que danificam o dispositivo, adicionam cobranças ocultas à fatura de dados móveis ou roubam as suas informações pessoais. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">Sem Internet</translation>
@@ -419,6 +436,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="2248949050832152960">Utilizar WebAuthn</translation>
<translation id="2250931979407627383">Coser extremidade esquerda</translation>
<translation id="225207911366869382">Este valor está desatualizado para esta política.</translation>
+<translation id="2256115617011615191">Reiniciar agora</translation>
<translation id="2258928405015593961">Introduza uma data de validade no futuro e tente novamente.</translation>
<translation id="225943865679747347">Código de erro: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">Erro HTTP</translation>
@@ -446,12 +464,13 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="2337852623177822836">Definição controlada pelo gestor</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> pretende sincronizar</translation>
<translation id="2346319942568447007">Imagem que copiou</translation>
+<translation id="2350796302381711542">Permitir que <ph name="HANDLER_HOSTNAME" /> abra todos os links <ph name="PROTOCOL" />, em vez de <ph name="REPLACED_HANDLER_TITLE" />?</translation>
<translation id="2354001756790975382">Outros marcadores</translation>
<translation id="2354430244986887761">A Navegação segura do Google <ph name="BEGIN_LINK" />encontrou aplicações prejudiciais<ph name="END_LINK" /> recentemente em <ph name="SITE" />.</translation>
<translation id="2355395290879513365">Os atacantes podem ver as imagens que está a visualizar neste site e enganá-lo ao modificá-las.</translation>
<translation id="2356070529366658676">Perguntar</translation>
<translation id="2357481397660644965">O seu dispositivo é gerido por <ph name="DEVICE_MANAGER" /> e a sua conta é gerida por <ph name="ACCOUNT_MANAGER" />.</translation>
-<translation id="2359347814217202136">{NUM_DAYS,plural, =0{Em menos de 1 dia}=1{Dentro de 1 dia}one{Dentro de {NUM_DAYS} dia(s)}other{Dentro de {NUM_DAYS} dias}}</translation>
+<translation id="2359347814217202136">{NUM_DAYS,plural, =0{Em menos de 1 dia}=1{Dentro de 1 dia}other{Dentro de {NUM_DAYS} dias}}</translation>
<translation id="2359629602545592467">Várias</translation>
<translation id="2359808026110333948">Continuar</translation>
<translation id="236340516568226369">Menu de interruptores de redimensionamento</translation>
@@ -471,6 +490,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="2413528052993050574">Este servidor não conseguiu provar que é o domínio <ph name="DOMAIN" />; o respetivo certificado de segurança poderá ser revogado. Isto pode ser o resultado de uma configuração incorreta ou de um invasor a intercetar a sua ligação.</translation>
<translation id="2414886740292270097">Escuro</translation>
<translation id="2430968933669123598">Faça a gestão da Conta Google, prima Enter para gerir as suas informações, privacidade e segurança na Conta Google</translation>
+<translation id="2436186046335138073">Permitir que <ph name="HANDLER_HOSTNAME" /> abra todos os links <ph name="PROTOCOL" />?</translation>
<translation id="2438874542388153331">Perfuração quádrupla à direita</translation>
<translation id="2450021089947420533">Percursos</translation>
<translation id="2463739503403862330">Preencher</translation>
@@ -478,6 +498,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="2465655957518002998">Escolher método de fornecimento</translation>
<translation id="2465688316154986572">Agrafar</translation>
<translation id="2465914000209955735">Faça a gestão dos ficheiros que transferiu no Chrome</translation>
+<translation id="2466004615675155314">Mostre informações da Web</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Executar o Diagnóstico de rede<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">Ordem de 1 para N</translation>
<translation id="2470767536994572628">Quando edita anotações, este documento volta à vista de página única e à respetiva rotação original.</translation>
@@ -498,7 +519,8 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="2523886232349826891">Guardado apenas neste dispositivo.</translation>
<translation id="2524461107774643265">Adicionar mais informações</translation>
<translation id="2529899080962247600">Este campo não deve ter mais de <ph name="MAX_ITEMS_LIMIT" /> entradas. Todas as restantes entradas serão ignoradas.</translation>
-<translation id="2535659140340599600">{COUNT,plural, =1{e mais 1}one{e mais #}other{e mais #}}</translation>
+<translation id="2535585790302968248">Abra um novo separador de navegação anónima para navegar em privado</translation>
+<translation id="2535659140340599600">{COUNT,plural, =1{e mais 1}other{e mais #}}</translation>
<translation id="2536110899380797252">Adicionar endereço</translation>
<translation id="2539524384386349900">Detetar</translation>
<translation id="2540701853218677861">Histórico de início/fim de sessão do dispositivo, incluindo data/hora e tentativas falhadas</translation>
@@ -523,7 +545,14 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="2597378329261239068">Este documento está protegido por palavra-passe. Introduza uma palavra-passe.</translation>
<translation id="2609632851001447353">Variações</translation>
<translation id="2610561535971892504">Clique para copiar</translation>
+<translation id="2617988307566202237">O Chrome <ph name="BEGIN_EMPHASIS" />não guardará<ph name="END_EMPHASIS" /> as seguintes informações:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />O seu histórico de navegação
+ <ph name="LIST_ITEM" />Os cookies e os dados de sites
+ <ph name="LIST_ITEM" />As informações introduzidas em formulários
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (Envelope)</translation>
+<translation id="2623663032199728144">Pode solicitar a utilização de informações acerca dos seus ecrãs</translation>
<translation id="2625385379895617796">O seu relógio está adiantado</translation>
<translation id="262745152991669301">Pode solicitar a ligação a dispositivos USB</translation>
<translation id="2629325967560697240">Para obter o nível de segurança mais elevado do Chrome, <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />ative a proteção melhorada<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -536,7 +565,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="2653659639078652383">Enviar</translation>
<translation id="2659491813326907275">Personalize as ferramentas de acessibilidade nas definições do Chrome OS</translation>
<translation id="2660779039299703961">Evento</translation>
-<translation id="2664887757054927933">{COUNT,plural, =0{Nenhuma}=1{1 palavra-passe (de <ph name="DOMAIN_LIST" />)}=2{2 palavras-passe (de <ph name="DOMAIN_LIST" />)}one{# palavra(s)-passe (de <ph name="DOMAIN_LIST" />)}other{# palavras-passe (de <ph name="DOMAIN_LIST" />)}}</translation>
+<translation id="2664887757054927933">{COUNT,plural, =0{Nenhuma}=1{1 palavra-passe (de <ph name="DOMAIN_LIST" />)}=2{2 palavras-passe (de <ph name="DOMAIN_LIST" />)}other{# palavras-passe (de <ph name="DOMAIN_LIST" />)}}</translation>
<translation id="2666092431469916601">Parte superior</translation>
<translation id="2666117266261740852">Fechar outros separadores ou aplicações</translation>
<translation id="2672201172023654893">O seu navegador não é gerido.</translation>
@@ -557,6 +586,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="2709516037105925701">Preenchimento automático</translation>
<translation id="2713444072780614174">Branco</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />, prima Tab e, em seguida, Enter para as suas informações de cartões de crédito e pagamentos nas Definições do Chrome.</translation>
+<translation id="271663710482723385">Prima |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| para sair do ecrã inteiro</translation>
<translation id="2721148159707890343">Pedido com êxito</translation>
<translation id="2723669454293168317">Execute uma verificação de segurança nas definições do Chrome</translation>
<translation id="2726001110728089263">Tabuleiro lateral</translation>
@@ -587,6 +617,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="2850739647070081192">Invite (Envelope)</translation>
<translation id="2856444702002559011">Os atacantes poderão estar a tentar roubar as suas informações de <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (por exemplo, palavras-passe, mensagens ou cartões de crédito). <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">Este site apresenta anúncios intrusivos ou enganadores.</translation>
+<translation id="286512204874376891">Um cartão virtual disfarça o seu cartão real como medida de proteção contra potenciais fraudes. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">Amigável</translation>
<translation id="2876489322757410363">Está a sair do Modo de navegação anónima para pagar através de uma aplicação externa. Pretende continuar?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />, prima Tab e, em seguida, Enter para gerir a Navegação segura e muito mais nas Definições do Chrome</translation>
@@ -607,10 +638,11 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="2922350208395188000">Não é possível verificar o certificado do servidor.</translation>
<translation id="2925673989565098301">Método de fornecimento</translation>
<translation id="2928905813689894207">Endereço de faturação</translation>
-<translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> e mais <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}one{<ph name="SHIPPING_ADDRESS_PREVIEW" /> e mais <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> e mais <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}}</translation>
+<translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> e mais <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> e mais <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}}</translation>
<translation id="2930577230479659665">Cortar no fim de cada cópia</translation>
<translation id="2932085390869194046">Sugerir palavra-passe…</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019">Abrir links de <ph name="PROTOCOL" /></translation>
<translation id="2941952326391522266">Este servidor não conseguiu provar que é o domínio <ph name="DOMAIN" />; o respetivo certificado de segurança é do domínio <ph name="DOMAIN2" />. Isto pode ser o resultado de uma configuração incorreta ou de um invasor a intercetar a sua ligação.</translation>
<translation id="2943895734390379394">Hora do carregamento:</translation>
<translation id="2948083400971632585">Pode desativar qualquer proxy configurado para uma ligação a partir da página de definições.</translation>
@@ -643,6 +675,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="3037605927509011580">Ah, bolas!!</translation>
<translation id="3041612393474885105">Informações do certificado</translation>
<translation id="3044034790304486808">Retomar pesquisa</translation>
+<translation id="305162504811187366">Histórico do Ambiente de Trabalho Remoto do Chrome, incluindo datas/horas, anfitriões e IDs de sessão de cliente</translation>
<translation id="3060227939791841287">C9 (Envelope)</translation>
<translation id="3061707000357573562">Serviço de patch</translation>
<translation id="306573536155379004">Jogo iniciado.</translation>
@@ -662,7 +695,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="3120730422813725195">Elo</translation>
<translation id="31207688938192855"><ph name="BEGIN_LINK" />Experimente executar o Diagnóstico de conetividade<ph name="END_LINK" />.</translation>
<translation id="3121994479408824897">Ir para <ph name="DOMAIN" /></translation>
-<translation id="3137507986424712703">{COUNT,plural, =0{Sem}=1{dados de início de sessão para 1 conta}one{sign-in data for # accounts}other{dados de início de sessão para # contas}}</translation>
+<translation id="3137507986424712703">{COUNT,plural, =0{Sem}=1{dados de início de sessão para 1 conta}other{dados de início de sessão para # contas}}</translation>
<translation id="3145945101586104090">Falha ao descodificar resposta</translation>
<translation id="3150653042067488994">Erro temporário do servidor</translation>
<translation id="3154506275960390542">Esta página inclui um formulário que pode não ser enviado em segurança. Os dados que enviar podem ser vistos por outros utilizadores em trânsito ou podem ser modificados por um utilizador mal intencionado para alterar o que é recebido pelo servidor.</translation>
@@ -683,6 +716,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="3197136577151645743">Pode pedir para saber quando está a utilizar ativamente este dispositivo</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />, prima Tab e, em seguida, Enter para gerir as informações que sincroniza nas Definições do Chrome.</translation>
<translation id="320323717674993345">Cancelar pagamento</translation>
+<translation id="3203366800380907218">Da Web</translation>
<translation id="3207960819495026254">Adicionado aos marcadores</translation>
<translation id="3209034400446768650">A página pode efetuar cobranças</translation>
<translation id="3212581601480735796">A sua atividade em <ph name="HOSTNAME" /> está a ser monitorizada</translation>
@@ -699,10 +733,12 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="3234666976984236645">Detetar sempre conteúdo importante neste site</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />, prima Tab e, em seguida, Enter para personalizar o aspeto do seu navegador</translation>
<translation id="3240791268468473923">A página de credenciais de pagamento seguro sem correspondência com as credenciais está aberta</translation>
+<translation id="324180406144491771">Os links do anfitrião "<ph name="HOST_NAME" />" estão bloqueados</translation>
<translation id="3249845759089040423">Descontraído</translation>
<translation id="3252266817569339921">Francês</translation>
<translation id="3257954757204451555">Quem é responsável por estas informações?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />, prima Tab e, em seguida, Enter para criar rapidamente um novo evento no Calendário Google</translation>
+<translation id="3261488570342242926">Saiba mais sobre cartões virtuais</translation>
<translation id="3264837738038045344">Botão Gerir definições do Chrome, prima Enter para visitar as definições do Chrome</translation>
<translation id="3266793032086590337">Valor (em conflito)</translation>
<translation id="3268451620468152448">Separadores abertos</translation>
@@ -716,6 +752,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="3288238092761586174"><ph name="URL" /> pode ter de efetuar passos adicionais para validar o seu pagamento</translation>
<translation id="3293642807462928945">Saiba mais acerca da política <ph name="POLICY_NAME" /></translation>
<translation id="3295444047715739395">Veja e efetue a gestão das suas palavras-passe nas definições do Chrome.</translation>
+<translation id="3303795387212510132">Pretende permitir que a app abra os links <ph name="PROTOCOL_SCHEME" />?</translation>
<translation id="3303855915957856445">Não foram encontrados resultados da pesquisa</translation>
<translation id="3304073249511302126">procura de bluetooth</translation>
<translation id="3308006649705061278">Unidade organizacional (OU)</translation>
@@ -729,12 +766,6 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="3345782426586609320">Olhos</translation>
<translation id="3355823806454867987">Alterar definições de proxy...</translation>
<translation id="3360103848165129075">Página do controlador do pagamento</translation>
-<translation id="3361596688432910856">O Chrome <ph name="BEGIN_EMPHASIS" />não guardará<ph name="END_EMPHASIS" /> as seguintes informações:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />O seu histórico de navegação
- <ph name="LIST_ITEM" />Os cookies e os dados de sites
- <ph name="LIST_ITEM" />As informações introduzidas em formulários
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">Esta política foi copiada automaticamente da política <ph name="OLD_POLICY" /> descontinuada. Deverá optar por utilizar esta política.</translation>
<translation id="3364869320075768271"><ph name="URL" /> pretende utilizar os seus dados e dispositivo de realidade virtual.</translation>
<translation id="3366477098757335611">Ver cartões</translation>
@@ -798,7 +829,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="3518941727116570328">Processamento de vários objetos</translation>
<translation id="3528171143076753409">O certificado do servidor não é fidedigno.</translation>
<translation id="3528485271872257980">Castanho-escuro</translation>
-<translation id="3530944546672790857">{COUNT,plural, =0{Pelo menos 1 item em dispositivos sincronizados}=1{1 item (e mais em dispositivos sincronizados)}one{# itens (e mais em dispositivos sincronizados)}other{# itens (e mais em dispositivos sincronizados)}}</translation>
+<translation id="3530944546672790857">{COUNT,plural, =0{Pelo menos 1 item em dispositivos sincronizados}=1{1 item (e mais em dispositivos sincronizados)}other{# itens (e mais em dispositivos sincronizados)}}</translation>
<translation id="3531780078352352885">Folhas da tarefa</translation>
<translation id="3532844647053365774"><ph name="HOST" /> pretende utilizar o seu microfone.</translation>
<translation id="3533328374079021623">Caixa de correio 5</translation>
@@ -816,8 +847,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="3586931643579894722">Ocultar detalhes</translation>
<translation id="3587738293690942763">Central</translation>
<translation id="3592413004129370115">Italian (Envelope)</translation>
-<translation id="3595699422137460894">{NUM_DAYS,plural, =0{Pode repor o grupo em qualquer altura. A adesão a um novo grupo demora cerca de um dia.}=1{Pode repor o grupo em qualquer altura. A adesão a um novo grupo demora cerca de um dia.}one{Pode repor o grupo em qualquer altura. A adesão a um novo grupo demora cerca de {NUM_DAYS} dia(s).}other{Pode repor o grupo em qualquer altura. A adesão a um novo grupo demora cerca de {NUM_DAYS} dias.}}</translation>
-<translation id="3596012367874587041">Definições da app</translation>
+<translation id="3595699422137460894">{NUM_DAYS,plural, =0{Pode repor o grupo em qualquer altura. A adesão a um novo grupo demora cerca de um dia.}=1{Pode repor o grupo em qualquer altura. A adesão a um novo grupo demora cerca de um dia.}other{Pode repor o grupo em qualquer altura. A adesão a um novo grupo demora cerca de {NUM_DAYS} dias.}}</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">App bloqueada pelo seu administrador</translation>
<translation id="3608932978122581043">Guiar a orientação</translation>
@@ -860,6 +890,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="370972442370243704">Ativar os percursos</translation>
<translation id="3711895659073496551">Suspenso</translation>
<translation id="3712624925041724820">Licenças esgotadas</translation>
+<translation id="3714633008798122362">calendário Web</translation>
<translation id="3714780639079136834">Ativar os dados móveis ou o Wi-Fi</translation>
<translation id="3715597595485130451">Estabelecer ligação a redes Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Verificar a configuração do proxy, da firewall e de DNS<ph name="END_LINK" /></translation>
@@ -921,6 +952,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="3906954721959377182">Tablet</translation>
<translation id="3909477809443608991"><ph name="URL" /> pretende reproduzir conteúdo protegido. A identidade do seu dispositivo será validada pela Google e este site poderá aceder à mesma.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">Recusar</translation>
<translation id="3939773374150895049">Pretende utilizar o WebAuthn em vez do CVC?</translation>
<translation id="3946209740501886391">Perguntar sempre neste site</translation>
<translation id="3947595700203588284">Pode solicitar a ligação a dispositivos MIDI</translation>
@@ -933,7 +965,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="3962859241508114581">Faixa anterior</translation>
<translation id="3963721102035795474">Modo de leitor</translation>
<translation id="3963837677003247395">Pretende continuar manualmente?</translation>
-<translation id="3964661563329879394">{COUNT,plural, =0{Nenhum}=1{De 1 site }one{De # sites }other{De # sites }}</translation>
+<translation id="3964661563329879394">{COUNT,plural, =0{Nenhum}=1{De 1 site }other{De # sites }}</translation>
<translation id="3969052498612555048">Não consegue encontrar o seu código? <ph name="BEGIN_LINK" />Obtenha um novo código<ph name="END_LINK" /></translation>
<translation id="397105322502079400">A calcular...</translation>
<translation id="3973234410852337861"><ph name="HOST_NAME" /> está bloqueado</translation>
@@ -942,8 +974,9 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="3990250421422698716">Separar conjuntos</translation>
<translation id="3996311196211510766">O site <ph name="ORIGIN" /> solicitou que seja aplicada uma política de origem
a todos os pedidos, mas, de momento, não é possível aplicar essa política.</translation>
+<translation id="4009243425692662128">O conteúdo das páginas que imprime é enviado para o Google Cloud ou terceiros para análise. Por exemplo, pode ser analisado quanto a dados confidenciais.</translation>
<translation id="4010758435855888356">Pretende permitir o acesso ao armazenamento?</translation>
-<translation id="4014128326099193693">{COUNT,plural, =1{Documento PDF com {COUNT} página}one{Documento PDF com {COUNT} página(s)}other{Documento PDF com {COUNT} páginas}}</translation>
+<translation id="4014128326099193693">{COUNT,plural, =1{Documento PDF com {COUNT} página}other{Documento PDF com {COUNT} páginas}}</translation>
<translation id="4023431997072828269">Uma vez que este formulário está a ser enviado através de uma ligação insegura, as suas informações vão ficar visíveis para outras pessoas.</translation>
<translation id="4025913568718019429">Botão Gerir definições de privacidade do Google, prima Enter para visitar as definições de privacidade da sua Conta Google</translation>
<translation id="4030383055268325496">&amp;Anular adição</translation>
@@ -977,14 +1010,14 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="4121428309786185360">Expira em</translation>
<translation id="4123572138124678573">Perfuração tripla na parte inferior</translation>
<translation id="4127575959421463246">Está à procura das sinalizações do Chrome OS? Visite</translation>
-<translation id="4129401438321186435">{COUNT,plural, =1{1 outro}one{# others}other{# outros}}</translation>
+<translation id="4129401438321186435">{COUNT,plural, =1{1 outro}other{# outros}}</translation>
<translation id="4130226655945681476">Verificar os cabos de rede, o modem e o router</translation>
<translation id="4134123981501319574">Criar documento</translation>
<translation id="413544239732274901">Saiba mais</translation>
<translation id="4142935452406587478">Tabuleiro 10</translation>
<translation id="4148925816941278100">American Express</translation>
<translation id="4151403195736952345">Utilizar predefinição global (Detetar)</translation>
-<translation id="4152318981910038897">{COUNT,plural, =1{Página 1}one{Página {COUNT}}other{Página {COUNT}}}</translation>
+<translation id="4152318981910038897">{COUNT,plural, =1{Página 1}other{Página {COUNT}}}</translation>
<translation id="4154664944169082762">Impressões digitais</translation>
<translation id="4159784952369912983">Roxo</translation>
<translation id="4165986682804962316">Definições de sites</translation>
@@ -992,7 +1025,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="4171489848299289778"><ph name="RESULT_MODIFIED_DATE" /> – <ph name="RESULT_OWNER" /> – <ph name="RESULT_PRODUCT_SOURCE" /></translation>
<translation id="4172051516777682613">Mostrar sempre</translation>
<translation id="4173315687471669144">Foolscap</translation>
-<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{Mais <ph name="ITEM_COUNT" /> item}one{Mais <ph name="ITEM_COUNT" /> item}other{Mais <ph name="ITEM_COUNT" /> itens}}</translation>
+<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{Mais <ph name="ITEM_COUNT" /> item}other{Mais <ph name="ITEM_COUNT" /> itens}}</translation>
<translation id="4176463684765177261">Desativado</translation>
<translation id="4179515394835346607"><ph name="ROW_NAME" /> <ph name="ROW_CONTENT" /></translation>
<translation id="4194250254487269611">Não é possível guardar o seu cartão neste momento.</translation>
@@ -1036,6 +1069,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="4250680216510889253">Não</translation>
<translation id="4253168017788158739">Nota</translation>
<translation id="425582637250725228">É possível que as alterações não tenham sido efetuadas.</translation>
+<translation id="425869179292622354">Torná-lo mais seguro com um cartão virtual?</translation>
<translation id="4258748452823770588">Assinatura incorreta</translation>
<translation id="4261046003697461417">Não é possível anotar documentos protegidos</translation>
<translation id="4265872034478892965">Permitida pelo gestor</translation>
@@ -1043,7 +1077,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="4275830172053184480">Reiniciar o dispositivo</translation>
<translation id="4277028893293644418">Repor palavra-passe</translation>
<translation id="4278390842282768270">Permitido</translation>
-<translation id="428639260510061158">{NUM_CARDS,plural, =1{Este cartão foi guardado na sua Conta Google.}one{Este(s) cartão(ões) foi/foram guardado(s) na sua Conta Google.}other{Estes cartões foram guardados na sua Conta Google.}}</translation>
+<translation id="428639260510061158">{NUM_CARDS,plural, =1{Este cartão foi guardado na sua Conta Google.}other{Estes cartões foram guardados na sua Conta Google.}}</translation>
<translation id="4287885627794386150">Elegível para avaliação, mas não ativa</translation>
<translation id="4297502707443874121">Miniatura da página <ph name="THUMBNAIL_PAGE" /></translation>
<translation id="42981349822642051">Expandir</translation>
@@ -1098,6 +1132,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="4434045419905280838">Pop-ups e redirecionamentos</translation>
<translation id="4435702339979719576">Postcard)</translation>
<translation id="443673843213245140">A utilização de um proxy está desativada, mas existe uma configuração de proxy explícita especificada.</translation>
+<translation id="4441832193888514600">Ignorado porque a política só pode ser definida como uma Política do Utilizador da nuvem.</translation>
<translation id="4450893287417543264">Não mostrar de novo</translation>
<translation id="4451135742916150903">Pode solicitar a ligação a dispositivos HID</translation>
<translation id="4452328064229197696">A palavra-passe que acabou de utilizar foi encontrada numa violação de dados. Para proteger as suas contas, o Gestor de palavras-passe da Google recomenda que verifique as suas palavras-passe guardadas.</translation>
@@ -1153,6 +1188,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="4628948037717959914">Fotografia</translation>
<translation id="4631649115723685955">Reembolso associado</translation>
<translation id="4636930964841734540">Informações</translation>
+<translation id="4638670630777875591">Navegação anónima no Chromium</translation>
<translation id="464342062220857295">Funcionalidades de pesquisa</translation>
<translation id="4644670975240021822">Ordem inversa, com orientação para baixo</translation>
<translation id="4646534391647090355">Aceder agora</translation>
@@ -1173,6 +1209,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="4708268264240856090">A ligação foi interrompida</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Executar o Diagnóstico de rede do Windows<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426">Palavra-passe de <ph name="USERNAME" /></translation>
<translation id="4724144314178270921">Pode solicitar a visualização de texto e imagens na sua área de transferência</translation>
<translation id="4726672564094551039">Recarregar políticas</translation>
<translation id="4728558894243024398">Plataforma</translation>
@@ -1194,10 +1231,11 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="4757993714154412917">Acabou de introduzir a sua palavra-passe num site fraudulento. Para proteger as suas contas, o Chromium recomenda verificar as palavras-chave guardadas.</translation>
<translation id="4758311279753947758">Adicionar informações de contacto</translation>
<translation id="4761104368405085019">Utilizar o seu microfone</translation>
+<translation id="4761869838909035636">Executar verificação de segurança do Chrome</translation>
<translation id="4764776831041365478">A página Web em <ph name="URL" /> poderá estar temporariamente inactiva ou poderá ter sido movida permanentemente para um novo endereço Web.</translation>
<translation id="4766713847338118463">Agrafo duplo na parte inferior</translation>
<translation id="4771973620359291008">Ocorreu um erro desconhecido.</translation>
-<translation id="477945296921629067">{NUM_POPUPS,plural, =1{Pop-up bloqueado}one{# pop-ups blocked}other{# pop-ups bloqueados}}</translation>
+<translation id="477945296921629067">{NUM_POPUPS,plural, =1{Pop-up bloqueado}other{# pop-ups bloqueados}}</translation>
<translation id="4780366598804516005">Caixa de correio 1</translation>
<translation id="4785376858512657294">Gerir Conta Google</translation>
<translation id="4785689107224900852">Mudar para este separador</translation>
@@ -1214,12 +1252,6 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="4819347708020428563">Pretende editar anotações na vista predefinida?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />, prima Tab e, em seguida, Enter para criar rapidamente uma nova Folha de cálculo do Google Sheets</translation>
<translation id="4825507807291741242">Potente</translation>
-<translation id="4827402517081186284">A Navegação anónima não faz com que esteja invisível online:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Os sites sabem quando os visita<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Os empregadores ou as escolas podem monitorizar a atividade de navegação<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Os fornecedores de serviços de Internet podem monitorizar o tráfego da Web<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">Ativar avisos</translation>
<translation id="4838327282952368871">Sonhador</translation>
<translation id="4840250757394056958">Ver o Histórico do Chrome</translation>
@@ -1231,12 +1263,12 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="4854362297993841467">Este método de fornecimento não está disponível. Experimente um método diferente.</translation>
<translation id="4854853140771946034">Crie rapidamente uma nova nota no Google Keep</translation>
<translation id="485902285759009870">A validar o código…</translation>
+<translation id="4866506163384898554">Prima |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| para mostrar o cursor</translation>
<translation id="4876188919622883022">Vista simplificada</translation>
<translation id="4876305945144899064">Sem nome de utilizador</translation>
-<translation id="4877083676943085827">{COUNT,plural, =0{Nenhuma}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}one{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}}</translation>
+<translation id="4877083676943085827">{COUNT,plural, =0{Nenhuma}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831">Pesquisa de <ph name="TEXT" /></translation>
<translation id="4879491255372875719">Automático (predefinição)</translation>
-<translation id="4879725228911483934">Abrir e colocar janelas nos seus ecrãs</translation>
<translation id="4880827082731008257">Pesquisar histórico</translation>
<translation id="4881695831933465202">Abrir</translation>
<translation id="4885256590493466218">Utilize o <ph name="CARD_DETAIL" /> no pagamento.</translation>
@@ -1245,6 +1277,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">Nono rolo</translation>
<translation id="4901778704868714008">Guardar…</translation>
+<translation id="4905659621780993806">O seu administrador vai reiniciar o dispositivo à(s) <ph name="TIME" /> de <ph name="DATE" />. Guarde os itens abertos antes de o dispositivo ser reiniciado.</translation>
<translation id="4913987521957242411">Perfurar na parte superior esquerda</translation>
<translation id="4918221908152712722">Instale a aplicação <ph name="APP_NAME" /> (não é necessária qualquer transferência).</translation>
<translation id="4923459931733593730">Pagamento</translation>
@@ -1253,6 +1286,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, prima Tab e, em seguida, Enter para pesquisar.</translation>
<translation id="4930153903256238152">Capacidade elevada</translation>
+<translation id="4940163644868678279">Navegação anónima no Chrome</translation>
<translation id="4943872375798546930">Nenhum resultado</translation>
<translation id="4950898438188848926">Botão de mudança de separador: prima Enter para mudar para o separador aberto, <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="495170559598752135">Ações</translation>
@@ -1262,6 +1296,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="4968522289500246572">Esta app foi concebida para dispositivos móveis e pode não ser redimensionada corretamente. A app pode ter problemas ou reiniciar.</translation>
<translation id="4969341057194253438">Eliminar gravação</translation>
<translation id="4973922308112707173">Perfuração dupla na parte superior</translation>
+<translation id="4976702386844183910">Última visita a <ph name="DATE" /></translation>
<translation id="4984088539114770594">Pretende utilizar o microfone?</translation>
<translation id="4984339528288761049">Prc5 (Envelope)</translation>
<translation id="4989163558385430922">Ver tudo</translation>
@@ -1288,12 +1323,12 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="5040262127954254034">Privacidade</translation>
<translation id="5043480802608081735">Link que copiou</translation>
<translation id="5045550434625856497">Palavra-passe incorrecta</translation>
-<translation id="5056425809654826431">{NUM_FILES,plural, =1{Para enviar este ficheiro através da funcionalidade Partilhar na proximidade, liberte espaço (<ph name="DISK_SPACE_SIZE" />) no seu dispositivo}one{Para enviar este(s) ficheiro(s) através da funcionalidade Partilhar na proximidade, liberte espaço (<ph name="DISK_SPACE_SIZE" />) no seu dispositivo}other{Para enviar estes ficheiros através da funcionalidade Partilhar na proximidade, liberte espaço (<ph name="DISK_SPACE_SIZE" />) no seu dispositivo}}</translation>
+<translation id="5056425809654826431">{NUM_FILES,plural, =1{Para enviar este ficheiro através da funcionalidade Partilhar na proximidade, liberte espaço (<ph name="DISK_SPACE_SIZE" />) no seu dispositivo}other{Para enviar estes ficheiros através da funcionalidade Partilhar na proximidade, liberte espaço (<ph name="DISK_SPACE_SIZE" />) no seu dispositivo}}</translation>
<translation id="5056549851600133418">Artigos para si</translation>
<translation id="5061227663725596739">Será que quis dizer <ph name="LOOKALIKE_DOMAIN" />?</translation>
<translation id="5066056036849835175">Histórico de impressão</translation>
<translation id="5068524481479508725">A10</translation>
-<translation id="5068778127327928576">{NUM_COOKIES,plural, =1{(1 em utilização)}one{(# em utilização)}other{(# em utilização)}}</translation>
+<translation id="5068778127327928576">{NUM_COOKIES,plural, =1{(1 em utilização)}other{(# em utilização)}}</translation>
<translation id="5070335125961472645"><ph name="BEGIN_LINK" />Verificar o endereço proxy<ph name="END_LINK" /></translation>
<translation id="5070838744279127212">Décimo rolo</translation>
<translation id="507130231501693183">Caixa de correio 4</translation>
@@ -1323,6 +1358,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="5138227688689900538">Mostrar menos</translation>
<translation id="5145883236150621069">Código de erro presente na resposta da política</translation>
<translation id="5146995429444047494">As notificações de <ph name="ORIGIN" /> estão bloqueadas</translation>
+<translation id="514704532284964975"><ph name="URL" /> quer ver e alterar informações em dispositivos NFC nos quais toca com o telemóvel</translation>
<translation id="5148809049217731050">Com orientação para cima</translation>
<translation id="515292512908731282">C4 (Envelope)</translation>
<translation id="5158275234811857234">Capa</translation>
@@ -1337,7 +1373,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="5172758083709347301">Equipamento</translation>
<translation id="5179510805599951267">Não está em <ph name="ORIGINAL_LANGUAGE" />? Comunicar este erro</translation>
<translation id="5190835502935405962">Barra de marcadores</translation>
-<translation id="51918995459521422"><ph name="ORIGIN" /> pretende transferir vários ficheiros.</translation>
+<translation id="51918995459521422"><ph name="ORIGIN" /> quer transferir vários ficheiros.</translation>
<translation id="519422657042045905">As notas não estão disponíveis.</translation>
<translation id="5201306358585911203">Uma página incorporada nesta página diz</translation>
<translation id="5204468114771111727">O Chrome encontrou a palavra-passe que acabou de utilizar numa violação de dados. O Assistente Google pode alterar a sua palavra-passe automaticamente.</translation>
@@ -1347,6 +1383,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="5215116848420601511">Métodos de pagamento e endereços do Google Pay</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">Tabuleiro 13</translation>
+<translation id="5216942107514965959">Última visita hoje</translation>
<translation id="5222812217790122047">Email obrigatório</translation>
<translation id="5230733896359313003">Endereço de envio</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1367,7 +1404,6 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">Propriedades do documento</translation>
<translation id="528468243742722775">Sair</translation>
-<translation id="5284909709419567258">Endereços de rede</translation>
<translation id="5285570108065881030">Mostrar todas as palavras-passe guardadas</translation>
<translation id="5287240709317226393">Mostrar cookies</translation>
<translation id="5287456746628258573">Este site utiliza uma configuração de segurança desatualizada, que pode expor as suas informações (por exemplo, palavras-passe ou números de cartões de crédito) quando são enviados para este site.</translation>
@@ -1419,7 +1455,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="5452270690849572955">Não é possível encontrar esta página de <ph name="HOST_NAME" /></translation>
<translation id="5455374756549232013">Carimbo de data/hora da política incorreto</translation>
<translation id="5457113250005438886">Inválido</translation>
-<translation id="5458150163479425638">{CONTACT,plural, =0{<ph name="CONTACT_PREVIEW" />}=1{<ph name="CONTACT_PREVIEW" /> e mais <ph name="NUMBER_OF_ADDITIONAL_CONTACTS" />}one{<ph name="CONTACT_PREVIEW" /> e mais <ph name="NUMBER_OF_ADDITIONAL_CONTACTS" />}other{<ph name="CONTACT_PREVIEW" /> e mais <ph name="NUMBER_OF_ADDITIONAL_CONTACTS" />}}</translation>
+<translation id="5458150163479425638">{CONTACT,plural, =0{<ph name="CONTACT_PREVIEW" />}=1{<ph name="CONTACT_PREVIEW" /> e mais <ph name="NUMBER_OF_ADDITIONAL_CONTACTS" />}other{<ph name="CONTACT_PREVIEW" /> e mais <ph name="NUMBER_OF_ADDITIONAL_CONTACTS" />}}</translation>
<translation id="5463625433003343978">A localizar dispositivos…</translation>
<translation id="5469868506864199649">Italiano</translation>
<translation id="5470861586879999274">&amp;Refazer edição</translation>
@@ -1451,6 +1487,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="5556459405103347317">Recarregar</translation>
<translation id="5560088892362098740">Data de validade</translation>
<translation id="55635442646131152">Contorno do documento</translation>
+<translation id="5565613213060953222">Abrir separador de navegação anónima</translation>
<translation id="5565735124758917034">Ativo</translation>
<translation id="5570825185877910964">Proteger conta</translation>
<translation id="5571083550517324815">Não é possível recolher a partir deste endereço. Selecione um diferente.</translation>
@@ -1497,9 +1534,9 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="5720705177508910913">Utilizador atual</translation>
<translation id="5728056243719941842">C5 (Envelope)</translation>
<translation id="5730040223043577876">O Chrome recomenda a reposição da palavra-passe se a tiver reutilizado noutros sites.</translation>
-<translation id="5737183892635480227">{NUM_CARDS,plural, =1{Guardar o cartão na sua Conta Google}one{Guardar o(s) cartão(ões) na sua Conta Google}other{Guardar os cartões na sua Conta Google}}</translation>
+<translation id="5737183892635480227">{NUM_CARDS,plural, =1{Guardar o cartão na sua Conta Google}other{Guardar os cartões na sua Conta Google}}</translation>
<translation id="5745733273847572235">Pode solicitar a sua localização</translation>
-<translation id="5745980000221562234">{NUM_CARDS,plural, =1{Utilize um número virtual para este cartão}one{Selecione um cartão}other{Selecione um cartão}}</translation>
+<translation id="5745980000221562234">{NUM_CARDS,plural, =1{Utilize um número virtual para este cartão}other{Selecione um cartão}}</translation>
<translation id="5759751709240058861">Utilizar e mover a sua câmara</translation>
<translation id="5763042198335101085">Introduza um endereço de email válido</translation>
<translation id="5765072501007116331">Para ver os métodos de fornecimento e os requisitos, selecione um endereço</translation>
@@ -1519,7 +1556,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="5812947184178430888">Quando o Chrome sinaliza eventos de segurança, são enviados dados relevantes acerca dos eventos ao seu administrador. Estes podem incluir os URLs das páginas que visita no Chrome, os metadados ou os nomes de ficheiros e o nome de utilizador que utiliza para iniciar sessão nas aplicações baseadas na Web, no dispositivo e no Chrome.</translation>
<translation id="5813119285467412249">&amp;Refazer adição</translation>
<translation id="5817918615728894473">Sincronizar</translation>
-<translation id="5824687817967109979">{NUM_CARDS,plural, =1{Será efetuada uma cobrança neste cartão quando pagar, mas o respetivo número verdadeiro não será partilhado com este site. Como medida de segurança adicional, será gerado um CVC temporário.}one{Será efetuada uma cobrança no cartão que selecionar quando pagar, mas o respetivo número verdadeiro não será partilhado com este site. Como medida de segurança adicional, será gerado um CVC temporário.}other{Será efetuada uma cobrança no cartão que selecionar quando pagar, mas o respetivo número verdadeiro não será partilhado com este site. Como medida de segurança adicional, será gerado um CVC temporário.}}</translation>
+<translation id="5824687817967109979">{NUM_CARDS,plural, =1{Será efetuada uma cobrança neste cartão quando pagar, mas o respetivo número verdadeiro não será partilhado com este site. Como medida de segurança adicional, será gerado um CVC temporário.}other{Será efetuada uma cobrança no cartão que selecionar quando pagar, mas o respetivo número verdadeiro não será partilhado com este site. Como medida de segurança adicional, será gerado um CVC temporário.}}</translation>
<translation id="5826507051599432481">Nome comum (CN)</translation>
<translation id="5830698870816298009">utilização e movimento da câmara</translation>
<translation id="5838278095973806738">Não deve introduzir informações confidenciais neste site (por exemplo, palavras-passe ou números de cartões de crédito), porque podem ser roubadas por atacantes.</translation>
@@ -1533,6 +1570,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="5869522115854928033">Palavras-passe guardadas</translation>
<translation id="5873013647450402046">O banco quer confirmar a sua identidade.</translation>
<translation id="5887400589839399685">Cartão guardado</translation>
+<translation id="5887687176710214216">Última visita ontem</translation>
<translation id="5895138241574237353">Reiniciar</translation>
<translation id="5895187275912066135">Emitido em</translation>
<translation id="5901630391730855834">Amarelo</translation>
@@ -1541,11 +1579,12 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="5908541034548427511"><ph name="TYPE_1" /> (sincronizados)</translation>
<translation id="59174027418879706">Ativada</translation>
<translation id="5919090499915321845">B10</translation>
-<translation id="5920262536204764679">{NUM_COOKIES,plural, =1{1 em utilização}one{# in use}other{# em utilização}}</translation>
+<translation id="5920262536204764679">{NUM_COOKIES,plural, =1{1 em utilização}other{# em utilização}}</translation>
<translation id="5921185718311485855">Ativado</translation>
<translation id="5921639886840618607">Pretende guardar o cartão na Conta Google?</translation>
<translation id="5922853866070715753">Estamos quase a terminar</translation>
<translation id="5932224571077948991">O site apresenta anúncios intrusivos ou enganadores.</translation>
+<translation id="5938153366081463283">Adicione um cartão virtual</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347">A abrir <ph name="SITE_NAME" />…</translation>
<translation id="5951495562196540101">Não é possível inscrever-se com conta de consumidor (licença incluída disponível).</translation>
@@ -1610,6 +1649,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="6120179357481664955">Lembra-se do seu ID do UPI?</translation>
<translation id="6124432979022149706">Conetores do Chrome Enterprise</translation>
<translation id="6127379762771434464">Item removido</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Saiba mais sobre a Navegação anónima no Chrome<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">Verifique os cabos e reinicie todos os routers, modems ou outros
dispositivos de rede que possa estar a utilizar.</translation>
<translation id="614940544461990577">Experimente:</translation>
@@ -1622,7 +1662,6 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="6169916984152623906">Agora, pode navegar em privado e as outras pessoas que utilizarem este dispositivo não veem a sua atividade. No entanto, as transferências e os marcadores são guardados.</translation>
<translation id="6177128806592000436">A sua ligação a este site não é segura</translation>
<translation id="6180316780098470077">Intervalo entre tentativas</translation>
-<translation id="619448280891863779">Pode solicitar a abertura e colocação de janelas nos seus ecrãs</translation>
<translation id="6196640612572343990">Bloquear cookies de terceiros</translation>
<translation id="6203231073485539293">Verificar a ligação à Internet</translation>
<translation id="6218753634732582820">Remover o endereço do Chromium?</translation>
@@ -1645,7 +1684,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="6272383483618007430">Google Update</translation>
<translation id="6276112860590028508">As páginas da sua lista de leitura aparecem aqui</translation>
<translation id="627746635834430766">Para pagar mais rapidamente da próxima vez, guarde o cartão e o endereço de faturação na sua Conta Google.</translation>
-<translation id="6279098320682980337">O número do cartão virtual não foi preenchido? Clique nos detalhes do cartão para copiar</translation>
+<translation id="6279183038361895380">Premir |<ph name="ACCELERATOR" />| para mostrar o cursor</translation>
<translation id="6280223929691119688">Não é possível entregar neste endereço. Selecione um diferente.</translation>
<translation id="6282194474023008486">Código postal</translation>
<translation id="6285507000506177184">Botão Gerir transferências no Chrome, prima Enter para gerir os ficheiros que transferiu no Chrome</translation>
@@ -1653,6 +1692,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="6290238015253830360">Os seus artigos sugeridos são apresentados aqui</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">Código de segurança:</translation>
+<translation id="6300452962057769623">{0,plural, =0{O seu dispositivo será reiniciado agora}=1{O seu dispositivo será reiniciado dentro de 1 segundo}other{O seu dispositivo será reiniciado dentro de # segundos}}</translation>
<translation id="6302269476990306341">Paragem do Assistente Google no Chrome</translation>
<translation id="6305205051461490394"><ph name="URL" /> está inacessível.</translation>
<translation id="6312113039770857350">Página Web não disponível</translation>
@@ -1666,7 +1706,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="6337534724793800597">Filtrar políticas pelo nome</translation>
<translation id="6340739886198108203">A política do administrador não recomenda fazer capturas de ecrã nem gravações quando existe conteúdo confidencial visível:</translation>
<translation id="6349101878882523185">Instale a aplicação <ph name="APP_NAME" /></translation>
-<translation id="6353505687280762741">{COUNT,plural, =0{Nenhuma}=1{1 palavra-passe (de <ph name="DOMAIN_LIST" />, sincronizada)}=2{2 palavras-passe (de <ph name="DOMAIN_LIST" />, sincronizadas)}one{# palavra(s)-passe (de <ph name="DOMAIN_LIST" />, sincronizada(s))}other{# palavras-passe (de <ph name="DOMAIN_LIST" />, sincronizadas)}}</translation>
+<translation id="6353505687280762741">{COUNT,plural, =0{Nenhuma}=1{1 palavra-passe (de <ph name="DOMAIN_LIST" />, sincronizada)}=2{2 palavras-passe (de <ph name="DOMAIN_LIST" />, sincronizadas)}other{# palavras-passe (de <ph name="DOMAIN_LIST" />, sincronizadas)}}</translation>
<translation id="6355392890578844978">Este navegador não é gerido por uma empresa ou outra entidade. A atividade neste dispositivo pode ser gerida fora do Chromium. <ph name="BEGIN_LINK" />Saiba mais<ph name="END_LINK" /></translation>
<translation id="6358450015545214790">O que significam?</translation>
<translation id="6361757823711327522">B7</translation>
@@ -1675,7 +1715,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="6377268785556383139">1 resultado para "<ph name="SEARCH_TEXT" />"</translation>
<translation id="6380497234672085559">A0</translation>
<translation id="6383221683286411806">Possíveis cobranças se prosseguir.</translation>
-<translation id="6386120369904791316">{COUNT,plural, =1{1 outra sugestão}one{# other suggestions}other{# outras sugestões}}</translation>
+<translation id="6386120369904791316">{COUNT,plural, =1{1 outra sugestão}other{# outras sugestões}}</translation>
<translation id="6387645831795005740">Por vezes, os atacantes imitam sites ao efetuarem alterações pequenas e difíceis de detetar no URL.</translation>
<translation id="6389470377220713856">Nome no cartão</translation>
<translation id="6390200185239044127">Dobrar metade em Z</translation>
@@ -1726,6 +1766,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="6529602333819889595">&amp;Refazer eliminação</translation>
<translation id="6545864417968258051">Procura de Bluetooth</translation>
<translation id="6547208576736763147">Perfuração dupla à esquerda</translation>
+<translation id="6554732001434021288">Última visita há <ph name="NUM_DAYS" /> dias</translation>
<translation id="6556866813142980365">Refazer</translation>
<translation id="6569060085658103619">Está a ver a página de uma extensão</translation>
<translation id="6573200754375280815">Perfuração dupla à direita</translation>
@@ -1748,7 +1789,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="663260587451432563">JIS B4</translation>
<translation id="6643016212128521049">Limpar</translation>
<translation id="6645291930348198241">Aceder aos cookies e dados de sites.</translation>
-<translation id="6646269444027925224">{COUNT,plural, =0{Nenhum}=1{De 1 site (a sessão na sua Conta Google não é terminada).}one{From # sites (you won't be signed out of your Google Account)}other{De # sites (a sessão na sua Conta Google não é terminada).}}</translation>
+<translation id="6646269444027925224">{COUNT,plural, =0{Nenhum}=1{De 1 site (a sessão na sua Conta Google não é terminada).}other{De # sites (a sessão na sua Conta Google não é terminada).}}</translation>
<translation id="6648459603387803038">O administrador pode alterar a configuração do navegador remotamente. A atividade neste dispositivo também pode ser gerida fora do Chrome.</translation>
<translation id="6648524591329069940">Tipo de letra Serif</translation>
<translation id="6651270836885078973">Gerido por:</translation>
@@ -1786,7 +1827,6 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="6757797048963528358">O dispositivo entrou em suspensão.</translation>
<translation id="6767985426384634228">Pretende atualizar o endereço?</translation>
<translation id="6768213884286397650">Hagaki (Postcard)</translation>
-<translation id="6774185088257932239"><ph name="BEGIN_LINK" />Saiba mais<ph name="END_LINK" /> sobre a Navegação anónima</translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">Violeta</translation>
<translation id="6786747875388722282">Extensões</translation>
@@ -1863,14 +1903,13 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="7031646650991750659">As apps do Google Play que instalou.</translation>
<translation id="7038063300915481831"><ph name="MANAGE_GOOGLE_PRIVACY_FOCUSED_FRIENDLY_MATCH_TEXT" />, prima Tab e, em seguida, Enter para gerir as definições de privacidade da sua Conta Google</translation>
<translation id="7050187094878475250">Tentou aceder a <ph name="DOMAIN" />, mas o servidor apresentou um certificado cujo período de validade é demasiado longo para ser fidedigno.</translation>
-<translation id="705310974202322020">{NUM_CARDS,plural, =1{De momento, não é possível guardar este cartão.}one{De momento, não é possível guardar este(s) cartão(ões).}other{De momento, não é possível guardar estes cartões.}}</translation>
+<translation id="705310974202322020">{NUM_CARDS,plural, =1{De momento, não é possível guardar este cartão.}other{De momento, não é possível guardar estes cartões.}}</translation>
<translation id="7053983685419859001">Bloquear</translation>
<translation id="7058163556978339998">O <ph name="BROWSER" /> confirmou que a <ph name="ISSUER" /> emitiu o certificado deste Website.</translation>
<translation id="7062635574500127092">Azul esverdeado</translation>
<translation id="706295145388601875">Adicione e faça a gestão de endereços nas Definições do Chrome.</translation>
<translation id="7064851114919012435">Informações de contacto</translation>
<translation id="7068733155164172741">Introduza um código de <ph name="OTP_LENGTH" /> dígitos</translation>
-<translation id="7070090581017165256">Acerca deste site</translation>
<translation id="70705239631109039">A sua ligação não é totalmente segura</translation>
<translation id="7075452647191940183">O pedido é demasiado grande.</translation>
<translation id="7079718277001814089">Este site contém um software malicioso</translation>
@@ -1887,6 +1926,12 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="7111012039238467737">(Válido)</translation>
<translation id="7118618213916969306">Pesquisar URL da área de transferência, <ph name="SHORT_URL" /></translation>
<translation id="7119414471315195487">Fechar outros separadores ou programas</translation>
+<translation id="7129355289156517987">Quando fechar todos os separadores de navegação anónima do Chromium, a sua atividade nesses separadores será limpa neste dispositivo:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Atividade de navegação<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Histórico de pesquisas<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Informações introduzidas em formulários<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">Não é possível enviar para este endereço. Selecione um diferente.</translation>
<translation id="7132939140423847331">O seu administrador proibiu a cópia destes dados.</translation>
<translation id="7135130955892390533">Mostrar estado</translation>
@@ -1895,12 +1940,12 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="7139892792842608322">Tabuleiro principal</translation>
<translation id="714064300541049402">Turno X da imagem 2 lateral</translation>
<translation id="7152423860607593928">Number-14 (Envelope)</translation>
-<translation id="7153549335910886479">{PAYMENT_METHOD,plural, =0{<ph name="PAYMENT_METHOD_PREVIEW" />}=1{<ph name="PAYMENT_METHOD_PREVIEW" /> e mais <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}one{<ph name="PAYMENT_METHOD_PREVIEW" /> e mais <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}other{<ph name="PAYMENT_METHOD_PREVIEW" /> e mais <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}}</translation>
+<translation id="7153549335910886479">{PAYMENT_METHOD,plural, =0{<ph name="PAYMENT_METHOD_PREVIEW" />}=1{<ph name="PAYMENT_METHOD_PREVIEW" /> e mais <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}other{<ph name="PAYMENT_METHOD_PREVIEW" /> e mais <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}}</translation>
<translation id="7153618581592392745">Lilás</translation>
<translation id="7156870133441232244">É necessário atualizar o servidor para a versão TLS 1.2 ou posterior.</translation>
<translation id="717330890047184534">ID Gaia:</translation>
<translation id="7174545416324379297">Unida</translation>
-<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" /> e mais <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}one{<ph name="SHIPPING_OPTION_PREVIEW" /> e mais <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}other{<ph name="SHIPPING_OPTION_PREVIEW" /> e mais <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}}</translation>
+<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" /> e mais <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}other{<ph name="SHIPPING_OPTION_PREVIEW" /> e mais <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}}</translation>
<translation id="7179323680825933600">Guardar e preencher métodos de pagamento</translation>
<translation id="7180611975245234373">Atualizar</translation>
<translation id="7181261019481237103">Abrir janela de navegação anónima</translation>
@@ -1909,6 +1954,7 @@ Se não permitir, isto será bloqueado pelas suas definições de privacidade. I
<translation id="7192203810768312527">Liberta <ph name="SIZE" />. É possível que alguns sites sejam carregados mais lentamente na sua próxima visita.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">O administrador pode ver:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, prima Tab e, em seguida, Enter para abrir um novo separador de navegação anónima para navegar em privado</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> não respeita os padrões de segurança.</translation>
<translation id="7210993021468939304">A atividade do Linux dentro do contentor, podendo instalar e executar apps para Linux no contentor.</translation>
@@ -1940,6 +1986,7 @@ Detalhes adicionais:
<translation id="7304562222803846232">Gerir definições de privacidade da Conta Google</translation>
<translation id="7305756307268530424">Iniciar mais lentamente</translation>
<translation id="7308436126008021607">sincronização em segundo plano</translation>
+<translation id="7310392214323165548">O dispositivo será reiniciado em breve</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">Ajuda para estabelecer ligação</translation>
<translation id="7323804146520582233">Ocultar a secção "<ph name="SECTION" />"</translation>
@@ -1947,6 +1994,7 @@ Detalhes adicionais:
<translation id="7334320624316649418">&amp;Refazer reordenação</translation>
<translation id="7335157162773372339">Pode solicitar a utilização da câmara</translation>
<translation id="7337248890521463931">Mostrar mais linhas</translation>
+<translation id="7337418456231055214">O número do cartão virtual não foi preenchido? Clique nos detalhes do cartão para copiar. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">Indisponível na sua plataforma.</translation>
<translation id="733923710415886693">O certificado do servidor não foi divulgado através da Transparência de certificados.</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1969,6 +2017,7 @@ Detalhes adicionais:
<translation id="7378627244592794276">Não</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">Não aplicável</translation>
+<translation id="7388594495505979117">{0,plural, =1{O seu dispositivo será reiniciado dentro de 1 minuto}other{O seu dispositivo será reiniciado dentro de # minutos}}</translation>
<translation id="7390545607259442187">Confirmar cartão</translation>
<translation id="7392089738299859607">Atualize o endereço</translation>
<translation id="7399802613464275309">Verificação de segurança</translation>
@@ -2004,6 +2053,12 @@ Detalhes adicionais:
<translation id="7485870689360869515">Não foram encontrados dados.</translation>
<translation id="7495528107193238112">Este conteúdo está bloqueado. Contacte o proprietário do site para corrigir o problema.</translation>
<translation id="7497998058912824456">Botão Criar documento prima Enter para criar rapidamente um novo Documento do Google Docs</translation>
+<translation id="7506488012654002225">O Chrome <ph name="BEGIN_EMPHASIS" />não guardará<ph name="END_EMPHASIS" /> as seguintes informações:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />O seu histórico de navegação
+ <ph name="LIST_ITEM" />Os cookies e os dados de sites
+ <ph name="LIST_ITEM" />As informações introduzidas em formulários
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">O ID do dispositivo da política devolvido está vazio ou não corresponde ao ID do dispositivo atual</translation>
<translation id="7508870219247277067">Verde abacate</translation>
<translation id="7511955381719512146">A rede Wi-Fi que está a utilizar pode exigir que visite <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
@@ -2051,7 +2106,7 @@ Detalhes adicionais:
<translation id="762844065391966283">Um item de cada vez</translation>
<translation id="7633909222644580952">Dados de desempenho e relatórios de falhas</translation>
<translation id="7637571805876720304">Remover o cartão de crédito do Chromium?</translation>
-<translation id="7637586430889951925">{COUNT,plural, =0{Nenhuma}=1{1 palavra-passe na sua conta (para <ph name="DOMAIN_LIST" />)}one{# palavra(s)-passe na sua conta (para <ph name="DOMAIN_LIST" />)}other{# palavras-passe na sua conta (para <ph name="DOMAIN_LIST" />)}}</translation>
+<translation id="7637586430889951925">{COUNT,plural, =0{Nenhuma}=1{1 palavra-passe na sua conta (para <ph name="DOMAIN_LIST" />)}other{# palavras-passe na sua conta (para <ph name="DOMAIN_LIST" />)}}</translation>
<translation id="7638605456503525968">Portas de série</translation>
<translation id="7639968568612851608">Cinzento-escuro</translation>
<translation id="7647206758853451655">Qualidade de impressão</translation>
@@ -2067,7 +2122,7 @@ Detalhes adicionais:
<translation id="7667346355482952095">O símbolo da política devolvido está vazio ou não corresponde ao símbolo atual</translation>
<translation id="7668654391829183341">Dispositivo desconhecido</translation>
<translation id="7669271284792375604">Os utilizadores mal intencionados neste site podem tentar enganá-lo para instalar programas que são prejudiciais para a sua experiência de navegação (por exemplo, ao alterar a sua página inicial ou ao mostrar anúncios adicionais em sites que visita).</translation>
-<translation id="7669907849388166732">{COUNT,plural, =1{Ações tomadas com dados sinalizados como confidenciais (1 ação desde o início de sessão). <ph name="BEGIN_LINK" />Saiba mais<ph name="END_LINK" />}one{Ações tomadas com dados sinalizados como confidenciais (# ação(ões) desde o início de sessão). <ph name="BEGIN_LINK" />Saiba mais<ph name="END_LINK" />}other{Ações tomadas com dados sinalizados como confidenciais (# ações desde o início de sessão). <ph name="BEGIN_LINK" />Saiba mais<ph name="END_LINK" />}}</translation>
+<translation id="7669907849388166732">{COUNT,plural, =1{Ações tomadas com dados sinalizados como confidenciais (1 ação desde o início de sessão). <ph name="BEGIN_LINK" />Saiba mais<ph name="END_LINK" />}other{Ações tomadas com dados sinalizados como confidenciais (# ações desde o início de sessão). <ph name="BEGIN_LINK" />Saiba mais<ph name="END_LINK" />}}</translation>
<translation id="7673278391011283842">Caixa de correio 6</translation>
<translation id="7676643023259824263">Pesquisar texto da área de transferência, <ph name="TEXT" /></translation>
<translation id="7679367271685653708">Veja e faça a gestão do histórico de navegação nas definições do Chrome</translation>
@@ -2117,10 +2172,9 @@ Detalhes adicionais:
<translation id="7813600968533626083">Remover a sugestão do formulário do Chrome?</translation>
<translation id="781440967107097262">Pretende partilhar a área de transferência?</translation>
<translation id="7815407501681723534">Encontrados <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> para "<ph name="SEARCH_STRING" />"</translation>
-<translation id="782125616001965242">Veja informações acerca deste site</translation>
<translation id="782886543891417279">A rede Wi-Fi que está a utilizar (<ph name="WIFI_NAME" />) pode exigir que visite a respetiva página de início de sessão.</translation>
<translation id="7836231406687464395">Postfix (Envelope)</translation>
-<translation id="7844689747373518809">{COUNT,plural, =0{Nenhuma}=1{1 aplicação (<ph name="EXAMPLE_APP_1" />)}=2{2 aplicações (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}one{# aplicação(ões) (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}other{# aplicações (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}}</translation>
+<translation id="7844689747373518809">{COUNT,plural, =0{Nenhuma}=1{1 aplicação (<ph name="EXAMPLE_APP_1" />)}=2{2 aplicações (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}other{# aplicações (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}}</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7862185352068345852">Pretende sair do site?</translation>
<translation id="7865448901209910068">A melhor velocidade</translation>
@@ -2134,7 +2188,6 @@ Detalhes adicionais:
<translation id="7888575728750733395">Imprimir intenção de renderização</translation>
<translation id="7894280532028510793">Se a ortografia estiver correta, <ph name="BEGIN_LINK" />experimente executar o Diagnóstico de rede<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (Envelope)</translation>
-<translation id="7931318309563332511">Desconhecido</translation>
<translation id="793209273132572360">Pretende atualizar o endereço?</translation>
<translation id="7932579305932748336">Revestir</translation>
<translation id="79338296614623784">Introduza um número de telefone válido</translation>
@@ -2159,16 +2212,17 @@ Detalhes adicionais:
<translation id="7976214039405368314">Demasiados pedidos</translation>
<translation id="7977538094055660992">Dispositivo de saída</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">Associado a</translation>
<translation id="798134797138789862">Pode solicitar a utilização de dados e dispositivos de realidade virtual</translation>
<translation id="7984945080620862648">De momento é possível visitar <ph name="SITE" /> porque o Website enviou credenciais codificadas que o Chrome não consegue processar. Os erros de rede e os ataques normalmente são temporários, por isso, esta página voltará provavelmente a funcionar.</translation>
-<translation id="79859296434321399">Para ver conteúdo de realidade aumentada, instale o ARCore.</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">Encadernar</translation>
<translation id="7992044431894087211">A partilha de ecrã com a aplicação <ph name="APPLICATION_TITLE" /> foi retomada.</translation>
<translation id="7995512525968007366">Não especificado</translation>
+<translation id="7998269595945679889">Botão Abrir separador de navegação anónima; prima Enter para abrir um novo separador de navegação anónima para navegar em privado</translation>
<translation id="800218591365569300">Experimente fechar outros separadores ou programas para libertar memória.</translation>
<translation id="8004582292198964060">Navegador</translation>
-<translation id="8012116502927253373">{NUM_CARDS,plural, =1{Este cartão e o respetivo endereço de faturação serão guardados. Pode utilizá-lo quando tiver sessão iniciada em <ph name="USER_EMAIL" />.}one{Este(s) cartão(ões) e o(s) respetivo(s) endereço(s) de faturação serão guardados. Pode utilizá-lo(s) quando tiver sessão iniciada em <ph name="USER_EMAIL" />.}other{Estes cartões e os respetivos endereços de faturação serão guardados. Pode utilizá-los quando tiver sessão iniciada em <ph name="USER_EMAIL" />.}}</translation>
+<translation id="8012116502927253373">{NUM_CARDS,plural, =1{Este cartão e o respetivo endereço de faturação serão guardados. Pode utilizá-lo quando tiver sessão iniciada em <ph name="USER_EMAIL" />.}other{Estes cartões e os respetivos endereços de faturação serão guardados. Pode utilizá-los quando tiver sessão iniciada em <ph name="USER_EMAIL" />.}}</translation>
<translation id="8025119109950072390">Os utilizadores mal intencionados neste site podem enganá-lo no sentido de fazer algo perigoso como instalar software ou revelar as suas informações pessoais (por exemplo, palavras-passe, números de telefone ou cartões de crédito).</translation>
<translation id="8026334261755873520">Limpar dados de navegação</translation>
<translation id="8027077570865220386">Tabuleiro 15</translation>
@@ -2225,6 +2279,7 @@ Detalhes adicionais:
<translation id="8202370299023114387">Conflito</translation>
<translation id="8206978196348664717">Prc4 (Envelope)</translation>
<translation id="8211406090763984747">A ligação é segura</translation>
+<translation id="8217240300496046857">Os sites não podem utilizar cookies que monitorizem a sua navegação na Web. As funcionalidades em alguns sites podem falhar.</translation>
<translation id="8218327578424803826">Localização atribuída:</translation>
<translation id="8220146938470311105">C7/C6 (Envelope)</translation>
<translation id="8225771182978767009">A pessoa que configurou este computador optou por bloquear este site.</translation>
@@ -2265,14 +2320,9 @@ Detalhes adicionais:
<translation id="830498451218851433">Dobrar a meio</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">Apps instaladas e a frequência com que são utilizadas.</translation>
+<translation id="8317207217658302555">Atualizar o ARCore?</translation>
<translation id="831997045666694187">Noite</translation>
<translation id="8321476692217554900">notificações</translation>
-<translation id="8328484624016508118">Após fechar todos os separadores de navegação anónima, o Chrome limpa:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />A sua atividade de navegação deste dispositivo<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />O seu histórico de pesquisas deste dispositivo<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />As informações introduzidas em formulários<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489">O acesso a <ph name="HOST_NAME" /> foi recusado</translation>
<translation id="833262891116910667">Realçar</translation>
<translation id="8339163506404995330">As páginas em <ph name="LANGUAGE" /> não serão traduzidas</translation>
@@ -2310,7 +2360,7 @@ Detalhes adicionais:
<translation id="8449836157089738489">Abrir tudo num novo grupo de separadores</translation>
<translation id="8457125768502047971">Indefinida</translation>
<translation id="8461694314515752532">Encriptar dados sincronizados com a sua própria frase de acesso de sincronização</translation>
-<translation id="8466379296835108687">{COUNT,plural, =1{1 cartão de crédito}one{# credit cards}other{# cartões de crédito}}</translation>
+<translation id="8466379296835108687">{COUNT,plural, =1{1 cartão de crédito}other{# cartões de crédito}}</translation>
<translation id="8473863474539038330">Endereços e mais</translation>
<translation id="8474910779563686872">Mostrar detalhes do programador</translation>
<translation id="8479754468255770962">Agrafo na parte inferior esquerda</translation>
@@ -2324,6 +2374,7 @@ Detalhes adicionais:
<translation id="8507227106804027148">Linha de comandos</translation>
<translation id="8508648098325802031">Ãcone de pesquisa</translation>
<translation id="8511402995811232419">Gerir cookies</translation>
+<translation id="8519753333133776369">Dispositivo HID permitido pelo seu administrador</translation>
<translation id="8522552481199248698">O Chrome pode ajudá-lo a proteger a sua Conta Google e a alterar a palavra-passe.</translation>
<translation id="8530813470445476232">Limpe o seu histórico de navegação, cookies, cache e muito mais nas definições do Chrome.</translation>
<translation id="8533619373899488139">Visite &lt;strong&gt;chrome://policy&lt;/strong&gt; para ver a lista dos URLs bloqueados e outras políticas aplicadas pelo administrador do sistema.</translation>
@@ -2332,10 +2383,9 @@ Detalhes adicionais:
<translation id="8542014550340843547">Agrafo triplo na parte inferior</translation>
<translation id="8543181531796978784">Pode <ph name="BEGIN_ERROR_LINK" />comunicar um problema de deteção<ph name="END_ERROR_LINK" /> ou, se compreende os riscos para a sua segurança, <ph name="BEGIN_LINK" />aceda a este site não seguro<ph name="END_LINK" />.</translation>
<translation id="8554010658308662631">Carregar mais</translation>
-<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{Repor autorização}one{Repor autorização(ões)}other{Repor autorizações}}</translation>
+<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{Repor autorização}other{Repor autorizações}}</translation>
<translation id="8555010941760982128">Utilize este código no pagamento</translation>
<translation id="8557066899867184262">O Código de Segurança/CVC está localizado no verso do cartão.</translation>
-<translation id="8558485628462305855">Para ver conteúdo de realidade aumentada, atualize o ARCore.</translation>
<translation id="8559762987265718583">Não é possível estabelecer uma ligação privada a <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />, porque a data e a hora do seu dispositivo (<ph name="DATE_AND_TIME" />) estão incorretas.</translation>
<translation id="8564182942834072828">Documentos separados/Cópias não agrupadas</translation>
<translation id="8564985650692024650">O Chromium recomenda a reposição da palavra-passe da <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> se a tiver reutilizado noutros sites.</translation>
@@ -2355,6 +2405,7 @@ Detalhes adicionais:
<translation id="865032292777205197">sensores de movimento</translation>
<translation id="8663226718884576429">Resumo da encomenda, <ph name="TOTAL_LABEL" />, mais detalhes</translation>
<translation id="8666678546361132282">Inglês</translation>
+<translation id="8669306706049782872">Utilizar informações acerca dos seus ecrãs para abrir e posicionar janelas</translation>
<translation id="867224526087042813">Assinatura</translation>
<translation id="8676424191133491403">Sem atraso</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, resposta, <ph name="ANSWER" /></translation>
@@ -2381,6 +2432,7 @@ Detalhes adicionais:
<translation id="8731544501227493793">Botão Gerir palavras-passe; prima Enter para ver e gerir as suas palavras-passes nas Definições do Chrome.</translation>
<translation id="8734529307927223492">O seu <ph name="DEVICE_TYPE" /> é gerido por <ph name="MANAGER" /></translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, prima Tab e, em seguida, Enter para abrir uma nova janela de navegação anónima para navegar em privado.</translation>
+<translation id="8737685506611670901">Abrir links de <ph name="PROTOCOL" /> em vez de <ph name="REPLACED_HANDLER_TITLE" /></translation>
<translation id="8738058698779197622">Para estabelecer uma ligação segura, o relógio tem de ser definido corretamente. Isto deve-se ao facto de os certificados que os Sites utilizam para se identificarem serem apenas válidos para períodos de tempo específicos. Uma vez que o relógio do seu dispositivo está incorreto, o Chromium não consegue validar estes certificados.</translation>
<translation id="8740359287975076522">Não foi possível encontrar o &lt;abbr id="dnsDefinition"&gt;endereço DNS&lt;/abbr&gt; de <ph name="HOST_NAME" />. Estamos a diagnosticar o problema.</translation>
<translation id="8742371904523228557"><ph name="ONE_TIME_CODE" /> é o seu código para <ph name="ORIGIN" />.</translation>
@@ -2408,6 +2460,7 @@ Detalhes adicionais:
<translation id="883848425547221593">Outros marcadores</translation>
<translation id="884264119367021077">Endereço para envio</translation>
<translation id="884923133447025588">Não foi encontrado qualquer mecanismo de revogação.</translation>
+<translation id="8849262850971482943">Utilize o seu cartão virtual para maior segurança</translation>
<translation id="885730110891505394">Partilha com a Google</translation>
<translation id="8858065207712248076">O Chrome recomenda a reposição da palavra-passe da <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> se a tiver reutilizado noutros sites.</translation>
<translation id="885906927438988819">Se a ortografia estiver correta, <ph name="BEGIN_LINK" />experimente executar o Diagnóstico de rede do Windows<ph name="END_LINK" />.</translation>
@@ -2457,6 +2510,7 @@ Detalhes adicionais:
<translation id="9004367719664099443">Sessão de RV em curso</translation>
<translation id="9005998258318286617">Falha ao carregar o documento PDF.</translation>
<translation id="9008201768610948239">Ignorar</translation>
+<translation id="901834265349196618">email</translation>
<translation id="9020200922353704812">Endereço de faturação do cartão necessário</translation>
<translation id="9020542370529661692">Esta página foi traduzida para <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9020742383383852663">A8</translation>
@@ -2505,6 +2559,7 @@ Detalhes adicionais:
<translation id="9150045010208374699">Utilizar a sua câmara</translation>
<translation id="9150685862434908345">O administrador pode alterar a configuração do navegador remotamente. A atividade neste dispositivo também pode ser gerida fora do Chrome. <ph name="BEGIN_LINK" />Saiba mais<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">Atualizado</translation>
+<translation id="9155211586651734179">Periféricos de áudio ligados</translation>
<translation id="9157595877708044936">A configurar...</translation>
<translation id="9158625974267017556">C6 (Envelope)</translation>
<translation id="9164029392738894042">Verificação da precisão</translation>
@@ -2543,7 +2598,7 @@ Detalhes adicionais:
<translation id="962484866189421427">Este conteúdo poderá tentar instalar aplicações fraudulentas que se fazem passar por algo diferente ou que recolhem dados que podem ser utilizados para o monitorizar. <ph name="BEGIN_LINK" />Mostrar, mesmo assim<ph name="END_LINK" /></translation>
<translation id="969892804517981540">Compilação oficial</translation>
<translation id="973773823069644502">Adicionar endereço de entrega</translation>
-<translation id="975560348586398090">{COUNT,plural, =0{Nenhum}=1{1 item}one{# itens}other{# itens}}</translation>
+<translation id="975560348586398090">{COUNT,plural, =0{Nenhum}=1{1 item}other{# itens}}</translation>
<translation id="981121421437150478">Offline</translation>
<translation id="984275831282074731">Métodos de pagamento</translation>
<translation id="985199708454569384">&lt;p&gt;Este erro é apresentado se a data e a hora do computador ou do dispositivo móvel estiverem erradas.&lt;/p&gt;
diff --git a/chromium/components/strings/components_strings_ro.xtb b/chromium/components/strings/components_strings_ro.xtb
index 725f654a722..2c36cb7b122 100644
--- a/chromium/components/strings/components_strings_ro.xtb
+++ b/chromium/components/strings/components_strings_ro.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">Vezi detaliile</translation>
<translation id="1030706264415084469"><ph name="URL" /> dorește să stocheze permanent cantități mari de date pe dispozitiv</translation>
<translation id="1032854598605920125">Rotește în sensul acelor de ceasornic</translation>
+<translation id="1033329911862281889">Modul incognito nu îți asigură invizibilitatea online:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />site-urile și serviciile pe care le folosesc știu când le accesezi;<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />angajatorii sau școlile pot să urmărească activitatea de navigare;<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />furnizorii de servicii de internet pot monitoriza traficul pe web.<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">Dezactivează</translation>
<translation id="1036982837258183574">Apasă pe |<ph name="ACCELERATOR" />| pentru a ieși din ecranul complet</translation>
<translation id="1038106730571050514">Afișează sugestii</translation>
<translation id="1038842779957582377">nume necunoscut</translation>
<translation id="1041998700806130099">Mesajul din foaia sarcinii</translation>
<translation id="1048785276086539861">Când editezi adnotări, acest document va reveni la afișarea cu o pagină</translation>
-<translation id="1049743911850919806">Incognito</translation>
<translation id="1050038467049342496">închide celelalte aplicații;</translation>
<translation id="1055184225775184556">&amp;Anulați adăugarea</translation>
<translation id="1056898198331236512">Avertisment</translation>
@@ -38,7 +43,7 @@
<translation id="1088860948719068836">Adaugă numele de pe card</translation>
<translation id="1089439967362294234">Schimbă parola</translation>
<translation id="1096545575934602868">Acest câmp nu poate să conțină mai mult de <ph name="MAX_ITEMS_LIMIT" /> intrări. Toate intrările suplimentare vor fi șterse.</translation>
-<translation id="1100782917270858593">Butonul Repetă experiența, apasă pe Enter pentru a repeta experiența și a vedea activitatea relevantă din istoricul Chrome</translation>
+<translation id="1100782917270858593">Butonul Continuă-ți parcursul, apasă pe Enter pentru a-ți continua parcursul și a vedea activitatea relevantă din istoricul Chrome</translation>
<translation id="1101672080107056897">Eroare privind acțiunea</translation>
<translation id="1103523840287552314">Tradu întotdeauna din <ph name="LANGUAGE" /></translation>
<translation id="1110994991967754504">Selectează permisiunea pentru <ph name="PERMISSION_NAME" /></translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">Memoria cache pentru politică este OK</translation>
<translation id="1130564665089811311">Butonul Tradu pagina, apasă pe Enter pentru a traduce această pagină cu Google Traducere</translation>
<translation id="1131264053432022307">Imaginea copiată de tine</translation>
+<translation id="1142846828089312304">Blochează cookie-urile terță parte în modul incognito</translation>
<translation id="1150979032973867961">Acest server nu a putut dovedi că este <ph name="DOMAIN" />; sistemul de operare al computerului nu consideră că certificatul său de securitate este de încredere. Cauza poate fi o configurare greșită sau interceptarea conexiunii de către un atacator.</translation>
<translation id="1151972924205500581">Trebuie să introduceți o parolă</translation>
<translation id="1156303062776767266">Se afișează un fișier local sau comun</translation>
@@ -64,7 +70,6 @@
<translation id="1178581264944972037">ÃŽntrerupe</translation>
<translation id="1181037720776840403">Elimină</translation>
<translation id="1186201132766001848">Verifică parolele</translation>
-<translation id="1195210374336998651">Accesează setările aplicației</translation>
<translation id="1195558154361252544">Notificările sunt blocate automat pentru toate site-urile, cu excepția celor pe care le accepți</translation>
<translation id="1197088940767939838">Portocaliu</translation>
<translation id="1201402288615127009">ÃŽnainte</translation>
@@ -111,7 +116,7 @@
<translation id="1307966114820526988">Funcții învechite</translation>
<translation id="1308113895091915999">Ofertă disponibilă</translation>
<translation id="1312803275555673949">Ce dovezi există?</translation>
-<translation id="131405271941274527"><ph name="URL" /> dorește să trimită și să primească informații când atingi telefonul de pe un dispozitiv NFC</translation>
+<translation id="1314311879718644478">Vezi conținutul în realitatea augmentată</translation>
<translation id="1314509827145471431">Legare în dreapta</translation>
<translation id="1318023360584041678">Salvată în grupul de file</translation>
<translation id="1319245136674974084">Nu mai întreba pentru această aplicație</translation>
@@ -161,6 +166,7 @@
<translation id="142858679511221695">Utilizator de cloud</translation>
<translation id="1428729058023778569">Avertismentul se afișează deoarece acest site nu acceptă HTTPS. <ph name="BEGIN_LEARN_MORE_LINK" />Află mai multe<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">Printează</translation>
+<translation id="1432187715652018471">Pagina dorește să instaleze un handler de serviciu.</translation>
<translation id="1432581352905426595">Gestionați motoarele de căutare</translation>
<translation id="1436185428532214179">Poate solicita permisiunea de a modifica fișiere și dosare de pe dispozitiv</translation>
<translation id="1442386063175183758">Îndoire tip fereastră spre dreapta</translation>
@@ -181,6 +187,12 @@
<translation id="1483493594462132177">Trimite</translation>
<translation id="1484290072879560759">Alege adresa de expediere</translation>
<translation id="1492194039220927094">Notificări pentru politici:</translation>
+<translation id="149293076951187737">Când închizi toate filele incognito din Chrome, activitatea ta din acele file este ștearsă de pe dispozitiv:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />activitatea de navigare,<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />istoricul căutărilor<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />informațiile introduse în formulare.<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">Înpoi la filă</translation>
<translation id="1501859676467574491">Arată cardurile din Contul Google</translation>
<translation id="1507202001669085618">&lt;p&gt;Această eroare se va afișa dacă folosești un portal Wi-Fi la care trebuie să te conectezi înainte de a putea fi online.&lt;/p&gt;
@@ -208,6 +220,8 @@
<translation id="1559572115229829303">&lt;p&gt;O conexiune privată la <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> nu poate fi stabilită, deoarece data și ora dispozitivului (<ph name="DATE_AND_TIME" />) sunt incorecte.&lt;/p&gt;
&lt;p&gt;Corectează data și ora din secțiunea &lt;strong&gt;General&lt;/strong&gt; a aplicației &lt;strong&gt;Setări&lt;/strong&gt;.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">Administratorul îți va reporni dispozitivul la ora <ph name="TIME" />, pe <ph name="DATE" /></translation>
+<translation id="156703335097561114">Informații despre rețea cum ar fi adresele, configurația interfeței și calitatea conexiunii</translation>
<translation id="1567040042588613346">Politica funcționează corespunzător, dar în altă sursă a fost setată aceeași valoare, care este înlocuită prin această politică.</translation>
<translation id="1569487616857761740">Introdu data expirării</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@
<translation id="1583429793053364125">A apărut o eroare la afișarea paginii web.</translation>
<translation id="1586541204584340881">extensiile instalate;</translation>
<translation id="1588438908519853928">Normal</translation>
+<translation id="1589050138437146318">Instalezi ARCore?</translation>
<translation id="1592005682883173041">Accesul la datele locale</translation>
<translation id="1594030484168838125">Alegeți</translation>
<translation id="160851722280695521">Joacă jocul Dino Run în Chrome</translation>
@@ -283,6 +298,7 @@
antetul are o formă necorespunzătoare, ceea ce împiedică browserul să îți îndeplinească
solicitarea pentru <ph name="SITE" />. Politicile de origine pot fi folosite de
operatorii de site pentru a configura securitatea și alte proprietăți ale site-ului.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Află mai multe despre modul incognito în Chromium<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">Filele deschise sunt afișate aici</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -410,6 +426,7 @@
<translation id="22081806969704220">Tava 3</translation>
<translation id="2212735316055980242">Politica nu a fost găsită</translation>
<translation id="2213606439339815911">Se preiau intrările...</translation>
+<translation id="2213612003795704869">Pagina este printată</translation>
<translation id="2215727959747642672">Editează fișiere</translation>
<translation id="2218879909401188352">Atacatorii de pe <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ar putea să instaleze aplicații periculoase care deteriorează dispozitivul, adaugă costuri ascunse pe factura de telefonie mobilă sau îți fură informațiile cu caracter personal. <ph name="BEGIN_LEARN_MORE_LINK" />Află mai multe<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">Nu există conexiune la internet</translation>
@@ -419,6 +436,7 @@
<translation id="2248949050832152960">Folosește WebAuthn</translation>
<translation id="2250931979407627383">Broșare pe marginea din stânga</translation>
<translation id="225207911366869382">Valoarea este învechită pentru această politică.</translation>
+<translation id="2256115617011615191">Repornește acum</translation>
<translation id="2258928405015593961">Introdu o dată de expirare din viitor și încearcă din nou</translation>
<translation id="225943865679747347">Cod de eroare: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">Eroare HTTP</translation>
@@ -446,6 +464,7 @@
<translation id="2337852623177822836">Setare controlată de administrator</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> dorește să se asocieze</translation>
<translation id="2346319942568447007">Imaginea copiată de tine</translation>
+<translation id="2350796302381711542">Permiteți ca <ph name="HANDLER_HOSTNAME" /> să deschidă toate linkurile <ph name="PROTOCOL" /> în locul <ph name="REPLACED_HANDLER_TITLE" />?</translation>
<translation id="2354001756790975382">Alte marcaje</translation>
<translation id="2354430244986887761">Navigarea sigură Google <ph name="BEGIN_LINK" />a descoperit recent aplicații dăunătoare<ph name="END_LINK" /> pe <ph name="SITE" />.</translation>
<translation id="2355395290879513365">Este posibil ca atacatorii să poată vedea imaginile la care te uiți pe acest site și să te păcălească prin modificarea lor.</translation>
@@ -471,13 +490,15 @@
<translation id="2413528052993050574">Acest server nu a putut dovedi că este <ph name="DOMAIN" />; este posibil ca certificatul său de securitate să fie revocat. Cauza poate fi o configurare greșită sau interceptarea conexiunii de către un atacator.</translation>
<translation id="2414886740292270097">ÃŽntunecat</translation>
<translation id="2430968933669123598">Gestionează Contul Google, apasă pe Enter pentru a gestiona informațiile, confidențialitatea și securitatea Contului Google</translation>
+<translation id="2436186046335138073">Permiteți ca <ph name="HANDLER_HOSTNAME" /> să deschidă toate linkurile <ph name="PROTOCOL" />?</translation>
<translation id="2438874542388153331">Perforare cvadruplă în dreapta</translation>
-<translation id="2450021089947420533">Experiențe</translation>
+<translation id="2450021089947420533">Parcursuri</translation>
<translation id="2463739503403862330">Completează</translation>
<translation id="2465402087343596252">Architecture-E</translation>
<translation id="2465655957518002998">Alege metoda de livrare</translation>
<translation id="2465688316154986572">Capsare</translation>
<translation id="2465914000209955735">Gestionează fișierele pe care le-ai descărcat în Chrome</translation>
+<translation id="2466004615675155314">Afișează informații de pe web</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />să rulezi Diagnostice rețea<ph name="END_LINK" />;</translation>
<translation id="2469153820345007638">ÃŽn ordinea de la 1-la-N</translation>
<translation id="2470767536994572628">Când editezi adnotări, acest document va reveni la afișarea cu o pagină și la orientarea inițială</translation>
@@ -498,6 +519,7 @@
<translation id="2523886232349826891">Salvat numai pe acest dispozitiv</translation>
<translation id="2524461107774643265">Adaugă mai multe informații</translation>
<translation id="2529899080962247600">Acest câmp nu poate să conțină mai mult de <ph name="MAX_ITEMS_LIMIT" /> intrări. Intrările suplimentare vor fi ignorate.</translation>
+<translation id="2535585790302968248">Deschide o nouă filă incognito pentru a naviga în privat</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{și încă una}few{și încă #}other{și încă #}}</translation>
<translation id="2536110899380797252">Adaugă o adresă</translation>
<translation id="2539524384386349900">Detectează</translation>
@@ -523,7 +545,14 @@
<translation id="2597378329261239068">Acest document este protejat cu parolă. Introdu o parolă.</translation>
<translation id="2609632851001447353">Modificări</translation>
<translation id="2610561535971892504">Dă clic pentru a copia</translation>
+<translation id="2617988307566202237">Chrome <ph name="BEGIN_EMPHASIS" />nu va salva<ph name="END_EMPHASIS" /> următoarele informații:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />istoricul de navigare,
+ <ph name="LIST_ITEM" />cookie-urile și datele de pe site-uri,
+ <ph name="LIST_ITEM" />informațiile introduse în formulare.
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (Plic)</translation>
+<translation id="2623663032199728144">Poate solicita să folosească informații despre ecrane</translation>
<translation id="2625385379895617796">Ora este setată în viitor</translation>
<translation id="262745152991669301">Poate solicita permisiunea de a se conecta la dispozitive USB</translation>
<translation id="2629325967560697240">Pentru a beneficia de cel mai înalt nivel de securitate, <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />activează protecția îmbunătățită<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -557,6 +586,7 @@
<translation id="2709516037105925701">Completare automată</translation>
<translation id="2713444072780614174">Alb</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />, apasă pe Tab, apoi pe Enter pentru a gestiona informațiile despre plăți și carduri de credit în setările Chrome</translation>
+<translation id="271663710482723385">Apasă pe |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| pentru a ieși din ecranul complet</translation>
<translation id="2721148159707890343">Solicitarea a reușit</translation>
<translation id="2723669454293168317">Rulează o verificare de siguranță în setările Chrome</translation>
<translation id="2726001110728089263">Tava laterală</translation>
@@ -587,6 +617,7 @@
<translation id="2850739647070081192">Invite (Plic)</translation>
<translation id="2856444702002559011">Atacatorii pot încerca să îți fure informațiile de pe <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (de exemplu, parole, mesaje sau date despre cardurile de credit). <ph name="BEGIN_LEARN_MORE_LINK" />Află mai multe<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">Acest site afișează anunțuri deranjante sau înșelătoare.</translation>
+<translation id="286512204874376891">Cardul virtual îți maschează cardul fizic pentru a te proteja împotriva fraudelor. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">Amical</translation>
<translation id="2876489322757410363">Vei părăsi modul incognito pentru a plăti folosind o aplicație externă. Continui?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />, apasă pe Tab, apoi pe Enter pentru a gestiona Navigarea sigură și alte opțiuni din setările Chrome</translation>
@@ -611,6 +642,7 @@
<translation id="2930577230479659665">Decupare după fiecare exemplar</translation>
<translation id="2932085390869194046">Sugerează o parolă...</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019">Deschide linkurile <ph name="PROTOCOL" /></translation>
<translation id="2941952326391522266">Acest server nu a putut dovedi că este <ph name="DOMAIN" />; certificatul său de securitate provine de la <ph name="DOMAIN2" />. Cauza poate fi o configurare greșită sau interceptarea conexiunii de către un atacator.</translation>
<translation id="2943895734390379394">Ora încărcării:</translation>
<translation id="2948083400971632585">Puteți să dezactivați serverele proxy configurate pentru o conexiune din pagina de setări.</translation>
@@ -643,6 +675,7 @@
<translation id="3037605927509011580">Of, nu mai merge!</translation>
<translation id="3041612393474885105">Informații despre certificat</translation>
<translation id="3044034790304486808">Reia căutarea</translation>
+<translation id="305162504811187366">Istoricul Desktopului la distanță Chrome, inclusiv marcajele temporale, gazdele și ID-urile sesiunii de client</translation>
<translation id="3060227939791841287">C9 (Plic)</translation>
<translation id="3061707000357573562">Serviciu de corecție</translation>
<translation id="306573536155379004">Jocul a început.</translation>
@@ -683,6 +716,7 @@
<translation id="3197136577151645743">Poate solicita permisiunea de a afla când folosești activ dispozitivul</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />, apasă pe Tab, apoi pe Enter pentru a gestiona informațiile de sincronizat din setările Chrome</translation>
<translation id="320323717674993345">Anulează plata</translation>
+<translation id="3203366800380907218">De pe web</translation>
<translation id="3207960819495026254">Marcată</translation>
<translation id="3209034400446768650">Pagina poate percepe o taxă</translation>
<translation id="3212581601480735796">Activitatea ta de pe <ph name="HOSTNAME" /> este monitorizată</translation>
@@ -699,10 +733,12 @@
<translation id="3234666976984236645">Detectează întotdeauna conținutul important pe acest site</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />, apasă pe Tab, apoi pe Enter pentru a personaliza aspectul browserului</translation>
<translation id="3240791268468473923">Foaia „Datele de conectare pentru plăți securizate nu corespund datelor de conectare†este deschisă</translation>
+<translation id="324180406144491771">Linkurile <ph name="HOST_NAME" /> sunt blocate</translation>
<translation id="3249845759089040423">Șic</translation>
<translation id="3252266817569339921">Franceză</translation>
<translation id="3257954757204451555">De unde provin aceste informații?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />, apasă pe Tab, apoi pe Enter pentru a crea rapid un eveniment în Google Calendar</translation>
+<translation id="3261488570342242926">Află despre cardurile virtuale</translation>
<translation id="3264837738038045344">Butonul de gestionare a setărilor Chrome, apasă pe Enter pentru a accesa setările Chrome</translation>
<translation id="3266793032086590337">Valoare (conflictuală)</translation>
<translation id="3268451620468152448">File deschise</translation>
@@ -716,6 +752,7 @@
<translation id="3288238092761586174">Poate fi necesar ca <ph name="URL" /> să parcurgă câțiva pași suplimentari pentru a confirma plata</translation>
<translation id="3293642807462928945">Află mai multe despre politica <ph name="POLICY_NAME" /></translation>
<translation id="3295444047715739395">Afișează și gestionează parolele din setările Chrome</translation>
+<translation id="3303795387212510132">Permiți aplicației să deschidă linkuri <ph name="PROTOCOL_SCHEME" />?</translation>
<translation id="3303855915957856445">Nu s-au găsit rezultate de căutare</translation>
<translation id="3304073249511302126">căutarea Bluetooth</translation>
<translation id="3308006649705061278">Unitate organizațională (OU)</translation>
@@ -729,12 +766,6 @@
<translation id="3345782426586609320">Ochi</translation>
<translation id="3355823806454867987">Modifica setările proxy...</translation>
<translation id="3360103848165129075">Foaia handlerului pentru plăți</translation>
-<translation id="3361596688432910856">Chrome <ph name="BEGIN_EMPHASIS" />nu va salva<ph name="END_EMPHASIS" /> următoarele informații:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />istoricul de navigare;
- <ph name="LIST_ITEM" />cookie-urile și datele privind site-urile;
- <ph name="LIST_ITEM" />informațiile introduse în formulare.
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">Politica a fost copiată automat din politica învechită <ph name="OLD_POLICY" />. Ar trebui să folosești această politică.</translation>
<translation id="3364869320075768271"><ph name="URL" /> dorește să folosească dispozitivul tău de realitate virtuală și datele conexe</translation>
<translation id="3366477098757335611">Vezi cardurile</translation>
@@ -817,7 +848,6 @@
<translation id="3587738293690942763">Central</translation>
<translation id="3592413004129370115">Italian (Plic)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{Poți reseta oricând grupul. Durează aproximativ o zi să te alături unui alt grup.}=1{Poți reseta oricând grupul. Durează aproximativ o zi să te alături unui alt grup.}few{Poți reseta oricând grupul. Durează aproximativ {NUM_DAYS} zile să te alături unui alt grup.}other{Poți reseta oricând grupul. Durează aproximativ {NUM_DAYS} de zile să te alături unui alt grup.}}</translation>
-<translation id="3596012367874587041">Setările aplicației</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">Aplicația a fost blocată de administrator</translation>
<translation id="3608932978122581043">Orientarea alimentării</translation>
@@ -857,9 +887,10 @@
<translation id="3705189812819839667"><ph name="RESULT_OWNER" /> – <ph name="RESULT_PRODUCT_SOURCE" /></translation>
<translation id="370665806235115550">Se încarcă…</translation>
<translation id="3709599264800900598">Textul copiat de tine</translation>
-<translation id="370972442370243704">Activează Experiențe</translation>
+<translation id="370972442370243704">Activează Parcursuri</translation>
<translation id="3711895659073496551">Suspendați</translation>
<translation id="3712624925041724820">Licențe epuizate</translation>
+<translation id="3714633008798122362">calendar web</translation>
<translation id="3714780639079136834">să activezi datele mobile sau conexiunea Wi-Fi;</translation>
<translation id="3715597595485130451">Conectează-te la o rețea Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />să verifici configurarea pentru proxy, firewall și DNS;<ph name="END_LINK" /></translation>
@@ -921,6 +952,7 @@
<translation id="3906954721959377182">Tabletă</translation>
<translation id="3909477809443608991"><ph name="URL" /> vrea să redea conținut protejat. Identitatea dispozitivului tău va fi verificată de Google și poate fi accesată de acest site.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">Refuză</translation>
<translation id="3939773374150895049">Folosești WebAuthn în loc de CVC?</translation>
<translation id="3946209740501886391">Întreabă întotdeauna pe acest site</translation>
<translation id="3947595700203588284">Poate solicita permisiunea de a se conecta la dispozitive MIDI</translation>
@@ -942,6 +974,7 @@
<translation id="3990250421422698716">Decalaj de îndoire</translation>
<translation id="3996311196211510766">Site-ul <ph name="ORIGIN" /> a solicitat ca o politică de origine
să se aplice tuturor solicitărilor, dar această politică nu poate fi aplicată momentan.</translation>
+<translation id="4009243425692662128">Conținutul paginilor pe care le printezi este trimis la Google Cloud sau la terți spre analiză. De exemplu, se pot căuta date sensibile.</translation>
<translation id="4010758435855888356">Permiți accesul la spațiul de stocare?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{Document PDF cu {COUNT} pagină}few{Document PDF cu {COUNT} pagini}other{Document PDF cu {COUNT} de pagini}}</translation>
<translation id="4023431997072828269">Întrucât formularul este trimis printr-o conexiune care nu este securizată, informațiile tale vor vizibile pentru alte persoane.</translation>
@@ -1036,6 +1069,7 @@
<translation id="4250680216510889253">Nu</translation>
<translation id="4253168017788158739">Notă</translation>
<translation id="425582637250725228">Este posibil ca modificările să nu se salveze.</translation>
+<translation id="425869179292622354">Vrei să-l securizezi folosind un card virtual?</translation>
<translation id="4258748452823770588">Semnătură greșită</translation>
<translation id="4261046003697461417">Nu se pot face adnotări în documentele protejate</translation>
<translation id="4265872034478892965">Permisă de administrator</translation>
@@ -1098,6 +1132,7 @@
<translation id="4434045419905280838">Ferestre pop-up și redirecționări</translation>
<translation id="4435702339979719576">Carte poștală)</translation>
<translation id="443673843213245140">Utilizarea unui proxy este dezactivată, dar o configurare proxy este specificată în mod explicit.</translation>
+<translation id="4441832193888514600">Ignorată deoarece politica poate fi setată numai ca politică privind utilizatorii cloud.</translation>
<translation id="4450893287417543264">Nu mai afișa</translation>
<translation id="4451135742916150903">Poate solicita permisiunea de a se conecta la dispozitive HID</translation>
<translation id="4452328064229197696">Parola pe care tocmai ai folosit-o a fost găsită într-o încălcare a securității datelor. Pentru a-ți proteja conturile, Managerul de parole Google îți recomandă să verifici parolele salvate.</translation>
@@ -1121,7 +1156,7 @@
<translation id="4508814173490746936">Nu s-a putut folosi Touch ID</translation>
<translation id="4509074745930862522"><ph name="TRANSLATE_FOCUSED_FRIENDLY_MATCH_TEXT" />, apasă pe Tab, apoi pe Enter pentru a traduce această pagină cu Google Traducere</translation>
<translation id="4510487217173779431">Chou4 (Plic)</translation>
-<translation id="4514308731478712184">Dezactivează Experiențe</translation>
+<translation id="4514308731478712184">Dezactivează Parcursuri</translation>
<translation id="4515275063822566619">Cardurile și adresele sunt din Chrome și din Contul Google (<ph name="ACCOUNT_EMAIL" />). Poți să le gestionezi în <ph name="BEGIN_LINK" />Setări<ph name="END_LINK" />.</translation>
<translation id="4517607026994743406">Comm-10 (Plic)</translation>
<translation id="4521157617044179198"><ph name="WIDTH" /> × <ph name="HEIGHT" /> mm (<ph name="ORIENTATION" />)</translation>
@@ -1153,6 +1188,7 @@
<translation id="4628948037717959914">Fotografie</translation>
<translation id="4631649115723685955">Ofertă cu returnare de bani</translation>
<translation id="4636930964841734540">Informații</translation>
+<translation id="4638670630777875591">Modul incognito în Chromium</translation>
<translation id="464342062220857295">Funcții de căutare</translation>
<translation id="4644670975240021822">În ordine inversă, cu fața în jos</translation>
<translation id="4646534391647090355">Accesez acum</translation>
@@ -1173,6 +1209,7 @@
<translation id="4708268264240856090">Conexiunea a fost întreruptă</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />să rulezi Diagnostice rețea Windows<ph name="END_LINK" />;</translation>
+<translation id="4722735765955348426">Parola pentru <ph name="USERNAME" /></translation>
<translation id="4724144314178270921">Poate solicita permisiunea să vadă text și imagini din clipboard</translation>
<translation id="4726672564094551039">Reîncărcați politicile</translation>
<translation id="4728558894243024398">Platformă</translation>
@@ -1194,6 +1231,7 @@
<translation id="4757993714154412917">Ai introdus parola pe un site înșelător. Pentru a-ți proteja conturile, Chromium recomandă să verifici parolele salvate.</translation>
<translation id="4758311279753947758">Adaugă informații de contact</translation>
<translation id="4761104368405085019">Utilizează microfonul</translation>
+<translation id="4761869838909035636">Rulează verificarea de siguranță pentru Chrome</translation>
<translation id="4764776831041365478">Pagina web de la <ph name="URL" /> poate fi temporar nefuncțională sau a fost mutată definitiv la o nouă adresă web.</translation>
<translation id="4766713847338118463">Capsare dublă în partea de jos</translation>
<translation id="4771973620359291008">A apărut o eroare necunoscută.</translation>
@@ -1214,12 +1252,6 @@
<translation id="4819347708020428563">Editezi adnotările în afișarea prestabilită?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />, apasă pe Tab, apoi pe Enter pentru a crea rapid o Foaie de calcul Google</translation>
<translation id="4825507807291741242">Puternic</translation>
-<translation id="4827402517081186284">Modul incognito nu îți asigură invizibilitatea online:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />site-urile știu când le accesezi;<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />angajatorii sau școlile pot să urmărească activitatea de navigare;<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />furnizorii de servicii de internet pot monitoriza traficul pe web.<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">Activează avertizările</translation>
<translation id="4838327282952368871">Visare</translation>
<translation id="4840250757394056958">Vezi istoricul Chrome</translation>
@@ -1231,12 +1263,12 @@
<translation id="4854362297993841467">Această metodă de livrare nu este disponibilă. Încearcă altă metodă.</translation>
<translation id="4854853140771946034">Creează rapid o notă în Google Keep</translation>
<translation id="485902285759009870">Codul se verifică...</translation>
+<translation id="4866506163384898554">Apasă pe |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| pentru a afișa cursorul</translation>
<translation id="4876188919622883022">Afișare simplificată</translation>
<translation id="4876305945144899064">Niciun nume de utilizator</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{Niciuna}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}few{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831">Căutare <ph name="TEXT" /></translation>
<translation id="4879491255372875719">Automat (prestabilit)</translation>
-<translation id="4879725228911483934">să deschidă și să plaseze ferestre în ecrane.</translation>
<translation id="4880827082731008257">Caută în istoric</translation>
<translation id="4881695831933465202">Deschide</translation>
<translation id="4885256590493466218">Plătești cu <ph name="CARD_DETAIL" /> la finalizarea achiziției</translation>
@@ -1245,6 +1277,7 @@
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">A noua rolă</translation>
<translation id="4901778704868714008">Salvează...</translation>
+<translation id="4905659621780993806">Administratorul îți va reporni dispozitivul automat la ora <ph name="TIME" />, pe <ph name="DATE" />. Salvează elementele deschise înainte ca dispozitivul să repornească.</translation>
<translation id="4913987521957242411">Perforare în stânga sus</translation>
<translation id="4918221908152712722">Instalează <ph name="APP_NAME" /> (nu necesită descărcare)</translation>
<translation id="4923459931733593730">Plată</translation>
@@ -1253,6 +1286,7 @@
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, apasă pe Tab, apoi pe Enter pentru a căuta</translation>
<translation id="4930153903256238152">Capacitate mare</translation>
+<translation id="4940163644868678279">Modul incognito în Chrome</translation>
<translation id="4943872375798546930">Nu există rezultate</translation>
<translation id="4950898438188848926">Butonul Comută între file, apasă pe Enter pentru a comuta la fila deschisă, <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="495170559598752135">Acțiuni</translation>
@@ -1262,6 +1296,7 @@
<translation id="4968522289500246572">Aplicația este creată pentru dispozitive mobile și poate să nu fie redimensionată corect. Poate să aibă erori sau să repornească.</translation>
<translation id="4969341057194253438">Șterge înregistrarea</translation>
<translation id="4973922308112707173">Perforare dublă în partea de sus</translation>
+<translation id="4976702386844183910">Accesat ultima dată pe <ph name="DATE" /></translation>
<translation id="4984088539114770594">Folosești microfonul?</translation>
<translation id="4984339528288761049">Prc5 (Plic)</translation>
<translation id="4989163558385430922">Afișează-le pe toate</translation>
@@ -1323,6 +1358,7 @@
<translation id="5138227688689900538">Afișează mai puțin</translation>
<translation id="5145883236150621069">Răspunsul pentru politică include un cod de eroare</translation>
<translation id="5146995429444047494">Notificările pentru <ph name="ORIGIN" /> sunt blocate</translation>
+<translation id="514704532284964975"><ph name="URL" /> solicită să vadă și să modifice informații de pe un dispozitiv NFC când atingi pe telefon</translation>
<translation id="5148809049217731050">Cu fața în sus</translation>
<translation id="515292512908731282">C4 (Plic)</translation>
<translation id="5158275234811857234">Copertă</translation>
@@ -1347,6 +1383,7 @@
<translation id="5215116848420601511">Metodele de plată și adresele care folosesc Google Pay</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">Tava 13</translation>
+<translation id="5216942107514965959">Accesat ultima dată azi</translation>
<translation id="5222812217790122047">Adresa de e-mail este obligatorie</translation>
<translation id="5230733896359313003">Adresă de expediere</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1367,7 +1404,6 @@
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">Proprietățile documentului</translation>
<translation id="528468243742722775">Oprește</translation>
-<translation id="5284909709419567258">Adrese de rețea</translation>
<translation id="5285570108065881030">Afișează toate parolele salvate</translation>
<translation id="5287240709317226393">Afișați cookie-urile</translation>
<translation id="5287456746628258573">Site-ul folosește o configurație de securitate învechită, care îți poate expune informațiile (de exemplu, parolele sau numerele cardurilor de credit) când sunt trimise la acest site.</translation>
@@ -1451,6 +1487,7 @@
<translation id="5556459405103347317">Reîncarcă</translation>
<translation id="5560088892362098740">Data expirării</translation>
<translation id="55635442646131152">Schița documentului</translation>
+<translation id="5565613213060953222">Deschide o filă incognito</translation>
<translation id="5565735124758917034">Activ</translation>
<translation id="5570825185877910964">Protejează contul</translation>
<translation id="5571083550517324815">Nu se poate prelua de la această adresă. Selectează altă adresă.</translation>
@@ -1491,7 +1528,7 @@
<translation id="5695542892312572833">Folosești Windows Hello ca să confirmi și finalizezi achiziția?</translation>
<translation id="5701381305118179107">Pe centru</translation>
<translation id="570530837424789914">Gestionează...</translation>
-<translation id="5707154300732650394">Repetă experiența</translation>
+<translation id="5707154300732650394">Continuă-ți parcursul</translation>
<translation id="57094364128775171">Sugerează o parolă puternică…</translation>
<translation id="571403275720188526">(arm64)</translation>
<translation id="5720705177508910913">Utilizator curent</translation>
@@ -1533,6 +1570,7 @@
<translation id="5869522115854928033">Parole salvate</translation>
<translation id="5873013647450402046">Banca dorește să îți confirme identitatea.</translation>
<translation id="5887400589839399685">Cardul a fost salvat</translation>
+<translation id="5887687176710214216">Accesat ultima dată ieri</translation>
<translation id="5895138241574237353">Reîncepe</translation>
<translation id="5895187275912066135">Emis la</translation>
<translation id="5901630391730855834">Galben</translation>
@@ -1546,6 +1584,7 @@
<translation id="5921639886840618607">Salvezi cardul în Contul Google?</translation>
<translation id="5922853866070715753">Aproape finalizat</translation>
<translation id="5932224571077948991">Site-ul afișează anunțuri deranjante sau înșelătoare</translation>
+<translation id="5938153366081463283">Adaugă un card virtual</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347">Se deschide <ph name="SITE_NAME" />…</translation>
<translation id="5951495562196540101">Nu te poți înscrie cu contul de consumator (este disponibilă o licență din pachet).</translation>
@@ -1610,6 +1649,7 @@
<translation id="6120179357481664955">Îți amintești ID-ul UPI?</translation>
<translation id="6124432979022149706">Conectori Chrome Enterprise</translation>
<translation id="6127379762771434464">Elementul a fost eliminat</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Află mai multe despre modul incognito în Chrome<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">Verifică toate cablurile și repornește routerele, modemurile sau alte
dispozitive de rețea pe care le folosești.</translation>
<translation id="614940544461990577">Încearcă:</translation>
@@ -1622,7 +1662,6 @@
<translation id="6169916984152623906">Acum poți naviga în mod privat, iar celelalte persoane care folosesc acest dispozitiv nu îți vor vedea activitatea. Cu toate acestea, descărcările și marcajele vor fi salvate.</translation>
<translation id="6177128806592000436">Conexiunea la acest site nu este sigură</translation>
<translation id="6180316780098470077">Intervalul de reîncercare</translation>
-<translation id="619448280891863779">Poate solicita permisiunea să deschidă și să plaseze ferestre în ecrane</translation>
<translation id="6196640612572343990">Blochează cookie-urile terță parte</translation>
<translation id="6203231073485539293">Verificați conexiunea la internet</translation>
<translation id="6218753634732582820">Elimini adresa din Chromium?</translation>
@@ -1641,11 +1680,11 @@
<translation id="6264485186158353794">Înapoi la zona sigură</translation>
<translation id="6265794661083428563">Copiază valoarea pentru politica <ph name="POLICY_NAME" /></translation>
<translation id="6266934640124581640">Turcoaz deschis</translation>
-<translation id="6272088941196661550">Repetă experiența pentru a vedea activitatea relevantă din istoricul Chrome</translation>
+<translation id="6272088941196661550">Continuă-ți parcursul pentru a vedea activitatea relevantă din istoricul Chrome</translation>
<translation id="6272383483618007430">Actualizare Google</translation>
<translation id="6276112860590028508">Paginile din lista de lectură sunt afișate aici</translation>
<translation id="627746635834430766">Pentru a plăti mai rapid data viitoare, salvează cardul și adresa de facturare în Contul Google.</translation>
-<translation id="6279098320682980337">Numărul de card virtual nu este completat? Dă clic pe detaliile cardului pentru a le copia</translation>
+<translation id="6279183038361895380">Apasă pe |<ph name="ACCELERATOR" />| pentru a fi afișat cursorul</translation>
<translation id="6280223929691119688">Nu se poate livra la această adresă. Selectează altă adresă.</translation>
<translation id="6282194474023008486">Cod poștal</translation>
<translation id="6285507000506177184">Butonul de gestionare a descărcărilor în Chrome, apasă pe Enter pentru a gestiona fișierele pe care le-ai descărcat în Chrome</translation>
@@ -1653,6 +1692,7 @@
<translation id="6290238015253830360">Articolele sugerate apar aici</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{Dispozitivul va reporni acum}=1{Dispozitivul va reporni într-o secundă}few{Dispozitivul va reporni în # secunde}other{Dispozitivul va reporni în # de secunde}}</translation>
<translation id="6302269476990306341">Asistentul Google în Chrome se oprește</translation>
<translation id="6305205051461490394">Adresa URL <ph name="URL" /> nu poate fi accesată.</translation>
<translation id="6312113039770857350">Pagina web nu este disponibilă</translation>
@@ -1726,6 +1766,7 @@
<translation id="6529602333819889595">&amp;Repetați ștergerea</translation>
<translation id="6545864417968258051">Căutare Bluetooth</translation>
<translation id="6547208576736763147">Perforare dublă în stânga</translation>
+<translation id="6554732001434021288">Accesat ultima dată acum <ph name="NUM_DAYS" /> zile</translation>
<translation id="6556866813142980365">Repetă</translation>
<translation id="6569060085658103619">Se afișează pagina unei extensii</translation>
<translation id="6573200754375280815">Perforare dublă în dreapta</translation>
@@ -1786,7 +1827,6 @@
<translation id="6757797048963528358">Dispozitivul este inactiv.</translation>
<translation id="6767985426384634228">Actualizezi adresa?</translation>
<translation id="6768213884286397650">Hagaki (Carte poștală)</translation>
-<translation id="6774185088257932239"><ph name="BEGIN_LINK" />Află mai multe<ph name="END_LINK" /> despre modul incognito</translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">Violet</translation>
<translation id="6786747875388722282">Extensii</translation>
@@ -1870,7 +1910,6 @@
<translation id="706295145388601875">Adaugă și gestionează adrese din setările Chrome</translation>
<translation id="7064851114919012435">Informații de contact</translation>
<translation id="7068733155164172741">Introdu codul de <ph name="OTP_LENGTH" /> cifre</translation>
-<translation id="7070090581017165256">Despre acest site</translation>
<translation id="70705239631109039">Conexiunea nu este complet sigură</translation>
<translation id="7075452647191940183">Solicitarea este prea mare</translation>
<translation id="7079718277001814089">Acest site conține programe malware</translation>
@@ -1887,6 +1926,12 @@
<translation id="7111012039238467737">(Valid)</translation>
<translation id="7118618213916969306">Caută URL-ul din clipboard, <ph name="SHORT_URL" /></translation>
<translation id="7119414471315195487">închide celelalte file sau programe;</translation>
+<translation id="7129355289156517987">Când închizi toate filele incognito din Chromium, activitatea ta din acele file este ștearsă de pe dispozitiv:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />activitatea de navigare,<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />istoricul căutărilor<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />informațiile introduse în formulare.<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">Nu se poate expedia la această adresă. Selectează altă adresă.</translation>
<translation id="7132939140423847331">Administratorul a interzis copierea acestor date.</translation>
<translation id="7135130955892390533">Arată starea</translation>
@@ -1909,6 +1954,7 @@
<translation id="7192203810768312527">Eliberează <ph name="SIZE" />. Este posibil ca unele site-uri să se încarce mai lent la următoarea accesare.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">Administratorul tău poate să vadă:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, apasă pe Tab, apoi pe Enter pentru a deschide o nouă filă incognito ca să navighezi în privat</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> nu respectă standardele de securitate.</translation>
<translation id="7210993021468939304">activitatea Linux din container și pot să instaleze și să ruleze aplicații Linux în container</translation>
@@ -1940,6 +1986,7 @@ Detalii suplimentare:
<translation id="7304562222803846232">Gestionează setările de confidențialitate ale Contului Google</translation>
<translation id="7305756307268530424">Pornește mai lent</translation>
<translation id="7308436126008021607">Sincronizare în fundal</translation>
+<translation id="7310392214323165548">Dispozitivul va reporni în curând</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">Ajutor pentru conectare</translation>
<translation id="7323804146520582233">Ascunde secÈ›iunea „<ph name="SECTION" />â€</translation>
@@ -1947,6 +1994,7 @@ Detalii suplimentare:
<translation id="7334320624316649418">&amp;Repetați reordonarea</translation>
<translation id="7335157162773372339">Poate solicita permisiunea de a folosi camera</translation>
<translation id="7337248890521463931">Afișează mai multe rânduri</translation>
+<translation id="7337418456231055214">Numărul de card virtual nu este completat? Dă clic pe detaliile cardului pentru a le copia. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">Nu este disponibil pe platforma ta.</translation>
<translation id="733923710415886693">Certificatul serverului nu a fost dezvăluit folosind Transparența certificatului.</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1969,6 +2017,7 @@ Detalii suplimentare:
<translation id="7378627244592794276">Nu</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">Nu se aplică</translation>
+<translation id="7388594495505979117">{0,plural, =1{Dispozitivul va reporni într-un minut}few{Dispozitivul va reporni în # minute}other{Dispozitivul va reporni în # de minute}}</translation>
<translation id="7390545607259442187">Confirmă cardul</translation>
<translation id="7392089738299859607">Actualizează adresa</translation>
<translation id="7399802613464275309">Verificare de siguranță</translation>
@@ -2005,6 +2054,12 @@ Detalii suplimentare:
<translation id="7485870689360869515">Nu s-au găsit date.</translation>
<translation id="7495528107193238112">Acest conținut este blocat. Contactează proprietarul site-ului pentru a remedia problema.</translation>
<translation id="7497998058912824456">Butonul Creează un document, apasă pe Enter pentru a crea rapid un document Google</translation>
+<translation id="7506488012654002225">Chromium <ph name="BEGIN_EMPHASIS" />nu va salva<ph name="END_EMPHASIS" /> următoarele informații:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />istoricul de navigare,
+ <ph name="LIST_ITEM" />cookie-urile și datele de pe site-uri,
+ <ph name="LIST_ITEM" />informațiile introduse în formulare.
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">ID-ul de dispozitiv returnat pentru politică este gol sau nu corespunde cu ID-ul de dispozitiv actual</translation>
<translation id="7508870219247277067">Verde avocado</translation>
<translation id="7511955381719512146">Rețeaua Wi-Fi pe care o folosești poate solicita accesarea adresei <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
@@ -2118,7 +2173,6 @@ Detalii suplimentare:
<translation id="7813600968533626083">Elimini sugestia pentru formular din Chrome?</translation>
<translation id="781440967107097262">Permiți accesul la clipboard?</translation>
<translation id="7815407501681723534">S-au găsit <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> pentru „<ph name="SEARCH_STRING" />â€</translation>
-<translation id="782125616001965242">Afișează informații despre acest site</translation>
<translation id="782886543891417279">Rețeaua Wi-Fi pe care o folosești (<ph name="WIFI_NAME" />) poate solicita accesarea paginii de conectare.</translation>
<translation id="7836231406687464395">Postfix (Plic)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{Niciuna}=1{O aplicație (<ph name="EXAMPLE_APP_1" />)}=2{Două aplicații (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}few{# aplicații (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}other{# de aplicații (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}}</translation>
@@ -2135,7 +2189,6 @@ Detalii suplimentare:
<translation id="7888575728750733395">Intenția de redare a printării</translation>
<translation id="7894280532028510793">Dacă scrierea este corectă, <ph name="BEGIN_LINK" />încearcă să rulezi Diagnosticarea rețelei<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (Plic)</translation>
-<translation id="7931318309563332511">Necunoscută</translation>
<translation id="793209273132572360">Actualizezi adresa?</translation>
<translation id="7932579305932748336">Acoperire</translation>
<translation id="79338296614623784">Introdu un număr de telefon valid</translation>
@@ -2160,13 +2213,14 @@ Detalii suplimentare:
<translation id="7976214039405368314">Prea multe solicitări</translation>
<translation id="7977538094055660992">Dispozitiv de ieșire</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">Conectat cu</translation>
<translation id="798134797138789862">Poate solicita permisiunea de a folosi dispozitive de realitate virtuală și date conexe</translation>
<translation id="7984945080620862648">Nu puteți accesa acum site-ul <ph name="SITE" />, deoarece acesta a trimis date de conectare într-un format necunoscut, pe care Chrome nu le poate procesa. Erorile de rețea și atacurile sunt de obicei temporare și probabil că această pagină va funcționa mai târziu.</translation>
-<translation id="79859296434321399">Pentru a vedea conținut din realitatea augmentată, instalează ARCore</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">Legare</translation>
<translation id="7992044431894087211">Permiterea accesului la eran pentru <ph name="APPLICATION_TITLE" /> a fost reluată</translation>
<translation id="7995512525968007366">Nespecificată</translation>
+<translation id="7998269595945679889">Butonul Deschide o filă incognito, apasă pe Enter pentru a deschide o filă incognito ca să navighezi în privat</translation>
<translation id="800218591365569300">Încearcă să închizi celelalte file sau programe pentru a elibera memoria.</translation>
<translation id="8004582292198964060">Browser</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{Acest card și adresa de facturare vor fi salvate. Le vei putea folosi după ce te-ai conectat la <ph name="USER_EMAIL" />.}few{Aceste carduri și adresele de facturare vor fi salvate. Le vei putea folosi după ce te-ai conectat la <ph name="USER_EMAIL" />.}other{Aceste carduri și adresele de facturare vor fi salvate. Le vei putea folosi după ce te-ai conectat la <ph name="USER_EMAIL" />.}}</translation>
@@ -2226,6 +2280,7 @@ Detalii suplimentare:
<translation id="8202370299023114387">Conflict</translation>
<translation id="8206978196348664717">Prc4 (Plic)</translation>
<translation id="8211406090763984747">Conexiunea este securizată</translation>
+<translation id="8217240300496046857">Site-urile nu pot folosi cookie-uri care te urmăresc pe web. Este posibil ca funcțiile de pe anumite site-uri să fie întrerupte.</translation>
<translation id="8218327578424803826">Locație atribuită:</translation>
<translation id="8220146938470311105">C7/C6 (Plic)</translation>
<translation id="8225771182978767009">Persoana care a configurat computerul a ales să blocheze acest site.</translation>
@@ -2266,14 +2321,9 @@ Detalii suplimentare:
<translation id="830498451218851433">Îndoire la jumătate</translation>
<translation id="8307358339886459768">Fotografie-Mic</translation>
<translation id="8307888238279532626">Aplicațiile instalate și frecvența de folosire a acestora</translation>
+<translation id="8317207217658302555">Actualizezi ARCore?</translation>
<translation id="831997045666694187">Seara</translation>
<translation id="8321476692217554900">Notificări</translation>
-<translation id="8328484624016508118">După ce închizi toate filele incognito, Chrome șterge:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />activitatea de navigare de pe dispozitiv,<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />istoricul căutărilor de pe dispozitiv,<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />informațiile introduse în formulare.<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489">Accesul la <ph name="HOST_NAME" /> nu este permis</translation>
<translation id="833262891116910667">Evidențiază</translation>
<translation id="8339163506404995330">Paginile în <ph name="LANGUAGE" /> nu vor fi traduse</translation>
@@ -2325,6 +2375,7 @@ Detalii suplimentare:
<translation id="8507227106804027148">Linie de comandă</translation>
<translation id="8508648098325802031">Pictograma Căutare</translation>
<translation id="8511402995811232419">Gestionează cookie-urile</translation>
+<translation id="8519753333133776369">Dispozitiv HID permis de administrator</translation>
<translation id="8522552481199248698">Chrome te poate ajuta să îți protejezi Contul Google și să îți schimbi parola.</translation>
<translation id="8530813470445476232">Șterge istoricul de navigare, cookie-urile, memoria cache și altele din setările Chrome</translation>
<translation id="8533619373899488139">Accesează &lt;strong&gt;chrome://policy&lt;/strong&gt; ca să vezi lista de adrese URL blocate și alte politici aplicate de administratorul de sistem.</translation>
@@ -2336,7 +2387,6 @@ Detalii suplimentare:
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{Resetează permisiunea}few{Resetează permisiunile}other{Resetează permisiunile}}</translation>
<translation id="8555010941760982128">Folosește codul la finalizarea achiziției</translation>
<translation id="8557066899867184262">Codul CVC se află pe spatele cardului.</translation>
-<translation id="8558485628462305855">Pentru a vedea conținut din realitatea augmentată, actualizează ARCore</translation>
<translation id="8559762987265718583">O conexiune privată la <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> nu poate fi stabilită, deoarece data și ora dispozitivului (<ph name="DATE_AND_TIME" />) sunt incorecte.</translation>
<translation id="8564182942834072828">Documente separate/Copii necolaționate</translation>
<translation id="8564985650692024650">Chromium îți recomandă să resetezi parola pentru <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> dacă ai folosit-o și pe alte site-uri.</translation>
@@ -2356,6 +2406,7 @@ Detalii suplimentare:
<translation id="865032292777205197">Senzori de mișcare</translation>
<translation id="8663226718884576429">Rezumatul comenzii, <ph name="TOTAL_LABEL" />, Mai multe detalii</translation>
<translation id="8666678546361132282">Engleză</translation>
+<translation id="8669306706049782872">să folosească informațiile despre ecrane pentru a deschide și a plasa ferestre</translation>
<translation id="867224526087042813">Semnătura</translation>
<translation id="8676424191133491403">Fără întârziere</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, răspuns, <ph name="ANSWER" /></translation>
@@ -2382,6 +2433,7 @@ Detalii suplimentare:
<translation id="8731544501227493793">Butonul Gestionează parolele, apasă pe Enter pentru a vedea și a gestiona parolele în setările Chrome</translation>
<translation id="8734529307927223492">Dispozitivul <ph name="DEVICE_TYPE" /> este gestionat de <ph name="MANAGER" /></translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, apasă pe Tab, apoi pe Enter pentru a deschide o nouă fereastră incognito ca să navighezi în privat</translation>
+<translation id="8737685506611670901">Deschide linkurile <ph name="PROTOCOL" /> și nu <ph name="REPLACED_HANDLER_TITLE" /></translation>
<translation id="8738058698779197622">Pentru a stabili o conexiune securizată, ceasul trebuie să fie setat corect. Aceasta deoarece certificatele pe care site-urile le folosesc pentru a se identifica sunt valabile numai pentru anumite intervale de timp. Din moment ce ora de pe dispozitiv este incorectă, Chromium nu poate verifica aceste certificate.</translation>
<translation id="8740359287975076522">&lt;abbr id="dnsDefinition"&gt;Adresa DNS&lt;/abbr&gt; pentru <ph name="HOST_NAME" /> nu a putut fi găsită. Se diagnostichează problema.</translation>
<translation id="8742371904523228557"><ph name="ONE_TIME_CODE" /> este codul tău pentru <ph name="ORIGIN" /></translation>
@@ -2409,6 +2461,7 @@ Detalii suplimentare:
<translation id="883848425547221593">Alte marcaje</translation>
<translation id="884264119367021077">Adresa de expediere</translation>
<translation id="884923133447025588">Nu a fost găsit niciun mecanism de revocare.</translation>
+<translation id="8849262850971482943">Folosește cardul virtual pentru mai multă securitate</translation>
<translation id="885730110891505394">Permiterea accesului pentru Google</translation>
<translation id="8858065207712248076">Chrome îți recomandă să resetezi parola pentru <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> dacă ai folosit-o și pe alte site-uri.</translation>
<translation id="885906927438988819">Dacă scrierea este corectă, <ph name="BEGIN_LINK" />încearcă să rulezi Diagnosticarea rețelei Windows<ph name="END_LINK" />.</translation>
@@ -2458,6 +2511,7 @@ Detalii suplimentare:
<translation id="9004367719664099443">O sesiune RV este în desfășurare</translation>
<translation id="9005998258318286617">Documentul PDF nu a fost încărcat.</translation>
<translation id="9008201768610948239">Ignorați</translation>
+<translation id="901834265349196618">e-mail</translation>
<translation id="9020200922353704812">Este necesară adresa de facturare a cardului</translation>
<translation id="9020542370529661692">Această pagină a fost tradusă în <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9020742383383852663">A8</translation>
@@ -2493,7 +2547,7 @@ Detalii suplimentare:
<translation id="9114524666733003316">Se confirmă cardul…</translation>
<translation id="9114581008513152754">Browserul nu este gestionat de o companie sau o altă organizație. Este posibil ca activitatea de pe acest dispozitiv să fie gestionată în afara Chrome. <ph name="BEGIN_LINK" />Află mai multe<ph name="END_LINK" /></translation>
<translation id="9117930699067497412">Prospețime</translation>
-<translation id="9118692854637641831"><ph name="HISTORY_CLUSTERS_SEARCH_FOCUSED_FRIENDLY_MATCH_TEXT" />, apasă pe Tab, apoi pe Enter pentru a repeta experiența și a vedea activitatea relevantă din istoricul Chrome</translation>
+<translation id="9118692854637641831"><ph name="HISTORY_CLUSTERS_SEARCH_FOCUSED_FRIENDLY_MATCH_TEXT" />, apasă pe Tab, apoi pe Enter pentru a-ți continua parcursul și a vedea activitatea relevantă din istoricul Chrome</translation>
<translation id="9119042192571987207">Încărcat</translation>
<translation id="9128016270925453879">Politicile s-au încărcat</translation>
<translation id="9128870381267983090">Conectați-vă la rețea</translation>
@@ -2506,6 +2560,7 @@ Detalii suplimentare:
<translation id="9150045010208374699">Utilizează camera foto</translation>
<translation id="9150685862434908345">Administratorul poate schimba configurația browserului de la distanță. Este posibil ca activitatea de pe acest dispozitiv să fie gestionată și din afara Chrome. <ph name="BEGIN_LINK" />Află mai multe<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">Actualizat</translation>
+<translation id="9155211586651734179">dispozitivele periferice audio conectate;</translation>
<translation id="9157595877708044936">Se configurează...</translation>
<translation id="9158625974267017556">C6 (Plic)</translation>
<translation id="9164029392738894042">Verificarea preciziei</translation>
diff --git a/chromium/components/strings/components_strings_ru.xtb b/chromium/components/strings/components_strings_ru.xtb
index efa2b9c4884..fbcdf5aa520 100644
--- a/chromium/components/strings/components_strings_ru.xtb
+++ b/chromium/components/strings/components_strings_ru.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">Подробнее…</translation>
<translation id="1030706264415084469">Сайт <ph name="URL" /> запрашивает разрешение на поÑтоÑнное хранение большого объема данных на вашем уÑтройÑтве.</translation>
<translation id="1032854598605920125">Повернуть по чаÑовой Ñтрелке</translation>
+<translation id="1033329911862281889">Режим инкогнито не позволÑет Ñкрыть информацию о ваших дейÑтвиÑÑ… в интернете:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Сайты и иÑпользуемые ими ÑервиÑÑ‹ региÑтрируют поÑещениÑ.<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Работодатели и админиÑтраторы образовательных учреждений могут отÑлеживать дейÑÑ‚Ð²Ð¸Ñ Ð² браузере.<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Интернет-провайдеры могут анализировать трафик.<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">Отключить</translation>
<translation id="1036982837258183574">Чтобы выйти из полноÑкранного режима, нажмите |<ph name="ACCELERATOR" />|</translation>
<translation id="1038106730571050514">Показать подÑказки</translation>
<translation id="1038842779957582377">неизвеÑтное имÑ</translation>
<translation id="1041998700806130099">Сообщение на лиÑте заданиÑ</translation>
<translation id="1048785276086539861">При редактировании заметок документ вернетÑÑ Ð² одноÑтраничный режим проÑмотра.</translation>
-<translation id="1049743911850919806">Инкогнито</translation>
<translation id="1050038467049342496">Закройте другие приложениÑ.</translation>
<translation id="1055184225775184556">&amp;Отменить добавление</translation>
<translation id="1056898198331236512">Внимание</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">В кеше политики ошибок не найдено</translation>
<translation id="1130564665089811311">Кнопка перевода Ñтраницы. Чтобы Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ Google Переводчика ознакомитьÑÑ Ñ ÐµÐµ Ñодержанием, нажмите Ввод.</translation>
<translation id="1131264053432022307">Скопированное изображение</translation>
+<translation id="1142846828089312304">Блокировать Ñторонние файлы cookie в режиме инкогнито</translation>
<translation id="1150979032973867961">Ðе удалоÑÑŒ подтвердить, что Ñто Ñервер <ph name="DOMAIN" />. ÐžÐ¿ÐµÑ€Ð°Ñ†Ð¸Ð¾Ð½Ð½Ð°Ñ ÑиÑтема компьютера не доверÑет его Ñертификату безопаÑноÑти. Возможно, Ñервер наÑтроен неправильно или кто-то пытаетÑÑ Ð¿ÐµÑ€ÐµÑ…Ð²Ð°Ñ‚Ð¸Ñ‚ÑŒ ваши данные.</translation>
<translation id="1151972924205500581">Ðеобходимо ввеÑти пароль</translation>
<translation id="1156303062776767266">Ð’Ñ‹ проÑматриваете локальный или общий файл</translation>
@@ -64,7 +70,6 @@
<translation id="1178581264944972037">Пауза</translation>
<translation id="1181037720776840403">Удалить</translation>
<translation id="1186201132766001848">Проверить пароли</translation>
-<translation id="1195210374336998651">Открыть наÑтройки приложений</translation>
<translation id="1195558154361252544">Ð£Ð²ÐµÐ´Ð¾Ð¼Ð»ÐµÐ½Ð¸Ñ Ñо вÑех Ñайтов, кроме тех, которым вы предоÑтавили отдельные разрешениÑ, автоматичеÑки блокируютÑÑ.</translation>
<translation id="1197088940767939838">Оранжевый</translation>
<translation id="1201402288615127009">Далее</translation>
@@ -111,7 +116,7 @@
<translation id="1307966114820526988">УÑтаревшие функции</translation>
<translation id="1308113895091915999">ЕÑÑ‚ÑŒ предложение</translation>
<translation id="1312803275555673949">Чем Ñто подтверждаетÑÑ?</translation>
-<translation id="131405271941274527">Сайт <ph name="URL" /> запрашивает разрешение на обмен информацией через NFC.</translation>
+<translation id="1314311879718644478">Смотрите контент в режиме дополненной реальноÑти.</translation>
<translation id="1314509827145471431">Скрепление Ñправа</translation>
<translation id="1318023360584041678">Сохранено в группе вкладок</translation>
<translation id="1319245136674974084">Больше не Ñпрашивать Ð´Ð»Ñ Ñтого приложениÑ</translation>
@@ -161,6 +166,7 @@
<translation id="142858679511221695">Пользователь облака</translation>
<translation id="1428729058023778569">Ð’Ñ‹ видите Ñто предупреждение, потому что Ñайт не поддерживает HTTPS. <ph name="BEGIN_LEARN_MORE_LINK" />Подробнее…<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">Печать</translation>
+<translation id="1432187715652018471">Страница пытаетÑÑ ÑƒÑтановить обработчик Ñлужбы</translation>
<translation id="1432581352905426595">Управление поиÑковыми ÑиÑтемами</translation>
<translation id="1436185428532214179">Разрешено отправлÑÑ‚ÑŒ Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð½Ð° редактирование файлов или папок на уÑтройÑтве</translation>
<translation id="1442386063175183758">Фальцовка правой четверти</translation>
@@ -181,6 +187,12 @@
<translation id="1483493594462132177">Отправить</translation>
<translation id="1484290072879560759">Выбрать Ð°Ð´Ñ€ÐµÑ Ð´Ð¾Ñтавки поÑылок</translation>
<translation id="1492194039220927094">Обновление правил:</translation>
+<translation id="149293076951187737">Когда вы закроете вÑе вкладки инкогнито в Chrome, Ñ Ñтого уÑтройÑтва будет удалена ÑвÑÐ·Ð°Ð½Ð½Ð°Ñ Ñ Ð½Ð¸Ð¼Ð¸ информациÑ:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ÑÐ²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ дейÑтвиÑÑ… в браузере;<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />иÑÑ‚Ð¾Ñ€Ð¸Ñ Ð¿Ð¾Ð¸Ñка;<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />данные, указанные в формах.<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">ВернутьÑÑ Ð½Ð° вкладку</translation>
<translation id="1501859676467574491">Показывать банковÑкие карты, Ñохраненные в аккаунте Google</translation>
<translation id="1507202001669085618">&lt;p&gt;Эта ошибка может возникать при иÑпользовании портала Wi-Fi, Ð´Ð»Ñ Ñ€Ð°Ð±Ð¾Ñ‚Ñ‹ Ñ ÐºÐ¾Ñ‚Ð¾Ñ€Ñ‹Ð¼ требуетÑÑ Ð²Ñ‹Ð¿Ð¾Ð»Ð½Ð¸Ñ‚ÑŒ вход.&lt;/p&gt;
@@ -208,6 +220,8 @@
<translation id="1559572115229829303">&lt;p&gt;Ðе удалоÑÑŒ уÑтановить защищенное Ñоединение Ñ Ð´Ð¾Ð¼ÐµÐ½Ð¾Ð¼ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> из-за неверных наÑтроек ÑиÑтемных чаÑов и ÐºÐ°Ð»ÐµÐ½Ð´Ð°Ñ€Ñ (<ph name="DATE_AND_TIME" />).&lt;/p&gt;
&lt;p&gt;УÑтановите точную дату и времÑ. Ð”Ð»Ñ Ñтого откройте раздел &lt;strong&gt;Общие&lt;/strong&gt; в приложении &lt;strong&gt;ÐаÑтройки&lt;/strong&gt;.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">ÐдминиÑтратор перезапуÑтит уÑтройÑтво <ph name="DATE" /> в <ph name="TIME" />.</translation>
+<translation id="156703335097561114">Сетевые данные, такие как адреÑа, наÑтройки интерфейÑа и качеÑтво подключениÑ.</translation>
<translation id="1567040042588613346">Правило работает корректно, но заменÑет одинаковое значение, заданное где-то ещё.</translation>
<translation id="1569487616857761740">Укажите дату Ð¾ÐºÐ¾Ð½Ñ‡Ð°Ð½Ð¸Ñ Ñрока дейÑтвиÑ</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@
<translation id="1583429793053364125">При загрузке Ñтой Ñтраницы возникли неполадки.</translation>
<translation id="1586541204584340881">УÑтановленные раÑширениÑ.</translation>
<translation id="1588438908519853928">Обычный</translation>
+<translation id="1589050138437146318">УÑтановить ARCore?</translation>
<translation id="1592005682883173041">ДоÑтуп к данным на уÑтройÑтве</translation>
<translation id="1594030484168838125">Выбрать</translation>
<translation id="160851722280695521">Играть в Chrome Dino</translation>
@@ -254,7 +269,7 @@
<translation id="1711234383449478798">ИгнорируетÑÑ, так как Ð´Ð»Ñ Ð¿Ñ€Ð°Ð²Ð¸Ð»Ð° <ph name="POLICY_NAME" /> не уÑтановлено нужное значение (<ph name="VALUE" />).</translation>
<translation id="1712552549805331520">Сайт <ph name="URL" /> запрашивает разрешение на поÑтоÑнное хранение данных на вашем компьютере.</translation>
<translation id="1713628304598226412">Лоток 2</translation>
-<translation id="1715874602234207">F</translation>
+<translation id="1715874602234207">П</translation>
<translation id="1717218214683051432">Датчики движениÑ</translation>
<translation id="1717494416764505390">Почтовый Ñщик 3</translation>
<translation id="1718029547804390981">ÐедоÑтупно, так как документ Ñлишком большой</translation>
@@ -279,6 +294,7 @@
<translation id="1763864636252898013">Ðе удалоÑÑŒ подтвердить, что Ñто Ñервер <ph name="DOMAIN" />. ÐžÐ¿ÐµÑ€Ð°Ñ†Ð¸Ð¾Ð½Ð½Ð°Ñ ÑиÑтема уÑтройÑтва не доверÑет его Ñертификату безопаÑноÑти. Возможно, Ñервер наÑтроен неправильно или кто-то пытаетÑÑ Ð¿ÐµÑ€ÐµÑ…Ð²Ð°Ñ‚Ð¸Ñ‚ÑŒ ваши данные.</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Выполните диагноÑтику Ñети в Windows<ph name="END_LINK" />.</translation>
<translation id="1772163372082567643">Сервер <ph name="ORIGIN" />, на который вы переходите, уÑтановил заголовок, требующий применÑÑ‚ÑŒ правило иÑточника ко вÑем запроÑам. Однако из-за неверного формата заголовка браузер не может выполнить ваш Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð´Ð»Ñ Ñайта <ph name="SITE" />. Правила в отношении иÑточников позволÑÑŽÑ‚ операторам наÑтраивать параметры безопаÑноÑти и другие ÑвойÑтва Ñайтов.</translation>
+<translation id="1774592222195216949">Подробнее <ph name="BEGIN_LINK" />о режиме инкогнито в Chromium<ph name="END_LINK" />…</translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">ЗдеÑÑŒ поÑвÑÑ‚ÑÑ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ñ‹Ðµ вкладки.</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -406,6 +422,7 @@
<translation id="22081806969704220">Лоток 3</translation>
<translation id="2212735316055980242">Политика Ð´Ð»Ñ ÑƒÑтройÑтва не найдена</translation>
<translation id="2213606439339815911">Извлечение запиÑей…</translation>
+<translation id="2213612003795704869">Страница напечатана.</translation>
<translation id="2215727959747642672">Редактирование файлов</translation>
<translation id="2218879909401188352">Злоумышленники могут иÑпользовать Ñайт <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />, чтобы уÑтановить опаÑные приложениÑ, которые причинÑÑŽÑ‚ вред уÑтройÑтвам, увеличивают раÑходы на мобильную ÑвÑзь и крадут личные данные. <ph name="BEGIN_LEARN_MORE_LINK" />Подробнее…<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">Ðет Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ðº Интернету</translation>
@@ -415,6 +432,7 @@
<translation id="2248949050832152960">ИÑпользовать WebAuthn</translation>
<translation id="2250931979407627383">Скобы по левому краю</translation>
<translation id="225207911366869382">Это значение Ð´Ð»Ñ Ð´Ð°Ð½Ð½Ð¾Ð³Ð¾ правила больше не иÑпользуетÑÑ.</translation>
+<translation id="2256115617011615191">ПерезапуÑтить</translation>
<translation id="2258928405015593961">Введите правильный Ñрок Ð¾ÐºÐ¾Ð½Ñ‡Ð°Ð½Ð¸Ñ Ð´ÐµÐ¹ÑÑ‚Ð²Ð¸Ñ Ð¸ повторите попытку.</translation>
<translation id="225943865679747347">Код ошибки: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">Ошибка HTTP</translation>
@@ -442,6 +460,7 @@
<translation id="2337852623177822836">Эта наÑтройка управлÑетÑÑ Ð°Ð´Ð¼Ð¸Ð½Ð¸Ñтратором</translation>
<translation id="2340263603246777781">Сайт <ph name="ORIGIN" /> запрашивает подключение</translation>
<translation id="2346319942568447007">Скопированное изображение</translation>
+<translation id="2350796302381711542">ИÑпользовать <ph name="HANDLER_HOSTNAME" /> Ð´Ð»Ñ Ð¾Ð±Ñ€Ð°Ð±Ð¾Ñ‚ÐºÐ¸ ÑÑылок типа "<ph name="PROTOCOL" />" вмеÑто ÑервиÑа "<ph name="REPLACED_HANDLER_TITLE" />"?</translation>
<translation id="2354001756790975382">Другие закладки</translation>
<translation id="2354430244986887761">СиÑтема БезопаÑного проÑмотра Google недавно <ph name="BEGIN_LINK" />обнаружила вредоноÑные приложениÑ<ph name="END_LINK" /> на Ñайте <ph name="SITE" />.</translation>
<translation id="2355395290879513365">Злоумышленники могут видеть изображениÑ, которые видны вам, и изменÑÑ‚ÑŒ их в целÑÑ… мошенничеÑтва.</translation>
@@ -467,13 +486,15 @@
<translation id="2413528052993050574">Ðе удалоÑÑŒ подтвердить, что Ñто Ñервер <ph name="DOMAIN" />. Его Ñертификат безопаÑноÑти может быть отозван. Возможно, Ñервер наÑтроен неправильно или кто-то пытаетÑÑ Ð¿ÐµÑ€ÐµÑ…Ð²Ð°Ñ‚Ð¸Ñ‚ÑŒ ваши данные.</translation>
<translation id="2414886740292270097">ТемнаÑ</translation>
<translation id="2430968933669123598">Параметры аккаунта Google. Чтобы управлÑÑ‚ÑŒ Ñвоими данными, конфиденциальноÑтью и безопаÑноÑтью в аккаунте Google, нажмите Ввод.</translation>
+<translation id="2436186046335138073">ИÑпользовать <ph name="HANDLER_HOSTNAME" /> Ð´Ð»Ñ Ð¾Ð±Ñ€Ð°Ð±Ð¾Ñ‚ÐºÐ¸ ÑÑылок типа "<ph name="PROTOCOL" />"?</translation>
<translation id="2438874542388153331">Четыре отверÑÑ‚Ð¸Ñ Ñправа</translation>
-<translation id="2450021089947420533">СвÑзи</translation>
+<translation id="2450021089947420533">СеанÑÑ‹</translation>
<translation id="2463739503403862330">Заполнить</translation>
<translation id="2465402087343596252">Architecture-E</translation>
<translation id="2465655957518002998">Выбрать ÑпоÑоб доÑтавки</translation>
<translation id="2465688316154986572">Скоба</translation>
<translation id="2465914000209955735">УправлÑÑ‚ÑŒ Ñкачанными файлами в Chrome</translation>
+<translation id="2466004615675155314">Показывать информацию из интернета</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Выполните диагноÑтику Ñети<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">Ð’ порÑдке от 1 до N</translation>
<translation id="2470767536994572628">При редактировании заметок документ вернетÑÑ Ð² одноÑтраничный режим и иÑходную ориентацию.</translation>
@@ -494,6 +515,7 @@
<translation id="2523886232349826891">Карта будет Ñохранена только на Ñтом уÑтройÑтве</translation>
<translation id="2524461107774643265">Укажите дополнительную информацию</translation>
<translation id="2529899080962247600">МакÑимальное чиÑло запиÑей в Ñтом поле: <ph name="MAX_ITEMS_LIMIT" />. ОÑтальные запиÑи будут игнорироватьÑÑ.</translation>
+<translation id="2535585790302968248">Открыть новую вкладку в режиме инкогнито</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{и ещё 1}one{и ещё #}few{и ещё #}many{и ещё #}other{и ещё #}}</translation>
<translation id="2536110899380797252">Добавить адреÑ</translation>
<translation id="2539524384386349900">ОпределÑÑ‚ÑŒ</translation>
@@ -519,7 +541,14 @@
<translation id="2597378329261239068">Документ защищен паролем. Введите пароль.</translation>
<translation id="2609632851001447353">Варианты</translation>
<translation id="2610561535971892504">Ðажмите, чтобы Ñкопировать</translation>
+<translation id="2617988307566202237">Ð’ Chrome <ph name="BEGIN_EMPHASIS" />не будет ÑохранÑÑ‚ÑŒÑÑ<ph name="END_EMPHASIS" /> ÑÐ»ÐµÐ´ÑƒÑŽÑ‰Ð°Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />иÑÑ‚Ð¾Ñ€Ð¸Ñ Ð±Ñ€Ð°ÑƒÐ·ÐµÑ€Ð°;
+ <ph name="LIST_ITEM" />файлы cookie и данные Ñайтов;
+ <ph name="LIST_ITEM" />ÑведениÑ, указанные в формах.
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (конверт)</translation>
+<translation id="2623663032199728144">Разрешено запрашивать ÑÐ²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ ваших Ñкранах</translation>
<translation id="2625385379895617796">ЧаÑÑ‹ Ñпешат</translation>
<translation id="262745152991669301">Разрешено отправлÑÑ‚ÑŒ Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð½Ð° подключение к USB-уÑтройÑтвам</translation>
<translation id="2629325967560697240">Чтобы браузер Chrome Ñтал макÑимально безопаÑным, <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />включите режим "Ð£Ð»ÑƒÑ‡ÑˆÐµÐ½Ð½Ð°Ñ Ð·Ð°Ñ‰Ð¸Ñ‚Ð°"<ph name="END_ENHANCED_PROTECTION_LINK" />.</translation>
@@ -553,6 +582,7 @@
<translation id="2709516037105925701">Ðвтозаполнение</translation>
<translation id="2713444072780614174">Белый</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />. Ðажмите Tab и затем Ввод, чтобы изменить данные о ÑпоÑобах оплаты и банковÑких картах в наÑтройках Chrome.</translation>
+<translation id="271663710482723385">Чтобы выйти из полноÑкранного режима, нажмите |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />|.</translation>
<translation id="2721148159707890343">Ð—Ð°Ð¿Ñ€Ð¾Ñ Ð²Ñ‹Ð¿Ð¾Ð»Ð½ÐµÐ½ уÑпешно</translation>
<translation id="2723669454293168317">ЗапуÑтите проверку безопаÑноÑти в наÑтройках Chrome</translation>
<translation id="2726001110728089263">Боковой лоток</translation>
@@ -583,6 +613,7 @@
<translation id="2850739647070081192">Invite (конверт)</translation>
<translation id="2856444702002559011">Злоумышленники могут пытатьÑÑ Ð¿Ð¾Ñ…Ð¸Ñ‚Ð¸Ñ‚ÑŒ ваши данные Ñ Ñайта <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (например, пароли, ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð¸Ð»Ð¸ номера банковÑких карт). <ph name="BEGIN_LEARN_MORE_LINK" />Подробнее…<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">Этот Ñайт показывает навÑзчивую или вводÑщую в заблуждение рекламу.</translation>
+<translation id="286512204874376891">Чтобы защитить ваши данные от мошенников, вмеÑто наÑтоÑщей карты будет иÑпользоватьÑÑ Ð²Ð¸Ñ€Ñ‚ÑƒÐ°Ð»ÑŒÐ½Ð°Ñ. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">Дружелюбный</translation>
<translation id="2876489322757410363">Вы выйдете из режима инкогнито, чтобы выполнить оплату во внешнем приложении. Продолжить?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />. Ðажмите Tab, а затем Ввод, чтобы задать параметры БезопаÑного проÑмотра и других функций в наÑтройках Chrome.</translation>
@@ -607,6 +638,7 @@
<translation id="2930577230479659665">Подрезать поÑле каждого ÑкземплÑра</translation>
<translation id="2932085390869194046">Сгенерировать пароль…</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019">переход по ÑÑылкам <ph name="PROTOCOL" /></translation>
<translation id="2941952326391522266">Ðе удалоÑÑŒ подтвердить, что Ñто Ñервер <ph name="DOMAIN" />. Его Ñертификат безопаÑноÑти отноÑитÑÑ Ðº <ph name="DOMAIN2" />. Возможно, Ñервер наÑтроен неправильно или кто-то пытаетÑÑ Ð¿ÐµÑ€ÐµÑ…Ð²Ð°Ñ‚Ð¸Ñ‚ÑŒ ваши данные.</translation>
<translation id="2943895734390379394">Ð’Ñ€ÐµÐ¼Ñ Ð·Ð°Ð³Ñ€ÑƒÐ·ÐºÐ¸:</translation>
<translation id="2948083400971632585">ПрокÑи-Ñерверы, иÑпользуемые Ð´Ð»Ñ ÑоединениÑ, можно отключить на Ñтранице наÑтроек.</translation>
@@ -639,6 +671,7 @@
<translation id="3037605927509011580">Опаньки...</translation>
<translation id="3041612393474885105">Данные Ñертификата</translation>
<translation id="3044034790304486808">Продолжить поиÑк в иÑтории</translation>
+<translation id="305162504811187366">иÑторию Удаленного рабочего Ñтола Chrome, в том чиÑле временные метки, хоÑÑ‚Ñ‹ и идентификаторы ÑеанÑов клиентов.</translation>
<translation id="3060227939791841287">C9 (конверт)</translation>
<translation id="3061707000357573562">ИÑправление ÑервиÑа</translation>
<translation id="306573536155379004">Игра началаÑÑŒ.</translation>
@@ -678,6 +711,7 @@
<translation id="3197136577151645743">Разрешено запрашивать информацию об иÑпользовании уÑтройÑтва</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />. Ðажмите Tab, а затем – Ввод, чтобы открыть наÑтройки Chrome и указать, ÐºÐ°ÐºÐ°Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð´Ð¾Ð»Ð¶Ð½Ð° ÑинхронизироватьÑÑ.</translation>
<translation id="320323717674993345">Отменить оплату</translation>
+<translation id="3203366800380907218">Из интернета</translation>
<translation id="3207960819495026254">Добавлено в закладки.</translation>
<translation id="3209034400446768650">Ðа Ñтой Ñтранице может взиматьÑÑ Ð¿Ð»Ð°Ñ‚Ð°</translation>
<translation id="3212581601480735796">Ваши дейÑÑ‚Ð²Ð¸Ñ Ð½Ð° Ñайте <ph name="HOSTNAME" /> отÑлеживаютÑÑ</translation>
@@ -694,10 +728,12 @@
<translation id="3234666976984236645">Ð’Ñегда находить важный контент на Ñтом Ñайте</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />. Ðажмите Tab, а затем Ввод, чтобы наÑтроить внешний вид браузера.</translation>
<translation id="3240791268468473923">Экран неÑоответÑÑ‚Ð²Ð¸Ñ ÑƒÑ‡ÐµÑ‚Ð½Ñ‹Ñ… данных Ð´Ð»Ñ Ð·Ð°Ñ‰Ð¸Ñ‰ÐµÐ½Ð½Ñ‹Ñ… платежей открыт</translation>
+<translation id="324180406144491771">СÑылки "<ph name="HOST_NAME" />" заблокированы</translation>
<translation id="3249845759089040423">Яркий</translation>
<translation id="3252266817569339921">ФранцузÑкий</translation>
<translation id="3257954757204451555">Кто предоÑтавил Ñти ÑведениÑ?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />. Чтобы быÑтро Ñоздать мероприÑтие в Google Календаре, нажмите Tab, а затем Ввод.</translation>
+<translation id="3261488570342242926">Подробнее…</translation>
<translation id="3264837738038045344">Кнопка "Открыть наÑтройки Chrome". Ðажмите Ввод, чтобы перейти в наÑтройки Chrome.</translation>
<translation id="3266793032086590337">Значение (конфликтующее)</translation>
<translation id="3268451620468152448">Вкладки</translation>
@@ -711,6 +747,7 @@
<translation id="3288238092761586174">Сайт <ph name="URL" /> может выполнить дополнительные дейÑтвиÑ, чтобы подтвердить ваш платеж.</translation>
<translation id="3293642807462928945">Подробнее о политике <ph name="POLICY_NAME" />…</translation>
<translation id="3295444047715739395">Перейти к проÑмотру паролей и управлению ими в наÑтройках Chrome</translation>
+<translation id="3303795387212510132">Разрешить приложению открывать ÑÑылки <ph name="PROTOCOL_SCHEME" />?</translation>
<translation id="3303855915957856445">Ðичего не найдено</translation>
<translation id="3304073249511302126">поиÑк уÑтройÑтв Bluetooth</translation>
<translation id="3308006649705061278">Подразделение (OU)</translation>
@@ -724,12 +761,6 @@
<translation id="3345782426586609320">Глаза</translation>
<translation id="3355823806454867987">Изменить наÑтройки прокÑи-Ñервера...</translation>
<translation id="3360103848165129075">ЛиÑÑ‚ Ñ Ð¾Ð±Ñ€Ð°Ð±Ð¾Ñ‚Ñ‡Ð¸ÐºÐ¾Ð¼ платежа</translation>
-<translation id="3361596688432910856">Ð’ Chrome <ph name="BEGIN_EMPHASIS" />не будет ÑохранÑÑ‚ÑŒÑÑ<ph name="END_EMPHASIS" /> ÑÐ»ÐµÐ´ÑƒÑŽÑ‰Ð°Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />иÑÑ‚Ð¾Ñ€Ð¸Ñ Ð±Ñ€Ð°ÑƒÐ·ÐµÑ€Ð°;
- <ph name="LIST_ITEM" />файлы cookie и данные Ñайтов;
- <ph name="LIST_ITEM" />ÑведениÑ, которые вы указываете в формах.
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">Это значение было автоматичеÑки Ñкопировано из уÑтаревшего правила <ph name="OLD_POLICY" />. ВоÑпользуйтеÑÑŒ Ñтим правилом.</translation>
<translation id="3364869320075768271">Сайт <ph name="URL" /> запрашивает разрешение на иÑпользование уÑтройÑтва и данных виртуальной реальноÑти.</translation>
<translation id="3366477098757335611">СпиÑок карт</translation>
@@ -812,7 +843,6 @@
<translation id="3587738293690942763">Середина</translation>
<translation id="3592413004129370115">Italian (конверт)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{Ð’Ñ‹ можете в любое Ð²Ñ€ÐµÐ¼Ñ ÑброÑить наÑтройки группы. Чтобы приÑоединитьÑÑ Ðº другой группе, потребуетÑÑ Ð¿Ñ€Ð¸Ð¼ÐµÑ€Ð½Ð¾ 1 день.}=1{Ð’Ñ‹ можете в любое Ð²Ñ€ÐµÐ¼Ñ ÑброÑить наÑтройки группы. Чтобы приÑоединитьÑÑ Ðº другой группе, потребуетÑÑ Ð¿Ñ€Ð¸Ð¼ÐµÑ€Ð½Ð¾ 1 день.}one{Ð’Ñ‹ можете в любое Ð²Ñ€ÐµÐ¼Ñ ÑброÑить наÑтройки группы. Чтобы приÑоединитьÑÑ Ðº другой группе, потребуетÑÑ Ð¿Ñ€Ð¸Ð¼ÐµÑ€Ð½Ð¾ {NUM_DAYS} день.}few{Ð’Ñ‹ можете в любое Ð²Ñ€ÐµÐ¼Ñ ÑброÑить наÑтройки группы. Чтобы приÑоединитьÑÑ Ðº другой группе, потребуетÑÑ Ð¿Ñ€Ð¸Ð¼ÐµÑ€Ð½Ð¾ {NUM_DAYS} днÑ.}many{Ð’Ñ‹ можете в любое Ð²Ñ€ÐµÐ¼Ñ ÑброÑить наÑтройки группы. Чтобы приÑоединитьÑÑ Ðº другой группе, потребуетÑÑ Ð¿Ñ€Ð¸Ð¼ÐµÑ€Ð½Ð¾ {NUM_DAYS} дней.}other{Ð’Ñ‹ можете в любое Ð²Ñ€ÐµÐ¼Ñ ÑброÑить наÑтройки группы. Чтобы приÑоединитьÑÑ Ðº другой группе, потребуетÑÑ Ð¾ÐºÐ¾Ð»Ð¾ {NUM_DAYS} днÑ.}}</translation>
-<translation id="3596012367874587041">ÐаÑтройки приложений</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">Приложение заблокировано админиÑтратором</translation>
<translation id="3608932978122581043">Задать ориентацию</translation>
@@ -852,9 +882,10 @@
<translation id="3705189812819839667"><ph name="RESULT_OWNER" /> – <ph name="RESULT_PRODUCT_SOURCE" /></translation>
<translation id="370665806235115550">Загрузка...</translation>
<translation id="3709599264800900598">Скопированный текÑÑ‚</translation>
-<translation id="370972442370243704">Включить формирование ÑвÑзей</translation>
+<translation id="370972442370243704">Включить ÑеанÑÑ‹</translation>
<translation id="3711895659073496551">СпÑщий режим</translation>
<translation id="3712624925041724820">ÐедоÑтаточно лицензий</translation>
+<translation id="3714633008798122362">веб-календарь</translation>
<translation id="3714780639079136834">Включите Wi-Fi или мобильный Интернет.</translation>
<translation id="3715597595485130451">Подключение к Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Проверьте наÑтройки прокÑи-Ñервера, брандмауÑра и DNS<ph name="END_LINK" />.</translation>
@@ -916,6 +947,7 @@
<translation id="3906954721959377182">Планшет</translation>
<translation id="3909477809443608991">Сайт <ph name="URL" /> ÑобираетÑÑ Ð²Ð¾ÑпроизвеÑти защищенный контент. Ваше уÑтройÑтво пройдет проверку в Google, и Ñтот Ñайт Ñможет получать к нему доÑтуп.</translation>
<translation id="3909695131102177774"><ph name="LABEL" />. <ph name="ERROR" />.</translation>
+<translation id="3927932062596804919">Запретить</translation>
<translation id="3939773374150895049">ИÑпользовать WebAuthn вмеÑто CVC-кода?</translation>
<translation id="3946209740501886391">Ð’Ñегда Ñпрашивать на Ñтом Ñайте</translation>
<translation id="3947595700203588284">Разрешено отправлÑÑ‚ÑŒ Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð½Ð° подключение к MIDI-уÑтройÑтвам</translation>
@@ -936,6 +968,7 @@
<translation id="3987940399970879459">Менее 1 МБ</translation>
<translation id="3990250421422698716">Смещение</translation>
<translation id="3996311196211510766">Сайт <ph name="ORIGIN" />, на который вы переходите, требует применÑÑ‚ÑŒ правило иÑточника ко вÑем запроÑам, однако Ñто ÑÐµÐ¹Ñ‡Ð°Ñ Ð½ÐµÐ²Ð¾Ð·Ð¼Ð¾Ð¶Ð½Ð¾.</translation>
+<translation id="4009243425692662128">Содержание Ñтраниц, которые вы печатаете, отправлÑетÑÑ Ð² Google Cloud или третьим лицам Ð´Ð»Ñ Ð°Ð½Ð°Ð»Ð¸Ð·Ð°. Ð’ чаÑтноÑти, оно может быть проÑканировано на наличие конфиденциальных данных.</translation>
<translation id="4010758435855888356">ПредоÑтавить доÑтуп к хранилищу?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{PDF-документ, ÑоÑтоÑщий из {COUNT} Ñтраницы}one{PDF-документ, ÑоÑтоÑщий из {COUNT} Ñтраницы}few{PDF-документ, ÑоÑтоÑщий из {COUNT} Ñтраниц}many{PDF-документ, ÑоÑтоÑщий из {COUNT} Ñтраниц}other{PDF-документ, ÑоÑтоÑщий из {COUNT} Ñтраницы}}</translation>
<translation id="4023431997072828269">ПоÑкольку вы отправлÑете Ñту форму Ñ Ð¸Ñпользованием незащищенного подключениÑ, ваша Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¼Ð¾Ð¶ÐµÑ‚ Ñтать извеÑтна поÑторонним.</translation>
@@ -1026,6 +1059,7 @@
<translation id="4250680216510889253">Ðет</translation>
<translation id="4253168017788158739">Примечание</translation>
<translation id="425582637250725228">Возможно, внеÑенные Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð½Ðµ ÑохранÑÑ‚ÑÑ.</translation>
+<translation id="425869179292622354">Защитить ее Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ виртуальной?</translation>
<translation id="4258748452823770588">ПодпиÑÑŒ недейÑтвительна</translation>
<translation id="4261046003697461417">ÐедоÑтупно, так как документ защищен</translation>
<translation id="4265872034478892965">Разрешено админиÑтратором</translation>
@@ -1088,6 +1122,7 @@
<translation id="4434045419905280838">Ð’Ñплывающие окна и переадреÑациÑ</translation>
<translation id="4435702339979719576">Открытка</translation>
<translation id="443673843213245140">ПрокÑи-Ñервер отключен, но при Ñтом его ÐºÐ¾Ð½Ñ„Ð¸Ð³ÑƒÑ€Ð°Ñ†Ð¸Ñ Ð·Ð°Ð´Ð°Ð½Ð° Ñвным образом.</translation>
+<translation id="4441832193888514600">ИгнорируетÑÑ, так как правило может быть наÑтроено только на уровне облака.</translation>
<translation id="4450893287417543264">Больше не показывать</translation>
<translation id="4451135742916150903">Разрешено отправлÑÑ‚ÑŒ Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð½Ð° подключение к HID-уÑтройÑтвам</translation>
<translation id="4452328064229197696">Пароль, который вы только что иÑпользовали, был раÑкрыт в результате утечки данных. Чтобы защитить Ñвои аккаунты, проверьте Ñохраненные пароли в ДиÑпетчере паролей Google.</translation>
@@ -1111,7 +1146,7 @@
<translation id="4508814173490746936">Ðе удалоÑÑŒ иÑпользовать Touch ID</translation>
<translation id="4509074745930862522"><ph name="TRANSLATE_FOCUSED_FRIENDLY_MATCH_TEXT" />. Ðажмите Tab и затем Ввод, чтобы Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ Google Переводчика ознакомитьÑÑ Ñ Ñодержанием Ñтраницы.</translation>
<translation id="4510487217173779431">Chou4 (конверт)</translation>
-<translation id="4514308731478712184">Отключить формирование ÑвÑзей</translation>
+<translation id="4514308731478712184">Отключить ÑеанÑÑ‹</translation>
<translation id="4515275063822566619">Это карты и адреÑа, указанные в Chrome и вашем аккаунте Google (<ph name="ACCOUNT_EMAIL" />). Ð’Ñ‹ можете изменить их на Ñтранице <ph name="BEGIN_LINK" />ÐаÑтройки<ph name="END_LINK" />.</translation>
<translation id="4517607026994743406">Comm-10 (конверт)</translation>
<translation id="4521157617044179198"><ph name="WIDTH" /> × <ph name="HEIGHT" /> мм (<ph name="ORIENTATION" />)</translation>
@@ -1143,6 +1178,7 @@
<translation id="4628948037717959914">Фото</translation>
<translation id="4631649115723685955">С кешбÑком</translation>
<translation id="4636930964841734540">ИнформациÑ</translation>
+<translation id="4638670630777875591">Режим инкогнито в Chromium</translation>
<translation id="464342062220857295">Функции поиÑка</translation>
<translation id="4644670975240021822">Ð’ обратном порÑдке лицевой Ñтороной вниз</translation>
<translation id="4646534391647090355">Перейти ÑейчаÑ</translation>
@@ -1163,6 +1199,7 @@
<translation id="4708268264240856090">Соединение прервано</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Выполните диагноÑтику Ñети в Windows<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426">Пароль аккаунта Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ <ph name="USERNAME" /></translation>
<translation id="4724144314178270921">Разрешено отправлÑÑ‚ÑŒ Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð½Ð° доÑтуп к текÑту и изображениÑм, Ñкопированным в буфер обмена</translation>
<translation id="4726672564094551039">Повторно загрузить правила</translation>
<translation id="4728558894243024398">Платформа</translation>
@@ -1184,6 +1221,7 @@
<translation id="4757993714154412917">Ð’Ñ‹ только что ввели пароль на поддельном Ñайте. Чтобы защитить Ñвои аккаунты, проверьте Ñохраненные пароли в браузере Chromium.</translation>
<translation id="4758311279753947758">Добавить контактные данные</translation>
<translation id="4761104368405085019">ИÑпользование микрофона</translation>
+<translation id="4761869838909035636">ЗапуÑтить проверку безопаÑноÑти</translation>
<translation id="4764776831041365478">Веб-Ñтраница по адреÑу <ph name="URL" />, возможно, временно недоÑтупна или поÑтоÑнно перемещена по новому адреÑу.</translation>
<translation id="4766713847338118463">Две Ñкобы Ñнизу</translation>
<translation id="4771973620359291008">Произошла неизвеÑÑ‚Ð½Ð°Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ°.</translation>
@@ -1204,12 +1242,6 @@
<translation id="4819347708020428563">Изменить заметки в режиме по умолчанию?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />. Чтобы быÑтро Ñоздать таблицу Google, нажмите Tab, а затем Ввод.</translation>
<translation id="4825507807291741242">Мощный</translation>
-<translation id="4827402517081186284">Ð’ режиме инкогнито доÑтупна Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾ некоторых дейÑтвиÑÑ…:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Ñайты узнают, когда вы на них заходите;<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />работодатели и образовательные ÑƒÑ‡Ñ€ÐµÐ¶Ð´ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ отÑлеживать дейÑÑ‚Ð²Ð¸Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»ÐµÐ¹ в браузере;<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />интернет-провайдеры могут отÑлеживать трафик.<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">Включить предупреждениÑ</translation>
<translation id="4838327282952368871">Сказочный</translation>
<translation id="4840250757394056958">ПоÑмотреть иÑторию Chrome</translation>
@@ -1221,12 +1253,12 @@
<translation id="4854362297993841467">Этот ÑпоÑоб доÑтавки недоÑтупен. Выберите другой.</translation>
<translation id="4854853140771946034">БыÑтро Ñоздать заметку в Google Keep</translation>
<translation id="485902285759009870">Проверка кода…</translation>
+<translation id="4866506163384898554">Чтобы увидеть курÑор, нажмите |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />|.</translation>
<translation id="4876188919622883022">Упрощенный проÑмотр</translation>
<translation id="4876305945144899064">Ð˜Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð½Ðµ указано</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{Ðет}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" /> и <ph name="EXAMPLE_DOMAIN_2" />}one{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}few{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}many{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831">ПоиÑк по запроÑу "<ph name="TEXT" />"</translation>
<translation id="4879491255372875719">ÐвтоматичеÑки (по умолчанию)</translation>
-<translation id="4879725228911483934">Открытие и размещение окон на Ñкранах.</translation>
<translation id="4880827082731008257">ИÑкать в иÑтории</translation>
<translation id="4881695831933465202">Открыть</translation>
<translation id="4885256590493466218">Оплатите Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ <ph name="CARD_DETAIL" /></translation>
@@ -1235,6 +1267,7 @@
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" /> и <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">ДевÑтый лоток</translation>
<translation id="4901778704868714008">Сохранить</translation>
+<translation id="4905659621780993806">ÐдминиÑтратор автоматичеÑки перезапуÑтит уÑтройÑтво <ph name="DATE" /> в <ph name="TIME" />. Ðе забудьте Ñохранить открытые файлы.</translation>
<translation id="4913987521957242411">ОтверÑтие в левом верхнем углу</translation>
<translation id="4918221908152712722">УÑтановить приложение "<ph name="APP_NAME" />" (Ñкачивание не требуетÑÑ)</translation>
<translation id="4923459931733593730">Платеж</translation>
@@ -1243,6 +1276,7 @@
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />. Ðажмите Tab и затем Ввод, чтобы выполнить поиÑк.</translation>
<translation id="4930153903256238152">Ð‘Ð¾Ð»ÑŒÑˆÐ°Ñ ÐµÐ¼ÐºÐ¾ÑÑ‚ÑŒ</translation>
+<translation id="4940163644868678279">Режим инкогнито в Chrome</translation>
<translation id="4943872375798546930">Ðет результатов</translation>
<translation id="4950898438188848926">Кнопка Ð¿ÐµÑ€ÐµÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ð¼ÐµÐ¶Ð´Ñƒ вкладками. Чтобы переключитьÑÑ Ð½Ð° открытую вкладку (<ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" />), нажмите клавишу "Ввод".</translation>
<translation id="495170559598752135">ДейÑтвиÑ</translation>
@@ -1252,6 +1286,7 @@
<translation id="4968522289500246572">Это приложение предназначено Ð´Ð»Ñ Ð¼Ð¾Ð±Ð¸Ð»ÑŒÐ½Ñ‹Ñ… уÑтройÑтв. ПоÑле Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ñ€Ð°Ð·Ð¼ÐµÑ€Ð° оно может работать некорректно или перезапуÑтитьÑÑ.</translation>
<translation id="4969341057194253438">Удалить запиÑÑŒ</translation>
<translation id="4973922308112707173">Два отверÑÑ‚Ð¸Ñ Ñверху</translation>
+<translation id="4976702386844183910">ПоÑледнее поÑещение: <ph name="DATE" /></translation>
<translation id="4984088539114770594">ИÑпользовать микрофон?</translation>
<translation id="4984339528288761049">Prc5 (конверт)</translation>
<translation id="4989163558385430922">Показать вÑе</translation>
@@ -1313,6 +1348,7 @@
<translation id="5138227688689900538">Свернуть</translation>
<translation id="5145883236150621069">При проверке политики возвращен код ошибки</translation>
<translation id="5146995429444047494">Ð£Ð²ÐµÐ´Ð¾Ð¼Ð»ÐµÐ½Ð¸Ñ Ð´Ð»Ñ Ñайта <ph name="ORIGIN" /> заблокированы.</translation>
+<translation id="514704532284964975">Сайт <ph name="URL" /> запрашивает разрешение на доÑтуп к информации и ее изменение на уÑтройÑтвах, которые подключаютÑÑ Ðº телефону через NFC.</translation>
<translation id="5148809049217731050">Лицевой Ñтороной вверх</translation>
<translation id="515292512908731282">C4 (конверт)</translation>
<translation id="5158275234811857234">Обложка</translation>
@@ -1337,6 +1373,7 @@
<translation id="5215116848420601511">СпоÑобы оплаты и адреÑа из Google Pay</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">Лоток 13</translation>
+<translation id="5216942107514965959">ПоÑледнее поÑещение: ÑегоднÑ</translation>
<translation id="5222812217790122047">Введите Ð°Ð´Ñ€ÐµÑ Ñлектронной почты</translation>
<translation id="5230733896359313003">ÐÐ´Ñ€ÐµÑ Ð´Ð¾Ñтавки</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1357,7 +1394,6 @@
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">СвойÑтва документа</translation>
<translation id="528468243742722775">Завершить</translation>
-<translation id="5284909709419567258">Ñетевые адреÑа;</translation>
<translation id="5285570108065881030">Показать вÑе Ñохраненные пароли</translation>
<translation id="5287240709317226393">Показать файлы Ñookie</translation>
<translation id="5287456746628258573">ÐаÑтройки безопаÑноÑти Ñтого Ñайта уÑтарели. Злоумышленники могут получить доÑтуп к вашим данным (например, паролÑм и номерам банковÑких карт) при их отправке на Ñтот Ñайт.</translation>
@@ -1441,6 +1477,7 @@
<translation id="5556459405103347317">Перезагрузить</translation>
<translation id="5560088892362098740">Дата Ð¾ÐºÐ¾Ð½Ñ‡Ð°Ð½Ð¸Ñ Ñрока дейÑтвиÑ</translation>
<translation id="55635442646131152">Структура документа</translation>
+<translation id="5565613213060953222">Открыть вкладку инкогнито</translation>
<translation id="5565735124758917034">Ðктивен</translation>
<translation id="5570825185877910964">Защитить аккаунт</translation>
<translation id="5571083550517324815">Этот Ð°Ð´Ñ€ÐµÑ Ð½Ðµ поддерживаетÑÑ. Выберите другой.</translation>
@@ -1523,6 +1560,7 @@
<translation id="5869522115854928033">Сайты Ñ Ñохраненными паролÑми</translation>
<translation id="5873013647450402046">Банку нужно убедитьÑÑ, что Ñто дейÑтвительно вы.</translation>
<translation id="5887400589839399685">Карта Ñохранена</translation>
+<translation id="5887687176710214216">ПоÑледнее поÑещение: вчера</translation>
<translation id="5895138241574237353">ПерезапуÑтить</translation>
<translation id="5895187275912066135">Дата выдачи</translation>
<translation id="5901630391730855834">Желтый</translation>
@@ -1536,6 +1574,7 @@
<translation id="5921639886840618607">Сохранить карту в аккаунте Google?</translation>
<translation id="5922853866070715753">Почти готово…</translation>
<translation id="5932224571077948991">Сайт показывает навÑзчивую или вводÑщую в заблуждение рекламу</translation>
+<translation id="5938153366081463283">Добавить виртуальную карту</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347">Загрузка <ph name="SITE_NAME" />…</translation>
<translation id="5951495562196540101">РегиÑÑ‚Ñ€Ð°Ñ†Ð¸Ñ Ð½ÐµÐ²Ð¾Ð·Ð¼Ð¾Ð¶Ð½Ð°, так как тип аккаунта не ÑоответÑтвует лицензии на уÑтройÑтве.</translation>
@@ -1600,6 +1639,7 @@
<translation id="6120179357481664955">Запомнить идентификатор UPI?</translation>
<translation id="6124432979022149706">Коннекторы Chrome Enterprise</translation>
<translation id="6127379762771434464">БыÑÑ‚Ñ€Ð°Ñ ÑÑылка удалена.</translation>
+<translation id="6132161237766805930">Подробнее <ph name="BEGIN_LINK" />о режиме инкогнито в Chrome<ph name="END_LINK" />…</translation>
<translation id="6146055958333702838">Проверьте Ñоединение кабелей, перезагрузите маршрутизаторы, модемы и другие
Ñетевые уÑтройÑтва.</translation>
<translation id="614940544461990577">Попробуйте Ñделать Ñледующее:</translation>
@@ -1612,7 +1652,6 @@
<translation id="6169916984152623906">Ваши дейÑÑ‚Ð²Ð¸Ñ Ð² режиме инкогнито будут недоÑтупны другим пользователÑм Ñтого уÑтройÑтва. Однако закладки и Ñкачанные файлы ÑохранÑÑ‚ÑÑ.</translation>
<translation id="6177128806592000436">Подключение к Ñайту не защищено</translation>
<translation id="6180316780098470077">Интервал повтора</translation>
-<translation id="619448280891863779">Разрешено отправлÑÑ‚ÑŒ Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð½Ð° открытие и размещение окон на Ñкранах</translation>
<translation id="6196640612572343990">Блокировать Ñторонние файлы cookie</translation>
<translation id="6203231073485539293">Проверьте подключение к Интернету</translation>
<translation id="6218753634732582820">Удалить Ð°Ð´Ñ€ÐµÑ Ð¸Ð· Chromium?</translation>
@@ -1635,7 +1674,7 @@
<translation id="6272383483618007430">Google Update</translation>
<translation id="6276112860590028508">ЗдеÑÑŒ будут Ñтраницы из ÑпиÑка Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ.</translation>
<translation id="627746635834430766">Чтобы уÑкорить процеÑÑ Ð¾Ð¿Ð»Ð°Ñ‚Ñ‹ в будущем, Ñохраните карту и платежный Ð°Ð´Ñ€ÐµÑ Ð² аккаунте Google.</translation>
-<translation id="6279098320682980337">Ðомер виртуальной карты не указан? Ðажмите на реквизиты, чтобы Ñкопировать их.</translation>
+<translation id="6279183038361895380">Чтобы показать курÑор, нажмите |<ph name="ACCELERATOR" />|</translation>
<translation id="6280223929691119688">Ðевозможно доÑтавить заказ по Ñтому адреÑу. Выберите другой вариант.</translation>
<translation id="6282194474023008486">Почтовый индекÑ</translation>
<translation id="6285507000506177184">Кнопка "УправлÑÑ‚ÑŒ Ñкачанными файлами в Chrome". Ðажмите Ввод, чтобы управлÑÑ‚ÑŒ Ñкачанными файлами в Chrome.</translation>
@@ -1643,6 +1682,7 @@
<translation id="6290238015253830360">ЗдеÑÑŒ поÑвÑÑ‚ÑÑ Ñ€ÐµÐºÐ¾Ð¼ÐµÐ½Ð´ÑƒÐµÐ¼Ñ‹Ðµ Ñтатьи.</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">Код CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{УÑтройÑтво ÑÐµÐ¹Ñ‡Ð°Ñ Ð¿ÐµÑ€ÐµÐ·Ð°Ð¿ÑƒÑтитÑÑ}=1{УÑтройÑтво перезапуÑтитÑÑ Ñ‡ÐµÑ€ÐµÐ· 1 Ñекунду}one{УÑтройÑтво перезапуÑтитÑÑ Ñ‡ÐµÑ€ÐµÐ· # Ñекунду}few{УÑтройÑтво перезапуÑтитÑÑ Ñ‡ÐµÑ€ÐµÐ· # Ñекунды}many{УÑтройÑтво перезапуÑтитÑÑ Ñ‡ÐµÑ€ÐµÐ· # Ñекунд}other{УÑтройÑтво перезапуÑтитÑÑ Ñ‡ÐµÑ€ÐµÐ· # Ñекунды}}</translation>
<translation id="6302269476990306341">Google ÐÑÑиÑтент в Chrome отключитÑÑ</translation>
<translation id="6305205051461490394">Сайт <ph name="URL" /> недоÑтупен.</translation>
<translation id="6312113039770857350">Ðе удалоÑÑŒ открыть веб-Ñтраницу</translation>
@@ -1716,6 +1756,7 @@
<translation id="6529602333819889595">&amp;Повторить удаление</translation>
<translation id="6545864417968258051">ПоиÑк Bluetooth-уÑтройÑтв</translation>
<translation id="6547208576736763147">Два отверÑÑ‚Ð¸Ñ Ñлева</translation>
+<translation id="6554732001434021288">ПоÑледнее поÑещение: <ph name="NUM_DAYS" /> дн. назад</translation>
<translation id="6556866813142980365">Повторить</translation>
<translation id="6569060085658103619">Ð’Ñ‹ проÑматриваете Ñтраницу раÑширениÑ</translation>
<translation id="6573200754375280815">Два отверÑÑ‚Ð¸Ñ Ñправа</translation>
@@ -1776,7 +1817,6 @@
<translation id="6757797048963528358">УÑтройÑтво находитÑÑ Ð² ÑпÑщем режиме.</translation>
<translation id="6767985426384634228">Изменить адреÑ?</translation>
<translation id="6768213884286397650">Hagaki (открытка)</translation>
-<translation id="6774185088257932239">Подробнее <ph name="BEGIN_LINK" />о режиме инкогнито<ph name="END_LINK" />…</translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">Фиолетовый</translation>
<translation id="6786747875388722282">РаÑширениÑ</translation>
@@ -1860,7 +1900,6 @@
<translation id="706295145388601875">Добавить и изменить адреÑа в наÑтройках Chrome</translation>
<translation id="7064851114919012435">Контактные данные</translation>
<translation id="7068733155164172741">Введите <ph name="OTP_LENGTH" />-значный код</translation>
-<translation id="7070090581017165256">О Ñайте</translation>
<translation id="70705239631109039">Подключение к Ñайту небезопаÑно</translation>
<translation id="7075452647191940183">Ð—Ð°Ð¿Ñ€Ð¾Ñ Ñлишком велик.</translation>
<translation id="7079718277001814089">Этот Ñайт Ñодержит вредоноÑное ПО</translation>
@@ -1877,6 +1916,12 @@
<translation id="7111012039238467737">(дейÑтвительный)</translation>
<translation id="7118618213916969306">ПоиÑк по адреÑу <ph name="SHORT_URL" /> из буфера обмена</translation>
<translation id="7119414471315195487">Закройте другие вкладки и программы.</translation>
+<translation id="7129355289156517987">Когда вы закроете вÑе вкладки инкогнито в Chromium, Ñ Ñтого уÑтройÑтва будет удалена ÑвÑÐ·Ð°Ð½Ð½Ð°Ñ Ñ Ð½Ð¸Ð¼Ð¸ информациÑ:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ÑÐ²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ дейÑтвиÑÑ… в браузере;<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />иÑÑ‚Ð¾Ñ€Ð¸Ñ Ð¿Ð¾Ð¸Ñка;<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />данные, указанные в формах.<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">Ðевозможно отправить заказ по Ñтому адреÑу. Выберите другой вариант.</translation>
<translation id="7132939140423847331">ÐдминиÑтратор запретил копирование Ñтих данных.</translation>
<translation id="7135130955892390533">Показать ÑтатуÑ</translation>
@@ -1899,6 +1944,7 @@
<translation id="7192203810768312527">ОÑвободитÑÑ <ph name="SIZE" /> проÑтранÑтва. ПоÑле Ñтого некоторые веб-Ñтраницы могут загружатьÑÑ Ð´Ð¾Ð»ÑŒÑˆÐµ обычного.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">ÐдминиÑтратор может отÑлеживать:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />. Ðажмите Tab и затем Ввод, чтобы открыть новую вкладку в режиме инкогнито.</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423">Сайт <ph name="HOST_NAME" /> не ÑоответÑтвует Ñтандартам безопаÑноÑти.</translation>
<translation id="7210993021468939304">ДейÑÑ‚Ð²Ð¸Ñ Linux в контейнере (также он может уÑтанавливать и запуÑкать Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Linux из контейнера).</translation>
@@ -1930,6 +1976,7 @@
<translation id="7304562222803846232">Перейти в наÑтройки конфиденциальноÑти аккаунта Google</translation>
<translation id="7305756307268530424">ЗапуÑтить медленнее</translation>
<translation id="7308436126008021607">Ð¤Ð¾Ð½Ð¾Ð²Ð°Ñ ÑинхронизациÑ</translation>
+<translation id="7310392214323165548">Скоро уÑтройÑтво будет перезагружено</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">УÑтранение ошибок при подключении к Интернету</translation>
<translation id="7323804146520582233">Скрыть раздел "<ph name="SECTION" />"</translation>
@@ -1937,6 +1984,7 @@
<translation id="7334320624316649418">&amp;Повторить изменение порÑдка</translation>
<translation id="7335157162773372339">Разрешено отправлÑÑ‚ÑŒ Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð½Ð° иÑпользование камеры</translation>
<translation id="7337248890521463931">Показать больше Ñтрок</translation>
+<translation id="7337418456231055214">Ðомер виртуальной карты не указан? Ðажмите на реквизиты, чтобы Ñкопировать их. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">ÐедоÑтупно на вашей платформе.</translation>
<translation id="733923710415886693">Сертификат Ñервера не проходил проверку.</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1959,6 +2007,7 @@
<translation id="7378627244592794276">Ðет</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">Ðеприменимо</translation>
+<translation id="7388594495505979117">{0,plural, =1{УÑтройÑтво перезапуÑтитÑÑ Ñ‡ÐµÑ€ÐµÐ· 1 минуту}one{УÑтройÑтво перезапуÑтитÑÑ Ñ‡ÐµÑ€ÐµÐ· # минуту}few{УÑтройÑтво перезапуÑтитÑÑ Ñ‡ÐµÑ€ÐµÐ· # минуты}many{УÑтройÑтво перезапуÑтитÑÑ Ñ‡ÐµÑ€ÐµÐ· # минут}other{УÑтройÑтво перезапуÑтитÑÑ Ñ‡ÐµÑ€ÐµÐ· # минуты}}</translation>
<translation id="7390545607259442187">Подтвердите карту</translation>
<translation id="7392089738299859607">Изменить адреÑ</translation>
<translation id="7399802613464275309">Проверка безопаÑноÑти</translation>
@@ -1995,6 +2044,12 @@
<translation id="7485870689360869515">Данные не найдены.</translation>
<translation id="7495528107193238112">Этот контент заблокирован. Чтобы уÑтранить неполадку, ÑвÑжитеÑÑŒ Ñ Ð²Ð»Ð°Ð´ÐµÐ»ÑŒÑ†ÐµÐ¼ Ñайта.</translation>
<translation id="7497998058912824456">Кнопка "Создать документ". Чтобы быÑтро Ñоздать документ Google, нажмите Ввод.</translation>
+<translation id="7506488012654002225">Ð’ Chromium <ph name="BEGIN_EMPHASIS" />не будет ÑохранÑÑ‚ÑŒÑÑ<ph name="END_EMPHASIS" /> ÑÐ»ÐµÐ´ÑƒÑŽÑ‰Ð°Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />иÑÑ‚Ð¾Ñ€Ð¸Ñ Ð±Ñ€Ð°ÑƒÐ·ÐµÑ€Ð°;
+ <ph name="LIST_ITEM" />файлы cookie и данные Ñайтов;
+ <ph name="LIST_ITEM" />ÑведениÑ, указанные в формах.
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">Возвращенный идентификатор уÑтройÑтва пуÑÑ‚ или не ÑоответÑтвует имеющемуÑÑ</translation>
<translation id="7508870219247277067">Зеленый (авокадо)</translation>
<translation id="7511955381719512146">Возможно, вам нужно перейти на Ñтраницу <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> Ñети Wi-Fi.</translation>
@@ -2108,7 +2163,6 @@
<translation id="7813600968533626083">Удалить подÑказку из Chrome?</translation>
<translation id="781440967107097262">ПредоÑтавить доÑтуп к буферу обмена?</translation>
<translation id="7815407501681723534"><ph name="SEARCH_RESULTS" /> по запроÑу "<ph name="SEARCH_STRING" />" (<ph name="NUMBER_OF_RESULTS" />)</translation>
-<translation id="782125616001965242">Показать информацию об Ñтом Ñайте</translation>
<translation id="782886543891417279">Возможно, вам нужно перейти на Ñтраницу входа Ñети Wi-Fi (<ph name="WIFI_NAME" />).</translation>
<translation id="7836231406687464395">Postfix (конверт)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{Ðет}=1{1 приложение (<ph name="EXAMPLE_APP_1" />)}=2{2 Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}one{# приложение (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" /> <ph name="AND_MORE" />)}few{# Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" /> <ph name="AND_MORE" />)}many{# приложений (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" /> <ph name="AND_MORE" />)}other{# Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" /> <ph name="AND_MORE" />)}}</translation>
@@ -2125,7 +2179,6 @@
<translation id="7888575728750733395">СпоÑоб цветового переÑчета Ð´Ð»Ñ Ð¿ÐµÑ‡Ð°Ñ‚Ð¸</translation>
<translation id="7894280532028510793">ЕÑли вÑе правильно, <ph name="BEGIN_LINK" />выполните диагноÑтику Ñети<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (конверт)</translation>
-<translation id="7931318309563332511">ÐеизвеÑтно</translation>
<translation id="793209273132572360">Обновить адреÑ?</translation>
<translation id="7932579305932748336">Покрытие</translation>
<translation id="79338296614623784">Укажите дейÑтвительный номер телефона.</translation>
@@ -2150,13 +2203,14 @@
<translation id="7976214039405368314">Ñлишком много запроÑов</translation>
<translation id="7977538094055660992">УÑтройÑтво вывода</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">СвÑзана Ñ</translation>
<translation id="798134797138789862">Разрешено отправлÑÑ‚ÑŒ Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð½Ð° иÑпользование уÑтройÑтв и данных виртуальной реальноÑти</translation>
<translation id="7984945080620862648">Перейти на Ñайт <ph name="SITE" /> невозможно, так как его идентификационные данные зашифрованы, и Chrome не может их обработать. Это могло произойти из-за ошибки Ñети или атаки на Ñайт. Скорее вÑего, он заработает через некоторое времÑ.</translation>
-<translation id="79859296434321399">Чтобы проÑматривать контент в режиме дополненной реальноÑти, уÑтановите приложение ARCore.</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">Скрепление</translation>
<translation id="7992044431894087211">ДемонÑÑ‚Ñ€Ð°Ñ†Ð¸Ñ Ñкрана Ð´Ð»Ñ Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ <ph name="APPLICATION_TITLE" /> возобновлена.</translation>
<translation id="7995512525968007366">Ðе указано</translation>
+<translation id="7998269595945679889">Кнопка "Открыть вкладку инкогнито". Ðажмите Ввод, чтобы открыть такую вкладку.</translation>
<translation id="800218591365569300">Закройте другие вкладки и программы, чтобы оÑвободить памÑÑ‚ÑŒ.</translation>
<translation id="8004582292198964060">Браузер</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{Данные Ñтой карты и ее платежный Ð°Ð´Ñ€ÐµÑ Ð±ÑƒÐ´ÑƒÑ‚ Ñохранены. Ð’Ñ‹ Ñможете пользоватьÑÑ ÐµÑŽ поÑле входа в аккаунт <ph name="USER_EMAIL" />.}one{Данные Ñтих карт и их платежные адреÑа будут Ñохранены. Ð’Ñ‹ Ñможете пользоватьÑÑ Ð¸Ð¼Ð¸ поÑле входа в аккаунт <ph name="USER_EMAIL" />.}few{Данные Ñтих карт и их платежные адреÑа будут Ñохранены. Ð’Ñ‹ Ñможете пользоватьÑÑ Ð¸Ð¼Ð¸ поÑле входа в аккаунт <ph name="USER_EMAIL" />.}many{Данные Ñтих карт и их платежные адреÑа будут Ñохранены. Ð’Ñ‹ Ñможете пользоватьÑÑ Ð¸Ð¼Ð¸ поÑле входа в аккаунт <ph name="USER_EMAIL" />.}other{Данные Ñтих карт и их платежные адреÑа будут Ñохранены. Ð’Ñ‹ Ñможете пользоватьÑÑ Ð¸Ð¼Ð¸ поÑле входа в аккаунт <ph name="USER_EMAIL" />.}}</translation>
@@ -2216,6 +2270,7 @@
<translation id="8202370299023114387">Конфликт</translation>
<translation id="8206978196348664717">Prc4 (конверт)</translation>
<translation id="8211406090763984747">БезопаÑное подключение</translation>
+<translation id="8217240300496046857">Сайтам запрещаетÑÑ Ð¸Ñпользовать файлы cookie, которые отÑлеживают ваши дейÑÑ‚Ð²Ð¸Ñ Ð² интернете. Из-за Ñтого некоторые функции Ñайтов могут работать некорректно.</translation>
<translation id="8218327578424803826">Ðазначенное меÑтоположение:</translation>
<translation id="8220146938470311105">C7/C6 (конверт)</translation>
<translation id="8225771182978767009">Тот, кто наÑтраивал компьютер, заблокировал Ñтот Ñайт.</translation>
@@ -2256,13 +2311,9 @@
<translation id="830498451218851433">Фальцовка книжкой</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">уÑтановленные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¸ чаÑтоту их иÑпользованиÑ.</translation>
+<translation id="8317207217658302555">Обновить ARCore?</translation>
<translation id="831997045666694187">До вечера</translation>
<translation id="8321476692217554900">УведомлениÑ</translation>
-<translation id="8328484624016508118">ПоÑле Ð·Ð°ÐºÑ€Ñ‹Ñ‚Ð¸Ñ Ð²Ñех вкладок инкогнито Chrome удалÑет:<ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />ваши дейÑÑ‚Ð²Ð¸Ñ Ð² браузере на Ñтом уÑтройÑтве;<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />иÑторию поиÑка на Ñтом уÑтройÑтве;<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />данные, которые вы указали в формах.<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489">ДоÑтуп к <ph name="HOST_NAME" /> запрещен</translation>
<translation id="833262891116910667">Выделить</translation>
<translation id="8339163506404995330">Страницы на Ñтом Ñзыке (<ph name="LANGUAGE" />) не будут переводитьÑÑ Ð°Ð²Ñ‚Ð¾Ð¼Ð°Ñ‚Ð¸Ñ‡ÐµÑки</translation>
@@ -2314,6 +2365,7 @@
<translation id="8507227106804027148">ÐšÐ¾Ð¼Ð°Ð½Ð´Ð½Ð°Ñ Ñтрока</translation>
<translation id="8508648098325802031">Значок поиÑка</translation>
<translation id="8511402995811232419">Открыть наÑтройки файлов cookie</translation>
+<translation id="8519753333133776369">Разрешенное админиÑтратором HID-уÑтройÑтво</translation>
<translation id="8522552481199248698">Защитите Ñвой аккаунт Google и Ñмените пароль Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ Chrome.</translation>
<translation id="8530813470445476232">Удалить иÑторию браузера, файлы cookie, кеш и другие данные в наÑтройках Chrome</translation>
<translation id="8533619373899488139">Чтобы поÑмотреть ÑпиÑок заблокированных URL и узнать, какие ещё правила заданы ÑиÑтемным админиÑтратором, перейдите на Ñтраницу &lt;strong&gt;chrome://policy&lt;/strong&gt;.</translation>
@@ -2325,7 +2377,6 @@
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{СброÑить разрешение}one{СброÑить вÑе разрешениÑ}few{СброÑить вÑе разрешениÑ}many{СброÑить вÑе разрешениÑ}other{СброÑить вÑе разрешениÑ}}</translation>
<translation id="8555010941760982128">Укажите Ñтот код при оформлении заказа</translation>
<translation id="8557066899867184262">CVC-код указан на обратной Ñтороне карты.</translation>
-<translation id="8558485628462305855">Чтобы проÑматривать контент в режиме дополненной реальноÑти, обновите приложение ARCore.</translation>
<translation id="8559762987265718583">Ðе удалоÑÑŒ уÑтановить защищенное Ñоединение Ñ Ð´Ð¾Ð¼ÐµÐ½Ð¾Ð¼ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> из-за неверных наÑтроек ÑиÑтемных чаÑов и ÐºÐ°Ð»ÐµÐ½Ð´Ð°Ñ€Ñ (<ph name="DATE_AND_TIME" />).</translation>
<translation id="8564182942834072828">ÐеÑколько документов/без разбора по копиÑм</translation>
<translation id="8564985650692024650">Chromium рекомендует ÑброÑить пароль, иÑпользуемый в подразделении <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" />, еÑли вы указывали его на других Ñайтах.</translation>
@@ -2344,6 +2395,7 @@
<translation id="865032292777205197">Датчики движениÑ</translation>
<translation id="8663226718884576429">Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾ заказе, <ph name="TOTAL_LABEL" />, дополнительные ÑведениÑ</translation>
<translation id="8666678546361132282">ÐнглийÑкий</translation>
+<translation id="8669306706049782872">ИÑпользование Ñведений о вашем Ñкране, чтобы открывать и размещать окна</translation>
<translation id="867224526087042813">ПодпиÑÑŒ</translation>
<translation id="8676424191133491403">Без задержки</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, ответ, <ph name="ANSWER" /></translation>
@@ -2370,6 +2422,7 @@
<translation id="8731544501227493793">Кнопка "Управление паролÑми". Ðажмите Ввод, чтобы перейти к управлению паролÑми в наÑтройках Chrome.</translation>
<translation id="8734529307927223492">Вашим уÑтройÑтвом <ph name="DEVICE_TYPE" /> управлÑет <ph name="MANAGER" /></translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />. Ðажмите Tab и затем Ввод, чтобы открыть новое окно в режиме инкогнито.</translation>
+<translation id="8737685506611670901">обработку вÑех ÑÑылок типа "<ph name="PROTOCOL" />" вмеÑто ÑервиÑа <ph name="REPLACED_HANDLER_TITLE" /></translation>
<translation id="8738058698779197622">Ð”Ð»Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ð±ÐµÐ·Ð¾Ð¿Ð°Ñного Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ð½ÐµÐ¾Ð±Ñ…Ð¾Ð´Ð¸Ð¼Ð¾, чтобы Ð¿Ð¾ÐºÐ°Ð·Ð°Ð½Ð¸Ñ ÑиÑтемных чаÑов были верны. Причина в том, что Ñертификаты Ð´Ð»Ñ Ð¸Ð´ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ð¸ Ñайтов имеют ограниченный Ñрок дейÑтвиÑ. ЕÑли чаÑÑ‹ на уÑтройÑтве неточны, Chromium не может проверить актуальноÑÑ‚ÑŒ Ñтих Ñертификатов.</translation>
<translation id="8740359287975076522">Ðе удаетÑÑ Ð½Ð°Ð¹Ñ‚Ð¸ &lt;abbr id="dnsDefinition"&gt;DNS-адреÑ&lt;/abbr&gt; Ñайта <ph name="HOST_NAME" />. ВыполнÑетÑÑ Ð´Ð¸Ð°Ð³Ð½Ð¾Ñтика.</translation>
<translation id="8742371904523228557">Ваш код Ð´Ð»Ñ ÑервиÑа <ph name="ORIGIN" />: <ph name="ONE_TIME_CODE" />.</translation>
@@ -2397,6 +2450,7 @@
<translation id="883848425547221593">Другие закладки</translation>
<translation id="884264119367021077">ÐÐ´Ñ€ÐµÑ Ð´Ð¾Ñтавки</translation>
<translation id="884923133447025588">Ðе обнаружен механизм отзыва.</translation>
+<translation id="8849262850971482943">Ð”Ð»Ñ Ð´Ð¾Ð¿Ð¾Ð»Ð½Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð¾Ð¹ защиты иÑпользуйте виртуальную карту.</translation>
<translation id="885730110891505394">ДоÑтуп Google</translation>
<translation id="8858065207712248076">Chrome рекомендует ÑброÑить пароль, иÑпользуемый в подразделении <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" />, еÑли вы указывали его на других Ñайтах.</translation>
<translation id="885906927438988819">ЕÑли вÑе правильно, <ph name="BEGIN_LINK" />воÑпользуйтеÑÑŒ инÑтрументом "ДиагноÑтика Ñетей Windows"<ph name="END_LINK" />.</translation>
@@ -2446,6 +2500,7 @@
<translation id="9004367719664099443">Ð¡ÐµÐ°Ð½Ñ VR запущен</translation>
<translation id="9005998258318286617">Ðе удалоÑÑŒ загрузить PDF-документ.</translation>
<translation id="9008201768610948239">ПропуÑтить</translation>
+<translation id="901834265349196618">ÑÐ»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð°Ñ Ð¿Ð¾Ñ‡Ñ‚Ð°</translation>
<translation id="9020200922353704812">Ðеобходимо указать платежный Ð°Ð´Ñ€ÐµÑ ÐºÐ°Ñ€Ñ‚Ñ‹</translation>
<translation id="9020542370529661692">Эта Ñтраница переведена на <ph name="TARGET_LANGUAGE" />.</translation>
<translation id="9020742383383852663">A8</translation>
@@ -2494,6 +2549,7 @@
<translation id="9150045010208374699">ИÑпользование камеры</translation>
<translation id="9150685862434908345">ÐдминиÑтратор может удаленно менÑÑ‚ÑŒ наÑтройки браузера и управлÑÑ‚ÑŒ дейÑтвиÑми вне браузера Chrome на Ñтом уÑтройÑтве. <ph name="BEGIN_LINK" />Подробнее…<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">Обновлено</translation>
+<translation id="9155211586651734179">Какие периферийные аудиоуÑтройÑтва подключены.</translation>
<translation id="9157595877708044936">ÐаÑтройка...</translation>
<translation id="9158625974267017556">C6 (конверт)</translation>
<translation id="9164029392738894042">Проверка точноÑти</translation>
diff --git a/chromium/components/strings/components_strings_si.xtb b/chromium/components/strings/components_strings_si.xtb
index 4f54efa9877..f7f5a541bc4 100644
--- a/chromium/components/strings/components_strings_si.xtb
+++ b/chromium/components/strings/components_strings_si.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">විස්තර බලන්න</translation>
<translation id="1030706264415084469"><ph name="URL" /> හට ඔබේ උපà·à¶‚ගය මත විà·à·à¶½ දත්ත ස්ථිරව ගබඩ෠කිරීමට අවà·à·Šâ€à¶ºà¶ºà·’</translation>
<translation id="1032854598605920125">දක්ෂිණà·à·€à¶»à·Šà¶­à·€ කරකවන්න</translation>
+<translation id="1033329911862281889">අප්â€à¶»à·ƒà·’ද්ධ ප්â€à¶»à¶šà·à¶»à¶º ඔබව සබà·à¶³à·’à·€ අදෘà·à·Šâ€à¶ºà¶¸à·à¶± බවට පත් නොකරයි:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ඔවුන් භà·à·€à·’ත කරන අඩවි සහ සේවà·à·€à¶½à¶§ පà·à¶¸à·’ණීම් දà·à¶šà·’ය à·„à·à¶šà·’ය<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />සේවà·à¶ºà·à¶¢à¶šà¶ºà¶±à·Šà¶§ හ෠පà·à·ƒà¶½à·Šà·€à¶½à¶§ බ්â€à¶»à·€à·”ස් කිරීමේ ක්â€à¶»à·’යà·à¶šà·à¶»à¶šà¶¸à·Š හඹ෠යà·à¶¸à¶§ à·„à·à¶šà·’ය<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />අන්තර්ජà·à¶½ සේව෠සපයන්නන් වෙබ් තදබදය නිරීක්ෂණය කළ à·„à·à¶šà·’ය<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">ක්â€à¶»à·’ය෠විරහිතය</translation>
<translation id="1036982837258183574">පූර්ණ තිරයෙන් පිටවීමට |<ph name="ACCELERATOR" />| ඔබන්න</translation>
<translation id="1038106730571050514">යà·à¶¢à¶±à· පෙන්වන්න</translation>
<translation id="1038842779957582377">නොදන්න෠නමක්</translation>
<translation id="1041998700806130099">à·€à·à¶© පත්â€à¶» පණිවුඩය</translation>
<translation id="1048785276086539861">ඔබ අනුසටහන් සංස්කරණය කරන විට, මෙම ලේඛනය තනි පිටු දසුනකට ආපසු යනු ඇත</translation>
-<translation id="1049743911850919806">අප්â€à¶»à¶šà¶§</translation>
<translation id="1050038467049342496">අනෙකුත් යෙදුම් වසන්න</translation>
<translation id="1055184225775184556">&amp;එක් කිරීම පසුගමනය කිරීම</translation>
<translation id="1056898198331236512">අවවà·à¶¯à¶ºà¶ºà·’</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">ප්â€à¶»à¶­à·’පත්ති තà·à·€à¶šà·à¶½à·’ක මතකය හරි</translation>
<translation id="1130564665089811311">පිටුව පරිවර්තනය කරන්න බොත්තම, Google පරිවර්තනය සමඟ මෙම පිටුව පරිවර්තනය කිරීමට Enter ඔබන්න</translation>
<translation id="1131264053432022307">ඔබ පිටපත් කළ රූපය</translation>
+<translation id="1142846828089312304">අප්â€à¶»à·ƒà·’ද්ධ තුළ තෙවන පà·à¶»à·Šà·à·Šà·€ කුකි අවහිර කරන්න</translation>
<translation id="1150979032973867961">මෙම සේවà·à¶¯à·à¶ºà¶šà¶ºà¶§ එය <ph name="DOMAIN" /> බව සනà·à¶® කිරීමට නොහà·à¶šà·’ විය; එහි ආරක්ෂණ සහතිකය ඔබගේ පරිගණකයෙහි මෙහෙයුම් පද්ධතිය මගින් විà·à·Šà·€à·à·ƒ නොකරයි. මෙය à·€à·à¶»à¶¯à·’ වින්â€à¶ºà·à·ƒ කිරීමක් හ෠ප්â€à¶»à·„à·à¶»à¶šà¶ºà¶šà·” ඔබගේ සබà·à¶³à·”මට බà·à¶°à· කිරීමක් නිස෠විය à·„à·à¶šà·’ය.</translation>
<translation id="1151972924205500581">රහස්වචනය අවà·à·Šâ€à¶ºà¶ºà·’</translation>
<translation id="1156303062776767266">ඔබ දේà·à·“ය හ෠පොදු ගොනුවක් නරඹමින් සිටී</translation>
@@ -64,7 +70,6 @@
<translation id="1178581264944972037">විරà·à¶¸à¶º</translation>
<translation id="1181037720776840403">ඉවත් කරන්න</translation>
<translation id="1186201132766001848">මුරපද පරීක්â€à·‚෠කරන්න</translation>
-<translation id="1195210374336998651">යෙදුම් à·ƒà·à¶šà·ƒà·“ම් වෙත යන්න</translation>
<translation id="1195558154361252544">ඔබ අවසර දෙන ඒව෠හà·à¶» සියලුම වෙබ් අඩවි සඳහ෠දà·à¶±à·”ම්දීම් ස්වයංක්â€à¶»à·“යව අවහිර කෙරෙති</translation>
<translation id="1197088940767939838">තà·à¶¹à·’ලි</translation>
<translation id="1201402288615127009">ඊළඟ</translation>
@@ -111,7 +116,7 @@
<translation id="1307966114820526988">අත් හරින ලද විà·à·šà·‚à·à¶‚ග</translation>
<translation id="1308113895091915999">දීමනà·à·€à¶šà·Š තිබේ</translation>
<translation id="1312803275555673949">එයට සහà·à¶º දෙන à·ƒà·à¶šà·Šà·‚à·’ මොනවà·à¶¯?</translation>
-<translation id="131405271941274527"><ph name="URL" /> හට ඔබ NFC උපà·à¶‚ගයක ඔබේ දුරකථනය තට්ටු කරන විට තතු යà·à·€à·“මට සහ ලà·à¶¶à·“මට අවà·à·Šâ€à¶ºà¶ºà·’</translation>
+<translation id="1314311879718644478">ආවර්ධිත යථà·à¶»à·Šà¶­ අන්තර්ගතය බලන්න</translation>
<translation id="1314509827145471431">දකුණ බà·à¶³à·“ම</translation>
<translation id="1318023360584041678">ටà·à¶¶ සමූහයක සුරකින ලදි</translation>
<translation id="1319245136674974084">මෙම යෙදුම සඳහ෠නà·à·€à¶­ නොඅසන්න</translation>
@@ -161,6 +166,7 @@
<translation id="142858679511221695">ක්ලවුඩ් පරිà·à·“ලක</translation>
<translation id="1428729058023778569">මෙම අඩවිය HTTPS සඳහ෠සහය නොදක්වන බà·à·€à·’න් â€à¶”බ මෙම අනතුරු ඇඟවීම දකියි. <ph name="BEGIN_LEARN_MORE_LINK" />තව දà·à¶± ගන්න<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">මුද්â€à¶»à¶«à¶º කරන්න</translation>
+<translation id="1432187715652018471">පිටුවට සේව෠හසුරුවන්නෙක් ස්ථà·à¶´à¶±à¶º කිරීමට අවà·à·Šâ€à¶ºà¶ºà·’.</translation>
<translation id="1432581352905426595">සෙවීම් යà·à¶±à·Šà¶­à·Šâ€à¶»à¶« කළමණà·à¶šà¶»à¶«à¶º කරන්න</translation>
<translation id="1436185428532214179">ඔබගේ උපà·à¶‚ගයෙහි ගොනු සහ à·†à·à¶½à·Šà¶©à¶» සංස්කරණය කිරීමට ඉල්ලිය à·„à·à¶šà·’ය</translation>
<translation id="1442386063175183758">දකුණු දොරටු නà·à¶¸à·“ම</translation>
@@ -181,6 +187,12 @@
<translation id="1483493594462132177">යවන්න</translation>
<translation id="1484290072879560759">නà·à·€à·Šà¶œà¶­ කිරීමේ ලිපිනය තà·à¶»à·à¶œà¶±à·Šà¶±</translation>
<translation id="1492194039220927094">ප්â€à¶»à¶­à·’පත්ති පුෂ්:</translation>
+<translation id="149293076951187737">ඔබ Chrome අප්â€à¶»à·ƒà·’ද්ධ ටà·à¶¶ සියල්ල à·€à·à·ƒà·– විට, එම ටà·à¶¶à·€à¶½ ඔබගේ ක්â€à¶»à·’යà·à¶šà·à¶»à¶šà¶¸à·Š මෙම උපà·à¶‚ගයෙන් හිස් වේ:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />බ්â€à¶»à·€à·”ස් කිරීමේ ක්â€à¶»à·’යà·à¶šà·à¶»à¶šà¶¸<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />සෙවීම් ඉතිහà·à·ƒà¶º<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />පà·à¶»à¶¸à·€à¶½ ඇතුළත් කළ තොරතුරු<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">ආපසු පටිත්ත වෙත</translation>
<translation id="1501859676467574491">ඔබේ Google ගිණුමෙන් කà·à¶©à·Šà¶´à¶­à·Š පෙන්වන්න</translation>
<translation id="1507202001669085618">&lt;p&gt;ඔබ සබà·à¶³à·’ වීමට à·„à·à¶šà·’ වීමට පෙර පුරනය වීමට අවà·à·Šâ€à¶º වන Wi-Fi ද්වà·à¶»à¶ºà¶šà·Š භà·à·€à·’ත෠කරන්නේ නම් ඔබ මෙම දà·à·‚ය දකිනු ඇත.&lt;/p&gt;
@@ -208,6 +220,8 @@
<translation id="1559572115229829303">&lt;p&gt;ඔබගේ උපà·à¶‚ගයේ දිනය සහ වේලà·à·€ (<ph name="DATE_AND_TIME" />) à·€à·à¶»à¶¯à·’ නිස෠<ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> වෙත පුද්ගලික සබà·à¶³à·”ම ස්ථà·à¶´à¶±à¶º කළ නොහà·à¶šà·’ය.&lt;/p&gt;
&lt;p&gt;කරුණà·à¶šà¶» &lt;strong&gt;à·ƒà·à¶šà·ƒà·“ම්&lt;/strong&gt; යෙදුම තුළ &lt;strong&gt;à·ƒà·à¶¸à·à¶±à·Šâ€à¶º&lt;/strong&gt; කොටස වෙතින් දිනය සහ වේලà·à·€ සීරුමà·à¶»à·” කරන්න.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">ඔබගේ පරිපà·à¶½à¶š ඔබගේ උපà·à¶‚ගය <ph name="DATE" /> <ph name="TIME" />ට යළි ආරම්භ කරනු ඇත</translation>
+<translation id="156703335097561114">ලිපින, අතුරු මුහුණත් වින්â€à¶ºà·à·ƒ කිරීම සහ සම්බන්ධත෠ගුණත්වය à·€à·à¶±à·’ ජà·à¶½à¶šà¶»à¶« තොරතුරු</translation>
<translation id="1567040042588613346">මෙම ප්â€à¶»à¶­à·’පත්තිය අපේක්ෂිත පරිදි ක්â€à¶»à·’යà·à¶­à·Šà¶¸à¶š වන නමුත් සමà·à¶± අගයක් වෙනත් තà·à¶±à¶š සකස෠ඇති අතර එය මෙම ප්â€à¶»à¶­à·’පත්තියෙන් ඉක්මව෠යයි.</translation>
<translation id="1569487616857761740">කල් ඉකුත්වීමේ දිනය ඇතුළත් කරන්න</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@
<translation id="1583429793053364125">මෙම වෙබ් පිටුව සංසංදර්à·à¶±à¶º කිරීමේදී යමක් à·€à·à¶»à¶¯à·“ ඇත.</translation>
<translation id="1586541204584340881">ඔබ ස්ථà·à¶´à¶± කර ඇති දිගු මොනවà·à¶¯</translation>
<translation id="1588438908519853928">à·ƒà·à¶¸à·à¶±à·Šâ€à¶º</translation>
+<translation id="1589050138437146318">ARCore ස්ථà·à¶´à¶±à¶º කරන්නද?</translation>
<translation id="1592005682883173041">ස්ථà·à¶±à·“ය දත්ත ප්â€à¶»à·€à·šà·à¶º</translation>
<translation id="1594030484168838125">තà·à¶»à¶±à·Šà¶±</translation>
<translation id="160851722280695521">Chrome තුළ Dino Run ක්â€à¶»à·“ඩ෠කරන්න</translation>
@@ -254,7 +269,7 @@
<translation id="1711234383449478798"><ph name="POLICY_NAME" /> <ph name="VALUE" /> වෙත සකස෠නà·à¶­à·’ නිස෠නොසලක෠හරින ලදි.</translation>
<translation id="1712552549805331520"><ph name="URL" /> හට ස්ථිරව දත්ත ඔබේ ස්ථà·à¶±à·“ය පරිගණකයේ ගබඩ෠කිරීමට අවà·à·Šâ€à¶ºà¶ºà·’.</translation>
<translation id="1713628304598226412">බඳුන 2</translation>
-<translation id="1715874602234207">F</translation>
+<translation id="1715874602234207">සි</translation>
<translation id="1717218214683051432">චලන සංවේදක</translation>
<translation id="1717494416764505390">තà·à¶´à·à¶½à·Š පෙට්ටිය 3</translation>
<translation id="1718029547804390981">ලේඛනය අනුසටහන් කිරීමට විà·à·à¶½ à·€à·à¶©à·’යි</translation>
@@ -283,6 +298,7 @@
මà·à¶­à·˜à¶šà·à·€ à·€à·à¶»à¶¯à·’à·€ ආකෘති කර ඇත, එය බ්â€à¶»à·€à·”සරය
<ph name="SITE" /> සඳහ෠වන ඔබේ ඉල්ලීම ඉටු කිරීමෙන් වළක්වයි. වෙබ් අඩවියක් සඳහ෠ආරක්â€à·‚à·à·€ සහ වෙනත් ලක්â€à·‚ණ
වින්â€à¶ºà·à·ƒ කිරීමට වෙබ් අඩවිය ක්â€à¶»à·’ය෠කරවන්නන් විසින් මූලà·à¶»à¶¸à·Šà¶· ප්â€à¶»à¶­à·’පත්ති භà·à·€à·’ත කරනු ලà·à¶¶à·’ය à·„à·à¶š.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Chromium à·„à·’ අප්â€à¶»à·ƒà·’ද්ධ ගà·à¶± තව දà·à¶± ගන්න<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">ඔබේ විවෘත කළ පටිති මෙහි දිස් වේ</translation>
<translation id="1791429645902722292">Google ස්මà·à¶§à·Š අගුල</translation>
@@ -410,6 +426,7 @@
<translation id="22081806969704220">බඳුන 3</translation>
<translation id="2212735316055980242">ප්â€à¶»à¶­à·’පත්තිය නොමà·à¶­</translation>
<translation id="2213606439339815911">ඇතුළත් කිරීම් ලබමින්...</translation>
+<translation id="2213612003795704869">පිටුව මුද්â€à¶»à¶«à¶º කර ඇත</translation>
<translation id="2215727959747642672">ගොනු සංස්කරණය</translation>
<translation id="2218879909401188352"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> à·„à·’ දà·à¶±à¶§ සිටින ප්â€à¶»à·„à·à¶»à¶šà¶ºà·’න්ට ඔබේ උපà·à¶‚ගයට à·„à·à¶±à·’ කරන, ඔබේ ජංගම බිලට à·ƒà·à¶Ÿà·€à·”ණු ගà·à·ƒà·Šà¶­à·” එක් කරන, හ෠ඔබේ පුද්ගලික තොරතුරු සොරකම් කරන භයà·à¶±à¶š යෙදුම් ස්ථà·à¶´à¶±à¶º කළ à·„à·à¶šà·’ය. <ph name="BEGIN_LEARN_MORE_LINK" />තව දà·à¶± ගන්න<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">අන්තර්ජà·à¶½à¶º නà·à¶­</translation>
@@ -419,6 +436,7 @@
<translation id="2248949050832152960">WebAuthn භà·à·€à·’ත කරන්න</translation>
<translation id="2250931979407627383">වමට දà·à¶»à¶º මසන්න</translation>
<translation id="225207911366869382">මෙම ප්â€à¶»à¶­à·’පත්තිය සඳහ෠අගය ක්ෂය කර ඇත.</translation>
+<translation id="2256115617011615191">දà·à¶±à·Š යළි අà·à¶»à¶¸à·Šà¶· කරන්න</translation>
<translation id="2258928405015593961">අනà·à¶œà¶­à¶ºà·š කල් ඉකුත් වීමේ දිනයක් ඇතුළත් කර නà·à·€à¶­ උත්සà·à·„ කරන්න</translation>
<translation id="225943865679747347">දà·à· කේතය: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">HTTP දà·à·‚ය</translation>
@@ -446,6 +464,7 @@
<translation id="2337852623177822836">à·ƒà·à¶šà·ƒà·“ම ඔබේ පරිපà·à¶½à¶š විසින් පà·à¶½à¶±à¶º කරයි</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> හට යුගල වීමට අවà·à·Šâ€à¶ºà¶ºà·’</translation>
<translation id="2346319942568447007">ඔබ පිටපත් කළ රූපය</translation>
+<translation id="2350796302381711542"><ph name="REPLACED_HANDLER_TITLE" /> වෙනුවට සියලු <ph name="PROTOCOL" /> සබà·à¶³à·’ විවෘත කිරීමට <ph name="HANDLER_HOSTNAME" />ට ඉඩ දෙන්නද?</translation>
<translation id="2354001756790975382">වෙනත් පිටු සලකුණු</translation>
<translation id="2354430244986887761">Google සුරක්ෂිත බ්â€à¶»à·€à·”ස් කිරීම මෑත දී <ph name="SITE" /> à·„à·’ <ph name="BEGIN_LINK" />à·„à·à¶±à·’කර යෙදුම් සොය෠ගත්තේය<ph name="END_LINK" />.</translation>
<translation id="2355395290879513365">ප්â€à¶»à·„à·à¶»à¶šà¶ºà¶±à·Šà¶§ ඔබ මෙම වෙබ් අඩවියේදී සොයන රූප දà·à¶š ඒව෠විකරණය කිරීමෙන් ඔබව රà·à·€à¶§à·“මට à·„à·à¶šà·’ වනු ඇත.</translation>
@@ -471,6 +490,7 @@
<translation id="2413528052993050574">මෙම සේවà·à¶¯à·à¶ºà¶šà¶ºà¶§ එය <ph name="DOMAIN" /> බව සනà·à¶® කිරීමට නොහà·à¶šà·’ විය; එහි ආරක්ෂණ සහතිකය අහà·à·ƒà·’ කර තිබිය à·„à·à¶šà·’ය. මෙය à·€à·à¶»à¶¯à·’ වින්â€à¶ºà·à·ƒ කිරීමක් හ෠ප්â€à¶»à·„à·à¶»à¶šà¶ºà¶šà·” ඔබගේ සබà·à¶³à·”මට බà·à¶°à· කිරීමක් නිස෠විය à·„à·à¶šà·’ය.</translation>
<translation id="2414886740292270097">අඳුරු</translation>
<translation id="2430968933669123598">Google ගිණුම කළමනà·à¶šà¶»à¶«à¶º කරන්න, ඔබගේ තොරතුරු, පෞද්ගලිකත්වය සහ ආරක්ෂà·à·€ කළමනà·à¶šà¶»à¶«à¶º කිරීමට Enter ඔබන්න</translation>
+<translation id="2436186046335138073"><ph name="HANDLER_HOSTNAME" /> හට සියලු <ph name="PROTOCOL" /> සබà·à¶³à·“න් විවෘත කිරීමට ඉඩ දෙන්නද?</translation>
<translation id="2438874542388153331">දකුණට සිවු වරක් අනින්න</translation>
<translation id="2450021089947420533">සංචà·à¶»</translation>
<translation id="2463739503403862330">සම්පූර්ණ කරන්න</translation>
@@ -478,6 +498,7 @@
<translation id="2465655957518002998">බෙද෠හà·à¶»à·“මේ ක්â€à¶»à¶¸à¶º තà·à¶»à·à¶œà¶±à·Šà¶±</translation>
<translation id="2465688316154986572">ස්ටේපල්</translation>
<translation id="2465914000209955735">Chrome තුළ ඔබ බà·à¶œà·™à¶± ඇති ගොනු කළමනà·à¶šà¶»à¶«à¶º කරන්න</translation>
+<translation id="2466004615675155314">වෙබය වෙතින් තොරතුරු පෙන්වන්න</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />ජà·à¶½ දà·à·‚හරණ ධà·à·€à¶±à¶º කරමින්<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">1-සිට-N පිළිවෙළ</translation>
<translation id="2470767536994572628">ඔබ අනුසටහන් සංස්කරණය කරන විට, මෙම ලේඛනය තනි පිටු දසුනකට සහ එහි මුල් කරකà·à·€à·“මට ආපසු යනු ඇත</translation>
@@ -498,6 +519,7 @@
<translation id="2523886232349826891">මෙම උපà·à¶‚ගයෙහි පමණක් සුරà·à¶šà·’ණි</translation>
<translation id="2524461107774643265">à·€à·à¶©à·’දුර තොරතුරු එක් කරන්න</translation>
<translation id="2529899080962247600">මෙම ක්ෂේත්â€à¶»à¶ºà¶§ <ph name="MAX_ITEMS_LIMIT" />කට වඩ෠වà·à¶©à·’ ඇතුළත් කිරීම් තිබිය යුතුය. සියලු à·€à·à¶©à·’දුර ඇතුළත් කිරීම් නොසලක෠හරිනු ඇත.</translation>
+<translation id="2535585790302968248">පුද්ගලිකව බ්â€à¶»à·€à·”ස් කිරීමට නව අප්â€à¶»à¶šà¶§ ටà·à¶¶à¶ºà¶šà·Š විවෘත කරන්න</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{සහ තව 1 ක්}one{සහ තව #ක්}other{සහ තව #ක්}}</translation>
<translation id="2536110899380797252">ලිපිනය එක් කරන්න</translation>
<translation id="2539524384386349900">හඳුනà·à¶œà¶±à·Šà¶±</translation>
@@ -523,7 +545,14 @@
<translation id="2597378329261239068">මෙම ලේඛනයේ රහස්වචනය ආරක්ෂ෠කර තිබේ. කරුණà·à¶šà¶» රහස්වචනයක් ඇතුළු කරන්න.</translation>
<translation id="2609632851001447353">විචලතà·</translation>
<translation id="2610561535971892504">පිටපත් කිරීමට ක්ලික් කිරීම</translation>
+<translation id="2617988307566202237">Chrome පහත තොරතුරු <ph name="BEGIN_EMPHASIS" />නොසුරකිනු ඇත<ph name="END_EMPHASIS" />:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ඔබගේ බ්â€à¶»à·€à·”ස් කිරීමේ ඉතිහà·à·ƒà¶º
+ <ph name="LIST_ITEM" />කුකි සහ අඩවි දත්ත
+ <ph name="LIST_ITEM" />පà·à¶»à¶¸ තුළ ඇතුළත් කළ තොරතුරු
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (ලියුම් කවරය)</translation>
+<translation id="2623663032199728144">ඔබගේ තිර පිළිබඳ තොරතුරු භà·à·€à·’ත කිරීමට ඉල්ලිය à·„à·à¶šà·’ය</translation>
<translation id="2625385379895617796">ඔබගේ ඔරලà·à·ƒà·”à·€ ඉදිරියෙන් සිටියි</translation>
<translation id="262745152991669301">USB උපà·à¶‚ග වෙත සම්බන්ධ වීමට ඉල්ලිය à·„à·à¶šà·’ය</translation>
<translation id="2629325967560697240">Chrome à·„à·’ ඉහළම ආරක්ෂà·à·€ ලබ෠ගà·à¶±à·“මට, <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />à·€à·à¶©à·’ දියුණු කළ ආරක්ෂà·à·€ ක්â€à¶»à·’යà·à¶­à·Šà¶¸à¶š කරන්න<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -557,6 +586,7 @@
<translation id="2709516037105925701">ස්වයං පිරවීම</translation>
<translation id="2713444072780614174">සුදු</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />, Chrome à·ƒà·à¶šà·ƒà·“ම් තුළ ඔබගේ ගෙවීම් සහ ණය කà·à¶©à·Šà¶´à¶­à·Š තතු කළමනà·à¶šà¶»à¶«à¶º කිරීමට Tab ඔබ෠අනතුරුව Enter ඔබන්න</translation>
+<translation id="271663710482723385">පූර්ණ තිරයෙන් පිටවීමට |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| ඔබන්න</translation>
<translation id="2721148159707890343">ඉල්ලීම à·ƒà·à¶»à·Šà¶®à¶šà¶ºà·’</translation>
<translation id="2723669454293168317">Chrome à·ƒà·à¶šà·ƒà·“ම් තුළ ආරක්ෂක පරීක්ෂà·à·€à¶šà·Š ධà·à·€à¶±à¶º කරන්න</translation>
<translation id="2726001110728089263">Side Tray</translation>
@@ -587,6 +617,7 @@
<translation id="2850739647070081192">Invite (ලියුම් කවරය)</translation>
<translation id="2856444702002559011">ප්â€à¶»à·„à·à¶»à¶šà¶ºà¶±à·Š <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> වෙතින් ඔබේ තොරතුරු සොරකම් කිරීමට උත්සà·à·„ කරනව෠විය à·„à·à¶š (උදà·à·„රණ ලෙස, මුරපද, පණිවිඩ, හ෠ණයපත්). <ph name="BEGIN_LEARN_MORE_LINK" />තව දà·à¶± ගන්න<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">මෙම වෙබ් අඩවිය ආක්â€à¶»à¶¸à¶«à·’ක හ෠නොමඟ යවන දà·à¶±à·Šà·€à·“ම් පෙන්වයි.</translation>
+<translation id="286512204874376891">අතථ්â€à¶º කà·à¶©à·Šà¶´à¶­à¶šà·Š සිදු විය à·„à·à¶šà·’ වංචà·à·€à·™à¶±à·Š ඔබව සුරක්ෂිත කර ගà·à¶±à·“මට ඔබගේ à·ƒà·à¶¶à·‘ කà·à¶©à·Šà¶´à¶­ මෙන් වෙස්වළ෠ගනී. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">මිත්â€à¶»</translation>
<translation id="2876489322757410363">බà·à·„ිර යෙදුමක් හරහ෠ගෙවීමට අප්â€à¶»à·ƒà·’ද්ධ ප්â€à¶»à¶šà·à¶»à¶º à·„à·à¶» යමින්. ඉදිරියට යන්නද?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />, Chrome à·ƒà·à¶šà·ƒà·“ම් තුළ ඔබගේ සුරක්ෂිත බ්â€à¶»à·€à·”ස් කිරීම කළමනà·à¶šà¶»à¶«à¶º කිරීමට Tab ඔබ෠අනතුරුව Enter ඔබන්න</translation>
@@ -611,6 +642,7 @@
<translation id="2930577230479659665">සෑම පිටපතකටම පසුව කප්පà·à¶¯à·” කරන්න</translation>
<translation id="2932085390869194046">මුරපදය යà·à¶¢à¶±à· කරන්න...</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019"><ph name="PROTOCOL" /> සබà·à¶³à·’ විවෘත කරන්න</translation>
<translation id="2941952326391522266">මෙම සේවà·à¶¯à·à¶ºà¶šà¶ºà¶§ එය <ph name="DOMAIN" /> බව සනà·à¶® කිරීමට නොහà·à¶šà·’ විය; එහි ආරක්ෂණ සහතිකය <ph name="DOMAIN2" /> වෙතිනි. මෙය à·€à·à¶»à¶¯à·’ වින්â€à¶ºà·à·ƒ කිරීමක් හ෠ප්â€à¶»à·„à·à¶»à¶šà¶ºà¶šà·” ඔබගේ සබà·à¶³à·”මට බà·à¶°à· කිරීමක් නිස෠විය à·„à·à¶šà·’ය.</translation>
<translation id="2943895734390379394">උඩුගත කිරීමේ වේලà·à·€:</translation>
<translation id="2948083400971632585">ඔබට සබà·à¶³à·”මක් සඳහ෠වින්â€à¶ºà·à·ƒ කළ ඕනෑම ප්â€à¶»à·œà¶šà·Šà·ƒà·’යක් à·ƒà·à¶šà·ƒà·”ම් පිටුවෙන් අබල කළ à·„à·à¶š.</translation>
@@ -643,6 +675,7 @@
<translation id="3037605927509011580">අනේ, අපොයි!</translation>
<translation id="3041612393474885105">සහතික තොරතුරු</translation>
<translation id="3044034790304486808">ඔබගේ පර්යේෂණය නà·à·€à¶­ පටන් ගන්න</translation>
+<translation id="305162504811187366">වේල෠මුද්â€à¶»à·, සංග්â€à¶»à·à·„ක සහ සේවà·à¶½à·à¶·à·“ à·ƒà·à·ƒà·’ ID ඇතුළුව, Chrome දුරස්ථ ඩෙස්ක්ටොප් ඉතිහà·à·ƒà¶º</translation>
<translation id="3060227939791841287">C9 (ලියුම් කවරය)</translation>
<translation id="3061707000357573562">පà·à¶ à·Š සේවà·à·€</translation>
<translation id="306573536155379004">ක්â€à¶»à·“ඩà·à·€ ඇරඹිණි.</translation>
@@ -683,6 +716,7 @@
<translation id="3197136577151645743">ඔබ මෙම උපà·à¶‚ගය සක්â€à¶»à·’යව භà·à·€à·’ත කරන අවස්ථà·à·€ දà·à¶± ගà·à¶±à·“මට ඉල්ලිය à·„à·à¶šà·’ය</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />, Chrome à·ƒà·à¶šà·ƒà·“ම් තුළ ඔබ සමමුහුර්ත කරන තොරතුරු කළමනà·à¶šà¶»à¶«à¶º කිරීමට Tab ඔබà·ï»¿ අනතුරුව Enter ඔබන්න</translation>
<translation id="320323717674993345">ගෙවීම අවලංගු කරන්න</translation>
+<translation id="3203366800380907218">වෙබය වෙතින්</translation>
<translation id="3207960819495026254">පිටුසලකුණු කළ</translation>
<translation id="3209034400446768650">පිටුවට මුදල් අය කළ à·„à·à¶šà·’ය</translation>
<translation id="3212581601480735796"><ph name="HOSTNAME" /> මත ඔබේ ක්â€à¶»à·’යà·à¶šà·à¶»à¶šà¶¸ නිරීක්â€à·‚ණ කෙරේ</translation>
@@ -699,10 +733,12 @@
<translation id="3234666976984236645">මෙම අඩවිය මත à·€à·à¶¯à¶œà¶­à·Š අන්තර්ගත සෑම වඉටම හඳුනà·à¶œà¶±à·Šà¶±</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />, ඔබගේ බ්â€à¶»à·€à·”සරයේ පෙනුම අභිරුචිකරණය කිරීමට Tab ඔබ෠අනතුරුව Enter ඔබන්න</translation>
<translation id="3240791268468473923">සුරක්ෂිත ගෙවීම් අක්තපත්â€à¶» ගà·à·…පෙන අක්තපත්â€à¶» පත්â€à¶»à¶º විවෘත කර නà·à¶­</translation>
+<translation id="324180406144491771">“<ph name="HOST_NAME" />†සබà·à¶³à·’ අවහිර කර ඇත</translation>
<translation id="3249845759089040423">විනà·à¶¯à¶¢à¶±à¶š</translation>
<translation id="3252266817569339921">ප්â€à¶»à¶‚à·</translation>
<translation id="3257954757204451555">මෙම තොරතුරු පිටුපස සිටින්නේ කවුද?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />, Google දින දර්à·à¶±à¶º තුළ නව සිදුවීමක් ඉක්මනින් තà·à¶±à·“මට Tab ඔබ෠අනතුරුව Enter ඔබන්න</translation>
+<translation id="3261488570342242926">අතථ්â€à¶º කà·à¶©à·Šà¶´à¶­à·Š ගà·à¶± දà·à¶± ගන්න</translation>
<translation id="3264837738038045344">Chrome à·ƒà·à¶šà·ƒà·“ම් කළමනà·à¶šà¶»à¶«à¶º කරන්න බොත්තම, ඔබගේ Chrome à·ƒà·à¶šà·ƒà·“ම් වෙත යà·à¶¸à¶§ Enter ඔබන්න</translation>
<translation id="3266793032086590337">අගය (ගà·à¶§à·”ම්කà·à¶»à·“)</translation>
<translation id="3268451620468152448">ටà·à¶¶ විවෘත කරන්න</translation>
@@ -716,6 +752,7 @@
<translation id="3288238092761586174"><ph name="URL" /> හට ඔබගේ ගෙවීම සත්â€à¶ºà·à¶´à¶±à¶º කිරීම සඳහ෠අතිරේක පියවර ගà·à¶±à·“මට අවà·à·Šâ€à¶º විය à·„à·à¶šà·’ය</translation>
<translation id="3293642807462928945"><ph name="POLICY_NAME" /> ප්â€à¶»à¶­à·’පත්තිය ගà·à¶± තව දà·à¶± ගන්න</translation>
<translation id="3295444047715739395">Chrome à·ƒà·à¶šà·ƒà·“ම් තුළ ඔබගේ මුරපද බලන්න සහ කළමනà·à¶šà¶»à¶«à¶º කරන්න</translation>
+<translation id="3303795387212510132"><ph name="PROTOCOL_SCHEME" /> සබà·à¶³à·’ විවෘත කිරීමට යෙදුමට ඉඩ දෙන්නද?</translation>
<translation id="3303855915957856445">සෙවුම් ප්â€à¶»à¶­à·’ඵල හමු නොවිණි</translation>
<translation id="3304073249511302126">බ්ලූටූත් ස්කෑන් කිරීම</translation>
<translation id="3308006649705061278">සංවිධà·à¶± එ්කකය (OU)</translation>
@@ -729,12 +766,6 @@
<translation id="3345782426586609320">ඇස්</translation>
<translation id="3355823806454867987">ප්â€à¶»à·œà¶šà·Šà·ƒà·’ à·ƒà·à¶šà·ƒà·”ම් වෙනස් කරන්න...</translation>
<translation id="3360103848165129075">ගෙවීම් හසුරුවන පත්â€à¶»à¶º</translation>
-<translation id="3361596688432910856">Chrome පහත තොරතුරු <ph name="BEGIN_EMPHASIS" />නොසුරකිනු ඇත<ph name="END_EMPHASIS" />:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />ඔබේ බ්â€à¶»à·€à·”ස් කිරීමේ ඉතිහà·à·ƒà¶º
- <ph name="LIST_ITEM" />කුකීස් සහ අඩවියේ දත්ත
- <ph name="LIST_ITEM" />පà·à¶»à¶¸à·€à¶½ ඇතුළු කළ තොරතුරු
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">මෙම ප්â€à¶»à¶­à·’පත්තිය අත්හරින ලද <ph name="OLD_POLICY" /> ප්â€à¶»à¶­à·’පත්තියෙන් ස්වයංක්â€à¶»à·“යව පිටපත් කරන ලදි. ඒ වෙනුවෙට ඔබ මෙම ප්â€à¶»à¶­à·’පත්තිය භà·à·€à·’ත කළ යුතු ය.</translation>
<translation id="3364869320075768271"><ph name="URL" /> ඔබේ අතත්â€à¶º යථà·à¶»à·Šà¶® උපà·à¶‚ගය සහ දත්ත භà·à·€à·’ත කිරීමට කà·à¶¸à¶­à·’යි</translation>
<translation id="3366477098757335611">කà·à¶©à·Šà¶´à¶­à·Š බලන්න</translation>
@@ -817,7 +848,6 @@
<translation id="3587738293690942763">මà·à¶¯</translation>
<translation id="3592413004129370115">Italian (ලියුම් කවරය)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{ඔබට ඕනෑම වේලà·à·€à¶š ඔබගේ සමූහය යළි à·ƒà·à¶šà·ƒà·’ය à·„à·à¶šà·’ය. නව සමූහයකට එක් වීමට දිනක් පමණ ගත වේ.}=1{ඔබට ඕනෑම වේලà·à·€à¶š ඔබගේ සමූහය යළි à·ƒà·à¶šà·ƒà·’ය à·„à·à¶šà·’ය. නව සමූහයකට එක් වීමට දිනක් පමණ ගත වේ.}one{ඔබට ඕනෑම වේලà·à·€à¶š ඔබගේ සමූහය යළි à·ƒà·à¶šà·ƒà·’ය à·„à·à¶šà·’ය. නව සමූහයකට එක් වීමට දින {NUM_DAYS}ක් ගත වේ.}other{ඔබට ඕනෑම වේලà·à·€à¶š ඔබගේ සමූහය යළි à·ƒà·à¶šà·ƒà·’ය à·„à·à¶šà·’ය. නව සමූහයකට එක් වීමට දින {NUM_DAYS}ක් ගත වේ.}}</translation>
-<translation id="3596012367874587041">යෙදුම් à·ƒà·à¶šà·ƒà·“ම්</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">ඔබේ පරිපà·à¶½à¶šà¶ºà· යෙදුම අවහිර කර ඇත</translation>
<translation id="3608932978122581043">පà·à·‚ණ දිà·à·à¶±à¶­à·’ය</translation>
@@ -860,6 +890,7 @@
<translation id="370972442370243704">සංචà·à¶» ක්â€à¶»à·’යà·à¶­à·Šà¶¸à¶š කරන්න</translation>
<translation id="3711895659073496551">අත්හිටුවන්න</translation>
<translation id="3712624925041724820">බලපත්â€à¶» අවසන්</translation>
+<translation id="3714633008798122362">ජà·à¶½ දිනදසුන</translation>
<translation id="3714780639079136834">ජංගම දත්ත à·„à· Wi-Fi ක්â€à¶»à·’යà·à¶­à·Šà¶¸à¶š කරමින්</translation>
<translation id="3715597595485130451">Wi-Fi වෙත සම්බන්ධ වන්න</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />ප්â€à¶»à·œà¶šà·Šà·ƒà·’, සුරà·à¶šà·”ම් පවුර සහ DNS වින්â€à¶ºà·à·ƒ කිරීම පරීක්ෂ෠කරමින්<ph name="END_LINK" /></translation>
@@ -921,6 +952,7 @@
<translation id="3906954721959377182">ටà·à¶¶à·Šà¶½à¶§à·Š</translation>
<translation id="3909477809443608991"><ph name="URL" /> ආරක්â€à·‚ිත අන්තර්ගතය ධà·à·€à¶± කිරීමට කà·à¶¸à¶­à·’යි. ඔබේ උපà·à¶‚ගයේ අනන්â€à¶ºà¶­à·à·€ Google විසින් සත්â€à¶ºà·à¶´à¶± කරනු ලබන අතර මෙම වෙබ් අඩවිය විසින් ප්â€à¶»à·€à·šà· වනු ලà·à¶¶à·’ය à·„à·à¶š.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">ප්â€à¶»à¶­à·’ක්ෂේප කරන්න</translation>
<translation id="3939773374150895049">CVC වෙනුවට WebAuthn භà·à·€à·’ත කරන්නද?</translation>
<translation id="3946209740501886391">මෙම අඩවියේදී à·ƒà·à¶¸à·€à·’ටම විමසන්න</translation>
<translation id="3947595700203588284">අඩවි MIDI උපà·à¶‚ග වෙත සම්බන්ධ වීමට ඉල්ලිය à·„à·à¶šà·’ය</translation>
@@ -942,6 +974,7 @@
<translation id="3990250421422698716">අනුලම්බයේ සෙමින් දුවන්න</translation>
<translation id="3996311196211510766">මූලà·à¶»à¶¸à·Šà¶· ප්â€à¶»à¶­à·’පත්තිය එය වෙත සියලුම ඉල්ලීම්වලට යෙදීමට <ph name="ORIGIN" /> වෙබ් අඩවිය
ඉල්ල෠ඇති නමුත්, දà·à¶±à¶§ මෙම ප්â€à¶»à¶­à·’පත්තිය යෙදිය නොහà·à¶š.</translation>
+<translation id="4009243425692662128">ඔබ මුද්â€à¶»à¶«à¶º කරන පිටුවල අන්තර්ගතය විà·à·Šà¶½à·šà·‚ණය සඳහ෠Google ක්ලවුඩ් හ෠තෙවන පà·à¶»à·Šà·à·Šà·€ වෙත යවනු ලà·à¶¶à·š. උදà·à·„රණයක් à·€à·à¶ºà·™à¶±à·Š, සංවේදි දත්ත සඳහ෠එය ස්කෑන් කරනු ලà·à¶¶à·’ය à·„à·à¶šà·’ය.</translation>
<translation id="4010758435855888356">ගබඩ෠ප්â€à¶»à·€à·šà·à¶º ඉඩ දෙන්නද?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{{COUNT} පිටුවක් ඇති PDF ලේඛනය}one{පිටු {COUNT} ක් ඇති PDF ලේඛනය}other{පිටු {COUNT} ක් ඇති PDF ලේඛනය}}</translation>
<translation id="4023431997072828269">ආරක්ෂිත නොවන සම්බන්ධතà·à·€à¶šà·Š භà·à·€à·’ත කරමින් මෙම පà·à¶»à¶¸à¶º ඉදිරිපත් කර ඇති නිසà·, ඔබේ තොරතුරු අන් අයට පෙනෙනු ඇත.</translation>
@@ -1033,6 +1066,7 @@
<translation id="4250680216510889253">නà·à¶­</translation>
<translation id="4253168017788158739">සටහන</translation>
<translation id="425582637250725228">ඔබ සිදු කළ වෙනස්කම් සුරà·à¶šà·“ම නොවනු ඇත.</translation>
+<translation id="425869179292622354">අතථ්â€à¶º කà·à¶©à·Šà¶´à¶­à¶šà·’න් එය වඩà·à¶­à·Š සුරක්ෂිත කරන්නද?</translation>
<translation id="4258748452823770588">à·€à·à¶»à¶¯à·’ අත්සනකි</translation>
<translation id="4261046003697461417">ආරක්â€à·‚ිත ලේඛන අනුසටහන් කළ නොහà·à¶š</translation>
<translation id="4265872034478892965">ඔබේ පරිපà·à¶½à¶š විසින් ඉඩ දෙයි</translation>
@@ -1095,6 +1129,7 @@
<translation id="4434045419905280838">උත්පතන සහ හරව෠යà·à·€à·“ම්</translation>
<translation id="4435702339979719576">තà·à¶´à·à¶½à·Š පත)</translation>
<translation id="443673843213245140">ප්â€à¶»à·œà¶šà·Šà·ƒà·’යක භà·à·€à·’තය අබල කර ඇති නමුත් ප්â€à¶»à¶šà·à·à·’ත ප්â€à¶»à·œà¶šà·Šà·ƒà·’ වින්â€à¶ºà·à·ƒà¶šà¶»à¶«à¶ºà¶šà·Š නිà·à·Šà¶ à¶º කර ඇත.</translation>
+<translation id="4441832193888514600">ප්â€à¶»à¶­à·’පත්තිය ක්ලවුඩ් පරිà·à·“ලක ප්â€à¶»à¶­à·’පත්තියක් ලෙස පමණක් à·ƒà·à¶šà·ƒà·’ය à·„à·à¶šà·’ බà·à·€à·’න් නොසලක෠හරින ලදී.</translation>
<translation id="4450893287417543264">නà·à·€à¶­ නොපෙන්වන්න</translation>
<translation id="4451135742916150903">HID උපà·à¶‚ග වෙත සම්බන්ධ වීමට ඉල්ලිය à·„à·à¶šà·’ය</translation>
<translation id="4452328064229197696">ඔබ මේ දà·à¶±à·Š භà·à·€à·’ත෠කළ මුරපදය දත්ත කඩ කිරීමකින් සොය෠ගන්න෠ලදී. ඔබගේ ගිණුම් සුරක්ෂිත කිරීමට, Google මුරපද කළමනà·à¶šà¶»à·” ඔබගේ සුරකින ලද මුරපද පරීක්ෂ෠කිරීම නිර්දේ෠කරයි.</translation>
@@ -1150,6 +1185,7 @@
<translation id="4628948037717959914">ඡà·à¶ºà·à¶»à·–පය</translation>
<translation id="4631649115723685955">මුදල් ආපසු දීම සබà·à¶³à·’ කරන ලදි</translation>
<translation id="4636930964841734540">තතු</translation>
+<translation id="4638670630777875591">Chromium à·„à·’ අප්â€à¶»à·ƒà·’ද්ධ</translation>
<translation id="464342062220857295">විà·à·šà·‚à·à¶‚ග සොයන්න</translation>
<translation id="4644670975240021822">ප්â€à¶»à¶­à·’වර්තන පිළිවෙළ මුහුණු පහළට</translation>
<translation id="4646534391647090355">දà·à¶±à·Š මà·à·€ එතà·à¶±à¶§ ගෙන යන්න</translation>
@@ -1170,6 +1206,7 @@
<translation id="4708268264240856090">ඔබේ සබà·à¶³à·”මට බà·à¶°à· ඇති විය</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Windows ජà·à¶½ දà·à·‚හරණ ධà·à·€à¶±à¶º කරමින්<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426"><ph name="USERNAME" /> සඳහ෠මුරපදය</translation>
<translation id="4724144314178270921">ඔබගේ පසුරු පුවරුවේ පෙළ සහ රූප බà·à¶½à·“මට ඉල්ලිය à·„à·à¶šà·’ය</translation>
<translation id="4726672564094551039">ප්â€à¶»à¶­à·’පත්ති නà·à·€à·”ම් කරන්න</translation>
<translation id="4728558894243024398">වේදිකà·à·€</translation>
@@ -1191,6 +1228,7 @@
<translation id="4757993714154412917">ඔබ මේ දà·à¶±à·Š වංචනික අඩවියකට ඔබගේ මුරපදය ඇතුළු කළේය. ඔබගේ ගිණුම් සුරක්ෂිත කිරීමට, ඔබගේ සුරà·à¶šà·’ මුරපද පරීක්ෂ෠කිරීමට Chromium නිර්දේ෠කරයි.</translation>
<translation id="4758311279753947758">සම්බන්ධත෠තතු එක් කරන්න</translation>
<translation id="4761104368405085019">මයික්â€à¶»à·œà·™à·†à·à¶±à¶º භà·à·€à·’ත෠කරන්න</translation>
+<translation id="4761869838909035636">Chrome ආරක්ෂක පරීක්ෂà·à·€ ධà·à·€à¶±à¶º කරන්න</translation>
<translation id="4764776831041365478"><ph name="URL" /> à·„à·’ වෙබ් පිටුව තà·à·€à¶šà·à¶½à·’කව ක්â€à¶»à·’ය෠නොකරයි නà·à¶­à·„ොත් එය ස්ථිරවම වෙනත් වෙබ් ලිපිනයක් වෙත ගෙනගොස් ඇත.</translation>
<translation id="4766713847338118463">පහළට දෙවරක් ස්ටේපල්</translation>
<translation id="4771973620359291008">නොදන්න෠දà·à·‚යක් ඇති විය.</translation>
@@ -1211,12 +1249,6 @@
<translation id="4819347708020428563">පෙරනිමි දසුන තුළ අනුසටහන් සංස්කරණය කරන්නද?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />, ඉක්මනින් නව Google Sheet එකක් තà·à¶±à·“මට Tab ඔබ෠අනතුරුව Enter ඔබන්න</translation>
<translation id="4825507807291741242">à·à¶šà·Šà¶­à·’සම්පන්න</translation>
-<translation id="4827402517081186284">අප්â€à¶»à·ƒà·’ද්ධ ප්â€à¶»à¶šà·à¶»à¶º ඔබව සබà·à¶³à·’à·€ අදෘà·à·Šâ€à¶ºà¶¸à·à¶± බවට පත් නොකරයි:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />අඩවි ඔබ ඒවà·à¶§ පිවිසෙන විට දනියි<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />සේවà·à¶ºà·à¶¢à¶šà¶ºà¶±à·Šà¶§ හ෠පà·à·ƒà¶½à·Šà·€à¶½à¶§ බ්â€à¶»à·€à·”ස් කිරීමේ ක්â€à¶»à·’යà·à¶šà·à¶»à¶šà¶¸à·Š හඹ෠යà·à¶¸à¶§ à·„à·à¶šà·’ය<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />අන්තර්ජà·à¶½ සේව෠සපයන්නන් වෙබ් තදබදය නිරීක්ෂණය කළ à·„à·à¶šà·’ය<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">අනතුරු ඇඟවීම් ක්â€à¶»à·’යà·à¶­à·Šà¶¸à¶š කරන්න</translation>
<translation id="4838327282952368871">සිහිනමය</translation>
<translation id="4840250757394056958">ඔබගේ Chrome ඉතිහà·à·ƒà¶º බලන්න</translation>
@@ -1228,12 +1260,12 @@
<translation id="4854362297993841467">මෙම බෙද෠හà·à¶»à·“මේ ක්â€à¶»à¶¸à¶º ලබ෠ගත නොහà·à¶šà·’ය. වෙනත් ක්â€à¶»à¶¸à¶ºà¶šà·Š උත්සà·à·„ කරන්න.</translation>
<translation id="4854853140771946034">Google Keep හි නව සටහනක් ඉක්මනින් තනන්න</translation>
<translation id="485902285759009870">කේතය සත්â€à¶ºà·à¶´à¶±à¶º කරමින්...</translation>
+<translation id="4866506163384898554">ඔබගේ කර්සරය පෙන්වීමට |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| ඔබන්න</translation>
<translation id="4876188919622883022">සරල දසුන</translation>
<translation id="4876305945144899064">පරිà·à·“ලක නමක් නà·à¶­</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{කිසිවක් නà·à¶­}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}one{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831"><ph name="TEXT" /> සෙවීම</translation>
<translation id="4879491255372875719">ස්වයංක්â€à¶»à·’ය (පෙරනිමි)</translation>
-<translation id="4879725228911483934">ඔබේ තිරය මත කවුළු විවෘත කරන්න සහ තබන්න</translation>
<translation id="4880827082731008257">ඉතිහà·à·ƒà¶º සොයන්න</translation>
<translation id="4881695831933465202">විවෘත කරන්න</translation>
<translation id="4885256590493466218">ගෙවීමේදී <ph name="CARD_DETAIL" /> සමගින් ගෙවන්න</translation>
@@ -1242,6 +1274,7 @@
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">Ninth Roll</translation>
<translation id="4901778704868714008">සුරකින්න...</translation>
+<translation id="4905659621780993806">ඔබගේ පරිපà·à¶½à¶š ඔබගේ උපà·à¶‚ගය <ph name="DATE" /> <ph name="TIME" />ට ස්වයංක්â€à¶»à·’යව යළි ආරම්භ කරනු ඇත ඔබගේ උපà·à¶‚ගය යළි ආරම්භ කිරීමට පෙර කිනම් හ෠විවෘත අයිතම සුරකින්න.</translation>
<translation id="4913987521957242411">ඉහළ වමට අනින්න</translation>
<translation id="4918221908152712722"><ph name="APP_NAME" /> ස්ථà·à¶´à¶±à¶º කරන්න (බà·à¶œà·à¶±à·“මක් අවà·à·Šâ€à¶º නොවේ)</translation>
<translation id="4923459931733593730">ගෙවීම</translation>
@@ -1250,6 +1283,7 @@
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, සෙවීමට Tab ඔබ෠අනතුරුව Enter ඔබන්න</translation>
<translation id="4930153903256238152">විà·à·à¶½ ධà·à¶»à·’තà·à·€</translation>
+<translation id="4940163644868678279">Chrome තුළ අප්â€à¶»à·ƒà·’ද්ධ</translation>
<translation id="4943872375798546930">ප්â€à¶»à¶­à·’ඵල නà·à¶­</translation>
<translation id="4950898438188848926">පටිත්ත මà·à¶»à·” වීමේ බොත්තමෙන්, <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /> විවෘත පටිත්තට මà·à¶»à·” වීමට Enter ඔබන්න</translation>
<translation id="495170559598752135">ක්â€à¶»à·’යà·à¶¸à·à¶»à·Šà¶œ</translation>
@@ -1259,6 +1293,7 @@
<translation id="4968522289500246572">මෙම යෙදුම ජංගම සඳහ෠සà·à¶½à·ƒà·”ම් කර ඇති අතර ප්â€à¶»à¶­à·’ප්â€à¶»à¶¸à·à¶« නොවීමටද à·„à·à¶šà·’ය. මෙම යෙදුම ගà·à¶§à¶½à·” හ෠යළි ආරම්භ වීම අත්විඳිය à·„à·à¶šà·’ය.</translation>
<translation id="4969341057194253438">පටිගත කිරීම මකන්න</translation>
<translation id="4973922308112707173">ඉහළට දෙවරක් අනින්න</translation>
+<translation id="4976702386844183910">අවසන් වරට <ph name="DATE" /> පිවිසි</translation>
<translation id="4984088539114770594">මයික්â€à¶»à·†à·à¶±à¶º භà·à·€à·’ත කරන්නද?</translation>
<translation id="4984339528288761049">Prc5 (ලියුම් කවරය)</translation>
<translation id="4989163558385430922">සියල්ල බලන්න</translation>
@@ -1320,6 +1355,7 @@
<translation id="5138227688689900538">අඩුවෙන් පෙන්වන්න</translation>
<translation id="5145883236150621069">ප්â€à¶»à¶­à·’්පත්ති ප්â€à¶»à¶­à·’චà·à¶»à¶º තුළ දà·à·‚ කේතය ඉදිරිපත් කරයි</translation>
<translation id="5146995429444047494"><ph name="ORIGIN" /> සඳහ෠දà·à¶±à·”ම්දීම් අවහිරයි</translation>
+<translation id="514704532284964975"><ph name="URL" /> හට ඔබ ඔබගේ දුරකථනය සමඟ තට්ටු කරන NFC උපà·à¶‚ගවල තොරතුරු බà·à¶½à·“මට සහ වෙනස් කිරීමට අවà·à·Šâ€à¶ºà¶ºà·’</translation>
<translation id="5148809049217731050">මුහුණ ඉහළට</translation>
<translation id="515292512908731282">C4 (ලියුම් කවරය)</translation>
<translation id="5158275234811857234">කවරය</translation>
@@ -1344,6 +1380,7 @@
<translation id="5215116848420601511">Google Pay භà·à·€à·’තයෙන් ගෙවීම් ක්â€à¶»à¶¸ සහ ලිපින</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">Tray 13</translation>
+<translation id="5216942107514965959">අද අවසන් වරට පිවිසි</translation>
<translation id="5222812217790122047">ඊ-තà·à¶´à·‘ල අවà·à·Šâ€à¶ºà¶ºà·’</translation>
<translation id="5230733896359313003">නà·à·€à·Šà¶œà¶­ කිරීමේ ලිපිනය</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1364,7 +1401,6 @@
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">ලේඛන ගුණà·à¶‚ග</translation>
<translation id="528468243742722775">අවසන් කරන්න</translation>
-<translation id="5284909709419567258">ජà·à¶½ ලිපින.</translation>
<translation id="5285570108065881030">සුරà·à¶šà·’ මුරපද සියල්ල පෙන්වන්න</translation>
<translation id="5287240709317226393">කුකි පෙන්වන්න</translation>
<translation id="5287456746628258573">මෙම අඩවිය යල් පà·à¶± ගිය ආරක්ෂක වින්â€à¶ºà·à·ƒà¶ºà¶šà·Š භà·à·€à·’ත෠කරයි, එමඟින් ඔබේ තොරතුරු (උදà·à·„රණයක් ලෙස, මුරපද හ෠ණයපත් අංක) මෙම අඩවියට යවන විට හෙළි කළ à·„à·à¶šà·’ය.</translation>
@@ -1448,6 +1484,7 @@
<translation id="5556459405103347317">නà·à·€à¶­</translation>
<translation id="5560088892362098740">කල් ඉකුත් වීමේ දිනය</translation>
<translation id="55635442646131152">ලේඛන à·€à·à¶§à·’සන</translation>
+<translation id="5565613213060953222">අප්â€à¶»à¶šà¶§ ටà·à¶¶à¶º විවෘත කරන්න</translation>
<translation id="5565735124758917034">සක්â€à¶»à·’යයි</translation>
<translation id="5570825185877910964">ගිණුම ආරක්â€à·‚෠කරන්න</translation>
<translation id="5571083550517324815">මෙම ලිපිනයෙන් ලබ෠ගà·à¶±à·“මට නොහà·à¶šà·’ය. වෙනත් ලිපිනයක් තà·à¶»à¶±à·Šà¶±.</translation>
@@ -1530,6 +1567,7 @@
<translation id="5869522115854928033">සුරà·à¶šà·’ රහස්වචන</translation>
<translation id="5873013647450402046">ඔබගේ බà·à¶‚කුවට මේ ඔබ බව තහවුරු කර ගà·à¶±à·“මට අවà·à·Šâ€à¶ºà¶ºà·’.</translation>
<translation id="5887400589839399685">කà·à¶©à·Šà¶´à¶­ සුරà·à¶šà·’ණි</translation>
+<translation id="5887687176710214216">අවසන් වරට ඊයේ පිවිසි</translation>
<translation id="5895138241574237353">යළි අරඹන්න</translation>
<translation id="5895187275912066135">නිකුත් කළේ</translation>
<translation id="5901630391730855834">කහ</translation>
@@ -1543,6 +1581,7 @@
<translation id="5921639886840618607">කà·à¶©à·Šà¶´à¶­ Google ගිණුමට සුරකින්නද?</translation>
<translation id="5922853866070715753">මුළුමනින්ම පà·à·„à·š නිමයි</translation>
<translation id="5932224571077948991">වෙබ් අඩවිය ආක්â€à¶»à¶¸à¶«à·’ක හ෠නොමඟ යවන දà·à¶±à·Šà·€à·“ම් පෙන්වයි</translation>
+<translation id="5938153366081463283">අතථ්â€à¶º කà·à¶©à·Šà¶´à¶­ එක් කරන්න</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347"><ph name="SITE_NAME" /> විවෘත කරමින්…</translation>
<translation id="5951495562196540101">පà·à¶»à·’භà·à¶œà·’ක ගිණුම සමඟ ලියà·à¶´à¶¯à·’ංචි විය නොහà·à¶š (ඇසුරුම් කළ බලපත්â€à¶»à¶ºà¶šà·Š ලබà·à¶œà¶­ à·„à·à¶š).</translation>
@@ -1607,6 +1646,7 @@
<translation id="6120179357481664955">ඔබේ UPI à·„à·à¶³à·”නුම මතකද?</translation>
<translation id="6124432979022149706">Chrome ව්â€à¶ºà·€à·ƒà·à¶º සම්බන්ධක</translation>
<translation id="6127379762771434464">අයිතමය ඉවත් කරන ලදී</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Chrome à·„à·’ අප්â€à¶»à·ƒà·’ද්ධ ගà·à¶± තව දà·à¶± ගන්න<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">කිනම් හ෠කේබල පරීක්ෂ෠කර කිනම් හ෠රවුටර, මොඩම හ෠ඔබ භà·à·€à·’ත කරමින් සිටිය à·„à·à¶šà·’
වෙනත් ජà·à¶½ උපà·à¶‚ග යළි පණ ගන්වන්න.</translation>
<translation id="614940544461990577">උත්සà·à·„ කරන්න:</translation>
@@ -1619,7 +1659,6 @@
<translation id="6169916984152623906">දà·à¶±à·Š ඔබට පෞද්ගලිකව බ්â€à¶»à·€à·”ස් කළ à·„à·à¶šà·’ අතර, මෙම උපà·à¶‚ගය භà·à·€à·’ත෠කරන වෙනත් පුද්ගලයින් ඔබේ ක්â€à¶»à·’යà·à¶šà·à¶»à¶šà¶¸à·Š නොදකිනු ඇත. කෙසේ වෙතත්, බà·à¶œà·à¶±à·“ම් සහ පිටුසන් සුරà·à¶šà·™à¶±à·” ඇත.</translation>
<translation id="6177128806592000436">මෙම අඩවිය වෙත ඔබගේ සම්බන්ධතà·à·€à¶º සුරක්ෂිත නොවේ</translation>
<translation id="6180316780098470077">යළි උත්සà·à·„ කිරීමේ විරà·à¶¸à¶º</translation>
-<translation id="619448280891863779">ඔබගේ තිර මත කවුළු විවෘත කිරීමට සහ තà·à¶¶à·“මට අවà·à·Šâ€à¶º වූ විට අසන්න</translation>
<translation id="6196640612572343990">තෙවන-පà·à¶»à·Šà·à·Šà·€ කුකී අවහිර කරන්න</translation>
<translation id="6203231073485539293">ඔබගේ අන්තර්ජà·à¶½ සබà·à¶³à·”ම පරික්ෂ෠කරන්න</translation>
<translation id="6218753634732582820">Chromium වෙතින් ලිපිනය ඉවත් කරන්නද?</translation>
@@ -1642,7 +1681,7 @@
<translation id="6272383483618007430">Google යà·à·€à¶­à·Šà¶šà·à¶½à·“න</translation>
<translation id="6276112860590028508">ඔබේ කියවීම් ලà·à¶ºà·’ස්තුවෙන් පිටු මෙහි දිස් වනු ඇත</translation>
<translation id="627746635834430766">මීළඟ වතà·à·€à·š දී වේගවත්ව ගෙවීමට, ඔබේ Google ගිණුමට ඔබේ කà·à¶©à·Šà¶´à¶­ සහ බිල්පත් ලිපිනය සුරකින්න.</translation>
-<translation id="6279098320682980337">අතථ්â€à¶º කà·à¶©à·Šà¶´à¶­à·Š අංකය පුරව෠නà·à¶­à·’ද? පිටපත් කිරීමට කà·à¶©à·Šà¶´à¶­à·Š විස්තර ක්ලික් කරන්න</translation>
+<translation id="6279183038361895380">ඔබේ කර්සරය පෙන්වීමට |<ph name="ACCELERATOR" />| ඔබන්න</translation>
<translation id="6280223929691119688">මෙම ලිපිනයට බෙද෠හà·à¶»à·“මට නොහà·à¶šà·’ය. වෙනත් ලිපිනයක් තà·à¶»à¶±à·Šà¶±.</translation>
<translation id="6282194474023008486">තà·à¶´à·à¶½à·Š කේතය</translation>
<translation id="6285507000506177184">Chrome තුළ බà·à¶œà·à¶±à·“ම් කළමනà·à¶šà¶»à¶«à¶º කරන්න බොත්තම, ඔබ Chrome තුළ බà·à¶œà¶­à·Š ගොනු කළමනà·à¶šà¶»à¶«à¶º කිරීමට Enter ඔබන්න</translation>
@@ -1650,6 +1689,7 @@
<translation id="6290238015253830360">ඔබේ යà·à¶¢à·’ත ලිපි මෙහි දිස්වනු ඇත</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{ඔබගේ උපà·à¶‚ගය දà·à¶±à·Š යළි ආරම්භ වනු ඇත}=1{ඔබගේ උපà·à¶‚ගය තත්පර 1කින් යළි ආරම්භ වනු ඇත}one{ඔබගේ උපà·à¶‚ගය තත්පර #කින් යළි ආරම්භ වනු ඇත}other{ඔබගේ උපà·à¶‚ගය තත්පර #කින් යළි ආරම්භ වනු ඇත}}</translation>
<translation id="6302269476990306341">Chrome à·„à·’ Google සහà·à¶ºà¶š නà·à·€à¶­à·™à¶ºà·’</translation>
<translation id="6305205051461490394"><ph name="URL" /> වෙත ළඟ෠විය නොහà·à¶šà·’ය.</translation>
<translation id="6312113039770857350">වෙබ් පිටුව ලබ෠ගත නොහà·à¶šà·’ය</translation>
@@ -1723,6 +1763,7 @@
<translation id="6529602333819889595">මà·à¶šà·“ම &amp;යළි කරන්න</translation>
<translation id="6545864417968258051">බ්ලූටූත් ස්කෑන් කිරීම</translation>
<translation id="6547208576736763147">වමට ද්වි අනින්න</translation>
+<translation id="6554732001434021288">දින <ph name="NUM_DAYS" />කට පෙර අවසන් වරට පිවිසි</translation>
<translation id="6556866813142980365">නà·à·€à¶­ කරන්න</translation>
<translation id="6569060085658103619">ඔබ දිගු පිටුවක් බලමින් සිටී</translation>
<translation id="6573200754375280815">දකුණට දෙවරක් අනින්න</translation>
@@ -1783,7 +1824,6 @@
<translation id="6757797048963528358">ඔබගේ උපà·à¶‚ගය නින්දට ගියේය.</translation>
<translation id="6767985426384634228">ලිපිනය යà·à·€à¶­à·Šà¶šà·à¶½à·“න කරන්නද?</translation>
<translation id="6768213884286397650">Hagaki (තà·à¶´à·à¶½à·Š පත)</translation>
-<translation id="6774185088257932239">අප්â€à¶»à·ƒà·’ද්ධ ගà·à¶± <ph name="BEGIN_LINK" />තව දà·à¶± ගන්න<ph name="END_LINK" /></translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">ජම්බූල</translation>
<translation id="6786747875388722282">දිගු</translation>
@@ -1867,7 +1907,6 @@
<translation id="706295145388601875">Chrome à·ƒà·à¶šà·ƒà·“ම් තුළ ලිපින එක් කරන්න සහ කළමනà·à¶šà¶»à¶«à¶º කරන්න</translation>
<translation id="7064851114919012435">සම්බන්ධත෠තතු</translation>
<translation id="7068733155164172741">ඉලක්කම්-<ph name="OTP_LENGTH" /> කේතය ඇතුළු කරන්න</translation>
-<translation id="7070090581017165256">මෙම අඩවිය ගà·à¶±</translation>
<translation id="70705239631109039">ඔබේ සම්බන්ධතà·à·€ සම්පූර්ණයෙන් සුරක්â€à·‚ිත නොවේ</translation>
<translation id="7075452647191940183">ඉල්ලීම විà·à·à¶½ à·€à·à¶©à·’යි</translation>
<translation id="7079718277001814089">මෙම අඩවියෙහි අනිෂ්ට මෘදුකà·à¶‚ග අඩංගුය</translation>
@@ -1884,6 +1923,12 @@
<translation id="7111012039238467737">(වලංගුයි)</translation>
<translation id="7118618213916969306">පසුරු පුවරු URL එක සොයන්න, <ph name="SHORT_URL" /></translation>
<translation id="7119414471315195487">අනෙකුත් පටිති à·„à· à·€à·à¶©à·ƒà¶§à·„න් වසන්න</translation>
+<translation id="7129355289156517987">ඔබ Chromium අප්â€à¶»à·ƒà·’ද්ධ ටà·à¶¶ සියල්ල à·€à·à·ƒà·– විට, එම ටà·à¶¶à·€à¶½ ඔබගේ ක්â€à¶»à·’යà·à¶šà·à¶»à¶šà¶¸à·Š මෙම උපà·à¶‚ගයෙන් හිස් වේ:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />බ්â€à¶»à·€à·”ස් කිරීමේ ක්â€à¶»à·’යà·à¶šà·à¶»à¶šà¶¸<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />සෙවීම් ඉතිහà·à·ƒà¶º<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />පà·à¶»à¶¸à·€à¶½ ඇතුළත් කළ තොරතුරු<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">මෙම ලිපිනයට නà·à·€à·Šà¶œà¶­ කළ නොහà·à¶šà·’ය. වෙනත් ලිපිනයක් තà·à¶»à¶±à·Šà¶±.</translation>
<translation id="7132939140423847331">ඔබගේ පරිපà·à¶½à¶š මෙම දත්ත පිටපත් කිරීම තහනම් කර ඇත.</translation>
<translation id="7135130955892390533">තත්ත්â€à·€à¶º පෙන්වන්න</translation>
@@ -1906,6 +1951,7 @@
<translation id="7192203810768312527"><ph name="SIZE" /> හිස් කරයි. ඔබේ ඊළඟ පිවිසීමේදී සමහර අඩවි වඩà·à¶­à·Š සෙමින් පූරණය විය à·„à·à¶šà·’ය.</translation>
<translation id="719464814642662924">වීසà·</translation>
<translation id="7201591969684833065">ඔබේ පරිපà·à¶½à¶šà¶ºà·à¶§ බà·à¶½à·’ය à·„à·à¶šà·Šà¶šà·š:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, පුද්ගලිකව බ්â€à¶»à·€à·”ස් කිරීමට නව අප්â€à¶»à¶šà¶§ ටà·à¶¶à¶ºà¶šà·Š විවෘත කිරීමට, Tab ඔබ෠අනතුරුව Enter ඔබන්න</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> ආරක්ෂක සම්මත අනුගමනය නොකරයි.</translation>
<translation id="7210993021468939304">බඳුන තුළ ලිනක්ස් ක්â€à¶»à·’යà·à·€, සහ බඳුන තුළ ලිනක්ස් යෙදුම් ස්ථà·à¶´à¶± කර ධà·à·€à¶± කළ à·„à·à¶š</translation>
@@ -1937,6 +1983,7 @@
<translation id="7304562222803846232">Google ගිණුම් පෞද්ගලිකත්ව à·ƒà·à¶šà·ƒà·“ම් කළමනà·à¶šà¶»à¶«à¶º කරන්න</translation>
<translation id="7305756307268530424">වඩ෠මන්දගà·à¶¸à·“à·€ අරඹන්න</translation>
<translation id="7308436126008021607">පසුබිම සමමුහුර්ත කිරීම</translation>
+<translation id="7310392214323165548">උපà·à¶‚ගය ඉත෠ඉක්මනින් යළි ආරම්භ වනු ඇත</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">සම්බන්ධත෠උපකà·à¶»à¶º</translation>
<translation id="7323804146520582233">"<ph name="SECTION" />" කොටස සඟවන්න</translation>
@@ -1944,6 +1991,7 @@
<translation id="7334320624316649418">යළි ඇනවුම් කිරීම &amp;යළි කරන්න</translation>
<translation id="7335157162773372339">ඔබගේ කà·à¶¸à¶»à·à·€ භà·à·€à·’ත කිරීමට ඉල්ලිය à·„à·à¶šà·’ය</translation>
<translation id="7337248890521463931">තවත් පේළි පෙන්වන්න</translation>
+<translation id="7337418456231055214">අතථ්â€à¶º කà·à¶©à·Šà¶´à¶­à·Š අංකය පුරව෠නà·à¶­à·’ද? පිටපත් කිරීමට කà·à¶©à·Šà¶´à¶­à·Š විස්තර ක්ලික් කරන්න. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">ඔබේ වේදිකà·à·€ මත නොතිබේ.</translation>
<translation id="733923710415886693">සහතික පà·à¶»à¶¯à·˜à·à·Šâ€à¶ºà¶­à·à·€ හරහ෠සේවà·à¶¯à·à¶ºà¶šà¶ºà·š සහතිකය අනà·à·€à¶»à¶«à¶º නොකෙරේ.</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1966,6 +2014,7 @@
<translation id="7378627244592794276">නà·à·„à·</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">අදà·à·… නොවේ</translation>
+<translation id="7388594495505979117">{0,plural, =1{ඔබගේ උපà·à¶‚ගය මිනිත්තු 1කින් යළි ආරම්භ වනු ඇත}one{ඔබගේ උපà·à¶‚ගය මිනිත්තු #කින් යළි ආරම්භ වනු ඇත}other{ඔබගේ උපà·à¶‚ගය මිනිත්තු #කින් යළි ආරම්භ වනු ඇත}}</translation>
<translation id="7390545607259442187">කà·à¶©à·Šà¶´à¶­ තහවුරු කිරීම</translation>
<translation id="7392089738299859607">ලිපිනය යà·à·€à¶­à·Šà¶šà·à¶½à·“න කරන්න</translation>
<translation id="7399802613464275309">ආරක්ෂක පරීක්ෂà·à·€</translation>
@@ -2002,6 +2051,12 @@
<translation id="7485870689360869515">දත්ත කිසිවක් හමු නොවිනි</translation>
<translation id="7495528107193238112">මෙම අන්තර්ගතය අවහිර කර ඇත. ගà·à¶§à¶½à·”à·€ නිවà·à¶»à¶¯à·’ කිරීමට අඩවි හිමිකරු අමතන්න</translation>
<translation id="7497998058912824456">ලේඛනය තනන්න බොත්තම, ඉක්මනින් අලුත් Google Doc එකක් තà·à¶±à·“මට Enter ඔබන්න</translation>
+<translation id="7506488012654002225">Chromium පහත තොරතුරු <ph name="BEGIN_EMPHASIS" />නොසුරකිනු ඇත<ph name="END_EMPHASIS" />:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ඔබගේ බ්â€à¶»à·€à·”ස් කිරීමේ ඉතිහà·à·ƒà¶º
+ <ph name="LIST_ITEM" />කුකි සහ අඩවි දත්ත
+ <ph name="LIST_ITEM" />පà·à¶»à¶¸ තුළ ඇතුළත් කළ තොරතුරු
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">ආපසු ලබ෠දුන් ප්â€à¶»à¶­à·’පත්ති උපà·à¶‚ග id හිස් හ෠වත්මන් උපà·à¶‚ග id හ෠නොගà·à·…පෙයි</translation>
<translation id="7508870219247277067">අලිගà·à¶§ පේර කොළ</translation>
<translation id="7511955381719512146">ඔබ භà·à·€à·’ත෠කරන Wi-Fi මගින් ඔබ <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> වෙත පිවිසීමට අවà·à·Šâ€à¶º විය à·„à·à¶š.</translation>
@@ -2115,7 +2170,6 @@
<translation id="7813600968533626083">Chrome වෙතින් වන යà·à¶¢à¶±à·à·€à¶½à·’න් ඉවත් කරන්නද?</translation>
<translation id="781440967107097262">පසුරු පුවරුව බෙද෠ගන්නද?</translation>
<translation id="7815407501681723534">'<ph name="SEARCH_STRING" />' සඳහ෠<ph name="SEARCH_RESULTS" /> <ph name="NUMBER_OF_RESULTS" /> හමු විය</translation>
-<translation id="782125616001965242">මෙම අඩවිය ගà·à¶± තොරතුරු පෙන්වන්න</translation>
<translation id="782886543891417279">ඔබ භà·à·€à·’ත෠කරන Wi-Fi (<ph name="WIFI_NAME" />) මගින් ඔබ එහි පුරනය වීමේ පිටුවට පිවිසීමට අවà·à·Šâ€à¶º විය à·„à·à¶š.</translation>
<translation id="7836231406687464395">Postfix (ලියුම් කවරය)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{කිසිවක් නà·à¶­}=1{1 යෙදුමක් (<ph name="EXAMPLE_APP_1" />)}=2{යෙදුම් 2ක් (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}one{යෙදුම් #ක් (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}other{යෙදුම් #ක් (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}}</translation>
@@ -2132,7 +2186,6 @@
<translation id="7888575728750733395">මුද්â€à¶»à¶« විදහීමේ යෙදීම</translation>
<translation id="7894280532028510793">අක්ෂර වින්â€à¶ºà·à·ƒà¶º නිවà·à¶»à¶¯à·’ නම්, <ph name="BEGIN_LINK" />ජà·à¶½ දà·à·‚ නිර්ණ ධà·à·€à¶±à¶º කිරීම උත්සà·à·„ කරන්න<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (ලියුම් කවරය)</translation>
-<translation id="7931318309563332511">නොදනී</translation>
<translation id="793209273132572360">ලිපිනය යà·à·€à¶­à·Šà¶šà·à¶½à·“න කරන්නද?</translation>
<translation id="7932579305932748336">කබà·à¶º</translation>
<translation id="79338296614623784">වලංගු දුරකථන අංකයක් ඇතුළු කරන්න</translation>
@@ -2157,13 +2210,14 @@
<translation id="7976214039405368314">ඉල්ලීම් ඉත෠වà·à¶©à·’ය</translation>
<translation id="7977538094055660992">ප්â€à¶»à¶­à·’දà·à¶± උපà·à¶‚ගය</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">මෙය සමඟ සබà·à¶³à·’ කරන ලදි</translation>
<translation id="798134797138789862">අතථ්â€à¶º යථà·à¶»à·Šà¶® උපà·à¶‚ග සහ දත්ත භà·à·€à·’ත කිරීමට ඉල්ලිය à·„à·à¶šà·’ය</translation>
<translation id="7984945080620862648">වෙබ් අඩවිය Chrome හට à·ƒà·à¶šà·ƒà·’ය නොහà·à¶šà·’ ව්â€à¶ºà·à¶šà·–ල අක්තපත්â€à¶» එව෠ඇති නිස෠ඔබට මේ දà·à¶±à·Š <ph name="SITE" /> පිවිසිය නොහà·à¶š. ජà·à¶½ දà·à·‚ සහ ප්â€à¶»à·„à·à¶» à·ƒà·à¶¸à·à¶±à·Šâ€à¶º යෙන් තà·à·€à¶šà·à¶½à·’කය, එනිස෠මෙම පිටුව සමහරවිට පසුව à·€à·à¶© කරනු ඇත.</translation>
-<translation id="79859296434321399">à·€à·à¶©à·’ දියුණු කළ යතà·à¶»à·Šà¶® අන්තර්ගතය බà·à¶½à·“මට, ARCore ස්ථà·à¶´à¶±à¶º කරන්න</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">බඳින්න</translation>
<translation id="7992044431894087211"><ph name="APPLICATION_TITLE" /> සමග තිරය බෙද෠ගà·à¶±à·“ම නà·à·€à¶­ පටන් ගන්න෠ලදි</translation>
<translation id="7995512525968007366">නියම නොකළ</translation>
+<translation id="7998269595945679889">අප්â€à¶»à¶šà¶§ ටà·à¶¶à¶ºà¶šà·Š විවෘත කිරීමේ බොත්තම, පුද්ගලිකව බ්â€à¶»à·€à·”ස් කිරීමට නව Chrome අප්â€à¶»à¶šà¶§ ටà·à¶¶à¶º විවෘත කිරීමට Enter ඔබන්න</translation>
<translation id="800218591365569300">මතකය නිදහස් කිරීමට වෙනත් පටිති à·„à· à·€à·à¶©à·ƒà¶§à·„න් à·€à·à·ƒà·“මට උත්සà·à·„ කරන්න.</translation>
<translation id="8004582292198964060">බ්â€à¶»à·€à·”සරය</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{මෙම කà·à¶©à·Šà¶´à¶­ සහ මෙහි බිල්පත් ලිපිනය සුරකිනු ලà·à¶¶à·š. ඔබට <ph name="USER_EMAIL" /> වෙත පුරනය වූ විට එය භà·à·€à·’ත කිරීමට à·„à·à¶šà·’ වෙයි.}one{මෙම කà·à¶©à·Šà¶´à¶­à·Š සහ මේවà·à¶ºà·š බිල්පත් ලිපින සුරකිනු ලà·à¶¶à·š. ඔබට <ph name="USER_EMAIL" /> වෙත පුරනය වූ විට ඒව෠භà·à·€à·’ත කිරීමට à·„à·à¶šà·’ වෙයි.}other{මෙම කà·à¶©à·Šà¶´à¶­à·Š සහ මේවà·à¶ºà·š බිල්පත් ලිපින සුරකිනු ලà·à¶¶à·š. ඔබට <ph name="USER_EMAIL" /> වෙත පුරනය වූ විට ඒව෠භà·à·€à·’ත කිරීමට à·„à·à¶šà·’ වෙයි.}}</translation>
@@ -2223,6 +2277,7 @@
<translation id="8202370299023114387">ගà·à¶§à·”ම</translation>
<translation id="8206978196348664717">Prc4 (ලියුම් කවරය)</translation>
<translation id="8211406090763984747">සම්බන්ධතà·à·€à¶º ආරක්ෂිත වේ</translation>
+<translation id="8217240300496046857">අඩවිවලට වෙබය හරහ෠ඔබව හඹ෠යන කුකි භà·à·€à·’ත කළ නොහà·à¶šà·’ය. සමහර අඩවිවල විà·à·šà·‚à·à¶‚ග බිඳිය à·„à·à¶šà·’ය.</translation>
<translation id="8218327578424803826">පà·à·€à¶»à·– ස්ථà·à¶±à¶º:</translation>
<translation id="8220146938470311105">C7/C6 (ලියුම් කවරය)</translation>
<translation id="8225771182978767009">මෙම පරිගණකය පිහිටුවීම කළ පුද්ගලය෠මෙම අඩවිය අවහිර කිරීමට තà·à¶»à· ඇත.</translation>
@@ -2263,14 +2318,9 @@
<translation id="830498451218851433">භà·à¶œà¶ºà¶§ නවන්න</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">ස්ථà·à¶´à¶±à¶º කළ යෙදුම් සහ ඒව෠කොතරම් නිතර භà·à·€à·’ත කරන්නේද යන්න</translation>
+<translation id="8317207217658302555">ARCore යà·à·€à¶­à·Šà¶šà·à¶½à·“න කරන්නද?</translation>
<translation id="831997045666694187">සවස</translation>
<translation id="8321476692217554900">දà·à¶±à·”ම්දීම්</translation>
-<translation id="8328484624016508118">සියලු අප්â€à¶»à·ƒà·’ද්ධ ටà·à¶¶ à·€à·à·ƒà·“මෙන් පසු, Chrome පහත ඒව෠හිස් කරයි:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />මෙම උපà·à¶‚ගයෙන් ඔබගේ බ්â€à¶»à·€à·”ස් කිරීමේ ක්â€à¶»à·’යà·à¶šà·à¶»à¶šà¶¸<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />මෙම උපà·à¶‚ගයෙන් ඔබගේ සෙවීම් ඉතිහà·à·ƒà¶º<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />පà·à¶»à¶¸ තුළ ඇතුළත් කළ තොරතුරු<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489"><ph name="HOST_NAME" /> වෙත ප්â€à¶»à·€à·šà·à¶º ප්â€à¶»à¶­à·’ක්ෂේප කරන ලදී</translation>
<translation id="833262891116910667">උද්දීපන කරන්න</translation>
<translation id="8339163506404995330"><ph name="LANGUAGE" /> හි පිටු පරිවර්තනය නොවනු ඇත</translation>
@@ -2322,6 +2372,7 @@
<translation id="8507227106804027148">විධà·à¶± පේළිය</translation>
<translation id="8508648098325802031">සෙවීමේ නිරූපකය</translation>
<translation id="8511402995811232419">කුකි කළමනà·à¶šà¶»à¶«à¶º කරන්න</translation>
+<translation id="8519753333133776369">ඔබගේ පරිපà·à¶½à¶š විසින් ඉඩ දෙන HID උපà·à¶‚ගය</translation>
<translation id="8522552481199248698">Chrome ඔබට ඔබේ Google ගිණුම ආරක්â€à·‚෠කිරීමටත් ඔබේ මුරපදය වෙනස් කිරීමටත් ඔබට උදවු කළ à·„à·à¶š.</translation>
<translation id="8530813470445476232">ඔබගේ බ්â€à¶»à·€à·”ස් කිරීමේ ඉතිහà·à·ƒà¶º, කුකි, à·„à·à¶¹à·’ලි සහ තවත් දේ Chrome à·ƒà·à¶šà·ƒà·“ම් තුළ හිස් කරන්න</translation>
<translation id="8533619373899488139">ඔබේ පද්ධති පරිපà·à¶½à¶š විසින් පනවන ලද අවහිර කළ URL සහ වෙනත් ප්â€à¶»à¶­à·’පත්ති බà·à¶½à·“මට &lt;strong&gt;chrome://policy&lt;/strong&gt; වෙත පිවිසෙන්න.</translation>
@@ -2333,7 +2384,6 @@
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{අවසරය යළි සකසන්න}one{අවසර යළි සකසන්න}other{අවසර යළි සකසන්න}}</translation>
<translation id="8555010941760982128">ගෙව෠පිටවීමේදී මෙම කේතය භà·à·€à·’ත කරන්න</translation>
<translation id="8557066899867184262">CVC ඔබේ කà·à¶©à·Šà¶´à¶­ පිටුපස පිහිට෠ඇත.</translation>
-<translation id="8558485628462305855">à·€à·à¶©à·’ දියුණු කළ යතà·à¶»à·Šà¶® අන්තර්ගතය බà·à¶½à·“මට, ARCore යà·à·€à¶­à·Šà¶šà·à¶½à·“න කරන්න</translation>
<translation id="8559762987265718583">ඔබගේ උපà·à¶‚ගයේ දිනය සහ වේලà·à·€ (<ph name="DATE_AND_TIME" />) නිවà·à¶»à¶¯à·’ නොවන නිස෠<ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> වෙත පෞද්ගලික සම්බන්ධයක් සෑදිය නොහà·à¶šà·’යි.</translation>
<translation id="8564182942834072828">වෙන් වූ ලේඛන/එකතු නොකළ පිටපත්</translation>
<translation id="8564985650692024650">Chromium ඔබේ <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> මුරපදය ඔබ වෙනත් අඩවිවල නà·à·€à¶­ භà·à·€à·’ත කර තිබේ නම් යළි à·ƒà·à¶šà·ƒà·“මට නිර්දේ෠කරයි.</translation>
@@ -2352,6 +2402,7 @@
<translation id="865032292777205197">චලන සංවේදක</translation>
<translation id="8663226718884576429">ඇණවුමේ à·ƒà·à¶»à·à¶‚à·à¶º, <ph name="TOTAL_LABEL" />, තව විස්තර</translation>
<translation id="8666678546361132282">ඉංග්â€à¶»à·“සි</translation>
+<translation id="8669306706049782872">කවුළු විවෘත කිරීමට සහ තà·à¶¶à·“මට ඔබගේ තිර පිළිබඳ තොරතුරු භà·à·€à·’ත කරන්න</translation>
<translation id="867224526087042813">අත්සන</translation>
<translation id="8676424191133491403">ප්â€à¶»à¶¸à·à¶¯ නà·à¶­</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, පිළිතුර, <ph name="ANSWER" /></translation>
@@ -2378,6 +2429,7 @@
<translation id="8731544501227493793">මුරපද කළමනà·à¶šà¶»à¶«à¶º කරන්න බොත්තම, ඔබගේ මුරපද Chrome à·ƒà·à¶šà·ƒà·“ම් තුළ බà·à¶½à·“මට සහ කළමනà·à¶šà¶»à¶«à¶º කිරීමට Enter ඔබන්න</translation>
<translation id="8734529307927223492">ඔබගේ <ph name="DEVICE_TYPE" /> <ph name="MANAGER" /> විසින් කළමනà·à¶šà¶»à¶«à¶º කෙරේ</translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, පුද්ගලිකව බ්â€à¶»à·€à·”ස් කිරීමට නව අප්â€à¶»à·ƒà·’ද්ධ කවුළුවක් විවෘත කිරීමට, Tab ඔබ෠අනතුරුව Enter ඔබන්න</translation>
+<translation id="8737685506611670901"><ph name="REPLACED_HANDLER_TITLE" /> වෙනුවට <ph name="PROTOCOL" /> සබà·à¶³à·’ය විවෘත කරන්න</translation>
<translation id="8738058698779197622">ආරක්ෂිත සම්බන්ධතà·à·€à¶šà·Š ස්ථà·à¶´à¶±à¶º කිරීමට, ඔබගේ ඔරලà·à·ƒà·”à·€ නිවà·à¶»à¶¯à·’à·€ සකස් කරගà·à¶±à·“මට අවà·à·Šâ€à¶ºà¶º. මෙයට හේතුව වෙබ් අඩවි ඔවුන්ව හඳුනà·à¶œà·à¶±à·“මට භà·à·€à·’ත෠කරන සහතිකපත්â€à¶» වලංගු වන්නේ යම්කිසි කà·à¶½à¶ºà¶šà·Š සඳහ෠පමණි. ඔබගේ උපà·à¶‚ගයේ ඔරලà·à·ƒà·”à·€ à·€à·à¶»à¶¯à·’ විට, Chromium වලට මෙම සහතික සත්â€à¶ºà·à¶´à¶±à¶º කිරීම කළ නොහà·à¶š.</translation>
<translation id="8740359287975076522"><ph name="HOST_NAME" /> à·„à·’ &lt;abbr id="dnsDefinition"&gt;DNS ලිපිනය&lt;/abbr&gt; සොය෠ගත නොහà·à¶šà·’ විය. ගà·à¶§à¶½à·”à·€ නිර්ණය කරමින්.</translation>
<translation id="8742371904523228557"><ph name="ONE_TIME_CODE" /> යනු <ph name="ORIGIN" /> සඳහ෠ඔබේ කේතය වෙයි</translation>
@@ -2405,6 +2457,7 @@
<translation id="883848425547221593">වෙනත් පිටු සලකුණු</translation>
<translation id="884264119367021077">නà·à·€à·Šà¶œà¶­ ලිපිනය</translation>
<translation id="884923133447025588">අවලංගු කිරීමේ යà·à¶±à·Šà¶­à·Šâ€à¶»à¶«à¶ºà¶šà·Š නà·à¶­.</translation>
+<translation id="8849262850971482943">අමතර ආරක්ෂà·à·€ සඳහ෠ඔබගේ අතථ්â€à¶º කà·à¶©à·Šà¶´à¶­ භà·à·€à·’ත කරන්න</translation>
<translation id="885730110891505394">Google සමග බෙද෠ගà·à¶±à·“ම</translation>
<translation id="8858065207712248076">Chrome ඔබේ <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> මුරපදය ඔබ වෙනත් අඩවිවල නà·à·€à¶­ භà·à·€à·’ත කර තිබේ නම් යළි à·ƒà·à¶šà·ƒà·“මට නිර්දේ෠කරයි.</translation>
<translation id="885906927438988819">අක්ෂර වින්â€à¶ºà·à·ƒà¶º නිවà·à¶»à¶¯à·’ නම්, <ph name="BEGIN_LINK" />Windows ජà·à¶½ දà·à·‚ නිර්ණ ධà·à·€à¶±à¶º කිරීම උත්සà·à·„ කරන්න<ph name="END_LINK" />.</translation>
@@ -2454,6 +2507,7 @@
<translation id="9004367719664099443">VR à·ƒà·à·ƒà·’ය ප්â€à¶»à¶œà¶­à·’යේ පවතියි</translation>
<translation id="9005998258318286617">PDF ගොනුව පූරණය කිරීමට අසමත් විය.</translation>
<translation id="9008201768610948239">මඟහරින්න</translation>
+<translation id="901834265349196618">ඊතà·à¶´à·‘ල</translation>
<translation id="9020200922353704812">කà·à¶©à·Šà¶´à¶­à·š බිල්පත් ලිපිනය අවà·à·Šâ€à¶ºà¶ºà·’</translation>
<translation id="9020542370529661692">මෙම පිටුව <ph name="TARGET_LANGUAGE" /> ට පරිවර්තනය වී ඇත</translation>
<translation id="9020742383383852663">A8</translation>
@@ -2502,6 +2556,7 @@
<translation id="9150045010208374699">ඔබගේ කà·à¶¸à¶»à·à·€ භà·à·€à·’ත෠කරන්න</translation>
<translation id="9150685862434908345">ඔබේ පරිපà·à¶½à¶šà¶§ දුරස්ථව ඔබේ බ්â€à¶»à·€à·”සර à·ƒà·à¶šà·ƒà·“ම වෙනස් කළ à·„à·à¶šà·’ය. මෙම උපà·à¶‚ගයේ ක්â€à¶»à·’යà·à¶šà·à¶»à¶šà¶¸à·Š Chrome වලින් පිටත ද කළමනà·à¶šà¶»à¶«à¶º කිරීමට ඇතà·à¶¸à·Š විට à·„à·à¶šà·’ය. <ph name="BEGIN_LINK" />තව දà·à¶± ගන්න<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">යà·à·€à¶­à·Šà¶šà·à¶½à·“න කෙරිණි</translation>
+<translation id="9155211586651734179">à·à·Šâ€à¶»à·€à·Šâ€à¶º පර්යන්ත අමුණ෠ඇත</translation>
<translation id="9157595877708044936">පිහිටුවමින්...</translation>
<translation id="9158625974267017556">C6 (ලියුම් කවරය)</translation>
<translation id="9164029392738894042">නිරවද්â€à¶ºà¶­à· පරීක්ෂà·à·€</translation>
diff --git a/chromium/components/strings/components_strings_sk.xtb b/chromium/components/strings/components_strings_sk.xtb
index cb9eed460f6..27f0200b31f 100644
--- a/chromium/components/strings/components_strings_sk.xtb
+++ b/chromium/components/strings/components_strings_sk.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">Zobraziť podrobnosti</translation>
<translation id="1030706264415084469"><ph name="URL" /> chce natrvalo ukladať veľké množstvo dát vo vašom zariadení</translation>
<translation id="1032854598605920125">OtoÄiÅ¥ v smere hodinových ruÄiÄiek</translation>
+<translation id="1033329911862281889">Režim inkognito neznamená, že vás na internete nie je vidieť:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Weby a nimi využívané služby vedia o vašich návštevách.<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Zamestnávatelia alebo školy môžu sledovať aktivitu prehliadania.<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Poskytovatelia internetových služieb môžu sledovať návštevnosť webov.<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">Vypnúť</translation>
<translation id="1036982837258183574">Režim celej obrazovky ukonÄíte stlaÄením klávesa |<ph name="ACCELERATOR" />|</translation>
<translation id="1038106730571050514">Zobraziť návrhy</translation>
<translation id="1038842779957582377">neznámy názov</translation>
<translation id="1041998700806130099">Správa hárku úlohy</translation>
<translation id="1048785276086539861">KeÄ upravíte poznámky, tento dokument sa vráti na zobrazenie jednej stránky</translation>
-<translation id="1049743911850919806">Inkognito</translation>
<translation id="1050038467049342496">Zavrite ostatné aplikácie</translation>
<translation id="1055184225775184556">&amp;Vrátiť späť pridanie</translation>
<translation id="1056898198331236512">Upozornenie</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">Vyrovnávacia pamäť pravidla je v poriadku</translation>
<translation id="1130564665089811311">TlaÄidlo PreložiÅ¥ stránku. Po stlaÄení klávesa Enter PrekladaÄ Google túto stránku preloží.</translation>
<translation id="1131264053432022307">Skopírovaný obrázok</translation>
+<translation id="1142846828089312304">Blokovať súbory cookie tretích strán v režime inkognito</translation>
<translation id="1150979032973867961">Server nedokáže overiÅ¥, Äi ide o doménu <ph name="DOMAIN" />, operaÄný systém vášho poÄítaÄa nedôveruje jej bezpeÄnostnému certifikátu. Môže to byÅ¥ spôsobené nesprávnou konfiguráciou alebo tým, že vaÅ¡e pripojenie zachytil útoÄník.</translation>
<translation id="1151972924205500581">Vyžaduje sa heslo</translation>
<translation id="1156303062776767266">Prezeráte si miestny alebo zdieľaný súbor</translation>
@@ -64,7 +70,6 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="1178581264944972037">Pozastaviť</translation>
<translation id="1181037720776840403">Odstrániť</translation>
<translation id="1186201132766001848">Skontrolovať heslá</translation>
-<translation id="1195210374336998651">Prejsť do nastavení aplikácie</translation>
<translation id="1195558154361252544">Upozornenia sú automaticky blokované pre všetky weby okrem tých, ktoré povolíte</translation>
<translation id="1197088940767939838">Oranžová</translation>
<translation id="1201402288615127009">ÄŽalej</translation>
@@ -111,7 +116,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="1307966114820526988">Funkcie s ukonÄenou podporou</translation>
<translation id="1308113895091915999">Ponuka je k dispozícii</translation>
<translation id="1312803275555673949">Aký dôkaz to podporuje?</translation>
-<translation id="131405271941274527"><ph name="URL" /> chce odosielaÅ¥ a prijímaÅ¥ informácie, keÄ klepnete na svoj telefón v zariadení NFC</translation>
+<translation id="1314311879718644478">Zobrazenie obsahu rozšírenej reality</translation>
<translation id="1314509827145471431">Zviazať vpravo</translation>
<translation id="1318023360584041678">Uložené v skupine kariet</translation>
<translation id="1319245136674974084">V prípade tejto aplikácie sa nabudúce nepýtať</translation>
@@ -161,6 +166,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="142858679511221695">Používateľ cloudu</translation>
<translation id="1428729058023778569">Toto upozornenie sa vám zobrazuje, pretože tento web nepodporuje protokol HTTPS. <ph name="BEGIN_LEARN_MORE_LINK" />Ďalšie informácie<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">TlaÄiÅ¥</translation>
+<translation id="1432187715652018471">stránka chce nainštalovať obslužný nástroj služby.</translation>
<translation id="1432581352905426595">SpravovaÅ¥ vyhľadávaÄe</translation>
<translation id="1436185428532214179">Môže žiadaÅ¥ o povolenie upravovaÅ¥ súbory a prieÄinky v zariadení</translation>
<translation id="1442386063175183758">Obojstranná fazóna s otváraním doprava</translation>
@@ -181,6 +187,12 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="1483493594462132177">Odoslať</translation>
<translation id="1484290072879560759">Zvoliť dodaciu adresu</translation>
<translation id="1492194039220927094">Odosielanie pravidiel:</translation>
+<translation id="149293076951187737">Po zavretí všetkých kariet inkognito v Chrome sa vaša aktivita v nich vymaže z tohto zariadenia:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Aktivita prehliadania<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />História vyhľadávania<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Informácie zadané vo formulároch<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">Späť na kartu</translation>
<translation id="1501859676467574491">ZobraziÅ¥ karty z vášho úÄtu Google</translation>
<translation id="1507202001669085618">&lt;p&gt;Táto chyba sa zobrazí, keÄ používate portál Wi-Fi, ktorý podmieňuje prístup k internetu prihlásením.&lt;/p&gt;
@@ -208,6 +220,8 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="1559572115229829303">&lt;p&gt;Súkromné pripojenie k doméne <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> sa nedá nadviazaÅ¥, pretože dátum a Äas (<ph name="DATE_AND_TIME" />) vášho zariadenia sú nesprávne.&lt;/p&gt;
&lt;p&gt;Dátum a Äas upravte v aplikácii &lt;strong&gt;Nastavenia&lt;/strong&gt; v sekcii &lt;strong&gt;VÅ¡eobecné&lt;/strong&gt;.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">Správca reštartuje vaše zariadenie <ph name="DATE" /> o <ph name="TIME" /></translation>
+<translation id="156703335097561114">Informácie o sieťach, napríklad adresy, konfigurácia rozhrania a kvalita pripojenia</translation>
<translation id="1567040042588613346">Toto pravidlo funguje podľa oÄakávania, ale niekde inde je nastavená rovnaká hodnota, ktorú toto pravidlo nahradilo.</translation>
<translation id="1569487616857761740">Zadajte dátum vypršania platnosti</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="1583429793053364125">Pri zobrazovaní webovej stránky sa nieÄo pokazilo.</translation>
<translation id="1586541204584340881">Ktoré rozšírenia ste nainštalovali</translation>
<translation id="1588438908519853928">Normálny</translation>
+<translation id="1589050138437146318">Chcete nainštalovať ARCore?</translation>
<translation id="1592005682883173041">Prístup k miestnym údajom</translation>
<translation id="1594030484168838125">Zvoliť</translation>
<translation id="160851722280695521">Hrať hru Dino Run v Chrome</translation>
@@ -279,6 +294,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="1763864636252898013">Server nedokáže overiÅ¥, Äi ide o doménu <ph name="DOMAIN" />, operaÄný systém vášho zariadenia nedôveruje jej bezpeÄnostnému certifikátu. Môže to byÅ¥ spôsobené nesprávnou konfiguráciou alebo tým, že vaÅ¡e pripojenie zachytil útoÄník.</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Skúste spustiť nástroj Diagnostika siete systému Windows<ph name="END_LINK" />.</translation>
<translation id="1772163372082567643">Server <ph name="ORIGIN" />, na ktorý prechádzate, nastavil hlaviÄku, ktorá požaduje, aby sa na vÅ¡etky požiadavky odoslané na server vzÅ¥ahovalo pravidlo pre zdroj. HlaviÄka má vÅ¡ak nesprávny tvar a prehliadaÄ preto nemôže vaÅ¡ej požiadavke pre web <ph name="SITE" /> vyhovieÅ¥. Pomocou pravidiel pre zdroj môžu operátori webu nakonfigurovaÅ¥ zabezpeÄenie a ÄalÅ¡ie vlastnosti webu.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />ÄŽalÅ¡ie informácie o režime inkognito v prehliadaÄi Chromium<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">Tu sa zobrazia otvorené karty</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -406,6 +422,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="22081806969704220">Priehradka Ä. 3</translation>
<translation id="2212735316055980242">Pravidlo sa nenašlo</translation>
<translation id="2213606439339815911">NaÄítavanie záznamov...</translation>
+<translation id="2213612003795704869">Stránka je vytlaÄená</translation>
<translation id="2215727959747642672">Úprava súborov</translation>
<translation id="2218879909401188352">ÚtoÄníci na webe <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> by mohli nainÅ¡talovaÅ¥ nebezpeÄné aplikácie, ktoré poÅ¡kodia vaÅ¡e zariadenia, pridaÅ¥ skryté poplatky do vaÅ¡ej faktúry za mobilné služby alebo ukradnúť vaÅ¡e osobné informácie. <ph name="BEGIN_LEARN_MORE_LINK" />ÄŽalÅ¡ie informácie<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">Bez internetu</translation>
@@ -415,6 +432,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="2248949050832152960">Použiť WebAuthn</translation>
<translation id="2250931979407627383">Zošiť hrebeňovou väzbou vľavo</translation>
<translation id="225207911366869382">Táto hodnota už pre toto pravidlo nie je podporovaná.</translation>
+<translation id="2256115617011615191">Reštartovať</translation>
<translation id="2258928405015593961">Zadajte dátum vypršania platnosti v budúcnosti a skúste to znova</translation>
<translation id="225943865679747347">Kód chyby: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">Chyba protokolu HTTP</translation>
@@ -442,6 +460,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="2337852623177822836">Nastavenie ovládané správcom</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> žiada o spárovanie</translation>
<translation id="2346319942568447007">Skopírovaný obrázok</translation>
+<translation id="2350796302381711542">Chcete povoliť obslužnému nástroju <ph name="HANDLER_HOSTNAME" /> otvárať všetky odkazy s protokolom <ph name="PROTOCOL" /> (namiesto obslužného nástroja <ph name="REPLACED_HANDLER_TITLE" />)?</translation>
<translation id="2354001756790975382">Ostatné</translation>
<translation id="2354430244986887761">Funkcia BezpeÄné prehliadanie Google nedávno <ph name="BEGIN_LINK" />naÅ¡la Å¡kodlivé aplikácie<ph name="END_LINK" /> na webe <ph name="SITE" />.</translation>
<translation id="2355395290879513365">ÚtoÄníci môžu vidieÅ¥ obrázky, ktoré si prehliadate na tomto webe, a môžu vás napadnúť tým, že ich podvodným spôsobom upravia.</translation>
@@ -467,6 +486,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="2413528052993050574">Server nedokáže overiÅ¥, Äi ide o doménu <ph name="DOMAIN" />, jej bezpeÄnostný certifikát bol zrejme zruÅ¡ený. Môže to byÅ¥ spôsobené nesprávnou konfiguráciou alebo tým, že vaÅ¡e pripojenie zachytil útoÄník.</translation>
<translation id="2414886740292270097">Tmavý režim</translation>
<translation id="2430968933669123598">SpravovaÅ¥ úÄet Google, stlaÄením klávesa Enter môžete spravovaÅ¥ informácie, ochranu súkromia a zabezpeÄenie v úÄte Google</translation>
+<translation id="2436186046335138073">Chcete povoliť obslužnému programu <ph name="HANDLER_HOSTNAME" /> otvárať všetky odkazy protokolu <ph name="PROTOCOL" />?</translation>
<translation id="2438874542388153331">Å tyri dierky vpravo</translation>
<translation id="2450021089947420533">Journeys</translation>
<translation id="2463739503403862330">Vyplniť</translation>
@@ -474,6 +494,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="2465655957518002998">ZvoliÅ¥ spôsob doruÄenia</translation>
<translation id="2465688316154986572">Zošiť spinkou</translation>
<translation id="2465914000209955735">Spravovať súbory stiahnuté v Chrome</translation>
+<translation id="2466004615675155314">Zobraziť informácie z webu</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Spustiť nástroj Diagnostika siete<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">Poradie 1 až N</translation>
<translation id="2470767536994572628">KeÄ upravíte poznámky, tento dokument sa vráti na zobrazenie jednej stránky a do pôvodného otoÄenia</translation>
@@ -494,6 +515,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="2523886232349826891">Uložené iba na tomto zariadení</translation>
<translation id="2524461107774643265">Pridanie Äalších informácií</translation>
<translation id="2529899080962247600">Toto pole by nemalo maÅ¥ viac ako tento poÄet vstupov: <ph name="MAX_ITEMS_LIMIT" />. VÅ¡etky ÄalÅ¡ie vstupy budú ignorované.</translation>
+<translation id="2535585790302968248">Otvoriť novú kartu inkognito a prehliadať v súkromí</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{a 1 ÄalÅ¡ia}few{a # ÄalÅ¡ie}many{and # more}other{a # Äalších}}</translation>
<translation id="2536110899380797252">Pridať adresu</translation>
<translation id="2539524384386349900">Rozpoznávať</translation>
@@ -519,7 +541,14 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="2597378329261239068">Tento dokument je chránený heslom. Zadajte heslo.</translation>
<translation id="2609632851001447353">Variácie</translation>
<translation id="2610561535971892504">Skopírovať kliknutím</translation>
+<translation id="2617988307566202237">Chrome <ph name="BEGIN_EMPHASIS" />neuloží<ph name="END_EMPHASIS" /> nasledujúce informácie:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />vašu históriu prehliadania,
+ <ph name="LIST_ITEM" />súbory cookie a dáta webov,
+ <ph name="LIST_ITEM" />informácie zadané vo formulároch.
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (obálka)</translation>
+<translation id="2623663032199728144">Môže žiadať o povolenie používať informácie o vašich obrazovkách</translation>
<translation id="2625385379895617796">Vaše hodiny idú dopredu</translation>
<translation id="262745152991669301">Môže žiadať o povolenie pripájať sa k zariadeniam s rozhraním USB</translation>
<translation id="2629325967560697240">Ak chcete získaÅ¥ najvyšší stupeň zabezpeÄenia Chromu, <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />zapnite rozšírenú ochranu<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -553,6 +582,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="2709516037105925701">Automatické dopĺňanie</translation>
<translation id="2713444072780614174">Biela</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />, postupným stlaÄením klávesov Tab a Enter môžete v nastaveniach Chromu spravovaÅ¥ platby a informácie o kreditnej karte</translation>
+<translation id="271663710482723385">StlaÄením klávesov |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| ukonÄíte režim celej obrazovky</translation>
<translation id="2721148159707890343">Žiadosť bola úspešná</translation>
<translation id="2723669454293168317">SpustiÅ¥ kontrolu bezpeÄnosti v nastaveniach Chromu</translation>
<translation id="2726001110728089263">BoÄný zásobník</translation>
@@ -583,6 +613,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="2850739647070081192">Invite (obálka)</translation>
<translation id="2856444702002559011">ÚtoÄníci sa môžu pokúsiÅ¥ ukradnúť vaÅ¡e informácie z webu <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (napríklad heslá, správy alebo kreditné karty). <ph name="BEGIN_LEARN_MORE_LINK" />ÄŽalÅ¡ie informácie<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">Tento web zobrazuje obťažujúce alebo zavádzajúce reklamy.</translation>
+<translation id="286512204874376891">Virtuálnou kartou sa zamaskuje vaÅ¡a skutoÄná karta, Äo vás lepÅ¡ie ochráni pred potenciálnymi podvodmi. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">Milé</translation>
<translation id="2876489322757410363">Ak zaplatíte pomocou externej aplikácie, opustíte režim inkognito. Chcete pokraÄovaÅ¥?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />, postupným stlaÄením klávesov Tab a Enter spravujte BezpeÄné prehliadanie a ÄalÅ¡ie položky v nastaveniach Chromu</translation>
@@ -607,6 +638,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="2930577230479659665">Orezať po každej kópii</translation>
<translation id="2932085390869194046">Navrhnúť heslo…</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019">Otvárať odkazy protokolu <ph name="PROTOCOL" /></translation>
<translation id="2941952326391522266">Server nedokáže overiÅ¥, Äi ide o doménu <ph name="DOMAIN" />, jej bezpeÄnostný certifikát pochádza z domény <ph name="DOMAIN2" />. Môže to byÅ¥ spôsobené nesprávnou konfiguráciou alebo tým, že vaÅ¡e pripojenie zachytil útoÄník.</translation>
<translation id="2943895734390379394">ÄŒas nahrania:</translation>
<translation id="2948083400971632585">Môžete zakázať ktorékoľvek servery proxy nakonfigurované na pripojenie na stránke nastavení.</translation>
@@ -639,6 +671,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="3037605927509011580">Aj, chyba!</translation>
<translation id="3041612393474885105">Informácie o certifikáte</translation>
<translation id="3044034790304486808">PokraÄovaÅ¥ v prieskume</translation>
+<translation id="305162504811187366">História Vzdialenej plochy Chromu vrátane Äasových peÄiatok a identifikátorov relácií hostiteľov a klientov</translation>
<translation id="3060227939791841287">C9 (obálka)</translation>
<translation id="3061707000357573562">Služba opráv</translation>
<translation id="306573536155379004">Hra bola spustená.</translation>
@@ -676,6 +709,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="3197136577151645743">Môže žiadať o povolenie zistiť, kedy aktívne používate toto zariadenie</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />, postupným stlaÄením klávesov Tab a Enter môžete v nastaveniach Chromu spravovaÅ¥, aké údaje sa synchronizujú</translation>
<translation id="320323717674993345">Zrušiť platbu</translation>
+<translation id="3203366800380907218">Z webu</translation>
<translation id="3207960819495026254">Pridané medzi záložky</translation>
<translation id="3209034400446768650">Stránka môže úÄtovaÅ¥ peniaze</translation>
<translation id="3212581601480735796">Vaša aktivita v zariadení <ph name="HOSTNAME" /> je sledovaná</translation>
@@ -692,10 +726,12 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="3234666976984236645">Vždy na tomto webe zisťovať dôležitý obsah</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />, postupným stlaÄením klávesov Tab a Enter si prispôsobte vzhľad prehliadaÄa</translation>
<translation id="3240791268468473923">Hárok s nezodpovedajúcim poverením pre prihlasovací údaj zabezpeÄenej platby je otvorený</translation>
+<translation id="324180406144491771">Odkazy na hostiteľa <ph name="HOST_NAME" /> sú blokované</translation>
<translation id="3249845759089040423">Štýlové</translation>
<translation id="3252266817569339921">Francúzština</translation>
<translation id="3257954757204451555">Kto stojí za touto informáciou?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />, postupným stlaÄením klávesov Tab a Enter vytvoríte rýchlym spôsobom novú udalosÅ¥ v Kalendári Google</translation>
+<translation id="3261488570342242926">Ďalšie informácie o virtuálnych kartách</translation>
<translation id="3264837738038045344">TlaÄidlo na správu nastavení Chromu, stlaÄením klávesa Enter prejdete do nastavení Chromu</translation>
<translation id="3266793032086590337">Hodnota (konflikt)</translation>
<translation id="3268451620468152448">Otvorené karty</translation>
@@ -709,6 +745,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="3288238092761586174"><ph name="URL" /> môže vykonaÅ¥ ÄalÅ¡ie kroky na overenie vaÅ¡ej platby</translation>
<translation id="3293642807462928945">Ďalšie informácie o pravidle <ph name="POLICY_NAME" /></translation>
<translation id="3295444047715739395">Čítanie a správa hesiel v nastaveniach Chromu</translation>
+<translation id="3303795387212510132">Chcete povoliť aplikácii otvárať odkazy <ph name="PROTOCOL_SCHEME" />?</translation>
<translation id="3303855915957856445">NiÄ sa nenaÅ¡lo</translation>
<translation id="3304073249511302126">vyhľadávanie zariadení s rozhraním bluetooth</translation>
<translation id="3308006649705061278">OrganizaÄná jednotka (OU)</translation>
@@ -722,12 +759,6 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="3345782426586609320">OÄi</translation>
<translation id="3355823806454867987">Zmeniť nastavenia proxy...</translation>
<translation id="3360103848165129075">Hárok obslužného nástroja platieb</translation>
-<translation id="3361596688432910856">Chrome <ph name="BEGIN_EMPHASIS" />nebude ukladať<ph name="END_EMPHASIS" />:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />vašu históriu prehliadania
- <ph name="LIST_ITEM" />súbory cookie a dáta webov
- <ph name="LIST_ITEM" />údaje zadané do formulárov
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">Toto pravidlo bolo automaticky skopírované z pravidla <ph name="OLD_POLICY" />, ktorého podpora bola ukonÄená. Toto pravidlo používajte namiesto neho.</translation>
<translation id="3364869320075768271"><ph name="URL" /> chce používať vaše zariadenie a údaje virtuálnej reality</translation>
<translation id="3366477098757335611">Zobraziť karty</translation>
@@ -810,7 +841,6 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="3587738293690942763">Stred</translation>
<translation id="3592413004129370115">Italian (obálka)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{Skupinu môžete kedykoľvek resetovať. Pripojenie k novej skupine trvá približne deň.}=1{Skupinu môžete kedykoľvek resetovať. Pripojenie k novej skupine trvá približne deň.}few{Skupinu môžete kedykoľvek resetovať. Pripojenie k novej skupine trvá približne {NUM_DAYS} dni.}many{Skupinu môžete kedykoľvek resetovať. Pripojenie k novej skupine trvá približne {NUM_DAYS} dňa.}other{Skupinu môžete kedykoľvek resetovať. Pripojenie k novej skupine trvá približne {NUM_DAYS} dní.}}</translation>
-<translation id="3596012367874587041">Nastavenia aplikácie</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">Aplikácia bola zablokovaná vaším správcom</translation>
<translation id="3608932978122581043">Orientácia zásobníka</translation>
@@ -852,6 +882,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="370972442370243704">Zapnúť Journeys</translation>
<translation id="3711895659073496551">Režim spánku</translation>
<translation id="3712624925041724820">VyÄerpané licencie</translation>
+<translation id="3714633008798122362">webový kalendár</translation>
<translation id="3714780639079136834">Zapnúť mobilné dáta alebo Wi‑Fi</translation>
<translation id="3715597595485130451">Pripojenie k sieti Wi‑Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Skontrolovať proxy server, bránu firewall a konfiguráciu DNS<ph name="END_LINK" /></translation>
@@ -913,6 +944,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="3906954721959377182">Tablet</translation>
<translation id="3909477809443608991"><ph name="URL" /> chce prehrať chránený obsah. Google overí totožnosť vášho zariadenia a tento web k nej môže získať prístup.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">Odmietnuť</translation>
<translation id="3939773374150895049">Chcete namiesto overovacieho kódu karty použiť WebAuthn?</translation>
<translation id="3946209740501886391">Vždy sa opýtať na tomto webe</translation>
<translation id="3947595700203588284">Môže žiadať o povolenie pripájať sa k zariadeniam MIDI</translation>
@@ -933,6 +965,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="3987940399970879459">Menej ako 1 MB</translation>
<translation id="3990250421422698716">Odsadenie zarovnania okrajov</translation>
<translation id="3996311196211510766">Web <ph name="ORIGIN" /> požiadal, aby sa na všetky jeho požiadavky vzťahovalo pravidlo pre zdroj, ale toto pravidlo sa momentálne nedá uplatniť.</translation>
+<translation id="4009243425692662128">Obsah stránok, ktoré vytlaÄíte, sa odosiela na analýzu do služby Google Cloud alebo tretím stranám. Môže sa v ňom napríklad kontrolovaÅ¥ prítomnosÅ¥ citlivých údajov.</translation>
<translation id="4010758435855888356">Chcete povoliť prístup k úložisku?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{Dokument PDF s {COUNT} stranou}few{Dokument PDF s {COUNT} stranami}many{Dokument PDF s {COUNT} strany}other{Dokument PDF s {COUNT} stranami}}</translation>
<translation id="4023431997072828269">Tento formulár je odosielaný cez pripojenie, ktoré nie je zabezpeÄené, takže ostatní budú vidieÅ¥ vaÅ¡e informácie.</translation>
@@ -1023,6 +1056,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="4250680216510889253">Nie</translation>
<translation id="4253168017788158739">Poznámka</translation>
<translation id="425582637250725228">Zmeny, ktoré ste vykonali, sa nemusia uložiť.</translation>
+<translation id="425869179292622354">Chcete zlepÅ¡iÅ¥ zabezpeÄenie pomocou virtuálnej karty?</translation>
<translation id="4258748452823770588">Chybný podpis</translation>
<translation id="4261046003697461417">V chránených dokumentoch nie je anotácia možná</translation>
<translation id="4265872034478892965">Povolené správcom</translation>
@@ -1085,6 +1119,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="4434045419905280838">Vyskakovacie okná a presmerovania</translation>
<translation id="4435702339979719576">pohľadnica)</translation>
<translation id="443673843213245140">Použitie servera proxy je zakázané, ale je urÄená explicitná konfigurácia servera proxy.</translation>
+<translation id="4441832193888514600">Ignorované, pretože pravidlá sa dajú nastaviť iba pravidlami cloudu pre používateľov.</translation>
<translation id="4450893287417543264">Nabudúce nezobrazovať</translation>
<translation id="4451135742916150903">Môže žiadať o povolenie pripájať sa k zariadeniam HID</translation>
<translation id="4452328064229197696">Heslo, ktoré ste práve použili, bolo nájdené v zozname hesiel odhalených pri poruÅ¡ení ochrany údajov. Ak chcete svoje úÄty zabezpeÄiÅ¥, správca hesiel od Googlu odporúÄa skontrolovaÅ¥ uložené heslá.</translation>
@@ -1140,6 +1175,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="4628948037717959914">Fotografia</translation>
<translation id="4631649115723685955">Funkcia Cashback je prepojená</translation>
<translation id="4636930964841734540">Informácie</translation>
+<translation id="4638670630777875591">Režim inkognito v prehliadaÄi Chromium</translation>
<translation id="464342062220857295">Funkcie vyhľadávania</translation>
<translation id="4644670975240021822">V opaÄnom poradí lícom nadol</translation>
<translation id="4646534391647090355">Prejsť do daného umiestnenia</translation>
@@ -1160,6 +1196,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="4708268264240856090">Pripojenie bolo prerušené</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Spustiť nástroj Diagnostika siete systému Windows<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426">Heslo používateľa <ph name="USERNAME" /></translation>
<translation id="4724144314178270921">Môže žiadať o povolenie zobrazovať text a obrázky zo schránky</translation>
<translation id="4726672564094551039">Znova naÄítaÅ¥ pravidlá</translation>
<translation id="4728558894243024398">Platforma</translation>
@@ -1181,6 +1218,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="4757993714154412917">Práve ste zadali svoje heslo na podvodnom webe. Chromium odporúÄa skontrolovaÅ¥ uložené heslá, aby ste zabezpeÄili svoje úÄty.</translation>
<translation id="4758311279753947758">Pridať kontaktné údaje</translation>
<translation id="4761104368405085019">Používať váš mikrofón</translation>
+<translation id="4761869838909035636">SpustiÅ¥ kontrolu bezpeÄnosti Chromu</translation>
<translation id="4764776831041365478">Stránka <ph name="URL" /> je možno doÄasne nedostupná, možno bola natrvalo presunutá na novú webovú adresu.</translation>
<translation id="4766713847338118463">Dve spinky dole</translation>
<translation id="4771973620359291008">Vyskytla sa neznáma chyba.</translation>
@@ -1201,12 +1239,6 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="4819347708020428563">Chcete upraviť poznámky v predvolenom zobrazení?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />, postupným stlaÄením klávesov Tab a Enter vytvoríte rýchlym spôsobom novú tabuľku Google</translation>
<translation id="4825507807291741242">Pôsobivé</translation>
-<translation id="4827402517081186284">Režim inkognito neznamená vašu neviditeľnosť na internete:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />weby vedia o vašej návšteve;<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />zamestnávateľ Äi Å¡kola môže sledovaÅ¥ vaÅ¡u aktivitu prehliadania;<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />poskytovateľ internetu môže monitorovať webovú premávku.<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">Zapnúť upozornenia</translation>
<translation id="4838327282952368871">Rozprávkové</translation>
<translation id="4840250757394056958">Zobraziť históriu Chromu</translation>
@@ -1218,12 +1250,12 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="4854362297993841467">Tento spôsob doruÄenia nie je k dispozícii. Skúste inú adresu.</translation>
<translation id="4854853140771946034">Rýchlo vytvoriť novú poznámku v službe Google Keep</translation>
<translation id="485902285759009870">Overuje sa kód...</translation>
+<translation id="4866506163384898554">StlaÄením klávesov |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| zobrazíte kurzor</translation>
<translation id="4876188919622883022">Zjednodušené zobrazenie</translation>
<translation id="4876305945144899064">Žiadne používateľské meno</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{Žiadna}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}few{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}many{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831">Vyhľadávanie <ph name="TEXT" /></translation>
<translation id="4879491255372875719">Automatické (predvolené)</translation>
-<translation id="4879725228911483934">otvárať a umiestňovať okná na vaše obrazovky</translation>
<translation id="4880827082731008257">Hľadať v histórii</translation>
<translation id="4881695831933465202">Otvoriť</translation>
<translation id="4885256590493466218">Zaplaťte za nákup kartou <ph name="CARD_DETAIL" /></translation>
@@ -1232,6 +1264,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">Deviaty kotúÄ</translation>
<translation id="4901778704868714008">Uložiť...</translation>
+<translation id="4905659621780993806">Správca reštartuje vaše zariadenie automaticky <ph name="DATE" /> o <ph name="TIME" />. Uložte si predtým všetky otvorené položky.</translation>
<translation id="4913987521957242411">Prederaviť vľavo hore</translation>
<translation id="4918221908152712722">Nainštalujte si <ph name="APP_NAME" /> (bez nutnosti stiahnutia)</translation>
<translation id="4923459931733593730">Platba</translation>
@@ -1240,6 +1273,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, stlaÄením klávesov Tab a potom Enter spustite vyhľadávanie</translation>
<translation id="4930153903256238152">Veľká kapacita</translation>
+<translation id="4940163644868678279">Režim inkognito v Chrome</translation>
<translation id="4943872375798546930">Žiadne výsledky</translation>
<translation id="4950898438188848926">TlaÄidlo na prepnutie karty, stlaÄením klávesa Enter prepnete na otvorenú kartu, <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="495170559598752135">Akcie</translation>
@@ -1249,6 +1283,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="4968522289500246572">Táto aplikácia je urÄená pre mobilné zariadenia a jej veľkosÅ¥ sa nemusí náležite zmeniÅ¥. Môžu sa v nej vyskytnúť problémy alebo sa môže reÅ¡tartovaÅ¥.</translation>
<translation id="4969341057194253438">Odstrániť nahrávku</translation>
<translation id="4973922308112707173">Dve dierky hore</translation>
+<translation id="4976702386844183910">Naposledy navštívené <ph name="DATE" /></translation>
<translation id="4984088539114770594">Chcete používať mikrofón?</translation>
<translation id="4984339528288761049">Prc5 (obálka)</translation>
<translation id="4989163558385430922">Zobraziť všetko</translation>
@@ -1310,6 +1345,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="5138227688689900538">Zobraziť menej</translation>
<translation id="5145883236150621069">V odpovedi na pravidlo sa nachádza kód chyby</translation>
<translation id="5146995429444047494">Upozornenia webu <ph name="ORIGIN" /> sú blokované</translation>
+<translation id="514704532284964975"><ph name="URL" /> chce zobrazovať a meniť informácie v zariadeniach, ku ktorým priložíte svoj telefón</translation>
<translation id="5148809049217731050">Lícom nahor</translation>
<translation id="515292512908731282">C4 (obálka)</translation>
<translation id="5158275234811857234">Titulná strana</translation>
@@ -1334,6 +1370,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="5215116848420601511">Spôsoby platby a adresy pomocou Google Pay</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">Zásobník Ä. 13</translation>
+<translation id="5216942107514965959">Naposledy navštívený dnes</translation>
<translation id="5222812217790122047">E-mailová adresa je povinný údaj</translation>
<translation id="5230733896359313003">Dodacia adresa</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1354,7 +1391,6 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">Vlastnosti dokumentu</translation>
<translation id="528468243742722775">Koniec</translation>
-<translation id="5284909709419567258">Sieťové adresy</translation>
<translation id="5285570108065881030">Zobraziť všetky uložené heslá</translation>
<translation id="5287240709317226393">Zobraziť súbory cookie</translation>
<translation id="5287456746628258573">Tento web používa zastaranú konfiguráciu zabezpeÄenia, ktorá môže odhaliÅ¥ vaÅ¡e informácie (napríklad heslá alebo Äísla kreditných kariet), keÄ ich naň odoÅ¡lete.</translation>
@@ -1438,6 +1474,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="5556459405103347317">Znova naÄítaÅ¥</translation>
<translation id="5560088892362098740">Dátum vypršania platnosti</translation>
<translation id="55635442646131152">Osnova dokumentu</translation>
+<translation id="5565613213060953222">Otvoriť kartu inkognito</translation>
<translation id="5565735124758917034">Aktívne</translation>
<translation id="5570825185877910964">OchrániÅ¥ úÄet</translation>
<translation id="5571083550517324815">Vyzdvihnutie na tejto adrese nie je možné. Vyberte inú adresu.</translation>
@@ -1520,6 +1557,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="5869522115854928033">Uložené heslá</translation>
<translation id="5873013647450402046">Vaša banka chce overiť, že ste to vy.</translation>
<translation id="5887400589839399685">Karta bola uložená</translation>
+<translation id="5887687176710214216">Naposledy navÅ¡tívený vÄera</translation>
<translation id="5895138241574237353">Reštartovať</translation>
<translation id="5895187275912066135">Vydané dňa</translation>
<translation id="5901630391730855834">Žltá</translation>
@@ -1533,6 +1571,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="5921639886840618607">Chcete uložiÅ¥ kartu do úÄtu Google?</translation>
<translation id="5922853866070715753">Takmer dokonÄené</translation>
<translation id="5932224571077948991">Web zobrazuje obťažujúce alebo zavádzajúce reklamy</translation>
+<translation id="5938153366081463283">Pridajte si virtuálnu kartu</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347">Otvára sa web <ph name="SITE_NAME" />…</translation>
<translation id="5951495562196540101">Nemôžete sa zaregistrovaÅ¥ spotrebiteľským úÄtom (k dispozícii je licencia v balíÄku).</translation>
@@ -1597,6 +1636,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="6120179357481664955">Chcete uložiť svoj identifikátor UPI?</translation>
<translation id="6124432979022149706">Konektory Chrome Enterprise</translation>
<translation id="6127379762771434464">Položka bola odstránená</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Ďalšie informácie o režime inkognito v Chrome<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">Skontrolujte vÅ¡etky káble a reÅ¡tartujte vÅ¡etky používané smerovaÄe, modemy alebo iné sieÅ¥ové zariadenia.</translation>
<translation id="614940544461990577">Vyskúšajte:</translation>
<translation id="6150036310511284407">Tri dierky vľavo</translation>
@@ -1608,7 +1648,6 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="6169916984152623906">Teraz môžete prehliadať internet v súkromí a ostatní používatelia tohto zariadenia vašu aktivitu neuvidia. Stiahnuté súbory a záložky však budú uložené.</translation>
<translation id="6177128806592000436">Spojenie s týmto webom nie je zabezpeÄené</translation>
<translation id="6180316780098470077">Interval opakovania pokusov</translation>
-<translation id="619448280891863779">Môže žiadať o povolenie otvárať a umiestňovať okná na vaše obrazovky</translation>
<translation id="6196640612572343990">Blokovať súbory cookie tretích strán</translation>
<translation id="6203231073485539293">Skontrolujte internetové pripojenie</translation>
<translation id="6218753634732582820">Chcete adresu odstrániÅ¥ z prehliadaÄa Chromium?</translation>
@@ -1631,7 +1670,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="6272383483618007430">Aktualizácie Google</translation>
<translation id="6276112860590028508">Tu nájdete stránky z Äitateľského zoznamu</translation>
<translation id="627746635834430766">Ak chcete nabudúce zaplatiÅ¥ rýchlejÅ¡ie, uložte si kartu a fakturaÄnú adresu do úÄtu Google.</translation>
-<translation id="6279098320682980337">Nebolo vyplnené Äíslo virtuálnej karty? Skopírujte podrobnosti karty tak, že na ne kliknete.</translation>
+<translation id="6279183038361895380">StlaÄením klávesa |<ph name="ACCELERATOR" />| zobrazíte kurzor</translation>
<translation id="6280223929691119688">DoruÄenie na túto adresu nie je možné. Vyberte inú adresu.</translation>
<translation id="6282194474023008486">PoÅ¡tové smerovacie Äíslo</translation>
<translation id="6285507000506177184">TlaÄidlo na správu stiahnutých súborov v Chrome, stlaÄením klávesa Enter spravujte súbory stiahnuté v Chrome</translation>
@@ -1639,6 +1678,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="6290238015253830360">Tu sa zobrazia vaÅ¡e navrhované Älánky</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{Vaše zariadenie sa reštartuje teraz}=1{Vaše zariadenie sa reštartuje o 1 sekundu}few{Vaše zariadenie sa reštartuje o # sekundy}many{Vaše zariadenie sa reštartuje o # sekundy}other{Vaše zariadenie sa reštartuje o # sekúnd}}</translation>
<translation id="6302269476990306341">Zastavuje sa Asistent Google v Chrome</translation>
<translation id="6305205051461490394">Web <ph name="URL" /> je nedostupný.</translation>
<translation id="6312113039770857350">Webová stránka nie je k dispozícii</translation>
@@ -1712,6 +1752,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="6529602333819889595">&amp;Znova odstrániť</translation>
<translation id="6545864417968258051">Vyhľadávanie zariadení Bluetooth</translation>
<translation id="6547208576736763147">Dve dierky vľavo</translation>
+<translation id="6554732001434021288">Naposledy navštívené pred <ph name="NUM_DAYS" /> dňami</translation>
<translation id="6556866813142980365">Znova</translation>
<translation id="6569060085658103619">Prezeráte si stránku s rozšíreniami</translation>
<translation id="6573200754375280815">Dve dierky vpravo</translation>
@@ -1772,7 +1813,6 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="6757797048963528358">Vaše zariadenie prešlo do režimu spánku.</translation>
<translation id="6767985426384634228">Chcete adresu aktualizovať?</translation>
<translation id="6768213884286397650">Hagaki (pohľadnica)</translation>
-<translation id="6774185088257932239"><ph name="BEGIN_LINK" />Ďalšie informácie<ph name="END_LINK" /> o režime inkognito</translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">Fialová</translation>
<translation id="6786747875388722282">Rozšírenia</translation>
@@ -1856,7 +1896,6 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="706295145388601875">Pridávajte a spravujte adresy v nastaveniach Chromu</translation>
<translation id="7064851114919012435">Kontaktné údaje</translation>
<translation id="7068733155164172741">Zadajte <ph name="OTP_LENGTH" />-miestny kód</translation>
-<translation id="7070090581017165256">Tento web</translation>
<translation id="70705239631109039">VaÅ¡e pripojenie nie je úplne zabezpeÄené</translation>
<translation id="7075452647191940183">Žiadosť je príliš veľká</translation>
<translation id="7079718277001814089">Tento web obsahuje malvér</translation>
@@ -1873,6 +1912,12 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="7111012039238467737">(Platný)</translation>
<translation id="7118618213916969306">Vyhľadať webovú adresu v schránke <ph name="SHORT_URL" /></translation>
<translation id="7119414471315195487">Zavrite ostatné karty alebo programy</translation>
+<translation id="7129355289156517987">Po zavretí vÅ¡etkých kariet inkognito v prehliadaÄi Chromium sa vaÅ¡a aktivita v nich vymaže z tohto zariadenia:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Aktivita prehliadania<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />História vyhľadávania<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Informácie zadané vo formulároch<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">Dodanie na túto adresu nie je možné. Vyberte inú adresu.</translation>
<translation id="7132939140423847331">Váš správca zakázal kopírovanie týchto údajov.</translation>
<translation id="7135130955892390533">Zobraziť stav</translation>
@@ -1895,6 +1940,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="7192203810768312527">Uvoľní <ph name="SIZE" />. Niektoré weby sa môžu pri ÄalÅ¡ej návÅ¡teve naÄítaÅ¥ pomalÅ¡ie.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">Váš správca uvidí:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, stlaÄením klávesov Tab a potom Enter otvorte novú kartu inkognito a prehliadajte v súkromí</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423">Web <ph name="HOST_NAME" /> nespĺňa bezpeÄnostné Å¡tandardy.</translation>
<translation id="7210993021468939304">Aktivita Linux v rámci kontajnera. Môže inštalovať a spúšťať aplikácie pre systém LInux v kontajneri.</translation>
@@ -1926,6 +1972,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="7304562222803846232">SpravovaÅ¥ nastavenia ochrany súkromia úÄtu Google</translation>
<translation id="7305756307268530424">Pomalšie</translation>
<translation id="7308436126008021607">synchronizácia na pozadí</translation>
+<translation id="7310392214323165548">Zariadenie sa Äoskoro reÅ¡tartuje</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">Pomocník s pripojením</translation>
<translation id="7323804146520582233">Skryť sekciu <ph name="SECTION" /></translation>
@@ -1933,6 +1980,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="7334320624316649418">&amp;Znova zmeniť poradie</translation>
<translation id="7335157162773372339">Môže žiadať o povolenie používať kameru</translation>
<translation id="7337248890521463931">Zobraziť viac riadkov</translation>
+<translation id="7337418456231055214">Nebolo vyplnené Äíslo virtuálnej karty? Kliknutím skopírujte podrobnosti karty. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">Nie je k dispozícii pre vašu platformu.</translation>
<translation id="733923710415886693">Certifikát servera nebol zverejnený prostredníctvom pravidla transparentnosti certifikátov.</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1955,6 +2003,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="7378627244592794276">Nie</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">Nedá sa použiť</translation>
+<translation id="7388594495505979117">{0,plural, =1{Vaše zariadenie sa reštartuje o 1 minútu}few{Vaše zariadenie sa reštartuje o # minúty}many{Vaše zariadenie sa reštartuje o # minúty}other{Vaše zariadenie sa reštartuje o # minút}}</translation>
<translation id="7390545607259442187">Overenie karty</translation>
<translation id="7392089738299859607">Aktualizácia adresy</translation>
<translation id="7399802613464275309">Kontrola bezpeÄnosti</translation>
@@ -1991,6 +2040,12 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="7485870689360869515">Nenašli sa žiadne údaje.</translation>
<translation id="7495528107193238112">Tento obsah je blokovaný. Kontaktujte vlastníka webu a požiadajte ho odstránenie daného problému.</translation>
<translation id="7497998058912824456">TlaÄidlo na vytvorenie dokumentu, stlaÄením klávesa Enter vytvoríte rýchlym spôsobom nový dokument Google</translation>
+<translation id="7506488012654002225">Chromium <ph name="BEGIN_EMPHASIS" />neuloží<ph name="END_EMPHASIS" /> the nasledujúce informácie:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />históriu prehliadania,
+ <ph name="LIST_ITEM" />súbory cookie a dáta webov,
+ <ph name="LIST_ITEM" />informácie zadané vo formulároch.
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">Identifikátor zariadenia vráteného v rámci záruky je prázdny alebo sa nezhoduje s identifikátorom aktuálneho zariadenia</translation>
<translation id="7508870219247277067">Žltozelená</translation>
<translation id="7511955381719512146">Sieť Wi‑Fi, ktorú používate, môže vyžadovať, aby ste navštívili stránku <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /></translation>
@@ -2104,7 +2159,6 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="7813600968533626083">Chcete návrh odstrániÅ¥ z prehliadaÄa Chrome?</translation>
<translation id="781440967107097262">Chcete zdieľať schránku?</translation>
<translation id="7815407501681723534">Nájdené výsledky (poÄet: <ph name="NUMBER_OF_RESULTS" />) pre dopyt „<ph name="SEARCH_STRING" />“: <ph name="SEARCH_RESULTS" /></translation>
-<translation id="782125616001965242">Zobraziť informácie o tomto webe</translation>
<translation id="782886543891417279">Sieť Wi‑Fi (<ph name="WIFI_NAME" />), ktorú používate, môže vyžadovať, aby ste navštívili jej prihlasovaciu stránku</translation>
<translation id="7836231406687464395">Postfix (obálka)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{Žiadne}=1{1 aplikácia (<ph name="EXAMPLE_APP_1" />)}=2{2 aplikácie (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}few{# aplikácie (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}many{# apps (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}other{# aplikácií (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}}</translation>
@@ -2121,7 +2175,6 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="7888575728750733395">Vykresľovacia intencia tlaÄe</translation>
<translation id="7894280532028510793">Ak je pravopis správny, <ph name="BEGIN_LINK" />skúste spustiť nástroj Network Diagnostics<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (obálka)</translation>
-<translation id="7931318309563332511">Neznámy</translation>
<translation id="793209273132572360">Chcete aktualizovať adresu?</translation>
<translation id="7932579305932748336">Naniesť povrchovú vrstvu</translation>
<translation id="79338296614623784">Zadajte platné telefónne Äíslo</translation>
@@ -2146,13 +2199,14 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="7976214039405368314">Príliš veľa žiadostí</translation>
<translation id="7977538094055660992">Zariadenie výstupu</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">Prepojené s kartou</translation>
<translation id="798134797138789862">Môže žiadať o povolenie používať zariadenia a dáta virtuálnej reality</translation>
<translation id="7984945080620862648">Webové stránky <ph name="SITE" /> momentálne nemôžete navÅ¡tíviÅ¥, pretože vrátili zakódované poverenia, ktoré Chrome nedokáže spracovaÅ¥. Chyby siete a útoky sú zvyÄajne doÄasné, takže by táto stránka mala neskôr pravdepodobne fungovaÅ¥.</translation>
-<translation id="79859296434321399">Ak chcete zobraziť obsah v rozšírenej realite, nainštalujte si ARCore</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">Zviazať</translation>
<translation id="7992044431894087211">Zdieľanie obrazovky pomocou aplikácie <ph name="APPLICATION_TITLE" /> bolo obnovené</translation>
<translation id="7995512525968007366">Nie je upresnené</translation>
+<translation id="7998269595945679889">TlaÄidlo OtvoriÅ¥ kartu inkognito, stlaÄením klávesa Enter otvorte novú kartu inkognito a prehliadajte v súkromí</translation>
<translation id="800218591365569300">Skúste zavrieť ostatné karty alebo programy a uvoľniť tak miesto v pamäti.</translation>
<translation id="8004582292198964060">PrehliadaÄ</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{Táto karta a jej fakturaÄná adresa budú uložené. Budete ju môcÅ¥ použiÅ¥ po prihlásení do úÄtu <ph name="USER_EMAIL" />.}few{Tieto karty a ich fakturaÄné adresy budú uložené. Budete ich môcÅ¥ použiÅ¥ po prihlásení do úÄtu <ph name="USER_EMAIL" />.}many{Tieto karty a ich fakturaÄné adresy budú uložené. Budete ich môcÅ¥ použiÅ¥ po prihlásení do úÄtu <ph name="USER_EMAIL" />.}other{Tieto karty a ich fakturaÄné adresy budú uložené. Budete ich môcÅ¥ použiÅ¥ po prihlásení do úÄtu <ph name="USER_EMAIL" />.}}</translation>
@@ -2212,6 +2266,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="8202370299023114387">Konflikt</translation>
<translation id="8206978196348664717">Prc4 (obálka)</translation>
<translation id="8211406090763984747">Spojenie je zabezpeÄené</translation>
+<translation id="8217240300496046857">Weby nemôžu používať súbory cookie, ktoré vás sledujú na internete. Funkcie na niektorých weboch môžu zlyhávať.</translation>
<translation id="8218327578424803826">Pridelená poloha:</translation>
<translation id="8220146938470311105">C7/C6 (obálka)</translation>
<translation id="8225771182978767009">Osoba, ktorá nastavila tento poÄítaÄ, sa rozhodla daný web blokovaÅ¥.</translation>
@@ -2252,14 +2307,9 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="830498451218851433">Zahnúť v polovici</translation>
<translation id="8307358339886459768">Malá fotka</translation>
<translation id="8307888238279532626">NainÅ¡talované aplikácie a ako Äasto sú používané</translation>
+<translation id="8317207217658302555">Chcete aktualizovať ARCore?</translation>
<translation id="831997045666694187">VeÄer</translation>
<translation id="8321476692217554900">upozornenia</translation>
-<translation id="8328484624016508118">Po zavretí všetkých kariet inkognito Chrome vymaže:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />vašu aktivitu prehliadania z tohto zariadenia;<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />vašu históriu vyhľadávania z tohto zariadenia;<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />údaje zadané do formulárov.<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489">Prístup k webu <ph name="HOST_NAME" /> bol zamietnutý</translation>
<translation id="833262891116910667">Zvýrazniť</translation>
<translation id="8339163506404995330">Stránky v jazyku <ph name="LANGUAGE" /> nebudú prekladané</translation>
@@ -2311,6 +2361,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="8507227106804027148">Príkazový riadok</translation>
<translation id="8508648098325802031">Ikona vyhľadávania</translation>
<translation id="8511402995811232419">Spravovať súbory cookie</translation>
+<translation id="8519753333133776369">Zariadenie HID povolené vaším správcom</translation>
<translation id="8522552481199248698">Chrome vám pomôže ochrániÅ¥ úÄet Google a zmeniÅ¥ heslo.</translation>
<translation id="8530813470445476232">VymazaÅ¥ svoju históriu prehliadania, súbory cookie, vyrovnávaciu pamäť a ÄalÅ¡ie položky v nastaveniach Chromu</translation>
<translation id="8533619373899488139">Na stránke &lt;strong&gt;chrome://policy&lt;/strong&gt; nájdete zoznam zakázaných webových adries a ÄalÅ¡ie pravidlá presadzované vaším správcom systému.</translation>
@@ -2322,7 +2373,6 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{Resetovať povolenie}few{Resetovať povolenia}many{Resetovať povolenia}other{Resetovať povolenia}}</translation>
<translation id="8555010941760982128">Tento kód použite pri platbe</translation>
<translation id="8557066899867184262">Kód CVC nájdete na zadnej strane karty.</translation>
-<translation id="8558485628462305855">Ak chcete zobraziť obsah v rozšírenej realite, aktualizujte ARCore</translation>
<translation id="8559762987265718583">Súkromné pripojenie k doméne <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> sa nedá nadviazaÅ¥, pretože dátum a Äas (<ph name="DATE_AND_TIME" />) vášho zariadenia sú nesprávne.</translation>
<translation id="8564182942834072828">Samostatné dokumenty alebo nezoradené kópie</translation>
<translation id="8564985650692024650">Ak ste heslo organizácie <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> použili aj na iných weboch, Chromium ho odporúÄa obnoviÅ¥.</translation>
@@ -2342,6 +2392,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="865032292777205197">senzory pohybu</translation>
<translation id="8663226718884576429">Súhrn objednávky, <ph name="TOTAL_LABEL" />, ÄalÅ¡ie podrobnosti</translation>
<translation id="8666678546361132282">AngliÄtina</translation>
+<translation id="8669306706049782872">Otvárať a umiestňovať okná pomocou informácií o vašich obrazovkách</translation>
<translation id="867224526087042813">Podpis</translation>
<translation id="8676424191133491403">Bez oneskorenia</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, odpoveÄ, <ph name="ANSWER" /></translation>
@@ -2368,6 +2419,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="8731544501227493793">TlaÄidlo SpravovaÅ¥ heslá. StlaÄením klávesa Enter môžete heslá zobraziÅ¥ a spravovaÅ¥ v nastaveniach Chromu.</translation>
<translation id="8734529307927223492">Vaše zariadenie <ph name="DEVICE_TYPE" /> spravuje <ph name="MANAGER" /></translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, stlaÄením klávesov Tab a potom Enter otvorte nové okno inkognito a prehliadajte v súkromí</translation>
+<translation id="8737685506611670901">Otvárať odkazy protokolu <ph name="PROTOCOL" /> a nie aplikáciu <ph name="REPLACED_HANDLER_TITLE" /></translation>
<translation id="8738058698779197622">Ak chcete nadviazaÅ¥ zabezpeÄené pripojenie, vaÅ¡e hodiny musia byÅ¥ nastavené správne. Je to preto, že certifikáty, ktoré webové stránky používajú na vlastnú identifikáciu, sú platné iba urÄitý Äas. KeÄže nie sú hodiny vášho zariadenia nastavené správne, Chromium nemôže tieto certifikáty overiÅ¥.</translation>
<translation id="8740359287975076522">&lt;abbr id="dnsDefinition"&gt;Adresa DNS&lt;/abbr&gt; webu <ph name="HOST_NAME" /> sa nenašla. Problém sa diagnostikuje.</translation>
<translation id="8742371904523228557"><ph name="ONE_TIME_CODE" /> je kód pre <ph name="ORIGIN" /></translation>
@@ -2395,6 +2447,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="883848425547221593">Iné záložky</translation>
<translation id="884264119367021077">Dodacia adresa</translation>
<translation id="884923133447025588">Nenašiel sa žiadny mechanizmus rušenia certifikátov.</translation>
+<translation id="8849262850971482943">V záujme vyÅ¡Å¡ej bezpeÄnosti použite virtuálnu kartu</translation>
<translation id="885730110891505394">Zdieľanie s Googlom</translation>
<translation id="8858065207712248076">Ak ste heslo organizácie <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> použili aj na iných weboch, Chrome ho odporúÄa obnoviÅ¥.</translation>
<translation id="885906927438988819">Ak je pravopis správny, <ph name="BEGIN_LINK" />skúste spustiť nástroj Windows Network Diagnostics<ph name="END_LINK" />.</translation>
@@ -2444,6 +2497,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="9004367719664099443">Prebieha relácia VR</translation>
<translation id="9005998258318286617">Dokument PDF sa nepodarilo naÄítaÅ¥.</translation>
<translation id="9008201768610948239">Ignorovať</translation>
+<translation id="901834265349196618">e-mail</translation>
<translation id="9020200922353704812">FakturaÄná adresa karty je povinná</translation>
<translation id="9020542370529661692">Táto stránka bola preložená do jazyka <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9020742383383852663">A8</translation>
@@ -2492,6 +2546,7 @@ Ich používanie by bolo inak blokované vašimi nastaveniami ochrany súkromia.
<translation id="9150045010208374699">Používať vašu kameru</translation>
<translation id="9150685862434908345">Nastavenia prehliadaÄa môže vzdialene zmeniÅ¥ správca. Aktivita v tomto zariadení môže byÅ¥ tiež spravovaná mimo Chromu. <ph name="BEGIN_LINK" />ÄŽalÅ¡ie informácie<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">Aktualizované</translation>
+<translation id="9155211586651734179">Pripojené zvukové periférie</translation>
<translation id="9157595877708044936">Prebieha nastavenie...</translation>
<translation id="9158625974267017556">C6 (obálka)</translation>
<translation id="9164029392738894042">Kontrola presnosti</translation>
diff --git a/chromium/components/strings/components_strings_sl.xtb b/chromium/components/strings/components_strings_sl.xtb
index 5753319588b..446d7bc8a99 100644
--- a/chromium/components/strings/components_strings_sl.xtb
+++ b/chromium/components/strings/components_strings_sl.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">Ogled podrobnosti</translation>
<translation id="1030706264415084469"><ph name="URL" /> želi trajno shranjevati velike koliÄine podatkov v vaÅ¡i napravi</translation>
<translation id="1032854598605920125">Sukanje v smeri urnega kazalca</translation>
+<translation id="1033329911862281889">V anonimnem naÄinu niste nevidni v spletu:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />spletna mesta in storitve, ki jih uporabljajo, si lahko ogledajo obiske;<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />delodajalci ali šole lahko spremljajo vaše brskanje;<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ponudniki internetnih storitev lahko spremljajo spletni promet.<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">Izklop</translation>
<translation id="1036982837258183574">Pritisnite |<ph name="ACCELERATOR" />| za zapiranje celozaslonskega naÄina</translation>
<translation id="1038106730571050514">Prikaz predlogov</translation>
<translation id="1038842779957582377">neznano ime</translation>
<translation id="1041998700806130099">SporoÄilo glede delovnega lista</translation>
<translation id="1048785276086539861">ÄŒe boste urejali pripise, se bo ta dokument vrnil v pogled ene strani.</translation>
-<translation id="1049743911850919806">Anonimni naÄin</translation>
<translation id="1050038467049342496">Zaprite druge aplikacije</translation>
<translation id="1055184225775184556">&amp;Razveljavi dodajanje</translation>
<translation id="1056898198331236512">Opozorilo</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">Predpomnilnik pravilnika ustrezen</translation>
<translation id="1130564665089811311">Gumb za prevajanje strani, pritisnite Enter, Äe želite prevesti to stran z Google Prevajalnikom</translation>
<translation id="1131264053432022307">Slika, ki ste jo kopirali</translation>
+<translation id="1142846828089312304">Blokiraj piÅ¡kotke drugih mest v anonimnem naÄinu</translation>
<translation id="1150979032973867961">Strežniku ni uspelo dokazati, da je <ph name="DOMAIN" />; operacijski sistem vaÅ¡ega raÄunalnika ne zaupa njegovemu varnostnemu potrdilu. Razlog za to je lahko napaÄna konfiguracija ali napadalÄevo prestrezanje povezave.</translation>
<translation id="1151972924205500581">Potrebno je geslo</translation>
<translation id="1156303062776767266">Ogledujete si lokalno datoteko ali datoteko v skupni rabi</translation>
@@ -64,7 +70,6 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="1178581264944972037">Prekini</translation>
<translation id="1181037720776840403">Odstrani</translation>
<translation id="1186201132766001848">Preveri gesla</translation>
-<translation id="1195210374336998651">V nastavitve aplikacije</translation>
<translation id="1195558154361252544">Obvestila so samodejno blokirana za vsa spletna mesta, razen za tista z vašim dovoljenjem</translation>
<translation id="1197088940767939838">Oranžna</translation>
<translation id="1201402288615127009">Naprej</translation>
@@ -111,7 +116,7 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="1307966114820526988">Zastarele funkcije</translation>
<translation id="1308113895091915999">Ponudba je na voljo</translation>
<translation id="1312803275555673949">Kateri dokazi to potrjujejo?</translation>
-<translation id="131405271941274527"><ph name="URL" /> želi pošiljati in prejemati podatke, ko se dotaknete telefona v napravi s tehnologijo NFC</translation>
+<translation id="1314311879718644478">Ogled vsebine v razÅ¡irjeno resniÄnosti</translation>
<translation id="1314509827145471431">Vezava na desni</translation>
<translation id="1318023360584041678">Shranjeno v skupini zavihkov</translation>
<translation id="1319245136674974084">Ne spraÅ¡uj veÄ za to aplikacijo</translation>
@@ -161,6 +166,7 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="142858679511221695">Uporabnik v oblaku</translation>
<translation id="1428729058023778569">To opozorilo je prikazano, ker spletno mesto ne podpira protokola HTTPS. <ph name="BEGIN_LEARN_MORE_LINK" />VeÄ o tem<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">Natisni</translation>
+<translation id="1432187715652018471">stran želi namestiti rutino za obravnavo storitev.</translation>
<translation id="1432581352905426595">Upravljanje iskalnikov</translation>
<translation id="1436185428532214179">Lahko zahteva urejanje datotek in map v napravi.</translation>
<translation id="1442386063175183758">Prepogibanje v obliki okna z desne</translation>
@@ -181,6 +187,12 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="1483493594462132177">Pošlji</translation>
<translation id="1484290072879560759">Izbira naslova za pošiljanje</translation>
<translation id="1492194039220927094">Potiskanje pravilnikov:</translation>
+<translation id="149293076951187737">Ko v Chromu zaprete vse anonimne zavihke, se dejavnost na teh zavihkih izbriše iz te naprave:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />dejavnost brskanja;<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />zgodovina iskanja;<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />podatki, vneseni v obrazce.<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">Nazaj na zavihek</translation>
<translation id="1501859676467574491">Prikaz kartic iz Google RaÄuna</translation>
<translation id="1507202001669085618">&lt;p&gt;Ta napaka se prikaže, Äe uporabljate portal Wi-Fi, ki pred uporabo spleta zahteva prijavo.&lt;/p&gt;
@@ -208,6 +220,8 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="1559572115229829303">&lt;p&gt;Zasebne povezave z domeno <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> ni mogoÄe vzpostaviti, ker sta datum in ura (<ph name="DATE_AND_TIME" />) v napravi nepravilna.&lt;/p&gt;
&lt;p&gt;V razdelku &lt;strong&gt;Splošno&lt;/strong&gt; aplikacije &lt;strong&gt;Nastavitve&lt;/strong&gt; prilagodite datum in uro.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">Skrbnik bo znova zagnal napravo ob <ph name="TIME" /> dne <ph name="DATE" /></translation>
+<translation id="156703335097561114">Podatki o omrežju, kot so naslovi, konfiguracija vmesnika in kakovost povezave</translation>
<translation id="1567040042588613346">Ta pravilnik deluje, kot je predvideno, vendar je nekje drugje nastavljena enaka vrednost, ki jo ta pravilnik nadomesti.</translation>
<translation id="1569487616857761740">Vnesite datum poteka</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="1583429793053364125">Med prikazom spletne strani je prišlo do napake.</translation>
<translation id="1586541204584340881">Katere razširitve ste namestili</translation>
<translation id="1588438908519853928">ObiÄajen</translation>
+<translation id="1589050138437146318">Želite namestiti ARCore?</translation>
<translation id="1592005682883173041">Dostop do lokalnih podatkov</translation>
<translation id="1594030484168838125">Izberi</translation>
<translation id="160851722280695521">Igranje igre Dino Run v Chromu</translation>
@@ -283,6 +298,7 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
je glava popaÄena, zaradi Äesar brskalnik ne more
izpolniti vaše zahteve za <ph name="SITE" />. Pravilnike izvora lahko uporabljajo
ponudniki spletnih mest zaradi konfiguriranja varnosti in drugih lastnosti spletnega mesta.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Preberite veÄ o anonimnem naÄinu v Chromiumu<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">Tu so prikazani odprti zavihki</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -410,6 +426,7 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="22081806969704220">Pladenj 3</translation>
<translation id="2212735316055980242">Pravilnika ni mogoÄe najti</translation>
<translation id="2213606439339815911">Prenos vnosov ...</translation>
+<translation id="2213612003795704869">Stran je natisnjena</translation>
<translation id="2215727959747642672">Urejanje datotek</translation>
<translation id="2218879909401188352">Napadalci, ki so trenutno na spletnem mestu <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />, bi lahko namestili nevarne aplikacije, ki poÅ¡kodujejo napravo, dodajo skrite stroÅ¡ke na raÄun za mobilno napravo ali ukradejo osebne podatke. <ph name="BEGIN_LEARN_MORE_LINK" />VeÄ o tem<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">Ni internetne povezave</translation>
@@ -419,6 +436,7 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="2248949050832152960">Uporabi WebAuthn</translation>
<translation id="2250931979407627383">Robni Å¡iv na levi</translation>
<translation id="225207911366869382">Vrednost za ta pravilnik je zastarela.</translation>
+<translation id="2256115617011615191">Znova zaženi</translation>
<translation id="2258928405015593961">Vnesite datum poteka v prihodnosti in poskusite znova.</translation>
<translation id="225943865679747347">Koda napake: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">Napaka HTTP</translation>
@@ -446,6 +464,7 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="2337852623177822836">Nastavitev nadzira vaš skrbnik</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> želi izvesti seznanitev</translation>
<translation id="2346319942568447007">Slika, ki ste jo kopirali</translation>
+<translation id="2350796302381711542">Dovoli gostitelju <ph name="HANDLER_HOSTNAME" /> odpreti vse povezave za <ph name="PROTOCOL" /> namesto gostitelja <ph name="REPLACED_HANDLER_TITLE" />?</translation>
<translation id="2354001756790975382">Drugi zaznamki</translation>
<translation id="2354430244986887761">Google Varno brskanje je nedavno <ph name="BEGIN_LINK" />našlo škodljive aplikacije<ph name="END_LINK" /> na spletnem mestu <ph name="SITE" />.</translation>
<translation id="2355395290879513365">Napadalci morda vidijo slike, ki si jih ogledujete na tem spletnem mestu, in vas ukanijo, tako da jih spremenijo.</translation>
@@ -471,6 +490,7 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="2413528052993050574">Strežniku ni uspelo dokazati, da je <ph name="DOMAIN" />; njegovo varnostno potrdilo je bilo morda preklicano. Razlog za to je lahko napaÄna konfiguracija ali napadalÄevo prestrezanje povezave.</translation>
<translation id="2414886740292270097">Temno</translation>
<translation id="2430968933669123598">Upravljanje raÄuna Google, pritisnite Enter, Äe želite upravljati podatke, zasebnost in varnost v raÄunu Google</translation>
+<translation id="2436186046335138073">Dovoli gostitelju <ph name="HANDLER_HOSTNAME" /> odpreti vse povezave za <ph name="PROTOCOL" />?</translation>
<translation id="2438874542388153331">ÄŒetverno luknjanje na desni</translation>
<translation id="2450021089947420533">Poti</translation>
<translation id="2463739503403862330">Izpolni</translation>
@@ -478,6 +498,7 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="2465655957518002998">Izbira naÄina dostave</translation>
<translation id="2465688316154986572">Spenjanje</translation>
<translation id="2465914000209955735">Upravljanje datotek, ki ste jih prenesli v Chromu</translation>
+<translation id="2466004615675155314">Prikaz informacij iz spleta</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Izvajanje orodja za omrežno diagnostiko<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">Vrstni red 1–N</translation>
<translation id="2470767536994572628">ÄŒe boste urejali pripise, se bo ta dokument vrnil v pogled ene strani in prvotno stanje vrtenja.</translation>
@@ -498,6 +519,7 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="2523886232349826891">Shranjena samo v tej napravi</translation>
<translation id="2524461107774643265">Dodajanje veÄ podatkov</translation>
<translation id="2529899080962247600">V tem polju je lahko najveÄ toliko vnosov: <ph name="MAX_ITEMS_LIMIT" />. Vsi nadaljnji vnosi bodo prezrti.</translation>
+<translation id="2535585790302968248">Odpiranje novega anonimnega zavihka za zasebno brskanje</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{in Å¡e 1}one{in Å¡e #}two{in Å¡e #}few{in Å¡e #}other{in Å¡e #}}</translation>
<translation id="2536110899380797252">Dodaj naslov</translation>
<translation id="2539524384386349900">Zaznava</translation>
@@ -523,7 +545,14 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="2597378329261239068">Dokument je zaÅ¡Äiten z geslom. Vnesite geslo.</translation>
<translation id="2609632851001447353">RazliÄice</translation>
<translation id="2610561535971892504">Kliknite za kopiranje</translation>
+<translation id="2617988307566202237">Chrome <ph name="BEGIN_EMPHASIS" />ne shrani<ph name="END_EMPHASIS" /> teh podatkov:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />zgodovine brskanja,
+ <ph name="LIST_ITEM" />piškotkov in podatkov spletnih mest,
+ <ph name="LIST_ITEM" />podatkov, vnesenih v obrazce.
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (Envelope)</translation>
+<translation id="2623663032199728144">lahko zahteva uporabo podatkov o zaslonih</translation>
<translation id="2625385379895617796">Ura prehiteva</translation>
<translation id="262745152991669301">Lahko zahteva vzpostavitev povezave z napravami USB.</translation>
<translation id="2629325967560697240">ÄŒe želite imeti Chromovo najveÄjo raven varnosti, <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />vklopite izboljÅ¡ano zaÅ¡Äito<ph name="END_ENHANCED_PROTECTION_LINK" />.</translation>
@@ -557,6 +586,7 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="2709516037105925701">Samodejno izpolnjevanje</translation>
<translation id="2713444072780614174">Bela</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />, pritisnite tabulatorko, nato Enter, Äe želite upravljati plaÄila in podatke o kreditnih karticah v Chromovih nastavitvah</translation>
+<translation id="271663710482723385">Pritisnite |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| za zapiranje celozaslonskega naÄina</translation>
<translation id="2721148159707890343">Zahteva je uspela</translation>
<translation id="2723669454293168317">V nastavitvah Chroma zaženite varnostno preverjanje.</translation>
<translation id="2726001110728089263">Stranski pladenj</translation>
@@ -587,6 +617,7 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="2850739647070081192">Invite (Envelope)</translation>
<translation id="2856444702002559011">Morda poskuÅ¡ajo napadalci ukrasti vaÅ¡e podatke s spletnega mesta <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (na primer gesla, sporoÄila ali podatke kreditnih kartic). <ph name="BEGIN_LEARN_MORE_LINK" />VeÄ o tem<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">To spletno mesto prikazuje vsiljive ali zavajajoÄe oglase.</translation>
+<translation id="286512204874376891">Navidezna kartica zakrije dejansko kartico in ste tako zaÅ¡Äiteni pred morebitno prevaro. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">Prijateljsko</translation>
<translation id="2876489322757410363">Zaradi plaÄila v zunanji aplikaciji boste zapustili anonimni naÄin. Želite nadaljevati?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />, pritisnite tabulatorko, nato Enter, Äe želite upravljati Varno brskanje in drugo v Chromovih nastavitvah.</translation>
@@ -611,6 +642,7 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="2930577230479659665">Obrezovanje po vsakem izvodu</translation>
<translation id="2932085390869194046">Predlagaj geslo …</translation>
<translation id="2934466151127459956">Government Letter</translation>
+<translation id="2938225289965773019">Odpiranje povezav za <ph name="PROTOCOL" /></translation>
<translation id="2941952326391522266">Strežniku ni uspelo dokazati, da je res <ph name="DOMAIN" />; njegovo varnostno potrdilo je od <ph name="DOMAIN2" />. Razlog za to je lahko napaÄna konfiguracija ali napadalÄevo prestrezanje povezave.</translation>
<translation id="2943895734390379394">ÄŒas nalaganja:</translation>
<translation id="2948083400971632585">NamestniÅ¡ke strežnike, konfigurirane za povezavo, lahko onemogoÄite na strani z nastavitvami.</translation>
@@ -643,6 +675,7 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="3037605927509011580">Ti Å¡ment!</translation>
<translation id="3041612393474885105">Informacije o potrdilu</translation>
<translation id="3044034790304486808">Nadaljujte raziskavo</translation>
+<translation id="305162504811187366">Zgodovina Oddaljenega namizja Chrome, vkljuÄno s Äasovnimi žigi, gostitelji in ID-ji sej odjemalca</translation>
<translation id="3060227939791841287">C9 (Envelope)</translation>
<translation id="3061707000357573562">Storitev za popravke</translation>
<translation id="306573536155379004">Igra se je zaÄela.</translation>
@@ -683,6 +716,7 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="3197136577151645743">Lahko zahteva, da izve, kdaj aktivno uporabljate napravo.</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />, pritisnite tabulatorko, nato Enter, Äe želite upravljati, kateri podatki se sinhronizirajo v Chromovih nastavitvah.</translation>
<translation id="320323717674993345">PrekliÄi plaÄilo</translation>
+<translation id="3203366800380907218">Iz spleta</translation>
<translation id="3207960819495026254">Dodano med zaznamke</translation>
<translation id="3209034400446768650">Stran morda zaraÄunava</translation>
<translation id="3212581601480735796">Vaša dejavnost v gostitelju <ph name="HOSTNAME" /> je nadzorovana</translation>
@@ -699,10 +733,12 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="3234666976984236645">Vedno zaznaj pomembno vsebino na tem spletnem mestu</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />, pritisnite tabulatorko, nato Enter, Äe želite prilagoditi videz brskalnika.</translation>
<translation id="3240791268468473923">Preglednica za neujemanje poverilnic poverilnice za varno plaÄilo je odprta</translation>
+<translation id="324180406144491771">Povezave gostitelja »<ph name="HOST_NAME" />« so blokirane</translation>
<translation id="3249845759089040423">Razgibano</translation>
<translation id="3252266817569339921">francoÅ¡Äina</translation>
<translation id="3257954757204451555">Kdo stoji za temi informacijami?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />, pritisnite tabulatorko, nato Enter, Äe želite hitro ustvariti nov dogodek v Google Koledarju</translation>
+<translation id="3261488570342242926">Preberite veÄ o navideznih karticah</translation>
<translation id="3264837738038045344">Gumb za upravljanje Chromovih nastavitev, pritisnite Enter, Äe želite odpreti Chromove nastavitve</translation>
<translation id="3266793032086590337">Vrednost (v sporu)</translation>
<translation id="3268451620468152448">Odprti zavihki</translation>
@@ -716,6 +752,7 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="3288238092761586174">Gostitelj <ph name="URL" /> bo morda moral opraviti dodatne korake za preverjanje vaÅ¡ega plaÄila.</translation>
<translation id="3293642807462928945">Preberite veÄ o pravilniku <ph name="POLICY_NAME" /></translation>
<translation id="3295444047715739395">Ogled in upravljanje gesel v nastavitvah v Chromu</translation>
+<translation id="3303795387212510132">Želite aplikaciji omogoÄiti odpiranje povezav <ph name="PROTOCOL_SCHEME" />?</translation>
<translation id="3303855915957856445">Ni rezultatov iskanja</translation>
<translation id="3304073249511302126">iskanje naprav Bluetooth</translation>
<translation id="3308006649705061278">Organizacijska enota (OU)</translation>
@@ -729,12 +766,6 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="3345782426586609320">OÄi</translation>
<translation id="3355823806454867987">Spremeni nastavitve proxyja ...</translation>
<translation id="3360103848165129075">List rutine za obravnavo plaÄil</translation>
-<translation id="3361596688432910856">Chrome <ph name="BEGIN_EMPHASIS" />ne shrani<ph name="END_EMPHASIS" /> teh podatkov:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />zgodovine brskanja,
- <ph name="LIST_ITEM" />piškotkov in podatkov spletnih mest,
- <ph name="LIST_ITEM" />podatkov, vnesenih v obrazce.
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">Ta pravilnik je bil samodejno kopiran iz zastarelega pravilnika <ph name="OLD_POLICY" />. Uporabite ta pravilnik.</translation>
<translation id="3364869320075768271"><ph name="URL" /> želi uporabljati napravo in podatke za navidezno resniÄnost</translation>
<translation id="3366477098757335611">Ogled kartic</translation>
@@ -817,7 +848,6 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="3587738293690942763">Srednje</translation>
<translation id="3592413004129370115">Italian (Envelope)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{Skupino lahko kadar koli ponastavite. Pridružitev novi skupini traja približno en dan.}=1{Skupino lahko kadar koli ponastavite. Pridružitev novi skupini traja približno en dan.}one{Skupino lahko kadar koli ponastavite. Pridružitev novi skupini traja približno {NUM_DAYS} dan.}two{Skupino lahko kadar koli ponastavite. Pridružitev novi skupini traja približno {NUM_DAYS} dneva.}few{Skupino lahko kadar koli ponastavite. Pridružitev novi skupini traja približno {NUM_DAYS} dni.}other{Skupino lahko kadar koli ponastavite. Pridružitev novi skupini traja približno {NUM_DAYS} dni.}}</translation>
-<translation id="3596012367874587041">Nastavitve aplikacije</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">Aplikacijo je blokiral skrbnik</translation>
<translation id="3608932978122581043">Usmerjenost podajanja</translation>
@@ -860,6 +890,7 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="370972442370243704">Vklop Poti</translation>
<translation id="3711895659073496551">Prekinitev</translation>
<translation id="3712624925041724820">Ni dovolj licenc</translation>
+<translation id="3714633008798122362">spletni koledar</translation>
<translation id="3714780639079136834">vklopiti prenos podatkov v mobilnih omrežjih ali Wi-Fi</translation>
<translation id="3715597595485130451">Vzpostavljanje povezave z omrežjem Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />preveriti strežnik proxy, požarni zid in konfiguracijo DNS-ja<ph name="END_LINK" /></translation>
@@ -921,6 +952,7 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="3906954721959377182">TabliÄni raÄunalnik</translation>
<translation id="3909477809443608991"><ph name="URL" /> želi predvajati zaÅ¡Äiteno vsebino. Google bo preveril identiteto naprave in do nje bo morda dostopalo to spletno mesto.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> – <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">Ne dovoli</translation>
<translation id="3939773374150895049">Želite namesto kode CVC uporabiti WebAuthn?</translation>
<translation id="3946209740501886391">Vedno vprašaj na tem spletnem mestu</translation>
<translation id="3947595700203588284">Lahko zahteva vzpostavitev povezave z napravami MIDI.</translation>
@@ -942,6 +974,7 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="3990250421422698716">Zamik v naÄinu dela »jog«</translation>
<translation id="3996311196211510766">Spletno mesto <ph name="ORIGIN" /> je zahtevalo, da izvorni pravilnik
velja za vse njegove zahteve, vendar tega pravilnika trenutno ni mogoÄe uveljaviti.</translation>
+<translation id="4009243425692662128">Vsebina natisnjenih strani je poslana v Google Cloud ali drugim ponudnikom v analizo. Lahko je na primer pregledana glede tega, ali vsebuje obÄutljive podatke.</translation>
<translation id="4010758435855888356">Želite odobriti dostop do shrambe?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{Dokument PDF, ki vsebuje {COUNT} stran}one{Dokument PDF, ki vsebuje {COUNT} stran}two{Dokument PDF, ki vsebuje {COUNT} strani}few{Dokument PDF, ki vsebuje {COUNT} strani}other{Dokument PDF, ki vsebuje {COUNT} strani}}</translation>
<translation id="4023431997072828269">Ta obrazec pošiljate prek povezave, ki ni varna, zato bodo drugi uporabniki lahko videli vaše podatke.</translation>
@@ -1036,6 +1069,7 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="4250680216510889253">Ne</translation>
<translation id="4253168017788158739">Opomba</translation>
<translation id="425582637250725228">Spremembe, ki ste jih naredili, morda niso shranjene.</translation>
+<translation id="425869179292622354">Ali želite poskrbeti za veÄjo zaÅ¡Äito z navidezno kartico?</translation>
<translation id="4258748452823770588">NapaÄen podpis</translation>
<translation id="4261046003697461417">ZaÅ¡Äitenim dokumentom ni mogoÄe dodajati pripisov</translation>
<translation id="4265872034478892965">OmogoÄil skrbnik</translation>
@@ -1098,6 +1132,7 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="4434045419905280838">Pojavna okna in preusmeritve</translation>
<translation id="4435702339979719576">Postcard)</translation>
<translation id="443673843213245140">Uporaba strežnika proxy je onemogoÄena, vendar je njegova konfiguracija izrecno doloÄena.</translation>
+<translation id="4441832193888514600">Prezrto, ker je pravilnik mogoÄe nastaviti samo kot uporabniÅ¡ki pravilnik za oblak.</translation>
<translation id="4450893287417543264">Tega ne prikaži veÄ</translation>
<translation id="4451135742916150903">Lahko zahteva vzpostavitev povezave z napravami HID.</translation>
<translation id="4452328064229197696">Geslo, ki ste ga pravkar uporabili, je bilo najdeno v podatkovni krÅ¡itvi. Zaradi zavarovanja raÄunov Google Upravitelj gesel priporoÄa, da preverite shranjena gesla.</translation>
@@ -1153,6 +1188,7 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="4628948037717959914">Fotografija</translation>
<translation id="4631649115723685955">VkljuÄuje vraÄilo gotovine</translation>
<translation id="4636930964841734540">Informacije</translation>
+<translation id="4638670630777875591">Anonimni naÄin v Chromiumu</translation>
<translation id="464342062220857295">Funkcije iskanja</translation>
<translation id="4644670975240021822">V obratnem vrstnem redu s tiskom na spodnji strani</translation>
<translation id="4646534391647090355">Odpri zdaj</translation>
@@ -1173,6 +1209,7 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="4708268264240856090">Povezava je bila prekinjena</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Izvajanje orodja Omrežna diagnostika Windows<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426">Geslo za uporabniško ime <ph name="USERNAME" /></translation>
<translation id="4724144314178270921">Lahko zahteva ogled besedila in slik v odložiÅ¡Äu.</translation>
<translation id="4726672564094551039">Znova naloži pravilnike</translation>
<translation id="4728558894243024398">Okolje</translation>
@@ -1194,6 +1231,7 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="4757993714154412917">Pravkar ste vnesli geslo na zavajajoÄem spletnem mestu. Chromium zaradi zaÅ¡Äite raÄunov priporoÄa, da preverite shranjena gesla.</translation>
<translation id="4758311279753947758">Dodaj podatke za stik</translation>
<translation id="4761104368405085019">Uporabite mikrofon</translation>
+<translation id="4761869838909035636">Zaženi varnostno opravljanje v Chromu</translation>
<translation id="4764776831041365478">Spletna stran na naslovu <ph name="URL" /> morda zaÄasno ne deluje ali pa je trajno premaknjena na novi spletni naslov.</translation>
<translation id="4766713847338118463">Dvojno spenjanje spodaj</translation>
<translation id="4771973620359291008">Prišlo je do neznane napake.</translation>
@@ -1214,12 +1252,6 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="4819347708020428563">Želite urejati pripise v privzetem pogledu?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />, pritisnite tabulatorko, nato Enter, Äe želite hitro ustvariti novo Google Preglednico</translation>
<translation id="4825507807291741242">Zmogljivo</translation>
-<translation id="4827402517081186284">V anonimnem naÄinu niste nevidni v spletu:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />spletna mesta vedo, kdaj jih obiÅ¡Äete;<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />delodajalci ali šole lahko spremljajo vaše brskanje;<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />ponudniki internetnih storitev morda spremljajo spletni promet.<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">Vklopi opozorila</translation>
<translation id="4838327282952368871">Zasanjano</translation>
<translation id="4840250757394056958">Ogled zgodovine v Chromu</translation>
@@ -1231,12 +1263,12 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="4854362297993841467">Ta naÄin poÅ¡iljanja ni na voljo. Poskusite uporabiti drugega.</translation>
<translation id="4854853140771946034">Hitro ustvarjanje novega zapiska v Googlu Keep</translation>
<translation id="485902285759009870">Preverjanje kode …</translation>
+<translation id="4866506163384898554">Pritisnite |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| za prikaz kazalca</translation>
<translation id="4876188919622883022">Poenostavljen pogled</translation>
<translation id="4876305945144899064">Ni uporabniškega imena</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{NiÄ}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}one{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}two{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}few{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831">Iskanje poizvedbe <ph name="TEXT" /></translation>
<translation id="4879491255372875719">Samodejno (privzeto)</translation>
-<translation id="4879725228911483934">Odpiranje in postavitev oken na zaslonih</translation>
<translation id="4880827082731008257">Zgodovina iskanja</translation>
<translation id="4881695831933465202">Odpri</translation>
<translation id="4885256590493466218">PlaÄajte s kartico <ph name="CARD_DETAIL" /> pri dokonÄanju nakupa.</translation>
@@ -1245,6 +1277,7 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">Kolut 9</translation>
<translation id="4901778704868714008">Shrani ...</translation>
+<translation id="4905659621780993806">Skrbnik bo napravo samodejno znova zagnal ob <ph name="TIME" /> dne <ph name="DATE" />. Preden se naprava znova zažene, shranite odprte elemente.</translation>
<translation id="4913987521957242411">Luknjanje zgoraj levo</translation>
<translation id="4918221908152712722">Namestite <ph name="APP_NAME" /> (prenos ni potreben)</translation>
<translation id="4923459931733593730">PlaÄilo</translation>
@@ -1253,6 +1286,7 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, pritisnite tabulatorko, nato Enter, Äe želite iskati</translation>
<translation id="4930153903256238152">Velika zmogljivost</translation>
+<translation id="4940163644868678279">Anonimni naÄin v Chromu</translation>
<translation id="4943872375798546930">Ni rezultatov</translation>
<translation id="4950898438188848926">Gumb za preklop zavihkov, pritisnite Enter, Äe želite preklopiti na odprti zavihek, <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="495170559598752135">Dejanja</translation>
@@ -1262,6 +1296,7 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="4968522289500246572">Ta aplikacija je zasnovana za mobilne naprave in sprememba velikosti morda ne bo delovala pravilno. Z aplikacijo bodo morda težave ali pa se bo znova zagnala.</translation>
<translation id="4969341057194253438">Izbriši posnetek</translation>
<translation id="4973922308112707173">Dvojno luknjanje zgoraj</translation>
+<translation id="4976702386844183910">Nazadnje obiskano: <ph name="DATE" /></translation>
<translation id="4984088539114770594">Želite uporabiti mikrofon?</translation>
<translation id="4984339528288761049">Prc5 (Envelope)</translation>
<translation id="4989163558385430922">Pokaži vse</translation>
@@ -1323,6 +1358,7 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="5138227688689900538">Pokaži manj</translation>
<translation id="5145883236150621069">Koda napake v odzivu pravilnika</translation>
<translation id="5146995429444047494">Obvestila za <ph name="ORIGIN" /> so blokirana</translation>
+<translation id="514704532284964975"><ph name="URL" /> si želi ogledati in spremeniti podatke v napravah NFC, ki se jih dotaknete s svojim telefonom.</translation>
<translation id="5148809049217731050">Z licem navzgor</translation>
<translation id="515292512908731282">C4 (Envelope)</translation>
<translation id="5158275234811857234">Naslovnica</translation>
@@ -1347,6 +1383,7 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="5215116848420601511">PlaÄilna sredstva in naslovi z Googlom Pay</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">Pladenj 13</translation>
+<translation id="5216942107514965959">Nazadnje obiskano danes</translation>
<translation id="5222812217790122047">E-poštni naslov je obvezen</translation>
<translation id="5230733896359313003">Naslov za pošiljanje</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1367,7 +1404,6 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">Lastnosti dokumenta</translation>
<translation id="528468243742722775">Konec</translation>
-<translation id="5284909709419567258">Omrežni naslovi</translation>
<translation id="5285570108065881030">Prikaži vsa shranjena gesla</translation>
<translation id="5287240709317226393">Pokaži piškotke</translation>
<translation id="5287456746628258573">To spletno mesto uporablja zastarelo varnostno konfiguracijo, zaradi Äesar so lahko vaÅ¡i podatki ob poÅ¡iljanju temu spletnemu mestu izpostavljeni (npr. gesla ali Å¡tevilke kreditnih kartic).</translation>
@@ -1451,6 +1487,7 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="5556459405103347317">Znova naloži</translation>
<translation id="5560088892362098740">Datum poteka</translation>
<translation id="55635442646131152">Oris dokumenta</translation>
+<translation id="5565613213060953222">Odpri anonimni zavihek</translation>
<translation id="5565735124758917034">Aktivno</translation>
<translation id="5570825185877910964">ZaÅ¡Äita raÄuna</translation>
<translation id="5571083550517324815">Prevzem na tem naslovu ni mogoÄ. Izberite drugega.</translation>
@@ -1533,6 +1570,7 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="5869522115854928033">Shranjena gesla</translation>
<translation id="5873013647450402046">Vaša banka želi potrditi vašo identiteto.</translation>
<translation id="5887400589839399685">Kartica je shranjena</translation>
+<translation id="5887687176710214216">Nazadnje obiskano vÄeraj</translation>
<translation id="5895138241574237353">Znova zaženi</translation>
<translation id="5895187275912066135">Izdano dne</translation>
<translation id="5901630391730855834">Rumena</translation>
@@ -1546,6 +1584,7 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="5921639886840618607">Ali želite kartico shraniti v Google RaÄun?</translation>
<translation id="5922853866070715753">Skoraj konÄano</translation>
<translation id="5932224571077948991">Spletno mesto prikazuje vsiljive ali zavajajoÄe oglase</translation>
+<translation id="5938153366081463283">Dodaj navidezno kartico</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347">Odpiranje spletnega mesta <ph name="SITE_NAME" /> …</translation>
<translation id="5951495562196540101">S potroÅ¡niÅ¡kim raÄunom se ni mogoÄe vÄlaniti (na voljo je pridružena licenca).</translation>
@@ -1610,6 +1649,7 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="6120179357481664955">Si želite zapomniti ID za UPI?</translation>
<translation id="6124432979022149706">PrikljuÄki za Chrome za podjetja</translation>
<translation id="6127379762771434464">Element odstranjen</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Preberite veÄ o anonimnem naÄinu v Chromu<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">Preverite kable in znova zaženite usmerjevalnike, modeme ali druge omrežne
naprave, ki jih uporabljate.</translation>
<translation id="614940544461990577">Poskusite:</translation>
@@ -1622,7 +1662,6 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="6169916984152623906">Zdaj je mogoÄe brskati zasebno in drugi, ki uporabljajo to napravo, ne bodo videli vaÅ¡e dejavnosti. Prenosi in zaznamki bodo vseeno shranjeni.</translation>
<translation id="6177128806592000436">Povezava s tem spletnim mestom ni varna</translation>
<translation id="6180316780098470077">Interval vnoviÄnih poskusov</translation>
-<translation id="619448280891863779">Lahko zahteva odpiranje in postavite oken na zaslonih.</translation>
<translation id="6196640612572343990">Blokiraj piškotke drugih spletnih mest</translation>
<translation id="6203231073485539293">Preverite internetno povezavo</translation>
<translation id="6218753634732582820">Želite naslov odstraniti iz Chromiuma?</translation>
@@ -1645,7 +1684,7 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="6272383483618007430">Google Posodobitve</translation>
<translation id="6276112860590028508">Strani z bralnega seznama so prikazane tukaj</translation>
<translation id="627746635834430766">ÄŒe želite naslednjiÄ hitreje plaÄati, shranite kartico in naslov za izstavitev raÄuna v Google RaÄunu.</translation>
-<translation id="6279098320682980337">Å tevilka virtualne kartice ni izpolnjena? Kliknite podrobnosti kartice, Äe želite kopirati.</translation>
+<translation id="6279183038361895380">Pritisnite |<ph name="ACCELERATOR" />| za prikaz kazalca</translation>
<translation id="6280223929691119688">Dostava na ta naslov ni mogoÄa. Izberite drugega.</translation>
<translation id="6282194474023008486">Poštna številka</translation>
<translation id="6285507000506177184">Gumb za upravljanje prenosov v Chromu, pritisnite Enter, Äe želite upravljati datoteke, ki ste jih prenesli v Chromu.</translation>
@@ -1653,6 +1692,7 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="6290238015253830360">Tu so prikazani predlagani Älanki</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{Naprava se bo zdaj znova zagnala}=1{Naprava se bo znova zagnala Äez 1 sekundo}one{Naprava se bo znova zagnala Äez # sekundo}two{Naprava se bo znova zagnala Äez # sekundi}few{Naprava se bo znova zagnala Äez # sekunde}other{Naprava se bo znova zagnala Äez # sekund}}</translation>
<translation id="6302269476990306341">PomoÄnik Google v Chromu se ustavlja</translation>
<translation id="6305205051461490394">Naslov <ph name="URL" /> je nedosegljiv.</translation>
<translation id="6312113039770857350">Spletna stran ni na voljo</translation>
@@ -1726,6 +1766,7 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="6529602333819889595">&amp;Uveljavi izbris</translation>
<translation id="6545864417968258051">Iskanje naprav Bluetooth</translation>
<translation id="6547208576736763147">Dvojno luknjanje na levi</translation>
+<translation id="6554732001434021288">Nazadnje obiskano pred toliko dnevi: <ph name="NUM_DAYS" /></translation>
<translation id="6556866813142980365">Uveljavi</translation>
<translation id="6569060085658103619">Ogledujete si stran razširitve</translation>
<translation id="6573200754375280815">Dvojno luknjanje na desni</translation>
@@ -1786,7 +1827,6 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="6757797048963528358">Naprava je preklopila v stanje pripravljenosti.</translation>
<translation id="6767985426384634228">Želite posodobiti naslov?</translation>
<translation id="6768213884286397650">Hagaki (Postcard)</translation>
-<translation id="6774185088257932239"><ph name="BEGIN_LINK" />Preberite veÄ<ph name="END_LINK" /> o anonimnem naÄinu</translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">VijoliÄnomodra</translation>
<translation id="6786747875388722282">Razširitve</translation>
@@ -1870,7 +1910,6 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="706295145388601875">Dodajte in upravljajte naslove v Chromovih nastavitvah.</translation>
<translation id="7064851114919012435">Podatki o stiku</translation>
<translation id="7068733155164172741">Vnesite <ph name="OTP_LENGTH" />-mestno kodo</translation>
-<translation id="7070090581017165256">O tem spletnem mestu</translation>
<translation id="70705239631109039">Povezava ni v celoti varna</translation>
<translation id="7075452647191940183">Zahteva je prevelika</translation>
<translation id="7079718277001814089">To spletno mesto vsebuje zlonamerno programsko opremo</translation>
@@ -1887,6 +1926,12 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="7111012039238467737">(veljavno)</translation>
<translation id="7118618213916969306">Iskanje URL-ja v odložiÅ¡Äu, <ph name="SHORT_URL" /></translation>
<translation id="7119414471315195487">Zaprite druge zavihke ali programe</translation>
+<translation id="7129355289156517987">Ko v Chromiumu zaprete vse anonimne zavihke, se dejavnost na teh zavihkih izbriše iz te naprave:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />dejavnost brskanja;<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />zgodovina iskanja;<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />podatki, vneseni v obrazce.<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">PoÅ¡iljanje na ta naslov ni mogoÄe. Izberite drugega.</translation>
<translation id="7132939140423847331">Skrbnik je prepovedal kopiranje teh podatkov.</translation>
<translation id="7135130955892390533">Prikaz stanja</translation>
@@ -1909,6 +1954,7 @@ V nasprotnem primeru bodo to blokirale nastavitve zasebnosti. S tem bo vsebina,
<translation id="7192203810768312527">Sprosti <ph name="SIZE" />. Nekatera spletna mesta se bodo ob naslednjem obisku morda poÄasneje naložila.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">Skrbniku je prikazano to:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, pritisnite tabulatorko, nato Enter, Äe želite odpreti nov anonimni zavihek za zasebno brskanje</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423">Spletno mesto <ph name="HOST_NAME" /> ne upošteva varnostnih standardov.</translation>
<translation id="7210993021468939304">Dejavnost Linuxa v vsebniku in omogoÄeno nameÅ¡Äanje ter izvajanje aplikacij za Linux v vsebniku</translation>
@@ -1940,6 +1986,7 @@ Dodatne podrobnosti:
<translation id="7304562222803846232">Upravljanje nastavitev zasebnosti v raÄunu Google</translation>
<translation id="7305756307268530424">ZaÄni poÄasneje</translation>
<translation id="7308436126008021607">sinhronizacija v ozadju</translation>
+<translation id="7310392214323165548">Naprava se bo kmalu znova zagnala</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">PomoÄ pri povezavi</translation>
<translation id="7323804146520582233">Skrij razdelek »<ph name="SECTION" />«</translation>
@@ -1947,6 +1994,7 @@ Dodatne podrobnosti:
<translation id="7334320624316649418">&amp;Uveljavi razvrstitev</translation>
<translation id="7335157162773372339">Lahko zahteva uporabo fotoaparata.</translation>
<translation id="7337248890521463931">Pokaži veÄ vrstic</translation>
+<translation id="7337418456231055214">Å tevilka virtualne kartice ni izpolnjena? Kliknite podrobnosti kartice, Äe želite kopirati. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">Ni na voljo v vašem okolju.</translation>
<translation id="733923710415886693">Potrdilo strežnika ni bilo razkrito na podlagi pravilnika o preglednosti potrdila.</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1969,6 +2017,7 @@ Dodatne podrobnosti:
<translation id="7378627244592794276">Ne</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">Se ne uporablja</translation>
+<translation id="7388594495505979117">{0,plural, =1{Naprava se bo znova zagnala Äez 1 minuto}one{Naprava se bo znova zagnala Äez # minuto}two{Naprava se bo znova zagnala Äez # minuti}few{Naprava se bo znova zagnala Äez # minute}other{Naprava se bo znova zagnala Äez # minut}}</translation>
<translation id="7390545607259442187">Potrditev kartice</translation>
<translation id="7392089738299859607">Posodobitev naslova</translation>
<translation id="7399802613464275309">Varnostno preverjanje</translation>
@@ -2005,6 +2054,12 @@ Dodatne podrobnosti:
<translation id="7485870689360869515">Ni podatkov.</translation>
<translation id="7495528107193238112">Ta vsebina je blokirana. Obrnite se na lastnika spletnega mesta, da odpravi težavo.</translation>
<translation id="7497998058912824456">Gumb za ustvarjanje dokumenta, pritisnite Enter, Äe želite hitro ustvariti nov Google Dokument</translation>
+<translation id="7506488012654002225">Chromium <ph name="BEGIN_EMPHASIS" />ne shrani<ph name="END_EMPHASIS" /> teh podatkov:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />zgodovine brskanja,
+ <ph name="LIST_ITEM" />piškotkov in podatkov spletnih mest,
+ <ph name="LIST_ITEM" />podatkov, vnesenih v obrazce.
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">Vrnjen ID naprave pravilnika je prazen ali se ne ujema s trenutnim ID-jem naprave</translation>
<translation id="7508870219247277067">Avokadovo zelena</translation>
<translation id="7511955381719512146">Omrežje Wi-Fi, ki ga uporabljate, morda zahteva, da obiÅ¡Äete <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
@@ -2118,7 +2173,6 @@ Dodatne podrobnosti:
<translation id="7813600968533626083">Želite odstraniti predlog obrazca iz Chroma?</translation>
<translation id="781440967107097262">Želite odložiÅ¡Äe deliti z drugimi?</translation>
<translation id="7815407501681723534">Za »<ph name="SEARCH_STRING" />« je bilo najdenih toliko <ph name="SEARCH_RESULTS" />: <ph name="NUMBER_OF_RESULTS" />.</translation>
-<translation id="782125616001965242">Prikaz podatkov o tem spletnem mestu</translation>
<translation id="782886543891417279">Omrežje Wi-Fi, ki ga uporabljate (<ph name="WIFI_NAME" />), morda zahteva, da obiÅ¡Äete stran za prijavo.</translation>
<translation id="7836231406687464395">Postfix (Envelope)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{Brez}=1{1 aplikacija (<ph name="EXAMPLE_APP_1" />)}=2{2 aplikaciji (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}one{# aplikacija (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}two{# aplikaciji (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}few{# aplikacije (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}other{# aplikacij (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}}</translation>
@@ -2135,7 +2189,6 @@ Dodatne podrobnosti:
<translation id="7888575728750733395">Namen upodabljanja tiskanja</translation>
<translation id="7894280532028510793">ÄŒe je Ärkovanje pravilno, <ph name="BEGIN_LINK" />poskuÅ¡ajte zagnati orodje za omrežno diagnostiko<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (Envelope)</translation>
-<translation id="7931318309563332511">Neznano</translation>
<translation id="793209273132572360">Želite posodobiti naslov?</translation>
<translation id="7932579305932748336">Prevleka</translation>
<translation id="79338296614623784">Vnesite veljavno telefonsko Å¡tevilko</translation>
@@ -2160,13 +2213,14 @@ Dodatne podrobnosti:
<translation id="7976214039405368314">PreveÄ zahtev.</translation>
<translation id="7977538094055660992">Izhodna naprava</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">Povezano s/z</translation>
<translation id="798134797138789862">Lahko zahteva uporabo naprav in podatkov za navidezno resniÄnost.</translation>
<translation id="7984945080620862648">Spletnega mesta <ph name="SITE" /> trenutno ne morete obiskati, saj je poslalo Å¡ifrirane poverilnice, ki jih Chrome ne more obdelati. Napake omrežja in napadi na omrežje so obiÄajno zaÄasni, zato bo ta stran verjetno delovala pozneje.</translation>
-<translation id="79859296434321399">ÄŒe si želite ogledati vsebino v razÅ¡irjeni resniÄnosti, namestite ARCore</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">Vezava</translation>
<translation id="7992044431894087211">Deljenje zaslona z aplikacijo <ph name="APPLICATION_TITLE" /> se nadaljuje.</translation>
<translation id="7995512525968007366">Ni navedeno</translation>
+<translation id="7998269595945679889">Gumb za odpiranje anonimnega zavihka, pritisnite Enter, Äe želite odpreti nov anonimni zavihek za zasebno brskanje</translation>
<translation id="800218591365569300">Poskusite zapreti druge zavihke ali programe, da boste tako sprostili pomnilnik.</translation>
<translation id="8004582292198964060">Brskalnik</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{Shranjena bosta ta kartica in njen naslov za izstavitev raÄuna. Uporabljali jo boste lahko, ko boste prijavljeni v raÄun <ph name="USER_EMAIL" />.}one{Shranjene bodo te kartice in njihovi naslovi za izstavitev raÄuna. Uporabljali jih boste lahko, ko boste prijavljeni v raÄun <ph name="USER_EMAIL" />.}two{Shranjene bodo te kartice in njihovi naslovi za izstavitev raÄuna. Uporabljali jih boste lahko, ko boste prijavljeni v raÄun <ph name="USER_EMAIL" />.}few{Shranjene bodo te kartice in njihovi naslovi za izstavitev raÄuna. Uporabljali jih boste lahko, ko boste prijavljeni v raÄun <ph name="USER_EMAIL" />.}other{Shranjene bodo te kartice in njihovi naslovi za izstavitev raÄuna. Uporabljali jih boste lahko, ko boste prijavljeni v raÄun <ph name="USER_EMAIL" />.}}</translation>
@@ -2226,6 +2280,7 @@ Dodatne podrobnosti:
<translation id="8202370299023114387">Spor</translation>
<translation id="8206978196348664717">Prc4 (Envelope)</translation>
<translation id="8211406090763984747">Povezava je varna</translation>
+<translation id="8217240300496046857">Spletna mesta vam ne morejo slediti po spletu na podlagi piškotkov. Funkcije na nekaterih spletnih mestih morda ne bodo delovale.</translation>
<translation id="8218327578424803826">Dodeljena lokacija:</translation>
<translation id="8220146938470311105">C7/C6 (Envelope)</translation>
<translation id="8225771182978767009">Oseba, ki je nastavila ta raÄunalnik, je blokirala to spletno mesto.</translation>
@@ -2266,14 +2321,9 @@ Dodatne podrobnosti:
<translation id="830498451218851433">Prepogibanje na pol</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">NameÅ¡Äene aplikacije in pogostost njihove uporabe</translation>
+<translation id="8317207217658302555">Želite posodobiti ARCore?</translation>
<translation id="831997045666694187">VeÄer</translation>
<translation id="8321476692217554900">obvestila</translation>
-<translation id="8328484624016508118">Po zaprtju vseh anonimnih zavihkov Chrome poÄisti:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />vaše brskanje v tej napravi;<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />vašo zgodovino iskanja v tej napravi;<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />podatke, vnesene v obrazce.<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489">Dostop do spletnega mesta <ph name="HOST_NAME" /> je bil zavrnjen</translation>
<translation id="833262891116910667">OznaÄevanje</translation>
<translation id="8339163506404995330">Strani v jeziku <ph name="LANGUAGE" /> ne bodo prevedene</translation>
@@ -2325,6 +2375,7 @@ Dodatne podrobnosti:
<translation id="8507227106804027148">Ukazna vrstica</translation>
<translation id="8508648098325802031">Ikona za iskanje</translation>
<translation id="8511402995811232419">Upravljanje piškotkov</translation>
+<translation id="8519753333133776369">Naprava HID, ki jo je dovolil skrbnik</translation>
<translation id="8522552481199248698">Chrome vam lahko pomaga zaÅ¡Äititi raÄun za Google in spremeniti geslo.</translation>
<translation id="8530813470445476232">PoÄistite zgodovino brskanja, piÅ¡kotke, predpomnilnik in drugo v nastavitvah v Chromu</translation>
<translation id="8533619373899488139">Na &lt;strong&gt;chrome://policy&lt;/strong&gt; si lahko ogledate seznam blokiranih URL-jev in drugih pravilnikov, ki jih uveljavlja skrbnik sistema.</translation>
@@ -2336,7 +2387,6 @@ Dodatne podrobnosti:
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{Ponastavi dovoljenje}one{Ponastavi dovoljenja}two{Ponastavi dovoljenja}few{Ponastavi dovoljenja}other{Ponastavi dovoljenja}}</translation>
<translation id="8555010941760982128">Na blagajni uporabite to kodo</translation>
<translation id="8557066899867184262">CVC je na zadnji strani kartice.</translation>
-<translation id="8558485628462305855">ÄŒe si želite ogledati vsebino v razÅ¡irjeni resniÄnosti, posodobite ARCore</translation>
<translation id="8559762987265718583">Zasebne povezave z domeno <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> ni mogoÄe vzpostaviti, ker sta datum in ura (<ph name="DATE_AND_TIME" />) v napravi nepravilna.</translation>
<translation id="8564182942834072828">LoÄeni dokumenti/nezbrane kopije</translation>
<translation id="8564985650692024650">Chromium priporoÄa, da ponastavite geslo za <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" />, Äe ste ga uporabljali tudi na drugih spletnih mestih.</translation>
@@ -2355,6 +2405,7 @@ Dodatne podrobnosti:
<translation id="865032292777205197">tipala gibanja</translation>
<translation id="8663226718884576429">Povzetek naroÄila, <ph name="TOTAL_LABEL" />, veÄ podrobnosti</translation>
<translation id="8666678546361132282">angleÅ¡Äina</translation>
+<translation id="8669306706049782872">uporabiti podatke o zaslonih za odpiranje in postavitev oken</translation>
<translation id="867224526087042813">Podpis</translation>
<translation id="8676424191133491403">Brez zakasnitve</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, odgovor, <ph name="ANSWER" /></translation>
@@ -2381,6 +2432,7 @@ Dodatne podrobnosti:
<translation id="8731544501227493793">Gumb za upravljanje gesel, pritisnite Enter, Äe si želite ogledati in upravljati gesla v Chromovih nastavitvah</translation>
<translation id="8734529307927223492">Vašo napravo <ph name="DEVICE_TYPE" /> upravlja domena <ph name="MANAGER" /></translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, pritisnite tabulatorko, nato Enter, Äe želite odpreti novo anonimno okno za zasebno brskanje</translation>
+<translation id="8737685506611670901">Odpiranje povezav za <ph name="PROTOCOL" /> namesto <ph name="REPLACED_HANDLER_TITLE" /></translation>
<translation id="8738058698779197622">ÄŒe želite vzpostaviti varno povezavo, mora biti ura pravilno nastavljena. Potrdila, ki jih uporabljajo spletna mesta za prepoznavanje, namreÄ veljajo samo doloÄen Äas. Ker je ura sistema nepravilna, Chromium teh potrdil ne more preveriti.</translation>
<translation id="8740359287975076522">&lt;abbr id="dnsDefinition"&gt;Naslova DNS&lt;/abbr&gt; spletnega mesta <ph name="HOST_NAME" /> ni bilo mogoÄe najti. Poteka diagnosticiranje težave.</translation>
<translation id="8742371904523228557"><ph name="ONE_TIME_CODE" /> je vaša koda za <ph name="ORIGIN" /></translation>
@@ -2408,6 +2460,7 @@ Dodatne podrobnosti:
<translation id="883848425547221593">Drugi zaznamki</translation>
<translation id="884264119367021077">Naslov za pošiljanje</translation>
<translation id="884923133447025588">Najden ni bil noben mehanizem za preklic.</translation>
+<translation id="8849262850971482943">Uporabite navidezno kartico za veÄjo varnost.</translation>
<translation id="885730110891505394">Deljenje z Googlom</translation>
<translation id="8858065207712248076">Chrome priporoÄa, da ponastavite geslo za <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" />, Äe ste ga uporabljali na drugih spletnih mestih.</translation>
<translation id="885906927438988819">ÄŒe je Ärkovanje pravilno, <ph name="BEGIN_LINK" />poskuÅ¡ajte zagnati orodje za omrežno diagnostiko sistema Windows<ph name="END_LINK" />.</translation>
@@ -2457,6 +2510,7 @@ Dodatne podrobnosti:
<translation id="9004367719664099443">Seja VR je v teku</translation>
<translation id="9005998258318286617">Dokumenta PDF ni bilo mogoÄe naložiti.</translation>
<translation id="9008201768610948239">Prezri</translation>
+<translation id="901834265349196618">e-pošta</translation>
<translation id="9020200922353704812">Naslov kreditne kartice za raÄune je obvezen</translation>
<translation id="9020542370529661692">Ta stran je prevedena v jezik <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9020742383383852663">A8</translation>
@@ -2505,6 +2559,7 @@ Dodatne podrobnosti:
<translation id="9150045010208374699">Uporabite kamero</translation>
<translation id="9150685862434908345">Skrbnik lahko spremeni nastavitev brskalnika na daljavo. Dejavnost v tej napravi morda tudi upravljajo zunaj Chroma. <ph name="BEGIN_LINK" />VeÄ o tem<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">Posodobljeno</translation>
+<translation id="9155211586651734179">PrikljuÄena zvoÄna dodatna oprema</translation>
<translation id="9157595877708044936">Nastavljanje ...</translation>
<translation id="9158625974267017556">C6 (Envelope)</translation>
<translation id="9164029392738894042">Preverjanje natanÄnosti</translation>
diff --git a/chromium/components/strings/components_strings_sq.xtb b/chromium/components/strings/components_strings_sq.xtb
index bf8e2f3c185..b51e06c43dd 100644
--- a/chromium/components/strings/components_strings_sq.xtb
+++ b/chromium/components/strings/components_strings_sq.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">Shiko detajet</translation>
<translation id="1030706264415084469"><ph name="URL" /> do të ruajë në mënyrë të përhershme të dhëna të mëdha në pajisjen tënde</translation>
<translation id="1032854598605920125">Rrotullo në drejtim të akrepave të orës</translation>
+<translation id="1033329911862281889">Modaliteti "I fshehtë" nuk të bën të padukshëm në linjë:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Sajtet dhe shërbimet që ato përdorin mund të shohin vizitat<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Punëdhënësit ose shkollat mund të monitorojnë aktivitetin e shfletimit<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Ofruesit e shërbimit të internetit mund të monitorojnë trafikun e uebit<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">Çaktivizo</translation>
<translation id="1036982837258183574">Shtyp |<ph name="ACCELERATOR" />| për të dalë nga ekrani i plotë</translation>
<translation id="1038106730571050514">Shfaq sugjerimet</translation>
<translation id="1038842779957582377">emër i panjohur</translation>
<translation id="1041998700806130099">Mesazhi i fletës së punës</translation>
<translation id="1048785276086539861">Kur redakton shënimet, ky dokument do të kthehet te pamja me një faqe</translation>
-<translation id="1049743911850919806">I fshehtë</translation>
<translation id="1050038467049342496">Mbyll aplikacionet e tjera</translation>
<translation id="1055184225775184556">&amp;Zhbëj shtimin</translation>
<translation id="1056898198331236512">Paralajmërim</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">Memoria specifike e politikës është në rregull</translation>
<translation id="1130564665089811311">Butoni "Përkthe faqen", shtyp "Enter" për ta përkthyer këtë faqe me "Përkthe me Google"</translation>
<translation id="1131264053432022307">Imazhi që kopjove</translation>
+<translation id="1142846828089312304">Blloko kukit e palëve të treta në modalitetin "I fshehtë"</translation>
<translation id="1150979032973867961">Ky server nuk mundi të dëshmonte se ky është <ph name="DOMAIN" />; certifikata e tij e sigurisë nuk është e besueshme nga sistemi operativ i kompjuterit. Kjo mund të shkaktohet nga keqkonfigurimi ose ndonjë sulmues që po ndërhyn në lidhjen tënde.</translation>
<translation id="1151972924205500581">Kërkohet fjalëkalimi</translation>
<translation id="1156303062776767266">Po shikon një skedar lokal ose të ndarë</translation>
@@ -64,7 +70,6 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="1178581264944972037">Pauzë</translation>
<translation id="1181037720776840403">Hiq</translation>
<translation id="1186201132766001848">Kontrollo fjalëkalimet</translation>
-<translation id="1195210374336998651">Shko te cilësimet e aplikacionit</translation>
<translation id="1195558154361252544">Njoftimet janë bllokuar automatikisht për të gjitha sajtet përveçse për ato që lejon ti</translation>
<translation id="1197088940767939838">Portokalli</translation>
<translation id="1201402288615127009">Para</translation>
@@ -111,7 +116,7 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="1307966114820526988">Veçori të vjetruara</translation>
<translation id="1308113895091915999">Ofertë e disponueshme</translation>
<translation id="1312803275555673949">Çfarë prove e mbështet?</translation>
-<translation id="131405271941274527"><ph name="URL" /> dëshiron që të dërgojë dhe të marrë informacion kur troket te telefoni në një pajisje me NFC</translation>
+<translation id="1314311879718644478">Shiko përmbajtjen e realitetit të zgjeruar</translation>
<translation id="1314509827145471431">Lidhje djathtas</translation>
<translation id="1318023360584041678">Ruajtur në grupin e skedave</translation>
<translation id="1319245136674974084">Mos pyet përsëri për këtë aplikacion</translation>
@@ -161,6 +166,7 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="142858679511221695">Përdorues në renë kompjuterike</translation>
<translation id="1428729058023778569">Je duke e parë këtë paralajmërim pasi kjo faqe nuk mbështet HTTPS. <ph name="BEGIN_LEARN_MORE_LINK" />Mëso më shumë<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">Printo</translation>
+<translation id="1432187715652018471">faqja kërkon të instalojë një përpunues të shërbimit.</translation>
<translation id="1432581352905426595">Menaxho motorët e kërkimit</translation>
<translation id="1436185428532214179">Mund të kërkojë të modifikojë skedarët ose dosjet në pajisjen tënde</translation>
<translation id="1442386063175183758">Palosje me dritare djathtas</translation>
@@ -181,6 +187,12 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="1483493594462132177">Dërgo</translation>
<translation id="1484290072879560759">Zgjidh adresën e dërgimit</translation>
<translation id="1492194039220927094">Politikat e detyruara:</translation>
+<translation id="149293076951187737">Kur mbyll të gjitha skedat "e fshehta" në Chrome, aktiviteti yt në këto skeda fshihet nga kjo pajisje:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Aktiviteti i shfletimit<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Historiku i kërkimeve<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Informacionet e futura në formularë<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">Kthehu te skeda</translation>
<translation id="1501859676467574491">Shfaq kartat nga "Llogaria jote e Google"</translation>
<translation id="1507202001669085618">&lt;p&gt;Do të shikosh këtë gabim nëse përdor një portal Wi-Fi ku duhet të identifikohesh përpara se të hysh në linjë.&lt;/p&gt;
@@ -208,6 +220,8 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="1559572115229829303">&lt;p&gt;Nuk mund të vendoset një lidhje private me <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />, sepse data dhe ora (<ph name="DATE_AND_TIME" />) e kompjuterit tënd nuk janë të sakta.&lt;/p&gt;
&lt;p&gt;Rregullo datën dhe orën nga seksioni &lt;strong&gt;Të përgjithshme&lt;/strong&gt; i aplikacionit &lt;strong&gt;Cilësimet&lt;/strong&gt;.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">Administratori yt do ta rinisë pajisjen në orën <ph name="TIME" /> më <ph name="DATE" /></translation>
+<translation id="156703335097561114">Informacioni i rrjetit, si p.sh. adresat, konfigurimi i ndërfaqes dhe cilësia e lidhjes</translation>
<translation id="1567040042588613346">Kjo politikë funksionon sipas parashikimit, por diku është caktuar e njëjta vlerë dhe ajo është zëvendësuar nga kjo politikë.</translation>
<translation id="1569487616857761740">Fut datën e skadimit</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="1583429793053364125">Shkoi diçka keq kur po shfaqej faqja e uebit.</translation>
<translation id="1586541204584340881">Cilat shtesa ke instaluar</translation>
<translation id="1588438908519853928">Normal</translation>
+<translation id="1589050138437146318">Të instalohet ARCore?</translation>
<translation id="1592005682883173041">Qasja te të dhënat lokale</translation>
<translation id="1594030484168838125">Zgjidh</translation>
<translation id="160851722280695521">Luaj lojën Dino Run në Chrome</translation>
@@ -254,7 +269,7 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="1711234383449478798">U shpërfill sepse <ph name="POLICY_NAME" /> nuk është caktuar si "<ph name="VALUE" />".</translation>
<translation id="1712552549805331520"><ph name="URL" /> kërkon të ruajë të dhëna në mënyrë të përhershme në kompjuterin tënd lokal</translation>
<translation id="1713628304598226412">Tabakaja 2</translation>
-<translation id="1715874602234207">F</translation>
+<translation id="1715874602234207">P</translation>
<translation id="1717218214683051432">Sensorët e lëvizjes</translation>
<translation id="1717494416764505390">Kutia postare 3</translation>
<translation id="1718029547804390981">Dokumenti është shumë i madh për t'u shënuar</translation>
@@ -282,6 +297,7 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
që kërkon që të aplikohet një politikë origjine për të gjitha kërkesat drejtuar atij. Por
titulli është formuar gabimisht, gjë që e parandalon përmbushjen e
kërkesës sate për <ph name="SITE" />. Politikat e origjinës mund të përdoren nga operatorët e sajtit për të konfiguruar karakteristikat e sigurisë dhe karakteristika të tjera për një sajt.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Mëso më shumë për modalitetin "I fshehtë" në Chromium<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">Skedat e tua të hapura shfaqen këtu</translation>
<translation id="1791429645902722292">Smart Lock-u i Google</translation>
@@ -409,6 +425,7 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="22081806969704220">Tabakaja 3</translation>
<translation id="2212735316055980242">Politika nuk u gjet</translation>
<translation id="2213606439339815911">Po merr hyrjet...</translation>
+<translation id="2213612003795704869">Faqja u printua</translation>
<translation id="2215727959747642672">Modifikimi i skedarëve</translation>
<translation id="2218879909401188352">Sulmuesit aktualisht në <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> mund të instalojnë aplikacione të rrezikshme që e dëmtojnë pajisjen tënde, shtojnë tarifa të fshehura në faturën tënde të celularit ose vjedhin informacionet e tua personale. <ph name="BEGIN_LEARN_MORE_LINK" />Mëso më shumë<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">Nuk ka internet</translation>
@@ -418,6 +435,7 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="2248949050832152960">Përdor WebAuthn</translation>
<translation id="2250931979407627383">Qepje anësore majtas</translation>
<translation id="225207911366869382">Kjo vlerë është tërhequr për këtë politikë.</translation>
+<translation id="2256115617011615191">Rinise tani</translation>
<translation id="2258928405015593961">Fut një datë skadimi në të ardhmen dhe provo përsëri</translation>
<translation id="225943865679747347">Kodi i gabimit: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">Gabim në HTTP</translation>
@@ -445,6 +463,7 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="2337852623177822836">Cilësim i kontrolluar nga administratori yt</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> dëshiron të çiftohet</translation>
<translation id="2346319942568447007">Imazhi që kopjove</translation>
+<translation id="2350796302381711542">Të lejohet <ph name="HANDLER_HOSTNAME" /> të hapë të gjitha lidhjet <ph name="PROTOCOL" /> në vend të <ph name="REPLACED_HANDLER_TITLE" />?</translation>
<translation id="2354001756790975382">Faqeshënues të tjerë</translation>
<translation id="2354430244986887761">"Shfletimi i sigurt i Google" zbuloi së fundi <ph name="BEGIN_LINK" />aplikacione të dëmshme<ph name="END_LINK" /> në <ph name="SITE" />.</translation>
<translation id="2355395290879513365">Sulmuesit mund të arrijnë t'i shikojnë imazhet që po shikon në këtë sajt dhe të të mashtrojnë duke i modifikuar ato.</translation>
@@ -470,6 +489,7 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="2413528052993050574">Ky server nuk mund të dëshmonte se është <ph name="DOMAIN" />; certifikata e tij e sigurisë mund të jetë e revokuar. Kjo mund të shkaktohet nga një konfigurim i pasaktë ose nga ndërhyrja e një sulmuesi në lidhjen tënde.</translation>
<translation id="2414886740292270097">E errët</translation>
<translation id="2430968933669123598">Menaxho "Llogarinë e Google", shtyp Enter për të menaxhuar informacionin, privatësinë dhe sigurinë tënde në "Llogarinë tënde të Google"</translation>
+<translation id="2436186046335138073">Të lejohet <ph name="HANDLER_HOSTNAME" /> të hapë të gjitha lidhjet <ph name="PROTOCOL" />?</translation>
<translation id="2438874542388153331">Katër shpime djathtas</translation>
<translation id="2450021089947420533">Udhëtimet</translation>
<translation id="2463739503403862330">Plotëso</translation>
@@ -477,6 +497,7 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="2465655957518002998">Zgjidh mënyrën e dorëzimit</translation>
<translation id="2465688316154986572">Kapje me tel</translation>
<translation id="2465914000209955735">Menaxho skedarët që ke shkarkuar në Chrome</translation>
+<translation id="2466004615675155314">Shfaq informacione nga uebi</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Po ekzekuton diagnostikimin e rrjetit<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">Renditja 1 deri në N</translation>
<translation id="2470767536994572628">Kur redakton shënimet, ky dokument do të kthehet te pamja me një faqe dhe te rrotullimi fillestar</translation>
@@ -497,6 +518,7 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="2523886232349826891">Ruajtur vetëm në këtë pajisje</translation>
<translation id="2524461107774643265">Shto më shumë informacion</translation>
<translation id="2529899080962247600">Kjo fushë nuk duhet të ketë më shumë se <ph name="MAX_ITEMS_LIMIT" /> regjistrime. Të gjitha hyrjet e mëtejshme do të shpërfillen.</translation>
+<translation id="2535585790302968248">Hap një skedë të re "të fshehtë" për të shfletuar në mënyrë private</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{dhe 1 tjetër}other{dhe # të tjera}}</translation>
<translation id="2536110899380797252">Shto adresë</translation>
<translation id="2539524384386349900">Zbulo</translation>
@@ -522,7 +544,14 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="2597378329261239068">Ky dokument mbrohet me fjalëkalim. Fut një fjalëkalim.</translation>
<translation id="2609632851001447353">Variantet</translation>
<translation id="2610561535971892504">Kliko për të kopjuar</translation>
+<translation id="2617988307566202237">Chrome <ph name="BEGIN_EMPHASIS" />nuk do të ruajë<ph name="END_EMPHASIS" /> informacionet e mëposhtme:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Historikun tënd të shfletimit
+ <ph name="LIST_ITEM" />Kukit dhe të dhënat e sajteve
+ <ph name="LIST_ITEM" />Informacionet e futura në formularë
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (Zarf)</translation>
+<translation id="2623663032199728144">Mund të kërkojë të përdorë informacione rreth ekraneve të tua</translation>
<translation id="2625385379895617796">Ora jote është përpara</translation>
<translation id="262745152991669301">Mund të kërkojë të lidhet me pajisjet me USB</translation>
<translation id="2629325967560697240">Për të marrë nivelin më të lartë të sigurisë së Chrome, <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />aktivizo mbrojtjen e përmirësuar<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -556,6 +585,7 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="2709516037105925701">Plotëso automatikisht</translation>
<translation id="2713444072780614174">E bardhë</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />, shtyp "Tab", më pas "Enter" për të menaxhuar informacionet e pagesave dhe të kartës së kreditit te cilësimet e Chrome</translation>
+<translation id="271663710482723385">Shtyp |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| për të dalë nga ekrani i plotë</translation>
<translation id="2721148159707890343">Kërkesa pati sukses</translation>
<translation id="2723669454293168317">Ekzekuto një kontroll sigurie te cilësimet e Chrome</translation>
<translation id="2726001110728089263">Tabakaja rrëshqitëse</translation>
@@ -586,6 +616,7 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="2850739647070081192">Invite (Zarf)</translation>
<translation id="2856444702002559011">Sulmuesit mund të përpiqen të vjedhin informacionet e tua nga <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (për shembull, fjalëkalimet, mesazhet ose kartat e kreditit). <ph name="BEGIN_LEARN_MORE_LINK" />Mëso më shumë<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">Ky sajt shfaq reklama ndërhyrëse ose mashtruese.</translation>
+<translation id="286512204874376891">Një kartë virtuale fsheh kartën tënde reale për të të mbrojtur nga mashtrimi i mundshëm.<ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">Miqësor</translation>
<translation id="2876489322757410363">Po del nga modaliteti "i fshehtë" për të paguar nëpërmjet një aplikacioni të jashtëm. Të vazhdohet?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />. Shtyp "Tab" dhe më pas "Enter" për të menaxhuar "Shfletimin e sigurt" dhe më shumë te cilësimet e Chrome</translation>
@@ -610,6 +641,7 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="2930577230479659665">Prerje pas çdo kopjeje</translation>
<translation id="2932085390869194046">Sugjero një fjalëkalim...</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019">Hap lidhjet e <ph name="PROTOCOL" /></translation>
<translation id="2941952326391522266">Ky server nuk mund të dëshmonte se është <ph name="DOMAIN" />; certifikata e tij e sigurisë është nga <ph name="DOMAIN2" />. Kjo mund të shkaktohet nga një konfigurim i pasaktë ose nga ndërhyrja e një sulmuesi në lidhjen tënde.</translation>
<translation id="2943895734390379394">Koha e ngarkimit:</translation>
<translation id="2948083400971632585">Mund të çaktivizosh çdo përfaqësues të konfiguruar për një lidhje nga faqja e cilësimeve.</translation>
@@ -642,6 +674,7 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="3037605927509011580">Ndërprerje aksidentale!</translation>
<translation id="3041612393474885105">Informacioni i certifikatës</translation>
<translation id="3044034790304486808">Vazhdo kërkimin</translation>
+<translation id="305162504811187366">Historiku i "Desktopit në distancë të Chrome", duke përfshirë vulat kohore, organizatorët dhe ID-të e seancës së klientit.</translation>
<translation id="3060227939791841287">C9 (Zarf)</translation>
<translation id="3061707000357573562">Shërbimi i korrigjimit</translation>
<translation id="306573536155379004">Loja filloi.</translation>
@@ -682,6 +715,7 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="3197136577151645743">Mund të kërkojë të dijë kur e përdor pajisjen tënde në mënyrë aktive</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />. Shtyp "Tab" dhe më pas "Enter" për të menaxhuar se çfarë informacionesh sinkronizon ti te cilësimet e Chrome</translation>
<translation id="320323717674993345">Anulo pagesën</translation>
+<translation id="3203366800380907218">Nga uebi</translation>
<translation id="3207960819495026254">Regjistruar në faqeshënues</translation>
<translation id="3209034400446768650">Faqja mund të tarifojë para</translation>
<translation id="3212581601480735796">Aktiviteti yt në <ph name="HOSTNAME" /> po monitorohet</translation>
@@ -698,10 +732,12 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="3234666976984236645">Zbulo gjithmonë përmbajtje të rëndësishme në këtë sajt</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />. Shtyp "Tab" dhe më pas "Enter" për të personalizuar pamjen e shfletuesit tënd</translation>
<translation id="3240791268468473923">Kredenciali i pagesës së sigurt pa fletë përkatëse kredenciali është i hapur</translation>
+<translation id="324180406144491771">Lidhjet e "<ph name="HOST_NAME" />" janë bllokuar</translation>
<translation id="3249845759089040423">Moderne</translation>
<translation id="3252266817569339921">Frëngjisht</translation>
<translation id="3257954757204451555">Kush qëndron pas këtij informacioni?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />, shtyp Tab pastaj Enter për të krijuar shpejt një ngjarje të re në "Google Calendar"</translation>
+<translation id="3261488570342242926">Mëso rreth kartave virtuale</translation>
<translation id="3264837738038045344">Butoni "Menaxho cilësimet e Chrome". Shtyp "Enter" për të vizituar cilësimet e Chrome</translation>
<translation id="3266793032086590337">Vlera (konflikt)</translation>
<translation id="3268451620468152448">Hap skedat</translation>
@@ -715,6 +751,7 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="3288238092761586174"><ph name="URL" /> mund të duhet të marrë hapa të mëtejshëm për të verifikuar pagesën tënde</translation>
<translation id="3293642807462928945">Mëso më shumë për politikën <ph name="POLICY_NAME" /></translation>
<translation id="3295444047715739395">Shiko dhe menaxho fjalëkalimet e tua te cilësimet e Chrome</translation>
+<translation id="3303795387212510132">Të lejohet aplikacioni të hapë lidhje <ph name="PROTOCOL_SCHEME" />?</translation>
<translation id="3303855915957856445">Nuk u gjetën rezultate kërkimi</translation>
<translation id="3304073249511302126">Skanimi i Bluetooth-it</translation>
<translation id="3308006649705061278">Njësia organizative (OU)</translation>
@@ -728,12 +765,6 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="3345782426586609320">Sy</translation>
<translation id="3355823806454867987">Ndrysho cilësimet e përfaqësuesit...</translation>
<translation id="3360103848165129075">Fleta e përpunuesit të pagesës</translation>
-<translation id="3361596688432910856">Chrome <ph name="BEGIN_EMPHASIS" />nuk do të ruajë<ph name="END_EMPHASIS" /> informacionet e mëposhtme:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Historikun tënd të shfletimit
- <ph name="LIST_ITEM" />Kukit dhe të dhënat e sajteve
- <ph name="LIST_ITEM" />Informacionet e futura në formularë
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">Kjo politikë është kopjuar automatikisht nga politika e vjetruar <ph name="OLD_POLICY" />. Duhet të përdorësh këtë politikë më mirë.</translation>
<translation id="3364869320075768271"><ph name="URL" /> kërkon të përdorë pajisjen dhe të dhënat e tua të realitetit virtual</translation>
<translation id="3366477098757335611">Shiko kartat</translation>
@@ -816,7 +847,6 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="3587738293690942763">Mesatar</translation>
<translation id="3592413004129370115">Italian (Zarf)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{Mund ta rivendosësh grupin tënd në çdo kohë. Duhet rreth një ditë për t'u bashkuar në një grup të ri.}=1{Mund ta rivendosësh grupin tënd në çdo kohë. Duhet rreth një ditë për t'u bashkuar në një grup të ri.}other{Mund ta rivendosësh grupin tënd në çdo kohë. Duhen {NUM_DAYS} ditë për t'u bashkuar në një grup të ri.}}</translation>
-<translation id="3596012367874587041">Cilësimet e aplikacionit</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">Aplikacioni u bllokua nga administratori yt</translation>
<translation id="3608932978122581043">Orientimi i furnizimit</translation>
@@ -859,6 +889,7 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="370972442370243704">Aktivizo "Udhëtimet"</translation>
<translation id="3711895659073496551">Pezullo</translation>
<translation id="3712624925041724820">Licencat janë shfrytëzuar</translation>
+<translation id="3714633008798122362">kalendari në ueb</translation>
<translation id="3714780639079136834">Të aktivizosh të dhënat celulare ose Wi-Fi</translation>
<translation id="3715597595485130451">Lidhu me Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Të kontrollosh përfaqësuesin, murin mbrojtës dhe konfigurimin e DNS-së<ph name="END_LINK" /></translation>
@@ -920,6 +951,7 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="3906954721959377182">Tablet</translation>
<translation id="3909477809443608991"><ph name="URL" /> dëshiron të luajë përmbajtjen e mbrojtur. Identiteti i pajisjes sate do të verifikohet nga Google dhe mund të qaset nga ky sajt.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">Refuzo</translation>
<translation id="3939773374150895049">Të përdoret WebAuthn në vend të CVC?</translation>
<translation id="3946209740501886391">Gjithmonë pyet në këtë faqe</translation>
<translation id="3947595700203588284">Mund të kërkojë të lidhet me pajisjet MIDI</translation>
@@ -941,6 +973,7 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="3990250421422698716">Zhvendosja e bordurës</translation>
<translation id="3996311196211510766">Sajti <ph name="ORIGIN" /> ka kërkuar që të zbatohet një politikë e origjinës
për të gjitha kërkesat drejtuar atij, por kjo politikë nuk mund të zbatohet aktualisht.</translation>
+<translation id="4009243425692662128">Përmbajtja e faqeve që printon i dërgohet "Resë kompjuterike të Google" ose palëve të treta për analizë. Për shembull, mund të skanohet për të dhëna delikate.</translation>
<translation id="4010758435855888356">Të lejohet qasja te hapësira ruajtëse?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{Dokumenti PDF me {COUNT} faqe}other{Dokumenti PDF me {COUNT} faqe}}</translation>
<translation id="4023431997072828269">Për shkak se ky formular po dërgohet duke përdorur një lidhje që nuk është e sigurt, informacionet e tua do të jenë të dukshme për të tjerët.</translation>
@@ -1033,6 +1066,7 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="4250680216510889253">Jo</translation>
<translation id="4253168017788158739">Shënim</translation>
<translation id="425582637250725228">Ndryshimet që ke bërë mund të mos ruhen.</translation>
+<translation id="425869179292622354">Të bëhet më e sigurt me një kartë virtuale?</translation>
<translation id="4258748452823770588">Nënshkrim i gabuar</translation>
<translation id="4261046003697461417">Dokumentet e mbrojtura nuk mund të shënohen</translation>
<translation id="4265872034478892965">Lejuar nga administratori yt</translation>
@@ -1095,6 +1129,7 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="4434045419905280838">Dritaret kërcyese dhe ridrejtimet</translation>
<translation id="4435702339979719576">Postcard)</translation>
<translation id="443673843213245140">Përdorimi i një përfaqësuesi është i çaktivizuar, por është specifikuar një konfigurim i qartë përfaqësuesi.</translation>
+<translation id="4441832193888514600">Shpërfillur për shkak se politika mund të shtohet vetëm si politikë e përdoruesit të resë kompjuterike.</translation>
<translation id="4450893287417543264">Mos e shfaq përsëri</translation>
<translation id="4451135742916150903">Mund të kërkojë të lidhet me pajisjet HID</translation>
<translation id="4452328064229197696">Fjalëkalimi që sapo përdore u gjet në një nxjerrje të paautorizuar të të dhënave. Për të mbrojtur llogaritë e tua, "Menaxheri i fjalëkalimeve" i Google rekomandon të kontrollosh fjalëkalimet e ruajtura.</translation>
@@ -1150,6 +1185,7 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="4628948037717959914">Fotografia</translation>
<translation id="4631649115723685955">Oferta e kthimit të parave është e lidhur</translation>
<translation id="4636930964841734540">Informacion</translation>
+<translation id="4638670630777875591">Modaliteti "I fshehtë" në Chromium</translation>
<translation id="464342062220857295">Veçoritë e kërkimit</translation>
<translation id="4644670975240021822">Renditja e kundërt e kthyer poshtë</translation>
<translation id="4646534391647090355">Më ço atje tani</translation>
@@ -1170,6 +1206,7 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="4708268264240856090">Lidhja jote u ndërpre</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Po ekzekuton diagnostikimin e rrjetit të Windows<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426">Fjalëkalimi për <ph name="USERNAME" /></translation>
<translation id="4724144314178270921">Mund të kërkojë të shikojë tekstin dhe imazhet në kujtesën e fragmenteve</translation>
<translation id="4726672564094551039">Ringarko politikat</translation>
<translation id="4728558894243024398">Platforma</translation>
@@ -1191,6 +1228,7 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="4757993714154412917">Sapo e fute fjalëkalimin tënd në një sajt mashtrues. Për të siguruar llogaritë e tua, Chromium rekomandon të kontrollosh fjalëkalimet e ruajtura.</translation>
<translation id="4758311279753947758">Shto informacionet e kontaktit</translation>
<translation id="4761104368405085019">Përdor mikrofonin</translation>
+<translation id="4761869838909035636">Ekzekuto "Kontrollin e sigurisë" të Chrome</translation>
<translation id="4764776831041365478">Faqja e internetit në <ph name="URL" /> mund të mos ofrohet përkohësisht ose është zhvendosur përgjithmonë në një adresë të re interneti.</translation>
<translation id="4766713847338118463">Dy kapje me tel në fund</translation>
<translation id="4771973620359291008">Ka ndodhur një gabim i panjohur.</translation>
@@ -1211,12 +1249,6 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="4819347708020428563">Të redaktohen shënimet në pamjen e parazgjedhur?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />, shtyp Tab pastaj Enter për të krijuar shpejt një "Fletë të re të Google</translation>
<translation id="4825507807291741242">I fuqishëm</translation>
-<translation id="4827402517081186284">Modaliteti "I fshehtë" nuk të bën të padukshëm në linjë:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Sajtet e dinë kur i viziton ato<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Punëdhënësit ose shkollat mund të monitorojnë aktivitetin e shfletimit<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Ofruesit e shërbimit të internetit mund të monitorojnë trafikun e uebit<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">Aktivizo paralajmërimet</translation>
<translation id="4838327282952368871">Si në ëndërr</translation>
<translation id="4840250757394056958">Shiko historikun tënd të Chrome</translation>
@@ -1228,12 +1260,12 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="4854362297993841467">Kjo mënyrë dorëzimi nuk ofrohet. Provo një mënyrë tjetër.</translation>
<translation id="4854853140771946034">Krijo shpejt një shënim të ri në Google Keep</translation>
<translation id="485902285759009870">Po verifikon kodin...</translation>
+<translation id="4866506163384898554">Shtyp |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| për të shfaqur kursorin</translation>
<translation id="4876188919622883022">Pamja e thjeshtuar</translation>
<translation id="4876305945144899064">Nuk ka emër përdoruesi</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{Asnjë}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831">Kërko për <ph name="TEXT" /></translation>
<translation id="4879491255372875719">Automatike (e parazgjedhur)</translation>
-<translation id="4879725228911483934">Hap dhe vendos dritare në ekranet e tua</translation>
<translation id="4880827082731008257">Historiku i kërkimeve</translation>
<translation id="4881695831933465202">Hap</translation>
<translation id="4885256590493466218">Paguaj me <ph name="CARD_DETAIL" /> në përfundim të blerjes</translation>
@@ -1242,6 +1274,7 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">Ruli i nëntë</translation>
<translation id="4901778704868714008">Ruaj...</translation>
+<translation id="4905659621780993806">Administratori yt do ta rinisë pajisjen automatikisht në orën <ph name="TIME" /> më <ph name="DATE" />. Ruaj çdo artikull të hapur përpara se pajisja të riniset.</translation>
<translation id="4913987521957242411">Shpim lart majtas</translation>
<translation id="4918221908152712722">Instalo <ph name="APP_NAME" /> (nuk nevojitet shkarkim)</translation>
<translation id="4923459931733593730">Pagesa</translation>
@@ -1250,6 +1283,7 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, shtyp "Tab", më pas "Enter" për të kërkuar</translation>
<translation id="4930153903256238152">Kapaciteti i madh</translation>
+<translation id="4940163644868678279">Modaliteti "I fshehtë" në Chrome</translation>
<translation id="4943872375798546930">Asnjë rezultat</translation>
<translation id="4950898438188848926">Butoni i ndërrimit të skedës. Shtyp "Enter" për të kaluar te skeda e hapur, <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="495170559598752135">Veprimet</translation>
@@ -1259,6 +1293,7 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="4968522289500246572">Ky aplikacion është projektuar për celular dhe përmasat mund të mos ndryshohen si duhet. Aplikacioni mund të ketë probleme ose të riniset.</translation>
<translation id="4969341057194253438">Fshi regjistrimin</translation>
<translation id="4973922308112707173">Dy shpime lart</translation>
+<translation id="4976702386844183910">Vizituar së fundi më <ph name="DATE" /></translation>
<translation id="4984088539114770594">Të përdoret mikrofoni?</translation>
<translation id="4984339528288761049">Prc5 (Zarf)</translation>
<translation id="4989163558385430922">Shiko të gjitha</translation>
@@ -1320,6 +1355,7 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="5138227688689900538">Shfaq më pak</translation>
<translation id="5145883236150621069">Një kod gabimi i pranishëm në përgjigjen e politikës</translation>
<translation id="5146995429444047494">Njoftimet për <ph name="ORIGIN" /> janë bllokuar</translation>
+<translation id="514704532284964975"><ph name="URL" /> kërkon të shikojë dhe të ndryshojnë informacionin në pajisjet NFC dhe troket me telefon</translation>
<translation id="5148809049217731050">E kthyer lart</translation>
<translation id="515292512908731282">C4 (Zarf)</translation>
<translation id="5158275234811857234">Kapak</translation>
@@ -1344,6 +1380,7 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="5215116848420601511">Mënyrat e pagesës dhe adresat që përdorin Google Pay</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">Tabakaja 13</translation>
+<translation id="5216942107514965959">Vizituar për herë të fundit sot</translation>
<translation id="5222812217790122047">Email-i është i detyrueshëm</translation>
<translation id="5230733896359313003">Adresa e dërgimit</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1364,7 +1401,6 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">Karakteristikat e dokumentit</translation>
<translation id="528468243742722775">Fundi</translation>
-<translation id="5284909709419567258">Adresat e rrjetit</translation>
<translation id="5285570108065881030">Shfaq të gjitha fjalëkalimet e ruajtura</translation>
<translation id="5287240709317226393">Shfaq kukit</translation>
<translation id="5287456746628258573">Ky sajt përdor një konfigurim të vjetruar të sigurisë, i cili mund t'i ekspozojë informacionet e tua (p.sh. fjalëkalimin ose numrat e kartës së kreditit) kur dërgohen te ky sajt.</translation>
@@ -1448,6 +1484,7 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="5556459405103347317">Ringarko</translation>
<translation id="5560088892362098740">Data e skadimit</translation>
<translation id="55635442646131152">Konturi i dokumentit</translation>
+<translation id="5565613213060953222">Hap skedën "e fshehtë"</translation>
<translation id="5565735124758917034">Aktiv</translation>
<translation id="5570825185877910964">Mbroje llogarinë</translation>
<translation id="5571083550517324815">Nuk mund të merret nga kjo adresë. Zgjidh një adresë tjetër.</translation>
@@ -1530,6 +1567,7 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="5869522115854928033">Fjalëkalimet e ruajtura</translation>
<translation id="5873013647450402046">Banka jote dëshiron të konfirmojë që je ti.</translation>
<translation id="5887400589839399685">Karta u ruajt</translation>
+<translation id="5887687176710214216">Vizituar së fundi dje</translation>
<translation id="5895138241574237353">Rinis</translation>
<translation id="5895187275912066135">Lëshuar më</translation>
<translation id="5901630391730855834">E verdhë</translation>
@@ -1543,6 +1581,7 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="5921639886840618607">Të ruhet karta te "Llogaria e Google"?</translation>
<translation id="5922853866070715753">Pothuajse mbaroi</translation>
<translation id="5932224571077948991">Sajti shfaq reklama ndërhyrëse ose mashtruese</translation>
+<translation id="5938153366081463283">Shto kartë virtuale</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347">Po hap <ph name="SITE_NAME" />…</translation>
<translation id="5951495562196540101">Nuk mund të regjistrohesh me një llogari konsumatori (ofrohet një licencë paketë).</translation>
@@ -1607,6 +1646,7 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="6120179357481664955">Të kujtohet ID-ja e UPI?</translation>
<translation id="6124432979022149706">Chrome Enterprise Connectors</translation>
<translation id="6127379762771434464">Artikulli u hoq</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Mëso më shumë për modalitetin "I fshehtë" në Chrome<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">Kontrollo kabllot dhe rindiz router-it, modemët ose pajisjet e tjera të rrjetit që mund të jesh duke përdorur.</translation>
<translation id="614940544461990577">Provo:</translation>
<translation id="6150036310511284407">Tri shpime majtas</translation>
@@ -1618,7 +1658,6 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="6169916984152623906">Tani mund të shfletosh në mënyrë private dhe personat e tjerë që përdorin këtë pajisje nuk do të shikojnë aktivitetin tënd. Sidoqoftë, shkarkimet dhe faqeshënuesit do të ruhen.</translation>
<translation id="6177128806592000436">Lidhja jote me këtë sajt nuk është e sigurt</translation>
<translation id="6180316780098470077">Intervali i ripërpjekjes</translation>
-<translation id="619448280891863779">Mund të kërkojë të hapë dhe të vendosë dritare në ekranet e tua</translation>
<translation id="6196640612572343990">Blloko kukit e palëve të treta</translation>
<translation id="6203231073485539293">Kontrollo lidhjen e internetit.</translation>
<translation id="6218753634732582820">Të hiqet adresa nga Chromium?</translation>
@@ -1641,7 +1680,7 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="6272383483618007430">Përditësimi i Google</translation>
<translation id="6276112860590028508">Faqet nga lista jote e leximit shfaqen këtu</translation>
<translation id="627746635834430766">Për të paguar më shpejt herën tjetër, ruaje kartën dhe adresën tënde të faturimit në llogarinë tënde të Google.</translation>
-<translation id="6279098320682980337">Nuk është plotësuar numri i kartës virtuale? Kliko detajet e kartës për t'i kopjuar</translation>
+<translation id="6279183038361895380">Shtyp |<ph name="ACCELERATOR" />| për të shfaqur kursorin</translation>
<translation id="6280223929691119688">Nuk mund të dorëzohet në këtë adresë. Zgjidh një adresë tjetër.</translation>
<translation id="6282194474023008486">Kodi postar</translation>
<translation id="6285507000506177184">Butoni "Menaxho shkarkimet në Chrome". Shtyp "Enter" për të menaxhuar skedarët që ke shkarkuar në Chrome</translation>
@@ -1649,6 +1688,7 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="6290238015253830360">Artikujt e tu të sugjeruar shfaqen këtu</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{Pajisja do të riniset tani}=1{Pajisja do të riniset pas 1 sekonde}other{Pajisja do të riniset pas # sekondash}}</translation>
<translation id="6302269476990306341">"Asistenti i Google" në Chrome po ndalon</translation>
<translation id="6305205051461490394"><ph name="URL" /> është i paarritshëm.</translation>
<translation id="6312113039770857350">Faqja e uebit nuk është e disponueshme</translation>
@@ -1722,6 +1762,7 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="6529602333819889595">&amp;Bëje përsëri fshirjen</translation>
<translation id="6545864417968258051">Skanimi për Bluetooth</translation>
<translation id="6547208576736763147">Dy shpime majtas</translation>
+<translation id="6554732001434021288">Vizituar së fundi <ph name="NUM_DAYS" /> ditë më parë</translation>
<translation id="6556866813142980365">Ribëje</translation>
<translation id="6569060085658103619">Po shikon një faqe të shtesës</translation>
<translation id="6573200754375280815">Dy shpime djathtas</translation>
@@ -1782,7 +1823,6 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="6757797048963528358">Pajisja jote kaloi në gjumë.</translation>
<translation id="6767985426384634228">Të përditësohet adresa?</translation>
<translation id="6768213884286397650">Hagaki (Kartolinë)</translation>
-<translation id="6774185088257932239"><ph name="BEGIN_LINK" />Mëso më shumë<ph name="END_LINK" /> rreth modalitetit "Të fshehtë"</translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">Vjollcë</translation>
<translation id="6786747875388722282">Shtesat</translation>
@@ -1866,7 +1906,6 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="706295145388601875">Shto dhe menaxho adresat te cilësimet e Chrome</translation>
<translation id="7064851114919012435">Informacionet e kontaktit</translation>
<translation id="7068733155164172741">Fut kodin <ph name="OTP_LENGTH" />-shifror</translation>
-<translation id="7070090581017165256">Rreth këtij sajti</translation>
<translation id="70705239631109039">Lidhja jote nuk është plotësisht e sigurt</translation>
<translation id="7075452647191940183">Kërkesa është tepër e madhe</translation>
<translation id="7079718277001814089">Ky sajt përmban softuerë keqdashës</translation>
@@ -1883,6 +1922,12 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="7111012039238467737">(E vlefshme)</translation>
<translation id="7118618213916969306">Kërko për URL-në e kujtesës së fragmenteve, <ph name="SHORT_URL" /></translation>
<translation id="7119414471315195487">Mbyll skedat ose programet e tjera</translation>
+<translation id="7129355289156517987">Kur mbyll të gjitha skedat "e fshehta" në Chromium, aktiviteti yt në këto skeda fshihet nga kjo pajisje:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Aktiviteti i shfletimit<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Historiku i kërkimeve<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Informacionet e futura në formularë<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">Nuk mund të dërgohet në këtë adresë. Zgjidh një adresë tjetër.</translation>
<translation id="7132939140423847331">Administratori yt e ka ndaluar kopjimin e këtyre të dhënave.</translation>
<translation id="7135130955892390533">Shfaq statusin</translation>
@@ -1905,6 +1950,7 @@ Ndryshe kjo do të bllokohet nga cilësimet e tua të privatësisë. Kjo do ta l
<translation id="7192203810768312527">Liron <ph name="SIZE" />. Disa sajte mund të ngarkohen më ngadalë gjatë vizitës tënde të radhës.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">Administratori yt mund të shohë:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, shtyp tastin Tab dhe më pas tastin Enter për të hapur një dritare të re "të fshehtë" për të shfletuar në mënyrë private</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> nuk i respekton standardet e sigurisë.</translation>
<translation id="7210993021468939304">Aktiviteti i Linux brenda kontejnerit dhe mund të instalojë dhe të ekzekutojë aplikacione të Linux brenda kontejnerit</translation>
@@ -1936,6 +1982,7 @@ Detaje shtesë:
<translation id="7304562222803846232">Menaxho cilësimet e privatësisë të "Llogarisë së Google"</translation>
<translation id="7305756307268530424">Fillo më ngadalë</translation>
<translation id="7308436126008021607">sinkronizimi në sfond</translation>
+<translation id="7310392214323165548">Pajisja do të riniset së shpejti</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">Ndihma e lidhjes</translation>
<translation id="7323804146520582233">Fshihe seksionin "<ph name="SECTION" />"</translation>
@@ -1943,6 +1990,7 @@ Detaje shtesë:
<translation id="7334320624316649418">&amp;Ribëj renditjen</translation>
<translation id="7335157162773372339">Mund të kërkojë të përdorë kamerën tënde</translation>
<translation id="7337248890521463931">Shfaq më shumë radhë</translation>
+<translation id="7337418456231055214">Nuk është plotësuar numri i kartës virtuale? Kliko detajet e kartës për t'i kopjuar. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">Nuk ofrohet në këtë platformë.</translation>
<translation id="733923710415886693">Certifikata e serverit nuk është zbuluar përmes "Transparencës së certifikatave".</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1965,6 +2013,7 @@ Detaje shtesë:
<translation id="7378627244592794276">Jo</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">Nuk është i zbatueshëm</translation>
+<translation id="7388594495505979117">{0,plural, =1{Pajisja do të riniset pas 1 minute}other{Pajisja do të riniset pas # minutash}}</translation>
<translation id="7390545607259442187">Konfirmo kartën</translation>
<translation id="7392089738299859607">Përditëso adresën</translation>
<translation id="7399802613464275309">Kontrolli i sigurisë</translation>
@@ -2001,6 +2050,12 @@ Detaje shtesë:
<translation id="7485870689360869515">Nuk u gjetën të dhëna.</translation>
<translation id="7495528107193238112">Kjo përmbajtje është bllokuar. Kontakto me zotëruesin e sajtit për të rregulluar problemin.</translation>
<translation id="7497998058912824456">Butoni "Krijo dokument", shtyp Enter për të krijuar shpejt një "Dokument të ri të Google"</translation>
+<translation id="7506488012654002225">Chromium <ph name="BEGIN_EMPHASIS" />nuk do të ruajë<ph name="END_EMPHASIS" /> informacionet e mëposhtme:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Historikun tënd të shfletimit
+ <ph name="LIST_ITEM" />Kukit dhe të dhënat e sajteve
+ <ph name="LIST_ITEM" />Informacionet e futura në formularë
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">ID-ja e kthyer e pajisjes së politikës është bosh ose nuk përputhet me ID-në e pajisjes aktuale</translation>
<translation id="7508870219247277067">Jeshile avokadoje</translation>
<translation id="7511955381719512146">Wi-Fi që po përdor mund të kërkojë që të vizitosh <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
@@ -2114,7 +2169,6 @@ Detaje shtesë:
<translation id="7813600968533626083">Të hiqet sugjerimi i formularit nga Chrome?</translation>
<translation id="781440967107097262">Të ndahet kujtesa e fragmenteve?</translation>
<translation id="7815407501681723534">U gjetën <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> për "<ph name="SEARCH_STRING" />"</translation>
-<translation id="782125616001965242">Shfaq informacione rreth këtij sajti</translation>
<translation id="782886543891417279">Lidhja Wi-Fi që po përdor (<ph name="WIFI_NAME" />) mund të kërkojë që të vizitosh faqen e saj të lidhjes.</translation>
<translation id="7836231406687464395">Postfix (Zarf)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{Asnjë}=1{1 aplikacion (<ph name="EXAMPLE_APP_1" />)}=2{2 aplikacione (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}other{# aplikacione (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}}</translation>
@@ -2131,7 +2185,6 @@ Detaje shtesë:
<translation id="7888575728750733395">Synimi i paraqitjes për printimin</translation>
<translation id="7894280532028510793">Nëse nuk ka ndonjë gabim drejtshkrimor, <ph name="BEGIN_LINK" />provo të ekzekutosh "Diagnostikimin e rrjetit"<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (Zarf)</translation>
-<translation id="7931318309563332511">E panjohur</translation>
<translation id="793209273132572360">Të përditësohet adresa?</translation>
<translation id="7932579305932748336">Veshje</translation>
<translation id="79338296614623784">Fut një numër të vlefshëm telefoni</translation>
@@ -2156,13 +2209,14 @@ Detaje shtesë:
<translation id="7976214039405368314">Ka shumë kërkesa</translation>
<translation id="7977538094055660992">Pajisja e daljes</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">Lidhur me</translation>
<translation id="798134797138789862">Mund të kërkojë të përdorë të dhënat dhe pajisjet e realitetit virtual</translation>
<translation id="7984945080620862648">Nuk mund ta vizitosh <ph name="SITE" /> tani sepse sajti i uebit dërgoi kredenciale të koduara që nuk mund të përpunohen nga Chrome. Gabimet dhe sulmet në rrjet zakonisht janë të përkohshme, kështu që kjo faqe ndoshta do të punojë më vonë.</translation>
-<translation id="79859296434321399">Për të parë përmbajtje realiteti të zgjeruar, instalo ARCore</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">Lidhje</translation>
<translation id="7992044431894087211">U riaktivizua ndarja e ekranit me <ph name="APPLICATION_TITLE" /></translation>
<translation id="7995512525968007366">Nuk është specifikuar</translation>
+<translation id="7998269595945679889">Hap butonin e skedës "së fshehtë" dhe shtyp tastin Enter për të hapur një skedë të re "të fshehtë" për të shfletuar në mënyrë private</translation>
<translation id="800218591365569300">Provo të mbyllësh skedat ose programet e tjera për të liruar memorien.</translation>
<translation id="8004582292198964060">Shfletuesi</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{Kjo kartë dhe adresa e saj e faturimit do të ruhen. Do të jesh në gjendje ta përdorësh kur të jesh identifikuar në <ph name="USER_EMAIL" />.}other{Këto karta dhe adresat e tyre të faturimit do të ruhen. Do të jesh në gjendje t'i përdorësh kur të jesh identifikuar në <ph name="USER_EMAIL" />.}}</translation>
@@ -2222,6 +2276,7 @@ Detaje shtesë:
<translation id="8202370299023114387">Konflikt</translation>
<translation id="8206978196348664717">Prc4 (Zarf)</translation>
<translation id="8211406090763984747">Lidhja është e sigurt</translation>
+<translation id="8217240300496046857">Sajtet nuk mund të përdorin kuki që të monitorojnë nëpër ueb. Veçoritë në disa sajte mund të ndalojnë së funksionuari.</translation>
<translation id="8218327578424803826">Vendndodhja e caktuar:</translation>
<translation id="8220146938470311105">C7/C6 (Zarf)</translation>
<translation id="8225771182978767009">Personi që ka konfiguruar këtë kompjuter ka zgjedhur ta bllokojë këtë sajt.</translation>
@@ -2262,14 +2317,9 @@ Detaje shtesë:
<translation id="830498451218851433">Palosje në gjysmë</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">Aplikacionet e instaluara dhe sa shpesh përdoren</translation>
+<translation id="8317207217658302555">Të përditësohet ARCore?</translation>
<translation id="831997045666694187">Mbrëmje</translation>
<translation id="8321476692217554900">njoftimet</translation>
-<translation id="8328484624016508118">Pas mbylljes së të gjitha skedave të modalitetit "Të fshehtë", Chrome pastron:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Aktivitetin tënd të shfletimit nga kjo pajisje<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Historikun tënd të kërkimeve nga kjo pajisje<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Informacionet e futura në formularë<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489">Qasja te <ph name="HOST_NAME" /> u refuzua</translation>
<translation id="833262891116910667">Thekso</translation>
<translation id="8339163506404995330">Faqet në <ph name="LANGUAGE" /> nuk do të përkthehen</translation>
@@ -2321,6 +2371,7 @@ Detaje shtesë:
<translation id="8507227106804027148">Rreshti i komandës</translation>
<translation id="8508648098325802031">Ikona e kërkimit</translation>
<translation id="8511402995811232419">Menaxho kukit</translation>
+<translation id="8519753333133776369">Pajisja HID e lejuar nga administratori yt</translation>
<translation id="8522552481199248698">Chrome mund të të ndihmojë ta mbrosh "Llogarinë tënde të Google" dhe të ndryshosh fjalëkalimin tënd.</translation>
<translation id="8530813470445476232">Pastro historikun e shfletimit, kukit, memorien specifike etj. te cilësimet e Chrome</translation>
<translation id="8533619373899488139">Vizito &lt;strong&gt;chrome://policy&lt;/strong&gt; për të parë listën e URL-ve të bllokuara dhe politika të tjera të detyruara nga administratori i sistemit tënd.</translation>
@@ -2332,7 +2383,6 @@ Detaje shtesë:
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{RIvendos lejen}other{Rivendos lejet}}</translation>
<translation id="8555010941760982128">Përdor këtë kod në përfundim të blerjes</translation>
<translation id="8557066899867184262">Kodi CVC ndodhet në pjesën e pasme të kartës.</translation>
-<translation id="8558485628462305855">Për të parë përmbajtje realiteti të zgjeruar, përditëso ARCore</translation>
<translation id="8559762987265718583">Nuk mund të vendoset një lidhje private me <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />sepse data dhe ora (<ph name="DATE_AND_TIME" />) e pajisjes tënde nuk janë të sakta.</translation>
<translation id="8564182942834072828">Dokumente të ndara/kopje të parenditura</translation>
<translation id="8564985650692024650">Chromium rekomandon rivendosjen e fjalëkalimit tënd të <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> nëse e ke ripërdorur në sajte të tjera.</translation>
@@ -2351,6 +2401,7 @@ Detaje shtesë:
<translation id="865032292777205197">sensorët e lëvizjes</translation>
<translation id="8663226718884576429">Përmbledhje e porosisë, <ph name="TOTAL_LABEL" />, detaje të tjera</translation>
<translation id="8666678546361132282">Anglisht</translation>
+<translation id="8669306706049782872">Të përdorë informacionet rreth ekraneve të tua për të hapur dhe për të vendosur dritare</translation>
<translation id="867224526087042813">Nënshkrimi</translation>
<translation id="8676424191133491403">Pa vonesë</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, përgjigjja, <ph name="ANSWER" /></translation>
@@ -2377,6 +2428,7 @@ Detaje shtesë:
<translation id="8731544501227493793">Menaxho butonin e fjalëkalimeve, shtyp "Enter" për të parë dhe menaxhuar fjalëkalimet e tua në cilësimet e Chrome</translation>
<translation id="8734529307927223492">Pajisja jote <ph name="DEVICE_TYPE" /> menaxhohet nga <ph name="MANAGER" /></translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, shtyp "Tab", më pas "Enter" për të hapur një dritare të re "të fshehtë" për të shfletuar në mënyrë private</translation>
+<translation id="8737685506611670901">Hap lidhjet e <ph name="PROTOCOL" /> në vend të <ph name="REPLACED_HANDLER_TITLE" /></translation>
<translation id="8738058698779197622">Për të krijuar një lidhje të sigurt, ora duhet të vendoset në mënyrë të saktë. Kjo ndodh sepse certifikatat që përdorin sajtet e internetit për t'u identifikuar janë të vlefshme vetëm për periudha specifike kohore. Meqenëse ora e pajisjes është e pasaktë, Chromium nuk mund t'i verifikojë këto certifikata.</translation>
<translation id="8740359287975076522">&lt;abbr id="dnsDefinition"&gt;Adresa DNS&lt;/abbr&gt; e <ph name="HOST_NAME" /> nuk mund të gjendej. Problemi po diagnostikohet.</translation>
<translation id="8742371904523228557"><ph name="ONE_TIME_CODE" /> është kodi për <ph name="ORIGIN" /></translation>
@@ -2404,6 +2456,7 @@ Detaje shtesë:
<translation id="883848425547221593">Faqeshënues të tjerë</translation>
<translation id="884264119367021077">Adresa e transportit</translation>
<translation id="884923133447025588">Nuk u gjet asnjë mekanizëm revokimi.</translation>
+<translation id="8849262850971482943">Përdor kartën tënde virtuale për më shumë siguri</translation>
<translation id="885730110891505394">Ndarja me Google</translation>
<translation id="8858065207712248076">Chrome rekomandon rivendosjen e fjalëkalimit tënd të <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> nëse e ke ripërdorur në sajte të tjera.</translation>
<translation id="885906927438988819">Nëse nuk ka ndonjë gabim drejtshkrimor, <ph name="BEGIN_LINK" />provo të ekzekutosh "Diagnostikimin e rrjetit të Windows"<ph name="END_LINK" />.</translation>
@@ -2453,6 +2506,7 @@ Detaje shtesë:
<translation id="9004367719664099443">Sesioni VR në proces</translation>
<translation id="9005998258318286617">Ngarkimi i dokumentit PDF dështoi.</translation>
<translation id="9008201768610948239">Shpërfill</translation>
+<translation id="901834265349196618">mail</translation>
<translation id="9020200922353704812">Adresa e faturimit të kartës është e detyrueshme</translation>
<translation id="9020542370529661692">Kjo faqe është përkthyer në <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9020742383383852663">A8</translation>
@@ -2501,6 +2555,7 @@ Detaje shtesë:
<translation id="9150045010208374699">Përdor kamerën</translation>
<translation id="9150685862434908345">Administratori yt mund të ndryshojë konfigurimin e shfletuesit në distancë. Aktiviteti në këtë pajisje mund të menaxhohet edhe jashtë Chrome. <ph name="BEGIN_LINK" />Mëso më shumë<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">I përditësuar</translation>
+<translation id="9155211586651734179">Pajisjet periferike audio të lidhura</translation>
<translation id="9157595877708044936">Po konfiguron...</translation>
<translation id="9158625974267017556">C6 (Zarf)</translation>
<translation id="9164029392738894042">Kontrolli i saktësisë</translation>
diff --git a/chromium/components/strings/components_strings_sr-Latn.xtb b/chromium/components/strings/components_strings_sr-Latn.xtb
index 8b62c1d65de..37c5a471832 100644
--- a/chromium/components/strings/components_strings_sr-Latn.xtb
+++ b/chromium/components/strings/components_strings_sr-Latn.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">Prikaži detalje</translation>
<translation id="1030706264415084469"><ph name="URL" /> želi trajno da skladiÅ¡ti velike koliÄine podataka na ureÄ‘aju</translation>
<translation id="1032854598605920125">Okrenite u smeru kazaljke na satu</translation>
+<translation id="1033329911862281889">Režim bez arhiviranja vas ne Äini nevidljivim onlajn:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Sajtovi i usluge koje koristite mogu da vide posete<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Poslodavci ili Å¡kole mogu da prate aktivnosti pregledanja<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Internet provajderi mogu da prate saobracÌaj na vebu<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">IskljuÄi</translation>
<translation id="1036982837258183574">Pritisnite |<ph name="ACCELERATOR" />| da biste izašli iz režima celog ekrana</translation>
<translation id="1038106730571050514">Prikažite predloge</translation>
<translation id="1038842779957582377">nepoznato ime</translation>
<translation id="1041998700806130099">Poruka o radnom listu</translation>
<translation id="1048785276086539861">Kada izmenite komentare, ovaj dokument se vracÌa na prikaz pojedinaÄne stranice.</translation>
-<translation id="1049743911850919806">Bez arhiviranja</translation>
<translation id="1050038467049342496">Zatvorite druge aplikacije</translation>
<translation id="1055184225775184556">&amp;Opozovi dodavanje</translation>
<translation id="1056898198331236512">Upozorenje</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">Keš smernica je u redu</translation>
<translation id="1130564665089811311">Dugme Prevedi stranicu, pritisnite Enter da biste preveli ovu stranicu pomocÌu Google prevodioca</translation>
<translation id="1131264053432022307">Kopirana slika</translation>
+<translation id="1142846828089312304">Blokiraj kolaÄicÌe trecÌih strana u režimu bez arhiviranja</translation>
<translation id="1150979032973867961">Ovaj server ne može da dokaže da je <ph name="DOMAIN" />; operativni sistem raÄunara nema poverenja u njegov bezbednosni sertifikat. Uzrok tome je možda pogreÅ¡na konfiguracija ili napadaÄ koji je prekinuo vezu.</translation>
<translation id="1151972924205500581">Lozinka je obavezna</translation>
<translation id="1156303062776767266">Pregledate lokalnu ili deljenu datoteku</translation>
@@ -64,7 +70,6 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="1178581264944972037">Pauziraj</translation>
<translation id="1181037720776840403">Ukloni</translation>
<translation id="1186201132766001848">Proveri lozinke</translation>
-<translation id="1195210374336998651">Otvori podešavanja aplikacije</translation>
<translation id="1195558154361252544">ObaveÅ¡tenja su automatski blokirana za sve sajtove osim za one koje omogucÌite</translation>
<translation id="1197088940767939838">Narandžasta</translation>
<translation id="1201402288615127009">Dalje</translation>
@@ -111,7 +116,7 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="1307966114820526988">Zastarele funkcije</translation>
<translation id="1308113895091915999">Ponuda je dostupna</translation>
<translation id="1312803275555673949">Koji dokazi podržavaju ovo?</translation>
-<translation id="131405271941274527"><ph name="URL" /> želi da šalje i dobija informacije kada telefonom dodirnete NFC uređaj</translation>
+<translation id="1314311879718644478">Pregledajte sadržaj sa proÅ¡irenom realnoÅ¡cÌu</translation>
<translation id="1314509827145471431">Povez na desnoj strani</translation>
<translation id="1318023360584041678">SaÄuvano je u grupi kartica</translation>
<translation id="1319245136674974084">Ne pitaj ponovo za ovu aplikaciju</translation>
@@ -161,6 +166,7 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="142858679511221695">Korisnik usluge u klaudu</translation>
<translation id="1428729058023778569">Ovo upozorenje vam se prikazuje jer ovaj sajt ne podržava HTTPS. <ph name="BEGIN_LEARN_MORE_LINK" />Saznajte više<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">Å tampaj</translation>
+<translation id="1432187715652018471">Stranica želi da instalira obraÄ‘ivaÄa usluge.</translation>
<translation id="1432581352905426595">Upravljaj pretraživaÄima</translation>
<translation id="1436185428532214179">Može da traži da menja fajlove i foldere na uređaju</translation>
<translation id="1442386063175183758">Presavijanje na desnoj strani u obliku prozora</translation>
@@ -181,6 +187,12 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="1483493594462132177">Pošalji</translation>
<translation id="1484290072879560759">Odaberite adresu za isporuku</translation>
<translation id="1492194039220927094">Slanje smernica:</translation>
+<translation id="149293076951187737">Kada zatvorite sve Chrome kartice bez arhiviranja, aktivnost na tim karticama se briše sa uređaja:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Aktivnosti pregledanja<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Istorija pretrage<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Informacije unete u obrascima<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">Nazad na karticu</translation>
<translation id="1501859676467574491">Prikazuj kartice sa mog Google naloga</translation>
<translation id="1507202001669085618">&lt;p&gt;Ova greška se prikazuje ako koristite WiFi portal na kome morate da se prijavite da biste se povezali na internet.&lt;/p&gt;
@@ -208,6 +220,8 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="1559572115229829303">&lt;p&gt;Nije mogucÌe uspostaviti privatnu vezu sa domenom <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> jer datum i vreme na ureÄ‘aju (<ph name="DATE_AND_TIME" />) nisu taÄni.&lt;/p&gt;
&lt;p&gt;Prilagodite datum i vreme u odeljku &lt;strong&gt;Opšte&lt;/strong&gt; u aplikaciji &lt;strong&gt;Podešavanja&lt;/strong&gt;.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">Administrator cÌe restartovati ureÄ‘aj u <ph name="TIME" /> <ph name="DATE" /></translation>
+<translation id="156703335097561114">Informacije o mrežama poput adresa, konfiguracije interfejsa i kvaliteta veze</translation>
<translation id="1567040042588613346">Ove smernice rade kao što je predviđeno, ali ista vrednost je podešena na drugom mestu i zamenjuju je ove smernice.</translation>
<translation id="1569487616857761740">Unesite datum isteka</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="1583429793053364125">Došlo je do greške pri prikazivanju ove veb-stranice.</translation>
<translation id="1586541204584340881">dodatke koje ste instalirali</translation>
<translation id="1588438908519853928">Normalan</translation>
+<translation id="1589050138437146318">Želite da instalirate ARCore?</translation>
<translation id="1592005682883173041">Pristup lokalnim podacima</translation>
<translation id="1594030484168838125">Odaberi</translation>
<translation id="160851722280695521">Igrajte igru Dinosaurus u Chrome-u</translation>
@@ -254,7 +269,7 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="1711234383449478798">Zanemareno jer <ph name="POLICY_NAME" /> nema vrednost <ph name="VALUE" />.</translation>
<translation id="1712552549805331520"><ph name="URL" /> želi trajno da skladiÅ¡ti podatke na lokalnom raÄunaru</translation>
<translation id="1713628304598226412">2. fioka</translation>
-<translation id="1715874602234207">F</translation>
+<translation id="1715874602234207">P</translation>
<translation id="1717218214683051432">Senzori pokreta</translation>
<translation id="1717494416764505390">3. poÅ¡tansko sanduÄe</translation>
<translation id="1718029547804390981">Dokument je isuviše veliki da biste mu dodali napomene</translation>
@@ -283,6 +298,7 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
format zaglavlja je netaÄan, Å¡to spreÄava pregledaÄ da ispuni
zahtev za <ph name="SITE" />. PomocÌu smernica za poreklo
operatori sajtova mogu da konfigurišu bezbednost i druga svojstva za sajt.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Saznajte više o režimu Bez arhiviranja u Chromium-u<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">Otvorene kartice se pojavljuju ovde</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -410,6 +426,7 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="22081806969704220">3. fioka</translation>
<translation id="2212735316055980242">Smernice nisu pronađene</translation>
<translation id="2213606439339815911">Preuzimanje unosa...</translation>
+<translation id="2213612003795704869">Stranica je odštampana</translation>
<translation id="2215727959747642672">Menjanje datoteka</translation>
<translation id="2218879909401188352">NapadaÄi koji su trenutno na <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> mogu da instaliraju opasne aplikacije koje cÌe vam oÅ¡tetiti ureÄ‘aj, dodati neželjene troÅ¡kove kod mobilnog operatera ili ukrasti liÄne podatke. <ph name="BEGIN_LEARN_MORE_LINK" />Saznajte viÅ¡e<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">Nema interneta</translation>
@@ -419,6 +436,7 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="2248949050832152960">Koristi WebAuthn</translation>
<translation id="2250931979407627383">Spajanje ivica Å¡avom na levoj strani</translation>
<translation id="225207911366869382">Ova vrednost je zastarela za ove smernice.</translation>
+<translation id="2256115617011615191">Restartuj odmah</translation>
<translation id="2258928405015593961">Unesite datum isteka koji je u buducÌnosti i probajte ponovo</translation>
<translation id="225943865679747347">Kôd greške: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">HTTP greška</translation>
@@ -446,6 +464,7 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="2337852623177822836">Podešavanje kontroliše administrator</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> želi da se upari</translation>
<translation id="2346319942568447007">Kopirana slika</translation>
+<translation id="2350796302381711542">Želite li da dozvolite da <ph name="HANDLER_HOSTNAME" /> otvara sve <ph name="PROTOCOL" /> linkove za koje ste do sada koristili <ph name="REPLACED_HANDLER_TITLE" />?</translation>
<translation id="2354001756790975382">Ostali obeleživaÄi</translation>
<translation id="2354430244986887761">Google bezbedno pregledanje je nedavno <ph name="BEGIN_LINK" />otkrilo Å¡tetne aplikacije<ph name="END_LINK" /> na <ph name="SITE" />.</translation>
<translation id="2355395290879513365">NapadaÄi cÌe mocÌi da vide slike koje gledate na ovom sajtu i da ih izmene kako bi vas prevarili.</translation>
@@ -471,6 +490,7 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="2413528052993050574">Ovaj server ne može da dokaže da je <ph name="DOMAIN" />; njegov bezbednosni sertifikat cÌe možda biti opozvan. Uzrok tome je možda pogreÅ¡na konfiguracija ili napadaÄ koji je prekinuo vezu.</translation>
<translation id="2414886740292270097">Tamna</translation>
<translation id="2430968933669123598">Upravljajte Google nalogom, pritisnite Enter da biste upravljali informacijama, privatnoÅ¡cÌu i bezbednoÅ¡cÌu na Google nalogu</translation>
+<translation id="2436186046335138073">Želite li da dozvolite da <ph name="HANDLER_HOSTNAME" /> otvara sve <ph name="PROTOCOL" /> linkove?</translation>
<translation id="2438874542388153331">Četvorostruko bušenje na desnoj strani</translation>
<translation id="2450021089947420533">Putevi</translation>
<translation id="2463739503403862330">Popuni</translation>
@@ -478,6 +498,7 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="2465655957518002998">Odaberite naÄin dostave</translation>
<translation id="2465688316154986572">Spajanje</translation>
<translation id="2465914000209955735">Upravljajte fajlovima koje ste preuzeli u Chrome-u</translation>
+<translation id="2466004615675155314">Prikazuje informacije sa veba</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />da pokrenete dijagnostiku mreže<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">Redosled od 1 do n</translation>
<translation id="2470767536994572628">Kada izmenite komentare, ovaj dokument se vracÌa na prikaz pojedinaÄne stranice i u prvobitni položaj.</translation>
@@ -498,6 +519,7 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="2523886232349826891">SaÄuvano je samo na ovom ureÄ‘aju</translation>
<translation id="2524461107774643265">Dodajte još informacija</translation>
<translation id="2529899080962247600">Ovo polje ne sme da ima viÅ¡e od <ph name="MAX_ITEMS_LIMIT" /> unosa. Svi buducÌi unosi cÌe se zanemariti.</translation>
+<translation id="2535585790302968248">Otvorite novu karticu bez arhiviranja da biste pregledali privatno</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{i još 1}one{i još #}few{i još #}other{i još #}}</translation>
<translation id="2536110899380797252">Dodaj adresu</translation>
<translation id="2539524384386349900">Otkrij</translation>
@@ -523,7 +545,14 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="2597378329261239068">Ovaj dokument je zaÅ¡ticÌen lozinkom. Unesite lozinku.</translation>
<translation id="2609632851001447353">Varijacije</translation>
<translation id="2610561535971892504">Kliknite da biste kopirali</translation>
+<translation id="2617988307566202237">Chrome <ph name="BEGIN_EMPHASIS" />ne Äuva<ph name="END_EMPHASIS" /> sledecÌe informacije:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />istoriju pregledanja
+ <ph name="LIST_ITEM" />kolaÄicÌe i podatke o sajtovima
+ <ph name="LIST_ITEM" />informacije koje unosite u obrascima
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (koverat)</translation>
+<translation id="2623663032199728144">Može da zatraži da koristi informacije o ekranima</translation>
<translation id="2625385379895617796">Sat vam žuri</translation>
<translation id="262745152991669301">Može da traži da se povezuje sa USB uređajima</translation>
<translation id="2629325967560697240">Da biste dobili najviÅ¡i nivo zaÅ¡tite u Chrome-u, <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />ukljuÄite poboljÅ¡anu zaÅ¡titu<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -557,6 +586,7 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="2709516037105925701">Automatsko popunjavanje</translation>
<translation id="2713444072780614174">Bela</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />, pritisnite Tab, pa Enter da biste upravljali placÌanjima i informacijama o kreditnim karticama u podeÅ¡avanjima Chrome-a</translation>
+<translation id="271663710482723385">Pritisnite |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| da biste izašli iz režima celog ekrana</translation>
<translation id="2721148159707890343">Zahtev je uspeo</translation>
<translation id="2723669454293168317">Pokrenite proveru bezbednosti u Chrome podešavanjima</translation>
<translation id="2726001110728089263">BoÄna fioka</translation>
@@ -587,6 +617,7 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="2850739647070081192">Invite (koverat)</translation>
<translation id="2856444702002559011">NapadaÄi možda pokuÅ¡avaju da ukradu informacije sa <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (na primer, lozinke, poruke ili kreditne kartice). <ph name="BEGIN_LEARN_MORE_LINK" />Saznajte viÅ¡e<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">Ovaj sajt prikazuje oglase koji ometaju aktivnosti ili obmanjujucÌe oglase.</translation>
+<translation id="286512204874376891">Virtuelna kartica krije vašu stvarnu karticu da bi vas zaštitila od potencijalne prevare. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">Prijateljski</translation>
<translation id="2876489322757410363">NapusticÌete režim bez arhiviranja da biste platili u spoljnoj aplikaciji. Želite li da nastavite?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />, pritisnite Tab, pa Enter da biste upravljali Bezbednim pregledanjem i drugim sadržajem u podešavanjima Chrome-a</translation>
@@ -611,6 +642,7 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="2930577230479659665">Skrati posle svakog kopiranja</translation>
<translation id="2932085390869194046">Predloži lozinku...</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019">otvori linkove za <ph name="PROTOCOL" /></translation>
<translation id="2941952326391522266">Ovaj server ne može da dokaže da je <ph name="DOMAIN" />; njegov bezbednosni sertifikat je sa domena <ph name="DOMAIN2" />. Uzrok tome je možda pogreÅ¡na konfiguracija ili napadaÄ koji je prekinuo vezu.</translation>
<translation id="2943895734390379394">Vreme otpremanja:</translation>
<translation id="2948083400971632585">Na stranici PodeÅ¡avanja možete da onemogucÌite sve proksije konfigurisane za vezu.</translation>
@@ -643,6 +675,7 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="3037605927509011580">O, ne!</translation>
<translation id="3041612393474885105">Informacije o sertifikatu</translation>
<translation id="3044034790304486808">Nastavite istraživanje</translation>
+<translation id="305162504811187366">Istorija Chrome udaljenog raÄunara, ukljuÄujucÌi vremenske oznake, ID-eve sesija hostova i klijenata</translation>
<translation id="3060227939791841287">C9 (koverat)</translation>
<translation id="3061707000357573562">Usluga krpljenja</translation>
<translation id="306573536155379004">Igra je pokrenuta.</translation>
@@ -683,6 +716,7 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="3197136577151645743">Može da traži da zna kada aktivno koristite uređaj</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />, pritisnite Tab, pa Enter da biste upravljali time koje informacije sinhronizujete u podešavanjima Chrome-a</translation>
<translation id="320323717674993345">Otkaži placÌanje</translation>
+<translation id="3203366800380907218">Sa veba</translation>
<translation id="3207960819495026254">Obeleženo</translation>
<translation id="3209034400446768650">Stranica može da naplacÌuje</translation>
<translation id="3212581601480735796">Vaše aktivnosti na <ph name="HOSTNAME" /> se prate</translation>
@@ -699,10 +733,12 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="3234666976984236645">Uvek otkrivaj važan sadržaj na ovom sajtu</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />, pritisnite Tab, pa Enter da biste prilagodili izgled pregledaÄa</translation>
<translation id="3240791268468473923">Otvoreno je obaveÅ¡tenje da nema akreditiva koji se podudaraju za bezbedno placÌanje</translation>
+<translation id="324180406144491771">Linkovi hosta <ph name="HOST_NAME" /> su blokirani</translation>
<translation id="3249845759089040423">Hipi</translation>
<translation id="3252266817569339921">francuski</translation>
<translation id="3257954757204451555">Ko je izvor ovih informacija?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />, pritisnite Tab, pa Enter da biste brzo napravili nov događaj u Google kalendaru</translation>
+<translation id="3261488570342242926">Saznajte više o virtuelnim karticama</translation>
<translation id="3264837738038045344">Dugme za upravljanje podešavanjima Chrome-a, pritisnite Enter da biste posetili podešavanja Chrome-a</translation>
<translation id="3266793032086590337">Vrednost (neusaglašena)</translation>
<translation id="3268451620468152448">Otvorene kartice</translation>
@@ -716,6 +752,7 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="3288238092761586174"><ph name="URL" /> treba da obavi dodatne korake radi potvrde placÌanja</translation>
<translation id="3293642807462928945">Saznajte više o smernicama <ph name="POLICY_NAME" /></translation>
<translation id="3295444047715739395">Pregledajte lozinke i upravljajte njima u podešavanjima Chrome-a</translation>
+<translation id="3303795387212510132">Želite li da dozvolite da aplikacija otvara <ph name="PROTOCOL_SCHEME" /> linkove?</translation>
<translation id="3303855915957856445">Nisu pronađeni rezultati pretrage</translation>
<translation id="3304073249511302126">Bluetooth skeniranje</translation>
<translation id="3308006649705061278">Organizaciona jedinica (OU)</translation>
@@ -729,12 +766,6 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="3345782426586609320">OÄi</translation>
<translation id="3355823806454867987">Promeni podešavanja proksija...</translation>
<translation id="3360103848165129075">Stranica obraÄ‘ivaÄa placÌanja</translation>
-<translation id="3361596688432910856">Chrome <ph name="BEGIN_EMPHASIS" />ne Äuva<ph name="END_EMPHASIS" /> sledecÌe informacije:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />istoriju pregledanja
- <ph name="LIST_ITEM" />kolaÄicÌe i podatke o sajtovima
- <ph name="LIST_ITEM" />informacije koje unosite u obrascima
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">Ove smernice se automatski kopiraju iz zastarelih smernica <ph name="OLD_POLICY" />. Umesto njih treba da koristite ove smernice.</translation>
<translation id="3364869320075768271"><ph name="URL" /> želi da koristi uređaj i podatke virtuelne realnosti</translation>
<translation id="3366477098757335611">Prikaži kartice</translation>
@@ -817,7 +848,6 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="3587738293690942763">Srednje</translation>
<translation id="3592413004129370115">Italian (koverat)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{Grupu možete da resetujete u bilo kom trenutku. Pridruživanje novoj grupi traje otprilike jedan dan.}=1{Grupu možete da resetujete u bilo kom trenutku. Pridruživanje novoj grupi traje otprilike jedan dan.}one{Grupu možete da resetujete u bilo kom trenutku. Pridruživanje novoj grupi traje otprilike {NUM_DAYS} dan.}few{Grupu možete da resetujete u bilo kom trenutku. Pridruživanje novoj grupi traje otprilike {NUM_DAYS} dana.}other{Grupu možete da resetujete u bilo kom trenutku. Pridruživanje novoj grupi traje otprilike {NUM_DAYS} dana.}}</translation>
-<translation id="3596012367874587041">Podešavanja aplikacije</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">Administrator blokira aplikaciju</translation>
<translation id="3608932978122581043">Smer unosa</translation>
@@ -860,6 +890,7 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="370972442370243704">UkljuÄi Puteve</translation>
<translation id="3711895659073496551">IskljuÄi</translation>
<translation id="3712624925041724820">Nema više licenci</translation>
+<translation id="3714633008798122362">veb kalendar</translation>
<translation id="3714780639079136834">da ukljuÄite podatke za mobilne ureÄ‘aje ili WiFi</translation>
<translation id="3715597595485130451">Povezivanje sa WiFi mrežom</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />da proverite konfiguraciju proksija, zaštitnog zida i DNS-a<ph name="END_LINK" /></translation>
@@ -921,6 +952,7 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="3906954721959377182">Tablet</translation>
<translation id="3909477809443608991"><ph name="URL" /> želi da pusti zaÅ¡ticÌeni sadržaj. Google cÌe potvrditi identitet ureÄ‘aja i ovaj sajt cÌe mocÌi da mu pristupa.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">Odbij</translation>
<translation id="3939773374150895049">Želite li da koristite WebAuthn umesto CVC-a?</translation>
<translation id="3946209740501886391">Uvek pitaj na ovom sajtu</translation>
<translation id="3947595700203588284">Može da traži da se povezuje sa MIDI uređajima</translation>
@@ -942,6 +974,7 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="3990250421422698716">Protresanje radi poravnanja</translation>
<translation id="3996311196211510766">Sajt <ph name="ORIGIN" /> je zatražio da se smernice za poreklo
primene na sve zahteve ka njemu, ali ove smernice trenutno ne mogu da se primene.</translation>
+<translation id="4009243425692662128">Sadržaj stranica koje Å¡tampate se Å¡alje u Google Cloud ili trecÌim stranama na analizu. Na primer, možda cÌe biti skeniran u potrazi za osetljivim podacima.</translation>
<translation id="4010758435855888356">Želite li da dozvolite pristup memorijskom prostoru?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{PDF dokument koji sadrži {COUNT} stranicu}one{PDF dokument koji sadrži {COUNT} stranicu}few{PDF dokument koji sadrži {COUNT} stranice}other{PDF dokument koji sadrži {COUNT} stranica}}</translation>
<translation id="4023431997072828269">Ovaj obrazac se Å¡alje pomocÌu veze koja nije bezbedna, pa cÌe informacije biti vidljive drugima.</translation>
@@ -1036,6 +1069,7 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="4250680216510889253">Ne</translation>
<translation id="4253168017788158739">Napomena</translation>
<translation id="425582637250725228">Promene koje ste uneli možda necÌe biti saÄuvane.</translation>
+<translation id="425869179292622354">Želite li da povecÌate bezbednost pomocÌu virtuelne kartice?</translation>
<translation id="4258748452823770588">Neispravan potpis</translation>
<translation id="4261046003697461417">Napomene ne mogu da se dodaju u zaÅ¡ticÌene dokumente</translation>
<translation id="4265872034478892965">Dozvoljava administrator</translation>
@@ -1098,6 +1132,7 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="4434045419905280838">IskaÄucÌi prozori i preusmeravanja</translation>
<translation id="4435702339979719576">razglednica)</translation>
<translation id="443673843213245140">KoriÅ¡cÌenje proksija je onemogucÌeno, ali je navedena eksplicitna konfiguracija proksija.</translation>
+<translation id="4441832193888514600">Ignoriše se jer smernice mogu da se podese samo kao smernice za korisnika u klaudu.</translation>
<translation id="4450893287417543264">Ne prikazuj ponovo</translation>
<translation id="4451135742916150903">Može da traži da se povezuje sa HID uređajima</translation>
<translation id="4452328064229197696">Lozinka koju ste upravo koristili je pronaÄ‘ena pri povredi podataka. Da biste zaÅ¡titili naloge, Google menadžer lozinki preporuÄuje da proverite saÄuvane lozinke.</translation>
@@ -1153,6 +1188,7 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="4628948037717959914">Slika</translation>
<translation id="4631649115723685955">Povezan je povracÌaj gotovine</translation>
<translation id="4636930964841734540">Informacije</translation>
+<translation id="4638670630777875591">Bez arhiviranja u Chromium-u</translation>
<translation id="464342062220857295">Funkcije pretrage</translation>
<translation id="4644670975240021822">Obrnutim redosledom sa odštampanom stranom nadole</translation>
<translation id="4646534391647090355">Odvedi me tamo</translation>
@@ -1173,6 +1209,7 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="4708268264240856090">Veza je prekinuta</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />da pokrenete Windows dijagnostiku mreže<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426">Lozinka za <ph name="USERNAME" /></translation>
<translation id="4724144314178270921">Može da traži da vidi tekst i slike u privremenoj memoriji</translation>
<translation id="4726672564094551039">Ponovo uÄitaj smernice</translation>
<translation id="4728558894243024398">Platforma</translation>
@@ -1194,6 +1231,7 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="4757993714154412917">Upravo ste uneli lozinku na obmanjujucÌem sajtu. Da biste zaÅ¡titili naloge, Chromium preporuÄuje da proverite saÄuvane lozinke.</translation>
<translation id="4758311279753947758">Dodaj kontakt informacije</translation>
<translation id="4761104368405085019">KoriÅ¡cÌenje mikrofona</translation>
+<translation id="4761869838909035636">Pokrenite Chrome bezbednosnu proveru</translation>
<translation id="4764776831041365478">MogucÌe je da veb-stranica na adresi <ph name="URL" /> privremeno ne funkcioniÅ¡e ili da je trajno premeÅ¡tena na novu veb adresu.</translation>
<translation id="4766713847338118463">Dvostruko spajanje na dnu</translation>
<translation id="4771973620359291008">Došlo je do nepoznate greške.</translation>
@@ -1214,12 +1252,6 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="4819347708020428563">Želite li da izmenite komentare u podrazumevanom prikazu?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />, pritisnite Tab, pa Enter da biste brzo napravili novu Google tabelu</translation>
<translation id="4825507807291741242">MocÌno</translation>
-<translation id="4827402517081186284">Režim bez arhiviranja vas ne Äini nevidljivim onlajn:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />sajtovi znaju da ih posecÌujete<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />poslodavci ili Å¡kole mogu da prate aktivnosti pregledanja<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />internet provajderi mogu da prate saobracÌaj na vebu<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">UkljuÄi upozorenja</translation>
<translation id="4838327282952368871">ÄŒarobno</translation>
<translation id="4840250757394056958">Pregledajte istoriju Chrome-a</translation>
@@ -1231,12 +1263,12 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="4854362297993841467">Ovaj naÄin isporuke nije dostupan. Isprobajte neki drugi naÄin.</translation>
<translation id="4854853140771946034">Brzo napravite novu belešku u Google Keep-u</translation>
<translation id="485902285759009870">Kôd se verifikuje...</translation>
+<translation id="4866506163384898554">Pritisnite |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| da bi se pokazivaÄ prikazao</translation>
<translation id="4876188919622883022">Pojednostavljeni prikaz</translation>
<translation id="4876305945144899064">Nema korisniÄkog imena</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{Nijedna}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}one{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}few{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831">Pretraga <ph name="TEXT" /></translation>
<translation id="4879491255372875719">Automatski (podrazumevano)</translation>
-<translation id="4879725228911483934">da otvara i postavlja prozore na ekrane</translation>
<translation id="4880827082731008257">Pretraži istoriju</translation>
<translation id="4881695831933465202">Otvori</translation>
<translation id="4885256590493466218">PlacÌajte pomocÌu kartice <ph name="CARD_DETAIL" /></translation>
@@ -1245,6 +1277,7 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">Deveti kotur</translation>
<translation id="4901778704868714008">SaÄuvaj...</translation>
+<translation id="4905659621780993806">Administrator cÌe automatski restartovati ureÄ‘aj u <ph name="TIME" />, <ph name="DATE" />. SaÄuvajte otvorene stavke pre nego Å¡to se ureÄ‘aj restartuje.</translation>
<translation id="4913987521957242411">Bušenje u gornjem levom uglu</translation>
<translation id="4918221908152712722">Instalirajte aplikaciju <ph name="APP_NAME" /> (ne treba da je preuzimate)</translation>
<translation id="4923459931733593730">PlacÌanje</translation>
@@ -1253,6 +1286,7 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, pritisnite Tab, pa Enter da biste pretražili</translation>
<translation id="4930153903256238152">Veliki kapacitet</translation>
+<translation id="4940163644868678279">Bez arhiviranja u Chrome-u</translation>
<translation id="4943872375798546930">Nema rezultata</translation>
<translation id="4950898438188848926">Dugme za promenu kartice, pritisnite Enter da biste prešli na otvorenu karticu, <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="495170559598752135">Radnje</translation>
@@ -1262,6 +1296,7 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="4968522289500246572">Ova aplikacija je dizajnirana za mobilne ureÄ‘aje i možda necÌe promeniti veliÄinu na pravilan naÄin. Možda cÌe imati probleme ili se restartovati.</translation>
<translation id="4969341057194253438">Izbriši snimak</translation>
<translation id="4973922308112707173">Dvostruko bušenje na vrhu</translation>
+<translation id="4976702386844183910">Poslednja poseta: <ph name="DATE" /></translation>
<translation id="4984088539114770594">DozvolicÌete koriÅ¡cÌenje mikrofona?</translation>
<translation id="4984339528288761049">Prc5 (koverat)</translation>
<translation id="4989163558385430922">Prikaži sve</translation>
@@ -1323,6 +1358,7 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="5138227688689900538">Prikaži manje</translation>
<translation id="5145883236150621069">Kôd greške je prisutan u odgovoru na smernice</translation>
<translation id="5146995429444047494">Obaveštenja za <ph name="ORIGIN" /> su blokirana</translation>
+<translation id="514704532284964975"><ph name="URL" /> želi da vidi i menja informacije na NFC uređajima koje dodirujete telefonom</translation>
<translation id="5148809049217731050">Sa odštampanom stranom nagore</translation>
<translation id="515292512908731282">C4 (koverat)</translation>
<translation id="5158275234811857234">Korice</translation>
@@ -1347,6 +1383,7 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="5215116848420601511">NaÄini placÌanja i adrese iz Google Pay-a</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">13. fioka</translation>
+<translation id="5216942107514965959">Poslednji posecÌen danas</translation>
<translation id="5222812217790122047">Imejl je obavezan</translation>
<translation id="5230733896359313003">Adresa za isporuku</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1367,7 +1404,6 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">Svojstva dokumenta</translation>
<translation id="528468243742722775">Završi</translation>
-<translation id="5284909709419567258">Mrežne adrese</translation>
<translation id="5285570108065881030">Prikaži sve saÄuvane lozinke</translation>
<translation id="5287240709317226393">Prikaži kolaÄicÌe</translation>
<translation id="5287456746628258573">Ovaj sajt koristi zastarelu bezbednosnu konfiguraciju, koja može da otkrije vaše informacije (na primer, lozinke ili brojeve kreditnih kartica) kada se šalju na njega.</translation>
@@ -1451,6 +1487,7 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="5556459405103347317">UÄitaj ponovo</translation>
<translation id="5560088892362098740">Datum isteka</translation>
<translation id="55635442646131152">Struktura dokumenta</translation>
+<translation id="5565613213060953222">Otvori karticu bez arhiviranja</translation>
<translation id="5565735124758917034">Aktivno</translation>
<translation id="5570825185877910964">Zaštiti nalog</translation>
<translation id="5571083550517324815">Preuzimanje sa ove adrese nije mogucÌe. Izaberite drugu adresu.</translation>
@@ -1533,6 +1570,7 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="5869522115854928033">SaÄuvane lozinke</translation>
<translation id="5873013647450402046">Banka želi da potvrdi da ste to vi.</translation>
<translation id="5887400589839399685">Kartica je saÄuvana</translation>
+<translation id="5887687176710214216">Poslednja poseta: juÄe</translation>
<translation id="5895138241574237353">Pokreni ponovo</translation>
<translation id="5895187275912066135">Izdato</translation>
<translation id="5901630391730855834">Žuta</translation>
@@ -1546,6 +1584,7 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="5921639886840618607">Želite li da saÄuvate karticu na Google nalogu?</translation>
<translation id="5922853866070715753">Skoro je gotovo</translation>
<translation id="5932224571077948991">Sajt prikazuje oglase koji ometaju aktivnosti ili obmanjujucÌe oglase</translation>
+<translation id="5938153366081463283">Dodajte virtuelnu karticu</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347">Otvara se <ph name="SITE_NAME" />…</translation>
<translation id="5951495562196540101">Registracija korisniÄkog naloga nije uspela (dostupna je licenca paketa).</translation>
@@ -1610,6 +1649,7 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="6120179357481664955">Želite da saÄuvate ID za UPI?</translation>
<translation id="6124432979022149706">PrikljuÄci za Chrome za preduzecÌa</translation>
<translation id="6127379762771434464">Uklonili ste stavku</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Saznajte više o režimu Bez arhiviranja u Chrome-u<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">Proverite sve kablove i restartujte sve rutere, modeme ili druge mrežne uređaje koje možda koristite.</translation>
<translation id="614940544461990577">Pokušajte:</translation>
<translation id="6150036310511284407">Trostruko bušenje na levoj strani</translation>
@@ -1621,7 +1661,6 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="6169916984152623906">Sada možete da pregledate privatno i drugi ljudi koji koriste ovaj ureÄ‘aj necÌe videti vaÅ¡e aktivnosti. MeÄ‘utim, preuzimanja i obeleživaÄi cÌe biti saÄuvani.</translation>
<translation id="6177128806592000436">Veza sa ovim sajtom nije bezbedna</translation>
<translation id="6180316780098470077">Interval između ponovnih pokušaja</translation>
-<translation id="619448280891863779">Može da traži da otvara i postavlja prozore na ekranima</translation>
<translation id="6196640612572343990">Blokiraj kolaÄicÌe trecÌe strane</translation>
<translation id="6203231073485539293">Proverite internet vezu</translation>
<translation id="6218753634732582820">Želite li da uklonite adresu iz Chromium-a?</translation>
@@ -1644,7 +1683,7 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="6272383483618007430">Google ažuriranje</translation>
<translation id="6276112860590028508">Stranice sa liste za Äitanje cÌe se pojaviti ovde</translation>
<translation id="627746635834430766">Da biste sledecÌi put platili brže, saÄuvajte karticu i adresu za obraÄun na Google nalogu.</translation>
-<translation id="6279098320682980337">Broj virtuelne kartice nije unet? Kliknite na podatke o kartici da biste ih kopirali</translation>
+<translation id="6279183038361895380">Pritisnite |<ph name="ACCELERATOR" />| da biste prikazali pokazivaÄ</translation>
<translation id="6280223929691119688">Isporuka na ovu adresu nije mogucÌa. Izaberite drugu adresu.</translation>
<translation id="6282194474023008486">Poštanski broj</translation>
<translation id="6285507000506177184">Dugme za upravljanje preuzimanjima u Chrome-u, pritisnite Enter da biste upravljali fajlovima koje ste preuzeli u Chrome-u</translation>
@@ -1652,6 +1691,7 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="6290238015253830360">Predloženi Älanci se prikazuju ovde</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{UreÄ‘aj cÌe se restartovati}=1{UreÄ‘aj cÌe se restartovati za 1 sekundu}one{UreÄ‘aj cÌe se restartovati za # sekundu}few{UreÄ‘aj cÌe se restartovati za # sekunde}other{UreÄ‘aj cÌe se restartovati za # sekundi}}</translation>
<translation id="6302269476990306341">Google pomocÌnik u Chrome-u se zaustavlja</translation>
<translation id="6305205051461490394">URL <ph name="URL" /> nije dostupan.</translation>
<translation id="6312113039770857350">Veb-stranica nije dostupna</translation>
@@ -1725,6 +1765,7 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="6529602333819889595">&amp;Ponovi brisanje</translation>
<translation id="6545864417968258051">Bluetooth skeniranje</translation>
<translation id="6547208576736763147">Dvostruko bušenje na levoj strani</translation>
+<translation id="6554732001434021288">Poslednja poseta: pre <ph name="NUM_DAYS" /> dana</translation>
<translation id="6556866813142980365">Ponovi</translation>
<translation id="6569060085658103619">Pregledate stranicu dodatka.</translation>
<translation id="6573200754375280815">Dvostruko bušenje na desnoj strani</translation>
@@ -1785,7 +1826,6 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="6757797048963528358">Uređaj je prešao u režim spavanja.</translation>
<translation id="6767985426384634228">Želite da ažurirate adresu?</translation>
<translation id="6768213884286397650">Hagaki (razglednica)</translation>
-<translation id="6774185088257932239"><ph name="BEGIN_LINK" />Saznajte više<ph name="END_LINK" /> o režimu bez arhiviranja</translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">LjubiÄasta</translation>
<translation id="6786747875388722282">Dodaci</translation>
@@ -1869,7 +1909,6 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="706295145388601875">Dodajte adrese i upravljajte njima u podešavanjima Chrome-a</translation>
<translation id="7064851114919012435">Kontakt informacije</translation>
<translation id="7068733155164172741">Unesite <ph name="OTP_LENGTH" />-cifreni kôd</translation>
-<translation id="7070090581017165256">O ovom sajtu</translation>
<translation id="70705239631109039">Veza nije potpuno bezbedna</translation>
<translation id="7075452647191940183">Zahtev je prevelik</translation>
<translation id="7079718277001814089">Ovaj sajt sadrži malver</translation>
@@ -1886,6 +1925,12 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="7111012039238467737">(VažecÌi)</translation>
<translation id="7118618213916969306">Potražite URL u privremenoj memoriji, <ph name="SHORT_URL" /></translation>
<translation id="7119414471315195487">Zatvorite druge kartice ili programe</translation>
+<translation id="7129355289156517987">Kada zatvorite sve Chromium kartice bez arhiviranja, aktivnost na tim karticama se briše sa uređaja:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Aktivnosti pregledanja<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Istorija pretrage<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Informacije unete u obrascima<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">Slanje na ovu adresu nije mogucÌe. Izaberite drugu adresu.</translation>
<translation id="7132939140423847331">Administrator je zabranio kopiranje ovih podataka.</translation>
<translation id="7135130955892390533">Prikaži status</translation>
@@ -1908,6 +1953,7 @@ To inaÄe blokiraju podeÅ¡avanja privatnosti. To omogucÌava da sadržaj sa koji
<translation id="7192203810768312527">OslobodicÌe se <ph name="SIZE" />. Neki sajtovi cÌe se sporije uÄitavati pri sledecÌoj poseti.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">Administrator može da vidi:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, pritisnite Tab, pa Enter da biste otvorili novu karticu bez arhiviranja i pregledali privatno</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423">Host <ph name="HOST_NAME" /> ne poštuje bezbednosne standarde.</translation>
<translation id="7210993021468939304">Linux aktivnosti unutar kontejnera i može da instalira i pokrecÌe Linux aplikacije unutar kontejnera</translation>
@@ -1939,6 +1985,7 @@ Dodatni detalji:
<translation id="7304562222803846232">Upravljajte podešavanjima privatnosti Google naloga</translation>
<translation id="7305756307268530424">PoÄnite sporije</translation>
<translation id="7308436126008021607">sinhronizacija u pozadini</translation>
+<translation id="7310392214323165548">UreÄ‘aj cÌe se restartovati veoma brzo</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">PomocÌ pri povezivanju</translation>
<translation id="7323804146520582233">Sakrijte odeljak <ph name="SECTION" /></translation>
@@ -1946,6 +1993,7 @@ Dodatni detalji:
<translation id="7334320624316649418">&amp;Ponovi promenu redosleda</translation>
<translation id="7335157162773372339">Može da traži da koristi kameru</translation>
<translation id="7337248890521463931">Prikaži više redova</translation>
+<translation id="7337418456231055214">Broj virtuelne kartice nije unet? Kliknite na podatke o kartici da biste ih kopirali. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">Nije dostupno na vašoj platformi.</translation>
<translation id="733923710415886693">Sertifikat servera nije otkriven pomocÌu Transparentnosti sertifikata.</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1968,6 +2016,7 @@ Dodatni detalji:
<translation id="7378627244592794276">Ne</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">Nije primenjivo</translation>
+<translation id="7388594495505979117">{0,plural, =1{UreÄ‘aj cÌe se restartovati za 1 minut}one{UreÄ‘aj cÌe se restartovati za # minut}few{UreÄ‘aj cÌe se restartovati za # minuta}other{UreÄ‘aj cÌe se restartovati za # minuta}}</translation>
<translation id="7390545607259442187">Potvrdite karticu</translation>
<translation id="7392089738299859607">Ažurirajte adresu</translation>
<translation id="7399802613464275309">Bezbednosna provera</translation>
@@ -2004,6 +2053,12 @@ Dodatni detalji:
<translation id="7485870689360869515">Nisu pronađeni podaci.</translation>
<translation id="7495528107193238112">Ovaj sadržaj je blokiran. Obratite se vlasniku sajta da biste rešili problem.</translation>
<translation id="7497998058912824456">Dugme Napravite dokument, pritisnite Enter da biste brzo napravili nov Google dokument</translation>
+<translation id="7506488012654002225">Chromium <ph name="BEGIN_EMPHASIS" />ne Äuva<ph name="END_EMPHASIS" /> sledecÌe informacije:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />istoriju pregledanja
+ <ph name="LIST_ITEM" />kolaÄicÌe i podatke o sajtovima
+ <ph name="LIST_ITEM" />informacije koje unosite u obrascima
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">VracÌeni ID ureÄ‘aja za smernice je prazan ili se ne podudara sa aktuelnim ID-om ureÄ‘aja</translation>
<translation id="7508870219247277067">Zelenožuta</translation>
<translation id="7511955381719512146">WiFi mreža koju koristite cÌe možda zahtevati da posetite <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
@@ -2117,7 +2172,6 @@ Dodatni detalji:
<translation id="7813600968533626083">Želite li da uklonite predlog iz Chrome-a?</translation>
<translation id="781440967107097262">DozvolicÌete deljenje privremene memorije?</translation>
<translation id="7815407501681723534">Pronašli smo <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> za „<ph name="SEARCH_STRING" />“</translation>
-<translation id="782125616001965242">Prikazuje informacije o ovom sajtu</translation>
<translation id="782886543891417279">WiFi mreža koju koristite (<ph name="WIFI_NAME" />) cÌe možda zahtevati da posetite stranicu za prijavljivanje.</translation>
<translation id="7836231406687464395">Postfix (koverat)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{Nijedna}=1{1 aplikacija (<ph name="EXAMPLE_APP_1" />)}=2{2 aplikacije (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}one{# aplikacija (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}few{# aplikacije (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}other{# aplikacija (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}}</translation>
@@ -2134,7 +2188,6 @@ Dodatni detalji:
<translation id="7888575728750733395">Namera renderovanja Å¡tampanja</translation>
<translation id="7894280532028510793">Ako nema grešaka, <ph name="BEGIN_LINK" />pokrenite dijagnostiku mreže<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (koverat)</translation>
-<translation id="7931318309563332511">Nepoznato</translation>
<translation id="793209273132572360">Želite da ažurirate adresu?</translation>
<translation id="7932579305932748336">Omot</translation>
<translation id="79338296614623784">Unesite važecÌi broj telefona</translation>
@@ -2159,13 +2212,14 @@ Dodatni detalji:
<translation id="7976214039405368314">Previše je zahteva</translation>
<translation id="7977538094055660992">Izlazni uređaj</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">Povezana sa:</translation>
<translation id="798134797138789862">Može da traži da koristi uređaje i podatke virtuelne realnosti</translation>
<translation id="7984945080620862648">Trenutno ne možete da posetite <ph name="SITE" /> zato Å¡to je veb-sajt poslao Å¡ifrovane akreditive koje Chrome ne može da obradi. GreÅ¡ke i napadi na mreži su obiÄno privremeni, pa cÌe ova stranica verovatno funkcionisati kasnije.</translation>
-<translation id="79859296434321399">Da biste videli sadržaj proširene realnosti, instalirajte ARCore</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">Povezivanje</translation>
<translation id="7992044431894087211">Nastavljeno je deljenje sadržaja ekrana sa aplikacijom <ph name="APPLICATION_TITLE" /></translation>
<translation id="7995512525968007366">Nije navedeno</translation>
+<translation id="7998269595945679889">Pritisnite dugme Otvori karticu bez arhiviranja, pa Enter da biste otvorili novu karticu bez arhiviranja i pregledali privatno</translation>
<translation id="800218591365569300">Probajte da zatvorite druge kartice ili programe da biste oslobodili memoriju.</translation>
<translation id="8004582292198964060">PregledaÄ</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{Ta kartica i njena adresa za obraÄun cÌe biti saÄuvane. MocÌi cÌete da je koristite kada ste prijavljeni na <ph name="USER_EMAIL" />.}one{Te kartice i njihove adrese za obraÄun cÌe biti saÄuvane. MocÌi cÌete da ih koristite kada ste prijavljeni na <ph name="USER_EMAIL" />.}few{Te kartice i njihove adrese za obraÄun cÌe biti saÄuvane. MocÌi cÌete da ih koristite kada ste prijavljeni na <ph name="USER_EMAIL" />.}other{Te kartice i njihove adrese za obraÄun cÌe biti saÄuvane. MocÌi cÌete da ih koristite kada ste prijavljeni na <ph name="USER_EMAIL" />.}}</translation>
@@ -2225,6 +2279,7 @@ Dodatni detalji:
<translation id="8202370299023114387">Neusaglašenost</translation>
<translation id="8206978196348664717">Prc4 (koverat)</translation>
<translation id="8211406090763984747">Veza je bezbedna</translation>
+<translation id="8217240300496046857">Sajtovi ne mogu da koriste kolaÄicÌe koji vas prate na vebu. Funkcije na nekim sajtovima mogu da prestanu sa radom.</translation>
<translation id="8218327578424803826">Dodeljena lokacija:</translation>
<translation id="8220146938470311105">C7/C6 (koverat)</translation>
<translation id="8225771182978767009">Osoba koja je podesila ovaj raÄunar je odluÄila da blokira ovaj sajt.</translation>
@@ -2265,14 +2320,9 @@ Dodatni detalji:
<translation id="830498451218851433">Presavijanje napola</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">Instalirane aplikacije i koliko Äesto se koriste</translation>
+<translation id="8317207217658302555">Želite da ažurirate ARCore?</translation>
<translation id="831997045666694187">UveÄe</translation>
<translation id="8321476692217554900">obaveštenja</translation>
-<translation id="8328484624016508118">Kada zatvorite sve kartice bez arhiviranja, Chrome briše:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />aktivnosti pregledanja sa ovog uređaja<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />istoriju pretrage sa ovog uređaja<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />informacije unesene preko obrazaca<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489">Pristup hostu <ph name="HOST_NAME" /> je odbijen</translation>
<translation id="833262891116910667">Isticanje</translation>
<translation id="8339163506404995330">Stranice na jeziku <ph name="LANGUAGE" /> se necÌe prevoditi</translation>
@@ -2324,6 +2374,7 @@ Dodatni detalji:
<translation id="8507227106804027148">Komandna linija</translation>
<translation id="8508648098325802031">Ikona Pretraga</translation>
<translation id="8511402995811232419">Upravljajte kolaÄicÌima</translation>
+<translation id="8519753333133776369">Administrator je dozvolio HID uređaj</translation>
<translation id="8522552481199248698">Chrome može da vam pomogne da zaštitite Google nalog i promenite lozinku.</translation>
<translation id="8530813470445476232">ObriÅ¡ite istoriju pregledanja, kolaÄicÌe, keÅ¡ i drugo u podeÅ¡avanjima Chrome-a</translation>
<translation id="8533619373899488139">Posetite &lt;strong&gt;chrome://policy&lt;/strong&gt; da biste videli listu blokiranih URL-ova i druge smernice koje je odredio administrator sistema.</translation>
@@ -2335,7 +2386,6 @@ Dodatni detalji:
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{Resetuj dozvolu}one{Resetuj dozvole}few{Resetuj dozvole}other{Resetuj dozvole}}</translation>
<translation id="8555010941760982128">Koristite ovaj kôd pri placÌanju</translation>
<translation id="8557066899867184262">CVC je na poleđini kartice.</translation>
-<translation id="8558485628462305855">Da biste videli sadržaj proširene realnosti, ažurirajte ARCore</translation>
<translation id="8559762987265718583">Nije mogucÌe uspostaviti privatnu vezu sa domenom <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> jer datum i vreme na ureÄ‘aju (<ph name="DATE_AND_TIME" />) nisu taÄni.</translation>
<translation id="8564182942834072828">Odvojeni dokumenti/nesređene kopije</translation>
<translation id="8564985650692024650">Chromium vam preporuÄuje da resetujete lozinku za <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> ako ste je koristili na drugim sajtovima.</translation>
@@ -2355,6 +2405,7 @@ Dodatni detalji:
<translation id="865032292777205197">senzori za pokret</translation>
<translation id="8663226718884576429">Rezime porudžbine, <ph name="TOTAL_LABEL" />, još detalja</translation>
<translation id="8666678546361132282">engleski</translation>
+<translation id="8669306706049782872">Koristi informacije o ekranima da bi otvarao i postavljao prozore</translation>
<translation id="867224526087042813">Potpis</translation>
<translation id="8676424191133491403">Bez odlaganja</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, odgovor, <ph name="ANSWER" /></translation>
@@ -2381,6 +2432,7 @@ Dodatni detalji:
<translation id="8731544501227493793">Dugme Upravljaj lozinkama, pritisnite Enter da biste pregledali lozinke i upravljali njima u podešavanjima Chrome-a</translation>
<translation id="8734529307927223492"><ph name="DEVICE_TYPE" />-om upravlja <ph name="MANAGER" /></translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, pritisnite Tab, pa Enter da biste otvorili nov prozor bez arhiviranja i pregledali privatno</translation>
+<translation id="8737685506611670901">otvori linkove za <ph name="PROTOCOL" /> umesto <ph name="REPLACED_HANDLER_TITLE" /></translation>
<translation id="8738058698779197622">Da biste uspostavili bezbednu vezu, sat na ureÄ‘aju mora da bude taÄan. To je zato Å¡to sertifikati koje veb-sajtovi koriste za identifikaciju važe samo odreÄ‘eni vremenski period. PoÅ¡to sat na vaÅ¡em ureÄ‘aju nije taÄan, Chromium ne može da verifikuje ove sertifikate.</translation>
<translation id="8740359287975076522">Nismo uspeli da pronaÄ‘emo &lt;abbr id="dnsDefinition"&gt;DNS adresu&lt;/abbr&gt; hosta <ph name="HOST_NAME" />. PokuÅ¡avamo da utvrdimo u Äemu je problem.</translation>
<translation id="8742371904523228557"><ph name="ONE_TIME_CODE" /> je vaš kôd za <ph name="ORIGIN" /></translation>
@@ -2408,6 +2460,7 @@ Dodatni detalji:
<translation id="883848425547221593">Ostali obeleživaÄi</translation>
<translation id="884264119367021077">Adresa za isporuku</translation>
<translation id="884923133447025588">Nije pronađen nijedan mehanizam opoziva.</translation>
+<translation id="8849262850971482943">Koristite virtuelnu karticu radi dodatne bezbednosti</translation>
<translation id="885730110891505394">Deljenje sa Google-om</translation>
<translation id="8858065207712248076">Chrome vam preporuÄuje da resetujete lozinku za <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> ako ste je koristili na drugim sajtovima.</translation>
<translation id="885906927438988819">Ako nema grešaka, <ph name="BEGIN_LINK" />pokrenite Windows dijagnostiku mreže<ph name="END_LINK" />.</translation>
@@ -2457,6 +2510,7 @@ Dodatni detalji:
<translation id="9004367719664099443">VR sesija je u toku</translation>
<translation id="9005998258318286617">UÄitavanje PDF dokumenta nije uspelo.</translation>
<translation id="9008201768610948239">Ignoriši</translation>
+<translation id="901834265349196618">imejl</translation>
<translation id="9020200922353704812">Adresa za obraÄun za karticu je obavezna</translation>
<translation id="9020542370529661692">Ova stranica je prevedena na <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9020742383383852663">A8</translation>
@@ -2505,6 +2559,7 @@ Dodatni detalji:
<translation id="9150045010208374699">KoriÅ¡cÌenje kamere</translation>
<translation id="9150685862434908345">Administrator može daljinski da promeni podeÅ¡avanje pregledaÄa. Aktivnostima na ovom ureÄ‘aju se možda upravlja i van Chrome-a. <ph name="BEGIN_LINK" />Saznajte viÅ¡e<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">Ažurirano</translation>
+<translation id="9155211586651734179">Audio periferni ureÄ‘aji su prikljuÄeni</translation>
<translation id="9157595877708044936">Podešavanje...</translation>
<translation id="9158625974267017556">C6 (koverat)</translation>
<translation id="9164029392738894042">Provera taÄnosti</translation>
diff --git a/chromium/components/strings/components_strings_sr.xtb b/chromium/components/strings/components_strings_sr.xtb
index 30c7b4a6593..c75205dad51 100644
--- a/chromium/components/strings/components_strings_sr.xtb
+++ b/chromium/components/strings/components_strings_sr.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">Прикажи детаље</translation>
<translation id="1030706264415084469"><ph name="URL" /> жели трајно да Ñкладишти велике количине података на уређају</translation>
<translation id="1032854598605920125">Окрените у Ñмеру казаљке на Ñату</translation>
+<translation id="1033329911862281889">Режим без архивирања Ð²Ð°Ñ Ð½Ðµ чини невидљивим онлајн:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Сајтови и уÑлуге које кориÑтите могу да виде поÑете<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ПоÑлодавци или школе могу да прате активноÑти прегледања<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Интернет провајдери могу да прате Ñаобраћај на вебу<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">ИÑкључи</translation>
<translation id="1036982837258183574">ПритиÑните |<ph name="ACCELERATOR" />| да биÑте изашли из режима целог екрана</translation>
<translation id="1038106730571050514">Прикажите предлоге</translation>
<translation id="1038842779957582377">непознато име</translation>
<translation id="1041998700806130099">Порука о радном лиÑту</translation>
<translation id="1048785276086539861">Када измените коментаре, овај документ Ñе враћа на приказ појединачне Ñтранице.</translation>
-<translation id="1049743911850919806">Без архивирања</translation>
<translation id="1050038467049342496">Затворите друге апликације</translation>
<translation id="1055184225775184556">&amp;Опозови додавање</translation>
<translation id="1056898198331236512">Упозорење</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">Кеш Ñмерница је у реду</translation>
<translation id="1130564665089811311">Дугме Преведи Ñтраницу, притиÑните Enter да биÑте превели ову Ñтраницу помоћу Google преводиоца</translation>
<translation id="1131264053432022307">Копирана Ñлика</translation>
+<translation id="1142846828089312304">Блокирај колачиће трећих Ñтрана у режиму без архивирања</translation>
<translation id="1150979032973867961">Овај Ñервер не може да докаже да је <ph name="DOMAIN" />; оперативни ÑиÑтем рачунара нема поверења у његов безбедноÑни Ñертификат. Узрок томе је можда погрешна конфигурација или нападач који је прекинуо везу.</translation>
<translation id="1151972924205500581">Лозинка је обавезна</translation>
<translation id="1156303062776767266">Прегледате локалну или дељену датотеку</translation>
@@ -64,7 +70,6 @@
<translation id="1178581264944972037">Паузирај</translation>
<translation id="1181037720776840403">Уклони</translation>
<translation id="1186201132766001848">Провери лозинке</translation>
-<translation id="1195210374336998651">Отвори подешавања апликације</translation>
<translation id="1195558154361252544">Обавештења Ñу аутоматÑки блокирана за Ñве Ñајтове оÑим за оне које омогућите</translation>
<translation id="1197088940767939838">ÐаранџаÑта</translation>
<translation id="1201402288615127009">Даље</translation>
@@ -111,7 +116,7 @@
<translation id="1307966114820526988">ЗаÑтареле функције</translation>
<translation id="1308113895091915999">Понуда је доÑтупна</translation>
<translation id="1312803275555673949">Који докази подржавају ово?</translation>
-<translation id="131405271941274527"><ph name="URL" /> жели да шаље и добија информације када телефоном додирнете NFC уређај</translation>
+<translation id="1314311879718644478">Прегледајте Ñадржај Ñа проширеном реалношћу</translation>
<translation id="1314509827145471431">Повез на деÑној Ñтрани</translation>
<translation id="1318023360584041678">Сачувано је у групи картица</translation>
<translation id="1319245136674974084">Ðе питај поново за ову апликацију</translation>
@@ -161,6 +166,7 @@
<translation id="142858679511221695">КориÑник уÑлуге у клауду</translation>
<translation id="1428729058023778569">Ово упозорење вам Ñе приказује јер овај Ñајт не подржава HTTPS. <ph name="BEGIN_LEARN_MORE_LINK" />Сазнајте више<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">Штампај</translation>
+<translation id="1432187715652018471">Страница жели да инÑталира обрађивача уÑлуге.</translation>
<translation id="1432581352905426595">Управљај претраживачима</translation>
<translation id="1436185428532214179">Може да тражи да мења фајлове и фолдере на уређају</translation>
<translation id="1442386063175183758">ПреÑавијање на деÑној Ñтрани у облику прозора</translation>
@@ -181,6 +187,12 @@
<translation id="1483493594462132177">Пошаљи</translation>
<translation id="1484290072879560759">Одаберите адреÑу за иÑпоруку</translation>
<translation id="1492194039220927094">Слање Ñмерница:</translation>
+<translation id="149293076951187737">Када затворите Ñве Chrome картице без архивирања, активноÑÑ‚ на тим картицама Ñе брише Ñа уређаја:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ÐктивноÑти прегледања<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ИÑторија претраге<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Информације унете у обраÑцима<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">Ðазад на картицу</translation>
<translation id="1501859676467574491">Приказуј картице Ñа мог Google налога</translation>
<translation id="1507202001669085618">&lt;p&gt;Ова грешка Ñе приказује ако кориÑтите WiFi портал на коме морате да Ñе пријавите да биÑте Ñе повезали на интернет.&lt;/p&gt;
@@ -208,6 +220,8 @@
<translation id="1559572115229829303">&lt;p&gt;Ðије могуће уÑпоÑтавити приватну везу Ñа доменом <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> јер датум и време на уређају (<ph name="DATE_AND_TIME" />) ниÑу тачни.&lt;/p&gt;
&lt;p&gt;Прилагодите датум и време у одељку &lt;strong&gt;Опште&lt;/strong&gt; у апликацији &lt;strong&gt;Подешавања&lt;/strong&gt;.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">ÐдминиÑтратор ће реÑтартовати уређај у <ph name="TIME" /> <ph name="DATE" /></translation>
+<translation id="156703335097561114">Информације о мрежама попут адреÑа, конфигурације интерфејÑа и квалитета везе</translation>
<translation id="1567040042588613346">Ове Ñмернице раде као што је предвиђено, али иÑта вредноÑÑ‚ је подешена на другом меÑту и замењују је ове Ñмернице.</translation>
<translation id="1569487616857761740">УнеÑите датум иÑтека</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@
<translation id="1583429793053364125">Дошло је до грешке при приказивању ове веб-Ñтранице.</translation>
<translation id="1586541204584340881">додатке које Ñте инÑталирали</translation>
<translation id="1588438908519853928">Ðормалан</translation>
+<translation id="1589050138437146318">Желите да инÑталирате ARCore?</translation>
<translation id="1592005682883173041">ПриÑтуп локалним подацима</translation>
<translation id="1594030484168838125">Одабери</translation>
<translation id="160851722280695521">Играјте игру ДиноÑÐ°ÑƒÑ€ÑƒÑ Ñƒ Chrome-у</translation>
@@ -254,7 +269,7 @@
<translation id="1711234383449478798">Занемарено јер <ph name="POLICY_NAME" /> нема вредноÑÑ‚ <ph name="VALUE" />.</translation>
<translation id="1712552549805331520"><ph name="URL" /> жели трајно да Ñкладишти податке на локалном рачунару</translation>
<translation id="1713628304598226412">2. фиока</translation>
-<translation id="1715874602234207">F</translation>
+<translation id="1715874602234207">П</translation>
<translation id="1717218214683051432">Сензори покрета</translation>
<translation id="1717494416764505390">3. поштанÑко Ñандуче</translation>
<translation id="1718029547804390981">Документ је иÑувише велики да биÑте му додали напомене</translation>
@@ -283,6 +298,7 @@
формат заглавља је нетачан, што Ñпречава прегледач да иÑпуни
захтев за <ph name="SITE" />. Помоћу Ñмерница за порекло
оператори Ñајтова могу да конфигуришу безбедноÑÑ‚ и друга ÑвојÑтва за Ñајт.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Сазнајте више о режиму Без архивирања у Chromium-у<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">Отворене картице Ñе појављују овде</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -410,6 +426,7 @@
<translation id="22081806969704220">3. фиока</translation>
<translation id="2212735316055980242">Смернице ниÑу пронађене</translation>
<translation id="2213606439339815911">Преузимање уноÑа...</translation>
+<translation id="2213612003795704869">Страница је одштампана</translation>
<translation id="2215727959747642672">Мењање датотека</translation>
<translation id="2218879909401188352">Ðападачи који Ñу тренутно на <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> могу да инÑталирају опаÑне апликације које ће вам оштетити уређај, додати нежељене трошкове код мобилног оператера или украÑти личне податке. <ph name="BEGIN_LEARN_MORE_LINK" />Сазнајте више<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">Ðема интернета</translation>
@@ -419,6 +436,7 @@
<translation id="2248949050832152960">КориÑти WebAuthn</translation>
<translation id="2250931979407627383">Спајање ивица шавом на левој Ñтрани</translation>
<translation id="225207911366869382">Ова вредноÑÑ‚ је заÑтарела за ове Ñмернице.</translation>
+<translation id="2256115617011615191">РеÑтартуј одмах</translation>
<translation id="2258928405015593961">УнеÑите датум иÑтека који је у будућноÑти и пробајте поново</translation>
<translation id="225943865679747347">Кôд грешке: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">HTTP грешка</translation>
@@ -446,6 +464,7 @@
<translation id="2337852623177822836">Подешавање контролише админиÑтратор</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> жели да Ñе упари</translation>
<translation id="2346319942568447007">Копирана Ñлика</translation>
+<translation id="2350796302381711542">Желите ли да дозволите да <ph name="HANDLER_HOSTNAME" /> отвара Ñве <ph name="PROTOCOL" /> линкове за које Ñте до Ñада кориÑтили <ph name="REPLACED_HANDLER_TITLE" />?</translation>
<translation id="2354001756790975382">ОÑтали обележивачи</translation>
<translation id="2354430244986887761">Google безбедно прегледање је недавно <ph name="BEGIN_LINK" />открило штетне апликације<ph name="END_LINK" /> на <ph name="SITE" />.</translation>
<translation id="2355395290879513365">Ðападачи ће моћи да виде Ñлике које гледате на овом Ñајту и да их измене како би Ð²Ð°Ñ Ð¿Ñ€ÐµÐ²Ð°Ñ€Ð¸Ð»Ð¸.</translation>
@@ -471,6 +490,7 @@
<translation id="2413528052993050574">Овај Ñервер не може да докаже да је <ph name="DOMAIN" />; његов безбедноÑни Ñертификат ће можда бити опозван. Узрок томе је можда погрешна конфигурација или нападач који је прекинуо везу.</translation>
<translation id="2414886740292270097">Тамнa</translation>
<translation id="2430968933669123598">Управљајте Google налогом, притиÑните Enter да биÑте управљали информацијама, приватношћу и безбедношћу на Google налогу</translation>
+<translation id="2436186046335138073">Желите ли да дозволите да <ph name="HANDLER_HOSTNAME" /> отвара Ñве <ph name="PROTOCOL" /> линкове?</translation>
<translation id="2438874542388153331">ЧетвороÑтруко бушење на деÑној Ñтрани</translation>
<translation id="2450021089947420533">Путеви</translation>
<translation id="2463739503403862330">Попуни</translation>
@@ -478,6 +498,7 @@
<translation id="2465655957518002998">Одаберите начин доÑтаве</translation>
<translation id="2465688316154986572">Спајање</translation>
<translation id="2465914000209955735">Управљајте фајловима које Ñте преузели у Chrome-у</translation>
+<translation id="2466004615675155314">Приказује информације Ñа веба</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />да покренете дијагноÑтику мреже<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">РедоÑлед од 1 до n</translation>
<translation id="2470767536994572628">Када измените коментаре, овај документ Ñе враћа на приказ појединачне Ñтранице и у првобитни положај.</translation>
@@ -498,6 +519,7 @@
<translation id="2523886232349826891">Сачувано је Ñамо на овом уређају</translation>
<translation id="2524461107774643265">Додајте још информација</translation>
<translation id="2529899080962247600">Ово поље не Ñме да има више од <ph name="MAX_ITEMS_LIMIT" /> уноÑа. Сви будући уноÑи ће Ñе занемарити.</translation>
+<translation id="2535585790302968248">Отворите нову картицу без архивирања да биÑте прегледали приватно</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{и још 1}one{и још #}few{и још #}other{и још #}}</translation>
<translation id="2536110899380797252">Додај адреÑу</translation>
<translation id="2539524384386349900">Откриј</translation>
@@ -523,7 +545,14 @@
<translation id="2597378329261239068">Овај документ је заштићен лозинком. УнеÑите лозинку.</translation>
<translation id="2609632851001447353">Варијације</translation>
<translation id="2610561535971892504">Кликните да биÑте копирали</translation>
+<translation id="2617988307566202237">Chrome <ph name="BEGIN_EMPHASIS" />не чува<ph name="END_EMPHASIS" /> Ñледеће информације:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />иÑторију прегледања
+ <ph name="LIST_ITEM" />колачиће и податке о Ñајтовима
+ <ph name="LIST_ITEM" />информације које уноÑите у обраÑцима
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (коверат)</translation>
+<translation id="2623663032199728144">Може да затражи да кориÑти информације о екранима</translation>
<translation id="2625385379895617796">Сат вам жури</translation>
<translation id="262745152991669301">Може да тражи да Ñе повезује Ñа USB уређајима</translation>
<translation id="2629325967560697240">Да биÑте добили највиши ниво заштите у Chrome-у, <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />укључите побољшану заштиту<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -557,6 +586,7 @@
<translation id="2709516037105925701">ÐутоматÑко попуњавање</translation>
<translation id="2713444072780614174">Бела</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />, притиÑните Tab, па Enter да биÑте управљали плаћањима и информацијама о кредитним картицама у подешавањима Chrome-а</translation>
+<translation id="271663710482723385">ПритиÑните |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| да биÑте изашли из режима целог екрана</translation>
<translation id="2721148159707890343">Захтев је уÑпео</translation>
<translation id="2723669454293168317">Покрените проверу безбедноÑти у Chrome подешавањима</translation>
<translation id="2726001110728089263">Бочна фиока</translation>
@@ -587,6 +617,7 @@
<translation id="2850739647070081192">Invite (коверат)</translation>
<translation id="2856444702002559011">Ðападачи можда покушавају да украду информације Ñа <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (на пример, лозинке, поруке или кредитне картице). <ph name="BEGIN_LEARN_MORE_LINK" />Сазнајте више<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">Овај Ñајт приказује оглаÑе који ометају активноÑти или обмањујуће оглаÑе.</translation>
+<translation id="286512204874376891">Виртуелна картица крије вашу Ñтварну картицу да би Ð²Ð°Ñ Ð·Ð°ÑˆÑ‚Ð¸Ñ‚Ð¸Ð»Ð° од потенцијалне преваре. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">ПријатељÑки</translation>
<translation id="2876489322757410363">ÐапуÑтићете режим без архивирања да биÑте платили у Ñпољној апликацији. Желите ли да наÑтавите?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />, притиÑните Tab, па Enter да биÑте управљали Безбедним прегледањем и другим Ñадржајем у подешавањима Chrome-а</translation>
@@ -611,6 +642,7 @@
<translation id="2930577230479659665">Скрати поÑле Ñваког копирања</translation>
<translation id="2932085390869194046">Предложи лозинку...</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019">отвори линкове за <ph name="PROTOCOL" /></translation>
<translation id="2941952326391522266">Овај Ñервер не може да докаже да је <ph name="DOMAIN" />; његов безбедноÑни Ñертификат је Ñа домена <ph name="DOMAIN2" />. Узрок томе је можда погрешна конфигурација или нападач који је прекинуо везу.</translation>
<translation id="2943895734390379394">Време отпремања:</translation>
<translation id="2948083400971632585">Ðа Ñтраници Подешавања можете да онемогућите Ñве прокÑије конфигуриÑане за везу.</translation>
@@ -643,6 +675,7 @@
<translation id="3037605927509011580">О, не!</translation>
<translation id="3041612393474885105">Информације о Ñертификату</translation>
<translation id="3044034790304486808">ÐаÑтавите иÑтраживање</translation>
+<translation id="305162504811187366">ИÑторија Chrome удаљеног рачунара, укључујући временÑке ознаке, ИД-еве ÑеÑија хоÑтова и клијената</translation>
<translation id="3060227939791841287">C9 (коверат)</translation>
<translation id="3061707000357573562">УÑлуга крпљења</translation>
<translation id="306573536155379004">Игра је покренута.</translation>
@@ -683,6 +716,7 @@
<translation id="3197136577151645743">Може да тражи да зна када активно кориÑтите уређај</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />, притиÑните Tab, па Enter да биÑте управљали тиме које информације Ñинхронизујете у подешавањима Chrome-а</translation>
<translation id="320323717674993345">Откажи плаћање</translation>
+<translation id="3203366800380907218">Са веба</translation>
<translation id="3207960819495026254">Обележено</translation>
<translation id="3209034400446768650">Страница може да наплаћује</translation>
<translation id="3212581601480735796">Ваше активноÑти на <ph name="HOSTNAME" /> Ñе прате</translation>
@@ -699,10 +733,12 @@
<translation id="3234666976984236645">Увек откривај важан Ñадржај на овом Ñајту</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />, притиÑните Tab, па Enter да биÑте прилагодили изглед прегледача</translation>
<translation id="3240791268468473923">Отворено је обавештење да нема акредитива који Ñе подударају за безбедно плаћање</translation>
+<translation id="324180406144491771">Линкови хоÑта <ph name="HOST_NAME" /> Ñу блокирани</translation>
<translation id="3249845759089040423">Хипи</translation>
<translation id="3252266817569339921">француÑки</translation>
<translation id="3257954757204451555">Ко је извор ових информација?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />, притиÑните Tab, па Enter да биÑте брзо направили нов догађај у Google календару</translation>
+<translation id="3261488570342242926">Сазнајте више о виртуелним картицама</translation>
<translation id="3264837738038045344">Дугме за управљање подешавањима Chrome-а, притиÑните Enter да биÑте поÑетили подешавања Chrome-а</translation>
<translation id="3266793032086590337">ВредноÑÑ‚ (неуÑаглашена)</translation>
<translation id="3268451620468152448">Отворене картице</translation>
@@ -716,6 +752,7 @@
<translation id="3288238092761586174"><ph name="URL" /> треба да обави додатне кораке ради потврде плаћања</translation>
<translation id="3293642807462928945">Сазнајте више о Ñмерницама <ph name="POLICY_NAME" /></translation>
<translation id="3295444047715739395">Прегледајте лозинке и управљајте њима у подешавањима Chrome-а</translation>
+<translation id="3303795387212510132">Желите ли да дозволите да апликација отвара <ph name="PROTOCOL_SCHEME" /> линкове?</translation>
<translation id="3303855915957856445">ÐиÑу пронађени резултати претраге</translation>
<translation id="3304073249511302126">Bluetooth Ñкенирање</translation>
<translation id="3308006649705061278">Организациона јединица (OU)</translation>
@@ -729,12 +766,6 @@
<translation id="3345782426586609320">Очи</translation>
<translation id="3355823806454867987">Промени подешавања прокÑија...</translation>
<translation id="3360103848165129075">Страница обрађивача плаћања</translation>
-<translation id="3361596688432910856">Chrome <ph name="BEGIN_EMPHASIS" />не чува<ph name="END_EMPHASIS" /> Ñледеће информације:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />иÑторију прегледања
- <ph name="LIST_ITEM" />колачиће и податке о Ñајтовима
- <ph name="LIST_ITEM" />информације које уноÑите у обраÑцима
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">Ове Ñмернице Ñе аутоматÑки копирају из заÑтарелих Ñмерница <ph name="OLD_POLICY" />. УмеÑто њих треба да кориÑтите ове Ñмернице.</translation>
<translation id="3364869320075768271"><ph name="URL" /> жели да кориÑти уређај и податке виртуелне реалноÑти</translation>
<translation id="3366477098757335611">Прикажи картице</translation>
@@ -817,7 +848,6 @@
<translation id="3587738293690942763">Средње</translation>
<translation id="3592413004129370115">Italian (коверат)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{Групу можете да реÑетујете у било ком тренутку. Придруживање новој групи траје отприлике један дан.}=1{Групу можете да реÑетујете у било ком тренутку. Придруживање новој групи траје отприлике један дан.}one{Групу можете да реÑетујете у било ком тренутку. Придруживање новој групи траје отприлике {NUM_DAYS} дан.}few{Групу можете да реÑетујете у било ком тренутку. Придруживање новој групи траје отприлике {NUM_DAYS} дана.}other{Групу можете да реÑетујете у било ком тренутку. Придруживање новој групи траје отприлике {NUM_DAYS} дана.}}</translation>
-<translation id="3596012367874587041">Подешавања апликације</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">ÐдминиÑтратор блокира апликацију</translation>
<translation id="3608932978122581043">Смер уноÑа</translation>
@@ -860,6 +890,7 @@
<translation id="370972442370243704">Укључи Путеве</translation>
<translation id="3711895659073496551">ИÑкључи</translation>
<translation id="3712624925041724820">Ðема више лиценци</translation>
+<translation id="3714633008798122362">веб календар</translation>
<translation id="3714780639079136834">да укључите податке за мобилне уређаје или WiFi</translation>
<translation id="3715597595485130451">Повезивање Ñа WiFi мрежом</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />да проверите конфигурацију прокÑија, заштитног зида и DNS-а<ph name="END_LINK" /></translation>
@@ -921,6 +952,7 @@
<translation id="3906954721959377182">Таблет</translation>
<translation id="3909477809443608991"><ph name="URL" /> жели да пуÑти заштићени Ñадржај. Google ће потврдити идентитет уређаја и овај Ñајт ће моћи да му приÑтупа.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">Одбиј</translation>
<translation id="3939773374150895049">Желите ли да кориÑтите WebAuthn умеÑто CVC-а?</translation>
<translation id="3946209740501886391">Увек питај на овом Ñајту</translation>
<translation id="3947595700203588284">Може да тражи да Ñе повезује Ñа MIDI уређајима</translation>
@@ -942,6 +974,7 @@
<translation id="3990250421422698716">ПротреÑање ради поравнања</translation>
<translation id="3996311196211510766">Сајт <ph name="ORIGIN" /> је затражио да Ñе Ñмернице за порекло
примене на Ñве захтеве ка њему, али ове Ñмернице тренутно не могу да Ñе примене.</translation>
+<translation id="4009243425692662128">Садржај Ñтраница које штампате Ñе шаље у Google Cloud или трећим Ñтранама на анализу. Ðа пример, можда ће бити Ñкениран у потрази за оÑетљивим подацима.</translation>
<translation id="4010758435855888356">Желите ли да дозволите приÑтуп меморијÑком проÑтору?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{PDF документ који Ñадржи {COUNT} Ñтраницу}one{PDF документ који Ñадржи {COUNT} Ñтраницу}few{PDF документ који Ñадржи {COUNT} Ñтранице}other{PDF документ који Ñадржи {COUNT} Ñтраница}}</translation>
<translation id="4023431997072828269">Овај образац Ñе шаље помоћу везе која није безбедна, па ће информације бити видљиве другима.</translation>
@@ -1036,6 +1069,7 @@
<translation id="4250680216510889253">Ðе</translation>
<translation id="4253168017788158739">Ðапомена</translation>
<translation id="425582637250725228">Промене које Ñте унели можда неће бити Ñачуване.</translation>
+<translation id="425869179292622354">Желите ли да повећате безбедноÑÑ‚ помоћу виртуелне картице?</translation>
<translation id="4258748452823770588">ÐеиÑправан потпиÑ</translation>
<translation id="4261046003697461417">Ðапомене не могу да Ñе додају у заштићене документе</translation>
<translation id="4265872034478892965">Дозвољава админиÑтратор</translation>
@@ -1098,6 +1132,7 @@
<translation id="4434045419905280838">ИÑкачући прозори и преуÑмеравања</translation>
<translation id="4435702339979719576">разгледница)</translation>
<translation id="443673843213245140">Коришћење прокÑија је онемогућено, али је наведена екÑплицитна конфигурација прокÑија.</translation>
+<translation id="4441832193888514600">Игнорише Ñе јер Ñмернице могу да Ñе подеÑе Ñамо као Ñмернице за кориÑника у клауду.</translation>
<translation id="4450893287417543264">Ðе приказуј поново</translation>
<translation id="4451135742916150903">Може да тражи да Ñе повезује Ñа HID уређајима</translation>
<translation id="4452328064229197696">Лозинка коју Ñте управо кориÑтили је пронађена при повреди података. Да биÑте заштитили налоге, Google менаџер лозинки препоручује да проверите Ñачуване лозинке.</translation>
@@ -1153,6 +1188,7 @@
<translation id="4628948037717959914">Слика</translation>
<translation id="4631649115723685955">Повезан је повраћај готовине</translation>
<translation id="4636930964841734540">Информације</translation>
+<translation id="4638670630777875591">Без архивирања у Chromium-у</translation>
<translation id="464342062220857295">Функције претраге</translation>
<translation id="4644670975240021822">Обрнутим редоÑледом Ñа одштампаном Ñтраном надоле</translation>
<translation id="4646534391647090355">Одведи ме тамо</translation>
@@ -1173,6 +1209,7 @@
<translation id="4708268264240856090">Веза је прекинута</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />да покренете Windows дијагноÑтику мреже<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426">Лозинка за <ph name="USERNAME" /></translation>
<translation id="4724144314178270921">Може да тражи да види текÑÑ‚ и Ñлике у привременој меморији</translation>
<translation id="4726672564094551039">Поново учитај Ñмернице</translation>
<translation id="4728558894243024398">Платформа</translation>
@@ -1194,6 +1231,7 @@
<translation id="4757993714154412917">Управо Ñте унели лозинку на обмањујућем Ñајту. Да биÑте заштитили налоге, Chromium препоручује да проверите Ñачуване лозинке.</translation>
<translation id="4758311279753947758">Додај контакт информације</translation>
<translation id="4761104368405085019">Коришћење микрофона</translation>
+<translation id="4761869838909035636">Покрените Chrome безбедноÑну проверу</translation>
<translation id="4764776831041365478">Могуће је да веб-Ñтраница на адреÑи <ph name="URL" /> привремено не функционише или да је трајно премештена на нову веб адреÑу.</translation>
<translation id="4766713847338118463">ДвоÑтруко Ñпајање на дну</translation>
<translation id="4771973620359291008">Дошло је до непознате грешке.</translation>
@@ -1214,12 +1252,6 @@
<translation id="4819347708020428563">Желите ли да измените коментаре у подразумеваном приказу?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />, притиÑните Tab, па Enter да биÑте брзо направили нову Google табелу</translation>
<translation id="4825507807291741242">Моћно</translation>
-<translation id="4827402517081186284">Режим без архивирања Ð²Ð°Ñ Ð½Ðµ чини невидљивим онлајн:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Ñајтови знају да их поÑећујете<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />поÑлодавци или школе могу да прате активноÑти прегледања<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />интернет провајдери могу да прате Ñаобраћај на вебу<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">Укључи упозорења</translation>
<translation id="4838327282952368871">Чаробно</translation>
<translation id="4840250757394056958">Прегледајте иÑторију Chrome-а</translation>
@@ -1231,12 +1263,12 @@
<translation id="4854362297993841467">Овај начин иÑпоруке није доÑтупан. ИÑпробајте неки други начин.</translation>
<translation id="4854853140771946034">Брзо направите нову белешку у Google Keep-у</translation>
<translation id="485902285759009870">Кôд Ñе верификује...</translation>
+<translation id="4866506163384898554">ПритиÑните |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| да би Ñе показивач приказао</translation>
<translation id="4876188919622883022">ПоједноÑтављени приказ</translation>
<translation id="4876305945144899064">Ðема кориÑничког имена</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{Ðиједна}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}one{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}few{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831">Претрага <ph name="TEXT" /></translation>
<translation id="4879491255372875719">ÐутоматÑки (подразумевано)</translation>
-<translation id="4879725228911483934">да отвара и поÑтавља прозоре на екране</translation>
<translation id="4880827082731008257">Претражи иÑторију</translation>
<translation id="4881695831933465202">Отвори</translation>
<translation id="4885256590493466218">Плаћајте помоћу картице <ph name="CARD_DETAIL" /></translation>
@@ -1245,6 +1277,7 @@
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">Девети котур</translation>
<translation id="4901778704868714008">Сачувај...</translation>
+<translation id="4905659621780993806">ÐдминиÑтратор ће аутоматÑки реÑтартовати уређај у <ph name="TIME" />, <ph name="DATE" />. Сачувајте отворене Ñтавке пре него што Ñе уређај реÑтартује.</translation>
<translation id="4913987521957242411">Бушење у горњем левом углу</translation>
<translation id="4918221908152712722">ИнÑталирајте апликацију <ph name="APP_NAME" /> (не треба да је преузимате)</translation>
<translation id="4923459931733593730">Плаћање</translation>
@@ -1253,6 +1286,7 @@
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, притиÑните Tab, па Enter да биÑте претражили</translation>
<translation id="4930153903256238152">Велики капацитет</translation>
+<translation id="4940163644868678279">Без архивирања у Chrome-у</translation>
<translation id="4943872375798546930">Ðема резултата</translation>
<translation id="4950898438188848926">Дугме за промену картице, притиÑните Enter да биÑте прешли на отворену картицу, <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="495170559598752135">Радње</translation>
@@ -1262,6 +1296,7 @@
<translation id="4968522289500246572">Ова апликација је дизајнирана за мобилне уређаје и можда неће променити величину на правилан начин. Можда ће имати проблеме или Ñе реÑтартовати.</translation>
<translation id="4969341057194253438">Избриши Ñнимак</translation>
<translation id="4973922308112707173">ДвоÑтруко бушење на врху</translation>
+<translation id="4976702386844183910">ПоÑледња поÑета: <ph name="DATE" /></translation>
<translation id="4984088539114770594">Дозволићете коришћење микрофона?</translation>
<translation id="4984339528288761049">Prc5 (коверат)</translation>
<translation id="4989163558385430922">Прикажи Ñве</translation>
@@ -1323,6 +1358,7 @@
<translation id="5138227688689900538">Прикажи мање</translation>
<translation id="5145883236150621069">Кôд грешке је приÑутан у одговору на Ñмернице</translation>
<translation id="5146995429444047494">Обавештења за <ph name="ORIGIN" /> Ñу блокирана</translation>
+<translation id="514704532284964975"><ph name="URL" /> жели да види и мења информације на NFC уређајима које додирујете телефоном</translation>
<translation id="5148809049217731050">Са одштампаном Ñтраном нагоре</translation>
<translation id="515292512908731282">C4 (коверат)</translation>
<translation id="5158275234811857234">Корице</translation>
@@ -1347,6 +1383,7 @@
<translation id="5215116848420601511">Ðачини плаћања и адреÑе из Google Pay-а</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">13. фиока</translation>
+<translation id="5216942107514965959">ПоÑледњи поÑећен данаÑ</translation>
<translation id="5222812217790122047">Имејл је обавезан</translation>
<translation id="5230733896359313003">ÐдреÑа за иÑпоруку</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1367,7 +1404,6 @@
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">СвојÑтва документа</translation>
<translation id="528468243742722775">Заврши</translation>
-<translation id="5284909709419567258">Мрежне адреÑе</translation>
<translation id="5285570108065881030">Прикажи Ñве Ñачуване лозинке</translation>
<translation id="5287240709317226393">Прикажи колачиће</translation>
<translation id="5287456746628258573">Овај Ñајт кориÑти заÑтарелу безбедноÑну конфигурацију, која може да открије ваше информације (на пример, лозинке или бројеве кредитних картица) када Ñе шаљу на њега.</translation>
@@ -1451,6 +1487,7 @@
<translation id="5556459405103347317">Учитај поново</translation>
<translation id="5560088892362098740">Датум иÑтека</translation>
<translation id="55635442646131152">Структура документа</translation>
+<translation id="5565613213060953222">Отвори картицу без архивирања</translation>
<translation id="5565735124758917034">Ðктивно</translation>
<translation id="5570825185877910964">Заштити налог</translation>
<translation id="5571083550517324815">Преузимање Ñа ове адреÑе није могуће. Изаберите другу адреÑу.</translation>
@@ -1533,6 +1570,7 @@
<translation id="5869522115854928033">Сачуване лозинке</translation>
<translation id="5873013647450402046">Банка жели да потврди да Ñте то ви.</translation>
<translation id="5887400589839399685">Картица је Ñачувана</translation>
+<translation id="5887687176710214216">ПоÑледња поÑета: јуче</translation>
<translation id="5895138241574237353">Покрени поново</translation>
<translation id="5895187275912066135">Издато</translation>
<translation id="5901630391730855834">Жута</translation>
@@ -1546,6 +1584,7 @@
<translation id="5921639886840618607">Желите ли да Ñачувате картицу на Google налогу?</translation>
<translation id="5922853866070715753">Скоро је готово</translation>
<translation id="5932224571077948991">Сајт приказује оглаÑе који ометају активноÑти или обмањујуће оглаÑе</translation>
+<translation id="5938153366081463283">Додајте виртуелну картицу</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347">Отвара Ñе <ph name="SITE_NAME" />…</translation>
<translation id="5951495562196540101">РегиÑтрација кориÑничког налога није уÑпела (доÑтупна је лиценца пакета).</translation>
@@ -1610,6 +1649,7 @@
<translation id="6120179357481664955">Желите да Ñачувате ИД за UPI?</translation>
<translation id="6124432979022149706">Прикључци за Chrome за предузећа</translation>
<translation id="6127379762771434464">Уклонили Ñте Ñтавку</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Сазнајте више о режиму Без архивирања у Chrome-у<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">Проверите Ñве каблове и реÑтартујте Ñве рутере, модеме или друге мрежне уређаје које можда кориÑтите.</translation>
<translation id="614940544461990577">Покушајте:</translation>
<translation id="6150036310511284407">ТроÑтруко бушење на левој Ñтрани</translation>
@@ -1621,7 +1661,6 @@
<translation id="6169916984152623906">Сада можете да прегледате приватно и други људи који кориÑте овај уређај неће видети ваше активноÑти. Међутим, преузимања и обележивачи ће бити Ñачувани.</translation>
<translation id="6177128806592000436">Веза Ñа овим Ñајтом није безбедна</translation>
<translation id="6180316780098470077">Интервал између поновних покушаја</translation>
-<translation id="619448280891863779">Може да тражи да отвара и поÑтавља прозоре на екранима</translation>
<translation id="6196640612572343990">Блокирај колачиће треће Ñтране</translation>
<translation id="6203231073485539293">Проверите интернет везу</translation>
<translation id="6218753634732582820">Желите ли да уклоните адреÑу из Chromium-а?</translation>
@@ -1644,7 +1683,7 @@
<translation id="6272383483618007430">Google ажурирање</translation>
<translation id="6276112860590028508">Странице Ñа лиÑте за читање ће Ñе појавити овде</translation>
<translation id="627746635834430766">Да биÑте Ñледећи пут платили брже, Ñачувајте картицу и адреÑу за обрачун на Google налогу.</translation>
-<translation id="6279098320682980337">Број виртуелне картице није унет? Кликните на податке о картици да биÑте их копирали</translation>
+<translation id="6279183038361895380">ПритиÑните |<ph name="ACCELERATOR" />| да биÑте приказали показивач</translation>
<translation id="6280223929691119688">ИÑпорука на ову адреÑу није могућа. Изаберите другу адреÑу.</translation>
<translation id="6282194474023008486">ПоштанÑки број</translation>
<translation id="6285507000506177184">Дугме за управљање преузимањима у Chrome-у, притиÑните Enter да биÑте управљали фајловима које Ñте преузели у Chrome-у</translation>
@@ -1652,6 +1691,7 @@
<translation id="6290238015253830360">Предложени чланци Ñе приказују овде</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{Уређај ће Ñе реÑтартовати}=1{Уређај ће Ñе реÑтартовати за 1 Ñекунду}one{Уређај ће Ñе реÑтартовати за # Ñекунду}few{Уређај ће Ñе реÑтартовати за # Ñекунде}other{Уређај ће Ñе реÑтартовати за # Ñекунди}}</translation>
<translation id="6302269476990306341">Google помоћник у Chrome-у Ñе зауÑтавља</translation>
<translation id="6305205051461490394">URL <ph name="URL" /> није доÑтупан.</translation>
<translation id="6312113039770857350">Веб-Ñтраница није доÑтупна</translation>
@@ -1725,6 +1765,7 @@
<translation id="6529602333819889595">&amp;Понови бриÑање</translation>
<translation id="6545864417968258051">Bluetooth Ñкенирање</translation>
<translation id="6547208576736763147">ДвоÑтруко бушење на левој Ñтрани</translation>
+<translation id="6554732001434021288">ПоÑледња поÑета: пре <ph name="NUM_DAYS" /> дана</translation>
<translation id="6556866813142980365">Понови</translation>
<translation id="6569060085658103619">Прегледате Ñтраницу додатка.</translation>
<translation id="6573200754375280815">ДвоÑтруко бушење на деÑној Ñтрани</translation>
@@ -1785,7 +1826,6 @@
<translation id="6757797048963528358">Уређај је прешао у режим Ñпавања.</translation>
<translation id="6767985426384634228">Желите да ажурирате адреÑу?</translation>
<translation id="6768213884286397650">Hagaki (разгледница)</translation>
-<translation id="6774185088257932239"><ph name="BEGIN_LINK" />Сазнајте више<ph name="END_LINK" /> о режиму без архивирања</translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">ЉубичаÑта</translation>
<translation id="6786747875388722282">Додаци</translation>
@@ -1869,7 +1909,6 @@
<translation id="706295145388601875">Додајте адреÑе и управљајте њима у подешавањима Chrome-а</translation>
<translation id="7064851114919012435">Контакт информације</translation>
<translation id="7068733155164172741">УнеÑите <ph name="OTP_LENGTH" />-цифрени кôд</translation>
-<translation id="7070090581017165256">О овом Ñајту</translation>
<translation id="70705239631109039">Веза није потпуно безбедна</translation>
<translation id="7075452647191940183">Захтев је превелик</translation>
<translation id="7079718277001814089">Овај Ñајт Ñадржи малвер</translation>
@@ -1886,6 +1925,12 @@
<translation id="7111012039238467737">(Важећи)</translation>
<translation id="7118618213916969306">Потражите URL у привременој меморији, <ph name="SHORT_URL" /></translation>
<translation id="7119414471315195487">Затворите друге картице или програме</translation>
+<translation id="7129355289156517987">Када затворите Ñве Chromium картице без архивирања, активноÑÑ‚ на тим картицама Ñе брише Ñа уређаја:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ÐктивноÑти прегледања<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ИÑторија претраге<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Информације унете у обраÑцима<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">Слање на ову адреÑу није могуће. Изаберите другу адреÑу.</translation>
<translation id="7132939140423847331">ÐдминиÑтратор је забранио копирање ових података.</translation>
<translation id="7135130955892390533">Прикажи ÑтатуÑ</translation>
@@ -1908,6 +1953,7 @@
<translation id="7192203810768312527">ОÑлободиће Ñе <ph name="SIZE" />. Ðеки Ñајтови ће Ñе Ñпорије учитавати при Ñледећој поÑети.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">ÐдминиÑтратор може да види:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, притиÑните Tab, па Enter да биÑте отворили нову картицу без архивирања и прегледали приватно</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423">ХоÑÑ‚ <ph name="HOST_NAME" /> не поштује безбедноÑне Ñтандарде.</translation>
<translation id="7210993021468939304">Linux активноÑти унутар контејнера и може да инÑталира и покреће Linux апликације унутар контејнера</translation>
@@ -1939,6 +1985,7 @@
<translation id="7304562222803846232">Управљајте подешавањима приватноÑти Google налога</translation>
<translation id="7305756307268530424">Почните Ñпорије</translation>
<translation id="7308436126008021607">Ñинхронизација у позадини</translation>
+<translation id="7310392214323165548">Уређај ће Ñе реÑтартовати веома брзо</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">Помоћ при повезивању</translation>
<translation id="7323804146520582233">Сакријте одељак <ph name="SECTION" /></translation>
@@ -1946,6 +1993,7 @@
<translation id="7334320624316649418">&amp;Понови промену редоÑледа</translation>
<translation id="7335157162773372339">Може да тражи да кориÑти камеру</translation>
<translation id="7337248890521463931">Прикажи више редова</translation>
+<translation id="7337418456231055214">Број виртуелне картице није унет? Кликните на податке о картици да биÑте их копирали. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">Ðије доÑтупно на вашој платформи.</translation>
<translation id="733923710415886693">Сертификат Ñервера није откривен помоћу ТранÑпарентноÑти Ñертификата.</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1968,6 +2016,7 @@
<translation id="7378627244592794276">Ðе</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">Ðије примењиво</translation>
+<translation id="7388594495505979117">{0,plural, =1{Уређај ће Ñе реÑтартовати за 1 минут}one{Уређај ће Ñе реÑтартовати за # минут}few{Уређај ће Ñе реÑтартовати за # минута}other{Уређај ће Ñе реÑтартовати за # минута}}</translation>
<translation id="7390545607259442187">Потврдите картицу</translation>
<translation id="7392089738299859607">Ðжурирајте адреÑу</translation>
<translation id="7399802613464275309">БезбедноÑна провера</translation>
@@ -2004,6 +2053,12 @@
<translation id="7485870689360869515">ÐиÑу пронађени подаци.</translation>
<translation id="7495528107193238112">Овај Ñадржај је блокиран. Обратите Ñе влаÑнику Ñајта да биÑте решили проблем.</translation>
<translation id="7497998058912824456">Дугме Ðаправите документ, притиÑните Enter да биÑте брзо направили нов Google документ</translation>
+<translation id="7506488012654002225">Chromium <ph name="BEGIN_EMPHASIS" />не чува<ph name="END_EMPHASIS" /> Ñледеће информације:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />иÑторију прегледања
+ <ph name="LIST_ITEM" />колачиће и податке о Ñајтовима
+ <ph name="LIST_ITEM" />информације које уноÑите у обраÑцима
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">Враћени ИД уређаја за Ñмернице је празан или Ñе не подудара Ñа актуелним ИД-ом уређаја</translation>
<translation id="7508870219247277067">Зеленожута</translation>
<translation id="7511955381719512146">WiFi мрежа коју кориÑтите ће можда захтевати да поÑетите <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
@@ -2117,7 +2172,6 @@
<translation id="7813600968533626083">Желите ли да уклоните предлог из Chrome-а?</translation>
<translation id="781440967107097262">Дозволићете дељење привремене меморије?</translation>
<translation id="7815407501681723534">Пронашли Ñмо <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> за „<ph name="SEARCH_STRING" />“</translation>
-<translation id="782125616001965242">Приказује информације о овом Ñајту</translation>
<translation id="782886543891417279">WiFi мрежа коју кориÑтите (<ph name="WIFI_NAME" />) ће можда захтевати да поÑетите Ñтраницу за пријављивање.</translation>
<translation id="7836231406687464395">Postfix (коверат)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{Ðиједна}=1{1 апликација (<ph name="EXAMPLE_APP_1" />)}=2{2 апликације (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}one{# апликација (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}few{# апликације (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}other{# апликација (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}}</translation>
@@ -2134,7 +2188,6 @@
<translation id="7888575728750733395">Ðамера рендеровања штампања</translation>
<translation id="7894280532028510793">Ðко нема грешака, <ph name="BEGIN_LINK" />покрените дијагноÑтику мреже<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (коверат)</translation>
-<translation id="7931318309563332511">Ðепознато</translation>
<translation id="793209273132572360">Желите да ажурирате адреÑу?</translation>
<translation id="7932579305932748336">Омот</translation>
<translation id="79338296614623784">УнеÑите важећи број телефона</translation>
@@ -2159,13 +2212,14 @@
<translation id="7976214039405368314">Превише је захтева</translation>
<translation id="7977538094055660992">Излазни уређај</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">Повезана Ñа:</translation>
<translation id="798134797138789862">Може да тражи да кориÑти уређаје и податке виртуелне реалноÑти</translation>
<translation id="7984945080620862648">Тренутно не можете да поÑетите <ph name="SITE" /> зато што је веб-Ñајт поÑлао шифроване акредитиве које Chrome не може да обради. Грешке и напади на мрежи Ñу обично привремени, па ће ова Ñтраница вероватно функциониÑати каÑније.</translation>
-<translation id="79859296434321399">Да биÑте видели Ñадржај проширене реалноÑти, инÑталирајте ARCore</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">Повезивање</translation>
<translation id="7992044431894087211">ÐаÑтављено је дељење Ñадржаја екрана Ñа апликацијом <ph name="APPLICATION_TITLE" /></translation>
<translation id="7995512525968007366">Ðије наведено</translation>
+<translation id="7998269595945679889">ПритиÑните дугме Отвори картицу без архивирања, па Enter да биÑте отворили нову картицу без архивирања и прегледали приватно</translation>
<translation id="800218591365569300">Пробајте да затворите друге картице или програме да биÑте оÑлободили меморију.</translation>
<translation id="8004582292198964060">Прегледач</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{Та картица и њена адреÑа за обрачун ће бити Ñачуване. Моћи ћете да је кориÑтите када Ñте пријављени на <ph name="USER_EMAIL" />.}one{Те картице и њихове адреÑе за обрачун ће бити Ñачуване. Моћи ћете да их кориÑтите када Ñте пријављени на <ph name="USER_EMAIL" />.}few{Те картице и њихове адреÑе за обрачун ће бити Ñачуване. Моћи ћете да их кориÑтите када Ñте пријављени на <ph name="USER_EMAIL" />.}other{Те картице и њихове адреÑе за обрачун ће бити Ñачуване. Моћи ћете да их кориÑтите када Ñте пријављени на <ph name="USER_EMAIL" />.}}</translation>
@@ -2225,6 +2279,7 @@
<translation id="8202370299023114387">ÐеуÑаглашеноÑÑ‚</translation>
<translation id="8206978196348664717">Prc4 (коверат)</translation>
<translation id="8211406090763984747">Веза је безбедна</translation>
+<translation id="8217240300496046857">Сајтови не могу да кориÑте колачиће који Ð²Ð°Ñ Ð¿Ñ€Ð°Ñ‚Ðµ на вебу. Функције на неким Ñајтовима могу да преÑтану Ñа радом.</translation>
<translation id="8218327578424803826">Додељена локација:</translation>
<translation id="8220146938470311105">C7/C6 (коверат)</translation>
<translation id="8225771182978767009">ОÑоба која је подеÑила овај рачунар је одлучила да блокира овај Ñајт.</translation>
@@ -2265,14 +2320,9 @@
<translation id="830498451218851433">ПреÑавијање напола</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">ИнÑталиране апликације и колико чеÑто Ñе кориÑте</translation>
+<translation id="8317207217658302555">Желите да ажурирате ARCore?</translation>
<translation id="831997045666694187">Увече</translation>
<translation id="8321476692217554900">обавештења</translation>
-<translation id="8328484624016508118">Када затворите Ñве картице без архивирања, Chrome брише:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />активноÑти прегледања Ñа овог уређаја<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />иÑторију претраге Ñа овог уређаја<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />информације унеÑене преко образаца<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489">ПриÑтуп хоÑту <ph name="HOST_NAME" /> је одбијен</translation>
<translation id="833262891116910667">ИÑтицање</translation>
<translation id="8339163506404995330">Странице на језику <ph name="LANGUAGE" /> Ñе неће преводити</translation>
@@ -2324,6 +2374,7 @@
<translation id="8507227106804027148">Командна линија</translation>
<translation id="8508648098325802031">Икона Претрага</translation>
<translation id="8511402995811232419">Управљајте колачићима</translation>
+<translation id="8519753333133776369">ÐдминиÑтратор је дозволио HID уређај</translation>
<translation id="8522552481199248698">Chrome може да вам помогне да заштитите Google налог и промените лозинку.</translation>
<translation id="8530813470445476232">Обришите иÑторију прегледања, колачиће, кеш и друго у подешавањима Chrome-а</translation>
<translation id="8533619373899488139">ПоÑетите &lt;strong&gt;chrome://policy&lt;/strong&gt; да биÑте видели лиÑту блокираних URL-ова и друге Ñмернице које је одредио админиÑтратор ÑиÑтема.</translation>
@@ -2335,7 +2386,6 @@
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{РеÑетуј дозволу}one{РеÑетуј дозволе}few{РеÑетуј дозволе}other{РеÑетуј дозволе}}</translation>
<translation id="8555010941760982128">КориÑтите овај кôд при плаћању</translation>
<translation id="8557066899867184262">CVC је на полеђини картице.</translation>
-<translation id="8558485628462305855">Да биÑте видели Ñадржај проширене реалноÑти, ажурирајте ARCore</translation>
<translation id="8559762987265718583">Ðије могуће уÑпоÑтавити приватну везу Ñа доменом <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> јер датум и време на уређају (<ph name="DATE_AND_TIME" />) ниÑу тачни.</translation>
<translation id="8564182942834072828">Одвојени документи/неÑређене копије</translation>
<translation id="8564985650692024650">Chromium вам препоручује да реÑетујете лозинку за <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> ако Ñте је кориÑтили на другим Ñајтовима.</translation>
@@ -2355,6 +2405,7 @@
<translation id="865032292777205197">Ñензори за покрет</translation>
<translation id="8663226718884576429">Резиме поруџбине, <ph name="TOTAL_LABEL" />, још детаља</translation>
<translation id="8666678546361132282">енглеÑки</translation>
+<translation id="8669306706049782872">КориÑти информације о екранима да би отварао и поÑтављао прозоре</translation>
<translation id="867224526087042813">ПотпиÑ</translation>
<translation id="8676424191133491403">Без одлагања</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, одговор, <ph name="ANSWER" /></translation>
@@ -2381,6 +2432,7 @@
<translation id="8731544501227493793">Дугме Управљај лозинкама, притиÑните Enter да биÑте прегледали лозинке и управљали њима у подешавањима Chrome-а</translation>
<translation id="8734529307927223492"><ph name="DEVICE_TYPE" />-ом управља <ph name="MANAGER" /></translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, притиÑните Tab, па Enter да биÑте отворили нов прозор без архивирања и прегледали приватно</translation>
+<translation id="8737685506611670901">отвори линкове за <ph name="PROTOCOL" /> умеÑто <ph name="REPLACED_HANDLER_TITLE" /></translation>
<translation id="8738058698779197622">Да биÑте уÑпоÑтавили безбедну везу, Ñат на уређају мора да буде тачан. То је зато што Ñертификати које веб-Ñајтови кориÑте за идентификацију важе Ñамо одређени временÑки период. Пошто Ñат на вашем уређају није тачан, Chromium не може да верификује ове Ñертификате.</translation>
<translation id="8740359287975076522">ÐиÑмо уÑпели да пронађемо &lt;abbr id="dnsDefinition"&gt;DNS адреÑу&lt;/abbr&gt; хоÑта <ph name="HOST_NAME" />. Покушавамо да утврдимо у чему је проблем.</translation>
<translation id="8742371904523228557"><ph name="ONE_TIME_CODE" /> је ваш кôд за <ph name="ORIGIN" /></translation>
@@ -2408,6 +2460,7 @@
<translation id="883848425547221593">ОÑтали обележивачи</translation>
<translation id="884264119367021077">ÐдреÑа за иÑпоруку</translation>
<translation id="884923133447025588">Ðије пронађен ниједан механизам опозива.</translation>
+<translation id="8849262850971482943">КориÑтите виртуелну картицу ради додатне безбедноÑти</translation>
<translation id="885730110891505394">Дељење Ñа Google-ом</translation>
<translation id="8858065207712248076">Chrome вам препоручује да реÑетујете лозинку за <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> ако Ñте је кориÑтили на другим Ñајтовима.</translation>
<translation id="885906927438988819">Ðко нема грешака, <ph name="BEGIN_LINK" />покрените Windows дијагноÑтику мреже<ph name="END_LINK" />.</translation>
@@ -2457,6 +2510,7 @@
<translation id="9004367719664099443">ВР ÑеÑија је у току</translation>
<translation id="9005998258318286617">Учитавање PDF документа није уÑпело.</translation>
<translation id="9008201768610948239">Игнориши</translation>
+<translation id="901834265349196618">имејл</translation>
<translation id="9020200922353704812">ÐдреÑа за обрачун за картицу је обавезна</translation>
<translation id="9020542370529661692">Ова Ñтраница је преведена на <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9020742383383852663">A8</translation>
@@ -2505,6 +2559,7 @@
<translation id="9150045010208374699">Коришћење камере</translation>
<translation id="9150685862434908345">ÐдминиÑтратор може даљинÑки да промени подешавање прегледача. ÐктивноÑтима на овом уређају Ñе можда управља и ван Chrome-а. <ph name="BEGIN_LINK" />Сазнајте више<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">Ðжурирано</translation>
+<translation id="9155211586651734179">Ðудио периферни уређаји Ñу прикључени</translation>
<translation id="9157595877708044936">Подешавање...</translation>
<translation id="9158625974267017556">C6 (коверат)</translation>
<translation id="9164029392738894042">Провера тачноÑти</translation>
diff --git a/chromium/components/strings/components_strings_sv.xtb b/chromium/components/strings/components_strings_sv.xtb
index 885dc2f0e78..54ceaef3bd1 100644
--- a/chromium/components/strings/components_strings_sv.xtb
+++ b/chromium/components/strings/components_strings_sv.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">Visa information</translation>
<translation id="1030706264415084469"><ph name="URL" /> vill lagra stora mängder data permanent på din enhet</translation>
<translation id="1032854598605920125">Rotera medurs</translation>
+<translation id="1033329911862281889">Inkognitoläget gör dig inte osynlig online:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Webbplatser och tjänster de använder kan se ditt besök<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Din arbetsgivare eller skola kan spåra webbaktivitet<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Internetleverantören kan övervaka webbtrafik<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">Inaktivera</translation>
<translation id="1036982837258183574">Tryck på |<ph name="ACCELERATOR" />| för att stänga helskärmen</translation>
<translation id="1038106730571050514">Visa förslag</translation>
<translation id="1038842779957582377">okänt namn</translation>
<translation id="1041998700806130099">Meddelande på arbetsorder</translation>
<translation id="1048785276086539861">När du redigerar kommentarer aktiveras enkelsidig vy igen för dokumentet</translation>
-<translation id="1049743911850919806">Inkognito</translation>
<translation id="1050038467049342496">Stäng andra appar</translation>
<translation id="1055184225775184556">&amp;Ångra Lägg till</translation>
<translation id="1056898198331236512">Varning</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">Cacheminnet för policyn är OK</translation>
<translation id="1130564665089811311">Knappen Översätt sida, tryck på Retur om du vill översätta sidan med Google Översätt</translation>
<translation id="1131264053432022307">Bilden som du kopierade</translation>
+<translation id="1142846828089312304">Blockera cookies från tredje part i inkognitoläge</translation>
<translation id="1150979032973867961">Servern kunde inte bevisa att den är <ph name="DOMAIN" /> eftersom datorns operativsystem inte litar på dess säkerhetscertifikat. Detta kan orsakas av en felaktig konfigurering eller att någon spärrar anslutningen.</translation>
<translation id="1151972924205500581">Lösenord krävs</translation>
<translation id="1156303062776767266">Detta är en lokal eller delad fil</translation>
@@ -64,7 +70,6 @@ Annars blockeras detta av integritetsinställningarna. Om du tillåter detta kan
<translation id="1178581264944972037">Paus</translation>
<translation id="1181037720776840403">Ta bort</translation>
<translation id="1186201132766001848">Kontrollera lösenord</translation>
-<translation id="1195210374336998651">Öppna appinställningarna</translation>
<translation id="1195558154361252544">Aviseringar blockeras automatiskt på alla webbplatser utom sådana du tillåter</translation>
<translation id="1197088940767939838">Orange</translation>
<translation id="1201402288615127009">Nästa</translation>
@@ -111,7 +116,7 @@ Annars blockeras detta av integritetsinställningarna. Om du tillåter detta kan
<translation id="1307966114820526988">Utfasade funktioner</translation>
<translation id="1308113895091915999">Tillgängligt erbjudande</translation>
<translation id="1312803275555673949">Vad finns det för belägg för detta?</translation>
-<translation id="131405271941274527"><ph name="URL" /> vill skicka och ta emot information när du snuddar vid en NFC-enhet med telefonen</translation>
+<translation id="1314311879718644478">Visa innehåll med förstärkt verklighet</translation>
<translation id="1314509827145471431">Bindning till höger</translation>
<translation id="1318023360584041678">Sparades i en flikgrupp</translation>
<translation id="1319245136674974084">Fråga inte igen för den här appen</translation>
@@ -161,6 +166,7 @@ Annars blockeras detta av integritetsinställningarna. Om du tillåter detta kan
<translation id="142858679511221695">Molnanvändare</translation>
<translation id="1428729058023778569">Den här varningen visas därför att webbplatsen inte stöder HTTPS. <ph name="BEGIN_LEARN_MORE_LINK" />Läs mer<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">Skriv ut</translation>
+<translation id="1432187715652018471">Sidan vill installera en tjänsthanterare.</translation>
<translation id="1432581352905426595">Hantera sökmotorer</translation>
<translation id="1436185428532214179">Får begära tillstånd att redigera filer eller mappar på enheten</translation>
<translation id="1442386063175183758">Fönsterfalsning, höger flik</translation>
@@ -181,6 +187,12 @@ Annars blockeras detta av integritetsinställningarna. Om du tillåter detta kan
<translation id="1483493594462132177">Skicka</translation>
<translation id="1484290072879560759">Välj leveransadress</translation>
<translation id="1492194039220927094">Skicka principer:</translation>
+<translation id="149293076951187737">När du stänger inkognitoflikar i Chrome rensas följande aktivitet i flikarna från denna enhet:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Webbaktivitet<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Sökhistorik<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Uppgifter som anges i formulär<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">Tillbaka till flik</translation>
<translation id="1501859676467574491">Visa kort från ditt Google-konto</translation>
<translation id="1507202001669085618">&lt;p&gt;Felmeddelandet visas om du använder en wifi-portal där du måste logga in innan du kommer ut på internet.&lt;/p&gt;
@@ -208,6 +220,8 @@ Annars blockeras detta av integritetsinställningarna. Om du tillåter detta kan
<translation id="1559572115229829303">&lt;p&gt;Det gick inte att upprätta en privat anslutning till <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> eftersom enhetens datum och tid (<ph name="DATE_AND_TIME" />) inte stämmer.&lt;/p&gt;
&lt;p&gt;Ändra datumet och tiden under &lt;strong&gt;Allmänt&lt;/strong&gt; i appen &lt;strong&gt;Inställningar&lt;/strong&gt;.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">Administratören startar om enheten kl. <ph name="TIME" /> den <ph name="DATE" /></translation>
+<translation id="156703335097561114">Nätverksinformation som adresser, gränssnittskonfiguration och anslutningskvalitet</translation>
<translation id="1567040042588613346">Den här principen fungerar som avsett, men den har även ställts in på annan plats med samma värde och detta andra värde ersätts av denna princip.</translation>
<translation id="1569487616857761740">Ange sista giltighetsdatum</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@ Annars blockeras detta av integritetsinställningarna. Om du tillåter detta kan
<translation id="1583429793053364125">Ett fel uppstod när webbsidan skulle visas.</translation>
<translation id="1586541204584340881">Vilka tillägg du har installerat</translation>
<translation id="1588438908519853928">Normal</translation>
+<translation id="1589050138437146318">Vill du installera ARCore?</translation>
<translation id="1592005682883173041">Lokal dataåtkomst</translation>
<translation id="1594030484168838125">Välj</translation>
<translation id="160851722280695521">Spela Dino Run-spelet i Chrome</translation>
@@ -283,6 +298,7 @@ Annars blockeras detta av integritetsinställningarna. Om du tillåter detta kan
inställningen har fel format, och därför går det inte att slutföra begäran
om <ph name="SITE" /> i webbläsaren. Ursprungsprinciper kan användas av
webbplatsoperatörer för att konfigurera säkerhetsfunktioner och andra funktioner för webbplatser.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Läs mer om inkognitoläge i Chromium<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">Öppna flikar visas här</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -359,7 +375,7 @@ Annars blockeras detta av integritetsinställningarna. Om du tillåter detta kan
<translation id="204357726431741734">Logga in om du vill använda lösenord som har sparats i Google-kontot</translation>
<translation id="2053111141626950936">Sidor på <ph name="LANGUAGE" /> översätts inte.</translation>
<translation id="2053373601901562871">{NUM_DAYS,plural, =0{När den här inställningen är på och statusen är Aktiv fastställer Chrome vilken grupp, eller kohort, som du tillhör utifrån din senaste webbaktivitet. Annonsörer kan välja annonser för denna grupp och din webbhistorik förblir privat på enheten. Grupptillhörigheten uppdateras dagligen.}=1{När den här inställningen är på och statusen är Aktiv fastställer Chrome vilken grupp, eller kohort, som du tillhör utifrån din senaste webbaktivitet. Annonsörer kan välja annonser för denna grupp och din webbhistorik förblir privat på enheten. Grupptillhörigheten uppdateras dagligen.}other{När den här inställningen är på och statusen är Aktiv fastställer Chrome vilken grupp, eller kohort, som du tillhör utifrån din senaste webbaktivitet. Annonsörer kan välja annonser för denna grupp och din webbhistorik förblir privat på enheten. Grupptillhörigheten uppdateras med {NUM_DAYS} dagars mellanrum.}}</translation>
-<translation id="2053553514270667976">ZIP</translation>
+<translation id="2053553514270667976">Postnummer</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 förslag}other{# förslag}}</translation>
<translation id="2071156619270205202">Detta kort uppfyller inte kraven för virtuella kortnummer.</translation>
<translation id="2071692954027939183">Aviseringar blockerades automatiskt eftersom du vanligtvis inte tillåter dem</translation>
@@ -410,6 +426,7 @@ Annars blockeras detta av integritetsinställningarna. Om du tillåter detta kan
<translation id="22081806969704220">Fack 3</translation>
<translation id="2212735316055980242">Policyn hittades inte</translation>
<translation id="2213606439339815911">Hämtar poster …</translation>
+<translation id="2213612003795704869">Sidan skrivs ut</translation>
<translation id="2215727959747642672">Filredigering</translation>
<translation id="2218879909401188352">Angripare på <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> skulle kunna installera farliga appar som skadar enheten, lägger till dolda avgifter på din mobilfaktura eller stjäl personliga uppgifter. <ph name="BEGIN_LEARN_MORE_LINK" />Läs mer<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">Inget internet</translation>
@@ -419,6 +436,7 @@ Annars blockeras detta av integritetsinställningarna. Om du tillåter detta kan
<translation id="2248949050832152960">Använd WebAuthn</translation>
<translation id="2250931979407627383">Kanthäftning till vänster</translation>
<translation id="225207911366869382">Värdet är inte längre giltigt för policyn.</translation>
+<translation id="2256115617011615191">Starta om nu</translation>
<translation id="2258928405015593961">Ange ett sista giltighetsdatum som inte har varit och försök igen</translation>
<translation id="225943865679747347">Felkod: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">HTTP-fel</translation>
@@ -446,6 +464,7 @@ Annars blockeras detta av integritetsinställningarna. Om du tillåter detta kan
<translation id="2337852623177822836">Inställningen styrs av administratören</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> vill kopplas</translation>
<translation id="2346319942568447007">Bilden som du kopierade</translation>
+<translation id="2350796302381711542">Vill du tillåta att <ph name="HANDLER_HOSTNAME" /> öppnar alla <ph name="PROTOCOL" />-länkar i stället för <ph name="REPLACED_HANDLER_TITLE" />?</translation>
<translation id="2354001756790975382">Övriga bokmärken</translation>
<translation id="2354430244986887761">Google Säker webbsökning <ph name="BEGIN_LINK" />hittade skadliga appar<ph name="END_LINK" /> nyligen på <ph name="SITE" />.</translation>
<translation id="2355395290879513365">Det är möjligt att hackare kan se vilka bilder du visar på den här webbplatsen och att de försöker lura dig genom att modifiera dem.</translation>
@@ -471,6 +490,7 @@ Annars blockeras detta av integritetsinställningarna. Om du tillåter detta kan
<translation id="2413528052993050574">Servern kunde inte bevisa att den är <ph name="DOMAIN" /> eftersom dess säkerhetscertifikat kan ha återkallats. Detta kan orsakas av en felaktig konfigurering eller att någon spärrar anslutningen.</translation>
<translation id="2414886740292270097">Mörk</translation>
<translation id="2430968933669123598">Hantera Google-kontot: tryck på Retur om du vill hantera uppgifter, integritet och säkerhet i Google-kontot</translation>
+<translation id="2436186046335138073">Vill du tillåta att <ph name="HANDLER_HOSTNAME" /> öppnar alla <ph name="PROTOCOL" />-länkar?</translation>
<translation id="2438874542388153331">Fyra hål till höger</translation>
<translation id="2450021089947420533">Sökningar</translation>
<translation id="2463739503403862330">Fyll i</translation>
@@ -478,6 +498,7 @@ Annars blockeras detta av integritetsinställningarna. Om du tillåter detta kan
<translation id="2465655957518002998">Välj leveranssätt</translation>
<translation id="2465688316154986572">Häftning</translation>
<translation id="2465914000209955735">Hantera filer du har laddat ned i Chrome</translation>
+<translation id="2466004615675155314">Visa information från webben</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />att köra nätverksdiagnostik<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">1 till N-ordning</translation>
<translation id="2470767536994572628">När du redigerar kommentarer aktiveras enkelsidig vy och ursprunglig rotation igen för dokumentet</translation>
@@ -498,6 +519,7 @@ Annars blockeras detta av integritetsinställningarna. Om du tillåter detta kan
<translation id="2523886232349826891">Endast sparat på den här enheten</translation>
<translation id="2524461107774643265">Lägg till mer information</translation>
<translation id="2529899080962247600">Fältet får ha högst <ph name="MAX_ITEMS_LIMIT" /> poster. Alla poster utöver det ignoreras.</translation>
+<translation id="2535585790302968248">Öppna en ny inkognitoflik och surfa privat</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{och 1 till}other{och # till}}</translation>
<translation id="2536110899380797252">Lägg till adress</translation>
<translation id="2539524384386349900">Identifiera</translation>
@@ -523,7 +545,14 @@ Annars blockeras detta av integritetsinställningarna. Om du tillåter detta kan
<translation id="2597378329261239068">Dokumentet är lösenordsskyddat. Ange ett lösenord.</translation>
<translation id="2609632851001447353">Varianter</translation>
<translation id="2610561535971892504">Klicka för att kopiera</translation>
+<translation id="2617988307566202237">Följande information sparas <ph name="BEGIN_EMPHASIS" />inte<ph name="END_EMPHASIS" /> i Chrome:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Din webbhistorik
+ <ph name="LIST_ITEM" />Cookies och webbplatsdata
+ <ph name="LIST_ITEM" />Uppgifter som anges i formulär
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (kuvert)</translation>
+<translation id="2623663032199728144">Får begära att använda information om dina skärmar</translation>
<translation id="2625385379895617796">Klockan går före</translation>
<translation id="262745152991669301">Får begära tillstånd att ansluta till USB-enheter</translation>
<translation id="2629325967560697240"><ph name="BEGIN_ENHANCED_PROTECTION_LINK" />Aktivera Förbättrat skydd<ph name="END_ENHANCED_PROTECTION_LINK" /> för att få Chromes högsta säkerhetsnivå</translation>
@@ -557,6 +586,7 @@ Annars blockeras detta av integritetsinställningarna. Om du tillåter detta kan
<translation id="2709516037105925701">Autofyll</translation>
<translation id="2713444072780614174">Vit</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />, tryck på Tabb och sedan på Retur om du vill hantera betalningar och kreditkortsuppgifter i inställningarna för Chrome</translation>
+<translation id="271663710482723385">Tryck på |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| om du vill avsluta helskärmsläget</translation>
<translation id="2721148159707890343">Begäran genomfördes</translation>
<translation id="2723669454293168317">Kör en säkerhetskontroll i inställningarna för Chrome</translation>
<translation id="2726001110728089263">Sidofack</translation>
@@ -587,6 +617,7 @@ Annars blockeras detta av integritetsinställningarna. Om du tillåter detta kan
<translation id="2850739647070081192">Invite (kuvert)</translation>
<translation id="2856444702002559011">En angripare kan försöka stjäla dina uppgifter från <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (t.ex. lösenord, meddelanden eller kreditkortsuppgifter). <ph name="BEGIN_LEARN_MORE_LINK" />Läs mer<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">Påträngande eller vilseledande annonser visas på den här webbplatsen.</translation>
+<translation id="286512204874376891">Ett virtuellt kort döljer det riktiga kortet och skyddar dig från eventuella bedrägerier. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">Vänlig</translation>
<translation id="2876489322757410363">Om du betalar i ett externt program sker inte det i inkognitoläge. Vill du fortsätta?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />: tryck på Tabb och sedan på Retur om du vill hantera Säker webbsökning med mera i inställningarna för Chrome</translation>
@@ -611,6 +642,7 @@ Annars blockeras detta av integritetsinställningarna. Om du tillåter detta kan
<translation id="2930577230479659665">Beskär efter varje exemplar</translation>
<translation id="2932085390869194046">Föreslå lösenord …</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019">Öppna <ph name="PROTOCOL" />-länkar</translation>
<translation id="2941952326391522266">Servern kunde inte bevisa att den är <ph name="DOMAIN" /> eftersom dess säkerhetscertifikat kommer från <ph name="DOMAIN2" />. Detta kan orsakas av en felaktig konfigurering eller att någon spärrar anslutningen.</translation>
<translation id="2943895734390379394">Uppladdningstid:</translation>
<translation id="2948083400971632585">Du kan inaktivera alla proxyservrar som har konfigurerats för en anslutning från sidan Inställningar.</translation>
@@ -643,6 +675,7 @@ Annars blockeras detta av integritetsinställningarna. Om du tillåter detta kan
<translation id="3037605927509011580">Oj, ett fel har uppstått!</translation>
<translation id="3041612393474885105">Certifikatinformation</translation>
<translation id="3044034790304486808">Återuppta sökningen</translation>
+<translation id="305162504811187366">Historik för Chrome Remote Desktop, bland annat tidsstämplar, värdar och id:n för klientsessioner</translation>
<translation id="3060227939791841287">C9 (kuvert)</translation>
<translation id="3061707000357573562">Tjänst för programkorrigering</translation>
<translation id="306573536155379004">Spelet har startats.</translation>
@@ -683,6 +716,7 @@ Annars blockeras detta av integritetsinställningarna. Om du tillåter detta kan
<translation id="3197136577151645743">Får begära tillstånd att få veta om du använder den här enheten aktivt</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />, tryck på Tabb och sedan på Retur om du vill hantera vilken information som synkroniseras i inställningarna för Chrome</translation>
<translation id="320323717674993345">Avbryt betalningen</translation>
+<translation id="3203366800380907218">Från webben</translation>
<translation id="3207960819495026254">Bokmärkt</translation>
<translation id="3209034400446768650">Sidan kan vara avgiftsbelagd</translation>
<translation id="3212581601480735796">Din aktivitet på <ph name="HOSTNAME" /> övervakas</translation>
@@ -699,10 +733,12 @@ Annars blockeras detta av integritetsinställningarna. Om du tillåter detta kan
<translation id="3234666976984236645">Upptäck alltid viktigt innehåll på den här webbplatsen</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />: tryck på Tabb och sedan på Retur om du vill anpassa webbläsarens utseende</translation>
<translation id="3240791268468473923">Arbetsblad för användaruppgifter för säker betalning utan överensstämmande användaruppgifter är öppet</translation>
+<translation id="324180406144491771"><ph name="HOST_NAME" />-länkarna har blockerats</translation>
<translation id="3249845759089040423">Tuff</translation>
<translation id="3252266817569339921">franska</translation>
<translation id="3257954757204451555">Vem står bakom informationen?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />: tryck på Tabb och sedan på Retur om du snabbt vill skapa en ny händelse i Google Kalender</translation>
+<translation id="3261488570342242926">Läs mer om virtuella kort</translation>
<translation id="3264837738038045344">Knappen Hantera inställningar för Chrome: tryck på Retur om du vill öppna Chrome-inställningarna</translation>
<translation id="3266793032086590337">Värde (konflikt)</translation>
<translation id="3268451620468152448">Öppna flikar</translation>
@@ -716,6 +752,7 @@ Annars blockeras detta av integritetsinställningarna. Om du tillåter detta kan
<translation id="3288238092761586174"><ph name="URL" /> kan behöva vidta ytterligare steg för att verifiera din betalning</translation>
<translation id="3293642807462928945">Läs mer om principen <ph name="POLICY_NAME" /></translation>
<translation id="3295444047715739395">Visa och hantera dina lösenord i inställningarna för Chrome</translation>
+<translation id="3303795387212510132">Vill du tillåta att appen öppnar <ph name="PROTOCOL_SCHEME" />-länkar?</translation>
<translation id="3303855915957856445">Inga sökresultat hittades</translation>
<translation id="3304073249511302126">Bluetooth-sökning</translation>
<translation id="3308006649705061278">Organisationsenhet (OU)</translation>
@@ -729,12 +766,6 @@ Annars blockeras detta av integritetsinställningarna. Om du tillåter detta kan
<translation id="3345782426586609320">Ögon</translation>
<translation id="3355823806454867987">Ändra proxyinställningar...</translation>
<translation id="3360103848165129075">Arbetsblad för betalningshantering</translation>
-<translation id="3361596688432910856">Följande information <ph name="BEGIN_EMPHASIS" />sparas inte<ph name="END_EMPHASIS" /> i Chrome:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />webbhistoriken
- <ph name="LIST_ITEM" />cookies och webbplatsdata
- <ph name="LIST_ITEM" />uppgifter som angetts i formulär.
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">Den här principen kopierades automatiskt från den utfasade principen <ph name="OLD_POLICY" />. Använd den här principen i stället.</translation>
<translation id="3364869320075768271"><ph name="URL" /> vill använda VR-enheter och VR-data</translation>
<translation id="3366477098757335611">Visa kort</translation>
@@ -817,7 +848,6 @@ Annars blockeras detta av integritetsinställningarna. Om du tillåter detta kan
<translation id="3587738293690942763">Mellan</translation>
<translation id="3592413004129370115">Italian (kuvert)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{Du kan återställa grupptillhörigheten när som helst. Det tar ungefär ett dygn att bli med i en ny grupp.}=1{Du kan återställa grupptillhörigheten när som helst. Det tar ungefär ett dygn att bli med i en ny grupp.}other{Du kan återställa grupptillhörigheten när som helst. Det tar {NUM_DAYS} dygn att bli med i en ny grupp.}}</translation>
-<translation id="3596012367874587041">Appinställningar</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">Appen blockeras av administratören</translation>
<translation id="3608932978122581043">Ställa in riktning</translation>
@@ -860,6 +890,7 @@ Annars blockeras detta av integritetsinställningarna. Om du tillåter detta kan
<translation id="370972442370243704">Aktivera sökningar</translation>
<translation id="3711895659073496551">Stäng av</translation>
<translation id="3712624925041724820">Licenserna har tagit slut</translation>
+<translation id="3714633008798122362">webbkalender</translation>
<translation id="3714780639079136834">aktivera mobildata eller wifi</translation>
<translation id="3715597595485130451">Anslut till wifi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />kontrollera proxyn, brandväggen och DNS-konfigureringen<ph name="END_LINK" /></translation>
@@ -921,6 +952,7 @@ Annars blockeras detta av integritetsinställningarna. Om du tillåter detta kan
<translation id="3906954721959377182">Surfplatta</translation>
<translation id="3909477809443608991"><ph name="URL" /> vill spela upp skyddat innehåll. Enhetens identitet verifieras av Google och kan öppnas av webbplatsen.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">Neka</translation>
<translation id="3939773374150895049">Vill du använda WebAuthn i stället för CVC?</translation>
<translation id="3946209740501886391">Fråga alltid på den här webbplatsen</translation>
<translation id="3947595700203588284">Får begära tillstånd att ansluta till MIDI-enheter</translation>
@@ -942,6 +974,7 @@ Annars blockeras detta av integritetsinställningarna. Om du tillåter detta kan
<translation id="3990250421422698716">Stötvis förskjutning</translation>
<translation id="3996311196211510766">Webbplatsen <ph name="ORIGIN" /> har begärt att en ursprungsprincip
ska gälla varje gång den svarar på en begäran, men denna princip går inte att tillämpa just nu.</translation>
+<translation id="4009243425692662128">Innehållet på sidor du skriver ut skickas till Google Cloud eller tredje part för analys. Den kan till exempel genomsökas efter känsliga uppgifter.</translation>
<translation id="4010758435855888356">Vill du tillåta åtkomst till lagringsutrymmet?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{PDF-dokument som innehåller {COUNT} sida}other{PDF-dokument som innehåller {COUNT} sidor}}</translation>
<translation id="4023431997072828269">Din information blir synlig för andra eftersom anslutningen som används för att skicka formuläret inte är säker.</translation>
@@ -1036,6 +1069,7 @@ Annars blockeras detta av integritetsinställningarna. Om du tillåter detta kan
<translation id="4250680216510889253">Nej</translation>
<translation id="4253168017788158739">Kommentar</translation>
<translation id="425582637250725228">Ändringar som du har gjort kanske inte sparas.</translation>
+<translation id="425869179292622354">Vill du göra det säkrare med ett virtuellt kort?</translation>
<translation id="4258748452823770588">Felaktig signatur</translation>
<translation id="4261046003697461417">Det går inte annotera i skyddade dokument</translation>
<translation id="4265872034478892965">Beviljades av administratören</translation>
@@ -1098,6 +1132,7 @@ Annars blockeras detta av integritetsinställningarna. Om du tillåter detta kan
<translation id="4434045419905280838">Popup-fönster och omdirigeringar</translation>
<translation id="4435702339979719576">vykort)</translation>
<translation id="443673843213245140">Användning av proxy är inaktiverad men en explicit proxykonfiguration har angetts.</translation>
+<translation id="4441832193888514600">Ignoreras eftersom principen bara kan ställas in som en princip för molnanvändare.</translation>
<translation id="4450893287417543264">Visa inte igen</translation>
<translation id="4451135742916150903">Får begära tillstånd att ansluta till HID-enheter</translation>
<translation id="4452328064229197696">Lösenordet som du precis använde har läckt ut vid ett dataintrång. Du bör se över dina sparade lösenord för att skydda dina konton.</translation>
@@ -1153,6 +1188,7 @@ Annars blockeras detta av integritetsinställningarna. Om du tillåter detta kan
<translation id="4628948037717959914">Foto</translation>
<translation id="4631649115723685955">Cashback länkad</translation>
<translation id="4636930964841734540">Info</translation>
+<translation id="4638670630777875591">Inkognitoläge i Chromium</translation>
<translation id="464342062220857295">Sökfunktioner</translation>
<translation id="4644670975240021822">Motsatt ordning – framsidan nedåt</translation>
<translation id="4646534391647090355">GÃ¥ dit nu</translation>
@@ -1173,6 +1209,7 @@ Annars blockeras detta av integritetsinställningarna. Om du tillåter detta kan
<translation id="4708268264240856090">Anslutningen avbröts</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" /> köra nätverksdiagnostik för Windows<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426">Lösenord för <ph name="USERNAME" /></translation>
<translation id="4724144314178270921">Får begära tillstånd att läsa text och bilder i Urklipp</translation>
<translation id="4726672564094551039">Läs in policyer på nytt</translation>
<translation id="4728558894243024398">Plattform</translation>
@@ -1194,6 +1231,7 @@ Annars blockeras detta av integritetsinställningarna. Om du tillåter detta kan
<translation id="4757993714154412917">Du angav just ditt lösenord på en bedräglig webbplats. Du rekommenderas att kontrollera dina sparade lösenord i Chromium nu för att skydda dina konton.</translation>
<translation id="4758311279753947758">Lägg till kontaktuppgifter</translation>
<translation id="4761104368405085019">Använd mikrofonen</translation>
+<translation id="4761869838909035636">Kör säkerhetskontroll i Chrome</translation>
<translation id="4764776831041365478">Webbsidan på <ph name="URL" /> kan ligga nere för tillfället eller kan ha flyttats permanent till en ny webbadress.</translation>
<translation id="4766713847338118463">Två häftklamrar längst ned</translation>
<translation id="4771973620359291008">Ett okänt fel uppstod.</translation>
@@ -1214,12 +1252,6 @@ Annars blockeras detta av integritetsinställningarna. Om du tillåter detta kan
<translation id="4819347708020428563">Vill du redigera kommentarer i standardvyn?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />: tryck på Tabb och sedan på Retur om du snabbt vill skapa ett nytt Google-kalkylark</translation>
<translation id="4825507807291741242">Kraftfull</translation>
-<translation id="4827402517081186284">Inkognitoläget gör dig inte osynlig online:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Webbplatser vet att du besöker dem<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Din arbetsgivare eller skola kan spåra webbaktivitet<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Internetleverantören kan övervaka webbtrafik<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">Aktivera varningar</translation>
<translation id="4838327282952368871">Drömsk</translation>
<translation id="4840250757394056958">Visa Chrome-historiken</translation>
@@ -1231,12 +1263,12 @@ Annars blockeras detta av integritetsinställningarna. Om du tillåter detta kan
<translation id="4854362297993841467">Det här leveranssättet är inte tillgängligt. Testa ett annat alternativ.</translation>
<translation id="4854853140771946034">Skapa en ny anteckning i Google Keep snabbt</translation>
<translation id="485902285759009870">Koden verifieras …</translation>
+<translation id="4866506163384898554">Tryck på |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| om du vill att markören ska visas</translation>
<translation id="4876188919622883022">Förenklad visning</translation>
<translation id="4876305945144899064">Inget användarnamn</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{Inga}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831">Sök på <ph name="TEXT" /></translation>
<translation id="4879491255372875719">Automatiskt (standard)</translation>
-<translation id="4879725228911483934">Öppna fönster och placera ut dem på skärmen</translation>
<translation id="4880827082731008257">Sök i historiken</translation>
<translation id="4881695831933465202">Öppna</translation>
<translation id="4885256590493466218">Betala med <ph name="CARD_DETAIL" /> i kassan</translation>
@@ -1245,6 +1277,7 @@ Annars blockeras detta av integritetsinställningarna. Om du tillåter detta kan
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">Nionde rullen</translation>
<translation id="4901778704868714008">Spara …</translation>
+<translation id="4905659621780993806">Administratören startar om enheten automatiskt kl. <ph name="TIME" /> den <ph name="DATE" />. Spara det som du har öppet innan enheten startas om.</translation>
<translation id="4913987521957242411">Häfta uppe till vänster</translation>
<translation id="4918221908152712722">Installera <ph name="APP_NAME" /> (ingen nedladdning krävs)</translation>
<translation id="4923459931733593730">Betalning</translation>
@@ -1253,6 +1286,7 @@ Annars blockeras detta av integritetsinställningarna. Om du tillåter detta kan
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, tryck på Tabb och sedan på Retur om du vill söka</translation>
<translation id="4930153903256238152">Hög kapacitet</translation>
+<translation id="4940163644868678279">Inkognitoläge i Chrome</translation>
<translation id="4943872375798546930">Inga resultat</translation>
<translation id="4950898438188848926">Knapp för flikbyte. Tryck på retur för att byta till den öppna fliken <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="495170559598752135">Åtgärder</translation>
@@ -1262,6 +1296,7 @@ Annars blockeras detta av integritetsinställningarna. Om du tillåter detta kan
<translation id="4968522289500246572">Den här appen har utformats för mobila enheter och kan påverkas om storleken ändras. Appen kanske inte fungerar som den ska eller startas om.</translation>
<translation id="4969341057194253438">Radera inspelningen</translation>
<translation id="4973922308112707173">Två hål högst upp</translation>
+<translation id="4976702386844183910">Besöktes senast <ph name="DATE" /></translation>
<translation id="4984088539114770594">Vill du använda mikrofonen?</translation>
<translation id="4984339528288761049">Prc5 (kuvert)</translation>
<translation id="4989163558385430922">Visa alla</translation>
@@ -1323,6 +1358,7 @@ Annars blockeras detta av integritetsinställningarna. Om du tillåter detta kan
<translation id="5138227688689900538">Visa färre</translation>
<translation id="5145883236150621069">Felkoden ingår i policysvaret</translation>
<translation id="5146995429444047494">Aviseringar för <ph name="ORIGIN" /> blockeras.</translation>
+<translation id="514704532284964975"><ph name="URL" /> vill visa och ändra information på NFC-enheter som du trycker på med telefonen</translation>
<translation id="5148809049217731050">Framsidan uppåt</translation>
<translation id="515292512908731282">C4 (kuvert)</translation>
<translation id="5158275234811857234">Omslag</translation>
@@ -1347,6 +1383,7 @@ Annars blockeras detta av integritetsinställningarna. Om du tillåter detta kan
<translation id="5215116848420601511">Betalningsmetoder och adresser som används med Google Pay</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">Fack 13</translation>
+<translation id="5216942107514965959">Besöktes senast i dag</translation>
<translation id="5222812217790122047">E-postadress måste anges</translation>
<translation id="5230733896359313003">Leveransadress</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1367,7 +1404,6 @@ Annars blockeras detta av integritetsinställningarna. Om du tillåter detta kan
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">Dokumentegenskaper</translation>
<translation id="528468243742722775">Avsluta</translation>
-<translation id="5284909709419567258">Nätverksadresser</translation>
<translation id="5285570108065881030">Visa alla sparade lösenord</translation>
<translation id="5287240709317226393">Visa cookies</translation>
<translation id="5287456746628258573">Den här webbplatsens säkerhetskonfiguration är inaktuell. Det kan leda till att dina uppgifter (till exempel lösenord eller kreditkortsnummer) exponeras när de skickas till den här webbplatsen.</translation>
@@ -1451,6 +1487,7 @@ Annars blockeras detta av integritetsinställningarna. Om du tillåter detta kan
<translation id="5556459405103347317">Hämta igen</translation>
<translation id="5560088892362098740">Sista giltighetsdatum</translation>
<translation id="55635442646131152">Dokumentdisposition</translation>
+<translation id="5565613213060953222">Öppna inkognitoflik</translation>
<translation id="5565735124758917034">Aktiv</translation>
<translation id="5570825185877910964">Skydda kontot</translation>
<translation id="5571083550517324815">Utlämning erbjuds inte på den här adressen. Välj en annan adress.</translation>
@@ -1533,6 +1570,7 @@ Annars blockeras detta av integritetsinställningarna. Om du tillåter detta kan
<translation id="5869522115854928033">Sparade lösenord</translation>
<translation id="5873013647450402046">Din bank vill bekräfta att det är du.</translation>
<translation id="5887400589839399685">Kortet har sparats</translation>
+<translation id="5887687176710214216">Besöktes senast i går</translation>
<translation id="5895138241574237353">Starta om</translation>
<translation id="5895187275912066135">Utfärdat</translation>
<translation id="5901630391730855834">Gul</translation>
@@ -1546,6 +1584,7 @@ Annars blockeras detta av integritetsinställningarna. Om du tillåter detta kan
<translation id="5921639886840618607">Vill du spara kortet i Google-kontot?</translation>
<translation id="5922853866070715753">Nästan klart</translation>
<translation id="5932224571077948991">Påträngande eller vilseledande annonser visas på webbplatsen</translation>
+<translation id="5938153366081463283">Lägg till ett virtuellt kort</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347">Öppnar <ph name="SITE_NAME" /> …</translation>
<translation id="5951495562196540101">Det går inte att registrera enheten med ett konsumentkonto (paketerad licens är tillgänglig).</translation>
@@ -1610,6 +1649,7 @@ Annars blockeras detta av integritetsinställningarna. Om du tillåter detta kan
<translation id="6120179357481664955">Vill du spara UPI-id?</translation>
<translation id="6124432979022149706">Chrome Enterprise Connectors</translation>
<translation id="6127379762771434464">Objektet har tagits bort</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Läs mer om inkognitoläge i Chrome<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">Kontrollera kablar och starta om routrar, modem och andra nätverksenheter
som används.</translation>
<translation id="614940544461990577">Testa att</translation>
@@ -1622,7 +1662,6 @@ Annars blockeras detta av integritetsinställningarna. Om du tillåter detta kan
<translation id="6169916984152623906">Nu kan du surfa privat. Din aktivitet visas inte för andra som använder enheten, men nedladdningar och bokmärken sparas.</translation>
<translation id="6177128806592000436">Anslutningen till webbplatsen är inte säker</translation>
<translation id="6180316780098470077">Intervall för nytt försök</translation>
-<translation id="619448280891863779">Får begära tillstånd att öppna fönster och placera ut dem på skärmen</translation>
<translation id="6196640612572343990">Blockera cookies från tredje part</translation>
<translation id="6203231073485539293">Kontrollera internetanslutningen</translation>
<translation id="6218753634732582820">Vill du ta bort adressen från Chromium?</translation>
@@ -1645,7 +1684,7 @@ Annars blockeras detta av integritetsinställningarna. Om du tillåter detta kan
<translation id="6272383483618007430">Google Update</translation>
<translation id="6276112860590028508">Sidor från läslistan visas här</translation>
<translation id="627746635834430766">Spara kortet och faktureringsadressen i Google-kontot så går det snabbare att betala nästa gång.</translation>
-<translation id="6279098320682980337">Har det virtuella kortnumret inte fyllts i? Klicka på kortuppgifterna om du vill kopiera dem</translation>
+<translation id="6279183038361895380">Tryck på |<ph name="ACCELERATOR" />| om du vill visa markören</translation>
<translation id="6280223929691119688">Det går inte att leverera till den här adressen. Välj en annan adress.</translation>
<translation id="6282194474023008486">Postnummer</translation>
<translation id="6285507000506177184">Knappen Hantera nedladdningar i Chrome: tryck på Retur om du vill hantera filer du har laddat ned i Chrome</translation>
@@ -1653,6 +1692,7 @@ Annars blockeras detta av integritetsinställningarna. Om du tillåter detta kan
<translation id="6290238015253830360">Rekommenderade artiklar visas här</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{Enheten startas om nu}=1{Om 1 sekund startas enheten om}other{Om # sekunder startas enheten om}}</translation>
<translation id="6302269476990306341">Google-assistenten i Chrome stoppas</translation>
<translation id="6305205051461490394"><ph name="URL" /> kan inte nås.</translation>
<translation id="6312113039770857350">Webbsidan är inte tillgänglig</translation>
@@ -1726,6 +1766,7 @@ Annars blockeras detta av integritetsinställningarna. Om du tillåter detta kan
<translation id="6529602333819889595">&amp;Gör om Ta bort</translation>
<translation id="6545864417968258051">Bluetooth-sökning</translation>
<translation id="6547208576736763147">Två hål till vänster</translation>
+<translation id="6554732001434021288">Besöktes senast för <ph name="NUM_DAYS" /> dagar sedan</translation>
<translation id="6556866813142980365">Upprepa</translation>
<translation id="6569060085658103619">Du visar en tilläggssida</translation>
<translation id="6573200754375280815">Två hål till höger</translation>
@@ -1786,7 +1827,6 @@ Annars blockeras detta av integritetsinställningarna. Om du tillåter detta kan
<translation id="6757797048963528358">Enheten gick i viloläge.</translation>
<translation id="6767985426384634228">Vill du uppdatera adressen?</translation>
<translation id="6768213884286397650">Hagaki (vykort)</translation>
-<translation id="6774185088257932239"><ph name="BEGIN_LINK" />Läs mer<ph name="END_LINK" /> om inkognitoläget</translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">Violett</translation>
<translation id="6786747875388722282">Tillägg</translation>
@@ -1870,7 +1910,6 @@ Annars blockeras detta av integritetsinställningarna. Om du tillåter detta kan
<translation id="706295145388601875">Lägg till och hantera adresser i inställningarna för Chrome</translation>
<translation id="7064851114919012435">Kontaktuppgifter</translation>
<translation id="7068733155164172741">Ange den <ph name="OTP_LENGTH" />-siffriga koden</translation>
-<translation id="7070090581017165256">Om den här webbplatsen</translation>
<translation id="70705239631109039">Anslutningen är inte helt säker</translation>
<translation id="7075452647191940183">Begäran är för stor</translation>
<translation id="7079718277001814089">Webbplatsen innehåller skadlig programvara.</translation>
@@ -1887,6 +1926,12 @@ Annars blockeras detta av integritetsinställningarna. Om du tillåter detta kan
<translation id="7111012039238467737">(Giltigt)</translation>
<translation id="7118618213916969306">Sök efter webbadressen i Urklipp, <ph name="SHORT_URL" /></translation>
<translation id="7119414471315195487">Stäng andra flikar eller program</translation>
+<translation id="7129355289156517987">När du stänger inkognitoflikar i Chromium rensas följande aktivitet i flikarna från denna enhet:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Webbaktivitet<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Sökhistorik<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Uppgifter som anges i formulär<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">Det går inte att skicka till den här adressen. Välj en annan adress.</translation>
<translation id="7132939140423847331">Administratören tillåter inte att denna data kopieras.</translation>
<translation id="7135130955892390533">Visa status</translation>
@@ -1909,6 +1954,7 @@ Annars blockeras detta av integritetsinställningarna. Om du tillåter detta kan
<translation id="7192203810768312527">Frigör <ph name="SIZE" />. Vissa webbplatser kan läsas in långsammare nästa gång du besöker dem.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">Administratören kan se</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />. Tryck på Tabb och sedan på Retur om du vill öppna en ny inkognitoflik och surfa privat</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> följer inte säkerhetsstandarderna.</translation>
<translation id="7210993021468939304">Linux-aktivitet i behållaren och kan installera och köra Linux-appar i behållaren</translation>
@@ -1940,6 +1986,7 @@ Mer information.
<translation id="7304562222803846232">Hantera Google-kontots integritetsinställningar</translation>
<translation id="7305756307268530424">Starta långsammare</translation>
<translation id="7308436126008021607">synkronisering i bakgrunden</translation>
+<translation id="7310392214323165548">Enheten startas om inom kort</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">Anslutningshjälp</translation>
<translation id="7323804146520582233">Dölj avsnittet <ph name="SECTION" /></translation>
@@ -1947,6 +1994,7 @@ Mer information.
<translation id="7334320624316649418">&amp;Gör om Ändra ordning</translation>
<translation id="7335157162773372339">Får begära åtkomst till kameran</translation>
<translation id="7337248890521463931">Visa fler rader</translation>
+<translation id="7337418456231055214">Har det virtuella kortnumret inte fyllts i? Klicka på kortuppgifterna om du vill kopiera dem. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">Ej tillgänglig för din plattform.</translation>
<translation id="733923710415886693">Servercertifikatet har inte lämnats ut via Certifikattransparens.</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1969,6 +2017,7 @@ Mer information.
<translation id="7378627244592794276">Nej</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">Ej tillämpligt</translation>
+<translation id="7388594495505979117">{0,plural, =1{Om 1 minut startas enheten om}other{Om # minuter startas enheten om}}</translation>
<translation id="7390545607259442187">Bekräfta kort</translation>
<translation id="7392089738299859607">Uppdatera adressen</translation>
<translation id="7399802613464275309">Säkerhetskontroll</translation>
@@ -2005,6 +2054,12 @@ Mer information.
<translation id="7485870689360869515">Ingen data hittades.</translation>
<translation id="7495528107193238112">Det här innehållet har blockerats. Kontakta webbplatsägaren om du vill åtgärda problemet.</translation>
<translation id="7497998058912824456">Knappen Skapa Google-dokument: tryck på Retur om du snabbt vill skapa ett nytt Google-dokument</translation>
+<translation id="7506488012654002225">Följande information sparas <ph name="BEGIN_EMPHASIS" />inte<ph name="END_EMPHASIS" /> i Chromium:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Din webbhistorik
+ <ph name="LIST_ITEM" />Cookies och webbplatsdata
+ <ph name="LIST_ITEM" />Uppgifter som anges i formulär
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">Enhets-id för returnerad princip är tomt eller matchar inte nuvarande enhets-id</translation>
<translation id="7508870219247277067">Avokadogrön</translation>
<translation id="7511955381719512146">wifi-nätverket du använder kanske kräver att du besöker <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
@@ -2118,7 +2173,6 @@ Mer information.
<translation id="7813600968533626083">Vill du ta bort formulärförslaget från Chrome?</translation>
<translation id="781440967107097262">Vill du dela urklipp?</translation>
<translation id="7815407501681723534">Hittade <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> för <ph name="SEARCH_STRING" /></translation>
-<translation id="782125616001965242">Visa information om den här webbplatsen</translation>
<translation id="782886543891417279">wifi-nätverket du använder (<ph name="WIFI_NAME" />) kanske kräver att du besöker dess inloggningssida.</translation>
<translation id="7836231406687464395">Postfix (kuvert)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{Inga}=1{1 app (<ph name="EXAMPLE_APP_1" />)}=2{2 appar (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}other{# appar (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}}</translation>
@@ -2135,7 +2189,6 @@ Mer information.
<translation id="7888575728750733395">Renderingsmetod för utskrifter</translation>
<translation id="7894280532028510793">Om stavningen är rätt <ph name="BEGIN_LINK" />testar du att köra nätverksdiagnostik<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (kuvert)</translation>
-<translation id="7931318309563332511">okänt</translation>
<translation id="793209273132572360">Vill du uppdatera adressen?</translation>
<translation id="7932579305932748336">Beläggning</translation>
<translation id="79338296614623784">Ange ett giltigt telefonnummer</translation>
@@ -2160,13 +2213,14 @@ Mer information.
<translation id="7976214039405368314">För många begäranden</translation>
<translation id="7977538094055660992">Utmatningsenhet</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">Är länkat till</translation>
<translation id="798134797138789862">Får begära tillstånd att använda VR-enheter och VR-data</translation>
<translation id="7984945080620862648">Det går inte att besöka <ph name="SITE" /> just nu på grund av att webbplatsen skickade röriga användaruppgifter som Chrome inte kan behandla. Nätverksfel och attacker är vanligtvis tillfälliga, så sidan fungerar troligen senare.</translation>
-<translation id="79859296434321399">Installera ARCore om du vill visa innehåll med förstärkt verklighet</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">Bind</translation>
<translation id="7992044431894087211">Skärmdelningen med <ph name="APPLICATION_TITLE" /> återupptogs</translation>
<translation id="7995512525968007366">Inte specificerad</translation>
+<translation id="7998269595945679889">Knappen Öppna en inkognitoflik. Tryck på Retur om du vill öppna en ny inkognitoflik och surfa privat</translation>
<translation id="800218591365569300">Testa att stänga andra flikar eller program för att frigöra minne.</translation>
<translation id="8004582292198964060">Webbläsare</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{Det här kortet och dess faktureringsadress sparas. Du kan använda det när du är inloggad som <ph name="USER_EMAIL" />.}other{De här korten och deras faktureringsadresser sparas. Du kan använda dem när du är inloggad som <ph name="USER_EMAIL" />.}}</translation>
@@ -2226,6 +2280,7 @@ Mer information.
<translation id="8202370299023114387">Konflikt</translation>
<translation id="8206978196348664717">Prc4 (kuvert)</translation>
<translation id="8211406090763984747">Anslutningen är säker</translation>
+<translation id="8217240300496046857">Webbplatser kan inte använda cookies som spårar dig på webben. Funktioner på vissa webbplatser kan sluta fungera.</translation>
<translation id="8218327578424803826">Tilldelad plats:</translation>
<translation id="8220146938470311105">C7/C6 (kuvert)</translation>
<translation id="8225771182978767009">Personen som konfigurerade datorn har valt att blockera den här webbplatsen.</translation>
@@ -2266,14 +2321,9 @@ Mer information.
<translation id="830498451218851433">Enkelfalsning</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">Vilka appar som har installerats och hur ofta de används</translation>
+<translation id="8317207217658302555">Vill du uppdatera ARCore?</translation>
<translation id="831997045666694187">kvällen</translation>
<translation id="8321476692217554900">aviseringar</translation>
-<translation id="8328484624016508118">När du har stängt alla inkognitoflikar i Chrome raderas följande:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Din webbaktivitet från den här enheten<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Din sökhistorik från den här enheten<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Information som angetts i formulär<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489">Ã…tkomst nekades till <ph name="HOST_NAME" />.</translation>
<translation id="833262891116910667">Markera</translation>
<translation id="8339163506404995330">Sidor på <ph name="LANGUAGE" /> översätts inte</translation>
@@ -2325,6 +2375,7 @@ Mer information:
<translation id="8507227106804027148">Kommandorad</translation>
<translation id="8508648098325802031">Sökikon</translation>
<translation id="8511402995811232419">Hantera cookies</translation>
+<translation id="8519753333133776369">HID-enhet som tillåts av administratören</translation>
<translation id="8522552481199248698">Du kan skydda Google-kontot genom att byta lösenord.</translation>
<translation id="8530813470445476232">Rensa webbhistorik, cookies, cache med mera i inställningarna för Chrome</translation>
<translation id="8533619373899488139">Besök &lt;strong&gt;chrome://policy&lt;/strong&gt; om du vill visa listan med blockerade webbadresser och andra policyer som angetts av systemadministratören.</translation>
@@ -2336,7 +2387,6 @@ Mer information:
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{Återställ behörighet}other{Återställ behörigheter}}</translation>
<translation id="8555010941760982128">Använd följande kod i kassan</translation>
<translation id="8557066899867184262">CVC-koden finns på baksidan av kortet.</translation>
-<translation id="8558485628462305855">Uppdatera ARCore om du vill visa innehåll med förstärkt verklighet</translation>
<translation id="8559762987265718583">Det gick inte att upprätta en privat anslutning till <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> eftersom enhetens datum och tid (<ph name="DATE_AND_TIME" />) inte stämmer.</translation>
<translation id="8564182942834072828">Separata dokument/kopior grupperade per sida</translation>
<translation id="8564985650692024650">Du rekommenderas att återställa lösenordet för <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> om du har återanvänt det på andra webbplatser.</translation>
@@ -2356,6 +2406,7 @@ Mer information:
<translation id="865032292777205197">rörelsesensorer</translation>
<translation id="8663226718884576429">Beställningsöversikt, <ph name="TOTAL_LABEL" />, mer information</translation>
<translation id="8666678546361132282">engelska</translation>
+<translation id="8669306706049782872">Använda information om dina skärmar för att öppna och placera ut fönster</translation>
<translation id="867224526087042813">Signatur</translation>
<translation id="8676424191133491403">Ingen fördröjning</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, svar, <ph name="ANSWER" /></translation>
@@ -2382,6 +2433,7 @@ Mer information:
<translation id="8731544501227493793">Knappen Hantera lösenord, tryck på Retur om du vill visa och hantera lösenord i inställningarna för Chrome</translation>
<translation id="8734529307927223492">Din <ph name="DEVICE_TYPE" /> hanteras av <ph name="MANAGER" /></translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, tryck på Tabb och sedan på Retur om du vill öppna ett nytt inkognitofönster och surfa privat</translation>
+<translation id="8737685506611670901">Öppna <ph name="PROTOCOL" />-länkar i stället för <ph name="REPLACED_HANDLER_TITLE" /></translation>
<translation id="8738058698779197622">Om du vill upprätta en säker anslutning måste klockan vara rätt inställd. Det beror på att certifikaten som webbplatserna använder för att identifiera sig endast är giltiga under vissa tidsperioder. Chromium kan inte verifiera certifikaten eftersom klockan på enheten inte stämmer.</translation>
<translation id="8740359287975076522">Det gick inte att hitta <ph name="HOST_NAME" />s &lt;abbr id="dnsDefinition"&gt;DNS-adress&lt;/abbr&gt;. Diagnostiserar problemet.</translation>
<translation id="8742371904523228557"><ph name="ONE_TIME_CODE" /> är din kod för <ph name="ORIGIN" /></translation>
@@ -2409,6 +2461,7 @@ Mer information:
<translation id="883848425547221593">Övriga bokmärken</translation>
<translation id="884264119367021077">Leveransadress</translation>
<translation id="884923133447025588">Ingen återkallningsmekanism har hittats.</translation>
+<translation id="8849262850971482943">Använd det virtuella kreditkortet för ökad säkerhet</translation>
<translation id="885730110891505394">Delar med Google</translation>
<translation id="8858065207712248076">Du rekommenderas att återställa lösenordet för <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> om du har återanvänt det på andra webbplatser.</translation>
<translation id="885906927438988819">Om stavningen är rätt <ph name="BEGIN_LINK" />testar du att köra nätverksdiagnostik för Windows<ph name="END_LINK" />.</translation>
@@ -2458,6 +2511,7 @@ Mer information:
<translation id="9004367719664099443">En VR-session pågår</translation>
<translation id="9005998258318286617">Det gick inte att läsa in PDF-dokumentet.</translation>
<translation id="9008201768610948239">Ignorera</translation>
+<translation id="901834265349196618">e-post</translation>
<translation id="9020200922353704812">Kortets faktureringsadress måste anges</translation>
<translation id="9020542370529661692">Den här sidan har översatts till <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9020742383383852663">A8</translation>
@@ -2506,6 +2560,7 @@ Mer information:
<translation id="9150045010208374699">Använd kameran</translation>
<translation id="9150685862434908345">Administratören kan ändra webbläsarinställningarna på distans. Aktivitet på den här enheten kan hanteras även utanför Chrome. <ph name="BEGIN_LINK" />Läs mer<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">Uppdaterat</translation>
+<translation id="9155211586651734179">Ansluten kringutrustning för ljud</translation>
<translation id="9157595877708044936">Konfigurerar...</translation>
<translation id="9158625974267017556">C6 (kuvert)</translation>
<translation id="9164029392738894042">Precisionskontroll</translation>
diff --git a/chromium/components/strings/components_strings_sw.xtb b/chromium/components/strings/components_strings_sw.xtb
index 0d70253822f..6a974accbda 100644
--- a/chromium/components/strings/components_strings_sw.xtb
+++ b/chromium/components/strings/components_strings_sw.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">Angalia maelezo</translation>
<translation id="1030706264415084469"><ph name="URL" /> inataka kuhifadhi data nyingi kwenye kifaa chako kwa muda mrefu</translation>
<translation id="1032854598605920125">Zungusha kwenye mwendo wa saa</translation>
+<translation id="1033329911862281889">Hali fiche haizuii shughuli unazotekeleza mtandaoni zisionekane:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Tovuti na huduma unazotembelea zinaweza kuonekana<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Waajiri au shule zinaweza kufuatilia shughuli za kuvinjari<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Watoa huduma za Intaneti wanaweza kufuatilia trafiki kwenye wavuti<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">Zima</translation>
<translation id="1036982837258183574">Bonyeza |<ph name="ACCELERATOR" />| ili uondoke kwenye skrini nzima</translation>
<translation id="1038106730571050514">Onyesha mapendekezo</translation>
<translation id="1038842779957582377">jina lisilojulikana</translation>
<translation id="1041998700806130099">Ujumbe wa laha la kazi</translation>
<translation id="1048785276086539861">Ukibadilisha vidokezo, hati hii itarejea kwenye mwonekano wa ukurasa mmoja</translation>
-<translation id="1049743911850919806">Kichupo fiche</translation>
<translation id="1050038467049342496">Funga programu nyingine</translation>
<translation id="1055184225775184556">Tendua Kuongeza</translation>
<translation id="1056898198331236512">Ilani</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">Akiba ya sera ni SAWA</translation>
<translation id="1130564665089811311">Kitufe cha 'Tafsiri ukurasa', bonyeza 'Enter' ili utafsiri ukurasa huu kwa kutumia Google Tafsiri</translation>
<translation id="1131264053432022307">Picha Uliyonakili</translation>
+<translation id="1142846828089312304">Zuia vidakuzi vya wengine katika hali fiche</translation>
<translation id="1150979032973867961">Seva hii haikuweza kuthibitisha kuwa ni <ph name="DOMAIN" />; cheti chake cha usalama hakiaminiwi na mfumo wa uendeshaji wa kompyuta yako. Hii inaweza kusababishwa na usanidi usiofaa au mvamizi kuingilia muunganisho wako.</translation>
<translation id="1151972924205500581">Nenosiri linahitajika</translation>
<translation id="1156303062776767266">Unaangalia faili ya mfumo au iliyoshirikiwa</translation>
@@ -64,7 +70,6 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="1178581264944972037">Sitisha</translation>
<translation id="1181037720776840403">Ondoa</translation>
<translation id="1186201132766001848">Kagua Manenosiri</translation>
-<translation id="1195210374336998651">Nenda kwenye mipangilio ya programu</translation>
<translation id="1195558154361252544">Arifa zinazuiwa kiotomatiki kwenye tovuti zote isipokuwa zile unazoruhusu</translation>
<translation id="1197088940767939838">Rangi ya machungwa</translation>
<translation id="1201402288615127009">Endelea</translation>
@@ -111,7 +116,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="1307966114820526988">Vipengele Vilivyoacha Kutumiwa</translation>
<translation id="1308113895091915999">Ofa inapatikana</translation>
<translation id="1312803275555673949">Je, kuna ithibati gani nyingine?</translation>
-<translation id="131405271941274527"><ph name="URL" /> inataka kutuma na kupokea maelezo unapogusisha simu yako kwenye kifaa cha NFC</translation>
+<translation id="1314311879718644478">Angalia maudhui ya uhalisia ulioboreshwa</translation>
<translation id="1314509827145471431">Unganisha kulia</translation>
<translation id="1318023360584041678">Imehifadhiwa katika kikundi cha vichupo</translation>
<translation id="1319245136674974084">Usiulize tena kwenye programu hii</translation>
@@ -161,6 +166,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="142858679511221695">Mtumiaji wa Google Cloud</translation>
<translation id="1428729058023778569">Unaona onyo hili kwa sababu tovuti hii haiwezi kutumia HTTPS. <ph name="BEGIN_LEARN_MORE_LINK" />Pata maelezo zaidi<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">Chapisha</translation>
+<translation id="1432187715652018471">ukurasa huu unataka kusakinisha kidhibiti cha huduma.</translation>
<translation id="1432581352905426595">Dhibiti mitambo ya kutafuta</translation>
<translation id="1436185428532214179">Inaweza kuomba ruhusa ya kubadilisha faili na folda kwenye kifaa chako</translation>
<translation id="1442386063175183758">Mikunjo miwili sambamba kulia</translation>
@@ -181,6 +187,12 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="1483493594462132177">Tuma</translation>
<translation id="1484290072879560759">Chagua Anwani ya Mahali Bidhaa Zitakapopelekwa</translation>
<translation id="1492194039220927094">Sera zinaweza kutumwa:</translation>
+<translation id="149293076951187737">Unapofunga vichupo vyote fiche kwenye Chrome, shughuli zako kwenye vichupo hivyo zitafutwa katika kifaa hiki:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Shughuli za kuvinjari<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Historia ya mambo uliyotafuta<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Maelezo unayojaza katika fomu<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">Rudi kwenye kichupo</translation>
<translation id="1501859676467574491">Onyesha kadi kutoka Akaunti yako ya Google</translation>
<translation id="1507202001669085618">&lt;p&gt;Utaona hitilafu hii kama unatumia mtandao wa Wi-Fi ambapo unatakiwa kuingia katika akaunti kabla ya kwenda mtandaoni.&lt;/p&gt;
@@ -208,6 +220,8 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="1559572115229829303">&lt;p&gt;Muunganisho wa faragha kwenye <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> hauwezi kutambuliwa kwa sababu tarehe na wakati wa kifaa chako <ph name="DATE_AND_TIME" /> si sahihi.&lt;/p&gt;
&lt;p&gt;Tafadhali rekebisha tarehe na wakati kutoka kwenye &lt;strong&gt;sehemu ya Jumla&lt;/strong&gt; ya &lt;strong&gt;programu ya Mipangilio&lt;/strong&gt;.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">Msimamizi wako atazima kisha kuwasha kifaa chako saa <ph name="TIME" /> tarehe <ph name="DATE" /></translation>
+<translation id="156703335097561114">Maelezo ya mtandao kama vile anwani, mipangilio ya kiolesura na ubora wa muunganisho</translation>
<translation id="1567040042588613346">Sera hii inafanya kazi inavyokusudiwa lakini thamani sawa na hii imewekwa mahali pengine na nafasi yake imechukuliwa na sera hii.</translation>
<translation id="1569487616857761740">Weka tarehe ya mwisho wa matumizi</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="1583429793053364125">Hitilafu ilitokea wakati wa kuonyesha ukurasa huu wa wavuti.</translation>
<translation id="1586541204584340881">Viendelezi ambavyo umesakinisha</translation>
<translation id="1588438908519853928">Ya kawaida</translation>
+<translation id="1589050138437146318">Ungependa kusakinisha ARCore?</translation>
<translation id="1592005682883173041">Ufikiaji wa Data Iliyo Katika Kifaa Chako</translation>
<translation id="1594030484168838125">Chagua</translation>
<translation id="160851722280695521">Cheza mchezo wa Dinosau Anayekimbia katika Chrome</translation>
@@ -254,7 +269,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="1711234383449478798">Imepuuzwa kwa sababu <ph name="POLICY_NAME" /> haijawekwa kuwa <ph name="VALUE" />.</translation>
<translation id="1712552549805331520"><ph name="URL" /> inataka kuhifadhi kabisa data kwenye kompyuta yako ya karibu</translation>
<translation id="1713628304598226412">Trei ya pili</translation>
-<translation id="1715874602234207">F</translation>
+<translation id="1715874602234207">Ij</translation>
<translation id="1717218214683051432">Vitambuzi vya mwendo</translation>
<translation id="1717494416764505390">Kikasha cha barua cha tatu</translation>
<translation id="1718029547804390981">Huwezi kuweka vidokezo kwenye hati kwa kuwa ni kubwa mno</translation>
@@ -282,6 +297,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
inayotaka sera ya asili itumike katika maombi yote inayopokea. Lakini
mada si sahihi, hali inayozuia kivinjari kisitekeleze
ombi lako la <ph name="SITE" />. Sera za asili zinaweza kutumiwa na wahudumu wa tovuti kuweka mipangilio ya usalama na sifa nyingine za tovuti.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Pata maelezo zaidi kuhusu Hali fiche kwenye Chromium<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">Vichupo vyako vilivyo wazi huonekana hapa</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -409,6 +425,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="22081806969704220">Trei ya tatu</translation>
<translation id="2212735316055980242">Sera haikupatikana</translation>
<translation id="2213606439339815911">Inachukua viingizo...</translation>
+<translation id="2213612003795704869">Ukurasa umechapishwa</translation>
<translation id="2215727959747642672">Kubadilisha faili</translation>
<translation id="2218879909401188352">Wavamizi walio kwenye <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> hivi sasa, wanaweza kusakinisha programu hatari zinazoweza kukiharibu kifaa chako, kuongeza gharama fiche kwenye malipo yako ya simu, au kuiba maelezo yako ya binafsi. <ph name="BEGIN_LEARN_MORE_LINK" />Pata maelezo zaidi<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">Hakuna intaneti</translation>
@@ -418,6 +435,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="2248949050832152960">Tumia WebAuthn</translation>
<translation id="2250931979407627383">Shona ncha ya kushoto</translation>
<translation id="225207911366869382">Thamani hii inapingwa kwa sera hii.</translation>
+<translation id="2256115617011615191">Zima na uwashe sasa</translation>
<translation id="2258928405015593961">Weka tarehe ya mwisho wa matumizi katika wakati ujao kisha ujaribu tena</translation>
<translation id="225943865679747347">Hitilafu ya msimbo: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">Hitilfau ya HTTP</translation>
@@ -445,6 +463,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="2337852623177822836">Mipangilio inadhibitiwa na msimamizi wako</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> inataka kuoanisha</translation>
<translation id="2346319942568447007">Picha uliyonakili</translation>
+<translation id="2350796302381711542">Ungependa kuruhusu <ph name="HANDLER_HOSTNAME" /> kufungua viungo vyote vya <ph name="PROTOCOL" /> badala ya <ph name="REPLACED_HANDLER_TITLE" />?</translation>
<translation id="2354001756790975382">Alamisho zingine</translation>
<translation id="2354430244986887761">Kipengele cha Kuvinjari Salama kwenye Google <ph name="BEGIN_LINK" />kilipata programu hasidi<ph name="END_LINK" /> kwenye <ph name="SITE" /> hivi majuzi.</translation>
<translation id="2355395290879513365">Wavamizi wanaweza kuona picha unazoangalia kwenye tovuti hii na wakuhadae kwa kuzibadilisha.</translation>
@@ -470,6 +489,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="2413528052993050574">Seva hii haikuweza kuthibitisha kuwa ni <ph name="DOMAIN" />; huenda cheti chake cha usalama kimebatilishwa. Hii inaweza kusababishwa na usanidi usiofaa au mvamizi kuingilia muunganisho wako.</translation>
<translation id="2414886740292270097">Giza</translation>
<translation id="2430968933669123598">Dhibiti Akaunti ya Google, bonyeza 'Enter' ili udhibiti maelezo, faragha na usalama wako katika Akaunti yako ya Google</translation>
+<translation id="2436186046335138073">Ungependa kuruhusu <ph name="HANDLER_HOSTNAME" /> kufungua viungo vyote vya <ph name="PROTOCOL" />?</translation>
<translation id="2438874542388153331">Toboa mara nne kulia</translation>
<translation id="2450021089947420533">Ziara</translation>
<translation id="2463739503403862330">Jaza</translation>
@@ -477,6 +497,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="2465655957518002998">Chagua Njia ya Kusafirisha</translation>
<translation id="2465688316154986572">Bana</translation>
<translation id="2465914000209955735">Dhibiti faili ulizozipakua katika Chrome</translation>
+<translation id="2466004615675155314">Onyesha maelezo kutoka kwenye wavuti</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Inaendesha Zana ya Kuchunguza Mtandao<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">Mpangilio wa moja hadi N</translation>
<translation id="2470767536994572628">Ukibadilisha vidokezo, hati hii itarejea kwenye mwonekano wa ukurasa mmoja na mzunguko wake wa asili</translation>
@@ -497,6 +518,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="2523886232349826891">Imehifadhiwa kwenye kifaa hiki pekee</translation>
<translation id="2524461107774643265">Ongeza Maelezo Zaidi</translation>
<translation id="2529899080962247600">Hupaswi kuweka zaidi ya vipengee <ph name="MAX_ITEMS_LIMIT" /> katika sehemu hii. Vipengee vyote vya ziada vitapuuzwa.</translation>
+<translation id="2535585790302968248">Fungua kichupo fiche kipya ili uvinjari kwa faragha</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{na lingine 1}other{na mengine #}}</translation>
<translation id="2536110899380797252">Ongeza Anwani</translation>
<translation id="2539524384386349900">Gundua</translation>
@@ -522,7 +544,14 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="2597378329261239068">Hati hii imelindwa kwa nenosiri. Tafadhali weka nenosiri linalotumika.</translation>
<translation id="2609632851001447353">Vipera</translation>
<translation id="2610561535971892504">Bofya ili unakili</translation>
+<translation id="2617988307566202237">Chrome <ph name="BEGIN_EMPHASIS" />haitahifadhi<ph name="END_EMPHASIS" /> maelezo yafuatayo:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Historia yako ya kuvinjari
+ <ph name="LIST_ITEM" />Vidakuzi na data ya tovuti
+ <ph name="LIST_ITEM" />Maelezo unayojaza katika fomu
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (Bahasha)</translation>
+<translation id="2623663032199728144">Inaweza kuomba ruhusa ya kutumia maelezo kuhusu skrini zako</translation>
<translation id="2625385379895617796">Saa yako iko mbele</translation>
<translation id="262745152991669301">Inaweza kuomba ruhusa ya kuunganisha kwenye vifaa vya USB</translation>
<translation id="2629325967560697240">Ili upate kiwango cha juu zaidi cha usalama kutoka Chrome, <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />washa kipengele cha ulinzi wa kiwango cha juu<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -556,6 +585,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="2709516037105925701">Kujaza Kiotomatiki</translation>
<translation id="2713444072780614174">Nyeupe</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />, bonyeza 'Tab' kisha 'Enter' ili udhibiti maelezo yako ya malipo na ya kadi ya mikopo katika mipangilio ya Chrome</translation>
+<translation id="271663710482723385">Bonyeza |<ph name="ACCELERATOR1" />| + | <ph name="ACCELERATOR2" /> | ili uondoke kwenye skrini nzima</translation>
<translation id="2721148159707890343">Ombi limefanikiwa</translation>
<translation id="2723669454293168317">Fanya ukaguzi wa usalama katika mipangilio ya Chrome</translation>
<translation id="2726001110728089263">Trei ya Pembeni</translation>
@@ -586,6 +616,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="2850739647070081192">Invite (Bahasha)</translation>
<translation id="2856444702002559011">Huenda wavamizi wanajaribu kuiba maelezo yako kutoka <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (kwa mfano, manenosiri, ujumbe au kadi za mikopo).<ph name="BEGIN_LEARN_MORE_LINK" />Pata maelezo zaidi<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">Tovuti inaonyesha matangazo yanayopotosha au yanayokatiza huduma.</translation>
+<translation id="286512204874376891">Kadi pepe huficha kadi yako halisi ili kusaidia kukulinda dhidi ya ulaghai unaoweza kutokea. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">Friendly</translation>
<translation id="2876489322757410363">Inafunga hali fiche ili kulipa kupitia programu ya nje. Ungependa kuendelea?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />, bonyeza 'Tab' kisha 'Enter' ili udhibiti kipengele chako cha Kuvinjari Salama na zaidi katika mipangilio ya Chrome</translation>
@@ -610,6 +641,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="2930577230479659665">Punguza baada ya kila nakala</translation>
<translation id="2932085390869194046">Pendekeza Nenosiri…</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019">Kufungua viungo vya <ph name="PROTOCOL" /></translation>
<translation id="2941952326391522266">Seva hii haikuweza kuthibitisha kuwa ni <ph name="DOMAIN" />; cheti chake cha usalama kinatoka <ph name="DOMAIN2" />. Hii inaweza kusababishwa na usanidi usiofaa au mvamizi kuingilia muunganisho wako.</translation>
<translation id="2943895734390379394">Muda wa Kupakia:</translation>
<translation id="2948083400971632585">Unaweza kuzima proksi zozote zilizosanidiwa kwa muunganisho kutoka kwenye ukurasa wa mipangilio.</translation>
@@ -642,6 +674,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="3037605927509011580">Lo!</translation>
<translation id="3041612393474885105">Maelezo ya Cheti</translation>
<translation id="3044034790304486808">Endelea na utafiti wako</translation>
+<translation id="305162504811187366">Historia ya Programu ya Chrome ya Ufikiaji wa Kompyuta kutoka Mbali, ikiwa ni pamoja na mihuri ya wakati, seva pangishi na vitambulisho vya vipindi vya programu teja</translation>
<translation id="3060227939791841287">C9 (Bahasha)</translation>
<translation id="3061707000357573562">Huduma ya Kurekebisha</translation>
<translation id="306573536155379004">Mchezo umeanza.</translation>
@@ -682,6 +715,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="3197136577151645743">Inaweza kuomba ruhusa ya kujua wakati unatumia kifaa hiki</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />, bonyeza 'Tab' kisha 'Enter' ili udhibiti maelezo unayosawazisha katika mipangilio ya Chrome</translation>
<translation id="320323717674993345">Ghairi Malipo</translation>
+<translation id="3203366800380907218">Kutoka kwenye wavuti</translation>
<translation id="3207960819495026254">Imealamishwa</translation>
<translation id="3209034400446768650">Huenda ukurasa ukakutoza</translation>
<translation id="3212581601480735796">Shughuli zako kwenye <ph name="HOSTNAME" /> zinafuatiliwa</translation>
@@ -698,10 +732,12 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="3234666976984236645">Gundua maudhui muhimu kwenye tovuti hii wakati wowote</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />, Bonyeza 'tab' kisha 'Enter' ili uweke mapendeleo ya mwonekano wa kivinjari chako</translation>
<translation id="3240791268468473923">Laha ya 'hakuna kitambulisho kinacholingana' imefunguliwa</translation>
+<translation id="324180406144491771">Viungo vya “<ph name="HOST_NAME" />†vimezuiwa</translation>
<translation id="3249845759089040423">Groovy</translation>
<translation id="3252266817569339921">Kifaransa</translation>
<translation id="3257954757204451555">Maelezo haya yameandikwa na nani?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />, bonyeza 'Tab' kisha 'Enter' ili uweke tukio jipya katika Kalenda ya Google kwa haraka</translation>
+<translation id="3261488570342242926">Pata maelezo kuhusu kadi pepe</translation>
<translation id="3264837738038045344">Kitufe cha 'Dhibiti mipangilio ya Chrome', bonyeza 'Enter' ili uende kwenye mipangilio yako ya Chrome</translation>
<translation id="3266793032086590337">Thamani (inakinzana)</translation>
<translation id="3268451620468152448">Fungua Vichupo</translation>
@@ -715,6 +751,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="3288238092761586174">Huenda <ph name="URL" /> ikahitaji kuchukua hatua za ziada ili kuthibitisha malipo yako</translation>
<translation id="3293642807462928945">Pata maelezo zaidi kuhusu sera ya <ph name="POLICY_NAME" /></translation>
<translation id="3295444047715739395">Angalia na udhibiti manenosiri yako katika mipangilio ya Chrome</translation>
+<translation id="3303795387212510132">Ungependa kuruhusu programu ifungue viungo vya <ph name="PROTOCOL_SCHEME" />?</translation>
<translation id="3303855915957856445">Hakuna matokeo ya utafutaji yaliyopatikana</translation>
<translation id="3304073249511302126">kutafuta vifaa vyenye bluetooth</translation>
<translation id="3308006649705061278">Sehemu ya Shirika (OU)</translation>
@@ -728,12 +765,6 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="3345782426586609320">Macho</translation>
<translation id="3355823806454867987">Badilisha mipangilio ya seva mbadala...</translation>
<translation id="3360103848165129075">Laha la kidhibiti cha malipo</translation>
-<translation id="3361596688432910856">Chrome <ph name="BEGIN_EMPHASIS" />haitahifadhi<ph name="END_EMPHASIS" /> maelezo yafuatayo:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Historia yako ya kuvinjari
- <ph name="LIST_ITEM" />Data ya vidakuzi na tovuti
- <ph name="LIST_ITEM" />Maelezo unayojaza katika fomu
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">Sera hii ilinakiliwa kiotomatiki kutoka sera iliyoacha kuendesha huduma ya <ph name="OLD_POLICY" />. Unapaswa kutumia sera hii badala yake.</translation>
<translation id="3364869320075768271"><ph name="URL" /> inataka kutumia data na kifaa chako cha uhalisia pepe</translation>
<translation id="3366477098757335611">Angalia kadi</translation>
@@ -816,7 +847,6 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="3587738293690942763">Katikati</translation>
<translation id="3592413004129370115">Italian (Bahasha)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{Unaweza kubadilisha kikundi chako wakati wowote. Inachukua takriban siku moja kujiunga na kikundi kipya.}=1{Unaweza kubadilisha kikundi chako wakati wowote. Inachukua takriban siku moja kujiunga na kikundi kipya.}other{Unaweza kubadilisha kikundi chako wakati wowote. Inachukua siku {NUM_DAYS} kujiunga na kikundi kipya.}}</translation>
-<translation id="3596012367874587041">Mipangilio ya programu</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">Programu imezuiwa na msimamizi wako</translation>
<translation id="3608932978122581043">Weka mkao</translation>
@@ -859,6 +889,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="370972442370243704">Washa kipengele cha Ziara</translation>
<translation id="3711895659073496551">Sitisha</translation>
<translation id="3712624925041724820">Leseni zimekwisha</translation>
+<translation id="3714633008798122362">kalenda ya wavuti</translation>
<translation id="3714780639079136834">Kuwasha data ya simu au Wi-Fi</translation>
<translation id="3715597595485130451">Unganisha kwenye Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Kuangalia seva mbadala, kingamtandao na mipangilio ya DNS<ph name="END_LINK" /></translation>
@@ -920,6 +951,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="3906954721959377182">Kompyuta kibao</translation>
<translation id="3909477809443608991"><ph name="URL" /> inataka kucheza maudhui yanayolindwa. Utambulisho wa kifaa chako utathibitishwa na Google na kinaweza kufikiwa na tovuti hii.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">Kataza</translation>
<translation id="3939773374150895049">Ungependa kutumia WebAuthn badala ya CVC?</translation>
<translation id="3946209740501886391">Uliza kwenye tovuti hii kila wakati</translation>
<translation id="3947595700203588284">Inaweza kuomba ruhusa ya kuunganisha kwenye vifaa vya MIDI</translation>
@@ -941,6 +973,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="3990250421422698716">Kunja kuwa katika muundo wa Z</translation>
<translation id="3996311196211510766">Tovuti ya <ph name="ORIGIN" /> inataka sera ya asili
itumike kwenye maombi yote inayopokea, lakini sera hii haiwezi kutumika kwa sasa.</translation>
+<translation id="4009243425692662128">Maudhui ya kurasa unazochapisha yanatumwa kwenda katika huduma za Google Cloud au kwa washirika wengine kwa ajili ya uchambuzi. Kwa mfano, yanaweza kuchanganuliwa ili kubaini data nyeti.</translation>
<translation id="4010758435855888356">Ungependa kuruhusu nafasi ya hifadhi ifikiwe?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{Hati ya PDF iliyo na ukurasa {COUNT}}other{Hati ya PDF iliyo na kurasa {COUNT}}}</translation>
<translation id="4023431997072828269">Kwa sababu fomu hii inatumwa kwa kutumia muunganisho ambao si salama, watu wengine wataona maelezo yako.</translation>
@@ -1035,6 +1068,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="4250680216510889253">La</translation>
<translation id="4253168017788158739">Dokezo</translation>
<translation id="425582637250725228">Huenda mabadiliko uliyofanya hayatahifadhiwa.</translation>
+<translation id="425869179292622354">Unataka kufanya iwe salama zaidi ukiwa na kadi pepe?</translation>
<translation id="4258748452823770588">Sahihi mbaya</translation>
<translation id="4261046003697461417">Huwezi kuweka vidokezo kwenye hati zinazolindwa</translation>
<translation id="4265872034478892965">Imeruhusiwa na msimamizi wako</translation>
@@ -1097,6 +1131,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="4434045419905280838">Madirisha ibukizi/kuelekeza kwingine</translation>
<translation id="4435702339979719576">Kad ya Posta)</translation>
<translation id="443673843213245140">Matumizi ya proksi yamelemazwa lakini usanidi wa proksi wazi umebainishwa.</translation>
+<translation id="4441832193888514600">Imepuuzwa kwa sababu sera inaweza kuwekwa tu kama sera ya mtumiaji wa wingu.</translation>
<translation id="4450893287417543264">Usionyeshe tena</translation>
<translation id="4451135742916150903">Inaweza kuomba ruhusa ya kuunganisha kwenye vifaa vya HID</translation>
<translation id="4452328064229197696">Nenosiri ulilotumia sasa hivi limepatikana kwenye tukio la ufichuzi haramu wa data. Ili uimarishe usalama wa akaunti zako, Kidhibiti cha Manenosiri cha Google kinapendekeza ukague manenosiri yako yaliyohifadhiwa.</translation>
@@ -1152,6 +1187,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="4628948037717959914">Picha</translation>
<translation id="4631649115723685955">Inajumuisha tuzo ya pesa</translation>
<translation id="4636930964841734540">Maelezo</translation>
+<translation id="4638670630777875591">Hali fiche kwenye Chromium</translation>
<translation id="464342062220857295">Vipengele vya utafutaji</translation>
<translation id="4644670975240021822">Mpangilio uliopinduliwa zikiangalia chini</translation>
<translation id="4646534391647090355">Nipeleke kwenye sehemu hiyo sasa</translation>
@@ -1172,6 +1208,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="4708268264240856090">Muunganisho wako umekatizwa</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Kuendesha Zana ya Windows ya Kuchunguza Mtandao<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426">Nenosiri la <ph name="USERNAME" /></translation>
<translation id="4724144314178270921">Inaweza kuomba ruhusa ya kuona maandishi na picha kwenye ubao wako wa kunakili</translation>
<translation id="4726672564094551039">Pakia sera upya</translation>
<translation id="4728558894243024398">Mfumo wa uendeshaji</translation>
@@ -1193,6 +1230,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="4757993714154412917">Umeweka nenosiri lako kwenye tovuti ya kupotosha. Ili uimarishe usalama wa akaunti zako, Chromium inapendekeza ukague manenosiri uliyoyahifadhi.</translation>
<translation id="4758311279753947758">Ongeza maelezo ya mawasiliano</translation>
<translation id="4761104368405085019">Tumia kipazasauti chako</translation>
+<translation id="4761869838909035636">Fanya Ukaguzi wa Usalama kwenye Chrome</translation>
<translation id="4764776831041365478">Ukurasa wa wavuti ulio <ph name="URL" /> unaweza kuwa haupatikani kwa muda au unaweza kuwa umehamishwa kabisa hadi anwani mpya ya wavuti.</translation>
<translation id="4766713847338118463">Bana mara mbili chini</translation>
<translation id="4771973620359291008">Hitilafu isiyojulikana imetokea.</translation>
@@ -1213,12 +1251,6 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="4819347708020428563">Ungependa kubadilisha vidokezo katika mwonekano chaguomsingi?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />, bonyeza 'Tab' kisha 'Enter' ili uunde Jedwali jipya la Google kwa haraka</translation>
<translation id="4825507807291741242">Powerful</translation>
-<translation id="4827402517081186284">Hali fiche haikufanyi usionekane mtandaoni:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Tovuti hujua unapozitembelea<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Waajiri au shule zinaweza kufuatilia shughuli za kuvinjari<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Huenda watoa huduma za intaneti wakafuatilia trafiki kwenye wavuti<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">Washa maonyo</translation>
<translation id="4838327282952368871">Dreamy</translation>
<translation id="4840250757394056958">Angalia historia yako kwenye Chrome</translation>
@@ -1230,12 +1262,12 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="4854362297993841467">Njia hii ya kusafirisha haitumiki. Jaribu njia tofauti.</translation>
<translation id="4854853140771946034">Unda dokezo jipya katika Google Keep kwa haraka</translation>
<translation id="485902285759009870">Inathibitisha nambari...</translation>
+<translation id="4866506163384898554">Bonyeza |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| ili kuonyesha kiteuzi chako</translation>
<translation id="4876188919622883022">Mwonekano rahisi</translation>
<translation id="4876305945144899064">Hakuna jina la mtumiaji</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{Hamna}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831">Tafuta <ph name="TEXT" /></translation>
<translation id="4879491255372875719">Kiotomatiki (chaguomsingi)</translation>
-<translation id="4879725228911483934">Fungua na uonyeshe madirisha kwenye skrini zako</translation>
<translation id="4880827082731008257">Tafuta katika historia</translation>
<translation id="4881695831933465202">Fungua</translation>
<translation id="4885256590493466218">Tumia <ph name="CARD_DETAIL" /> wakati wa kulipa</translation>
@@ -1244,6 +1276,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">Gombo la Tisa</translation>
<translation id="4901778704868714008">Hifadhi...</translation>
+<translation id="4905659621780993806">Msimamizi wako atazima kisha kuwasha kifaa chako kiotomatiki saa <ph name="TIME" /> tarehe <ph name="DATE" />. Hifadhi vipengee vyovyote vilivyofunguliwa kabla ya kifaa chako kuzimika kisha kiwake.</translation>
<translation id="4913987521957242411">Toboa juu kushoto</translation>
<translation id="4918221908152712722">Sakinisha <ph name="APP_NAME" /> (huhitaji kupakua)</translation>
<translation id="4923459931733593730">Malipo</translation>
@@ -1252,6 +1285,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, bonyeza 'Tab' kisha 'Enter' ili utafute</translation>
<translation id="4930153903256238152">Uwezo mkubwa</translation>
+<translation id="4940163644868678279">Hali fiche kwenye Chrome</translation>
<translation id="4943872375798546930">Hakuna matokeo yoyote yaliyopatikana</translation>
<translation id="4950898438188848926">Kitufe cha kubadilisha kichupo, bonyeza Enter ili uende kwenye kichupo cha kufungua, <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="495170559598752135">Vitendo</translation>
@@ -1261,6 +1295,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="4968522289500246572">Programu hii imeundwa kwa ajili ya vifaa vya mkononi na huenda ukubwa wake usibadilike vizuri. Huenda programu ikakumbwa na matatizo au izimwe kisha iwashwe tena.</translation>
<translation id="4969341057194253438">Futa rekodi</translation>
<translation id="4973922308112707173">Toboa juu mara mbili</translation>
+<translation id="4976702386844183910">Ilitembelewa mara ya mwisho <ph name="DATE" /></translation>
<translation id="4984088539114770594">Ungependa kutumia maikrofoni?</translation>
<translation id="4984339528288761049">Prc5 (Bahasha)</translation>
<translation id="4989163558385430922">Angalia vyote</translation>
@@ -1322,6 +1357,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="5138227688689900538">Onyesha chache</translation>
<translation id="5145883236150621069">Msimbo wa hitilafu uko katika jibu la sera</translation>
<translation id="5146995429444047494">Arifa za <ph name="ORIGIN" /> zimezuiwa</translation>
+<translation id="514704532284964975"><ph name="URL" /> ingependa kuona na kubadilisha maelezo kwenye vifaa vya NFC unavyogusa kwa kutumia simu yako</translation>
<translation id="5148809049217731050">Kuangalia juu</translation>
<translation id="515292512908731282">C4 (Bahasha)</translation>
<translation id="5158275234811857234">Jalada</translation>
@@ -1346,6 +1382,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="5215116848420601511">Njia za kulipa na anwani zinazotumia Google Pay</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">Trei ya 13</translation>
+<translation id="5216942107514965959">Ilitembelewa mara ya mwisho leo</translation>
<translation id="5222812217790122047">Anwani ya barua pepe inahitajika</translation>
<translation id="5230733896359313003">Anwani ya Mahali Bidhaa Zitakapopelekwa</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1366,7 +1403,6 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">Sifa za hati</translation>
<translation id="528468243742722775">Mwisho</translation>
-<translation id="5284909709419567258">Anwani za mtandao</translation>
<translation id="5285570108065881030">Onyesha manenosiri yote yaliyohifadhiwa</translation>
<translation id="5287240709317226393">Onyesha vidakuzi</translation>
<translation id="5287456746628258573">Tovuti hii inatumia mipangilio ya usalama iliyopitwa na wakati, hali ambayo inaweza kuonyesha taarifa zako (kwa mfano, manenosiri au nambari za kadi za mikopo) zikitumwa kwenye tovuti hii.</translation>
@@ -1450,6 +1486,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="5556459405103347317">Pakia upya</translation>
<translation id="5560088892362098740">Tarehe ya Mwisho wa Matumizi</translation>
<translation id="55635442646131152">Muhtasari wa hati</translation>
+<translation id="5565613213060953222">Fungua kichupo fiche</translation>
<translation id="5565735124758917034">Inatumika</translation>
<translation id="5570825185877910964">Linda akaunti</translation>
<translation id="5571083550517324815">Haiwezi kuchukua kutoka kwenye anwani hii. Chagua anwani tofauti.</translation>
@@ -1532,6 +1569,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="5869522115854928033">Manenosiri yaliyohifadhiwa</translation>
<translation id="5873013647450402046">Benki yako ingependa kuthibitisha kwamba ni wewe.</translation>
<translation id="5887400589839399685">Kadi imehifadhiwa</translation>
+<translation id="5887687176710214216">Ilitembelewa mara ya mwisho jana</translation>
<translation id="5895138241574237353">Zzima na uwashe</translation>
<translation id="5895187275912066135">Kilitolewa</translation>
<translation id="5901630391730855834">Manjano</translation>
@@ -1545,6 +1583,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="5921639886840618607">Ungependa kuhifadhi kadi kwenye Akaunti ya Google?</translation>
<translation id="5922853866070715753">Unakaribia kumaliza</translation>
<translation id="5932224571077948991">Tovuti inaonyesha matangazo yanayopotosha au yanayokatiza huduma</translation>
+<translation id="5938153366081463283">Weka kadi pepe</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347">Inafungua <ph name="SITE_NAME" />…</translation>
<translation id="5951495562196540101">Huwezi kujiandikisha ukitumia akaunti ya mteja (ina leseni ya kifurushi).</translation>
@@ -1609,6 +1648,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="6120179357481664955">Ungependa kukumbuka kitambulisho chako cha UPI?</translation>
<translation id="6124432979022149706">Viunganishi vya Chrome Enterprise</translation>
<translation id="6127379762771434464">Kipengee kimeondolewa</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Pata maelezo zaidi kuhusu Hali fiche kwenye Chrome<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">Angalia kebo zozote na uwashe tena kisambaza data, modemu, au vifaa vingine vyovyote vya
mtandao ambavyo huenda unavitumia.</translation>
<translation id="614940544461990577">Jaribu:</translation>
@@ -1621,7 +1661,6 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="6169916984152623906">Sasa unaweza kuvinjari kwa faragha na watu wengine wanaotumia kifaa hiki hawataona shughuli zako. Hata hivyo, vipakuliwa na alamisho zitahifadhiwa.</translation>
<translation id="6177128806592000436">Muunganisho wako kwenye tovuti hii si salama</translation>
<translation id="6180316780098470077">Kipindi cha mara unazojaribu</translation>
-<translation id="619448280891863779">Inaweza kuomba ruhusa ya kufungua na kuweka madirisha kwenye skrini zako</translation>
<translation id="6196640612572343990">Zuia vidakuzi vya tovuti nyingine</translation>
<translation id="6203231073485539293">Angalia muunganisho wako wa Intaneti</translation>
<translation id="6218753634732582820">Je, ungependa kuondoa anwani kwenye Chromium?</translation>
@@ -1644,7 +1683,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="6272383483618007430">Sasisho kwa Google</translation>
<translation id="6276112860590028508">Kurasa kutoka orodha yako ya usomaji huonekana hapa</translation>
<translation id="627746635834430766">Ili ulipe kwa haraka wakati ujao, hifadhi anwani ya kutuma bili na maelezo ya kadi yako kwenye Akaunti yako ya Google.</translation>
-<translation id="6279098320682980337">Je, nambari ya kadi pepe haijajazwa? Bofya maelezo ya kadi ili unakili</translation>
+<translation id="6279183038361895380">Bonyeza |<ph name="ACCELERATOR" />| ili kiteuzi kionekane</translation>
<translation id="6280223929691119688">Haiwezi kuwasilisha kwenye anwani hii. Chagua anwani tofauti.</translation>
<translation id="6282194474023008486">Msimbo wa eneo</translation>
<translation id="6285507000506177184">Kitufe cha 'Dhibiti vipakuliwa kwenye Chrome', bonyeza 'Enter' ili udhibiti faili ulizozipakua katika Chrome</translation>
@@ -1652,6 +1691,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="6290238015253830360">Makala unayopendekezewa yataonekana hapa</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{Vifaa vyako vitazimika kisha viwake sasa}=1{Kifaa chako kitazimika kisha kiwake baada ya sekunde moja}other{Vifaa vyako vitazimika kisha viwake baada ya sekunde #}}</translation>
<translation id="6302269476990306341">Programu ya Mratibu wa Google katika Chrome inaacha kufanya kazi</translation>
<translation id="6305205051461490394"><ph name="URL" /> haiwezi kufikiwa.</translation>
<translation id="6312113039770857350">Ukurasa wa wavuti haupatikani</translation>
@@ -1725,6 +1765,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="6529602333819889595">Rudia Kufuta</translation>
<translation id="6545864417968258051">Kutafuta Bluetooth</translation>
<translation id="6547208576736763147">Toboa mara mbili kushoto</translation>
+<translation id="6554732001434021288">Ilitembelewa mara ya mwisho siku <ph name="NUM_DAYS" /> zilizopita</translation>
<translation id="6556866813142980365">Rudia</translation>
<translation id="6569060085658103619">Unaangalia ukurasa wa kiendelezi</translation>
<translation id="6573200754375280815">Toboa mara mbili kulia</translation>
@@ -1785,7 +1826,6 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="6757797048963528358">Kifaa chako kiko katika hali tuli.</translation>
<translation id="6767985426384634228">Ungependa Kusasisha Anwani?</translation>
<translation id="6768213884286397650">Hagaki (Kadi ya Posta)</translation>
-<translation id="6774185088257932239"><ph name="BEGIN_LINK" />Pata maelezo zaidi<ph name="END_LINK" /> kuhusu hali fiche</translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">Zambarau iliyokolea</translation>
<translation id="6786747875388722282">Viendelezi</translation>
@@ -1869,7 +1909,6 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="706295145388601875">Weka na udhibiti anwani katika mipangilio ya Chrome</translation>
<translation id="7064851114919012435">Maelezo ya mawasiliano</translation>
<translation id="7068733155164172741">Weka nambari ya kuthibitisha yenye tarakimu <ph name="OTP_LENGTH" /></translation>
-<translation id="7070090581017165256">Kuhusu tovuti hii</translation>
<translation id="70705239631109039">Muunganisho wako si salama kabisa</translation>
<translation id="7075452647191940183">Ombi ni kubwa mno</translation>
<translation id="7079718277001814089">Tovuti hii ina programu hasidi</translation>
@@ -1886,6 +1925,12 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="7111012039238467737">(Sahihi)</translation>
<translation id="7118618213916969306">Tafuta URL ya ubao wa kunakili, <ph name="SHORT_URL" /></translation>
<translation id="7119414471315195487">Funga vichupo au programu nyingine</translation>
+<translation id="7129355289156517987">Unapofunga vichupo vyote fiche kwenye Chromium, shughuli zako kwenye vichupo hivyo zitafutwa katika kifaa hiki:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Shughuli za kuvinjari<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Historia ya mambo uliyotafuta<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Maelezo unayojaza katika fomu<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">Haiwezi kusafirisha kwenda kwenye anwani hii. Chagua anwani tofauti.</translation>
<translation id="7132939140423847331">Msimamizi wako amezuia data hii isinakiliwe.</translation>
<translation id="7135130955892390533">Onyesha hali</translation>
@@ -1908,6 +1953,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="7192203810768312527">Huongeza nafasi ya <ph name="SIZE" />. Huenda baadhi ya tovuti zikapakia polepole katika tembeleo lako lijalo.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">Msimamizi wako anaweza kuona:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, bonyeza 'Tab' kisha 'Enter' ufungue kichupo fiche kipya ili uvinjari kwa faragha</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> haizingatii viwango vya usalama.</translation>
<translation id="7210993021468939304">Shughuli ya Linux ndani ya metadata inaweza kusakinisha na kutekeleza programu za Linux ndani ya metadata</translation>
@@ -1937,6 +1983,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="7304562222803846232">Dhibiti mipangilio ya faragha ya Akaunti ya Google</translation>
<translation id="7305756307268530424">Anza polepole</translation>
<translation id="7308436126008021607">usawazishaji wa chinichini</translation>
+<translation id="7310392214323165548">Kifaa kitazimika kisha kiwake hivi punde</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">Usaidizi kuhusu Muunganisho</translation>
<translation id="7323804146520582233">Ficha sehemu ya "<ph name="SECTION" />"</translation>
@@ -1944,6 +1991,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="7334320624316649418">Rudia Kupanga Upya</translation>
<translation id="7335157162773372339">Inaweza kuomba ruhusa ya kutumia kamera yako</translation>
<translation id="7337248890521463931">Onyesha mistari zaidi</translation>
+<translation id="7337418456231055214">Je, nambari ya kadi pepe haijajazwa? Bofya maelezo ya kadi ili unakili. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">Haipatikani kwenye mfumo wako.</translation>
<translation id="733923710415886693">Cheti cha seva hakikufichuliwa kupitia Uwazi wa Cheti.</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1966,6 +2014,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="7378627244592794276">La</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">Haitumiki</translation>
+<translation id="7388594495505979117">{0,plural, =1{Kifaa chako kitazimika na kuwaka tena baada ya dakika moja}other{Vifaa vyako vitazimika na kuwaka tena baada ya dakika #}}</translation>
<translation id="7390545607259442187">Thibitisha Kadi</translation>
<translation id="7392089738299859607">Sasisha Anwani</translation>
<translation id="7399802613464275309">Angalizo la Usalama</translation>
@@ -2002,6 +2051,12 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="7485870689360869515">Hakuna data iliyopatikana.</translation>
<translation id="7495528107193238112">Maudhui haya yamezuiwa. Wasiliana na mmiliki wa tovuti ili asuluhishe tatizo.</translation>
<translation id="7497998058912824456">Kitufe cha kuunda hati, bonyeza 'Enter' ili uunde Hati mpya ya Google kwa haraka</translation>
+<translation id="7506488012654002225">Chromium <ph name="BEGIN_EMPHASIS" />haitahifadhi<ph name="END_EMPHASIS" /> maelezo yafuatayo:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Historia yako ya kuvinjari
+ <ph name="LIST_ITEM" />Vidakuzi na data ya tovuti
+ <ph name="LIST_ITEM" />Maelezo unayojaza katika fomu
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">Kitambulisho cha sera ya kifaa kilichorejeshwa hakina kitu au hakilingani na kitambulisho cha kifaa kilichopo</translation>
<translation id="7508870219247277067">Kijani cha Parachichi</translation>
<translation id="7511955381719512146">Wi-Fi unayotumia inaweza kukuhitaji kutembelea <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
@@ -2115,7 +2170,6 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="7813600968533626083">Ungependa kuondoa pendekezo la fomu kutoka kwenye Chrome?</translation>
<translation id="781440967107097262">Ungependa kushiriki ubao wa kunakili?</translation>
<translation id="7815407501681723534">Imepata matokeo <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> ya '<ph name="SEARCH_STRING" />'</translation>
-<translation id="782125616001965242">Onyesha maelezo kuhusu tovuti hii</translation>
<translation id="782886543891417279">Wi-Fi unayotumia (<ph name="WIFI_NAME" />) inaweza kukuhitaji kutembelea ukurasa wake wa kuingia katika akaunti.</translation>
<translation id="7836231406687464395">Postfix (Bahasha)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{Hamna}=1{Programu 1 (<ph name="EXAMPLE_APP_1" />)}=2{Programu 2 (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}other{Programu # (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}}</translation>
@@ -2132,7 +2186,6 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="7888575728750733395">Utaratibu wa kuratibu utekelezaji wa uchapishaji</translation>
<translation id="7894280532028510793">Iwapo hakuna kosa la hijai, <ph name="BEGIN_LINK" />jaribu kutekeleza Uchunguzi wa Mtandao<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (Bahasha)</translation>
-<translation id="7931318309563332511">Haijulikani</translation>
<translation id="793209273132572360">Ungependa kusasisha anwani?</translation>
<translation id="7932579305932748336">Koleza</translation>
<translation id="79338296614623784">Andika nambari sahihi ya simu</translation>
@@ -2157,13 +2210,14 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="7976214039405368314">Maombi mengi mno</translation>
<translation id="7977538094055660992">Kifaa cha kutoa maudhui</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">Imeunganishwa na</translation>
<translation id="798134797138789862">Inaweza kuomba ruhusa ya kutumia data na vifaa vya uhalisia pepe</translation>
<translation id="7984945080620862648">Huwezi kutembelea <ph name="SITE" /> sasa hivi kwa sababu tovuti ilituma kitambulisho kilichoharibika ambacho Chrome haiwezi kuchakata. Hitilafu na uvamizi wa mtandao kwa kawaida huwa vya muda, kwa hivyo ukurasa huu huenda utafanya kazi baadaye.</translation>
-<translation id="79859296434321399">Sakinisha ARCore ili uangalie maudhui ya uhalisia ulioboreshwa</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">Unganisha</translation>
<translation id="7992044431894087211">Uwezo wa kushiriki skrini na <ph name="APPLICATION_TITLE" /> umerejeshwa</translation>
<translation id="7995512525968007366">Hakijabainishwa</translation>
+<translation id="7998269595945679889">Fungua kitufe cha kichupo fiche, bonyeza 'Enter' ufungue kichupo Fiche kipya ili uvinjari kwa faragha</translation>
<translation id="800218591365569300">Jaribu kufunga vichupo au programu nyingine upate nafasi zaidi.</translation>
<translation id="8004582292198964060">Kivinjari</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{Tutahifadhi maelezo ya kadi hii pamoja na anwani yake ya kutuma bili. Utaweza kuitumia utakapoingia katika akaunti ya <ph name="USER_EMAIL" />.}other{Tutahifadhi maelezo ya kadi hizi pamoja na anwani za kutuma bili. Utaweza kuzitumia utakapoingia katika akaunti ya <ph name="USER_EMAIL" />.}}</translation>
@@ -2223,6 +2277,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="8202370299023114387">Mgogoro</translation>
<translation id="8206978196348664717">Prc4 (Bahasha)</translation>
<translation id="8211406090763984747">Muunganisho ni salama</translation>
+<translation id="8217240300496046857">Tovuti haziwezi kutumia vidakuzi vinavyofuatilia shughuli zako kwenye wavuti Huenda vipengele kwenye baadhi ya tovuti vikakosa kufanya kazi.</translation>
<translation id="8218327578424803826">Mahali Palipohawilishwa:</translation>
<translation id="8220146938470311105">C7/C6 (Bahasha)</translation>
<translation id="8225771182978767009">Mtu ambaye aliweka mipangilio ya kompyuta hii ameamua kuzuia tovuti hii.</translation>
@@ -2263,14 +2318,9 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="830498451218851433">Kunja nusu</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">Programu zilizosakinishwa na mara ambazo zinatumika</translation>
+<translation id="8317207217658302555">Ungependa kusasisha ARCore?</translation>
<translation id="831997045666694187">Jioni</translation>
<translation id="8321476692217554900">arifa</translation>
-<translation id="8328484624016508118">Baada ya kufunga vichupo vyote fiche, Chrome hufuta:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Shughuli zako za kuvinjari kwenye kifaa hiki<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Historia ya mambo uliyoyatafuta kwenye kifaa hiki<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Maelezo yaliyowekwa kwenye fomu<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489">Ufikiaji wa <ph name="HOST_NAME" /> umekataliwa</translation>
<translation id="833262891116910667">Angazia</translation>
<translation id="8339163506404995330">Kurasa za <ph name="LANGUAGE" /> hazitatafsiriwa</translation>
@@ -2320,6 +2370,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="8507227106804027148">Mbinu ya amri</translation>
<translation id="8508648098325802031">Aikoni ya Utafutaji</translation>
<translation id="8511402995811232419">Dhibiti vidakuzi</translation>
+<translation id="8519753333133776369">Kifaa cha HID kinachoruhusiwa na msimamizi wako</translation>
<translation id="8522552481199248698">Chrome inaweza kukusaidia kulinda Akaunti yako ya Google na kubadilisha nenosiri lako.</translation>
<translation id="8530813470445476232">Futa historia yako ya kuvinjari, vidakuzi, akiba na zaidi katika mipangilio ya Chrome</translation>
<translation id="8533619373899488139">Tembelea &lt;strong&gt;chrome://policy&lt;/strong&gt; ili uone orodha ya URL zilizozuiwa na sera zingine zinazotekelezwa na msimamizi wako wa mfumo.</translation>
@@ -2331,7 +2382,6 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{Badilisha ruhusa}other{Badilisha ruhusa}}</translation>
<translation id="8555010941760982128">Tumia kuponi hii wakati wa kulipa</translation>
<translation id="8557066899867184262">CVC inapatikana nyuma ya kadi yako.</translation>
-<translation id="8558485628462305855">Sasisha ARCore ili uangalie maudhui ya uhalisia ulioboreshwa</translation>
<translation id="8559762987265718583">Muunganisho wa faragha kwenye <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> hauwezi kupatikana kwa sababu tarehe na wakati wa kifaa chako (<ph name="DATE_AND_TIME" />) si sahihi.</translation>
<translation id="8564182942834072828">Hati zilizotenganishwa/Nakala ambazo hazijapangwa</translation>
<translation id="8564985650692024650">Chromium inapendekeza ubadilishe nenosiri lako la <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> ikiwa ulilitumia tena kwenye tovuti zingine.</translation>
@@ -2351,6 +2401,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="865032292777205197">vitambuzi vya mwendo</translation>
<translation id="8663226718884576429">Muhtasari wa Agizo, <ph name="TOTAL_LABEL" />, Maelezo Zaidi</translation>
<translation id="8666678546361132282">Kiingereza</translation>
+<translation id="8669306706049782872">Kutumia maelezo kuhusu skrini zako kwa ajili ya kufungua na kuweka madirisha</translation>
<translation id="867224526087042813">Sahihi</translation>
<translation id="8676424191133491403">Hakuna kuchelewa</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, jibu, <ph name="ANSWER" /></translation>
@@ -2377,6 +2428,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="8731544501227493793">Kitufe cha 'Dhibiti manenosiri', bonyeza 'Enter' ili uangalie na udhibiti manenosiri yako katika mipangilio ya Chrome</translation>
<translation id="8734529307927223492"><ph name="DEVICE_TYPE" /> yako inadhibitiwa na <ph name="MANAGER" /></translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, bonyeza 'Tab' kisha 'Enter' ufungue dirisha jipya fiche ili uvinjari kwa faragha</translation>
+<translation id="8737685506611670901">Kufungua viungo vya <ph name="PROTOCOL" /> badala ya <ph name="REPLACED_HANDLER_TITLE" /></translation>
<translation id="8738058698779197622">Ili kutambua muunganisho salama, saa yako inahitaji kuwekwa sahihi. Hii ni kwa sababu vyeti ambavyo tovuti hutumia kujitambua ni sahihi kwa vipindi mahususi pekee. Kwa kuwa saa ya kifaa chako si sahihi, Chromium haiwezi kuthibitisha vyeti hivi.</translation>
<translation id="8740359287975076522"><ph name="HOST_NAME" /> &lt;abbr id="dnsDefinition"&gt;anwani ya DNS&lt;/abbr&gt; haikupatikana. Tatizo linachunguzwa.</translation>
<translation id="8742371904523228557"><ph name="ONE_TIME_CODE" /> ni nambari yako ya <ph name="ORIGIN" /></translation>
@@ -2404,6 +2456,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="883848425547221593">Alamisho Zingine</translation>
<translation id="884264119367021077">Anwani ya kusafirisha</translation>
<translation id="884923133447025588">Mbinu ya ubatilishaji haikupatikana.</translation>
+<translation id="8849262850971482943">Tumia kadi yako pepe kwa usalama wa ziada</translation>
<translation id="885730110891505394">Kushiriki kwenye Google</translation>
<translation id="8858065207712248076">Chrome inapendekeza ubadilishe nenosiri lako la <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> ikiwa ulilitumia tena kwenye tovuti zingine.</translation>
<translation id="885906927438988819">Iwapo hakuna kosa la hijai, <ph name="BEGIN_LINK" />jaribu kutekeleza Uchunguzi wa Mtandao<ph name="END_LINK" />.</translation>
@@ -2453,6 +2506,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="9004367719664099443">Kipindi cha VR kinaendelea</translation>
<translation id="9005998258318286617">Imeshindwa kupakia hati ya PDF.</translation>
<translation id="9008201768610948239">Puuza</translation>
+<translation id="901834265349196618">Barua pepe</translation>
<translation id="9020200922353704812">Anwani ya kutuma bili ya kadi sharti iandikwe</translation>
<translation id="9020542370529661692">Ukurasa huu umetafsiriwa kwenda <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9020742383383852663">A8</translation>
@@ -2501,6 +2555,7 @@ Usipoiruhusu, itazuiwa na mipangilio yako ya faragha. Hali hii itaruhusu maudhui
<translation id="9150045010208374699">Tumia kamera yako</translation>
<translation id="9150685862434908345">Msimamizi wako anaweza kubadilisha mipangilio ya kivinjari chako kwa mbali. Huenda shughuli kwenye kifaa hiki zikadhibitiwa nje ya Chrome. <ph name="BEGIN_LINK" />Pata maelezo zaidi<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">Imesasishwa</translation>
+<translation id="9155211586651734179">Vifaa vya sauti vimeambatishwa</translation>
<translation id="9157595877708044936">Inasanidi...</translation>
<translation id="9158625974267017556">C6 (Bahasha)</translation>
<translation id="9164029392738894042">Ukaguzi wa Usahihi</translation>
diff --git a/chromium/components/strings/components_strings_ta.xtb b/chromium/components/strings/components_strings_ta.xtb
index 2d105986d9b..a148e07e94c 100644
--- a/chromium/components/strings/components_strings_ta.xtb
+++ b/chromium/components/strings/components_strings_ta.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">விவரஙà¯à®•à®³à¯ˆà®•à¯ காடà¯à®Ÿà¯</translation>
<translation id="1030706264415084469">உஙà¯à®•à®³à¯ சாதனதà¯à®¤à®¿à®²à¯, அதிக அளவ௠தரவை நிரநà¯à®¤à®°à®®à®¾à®•à®šà¯ சேமிகà¯à®• <ph name="URL" /> விரà¯à®®à¯à®ªà¯à®•à®¿à®±à®¤à¯</translation>
<translation id="1032854598605920125">கடிகாரதà¯à®¤à®¿à®šà¯ˆà®¯à®¿à®²à¯ சà¯à®´à®±à¯à®±à¯</translation>
+<translation id="1033329911862281889">மறைநிலையில௠உலாவà¯à®®à¯à®ªà¯‹à®¤à¯ ஆனà¯à®²à¯ˆà®©à®¿à®²à¯ உஙà¯à®•à®³à¯ அடையாளம௠மறைகà¯à®•à®ªà¯à®ªà®Ÿà®¾à®¤à¯:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />தளஙà¯à®•à®³à®¾à®²à¯à®®à¯ அவை பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à¯à®®à¯ சேவைகளாலà¯à®®à¯ உஙà¯à®•à®³à¯ வரà¯à®•à¯ˆà®•à®³à¯ˆà®¤à¯ தெரிநà¯à®¤à¯à®•à¯Šà®³à¯à®³ à®®à¯à®Ÿà®¿à®¯à¯à®®à¯<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />நிறà¯à®µà®©à®™à¯à®•à®³à®¾à®²à¯à®®à¯ பளà¯à®³à®¿à®•à®³à®¾à®²à¯à®®à¯ உஙà¯à®•à®³à¯ உலாவல௠செயலà¯à®ªà®¾à®Ÿà¯à®Ÿà¯ˆà®•à¯ கணà¯à®•à®¾à®£à®¿à®•à¯à®• à®®à¯à®Ÿà®¿à®¯à¯à®®à¯<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />இணையச௠சேவை வழஙà¯à®•à¯à®¨à®°à¯à®•à®³à®¾à®²à¯ இணைய டிராஃபிகà¯à®•à¯ˆà®•à¯ கணà¯à®•à®¾à®£à®¿à®•à¯à®• à®®à¯à®Ÿà®¿à®¯à¯à®®à¯<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">à®®à¯à®Ÿà®•à¯à®•à¯</translation>
<translation id="1036982837258183574">à®®à¯à®´à¯à®¤à¯à®¤à®¿à®°à¯ˆà®¯à®¿à®²à®¿à®°à¯à®¨à¯à®¤à¯ வெளியேற, |<ph name="ACCELERATOR" />|à® à®…à®´à¯à®¤à¯à®¤à®µà¯à®®à¯</translation>
<translation id="1038106730571050514">பரிநà¯à®¤à¯à®°à¯ˆà®•à®³à¯ˆà®•à¯ காடà¯à®Ÿà¯à®®à¯</translation>
<translation id="1038842779957582377">அறியபà¯à®ªà®Ÿà®¾à®¤ பெயரà¯</translation>
<translation id="1041998700806130099">பணித௠தாள௠மெசேஜà¯</translation>
<translation id="1048785276086539861">விரிவà¯à®°à¯ˆà®•à®³à¯ˆà®¤à¯ திரà¯à®¤à¯à®¤à®¿à®©à®¾à®²à¯ இநà¯à®¤ ஆவணம௠ஒறà¯à®±à¯ˆà®ªà¯ பகà¯à®•à®•à¯à®•à®¾à®Ÿà¯à®šà®¿à®•à¯à®•à¯ மாறà¯à®®à¯</translation>
-<translation id="1049743911850919806">மறைநிலை</translation>
<translation id="1050038467049342496">பிற ஆபà¯à®¸à¯ˆ மூடவà¯à®®à¯</translation>
<translation id="1055184225775184556">&amp;சேரà¯à®¤à¯à®¤à®²à¯ˆà®šà¯ செயலà¯à®¤à®µà®¿à®°à¯</translation>
<translation id="1056898198331236512">எசà¯à®šà®°à®¿à®•à¯à®•à¯ˆ</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">கொளà¯à®•à¯ˆ தறà¯à®•à®¾à®²à®¿à®• சேமிபà¯à®ªà¯ சரியாக உளà¯à®³à®¤à¯</translation>
<translation id="1130564665089811311">’பகà¯à®•à®¤à¯à®¤à¯ˆ மொழிபெயரà¯â€™ படà¯à®Ÿà®©à¯, Google Translate மூலம௠இநà¯à®¤à®ªà¯ பகà¯à®•à®¤à¯à®¤à¯ˆ மொழிபெயரà¯à®•à¯à®• Enter விசையை à®…à®´à¯à®¤à¯à®¤à¯à®™à¯à®•à®³à¯</translation>
<translation id="1131264053432022307">நீஙà¯à®•à®³à¯ நகலெடà¯à®¤à¯à®¤ படமà¯</translation>
+<translation id="1142846828089312304">மறைநிலையில௠மூனà¯à®±à®¾à®®à¯ தரபà¯à®ªà¯à®•à¯ கà¯à®•à¯à®•à¯€à®•à®³à¯ˆà®¤à¯ தடà¯</translation>
<translation id="1150979032973867961">இத௠<ph name="DOMAIN" /> தான௠எனà¯à®ªà®¤à¯ˆ இநà¯à®¤à®šà¯ சேவையகம௠உறà¯à®¤à®¿à®ªà¯à®ªà®Ÿà¯à®¤à¯à®¤à®µà®¿à®²à¯à®²à¯ˆ; இதன௠பாதà¯à®•à®¾à®ªà¯à®ªà¯à®šà¯ சானà¯à®±à®¿à®¤à®´à¯ˆ உஙà¯à®•à®³à¯ கமà¯à®ªà¯à®¯à¯‚டà¯à®Ÿà®°à®¿à®©à¯ ஆபà¯à®°à¯‡à®Ÿà¯à®Ÿà®¿à®™à¯ சிஸà¯à®Ÿà®®à¯ நமà¯à®ªà®µà®¿à®²à¯à®²à¯ˆ. இத௠தவறான உளà¯à®³à®®à¯ˆà®µà®¾à®²à¯ à®à®±à¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯ அலà¯à®²à®¤à¯ தீஙà¯à®•à®¿à®´à¯ˆà®ªà¯à®ªà®µà®°à¯ உஙà¯à®•à®³à¯ இணைபà¯à®ªà®¿à®²à¯ கà¯à®±à¯à®•à¯à®•à®¿à®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯.</translation>
<translation id="1151972924205500581">கடவà¯à®šà¯à®šà¯Šà®²à¯ தேவை</translation>
<translation id="1156303062776767266">அக ஃபைல௠அலà¯à®²à®¤à¯ பகிரபà¯à®ªà®Ÿà¯à®Ÿ ஃபைலைப௠பாரà¯à®•à¯à®•à®¿à®±à¯€à®°à¯à®•à®³à¯</translation>
@@ -64,7 +70,6 @@
<translation id="1178581264944972037">இடைநிறà¯à®¤à¯à®¤à¯</translation>
<translation id="1181037720776840403">அகறà¯à®±à¯</translation>
<translation id="1186201132766001848">கடவà¯à®šà¯à®šà¯Šà®±à¯à®•à®³à¯ˆà®šà¯ சோதிதà¯à®¤à¯à®ªà¯ பாரà¯à®•à¯à®•à®µà¯à®®à¯</translation>
-<translation id="1195210374336998651">ஆபà¯à®¸à¯ அமைபà¯à®ªà¯à®•à®³à¯à®•à¯à®•à¯à®šà¯ செலà¯à®²à¯à®®à¯</translation>
<translation id="1195558154361252544">நீஙà¯à®•à®³à¯ அனà¯à®®à®¤à®¿à®•à¯à®•à¯à®®à¯ தளஙà¯à®•à®³à¯ˆà®¤à¯ தவிர பிற அனைதà¯à®¤à¯à®¤à¯ தளஙà¯à®•à®³à¯à®•à¯à®•à¯à®®à¯ அறிவிபà¯à®ªà¯à®•à®³à¯ தானாகவே à®®à¯à®Ÿà®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®®à¯</translation>
<translation id="1197088940767939838">ஆரஞà¯à®šà¯</translation>
<translation id="1201402288615127009">அடà¯à®¤à¯à®¤à¯</translation>
@@ -111,7 +116,7 @@
<translation id="1307966114820526988">நிறà¯à®¤à¯à®¤à®ªà¯à®ªà®Ÿà¯à®Ÿ à®…à®®à¯à®šà®™à¯à®•à®³à¯</translation>
<translation id="1308113895091915999">ஆஃபர௠உளà¯à®³à®¤à¯</translation>
<translation id="1312803275555673949">இதறà¯à®•à®¾à®© ஆதாரம௠எனà¯à®©?</translation>
-<translation id="131405271941274527">NFC சாதனதà¯à®¤à®¿à®²à¯ உஙà¯à®•à®³à¯ மொபைலைத௠தடà¯à®Ÿà¯à®®à¯à®ªà¯‹à®¤à¯ தகவலை அனà¯à®ªà¯à®ªà¯à®µà®¤à®±à¯à®•à¯à®®à¯ பெறà¯à®µà®¤à®±à¯à®•à¯à®®à®¾à®© அனà¯à®®à®¤à®¿ <ph name="URL" />கà¯à®•à¯à®¤à¯ தேவை</translation>
+<translation id="1314311879718644478">ஆகà¯à®®à¯†à®©à¯à®Ÿà¯à®Ÿà®Ÿà¯ ரியாலிடà¯à®Ÿà®¿ உளà¯à®³à®Ÿà®•à¯à®•à®¤à¯à®¤à¯ˆà®ªà¯ பாரà¯à®™à¯à®•à®³à¯</translation>
<translation id="1314509827145471431">பைணà¯à®Ÿà¯ ரைடà¯</translation>
<translation id="1318023360584041678">பகà¯à®•à®•à¯ கà¯à®´à¯à®µà®¿à®²à¯ சேமிகà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯</translation>
<translation id="1319245136674974084">இநà¯à®¤ ஆபà¯à®¸à®¿à®²à¯ மீணà¯à®Ÿà¯à®®à¯ கேடà¯à®•à®¾à®¤à¯‡</translation>
@@ -161,12 +166,13 @@
<translation id="142858679511221695">கிளவà¯à®Ÿà¯ பயனரà¯</translation>
<translation id="1428729058023778569">இநà¯à®¤à®¤à¯ தளம௠HTTPSஸை ஆதரிகà¯à®•à®¾à®¤à®¤à®¾à®²à¯ எசà¯à®šà®°à®¿à®•à¯à®•à¯ˆ காடà¯à®Ÿà®ªà¯à®ªà®Ÿà¯à®•à®¿à®±à®¤à¯. <ph name="BEGIN_LEARN_MORE_LINK" />மேலà¯à®®à¯ அறிக<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">அசà¯à®šà®¿à®Ÿà¯à®•</translation>
+<translation id="1432187715652018471">சேவை ஹேணà¯à®Ÿà¯à®²à®°à¯ˆ இநà¯à®¤à®ªà¯ பகà¯à®•à®®à¯ நிறà¯à®µ விரà¯à®®à¯à®ªà¯à®•à®¿à®±à®¤à¯.</translation>
<translation id="1432581352905426595">தேடல௠இனà¯à®œà®¿à®©à¯à®•à®³à¯ˆ நிரà¯à®µà®•à®¿</translation>
<translation id="1436185428532214179">எனத௠சாதனதà¯à®¤à®¿à®²à¯ உளà¯à®³ ஃபைலà¯à®•à®³à®¿à®²à¯à®®à¯ ஃபோலà¯à®Ÿà®°à¯à®•à®³à®¿à®²à¯à®®à¯ மாறà¯à®±à®®à¯ செயà¯à®¯ à®®à¯à®¯à®²à¯à®®à¯à®ªà¯‹à®¤à¯ அனà¯à®®à®¤à®¿ கேடà¯à®• வேணà¯à®Ÿà¯à®®à¯</translation>
<translation id="1442386063175183758">ரைட௠கேட௠ஃபோலà¯à®Ÿà¯</translation>
<translation id="1442987760062738829">பஞà¯à®šà¯</translation>
<translation id="1447067628680007684">(x86_64)</translation>
-<translation id="1453974140256777690">நீஙà¯à®•à®³à¯ ஒடà¯à®Ÿà¯à®®à¯/இணைகà¯à®•à¯à®®à¯ உரை Google கிளவà¯à®Ÿà¯à®•à¯à®•à¯‹ மூனà¯à®±à®¾à®®à¯ தரபà¯à®ªà®¿à®©à®°à¯à®•à¯à®•à¯‹ ஆயà¯à®µà¯à®•à¯à®•à®¾à®• அனà¯à®ªà¯à®ªà®ªà¯à®ªà®Ÿà¯à®®à¯. எடà¯à®¤à¯à®¤à¯à®•à¯à®•à®¾à®Ÿà¯à®Ÿà®¾à®•, பாதà¯à®•à®¾à®•à¯à®• வேணà¯à®Ÿà®¿à®¯ தரவ௠உளà¯à®³à®¤à®¾ எனà¯à®±à¯ கணà¯à®Ÿà®±à®¿à®µà®¤à®±à¯à®•à®¾à®• அத௠ஸà¯à®•à¯‡à®©à¯ செயà¯à®¯à®ªà¯à®ªà®Ÿà®²à®¾à®®à¯.</translation>
+<translation id="1453974140256777690">நீஙà¯à®•à®³à¯ ஒடà¯à®Ÿà¯à®®à¯/இணைகà¯à®•à¯à®®à¯ உரை Google கிளவà¯à®Ÿà¯à®•à¯à®•à¯‹ மூனà¯à®±à®¾à®®à¯ தரபà¯à®ªà®¿à®©à®°à¯à®•à¯à®•à¯‹ ஆயà¯à®µà¯à®•à¯à®•à®¾à®• அனà¯à®ªà¯à®ªà®ªà¯à®ªà®Ÿà¯à®®à¯. எடà¯à®¤à¯à®¤à¯à®•à¯à®•à®¾à®Ÿà¯à®Ÿà®¾à®•, பாதà¯à®•à®¾à®•à¯à®•à®ªà¯à®ªà®Ÿ வேணà¯à®Ÿà®¿à®¯ தனிபà¯à®ªà®Ÿà¯à®Ÿ தரவ௠உளà¯à®³à®¤à®¾ எனà¯à®±à¯ கணà¯à®Ÿà®±à®¿à®µà®¤à®±à¯à®•à®¾à®• அத௠ஸà¯à®•à¯‡à®©à¯ செயà¯à®¯à®ªà¯à®ªà®Ÿà®²à®¾à®®à¯.</translation>
<translation id="1455413310270022028">எரேஸரà¯</translation>
<translation id="1462245070427461050">JIS B9</translation>
<translation id="1462951478840426066">தà¯à®²à¯à®²à®¿à®¯à®®à®¾à®© உளà¯à®³à®Ÿà®•à¯à®•à®¤à¯à®¤à¯ˆ உரà¯à®µà®¾à®•à¯à®•, உஙà¯à®•à®³à¯ கமà¯à®ªà¯à®¯à¯‚டà¯à®Ÿà®°à®¿à®²à¯ உளà¯à®³ எழà¯à®¤à¯à®¤à¯à®°à¯à®•à¯à®•à®³à¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®µà¯à®®à¯</translation>
@@ -181,6 +187,12 @@
<translation id="1483493594462132177">அனà¯à®ªà¯à®ªà¯</translation>
<translation id="1484290072879560759">ஷிபà¯à®ªà®¿à®™à¯ à®®à¯à®•à®µà®°à®¿à®¯à¯ˆà®¤à¯ தேரà¯à®µà¯ செயà¯</translation>
<translation id="1492194039220927094">கொளà¯à®•à¯ˆà®•à®³à¯ பà¯à®·à¯:</translation>
+<translation id="149293076951187737">Chrome மறைநிலைப௠பகà¯à®•à®™à¯à®•à®³à¯ அனைதà¯à®¤à¯ˆà®¯à¯à®®à¯ மூடà¯à®®à¯à®ªà¯‹à®¤à¯ அநà¯à®¤à®ªà¯ பகà¯à®•à®™à¯à®•à®³à®¿à®²à¯ நீஙà¯à®•à®³à¯ மேறà¯à®•à¯Šà®£à¯à®Ÿ செயலà¯à®ªà®¾à®Ÿà¯à®•à®³à¯ இநà¯à®¤à®šà¯ சாதனதà¯à®¤à®¿à®²à¯ இரà¯à®¨à¯à®¤à¯ அழிகà¯à®•à®ªà¯à®ªà®Ÿà¯à®®à¯:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />உலாவல௠செயலà¯à®ªà®¾à®Ÿà¯<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />இதà¯à®µà®°à¯ˆ தேடியவை<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />படிவஙà¯à®•à®³à®¿à®²à¯ டைப௠செயà¯à®¤ தகவலà¯à®•à®³à¯<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">தாவலà¯à®•à¯à®•à¯à®¤à¯ திரà¯à®®à¯à®ªà¯</translation>
<translation id="1501859676467574491">எனத௠Google கணகà¯à®•à®¿à®²à®¿à®°à¯à®¨à¯à®¤à¯ காரà¯à®Ÿà¯à®•à®³à¯ˆà®•à¯ காணà¯à®ªà®¿</translation>
<translation id="1507202001669085618">&lt;p&gt;சில வைஃபை போரà¯à®Ÿà¯à®Ÿà®²à¯à®•à®³à®¿à®²à¯, இணையதà¯à®¤à¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à¯à®®à¯ à®®à¯à®©à¯à®ªà¯ நீஙà¯à®•à®³à¯ உளà¯à®¨à¯à®´à¯ˆà®¯ வேணà¯à®Ÿà®¿à®¯à®¿à®°à¯à®•à¯à®•à¯à®®à¯. அதà¯à®ªà¯‹à®©à¯à®± போரà¯à®Ÿà¯à®Ÿà®²à¯à®•à®³à¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®¿à®©à®¾à®²à¯, இநà¯à®¤à®ªà¯ பிழையைப௠பாரà¯à®ªà¯à®ªà¯€à®°à¯à®•à®³à¯.&lt;/p&gt;
@@ -208,6 +220,8 @@
<translation id="1559572115229829303">&lt;p&gt;உஙà¯à®•à®³à¯ சாதனதà¯à®¤à®¿à®©à¯ தேதி மறà¯à®±à¯à®®à¯ நேரம௠(<ph name="DATE_AND_TIME" />) தவறாக இரà¯à®ªà¯à®ªà®¤à®¾à®²à¯ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> எனà¯à®•à®¿à®± டொமைனிறà¯à®•à¯à®¤à¯ தனிபà¯à®ªà®Ÿà¯à®Ÿ இணைபà¯à®ªà¯ˆ à®à®±à¯à®ªà®Ÿà¯à®¤à¯à®¤ à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ.&lt;/p&gt;
&lt;p&gt;தேதி மறà¯à®±à¯à®®à¯ நேரதà¯à®¤à¯ˆ &lt;strong&gt;அமைபà¯à®ªà¯à®•à®³à¯&lt;/strong&gt; ஆபà¯à®¸à®¿à®©à¯ &lt;strong&gt;பொதà¯&lt;/strong&gt; எனà¯à®•à®¿à®± பகà¯à®¤à®¿à®¯à®¿à®²à¯ மாறà¯à®±à®µà¯à®®à¯.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">உஙà¯à®•à®³à¯ நிரà¯à®µà®¾à®•à®¿ சாதனதà¯à®¤à¯ˆ <ph name="DATE" /> அனà¯à®±à¯ <ph name="TIME" /> மணிகà¯à®•à¯ மீணà¯à®Ÿà¯à®®à¯ தொடஙà¯à®•à¯à®µà®¾à®°à¯</translation>
+<translation id="156703335097561114">à®®à¯à®•à®µà®°à®¿à®•à®³à¯, இடைமà¯à®• உளà¯à®³à®®à¯ˆà®µà¯, இணைபà¯à®ªà®¿à®©à¯ தரம௠போனà¯à®± நெடà¯à®µà¯Šà®°à¯à®•à¯à®•à®¿à®™à¯ தகவலà¯à®•à®³à¯</translation>
<translation id="1567040042588613346">இநà¯à®¤à®•à¯ கொளà¯à®•à¯ˆ எதிரà¯à®ªà®¾à®°à¯à®¤à¯à®¤ வகையில௠வேலை செயà¯à®•à®¿à®±à®¤à¯. ஆனால௠இதே மதிபà¯à®ªà¯ வேற௠எஙà¯à®•à¯‹ அமைகà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯‹à®Ÿà¯ இநà¯à®¤à®•à¯ கொளà¯à®•à¯ˆà®¯à®¿à®©à¯ மூலம௠மாறà¯à®±à®¿à®¯à®®à¯ˆà®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®•à®¿à®±à®¤à¯.</translation>
<translation id="1569487616857761740">காலாவதித௠தேதியை உளà¯à®³à®¿à®Ÿà®µà¯à®®à¯</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@
<translation id="1583429793053364125">இநà¯à®¤ இணையபà¯à®ªà®•à¯à®•à®¤à¯à®¤à¯ˆà®•à¯ காடà¯à®Ÿà¯à®®à¯à®ªà¯‹à®¤à¯ à®à®¤à¯‹ தவற௠à®à®±à¯à®ªà®Ÿà¯à®Ÿà®¤à¯.</translation>
<translation id="1586541204584340881">நீஙà¯à®•à®³à¯ நிறà¯à®µà®¿à®¯à¯à®³à¯à®³ நீடà¯à®Ÿà®¿à®ªà¯à®ªà¯à®•à®³à¯</translation>
<translation id="1588438908519853928">இயலà¯à®ªà¯</translation>
+<translation id="1589050138437146318">ARCoreரை நிறà¯à®µà®µà®¾?</translation>
<translation id="1592005682883173041">அகத௠தரவ௠அணà¯à®•à®²à¯</translation>
<translation id="1594030484168838125">தேரà¯à®µà¯à®šà¯†à®¯à¯</translation>
<translation id="160851722280695521">Chromeமில௠டைனோசர௠கேமை விளையாடலாமà¯</translation>
@@ -283,6 +298,7 @@
மேறà¯à®•à¯à®±à®¿à®ªà¯à®ªà¯ தவறாக உளà¯à®³à®¤à®¾à®²à¯
<ph name="SITE" /> தளதà¯à®¤à®¿à®±à¯à®•à®¾à®© உஙà¯à®•à®³à¯ கோரிகà¯à®•à¯ˆà®¯à¯ˆ நிறைவà¯à®šà¯†à®¯à¯à®¯ à®®à¯à®Ÿà®¿à®¯à®¾à®¤ வகையில௠உலாவி தடà¯à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯. இணையதள ஆபà¯à®°à¯‡à®Ÿà¯à®Ÿà®°à¯à®•à®³à¯ இணையதளதà¯à®¤à®¿à®±à¯à®•à®¾à®© பாதà¯à®•à®¾à®ªà¯à®ªà¯ˆà®¯à¯à®®à¯ மறà¯à®± பணà¯à®ªà¯à®•à®³à¯ˆà®¯à¯à®®à¯ உளà¯à®³à®®à¯ˆà®•à¯à®•
அசல௠கொளà¯à®•à¯ˆà®•à®³à¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®²à®¾à®®à¯.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Chromium மறைநிலைப௠பயனà¯à®®à¯à®±à¯ˆ கà¯à®±à®¿à®¤à¯à®¤à¯ மேலà¯à®®à¯ அறிக<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">உஙà¯à®•à®³à¯ தாவலà¯à®•à®³à¯ இஙà¯à®•à¯‡ தோனà¯à®±à¯à®®à¯</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -359,7 +375,7 @@
<translation id="204357726431741734">உஙà¯à®•à®³à¯ Google கணகà¯à®•à®¿à®²à¯ சேமிகà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³ கடவà¯à®šà¯à®šà¯Šà®±à¯à®•à®³à¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤ உளà¯à®¨à¯à®´à¯ˆà®•</translation>
<translation id="2053111141626950936"><ph name="LANGUAGE" /> மொழியில௠உளà¯à®³ பகà¯à®•à®™à¯à®•à®³à¯ மொழிபெயரà¯à®•à¯à®•à®ªà¯à®ªà®Ÿà®¾à®¤à¯.</translation>
<translation id="2053373601901562871">{NUM_DAYS,plural, =0{இநà¯à®¤à®•à¯ கடà¯à®Ÿà¯à®ªà¯à®ªà®¾à®Ÿà¯ இயகà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯ ‘செயலில௠உளà¯à®³à®¤à¯â€™ எனà¯à®± நிலையில௠இரà¯à®¨à¯à®¤à®¾à®²à¯ உஙà¯à®•à®³à¯ சமீபதà¯à®¤à®¿à®¯ உலாவல௠செயலà¯à®ªà®¾à®Ÿà¯à®Ÿà®¿à®±à¯à®•à¯ மிகவà¯à®®à¯ பொரà¯à®¨à¯à®¤à®•à¯à®•à¯‚டிய பெரிய கà¯à®´à¯ அலà¯à®²à®¤à¯ “கà¯à®´à¯à®µà®¿à®©à®°à¯ˆâ€ Chrome அறிநà¯à®¤à¯à®•à¯Šà®³à¯à®³à¯à®®à¯. விளமà¯à®ªà®°à®¤à®¾à®°à®°à¯à®•à®³à¯ கà¯à®´à¯à®µà®¿à®±à¯à®•à®¾à®© விளமà¯à®ªà®°à®™à¯à®•à®³à¯ˆà®¤à¯ தேரà¯à®¨à¯à®¤à¯†à®Ÿà¯à®•à¯à®•à®²à®¾à®®à¯. மேலà¯à®®à¯ உஙà¯à®•à®³à¯ உலாவல௠செயலà¯à®ªà®¾à®Ÿà¯ உஙà¯à®•à®³à¯ சாதனதà¯à®¤à®¿à®²à¯ தனிபà¯à®ªà®Ÿà¯à®Ÿ à®®à¯à®±à¯ˆà®¯à®¿à®²à¯ சேமிகà¯à®•à®ªà¯à®ªà®Ÿà¯à®®à¯. தினமà¯à®®à¯ உஙà¯à®•à®³à¯ கà¯à®´à¯ பà¯à®¤à¯à®ªà¯à®ªà®¿à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®®à¯.}=1{இநà¯à®¤à®•à¯ கடà¯à®Ÿà¯à®ªà¯à®ªà®¾à®Ÿà¯ இயகà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯ ‘செயலில௠உளà¯à®³à®¤à¯â€™ எனà¯à®± நிலையில௠இரà¯à®¨à¯à®¤à®¾à®²à¯ உஙà¯à®•à®³à¯ சமீபதà¯à®¤à®¿à®¯ உலாவல௠செயலà¯à®ªà®¾à®Ÿà¯à®Ÿà®¿à®±à¯à®•à¯ மிகவà¯à®®à¯ பொரà¯à®¨à¯à®¤à®•à¯à®•à¯‚டிய பெரிய கà¯à®´à¯ அலà¯à®²à®¤à¯ “கà¯à®´à¯à®µà®¿à®©à®°à¯ˆâ€ Chrome அறிநà¯à®¤à¯à®•à¯Šà®³à¯à®³à¯à®®à¯. விளமà¯à®ªà®°à®¤à®¾à®°à®°à¯à®•à®³à¯ கà¯à®´à¯à®µà®¿à®±à¯à®•à®¾à®© விளமà¯à®ªà®°à®™à¯à®•à®³à¯ˆà®¤à¯ தேரà¯à®¨à¯à®¤à¯†à®Ÿà¯à®•à¯à®•à®²à®¾à®®à¯. மேலà¯à®®à¯ உஙà¯à®•à®³à¯ உலாவல௠செயலà¯à®ªà®¾à®Ÿà¯ உஙà¯à®•à®³à¯ சாதனதà¯à®¤à®¿à®²à¯ தனிபà¯à®ªà®Ÿà¯à®Ÿ à®®à¯à®±à¯ˆà®¯à®¿à®²à¯ சேமிகà¯à®•à®ªà¯à®ªà®Ÿà¯à®®à¯. தினமà¯à®®à¯ உஙà¯à®•à®³à¯ கà¯à®´à¯ பà¯à®¤à¯à®ªà¯à®ªà®¿à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®®à¯.}other{இநà¯à®¤à®•à¯ கடà¯à®Ÿà¯à®ªà¯à®ªà®¾à®Ÿà¯ இயகà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯ ‘செயலில௠உளà¯à®³à®¤à¯â€™ எனà¯à®± நிலையில௠இரà¯à®¨à¯à®¤à®¾à®²à¯ உஙà¯à®•à®³à¯ சமீபதà¯à®¤à®¿à®¯ உலாவல௠செயலà¯à®ªà®¾à®Ÿà¯à®Ÿà®¿à®±à¯à®•à¯ மிகவà¯à®®à¯ பொரà¯à®¨à¯à®¤à®•à¯à®•à¯‚டிய பெரிய கà¯à®´à¯ அலà¯à®²à®¤à¯ “கà¯à®´à¯à®µà®¿à®©à®°à¯ˆâ€ Chrome அறிநà¯à®¤à¯à®•à¯Šà®³à¯à®³à¯à®®à¯. விளமà¯à®ªà®°à®¤à®¾à®°à®°à¯à®•à®³à¯ கà¯à®´à¯à®µà®¿à®±à¯à®•à®¾à®© விளமà¯à®ªà®°à®™à¯à®•à®³à¯ˆà®¤à¯ தேரà¯à®¨à¯à®¤à¯†à®Ÿà¯à®•à¯à®•à®²à®¾à®®à¯. மேலà¯à®®à¯ உஙà¯à®•à®³à¯ உலாவல௠செயலà¯à®ªà®¾à®Ÿà¯ உஙà¯à®•à®³à¯ சாதனதà¯à®¤à®¿à®²à¯ தனிபà¯à®ªà®Ÿà¯à®Ÿ à®®à¯à®±à¯ˆà®¯à®¿à®²à¯ சேமிகà¯à®•à®ªà¯à®ªà®Ÿà¯à®®à¯. {NUM_DAYS} நாடà¯à®•à®³à¯à®•à¯à®•à¯ à®’à®°à¯à®®à¯à®±à¯ˆ உஙà¯à®•à®³à¯ கà¯à®´à¯ பà¯à®¤à¯à®ªà¯à®ªà®¿à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®®à¯.}}</translation>
-<translation id="2053553514270667976">ஜிப௠கà¯à®±à®¿à®¯à¯€à®Ÿà¯</translation>
+<translation id="2053553514270667976">அஞà¯à®šà®²à¯ கà¯à®±à®¿à®¯à¯€à®Ÿà¯</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 பரிநà¯à®¤à¯à®°à¯ˆ}other{# பரிநà¯à®¤à¯à®°à¯ˆà®•à®³à¯}}</translation>
<translation id="2071156619270205202">இநà¯à®¤à®•à¯ காரà¯à®Ÿà¯ எணà¯à®£à¯ˆ விரà¯à®šà¯à®šà¯à®µà®²à¯ காரà¯à®Ÿà¯ எணà¯à®£à®¾à®•à®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤ à®®à¯à®Ÿà®¿à®¯à®¾à®¤à¯.</translation>
<translation id="2071692954027939183">வழகà¯à®•à®®à®¾à®• நீஙà¯à®•à®³à¯ அறிவிபà¯à®ªà¯à®•à®³à¯ˆ அனà¯à®®à®¤à®¿à®ªà¯à®ªà®¤à®¿à®²à¯à®²à¯ˆ எனà¯à®ªà®¤à®¾à®²à¯ அவை தானாகவே தடà¯à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®©</translation>
@@ -410,6 +426,7 @@
<translation id="22081806969704220">தடà¯à®Ÿà¯ 3</translation>
<translation id="2212735316055980242">கொளà¯à®•à¯ˆ காணபà¯à®ªà®Ÿà®µà®¿à®²à¯à®²à¯ˆ</translation>
<translation id="2213606439339815911">உளà¯à®³à¯€à®Ÿà¯à®•à®³à¯ˆà®ªà¯ பெறà¯à®•à®¿à®±à®¤à¯...</translation>
+<translation id="2213612003795704869">பகà¯à®•à®®à¯ அசà¯à®šà®¿à®Ÿà®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯</translation>
<translation id="2215727959747642672">ஃபைலைத௠திரà¯à®¤à¯à®¤à¯à®¤à®²à¯</translation>
<translation id="2218879909401188352">தறà¯à®ªà¯‹à®¤à¯ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> எனà¯à®®à¯ தளதà¯à®¤à®¿à®²à¯ உளà¯à®³ தீஙà¯à®•à®¿à®´à¯ˆà®ªà¯à®ªà®µà®°à¯à®•à®³à¯ உஙà¯à®•à®³à¯ சாதனதà¯à®¤à¯ˆà®šà¯ சேதபà¯à®ªà®Ÿà¯à®¤à¯à®¤à¯à®®à¯ ஆபதà¯à®¤à®¾à®© ஆபà¯à®¸à¯ˆ நிறà¯à®µà®²à®¾à®®à¯, மொபைல௠கடà¯à®Ÿà®£à®¤à¯à®¤à®¿à®²à¯ மறைமà¯à®•à®•à¯ கடà¯à®Ÿà®£à®™à¯à®•à®³à¯ˆà®šà¯ சேரà¯à®•à¯à®•à®²à®¾à®®à¯ அலà¯à®²à®¤à¯ உஙà¯à®•à®³à¯ தனிபà¯à®ªà®Ÿà¯à®Ÿ தகவலைத௠திரà¯à®Ÿà®²à®¾à®®à¯. <ph name="BEGIN_LEARN_MORE_LINK" />மேலà¯à®®à¯ அறிக<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">இணைய இணைபà¯à®ªà¯ இலà¯à®²à¯ˆ</translation>
@@ -419,6 +436,7 @@
<translation id="2248949050832152960">WebAuthnனைப௠பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à¯</translation>
<translation id="2250931979407627383">எடà¯à®œà¯ ஸà¯à®Ÿà®¿à®Ÿà¯à®šà¯ லெஃபà¯à®Ÿà¯</translation>
<translation id="225207911366869382">இநà¯à®¤ கொளà¯à®•à¯ˆà®•à¯à®•à®¾à®© மதிபà¯à®ªà¯ நிறà¯à®¤à¯à®¤à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯.</translation>
+<translation id="2256115617011615191">இபà¯à®ªà¯‹à®¤à¯ மீணà¯à®Ÿà¯à®®à¯ தொடஙà¯à®•à¯</translation>
<translation id="2258928405015593961">எதிரà¯à®•à®¾à®²à®¤à¯ தேதியில௠காலாவதித௠தேதியை உளà¯à®³à®¿à®Ÿà¯à®Ÿà¯ மீணà¯à®Ÿà¯à®®à¯ à®®à¯à®¯à®²à®µà¯à®®à¯</translation>
<translation id="225943865679747347">பிழைக௠கà¯à®±à®¿à®¯à¯€à®Ÿà¯: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">HTTP பிழை</translation>
@@ -446,6 +464,7 @@
<translation id="2337852623177822836">அமைபà¯à®ªà¯ˆ உஙà¯à®•à®³à¯ நிரà¯à®µà®¾à®•à®¿ கடà¯à®Ÿà¯à®ªà¯à®ªà®Ÿà¯à®¤à¯à®¤à¯à®•à®¿à®±à®¾à®°à¯</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> இணைய விரà¯à®®à¯à®ªà¯à®•à®¿à®±à®¤à¯</translation>
<translation id="2346319942568447007">நீஙà¯à®•à®³à¯ நகலெடà¯à®¤à¯à®¤à®ªà¯ படமà¯</translation>
+<translation id="2350796302381711542">எலà¯à®²à®¾ <ph name="PROTOCOL" /> இணைபà¯à®ªà¯à®•à®³à¯ˆà®¯à¯à®®à¯ திறகà¯à®•, <ph name="REPLACED_HANDLER_TITLE" /> கà¯à®•à¯à®ªà¯ பதிலாக <ph name="HANDLER_HOSTNAME" /> ஠அனà¯à®®à®¤à®¿à®•à¯à®•à®µà®¾?</translation>
<translation id="2354001756790975382">பிற பà¯à®•à¯à®®à®¾à®°à¯à®•à¯à®¸à¯</translation>
<translation id="2354430244986887761">சமீபதà¯à®¤à®¿à®²à¯ Google பாதà¯à®•à®¾à®ªà¯à®ªà®¾à®© தேடலானத௠<ph name="SITE" /> இல௠<ph name="BEGIN_LINK" />தீஙà¯à®•à®¿à®´à¯ˆà®•à¯à®•à¯à®®à¯ பயனà¯à®ªà®¾à®Ÿà¯à®•à®³à¯ˆà®•à¯ கணà¯à®Ÿà®±à®¿à®¨à¯à®¤à®¤à¯<ph name="END_LINK" />.</translation>
<translation id="2355395290879513365">இநà¯à®¤à®¤à¯ தளதà¯à®¤à®¿à®²à¯ நீஙà¯à®•à®³à¯ பாரà¯à®¤à¯à®¤à¯à®•à¯ கொணà¯à®Ÿà®¿à®°à¯à®•à¯à®•à¯à®®à¯ படஙà¯à®•à®³à¯ˆ தீஙà¯à®•à®¿à®´à¯ˆà®ªà¯à®ªà®µà®°à¯à®•à®³à¯à®®à¯ பாரà¯à®¤à¯à®¤à¯, அவறà¯à®±à¯ˆ மாறà¯à®±à®¿à®¯à®®à¯ˆà®¤à¯à®¤à¯ உஙà¯à®•à®³à¯ˆ à®à®®à®¾à®±à¯à®±à®•à¯à®•à¯‚டà¯à®®à¯.</translation>
@@ -471,6 +490,7 @@
<translation id="2413528052993050574">இத௠<ph name="DOMAIN" /> தான௠எனà¯à®ªà®¤à¯ˆ இநà¯à®¤à®šà¯ சேவையகம௠உறà¯à®¤à®¿à®ªà¯à®ªà®Ÿà¯à®¤à¯à®¤à®µà®¿à®²à¯à®²à¯ˆ; இதன௠பாதà¯à®•à®¾à®ªà¯à®ªà¯à®šà¯ சானà¯à®±à®¿à®¤à®´à¯ திரà¯à®®à¯à®ªà®ªà¯à®ªà¯†à®±à®ªà¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯. இத௠தவறான உளà¯à®³à®®à¯ˆà®µà®¾à®²à¯ à®à®±à¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯ அலà¯à®²à®¤à¯ தீஙà¯à®•à®¿à®´à¯ˆà®ªà¯à®ªà®µà®°à¯ உஙà¯à®•à®³à¯ இணைபà¯à®ªà®¿à®²à¯ கà¯à®±à¯à®•à¯à®•à®¿à®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯.</translation>
<translation id="2414886740292270097">அடரà¯</translation>
<translation id="2430968933669123598">Google கணகà¯à®•à¯ˆ நிரà¯à®µà®•à®¿à®•à¯à®•à®²à®¾à®®à¯. உஙà¯à®•à®³à¯ Google கணகà¯à®•à®¿à®²à¯ உளà¯à®³ தகவலà¯à®•à®³à¯, தனியà¯à®°à®¿à®®à¯ˆ, பாதà¯à®•à®¾à®ªà¯à®ªà¯ ஆகியவறà¯à®±à¯ˆ நிரà¯à®µà®•à®¿à®•à¯à®• Enter படà¯à®Ÿà®©à¯ˆ à®…à®´à¯à®¤à¯à®¤à¯à®™à¯à®•à®³à¯</translation>
+<translation id="2436186046335138073">எலà¯à®²à®¾ <ph name="PROTOCOL" /> இணைபà¯à®ªà¯à®•à®³à¯ˆà®¯à¯à®®à¯ திறகà¯à®•, <ph name="HANDLER_HOSTNAME" /> ஠அனà¯à®®à®¤à®¿à®•à¯à®•à®µà®¾?</translation>
<translation id="2438874542388153331">கà¯à®µà®¾à®Ÿà¯ பஞà¯à®šà¯ ரைடà¯</translation>
<translation id="2450021089947420533">கà¯à®±à®¿à®ªà¯à®ªà®¿à®Ÿà¯à®Ÿ தேடல௠விவரஙà¯à®•à®³à¯</translation>
<translation id="2463739503403862330">நிரபà¯à®ªà¯</translation>
@@ -478,6 +498,7 @@
<translation id="2465655957518002998">டெலிவரி à®®à¯à®±à¯ˆà®¯à¯ˆà®¤à¯ தேரà¯à®µà¯ செயà¯</translation>
<translation id="2465688316154986572">ஸà¯à®Ÿà¯‡à®ªà¯à®ªà®¿à®²à¯</translation>
<translation id="2465914000209955735">Chromeமில௠நீஙà¯à®•à®³à¯ பதிவிறகà¯à®•à®¿à®¯ ஃபைலà¯à®•à®³à¯ˆ நிரà¯à®µà®•à®¿à®•à¯à®•à®²à®¾à®®à¯</translation>
+<translation id="2466004615675155314">இணையதà¯à®¤à®¿à®²à¯ இரà¯à®¨à¯à®¤à¯ தகவலà¯à®•à®³à¯ˆà®•à¯ காடà¯à®Ÿà¯à®®à¯</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />நெடà¯à®µà¯Šà®°à¯à®•à¯ டயகà¯à®©à®¾à®¸à¯à®Ÿà®¿à®•à¯à®¸à¯ கரà¯à®µà®¿à®¯à¯ˆ இயகà¯à®•à®µà¯à®®à¯<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">à®®à¯à®©à¯à®©à¯‹à®•à¯à®•à®¿à®¯ வரிசை</translation>
<translation id="2470767536994572628">விரிவà¯à®°à¯ˆà®•à®³à¯ˆà®¤à¯ திரà¯à®¤à¯à®¤à®¿à®©à®¾à®²à¯ இநà¯à®¤ ஆவணம௠ஒறà¯à®±à¯ˆà®ªà¯ பகà¯à®•à®•à¯à®•à®¾à®Ÿà¯à®šà®¿à®•à¯à®•à¯à®®à¯ தனத௠அசல௠நிலைகà¯à®•à¯à®®à¯ மாறà¯à®®à¯</translation>
@@ -498,6 +519,7 @@
<translation id="2523886232349826891">இநà¯à®¤à®šà¯ சாதனதà¯à®¤à®¿à®²à¯ மடà¯à®Ÿà¯à®®à¯ சேமிகà¯à®•à®ªà¯à®ªà®Ÿà¯à®®à¯</translation>
<translation id="2524461107774643265">மேலà¯à®®à¯ தகவலைச௠சேரà¯à®•à¯à®•à®µà¯à®®à¯</translation>
<translation id="2529899080962247600">இதில௠<ph name="MAX_ITEMS_LIMIT" /> உளà¯à®³à¯€à®Ÿà¯à®•à®³à¯à®•à¯à®•à¯ மேல௠இரà¯à®•à¯à®•à®•à¯à®•à¯‚டாதà¯. அதறà¯à®•à¯ மேல௠இரà¯à®ªà¯à®ªà®µà¯ˆ நிராகரிகà¯à®•à®ªà¯à®ªà®Ÿà¯à®®à¯.</translation>
+<translation id="2535585790302968248">தனிபà¯à®ªà®Ÿà¯à®Ÿ à®®à¯à®±à¯ˆà®¯à®¿à®²à¯ உலாவ, பà¯à®¤à®¿à®¯ மறைநிலைப௠பகà¯à®•à®¤à¯à®¤à¯ˆà®¤à¯ திறகà¯à®•à¯à®®à¯</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{மேலà¯à®®à¯ ஒனà¯à®±à¯}other{மேலà¯à®®à¯ #}}</translation>
<translation id="2536110899380797252">à®®à¯à®•à®µà®°à®¿à®¯à¯ˆà®šà¯ சேரà¯</translation>
<translation id="2539524384386349900">கணà¯à®Ÿà®±à®¿</translation>
@@ -523,7 +545,14 @@
<translation id="2597378329261239068">இநà¯à®¤ ஆவணம௠கடவà¯à®šà¯à®šà¯Šà®²à¯ பாதà¯à®•à®¾à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿ ஒனà¯à®±à¯. தயவà¯à®šà¯†à®¯à¯à®¤à¯ ஒர௠கடவà¯à®šà¯à®šà¯Šà®²à¯à®²à¯ˆ உளà¯à®³à®¿à®Ÿà¯à®•.</translation>
<translation id="2609632851001447353">வேறà¯à®ªà®¾à®Ÿà¯à®•à®³à¯</translation>
<translation id="2610561535971892504">கிளிக௠செயà¯à®¤à¯ நகலெடà¯à®•à¯à®•à®µà¯à®®à¯</translation>
+<translation id="2617988307566202237">பினà¯à®µà®°à¯à®®à¯ தகவலà¯à®•à®³à¯ˆ Chrome <ph name="BEGIN_EMPHASIS" />சேமிகà¯à®•à®¾à®¤à¯<ph name="END_EMPHASIS" />:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />நீஙà¯à®•à®³à¯ இதà¯à®µà®°à¯ˆ இணையதà¯à®¤à®¿à®²à¯ பாரà¯à®¤à¯à®¤à®µà¯ˆ
+ <ph name="LIST_ITEM" />கà¯à®•à¯à®•à¯€à®•à®³à¯ மறà¯à®±à¯à®®à¯ தளத௠தரவà¯
+ <ph name="LIST_ITEM" />படிவஙà¯à®•à®³à®¿à®²à¯ டைப௠செயà¯à®¤ தகவலà¯à®•à®³à¯
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (எனà¯à®µà®²à®ªà¯)</translation>
+<translation id="2623663032199728144">திரைகள௠கà¯à®±à®¿à®¤à¯à®¤ தகவலைப௠பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®²à®¾à®®à®¾ என உஙà¯à®•à®³à®¿à®Ÿà®®à¯ கேடà¯à®•à¯à®®à¯</translation>
<translation id="2625385379895617796">உஙà¯à®•à®³à¯ கடிகாரம௠மிகவà¯à®®à¯ à®®à¯à®©à¯à®©à¯‹à®•à¯à®•à®¿ இரà¯à®•à¯à®•à®¿à®±à®¤à¯</translation>
<translation id="262745152991669301">USB சாதனஙà¯à®•à®³à¯à®Ÿà®©à¯ இணைய à®®à¯à®¯à®²à¯à®®à¯à®ªà¯‹à®¤à¯ அனà¯à®®à®¤à®¿ கேடà¯à®• வேணà¯à®Ÿà¯à®®à¯</translation>
<translation id="2629325967560697240">Chromeமின௠அதிகபடà¯à®šà®ªà¯ பாதà¯à®•à®¾à®ªà¯à®ªà¯ˆà®ªà¯ பெற, <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />மேமà¯à®ªà®Ÿà¯à®Ÿ பாதà¯à®•à®¾à®ªà¯à®ªà¯ˆ இயகà¯à®•à®µà¯à®®à¯<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -557,6 +586,7 @@
<translation id="2709516037105925701">தானாகநிரபà¯à®ªà¯</translation>
<translation id="2713444072780614174">வெளà¯à®³à¯ˆ</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />, Chrome அமைபà¯à®ªà¯à®•à®³à®¿à®²à¯ பேமெணà¯à®Ÿà¯à®Ÿà¯à®•à®³à¯, கிரெடிட௠காரà¯à®Ÿà¯ ஆகியவை கà¯à®±à®¿à®¤à¯à®¤ தகவலை நிரà¯à®µà®•à®¿à®•à¯à®• Tab விசையை à®…à®´à¯à®¤à¯à®¤à®¿à®¯ பிறக௠Enter விசையை à®…à®´à¯à®¤à¯à®¤à¯à®™à¯à®•à®³à¯</translation>
+<translation id="271663710482723385">à®®à¯à®´à¯à®¤à¯à®¤à®¿à®°à¯ˆà®¯à®¿à®²à¯ இரà¯à®¨à¯à®¤à¯ வெளியேற, |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| படà¯à®Ÿà®©à¯à®•à®³à¯ˆ à®…à®´à¯à®¤à¯à®¤à®µà¯à®®à¯</translation>
<translation id="2721148159707890343">கோரிகà¯à®•à¯ˆ வெறà¯à®±à®¿à®¯à®Ÿà¯ˆà®¨à¯à®¤à®¤à¯</translation>
<translation id="2723669454293168317">Chrome அமைபà¯à®ªà¯à®•à®³à®¿à®²à¯ பாதà¯à®•à®¾à®ªà¯à®ªà¯à®šà¯ சரிபாரà¯à®ªà¯à®ªà¯ˆ இயகà¯à®•à¯à®®à¯</translation>
<translation id="2726001110728089263">சைட௠டிரே</translation>
@@ -587,6 +617,7 @@
<translation id="2850739647070081192">Invite (எனà¯à®µà®²à®ªà¯)</translation>
<translation id="2856444702002559011"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> தளதà¯à®¤à®¿à®²à®¿à®°à¯à®¨à¯à®¤à¯ ஹேகà¯à®•à®°à¯à®•à®³à¯ உஙà¯à®•à®³à¯ தகவலை (எடà¯à®¤à¯à®¤à¯à®•à¯à®•à®¾à®Ÿà¯à®Ÿà®¾à®•, கடவà¯à®šà¯à®šà¯Šà®±à¯à®•à®³à¯, செயà¯à®¤à®¿à®•à®³à¯ அலà¯à®²à®¤à¯ கிரெடிட௠காரà¯à®Ÿà¯à®•à®³à¯) திரà¯à®Ÿ à®®à¯à®¯à®±à¯à®šà®¿à®•à¯à®•à®•à¯à®•à¯‚டà¯à®®à¯. <ph name="BEGIN_LEARN_MORE_LINK" />மேலà¯à®®à¯ அறிக<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">கà¯à®±à¯à®•à¯à®•à®¿à®Ÿà¯à®®à¯ அலà¯à®²à®¤à¯ தவறாக வழிநடதà¯à®¤à¯à®®à¯ விளமà¯à®ªà®°à®™à¯à®•à®³à¯ˆ இநà¯à®¤à®¤à¯ தளம௠காணà¯à®ªà®¿à®•à¯à®•à®¿à®±à®¤à¯.</translation>
+<translation id="286512204874376891">மோசடி அபாயஙà¯à®•à®³à®¿à®²à¯ இரà¯à®¨à¯à®¤à¯ உஙà¯à®•à®³à¯ அசல௠காரà¯à®Ÿà¯ˆà®ªà¯ பாதà¯à®•à®¾à®•à¯à®• விரà¯à®šà¯à®šà¯à®µà®²à¯ காரà¯à®Ÿà¯ உதவà¯à®•à®¿à®±à®¤à¯.<ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">ஃபà¯à®°à®£à¯à®Ÿà¯à®²à®¿</translation>
<translation id="2876489322757410363">மூனà¯à®±à®¾à®®à¯ தரபà¯à®ªà¯ ஆபà¯à®¸à®¿à®©à¯ மூலம௠பணதà¯à®¤à¯ˆà®šà¯ செலà¯à®¤à¯à®¤, மறைநிலைப௠பயனà¯à®®à¯à®±à¯ˆà®¯à®¿à®²à¯ இரà¯à®¨à¯à®¤à¯ வெளியேறà¯à®•à®¿à®±à®¤à¯. தொடரவா?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />. Chrome அமைபà¯à®ªà¯à®•à®³à®¿à®²à¯ பாதà¯à®•à®¾à®ªà¯à®ªà¯ உலாவலையà¯à®®à¯ மேலà¯à®®à¯ பலவறà¯à®±à¯ˆà®¯à¯à®®à¯ நிரà¯à®µà®•à®¿à®•à¯à®•, Tab படà¯à®Ÿà®©à¯ˆ à®…à®´à¯à®¤à¯à®¤à®¿à®µà®¿à®Ÿà¯à®Ÿà¯ Enter படà¯à®Ÿà®©à¯ˆ à®…à®´à¯à®¤à¯à®¤à¯à®™à¯à®•à®³à¯</translation>
@@ -611,6 +642,7 @@
<translation id="2930577230479659665">டிரிம௠ஆஃபà¯à®Ÿà®°à¯ ஈச௠காபà¯à®ªà®¿</translation>
<translation id="2932085390869194046">கடவà¯à®šà¯à®šà¯Šà®²à¯à®²à¯ˆà®ªà¯ பரிநà¯à®¤à¯à®°à¯ˆ...</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019"><ph name="PROTOCOL" /> இணைபà¯à®ªà¯à®•à®³à¯ˆà®¤à¯ திறகà¯à®•à¯à®®à¯</translation>
<translation id="2941952326391522266">இத௠<ph name="DOMAIN" /> தான௠எனà¯à®ªà®¤à¯ˆ இநà¯à®¤à®šà¯ சேவையகம௠உறà¯à®¤à®¿à®ªà¯à®ªà®Ÿà¯à®¤à¯à®¤à®µà®¿à®²à¯à®²à¯ˆ; இதன௠பாதà¯à®•à®¾à®ªà¯à®ªà¯à®šà¯ சானà¯à®±à®¿à®¤à®´à¯ <ph name="DOMAIN2" /> இலிரà¯à®¨à¯à®¤à¯ பெறபà¯à®ªà®Ÿà¯à®Ÿà®¤à¯. இத௠தவறான உளà¯à®³à®®à¯ˆà®µà®¾à®²à¯ à®à®±à¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯ அலà¯à®²à®¤à¯ தீஙà¯à®•à®¿à®´à¯ˆà®ªà¯à®ªà®µà®°à¯ உஙà¯à®•à®³à¯ இணைபà¯à®ªà®¿à®²à¯ கà¯à®±à¯à®•à¯à®•à®¿à®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯.</translation>
<translation id="2943895734390379394">பதிவேறà¯à®±à®¿à®¯ நேரமà¯:</translation>
<translation id="2948083400971632585">இணைபà¯à®ªà®¿à®±à¯à®•à®¾à®• உளà¯à®³à®®à¯ˆà®¤à¯à®¤ எநà¯à®¤ பிராகà¯à®šà®¿à®•à®³à¯ˆà®¯à¯à®®à¯ நீஙà¯à®•à®³à¯ அமைபà¯à®ªà¯à®•à®³à¯ பகà¯à®•à®¤à¯à®¤à®¿à®²à®¿à®°à¯à®¨à¯à®¤à¯ à®®à¯à®Ÿà®•à¯à®•à®²à®¾à®®à¯.</translation>
@@ -643,6 +675,7 @@
<translation id="3037605927509011580">அசà¯à®šà®šà¯à®šà¯‹!</translation>
<translation id="3041612393474885105">சானà¯à®±à®¿à®¤à®´à¯ தகவலà¯</translation>
<translation id="3044034790304486808">உலாவலைத௠தொடரà¯à®•</translation>
+<translation id="305162504811187366">நேர à®®à¯à®¤à¯à®¤à®¿à®°à¯ˆà®•à®³à¯, ஹோஸà¯à®Ÿà¯à®Ÿà¯à®•à®³à¯, கிளையணà¯à®Ÿà¯ அமரà¯à®µà¯ à®à®Ÿà®¿à®•à®³à¯ உடà¯à®ªà®Ÿ இதà¯à®µà®°à¯ˆà®¯à®¿à®²à®¾à®© Chrome தொலைநிலை டெஸà¯à®•à¯à®Ÿà®¾à®ªà¯ நிகழà¯à®µà¯à®•à®³à¯</translation>
<translation id="3060227939791841287">C9 (எனà¯à®µà®²à®ªà¯)</translation>
<translation id="3061707000357573562">பேடà¯à®šà¯ சேவை</translation>
<translation id="306573536155379004">கேம௠தொடஙà¯à®•à®¿à®¯à®¤à¯.</translation>
@@ -680,6 +713,7 @@
<translation id="3197136577151645743">இநà¯à®¤à®šà¯ சாதனதà¯à®¤à®¿à®²à¯ நான௠செயலில௠இரà¯à®ªà¯à®ªà®¤à¯ˆ அறிநà¯à®¤à¯à®•à¯Šà®³à¯à®³ அனà¯à®®à®¤à®¿ கேடà¯à®• வேணà¯à®Ÿà¯à®®à¯</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />. எநà¯à®¤à¯†à®¨à¯à®¤à®¤à¯ தகவலà¯à®•à®³à¯ˆ ஒதà¯à®¤à®¿à®šà¯ˆà®•à¯à®• வேணà¯à®Ÿà¯à®®à¯ எனà¯à®ªà®¤à¯ˆ Chrome அமைபà¯à®ªà¯à®•à®³à®¿à®²à¯ நிரà¯à®µà®•à®¿à®•à¯à®•, Tab விசையை à®…à®´à¯à®¤à¯à®¤à®¿à®µà®¿à®Ÿà¯à®Ÿà¯ Enter விசையை à®…à®´à¯à®¤à¯à®¤à¯à®™à¯à®•à®³à¯</translation>
<translation id="320323717674993345">கடà¯à®Ÿà®£à®®à¯ செலà¯à®¤à¯à®¤à¯à®µà®¤à¯ˆ ரதà¯à®¤à¯à®šà¯†à®¯à¯</translation>
+<translation id="3203366800380907218">இணையதà¯à®¤à®¿à®²à¯ இரà¯à®¨à¯à®¤à¯</translation>
<translation id="3207960819495026254">பà¯à®•à¯à®®à®¾à®°à¯à®•à¯ செயà¯à®¯à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯</translation>
<translation id="3209034400446768650">இநà¯à®¤à®ªà¯ பகà¯à®•à®¤à¯à®¤à®¿à®±à¯à®•à¯à®šà¯ செனà¯à®±à®¾à®²à¯ கடà¯à®Ÿà®£à®®à¯ விதிகà¯à®•à®•à¯à®•à¯‚டà¯à®®à¯</translation>
<translation id="3212581601480735796"><ph name="HOSTNAME" /> இல௠உஙà¯à®•à®³à¯ செயலà¯à®ªà®¾à®Ÿà¯ கணà¯à®•à®¾à®£à®¿à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®•à®¿à®±à®¤à¯</translation>
@@ -688,7 +722,7 @@
<translation id="3223287115535306850">ஆபà¯à®¸à¯ தà¯à®µà®•à¯à®•à®¿ லோடிங௠à®à®•à®¾à®©à¯</translation>
<translation id="3225347164936328585">கைதடà¯à®Ÿà¯à®®à¯ ஈமோஜி</translation>
<translation id="3225919329040284222">உளà¯à®³à®®à¯ˆà®¨à¯à®¤ எதிரà¯à®ªà®¾à®°à¯à®ªà¯à®ªà¯à®•à®³à¯à®Ÿà®©à¯ பொரà¯à®¨à¯à®¤à®¾à®¤ சானà¯à®±à®¿à®¤à®´à¯ˆ சேவையகம௠வழஙà¯à®•à®¿à®¯à®¤à¯. சில உயரà¯-பாதà¯à®•à®¾à®ªà¯à®ªà¯ வலைதà¯à®¤à®³à®™à¯à®•à®³à®¿à®²à¯ உஙà¯à®•à®³à¯ˆà®ªà¯ பாதà¯à®•à®¾à®•à¯à®•à®µà¯‡ இநà¯à®¤ எதிரà¯à®ªà®¾à®°à¯à®ªà¯à®ªà¯à®•à®³à¯ சேரà¯à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®•à®¿à®©à¯à®±à®©.</translation>
-<translation id="3226128629678568754">பகà¯à®•à®¤à¯à®¤à¯ˆ à®à®±à¯à®± தேவைபà¯à®ªà®Ÿà¯à®®à¯ தரவை மறà¯à®®à¯à®±à¯ˆà®šà¯ சமரà¯à®ªà¯à®ªà®¿à®ªà¯à®ªà®¤à®±à¯à®•à¯ மீணà¯à®Ÿà¯à®®à¯ à®à®±à¯à®±à¯ எனà¯à®± பொதà¯à®¤à®¾à®©à¯ˆ à®…à®´à¯à®¤à¯à®¤à¯à®•.</translation>
+<translation id="3226128629678568754">பகà¯à®•à®¤à¯à®¤à¯ˆ à®à®±à¯à®± தேவைபà¯à®ªà®Ÿà¯à®®à¯ தரவை மறà¯à®®à¯à®±à¯ˆà®šà¯ சமரà¯à®ªà¯à®ªà®¿à®ªà¯à®ªà®¤à®±à¯à®•à¯ மீணà¯à®Ÿà¯à®®à¯ à®à®±à¯à®±à¯ எனà¯à®± படà¯à®Ÿà®©à¯ˆ à®…à®´à¯à®¤à¯à®¤à¯à®•.</translation>
<translation id="3226387218769101247">சிறà¯à®ªà®Ÿà®™à¯à®•à®³à¯</translation>
<translation id="3227137524299004712">மைகà¯à®°à¯‡à®¾à®ƒà®ªà¯‡à®¾à®©à¯</translation>
<translation id="3229041911291329567">உஙà¯à®•à®³à¯ சாதனம௠மறà¯à®±à¯à®®à¯ உலாவியின௠பதிபà¯à®ªà¯à®¤à¯ தகவலà¯</translation>
@@ -696,10 +730,12 @@
<translation id="3234666976984236645">இநà¯à®¤à®¤à¯ தளதà¯à®¤à®¿à®©à¯ à®®à¯à®•à¯à®•à®¿à®¯ உளà¯à®³à®Ÿà®•à¯à®•à®¤à¯à®¤à¯ˆ எபà¯à®ªà¯‹à®¤à¯à®®à¯ இயகà¯à®•à®µà¯à®®à¯</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />. உலாவியின௠தோறà¯à®±à®¤à¯à®¤à¯ˆà®ªà¯ பிரதà¯à®¤à®¿à®¯à¯‡à®•à®®à®¾à®•à¯à®•, Tab படà¯à®Ÿà®©à¯ˆ à®…à®´à¯à®¤à¯à®¤à®¿à®µà®¿à®Ÿà¯à®Ÿà¯ Enter படà¯à®Ÿà®©à¯ˆ à®…à®´à¯à®¤à¯à®¤à¯à®™à¯à®•à®³à¯</translation>
<translation id="3240791268468473923">பாதà¯à®•à®¾à®ªà¯à®ªà®¾à®© பேமெணà¯à®Ÿà¯ அனà¯à®®à®¤à®¿à®šà¯ சானà¯à®±à¯à®•à®³à¯ பொரà¯à®¨à¯à®¤à®µà®¿à®²à¯à®²à¯ˆ எனà¯à®ªà®¤à®±à¯à®•à®¾à®© தாள௠திறகà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯</translation>
+<translation id="324180406144491771">“<ph name="HOST_NAME" />†இணைபà¯à®ªà¯à®•à®³à¯ தடà¯à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®©</translation>
<translation id="3249845759089040423">கà¯à®°à¯‚வி</translation>
<translation id="3252266817569339921">பிரெஞà¯à®šà¯</translation>
<translation id="3257954757204451555">இநà¯à®¤à®¤à¯ தகவலà¯à®•à®³à¯ˆ வழஙà¯à®•à¯à®µà®¤à¯ யாரà¯?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />, Google Calendarரில௠பà¯à®¤à®¿à®¯ நிகழà¯à®µà¯ˆ விரைவாக உரà¯à®µà®¾à®•à¯à®• Tab படà¯à®Ÿà®©à¯ˆ à®…à®´à¯à®¤à¯à®¤à®¿à®µà®¿à®Ÿà¯à®Ÿà¯ Enter படà¯à®Ÿà®©à¯ˆ à®…à®´à¯à®¤à¯à®¤à¯à®™à¯à®•à®³à¯</translation>
+<translation id="3261488570342242926">விரà¯à®šà¯à®šà¯à®µà®²à¯ காரà¯à®Ÿà¯à®•à®³à¯ கà¯à®±à®¿à®¤à¯à®¤à¯ அறிக</translation>
<translation id="3264837738038045344">Chrome அமைபà¯à®ªà¯à®•à®³à¯ˆ நிரà¯à®µà®•à®¿à®•à¯à®•à¯à®®à¯ படà¯à®Ÿà®©à¯. Chrome அமைபà¯à®ªà¯à®•à®³à¯ˆà®ªà¯ பாரà¯à®•à¯à®•, Enter படà¯à®Ÿà®©à¯ˆ à®…à®´à¯à®¤à¯à®¤à¯à®™à¯à®•à®³à¯</translation>
<translation id="3266793032086590337">மதிபà¯à®ªà¯ (à®®à¯à®°à®£à¯à®ªà®¾à®Ÿà¯)</translation>
<translation id="3268451620468152448">திறநà¯à®¤ ததà¯à®¤à®²à¯à®•à®³à¯</translation>
@@ -713,6 +749,7 @@
<translation id="3288238092761586174">உஙà¯à®•à®³à¯ பேமெணà¯à®Ÿà¯à®Ÿà¯ˆ உறà¯à®¤à®¿à®ªà¯à®ªà®Ÿà¯à®¤à¯à®¤ <ph name="URL" /> தளதà¯à®¤à®¿à®²à¯ கூடà¯à®¤à®²à¯ படிகளைச௠செயà¯à®¯ வேணà¯à®Ÿà®¿à®¯à®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯</translation>
<translation id="3293642807462928945"><ph name="POLICY_NAME" /> கொளà¯à®•à¯ˆ கà¯à®±à®¿à®¤à¯à®¤à¯ மேலà¯à®®à¯ அறிக</translation>
<translation id="3295444047715739395">Chrome அமைபà¯à®ªà¯à®•à®³à®¿à®²à¯ உஙà¯à®•à®³à¯ கடவà¯à®šà¯à®šà¯Šà®±à¯à®•à®³à¯ˆà®ªà¯ பாரà¯à®¤à¯à®¤à®²à¯ &amp; நிரà¯à®µà®•à®¿à®¤à¯à®¤à®²à¯</translation>
+<translation id="3303795387212510132"><ph name="PROTOCOL_SCHEME" /> இணைபà¯à®ªà¯à®•à®³à¯ˆà®¤à¯ திறகà¯à®• ஆபà¯à®¸à¯ˆ அனà¯à®®à®¤à®¿à®•à¯à®•à®µà®¾?</translation>
<translation id="3303855915957856445">தேடல௠மà¯à®Ÿà®¿à®µà¯à®•à®³à¯ எதà¯à®µà¯à®®à®¿à®²à¯à®²à¯ˆ</translation>
<translation id="3304073249511302126">பà¯à®³à¯‚டூத௠ஸà¯à®•à¯‡à®©à®¿à®™à¯</translation>
<translation id="3308006649705061278">நிறà¯à®µà®© யூனிட௠(OU)</translation>
@@ -726,12 +763,6 @@
<translation id="3345782426586609320">கணà¯à®•à®³à¯ ஈமோஜி</translation>
<translation id="3355823806454867987">பà¯à®°à®¾à®•à¯à®¸à®¿ அமைபà¯à®ªà¯à®•à®³à¯ˆ மாறà¯à®±à¯à®•...</translation>
<translation id="3360103848165129075">பேமெணà¯à®Ÿà¯ ஹேணà¯à®Ÿà¯à®²à®°à¯ ஷீடà¯</translation>
-<translation id="3361596688432910856">பினà¯à®µà®°à¯à®®à¯ தகவலை Chrome <ph name="BEGIN_EMPHASIS" />சேமிகà¯à®•à®¾à®¤à¯<ph name="END_EMPHASIS" />:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />உலாவல௠வரலாறà¯
- <ph name="LIST_ITEM" />கà¯à®•à¯à®•à¯€à®•à®³à¯ மறà¯à®±à¯à®®à¯ தளத௠தரவà¯
- <ph name="LIST_ITEM" />படிவஙà¯à®•à®³à®¿à®²à¯ உளà¯à®³à®¿à®Ÿà¯à®®à¯ தகவலà¯
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">தடà¯à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³ <ph name="OLD_POLICY" /> கொளà¯à®•à¯ˆà®¯à®¿à®²à¯ இரà¯à®¨à¯à®¤à¯ இத௠தானாகவே நகலெடà¯à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯. மாறாக இநà¯à®¤à®•à¯ கொளà¯à®•à¯ˆà®¯à¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤ வேணà¯à®Ÿà¯à®®à¯.</translation>
<translation id="3364869320075768271"><ph name="URL" /> உஙà¯à®•à®³à¯ விரà¯à®šà¯à®šà¯à®µà®²à¯ ரியாலிடà¯à®Ÿà®¿ சாதனதà¯à®¤à¯ˆà®¯à¯à®®à¯ தரவையà¯à®®à¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤ விரà¯à®®à¯à®ªà¯à®•à®¿à®±à®¤à¯</translation>
<translation id="3366477098757335611">காரà¯à®Ÿà¯à®•à®³à¯ˆà®•à¯ காடà¯à®Ÿà¯</translation>
@@ -757,7 +788,7 @@
<translation id="3405664148539009465">எழà¯à®¤à¯à®¤à¯à®°à¯à®•à¯à®•à®³à¯ˆà®ªà¯ பிரதà¯à®¤à®¿à®¯à¯‡à®•à®®à®¾à®•à¯à®•à¯</translation>
<translation id="3409896703495473338">பாதà¯à®•à®¾à®ªà¯à®ªà¯ அமைபà¯à®ªà¯à®•à®³à¯ˆ நிரà¯à®µà®•à®¿à®¯à¯à®™à¯à®•à®³à¯</translation>
<translation id="3414952576877147120">அளவà¯:</translation>
-<translation id="3417660076059365994">நீஙà¯à®•à®³à¯ பதிவேறà¯à®±à¯à®®à¯/இணைகà¯à®•à¯à®®à¯ ஃபைலà¯à®•à®³à¯ Google கிளவà¯à®Ÿà¯à®•à¯à®•à¯‹ மூனà¯à®±à®¾à®®à¯ தரபà¯à®ªà®¿à®©à®°à¯à®•à¯à®•à¯‹ ஆயà¯à®µà¯à®•à¯à®•à®¾à®• அனà¯à®ªà¯à®ªà®ªà¯à®ªà®Ÿà¯à®®à¯. எடà¯à®¤à¯à®¤à¯à®•à¯à®•à®¾à®Ÿà¯à®Ÿà®¾à®•, பாதà¯à®•à®¾à®•à¯à®• வேணà¯à®Ÿà®¿à®¯ தரவோ மாலà¯à®µà¯‡à®°à¯‹ உளà¯à®³à®¤à®¾ எனà¯à®±à¯ கணà¯à®Ÿà®±à®¿à®µà®¤à®±à¯à®•à®¾à®• அவை ஸà¯à®•à¯‡à®©à¯ செயà¯à®¯à®ªà¯à®ªà®Ÿà®²à®¾à®®à¯.</translation>
+<translation id="3417660076059365994">நீஙà¯à®•à®³à¯ பதிவேறà¯à®±à¯à®®à¯/இணைகà¯à®•à¯à®®à¯ ஃபைலà¯à®•à®³à¯ Google கிளவà¯à®Ÿà¯à®•à¯à®•à¯‹ மூனà¯à®±à®¾à®®à¯ தரபà¯à®ªà®¿à®©à®°à¯à®•à¯à®•à¯‹ ஆயà¯à®µà¯à®•à¯à®•à®¾à®• அனà¯à®ªà¯à®ªà®ªà¯à®ªà®Ÿà¯à®®à¯. எடà¯à®¤à¯à®¤à¯à®•à¯à®•à®¾à®Ÿà¯à®Ÿà®¾à®•, பாதà¯à®•à®¾à®•à¯à®•à®ªà¯à®ªà®Ÿ வேணà¯à®Ÿà®¿à®¯ தனிபà¯à®ªà®Ÿà¯à®Ÿ தரவோ மாலà¯à®µà¯‡à®°à¯‹ உளà¯à®³à®¤à®¾ எனà¯à®±à¯ கணà¯à®Ÿà®±à®¿à®µà®¤à®±à¯à®•à®¾à®• அவை ஸà¯à®•à¯‡à®©à¯ செயà¯à®¯à®ªà¯à®ªà®Ÿà®²à®¾à®®à¯.</translation>
<translation id="3422248202833853650">பிற நிரலà¯à®•à®³à®¿à®²à®¿à®°à¯à®¨à¯à®¤à¯ வெளியேறி, நினைவகதà¯à®¤à¯ˆà®•à¯ காலியாகà¯à®•à®µà¯à®®à¯.</translation>
<translation id="3422472998109090673"><ph name="HOST_NAME" />à®à®¤à¯ தறà¯à®ªà¯‹à®¤à¯ அணà¯à®• à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ.</translation>
<translation id="3423742043356668186">சிஸà¯à®Ÿà®®à¯ அமைதà¯à®¤à®¤à¯</translation>
@@ -813,7 +844,6 @@
<translation id="3587738293690942763">நடà¯à®µà®¿à®²à¯à®³à¯à®³à®¤à¯</translation>
<translation id="3592413004129370115">Italian (எனà¯à®µà®²à®ªà¯)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{எபà¯à®ªà¯‹à®¤à¯ வேணà¯à®Ÿà¯à®®à®¾à®©à®¾à®²à¯à®®à¯ உஙà¯à®•à®³à¯ கà¯à®´à¯à®µà¯ˆ மீடà¯à®Ÿà®®à¯ˆà®•à¯à®•à®²à®¾à®®à¯. பà¯à®¤à®¿à®¯ கà¯à®´à¯à®µà®¿à®²à¯ சேர ஒர௠நாள௠ஆகà¯à®®à¯.}=1{எபà¯à®ªà¯‹à®¤à¯ வேணà¯à®Ÿà¯à®®à®¾à®©à®¾à®²à¯à®®à¯ உஙà¯à®•à®³à¯ கà¯à®´à¯à®µà¯ˆ மீடà¯à®Ÿà®®à¯ˆà®•à¯à®•à®²à®¾à®®à¯. பà¯à®¤à®¿à®¯ கà¯à®´à¯à®µà®¿à®²à¯ சேர ஒர௠நாள௠ஆகà¯à®®à¯.}other{எபà¯à®ªà¯‹à®¤à¯ வேணà¯à®Ÿà¯à®®à®¾à®©à®¾à®²à¯à®®à¯ உஙà¯à®•à®³à¯ கà¯à®´à¯à®µà¯ˆ மீடà¯à®Ÿà®®à¯ˆà®•à¯à®•à®²à®¾à®®à¯. பà¯à®¤à®¿à®¯ கà¯à®´à¯à®µà®¿à®²à¯ சேர {NUM_DAYS} நாடà¯à®•à®³à¯ ஆகà¯à®®à¯.}}</translation>
-<translation id="3596012367874587041">ஆபà¯à®¸à¯ அமைபà¯à®ªà¯à®•à®³à¯</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">உஙà¯à®•à®³à¯ நிரà¯à®µà®¾à®•à®¿ ஆபà¯à®¸à¯ˆà®¤à¯ தடà¯à®¤à¯à®¤à¯à®³à¯à®³à®¾à®°à¯</translation>
<translation id="3608932978122581043">உடà¯à®šà¯†à®²à¯à®¤à¯à®¤à¯à®®à¯ திசையமைபà¯à®ªà¯</translation>
@@ -856,6 +886,7 @@
<translation id="370972442370243704">‘கà¯à®±à®¿à®ªà¯à®ªà®¿à®Ÿà¯à®Ÿ தேடல௠விவரஙà¯à®•à®³à¯â€™ à®…à®®à¯à®šà®¤à¯à®¤à¯ˆ இயகà¯à®•à¯</translation>
<translation id="3711895659073496551">இடைநிறà¯à®¤à¯à®¤à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯</translation>
<translation id="3712624925041724820">உரிமம௠மà¯à®Ÿà®¿à®¨à¯à®¤à®¤à¯</translation>
+<translation id="3714633008798122362">வலை காலெணà¯à®Ÿà®°à¯</translation>
<translation id="3714780639079136834">மொபைல௠டேடà¯à®Ÿà®¾ அலà¯à®²à®¤à¯ வைஃபையை இயகà¯à®•à¯à®¤à®²à¯</translation>
<translation id="3715597595485130451">வைஃபையà¯à®Ÿà®©à¯ இணைதà¯à®¤à®²à¯</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />பà¯à®°à®¾à®•à¯à®¸à®¿, ஃபயரà¯à®µà®¾à®²à¯ மறà¯à®±à¯à®®à¯ DNS உளà¯à®³à®®à¯ˆà®µà¯ˆà®šà¯ சரிபாரà¯à®¤à¯à®¤à®²à¯<ph name="END_LINK" /></translation>
@@ -917,6 +948,7 @@
<translation id="3906954721959377182">டேபà¯à®²à¯†à®Ÿà¯</translation>
<translation id="3909477809443608991">பாதà¯à®•à®¾à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿ உளà¯à®³à®Ÿà®•à¯à®•à®¤à¯à®¤à¯ˆ <ph name="URL" /> இயகà¯à®• விரà¯à®®à¯à®ªà¯à®•à®¿à®±à®¤à¯. உஙà¯à®•à®³à¯ சாதனதà¯à®¤à®¿à®©à¯ அடையாளதà¯à®¤à¯ˆ Google சரிபாரà¯à®•à¯à®•à¯à®®à¯, சாதன அடையாளதà¯à®¤à¯ˆ இநà¯à®¤à®¤à¯ தளம௠அணà¯à®•à®•à¯à®•à¯‚டà¯à®®à¯.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">மறà¯</translation>
<translation id="3939773374150895049">CVCகà¯à®•à¯ பதிலாக WebAuthnனைப௠பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®µà®¾?</translation>
<translation id="3946209740501886391">இநà¯à®¤à®¤à¯ தளதà¯à®¤à®¿à®²à¯ எபà¯à®ªà¯‹à®¤à¯à®®à¯ கேளà¯</translation>
<translation id="3947595700203588284">MIDI சாதனஙà¯à®•à®³à¯à®Ÿà®©à¯ இணைய à®®à¯à®¯à®²à¯à®®à¯à®ªà¯‹à®¤à¯ அனà¯à®®à®¤à®¿ கேடà¯à®• வேணà¯à®Ÿà¯à®®à¯</translation>
@@ -938,6 +970,7 @@
<translation id="3990250421422698716">ஜாக௠ஆஃபà¯à®šà¯†à®Ÿà¯</translation>
<translation id="3996311196211510766"><ph name="ORIGIN" /> தளமà¯, அதறà¯à®•à®¾à®© அனைதà¯à®¤à¯à®•à¯ கோரிகà¯à®•à¯ˆà®•à®³à¯à®•à¯à®•à¯à®®à¯
அசல௠கொளà¯à®•à¯ˆà®¯à¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤ வேணà¯à®Ÿà¯à®®à¯†à®©à®•à¯ கோரிகà¯à®•à¯ˆ விடà¯à®¤à¯à®¤à¯à®³à¯à®³à®¤à¯, ஆனால௠தறà¯à®šà®®à®¯à®®à¯ அதைச௠செயà¯à®¯ à®®à¯à®Ÿà®¿à®¯à®¾à®¤à¯.</translation>
+<translation id="4009243425692662128">நீஙà¯à®•à®³à¯ அசà¯à®šà®¿à®Ÿà¯à®®à¯ பகà¯à®•à®™à¯à®•à®³à®¿à®²à¯ உளà¯à®³ உளà¯à®³à®Ÿà®•à¯à®•à®®à¯ பகà¯à®ªà¯à®ªà®¾à®¯à¯à®µà®¿à®±à¯à®•à®¾à®• Google Cloud அலà¯à®²à®¤à¯ மூனà¯à®±à®¾à®®à¯ தரபà¯à®ªà®¿à®©à®°à¯à®•à¯à®•à¯ அனà¯à®ªà¯à®ªà®ªà¯à®ªà®Ÿà¯à®®à¯. எடà¯à®¤à¯à®¤à¯à®•à¯à®•à®¾à®Ÿà¯à®Ÿà®¾à®•, பாதà¯à®•à®¾à®•à¯à®•à®ªà¯à®ªà®Ÿ வேணà¯à®Ÿà®¿à®¯ தனிபà¯à®ªà®Ÿà¯à®Ÿ தரவ௠உளà¯à®³à®¤à®¾ எனக௠கணà¯à®Ÿà®±à®¿à®µà®¤à®±à¯à®•à®¾à®• அத௠ஸà¯à®•à¯‡à®©à¯ செயà¯à®¯à®ªà¯à®ªà®Ÿà®²à®¾à®®à¯.</translation>
<translation id="4010758435855888356">சேமிபà¯à®ªà®• அணà¯à®•à®²à¯ˆ வழஙà¯à®•à®µà®¾?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{{COUNT} பகà¯à®•à®¤à¯à®¤à¯ˆà®•à¯ கொணà¯à®Ÿ PDF ஆவணமà¯}other{{COUNT} பகà¯à®•à®™à¯à®•à®³à¯ˆà®•à¯ கொணà¯à®Ÿ PDF ஆவணமà¯}}</translation>
<translation id="4023431997072828269">பாதà¯à®•à®¾à®ªà¯à®ªà®±à¯à®± இணைபà¯à®ªà¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®¿ இநà¯à®¤à®ªà¯ படிவம௠சமரà¯à®ªà¯à®ªà®¿à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®µà®¤à®¾à®²à¯ உஙà¯à®•à®³à¯ தகவலà¯à®•à®³à¯ˆà®ªà¯ பிறரால௠பாரà¯à®•à¯à®• à®®à¯à®Ÿà®¿à®¯à¯à®®à¯.</translation>
@@ -1032,6 +1065,7 @@
<translation id="4250680216510889253">இலà¯à®²à¯ˆ</translation>
<translation id="4253168017788158739">கà¯à®±à®¿à®ªà¯à®ªà¯</translation>
<translation id="425582637250725228">உஙà¯à®•à®³à¯ மாறà¯à®±à®™à¯à®•à®³à¯ சேமிகà¯à®•à®ªà¯à®ªà®Ÿà®¾à®®à®²à¯ இரà¯à®•à¯à®•à®²à®¾à®®à¯.</translation>
+<translation id="425869179292622354">விரà¯à®šà¯à®šà¯à®µà®²à¯ காரà¯à®Ÿà¯ மூலம௠இதை மேலà¯à®®à¯ பாதà¯à®•à®¾à®ªà¯à®ªà®¾à®©à®¤à®¾à®•à¯à®• வேணà¯à®Ÿà¯à®®à®¾?</translation>
<translation id="4258748452823770588">தவறான கையொபà¯à®ªà®®à¯</translation>
<translation id="4261046003697461417">பாதà¯à®•à®¾à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿ ஆவணஙà¯à®•à®³à®¿à®²à¯ விரிவà¯à®°à¯ˆà®¯à¯ˆà®šà¯ சேரà¯à®•à¯à®• à®®à¯à®Ÿà®¿à®¯à®¾à®¤à¯</translation>
<translation id="4265872034478892965">உஙà¯à®•à®³à¯ நிரà¯à®µà®¾à®•à®¿ அனà¯à®®à®¤à®¿à®¤à¯à®¤à®¾à®°à¯</translation>
@@ -1094,6 +1128,7 @@
<translation id="4434045419905280838">பாபà¯-அபà¯à®•à®³à¯ &amp; திசைதிரà¯à®ªà¯à®ªà¯à®¤à®²à¯à®•à®³à¯</translation>
<translation id="4435702339979719576">Postcard)</translation>
<translation id="443673843213245140">பà¯à®°à®¾à®•à¯à®¸à®¿ பயனà¯à®ªà®¾à®Ÿà¯ à®®à¯à®Ÿà®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯. ஆனால௠வெளிபà¯à®ªà®Ÿà¯ˆà®¯à®¾à®© பà¯à®°à®¾à®•à¯à®¸à®¿ உளà¯à®³à®®à¯ˆà®µà¯ கà¯à®±à®¿à®ªà¯à®ªà®¿à®Ÿà®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯.</translation>
+<translation id="4441832193888514600">கிளவà¯à®Ÿà¯ பயனர௠கொளà¯à®•à¯ˆà®¯à®¾à®• மடà¯à®Ÿà¯à®®à¯‡ கொளà¯à®•à¯ˆà®¯à¯ˆ அமைகà¯à®• à®®à¯à®Ÿà®¿à®¯à¯à®®à¯†à®©à¯à®ªà®¤à®¾à®²à¯ பà¯à®±à®•à¯à®•à®£à®¿à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯.</translation>
<translation id="4450893287417543264">மீணà¯à®Ÿà¯à®®à¯ காடà¯à®Ÿà®¾à®¤à¯‡</translation>
<translation id="4451135742916150903">HID சாதனஙà¯à®•à®³à¯à®Ÿà®©à¯ இணைய à®®à¯à®¯à®²à¯à®®à¯à®ªà¯‹à®¤à¯ அனà¯à®®à®¤à®¿ கேடà¯à®• வேணà¯à®Ÿà¯à®®à¯</translation>
<translation id="4452328064229197696">நீஙà¯à®•à®³à¯ தறà¯à®ªà¯‹à®¤à¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®¿à®¯ கடவà¯à®šà¯à®šà¯Šà®²à¯, தரவ௠மீறலà¯à®•à¯à®•à¯ உடà¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®ªà¯à®ªà®¤à®¾à®•à®•à¯ கணà¯à®Ÿà®±à®¿à®¯à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯. உஙà¯à®•à®³à¯ கணகà¯à®•à¯à®•à®³à¯ˆà®ªà¯ பாதà¯à®•à®¾à®ªà¯à®ªà®¾à®• வைதà¯à®¤à®¿à®°à¯à®•à¯à®•, சேமிதà¯à®¤ கடவà¯à®šà¯à®šà¯Šà®±à¯à®•à®³à¯ˆà®šà¯ சரிபாரà¯à®•à¯à®•à¯à®®à®¾à®±à¯ Googleளின௠கடவà¯à®šà¯à®šà¯Šà®²à¯ நிரà¯à®µà®¾à®•à®¿ பரிநà¯à®¤à¯à®°à¯ˆà®•à¯à®•à®¿à®±à®¤à¯.</translation>
@@ -1149,6 +1184,7 @@
<translation id="4628948037717959914">படமà¯</translation>
<translation id="4631649115723685955">கேஷà¯à®ªà¯‡à®•à¯ ஆஃபர௠உளà¯à®³à®¤à¯</translation>
<translation id="4636930964841734540">தகவலà¯</translation>
+<translation id="4638670630777875591">Chromium மறைநிலைப௠பயனà¯à®®à¯à®±à¯ˆ</translation>
<translation id="464342062220857295">தேடல௠அமà¯à®šà®™à¯à®•à®³à¯</translation>
<translation id="4644670975240021822">பினà¯à®©à¯‹à®•à¯à®•à®¿à®¯ வரிசையில௠கீழà¯à®¨à¯‹à®•à¯à®•à®¿à®¯ பாணி</translation>
<translation id="4646534391647090355">à®…à®™à¯à®•à¯‡ செலà¯</translation>
@@ -1169,6 +1205,7 @@
<translation id="4708268264240856090">உஙà¯à®•à®³à¯ இணைபà¯à®ªà®¿à®²à¯ தடஙà¯à®•à®²à¯ à®à®±à¯à®ªà®Ÿà¯à®Ÿà®¤à¯</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Windows நெடà¯à®µà¯Šà®°à¯à®•à¯ டயகà¯à®©à®¾à®¸à¯à®Ÿà®¿à®•à¯à®¸à¯ கரà¯à®µà®¿à®¯à¯ˆ இயகà¯à®•à®µà¯à®®à¯<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426"><ph name="USERNAME" /> இன௠கடவà¯à®šà¯à®šà¯Šà®²à¯</translation>
<translation id="4724144314178270921">கிளிபà¯à®ªà¯‹à®°à¯à®Ÿà®¿à®²à¯ உளà¯à®³ உளà¯à®³à®Ÿà®•à¯à®•à®¤à¯à®¤à¯ˆà®¯à¯à®®à¯ படஙà¯à®•à®³à¯ˆà®¯à¯à®®à¯ பாரà¯à®•à¯à®• à®®à¯à®¯à®²à¯à®®à¯à®ªà¯‹à®¤à¯ அனà¯à®®à®¤à®¿ கேடà¯à®• வேணà¯à®Ÿà¯à®®à¯</translation>
<translation id="4726672564094551039">கொளà¯à®•à¯ˆà®•à®³à¯ˆ மீணà¯à®Ÿà¯à®®à¯ à®à®±à¯à®±à¯</translation>
<translation id="4728558894243024398">பà¯à®³à®¾à®Ÿà¯à®ƒà®ªà®¾à®°à¯à®®à¯</translation>
@@ -1190,6 +1227,7 @@
<translation id="4757993714154412917">à®à®®à®¾à®±à¯à®±à®•à¯à®•à¯‚டிய தளதà¯à®¤à®¿à®²à¯ கடவà¯à®šà¯à®šà¯Šà®²à¯à®²à¯ˆ உளà¯à®³à®¿à®Ÿà¯à®Ÿà¯à®³à¯à®³à¯€à®°à¯à®•à®³à¯. உஙà¯à®•à®³à¯ கணகà¯à®•à¯à®•à®³à¯ˆà®ªà¯ பாதà¯à®•à®¾à®•à¯à®•, நீஙà¯à®•à®³à¯ சேமிதà¯à®¤à¯à®³à¯à®³ கடவà¯à®šà¯à®šà¯Šà®±à¯à®•à®³à¯ˆà®šà¯ சரிபாரà¯à®•à¯à®•à¯à®®à®¾à®±à¯ Chromium பரிநà¯à®¤à¯à®°à¯ˆà®•à¯à®•à®¿à®±à®¤à¯.</translation>
<translation id="4758311279753947758">தொடரà¯à®ªà¯à®¤à¯ தகவலைச௠சேரà¯</translation>
<translation id="4761104368405085019">உஙà¯à®•à®³à¯ மைகà¯à®°à¯‹à®ƒà®ªà¯‹à®©à¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®²à®¾à®®à¯</translation>
+<translation id="4761869838909035636">Chrome பாதà¯à®•à®¾à®ªà¯à®ªà¯à®šà¯ சரிபாரà¯à®ªà¯à®ªà¯ˆ இயகà¯à®•à¯</translation>
<translation id="4764776831041365478"><ph name="URL" /> இல௠உளà¯à®³ வலைபà¯à®ªà®•à¯à®•à®®à®¾à®©à®¤à¯ தறà¯à®•à®¾à®²à®¿à®•à®®à®¾à®• இயஙà¯à®•à®¾à®®à®²à¯ இரà¯à®•à¯à®•à®²à®¾à®®à¯ அலà¯à®²à®¤à¯ அத௠ஒர௠பà¯à®¤à®¿à®¯ வலை à®®à¯à®•à®µà®°à®¿à®•à¯à®•à¯ நிரநà¯à®¤à®°à®®à®¾à®• நகரà¯à®¤à¯à®¤à®ªà¯à®ªà®Ÿà¯à®Ÿà®¿à®°à¯à®•à¯à®•à®²à®¾à®®à¯.</translation>
<translation id="4766713847338118463">டூயல௠ஸà¯à®Ÿà¯‡à®ªà¯à®ªà®¿à®²à¯ பாடà¯à®Ÿà®®à¯</translation>
<translation id="4771973620359291008">அறியபà¯à®ªà®Ÿà®¾à®¤ பிழை à®à®±à¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯.</translation>
@@ -1210,12 +1248,6 @@
<translation id="4819347708020428563">இயலà¯à®ªà¯à®•à¯ காடà¯à®šà®¿à®¯à®¿à®²à¯ விரிவà¯à®°à¯ˆà®•à®³à¯ˆà®¤à¯ திரà¯à®¤à¯à®¤à®µà®¾?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />, Google விரிதாளை விரைவாக உரà¯à®µà®¾à®•à¯à®• Tab படà¯à®Ÿà®©à¯ˆ à®…à®´à¯à®¤à¯à®¤à®¿à®µà®¿à®Ÿà¯à®Ÿà¯ Enter படà¯à®Ÿà®©à¯ˆ à®…à®´à¯à®¤à¯à®¤à¯à®™à¯à®•à®³à¯</translation>
<translation id="4825507807291741242">பவரà¯à®ƒà®ªà¯à®²à¯</translation>
-<translation id="4827402517081186284">மறைநிலையில௠உலாவà¯à®®à¯à®ªà¯‹à®¤à¯ ஆனà¯à®²à¯ˆà®©à®¿à®²à¯ உஙà¯à®•à®³à¯ அடையாளம௠மறைகà¯à®•à®ªà¯à®ªà®Ÿà®¾à®¤à¯:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />நீஙà¯à®•à®³à¯à®¤à®¾à®©à¯ பாரà¯à®µà¯ˆà®¯à®¿à®Ÿà¯à®•à®¿à®±à¯€à®°à¯à®•à®³à¯ எனà¯à®ªà®¤à¯ˆà®¤à¯ தளஙà¯à®•à®³à®¾à®²à¯ அறிய à®®à¯à®Ÿà®¿à®¯à¯à®®à¯<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />நிறà¯à®µà®©à®™à¯à®•à®³à¯ அலà¯à®²à®¤à¯ பளà¯à®³à®¿à®•à®³à®¾à®²à¯ உஙà¯à®•à®³à¯ உலாவல௠செயலà¯à®ªà®¾à®Ÿà¯à®Ÿà¯ˆà®•à¯ கணà¯à®•à®¾à®£à®¿à®•à¯à®• à®®à¯à®Ÿà®¿à®¯à¯à®®à¯<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />இணைய டிராஃபிகà¯à®•à¯ˆ இணையச௠சேவை வழஙà¯à®•à¯à®¨à®°à¯à®•à®³à¯ கணà¯à®•à®¾à®£à®¿à®•à¯à®•à®•à¯à®•à¯‚டà¯à®®à¯<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">எசà¯à®šà®°à®¿à®•à¯à®•à¯ˆà®•à®³à¯ˆ இயகà¯à®•à¯</translation>
<translation id="4838327282952368871">டà¯à®°à¯€à®®à®¿</translation>
<translation id="4840250757394056958">எனத௠Chrome செயலà¯à®ªà®¾à®Ÿà¯à®•à®³à¯ˆà®•à¯ காடà¯à®Ÿà¯</translation>
@@ -1227,12 +1259,12 @@
<translation id="4854362297993841467">இநà¯à®¤ டெலிவரி à®®à¯à®±à¯ˆ இலà¯à®²à¯ˆ. வேற௠மà¯à®±à¯ˆà®¯à¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®¿à®ªà¯ பாரà¯à®•à¯à®•à®µà¯à®®à¯.</translation>
<translation id="4854853140771946034">Google Keepபில௠பà¯à®¤à®¿à®¯ கà¯à®±à®¿à®ªà¯à®ªà¯ˆ விரைவாக உரà¯à®µà®¾à®•à¯à®•à¯à®®à¯</translation>
<translation id="485902285759009870">கà¯à®±à®¿à®¯à¯€à®Ÿà¯à®Ÿà¯ˆà®šà¯ சரிபாரà¯à®•à¯à®•à®¿à®±à®¤à¯...</translation>
+<translation id="4866506163384898554">கரà¯à®šà®°à¯ˆà®•à¯ காடà¯à®Ÿ, |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| படà¯à®Ÿà®©à¯à®•à®³à¯ˆ à®…à®´à¯à®¤à¯à®¤à®µà¯à®®à¯</translation>
<translation id="4876188919622883022">எளிதாகà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿ காடà¯à®šà®¿</translation>
<translation id="4876305945144899064">பயனரà¯à®ªà¯†à®¯à®°à¯ இலà¯à®²à¯ˆ</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{எதà¯à®µà¯à®®à®¿à®²à¯à®²à¯ˆ}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831">'<ph name="TEXT" />’ கà¯à®±à®¿à®¤à¯à®¤ தேடலà¯</translation>
<translation id="4879491255372875719">தானியஙà¯à®•à¯ (இயலà¯à®ªà¯)</translation>
-<translation id="4879725228911483934">உஙà¯à®•à®³à¯ திரைகளில௠சாளரஙà¯à®•à®³à¯ˆà®¤à¯ திறநà¯à®¤à¯ வைகà¯à®•</translation>
<translation id="4880827082731008257">தேடல௠வரலாறà¯</translation>
<translation id="4881695831933465202">திற</translation>
<translation id="4885256590493466218">செகà¯-அவà¯à®Ÿà¯à®Ÿà®¿à®©à¯à®ªà¯‹à®¤à¯ <ph name="CARD_DETAIL" /> காரà¯à®Ÿà¯ மூலம௠பணம௠செலà¯à®¤à¯à®¤à®²à®¾à®®à¯</translation>
@@ -1241,6 +1273,7 @@
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">ரோல௠9</translation>
<translation id="4901778704868714008">சேமி...</translation>
+<translation id="4905659621780993806">உஙà¯à®•à®³à¯ நிரà¯à®µà®¾à®•à®¿ <ph name="DATE" />, <ph name="TIME" />கà¯à®•à¯à®¤à¯ தானாகவே உஙà¯à®•à®³à¯ சாதனதà¯à®¤à¯ˆ மீணà¯à®Ÿà¯à®®à¯ தொடஙà¯à®•à¯à®µà®¾à®°à¯. நீஙà¯à®•à®³à¯ திறநà¯à®¤à®¿à®°à¯à®ªà¯à®ªà®µà®±à¯à®±à¯ˆà®šà¯ சாதனம௠மீணà¯à®Ÿà¯à®®à¯ தொடஙà¯à®•à¯à®µà®¤à®±à¯à®•à¯ à®®à¯à®©à¯ சேமிகà¯à®•à®µà¯à®®à¯.</translation>
<translation id="4913987521957242411">பஞà¯à®šà¯ டாப௠லெஃபà¯à®Ÿà¯</translation>
<translation id="4918221908152712722"><ph name="APP_NAME" />஠நிறà¯à®µà¯ (பதிவிறகà¯à®• வேணà¯à®Ÿà®¿à®¯à®¤à®¿à®²à¯à®²à¯ˆ)</translation>
<translation id="4923459931733593730">கடà¯à®Ÿà®£ à®®à¯à®±à¯ˆ</translation>
@@ -1249,6 +1282,7 @@
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, தேட Tab விசையை à®…à®´à¯à®¤à¯à®¤à®¿à®¯ பிறக௠Enter விசையை à®…à®´à¯à®¤à¯à®¤à¯à®™à¯à®•à®³à¯</translation>
<translation id="4930153903256238152">அதிக கொளà¯à®³à®³à®µà¯</translation>
+<translation id="4940163644868678279">Chrome மறைநிலைப௠பயனà¯à®®à¯à®±à¯ˆ</translation>
<translation id="4943872375798546930">à®®à¯à®Ÿà®¿à®µà¯à®•à®³à¯ இலà¯à®²à¯ˆ</translation>
<translation id="4950898438188848926"><ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /> தாவலைத௠திறகà¯à®•, ‘தாவலà¯â€™ மாறà¯à®± படà¯à®Ÿà®©à¯ˆà®¤à¯ தடà¯à®Ÿà®¿, ‘எணà¯à®Ÿà®°à¯â€™ படà¯à®Ÿà®©à¯ˆ à®…à®´à¯à®¤à¯à®¤à®µà¯à®®à¯</translation>
<translation id="495170559598752135">செயலà¯à®•à®³à¯</translation>
@@ -1258,6 +1292,7 @@
<translation id="4968522289500246572">மொபைல௠சாதனஙà¯à®•à®³à¯à®•à¯à®•à®¾à®• இநà¯à®¤ ஆபà¯à®¸à¯ வடிவமைகà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à®¾à®²à¯ இதன௠அளவைச௠சரியாக மாறà¯à®± à®®à¯à®Ÿà®¿à®¯à®¾à®®à®²à¯ போகலாமà¯. அதà¯à®¤à¯à®Ÿà®©à¯ இதில௠சிகà¯à®•à®²à¯à®•à®³à¯ à®à®±à¯à®ªà®Ÿà®²à®¾à®®à¯ அலà¯à®²à®¤à¯ இத௠மீணà¯à®Ÿà¯à®®à¯ தொடஙà¯à®•à®²à®¾à®®à¯.</translation>
<translation id="4969341057194253438">ரெகà¯à®•à®¾à®°à¯à®Ÿà®¿à®™à¯à®•à¯ˆ நீகà¯à®•à¯</translation>
<translation id="4973922308112707173">டூயல௠பஞà¯à®šà¯ டாபà¯</translation>
+<translation id="4976702386844183910">கடைசியாகப௠பாரà¯à®¤à¯à®¤à®¤à¯: <ph name="DATE" /></translation>
<translation id="4984088539114770594">மைகà¯à®°à¯‹à®ƒà®ªà¯‹à®©à¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®µà®¾?</translation>
<translation id="4984339528288761049">Prc5 (எனà¯à®µà®²à®ªà¯)</translation>
<translation id="4989163558385430922">எலà¯à®²à®¾à®®à¯ காடà¯à®Ÿà¯</translation>
@@ -1319,6 +1354,7 @@
<translation id="5138227688689900538">கà¯à®±à¯ˆà®µà®¾à®•à®•à¯ காடà¯à®Ÿà¯</translation>
<translation id="5145883236150621069">கொளà¯à®•à¯ˆà®ªà¯ பதிலில௠பிழைக௠கà¯à®±à®¿à®¯à¯€à®Ÿà¯ உளà¯à®³à®¤à¯</translation>
<translation id="5146995429444047494"><ph name="ORIGIN" /> இணையதளதà¯à®¤à®¿à®±à¯à®•à®¾à®© அறிவிபà¯à®ªà¯à®•à®³à¯ தடà¯à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®©</translation>
+<translation id="514704532284964975">உஙà¯à®•à®³à¯ ஃபோன௠மூலம௠தடà¯à®Ÿà¯à®®à¯ NFC சாதனஙà¯à®•à®³à®¿à®©à¯ தகவலà¯à®•à®³à¯ˆà®ªà¯ பாரà¯à®•à¯à®•à®µà¯à®®à¯ மாறà¯à®±à®µà¯à®®à¯ <ph name="URL" /> அனà¯à®®à®¤à®¿ கோரà¯à®•à®¿à®±à®¤à¯</translation>
<translation id="5148809049217731050">மேல௠நோகà¯à®•à®¿à®¯à®¤à¯</translation>
<translation id="515292512908731282">C4 (எனà¯à®µà®²à®ªà¯)</translation>
<translation id="5158275234811857234">அடà¯à®Ÿà¯ˆ</translation>
@@ -1343,6 +1379,7 @@
<translation id="5215116848420601511">Google Payவைப௠பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à¯à®®à¯ கடà¯à®Ÿà®£ à®®à¯à®±à¯ˆà®•à®³à¯à®®à¯ à®®à¯à®•à®µà®°à®¿à®•à®³à¯à®®à¯</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">டிரே 13</translation>
+<translation id="5216942107514965959">கடைசியாகப௠பாரà¯à®¤à¯à®¤à®¤à¯: இனà¯à®±à¯</translation>
<translation id="5222812217790122047">மினà¯à®©à®žà¯à®šà®²à¯ தேவை</translation>
<translation id="5230733896359313003">ஷிபà¯à®ªà®¿à®™à¯ à®®à¯à®•à®µà®°à®¿</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1363,7 +1400,6 @@
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">ஆவண விவரஙà¯à®•à®³à¯</translation>
<translation id="528468243742722775">நிறà¯à®¤à¯à®¤à¯</translation>
-<translation id="5284909709419567258">நெடà¯à®µà¯Šà®°à¯à®•à¯ à®®à¯à®•à®µà®°à®¿à®•à®³à¯</translation>
<translation id="5285570108065881030">சேமிதà¯à®¤ எலà¯à®²à®¾à®•à¯ கடவà¯à®šà¯à®šà¯Šà®±à¯à®•à®³à¯ˆà®¯à¯à®®à¯ காடà¯à®Ÿà¯</translation>
<translation id="5287240709317226393">கà¯à®•à¯à®•à¯€à®•à®³à¯ˆà®•à¯ காடà¯à®Ÿà¯à®®à¯</translation>
<translation id="5287456746628258573">இநà¯à®¤à®¤à¯ தளம௠காலாவதியான பாதà¯à®•à®¾à®ªà¯à®ªà¯ உளà¯à®³à®®à¯ˆà®µà¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à¯à®•à®¿à®±à®¤à¯, உஙà¯à®•à®³à¯ கடவà¯à®šà¯à®šà¯Šà®±à¯à®•à®³à¯, கிரெடிட௠காரà¯à®Ÿà¯ எணà¯à®•à®³à¯ போனà¯à®±à®µà®±à¯à®±à¯ˆ இதà¯à®¤à®³à®¤à¯à®¤à®¿à®±à¯à®•à¯ அனà¯à®ªà¯à®ªà®¿à®©à®¾à®²à¯ மறà¯à®±à®µà®°à¯à®•à®³à¯ அநà¯à®¤à®¤à¯ தகவலà¯à®•à®³à¯ˆà®¤à¯ தெரிநà¯à®¤à¯à®•à¯Šà®³à¯à®³à®•à¯à®•à¯‚டà¯à®®à¯.</translation>
@@ -1447,6 +1483,7 @@
<translation id="5556459405103347317">மீணà¯à®Ÿà¯à®®à¯ à®à®±à¯à®±à¯</translation>
<translation id="5560088892362098740">காலாவதியாகà¯à®®à¯ தேதி</translation>
<translation id="55635442646131152">ஆவணதà¯à®¤à®¿à®©à¯ மேலோடà¯à®Ÿà®®à¯</translation>
+<translation id="5565613213060953222">மறைநிலைப௠பகà¯à®•à®¤à¯à®¤à¯ˆà®¤à¯ திற</translation>
<translation id="5565735124758917034">செயலில௠உளà¯à®³à®¤à¯</translation>
<translation id="5570825185877910964">கணகà¯à®•à¯ˆà®ªà¯ பாதà¯à®•à®¾à®¤à¯à®¤à®¿à®Ÿà¯</translation>
<translation id="5571083550517324815">இநà¯à®¤ à®®à¯à®•à®µà®°à®¿à®¯à®¿à®²à®¿à®°à¯à®¨à¯à®¤à¯ பிகà¯à®…ப௠செயà¯à®¯ à®®à¯à®Ÿà®¿à®¯à®¾à®¤à¯. வேற௠மà¯à®•à®µà®°à®¿à®¯à¯ˆà®¤à¯ தேரà¯à®¨à¯à®¤à¯†à®Ÿà¯à®•à¯à®•à®µà¯à®®à¯.</translation>
@@ -1518,7 +1555,7 @@
<translation id="5824687817967109979">{NUM_CARDS,plural, =1{நீஙà¯à®•à®³à¯ பணம௠செலà¯à®¤à¯à®¤à¯à®®à¯à®ªà¯‹à®¤à¯ இநà¯à®¤à®•à¯ காரà¯à®Ÿà®¿à®²à®¿à®°à¯à®¨à¯à®¤à¯ கடà¯à®Ÿà®£à®®à¯ வசூலிகà¯à®•à®ªà¯à®ªà®Ÿà¯à®®à¯, ஆனால௠காரà¯à®Ÿà®¿à®©à¯ எண௠இநà¯à®¤à®¤à¯ தளதà¯à®¤à¯à®Ÿà®©à¯ பகிரபà¯à®ªà®Ÿà®¾à®¤à¯. கூடà¯à®¤à®²à¯ பாதà¯à®•à®¾à®ªà¯à®ªà®¿à®±à¯à®•à®¾à®•, தறà¯à®•à®¾à®²à®¿à®• CVC ஒனà¯à®±à¯ உரà¯à®µà®¾à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®®à¯.}other{பணம௠செலà¯à®¤à¯à®¤à¯à®®à¯à®ªà¯‹à®¤à¯ நீஙà¯à®•à®³à¯ தேரà¯à®¨à¯à®¤à¯†à®Ÿà¯à®•à¯à®•à¯à®®à¯ காரà¯à®Ÿà®¿à®²à®¿à®°à¯à®¨à¯à®¤à¯ கடà¯à®Ÿà®£à®®à¯ வசூலிகà¯à®•à®ªà¯à®ªà®Ÿà¯à®®à¯, ஆனால௠காரà¯à®Ÿà®¿à®©à¯ எண௠இநà¯à®¤à®¤à¯ தளதà¯à®¤à¯à®Ÿà®©à¯ பகிரபà¯à®ªà®Ÿà®¾à®¤à¯. கூடà¯à®¤à®²à¯ பாதà¯à®•à®¾à®ªà¯à®ªà®¿à®±à¯à®•à®¾à®•, தறà¯à®•à®¾à®²à®¿à®• CVC ஒனà¯à®±à¯ உரà¯à®µà®¾à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®®à¯.}}</translation>
<translation id="5826507051599432481">பொதà¯à®µà®¾à®© பெயர௠(CN)</translation>
<translation id="5830698870816298009">கேமரா உபயோகம௠&amp; நகரà¯à®µà¯</translation>
-<translation id="5838278095973806738">தீஙà¯à®•à®¿à®´à¯ˆà®ªà¯à®ªà®µà®°à¯à®•à®³à¯ திரà¯à®Ÿà®¿à®µà®¿à®Ÿà®²à®¾à®®à¯ எனà¯à®ªà®¤à®¾à®²à¯, இநà¯à®¤à®¤à¯ தளதà¯à®¤à®¿à®²à¯ à®®à¯à®•à¯à®•à®¿à®¯à®¤à¯ தகவலை (எடà¯à®¤à¯à®¤à¯à®•à¯à®•à®¾à®Ÿà¯à®Ÿà¯: கடவà¯à®šà¯à®šà¯Šà®±à¯à®•à®³à¯ அலà¯à®²à®¤à¯ கிரெடிட௠காரà¯à®Ÿà¯à®•à®³à¯) உளà¯à®³à®¿à®Ÿ வேணà¯à®Ÿà®¾à®®à¯.</translation>
+<translation id="5838278095973806738">தீஙà¯à®•à®¿à®´à¯ˆà®ªà¯à®ªà®µà®°à¯à®•à®³à¯ திரà¯à®Ÿà®¿à®µà®¿à®Ÿà®²à®¾à®®à¯ எனà¯à®ªà®¤à®¾à®²à¯, இநà¯à®¤à®¤à¯ தளதà¯à®¤à®¿à®²à¯ பாதà¯à®•à®¾à®•à¯à®•à®ªà¯à®ªà®Ÿ வேணà¯à®Ÿà®¿à®¯ தகவலை (எடà¯à®¤à¯à®¤à¯à®•à¯à®•à®¾à®Ÿà¯à®Ÿà¯: கடவà¯à®šà¯à®šà¯Šà®±à¯à®•à®³à¯ அலà¯à®²à®¤à¯ கிரெடிட௠காரà¯à®Ÿà¯à®•à®³à¯) உளà¯à®³à®¿à®Ÿ வேணà¯à®Ÿà®¾à®®à¯.</translation>
<translation id="5851548754964597211">தாவல௠படà¯à®Ÿà®¿à®¯à®²à¯</translation>
<translation id="5860033963881614850">ஆஃபà¯</translation>
<translation id="5862579898803147654">ஸà¯à®Ÿà¯‡à®•à¯à®•à®°à¯ 8</translation>
@@ -1529,6 +1566,7 @@
<translation id="5869522115854928033">சேமிகà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿ கடவà¯à®šà¯à®šà¯Šà®±à¯à®•à®³à¯</translation>
<translation id="5873013647450402046">இத௠நீஙà¯à®•à®³à¯à®¤à®¾à®©à¯ எனà¯à®ªà®¤à¯ˆ உஙà¯à®•à®³à¯ பேஙà¯à®•à¯ உறà¯à®¤à®¿à®šà¯†à®¯à¯à®¯ விரà¯à®®à¯à®ªà¯à®•à®¿à®±à®¤à¯.</translation>
<translation id="5887400589839399685">காரà¯à®Ÿà¯ சேமிகà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯</translation>
+<translation id="5887687176710214216">கடைசியாகப௠பாரà¯à®¤à¯à®¤à®¤à¯: நேறà¯à®±à¯</translation>
<translation id="5895138241574237353">மறà¯à®¤à¯Šà®Ÿà®•à¯à®•à®®à¯</translation>
<translation id="5895187275912066135">வழஙà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯</translation>
<translation id="5901630391730855834">மஞà¯à®šà®³à¯</translation>
@@ -1542,6 +1580,7 @@
<translation id="5921639886840618607">Google கணகà¯à®•à®¿à®²à¯ காரà¯à®Ÿà¯ˆà®šà¯ சேமிகà¯à®•à®µà®¾?</translation>
<translation id="5922853866070715753">கிடà¯à®Ÿà®¤à¯à®¤à®Ÿà¯à®Ÿ à®®à¯à®Ÿà®¿à®¨à¯à®¤à¯à®µà®¿à®Ÿà¯à®Ÿà®¤à¯</translation>
<translation id="5932224571077948991">கà¯à®±à¯à®•à¯à®•à®¿à®Ÿà¯à®®à¯ அலà¯à®²à®¤à¯ தவறாக வழிநடதà¯à®¤à¯à®®à¯ விளமà¯à®ªà®°à®™à¯à®•à®³à¯ˆ தளம௠காணà¯à®ªà®¿à®•à¯à®•à®¿à®±à®¤à¯</translation>
+<translation id="5938153366081463283">விரà¯à®šà¯à®šà¯à®µà®²à¯ காரà¯à®Ÿà¯ˆà®šà¯ சேரà¯à®•à¯à®•à¯à®®à¯</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347"><ph name="SITE_NAME" />à®à®¤à¯ திறகà¯à®•à®¿à®±à®¤à¯â€¦</translation>
<translation id="5951495562196540101">நà¯à®•à®°à¯à®µà¯‹à®°à¯ கணகà¯à®•à®¿à®²à¯ பதிவà¯à®šà¯†à®¯à¯à®¯ à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ (தொகà¯à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿ உரிமம௠உளà¯à®³à®¤à¯).</translation>
@@ -1606,6 +1645,7 @@
<translation id="6120179357481664955">உஙà¯à®•à®³à¯ UPI à®à®Ÿà®¿à®¯à¯ˆà®šà¯ சேமிகà¯à®•à®µà®¾?</translation>
<translation id="6124432979022149706">Chrome Enterprise Connectors</translation>
<translation id="6127379762771434464">உரà¯à®ªà¯à®ªà®Ÿà®¿ அகறà¯à®±à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Chrome மறைநிலைப௠பயனà¯à®®à¯à®±à¯ˆ கà¯à®±à®¿à®¤à¯à®¤à¯ மேலà¯à®®à¯ அறிக<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">கேபிளà¯à®•à®³à¯ˆà®šà¯ சரிபாரà¯à®¤à¯à®¤à¯, நீஙà¯à®•à®³à¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®•à¯à®•à¯‚டிய ரூடà¯à®Ÿà®°à¯à®•à®³à¯, மோடமà¯à®•à®³à¯ அலà¯à®²à®¤à¯ பிற நெடà¯à®µà¯Šà®°à¯à®•à¯ சாதனஙà¯à®•à®³à¯ˆ மறà¯à®¤à¯Šà®Ÿà®•à¯à®•à®®à¯ செயà¯à®¯à®µà¯à®®à¯.</translation>
<translation id="614940544461990577">இவறà¯à®±à¯ˆà®šà¯ செயà¯à®¤à¯ பாரà¯à®•à¯à®•à®µà¯à®®à¯:</translation>
<translation id="6150036310511284407">டிரிபà¯à®ªà®¿à®²à¯ பஞà¯à®šà¯ லெஃபà¯à®Ÿà¯</translation>
@@ -1617,7 +1657,6 @@
<translation id="6169916984152623906">இபà¯à®ªà¯‹à®¤à¯ தனிபà¯à®ªà®Ÿà¯à®Ÿ à®®à¯à®±à¯ˆà®¯à®¿à®²à¯ உலாவலாமà¯. இநà¯à®¤à®šà¯ சாதனதà¯à®¤à¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à¯à®®à¯ பிறரால௠உஙà¯à®•à®³à¯ செயலà¯à®ªà®¾à®Ÿà¯à®Ÿà¯ˆà®ªà¯ பாரà¯à®•à¯à®• à®®à¯à®Ÿà®¿à®¯à®¾à®¤à¯. எனினà¯à®®à¯, பதிவிறகà¯à®•à®™à¯à®•à®³à¯à®®à¯ பà¯à®¤à¯à®¤à®•à®•à¯à®•à¯à®±à®¿à®•à®³à¯à®®à¯ சேமிகà¯à®•à®ªà¯à®ªà®Ÿà¯à®®à¯.</translation>
<translation id="6177128806592000436">இநà¯à®¤à®¤à¯ தளதà¯à®¤à®¿à®±à¯à®•à®¾à®© உஙà¯à®•à®³à¯ இணைபà¯à®ªà¯, பாதà¯à®•à®¾à®ªà¯à®ªà®¾à®• இலà¯à®²à¯ˆ</translation>
<translation id="6180316780098470077">மீணà¯à®Ÿà¯à®®à¯ à®®à¯à®¯à®²à¯à®µà®¤à®±à¯à®•à®¾à®© இடைவெளி</translation>
-<translation id="619448280891863779">எனத௠திரைகளில௠சாளரஙà¯à®•à®³à¯ˆà®¤à¯ திறநà¯à®¤à¯ வைகà¯à®• அனà¯à®®à®¤à®¿ கேடà¯à®• வேணà¯à®Ÿà¯à®®à¯</translation>
<translation id="6196640612572343990">மூனà¯à®±à®¾à®®à¯ தரபà¯à®ªà¯à®•à¯ கà¯à®•à¯à®•à¯€à®•à®³à¯ˆà®¤à¯ தடà¯</translation>
<translation id="6203231073485539293">உஙà¯à®•à®³à¯ இணைய இணைபà¯à®ªà¯ˆà®šà¯ சரிபாரà¯à®•à¯à®•à®µà¯à®®à¯</translation>
<translation id="6218753634732582820">Chromium இலிரà¯à®¨à¯à®¤à¯ à®®à¯à®•à®µà®°à®¿à®¯à¯ˆ அகறà¯à®±à®µà®¾?</translation>
@@ -1640,7 +1679,7 @@
<translation id="6272383483618007430">Google பà¯à®¤à¯à®ªà¯à®ªà®¿à®ªà¯à®ªà¯</translation>
<translation id="6276112860590028508">வாசிபà¯à®ªà¯à®ªà¯ படà¯à®Ÿà®¿à®¯à®²à®¿à®²à¯ இரà¯à®•à¯à®•à¯à®®à¯ பகà¯à®•à®™à¯à®•à®³à¯ இஙà¯à®•à¯‡ தோனà¯à®±à¯à®®à¯</translation>
<translation id="627746635834430766">அடà¯à®¤à¯à®¤ à®®à¯à®±à¯ˆ விரைவாகப௠பணம௠அனà¯à®ªà¯à®ª, உஙà¯à®•à®³à¯ காரà¯à®Ÿà¯ˆà®¯à¯à®®à¯ பிலà¯à®²à®¿à®™à¯ à®®à¯à®•à®µà®°à®¿à®¯à¯ˆà®¯à¯à®®à¯ Google கணகà¯à®•à®¿à®²à¯ சேமிகà¯à®•à®µà¯à®®à¯.</translation>
-<translation id="6279098320682980337">விரà¯à®šà¯à®šà¯à®µà®²à¯ காரà¯à®Ÿà¯ எண௠நிரபà¯à®ªà®ªà¯à®ªà®Ÿà®µà®¿à®²à¯à®²à¯ˆà®¯à®¾? நகலெடà¯à®•à¯à®•, காரà¯à®Ÿà¯ விவரஙà¯à®•à®³à¯ˆà®•à¯ கிளிக௠செயà¯à®¯à®µà¯à®®à¯</translation>
+<translation id="6279183038361895380">உஙà¯à®•à®³à¯ சà¯à®Ÿà¯à®Ÿà®¿à®¯à¯ˆà®•à¯ காடà¯à®Ÿ |<ph name="ACCELERATOR" />| எனà¯à®ªà®¤à¯ˆ à®…à®´à¯à®¤à¯à®¤à®µà¯à®®à¯</translation>
<translation id="6280223929691119688">இநà¯à®¤ à®®à¯à®•à®µà®°à®¿à®•à¯à®•à¯ டெலிவரி செயà¯à®¯ à®®à¯à®Ÿà®¿à®¯à®¾à®¤à¯. வேற௠மà¯à®•à®µà®°à®¿à®¯à¯ˆà®¤à¯ தேரà¯à®¨à¯à®¤à¯†à®Ÿà¯à®•à¯à®•à®µà¯à®®à¯.</translation>
<translation id="6282194474023008486">அஞà¯à®šà®²à¯ கà¯à®±à®¿à®¯à¯€à®Ÿà¯</translation>
<translation id="6285507000506177184">Chromeமில௠பதிவிறகà¯à®•à®¿à®¯à®µà®±à¯à®±à¯ˆ நிரà¯à®µà®•à®¿à®ªà¯à®ªà®¤à®±à¯à®•à®¾à®© படà¯à®Ÿà®©à¯. Chromeமில௠நீஙà¯à®•à®³à¯ பதிவிறகà¯à®•à®¿à®¯ ஃபைலà¯à®•à®³à¯ˆ நிரà¯à®µà®•à®¿à®•à¯à®•, Enter படà¯à®Ÿà®©à¯ˆ à®…à®´à¯à®¤à¯à®¤à¯à®™à¯à®•à®³à¯</translation>
@@ -1648,6 +1687,7 @@
<translation id="6290238015253830360">நீஙà¯à®•à®³à¯ பரிநà¯à®¤à¯à®°à¯ˆà®¤à¯à®¤ கடà¯à®Ÿà¯à®°à¯ˆà®•à®³à¯ இஙà¯à®•à¯‡ தோனà¯à®±à¯à®®à¯</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{இபà¯à®ªà¯‹à®¤à¯ சாதனம௠மீணà¯à®Ÿà¯à®®à¯ தொடஙà¯à®•à¯à®®à¯}=1{ஒர௠வினாடியில௠சாதனம௠மீணà¯à®Ÿà¯à®®à¯ தொடஙà¯à®•à¯à®®à¯}other{# வினாடிகளில௠சாதனம௠மீணà¯à®Ÿà¯à®®à¯ தொடஙà¯à®•à¯à®®à¯}}</translation>
<translation id="6302269476990306341">’Chromeமில௠Google அசிஸà¯à®Ÿà®£à¯à®Ÿà¯â€™ நிறà¯à®¤à¯à®¤à®ªà¯à®ªà®Ÿà¯à®•à®¿à®±à®¤à¯</translation>
<translation id="6305205051461490394"><ph name="URL" />஠அடையமà¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ.</translation>
<translation id="6312113039770857350">இணையபà¯à®ªà®•à¯à®•à®®à¯ கிடைகà¯à®•à®µà®¿à®²à¯à®²à¯ˆ</translation>
@@ -1721,6 +1761,7 @@
<translation id="6529602333819889595">&amp;நீகà¯à®•à¯à®¤à®²à¯ˆ மீணà¯à®Ÿà¯à®®à¯ செயà¯</translation>
<translation id="6545864417968258051">பà¯à®³à¯‚டூத௠ஸà¯à®•à¯‡à®©à®¿à®™à¯</translation>
<translation id="6547208576736763147">டூயல௠பஞà¯à®šà¯ லெஃபà¯à®Ÿà¯</translation>
+<translation id="6554732001434021288">கடைசியாகப௠பாரà¯à®¤à¯à®¤à®¤à¯: <ph name="NUM_DAYS" /> நாடà¯à®•à®³à¯à®•à¯à®•à¯ à®®à¯à®©à¯</translation>
<translation id="6556866813142980365">மீணà¯à®Ÿà¯à®®à¯ செயà¯</translation>
<translation id="6569060085658103619">நீடà¯à®Ÿà®¿à®ªà¯à®ªà¯à®ªà¯ பகà¯à®•à®¤à¯à®¤à¯ˆà®ªà¯ பாரà¯à®•à¯à®•à®¿à®±à¯€à®°à¯à®•à®³à¯</translation>
<translation id="6573200754375280815">டூயல௠பஞà¯à®šà¯ ரைடà¯</translation>
@@ -1781,7 +1822,6 @@
<translation id="6757797048963528358">உஙà¯à®•à®³à¯ சாதனம௠உறகà¯à®•à®¨à®¿à®²à¯ˆà®•à¯à®•à¯à®šà¯ செனà¯à®±à®¤à¯.</translation>
<translation id="6767985426384634228">à®®à¯à®•à®µà®°à®¿à®¯à¯ˆ மாறà¯à®±à®µà®¾?</translation>
<translation id="6768213884286397650">Hagaki (போஸà¯à®Ÿà¯à®•à®¾à®°à¯à®Ÿà¯)</translation>
-<translation id="6774185088257932239">மறைநிலை கà¯à®±à®¿à®¤à¯à®¤à¯ <ph name="BEGIN_LINK" />மேலà¯à®®à¯ அறிக<ph name="END_LINK" /></translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">ஊதா</translation>
<translation id="6786747875388722282">நீடà¯à®Ÿà®¿à®ªà¯à®ªà¯à®•à®³à¯</translation>
@@ -1844,7 +1884,7 @@
<translation id="6978236010531171013">பரவாயிலà¯à®²à¯ˆ, பகிரà¯</translation>
<translation id="6979158407327259162">Google Drive</translation>
<translation id="6979440798594660689">à®®à¯à®Ÿà®•à¯à®•à¯ (இயலà¯à®ªà¯)</translation>
-<translation id="6979983982287291980">நீஙà¯à®•à®³à¯ பதிவிறகà¯à®•à¯à®®à¯ ஃபைலà¯à®•à®³à¯ Google கிளவà¯à®Ÿà¯à®•à¯à®•à¯‹ மூனà¯à®±à®¾à®®à¯ தரபà¯à®ªà®¿à®©à®°à¯à®•à¯à®•à¯‹ ஆயà¯à®µà¯à®•à¯à®•à®¾à®• அனà¯à®ªà¯à®ªà®ªà¯à®ªà®Ÿà¯à®®à¯. எடà¯à®¤à¯à®¤à¯à®•à¯à®•à®¾à®Ÿà¯à®Ÿà®¾à®•, பாதà¯à®•à®¾à®•à¯à®• வேணà¯à®Ÿà®¿à®¯ தரவோ மாலà¯à®µà¯‡à®°à¯‹ உளà¯à®³à®¤à®¾ எனà¯à®±à¯ கணà¯à®Ÿà®±à®¿à®µà®¤à®±à¯à®•à®¾à®• அவை ஸà¯à®•à¯‡à®©à¯ செயà¯à®¯à®ªà¯à®ªà®Ÿà®²à®¾à®®à¯.</translation>
+<translation id="6979983982287291980">நீஙà¯à®•à®³à¯ பதிவிறகà¯à®•à¯à®®à¯ ஃபைலà¯à®•à®³à¯ Google கிளவà¯à®Ÿà¯à®•à¯à®•à¯‹ மூனà¯à®±à®¾à®®à¯ தரபà¯à®ªà®¿à®©à®°à¯à®•à¯à®•à¯‹ ஆயà¯à®µà¯à®•à¯à®•à®¾à®• அனà¯à®ªà¯à®ªà®ªà¯à®ªà®Ÿà¯à®®à¯. எடà¯à®¤à¯à®¤à¯à®•à¯à®•à®¾à®Ÿà¯à®Ÿà®¾à®•, பாதà¯à®•à®¾à®•à¯à®•à®ªà¯à®ªà®Ÿ வேணà¯à®Ÿà®¿à®¯ தனிபà¯à®ªà®Ÿà¯à®Ÿ தரவோ மாலà¯à®µà¯‡à®°à¯‹ உளà¯à®³à®¤à®¾ எனà¯à®±à¯ கணà¯à®Ÿà®±à®¿à®µà®¤à®±à¯à®•à®¾à®• அவை ஸà¯à®•à¯‡à®©à¯ செயà¯à®¯à®ªà¯à®ªà®Ÿà®²à®¾à®®à¯.</translation>
<translation id="6989763994942163495">மேமà¯à®ªà®Ÿà¯à®Ÿ அமைபà¯à®ªà¯à®•à®³à¯ˆà®•à¯ காணà¯à®ªà®¿...</translation>
<translation id="6993898126790112050">6x9 (எனà¯à®µà®²à®ªà¯)</translation>
<translation id="6996312675313362352"><ph name="ORIGINAL_LANGUAGE" /> மொழியிலிரà¯à®¨à¯à®¤à¯ எபà¯à®ªà¯‹à®¤à¯à®®à¯ மொழிபெயரà¯</translation>
@@ -1865,7 +1905,6 @@
<translation id="706295145388601875">Chrome அமைபà¯à®ªà¯à®•à®³à®¿à®²à¯ இணைய à®®à¯à®•à®µà®°à®¿à®•à®³à¯ˆà®šà¯ சேரà¯à®™à¯à®•à®³à¯ &amp; நிரà¯à®µà®•à®¿à®¯à¯à®™à¯à®•à®³à¯</translation>
<translation id="7064851114919012435">தொடரà¯à®ªà¯à®¤à¯ தகவலà¯</translation>
<translation id="7068733155164172741"><ph name="OTP_LENGTH" /> இலகà¯à®•à®•à¯ கà¯à®±à®¿à®¯à¯€à®Ÿà¯à®Ÿà¯ˆ டைப௠செயà¯à®¯à®µà¯à®®à¯</translation>
-<translation id="7070090581017165256">இநà¯à®¤à®¤à¯ தளதà¯à®¤à¯ˆà®ªà¯ பறà¯à®±à®¿</translation>
<translation id="70705239631109039">உஙà¯à®•à®³à¯ இணைபà¯à®ªà¯ à®®à¯à®´à¯à®ªà¯ பாதà¯à®•à®¾à®ªà¯à®ªà¯à®Ÿà®©à¯ இலà¯à®²à¯ˆ</translation>
<translation id="7075452647191940183">கோரிகà¯à®•à¯ˆà®¯à®¿à®©à¯ அளவ௠மிகப௠பெரியதாக உளà¯à®³à®¤à¯</translation>
<translation id="7079718277001814089">இநà¯à®¤à®¤à¯ தளதà¯à®¤à®¿à®²à¯ மாலà¯à®µà¯‡à®°à¯ உளà¯à®³à®¤à¯</translation>
@@ -1882,6 +1921,12 @@
<translation id="7111012039238467737">(சரியானதà¯)</translation>
<translation id="7118618213916969306"><ph name="SHORT_URL" /> எனà¯à®®à¯ கிளிபà¯-போரà¯à®Ÿà¯ URLலைத௠தேடà¯à®®à¯</translation>
<translation id="7119414471315195487">பிற தாவலà¯à®•à®³à¯ அலà¯à®²à®¤à¯ நிரலà¯à®•à®³à¯ˆ மூடவà¯à®®à¯</translation>
+<translation id="7129355289156517987">Chromium மறைநிலைப௠பகà¯à®•à®™à¯à®•à®³à¯ அனைதà¯à®¤à¯ˆà®¯à¯à®®à¯ மூடà¯à®®à¯à®ªà¯‹à®¤à¯ அநà¯à®¤à®ªà¯ பகà¯à®•à®™à¯à®•à®³à®¿à®²à¯ நீஙà¯à®•à®³à¯ மேறà¯à®•à¯Šà®£à¯à®Ÿ செயலà¯à®ªà®¾à®Ÿà¯à®•à®³à¯ இநà¯à®¤à®šà¯ சாதனதà¯à®¤à®¿à®²à¯ இரà¯à®¨à¯à®¤à¯ அழிகà¯à®•à®ªà¯à®ªà®Ÿà¯à®®à¯:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />உலாவல௠செயலà¯à®ªà®¾à®Ÿà¯<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />இதà¯à®µà®°à¯ˆ தேடியவை<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />படிவஙà¯à®•à®³à®¿à®²à¯ டைப௠செயà¯à®¤ தகவலà¯à®•à®³à¯<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">இநà¯à®¤ à®®à¯à®•à®µà®°à®¿à®•à¯à®•à¯ அனà¯à®ªà¯à®ª à®®à¯à®Ÿà®¿à®¯à®¾à®¤à¯. வேற௠மà¯à®•à®µà®°à®¿à®¯à¯ˆà®¤à¯ தேரà¯à®¨à¯à®¤à¯†à®Ÿà¯à®•à¯à®•à®µà¯à®®à¯.</translation>
<translation id="7132939140423847331">இநà¯à®¤à®¤à¯ தரவை நகலெடà¯à®ªà¯à®ªà®¤à¯ˆ உஙà¯à®•à®³à¯ நிரà¯à®µà®¾à®•à®¿ தடà¯à®¤à¯à®¤à¯à®³à¯à®³à®¾à®°à¯.</translation>
<translation id="7135130955892390533">நிலையைக௠காடà¯à®Ÿà¯</translation>
@@ -1904,6 +1949,7 @@
<translation id="7192203810768312527"><ph name="SIZE" /> அளவைக௠காலியாகà¯à®•à¯à®®à¯. நீஙà¯à®•à®³à¯ அடà¯à®¤à¯à®¤ à®®à¯à®±à¯ˆ பாரà¯à®µà¯ˆà®¯à®¿à®Ÿà¯à®®à¯ போதà¯, சில தளஙà¯à®•à®³à¯ மிகவà¯à®®à¯ மெதà¯à®µà®¾à®• à®à®±à¯à®±à®ªà¯à®ªà®Ÿà®²à®¾à®®à¯.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">உஙà¯à®•à®³à¯ நிரà¯à®µà®¾à®•à®¿ இவறà¯à®±à¯ˆà®ªà¯ பாரà¯à®•à¯à®• à®®à¯à®Ÿà®¿à®¯à¯à®®à¯:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, தனிபà¯à®ªà®Ÿà¯à®Ÿ à®®à¯à®±à¯ˆà®¯à®¿à®²à¯ உலாவà¯à®µà®¤à®±à¯à®•à¯à®ªà¯ பà¯à®¤à®¿à®¯ மறைநிலைப௠பகà¯à®•à®¤à¯à®¤à¯ˆà®¤à¯ திறகà¯à®•, Tab படà¯à®Ÿà®©à¯ˆ à®…à®´à¯à®¤à¯à®¤à®¿à®µà®¿à®Ÿà¯à®Ÿà¯ Enter படà¯à®Ÿà®©à¯ˆ à®…à®´à¯à®¤à¯à®¤à¯à®™à¯à®•à®³à¯</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> பாதà¯à®•à®¾à®ªà¯à®ªà¯à®¤à¯ தரநிலைகளà¯à®•à¯à®•à¯ இணஙà¯à®•à®µà®¿à®²à¯à®²à¯ˆ.</translation>
<translation id="7210993021468939304">கணà¯à®Ÿà¯†à®¯à¯à®©à®°à¯à®•à¯à®•à¯à®³à¯ நடகà¯à®•à¯à®®à¯ Linux செயலà¯à®ªà®¾à®Ÿà¯à®Ÿà®¿à®©à¯ˆà®ªà¯ பாரà¯à®•à¯à®• à®®à¯à®Ÿà®¿à®¯à¯à®®à¯, மறà¯à®±à¯à®®à¯ கணà¯à®Ÿà¯†à®¯à¯à®©à®°à¯à®•à¯à®•à¯à®³à¯ Linux ஆபà¯à®¸à¯ˆ நிறà¯à®µà®¿ இயகà¯à®• à®®à¯à®Ÿà®¿à®¯à¯à®®à¯</translation>
@@ -1935,6 +1981,7 @@
<translation id="7304562222803846232">Google கணகà¯à®•à®¿à®©à¯ தனியà¯à®°à®¿à®®à¯ˆ அமைபà¯à®ªà¯à®•à®³à¯ˆ நிரà¯à®µà®•à®¿à®¯à¯à®™à¯à®•à®³à¯</translation>
<translation id="7305756307268530424">மெதà¯à®µà®¾à®© வேகதà¯à®¤à®¿à®²à¯ தொடஙà¯à®•à¯</translation>
<translation id="7308436126008021607">பினà¯à®©à®£à®¿ ஒதà¯à®¤à®¿à®šà¯ˆà®µà¯</translation>
+<translation id="7310392214323165548">சாதனம௠விரைவில௠மீணà¯à®Ÿà¯à®®à¯ தொடஙà¯à®•à¯à®®à¯</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">இணைபà¯à®ªà®¿à®±à¯à®•à®¾à®© உதவி</translation>
<translation id="7323804146520582233">"<ph name="SECTION" />" பிரிவை மறைகà¯à®•à¯à®®à¯</translation>
@@ -1942,6 +1989,7 @@
<translation id="7334320624316649418">&amp;மறà¯à®µà®°à®¿à®šà¯ˆà®ªà¯à®ªà®Ÿà¯à®¤à¯à®¤à®²à¯ˆ மீணà¯à®Ÿà¯à®®à¯ செயà¯</translation>
<translation id="7335157162773372339">கேமராவைப௠பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤ அனà¯à®®à®¤à®¿ கேடà¯à®• வேணà¯à®Ÿà¯à®®à¯</translation>
<translation id="7337248890521463931">மேலà¯à®®à¯ வரிகளைக௠காடà¯à®Ÿà¯à®®à¯</translation>
+<translation id="7337418456231055214">விரà¯à®šà¯à®šà¯à®µà®²à¯ காரà¯à®Ÿà¯ எண௠நிரபà¯à®ªà®ªà¯à®ªà®Ÿà®µà®¿à®²à¯à®²à¯ˆà®¯à®¾? நகலெடà¯à®•à¯à®•, காரà¯à®Ÿà¯ விவரஙà¯à®•à®³à¯ˆà®•à¯ கிளிக௠செயà¯à®¯à®µà¯à®®à¯. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">உஙà¯à®•à®³à¯ இயஙà¯à®•à¯à®¤à®³à®¤à¯à®¤à®¿à®²à¯ இலà¯à®²à¯ˆ.</translation>
<translation id="733923710415886693">சானà¯à®±à®¿à®¤à®´à¯ வெளிபà¯à®ªà®Ÿà¯ˆà®¤à¯à®¤à®©à¯à®®à¯ˆ மூலம௠சேவையகதà¯à®¤à®¿à®©à¯ சானà¯à®±à®¿à®¤à®´à¯ வெளியிடபà¯à®ªà®Ÿà®µà®¿à®²à¯à®²à¯ˆ.</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1964,6 +2012,7 @@
<translation id="7378627244592794276">வேணà¯à®Ÿà®¾à®®à¯</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">பொரà¯à®¨à¯à®¤à®¾à®¤à¯</translation>
+<translation id="7388594495505979117">{0,plural, =1{ஒர௠நிமிடதà¯à®¤à®¿à®²à¯ சாதனம௠மீணà¯à®Ÿà¯à®®à¯ தொடஙà¯à®•à¯à®®à¯}other{# நிமிடஙà¯à®•à®³à®¿à®²à¯ சாதனம௠மீணà¯à®Ÿà¯à®®à¯ தொடஙà¯à®•à¯à®®à¯}}</translation>
<translation id="7390545607259442187">காரà¯à®Ÿà¯ˆ உறà¯à®¤à®¿à®šà¯†à®¯à¯</translation>
<translation id="7392089738299859607">à®®à¯à®•à®µà®°à®¿à®¯à¯ˆ மாறà¯à®±à¯à®™à¯à®•à®³à¯</translation>
<translation id="7399802613464275309">பாதà¯à®•à®¾à®ªà¯à®ªà¯à®šà¯ சரிபாரà¯à®ªà¯à®ªà¯</translation>
@@ -2000,6 +2049,12 @@
<translation id="7485870689360869515">தரவ௠எதà¯à®µà¯à®®à¯ இலà¯à®²à¯ˆ.</translation>
<translation id="7495528107193238112">இநà¯à®¤ உளà¯à®³à®Ÿà®•à¯à®•à®®à¯ தடà¯à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯. இநà¯à®¤à®šà¯ சிகà¯à®•à®²à¯ˆà®šà¯ சரிசெயà¯à®¯, தளதà¯à®¤à®¿à®©à¯ உரிமையாளரைத௠தொடரà¯à®ªà¯à®•à¯Šà®³à¯à®³à®µà¯à®®à¯.</translation>
<translation id="7497998058912824456">ஆவணதà¯à®¤à¯ˆ உரà¯à®µà®¾à®•à¯à®•à¯à®µà®¤à®±à¯à®•à®¾à®© படà¯à®Ÿà®©à¯. பà¯à®¤à®¿à®¯ Google ஆவணதà¯à®¤à¯ˆ விரைவாக உரà¯à®µà®¾à®•à¯à®• Enter படà¯à®Ÿà®©à¯ˆ à®…à®´à¯à®¤à¯à®¤à¯à®™à¯à®•à®³à¯</translation>
+<translation id="7506488012654002225">பினà¯à®µà®°à¯à®®à¯ தகவலà¯à®•à®³à¯ˆ Chromium <ph name="BEGIN_EMPHASIS" />சேமிகà¯à®•à®¾à®¤à¯<ph name="END_EMPHASIS" />:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />நீஙà¯à®•à®³à¯ இதà¯à®µà®°à¯ˆ இணையதà¯à®¤à®¿à®²à¯ பாரà¯à®¤à¯à®¤à®µà¯ˆ
+ <ph name="LIST_ITEM" />கà¯à®•à¯à®•à¯€à®•à®³à¯ மறà¯à®±à¯à®®à¯ தளத௠தரவà¯
+ <ph name="LIST_ITEM" />படிவஙà¯à®•à®³à®¿à®²à¯ டைப௠செயà¯à®¤ தகவலà¯à®•à®³à¯
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">கிடைதà¯à®¤ பாலிசி சாதன à®à®Ÿà®¿ காலியாக உளà¯à®³à®¤à¯ அலà¯à®²à®¤à¯ தறà¯à®ªà¯‹à®¤à¯ˆà®¯ சாதன à®à®Ÿà®¿à®¯à¯à®Ÿà®©à¯ பொரà¯à®¨à¯à®¤à®µà®¿à®²à¯à®²à¯ˆ</translation>
<translation id="7508870219247277067">அவகாடோ பசà¯à®šà¯ˆ</translation>
<translation id="7511955381719512146">நீஙà¯à®•à®³à¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®¿à®•à¯ கொணà¯à®Ÿà®¿à®°à¯à®•à¯à®•à¯à®®à¯ வைஃபை, அதன௠<ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />஠நீஙà¯à®•à®³à¯ பாரà¯à®•à¯à®•à®•à¯ கோரலாமà¯.</translation>
@@ -2113,7 +2168,6 @@
<translation id="7813600968533626083">Chrome இலிரà¯à®¨à¯à®¤à¯ படிவப௠பரிநà¯à®¤à¯à®°à¯ˆà®¯à¯ˆ அகறà¯à®±à®µà®¾?</translation>
<translation id="781440967107097262">கிளிபà¯à®ªà¯‹à®°à¯à®Ÿà¯ˆà®ªà¯ பகிரவா?</translation>
<translation id="7815407501681723534">'<ph name="SEARCH_STRING" />'கà¯à®•à¯ <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> உளà¯à®³à®©</translation>
-<translation id="782125616001965242">இநà¯à®¤à®¤à¯ தளம௠கà¯à®±à®¿à®¤à¯à®¤ தகவலà¯à®•à®³à¯ˆà®•à¯ காடà¯à®Ÿà¯à®®à¯</translation>
<translation id="782886543891417279">நீஙà¯à®•à®³à¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®¿à®•à¯ கொணà¯à®Ÿà®¿à®°à¯à®•à¯à®•à¯à®®à¯ (<ph name="WIFI_NAME" />) வைஃபை, அதன௠உளà¯à®¨à¯à®´à¯ˆà®µà¯à®ªà¯ பகà¯à®•à®¤à¯à®¤à¯ˆ நீஙà¯à®•à®³à¯ பாரà¯à®•à¯à®•à®•à¯ கோரலாமà¯.</translation>
<translation id="7836231406687464395">Postfix (எனà¯à®µà®²à®ªà¯)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{எதà¯à®µà¯à®®à®¿à®²à¯à®²à¯ˆ}=1{1 ஆபà¯à®¸à¯ (<ph name="EXAMPLE_APP_1" />)}=2{2 ஆபà¯à®¸à¯ (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}other{# ஆபà¯à®¸à¯ (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}}</translation>
@@ -2130,7 +2184,6 @@
<translation id="7888575728750733395">அசà¯à®šà¯ ரெனà¯à®Ÿà®°à®¿à®™à¯ இனà¯à®Ÿà¯†à®©à¯à®Ÿà¯</translation>
<translation id="7894280532028510793">எழà¯à®¤à¯à®¤à¯à®ªà¯à®ªà®¿à®´à¯ˆ இலà¯à®²à¯ˆà®¯à¯†à®©à®¿à®²à¯ <ph name="BEGIN_LINK" />நெடà¯à®µà¯Šà®°à¯à®•à¯ சரிபாரà¯à®ªà¯à®ªà¯ˆ இயகà¯à®•à®¿à®ªà¯ பாரà¯à®•à¯à®•à®µà¯à®®à¯<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (எனà¯à®µà®²à®ªà¯)</translation>
-<translation id="7931318309563332511">தெரியவிலà¯à®²à¯ˆ</translation>
<translation id="793209273132572360">à®®à¯à®•à®µà®°à®¿à®¯à¯ˆ மாறà¯à®±à®µà®¾?</translation>
<translation id="7932579305932748336">கோடà¯</translation>
<translation id="79338296614623784">சரியான ஃபோன௠எணà¯à®£à¯ˆ உளà¯à®³à®¿à®Ÿà®µà¯à®®à¯</translation>
@@ -2155,13 +2208,14 @@
<translation id="7976214039405368314">அளவà¯à®•à¯à®•à¯ அதிகமான கோரிகà¯à®•à¯ˆà®•à®³à¯</translation>
<translation id="7977538094055660992">அவà¯à®Ÿà¯à®ªà¯à®Ÿà¯ சாதனமà¯</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">இதனà¯à®Ÿà®©à¯ இணைதà¯à®¤à¯à®³à¯à®³à¯€à®°à¯à®•à®³à¯:</translation>
<translation id="798134797138789862">விரà¯à®šà¯à®šà¯à®µà®²à¯ ரியாலிடà¯à®Ÿà®¿ சாதனஙà¯à®•à®³à¯ˆà®¯à¯à®®à¯ தரவையà¯à®®à¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤ à®®à¯à®¯à®²à¯à®®à¯à®ªà¯‹à®¤à¯ அனà¯à®®à®¤à®¿ கேடà¯à®• வேணà¯à®Ÿà¯à®®à¯</translation>
<translation id="7984945080620862648">இணையதளமானத௠Chrome ஆல௠செயலà¯à®ªà®Ÿà¯à®¤à¯à®¤ à®®à¯à®Ÿà®¿à®¯à®¾à®¤ வழகà¯à®•à®¤à¯à®¤à®¿à®±à¯à®•à¯ மாறான நறà¯à®šà®¾à®©à¯à®±à¯à®•à®³à¯ˆ அனà¯à®ªà¯à®ªà®¿à®¯à¯à®³à¯à®³à®¤à®¾à®²à¯, நீஙà¯à®•à®³à¯ இபà¯à®ªà¯‹à®¤à¯ <ph name="SITE" /> à®à®ªà¯ பாரà¯à®µà¯ˆà®¯à®¿à®Ÿ à®®à¯à®Ÿà®¿à®¯à®¾à®¤à¯, நெடà¯à®µà¯Šà®°à¯à®•à¯ பிழைகள௠மறà¯à®±à¯à®®à¯ தாகà¯à®•à¯à®¤à®²à¯à®•à®³à¯ தறà¯à®•à®¾à®²à®¿à®•à®®à®¾à®©à®µà¯ˆà®¯à®¾à®•à¯à®®à¯, எனவே இநà¯à®¤à®ªà¯ பகà¯à®•à®®à¯ சிறித௠நேரம௠கழிதà¯à®¤à¯ செயலà¯à®ªà®Ÿà¯à®®à¯.</translation>
-<translation id="79859296434321399">ஆகà¯à®®à¯†à®©à¯à®Ÿà¯à®Ÿà®Ÿà¯ ரியாலிடà¯à®Ÿà®¿ உளà¯à®³à®Ÿà®•à¯à®•à®¤à¯à®¤à¯ˆà®ªà¯ பாரà¯à®•à¯à®•, ARCore஠நிறà¯à®µà®µà¯à®®à¯</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">பைணà¯à®Ÿà¯</translation>
<translation id="7992044431894087211"><ph name="APPLICATION_TITLE" /> உடன௠திரையைப௠பகிரà¯à®µà®¤à¯ மீணà¯à®Ÿà¯à®®à¯ தொடஙà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯</translation>
<translation id="7995512525968007366">கà¯à®±à®¿à®ªà¯à®ªà®¿à®Ÿà®ªà¯à®ªà®Ÿà®µà®¿à®²à¯à®²à¯ˆ</translation>
+<translation id="7998269595945679889">மறைநிலைப௠பகà¯à®•à®¤à¯à®¤à¯ˆà®¤à¯ திறபà¯à®ªà®¤à®±à¯à®•à®¾à®© படà¯à®Ÿà®©à¯, தனிபà¯à®ªà®Ÿà¯à®Ÿ à®®à¯à®±à¯ˆà®¯à®¿à®²à¯ உலாவà¯à®µà®¤à®±à¯à®•à¯à®ªà¯ பà¯à®¤à®¿à®¯ மறைநிலைப௠பகà¯à®•à®¤à¯à®¤à¯ˆà®¤à¯ திறகà¯à®•, Enter படà¯à®Ÿà®©à¯ˆ à®…à®´à¯à®¤à¯à®¤à¯à®™à¯à®•à®³à¯</translation>
<translation id="800218591365569300">பிற தாவலà¯à®•à®³à¯ அலà¯à®²à®¤à¯ நிரலà¯à®•à®³à¯ˆ மூடி, நினைவகதà¯à®¤à¯ˆà®•à¯ காலியாகà¯à®•à®µà¯à®®à¯.</translation>
<translation id="8004582292198964060">உலாவி</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{இநà¯à®¤à®•à¯ காரà¯à®Ÿà¯à®®à¯ அதன௠பிலà¯à®²à®¿à®™à¯ à®®à¯à®•à®µà®°à®¿à®¯à¯à®®à¯ சேமிகà¯à®•à®ªà¯à®ªà®Ÿà¯à®®à¯. <ph name="USER_EMAIL" /> இல௠உளà¯à®¨à¯à®´à¯ˆà®¨à¯à®¤à®¿à®°à¯à®•à¯à®•à¯à®®à¯à®ªà¯‹à®¤à¯ இதைப௠பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®²à®¾à®®à¯.}other{இநà¯à®¤à®•à¯ காரà¯à®Ÿà¯à®•à®³à¯à®®à¯ அவறà¯à®±à®¿à®©à¯ பிலà¯à®²à®¿à®™à¯ à®®à¯à®•à®µà®°à®¿à®•à®³à¯à®®à¯ சேமிகà¯à®•à®ªà¯à®ªà®Ÿà¯à®®à¯. <ph name="USER_EMAIL" /> இல௠உளà¯à®¨à¯à®´à¯ˆà®¨à¯à®¤à®¿à®°à¯à®•à¯à®•à¯à®®à¯à®ªà¯‹à®¤à¯ இவறà¯à®±à¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®²à®¾à®®à¯.}}</translation>
@@ -2221,6 +2275,7 @@
<translation id="8202370299023114387">à®®à¯à®°à®£à¯à®ªà®¾à®Ÿà¯</translation>
<translation id="8206978196348664717">Prc4 (எனà¯à®µà®²à®ªà¯)</translation>
<translation id="8211406090763984747">இணைபà¯à®ªà¯ பாதà¯à®•à®¾à®ªà¯à®ªà®¾à®©à®¤à¯</translation>
+<translation id="8217240300496046857">உஙà¯à®•à®³à¯ இணையச௠செயலà¯à®ªà®¾à®Ÿà¯à®•à®³à¯ˆà®•à¯ கணà¯à®•à®¾à®£à®¿à®•à¯à®•à¯à®®à¯ கà¯à®•à¯à®•à¯€à®•à®³à¯ˆà®¤à¯ தளஙà¯à®•à®³à®¾à®²à¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤ à®®à¯à®Ÿà®¿à®¯à®¾à®¤à¯. சில தளஙà¯à®•à®³à®¿à®²à¯à®³à¯à®³ à®…à®®à¯à®šà®™à¯à®•à®³à¯ செயலà¯à®ªà®Ÿà®¾à®®à®²à¯ போககà¯à®•à¯‚டà¯à®®à¯.</translation>
<translation id="8218327578424803826">ஒதà¯à®•à¯à®•à®¿à®¯ இரà¯à®ªà¯à®ªà®¿à®Ÿà®®à¯:</translation>
<translation id="8220146938470311105">C7/C6 (எனà¯à®µà®²à®ªà¯)</translation>
<translation id="8225771182978767009">இநà¯à®¤à®•à¯ கமà¯à®ªà¯à®¯à¯‚டà¯à®Ÿà®°à¯ˆ அமைதà¯à®¤ நபர௠இநà¯à®¤à®¤à¯ தளதà¯à®¤à¯ˆà®¤à¯ தடà¯à®•à¯à®•à¯à®®à¯à®ªà®Ÿà®¿ தேரà¯à®µà¯à®šà¯†à®¯à¯à®¤à¯à®³à¯à®³à®¾à®°à¯.</translation>
@@ -2261,14 +2316,9 @@
<translation id="830498451218851433">ஃபோலà¯à®Ÿà¯ ஹாஃபà¯</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">நிறà¯à®µà®¿à®¯à¯à®³à¯à®³ ஆபà¯à®¸à¯à®®à¯ அவை எபà¯à®ªà¯‹à®¤à¯†à®²à¯à®²à®¾à®®à¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®ªà¯à®ªà®Ÿà¯à®•à®¿à®©à¯à®±à®© எனà¯à®± தகவலà¯à®®à¯</translation>
+<translation id="8317207217658302555">ARCoreரைப௠பà¯à®¤à¯à®ªà¯à®ªà®¿à®•à¯à®•à®µà®¾?</translation>
<translation id="831997045666694187">மாலை</translation>
<translation id="8321476692217554900">அறிவிபà¯à®ªà¯à®•à®³à¯</translation>
-<translation id="8328484624016508118">அனைதà¯à®¤à¯ மறைநிலைப௠பகà¯à®•à®™à¯à®•à®³à¯ˆà®¯à¯à®®à¯ மூடியதà¯à®®à¯ Chrome இவறà¯à®±à¯ˆ அழிகà¯à®•à¯à®®à¯:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />இநà¯à®¤à®šà¯ சாதனதà¯à®¤à®¿à®²à¯ உளà¯à®³ உஙà¯à®•à®³à®¿à®©à¯ உலாவல௠செயலà¯à®ªà®¾à®Ÿà¯<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />இநà¯à®¤à®šà¯ சாதனதà¯à®¤à®¿à®²à¯ உளà¯à®³ உஙà¯à®•à®³à®¿à®©à¯ தேடல௠விவரஙà¯à®•à®³à¯<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />படிவஙà¯à®•à®³à®¿à®²à¯ டைப௠செயà¯à®¤ தகவலà¯à®•à®³à¯<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489"><ph name="HOST_NAME" /> கà¯à®•à®¾à®© அணà¯à®•à®²à¯ மறà¯à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯</translation>
<translation id="833262891116910667">தனிபà¯à®ªà®Ÿà¯à®¤à¯à®¤à¯à®®à¯</translation>
<translation id="8339163506404995330"><ph name="LANGUAGE" /> மொழியில௠உளà¯à®³ பகà¯à®•à®™à¯à®•à®³à¯ மொழிபெயரà¯à®•à¯à®•à®ªà¯à®ªà®Ÿà®¾à®¤à¯</translation>
@@ -2320,6 +2370,7 @@
<translation id="8507227106804027148">கடà¯à®Ÿà®³à¯ˆ வரி</translation>
<translation id="8508648098325802031">தேடல௠à®à®•à®¾à®©à¯</translation>
<translation id="8511402995811232419">கà¯à®•à¯à®•à¯€à®•à®³à¯ˆ நிரà¯à®µà®•à®¿à®¯à¯à®™à¯à®•à®³à¯</translation>
+<translation id="8519753333133776369">உஙà¯à®•à®³à¯ நிரà¯à®µà®¾à®•à®¿ அனà¯à®®à®¤à®¿à®¤à¯à®¤à¯à®³à¯à®³ HID சாதனமà¯</translation>
<translation id="8522552481199248698">உஙà¯à®•à®³à¯ Google கணகà¯à®•à¯ˆà®ªà¯ பாதà¯à®•à®¾à®•à¯à®•à®µà¯à®®à¯ கடவà¯à®šà¯à®šà¯Šà®²à¯à®²à¯ˆ மாறà¯à®±à®µà¯à®®à¯ Chrome உதவà¯à®®à¯.</translation>
<translation id="8530813470445476232">Chrome அமைபà¯à®ªà¯à®•à®³à®¿à®²à¯ உலாவல௠வரலாறà¯, கà¯à®•à¯à®•à¯€à®•à®³à¯ தறà¯à®•à®¾à®²à®¿à®• சேமிபà¯à®ªà¯ ஆகியவறà¯à®±à¯ˆ அழி</translation>
<translation id="8533619373899488139">தடைசெயà¯à®¯à®ªà¯à®ªà®Ÿà¯à®Ÿ URLகளின௠படà¯à®Ÿà®¿à®¯à®²à¯ˆà®¯à¯à®®à¯ உஙà¯à®•à®³à¯ சிஸà¯à®Ÿà®®à¯ நிரà¯à®µà®¾à®•à®¿ செயலà¯à®ªà®Ÿà¯à®¤à¯à®¤à®¿à®¯à¯à®³à¯à®³ பிற கொளà¯à®•à¯ˆà®•à®³à¯ˆà®¯à¯à®®à¯ பாரà¯à®•à¯à®• &lt;strong&gt;chrome://policy&lt;/strong&gt; எனà¯à®ªà®¤à®±à¯à®•à¯à®šà¯ செலà¯à®²à®µà¯à®®à¯.</translation>
@@ -2331,7 +2382,6 @@
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{அனà¯à®®à®¤à®¿à®¯à¯ˆ மீடà¯à®Ÿà®®à¯ˆ}other{அனà¯à®®à®¤à®¿à®•à®³à¯ˆ மீடà¯à®Ÿà®®à¯ˆ}}</translation>
<translation id="8555010941760982128">செகà¯-அவà¯à®Ÿà¯à®Ÿà®¿à®©à¯à®ªà¯‹à®¤à¯ இநà¯à®¤à®•à¯ கà¯à®±à®¿à®¯à¯€à®Ÿà¯à®Ÿà¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à¯à®™à¯à®•à®³à¯</translation>
<translation id="8557066899867184262">உஙà¯à®•à®³à¯ காரà¯à®Ÿà®¿à®©à¯ பினà¯à®ªà¯à®±à®¤à¯à®¤à®¿à®²à¯ CVC எண௠இரà¯à®•à¯à®•à¯à®®à¯.</translation>
-<translation id="8558485628462305855">ஆகà¯à®®à¯†à®©à¯à®Ÿà¯à®Ÿà®Ÿà¯ ரியாலிடà¯à®Ÿà®¿ உளà¯à®³à®Ÿà®•à¯à®•à®¤à¯à®¤à¯ˆà®ªà¯ பாரà¯à®•à¯à®•, ARCoreà®à®ªà¯ பà¯à®¤à¯à®ªà¯à®ªà®¿à®•à¯à®•à®µà¯à®®à¯</translation>
<translation id="8559762987265718583">உஙà¯à®•à®³à¯ சாதனதà¯à®¤à®¿à®©à¯ தேதி மறà¯à®±à¯à®®à¯ நேரம௠(<ph name="DATE_AND_TIME" />) தவறாக உளà¯à®³à®¤à®¾à®²à¯ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> கà¯à®•à®¾à®© தனிபà¯à®ªà®Ÿà¯à®Ÿ இணைபà¯à®ªà¯ˆ à®à®±à¯à®ªà®Ÿà¯à®¤à¯à®¤ à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ.</translation>
<translation id="8564182942834072828">தனிதà¯à®¤à®©à®¿ ஆவணஙà¯à®•à®³à¯/தொகà¯à®•à¯à®•à®ªà¯à®ªà®Ÿà®¾à®¤ நகலà¯à®•à®³à¯</translation>
<translation id="8564985650692024650">பிற தளஙà¯à®•à®³à®¿à®²à¯ உஙà¯à®•à®³à¯ <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> கடவà¯à®šà¯à®šà¯Šà®²à¯à®²à¯ˆ மீணà¯à®Ÿà¯à®®à¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®¿à®©à®¾à®²à¯, அதை மீடà¯à®Ÿà®®à¯ˆà®•à¯à®•à¯à®®à¯à®ªà®Ÿà®¿ Chromium பரிநà¯à®¤à¯à®°à¯ˆà®•à¯à®•à®¿à®±à®¤à¯.</translation>
@@ -2350,6 +2400,7 @@
<translation id="865032292777205197">மோஷன௠செனà¯à®šà®¾à®°à¯à®•à®³à¯</translation>
<translation id="8663226718884576429">ஆரà¯à®Ÿà®°à¯ சà¯à®°à¯à®•à¯à®•à®®à¯, <ph name="TOTAL_LABEL" />, மேலà¯à®®à¯ விவரஙà¯à®•à®³à¯</translation>
<translation id="8666678546361132282">ஆஙà¯à®•à®¿à®²à®®à¯</translation>
+<translation id="8669306706049782872">சாளரஙà¯à®•à®³à¯ˆà®¤à¯ திறநà¯à®¤à¯ வைகà¯à®• உஙà¯à®•à®³à¯ திரைகள௠கà¯à®±à®¿à®¤à¯à®¤ தகவலைப௠பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à¯à®¤à®²à¯</translation>
<translation id="867224526087042813">கையொபà¯à®ªà®®à¯</translation>
<translation id="8676424191133491403">தாமதபà¯à®ªà®Ÿà¯à®¤à¯à®¤ வேணà¯à®Ÿà®¾à®®à¯</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, பதிலà¯, <ph name="ANSWER" /></translation>
@@ -2376,6 +2427,7 @@
<translation id="8731544501227493793">’கடவà¯à®šà¯à®šà¯Šà®±à¯à®•à®³à¯ˆ நிரà¯à®µà®•à®¿â€™ படà¯à®Ÿà®©à¯, Chrome அமைபà¯à®ªà¯à®•à®³à®¿à®²à¯ கடவà¯à®šà¯à®šà¯Šà®±à¯à®•à®³à¯ˆà®ªà¯ பாரà¯à®•à¯à®•à®µà¯à®®à¯ நிரà¯à®µà®•à®¿à®•à¯à®•à®µà¯à®®à¯ Enter விசையை à®…à®´à¯à®¤à¯à®¤à¯à®™à¯à®•à®³à¯</translation>
<translation id="8734529307927223492">உஙà¯à®•à®³à¯ <ph name="DEVICE_TYPE" /> சாதனதà¯à®¤à¯ˆ <ph name="MANAGER" /> நிரà¯à®µà®•à®¿à®•à¯à®•à®¿à®±à®¤à¯</translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, தனிபà¯à®ªà®Ÿà¯à®Ÿ à®®à¯à®±à¯ˆà®¯à®¿à®²à¯ உலாவà¯à®µà®¤à®±à¯à®•à¯à®ªà¯ பà¯à®¤à®¿à®¯ மறைநிலை சாளரதà¯à®¤à¯ˆà®¤à¯ திறகà¯à®• Tab விசையை à®…à®´à¯à®¤à¯à®¤à®¿à®¯ பிறக௠Enter விசையை à®…à®´à¯à®¤à¯à®¤à¯à®™à¯à®•à®³à¯</translation>
+<translation id="8737685506611670901"><ph name="REPLACED_HANDLER_TITLE" />கà¯à®•à¯à®ªà¯ பதிலாக <ph name="PROTOCOL" /> இணைபà¯à®ªà¯à®•à®³à¯ˆà®¤à¯ திறகà¯à®•à¯à®®à¯</translation>
<translation id="8738058698779197622">பாதà¯à®•à®¾à®ªà¯à®ªà®¾à®© இணைபà¯à®ªà¯ˆ அமைகà¯à®•, கடிகாரம௠சரியாக அமைகà¯à®•à®ªà¯à®ªà®Ÿ வேணà¯à®Ÿà¯à®®à¯. இதறà¯à®•à¯à®•à¯ காரணமà¯, இணையதளஙà¯à®•à®³à¯ தஙà¯à®•à®³à¯ˆà®¤à¯ தானே அடையாளபà¯à®ªà®Ÿà¯à®¤à¯à®¤ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à¯à®®à¯ சானà¯à®±à®¿à®¤à®´à¯à®•à®³à¯ கà¯à®±à®¿à®ªà¯à®ªà®¿à®Ÿà¯à®Ÿ காலநேரதà¯à®¤à®¿à®±à¯à®•à¯‡ செலà¯à®²à¯à®ªà®Ÿà®¿à®¯à®¾à®•à¯à®®à¯. உஙà¯à®•à®³à¯ சாதனதà¯à®¤à®¿à®©à¯ கடிகாரம௠தவறாக இரà¯à®¨à¯à®¤à®¾à®²à¯, Chromium இநà¯à®¤à®šà¯ சானà¯à®±à®¿à®¤à®´à¯à®•à®³à¯ˆà®šà¯ சரிபாரà¯à®•à¯à®•à®¾à®¤à¯.</translation>
<translation id="8740359287975076522"><ph name="HOST_NAME" />’s &lt;abbr id="dnsDefinition"&gt;DNS à®®à¯à®•à®µà®°à®¿à®¯à¯ˆà®•à¯&lt;/abbr&gt; கணà¯à®Ÿà®±à®¿à®¯ à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ. சிகà¯à®•à®²à¯ˆ ஆயà¯à®µà¯ செயà¯à®•à®¿à®±à®¤à¯.</translation>
<translation id="8742371904523228557"><ph name="ORIGIN" />கà¯à®•à®¾à®© உஙà¯à®•à®³à¯ கà¯à®±à®¿à®¯à¯€à®Ÿà¯: <ph name="ONE_TIME_CODE" /></translation>
@@ -2403,6 +2455,7 @@
<translation id="883848425547221593">மறà¯à®± பà¯à®•à¯à®®à®¾à®°à¯à®•à¯à®•à¯à®•à®³à¯</translation>
<translation id="884264119367021077">ஷிபà¯à®ªà®¿à®™à¯ à®®à¯à®•à®µà®°à®¿</translation>
<translation id="884923133447025588">திரà¯à®®à¯à®ªà®ªà¯à®ªà¯†à®±à¯à®¤à®²à¯ செயலà¯à®®à¯à®±à¯ˆ காணபà¯à®ªà®Ÿà®µà®¿à®²à¯à®²à¯ˆ.</translation>
+<translation id="8849262850971482943">கூடà¯à®¤à®²à¯ பாதà¯à®•à®¾à®ªà¯à®ªà®¿à®±à¯à®•à¯ விரà¯à®šà¯à®šà¯à®µà®²à¯ காரà¯à®Ÿà¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®µà¯à®®à¯</translation>
<translation id="885730110891505394">Google உடன௠பகிரà¯à®ªà®µà¯ˆ</translation>
<translation id="8858065207712248076">பிற தளஙà¯à®•à®³à®¿à®²à¯ உஙà¯à®•à®³à¯ <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> கடவà¯à®šà¯à®šà¯Šà®²à¯à®²à¯ˆ மீணà¯à®Ÿà¯à®®à¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®¿à®©à®¾à®²à¯, அதை மீடà¯à®Ÿà®®à¯ˆà®•à¯à®•à¯à®®à¯à®ªà®Ÿà®¿ Chrome பரிநà¯à®¤à¯à®°à¯ˆà®•à¯à®•à®¿à®±à®¤à¯.</translation>
<translation id="885906927438988819">எழà¯à®¤à¯à®¤à¯à®ªà¯à®ªà®¿à®´à¯ˆ இலà¯à®²à¯ˆà®¯à¯†à®©à®¿à®²à¯ <ph name="BEGIN_LINK" />Windows நெடà¯à®µà¯Šà®°à¯à®•à¯ சரிபாரà¯à®ªà¯à®ªà¯ˆ இயகà¯à®•à®¿à®ªà¯ பாரà¯à®•à¯à®•à®µà¯à®®à¯<ph name="END_LINK" />.</translation>
@@ -2452,6 +2505,7 @@
<translation id="9004367719664099443">VR அமரà¯à®µà¯ செயலà¯à®ªà®¾à®Ÿà¯à®Ÿà®¿à®²à¯à®³à¯à®³à®¤à¯</translation>
<translation id="9005998258318286617">PDF ஆவணதà¯à®¤à¯ˆ à®à®±à¯à®± à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ.</translation>
<translation id="9008201768610948239">பà¯à®±à®•à¯à®•à®£à®¿</translation>
+<translation id="901834265349196618">மினà¯à®©à®žà¯à®šà®²à¯</translation>
<translation id="9020200922353704812">காரà¯à®Ÿà¯ பிலà¯à®²à®¿à®™à¯ à®®à¯à®•à®µà®°à®¿ தேவை</translation>
<translation id="9020542370529661692">இநà¯à®¤à®ªà¯ பகà¯à®•à®®à¯ <ph name="TARGET_LANGUAGE" /> கà¯à®•à¯ மொழிபெயரà¯à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯</translation>
<translation id="9020742383383852663">A8</translation>
@@ -2501,6 +2555,7 @@
<translation id="9150045010208374699">உஙà¯à®•à®³à¯ கேமராவைப௠பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®²à®¾à®®à¯</translation>
<translation id="9150685862434908345">உலாவியின௠அமைவை உஙà¯à®•à®³à¯ நிரà¯à®µà®¾à®•à®¿à®¯à®¾à®²à¯ தொலைநிலையிலிரà¯à®¨à¯à®¤à¯‡ மாறà¯à®± à®®à¯à®Ÿà®¿à®¯à¯à®®à¯. இநà¯à®¤à®šà¯ சாதனதà¯à®¤à®¿à®©à¯ செயலà¯à®ªà®¾à®Ÿà¯à®•à®³à¯ˆ Chromeà®®à¯à®•à¯à®•à¯ வெளியிலிரà¯à®¨à¯à®¤à¯à®®à¯ நிரà¯à®µà®•à®¿à®•à¯à®•à®²à®¾à®®à¯. <ph name="BEGIN_LINK" />மேலà¯à®®à¯ அறிக<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">பà¯à®¤à¯à®ªà¯à®ªà®¿à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà®¤à¯</translation>
+<translation id="9155211586651734179">இணைகà¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³ ஆடியோ சாதனஙà¯à®•à®³à¯</translation>
<translation id="9157595877708044936">அமைகà¯à®•à®¿à®±à®¤à¯...</translation>
<translation id="9158625974267017556">C6 (எனà¯à®µà®²à®ªà¯)</translation>
<translation id="9164029392738894042">தà¯à®²à¯à®²à®¿à®¯à®¤à¯à®¤à®©à¯à®®à¯ˆà®šà¯ சரிபாரà¯à®ªà¯à®ªà¯</translation>
@@ -2546,7 +2601,7 @@
&lt;p&gt;இநà¯à®¤à®ªà¯ பிழையைச௠சரிசெயà¯à®¯, உஙà¯à®•à®³à¯ சாதனதà¯à®¤à®¿à®©à¯ கடிகாரதà¯à®¤à¯ˆà®¤à¯ திறகà¯à®•à®µà¯à®®à¯. நேரமà¯à®®à¯ தேதியà¯à®®à¯ சரியாக இரà¯à®ªà¯à®ªà®¤à¯ˆ உறà¯à®¤à®¿à®ªà¯à®ªà®Ÿà¯à®¤à¯à®¤à®µà¯à®®à¯.&lt;/p&gt;</translation>
<translation id="985956168329721395">Prc-32K</translation>
<translation id="987264212798334818">பொதà¯</translation>
-<translation id="988159990683914416">டெவலபà¯à®ªà®°à¯ கடà¯à®Ÿà®®à¯ˆà®ªà¯à®ªà¯</translation>
+<translation id="988159990683914416">டெவெலபà¯à®ªà®°à¯ கடà¯à®Ÿà®®à¯ˆà®ªà¯à®ªà¯</translation>
<translation id="989988560359834682">à®®à¯à®•à®µà®°à®¿à®¯à¯ˆà®¤à¯ திரà¯à®¤à¯à®¤à¯</translation>
<translation id="991413375315957741">மோஷன௠அலà¯à®²à®¤à¯ ஒளி செனà¯à®šà®¾à®°à¯à®•à®³à¯</translation>
<translation id="992115559265932548"><ph name="MICROSOFT_ACTIVE_DIRECTORY" /></translation>
diff --git a/chromium/components/strings/components_strings_te.xtb b/chromium/components/strings/components_strings_te.xtb
index 558c0c2c620..82e2b76865c 100644
--- a/chromium/components/strings/components_strings_te.xtb
+++ b/chromium/components/strings/components_strings_te.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">వివరాలనౠచూడండి</translation>
<translation id="1030706264415084469">డేటానౠమీ పరికరంలో అధిక మొతà±à°¤à°‚లో, శాశà±à°µà°¤à°‚à°—à°¾ నిలà±à°µ చేయాలని <ph name="URL" /> à°…à°¨à±à°•à±à°‚టోంది</translation>
<translation id="1032854598605920125">సవà±à°¯à°¦à°¿à°¶à°²à±‹ తిపà±à°ªà±</translation>
+<translation id="1033329911862281889">à°…à°œà±à°žà°¾à°¤ మోడà±â€Œà°¨à± ఉపయోగిసà±à°¤à±à°¨à±à°¨à°‚à°¤ మాతà±à°°à°¾à°¨ మీరౠఆనà±â€Œà°²à±ˆà°¨à±â€Œà°²à±‹ ఇతరà±à°²à°•à± కనపడరని à°…à°°à±à°§à°‚ కాదà±:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />వారౠఉపయోగించే సైటà±â€Œà°²à±, సరà±à°µà±€à°¸à±â€Œà°²à± వారి సందరà±à°¶à°¨à°²à°¨à± చూడగలవà±<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />యాజమానà±à°¯ సంసà±à°¥à°²à± లేదా పాఠశాలలౠబà±à°°à±Œà°œà°¿à°‚గౠయాకà±à°Ÿà°¿à°µà°¿à°Ÿà±€à°¨à°¿ à°Ÿà±à°°à°¾à°•à± చేయగలవà±<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ఇంటరà±à°¨à±†à°Ÿà± సరà±à°µà±€à°¸à± à°ªà±à°°à±Šà°µà±ˆà°¡à°°à±â€Œà°²à± వెబౠటà±à°°à°¾à°«à°¿à°•à±â€Œà°¨à± మానిటరౠచేయగలవà±<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">ఆఫౠచేయి</translation>
<translation id="1036982837258183574">à°«à±à°²à±-à°¸à±à°•à±à°°à±€à°¨à±â€Œâ€Œ à°¨à±à°‚à°¡à°¿ నిషà±à°•à±à°°à°®à°¿à°‚చడానికి |<ph name="ACCELERATOR" />| నొకà±à°•à°‚à°¡à°¿</translation>
<translation id="1038106730571050514">సూచనలనౠచూపà±</translation>
<translation id="1038842779957582377">తెలియని పేరà±</translation>
<translation id="1041998700806130099">జాబౠషీటౠమెసేజà±â€Œ</translation>
<translation id="1048785276086539861">మీరౠఅదనపౠగమనికలనౠఎడిటౠచేసినపà±à°ªà±à°¡à±, à°ˆ డాకà±à°¯à±à°®à±†à°‚టౠసింగిలౠపేజీ వీకà±à°·à°£à°•à± తిరిగి వసà±à°¤à±à°‚ది</translation>
-<translation id="1049743911850919806">à°…à°œà±à°žà°¾à°¤ మోడà±</translation>
<translation id="1050038467049342496">ఇతర యాపà±â€Œà°²à°¨à± మూసివేయండి</translation>
<translation id="1055184225775184556">&amp;జోడించడానà±à°¨à°¿ à°°à°¦à±à°¦à± చేయి</translation>
<translation id="1056898198331236512">హెచà±à°šà°°à°¿à°•</translation>
@@ -39,7 +44,7 @@
<translation id="1089439967362294234">పాసà±â€Œà°µà°°à±à°¡à±â€Œà°¨à°¿ మారà±à°šà±</translation>
<translation id="1096545575934602868">à°ˆ ఫీలà±à°¡à±â€Œà°²à±‹ <ph name="MAX_ITEMS_LIMIT" /> కంటే à°Žà°•à±à°•à±à°µ నమోదà±à°²à± ఉండకూడదà±. తదà±à°ªà°°à°¿ à°…à°¨à±à°¨à°¿ నమోదà±à°²à± విసà±à°®à°°à°¿à°‚చబడతాయి.</translation>
<translation id="1100782917270858593">'మీ సెరà±à°šà±â€Œà°¨à± కొనసాగించండి' బటనà±, మీ సెరà±à°šà±â€Œà°¨à± కొనసాగించడానికి Enterనౠనొకà±à°•à°‚à°¡à°¿, మీ Chrome హిసà±à°Ÿà°°à±€à°²à±‹ సందరà±à°­à±‹à°šà°¿à°¤à°®à±ˆà°¨ యాకà±à°Ÿà°¿à°µà°¿à°Ÿà±€à°¨à°¿ చూడండి</translation>
-<translation id="1101672080107056897">అమలà±à°²à±‹ లోపం</translation>
+<translation id="1101672080107056897">అమలà±à°²à±‹ à°Žà°°à±à°°à°°à±</translation>
<translation id="1103523840287552314"><ph name="LANGUAGE" />‌నౠఎలà±à°²à°ªà±à°ªà±à°¡à±‚ à°…à°¨à±à°µà°¦à°¿à°‚à°šà°‚à°¡à°¿</translation>
<translation id="1110994991967754504"><ph name="PERMISSION_NAME" /> కోసం à°…à°¨à±à°®à°¤à°¿à°¨à°¿ à°Žà°‚à°šà±à°•à±‹à°‚à°¡à°¿</translation>
<translation id="1113869188872983271">&amp;మళà±à°²à±€ à°•à±à°°à°®à°‚ చేయడానà±à°¨à°¿ à°°à°¦à±à°¦à± చేయి</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">విధాన కాషౠసరిపోయింది</translation>
<translation id="1130564665089811311">'పేజీని à°…à°¨à±à°µà°¦à°¿à°‚à°šà±' బటనà±, à°ˆ పేజీని Google Translateతో à°…à°¨à±à°µà°¦à°¿à°‚చేందà±à°•à± 'Enter' నొకà±à°•à°‚à°¡à°¿</translation>
<translation id="1131264053432022307">మీరౠకాపీ చేసిన à°šà°¿à°¤à±à°°à°‚</translation>
+<translation id="1142846828089312304">à°…à°œà±à°žà°¾à°¤ మోడà±â€Œà°²à±‹ థరà±à°¡à±-పారà±à°Ÿà±€ à°•à±à°•à±à°•à±€à°²à°¨à± à°¬à±à°²à°¾à°•à± చేయండి</translation>
<translation id="1150979032973867961">à°ˆ సరà±à°µà°°à± <ph name="DOMAIN" /> అని నిరూపించà±à°•à±‹à°²à±‡à°•à°ªà±‹à°¯à°¿à°‚ది; దీని à°­à°¦à±à°°à°¤à°¾ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°¾à°¨à±à°¨à°¿ మీ à°•à°‚à°ªà±à°¯à±‚టరౠఆపరేటింగౠసిసà±à°Ÿà°®à± విశà±à°µà°¸à°¿à°‚చలేదà±. ఇది తపà±à°ªà±à°—à°¾ కానà±à°«à°¿à°—రౠచేయడం వలన లేదా దాడిచేసే à°µà±à°¯à°•à±à°¤à°¿ మీ కనెకà±à°·à°¨à±â€Œà°•à± అంతరాయం కలిగించడం వలన జరిగి ఉండవచà±à°šà±.</translation>
<translation id="1151972924205500581">పాసà±â€Œà°µà°°à±à°¡à± అవసరం</translation>
<translation id="1156303062776767266">మీరౠసà±à°¥à°¾à°¨à°¿à°• లేదా షేరౠచేసిన ఫైలà±â€Œà°¨à± చూసà±à°¤à±à°¨à±à°¨à°¾à°°à±</translation>
@@ -64,7 +70,6 @@
<translation id="1178581264944972037">పాజౠచేయి</translation>
<translation id="1181037720776840403">తీసివేయి</translation>
<translation id="1186201132766001848">పాసà±â€Œà°µà°°à±à°¡à±â€Œà°²à°¨à± చెకౠచేయండి</translation>
-<translation id="1195210374336998651">యాపౠసెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²à°•à± వెళà±à°²à°‚à°¡à°¿</translation>
<translation id="1195558154361252544">మీరౠఅనà±à°®à°¤à°¿à°‚చినవి మినహా, ఇతర à°…à°¨à±à°¨à°¿ సైటà±â€Œà°²à°•à± నోటిఫికేషనà±â€Œà°²à± ఆటోమేటికà±â€Œà°—à°¾ à°¬à±à°²à°¾à°•à± చేయబడà±à°¡à°¾à°¯à°¿</translation>
<translation id="1197088940767939838">నారింజ à°°à°‚à°—à±</translation>
<translation id="1201402288615127009">తరà±à°µà°¾à°¤</translation>
@@ -84,7 +89,7 @@
<translation id="1243027604378859286">రచయిత:</translation>
<translation id="1246424317317450637">బోలà±à°¡à±</translation>
<translation id="1248573052514400575"><ph name="MANAGE_CHROMEOS_ACCESSIBILITY_FOCUSED_FRIENDLY_MATCH_TEXT" />, Chrome OS సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²à°²à±‹ మీ యాకà±à°¸à±†à°¸à°¿à°¬à°¿à°²à°¿à°Ÿà±€ టూలà±à°¸à±â€Œà°¨à± à°µà±à°¯à°•à±à°¤à°¿à°—తీకరించడానికి 'Tab'నౠనొకà±à°•à°¿, ఆపై 'Enter'నౠనొకà±à°•à°‚à°¡à°¿</translation>
-<translation id="1250759482327835220">తరà±à°µà°¾à°¤à°¿à°¸à°¾à°°à°¿ మరింత వేగంగా చెలà±à°²à°¿à°‚చడానికి, మీ కారà±à°¡à±, పేరౠమరియౠబిలà±à°²à°¿à°‚à°—à± à°…à°¡à±à°°à°¸à±â€Œà°¨à± మీ Google ఖాతాకౠసేవౠచేయండి.</translation>
+<translation id="1250759482327835220">తరà±à°µà°¾à°¤à°¿à°¸à°¾à°°à°¿ మరింత వేగంగా పేమెంటౠచేయడానికి, మీ కారà±à°¡à±, పేరౠమరియౠబిలà±à°²à°¿à°‚à°—à± à°…à°¡à±à°°à°¸à±â€Œà°¨à± మీ Google ఖాతాకౠసేవౠచేయండి.</translation>
<translation id="1252799212227771492">'షీటà±â€Œà°¨à± à°•à±à°°à°¿à°¯à±‡à°Ÿà± చేయండి' బటనà±, కొతà±à°¤ Google షీటà±â€Œà°¨à± à°¤à±à°µà°°à°—à°¾ à°•à±à°°à°¿à°¯à±‡à°Ÿà± చేయడానికి Enterనౠనొకà±à°•à°‚à°¡à°¿</translation>
<translation id="1253921432148366685"><ph name="TYPE_1" />, <ph name="TYPE_2" /> (సమకాలీకరించబడà±à°¡à°¾à°¯à°¿)</translation>
<translation id="1256368399071562588">&lt;p&gt;మీరౠà°à°¦à±ˆà°¨à°¾ వెబà±â€Œà°¸à±ˆà°Ÿà±â€Œà°¨à± తెరవడానికి à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚చినపà±à°ªà±à°¡à±, అది తెరవబడకà±à°‚టే, à°®à±à°‚à°¦à±à°—à°¾ à°ˆ సమసà±à°¯ నివారణ à°ªà±à°°à°•à±à°°à°¿à°¯ దశలనౠఉపయోగించి à°Žà°°à±à°°à°°à±â€Œà°¨à± పరిషà±à°•à°°à°¿à°‚చడానికి à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚à°šà°‚à°¡à°¿:&lt;/p&gt;
@@ -111,7 +116,7 @@
<translation id="1307966114820526988">విసà±à°®à°°à°¿à°‚చబడిన ఫీచరà±â€Œà°²à±</translation>
<translation id="1308113895091915999">ఆఫరౠఅందà±à°¬à°¾à°Ÿà±à°²à±‹ ఉంది</translation>
<translation id="1312803275555673949">సమాచారం సరైనదనడానికి ఆధారాలౠà°à°‚à°Ÿà°¿?</translation>
-<translation id="131405271941274527">మీరౠNFC పరికరంలో మీ ఫోనà±â€Œà°ªà±ˆ నొకà±à°•à°¿à°¨à°ªà±à°ªà±à°¡à± సమాచారం పంపడానికి, à°…à°‚à°¦à±à°•à±‹à°µà°¡à°¾à°¨à°¿à°•à°¿ <ph name="URL" /> à°…à°¨à±à°®à°¤à°¿ కోరà±à°¤à±‹à°‚ది</translation>
+<translation id="1314311879718644478">à°…à°—à±â€Œà°®à±†à°‚టెడౠరియాలిటీ కంటెంటà±â€Œà°¨à± చూడండి</translation>
<translation id="1314509827145471431">à°•à±à°¡à°¿à°µà±ˆà°ªà±à°¨ బైండà±</translation>
<translation id="1318023360584041678">à°Ÿà±à°¯à°¾à°¬à± à°—à±à°°à±‚à°ªà±â€Œà°²à±‹ సేవౠచేయబడింది</translation>
<translation id="1319245136674974084">à°ˆ యాపà±â€Œ కోసం మళà±à°²à±€ అడగవదà±à°¦à±</translation>
@@ -163,6 +168,7 @@
<translation id="142858679511221695">à°•à±à°²à±Œà°¡à± యూజరà±</translation>
<translation id="1428729058023778569">à°ˆ సైటౠHTTPS‌కౠసపోరà±à°Ÿà± చేయనందà±à°¨ మీరౠఈ హెచà±à°šà°°à°¿à°•à°¨à± చూసà±à°¤à±à°¨à±à°¨à°¾à°°à±. <ph name="BEGIN_LEARN_MORE_LINK" />మరింత తెలà±à°¸à±à°•à±‹à°‚à°¡à°¿<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">à°ªà±à°°à°¿à°‚à°Ÿà±</translation>
+<translation id="1432187715652018471">సరà±à°µà±€à°¸à± à°¹à±à°¯à°¾à°‚à°¡à±à°²à°°à±â€Œà°¨à± ఇనà±â€Œà°¸à±à°Ÿà°¾à°²à± చేయమని పేజీ కోరà±à°¤à±‹à°‚ది.</translation>
<translation id="1432581352905426595">సెరà±à°šà± ఇంజినà±â€Œà°²à°¨à± మేనేజౠచేయండి</translation>
<translation id="1436185428532214179">మీ పరికరంలో ఫైళà±à°²à±, అలాగే ఫోలà±à°¡à°°à±â€Œà°²à°¨à± ఎడిటౠచేయడానికి సైటౠఅనà±à°®à°¤à°¿ అడగవచà±à°šà±</translation>
<translation id="1442386063175183758">à°•à±à°¡à°¿à°µà±ˆà°ªà± గేటౠఫోలà±à°¡à±</translation>
@@ -183,6 +189,12 @@
<translation id="1483493594462132177">పంపà±</translation>
<translation id="1484290072879560759">à°·à°¿à°ªà±à°ªà°¿à°‚à°—à± à°…à°¡à±à°°à°¸à±â€Œà°¨à± à°Žà°‚à°šà±à°•à±‹à°‚à°¡à°¿</translation>
<translation id="1492194039220927094">విధానాలనౠపà±à°·à± చేయి:</translation>
+<translation id="149293076951187737">మీరౠఅనà±à°¨à°¿ Chrome à°…à°œà±à°žà°¾à°¤ à°Ÿà±à°¯à°¾à°¬à±â€Œà°²à°¨à± మూసివేసినపà±à°ªà±à°¡à±, à°† à°Ÿà±à°¯à°¾à°¬à±â€Œà°²à°²à±‹à°¨à°¿ మీ యాకà±à°Ÿà°¿à°µà°¿à°Ÿà±€ à°ˆ పరికరం à°¨à±à°‚à°¡à°¿ తీసివేయబడà±à°¤à±à°‚ది:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />à°¬à±à°°à±Œà°œà°¿à°‚గౠయాకà±à°Ÿà°¿à°µà°¿à°Ÿà±€<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />సెరà±à°šà± హిసà±à°Ÿà°°à±€<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ఫారమà±â€Œà°²à°²à±‹ ఎంటరౠచేసిన సమాచారం<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">తిరిగి à°Ÿà±à°¯à°¾à°¬à±â€Œà°•à± వెళà±à°²à±</translation>
<translation id="1501859676467574491">మీ Google ఖాతా à°¨à±à°‚à°¡à°¿ కారà±à°¡à±â€Œà°²à°¨à± చూపండి</translation>
<translation id="1507202001669085618">&lt;p&gt;ఆనà±â€Œà°²à±ˆà°¨à±â€Œà°•à± వెళà±à°²à°¡à°‚ కంటే à°®à±à°‚దౠసైనౠఇనౠచేయాలà±à°¸à°¿à°¨ అవసరం ఉనà±à°¨ Wi-Fi పోరà±à°Ÿà°²à±â€Œà°¨à± మీరౠఉపయోగిసà±à°¤à±à°¨à±à°¨à°Ÿà±à°²à°¯à°¿à°¤à±‡ మీకౠఈ à°Žà°°à±à°°à°°à± కనిపిసà±à°¤à±à°‚ది.&lt;/p&gt;
@@ -210,6 +222,8 @@
<translation id="1559572115229829303">&lt;p&gt;మీ పరికరం తేదీ మరియౠసమయం తపà±à°ªà±à°—à°¾ (<ph name="DATE_AND_TIME" />) ఉనà±à°¨à°‚à°¦à±à°¨, <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />à°•à± à°ªà±à°°à±ˆà°µà±‡à°Ÿà± కనెకà±à°·à°¨à± à°à°°à±à°ªà°¾à°Ÿà± చేయడం సాధà±à°¯à°ªà°¡à°²à±‡à°¦à±.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²à±&lt;/strong&gt; యాపౠయొకà±à°• &lt;strong&gt;సాధారణం&lt;/strong&gt; విభాగంలో తేదీ మరియౠసమయానà±à°¨à°¿ దయచేసి సరà±à°¦à±à°¬à°¾à°Ÿà± చేయండి.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">మీ à°…à°¡à±à°®à°¿à°¨à°¿à°¸à±à°Ÿà±à°°à±‡à°Ÿà°°à± మీ పరికరానà±à°¨à°¿ <ph name="DATE" />à°¨ <ph name="TIME" />కౠరీసà±à°Ÿà°¾à°°à±à°Ÿà± చేసà±à°¤à°¾à°°à±</translation>
+<translation id="156703335097561114">à°…à°¡à±à°°à°¸à±â€Œà°²à±, ఇంటరà±â€Œà°«à±‡à°¸à± కానà±à°«à°¿à°—రేషనà±, కనెకà±à°·à°¨à± à°•à±à°µà°¾à°²à°¿à°Ÿà±€ వంటి నెటà±â€Œà°µà°°à±à°•à°¿à°‚గౠసమాచారం</translation>
<translation id="1567040042588613346">à°ˆ పాలసీ à°…à°¨à±à°•à±à°¨à±à°¨à°Ÿà±à°Ÿà±à°—à°¾ పని చేసà±à°¤à±‹à°‚ది, కానీ అదే విలà±à°µ మరో చోట సెటౠచేయబడింది, అలాగే à°ˆ పాలసీ à°¦à±à°µà°¾à°°à°¾ అధిగమించబడింది.</translation>
<translation id="1569487616857761740">à°—à°¡à±à°µà± à°®à±à°—ింపౠతేదీని నమోదౠచేయండి</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -217,6 +231,7 @@
<translation id="1583429793053364125">à°ˆ వెబౠపేజీని à°ªà±à°°à°¦à°°à±à°¶à°¿à°¸à±à°¤à±à°¨à±à°¨à°ªà±à°ªà±à°¡à± à°à°¦à±‹ తపà±à°ªà± జరిగింది.</translation>
<translation id="1586541204584340881">మీరౠఠఎకà±à°¸à±â€Œà°Ÿà±†à°¨à±à°·à°¨à±â€Œà°²à°¨à± ఇనౠసà±à°Ÿà°¾à°²à± చేసà±à°•à±à°¨à±à°¨à°¾à°°à±</translation>
<translation id="1588438908519853928">సాధారణ</translation>
+<translation id="1589050138437146318">ARCoreనౠఇనà±â€Œà°¸à±à°Ÿà°¾à°²à± చేయాలా?</translation>
<translation id="1592005682883173041">à°¸à±à°¥à°¾à°¨à°¿à°• డేటా యాకà±à°¸à±†à°¸à±</translation>
<translation id="1594030484168838125">à°Žà°‚à°šà±à°•à±‹à°‚à°¡à°¿</translation>
<translation id="160851722280695521">Chromeలో Dino Run గేమà±â€Œà°¨à± ఆడండి</translation>
@@ -285,6 +300,7 @@
హెడరౠతపà±à°ªà±à°—à°¾ సెటౠచేయబడింది, దాని వలన <ph name="SITE" />కౠమీరౠపంపిన à°°à°¿à°•à±à°µà±†à°¸à±à°Ÿà±â€Œà°¨à±
à°¬à±à°°à±Œà°œà°°à± పూరà±à°¤à°¿ చేయలేకపోతోంది. à°­à°¦à±à°°à°¤à°¨à±, సైటౠఇతర à°ªà±à°°à°¾à°ªà°°à±à°Ÿà±€â€Œà°²à°¨à±
కానà±à°«à°¿à°—రౠచేయడానికి సైటౠఆపరేటరà±â€Œà°²à± ఆరిజినౠపాలసీలనౠఉపయోగించవచà±à°šà±.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Chromiumలో à°…à°œà±à°žà°¾à°¤ మోడౠగà±à°°à°¿à°‚à°šà°¿ మరింత తెలà±à°¸à±à°•à±‹à°‚à°¡à°¿<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">మీ తెరవబడిన à°Ÿà±à°¯à°¾à°¬à±â€Œà°²à± ఇకà±à°•à°¡ కనిపిసà±à°¤à°¾à°¯à°¿</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -412,6 +428,7 @@
<translation id="22081806969704220">à°Ÿà±à°°à±‡ 3</translation>
<translation id="2212735316055980242">విధానం à°•à°¨à±à°—ొనబడలేదà±</translation>
<translation id="2213606439339815911">నమోదà±à°²à°¨à± పొందà±à°¤à±‹à°‚ది...</translation>
+<translation id="2213612003795704869">పేజీ à°ªà±à°°à°¿à°‚టౠచేయబడింది</translation>
<translation id="2215727959747642672">ఫైలà±â€Œà°¨à± సవరించడం</translation>
<translation id="2218879909401188352"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />లోని à°¹à±à°¯à°¾à°•à°°à±â€Œà°²à± మీ పరికరంలో హానికరమైన యాపà±â€Œà°²à°¨à± ఇనà±â€Œà°¸à±à°Ÿà°¾à°²à± చేయవచà±à°šà±. మీ మొబైలౠబిలà±â€Œà°²à±‹ అదృశà±à°¯ ఛారà±à°œà±€à°²à°•à± కారణం కావచà±à°šà± లేదా మీ à°µà±à°¯à°•à±à°¤à°¿à°—à°¤ సమాచారానà±à°¨à°¿ దొంగిలించవచà±à°šà±. <ph name="BEGIN_LEARN_MORE_LINK" />మరింత తెలà±à°¸à±à°•à±‹à°‚à°¡à°¿<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">ఇంటరà±à°¨à±†à°Ÿà± లేదà±</translation>
@@ -421,8 +438,9 @@
<translation id="2248949050832152960">WebAuthnనౠఉపయోగించండి</translation>
<translation id="2250931979407627383">ఎడమవైపౠకà±à°Ÿà±à°Ÿà°¿à°¨ à°…à°‚à°šà±</translation>
<translation id="225207911366869382">à°ˆ విధానం కోసం à°ˆ విలà±à°µ విసà±à°®à°°à°¿à°‚చబడింది.</translation>
+<translation id="2256115617011615191">ఇపà±à°ªà±à°¡à±‡ à°ªà±à°¨à°ƒà°ªà±à°°à°¾à°°à°‚à°­à°¿à°‚à°šà±</translation>
<translation id="2258928405015593961">భవిషà±à°¯à°¤à±à°¤à±à°²à±‹à°¨à°¿ à°—à°¡à±à°µà± à°®à±à°—ింపౠతేదీని నమోదౠచేసి, మళà±à°²à±€ à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚à°šà°‚à°¡à°¿</translation>
-<translation id="225943865679747347">లోపం కోడà±: <ph name="ERROR_CODE" /></translation>
+<translation id="225943865679747347">à°Žà°°à±à°°à°°à± కోడà±: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">HTTP à°Žà°°à±à°°à°°à±</translation>
<translation id="2267047181501709434">మీ à°—à±à°°à±à°¤à°¿à°‚à°ªà±à°¨à± ధృవీకరిసà±à°¤à±‹à°‚ది...</translation>
<translation id="2270484714375784793">ఫోనౠనంబరà±</translation>
@@ -448,6 +466,7 @@
<translation id="2337852623177822836">సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°¨à± మీ నిరà±à°µà°¾à°¹à°•à±à°²à± నియంతà±à°°à°¿à°¸à±à°¤à±à°¨à±à°¨à°¾à°°à±</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> దీనితో జత చేయాలనà±à°•à±à°‚టోంది</translation>
<translation id="2346319942568447007">మీరౠకాపీ చేసిన à°šà°¿à°¤à±à°°à°‚</translation>
+<translation id="2350796302381711542"><ph name="REPLACED_HANDLER_TITLE" />à°•à°¿ బదà±à°²à±à°—à°¾ à°…à°¨à±à°¨à°¿ <ph name="PROTOCOL" /> లింకà±â€Œà°²à°¨à± తెరవడానికి <ph name="HANDLER_HOSTNAME" />నౠఅనà±à°®à°¤à°¿à°‚చాలా?</translation>
<translation id="2354001756790975382">ఇతర à°¬à±à°•à±â€Œà°®à°¾à°°à±à°•à±â€Œà°²à±</translation>
<translation id="2354430244986887761">Google à°¸à±à°°à°•à±à°·à°¿à°¤ à°¬à±à°°à±Œà°œà°¿à°‚గౠఇటీవల <ph name="SITE" />లో <ph name="BEGIN_LINK" />హానికర యాపà±â€Œà°²à°¨à± à°•à°¨à±à°—ొంది<ph name="END_LINK" />.</translation>
<translation id="2355395290879513365">దాడికి పాలà±à°ªà°¡à±‡à°µà°¾à°°à± à°ˆ సైటà±â€Œà°²à±‹ మీరౠచూసà±à°¤à±à°¨à±à°¨ à°šà°¿à°¤à±à°°à°¾à°²à°¨à± చూడగలరà±, వాటిని సవరించడం à°¦à±à°µà°¾à°°à°¾ మిమà±à°®à°²à±à°¨à°¿ మోసగించవచà±à°šà±.</translation>
@@ -473,6 +492,7 @@
<translation id="2413528052993050574">à°ˆ సరà±à°µà°°à± <ph name="DOMAIN" /> అని నిరూపించà±à°•à±‹à°²à±‡à°•à°ªà±‹à°¯à°¿à°‚ది; దీని à°­à°¦à±à°°à°¤à°¾ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ ఉపసంహరించబడి ఉండవచà±à°šà±. ఇది తపà±à°ªà±à°—à°¾ కానà±à°«à°¿à°—రౠచేయడం వలన లేదా దాడిచేసే à°µà±à°¯à°•à±à°¤à°¿ మీ కనెకà±à°·à°¨à±â€Œà°•à± అంతరాయం కలిగించడం వలన జరిగి ఉండవచà±à°šà±.</translation>
<translation id="2414886740292270097">à°®à±à°¦à±à°°à±</translation>
<translation id="2430968933669123598">Google ఖాతానౠమేనేజౠచేయండి, మీ Google ఖాతాలో మీ సమాచారం, గోపà±à°¯à°¤, ఇంకా à°­à°¦à±à°°à°¤à°¨à± మేనేజౠచేయడం కోసం Enterనౠనొకà±à°•à°‚à°¡à°¿</translation>
+<translation id="2436186046335138073">à°…à°¨à±à°¨à°¿ <ph name="PROTOCOL" /> లింకà±â€Œà°²à°¨à± తెరవడానికి <ph name="HANDLER_HOSTNAME" />నౠఅనà±à°®à°¤à°¿à°‚చాలా?</translation>
<translation id="2438874542388153331">à°•à±à°¡à°¿à°µà±ˆà°ªà± నాలà±à°—à± à°°à°‚à°§à±à°°à°¾à°²à±</translation>
<translation id="2450021089947420533">Chrome హిసà±à°Ÿà°°à±€à°²à±‹ మీ యాకà±à°Ÿà°¿à°µà°¿à°Ÿà±€à°²à±</translation>
<translation id="2463739503403862330">పూరించà±</translation>
@@ -480,6 +500,7 @@
<translation id="2465655957518002998">బటà±à°µà°¾à°¡à°¾ పదà±à°§à°¤à°¿à°¨à°¿ à°Žà°‚à°šà±à°•à±‹à°‚à°¡à°¿</translation>
<translation id="2465688316154986572">à°¸à±à°Ÿà±‡à°ªà±à°²à±</translation>
<translation id="2465914000209955735">Chromeలో మీరౠడౌనà±â€Œà°²à±‹à°¡à± చేసిన ఫైలà±â€Œà°²à°¨à± మేనేజౠచేయండి</translation>
+<translation id="2466004615675155314">వెబౠనà±à°‚à°¡à°¿ సమాచారానà±à°¨à°¿ చూపించà±</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />నెటà±â€Œà°µà°°à±à°•à± సమసà±à°¯ విశà±à°²à±‡à°·à°£à°²à°¨à± అమలౠచేయడం<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">1-à°¨à±à°‚à°¡à°¿-N వరకౠఉనà±à°¨ à°•à±à°°à°®à°‚</translation>
<translation id="2470767536994572628">మీరౠఅదనపౠగమనికలనౠఎడిటౠచేసినపà±à°ªà±à°¡à±, à°ˆ డాకà±à°¯à±à°®à±†à°‚టౠసింగిలౠపేజీ వీకà±à°·à°£à°•à±, అలాగే దాని ఒరిజినలౠరొటేషనà±â€Œà°•à± తిరిగి వసà±à°¤à±à°‚ది</translation>
@@ -500,6 +521,7 @@
<translation id="2523886232349826891">à°ˆ పరికరంలో మాతà±à°°à°®à±‡ సేవౠచేయబడి ఉంటà±à°‚ది</translation>
<translation id="2524461107774643265">మరింత సమాచారానà±à°¨à°¿ జోడించండి</translation>
<translation id="2529899080962247600">à°ˆ ఫీలà±à°¡à±â€Œà°²à±‹ <ph name="MAX_ITEMS_LIMIT" /> కంటే à°Žà°•à±à°•à±à°µ à°Žà°‚à°Ÿà±à°°à±€à°²à± ఉండకూడదà±. à°…à°¨à±à°¨à°¿ తదà±à°ªà°°à°¿ à°Žà°‚à°Ÿà±à°°à±€à°²à± విసà±à°®à°°à°¿à°‚చబడతాయి.</translation>
+<translation id="2535585790302968248">à°ªà±à°°à±ˆà°µà±‡à°Ÿà±â€Œà°—à°¾ à°¬à±à°°à±Œà°œà± చేయడానికి కొతà±à°¤ à°…à°œà±à°žà°¾à°¤ à°Ÿà±à°¯à°¾à°¬à±â€Œà°¨à± తెరవండి</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{మరియౠమరో 1}other{మరియౠమరో #}}</translation>
<translation id="2536110899380797252">à°…à°¡à±à°°à°¸à±â€Œà°¨à± జోడించà±</translation>
<translation id="2539524384386349900">à°—à±à°°à±à°¤à°¿à°‚à°šà±</translation>
@@ -525,7 +547,14 @@
<translation id="2597378329261239068">à°ˆ డాకà±à°¯à±à°®à±†à°‚à°Ÿà±â€Œ à°…à°¨à±à°®à°¤à°¿ పదంచే à°°à°•à±à°·à°¿à°‚చబడింది. దయచేసి à°…à°¨à±à°®à°¤à°¿ పదానà±à°¨à°¿ నమోదౠచేయండి.</translation>
<translation id="2609632851001447353">à°µà±à°¯à°¤à±à°¯à°¾à°¸à°¾à°²à±</translation>
<translation id="2610561535971892504">కాపీ చేయడానికి à°•à±à°²à°¿à°•à± చేయండి</translation>
+<translation id="2617988307566202237">Chrome à°ˆ కింది సమాచారానà±à°¨à°¿ <ph name="BEGIN_EMPHASIS" />సేవౠచేయదà±<ph name="END_EMPHASIS" />:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />మీ à°¬à±à°°à±Œà°œà°¿à°‚గౠహిసà±à°Ÿà°°à±€
+ <ph name="LIST_ITEM" />à°•à±à°•à±à°•à±€à°²à±, సైటౠడేటా
+ <ph name="LIST_ITEM" />ఫారమà±â€Œà°²à°²à±‹ ఎంటరౠచేసిన సమాచారం
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (à°Žà°¨à±à°µà°²à°ªà±)</translation>
+<translation id="2623663032199728144">మీ à°¸à±à°•à±à°°à±€à°¨à±â€Œà°²à°•à± సంబంధించిన సమాచారానà±à°¨à°¿ ఉపయోగించడానికి సైటౠఅనà±à°®à°¤à°¿ అడగవచà±à°šà±</translation>
<translation id="2625385379895617796">మీ గడియారం సమయం భవిషà±à°¯à°¤à±à°¤à±à°²à±‹ ఉంది</translation>
<translation id="262745152991669301">USB పరికరాలకౠకనెకà±à°Ÿà± చేయడానికి సైటౠఅనà±à°®à°¤à°¿ అడగవచà±à°šà±</translation>
<translation id="2629325967560697240">Chrome à°…à°¤à±à°¯à°§à°¿à°• à°¸à±à°¥à°¾à°¯à°¿ à°°à°•à±à°·à°£à°¨à± పొందడానికి, <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />మెరà±à°—à±à°ªà°°à°¿à°šà°¿à°¨ ఫీచరà±â€Œà°²à°¨à± ఆనౠచేయండి<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -559,6 +588,7 @@
<translation id="2709516037105925701">ఆటో-à°«à°¿à°²à±</translation>
<translation id="2713444072780614174">తెలà±à°ªà±</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />, Chrome సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²à°²à±‹ మీ పేమెంటà±â€Œà°²à±, à°•à±à°°à±†à°¡à°¿à°Ÿà± కారà±à°¡à± సమాచారం మేనేజౠచేయడానికి 'Tab'నౠనొకà±à°•à°¿, ఆపై 'Enter'నౠనొకà±à°•à°‚à°¡à°¿</translation>
+<translation id="271663710482723385">à°«à±à°²à± à°¸à±à°•à±à°°à±€à°¨à± à°¨à±à°‚à°¡à°¿ నిషà±à°•à±à°°à°®à°¿à°‚చడానికి |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| నొకà±à°•à°‚à°¡à°¿</translation>
<translation id="2721148159707890343">à°°à°¿à°•à±à°µà±†à°¸à±à°Ÿà±â€Œ విజయవంతం అయింది</translation>
<translation id="2723669454293168317">Chrome సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²à°²à±‹ à°­à°¦à±à°°à°¤à°¾ తనిఖీని రనౠచేయండి</translation>
<translation id="2726001110728089263">సైడౠటà±à°°à±‡</translation>
@@ -589,8 +619,9 @@
<translation id="2850739647070081192">ఆహà±à°µà°¾à°¨à°‚ (à°Žà°¨à±à°µà°²à°ªà±)</translation>
<translation id="2856444702002559011">à°¹à±à°¯à°¾à°•à°°à±â€Œà°²à± <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> à°¨à±à°‚à°¡à°¿ మీ సమాచారానà±à°¨à°¿ దొంగిలించడానికి à°ªà±à°°à°¯à°¤à±à°¨à°¿à°¸à±à°¤à±‚ ఉండవచà±à°šà± (ఉదాహరణకà±, పాసà±â€Œà°µà°°à±à°¡à±â€Œà°²à±, మెసేజà±â€Œà°²à± లేదా à°•à±à°°à±†à°¡à°¿à°Ÿà± కారà±à°¡à±â€Œà°²à±). <ph name="BEGIN_LEARN_MORE_LINK" />మరింత తెలà±à°¸à±à°•à±‹à°‚à°¡à°¿<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">à°ˆ సైటౠఅనà±à°šà°¿à°¤à°®à±ˆà°¨ లేదా తపà±à°ªà±à°¦à°¾à°°à°¿ పటà±à°Ÿà°¿à°‚చే à°ªà±à°°à°•à°Ÿà°¨à°²à°¨à± చూపà±à°¤à±à°‚ది.</translation>
+<translation id="286512204874376891">మోసం జరిగే అవకాశమà±à°¨à±à°¨ సందరà±à°­à°‚లో మిమà±à°®à°²à±à°¨à°¿ à°°à°•à±à°·à°¿à°‚చడంలో సహాయపడటానికి వరà±à°šà±à°µà°²à± కారà±à°¡à± మీ అసలౠకారà±à°¡à±â€Œà°²à°¾ à°µà±à°¯à°µà°¹à°°à°¿à°¸à±à°¤à±à°‚ది. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">à°¸à±à°¨à±‡à°¹à°ªà±‚à°°à±à°µà°•à°®à±ˆà°¨à°¦à°¿</translation>
-<translation id="2876489322757410363">వెలà±à°ªà°²à°¿ à°…à°ªà±à°²à°¿à°•à±‡à°·à°¨à± à°¦à±à°µà°¾à°°à°¾ చెలà±à°²à°¿à°‚చడానికి à°…à°œà±à°žà°¾à°¤ మోడౠనà±à°‚à°¡à°¿ నిషà±à°•à±à°°à°®à°¿à°¸à±à°¤à±‹à°‚ది. కొనసాగించాలా?</translation>
+<translation id="2876489322757410363">వెలà±à°ªà°²à°¿ à°…à°ªà±à°²à°¿à°•à±‡à°·à°¨à± à°¦à±à°µà°¾à°°à°¾ పేమెంటౠచేయడానికి à°…à°œà±à°žà°¾à°¤ మోడౠనà±à°‚à°¡à°¿ నిషà±à°•à±à°°à°®à°¿à°¸à±à°¤à±‹à°‚ది. కొనసాగించాలా?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />, Chrome సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²à°²à±‹ మీ à°¸à±à°°à°•à±à°·à°¿à°¤ à°¬à±à°°à±Œà°œà°¿à°‚à°—à±â€Œà°¨à±, ఇంకా మరినà±à°¨à°¿à°‚టిని మేనేజౠచేయడానికి 'Tab'నౠనొకà±à°•à°¿, ఆపై 'Enter'నౠనొకà±à°•à°‚à°¡à°¿</translation>
<translation id="2878197950673342043">పోసà±à°Ÿà°°à± ఫోలà±à°¡à±</translation>
<translation id="2878424575911748999">A1</translation>
@@ -613,6 +644,7 @@
<translation id="2930577230479659665">à°ªà±à°°à°¤à°¿ కాపీ తరà±à°µà°¾à°¤ à°•à°¤à±à°¤à°¿à°°à°¿à°‚à°šà°‚à°¡à°¿</translation>
<translation id="2932085390869194046">పాసà±â€Œà°µà°°à±à°¡à±â€Œâ€Œà°¨à± సూచించà±...</translation>
<translation id="2934466151127459956">à°ªà±à°°à°­à±à°¤à±à°µ-లెటరà±</translation>
+<translation id="2938225289965773019"><ph name="PROTOCOL" /> లింకà±â€Œà°²à°¨à± తెరవండి</translation>
<translation id="2941952326391522266">à°ˆ సరà±à°µà°°à± <ph name="DOMAIN" /> అని నిరూపించà±à°•à±‹à°²à±‡à°•à°ªà±‹à°¯à°¿à°‚ది; దీని à°­à°¦à±à°°à°¤à°¾ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ <ph name="DOMAIN2" /> à°¨à±à°‚à°¡à°¿ జారీ చేయబడింది. ఇది తపà±à°ªà±à°—à°¾ కానà±à°«à°¿à°—రౠచేయడం వలన లేదా దాడిచేసే à°µà±à°¯à°•à±à°¤à°¿ మీ కనెకà±à°·à°¨à±â€Œà°•à± అంతరాయం కలిగించడం వలన జరిగి ఉండవచà±à°šà±.</translation>
<translation id="2943895734390379394">à°…à°ªà±â€Œà°²à±‹à°¡à± సమయం:</translation>
<translation id="2948083400971632585">మీరౠసెటà±à°Ÿà°¿à°‚à°—à±â€Œà°² పేజీ à°¨à±à°‚à°¡à°¿ కనెకà±à°·à°¨à± కోసం కానà±à°«à°¿à°—రౠచేయబడిన à° à°ªà±à°°à°¾à°•à±à°¸à±€à°²à°¨à± అయినా నిలిపివేయవచà±à°šà±.</translation>
@@ -645,6 +677,7 @@
<translation id="3037605927509011580">ఆవà±, à°¸à±à°¨à°¾à°ªà±!</translation>
<translation id="3041612393474885105">సరà±à°Ÿà°¿à°«à°¿à°•à±†à°Ÿà± సమాచారం</translation>
<translation id="3044034790304486808">మీ పరిశోధననౠకొనసాగించండి</translation>
+<translation id="305162504811187366">టైమౠసà±à°Ÿà°¾à°‚à°ªà±â€Œâ€Œà°²à±, హోసà±à°Ÿà±â€Œà°²à±, à°•à±à°²à°¯à°¿à°‚టౠసెషనౠidలతో సహా Chrome రిమోటౠడెసà±à°•à±â€Œà°Ÿà°¾à°ªà± హిసà±à°Ÿà°°à±€</translation>
<translation id="3060227939791841287">C9 (à°Žà°¨à±à°µà°²à°ªà±)</translation>
<translation id="3061707000357573562">à°ªà±à°¯à°¾à°šà± సేవ</translation>
<translation id="306573536155379004">గేమౠపà±à°°à°¾à°°à°‚భమైంది.</translation>
@@ -666,7 +699,7 @@
<translation id="3121994479408824897"><ph name="DOMAIN" />కౠవెళà±à°²à±</translation>
<translation id="3137507986424712703">{COUNT,plural, =0{à°à°®à±€ లేవà±}=1{1 ఖాతా సైనౠఇనౠడేటా}other{# ఖాతాల సైనౠఇనౠడేటా}}</translation>
<translation id="3145945101586104090">à°ªà±à°°à°¤à°¿à°¸à±à°ªà°‚దననౠడీకోడౠచేయడంలో విఫలమైంది</translation>
-<translation id="3150653042067488994">తాతà±à°•à°¾à°²à°¿à°• సరà±à°µà°°à± లోపం</translation>
+<translation id="3150653042067488994">తాతà±à°•à°¾à°²à°¿à°• సరà±à°µà°°à± à°Žà°°à±à°°à°°à±</translation>
<translation id="3154506275960390542">à°ˆ పేజీలో ఉనà±à°¨ ఫారమà±â€Œà°¨à± à°¸à±à°°à°•à±à°·à°¿à°¤à°‚à°—à°¾ సమరà±à°ªà°¿à°‚చలేకపోవచà±à°šà±. బదిలీ చేయబడే సమయంలో మీరౠపంపే డేటాని ఇతరà±à°²à± వీకà±à°·à°¿à°‚చవచà±à°šà± లేదా సరà±à°µà°°à± à°¸à±à°µà±€à°•à°°à°¿à°‚చే డేటానౠమారà±à°šà°¡à°‚ కోసం à°¹à±à°¯à°¾à°•à°°à±â€Œà°²à± దీనిని సవరించవచà±à°šà±.</translation>
<translation id="3154987252551138431">'సమీపంలోని షేరింగà±'నౠఉపయోగిసà±à°¤à±à°¨à±à°¨à°ªà±à°ªà±à°¡à± à°à°¦à±‹ తపà±à°ªà± జరిగింది</translation>
<translation id="315504272643575312"><ph name="MANAGER" /> మీ ఖాతానౠమేనేజౠచేసà±à°¤à±‹à°‚ది.</translation>
@@ -685,6 +718,7 @@
<translation id="3197136577151645743">మీరౠఈ పరికరానà±à°¨à°¿ యాకà±à°Ÿà°¿à°µà±â€Œà°—à°¾ ఉపయోగించే సమయాలనౠతెలà±à°¸à±à°•à±‹à°µà°¡à°¾à°¨à°¿à°•à°¿ సైటౠఅనà±à°®à°¤à°¿ అడగవచà±à°šà±</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />, Chrome సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²à°²à±‹ మీరౠఠసమాచారానà±à°¨à°¿ సింకౠచేయాలనà±à°•à±à°‚à°Ÿà±à°¨à±à°¨à°¾à°°à±‹ మేనేజౠచేయడానికి 'Tab'నౠనొకà±à°•à°¿, ఆపై 'Enter'నౠనొకà±à°•à°‚à°¡à°¿</translation>
<translation id="320323717674993345">పేమెంటà±â€Œà°¨à± à°°à°¦à±à°¦à± చేయండి</translation>
+<translation id="3203366800380907218">వెబౠనà±à°‚à°¡à°¿</translation>
<translation id="3207960819495026254">à°¬à±à°•à±â€Œà°®à°¾à°°à±à°•à± చేయబడింది</translation>
<translation id="3209034400446768650">పేజీ, నగదà±à°¨à± ఛారà±à°œà± చేయవచà±à°šà±</translation>
<translation id="3212581601480735796"><ph name="HOSTNAME" />లోని మీ యాకà±à°Ÿà°¿à°µà°¿à°Ÿà±€ పరà±à°¯à°µà±‡à°•à±à°·à°¿à°‚చబడà±à°¤à±‹à°‚ది</translation>
@@ -701,10 +735,12 @@
<translation id="3234666976984236645">à°ˆ సైటà±â€Œà°²à±‹ à°Žà°ªà±à°ªà±à°¡à±‚ à°®à±à°–à±à°¯à°®à±ˆà°¨ కంటెంటà±â€Œà°¨à± à°—à±à°°à±à°¤à°¿à°‚à°šà±</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />, మీ à°¬à±à°°à±Œà°œà°°à± రూపానà±à°¨à°¿ à°…à°¨à±à°•à±‚లీకరించడానికి 'Tab'నౠనొకà±à°•à°¿, ఆపై 'Enter'నౠనొకà±à°•à°‚à°¡à°¿</translation>
<translation id="3240791268468473923">à°¸à±à°°à°•à±à°·à°¿à°¤à°®à±ˆà°¨ పేమెంటౠఆధారానికి సంబంధించిన à°®à±à°¯à°¾à°šà± à°…à°¯à±à°¯à±‡ ఆధారాల షీటౠà°à°¦à±€ తెరవబడలేదà±</translation>
+<translation id="324180406144491771">“<ph name="HOST_NAME" />†లింకà±â€Œà°²à± à°¬à±à°²à°¾à°•à± చేయబడà±à°¡à°¾à°¯à°¿</translation>
<translation id="3249845759089040423">సొగసైనది</translation>
<translation id="3252266817569339921">à°«à±à°°à±†à°‚à°šà±</translation>
<translation id="3257954757204451555">à°ˆ సమాచారానà±à°¨à°¿ ఎవరౠఅందించారà±?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />, Google Calendarలో à°¤à±à°µà°°à°—à°¾ కొతà±à°¤ ఈవెంటà±â€Œà°¨à± à°•à±à°°à°¿à°¯à±‡à°Ÿà± చేయడానికి Tabనౠనొకà±à°•à°¿, ఆపై Enterనౠనొకà±à°•à°‚à°¡à°¿</translation>
+<translation id="3261488570342242926">వరà±à°šà±à°µà°²à± కారà±à°¡à±â€Œà°² à°—à±à°°à°¿à°‚à°šà°¿ తెలà±à°¸à±à°•à±‹à°‚à°¡à°¿</translation>
<translation id="3264837738038045344">'Chrome సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²à°¨à± మేనేజౠచేయండి' బటనà±, మీ Chrome సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²à°•à± వెళà±à°²à°¡à°¾à°¨à°¿à°•à°¿ Enterనౠనొకà±à°•à°‚à°¡à°¿</translation>
<translation id="3266793032086590337">విలà±à°µ (వైరà±à°§à±à°¯à°‚)</translation>
<translation id="3268451620468152448">ఓపెనౠటాబà±â€Œà°²à±</translation>
@@ -718,6 +754,7 @@
<translation id="3288238092761586174">మీ పేమెంటà±â€Œà°¨à± వెరిఫై చేయడానికి, <ph name="URL" /> అదనపౠదశలనౠతీసà±à°•à±‹à°µà°¾à°²à±à°¸à°¿ రావచà±à°šà±</translation>
<translation id="3293642807462928945"><ph name="POLICY_NAME" /> విధానం à°—à±à°°à°¿à°‚à°šà°¿ మరింత తెలà±à°¸à±à°•à±‹à°‚à°¡à°¿</translation>
<translation id="3295444047715739395">Chrome సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²à°²à±‹ మీ పాసà±â€Œà°µà°°à±à°¡à±â€Œà°²à°¨à± చూడండి, మేనేజౠచేయండి</translation>
+<translation id="3303795387212510132"><ph name="PROTOCOL_SCHEME" /> లింకà±â€Œà°²à°¨à± తెరవడానికి యాపà±â€Œà°¨à± à°…à°¨à±à°®à°¤à°¿à°‚చాలా?</translation>
<translation id="3303855915957856445">à°† సెరà±à°šà± కోసం ఫలితాలౠà°à°µà±€ దొరకలేదà±</translation>
<translation id="3304073249511302126">à°¬à±à°²à±‚టూతౠసà±à°•à°¾à°¨à°¿à°‚à°—à±</translation>
<translation id="3308006649705061278">ఆరà±à°—నైజేషనలౠయూనిటౠ(OU)</translation>
@@ -731,12 +768,6 @@
<translation id="3345782426586609320">à°•à°³à±à°²à±</translation>
<translation id="3355823806454867987">à°ªà±à°°à°¾à°•à±à°¸à±€ సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²à°¨à± మారà±à°šà±...</translation>
<translation id="3360103848165129075">చెలà±à°²à°¿à°‚పౠహà±à°¯à°¾à°‚à°¡à±à°²à°°à± షీటà±</translation>
-<translation id="3361596688432910856">Chrome à°ˆ కింది సమాచారానà±à°¨à°¿ <ph name="BEGIN_EMPHASIS" />సేవౠచేయదà±<ph name="END_EMPHASIS" />:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />మీ à°¬à±à°°à±Œà°œà°¿à°‚à°—à± à°šà°°à°¿à°¤à±à°°
- <ph name="LIST_ITEM" />à°•à±à°•à±à°•à±€à°²à± మరియౠసైటౠడేటా
- <ph name="LIST_ITEM" />ఫారమà±â€Œà°²à°²à±‹ నమోదౠచేసిన సమాచారం
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">à°ˆ విధానం à°’à°• విసà±à°®à°°à°¿à°‚చబడిన <ph name="OLD_POLICY" /> విధానం à°¨à±à°‚à°¡à°¿ ఆటోమేటికà±â€Œà°—à°¾ కాపీ చేయబడింది. దానికి బదà±à°²à±à°—à°¾, మీరౠఈ విధానానà±à°¨à°¿ ఉపయోగించాలి.</translation>
<translation id="3364869320075768271">'<ph name="URL" />', మీ వరà±à°šà±à°µà°²à± రియాలిటీ పరికరానà±à°¨à°¿, డేటానౠవినియోగించడానికి à°…à°¨à±à°®à°¤à°¿ కోరà±à°¤à±‹à°‚ది</translation>
<translation id="3366477098757335611">కారà±à°¡à±â€Œà°²à°¨à± చూడండి</translation>
@@ -819,7 +850,6 @@
<translation id="3587738293690942763">మధà±à°¯à°²à±‹</translation>
<translation id="3592413004129370115">ఇటాలియనౠ(à°Žà°¨à±à°µà°²à°ªà±)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{మీరౠఠసమయంలో అయినా మీ à°—à±à°°à±‚à°ªà±â€Œà°¨à± రీసెటౠచేయవచà±à°šà±. కొతà±à°¤ à°—à±à°°à±‚à°ªà±â€Œà°•à± చేరడానికి à°’à°• రోజౠవరకౠపడà±à°¤à±à°‚ది.}=1{మీరౠఠసమయంలో అయినా మీ à°—à±à°°à±‚à°ªà±â€Œà°¨à± రీసెటౠచేయవచà±à°šà±. కొతà±à°¤ à°—à±à°°à±‚à°ªà±â€Œà°•à± చేరడానికి à°’à°• రోజౠవరకౠపడà±à°¤à±à°‚ది.}other{మీరౠఠసమయంలో అయినా మీ à°—à±à°°à±‚à°ªà±â€Œà°¨à± రీసెటౠచేయవచà±à°šà±. కొతà±à°¤ à°—à±à°°à±‚à°ªà±â€Œà°•à± చేరడానికి {NUM_DAYS} రోజà±à°²à± పడà±à°¤à±à°‚ది.}}</translation>
-<translation id="3596012367874587041">యాపౠసెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²à±</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">మీ నిరà±à°µà°¾à°¹à°•à±à°¡à± యాపà±â€Œà°¨à± à°¬à±à°²à°¾à°•à± చేశారà±</translation>
<translation id="3608932978122581043">ఫీడౠఓరియంటేషనà±</translation>
@@ -862,6 +892,7 @@
<translation id="370972442370243704">జరà±à°¨à±€à°¸à± ఫీచరà±â€Œà°¨à± ఆనౠచేయండి</translation>
<translation id="3711895659073496551">తాతà±à°•à°¾à°²à°¿à°•à°‚à°—à°¾ నిలిపివేయడం</translation>
<translation id="3712624925041724820">లైసెనà±à°¸à±â€Œà°²à± అయిపోయాయి</translation>
+<translation id="3714633008798122362">వెబౠకà±à°¯à°¾à°²à±†à°‚à°¡à°°à±</translation>
<translation id="3714780639079136834">మొబైలౠడేటా లేదా Wi-Fiని ఆనౠచేయడం</translation>
<translation id="3715597595485130451">Wi-Fià°•à°¿ కనెకà±à°Ÿà± చేయండి</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />à°ªà±à°°à°¾à°•à±à°¸à±€, ఫైరà±â€Œà°µà°¾à°²à± మరియౠDNS కానà±à°«à°¿à°—రేషనà±â€Œà°¨à± తనిఖీ చేయడం<ph name="END_LINK" /></translation>
@@ -892,7 +923,7 @@
<translation id="3789841737615482174">ఇనà±â€Œà°¸à±à°Ÿà°¾à°²à± చేయి</translation>
<translation id="3793574014653384240">ఇటీవల à°à°°à±à°ªà°¡à°¿à°¨ à°•à±à°°à°¾à°·à±â€Œà°² సంఖà±à°¯à°²à±, వాటికి à°—à°² కారణాలà±</translation>
<translation id="3797522431967816232">Prc3 (à°Žà°¨à±à°µà°²à°ªà±)</translation>
-<translation id="3799805948399000906">à°…à°­à±à°¯à°°à±à°¥à°¿à°‚à°šà°¿à°¨ ఫాంటà±</translation>
+<translation id="3799805948399000906">à°°à°¿à°•à±à°µà±†à°¸à±à°Ÿà± చేసిన ఫాంటà±</translation>
<translation id="380329542618494757">పేరà±</translation>
<translation id="3807366285948165054">à°šà°¿à°¤à±à°°à°¾à°¨à±à°¨à°¿ X à°…à°•à±à°·à°‚లో జరపà±</translation>
<translation id="3807873520724684969">హానికర కంటెంటౠబà±à°²à°¾à°•à± చేయబడింది.</translation>
@@ -923,11 +954,12 @@
<translation id="3906954721959377182">టాబà±à°²à±†à°Ÿà±</translation>
<translation id="3909477809443608991">à°°à°•à±à°·à°¿à°¤ కంటెంటà±â€Œà°¨à± à°ªà±à°²à±‡ చేయడానికి <ph name="URL" /> à°…à°¨à±à°®à°¤à°¿ కోరà±à°¤à±à°‚ది. మీ పరికరం à°—à±à°°à±à°¤à°¿à°‚పౠGoogle à°¦à±à°µà°¾à°°à°¾ ధృవీకరించబడà±à°¤à±à°‚ది, దీనిని à°ˆ సైటౠదà±à°µà°¾à°°à°¾ యాకà±à°¸à±†à°¸à± చేయవచà±à°šà±</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">తిరసà±à°•à°°à°¿à°‚à°šà±</translation>
<translation id="3939773374150895049">CVCà°•à°¿ బదà±à°²à±à°—à°¾ WebAuthnనౠఉపయోగించాలా?</translation>
<translation id="3946209740501886391">à°ˆ సైటà±â€Œà°²à±‹ à°Žà°²à±à°²à°ªà±à°ªà±à°¡à±‚ అడగాలి</translation>
<translation id="3947595700203588284">MIDI పరికరాలకౠకనెకà±à°Ÿà± చేయడానికి సైటౠఅనà±à°®à°¤à°¿ అడగవచà±à°šà±</translation>
<translation id="3949571496842715403">à°ˆ సరà±à°µà°°à± తనౠ<ph name="DOMAIN" /> అని నిరూపించà±à°•à±‹à°²à±‡à°•à°ªà±‹à°¯à°¿à°‚ది; దీని à°­à°¦à±à°°à°¤à°¾ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚లో విషయ à°ªà±à°°à°¤à±à°¯à°¾à°®à±à°¨à°¾à°¯ పేరà±à°²à± పేరà±à°•à±Šà°¨à°¬à°¡à°²à±‡à°¦à±. తపà±à°ªà±à°—à°¾ కానà±à°«à°¿à°—రౠచేయడం వలన లేదా à°¹à±à°¯à°¾à°•à°°à± మీ కనెకà±à°·à°¨à±â€Œà°•à± అంతరాయం కలిగించడం వలన ఇలా జరిగి ఉండవచà±à°šà±.</translation>
-<translation id="3949601375789751990">మీ à°¬à±à°°à±Œà°œà°¿à°‚à°—à± à°šà°°à°¿à°¤à±à°° ఇకà±à°•à°¡ కనిపిసà±à°¤à±à°‚ది</translation>
+<translation id="3949601375789751990">మీ à°¬à±à°°à±Œà°œà°¿à°‚గౠహిసà±à°Ÿà°°à±€ ఇకà±à°•à°¡ కనిపిసà±à°¤à±à°‚ది</translation>
<translation id="3949790930165450333"><ph name="DEVICE_NAME" /> (<ph name="DEVICE_ID" />)</translation>
<translation id="3949870428812919180">సేవౠచేసిన చెలà±à°²à°¿à°‚పౠపదà±à°§à°¤à±à°²à±‡à°µà±€ లేవà±</translation>
<translation id="3950820424414687140">సైనౠఇనà±</translation>
@@ -944,6 +976,7 @@
<translation id="3990250421422698716">జోగౠఆఫà±â€Œà°¸à±†à°Ÿà±</translation>
<translation id="3996311196211510766"><ph name="ORIGIN" /> సైటà±, తనకౠచేసే à°…à°¨à±à°¨à°¿ à°°à°¿à°•à±à°µà±†à°¸à±à°Ÿà±â€Œà°²à°•à± ఆరిజినౠపాలసీని
వరà±à°¤à°¿à°‚పజేయమని à°…à°­à±à°¯à°°à±à°¥à°¿à°‚చింది. కానీ, à°ªà±à°°à°¸à±à°¤à±à°¤à°‚ à°ˆ పాలసీని వరà±à°¤à°¿à°‚పజేయడం సాధà±à°¯à°ªà°¡à°¦à±.</translation>
+<translation id="4009243425692662128">మీరౠపà±à°°à°¿à°‚టౠచేసిన పేజీల కంటెంటà±, విశà±à°²à±‡à°·à°£ కోసం Google Cloud లేదా థరà±à°¡à±-పారà±à°Ÿà±€à°²à°•à± పంపబడà±à°¤à±à°‚ది. ఉదాహరణకà±, ఇది à°¸à±à°¨à±à°¨à°¿à°¤à°®à±†à±–à°¨ à°µà±à°¯à°•à±à°¤à°¿à°—à°¤ సమాచారం కోసం à°¸à±à°•à°¾à°¨à± చేయబడవచà±à°šà±.</translation>
<translation id="4010758435855888356">à°¸à±à°Ÿà±‹à°°à±‡à°œà±â€Œà°¨à± యాకà±à°¸à±†à°¸à± చేయడానికి à°…à°¨à±à°®à°¤à°¿à°‚చాలా?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{PDF డాకà±à°¯à±à°®à±†à°‚à°Ÿà±â€Œâ€Œà°²à±‹ {COUNT} పేజీ ఉంది}other{PDF డాకà±à°¯à±à°®à±†à°‚à°Ÿà±â€Œâ€Œà°²à±‹ {COUNT} పేజీలౠఉనà±à°¨à°¾à°¯à°¿}}</translation>
<translation id="4023431997072828269">à°ˆ ఫారమౠసà±à°°à°•à±à°·à°¿à°¤à°‚à°—à°¾ లేని కనెకà±à°·à°¨à±â€Œà°¨à± ఉపయోగించి సమరà±à°ªà°¿à°‚చబడà±à°¤à±‹à°‚ది, కాబటà±à°Ÿà°¿ మీ సమాచారం ఇతరà±à°²à°•à± కనిపిసà±à°¤à±à°‚ది.</translation>
@@ -956,7 +989,7 @@
<translation id="4072193657607981494">పాలసీలనౠలోడౠచేసà±à°¤à±‹à°‚ది</translation>
<translation id="4072486802667267160">మీ ఆరà±à°¡à°°à±â€Œà°¨à± à°ªà±à°°à°¾à°¸à±†à°¸à± చేసà±à°¤à±à°¨à±à°¨à°ªà±à°ªà±à°¡à± à°Žà°°à±à°°à°°à± à°à°°à±à°ªà°¡à°¿à°‚ది. దయచేసి మళà±à°²à±€ à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚à°šà°‚à°¡à°¿.</translation>
<translation id="4073797364926776829">కారà±à°¡à±â€Œà°¨à± చూడండి</translation>
-<translation id="4075732493274867456">à°•à±à°²à°¯à°¿à°‚à°Ÿà±, సరà±à°µà°°à±- ఒకే SSL à°ªà±à°°à±‹à°Ÿà±‹à°•à°¾à°²à± సంసà±à°•à°°à°£ లేదా సైఫరౠసూటà±â€Œà°•à± మదà±à°¦à°¤à± ఇవà±à°µà°µà±.</translation>
+<translation id="4075732493274867456">à°•à±à°²à°¯à°¿à°‚à°Ÿà±, సరà±à°µà°°à±- ఒకే SSL à°ªà±à°°à±‹à°Ÿà±‹à°•à°¾à°²à± వెరà±à°·à°¨à±â€Œ లేదా సైఫరౠసూటà±â€Œà°•à± మదà±à°¦à°¤à± ఇవà±à°µà°µà±.</translation>
<translation id="4075941231477579656">Touch ID</translation>
<translation id="4079302484614802869">à°¸à±à°¥à°¿à°°à°®à±ˆà°¨ à°ªà±à°°à°¾à°•à±à°¸à±€ సరà±à°µà°°à±â€Œà°²à°¨à± కాకà±à°‚à°¡à°¾, à°’à°• .pac à°¸à±à°•à±à°°à°¿à°ªà±à°Ÿà± URLనౠఉపయోగించేలా à°ªà±à°°à°¾à°•à±à°¸à±€ కానà±à°«à°¿à°—రేషనౠసెటౠచేయబడింది.</translation>
<translation id="4082393374666368382">సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²à± - నిరà±à°µà°¹à°£</translation>
@@ -1038,6 +1071,7 @@
<translation id="4250680216510889253">లేదà±</translation>
<translation id="4253168017788158739">గమనిక</translation>
<translation id="425582637250725228">మీరౠచేసిన మారà±à°ªà±à°²à± సేవౠఅయà±à°¯à°¿ ఉండకపోవచà±à°šà±.</translation>
+<translation id="425869179292622354">వరà±à°šà±à°µà°²à± కారà±à°¡à±â€Œà°¤à±‹ దీనà±à°¨à°¿ మరింత à°¸à±à°°à°•à±à°·à°¿à°¤à°‚à°—à°¾ ఉంచాలనà±à°•à±à°‚à°Ÿà±à°¨à±à°¨à°¾à°°à°¾?</translation>
<translation id="4258748452823770588">చెలà±à°²à°¨à°¿ సంతకం</translation>
<translation id="4261046003697461417">à°°à°•à±à°·à°£à°²à±‹ ఉనà±à°¨ డాకà±à°¯à±à°®à±†à°‚à°Ÿà±â€Œà°²à°•à± అదనపౠగమనికలనౠజోడించలేరà±</translation>
<translation id="4265872034478892965">మీ నిరà±à°µà°¾à°¹à°•à±à°²à± à°…à°¨à±à°®à°¤à°¿à°‚చారà±</translation>
@@ -1077,7 +1111,7 @@
<translation id="4351175281479794167">వెరిఫికేషనౠకోడà±â€Œà°¨à± ఎంటరౠచేయండి</translation>
<translation id="4356973930735388585">à°ˆ సైటà±â€Œà°²à±‹à°¨à°¿ దాడి చేసేవారౠమీ సమాచారానà±à°¨à°¿ (ఉదాహరణకà±, ఫోటోలà±, పాసà±â€Œà°µà°°à±à°¡à±â€Œà°²à±, మెసేజà±â€Œà°²à± మరియౠకà±à°°à±†à°¡à°¿à°Ÿà± కారà±à°¡à±â€Œà°²à±) దొంగిలించడం కోసం లేదా తొలగించడం కోసం మీ à°•à°‚à°ªà±à°¯à±‚à°Ÿà°°à±â€Œà°²à±‹ à°ªà±à°°à°®à°¾à°¦à°•à°°à°®à±ˆà°¨ à°ªà±à°°à±‹à°—à±à°°à°¾à°®à±â€Œà°²à°¨à± ఇనà±â€Œà°¸à±à°Ÿà°¾à°²à± చేయడానికి à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚చవచà±à°šà±.</translation>
<translation id="4358059973562876591">DnsOverHttpsMode విధానానికి సంబంధించి à°à°°à±à°ªà°¡à°¿à°¨ à°Žà°°à±à°°à°°à± కారణంగా మీరౠపేరà±à°•à±Šà°¨à±à°¨ టెంపà±à°²à±‡à°Ÿà±â€Œà°²à°¨à± వరà±à°¤à°¿à°‚పజేయడం వీలౠకాకపోవచà±à°šà±.</translation>
-<translation id="4358461427845829800">చెలà±à°²à°¿à°‚పౠపదà±à°§à°¤à±à°²à°¨à± నిరà±à°µà°¹à°¿à°‚à°šà°‚à°¡à°¿...</translation>
+<translation id="4358461427845829800">పేమెంటౠఆపà±à°·à°¨à±â€Œà°²à°¨à± నిరà±à°µà°¹à°¿à°‚à°šà°‚à°¡à°¿...</translation>
<translation id="4359160567981085931">మీరౠమోసపూరితమైన సైటà±â€Œà°²à±‹ మీ పాసà±â€Œà°µà°°à±à°¡à±â€Œà°¨à± ఎంటరౠచేశారà±. Chrome సహాయపడగలదà±. మీ పాసà±â€Œà°µà°°à±à°¡à±â€Œâ€Œà°¨à± మారà±à°šà°¿, మీ ఖాతా à°ªà±à°°à°®à°¾à°¦à°‚లో ఉండవచà±à°šà°¨à°¿ Googleకౠతెలియజేయడానికి, 'ఖాతానౠసంరకà±à°·à°¿à°‚à°šà±'నౠకà±à°²à°¿à°•à± చేయండి.</translation>
<translation id="4367563149485757821">నంబరà±-12 (à°Žà°¨à±à°µà°²à°ªà±)</translation>
<translation id="437040971055499437">సెకà±à°¯à±‚à°°à°¿à°Ÿà±€ ఈవెంటౠజరిగినపà±à°ªà±à°¡à±</translation>
@@ -1100,6 +1134,7 @@
<translation id="4434045419905280838">పాపà±-à°…à°ªà±â€Œà°²à± మరియౠమళà±à°²à°¿à°‚à°ªà±à°²à±</translation>
<translation id="4435702339979719576">పోసà±à°Ÿà±â€Œà°•à°¾à°°à±à°¡à±)</translation>
<translation id="443673843213245140">à°ªà±à°°à°¾à°•à±à°¸à±€à°¨à°¿ ఉపయోగించడం ఆపివేయబడింది కానీ à°¸à±à°ªà°·à±à°Ÿà°®à±ˆà°¨ à°ªà±à°°à°¾à°•à±à°¸à±€ కానà±à°«à°¿à°—రేషనౠపేరà±à°•à±Šà°¨à°¬à°¡à°¿à°‚ది.</translation>
+<translation id="4441832193888514600">à°•à±à°²à±Œà°¡à± యూజరౠపాలసీ à°¦à±à°µà°¾à°°à°¾ మాతà±à°°à°®à±‡ పాలసీని సెటౠచేయాలి కాబటà±à°Ÿà°¿ ఇది విసà±à°®à°°à°¿à°‚చబడింది.</translation>
<translation id="4450893287417543264">మళà±à°²à±€ చూపవదà±à°¦à±</translation>
<translation id="4451135742916150903">HID పరికరాలకౠకనెకà±à°Ÿà± చేయడానికి సైటౠఅనà±à°®à°¤à°¿ అడగవచà±à°šà±</translation>
<translation id="4452328064229197696">మీరౠఇపà±à°ªà±à°¡à±‡ ఉపయోగించిన పాసà±â€Œà°µà°°à±à°¡à±, డేటా ఉలà±à°²à°‚ఘనలో కనగొనబడింది. మీ ఖాతాలనౠసà±à°°à°•à±à°·à°¿à°¤à°‚ చేయడానికి, మీరౠసేవౠచేసిన పాసà±â€Œà°µà°°à±à°¡à±â€Œà°²à°¨à± చెకౠచేయమని Google పాసà±â€Œà°µà°°à±à°¡à± మేనేజరౠసిఫారà±à°¸à± చేసà±à°¤à±‹à°‚ది.</translation>
@@ -1155,6 +1190,7 @@
<translation id="4628948037717959914">ఫోటో</translation>
<translation id="4631649115723685955">à°•à±à°¯à°¾à°·à±â€Œà°¬à±à°¯à°¾à°•à± లింకౠచేయబడింది</translation>
<translation id="4636930964841734540">సమాచారం</translation>
+<translation id="4638670630777875591">Chromiumలో à°…à°œà±à°žà°¾à°¤ మోడà±</translation>
<translation id="464342062220857295">శోధన ఫీచరà±â€Œà°²à±</translation>
<translation id="4644670975240021822">à°µà±à°¯à°¤à°¿à°°à±‡à°• à°•à±à°°à°®à°‚లో ఉనà±à°¨ ఫేసౠడౌనà±</translation>
<translation id="4646534391647090355">ఇపà±à°ªà±à°¡à± ననà±à°¨à± à°…à°•à±à°•à°¡à°•à± తీసà±à°•à± వెళà±à°²à±</translation>
@@ -1175,6 +1211,7 @@
<translation id="4708268264240856090">మీ కనెకà±à°·à°¨à±â€Œà°•à± అంతరాయం à°à°°à±à°ªà°¡à°¿à°‚ది</translation>
<translation id="4712404868219726379">Windows Hell</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Windows నెటà±â€Œà°µà°°à±à°•à± సమసà±à°¯ విశà±à°²à±‡à°·à°£à°²à°¨à± అమలౠచేయడం<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426"><ph name="USERNAME" /> కోసం పాసà±â€Œà°µà°°à±à°¡à±</translation>
<translation id="4724144314178270921">మీ à°•à±à°²à°¿à°ªà±â€Œà°¬à±‹à°°à±à°¡à±â€Œà°²à±‹à°¨à°¿ టెకà±à°¸à±à°Ÿà±, ఇమేజà±â€Œà°²à°¨à± చూడటానికి సైటౠఅనà±à°®à°¤à°¿ అడగవచà±à°šà±</translation>
<translation id="4726672564094551039">విధానాలనౠమళà±à°²à±€ లోడౠచేయి</translation>
<translation id="4728558894243024398">à°ªà±à°²à°¾à°Ÿà±â€Œà°«à°¾à°°à°®à±</translation>
@@ -1196,6 +1233,7 @@
<translation id="4757993714154412917">మీరౠమోసపూరితమైన సైటà±â€Œà°²à±‹ మీ పాసà±â€Œà°µà°°à±à°¡à±â€Œà°¨à± ఎంటరౠచేశారà±. మీ ఖాతాలనౠసà±à°°à°•à±à°·à°¿à°¤à°‚à°—à°¾ ఉంచడానికి, Chromium మీ సేవౠచేసిన పాసà±â€Œà°µà°°à±à°¡à±â€Œà°²à°¨à± చెకౠచేయాలని సిఫారà±à°¸à± చేసà±à°¤à±‹à°‚ది.</translation>
<translation id="4758311279753947758">సంపà±à°°à°¦à°¿à°‚పౠసమాచారానà±à°¨à°¿ జోడించà±</translation>
<translation id="4761104368405085019">మీ మైకà±à°°à±‹à°«à±‹à°¨à±â€Œà°¨à± ఉపయోగించండి</translation>
+<translation id="4761869838909035636">Chrome à°­à°¦à±à°°à°¤à°¾ తనిఖీని రనౠచేయి</translation>
<translation id="4764776831041365478"><ph name="URL" /> వదà±à°¦ వెబà±â€Œà°ªà±‡à°œà±€ తాతà±à°•à°¾à°²à°¿à°•à°‚à°—à°¾ తెరà±à°šà±à°•à±‹à°µà°Ÿà°‚ లేదౠలేదా అది కొతà±à°¤â€Œ వెబౠఅడà±à°°à°¸à±â€Œà°•à± శాశà±à°µà°¤à°‚à°—à°¾ తరలించబడి ఉండవచà±à°šà±.</translation>
<translation id="4766713847338118463">దిగà±à°µ భాగంలో à°¡à±à°¯à±à°¯à°²à± à°¸à±à°Ÿà±‡à°ªà±à°²à±</translation>
<translation id="4771973620359291008">తెలియని à°Žà°°à±à°°à°°à± à°’à°•à°Ÿà°¿ à°à°°à±à°ªà°¡à°¿à°‚ది.</translation>
@@ -1216,12 +1254,6 @@
<translation id="4819347708020428563">అదనపౠగమనికలనౠఆటోమేటికౠవీకà±à°·à°£à°²à±‹ ఎడిటౠచేయాలనà±à°•à±à°‚à°Ÿà±à°¨à±à°¨à°¾à°°à°¾?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />, కొతà±à°¤ Google షీటà±â€Œà°¨à± à°¤à±à°µà°°à°—à°¾ à°•à±à°°à°¿à°¯à±‡à°Ÿà± చేయడానికి Tabనౠనొకà±à°•à°¿, ఆపై Enterనౠనొకà±à°•à°‚à°¡à°¿</translation>
<translation id="4825507807291741242">శకà±à°¤à°¿à°µà°‚తమైనది</translation>
-<translation id="4827402517081186284">à°…à°œà±à°žà°¾à°¤ మోడà±â€Œà°¨à± ఉపయోగిసà±à°¤à±à°¨à±à°¨à°‚à°¤ మాతà±à°°à°¾à°¨ మీరౠఆనà±â€Œà°²à±ˆà°¨à±â€Œà°²à±‹ ఇతరà±à°²à°•à± కనపడరని à°…à°°à±à°§à°‚ కాదà±:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />మీరౠసైటà±â€Œà°²à°•à± వెళà±à°²à°¿à°¨à°ªà±à°ªà±à°¡à± వాటికి తెలà±à°¸à±à°¤à±à°‚ది<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />యాజమానà±à°¯ సంసà±à°¥à°²à± లేదా పాఠశాలలౠబà±à°°à±Œà°œà°¿à°‚గౠయాకà±à°Ÿà°¿à°µà°¿à°Ÿà±€à°¨à°¿ à°Ÿà±à°°à°¾à°•à± చేయగలవà±<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />ఇంటరà±à°¨à±†à°Ÿà± సరà±à°µà±€à°¸à± à°ªà±à°°à±Šà°µà±ˆà°¡à°°à±â€Œà°²à± వెబౠటà±à°°à°¾à°«à°¿à°•à±â€Œà°¨à± మానిటరౠచేయగలవà±<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">హెచà±à°šà°°à°¿à°•à°²à°¨à± ఆనౠచేయండి</translation>
<translation id="4838327282952368871">à°¸à±à°µà°ªà±à°¨à°‚ లాంటిది</translation>
<translation id="4840250757394056958">మీ Chrome హిసà±à°Ÿà°°à±€à°¨à°¿ చూడండి</translation>
@@ -1233,12 +1265,12 @@
<translation id="4854362297993841467">à°ˆ బటà±à°µà°¾à°¡à°¾ పదà±à°§à°¤à°¿ à°…à°‚à°¦à±à°¬à°¾à°Ÿà±à°²à±‹ లేదà±. వేరే పదà±à°§à°¤à°¿à°¨à°¿ à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚à°šà°‚à°¡à°¿.</translation>
<translation id="4854853140771946034">Google Keepలో à°¤à±à°µà°°à°—à°¾ కొతà±à°¤ నోటà±â€Œà°¨à± à°•à±à°°à°¿à°¯à±‡à°Ÿà± చేయండి</translation>
<translation id="485902285759009870">కోడà±â€Œà°¨à± వెరిఫై చేసà±à°¤à±‹à°‚ది...</translation>
+<translation id="4866506163384898554">మీ à°•à°°à±à°¸à°°à±â€Œâ€Œà°¨à± చూపించడానికి |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| నొకà±à°•à°‚à°¡à°¿</translation>
<translation id="4876188919622883022">సరళీకృత వీకà±à°·à°£</translation>
<translation id="4876305945144899064">వినియోగదారౠపేరౠలేదà±</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{à°à°µà±€ లేవà±}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831"><ph name="TEXT" /> శోధన</translation>
<translation id="4879491255372875719">ఆటోమేటికౠ(డిఫాలà±à°Ÿà±)</translation>
-<translation id="4879725228911483934">విండోలనౠతెరిచి, మీ à°¸à±à°•à±à°°à±€à°¨à±â€Œà°²à°ªà±ˆ ఉంచండి</translation>
<translation id="4880827082731008257">శోధన à°šà°°à°¿à°¤à±à°°</translation>
<translation id="4881695831933465202">తెరà±à°µà±</translation>
<translation id="4885256590493466218">చెకà±à°…à°µà±à°Ÿà±â€Œà°²à±‹ <ph name="CARD_DETAIL" />తో పేమెంటౠచేయండి</translation>
@@ -1247,6 +1279,7 @@
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">నైనà±à°¤à± రోలà±</translation>
<translation id="4901778704868714008">సేవౠచేయండి...</translation>
+<translation id="4905659621780993806">మీ à°…à°¡à±à°®à°¿à°¨à°¿à°¸à±à°Ÿà±à°°à±‡à°Ÿà°°à± మీ పరికరానà±à°¨à°¿ <ph name="DATE" />à°¨ <ph name="TIME" />కౠఆటోమేటికà±â€Œà°—à°¾ రీసà±à°Ÿà°¾à°°à±à°Ÿà± చేసà±à°¤à°¾à°°à±. మీ పరికరం రీసà±à°Ÿà°¾à°°à±à°Ÿà± కావడానికి à°®à±à°‚దే, తెరిచి ఉనà±à°¨ à°à°Ÿà±†à°®à±â€Œà°²à± à°à°µà±ˆà°¨à°¾ ఉంటే, వాటిని సేవౠచేయండి.</translation>
<translation id="4913987521957242411">ఎడమవైపౠఎగà±à°µ భాగంలో à°°à°‚à°§à±à°°à°¾à°²à±</translation>
<translation id="4918221908152712722"><ph name="APP_NAME" />నౠఇనà±â€Œà°¸à±à°Ÿà°¾à°²à± చేయండి (డౌనà±â€Œà°²à±‹à°¡à± చేయాలà±à°¸à°¿à°¨ అవసరం లేదà±)</translation>
<translation id="4923459931733593730">చెలà±à°²à°¿à°‚à°ªà±</translation>
@@ -1255,6 +1288,7 @@
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, వెతకడానికి 'Tab'నౠనొకà±à°•à°¿, ఆపై 'Enter'నౠనొకà±à°•à°‚à°¡à°¿</translation>
<translation id="4930153903256238152">à°Žà°•à±à°•à±à°µ సామరà±à°¥à±à°¯à°‚</translation>
+<translation id="4940163644868678279">Chromeలో à°…à°œà±à°žà°¾à°¤ మోడà±</translation>
<translation id="4943872375798546930">ఫలితాలౠà°à°µà±€ లేవà±</translation>
<translation id="4950898438188848926">à°Ÿà±à°¯à°¾à°¬à± మారà±à°ªà± బటనà±, తెరిచియà±à°¨à±à°¨ à°Ÿà±à°¯à°¾à°¬à± <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" />కౠమారడానికి ఎంటరౠనొకà±à°•à°‚à°¡à°¿</translation>
<translation id="495170559598752135">à°šà°°à±à°¯à°²à±</translation>
@@ -1264,6 +1298,7 @@
<translation id="4968522289500246572">à°ˆ యాపౠమొబైలౠకోసం డిజైనౠచేయబడింది, పరిమాణానà±à°¨à°¿ మారà±à°šà°¡à°‚ సాధà±à°¯à°‚ కాకపోవచà±à°šà±. యాపà±â€Œà°¨à± ఉపయోగించేటపà±à°ªà±à°¡à± సమసà±à°¯à°²à± à°Žà°¦à±à°°à±à°•à°¾à°µà°šà±à°šà± లేదా మీరౠరీసà±à°Ÿà°¾à°°à±à°Ÿà± చేయవలసి రావచà±à°šà±.</translation>
<translation id="4969341057194253438">రికారà±à°¡à°¿à°‚à°—à±â€Œà°¨à± తొలగించండి</translation>
<translation id="4973922308112707173">à°Žà°—à±à°µ భాగంలో రెండౠరంధà±à°°à°¾à°²à±</translation>
+<translation id="4976702386844183910"><ph name="DATE" />à°¨ చివరగా సందరà±à°¶à°¿à°‚చారà±</translation>
<translation id="4984088539114770594">మైకà±à°°à±‹à°«à±‹à°¨à±â€Œà°¨à± ఉపయోగించాలా?</translation>
<translation id="4984339528288761049">Prc5 (à°Žà°¨à±à°µà°²à°ªà±)</translation>
<translation id="4989163558385430922">à°…à°¨à±à°¨à±€ చూడండి</translation>
@@ -1283,7 +1318,7 @@
<translation id="5029568752722684782">కాపీని తీసివేయి</translation>
<translation id="5030338702439866405">వీరిచే జారీచేయబడింది</translation>
<translation id="503069730517007720">"<ph name="SOFTWARE_NAME" />" యొకà±à°• రూటౠసరà±à°Ÿà°¿à°«à°¿à°•à±‡à°Ÿà± అవసరం, కానీ అది ఇనà±â€Œà°¸à±à°Ÿà°¾à°²à± చేయబడలేదà±. à°ˆ సమసà±à°¯à°¨à± పరిషà±à°•à°°à°¿à°‚చాలంటే, మీ IT నిరà±à°µà°¾à°¹à°•à±à°²à± "<ph name="SOFTWARE_NAME" />" యొకà±à°• కానà±à°«à°¿à°—రేషనౠసూచనలనౠపరిశీలించాలి. <ph name="FURTHER_EXPLANATION" /></translation>
-<translation id="5031870354684148875">Google à°…à°¨à±à°µà°¾à°¦à°‚ à°—à±à°°à°¿à°‚à°šà°¿</translation>
+<translation id="5031870354684148875">Google Translate à°—à±à°°à°¿à°‚à°šà°¿</translation>
<translation id="503498442187459473"><ph name="HOST" /> మీ కెమెరానౠమరియౠమైకà±à°°à±‹à°«à±‹à°¨à±â€Œà°¨à± ఉపయోగించాలనà±à°•à±à°‚టోంది</translation>
<translation id="5039762155821394373">ఫాంటౠసైజà±</translation>
<translation id="5039804452771397117">à°…à°¨à±à°®à°¤à°¿à°‚à°šà±</translation>
@@ -1325,6 +1360,7 @@
<translation id="5138227688689900538">తకà±à°•à±à°µ చూపà±</translation>
<translation id="5145883236150621069">విధాన à°ªà±à°°à°¤à°¿à°¸à±à°ªà°‚దనలో à°Žà°°à±à°°à°°à± కోడౠఉంది</translation>
<translation id="5146995429444047494"><ph name="ORIGIN" /> కోసం నోటిఫికేషనà±â€Œà°²à± à°¬à±à°²à°¾à°•à± చేయబడà±à°¡à°¾à°¯à°¿</translation>
+<translation id="514704532284964975">మీరౠమీ ఫోనà±â€Œà°¤à±‹ à°Ÿà±à°¯à°¾à°ªà± చేసే NFC పరికరాలలోని సమాచారానà±à°¨à°¿ <ph name="URL" /> చూడాలని, మారà±à°šà°¾à°²à°¨à±à°•à±à°‚టోంది</translation>
<translation id="5148809049217731050">ఫేసౠఅపà±</translation>
<translation id="515292512908731282">C4 (à°Žà°¨à±à°µà°²à°ªà±)</translation>
<translation id="5158275234811857234">à°®à±à°–à°šà°¿à°¤à±à°°à°‚</translation>
@@ -1346,9 +1382,10 @@
<translation id="5205222826937269299">పేరౠఆవశà±à°¯à°•à°‚</translation>
<translation id="5209518306177824490">SHA-1 వేలిమà±à°¦à±à°°</translation>
<translation id="5209670883520018268">à°Ÿà±à°°à±‡ 20</translation>
-<translation id="5215116848420601511">Google Payని ఉపయోగిసà±à°¤à±à°¨à±à°¨ చెలà±à°²à°¿à°‚పౠపదà±à°§à°¤à±à°²à± మరియౠఅడà±à°°à°¸à±â€Œà°²à±</translation>
+<translation id="5215116848420601511">Google Payని ఉపయోగిసà±à°¤à±à°¨à±à°¨ పేమెంటౠఆపà±à°·à°¨à±â€Œà°²à± మరియౠఅడà±à°°à°¸à±â€Œà°²à±</translation>
<translation id="5215363486134917902">ఫోలియో-Sp</translation>
<translation id="521659676233207110">à°Ÿà±à°°à±‡ 13</translation>
+<translation id="5216942107514965959">చివరిగా ఈరోజౠసందరà±à°¶à°¿à°‚చారà±</translation>
<translation id="5222812217790122047">ఈమెయిలà±â€Œ అవ‌స‌రం</translation>
<translation id="5230733896359313003">బటà±à°µà°¾à°¡à°¾ à°…à°¡à±à°°à°¸à±â€Œ</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1369,7 +1406,6 @@
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">డాకà±à°¯à±à°®à±†à°‚à°Ÿà± à°ªà±à°°à°¾à°ªà°°à±à°Ÿà±€à°²à±</translation>
<translation id="528468243742722775">à°®à±à°—à°¿à°‚à°šà±</translation>
-<translation id="5284909709419567258">నెటà±â€Œà°µà°°à±à°•à± à°…à°¡à±à°°à°¸à±â€Œà°²à±</translation>
<translation id="5285570108065881030">సేవౠచేసిన à°…à°¨à±à°¨à°¿ పాసà±â€Œà°µà°°à±à°¡à±â€Œà°²à°¨à± చూపà±</translation>
<translation id="5287240709317226393">à°•à±à°•à±à°•à±€à°²à°¨à± చూపించà±</translation>
<translation id="5287456746628258573">à°ˆ సైటౠఉపయోగించే à°­à°¦à±à°°à°¤à°¾ కానà±à°«à°¿à°—రేషనౠగడà±à°µà± à°®à±à°—ిసింది, మీ సమాచారానà±à°¨à°¿ (ఉదాహరణకౠపాసà±â€Œà°µà°°à±à°¡à±â€Œà°²à± లేదా à°•à±à°°à±†à°¡à°¿à°Ÿà± కారà±à°¡à± నంబరà±â€Œà°²à±) à°ˆ సైటà±â€Œà°•à± పంపినపà±à°ªà±à°¡à±, దానిని à°ˆ సైటౠబహిరà±à°—తం చేయవచà±à°šà±.</translation>
@@ -1445,7 +1481,7 @@
<translation id="5535133333442455806">'à°¬à±à°°à±Œà°œà°¿à°‚గౠడేటానౠకà±à°²à°¿à°¯à°°à± చేయి' బటనà±, Chrome సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²à°²à±‹ మీ à°¬à±à°°à±Œà°œà°¿à°‚గౠహిసà±à°Ÿà°°à±€, à°•à±à°•à±à°•à±€à°²à±, కాషౠఇంకా మరినà±à°¨à°¿à°‚టిని à°•à±à°²à°¿à°¯à°°à± చేయడానికి 'Enter' నొకà±à°•à°‚à°¡à°¿</translation>
<translation id="5536214594743852365">"<ph name="SECTION" />" విభాగానà±à°¨à°¿ చూపించà±</translation>
<translation id="5539243836947087108">రాఫà±à°Ÿà±</translation>
-<translation id="5540224163453853">à°…à°­à±à°¯à°°à±à°¥à°¿à°‚à°šà°¿à°¨ కథనానà±à°¨à°¿ à°•à°¨à±à°—ొనడం సాధà±à°¯à°ªà°¡à°²à±‡à°¦à±.</translation>
+<translation id="5540224163453853">à°°à°¿à°•à±à°µà±†à°¸à±à°Ÿà± చేసిన కథనానà±à°¨à°¿ à°•à°¨à±à°—ొనడం సాధà±à°¯à°ªà°¡à°²à±‡à°¦à±.</translation>
<translation id="5541086400771735334">మెయిలà±â€Œà°¬à°¾à°•à±à°¸à± 7</translation>
<translation id="5541546772353173584">ఈమెయిలà±â€Œà°¨à± జోడించండి</translation>
<translation id="5545756402275714221">మీ కోసం కథనాలà±</translation>
@@ -1453,6 +1489,7 @@
<translation id="5556459405103347317">మళà±à°²à±€ లోడౠచేయి</translation>
<translation id="5560088892362098740">à°—à°¡à±à°µà± à°®à±à°—ింపౠతేదీ</translation>
<translation id="55635442646131152">డాకà±à°¯à±à°®à±†à°‚à°Ÿà± à°šà±à°Ÿà±à°Ÿà±à°—ీత</translation>
+<translation id="5565613213060953222">à°…à°œà±à°žà°¾à°¤ à°Ÿà±à°¯à°¾à°¬à±â€Œà°¨à± తెరవండి</translation>
<translation id="5565735124758917034">సకà±à°°à°¿à°¯à°‚</translation>
<translation id="5570825185877910964">ఖాతానౠసంరకà±à°·à°¿à°‚à°šà±</translation>
<translation id="5571083550517324815">à°ˆ à°…à°¡à±à°°à°¸à±â€Œ à°¨à±à°‚à°¡à°¿ పికపౠచేసà±à°•à±‹à°µà°¡à°‚ సాధà±à°¯à°‚ కాదà±. వేరే à°…à°¡à±à°°à°¸à±â€Œà°¨à± à°Žà°‚à°šà±à°•à±‹à°‚à°¡à°¿.</translation>
@@ -1460,8 +1497,8 @@
<translation id="5586446728396275693">సేవౠచేయబడిన à°…à°¡à±à°°à°¸à±â€Œà°²à± లేవà±</translation>
<translation id="5587987780934666589">à°ªà±à°²à°¾à°Ÿà±â€Œà°«à°¾à°®à± యూజరà±</translation>
<translation id="5593349413089863479">కనెకà±à°·à°¨à± పూరà±à°¤à°¿à°—à°¾ à°¸à±à°°à°•à±à°·à°¿à°¤à°®à±ˆà°¨à°¦à°¿ కాదà±</translation>
-<translation id="5595485650161345191">à°…à°¡à±à°°à°¸à±â€Œà°¨à± సవరించà±</translation>
-<translation id="5598944008576757369">చెలà±à°²à°¿à°‚పౠపదà±à°§à°¤à°¿à°¨à°¿ à°Žà°‚à°šà±à°•à±‹à°‚à°¡à°¿</translation>
+<translation id="5595485650161345191">à°…à°¡à±à°°à°¸à±â€Œà°¨à± ఎడిటౠచేయండి</translation>
+<translation id="5598944008576757369">పేమెంటౠఆపà±à°·à°¨à±â€Œà°¨à± à°Žà°‚à°šà±à°•à±‹à°‚à°¡à°¿</translation>
<translation id="560412284261940334">నిరà±à°µà°¹à°£à°•à± మదà±à°¦à°¤à± లేదà±</translation>
<translation id="5605670050355397069">లెడà±à°œà°°à±</translation>
<translation id="5607240918979444548">ఆరà±à°•à°¿à°Ÿà±†à°•à±à°šà°°à±-C</translation>
@@ -1535,6 +1572,7 @@
<translation id="5869522115854928033">సేవౠచేసిన పాసà±â€Œà°µà°°à±à°¡à±â€Œà°²à±</translation>
<translation id="5873013647450402046">ఇది మీరేనని మీ à°¬à±à°¯à°¾à°‚కౠనిరà±à°§à°¾à°°à°¿à°‚à°šà±à°•à±‹à°µà°¾à°²à°¨à±à°•à±à°‚టోంది.</translation>
<translation id="5887400589839399685">కారà±à°¡à± సేవౠచేయబడింది</translation>
+<translation id="5887687176710214216">చివరిగా నినà±à°¨ సందరà±à°¶à°¿à°‚చారà±</translation>
<translation id="5895138241574237353">మళà±à°³à±€ à°ªà±à°°à°¾à°°à°‚à°­à°¿à°‚à°šà±</translation>
<translation id="5895187275912066135">జారీ చేయబడినది</translation>
<translation id="5901630391730855834">పసà±à°ªà±</translation>
@@ -1548,6 +1586,7 @@
<translation id="5921639886840618607">Google ఖాతాకౠకారà±à°¡à±â€Œà°¨à± సేవౠచేయాలా?</translation>
<translation id="5922853866070715753">దాదాపౠపూరà±à°¤à°¯à°¿à°‚ది</translation>
<translation id="5932224571077948991">సైటౠఅనà±à°šà°¿à°¤à°®à±ˆà°¨ లేదా తపà±à°ªà±à°¦à°¾à°°à°¿ పటà±à°Ÿà°¿à°‚చే à°ªà±à°°à°•à°Ÿà°¨à°²à°¨à± చూపà±à°¤à±à°‚ది</translation>
+<translation id="5938153366081463283">వరà±à°šà±à°µà°²à± కారà±à°¡à±â€Œà°¨à± జోడించండి</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347"><ph name="SITE_NAME" /> తెరవబడà±à°¤à±‹à°‚ది…</translation>
<translation id="5951495562196540101">వినియోగదారౠఖాతాతో నమోదౠచేయడం సాధà±à°¯à°ªà°¡à°¦à± (à°ªà±à°¯à°¾à°•à±‡à°œà±à°¡à± లైసెనà±à°¸à± à°…à°‚à°¦à±à°¬à°¾à°Ÿà±à°²à±‹ ఉంది).</translation>
@@ -1607,11 +1646,12 @@
<translation id="6105460996796456817">సైటà±â€Œà°¨à± à°•à±à°°à°¿à°¯à±‡à°Ÿà± చేయండి</translation>
<translation id="6106989379647458772"><ph name="PAGE" />లోని వెబà±â€Œà°ªà±‡à°œà±€ తాతà±à°•à°¾à°²à°¿à°•à°‚à°—à°¾ నిలిపివేయబడి ఉండవచà±à°šà± లేదా ఇది శాశà±à°µà°¤à°‚à°—à°¾ కొతà±à°¤ వెబౠఅడà±à°°à°¸à±â€Œà°•à± తరలించబడి ఉండవచà±à°šà±.</translation>
<translation id="6107012941649240045">వీరికి జారీ చేయబడింది</translation>
-<translation id="610911394827799129">మీ Google ఖాతా <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" />లో ఇతర రూపాలà±à°²à±‹ ఉనà±à°¨ à°¬à±à°°à±Œà°œà°¿à°‚à°—à± à°šà°°à°¿à°¤à±à°°à°¨à± కలిగి ఉండవచà±à°šà±</translation>
+<translation id="610911394827799129">మీ Google ఖాతా <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" />లో ఇతర రూపాలà±à°²à±‹ ఉనà±à°¨ à°¬à±à°°à±Œà°œà°¿à°‚గౠహిసà±à°Ÿà°°à±€à°¨à°¿ కలిగి ఉండవచà±à°šà±</translation>
<translation id="6116338172782435947">à°•à±à°²à°¿à°ªà±â€Œà°¬à±‹à°°à±à°¡à±â€Œà°•à± కాపీ చేసిన వచనం మరియౠచితà±à°°à°¾à°²à°¨à± చూడండి</translation>
<translation id="6120179357481664955">మీ UPI ID à°—à±à°°à±à°¤à±à°‚దా?</translation>
<translation id="6124432979022149706">Chrome Enterprise కనెకà±à°Ÿà°°à±â€Œà°²à±</translation>
<translation id="6127379762771434464">అంశానà±à°¨à°¿ తీసివేసారà±</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Chromeలో à°…à°œà±à°žà°¾à°¤ మోడౠగà±à°°à°¿à°‚à°šà°¿ మరింత తెలà±à°¸à±à°•à±‹à°‚à°¡à°¿<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">à°à°µà±ˆà°¨à°¾ కేబà±à°²à±â€Œà°²à°¨à± తనిఖీ చేయండి మరియౠమీరౠఉపయోగించే à°à°µà±ˆà°¨à°¾ రూటరà±â€Œà°²à±, మోడెమà±â€Œà°²à±
లేదా ఇతర నెటà±â€Œà°µà°°à±à°•à± పరికరాలనౠరీబూటౠచేయండి.</translation>
<translation id="614940544461990577">ఇలా చేసి à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚à°šà°‚à°¡à°¿:</translation>
@@ -1624,7 +1664,6 @@
<translation id="6169916984152623906">‌ఇపà±à°ªà±à°¡à± మీరౠవà±à°¯à°•à±à°¤à°¿à°—తంగా à°¬à±à°°à±Œà°œà± చేయవచà±à°šà± మరియౠఈ పరికరానà±à°¨à°¿ ఉపయోగించే ఇతర à°µà±à°¯à°•à±à°¤à±à°²à°•à± మీ కారà±à°¯â€Œà°•â€Œà°²à°¾à°ªà°‚ కనిపించదà±. అయినపà±à°ªà°Ÿà°¿à°•à±€, డౌనà±â€Œà°²à±‹à°¡à±â€Œà°²à± మరియౠబà±à°•à±â€Œà°®à°¾à°°à±à°•à±â€Œà°²à± సేవౠచేయబడతాయి.</translation>
<translation id="6177128806592000436">à°ˆ సైటà±â€Œà°¤à±‹ మీకà±à°¨à±à°¨ కనెకà±à°·à°¨à± à°¸à±à°°à°•à±à°·à°¿à°¤à°‚à°—à°¾ లేదà±</translation>
<translation id="6180316780098470077">à°ªà±à°¨à°ƒà°ªà±à°°à°¯à°¤à±à°¨à°¾à°² మధà±à°¯ విరామం</translation>
-<translation id="619448280891863779">మీ à°¸à±à°•à±à°°à±€à°¨à±â€Œà°²à°²à±‹ విండోలనౠతెరిచి, ఉంచడానికి సైటౠఅనà±à°®à°¤à°¿ అడగవచà±à°šà±</translation>
<translation id="6196640612572343990">థరà±à°¡à± పారà±à°Ÿà±€ à°•à±à°•à±à°•à±€à°²à°¨à± à°¬à±à°²à°¾à°•à± చేయండి</translation>
<translation id="6203231073485539293">మీ ఇంటరà±à°¨à±†à°Ÿà± కనెకà±à°·à°¨à±â€Œà°¨à± తనిఖీ చేయండి</translation>
<translation id="6218753634732582820">Chromium à°¨à±à°‚à°¡à°¿ à°…à°¡à±à°°à°¸à±â€Œà°¨à± తీసివేయాలా?</translation>
@@ -1646,8 +1685,8 @@
<translation id="6272088941196661550">మీ Chrome హిసà±à°Ÿà°°à±€à°²à±‹ మీ సందరà±à°­à±‹à°šà°¿à°¤à°®à±ˆà°¨ యాకà±à°Ÿà°¿à°µà°¿à°Ÿà±€à°¨à°¿ చూడటానికి మీ సెరà±à°šà±â€Œà°¨à± కొనసాగించండి</translation>
<translation id="6272383483618007430">Google à°…à°ªà±â€Œà°¡à±‡à°Ÿà±</translation>
<translation id="6276112860590028508">మీ పఠన లిసà±à°Ÿà±â€Œà°²à±‹ ఉనà±à°¨ పేజీలౠఇకà±à°•à°¡ కనిపిసà±à°¤à°¾à°¯à°¿</translation>
-<translation id="627746635834430766">తరà±à°µà°¾à°¤à°¿à°¸à°¾à°°à°¿ మరింత వేగంగా చెలà±à°²à°¿à°‚చడానికి, మీ కారà±à°¡à±, బిలà±à°²à°¿à°‚à°—à± à°…à°¡à±à°°à°¸à±â€Œà°¨à± మీ Google ఖాతాకౠసేవౠచేయండి.</translation>
-<translation id="6279098320682980337">వరà±à°šà±à°µà°²à± కారà±à°¡à± నంబరౠపూరించబడలేదా? కాపీ చేయడం కోసం కారà±à°¡à± వివరాలనౠకà±à°²à°¿à°•à± చేయండి</translation>
+<translation id="627746635834430766">తరà±à°µà°¾à°¤à°¿à°¸à°¾à°°à°¿ మరింత వేగంగా పేమెంటౠచేయడానికి, మీ కారà±à°¡à±, బిలà±à°²à°¿à°‚à°—à± à°…à°¡à±à°°à°¸à±â€Œà°¨à± మీ Google ఖాతాకౠసేవౠచేయండి.</translation>
+<translation id="6279183038361895380">మీ à°•à°°à±à°¸à°°à±â€Œà°¨à± చూపడానికి |<ph name="ACCELERATOR" />| నొకà±à°•à°‚à°¡à°¿</translation>
<translation id="6280223929691119688">à°ˆ à°…à°¡à±à°°à°¸à±â€Œà°•à± బటà±à°µà°¾à°¡à°¾ చేయడం సాధà±à°¯à°‚ కాదà±. వేరే à°…à°¡à±à°°à°¸à±â€Œà°¨à± à°Žà°‚à°šà±à°•à±‹à°‚à°¡à°¿.</translation>
<translation id="6282194474023008486">పోసà±à°Ÿà°²à± కోడà±</translation>
<translation id="6285507000506177184">'Chromeలో డౌనà±â€Œà°²à±‹à°¡à±â€Œà°²à°¨à± మేనేజౠచేయండి' బటనà±, Chromeలో మీరౠడౌనà±â€Œà°²à±‹à°¡à± చేసిన ఫైలà±à°¸à±â€Œà°¨à± మేనేజౠచేయడానికి 'Enter'నౠనొకà±à°•à°‚à°¡à°¿</translation>
@@ -1655,6 +1694,7 @@
<translation id="6290238015253830360">మీకౠసూచించిన కథనాలౠఇకà±à°•à°¡ కనిపిసà±à°¤à°¾à°¯à°¿</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{మీ పరికరం ఇపà±à°ªà±à°¡à± రీసà±à°Ÿà°¾à°°à±à°Ÿà± à°…à°µà±à°¤à±à°‚ది}=1{మీ పరికరం 1 సెకనà±à°²à±‹ రీసà±à°Ÿà°¾à°°à±à°Ÿà± à°…à°µà±à°¤à±à°‚ది}other{మీ పరికరం # సెకనà±à°²à°²à±‹ రీసà±à°Ÿà°¾à°°à±à°Ÿà± à°…à°µà±à°¤à±à°‚ది}}</translation>
<translation id="6302269476990306341">Chromeలో Google అసిసà±à°Ÿà±†à°‚టౠఆపివేయబడà±à°¤à±‹à°‚ది</translation>
<translation id="6305205051461490394"><ph name="URL" />ని చేరà±à°•à±‹à°²à±‡à°•à°ªà±‹à°¯à°¾à°®à±.</translation>
<translation id="6312113039770857350">వెబà±â€Œà°ªà±‡à°œà±€ à°…à°‚à°¦à±à°¬à°¾à°Ÿà±à°²à±‹ లేదà±</translation>
@@ -1687,7 +1727,7 @@
<translation id="6398277657359595425">బిగà±à°—à°°à°—à°¾ à°à°¡à°µà°¡à°‚</translation>
<translation id="6398765197997659313">à°«à±à°²à±-à°¸à±à°•à±à°°à±€à°¨à±â€Œ à°¨à±à°‚à°¡à°¿ నిషà±à°•à±à°°à°®à°¿à°‚à°šà±</translation>
<translation id="6401136357288658127">à°ˆ విధానం విసà±à°®à°°à°¿à°‚చబడింది. దానికి బదà±à°²à±à°—à°¾, మీరౠ<ph name="NEW_POLICY" /> విధానానà±à°¨à°¿ ఉపయోగించాలి.</translation>
-<translation id="6404511346730675251">à°¬à±à°•à±â€Œà°®à°¾à°°à±à°•à±â€Œà°¨à± సవరించà±</translation>
+<translation id="6404511346730675251">à°¬à±à°•à±â€Œà°®à°¾à°°à±à°•à±â€Œà°¨à± ఎడిటౠచేయండి</translation>
<translation id="6406765186087300643">C0 (à°Žà°¨à±à°µà°²à°ªà±)</translation>
<translation id="6410264514553301377"><ph name="CREDIT_CARD" /> à°—à°¡à±à°µà± à°®à±à°—ింపౠతేదీ మరియౠCVCని నమోదౠచేయండి</translation>
<translation id="6415778972515849510">మీ Google ఖాతానౠసంరకà±à°·à°¿à°‚à°šà±à°•à±‹à°µà°¡à°‚లో, మీ పాసà±â€Œà°µà°°à±à°¡à±â€Œà°¨à± మారà±à°šà°¡à°‚లో Chromium మీకౠసహాయపడగలదà±.</translation>
@@ -1712,7 +1752,7 @@
<translation id="6465306955648956876">పాసà±â€Œà°µà°°à±à°¡à±â€Œà°²à°¨à± నిరà±à°µà°¹à°¿à°‚à°šà°‚à°¡à°¿...</translation>
<translation id="6468485451923838994">ఫాంటà±â€Œà°²à±</translation>
<translation id="647261751007945333">పరికర విధానాలà±</translation>
-<translation id="6476284679642588870">చెలà±à°²à°¿à°‚పౠపదà±à°§à°¤à±à°²à°¨à± నిరà±à°µà°¹à°¿à°‚à°šà°‚à°¡à°¿</translation>
+<translation id="6476284679642588870">పేమెంటౠఆపà±à°·à°¨à±â€Œà°²à°¨à± నిరà±à°µà°¹à°¿à°‚à°šà°‚à°¡à°¿</translation>
<translation id="6489534406876378309">à°•à±à°°à°¾à°·à±â€Œà°²à°¨à± à°…à°ªà±â€Œà°²à±‹à°¡à± చేయడానà±à°¨à°¿ à°ªà±à°°à°¾à°°à°‚à°­à°¿à°‚à°šà°‚à°¡à°¿</translation>
<translation id="6493924760403974580">à°ˆ యాపౠఈ పరిమాణానà±à°¨à°¿ మాతà±à°°à°®à±‡ సపోరà±à°Ÿà± చేసà±à°¤à±à°‚ది.</translation>
<translation id="6494750904506170417">పాపà±-à°…à°ªà±â€Œà°²à±, మళà±à°²à°¿à°‚à°ªà±à°²à±</translation>
@@ -1728,6 +1768,7 @@
<translation id="6529602333819889595">&amp;తొలగించడానà±à°¨à°¿ à°ªà±à°¨à°°à°¾à°µà±ƒà°¤à°‚ చేయి</translation>
<translation id="6545864417968258051">à°¬à±à°²à±‚టూతౠసà±à°•à°¾à°¨à°¿à°‚à°—à±</translation>
<translation id="6547208576736763147">ఎడమవైపౠరెండౠరంధà±à°°à°¾à°²à±</translation>
+<translation id="6554732001434021288"><ph name="NUM_DAYS" /> రోజà±à°² à°•à±à°°à°¿à°¤à°‚ చివరిగా సందరà±à°¶à°¿à°‚చారà±</translation>
<translation id="6556866813142980365">మళà±à°²à±€ చేయి</translation>
<translation id="6569060085658103619">మీరౠఎకà±à°¸à±â€Œà°Ÿà±†à°¨à±à°·à°¨à±â€Œ పేజీని వీకà±à°·à°¿à°¸à±à°¤à±à°¨à±à°¨à°¾à°°à±</translation>
<translation id="6573200754375280815">à°•à±à°¡à°¿à°µà±ˆà°ªà± రెండౠరంధà±à°°à°¾à°²à±</translation>
@@ -1763,14 +1804,14 @@
<translation id="6665553082534466207">à°•à±à°¡à°¿à°µà±ˆà°ªà± మూడౠరంధà±à°°à°¾à°²à±</translation>
<translation id="6671697161687535275">Chromium à°¨à±à°‚à°¡à°¿ ఫారమౠసూచననౠతీసివేయాలా?</translation>
<translation id="6685834062052613830">సైనౠఅవà±à°Ÿà± చేసి, సెటపà±â€Œà°¨à± పూరà±à°¤à°¿ చేయండి</translation>
-<translation id="6687335167692595844">à°…à°­à±à°¯à°°à±à°¥à°¿à°‚చబడిన ఫాంటౠపరిమాణం</translation>
+<translation id="6687335167692595844">à°°à°¿à°•à±à°µà±†à°¸à±à°Ÿà± చేయబడిన ఫాంటౠపరిమాణం</translation>
<translation id="6688743156324860098">à°…à°ªà±â€Œà°¡à±‡à°Ÿà± చేయి…</translation>
<translation id="6688775486821967877">à°ªà±à°°à°¸à±à°¤à±à°¤à°¾à°¨à°¿à°•à°¿ వరà±à°šà±à°µà°²à± కారà±à°¡à± à°…à°‚à°¦à±à°¬à°¾à°Ÿà±à°²à±‹ లేదà±, దయచేసి తరà±à°µà°¾à°¤ మళà±à°²à±€ à°Ÿà±à°°à±ˆ చేయండి</translation>
<translation id="6689249931105087298">సంబంధిత à°¬à±à°²à°¾à°•à± పాయింటౠకంపà±à°°à±†à°·à°¨à±</translation>
<translation id="6689271823431384964">మీరౠసైనౠఇనౠచేసి ఉనà±à°¨à°‚à°¦à±à°¨, మీ కారà±à°¡à±â€Œà°²à°¨à± మీ Google ఖాతాలో సేవౠచేసà±à°•à±‹à°—à°² అవకాశానà±à°¨à°¿ Chrome మీకౠఅందిసà±à°¤à±‹à°‚ది. మీరౠసెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²à°²à±‹ à°ˆ à°ªà±à°°à°µà°°à±à°¤à°¨à°¨à± మారà±à°šà°µà°šà±à°šà±. కారà±à°¡à±à°¦à°¾à°°à±à°¡à°¿ పేరౠమీ ఖాతా à°¨à±à°‚à°¡à°¿ అందించబడింది.</translation>
<translation id="6694681292321232194"><ph name="FIND_MY_PHONE_FOCUSED_FRIENDLY_MATCH_TEXT" />, Google ఖాతాలో మీ పరికరానà±à°¨à°¿ à°•à°¨à±à°—ొనడానికి Tabనౠనొకà±à°•à°¿, ఆపై Enterనౠనొకà±à°•à°‚à°¡à°¿</translation>
<translation id="6696588630955820014">'à°ˆ à°Ÿà±à°¯à°¾à°¬à±â€Œà°¨à± షేరౠచేయండి' బటనà±, 'లింకà±â€Œà°¨à± షేరౠచేయడం', 'QR కోడà±â€Œà°¨à± à°•à±à°°à°¿à°¯à±‡à°Ÿà± చేయడం', 'కాసà±à°Ÿà± చేయడం' ఇంకా మరెనà±à°¨à±‹ ఆపà±à°·à°¨à±â€Œà°² à°¦à±à°µà°¾à°°à°¾ à°ˆ à°Ÿà±à°¯à°¾à°¬à±â€Œà°¨à± షేరౠచేయడానికి 'Enter'నౠనొకà±à°•à°‚à°¡à°¿</translation>
-<translation id="6698381487523150993">సృషà±à°Ÿà°¿à°‚చబడింది:</translation>
+<translation id="6698381487523150993">à°•à±à°°à°¿à°¯à±‡à°Ÿà± చేయబడింది:</translation>
<translation id="6702919718839027939">పినౠచేయండి</translation>
<translation id="6710213216561001401">à°®à±à°¨à±à°ªà°Ÿà°¿</translation>
<translation id="6710594484020273272">&lt;శోధన పదానà±à°¨à°¿ టైపౠచేయండి&gt;</translation>
@@ -1781,14 +1822,13 @@
<translation id="6721678857435001674">మీ à°­à°¦à±à°°à°¤à°¾ à°•à±€ యొకà±à°• తయారీదారౠబà±à°°à°¾à°‚డౠపేరౠమరియౠమోడలà±â€Œà°¨à°¿ చూడండి</translation>
<translation id="6732087373923685049">కెమెరా</translation>
<translation id="6738516213925468394"><ph name="TIME" /> తేదీన మీ <ph name="BEGIN_LINK" />సింకà±â€Œ రహసà±à°¯ పదబంధం <ph name="END_LINK" />తో మీ డేటా à°Žà°¨à±â€Œà°•à±à°°à°¿à°ªà±à°Ÿà± చేయ‌బ‌డింది. సింకà±â€Œà°¨à± à°ªà±à°°à°¾à°°à°‚భించడానికి దీనà±à°¨à°¿ నమోదౠచేయండి.</translation>
-<translation id="674375294223700098">తెలియని సరà±à°µà°°à± à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ లోపం.</translation>
+<translation id="674375294223700098">తెలియని సరà±à°µà°°à± à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ à°Žà°°à±à°°à°°à±.</translation>
<translation id="6744009308914054259">కనెకà±à°·à°¨à± కోసం వేచి ఉనà±à°¨à°ªà±à°ªà±à°¡à±, మీరౠఆఫà±â€Œà°²à±ˆà°¨à± కథనాలనౠచదవడానికి డౌనà±â€Œà°²à±‹à°¡à±â€Œà°²à°¨à± సందరà±à°¶à°¿à°‚చవచà±à°šà±.</translation>
<translation id="6753269504797312559">విధానం విలà±à°µ</translation>
<translation id="6755241357817244406">chrome://flags</translation>
<translation id="6757797048963528358">మీ పరికరం నిదà±à°°à°¾à°µà°¸à±à°¥à°•à± వెళà±à°²à°¿à°‚ది.</translation>
<translation id="6767985426384634228">à°…à°¡à±à°°à°¸à±â€Œà°¨à± à°…à°ªà±â€Œà°¡à±‡à°Ÿà± చేయాలా?</translation>
<translation id="6768213884286397650">హగకి (పోసà±à°Ÿà±â€Œà°•à°¾à°°à±à°¡à±)</translation>
-<translation id="6774185088257932239">à°…à°œà±à°žà°¾à°¤ మోడౠగà±à°°à°¿à°‚à°šà°¿ <ph name="BEGIN_LINK" />మరింత తెలà±à°¸à±à°•à±‹à°‚à°¡à°¿<ph name="END_LINK" /></translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">నీలి ఊదా à°°à°‚à°—à±</translation>
<translation id="6786747875388722282">à°Žà°•à±à°¸à±â€Œà°Ÿà±†à°¨à±à°·à°¨à±â€Œà°²à±</translation>
@@ -1872,13 +1912,12 @@
<translation id="706295145388601875">Chrome సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²à°²à±‹ à°…à°¡à±à°°à°¸à±â€Œà°²à°¨à± జోడించండి, మేనేజౠచేయండి</translation>
<translation id="7064851114919012435">సంపà±à°°à°¦à°¿à°‚పౠసమాచారం</translation>
<translation id="7068733155164172741"><ph name="OTP_LENGTH" />-అంకెల కోడà±â€Œà°¨à± ఎంటరౠచేయండి</translation>
-<translation id="7070090581017165256">à°ˆ సైటౠగà±à°°à°¿à°‚à°šà°¿</translation>
<translation id="70705239631109039">మీ కనెకà±à°·à°¨à± పూరà±à°¤à°¿à°—à°¾ à°¸à±à°°à°•à±à°·à°¿à°¤à°®à±ˆà°¨à°¦à°¿ కాదà±</translation>
<translation id="7075452647191940183">à°°à°¿à°•à±à°µà±†à°¸à±à°Ÿà±â€Œ చాలా పెదà±à°¦à°¦à°¿à°—à°¾ ఉంది</translation>
<translation id="7079718277001814089">à°ˆ సైటà±â€Œà°²à±‹ మాలà±à°µà±‡à°°à± ఉంది</translation>
<translation id="7081308185095828845">మీ పరికరంలో à°ˆ ఫీచరౠఅందà±à°¬à°¾à°Ÿà±à°²à±‹ లేదà±</translation>
<translation id="7083258188081898530">à°Ÿà±à°°à±‡ 9</translation>
-<translation id="7086090958708083563">à°…à°ªà±â€Œà°²à±‹à°¡à±â€Œà°¨à± యూజరౠఅభà±à°¯à°°à±à°¥à°¿à°‚చారà±</translation>
+<translation id="7086090958708083563">à°…à°ªà±â€Œà°²à±‹à°¡à±â€Œà°¨à± యూజరౠరికà±à°µà±†à°¸à±à°Ÿà± చేశారà±</translation>
<translation id="7087282848513945231">కౌంటి</translation>
<translation id="7095139009144195559"><ph name="MANAGE_SITE_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />, Chrome సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²à°²à±‹ à°…à°¨à±à°®à°¤à±à°²à°¨à± మేనేజౠచేయడానికి, అలాగే సైటà±â€Œà°² అంతటా à°¸à±à°Ÿà±‹à°°à± చేయబడిన డేటానౠమేనేజౠచేయడానికి 'Tab'నౠనొకà±à°•à°¿, ఆపై 'Enter'నౠనొకà±à°•à°‚à°¡à°¿</translation>
<translation id="7096937462164235847">à°ˆ వెబà±â€à°¸à±ˆà°Ÿà±â€Œà°•à± సంబంధించిన à°—à±à°°à±à°¤à°¿à°‚పౠవెరిఫై చేయబడలేదà±.</translation>
@@ -1889,6 +1928,12 @@
<translation id="7111012039238467737">(చెలà±à°²à±à°¤à±à°‚ది)</translation>
<translation id="7118618213916969306">à°•à±à°²à°¿à°ªà±â€Œà°¬à±‹à°°à±à°¡à± URL, <ph name="SHORT_URL" /> కోసం వెతకండి</translation>
<translation id="7119414471315195487">ఇతర à°Ÿà±à°¯à°¾à°¬à±â€Œà°²à± లేదా à°ªà±à°°à±‹à°—à±à°°à°¾à°®à±â€Œà°²à°¨à± మూసివేయండి</translation>
+<translation id="7129355289156517987">మీరౠఅనà±à°¨à°¿ Chromium à°…à°œà±à°žà°¾à°¤ à°Ÿà±à°¯à°¾à°¬à±â€Œà°²à°¨à± మూసివేసినపà±à°ªà±à°¡à±, à°† à°Ÿà±à°¯à°¾à°¬à±â€Œà°²à°²à±‹à°¨à°¿ మీ యాకà±à°Ÿà°¿à°µà°¿à°Ÿà±€ à°ˆ పరికరం à°¨à±à°‚à°¡à°¿ తీసివేయబడà±à°¤à±à°‚ది:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />à°¬à±à°°à±Œà°œà°¿à°‚గౠయాకà±à°Ÿà°¿à°µà°¿à°Ÿà±€<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />సెరà±à°šà± హిసà±à°Ÿà°°à±€<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ఫారమà±â€Œà°²à°²à±‹ ఎంటరౠచేసిన సమాచారం<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">à°ˆ à°…à°¡à±à°°à°¸à±â€Œà°•à± రవాణా చేయడం సాధà±à°¯à°‚ కాదà±. వేరే à°…à°¡à±à°°à°¸à±â€Œà°¨à± à°Žà°‚à°šà±à°•à±‹à°‚à°¡à°¿.</translation>
<translation id="7132939140423847331">మీ à°…à°¡à±à°®à°¿à°¨à± à°ˆ డేటానౠకాపీ చేయకà±à°‚à°¡à°¾ నిషేధించారà±.</translation>
<translation id="7135130955892390533">à°¸à±à°¥à°¿à°¤à°¿à°¨à°¿ చూపà±</translation>
@@ -1911,6 +1956,7 @@
<translation id="7192203810768312527"><ph name="SIZE" /> à°¸à±à°Ÿà±‹à°°à±‡à°œà±€à°¨à°¿ ఖాళీ చేసà±à°¤à±à°‚ది. కొనà±à°¨à°¿ సైటà±â€Œà°²à°¨à± మీరౠతరà±à°µà°¾à°¤à°¿à°¸à°¾à°°à°¿ సందరà±à°¶à°¿à°‚చినపà±à°ªà±à°¡à± అవి మరింత నెమà±à°®à°¦à°¿à°—à°¾ లోడౠకావచà±à°šà±.</translation>
<translation id="719464814642662924">వీసా</translation>
<translation id="7201591969684833065">మీ నిరà±à°µà°¾à°¹à°•à±à°¡à± వీటిని చూడగలరà±:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, à°ªà±à°°à±ˆà°µà±‡à°Ÿà±â€Œà°—à°¾ à°¬à±à°°à±Œà°œà± చేసేందà±à°•à± కొతà±à°¤ à°…à°œà±à°žà°¾à°¤ à°Ÿà±à°¯à°¾à°¬à±â€Œà°¨à± తెరవడానికి Tabనౠనొకà±à°•à°¿, ఆపై Enterనౠనొకà±à°•à°‚à°¡à°¿</translation>
<translation id="7202346780273620635">లెటరà±-అదనం</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> à°­à°¦à±à°°à°¤à°¾ à°ªà±à°°à°®à°¾à°£à°¾à°²à°•à± à°•à°Ÿà±à°Ÿà±à°¬à°¡à°¿ లేదà±.</translation>
<translation id="7210993021468939304">కంటెయినరౠలోపల Linux యాకà±à°Ÿà°¿à°µà°¿à°Ÿà±€, కంటెయినరౠలోపల Linux యాపà±â€Œà°²à°¨à± ఇనà±â€Œà°¸à±à°Ÿà°¾à°²à± చేయవచà±à°šà±</translation>
@@ -1942,6 +1988,7 @@
<translation id="7304562222803846232">Google ఖాతాకౠసంబంధించిన గోపà±à°¯à°¤à°¾ సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²à°¨à± మేనేజౠచేయండి</translation>
<translation id="7305756307268530424">నెమà±à°®à°¦à°¿à°—à°¾ à°ªà±à°°à°¾à°°à°‚à°­à°¿à°‚à°šà°‚à°¡à°¿</translation>
<translation id="7308436126008021607">à°¬à±à°¯à°¾à°•à±â€Œà°—à±à°°à±Œà°‚డౠసింకà±</translation>
+<translation id="7310392214323165548">పరికరం à°¤à±à°µà°°à°²à±‹à°¨à±‡ రీసà±à°Ÿà°¾à°°à±à°Ÿà± à°…à°µà±à°¤à±à°‚ది</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">కనెకà±à°·à°¨à± సహాయం</translation>
<translation id="7323804146520582233">"<ph name="SECTION" />" విభాగానà±à°¨à°¿ దాచà±</translation>
@@ -1949,6 +1996,7 @@
<translation id="7334320624316649418">&amp;మళà±à°²à±€ à°•à±à°°à°®à°‚ చేయడానà±à°¨à°¿ à°ªà±à°¨à°°à°¾à°µà±ƒà°¤à°‚ చేయి</translation>
<translation id="7335157162773372339">మీ కెమెరానౠఉపయోగించడానికి సైటౠఅనà±à°®à°¤à°¿ అడగవచà±à°šà±</translation>
<translation id="7337248890521463931">మరినà±à°¨à°¿ వరà±à°¸à°²à°¨à± చూపించà±</translation>
+<translation id="7337418456231055214">వరà±à°šà±à°µà°²à± కారà±à°¡à± నంబరà±â€Œà°¨à± పూరించలేదా? కాపీ చేయడం కోసం కారà±à°¡à± వివరాలనౠకà±à°²à°¿à°•à± చేయండి. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">మీ à°ªà±à°²à°¾à°Ÿà±â€Œà°«à°¾à°°à°®à±â€Œà°²à±‹ à°…à°‚à°¦à±à°¬à°¾à°Ÿà±à°²à±‹ లేదà±.</translation>
<translation id="733923710415886693">సరà±à°µà°°à± à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°¾à°¨à±à°¨à°¿ à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ పారదరà±à°¶à°•à°¤ à°¦à±à°µà°¾à°°à°¾ బహిరంగపరచలేదà±.</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1971,6 +2019,7 @@
<translation id="7378627244592794276">వదà±à°¦à±</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">వరà±à°¤à°¿à°‚à°šà°¦à±</translation>
+<translation id="7388594495505979117">{0,plural, =1{మీ పరికరం 1 నిమిషంలో రీసà±à°Ÿà°¾à°°à±à°Ÿà± à°…à°µà±à°¤à±à°‚ది}other{మీ పరికరం # నిమిషాలలో రీసà±à°Ÿà°¾à°°à±à°Ÿà± à°…à°µà±à°¤à±à°‚ది}}</translation>
<translation id="7390545607259442187">కారà±à°¡à±â€Œà°¨à°¿ నిరà±à°§à°¾à°°à°¿à°‚à°šà°‚à°¡à°¿</translation>
<translation id="7392089738299859607">à°…à°¡à±à°°à°¸à±â€Œà°¨à± à°…à°ªà±â€Œà°¡à±‡à°Ÿà± చేయండి</translation>
<translation id="7399802613464275309">à°­à°¦à±à°°à°¤à°¾ చెకà±-à°…à°ªà±</translation>
@@ -2007,6 +2056,12 @@
<translation id="7485870689360869515">డేటా à°•à°¨à±à°—ొనబడలేదà±.</translation>
<translation id="7495528107193238112">à°ˆ కంటెంటౠబà±à°²à°¾à°•à± అయింది. à°ˆ సమసà±à°¯ పరిషà±à°•à°¾à°°à°‚ కోసం సైటౠఓనరà±â€Œà°¨à± సంపà±à°°à°¦à°¿à°‚à°šà°‚à°¡à°¿.</translation>
<translation id="7497998058912824456">'డాకà±â€Œà°¨à± à°•à±à°°à°¿à°¯à±‡à°Ÿà± చేయండి' బటనà±, కొతà±à°¤ Google డాకà±â€Œà°¨à± à°¤à±à°µà°°à°—à°¾ à°•à±à°°à°¿à°¯à±‡à°Ÿà± చేయడానికి Enterనౠనొకà±à°•à°‚à°¡à°¿</translation>
+<translation id="7506488012654002225">Chromium à°ˆ కింది సమాచారానà±à°¨à°¿ <ph name="BEGIN_EMPHASIS" />సేవౠచేయదà±<ph name="END_EMPHASIS" />:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />మీ à°¬à±à°°à±Œà°œà°¿à°‚గౠహిసà±à°Ÿà°°à±€
+ <ph name="LIST_ITEM" />à°•à±à°•à±à°•à±€à°²à±, సైటౠడేటా
+ <ph name="LIST_ITEM" />ఫారమà±â€Œà°²à°²à±‹ ఎంటరౠచేసిన సమాచారం
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">అందించబడిన విధాన పరికర id ఖాళీగా ఉంది లేదా à°ªà±à°°à°¸à±à°¤à±à°¤ పరికర idà°•à°¿ సరిపోలలేదà±</translation>
<translation id="7508870219247277067">వెనà±à°¨à°ªà°‚డౠఆకà±à°ªà°šà±à°š</translation>
<translation id="7511955381719512146">మీరౠఉపయోగిసà±à°¤à±à°¨à±à°¨ Wi-Fiకౠమీరà±<ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />నౠసందరà±à°¶à°¿à°‚à°šà°¡à°‚ అవసరం.</translation>
@@ -2036,7 +2091,7 @@
<translation id="7569952961197462199">Chrome à°¨à±à°‚à°¡à°¿ à°•à±à°°à±†à°¡à°¿à°Ÿà± కారà±à°¡à±â€Œà°¨à± తీసివేయాలా?</translation>
<translation id="7569983096843329377">నలà±à°ªà±</translation>
<translation id="7575207903026901870">సూచన బటనà±â€Œà°¨à± తీసివేసి, à°ˆ సూచననౠతీసివేయడానికి ఎంటరౠనొకà±à°•à°‚à°¡à°¿</translation>
-<translation id="7578104083680115302">మీరౠGoogleతో సేవౠచేసిన కారà±à°¡à±â€Œà°²à°¨à± ఉపయోగించి పరికరాలà±à°²à±‹à°¨à°¿ సైటà±â€Œà°²à± మరియౠఅనà±à°µà°°à±à°¤à°¨à°¾à°²à±à°²à±‹ శీఘà±à°°à°‚à°—à°¾ పేమెంటౠచేయండి.</translation>
+<translation id="7578104083680115302">మీరౠGoogleతో సేవౠచేసిన కారà±à°¡à±â€Œà°²à°¨à± ఉపయోగించి పరికరాలà±à°²à±‹à°¨à°¿ సైటà±â€Œà°²à± మరియౠయాపà±â€Œà°²à°²à±‹ శీఘà±à°°à°‚à°—à°¾ పేమెంటౠచేయండి.</translation>
<translation id="7581199239021537589">2à°µ వైపౠపà±à°°à°¿à°‚à°Ÿà±â€Œà°²à±‹ à°šà°¿à°¤à±à°°à°¾à°¨à±à°¨à°¿ Y à°…à°•à±à°·à°‚లో జరపà±</translation>
<translation id="7582602800368606489">Google Calendarలో à°¤à±à°µà°°à°—à°¾ కొతà±à°¤ ఈవెంటà±â€Œà°¨à± à°•à±à°°à°¿à°¯à±‡à°Ÿà± చేయండి</translation>
<translation id="7591288787774558753">గోపà±à°¯à°®à±ˆà°¨ కంటెంటà±â€Œà°¨à± షేరౠచేయాలా?</translation>
@@ -2111,7 +2166,7 @@
<translation id="7791196057686275387">బండిలà±</translation>
<translation id="7791543448312431591">జోడించà±</translation>
<translation id="7798389633136518089">à°ˆ పాలసీ, à°•à±à°²à±Œà°¡à± సోరà±à°¸à± à°¦à±à°µà°¾à°°à°¾ సెటౠచేయబడనందà±à°¨ విసà±à°®à°°à°¿à°‚చబడింది.</translation>
-<translation id="7800304661137206267"><ph name="KX" />‌నౠకీ మారà±à°ªà°¿à°¡à°¿ విధానం లాగా మరియౠసందేశ à°ªà±à°°à°¾à°®à°¾à°£à±€à°•à°°à°£ కోసం <ph name="CIPHER" />‌నౠ<ph name="MAC" />తో ఉపయోగించడం à°¦à±à°µà°¾à°°à°¾ కనెకà±à°·à°¨à± à°—à±à°ªà±à°¤à±€à°•à°°à°¿à°‚చబడింది.</translation>
+<translation id="7800304661137206267"><ph name="KX" />‌నౠకీ మారà±à°ªà°¿à°¡à°¿ విధానం లాగా మరియౠసందేశ à°ªà±à°°à°¾à°®à°¾à°£à±€à°•à°°à°£ కోసం <ph name="CIPHER" />‌నౠ<ph name="MAC" />తో ఉపయోగించడం à°¦à±à°µà°¾à°°à°¾ కనెకà±à°·à°¨à± à°Žà°¨à±â€Œà°•à±à°°à°¿à°ªà±à°Ÿà± చేయబడింది.</translation>
<translation id="7802523362929240268">సైటౠచటà±à°Ÿà°¬à°¦à±à°§à°®à±ˆà°¨à°¦à°¿</translation>
<translation id="780301667611848630">వదà±à°¦à± , ధనà±à°¯à°µà°¾à°¦à°¾à°²à±</translation>
<translation id="7805571567667010077">మీ సంసà±à°¥ à°¦à±à°µà°¾à°°à°¾ మేనేజౠచేయబడà±à°¤à±à°‚ది</translation>
@@ -2120,7 +2175,6 @@
<translation id="7813600968533626083">Chrome à°¨à±à°‚à°¡à°¿ ఫారమౠసూచననౠతీసివేయాలా?</translation>
<translation id="781440967107097262">à°•à±à°²à°¿à°ªà±â€Œà°¬à±‹à°°à±à°¡à±â€Œà°•à± షేరౠచేయాలా?</translation>
<translation id="7815407501681723534">'<ph name="SEARCH_STRING" />' కోసం <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> à°•à°¨à±à°—ొనబడà±à°¡à°¾à°¯à°¿</translation>
-<translation id="782125616001965242">à°ˆ సైటà±â€Œà°•à± సంబంధించిన సమాచారానà±à°¨à°¿ చూపించà±</translation>
<translation id="782886543891417279">మీరౠఉపయోగిసà±à°¤à±à°¨à±à°¨ Wi-Fi (<ph name="WIFI_NAME" />)కౠమీరౠదాని లాగినౠపేజీని సందరà±à°¶à°¿à°‚à°šà°¡à°‚ అవసరం.</translation>
<translation id="7836231406687464395">Postfix (à°Žà°¨à±à°µà°²à°ªà±)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{à°à°¦à±€ వదà±à°¦à±}=1{1 యాపౠ(<ph name="EXAMPLE_APP_1" />)}=2{2 యాపà±â€Œà°²à± (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}other{# యాపà±â€Œà°²à± (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}}</translation>
@@ -2137,7 +2191,6 @@
<translation id="7888575728750733395">à°ªà±à°°à°¿à°‚టౠరెండరింగౠఇంటెంటà±</translation>
<translation id="7894280532028510793">à°¸à±à°ªà±†à°²à±à°²à°¿à°‚గౠసరైనది అయితే, <ph name="BEGIN_LINK" />నెటà±â€Œà°µà°°à±à°•à± సమసà±à°¯ విశà±à°²à±‡à°·à°£à°²à°¨à± రనౠచేయడానికి à°Ÿà±à°°à±ˆ చేయండి<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (à°Žà°¨à±à°µà°²à°ªà±)</translation>
-<translation id="7931318309563332511">తెలియదà±</translation>
<translation id="793209273132572360">à°…à°¡à±à°°à°¸à±â€Œà°¨à± à°…à°ªà±â€Œà°¡à±‡à°Ÿà± చేయాలా?</translation>
<translation id="7932579305932748336">కోటà±</translation>
<translation id="79338296614623784">చెలà±à°²à±à°¬à°¾à°Ÿà± à°…à°¯à±à°¯à±‡ ఫోనౠనంబరà±â€Œà°¨à± నమోదౠచేయండి</translation>
@@ -2162,13 +2215,14 @@
<translation id="7976214039405368314">చాలా à°Žà°•à±à°•à±à°µ à°°à°¿à°•à±à°µà±†à°¸à±à°Ÿà±â€Œà°²à±</translation>
<translation id="7977538094055660992">à°…à°µà±à°Ÿà±â€Œà°ªà±à°Ÿà± పరికరం</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">దీనితో లింకౠచేయబడింది</translation>
<translation id="798134797138789862">వరà±à°šà±à°µà°²à± రియాలిటీ పరికరాలà±, డేటానౠఉపయోగించడానికి సైటౠఅనà±à°®à°¤à°¿ అడగవచà±à°šà±</translation>
<translation id="7984945080620862648">Chrome à°ªà±à°°à°¾à°¸à±†à°¸à± చేయలేని, గజిబిజిగా ఉండే ఆధారాలనౠవెబà±â€Œà°¸à±ˆà°Ÿà± పంపినందà±à°¨ మీరౠపà±à°°à°¸à±à°¤à±à°¤à°‚ <ph name="SITE" />ని సందరà±à°¶à°¿à°‚చలేరà±. నెటà±â€Œà°µà°°à±à°•à± లోపాలౠమరియౠదాడà±à°²à± సాధారణంగా తాతà±à°•à°¾à°²à°¿à°•à°‚గానే ఉంటాయి, కావà±à°¨ à°ˆ పేజీ కాసేపటి తరà±à°µà°¾à°¤ పని చేసే అవకాశం ఉంది.</translation>
-<translation id="79859296434321399">మెరà±à°—ైన వాసà±à°¤à°µà°¿à°• à°…à°¨à±à°­à°µ కంటెంటà±â€Œà°¨à± చూడడానికి, ARCoreని ఇనà±â€Œà°¸à±à°Ÿà°¾à°²à± చేయండి</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">బైండà±</translation>
<translation id="7992044431894087211"><ph name="APPLICATION_TITLE" />తో à°¸à±à°•à±à°°à±€à°¨à± షేరింగౠకొనసాగించబడింది</translation>
<translation id="7995512525968007366">పేరà±à°•à±Šà°¨à°¬à°¡à°²à±‡à°¦à±</translation>
+<translation id="7998269595945679889">à°…à°œà±à°žà°¾à°¤ à°Ÿà±à°¯à°¾à°¬à± బటనà±â€Œà°¨à± తెరవండి, à°ªà±à°°à±ˆà°µà±‡à°Ÿà±â€Œà°—à°¾ à°¬à±à°°à±Œà°œà± చేసేందà±à°•à± కొతà±à°¤ à°…à°œà±à°žà°¾à°¤ à°Ÿà±à°¯à°¾à°¬à±â€Œà°¨à± తెరవడానికి, Enterనౠనొకà±à°•à°‚à°¡à°¿</translation>
<translation id="800218591365569300">మెమరీని ఖాళీ చేయడానికి ఇతర à°Ÿà±à°¯à°¾à°¬à±â€Œà°²à± లేదా à°ªà±à°°à±‹à°—à±à°°à°¾à°®à±â€Œà°²à°¨à± మూసివేయడానà±à°¨à°¿ à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚à°šà°‚à°¡à°¿.</translation>
<translation id="8004582292198964060">à°¬à±à°°à±Œà°œà°°à±</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{à°ˆ కారà±à°¡à±, దీని బిలà±à°²à°¿à°‚à°—à± à°…à°¡à±à°°à°¸à±â€Œ సేవౠచేయబడతాయి. <ph name="USER_EMAIL" />కౠసైనౠఇనౠచేసినపà±à°ªà±à°¡à± మీరౠదీనిని ఉపయోగించగలరà±.}other{à°ˆ కారà±à°¡à±â€Œà°²à±, వీటి బిలà±à°²à°¿à°‚à°—à± à°…à°¡à±à°°à°¸à±â€Œà°²à± సేవౠచేయబడతాయి. <ph name="USER_EMAIL" />కౠసైనౠఇనౠచేసినపà±à°ªà°¡à±, మీరౠవీటిని ఉపయోగించగలరà±.}}</translation>
@@ -2204,12 +2258,12 @@
<translation id="8094917007353911263">మీరౠఉపయోగిసà±à°¤à±à°¨à±à°¨ నెటà±â€Œà°µà°°à±à°•à±â€Œà°•à± మీరౠ<ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />నౠసందరà±à°¶à°¿à°‚à°šà°¡à°‚ అవసరం.</translation>
<translation id="809898108652741896">A6</translation>
<translation id="8100588592594801589">చెలà±à°²à°¨à°¿ కారà±à°¡à±â€Œà°²à± తీసివేయబడà±à°¡à°¾à°¯à°¿</translation>
-<translation id="8103161714697287722">చెలà±à°²à°¿à°‚పౠపదà±à°§à°¤à°¿</translation>
+<translation id="8103161714697287722">పేమెంటౠఆపà±à°·à°¨à±â€Œ</translation>
<translation id="8103643211515685474">à°à°¦à±‡à°®à±ˆà°¨à°¾ à°ªà±à°°à°¿à°‚టౠచేయండి</translation>
<translation id="8105368624971345109">ఆఫౠచేయి</translation>
<translation id="810875025413331850">సమీప పరికరాలౠà°à°µà±€ à°•à°¨à±à°—ొనబడలేదà±.</translation>
<translation id="8116925261070264013">à°®à±à°¯à±‚టౠచేసినవి</translation>
-<translation id="8118489163946903409">చెలà±à°²à°¿à°‚పౠపదà±à°§à°¤à°¿</translation>
+<translation id="8118489163946903409">పేమెంటౠఆపà±à°·à°¨à±â€Œ</translation>
<translation id="8124639700796374294">'Chromeనౠఅనà±à°•à±‚లీకరించండి' బటనà±, మీ à°¬à±à°°à±Œà°œà°°à± రూపానà±à°¨à°¿ à°…à°¨à±à°•à±‚లీకరించడానికి 'Enter'నౠనొకà±à°•à°‚à°¡à°¿</translation>
<translation id="8127301229239896662">మీ à°•à°‚à°ªà±à°¯à±‚టరౠలేదా నెటà±â€Œà°µà°°à±à°•à±â€Œà°²à±‹ "<ph name="SOFTWARE_NAME" />" సరిగà±à°—à°¾ ఇనà±â€Œà°¸à±à°Ÿà°¾à°²à± కాలేదà±. à°ˆ సమసà±à°¯à°¨à± పరిషà±à°•à°°à°¿à°‚చమని మీ IT నిరà±à°µà°¾à°¹à°•à±à°²à°¨à± కోరండి.</translation>
<translation id="8131740175452115882">నిరà±à°§à°¾à°°à°¿à°‚à°šà±</translation>
@@ -2228,6 +2282,7 @@
<translation id="8202370299023114387">వైరà±à°§à±à°¯à°‚</translation>
<translation id="8206978196348664717">Prc4 (à°Žà°¨à±à°µà°²à°ªà±)</translation>
<translation id="8211406090763984747">కనెకà±à°·à°¨à± à°¸à±à°°à°•à±à°·à°¿à°¤à°‚à°—à°¾ ఉంది</translation>
+<translation id="8217240300496046857">వెబౠఅంతటా మిమà±à°®à°²à±à°¨à°¿ à°Ÿà±à°°à°¾à°•à± చేయడానికి ఉపయోగించే à°•à±à°•à±à°•à±€à°²à°¨à± సైటà±â€Œà°²à± ఉపయోగించడం సాధà±à°¯à°‚ కాదà±. కొనà±à°¨à°¿ సైటà±â€Œà°²à°²à±‹à°¨à°¿ ఫీచరà±â€Œà°²à± సరిగà±à°—à°¾ పని చేయకపోవచà±à°šà±.</translation>
<translation id="8218327578424803826">కేటాయించిన à°¸à±à°¥à°¾à°¨à°‚:</translation>
<translation id="8220146938470311105">C7/C6 (à°Žà°¨à±à°µà°²à°ªà±)</translation>
<translation id="8225771182978767009">à°ˆ à°•à°‚à°ªà±à°¯à±‚à°Ÿà°°à±â€Œà°¨à± సెటపౠచేసిన à°µà±à°¯à°•à±à°¤à°¿ à°ˆ సైటà±â€Œà°¨à± à°¬à±à°²à°¾à°•à± చేయడం à°Žà°‚à°šà±à°•à±à°¨à±à°¨à°¾à°°à±.</translation>
@@ -2268,14 +2323,9 @@
<translation id="830498451218851433">సగం ఫోలà±à°¡à±</translation>
<translation id="8307358339886459768">à°šà°¿à°¨à±à°¨-ఫోటో</translation>
<translation id="8307888238279532626">ఇనà±â€Œà°¸à±à°Ÿà°¾à°²à± చేయబడిన యాపà±â€Œà°²à± అలాగే వాటిని à°Žà°‚à°¤ తరచà±à°—à°¾ ఉపయోగించినది తెలిపే వివరాలà±</translation>
+<translation id="8317207217658302555">ARCoreనౠఅపà±â€Œà°¡à±‡à°Ÿà± చేయాలా?</translation>
<translation id="831997045666694187">సాయంతà±à°°à°‚</translation>
<translation id="8321476692217554900">నోటిఫికేషనà±â€Œà°²à±</translation>
-<translation id="8328484624016508118">à°…à°¨à±à°¨à°¿ à°…à°œà±à°žà°¾à°¤ à°Ÿà±à°¯à°¾à°¬à±â€Œà°²à°¨à± మూసివేసిన తరà±à°µà°¾à°¤, Chrome వీటిని à°•à±à°²à°¿à°¯à°°à± చేసà±à°¤à±à°‚ది:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />à°ˆ పరికరం à°¨à±à°‚à°¡à°¿ మీ à°¬à±à°°à±Œà°œà°¿à°‚గౠయాకà±à°Ÿà°¿à°µà°¿à°Ÿà±€<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />à°ˆ పరికరం à°¨à±à°‚à°¡à°¿ మీ సెరà±à°šà± హిసà±à°Ÿà°°à±€<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />ఫారమà±â€Œà°²à°²à±‹ ఎంటరౠచేయబడిన సమాచారం<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489"><ph name="HOST_NAME" />à°•à°¿ యాకà±à°¸à±†à°¸à± నిరాకరించబడింది</translation>
<translation id="833262891116910667">హైలైటౠచేసà±à°¤à±à°‚ది</translation>
<translation id="8339163506404995330"><ph name="LANGUAGE" />లో ఉనà±à°¨ పేజీలౠఅనà±à°µà°¦à°¿à°‚చబడవà±</translation>
@@ -2327,6 +2377,7 @@
<translation id="8507227106804027148">ఆదేశ పంకà±à°¤à°¿</translation>
<translation id="8508648098325802031">శోధన à°šà°¿à°¹à±à°¨à°‚</translation>
<translation id="8511402995811232419">à°•à±à°•à±à°•à±€à°²à°¨à± మేనేజౠచేయండి</translation>
+<translation id="8519753333133776369">మీ à°…à°¡à±à°®à°¿à°¨à°¿à°¸à±à°Ÿà±à°°à±‡à°Ÿà°°à± à°…à°¨à±à°®à°¤à°¿à°‚à°šà°¿à°¨ HID పరికరం</translation>
<translation id="8522552481199248698">మీ Google ఖాతానౠసంరకà±à°·à°¿à°‚à°šà±à°•à±‹à°µà°¡à°‚లో, మీ పాసà±â€Œà°µà°°à±à°¡à±â€Œà°¨à± మారà±à°šà°¡à°‚లో Chrome మీకౠసహాయపడగలదà±.</translation>
<translation id="8530813470445476232">Chrome సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²à°²à±‹ మీ à°¬à±à°°à±Œà°œà°¿à°‚గౠహిసà±à°Ÿà°°à±€, à°•à±à°•à±à°•à±€à°²à±, కాషౠఇంకా మరినà±à°¨à°¿à°‚టిని à°•à±à°²à°¿à°¯à°°à± చేయండి</translation>
<translation id="8533619373899488139">à°¬à±à°²à°¾à°•à± చేయబడి ఉనà±à°¨ URLà°² లిసà±à°Ÿà±â€Œà°¨à±, మీ సిసà±à°Ÿà°®à± à°…à°¡à±à°®à°¿à°¨à°¿à°¸à±à°Ÿà±à°°à±‡à°Ÿà°°à± à°¦à±à°µà°¾à°°à°¾ అమలౠచేయబడిన ఇతర పాలసీలనౠచూడటానికి &lt;strong&gt;chrome://policy&lt;/strong&gt;ని సందరà±à°¶à°¿à°‚à°šà°‚à°¡à°¿.</translation>
@@ -2338,7 +2389,6 @@
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{à°…à°¨à±à°®à°¤à°¿à°¨à°¿ రీసెటౠచేయండి}other{à°…à°¨à±à°®à°¤à±à°²à°¨à± రీసెటౠచేయండి}}</translation>
<translation id="8555010941760982128">చెకౠఅవà±à°Ÿà± వదà±à°¦ à°ˆ కోడà±â€Œà°¨à± ఉపయోగించండి</translation>
<translation id="8557066899867184262">మీ కారà±à°¡à± వెనà±à°•à°µà±ˆà°ªà± CVC ఉంటà±à°‚ది.</translation>
-<translation id="8558485628462305855">మెరà±à°—ైన వాసà±à°¤à°µà°¿à°• à°…à°¨à±à°­à°µ కంటెంటà±â€Œà°¨à± చూడడానికి, ARCoreని à°…à°ªà±â€Œà°¡à±‡à°Ÿà± చేయండి</translation>
<translation id="8559762987265718583">మీ పరికరం తేదీ మరియౠసమయం <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> తపà±à°ªà±à°—à°¾ ఉనà±à°¨à°‚à°¦à±à°¨ (<ph name="DATE_AND_TIME" />)à°•à± à°ªà±à°°à±ˆà°µà±‡à°Ÿà± కనెకà±à°·à°¨à± à°à°°à±à°ªà°¾à°Ÿà± చేయబడదà±.</translation>
<translation id="8564182942834072828">విడి డాకà±à°¯à±à°®à±†à°‚à°Ÿà±â€Œà°²à±/విడి కాపీలà±</translation>
<translation id="8564985650692024650">మీరౠమీ <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> పాసà±â€Œà°µà°°à±à°¡à±â€Œà°¨à°¿ ఇతర సైటà±â€Œà°²à°²à±‹ తిరిగి ఉపయోగించినటà±à°²à°¯à°¿à°¤à±‡ దీనిని రీసెటౠచేయాలà±à°¸à°¿à°‚దిగా Chromium సిఫారà±à°¸à± చేసà±à°¤à±‹à°‚ది.</translation>
@@ -2357,6 +2407,7 @@
<translation id="865032292777205197">మోషనౠసెనà±à°¸à°¾à°°à±â€Œà°²à±</translation>
<translation id="8663226718884576429">ఆరà±à°¡à°°à± సారాంశం, <ph name="TOTAL_LABEL" />, మరినà±à°¨à°¿ వివరాలà±</translation>
<translation id="8666678546361132282">ఇంగà±à°²à±€à°·à±</translation>
+<translation id="8669306706049782872">విండోలనౠతెరిచి, ఉంచడానికి మీ à°¸à±à°•à±à°°à±€à°¨à±â€Œà°²à°•à± సంబంధించిన సమాచారానà±à°¨à°¿ ఉపయోగించండి</translation>
<translation id="867224526087042813">సంతకం</translation>
<translation id="8676424191133491403">ఆలసà±à°¯à°‚ లేదà±</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, సమాధానం, <ph name="ANSWER" /></translation>
@@ -2383,6 +2434,7 @@
<translation id="8731544501227493793">'పాసà±â€Œà°µà°°à±à°¡à±â€Œà°²à± మేనేజౠచేయి' బటనà±, Chrome సెటà±à°Ÿà°¿à°‚à°—à±â€Œà°²à°²à±‹ మీ పాసà±â€Œà°µà°°à±à°¡à±â€Œà°²à± చూసి, మేనేజౠచేయడానికి 'Enter' నొకà±à°•à°‚à°¡à°¿</translation>
<translation id="8734529307927223492"><ph name="MANAGER" />, మీ <ph name="DEVICE_TYPE" />నౠమేనేజౠచేసà±à°¤à±‹à°‚ది</translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, à°ªà±à°°à±ˆà°µà±‡à°Ÿà±â€Œà°—à°¾ à°¬à±à°°à±Œà°œà± చేసà±à°•à±à°¨à±‡à°‚à°¦à±à°•à± కొతà±à°¤ à°…à°œà±à°žà°¾à°¤ విండోనౠతెరవడానికి à°®à±à°‚దౠ'Tab'నౠనొకà±à°•à°¿, ఆపై 'Enter'నౠనొకà±à°•à°‚à°¡à°¿</translation>
+<translation id="8737685506611670901"><ph name="REPLACED_HANDLER_TITLE" />à°•à°¿ బదà±à°²à±à°—à°¾ <ph name="PROTOCOL" /> లింకà±â€Œà°²à°¨à± తెరవాలనà±à°•à±à°‚టోంది</translation>
<translation id="8738058698779197622">à°¸à±à°°à°•à±à°·à°¿à°¤ కనెకà±à°·à°¨à±â€Œà°¨à± à°à°°à±à°ªà°¾à°Ÿà± చేయడానికి, మీ గడియారానà±à°¨à°¿ సరైన సమయానికి సెటౠచేయాలి. à°Žà°‚à°¦à±à°•à°‚టే వెబà±â€Œà°¸à±ˆà°Ÿà±â€Œà°²à± వాటిని à°—à±à°°à±à°¤à°¿à°‚చడానికి ఉపయోగించే సరà±à°Ÿà°¿à°«à°¿à°•à±†à°Ÿà±â€Œà°²à± నిరà±à°¦à°¿à°·à±à°Ÿ కాలవà±à°¯à°µà°§à±à°²à°²à±‹ మాతà±à°°à°®à±‡ చెలà±à°²à±à°¬à°¾à°Ÿà± à°…à°µà±à°¤à°¾à°¯à°¿. మీ పరికరం యొకà±à°• గడియారం సమయం తపà±à°ªà±à°—à°¾ ఉనà±à°¨à°‚à°¦à±à°¨, Chromium à°ˆ సరà±à°Ÿà°¿à°«à°¿à°•à±†à°Ÿà±â€Œà°²à°¨à± ధృవీకరించలేకపోయింది.</translation>
<translation id="8740359287975076522"><ph name="HOST_NAME" /> &lt;abbr id="dnsDefinition"&gt;DNS à°…à°¡à±à°°à°¸à±â€Œ&lt;/abbr&gt; à°•à°¨à±à°—ొనబడలేదà±. సమసà±à°¯à°¨à± నిరà±à°§à°¾à°°à°¿à°¸à±à°¤à±‹à°‚ది.</translation>
<translation id="8742371904523228557"><ph name="ORIGIN" /> కోసం మీ కోడౠ<ph name="ONE_TIME_CODE" /></translation>
@@ -2410,6 +2462,7 @@
<translation id="883848425547221593">ఇతర à°¬à±à°•à±â€Œà°®à°¾à°°à±à°•à±â€Œà°²à±:</translation>
<translation id="884264119367021077">à°·à°¿à°ªà±à°ªà°¿à°‚à°—à± à°…à°¡à±à°°à°¸à±â€Œ</translation>
<translation id="884923133447025588">à° à°°à°¦à±à°¦à± విధానం à°•à°¨à±à°—ొనబడలేదà±.</translation>
+<translation id="8849262850971482943">అదనపౠభదà±à°°à°¤ కోసం మీ వరà±à°šà±à°µà°²à± కారà±à°¡à±â€Œà°¨à± ఉపయోగించండి</translation>
<translation id="885730110891505394">Googleతో భాగసà±à°µà°¾à°®à±à°¯à°‚</translation>
<translation id="8858065207712248076">మీరౠమీ <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> పాసà±â€Œà°µà°°à±à°¡à±â€Œà°¨à°¿ ఇతర సైటà±â€Œà°²à°²à±‹ తిరిగి ఉపయోగించినటà±à°²à°¯à°¿à°¤à±‡ దీనిని రీసెటౠచేయాలà±à°¸à°¿à°‚దిగా Chrome సిఫారà±à°¸à± చేసà±à°¤à±‹à°‚ది.</translation>
<translation id="885906927438988819">à°¸à±à°ªà±†à°²à±à°²à°¿à°‚గౠసరైనది అయితే, <ph name="BEGIN_LINK" />విండోల సమసà±à°¯ విశà±à°²à±‡à°·à°£à°²à°¨à± రనౠచేయడానికి à°Ÿà±à°°à±ˆ చేయండి<ph name="END_LINK" />.</translation>
@@ -2444,8 +2497,8 @@
<translation id="8971063699422889582">సరà±à°µà°°à± à°ªà±à°°à°®à°¾à°£à°ªà°¤à±à°°à°‚ à°—à°¡à±à°µà± à°®à±à°—ిసింది.</translation>
<translation id="8975012916872825179">ఫోనౠనంబరà±â€Œà°²à±, ఈమెయిలà±â€Œ à°…à°¡à±à°°à°¸à±â€Œà°²à± మరియౠబటà±à°µà°¾à°¡à°¾ à°…à°¡à±à°°à°¸à±â€Œà°²à± లాంటి సమాచారం ఉంటà±à°‚ది</translation>
<translation id="8975263830901772334">మీరౠమà±à°¦à±à°°à°¿à°‚చే ఫైళà±à°² పేరà±à°²à±</translation>
-<translation id="8978053250194585037">Google à°¸à±à°°à°•à±à°·à°¿à°¤ à°¬à±à°°à±Œà°œà°¿à°‚గౠఇటీవల <ph name="SITE" />లో <ph name="BEGIN_LINK" />à°«à°¿à°·à°¿à°‚à°—à±â€Œà°¨à°¿ à°—à±à°°à±à°¤à°¿à°‚చింది<ph name="END_LINK" />. ఫిషింగౠసైటà±â€Œà°²à± వేరే వెబà±â€Œà°¸à±ˆà°Ÿà±â€Œà°² వలె à°ªà±à°°à°µà°°à±à°¤à°¿à°‚à°šà°¡à°‚ à°¦à±à°µà°¾à°°à°¾ మిమà±à°®à°²à±à°¨à°¿ మాయ చేయవచà±à°šà±.</translation>
-<translation id="8983003182662520383">Google Payని ఉపయోగిసà±à°¤à±à°¨à±à°¨ చెలà±à°²à°¿à°‚పౠపదà±à°§à°¤à±à°²à± మరియౠఅడà±à°°à°¸à±â€Œà°²à±</translation>
+<translation id="8978053250194585037">Google à°¸à±à°°à°•à±à°·à°¿à°¤ à°¬à±à°°à±Œà°œà°¿à°‚గౠఇటీవల <ph name="SITE" />లో <ph name="BEGIN_LINK" />à°«à°¿à°·à°¿à°‚à°—à±â€Œà°¨à°¿ à°—à±à°°à±à°¤à°¿à°‚చింది<ph name="END_LINK" />. ఫిషింగౠసైటà±â€Œà°²à± వేరే వెబà±â€Œà°¸à±ˆà°Ÿà±â€Œà°² లాగా à°ªà±à°°à°µà°°à±à°¤à°¿à°‚à°šà°¡à°‚ à°¦à±à°µà°¾à°°à°¾ మిమà±à°®à°²à±à°¨à°¿ మాయ చేయవచà±à°šà±.</translation>
+<translation id="8983003182662520383">Google Payని ఉపయోగిసà±à°¤à±à°¨à±à°¨ పేమెంటౠఆపà±à°·à°¨à±â€Œà°²à± మరియౠఅడà±à°°à°¸à±â€Œà°²à±</translation>
<translation id="8983369100812962543">మీరౠఇపà±à°ªà±à°¡à± యాపౠపరిమాణం మారà±à°šà°µà°šà±à°šà±</translation>
<translation id="8987245424886630962"><ph name="VIEW_CHROME_HISTORY_FOCUSED_FRIENDLY_MATCH_TEXT" />, Chromeలో మీ à°¬à±à°°à±Œà°œà°¿à°‚గౠహిసà±à°Ÿà°°à±€à°¨à°¿ చూడడానికి Tabనౠనొకà±à°•à°¿, ఆపై Enterనౠనొకà±à°•à°‚à°¡à°¿</translation>
<translation id="8987927404178983737">నెల</translation>
@@ -2459,6 +2512,7 @@
<translation id="9004367719664099443">VR సెషనౠపà±à°°à±‹à°—à±à°°à±†à°¸à±â€Œà°²à±‹ ఉంది</translation>
<translation id="9005998258318286617">PDF డాకà±à°¯à±à°®à±†à°‚à°Ÿà±â€Œà°¨à± లోడౠచేయడం విఫలమైంది.</translation>
<translation id="9008201768610948239">విసà±à°®à°°à°¿à°‚à°šà±</translation>
+<translation id="901834265349196618">ఈమెయిలà±â€Œ</translation>
<translation id="9020200922353704812">కారà±à°¡à± బిలà±à°²à°¿à°‚à°—à± à°…à°¡à±à°°à°¸à±â€Œ అవసరం</translation>
<translation id="9020542370529661692">à°ˆ పేజీ <ph name="TARGET_LANGUAGE" />à°•à°¿ à°…à°¨à±à°µà°¦à°¿à°‚చబడింది</translation>
<translation id="9020742383383852663">A8</translation>
@@ -2507,6 +2561,7 @@
<translation id="9150045010208374699">మీ కెమెరానౠఉపయోగించండి</translation>
<translation id="9150685862434908345">మీ à°…à°¡à±à°®à°¿à°¨à°¿à°¸à±à°Ÿà±à°°à±‡à°Ÿâ€Œà°°à± మీ à°¬à±à°°à±Œà°œà°°à± సెటపà±â€Œà°¨à± రిమోటౠవిధానంలో మారà±à°šà°µà°šà±à°šà±. à°ˆ పరికరంలోని యాకà±à°Ÿà°¿à°µà°¿à°Ÿà±€à°¨à°¿ Chrome వెలà±à°ªà°² కూడా మేనేజౠచేసà±à°¤à±à°‚డవచà±à°šà±. <ph name="BEGIN_LINK" />మరింత తెలà±à°¸à±à°•à±‹à°‚à°¡à°¿<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">నవీకరించబడింది</translation>
+<translation id="9155211586651734179">ఆడియో పెరిఫెరలà±à°¸à± జోడించబడà±à°¡à°¾à°¯à°¿</translation>
<translation id="9157595877708044936">అమరà±à°šà±à°¤à±‹à°‚ది...</translation>
<translation id="9158625974267017556">C6 (à°Žà°¨à±à°µà°²à°ªà±)</translation>
<translation id="9164029392738894042">à°–à°šà±à°šà°¿à°¤à°¤à±à°µ తనిఖీ</translation>
@@ -2553,7 +2608,7 @@
<translation id="985956168329721395">Prc-32K</translation>
<translation id="987264212798334818">సాధారణం</translation>
<translation id="988159990683914416">డెవలపరౠబిలà±à°¡à±</translation>
-<translation id="989988560359834682">à°…à°¡à±à°°à°¸à±â€Œà°¨à± సవరించà±</translation>
+<translation id="989988560359834682">à°…à°¡à±à°°à°¸à±â€Œà°¨à± ఎడిటౠచేయండి</translation>
<translation id="991413375315957741">మోషనౠలేదా కాంతి సెనà±à°¸à°¾à°°à±â€Œà°²à±</translation>
<translation id="992115559265932548"><ph name="MICROSOFT_ACTIVE_DIRECTORY" /></translation>
<translation id="992256792861109788">à°—à±à°²à°¾à°¬à°¿ à°°à°‚à°—à±</translation>
diff --git a/chromium/components/strings/components_strings_th.xtb b/chromium/components/strings/components_strings_th.xtb
index 909bcb71ea4..278cb450b16 100644
--- a/chromium/components/strings/components_strings_th.xtb
+++ b/chromium/components/strings/components_strings_th.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">ดูรายละเอียด</translation>
<translation id="1030706264415084469"><ph name="URL" /> ต้องà¸à¸²à¸£à¸ˆà¸±à¸”เà¸à¹‡à¸šà¸‚้อมูลขนาดใหà¸à¹ˆà¸­à¸¢à¹ˆà¸²à¸‡à¸–าวรในอุปà¸à¸£à¸“์ของคุณ</translation>
<translation id="1032854598605920125">หมุนตามเข็มนาฬิà¸à¸²</translation>
+<translation id="1033329911862281889">โหมดไม่ระบุตัวตนไม่ได้ซ่อนà¸à¸²à¸£à¹ƒà¸Šà¹‰à¸‡à¸²à¸™à¸­à¸­à¸™à¹„ลน์ของคุณ
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />เว็บไซต์à¹à¸¥à¸°à¸šà¸£à¸´à¸à¸²à¸£à¸—ี่คุณใช้จะเห็นà¸à¸²à¸£à¹€à¸‚้าชม<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />นายจ้างหรือโรงเรียนติดตามà¸à¸´à¸ˆà¸à¸£à¸£à¸¡à¸à¸²à¸£à¸—่องเว็บได้<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ผู้ให้บริà¸à¸²à¸£à¸­à¸´à¸™à¹€à¸—อร์เน็ตจะตรวจสอบà¸à¸²à¸£à¹€à¸‚้าชมเว็บได้<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">ปิด</translation>
<translation id="1036982837258183574">à¸à¸” |<ph name="ACCELERATOR" />| เพื่อออà¸à¸ˆà¸²à¸à¹‚หมดเต็มหน้าจอ</translation>
<translation id="1038106730571050514">à¹à¸ªà¸”งคำà¹à¸™à¸°à¸™à¸³</translation>
<translation id="1038842779957582377">ไม่ทราบชื่อ</translation>
<translation id="1041998700806130099">ข้อความà¹à¸œà¹ˆà¸™à¸‡à¸²à¸™</translation>
<translation id="1048785276086539861">เมื่อคุณà¹à¸à¹‰à¹„ขคำอธิบายประà¸à¸­à¸š เอà¸à¸ªà¸²à¸£à¸™à¸µà¹‰à¸ˆà¸°à¸à¸¥à¸±à¸šà¹„ปเป็นมุมมองà¹à¸šà¸šà¸«à¸™à¹‰à¸²à¹€à¸”ียว</translation>
-<translation id="1049743911850919806">โหมดไม่ระบุตัวตน</translation>
<translation id="1050038467049342496">ปิดà¹à¸­à¸›à¸­à¸·à¹ˆà¸™à¹†</translation>
<translation id="1055184225775184556">&amp;เลิà¸à¸—ำà¸à¸²à¸£à¹€à¸žà¸´à¹ˆà¸¡</translation>
<translation id="1056898198331236512">คำเตือน</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">à¹à¸„ชนโยบายใช้ได้</translation>
<translation id="1130564665089811311">ปุ่มà¹à¸›à¸¥à¸«à¸™à¹‰à¸²à¹€à¸§à¹‡à¸š à¸à¸” Enter เพื่อà¹à¸›à¸¥à¸«à¸™à¹‰à¸²à¸™à¸µà¹‰à¸”้วย Google à¹à¸›à¸¥à¸ à¸²à¸©à¸²</translation>
<translation id="1131264053432022307">รูปภาพที่คุณคัดลอà¸</translation>
+<translation id="1142846828089312304">บล็อà¸à¸„ุà¸à¸à¸µà¹‰à¸‚องบุคคลที่สามในโหมดไม่ระบุตัวตน</translation>
<translation id="1150979032973867961">เซิร์ฟเวอร์นี้ไม่สามารถพิสูจน์ได้ว่าเป็น <ph name="DOMAIN" /> เพราะระบบปà¸à¸´à¸šà¸±à¸•à¸´à¸à¸²à¸£à¸‚องคอมพิวเตอร์ของคุณไม่เชื่อถือใบรับรองความปลอดภัย โดยอาจเà¸à¸´à¸”จาà¸à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าผิดหรือผู้บุà¸à¸£à¸¸à¸à¸—ี่ขัดขวางà¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸‚องคุณ</translation>
<translation id="1151972924205500581">ต้องมีรหัสผ่าน</translation>
<translation id="1156303062776767266">คุณà¸à¸³à¸¥à¸±à¸‡à¸”ูไฟล์ในเครื่องหรือไฟล์ที่à¹à¸Šà¸£à¹Œ</translation>
@@ -64,7 +70,6 @@
<translation id="1178581264944972037">หยุดชั่วคราว</translation>
<translation id="1181037720776840403">นำออà¸</translation>
<translation id="1186201132766001848">ตรวจสอบรหัสผ่าน</translation>
-<translation id="1195210374336998651">ไปที่à¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่าà¹à¸­à¸›</translation>
<translation id="1195558154361252544">ระบบจะบล็อà¸à¸à¸²à¸£à¹à¸ˆà¹‰à¸‡à¹€à¸•à¸·à¸­à¸™à¸‚องทุà¸à¹€à¸§à¹‡à¸šà¹„ซต์โดยอัตโนมัติ ยà¸à¹€à¸§à¹‰à¸™à¹€à¸§à¹‡à¸šà¹„ซต์ที่คุณอนุà¸à¸²à¸•</translation>
<translation id="1197088940767939838">สีส้ม</translation>
<translation id="1201402288615127009">ถัดไป</translation>
@@ -111,7 +116,7 @@
<translation id="1307966114820526988">ฟีเจอร์ที่เลิà¸à¹ƒà¸Šà¹‰à¸‡à¸²à¸™à¹à¸¥à¹‰à¸§</translation>
<translation id="1308113895091915999">มีข้อเสนอพิเศษ</translation>
<translation id="1312803275555673949">ดูหลัà¸à¸à¸²à¸™à¸ªà¸™à¸±à¸šà¸ªà¸™à¸¸à¸™</translation>
-<translation id="131405271941274527"><ph name="URL" /> ต้องà¸à¸²à¸£à¸ªà¹ˆà¸‡à¹à¸¥à¸°à¸£à¸±à¸šà¸‚้อมูลเมื่อคุณà¹à¸•à¸°à¹‚ทรศัพท์à¸à¸±à¸šà¸­à¸¸à¸›à¸à¸£à¸“์ NFC</translation>
+<translation id="1314311879718644478">ดูเนื้อหา Augmented Reality</translation>
<translation id="1314509827145471431">เย็บเล่มด้านขวา</translation>
<translation id="1318023360584041678">บันทึà¸à¹„ว้ในà¸à¸¥à¸¸à¹ˆà¸¡à¹à¸—็บ</translation>
<translation id="1319245136674974084">ไม่ต้องถามอีà¸à¸ªà¸³à¸«à¸£à¸±à¸šà¹à¸­à¸›à¸™à¸µà¹‰</translation>
@@ -161,6 +166,7 @@
<translation id="142858679511221695">ผู้ใช้ระบบคลาวด์</translation>
<translation id="1428729058023778569">คุณเห็นคำเตือนนี้เพราะเว็บไซต์ไม่รองรับ HTTPS <ph name="BEGIN_LEARN_MORE_LINK" />ดูข้อมูลเพิ่มเติม<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">พิมพ์</translation>
+<translation id="1432187715652018471">หน้าเว็บต้องà¸à¸²à¸£à¸•à¸´à¸”ตั้งเครื่องจัดà¸à¸²à¸£à¸šà¸£à¸´à¸à¸²à¸£</translation>
<translation id="1432581352905426595">จัดà¸à¸²à¸£à¹€à¸„รื่องมือค้นหา</translation>
<translation id="1436185428532214179">สามารถขอà¹à¸à¹‰à¹„ขไฟล์à¹à¸¥à¸°à¹‚ฟลเดอร์ในอุปà¸à¸£à¸“์ของคุณได้</translation>
<translation id="1442386063175183758">พับทบด้านขวา</translation>
@@ -181,6 +187,12 @@
<translation id="1483493594462132177">ส่ง</translation>
<translation id="1484290072879560759">เลือà¸à¸—ี่อยู่สำหรับจัดส่ง</translation>
<translation id="1492194039220927094">à¸à¸²à¸£à¸žà¸¸à¸Šà¸™à¹‚ยบาย:</translation>
+<translation id="149293076951187737">เมื่อคุณปิดà¹à¸—็บที่ไม่ระบุตัวตนใน Chrome ทั้งหมด ระบบจะล้างà¸à¸´à¸ˆà¸à¸£à¸£à¸¡à¹ƒà¸™à¹à¸—็บเหล่านั้นจาà¸à¸­à¸¸à¸›à¸à¸£à¸“์เครื่องนี้
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />à¸à¸´à¸ˆà¸à¸£à¸£à¸¡à¸à¸²à¸£à¸—่องเว็บ<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ประวัติà¸à¸²à¸£à¸„้นหา<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ข้อมูลที่ป้อนในà¹à¸šà¸šà¸Ÿà¸­à¸£à¹Œà¸¡<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">à¸à¸¥à¸±à¸šà¹„ปที่à¹à¸—็บ</translation>
<translation id="1501859676467574491">à¹à¸ªà¸”งบัตรจาà¸à¸šà¸±à¸à¸Šà¸µ Google ของคุณ</translation>
<translation id="1507202001669085618">&lt;p&gt;คุณจะเห็นข้อผิดพลาดนี้ หาà¸à¹ƒà¸Šà¹‰à¸žà¸­à¸£à¹Œà¸—ัล Wi-Fi ที่คุณต้องลงชื่อเข้าใช้à¸à¹ˆà¸­à¸™à¸ˆà¸¶à¸‡à¸ˆà¸°à¸ªà¸²à¸¡à¸²à¸£à¸–ออนไลน์ได้&lt;/p&gt;
@@ -208,6 +220,8 @@
<translation id="1559572115229829303">&lt;p&gt;ไม่สามารถสร้างà¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸ªà¹ˆà¸§à¸™à¸•à¸±à¸§à¹„ปที่ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> เนื่องจาà¸à¸§à¸±à¸™à¸—ี่à¹à¸¥à¸°à¹€à¸§à¸¥à¸² (<ph name="DATE_AND_TIME" />) ในอุปà¸à¸£à¸“์ไม่ถูà¸à¸•à¹‰à¸­à¸‡&lt;/p&gt;
&lt;p&gt;โปรดปรับวันที่à¹à¸¥à¸°à¹€à¸§à¸¥à¸²à¸ˆà¸²à¸à¸«à¸±à¸§à¸‚้อ&lt;strong&gt;ทั่วไป&lt;/strong&gt;ในà¹à¸­à¸›&lt;strong&gt;à¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่า&lt;/strong&gt;&lt;/p&gt;</translation>
+<translation id="1559839503761818503">ผู้ดูà¹à¸¥à¸£à¸°à¸šà¸šà¸ˆà¸°à¸£à¸µà¸ªà¸•à¸²à¸£à¹Œà¸—อุปà¸à¸£à¸“์ในวันที่ <ph name="DATE" /> เวลา <ph name="TIME" /></translation>
+<translation id="156703335097561114">ข้อมูลà¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¹€à¸„รือข่าย เช่น ที่อยู่ à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าอินเทอร์เฟซ à¹à¸¥à¸°à¸„ุณภาพà¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­</translation>
<translation id="1567040042588613346">นโยบายนี้ทำงานตามที่ควรจะเป็นà¹à¸•à¹ˆà¸¡à¸µà¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่าเดียวà¸à¸±à¸™à¹„ว้ที่อื่นà¹à¸¥à¸°à¸–ูà¸à¹à¸—นที่โดยนโยบายนี้</translation>
<translation id="1569487616857761740">ป้อนวันที่หมดอายุ</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@
<translation id="1583429793053364125">มีสิ่งผิดปà¸à¸•à¸´à¹€à¸à¸´à¸”ขึ้นในขณะที่à¹à¸ªà¸”งหน้าเว็บนี้</translation>
<translation id="1586541204584340881">ส่วนขยายที่คุณติดตั้ง</translation>
<translation id="1588438908519853928">ปà¸à¸•à¸´</translation>
+<translation id="1589050138437146318">ติดตั้ง ARCore ไหม</translation>
<translation id="1592005682883173041">à¸à¸²à¸£à¹€à¸‚้าถึงข้อมูลในเครื่อง</translation>
<translation id="1594030484168838125">เลือà¸</translation>
<translation id="160851722280695521">เล่นเà¸à¸¡à¹„ดโนเสาร์วิ่งใน Chrome</translation>
@@ -279,6 +294,7 @@
<translation id="1763864636252898013">เซิร์ฟเวอร์นี้ไม่สามารถพิสูจน์ได้ว่าเป็น <ph name="DOMAIN" /> เพราะระบบปà¸à¸´à¸šà¸±à¸•à¸´à¸à¸²à¸£à¸‚องอุปà¸à¸£à¸“์ของคุณไม่เชื่อถือใบรับรองความปลอดภัย โดยอาจเà¸à¸´à¸”จาà¸à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าผิดหรือผู้บุà¸à¸£à¸¸à¸à¸—ี่ขัดขวางà¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸‚องคุณ</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />ลองเรียà¸à¹ƒà¸Šà¹‰à¸à¸²à¸£à¸§à¸´à¸™à¸´à¸ˆà¸‰à¸±à¸¢à¹€à¸„รือข่ายของ Windows<ph name="END_LINK" /></translation>
<translation id="1772163372082567643">เซิร์ฟเวอร์ที่คุณà¸à¸³à¸¥à¸±à¸‡à¸ˆà¸°à¹€à¸‚้าถึง <ph name="ORIGIN" /> ได้ตั้งค่าส่วนหัวที่à¸à¸³à¸«à¸™à¸”ให้บังคับใช้นโยบายดั้งเดิมà¸à¸±à¸šà¸„ำขอทั้งหมดที่ส่งถึงเซิร์ฟเวอร์ à¹à¸•à¹ˆà¸ªà¹ˆà¸§à¸™à¸«à¸±à¸§à¸”ังà¸à¸¥à¹ˆà¸²à¸§à¸¡à¸µà¸£à¸¹à¸›à¹à¸šà¸šà¸—ี่ไม่ถูà¸à¸•à¹‰à¸­à¸‡ ซึ่งทำให้เบราว์เซอร์ดำเนินà¸à¸²à¸£à¸•à¸²à¸¡à¸„ำขอของคุณสำหรับ <ph name="SITE" /> ไม่ได้ ผู้ให้บริà¸à¸²à¸£à¹€à¸§à¹‡à¸šà¹„ซต์อาจใช้นโยบายดั้งเดิมในà¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าความปลอดภัยà¹à¸¥à¸°à¸žà¸£à¹‡à¸­à¸žà¹€à¸žà¸­à¸£à¹Œà¸•à¸µà¹‰à¸­à¸·à¹ˆà¸™à¹† ของเว็บไซต์</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />ดูข้อมูลเพิ่มเติมเà¸à¸µà¹ˆà¸¢à¸§à¸à¸±à¸šà¹‚หมดไม่ระบุตัวตนใน Chromium<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">à¹à¸—็บที่คุณเปิดไว้จะปราà¸à¸à¸—ี่นี่</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -406,6 +422,7 @@
<translation id="22081806969704220">ถาด 3</translation>
<translation id="2212735316055980242">ไม่พบนโยบาย</translation>
<translation id="2213606439339815911">à¸à¸³à¸¥à¸±à¸‡à¸”ึงรายà¸à¸²à¸£...</translation>
+<translation id="2213612003795704869">พิมพ์หน้าà¹à¸¥à¹‰à¸§</translation>
<translation id="2215727959747642672">à¸à¸²à¸£à¹à¸à¹‰à¹„ขไฟล์</translation>
<translation id="2218879909401188352">ผู้โจมตีที่à¸à¸³à¸¥à¸±à¸‡à¸­à¸¢à¸¹à¹ˆà¹ƒà¸™ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> สามารถติดตั้งà¹à¸­à¸›à¸­à¸±à¸™à¸•à¸£à¸²à¸¢à¸—ี่ทำลายอุปà¸à¸£à¸“์ของคุณ เพิ่มค่าใช้จ่ายà¹à¸à¸‡à¹ƒà¸™à¹ƒà¸šà¹à¸ˆà¹‰à¸‡à¸¢à¸­à¸”มือถือ หรือขโมยข้อมูลส่วนบุคคล <ph name="BEGIN_LEARN_MORE_LINK" />ดูข้อมูลเพิ่มเติม<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">ไม่มีอินเทอร์เน็ต</translation>
@@ -415,6 +432,7 @@
<translation id="2248949050832152960">ใช้ WebAuthn</translation>
<translation id="2250931979407627383">เย็บขอบด้านซ้าย</translation>
<translation id="225207911366869382">เลิà¸à¹ƒà¸Šà¹‰à¸‡à¸²à¸™à¸„่านี้à¸à¸±à¸šà¸™à¹‚ยบายนี้</translation>
+<translation id="2256115617011615191">รีสตาร์ทเลย</translation>
<translation id="2258928405015593961">ป้อนวันที่หมดอายุในอนาคตà¹à¸¥à¹‰à¸§à¸¥à¸­à¸‡à¸­à¸µà¸à¸„รั้ง</translation>
<translation id="225943865679747347">รหัสข้อผิดพลาด: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">ข้อผิดพลาดของ HTTP</translation>
@@ -442,6 +460,7 @@
<translation id="2337852623177822836">ผู้ดูà¹à¸¥à¸£à¸°à¸šà¸šà¹€à¸›à¹‡à¸™à¸œà¸¹à¹‰à¸„วบคุมà¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่า</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> ต้องà¸à¸²à¸£à¸ˆà¸±à¸šà¸„ู่</translation>
<translation id="2346319942568447007">รูปภาพที่คุณคัดลอà¸</translation>
+<translation id="2350796302381711542">ต้องà¸à¸²à¸£à¸­à¸™à¸¸à¸à¸²à¸•à¹ƒà¸«à¹‰ <ph name="HANDLER_HOSTNAME" /> เปิดลิงà¸à¹Œ <ph name="PROTOCOL" /> ทั้งหมดà¹à¸—น <ph name="REPLACED_HANDLER_TITLE" /> ไหม</translation>
<translation id="2354001756790975382">บุ๊à¸à¸¡à¸²à¸£à¹Œà¸à¸­à¸·à¹ˆà¸™à¹†</translation>
<translation id="2354430244986887761">เมื่อเร็วๆ นี้ Google Safe Browsing <ph name="BEGIN_LINK" />พบà¹à¸­à¸›à¸­à¸±à¸™à¸•à¸£à¸²à¸¢<ph name="END_LINK" />ใน <ph name="SITE" /></translation>
<translation id="2355395290879513365">ผู้โจมตีอาจเห็นรูปภาพที่คุณà¸à¸³à¸¥à¸±à¸‡à¸”ูอยู่บนเว็บไซต์นี้à¹à¸¥à¸°à¸«à¸¥à¸­à¸à¸¥à¸§à¸‡à¸„ุณโดยà¸à¸²à¸£à¹à¸à¹‰à¹„ขรูปภาพ</translation>
@@ -467,6 +486,7 @@
<translation id="2413528052993050574">เซิร์ฟเวอร์นี้ไม่สามารถพิสูจน์ได้ว่าเป็น <ph name="DOMAIN" /> เพราะอาจมีà¸à¸²à¸£à¹€à¸žà¸´à¸à¸–อนใบรับรองความปลอดภัย โดยอาจเà¸à¸´à¸”จาà¸à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าผิดหรือผู้บุà¸à¸£à¸¸à¸à¸—ี่ขัดขวางà¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸‚องคุณ</translation>
<translation id="2414886740292270097">มืด</translation>
<translation id="2430968933669123598">จัดà¸à¸²à¸£à¸šà¸±à¸à¸Šà¸µ Google à¸à¸” Enter เพื่อจัดà¸à¸²à¸£à¸‚้อมูล ความเป็นส่วนตัว à¹à¸¥à¸°à¸à¸²à¸£à¸£à¸±à¸à¸©à¸²à¸„วามปลอดภัยในบัà¸à¸Šà¸µ Google ของคุณ</translation>
+<translation id="2436186046335138073">อนุà¸à¸²à¸•à¹ƒà¸«à¹‰ <ph name="HANDLER_HOSTNAME" /> เปิดลิงà¸à¹Œ <ph name="PROTOCOL" /> ทั้งหมดไหม</translation>
<translation id="2438874542388153331">เจาะรูด้านขวา 4 รู</translation>
<translation id="2450021089947420533">เส้นทางà¸à¸²à¸£à¸—่องเว็บ</translation>
<translation id="2463739503403862330">à¸à¸£à¸­à¸à¸‚้อมูล</translation>
@@ -474,6 +494,7 @@
<translation id="2465655957518002998">เลือà¸à¸§à¸´à¸˜à¸µà¸™à¸³à¸ªà¹ˆà¸‡à¸ªà¸´à¸™à¸„้า</translation>
<translation id="2465688316154986572">เย็บด้วยลวดเย็บà¸à¸£à¸°à¸”าษ</translation>
<translation id="2465914000209955735">จัดà¸à¸²à¸£à¹„ฟล์ที่คุณดาวน์โหลดใน Chrome</translation>
+<translation id="2466004615675155314">à¹à¸ªà¸”งข้อมูลจาà¸à¹€à¸§à¹‡à¸š</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />เรียà¸à¹ƒà¸Šà¹‰à¸à¸²à¸£à¸§à¸´à¸™à¸´à¸ˆà¸‰à¸±à¸¢à¹€à¸„รือข่าย<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">ลำดับ 1 ถึง N</translation>
<translation id="2470767536994572628">เมื่อคุณà¹à¸à¹‰à¹„ขคำอธิบายประà¸à¸­à¸š เอà¸à¸ªà¸²à¸£à¸™à¸µà¹‰à¸ˆà¸°à¸à¸¥à¸±à¸šà¹„ปเป็นมุมมองà¹à¸šà¸šà¸«à¸™à¹‰à¸²à¹€à¸”ียวà¹à¸¥à¸°à¸à¸¥à¸±à¸šà¹„ปใช้à¸à¸²à¸£à¸«à¸¡à¸¸à¸™à¹à¸šà¸šà¹€à¸”ิม</translation>
@@ -494,6 +515,7 @@
<translation id="2523886232349826891">บันทึà¸à¹„ว้เฉพาะในอุปà¸à¸£à¸“์นี้</translation>
<translation id="2524461107774643265">เพิ่มข้อมูลอื่นๆ</translation>
<translation id="2529899080962247600">ช่องนี้ต้องมีข้อมูลไม่เà¸à¸´à¸™ <ph name="MAX_ITEMS_LIMIT" /> รายà¸à¸²à¸£ ระบบจะไม่สนใจรายà¸à¸²à¸£à¸­à¸·à¹ˆà¸™à¹† ทั้งหมด</translation>
+<translation id="2535585790302968248">เปิดà¹à¸—็บที่ไม่ระบุตัวตนà¹à¸—็บใหม่เพื่อท่องเว็บà¹à¸šà¸šà¸ªà¹ˆà¸§à¸™à¸•à¸±à¸§</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{à¹à¸¥à¸°à¸­à¸µà¸ 1 โดเมน}other{à¹à¸¥à¸°à¸­à¸µà¸ # โดเมน}}</translation>
<translation id="2536110899380797252">เพิ่มที่อยู่</translation>
<translation id="2539524384386349900">ตรวจหา</translation>
@@ -519,7 +541,14 @@
<translation id="2597378329261239068">เอà¸à¸ªà¸²à¸£à¸™à¸µà¹‰à¹„ด้รับà¸à¸²à¸£à¸›à¹‰à¸­à¸‡à¸à¸±à¸™à¸”้วยรหัสผ่าน โปรดป้อนรหัสผ่าน</translation>
<translation id="2609632851001447353">รูปà¹à¸šà¸šà¸•à¹ˆà¸²à¸‡à¹†</translation>
<translation id="2610561535971892504">คลิà¸à¹€à¸žà¸·à¹ˆà¸­à¸„ัดลอà¸</translation>
+<translation id="2617988307566202237">Chrome <ph name="BEGIN_EMPHASIS" />จะไม่บันทึà¸<ph name="END_EMPHASIS" />ข้อมูลต่อไปนี้
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ประวัติà¸à¸²à¸£à¸—่องเว็บ
+ <ph name="LIST_ITEM" />คุà¸à¸à¸µà¹‰à¹à¸¥à¸°à¸‚้อมูลเว็บไซต์
+ <ph name="LIST_ITEM" />ข้อมูลที่ป้อนในà¹à¸šà¸šà¸Ÿà¸­à¸£à¹Œà¸¡
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (ซองจดหมาย)</translation>
+<translation id="2623663032199728144">สามารถขอใช้ข้อมูลเà¸à¸µà¹ˆà¸¢à¸§à¸à¸±à¸šà¸«à¸™à¹‰à¸²à¸ˆà¸­à¹„ด้</translation>
<translation id="2625385379895617796">นาฬิà¸à¸²à¹€à¸£à¹‡à¸§à¹€à¸à¸´à¸™à¹„ป</translation>
<translation id="262745152991669301">สามารถขอเชื่อมต่อà¸à¸±à¸šà¸­à¸¸à¸›à¸à¸£à¸“์ USB ได้</translation>
<translation id="2629325967560697240"><ph name="BEGIN_ENHANCED_PROTECTION_LINK" />เปิดà¸à¸²à¸£à¸›à¸à¸›à¹‰à¸­à¸‡à¸—ี่ปรับปรุงà¹à¸¥à¹‰à¸§<ph name="END_ENHANCED_PROTECTION_LINK" />เพื่อให้ Chrome รัà¸à¸©à¸²à¸„วามปลอดภัยในระดับสูงสุด</translation>
@@ -553,6 +582,7 @@
<translation id="2709516037105925701">ป้อนอัตโนมัติ</translation>
<translation id="2713444072780614174">สีขาว</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" /> à¸à¸” Tab ตามด้วย Enter เพื่อจัดà¸à¸²à¸£à¸à¸²à¸£à¸Šà¸³à¸£à¸°à¹€à¸‡à¸´à¸™à¹à¸¥à¸°à¸‚้อมูลบัตรเครดิตในà¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่า Chrome</translation>
+<translation id="271663710482723385">à¸à¸” |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| เพื่อออà¸à¸ˆà¸²à¸à¹‚หมดเต็มหน้าจอ</translation>
<translation id="2721148159707890343">คำขอสำเร็จ</translation>
<translation id="2723669454293168317">เรียà¸à¹ƒà¸Šà¹‰à¸à¸²à¸£à¸•à¸£à¸§à¸ˆà¸ªà¸­à¸šà¸„วามปลอดภัยในà¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่า Chrome</translation>
<translation id="2726001110728089263">ถาดข้าง</translation>
@@ -583,6 +613,7 @@
<translation id="2850739647070081192">Invite (ซองจดหมาย)</translation>
<translation id="2856444702002559011">ผู้โจมตีอาจพยายามขโมยข้อมูลจาภ<ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (ตัวอย่างเช่น รหัสผ่าน ข้อความ หรือบัตรเครดิต) <ph name="BEGIN_LEARN_MORE_LINK" />ดูข้อมูลเพิ่มเติม<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">เว็บไซต์นี้à¹à¸ªà¸”งโฆษณาที่à¹à¸—รà¸à¸«à¸£à¸·à¸­à¸—ำให้เข้าใจผิด</translation>
+<translation id="286512204874376891">บัตรเสมือนจะอำพรางบัตรจริงไว้เพื่อช่วยปà¸à¸›à¹‰à¸­à¸‡à¸„ุณจาà¸à¸à¸²à¸£à¸‰à¹‰à¸­à¹‚à¸à¸‡à¸—ี่อาจเà¸à¸´à¸”ขึ้น <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">เป็นà¸à¸±à¸™à¹€à¸­à¸‡</translation>
<translation id="2876489322757410363">à¸à¸³à¸¥à¸±à¸‡à¸­à¸­à¸à¸ˆà¸²à¸à¹‚หมดไม่ระบุตัวตนเพื่อชำระเงินผ่านà¹à¸­à¸›à¸žà¸¥à¸´à¹€à¸„ชันภายนอภต้องà¸à¸²à¸£à¸”ำเนินà¸à¸²à¸£à¸•à¹ˆà¸­à¹„หม</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" /> à¸à¸” Tab ตามด้วย Enter เพื่อจัดà¸à¸²à¸£ Google Safe Browsing à¹à¸¥à¸°à¸­à¸·à¹ˆà¸™à¹† ในà¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่า Chrome</translation>
@@ -607,6 +638,7 @@
<translation id="2930577230479659665">ตัดออà¸à¸«à¸¥à¸±à¸‡à¸ªà¸³à¹€à¸™à¸²à¹à¸•à¹ˆà¸¥à¸°à¸‰à¸šà¸±à¸š</translation>
<translation id="2932085390869194046">à¹à¸™à¸°à¸™à¸³à¸£à¸«à¸±à¸ªà¸œà¹ˆà¸²à¸™...</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019">เปิดลิงà¸à¹Œ <ph name="PROTOCOL" /></translation>
<translation id="2941952326391522266">เซิร์ฟเวอร์นี้ไม่สามารถพิสูจน์ได้ว่าเป็น <ph name="DOMAIN" /> เพราะใบรับรองความปลอดภัยมาจาภ<ph name="DOMAIN2" /> โดยอาจเà¸à¸´à¸”จาà¸à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าผิดหรือผู้บุà¸à¸£à¸¸à¸à¸—ี่ขัดขวางà¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸‚องคุณ</translation>
<translation id="2943895734390379394">เวลาที่อัปโหลด:</translation>
<translation id="2948083400971632585">คุณสามารถปิดใช้งานพร็อà¸à¸‹à¸µà¸—ี่à¸à¸³à¸«à¸™à¸”ค่าสำหรับà¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸ˆà¸²à¸à¸«à¸™à¹‰à¸²à¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่าได้</translation>
@@ -639,6 +671,7 @@
<translation id="3037605927509011580">à¹à¸¢à¹ˆà¸ˆà¸±à¸‡!</translation>
<translation id="3041612393474885105">ข้อมูลในใบรับรอง</translation>
<translation id="3044034790304486808">หาข้อมูลต่อ</translation>
+<translation id="305162504811187366">ประวัติà¸à¸²à¸£à¹ƒà¸Šà¹‰ Chrome Remote Desktop รวมถึงà¸à¸²à¸£à¸›à¸£à¸°à¸—ับเวลา โฮสต์ à¹à¸¥à¸°à¸£à¸«à¸±à¸ªà¹€à¸‹à¸ªà¸Šà¸±à¸™à¹„คลเอ็นต์</translation>
<translation id="3060227939791841287">C9 (ซองจดหมาย)</translation>
<translation id="3061707000357573562">à¹à¸žà¸•à¸Šà¹Œà¸šà¸£à¸´à¸à¸²à¸£</translation>
<translation id="306573536155379004">เà¸à¸¡à¹€à¸£à¸´à¹ˆà¸¡à¹à¸¥à¹‰à¸§</translation>
@@ -679,6 +712,7 @@
<translation id="3197136577151645743">สามารถขอทราบเวลาที่คุณใช้งานอุปà¸à¸£à¸“์อยู่ได้</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" /> à¸à¸” Tab ตามด้วย Enter เพื่อจัดà¸à¸²à¸£à¸‚้อมูลที่คุณซิงค์ในà¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่า Chrome</translation>
<translation id="320323717674993345">ยà¸à¹€à¸¥à¸´à¸à¸à¸²à¸£à¸Šà¸³à¸£à¸°à¹€à¸‡à¸´à¸™</translation>
+<translation id="3203366800380907218">จาà¸à¹€à¸§à¹‡à¸š</translation>
<translation id="3207960819495026254">บุ๊à¸à¸¡à¸²à¸£à¹Œà¸à¹à¸¥à¹‰à¸§</translation>
<translation id="3209034400446768650">อาจมีà¸à¸²à¸£à¹€à¸£à¸µà¸¢à¸à¹€à¸à¹‡à¸šà¹€à¸‡à¸´à¸™à¹ƒà¸™à¸«à¸™à¹‰à¸²à¸™à¸µà¹‰</translation>
<translation id="3212581601480735796">มีà¸à¸²à¸£à¸•à¸£à¸§à¸ˆà¸ªà¸­à¸šà¸à¸´à¸ˆà¸à¸£à¸£à¸¡à¸—ี่คุณทำใน <ph name="HOSTNAME" /></translation>
@@ -695,10 +729,12 @@
<translation id="3234666976984236645">ตรวจหาเนื้อหาที่สำคัà¸à¸šà¸™à¹„ซต์นี้เสมอ</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" /> à¸à¸” Tab ตามด้วย Enter เพื่อปรับà¹à¸•à¹ˆà¸‡à¸£à¸¹à¸›à¸¥à¸±à¸à¸©à¸“์ของเบราว์เซอร์</translation>
<translation id="3240791268468473923">ระบบได้เปิด Bottom Sheet ซึ่งà¹à¸ˆà¹‰à¸‡à¸§à¹ˆà¸²à¹„ม่พบข้อมูลเข้าสู่ระบบที่ตรงà¸à¸±à¸™à¸ªà¸³à¸«à¸£à¸±à¸šà¸‚้อมูลเข้าสู่ระบบà¸à¸²à¸£à¸Šà¸³à¸£à¸°à¹€à¸‡à¸´à¸™à¸—ี่ปลอดภัย</translation>
+<translation id="324180406144491771">ลิงà¸à¹Œ “<ph name="HOST_NAME" />†ถูà¸à¸šà¸¥à¹‡à¸­à¸</translation>
<translation id="3249845759089040423">ดึงดูด</translation>
<translation id="3252266817569339921">à¸à¸£à¸±à¹ˆà¸‡à¹€à¸¨à¸ª</translation>
<translation id="3257954757204451555">ดูผู้ที่อยู่เบื้องหลังข้อมูลนี้</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" /> à¸à¸” Tab ตามด้วย Enter เพื่อสร้างà¸à¸´à¸ˆà¸à¸£à¸£à¸¡à¹ƒà¸«à¸¡à¹ˆà¹ƒà¸™ Google ปà¸à¸´à¸—ินอย่างรวดเร็ว</translation>
+<translation id="3261488570342242926">ดูข้อมูลเà¸à¸µà¹ˆà¸¢à¸§à¸à¸±à¸šà¸šà¸±à¸•à¸£à¹€à¸ªà¸¡à¸·à¸­à¸™</translation>
<translation id="3264837738038045344">ปุ่มจัดà¸à¸²à¸£à¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่า Chrome à¸à¸” Enter เพื่อไปที่à¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่า Chrome</translation>
<translation id="3266793032086590337">ค่า (มีความขัดà¹à¸¢à¹‰à¸‡)</translation>
<translation id="3268451620468152448">à¹à¸—็บที่เปิดอยู่</translation>
@@ -712,6 +748,7 @@
<translation id="3288238092761586174"><ph name="URL" /> อาจต้องทำตามขั้นตอนเพิ่มเติมเพื่อยืนยันà¸à¸²à¸£à¸Šà¸³à¸£à¸°à¹€à¸‡à¸´à¸™</translation>
<translation id="3293642807462928945">ดูข้อมูลเพิ่มเติมเà¸à¸µà¹ˆà¸¢à¸§à¸à¸±à¸šà¸™à¹‚ยบาย <ph name="POLICY_NAME" /></translation>
<translation id="3295444047715739395">ดูà¹à¸¥à¸°à¸ˆà¸±à¸”à¸à¸²à¸£à¸£à¸«à¸±à¸ªà¸œà¹ˆà¸²à¸™à¹ƒà¸™à¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่า Chrome</translation>
+<translation id="3303795387212510132">อนุà¸à¸²à¸•à¹ƒà¸«à¹‰à¹à¸­à¸›à¹€à¸›à¸´à¸”ลิงà¸à¹Œ <ph name="PROTOCOL_SCHEME" /> ไหม</translation>
<translation id="3303855915957856445">ไม่พบผลà¸à¸²à¸£à¸„้นหา</translation>
<translation id="3304073249511302126">à¸à¸²à¸£à¸ªà¹à¸à¸™à¸«à¸²à¸šà¸¥à¸¹à¸—ูธ</translation>
<translation id="3308006649705061278">หน่วยองค์à¸à¸£ (OU)</translation>
@@ -725,12 +762,6 @@
<translation id="3345782426586609320">ตา</translation>
<translation id="3355823806454867987">เปลี่ยนà¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่าพร็อà¸à¸‹à¸µ...</translation>
<translation id="3360103848165129075">à¹à¸œà¹ˆà¸™à¸‡à¸²à¸™à¸‚องเครื่องจัดà¸à¸²à¸£à¸à¸²à¸£à¸Šà¸³à¸£à¸°à¹€à¸‡à¸´à¸™</translation>
-<translation id="3361596688432910856">Chrome <ph name="BEGIN_EMPHASIS" />จะไม่บันทึà¸<ph name="END_EMPHASIS" />ข้อมูลต่อไปนี้:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />ประวัติà¸à¸²à¸£à¸—่องเว็บของคุณ
- <ph name="LIST_ITEM" />คุà¸à¸à¸µà¹‰à¹à¸¥à¸°à¸‚้อมูลไซต์
- <ph name="LIST_ITEM" />ข้อมูลที่à¸à¸£à¸­à¸à¹ƒà¸™à¸Ÿà¸­à¸£à¹Œà¸¡
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">เราคัดลอà¸à¸™à¹‚ยบายนี้มาโดยอัตโนมัติจาà¸à¸™à¹‚ยบาย <ph name="OLD_POLICY" /> ที่เลิà¸à¹ƒà¸Šà¹‰à¸‡à¸²à¸™à¹à¸¥à¹‰à¸§ คุณควรใช้นโยบายนี้à¹à¸—น</translation>
<translation id="3364869320075768271"><ph name="URL" /> ต้องà¸à¸²à¸£à¹€à¸‚้าถึงอุปà¸à¸£à¸“์à¹à¸¥à¸°à¸‚้อมูล Virtual Reality ของคุณ</translation>
<translation id="3366477098757335611">ดูบัตร</translation>
@@ -812,7 +843,6 @@
<translation id="3587738293690942763">ตรงà¸à¸¥à¸²à¸‡</translation>
<translation id="3592413004129370115">Italian (ซองจดหมาย)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{คุณรีเซ็ตà¸à¸¥à¸¸à¹ˆà¸¡à¹„ด้ทุà¸à¹€à¸¡à¸·à¹ˆà¸­ à¸à¸²à¸£à¹€à¸‚้าร่วมà¸à¸¥à¸¸à¹ˆà¸¡à¹ƒà¸«à¸¡à¹ˆà¸ˆà¸°à¹ƒà¸Šà¹‰à¹€à¸§à¸¥à¸²à¸›à¸£à¸°à¸¡à¸²à¸“ 1 วัน}=1{คุณรีเซ็ตà¸à¸¥à¸¸à¹ˆà¸¡à¹„ด้ทุà¸à¹€à¸¡à¸·à¹ˆà¸­ à¸à¸²à¸£à¹€à¸‚้าร่วมà¸à¸¥à¸¸à¹ˆà¸¡à¹ƒà¸«à¸¡à¹ˆà¸ˆà¸°à¹ƒà¸Šà¹‰à¹€à¸§à¸¥à¸²à¸›à¸£à¸°à¸¡à¸²à¸“ 1 วัน}other{คุณรีเซ็ตà¸à¸¥à¸¸à¹ˆà¸¡à¹„ด้ทุà¸à¹€à¸¡à¸·à¹ˆà¸­ à¸à¸²à¸£à¹€à¸‚้าร่วมà¸à¸¥à¸¸à¹ˆà¸¡à¹ƒà¸«à¸¡à¹ˆà¸ˆà¸°à¹ƒà¸Šà¹‰à¹€à¸§à¸¥à¸²à¸›à¸£à¸°à¸¡à¸²à¸“ {NUM_DAYS} วัน}}</translation>
-<translation id="3596012367874587041">à¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่าà¹à¸­à¸›</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">ผู้ดูà¹à¸¥à¸£à¸°à¸šà¸šà¸šà¸¥à¹‡à¸­à¸à¹à¸­à¸›à¸žà¸¥à¸´à¹€à¸„ชันไว้</translation>
<translation id="3608932978122581043">ฟีดà¸à¸£à¸°à¸”าษตามà¹à¸™à¸§</translation>
@@ -855,6 +885,7 @@
<translation id="370972442370243704">เปิดใช้เส้นทางà¸à¸²à¸£à¸—่องเว็บ</translation>
<translation id="3711895659073496551">ระงับà¸à¸²à¸£à¹ƒà¸Šà¹‰à¸‡à¸²à¸™</translation>
<translation id="3712624925041724820">ใบอนุà¸à¸²à¸•à¸«à¸¡à¸”</translation>
+<translation id="3714633008798122362">ปà¸à¸´à¸—ินเว็บ</translation>
<translation id="3714780639079136834">เปิดอินเทอร์เน็ตมือถือหรือ Wi-Fi</translation>
<translation id="3715597595485130451">เชื่อมต่อ Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />ตรวจสอบพร็อà¸à¸‹à¸µ ไฟร์วอลล์ à¹à¸¥à¸°à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่า DNS<ph name="END_LINK" /></translation>
@@ -916,6 +947,7 @@
<translation id="3906954721959377182">à¹à¸—็บเล็ต</translation>
<translation id="3909477809443608991"><ph name="URL" /> ต้องà¸à¸²à¸£à¹€à¸¥à¹ˆà¸™à¹€à¸™à¸·à¹‰à¸­à¸«à¸²à¸—ี่ได้รับความคุ้มครอง ข้อมูลประจำตัวของอุปà¸à¸£à¸“์จะได้รับà¸à¸²à¸£à¸¢à¸·à¸™à¸¢à¸±à¸™à¹‚ดย Google à¹à¸¥à¸°à¹€à¸§à¹‡à¸šà¹„ซต์นี้อาจเข้าถึงข้อมูลดังà¸à¸¥à¹ˆà¸²à¸§</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">ปà¸à¸´à¹€à¸ªà¸˜</translation>
<translation id="3939773374150895049">ใช้ WebAuthn à¹à¸—น CVC ไหม</translation>
<translation id="3946209740501886391">ถามทุà¸à¸„รั้งบนเว็บไซต์นี้</translation>
<translation id="3947595700203588284">สามารถขอเชื่อมต่อà¸à¸±à¸šà¸­à¸¸à¸›à¸à¸£à¸“์ MIDI ได้</translation>
@@ -936,6 +968,7 @@
<translation id="3987940399970879459">ไม่ถึง 1 MB</translation>
<translation id="3990250421422698716">à¸à¸²à¸£à¸Šà¸”เชยพื้นผิวที่ไม่สม่ำเสมอ</translation>
<translation id="3996311196211510766">เว็บไซต์ <ph name="ORIGIN" /> ขอให้บังคับใช้นโยบายดั้งเดิมà¸à¸±à¸šà¸„ำขอทั้งหมดที่ส่งถึงเว็บไซต์ à¹à¸•à¹ˆà¸‚ณะนี้ใช้นโยบายนี้ไม่ได้</translation>
+<translation id="4009243425692662128">ระบบจะส่งเนื้อหาของหน้าที่คุณพิมพ์ไปยัง Google Cloud หรือบุคคลที่สามเพื่อà¸à¸²à¸£à¸§à¸´à¹€à¸„ราะห์ เช่น สà¹à¸à¸™à¸«à¸²à¸‚้อมูลที่ละเอียดอ่อน</translation>
<translation id="4010758435855888356">อนุà¸à¸²à¸•à¹ƒà¸«à¹‰à¹€à¸‚้าถึงพื้นที่เà¸à¹‡à¸šà¸‚้อมูลไหม</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{เอà¸à¸ªà¸²à¸£ PDF ที่มี {COUNT} หน้า}other{เอà¸à¸ªà¸²à¸£ PDF ที่มี {COUNT} หน้า}}</translation>
<translation id="4023431997072828269">เนื่องจาà¸à¹à¸šà¸šà¸Ÿà¸­à¸£à¹Œà¸¡à¸™à¸µà¹‰à¸ªà¹ˆà¸‡à¸œà¹ˆà¸²à¸™à¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸—ี่ไม่ปลอดภัย ผู้อื่นอาจมองเห็นข้อมูลของคุณ</translation>
@@ -1026,6 +1059,7 @@
<translation id="4250680216510889253">ไม่</translation>
<translation id="4253168017788158739">หมายเหตุ</translation>
<translation id="425582637250725228">ระบบอาจไม่ได้บันทึà¸à¸à¸²à¸£à¹€à¸›à¸¥à¸µà¹ˆà¸¢à¸™à¹à¸›à¸¥à¸‡à¸‚องคุณ</translation>
+<translation id="425869179292622354">เพิ่มความปลอดภัยด้วยบัตรเสมือนไหม</translation>
<translation id="4258748452823770588">ลายเซ็นไม่เหมาะสม</translation>
<translation id="4261046003697461417">เอà¸à¸ªà¸²à¸£à¸—ี่มีà¸à¸²à¸£à¸›à¹‰à¸­à¸‡à¸à¸±à¸™à¸ˆà¸°à¹ƒà¸ªà¹ˆà¸«à¸¡à¸²à¸¢à¹€à¸«à¸•à¸¸à¹„ม่ได้</translation>
<translation id="4265872034478892965">อนุà¸à¸²à¸•à¹‚ดยผู้ดูà¹à¸¥à¸£à¸°à¸šà¸š</translation>
@@ -1088,6 +1122,7 @@
<translation id="4434045419905280838">ป๊อปอัปà¹à¸¥à¸°à¸à¸²à¸£à¹€à¸›à¸¥à¸µà¹ˆà¸¢à¸™à¹€à¸ªà¹‰à¸™à¸—าง</translation>
<translation id="4435702339979719576">โปสà¸à¸²à¸£à¹Œà¸”)</translation>
<translation id="443673843213245140">à¸à¸²à¸£à¹ƒà¸Šà¹‰à¸žà¸£à¹‡à¸­à¸à¸‹à¸µà¸–ูà¸à¸›à¸´à¸”ใช้งาน à¹à¸•à¹ˆà¸¡à¸µà¸à¸²à¸£à¸£à¸°à¸šà¸¸à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าพร็อà¸à¸‹à¸µà¸­à¸¢à¹ˆà¸²à¸‡à¸Šà¸±à¸”เจน</translation>
+<translation id="4441832193888514600">ถูà¸à¸¥à¸°à¹€à¸§à¹‰à¸™à¹€à¸™à¸·à¹ˆà¸­à¸‡à¸ˆà¸²à¸à¸™à¹‚ยบายจะต้องตั้งค่าเป็นนโยบายผู้ใช้ระบบคลาวด์เท่านั้น</translation>
<translation id="4450893287417543264">ไม่ต้องà¹à¸ªà¸”งอีà¸</translation>
<translation id="4451135742916150903">สามารถขอเชื่อมต่อà¸à¸±à¸šà¸­à¸¸à¸›à¸à¸£à¸“์ HID ได้</translation>
<translation id="4452328064229197696">ระบบพบว่ารหัสผ่านที่คุณเพิ่งใช้มีà¸à¸²à¸£à¸£à¸±à¹ˆà¸§à¹„หลในà¸à¸²à¸£à¸¥à¸°à¹€à¸¡à¸´à¸”ข้อมูลครั้งหนึ่ง เพื่อรัà¸à¸©à¸²à¸„วามปลอดภัยของบัà¸à¸Šà¸µ เครื่องมือจัดà¸à¸²à¸£à¸£à¸«à¸±à¸ªà¸œà¹ˆà¸²à¸™à¸‚อง Google à¹à¸™à¸°à¸™à¸³à¹ƒà¸«à¹‰à¸•à¸£à¸§à¸ˆà¸ªà¸­à¸šà¸£à¸«à¸±à¸ªà¸œà¹ˆà¸²à¸™à¸—ี่บันทึà¸à¹„ว้</translation>
@@ -1143,6 +1178,7 @@
<translation id="4628948037717959914">รูปภาพ</translation>
<translation id="4631649115723685955">บริà¸à¸²à¸£à¸„ืนเงินที่ลิงà¸à¹Œà¸­à¸¢à¸¹à¹ˆ</translation>
<translation id="4636930964841734540">ข้อมูล</translation>
+<translation id="4638670630777875591">โหมดไม่ระบุตัวตนใน Chromium</translation>
<translation id="464342062220857295">ฟีเจอร์à¸à¸²à¸£à¸„้นหา</translation>
<translation id="4644670975240021822">ลำดับย้อนà¸à¸¥à¸±à¸šà¸„ว่ำหน้าลง</translation>
<translation id="4646534391647090355">พาฉันไปที่นั่นเลย</translation>
@@ -1163,6 +1199,7 @@
<translation id="4708268264240856090">à¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸‚องคุณขัดข้อง</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />เรียà¸à¹ƒà¸Šà¹‰à¸à¸²à¸£à¸§à¸´à¸™à¸´à¸ˆà¸‰à¸±à¸¢à¹€à¸„รือข่ายของ Windows<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426">รหัสผ่านของ <ph name="USERNAME" /></translation>
<translation id="4724144314178270921">สามารถขอดูข้อความà¹à¸¥à¸°à¸£à¸¹à¸›à¸ à¸²à¸žà¹ƒà¸™à¸„ลิปบอร์ดของคุณได้</translation>
<translation id="4726672564094551039">โหลดนโยบายซ้ำ</translation>
<translation id="4728558894243024398">à¹à¸žà¸¥à¸•à¸Ÿà¸­à¸£à¹Œà¸¡</translation>
@@ -1184,6 +1221,7 @@
<translation id="4757993714154412917">คุณเพิ่งใส่รหัสผ่านในเว็บไซต์ที่มีà¸à¸²à¸£à¸«à¸¥à¸­à¸à¸¥à¸§à¸‡ Chromium ขอà¹à¸™à¸°à¸™à¸³à¹ƒà¸«à¹‰à¸•à¸£à¸§à¸ˆà¸ªà¸­à¸šà¸£à¸«à¸±à¸ªà¸œà¹ˆà¸²à¸™à¸—ี่บันทึà¸à¹„ว้เพื่อรัà¸à¸©à¸²à¸„วามปลอดภัยของบัà¸à¸Šà¸µ</translation>
<translation id="4758311279753947758">เพิ่มข้อมูลติดต่อ</translation>
<translation id="4761104368405085019">ใช้ไมโครโฟนของคุณ</translation>
+<translation id="4761869838909035636">เรียà¸à¹ƒà¸Šà¹‰à¸à¸²à¸£à¸•à¸£à¸§à¸ˆà¸ªà¸­à¸šà¸„วามปลอดภัยของ Chrome</translation>
<translation id="4764776831041365478">หน้าเว็บใน <ph name="URL" /> อาจหยุดให้บริà¸à¸²à¸£à¸Šà¸±à¹ˆà¸§à¸„ราวหรืออาจถูà¸à¸¢à¹‰à¸²à¸¢à¹„ปยังที่อยู่เว็บใหม่อย่างถาวร</translation>
<translation id="4766713847338118463">เย็บด้วยลวดเย็บà¸à¸£à¸°à¸”าษด้านล่าง 2 ครั้ง</translation>
<translation id="4771973620359291008">มีข้อผิดพลาดที่ไม่ทราบเà¸à¸´à¸”ขึ้น</translation>
@@ -1204,12 +1242,6 @@
<translation id="4819347708020428563">à¹à¸à¹‰à¹„ขคำอธิบายประà¸à¸­à¸šà¹ƒà¸™à¸¡à¸¸à¸¡à¸¡à¸­à¸‡à¹€à¸£à¸´à¹ˆà¸¡à¸•à¹‰à¸™à¹ƒà¸Šà¹ˆà¹„หม</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" /> à¸à¸” Tab ตามด้วย Enter เพื่อสร้างชีตใหม่ใน Google ชีตอย่างรวดเร็ว</translation>
<translation id="4825507807291741242">ทรงพลัง</translation>
-<translation id="4827402517081186284">โหมดไม่ระบุตัวตนไม่ได้ซ่อนà¸à¸²à¸£à¹ƒà¸Šà¹‰à¸‡à¸²à¸™à¸­à¸­à¸™à¹„ลน์ของคุณ
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />เว็บไซต์รู้เมื่อคุณเข้าชม<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />นายจ้างหรือโรงเรียนติดตามà¸à¸´à¸ˆà¸à¸£à¸£à¸¡à¸à¸²à¸£à¸—่องเว็บได้<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />ผู้ให้บริà¸à¸²à¸£à¸­à¸´à¸™à¹€à¸—อร์เน็ตอาจตรวจสอบà¸à¸²à¸£à¹€à¸‚้าชมเว็บ<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">เปิดคำเตือน</translation>
<translation id="4838327282952368871">ชวนà¸à¸±à¸™</translation>
<translation id="4840250757394056958">ดูประวัติà¸à¸²à¸£à¹€à¸‚้าชมใน Chrome</translation>
@@ -1221,12 +1253,12 @@
<translation id="4854362297993841467">วิธีà¸à¸²à¸£à¸™à¸³à¸ªà¹ˆà¸‡à¸ªà¸´à¸™à¸„้านี้ไม่พร้อมให้บริà¸à¸²à¸£ โปรดลองใช้วิธีà¸à¸²à¸£à¸­à¸·à¹ˆà¸™</translation>
<translation id="4854853140771946034">สร้างโน้ตใหม่ใน Google Keep อย่างรวดเร็ว</translation>
<translation id="485902285759009870">à¸à¸³à¸¥à¸±à¸‡à¸¢à¸·à¸™à¸¢à¸±à¸™à¸£à¸«à¸±à¸ª...</translation>
+<translation id="4866506163384898554">à¸à¸” |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| เพื่อà¹à¸ªà¸”งเคอร์เซอร์</translation>
<translation id="4876188919622883022">มุมมองอย่างง่าย</translation>
<translation id="4876305945144899064">ไม่มีชื่อผู้ใช้</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{ไม่มี}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831">à¸à¸²à¸£à¸„้นหา <ph name="TEXT" /></translation>
<translation id="4879491255372875719">อัตโนมัติ (ค่าเริ่มต้น)</translation>
-<translation id="4879725228911483934">เปิดà¹à¸¥à¸°à¹à¸ªà¸”งหน้าต่างบนหน้าจอของคุณ</translation>
<translation id="4880827082731008257">ค้นประวัติà¸à¸²à¸£à¹€à¸‚้าชม</translation>
<translation id="4881695831933465202">เปิด</translation>
<translation id="4885256590493466218">ชำระเงินด้วย <ph name="CARD_DETAIL" /> ที่จุดชำระเงิน</translation>
@@ -1235,6 +1267,7 @@
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" /> à¹à¸¥à¸° <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">ม้วนà¸à¸£à¸°à¸”าษ 9</translation>
<translation id="4901778704868714008">บันทึà¸...</translation>
+<translation id="4905659621780993806">ผู้ดูà¹à¸¥à¸£à¸°à¸šà¸šà¸ˆà¸°à¸£à¸µà¸ªà¸•à¸²à¸£à¹Œà¸—อุปà¸à¸£à¸“์โดยอัตโนมัติในวันที่ <ph name="TIME" /> เวลา <ph name="DATE" /> บันทึà¸à¸£à¸²à¸¢à¸à¸²à¸£à¸—ี่เปิดอยู่à¸à¹ˆà¸­à¸™à¸­à¸¸à¸›à¸à¸£à¸“์จะรีสตาร์ท</translation>
<translation id="4913987521957242411">เจาะรูด้านซ้ายบน</translation>
<translation id="4918221908152712722">ติดตั้ง <ph name="APP_NAME" /> (ไม่จำเป็นต้องดาวน์โหลด)</translation>
<translation id="4923459931733593730">à¸à¸²à¸£à¸Šà¸³à¸£à¸°à¹€à¸‡à¸´à¸™</translation>
@@ -1243,6 +1276,7 @@
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" /> à¸à¸” Tab ตามด้วย Enter เพื่อค้นหา</translation>
<translation id="4930153903256238152">ความจุมาà¸</translation>
+<translation id="4940163644868678279">โหมดไม่ระบุตัวตนใน Chrome</translation>
<translation id="4943872375798546930">ไม่มีผลà¸à¸²à¸£à¸„้นหา</translation>
<translation id="4950898438188848926">ปุ่มเปลี่ยนà¹à¸—็บ โปรดà¸à¸” Enter เพื่อเปลี่ยนไปยังà¹à¸—็บที่เปิดอยู่ <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="495170559598752135">à¸à¸²à¸£à¸—ำงาน</translation>
@@ -1252,6 +1286,7 @@
<translation id="4968522289500246572">à¹à¸­à¸›à¸™à¸µà¹‰à¸­à¸­à¸à¹à¸šà¸šà¸¡à¸²à¸ªà¸³à¸«à¸£à¸±à¸šà¸­à¸¸à¸›à¸à¸£à¸“์เคลื่อนที่à¹à¸¥à¸°à¸­à¸²à¸ˆà¹„ม่เหมาะà¸à¸±à¸šà¸à¸²à¸£à¸›à¸£à¸±à¸šà¸‚นาด à¹à¸­à¸›à¸­à¸²à¸ˆà¹€à¸à¸´à¸”ปัà¸à¸«à¸²à¸«à¸£à¸·à¸­à¸£à¸µà¸ªà¸•à¸²à¸£à¹Œà¸—</translation>
<translation id="4969341057194253438">ลบà¸à¸²à¸£à¸šà¸±à¸™à¸—ึà¸</translation>
<translation id="4973922308112707173">เจาะรูด้านบน 2 รู</translation>
+<translation id="4976702386844183910">เข้าชมล่าสุด <ph name="DATE" /></translation>
<translation id="4984088539114770594">ใช้ไมโครโฟนไหม</translation>
<translation id="4984339528288761049">Prc5 (ซองจดหมาย)</translation>
<translation id="4989163558385430922">ดูทั้งหมด</translation>
@@ -1313,6 +1348,7 @@
<translation id="5138227688689900538">à¹à¸ªà¸”งน้อยลง</translation>
<translation id="5145883236150621069">มีรหัสข้อผิดพลาดในà¸à¸²à¸£à¸•à¸­à¸šà¸à¸¥à¸±à¸šà¸™à¹‚ยบาย</translation>
<translation id="5146995429444047494">บล็อà¸à¸à¸²à¸£à¹à¸ˆà¹‰à¸‡à¹€à¸•à¸·à¸­à¸™à¸‚อง <ph name="ORIGIN" /> ไว้</translation>
+<translation id="514704532284964975"><ph name="URL" /> ต้องà¸à¸²à¸£à¸”ูà¹à¸¥à¸°à¹€à¸›à¸¥à¸µà¹ˆà¸¢à¸™à¹à¸›à¸¥à¸‡à¸‚้อมูลในอุปà¸à¸£à¸“์ NFC ที่คุณà¹à¸•à¸°à¸ˆà¸²à¸à¹‚ทรศัพท์</translation>
<translation id="5148809049217731050">หงายหน้าขึ้น</translation>
<translation id="515292512908731282">C4 (ซองจดหมาย)</translation>
<translation id="5158275234811857234">หน้าปà¸</translation>
@@ -1337,6 +1373,7 @@
<translation id="5215116848420601511">วิธีà¸à¸²à¸£à¸Šà¸³à¸£à¸°à¹€à¸‡à¸´à¸™à¹à¸¥à¸°à¸—ี่อยู่จาภGoogle Pay</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">ถาด 13</translation>
+<translation id="5216942107514965959">เข้าชมล่าสุดวันนี้</translation>
<translation id="5222812217790122047">ต้องระบุอีเมล</translation>
<translation id="5230733896359313003">ที่อยู่ในà¸à¸²à¸£à¸ˆà¸±à¸”ส่ง</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1357,7 +1394,6 @@
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">คุณสมบัติของเอà¸à¸ªà¸²à¸£</translation>
<translation id="528468243742722775">สิ้นสุด</translation>
-<translation id="5284909709419567258">ที่อยู่เครือข่าย</translation>
<translation id="5285570108065881030">à¹à¸ªà¸”งรหัสผ่านที่บันทึà¸à¹„ว้ทั้งหมด</translation>
<translation id="5287240709317226393">à¹à¸ªà¸”งคุà¸à¸à¸µà¹‰</translation>
<translation id="5287456746628258573">เว็บไซต์นี้ใช้à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ค่าความปลอดภัยที่ล้าสมัย ซึ่งอาจทำให้ข้อมูลของคุณรั่วไหลเมื่อส่งไปยังเว็บไซต์นี้ (เช่น รหัสผ่านหรือหมายเลขบัตรเครดิต)</translation>
@@ -1441,6 +1477,7 @@
<translation id="5556459405103347317">โหลดใหม่</translation>
<translation id="5560088892362098740">วันที่หมดอายุ</translation>
<translation id="55635442646131152">โครงร่างเอà¸à¸ªà¸²à¸£</translation>
+<translation id="5565613213060953222">เปิดà¹à¸—็บที่ไม่ระบุตัวตน</translation>
<translation id="5565735124758917034">ใช้งานอยู่</translation>
<translation id="5570825185877910964">ปà¸à¸›à¹‰à¸­à¸‡à¸šà¸±à¸à¸Šà¸µ</translation>
<translation id="5571083550517324815">ไม่สามารถรับสินค้าจาà¸à¸—ี่อยู่นี้ โปรดเลือà¸à¸—ี่อยู่อื่น</translation>
@@ -1523,6 +1560,7 @@
<translation id="5869522115854928033">รหัสผ่านที่บันทึà¸à¹„ว้</translation>
<translation id="5873013647450402046">ธนาคารต้องà¸à¸²à¸£à¸¢à¸·à¸™à¸¢à¸±à¸™à¸•à¸±à¸§à¸•à¸™à¸‚องคุณ</translation>
<translation id="5887400589839399685">บันทึà¸à¸à¸²à¸£à¹Œà¸”à¹à¸¥à¹‰à¸§</translation>
+<translation id="5887687176710214216">เข้าชมล่าสุดเมื่อวาน</translation>
<translation id="5895138241574237353">ปิดà¹à¸¥à¹‰à¸§à¹€à¸›à¸´à¸”อีà¸à¸„รั้ง</translation>
<translation id="5895187275912066135">ออà¸à¹€à¸¡à¸·à¹ˆà¸­</translation>
<translation id="5901630391730855834">สีเหลือง</translation>
@@ -1536,6 +1574,7 @@
<translation id="5921639886840618607">บันทึà¸à¸šà¸±à¸•à¸£à¸¥à¸‡à¹ƒà¸™à¸šà¸±à¸à¸Šà¸µ Google ไหม</translation>
<translation id="5922853866070715753">เà¸à¸·à¸­à¸šà¹€à¸ªà¸£à¹‡à¸ˆà¹à¸¥à¹‰à¸§</translation>
<translation id="5932224571077948991">เว็บไซต์à¹à¸ªà¸”งโฆษณาที่à¹à¸—รà¸à¸«à¸£à¸·à¸­à¸—ำให้เข้าใจผิด</translation>
+<translation id="5938153366081463283">เพิ่มบัตรเสมือน</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347">à¸à¸³à¸¥à¸±à¸‡à¹€à¸›à¸´à¸” <ph name="SITE_NAME" />…</translation>
<translation id="5951495562196540101">ลงทะเบียนด้วยบัà¸à¸Šà¸µà¸œà¸¹à¹‰à¹ƒà¸Šà¹‰à¸—ั่วไปไม่ได้ (มีใบอนุà¸à¸²à¸•à¹à¸šà¸šà¹à¸žà¹‡à¸à¹€à¸à¸ˆ)</translation>
@@ -1578,7 +1617,7 @@
<translation id="6047927260846328439">เนื้อหานี้อาจพยายามหลอà¸à¸¥à¹ˆà¸­à¹ƒà¸«à¹‰à¸„ุณติดตั้งซอฟต์à¹à¸§à¸£à¹Œà¸«à¸£à¸·à¸­à¹€à¸›à¸´à¸”เผยข้อมูลส่วนบุคคล <ph name="BEGIN_LINK" />à¹à¸ªà¸”งเนื้อหา<ph name="END_LINK" /></translation>
<translation id="6049004884579590341">à¸à¸” |<ph name="ACCELERATOR" />| ค้างไว้เพื่อออà¸à¸ˆà¸²à¸à¹‚หมดเต็มหน้าจอ</translation>
<translation id="6049488691372270142">หน้าที่à¹à¸ªà¸”ง</translation>
-<translation id="6051221802930200923">คุณไม่สามารถไปที่ <ph name="SITE" /> ได้ในขณะนี้เนื่องจาà¸à¹€à¸§à¹‡à¸šà¹„ซต์ใช้à¸à¸²à¸£à¸•à¸£à¸¶à¸‡à¹ƒà¸šà¸£à¸±à¸šà¸£à¸­à¸‡ โดยปà¸à¸•à¸´à¸‚้อผิดพลาดของเครือข่ายà¹à¸¥à¸°à¸à¸²à¸£à¹‚จมตีจะเà¸à¸´à¸”ขึ้นเพียงชั่วคราว หน้านี้จึงอาจใช้งานได้ในภายหลัง</translation>
+<translation id="6051221802930200923">คุณไม่สามารถไปที่ <ph name="SITE" /> ได้ในขณะนี้เนื่องจาà¸à¹€à¸§à¹‡à¸šà¹„ซต์ใช้à¸à¸²à¸£à¸›à¸±à¸à¸«à¸¡à¸¸à¸”ใบรับรอง โดยปà¸à¸•à¸´à¸‚้อผิดพลาดของเครือข่ายà¹à¸¥à¸°à¸à¸²à¸£à¹‚จมตีจะเà¸à¸´à¸”ขึ้นเพียงชั่วคราว หน้านี้จึงอาจใช้งานได้ในภายหลัง</translation>
<translation id="6051898664905071243">จำนวนหน้า:</translation>
<translation id="6052284303005792909">•</translation>
<translation id="6052319569711353666">ระบบพบว่ารหัสผ่านที่คุณเพิ่งใช้มีà¸à¸²à¸£à¸£à¸±à¹ˆà¸§à¹„หลในà¸à¸²à¸£à¸¥à¸°à¹€à¸¡à¸´à¸”ข้อมูลครั้งหนึ่ง เครื่องมือจัดà¸à¸²à¸£à¸£à¸«à¸±à¸ªà¸œà¹ˆà¸²à¸™à¸‚อง Google à¹à¸™à¸°à¸™à¸³à¹ƒà¸«à¹‰à¹€à¸›à¸¥à¸µà¹ˆà¸¢à¸™à¸£à¸«à¸±à¸ªà¸œà¹ˆà¸²à¸™à¸™à¸µà¹‰à¸—ันที</translation>
@@ -1600,6 +1639,7 @@
<translation id="6120179357481664955">จำรหัส UPI ไหม</translation>
<translation id="6124432979022149706">เครื่องมือเชื่อมต่อ Chrome Enterprise</translation>
<translation id="6127379762771434464">นำรายà¸à¸²à¸£à¸­à¸­à¸à¹à¸¥à¹‰à¸§</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />ดูข้อมูลเพิ่มเติมเà¸à¸µà¹ˆà¸¢à¸§à¸à¸±à¸šà¹‚หมดไม่ระบุตัวตนใน Chrome<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">ตรวจสายเคเบิลà¹à¸¥à¸°à¸£à¸µà¸šà¸¹à¸•à¹€à¸£à¸²à¹€à¸•à¸­à¸£à¹Œ โมเด็ม หรืออุปà¸à¸£à¸“์เครือข่ายอื่น
ที่คุณอาจใช้งานอยู่</translation>
<translation id="614940544461990577">ลอง:</translation>
@@ -1612,7 +1652,6 @@
<translation id="6169916984152623906">ขณะนี้คุณสามารถท่องเว็บà¹à¸šà¸šà¹€à¸›à¹‡à¸™à¸ªà¹ˆà¸§à¸™à¸•à¸±à¸§ à¹à¸¥à¸°à¸œà¸¹à¹‰à¸­à¸·à¹ˆà¸™à¸—ี่ใช้อุปà¸à¸£à¸“์เครื่องนี้จะไม่เห็นà¸à¸´à¸ˆà¸à¸£à¸£à¸¡à¸‚องคุณ à¹à¸•à¹ˆà¸ˆà¸°à¸¡à¸µà¸à¸²à¸£à¸šà¸±à¸™à¸—ึà¸à¸à¸²à¸£à¸”าวน์โหลดà¹à¸¥à¸°à¸šà¸¸à¹Šà¸à¸¡à¸²à¸£à¹Œà¸à¹„ว้</translation>
<translation id="6177128806592000436">à¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸à¸±à¸šà¹€à¸§à¹‡à¸šà¹„ซต์นี้ไม่ปลอดภัย</translation>
<translation id="6180316780098470077">ช่วงเว้นระหว่างà¸à¸²à¸£à¸¥à¸­à¸‡à¹ƒà¸«à¸¡à¹ˆà¹à¸•à¹ˆà¸¥à¸°à¸„รั้ง</translation>
-<translation id="619448280891863779">สามารถขอเปิดà¹à¸¥à¸°à¸§à¸²à¸‡à¸«à¸™à¹‰à¸²à¸•à¹ˆà¸²à¸‡à¸šà¸™à¸«à¸™à¹‰à¸²à¸ˆà¸­</translation>
<translation id="6196640612572343990">บล็อà¸à¸„ุà¸à¸à¸µà¹‰à¸‚องบุคคลที่สาม</translation>
<translation id="6203231073485539293">ตรวจสอบà¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸­à¸´à¸™à¹€à¸—อร์เน็ต</translation>
<translation id="6218753634732582820">ต้องà¸à¸²à¸£à¸™à¸³à¸—ี่อยู่ออà¸à¸ˆà¸²à¸ Chromium ใช่ไหม</translation>
@@ -1635,7 +1674,7 @@
<translation id="6272383483618007430">Google อัปเดต</translation>
<translation id="6276112860590028508">หน้าเว็บจาà¸à¹€à¸£à¸·à¹ˆà¸­à¸‡à¸£à¸­à¸­à¹ˆà¸²à¸™à¸‚องคุณจะปราà¸à¸à¸—ี่นี่</translation>
<translation id="627746635834430766">เพื่อให้ชำระเงินได้เร็วขึ้นในครั้งถัดไป โปรดบันทึà¸à¸šà¸±à¸•à¸£à¹à¸¥à¸°à¸—ี่อยู่สำหรับà¸à¸²à¸£à¹€à¸£à¸µà¸¢à¸à¹€à¸à¹‡à¸šà¹€à¸‡à¸´à¸™à¹„ว้ในบัà¸à¸Šà¸µ Google</translation>
-<translation id="6279098320682980337">ไม่à¸à¸£à¸­à¸à¸«à¸¡à¸²à¸¢à¹€à¸¥à¸‚บัตรเสมือนใช่ไหม คลิà¸à¸£à¸²à¸¢à¸¥à¸°à¹€à¸­à¸µà¸¢à¸”บัตรเพื่อคัดลอà¸</translation>
+<translation id="6279183038361895380">à¸à¸” |<ph name="ACCELERATOR" />| เพื่อà¹à¸ªà¸”งเคอร์เซอร์ของคุณ</translation>
<translation id="6280223929691119688">ไม่สามารถนำส่งสินค้าไปยังที่อยู่นี้ โปรดเลือà¸à¸—ี่อยู่อื่น</translation>
<translation id="6282194474023008486">รหัสไปรษณีย์</translation>
<translation id="6285507000506177184">ปุ่มจัดà¸à¸²à¸£à¸à¸²à¸£à¸”าวน์โหลดใน Chrome à¸à¸” Enter เพื่อจัดà¸à¸²à¸£à¹„ฟล์ที่คุณดาวน์โหลดใน Chrome</translation>
@@ -1643,6 +1682,7 @@
<translation id="6290238015253830360">บทความที่à¹à¸™à¸°à¸™à¸³à¸ˆà¸°à¸›à¸£à¸²à¸à¸à¸—ี่นี่</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{อุปà¸à¸£à¸“์จะรีสตาร์ทตอนนี้}=1{อุปà¸à¸£à¸“์จะรีสตาร์ทใน 1 วินาที}other{อุปà¸à¸£à¸“์จะรีสตาร์ทใน # วินาที}}</translation>
<translation id="6302269476990306341">Google Assistant ใน Chrome หยุดทำงาน</translation>
<translation id="6305205051461490394">ไม่สามารถเข้าถึง <ph name="URL" /></translation>
<translation id="6312113039770857350">หน้าเว็บไม่พร้อมใช้งาน</translation>
@@ -1716,6 +1756,7 @@
<translation id="6529602333819889595">&amp;ทำซ้ำà¸à¸²à¸£à¸™à¸³à¸­à¸­à¸</translation>
<translation id="6545864417968258051">à¸à¸²à¸£à¸ªà¹à¸à¸™à¸«à¸²à¸šà¸¥à¸¹à¸—ูธ</translation>
<translation id="6547208576736763147">เจาะรูด้านซ้าย 2 รู</translation>
+<translation id="6554732001434021288">เข้าชมล่าสุด <ph name="NUM_DAYS" /> วันที่ผ่านมา</translation>
<translation id="6556866813142980365">ทำซ้ำ</translation>
<translation id="6569060085658103619">คุณà¸à¸³à¸¥à¸±à¸‡à¸”ูหน้าส่วนขยาย</translation>
<translation id="6573200754375280815">เจาะรูด้านขวา 2 รู</translation>
@@ -1776,7 +1817,6 @@
<translation id="6757797048963528358">อุปà¸à¸£à¸“์ของคุณเข้าสู่โหมดสลีปà¹à¸¥à¹‰à¸§</translation>
<translation id="6767985426384634228">อัปเดตที่อยู่ไหม</translation>
<translation id="6768213884286397650">Hagaki (โปสà¸à¸²à¸£à¹Œà¸”)</translation>
-<translation id="6774185088257932239"><ph name="BEGIN_LINK" />ดูข้อมูลเพิ่มเติม<ph name="END_LINK" />เà¸à¸µà¹ˆà¸¢à¸§à¸à¸±à¸šà¹‚หมดไม่ระบุตัวตน</translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">ม่วงอมน้ำเงิน</translation>
<translation id="6786747875388722282">ส่วนขยาย</translation>
@@ -1860,7 +1900,6 @@
<translation id="706295145388601875">เพิ่มà¹à¸¥à¸°à¸ˆà¸±à¸”à¸à¸²à¸£à¸—ี่อยู่ในà¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่า Chrome</translation>
<translation id="7064851114919012435">ข้อมูลติดต่อ</translation>
<translation id="7068733155164172741">ป้อนรหัส <ph name="OTP_LENGTH" /> หลัà¸</translation>
-<translation id="7070090581017165256">เà¸à¸µà¹ˆà¸¢à¸§à¸à¸±à¸šà¹€à¸§à¹‡à¸šà¹„ซต์นี้</translation>
<translation id="70705239631109039">à¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¹„ม่ปลอดภัยอย่างสมบูรณ์</translation>
<translation id="7075452647191940183">คำขอมีขนาดใหà¸à¹ˆà¹€à¸à¸´à¸™à¹„ป</translation>
<translation id="7079718277001814089">เว็บไซต์นี้มีมัลà¹à¸§à¸£à¹Œ</translation>
@@ -1877,6 +1916,12 @@
<translation id="7111012039238467737">(ถูà¸à¸•à¹‰à¸­à¸‡)</translation>
<translation id="7118618213916969306">ค้นหา URL ในคลิปบอร์ด <ph name="SHORT_URL" /></translation>
<translation id="7119414471315195487">ปิดà¹à¸—็บหรือโปรà¹à¸à¸£à¸¡à¸­à¸·à¹ˆà¸™à¹†</translation>
+<translation id="7129355289156517987">เมื่อคุณปิดà¹à¸—็บที่ไม่ระบุตัวตนใน Chromium ทั้งหมด ระบบจะล้างà¸à¸´à¸ˆà¸à¸£à¸£à¸¡à¹ƒà¸™à¹à¸—็บเหล่านั้นจาà¸à¸­à¸¸à¸›à¸à¸£à¸“์เครื่องนี้
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />à¸à¸´à¸ˆà¸à¸£à¸£à¸¡à¸à¸²à¸£à¸—่องเว็บ<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ประวัติà¸à¸²à¸£à¸„้นหา<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />ข้อมูลที่ป้อนในà¹à¸šà¸šà¸Ÿà¸­à¸£à¹Œà¸¡<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">ไม่สามารถจัดส่งสินค้าไปยังที่อยู่นี้ โปรดเลือà¸à¸—ี่อยู่อื่น</translation>
<translation id="7132939140423847331">ผู้ดูà¹à¸¥à¸£à¸°à¸šà¸šà¸‚องคุณห้ามไม่ให้คัดลอà¸à¸‚้อมูลนี้</translation>
<translation id="7135130955892390533">à¹à¸ªà¸”งสถานะ</translation>
@@ -1899,6 +1944,7 @@
<translation id="7192203810768312527">เพิ่มพื้นที่ว่าง <ph name="SIZE" /> เว็บไซต์บางà¹à¸«à¹ˆà¸‡à¸­à¸²à¸ˆà¹‚หลดช้าลงเมื่อคุณเข้าชมครั้งถัดไป</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">ผู้ดูà¹à¸¥à¸£à¸°à¸šà¸šà¸ˆà¸°à¹€à¸«à¹‡à¸™à¸ªà¸´à¹ˆà¸‡à¸•à¹ˆà¸­à¹„ปนี้</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" /> à¸à¸” Tab ตามด้วย Enter เพื่อเปิดà¹à¸—็บที่ไม่ระบุตัวตนà¹à¸—็บใหม่ในà¸à¸²à¸£à¸—่องเว็บà¹à¸šà¸šà¸ªà¹ˆà¸§à¸™à¸•à¸±à¸§</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> ไม่เป็นไปตามมาตรà¸à¸²à¸™à¸„วามปลอดภัย</translation>
<translation id="7210993021468939304">à¸à¸´à¸ˆà¸à¸£à¸£à¸¡ Linux ในคอนเทนเนอร์ à¹à¸¥à¸°à¸•à¸´à¸”ตั้งรวมถึงเรียà¸à¹ƒà¸Šà¹‰à¹à¸­à¸› Linux ในคอนเทนเนอร์ได้</translation>
@@ -1930,6 +1976,7 @@
<translation id="7304562222803846232">จัดà¸à¸²à¸£à¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่าความเป็นส่วนตัวของบัà¸à¸Šà¸µ Google</translation>
<translation id="7305756307268530424">เริ่มโดยให้ช้าลง</translation>
<translation id="7308436126008021607">à¸à¸²à¸£à¸‹à¸´à¸‡à¸„์ในเบื้องหลัง</translation>
+<translation id="7310392214323165548">อุปà¸à¸£à¸“์จะรีสตาร์ทเร็วๆ นี้</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">ความช่วยเหลือเà¸à¸µà¹ˆà¸¢à¸§à¸à¸±à¸šà¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­</translation>
<translation id="7323804146520582233">ซ่อนส่วน "<ph name="SECTION" />"</translation>
@@ -1937,6 +1984,7 @@
<translation id="7334320624316649418">&amp;ทำซ้ำà¸à¸²à¸£à¸ˆà¸±à¸”ลำดับใหม่</translation>
<translation id="7335157162773372339">สามารถขอใช้à¸à¸¥à¹‰à¸­à¸‡à¸‚องคุณได้</translation>
<translation id="7337248890521463931">à¹à¸ªà¸”งบรรทัดเพิ่มเติม</translation>
+<translation id="7337418456231055214">หาà¸à¸¢à¸±à¸‡à¹„ม่à¸à¸£à¸­à¸à¸«à¸¡à¸²à¸¢à¹€à¸¥à¸‚บัตรเสมือน คลิà¸à¸£à¸²à¸¢à¸¥à¸°à¹€à¸­à¸µà¸¢à¸”บัตรเพื่อคัดลอภ<ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">ยังไม่พร้อมให้ใช้งานในà¹à¸žà¸¥à¸•à¸Ÿà¸­à¸£à¹Œà¸¡à¸‚องคุณ</translation>
<translation id="733923710415886693">ไม่มีà¸à¸²à¸£à¹€à¸›à¸´à¸”เผยใบรับรองของเซิร์ฟเวอร์ผ่านความโปร่งใสของใบรับรอง</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1959,6 +2007,7 @@
<translation id="7378627244592794276">ไม่</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">ไม่เà¸à¸µà¹ˆà¸¢à¸§à¸‚้อง</translation>
+<translation id="7388594495505979117">{0,plural, =1{อุปà¸à¸£à¸“์จะรีสตาร์ทใน 1 นาที}other{อุปà¸à¸£à¸“์จะรีสตาร์ทใน # นาที}}</translation>
<translation id="7390545607259442187">ยืนยันบัตร</translation>
<translation id="7392089738299859607">อัปเดตที่อยู่</translation>
<translation id="7399802613464275309">à¸à¸²à¸£à¸•à¸£à¸§à¸ˆà¸ªà¸­à¸šà¸„วามปลอดภัย</translation>
@@ -1995,6 +2044,12 @@
<translation id="7485870689360869515">ไม่พบข้อมูล</translation>
<translation id="7495528107193238112">เนื้อหานี้ถูà¸à¸šà¸¥à¹‡à¸­à¸ โปรดติดต่อเจ้าของเว็บไซต์เพื่อให้à¹à¸à¹‰à¸›à¸±à¸à¸«à¸²</translation>
<translation id="7497998058912824456">ปุ่มสร้างเอà¸à¸ªà¸²à¸£ à¸à¸” Enter เพื่อสร้างเอà¸à¸ªà¸²à¸£à¹ƒà¸«à¸¡à¹ˆà¹ƒà¸™ Google เอà¸à¸ªà¸²à¸£à¸­à¸¢à¹ˆà¸²à¸‡à¸£à¸§à¸”เร็ว</translation>
+<translation id="7506488012654002225">Chromium <ph name="BEGIN_EMPHASIS" />จะไม่บันทึà¸<ph name="END_EMPHASIS" />ข้อมูลต่อไปนี้
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ประวัติà¸à¸²à¸£à¸—่องเว็บ
+ <ph name="LIST_ITEM" />คุà¸à¸à¸µà¹‰à¹à¸¥à¸°à¸‚้อมูลเว็บไซต์
+ <ph name="LIST_ITEM" />ข้อมูลที่ป้อนในà¹à¸šà¸šà¸Ÿà¸­à¸£à¹Œà¸¡
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">รหัสอุปà¸à¸£à¸“์นโยบายที่ส่งà¸à¸¥à¸±à¸šà¸§à¹ˆà¸²à¸‡à¹€à¸›à¸¥à¹ˆà¸²à¸«à¸£à¸·à¸­à¹„ม่ตรงà¸à¸±à¸šà¸£à¸«à¸±à¸ªà¸­à¸¸à¸›à¸à¸£à¸“์ปัจจุบัน</translation>
<translation id="7508870219247277067">เขียวอะโวคาโด</translation>
<translation id="7511955381719512146">Wi-Fi ที่คุณใช้อาจต้องà¸à¸²à¸£à¹ƒà¸«à¹‰à¸„ุณไปที่ <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /></translation>
@@ -2108,7 +2163,6 @@
<translation id="7813600968533626083">นำคำà¹à¸™à¸°à¸™à¸³à¸ªà¸³à¸«à¸£à¸±à¸šà¹à¸šà¸šà¸Ÿà¸­à¸£à¹Œà¸¡à¸­à¸­à¸à¸ˆà¸²à¸ Chrome ไหม</translation>
<translation id="781440967107097262">à¹à¸Šà¸£à¹Œà¸„ลิปบอร์ดไหม</translation>
<translation id="7815407501681723534">พบ<ph name="SEARCH_RESULTS" /> <ph name="NUMBER_OF_RESULTS" /> รายà¸à¸²à¸£à¸ªà¸³à¸«à¸£à¸±à¸š "<ph name="SEARCH_STRING" />"</translation>
-<translation id="782125616001965242">à¹à¸ªà¸”งข้อมูลเà¸à¸µà¹ˆà¸¢à¸§à¸à¸±à¸šà¹€à¸§à¹‡à¸šà¹„ซต์นี้</translation>
<translation id="782886543891417279">Wi-Fi ที่คุณใช้ (<ph name="WIFI_NAME" />) อาจต้องà¸à¸²à¸£à¹ƒà¸«à¹‰à¸„ุณไปที่หน้าà¸à¸²à¸£à¹€à¸‚้าสู่ระบบ</translation>
<translation id="7836231406687464395">Postfix (ซองจดหมาย)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{ไม่มี}=1{1 à¹à¸­à¸› (<ph name="EXAMPLE_APP_1" />)}=2{2 à¹à¸­à¸› (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}other{# à¹à¸­à¸› (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}}</translation>
@@ -2125,7 +2179,6 @@
<translation id="7888575728750733395">à¸à¸²à¸£à¸›à¸£à¸±à¸šà¸„่าสีà¸à¸²à¸£à¸žà¸´à¸¡à¸žà¹Œ</translation>
<translation id="7894280532028510793">หาà¸à¸à¸²à¸£à¸ªà¸°à¸à¸”ถูà¸à¸•à¹‰à¸­à¸‡ ให้<ph name="BEGIN_LINK" />ลองเรียà¸à¹ƒà¸Šà¹‰à¸à¸²à¸£à¸§à¸´à¸™à¸´à¸ˆà¸‰à¸±à¸¢à¹€à¸„รือข่าย<ph name="END_LINK" /></translation>
<translation id="7904208859782148177">C3 (ซองจดหมาย)</translation>
-<translation id="7931318309563332511">ไม่รู้จัà¸</translation>
<translation id="793209273132572360">อัปเดตที่อยู่ไหม</translation>
<translation id="7932579305932748336">เคลือบ</translation>
<translation id="79338296614623784">ป้อนหมายเลขโทรศัพท์ที่ถูà¸à¸•à¹‰à¸­à¸‡</translation>
@@ -2150,13 +2203,14 @@
<translation id="7976214039405368314">มีคำขอมาà¸à¹€à¸à¸´à¸™à¹„ป</translation>
<translation id="7977538094055660992">อุปà¸à¸£à¸“์à¸à¸£à¸°à¸”าษออà¸</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">ลิงà¸à¹Œà¸à¸±à¸š</translation>
<translation id="798134797138789862">สามารถขอใช้อุปà¸à¸£à¸“์à¹à¸¥à¸°à¸‚้อมูล Virtual Reality ได้</translation>
<translation id="7984945080620862648">คุณไม่สามารถไปที่ <ph name="SITE" /> ได้ในขณะนี้ เนื่องจาà¸à¹€à¸§à¹‡à¸šà¹„ซต์ดังà¸à¸¥à¹ˆà¸²à¸§à¸ªà¹ˆà¸‡à¸‚้อมูลรับรองที่สลับà¸à¸±à¸™ ซึ่ง Chrome ไม่สามารถเข้าถึงได้ โดยปà¸à¸•à¸´à¸‚้อผิดพลาดของเครือข่ายà¹à¸¥à¸°à¸à¸²à¸£à¸šà¸¸à¸à¸£à¸¸à¸à¸ˆà¸°à¹€à¸à¸´à¸”ขึ้นเพียงชั่วคราว หน้านี้จึงน่าจะใช้งานได้ในภายหลัง</translation>
-<translation id="79859296434321399">ติดตั้ง ARCore เพื่อดูเนื้อหา Augmented Reality</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">เย็บเล่ม</translation>
<translation id="7992044431894087211">à¸à¸¥à¸±à¸šà¸¡à¸²à¹à¸Šà¸£à¹Œà¸«à¸™à¹‰à¸²à¸ˆà¸­à¸à¸±à¸š <ph name="APPLICATION_TITLE" /> อีà¸à¸„รั้ง</translation>
<translation id="7995512525968007366">ไม่ได้ระบุ</translation>
+<translation id="7998269595945679889">ปุ่มเปิดà¹à¸—็บที่ไม่ระบุตัวตน à¸à¸” Enter เพื่อเปิดà¹à¸—็บที่ไม่ระบุตัวตนà¹à¸—็บใหม่ในà¸à¸²à¸£à¸—่องเว็บà¹à¸šà¸šà¸ªà¹ˆà¸§à¸™à¸•à¸±à¸§</translation>
<translation id="800218591365569300">ลองปิดà¹à¸—็บหรือโปรà¹à¸à¸£à¸¡à¸­à¸·à¹ˆà¸™à¹† เพื่อเพิ่มหน่วยความจำ</translation>
<translation id="8004582292198964060">เบราว์เซอร์</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{ระบบจะบันทึà¸à¸šà¸±à¸•à¸£à¸™à¸µà¹‰à¹à¸¥à¸°à¸—ี่อยู่สำหรับà¸à¸²à¸£à¹€à¸£à¸µà¸¢à¸à¹€à¸à¹‡à¸šà¹€à¸‡à¸´à¸™à¸‚องบัตร คุณจะใช้บัตรนี้ได้เมื่อลงชื่อเข้าใช้ <ph name="USER_EMAIL" />}other{ระบบจะบันทึà¸à¸šà¸±à¸•à¸£à¹€à¸«à¸¥à¹ˆà¸²à¸™à¸µà¹‰à¹à¸¥à¸°à¸—ี่อยู่สำหรับà¸à¸²à¸£à¹€à¸£à¸µà¸¢à¸à¹€à¸à¹‡à¸šà¹€à¸‡à¸´à¸™à¸‚องบัตร คุณจะใช้บัตรเหล่านี้ได้เมื่อลงชื่อเข้าใช้ <ph name="USER_EMAIL" />}}</translation>
@@ -2216,6 +2270,7 @@
<translation id="8202370299023114387">ความขัดà¹à¸¢à¹‰à¸‡</translation>
<translation id="8206978196348664717">Prc4 (ซองจดหมาย)</translation>
<translation id="8211406090763984747">à¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸›à¸¥à¸­à¸”ภัย</translation>
+<translation id="8217240300496046857">เว็บไซต์ต่างๆ จะใช้คุà¸à¸à¸µà¹‰à¸—ี่ติดตามคุณในอินเทอร์เน็ตไม่ได้ ฟีเจอร์ในเว็บไซต์บางà¹à¸«à¹ˆà¸‡à¸­à¸²à¸ˆà¹ƒà¸Šà¹‰à¸‡à¸²à¸™à¹„ม่ได้</translation>
<translation id="8218327578424803826">ตำà¹à¸«à¸™à¹ˆà¸‡à¸—ี่มอบหมาย:</translation>
<translation id="8220146938470311105">C7/C6 (ซองจดหมาย)</translation>
<translation id="8225771182978767009">ผู้ที่ตั้งค่าคอมพิวเตอร์เครื่องนี้เลือà¸à¸šà¸¥à¹‡à¸­à¸à¹€à¸§à¹‡à¸šà¹„ซต์นี้</translation>
@@ -2256,14 +2311,9 @@
<translation id="830498451218851433">พับครึ่ง</translation>
<translation id="8307358339886459768">รูปภาพขนาดเล็à¸</translation>
<translation id="8307888238279532626">à¹à¸­à¸›à¸—ี่ติดตั้งà¹à¸¥à¸°à¸„วามถี่ในà¸à¸²à¸£à¹ƒà¸Šà¹‰</translation>
+<translation id="8317207217658302555">อัปเดต ARCore ไหม</translation>
<translation id="831997045666694187">ตอนเย็น</translation>
<translation id="8321476692217554900">à¸à¸²à¸£à¹à¸ˆà¹‰à¸‡à¹€à¸•à¸·à¸­à¸™</translation>
-<translation id="8328484624016508118">หลังจาà¸à¸—ี่ปิดà¹à¸—็บที่ไม่ระบุตัวตนทั้งหมด Chrome จะล้าง
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />à¸à¸´à¸ˆà¸à¸£à¸£à¸¡à¸à¸²à¸£à¸—่องเว็บออà¸à¸ˆà¸²à¸à¸­à¸¸à¸›à¸à¸£à¸“์นี้<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />ประวัติà¸à¸²à¸£à¸„้นหาออà¸à¸ˆà¸²à¸à¸­à¸¸à¸›à¸à¸£à¸“์นี้<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />ข้อมูลที่ป้อนในà¹à¸šà¸šà¸Ÿà¸­à¸£à¹Œà¸¡<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489">à¸à¸²à¸£à¹€à¸‚้าถึง <ph name="HOST_NAME" /> ถูà¸à¸›à¸à¸´à¹€à¸ªà¸˜</translation>
<translation id="833262891116910667">ไฮไลต์</translation>
<translation id="8339163506404995330">ระบบจะไม่à¹à¸›à¸¥à¸«à¸™à¹‰à¸²à¹€à¸§à¹‡à¸šà¸ à¸²à¸©à¸²<ph name="LANGUAGE" /></translation>
@@ -2315,6 +2365,7 @@
<translation id="8507227106804027148">บรรทัดคำสั่ง</translation>
<translation id="8508648098325802031">ไอคอนค้นหา</translation>
<translation id="8511402995811232419">จัดà¸à¸²à¸£à¸„ุà¸à¸à¸µà¹‰</translation>
+<translation id="8519753333133776369">อุปà¸à¸£à¸“์ HID นี้ได้รับอนุà¸à¸²à¸•à¸ˆà¸²à¸à¸œà¸¹à¹‰à¸”ูà¹à¸¥à¸£à¸°à¸šà¸š</translation>
<translation id="8522552481199248698">Chrome ช่วยคุณปà¸à¸›à¹‰à¸­à¸‡à¸šà¸±à¸à¸Šà¸µ Google à¹à¸¥à¸°à¹€à¸›à¸¥à¸µà¹ˆà¸¢à¸™à¸£à¸«à¸±à¸ªà¸œà¹ˆà¸²à¸™à¹„ด้</translation>
<translation id="8530813470445476232">ล้างประวัติà¸à¸²à¸£à¸—่องเว็บ คุà¸à¸à¸µà¹‰ à¹à¸„ช à¹à¸¥à¸°à¸­à¸·à¹ˆà¸™à¹† ในà¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่า Chrome</translation>
<translation id="8533619373899488139">ไปที่ &lt;strong&gt;chrome://policy&lt;/strong&gt; เพื่อดูรายà¸à¸²à¸£ URL ที่ถูà¸à¸šà¸¥à¹‡à¸­à¸à¹à¸¥à¸°à¸™à¹‚ยบายอื่นๆ ที่ผู้ดูà¹à¸¥à¸£à¸°à¸šà¸šà¸šà¸±à¸‡à¸„ับใช้</translation>
@@ -2326,7 +2377,6 @@
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{รีเซ็ตสิทธิ์}other{รีเซ็ตสิทธิ์}}</translation>
<translation id="8555010941760982128">ใช้รหัสนี้เมื่อชำระเงิน</translation>
<translation id="8557066899867184262">CVC จะอยู่ที่ด้านหลังบัตร</translation>
-<translation id="8558485628462305855">อัปเดต ARCore เพื่อดูเนื้อหา Augmented Reality</translation>
<translation id="8559762987265718583">ไม่สามารถเริ่มà¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸ªà¹ˆà¸§à¸™à¸•à¸±à¸§à¸à¸±à¸š <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> ได้เนื่องจาà¸à¸§à¸±à¸™à¸—ี่à¹à¸¥à¸°à¹€à¸§à¸¥à¸²à¸‚องอุปà¸à¸£à¸“์ (<ph name="DATE_AND_TIME" />) ไม่ถูà¸à¸•à¹‰à¸­à¸‡</translation>
<translation id="8564182942834072828">เอà¸à¸ªà¸²à¸£à¹à¸¢à¸à¸à¸±à¸™/ไม่จัดชุดสำเนา</translation>
<translation id="8564985650692024650">Chromium ขอà¹à¸™à¸°à¸™à¸³à¹ƒà¸«à¹‰à¸£à¸µà¹€à¸‹à¹‡à¸•à¸£à¸«à¸±à¸ªà¸œà¹ˆà¸²à¸™ <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> หาà¸à¸„ุณใช้รหัสผ่านนี้ซ้ำในเว็บไซต์อื่น</translation>
@@ -2346,6 +2396,7 @@
<translation id="865032292777205197">เซ็นเซอร์ตรวจจับà¸à¸²à¸£à¹€à¸„ลื่อนไหว</translation>
<translation id="8663226718884576429">สรุปคำสั่งซื้อ <ph name="TOTAL_LABEL" /> รายละเอียดเพิ่มเติม</translation>
<translation id="8666678546361132282">อังà¸à¸¤à¸©</translation>
+<translation id="8669306706049782872">ใช้ข้อมูลเà¸à¸µà¹ˆà¸¢à¸§à¸à¸±à¸šà¸«à¸™à¹‰à¸²à¸ˆà¸­à¹€à¸žà¸·à¹ˆà¸­à¹€à¸›à¸´à¸”à¹à¸¥à¸°à¸§à¸²à¸‡à¸«à¸™à¹‰à¸²à¸•à¹ˆà¸²à¸‡</translation>
<translation id="867224526087042813">ลายเซ็น</translation>
<translation id="8676424191133491403">ไม่หน่วงเวลา</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, คำตอบ, <ph name="ANSWER" /></translation>
@@ -2372,6 +2423,7 @@
<translation id="8731544501227493793">จัดà¸à¸²à¸£à¸›à¸¸à¹ˆà¸¡à¸£à¸«à¸±à¸ªà¸œà¹ˆà¸²à¸™ à¸à¸” Enter เพื่อดูà¹à¸¥à¸°à¸ˆà¸±à¸”à¸à¸²à¸£à¸£à¸«à¸±à¸ªà¸œà¹ˆà¸²à¸™à¹ƒà¸™à¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่า Chrome</translation>
<translation id="8734529307927223492"><ph name="DEVICE_TYPE" /> ของคุณจัดà¸à¸²à¸£à¹‚ดย <ph name="MANAGER" /></translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" /> à¸à¸” Tab ตามด้วย Enter เพื่อเปิดหน้าต่างใหม่ที่ไม่ระบุตัวตนเพื่อท่องเว็บà¹à¸šà¸šà¸ªà¹ˆà¸§à¸™à¸•à¸±à¸§</translation>
+<translation id="8737685506611670901">เปิดลิงà¸à¹Œ <ph name="PROTOCOL" /> à¹à¸—น <ph name="REPLACED_HANDLER_TITLE" /></translation>
<translation id="8738058698779197622">หาà¸à¸•à¹‰à¸­à¸‡à¹€à¸£à¸´à¹ˆà¸¡à¸à¸²à¸£à¹€à¸Šà¸·à¹ˆà¸­à¸¡à¸•à¹ˆà¸­à¸—ี่ปลอดภัย นาฬิà¸à¸²à¸ˆà¸°à¸•à¹‰à¸­à¸‡à¸•à¸±à¹‰à¸‡à¸„่าไว้อย่างถูà¸à¸•à¹‰à¸­à¸‡ เนื่องจาà¸à¹ƒà¸šà¸£à¸±à¸šà¸£à¸­à¸‡à¸—ี่เว็บไซต์ใช้เพื่อระบุตนเองจะใช้ได้เฉพาะช่วงเวลาหนึ่งเท่านั้น นาฬิà¸à¸²à¸‚องอุปà¸à¸£à¸“์ไม่ถูà¸à¸•à¹‰à¸­à¸‡ Chromium จึงไม่สามารถยืนยันใบรับรองเหล่านี้ได้</translation>
<translation id="8740359287975076522">ไม่พบ&lt;abbr id="dnsDefinition"&gt;ที่อยู่ DNS&lt;/abbr&gt; ของ <ph name="HOST_NAME" /> à¸à¸³à¸¥à¸±à¸‡à¸§à¸´à¸™à¸´à¸ˆà¸‰à¸±à¸¢à¸›à¸±à¸à¸«à¸²</translation>
<translation id="8742371904523228557">รหัสสำหรับ <ph name="ORIGIN" /> คือ <ph name="ONE_TIME_CODE" /></translation>
@@ -2399,6 +2451,7 @@
<translation id="883848425547221593">บุ๊à¸à¸¡à¸²à¸£à¹Œà¸à¸­à¸·à¹ˆà¸™à¹†</translation>
<translation id="884264119367021077">ที่อยู่สำหรับจัดส่ง</translation>
<translation id="884923133447025588">ไม่พบà¸à¸£à¸°à¸šà¸§à¸™à¸à¸²à¸£à¹€à¸žà¸´à¸à¸–อน</translation>
+<translation id="8849262850971482943">ใช้บัตรเสมือนเพื่อเพิ่มความปลอดภัย</translation>
<translation id="885730110891505394">à¸à¸²à¸£à¹à¸Šà¸£à¹Œà¸à¸±à¸š Google</translation>
<translation id="8858065207712248076">Chrome ขอà¹à¸™à¸°à¸™à¸³à¹ƒà¸«à¹‰à¸£à¸µà¹€à¸‹à¹‡à¸•à¸£à¸«à¸±à¸ªà¸œà¹ˆà¸²à¸™ <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> หาà¸à¸„ุณใช้รหัสผ่านนี้ซ้ำในเว็บไซต์อื่น</translation>
<translation id="885906927438988819">หาà¸à¸à¸²à¸£à¸ªà¸°à¸à¸”ถูà¸à¸•à¹‰à¸­à¸‡ ให้<ph name="BEGIN_LINK" />ลองเรียà¸à¹ƒà¸Šà¹‰à¸à¸²à¸£à¸§à¸´à¸™à¸´à¸ˆà¸‰à¸±à¸¢à¹€à¸„รือข่ายของ Windows<ph name="END_LINK" /></translation>
@@ -2448,6 +2501,7 @@
<translation id="9004367719664099443">เซสชัน VR à¸à¸³à¸¥à¸±à¸‡à¸—ำงาน</translation>
<translation id="9005998258318286617">ไม่สามารถโหลดเอà¸à¸ªà¸²à¸£ PDF</translation>
<translation id="9008201768610948239">ไม่สนใจ</translation>
+<translation id="901834265349196618">อีเมล</translation>
<translation id="9020200922353704812">ต้องใส่ที่อยู่สำหรับà¸à¸²à¸£à¹€à¸£à¸µà¸¢à¸à¹€à¸à¹‡à¸šà¹€à¸‡à¸´à¸™à¸‚องบัตร</translation>
<translation id="9020542370529661692">หน้านี้ได้รับà¸à¸²à¸£à¹à¸›à¸¥à¹€à¸›à¹‡à¸™ <ph name="TARGET_LANGUAGE" /> à¹à¸¥à¹‰à¸§</translation>
<translation id="9020742383383852663">A8</translation>
@@ -2496,6 +2550,7 @@
<translation id="9150045010208374699">ใช้à¸à¸¥à¹‰à¸­à¸‡à¸–่ายรูปของคุณ</translation>
<translation id="9150685862434908345">ผู้ดูà¹à¸¥à¸£à¸°à¸šà¸šà¸ˆà¸°à¹€à¸›à¸¥à¸µà¹ˆà¸¢à¸™à¸à¸²à¸£à¸•à¸±à¹‰à¸‡à¸„่าเบราว์เซอร์จาà¸à¸£à¸°à¸¢à¸°à¹„à¸à¸¥à¹„ด้ à¸à¸´à¸ˆà¸à¸£à¸£à¸¡à¹ƒà¸™à¸­à¸¸à¸›à¸à¸£à¸“์นี้อาจมีà¸à¸²à¸£à¸ˆà¸±à¸”à¸à¸²à¸£à¸ à¸²à¸¢à¸™à¸­à¸ Chrome ได้ด้วย <ph name="BEGIN_LINK" />ดูข้อมูลเพิ่มเติม<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">อัปเดตà¹à¸¥à¹‰à¸§</translation>
+<translation id="9155211586651734179">อุปà¸à¸£à¸“์ต่อพ่วงเสียงที่ต่อเชื่อมไว้</translation>
<translation id="9157595877708044936">à¸à¸³à¸¥à¸±à¸‡à¸•à¸±à¹‰à¸‡à¸„่า...</translation>
<translation id="9158625974267017556">C6 (ซองจดหมาย)</translation>
<translation id="9164029392738894042">à¸à¸²à¸£à¸•à¸£à¸§à¸ˆà¸ªà¸­à¸šà¸„วามà¹à¸¡à¹ˆà¸™à¸¢à¸³</translation>
diff --git a/chromium/components/strings/components_strings_tr.xtb b/chromium/components/strings/components_strings_tr.xtb
index 3a519a255d6..ec439575365 100644
--- a/chromium/components/strings/components_strings_tr.xtb
+++ b/chromium/components/strings/components_strings_tr.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">Ayrıntıları bakın</translation>
<translation id="1030706264415084469"><ph name="URL" /> büyük miktarda veriyi cihazınızda kalıcı olarak depolamak istiyor</translation>
<translation id="1032854598605920125">Saat yönünde döndür</translation>
+<translation id="1033329911862281889">Gizli mod sizi internet ortamında görünmez hale getirmez:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Siteler ve bu sitelerin kullandığı hizmetler ziyaretlerinizi görebilir<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Ä°ÅŸverenler veya okullar tarama etkinliÄŸini izleyebilir<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />İnternet Servis Sağlayıcıları web trafiğini izleyebilir<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">Kapat</translation>
<translation id="1036982837258183574">Tam ekrandan çıkmak için |<ph name="ACCELERATOR" />| tuşuna basın</translation>
<translation id="1038106730571050514">Önerileri göster</translation>
<translation id="1038842779957582377">bilinmeyen ad</translation>
<translation id="1041998700806130099">İş sayfası mesajı</translation>
<translation id="1048785276086539861">Ek açıklamaları düzenlediğinizde bu doküman tek sayfalı görünüme geri döner</translation>
-<translation id="1049743911850919806">Gizli mod</translation>
<translation id="1050038467049342496">Diğer uygulamaları kapatın</translation>
<translation id="1055184225775184556">Eklemeyi &amp;Geri Al</translation>
<translation id="1056898198331236512">Uyarı</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">Politika önbelleği uygun</translation>
<translation id="1130564665089811311">Sayfayı çevir düğmesi, bu sayfayı Google Çeviri'yle çevirmek için Enter'a basın</translation>
<translation id="1131264053432022307">Kopyalanan Resim</translation>
+<translation id="1142846828089312304">Gizli modda üçüncü taraf çerezleri engelle</translation>
<translation id="1150979032973867961">Bu sunucu <ph name="DOMAIN" /> olduğunu kanıtlayamadı. Bilgisayarınızın işletim sistemi, sunucunun güvenlik sertifikasına güvenmiyor. Bu durum, bir yanlış yapılandırmadan veya bağlantıya müdahale eden bir saldırgandan kaynaklanıyor olabilir.</translation>
<translation id="1151972924205500581">Åžifre gerekiyor</translation>
<translation id="1156303062776767266">Yerel veya paylaşılan bir dosyayı görüntülüyorsunuz</translation>
@@ -64,7 +70,6 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="1178581264944972037">Duraklat</translation>
<translation id="1181037720776840403">Kaldır</translation>
<translation id="1186201132766001848">Åžifreleri Kontrol Et</translation>
-<translation id="1195210374336998651">Uygulama ayarlarına git</translation>
<translation id="1195558154361252544">Bildirimler, izin verdikleriniz dışındaki tüm siteler için otomatik olarak engellenir</translation>
<translation id="1197088940767939838">Turuncu</translation>
<translation id="1201402288615127009">Ä°leri</translation>
@@ -111,7 +116,7 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="1307966114820526988">Kullanımdan Kaldırılan Özellikler</translation>
<translation id="1308113895091915999">Teklif mevcut</translation>
<translation id="1312803275555673949">Bunu destekleyen kanıtlar neler?</translation>
-<translation id="131405271941274527"><ph name="URL" />, bir NFC cihazında telefonunuza dokunduğunuzda bilgi gönderip almak istiyor</translation>
+<translation id="1314311879718644478">Artırılmış gerçeklik içeriğini görüntüleyin</translation>
<translation id="1314509827145471431">Sağdan bağlı</translation>
<translation id="1318023360584041678">Sekme grubuna kaydedildi</translation>
<translation id="1319245136674974084">Bu uygulama için tekrar sorma</translation>
@@ -161,6 +166,7 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="142858679511221695">Bulut kullanıcısı</translation>
<translation id="1428729058023778569">Bu site HTTPS'yi desteklemediği için bu uyarıyı görüyorsunuz. <ph name="BEGIN_LEARN_MORE_LINK" />Daha fazla bilgi<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">Yazdır</translation>
+<translation id="1432187715652018471">sayfa bir servis işleyici yüklemek istiyor.</translation>
<translation id="1432581352905426595">Arama motorlarını yönet</translation>
<translation id="1436185428532214179">Cihazınızdaki dosyaları veya klasörleri düzenlemek isteyebilir</translation>
<translation id="1442386063175183758">Sağa doğru iki kırımlı katlama</translation>
@@ -181,6 +187,12 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="1483493594462132177">Gönder</translation>
<translation id="1484290072879560759">Gönderim Adresi Seç</translation>
<translation id="1492194039220927094">Politikalar aktarılabilir:</translation>
+<translation id="149293076951187737">Tüm Chrome gizli sekmelerini kapattığınızda bu sekmelerde bulunan aşağıdaki etkinlikleriniz cihazdan temizlenir:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Tarama etkinliÄŸi<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Arama geçmişi<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Formlara girilen bilgiler<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">Sekmeye dön</translation>
<translation id="1501859676467574491">Google Hesabımdaki kartları göster</translation>
<translation id="1507202001669085618">&lt;p&gt;İnternete girmek için oturum açmanızı gerektiren bir kablosuz portal kullanıyorsanız bu hatayı görürsünüz.&lt;/p&gt;
@@ -208,6 +220,8 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="1559572115229829303">&lt;p&gt;Cihazınızın tarih ve saati (<ph name="DATE_AND_TIME" />) yanlış olduğundan <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> alan adına gizli bir bağlantı kurulamadı.&lt;/p&gt;
&lt;p&gt;Lütfen &lt;strong&gt;Ayarlar&lt;/strong&gt; uygulamasının &lt;strong&gt;Genel&lt;/strong&gt; bölümünden tarih ve saati ayarlayın.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">Yöneticiniz cihazınızı <ph name="DATE" /> tarihinde saat <ph name="TIME" /> olunca yeniden başlatacak</translation>
+<translation id="156703335097561114">Adresler, arayüz yapılandırması ve bağlantı kalitesi gibi ağ iletişimi bilgileri</translation>
<translation id="1567040042588613346">Bu politika beklenildiği gibi çalışıyor, ancak başka bir yerde ayarlanmış aynı değeri geçersiz kılıyor.</translation>
<translation id="1569487616857761740">Son kullanma tarihi girin</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="1583429793053364125">Bu web sayfasını görüntülerken bir hata oluştu.</translation>
<translation id="1586541204584340881">Hangi uzantıları yüklediğiniz</translation>
<translation id="1588438908519853928">Normal</translation>
+<translation id="1589050138437146318">ARCore yüklensin mi?</translation>
<translation id="1592005682883173041">Yerel Veri EriÅŸimi</translation>
<translation id="1594030484168838125">Seç</translation>
<translation id="160851722280695521">Chrome'da Dinazor oyununu oynayın</translation>
@@ -254,7 +269,7 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="1711234383449478798"><ph name="POLICY_NAME" />, <ph name="VALUE" /> olarak ayarlanmadığından yok sayıldı.</translation>
<translation id="1712552549805331520"><ph name="URL" />, verileri yerel bilgisayarınızda kalıcı olarak saklamak istiyor</translation>
<translation id="1713628304598226412">Tepsi 2</translation>
-<translation id="1715874602234207">F</translation>
+<translation id="1715874602234207">C</translation>
<translation id="1717218214683051432">Hareket sensörleri</translation>
<translation id="1717494416764505390">Posta kutusu 3</translation>
<translation id="1718029547804390981">Doküman, ek açıklama ilave edilemeyecek kadar büyük</translation>
@@ -280,6 +295,7 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Windows Ağ Teşhislerini çalıştırmayı deneyin<ph name="END_LINK" />.</translation>
<translation id="1772163372082567643">Ziyaret etmek üzere olduğunuz sunucu (<ph name="ORIGIN" />) kendisine gelen tüm isteklere bir kaynak politikası uygulanmasını gerektiren bir üst bilgi ayarladı. Ancak üst bilgi yanlış biçimlendirildiği için tarayıcı, <ph name="SITE" /> sitesiyle ilgili isteğinizi yerine getiremiyor. Kaynak politikaları
site operatörleri tarafından sitenin güvenliğini ve diğer mülklerini yapılandırmak için kullanılabilir.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Chromium'daki Gizli mod hakkında daha fazla bilgi<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">Açık sekmeleriniz burada görünür</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -407,6 +423,7 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="22081806969704220">Tepsi 3</translation>
<translation id="2212735316055980242">Politika bulunamadı</translation>
<translation id="2213606439339815911">GiriÅŸler getiriliyor...</translation>
+<translation id="2213612003795704869">Sayfa yazdırıldı</translation>
<translation id="2215727959747642672">Dosya düzenleme</translation>
<translation id="2218879909401188352">Şu anda <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> öğesini kullanan saldırganlar cihazınıza zarar verebilecek uygulamalar yükleyebilir, sizden habersiz mobil faturanıza ücretler ekleyebilir veya kişisel bilgilerinizi çalabilirler. <ph name="BEGIN_LEARN_MORE_LINK" />Daha fazla bilgi<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">İnternet bağlantısı yok</translation>
@@ -416,6 +433,7 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="2248949050832152960">WebAuthn'u kullan</translation>
<translation id="2250931979407627383">Solda kenar dikiÅŸi</translation>
<translation id="225207911366869382">Bu değer bu politika için kullanımdan kaldırıldı.</translation>
+<translation id="2256115617011615191">Åžimdi yeniden baÅŸlat</translation>
<translation id="2258928405015593961">Gelecekte olan bir son kullanma tarihi girip tekrar deneyin</translation>
<translation id="225943865679747347">Hata kodu: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">HTTP hatası</translation>
@@ -443,6 +461,7 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="2337852623177822836">Ayar yöneticinizin kontrolü altındadır</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> eÅŸlenmek istiyor</translation>
<translation id="2346319942568447007">Kopyalanan resim</translation>
+<translation id="2350796302381711542">Tüm <ph name="PROTOCOL" /> bağlantılarını <ph name="REPLACED_HANDLER_TITLE" /> yerine <ph name="HANDLER_HOSTNAME" /> ana makinesinin açmasına izin verilsin mi?</translation>
<translation id="2354001756790975382">DiÄŸer yer iÅŸaretleri</translation>
<translation id="2354430244986887761">Google Güvenli Tarama son zamanlarda <ph name="SITE" /> sitesinde <ph name="BEGIN_LINK" />zararlı uygulamalar buldu<ph name="END_LINK" />.</translation>
<translation id="2355395290879513365">Saldırganlar bu sitede baktığınız resimleri görebilir ve bu resimler üzerinde değişiklik yaparak sizi kandırabilirler.</translation>
@@ -468,6 +487,7 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="2413528052993050574">Bu sunucu <ph name="DOMAIN" /> olduğunu kanıtlayamadı. Güvenlik sertifikası iptal edilmiş olabilir. Bu durum, bir yanlış yapılandırmadan veya bağlantıya müdahale eden bir saldırgandan kaynaklanıyor olabilir.</translation>
<translation id="2414886740292270097">Koyu</translation>
<translation id="2430968933669123598">Google Hesabı'nı yönet, Google Hesabınızda bilgilerinizi, gizliliğinizi ve güvenliğinizi yönetmek için Enter'a basın</translation>
+<translation id="2436186046335138073"><ph name="HANDLER_HOSTNAME" /> ana makinesinin tüm <ph name="PROTOCOL" /> bağlantılarını açmasına izin verilsin mi?</translation>
<translation id="2438874542388153331">Sağda dörtlü delik</translation>
<translation id="2450021089947420533">Arama Yolculukları</translation>
<translation id="2463739503403862330">Doldur</translation>
@@ -475,6 +495,7 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="2465655957518002998">Teslimat Yöntemi Seç</translation>
<translation id="2465688316154986572">Tel zımba</translation>
<translation id="2465914000209955735">Chrome'da indirdiğiniz dosyaları yönetin</translation>
+<translation id="2466004615675155314">Web'den alınan bilgileri göster</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Ağ Teşhislerini Çalıştırma<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">1'den N'ye sıralı</translation>
<translation id="2470767536994572628">Ek açıklamaları düzenlerseniz bu doküman hem tek sayfalı görünüme hem de orijinal rotasyonuna geri döner</translation>
@@ -495,6 +516,7 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="2523886232349826891">Yalnızca bu cihazda kaydedildi</translation>
<translation id="2524461107774643265">Daha Fazla Bilgi Ekleyin</translation>
<translation id="2529899080962247600">Bu alanda en çok <ph name="MAX_ITEMS_LIMIT" /> giriş olabilir. Bundan sonraki tüm girişler yok sayılacak.</translation>
+<translation id="2535585790302968248">Gizli olarak göz atmak için yeni bir gizli sekme aç</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{ve 1 tane daha}other{ve # tane daha}}</translation>
<translation id="2536110899380797252">Adres Ekle</translation>
<translation id="2539524384386349900">Algıla</translation>
@@ -520,7 +542,14 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="2597378329261239068">Doküman şifre korumalı. Lütfen şifreyi girin.</translation>
<translation id="2609632851001447353">Varyasyonlar</translation>
<translation id="2610561535971892504">Kopyalamak için tıkla</translation>
+<translation id="2617988307566202237">Chrome aşağıdaki bilgileri <ph name="BEGIN_EMPHASIS" />kaydetmez<ph name="END_EMPHASIS" />:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Tarama geçmişiniz
+ <ph name="LIST_ITEM" />Çerezler ve site verileri
+ <ph name="LIST_ITEM" />Formlara girilen bilgiler
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (Zarf)</translation>
+<translation id="2623663032199728144">Ekranlarınızla ilgili bilgileri kullanmak isteyebilir</translation>
<translation id="2625385379895617796">Saatiniz ileri</translation>
<translation id="262745152991669301">USB cihazlara baÄŸlanmak isteyebilir</translation>
<translation id="2629325967560697240">Chrome’un sağladığı en yüksek güvenlik düzeyinden faydalanmak için <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />gelişmiş korumayı açın<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -554,6 +583,7 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="2709516037105925701">Otomatik doldurma</translation>
<translation id="2713444072780614174">Beyaz</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />, Chrome ayarlarında ödemelerinizi ve kredi kartı bilgilerinizi yönetmek için Sekme'ye, sonra Enter'a basın</translation>
+<translation id="271663710482723385">Tam ekrandan çıkmak için |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| tuşlarına basın</translation>
<translation id="2721148159707890343">İstek başarılı oldu</translation>
<translation id="2723669454293168317">Chrome ayarlarında güvenlik kontrolü yürütün</translation>
<translation id="2726001110728089263">Yan Tepsi</translation>
@@ -584,6 +614,7 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="2850739647070081192">Invite (Zarf)</translation>
<translation id="2856444702002559011">Saldırganlar <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> üzerinden bilgilerinizi çalmaya çalışıyor olabilir (örneğin, şifreler, mesajlar veya kredi kartları). <ph name="BEGIN_LEARN_MORE_LINK" />Daha fazla bilgi<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">Bu site, araya giren veya yanıltıcı reklamlar gösteriyor.</translation>
+<translation id="286512204874376891">Sanal kart gerçek kartınızı saklayarak olası sahtekarlıklardan korunmanıza yardımcı olur. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">Dost Canlısı</translation>
<translation id="2876489322757410363">Harici bir uygulama üzerinden ödeme gerçekleştirmek için Gizli moddan çıkılıyor. Devam etmek istiyor musunuz?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />, Chrome ayarlarında Güvenli Tarama ve diğer özellikleri yönetmek için Sekme'ye, ardından Enter'a basın</translation>
@@ -608,6 +639,7 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="2930577230479659665">Her kopyadan sonra kırp</translation>
<translation id="2932085390869194046">Şifre Öner...</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019"><ph name="PROTOCOL" /> bağlantılarını açma</translation>
<translation id="2941952326391522266">Bu sunucu <ph name="DOMAIN" /> olduğunu kanıtlayamadı. Güvenlik sertifikası <ph name="DOMAIN2" /> alan adından geliyor. Bu durum, bir yanlış yapılandırmadan veya bağlantıya müdahale eden bir saldırgandan kaynaklanıyor olabilir.</translation>
<translation id="2943895734390379394">Yükleme Süresi:</translation>
<translation id="2948083400971632585">Ayarlar sayfasından, bir bağlantı için yapılandırılmış proxy'leri devre dışı bırakabilirsiniz.</translation>
@@ -640,6 +672,7 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="3037605927509011580">Hay aksi!</translation>
<translation id="3041612393474885105">Sertifika Bilgileri</translation>
<translation id="3044034790304486808">Araştırmanızı devam ettirin</translation>
+<translation id="305162504811187366">Zaman damgaları, ana makine ve istemci oturum kimlikleri dahil olmak üzere Chrome Uzaktan Masaüstü geçmişi</translation>
<translation id="3060227939791841287">C9 (Zarf)</translation>
<translation id="3061707000357573562">Yama Hizmeti</translation>
<translation id="306573536155379004">Oyun başladı.</translation>
@@ -680,6 +713,7 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="3197136577151645743">Bu cihazı etkin olarak kullandığınızda bilgilendirilmek isteyebilir</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />, Chrome ayarlarında hangi bilgileri senkronize ettiğinizi yönetmek için Sekme'ye, ardından Enter'a basın</translation>
<translation id="320323717674993345">Ödemeyi iptal et</translation>
+<translation id="3203366800380907218">Web'den</translation>
<translation id="3207960819495026254">Yer iÅŸareti koyuldu</translation>
<translation id="3209034400446768650">Sayfa sizden ücret alabilir</translation>
<translation id="3212581601480735796"><ph name="HOSTNAME" /> sitesinde etkinliÄŸiniz izleniyor</translation>
@@ -696,10 +730,12 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="3234666976984236645">Her zaman bu sitedeki önemli içeriği algıla</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />, Tarayıcınızın görünümünü özelleştirmek için sekmeye, ardından Enter'a basın</translation>
<translation id="3240791268468473923">Eşleşmeyen güvenli ödeme kimlik bilgisi sayfası açıldı</translation>
+<translation id="324180406144491771">"<ph name="HOST_NAME" />" bağlantıları engellenmiş</translation>
<translation id="3249845759089040423">Modern</translation>
<translation id="3252266817569339921">Fransızca</translation>
<translation id="3257954757204451555">Bu bilginin kaynağı kim?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />, Google Takvim'de hızlıca yeni bir etkinlik oluşturmak için Sekme'ye, ardından Enter'a basın</translation>
+<translation id="3261488570342242926">Sanal kartlar hakkında bilgi</translation>
<translation id="3264837738038045344">Chrome ayarlarını yönetin düğmesi, Chrome ayarlarınıza gitmek için Enter'a basın</translation>
<translation id="3266793032086590337">Değer (çakışma)</translation>
<translation id="3268451620468152448">Açık Sekmeler</translation>
@@ -713,6 +749,7 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="3288238092761586174"><ph name="URL" />, ödemenizi onaylamak için ek adımlar uygulayabilir</translation>
<translation id="3293642807462928945"><ph name="POLICY_NAME" /> politikası ile ilgili daha fazla bilgi edinin</translation>
<translation id="3295444047715739395">Chrome ayarlarında şifrelerinizi görüntüleyin ve yönetin</translation>
+<translation id="3303795387212510132">Uygulamanın <ph name="PROTOCOL_SCHEME" /> bağlantılarını açmasına izin verilsin mi?</translation>
<translation id="3303855915957856445">Arama sonucu bulunamadı</translation>
<translation id="3304073249511302126">bluetooth taraması</translation>
<translation id="3308006649705061278">KuruluÅŸ Birimi (OU)</translation>
@@ -726,12 +763,6 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="3345782426586609320">Gözler</translation>
<translation id="3355823806454867987">Proxy ayarlarını değiştir...</translation>
<translation id="3360103848165129075">Ödeme işleyici sayfası</translation>
-<translation id="3361596688432910856">Chrome aşağıdaki bilgileri <ph name="BEGIN_EMPHASIS" />kaydetmez<ph name="END_EMPHASIS" />:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Tarama geçmişiniz
- <ph name="LIST_ITEM" />Çerezler ve site verileri
- <ph name="LIST_ITEM" />Formlara girilen bilgiler
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">Bu politika, kullanımdan kaldırılmış <ph name="OLD_POLICY" /> politikasından otomatik olarak kopyalanmıştır. Onun yerine bu politikayı kullanmalısınız.</translation>
<translation id="3364869320075768271"><ph name="URL" /> sanal gerçeklik cihazınızı ve verilerinizi kullanmak istiyor</translation>
<translation id="3366477098757335611">Kartları göster</translation>
@@ -814,7 +845,6 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="3587738293690942763">Orta</translation>
<translation id="3592413004129370115">Italian (Zarf)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{Grubunuzu istediğiniz zaman sıfırlayabilirsiniz. Yeni bir gruba katılmak yaklaşık bir gün sürer.}=1{Grubunuzu istediğiniz zaman sıfırlayabilirsiniz. Yeni bir gruba katılmak yaklaşık bir gün sürer.}other{Grubunuzu istediğiniz zaman sıfırlayabilirsiniz. Yeni bir gruba katılmak yaklaşık {NUM_DAYS} gün sürer.}}</translation>
-<translation id="3596012367874587041">Uygulama ayarları</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">Uygulama, yöneticiniz tarafından engellendi</translation>
<translation id="3608932978122581043">Besleme yönü</translation>
@@ -857,6 +887,7 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="370972442370243704">Arama Yolculukları'nı aç</translation>
<translation id="3711895659073496551">Askıya al</translation>
<translation id="3712624925041724820">Lisanslar bitti</translation>
+<translation id="3714633008798122362">web takvimi</translation>
<translation id="3714780639079136834">Mobil veriyi veya kablosuz bağlantıyı açma</translation>
<translation id="3715597595485130451">Kablosuz Ağ Bağlantısı</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Proxy, güvenlik duvarı ve DNS yapılandırmasını kontrol etme<ph name="END_LINK" /></translation>
@@ -918,6 +949,7 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="3906954721959377182">Tablet</translation>
<translation id="3909477809443608991"><ph name="URL" />, korunan içeriği oynatmak istiyor. Cihazınızın kimliği Google tarafından doğrulanır ve bu site tarafından erişilebilir.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">Reddet</translation>
<translation id="3939773374150895049">CVC yerine WebAuthn kullanılsın mı?</translation>
<translation id="3946209740501886391">Bu sitede her zaman sor</translation>
<translation id="3947595700203588284">MIDI cihazlarına bağlanmak isteyebilir</translation>
@@ -938,6 +970,7 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="3987940399970879459">1 MB'tan az</translation>
<translation id="3990250421422698716">Jog ofset</translation>
<translation id="3996311196211510766"><ph name="ORIGIN" /> sitesi, bir kaynak politikasının kendisine gelen tüm talepler için geçerli olmasını istedi, ancak bu politika şu anda uygulanamıyor.</translation>
+<translation id="4009243425692662128">Yazdırdığınız sayfaların içeriği analiz edilmek üzere Google Cloud'a veya üçüncü taraflara gönderilir. Dosyalarınızın hassas veriler içerip içermediği kontrol edilir.</translation>
<translation id="4010758435855888356">Depolama alanına erişime izin verilsin mi?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{{COUNT} sayfalı PDF dokümanı}other{{COUNT} sayfalı PDF dokümanı}}</translation>
<translation id="4023431997072828269">Bu form, güvenli olmayan bir bağlantı kullanılarak gönderildiğinden bilgileriniz başkaları tarafından görülebilir.</translation>
@@ -1029,6 +1062,7 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="4250680216510889253">Hayır</translation>
<translation id="4253168017788158739">Notlar</translation>
<translation id="425582637250725228">Yaptığınız değişiklikler kaydedilmemiş olabilir.</translation>
+<translation id="425869179292622354">Sanal kartla daha güvenli hale getirilsin mi?</translation>
<translation id="4258748452823770588">İmza yanlış</translation>
<translation id="4261046003697461417">Korumalı dokümanlarda ek açıklama özelliği kullanılamaz</translation>
<translation id="4265872034478892965">Yöneticiniz tarafından izin verildi</translation>
@@ -1091,6 +1125,7 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="4434045419905280838">Pop-up'lar ve yönlendirmeler</translation>
<translation id="4435702339979719576">Kartpostal)</translation>
<translation id="443673843213245140">Proxy kullanımı devre dışı, ancak açık bir proxy yapılandırması belirtildi.</translation>
+<translation id="4441832193888514600">Yalnızca bulut kullanıcı politikası olarak ayarlanabileceği için politika yoksayıldı.</translation>
<translation id="4450893287417543264">Bir daha gösterme</translation>
<translation id="4451135742916150903">HID cihazlarına bağlanmak isteyebilir</translation>
<translation id="4452328064229197696">Az önce kullandığınız şifrenin bir veri ihlali sonucunda açığa çıktığı anlaşıldı. Google Şifre Yöneticisi, hesaplarınızın güvenliğini sağlamak için kayıtlı şifrelerinizi kontrol etmenizi öneriyor.</translation>
@@ -1146,6 +1181,7 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="4628948037717959914">FotoÄŸraf</translation>
<translation id="4631649115723685955">Nakit para üstü bağlantısı oluşturuldu</translation>
<translation id="4636930964841734540">Bilgi</translation>
+<translation id="4638670630777875591">Chromium'daki Gizli mod</translation>
<translation id="464342062220857295">Özellik ara</translation>
<translation id="4644670975240021822">Ters sırada ön yüz aşağı bakacak şekilde</translation>
<translation id="4646534391647090355">Ä°ndirilenlere git</translation>
@@ -1166,6 +1202,7 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="4708268264240856090">Bağlantınız kesildi</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Windows Ağ Teşhislerini Çalıştırma<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426"><ph name="USERNAME" /> için şifre</translation>
<translation id="4724144314178270921">Panonuzdaki metin ve görselleri görmek isteyebilir</translation>
<translation id="4726672564094551039">Politikaları yeniden yükle</translation>
<translation id="4728558894243024398">Platform</translation>
@@ -1187,6 +1224,7 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="4757993714154412917">Az önce şifrenizi yanıltıcı bir sitede girdiniz. Chromium, hesaplarınızın güvenliğini sağlamak için kayıtlı şifrelerinizi kontrol etmenizi öneriyor.</translation>
<translation id="4758311279753947758">Ä°letiÅŸim bilgilerinizi ekleyin</translation>
<translation id="4761104368405085019">Mikrofonunuzu kullanma</translation>
+<translation id="4761869838909035636">Chrome Güvenlik Kontrolü Yürüt</translation>
<translation id="4764776831041365478"><ph name="URL" /> adresindeki web sayfası, geçici olarak kullanılamıyor veya kalıcı olarak yeni bir web adresine taşınmış olabilir.</translation>
<translation id="4766713847338118463">Altta ikili tel zımba</translation>
<translation id="4771973620359291008">Bilinmeyen bir hata oluÅŸtu.</translation>
@@ -1207,12 +1245,6 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="4819347708020428563">Ek açıklamalar varsayılan görünümde düzenlensin mi?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />, hızlıca yeni bir Google E-Tablosu oluşturmak için Sekme'ye, ardından Enter'a basın</translation>
<translation id="4825507807291741242">Güçlü</translation>
-<translation id="4827402517081186284">Gizli mod sizi internet ortamında görünmez hale getirmez:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Siteler, ne zaman ziyaret ettiÄŸinizi bilir<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Ä°ÅŸverenler veya okullar tarama etkinliÄŸini izleyebilir<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />İnternet Servis Sağlayıcıları web trafiğini izleyebilir<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">Uyarıları açın</translation>
<translation id="4838327282952368871">Hayalperest</translation>
<translation id="4840250757394056958">Chrome geçmişimi göster</translation>
@@ -1224,12 +1256,12 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="4854362297993841467">Bu teslimat yöntemi kullanılamıyor. Farklı bir yöntem deneyin.</translation>
<translation id="4854853140771946034">Google Keep'te hızlıca yeni bir not oluşturun</translation>
<translation id="485902285759009870">Kod doğrulanıyor...</translation>
+<translation id="4866506163384898554">İmlecinizi göstermek için |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| tuşlarına basın</translation>
<translation id="4876188919622883022">Basitleştirilmiş görünüm</translation>
<translation id="4876305945144899064">Kullanıcı adı yok</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{Yok}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831"><ph name="TEXT" /> araması</translation>
<translation id="4879491255372875719">Otomatik (varsayılan)</translation>
-<translation id="4879725228911483934">Ekranlarınızda pencereler açıp yerleştirme</translation>
<translation id="4880827082731008257">Geçmişte ara</translation>
<translation id="4881695831933465202">Aç</translation>
<translation id="4885256590493466218">Ödeme sırasında <ph name="CARD_DETAIL" /> ile ödeyin</translation>
@@ -1238,6 +1270,7 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">Dokuzuncu Rulo</translation>
<translation id="4901778704868714008">Kaydet...</translation>
+<translation id="4905659621780993806">Yöneticiniz cihazınızı <ph name="DATE" /> tarihinde saat <ph name="TIME" /> olunca otomatik olarak yeniden başlatacak. Cihazınız yeniden başlatılmadan önce tüm açık öğeleri kaydedin.</translation>
<translation id="4913987521957242411">Sol üstte delik</translation>
<translation id="4918221908152712722"><ph name="APP_NAME" /> uygulamasını yükleyin (indirmek gerekmez)</translation>
<translation id="4923459931733593730">Ödeme</translation>
@@ -1246,6 +1279,7 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, aramak için Sekme'ye, sonra Enter'a basın</translation>
<translation id="4930153903256238152">Yüksek kapasite</translation>
+<translation id="4940163644868678279">Chrome'daki Gizli mod</translation>
<translation id="4943872375798546930">Sonuç yok</translation>
<translation id="4950898438188848926">Sekme değiştirme düğmesi, açık sekmeye geçmek için enter tuşuna basın, <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="495170559598752135">Ä°ÅŸlemler</translation>
@@ -1255,6 +1289,7 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="4968522289500246572">Bu uygulama, mobil cihazlar için tasarlandığından düzgün bir şekilde yeniden boyutlandırılamayabilir. Uygulama sorun çıkarabilir veya yeniden başlatılabilir.</translation>
<translation id="4969341057194253438">Kaydı sil</translation>
<translation id="4973922308112707173">Ãœstte ikili delik</translation>
+<translation id="4976702386844183910">Son ziyaret tarihi: <ph name="DATE" /></translation>
<translation id="4984088539114770594">Mikrofon kullanılsın mı?</translation>
<translation id="4984339528288761049">Prc5 (Zarf)</translation>
<translation id="4989163558385430922">Tümünü göster</translation>
@@ -1316,6 +1351,7 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="5138227688689900538">Daha az göster</translation>
<translation id="5145883236150621069">Politika yanıtında hata kodu var</translation>
<translation id="5146995429444047494"><ph name="ORIGIN" /> için bildirimler engellendi</translation>
+<translation id="514704532284964975"><ph name="URL" />, telefonunuzla dokunduğunuz NFC cihazlardaki bilgileri görme ve değiştirme izni istiyor</translation>
<translation id="5148809049217731050">Yukarı dönük</translation>
<translation id="515292512908731282">C4 (Zarf)</translation>
<translation id="5158275234811857234">Kapak</translation>
@@ -1340,6 +1376,7 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="5215116848420601511">Google Pay'i kullanan ödeme yöntemleri ve adresler</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">Tepsi 13</translation>
+<translation id="5216942107514965959">En son bugün ziyaret edildi</translation>
<translation id="5222812217790122047">E-posta gerekli</translation>
<translation id="5230733896359313003">Gönderim Adresi</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1360,7 +1397,6 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">Doküman özellikleri</translation>
<translation id="528468243742722775">Son</translation>
-<translation id="5284909709419567258">AÄŸ adresleri</translation>
<translation id="5285570108065881030">Tüm kayıtlı şifreleri göster</translation>
<translation id="5287240709317226393">Çerezleri göster</translation>
<translation id="5287456746628258573">Bu site, eski bir güvenlik yapılandırması kullanıyor. Bu siteye gönderildiğinde bilgileriniz (ör. şifreler veya kredi kartı numaraları) gösterilebilir.</translation>
@@ -1444,6 +1480,7 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="5556459405103347317">Yeniden Yükle</translation>
<translation id="5560088892362098740">Son Kullanma Tarihi</translation>
<translation id="55635442646131152">Dokümanın ana hatları</translation>
+<translation id="5565613213060953222">Gizli sekme aç</translation>
<translation id="5565735124758917034">Etkin</translation>
<translation id="5570825185877910964">Hesabı koru</translation>
<translation id="5571083550517324815">Bu adresten alım yapılamıyor. Farklı bir adres seçin.</translation>
@@ -1526,6 +1563,7 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="5869522115854928033">Kayıtlı şifreler</translation>
<translation id="5873013647450402046">Bankanız kimliğinizi doğrulamak istiyor.</translation>
<translation id="5887400589839399685">Kart kaydedildi</translation>
+<translation id="5887687176710214216">En son dün ziyaret edildi</translation>
<translation id="5895138241574237353">Yeniden baÅŸlat</translation>
<translation id="5895187275912066135">VerildiÄŸi Tarih</translation>
<translation id="5901630391730855834">Sarı</translation>
@@ -1539,6 +1577,7 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="5921639886840618607">Kart Google Hesabı'na kaydedilsin mi?</translation>
<translation id="5922853866070715753">Tamamlanmak üzere</translation>
<translation id="5932224571077948991">Site, araya giren veya yanıltıcı reklamlar gösteriyor</translation>
+<translation id="5938153366081463283">Sanal kart ekleyin</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347"><ph name="SITE_NAME" /> açılıyor…</translation>
<translation id="5951495562196540101">Tüketici hesabına kaydedilemiyor (paket lisans mevcut).</translation>
@@ -1603,6 +1642,7 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="6120179357481664955">UPI ID'nizi hatırlıyor musunuz?</translation>
<translation id="6124432979022149706">Chrome Enterprise Connectors</translation>
<translation id="6127379762771434464">Öğe kaldırıldı</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Chrome'daki Gizli mod hakkında daha fazla bilgi<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">Kabloları kontrol edin ve kullandığınız yönlendiricileri, modemleri
veya diğer ağ cihazlarını yeniden başlatın.</translation>
<translation id="614940544461990577">Aşağıdakileri deneyin:</translation>
@@ -1615,7 +1655,6 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="6169916984152623906">Artık gizli olarak göz atabilirsiniz ve bu cihazı kullanan diğer kişiler etkinliğinizi görmez. Yine de indirdikleriniz ve yer işaretleri kaydedilir.</translation>
<translation id="6177128806592000436">Bu siteye bağlantınız güvenli değil</translation>
<translation id="6180316780098470077">Deneme aralığı</translation>
-<translation id="619448280891863779">Ekranlarınızda pencereler açıp yerleştirmek isteyebilir</translation>
<translation id="6196640612572343990">Üçüncü taraf çerezlerini engelle</translation>
<translation id="6203231073485539293">İnternet bağlantınızı kontrol edin</translation>
<translation id="6218753634732582820">Adres Chromium'dan kaldırılsın mı?</translation>
@@ -1638,7 +1677,7 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="6272383483618007430">Google Güncelleme</translation>
<translation id="6276112860590028508">Okuma listenize ait sayfalar burada görünür</translation>
<translation id="627746635834430766">Bir dahaki sefere daha hızlı ödeme yapmak için kartınızı ve fatura adresinizi Google Hesabınıza kaydedin.</translation>
-<translation id="6279098320682980337">Sanal kart numarası doldurulmadı mı? Kopyalamak için kart detaylarını tıklayın</translation>
+<translation id="6279183038361895380">İmlecinizi göstermek için |<ph name="ACCELERATOR" />| tuşuna basın</translation>
<translation id="6280223929691119688">Bu adrese teslimat yapılamıyor. Farklı bir adres seçin.</translation>
<translation id="6282194474023008486">Posta kodu</translation>
<translation id="6285507000506177184">Chrome'da indirilenleri yönetin düğmesi. Chrome'da indirdiğiniz dosyaları yönetmek için Enter'a basın</translation>
@@ -1646,6 +1685,7 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="6290238015253830360">Önerilen makaleler burada görünür</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{Cihazınız şimdi yeniden başlatılacak}=1{Cihazınız 1 saniye içinde yeniden başlatılacak}other{Cihazınız # saniye içinde yeniden başlatılacak}}</translation>
<translation id="6302269476990306341">Chrome'da Google Asistan durduruluyor</translation>
<translation id="6305205051461490394"><ph name="URL" /> adresine ulaşılamıyor.</translation>
<translation id="6312113039770857350">Web sayfası mevcut değil</translation>
@@ -1719,6 +1759,7 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="6529602333819889595">Silmeyi &amp;Yeniden Yap</translation>
<translation id="6545864417968258051">Bluetooth taraması</translation>
<translation id="6547208576736763147">Solda ikili delik</translation>
+<translation id="6554732001434021288">En son <ph name="NUM_DAYS" /> gün önce ziyaret edildi</translation>
<translation id="6556866813142980365">Yeniden Yap</translation>
<translation id="6569060085658103619">Bir uzantı sayfası görüntülüyorsunuz</translation>
<translation id="6573200754375280815">SaÄŸda ikili delik</translation>
@@ -1779,7 +1820,6 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="6757797048963528358">Cihazınız uyku moduna geçti.</translation>
<translation id="6767985426384634228">Adres Güncellensin mi?</translation>
<translation id="6768213884286397650">Hagaki (Kartpostal)</translation>
-<translation id="6774185088257932239">Gizli mod hakkında <ph name="BEGIN_LINK" />daha fazla bilgi<ph name="END_LINK" /></translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">Mor</translation>
<translation id="6786747875388722282">Uzantılar</translation>
@@ -1863,7 +1903,6 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="706295145388601875">Chrome ayarlarında adres ekleyip yönetin</translation>
<translation id="7064851114919012435">Ä°letiÅŸim bilgileri</translation>
<translation id="7068733155164172741"><ph name="OTP_LENGTH" /> haneli kodu girin</translation>
-<translation id="7070090581017165256">Bu site hakkında</translation>
<translation id="70705239631109039">Bağlantınız tam olarak güvenli değil</translation>
<translation id="7075452647191940183">İstek çok büyük</translation>
<translation id="7079718277001814089">Bu site kötü amaçlı yazılım içeriyor</translation>
@@ -1880,6 +1919,12 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="7111012039238467737">(Geçerli)</translation>
<translation id="7118618213916969306">Panoda URL'yi (<ph name="SHORT_URL" />) ara</translation>
<translation id="7119414471315195487">Diğer sekmeleri veya programları kapatın</translation>
+<translation id="7129355289156517987">Tüm Chromium gizli sekmelerini kapattığınızda bu sekmelerde bulunan aşağıdaki etkinlikleriniz cihazdan temizlenir:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Tarama etkinliÄŸi<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Arama geçmişi<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Formlara girilen bilgiler<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">Bu adrese gönderim yapılamıyor. Farklı bir adres seçin.</translation>
<translation id="7132939140423847331">Yöneticiniz bu verilerin kopyalanmasını engellemiş.</translation>
<translation id="7135130955892390533">Durumu göster</translation>
@@ -1902,6 +1947,7 @@ Aksi halde bu işlem gizlilik ayarlarınız tarafından engellenecek. Buna izin
<translation id="7192203810768312527"><ph name="SIZE" /> yer açar. Bir sonraki ziyaretinizde bazı siteler daha yavaş yüklenebilir.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">Yöneticiniz şunları görebilir:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, yeni bir gizli sekme açıp gizli olarak göz atmak için Sekme tuşuna, sonra Enter'a basın</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> güvenlik standartlarına uymuyor.</translation>
<translation id="7210993021468939304">Yönetici kapsayıcı içindeki Linux etkinliğini görebilir ve kapsayıcı içindeki Linux uygulamalarını yükleyip çalıştırabilir</translation>
@@ -1933,6 +1979,7 @@ Ek ayrıntılar:
<translation id="7304562222803846232">Google Hesabı gizlilik ayarlarını yönet</translation>
<translation id="7305756307268530424">Daha yavaÅŸ baÅŸlat</translation>
<translation id="7308436126008021607">arka plan senkronizasyonu</translation>
+<translation id="7310392214323165548">Cihaz çok yakında yeniden başlatılacak</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">Bağlantı Yardımı</translation>
<translation id="7323804146520582233">"<ph name="SECTION" />" bölümünü gizle</translation>
@@ -1940,6 +1987,7 @@ Ek ayrıntılar:
<translation id="7334320624316649418">Sıralama değişikliğini &amp;yeniden yap</translation>
<translation id="7335157162773372339">Kameranızı kullanmak isteyebilir</translation>
<translation id="7337248890521463931">Daha fazla satır göster</translation>
+<translation id="7337418456231055214">Sanal kart numarası doldurulmadı mı? Kopyalamak için kart detaylarını tıklayın. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">Platformunuzda kullanılamıyor.</translation>
<translation id="733923710415886693">Sunucunun sertifikası, Sertifika Şeffaflığı aracılığıyla açıklanmadı.</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1962,6 +2010,7 @@ Ek ayrıntılar:
<translation id="7378627244592794276">Hayır</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">Geçerli değil</translation>
+<translation id="7388594495505979117">{0,plural, =1{Cihazınız 1 dakika içinde yeniden başlatılacak}other{Cihazınız # dakika içinde yeniden başlatılacak}}</translation>
<translation id="7390545607259442187">Kartı Onayla</translation>
<translation id="7392089738299859607">Adresi Güncelle</translation>
<translation id="7399802613464275309">Güvenlik Kontrolü</translation>
@@ -1998,6 +2047,12 @@ Ek ayrıntılar:
<translation id="7485870689360869515">Hiçbir veri bulunamadı.</translation>
<translation id="7495528107193238112">Bu içerik engellenmiştir. Sorunu gidermek için site sahibiyle iletişime geçin.</translation>
<translation id="7497998058912824456">Doküman oluştur düğmesi, hızlıca yeni bir Google Dokümanı oluşturmak için Enter'a basın</translation>
+<translation id="7506488012654002225">Chromium aşağıdaki bilgileri <ph name="BEGIN_EMPHASIS" />kaydetmez<ph name="END_EMPHASIS" />:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Tarama geçmişiniz
+ <ph name="LIST_ITEM" />Çerezler ve site verileri
+ <ph name="LIST_ITEM" />Formlara girilen bilgiler
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">Döndürülen politika cihaz kimliği boş veya mevcut cihaz kimliğiyle eşleşmiyor</translation>
<translation id="7508870219247277067">Avokado YeÅŸili</translation>
<translation id="7511955381719512146">Kullandığınız kablosuz bağlantı ağı, <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> adresini ziyaret etmenizi gerektiriyor olabilir.</translation>
@@ -2111,7 +2166,6 @@ Ek ayrıntılar:
<translation id="7813600968533626083">Form önerisi Chrome'dan kaldırılsın mı?</translation>
<translation id="781440967107097262">Pano paylaşılsın mı?</translation>
<translation id="7815407501681723534">"<ph name="SEARCH_STRING" />" için <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> bulundu.</translation>
-<translation id="782125616001965242">Bu site hakkındaki bilgileri göster</translation>
<translation id="782886543891417279">Kullandığınız kablosuz bağlantı ağı (<ph name="WIFI_NAME" />) giriş sayfasını ziyaret etmenizi gerektiriyor olabilir.</translation>
<translation id="7836231406687464395">Postfix (Zarf)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{Yok}=1{1 uygulama (<ph name="EXAMPLE_APP_1" />)}=2{2 uygulama (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}other{# uygulama (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}}</translation>
@@ -2128,7 +2182,6 @@ Ek ayrıntılar:
<translation id="7888575728750733395">Baskı oluşturma amacı</translation>
<translation id="7894280532028510793">Yazım doğruysa <ph name="BEGIN_LINK" />Ağ Teşhisi'ni çalıştırmayı deneyin<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (Zarf)</translation>
-<translation id="7931318309563332511">Bilinmiyor</translation>
<translation id="793209273132572360">Adres güncellensin mi?</translation>
<translation id="7932579305932748336">Kaplama</translation>
<translation id="79338296614623784">Geçerli bir telefon numarası girin</translation>
@@ -2153,13 +2206,14 @@ Ek ayrıntılar:
<translation id="7976214039405368314">Çok fazla istek var</translation>
<translation id="7977538094055660992">Çıkış cihazı</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">Şununla bağlantı oluşturuldu:</translation>
<translation id="798134797138789862">Sanal gerçeklik cihazlarını ve verilerini kullanmak isteyebilir</translation>
<translation id="7984945080620862648"><ph name="SITE" /> web sitesi Chrome'un işleyemediği karışık kimlik bilgileri gönderdiği için web sitesini şu anda ziyaret edemezsiniz. Ağ hataları ve saldırılar genellikle geçici olduğundan bu sayfa muhtemelen daha sonra çalışacaktır.</translation>
-<translation id="79859296434321399">Artırılmış gerçeklik içeriğini görüntülemek için ARCore'u yükleyin</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">BaÄŸlama</translation>
<translation id="7992044431894087211"><ph name="APPLICATION_TITLE" /> ile ekran paylaşımı devam ettirildi</translation>
<translation id="7995512525968007366">Belirtilmedi</translation>
+<translation id="7998269595945679889">Gizli sekme aç düğmesi: Yeni gizli pencere açıp gizli olarak göz atmak için Enter tuşuna basın</translation>
<translation id="800218591365569300">Bellekte yer açmak için diğer sekmeleri veya programları kapatmayı deneyin.</translation>
<translation id="8004582292198964060">Tarayıcı</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{Aşağıdaki kart ve ona ait fatura adresi kaydedilecektir. Kaydettiğiniz kartı <ph name="USER_EMAIL" /> hesabında oturumunuz açıkken kullanabilirsiniz.}other{Aşağıdaki kartlar ve onlara ait fatura adresleri kaydedilecektir. Kaydettiğiniz kartları <ph name="USER_EMAIL" /> hesabında oturumunuz açıkken kullanabilirsiniz.}}</translation>
@@ -2219,6 +2273,7 @@ Ek ayrıntılar:
<translation id="8202370299023114387">Çakışma</translation>
<translation id="8206978196348664717">Prc4 (Zarf)</translation>
<translation id="8211406090763984747">Bağlantı güvenli</translation>
+<translation id="8217240300496046857">Siteler sizi web'de takip eden çerezler kullanamaz. Bazı sitelerdeki özellikler düzgün çalışmayabilir.</translation>
<translation id="8218327578424803826">Atanan Konum:</translation>
<translation id="8220146938470311105">C7/C6 (Zarf)</translation>
<translation id="8225771182978767009">Bu bilgisayarı kuran kişi bu siteyi engellemeyi seçmiş.</translation>
@@ -2259,14 +2314,9 @@ Ek ayrıntılar:
<translation id="830498451218851433">Ortadan katlama</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">Yüklü uygulamalar ve ne sıklıkla kullanıldıkları</translation>
+<translation id="8317207217658302555">ARCore güncellensin mi?</translation>
<translation id="831997045666694187">AkÅŸam</translation>
<translation id="8321476692217554900">bildirimler</translation>
-<translation id="8328484624016508118">Tüm gizli sekmeler kapatıldıktan sonra Chrome şunları temizler:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Bu cihazdaki tarama etkinliÄŸiniz<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Bu cihazdaki arama geçmişiniz<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Formlara girilen bilgiler<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489"><ph name="HOST_NAME" /> ana makinesine eriÅŸim reddedildi</translation>
<translation id="833262891116910667">Vurgula</translation>
<translation id="8339163506404995330"><ph name="LANGUAGE" /> dilindeki sayfalar çevrilmeyecek</translation>
@@ -2318,6 +2368,7 @@ Ek ayrıntılar:
<translation id="8507227106804027148">Komut satırı</translation>
<translation id="8508648098325802031">Arama simgesi</translation>
<translation id="8511402995811232419">Çerezleri yönet</translation>
+<translation id="8519753333133776369">Yöneticiniz tarafından HID cihazlara izin verilmiştir</translation>
<translation id="8522552481199248698">Chrome, Google Hesabınızı korumanıza ve şifrenizi değiştirmenize yardımcı olabilir.</translation>
<translation id="8530813470445476232">Chrome ayarlarında tarama geçmişinizi, çerezleri, önbelleği ve diğer öğeleri temizleyin</translation>
<translation id="8533619373899488139">Engellenen URL'lerin ve sistem yöneticinizin zorunlu tuttuğu diğer politikaların listesini görmek için &lt;strong&gt;chrome://policy&lt;/strong&gt; adresini ziyaret edin.</translation>
@@ -2329,7 +2380,6 @@ Ek ayrıntılar:
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{İzni sıfırla}other{İzinleri sıfırla}}</translation>
<translation id="8555010941760982128">Ödeme sırasında bu kodu kullanın</translation>
<translation id="8557066899867184262">CVC, kartınızın arkasında bulunur.</translation>
-<translation id="8558485628462305855">Artırılmış gerçeklik içeriğini görüntülemek için ARCore'u güncelleyin</translation>
<translation id="8559762987265718583">Cihazınızın tarih ve saati (<ph name="DATE_AND_TIME" />) yanlış olduğundan <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> alan adına gizli bir bağlantı kurulamıyor.</translation>
<translation id="8564182942834072828">Ayrı dokümanlar/Harmanlanmamış kopyalar</translation>
<translation id="8564985650692024650">Chromium, <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> şifrenizi başka sitelerde kullandıysanız sıfırlamanızı önerir.</translation>
@@ -2349,6 +2399,7 @@ Ek ayrıntılar:
<translation id="865032292777205197">hareket sensörleri</translation>
<translation id="8663226718884576429">Sipariş Özeti, <ph name="TOTAL_LABEL" />, Daha Fazla Ayrıntı</translation>
<translation id="8666678546361132282">Ä°ngilizce</translation>
+<translation id="8669306706049782872">Pencere açıp yerleştirmek için ekranlarınızla ilgili bilgileri kullanma</translation>
<translation id="867224526087042813">Ä°mza</translation>
<translation id="8676424191133491403">Gecikme yok</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, yanıt, <ph name="ANSWER" /></translation>
@@ -2375,6 +2426,7 @@ Ek ayrıntılar:
<translation id="8731544501227493793">Şifreleri yönet düğmesi, Chrome ayarlarında şifrelerinizi görüp yönetmek için Enter'a basın</translation>
<translation id="8734529307927223492"><ph name="DEVICE_TYPE" /> cihazınız <ph name="MANAGER" /> tarafından yönetiliyor</translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, yeni bir Gizli pencere açıp gizli olarak göz atmak için Sekme'ye, sonra Enter'a basın</translation>
+<translation id="8737685506611670901"><ph name="REPLACED_HANDLER_TITLE" /> yerine <ph name="PROTOCOL" /> bağlantılarını açma</translation>
<translation id="8738058698779197622">Güvenli bir bağlantı kurmak için saatinizin doğru ayarlanmış olması gerekir. Bunun sebebi, web sitelerinin kendilerini tanımlamak için kullandıkları sertifikaların sadece belli süreler için geçerli olmasıdır. Cihazınızın saati yanlış olduğundan, Chromium bu sertifikaları doğrulayamaz.</translation>
<translation id="8740359287975076522"><ph name="HOST_NAME" /> ana makinesinin &lt;abbr id="dnsDefinition"&gt;DNS adresi&lt;/abbr&gt; bulunamadı. Sorun teşhis ediliyor.</translation>
<translation id="8742371904523228557"><ph name="ORIGIN" /> için kodunuz: <ph name="ONE_TIME_CODE" /></translation>
@@ -2402,6 +2454,7 @@ Ek ayrıntılar:
<translation id="883848425547221593">DiÄŸer Yer Ä°ÅŸaretleri</translation>
<translation id="884264119367021077">Gönderim adresi</translation>
<translation id="884923133447025588">İptal mekanizması bulunamadı.</translation>
+<translation id="8849262850971482943">Güvenliği artırmak için sanal kartınızı kullanın</translation>
<translation id="885730110891505394">Google ile PaylaÅŸma</translation>
<translation id="8858065207712248076">Chrome, <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> şifrenizi başka sitelerde kullandıysanız sıfırlamanızı önerir.</translation>
<translation id="885906927438988819">Yazım doğruysa <ph name="BEGIN_LINK" />Windows Ağ Teşhisi'ni çalıştırmayı deneyin<ph name="END_LINK" />.</translation>
@@ -2451,6 +2504,7 @@ Ek ayrıntılar:
<translation id="9004367719664099443">VR oturumu devam ediyor</translation>
<translation id="9005998258318286617">PDF dokümanı yüklenemedi.</translation>
<translation id="9008201768610948239">Yoksay</translation>
+<translation id="901834265349196618">e-posta</translation>
<translation id="9020200922353704812">Kartın fatura adresi gerekli</translation>
<translation id="9020542370529661692">Bu sayfa <ph name="TARGET_LANGUAGE" /> diline çevrildi</translation>
<translation id="9020742383383852663">A8</translation>
@@ -2499,6 +2553,7 @@ Ek ayrıntılar:
<translation id="9150045010208374699">Kameranızı kullanma</translation>
<translation id="9150685862434908345">Yöneticiniz, tarayıcınızın kurulumunu uzaktan değiştirebilir. Bu cihazdaki etkinlikler Chrome dışında da yönetilebilir. <ph name="BEGIN_LINK" />Daha fazla bilgi<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">Güncellendi</translation>
+<translation id="9155211586651734179">Takılı durumdaki ses çevre birimleri</translation>
<translation id="9157595877708044936">Ayarlanıyor...</translation>
<translation id="9158625974267017556">C6 (Zarf)</translation>
<translation id="9164029392738894042">Doğruluk Kontrolü</translation>
diff --git a/chromium/components/strings/components_strings_uk.xtb b/chromium/components/strings/components_strings_uk.xtb
index 18c35e7c9df..0bd8509689a 100644
--- a/chromium/components/strings/components_strings_uk.xtb
+++ b/chromium/components/strings/components_strings_uk.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">Докладніше</translation>
<translation id="1030706264415084469">Сайт <ph name="URL" /> хоче поÑтійно зберігати великий обÑÑг даних на вашому приÑтрої</translation>
<translation id="1032854598605920125">Обернути за годинниковою Ñтрілкою</translation>
+<translation id="1033329911862281889">Ð’ анонімному режимі ваші дії в Інтернеті не Ñтають невидимими:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Ñайти та ÑервіÑи, Ñкими вони кориÑтуютьÑÑ, бачать інформацію про ваші відвідуваннÑ;<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />роботодавці та заклади оÑвіти можуть відÑтежувати ваші дії у веб-переглÑдачі;<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />поÑтачальники поÑлуг Інтернету (ISP) можуть відÑтежувати веб-трафік.<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">Вимкнути</translation>
<translation id="1036982837258183574">ÐатиÑніть |<ph name="ACCELERATOR" />|, щоб вийти з повноекранного режиму</translation>
<translation id="1038106730571050514">Показувати пропозиції</translation>
<translation id="1038842779957582377">Ðевідоме ім’Ñ</translation>
<translation id="1041998700806130099">ÐŸÐ¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð½Ð° аркуші вихідних даних</translation>
<translation id="1048785276086539861">Коли ви редагуєте примітки, документ переходить у режим переглÑду по одній Ñторінці</translation>
-<translation id="1049743911850919806">Ðнонімний переглÑд</translation>
<translation id="1050038467049342496">Закрийте інші додатки</translation>
<translation id="1055184225775184556">&amp;Відмінити додаваннÑ</translation>
<translation id="1056898198331236512">ЗаÑтереженнÑ</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">Кеш-пам’ÑÑ‚ÑŒ правила не пошкоджено</translation>
<translation id="1130564665089811311">Кнопка "ПереклаÑти Ñторінку"; натиÑніть Enter, що переклаÑти цю Ñторінку в Google Перекладачі</translation>
<translation id="1131264053432022307">Скопійоване зображеннÑ</translation>
+<translation id="1142846828089312304">Блокувати файли cookie третіх Ñторін в анонімному режимі</translation>
<translation id="1150979032973867961">Цей Ñервер не зміг довеÑти, що він – домен <ph name="DOMAIN" />. Операційна ÑиÑтема вашого комп’ютера не вважає його Ñертифікат безпеки надійним. Імовірні причини: неправильна ÐºÐ¾Ð½Ñ„Ñ–Ð³ÑƒÑ€Ð°Ñ†Ñ–Ñ Ð°Ð±Ð¾ хтоÑÑŒ намагаєтьÑÑ Ð¿ÐµÑ€ÐµÑ…Ð¾Ð¿Ð¸Ñ‚Ð¸ ваше з’єднаннÑ.</translation>
<translation id="1151972924205500581">Потрібен пароль</translation>
<translation id="1156303062776767266">Ви переглÑдаєте локальний або Ñпільний файл</translation>
@@ -64,7 +70,6 @@
<translation id="1178581264944972037">Пауза</translation>
<translation id="1181037720776840403">Видалити</translation>
<translation id="1186201132766001848">Перевірити паролі</translation>
-<translation id="1195210374336998651">Перейдіть у Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð¾Ð´Ð°Ñ‚ÐºÐ°</translation>
<translation id="1195558154361252544">Ð¡Ð¿Ð¾Ð²Ñ–Ñ‰ÐµÐ½Ð½Ñ Ð°Ð²Ñ‚Ð¾Ð¼Ð°Ñ‚Ð¸Ñ‡Ð½Ð¾ заблоковано Ð´Ð»Ñ Ð²ÑÑ–Ñ… Ñайтів, крім тих, Ñкі ви дозволили</translation>
<translation id="1197088940767939838">Оранжевий</translation>
<translation id="1201402288615127009">Далі</translation>
@@ -111,7 +116,7 @@
<translation id="1307966114820526988">Функції не підтримуютьÑÑ</translation>
<translation id="1308113895091915999">ДоÑтупна пропозиціÑ</translation>
<translation id="1312803275555673949">Які є докази?</translation>
-<translation id="131405271941274527">Сайт <ph name="URL" /> хоче обмінюватиÑÑ Ð´Ð°Ð½Ð¸Ð¼Ð¸ з телефоном через NFC</translation>
+<translation id="1314311879718644478">ПереглÑньте контент у режимі доповненої реальноÑÑ‚Ñ–</translation>
<translation id="1314509827145471431">Зшити праворуч</translation>
<translation id="1318023360584041678">Збережено в групі вкладок</translation>
<translation id="1319245136674974084">Ðе запитувати знову Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ додатка</translation>
@@ -161,7 +166,8 @@
<translation id="142858679511221695">КориÑтувач Google Cloud</translation>
<translation id="1428729058023778569">Ви бачите це попередженнÑ, оÑкільки цей Ñайт не підтримує HTTPS. <ph name="BEGIN_LEARN_MORE_LINK" />Докладніше<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">Друк</translation>
-<translation id="1432581352905426595">ÐšÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ð¾ÑˆÑƒÐºÐ¾Ð²Ð¸Ð¼Ð¸ ÑиÑтемами</translation>
+<translation id="1432187715652018471">Ñторінка хоче вÑтановити обробник ÑервіÑів.</translation>
+<translation id="1432581352905426595">Керувати пошуковими ÑиÑтемами</translation>
<translation id="1436185428532214179">Може проÑити дозвіл змінювати файли та папки на приÑтрої</translation>
<translation id="1442386063175183758">Зігнути за типом "ворота праворуч"</translation>
<translation id="1442987760062738829">Пробити отвір</translation>
@@ -181,6 +187,12 @@
<translation id="1483493594462132177">ÐадіÑлати</translation>
<translation id="1484290072879560759">Вибрати адреÑу доÑтавки</translation>
<translation id="1492194039220927094">Ð¡Ð¿Ð¾Ð²Ñ–Ñ‰ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾ правила:</translation>
+<translation id="149293076951187737">Коли ви закриваєте вÑÑ– анонімні вкладки в Chrome, з приÑтрою видалÑÑŽÑ‚ÑŒÑÑ Ð´Ð°Ð½Ñ– про ваші дії в них, зокрема:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />дії у веб-переглÑдачі;<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Ñ–Ñторію пошуку;<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />інформацію, Ñку ви вводите у формах.<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">Ðазад на вкладку</translation>
<translation id="1501859676467574491">Показує картки з облікового запиÑу Google</translation>
<translation id="1507202001669085618">&lt;p&gt;Це Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾ помилку з’ÑвлÑєтьÑÑ, Ñкщо ви кориÑтуєтеÑÑ Ð¿Ð¾Ñ€Ñ‚Ð°Ð»Ð¾Ð¼ Wi-Fi, на Ñкий потрібно ввійти, перш ніж підключитиÑÑ Ð´Ð¾ мережі.&lt;/p&gt;
@@ -208,6 +220,8 @@
<translation id="1559572115229829303">&lt;p&gt;Ðе вдаєтьÑÑ Ð²Ñтановити конфіденційне Ð·â€™Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ñ–Ð· Ñайтом <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />, оÑкільки на вашому приÑтрої неправильно налаштовано дату й Ñ‡Ð°Ñ (<ph name="DATE_AND_TIME" />).&lt;/p&gt;
&lt;p&gt;Ðалаштуйте дату й Ñ‡Ð°Ñ Ñƒ розділі &lt;strong&gt;Загальні&lt;/strong&gt; додатка &lt;strong&gt;ÐалаштуваннÑ&lt;/strong&gt;.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">ÐдмініÑтратор перезапуÑтить приÑтрій <ph name="DATE" /> о <ph name="TIME" /></translation>
+<translation id="156703335097561114">Ð†Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ñ–Ñ Ð¿Ñ€Ð¾ мережу, наприклад адреÑи, конфігурацію інтерфейÑу та ÑкіÑÑ‚ÑŒ з’єднаннÑ</translation>
<translation id="1567040042588613346">Це правило працює належним чином, але в іншому міÑці вÑтановлюєтьÑÑ Ñ‚Ð°ÐºÐµ ж Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð¹ замінюєтьÑÑ Ñ†Ð¸Ð¼ правилом.</translation>
<translation id="1569487616857761740">Введіть дату Ð·Ð°ÐºÑ–Ð½Ñ‡ÐµÐ½Ð½Ñ Ñ‚ÐµÑ€Ð¼Ñ–Ð½Ñƒ дії</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@
<translation id="1583429793053364125">Під Ñ‡Ð°Ñ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ð½Ñ Ñ†Ñ–Ñ”Ñ— Ñторінки ÑталаÑÑ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ°.</translation>
<translation id="1586541204584340881">вÑтановлені розширеннÑ;</translation>
<translation id="1588438908519853928">Звичайний</translation>
+<translation id="1589050138437146318">УÑтановити ARCore?</translation>
<translation id="1592005682883173041">ДоÑтуп до локальних даних</translation>
<translation id="1594030484168838125">Вибрати</translation>
<translation id="160851722280695521">Грайте в гру Dino Run у Chrome</translation>
@@ -283,6 +298,7 @@
Ñтруктура заголовка неправильна, тому веб-переглÑдач не може виконати
ваш запит Ð´Ð»Ñ Ñайту <ph name="SITE" />. Оператори можуть викориÑтовувати
правило джерела, щоб налаштувати захиÑÑ‚ та інші реÑурÑи Ñайту.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Докладніше про анонімний режим у Chromium<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">Тут відображатимутьÑÑ Ð²Ð°ÑˆÑ– відкриті вкладки</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -410,6 +426,7 @@
<translation id="22081806969704220">Лоток 3</translation>
<translation id="2212735316055980242">Правило не знайдено</translation>
<translation id="2213606439339815911">ÐžÑ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñів…</translation>
+<translation id="2213612003795704869">Сторінку надруковано</translation>
<translation id="2215727959747642672">Ð ÐµÐ´Ð°Ð³ÑƒÐ²Ð°Ð½Ð½Ñ Ñ„Ð°Ð¹Ð»Ñƒ</translation>
<translation id="2218879909401188352">ЗловмиÑники можуть викориÑтати Ñайт <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />, щоб уÑтановити небезпечні додатки, Ñкі шкодÑÑ‚ÑŒ приÑтроÑм, наприклад, додають приховані платежі за мобільний зв’Ñзок або викрадають оÑобиÑту інформацію. <ph name="BEGIN_LEARN_MORE_LINK" />Докладніше<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">Ðемає Інтернету</translation>
@@ -419,6 +436,7 @@
<translation id="2248949050832152960">ВикориÑтовувати веб-автентифікацію</translation>
<translation id="2250931979407627383">Зшити вздовж лівого краю</translation>
<translation id="225207911366869382">Дію цього Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¸Ð¿Ð¸Ð½ÐµÐ½Ð¾ Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ правила</translation>
+<translation id="2256115617011615191">ПерезапуÑтити</translation>
<translation id="2258928405015593961">Введіть майбутню дату Ð·Ð°ÐºÑ–Ð½Ñ‡ÐµÐ½Ð½Ñ Ñ‚ÐµÑ€Ð¼Ñ–Ð½Ñƒ дії та повторіть Ñпробу</translation>
<translation id="225943865679747347">Код помилки: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">Помилка HTTP</translation>
@@ -446,6 +464,7 @@
<translation id="2337852623177822836">ÐалаштуваннÑм керує ваш адмініÑтратор</translation>
<translation id="2340263603246777781">Сайт <ph name="ORIGIN" /> хоче підключитиÑÑ Ð´Ð¾ приÑтрою</translation>
<translation id="2346319942568447007">Скопійоване зображеннÑ</translation>
+<translation id="2350796302381711542">Дозволити обробнику <ph name="HANDLER_HOSTNAME" /> відкривати вÑÑ– поÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¾Ñ‚Ð¾ÐºÐ¾Ð»Ñƒ <ph name="PROTOCOL" /> заміÑÑ‚ÑŒ обробника <ph name="REPLACED_HANDLER_TITLE" />?</translation>
<translation id="2354001756790975382">Інші закладки</translation>
<translation id="2354430244986887761">Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ Ð±ÐµÐ·Ð¿ÐµÑ‡Ð½Ð¾Ð³Ð¾ переглÑду від Google нещодавно <ph name="BEGIN_LINK" />виÑвила шкідливі додатки<ph name="END_LINK" /> на Ñайті <ph name="SITE" />.</translation>
<translation id="2355395290879513365">ЗловмиÑники можуть бачити зображеннÑ, Ñкі ви переглÑдаєте на цьому Ñайті, Ñ– змінювати Ñ—Ñ… із метою ошукати ваÑ.</translation>
@@ -471,6 +490,7 @@
<translation id="2413528052993050574">Цей Ñервер не зміг довеÑти, що він – домен <ph name="DOMAIN" />. Можливо, його Ñертифікат безпеки відкликано. Імовірні причини: неправильна ÐºÐ¾Ð½Ñ„Ñ–Ð³ÑƒÑ€Ð°Ñ†Ñ–Ñ Ð°Ð±Ð¾ хтоÑÑŒ намагаєтьÑÑ Ð¿ÐµÑ€ÐµÑ…Ð¾Ð¿Ð¸Ñ‚Ð¸ ваше з’єднаннÑ.</translation>
<translation id="2414886740292270097">Темна</translation>
<translation id="2430968933669123598">"Керувати обліковим запиÑом Google"; натиÑніть Enter, щоб керувати Ñвоєю інформацією, конфіденційніÑÑ‚ÑŽ й безпекою в обліковому запиÑÑ– Google</translation>
+<translation id="2436186046335138073">Дозволити обробнику <ph name="HANDLER_HOSTNAME" /> відкривати вÑÑ– поÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¾Ñ‚Ð¾ÐºÐ¾Ð»Ñƒ <ph name="PROTOCOL" />?</translation>
<translation id="2438874542388153331">Пробити чотири отвори праворуч</translation>
<translation id="2450021089947420533">СеанÑи</translation>
<translation id="2463739503403862330">Заповнити</translation>
@@ -478,6 +498,7 @@
<translation id="2465655957518002998">Вибрати ÑпоÑіб доÑтавки</translation>
<translation id="2465688316154986572">Скріпити</translation>
<translation id="2465914000209955735">Керувати завантаженими файлами в Chrome</translation>
+<translation id="2466004615675155314">Показати інформацію з Інтернету</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />провеÑти діагноÑтику мережі<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">ПорÑдок від 1 до N</translation>
<translation id="2470767536994572628">Коли ви редагуєте примітки, документ переходить у режим переглÑду по одній Ñторінці, а також відновлюєтьÑÑ Ð¹Ð¾Ð³Ð¾ початкова орієнтаціÑ</translation>
@@ -498,6 +519,7 @@
<translation id="2523886232349826891">Збережено лише на цьому приÑтрої</translation>
<translation id="2524461107774643265">Додайте більше інформації</translation>
<translation id="2529899080962247600">МакÑимальна кількіÑÑ‚ÑŒ запиÑів у цьому полі: <ph name="MAX_ITEMS_LIMIT" />. УÑÑ– подальші запиÑи ігноруватимутьÑÑ.</translation>
+<translation id="2535585790302968248">Відкрийте нову анонімну вкладку</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{і ще 1}one{і ще #}few{і ще #}many{і ще #}other{і ще #}}</translation>
<translation id="2536110899380797252">Додати адреÑу</translation>
<translation id="2539524384386349900">Визначити</translation>
@@ -523,7 +545,14 @@
<translation id="2597378329261239068">Цей документ захищено паролем. Введіть пароль.</translation>
<translation id="2609632851001447353">Різновиди</translation>
<translation id="2610561535971892504">ÐатиÑнути, щоб Ñкопіювати</translation>
+<translation id="2617988307566202237">Chrome <ph name="BEGIN_EMPHASIS" />не зберігатиме<ph name="END_EMPHASIS" />:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Ñ–Ñторію веб-переглÑду;
+ <ph name="LIST_ITEM" />файли cookie та дані із Ñайтів
+ <ph name="LIST_ITEM" />інформацію, Ñку ви вводите у формах.
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (конверт)</translation>
+<translation id="2623663032199728144">Може проÑити доÑтуп до інформації про ваші екрани</translation>
<translation id="2625385379895617796">Ваш годинник Ñпішить</translation>
<translation id="262745152991669301">Може проÑити дозвіл підключатиÑÑ Ð´Ð¾ приÑтроїв USB</translation>
<translation id="2629325967560697240">Щоб веб-переглÑдач Chrome був макÑимально безпечним, <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />увімкніть покращений захиÑÑ‚<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -557,6 +586,7 @@
<translation id="2709516037105925701">ÐвтозаповненнÑ</translation>
<translation id="2713444072780614174">Білий</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />; натиÑніть Tab, а потім – Enter, щоб керувати платежами й даними кредитної картки в налаштуваннÑÑ… Chrome</translation>
+<translation id="271663710482723385">ÐатиÑніть |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />|, щоб вийти з повноекранного режиму</translation>
<translation id="2721148159707890343">Запит надіÑлано</translation>
<translation id="2723669454293168317">Виконайте перевірку безпеки в налаштуваннÑÑ… Chrome</translation>
<translation id="2726001110728089263">Боковий лоток</translation>
@@ -587,6 +617,7 @@
<translation id="2850739647070081192">Invite (конверт)</translation>
<translation id="2856444702002559011">ЗловмиÑники можуть намагатиÑÑ Ð²Ð¸ÐºÑ€Ð°Ñти вашу інформацію із Ñайту <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (наприклад, паролі, Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ñ‡Ð¸ дані кредитних карток). <ph name="BEGIN_LEARN_MORE_LINK" />Докладніше<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">Цей Ñайт показує нав’Ñзливі чи оманливі оголошеннÑ.</translation>
+<translation id="286512204874376891">Щоб захиÑтити Ð²Ð°Ñ Ð²Ñ–Ð´ потенційного шахрайÑтва, заміÑÑ‚ÑŒ Ñправжньої картки буде викориÑтовуватиÑÑ Ð²Ñ–Ñ€Ñ‚ÑƒÐ°Ð»ÑŒÐ½Ð°. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">ПриÑзний</translation>
<translation id="2876489322757410363">Щоб оплатити в зовнішньому додатку, ви вийдете з режиму анонімного переглÑду. Продовжити?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />; натиÑніть Tab, а потім – Enter, щоб керувати Безпечним переглÑдом Ñ– виконувати інші дії в налаштуваннÑÑ… Chrome</translation>
@@ -611,6 +642,7 @@
<translation id="2930577230479659665">Обрізати піÑÐ»Ñ ÐºÐ¾Ð¶Ð½Ð¾Ñ— копії</translation>
<translation id="2932085390869194046">Запропонувати пароль…</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019">Відкрити поÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¾Ñ‚Ð¾ÐºÐ¾Ð»Ñƒ <ph name="PROTOCOL" /></translation>
<translation id="2941952326391522266">Цей Ñервер не зміг довеÑти, що він – домен <ph name="DOMAIN" />. Його Ñертифікат безпеки походить із домену <ph name="DOMAIN2" />. Імовірні причини: неправильна ÐºÐ¾Ð½Ñ„Ñ–Ð³ÑƒÑ€Ð°Ñ†Ñ–Ñ Ð°Ð±Ð¾ хтоÑÑŒ намагаєтьÑÑ Ð¿ÐµÑ€ÐµÑ…Ð¾Ð¿Ð¸Ñ‚Ð¸ ваше з’єднаннÑ.</translation>
<translation id="2943895734390379394">Ð§Ð°Ñ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ:</translation>
<translation id="2948083400971632585">УÑÑ– прокÑÑ–-Ñервери, налаштовані Ð´Ð»Ñ Ð·â€™Ñ”Ð´Ð½Ð°Ð½Ð½Ñ, можна вимкнути на Ñторінці налаштувань.</translation>
@@ -643,6 +675,7 @@
<translation id="3037605927509011580">От халепа!</translation>
<translation id="3041612393474885105">Ð†Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ñ–Ñ Ð¿Ñ€Ð¾ Ñертифікат</translation>
<translation id="3044034790304486808">Відновити пошук</translation>
+<translation id="305162504811187366">ІÑторію Віддаленого ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Chrome, включно з позначками чаÑу, хоÑтами й ідентифікаторами ÑеанÑів клієнта</translation>
<translation id="3060227939791841287">C9 (конверт)</translation>
<translation id="3061707000357573562">Служба виправлень</translation>
<translation id="306573536155379004">Гра почалаÑÑ.</translation>
@@ -683,6 +716,7 @@
<translation id="3197136577151645743">Може запитувати, чи ви активно викориÑтовуєте цей приÑтрій</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />; натиÑніть Tab, а потім – Enter, щоб вибрати в налаштуваннÑÑ… Chrome, Ñку інформацію Ñинхронізувати</translation>
<translation id="320323717674993345">СкаÑувати оплату</translation>
+<translation id="3203366800380907218">З Інтернету</translation>
<translation id="3207960819495026254">Створено закладку</translation>
<translation id="3209034400446768650">Ðа Ñторінці може ÑÑ‚ÑгуватиÑÑ Ð¿Ð»Ð°Ñ‚Ð°</translation>
<translation id="3212581601480735796">Ваші дії на Ñайті <ph name="HOSTNAME" /> відÑтежуютьÑÑ</translation>
@@ -699,10 +733,12 @@
<translation id="3234666976984236645">Завжди виÑвлÑти важливий вміÑÑ‚ на цьому Ñайті</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />; натиÑніть Tab, а потім – Enter, щоб налаштувати виглÑд веб-переглÑдача</translation>
<translation id="3240791268468473923">Відкрито нижній екран невідповідноÑÑ‚Ñ– облікових даних Ð´Ð»Ñ Ð±ÐµÐ·Ð¿ÐµÑ‡Ð½Ð¸Ñ… платежів</translation>
+<translation id="324180406144491771">ПоÑÐ¸Ð»Ð°Ð½Ð½Ñ <ph name="HOST_NAME" /> заблоковано</translation>
<translation id="3249845759089040423">Чудовий</translation>
<translation id="3252266817569339921">Французька</translation>
<translation id="3257954757204451555">Звідки надійшла Ñ†Ñ Ñ–Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ñ–Ñ?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />; натиÑніть Tab, а потім – Enter, щоб швидко Ñтворити нову подію в Google Календарі</translation>
+<translation id="3261488570342242926">Докладніше про віртуальні картки</translation>
<translation id="3264837738038045344">Кнопка "Керувати налаштуваннÑми Chrome"; натиÑніть Enter, щоб перейти в Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Chrome</translation>
<translation id="3266793032086590337">Ð—Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ (конфліктне)</translation>
<translation id="3268451620468152448">Відкриті вкладки</translation>
@@ -716,6 +752,7 @@
<translation id="3288238092761586174">Сайт <ph name="URL" /> може виконати додаткові дії, щоб підтвердити ваш платіж</translation>
<translation id="3293642807462928945">Докладніше про правило <ph name="POLICY_NAME" /></translation>
<translation id="3295444047715739395">ПереглÑнути паролі й керувати ними в налаштуваннÑÑ… Chrome</translation>
+<translation id="3303795387212510132">Дозволити додатку відкривати поÑÐ¸Ð»Ð°Ð½Ð½Ñ <ph name="PROTOCOL_SCHEME" />?</translation>
<translation id="3303855915957856445">Ðемає результатів</translation>
<translation id="3304073249511302126">пошук приÑтроїв із Bluetooth</translation>
<translation id="3308006649705061278">Організаційний підрозділ (OU)</translation>
@@ -729,12 +766,6 @@
<translation id="3345782426586609320">Очі</translation>
<translation id="3355823806454867987">Змінити Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¾ÐºÑÑ–...</translation>
<translation id="3360103848165129075">Ðркуш обробника платежу</translation>
-<translation id="3361596688432910856">Chrome <ph name="BEGIN_EMPHASIS" />не зберігатиме<ph name="END_EMPHASIS" />:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Ñ–Ñторію веб-переглÑду
- <ph name="LIST_ITEM" />файли cookie та дані із Ñайтів
- <ph name="LIST_ITEM" />дані, Ñкі ви заповнюєте у формах
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">Правило було автоматично Ñкопійовано з правила <ph name="OLD_POLICY" />, Ñке не підтримуєтьÑÑ. ÐатоміÑÑ‚ÑŒ потрібно заÑтоÑувати це правило.</translation>
<translation id="3364869320075768271">Сайт <ph name="URL" /> хоче отримати доÑтуп до ваших даних Ñ– приÑтрою віртуальної реальноÑÑ‚Ñ–</translation>
<translation id="3366477098757335611">ПереглÑнути картки</translation>
@@ -817,7 +848,6 @@
<translation id="3587738293690942763">Середній</translation>
<translation id="3592413004129370115">Italian (конверт)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{Ви можете будь-коли Ñкинути цю групу. Перехід у нову групу займає приблизно один день.}=1{Ви можете будь-коли Ñкинути цю групу. Перехід у нову групу займає приблизно один день.}one{Ви можете будь-коли Ñкинути цю групу. Перехід у нову групу займає {NUM_DAYS} день.}few{Ви можете будь-коли Ñкинути цю групу. Перехід у нову групу займає {NUM_DAYS} дні.}many{Ви можете будь-коли Ñкинути цю групу. Перехід у нову групу займає {NUM_DAYS} днів.}other{Ви можете будь-коли Ñкинути цю групу. Перехід у нову групу займає {NUM_DAYS} днÑ.}}</translation>
-<translation id="3596012367874587041">ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð¾Ð´Ð°Ñ‚ÐºÑ–Ð²</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">Додаток заблоковано адмініÑтратором</translation>
<translation id="3608932978122581043">ÐžÑ€Ñ–Ñ”Ð½Ñ‚Ð°Ñ†Ñ–Ñ Ñтрічки</translation>
@@ -860,6 +890,7 @@
<translation id="370972442370243704">Увімкнути функцію "СеанÑи"</translation>
<translation id="3711895659073496551">Призупинити</translation>
<translation id="3712624925041724820">Ліцензії вичерпано</translation>
+<translation id="3714633008798122362">веб-календар</translation>
<translation id="3714780639079136834">увімкнути мобільний Інтернет або Wi-Fi</translation>
<translation id="3715597595485130451">ÐŸÑ–Ð´â€™Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð´Ð¾ мережі Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />перевірити конфігурацію прокÑÑ–-Ñервера, брандмауера та DNS-Ñервера<ph name="END_LINK" /></translation>
@@ -921,6 +952,7 @@
<translation id="3906954721959377182">Планшет</translation>
<translation id="3909477809443608991"><ph name="URL" /> хоче відтворити захищений вміÑÑ‚. Ми перевіримо ідентифікаційні дані вашого приÑтрою, Ñ– Ñайт зможе отримати до нього доÑтуп.</translation>
<translation id="3909695131102177774"><ph name="LABEL" />: <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">Відмовити</translation>
<translation id="3939773374150895049">ВикориÑтовувати веб-автентифікацію заміÑÑ‚ÑŒ коду CVC?</translation>
<translation id="3946209740501886391">Завжди запитувати на цьому Ñайті</translation>
<translation id="3947595700203588284">Може проÑити дозвіл підключатиÑÑ Ð´Ð¾ приÑтроїв MIDI</translation>
@@ -942,6 +974,7 @@
<translation id="3990250421422698716">ПоÑтупове зміщеннÑ</translation>
<translation id="3996311196211510766">Сайт <ph name="ORIGIN" /> проÑить, щоб правило джерела
заÑтоÑовувалоÑÑ Ð´Ð¾ вÑÑ–Ñ… його запитів, однак наразі це неможливо.</translation>
+<translation id="4009243425692662128">Контент Ñторінок, Ñкі ви друкуєте, надÑилаєтьÑÑ Ð½Ð° аналіз на платформу Google Cloud або Ñтороннім ÑервіÑам. Ðаприклад, його можуть Ñканувати на наÑвніÑÑ‚ÑŒ конфіденційних даних.</translation>
<translation id="4010758435855888356">Дозволити доÑтуп до пам’ÑÑ‚Ñ–?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{Документ PDF міÑтить {COUNT} Ñторінку}one{Документ PDF міÑтить {COUNT} Ñторінку}few{Документ PDF міÑтить {COUNT} Ñторінки}many{Документ PDF міÑтить {COUNT} Ñторінок}other{Документ PDF міÑтить {COUNT} Ñторінки}}</translation>
<translation id="4023431997072828269">Вашу інформацію бачитимуть інші кориÑтувачі, оÑкільки форма надÑилаєтьÑÑ Ñ‡ÐµÑ€ÐµÐ· незахищене з'єднаннÑ.</translation>
@@ -1036,6 +1069,7 @@
<translation id="4250680216510889253">ÐÑ–</translation>
<translation id="4253168017788158739">Примітка</translation>
<translation id="425582637250725228">ВнеÑені зміни, можливо, не буде збережено.</translation>
+<translation id="425869179292622354">ЗахиÑтити за допомогою віртуальної картки?</translation>
<translation id="4258748452823770588">ÐедійÑний підпиÑ</translation>
<translation id="4261046003697461417">Ð”Ð»Ñ Ð·Ð°Ñ…Ð¸Ñ‰ÐµÐ½Ð¸Ñ… документів ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¸Ð¼Ñ–Ñ‚Ð¾Ðº недоÑтупне</translation>
<translation id="4265872034478892965">Дозволено адмініÑтратором</translation>
@@ -1055,7 +1089,7 @@
<translation id="4306812610847412719">буфер обміну</translation>
<translation id="4312613361423056926">B2</translation>
<translation id="4312866146174492540">Блокувати (за умовчаннÑм)</translation>
-<translation id="4314815835985389558">ÐšÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ñинхронізацією</translation>
+<translation id="4314815835985389558">Керувати Ñинхронізацією</translation>
<translation id="4318312030194671742">Ð¡ÐµÑ€Ð²Ñ–Ñ ÐºÐ¾Ð¼Ð¿Ð¾Ð½ÑƒÐ²Ð°Ð½Ð½Ñ Ð¿ÐµÑ€ÐµÐ³Ð»Ñду малюнків</translation>
<translation id="4318566738941496689">Ðазва приÑтрою й адреÑа мережі</translation>
<translation id="4325600325087822253">Лоток 17</translation>
@@ -1098,6 +1132,7 @@
<translation id="4434045419905280838">Спливаючі вікна/переÑпрÑмуваннÑ</translation>
<translation id="4435702339979719576">ЛиÑтівка)</translation>
<translation id="443673843213245140">ВикориÑÑ‚Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¾ÐºÑÑ–-Ñервера вимкнено, але чітко вказано Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¾ÐºÑÑ–-Ñервера.</translation>
+<translation id="4441832193888514600">ІгноруєтьÑÑ, оÑкільки це правило можна налаштувати лише Ñк хмарне правило Ð´Ð»Ñ ÐºÐ¾Ñ€Ð¸Ñтувачів.</translation>
<translation id="4450893287417543264">Більше не показувати</translation>
<translation id="4451135742916150903">Може проÑити дозвіл підключатиÑÑ Ð´Ð¾ приÑтроїв HID</translation>
<translation id="4452328064229197696">Введений пароль розкрито через Ð¿Ð¾Ñ€ÑƒÑˆÐµÐ½Ð½Ñ Ð±ÐµÐ·Ð¿ÐµÐºÐ¸ даних. Щоб захиÑтити ваші облікові запиÑи, Менеджер паролів Google радить перевірити збережені паролі.</translation>
@@ -1153,6 +1188,7 @@
<translation id="4628948037717959914">ФотографіÑ</translation>
<translation id="4631649115723685955">З кешбеком</translation>
<translation id="4636930964841734540">ІнформаціÑ</translation>
+<translation id="4638670630777875591">Ðнонімний режим у Chromium</translation>
<translation id="464342062220857295">Функції пошуку</translation>
<translation id="4644670975240021822">Зворотний порÑдок лицевою Ñтороною вниз</translation>
<translation id="4646534391647090355">Перейти зараз</translation>
@@ -1173,6 +1209,7 @@
<translation id="4708268264240856090">Ð—â€™Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ñ€Ð¾Ð·Ñ–Ñ€Ð²Ð°Ð½Ð¾</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />провеÑти діагноÑтику мережі Windows<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426">Пароль кориÑтувача <ph name="USERNAME" /></translation>
<translation id="4724144314178270921">Може проÑити дозвіл переглÑдати текÑÑ‚ Ñ– Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ Ð² буфері обміну</translation>
<translation id="4726672564094551039">Перезавантажити правила</translation>
<translation id="4728558894243024398">Платформа</translation>
@@ -1194,6 +1231,7 @@
<translation id="4757993714154412917">Щойно ви ввели пароль на оманливому Ñайті. Щоб захиÑтити ваші облікові запиÑи, Chromium радить перевірити збережені паролі.</translation>
<translation id="4758311279753947758">Додати контактну інформацію</translation>
<translation id="4761104368405085019">ВикориÑтовувати ваш мікрофон</translation>
+<translation id="4761869838909035636">Виконати перевірку безпеки Chrome</translation>
<translation id="4764776831041365478">Веб-Ñторінка за адреÑою <ph name="URL" /> може бути тимчаÑово недоÑтупною або Ñ—Ñ— назавжди переміщено на нову веб-адреÑу.</translation>
<translation id="4766713847338118463">Двічі Ñкріпити внизу</translation>
<translation id="4771973620359291008">Виникла невідома помилка.</translation>
@@ -1214,12 +1252,6 @@
<translation id="4819347708020428563">Редагувати примітки в режимі переглÑду за умовчаннÑм?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />; натиÑніть Tab, а потім – Enter, щоб швидко Ñтворити нову таблицю Google</translation>
<translation id="4825507807291741242">Потужний</translation>
-<translation id="4827402517081186284">Ð’ анонімному режимі ваші дії в Інтернеті не Ñтають невидимими:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />коли ви відвідуєте веб-Ñайти, вони бачать це;<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />роботодавці та заклади оÑвіти можуть відÑтежувати ваші дії у веб-переглÑдачі;<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />поÑтачальники поÑлуг Інтернету (ISP) можуть відÑтежувати веб-трафік.<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">Увімкнути попередженнÑ</translation>
<translation id="4838327282952368871">Мрійливий</translation>
<translation id="4840250757394056958">ПереглÑнути Ñ–Ñторію Chrome</translation>
@@ -1231,12 +1263,12 @@
<translation id="4854362297993841467">Цей ÑпоÑіб доÑтавки недоÑтупний. Виберіть інший ÑпоÑіб.</translation>
<translation id="4854853140771946034">Швидко Ñтворюйте нові нотатки в Google Keep</translation>
<translation id="485902285759009870">Перевірка коду…</translation>
+<translation id="4866506163384898554">ÐатиÑніть |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />|, щоб показати курÑор</translation>
<translation id="4876188919622883022">Спрощений переглÑд</translation>
<translation id="4876305945144899064">Ðемає імені кориÑтувача</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{Ðемає}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}one{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}few{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}many{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831">Пошук за запитом "<ph name="TEXT" />"</translation>
<translation id="4879491255372875719">Ðвтоматично (за умовчаннÑм)</translation>
-<translation id="4879725228911483934">Відкривати й розміщувати вікна на ваших екранах</translation>
<translation id="4880827082731008257">Пошук в Ñ–Ñторії</translation>
<translation id="4881695831933465202">Відкрити</translation>
<translation id="4885256590493466218">Оплатіть за допомогою <ph name="CARD_DETAIL" /></translation>
@@ -1245,6 +1277,7 @@
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">Дев’Ñтий рулон</translation>
<translation id="4901778704868714008">Зберегти…</translation>
+<translation id="4905659621780993806">ÐдмініÑтратор автоматично перезапуÑтить приÑтрій <ph name="DATE" /> о <ph name="TIME" />. Збережіть уÑÑ– відкриті файли до цього чаÑу.</translation>
<translation id="4913987521957242411">Пробити отвір угорі ліворуч</translation>
<translation id="4918221908152712722">УÑтановіть додаток <ph name="APP_NAME" /> (його не потрібно завантажувати)</translation>
<translation id="4923459931733593730">Оплата</translation>
@@ -1253,6 +1286,7 @@
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" /> з <ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />; натиÑніть Tab, а потім – Enter, щоб шукати</translation>
<translation id="4930153903256238152">Велика міÑткіÑÑ‚ÑŒ</translation>
+<translation id="4940163644868678279">Ðнонімний режим у Chrome</translation>
<translation id="4943872375798546930">Ðе знайдено жодного результату</translation>
<translation id="4950898438188848926">Кнопка Ð¿ÐµÑ€ÐµÐ¼Ð¸ÐºÐ°Ð½Ð½Ñ Ð²ÐºÐ»Ð°Ð´ÐºÐ¸: натиÑніть Enter, щоб перейти на відкриту вкладку, <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="495170559598752135">Дії</translation>
@@ -1262,6 +1296,7 @@
<translation id="4968522289500246572">Цей додаток Ñтворено Ð´Ð»Ñ Ð¼Ð¾Ð±Ñ–Ð»ÑŒÐ½Ð¸Ñ… приÑтроїв, тому можуть виникати проблеми зі зміною розміру на різних екранах. Також можуть траплÑтиÑÑ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ¸ в роботі й перезапуÑки.</translation>
<translation id="4969341057194253438">Видалити запиÑ</translation>
<translation id="4973922308112707173">Пробити два отвори вгорі</translation>
+<translation id="4976702386844183910">ОÑтаннє відвідуваннÑ: <ph name="DATE" /></translation>
<translation id="4984088539114770594">ВикориÑтовувати мікрофон?</translation>
<translation id="4984339528288761049">Prc5 (конверт)</translation>
<translation id="4989163558385430922">Показати вÑе</translation>
@@ -1323,6 +1358,7 @@
<translation id="5138227688689900538">Показати менше</translation>
<translation id="5145883236150621069">Відповідь правила міÑтить код помилки</translation>
<translation id="5146995429444047494">Ð¡Ð¿Ð¾Ð²Ñ–Ñ‰ÐµÐ½Ð½Ñ Ñайту <ph name="ORIGIN" /> заблоковано</translation>
+<translation id="514704532284964975">Сайт <ph name="URL" /> хоче переглÑдати й змінювати інформацію на приÑтроÑÑ… NFC, Ñких ви торкаєтеÑÑ Ñ‚ÐµÐ»ÐµÑ„Ð¾Ð½Ð¾Ð¼</translation>
<translation id="5148809049217731050">Лицевою Ñтороною вгору</translation>
<translation id="515292512908731282">C4 (конверт)</translation>
<translation id="5158275234811857234">Обкладинка</translation>
@@ -1347,6 +1383,7 @@
<translation id="5215116848420601511">СпоÑоби оплати й адреÑи, пов’Ñзані з Google Pay</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">Лоток 13</translation>
+<translation id="5216942107514965959">ОÑтаннє відвідуваннÑ: Ñьогодні</translation>
<translation id="5222812217790122047">Укажіть електронну адреÑу</translation>
<translation id="5230733896359313003">ÐдреÑа доÑтавки</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1367,7 +1404,6 @@
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">ВлаÑтивоÑÑ‚Ñ– документа</translation>
<translation id="528468243742722775">Завершити</translation>
-<translation id="5284909709419567258">ÐдреÑи мережі</translation>
<translation id="5285570108065881030">Показати вÑÑ– збережені паролі</translation>
<translation id="5287240709317226393">Показати cookie-файли</translation>
<translation id="5287456746628258573">Ðа цьому Ñайті викориÑтовуєтьÑÑ Ð½ÐµÐ´Ñ–Ð¹Ñна ÐºÐ¾Ð½Ñ„Ñ–Ð³ÑƒÑ€Ð°Ñ†Ñ–Ñ Ð±ÐµÐ·Ð¿ÐµÐºÐ¸. Через це ваші дані (наприклад, паролі або номери кредитних карток) може бути розкрито, коли вони надÑилаєтьÑÑ Ð½Ð° цей Ñайт.</translation>
@@ -1451,6 +1487,7 @@
<translation id="5556459405103347317">Перезавантажити</translation>
<translation id="5560088892362098740">Термін дії</translation>
<translation id="55635442646131152">Структура документа</translation>
+<translation id="5565613213060953222">Відкрити анонімну вкладку</translation>
<translation id="5565735124758917034">Ðктивний клієнт</translation>
<translation id="5570825185877910964">ЗахиÑтити обліковий запиÑ</translation>
<translation id="5571083550517324815">ÐдреÑа Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ð½Ðµ підтримуєтьÑÑ. Укажіть іншу адреÑу.</translation>
@@ -1533,6 +1570,7 @@
<translation id="5869522115854928033">Збережені паролі</translation>
<translation id="5873013647450402046">Банку потрібне Ð¿Ñ–Ð´Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ Ð²Ð°ÑˆÐ¾Ñ— оÑоби.</translation>
<translation id="5887400589839399685">Картку збережено</translation>
+<translation id="5887687176710214216">ОÑтаннє відвідуваннÑ: вчора</translation>
<translation id="5895138241574237353">ПерезапуÑтити</translation>
<translation id="5895187275912066135">Дата видачі</translation>
<translation id="5901630391730855834">Жовтий</translation>
@@ -1546,6 +1584,7 @@
<translation id="5921639886840618607">Зберегти картку в обліковому запиÑÑ– Google?</translation>
<translation id="5922853866070715753">Майже готово</translation>
<translation id="5932224571077948991">Сайт показує нав’Ñзливі чи оманливі оголошеннÑ</translation>
+<translation id="5938153366081463283">Додайте віртуальну картку</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347">ВідкриваєтьÑÑ <ph name="SITE_NAME" />…</translation>
<translation id="5951495562196540101">Ðе вдаєтьÑÑ Ð·Ð°Ñ€ÐµÑ”ÑтруватиÑÑ Ð·Ð° допомогою оÑобиÑтого облікового запиÑу кориÑтувача (ліцензію отримано в комплекті з приÑтроєм).</translation>
@@ -1610,6 +1649,7 @@
<translation id="6120179357481664955">Запам'Ñтати ідентифікатор UPI?</translation>
<translation id="6124432979022149706">Конектори Chrome Enterprise</translation>
<translation id="6127379762771434464">Веб-Ñайт видалено</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Докладніше про анонімний режим у Chrome<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">Перевірте вÑÑ– кабелі та перезавантажте вÑÑ– маршрутизатори, модеми чи інші мережеві
приÑтрої, Ñкі ви викориÑтовуєте.</translation>
<translation id="614940544461990577">Спробуйте:</translation>
@@ -1622,7 +1662,6 @@
<translation id="6169916984152623906">Тепер ви можете переглÑдати вміÑÑ‚ анонімно. Інші кориÑтувачі вашого приÑтрою не бачитимуть дані про вашу активніÑÑ‚ÑŒ. Однак Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ñ‚Ð° закладки зберігатимутьÑÑ.</translation>
<translation id="6177128806592000436">Ваше Ð·â€™Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð· цим Ñайтом не захищене</translation>
<translation id="6180316780098470077">Інтервал між повторними Ñпробами</translation>
-<translation id="619448280891863779">Може проÑити дозвіл відкривати й розміщувати вікна на ваших екранах</translation>
<translation id="6196640612572343990">Блокувати Ñторонні файли cookie</translation>
<translation id="6203231073485539293">Перевірте Ð·â€™Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð· Інтернетом</translation>
<translation id="6218753634732582820">Видалити адреÑу з Chromium?</translation>
@@ -1645,7 +1684,7 @@
<translation id="6272383483618007430">ÐžÐ½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Google</translation>
<translation id="6276112860590028508">Тут з’ÑвлÑтимутьÑÑ Ñторінки з вашого ÑпиÑку читаннÑ</translation>
<translation id="627746635834430766">Щоб наÑтупного разу платити швидше, збережіть дані картки та платіжну адреÑу в обліковому запиÑÑ– Google.</translation>
-<translation id="6279098320682980337">Ðомер віртуальної картки не заповнено? Щоб Ñкопіювати потрібні дані картки, натиÑніть Ñ—Ñ….</translation>
+<translation id="6279183038361895380">ÐатиÑніть |<ph name="ACCELERATOR" />|, щоб побачити курÑор</translation>
<translation id="6280223929691119688">Ðеможливо доÑтавити Ð·Ð°Ð¼Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð·Ð° цією адреÑою. Укажіть іншу адреÑу.</translation>
<translation id="6282194474023008486">Поштовий код</translation>
<translation id="6285507000506177184">Кнопка "Керувати завантаженнÑми в Chrome"; натиÑніть Enter, щоб керувати завантаженими файлами в Chrome</translation>
@@ -1653,6 +1692,7 @@
<translation id="6290238015253830360">Тут відображатимутьÑÑ Ñ€ÐµÐºÐ¾Ð¼ÐµÐ½Ð´Ð¾Ð²Ð°Ð½Ñ– Ñтатті</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{Ваш приÑтрій зараз перезапуÑтитьÑÑ}=1{Ваш приÑтрій перезапуÑтитьÑÑ Ñ‡ÐµÑ€ÐµÐ· 1 Ñекунду}one{Ваш приÑтрій перезапуÑтитьÑÑ Ñ‡ÐµÑ€ÐµÐ· # Ñекунду}few{Ваш приÑтрій перезапуÑтитьÑÑ Ñ‡ÐµÑ€ÐµÐ· # Ñекунди}many{Ваш приÑтрій перезапуÑтитьÑÑ Ñ‡ÐµÑ€ÐµÐ· # Ñекунд}other{Ваш приÑтрій перезапуÑтитьÑÑ Ñ‡ÐµÑ€ÐµÐ· # Ñекунди}}</translation>
<translation id="6302269476990306341">ÐŸÑ€Ð¸Ð¿Ð¸Ð½ÐµÐ½Ð½Ñ Ñ€Ð¾Ð±Ð¾Ñ‚Ð¸ Google ÐÑиÑтента в Chrome</translation>
<translation id="6305205051461490394">Сторінка <ph name="URL" /> недоÑтупна.</translation>
<translation id="6312113039770857350">Веб-Ñторінка недоÑтупна</translation>
@@ -1726,6 +1766,7 @@
<translation id="6529602333819889595">&amp;Повторити видаленнÑ</translation>
<translation id="6545864417968258051">Пошук приÑтроїв Bluetooth</translation>
<translation id="6547208576736763147">Пробити два отвори ліворуч</translation>
+<translation id="6554732001434021288">ОÑтаннє відвідуваннÑ: <ph name="NUM_DAYS" /> дн. тому</translation>
<translation id="6556866813142980365">Повторити</translation>
<translation id="6569060085658103619">Ви переглÑдаєте Ñторінку розширень</translation>
<translation id="6573200754375280815">Пробити два отвори праворуч</translation>
@@ -1786,7 +1827,6 @@
<translation id="6757797048963528358">Ваш приÑтрій перейшов у режим Ñну.</translation>
<translation id="6767985426384634228">Оновити адреÑу?</translation>
<translation id="6768213884286397650">Hagaki (лиÑтівка)</translation>
-<translation id="6774185088257932239"><ph name="BEGIN_LINK" />Докладніше<ph name="END_LINK" /> про анонімний режим</translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">Фіолетовий</translation>
<translation id="6786747875388722282">РозширеннÑ</translation>
@@ -1870,7 +1910,6 @@
<translation id="706295145388601875">Додайте адреÑи та керуйте ними в налаштуваннÑÑ… Chrome</translation>
<translation id="7064851114919012435">Контактна інформаціÑ</translation>
<translation id="7068733155164172741">Введіть <ph name="OTP_LENGTH" />-значний код</translation>
-<translation id="7070090581017165256">Про цей Ñайт</translation>
<translation id="70705239631109039">З'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð½Ðµ повніÑÑ‚ÑŽ захищене</translation>
<translation id="7075452647191940183">Запит завеликий</translation>
<translation id="7079718277001814089">Цей Ñайт міÑтить зловмиÑне програмне забезпеченнÑ</translation>
@@ -1887,6 +1926,12 @@
<translation id="7111012039238467737">(ДійÑний)</translation>
<translation id="7118618213916969306">Пошук URL-адреÑи з буфера обміну, <ph name="SHORT_URL" /></translation>
<translation id="7119414471315195487">Закрийте інші вкладки та програми</translation>
+<translation id="7129355289156517987">Коли ви закриваєте вÑÑ– анонімні вкладки в Chromium, з приÑтрою видалÑÑŽÑ‚ÑŒÑÑ Ð´Ð°Ð½Ñ– про ваші дії в них, зокрема:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />дії у веб-переглÑдачі;<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Ñ–Ñторію пошуку;<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />інформацію, Ñку ви вводите у формах.<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">Ðеможливо відправити Ð·Ð°Ð¼Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð½Ð° цю адреÑу. Укажіть іншу адреÑу.</translation>
<translation id="7132939140423847331">Ваш адмініÑтратор заборонив копіювати ці дані.</translation>
<translation id="7135130955892390533">Показати ÑтатуÑ</translation>
@@ -1909,6 +1954,7 @@
<translation id="7192203810768312527">ЗвільнитьÑÑ Ð´Ð¾ <ph name="SIZE" /> проÑтору. ПіÑÐ»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ деÑкі Ñайти можуть завантажуватиÑÑ Ð´Ð¾Ð²ÑˆÐµ.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">ÐдмініÑтратор може бачити:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />; натиÑніть Tab, а потім – Enter, щоб відкрити нову анонімну вкладку</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423">ХоÑÑ‚ <ph name="HOST_NAME" /> не відповідає Ñтандартам безпеки.</translation>
<translation id="7210993021468939304">ÐктивніÑÑ‚ÑŒ Linux у межах контейнера. Може вÑтановлювати та запуÑкати додатки Linux у межах контейнера</translation>
@@ -1940,6 +1986,7 @@
<translation id="7304562222803846232">Керувати налаштуваннÑми конфіденційноÑÑ‚Ñ– облікового запиÑу Google</translation>
<translation id="7305756307268530424">Сповільнити</translation>
<translation id="7308436126008021607">фонова ÑинхронізаціÑ</translation>
+<translation id="7310392214323165548">Ðевдовзі приÑтрій перезапуÑтитьÑÑ</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">Довідка щодо з’єднаннÑ</translation>
<translation id="7323804146520582233">Сховати розділ "<ph name="SECTION" />"</translation>
@@ -1947,6 +1994,7 @@
<translation id="7334320624316649418">&amp;Повторити перевпорÑдкуваннÑ</translation>
<translation id="7335157162773372339">Може проÑити доÑтуп до камери</translation>
<translation id="7337248890521463931">Показати більше Ñ€Ñдків</translation>
+<translation id="7337418456231055214">Ðомер віртуальної картки не заповнено? Щоб Ñкопіювати дані картки, натиÑніть Ñ—Ñ…. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">ÐедоÑтупний на вашій платформі.</translation>
<translation id="733923710415886693">Сертифікат Ñервера не надав інформацію про перевірку.</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1969,6 +2017,7 @@
<translation id="7378627244592794276">ÐÑ–</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">Ðе заÑтоÑовуєтьÑÑ</translation>
+<translation id="7388594495505979117">{0,plural, =1{Ваш приÑтрій перезапуÑтитьÑÑ Ñ‡ÐµÑ€ÐµÐ· 1 хвилину}one{Ваш приÑтрій перезапуÑтитьÑÑ Ñ‡ÐµÑ€ÐµÐ· # хвилину}few{Ваш приÑтрій перезапуÑтитьÑÑ Ñ‡ÐµÑ€ÐµÐ· # хвилини}many{Ваш приÑтрій перезапуÑтитьÑÑ Ñ‡ÐµÑ€ÐµÐ· # хвилин}other{Ваш приÑтрій перезапуÑтитьÑÑ Ñ‡ÐµÑ€ÐµÐ· # хвилини}}</translation>
<translation id="7390545607259442187">Підтвердити дані картки</translation>
<translation id="7392089738299859607">Оновіть адреÑу</translation>
<translation id="7399802613464275309">Перевірка безпеки</translation>
@@ -2005,6 +2054,12 @@
<translation id="7485870689360869515">Даних не знайдено.</translation>
<translation id="7495528107193238112">ÐŸÑ–Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð½Ñ Ð·Ð°Ð±Ð»Ð¾ÐºÐ¾Ð²Ð°Ð½Ð¾. Щоб вирішити проблему, зв'ÑжітьÑÑ Ð· влаÑником Ñайту.</translation>
<translation id="7497998058912824456">Кнопка "Створити документ"; натиÑніть Enter, щоб швидко Ñтворити новий документ Google</translation>
+<translation id="7506488012654002225">Chromium <ph name="BEGIN_EMPHASIS" />не зберігатиме<ph name="END_EMPHASIS" />:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Ñ–Ñторію веб-переглÑду;
+ <ph name="LIST_ITEM" />файли cookie та дані із Ñайтів
+ <ph name="LIST_ITEM" />інформацію, Ñку ви вводите у формах.
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">Отриманий ідентифікатор правил приÑтрою порожній або не збігаєтьÑÑ Ð· поточним ідентифікатором приÑтрою</translation>
<translation id="7508870219247277067">Світло-зелений</translation>
<translation id="7511955381719512146">Можливо, щоб під’єднатиÑÑ Ð´Ð¾ цієї мережі Wi-Fi, потрібно відвідати Ñторінку <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
@@ -2118,7 +2173,6 @@
<translation id="7813600968533626083">Видалити дані Ð´Ð»Ñ Ð°Ð²Ñ‚Ð¾Ð·Ð°Ð¿Ð¾Ð²Ð½ÐµÐ½Ð½Ñ Ñ„Ð¾Ñ€Ð¼ із Chrome?</translation>
<translation id="781440967107097262">Ðадати доÑтуп до буфера обміну?</translation>
<translation id="7815407501681723534">Знайдено результатів за запитом "<ph name="SEARCH_STRING" />": <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /></translation>
-<translation id="782125616001965242">Показати відомоÑÑ‚Ñ– про цей Ñайт</translation>
<translation id="782886543891417279">Можливо, щоб під’єднатиÑÑ Ð´Ð¾ цієї мережі Wi-Fi (<ph name="WIFI_NAME" />), потрібно відвідати Ñ—Ñ— Ñторінку входу.</translation>
<translation id="7836231406687464395">Postfix (конверт)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{Ðемає}=1{1 додаток (<ph name="EXAMPLE_APP_1" />)}=2{2 додатки (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}one{# додаток (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" /> <ph name="AND_MORE" />)}few{# додатки (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" /> <ph name="AND_MORE" />)}many{# додатків (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" /> <ph name="AND_MORE" />)}other{# додатка (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" /> <ph name="AND_MORE" />)}}</translation>
@@ -2135,7 +2189,6 @@
<translation id="7888575728750733395">Команда обробки друку</translation>
<translation id="7894280532028510793">Якщо помилок немає, <ph name="BEGIN_LINK" />проведіть діагноÑтику мережі<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (конверт)</translation>
-<translation id="7931318309563332511">невідомо</translation>
<translation id="793209273132572360">Оновити адреÑу?</translation>
<translation id="7932579305932748336">Вкрити обкладинкою</translation>
<translation id="79338296614623784">Введіть дійÑний номер телефону</translation>
@@ -2160,13 +2213,14 @@
<translation id="7976214039405368314">Забагато запитів</translation>
<translation id="7977538094055660992">ПриÑтрій виведеннÑ</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">Зв’Ñзано з карткою:</translation>
<translation id="798134797138789862">Може проÑити дозвіл викориÑтовувати приÑтрої й дані віртуальної реальноÑÑ‚Ñ–</translation>
<translation id="7984945080620862648">Зараз не можна перейти на Ñторінку <ph name="SITE" />, оÑкільки веб-Ñайт надіÑлав зашифровані облікові дані, Ñкі Chrome не може обробити. Помилки мережі й атаки зазвичай Ñ” тимчаÑовими, тому Ñ†Ñ Ñторінка може працювати пізніше.</translation>
-<translation id="79859296434321399">Щоб переглÑдати вміÑÑ‚ у режимі доповненої реальноÑÑ‚Ñ–, уÑтановіть ARCore</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">Зшити</translation>
<translation id="7992044431894087211">Показ екрана за допомогою додатка <ph name="APPLICATION_TITLE" /> відновлено</translation>
<translation id="7995512525968007366">Ðе вказано</translation>
+<translation id="7998269595945679889">Кнопка "Відкрити анонімну вкладку"; натиÑніть Enter, щоб відкрити нову анонімну вкладку</translation>
<translation id="800218591365569300">Щоб звільнити пам’ÑÑ‚ÑŒ, закрийте інші вкладки та програми.</translation>
<translation id="8004582292198964060">ПереглÑдач</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{Цю картку та Ñ—Ñ— платіжну адреÑу буде збережено. Ви зможете ÑкориÑтатиÑÑ Ð½ÐµÑŽ, коли ввійдете в обліковий Ð·Ð°Ð¿Ð¸Ñ <ph name="USER_EMAIL" />.}one{Ці картки та Ñ—Ñ… платіжні адреÑи буде збережено. Ви зможете ÑкориÑтатиÑÑ Ð½Ð¸Ð¼Ð¸, коли ввійдете в обліковий Ð·Ð°Ð¿Ð¸Ñ <ph name="USER_EMAIL" />.}few{Ці картки та Ñ—Ñ… платіжні адреÑи буде збережено. Ви зможете ÑкориÑтатиÑÑ Ð½Ð¸Ð¼Ð¸, коли ввійдете в обліковий Ð·Ð°Ð¿Ð¸Ñ <ph name="USER_EMAIL" />.}many{Ці картки та Ñ—Ñ… платіжні адреÑи буде збережено. Ви зможете ÑкориÑтатиÑÑ Ð½Ð¸Ð¼Ð¸, коли ввійдете в обліковий Ð·Ð°Ð¿Ð¸Ñ <ph name="USER_EMAIL" />.}other{Ці картки та Ñ—Ñ… платіжні адреÑи буде збережено. Ви зможете ÑкориÑтатиÑÑ Ð½Ð¸Ð¼Ð¸, коли ввійдете в обліковий Ð·Ð°Ð¿Ð¸Ñ <ph name="USER_EMAIL" />.}}</translation>
@@ -2226,6 +2280,7 @@
<translation id="8202370299023114387">Конфлікт</translation>
<translation id="8206978196348664717">Prc4 (конверт)</translation>
<translation id="8211406090763984747">Ð—â€™Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð±ÐµÐ·Ð¿ÐµÑ‡Ð½Ðµ</translation>
+<translation id="8217240300496046857">Сайти не можуть викориÑтовувати файли cookie, через Ñкі відÑтежуютьÑÑ Ð²Ð°ÑˆÑ– дії в Інтернеті. Функції на деÑких Ñайтах можуть не працювати.</translation>
<translation id="8218327578424803826">Указане міÑцезнаходженнÑ:</translation>
<translation id="8220146938470311105">C7/C6 (конверт)</translation>
<translation id="8225771182978767009">КориÑтувач, Ñкий налаштував комп’ютер, заблокував цей Ñайт.</translation>
@@ -2266,14 +2321,9 @@
<translation id="830498451218851433">Зігнути поÑередині</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">УÑтановлені додатки та Ñк чаÑто ними кориÑтуютьÑÑ</translation>
+<translation id="8317207217658302555">Оновити ARCore?</translation>
<translation id="831997045666694187">Увечері</translation>
<translation id="8321476692217554900">ÑповіщеннÑ</translation>
-<translation id="8328484624016508118">Коли ви закриєте вÑÑ– анонімні вкладки, у Chrome буде видалено:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />дані про ваші дії у веб-переглÑдачі на цьому приÑтрої;<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />вашу Ñ–Ñторію пошуку на цьому приÑтрої;<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />інформацію, Ñку ви вводили у форми.<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489">Відмовлено в доÑтупі до хоÑту <ph name="HOST_NAME" /></translation>
<translation id="833262891116910667">Виділити</translation>
<translation id="8339163506404995330">Сторінки цією мовою (<ph name="LANGUAGE" />) не перекладатимутьÑÑ</translation>
@@ -2325,6 +2375,7 @@
<translation id="8507227106804027148">Командний Ñ€Ñдок</translation>
<translation id="8508648098325802031">Значок пошуку</translation>
<translation id="8511402995811232419">Керувати файлами cookie</translation>
+<translation id="8519753333133776369">ÐдмініÑтратор дозволив цей приÑтрій HID</translation>
<translation id="8522552481199248698">Chrome допоможе захиÑтити обліковий Ð·Ð°Ð¿Ð¸Ñ Google Ñ– змінити пароль.</translation>
<translation id="8530813470445476232">ОчиÑтити Ñ–Ñторію веб-переглÑду, файли cookie, кеш та інше в налаштуваннÑÑ… Chrome</translation>
<translation id="8533619373899488139">Перейдіть на Ñторінку &lt;strong&gt;chrome://policy&lt;/strong&gt;, щоб переглÑнути ÑпиÑок заблокованих URL-Ð°Ð´Ñ€ÐµÑ Ñ‚Ð° інші правила, Ñкі ввімкнув ваш ÑиÑтемний адмініÑтратор.</translation>
@@ -2336,7 +2387,6 @@
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{Скинути дозвіл}one{Скинути дозволи}few{Скинути дозволи}many{Скинути дозволи}other{Скинути дозволи}}</translation>
<translation id="8555010941760982128">ВикориÑтайте цей код під Ñ‡Ð°Ñ Ð¾Ð¿Ð»Ð°Ñ‚Ð¸</translation>
<translation id="8557066899867184262">Код CVC розташований на зворотному боці картки.</translation>
-<translation id="8558485628462305855">Щоб переглÑдати вміÑÑ‚ у режимі доповненої реальноÑÑ‚Ñ–, оновіть ARCore</translation>
<translation id="8559762987265718583">Ðе вдаєтьÑÑ Ð²Ñтановити конфіденційне Ð·â€™Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð· <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />, оÑкільки на приÑтрої вÑтановлено неправильні дату й Ñ‡Ð°Ñ (<ph name="DATE_AND_TIME" />).</translation>
<translation id="8564182942834072828">Окремі документи/непідібрані копії</translation>
<translation id="8564985650692024650">Chromium радить Ñкинути пароль <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" />, Ñкщо ви заÑтоÑовували його на інших Ñайтах.</translation>
@@ -2356,6 +2406,7 @@
<translation id="865032292777205197">датчики руху</translation>
<translation id="8663226718884576429">ПідÑумок замовленнÑ, <ph name="TOTAL_LABEL" />, докладніше</translation>
<translation id="8666678546361132282">ÐнглійÑька</translation>
+<translation id="8669306706049782872">ВикориÑтовувати інформацію про ваші екрани, щоб відкрити й розміÑтити вікна</translation>
<translation id="867224526087042813">ПідпиÑ</translation>
<translation id="8676424191133491403">Без затримки</translation>
<translation id="8680536109547170164">"<ph name="QUERY" />", відповідь: "<ph name="ANSWER" />"</translation>
@@ -2382,6 +2433,7 @@
<translation id="8731544501227493793">Кнопка "Керувати паролÑми"; натиÑніть Enter, щоб переглÑнути паролі й керувати ними в налаштуваннÑÑ… Chrome</translation>
<translation id="8734529307927223492">Вашим приÑтроєм <ph name="DEVICE_TYPE" /> керує <ph name="MANAGER" /></translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />; натиÑніть Tab, а потім – Enter, щоб відкрити нове вікно в режимі анонімного переглÑду</translation>
+<translation id="8737685506611670901">Відкривати поÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¾Ñ‚Ð¾ÐºÐ¾Ð»Ñƒ <ph name="PROTOCOL" />, а не обробника <ph name="REPLACED_HANDLER_TITLE" /></translation>
<translation id="8738058698779197622">Щоб уÑтановити безпечне з’єднаннÑ, потрібно правильно вказати чаÑ, оÑкільки Ñертифікати, Ñкі веб-Ñайти викориÑтовують Ð´Ð»Ñ Ñамоідентифікації дійÑні лише протÑгом певного періоду чаÑу. Ð§Ð°Ñ Ð½Ð° вашому приÑтрої неправильний, тому Chromium не може перевірити Ñертифікати.</translation>
<translation id="8740359287975076522">&lt;abbr id="dnsDefinition"&gt;ÐдреÑу DNS&lt;/abbr&gt; хоÑту <ph name="HOST_NAME" /> не знайдено. ДіагноÑтика проблеми.</translation>
<translation id="8742371904523228557"><ph name="ONE_TIME_CODE" /> – ваш код Ð´Ð»Ñ Ñайту <ph name="ORIGIN" /></translation>
@@ -2409,6 +2461,7 @@
<translation id="883848425547221593">Інші закладки</translation>
<translation id="884264119367021077">ÐдреÑа доÑтавки</translation>
<translation id="884923133447025588">Ðе знайдено механізм відкликаннÑ.</translation>
+<translation id="8849262850971482943">СкориÑтайтеÑÑ Ð²Ñ–Ñ€Ñ‚ÑƒÐ°Ð»ÑŒÐ½Ð¾ÑŽ карткою Ð´Ð»Ñ Ð´Ð¾Ð´Ð°Ñ‚ÐºÐ¾Ð²Ð¾Ñ— безпеки</translation>
<translation id="885730110891505394">ÐÐ°Ð´Ð°Ð½Ð½Ñ Ñ–Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ñ–Ñ— Ñлужбам Google</translation>
<translation id="8858065207712248076">Chrome радить Ñкинути пароль <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" />, Ñкщо ви заÑтоÑовували його на інших Ñайтах.</translation>
<translation id="885906927438988819">Якщо помилок немає, <ph name="BEGIN_LINK" />проведіть діагноÑтику мережі Windows<ph name="END_LINK" />.</translation>
@@ -2458,6 +2511,7 @@
<translation id="9004367719664099443">Триває VR-ÑеанÑ</translation>
<translation id="9005998258318286617">Ðе вдалоÑÑ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶Ð¸Ñ‚Ð¸ документ PDF.</translation>
<translation id="9008201768610948239">Ігнорувати</translation>
+<translation id="901834265349196618">електронна адреÑа</translation>
<translation id="9020200922353704812">Потрібно вказати платіжну адреÑу картки</translation>
<translation id="9020542370529661692">Цю Ñторінку перекладено такою мовою: <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9020742383383852663">A8</translation>
@@ -2506,6 +2560,7 @@
<translation id="9150045010208374699">ВикориÑтовувати вашу камеру</translation>
<translation id="9150685862434908345">ÐдмініÑтратор може змінити Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð²ÐµÐ±-переглÑдача віддалено. ДіÑми на цьому приÑтрої можна керувати за межами Chrome. <ph name="BEGIN_LINK" />Докладніше<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">Оновлено</translation>
+<translation id="9155211586651734179">Підключено периферійні аудіоприÑтрої</translation>
<translation id="9157595877708044936">ÐалаштуваннÑ...</translation>
<translation id="9158625974267017556">C6 (конверт)</translation>
<translation id="9164029392738894042">Перевірка точноÑÑ‚Ñ–</translation>
diff --git a/chromium/components/strings/components_strings_ur.xtb b/chromium/components/strings/components_strings_ur.xtb
index 9db835381b2..8c2815f7251 100644
--- a/chromium/components/strings/components_strings_ur.xtb
+++ b/chromium/components/strings/components_strings_ur.xtb
@@ -14,13 +14,19 @@
<translation id="1028781062521375153">تÙصیلات دیکھیں</translation>
<translation id="1030706264415084469"><ph name="URL" /> آپ Ú©Û’ آلے پر مستقل طور پر بڑا ڈیٹا اسٹور کرنا چاÛتا ÛÛ’</translation>
<translation id="1032854598605920125">گھڑی کی سمت میں گھمائیں</translation>
+<translation id="1033329911862281889">پوشیدگی وضع آپ Ú©Ùˆ آن لائن غیر مرئی Ù†Ûیں کرتی ÛÛ’:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />سائٹس اور سروسز جو صار٠استعمال کرتا ÛÛ’ ملاحظات دیکھ سکتی Ûیں
+<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />آجر یا اسکول براؤزنگ Ú©ÛŒ سرگرمی Ú©Ùˆ ٹریک کر سکتے Ûیں<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />انٹرنیٹ سروس پرووائیڈرز ویب ٹریÙÚ© Ú©Ùˆ مانیٹر کر سکتے Ûیں<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">آ٠کریں</translation>
<translation id="1036982837258183574">پوری اسکرین سے باÛر نکلنے کیلئے |<ph name="ACCELERATOR" />| Ú©Ùˆ دبائیں</translation>
<translation id="1038106730571050514">تجاویز دکھائیں</translation>
<translation id="1038842779957582377">نامعلوم نام</translation>
<translation id="1041998700806130099">جاب شیٹ کا پیغام</translation>
<translation id="1048785276086539861">آپ Ú©Û’ تشریحات میں ترمیم کرنے پر، ÛŒÛ Ø¯Ø³ØªØ§ÙˆÛŒØ² واحد صÙØ­Û’ Ú©Û’ منظر پر واپس Ø¢ جائے گا</translation>
-<translation id="1049743911850919806">پوشیدگی</translation>
<translation id="1050038467049342496">دیگر ایپس بند کریں</translation>
<translation id="1055184225775184556">شامل کریں کو &amp;کالعدم کریں</translation>
<translation id="1056898198331236512">وارننگ</translation>
@@ -48,6 +54,7 @@
<translation id="112840717907525620">پالیسی کیش ٹھیک ÛÛ’</translation>
<translation id="1130564665089811311">â€'صÙØ­Û’ کا ØªØ±Ø¬Ù…Û Ú©Ø±ÛŒÚº' بٹن، Google ترجمے سے اس صÙØ­Û’ کا ØªØ±Ø¬Ù…Û Ú©Ø±Ù†Û’ Ú©Û’ لیے اینٹر دبائیں</translation>
<translation id="1131264053432022307">آپ Ú©ÛŒ کاپی Ú©Ø±Ø¯Û ØªØµÙˆÛŒØ±</translation>
+<translation id="1142846828089312304">پوشیدگی وضع میں Ùریق ثالث Ú©ÛŒ کوکیز Ú©Ùˆ مسدود کریں</translation>
<translation id="1150979032973867961">ÛŒÛ Ø³Ø±ÙˆØ± ÛŒÛ Ø«Ø§Ø¨Øª Ù†Ûیں کر سکا Ú©Û ÛŒÛ <ph name="DOMAIN" /> ÛÛ’Ø› اس کا سیکیورٹی سرٹیÙیکیٹ آپ Ú©Û’ کمپیوٹر Ú©Û’ آپریٹنگ سسٹم Ú©Û’ ذریعے Ø¨Ú¾Ø±ÙˆØ³Û Ù…Ù†Ø¯ Ù†Ûیں ÛÛ’Û” ÛŒÛ ØºÙ„Ø· Ú©Ù†Ùیگریشن یا آپ Ú©Û’ کنکشن میں مانع بن رÛÛ’ کسی Ø­Ù…Ù„Û Ø¢ÙˆØ± Ú©ÛŒ ÙˆØ¬Û Ø³Û’ ÛÙˆ سکتا ÛÛ’Û”</translation>
<translation id="1151972924205500581">پاس ورڈ درکار ÛÛ’</translation>
<translation id="1156303062776767266">آپ ایک مقامی یا اشتراک Ú©Ø±Ø¯Û Ùائل دیکھ رÛÛ’ Ûیں</translation>
@@ -64,7 +71,6 @@
<translation id="1178581264944972037">موقو٠کریں</translation>
<translation id="1181037720776840403">Ûٹائیں</translation>
<translation id="1186201132766001848">پاس ورڈز چیک کریں</translation>
-<translation id="1195210374336998651">ایپ کی ترتیبات پر جائیں</translation>
<translation id="1195558154361252544">تمام سائٹس Ú©Û’ لیے اطلاعات Ú©Ùˆ خودکار طور پر مسدود کر دیا گیا ÛÛ’ سوائے ان Ú©Û’ جن Ú©ÛŒ آپ Ù†Û’ اجازت دی ÛÛ’</translation>
<translation id="1197088940767939838">نارنجی</translation>
<translation id="1201402288615127009">اگلا</translation>
@@ -111,7 +117,7 @@
<translation id="1307966114820526988">ÙØ±Ø³ÙˆØ¯Û Ø®ØµÙˆØµÛŒØ§Øª</translation>
<translation id="1308113895091915999">پیشکش دستیاب ÛÛ’</translation>
<translation id="1312803275555673949">کون سا ثبوت اس Ú©Ùˆ سپورٹ کرتا ÛÛ’ØŸ</translation>
-<translation id="131405271941274527">â€Ø¢Ù¾ Ú©Û’ NFC Ø§Ù“Ù„Û Ù¾Ø± تھپتھپاتے وقت <ph name="URL" /> معلومات بھیجنا اور وصول کرنا چاÛتا ÛÛ’</translation>
+<translation id="1314311879718644478">اÙØ²ÙˆØ¯Û Ø­Ù‚ÛŒÙ‚Øª کا مواد دیکھیں</translation>
<translation id="1314509827145471431">دائیں طر٠باندھیں</translation>
<translation id="1318023360584041678">ٹیب گروپ Ù…Úº محÙوظ کردÛ</translation>
<translation id="1319245136674974084">اس ایپ کیلئے Ø¯ÙˆØ¨Ø§Ø±Û Ù†Û Ù¾ÙˆÚ†Ú¾ÛŒÚº</translation>
@@ -161,6 +167,7 @@
<translation id="142858679511221695">کلاؤڈ صارÙ</translation>
<translation id="1428729058023778569">â€Ø§Ù“Ù¾ ÛŒÛ ÙˆØ§Ø±Ù†Ù†Ú¯ اس لیے دیکھ رÛÛ’ Ûیں Ú©ÛŒÙˆÙ†Ú©Û ÛŒÛ Ø³Ø§Ø¦Ù¹ HTTPS Ú©Ùˆ سپورٹ Ù†Ûیں کرتی ÛÛ’Û” <ph name="BEGIN_LEARN_MORE_LINK" />مزید جانیں<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">پرنٹ کریں</translation>
+<translation id="1432187715652018471">صÙØ­Û Ø§ÛŒÚ© سروس Ûینڈلر انسٹال کرنا چاÛتا ÛÛ’Û”</translation>
<translation id="1432581352905426595">سرچ انجنز کا نظم کریں</translation>
<translation id="1436185428532214179">سائٹ آپ Ú©Û’ آلے پر موجود Ùائلز یا Ùولڈرز میں ترمیم کرنے کیلئے پوچھ سکتی ÛÛ’</translation>
<translation id="1442386063175183758">دایاں گیٹ Ùولڈ</translation>
@@ -181,6 +188,12 @@
<translation id="1483493594462132177">بھیجیں</translation>
<translation id="1484290072879560759">ترسیل کا Ù¾ØªÛ Ù…Ù†ØªØ®Ø¨ کریں</translation>
<translation id="1492194039220927094">پالیسیوں Ú©Ùˆ Ù¾ÙØ´ کرنا:</translation>
+<translation id="149293076951187737">â€Ø¬Ø¨ آپ سبھی Chrome ونڈوز بند کرتے Ûیں تو ان ٹیبز پر آپ Ú©ÛŒ سرگرمی اس آلے سے صا٠ÛÙˆ جاتی ÛÛ’:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />براؤزنگ کی سرگرمی<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />تلاش کی سرگزشت<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Ùارمز میں درج Ú©Ø±Ø¯Û Ù…Ø¹Ù„ÙˆÙ…Ø§Øª<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">ٹیب پر واپس جائیں</translation>
<translation id="1501859676467574491">â€Ø§Ù¾Ù†Û’ Google اکاؤنٹ سے کارڈز دکھائیں</translation>
<translation id="1507202001669085618">â€&lt;p&gt;اگر آپ کسی ایسے Wi-Fi پورٹل کا استعمال کر رÛÛ’ Ûیں، جس میں آپ Ú©Ùˆ آن لائن جانے سے Ù¾ÛÙ„Û’ سائن ان کرنا پڑتا ÛÛ’ØŒ تو آپ Ú©Ùˆ ÛŒÛ Ø®Ø±Ø§Ø¨ÛŒ دکھائی دے گی۔&lt;/p&gt;
@@ -208,6 +221,8 @@
<translation id="1559572115229829303">â€&lt;p&gt;<ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> سے ایک نجی کنکشن تشکیل Ù†Ûیں دیا جا سکتا ÛÛ’ Ú©ÛŒÙˆÙ†Ú©Û Ø¢Ù¾ Ú©Û’ آلے Ú©ÛŒ تاریخ اور وقت (<ph name="DATE_AND_TIME" />) غلط Ûیں۔&lt;‎/p&gt;
&lt;p&gt;Ø¨Ø±Ø§Û Ú©Ø±Ù… تاریخ اور وقت Ú©Ùˆ &lt;strong&gt;ترتیبات&lt;‎/strong&gt; ایپ Ú©Û’ &lt;strong&gt;عمومی&lt;‎/strong&gt; سیکشن سے ایڈجسٹ کریں۔&lt;‎/p&gt;</translation>
+<translation id="1559839503761818503"><ph name="DATE" /> کو <ph name="TIME" /> پر آپ کا منتظم آپ کے آلے کو ری سٹارٹ کرے گا</translation>
+<translation id="156703335097561114">نیٹ ورکنگ معلومات جیسے پتے، انٹرÙیس Ú©Ù†Ùیگریشن اور کنکشن کا معیار</translation>
<translation id="1567040042588613346">ÛŒÛ Ù¾Ø§Ù„ÛŒØ³ÛŒ توقع Ú©Û’ مطابق کام کر رÛÛŒ ÛÛ’ لیکن کسی دوسری Ø¬Ú¯Û Ø§ÛŒÚ© جیسی قدر سیٹ Ú©ÛŒ گئی ÛÛ’ اور اس Ù†Û’ اس پالیسی Ú©ÛŒ Ø¬Ú¯Û Ù„Û’ Ù„ÛŒ ÛÛ’Û”</translation>
<translation id="1569487616857761740">تاریخ اختتام درج کریں</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +230,7 @@
<translation id="1583429793053364125">ÛŒÛ ÙˆÛŒØ¨ صÙØ­Û ÚˆØ³Ù¾Ù„Û’ کرتے Ûوئے Ú©Ú†Ú¾ غلط ÛÙˆ گیا۔</translation>
<translation id="1586541204584340881">آپ Ù†Û’ Ú©Ù† ایکسٹینشنز Ú©Ùˆ انسٹال کیا ÛÛ’</translation>
<translation id="1588438908519853928">حسب معمول</translation>
+<translation id="1589050138437146318">â€ARCore انسٹال کریں؟</translation>
<translation id="1592005682883173041">مقامی ڈیٹا تک رسائی</translation>
<translation id="1594030484168838125">منتخب کریں</translation>
<translation id="160851722280695521">â€Chrome میں Dino Run گیم کھیلیں</translation>
@@ -283,6 +299,7 @@
Ûیڈر ناقص ÛÛ’ØŒ جو براؤزر Ú©Ùˆ <ph name="SITE" /> Ú©Û’ ليے Ú©ÛŒ گئی
آپ Ú©ÛŒ درخواست Ú©Ùˆ پورا کرنے سے روکتا ÛÛ’Û” کسی سائٹ Ú©ÛŒ خاطر سیکیورٹی اور دیگر پراپرٹیز Ú©Ùˆ ترتیب دینے Ú©Û’ لیے
سائٹ آپریٹرز Ú©Û’ ذریعے ماخذ پالیسیوں کا استعمال کیا جا سکتا ÛÛ’Û”</translation>
+<translation id="1774592222195216949">â€<ph name="BEGIN_LINK" />Chromium میں پوشیدگی وضع Ú©Û’ بارے میں مزید جانیں<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">آپ Ú©Û’ Ú©Ú¾Ù„Û’ ٹیبز ÛŒÛاں ظاÛر Ûوتے Ûیں</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -410,6 +427,7 @@
<translation id="22081806969704220">ٹرے 3</translation>
<translation id="2212735316055980242">پالیسی Ù†Ûیں ملی</translation>
<translation id="2213606439339815911">اندراجات Ú©ÛŒ بازیاÙت Ú©ÛŒ جا رÛÛŒ Ûے…</translation>
+<translation id="2213612003795704869">صÙØ­Û Ù¾Ø±Ù†Ù¹ Ú©Ø±Ø¯Û ÛÛ’</translation>
<translation id="2215727959747642672">Ùائل میں ترمیم کریں</translation>
<translation id="2218879909401188352">Ø­Ù…Ù„Û Ø¢ÙˆØ± ÙÛŒ الحال <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> پر آپ Ú©Û’ Ø¢Ù„Û Ú©Ùˆ نقصان Ù¾Ûنچانے والی، آپ Ú©Û’ موبائل بل پر مخÙÛŒ چارجز شامل کرنے والی یا آپ Ú©ÛŒ ذاتی معلومات Ú©ÛŒ چوری کرنے والی خطرناک ایپس انسٹال کر سکتے Ûیں۔<ph name="BEGIN_LEARN_MORE_LINK" />مزید جانیں<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">انٹرنیٹ Ù†Ûیں ÛÛ’</translation>
@@ -419,6 +437,7 @@
<translation id="2248949050832152960">â€WebAuthn کا استعمال کریں</translation>
<translation id="2250931979407627383">بائیں طر٠کنارے کی سلائی</translation>
<translation id="225207911366869382">ÛŒÛ Ù‚Ø¯Ø± اس پالیسی کیلئے ÙØ±Ø³ÙˆØ¯Û ÛÛ’Û”</translation>
+<translation id="2256115617011615191">ابھی Ø¯ÙˆØ¨Ø§Ø±Û Ø´Ø±ÙˆØ¹ کریں</translation>
<translation id="2258928405015593961">مستقبل میں ختم Ûونے والی تاریخ اختتام درج کریں اور Ø¯ÙˆØ¨Ø§Ø±Û Ú©ÙˆØ´Ø´ کریں</translation>
<translation id="225943865679747347">خرابی کا کوڈ: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">â€HTTP خرابی</translation>
@@ -446,6 +465,7 @@
<translation id="2337852623177822836">ترتیب آپ Ú©Û’ منتظم Ú©ÛŒ جانب سے کنٹرول Ú©ÛŒ جاتی ÛÛ’</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> جوڑا بنانا چاÛتی ÛÛ’</translation>
<translation id="2346319942568447007">آپ Ú©ÛŒ کاپی Ú©Ø±Ø¯Û ØªØµÙˆÛŒØ±</translation>
+<translation id="2350796302381711542"><ph name="HANDLER_HOSTNAME" /> کو <ph name="REPLACED_HANDLER_TITLE" /> کی بجائے سبھی <ph name="PROTOCOL" /> لنکس کھولنے کی اجازت دیں؟</translation>
<translation id="2354001756790975382">دیگر بÙÚ© مارکس</translation>
<translation id="2354430244986887761">â€Google محÙوظ براؤزنگ Ú©Ùˆ حال ÛÛŒ میں <ph name="SITE" /> پر <ph name="BEGIN_LINK" />Ù†Ù‚ØµØ§Ù†Ø¯Û Ø§ÛŒÙ¾Ø³ ملی Ûیں<ph name="END_LINK" />Û”</translation>
<translation id="2355395290879513365">Ø­Ù…Ù„Û Ø¢ÙˆØ± ان تصاویر Ú©Ùˆ دیکھ سکتے Ûیں جنÛیں آپ اس سائٹ پر دیکھ رÛÛ’ Ûیں اور ان میں ترمیم کر Ú©Û’ آپ Ú©Ùˆ Ø¯Ú¾ÙˆÚ©Û Ø¯Û’ سکتے Ûیں۔</translation>
@@ -471,6 +491,7 @@
<translation id="2413528052993050574">ÛŒÛ Ø³Ø±ÙˆØ± ÛŒÛ Ø«Ø§Ø¨Øª Ù†Ûیں کر سکا Ú©Û ÛŒÛ <ph name="DOMAIN" /> ÛÛ’Ø› ممکن ÛÛ’ Ú©Û Ø§Ø³ کا سیکیورٹی سرٹیÙکیٹ کالعدم قرار دے دیا گیا ÛÙˆÛ” ÛŒÛ ØºÙ„Ø· Ú©Ù†Ùیگریشن یا آپ Ú©Û’ کنکشن Ú©Ùˆ قطع کرنے والے کسی Ø­Ù…Ù„Û Ø¢ÙˆØ± Ú©ÛŒ ÙˆØ¬Û Ø³Û’ ÛÙˆ سکتا ÛÛ’Û”</translation>
<translation id="2414886740292270097">Ú¯Ûری</translation>
<translation id="2430968933669123598">â€Google اکاؤنٹ کا نظم کریں، اپنے Google اکاؤنٹ میں اپنی معلومات، رازداری اور سیکیورٹی کا نظم کرنے کیلئے Enter دبائیں</translation>
+<translation id="2436186046335138073"><ph name="HANDLER_HOSTNAME" /> کو سبھی <ph name="PROTOCOL" /> لنکس کھولنے کی اجازت دیں؟</translation>
<translation id="2438874542388153331">دائیں طر٠مستطیل سوراخ</translation>
<translation id="2450021089947420533">صار٠کے تجربے</translation>
<translation id="2463739503403862330">Ù¾Ùر کریں</translation>
@@ -478,6 +499,7 @@
<translation id="2465655957518002998">ڈیلیوری کا Ø·Ø±ÛŒÙ‚Û Ù…Ù†ØªØ®Ø¨ کریں</translation>
<translation id="2465688316154986572">سٹیپل</translation>
<translation id="2465914000209955735">â€Chrome میں ڈاؤن لوڈ Ú©Ø±Ø¯Û Ø§Ù¾Ù†ÛŒ Ùائلز کا نظم کریں</translation>
+<translation id="2466004615675155314">ویب سے معلومات دکھائیں</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />نیٹ ورک کی تشخیصات چلانے کی<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">â€1 سے N ترتیب</translation>
<translation id="2470767536994572628">آپ Ú©Û’ تشریحات میں ترمیم کرنے پر، ÛŒÛ Ø¯Ø³ØªØ§ÙˆÛŒØ² واحد صÙØ­Û’ Ú©Û’ منظر اور اپنے اصل گھماؤ پر واپس Ø¢ جائے گا</translation>
@@ -498,6 +520,7 @@
<translation id="2523886232349826891">صر٠اس Ø¢Ù„Û Ù¾Ø± محÙوظ ÛÛ’</translation>
<translation id="2524461107774643265">مزید معلومات شامل کریں</translation>
<translation id="2529899080962247600">اس Ùیلڈ میں <ph name="MAX_ITEMS_LIMIT" /> سے Ø²ÛŒØ§Ø¯Û Ø§Ù†Ø¯Ø±Ø§Ø¬Ø§Øª Ù†Ûیں Ûونے چاÛیے۔ مزید تمام اندراجات Ú©Ùˆ نظر انداز کر دیا جائے گا۔</translation>
+<translation id="2535585790302968248">نجی طور پر براؤز کرنے کے لیے ایک نیا پوشیدگی ٹیب کھولیں</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{اور 1 مزید}other{اور # مزید}}</translation>
<translation id="2536110899380797252">Ù¾ØªÛ Ø´Ø§Ù…Ù„ کریں</translation>
<translation id="2539524384386349900">پتا لگائیں</translation>
@@ -523,7 +546,14 @@
<translation id="2597378329261239068">ÛŒÛ Ø¯Ø³ØªØ§ÙˆÛŒØ² پاس ورڈ Ú©Û’ Ø°Ø±ÛŒØ¹Û ØªØ­Ùظ یاÙØªÛ ÛÛ’Û” Ø¨Ø±Ø§Û Ú©Ø±Ù… ایک پاس ورڈ درج کریں۔</translation>
<translation id="2609632851001447353">تغیرات</translation>
<translation id="2610561535971892504">کلک کر کے کاپی کریں</translation>
+<translation id="2617988307566202237">â€Chrome درج ذیل معلومات Ú©Ùˆ <ph name="BEGIN_EMPHASIS" />محÙوظ Ù†Ûیں کرے گا<ph name="END_EMPHASIS" />:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />آپ کی براؤزنگ کی سرگزشت
+ <ph name="LIST_ITEM" />کوکیز اور سائٹ ڈیٹا
+ <ph name="LIST_ITEM" />Ùارمز میں درج Ú©Ø±Ø¯Û Ù…Ø¹Ù„ÙˆÙ…Ø§Øª
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 ‎(Envelope‎)‎</translation>
+<translation id="2623663032199728144">آپ Ú©ÛŒ اسکرینز Ú©Û’ بارے میں معلومات کا استعمال کرنے Ú©Û’ لیے پوچھ سکتی Ûیں</translation>
<translation id="2625385379895617796">آپ Ú©ÛŒ Ú¯Ú¾Ú‘ÛŒ Ø¢Ú¯Û’ ÛÛ’</translation>
<translation id="262745152991669301">â€Ø³Ø§Ø¦Ù¹ USB آلات سے منسلک Ûونے کیلئے پوچھ سکتی ÛÛ’</translation>
<translation id="2629325967560697240">â€Chrome Ú©ÛŒ اعلی ترین سیکیورٹی حاصل کرنے Ú©Û’ لیے <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />بÛتر Ú©Ø±Ø¯Û Ø­Ùاظت Ú©Ùˆ آن کریں<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -557,6 +587,7 @@
<translation id="2709516037105925701">آٹو ÙÙ„</translation>
<translation id="2713444072780614174">سÙید</translation>
<translation id="2715612312510870559">â€<ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />ØŒ Chrome Ú©ÛŒ ترتیبات میں اپنی ادائیگیوں اور کریڈٹ کارڈ Ú©ÛŒ معلومات کا نظم کرنے Ú©Û’ لیے ٹیب، پھر اینٹر دبائیں</translation>
+<translation id="271663710482723385">پوری اسکرین سے باÛر نکلنے کیلئے |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| Ú©Ùˆ دبائیں</translation>
<translation id="2721148159707890343">درخواست کامیاب رÛÛŒ</translation>
<translation id="2723669454293168317">â€Chrome Ú©ÛŒ ترتیبات میں سیÙÙ¹ÛŒ چیک چلائیں</translation>
<translation id="2726001110728089263">سائڈ ٹرے</translation>
@@ -587,6 +618,7 @@
<translation id="2850739647070081192">Invite ‎(Envelope‎)‎</translation>
<translation id="2856444702002559011">Ø­Ù…Ù„Û Ø¢ÙˆØ± <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> سے آپ Ú©ÛŒ معلومات (مثلاً، پاس ورڈز، پیغامات یا کریڈٹ کارڈز) چوری کرنے Ú©ÛŒ کوشش کر سکتے Ûیں۔ <ph name="BEGIN_LEARN_MORE_LINK" />مزید جانیں<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">ÛŒÛ Ø³Ø§Ø¦Ù¹ دخل انداز یا Ú¯Ù…Ø±Ø§Û Ú©Ù† اشتÛارات دکھاتی ÛÛ’Û”</translation>
+<translation id="286512204874376891">ورچوئل کارڈ آپ Ú©Û’ اصل کارڈ Ú©Ùˆ چھپاتا ÛÛ’ ØªØ§Ú©Û Ø¢Ù¾ Ú©ÛŒ Ù…Ù…Ú©Ù†Û Ø¯Ú¾ÙˆÚ©Û Ø¯ÛÛŒ سے Ø­Ùاظت کرنے میں مدد کر سکے۔ <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">دوستانÛ</translation>
<translation id="2876489322757410363">کسی خارجی ایپلیکیشن Ú©Û’ ذریعے ادائیگی کرنے Ú©Û’ لیے پوشیدگی وضع Ú©Ùˆ Ú†Ú¾ÙˆÚ‘ رÛÛ’ Ûیں۔ جاری رکھیں؟</translation>
<translation id="2876949457278336305">â€<ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />ØŒ Chrome Ú©ÛŒ ترتیبات میں محÙوظ براؤزنگ اور بÛت Ú©Ú†Ú¾ کا نظم کرنے Ú©Û’ لیے ٹیب پھر Enter دبائیں</translation>
@@ -611,6 +643,7 @@
<translation id="2930577230479659665">Ûر ایک کاپی Ú©Û’ بعد تراشیں</translation>
<translation id="2932085390869194046">پاس ورڈ تجویز کریں...</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019"><ph name="PROTOCOL" /> لنکس کھولیں</translation>
<translation id="2941952326391522266">ÛŒÛ Ø³Ø±ÙˆØ± ÛŒÛ Ø«Ø§Ø¨Øª Ù†Ûیں کر سکا Ú©Û ÛŒÛ <ph name="DOMAIN" /> ÛÛ’Ø› اس کا سیکیورٹی سرٹیÙکیٹ <ph name="DOMAIN2" /> Ú©ÛŒ جانب سے ÛÛ’Û” ÛŒÛ ØºÙ„Ø· Ú©Ù†Ùیگریشن یا آپ Ú©Û’ کنکشن میں مانع بن رÛÛ’ کسی Ø­Ù…Ù„Û Ø¢ÙˆØ± Ú©ÛŒ ÙˆØ¬Û Ø³Û’ ÛÙˆ سکتا ÛÛ’Û”</translation>
<translation id="2943895734390379394">اپ لوڈ کا وقت:</translation>
<translation id="2948083400971632585">آپ کنکشن کیلئے Ú©Ù†Ùیگر Ú©Ø±Ø¯Û Ú©Ø³ÛŒ بھی پراکسیز Ú©Ùˆ ترتیبات Ú©Û’ صÙØ­Û Ø³Û’ غیر Ùعال کر سکتے Ûیں۔</translation>
@@ -643,6 +676,7 @@
<translation id="3037605927509011580">ارے، رکیں!</translation>
<translation id="3041612393474885105">سرٹیÙکیٹ Ú©ÛŒ معلومات</translation>
<translation id="3044034790304486808">اپنی ریسرچ Ø¯ÙˆØ¨Ø§Ø±Û Ø´Ø±ÙˆØ¹ کریں</translation>
+<translation id="305162504811187366">â€Ø¨Ø´Ù…ول ٹائم سٹیمپس، میزبانوں اور کلائنٹ سیشن IDs Ú©Û’ Chrome ریموٹ ڈیسک ٹاپ Ú©ÛŒ سرگزشت</translation>
<translation id="3060227939791841287">C9 ‎(Envelope‎)‎</translation>
<translation id="3061707000357573562">پیچ سروس</translation>
<translation id="306573536155379004">گیم شروع ÛÙˆ گئی۔</translation>
@@ -684,6 +718,7 @@
<translation id="3197136577151645743">آپ اپنے آلے کا Ùعال طور پر استعمال کب کر رÛÛ’ Ûیں ÛŒÛ Ø¬Ø§Ù†Ù†Û’ کیلئے سائٹ پوچھ سکتی ÛÛ’</translation>
<translation id="3202497928925179914">â€<ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />ØŒ آپ Chrome Ú©ÛŒ ترتیبات میں Ú©Ù† معلومات Ú©Ùˆ مطابقت پذیر بناتے Ûیں ان کا نظم کرنے Ú©Û’ لئے ٹیب پھر اینٹر دبائیں</translation>
<translation id="320323717674993345">ادائیگی منسوخ کریں</translation>
+<translation id="3203366800380907218">ویب سے</translation>
<translation id="3207960819495026254">بÙÚ© مارک بنایا Ûوا</translation>
<translation id="3209034400446768650">صÙØ­Û Ù¾ÛŒØ³Û’ چارج کر سکتا ÛÛ’</translation>
<translation id="3212581601480735796"><ph name="HOSTNAME" /> پر آپ Ú©ÛŒ سرگرمی پر نظر رکھی جا رÛÛŒ ÛÛ’</translation>
@@ -700,10 +735,12 @@
<translation id="3234666976984236645">اس سائٹ پر اÛÙ… مواد کا ÛÙ…ÛŒØ´Û Ù¾ØªØ§ لگائیں</translation>
<translation id="3240683217920639535">â€<ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />ØŒ اپنے براؤزر Ú©ÛŒ Ø´Ú©Ù„ Ú©Ùˆ حسب ضرورت بنانے کیلئے ٹیب پھر Enter دبائیں</translation>
<translation id="3240791268468473923">ادائیگی Ú©ÛŒ اسناد محÙوظ کریں کوئی مماثل اسناد Ù†Ûیں Ú©ÛŒ شیٹ Ú©Ú¾Ù„ÛŒ Ûوئی ÛÛ’</translation>
+<translation id="324180406144491771">“<ph name="HOST_NAME" />†لنکس مسدود Ûیں</translation>
<translation id="3249845759089040423">دلکش</translation>
<translation id="3252266817569339921">Ùرانسيسی</translation>
<translation id="3257954757204451555">اس معلومات Ú©Û’ پیچھے کون ÛÛ’ØŸ</translation>
<translation id="3259648571731540213">â€<ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />ØŒ Google کیلنڈر میں تیزی سے ایک نیا ایونٹ تخلیق کرنے کیلئے TabØŒ پھر Enter دبائیں</translation>
+<translation id="3261488570342242926">ورچوئل کارڈز کے بارے میں جانیں</translation>
<translation id="3264837738038045344">â€Chrome Ú©ÛŒ ترتیبات Ú©Û’ بٹن کا نظم کریں، اپنے Chrome Ú©ÛŒ ترتیبات Ù…Ù„Ø§Ø­Ø¸Û Ú©Ø±Ù†Û’ Ú©Û’ لیے اینٹر دبائیں</translation>
<translation id="3266793032086590337">قدر (متضاد)</translation>
<translation id="3268451620468152448">کھلے ٹیبز</translation>
@@ -717,6 +754,7 @@
<translation id="3288238092761586174">آپ Ú©ÛŒ ادائیگی Ú©ÛŒ تصدیق Ú©Û’ لیے <ph name="URL" /> Ú©Ùˆ اضاÙÛŒ اقدامات کرنے Ú©ÛŒ ضرورت Ù¾Ú‘ سکتی ÛÛ’</translation>
<translation id="3293642807462928945"><ph name="POLICY_NAME" /> پالیسی کے بارے میں مزید جانیں</translation>
<translation id="3295444047715739395">â€Chrome ترتیبات میں اپنے پاس ورڈز دیکھیں اور ان کا نظم کریں</translation>
+<translation id="3303795387212510132">ایپ کو <ph name="PROTOCOL_SCHEME" /> لنکس کھولنے کی اجازت دیں؟</translation>
<translation id="3303855915957856445">تلاش Ú©Û’ کوئی نتائج Ù†Ûیں ملے</translation>
<translation id="3304073249511302126">بلوٹوتھ اسکیننگ</translation>
<translation id="3308006649705061278">â€ØªÙ†Ø¸ÛŒÙ…ÛŒ اکائی (OU)</translation>
@@ -730,12 +768,6 @@
<translation id="3345782426586609320">آنکھیں</translation>
<translation id="3355823806454867987">پراکسی ترتیبات تبدیل کریں…</translation>
<translation id="3360103848165129075">ادائیگی Ûینڈلر Ú©ÛŒ شیٹ</translation>
-<translation id="3361596688432910856">â€Chrome Ù…Ù†Ø¯Ø±Ø¬Û Ø°ÛŒÙ„ معلومات Ú©Ùˆ <ph name="BEGIN_EMPHASIS" />محÙوظ Ù†Ûیں کرے گا<ph name="END_EMPHASIS" />:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />آپ کی براؤزنگ سرگزشت
- <ph name="LIST_ITEM" />کوکیز اور سائٹ ڈیٹا
- <ph name="LIST_ITEM" />Ùارمز میں درج Ú©Ø±Ø¯Û Ù…Ø¹Ù„ÙˆÙ…Ø§Øª
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">ÛŒÛ Ù¾Ø§Ù„ÛŒØ³ÛŒ خودکار طور پر ÙØ±Ø³ÙˆØ¯Û <ph name="OLD_POLICY" /> پالیسی سے کاپی Ú©ÛŒ گئی تھی۔ اس Ú©ÛŒ بجائے، آپ Ú©Ùˆ اس کا پالیسی کا استعمال کرنا چاÛیے۔</translation>
<translation id="3364869320075768271"><ph name="URL" /> آپ کا ورچوئل ریئلٹی Ø¢Ù„Û Ø§ÙˆØ± ڈیٹا استعمال کرنا چاÛتا ÛÛ’</translation>
<translation id="3366477098757335611">کارڈز دیکھیں</translation>
@@ -818,7 +850,6 @@
<translation id="3587738293690942763">وسطی</translation>
<translation id="3592413004129370115">Italian ‎(Envelope‎)‎</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{آپ کسی بھی وقت اپنے گروپ Ú©Ùˆ ری سیٹ کر سکتے Ûیں۔ ایک نئے گروپ میں شامل Ûونے Ú©Û’ لیے ایک دن لگتا ÛÛ’Û”}=1{آپ کسی بھی وقت اپنے گروپ Ú©Ùˆ ری سیٹ کر سکتے Ûیں۔ ایک نئے گروپ میں شامل Ûونے Ú©Û’ لیے ایک دن لگتا ÛÛ’Û”}other{آپ کسی بھی وقت اپنے گروپ Ú©Ùˆ ری سیٹ کر سکتے Ûیں۔ ایک نئے گروپ میں شامل Ûونے Ú©Û’ لیے {NUM_DAYS} دن لگتے Ûیں۔}}</translation>
-<translation id="3596012367874587041">ایپ کی ترتیبات</translation>
<translation id="3600246354004376029"><ph name="TITLE" />، <ph name="DOMAIN" />، <ph name="TIME" /></translation>
<translation id="3603507503523709">ایپلیکیشن کو آپ کے منتظم کے ذریعے مسدود کیا گیا</translation>
<translation id="3608932978122581043">سمت بندی Ùیڈ کریں</translation>
@@ -861,6 +892,7 @@
<translation id="370972442370243704">صار٠کا ØªØ¬Ø±Ø¨Û Ø¢Ù† کریں</translation>
<translation id="3711895659073496551">معطل</translation>
<translation id="3712624925041724820">لائسنسز ختم Ûوگئے</translation>
+<translation id="3714633008798122362">ویب کیلنڈر</translation>
<translation id="3714780639079136834">â€Ù…وبائل ڈیٹا یا Wi-Fi آن ÛÙˆ رÛا ÛÛ’</translation>
<translation id="3715597595485130451">â€Wi-Fi سے منسلک ÛÙˆÚº</translation>
<translation id="3717027428350673159">â€<ph name="BEGIN_LINK" />پراکسی، Ùائروال اور DNS Ú©Ù†Ùیگریشن Ú©Ùˆ چیک کیا جا رÛا ÛÛ’<ph name="END_LINK" /></translation>
@@ -922,6 +954,7 @@
<translation id="3906954721959377182">ٹیبلیٹ</translation>
<translation id="3909477809443608991">â€<ph name="URL" /> ایک تحÙظ یاÙØªÛ Ù…ÙˆØ§Ø¯ چلانا چاÛتا ÛÛ’Û” Google آپ Ú©Û’ آلے Ú©ÛŒ شناخت کرے گا اور عین ممکن ÛÛ’ Ú©Û ÛŒÛ Ø³Ø§Ø¦Ù¹ اس تک رسائی حاصل کرے۔</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">مسترد کریں</translation>
<translation id="3939773374150895049">â€CVC Ú©Û’ بجائے WebAuthn کا استعمال کریں؟</translation>
<translation id="3946209740501886391">اس سائٹ پر ÛÙ…ÛŒØ´Û Ù¾ÙˆÚ†Ú¾ÛŒÚº</translation>
<translation id="3947595700203588284">â€Ø³Ø§Ø¦Ù¹ MIDI آلات سے منسلک Ûونے کیلئے پوچھ سکتی ÛÛ’</translation>
@@ -943,6 +976,7 @@
<translation id="3990250421422698716">جاگ آÙسیٹ</translation>
<translation id="3996311196211510766">اس سائٹ <ph name="ORIGIN" /> Ù†Û’ درخواست Ú©ÛŒ ÛÛ’ Ú©Û Ø§ÛŒÚ© ماخذ پالیسی کا اطلاق
اس سے Ú©ÛŒ جانے والی سبھی درخواستوں پر کیا جائے، لیکن ÙÛŒ الحال اس پالیسی Ú©Ùˆ لاگو Ù†Ûیں کیا جا سکتا۔</translation>
+<translation id="4009243425692662128">â€Ø¢Ù¾ Ú©Û’ پرنٹ Ú©Ø±Ø¯Û ØµÙحات کا مواد ØªØ¬Ø²ÛŒÛ Ú©Û’ لیے Google کلاؤڈ یا Ùریقین ثالث Ú©Ùˆ بھیجا جاتا ÛÛ’Û” مثال Ú©Û’ طور پر، اسے حساس ڈیٹا کیلئے اسکین کیا جا سکتا ÛÛ’Û”</translation>
<translation id="4010758435855888356">اسٹوریج تک رسائی کی اجازت دیں؟</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{â€{COUNT} صÙØ­Û Ù¾Ø± مشتمل PDF دستاویز}other{â€{COUNT} صÙحات پر مشتمل PDF دستاویز}}</translation>
<translation id="4023431997072828269">Ú†ÙˆÙ†Ú©Û ÛŒÛ Ùارم ایک ایسے کنکشن کا استعمال کر Ú©Û’ جمع کیا جا رÛا ÛÛ’ جو محÙوظ Ù†Ûیں ÛÛ’ آپ Ú©ÛŒ معلومات دوسروں Ú©Ùˆ دکھائی دیں گی۔</translation>
@@ -1037,6 +1071,7 @@
<translation id="4250680216510889253">Ù†Ûیں</translation>
<translation id="4253168017788158739">نوٹ</translation>
<translation id="425582637250725228">ممکن ÛÛ’ Ú©Û Ø¢Ù¾ Ú©ÛŒ تبدیلیاں محÙوظ Ù†Û ÛÙˆÚºÛ”</translation>
+<translation id="425869179292622354">ورچوئل کارڈ Ú©Û’ ساتھ اسے مزید محÙوظ بنائیں؟</translation>
<translation id="4258748452823770588">غلط دستخط</translation>
<translation id="4261046003697461417">تحÙظ یاÙØªÛ Ø¯Ø³ØªØ§ÙˆÛŒØ²Ø§Øª Ú©ÛŒ تشریح Ù†Ûیں Ú©ÛŒ جا سکتی</translation>
<translation id="4265872034478892965">آپ Ú©Û’ منتظم Ú©ÛŒ جانب سے اجازت یاÙتÛ</translation>
@@ -1099,6 +1134,7 @@
<translation id="4434045419905280838">پوپ اپس اور ری ڈائریکٹس</translation>
<translation id="4435702339979719576">Postcard)‎</translation>
<translation id="443673843213245140">پراکسی کا استعمال غیر Ùعال کر دیا گیا ÛÛ’ لیکن ایک واضح پراکسی Ú©Ù†Ùیگریشن متعین Ú©ÛŒ گئی ÛÛ’Û”</translation>
+<translation id="4441832193888514600">نظر انداز کر دیا گیا Ú©ÛŒÙˆÙ†Ú©Û Ù¾Ø§Ù„ÛŒØ³ÛŒ صر٠کلاؤڈ صار٠کی پالیسی Ú©Û’ بطور سیٹ Ú©ÛŒ جا سکتی ÛÛ’Û”</translation>
<translation id="4450893287417543264">Ø¯ÙˆØ¨Ø§Ø±Û Ù†Û Ø¯Ú©Ú¾Ø§Ø¦ÛŒÚº</translation>
<translation id="4451135742916150903">â€Ø³Ø§Ø¦Ù¹ HID آلات سے منسلک Ûونے کیلئے پوچھ سکتی ÛÛ’</translation>
<translation id="4452328064229197696">â€Ø¢Ù¾ Ù†Û’ ابھی جو پاس ورڈ استعمال کیا ÙˆÛ ÚˆÛŒÙ¹Ø§ Ú©ÛŒ خلا٠ورزی میں پایا گیا۔ اپنے اکاؤنٹس محÙوظ کرنے Ú©Û’ لیے، Google پاس ورڈ مینیجر آپ Ú©Û’ محÙوظ Ú©Ø±Ø¯Û Ù¾Ø§Ø³ ورڈز Ú©Ùˆ چیک کرنے Ú©ÛŒ تجویز کرتا ÛÛ’Û”</translation>
@@ -1154,6 +1190,7 @@
<translation id="4628948037717959914">تصویر</translation>
<translation id="4631649115723685955">کیش بیک لنک Ú©Ø±Ø¯Û ÛÛ’</translation>
<translation id="4636930964841734540">معلومات</translation>
+<translation id="4638670630777875591">â€Chromium میں پوشیدگی وضع</translation>
<translation id="464342062220857295">خصوصیات تلاش کریں</translation>
<translation id="4644670975240021822">اÙلٹ ترتیب میں، صÙحات کا رÙØ® نیچے Ú©ÛŒ جانب</translation>
<translation id="4646534391647090355">اب مجھے ÙˆÛاں Ù„Û’ چلیں</translation>
@@ -1174,6 +1211,7 @@
<translation id="4708268264240856090">آپ Ú©Û’ کنکشن میں مداخلت Ûوگئی</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131">â€<ph name="BEGIN_LINK" />Windows نیٹ ورک Ú©ÛŒ تشخیصات چلانے Ú©ÛŒ<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426"><ph name="USERNAME" /> کے لیے پاس ورڈ</translation>
<translation id="4724144314178270921">سائٹ آپ Ú©Û’ کلپ بورڈ پر ٹیکسٹ اور تصاویر دیکھنے کیلئے پوچھ سکتی ÛÛ’</translation>
<translation id="4726672564094551039">پالیسیاں Ø¯ÙˆØ¨Ø§Ø±Û Ù„ÙˆÚˆ کریں</translation>
<translation id="4728558894243024398">پلیٹ Ùارم</translation>
@@ -1195,6 +1233,7 @@
<translation id="4757993714154412917">â€Ø¢Ù¾ Ù†Û’ ابھی ایک Ù¾ÙرÙریب سائٹ پر اپنا پاس ورڈ درج کیا ÛÛ’Û” اپنے اکاؤنٹس Ú©Ùˆ محÙوظ کرنے Ú©Û’ لیے، Chromium آپ Ú©Û’ محÙوظ Ú©Ø±Ø¯Û Ù¾Ø§Ø³ ورڈز Ú©Ùˆ چیک کرنے Ú©ÛŒ تجویز کرتا ÛÛ’Û”</translation>
<translation id="4758311279753947758">رابطے کی معلومات شامل کریں</translation>
<translation id="4761104368405085019">اپنا مائیکروÙون استعمال کریں</translation>
+<translation id="4761869838909035636">â€Chrome کا سیÙÙ¹ÛŒ چیک چلائیں</translation>
<translation id="4764776831041365478"><ph name="URL" /> پر موجود ویب صÙØ­Û Ø¹Ø§Ø±Ø¶ÛŒ طور پر سست ÛÙˆ سکتا ÛÛ’ یا اسے مستقل طور پر ایک نئے ویب پتے پر منتقل کیا گیا ÛÙˆ سکتا ÛÛ’Û”</translation>
<translation id="4766713847338118463">نیچے دÙÛری سٹیپل</translation>
<translation id="4771973620359291008">ایک نامعلوم خرابی پیش آگئی ÛÛ’Û”</translation>
@@ -1215,12 +1254,6 @@
<translation id="4819347708020428563">ÚˆÛŒÙالٹ منظر میں تشریحات میں ترمیم کریں؟</translation>
<translation id="4825496307559726072">â€<ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />ØŒ تیزی سے ایک نئی Google Sheet تخلیق کرنے کیلئے TabØŒ پھر Enter دبائیں</translation>
<translation id="4825507807291741242">طاقتور</translation>
-<translation id="4827402517081186284">پوشیدگی وضع آپ Ú©Ùˆ آن لائن غیر مرئی Ù†Ûیں کرتی ÛÛ’:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />سائٹس Ú©Ùˆ معلوم Ûوتا ÛÛ’ Ú©Û Ø¢Ù¾ کب انÛیں Ù…Ù„Ø§Ø­Ø¸Û Ú©Ø±ØªÛ’ Ûیں<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />آجر یا اسکول براؤزنگ Ú©ÛŒ سرگرمی Ú©Ùˆ ٹریک کر سکتے Ûیں<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />انٹرنیٹ سروس پرووائیڈرز ویب ٹریÙÚ© Ú©Ùˆ مانیٹر کر سکتے Ûیں<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">وارننگز کو آن کریں</translation>
<translation id="4838327282952368871">خیالی</translation>
<translation id="4840250757394056958">â€Ø§Ù¾Ù†Û’ Chrome Ú©ÛŒ سرگزشت دیکھیں</translation>
@@ -1232,12 +1265,12 @@
<translation id="4854362297993841467">ڈیلیوری کا ÛŒÛ Ø·Ø±ÛŒÙ‚Û Ø¯Ø³ØªÛŒØ§Ø¨ Ù†Ûیں ÛÛ’Û” کوئی دوسرا Ø·Ø±ÛŒÙ‚Û Ø¢Ø²Ù…Ø§Ø¦ÛŒÚºÛ”</translation>
<translation id="4854853140771946034">â€Google Keep میں تیزی سے ایک نیا نوٹ تخلیق کریں</translation>
<translation id="485902285759009870">Ú©ÙˆÚˆ Ú©ÛŒ توثیق ÛÙˆ رÛÛŒ ÛÛ’...</translation>
+<translation id="4866506163384898554">اپنا کرسر دکھانے کے لیے |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| دبائیں</translation>
<translation id="4876188919622883022">Ø³Ø§Ø¯Û Ù…Ù†Ø¸Ø±</translation>
<translation id="4876305945144899064">کوئی صار٠نام Ù†Ûیں ÛÛ’</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{کوئی Ù†Ûیں}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />ØŒ <ph name="EXAMPLE_DOMAIN_2" />}other{<ph name="EXAMPLE_DOMAIN_1" />ØŒ <ph name="EXAMPLE_DOMAIN_2" />ØŒ <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831"><ph name="TEXT" /> تلاش کریں</translation>
<translation id="4879491255372875719">خودکار (ÚˆÛŒÙالٹ)</translation>
-<translation id="4879725228911483934">ونڈوز کھولیں اور اپنی اسکرینز پر رکھیں</translation>
<translation id="4880827082731008257">تلاش کی سرگزشت</translation>
<translation id="4881695831933465202">کھولیں</translation>
<translation id="4885256590493466218">چیک آؤٹ کرنے پر <ph name="CARD_DETAIL" /> سے ادائیگی کریں۔</translation>
@@ -1246,6 +1279,7 @@
<translation id="4895877746940133817"><ph name="TYPE_1" />، <ph name="TYPE_2" />، <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">نواں ٹرے</translation>
<translation id="4901778704868714008">محÙوظ کریں...</translation>
+<translation id="4905659621780993806"><ph name="DATE" /> Ú©Ùˆ <ph name="TIME" /> پر آپ کا منتظم خودکار طور پر آپ Ú©Û’ آلے Ú©Ùˆ ری اسٹارٹ کرے گا۔ اپنے آلے Ú©Û’ ری اسٹارٹ Ûونے سے Ù¾ÛÙ„Û’ کسی بھی Ú©Ú¾Ù„Û’ آئٹم Ú©Ùˆ محÙوظ کریں۔</translation>
<translation id="4913987521957242411">اوپر بائیں طر٠Ùولڈ</translation>
<translation id="4918221908152712722"><ph name="APP_NAME" /> انسٹال کریں (ڈاؤن لوڈ درکار Ù†Ûیں ÛÛ’)</translation>
<translation id="4923459931733593730">ادائیگی</translation>
@@ -1254,6 +1288,7 @@
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101">â€<ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />ØŒ تلاش کرنے کیلئے TabØŒ پھر Enter دبائیں</translation>
<translation id="4930153903256238152">بڑی گنجائش</translation>
+<translation id="4940163644868678279">â€Chrome میں پوشیدگی وضع</translation>
<translation id="4943872375798546930">کوئی نتائج Ù†Ûیں Ûیں</translation>
<translation id="4950898438188848926">â€Ù¹ÛŒØ¨ پر سوئچ کرنے کا بٹن، Ú©Ú¾Ù„Û’ Ûوئے ٹیب پر سوئچ کرنے Ú©Û’ لیے Enter دبائیں، <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="495170559598752135">کارروائیاں</translation>
@@ -1263,6 +1298,7 @@
<translation id="4968522289500246572">ÛŒÛ Ø§ÛŒÙ¾ موبائل کیلئے ڈیزائن Ú©ÛŒ گئی ÛÛ’ اور ممکن ÛÛ’ Ú©Û Ø§Ø³ کا سائز صحیح طریقے سے تبدیل Ù†Û ÛÙˆÛ” اس Ú©Ùˆ استعمال کرنے میں مسائل کا سامنا ÛÙˆ سکتا ÛÛ’ یا ری اسٹارٹ کرنا Ù¾Ú‘ سکتی ÛÛ’Û”</translation>
<translation id="4969341057194253438">ریکارڈنگ حذ٠کریں</translation>
<translation id="4973922308112707173">اوپر دÙÛرا سوراخ</translation>
+<translation id="4976702386844183910">آخری بار Ù…Ù„Ø§Ø­Ø¸Û Ú©Ø±Ø¯Û <ph name="DATE" /></translation>
<translation id="4984088539114770594">مائیکروÙون کا استعمال کریں؟</translation>
<translation id="4984339528288761049">Prc5 ‎(Envelope‎)‎</translation>
<translation id="4989163558385430922">سبھی دیکھیں</translation>
@@ -1324,6 +1360,7 @@
<translation id="5138227688689900538">کم دکھائیں</translation>
<translation id="5145883236150621069">خرابی Ú©ÙˆÚˆ پالیسی جواب میں موجود ÛÛ’</translation>
<translation id="5146995429444047494"><ph name="ORIGIN" /> کیلئے اطلاعات مسدود Ûیں</translation>
+<translation id="514704532284964975">â€<ph name="URL" /> NFC آلات پر معلومات دیکھنا اور تبدیل کرنا چاÛتا ÛÛ’ جسے آپ اپنے Ùون سے تھپتھپاتے Ûیں</translation>
<translation id="5148809049217731050">سامنے</translation>
<translation id="515292512908731282">C4 ‎(Envelope‎)‎</translation>
<translation id="5158275234811857234">سر ورق</translation>
@@ -1348,6 +1385,7 @@
<translation id="5215116848420601511">â€Google Pay استعمال کرنے والے ادائیگی Ú©Û’ طریقے اور پتے</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">ٹرے 13</translation>
+<translation id="5216942107514965959">آخری بار آج Ù…Ù„Ø§Ø­Ø¸Û Ú©ÛŒØ§ گیا</translation>
<translation id="5222812217790122047">ای میل مطلوب ÛÛ’</translation>
<translation id="5230733896359313003">ترسیل کا پتÛ</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1368,7 +1406,6 @@
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">دستاویز کی خصوصیات</translation>
<translation id="528468243742722775">اختتام</translation>
-<translation id="5284909709419567258">نیٹ ورک کے پتے</translation>
<translation id="5285570108065881030">سبھی محÙوظ پاسورڈز دکھائيں</translation>
<translation id="5287240709317226393">کوکیز دکھائیں</translation>
<translation id="5287456746628258573">ÛŒÛ Ø³Ø§Ø¦Ù¹ پرانی سیکیورٹی Ú©Ù†Ùیگریشن Ú©Ùˆ استعمال کر رÛÛŒ ÛÛ’ جو اس سائٹ پر بھیجے جانے پر آپ Ú©ÛŒ معلومات (مثلاً، پاس ورڈز یا کریڈٹ کارڈ نمبرز) Ú©Ùˆ ظاÛر کر سکتی ÛÛ’Û”</translation>
@@ -1452,6 +1489,7 @@
<translation id="5556459405103347317">Ø¯ÙˆØ¨Ø§Ø±Û Ù„ÙˆÚˆ کریں</translation>
<translation id="5560088892362098740">تاریخ اختتام</translation>
<translation id="55635442646131152">دستاویز کی آؤٹ لائن</translation>
+<translation id="5565613213060953222">پوشیدگی ٹیب کھولیں</translation>
<translation id="5565735124758917034">Ùعال</translation>
<translation id="5570825185877910964">اکاؤنٹ محÙوظ کریں</translation>
<translation id="5571083550517324815">اس پتے سے Ù¾ÙÚ© اپ Ù†Ûیں کر سکتے۔ کوئی Ù…Ø®ØªÙ„Ù Ù¾ØªÛ Ù…Ù†ØªØ®Ø¨ کریں۔</translation>
@@ -1534,6 +1572,7 @@
<translation id="5869522115854928033">محÙوظ Ú©Ø±Ø¯Û Ù¾Ø§Ø³ ورڈز</translation>
<translation id="5873013647450402046">آپ کا بینک تصدیق کرنا چاÛتا ÛÛ’ Ú©Û ÛŒÛ Ø§Ù“Ù¾ Ûیں۔</translation>
<translation id="5887400589839399685">کارڈ محÙوظ کیا گیا</translation>
+<translation id="5887687176710214216">آخری بار Ú¯Ø²Ø´ØªÛ Ú©Ù„ چیک کیا گیا</translation>
<translation id="5895138241574237353">Ø¯ÙˆØ¨Ø§Ø±Û Ø´Ø±ÙˆØ¹ کریں</translation>
<translation id="5895187275912066135">تاریخ اجراء</translation>
<translation id="5901630391730855834">پیلا</translation>
@@ -1547,6 +1586,7 @@
<translation id="5921639886840618607">â€Ú©Ø§Ø±Úˆ Ú©Ùˆ Google اکاؤنٹ میں محÙوظ کریں؟</translation>
<translation id="5922853866070715753">تقریباً مکمل ÛÙˆ گیا</translation>
<translation id="5932224571077948991">سائٹ دخل انداز یا Ú¯Ù…Ø±Ø§Û Ú©Ù† اشتÛارات دکھاتی ÛÛ’</translation>
+<translation id="5938153366081463283">ورچوئل کارڈ شامل کریں</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347"><ph name="SITE_NAME" /> Ú©Ú¾Ù„ رÛÛŒ Ûے…</translation>
<translation id="5951495562196540101">صار٠اکاؤنٹ Ú©Û’ ذریعے اندراج Ù†Ûیں کر سکتے (پیکیج Ø´Ø¯Û Ù„Ø§Ø¦Ø³Ù†Ø³ دستیاب ÛÛ’)Û”</translation>
@@ -1611,6 +1651,7 @@
<translation id="6120179357481664955">â€Ø¢Ù¾ Ú©ÛŒ UPI ID یاد رکھیں؟</translation>
<translation id="6124432979022149706">â€Chrome Enterprise کنیکٹرز</translation>
<translation id="6127379762771434464">آئٹم Ûٹا دیا گیا</translation>
+<translation id="6132161237766805930">â€<ph name="BEGIN_LINK" />Chrome میں پوشیدگی وضع Ú©Û’ بارے میں مزید جانیں<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">کوئی بھی کیبلز چیک کریں اور کوئی بھی
روٹرز، موڈمز
یا ان دیگر نیٹ ورک آلات Ú©Ùˆ ریبوٹ کریں جنÛیں آپ استعمال کر سکتے Ûیں۔</translation>
@@ -1624,7 +1665,6 @@
<translation id="6169916984152623906">اب آپ نجی طور پر براؤز کر سکتے Ûیں، اور اس آلے کا استعمال کرنے والے دوسرے لوگوں Ú©Ùˆ آپ Ú©ÛŒ سرگرمی Ù†Ûیں دکھائی دے گی۔ تاÛÙ…ØŒ ڈاؤن لوڈز اور بک مارکس محÙوظ ÛÙˆ جائیں Ú¯Û’Û”</translation>
<translation id="6177128806592000436">اس سائٹ سے آپ کا کنکشن محÙوظ Ù†Ûیں ÛÛ’</translation>
<translation id="6180316780098470077">Ø¯ÙˆØ¨Ø§Ø±Û Ú©ÙˆØ´Ø´ کرنے کا وقÙÛ</translation>
-<translation id="619448280891863779">سائٹ آپ Ú©ÛŒ سکرینز پر ونڈوز کھولنے اور رکھنے کیلئے پوچھ سکتی ÛÛ’</translation>
<translation id="6196640612572343990">Ùریق ثالث کوکیز Ú©Ùˆ مسدود کریں</translation>
<translation id="6203231073485539293">اپنا انٹرنیٹ کنکشن چیک کریں</translation>
<translation id="6218753634732582820">â€Chromium سے Ù¾ØªÛ Ûٹائیں؟</translation>
@@ -1647,7 +1687,7 @@
<translation id="6272383483618007430">â€Google اپ ڈیٹ</translation>
<translation id="6276112860590028508">آپ Ú©ÛŒ Ù¾Ú‘Ú¾Ù†Û’ Ú©ÛŒ ÙÛرست Ú©Û’ صÙحات ÛŒÛاں دکھائی دیتے Ûیں</translation>
<translation id="627746635834430766">â€Ø§Ú¯Ù„ÛŒ بار Ø²ÛŒØ§Ø¯Û ØªÛŒØ²ÛŒ سے ادائیگی کرنے Ú©Û’ لیے، اپنے کارڈ اور بلنگ Ù¾ØªÛ Ú©Ùˆ اپنے Google اکاؤنٹ میں محÙوظ کریں۔</translation>
-<translation id="6279098320682980337">ورچوئل کارڈ نمبر Ù¾Ùر Ù†Ûیں ÛÛ’ØŸ کاپی کرنے Ú©Û’ لیے کارڈ Ú©ÛŒ تÙصیلات پر Ú©Ù„Ú© کریں</translation>
+<translation id="6279183038361895380">اپنا کرسر دکھانے کیلئے |<ph name="ACCELERATOR" />| کو دبائیں</translation>
<translation id="6280223929691119688">اس پتے پر ڈیلیوری Ù†Ûیں ÛÙˆ سکتی۔ کوئی Ù…Ø®ØªÙ„Ù Ù¾ØªÛ Ù…Ù†ØªØ®Ø¨ کریں۔</translation>
<translation id="6282194474023008486">پوسٹل کوڈ</translation>
<translation id="6285507000506177184">â€Chrome بٹن میں ڈاؤن لوڈز کا نظم کریں، Chrome میں ڈاؤن لوڈ Ú©Ø±Ø¯Û Ø§Ù¾Ù†ÛŒ Ùائلز کا نظم کرنے Ú©Û’ لیے اینٹر دبائیں</translation>
@@ -1655,6 +1695,7 @@
<translation id="6290238015253830360">آپ Ú©Û’ تجویز Ú©Ø±Ø¯Û Ù…Ø¶Ø§Ù…ÛŒÙ† ÛŒÛاں ظاÛر Ûوتے Ûیں</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{آپ کا Ø¢Ù„Û Ø§Ø¨Ú¾ÛŒ ری اسٹارٹ Ûوگا}=1{آپ کا Ø¢Ù„Û 1 سیکنڈ میں ری اسٹارٹ Ûوگا}other{آپ کا Ø¢Ù„Û # سیکنڈ میں ری اسٹارٹ Ûوگا}}</translation>
<translation id="6302269476990306341">â€Chrome میں Google اسسٹنٹ موقو٠کی جا ر ÛÛŒ ÛÛ’</translation>
<translation id="6305205051461490394"><ph name="URL" /> ناقابل رسائی ÛÛ’Û”</translation>
<translation id="6312113039770857350">ویب صÙØ­Û Ø¯Ø³ØªÛŒØ§Ø¨ Ù†Ûیں ÛÛ’</translation>
@@ -1728,6 +1769,7 @@
<translation id="6529602333819889595">&amp;Ø¯ÙˆØ¨Ø§Ø±Û Ø­Ø°Ù Ú©Ø±ÛŒÚº</translation>
<translation id="6545864417968258051">بلوٹوتھ اسکیننگ</translation>
<translation id="6547208576736763147">بائیں طر٠دÙÛرا سوراخ</translation>
+<translation id="6554732001434021288">سائٹ آخری بار <ph name="NUM_DAYS" /> دن Ù¾ÛÙ„Û’ Ù…Ù„Ø§Ø­Ø¸Û Ú©ÛŒ گئی</translation>
<translation id="6556866813142980365">واپس لائیں</translation>
<translation id="6569060085658103619">آپ ایک ایکسٹینشن صÙØ­Û Ø¯ÛŒÚ©Ú¾ رÛÛ’ Ûیں</translation>
<translation id="6573200754375280815">دائیں طر٠دÙÛرا سوراخ</translation>
@@ -1788,7 +1830,6 @@
<translation id="6757797048963528358">آپ کا Ø¢Ù„Û Ø³ÛŒÙ„Ù¾ وضع میں چلا گیا۔</translation>
<translation id="6767985426384634228">Ù¾ØªÛ Ø§Ù¾ ڈیٹ کریں؟</translation>
<translation id="6768213884286397650">Hagaki ‎(Postcard)‎</translation>
-<translation id="6774185088257932239">پوشیدگی وضع کے بارے میں <ph name="BEGIN_LINK" />مزید جانیں<ph name="END_LINK" /></translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">وائلیٹ</translation>
<translation id="6786747875388722282">توسیعات</translation>
@@ -1872,7 +1913,6 @@
<translation id="706295145388601875">â€Chrome ترتیبات میں پتوں Ú©Ùˆ شامل کریں اور ان کا نظم کریں</translation>
<translation id="7064851114919012435">Ø±Ø§Ø¨Ø·Û Ú©ÛŒ معلومات</translation>
<translation id="7068733155164172741"><ph name="OTP_LENGTH" /> Ûندسے والا Ú©ÙˆÚˆ درج کریں</translation>
-<translation id="7070090581017165256">اس سائٹ کے بارے میں</translation>
<translation id="70705239631109039">آپ کا کنکشن مکمل طور پر محÙوظ Ù†Ûیں ÛÛ’</translation>
<translation id="7075452647191940183">درخواست کاÙÛŒ بڑی ÛÛ’</translation>
<translation id="7079718277001814089">ÛŒÛ Ø³Ø§Ø¦Ù¹ میلویئر پر مشتمل ÛÛ’</translation>
@@ -1889,6 +1929,12 @@
<translation id="7111012039238467737">(درست)</translation>
<translation id="7118618213916969306">â€Ú©Ù„Ù¾ بورڈ URL تلاش کریں، <ph name="SHORT_URL" /></translation>
<translation id="7119414471315195487">دیگر ٹیبز یا پروگرامز کو کھولیں</translation>
+<translation id="7129355289156517987">â€Ø¬Ø¨ آپ سبھی Chromium ونڈوز بند کرتے Ûیں تو ان ٹیبز پر آپ Ú©ÛŒ سرگرمی اس آلے سے صا٠ÛÙˆ جاتی ÛÛ’:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />براؤزنگ کی سرگرمی<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />تلاش کی سرگزشت<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Ùارمز میں درج Ú©Ø±Ø¯Û Ù…Ø¹Ù„ÙˆÙ…Ø§Øª<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">اس پتے پر ترسیل Ù†Ûیں ÛÙˆ سکتی۔ کوئی Ù…Ø®ØªÙ„Ù Ù¾ØªÛ Ù…Ù†ØªØ®Ø¨ کریں۔</translation>
<translation id="7132939140423847331">آپ Ú©Û’ منتظم Ù†Û’ اس ڈیٹا Ú©Û’ کاپی کیے جانے پر پابندی لگائی ÛÛ’Û”</translation>
<translation id="7135130955892390533">اسٹیٹس دکھائیں</translation>
@@ -1911,6 +1957,7 @@
<translation id="7192203810768312527"><ph name="SIZE" /> بچاتا ÛÛ’: آپ Ú©Û’ اگلے Ù…Ù„Ø§Ø­Ø¸Û Ù¾Ø± مزید Ø¢ÛØ³ØªÛ Ø³Û’ Ú©Ú†Ú¾ سائٹس لوڈ کر سکتا ÛÛ’Û”</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">آپ کا منتظم ÛŒÛ Ø¯ÛŒÚ©Ú¾ سکتا ÛÛ’:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />، نجی طور پر براؤز کرنے کے لیے ایک نیا پوشیدگی ٹیب کھولنے کی خاطر ٹیب، پھر اینٹر دبائیں</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> سیکیورٹی Ú©Û’ معیارات Ú©ÛŒ پابندی Ù†Ûیں کرتا ÛÛ’Û”</translation>
<translation id="7210993021468939304">â€Ú©Ù†Ù¹ÛŒÙ†Ø± Ú©Û’ اندر Linux Ú©ÛŒ سرگرمی اور کنٹینر Ú©Û’ اندر Linux ایپ Ú©Ùˆ انسٹال کرکے چلا سکتا ÛÛ’</translation>
@@ -1942,6 +1989,7 @@
<translation id="7304562222803846232">â€Google اکاؤنٹ Ú©ÛŒ رازداری کا نظم کریں</translation>
<translation id="7305756307268530424">آÛØ³ØªÛ Ø´Ø±ÙˆØ¹ کریں</translation>
<translation id="7308436126008021607">پس منظر کی مطابقت پذیری</translation>
+<translation id="7310392214323165548">Ø¢Ù„Û Ø¬Ù„Ø¯ÛŒ ÛÛŒ ری سٹارٹ ÛÙˆ جائے گا</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">کنکشن سے متعلق مدد</translation>
<translation id="7323804146520582233">"<ph name="SECTION" />" سیکشن چھپائیں</translation>
@@ -1949,6 +1997,7 @@
<translation id="7334320624316649418">Ø¯ÙˆØ¨Ø§Ø±Û ØªØ±ØªÛŒØ¨ Ú©Ùˆ &amp;واپس لائیں</translation>
<translation id="7335157162773372339">سائٹ آپ کا کیمرا استعمال کرنے کیلئے پوچھ سکتی ÛÛ’</translation>
<translation id="7337248890521463931">مزید لائنز دکھائیں</translation>
+<translation id="7337418456231055214">ورچوئل کارڈ نمبر Ù¾Ùر Ù†Ûیں ÛÛ’ØŸ کاپی کرنے Ú©Û’ لیے کارڈ Ú©ÛŒ تÙصیلات پر Ú©Ù„Ú© کریں۔ <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">آپ Ú©Û’ پلیٹ Ùارم پر دستیاب Ù†Ûیں ÛÛ’Û”</translation>
<translation id="733923710415886693">سرٹیÙیکیٹ Ú©ÛŒ Ø´ÙاÙیت Ú©Û’ ذریعے سرور Ú©Û’ سرٹیÙیکیٹ کا انکشا٠نÛیں کیا گیا۔</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1971,6 +2020,7 @@
<translation id="7378627244592794276">Ù†Ûیں</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">ناقابل اطلاق</translation>
+<translation id="7388594495505979117">{0,plural, =1{آپ کا Ø¢Ù„Û 1 منٹ میں ری اسٹارٹ Ûوگا}other{آپ کا Ø¢Ù„Û # منٹ میں ری اسٹارٹ Ûوگا}}</translation>
<translation id="7390545607259442187">کارڈ کی توثیق کریں</translation>
<translation id="7392089738299859607">Ù¾ØªÛ Ø§Ù¾ ڈیٹ کریں</translation>
<translation id="7399802613464275309">سیÙÙ¹ÛŒ چیک</translation>
@@ -2007,6 +2057,12 @@
<translation id="7485870689360869515">کوئی ڈیٹا Ù†Ûیں ملا۔</translation>
<translation id="7495528107193238112">ÛŒÛ Ù…ÙˆØ§Ø¯ مسدود ÛÛ’Û” مسئلے Ú©Ùˆ حل کرنے Ú©Û’ لیے سائٹ Ú©Û’ مالک سے Ø±Ø§Ø¨Ø·Û Ú©Ø±ÛŒÚºÛ”</translation>
<translation id="7497998058912824456">â€Ø¯Ø³ØªØ§ÙˆÛŒØ² تخلیق کریں بٹن، تیزی سے ایک نیا Google Doc تخلیق کرنے کیلئے Enter دبائیں</translation>
+<translation id="7506488012654002225">â€Chromium درج ذیل معلومات Ú©Ùˆ <ph name="BEGIN_EMPHASIS" />محÙوظ Ù†Ûیں کرے گا<ph name="END_EMPHASIS" />:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />آپ کی براؤزنگ کی سرگزشت
+ <ph name="LIST_ITEM" />کوکیز اور سائٹ ڈیٹا
+ <ph name="LIST_ITEM" />Ùارمز میں درج Ú©Ø±Ø¯Û Ù…Ø¹Ù„ÙˆÙ…Ø§Øª
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">â€ÙˆØ§Ù¾Ø³ Ú©Ø±Ø¯Û Ù¾Ø§Ù„ÛŒØ³ÛŒ Ø¢Ù„Û id خالی ÛÛ’ یا Ù…ÙˆØ¬ÙˆØ¯Û Ø¢Ù„Û id سے مماثل Ù†Ûیں ÛÛ’</translation>
<translation id="7508870219247277067">مَگَر ناشپاتی سبز</translation>
<translation id="7511955381719512146">â€Ø¢Ù¾ کا زیر استعمال Wi-Fi آپ سے <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> Ù…Ù„Ø§Ø­Ø¸Û Ú©Ø±Ù†Û’ کا ØªÙ‚Ø§Ø¶Û Ú©Ø± سکتا ÛÛ’Û”</translation>
@@ -2120,7 +2176,6 @@
<translation id="7813600968533626083">â€Chrome سے Ùارم Ú©ÛŒ تجویز Ûٹائیں؟</translation>
<translation id="781440967107097262">کلپ بورڈ کا اشتراک کریں؟</translation>
<translation id="7815407501681723534">'<ph name="SEARCH_STRING" />' کیلئے <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> ملے۔</translation>
-<translation id="782125616001965242">اس سائٹ کے بارے میں معلومات دکھائیں</translation>
<translation id="782886543891417279">â€Ø¢Ù¾ جو Wi-Fi استعمال کر رÛÛ’ Ûیں <ph name="WIFI_NAME" /> ÙˆÛ Ø¢Ù¾ سے اپنا لاگ ان صÙØ­Û Ù…Ù„Ø§Ø­Ø¸Û Ú©Ø±Ù†Û’ کا ØªÙ‚Ø§Ø¶Û Ú©Ø± سکتا ÛÛ’Û”</translation>
<translation id="7836231406687464395">Postfix ‎(Envelope‎)‎</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{کوئی Ù†Ûیں}=1{1 ایپ (<ph name="EXAMPLE_APP_1" />)}=2{2 ایپس (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}other{# ایپس (<ph name="EXAMPLE_APP_1" />ØŒ <ph name="EXAMPLE_APP_2" />ØŒ <ph name="AND_MORE" />)}}</translation>
@@ -2137,7 +2192,6 @@
<translation id="7888575728750733395">پرنٹ رینڈرنگ انٹینٹ</translation>
<translation id="7894280532028510793">اگر Ûجے درست Ûیں تو <ph name="BEGIN_LINK" />نیٹ ورک Ú©ÛŒ تشخیصات چلانے Ú©ÛŒ کوشش کریں<ph name="END_LINK" />Û”</translation>
<translation id="7904208859782148177">C3 ‎(Envelope‎)‎</translation>
-<translation id="7931318309563332511">نامعلوم</translation>
<translation id="793209273132572360">Ù¾ØªÛ Ø§Ù¾ ڈیٹ کریں؟</translation>
<translation id="7932579305932748336">کوٹ</translation>
<translation id="79338296614623784">ایک درست Ùون نمبر درج کریں</translation>
@@ -2162,13 +2216,14 @@
<translation id="7976214039405368314">بÛت Ø²ÛŒØ§Ø¯Û Ø¯Ø±Ø®ÙˆØ§Ø³ØªÛŒÚº</translation>
<translation id="7977538094055660992">آؤٹ پٹ آلÛ</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">اس کے ساتھ لنک کیا گيا</translation>
<translation id="798134797138789862">سائٹ ورچوئل رئیلٹی آلات اور ڈیٹا استعمال کرنے کیلئے پوچھ سکتی ÛÛ’</translation>
<translation id="7984945080620862648">â€Ø¢Ù¾ ابھی <ph name="SITE" /> Ù…Ù„Ø§Ø­Ø¸Û Ù†Ûیں کر سکتے Ûیں Ú©ÛŒÙˆÙ†Ú©Û ÙˆÛŒØ¨ سائٹ Ù†Û’ جلد بازی والی اسنادات بھیجی Ûیں جس پر Chrome کارروائی Ù†Ûیں کر سکتا ÛÛ’Û” نیٹ ورک Ú©ÛŒ خرابیاں اور حملے عموماً عارضی Ûوتے Ûیں Ù„Ûذا ÛŒÛ ØµÙØ­Û Ø´Ø§ÛŒØ¯ بعد میں کام کرے گا۔</translation>
-<translation id="79859296434321399">â€Ø§ÙØ²ÙˆØ¯Û Ø­Ù‚ÛŒÙ‚Øª کا مواد دیکھنے کیلئے، ARCore Ú©Ùˆ انسٹال کریں</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">باندھیں</translation>
<translation id="7992044431894087211"><ph name="APPLICATION_TITLE" /> Ú©Û’ ساتھ اسکرین Ú©Û’ اشتراک Ú©Ùˆ Ø¯ÙˆØ¨Ø§Ø±Û Ø´Ø±ÙˆØ¹ کر دیا گیا</translation>
<translation id="7995512525968007366">متعین Ù†Ûیں ÛÛ’</translation>
+<translation id="7998269595945679889">پوشیدگی ٹیب بٹن کھولیں، نجی طور پر براؤز کرنے کی خاطر نیا پوشیدگی ٹیب کھولنے کے لیے اینٹر دبائیں</translation>
<translation id="800218591365569300">میموری خالی کرنے کیلئے دیگر ٹیبز یا پروگرامز کو بند کرنے کی کوشش کریں۔</translation>
<translation id="8004582292198964060">براؤزر</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{ÛŒÛ Ú©Ø§Ø±Úˆ اور اس کا بلنگ Ù¾ØªÛ Ù…Ø­Ùوظ ÛÙˆ جائے گا۔ <ph name="USER_EMAIL" /> میں سائن ان Ûونے پر آپ اس کا استعمال کر سکیں Ú¯Û’Û”}other{ÛŒÛ Ú©Ø§Ø±ÚˆØ² اور ان Ú©Û’ بلنگ پتے محÙوظ ÛÙˆ جائیں Ú¯Û’Û” <ph name="USER_EMAIL" /> میں سائن ان Ûونے پر آپ ان کا استعمال کر سکیں Ú¯Û’Û”}}</translation>
@@ -2228,6 +2283,7 @@
<translation id="8202370299023114387">تصادم</translation>
<translation id="8206978196348664717">Prc4 ‎(Envelope‎)‎</translation>
<translation id="8211406090763984747">کنکشن محÙوظ ÛÛ’</translation>
+<translation id="8217240300496046857">سائٹس ان کوکیز کا استعمال Ù†Ûیں کر سکتی Ûیں جو آپ Ú©Ùˆ پورے ویب پر ٹریک کرتی Ûیں۔ Ú©Ú†Ú¾ سائٹس پر خصوصیات میں خلل ÛÙˆ سکتا ÛÛ’Û”</translation>
<translation id="8218327578424803826">تÙویض Ú©Ø±Ø¯Û Ù…Ù‚Ø§Ù…</translation>
<translation id="8220146938470311105">C7/C6 ‎(Envelope‎)‎</translation>
<translation id="8225771182978767009">اس کمپیوٹر Ú©Ùˆ ترتیب دینے والے شخص Ù†Û’ اس سائٹ Ú©Ùˆ مسدود کرنے کا انتخاب کیا ÛÛ’Û”</translation>
@@ -2268,14 +2324,9 @@
<translation id="830498451218851433">آدھا Ùولڈ کریں</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">ایپس انسٹال ÛÙˆ گئی Ûیں اور کتنی بار استعمال Ûوتی Ûیں</translation>
+<translation id="8317207217658302555">â€ARCore Ú©Ùˆ اپ ڈیٹ کریں؟</translation>
<translation id="831997045666694187">شام</translation>
<translation id="8321476692217554900">اطلاعات</translation>
-<translation id="8328484624016508118">â€ØªÙ…ام پوشیدگی ٹیبز Ú©Ùˆ بند کرنے Ú©Û’ بعد، Chrome درج ذیل صا٠کرتا ÛÛ’:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />اس Ø¢Ù„Û Ø³Û’ آپ Ú©ÛŒ براؤزنگ Ú©ÛŒ سرگرمی<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />اس Ø¢Ù„Û Ø³Û’ آپ Ú©ÛŒ تلاش Ú©ÛŒ سرگزشت<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Ùارمز میں درج Ú©Ø±Ø¯Û Ù…Ø¹Ù„ÙˆÙ…Ø§Øª<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489"><ph name="HOST_NAME" /> تک رسائی مسترد کر دی گئی</translation>
<translation id="833262891116910667">Ûائی لائٹ کریں</translation>
<translation id="8339163506404995330"><ph name="LANGUAGE" /> Ú©Û’ صÙحات کا ØªØ±Ø¬Ù…Û Ù†Ûیں کیا جائے گا</translation>
@@ -2327,6 +2378,7 @@
<translation id="8507227106804027148">کمانڈ لائن</translation>
<translation id="8508648098325802031">تلاش کا آئیکن</translation>
<translation id="8511402995811232419">کوکیز کا نظم کریں</translation>
+<translation id="8519753333133776369">â€Ø¢Ù¾ Ú©Û’ منتظم Ú©ÛŒ جانب سے HID آلے Ú©ÛŒ اجازت ÛÛ’</translation>
<translation id="8522552481199248698">â€Chrome آپ Ú©ÛŒ اپنا Google اکاؤنٹ محÙوظ اور پاس ورڈ تبدیل کرنے میں مدد کر سکتا ÛÛ’Û”</translation>
<translation id="8530813470445476232">â€Chrome ترتیبات میں اپنے براؤزنگ Ú©ÛŒ سرگزشت، کوکیز، کیش اور بÛت Ú©Ú†Ú¾ Ú©Ùˆ صا٠کریں</translation>
<translation id="8533619373899488139">â€Ù…سدود Ú©Ø±Ø¯Û URLs Ú©ÛŒ ÙÛرست اور اپنے سسٹم Ú©Û’ منتظم Ú©Û’ ذریعے ناÙØ° Ú©Ø±Ø¯Û Ø¯ÛŒÚ¯Ø± پالیسیاں دیکھنے Ú©Û’ لیے &lt;strong&gt;chrome://policy&lt;/strong&gt; Ù…Ù„Ø§Ø­Ø¸Û Ú©Ø±ÛŒÚºÛ”</translation>
@@ -2338,7 +2390,6 @@
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{اجازت ری سیٹ کریں}other{اجازتیں ری سیٹ کریں}}</translation>
<translation id="8555010941760982128">چیک آؤٹ پر ÛŒÛ Ú©ÙˆÚˆ استعمال کریں</translation>
<translation id="8557066899867184262">â€CVC آپ Ú©Û’ کارڈ Ú©Û’ پیچھے ÛÛ’Û”</translation>
-<translation id="8558485628462305855">â€Ø§ÙØ²ÙˆØ¯Û Ø­Ù‚ÛŒÙ‚Øª کا مواد دیکھنے کیلئے، ARCore Ú©Ùˆ اپ ڈیٹ کریں</translation>
<translation id="8559762987265718583"><ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> سے ایک نجی کنکشن تشکیل Ù†Ûیں دیا جا سکتا ÛÛ’ Ú©ÛŒÙˆÙ†Ú©Û Ø¢Ù¾ Ú©Û’ آلے Ú©ÛŒ تاریخ اور وقت (<ph name="DATE_AND_TIME" />) غلط Ûیں۔</translation>
<translation id="8564182942834072828">Ø¹Ù„ÛŒØ­Ø¯Û Ø¯Ø³ØªØ§ÙˆÛŒØ²Ø§Øª/بغیر ملائی Ûوئی کاپیاں</translation>
<translation id="8564985650692024650">â€Ø§Ú¯Ø± آپ Ù†Û’ اپنا پاس ورڈ دیگر سائٹس پر Ø¯ÙˆØ¨Ø§Ø±Û Ø§Ø³ØªØ¹Ù…Ø§Ù„ کیا ÛÛ’ تو Chromium آپ Ú©Ùˆ اپنا <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> پاس ورڈ ری سیٹ کرنے Ú©ÛŒ تجویز کرتا ÛÛ’Û”</translation>
@@ -2357,6 +2408,7 @@
<translation id="865032292777205197">موشن سینسرز</translation>
<translation id="8663226718884576429">آرڈر کا خلاصÛØŒ <ph name="TOTAL_LABEL" />ØŒ مزید تÙصیلات</translation>
<translation id="8666678546361132282">انگريزی</translation>
+<translation id="8669306706049782872">ونڈوز کھولنے اور رکھنے کے لیے اپنی اسکرینز کے بارے میں معلومات کا استعمال کریں</translation>
<translation id="867224526087042813">دستخط</translation>
<translation id="8676424191133491403">کوئی تاخیر Ù†Ûیں</translation>
<translation id="8680536109547170164"><ph name="QUERY" />، جواب، <ph name="ANSWER" /></translation>
@@ -2383,6 +2435,7 @@
<translation id="8731544501227493793">â€'پاس ورڈز کا نظم کریں' بٹن، Chrome Ú©ÛŒ ترتیبات میں اپنے پاس ورڈز کا نظم کرنے اور انÛیں دیکھنے Ú©Û’ لیے اینٹر دبائیں</translation>
<translation id="8734529307927223492">آپ کا <ph name="DEVICE_TYPE" /> <ph name="MANAGER" /> Ú©Û’ زیر انتظام ÛÛ’</translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />، نجی طور پر براؤز کرنے کے لیے ایک نئی پوشیدگی ونڈو کھولنے کی خاطر ٹیب، پھر اینٹر دبائیں</translation>
+<translation id="8737685506611670901"><ph name="REPLACED_HANDLER_TITLE" /> کی بجائے <ph name="PROTOCOL" /> لنکس کھولیں</translation>
<translation id="8738058698779197622">â€Ø§ÛŒÚ© محÙوظ کنکشن تشکیل دینے کیلئے، آپ Ú©ÛŒ Ú¯Ú¾Ú‘ÛŒ Ú©Ùˆ صحیح سے سیٹ کرنے Ú©ÛŒ ضرورت ÛÛ’Û” اس Ú©ÛŒ ÙˆØ¬Û ÛŒÛ ÛÛ’ Ú©Û ÙˆÛŒØ¨ سائٹس خود Ú©Ùˆ شناخت کرنے کیلئے جو سرٹیÙکیٹس استعمال کرتی Ûیں ÙˆÛ ØµØ±Ù Ù…Ø®ØµÙˆØµ وقت کیلئے درست Ûیں۔ Ú†ÙˆÙ†Ú©Û Ø¢Ù¾ Ú©Û’ آلے Ú©ÛŒ Ú¯Ú¾Ú‘ÛŒ غلط ÛÛ’ Ù„Ûذا Chromium ان سرٹیÙکیٹس Ú©ÛŒ توثیق Ù†Ûیں کر سکتا ÛÛ’Û”</translation>
<translation id="8740359287975076522">â€<ph name="HOST_NAME" /> کا ‎&lt;abbr id="dnsDefinition"&gt;DNS پتÛ‎&lt;/abbr&gt;‎ Ù†Ûیں مل سکا۔ Ù…Ø³Ø¦Ù„Û Ú©ÛŒ تشخیص Ú©ÛŒ جا رÛÛŒ ÛÛ’Û”</translation>
<translation id="8742371904523228557"><ph name="ORIGIN" /> کیلئے آپ کا Ú©ÙˆÚˆ <ph name="ONE_TIME_CODE" /> ÛÛ’</translation>
@@ -2410,6 +2463,7 @@
<translation id="883848425547221593">دیگر بÙÚ© مارکس</translation>
<translation id="884264119367021077">ترسیل کا پتÛ</translation>
<translation id="884923133447025588">کوئی منسوخی کا میکانزم Ù†Ûیں ملا۔</translation>
+<translation id="8849262850971482943">اضاÙÛŒ سیکیورٹی Ú©Û’ لیے اپنا ورچوئل کارڈ استعمال کریں</translation>
<translation id="885730110891505394">â€Google Ú©Û’ ساتھ اشتراک کرنا</translation>
<translation id="8858065207712248076">â€Ø§Ú¯Ø± آپ Ù†Û’ اپنا پاس ورڈ دیگر سائٹس پر Ø¯ÙˆØ¨Ø§Ø±Û Ø§Ø³ØªØ¹Ù…Ø§Ù„ کیا ÛÛ’ تو Chrome آپ Ú©Ùˆ اپنا <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> پاس ورڈ ری سیٹ کرنے Ú©ÛŒ تجویز کرتا ÛÛ’Û”</translation>
<translation id="885906927438988819">â€Ø§Ú¯Ø± Ûجے درست Ûیں تو <ph name="BEGIN_LINK" />Windows نیٹ ورک Ú©ÛŒ تشخیصات چلانے Ú©ÛŒ کوشش کریں<ph name="END_LINK" />Û”</translation>
@@ -2459,6 +2513,7 @@
<translation id="9004367719664099443">â€VR سیشن پیشرÙت میں ÛÛ’</translation>
<translation id="9005998258318286617">â€PDF دستاویز لوڈ Ù†Ûیں ÛÙˆ سکی۔</translation>
<translation id="9008201768610948239">نظر انداز کریں</translation>
+<translation id="901834265349196618">ای میل</translation>
<translation id="9020200922353704812">کارڈ کا بلنگ Ù¾ØªÛ Ø¯Ø±Ú©Ø§Ø± ÛÛ’</translation>
<translation id="9020542370529661692">اس صÙØ­Û Ú©Ø§ <ph name="TARGET_LANGUAGE" /> میں ØªØ±Ø¬Ù…Û Ú©Ø± دیا گیا ÛÛ’</translation>
<translation id="9020742383383852663">A8</translation>
@@ -2508,6 +2563,7 @@
<translation id="9150045010208374699">اپنا کیمرا استعمال کریں</translation>
<translation id="9150685862434908345">â€Ø¢Ù¾ کا منتظم دور سے آپ Ú©Û’ براؤزر کا سیٹ اپ تبدیل کر سکتا ÛÛ’Û” اس آلے پر Ûونے والی سرگرمی کا نظم Chrome سے باÛر بھی کیا جا سکتا ÛÛ’Û” <ph name="BEGIN_LINK" />مزید جانیں<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">اپ ڈیٹ کر دیا گیا</translation>
+<translation id="9155211586651734179">آڈیو پیریÙیرلز منسلک Ûیں</translation>
<translation id="9157595877708044936">تشکیل دیا جا رÛا Ûے…</translation>
<translation id="9158625974267017556">C6 ‎(Envelope‎)‎</translation>
<translation id="9164029392738894042">درستگی چیک کریں</translation>
diff --git a/chromium/components/strings/components_strings_uz.xtb b/chromium/components/strings/components_strings_uz.xtb
index 2a16791c7b1..b761ecfb26a 100644
--- a/chromium/components/strings/components_strings_uz.xtb
+++ b/chromium/components/strings/components_strings_uz.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">Tafsilotlar</translation>
<translation id="1030706264415084469"><ph name="URL" /> saytidan katta hajmdagi ma’lumotlarni mobil qurilmangizda saqlashga ruxsat so‘rovi keldi</translation>
<translation id="1032854598605920125">Soat mili yo‘nalishida burish</translation>
+<translation id="1033329911862281889">Inkognito rejimida ayrim axborotlar yashirilmaydi:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Saytlar va xizmatlar ularga qilgan tashrifingizni biladi<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Ishxona va maktablarda brauzer tarixi kuzatilishi mumkin<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Internet provayderlari ham trafikni kuzatishi mumkin<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">O‘chirib qo‘yish</translation>
<translation id="1036982837258183574">To‘liq ekran rejimidan chiqish uchun |<ph name="ACCELERATOR" />| tugmasini bosing</translation>
<translation id="1038106730571050514">Variantlar taklif qilish</translation>
<translation id="1038842779957582377">noma’lum ism</translation>
<translation id="1041998700806130099">Vazifa varagʻidagi xabar</translation>
<translation id="1048785276086539861">Izohlarni tahrirlash vaqtida bu hujjat bir sahifali shaklga qaytadi</translation>
-<translation id="1049743911850919806">Inkognito</translation>
<translation id="1050038467049342496">Boshqa ilovalarni yoping</translation>
<translation id="1055184225775184556">&amp;Qo‘shishni bekor qilish</translation>
<translation id="1056898198331236512">Ogohlantirish</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">Siyosat keshida xatoliklar yo‘q</translation>
<translation id="1130564665089811311">“Sahifani tarjima qilish†tugmasi, bu sahifani Google Tarjimon orqali tarjima qilish uchun Enter tugmasini bosing</translation>
<translation id="1131264053432022307">Nusxalangan rasm</translation>
+<translation id="1142846828089312304">Inkognito rejimidagi tashqi cookie fayllarni taqiqlash</translation>
<translation id="1150979032973867961">Bu <ph name="DOMAIN" /> serveri ekanligini tasdiqlab bo‘lmadi. Uning havfsizlik sertifikati kompyuteringizdagi operatsion tizimga ishonchli tuyulmayapti. Balki, server noto‘g‘ri sozlangan yoki kimdir ma’lumotlaringizni o‘g‘rilashga urinayotgan bo‘lishi mumkin.</translation>
<translation id="1151972924205500581">Parol kiritish zarur</translation>
<translation id="1156303062776767266">Bu – mahalliy yoki ulashilgan fayl</translation>
@@ -64,7 +70,6 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="1178581264944972037">Pauza</translation>
<translation id="1181037720776840403">Olib tashlash</translation>
<translation id="1186201132766001848">Parollarni tekshiring</translation>
-<translation id="1195210374336998651">Ilova sozlamalarini ochish</translation>
<translation id="1195558154361252544">Bildirishnoamalar siz ruxsat bergan saytlardan tashqari barcha saytlar uchun taqiqlanadi</translation>
<translation id="1197088940767939838">Apelsinrang</translation>
<translation id="1201402288615127009">Keyingisi</translation>
@@ -111,7 +116,7 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="1307966114820526988">Eskirgan funksiyalar</translation>
<translation id="1308113895091915999">Mavjud takliflar</translation>
<translation id="1312803275555673949">Buning qaysi isboti bor ekan?</translation>
-<translation id="131405271941274527"><ph name="URL" /> sayti NFC orqali axborot almashinishga ruxsat soʻramoqda</translation>
+<translation id="1314311879718644478">Boyitilgan reallik kontentini ochish</translation>
<translation id="1314509827145471431">Oʻng chekkasini belgilash</translation>
<translation id="1318023360584041678">Varaqlar guruhiga saqlangan</translation>
<translation id="1319245136674974084">Bu ilova uchun boshqa soʻralmasin</translation>
@@ -161,6 +166,7 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="142858679511221695">Cloud foydalanuvchisi</translation>
<translation id="1428729058023778569">Bu sayt HTTPS protokolda ishlamasligi uchun bu ogohlantiruv chiqarildi. <ph name="BEGIN_LEARN_MORE_LINK" />Batafsil<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">Chop etish</translation>
+<translation id="1432187715652018471">sahifa xizmatga ishlov beruvchi vosita oʻrnatishga urinmoqda.</translation>
<translation id="1432581352905426595">Qidiruv tizimlarini boshqarish</translation>
<translation id="1436185428532214179">Qurilmangizdagi fayl yoki jildlarni tahrirlash uchun ruxsat soʻrashi mumkin</translation>
<translation id="1442386063175183758">Oʻng tomonni darvozasimon taxlash</translation>
@@ -181,6 +187,12 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="1483493594462132177">Yuborish</translation>
<translation id="1484290072879560759">Yetkazib berish manzilini tanlang</translation>
<translation id="1492194039220927094">Push-xabar orqali yuboriladigan siyosatlar:</translation>
+<translation id="149293076951187737">Chromeda barcha Inkognito varaqlar yopilsa, ulardagi faoliyatingiz bu qurilmadan tozalanadi:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Brauzer tarixi<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Qidiruv tarixi<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Shakllarga kiritilgan maʼlumotlar<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">Varaqqa qaytish</translation>
<translation id="1501859676467574491">Google hisobingizdagi kartalarni ochish</translation>
<translation id="1507202001669085618">&lt;p&gt;Wi-Fi portaldan foydalanayotganingizda onlayn bo‘lishingiz uchun sizdan kirishni so‘raganda shunday xatolik ko‘rsatiladi.&lt;/p&gt;
@@ -207,6 +219,8 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="1559528461873125649">Bunday fayl yoki jild mavjud emas</translation>
<translation id="1559572115229829303">&lt;p&gt;Qurilmadagi sana va vaqt sozlamalari (<ph name="DATE_AND_TIME" />) noto‘g‘ri bo‘lganligi sababli <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> domeni bilan xavfsiz aloqa o‘rnatib bo‘lmadi.&lt;/p&gt;
&lt;p&gt;Aniq sana va vaqt sozlamalarini &lt;strong&gt;Sozlamalar&lt;/strong&gt; ilovasidagi &lt;strong&gt;Umumiy&lt;/strong&gt; bo‘limida belgilang.</translation>
+<translation id="1559839503761818503">Administrator qurilmani <ph name="DATE" /> kuni <ph name="TIME" /> da qayta ishga tushiradi</translation>
+<translation id="156703335097561114">Manzillar, interfeys konfiguratsiyasi hamda ulanish sifati kabi tarmoqga oid axborot</translation>
<translation id="1567040042588613346">Bu parametr xatosiz ishlayapti, lekin boshqa qaysidir parametr qiymati bilan almashtirildi.</translation>
<translation id="1569487616857761740">Amal qilish muddatini kiriting</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -214,6 +228,7 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="1583429793053364125">Veb-sahifani ochish vaqtida kutilmagan xatolik yuz berdi.</translation>
<translation id="1586541204584340881">Oʻrnatilgan kengaytmalar</translation>
<translation id="1588438908519853928">Normal</translation>
+<translation id="1589050138437146318">ARCore oʻrnatilsinmi?</translation>
<translation id="1592005682883173041">Qurilmadagi mahalliy ma’lumotlarga ruxsat</translation>
<translation id="1594030484168838125">Tanlang</translation>
<translation id="160851722280695521">Chromeda Dino oʻyinini boshlash</translation>
@@ -282,6 +297,7 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
sarlavha xato formatdaligi sababli brauzer <ph name="SITE" /> saytidagi soʻrovingizni
bajara olmaydi. Manba siyosatlari sayt operatorlari
tomonidan xavfsizlik kabi sayt parametrlarini sozlashda ishlatiladi.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Chromiumdagi Inkognito rejimi haqida batafsil<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">Ochiq varaqlar shu yerda ko‘rsatiladi</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -409,6 +425,7 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="22081806969704220">Tarnov 3</translation>
<translation id="2212735316055980242">Bu qoida topilmadi</translation>
<translation id="2213606439339815911">Yozuvlar chiqarib olinmoqda...</translation>
+<translation id="2213612003795704869">Sahifa chop etildi</translation>
<translation id="2215727959747642672">Fayllarni tahrirlash</translation>
<translation id="2218879909401188352">Firibgarlar <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> saytida xavfli ilovalarni o‘rnatishlari mumkin. Bu ilovalar qurilmangizni buzishi, mobil hisobingizdan pul o‘g‘irlashi yoki shaxsiy ma’lumotlaringizni olishi mumkin. <ph name="BEGIN_LEARN_MORE_LINK" />Batafsil<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">Internet yo‘q</translation>
@@ -418,6 +435,7 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="2248949050832152960">WebAuthn ishlatish</translation>
<translation id="2250931979407627383">Chap chekkasini tikish</translation>
<translation id="225207911366869382">Bu qiymat joriy qoida uchun boshqa qo‘llanilmaydi.</translation>
+<translation id="2256115617011615191">Qayta ishga tushirish</translation>
<translation id="2258928405015593961">Kelgusidagi muddatni kiriting va qaytadan urining</translation>
<translation id="225943865679747347">Xatolik kodi: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">HTTP xatoligi</translation>
@@ -445,6 +463,7 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="2337852623177822836">Sozlamani administrator boshqaradi</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> qurilmangizga ulanmoqchi</translation>
<translation id="2346319942568447007">Nusxalangan rasm</translation>
+<translation id="2350796302381711542">“<ph name="PROTOCOL" />†kabi havolalarga ishlov berish uchun <ph name="REPLACED_HANDLER_TITLE" /> o‘rniga <ph name="HANDLER_HOSTNAME" /> xizmati foydalanilsinmi?</translation>
<translation id="2354001756790975382">Boshqa xatcho‘plar</translation>
<translation id="2354430244986887761">Google saytlar xavfsizligini tekshirish tizimi yaqinda <ph name="SITE" /> saytida <ph name="BEGIN_LINK" />zararli ilovalarni topdi<ph name="END_LINK" />.</translation>
<translation id="2355395290879513365">Firibgarlar bu saytda siz ochgan rasmlarni ko‘rishi va bu rasmlarni qalbakilashtirib, o‘zgartirishi mumkin.</translation>
@@ -470,6 +489,7 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="2413528052993050574">Bu <ph name="DOMAIN" /> serveri ekanligi tasdiqlanmadi. Uning havfsizlik sertifikati eskirgan. Server sozlamalari noto‘g‘ri moslangan yoki kimdir sizning shaxsiy ma’lumotlaringizni o‘g‘irlashga harakat qilmoqda.</translation>
<translation id="2414886740292270097">Qorong‘i</translation>
<translation id="2430968933669123598">Google hisobini boshqarish, Google hisobingizdagi axborot, maxfiylik va xavfsizlik sozlamalarini boshqarish uchun Enter tugmasini bosing</translation>
+<translation id="2436186046335138073"><ph name="HANDLER_HOSTNAME" /> saytiga “<ph name="PROTOCOL" />†kabi havolalarga ishlov berishga ruxsat berilsinmi?</translation>
<translation id="2438874542388153331">Oʻngdan 4 ta teshik ochish</translation>
<translation id="2450021089947420533">Tarixlar</translation>
<translation id="2463739503403862330">To‘ldirish</translation>
@@ -477,6 +497,7 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="2465655957518002998">Yetkazib berish usulini tanlang</translation>
<translation id="2465688316154986572">Steplerlash</translation>
<translation id="2465914000209955735">Chromeda yuklab olingan fayllarni boshqarish</translation>
+<translation id="2466004615675155314">Internetdan olingan axborot</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Tarmoq diagnostikasini ishga tushiring<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">1 dan N gacha tartibda</translation>
<translation id="2470767536994572628">Izohlarni tahrirlash vaqtida bu hujjat bir sahifali shaklga va asl tiklik holatiga qaytadi</translation>
@@ -497,6 +518,7 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="2523886232349826891">Faqat shu qurilmada saqlanadi</translation>
<translation id="2524461107774643265">Qo‘shimcha axborot qo‘shish</translation>
<translation id="2529899080962247600">Bu maydonchadagi elementlar soni <ph name="MAX_ITEMS_LIMIT" /> yozuvdan oshmasligi kerak. Qolganlari inobatga olinmaydi.</translation>
+<translation id="2535585790302968248">Internetdan maxfiy foydalanish uchun yangi Inkognito varaq ochish</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{va yana 1 ta}other{va yana # ta}}</translation>
<translation id="2536110899380797252">Manzil kiritish</translation>
<translation id="2539524384386349900">Aniqlansin</translation>
@@ -522,7 +544,14 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="2597378329261239068">Bu hujjat parol bilan himoyalangan. Iltimos parolni kiriting.</translation>
<translation id="2609632851001447353">Variantlar</translation>
<translation id="2610561535971892504">Nusxa olish uchun bosing</translation>
+<translation id="2617988307566202237">Chrome quyidagi maʼlumotlarni <ph name="BEGIN_EMPHASIS" />saqlamaydi<ph name="END_EMPHASIS" />:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Brauzer tarixi
+ <ph name="LIST_ITEM" />Cookie fayllar va sayt maʼlumotlari
+ <ph name="LIST_ITEM" />Shakllarga kiritilgan maʼlumotlar
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (Envelope)</translation>
+<translation id="2623663032199728144">Ekranlardagi axborotdan foydalanish uchun ruxsat soʻrashi mumkin</translation>
<translation id="2625385379895617796">Soatingiz oldinda</translation>
<translation id="262745152991669301">USB qurilmalarga ulanish uchun ruxsat soʻrashi mumkin</translation>
<translation id="2629325967560697240">Chrome brauzerining yuqori darajadagi xavfsizligidan foydalanish uchun <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />kengaytirilgan himoyani yoqing<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -556,6 +585,7 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="2709516037105925701">Avtoto‘ldirish</translation>
<translation id="2713444072780614174">Oq</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />, Chrome sozlamalari orqali toʻlov va kredit karta axborotini boshqarish uchun avval Tab, keyin esa Enter tugmasini bosing</translation>
+<translation id="271663710482723385">Butun ekran rejimidan chiqish uchun |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| tugmalarini bosing</translation>
<translation id="2721148159707890343">So‘rov bajarildi</translation>
<translation id="2723669454293168317">Chrome sozlamalari orqali xavfsizlik tekshiruvini bajaring</translation>
<translation id="2726001110728089263">Yon tarnov</translation>
@@ -586,6 +616,7 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="2850739647070081192">Invite (Envelope)</translation>
<translation id="2856444702002559011">Firibgarlar <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> saytidan ma’lumotlaringizni (parol, xabar va kredit karta ma’lumotlari kabilarni) o‘g‘irlashga urinayotgan bo‘lishi mumkin. <ph name="BEGIN_LEARN_MORE_LINK" />Batafsil<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">Bu saytda yoqimsiz yoki befoyda reklamalar chiqadi.</translation>
+<translation id="286512204874376891">Virtual karta haqiqiy kartani ehtimoliy firibgarlikdan himoya qiladi. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">Doʻstona</translation>
<translation id="2876489322757410363">Tashqi ilova orqali toʻlash uchun inkognito rejimidan chiqib ketasiz. Davom etasizmi?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />, Chrome sozlamalari orqali saytlarni xavfsiz kezish rejimini boshqarish uchun avval Tab, keyin Enter tugmasini bosing</translation>
@@ -610,6 +641,7 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="2930577230479659665">Har bir nusxa chekkasini qirqish</translation>
<translation id="2932085390869194046">Parol yaratish...</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019"><ph name="PROTOCOL" /> havolalarini ochish</translation>
<translation id="2941952326391522266">Bu <ph name="DOMAIN" /> serveri ekanligini tasdiqlab bo‘lmadi. Uning havfsizlik sertifikati <ph name="DOMAIN2" /> tomonidan berilgan. Server noto‘g‘ri sozlangan yoki kimdir ma’lumotlaringizni o‘g‘rilashga urinayotgan bo‘lishi mumkin.</translation>
<translation id="2943895734390379394">Yuklash vaqti:</translation>
<translation id="2948083400971632585">Ulanishga sozlangan proksilarni sozlamalar sahifasida o‘chirib qo‘yishingiz mumkin.</translation>
@@ -642,6 +674,7 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="3037605927509011580">Ana xolos!</translation>
<translation id="3041612393474885105">Sertifikat haqida ma’lumot</translation>
<translation id="3044034790304486808">Tarixni qaytaring</translation>
+<translation id="305162504811187366">Chrome Remote Desktop tarixi, vaqt belgisi, hostlar va mijoz seansi identifikatorlari</translation>
<translation id="3060227939791841287">C9 (Envelope)</translation>
<translation id="3061707000357573562">Xizmatni tuzatish</translation>
<translation id="306573536155379004">Oʻyin boshlandi.</translation>
@@ -680,6 +713,7 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="3197136577151645743">Qurilmadan foydalanishga oid axborotlarni soʻrashi mumkin</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />, Chrome sozlamalari orqali sinxronlanadigan maʼlumotlarni boshqarish uchun avval Tab, keyin Enter tugmasini bosing</translation>
<translation id="320323717674993345">To‘lovni bekor qilish</translation>
+<translation id="3203366800380907218">Internetdan</translation>
<translation id="3207960819495026254">Xatcho‘plarga qo‘shildi</translation>
<translation id="3209034400446768650">Sahifa pul yechib olishi mumkin</translation>
<translation id="3212581601480735796"><ph name="HOSTNAME" /> saytidagi harakatlaringiz kuzatuv ostida</translation>
@@ -696,10 +730,12 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="3234666976984236645">Bu saytda har doim muhim kontent aniqlansin</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />, Brauzeringiz koʻrinishini moslash uchun avval Tab, keyin Enter tugmasini bosing</translation>
<translation id="3240791268468473923">Xavfsiz toʻlov maʼlumotlari ochilgan jadvaldagi maʼlumotlarga mos kelmadi</translation>
+<translation id="324180406144491771">“<ph name="HOST_NAME" />†havolalari bloklangan</translation>
<translation id="3249845759089040423">Jozibali</translation>
<translation id="3252266817569339921">Fransuzcha</translation>
<translation id="3257954757204451555">Bu axborot orqasida kim bor?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />, Google Taqvimda yangi tadbirni tez yaratish uchun avval Tab, keyin Enter tugmasini bosing</translation>
+<translation id="3261488570342242926">Virtual kartalar haqida batafsil</translation>
<translation id="3264837738038045344">Chrome sozlamalarini boshqarish tugmasi, Chrome sozlamalarini ochish uchun Enter tugmasini bosing</translation>
<translation id="3266793032086590337">Qiymat (ziddiyatli)</translation>
<translation id="3268451620468152448">Ochiq ichki oynalar</translation>
@@ -713,6 +749,7 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="3288238092761586174">Toʻlovingizni tasdiqlash uchun <ph name="URL" /> qoʻshimcha bosqichlarni bajarishi kerak</translation>
<translation id="3293642807462928945"><ph name="POLICY_NAME" /> parametri haqida batafsil axborot olish</translation>
<translation id="3295444047715739395">Parollaringizni Chrome sozlamalari orqali koʻrish va boshqarish</translation>
+<translation id="3303795387212510132">Ilovaga <ph name="PROTOCOL_SCHEME" /> havolalarini ochishga ruxsat berilsinmi?</translation>
<translation id="3303855915957856445">Qidiruv hech qanday natija bermadi</translation>
<translation id="3304073249511302126">bluetooth qurilmalarni qidirish</translation>
<translation id="3308006649705061278">Bo‘lim (OU)</translation>
@@ -726,12 +763,6 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="3345782426586609320">Koʻzlar</translation>
<translation id="3355823806454867987">Proksi-server sozlamalarini o‘zgartirish...</translation>
<translation id="3360103848165129075">Toʻlovni qayta ishlash vositasi</translation>
-<translation id="3361596688432910856">Chrome quyidagi ma’lumotlarni <ph name="BEGIN_EMPHASIS" />saqlab qolmaydi<ph name="END_EMPHASIS" />:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Veb-sahifalarni ko‘rish tarixi;
- <ph name="LIST_ITEM" />Cookie-fayllar va sayt ma’lumotlari;
- <ph name="LIST_ITEM" />To‘ldirilgan shakllar.
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">Bu parametr eskirgan <ph name="OLD_POLICY" /> siyosatidan avtomatik ravishda nusxa olgan. Oʻrniga bu parametrdan foydalaning.</translation>
<translation id="3364869320075768271"><ph name="URL" /> virtual reallik qurilmangiz va uning maʼlumotlaridan foydalanmoqchi</translation>
<translation id="3366477098757335611">Kartalarni ko‘rish</translation>
@@ -813,7 +844,6 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="3587738293690942763">Oʻrtacha</translation>
<translation id="3592413004129370115">Italian (Envelope)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{Guruh sozlamalarini istalgan vaqtda tiklash mumkin. Yangi guruhga qoʻshilish bir kun vaqt oladi.}=1{Guruh sozlamalarini istalgan vaqtda tiklash mumkin. Yangi guruhga qoʻshilish bir kun vaqt oladi.}other{Guruh sozlamalarini istalgan vaqtda tiklash mumkin. Yangi guruhga qoʻshilish {NUM_DAYS} kun vaqt oladi.}}</translation>
-<translation id="3596012367874587041">Ilova sozlamalari</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">Ilova administrator tomonidan bloklangan</translation>
<translation id="3608932978122581043">Holatini belgilash</translation>
@@ -855,6 +885,7 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="370972442370243704">Tarixlarni yoqish</translation>
<translation id="3711895659073496551">To‘xtatib qo‘yish</translation>
<translation id="3712624925041724820">Litsenziyalar yetarli emas</translation>
+<translation id="3714633008798122362">veb-taqvim</translation>
<translation id="3714780639079136834">Mobil internet yoki Wi-Fi tarmoqlarini yoqish</translation>
<translation id="3715597595485130451">Wi-Fi‘ga ulanish</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Proksi-server, himoya devori va DNS sozlamalarini tekshirish<ph name="END_LINK" /></translation>
@@ -916,6 +947,7 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="3906954721959377182">Planshet</translation>
<translation id="3909477809443608991"><ph name="URL" /> himoyalangan kontentni ijro etmoqchi. Bu saytdagi himoyalangan kontent ijro etilishi uchun qurilmangizdagi shaxsni tasdiqlash axboroti Google tomonidan tekshiriladi.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">Taqiqlash</translation>
<translation id="3939773374150895049">CVC oʻrniga WebAuthn ishlatilsinmi?</translation>
<translation id="3946209740501886391">Bu saytda har doim so‘ralsin</translation>
<translation id="3947595700203588284">MIDI qurilmarga ulanish uchun ruxsat soʻrashi mumkin</translation>
@@ -937,6 +969,7 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="3990250421422698716">Qogʻozlarni ajratib toʻplash</translation>
<translation id="3996311196211510766"><ph name="ORIGIN" /> sayti manba siyosati tekshiruvini talab qildi
lekin bu tekshiruv barcha soʻrovlar uchun ishlatilganda bu siyosat uchun qoʻllanilmaydi.</translation>
+<translation id="4009243425692662128">Chop etiladigan sahifalar kontenti tahlil qilinishi uchun Google Cloud yoki tashqi xizmatlarga yuboriladi. Masalan, tarkibida maxfiy axborot borligini aniqlash uchun.</translation>
<translation id="4010758435855888356">Xotiraga ruxsat berilsinmi?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{{COUNT} ta sahifadan iborat PDF hujjat}other{{COUNT} ta sahifadan iborat PDF hujjat}}</translation>
<translation id="4023431997072828269">Chunki sayt xavfsiz boʻlmagan ulanishdan foydalanmoqda. Maʼlumotlaringiz boshqalarga koʻrinadi.</translation>
@@ -1031,6 +1064,7 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="4250680216510889253">Yo‘q</translation>
<translation id="4253168017788158739">Eslatma</translation>
<translation id="425582637250725228">Kiritilgan o‘zgarishlar saqlanmasligi mumkin.</translation>
+<translation id="425869179292622354">Himoyasi virtual karta bilan oshirilsinmi?</translation>
<translation id="4258748452823770588">Imzo buzilgan</translation>
<translation id="4261046003697461417">Himoyalangan hujjatlar izohlanmaydi</translation>
<translation id="4265872034478892965">Administrator ruxsat bergan</translation>
@@ -1093,6 +1127,7 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="4434045419905280838">Qalquvchi oyna va yo‘naltirishlar</translation>
<translation id="4435702339979719576">Postcard)</translation>
<translation id="443673843213245140">Proksi-server o‘chiq, lekin uning sozlamalari aniq belgilangan.</translation>
+<translation id="4441832193888514600">Parametr faqat bulutdagi foydalanuvchilar siyosati tomonidan belgilanishi mumkinligi uchun inkor etildi.</translation>
<translation id="4450893287417543264">Boshqa ko‘rsatilmasin</translation>
<translation id="4451135742916150903">HID qurilmalarga ulanish uchun ruxsat soʻrashi mumkin</translation>
<translation id="4452328064229197696">Hozirgina siz foydalangan parol oshkor qilingan. Hisoblaringizni himoyalash maqsadida Google Parollar menejeri saqlangan parollaringizni tekshirishni tavsiya etadi.</translation>
@@ -1148,6 +1183,7 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="4628948037717959914">Rasm</translation>
<translation id="4631649115723685955">Keshbek ulandi</translation>
<translation id="4636930964841734540">Ma’lumot</translation>
+<translation id="4638670630777875591">Chromiumdagi Inkognito rejimi</translation>
<translation id="464342062220857295">Funksiyalar qidiruvi</translation>
<translation id="4644670975240021822">Teskari tartibda orqa tomonida</translation>
<translation id="4646534391647090355">Hoziroq ochish</translation>
@@ -1168,6 +1204,7 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="4708268264240856090">Aloqa uzilib qoldi</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Windows tarmoq diagnostikasini ishga tushiring<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426"><ph name="USERNAME" /> hisobi paroli</translation>
<translation id="4724144314178270921">Vaqtinchalik xotiradagi rasm va matnlarni koʻrish uchun ruxsat soʻrashi mumkin</translation>
<translation id="4726672564094551039">Siyosatni qayta yuklash</translation>
<translation id="4728558894243024398">Platforma</translation>
@@ -1189,6 +1226,7 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="4757993714154412917">Hozirgina shubhali saytda parol kiritdingiz. Hisoblar himoyasi uchun Chromium saqlangan parollaringizni tekshirishni tavsiya qiladi.</translation>
<translation id="4758311279753947758">Aloqa ma’lumotini qo‘shish</translation>
<translation id="4761104368405085019">Mikrofoningizni ishlatish</translation>
+<translation id="4761869838909035636">Chrome Xavfsizlik tekshiruvini bajarish</translation>
<translation id="4764776831041365478"><ph name="URL" /> manzilidagi veb-sahifa vaqtinchalik ishlamayapti yoki boshqa manzilga butunlay ko‘chirilgan.</translation>
<translation id="4766713847338118463">Quyidan ikki marta steplerlash</translation>
<translation id="4771973620359291008">Noma’lum xatolik yuz berdi.</translation>
@@ -1209,12 +1247,6 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="4819347708020428563">Izohlar standart shaklda tahrirlansinmi?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />, yangi Google Sheetda yangi jadvalni tez yaratish uchun avval Tab, keyin Enter tugmasini bosing</translation>
<translation id="4825507807291741242">Qudratli</translation>
-<translation id="4827402517081186284">Inkognito rejimida ayrim axborotlar yashirilmaydi:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Saytlar ularga qilgan tashrifingizni biladi<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Ishxona va maktablarda brauzer tarixi kuzatilishi mumkin<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Internet provayderlari ham trafikni kuzatishi mumkin<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">Ogohlantiruvlarni yoqish</translation>
<translation id="4838327282952368871">Xayolparast</translation>
<translation id="4840250757394056958">Chrome tarixini koʻrish</translation>
@@ -1226,12 +1258,12 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="4854362297993841467">Bu yetkazib berish usuli hozirda ishlamayapti. Boshqa usuldan foydalaning.</translation>
<translation id="4854853140771946034">Google Keepda yangi qaydni tez yaratish</translation>
<translation id="485902285759009870">Kod tasdiqlanmoqda...</translation>
+<translation id="4866506163384898554">Kursorni koʻrish uchun |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| tugmalarini bosing</translation>
<translation id="4876188919622883022">Soddalashgan shaklda</translation>
<translation id="4876305945144899064">Ko‘satilmagan</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{Hech qanday}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831"><ph name="TEXT" /> – qidiruv</translation>
<translation id="4879491255372875719">Avtomatik (birlamchi)</translation>
-<translation id="4879725228911483934">Ekranlaringizga oynalarni ochish va joylashtirish</translation>
<translation id="4880827082731008257">Qidiruv tarixi</translation>
<translation id="4881695831933465202">Ochish</translation>
<translation id="4885256590493466218">Hisob-kitob vaqtida <ph name="CARD_DETAIL" /> bilan toʻlang</translation>
@@ -1240,6 +1272,7 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">Toʻqqizinchi oʻram</translation>
<translation id="4901778704868714008">Saqlash...</translation>
+<translation id="4905659621780993806">Administrator qurilmani <ph name="DATE" /> kuni <ph name="TIME" /> da avtomatik qayta ishga tushiradi Qurilma qayta ishga tushishidan oldin ochiq qolgan maʼlumotlarni saqlang.</translation>
<translation id="4913987521957242411">Yuqori chapdan teshik ochish</translation>
<translation id="4918221908152712722">Oʻrnatish: <ph name="APP_NAME" /> (yuklab olinmaydi)</translation>
<translation id="4923459931733593730">To‘lov</translation>
@@ -1248,6 +1281,7 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, qidirish uchun avval Tab, keyin esa Enter tugmasini bosing</translation>
<translation id="4930153903256238152">Koʻp sigʻimli</translation>
+<translation id="4940163644868678279">Chromedagi Inkognito rejimi</translation>
<translation id="4943872375798546930">Hech narsa topilmadi</translation>
<translation id="4950898438188848926">Varaqlar orasida almashish tugmasi, shu varaqqa almashish uchun Enter tugmasini bosing, <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="495170559598752135">Harakatlar</translation>
@@ -1257,6 +1291,7 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="4968522289500246572">Bu ilova mobil qurilmalar uchun ishlab chiqilgan va oʻlchami bexato oʻzgarmasligi mumkin. Ishlashida xato chiqishi yoki qaytadan ishga tushishi mumkin.</translation>
<translation id="4969341057194253438">Yozuvni oʻchirish</translation>
<translation id="4973922308112707173">Yuqoridan 2 ta teshik ochish</translation>
+<translation id="4976702386844183910">Oxirgi tashrif: <ph name="DATE" /></translation>
<translation id="4984088539114770594">Mikrofon ishlatilsinmi?</translation>
<translation id="4984339528288761049">Prc5 (Envelope)</translation>
<translation id="4989163558385430922">Hammasi</translation>
@@ -1318,6 +1353,7 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="5138227688689900538">Kamroq chiqsin</translation>
<translation id="5145883236150621069">Siyosat javobida xato kodi bor</translation>
<translation id="5146995429444047494"><ph name="ORIGIN" /> bildirishnomalari bloklandi</translation>
+<translation id="514704532284964975">Telefonga teginganingizda <ph name="URL" /> sayti NFC qurilmalarni koʻrmoqchi va ulardagi axborotni oʻzgartirmoqchi</translation>
<translation id="5148809049217731050">Old tomonida</translation>
<translation id="515292512908731282">C4 (Envelope)</translation>
<translation id="5158275234811857234">Muqova</translation>
@@ -1342,6 +1378,7 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="5215116848420601511">Google Pay xizmatidagi bank kartalari va manzillar</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">Tarnov 13</translation>
+<translation id="5216942107514965959">Oxirgi tashrif: bugun</translation>
<translation id="5222812217790122047">E-pochtangizni kiriting</translation>
<translation id="5230733896359313003">Yetkazib berish manzili</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1362,7 +1399,6 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">Hujjat parametrlari</translation>
<translation id="528468243742722775">Tugatish</translation>
-<translation id="5284909709419567258">Tarmoqdagi manzillar</translation>
<translation id="5285570108065881030">Saqlangan barcha parollar ko‘rsatilsin</translation>
<translation id="5287240709317226393">Cookie fayllarini ko‘rsatish</translation>
<translation id="5287456746628258573">Bu sayt eskirgan xavfsizlik sozlamasidan foydalanadi. maʼlumotlaringiz (masalan, parol va kredit kartalari nomlari) shu saytga yuborilganda ular xavf ostida qolishi mumkin.</translation>
@@ -1446,6 +1482,7 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="5556459405103347317">Qayta yuklash</translation>
<translation id="5560088892362098740">Tugash muddati</translation>
<translation id="55635442646131152">Hujjat mundarijasi</translation>
+<translation id="5565613213060953222">Inkognito varaq ochish</translation>
<translation id="5565735124758917034">Faol</translation>
<translation id="5570825185877910964">Hisobni himoyalash</translation>
<translation id="5571083550517324815">Bu manzildan olib keta olmaymiz. Boshqa manzilni tanlang.</translation>
@@ -1528,6 +1565,7 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="5869522115854928033">Saqlab olingan parollar</translation>
<translation id="5873013647450402046">Bank shaxsingizni tasdiqlamoqchi.</translation>
<translation id="5887400589839399685">Karta saqlandi</translation>
+<translation id="5887687176710214216">Oxirgi tashrif: kecha</translation>
<translation id="5895138241574237353">Qayta ishga tushirish</translation>
<translation id="5895187275912066135">Berilgan vaqti</translation>
<translation id="5901630391730855834">Sariq</translation>
@@ -1541,6 +1579,7 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="5921639886840618607">Ushbu karta Google hisobingizda saqlansinmi?</translation>
<translation id="5922853866070715753">Deyarli tayyor</translation>
<translation id="5932224571077948991">Saytda yoqimsiz yoki befoyda reklamalar chiqadi</translation>
+<translation id="5938153366081463283">Virtual karta kiritish</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347"><ph name="SITE_NAME" /> ochilmoqda…</translation>
<translation id="5951495562196540101">Qurilmani iste’molchi hisobidan registratsiya qilib bo‘lmadi (to‘plamli litsenziyasi bor)</translation>
@@ -1605,6 +1644,7 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="6120179357481664955">UPI identifikatori eslab qolinsinmi?</translation>
<translation id="6124432979022149706">Chrome korporativ konnektorlari</translation>
<translation id="6127379762771434464">Havola olib tashlandi</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Chromedagi Inkognito rejimi haqida batafsil<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">Kabel ulanishlarini tekshiring, router, modem yoki boshqa tarmoq qurilmalarini o‘chirib yoqing.</translation>
<translation id="614940544461990577">Quyidagilarni bajaring:</translation>
<translation id="6150036310511284407">Chapdan 3 ta teshik ochish</translation>
@@ -1616,7 +1656,6 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="6169916984152623906">Inkognito rejimida bajargan amallaringiz ushbu qurilmaning boshqa foydalanuvchilariga ko‘rinmaydi. Biroq xatcho‘plar va yuklab olingan fayllar saqlanib qoladi.</translation>
<translation id="6177128806592000436">Bu sayt bilan o‘rnatilgan aloqa himoyalanmagan.</translation>
<translation id="6180316780098470077">Qayta urinishlar intervali</translation>
-<translation id="619448280891863779">Ekranlarda oynalar ochish va joylashtirishdan oldin ruxsat soʻrashi mumkin</translation>
<translation id="6196640612572343990">Tashqi cookie-fayllarni bloklash.</translation>
<translation id="6203231073485539293">Internet aloqasini tekshiring</translation>
<translation id="6218753634732582820">Ushbu manzilni brauzer unutsinmi?</translation>
@@ -1639,7 +1678,7 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="6272383483618007430">Google Update</translation>
<translation id="6276112860590028508">Mutolaa ro‘yxatingizdagi sahifalar bu yerda ko‘rsatiladi</translation>
<translation id="627746635834430766">Keyingi safar tezroq to‘lash uchun kartangizni Google hisobingizga saqlang.</translation>
-<translation id="6279098320682980337">Virtual karta raqami kiritilmadimi? Nusxalanadigan karta maʼlumotlari ustiga bosing</translation>
+<translation id="6279183038361895380">Kursorni ko‘rish uchun |<ph name="ACCELERATOR" />| tugmasini bosing</translation>
<translation id="6280223929691119688">Bu manzilga yetkazib bera olmaymiz. Boshqa manzilni tanlang.</translation>
<translation id="6282194474023008486">Pochta indeksi</translation>
<translation id="6285507000506177184">Chromeda yuklanmalarni boshqarish tugmasi, Chromeda yuklab olingan fayllarni boshqarish uchun Enter tugmasini bosing</translation>
@@ -1647,6 +1686,7 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="6290238015253830360">Tavsiya etiladigan maqolalar shu yerda chiqadi</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC kod:</translation>
+<translation id="6300452962057769623">{0,plural, =0{Qurilmangiz hozir qayta ishga tushadi}=1{Qurilmangiz 1 soniyadan keyin qayta ishga tushadi}other{Qurilmangiz # soniyadan keyin qayta ishga tushadi}}</translation>
<translation id="6302269476990306341">Chrome ichidagi Google Assistent toʻxtatilmoqda</translation>
<translation id="6305205051461490394"><ph name="URL" /> bilan aloqa o‘rnatib bo‘lmadi.</translation>
<translation id="6312113039770857350">Veb-sahifa mavjud emas</translation>
@@ -1720,6 +1760,7 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="6529602333819889595">&amp;O‘chirishni qaytarish</translation>
<translation id="6545864417968258051">Bluetooth qurilmalarni qidirish</translation>
<translation id="6547208576736763147">Chapdan 2 ta teshik ochish</translation>
+<translation id="6554732001434021288">Oxirgi tashrif: <ph name="NUM_DAYS" /> kun oldin</translation>
<translation id="6556866813142980365">Qaytarish</translation>
<translation id="6569060085658103619">Siz kengaytma sahifasidasiz.</translation>
<translation id="6573200754375280815">Oʻngdan 2 ta teshik ochish</translation>
@@ -1780,7 +1821,6 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="6757797048963528358">Qurilma uyqu rejimiga o‘tib qoldi.</translation>
<translation id="6767985426384634228">Manzil yangilansinmi?</translation>
<translation id="6768213884286397650">Hagaki (Postcard)</translation>
-<translation id="6774185088257932239">Inkognito haqida <ph name="BEGIN_LINK" />batafsil<ph name="END_LINK" /></translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">Siyohrang</translation>
<translation id="6786747875388722282">Kengaytmalar</translation>
@@ -1864,7 +1904,6 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="706295145388601875">Chrome sozlamalari orqali manzillarni kiritish va boshqarish</translation>
<translation id="7064851114919012435">Aloqa ma’lumoti</translation>
<translation id="7068733155164172741"><ph name="OTP_LENGTH" /> xonali kodni kiriting</translation>
-<translation id="7070090581017165256">Bu sayt haqida</translation>
<translation id="70705239631109039">Saytga ulanish butunlay xavfsiz emas</translation>
<translation id="7075452647191940183">Yuborilgan soʻrov juda katta</translation>
<translation id="7079718277001814089">Ehtiyot bo‘ling! Bu sayt zararli.</translation>
@@ -1881,6 +1920,12 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="7111012039238467737">(yaroqli)</translation>
<translation id="7118618213916969306">Klipborddagi havolani qidirish, <ph name="SHORT_URL" /></translation>
<translation id="7119414471315195487">Boshqa varaq va dasturlarni yoping</translation>
+<translation id="7129355289156517987">Chromiumda barcha Inkognito varaqlar yopilsa, ulardagi faoliyatingiz bu qurilmadan tozalanadi:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Brauzer tarixi<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Qidiruv tarixi<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Shakllarga kiritilgan maʼlumotlar<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">Bu manzilga yetkazib bera olmaymiz. Boshqa manzilni tanlang.</translation>
<translation id="7132939140423847331">Administrator bu maʼlumotlardan nusxa olishni taqiqlagan.</translation>
<translation id="7135130955892390533">Holat axboroti</translation>
@@ -1903,6 +1948,7 @@ Aks holda bu maxfiylik sozlamalaringiz tomonidan bloklanadi. Bunda siz ochgan sa
<translation id="7192203810768312527">Xotiradan <ph name="SIZE" /> bo‘shatiladi. Bundan keyin ba’zi veb-saytlar sekinroq yuklanishi mumkin.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">Administratorga koʻrinadigan axborotlar:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, yangi Inkognito varaq ochish va internetdan maxfiy foydalanish uchun avval Tab, keyin Enter tugmasini bosing</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> sayti xavfsizlik standartlariga muvofiq kelmadi.</translation>
<translation id="7210993021468939304">Konteyner ichidagi Linux jarayonlari va Linux ilovalarining konteyner ichida oʻrnatilishi va ishga tushirilishi</translation>
@@ -1934,6 +1980,7 @@ Batafsil axborot:
<translation id="7304562222803846232">Google hisobi maxfiylik sozlamalarini boshqarish</translation>
<translation id="7305756307268530424">Sekinroq ishga tushirish</translation>
<translation id="7308436126008021607">orqa fonda sinxronlash</translation>
+<translation id="7310392214323165548">Qurilma tez orada qayta ishga tushadi</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">Internetga ulanish yuzasidan yordam</translation>
<translation id="7323804146520582233">“<ph name="SECTION" />†bandini yopish</translation>
@@ -1941,6 +1988,7 @@ Batafsil axborot:
<translation id="7334320624316649418">&amp;Qayta tartiblashni qayta bajarish</translation>
<translation id="7335157162773372339">Kameradan foydalanish uchun ruxsat soʻrashi mumkin</translation>
<translation id="7337248890521463931">Koʻproq qatorlarni koʻrsatish</translation>
+<translation id="7337418456231055214">Virtual karta raqami kiritilmadimi? Nusxalanadigan karta maʼlumotlari ustiga bosing. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">Sizdagi tizimda ishlamaydi.</translation>
<translation id="733923710415886693">Sertifikatning ishonchlilik belgilari haqidagi ma’lumot server tomonidan taqdim etilmadi.</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1963,6 +2011,7 @@ Batafsil axborot:
<translation id="7378627244592794276">Yo‘q</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">Tegishli emas</translation>
+<translation id="7388594495505979117">{0,plural, =1{Qurilmangiz 1 daqiqadan keyin qayta ishga tushadi}other{Qurilmangiz # daqiqadan keyin qayta ishga tushadi}}</translation>
<translation id="7390545607259442187">Kartani tasdiqlash</translation>
<translation id="7392089738299859607">Manzilni yangilash</translation>
<translation id="7399802613464275309">Xavfsizlik tekshiruvi</translation>
@@ -1999,6 +2048,12 @@ Batafsil axborot:
<translation id="7485870689360869515">Ma‘lumotlar topilmadi.</translation>
<translation id="7495528107193238112">Bu kontent bloklandi. Muammoni yechish uchun sayt egasiga murojaat qiling.</translation>
<translation id="7497998058912824456">Doc hujjatini yaratish tugmasi, yangi Google Doc hujjatini tezda yaratish uchun Enter tugmasini bosing</translation>
+<translation id="7506488012654002225">Chromium quyidagi maʼlumotlarni <ph name="BEGIN_EMPHASIS" />saqlamaydi<ph name="END_EMPHASIS" />:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Brauzer tarixi
+ <ph name="LIST_ITEM" />Cookie fayllar va sayt maʼlumotlari
+ <ph name="LIST_ITEM" />Shakllarga kiritilgan maʼlumotlar
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">Qurilmaning qaytarilgan identifikatori bo‘sh yoki joriy qurilma identifikatoriga mos kelmaydi</translation>
<translation id="7508870219247277067">Yashil avokado</translation>
<translation id="7511955381719512146">Siz ulangan Wi-Fi tarmog‘i <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> sahifaga o‘tishingizni talab qilishi mumkin.</translation>
@@ -2112,7 +2167,6 @@ Batafsil axborot:
<translation id="7813600968533626083">Bu taklif Chrome’dan o‘chirib tashlansinmi?</translation>
<translation id="781440967107097262">Klipbord ulashilsinmi?</translation>
<translation id="7815407501681723534">“<ph name="SEARCH_STRING" />†so‘rovi bo‘yicha <ph name="NUMBER_OF_RESULTS" /> ta <ph name="SEARCH_RESULTS" /> topildi.</translation>
-<translation id="782125616001965242">Bu sayt haqida maʼlumotlarni chiqarish</translation>
<translation id="782886543891417279">Siz ulangan Wi-Fi (<ph name="WIFI_NAME" />) tarmog‘i hisob sahifasida tizimga kirishingizni talab qilishi mumkin.</translation>
<translation id="7836231406687464395">Postfix (Envelope)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{Hech qanday}=1{1 ta ilova (<ph name="EXAMPLE_APP_1" />)}=2{2 ta ilova (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}other{# ta ilova (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}}</translation>
@@ -2129,7 +2183,6 @@ Batafsil axborot:
<translation id="7888575728750733395">Bosma uchun rangli renderlash usuli</translation>
<translation id="7894280532028510793">Xatosiz kiritilgan boʻlsa, <ph name="BEGIN_LINK" />Tarmoq diagnostikasini<ph name="END_LINK" /> ishga tushiring.</translation>
<translation id="7904208859782148177">C3 (Envelope)</translation>
-<translation id="7931318309563332511">Noma’lum</translation>
<translation id="793209273132572360">Manzil yangilansinmi?</translation>
<translation id="7932579305932748336">Muqovalash</translation>
<translation id="79338296614623784">Telefon raqamini xatosiz kiriting</translation>
@@ -2154,13 +2207,14 @@ Batafsil axborot:
<translation id="7976214039405368314">Limitdan oshib ketdi</translation>
<translation id="7977538094055660992">Chiqarish qurilmasi</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">Ulandi</translation>
<translation id="798134797138789862">Virtual reallik qurilmalari va axborotlardan foydalanish uchun ruxsat soʻrashi mumkin</translation>
<translation id="7984945080620862648"><ph name="SITE" /> saytiga o‘tib bo‘lmadi, chunki veb-sayt shifrlangan hisob ma’lumotlarini yubordi, Chrome ular bilan ishlay olmaydi. Tarmoq xatoligi yoki saytga hujumlar odatda vaqtinchalik bo‘ladi, shu sababli bu sahifa keyinroq ishga tushishi mumkin.</translation>
-<translation id="79859296434321399">Virtual reallik kontentini ochish uchun ARCore ilovasini yuklab oling</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">Belgilash</translation>
<translation id="7992044431894087211"><ph name="APPLICATION_TITLE" /> ilovasiga ekranni ulashish davom ettirildi</translation>
<translation id="7995512525968007366">Ko‘rsatilmagan</translation>
+<translation id="7998269595945679889">Inkognito varaq ochish tugmasi, yangi Inkognito varaqni ochish va Internetdan maxfiy foydalanish uchun Enter tugmasini bosing</translation>
<translation id="800218591365569300">Xotirani bo‘shatish uchun boshqa oyna va dasturlarni yopib ko‘ring</translation>
<translation id="8004582292198964060">Brauzer</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{Bu karta va uning toʻlov manzillari saqlanadi. <ph name="USER_EMAIL" /> hisobi bilan kirganingizdan keyin undan foydalanishingiz mumkin.}other{Bu kartalar va uning toʻlov manzillari saqlanadi. <ph name="USER_EMAIL" /> hisobi bilan kirganingizdan keyin ulardan foydalanishingiz mumkin.}}</translation>
@@ -2220,6 +2274,7 @@ Batafsil axborot:
<translation id="8202370299023114387">Ziddiyat</translation>
<translation id="8206978196348664717">Prc4 (Envelope)</translation>
<translation id="8211406090763984747">Bu ulanish xavfsiz</translation>
+<translation id="8217240300496046857">Saytlar sizni internet boʻylab kuzatadigan cookie fayllardan foydalana olmaydi. Ayrim saytlardagi funksiyalar ishlamay qolishi mumkin.</translation>
<translation id="8218327578424803826">Tayinlangan joylashuv:</translation>
<translation id="8220146938470311105">C7/C6 (Envelope)</translation>
<translation id="8225771182978767009">Bu saytga kirish ushbu kompyuter sozlamalarida taqiqlab qo‘yilgan.</translation>
@@ -2260,14 +2315,9 @@ Batafsil axborot:
<translation id="830498451218851433">Yarim taxlash</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">Oʻrnatilgan ilovalar va ularning qanday ishlatilishi</translation>
+<translation id="8317207217658302555">ARCore yangilansinmi?</translation>
<translation id="831997045666694187">Kechqurun</translation>
<translation id="8321476692217554900">bildirishnomalar</translation>
-<translation id="8328484624016508118">Barcha Inkognito varaqlar yopilganidan keyin Chrome quyidagilarni tozalaydi:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Bu qurilmadagi bauzer faoliyati tarixi<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Bu qurilmadagi qidiruv tarixi<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Shakllarda kiritilgan axborotlar<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489"><ph name="HOST_NAME" /> saytiga kirish taqiqlangan</translation>
<translation id="833262891116910667">Ajratib belgilash</translation>
<translation id="8339163506404995330"><ph name="LANGUAGE" /> tilidagi sahifalar tarjima qilinmaydi</translation>
@@ -2319,6 +2369,7 @@ Batafsil axborot:
<translation id="8507227106804027148">Buyruqlar qatori</translation>
<translation id="8508648098325802031">Qidiruv ikonkasi</translation>
<translation id="8511402995811232419">Cookie fayllarni boshqarish</translation>
+<translation id="8519753333133776369">HID qurilmaga administrator ruxsat bergan</translation>
<translation id="8522552481199248698">Chrome Google hisobingizni himoyalash va parolni almashtirish uchun yordam beradi.</translation>
<translation id="8530813470445476232">Brauzer tarixi, cookie fayllar, kesh va boshqa Chrome sozlamalarini tozalang</translation>
<translation id="8533619373899488139">Administrator tomonidan tuzilgan URL manzillar qora roʻyxati va boshqa parametrlarni &lt;strong&gt;chrome://policy&lt;/strong&gt; sahifasi orqali koʻrish mumkin.</translation>
@@ -2330,7 +2381,6 @@ Batafsil axborot:
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{Ruxsatni tiklash}other{Ruxsatlarni tiklash}}</translation>
<translation id="8555010941760982128">Hisob-kitob vaqtida ushbu kodni kiriting</translation>
<translation id="8557066899867184262">CVC kod kartangizning orqa tomonida joylashgan.</translation>
-<translation id="8558485628462305855">Virtual reallik kontentini ochish uchun ARCore ilovasini yangilang</translation>
<translation id="8559762987265718583">Tizimdagi sana va vaqt sozlamalari (<ph name="DATE_AND_TIME" />) noto‘g‘ri bo‘lganligi sababli <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> domeni bilan havfsiz aloqa o‘rnatib bo‘lmadi.</translation>
<translation id="8564182942834072828">Bir nechta hujjat/Tartibsiz nusxalarda</translation>
<translation id="8564985650692024650">Parolingizni <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> domenidan tashqaridagi saytda kiritgan bo‘lsangiz, uni zudlik bilan almashtirishingizni tavsiya etamiz.</translation>
@@ -2349,6 +2399,7 @@ Batafsil axborot:
<translation id="865032292777205197">harakat sensorlari</translation>
<translation id="8663226718884576429">Buyurtma axboroti, <ph name="TOTAL_LABEL" />, Batafsil</translation>
<translation id="8666678546361132282">Ingliz tili</translation>
+<translation id="8669306706049782872">Oynalarni ochish va joylash uchun ekranlardagi axborotdan foydalanish</translation>
<translation id="867224526087042813">Imzo</translation>
<translation id="8676424191133491403">Kechikishsiz</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, javob, <ph name="ANSWER" /></translation>
@@ -2375,6 +2426,7 @@ Batafsil axborot:
<translation id="8731544501227493793">Parollarni boshqarish tugmasi, Chrome sozlamalari orqali parollarni koʻrish va boshqarish uchun Enter tugmasini bosing</translation>
<translation id="8734529307927223492"><ph name="DEVICE_TYPE" /> qurilmangiz <ph name="MANAGER" /> domenida boshqariladi</translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, yangi Inkognito oynasini ochib internetni kuzatuvsiz kezish uchun avval Tab, keyin esa Enter tugmasini bosing</translation>
+<translation id="8737685506611670901">“<ph name="PROTOCOL" />†havolalari <ph name="REPLACED_HANDLER_TITLE" /> xizmati o‘rnida qo‘llanilsin</translation>
<translation id="8738058698779197622">Tezkor havfsiz aloqa o‘rnatish uchun tizim soati to‘g‘ri sozlangan bo‘lishi kerak. Chunki sertifikatlar saytlarda haqiqiylik tekshiruvi uchun muddat cheklamalariga ega. Agar qurilmadagi vaqt noto‘g‘ri bo‘lsa, Chromium sertifikatlardan hali ham foydalanish mumkinligini tekshira olmaydi.</translation>
<translation id="8740359287975076522"><ph name="HOST_NAME" /> saytining &lt;abbr id="dnsDefinition"&gt;DNS manzili&lt;/abbr&gt; topilmadi. Muammo o‘rganilmoqda.</translation>
<translation id="8742371904523228557"><ph name="ORIGIN" /> sayti uchun tasdiq kodingiz: <ph name="ONE_TIME_CODE" /></translation>
@@ -2402,6 +2454,7 @@ Batafsil axborot:
<translation id="883848425547221593">Boshqa xatcho‘plar</translation>
<translation id="884264119367021077">Yetkazib berish manzili</translation>
<translation id="884923133447025588">Javob mexanizmi topilmadi.</translation>
+<translation id="8849262850971482943">Xavfsizlikni oshirish uchun virtual kartadan foydalaning</translation>
<translation id="885730110891505394">Google bilan baham ko‘rish</translation>
<translation id="8858065207712248076">Parolingizni <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> domenidan tashqaridagi saytda kiritgan bo‘lsangiz, uni zudlik bilan almashtirishingizni tavsiya etamiz.</translation>
<translation id="885906927438988819">Xatosiz kiritilgan boʻlsa, <ph name="BEGIN_LINK" />Windows Tarmoq diagnostikasini<ph name="END_LINK" /> ishga tushiring.</translation>
@@ -2451,6 +2504,7 @@ Batafsil axborot:
<translation id="9004367719664099443">VR seansi faol</translation>
<translation id="9005998258318286617">PDF hujjat yuklanmadi.</translation>
<translation id="9008201768610948239">Tashlab ketish</translation>
+<translation id="901834265349196618">e-pochta</translation>
<translation id="9020200922353704812">Kartaga to‘lov manzilini kiriting</translation>
<translation id="9020542370529661692">Bu sahifa <ph name="TARGET_LANGUAGE" /> tiliga o‘girildi.</translation>
<translation id="9020742383383852663">A8</translation>
@@ -2499,6 +2553,7 @@ Batafsil axborot:
<translation id="9150045010208374699">Kameradan foydalanish</translation>
<translation id="9150685862434908345">Adminitratoringiz brauzerni masofadan sozlashi mumkin. Bu qurilmadagi amallar Chromedan tashqarida boshqarilishi mumkin. <ph name="BEGIN_LINK" />Batafsil<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">Yangilangan</translation>
+<translation id="9155211586651734179">Audio jihozlar biriktirildi</translation>
<translation id="9157595877708044936">Sozlanmoqda...</translation>
<translation id="9158625974267017556">C6 (Envelope)</translation>
<translation id="9164029392738894042">Aniqlik tekshiruvi</translation>
diff --git a/chromium/components/strings/components_strings_vi.xtb b/chromium/components/strings/components_strings_vi.xtb
index aa5ea140412..bc95b3c7fbb 100644
--- a/chromium/components/strings/components_strings_vi.xtb
+++ b/chromium/components/strings/components_strings_vi.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">Xem thông tin chi tiêÌt</translation>
<translation id="1030706264415084469"><ph name="URL" /> muốn lưu trữ vĩnh viễn một lượng lớn dữ liệu trên thiết bị của bạn</translation>
<translation id="1032854598605920125">Xoay theo chiá»u kim đồng hồ</translation>
+<translation id="1033329911862281889">Chế Ä‘á»™ ẩn danh không ẩn caÌc hoạt Ä‘á»™ng sau đây của baÌ£n trên maÌ£ng:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Trang web và dịch vụ bạn sử dụng có thể xem lượt truy cập<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Doanh nghiệp hoặc trÆ°á»ng há»c có thể theo dõi hoạt Ä‘á»™ng duyệt web<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Nhà cung cấp dịch vụ Internet có thể giám sát lưu lượng truy cập web<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">Tắt</translation>
<translation id="1036982837258183574">Nhấn |<ph name="ACCELERATOR" />| để thoát khá»i chế Ä‘á»™ toàn màn hình</translation>
<translation id="1038106730571050514">Hiển thị các đỠxuất</translation>
<translation id="1038842779957582377">tên không biết</translation>
<translation id="1041998700806130099">Thông báo tỠcông việc</translation>
<translation id="1048785276086539861">Khi bạn chỉnh sửa chú thích, tài liệu này sẽ trở vỠchế độ xem một trang</translation>
-<translation id="1049743911850919806">Ẩn danh</translation>
<translation id="1050038467049342496">Äóng các ứng dụng khác</translation>
<translation id="1055184225775184556">&amp;Hoàn tác thêm</translation>
<translation id="1056898198331236512">Cảnh báo</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">Bộ nhớ đệm chính sách OK</translation>
<translation id="1130564665089811311">Nút Dịch trang, nhấn phím Enter để dịch trang này bằng Google Dịch</translation>
<translation id="1131264053432022307">Hình ảnh bạn đã sao chép</translation>
+<translation id="1142846828089312304">Chặn cookie của bên thứ ba ở Chế độ ẩn danh</translation>
<translation id="1150979032973867961">Máy chủ này không chứng minh được rằng đó là <ph name="DOMAIN" />; chứng chỉ bảo mật của máy chủ này không được hệ Ä‘iá»u hành máy tính của bạn tin cậy. Äiá»u này có thể do định cấu hình sai hoặc có kẻ tấn công chặn kết nối của bạn.</translation>
<translation id="1151972924205500581">Mật khẩu bắt buộc</translation>
<translation id="1156303062776767266">Bạn đang xem tệp trên máy hoặc tệp được chia sẻ</translation>
@@ -64,7 +70,6 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="1178581264944972037">Tạm dừng</translation>
<translation id="1181037720776840403">Xóa</translation>
<translation id="1186201132766001848">Kiểm tra mật khẩu</translation>
-<translation id="1195210374336998651">Chuyển đến trang cài đặt ứng dụng</translation>
<translation id="1195558154361252544">Äã tá»± Ä‘á»™ng chặn thông báo đối vá»›i má»i trang web, ngoại trừ những trang web bạn cho phép</translation>
<translation id="1197088940767939838">Màu cam</translation>
<translation id="1201402288615127009">Tiếp theo</translation>
@@ -111,7 +116,7 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="1307966114820526988">Tính năng sắp ngừng hoạt động</translation>
<translation id="1308113895091915999">Ưu đãi có sẵn</translation>
<translation id="1312803275555673949">Bằng chứng nào xác minh việc này?</translation>
-<translation id="131405271941274527"><ph name="URL" /> muốn gửi và nhận thông tin khi bạn chạm điện thoại của bạn vào thiết bị dùng công nghệ giao tiếp tầm gần (NFC)</translation>
+<translation id="1314311879718644478">Xem nội dung thá»±c tế tăng cÆ°á»ng</translation>
<translation id="1314509827145471431">Äóng gáy bên phải</translation>
<translation id="1318023360584041678">Äã lÆ°u trong nhóm thẻ</translation>
<translation id="1319245136674974084">Không há»i lại đối vá»›i ứng dụng này</translation>
@@ -161,6 +166,7 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="142858679511221695">NgÆ°á»i dùng Google Cloud</translation>
<translation id="1428729058023778569">Cảnh báo này xuất hiện vì trang web mà bạn đang truy cập không hỗ trợ giao thức HTTPS. <ph name="BEGIN_LEARN_MORE_LINK" />Tìm hiểu thêm<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">In</translation>
+<translation id="1432187715652018471">trang muốn cài đặt trình xử lý dịch vụ.</translation>
<translation id="1432581352905426595">Quản lý công cụ tìm kiếm</translation>
<translation id="1436185428532214179">Trang web có thể yêu cầu chỉnh sửa các tệp và thư mục trên thiết bị của bạn</translation>
<translation id="1442386063175183758">Gấp dạng cửa bên phải</translation>
@@ -181,6 +187,12 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="1483493594462132177">Gá»­i</translation>
<translation id="1484290072879560759">Chá»n địa chỉ giao hàng</translation>
<translation id="1492194039220927094">Gửi thông báo đẩy khi có chính sách:</translation>
+<translation id="149293076951187737">Khi bạn đóng tất cả caÌc thẻ ẩn danh trên Chrome, chuÌng tôi sẽ xoaÌ khá»i thiết bị những hoạt Ä‘á»™ng sau đây của baÌ£n trên những thẻ Ä‘oÌ:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Hoạt động duyệt web<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Nhật ký tìm kiếm<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Thông tin đã nhập vào biểu mẫu<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">Quay lại thẻ</translation>
<translation id="1501859676467574491">Hiển thị các thẻ trong Tài khoản Google của bạn</translation>
<translation id="1507202001669085618">&lt;p&gt;Bạn sẽ gặp lỗi này nếu đang sử dụng cổng Wi-Fi yêu cầu bạn đăng nhập để có thể vào mạng.&lt;/p&gt;
@@ -208,6 +220,8 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="1559572115229829303">&lt;p&gt;Không thể thiết lập kết nối riêng tư với <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> vì ngày và giỠ(<ph name="DATE_AND_TIME" />) trên thiết bị của bạn không chính xác.&lt;/p&gt;
&lt;p&gt;Hãy Ä‘iá»u chỉnh ngày và giá» từ phần &lt;strong&gt;Chung&lt;/strong&gt; của ứng dụng &lt;strong&gt;Cài đặt&lt;/strong&gt;.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">Quản trị viên của bạn sẽ khởi động lại thiết bị của bạn vào <ph name="TIME" /> <ph name="DATE" /></translation>
+<translation id="156703335097561114">Thông tin nôÌi mạng nhÆ° địa chỉ, cấu hình giao diện và chất lượng kết nối</translation>
<translation id="1567040042588613346">Chính sách này đang hoạt động như dự kiến nhưng lại thay thế cho cùng một giá trị được đặt trong một nguồn khác.</translation>
<translation id="1569487616857761740">Nhập ngày hết hạn</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="1583429793053364125">Äã xảy ra lá»—i khi hiển thị trang web này.</translation>
<translation id="1586541204584340881">Các tiện ích bạn đã cài đặt</translation>
<translation id="1588438908519853928">Bình thÆ°á»ng</translation>
+<translation id="1589050138437146318">Cài đặt ARCore?</translation>
<translation id="1592005682883173041">Quyá»n truy cập dữ liệu cục bá»™</translation>
<translation id="1594030484168838125">Chá»n</translation>
<translation id="160851722280695521">Chơi trò chơi khủng long trên Chrome</translation>
@@ -283,6 +298,7 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
tiêu đỠđó không đúng định dạng. Äiá»u này khiến trình duyệt không hoàn thành được
yêu cầu của bạn là truy cập vào <ph name="SITE" />. Nhà Ä‘iá»u hành trang web có thể
dựa vào chính sách nguồn gốc để định cấu hình bảo mật và các thuộc tính khác cho trang web.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Tìm hiểu thêm vá» ChÃªÌ Ä‘Ã´Ì£ ẩn danh trên Chromium<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">Thẻ đang mở của bạn xuất hiện ở đây</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -359,7 +375,7 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="204357726431741734">Äăng nhập để sá»­ dụng mật khẩu đã lÆ°u trong Tài khoản Google của bạn</translation>
<translation id="2053111141626950936">Các trang viết bằng <ph name="LANGUAGE" /> sẽ không được dịch.</translation>
<translation id="2053373601901562871">{NUM_DAYS,plural, =0{Khi chế Ä‘á»™ Ä‘iá»u khiển này bật và trạng thái là Ä‘ang hoạt Ä‘á»™ng, Chrome sẽ xác định xem hoạt Ä‘á»™ng duyệt web gần đây của bạn giống vá»›i nhóm đông ngÆ°á»i hoặc "nhóm thuần tập" nào nhất. Các nhà quảng cáo có thể chá»n quảng cáo cho nhóm này và hoạt Ä‘á»™ng duyệt web sẽ được lÆ°u giữ riêng tÆ° trên thiết bị của bạn. Nhóm của bạn được cập nhật hằng ngày.}=1{Khi chế Ä‘á»™ Ä‘iá»u khiển này bật và trạng thái là Ä‘ang hoạt Ä‘á»™ng, Chrome sẽ xác định xem hoạt Ä‘á»™ng duyệt web gần đây của bạn giống vá»›i nhóm đông ngÆ°á»i hoặc "nhóm thuần tập" nào nhất. Các nhà quảng cáo có thể chá»n quảng cáo cho nhóm này và hoạt Ä‘á»™ng duyệt web sẽ được lÆ°u giữ riêng tÆ° trên thiết bị của bạn. Nhóm của bạn được cập nhật hằng ngày.}other{Khi chế Ä‘á»™ Ä‘iá»u khiển này bật và trạng thái là Ä‘ang hoạt Ä‘á»™ng, Chrome sẽ xác định xem hoạt Ä‘á»™ng duyệt web gần đây của bạn giống vá»›i nhóm đông ngÆ°á»i hoặc "nhóm thuần tập" nào nhất. Các nhà quảng cáo có thể chá»n quảng cáo cho nhóm này và hoạt Ä‘á»™ng duyệt web sẽ được lÆ°u giữ riêng tÆ° trên thiết bị của bạn. Nhóm của bạn được cập nhật {NUM_DAYS} ngày má»™t lần.}}</translation>
-<translation id="2053553514270667976">Mã zip</translation>
+<translation id="2053553514270667976">Mã ZIP</translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 đỠxuất}other{# đỠxuất}}</translation>
<translation id="2071156619270205202">Thẻ này không đáp ứng Ä‘iá»u kiện để tạo số thẻ ảo.</translation>
<translation id="2071692954027939183">Các thông báo tá»± Ä‘á»™ng bị chặn do bạn thÆ°á»ng xuyên không cho phép các thông báo đó</translation>
@@ -410,6 +426,7 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="22081806969704220">Khay 3</translation>
<translation id="2212735316055980242">Không tìm thấy chính sách</translation>
<translation id="2213606439339815911">Äang tìm nạp các mục nhập...</translation>
+<translation id="2213612003795704869">Trang Ä‘Æ°Æ¡Ì£c in</translation>
<translation id="2215727959747642672">Chỉnh sửa tệp</translation>
<translation id="2218879909401188352">Những kẻ tấn công hiện ở trên <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> có thể cài đặt ứng dụng nguy hiểm làm há»ng thiết bị của bạn, thêm các khoản phí ẩn vào hóa Ä‘Æ¡n di Ä‘á»™ng hoặc lấy cắp thông tin cá nhân của bạn. <ph name="BEGIN_LEARN_MORE_LINK" />Tìm hiểu thêm<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">Không có Internet</translation>
@@ -419,6 +436,7 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="2248949050832152960">Sử dụng WebAuthn</translation>
<translation id="2250931979407627383">May viá»n ở bên trái</translation>
<translation id="225207911366869382">Giá trị này không được dùng cho chính sách này nữa.</translation>
+<translation id="2256115617011615191">Khởi động lại ngay</translation>
<translation id="2258928405015593961">Hãy nhập một ngày hết hạn trong tương lai rồi thử lại</translation>
<translation id="225943865679747347">Mã lỗi: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">Lá»—i HTTP</translation>
@@ -446,6 +464,7 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="2337852623177822836">Cài đặt do quản trị viên kiểm soát</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> muốn ghép nối</translation>
<translation id="2346319942568447007">Hình ảnh bạn đã sao chép</translation>
+<translation id="2350796302381711542">Cho phép <ph name="HANDLER_HOSTNAME" /> mở tất cả liên kết <ph name="PROTOCOL" /> thay vì <ph name="REPLACED_HANDLER_TITLE" />?</translation>
<translation id="2354001756790975382">Dấu trang khác</translation>
<translation id="2354430244986887761">Gần đây, Duyệt web an toàn của Google <ph name="BEGIN_LINK" />đã tìm thấy các ứng dụng có hại<ph name="END_LINK" /> trên <ph name="SITE" />.</translation>
<translation id="2355395290879513365">Kẻ tấn công có thể thấy những hình ảnh mà bạn đang xem trên trang web này và lừa bạn bằng cách sửa đổi những hình ảnh đó.</translation>
@@ -471,6 +490,7 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="2413528052993050574">Máy chủ này không chứng minh được rằng đó là <ph name="DOMAIN" />; chứng chỉ bảo mật của máy chủ này có thể đã bị thu hồi. Äiá»u này có thể do định cấu hình sai hoặc có kẻ tấn công chặn kết nối của bạn.</translation>
<translation id="2414886740292270097">Tối</translation>
<translation id="2430968933669123598">Quản lý Tài khoản Google, nhấn phím Enter để quản lý thông tin, quyá»n riêng tÆ° và chế Ä‘á»™ bảo mật cho Tài khoản Google của bạn</translation>
+<translation id="2436186046335138073">Cho phép <ph name="HANDLER_HOSTNAME" /> mở tất cả liên kết <ph name="PROTOCOL" />?</translation>
<translation id="2438874542388153331">Äục 4 lá»— bên phải</translation>
<translation id="2450021089947420533">Hành trình</translation>
<translation id="2463739503403862330">Äiá»n</translation>
@@ -478,6 +498,7 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="2465655957518002998">Chá»n cách giao hàng</translation>
<translation id="2465688316154986572">Dập ghim</translation>
<translation id="2465914000209955735">Quản lý các tệp bạn đã tải xuống trong Chrome</translation>
+<translation id="2466004615675155314">Hiện thông tin trên web</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Chạy Chẩn đoán mạng<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">Thứ tự từ 1 đến N</translation>
<translation id="2470767536994572628">Khi bạn chỉnh sửa chú thích, tài liệu này sẽ trở vỠchế độ xem một trang và hướng xoay ban đầu</translation>
@@ -498,6 +519,7 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="2523886232349826891">Chỉ lưu trên thiết bị này</translation>
<translation id="2524461107774643265">Thêm thông tin khác</translation>
<translation id="2529899080962247600">TrÆ°á»ng này không được chứa nhiá»u hÆ¡n <ph name="MAX_ITEMS_LIMIT" /> mục. Tất cả mục thừa sẽ bị bá» qua.</translation>
+<translation id="2535585790302968248">Mở một thẻ ẩn danh mới để duyệt web ở chế độ riêng tư</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{và 1 miá»n khác}other{và # miá»n khác}}</translation>
<translation id="2536110899380797252">Thêm địa chỉ</translation>
<translation id="2539524384386349900">Phát hiện</translation>
@@ -523,7 +545,14 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="2597378329261239068">Tài liệu này được bảo vệ bằng mật khẩu. Vui lòng nhập mật khẩu.</translation>
<translation id="2609632851001447353">Các biến thể</translation>
<translation id="2610561535971892504">Nhấp để sao chép</translation>
+<translation id="2617988307566202237">Chrome <ph name="BEGIN_EMPHASIS" />sẽ không lưu<ph name="END_EMPHASIS" /> những thông tin sau:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Nhật ký duyệt web của bạn
+ <ph name="LIST_ITEM" />Cookie và dữ liệu trang web
+ <ph name="LIST_ITEM" />Thông tin đã nhập vào biểu mẫu
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (Phong bì)</translation>
+<translation id="2623663032199728144">Có thể yêu cầu sử dụng thông tin vỠmàn hình của bạn</translation>
<translation id="2625385379895617796">Äồng hồ của bạn chạy nhanh</translation>
<translation id="262745152991669301">Trang web có thể yêu cầu kết nối với thiết bị USB</translation>
<translation id="2629325967560697240">Äể tận dụng mức bảo mật cao nhất của Chrome, hãy <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />bật chế Ä‘á»™ bảo vệ tăng cÆ°á»ng<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -531,7 +560,7 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="2639739919103226564">Trạng thái:</translation>
<translation id="264810637653812429">Không tìm thấy thiết bị tương thích nào.</translation>
<translation id="2649204054376361687"><ph name="CITY" />, <ph name="COUNTRY" /></translation>
-<translation id="2649259151839507861"><ph name="CLEAR_BROWSING_DATA_FOCUSED_FRIENDLY_MATCH_TEXT" />, nhấn phím Tab rồi nhấn Enter để Xóa lịch sá»­ duyệt web, cookie, bá»™ nhá»› đệm và nhiá»u ná»™i dung khác trong phần cài đặt của Chrome</translation>
+<translation id="2649259151839507861"><ph name="CLEAR_BROWSING_DATA_FOCUSED_FRIENDLY_MATCH_TEXT" />, nhấn phím Tab rồi nhấn Enter để Xóa nhật ký duyệt web, cookie, bá»™ nhá»› đệm và nhiá»u ná»™i dung khác trong phần cài đặt của Chrome</translation>
<translation id="2650446666397867134">Truy cập vào tệp bị từ chối</translation>
<translation id="2653659639078652383">Gá»­i</translation>
<translation id="2659491813326907275">Cá nhân hóa các công cụ hỗ trợ tiếp cận của bạn trong phần cài đặt Chrome OS</translation>
@@ -540,7 +569,7 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="2666092431469916601">Hàng đầu</translation>
<translation id="2666117266261740852">Äóng các thẻ hoặc ứng dụng khác</translation>
<translation id="2672201172023654893">Trình duyệt của bạn không được quản lý.</translation>
-<translation id="2674170444375937751">Bạn có chắc chắn muốn xóa những trang này khá»i lịch sá»­ duyệt web của mình không?</translation>
+<translation id="2674170444375937751">Bạn có chắc chắn muốn xóa những trang này khá»i nhật ký duyệt web của mình không?</translation>
<translation id="2674804415323431591">Ẩn các đỠxuất</translation>
<translation id="2676271551327853224">Roc-8K</translation>
<translation id="2677748264148917807">Rá»i khá»i</translation>
@@ -557,6 +586,7 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="2709516037105925701">TÆ°Ì£ động Ä‘iá»n</translation>
<translation id="2713444072780614174">Trắng</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />, nhấn phím Tab rồi nhấn Enter để quản lý thông tin thanh toán và thẻ tín dụng trong phần cài đặt của Chrome</translation>
+<translation id="271663710482723385">Nhấn |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| để thoát chế độ toàn màn hình</translation>
<translation id="2721148159707890343">Yêu cầu đã thành công</translation>
<translation id="2723669454293168317">Chạy quy trình kiểm tra an toàn trong phần Cài đặt của Chrome</translation>
<translation id="2726001110728089263">Khay bên</translation>
@@ -587,6 +617,7 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="2850739647070081192">Invite (Phong bì)</translation>
<translation id="2856444702002559011">Những kẻ tấn công có thể đang cố gắng đánh cắp thông tin của bạn từ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (ví dụ: mật khẩu, thư hoặc thẻ tín dụng). <ph name="BEGIN_LEARN_MORE_LINK" />Tìm hiểu thêm<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">Trang web này hiển thị quảng cáo xâm nhập hoặc quảng cáo gây hiểu nhầm.</translation>
+<translation id="286512204874376891">Thẻ ảo giúp ngụy trang thẻ thá»±c của bạn để bảo vệ bạn khá»i nguy cÆ¡ bị lừa đảo.<ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">Thân thiện</translation>
<translation id="2876489322757410363">Äang thoát khá»i chế Ä‘á»™ Ẩn danh để thanh toán qua má»™t ứng dụng bên ngoài. Bạn muốn tiếp tục?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />, nhấn phím Tab rồi nhấn phím Enter để quản lý tính năng Duyệt web an toàn và nhiá»u tính năng khác trong phần Cài đặt của Chrome</translation>
@@ -611,6 +642,7 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="2930577230479659665">Cắt bỠsau mỗi bản sao chép</translation>
<translation id="2932085390869194046">Äá» xuất mật khẩu...</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019">Mở Ä‘Æ°á»ng liên kết <ph name="PROTOCOL" /></translation>
<translation id="2941952326391522266">Máy chủ này không chứng minh được rằng đó là <ph name="DOMAIN" />; chứng chỉ bảo mật của máy chủ này là từ <ph name="DOMAIN2" />. Äiá»u này có thể do định cấu hình sai hoặc có kẻ tấn công chặn kết nối của bạn.</translation>
<translation id="2943895734390379394">Thá»i gian tải lên:</translation>
<translation id="2948083400971632585">Bạn có thể tắt má»i proxy được định cấu hình cho kết nối từ trang cài đặt.</translation>
@@ -643,6 +675,7 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="3037605927509011580">Ôi, há»ng! </translation>
<translation id="3041612393474885105">Thông tin Chứng chỉ</translation>
<translation id="3044034790304486808">Tiếp tục tìm kiếm</translation>
+<translation id="305162504811187366">Nhật ký Chrome Remote Desktop, bao gồm cả dấu thá»i gian, mã phiên ứng dụng và máy chủ</translation>
<translation id="3060227939791841287">C9 (Phong bì)</translation>
<translation id="3061707000357573562">Dịch vụ vá lỗi</translation>
<translation id="306573536155379004">Äã bắt đầu trò chÆ¡i.</translation>
@@ -683,6 +716,7 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="3197136577151645743">Trang web có thể yêu cầu được biết khi bạn đang dùng thiết bị này</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />, hãy nhấn Tab, sau đó nhấn Enter để quản lý loại thông tin bạn đồng bộ hóa trong phần Cài đặt của Chrome</translation>
<translation id="320323717674993345">Hủy thanh toán</translation>
+<translation id="3203366800380907218">Trên web</translation>
<translation id="3207960819495026254">Äã đánh dấu trang</translation>
<translation id="3209034400446768650">Trang này có thể tính phí</translation>
<translation id="3212581601480735796">Hoạt động của bạn trên <ph name="HOSTNAME" /> sẽ bị giám sát</translation>
@@ -699,10 +733,12 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="3234666976984236645">Luôn luôn phát hiện ná»™i dung quan trá»ng trên trang web này</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />, Nhấn phím Tab rồi nhấn phím Enter để tuỳ chỉnh giao diện trình duyệt của bạn</translation>
<translation id="3240791268468473923">Äã mở thông tin xác thá»±c thanh toán an toàn không khá»›p vá»›i bảng thông tin xác thá»±c</translation>
+<translation id="324180406144491771">Äã chặn caÌc Ä‘Æ°Æ¡Ì€ng liên kêÌt đêÌn “<ph name="HOST_NAME" />â€</translation>
<translation id="3249845759089040423">Sành điệu</translation>
<translation id="3252266817569339921">Tiếng Pháp</translation>
<translation id="3257954757204451555">Ai là ngÆ°á»i phát tán thông tin này?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />, nhấn phím Tab rồi nhấn phím Enter để tạo nhanh một sự kiện mới trong Lịch Google</translation>
+<translation id="3261488570342242926">Tìm hiểu vỠthẻ ảo</translation>
<translation id="3264837738038045344">Nút quản lý chế độ cài đặt Chrome, hãy nhấn phím Enter để truy cập phần cài đặt Chrome của bạn</translation>
<translation id="3266793032086590337">Giá trị (xung đột)</translation>
<translation id="3268451620468152448">Thẻ đang mở</translation>
@@ -716,6 +752,7 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="3288238092761586174"><ph name="URL" /> có thể cần thực hiện các bước bổ sung để xác minh khoản thanh toán của bạn</translation>
<translation id="3293642807462928945">Hãy tìm hiểu thêm vỠchính sách <ph name="POLICY_NAME" /></translation>
<translation id="3295444047715739395">Xem và quản lý mật khẩu của bạn trong phần cài đặt của Chrome</translation>
+<translation id="3303795387212510132">Cho phép ứng dụng mở liên kết <ph name="PROTOCOL_SCHEME" />?</translation>
<translation id="3303855915957856445">Không tìm thấy kết quả tìm kiếm nào</translation>
<translation id="3304073249511302126">quét tìm Bluetooth</translation>
<translation id="3308006649705061278">ÄÆ¡n vị Tổ chức (OU)</translation>
@@ -729,12 +766,6 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="3345782426586609320">Mắt</translation>
<translation id="3355823806454867987">Thay đổi cài đặt proxy...</translation>
<translation id="3360103848165129075">Trang tính trình xử lý thanh toán</translation>
-<translation id="3361596688432910856">Chrome <ph name="BEGIN_EMPHASIS" />sẽ không lưu<ph name="END_EMPHASIS" /> thông tin sau đây:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Lịch sử duyệt web của bạn
- <ph name="LIST_ITEM" />Cookie và dữ liệu trang web
- <ph name="LIST_ITEM" />Thông tin đã nhập trong biểu mẫu
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">Chính sách này được sao chép tự động từ chính sách <ph name="OLD_POLICY" /> không còn dùng nữa. Thay vào đó, bạn nên sử dụng chính sách này.</translation>
<translation id="3364869320075768271"><ph name="URL" /> muốn sử dụng dữ liệu và thiết bị thực tế ảo của bạn</translation>
<translation id="3366477098757335611">Xem thẻ</translation>
@@ -817,7 +848,6 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="3587738293690942763">Ở giữa</translation>
<translation id="3592413004129370115">Italian (Phong bì)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{Bạn có thể đặt lại nhóm của mình bất cứ lúc nào. Bạn sẽ mất khoảng 1 ngày để tham gia một nhóm mới.}=1{Bạn có thể đặt lại nhóm của mình bất cứ lúc nào. Bạn sẽ mất khoảng 1 ngày để tham gia một nhóm mới.}other{Bạn có thể đặt lại nhóm của mình bất cứ lúc nào. Bạn sẽ mất {NUM_DAYS} ngày để tham gia một nhóm mới.}}</translation>
-<translation id="3596012367874587041">Cài đặt ứng dụng</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">Quản trị viên đã chặn ứng dụng</translation>
<translation id="3608932978122581043">Hướng nạp giấy</translation>
@@ -860,6 +890,7 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="370972442370243704">Bật tính năng Hành trình</translation>
<translation id="3711895659073496551">Tạm ngừng</translation>
<translation id="3712624925041724820">Giấy phép không đủ</translation>
+<translation id="3714633008798122362">lịch trên web</translation>
<translation id="3714780639079136834">Bật dữ liệu di dộng hoặc Wi-Fi</translation>
<translation id="3715597595485130451">Kết nối Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Kiểm tra proxy, tÆ°á»ng lá»­a và cấu hình DNS<ph name="END_LINK" /></translation>
@@ -921,6 +952,7 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="3906954721959377182">Máy tính bảng</translation>
<translation id="3909477809443608991"><ph name="URL" /> muốn phát nội dung được bảo vệ. Thông tin định danh của thiết bị sẽ được Google xác minh và trang web này có thể truy cập vào thông tin đó.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">Từ chối</translation>
<translation id="3939773374150895049">Sử dụng WebAuthn thay cho CVC?</translation>
<translation id="3946209740501886391">Luôn há»i trên trang web này</translation>
<translation id="3947595700203588284">Trang web có thể yêu cầu kết nối với thiết bị MIDI</translation>
@@ -942,6 +974,7 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="3990250421422698716">Bù dịch chuyển</translation>
<translation id="3996311196211510766">Trang web <ph name="ORIGIN" /> đã yêu cầu phải áp dụng một chính sách nguồn gốc
cho tất cả yêu cầu gửi tới trang web đó. Tuy nhiên, chính sách này hiện không áp dụng được.</translation>
+<translation id="4009243425692662128">Ná»™i dung của các trang bạn in được gá»­i tÆ¡Ìi Google Cloud hoặc các bên thứ ba để phân tích. Ví dụ: nội dung đó có thể được quét tìm dữ liệu nhạy cảm.</translation>
<translation id="4010758435855888356">Cho phép quyá»n truy cập bá»™ nhá»›?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{Tài liệu PDF chứa {COUNT} trang}other{Tài liệu PDF chứa {COUNT} trang}}</translation>
<translation id="4023431997072828269">Vì bạn Ä‘ang gá»­i biểu mẫu này bằng Ä‘Æ°á»ng kết nối không an toàn nên ngÆ°á»i khác có thể nhìn thấy thông tin của bạn.</translation>
@@ -1036,6 +1069,7 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="4250680216510889253">Không</translation>
<translation id="4253168017788158739">Lưu ý</translation>
<translation id="425582637250725228">Các thay đổi bạn đã thực hiện có thể không được lưu.</translation>
+<translation id="425869179292622354">Tăng cÆ°á»ng bảo mật nhá» thẻ ảo?</translation>
<translation id="4258748452823770588">Chữ ký không hợp lệ</translation>
<translation id="4261046003697461417">Không thể chú thích tài liệu được bảo vệ</translation>
<translation id="4265872034478892965">Äược quản trị viên cho phép</translation>
@@ -1098,6 +1132,7 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="4434045419905280838">Cửa sổ bật lên và liên kết chuyển hướng</translation>
<translation id="4435702339979719576">Bưu thiếp)</translation>
<translation id="443673843213245140">Äã tắt sá»­ dụng proxy nhÆ°ng cấu hình proxy rõ ràng được chỉ định.</translation>
+<translation id="4441832193888514600">Bá» qua vì chính sách này chỉ có thể thiết lập thành chính sách ngÆ°á»i dùng trên đám mây.</translation>
<translation id="4450893287417543264">Không hiện lại</translation>
<translation id="4451135742916150903">Trang web có thể yêu cầu kết nối với thiết bị HID</translation>
<translation id="4452328064229197696">Mật khẩu bạn vừa sá»­ dụng đã bị lá»™ trong má»™t sá»± cố rò rỉ dữ liệu. Äể bảo mật tài khoản của bạn, Trình quản lý mật khẩu của Google khuyên bạn nên kiểm tra các mật khẩu đã lÆ°u.</translation>
@@ -1153,6 +1188,7 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="4628948037717959914">Ảnh</translation>
<translation id="4631649115723685955">Äã liên kết Æ°u đãi hoàn tiá»n</translation>
<translation id="4636930964841734540">Thông tin</translation>
+<translation id="4638670630777875591">ChÃªÌ Ä‘Ã´Ì£ ẩn danh trên Chromium</translation>
<translation id="464342062220857295">Tìm kiếm tính năng</translation>
<translation id="4644670975240021822">Thứ tự đảo ngược hướng xuống</translation>
<translation id="4646534391647090355">Chuyển đến đó ngay</translation>
@@ -1173,6 +1209,7 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="4708268264240856090">Kết nối của bạn bị gián đoạn</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Chạy Chẩn đoán mạng của Windows<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426">Mật khẩu của <ph name="USERNAME" /></translation>
<translation id="4724144314178270921">Trang web có thể yêu cầu xem văn bản và hình ảnh trên bảng nhớ tạm</translation>
<translation id="4726672564094551039">Tải lại chính sách</translation>
<translation id="4728558894243024398">Nền tảng</translation>
@@ -1194,6 +1231,7 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="4757993714154412917">Bạn vừa nhập mật khẩu vào má»™t trang web lừa đảo. Äể bảo mật tài khoản của mình, bạn nên kiểm tra các mật khẩu đã lÆ°u trên Chromium.</translation>
<translation id="4758311279753947758">Thêm thông tin liên hệ</translation>
<translation id="4761104368405085019">Sử dụng micrô của bạn</translation>
+<translation id="4761869838909035636">Chạy quy trình Kiểm tra an toàn trên Chrome</translation>
<translation id="4764776831041365478">Trang web tại <ph name="URL" /> có thể tạm thá»i không hoạt Ä‘á»™ng hay được chuyển vÄ©nh viá»…n sang địa chỉ web má»›i.</translation>
<translation id="4766713847338118463">Dập 2 ghim dưới cùng</translation>
<translation id="4771973620359291008">Xảy ra lỗi chưa biết.</translation>
@@ -1214,12 +1252,6 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="4819347708020428563">Chỉnh sửa chú thích ở chế độ xem mặc định?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />, nhấn phím Tab rồi nhấn phím Enter để tạo nhanh một trang tính mới trong Google Trang tính</translation>
<translation id="4825507807291741242">Mạnh mẽ</translation>
-<translation id="4827402517081186284">Chế độ ẩn danh không ẩn các hoạt động trực tuyến của bạn:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Các trang web biết thá»i Ä‘iểm bạn truy cập<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />NgÆ°á»i quản lý doanh nghiệp hoặc trÆ°á»ng há»c có thể theo dõi hoạt Ä‘á»™ng duyệt web<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Nhà cung cấp dịch vụ Internet có thể giám sát lưu lượng truy cập web<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">Bật cảnh báo</translation>
<translation id="4838327282952368871">MÆ¡ má»™ng</translation>
<translation id="4840250757394056958">Xem nhật ký Chrome của bạn</translation>
@@ -1231,12 +1263,12 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="4854362297993841467">Phương thức phân phối này không có sẵn. Hãy thử một phương thức khác.</translation>
<translation id="4854853140771946034">Tạo nhanh một ghi chú mới trong Google Keep</translation>
<translation id="485902285759009870">Äang xác minh mã...</translation>
+<translation id="4866506163384898554">NhâÌn |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| để con trá» xuâÌt hiện</translation>
<translation id="4876188919622883022">Chế độ xem đơn giản</translation>
<translation id="4876305945144899064">Không có tên ngÆ°á»i dùng</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{Không có}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831">Cụm từ tìm kiếm <ph name="TEXT" /></translation>
<translation id="4879491255372875719">Tự động (mặc định)</translation>
-<translation id="4879725228911483934">Mở và đặt các cửa sổ trên màn hình của bạn</translation>
<translation id="4880827082731008257">Nhật ký tìm kiếm</translation>
<translation id="4881695831933465202">Mở</translation>
<translation id="4885256590493466218">Thanh toán bằng <ph name="CARD_DETAIL" /> khi thanh toán</translation>
@@ -1245,6 +1277,7 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">Cuộn thứ chín</translation>
<translation id="4901778704868714008">LÆ°u...</translation>
+<translation id="4905659621780993806">Quản trị viên của bạn sẽ tá»± Ä‘á»™ng khởi Ä‘á»™ng lại thiết bị của bạn vào luÌc <ph name="TIME" /> <ph name="DATE" /> Hãy lÆ°u má»i mục Ä‘ang mở trÆ°á»›c khi thiết bị của bạn khởi Ä‘á»™ng lại.</translation>
<translation id="4913987521957242411">Äục lá»— trên cùng bên trái</translation>
<translation id="4918221908152712722">Cài đặt <ph name="APP_NAME" /> (không cần tải xuống)</translation>
<translation id="4923459931733593730">Thanh toán</translation>
@@ -1253,6 +1286,7 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, nhấn phím Tab rồi nhấn Enter để tìm kiếm</translation>
<translation id="4930153903256238152">Dung tích lớn</translation>
+<translation id="4940163644868678279">ChÃªÌ Ä‘Ã´Ì£ ẩn danh trên Chrome</translation>
<translation id="4943872375798546930">Không tìm thấy kết quả nào</translation>
<translation id="4950898438188848926">Nút chuyển đổi thẻ, nhấn phím Enter để chuyển sang thẻ đang mở, <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="495170559598752135">Tác vụ</translation>
@@ -1262,6 +1296,7 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="4968522289500246572">Ứng dụng này được thiết kế cho thiết bị di động và có thể thay đổi kích thước không chuẩn xác. Ứng dụng có thể gặp sự cố hoặc khởi động lại.</translation>
<translation id="4969341057194253438">Xóa bản ghi</translation>
<translation id="4973922308112707173">Äục 2 lá»— trên cùng</translation>
+<translation id="4976702386844183910">Lần truy cập gần đây nhất: <ph name="DATE" /></translation>
<translation id="4984088539114770594">Sử dụng micrô?</translation>
<translation id="4984339528288761049">Prc5 (Phong bì)</translation>
<translation id="4989163558385430922">Xem tất cả</translation>
@@ -1323,6 +1358,7 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="5138227688689900538">Ẩn bớt</translation>
<translation id="5145883236150621069">Mã lỗi có trong phản hồi chính sách</translation>
<translation id="5146995429444047494">Äã chặn các thông báo đối vá»›i <ph name="ORIGIN" /></translation>
+<translation id="514704532284964975"><ph name="URL" /> muốn xem và thay đổi thông tin trên thiết bị NFC khi bạn nhấn vào điện thoại</translation>
<translation id="5148809049217731050">Hướng lên</translation>
<translation id="515292512908731282">C4 (Phong bì)</translation>
<translation id="5158275234811857234">Trang bìa</translation>
@@ -1347,6 +1383,7 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="5215116848420601511">Äịa chỉ và phÆ°Æ¡ng thức thanh toán lÆ°u trong Google Pay</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">Khay 13</translation>
+<translation id="5216942107514965959">Lần truy cập gần đây nhất: hôm nay</translation>
<translation id="5222812217790122047">Cần có email</translation>
<translation id="5230733896359313003">Äịa chỉ giao hàng</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1367,7 +1404,6 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">Thuộc tính tài liệu</translation>
<translation id="528468243742722775">Kết thúc</translation>
-<translation id="5284909709419567258">Äịa chỉ mạng</translation>
<translation id="5285570108065881030">Hiển thị tất cả mật khẩu đã lưu</translation>
<translation id="5287240709317226393">Hiển thị cookie</translation>
<translation id="5287456746628258573">Trang web này dùng cấu hình bảo mật lá»—i thá»i nên có thể làm lá»™ thông tin của bạn (chẳng hạn nhÆ° mật khẩu hoặc số thẻ tín dụng) trong quá trình gá»­i các thông tin này đến trang web.</translation>
@@ -1440,7 +1476,7 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="5523118979700054094">Tên chính sách</translation>
<translation id="55293785478302737">May viá»n</translation>
<translation id="553484882784876924">Prc6 (Phong bì)</translation>
-<translation id="5535133333442455806">Nút Xóa dữ liệu duyệt web, nhấn phím Enter để xóa lịch sá»­ duyệt web, cookie, bá»™ nhá»› đệm và nhiá»u ná»™i dung khác trong phần cài đặt của Chrome</translation>
+<translation id="5535133333442455806">Nút Xóa dữ liệu duyệt web, nhấn phím Enter để xóa nhật ký duyệt web, cookie, bá»™ nhá»› đệm và nhiá»u ná»™i dung khác trong phần cài đặt của Chrome</translation>
<translation id="5536214594743852365">Hiển thị phần "<ph name="SECTION" />"</translation>
<translation id="5539243836947087108">Bè nổi</translation>
<translation id="5540224163453853">Không thể tìm thấy bài viết đã yêu cầu.</translation>
@@ -1451,6 +1487,7 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="5556459405103347317">Tải lại</translation>
<translation id="5560088892362098740">Ngày hết hạn</translation>
<translation id="55635442646131152">ÄÆ°á»ng viá»n tài liệu</translation>
+<translation id="5565613213060953222">Mở thẻ ẩn danh</translation>
<translation id="5565735124758917034">Äang hoaÌ£t động</translation>
<translation id="5570825185877910964">Bảo vệ tài khoản</translation>
<translation id="5571083550517324815">Không thể nhận hàng từ địa chỉ này. Chá»n má»™t địa chỉ khác.</translation>
@@ -1533,6 +1570,7 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="5869522115854928033">Mật khẩu đã lưu</translation>
<translation id="5873013647450402046">Ngân hàng của bạn muốn xác nhận danh tính của bạn.</translation>
<translation id="5887400589839399685">Äã lÆ°u thẻ</translation>
+<translation id="5887687176710214216">Lần truy cập gần đây nhất: hôm qua</translation>
<translation id="5895138241574237353">Khởi động lại</translation>
<translation id="5895187275912066135">Cấp vào</translation>
<translation id="5901630391730855834">Vàng</translation>
@@ -1546,6 +1584,7 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="5921639886840618607">Bạn có muốn lưu thẻ vào Tài khoản Google không?</translation>
<translation id="5922853866070715753">Sắp hoàn tất</translation>
<translation id="5932224571077948991">Trang web hiển thị quảng cáo xâm nhập hoặc quảng cáo gây hiểu nhầm</translation>
+<translation id="5938153366081463283">Thêm thẻ ảo</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347">Äang mở <ph name="SITE_NAME" />…</translation>
<translation id="5951495562196540101">Không thể đăng ký bằng tài khoản ngÆ°á»i dùng thông thÆ°á»ng (có sẵn giấy phép theo gói).</translation>
@@ -1605,11 +1644,12 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="6105460996796456817">Tạo trang web</translation>
<translation id="6106989379647458772">Trang web tại <ph name="PAGE" /> có thể tạm thá»i không hoạt Ä‘á»™ng hoặc có thể đã được chuyển vÄ©nh viá»…n sang địa chỉ web má»›i.</translation>
<translation id="6107012941649240045">Cấp cho</translation>
-<translation id="610911394827799129">Tài khoản Google của bạn có thể có các dạng lịch sử duyệt web khác tại <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" /></translation>
+<translation id="610911394827799129">Tài khoản Google của bạn có thể có các dạng nhật ký duyệt web khác tại <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" /></translation>
<translation id="6116338172782435947">Xem văn bản và hình ảnh đã sao chép sang bảng nhớ tạm</translation>
<translation id="6120179357481664955">Ghi nhớ mã nhận dạng sản phẩm duy nhất (UPI) của bạn?</translation>
<translation id="6124432979022149706">Trình kết nối của Chrome Enterprise</translation>
<translation id="6127379762771434464">Äã xoÌa mục</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Tìm hiểu thêm về Chế độ ẩn danh trên Chrome<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">Kiểm tra má»i dây cáp rồi khởi Ä‘á»™ng lại bá»™ định tuyến, modem hoặc các thiết bị
mạng khác mà bạn có thể đang sử dụng.</translation>
<translation id="614940544461990577">Hãy thử:</translation>
@@ -1622,7 +1662,6 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="6169916984152623906">GiỠđây, bạn có thể duyệt web riêng tÆ° và ngÆ°á»i khác sá»­ dụng thiết bị này sẽ không thấy hoạt Ä‘á»™ng của bạn. Tuy nhiên, tài nguyên đã tải xuống và dấu trang sẽ được lÆ°u.</translation>
<translation id="6177128806592000436">Kết nối của bạn tới trang web này không an toàn</translation>
<translation id="6180316780098470077">Khoảng thá»i gian thá»­ lại</translation>
-<translation id="619448280891863779">Trang web có thể yêu cầu mở và đặt các cửa sổ trên màn hình của bạn</translation>
<translation id="6196640612572343990">Chặn cookie của bên thứ ba</translation>
<translation id="6203231073485539293">Kiểm tra kết nối Internet của bạn</translation>
<translation id="6218753634732582820">Bạn muốn xóa địa chỉ khá»i Chromium?</translation>
@@ -1645,7 +1684,7 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="6272383483618007430">Google Update</translation>
<translation id="6276112860590028508">Các trang từ danh sách Ä‘á»c của bạn sẽ xuất hiện tại đây</translation>
<translation id="627746635834430766">Äể thanh toán nhanh hÆ¡n vào lần tiếp theo, hãy lÆ°u địa chỉ thanh toán và thẻ vào Tài khoản Google của bạn.</translation>
-<translation id="6279098320682980337">Bạn chÆ°a Ä‘iá»n số thẻ ảo? Nhấp vào mục thông tin chi tiết của thẻ để sao chép</translation>
+<translation id="6279183038361895380">Nhấn |<ph name="ACCELERATOR" />| để hiển thị con trỠcủa bạn</translation>
<translation id="6280223929691119688">Không thể phân phối đến địa chỉ này. Chá»n má»™t địa chỉ khác.</translation>
<translation id="6282194474023008486">Mã bưu chính</translation>
<translation id="6285507000506177184">Nút quản lý tệp đã tải xuống trong Chrome, nhấn phím Enter để quản lý các tệp bạn đã tải xuống trong Chrome</translation>
@@ -1653,6 +1692,7 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="6290238015253830360">Bài viết đỠxuất cho bạn sẽ xuất hiện ở đây</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{Thiết bị của bạn sẽ khởi Ä‘á»™ng lại ngay bây giá»}=1{Thiết bị của bạn sẽ khởi Ä‘á»™ng lại sau 1 giây}other{Thiết bị của bạn sẽ khởi Ä‘á»™ng lại sau # giây}}</translation>
<translation id="6302269476990306341">Trợ lý Google trong Chrome đang dừng</translation>
<translation id="6305205051461490394">Không thể truy cập <ph name="URL" />.</translation>
<translation id="6312113039770857350">Trang web hiện không khả dụng</translation>
@@ -1726,6 +1766,7 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="6529602333819889595">&amp;Làm lại xóa</translation>
<translation id="6545864417968258051">Quét tìm Bluetooth</translation>
<translation id="6547208576736763147">Äục 2 lá»— bên trái</translation>
+<translation id="6554732001434021288">Lần truy cập gần đây nhất: <ph name="NUM_DAYS" /> ngày trước</translation>
<translation id="6556866813142980365">Làm lại</translation>
<translation id="6569060085658103619">Bạn đang xem trang tiện ích</translation>
<translation id="6573200754375280815">Äục 2 lá»— bên phải</translation>
@@ -1786,7 +1827,6 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="6757797048963528358">Thiết bị của bạn đã chuyển sang chế độ ngủ.</translation>
<translation id="6767985426384634228">Cập nhật địa chỉ?</translation>
<translation id="6768213884286397650">Hagaki (Bưu thiếp)</translation>
-<translation id="6774185088257932239"><ph name="BEGIN_LINK" />Tìm hiểu thêm<ph name="END_LINK" /> vỠChế độ ẩn danh</translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">Tím vi-ô-lét</translation>
<translation id="6786747875388722282">Tiện ích</translation>
@@ -1870,7 +1910,6 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="706295145388601875">Thêm và quản lý các địa chỉ trong phần Cài đặt của Chrome</translation>
<translation id="7064851114919012435">Thông tin liên hệ</translation>
<translation id="7068733155164172741">Nhập mã có <ph name="OTP_LENGTH" /> chữ số</translation>
-<translation id="7070090581017165256">Thông tin vỠtrang web này</translation>
<translation id="70705239631109039">Kết nối của bạn không đủ an toàn</translation>
<translation id="7075452647191940183">Yêu cầu quá lớn</translation>
<translation id="7079718277001814089">Trang web này có chứa phần má»m Ä‘á»™c hại</translation>
@@ -1887,6 +1926,12 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="7111012039238467737">(Hợp lệ)</translation>
<translation id="7118618213916969306">Tìm kiếm URL trong bảng nhớ tạm, <ph name="SHORT_URL" /></translation>
<translation id="7119414471315195487">Äóng các thẻ hoặc chÆ°Æ¡ng trình khác</translation>
+<translation id="7129355289156517987">Khi bạn đóng tất cả caÌc thẻ ẩn danh trên Chromium, chuÌng tôi sẽ xoaÌ khá»i thiết bị những hoạt Ä‘á»™ng sau đây của baÌ£n trên những thẻ Ä‘oÌ:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Hoạt động duyệt web<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Nhật ký tìm kiếm<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Thông tin đã nhập vào biểu mẫu<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">Không thể giao hàng đến địa chỉ này. Chá»n má»™t địa chỉ khác.</translation>
<translation id="7132939140423847331">Quản trị viên của bạn đã cấm sao chép dữ liệu này.</translation>
<translation id="7135130955892390533">Hiển thị trạng thái</translation>
@@ -1909,6 +1954,7 @@ Nếu bạn từ chối, chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của bạn
<translation id="7192203810768312527">Giải phóng <ph name="SIZE" />. Một số trang web có thể tải chậm hơn trong lần tiếp theo bạn truy cập.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">Quản trị viên của bạn có thể xem:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, nhấn Tab rồi nhấn Enter để mở một thẻ ẩn danh mới nhằm duyệt web ở chế độ riêng tư</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> không tuân thủ các tiêu chuẩn bảo mật.</translation>
<translation id="7210993021468939304">Hoạt Ä‘á»™ng của Linux trong vùng chứa, đồng thá»i có thể cài đặt và chạy các ứng dụng Linux trong vùng chứa</translation>
@@ -1940,6 +1986,7 @@ Thông tin chi tiết bổ sung:
<translation id="7304562222803846232">Quản lý chế Ä‘á»™ cài đặt quyá»n riêng tÆ° của Tài khoản Google</translation>
<translation id="7305756307268530424">Bắt đầu tốc độ chậm hơn</translation>
<translation id="7308436126008021607">đồng bá»™ hóa dÆ°á»›i ná»n</translation>
+<translation id="7310392214323165548">Thiết bị sẽ sớm khởi động lại</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">Trợ giúp kết nối</translation>
<translation id="7323804146520582233">Ẩn phần "<ph name="SECTION" />"</translation>
@@ -1947,6 +1994,7 @@ Thông tin chi tiết bổ sung:
<translation id="7334320624316649418">&amp;Làm lại sắp xếp lại</translation>
<translation id="7335157162773372339">Trang web có thể yêu cầu dùng máy ảnh của bạn</translation>
<translation id="7337248890521463931">Hiện thêm dòng</translation>
+<translation id="7337418456231055214">Bạn chÆ°a Ä‘iá»n số thẻ ảo? Hãy nhấp vào mục thông tin thẻ chi tiết để sao chép. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">Không được há»— trợ trên ná»n tảng của bạn.</translation>
<translation id="733923710415886693">Chứng chỉ của máy chủ đã không được tiết lộ qua Tính minh bạch của chứng chỉ.</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1969,6 +2017,7 @@ Thông tin chi tiết bổ sung:
<translation id="7378627244592794276">Không</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">Không áp dụng</translation>
+<translation id="7388594495505979117">{0,plural, =1{Thiết bị của bạn sẽ khởi động lại sau 1 phút}other{Thiết bị của bạn sẽ khởi động lại sau # phút}}</translation>
<translation id="7390545607259442187">Xác nhận thẻ</translation>
<translation id="7392089738299859607">Cập nhật địa chỉ</translation>
<translation id="7399802613464275309">Kiểm tra an toàn</translation>
@@ -2005,6 +2054,12 @@ Thông tin chi tiết bổ sung:
<translation id="7485870689360869515">Không tìm thấy dữ liệu.</translation>
<translation id="7495528107193238112">Nội dung này bị chặn. Hãy liên hệ với chủ sở hữu trang web để khắc phục sự cố.</translation>
<translation id="7497998058912824456">Nút tạo tài liệu, nhấn phím Enter để tạo nhanh một tài liệu mới trên Google Tài liệu</translation>
+<translation id="7506488012654002225">Chromium <ph name="BEGIN_EMPHASIS" />sẽ không lưu<ph name="END_EMPHASIS" /> những thông tin sau:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Nhật kyÌ duyệt web của bạn
+ <ph name="LIST_ITEM" />Cookie và dữ liệu trang web
+ <ph name="LIST_ITEM" />Thông tin đã nhập vào biểu mẫu
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">ID thiết bị thuộc chính sách trả lại trống hoặc không khớp với ID của thiết bị hiện tại</translation>
<translation id="7508870219247277067">Xanh quả bơ</translation>
<translation id="7511955381719512146">Wi-Fi mà bạn đang sử dụng có thể yêu cầu bạn phải truy cập <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
@@ -2118,7 +2173,6 @@ Thông tin chi tiết bổ sung:
<translation id="7813600968533626083">Xóa Ä‘á» xuất biểu mẫu khá»i Chrome?</translation>
<translation id="781440967107097262">Chia sẻ bảng nhớ tạm?</translation>
<translation id="7815407501681723534">Äã tìm thấy <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> cho '<ph name="SEARCH_STRING" />'</translation>
-<translation id="782125616001965242">Hiện thông tin vỠtrang web này</translation>
<translation id="782886543891417279">Wi-Fi mà bạn đang sử dụng (<ph name="WIFI_NAME" />) có thể yêu cầu bạn phải truy cập trang đăng nhập của mạng đó.</translation>
<translation id="7836231406687464395">Postfix (Phong bì)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{Không có}=1{1 ứng dụng (<ph name="EXAMPLE_APP_1" />)}=2{2 ứng dụng (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}other{# ứng dụng (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}}</translation>
@@ -2135,7 +2189,6 @@ Thông tin chi tiết bổ sung:
<translation id="7888575728750733395">In theo mục đích tái tạo</translation>
<translation id="7894280532028510793">Nếu đúng chính tả, hãy <ph name="BEGIN_LINK" />thử chạy Chẩn đoán mạng<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (Phong bì)</translation>
-<translation id="7931318309563332511">Không xác định</translation>
<translation id="793209273132572360">Cập nhật địa chỉ?</translation>
<translation id="7932579305932748336">Phủ</translation>
<translation id="79338296614623784">Nhập số điện thoại hợp lệ</translation>
@@ -2160,13 +2213,14 @@ Thông tin chi tiết bổ sung:
<translation id="7976214039405368314">Quá nhiá»u yêu cầu</translation>
<translation id="7977538094055660992">Thiết bị đầu ra</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">Äã liên kết vá»›i</translation>
<translation id="798134797138789862">Trang web có thể yêu cầu dùng dữ liệu và thiết bị thực tế ảo</translation>
<translation id="7984945080620862648">Bạn không thể truy cập <ph name="SITE" /> ngay bây giá» do trang web gá»­i thông tin đăng nhập đã thu thập mà Chrome không thể xá»­ lý. Lỗi maÌ£ng vaÌ€ caÌc cuộc tâÌn công maÌ£ng thÆ°Æ¡Ì€ng chỉ laÌ€ taÌ£m thÆ¡Ì€i, do Ä‘oÌ trang naÌ€y coÌ thể sẽ hoaÌ£t động laÌ£i sau.</translation>
-<translation id="79859296434321399">Äể xem ná»™i dung thá»±c tế tăng cÆ°á»ng, hãy cài đặt bá»™ công cụ ARCore</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">Äóng gáy</translation>
<translation id="7992044431894087211">Äã tiếp tục chia sẻ màn hình vá»›i <ph name="APPLICATION_TITLE" /></translation>
<translation id="7995512525968007366">Không chỉ định</translation>
+<translation id="7998269595945679889">Mở nút thẻ ẩn danh rồi nhấn Enter để mở một thẻ ẩn danh mới nhằm duyệt web ở chế độ riêng tư</translation>
<translation id="800218591365569300">Thử đóng các thẻ hoặc chương trình khác để giải phóng bộ nhớ.</translation>
<translation id="8004582292198964060">Trình duyệt</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{Thẻ này và địa chỉ thanh toán của thẻ sẽ được lưu. Bạn có thể sử dụng thẻ khi đăng nhập vào <ph name="USER_EMAIL" />.}other{Các thẻ này và địa chỉ thanh toán của thẻ sẽ được lưu. Bạn có thể sử dụng các thẻ này khi đăng nhập vào <ph name="USER_EMAIL" />.}}</translation>
@@ -2226,6 +2280,7 @@ Thông tin chi tiết bổ sung:
<translation id="8202370299023114387">Xung Ä‘á»™t</translation>
<translation id="8206978196348664717">Prc4 (Phong bì)</translation>
<translation id="8211406090763984747">Kết nối an toàn</translation>
+<translation id="8217240300496046857">Các trang web không thể dùng cookie theo dõi bạn trên web. Do đó, tính năng trên một số trang web có thể hoạt động không đúng cách.</translation>
<translation id="8218327578424803826">Vị trí được gán:</translation>
<translation id="8220146938470311105">C7/C6 (Phong bì)</translation>
<translation id="8225771182978767009">NgÆ°á»i thiết lập máy tính này đã chá»n chặn trang web này.</translation>
@@ -2242,7 +2297,7 @@ Thông tin chi tiết bổ sung:
<translation id="8253091569723639551">Yêu cầu địa chỉ thanh toán</translation>
<translation id="8257387598443225809">Ứng dụng này được thiết kế cho thiết bị di động</translation>
<translation id="825929999321470778">Hiển thị tất cả các mật khẩu đã lưu</translation>
-<translation id="8261506727792406068">Xóa</translation>
+<translation id="8261506727792406068">Xoá</translation>
<translation id="8262952874573525464">May viá»n ở dÆ°á»›i cùng</translation>
<translation id="8265992338205884890">Dữ liệu hiển thị</translation>
<translation id="8267698848189296333">Äăng nhập vá»›i tên <ph name="USERNAME" /></translation>
@@ -2266,14 +2321,9 @@ Thông tin chi tiết bổ sung:
<translation id="830498451218851433">Gấp đôi</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">Số ứng dụng đã cài đặt và tần suất sử dụng</translation>
+<translation id="8317207217658302555">Cập nhật ARCore?</translation>
<translation id="831997045666694187">Buổi tối</translation>
<translation id="8321476692217554900">thông báo</translation>
-<translation id="8328484624016508118">Sau khi bạn đóng tất cả thẻ Ẩn danh, Chrome sẽ xóa:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Hoạt động duyệt web của bạn trên thiết bị này<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Nhật ký tìm kiếm của bạn trên thiết bị này<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Thông tin bạn đã nhập vào các biểu mẫu<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489">Quyá»n truy cập <ph name="HOST_NAME" /> bị từ chối</translation>
<translation id="833262891116910667">Äánh dấu</translation>
<translation id="8339163506404995330">Các trang viết bằng <ph name="LANGUAGE" /> sẽ không được dịch</translation>
@@ -2325,8 +2375,9 @@ Thông tin chi tiết bổ sung:
<translation id="8507227106804027148">Dòng lệnh</translation>
<translation id="8508648098325802031">Biểu tượng Tìm kiếm</translation>
<translation id="8511402995811232419">Quản lyÌ cookie</translation>
+<translation id="8519753333133776369">Quản trị viên của bạn đã cho phép thiết bị HID</translation>
<translation id="8522552481199248698">Chrome có thể giúp bạn bảo vệ Tài khoản Google của mình và đổi mật khẩu.</translation>
-<translation id="8530813470445476232">Xóa lịch sử duyệt web, cookie, bộ nhớ đệm và các dữ liệu khác trong phần cài đặt của Chrome</translation>
+<translation id="8530813470445476232">Xóa nhật ký duyệt web, cookie, bộ nhớ đệm và các dữ liệu khác trong phần cài đặt của Chrome</translation>
<translation id="8533619373899488139">Hãy truy cập vào &lt;strong&gt;chrome://policy&lt;/strong&gt; để xem danh sách các URL bị chặn và những chính sách khác do quản trị viên hệ thống thực thi.</translation>
<translation id="8539500321752640291">Cấp 2 quyá»n truy cập?</translation>
<translation id="8541158209346794904">Thiết bị Bluetooth</translation>
@@ -2336,7 +2387,6 @@ Thông tin chi tiết bổ sung:
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{Äặt lại quyá»n}other{Äặt lại quyá»n}}</translation>
<translation id="8555010941760982128">Sử dụng mã này khi thanh toán</translation>
<translation id="8557066899867184262">CVC nằm ở mặt sau thẻ của bạn.</translation>
-<translation id="8558485628462305855">Äể xem ná»™i dung thá»±c tế tăng cÆ°á»ng, hãy cập nhật bá»™ công cụ ARCore</translation>
<translation id="8559762987265718583">Không thể thiết lập kết nối riêng tư với <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> vì ngày và giỠ(<ph name="DATE_AND_TIME" />) trên thiết bị của bạn không đúng.</translation>
<translation id="8564182942834072828">Tài liệu riêng biệt/Bản sao chưa đối chiếu</translation>
<translation id="8564985650692024650">Chromium khuyên bạn nên đặt lại mật khẩu <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> của mình nếu đã sử dụng lại mật khẩu này trên các trang web khác.</translation>
@@ -2356,6 +2406,7 @@ Thông tin chi tiết bổ sung:
<translation id="865032292777205197">cảm biến chuyển động</translation>
<translation id="8663226718884576429">Tóm tắt đơn hàng, <ph name="TOTAL_LABEL" />, chi tiết khác</translation>
<translation id="8666678546361132282">Tiếng Anh</translation>
+<translation id="8669306706049782872">Sử dụng thông tin vỠmàn hình của bạn để mở và đặt cửa sổ vào vị trí nhất định</translation>
<translation id="867224526087042813">Chữ ký</translation>
<translation id="8676424191133491403">Không trì hoãn</translation>
<translation id="8680536109547170164"><ph name="QUERY" />, câu trả lá»i, <ph name="ANSWER" /></translation>
@@ -2382,6 +2433,7 @@ Thông tin chi tiết bổ sung:
<translation id="8731544501227493793">Nút Quản lý mật khẩu, nhấn phím Enter để xem và quản lý các mật khẩu của bạn trong phần cài đặt của Chrome</translation>
<translation id="8734529307927223492"><ph name="DEVICE_TYPE" /> của bạn do <ph name="MANAGER" /> quản lý</translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, nhấn phím Tab rồi nhấn Enter để mở cửa sổ Ẩn danh mới nhằm duyệt web ở chế độ riêng tư</translation>
+<translation id="8737685506611670901">Mở Ä‘Æ°á»ng liên kết <ph name="PROTOCOL" /> thay vì <ph name="REPLACED_HANDLER_TITLE" /></translation>
<translation id="8738058698779197622">Äể thiết lập kết nối an toàn, bạn cần đặt thá»i gian đúng cho đồng hồ. Nguyên nhân là do chứng chỉ mà các trang web dùng để tá»± nhận dạng chỉ có hiệu lá»±c trong khoảng thá»i gian cụ thể. Vì đồng hồ trên thiết bị của bạn không đúng nên Chromium không thể xác minh các chứng chỉ này.</translation>
<translation id="8740359287975076522">Không thể tìm thấy &lt;abbr id="dnsDefinition"&gt;địa chỉ DNS&lt;/abbr&gt; của <ph name="HOST_NAME" />. Äang chẩn Ä‘oán sá»± cố.</translation>
<translation id="8742371904523228557"><ph name="ONE_TIME_CODE" /> là mã của bạn cho <ph name="ORIGIN" /></translation>
@@ -2409,6 +2461,7 @@ Thông tin chi tiết bổ sung:
<translation id="883848425547221593">Dấu trang Khác</translation>
<translation id="884264119367021077">Ãịa chỉ giao hàng</translation>
<translation id="884923133447025588">Không tìm thấy cơ chế thu hồi.</translation>
+<translation id="8849262850971482943">Sử dụng thẻ ảo để tăng thêm tính bảo mật</translation>
<translation id="885730110891505394">Chia sẻ với Google</translation>
<translation id="8858065207712248076">Chrome khuyên bạn nên đặt lại mật khẩu <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> của mình nếu đã sử dụng lại mật khẩu này trên các trang web khác.</translation>
<translation id="885906927438988819">Nếu đúng chính tả, hãy <ph name="BEGIN_LINK" />thử chạy Chẩn đoán mạng của Windows<ph name="END_LINK" />.</translation>
@@ -2458,6 +2511,7 @@ Thông tin chi tiết bổ sung:
<translation id="9004367719664099443">Phiên thực tế ảo đang diễn ra</translation>
<translation id="9005998258318286617">Không tải được tài liệu PDF.</translation>
<translation id="9008201768610948239">Bá» qua</translation>
+<translation id="901834265349196618">email</translation>
<translation id="9020200922353704812">Yêu cầu địa chỉ thanh toán của thẻ</translation>
<translation id="9020542370529661692">Trang này đã được dịch sang <ph name="TARGET_LANGUAGE" /></translation>
<translation id="9020742383383852663">A8</translation>
@@ -2506,6 +2560,7 @@ Thông tin chi tiết bổ sung:
<translation id="9150045010208374699">Sử dụng máy ảnh của bạn</translation>
<translation id="9150685862434908345">Quản trị viên có thể thay đổi cách thiết lập trình duyệt của bạn từ xa. Hoạt động trên thiết bị này cũng có thể được quản lý bên ngoài Chrome. <ph name="BEGIN_LINK" />Tìm hiểu thêm<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">Äã cập nhật</translation>
+<translation id="9155211586651734179">Thiết bị âm thanh ngoại vi gắn kèm</translation>
<translation id="9157595877708044936">Äang thiết lập...</translation>
<translation id="9158625974267017556">C6 (Phong bì)</translation>
<translation id="9164029392738894042">Kiểm tra độ chính xác</translation>
diff --git a/chromium/components/strings/components_strings_zh-CN.xtb b/chromium/components/strings/components_strings_zh-CN.xtb
index a523ccca514..63aa60b6a5e 100644
--- a/chromium/components/strings/components_strings_zh-CN.xtb
+++ b/chromium/components/strings/components_strings_zh-CN.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">查看详情</translation>
<translation id="1030706264415084469"><ph name="URL" /> 想在您的设备上永久存储大é‡æ•°æ®</translation>
<translation id="1032854598605920125">顺时针旋转</translation>
+<translation id="1033329911862281889">无痕模å¼æ— æ³•è®©æ‚¨åœ¨ç½‘上处于éšèº«çŠ¶æ€ï¼š
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />网站åŠå…¶ä½¿ç”¨çš„æœåŠ¡å¯ä»¥çœ‹åˆ°ç”¨æˆ·è®¿é—®è®°å½•<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />雇主或学校å¯ä»¥è·Ÿè¸ªæµè§ˆæ´»åŠ¨<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />互è”网æœåŠ¡æ供商å¯èƒ½ä¼šç›‘控网络æµé‡<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">关闭</translation>
<translation id="1036982837258183574">按 |<ph name="ACCELERATOR" />| å³å¯é€€å‡ºå…¨å±æ¨¡å¼</translation>
<translation id="1038106730571050514">显示æœç´¢å»ºè®®</translation>
<translation id="1038842779957582377">未知å称</translation>
<translation id="1041998700806130099">工作表消æ¯</translation>
<translation id="1048785276086539861">当您修改注释时,此文档会æ¢å¤ä¸ºå•é¡µè§†å›¾</translation>
-<translation id="1049743911850919806">æ— ç—•</translation>
<translation id="1050038467049342496">关闭其他应用</translation>
<translation id="1055184225775184556">撤消添加(&amp;U)</translation>
<translation id="1056898198331236512">警告</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">策略缓存良好</translation>
<translation id="1130564665089811311">“翻译网页â€æŒ‰é’®ï¼ŒæŒ‰ Enter é”®å³å¯ä½¿ç”¨â€œGoogle 翻译â€æœåŠ¡æ¥ç¿»è¯‘此页é¢</translation>
<translation id="1131264053432022307">您å¤åˆ¶çš„图片</translation>
+<translation id="1142846828089312304">在无痕模å¼ä¸‹é˜»æ­¢ç¬¬ä¸‰æ–¹ Cookie</translation>
<translation id="1150979032973867961">æ­¤æœåŠ¡å™¨æ— æ³•è¯æ˜Žå®ƒæ˜¯<ph name="DOMAIN" />;您计算机的æ“作系统ä¸ä¿¡ä»»å…¶å®‰å…¨è¯ä¹¦ã€‚出现此问题的原因å¯èƒ½æ˜¯é…置有误或您的连接被拦截了。</translation>
<translation id="1151972924205500581">需è¦å¯†ç </translation>
<translation id="1156303062776767266">您正在查看一个本地文件或共享文件</translation>
@@ -64,7 +70,6 @@
<translation id="1178581264944972037">æš‚åœ</translation>
<translation id="1181037720776840403">移除</translation>
<translation id="1186201132766001848">检查密ç </translation>
-<translation id="1195210374336998651">转到应用设置</translation>
<translation id="1195558154361252544">除您å…许的网站外,已自动阻止所有其他网站显示通知</translation>
<translation id="1197088940767939838">橙色</translation>
<translation id="1201402288615127009">下一步</translation>
@@ -111,7 +116,7 @@
<translation id="1307966114820526988">已被弃用的功能</translation>
<translation id="1308113895091915999">有优惠å¯ç”¨</translation>
<translation id="1312803275555673949">有何è¯æ®èƒ½è¯æ˜Žè¿™é¡¹ä¿¡æ¯å±žå®žï¼Ÿ</translation>
-<translation id="131405271941274527"><ph name="URL" /> 想在您的手机与 NFC 设备触碰时å‘é€å’ŒæŽ¥æ”¶ä¿¡æ¯</translation>
+<translation id="1314311879718644478">查看增强现实内容</translation>
<translation id="1314509827145471431">装订(å³ä¾§ï¼‰</translation>
<translation id="1318023360584041678">å·²ä¿å­˜åœ¨æ ‡ç­¾é¡µç»„中</translation>
<translation id="1319245136674974084">对于此应用ä¸å†è¯¢é—®</translation>
@@ -161,6 +166,7 @@
<translation id="142858679511221695">云端用户</translation>
<translation id="1428729058023778569">您之所以会看到此警告,是因为该网站ä¸æ”¯æŒ HTTPS。<ph name="BEGIN_LEARN_MORE_LINK" />了解详情<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">打å°</translation>
+<translation id="1432187715652018471">此页é¢æƒ³å®‰è£…一款æœåŠ¡å¤„ç†ç¨‹åºã€‚</translation>
<translation id="1432581352905426595">管ç†æœç´¢å¼•æ“Ž</translation>
<translation id="1436185428532214179">å¯ä»¥è¯¢é—®èƒ½å¦ä¿®æ”¹æ‚¨è®¾å¤‡ä¸Šçš„文件和文件夹</translation>
<translation id="1442386063175183758">关门折(å³ä¾§ï¼‰</translation>
@@ -181,6 +187,12 @@
<translation id="1483493594462132177">å‘é€</translation>
<translation id="1484290072879560759">选择é€è´§åœ°å€</translation>
<translation id="1492194039220927094">政策推é€ï¼š</translation>
+<translation id="149293076951187737">当您关闭 Chrome 中的所有无痕å¼æ ‡ç­¾é¡µåŽï¼Œç³»ç»Ÿä¼šä»Žæ­¤è®¾å¤‡ä¸Šæ¸…除您在这些标签页中的活动记录:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />æµè§ˆæ´»åŠ¨<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />æœç´¢è®°å½•<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />在表å•ä¸­å¡«å†™çš„ä¿¡æ¯<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">返回到标签页</translation>
<translation id="1501859676467574491">显示您的 Google å¸å·ä¸­ä¿å­˜çš„支付å¡</translation>
<translation id="1507202001669085618">&lt;p&gt;如果您使用的 Wi-Fi 门户网站必须登录æ‰èƒ½è¿žæŽ¥ç½‘络,您就会看到这æ¡é”™è¯¯æ¶ˆæ¯ã€‚&lt;/p&gt;
@@ -208,6 +220,8 @@
<translation id="1559572115229829303">&lt;p&gt;您设备的日期和时间(<ph name="DATE_AND_TIME" />)ä¸æ­£ç¡®ï¼Œå› æ­¤æ— æ³•ä¸Ž <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> 建立ç§å¯†è¿žæŽ¥ã€‚&lt;/p&gt;
&lt;p&gt;请在&lt;strong&gt;设置&lt;/strong&gt;应用的&lt;strong&gt;通用&lt;/strong&gt;部分调整日期和时间。&lt;/p&gt;</translation>
+<translation id="1559839503761818503">您的管ç†å‘˜å°†äºŽ <ph name="DATE" /><ph name="TIME" /> é‡å¯æ‚¨çš„设备</translation>
+<translation id="156703335097561114">网络信æ¯ï¼Œä¾‹å¦‚地å€ã€æŽ¥å£é…置和连接质é‡</translation>
<translation id="1567040042588613346">此政策正在正常è¿ä½œï¼Œä½†ä¸Žåˆ«å¤„设置的值相åŒä¸”已覆盖该值。</translation>
<translation id="1569487616857761740">输入失效日期</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@
<translation id="1583429793053364125">显示此网页时出了点问题。</translation>
<translation id="1586541204584340881">您已安装的扩展程åº</translation>
<translation id="1588438908519853928">正常</translation>
+<translation id="1589050138437146318">安装 ARCore?</translation>
<translation id="1592005682883173041">本地数æ®è®¿é—®æƒé™</translation>
<translation id="1594030484168838125">选择</translation>
<translation id="160851722280695521">在 Chrome 中玩《Dino Run》游æˆ</translation>
@@ -279,6 +294,7 @@
<translation id="1763864636252898013">æ­¤æœåŠ¡å™¨æ— æ³•è¯æ˜Žå®ƒæ˜¯<ph name="DOMAIN" />;您设备的æ“作系统ä¸ä¿¡ä»»å…¶å®‰å…¨è¯ä¹¦ã€‚出现此问题的原因å¯èƒ½æ˜¯é…置有误或您的连接被拦截了。</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />å°è¯•è¿è¡Œ Windows 网络诊断<ph name="END_LINK" />。</translation>
<translation id="1772163372082567643">您è¦è®¿é—®çš„æœåŠ¡å™¨ <ph name="ORIGIN" /> 已设定标头,其中è¦æ±‚收到的所有请求都应用一项æ¥æºæ”¿ç­–。但该标头的格å¼ä¸æ­£ç¡®ï¼Œå¯¼è‡´æµè§ˆå™¨æ— æ³•å®žçŽ°æ‚¨å¯¹ <ph name="SITE" /> 的访问请求。网站è¿è¥å•†å¯ä»¥ä½¿ç”¨æ¥æºæ”¿ç­–为网站é…置安全属性åŠå…¶ä»–属性。</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />详细了解 Chromium 中的无痕模å¼<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">您打开的标签页会显示在此处</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -355,7 +371,7 @@
<translation id="204357726431741734">登录åŽå³å¯ä½¿ç”¨æ‚¨ Google å¸å·ä¸­ä¿å­˜çš„密ç </translation>
<translation id="2053111141626950936">系统ä¸ä¼šç¿»è¯‘<ph name="LANGUAGE" />网页。</translation>
<translation id="2053373601901562871">{NUM_DAYS,plural, =0{如果此控件已开å¯ä¸”处于有效状æ€ï¼ŒChrome 会确定您近期的æµè§ˆæ´»åŠ¨ä¸Žå“ªä¸ªå¤§åž‹ç”¨æˆ·ç¾¤ç»„或“åŒç±»ç¾¤ç»„â€æœ€æŽ¥è¿‘。广告主å¯ä¸ºç¾¤ç»„选择广告,您的æµè§ˆæ´»åŠ¨è®°å½•ä¼šç§å¯†åœ°ä¿ç•™åœ¨æ‚¨çš„设备上。系统会按æ¯å¤© 1 次的频率更新您所属的群组。}=1{如果此控件已开å¯ä¸”处于有效状æ€ï¼ŒChrome 会确定您近期的æµè§ˆæ´»åŠ¨ä¸Žå“ªä¸ªå¤§åž‹ç”¨æˆ·ç¾¤ç»„或“åŒç±»ç¾¤ç»„â€æœ€æŽ¥è¿‘。广告主å¯ä¸ºç¾¤ç»„选择广告,您的æµè§ˆæ´»åŠ¨è®°å½•ä¼šç§å¯†åœ°ä¿ç•™åœ¨æ‚¨çš„设备上。系统会按æ¯å¤© 1 次的频率更新您所属的群组。}other{如果此控件已开å¯ä¸”处于有效状æ€ï¼ŒChrome 会确定您近期的æµè§ˆæ´»åŠ¨ä¸Žå“ªä¸ªå¤§åž‹ç”¨æˆ·ç¾¤ç»„或“åŒç±»ç¾¤ç»„â€æœ€æŽ¥è¿‘。广告主å¯ä¸ºç¾¤ç»„选择广告,您的æµè§ˆæ´»åŠ¨è®°å½•ä¼šç§å¯†åœ°ä¿ç•™åœ¨æ‚¨çš„è®¾å¤‡ä¸Šã€‚ç³»ç»Ÿä¼šæŒ‰æ¯ {NUM_DAYS} 天 1 次的频率更新您所属的群组。}}</translation>
-<translation id="2053553514270667976">邮编</translation>
+<translation id="2053553514270667976">邮政编ç </translation>
<translation id="2064691555167957331">{COUNT,plural, =1{1 æ¡å»ºè®®}other{# æ¡å»ºè®®}}</translation>
<translation id="2071156619270205202">这张å¡çš„å¡å·æ— æ³•ç”¨ä½œè™šæ‹Ÿå¡å·ã€‚</translation>
<translation id="2071692954027939183">由于您通常ä¸å…许显示通知,系统已自动å±è”½é€šçŸ¥</translation>
@@ -406,6 +422,7 @@
<translation id="22081806969704220">纸匣 3</translation>
<translation id="2212735316055980242">找ä¸åˆ°ç­–ç•¥</translation>
<translation id="2213606439339815911">正在获å–æ¡ç›®â€¦</translation>
+<translation id="2213612003795704869">页é¢å·²æ‰“å°</translation>
<translation id="2215727959747642672">文件修改</translation>
<translation id="2218879909401188352"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> 上的现有攻击者å¯èƒ½ä¼šå®‰è£…å±é™©åº”用æ¥æŸå®³æ‚¨çš„设备ã€ç»™æ‚¨çš„手机å¸å•å¢žæ·»éšå«è´¹ç”¨æˆ–窃å–您的个人信æ¯ã€‚<ph name="BEGIN_LEARN_MORE_LINK" />了解详情<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">未连接到互è”网</translation>
@@ -415,6 +432,7 @@
<translation id="2248949050832152960">使用 WebAuthn</translation>
<translation id="2250931979407627383">边缘装订(左侧)</translation>
<translation id="225207911366869382">适用于该政策的此值已弃用。</translation>
+<translation id="2256115617011615191">ç«‹å³é‡æ–°å¯åŠ¨</translation>
<translation id="2258928405015593961">失效日期必须是未æ¥çš„日期。请é‡æ–°è¾“入,å†è¯•ä¸€æ¬¡</translation>
<translation id="225943865679747347">错误代ç ï¼š<ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">HTTP 错误</translation>
@@ -442,6 +460,7 @@
<translation id="2337852623177822836">设置由管ç†å‘˜æŽ§åˆ¶</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> 希望与以下所选设备é…对:</translation>
<translation id="2346319942568447007">您å¤åˆ¶çš„图片</translation>
+<translation id="2350796302381711542">å…许<ph name="HANDLER_HOSTNAME" />打开所有<ph name="PROTOCOL" />链接(而éž<ph name="REPLACED_HANDLER_TITLE" />)?</translation>
<translation id="2354001756790975382">其他书签</translation>
<translation id="2354430244986887761">Google 安全æµè§ˆåŠŸèƒ½æœ€è¿‘在 <ph name="SITE" /> 上<ph name="BEGIN_LINK" />å‘现了有害应用<ph name="END_LINK" />。</translation>
<translation id="2355395290879513365">攻击者å¯èƒ½èƒ½å¤Ÿçœ‹åˆ°æ‚¨æ­£åœ¨æ­¤ç½‘站上æµè§ˆçš„图片,并通过编辑这些图片让您å—骗。</translation>
@@ -467,6 +486,7 @@
<translation id="2413528052993050574">æ­¤æœåŠ¡å™¨æ— æ³•è¯æ˜Žå®ƒæ˜¯<ph name="DOMAIN" />;其安全è¯ä¹¦å¯èƒ½å·²è¢«æ’¤æ¶ˆã€‚出现此问题的原因å¯èƒ½æ˜¯é…置有误或您的连接被拦截了。</translation>
<translation id="2414886740292270097">深色调</translation>
<translation id="2430968933669123598">â€œç®¡ç† Google å¸å·â€ï¼ŒæŒ‰ Enter é”®å³å¯åœ¨æ‚¨çš„ Google å¸å·ä¸­ç®¡ç†è‡ªå·±çš„ä¿¡æ¯ã€éšç§å’Œå®‰å…¨</translation>
+<translation id="2436186046335138073">å…许<ph name="HANDLER_HOSTNAME" />打开所有<ph name="PROTOCOL" />链接?</translation>
<translation id="2438874542388153331">四孔(å³ä¾§ï¼‰</translation>
<translation id="2450021089947420533">历程</translation>
<translation id="2463739503403862330">å¡«å……</translation>
@@ -474,6 +494,7 @@
<translation id="2465655957518002998">选择速递方å¼</translation>
<translation id="2465688316154986572">订书钉</translation>
<translation id="2465914000209955735">管ç†æ‚¨å·²åœ¨ Chrome 中下载的文件</translation>
+<translation id="2466004615675155314">显示æ¥è‡ªç½‘络的信æ¯</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />è¿è¡Œç½‘络诊断<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">从 1 到 N 的顺åº</translation>
<translation id="2470767536994572628">当您修改注释时,此文档会æ¢å¤ä¸ºå•é¡µè§†å›¾å’ŒåŽŸå§‹æ–¹å‘</translation>
@@ -494,6 +515,7 @@
<translation id="2523886232349826891">仅会ä¿å­˜åœ¨æ­¤è®¾å¤‡ä¸Š</translation>
<translation id="2524461107774643265">添加更多信æ¯</translation>
<translation id="2529899080962247600">此字段最多åªèƒ½åŒ…å« <ph name="MAX_ITEMS_LIMIT" /> 个æ¡ç›®ï¼Œåœ¨è¾¾åˆ°è¿™ä¸€ä¸Šé™åŽæ·»åŠ çš„所有æ¡ç›®éƒ½å°†è¢«å¿½ç•¥ã€‚</translation>
+<translation id="2535585790302968248">打开新的无痕å¼æ ‡ç­¾é¡µå³å¯è¿›è¡Œæ— ç—•æµè§ˆ</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{以åŠå¦å¤– 1 个网域}other{以åŠå¦å¤– # 个网域}}</translation>
<translation id="2536110899380797252">添加地å€</translation>
<translation id="2539524384386349900">检测</translation>
@@ -519,7 +541,14 @@
<translation id="2597378329261239068">本文档设置了密ç ä¿æŠ¤ï¼Œè¯·è¾“入密ç ã€‚</translation>
<translation id="2609632851001447353">其他å˜ä½“</translation>
<translation id="2610561535971892504">点击å¤åˆ¶</translation>
+<translation id="2617988307566202237">Chrome <ph name="BEGIN_EMPHASIS" />ä¸ä¼šä¿å­˜<ph name="END_EMPHASIS" />以下信æ¯ï¼š
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />您的æµè§ˆè®°å½•
+ <ph name="LIST_ITEM" />Cookie 和网站数æ®
+ <ph name="LIST_ITEM" />在表å•ä¸­å¡«å†™çš„ä¿¡æ¯
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (Envelope)</translation>
+<translation id="2623663032199728144">å¯ä»¥è¯¢é—®èƒ½å¦ä½¿ç”¨æ‚¨çš„å±å¹•çš„相关信æ¯</translation>
<translation id="2625385379895617796">您的时钟快了</translation>
<translation id="262745152991669301">å¯ä»¥è¯¢é—®èƒ½å¦è¿žæŽ¥åˆ° USB 设备</translation>
<translation id="2629325967560697240">如果您想获得 Chrome 最高级别的安全ä¿æŠ¤ï¼Œè¯·<ph name="BEGIN_ENHANCED_PROTECTION_LINK" />å¼€å¯å¢žå¼ºåž‹ä¿æŠ¤<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -553,6 +582,7 @@
<translation id="2709516037105925701">自动填充</translation>
<translation id="2713444072780614174">白色</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />,ä¾æ¬¡æŒ‰ Tab 键和 Enter é”®å³å¯åœ¨ Chrome 设置中管ç†æ‚¨çš„付款和信用å¡ä¿¡æ¯</translation>
+<translation id="271663710482723385">按 |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| å³å¯é€€å‡ºå…¨å±æ¨¡å¼</translation>
<translation id="2721148159707890343">请求æˆåŠŸ</translation>
<translation id="2723669454293168317">从 Chrome 设置中è¿è¡Œå®‰å…¨æ£€æŸ¥</translation>
<translation id="2726001110728089263">侧é¢çº¸åŒ£</translation>
@@ -583,6 +613,7 @@
<translation id="2850739647070081192">Invite (Envelope)</translation>
<translation id="2856444702002559011">攻击者å¯èƒ½ä¼šè¯•å›¾ä»Ž <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> 窃å–您的信æ¯ï¼ˆä¾‹å¦‚:密ç ã€é€šè®¯å†…容或信用å¡ä¿¡æ¯ï¼‰ã€‚<ph name="BEGIN_LEARN_MORE_LINK" />了解详情<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">此网站展示过侵扰性或误导性广告。</translation>
+<translation id="286512204874376891">虚拟å¡ä¼šä¼ªè£…æˆå®žä½“å¡ï¼Œä»Žè€Œä¿æŠ¤æ‚¨å…é­æ¬ºè¯ˆã€‚<ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">å‹å¥½</translation>
<translation id="2876489322757410363">å°†è¦é€€å‡ºæ— ç—•æ¨¡å¼ï¼Œä»¥ä¾¿é€šè¿‡å¤–部应用付款。是å¦ç»§ç»­ï¼Ÿ</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />,ä¾æ¬¡æŒ‰ Tab 键和 Enter é”®å³å¯åœ¨ Chrome 设置中管ç†æ‚¨çš„安全æµè§ˆè®¾ç½®åŠå…¶ä»–设置</translation>
@@ -607,6 +638,7 @@
<translation id="2930577230479659665">完æˆæ¯ä¸ªå‰¯æœ¬åŽè£åˆ‡</translation>
<translation id="2932085390869194046">建议密ç â€¦</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019">打开<ph name="PROTOCOL" />链接</translation>
<translation id="2941952326391522266">æ­¤æœåŠ¡å™¨æ— æ³•è¯æ˜Žå®ƒæ˜¯<ph name="DOMAIN" />;其安全è¯ä¹¦æ¥è‡ª<ph name="DOMAIN2" />。出现此问题的原因å¯èƒ½æ˜¯é…置有误或您的连接被拦截了。</translation>
<translation id="2943895734390379394">上传时间:</translation>
<translation id="2948083400971632585">您å¯ä»¥åœ¨è®¾ç½®é¡µé¢ä¸­åœç”¨ä»»ä½•é’ˆå¯¹æŸä¸ªè¿žæŽ¥é…置的代ç†ã€‚</translation>
@@ -639,6 +671,7 @@
<translation id="3037605927509011580">喔唷,崩溃啦ï¼</translation>
<translation id="3041612393474885105">è¯ä¹¦ä¿¡æ¯</translation>
<translation id="3044034790304486808">继续您的研究</translation>
+<translation id="305162504811187366">Chrome 远程桌é¢åŽ†å²è®°å½•ï¼ŒåŒ…括时间戳ã€ä¸»æœºå’Œå®¢æˆ·ç«¯ä¼šè¯ ID</translation>
<translation id="3060227939791841287">C9 (Envelope)</translation>
<translation id="3061707000357573562">修补æœåŠ¡</translation>
<translation id="306573536155379004">游æˆå·²å¼€å§‹ã€‚</translation>
@@ -677,6 +710,7 @@
<translation id="3197136577151645743">å¯ä»¥è¯¢é—®æ‚¨ä½•æ—¶åœ¨ä½¿ç”¨æ­¤è®¾å¤‡</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />,ä¾æ¬¡æŒ‰ Tab 键和 Enter é”®å³å¯åœ¨ Chrome 设置中管ç†æ‚¨è¦åŒæ­¥çš„ä¿¡æ¯</translation>
<translation id="320323717674993345">å–消付款</translation>
+<translation id="3203366800380907218">æ¥è‡ªç½‘络</translation>
<translation id="3207960819495026254">已加书签</translation>
<translation id="3209034400446768650">此网页å¯èƒ½ä¼šæ”¶å–费用</translation>
<translation id="3212581601480735796">您在 <ph name="HOSTNAME" /> 上的活动正被监控</translation>
@@ -693,10 +727,12 @@
<translation id="3234666976984236645">始终检测此网站上的é‡è¦å†…容</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />,ä¾æ¬¡æŒ‰ Tab 键和 Enter é”®å³å¯è‡ªå®šä¹‰æ‚¨çš„æµè§ˆå™¨å¤–观</translation>
<translation id="3240791268468473923">“无匹é…的安全付款凭æ®â€è¡¨å•å·²æ‰“å¼€</translation>
+<translation id="324180406144491771">“<ph name="HOST_NAME" />â€é“¾æŽ¥å·²è¢«ç¦ç”¨</translation>
<translation id="3249845759089040423">时髦</translation>
<translation id="3252266817569339921">法语</translation>
<translation id="3257954757204451555">这项信æ¯æ˜¯è°æ供的?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />,ä¾æ¬¡æŒ‰ Tab 键和 Enter é”®å³å¯åœ¨ Google 日历中快速创建新活动</translation>
+<translation id="3261488570342242926">了解虚拟å¡</translation>
<translation id="3264837738038045344">â€œç®¡ç† Chrome 设置â€æŒ‰é’®ï¼ŒæŒ‰ Enter é”®å³å¯è®¿é—®æ‚¨çš„ Chrome 设置</translation>
<translation id="3266793032086590337">值(冲çªï¼‰</translation>
<translation id="3268451620468152448">打开的标签页</translation>
@@ -710,6 +746,7 @@
<translation id="3288238092761586174"><ph name="URL" /> å¯èƒ½éœ€è¦é‡‡å–é¢å¤–措施æ¥éªŒè¯æ‚¨çš„付款</translation>
<translation id="3293642807462928945">详细了解“<ph name="POLICY_NAME" />â€æ”¿ç­–</translation>
<translation id="3295444047715739395">请在 Chrome 设置中查看和管ç†æ‚¨çš„密ç </translation>
+<translation id="3303795387212510132">å…许应用打开 <ph name="PROTOCOL_SCHEME" /> 链接?</translation>
<translation id="3303855915957856445">未找到任何æœç´¢ç»“æžœ</translation>
<translation id="3304073249511302126">è“牙扫æ</translation>
<translation id="3308006649705061278">组织å•ä½ (OU)</translation>
@@ -723,12 +760,6 @@
<translation id="3345782426586609320">眼ç›</translation>
<translation id="3355823806454867987">更改代ç†æœåŠ¡å™¨è®¾ç½®...</translation>
<translation id="3360103848165129075">付款处ç†ç¨‹åºå·¥ä½œè¡¨</translation>
-<translation id="3361596688432910856">Chrome <ph name="BEGIN_EMPHASIS" />ä¸ä¼šä¿å­˜<ph name="END_EMPHASIS" />以下信æ¯ï¼š
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />您的æµè§ˆè®°å½•
- <ph name="LIST_ITEM" />Cookie 和网站数æ®
- <ph name="LIST_ITEM" />在表å•ä¸­å¡«å†™çš„ä¿¡æ¯
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">此政策的值是系统从已弃用的 <ph name="OLD_POLICY" /> 政策中自动å¤åˆ¶è€Œæ¥çš„。您应改用此政策。</translation>
<translation id="3364869320075768271"><ph name="URL" /> 想使用您的虚拟实境设备和数æ®</translation>
<translation id="3366477098757335611">查看您的å¡</translation>
@@ -810,7 +841,6 @@
<translation id="3587738293690942763">中间</translation>
<translation id="3592413004129370115">Italian (Envelope)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{您å¯ä»¥éšæ—¶é‡ç½®è‡ªå·±æ‰€å±žçš„ç¾¤ç»„ã€‚å¤§çº¦éœ€è¦ 1 天的时间æ‰èƒ½åŠ å…¥æ–°ç¾¤ç»„。}=1{您å¯ä»¥éšæ—¶é‡ç½®è‡ªå·±æ‰€å±žçš„ç¾¤ç»„ã€‚å¤§çº¦éœ€è¦ 1 天的时间æ‰èƒ½åŠ å…¥æ–°ç¾¤ç»„。}other{您å¯ä»¥éšæ—¶é‡ç½®è‡ªå·±æ‰€å±žçš„ç¾¤ç»„ã€‚å¤§çº¦éœ€è¦ {NUM_DAYS} 天的时间æ‰èƒ½åŠ å…¥æ–°ç¾¤ç»„。}}</translation>
-<translation id="3596012367874587041">应用设置</translation>
<translation id="3600246354004376029"><ph name="TITLE" />,<ph name="DOMAIN" />,<ph name="TIME" /></translation>
<translation id="3603507503523709">已被您的管ç†å‘˜ç¦ç”¨çš„应用</translation>
<translation id="3608932978122581043">é€çº¸æ–¹å‘</translation>
@@ -852,6 +882,7 @@
<translation id="370972442370243704">å¼€å¯â€œåŽ†ç¨‹â€åŠŸèƒ½</translation>
<translation id="3711895659073496551">æš‚åœ</translation>
<translation id="3712624925041724820">许å¯å·²ç”¨å°½</translation>
+<translation id="3714633008798122362">网络日历</translation>
<translation id="3714780639079136834">å¼€å¯ç§»åŠ¨æ•°æ®ç½‘络或 WLAN</translation>
<translation id="3715597595485130451">连接到 Wi-Fi 网络</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />检查代ç†æœåŠ¡å™¨ã€é˜²ç«å¢™å’Œ DNS é…ç½®<ph name="END_LINK" /></translation>
@@ -913,6 +944,7 @@
<translation id="3906954721959377182">å¹³æ¿ç”µè„‘</translation>
<translation id="3909477809443608991"><ph name="URL" /> 想播放å—ä¿æŠ¤å†…容。Google 将会验è¯æ‚¨çš„设备身份,而且此网站å¯èƒ½ä¼šæŸ¥çœ‹æ‚¨çš„设备身份。</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">æ‹’ç»</translation>
<translation id="3939773374150895049">è¦æ”¹ç”¨ WebAuthn æ¥å–代银行å¡éªŒè¯ç  (CVC) å—?</translation>
<translation id="3946209740501886391">在该网站上一律询问</translation>
<translation id="3947595700203588284">å¯ä»¥è¯¢é—®èƒ½å¦è¿žæŽ¥åˆ° MIDI 设备</translation>
@@ -933,6 +965,7 @@
<translation id="3987940399970879459">å°äºŽ 1 MB</translation>
<translation id="3990250421422698716">撞页å移</translation>
<translation id="3996311196211510766">网站 <ph name="ORIGIN" /> å·²è¦æ±‚收到的所有请求都应用一项æ¥æºæ”¿ç­–,但此政策目å‰æ— æ³•åº”用。</translation>
+<translation id="4009243425692662128">您打å°çš„页é¢å†…容会被å‘é€åˆ° Google Cloud 或第三方进行分æžã€‚例如,这类内容å¯èƒ½ä¼šè¢«æ‰«æ,以确定其中是å¦åŒ…å«æ•æ„Ÿæ•°æ®ã€‚</translation>
<translation id="4010758435855888356">å…许使用存储空间?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{åŒ…å« {COUNT} 页内容的 PDF 文档}other{åŒ…å« {COUNT} 页内容的 PDF 文档}}</translation>
<translation id="4023431997072828269">由于系统正在使用ä¸å®‰å…¨çš„连接æ交此表å•ï¼Œä»–人将能看到您的信æ¯ã€‚</translation>
@@ -1023,6 +1056,7 @@
<translation id="4250680216510889253">å¦</translation>
<translation id="4253168017788158739">备注</translation>
<translation id="425582637250725228">系统å¯èƒ½ä¸ä¼šä¿å­˜æ‚¨æ‰€åšçš„更改。</translation>
+<translation id="425869179292622354">利用虚拟å¡å¢žå¼ºå®ƒçš„安全性?</translation>
<translation id="4258748452823770588">ç­¾å无效</translation>
<translation id="4261046003697461417">无法为å—ä¿æŠ¤çš„文档添加注释</translation>
<translation id="4265872034478892965">您的管ç†å‘˜å…许</translation>
@@ -1085,6 +1119,7 @@
<translation id="4434045419905280838">弹出å¼çª—å£å’Œé‡å®šå‘</translation>
<translation id="4435702339979719576">Postcard)</translation>
<translation id="443673843213245140">å·²åœç”¨ä»£ç†ï¼Œä½†æ˜¯æŒ‡å®šäº†æ˜Žç¡®çš„代ç†é…置。</translation>
+<translation id="4441832193888514600">被忽略了,因为此政策åªèƒ½è®¾ä¸ºäº‘端用户政策。</translation>
<translation id="4450893287417543264">ä¸å†æ˜¾ç¤º</translation>
<translation id="4451135742916150903">å¯ä»¥è¯¢é—®èƒ½å¦è¿žæŽ¥åˆ° HID 设备</translation>
<translation id="4452328064229197696">您刚æ‰ä½¿ç”¨çš„密ç é­é‡äº†æ•°æ®æ³„露。为确ä¿æ‚¨çš„å¸å·å®‰å…¨ï¼ŒGoogle 密ç ç®¡ç†å™¨å»ºè®®æ‚¨æ£€æŸ¥å·²ä¿å­˜çš„所有密ç ã€‚</translation>
@@ -1140,6 +1175,7 @@
<translation id="4628948037717959914">照片</translation>
<translation id="4631649115723685955">已关è”返现</translation>
<translation id="4636930964841734540">ä¿¡æ¯</translation>
+<translation id="4638670630777875591">Chromium 中的无痕模å¼</translation>
<translation id="464342062220857295">æœç´¢åŠŸèƒ½</translation>
<translation id="4644670975240021822">逆转顺åºï¼Œæ­£é¢æœä¸‹</translation>
<translation id="4646534391647090355">ç«‹å³å‰å¾€</translation>
@@ -1160,6 +1196,7 @@
<translation id="4708268264240856090">您的连接已中断</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />è¿è¡Œ Windows 网络诊断<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426"><ph name="USERNAME" /> 的密ç </translation>
<translation id="4724144314178270921">å¯ä»¥è¯¢é—®èƒ½å¦æŸ¥çœ‹æ‚¨å‰ªè´´æ¿ä¸­çš„文字和图片</translation>
<translation id="4726672564094551039">é‡æ–°åŠ è½½æ”¿ç­–</translation>
<translation id="4728558894243024398">å¹³å°</translation>
@@ -1181,6 +1218,7 @@
<translation id="4757993714154412917">您刚刚在一个诈骗网站中输入了密ç ã€‚为ä¿æŠ¤æ‚¨çš„å¸å·å®‰å…¨ï¼ŒChromium 建议检查您已ä¿å­˜çš„密ç ã€‚</translation>
<translation id="4758311279753947758">添加è”系信æ¯</translation>
<translation id="4761104368405085019">使用您的麦克风</translation>
+<translation id="4761869838909035636">è¿è¡Œ Chrome 安全检查</translation>
<translation id="4764776831041365478">网å€ä¸º <ph name="URL" /> 的网页å¯èƒ½æš‚时无法连接,或者它已永久性地移动到了新网å€ã€‚</translation>
<translation id="4766713847338118463">åŒé’‰ï¼ˆåº•éƒ¨ï¼‰</translation>
<translation id="4771973620359291008">å‘生未知错误。</translation>
@@ -1201,12 +1239,6 @@
<translation id="4819347708020428563">在默认视图中修改注释?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />,ä¾æ¬¡æŒ‰ Tab 键和 Enter é”®å³å¯å¿«é€Ÿåˆ›å»ºæ–°çš„ Google 表格</translation>
<translation id="4825507807291741242">强大</translation>
-<translation id="4827402517081186284">无痕模å¼æ— æ³•è®©æ‚¨åœ¨ç½‘上处于éšèº«çŠ¶æ€ï¼š
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />网站会知é“您何时访问了它们<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />雇主或学校å¯ä»¥è·Ÿè¸ªæµè§ˆæ´»åŠ¨<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />互è”网æœåŠ¡æ供商å¯èƒ½ä¼šç›‘控网络æµé‡<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">å¼€å¯è­¦å‘Š</translation>
<translation id="4838327282952368871">梦幻</translation>
<translation id="4840250757394056958">查看您的 Chrome 历å²è®°å½•</translation>
@@ -1218,12 +1250,12 @@
<translation id="4854362297993841467">该递é€æ–¹å¼ä¸å¯ç”¨ã€‚请å¦é€‰ä¸€ç§æ–¹å¼ã€‚</translation>
<translation id="4854853140771946034">在 Google Keep 中快速创建新记事</translation>
<translation id="485902285759009870">正在核对动æ€å¯†ç â€¦</translation>
+<translation id="4866506163384898554">按 |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| å¯æ˜¾ç¤ºé¼ æ ‡å…‰æ ‡</translation>
<translation id="4876188919622883022">简化版视图</translation>
<translation id="4876305945144899064">无用户å</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{æ— }=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />ã€<ph name="EXAMPLE_DOMAIN_2" />}other{<ph name="EXAMPLE_DOMAIN_1" />ã€<ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831">æœç´¢<ph name="TEXT" /></translation>
<translation id="4879491255372875719">自动(默认)</translation>
-<translation id="4879725228911483934">在您的å±å¹•ä¸Šæ‰“开和放置窗å£</translation>
<translation id="4880827082731008257">æœç´¢åŽ†å²è®°å½•</translation>
<translation id="4881695831933465202">打开</translation>
<translation id="4885256590493466218">结å¸æ—¶ä½¿ç”¨ <ph name="CARD_DETAIL" /> 付款</translation>
@@ -1232,6 +1264,7 @@
<translation id="4895877746940133817"><ph name="TYPE_1" />ã€<ph name="TYPE_2" />ã€<ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">第 9 å·</translation>
<translation id="4901778704868714008">ä¿å­˜â€¦</translation>
+<translation id="4905659621780993806">您的管ç†å‘˜å°†äºŽ <ph name="DATE" /><ph name="TIME" /> 自动é‡å¯æ‚¨çš„设备。请在设备é‡å¯å‰ä¿å­˜æ‰€æœ‰å·²æ‰“开的内容。</translation>
<translation id="4913987521957242411">打孔(左上角)</translation>
<translation id="4918221908152712722">安装<ph name="APP_NAME" />(ä¸éœ€è¦ä¸‹è½½ï¼‰</translation>
<translation id="4923459931733593730">付款</translation>
@@ -1240,6 +1273,7 @@
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />,按 Tab é”®å†æŒ‰ Enter é”®å¯è¿›è¡Œæœç´¢</translation>
<translation id="4930153903256238152">大容é‡</translation>
+<translation id="4940163644868678279">Chrome 中的无痕模å¼</translation>
<translation id="4943872375798546930">找ä¸åˆ°ç»“æžœ</translation>
<translation id="4950898438188848926">标签页切æ¢æŒ‰é’®ï¼ŒæŒ‰ Enter é”®å¯åˆ‡æ¢åˆ°æ‰“开的标签页,<ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="495170559598752135">æ“作</translation>
@@ -1249,6 +1283,7 @@
<translation id="4968522289500246572">此应用是专为移动设备设计的,å¯èƒ½æ— æ³•å¦¥å½“地调整大å°ã€‚此应用å¯èƒ½ä¼šå‡ºçŽ°é—®é¢˜æˆ–é‡å¯ã€‚</translation>
<translation id="4969341057194253438">删除录å±</translation>
<translation id="4973922308112707173">åŒå­”(顶部)</translation>
+<translation id="4976702386844183910">上次访问日期:<ph name="DATE" /></translation>
<translation id="4984088539114770594">使用麦克风?</translation>
<translation id="4984339528288761049">Prc5 (Envelope)</translation>
<translation id="4989163558385430922">查看全部</translation>
@@ -1310,6 +1345,7 @@
<translation id="5138227688689900538">收起</translation>
<translation id="5145883236150621069">ç­–ç•¥å“应中存在错误代ç </translation>
<translation id="5146995429444047494"><ph name="ORIGIN" /> 网站上的通知已被å±è”½</translation>
+<translation id="514704532284964975"><ph name="URL" /> 想在您点按手机时查看和更改 NFC 设备上的信æ¯</translation>
<translation id="5148809049217731050">æ­£é¢æœä¸Š</translation>
<translation id="515292512908731282">C4 (Envelope)</translation>
<translation id="5158275234811857234">å°é¢</translation>
@@ -1334,6 +1370,7 @@
<translation id="5215116848420601511">Google Pay 中存储的付款方å¼å’Œåœ°å€ä¿¡æ¯</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">纸匣 13</translation>
+<translation id="5216942107514965959">上次访问时间:今天</translation>
<translation id="5222812217790122047">需è¦æ供电å­é‚®ä»¶åœ°å€</translation>
<translation id="5230733896359313003">é€è´§åœ°å€</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1354,7 +1391,6 @@
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">文档属性</translation>
<translation id="528468243742722775">结æŸ</translation>
-<translation id="5284909709419567258">网络地å€</translation>
<translation id="5285570108065881030">显示所有已ä¿å­˜çš„密ç </translation>
<translation id="5287240709317226393">显示 Cookie</translation>
<translation id="5287456746628258573">此网站使用的安全性é…置已过期,这å¯èƒ½ä¼šå¯¼è‡´æ‚¨çš„ä¿¡æ¯ï¼ˆä¾‹å¦‚密ç æˆ–信用å¡å¡å·ï¼‰åœ¨å‘é€è‡³æ­¤ç½‘站时出现泄露。</translation>
@@ -1438,6 +1474,7 @@
<translation id="5556459405103347317">é‡æ–°åŠ è½½</translation>
<translation id="5560088892362098740">到期日期</translation>
<translation id="55635442646131152">文档大纲</translation>
+<translation id="5565613213060953222">打开无痕å¼æ ‡ç­¾é¡µ</translation>
<translation id="5565735124758917034">主动</translation>
<translation id="5570825185877910964">ä¿æŠ¤å¸å·</translation>
<translation id="5571083550517324815">无法从此地å€å–货。请å¦é€‰ä¸€ä¸ªåœ°å€ã€‚</translation>
@@ -1520,6 +1557,7 @@
<translation id="5869522115854928033">å·²ä¿å­˜çš„密ç </translation>
<translation id="5873013647450402046">银行需è¦ç¡®è®¤æ‚¨çš„身份。</translation>
<translation id="5887400589839399685">å·²ä¿å­˜å¡ç‰‡</translation>
+<translation id="5887687176710214216">上次访问时间:昨天</translation>
<translation id="5895138241574237353">é‡æ–°å¯åŠ¨</translation>
<translation id="5895187275912066135">é¢å‘日期</translation>
<translation id="5901630391730855834">黄色</translation>
@@ -1533,6 +1571,7 @@
<translation id="5921639886840618607">将银行å¡ä¿¡æ¯ä¿å­˜åˆ° Google å¸å·ä¸­ï¼Ÿ</translation>
<translation id="5922853866070715753">å³å°†å®Œæˆ</translation>
<translation id="5932224571077948991">网站展示过侵扰性或误导性广告</translation>
+<translation id="5938153366081463283">添加虚拟å¡</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347">正在打开 <ph name="SITE_NAME" />…</translation>
<translation id="5951495562196540101">无法通过消费者å¸å·æ³¨å†Œï¼ˆæœ‰å°è£…的许å¯ï¼‰ã€‚</translation>
@@ -1597,6 +1636,7 @@
<translation id="6120179357481664955">è¦è®°ä½æ‚¨çš„ UPI ID å—?</translation>
<translation id="6124432979022149706">Chrome ä¼ä¸šç‰ˆè¿žæŽ¥å™¨</translation>
<translation id="6127379762771434464">该项已移除</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />详细了解 Chrome 中的无痕模å¼<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">请检查所有网线是å¦éƒ½å·²è¿žå¥½ï¼Œç„¶åŽé‡æ–°å¯åŠ¨æ‚¨å¯èƒ½æ­£åœ¨ä½¿ç”¨çš„任何路由器ã€è°ƒåˆ¶è§£è°ƒå™¨æˆ–其他网络设备。</translation>
<translation id="614940544461990577">请试试以下办法:</translation>
<translation id="6150036310511284407">三孔(左侧)</translation>
@@ -1608,7 +1648,6 @@
<translation id="6169916984152623906">现在,您便å¯è¿›è¡Œç§å¯†æµè§ˆäº†ã€‚共用此设备的其他用户将ä¸ä¼šçœ‹åˆ°æ‚¨çš„活动,但您下载的内容和添加的书签ä»ä¼šä¿å­˜åœ¨è®¾å¤‡ä¸Šã€‚</translation>
<translation id="6177128806592000436">您与此网站之间建立的连接ä¸å®‰å…¨</translation>
<translation id="6180316780098470077">é‡è¯•é—´éš”</translation>
-<translation id="619448280891863779">å¯ä»¥è¯¢é—®èƒ½å¦åœ¨æ‚¨çš„å±å¹•ä¸Šæ‰“开和放置窗å£</translation>
<translation id="6196640612572343990">阻止第三方 Cookie</translation>
<translation id="6203231073485539293">请检查您的互è”网连接是å¦æ­£å¸¸</translation>
<translation id="6218753634732582820">è¦ä»Ž Chromium 中移除地å€å—?</translation>
@@ -1631,7 +1670,7 @@
<translation id="6272383483618007430">Google æ›´æ–°</translation>
<translation id="6276112860590028508">您的阅读清å•ä¸­çš„网页会显示在此处</translation>
<translation id="627746635834430766">若想在下次购物时更快æ·åœ°ä»˜æ¬¾ï¼Œè¯·å°†æ‚¨çš„付款å¡ä¿¡æ¯å’Œå¸å•é‚®å¯„地å€ä¿å­˜åˆ°æ‚¨çš„ Google å¸å·ä¸­ã€‚</translation>
-<translation id="6279098320682980337">未填充虚拟å¡å·ï¼Ÿç‚¹å‡»â€œä¿¡ç”¨å¡è¯¦ç»†ä¿¡æ¯â€å³å¯å¤åˆ¶</translation>
+<translation id="6279183038361895380">按 |<ph name="ACCELERATOR" />| å¯æ˜¾ç¤ºé¼ æ ‡å…‰æ ‡</translation>
<translation id="6280223929691119688">无法递é€åˆ°æ­¤åœ°å€ã€‚请å¦é€‰ä¸€ä¸ªåœ°å€ã€‚</translation>
<translation id="6282194474023008486">邮政编ç </translation>
<translation id="6285507000506177184">â€œç®¡ç† Chrome 中的下载内容â€æŒ‰é’®ï¼ŒæŒ‰ Enter é”®å³å¯ç®¡ç†æ‚¨å·²åœ¨ Chrome 中下载的文件</translation>
@@ -1639,6 +1678,7 @@
<translation id="6290238015253830360">为您推è的文章会显示在此处</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{您的设备将立å³é‡å¯}=1{您的设备将在 1 秒åŽé‡å¯}other{您的设备将在 # 秒åŽé‡å¯}}</translation>
<translation id="6302269476990306341">Chrome 中的 Google 助ç†å³å°†åœæ­¢å·¥ä½œ</translation>
<translation id="6305205051461490394">无法访问 <ph name="URL" />。</translation>
<translation id="6312113039770857350">网页无法打开</translation>
@@ -1712,6 +1752,7 @@
<translation id="6529602333819889595">æ¢å¤åˆ é™¤(&amp;R)</translation>
<translation id="6545864417968258051">è“牙扫æ</translation>
<translation id="6547208576736763147">åŒå­”(左侧)</translation>
+<translation id="6554732001434021288">上次访问时间:<ph name="NUM_DAYS" /> 天å‰</translation>
<translation id="6556866813142980365">é‡åš</translation>
<translation id="6569060085658103619">您正在查看扩展程åºé¡µé¢</translation>
<translation id="6573200754375280815">åŒå­”(å³ä¾§ï¼‰</translation>
@@ -1772,7 +1813,6 @@
<translation id="6757797048963528358">您的设备已进入休眠模å¼ã€‚</translation>
<translation id="6767985426384634228">更新地å€ï¼Ÿ</translation>
<translation id="6768213884286397650">Hagaki (Postcard)</translation>
-<translation id="6774185088257932239"><ph name="BEGIN_LINK" />详细了解<ph name="END_LINK" />无痕模å¼</translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">紫罗兰色</translation>
<translation id="6786747875388722282">扩展程åº</translation>
@@ -1856,7 +1896,6 @@
<translation id="706295145388601875">在 Chrome 设置中添加和管ç†åœ°å€</translation>
<translation id="7064851114919012435">è”系信æ¯</translation>
<translation id="7068733155164172741">输入 <ph name="OTP_LENGTH" /> ä½æ•°çš„动æ€å¯†ç </translation>
-<translation id="7070090581017165256">关于此网站</translation>
<translation id="70705239631109039">您的连接存在安全éšæ‚£</translation>
<translation id="7075452647191940183">请求过大</translation>
<translation id="7079718277001814089">此网站包å«æ¶æ„软件</translation>
@@ -1873,6 +1912,12 @@
<translation id="7111012039238467737">(有效)</translation>
<translation id="7118618213916969306">æœç´¢å‰ªè´´æ¿ä¸Šçš„网å€ï¼š<ph name="SHORT_URL" /></translation>
<translation id="7119414471315195487">关闭其他标签页或程åº</translation>
+<translation id="7129355289156517987">当您关闭 Chromium 中的所有无痕å¼æ ‡ç­¾é¡µåŽï¼Œç³»ç»Ÿä¼šä»Žæ­¤è®¾å¤‡ä¸Šæ¸…除您在这些标签页中的活动记录:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />æµè§ˆæ´»åŠ¨<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />æœç´¢è®°å½•<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />在表å•ä¸­å¡«å†™çš„ä¿¡æ¯<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">无法å‘此地å€é€è´§ã€‚请å¦é€‰ä¸€ä¸ªåœ°å€ã€‚</translation>
<translation id="7132939140423847331">您的管ç†å‘˜å·²ç¦æ­¢å¤åˆ¶æ­¤æ•°æ®ã€‚</translation>
<translation id="7135130955892390533">显示状æ€</translation>
@@ -1895,6 +1940,7 @@
<translation id="7192203810768312527">释放了 <ph name="SIZE" />。当您下次访问时,æŸäº›ç½‘站的加载速度å¯èƒ½ä¼šæ›´æ…¢ã€‚</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">您的管ç†å‘˜å¯ä»¥æŸ¥çœ‹ï¼š</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />,ä¾æ¬¡æŒ‰ Tab 键和 Enter é”®å³å¯æ‰“开新的无痕å¼æ ‡ç­¾é¡µè¿›è¡Œæ— ç—•æµè§ˆ</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> ä¸ç¬¦åˆç›¸å…³å®‰å…¨æ ‡å‡†ã€‚</translation>
<translation id="7210993021468939304">å¯æŸ¥çœ‹è¯¥å®¹å™¨å†…çš„ Linux 活动,并å¯åœ¨è¯¥å®¹å™¨å†…安装和è¿è¡Œ Linux 应用</translation>
@@ -1926,6 +1972,7 @@
<translation id="7304562222803846232">ç®¡ç† Google å¸å·éšç§è®¾ç½®</translation>
<translation id="7305756307268530424">å¯ç”¨æ…¢é€Ÿæ¨¡å¼</translation>
<translation id="7308436126008021607">åŽå°åŒæ­¥</translation>
+<translation id="7310392214323165548">设备很快就会é‡å¯</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">与连接相关的帮助</translation>
<translation id="7323804146520582233">éšè—“<ph name="SECTION" />â€éƒ¨åˆ†</translation>
@@ -1933,6 +1980,7 @@
<translation id="7334320624316649418">æ¢å¤é¡ºåºè°ƒæ•´(&amp;R)</translation>
<translation id="7335157162773372339">å¯ä»¥è¯¢é—®èƒ½å¦ä½¿ç”¨æ‚¨çš„æ‘„åƒå¤´</translation>
<translation id="7337248890521463931">显示更多行</translation>
+<translation id="7337418456231055214">未填充虚拟å¡å·ï¼Ÿç‚¹å‡»â€œä¿¡ç”¨å¡è¯¦ç»†ä¿¡æ¯â€å³å¯å¤åˆ¶ã€‚<ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">在您的平å°ä¸Šä¸å¯ç”¨ã€‚</translation>
<translation id="733923710415886693">该æœåŠ¡å™¨çš„è¯ä¹¦æœªé€šè¿‡è¯ä¹¦é€æ˜Žåº¦æ”¿ç­–进行披露。</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1955,6 +2003,7 @@
<translation id="7378627244592794276">å¦</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">ä¸é€‚用</translation>
+<translation id="7388594495505979117">{0,plural, =1{您的设备将在 1 分钟åŽé‡å¯}other{您的设备将在 # 分钟åŽé‡å¯}}</translation>
<translation id="7390545607259442187">确认信用å¡</translation>
<translation id="7392089738299859607">更新地å€</translation>
<translation id="7399802613464275309">安全检查</translation>
@@ -1991,6 +2040,12 @@
<translation id="7485870689360869515">找ä¸åˆ°æ•°æ®ã€‚</translation>
<translation id="7495528107193238112">该内容被å±è”½äº†ã€‚请è”系网站所有者以解决此问题。</translation>
<translation id="7497998058912824456">“创建文档â€æŒ‰é’®ï¼ŒæŒ‰ Enter é”®å³å¯å¿«é€Ÿåˆ›å»ºæ–°çš„ Google 文档</translation>
+<translation id="7506488012654002225">Chromium <ph name="BEGIN_EMPHASIS" />ä¸ä¼šä¿å­˜<ph name="END_EMPHASIS" />以下信æ¯ï¼š
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />您的æµè§ˆè®°å½•
+ <ph name="LIST_ITEM" />Cookie 和网站数æ®
+ <ph name="LIST_ITEM" />在表å•ä¸­å¡«å†™çš„ä¿¡æ¯
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">返回的政策设备 ID 为空,或与当å‰çš„设备 ID ä¸ä¸€è‡´</translation>
<translation id="7508870219247277067">黄绿色</translation>
<translation id="7511955381719512146">您è¦ä½¿ç”¨çš„ Wi-Fi 网络å¯èƒ½éœ€è¦æ‚¨è®¿é—® <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />。</translation>
@@ -2104,7 +2159,6 @@
<translation id="7813600968533626083">从 Chrome 中移除表å•å»ºè®®ï¼Ÿ</translation>
<translation id="781440967107097262">分享剪贴æ¿ï¼Ÿ</translation>
<translation id="7815407501681723534">找到了 <ph name="NUMBER_OF_RESULTS" /> 个与“<ph name="SEARCH_STRING" />â€ç›¸ç¬¦çš„<ph name="SEARCH_RESULTS" /></translation>
-<translation id="782125616001965242">显示此网站的相关信æ¯</translation>
<translation id="782886543891417279">您è¦ä½¿ç”¨çš„ Wi-Fi 网络(<ph name="WIFI_NAME" />)å¯èƒ½éœ€è¦æ‚¨è®¿é—®å…¶ç™»å½•é¡µé¢ã€‚</translation>
<translation id="7836231406687464395">Postfix (Envelope)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{æ— }=1{1 个应用(<ph name="EXAMPLE_APP_1" />)}=2{2 个应用(<ph name="EXAMPLE_APP_1" />ã€<ph name="EXAMPLE_APP_2" />)}other{# 个应用(<ph name="EXAMPLE_APP_1" />ã€<ph name="EXAMPLE_APP_2" />ã€<ph name="AND_MORE" />)}}</translation>
@@ -2121,7 +2175,6 @@
<translation id="7888575728750733395">打å°æ“作渲染方å¼</translation>
<translation id="7894280532028510793">如果拼写无误,请<ph name="BEGIN_LINK" />å°è¯•è¿è¡Œç½‘络诊断<ph name="END_LINK" />。</translation>
<translation id="7904208859782148177">C3 (Envelope)</translation>
-<translation id="7931318309563332511">未知</translation>
<translation id="793209273132572360">更新地å€ï¼Ÿ</translation>
<translation id="7932579305932748336">涂层</translation>
<translation id="79338296614623784">请输入有效的电è¯å·ç </translation>
@@ -2146,13 +2199,14 @@
<translation id="7976214039405368314">请求次数过多</translation>
<translation id="7977538094055660992">输出设备</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">å·²ç»å…³è”到</translation>
<translation id="798134797138789862">å¯ä»¥è¯¢é—®èƒ½å¦ä½¿ç”¨è™šæ‹Ÿå®žå¢ƒè®¾å¤‡å’Œæ•°æ®</translation>
<translation id="7984945080620862648">您目å‰æ— æ³•è®¿é—®<ph name="SITE" />,因为此网站å‘é€äº†Chrome无法处ç†çš„æ‚乱凭æ®ã€‚网络错误和攻击通常是暂时的,因此,此网页ç¨åŽå¯èƒ½ä¼šæ¢å¤æ­£å¸¸ã€‚</translation>
-<translation id="79859296434321399">è¦æŸ¥çœ‹å¢žå¼ºçŽ°å®žå†…容,请安装 ARCore</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">装订</translation>
<translation id="7992044431894087211">已继续与<ph name="APPLICATION_TITLE" />共享å±å¹•</translation>
<translation id="7995512525968007366">未指定</translation>
+<translation id="7998269595945679889">“打开无痕å¼æ ‡ç­¾é¡µâ€æŒ‰é’®ï¼ŒæŒ‰ä¸€ä¸‹ Enter é”®å³å¯æ‰“开新的无痕å¼æ ‡ç­¾é¡µè¿›è¡Œæ— ç—•æµè§ˆ</translation>
<translation id="800218591365569300">请å°è¯•å…³é—­å…¶ä»–标签页或程åºä»¥é‡Šæ”¾å†…存。</translation>
<translation id="8004582292198964060">æµè§ˆå™¨</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{这张å¡åŠå…¶å¸å•é‚®å¯„地å€å°†è¢«ä¿å­˜ã€‚登录 <ph name="USER_EMAIL" /> åŽå³å¯ä½¿ç”¨è¿™å¼ å¡ã€‚}other{这些å¡åŠå…¶å¸å•é‚®å¯„地å€å°†è¢«ä¿å­˜ã€‚登录 <ph name="USER_EMAIL" /> åŽå³å¯ä½¿ç”¨è¿™äº›å¡ã€‚}}</translation>
@@ -2212,6 +2266,7 @@
<translation id="8202370299023114387">冲çª</translation>
<translation id="8206978196348664717">Prc4 (Envelope)</translation>
<translation id="8211406090763984747">连接是安全的</translation>
+<translation id="8217240300496046857">网站无法使用 Cookie æ¥è·Ÿè¸ªæ‚¨åœ¨ç½‘上的活动。æŸäº›ç½‘站上的功能å¯èƒ½ä¼šæ— æ³•æ­£å¸¸è¿ä½œã€‚</translation>
<translation id="8218327578424803826">分é…çš„ä½ç½®ï¼š</translation>
<translation id="8220146938470311105">C7/C6 (Envelope)</translation>
<translation id="8225771182978767009">设置此计算机的用户已选择å±è”½æ­¤ç½‘站。</translation>
@@ -2252,14 +2307,9 @@
<translation id="830498451218851433">对折</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">已安装的应用åŠå…¶ä½¿ç”¨é¢‘率</translation>
+<translation id="8317207217658302555">更新 ARCore?</translation>
<translation id="831997045666694187">晚上</translation>
<translation id="8321476692217554900">通知</translation>
-<translation id="8328484624016508118">关闭所有无痕å¼æ ‡ç­¾é¡µä¹‹åŽï¼ŒChrome 会清除:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />您在这部设备上的æµè§ˆæ´»åŠ¨è®°å½•<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />您在这部设备上的æœç´¢è®°å½•<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />您在表å•ä¸­å¡«å†™è¿‡çš„ä¿¡æ¯<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489">访问 <ph name="HOST_NAME" /> 的请求é­åˆ°æ‹’ç»</translation>
<translation id="833262891116910667">çªå‡ºæ˜¾ç¤º</translation>
<translation id="8339163506404995330">系统ä¸ä¼šè‡ªåŠ¨ç¿»è¯‘æºè¯­è¨€ä¸º<ph name="LANGUAGE" />的网页</translation>
@@ -2311,6 +2361,7 @@
<translation id="8507227106804027148">命令行</translation>
<translation id="8508648098325802031">æœç´¢å›¾æ ‡</translation>
<translation id="8511402995811232419">ç®¡ç† Cookie</translation>
+<translation id="8519753333133776369">您的管ç†å‘˜å…许使用的 HID 设备</translation>
<translation id="8522552481199248698">Chrome å¯ä»¥å¸®åŠ©æ‚¨ä¿æŠ¤æ‚¨çš„ Google å¸å·å’Œæ›´æ”¹å¯†ç ã€‚</translation>
<translation id="8530813470445476232">请在 Chrome 设置中清除您的æµè§ˆè®°å½•ã€Cookieã€ç¼“å­˜åŠå…¶ä»–æ•°æ®</translation>
<translation id="8533619373899488139">请访问 &lt;strong&gt;chrome://policy&lt;/strong&gt;,查看被å±è”½çš„网å€åˆ—表以åŠæ‚¨çš„系统管ç†å‘˜å¼ºåˆ¶æ‰§è¡Œçš„其他政策。</translation>
@@ -2322,7 +2373,6 @@
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{é‡ç½®è¿™é¡¹æƒé™}other{é‡ç½®è¿™äº›æƒé™}}</translation>
<translation id="8555010941760982128">结账时请使用此促销代ç </translation>
<translation id="8557066899867184262">银行å¡éªŒè¯ç  (CVC) ä½äºŽé“¶è¡Œå¡èƒŒé¢ã€‚</translation>
-<translation id="8558485628462305855">è¦æŸ¥çœ‹å¢žå¼ºçŽ°å®žå†…容,请更新 ARCore</translation>
<translation id="8559762987265718583">您设备的日期和时间(<ph name="DATE_AND_TIME" />)ä¸æ­£ç¡®ï¼Œå› æ­¤æ— æ³•ä¸Ž <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> 建立ç§å¯†è¿žæŽ¥ã€‚</translation>
<translation id="8564182942834072828">å•ç‹¬çš„文档/éžé€ä»½æ‰“å°çš„副本</translation>
<translation id="8564985650692024650">如果您在其他网站上é‡å¤ä½¿ç”¨äº†æ‚¨çš„ <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> 密ç ï¼ŒChromium 建议您é‡ç½®è¯¥å¯†ç ã€‚</translation>
@@ -2342,6 +2392,7 @@
<translation id="865032292777205197">移动传感器</translation>
<translation id="8663226718884576429">订å•æ‘˜è¦ï¼Œ<ph name="TOTAL_LABEL" />,更多详情</translation>
<translation id="8666678546361132282">英语</translation>
+<translation id="8669306706049782872">使用您的å±å¹•çš„相关信æ¯æ‰“开并放置窗å£</translation>
<translation id="867224526087042813">ç­¾å</translation>
<translation id="8676424191133491403">无延迟</translation>
<translation id="8680536109547170164"><ph name="QUERY" />,答案,<ph name="ANSWER" /></translation>
@@ -2368,6 +2419,7 @@
<translation id="8731544501227493793">“管ç†å¯†ç â€æŒ‰é’®ï¼ŒæŒ‰ Enter é”®å³å¯åœ¨ Chrome 设置中查看和管ç†æ‚¨çš„密ç </translation>
<translation id="8734529307927223492">您的 <ph name="DEVICE_TYPE" /> ç”± <ph name="MANAGER" /> 管ç†</translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />,ä¾æ¬¡æŒ‰ Tab 键和 Enter é”®å³å¯æ‰“开一个新的无痕å¼çª—å£ä»¥ç§å¯†æµè§ˆç½‘页</translation>
+<translation id="8737685506611670901">打开<ph name="PROTOCOL" />链接而éžâ€œ<ph name="REPLACED_HANDLER_TITLE" />â€</translation>
<translation id="8738058698779197622">è¦å»ºç«‹å®‰å…¨è¿žæŽ¥ï¼Œæ‚¨çš„时钟设置必须正确。这是因为,网站用于è¯æ˜Žèº«ä»½çš„è¯ä¹¦ä»…在特定时间段有效。由于您设备的时钟ä¸æ­£ç¡®ï¼Œå› æ­¤ Chromium 无法验è¯è¿™äº›è¯ä¹¦ã€‚</translation>
<translation id="8740359287975076522">无法找到 <ph name="HOST_NAME" /> çš„ &lt;abbr id="dnsDefinition"&gt;DNS 地å€&lt;/abbr&gt;。正在诊断该问题。</translation>
<translation id="8742371904523228557">您的 <ph name="ORIGIN" /> 验è¯ç æ˜¯ <ph name="ONE_TIME_CODE" /></translation>
@@ -2395,6 +2447,7 @@
<translation id="883848425547221593">其他书签</translation>
<translation id="884264119367021077">é€è´§åœ°å€</translation>
<translation id="884923133447025588">未找到任何åŠé”€æœºåˆ¶ã€‚</translation>
+<translation id="8849262850971482943">使用您的虚拟å¡æå‡å®‰å…¨æ€§</translation>
<translation id="885730110891505394">与 Google 分享</translation>
<translation id="8858065207712248076">如果您在其他网站上é‡å¤ä½¿ç”¨äº†æ‚¨çš„ <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> 密ç ï¼ŒChrome 建议您é‡ç½®è¯¥å¯†ç ã€‚</translation>
<translation id="885906927438988819">如果拼写无误,请<ph name="BEGIN_LINK" />å°è¯•è¿è¡Œ Windows 网络诊断<ph name="END_LINK" />。</translation>
@@ -2444,6 +2497,7 @@
<translation id="9004367719664099443">VR 会è¯æ­£åœ¨è¿›è¡Œä¸­</translation>
<translation id="9005998258318286617">未能加载 PDF 文档。</translation>
<translation id="9008201768610948239">忽略</translation>
+<translation id="901834265349196618">电å­é‚®ä»¶</translation>
<translation id="9020200922353704812">必须输入信用å¡å¸å•é‚®å¯„地å€</translation>
<translation id="9020542370529661692">已将此网页内容翻译æˆ<ph name="TARGET_LANGUAGE" /></translation>
<translation id="9020742383383852663">A8</translation>
@@ -2492,6 +2546,7 @@
<translation id="9150045010208374699">使用您的摄åƒå¤´</translation>
<translation id="9150685862434908345">您的管ç†å‘˜å¯ä»¥è¿œç¨‹æ›´æ”¹æ‚¨çš„æµè§ˆå™¨è®¾ç½®ã€‚此设备上的活动å¯èƒ½ä¹Ÿåœ¨æŽ¥å— Chrome 外部的管ç†ã€‚<ph name="BEGIN_LINK" />了解详情<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">已更新</translation>
+<translation id="9155211586651734179">已连接音频外围设备</translation>
<translation id="9157595877708044936">正在设置...</translation>
<translation id="9158625974267017556">C6 (Envelope)</translation>
<translation id="9164029392738894042">准确度检查</translation>
diff --git a/chromium/components/strings/components_strings_zh-HK.xtb b/chromium/components/strings/components_strings_zh-HK.xtb
index 5d02f73cce7..d3214227d14 100644
--- a/chromium/components/strings/components_strings_zh-HK.xtb
+++ b/chromium/components/strings/components_strings_zh-HK.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">查看詳情</translation>
<translation id="1030706264415084469"><ph name="URL" /> è¦æ±‚在您的è£ç½®ä¸Šæ°¸ä¹…儲存大é‡æ•¸æ“š</translation>
<translation id="1032854598605920125">順時é‡æ–¹å‘旋轉</translation>
+<translation id="1033329911862281889">無痕模å¼ç„¡æ³•è®“您在網絡上ä¸ç•™ç—•è·¡ï¼š
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />網站åŠå…¶ä½¿ç”¨çš„æœå‹™å¯ä»¥æŸ¥çœ‹ç€è¦½æ´»å‹•<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />僱主或學校å¯ä»¥è¿½è¹¤ç€è¦½æ´»å‹•<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />互è¯ç¶²æœå‹™ä¾›æ‡‰å•†å¯ä»¥ç›£å¯Ÿç¶²çµ¡æµé‡<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">åœç”¨</translation>
<translation id="1036982837258183574">按下 |<ph name="ACCELERATOR" />| å³å¯é€€å‡ºå…¨èž¢å¹•</translation>
<translation id="1038106730571050514">顯示建議</translation>
<translation id="1038842779957582377">ä¸æ˜Žå稱</translation>
<translation id="1041998700806130099">工作表訊æ¯</translation>
<translation id="1048785276086539861">在您編輯註解時,此文件將會返回單é æª¢è¦–模å¼</translation>
-<translation id="1049743911850919806">無痕模å¼</translation>
<translation id="1050038467049342496">關閉其他應用程å¼</translation>
<translation id="1055184225775184556">復原新增(&amp;U)</translation>
<translation id="1056898198331236512">警告</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">政策快å–正確</translation>
<translation id="1130564665089811311">翻譯網é æŒ‰éˆ•ï¼Œã©’一下 Enter éµå°±å¯ä»¥é€éŽ Google 翻譯翻譯呢個網é </translation>
<translation id="1131264053432022307">您複製的圖片</translation>
+<translation id="1142846828089312304">在無痕模å¼ä¸­å°éŽ–第三方 Cookie</translation>
<translation id="1150979032973867961">伺æœå™¨ç„¡æ³•è­‰æ˜Žå…¶å±¬æ–¼ <ph name="DOMAIN" /> 網域;其安全性憑證未å–得您電腦的æ“作系統的信任。這å¯èƒ½æ˜¯å› ç‚ºè¨­å®šéŒ¯èª¤ï¼Œæˆ–有攻擊者攔截您的連線。</translation>
<translation id="1151972924205500581">請輸入密碼</translation>
<translation id="1156303062776767266">您正在查看本機或共用檔案</translation>
@@ -64,7 +70,6 @@
<translation id="1178581264944972037">æš«åœ</translation>
<translation id="1181037720776840403">移除</translation>
<translation id="1186201132766001848">檢查密碼</translation>
-<translation id="1195210374336998651">å‰å¾€æ‡‰ç”¨ç¨‹å¼è¨­å®š</translation>
<translation id="1195558154361252544">系統已自動å°éŽ–所有網站的通知,但您å…許的網站除外</translation>
<translation id="1197088940767939838">橙色</translation>
<translation id="1201402288615127009">下一個</translation>
@@ -111,7 +116,7 @@
<translation id="1307966114820526988">這些功能已被淘汰</translation>
<translation id="1308113895091915999">é©ç”¨å„ªæƒ </translation>
<translation id="1312803275555673949">有什麼證據證明資訊屬實?</translation>
-<translation id="131405271941274527"><ph name="URL" /> 想在您以手機觸踫 NFC è£ç½®æ™‚傳é€å’ŒæŽ¥æ”¶è³‡æ–™</translation>
+<translation id="1314311879718644478">查看擴張實境內容</translation>
<translation id="1314509827145471431">é‡˜è£ (å³å´)</translation>
<translation id="1318023360584041678">已儲存至分é ç¾¤çµ„</translation>
<translation id="1319245136674974084">使用這個應用程å¼æ™‚ä¸è¦å†å•æˆ‘</translation>
@@ -161,6 +166,7 @@
<translation id="142858679511221695">雲端使用者</translation>
<translation id="1428729058023778569">此網站ä¸æ”¯æ´ HTTPS,因此ç€è¦½å™¨é¡¯ç¤ºæ­¤è­¦å‘Šè¨Šæ¯ã€‚<ph name="BEGIN_LEARN_MORE_LINK" />瞭解詳情<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">列å°</translation>
+<translation id="1432187715652018471">網é æƒ³è¦å®‰è£æœå‹™è™•ç†å¸¸å¼ã€‚</translation>
<translation id="1432581352905426595">管ç†æœå°‹å¼•æ“Ž</translation>
<translation id="1436185428532214179">å¯è¦æ±‚編輯è£ç½®ä¸­çš„檔案和資料夾</translation>
<translation id="1442386063175183758">å³åŠé‚Šå°æ‘º</translation>
@@ -181,6 +187,12 @@
<translation id="1483493594462132177">傳é€</translation>
<translation id="1484290072879560759">é¸æ“‡ä»˜é‹åœ°å€</translation>
<translation id="1492194039220927094">政策推é€ï¼š</translation>
+<translation id="149293076951187737">關閉所有 Chrome ç„¡ç—•å¼åˆ†é å¾Œï¼Œç³»çµ±æœƒå¾žæ­¤è£ç½®ä¸Šæ¸…除您在這些分é ä¸Šçš„活動記錄:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ç€è¦½æ´»å‹•<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />æœå°‹è¨˜éŒ„<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />在表格中輸入的資料<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">返回分é </translation>
<translation id="1501859676467574491">顯示您 Google 帳戶中的付款å¡</translation>
<translation id="1507202001669085618">&lt;p&gt;如果您正在使用的 Wi-Fi å…¥å£ç¶²ç«™éœ€è¦ç™»å…¥æ‰èƒ½é€£ç·šè‡³ç¶²çµ¡ï¼Œä¾¿æœƒçœ‹åˆ°æ­¤éŒ¯èª¤è¨Šæ¯ã€‚&lt;/p&gt;
@@ -208,6 +220,8 @@
<translation id="1559572115229829303">&lt;p&gt;由於您è£ç½®çš„日期和時間 (<ph name="DATE_AND_TIME" />) ä¸æ­£ç¢ºï¼Œå› æ­¤ç„¡æ³•èˆ‡ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> 建立ç§äººé€£ç·šã€‚&lt;/p&gt;
&lt;p&gt;請在「設定ã€&lt;strong&gt;&lt;/strong&gt;應用程å¼ä¸­ï¼Œå‰å¾€ [一般] &lt;strong&gt;&lt;/strong&gt;並調整日期和時間。&lt;/p&gt;</translation>
+<translation id="1559839503761818503">管ç†å“¡å°‡åœ¨ <ph name="DATE" /><ph name="TIME" /> é‡æ–°å•Ÿå‹•æ‚¨çš„è£ç½®ã€‚</translation>
+<translation id="156703335097561114">網絡資料,例如網絡ä½å€ã€ä»‹é¢è¨­å®šï¼Œä»¥åŠé€£ç·šå“質</translation>
<translation id="1567040042588613346">此政策é‹ä½œæ­£å¸¸ï¼Œä½†èˆ‡å…¶ä»–地方設定的值相åŒï¼Œä¸¦å·²å–代該值。</translation>
<translation id="1569487616857761740">輸入到期日</translation>
<translation id="1581080074034554886">信用å¡é©—證碼 (CVC)</translation>
@@ -215,6 +229,7 @@
<translation id="1583429793053364125">顯示此網é æ™‚發生錯誤。</translation>
<translation id="1586541204584340881">您已安è£çš„擴充程å¼</translation>
<translation id="1588438908519853928">一般</translation>
+<translation id="1589050138437146318">è¦å®‰è£ ARCore 嗎?</translation>
<translation id="1592005682883173041">本地資料存å–</translation>
<translation id="1594030484168838125">é¸æ“‡</translation>
<translation id="160851722280695521">暢玩 Chrome æé¾éŠæˆ²</translation>
@@ -279,6 +294,7 @@
<translation id="1763864636252898013">伺æœå™¨ç„¡æ³•è­‰æ˜Žå…¶å±¬æ–¼ <ph name="DOMAIN" /> 網域;其安全性憑證未å–得您è£ç½®çš„æ“作系統的信任。這å¯èƒ½æ˜¯å› ç‚ºè¨­å®šéŒ¯èª¤ï¼Œæˆ–有攻擊者攔截您的連線。</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />嘗試執行 Windows 網絡診斷<ph name="END_LINK" />。</translation>
<translation id="1772163372082567643">您的目標伺æœå™¨ã€Œ<ph name="ORIGIN" />ã€å·²è¨­å®šæ¨™é¡Œè¦æ±‚為收到的所有è¦æ±‚套用來æºæ”¿ç­–。ä¸éŽï¼Œç”±æ–¼è©²æ¨™é¡Œæ ¼å¼éŒ¯èª¤ï¼Œå› æ­¤ç€è¦½å™¨ç„¡æ³•å®Œæˆæ‚¨å‘ <ph name="SITE" /> æ出的è¦æ±‚。網站網絡供應商å¯ä½¿ç”¨ä¾†æºæ”¿ç­–設定網站的安全性åŠå…¶ä»–屬性。</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />進一步瞭解 Chromium 無痕模å¼<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">您最近開啟的分é æœƒåœ¨é€™è£¡é¡¯ç¤º</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -406,6 +422,7 @@
<translation id="22081806969704220">紙匣 3</translation>
<translation id="2212735316055980242">找ä¸åˆ°æ”¿ç­–</translation>
<translation id="2213606439339815911">正在擷å–項目…</translation>
+<translation id="2213612003795704869">已列å°é é¢</translation>
<translation id="2215727959747642672">檔案編輯</translation>
<translation id="2218879909401188352">ç›®å‰åœ¨ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> 上的攻擊者å¯èƒ½æœƒå®‰è£å±éšªçš„應用程å¼ä¾†æ害您的è£ç½®ã€æš—中加入隱è—çš„æµå‹•æœå‹™è²»ç”¨ï¼Œæˆ–ç«Šå–您的個人資料。<ph name="BEGIN_LEARN_MORE_LINK" />瞭解詳情<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">沒有互è¯ç¶²</translation>
@@ -415,6 +432,7 @@
<translation id="2248949050832152960">使用 WebAuthn</translation>
<translation id="2250931979407627383">é‚Šç·£é‡˜è£ (å·¦å´)</translation>
<translation id="225207911366869382">這個政策值已ä¸é©ç”¨ã€‚</translation>
+<translation id="2256115617011615191">ç«‹å³é‡æ–°å•Ÿå‹•</translation>
<translation id="2258928405015593961">請將到期日設在未來,然後å†è©¦ä¸€æ¬¡</translation>
<translation id="225943865679747347">錯誤代碼:<ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">HTTP 錯誤</translation>
@@ -442,6 +460,7 @@
<translation id="2337852623177822836">由管ç†å“¡æŽ§åˆ¶çš„設定</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> è¦æ±‚與下列è—牙è£ç½®é…å°</translation>
<translation id="2346319942568447007">您複製的圖片</translation>
+<translation id="2350796302381711542">è¦å…許 <ph name="HANDLER_HOSTNAME" /> å–代 <ph name="REPLACED_HANDLER_TITLE" /> 開啟所有 <ph name="PROTOCOL" /> 連çµå—Žï¼Ÿ</translation>
<translation id="2354001756790975382">其他書籤</translation>
<translation id="2354430244986887761">Google 安全ç€è¦½åŠŸèƒ½æœ€è¿‘在 <ph name="SITE" /> 上<ph name="BEGIN_LINK" />發ç¾æœ‰å®³çš„應用程å¼<ph name="END_LINK" />。</translation>
<translation id="2355395290879513365">攻擊者å¯èƒ½å¯ä»¥çœ‹åˆ°æ‚¨æ­£åœ¨æ­¤ç¶²ç«™ä¸Šçœ‹åˆ°çš„圖片,然後é€éŽä¿®æ”¹åœ–片來欺騙您。</translation>
@@ -467,6 +486,7 @@
<translation id="2413528052993050574">伺æœå™¨ç„¡æ³•è­‰æ˜Žå…¶å±¬æ–¼ <ph name="DOMAIN" /> 網域;其安全性憑證已被撤銷。這å¯èƒ½æ˜¯å› ç‚ºè¨­å®šéŒ¯èª¤ï¼Œæˆ–有攻擊者攔截您的連線。</translation>
<translation id="2414886740292270097">ç°æš—</translation>
<translation id="2430968933669123598">ç®¡ç† Google 帳戶,㩒一下 Enter éµå°±å¯ä»¥å–º Google 帳戶度管ç†ä½ å˜…資料ã€ç§éš±æ¬ŠåŒåŸ‹å®‰å…¨è¨­å®š</translation>
+<translation id="2436186046335138073">è¦å…許 <ph name="HANDLER_HOSTNAME" /> 開啟所有 <ph name="PROTOCOL" /> 連çµå—Žï¼Ÿ</translation>
<translation id="2438874542388153331">四孔 (å³å´)</translation>
<translation id="2450021089947420533">ç€è¦½éŽç¨‹</translation>
<translation id="2463739503403862330">填寫</translation>
@@ -474,6 +494,7 @@
<translation id="2465655957518002998">é¸æ“‡é€Ÿéžæ–¹å¼</translation>
<translation id="2465688316154986572">釘書釘</translation>
<translation id="2465914000209955735">管ç†æ‚¨åœ¨ Chrome 中下載嘅檔案</translation>
+<translation id="2466004615675155314">顯示來自網絡的資料</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />執行網絡診斷<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">1 至 N çš„é †åº</translation>
<translation id="2470767536994572628">在您編輯註解時,此文件將會返回單é æª¢è¦–模å¼åŠè½‰å›žåŽŸæœ¬çš„æ–¹å‘</translation>
@@ -494,6 +515,7 @@
<translation id="2523886232349826891">åªæœƒå„²å­˜è‡³æ­¤è£ç½®</translation>
<translation id="2524461107774643265">新增更多資料</translation>
<translation id="2529899080962247600">此欄ä½åªèƒ½åŒ…å« <ph name="MAX_ITEMS_LIMIT" /> 個項目,超éŽçš„項目會被忽略。</translation>
+<translation id="2535585790302968248">é–‹å•Ÿæ–°çš„ç„¡ç—•å¼åˆ†é ä»¥ç§ä¸‹ç€è¦½å…§å®¹</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{å’Œå¦å¤– 1 個網域}other{å’Œå¦å¤– # 個網域}}</translation>
<translation id="2536110899380797252">新增地å€</translation>
<translation id="2539524384386349900">åµæ¸¬</translation>
@@ -519,7 +541,14 @@
<translation id="2597378329261239068">此文件å—到密碼ä¿è­·ï¼Œè«‹è¼¸å…¥å¯†ç¢¼ã€‚</translation>
<translation id="2609632851001447353">變化</translation>
<translation id="2610561535971892504">點擊複製</translation>
+<translation id="2617988307566202237">Chrome <ph name="BEGIN_EMPHASIS" />ä¸æœƒå„²å­˜<ph name="END_EMPHASIS" />以下資料:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />您的ç€è¦½è¨˜éŒ„
+ <ph name="LIST_ITEM" />Cookie 和網站資料
+ <ph name="LIST_ITEM" />在表格中輸入的資料
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (ä¿¡å°)</translation>
+<translation id="2623663032199728144">å¯è¦æ±‚使用螢幕中的資料</translation>
<translation id="2625385379895617796">您時é˜çš„時間éŽå¿«</translation>
<translation id="262745152991669301">å¯è¦æ±‚連接 USB è£ç½®</translation>
<translation id="2629325967560697240">如è¦ç²å¾— Chrome 最高程度的安全防護,請<ph name="BEGIN_ENHANCED_PROTECTION_LINK" />啟用強化ä¿è­·åŠŸèƒ½<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -553,6 +582,7 @@
<translation id="2709516037105925701">自動填入</translation>
<translation id="2713444072780614174">白色</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />,㩒一下 Tab éµï¼Œç„¶å¾Œã©’一下 Enter éµå°±å¯ä»¥å–º Chrome 設定度管ç†ä»˜æ¬¾åŒä¿¡ç”¨å¡è³‡æ–™</translation>
+<translation id="271663710482723385">按下 |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| å³å¯çµæŸå…¨èž¢å¹•æ¨¡å¼</translation>
<translation id="2721148159707890343">è¦æ±‚æˆåŠŸ</translation>
<translation id="2723669454293168317">在 Chrome 設定中執行安全檢查</translation>
<translation id="2726001110728089263">å´åŒ£</translation>
@@ -583,6 +613,7 @@
<translation id="2850739647070081192">Invite (ä¿¡å°)</translation>
<translation id="2856444702002559011">攻擊者å¯èƒ½æœƒè©¦åœ–é€éŽ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ç«Šå–您的資料 (例如密碼ã€è¨Šæ¯æˆ–信用å¡è³‡æ–™)。<ph name="BEGIN_LEARN_MORE_LINK" />瞭解詳情<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">此網站顯示滋擾性或誤導廣告。</translation>
+<translation id="286512204874376891">虛擬å¡æœƒéš±è—您的實體å¡ï¼Œä¿è­·æ‚¨å…å—潛在欺è©è¡Œç‚ºçš„å¨è„…。<ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">å‹å–„</translation>
<translation id="2876489322757410363">å³å°‡é€€å‡ºç„¡ç—•æ¨¡å¼ï¼Œæ”¹ç”¨å¤–部應用程å¼ä»˜æ¬¾ã€‚è¦ç¹¼çºŒå—Žï¼Ÿ</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />,㩒一下 Tab éµï¼Œç„¶å¾Œã©’一下 Enter éµå°±å¯ä»¥å–º Chrome 設定度管ç†å®‰å…¨ç€è¦½ä¹‹é¡žå˜…功能</translation>
@@ -607,6 +638,7 @@
<translation id="2930577230479659665">完æˆæ¯æ¬¡è¤‡å°å¾Œä¿®å‰ª</translation>
<translation id="2932085390869194046">建議密碼…</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019">開放<ph name="PROTOCOL" />連çµ</translation>
<translation id="2941952326391522266">伺æœå™¨ç„¡æ³•è­‰æ˜Žå…¶å±¬æ–¼ <ph name="DOMAIN" /> 網域;其安全性憑證來自 <ph name="DOMAIN2" /> 網域。這å¯èƒ½æ˜¯å› ç‚ºè¨­å®šéŒ¯èª¤ï¼Œæˆ–有攻擊者攔截您的連線。</translation>
<translation id="2943895734390379394">上載時間:</translation>
<translation id="2948083400971632585">您å¯ä»¥åœ¨è¨­å®šé é¢åœç”¨ä»»ä½•ç‚ºé€£ç·šè¨­å®šçš„ Proxy。</translation>
@@ -639,6 +671,7 @@
<translation id="3037605927509011580">糟糕ï¼</translation>
<translation id="3041612393474885105">憑證資料</translation>
<translation id="3044034790304486808">æ¢å¾©ç ”究</translation>
+<translation id="305162504811187366">Chrome é ç«¯æ¡Œé¢è¨˜éŒ„,包括時間戳記ã€ä¸»æ©Ÿå’Œç”¨æˆ¶ç«¯å·¥ä½œéšŽæ®µ ID</translation>
<translation id="3060227939791841287">C9 (ä¿¡å°)</translation>
<translation id="3061707000357573562">修補æœå‹™</translation>
<translation id="306573536155379004">å•Ÿå‹•å’—éŠæˆ²ã€‚</translation>
@@ -679,6 +712,7 @@
<translation id="3197136577151645743">å¯è¦æ±‚åµæ¸¬æ‚¨ä½¿ç”¨è£ç½®çš„時間</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />,㩒一下 Tab éµï¼Œç„¶å¾Œã©’一下 Enter éµå°±å¯ä»¥å–º Chrome 設定度管ç†åŒæ­¥é‚Šå•²è³‡æ–™</translation>
<translation id="320323717674993345">å–消付款</translation>
+<translation id="3203366800380907218">來自網絡</translation>
<translation id="3207960819495026254">已加入書籤</translation>
<translation id="3209034400446768650">網é å¯èƒ½æœƒæ”¶å–費用</translation>
<translation id="3212581601480735796">您在 <ph name="HOSTNAME" /> 上進行的活動正å—監控</translation>
@@ -695,10 +729,12 @@
<translation id="3234666976984236645">一律在這個網站上åµæ¸¬é‡è¦å…§å®¹</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />,㩒一下 Tab éµï¼Œç„¶å¾Œã©’一下 Enter éµå°±å¯ä»¥è‡ªè¨‚ç€è¦½å™¨å¤–觀</translation>
<translation id="3240791268468473923">開咗冇相符安全付款憑證工作表</translation>
+<translation id="324180406144491771">å·²å°éŽ–「<ph name="HOST_NAME" />ã€é€£çµ</translation>
<translation id="3249845759089040423">åž‹æ ¼</translation>
<translation id="3252266817569339921">法文</translation>
<translation id="3257954757204451555">這項資料是由誰æ供?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />,㩒一下 Tab éµï¼Œç„¶å¾Œã©’一下 Enter éµå°±å¯ä»¥å–º Google 日曆度快速建立新活動</translation>
+<translation id="3261488570342242926">瞭解虛擬å¡</translation>
<translation id="3264837738038045344">ç®¡ç† Chrome 設定按鈕,㩒一下 Enter éµå°±å¯ä»¥å‰å¾€ Chrome 設定</translation>
<translation id="3266793032086590337">值 (è¡çª)</translation>
<translation id="3268451620468152448">開啟的分é </translation>
@@ -712,6 +748,7 @@
<translation id="3288238092761586174"><ph name="URL" /> å¯èƒ½éœ€è¦æŽ¡å–其他步驟,æ‰èƒ½é©—證付款方å¼</translation>
<translation id="3293642807462928945">進一步瞭解 <ph name="POLICY_NAME" /> 政策</translation>
<translation id="3295444047715739395">在 Chrome 設定中查看和管ç†å¯†ç¢¼</translation>
+<translation id="3303795387212510132">è¦å…許應用程å¼é–‹å•Ÿã€Œ<ph name="PROTOCOL_SCHEME" />ã€é€£çµå—Žï¼Ÿ</translation>
<translation id="3303855915957856445">找ä¸åˆ°ä»»ä½•æœå°‹çµæžœ</translation>
<translation id="3304073249511302126">è—牙掃瞄</translation>
<translation id="3308006649705061278">æ©Ÿæ§‹å–®ä½ (OU)</translation>
@@ -725,12 +762,6 @@
<translation id="3345782426586609320">眼</translation>
<translation id="3355823806454867987">變更 Proxy 設定…</translation>
<translation id="3360103848165129075">付款處ç†å¸¸å¼å·¥ä½œè¡¨</translation>
-<translation id="3361596688432910856">Chrome <ph name="BEGIN_EMPHASIS" />ä¸æœƒå„²å­˜<ph name="END_EMPHASIS" />以下資料:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />您的ç€è¦½è¨˜éŒ„
- <ph name="LIST_ITEM" />Cookie 和網站資料
- <ph name="LIST_ITEM" />在表格中輸入的資料
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">此政策是從已淘汰的 <ph name="OLD_POLICY" /> 政策自動複製而來,請改用此政策。</translation>
<translation id="3364869320075768271"><ph name="URL" /> è¦æ±‚使用您的虛擬實境è£ç½®å’Œè³‡æ–™</translation>
<translation id="3366477098757335611">查看付款å¡</translation>
@@ -812,7 +843,6 @@
<translation id="3587738293690942763">中間</translation>
<translation id="3592413004129370115">Italian (ä¿¡å°)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{您å¯éš¨æ™‚é‡è¨­ç¾¤çµ„。加入新群組約需時 1 天。}=1{您å¯éš¨æ™‚é‡è¨­ç¾¤çµ„。加入新群組約需時 1 天。}other{您å¯éš¨æ™‚é‡è¨­ç¾¤çµ„。加入新群組約需時 {NUM_DAYS} 天。}}</translation>
-<translation id="3596012367874587041">應用程å¼è¨­å®š</translation>
<translation id="3600246354004376029"><ph name="TITLE" />,<ph name="DOMAIN" />,<ph name="TIME" /></translation>
<translation id="3603507503523709">您的管ç†å“¡å·²å°éŽ–應用程å¼</translation>
<translation id="3608932978122581043">é€ç´™æ–¹å‘</translation>
@@ -855,6 +885,7 @@
<translation id="370972442370243704">é–‹å•Ÿç€è¦½éŽç¨‹</translation>
<translation id="3711895659073496551">æš«åœ</translation>
<translation id="3712624925041724820">授權已用盡</translation>
+<translation id="3714633008798122362">網絡日曆</translation>
<translation id="3714780639079136834">é–‹å•Ÿæµå‹•æ•¸æ“šæˆ– Wi-Fi</translation>
<translation id="3715597595485130451">連線至 Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />檢查 Proxyã€é˜²ç«ç‰†å’Œ DNS 設定<ph name="END_LINK" /></translation>
@@ -916,6 +947,7 @@
<translation id="3906954721959377182">å¹³æ¿é›»è…¦</translation>
<translation id="3909477809443608991"><ph name="URL" /> 想播放å—ä¿è­·çš„內容。Google 會驗證您的è£ç½®èº«åˆ†ï¼Œæ­¤ç¶²ç«™å¯èƒ½ä¹Ÿæœƒå­˜å–您的è£ç½®èº«åˆ†ã€‚</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">拒絕</translation>
<translation id="3939773374150895049">è¦ä½¿ç”¨ WebAuthn å–代 CVC 嗎?</translation>
<translation id="3946209740501886391">在此網站上一律詢å•</translation>
<translation id="3947595700203588284">å¯è¦æ±‚連接 MIDI è£ç½®</translation>
@@ -936,6 +968,7 @@
<translation id="3987940399970879459">å°æ–¼ 1 MB</translation>
<translation id="3990250421422698716">æ’žé å移</translation>
<translation id="3996311196211510766">網站 <ph name="ORIGIN" /> 指定所有收到的è¦æ±‚都必須套用來æºæ”¿ç­–,但目å‰ç„¡æ³•å¥—用此政策。</translation>
+<translation id="4009243425692662128">您列å°çš„é é¢å…§å®¹æœƒå‚³é€è‡³ Google Cloud 或第三方進行分æžã€‚例如,Google Cloud 或第三方å¯èƒ½æœƒæŽƒçž„文字,檢查是å¦å«æœ‰æ•æ„Ÿè³‡æ–™ã€‚</translation>
<translation id="4010758435855888356">è¦æŽˆäºˆå„²å­˜ç©ºé–“å­˜å–權嗎?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{PDF 文件入é¢æœ‰ {COUNT} é }other{PDF 文件入é¢æœ‰ {COUNT} é }}</translation>
<translation id="4023431997072828269">由於此表格é€éŽä¸å®‰å…¨çš„連線æ交,其他人將å¯çœ‹åˆ°æ‚¨çš„資料。</translation>
@@ -1026,6 +1059,7 @@
<translation id="4250680216510889253">å¦</translation>
<translation id="4253168017788158739">注æ„事項</translation>
<translation id="425582637250725228">系統å¯èƒ½ä¸æœƒå„²å­˜æ‚¨çš„變更。</translation>
+<translation id="425869179292622354">è¦é€éŽè™›æ“¬å¡ä¾†æå‡å¡çš„安全性嗎?</translation>
<translation id="4258748452823770588">ç°½å有誤</translation>
<translation id="4261046003697461417">無法為å—ä¿è­·çš„文件加入註釋</translation>
<translation id="4265872034478892965">根據管ç†å“¡çš„設定å…許</translation>
@@ -1088,6 +1122,7 @@
<translation id="4434045419905280838">彈出å¼è¦–窗和é‡æ–°å°Žå‘</translation>
<translation id="4435702339979719576">明信片</translation>
<translation id="443673843213245140">雖然已åœç”¨ Proxy,ä¸éŽå·²æ˜Žç¢ºæŒ‡å®šäº† Proxy 設定。</translation>
+<translation id="4441832193888514600">由於此政策åªèƒ½è¨­å®šç‚ºé›²ç«¯ä½¿ç”¨è€…政策,因此系統已忽略。</translation>
<translation id="4450893287417543264">ä¸è¦å†é¡¯ç¤º</translation>
<translation id="4451135742916150903">å¯è¦æ±‚連接 HID è£ç½®</translation>
<translation id="4452328064229197696">系統發ç¾æ‚¨å‰›æ‰ä½¿ç”¨çš„密碼因資料外洩而被洩露。為確ä¿å¸³æˆ¶å®‰å…¨ï¼ŒGoogle 密碼管ç†å·¥å…·å»ºè­°æ‚¨æª¢æŸ¥å·²å„²å­˜çš„密碼。</translation>
@@ -1143,6 +1178,7 @@
<translation id="4628948037717959914">相片</translation>
<translation id="4631649115723685955">已連çµç¾é‡‘回贈</translation>
<translation id="4636930964841734540">資訊</translation>
+<translation id="4638670630777875591">Chromium 無痕模å¼</translation>
<translation id="464342062220857295">æœå°‹åŠŸèƒ½</translation>
<translation id="4644670975240021822">相åé †åº (æ­£é¢æœä¸‹)</translation>
<translation id="4646534391647090355">ç«‹å³å‰å¾€ä¸‹è¼‰ä¸­å¿ƒ</translation>
@@ -1163,6 +1199,7 @@
<translation id="4708268264240856090">您的連線已中斷</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />執行 Windows 網絡診斷<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426"><ph name="USERNAME" />的密碼</translation>
<translation id="4724144314178270921">å¯è¦æ±‚查看剪貼簿上的文字和圖片</translation>
<translation id="4726672564094551039">é‡æ–°è¼‰å…¥æ”¿ç­–</translation>
<translation id="4728558894243024398">å¹³å°</translation>
@@ -1184,6 +1221,7 @@
<translation id="4757993714154412917">您剛æ‰åœ¨æ¬ºè©ç¶²ç«™ä¸Šè¼¸å…¥äº†å¯†ç¢¼ã€‚為確ä¿å¸³æˆ¶å®‰å…¨ï¼ŒChromium 建議您檢查已儲存的密碼。</translation>
<translation id="4758311279753947758">新增è¯çµ¡äººè³‡è¨Š</translation>
<translation id="4761104368405085019">使用您的麥克風</translation>
+<translation id="4761869838909035636">執行 Chrome 安全檢查</translation>
<translation id="4764776831041365478"><ph name="URL" /> 的網é å¯èƒ½æš«æ™‚無法使用或被永久移至新網å€ã€‚</translation>
<translation id="4766713847338118463">雙釘 (底部)</translation>
<translation id="4771973620359291008">發生ä¸æ˜Žçš„錯誤。</translation>
@@ -1204,12 +1242,6 @@
<translation id="4819347708020428563">è¦åœ¨é è¨­æª¢è¦–模å¼ä¸­ç·¨è¼¯è¨»è§£å—Žï¼Ÿ</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />,㩒一下 Tab éµï¼Œç„¶å¾Œã©’一下 Enter éµå°±å¯ä»¥å¿«é€Ÿå»ºç«‹æ–°å˜… Google 試算表</translation>
<translation id="4825507807291741242">強大</translation>
-<translation id="4827402517081186284">無痕模å¼ä¸æœƒä»¤æ‚¨åœ¨ç¶²çµ¡ä¸Šéš±èº«ï¼š
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />網站會知é“您在ç€è¦½<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />僱主或學校å¯ä»¥è¿½è¹¤ç€è¦½æ´»å‹•<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />互è¯ç¶²æœå‹™ä¾›æ‡‰å•†å¯èƒ½æœƒç›£å¯Ÿç¶²çµ¡æµé‡<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">開啟警告</translation>
<translation id="4838327282952368871">夢幻</translation>
<translation id="4840250757394056958">查看 Chrome 記錄</translation>
@@ -1221,12 +1253,12 @@
<translation id="4854362297993841467">ä¸æ”¯æ´æ­¤é€è²¨æ–¹å¼ï¼Œè«‹é¸æ“‡å…¶ä»–æ–¹å¼ã€‚</translation>
<translation id="4854853140771946034">在 Google Keep 中快速建立新筆記</translation>
<translation id="485902285759009870">正在確èªé©—證碼…</translation>
+<translation id="4866506163384898554">按下 |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| å³å¯é¡¯ç¤ºæ¸¸æ¨™</translation>
<translation id="4876188919622883022">簡化檢視</translation>
<translation id="4876305945144899064">沒有使用者å稱</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{ç„¡}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />ã€<ph name="EXAMPLE_DOMAIN_2" />}other{<ph name="EXAMPLE_DOMAIN_1" />ã€<ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831">æµã€Œ<ph name="TEXT" />ã€</translation>
<translation id="4879491255372875719">自動 (é è¨­)</translation>
-<translation id="4879725228911483934">在您的螢幕上開啟並放置視窗</translation>
<translation id="4880827082731008257">æœå°‹è¨˜éŒ„</translation>
<translation id="4881695831933465202">é–‹å•Ÿ</translation>
<translation id="4885256590493466218">使用 <ph name="CARD_DETAIL" /> çµå¸³ä»˜æ¬¾</translation>
@@ -1235,6 +1267,7 @@
<translation id="4895877746940133817"><ph name="TYPE_1" />ã€<ph name="TYPE_2" />,<ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">第ä¹å·</translation>
<translation id="4901778704868714008">儲存…</translation>
+<translation id="4905659621780993806">管ç†å“¡å°‡æ–¼ <ph name="DATE" /><ph name="TIME" /> 自動é‡æ–°å•Ÿå‹•æ‚¨çš„è£ç½®ã€‚請在è£ç½®é‡æ–°å•Ÿå‹•å‰å„²å­˜ä»»ä½•é–‹å•Ÿçš„項目。</translation>
<translation id="4913987521957242411">打孔 (左上方)</translation>
<translation id="4918221908152712722">安è£ã€Œ<ph name="APP_NAME" />ã€(無需下載)</translation>
<translation id="4923459931733593730">付款</translation>
@@ -1243,6 +1276,7 @@
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />,㩒一下 Tab éµï¼Œç„¶å¾Œã©’一下 Enter éµå°±å¯ä»¥æµ</translation>
<translation id="4930153903256238152">大容é‡</translation>
+<translation id="4940163644868678279">Chrome 無痕模å¼</translation>
<translation id="4943872375798546930">沒有çµæžœ</translation>
<translation id="4950898438188848926">分é åˆ‡æ›æŒ‰éˆ•ï¼Œã©’一下 Enter éµå°±å¯ä»¥è½‰åŽ»é–‹ä»¥ä¸‹å˜…分é ï¼š<ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="495170559598752135">動作</translation>
@@ -1252,6 +1286,7 @@
<translation id="4968522289500246572">此應用程å¼å°ˆç‚ºæµå‹•è£ç½®è€Œè¨­ï¼Œå¯èƒ½ç„¡æ³•æ­£å¸¸èª¿æ•´å¤§å°ã€‚應用程å¼å¯èƒ½æœƒç™¼ç”Ÿå•é¡Œæˆ–é‡æ–°å•Ÿå‹•ã€‚</translation>
<translation id="4969341057194253438">刪除錄影</translation>
<translation id="4973922308112707173">雙孔 (頂端)</translation>
+<translation id="4976702386844183910">上次ç€è¦½æ—¥æœŸï¼š<ph name="DATE" /></translation>
<translation id="4984088539114770594">è¦ä½¿ç”¨éº¥å…‹é¢¨å—Žï¼Ÿ</translation>
<translation id="4984339528288761049">Prc5 (ä¿¡å°)</translation>
<translation id="4989163558385430922">查看全部</translation>
@@ -1313,6 +1348,7 @@
<translation id="5138227688689900538">顯示較少</translation>
<translation id="5145883236150621069">政策回應中存在錯誤代碼</translation>
<translation id="5146995429444047494">å·²å°éŽ– <ph name="ORIGIN" /> 的通知</translation>
+<translation id="514704532284964975"><ph name="URL" /> 希望查看和變更您é€éŽæ‰‹æ©Ÿåœ¨ NFC è£ç½®ä¸Šè¼•æŒ‰çš„資料</translation>
<translation id="5148809049217731050">æ­£é¢æœä¸Š</translation>
<translation id="515292512908731282">C4 (ä¿¡å°)</translation>
<translation id="5158275234811857234">å°é¢</translation>
@@ -1337,6 +1373,7 @@
<translation id="5215116848420601511">使用 Google Pay 儲存的付款方法和地å€</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">紙匣 13</translation>
+<translation id="5216942107514965959">上次ç€è¦½æ™‚間:今天</translation>
<translation id="5222812217790122047">需è¦æ供電郵</translation>
<translation id="5230733896359313003">付é‹åœ°å€</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1357,7 +1394,6 @@
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">文件屬性</translation>
<translation id="528468243742722775">çµæŸ</translation>
-<translation id="5284909709419567258">網絡ä½å€</translation>
<translation id="5285570108065881030">顯示所有已儲存的密碼…</translation>
<translation id="5287240709317226393">顯示 Cookie</translation>
<translation id="5287456746628258573">此網站的安全性設定éŽèˆŠï¼Œå› æ­¤æ‚¨å‚³é€çµ¦æ­¤ç¶²ç«™çš„資料 (例如密碼或信用å¡è™Ÿç¢¼) å¯èƒ½æœƒå¤–洩。</translation>
@@ -1441,6 +1477,7 @@
<translation id="5556459405103347317">é‡æ–°è¼‰å…¥</translation>
<translation id="5560088892362098740">到期日</translation>
<translation id="55635442646131152">文件大綱</translation>
+<translation id="5565613213060953222">é–‹å•Ÿç„¡ç—•å¼åˆ†é </translation>
<translation id="5565735124758917034">啟用</translation>
<translation id="5570825185877910964">ä¿è­·å¸³æˆ¶</translation>
<translation id="5571083550517324815">無法在此地å€å–貨,請é¸å–其他地å€ã€‚</translation>
@@ -1523,6 +1560,7 @@
<translation id="5869522115854928033">已儲存的密碼</translation>
<translation id="5873013647450402046">銀行è¦ç¢ºèªæ‚¨çš„身分。</translation>
<translation id="5887400589839399685">已儲存的付款å¡</translation>
+<translation id="5887687176710214216">上次ç€è¦½æ—¥æœŸï¼šæ˜¨å¤©</translation>
<translation id="5895138241574237353">é‡æ–°å•Ÿå‹•</translation>
<translation id="5895187275912066135">發行日期</translation>
<translation id="5901630391730855834">黃色</translation>
@@ -1536,6 +1574,7 @@
<translation id="5921639886840618607">è¦å°‡ä»˜æ¬¾å¡å„²å­˜è‡³ Google 帳戶嗎?</translation>
<translation id="5922853866070715753">快將完æˆ</translation>
<translation id="5932224571077948991">網站顯示滋擾性或誤導廣告</translation>
+<translation id="5938153366081463283">新增虛擬å¡</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347">正在開啟 <ph name="SITE_NAME" />…</translation>
<translation id="5951495562196540101">無法使用消費者帳戶註冊 (有å¯ç”¨å¥—è£æŽˆæ¬Š)。</translation>
@@ -1600,6 +1639,7 @@
<translation id="6120179357481664955">è¦è¨˜ä½æ‚¨çš„ UPI ID 嗎?</translation>
<translation id="6124432979022149706">Chrome Enterprise Connectors</translation>
<translation id="6127379762771434464">項目已移除</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />進一步瞭解 Chrome 無痕模å¼<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">檢查連接線,或é‡æ–°å•Ÿå‹•è·¯ç”±å™¨ã€æ•¸æ“šæ©Ÿæˆ–其他使用中的
網絡è£ç½®ã€‚</translation>
<translation id="614940544461990577">建議åšæ³•ï¼š</translation>
@@ -1612,7 +1652,6 @@
<translation id="6169916984152623906">ç¾åœ¨æ‚¨å¯ç§ä¸‹ç€è¦½äº†ã€‚共用此è£ç½®çš„其他使用者將無法看到您的活動,但您下載的檔案和加入的書籤ä»æœƒå„²å­˜åœ¨è£ç½®ä¸Šã€‚</translation>
<translation id="6177128806592000436">您與此網站的連線並éžå®Œå…¨å®‰å…¨</translation>
<translation id="6180316780098470077">é‡è©¦é–“éš”</translation>
-<translation id="619448280891863779">å¯è¦æ±‚在您的畫é¢ä¸­é–‹å•Ÿå’Œæ”¾ç½®è¦–窗</translation>
<translation id="6196640612572343990">å°éŽ–第三方 Cookie</translation>
<translation id="6203231073485539293">檢查互è¯ç¶²é€£ç·š</translation>
<translation id="6218753634732582820">è¦å¾ž Chromium 移除地å€å—Žï¼Ÿ</translation>
@@ -1635,7 +1674,7 @@
<translation id="6272383483618007430">Google æ›´æ–°</translation>
<translation id="6276112860590028508">您的閱讀清單中的網é å°‡æœƒåœ¨é€™è£¡é¡¯ç¤º</translation>
<translation id="627746635834430766">åªè¦å°‡æ­¤ä»˜æ¬¾å¡å’Œå¸³å–®åœ°å€å„²å­˜è‡³æ‚¨çš„ Google 帳戶,下次å³å¯æ›´å¿«å®Œæˆä»˜æ¬¾ç¨‹åºã€‚</translation>
-<translation id="6279098320682980337">未填寫虛擬å¡è™Ÿå—Žï¼ŸæŒ‰ä¸€ä¸‹ä¿¡ç”¨å¡è©³æƒ…å³å¯è¤‡è£½</translation>
+<translation id="6279183038361895380">按下 |<ph name="ACCELERATOR" />| å³å¯é¡¯ç¤ºæ¸¸æ¨™</translation>
<translation id="6280223929691119688">無法é€è²¨è‡³æ­¤åœ°å€ï¼Œè«‹é¸å–其他地å€ã€‚</translation>
<translation id="6282194474023008486">郵éžå€è™Ÿ</translation>
<translation id="6285507000506177184">ç®¡ç† Chrome 嘅下載項目按鈕,㩒一下 Enter éµå°±å¯ä»¥ç®¡ç†æ‚¨å–º Chrome 度下載嘅檔案</translation>
@@ -1643,6 +1682,7 @@
<translation id="6290238015253830360">為您推薦的文章會在這裡顯示</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{è£ç½®æœƒç«‹å³é‡æ–°å•Ÿå‹•}=1{è£ç½®å°‡æ–¼ 1 秒後é‡æ–°å•Ÿå‹•}other{è£ç½®å°‡æ–¼ # 秒後é‡æ–°å•Ÿå‹•}}</translation>
<translation id="6302269476990306341">正在åœæ­¢ Chrome 的「Google 助ç†ã€</translation>
<translation id="6305205051461490394">ç„¡æ³•å­˜å– <ph name="URL" />。</translation>
<translation id="6312113039770857350">網é ç„¡æ³•ä½¿ç”¨</translation>
@@ -1716,6 +1756,7 @@
<translation id="6529602333819889595">é‡åšåˆªé™¤(&amp;R)</translation>
<translation id="6545864417968258051">è—牙掃瞄</translation>
<translation id="6547208576736763147">雙孔 (å·¦å´)</translation>
+<translation id="6554732001434021288">上次ç€è¦½æ—¥æœŸï¼š<ph name="NUM_DAYS" /> 天å‰</translation>
<translation id="6556866813142980365">é‡åš</translation>
<translation id="6569060085658103619">您正在查看擴充程å¼é é¢</translation>
<translation id="6573200754375280815">雙孔 (å³å´)</translation>
@@ -1776,7 +1817,6 @@
<translation id="6757797048963528358">您的è£ç½®å·²é€²å…¥ä¼‘眠狀態。</translation>
<translation id="6767985426384634228">è¦æ›´æ–°åœ°å€å—Žï¼Ÿ</translation>
<translation id="6768213884286397650">Hagaki (明信片)</translation>
-<translation id="6774185088257932239"><ph name="BEGIN_LINK" />進一步瞭解<ph name="END_LINK" />「無痕模å¼ã€</translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">紫羅蘭色</translation>
<translation id="6786747875388722282">擴充功能</translation>
@@ -1860,7 +1900,6 @@
<translation id="706295145388601875">在 Chrome 設定中新增並管ç†åœ°å€</translation>
<translation id="7064851114919012435">è¯çµ¡äººè³‡è¨Š</translation>
<translation id="7068733155164172741">請輸入 <ph name="OTP_LENGTH" /> ä½æ•¸é©—證碼</translation>
-<translation id="7070090581017165256">關於此網站</translation>
<translation id="70705239631109039">您的連線並éžå®Œå…¨å®‰å…¨</translation>
<translation id="7075452647191940183">è¦æ±‚éŽå¤§</translation>
<translation id="7079718277001814089">此網站å«æœ‰æƒ¡æ„軟件</translation>
@@ -1877,6 +1916,12 @@
<translation id="7111012039238467737">(有效)</translation>
<translation id="7118618213916969306">æµå‰ªè²¼ç°¿ç¶²å€ <ph name="SHORT_URL" /></translation>
<translation id="7119414471315195487">關閉其他分é æˆ–程å¼</translation>
+<translation id="7129355289156517987">關閉所有 Chromium ç„¡ç—•å¼åˆ†é å¾Œï¼Œç³»çµ±æœƒå¾žæ­¤è£ç½®ä¸Šæ¸…除您在這些分é ä¸Šçš„活動記錄:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ç€è¦½æ´»å‹•<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />æœå°‹è¨˜éŒ„<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />在表格中輸入的資料<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">無法é‹é€è‡³æ­¤åœ°å€ï¼Œè«‹é¸å–其他地å€ã€‚</translation>
<translation id="7132939140423847331">管ç†å“¡å·²ç¦æ­¢è¤‡è£½æ­¤è³‡æ–™ã€‚</translation>
<translation id="7135130955892390533">顯示狀態</translation>
@@ -1899,6 +1944,7 @@
<translation id="7192203810768312527">釋出 <ph name="SIZE" />。在您下次ç€è¦½éƒ¨åˆ†ç¶²ç«™æ™‚,載入速度å¯èƒ½æœƒè®Šæ…¢ã€‚</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">您的管ç†å“¡å¯ä»¥æŸ¥çœ‹ä»¥ä¸‹é …目:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />,㩒一下 Tab éµï¼Œç„¶å¾Œã©’一下 Enter éµå°±å¯ä»¥é–‹æ–°å˜…ç„¡ç—•å¼åˆ†é ç§ä¸‹ç€è¦½</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> 沒有ä¾å¾ªå®‰å…¨æ¨™æº–。</translation>
<translation id="7210993021468939304">å¯æŸ¥çœ‹å®¹å™¨ä¸­çš„ Linux 活動,並å¯åœ¨å®¹å™¨å…§å®‰è£åŠåŸ·è¡Œ Linux 應用程å¼</translation>
@@ -1930,6 +1976,7 @@
<translation id="7304562222803846232">ç®¡ç† Google 帳戶ç§éš±è¨­å®š</translation>
<translation id="7305756307268530424">啟用慢速模å¼</translation>
<translation id="7308436126008021607">背景åŒæ­¥è™•ç†</translation>
+<translation id="7310392214323165548">è£ç½®å³å°‡é‡æ–°å•Ÿå‹•</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">連線說明</translation>
<translation id="7323804146520582233">éš±è—「<ph name="SECTION" />ã€éƒ¨åˆ†</translation>
@@ -1937,6 +1984,7 @@
<translation id="7334320624316649418">é‡åšé‡æ–°æŽ’åº(&amp;R)</translation>
<translation id="7335157162773372339">å¯è¦æ±‚使用æ”錄機</translation>
<translation id="7337248890521463931">顯示更多行</translation>
+<translation id="7337418456231055214">未填寫虛擬å¡è™Ÿå—Žï¼ŸæŒ‰ä¸€ä¸‹è™›æ“¬å¡è©³æƒ…å³å¯è¤‡è£½ã€‚<ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">無法在您的平å°ä¸Šä½¿ç”¨ã€‚</translation>
<translation id="733923710415886693">伺æœå™¨æ†‘證並未é€éŽæ†‘è­‰é€æ˜Žåº¦æ”¿ç­–披露。</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1959,6 +2007,7 @@
<translation id="7378627244592794276">ä¸éœ€è¦</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">ä¸é©ç”¨</translation>
+<translation id="7388594495505979117">{0,plural, =1{è£ç½®å°‡æ–¼ 1 分é˜å¾Œé‡æ–°å•Ÿå‹•}other{è£ç½®å°‡æ–¼ # 分é˜å¾Œé‡æ–°å•Ÿå‹•}}</translation>
<translation id="7390545607259442187">驗證信用å¡</translation>
<translation id="7392089738299859607">更新地å€</translation>
<translation id="7399802613464275309">安全檢查</translation>
@@ -1995,6 +2044,12 @@
<translation id="7485870689360869515">找ä¸åˆ°ä»»ä½•æ•¸æ“šã€‚</translation>
<translation id="7495528107193238112">此內容已被å°éŽ–。如è¦ä¿®æ­£å•é¡Œï¼Œè«‹è¯çµ¡ç¶²ç«™æ“有者。</translation>
<translation id="7497998058912824456">建立文件掣,㩒一下 Enter éµå°±å¯ä»¥å¿«é€Ÿå»ºç«‹æ–°å˜… Google 文件</translation>
+<translation id="7506488012654002225">Chromium <ph name="BEGIN_EMPHASIS" />ä¸æœƒå„²å­˜<ph name="END_EMPHASIS" />以下資料:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />您的ç€è¦½è¨˜éŒ„
+ <ph name="LIST_ITEM" />Cookie 和網站資料
+ <ph name="LIST_ITEM" />在表格中輸入的資料
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">傳回的政策è£ç½®è­˜åˆ¥ç¢¼ç‚ºç©ºç™½æˆ–與目å‰è£ç½®è­˜åˆ¥ç¢¼ä¸ç¬¦</translation>
<translation id="7508870219247277067">牛油果色</translation>
<translation id="7511955381719512146">ç›®å‰ä½¿ç”¨çš„ Wi-Fi å¯èƒ½è¦æ±‚您å‰å¾€ <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />。</translation>
@@ -2108,7 +2163,6 @@
<translation id="7813600968533626083">è¦å¾ž Chrome 中移除表格建議嗎?</translation>
<translation id="781440967107097262">è¦åˆ†äº«å‰ªè²¼ç°¿å—Žï¼Ÿ</translation>
<translation id="7815407501681723534">找到 <ph name="NUMBER_OF_RESULTS" /> 個與「<ph name="SEARCH_STRING" />ã€ç›¸ç¬¦çš„<ph name="SEARCH_RESULTS" /></translation>
-<translation id="782125616001965242">顯示關於此網站的資料</translation>
<translation id="782886543891417279">ç›®å‰ä½¿ç”¨çš„ Wi-Fi (<ph name="WIFI_NAME" />) å¯èƒ½è¦æ±‚您å‰å¾€å…¶ç™»å…¥é é¢ã€‚</translation>
<translation id="7836231406687464395">Postfix (ä¿¡å°)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{ç„¡}=1{1 å€‹æ‡‰ç”¨ç¨‹å¼ (<ph name="EXAMPLE_APP_1" />)}=2{2 å€‹æ‡‰ç”¨ç¨‹å¼ (<ph name="EXAMPLE_APP_1" />ã€<ph name="EXAMPLE_APP_2" />)}other{# å€‹æ‡‰ç”¨ç¨‹å¼ (<ph name="EXAMPLE_APP_1" />ã€<ph name="EXAMPLE_APP_2" />ã€<ph name="AND_MORE" />)}}</translation>
@@ -2125,7 +2179,6 @@
<translation id="7888575728750733395">列å°è¼¸å‡ºæ„圖</translation>
<translation id="7894280532028510793">如果拼字正確,<ph name="BEGIN_LINK" />請嘗試執行網絡診斷<ph name="END_LINK" />。</translation>
<translation id="7904208859782148177">C3 (ä¿¡å°)</translation>
-<translation id="7931318309563332511">ä¸æ˜Ž</translation>
<translation id="793209273132572360">è¦æ›´æ–°åœ°å€å—Žï¼Ÿ</translation>
<translation id="7932579305932748336">塗布</translation>
<translation id="79338296614623784">請輸入有效的電話號碼</translation>
@@ -2150,13 +2203,14 @@
<translation id="7976214039405368314">è¦æ±‚數é‡éŽå¤š</translation>
<translation id="7977538094055660992">輸出è£ç½®</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">已連çµ</translation>
<translation id="798134797138789862">å¯è¦æ±‚使用虛擬實境è£ç½®å’Œè³‡æ–™</translation>
<translation id="7984945080620862648">您目å‰ç„¡æ³•ç€è¦½ <ph name="SITE" />,因為這個網站傳é€çš„憑證經éŽç·¨ç¢¼ï¼Œå°Žè‡´ Chrome 無法處ç†ã€‚網絡錯誤和攻擊行為通常是暫時性的,所以這個網é å¯èƒ½ç¨å¾Œå°±èƒ½æ­£å¸¸ä½¿ç”¨ã€‚</translation>
-<translation id="79859296434321399">如è¦è§€çœ‹æ“´å¼µå¯¦å¢ƒå…§å®¹ï¼Œè«‹å…ˆå®‰è£ ARCore</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">釘è£</translation>
<translation id="7992044431894087211">已繼續與「<ph name="APPLICATION_TITLE" />ã€åˆ†äº«èž¢å¹•ç•«é¢çš„功能</translation>
<translation id="7995512525968007366">未指定 </translation>
+<translation id="7998269595945679889">é–‹å•Ÿç„¡ç—•å¼åˆ†é æŒ‰éˆ•ï¼Œã©’一下 Enter éµå°±å¯ä»¥é–‹æ–°å˜…ç„¡ç—•å¼åˆ†é ç§ä¸‹ç€è¦½</translation>
<translation id="800218591365569300">嘗試關閉其他分é æˆ–應用程å¼ï¼Œä»¥é‡‹å‡ºè¨˜æ†¶é«”。</translation>
<translation id="8004582292198964060">ç€è¦½å™¨</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{系統將會儲存此付款å¡å’Œå¸³å–®åœ°å€ã€‚您登入 <ph name="USER_EMAIL" /> 後便å¯ä»¥ä½¿ç”¨é€™äº›è³‡æ–™ã€‚}other{系統將會儲存這些付款å¡å’Œå¸³å–®åœ°å€ã€‚您登入 <ph name="USER_EMAIL" /> 後便å¯ä»¥ä½¿ç”¨é€™äº›è³‡æ–™ã€‚}}</translation>
@@ -2216,6 +2270,7 @@
<translation id="8202370299023114387">è¡çª</translation>
<translation id="8206978196348664717">Prc4 (ä¿¡å°)</translation>
<translation id="8211406090763984747">己建立安全連線</translation>
+<translation id="8217240300496046857">網站ä¸èƒ½ä½¿ç”¨ Cookie 追蹤您的網絡活動。有些網站的功能å¯èƒ½ç„¡æ³•æ­£å¸¸é‹ä½œã€‚</translation>
<translation id="8218327578424803826">已指派的ä½ç½®ï¼š</translation>
<translation id="8220146938470311105">C7/C6 (ä¿¡å°)</translation>
<translation id="8225771182978767009">設定此電腦的用戶已å°éŽ–此網站。</translation>
@@ -2256,14 +2311,9 @@
<translation id="830498451218851433">å°æ‘º</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">已安è£çš„應用程å¼åŠä½¿ç”¨é »çŽ‡</translation>
+<translation id="8317207217658302555">è¦æ›´æ–° ARCore 嗎?</translation>
<translation id="831997045666694187">å‚晚</translation>
<translation id="8321476692217554900">通知</translation>
-<translation id="8328484624016508118">關閉所有無痕å¼åˆ†é å¾Œï¼ŒChrome 就會清除以下資料:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />您的ç€è¦½æ´»å‹•<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />您的æœå°‹è¨˜éŒ„<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />您在表格中輸入的資料<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489"><ph name="HOST_NAME" /> çš„å­˜å–被拒</translation>
<translation id="833262891116910667">çªé¡¯å˜…內容</translation>
<translation id="8339163506404995330">系統將ä¸æœƒè‡ªå‹•ç¿»è­¯ä¾†æºèªžè¨€ç‚º<ph name="LANGUAGE" />的網é </translation>
@@ -2315,6 +2365,7 @@
<translation id="8507227106804027148">指令列</translation>
<translation id="8508648098325802031">æœå°‹åœ–示</translation>
<translation id="8511402995811232419">ç®¡ç† Cookie</translation>
+<translation id="8519753333133776369">管ç†å“¡å…許使用的 HID è£ç½®</translation>
<translation id="8522552481199248698">Chrome å¯åŠ©æ‚¨ä¿è­· Google 帳戶並變更密碼。</translation>
<translation id="8530813470445476232">清除您的ç€è¦½è¨˜éŒ„ã€Cookieã€å¿«å–以åŠå…¶ä»– Chrome 設定</translation>
<translation id="8533619373899488139">è«‹å‰å¾€ &lt;strong&gt;chrome://policy&lt;/strong&gt; 查看被å°éŽ–的網å€æ¸…單,以åŠç”±ç³»çµ±ç®¡ç†å“¡å¼·åˆ¶åŸ·è¡Œçš„其他政策。</translation>
@@ -2326,7 +2377,6 @@
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{é‡è¨­æ¬Šé™}other{é‡è¨­æ¬Šé™}}</translation>
<translation id="8555010941760982128">çµå¸³æ™‚請使用此宣傳代碼</translation>
<translation id="8557066899867184262">信用å¡é©—證碼 (CVC) ä½æ–¼ä¿¡ç”¨å¡èƒŒé¢ã€‚</translation>
-<translation id="8558485628462305855">如è¦è§€çœ‹æ“´å¼µå¯¦å¢ƒå…§å®¹ï¼Œè«‹å…ˆæ›´æ–° ARCore</translation>
<translation id="8559762987265718583">您è£ç½®çš„日期和時間 (<ph name="DATE_AND_TIME" />) ä¸æ­£ç¢ºï¼Œå› æ­¤ç„¡æ³•å»ºç«‹ç§äººé€£ç·šè‡³ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" />。</translation>
<translation id="8564182942834072828">個別文件/未自動分é çš„副本</translation>
<translation id="8564985650692024650">如果您已在其他網站上é‡ç”¨ <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> 密碼,Chromium 建議您é‡è¨­å¯†ç¢¼ã€‚</translation>
@@ -2345,6 +2395,7 @@
<translation id="865032292777205197">動作感應器</translation>
<translation id="8663226718884576429">訂單摘è¦ã€<ph name="TOTAL_LABEL" /> åŠæ›´å¤šè©³æƒ…</translation>
<translation id="8666678546361132282">英文</translation>
+<translation id="8669306706049782872">使用螢幕中的資料開啟åŠæ”¾ç½®è¦–窗</translation>
<translation id="867224526087042813">ç°½å</translation>
<translation id="8676424191133491403">ä¸å»¶é²</translation>
<translation id="8680536109547170164"><ph name="QUERY" />,答案:<ph name="ANSWER" /></translation>
@@ -2371,6 +2422,7 @@
<translation id="8731544501227493793">管ç†å¯†ç¢¼æŒ‰éˆ•ï¼Œã©’一下 Enter éµå°±å¯ä»¥å–º Chrome 設定度ç‡åŒç®¡ç†å¯†ç¢¼</translation>
<translation id="8734529307927223492">您的 <ph name="DEVICE_TYPE" /> ç”± <ph name="MANAGER" /> 管ç†</translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />,㩒一下 Tab éµï¼Œç„¶å¾Œã©’一下 Enter éµå°±å¯ä»¥é–‹æ–°å˜…ç„¡ç—•å¼è¦–窗ç§ä¸‹ç€è¦½</translation>
+<translation id="8737685506611670901">é–‹å•Ÿ<ph name="PROTOCOL" />é€£çµ (è€Œéž <ph name="REPLACED_HANDLER_TITLE" />)</translation>
<translation id="8738058698779197622">如è¦å»ºç«‹å®‰å…¨é€£ç·šï¼Œæ‚¨æ™‚é˜çš„設定必須正確無誤;因為網站用於自我識別的憑證僅在特定時間內有效。由於您è£ç½®çš„時é˜è¨­å®šæœ‰èª¤ï¼ŒChromium 無法驗證這些憑證。</translation>
<translation id="8740359287975076522">找ä¸åˆ° <ph name="HOST_NAME" /> çš„ &lt;abbr id="dnsDefinition"&gt;網域å稱系統 (DNS) 地å€&lt;/abbr&gt;。正在診斷å•é¡Œã€‚</translation>
<translation id="8742371904523228557">您的 <ph name="ORIGIN" /> 驗證碼是 <ph name="ONE_TIME_CODE" /></translation>
@@ -2398,6 +2450,7 @@
<translation id="883848425547221593">其他書籤</translation>
<translation id="884264119367021077">é‹é€åœ°å€</translation>
<translation id="884923133447025588">未發ç¾æ’¤éŠ·æ©Ÿåˆ¶ã€‚</translation>
+<translation id="8849262850971482943">使用虛擬å¡ä»¥æå‡å®‰å…¨æ€§</translation>
<translation id="885730110891505394">與 Google 分享</translation>
<translation id="8858065207712248076">如果您已在其他網站上é‡ç”¨ <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> 密碼,Chrome 建議您é‡è¨­å¯†ç¢¼ã€‚</translation>
<translation id="885906927438988819">如果拼字正確,請<ph name="BEGIN_LINK" />嘗試執行 Windows 網絡診斷<ph name="END_LINK" />。</translation>
@@ -2447,6 +2500,7 @@
<translation id="9004367719664099443">正在執行 VR 工作階段</translation>
<translation id="9005998258318286617">無法載入 PDF 文件。</translation>
<translation id="9008201768610948239">ç•¥éŽ</translation>
+<translation id="901834265349196618">電郵</translation>
<translation id="9020200922353704812">請輸入信用å¡å¸³å–®åœ°å€</translation>
<translation id="9020542370529661692">這個網é å…§å®¹å·²ç¿»è­¯æˆ<ph name="TARGET_LANGUAGE" /></translation>
<translation id="9020742383383852663">A8</translation>
@@ -2495,6 +2549,7 @@
<translation id="9150045010208374699">使用您的相機。</translation>
<translation id="9150685862434908345">您的管ç†å“¡å¯é ç«¯è®Šæ›´ç€è¦½å™¨è¨­å®šã€‚æ­¤è£ç½®ä¸Šçš„活動也å¯é€éŽ Chrome 以外的æœå‹™ç®¡ç†ã€‚<ph name="BEGIN_LINK" />瞭解詳情<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">已更新</translation>
+<translation id="9155211586651734179">已連çµçš„音訊周邊è£ç½®</translation>
<translation id="9157595877708044936">設定中…</translation>
<translation id="9158625974267017556">C6 (ä¿¡å°)</translation>
<translation id="9164029392738894042">精確度檢查</translation>
diff --git a/chromium/components/strings/components_strings_zh-TW.xtb b/chromium/components/strings/components_strings_zh-TW.xtb
index 2fa01116263..d469c1d636a 100644
--- a/chromium/components/strings/components_strings_zh-TW.xtb
+++ b/chromium/components/strings/components_strings_zh-TW.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">查看詳細資料</translation>
<translation id="1030706264415084469"><ph name="URL" /> è¦æ±‚在你的è£ç½®ä¸Šæ°¸ä¹…儲存大é‡è³‡æ–™</translation>
<translation id="1032854598605920125">順時é‡æ—‹è½‰</translation>
+<translation id="1033329911862281889">無痕模å¼ç„¡æ³•è®“你在網路上ä¸ç•™ç—•è·¡ï¼š
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />網站åŠå…¶ä½¿ç”¨çš„æœå‹™å¯ä»¥æŸ¥çœ‹é€ è¨ªè¨˜éŒ„<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />雇主或學校å¯ä»¥è¿½è¹¤ç€è¦½æ´»å‹•<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />網際網路æœå‹™ä¾›æ‡‰å•†å¯ä»¥ç›£æŽ§ç¶²è·¯æµé‡<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">關閉</translation>
<translation id="1036982837258183574">按下 |<ph name="ACCELERATOR" />| å³å¯çµæŸå…¨èž¢å¹•æ¨¡å¼</translation>
<translation id="1038106730571050514">顯示æœå°‹å»ºè­°</translation>
<translation id="1038842779957582377">ä¸æ˜Žå稱</translation>
<translation id="1041998700806130099">工作表訊æ¯</translation>
<translation id="1048785276086539861">這份文件會在你編輯註解時é‡è¨­ç‚ºå–®é æª¢è¦–</translation>
-<translation id="1049743911850919806">無痕模å¼</translation>
<translation id="1050038467049342496">關閉其他應用程å¼</translation>
<translation id="1055184225775184556">復原新增(&amp;U)</translation>
<translation id="1056898198331236512">警告</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">政策快å–正確</translation>
<translation id="1130564665089811311">「翻譯網é ã€æŒ‰éˆ•ï¼ŒæŒ‰ä¸‹ Enter éµå³å¯ä½¿ç”¨ Google 翻譯來翻譯這個網é </translation>
<translation id="1131264053432022307">你複製的圖片</translation>
+<translation id="1142846828089312304">在無痕模å¼ä¸­å°éŽ–第三方 Cookie</translation>
<translation id="1150979032973867961">伺æœå™¨ç„¡æ³•è­‰æ˜Žå…¶å±¬æ–¼ <ph name="DOMAIN" /> 網域;其安全性憑證未å–得你電腦作業系統的信任。這å¯èƒ½æ˜¯å› ç‚ºè¨­å®šéŒ¯èª¤ï¼Œæˆ–有攻擊者攔截你的連線所致。</translation>
<translation id="1151972924205500581">請輸入密碼</translation>
<translation id="1156303062776767266">ç›®å‰æŸ¥çœ‹çš„是本機檔案或共用檔案</translation>
@@ -64,7 +70,6 @@
<translation id="1178581264944972037">æš«åœ</translation>
<translation id="1181037720776840403">移除</translation>
<translation id="1186201132766001848">檢查密碼</translation>
-<translation id="1195210374336998651">å‰å¾€æ‡‰ç”¨ç¨‹å¼è¨­å®š</translation>
<translation id="1195558154361252544">除了你å…許的網站之外,自動å°éŽ–所有網站的通知</translation>
<translation id="1197088940767939838">橘色</translation>
<translation id="1201402288615127009">繼續</translation>
@@ -111,7 +116,7 @@
<translation id="1307966114820526988">已淘汰的功能</translation>
<translation id="1308113895091915999">é©ç”¨å„ªæƒ </translation>
<translation id="1312803275555673949">有何證據å¯è­‰æ˜Žè³‡è¨Šå±¬å¯¦ï¼Ÿ</translation>
-<translation id="131405271941274527"><ph name="URL" /> è¦æ±‚在你將手機貼近 NFC è£ç½®æ™‚傳é€åŠæŽ¥æ”¶è³‡è¨Š</translation>
+<translation id="1314311879718644478">查看擴增實境內容</translation>
<translation id="1314509827145471431">è£è¨‚ (å³å´)</translation>
<translation id="1318023360584041678">已儲存至分é ç¾¤çµ„</translation>
<translation id="1319245136674974084">ä¸è¦å†è©¢å•æ˜¯å¦å…許調整這個應用程å¼çš„大å°</translation>
@@ -161,6 +166,7 @@
<translation id="142858679511221695">Cloud 使用者</translation>
<translation id="1428729058023778569">這個網站ä¸æ”¯æ´ HTTPS,因此ç€è¦½å™¨é¡¯ç¤ºé€™å‰‡è­¦å‘Šè¨Šæ¯ã€‚<ph name="BEGIN_LEARN_MORE_LINK" />瞭解詳情<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">列å°</translation>
+<translation id="1432187715652018471">網é æƒ³è¦å®‰è£æœå‹™è™•ç†å¸¸å¼ã€‚</translation>
<translation id="1432581352905426595">管ç†æœå°‹å¼•æ“Ž</translation>
<translation id="1436185428532214179">å¯ä»¥è¦æ±‚編輯è£ç½®ä¸Šçš„檔案和資料夾</translation>
<translation id="1442386063175183758">å³åŠé‚Šå°æŠ˜</translation>
@@ -181,6 +187,12 @@
<translation id="1483493594462132177">傳é€</translation>
<translation id="1484290072879560759">é¸æ“‡é‹é€åœ°å€</translation>
<translation id="1492194039220927094">政策通知推é€ï¼š</translation>
+<translation id="149293076951187737">關閉所有 Chrome 無痕分é å¾Œï¼Œç³»çµ±æœƒå°‡ä½ åœ¨é€™äº›åˆ†é ä¸Šçš„活動記錄從這部è£ç½®ä¸Šæ¸…除:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ç€è¦½æ´»å‹•<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />æœå°‹è¨˜éŒ„<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />在表單中輸入的資訊<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">返回分é </translation>
<translation id="1501859676467574491">顯示你 Google 帳戶中的å¡ç‰‡</translation>
<translation id="1507202001669085618">&lt;p&gt;如果您使用的 Wi-Fi å…¥å£ç¶²ç«™å¿…須先登入æ‰èƒ½é€£ä¸Šç¶²è·¯ï¼Œç³»çµ±å°±æœƒé¡¯ç¤ºé€™å‰‡éŒ¯èª¤è¨Šæ¯ã€‚&lt;/p&gt;
@@ -208,6 +220,8 @@
<translation id="1559572115229829303">&lt;p&gt;您è£ç½®çš„日期和時間 (<ph name="DATE_AND_TIME" />) ä¸æ­£ç¢ºï¼Œå› æ­¤ç„¡æ³•èˆ‡ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> 建立ç§äººé€£ç·šã€‚&lt;/p&gt;
&lt;p&gt;è«‹å‰å¾€ã€Œè¨­å®šã€æ‡‰ç”¨ç¨‹å¼çš„「一般設定ã€å°ˆå€èª¿æ•´æ—¥æœŸå’Œæ™‚間。&lt;strong&gt;&lt;/strong&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/p&gt;</translation>
+<translation id="1559839503761818503">系統管ç†å“¡å°‡åœ¨ <ph name="DATE" /><ph name="TIME" /> é‡æ–°å•Ÿå‹•ä½ çš„è£ç½®ã€‚</translation>
+<translation id="156703335097561114">包括ä½å€ã€ä»‹é¢è¨­å®šå’Œé€£ç·šå“質等網路資訊</translation>
<translation id="1567040042588613346">這項政策é‹ä½œæ­£å¸¸ï¼Œä½†èˆ‡å…¶ä»–地方設定的值相åŒï¼Œä¸¦å·²å–代該值。</translation>
<translation id="1569487616857761740">輸入到期日</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@
<translation id="1583429793053364125">顯示這個網é æ™‚發生錯誤。</translation>
<translation id="1586541204584340881">你安è£çš„擴充功能</translation>
<translation id="1588438908519853928">一般</translation>
+<translation id="1589050138437146318">è¦å®‰è£ ARCore 嗎?</translation>
<translation id="1592005682883173041">本機資料存å–權</translation>
<translation id="1594030484168838125">é¸æ“‡</translation>
<translation id="160851722280695521">暢玩 Chrome æé¾éŠæˆ²</translation>
@@ -254,7 +269,7 @@
<translation id="1711234383449478798">由於 <ph name="POLICY_NAME" /> 未設為 <ph name="VALUE" />,因此é­åˆ°å¿½ç•¥ã€‚</translation>
<translation id="1712552549805331520"><ph name="URL" /> è¦æ±‚在你的本機電腦上永久儲存資料</translation>
<translation id="1713628304598226412">紙匣 2</translation>
-<translation id="1715874602234207">F</translation>
+<translation id="1715874602234207">五</translation>
<translation id="1717218214683051432">動作感應器</translation>
<translation id="1717494416764505390">出紙槽 3</translation>
<translation id="1718029547804390981">文件éŽå¤§ï¼Œç„¡æ³•åŠ è¨»</translation>
@@ -279,6 +294,7 @@
<translation id="1763864636252898013">伺æœå™¨ç„¡æ³•è­‰æ˜Žå…¶å±¬æ–¼ <ph name="DOMAIN" /> 網域;其安全性憑證未å–å¾—ä½ è£ç½®ä½œæ¥­ç³»çµ±çš„信任。這å¯èƒ½æ˜¯å› ç‚ºè¨­å®šéŒ¯èª¤ï¼Œæˆ–有攻擊者攔截你的連線所致。</translation>
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />嘗試執行 Windows 網路診斷<ph name="END_LINK" />。</translation>
<translation id="1772163372082567643">ä½ è¦å­˜å–的伺æœå™¨ã€Œ<ph name="ORIGIN" />ã€å·²è¨­å®šæ¨™é ­ï¼ŒæŒ‡å®šæ‰€æœ‰æ”¶åˆ°çš„è¦æ±‚都必須套用來æºæ”¿ç­–。但該標頭格å¼éŒ¯èª¤ï¼Œå› æ­¤ç€è¦½å™¨ç„¡æ³•å®Œæˆä½ å‘「<ph name="SITE" />ã€æ出的è¦æ±‚。網站業者å¯ä½¿ç”¨ä¾†æºæ”¿ç­–設定網站的安全性和其他屬性。</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />進一步瞭解 Chromium 無痕模å¼<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">JIS B0</translation>
<translation id="1787142507584202372">這裡會顯示你最近開啟的分é </translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
@@ -406,6 +422,7 @@
<translation id="22081806969704220">紙匣 3</translation>
<translation id="2212735316055980242">找ä¸åˆ°æ”¿ç­–</translation>
<translation id="2213606439339815911">正在擷å–é …ç›®...</translation>
+<translation id="2213612003795704869">已列å°é é¢</translation>
<translation id="2215727959747642672">檔案編輯</translation>
<translation id="2218879909401188352">ç›®å‰åœ¨ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> 上的攻擊者å¯èƒ½æœƒè®“你安è£ä¸å®‰å…¨çš„應用程å¼ï¼Œå°Žè‡´è£ç½®å—æã€æ‰‹æ©Ÿå¸³å–®ä¸­å¤šå‡ºéš±è—費用,或是個人資訊é­ç«Šã€‚<ph name="BEGIN_LEARN_MORE_LINK" />瞭解詳情<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">沒有網際網路連線</translation>
@@ -415,6 +432,7 @@
<translation id="2248949050832152960">使用 WebAuthn</translation>
<translation id="2250931979407627383">é‚Šç·£è£è¨‚ (å·¦å´)</translation>
<translation id="225207911366869382">這個政策值已é­æ±°æ›ã€‚</translation>
+<translation id="2256115617011615191">ç«‹å³é‡æ–°å•Ÿå‹•</translation>
<translation id="2258928405015593961">請將到期日設在未來,然後å†è©¦ä¸€æ¬¡</translation>
<translation id="225943865679747347">錯誤代碼:<ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">HTTP 錯誤</translation>
@@ -442,6 +460,7 @@
<translation id="2337852623177822836">管ç†å“¡æ‰€æŽ§åˆ¶çš„設定</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> è¦æ±‚é…å°</translation>
<translation id="2346319942568447007">你複製的圖片</translation>
+<translation id="2350796302381711542">è¦å…許 <ph name="HANDLER_HOSTNAME" /> å–代 <ph name="REPLACED_HANDLER_TITLE" /> 開啟所有<ph name="PROTOCOL" />連çµå—Žï¼Ÿ</translation>
<translation id="2354001756790975382">其他書籤</translation>
<translation id="2354430244986887761">Google 安全ç€è¦½æœå‹™æœ€è¿‘在 <ph name="SITE" /> <ph name="BEGIN_LINK" />發ç¾æœ‰å®³çš„應用程å¼<ph name="END_LINK" />。</translation>
<translation id="2355395290879513365">攻擊者å¯èƒ½æœƒçœ‹åˆ°ä½ æ­£åœ¨é€™å€‹ç¶²ç«™ä¸Šç€è¦½çš„圖片,並以修改圖片內容的方å¼è®“ä½ å—騙。</translation>
@@ -467,6 +486,7 @@
<translation id="2413528052993050574">伺æœå™¨ç„¡æ³•è­‰æ˜Žå…¶å±¬æ–¼ <ph name="DOMAIN" /> 網域;其安全性憑證已é­æ’¤éŠ·ã€‚這å¯èƒ½æ˜¯å› ç‚ºè¨­å®šéŒ¯èª¤ï¼Œæˆ–有攻擊者攔截你的連線所致。</translation>
<translation id="2414886740292270097">深色</translation>
<translation id="2430968933669123598">ç®¡ç† Google 帳戶;按下 Enter éµå³å¯ç®¡ç† Google 帳戶的資訊ã€éš±ç§æ¬Šå’Œå®‰å…¨æ€§</translation>
+<translation id="2436186046335138073">è¦å…許 <ph name="HANDLER_HOSTNAME" /> 開啟所有<ph name="PROTOCOL" />連çµå—Žï¼Ÿ</translation>
<translation id="2438874542388153331">四孔 (å³å´)</translation>
<translation id="2450021089947420533">ç€è¦½æ­·ç¨‹</translation>
<translation id="2463739503403862330">å¡«å…¥</translation>
@@ -474,6 +494,7 @@
<translation id="2465655957518002998">é¸æ“‡å¿«éžæ–¹å¼</translation>
<translation id="2465688316154986572">釘è£</translation>
<translation id="2465914000209955735">管ç†åœ¨ Chrome 中下載的檔案</translation>
+<translation id="2466004615675155314">顯示來自網路的資訊</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />執行網路診斷<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">1 到 N çš„é †åº</translation>
<translation id="2470767536994572628">這份文件會在你編輯註解時é‡è¨­ç‚ºå–®é æª¢è¦–和原始顯示方å‘</translation>
@@ -494,6 +515,7 @@
<translation id="2523886232349826891">僅儲存在這部è£ç½®</translation>
<translation id="2524461107774643265">新增詳細資訊</translation>
<translation id="2529899080962247600">這個欄ä½æœ€å¤šåªèƒ½åŒ…å« <ph name="MAX_ITEMS_LIMIT" /> 個項目,超éŽçš„項目會é­åˆ°å¿½ç•¥ã€‚</translation>
+<translation id="2535585790302968248">開啟新的無痕分é ä»¥é€²è¡Œç§å¯†ç€è¦½</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{å’Œå¦å¤– 1 個網域}other{å’Œå¦å¤– # 個網域}}</translation>
<translation id="2536110899380797252">新增地å€</translation>
<translation id="2539524384386349900">åµæ¸¬</translation>
@@ -519,7 +541,14 @@
<translation id="2597378329261239068">此文件å—到密碼ä¿è­·ï¼Œè«‹è¼¸å…¥å¯†ç¢¼ã€‚</translation>
<translation id="2609632851001447353">變化版本</translation>
<translation id="2610561535971892504">點é¸è¤‡è£½</translation>
+<translation id="2617988307566202237">Chrome <ph name="BEGIN_EMPHASIS" />ä¸æœƒå„²å­˜<ph name="END_EMPHASIS" />下列資訊:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ä½ çš„ç€è¦½è¨˜éŒ„
+ <ph name="LIST_ITEM" />Cookie 和網站資料
+ <ph name="LIST_ITEM" />在表單中輸入的資訊
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (ä¿¡å°)</translation>
+<translation id="2623663032199728144">å¯ä»¥è¦æ±‚使用畫é¢ä¸­çš„資訊</translation>
<translation id="2625385379895617796">你的時é˜æ™‚é–“éŽå¿«</translation>
<translation id="262745152991669301">å¯ä»¥è¦æ±‚連線至 USB è£ç½®</translation>
<translation id="2629325967560697240">è¦ç²å¾— Chrome 最高等級的安全防護,請<ph name="BEGIN_ENHANCED_PROTECTION_LINK" />啟用強化防護功能<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -553,6 +582,7 @@
<translation id="2709516037105925701">自動填入</translation>
<translation id="2713444072780614174">白色</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />,按下 Tab éµå†æŒ‰ä¸‹ Enter éµå³å¯åœ¨ Chrome 設定中管ç†ä»˜æ¬¾å’Œä¿¡ç”¨å¡è³‡è¨Š</translation>
+<translation id="271663710482723385">按下 |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| å³å¯çµæŸå…¨èž¢å¹•æ¨¡å¼</translation>
<translation id="2721148159707890343">è¦æ±‚æˆåŠŸ</translation>
<translation id="2723669454293168317">在 Chrome 設定中執行安全檢查</translation>
<translation id="2726001110728089263">å´åŒ£</translation>
@@ -583,6 +613,7 @@
<translation id="2850739647070081192">Invite (ä¿¡å°)</translation>
<translation id="2856444702002559011">攻擊者å¯èƒ½æœƒè©¦åœ–從 <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ç«Šå–你的資訊 (例如密碼ã€éƒµä»¶æˆ–信用å¡è³‡æ–™)。<ph name="BEGIN_LEARN_MORE_LINK" />瞭解詳情<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">這個網站會顯示干擾性或誤導性的廣告。</translation>
+<translation id="286512204874376891">虛擬å¡ç‰‡æœƒå½è£æˆå¯¦é«”å¡ç‰‡ï¼Œä¿è­·ä½ å…å—潛在è©æ¬ºäº‹ä»¶çš„侵擾。<ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">å‹å–„</translation>
<translation id="2876489322757410363">å³å°‡é€€å‡ºç„¡ç—•æ¨¡å¼ï¼Œæ”¹ç‚ºä½¿ç”¨å¤–部應用程å¼ä»˜æ¬¾ï¼Œè¦ç¹¼çºŒå—Žï¼Ÿ</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />;按下 Tab éµå†æŒ‰ä¸‹ Enter éµå³å¯åœ¨ Chrome 設定中管ç†å®‰å…¨ç€è¦½ç­‰åŠŸèƒ½</translation>
@@ -607,6 +638,7 @@
<translation id="2930577230479659665">完æˆæ¯æ¬¡è¤‡å°å¾Œè£åˆ‡</translation>
<translation id="2932085390869194046">建議密碼...</translation>
<translation id="2934466151127459956">Government-Letter</translation>
+<translation id="2938225289965773019">é–‹å•Ÿ<ph name="PROTOCOL" />連çµ</translation>
<translation id="2941952326391522266">伺æœå™¨ç„¡æ³•è­‰æ˜Žå…¶å±¬æ–¼ <ph name="DOMAIN" /> 網域;其安全性憑證來自 <ph name="DOMAIN2" /> 網域。這å¯èƒ½æ˜¯å› ç‚ºè¨­å®šéŒ¯èª¤ï¼Œæˆ–有攻擊者攔截你的連線所致。</translation>
<translation id="2943895734390379394">上傳時間:</translation>
<translation id="2948083400971632585">ä½ å¯ä»¥åœ¨è¨­å®šé é¢åœç”¨ä»»ä½•ç‚ºé€£ç·šè¨­ç½®çš„ Proxy。</translation>
@@ -639,6 +671,7 @@
<translation id="3037605927509011580">糟糕ï¼</translation>
<translation id="3041612393474885105">憑證資訊</translation>
<translation id="3044034790304486808">繼續æœå°‹</translation>
+<translation id="305162504811187366">Chrome é ç«¯æ¡Œé¢æ­·å²è¨˜éŒ„,包括時間戳記ã€ä¸»æ©Ÿå’Œç”¨æˆ¶ç«¯å·¥ä½œéšŽæ®µ ID</translation>
<translation id="3060227939791841287">C9 (ä¿¡å°)</translation>
<translation id="3061707000357573562">修補æœå‹™</translation>
<translation id="306573536155379004">已啟動éŠæˆ²ã€‚</translation>
@@ -679,6 +712,7 @@
<translation id="3197136577151645743">å¯ä»¥è¦æ±‚åµæ¸¬ä½ ä½¿ç”¨é€™éƒ¨è£ç½®çš„時間</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />;按下 Tab éµå†æŒ‰ä¸‹ Enter éµå³å¯åœ¨ Chrome 設定中管ç†è¦åŒæ­¥è™•ç†å“ªäº›è³‡è¨Š</translation>
<translation id="320323717674993345">å–消付款</translation>
+<translation id="3203366800380907218">來自網路</translation>
<translation id="3207960819495026254">已加入書籤</translation>
<translation id="3209034400446768650">這個é é¢å¯èƒ½æœƒç”¢ç”Ÿè²»ç”¨</translation>
<translation id="3212581601480735796">你在 <ph name="HOSTNAME" /> 上進行的活動正é­åˆ°ç›£æŽ§</translation>
@@ -695,10 +729,12 @@
<translation id="3234666976984236645">一律åµæ¸¬é€™å€‹ç¶²ç«™çš„é‡è¦å…§å®¹</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />;按下 Tab éµå†æŒ‰ä¸‹ Enter éµå³å¯è‡ªè¨‚ç€è¦½å™¨å¤–觀</translation>
<translation id="3240791268468473923">無相符安全付款憑證表已開啟</translation>
+<translation id="324180406144491771">「<ph name="HOST_NAME" />ã€é€£çµå·²é­åˆ°å°éŽ–</translation>
<translation id="3249845759089040423">時髦</translation>
<translation id="3252266817569339921">法文</translation>
<translation id="3257954757204451555">這項資訊是由誰æ供?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />;按下 Tab éµå†æŒ‰ä¸‹ Enter éµå³å¯åœ¨ Google 日曆中快速建立新活動</translation>
+<translation id="3261488570342242926">瞭解虛擬å¡ç‰‡</translation>
<translation id="3264837738038045344">ã€Œç®¡ç† Chrome 設定ã€æŒ‰éˆ•ï¼›æŒ‰ä¸‹ Enter éµå³å¯å‰å¾€ Chrome 設定</translation>
<translation id="3266793032086590337">值 (è¡çª)</translation>
<translation id="3268451620468152448">開啟的分é </translation>
@@ -712,6 +748,7 @@
<translation id="3288238092761586174"><ph name="URL" /> å¯èƒ½éœ€è¦æŽ¡å–其他步驟,æ‰èƒ½é©—證付款方å¼</translation>
<translation id="3293642807462928945">進一步瞭解 <ph name="POLICY_NAME" /> 政策</translation>
<translation id="3295444047715739395">在 Chrome 設定中查看和管ç†å¯†ç¢¼</translation>
+<translation id="3303795387212510132">è¦å…許應用程å¼é–‹å•Ÿã€Œ<ph name="PROTOCOL_SCHEME" />ã€é€£çµå—Žï¼Ÿ</translation>
<translation id="3303855915957856445">找ä¸åˆ°ç›¸ç¬¦çš„æœå°‹çµæžœ</translation>
<translation id="3304073249511302126">è—牙掃æ</translation>
<translation id="3308006649705061278">çµ„ç¹”å–®ä½ (OU)</translation>
@@ -725,12 +762,6 @@
<translation id="3345782426586609320">眼ç›</translation>
<translation id="3355823806454867987">變更 Proxy 設定...</translation>
<translation id="3360103848165129075">付款處ç†å¸¸å¼å·¥ä½œè¡¨</translation>
-<translation id="3361596688432910856">Chrome <ph name="BEGIN_EMPHASIS" />ä¸æœƒå„²å­˜<ph name="END_EMPHASIS" />下列資訊:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />ä½ çš„ç€è¦½è¨˜éŒ„
- <ph name="LIST_ITEM" />Cookie 和網站資料
- <ph name="LIST_ITEM" />你在表單中輸入的資訊
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">這項政策是從已淘汰的 <ph name="OLD_POLICY" /> 政策自動複製而來。請改用這項政策。</translation>
<translation id="3364869320075768271"><ph name="URL" /> è¦æ±‚使用你的虛擬實境è£ç½®å’Œè³‡æ–™</translation>
<translation id="3366477098757335611">查看å¡ç‰‡</translation>
@@ -813,7 +844,6 @@
<translation id="3587738293690942763">中間</translation>
<translation id="3592413004129370115">Italian (ä¿¡å°)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{你隨時å¯ä»¥é‡è¨­ç¾¤çµ„ã€‚å¤§ç´„éœ€è¦ 1 天æ‰èƒ½åŠ å…¥æ–°ç¾¤çµ„。}=1{你隨時å¯ä»¥é‡è¨­ç¾¤çµ„ã€‚å¤§ç´„éœ€è¦ 1 天æ‰èƒ½åŠ å…¥æ–°ç¾¤çµ„。}other{你隨時å¯ä»¥é‡è¨­ç¾¤çµ„ã€‚éœ€è¦ {NUM_DAYS} 天æ‰èƒ½åŠ å…¥æ–°ç¾¤çµ„。}}</translation>
-<translation id="3596012367874587041">應用程å¼è¨­å®š</translation>
<translation id="3600246354004376029"><ph name="TITLE" />,<ph name="DOMAIN" />,<ph name="TIME" /></translation>
<translation id="3603507503523709">å·²é­ç³»çµ±ç®¡ç†å“¡å°éŽ–的應用程å¼</translation>
<translation id="3608932978122581043">é€ç´™æ–¹å‘</translation>
@@ -856,6 +886,7 @@
<translation id="370972442370243704">é–‹å•Ÿç€è¦½æ­·ç¨‹</translation>
<translation id="3711895659073496551">æš«åœ</translation>
<translation id="3712624925041724820">授權已用盡</translation>
+<translation id="3714633008798122362">網路日曆</translation>
<translation id="3714780639079136834">開啟行動數據或 Wi-Fi</translation>
<translation id="3715597595485130451">連線至 Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />檢查 Proxyã€é˜²ç«ç‰†å’Œ DNS 設定<ph name="END_LINK" /></translation>
@@ -917,6 +948,7 @@
<translation id="3906954721959377182">å¹³æ¿é›»è…¦</translation>
<translation id="3909477809443608991"><ph name="URL" /> 想è¦æ’­æ”¾å—到ä¿è­·çš„內容。Google 會驗證你的è£ç½®èº«åˆ†ï¼Œé€™å€‹ç¶²ç«™å¯èƒ½ä¹Ÿæœƒå­˜å–ä½ çš„è£ç½®èº«åˆ†ã€‚</translation>
<translation id="3909695131102177774"><ph name="LABEL" />:<ph name="ERROR" /></translation>
+<translation id="3927932062596804919">拒絕</translation>
<translation id="3939773374150895049">è¦ä½¿ç”¨ WebAuthn å–代信用å¡é©—證碼嗎?</translation>
<translation id="3946209740501886391">一律詢å•ä½ æ˜¯å¦æŽ¥å—這個網站的è¦æ±‚</translation>
<translation id="3947595700203588284">å¯ä»¥è¦æ±‚連線至 MIDI è£ç½®</translation>
@@ -937,6 +969,7 @@
<translation id="3987940399970879459">ä¸åˆ° 1 MB</translation>
<translation id="3990250421422698716">æ’žé å移</translation>
<translation id="3996311196211510766">「<ph name="ORIGIN" />ã€ç¶²ç«™æŒ‡å®šæ‰€æœ‰æ”¶åˆ°çš„è¦æ±‚都必須套用來æºæ”¿ç­–,但目å‰ç„¡æ³•å¥—用此政策。</translation>
+<translation id="4009243425692662128">你列å°çš„é é¢å…§å®¹æœƒå‚³é€çµ¦ Google Cloud 或第三方進行分æžã€‚舉例來說,Google Cloud 或第三方å¯èƒ½æœƒæŽƒæ文字,檢查是å¦å«æœ‰æ©Ÿå¯†è³‡æ–™ã€‚</translation>
<translation id="4010758435855888356">è¦æŽˆäºˆå„²å­˜ç©ºé–“å­˜å–權嗎?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{PDF 文件,共 {COUNT} é }other{PDF 文件,共 {COUNT} é }}</translation>
<translation id="4023431997072828269">這個表單是é€éŽä¸å®‰å…¨çš„連線æ交,其他人將å¯çœ‹åˆ°ä½ çš„資訊。</translation>
@@ -1027,6 +1060,7 @@
<translation id="4250680216510889253">å¦</translation>
<translation id="4253168017788158739">附註</translation>
<translation id="425582637250725228">系統å¯èƒ½ä¸æœƒå„²å­˜ä½ æ‰€åšçš„變更。</translation>
+<translation id="425869179292622354">è¦é€éŽè™›æ“¬å¡ç‰‡é€²ä¸€æ­¥ä¿è­·å¡ç‰‡çš„安全嗎?</translation>
<translation id="4258748452823770588">ç°½å有誤</translation>
<translation id="4261046003697461417">無法加註å—ä¿è­·çš„文件</translation>
<translation id="4265872034478892965">ä¾æ“šç®¡ç†å“¡çš„設定å…許</translation>
@@ -1089,6 +1123,7 @@
<translation id="4434045419905280838">彈出å¼è¦–窗與é‡æ–°å°Žå‘</translation>
<translation id="4435702339979719576">明信片)</translation>
<translation id="443673843213245140">雖然已åœç”¨ Proxy,ä¸éŽå·²æŒ‡å®šæ˜Žç¢º Proxy 設定。</translation>
+<translation id="4441832193888514600">由於這項政策åªèƒ½è¨­ç‚ºé›²ç«¯ä½¿ç”¨è€…政策,因此系統予以忽略。</translation>
<translation id="4450893287417543264">ä¸è¦å†é¡¯ç¤º</translation>
<translation id="4451135742916150903">å¯ä»¥è¦æ±‚連線至 HID è£ç½®</translation>
<translation id="4452328064229197696">系統發ç¾ä½ å‰›æ‰ä½¿ç”¨çš„密碼因為資料侵害事件而é­åˆ°å¤–洩。為確ä¿å¸³æˆ¶å®‰å…¨ï¼ŒGoogle 密碼管ç†å“¡å»ºè­°ä½ ç«‹å³æª¢æŸ¥å·²å„²å­˜çš„密碼。</translation>
@@ -1144,6 +1179,7 @@
<translation id="4628948037717959914">相片</translation>
<translation id="4631649115723685955">已連çµç¾é‡‘回饋</translation>
<translation id="4636930964841734540">資訊</translation>
+<translation id="4638670630777875591">Chromium 無痕模å¼</translation>
<translation id="464342062220857295">æœå°‹åŠŸèƒ½</translation>
<translation id="4644670975240021822">相åé †åº (æ­£é¢æœä¸‹)</translation>
<translation id="4646534391647090355">ç«‹å³å‰å¾€ä¸‹è¼‰ä¸­å¿ƒ</translation>
@@ -1164,6 +1200,7 @@
<translation id="4708268264240856090">您的連線已中斷</translation>
<translation id="4712404868219726379">Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />執行 Windows 網路診斷<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426"><ph name="USERNAME" />的密碼</translation>
<translation id="4724144314178270921">å¯ä»¥è¦æ±‚查看剪貼簿上的文字和圖片</translation>
<translation id="4726672564094551039">é‡æ–°è¼‰å…¥æ”¿ç­–</translation>
<translation id="4728558894243024398">å¹³å°</translation>
@@ -1185,6 +1222,7 @@
<translation id="4757993714154412917">你剛æ‰åœ¨è©é¨™ç¶²ç«™ä¸Šè¼¸å…¥äº†å¯†ç¢¼ã€‚為確ä¿å¸³æˆ¶å®‰å…¨ï¼ŒChromium 建議你檢查已儲存的密碼。</translation>
<translation id="4758311279753947758">新增è¯çµ¡è³‡è¨Š</translation>
<translation id="4761104368405085019">使用你的麥克風</translation>
+<translation id="4761869838909035636">執行 Chrome 安全檢查</translation>
<translation id="4764776831041365478"><ph name="URL" /> 的網é å¯èƒ½æš«æ™‚離線,或是已經é·ç§»åˆ°å¦ä¸€å€‹ç¶²å€ã€‚</translation>
<translation id="4766713847338118463">雙釘 (底部)</translation>
<translation id="4771973620359291008">發生ä¸æ˜Žçš„錯誤。</translation>
@@ -1205,12 +1243,6 @@
<translation id="4819347708020428563">è¦åœ¨é è¨­æª¢è¦–中編輯註解嗎?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />;按下 Tab éµå†æŒ‰ä¸‹ Enter éµå³å¯å¿«é€Ÿå»ºç«‹æ–°çš„ Google 試算表</translation>
<translation id="4825507807291741242">強大</translation>
-<translation id="4827402517081186284">無痕模å¼ç„¡æ³•è®“你在網路上ä¸ç•™ç—•è·¡ï¼š
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />網站會知é“你在ç€è¦½<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />雇主或學校å¯ä»¥è¿½è¹¤ç€è¦½æ´»å‹•<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />網際網路æœå‹™ä¾›æ‡‰å•†å¯èƒ½æœƒç›£æŽ§ç¶²è·¯æµé‡<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">開啟警告</translation>
<translation id="4838327282952368871">夢幻</translation>
<translation id="4840250757394056958">查看 Chrome æ­·å²è¨˜éŒ„</translation>
@@ -1222,12 +1254,12 @@
<translation id="4854362297993841467">ä¸æ”¯æ´æ‰€é¸çš„å¿«éžæ–¹å¼ï¼Œè«‹æ”¹é¸å…¶ä»–æ–¹å¼ã€‚</translation>
<translation id="4854853140771946034">在 Google Keep 中快速建立新記事</translation>
<translation id="485902285759009870">正在驗證動態密碼...</translation>
+<translation id="4866506163384898554">按下 |<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| å³å¯é¡¯ç¤ºæ¸¸æ¨™</translation>
<translation id="4876188919622883022">簡易檢視</translation>
<translation id="4876305945144899064">沒有使用者å稱</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{ç„¡}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />ã€<ph name="EXAMPLE_DOMAIN_2" />}other{<ph name="EXAMPLE_DOMAIN_1" />ã€<ph name="EXAMPLE_DOMAIN_2" /> <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831">æœå°‹ã€Œ<ph name="TEXT" />ã€</translation>
<translation id="4879491255372875719">自動 (é è¨­)</translation>
-<translation id="4879725228911483934">在你的畫é¢ä¸­é–‹å•Ÿå’Œæ”¾ç½®è¦–窗</translation>
<translation id="4880827082731008257">æœå°‹è¨˜éŒ„</translation>
<translation id="4881695831933465202">é–‹å•Ÿ</translation>
<translation id="4885256590493466218">使用 <ph name="CARD_DETAIL" /> çµå¸³ä»˜æ¬¾</translation>
@@ -1236,6 +1268,7 @@
<translation id="4895877746940133817"><ph name="TYPE_1" />ã€<ph name="TYPE_2" />,<ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">第ä¹å·</translation>
<translation id="4901778704868714008">儲存...</translation>
+<translation id="4905659621780993806">管ç†å“¡å°‡è‡ªå‹•æ–¼ <ph name="DATE" /><ph name="TIME" />é‡æ–°å•Ÿå‹•ä½ çš„è£ç½®ã€‚在è£ç½®é‡æ–°å•Ÿå‹•å‰ï¼Œè«‹è¨˜å¾—儲存開啟的項目。</translation>
<translation id="4913987521957242411">打孔 (左上方)</translation>
<translation id="4918221908152712722">安è£ã€Œ<ph name="APP_NAME" />ã€(無須下載)</translation>
<translation id="4923459931733593730">付款</translation>
@@ -1244,6 +1277,7 @@
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />,按下 Tab éµå†æŒ‰ä¸‹ Enter éµå³å¯æœå°‹</translation>
<translation id="4930153903256238152">大容é‡</translation>
+<translation id="4940163644868678279">Chrome 無痕模å¼</translation>
<translation id="4943872375798546930">沒有çµæžœ</translation>
<translation id="4950898438188848926">分é åˆ‡æ›æŒ‰éˆ•ï¼ŒæŒ‰ä¸‹ Enter éµå³å¯åˆ‡æ›è‡³é–‹å•Ÿçš„分é ï¼š<ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="495170559598752135">動作</translation>
@@ -1253,6 +1287,7 @@
<translation id="4968522289500246572">這是專為行動è£ç½®è¨­è¨ˆçš„應用程å¼ï¼Œå¤§å°å¯èƒ½æœªå¦¥å–„調整。此應用程å¼å¯èƒ½æœƒç™¼ç”Ÿå•é¡Œï¼Œæˆ–是é‡æ–°å•Ÿå‹•ã€‚</translation>
<translation id="4969341057194253438">刪除錄製內容</translation>
<translation id="4973922308112707173">雙孔 (頂端)</translation>
+<translation id="4976702386844183910">上次造訪日期:<ph name="DATE" /></translation>
<translation id="4984088539114770594">è¦ä½¿ç”¨éº¥å…‹é¢¨å—Žï¼Ÿ</translation>
<translation id="4984339528288761049">Prc5 (ä¿¡å°)</translation>
<translation id="4989163558385430922">查看全部</translation>
@@ -1314,6 +1349,7 @@
<translation id="5138227688689900538">顯示較少</translation>
<translation id="5145883236150621069">政策回應中存在錯誤代碼</translation>
<translation id="5146995429444047494">å·²å°éŽ– <ph name="ORIGIN" /> 的通知</translation>
+<translation id="514704532284964975"><ph name="URL" /> 希望查看和變更你é€éŽæ‰‹æ©Ÿåœ¨ NFC è£ç½®ä¸Šè¼•è§¸çš„資訊</translation>
<translation id="5148809049217731050">æ­£é¢æœä¸Š</translation>
<translation id="515292512908731282">C4 (ä¿¡å°)</translation>
<translation id="5158275234811857234">å°é¢</translation>
@@ -1338,6 +1374,7 @@
<translation id="5215116848420601511">儲存在 Google Pay 的付款方å¼å’Œåœ°å€è³‡è¨Š</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">紙匣 13</translation>
+<translation id="5216942107514965959">上次造訪日期:今天</translation>
<translation id="5222812217790122047">請輸入電å­éƒµä»¶åœ°å€</translation>
<translation id="5230733896359313003">é‹é€åœ°å€</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1358,7 +1395,6 @@
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">文件屬性</translation>
<translation id="528468243742722775">çµæŸ</translation>
-<translation id="5284909709419567258">網路ä½å€</translation>
<translation id="5285570108065881030">顯示所有已儲存的密碼</translation>
<translation id="5287240709317226393">顯示 Cookie</translation>
<translation id="5287456746628258573">這個網站的安全性設定éŽèˆŠï¼Œå› æ­¤ä½ å‚³é€çµ¦é€™å€‹ç¶²ç«™çš„的資訊 (例如密碼或信用å¡è™Ÿç¢¼) å¯èƒ½æœƒå¤–洩。</translation>
@@ -1442,6 +1478,7 @@
<translation id="5556459405103347317">é‡æ–°è¼‰å…¥</translation>
<translation id="5560088892362098740">到期日</translation>
<translation id="55635442646131152">文件大綱</translation>
+<translation id="5565613213060953222">開啟無痕分é </translation>
<translation id="5565735124758917034">管ç†ä¸­</translation>
<translation id="5570825185877910964">ä¿è­·å¸³æˆ¶</translation>
<translation id="5571083550517324815">無法在這個地å€å–件,請改用其他地å€ã€‚</translation>
@@ -1524,6 +1561,7 @@
<translation id="5869522115854928033">已儲存的密碼</translation>
<translation id="5873013647450402046">銀行希望確èªä½ çš„身分。</translation>
<translation id="5887400589839399685">已儲存å¡ç‰‡</translation>
+<translation id="5887687176710214216">上次造訪日期:昨天</translation>
<translation id="5895138241574237353">é‡æ–°å•Ÿå‹•</translation>
<translation id="5895187275912066135">發行日期</translation>
<translation id="5901630391730855834">黃色</translation>
@@ -1537,12 +1575,13 @@
<translation id="5921639886840618607">è¦å°‡é€™å¼µå¡ç‰‡å„²å­˜åˆ° Google 帳戶嗎?</translation>
<translation id="5922853866070715753">å³å°‡å®Œæˆ</translation>
<translation id="5932224571077948991">網站顯示干擾性或誤導性廣告</translation>
+<translation id="5938153366081463283">新增虛擬å¡ç‰‡</translation>
<translation id="5938793338444039872">Troy</translation>
<translation id="5946937721014915347">正在開啟 <ph name="SITE_NAME" />…</translation>
<translation id="5951495562196540101">無法é€éŽå€‹äººå¸³æˆ¶è¨»å†Š (有å°è£æŽˆæ¬Š)。</translation>
<translation id="5963413905009737549">å€æ®µ</translation>
<translation id="5967592137238574583">編輯è¯çµ¡è³‡è¨Š</translation>
-<translation id="5967867314010545767">從記錄中移除</translation>
+<translation id="5967867314010545767">從歷å²è¨˜éŒ„中移除</translation>
<translation id="5968793460449681917">æ¯æ¬¡é€ è¨ª</translation>
<translation id="5974052231147553524">第六å·</translation>
<translation id="5975083100439434680">縮å°</translation>
@@ -1601,6 +1640,7 @@
<translation id="6120179357481664955">還記得你的 UPI ID 嗎?</translation>
<translation id="6124432979022149706">Chrome Enterprise 連接器</translation>
<translation id="6127379762771434464">已移除項目</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />進一步瞭解 Chrome 無痕模å¼<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">檢查您的網路線是å¦ç©©å›ºé€£æŽ¥ã€‚é‡æ–°å•Ÿå‹•æ‚¨å¯èƒ½æ­£åœ¨ä½¿ç”¨çš„任何路由器ã€
數據機或其他網路è£ç½®ã€‚</translation>
<translation id="614940544461990577">建議åšæ³•ï¼š</translation>
@@ -1613,7 +1653,6 @@
<translation id="6169916984152623906">ç¾åœ¨ï¼Œä½ å¯ä»¥é€²è¡Œç§å¯†ç€è¦½äº†ã€‚共用這部è£ç½®çš„其他使用者ä¸æœƒçœ‹åˆ°ä½ çš„活動,ä¸éŽï¼Œä½ ä¸‹è¼‰çš„內容和新增的書籤ä»æœƒä¿ç•™åœ¨è£ç½®ä¸Šã€‚</translation>
<translation id="6177128806592000436">你與這個網站的連線ä¸å®‰å…¨</translation>
<translation id="6180316780098470077">é‡è©¦é–“éš”</translation>
-<translation id="619448280891863779">å¯ä»¥è¦æ±‚在你的畫é¢ä¸­é–‹å•Ÿå’Œæ”¾ç½®è¦–窗</translation>
<translation id="6196640612572343990">å°éŽ–第三方 Cookie</translation>
<translation id="6203231073485539293">檢查網際網路連線</translation>
<translation id="6218753634732582820">è¦å¾ž Chromium 中移除地å€å—Žï¼Ÿ</translation>
@@ -1636,7 +1675,7 @@
<translation id="6272383483618007430">Google æ›´æ–°</translation>
<translation id="6276112860590028508">你的閱讀清單中的é é¢æœƒé¡¯ç¤ºåœ¨é€™è£¡</translation>
<translation id="627746635834430766">åªè¦å°‡å¡ç‰‡è³‡è¨Šèˆ‡å¸³å–®åœ°å€å„²å­˜åˆ°ä½ çš„ Google 帳戶中,下次å³å¯æ›´å¿«å®Œæˆä»˜æ¬¾ç¨‹åºã€‚</translation>
-<translation id="6279098320682980337">尚未填寫虛擬å¡è™Ÿå—Žï¼Ÿé»žé¸å¡ç‰‡è³‡æ–™å³å¯è¤‡è£½</translation>
+<translation id="6279183038361895380">按下 |<ph name="ACCELERATOR" />| å³å¯é¡¯ç¤ºæ¸¸æ¨™</translation>
<translation id="6280223929691119688">å¿«éžç„¡æ³•é€è²¨åˆ°é€™å€‹åœ°å€ï¼Œè«‹æ”¹ç”¨å…¶ä»–地å€ã€‚</translation>
<translation id="6282194474023008486">郵éžå€è™Ÿ</translation>
<translation id="6285507000506177184">[ç®¡ç† Chrome 下載內容] 按鈕;按下 Enter éµå³å¯ç®¡ç†åœ¨ Chrome 中下載的檔案</translation>
@@ -1644,6 +1683,7 @@
<translation id="6290238015253830360">這裡會顯示推薦給你的文章</translation>
<translation id="6293309776179964942">JIS B5</translation>
<translation id="6295618774959045776">CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{è£ç½®æœƒç«‹å³é‡æ–°å•Ÿå‹•}=1{è£ç½®å°‡æ–¼ 1 秒後é‡æ–°å•Ÿå‹•}other{è£ç½®å°‡æ–¼ # 秒後é‡æ–°å•Ÿå‹•}}</translation>
<translation id="6302269476990306341">正在åœæ­¢ Chrome 版 Google 助ç†</translation>
<translation id="6305205051461490394">無法連上 <ph name="URL" />。</translation>
<translation id="6312113039770857350">網é ç„¡æ³•ä½¿ç”¨</translation>
@@ -1717,6 +1757,7 @@
<translation id="6529602333819889595">é‡åšåˆªé™¤(&amp;R)</translation>
<translation id="6545864417968258051">è—牙掃æ</translation>
<translation id="6547208576736763147">雙孔 (å·¦å´)</translation>
+<translation id="6554732001434021288">上次造訪日期:<ph name="NUM_DAYS" /> 天å‰</translation>
<translation id="6556866813142980365">é‡åš</translation>
<translation id="6569060085658103619">ç›®å‰é¡¯ç¤ºçš„是擴充功能é é¢</translation>
<translation id="6573200754375280815">雙孔 (å³å´)</translation>
@@ -1777,7 +1818,6 @@
<translation id="6757797048963528358">您的è£ç½®å·²é€²å…¥ç¡çœ æ¨¡å¼ã€‚</translation>
<translation id="6767985426384634228">è¦æ›´æ–°åœ°å€å—Žï¼Ÿ</translation>
<translation id="6768213884286397650">Hagaki (明信片)</translation>
-<translation id="6774185088257932239"><ph name="BEGIN_LINK" />進一步瞭解<ph name="END_LINK" />無痕模å¼</translation>
<translation id="6775759552199460396">JIS B2</translation>
<translation id="67862343314499040">紫羅蘭色</translation>
<translation id="6786747875388722282">擴充功能</translation>
@@ -1861,7 +1901,6 @@
<translation id="706295145388601875">在 Chrome 設定中新增åŠç®¡ç†åœ°å€</translation>
<translation id="7064851114919012435">è¯çµ¡è³‡è¨Š</translation>
<translation id="7068733155164172741">輸入 <ph name="OTP_LENGTH" /> ä½æ•¸é©—證碼</translation>
-<translation id="7070090581017165256">關於這個網站</translation>
<translation id="70705239631109039">你的連線å¯èƒ½æœ‰å®‰å…¨æ¼æ´ž</translation>
<translation id="7075452647191940183">è¦æ±‚éŽå¤§</translation>
<translation id="7079718277001814089">這個網站å«æœ‰æƒ¡æ„軟體</translation>
@@ -1878,6 +1917,12 @@
<translation id="7111012039238467737">(有效)</translation>
<translation id="7118618213916969306">æœå°‹å‰ªè²¼ç°¿ç¶²å€ <ph name="SHORT_URL" /></translation>
<translation id="7119414471315195487">關閉其他分é æˆ–程å¼</translation>
+<translation id="7129355289156517987">關閉所有 Chromium 無痕分é å¾Œï¼Œç³»çµ±æœƒå°‡ä½ åœ¨é€™äº›åˆ†é ä¸Šçš„活動記錄從這部è£ç½®ä¸Šæ¸…除:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ç€è¦½æ´»å‹•<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />æœå°‹è¨˜éŒ„<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />在表單中輸入的資訊<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">無法é‹é€åˆ°é€™å€‹åœ°å€ï¼Œè«‹æ”¹ç”¨å…¶ä»–地å€ã€‚</translation>
<translation id="7132939140423847331">管ç†å“¡å·²ç¦æ­¢è¤‡è£½é€™å€‹è³‡æ–™ã€‚</translation>
<translation id="7135130955892390533">顯示狀態</translation>
@@ -1900,6 +1945,7 @@
<translation id="7192203810768312527">釋出 <ph name="SIZE" />。下次造訪部分網站時,載入速度å¯èƒ½æœƒè®Šæ…¢ã€‚</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7201591969684833065">系統管ç†å“¡å¯ä»¥æŸ¥çœ‹ä»¥ä¸‹é …目:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />;按下 Tab éµå†æŒ‰ä¸‹ Enter éµå³å¯é–‹å•Ÿæ–°çš„無痕分é ä»¥é€²è¡Œç§å¯†ç€è¦½</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> ä¸ç¬¦åˆå®‰å…¨æ€§æ¨™æº–。</translation>
<translation id="7210993021468939304">容器內的 Linux 活動,並å¯åœ¨å®¹å™¨å…§å®‰è£åŠåŸ·è¡Œ Linux 應用程å¼</translation>
@@ -1931,6 +1977,7 @@
<translation id="7304562222803846232">ç®¡ç† Google 帳戶隱ç§æ¬Šè¨­å®š</translation>
<translation id="7305756307268530424">啟用慢速模å¼</translation>
<translation id="7308436126008021607">背景åŒæ­¥è™•ç†</translation>
+<translation id="7310392214323165548">è£ç½®å¾ˆå¿«å°±æœƒé‡æ–°å•Ÿå‹•</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">連線說明</translation>
<translation id="7323804146520582233">éš±è—「<ph name="SECTION" />ã€éƒ¨åˆ†</translation>
@@ -1938,6 +1985,7 @@
<translation id="7334320624316649418">é‡åšé‡æ–°æŽ’åº(&amp;R)</translation>
<translation id="7335157162773372339">å¯ä»¥è¦æ±‚使用你的æ”影機</translation>
<translation id="7337248890521463931">顯示更多行</translation>
+<translation id="7337418456231055214">尚未填寫虛擬å¡è™Ÿå—Žï¼Ÿé»žé¸å¡ç‰‡è³‡æ–™å³å¯è¤‡è£½ã€‚<ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">ä½ çš„å¹³å°ç„¡æ³•ä½¿ç”¨å¯¦é©—性功能。</translation>
<translation id="733923710415886693">伺æœå™¨æ†‘證未ä¾æ†‘è­‰é€æ˜ŽåŒ–政策公開。</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1960,6 +2008,7 @@
<translation id="7378627244592794276">ä¸éœ€è¦</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">ä¸é©ç”¨</translation>
+<translation id="7388594495505979117">{0,plural, =1{è£ç½®å°‡æ–¼ 1 分é˜å¾Œé‡æ–°å•Ÿå‹•}other{è£ç½®å°‡æ–¼ # 分é˜å¾Œé‡æ–°å•Ÿå‹•}}</translation>
<translation id="7390545607259442187">驗證信用å¡</translation>
<translation id="7392089738299859607">更新地å€</translation>
<translation id="7399802613464275309">安全檢查</translation>
@@ -1996,6 +2045,12 @@
<translation id="7485870689360869515">找ä¸åˆ°ä»»ä½•è³‡æ–™ã€‚</translation>
<translation id="7495528107193238112">這項內容已é­åˆ°å°éŽ–,請è¯çµ¡ç¶²ç«™æ“有者以修正å•é¡Œã€‚</translation>
<translation id="7497998058912824456">建立文件的按鈕;按下 Enter éµå³å¯å¿«é€Ÿå»ºç«‹æ–°çš„ Google 文件</translation>
+<translation id="7506488012654002225">Chromium <ph name="BEGIN_EMPHASIS" />ä¸æœƒå„²å­˜<ph name="END_EMPHASIS" />下列資訊:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />ä½ çš„ç€è¦½è¨˜éŒ„
+ <ph name="LIST_ITEM" />Cookie 和網站資料
+ <ph name="LIST_ITEM" />在表單中輸入的資訊
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">傳回的政策è£ç½® ID 沒有任何內容,或是與目å‰çš„è£ç½® ID ä¸ç¬¦</translation>
<translation id="7508870219247277067">酪梨綠</translation>
<translation id="7511955381719512146">ç›®å‰ä½¿ç”¨çš„ Wi-Fi 網路å¯èƒ½æœƒè¦æ±‚您造訪 <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />。</translation>
@@ -2109,7 +2164,6 @@
<translation id="7813600968533626083">è¦å¾ž Chrome 中移除建議嗎?</translation>
<translation id="781440967107097262">è¦åˆ†äº«å‰ªè²¼ç°¿å—Žï¼Ÿ</translation>
<translation id="7815407501681723534">找到 <ph name="NUMBER_OF_RESULTS" /> 個與「<ph name="SEARCH_STRING" />ã€ç›¸ç¬¦çš„<ph name="SEARCH_RESULTS" /></translation>
-<translation id="782125616001965242">顯示這個網站的相關資訊</translation>
<translation id="782886543891417279">ç›®å‰ä½¿ç”¨çš„ Wi-Fi 網路 (<ph name="WIFI_NAME" />) å¯èƒ½æœƒè¦æ±‚您造訪登入網é ã€‚</translation>
<translation id="7836231406687464395">Postfix (ä¿¡å°)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{ç„¡}=1{1 個應用程å¼ï¼š<ph name="EXAMPLE_APP_1" />}=2{2 個應用程å¼ï¼š<ph name="EXAMPLE_APP_1" />ã€<ph name="EXAMPLE_APP_2" />}other{# 個應用程å¼ï¼š<ph name="EXAMPLE_APP_1" />ã€<ph name="EXAMPLE_APP_2" />ã€<ph name="AND_MORE" />}}</translation>
@@ -2126,7 +2180,6 @@
<translation id="7888575728750733395">列å°ç®—繪方å¼</translation>
<translation id="7894280532028510793">如果拼字正確,<ph name="BEGIN_LINK" />請嘗試執行網路診斷<ph name="END_LINK" />。</translation>
<translation id="7904208859782148177">C3 (ä¿¡å°)</translation>
-<translation id="7931318309563332511">ä¸æ˜Ž</translation>
<translation id="793209273132572360">è¦æ›´æ–°åœ°å€å—Žï¼Ÿ</translation>
<translation id="7932579305932748336">塗布</translation>
<translation id="79338296614623784">請輸入有效的電話號碼</translation>
@@ -2151,13 +2204,14 @@
<translation id="7976214039405368314">è¦æ±‚數é‡éŽå¤š</translation>
<translation id="7977538094055660992">輸出è£ç½®</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">已連çµåˆ°</translation>
<translation id="798134797138789862">å¯ä»¥è¦æ±‚使用虛擬實境è£ç½®å’Œè³‡æ–™</translation>
<translation id="7984945080620862648">ä½ ç›®å‰ç„¡æ³•é€ è¨ª <ph name="SITE" />,因為這個網站傳é€çš„憑證經éŽç·¨ç¢¼ï¼Œå°Žè‡´ Chrome 無法處ç†ã€‚網路錯誤和攻擊行為通常是暫時性的,所以這個網é å¯èƒ½ç¨å¾Œå°±èƒ½æ­£å¸¸ä½¿ç”¨ã€‚</translation>
-<translation id="79859296434321399">如è¦æŸ¥çœ‹æ“´å¢žå¯¦å¢ƒå…§å®¹ï¼Œè«‹å®‰è£ ARCore</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">è£è¨‚</translation>
<translation id="7992044431894087211">å·²é‡æ–°å•Ÿç”¨èˆ‡ã€Œ<ph name="APPLICATION_TITLE" />ã€åˆ†äº«èž¢å¹•ç•«é¢çš„功能</translation>
<translation id="7995512525968007366">未指定</translation>
+<translation id="7998269595945679889">「開啟無痕分é ã€æŒ‰éˆ•ï¼›æŒ‰ä¸‹ Enter éµå³å¯é–‹å•Ÿæ–°çš„無痕分é ä»¥é€²è¡Œç§å¯†ç€è¦½</translation>
<translation id="800218591365569300">嘗試關閉其他分é æˆ–程å¼ï¼Œä»¥é‡‹å‡ºè¨˜æ†¶é«”。</translation>
<translation id="8004582292198964060">ç€è¦½å™¨</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{系統會儲存這張å¡ç‰‡å’Œç›¸æ‡‰çš„帳單地å€ã€‚åªè¦ç™»å…¥ <ph name="USER_EMAIL" /> å³å¯ä½¿ç”¨ã€‚}other{系統會儲存這些å¡ç‰‡å’Œç›¸æ‡‰çš„帳單地å€ã€‚åªè¦ç™»å…¥ <ph name="USER_EMAIL" /> å³å¯ä½¿ç”¨ã€‚}}</translation>
@@ -2217,6 +2271,7 @@
<translation id="8202370299023114387">è¡çª</translation>
<translation id="8206978196348664717">Prc4 (ä¿¡å°)</translation>
<translation id="8211406090763984747">已建立安全連線</translation>
+<translation id="8217240300496046857">網站無法使用 Cookie 來追蹤你在網路上的活動。æŸäº›ç¶²ç«™çš„功能å¯èƒ½ç„¡æ³•æ­£å¸¸é‹ä½œã€‚</translation>
<translation id="8218327578424803826">指派的ä½ç½®ï¼š</translation>
<translation id="8220146938470311105">C7/C6 (ä¿¡å°)</translation>
<translation id="8225771182978767009">設定這部電腦的使用者é¸æ“‡å°éŽ–這個網站。</translation>
@@ -2257,14 +2312,9 @@
<translation id="830498451218851433">å°æŠ˜</translation>
<translation id="8307358339886459768">Small-Photo</translation>
<translation id="8307888238279532626">已安è£çš„應用程å¼ä»¥åŠä½¿ç”¨é »çŽ‡</translation>
+<translation id="8317207217658302555">è¦æ›´æ–° ARCore 嗎?</translation>
<translation id="831997045666694187">å‚晚</translation>
<translation id="8321476692217554900">通知</translation>
-<translation id="8328484624016508118">關閉所有無痕分é å¾Œï¼ŒChrome 就會從這部è£ç½®ä¸Šæ¸…除下列資料:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />ä½ çš„ç€è¦½æ´»å‹•<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />ä½ çš„æœå°‹è¨˜éŒ„<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />你在表單中輸入的資訊<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489">å­˜å– <ph name="HOST_NAME" /> çš„è¦æ±‚é­åˆ°æ‹’絕</translation>
<translation id="833262891116910667">醒目顯示</translation>
<translation id="8339163506404995330">系統將ä¸æœƒç¿»è­¯<ph name="LANGUAGE" />網é </translation>
@@ -2316,6 +2366,7 @@
<translation id="8507227106804027148">指令列</translation>
<translation id="8508648098325802031">æœå°‹åœ–示</translation>
<translation id="8511402995811232419">ç®¡ç† Cookie</translation>
+<translation id="8519753333133776369">管ç†å“¡å…許使用的 HID è£ç½®</translation>
<translation id="8522552481199248698">Chrome å¯å”助你ä¿è­· Google 帳戶並變更密碼。</translation>
<translation id="8530813470445476232">清除ç€è¦½è¨˜éŒ„ã€Cookieã€å¿«å–以åŠå…¶ä»– Chrome 設定</translation>
<translation id="8533619373899488139">è«‹å‰å¾€ &lt;strong&gt;chrome://policy&lt;/strong&gt; 查看é­åˆ°å°éŽ–的網å€æ¸…單,以åŠç”±ç³»çµ±ç®¡ç†å“¡æ‰€å¼·åˆ¶åŸ·è¡Œçš„其他政策。</translation>
@@ -2327,7 +2378,6 @@
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{é‡è¨­æ¬Šé™}other{é‡è¨­æ¬Šé™}}</translation>
<translation id="8555010941760982128">çµå¸³æ™‚請使用這個促銷代碼</translation>
<translation id="8557066899867184262">信用å¡é©—證碼ä½æ–¼ä¿¡ç”¨å¡èƒŒé¢ã€‚</translation>
-<translation id="8558485628462305855">如è¦æŸ¥çœ‹æ“´å¢žå¯¦å¢ƒå…§å®¹ï¼Œè«‹æ›´æ–° ARCore</translation>
<translation id="8559762987265718583">ä½ è£ç½®çš„日期和時間 (<ph name="DATE_AND_TIME" />) ä¸æ­£ç¢ºï¼Œå› æ­¤ç„¡æ³•èˆ‡ <ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> 建立ç§äººé€£ç·šã€‚</translation>
<translation id="8564182942834072828">個別文件/未自動分é çš„副本</translation>
<translation id="8564985650692024650">如果你在其他網站上é‡è¤‡ä½¿ç”¨éŽä½ çš„ <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> 密碼,Chromium 會建議你é‡è¨­å¯†ç¢¼ã€‚</translation>
@@ -2346,6 +2396,7 @@
<translation id="865032292777205197">動作感應器</translation>
<translation id="8663226718884576429">訂單摘è¦ï¼š<ph name="TOTAL_LABEL" />,更多詳細資料</translation>
<translation id="8666678546361132282">英文</translation>
+<translation id="8669306706049782872">使用畫é¢ä¸­çš„資訊開啟åŠæ”¾ç½®è¦–窗</translation>
<translation id="867224526087042813">ç°½å</translation>
<translation id="8676424191133491403">ä¸å»¶é²</translation>
<translation id="8680536109547170164"><ph name="QUERY" />,答案:<ph name="ANSWER" /></translation>
@@ -2372,6 +2423,7 @@
<translation id="8731544501227493793">「管ç†å¯†ç¢¼ã€æŒ‰éˆ•ï¼ŒæŒ‰ä¸‹ Enter éµå³å¯åœ¨ Chrome 設定中查看和管ç†å¯†ç¢¼</translation>
<translation id="8734529307927223492">ä½ çš„ <ph name="DEVICE_TYPE" /> 是由 <ph name="MANAGER" /> 管ç†</translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />,按下 Tab éµå†æŒ‰ä¸‹ Enter éµå³å¯é–‹å•Ÿæ–°çš„ç„¡ç—•å¼è¦–窗進行ç§å¯†ç€è¦½</translation>
+<translation id="8737685506611670901">é–‹å•Ÿ<ph name="PROTOCOL" />é€£çµ (å–代 <ph name="REPLACED_HANDLER_TITLE" />)</translation>
<translation id="8738058698779197622">你必須正確設定時é˜ï¼Œæ‰èƒ½å»ºç«‹å®‰å…¨é€£ç·šã€‚這是因為網站驗證身分時所使用的憑證僅於特定一段時間內有效。由於你è£ç½®çš„時é˜ä¸æ­£ç¢ºï¼Œå› æ­¤ Chromium 無法驗證這些憑證。</translation>
<translation id="8740359287975076522">找ä¸åˆ° <ph name="HOST_NAME" /> çš„ &lt;abbr id="dnsDefinition"&gt;DNS ä½å€&lt;/abbr&gt;,正在診斷å•é¡Œã€‚</translation>
<translation id="8742371904523228557">你的 <ph name="ORIGIN" /> 驗證碼是 <ph name="ONE_TIME_CODE" /></translation>
@@ -2399,6 +2451,7 @@
<translation id="883848425547221593">其他書籤</translation>
<translation id="884264119367021077">é‹é€åœ°å€</translation>
<translation id="884923133447025588">未發ç¾æ’¤éŠ·æ©Ÿåˆ¶ã€‚</translation>
+<translation id="8849262850971482943">使用虛擬å¡ç‰‡è®“安全更有ä¿éšœ</translation>
<translation id="885730110891505394">與 Google 分享</translation>
<translation id="8858065207712248076">如果你在其他網站上é‡è¤‡ä½¿ç”¨éŽä½ çš„ <ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> 密碼,Chrome 會建議你é‡è¨­å¯†ç¢¼ã€‚</translation>
<translation id="885906927438988819">如果拼字正確,<ph name="BEGIN_LINK" />請嘗試執行 Windows 網路診斷<ph name="END_LINK" />。</translation>
@@ -2448,6 +2501,7 @@
<translation id="9004367719664099443">正在執行 VR 工作階段</translation>
<translation id="9005998258318286617">無法載入 PDF 文件。</translation>
<translation id="9008201768610948239">ç•¥éŽ</translation>
+<translation id="901834265349196618">é›»å­éƒµä»¶</translation>
<translation id="9020200922353704812">請輸入信用å¡å¸³å–®åœ°å€</translation>
<translation id="9020542370529661692">此網é å…§å®¹å·²ç¿»è­¯æˆ<ph name="TARGET_LANGUAGE" /></translation>
<translation id="9020742383383852663">A8</translation>
@@ -2458,7 +2512,7 @@
<translation id="9036306139374661733">è¦æŽˆäºˆéº¥å…‹é¢¨æ¬Šé™å—Žï¼Ÿ</translation>
<translation id="9038649477754266430">使用é æ¸¬æŸ¥è©¢å­—串æœå‹™ï¼Œè®“系統更快載入網é </translation>
<translation id="9039213469156557790">此外,這個網é å«æœ‰å…¶ä»–ä¸å®‰å…¨çš„資æºã€‚其他人å¯èƒ½æœƒåœ¨è³‡æºå‚³è¼¸æœŸé–“檢視這些資æºï¼Œæ”»æ“Šè€…也å¯èƒ½æœƒä¿®æ”¹é€™äº›è³‡æºï¼Œé€²è€Œè®Šæ›´ç¶²é è¡Œç‚ºã€‚</translation>
-<translation id="9040464167025094690">「尋找我的è£ç½®ã€æŒ‰éˆ•ï¼›æŒ‰ä¸‹ Enter éµå³å¯æ‰¾å‡ºä½ åœ¨ Google 帳戶中的è£ç½®</translation>
+<translation id="9040464167025094690">「尋找我的è£ç½®ã€æŒ‰éˆ•ï¼›æŒ‰ä¸‹ Enter éµå³å¯å‰å¾€ Google 帳戶中的「尋找你的è£ç½®ã€é é¢</translation>
<translation id="9042617223719777575">大容é‡</translation>
<translation id="9044359186343685026">使用 Touch ID</translation>
<translation id="9045525010788763347"><ph name="RESULT_MODIFIED_DATE" /> - <ph name="RESULT_PRODUCT_SOURCE" /></translation>
@@ -2496,6 +2550,7 @@
<translation id="9150045010208374699">使用你的相機</translation>
<translation id="9150685862434908345">你的系統管ç†å“¡å¯ä»¥é ç«¯è®Šæ›´ç€è¦½å™¨è¨­å®šã€‚這部è£ç½®ä¸Šçš„活動也å¯ä»¥é€éŽ Chrome 以外的æœå‹™ç®¡ç†ã€‚<ph name="BEGIN_LINK" />瞭解詳情<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">已更新</translation>
+<translation id="9155211586651734179">已連çµçš„音訊周邊è£ç½®</translation>
<translation id="9157595877708044936">設定中...</translation>
<translation id="9158625974267017556">C6 (ä¿¡å°)</translation>
<translation id="9164029392738894042">準確率檢查</translation>
diff --git a/chromium/components/strings/components_strings_zu.xtb b/chromium/components/strings/components_strings_zu.xtb
index b11f872dfcf..273169ff4b9 100644
--- a/chromium/components/strings/components_strings_zu.xtb
+++ b/chromium/components/strings/components_strings_zu.xtb
@@ -14,13 +14,18 @@
<translation id="1028781062521375153">Bona imininingwane</translation>
<translation id="1030706264415084469">I-<ph name="URL" /> ifuna ukugcina ingunaphakade idatha enkulu kudivayisi yakho</translation>
<translation id="1032854598605920125">Zungezisa ngokulandela iwashi</translation>
+<translation id="1033329911862281889">I-Incognito ayikwenzi ukuthi ungabonakali ku-inthanethi:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Amasayithi namasevisi abawavakashelayo angabona ukuvakashelwa<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Abaqashi noma izikole bangalandelela umsebenzi wokuphequlua<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Abahlinzeki nge-inthanethi bangagada ithrafikhi yewebhu<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1036348656032585052">Vala</translation>
<translation id="1036982837258183574">Cindezela |<ph name="ACCELERATOR" />| ukuze uphume kusikrini esigcwele</translation>
<translation id="1038106730571050514">Bonisa iziphakamiso</translation>
<translation id="1038842779957582377">igama elingaziwa</translation>
<translation id="1041998700806130099">Umlayezo weshidi lomsebenzi</translation>
<translation id="1048785276086539861">Lapho uhlela izichasiselo, le dokhumenti izobuyela ekuhloleni ikhasi kuqala okukodwa</translation>
-<translation id="1049743911850919806">I-Incognito</translation>
<translation id="1050038467049342496">Vala ezinye izinhlelo zokusebenza</translation>
<translation id="1055184225775184556">&amp;Hlehlisa ukungeza</translation>
<translation id="1056898198331236512">Isexwayiso</translation>
@@ -48,6 +53,7 @@
<translation id="112840717907525620">Inqolobale yenqubomgomo ILUNGILE</translation>
<translation id="1130564665089811311">Inkinobho yokuhumusha ikhasi, cindezela u-Enter ukuze uhumushe leli khasi nge-Google Translate</translation>
<translation id="1131264053432022307">Isithombe osikopishile</translation>
+<translation id="1142846828089312304">Vimba amakhukhi wenkampani engahlangene ngqo ku-Incognito</translation>
<translation id="1150979032973867961">Le seva ayikwazanga ukukhombisa ukuthi iyi-<ph name="DOMAIN" />; isitifiketi sayo sokuvikeleka asithenjiwe isistimu yokusebenza yekhompyutha yakho. Lokhu kungenzeka kubangelwe ukulungisa okungalungile noma umhlaseli uzama ukufinyelela uxhumo lwakho.</translation>
<translation id="1151972924205500581">Kudingeka iphasiwedi</translation>
<translation id="1156303062776767266">Ubuka ifayela lasendaweni noma elabiwe</translation>
@@ -64,7 +70,6 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="1178581264944972037">Misa isikhashana</translation>
<translation id="1181037720776840403">Susa</translation>
<translation id="1186201132766001848">Hlola amaphasiwedi</translation>
-<translation id="1195210374336998651">Iya kumasethingi e-app</translation>
<translation id="1195558154361252544">Izaziso zivinjelwe ngokuzenzakalela kuwo wonke amasayithi ngaphandle kwalawo ovavumelayo</translation>
<translation id="1197088940767939838">Olintshi</translation>
<translation id="1201402288615127009">Okulandelayo</translation>
@@ -111,7 +116,7 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="1307966114820526988">Izici ezihoxisiwe</translation>
<translation id="1308113895091915999">Ukunikeza kuyatholakala</translation>
<translation id="1312803275555673949">Yibuphi ubufakazi obuyisekelayo?</translation>
-<translation id="131405271941274527">I-<ph name="URL" /> ifuna ukuthumela futhi yamukele ulwazi uma uthepha ifoni yakho kudivayisi ye-NFC</translation>
+<translation id="1314311879718644478">Buka okuqukethwe kwe-augmented reality</translation>
<translation id="1314509827145471431">Ukubophezela kwesokudla</translation>
<translation id="1318023360584041678">Kulondolozwe eqenjini lethebhu</translation>
<translation id="1319245136674974084">Ungaceli futhi le app</translation>
@@ -161,6 +166,7 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="142858679511221695">Umsebenzisi we-cloud</translation>
<translation id="1428729058023778569">Ubona lesi sexwayiso ngoba leli sayithi alisekeli i-HTTPS. <ph name="BEGIN_LEARN_MORE_LINK" />Funda kabanzi<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="1430915738399379752">Phrinta</translation>
+<translation id="1432187715652018471">leli khasi lifuna ukufaka isibambi sesevisi.</translation>
<translation id="1432581352905426595">Phatha izinjini zosesho</translation>
<translation id="1436185428532214179">Ingacela ukuhlela amafayela namafolda kudivayisi yakho</translation>
<translation id="1442386063175183758">Ukugoqa kwesango lesokudla</translation>
@@ -181,6 +187,12 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="1483493594462132177">Thumela</translation>
<translation id="1484290072879560759">Khetha ikheli lokuthumela</translation>
<translation id="1492194039220927094">Ukuphusha izinqubomgomo:</translation>
+<translation id="149293076951187737">Lapho uvala wonke amathebhu we-Incognito Chrome, umsebenzi wakho uyasulwa kusuka kule divayisi:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Umsebenzi wokuphequlula<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Umlando wokusesha<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Ulwazi olufakwa kumafomu<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="1495677929897281669">Emuva kuthebhu</translation>
<translation id="1501859676467574491">Bonisa amakhadi kusuka ku-akhawunti yakho ye-Google</translation>
<translation id="1507202001669085618">&lt;p&gt;Uzobona leli phutha uma uzama ukusebenzisa iphothali ye-Wi-Fi lapho kufanele ungene khona ngemvume ngaphambi okuthi ufike ku-inthanethi.&lt;/p&gt;
@@ -208,6 +220,8 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="1559572115229829303">&lt;p&gt;Ukuxhumeka okuyimfihlo okuya ku-<ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> akukwazi ukusungulwa ngoba idethi nesikhathi sedivayisi yakho (<ph name="DATE_AND_TIME" />) akulungile.&lt;/p&gt;
&lt;p&gt;Sicela ulungise idethi nesikhathi kusukela kusigaba se-&lt;strong&gt;Okujwayelekile&lt;/strong&gt; kohlelo lokusebenza le-&lt;strong&gt;Izilungiselelo&lt;/strong&gt;.&lt;/p&gt;</translation>
+<translation id="1559839503761818503">Umphathi wakho uzoqalisa idivayisi yakho ngo-<ph name="TIME" /> ngomhla ka-<ph name="DATE" /></translation>
+<translation id="156703335097561114">Ulwazi lwenethiwekhi olufana namakheli, ukulungiselelwa kwesixhumi esibonakalayo, kanye nekhwalithi yoxhumano</translation>
<translation id="1567040042588613346">Le nqubomgomo isebenza njengokuhlosiwe kodwa inani elifanayo lisethiwe kwenye indawo futhi lithathelwe isikhundla yile nqubomgomo.</translation>
<translation id="1569487616857761740">Faka idethi yokuphela kwesikhathi</translation>
<translation id="1581080074034554886">CVC</translation>
@@ -215,6 +229,7 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="1583429793053364125">Kukhona okungahambanga kahle ngenkathi kuboniswa lesi khasi lewebhu.</translation>
<translation id="1586541204584340881">Iziphi izandiso ozifakile</translation>
<translation id="1588438908519853928">Jwayelekile</translation>
+<translation id="1589050138437146318">Faka i-ARCore?</translation>
<translation id="1592005682883173041">Ukufinyelela kudatha yasendaweni</translation>
<translation id="1594030484168838125">Khetha</translation>
<translation id="160851722280695521">Dlala igeyimu ye-Dino Run ku-Chrome</translation>
@@ -283,6 +298,7 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
isihloko asakhekanga kahle, okugwema isiphequluli ukufeza
isicelo sakho se-<ph name="SITE" />. Izinqubomgomo zoqobo zingasetshenziswa
abasebenzisi besayithi ukulungisa ukuphepha nezinye izinto zesayithi.</translation>
+<translation id="1774592222195216949"><ph name="BEGIN_LINK" />Funda kabanzi nge-Incognito ku-Chromium<ph name="END_LINK" /></translation>
<translation id="1778646502362731194">I-JIS B0</translation>
<translation id="1787142507584202372">Amathebhu akho avulekile abonakala lapha</translation>
<translation id="1791429645902722292">I-Google Smart Lock</translation>
@@ -410,6 +426,7 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="22081806969704220">Ithileyi elingu-3</translation>
<translation id="2212735316055980242">Inqubomgomo ayitholiwe</translation>
<translation id="2213606439339815911">Ilanda okufakiwe...</translation>
+<translation id="2213612003795704869">Ikhasi liphrintiwe</translation>
<translation id="2215727959747642672">Ukuhlelwa kwefayela</translation>
<translation id="2218879909401188352">Abahlaseli okwamanje ku-<ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> bangafaka izinhlelo zokusebenza eziyingozi ezona idivayisi yakho, zingeza izindleko ezifihlakele enkokhelweni yakho yeselula, noma zitshontshe ulwazi lwakho oluyimfihlo. <ph name="BEGIN_LEARN_MORE_LINK" />Funda kabanzi<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2224337661447660594">Ayikho i-inthanethi</translation>
@@ -419,6 +436,7 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="2248949050832152960">Sebenzisa i-WebAuthn</translation>
<translation id="2250931979407627383">Ukuthunta umphetho kwesokunxele</translation>
<translation id="225207911366869382">Leli nani lehliselwe le nqubomgomo.</translation>
+<translation id="2256115617011615191">Qala kabusha manje</translation>
<translation id="2258928405015593961">Faka usuku lokuphelelwa isikhathi ngokuzayo bese uyazama futhi</translation>
<translation id="225943865679747347">Iphutha lekhodi: <ph name="ERROR_CODE" /></translation>
<translation id="2262243747453050782">Iphutha le-HTTP</translation>
@@ -446,6 +464,7 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="2337852623177822836">Isethingi lilawulwa umlawuli wakho</translation>
<translation id="2340263603246777781"><ph name="ORIGIN" /> ufuna ukubhangqa</translation>
<translation id="2346319942568447007">Isithombe osikopishile</translation>
+<translation id="2350796302381711542">Vumela i-<ph name="HANDLER_HOSTNAME" /> ukuba avule zonke izixhumanisi ze-<ph name="PROTOCOL" /> kune-<ph name="REPLACED_HANDLER_TITLE" />?</translation>
<translation id="2354001756790975382">Amanye amawebhusayithi</translation>
<translation id="2354430244986887761">I-Google Safe Browsing isanda <ph name="BEGIN_LINK" />kuthola izinhlelo zokuseebenza eziyingozi<ph name="END_LINK" /> ku-<ph name="SITE" />.</translation>
<translation id="2355395290879513365">Abahlaseli kungenzeka bakwazi ukubona izithombe ozibonayo kuleli sayithi baphinde bakukhohlise ngokuzilungisa.</translation>
@@ -471,6 +490,7 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="2413528052993050574">Le seva ayikwazanga ukukhombisa ukuthi iyi-<ph name="DOMAIN" />; isitifiketi sayo sokuvikeleka kungenzeka sibuyisiwe. Lokhu kungahle kubangelwe ukulungisa okungalungile noma umhlaseli uzama ukufinyelela uxhumo lwakho.</translation>
<translation id="2414886740292270097">Mnyama</translation>
<translation id="2430968933669123598">Phatha I-akhawunti ye-Google, cindezela u-Enter ukuze uphathe ulwazi lwakho, ubumfihlo, nokuvikeleka Ku-akhawunti yakho ye-Google</translation>
+<translation id="2436186046335138073">Vumela i-<ph name="HANDLER_HOSTNAME" /> ukuvula zonke izixhumanisi ze-<ph name="PROTOCOL" />?</translation>
<translation id="2438874542388153331">Ukushaya kane kwesokudla</translation>
<translation id="2450021089947420533">Amahambo</translation>
<translation id="2463739503403862330">Gcwalisa</translation>
@@ -478,6 +498,7 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="2465655957518002998">Khetha indlela yokulethwa</translation>
<translation id="2465688316154986572">Ukunamathisela</translation>
<translation id="2465914000209955735">Phatha amafayela owadawunilode ku-Chrome</translation>
+<translation id="2466004615675155314">Bonisa ulwazi olusuka kuwebhu</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />Iqalisa ukuxilongwa kwenethiwekhi<ph name="END_LINK" /></translation>
<translation id="2469153820345007638">1-ukuya ku-oda elingu-N</translation>
<translation id="2470767536994572628">Lapho uhlela izichasiselo, le dokhumenti izobuyela ekuhloleni ikhasi kuqala okukodwa nasekuzungeziseni kwayo kokwangempela</translation>
@@ -498,6 +519,7 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="2523886232349826891">Kulondolozwe kule divayisi kuphela</translation>
<translation id="2524461107774643265">Engeza ulwazi olungeziwe</translation>
<translation id="2529899080962247600">Le nkambu akufanele ibe nokungena okungaphe kokungu-<ph name="MAX_ITEMS_LIMIT" />. Konke okufakiwe okwengeziwe kuzoshaywa indiva.</translation>
+<translation id="2535585790302968248">Vula iwindi elisha le-Incognito ukuze ubhrawuze ngokugodliwe</translation>
<translation id="2535659140340599600">{COUNT,plural, =1{nokungu-1 ngaphezulu}one{nokungu-# ngaphezulu}other{nokungu-# ngaphezulu}}</translation>
<translation id="2536110899380797252">Engeza ikheli</translation>
<translation id="2539524384386349900">Thola</translation>
@@ -523,7 +545,14 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="2597378329261239068">Le dokhumenti ivikelwe yiphasiwedi. Sicela ufake iphasiwedi.</translation>
<translation id="2609632851001447353">Ukwahluka</translation>
<translation id="2610561535971892504">Chofoza ukuze ukopishe</translation>
+<translation id="2617988307566202237">I-Chrome <ph name="BEGIN_EMPHASIS" />ngeke ilondoloze<ph name="END_EMPHASIS" /> ulwazi olulandelayo:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Umlando wakho wokuphequlula
+ <ph name="LIST_ITEM" />Amakhukhi nedatha yesayithi
+ <ph name="LIST_ITEM" />Ulwazi olufakwe kumafomu
+ <ph name="END_LIST" /></translation>
<translation id="2618023639789766142">C10 (Envelope)</translation>
+<translation id="2623663032199728144">Ingase icele ukusebenzisa ulwazi olumayelana nezikrini zakho</translation>
<translation id="2625385379895617796">Iwashi lakho liphambili</translation>
<translation id="262745152991669301">Ingacela ukuxhuma kumadivayisi we-USB</translation>
<translation id="2629325967560697240">Ukuze uthole ileveli yokuphepha ephakeme kakhulu ye-Chrome, <ph name="BEGIN_ENHANCED_PROTECTION_LINK" />vula ukuvikela okuthuthukisiwe<ph name="END_ENHANCED_PROTECTION_LINK" /></translation>
@@ -557,6 +586,7 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="2709516037105925701">Gcwalisa ngokuzenzakalela</translation>
<translation id="2713444072780614174">Mhlophe</translation>
<translation id="2715612312510870559"><ph name="UPDATE_CREDIT_CARD_FOCUSED_FRIENDLY_MATCH_TEXT" />, cindezela u-Tab bese u-Enter ukuze ulawule izinkokhelo zakho nolwazi lwekhadi lesikweletu kumasethingi e-Chrome</translation>
+<translation id="271663710482723385">Cindezela u-|<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| ukuze uphume esikrinini esigcwele</translation>
<translation id="2721148159707890343">Isicelo siphumelele</translation>
<translation id="2723669454293168317">Qalisa Ukuhlola kokuphepha kumasethingi we-Chrome</translation>
<translation id="2726001110728089263">Ithileyi Lasohlangothini</translation>
@@ -587,6 +617,7 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="2850739647070081192">Mema (Envelope)</translation>
<translation id="2856444702002559011">Abahlaseli bangazama ukutshontsha ulwazi lwakho kusuka ku-<ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (isibonelo, amaphasiwedi, imilayezo, noma amakhadi esikweletu). <ph name="BEGIN_LEARN_MORE_LINK" />Funda kabanzi<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2859806420264540918">Leli sayithi libonisa izikhangiso ezingathandeki noma ezidukisayo.</translation>
+<translation id="286512204874376891">Ikhadi le-virtual lifihla ikhadi lakho langempela ukusiza ukukuvikela ekukhwabaniseni okungase kube khona. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_ENROLLMENT_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="287596039013813457">Ubungani</translation>
<translation id="2876489322757410363">Ushiya imodi ye-incognito ukuze ukhokhe nge-app yangaphandle. Qhubeka?</translation>
<translation id="2876949457278336305"><ph name="MANAGE_SECURITY_SETTINGS_FOCUSED_FRIENDLY_MATCH_TEXT" />, cindezela u-Tab bese no-Enter ukuphatha Ukuphequlula kwakho okuphephile nokuningi kumasethingi we-Chrome</translation>
@@ -611,6 +642,7 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="2930577230479659665">Sika ngemuva kwekhophi ngayinye</translation>
<translation id="2932085390869194046">Iphakamisa iphasiwedi...</translation>
<translation id="2934466151127459956">Incwadi kahulumeni</translation>
+<translation id="2938225289965773019">Vula izixhumanisi ze-<ph name="PROTOCOL" /></translation>
<translation id="2941952326391522266">Le seva ayikwazanga ukukhombisa ukuthi iyi-<ph name="DOMAIN" />; isitifiketi sayo sokuvikeleka sivela ku-<ph name="DOMAIN2" />. Lokhu kungenzeka ukuthi kubangelwe ukulungisa okungalungile noma umhlaseli uzama ukufinyelela uxhumo lwakho.</translation>
<translation id="2943895734390379394">Isikhathi sokulayisha:</translation>
<translation id="2948083400971632585">Ungakhubaza noma yibaphi ommeleli abalungiselelwe ukuxhumeka kusuka kukhasi lezilungiselelo.</translation>
@@ -643,6 +675,7 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="3037605927509011580">Hawu, iphutha!</translation>
<translation id="3041612393474885105">Ulwazi lesitifiketi</translation>
<translation id="3044034790304486808">Qhubeka nosesho lwakho</translation>
+<translation id="305162504811187366">Umlando wedeskithophu yesilawuli kude se-Chrome, ofaka izitembu zesikhathi, abasingathi nama-id weseshini yeklayenti</translation>
<translation id="3060227939791841287">C9 (Envelope)</translation>
<translation id="3061707000357573562">Isevisi yepeshi</translation>
<translation id="306573536155379004">Igeyimu iqalile.</translation>
@@ -681,6 +714,7 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="3197136577151645743">Ingase icele ukwazi lapho usebenzisa le divayisi</translation>
<translation id="3202497928925179914"><ph name="MANAGE_SYNC_FOCUSED_FRIENDLY_MATCH_TEXT" />, cindezela u-Tab bese no-Enter ukuze uphathe ukuthi yiluphi ulwazi olivumelanisa kumasethingi we-Chrome</translation>
<translation id="320323717674993345">Khansela inkokhelo</translation>
+<translation id="3203366800380907218">Kusuka kuwebhu</translation>
<translation id="3207960819495026254">Kubekwe uphawu lokubekisa</translation>
<translation id="3209034400446768650">Ikhasi lingakhokhisa imali</translation>
<translation id="3212581601480735796">Umsebenzi wakho ku-<ph name="HOSTNAME" /> ugadiwe</translation>
@@ -697,10 +731,12 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="3234666976984236645">Njalo thola okuqukethwe okubalulekile kuleli sayithi</translation>
<translation id="3240683217920639535"><ph name="MANAGE_CHROME_THEMES_FOCUSED_FRIENDLY_MATCH_TEXT" />, Cindezela u-tab bese u-Enter ukuze wenze ukubukeka kwe-browser yakho ngendlela oyifisayo</translation>
<translation id="3240791268468473923">Imfanelo yokukhokha evikelekile yeshidi lemfanelo elingafani ivuliwe</translation>
+<translation id="324180406144491771">Amalinki “ka-<ph name="HOST_NAME" />†avinjiwe</translation>
<translation id="3249845759089040423">I-Groovy</translation>
<translation id="3252266817569339921">Isi-French</translation>
<translation id="3257954757204451555">Ubani ongemva kwalolu lwazi?</translation>
<translation id="3259648571731540213"><ph name="CREATE_GOOGLE_CALENDAR_EVENT_FOCUSED_FRIENDLY_MATCH_TEXT" />, cindezela u-Tab bese u-Enter ukuze udale umcimbi omusha ngokushesha ku-Google Calendar</translation>
+<translation id="3261488570342242926">Funda mayelana namakhadi we-virtual</translation>
<translation id="3264837738038045344">Phatha inkinobho yamasethingi we-Chrome, cindezela u-Enter ukuze uvakashele amasethingi wakho we-Chrome</translation>
<translation id="3266793032086590337">Inani (liyaphambana)</translation>
<translation id="3268451620468152448">Vula amathebhu</translation>
@@ -714,6 +750,7 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="3288238092761586174">I-<ph name="URL" /> ingase idinge ukuthatha izinyathelo ezengeziwe ukuqinisekisa inkokhelo yakho</translation>
<translation id="3293642807462928945">Funda kabanzi mayelana nenqubomgomo ye-<ph name="POLICY_NAME" /></translation>
<translation id="3295444047715739395">Buka futhi phatha amaphasiwedi wakho kumasethingi we-Chrome</translation>
+<translation id="3303795387212510132">Vumela i-app ukuthi ivule amalinki we-<ph name="PROTOCOL_SCHEME" />?</translation>
<translation id="3303855915957856445">Ayikho imiphumela yosesho etholakele</translation>
<translation id="3304073249511302126">ukuskena kwe-bluetooth</translation>
<translation id="3308006649705061278">Iyunithi yenhlangano (i-OU)</translation>
@@ -727,12 +764,6 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="3345782426586609320">Amehlo</translation>
<translation id="3355823806454867987">Guqula izilungiselelo zommeleli...</translation>
<translation id="3360103848165129075">Isidi lesibambi senkokhelo</translation>
-<translation id="3361596688432910856">I-Chrome <ph name="BEGIN_EMPHASIS" />ngeke ilondoloze<ph name="END_EMPHASIS" /> ulwazi olulandelayo:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Umlando wakho wokuphequlula
- <ph name="LIST_ITEM" />Amakhukhi nedatha yesayithi
- <ph name="LIST_ITEM" />Ulwazi olufakwe kumafomu
- <ph name="END_LIST" /></translation>
<translation id="3362968246557010467">Le nqubomgomo ikopishelwe ngokuzenzakalela kusukela kunqubomgomo ehoxisiwe ye-<ph name="OLD_POLICY" />. Kuzomele usebenzise le nqubomgomo kunalokho.</translation>
<translation id="3364869320075768271">I-<ph name="URL" /> ifuna ukusebenzisa idivayisi yakho yento engekho ngokoqobo nedatha</translation>
<translation id="3366477098757335611">Buka amakhadi</translation>
@@ -815,7 +846,6 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="3587738293690942763">Okumaphakathi</translation>
<translation id="3592413004129370115">Italian (Envelope)</translation>
<translation id="3595699422137460894">{NUM_DAYS,plural, =0{Ungasetha kabusha iqembu lakho nganoma yisiphi isikhathi. Kuthatha cishe usuku ukujoyina iqembu elisha.}=1{Ungasetha kabusha iqembu lakho nganoma yisiphi isikhathi. Kuthatha cishe usuku ukujoyina iqembu elisha.}one{Ungasetha kabusha iqembu lakho nganoma yisiphi isikhathi. Kuthatha izinsuku ezingu-{NUM_DAYS} ukujoyina iqembu elisha.}other{Ungasetha kabusha iqembu lakho nganoma yisiphi isikhathi. Kuthatha izinsuku ezingu-{NUM_DAYS} ukujoyina iqembu elisha.}}</translation>
-<translation id="3596012367874587041">Amasethingi e-App</translation>
<translation id="3600246354004376029"><ph name="TITLE" />, <ph name="DOMAIN" />, <ph name="TIME" /></translation>
<translation id="3603507503523709">Uhlelo lokusebenza luvinjwe ngumlawuli wakho</translation>
<translation id="3608932978122581043">Umumo wokuphakelayo</translation>
@@ -857,6 +887,7 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="370972442370243704">Vula Uhambo</translation>
<translation id="3711895659073496551">Misa okwesikhashana</translation>
<translation id="3712624925041724820">Amalayisense akhathele</translation>
+<translation id="3714633008798122362">ikhalenda yewebhu</translation>
<translation id="3714780639079136834">Ukuvula idatha yeselula noma i-Wi-Fi</translation>
<translation id="3715597595485130451">Xhumeka ku-Wi-Fi</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />Ukuhlola i-proxy, i-firewall, nokulungiswa kwe-DNS<ph name="END_LINK" /></translation>
@@ -918,6 +949,7 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="3906954721959377182">Ithebulethi</translation>
<translation id="3909477809443608991"><ph name="URL" /> ifuna ukudlala okuqukethwe okuvikelwe. Ubunikazi bedivayisi yakho buzoqinisekiswa i-Google futhi bungafinyelelwa ngaleli sayithi.</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
+<translation id="3927932062596804919">Phika</translation>
<translation id="3939773374150895049">Sebenzisa i-WebAuthn esikhundleni se-CVC?</translation>
<translation id="3946209740501886391">Hlala ubuza kuleli sayithi</translation>
<translation id="3947595700203588284">Amasayithi angacela ukuxhuma kumadivayisi we-MIDI</translation>
@@ -939,6 +971,7 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="3990250421422698716">I-Jog offset</translation>
<translation id="3996311196211510766">Isayithi le-<ph name="ORIGIN" /> licele ukuthi inqubomgomo yokwangempela
isebenze kuzo zonke izicelo zayo, kodwa le nqubomgomo ayikwazi ukusetshenziswa okwamanje.</translation>
+<translation id="4009243425692662128">Okuqukethwe kwamakhasi owaphrintayo kuthunyelwa ku-Google Cloud noma kwizinkampani ezingahlangene ngqo ukuze kuhlaziywe. Isibonelo, ingapheqululwa mayelana nedatha ezwelayo</translation>
<translation id="4010758435855888356">Vumela ukufinyelela kusitoreji?</translation>
<translation id="4014128326099193693">{COUNT,plural, =1{Idokhumenti le-PDF eliqukethe ikhasi elingu-{COUNT}}one{Idokhumenti le-PDF eliqukethe amakhasi angu-{COUNT}}other{Idokhumenti le-PDF eliqukethe amakhasi angu-{COUNT}}}</translation>
<translation id="4023431997072828269">Ngenxa yokuthi leli fomu lithunyelwe kusetshenziswa uxhumo olungavikelwanga, ulwazi lwakho luzobonakala kwabanye.</translation>
@@ -1033,6 +1066,7 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="4250680216510889253">Cha</translation>
<translation id="4253168017788158739">Yazi</translation>
<translation id="425582637250725228">Ushintsho olwenzile kungenzeka lungalondolozwa.</translation>
+<translation id="425869179292622354">Lenze livikeleke kakhulu ngekhadi lokubuka?</translation>
<translation id="4258748452823770588">Isiginesha embi</translation>
<translation id="4261046003697461417">Amadokhumenti avikelwe awakwazi ukuchasiselwa</translation>
<translation id="4265872034478892965">Kuvunyelwe umlawuli wakho</translation>
@@ -1095,6 +1129,7 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="4434045419905280838">Okwesikhashana nokuqondiswa kabusha</translation>
<translation id="4435702339979719576">Ikhadi lokuposa)</translation>
<translation id="443673843213245140">Ukusetshenziswa ummeleli kukhitshaziwe kodwa ukulungiselelwa okubekelwe obala kommeleli kucacisiwe.</translation>
+<translation id="4441832193888514600">Kuzitshwe ngenxa yokuthi inqubomgomo ikwazi ukusethwa kuphela njengenqubomgomo yomsebenzisi we-cloud.</translation>
<translation id="4450893287417543264">Ungabonisi futhi</translation>
<translation id="4451135742916150903">Ingacela ukuxhuma kumadivayisi we-HID</translation>
<translation id="4452328064229197696">Iphasiwedi osanda kuyisebenzisa itholakele ekwephuleni isivumelwano sedatha. Ukuze ivikele ama-akhawunti akho, i-Google Password Manager incoma ukuhlola amaphasiwedi akho alondoloziwe.</translation>
@@ -1150,6 +1185,7 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="4628948037717959914">Isithombe</translation>
<translation id="4631649115723685955">Imbuyiselo ixhunyanisiwe</translation>
<translation id="4636930964841734540">Ulwazi</translation>
+<translation id="4638670630777875591">I-Incognito ku-Chromium</translation>
<translation id="464342062220857295">Sesha izici</translation>
<translation id="4644670975240021822">I-oda elingemuva libheke phansi</translation>
<translation id="4646534391647090355">Ngimikise lapho manje</translation>
@@ -1170,6 +1206,7 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="4708268264240856090">Ukuxhumeka kwakho kuye kwaphazanyiswa</translation>
<translation id="4712404868219726379">I-Windows Hello</translation>
<translation id="4722547256916164131"><ph name="BEGIN_LINK" />Iqalisa ukuxilongwa kwenethiwekhi ye-Windows<ph name="END_LINK" /></translation>
+<translation id="4722735765955348426">Iphasiwedi ye-<ph name="USERNAME" /></translation>
<translation id="4724144314178270921">Ingacela ukubona umbhalo nezithombe ebhodini lakho lokunamathisela</translation>
<translation id="4726672564094551039">Phinda ulayishe izilungiselelo</translation>
<translation id="4728558894243024398">ingxenyekazi</translation>
@@ -1191,6 +1228,7 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="4757993714154412917">Usanda kufaka iphasiwedi yakho kusayithi elikhohlisayo. Ukuze uvikele ama-akhawunti akho, i-Chromium incoma ukuhlola amaphasiwedi akho alondoloziwe.</translation>
<translation id="4758311279753947758">Engeza imininingwane yokuxhumana</translation>
<translation id="4761104368405085019">Sebenzisa imakrofoni yakho</translation>
+<translation id="4761869838909035636">Yenza Ukuhlola kokuphepha kwe-Chrome</translation>
<translation id="4764776831041365478">Ikhasi lewebhu ku-<ph name="URL" /> kungenzeka ukuthi liphansi okwesikhashana noma lihanjiswe unaphakade kukheli elisha lewebhu.</translation>
<translation id="4766713847338118463">Ukunamathisela okubili phansi</translation>
<translation id="4771973620359291008">Kuvele iphutha elingaziwa.</translation>
@@ -1211,12 +1249,6 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="4819347708020428563">Hlela izichasiselo kukubuka kokuzenzakalelayo?</translation>
<translation id="4825496307559726072"><ph name="CREATE_GOOGLE_SHEET_FOCUSED_FRIENDLY_MATCH_TEXT" />, cindezela u-Tab bese u-Enter ukuze udale i-Google Sheet entsha ngokushesha</translation>
<translation id="4825507807291741242">Kunamandla</translation>
-<translation id="4827402517081186284">I-Incognito ayikwenzi ukuthi ubonakale ku-inthanethi:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Amasayithi ayabona lapho uwavakashela<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Abaqashi noma izikole bangakwazi ukulandelela umsebenzi woku-browser<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Abahlinzeki nge-inthanethi bangase bagade ithrafikhi yewebhu<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="483241715238664915">Vula izexwayiso</translation>
<translation id="4838327282952368871">I-Dreamy</translation>
<translation id="4840250757394056958">Buka umlando wakho we-Chrome</translation>
@@ -1228,12 +1260,12 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="4854362297993841467">Le ndlela yokulethwa ayitholakali. Zama indlela ehlukile.</translation>
<translation id="4854853140771946034">Dala inothi elisha ngokushesha ku-Google Keep</translation>
<translation id="485902285759009870">Iqinisekisa ikhodi...</translation>
+<translation id="4866506163384898554">Cindezela u-|<ph name="ACCELERATOR1" />| + |<ph name="ACCELERATOR2" />| ukuze ubonise i-cursor yakho</translation>
<translation id="4876188919622883022">Ukubuka okwenziwe lula</translation>
<translation id="4876305945144899064">Alikho igama lomsebenzisi</translation>
<translation id="4877083676943085827">{COUNT,plural, =0{Lutho}=1{<ph name="EXAMPLE_DOMAIN_1" />}=2{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />}one{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}other{<ph name="EXAMPLE_DOMAIN_1" />, <ph name="EXAMPLE_DOMAIN_2" />, <ph name="AND_MORE" />}}</translation>
<translation id="4877422487531841831"><ph name="TEXT" /> usesho</translation>
<translation id="4879491255372875719">Okuzenzakalelayo (okuzenzakalelayo)</translation>
-<translation id="4879725228911483934">Vula uphinde ubeke amawindi kuzikrini zakho</translation>
<translation id="4880827082731008257">Umlando wosesho</translation>
<translation id="4881695831933465202">Vula</translation>
<translation id="4885256590493466218">Khokha nge-<ph name="CARD_DETAIL" /> lapho usuqedela ukuthenga</translation>
@@ -1242,6 +1274,7 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
<translation id="4900217275619098670">Umqulu Wesishiyagalolunye</translation>
<translation id="4901778704868714008">Londoloza...</translation>
+<translation id="4905659621780993806">Umphathi wakho uzoqalisa idivayisi yakho ngokuzenzakalelayo ngo-<ph name="TIME" /> ngomhla ka-<ph name="DATE" />. Londoloza noma yiziphi izinto ezivuliwe ngaphambi kokuthi idivayisi yakho iqale kabusha.</translation>
<translation id="4913987521957242411">Ukushaya phezulu kwesokunxele</translation>
<translation id="4918221908152712722">Faka i-<ph name="APP_NAME" /> (akukho ukulandwa okudingekayo)</translation>
<translation id="4923459931733593730">Inkokhelo</translation>
@@ -1250,6 +1283,7 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="4929871932072157101"><ph name="KEYWORD_FOCUSED_FRIENDLY_MATCH_TEXT" />, cindezela Ithebhu bese u-Enter ukusesha</translation>
<translation id="4930153903256238152">Umthamo omkhulu</translation>
+<translation id="4940163644868678279">I-Incognito ku-Chrome</translation>
<translation id="4943872375798546930">Akukho miphumela</translation>
<translation id="4950898438188848926">Inkinobho yokushintshwa kwethebhu, cindezela okuthi Enter ukuze uguqukele kuthebhu evulekile, ye-<ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT" /></translation>
<translation id="495170559598752135">Izenzo</translation>
@@ -1259,6 +1293,7 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="4968522289500246572">Le app idizayinelwe iselula futhi ingase ingashintshi kahle usayizi. I-app ingase ibhekane nezinkinga noma iqale kabusha.</translation>
<translation id="4969341057194253438">Sula okurekhodiwe</translation>
<translation id="4973922308112707173">Ukushaya okubili phezulu</translation>
+<translation id="4976702386844183910">Ugcine ukuvakashela ngo-<ph name="DATE" /></translation>
<translation id="4984088539114770594">Sebenzisa imakrofoni?</translation>
<translation id="4984339528288761049">Prc5 (Envelope)</translation>
<translation id="4989163558385430922">Buka konke</translation>
@@ -1320,6 +1355,7 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="5138227688689900538">Bonisa okuncane</translation>
<translation id="5145883236150621069">Ikhodi yephutha ekhona kumpendulo yenqubomgomo</translation>
<translation id="5146995429444047494">Izaziso ze-<ph name="ORIGIN" /> zivinjelwe</translation>
+<translation id="514704532284964975">I-<ph name="URL" /> ifuna ukubona futhi iguqule ulwazi kumadivayisi e-NFC owathepha ngefoni yakho</translation>
<translation id="5148809049217731050">Bheke phezulu</translation>
<translation id="515292512908731282">C4 (Envelope)</translation>
<translation id="5158275234811857234">Ikhava</translation>
@@ -1344,6 +1380,7 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="5215116848420601511">Izindlela zokukhokha namakheli asebenzisa i-Google Pay</translation>
<translation id="5215363486134917902">Folio-Sp</translation>
<translation id="521659676233207110">Ithileyi 13</translation>
+<translation id="5216942107514965959">Kugcine ukuvakashelwa namuhla</translation>
<translation id="5222812217790122047">I-imeyili iyadingeka</translation>
<translation id="5230733896359313003">Ikheli lokuthumela</translation>
<translation id="5230815978613972521">B8</translation>
@@ -1364,7 +1401,6 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="5283044957620376778">B1</translation>
<translation id="5284295735376057059">Izakhiwo zedokhumenti</translation>
<translation id="528468243742722775">Qeda</translation>
-<translation id="5284909709419567258">Amakheli enethiwekhi</translation>
<translation id="5285570108065881030">Bonisa onke amaphasiwedi alondoloziwe</translation>
<translation id="5287240709317226393">Bonisa amakhukhhi</translation>
<translation id="5287456746628258573">Leli sayithi lisebenzisa ukulungiselelwa kokuvikela okuphelelwe isikhathi, okungaveza ulwazi lwakho (isibonelo, amaphasiwedi noma izinombolo zekhadi lesikweletu) uma lithunyelwa kuleli sayithi.</translation>
@@ -1448,6 +1484,7 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="5556459405103347317">Phinda ulayishe</translation>
<translation id="5560088892362098740">Idethi yokuphelelwa isikhathi</translation>
<translation id="55635442646131152">Uhlaka lwedokhumenti</translation>
+<translation id="5565613213060953222">Vula ithebhu ye-Incognito</translation>
<translation id="5565735124758917034">Kuyasebenza</translation>
<translation id="5570825185877910964">Vikela i-akhawunti</translation>
<translation id="5571083550517324815">Ayikwazi ukulanda kusukela kuleli kheli. Khetha ikheli elihlukile.</translation>
@@ -1530,6 +1567,7 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="5869522115854928033">Amaphasiwedi alondoloziwe</translation>
<translation id="5873013647450402046">Ibhange lakho lifuna ukuqinisekisa ukuthi nguwe.</translation>
<translation id="5887400589839399685">Ikhadi lilondoloziwe</translation>
+<translation id="5887687176710214216">Kugcine ukuvakashelwa izolo</translation>
<translation id="5895138241574237353">Qalisa kabusha</translation>
<translation id="5895187275912066135">Kukhishwe ku-</translation>
<translation id="5901630391730855834">Okuliphuzi</translation>
@@ -1543,6 +1581,7 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="5921639886840618607">Londoloza ikhadi ku-akhawunti ye-Google?</translation>
<translation id="5922853866070715753">Usuzoqeda</translation>
<translation id="5932224571077948991">Isayithi libonisa izikhangiso ezingathandeki noma ezidukisayo</translation>
+<translation id="5938153366081463283">Engeza ikhadi lokubuka</translation>
<translation id="5938793338444039872">U-Troy</translation>
<translation id="5946937721014915347">Ivula i-<ph name="SITE_NAME" />…</translation>
<translation id="5951495562196540101">Ayikwazi ukubhalisa nge-akhawunti yekhasimende (ilayisensi lephakheji liyatholakala).</translation>
@@ -1607,6 +1646,7 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="6120179357481664955">Khumbula i-UPI ID yakho?</translation>
<translation id="6124432979022149706">I-Chrome Enterprise Connectors</translation>
<translation id="6127379762771434464">Into isusiwe</translation>
+<translation id="6132161237766805930"><ph name="BEGIN_LINK" />Funda kabanzi nge-Incognito ku-Chrome<ph name="END_LINK" /></translation>
<translation id="6146055958333702838">Hlola noma yiziphi izintambo uphinde uqalise kabusha kunoma yimiphi imizila, amamodemu, noma amanye amadivayisi
wenethiwekhi okungahle ukuthi uyawasebenzisa.</translation>
<translation id="614940544461990577">Zama:</translation>
@@ -1619,7 +1659,6 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="6169916984152623906">Manje ungaphequlula ngasese, futhi abanye abantu abasebenzisa le divayisi ngeke bakwazi ukubona umsebenzi wakho. Kodwa, ukulandwa namabhukhimakhi kuzolondolozwa.</translation>
<translation id="6177128806592000436">Ukuxhumeka kwakho kuleli sayithi akuqinisekisiwe</translation>
<translation id="6180316780098470077">Izikhawu zokuzama futhi</translation>
-<translation id="619448280891863779">Angacela ukuvula nokubeka amawindi kuzikrini zakho</translation>
<translation id="6196640612572343990">Vimba amakhukhi enkampani yangaphandle</translation>
<translation id="6203231073485539293">Hlola ukuxhumeka kwakho kwe-inthanethi</translation>
<translation id="6218753634732582820">Susa ikheli kusukela ku-Chromium?</translation>
@@ -1642,7 +1681,7 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="6272383483618007430">Isibuyekezo se-Google</translation>
<translation id="6276112860590028508">Amakhasi kusukela kuhlu lwakho lokufunda avela lapha</translation>
<translation id="627746635834430766">Khokha ngokushesha ngesikhathi esizayo, londoloza ikheli lakho lokukhokha ku-akhawunti yakho ye-Google.</translation>
-<translation id="6279098320682980337">Inombolo yekhadi le-virtual ayifakwanga? Chofoza imininingwane yekhadi ukuze ukopishe</translation>
+<translation id="6279183038361895380">Cindezela u-|<ph name="ACCELERATOR" />| ukuze ubonise ikhesa lakho</translation>
<translation id="6280223929691119688">Ayikwazi ukuletha kuleli kheli. Khetha ikheli elihlukile.</translation>
<translation id="6282194474023008486">Ikhodi yeposi</translation>
<translation id="6285507000506177184">Phatha okudawunilodiwe kwinkinobho ye-Chrome, cindezela u-Enter ukuphatha amafayela owadawunilodile ku-Chrome</translation>
@@ -1650,6 +1689,7 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="6290238015253830360">Ama-athikili akho aphakanyisiwe avela lapha</translation>
<translation id="6293309776179964942">I-JIS B5</translation>
<translation id="6295618774959045776">I-CVC:</translation>
+<translation id="6300452962057769623">{0,plural, =0{Idivayisi yakho izoqala kabusha manje}=1{Idivayisi yakho izoqala kabusha ngomzuzwana o-1}one{Idivayisi yakho izoqala kabusha ngemizuzwana engu-#}other{Idivayisi yakho izoqala kabusha ngemizuzwana engu-#}}</translation>
<translation id="6302269476990306341">Umsizi we-Google ku-Chrome uyama</translation>
<translation id="6305205051461490394">I-<ph name="URL" /> ayifinyeleleki.</translation>
<translation id="6312113039770857350">Ikhasi lwebhu alitholakali</translation>
@@ -1723,6 +1763,7 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="6529602333819889595">&amp;Yenza futhi ukususa</translation>
<translation id="6545864417968258051">Ukuskena kwe-Bluetooth</translation>
<translation id="6547208576736763147">Ukushay okubili kwesokunxele</translation>
+<translation id="6554732001434021288">Kugcine ukuvakashelwa ezinsukwini ezi-<ph name="NUM_DAYS" /> ezedlule</translation>
<translation id="6556866813142980365">Yenza kabusha</translation>
<translation id="6569060085658103619">Ubuka ikhasi ngesandiso sekhasi</translation>
<translation id="6573200754375280815">Ukushaya okubili kwesokudla</translation>
@@ -1783,7 +1824,6 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="6757797048963528358">Idivayisi yakho iye yalala.</translation>
<translation id="6767985426384634228">Buyekeza Ikheli?</translation>
<translation id="6768213884286397650">Hagaki (Postcard)</translation>
-<translation id="6774185088257932239"><ph name="BEGIN_LINK" />Funda kabanzi<ph name="END_LINK" /> mayelana ne-Incognito</translation>
<translation id="6775759552199460396">I-JIS B2</translation>
<translation id="67862343314499040">Okuvayolethi</translation>
<translation id="6786747875388722282">Izandiso</translation>
@@ -1867,7 +1907,6 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="706295145388601875">Engeza futhi phatha amakheli kumasethingi we-Chrome</translation>
<translation id="7064851114919012435">Ulwazi loxhumana naye</translation>
<translation id="7068733155164172741">Faka ikhodi enezinombolo ezingu-<ph name="OTP_LENGTH" /></translation>
-<translation id="7070090581017165256">Mayelana naleli sayithi</translation>
<translation id="70705239631109039">Uxhumano lwakho aluvikelekile ngokuphelele</translation>
<translation id="7075452647191940183">Isicelo sikhulu kakhulu</translation>
<translation id="7079718277001814089">Leli sayithi liqukethe uhlelo olungayilungele ikhompyutha</translation>
@@ -1884,6 +1923,12 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="7111012039238467737">(Lungile)</translation>
<translation id="7118618213916969306">Sesha i-URL yeklibhodi, <ph name="SHORT_URL" /></translation>
<translation id="7119414471315195487">Vala amanye amathebhu noma izinhlelo</translation>
+<translation id="7129355289156517987">Lapho uvala wonke amathebhu we-Incognito Chromium, umsebenzi wakho uyasulwa kusuka kule divayisi:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Umsebenzi wokuphequlula<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Umlando wokusesha<ph name="END_LIST_ITEM" />
+ <ph name="LIST_ITEM" />Ulwazi olufakwa kumafomu<ph name="END_LIST_ITEM" />
+ <ph name="END_LIST" /></translation>
<translation id="7129409597930077180">Ayikwazi ukuthumela kuleli kheli. Khetha ikheli elihlukile.</translation>
<translation id="7132939140423847331">Umphathi wakho uvimbele ukuthi le datha ikopishwe.</translation>
<translation id="7135130955892390533">Bonisa isimo</translation>
@@ -1906,6 +1951,7 @@ Lokhu uma kungenjalo kuzovinjelwa izilungiselelo zakho zobumfihlo. Lokhu kuzovum
<translation id="7192203810768312527">Khulula u-<ph name="SIZE" />. Amanye amasayihi angalayisha kancane Some sites may load more slowly on your next visit.</translation>
<translation id="719464814642662924">I-Visa</translation>
<translation id="7201591969684833065">Umlawuli wakho angabona:</translation>
+<translation id="7202217080450895452"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, cindezela u-Tab bese u-Enter ukuze uvule ithebhu ye-Incognito entsha yokubhrawuza ngokugodliwe</translation>
<translation id="7202346780273620635">Letter-Extra</translation>
<translation id="7210863904660874423">I-<ph name="HOST_NAME" /> ayithobeli amazinga ezokuvikela.</translation>
<translation id="7210993021468939304">Umsebenzi we-Linux ungaphakathi kwesiqukathi, futhi ungafaka uphinde uqalise izinhlelo zokusebenza ze-Linux ngaphakathi kwesiqukathi</translation>
@@ -1937,6 +1983,7 @@ Imininingwane engeziwe:
<translation id="7304562222803846232">Phatha amasethingi obumfihlo e-Google Account</translation>
<translation id="7305756307268530424">Qala kabuthaka</translation>
<translation id="7308436126008021607">ukuvumelanisa ingemuva</translation>
+<translation id="7310392214323165548">Idivayisi izoqala kabusha maduze nje</translation>
<translation id="7319430975418800333">A3</translation>
<translation id="7320336641823683070">Usizo lokuxhumana</translation>
<translation id="7323804146520582233">Fihla isigaba se-"<ph name="SECTION" />"</translation>
@@ -1944,6 +1991,7 @@ Imininingwane engeziwe:
<translation id="7334320624316649418">&amp;Yenza futhi ukuhlela kabusha</translation>
<translation id="7335157162773372339">Ingase icele ukusebenzisa ikhamera yakho</translation>
<translation id="7337248890521463931">Bonisa imigqa eminingi</translation>
+<translation id="7337418456231055214">Inombolo yekhadi elibonakalayo ayigcwalisiwe? Chofoza imininingwane yekhadi ukuze ukopishe. <ph name="IDS_AUTOFILL_VIRTUAL_CARD_MANUAL_FALLBACK_BUBBLE_LEARN_MORE_LINK_LABEL" /></translation>
<translation id="7337706099755338005">Akutholakali kungxenyekazi yakho.</translation>
<translation id="733923710415886693">Isitifiketi seseva asizange sidalulwe ngokubonisa ngale kwesitifiketi.</translation>
<translation id="734600844861828519">11x15</translation>
@@ -1966,6 +2014,7 @@ Imininingwane engeziwe:
<translation id="7378627244592794276">Cha</translation>
<translation id="7378810950367401542">/</translation>
<translation id="7386364858855961704">Akusebenzi</translation>
+<translation id="7388594495505979117">{0,plural, =1{Idivayisi yakho izoqala kabusha emzuzwini o-1}one{Idivayisi yakho izoqala kabusha emizuzwini engu-#f}other{Idivayisi yakho izoqala kabusha emizuzwini engu-#f}}</translation>
<translation id="7390545607259442187">Qinisekisa ikhadi</translation>
<translation id="7392089738299859607">Buyekeza Ikheli</translation>
<translation id="7399802613464275309">Ukuhlola kokuphepha</translation>
@@ -2002,6 +2051,12 @@ Imininingwane engeziwe:
<translation id="7485870689360869515">Ayikho idatha etholiwe.</translation>
<translation id="7495528107193238112">Lokhu okuqukethwe kuvinjelwe. Xhumana nomnikazi wesayithi ukulungisa inkinga.</translation>
<translation id="7497998058912824456">Inkinobo yokudala idokhumenti, cindezela u-Enter ukuze udale i-Google Doc entsha ngokushesha</translation>
+<translation id="7506488012654002225">I-Chromium <ph name="BEGIN_EMPHASIS" />ngeke ilondoloze<ph name="END_EMPHASIS" /> ulwazi olulandelayo:
+ <ph name="BEGIN_LIST" />
+ <ph name="LIST_ITEM" />Umlando wakho wokuphequlula
+ <ph name="LIST_ITEM" />Amakhukhi nedatha yesayithi
+ <ph name="LIST_ITEM" />Ulwazi olufakwe kumafomu
+ <ph name="END_LIST" /></translation>
<translation id="7508255263130623398">Inqubogomo yokubuyisa idivayisi ayinalutho noma ayifani ne-id yedivayisi yamanje</translation>
<translation id="7508870219247277067">I-Avocado Green</translation>
<translation id="7511955381719512146">I-Wi-Fi oyisebenzisayo ingadinga ukuthi uvakashele ku-<ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" />.</translation>
@@ -2115,7 +2170,6 @@ Imininingwane engeziwe:
<translation id="7813600968533626083">Susa kusuka kusiphakamiso kusuka ku-Chrome?</translation>
<translation id="781440967107097262">Yabelana ngebhodi yokunamathisela?</translation>
<translation id="7815407501681723534">Kutholakele <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> kwe-'<ph name="SEARCH_STRING" />'</translation>
-<translation id="782125616001965242">Bonisa ulwazi olumayelana naleli sayithi</translation>
<translation id="782886543891417279">I-Wi-Fi oyisebenzisayo (<ph name="WIFI_NAME" />) ingadinga ukuthi uvakashele ikhasi layo lokungena ngemvume.</translation>
<translation id="7836231406687464395">Postfix (Envelope)</translation>
<translation id="7844689747373518809">{COUNT,plural, =0{Lutho}=1{1 uhlelo lokusebenza (<ph name="EXAMPLE_APP_1" />)}=2{2 izinhlelo zokusebenza (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />)}one{# izinhlelo zokusebenza (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}other{# izinhlelo zokusebenza (<ph name="EXAMPLE_APP_1" />, <ph name="EXAMPLE_APP_2" />, <ph name="AND_MORE" />)}}</translation>
@@ -2132,7 +2186,6 @@ Imininingwane engeziwe:
<translation id="7888575728750733395">Phrinta inhloso yokunikezela</translation>
<translation id="7894280532028510793">Uma isipelingi singalungile, <ph name="BEGIN_LINK" />zama ukuqalisa Ukuxilongwa Kwenethiwekhi<ph name="END_LINK" />.</translation>
<translation id="7904208859782148177">C3 (Envelope)</translation>
-<translation id="7931318309563332511">Akwaziwa</translation>
<translation id="793209273132572360">Buyekeza ikheli?</translation>
<translation id="7932579305932748336">Ibhantshi</translation>
<translation id="79338296614623784">Faka inombolo yefoni evumelekile</translation>
@@ -2157,13 +2210,14 @@ Imininingwane engeziwe:
<translation id="7976214039405368314">Izicelo eziningi kakhulu</translation>
<translation id="7977538094055660992">Idivaysi yokukhishwayo</translation>
<translation id="7977894662897852582">Edp</translation>
+<translation id="7981260203882740562">Ilinkwe ne-</translation>
<translation id="798134797138789862">Amasayithi angacela ukusebenzisa amadivayisi ento engekho ngokoqobo nedatha</translation>
<translation id="7984945080620862648">Ngeke ukwazi ukuvakashela i-<ph name="SITE" /> njengamanje ngoba iwebhusayithi ithumele izifakazelo ezihlukanisiwe i-Chrome engeke ikwazi ukuzisebenzisa. Ngokuvamile amaphutha enethiwekhi nokuhlasela kungokwesikhashana, ngakho-ke leli khasi lingase lisebenze futhi ngemva kwesikhathi.</translation>
-<translation id="79859296434321399">Ukuze ubuke okuqukethwe kwe-augmented reality, faka i-ARCore</translation>
<translation id="7986319120639858961"><ph name="CARD_TITLE" /> <ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="799149739215780103">Ukubophezela</translation>
<translation id="7992044431894087211">Ukwabelana ngesikrini ne-<ph name="APPLICATION_TITLE" /> kuqhubekisiwe</translation>
<translation id="7995512525968007366">Akucacisiwe</translation>
+<translation id="7998269595945679889">Vula inkinobho yethebhu ye-Incognito, cindezela u-Enter ukuze uvule ithebhu ye-Incognito entsha ukubhrawuza ngokugodliwe</translation>
<translation id="800218591365569300">Zama ukuvala amanye amathebhu noma izinhlelo ukuze ukhulule imemori.</translation>
<translation id="8004582292198964060">Isiphequluli</translation>
<translation id="8012116502927253373">{NUM_CARDS,plural, =1{Leli khadi nekheli lalo lokukhokhisa kuzolondolozwa. Uzokwazi ukulisebenzisa uma ungene ngemvume ku-<ph name="USER_EMAIL" />.}one{Lawa makhadi namakheli okukhokhisa kuzolondolozwa. Uzokwazi ukuwasebenzisa uma ungene ngemvume ku-<ph name="USER_EMAIL" />.}other{Lawa makhadi namakheli okukhokhisa kuzolondolozwa. Uzokwazi ukuwasebenzisa uma ungene ngemvume ku-<ph name="USER_EMAIL" />.}}</translation>
@@ -2223,6 +2277,7 @@ Imininingwane engeziwe:
<translation id="8202370299023114387">Ingxabano</translation>
<translation id="8206978196348664717">Prc4 (Envelope)</translation>
<translation id="8211406090763984747">Ukuxhumeka kuvikelekile</translation>
+<translation id="8217240300496046857">Amasayithi awakwazi ukusebenzisa amakhukhi akulandelelayo kuwebhu yonkana. Izici ezikwamanye amasayithi zingase zinqamuke.</translation>
<translation id="8218327578424803826">Indawo enikeziwe:</translation>
<translation id="8220146938470311105">C7/C6 (Envelope)</translation>
<translation id="8225771182978767009">Umuntu osethe le khompuyutha ukhethe ukuvimbela leli sayithi.</translation>
@@ -2263,14 +2318,9 @@ Imininingwane engeziwe:
<translation id="830498451218851433">Goqa ngohafu</translation>
<translation id="8307358339886459768">Isithombe esincane</translation>
<translation id="8307888238279532626">Izinhlelo zokusebenza ezifakiwe nokuthi zisetshenziswa kaningi kangakanani</translation>
+<translation id="8317207217658302555">Buyekeza i-ARCore?</translation>
<translation id="831997045666694187">Kusihlwa</translation>
<translation id="8321476692217554900">izaziso</translation>
-<translation id="8328484624016508118">Ngemva kokuvala wonke amathebhu we-Incognito, i-Chrome isula:
- <ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" />Umsebenzi wakho woku-browser kule divayisi<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Umlando wakho wokusesha kule divayisi<ph name="END_LIST_ITEM" />
- <ph name="LIST_ITEM" />Ulwazi olufakwe kumafomu<ph name="END_LIST_ITEM" />
- <ph name="END_LIST" /></translation>
<translation id="8332188693563227489">Ukufinyelela ku-<ph name="HOST_NAME" /> kunqatshelwe</translation>
<translation id="833262891116910667">Gqamisa</translation>
<translation id="8339163506404995330">Amakhasi ngesi-<ph name="LANGUAGE" /> ngeke ahumushwe</translation>
@@ -2322,6 +2372,7 @@ Imininingwane engeziwe:
<translation id="8507227106804027148">Umugqa womyalo</translation>
<translation id="8508648098325802031">Isithonjana sosesho</translation>
<translation id="8511402995811232419">Phatha amakhukhi</translation>
+<translation id="8519753333133776369">Idivayisi ye-HID evunyelwe umlawuli wakho</translation>
<translation id="8522552481199248698">I-Chrome ingakusiza uvikele i-akhawunti yakho ye-Google uphinde ushintshe iphasiwedi yakho.</translation>
<translation id="8530813470445476232">Sula umlando wakho wokuphequlula, amakhukhi, inqolobane, nokuningi kumasethingi we-Chrome</translation>
<translation id="8533619373899488139">Vakashela ku-&lt;strong&gt;chrome://policy&lt;/strong&gt; ukuze ubone uhlu lwama-URL avinjiwe nezinye izinqubomgomo eziphoqwa ngumlawuli wesistimu yakho.</translation>
@@ -2333,7 +2384,6 @@ Imininingwane engeziwe:
<translation id="8554912124839363479">{NUM_PERMISSIONS,plural, =1{Setha kabusha imvume}one{Setha kabusha izimvume}other{Setha kabusha izimvume}}</translation>
<translation id="8555010941760982128">Sebenzisa le khodi ekuphumeni</translation>
<translation id="8557066899867184262">I-CVC isemuva kwekhadi lakho.</translation>
-<translation id="8558485628462305855">Ukuze ubuke okuqukethwe kwe-augmented reality, buyekeza i-ARCore</translation>
<translation id="8559762987265718583">Uxhumano oluyimfihlo oluya ku-<ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> alukwazi ukusungulwa ngoba idethi nesikhathi sedivayisi yakho (<ph name="DATE_AND_TIME" />) azilungile.</translation>
<translation id="8564182942834072828">Amadokhumenti ahlukene/Amakhophi angaqathaniswanga</translation>
<translation id="8564985650692024650">I-Chromium incoma ukusetha kabusha iphasiwedi yakho ye-<ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> uma uphinde wayisebenzisa kwamanye amasayithi.</translation>
@@ -2352,6 +2402,7 @@ Imininingwane engeziwe:
<translation id="865032292777205197">izinzwa zokunyakaza</translation>
<translation id="8663226718884576429">Isifinyezo se-oda, <ph name="TOTAL_LABEL" />, Imininingwane eminingi</translation>
<translation id="8666678546361132282">I-English</translation>
+<translation id="8669306706049782872">Sebenzisa ulwazi olumayelana nezikrini zakho ukuze uvule futhi ubeke amawindi</translation>
<translation id="867224526087042813">Isiginesha</translation>
<translation id="8676424191133491403">Akukho ukulibazisa</translation>
<translation id="8680536109547170164">I-<ph name="QUERY" />, phendula, <ph name="ANSWER" /></translation>
@@ -2378,6 +2429,7 @@ Imininingwane engeziwe:
<translation id="8731544501227493793">Inkinobho yokuphatha amaphasiwedi, cindezela u-Enter ukuze ubuke futhi uphathe amaphasiwedi akho kumasethingi e-Chrome</translation>
<translation id="8734529307927223492">I-<ph name="DEVICE_TYPE" /> yakho iphethwe ngu-<ph name="MANAGER" /></translation>
<translation id="8737134861345396036"><ph name="LAUNCH_INCOGNITO_FOCUSED_FRIENDLY_MATCH_TEXT" />, cindezela u-Tab bese u-Enter ukuze uvule iwindi le-incognito elisha lokuphequlula ngokuyimfihlo</translation>
+<translation id="8737685506611670901">Vula izixhumanisi ze-<ph name="PROTOCOL" /> esikhundleni se-<ph name="REPLACED_HANDLER_TITLE" /></translation>
<translation id="8738058698779197622">Ukuze usungule ukuxhumeka okuvikelekile, iwashi lakho lidinga ukusethwa ngokulungile. Lokhu yingenxa yokuthi izitifiketi ezisetshenziswa ngamawebhusayithi ukuzikhomba zivumeleke ngezikhathi ezithile kuphela. Njengoba iwashi ledivayisi yakho lingalungile, i-Chromium ayikwazi ukuqinisekisa lezi zitifiketi.</translation>
<translation id="8740359287975076522">Ikheli le-<ph name="HOST_NAME" /> &lt;abbr id="dnsDefinition"&gt;le-DNS&lt;/abbr&gt; alikwazanga ukutholwa. Xilonga inkinga.</translation>
<translation id="8742371904523228557">I-<ph name="ONE_TIME_CODE" /> ikhodi yakho ye-<ph name="ORIGIN" /></translation>
@@ -2405,6 +2457,7 @@ Imininingwane engeziwe:
<translation id="883848425547221593">Amanye amabhukhimakhi</translation>
<translation id="884264119367021077">Ikheli lokuthumela</translation>
<translation id="884923133447025588">Ayikho indlela yokuhoxisa etholiwe.</translation>
+<translation id="8849262850971482943">Sebenzisa ikhadi lakho elibonakalayo mayelana nokuphepha okungeziwe</translation>
<translation id="885730110891505394">Yabelana ne-Google</translation>
<translation id="8858065207712248076">I-Chrome incoma ukusetha kabusha iphasiwedi yakho ye-<ph name="BEGIN_BOLD" /><ph name="ORG_NAME" /><ph name="END_BOLD" /> uma uphinde wayisebenzisa kwamanye amasayithi.</translation>
<translation id="885906927438988819">Uma isipelingi singalungile, <ph name="BEGIN_LINK" />zama ukuqalisa Ukuxilongwa Kwenethiwekhi ye-Windows<ph name="END_LINK" />.</translation>
@@ -2454,6 +2507,7 @@ Imininingwane engeziwe:
<translation id="9004367719664099443">Isikhathi se-VR siyaqhubeka</translation>
<translation id="9005998258318286617">Yehlulekile ukulayisha idokhumenti ye-PDF.</translation>
<translation id="9008201768610948239">Ziba</translation>
+<translation id="901834265349196618">i-imeyili</translation>
<translation id="9020200922353704812">Ikheli lokukhokhisa ikhadi liyadingeka</translation>
<translation id="9020542370529661692">Leli khasi lihunyushelwe ku-<ph name="TARGET_LANGUAGE" /></translation>
<translation id="9020742383383852663">A8</translation>
@@ -2502,6 +2556,7 @@ Imininingwane engeziwe:
<translation id="9150045010208374699">Sebenzisa ikhamela yakho</translation>
<translation id="9150685862434908345">Umlawuli wakho angaguqula ukusethwa kwesiphequluli sakho akude. Umsebenzi kule divayisi ungaphinda aphathwe ngaphandle kwe-Chrome. <ph name="BEGIN_LINK" />Funda kabanzi<ph name="END_LINK" /></translation>
<translation id="9154194610265714752">Kubuyekeziwe</translation>
+<translation id="9155211586651734179">Ama-peripheral wokulalelwayo anamathiselwe</translation>
<translation id="9157595877708044936">Iyasetha...</translation>
<translation id="9158625974267017556">C6 (Envelope)</translation>
<translation id="9164029392738894042">Ukuhlola Ukunemba</translation>
diff --git a/chromium/components/subresource_filter/content/browser/BUILD.gn b/chromium/components/subresource_filter/content/browser/BUILD.gn
index 426f4edc659..d36c1aae306 100644
--- a/chromium/components/subresource_filter/content/browser/BUILD.gn
+++ b/chromium/components/subresource_filter/content/browser/BUILD.gn
@@ -147,6 +147,9 @@ static_library("test_support") {
"//components/safe_browsing/core/browser/db:test_database_manager",
"//components/safe_browsing/core/browser/db:util",
]
+ if (is_android) {
+ deps += [ "//components/messages/android:test_support" ]
+ }
}
source_set("unit_tests") {
diff --git a/chromium/components/subresource_filter/content/browser/DEPS b/chromium/components/subresource_filter/content/browser/DEPS
index 28c166219fd..ed4823b1512 100644
--- a/chromium/components/subresource_filter/content/browser/DEPS
+++ b/chromium/components/subresource_filter/content/browser/DEPS
@@ -2,6 +2,8 @@ include_rules = [
"+components/content_settings/browser",
"+components/content_settings/core/browser",
"+components/content_settings/core/common",
+ # TODO(bokan): Remove after investigating for crbug.com/1264667.
+ "+components/crash/core/common/crash_key.h",
"+components/infobars",
"+components/messages",
"+components/resources",
diff --git a/chromium/components/subresource_filter/content/browser/ads_blocked_message_delegate.cc b/chromium/components/subresource_filter/content/browser/ads_blocked_message_delegate.cc
index 52f6cef4dce..bb298bf2aa9 100644
--- a/chromium/components/subresource_filter/content/browser/ads_blocked_message_delegate.cc
+++ b/chromium/components/subresource_filter/content/browser/ads_blocked_message_delegate.cc
@@ -85,6 +85,11 @@ void AdsBlockedMessageDelegate::DismissMessage(
}
}
+void AdsBlockedMessageDelegate::DismissMessageForTesting(
+ messages::DismissReason dismiss_reason) {
+ HandleMessageDismissed(dismiss_reason);
+}
+
AdsBlockedMessageDelegate::AdsBlockedMessageDelegate(
content::WebContents* web_contents)
: AdsBlockedMessageDelegate(web_contents,
diff --git a/chromium/components/subresource_filter/content/browser/ads_blocked_message_delegate.h b/chromium/components/subresource_filter/content/browser/ads_blocked_message_delegate.h
index 3c51675bb18..6bc8ce7e699 100644
--- a/chromium/components/subresource_filter/content/browser/ads_blocked_message_delegate.h
+++ b/chromium/components/subresource_filter/content/browser/ads_blocked_message_delegate.h
@@ -47,6 +47,8 @@ class AdsBlockedMessageDelegate
void ShowMessage();
void DismissMessage(messages::DismissReason dismiss_reason);
+ void DismissMessageForTesting(messages::DismissReason dismiss_reason);
+
messages::MessageWrapper* message_for_testing() { return message_.get(); }
bool reprompt_required_flag_for_testing() { return reprompt_required_; }
diff --git a/chromium/components/subresource_filter/content/browser/ads_intervention_manager.cc b/chromium/components/subresource_filter/content/browser/ads_intervention_manager.cc
index edf220ce209..8c5fcff3ffa 100644
--- a/chromium/components/subresource_filter/content/browser/ads_intervention_manager.cc
+++ b/chromium/components/subresource_filter/content/browser/ads_intervention_manager.cc
@@ -92,17 +92,16 @@ AdsInterventionManager::GetLastAdsIntervention(const GURL& url) const {
if (!dict)
return absl::nullopt;
- int ads_violation;
+ absl::optional<int> ads_violation = dict->FindIntKey(kLastAdsViolationKey);
absl::optional<double> last_violation_time =
dict->FindDoubleKey(kLastAdsViolationTimeKey);
- if (dict->GetInteger(kLastAdsViolationKey, &ads_violation) &&
- last_violation_time) {
+ if (ads_violation && last_violation_time) {
base::TimeDelta diff =
clock_->Now() - base::Time::FromDoubleT(*last_violation_time);
return LastAdsIntervention(
- {diff, static_cast<mojom::AdsViolation>(ads_violation)});
+ {diff, static_cast<mojom::AdsViolation>(*ads_violation)});
}
return absl::nullopt;
diff --git a/chromium/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.h b/chromium/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.h
index b870380abf8..3d7a1cbccd0 100644
--- a/chromium/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.h
+++ b/chromium/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.h
@@ -96,7 +96,7 @@ class ContentSubresourceFilterThrottleManager
: public base::SupportsUserData::Data,
public mojom::SubresourceFilterHost {
public:
- static constexpr int kUserDataKey = 0;
+ static const int kUserDataKey = 0;
// Binds a remote in the given RenderFrame to the correct
// ContentSubresourceFilterThrottleManager in the browser.
@@ -166,6 +166,10 @@ class ContentSubresourceFilterThrottleManager
PageLoadStatistics* page_load_statistics() const { return statistics_.get(); }
+ ProfileInteractionManager* profile_interaction_manager_for_testing() {
+ return profile_interaction_manager_.get();
+ }
+
VerifiedRuleset::Handle* ruleset_handle_for_testing() {
return ruleset_handle_.get();
}
diff --git a/chromium/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager_unittest.cc b/chromium/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager_unittest.cc
index e58ade0a77a..5ea700d29a2 100644
--- a/chromium/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager_unittest.cc
+++ b/chromium/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager_unittest.cc
@@ -29,6 +29,7 @@
#include "components/subresource_filter/content/browser/async_document_subresource_filter.h"
#include "components/subresource_filter/content/browser/content_subresource_filter_web_contents_helper.h"
#include "components/subresource_filter/content/browser/fake_safe_browsing_database_manager.h"
+#include "components/subresource_filter/content/browser/profile_interaction_manager.h"
#include "components/subresource_filter/content/browser/subframe_navigation_test_utils.h"
#include "components/subresource_filter/content/browser/subresource_filter_observer_manager.h"
#include "components/subresource_filter/content/browser/throttle_manager_test_support.h"
@@ -54,6 +55,11 @@
#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
#include "url/url_constants.h"
+#if BUILDFLAG(IS_ANDROID)
+#include "components/messages/android/mock_message_dispatcher_bridge.h"
+#include "components/subresource_filter/content/browser/ads_blocked_message_delegate.h"
+#endif
+
namespace subresource_filter {
namespace proto = url_pattern_index::proto;
@@ -242,6 +248,12 @@ class ContentSubresourceFilterThrottleManagerTest
Observe(web_contents);
NavigateAndCommit(GURL("https://example.first"));
+
+#if BUILDFLAG(IS_ANDROID)
+ message_dispatcher_bridge_.SetMessagesEnabledForEmbedder(true);
+ messages::MessageDispatcherBridge::SetInstanceForTesting(
+ &message_dispatcher_bridge_);
+#endif
}
void TearDown() override {
@@ -249,6 +261,9 @@ class ContentSubresourceFilterThrottleManagerTest
dealer_handle_.reset();
base::RunLoop().RunUntilIdle();
content::RenderViewHostTestHarness::TearDown();
+#if BUILDFLAG(IS_ANDROID)
+ messages::MessageDispatcherBridge::SetInstanceForTesting(nullptr);
+#endif
}
void ExpectActivationSignalForFrame(
@@ -303,6 +318,15 @@ class ContentSubresourceFilterThrottleManagerTest
return throttle_manager()->ruleset_handle_for_testing();
}
+#if BUILDFLAG(IS_ANDROID)
+ void SimulateMessageDismissal() {
+ throttle_manager()
+ ->profile_interaction_manager_for_testing()
+ ->ads_blocked_message_delegate_for_testing()
+ ->DismissMessageForTesting(messages::DismissReason::SCOPE_DESTROYED);
+ }
+#endif
+
bool ads_blocked_in_content_settings() {
auto* content_settings =
content_settings::PageSpecificContentSettings::GetForFrame(
@@ -311,22 +335,6 @@ class ContentSubresourceFilterThrottleManagerTest
return content_settings->IsContentBlocked(ContentSettingsType::ADS);
}
- bool presenting_ads_blocked_infobar() {
- auto* infobar_manager = infobars::ContentInfoBarManager::FromWebContents(
- content::RenderViewHostTestHarness::web_contents());
- if (infobar_manager->infobar_count() == 0)
- return false;
-
- // No infobars other than the ads blocked infobar should be displayed in the
- // context of these tests.
- EXPECT_EQ(infobar_manager->infobar_count(), 1u);
- auto* infobar = infobar_manager->infobar_at(0);
- EXPECT_EQ(infobar->delegate()->GetIdentifier(),
- infobars::InfoBarDelegate::ADS_BLOCKED_INFOBAR_DELEGATE_ANDROID);
-
- return true;
- }
-
protected:
// content::WebContentsObserver
void RenderFrameCreated(content::RenderFrameHost* new_host) override {
@@ -397,6 +405,10 @@ class ContentSubresourceFilterThrottleManagerTest
return dealer_handle_.get();
}
+#if BUILDFLAG(IS_ANDROID)
+ messages::MockMessageDispatcherBridge message_dispatcher_bridge_;
+#endif
+
private:
ContentSubresourceFilterWebContentsHelper* web_contents_helper() {
return ContentSubresourceFilterWebContentsHelper::FromWebContents(
@@ -430,22 +442,26 @@ TEST_P(ContentSubresourceFilterThrottleManagerTest,
ExpectActivationSignalForFrame(main_rfh(), true /* expect_activation */);
// A disallowed subframe navigation should be successfully filtered.
+#if BUILDFLAG(IS_ANDROID)
+ EXPECT_CALL(message_dispatcher_bridge_, EnqueueMessage);
+#endif
CreateSubframeWithTestNavigation(
GURL("https://www.example.com/disallowed.html"), main_rfh());
EXPECT_EQ(content::NavigationThrottle::BLOCK_REQUEST_AND_COLLAPSE,
SimulateStartAndGetResult(navigation_simulator()));
EXPECT_TRUE(ads_blocked_in_content_settings());
-#if defined(OS_ANDROID)
- EXPECT_TRUE(presenting_ads_blocked_infobar());
+#if BUILDFLAG(IS_ANDROID)
+ ::testing::Mock::VerifyAndClearExpectations(&message_dispatcher_bridge_);
#endif
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
TEST_P(ContentSubresourceFilterThrottleManagerTest,
- NoCrashWhenInfoBarManagerIsNotPresent) {
+ NoCrashWhenMessageDelegateIsNotPresent) {
auto* web_contents = RenderViewHostTestHarness::web_contents();
- web_contents->RemoveUserData(infobars::ContentInfoBarManager::UserDataKey());
+ web_contents->RemoveUserData(
+ subresource_filter::AdsBlockedMessageDelegate::UserDataKey());
// Commit a navigation that triggers page level activation.
NavigateAndCommitMainFrame(GURL(kTestURLWithActivation));
@@ -473,13 +489,16 @@ TEST_P(ContentSubresourceFilterThrottleManagerTest, NoPageActivation) {
EXPECT_FALSE(ManagerHasRulesetHandle());
// A disallowed subframe navigation should not be filtered.
+#if BUILDFLAG(IS_ANDROID)
+ EXPECT_CALL(message_dispatcher_bridge_, EnqueueMessage).Times(0);
+#endif
CreateSubframeWithTestNavigation(
GURL("https://www.example.com/disallowed.html"), main_rfh());
EXPECT_EQ(content::NavigationThrottle::PROCEED,
SimulateCommitAndGetResult(navigation_simulator()));
EXPECT_FALSE(ads_blocked_in_content_settings());
-#if defined(OS_ANDROID)
- EXPECT_FALSE(presenting_ads_blocked_infobar());
+#if BUILDFLAG(IS_ANDROID)
+ ::testing::Mock::VerifyAndClearExpectations(&message_dispatcher_bridge_);
#endif
}
@@ -490,6 +509,9 @@ TEST_P(ContentSubresourceFilterThrottleManagerTest,
ExpectActivationSignalForFrame(main_rfh(), true /* expect_activation */);
// A disallowed subframe navigation should not be filtered in dry-run mode.
+#if BUILDFLAG(IS_ANDROID)
+ EXPECT_CALL(message_dispatcher_bridge_, EnqueueMessage).Times(0);
+#endif
CreateSubframeWithTestNavigation(
GURL("https://www.example.com/disallowed.html"), main_rfh());
EXPECT_EQ(content::NavigationThrottle::PROCEED,
@@ -503,8 +525,8 @@ TEST_P(ContentSubresourceFilterThrottleManagerTest,
true /* is_ad_subframe */);
EXPECT_FALSE(ads_blocked_in_content_settings());
-#if defined(OS_ANDROID)
- EXPECT_FALSE(presenting_ads_blocked_infobar());
+#if BUILDFLAG(IS_ANDROID)
+ ::testing::Mock::VerifyAndClearExpectations(&message_dispatcher_bridge_);
#endif
}
@@ -516,6 +538,9 @@ TEST_P(ContentSubresourceFilterThrottleManagerTest,
// A disallowed subframe navigation via redirect should be successfully
// filtered.
+#if BUILDFLAG(IS_ANDROID)
+ EXPECT_CALL(message_dispatcher_bridge_, EnqueueMessage);
+#endif
CreateSubframeWithTestNavigation(
GURL("https://www.example.com/before-redirect.html"), main_rfh());
EXPECT_EQ(content::NavigationThrottle::PROCEED,
@@ -525,8 +550,8 @@ TEST_P(ContentSubresourceFilterThrottleManagerTest,
navigation_simulator(),
GURL("https://www.example.com/disallowed.html")));
EXPECT_TRUE(ads_blocked_in_content_settings());
-#if defined(OS_ANDROID)
- EXPECT_TRUE(presenting_ads_blocked_infobar());
+#if BUILDFLAG(IS_ANDROID)
+ ::testing::Mock::VerifyAndClearExpectations(&message_dispatcher_bridge_);
#endif
}
@@ -537,6 +562,9 @@ TEST_P(ContentSubresourceFilterThrottleManagerTest,
ExpectActivationSignalForFrame(main_rfh(), true /* expect_activation */);
// An allowed subframe navigation should complete successfully.
+#if BUILDFLAG(IS_ANDROID)
+ EXPECT_CALL(message_dispatcher_bridge_, EnqueueMessage).Times(0);
+#endif
CreateSubframeWithTestNavigation(
GURL("https://www.example.com/allowed1.html"), main_rfh());
EXPECT_EQ(content::NavigationThrottle::PROCEED,
@@ -552,8 +580,8 @@ TEST_P(ContentSubresourceFilterThrottleManagerTest,
ExpectActivationSignalForFrame(child, true /* expect_activation */);
EXPECT_FALSE(ads_blocked_in_content_settings());
-#if defined(OS_ANDROID)
- EXPECT_FALSE(presenting_ads_blocked_infobar());
+#if BUILDFLAG(IS_ANDROID)
+ ::testing::Mock::VerifyAndClearExpectations(&message_dispatcher_bridge_);
#endif
}
@@ -566,15 +594,15 @@ TEST_P(ContentSubresourceFilterThrottleManagerTest,
ExpectActivationSignalForFrame(main_rfh(), true /* expect_activation */);
// A disallowed subframe navigation should be successfully filtered.
+#if BUILDFLAG(IS_ANDROID)
+ EXPECT_CALL(message_dispatcher_bridge_, EnqueueMessage);
+#endif
CreateSubframeWithTestNavigation(
GURL("https://www.example.com/1/disallowed.html"), main_rfh());
EXPECT_EQ(content::NavigationThrottle::BLOCK_REQUEST_AND_COLLAPSE,
SimulateStartAndGetResult(navigation_simulator()));
EXPECT_TRUE(ads_blocked_in_content_settings());
-#if defined(OS_ANDROID)
- EXPECT_TRUE(presenting_ads_blocked_infobar());
-#endif
CreateSubframeWithTestNavigation(
GURL("https://www.example.com/2/disallowed.html"), main_rfh());
@@ -582,8 +610,8 @@ TEST_P(ContentSubresourceFilterThrottleManagerTest,
SimulateStartAndGetResult(navigation_simulator()));
EXPECT_TRUE(ads_blocked_in_content_settings());
-#if defined(OS_ANDROID)
- EXPECT_TRUE(presenting_ads_blocked_infobar());
+#if BUILDFLAG(IS_ANDROID)
+ ::testing::Mock::VerifyAndClearExpectations(&message_dispatcher_bridge_);
#endif
}
@@ -594,79 +622,42 @@ TEST_P(ContentSubresourceFilterThrottleManagerTest,
ExpectActivationSignalForFrame(main_rfh(), true /* expect_activation */);
// A disallowed subframe navigation should be successfully filtered.
+#if BUILDFLAG(IS_ANDROID)
+ EXPECT_CALL(message_dispatcher_bridge_, EnqueueMessage);
+#endif
CreateSubframeWithTestNavigation(
GURL("https://www.example.com/1/disallowed.html"), main_rfh());
EXPECT_EQ(content::NavigationThrottle::BLOCK_REQUEST_AND_COLLAPSE,
SimulateStartAndGetResult(navigation_simulator()));
EXPECT_TRUE(ads_blocked_in_content_settings());
-#if defined(OS_ANDROID)
- EXPECT_TRUE(presenting_ads_blocked_infobar());
+#if BUILDFLAG(IS_ANDROID)
+ ::testing::Mock::VerifyAndClearExpectations(&message_dispatcher_bridge_);
#endif
// Commit another navigation that triggers page level activation.
+#if BUILDFLAG(IS_ANDROID)
+ // Since the MessageDispatcherBridge is mocked, navigation events are not
+ // tracked by the messages system to automatically dismiss the message on
+ // navigation. The message dismissal is therefore simulated.
+ SimulateMessageDismissal();
+#endif
NavigateAndCommitMainFrame(GURL(kTestURLWithActivation2));
ExpectActivationSignalForFrame(main_rfh(), true /* expect_activation */);
EXPECT_FALSE(ads_blocked_in_content_settings());
-#if defined(OS_ANDROID)
- EXPECT_FALSE(presenting_ads_blocked_infobar());
-#endif
-
- CreateSubframeWithTestNavigation(
- GURL("https://www.example.com/2/disallowed.html"), main_rfh());
- EXPECT_EQ(content::NavigationThrottle::BLOCK_REQUEST_AND_COLLAPSE,
- SimulateStartAndGetResult(navigation_simulator()));
-
- EXPECT_TRUE(ads_blocked_in_content_settings());
-#if defined(OS_ANDROID)
- EXPECT_TRUE(presenting_ads_blocked_infobar());
-#endif
-}
-
-// Test that once presented, the ads blocked infobar will remain present after a
-// same-document navigation.
-TEST_P(ContentSubresourceFilterThrottleManagerTest,
- InfoBarStaysPresentAfterSameDocumentNav) {
- // Commit a navigation that triggers page level activation.
- NavigateAndCommitMainFrame(GURL(kTestURLWithActivation));
- ExpectActivationSignalForFrame(main_rfh(), true /* expect_activation */);
-
- // A disallowed subframe navigation should be successfully filtered.
- CreateSubframeWithTestNavigation(
- GURL("https://www.example.com/1/disallowed.html"), main_rfh());
- EXPECT_EQ(content::NavigationThrottle::BLOCK_REQUEST_AND_COLLAPSE,
- SimulateStartAndGetResult(navigation_simulator()));
-
- EXPECT_TRUE(ads_blocked_in_content_settings());
-#if defined(OS_ANDROID)
- EXPECT_TRUE(presenting_ads_blocked_infobar());
-#endif
-
- // Commit another navigation that triggers page level activation.
- GURL url2 = GURL(base::StringPrintf("%s#ref", kTestURLWithActivation));
- CreateTestNavigation(url2, main_rfh());
- navigation_simulator()->CommitSameDocument();
-
- // Same-document navigations do not pass through ReadyToCommitNavigation so no
- // ActivateForNextCommittedLoad mojo call is expected.
- ExpectActivationSignalForFrame(main_rfh(), false /* expect_activation */,
- false /* expect_is_ad_subframe */,
- false /* expect_activation_sent_to_agent */);
- EXPECT_TRUE(ads_blocked_in_content_settings());
-#if defined(OS_ANDROID)
- EXPECT_TRUE(presenting_ads_blocked_infobar());
+#if BUILDFLAG(IS_ANDROID)
+ EXPECT_CALL(message_dispatcher_bridge_, EnqueueMessage);
#endif
-
CreateSubframeWithTestNavigation(
GURL("https://www.example.com/2/disallowed.html"), main_rfh());
EXPECT_EQ(content::NavigationThrottle::BLOCK_REQUEST_AND_COLLAPSE,
SimulateStartAndGetResult(navigation_simulator()));
EXPECT_TRUE(ads_blocked_in_content_settings());
-#if defined(OS_ANDROID)
- EXPECT_TRUE(presenting_ads_blocked_infobar());
+#if BUILDFLAG(IS_ANDROID)
+ ::testing::Mock::VerifyAndClearExpectations(&message_dispatcher_bridge_);
#endif
}
@@ -680,6 +671,9 @@ TEST_P(ContentSubresourceFilterThrottleManagerTest,
ExpectActivationSignalForFrame(main_rfh(), false /* expect_activation */);
// A subframe navigation should complete successfully.
+#if BUILDFLAG(IS_ANDROID)
+ EXPECT_CALL(message_dispatcher_bridge_, EnqueueMessage).Times(0);
+#endif
CreateSubframeWithTestNavigation(GURL("https://www.example.com/allowed.html"),
main_rfh());
EXPECT_EQ(content::NavigationThrottle::PROCEED,
@@ -691,8 +685,8 @@ TEST_P(ContentSubresourceFilterThrottleManagerTest,
ExpectActivationSignalForFrame(child, false /* expect_activation */);
EXPECT_FALSE(ads_blocked_in_content_settings());
-#if defined(OS_ANDROID)
- EXPECT_FALSE(presenting_ads_blocked_infobar());
+#if BUILDFLAG(IS_ANDROID)
+ ::testing::Mock::VerifyAndClearExpectations(&message_dispatcher_bridge_);
#endif
}
@@ -702,14 +696,17 @@ TEST_P(ContentSubresourceFilterThrottleManagerTest, RulesetHandleRegeneration) {
NavigateAndCommitMainFrame(GURL(kTestURLWithActivation));
ExpectActivationSignalForFrame(main_rfh(), true /* expect_activation */);
+#if BUILDFLAG(IS_ANDROID)
+ EXPECT_CALL(message_dispatcher_bridge_, EnqueueMessage);
+#endif
CreateSubframeWithTestNavigation(
GURL("https://www.example.com/disallowed.html"), main_rfh());
EXPECT_EQ(content::NavigationThrottle::BLOCK_REQUEST_AND_COLLAPSE,
SimulateStartAndGetResult(navigation_simulator()));
EXPECT_TRUE(ads_blocked_in_content_settings());
-#if defined(OS_ANDROID)
- EXPECT_TRUE(presenting_ads_blocked_infobar());
+#if BUILDFLAG(IS_ANDROID)
+ ::testing::Mock::VerifyAndClearExpectations(&message_dispatcher_bridge_);
#endif
// Simulate a renderer crash which should delete the frame.
@@ -717,23 +714,29 @@ TEST_P(ContentSubresourceFilterThrottleManagerTest, RulesetHandleRegeneration) {
process()->SimulateCrash();
EXPECT_FALSE(ManagerHasRulesetHandle());
+#if BUILDFLAG(IS_ANDROID)
+ // Since the MessageDispatcherBridge is mocked, navigation events are not
+ // tracked by the messages system to automatically dismiss the message on
+ // navigation. The message dismissal is therefore simulated.
+ SimulateMessageDismissal();
+#endif
NavigateAndCommit(GURL("https://example.reset"));
NavigateAndCommitMainFrame(GURL(kTestURLWithActivation));
ExpectActivationSignalForFrame(main_rfh(), true /* expect_activation */);
EXPECT_FALSE(ads_blocked_in_content_settings());
-#if defined(OS_ANDROID)
- EXPECT_FALSE(presenting_ads_blocked_infobar());
-#endif
+#if BUILDFLAG(IS_ANDROID)
+ EXPECT_CALL(message_dispatcher_bridge_, EnqueueMessage);
+#endif
CreateSubframeWithTestNavigation(
GURL("https://www.example.com/disallowed.html"), main_rfh());
EXPECT_EQ(content::NavigationThrottle::BLOCK_REQUEST_AND_COLLAPSE,
SimulateStartAndGetResult(navigation_simulator()));
EXPECT_TRUE(ads_blocked_in_content_settings());
-#if defined(OS_ANDROID)
- EXPECT_TRUE(presenting_ads_blocked_infobar());
+#if BUILDFLAG(IS_ANDROID)
+ ::testing::Mock::VerifyAndClearExpectations(&message_dispatcher_bridge_);
#endif
}
@@ -744,7 +747,7 @@ TEST_P(ContentSubresourceFilterThrottleManagerTest,
// ensure that it doesn't get preserved in the cache.
DisableBackForwardCacheForTesting(
RenderViewHostTestHarness::web_contents(),
- content::BackForwardCache::TEST_ASSUMES_NO_CACHING);
+ content::BackForwardCache::TEST_REQUIRES_NO_CACHING);
// This test assumes that we're not in DryRun mode.
base::test::ScopedFeatureList scoped_feature;
scoped_feature.InitAndDisableFeature(kAdTagging);
@@ -761,6 +764,9 @@ TEST_P(ContentSubresourceFilterThrottleManagerTest,
EXPECT_FALSE(ManagerHasRulesetHandle());
// A subframe navigation should complete successfully.
+#if BUILDFLAG(IS_ANDROID)
+ EXPECT_CALL(message_dispatcher_bridge_, EnqueueMessage).Times(0);
+#endif
CreateSubframeWithTestNavigation(
GURL("https://www.example.com/disallowed.html"), main_rfh());
EXPECT_EQ(content::NavigationThrottle::PROCEED,
@@ -772,8 +778,8 @@ TEST_P(ContentSubresourceFilterThrottleManagerTest,
ExpectActivationSignalForFrame(child, false /* expect_activation */);
EXPECT_FALSE(ads_blocked_in_content_settings());
-#if defined(OS_ANDROID)
- EXPECT_FALSE(presenting_ads_blocked_infobar());
+#if BUILDFLAG(IS_ANDROID)
+ ::testing::Mock::VerifyAndClearExpectations(&message_dispatcher_bridge_);
#endif
}
@@ -797,14 +803,17 @@ TEST_P(ContentSubresourceFilterThrottleManagerTest,
false /* expect_activation_sent_to_agent */);
// A subframe navigation fail.
+#if BUILDFLAG(IS_ANDROID)
+ EXPECT_CALL(message_dispatcher_bridge_, EnqueueMessage);
+#endif
CreateSubframeWithTestNavigation(
GURL("https://www.example.com/disallowed.html"), main_rfh());
EXPECT_EQ(content::NavigationThrottle::BLOCK_REQUEST_AND_COLLAPSE,
SimulateStartAndGetResult(navigation_simulator()));
EXPECT_TRUE(ads_blocked_in_content_settings());
-#if defined(OS_ANDROID)
- EXPECT_TRUE(presenting_ads_blocked_infobar());
+#if BUILDFLAG(IS_ANDROID)
+ ::testing::Mock::VerifyAndClearExpectations(&message_dispatcher_bridge_);
#endif
}
@@ -821,6 +830,9 @@ TEST_P(ContentSubresourceFilterThrottleManagerTest,
SimulateFailedNavigation(navigation_simulator(), net::ERR_FAILED);
ExpectActivationSignalForFrame(main_rfh(), false /* expect_activation */);
+#if BUILDFLAG(IS_ANDROID)
+ EXPECT_CALL(message_dispatcher_bridge_, EnqueueMessage).Times(0);
+#endif
CreateSubframeWithTestNavigation(
GURL("https://www.example.com/disallowed.html"), main_rfh());
EXPECT_EQ(content::NavigationThrottle::PROCEED,
@@ -832,8 +844,8 @@ TEST_P(ContentSubresourceFilterThrottleManagerTest,
ExpectActivationSignalForFrame(child, false /* expect_activation */);
EXPECT_FALSE(ads_blocked_in_content_settings());
-#if defined(OS_ANDROID)
- EXPECT_FALSE(presenting_ads_blocked_infobar());
+#if BUILDFLAG(IS_ANDROID)
+ ::testing::Mock::VerifyAndClearExpectations(&message_dispatcher_bridge_);
#endif
}
@@ -868,20 +880,23 @@ TEST_P(ContentSubresourceFilterThrottleManagerTest, ActivationPropagation) {
ExpectActivationSignalForFrame(subframe2, true /* expect_activation */);
// A final, nested subframe navigation is filtered.
+#if BUILDFLAG(IS_ANDROID)
+ EXPECT_CALL(message_dispatcher_bridge_, EnqueueMessage);
+#endif
CreateSubframeWithTestNavigation(GURL("https://www.c.com/disallowed.html"),
subframe2);
EXPECT_EQ(content::NavigationThrottle::BLOCK_REQUEST_AND_COLLAPSE,
SimulateStartAndGetResult(navigation_simulator()));
EXPECT_TRUE(ads_blocked_in_content_settings());
-#if defined(OS_ANDROID)
- EXPECT_TRUE(presenting_ads_blocked_infobar());
+#if BUILDFLAG(IS_ANDROID)
+ ::testing::Mock::VerifyAndClearExpectations(&message_dispatcher_bridge_);
#endif
}
// Ensure activation propagates through allowlisted documents.
// crbug.com/1010000: crashes on win
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#define MAYBE_ActivationPropagation2 DISABLED_ActivationPropagation2
#else
#define MAYBE_ActivationPropagation2 ActivationPropagation2
@@ -902,6 +917,9 @@ TEST_P(ContentSubresourceFilterThrottleManagerTest,
ExpectActivationSignalForFrame(subframe1, true /* expect_activation */);
// Navigate a sub-subframe that is not filtered due to the allowlist.
+#if BUILDFLAG(IS_ANDROID)
+ EXPECT_CALL(message_dispatcher_bridge_, EnqueueMessage).Times(0);
+#endif
CreateSubframeWithTestNavigation(
GURL("https://www.example.com/disallowed.html"), subframe1);
EXPECT_EQ(content::NavigationThrottle::PROCEED,
@@ -913,8 +931,8 @@ TEST_P(ContentSubresourceFilterThrottleManagerTest,
ExpectActivationSignalForFrame(subframe2, true /* expect_activation */);
EXPECT_FALSE(ads_blocked_in_content_settings());
-#if defined(OS_ANDROID)
- EXPECT_FALSE(presenting_ads_blocked_infobar());
+#if BUILDFLAG(IS_ANDROID)
+ ::testing::Mock::VerifyAndClearExpectations(&message_dispatcher_bridge_);
#endif
// An identical series of events that don't match allowlist rules cause
@@ -929,14 +947,17 @@ TEST_P(ContentSubresourceFilterThrottleManagerTest,
ExpectActivationSignalForFrame(subframe3, true /* expect_activation */);
// Navigate a sub-subframe that is not filtered due to the allowlist.
+#if BUILDFLAG(IS_ANDROID)
+ EXPECT_CALL(message_dispatcher_bridge_, EnqueueMessage);
+#endif
CreateSubframeWithTestNavigation(
GURL("https://www.example.com/disallowed.html"), subframe3);
EXPECT_EQ(content::NavigationThrottle::BLOCK_REQUEST_AND_COLLAPSE,
SimulateStartAndGetResult(navigation_simulator()));
EXPECT_TRUE(ads_blocked_in_content_settings());
-#if defined(OS_ANDROID)
- EXPECT_TRUE(presenting_ads_blocked_infobar());
+#if BUILDFLAG(IS_ANDROID)
+ ::testing::Mock::VerifyAndClearExpectations(&message_dispatcher_bridge_);
#endif
}
@@ -956,6 +977,9 @@ TEST_P(ContentSubresourceFilterThrottleManagerTest,
GURL(base::StringPrintf("%s/some_path/", kTestURLWithActivation)));
ExpectActivationSignalForFrame(main_rfh(), false /* expect_activation */);
+#if BUILDFLAG(IS_ANDROID)
+ EXPECT_CALL(message_dispatcher_bridge_, EnqueueMessage).Times(0);
+#endif
CreateSubframeWithTestNavigation(
GURL("https://www.example.com/disallowed.html"), main_rfh());
EXPECT_EQ(content::NavigationThrottle::PROCEED,
@@ -967,8 +991,8 @@ TEST_P(ContentSubresourceFilterThrottleManagerTest,
ExpectActivationSignalForFrame(child, false /* expect_activation */);
EXPECT_FALSE(ads_blocked_in_content_settings());
-#if defined(OS_ANDROID)
- EXPECT_FALSE(presenting_ads_blocked_infobar());
+#if BUILDFLAG(IS_ANDROID)
+ ::testing::Mock::VerifyAndClearExpectations(&message_dispatcher_bridge_);
#endif
}
@@ -1085,14 +1109,17 @@ TEST_P(ContentSubresourceFilterThrottleManagerTest,
false /* is_ad_subframe */);
// A disallowed subframe navigation should be successfully filtered.
+#if BUILDFLAG(IS_ANDROID)
+ EXPECT_CALL(message_dispatcher_bridge_, EnqueueMessage);
+#endif
CreateSubframeWithTestNavigation(
GURL("https://www.example.com/disallowed.html"), main_rfh());
EXPECT_EQ(content::NavigationThrottle::BLOCK_REQUEST_AND_COLLAPSE,
SimulateStartAndGetResult(navigation_simulator()));
EXPECT_TRUE(ads_blocked_in_content_settings());
-#if defined(OS_ANDROID)
- EXPECT_TRUE(presenting_ads_blocked_infobar());
+#if BUILDFLAG(IS_ANDROID)
+ ::testing::Mock::VerifyAndClearExpectations(&message_dispatcher_bridge_);
#endif
}
@@ -1249,6 +1276,9 @@ TEST_P(ContentSubresourceFilterThrottleManagerTest,
EXPECT_TRUE(throttle_manager()->IsRenderFrameHostTaggedAsAd(grandchild));
// Verify that a 2nd level nested frame should also be tagged.
+#if BUILDFLAG(IS_ANDROID)
+ EXPECT_CALL(message_dispatcher_bridge_, EnqueueMessage).Times(0);
+#endif
CreateSubframeWithTestNavigation(
GURL("https://www.example.com/great_grandchild_allowed_by_ruleset.html"),
child);
@@ -1264,8 +1294,8 @@ TEST_P(ContentSubresourceFilterThrottleManagerTest,
EXPECT_TRUE(throttle_manager()->IsRenderFrameHostTaggedAsAd(greatGrandchild));
EXPECT_FALSE(ads_blocked_in_content_settings());
-#if defined(OS_ANDROID)
- EXPECT_FALSE(presenting_ads_blocked_infobar());
+#if BUILDFLAG(IS_ANDROID)
+ ::testing::Mock::VerifyAndClearExpectations(&message_dispatcher_bridge_);
#endif
}
@@ -1289,6 +1319,9 @@ TEST_P(ContentSubresourceFilterThrottleManagerTest,
// Create a subframe which is allowed as per ruleset and should not be tagged
// as ad because its parent is not tagged as well.
+#if BUILDFLAG(IS_ANDROID)
+ EXPECT_CALL(message_dispatcher_bridge_, EnqueueMessage).Times(0);
+#endif
CreateSubframeWithTestNavigation(
GURL("https://www.example.com/also_allowed_by_ruleset.html"), child);
EXPECT_EQ(content::NavigationThrottle::PROCEED,
@@ -1303,8 +1336,8 @@ TEST_P(ContentSubresourceFilterThrottleManagerTest,
EXPECT_FALSE(throttle_manager()->IsRenderFrameHostTaggedAsAd(grandchild));
EXPECT_FALSE(ads_blocked_in_content_settings());
-#if defined(OS_ANDROID)
- EXPECT_FALSE(presenting_ads_blocked_infobar());
+#if BUILDFLAG(IS_ANDROID)
+ ::testing::Mock::VerifyAndClearExpectations(&message_dispatcher_bridge_);
#endif
}
@@ -1320,6 +1353,9 @@ TEST_P(ContentSubresourceFilterThrottleManagerTest,
ASSERT_TRUE(remote.is_bound());
ASSERT_TRUE(remote.is_connected());
+#if BUILDFLAG(IS_ANDROID)
+ EXPECT_CALL(message_dispatcher_bridge_, EnqueueMessage).Times(0);
+#endif
NavigateAndCommitMainFrame(GURL(kTestURLWithNoActivation));
// Simulate the previous navigation sending an IPC that a load was
@@ -1334,8 +1370,8 @@ TEST_P(ContentSubresourceFilterThrottleManagerTest,
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(ads_blocked_in_content_settings());
-#if defined(OS_ANDROID)
- EXPECT_FALSE(presenting_ads_blocked_infobar());
+#if BUILDFLAG(IS_ANDROID)
+ ::testing::Mock::VerifyAndClearExpectations(&message_dispatcher_bridge_);
#endif
}
@@ -1543,6 +1579,221 @@ TEST_P(ContentSubresourceFilterThrottleManagerTest,
throttle_manager);
}
+class ContentSubresourceFilterThrottleManagerInfoBarUiTest
+ : public ContentSubresourceFilterThrottleManagerTest {
+ public:
+ void SetUp() override {
+ ContentSubresourceFilterThrottleManagerTest::SetUp();
+#if BUILDFLAG(IS_ANDROID)
+ message_dispatcher_bridge_.SetMessagesEnabledForEmbedder(false);
+ messages::MessageDispatcherBridge::SetInstanceForTesting(
+ &message_dispatcher_bridge_);
+#endif
+ }
+
+ bool presenting_ads_blocked_infobar() {
+ auto* infobar_manager = infobars::ContentInfoBarManager::FromWebContents(
+ content::RenderViewHostTestHarness::web_contents());
+ if (infobar_manager->infobar_count() == 0)
+ return false;
+
+ // No infobars other than the ads blocked infobar should be displayed in the
+ // context of these tests.
+ EXPECT_EQ(infobar_manager->infobar_count(), 1u);
+ auto* infobar = infobar_manager->infobar_at(0);
+ EXPECT_EQ(infobar->delegate()->GetIdentifier(),
+ infobars::InfoBarDelegate::ADS_BLOCKED_INFOBAR_DELEGATE_ANDROID);
+
+ return true;
+ }
+
+ protected:
+#if BUILDFLAG(IS_ANDROID)
+ messages::MockMessageDispatcherBridge message_dispatcher_bridge_;
+#endif
+};
+
+INSTANTIATE_TEST_SUITE_P(All,
+ ContentSubresourceFilterThrottleManagerInfoBarUiTest,
+ ::testing::Values(WILL_START_REQUEST,
+ WILL_PROCESS_RESPONSE));
+
+#if BUILDFLAG(IS_ANDROID)
+TEST_P(ContentSubresourceFilterThrottleManagerInfoBarUiTest,
+ NoCrashWhenInfoBarManagerIsNotPresent) {
+ auto* web_contents = RenderViewHostTestHarness::web_contents();
+ web_contents->RemoveUserData(infobars::ContentInfoBarManager::UserDataKey());
+
+ // Commit a navigation that triggers page level activation.
+ NavigateAndCommitMainFrame(GURL(kTestURLWithActivation));
+ ExpectActivationSignalForFrame(main_rfh(), true /* expect_activation */);
+
+ // A disallowed subframe navigation should be successfully filtered, and the
+ // lack of infobar manager should not cause a crash.
+ CreateSubframeWithTestNavigation(
+ GURL("https://www.example.com/disallowed.html"), main_rfh());
+ EXPECT_EQ(content::NavigationThrottle::BLOCK_REQUEST_AND_COLLAPSE,
+ SimulateStartAndGetResult(navigation_simulator()));
+
+ EXPECT_TRUE(ads_blocked_in_content_settings());
+}
+#endif
+
+// Test that once presented, the ads blocked infobar will remain present after a
+// same-document navigation.
+TEST_P(ContentSubresourceFilterThrottleManagerInfoBarUiTest,
+ InfoBarStaysPresentAfterSameDocumentNav) {
+ // Commit a navigation that triggers page level activation.
+ NavigateAndCommitMainFrame(GURL(kTestURLWithActivation));
+ ExpectActivationSignalForFrame(main_rfh(), true /* expect_activation */);
+
+ // A disallowed subframe navigation should be successfully filtered.
+ CreateSubframeWithTestNavigation(
+ GURL("https://www.example.com/1/disallowed.html"), main_rfh());
+ EXPECT_EQ(content::NavigationThrottle::BLOCK_REQUEST_AND_COLLAPSE,
+ SimulateStartAndGetResult(navigation_simulator()));
+
+ EXPECT_TRUE(ads_blocked_in_content_settings());
+#if BUILDFLAG(IS_ANDROID)
+ EXPECT_TRUE(presenting_ads_blocked_infobar());
+#endif
+
+ // Commit another navigation that triggers page level activation.
+ GURL url2 = GURL(base::StringPrintf("%s#ref", kTestURLWithActivation));
+ CreateTestNavigation(url2, main_rfh());
+ navigation_simulator()->CommitSameDocument();
+
+ // Same-document navigations do not pass through ReadyToCommitNavigation so no
+ // ActivateForNextCommittedLoad mojo call is expected.
+ ExpectActivationSignalForFrame(main_rfh(), false /* expect_activation */,
+ false /* expect_is_ad_subframe */,
+ false /* expect_activation_sent_to_agent */);
+
+ EXPECT_TRUE(ads_blocked_in_content_settings());
+#if BUILDFLAG(IS_ANDROID)
+ EXPECT_TRUE(presenting_ads_blocked_infobar());
+#endif
+
+ CreateSubframeWithTestNavigation(
+ GURL("https://www.example.com/2/disallowed.html"), main_rfh());
+ EXPECT_EQ(content::NavigationThrottle::BLOCK_REQUEST_AND_COLLAPSE,
+ SimulateStartAndGetResult(navigation_simulator()));
+
+ EXPECT_TRUE(ads_blocked_in_content_settings());
+#if BUILDFLAG(IS_ANDROID)
+ EXPECT_TRUE(presenting_ads_blocked_infobar());
+#endif
+}
+
+// This should fail if the throttle manager notifies the delegate twice of a
+// disallowed load for the same page load.
+TEST_P(ContentSubresourceFilterThrottleManagerInfoBarUiTest,
+ ActivateMainFrameAndFilterTwoSubframeNavigations) {
+ // Commit a navigation that triggers page level activation.
+ NavigateAndCommitMainFrame(GURL(kTestURLWithActivation));
+ ExpectActivationSignalForFrame(main_rfh(), true /* expect_activation */);
+
+ // A disallowed subframe navigation should be successfully filtered.
+ CreateSubframeWithTestNavigation(
+ GURL("https://www.example.com/1/disallowed.html"), main_rfh());
+ EXPECT_EQ(content::NavigationThrottle::BLOCK_REQUEST_AND_COLLAPSE,
+ SimulateStartAndGetResult(navigation_simulator()));
+
+ EXPECT_TRUE(ads_blocked_in_content_settings());
+#if BUILDFLAG(IS_ANDROID)
+ EXPECT_TRUE(presenting_ads_blocked_infobar());
+#endif
+
+ CreateSubframeWithTestNavigation(
+ GURL("https://www.example.com/2/disallowed.html"), main_rfh());
+ EXPECT_EQ(content::NavigationThrottle::BLOCK_REQUEST_AND_COLLAPSE,
+ SimulateStartAndGetResult(navigation_simulator()));
+
+ EXPECT_TRUE(ads_blocked_in_content_settings());
+#if BUILDFLAG(IS_ANDROID)
+ EXPECT_TRUE(presenting_ads_blocked_infobar());
+#endif
+}
+
+TEST_P(ContentSubresourceFilterThrottleManagerInfoBarUiTest,
+ ActivateTwoMainFramesAndFilterTwoSubframeNavigations) {
+ // Commit a navigation that triggers page level activation.
+ NavigateAndCommitMainFrame(GURL(kTestURLWithActivation));
+ ExpectActivationSignalForFrame(main_rfh(), true /* expect_activation */);
+
+ // A disallowed subframe navigation should be successfully filtered.
+ CreateSubframeWithTestNavigation(
+ GURL("https://www.example.com/1/disallowed.html"), main_rfh());
+ EXPECT_EQ(content::NavigationThrottle::BLOCK_REQUEST_AND_COLLAPSE,
+ SimulateStartAndGetResult(navigation_simulator()));
+
+ EXPECT_TRUE(ads_blocked_in_content_settings());
+#if BUILDFLAG(IS_ANDROID)
+ EXPECT_TRUE(presenting_ads_blocked_infobar());
+#endif
+
+ // Commit another navigation that triggers page level activation.
+ NavigateAndCommitMainFrame(GURL(kTestURLWithActivation2));
+ ExpectActivationSignalForFrame(main_rfh(), true /* expect_activation */);
+
+ EXPECT_FALSE(ads_blocked_in_content_settings());
+#if BUILDFLAG(IS_ANDROID)
+ EXPECT_FALSE(presenting_ads_blocked_infobar());
+#endif
+
+ CreateSubframeWithTestNavigation(
+ GURL("https://www.example.com/2/disallowed.html"), main_rfh());
+ EXPECT_EQ(content::NavigationThrottle::BLOCK_REQUEST_AND_COLLAPSE,
+ SimulateStartAndGetResult(navigation_simulator()));
+
+ EXPECT_TRUE(ads_blocked_in_content_settings());
+#if BUILDFLAG(IS_ANDROID)
+ EXPECT_TRUE(presenting_ads_blocked_infobar());
+#endif
+}
+
+// Once there are no activated frames, the manager drops its ruleset handle. If
+// another frame is activated, make sure the handle is regenerated.
+TEST_P(ContentSubresourceFilterThrottleManagerInfoBarUiTest,
+ RulesetHandleRegeneration) {
+ NavigateAndCommitMainFrame(GURL(kTestURLWithActivation));
+ ExpectActivationSignalForFrame(main_rfh(), true /* expect_activation */);
+
+ CreateSubframeWithTestNavigation(
+ GURL("https://www.example.com/disallowed.html"), main_rfh());
+ EXPECT_EQ(content::NavigationThrottle::BLOCK_REQUEST_AND_COLLAPSE,
+ SimulateStartAndGetResult(navigation_simulator()));
+
+ EXPECT_TRUE(ads_blocked_in_content_settings());
+#if BUILDFLAG(IS_ANDROID)
+ EXPECT_TRUE(presenting_ads_blocked_infobar());
+#endif
+
+ // Simulate a renderer crash which should delete the frame.
+ EXPECT_TRUE(ManagerHasRulesetHandle());
+ process()->SimulateCrash();
+ EXPECT_FALSE(ManagerHasRulesetHandle());
+
+ NavigateAndCommit(GURL("https://example.reset"));
+ NavigateAndCommitMainFrame(GURL(kTestURLWithActivation));
+ ExpectActivationSignalForFrame(main_rfh(), true /* expect_activation */);
+
+ EXPECT_FALSE(ads_blocked_in_content_settings());
+#if BUILDFLAG(IS_ANDROID)
+ EXPECT_FALSE(presenting_ads_blocked_infobar());
+#endif
+
+ CreateSubframeWithTestNavigation(
+ GURL("https://www.example.com/disallowed.html"), main_rfh());
+ EXPECT_EQ(content::NavigationThrottle::BLOCK_REQUEST_AND_COLLAPSE,
+ SimulateStartAndGetResult(navigation_simulator()));
+
+ EXPECT_TRUE(ads_blocked_in_content_settings());
+#if BUILDFLAG(IS_ANDROID)
+ EXPECT_TRUE(presenting_ads_blocked_infobar());
+#endif
+}
+
// TODO(csharrison): Make sure the following conditions are exercised in tests:
//
// - Synchronous navigations to about:blank. These hit issues with the
diff --git a/chromium/components/subresource_filter/content/browser/content_subresource_filter_web_contents_helper.cc b/chromium/components/subresource_filter/content/browser/content_subresource_filter_web_contents_helper.cc
index 1236ae31573..d37de4b6c17 100644
--- a/chromium/components/subresource_filter/content/browser/content_subresource_filter_web_contents_helper.cc
+++ b/chromium/components/subresource_filter/content/browser/content_subresource_filter_web_contents_helper.cc
@@ -8,6 +8,7 @@
#include <utility>
#include "base/feature_list.h"
+#include "base/strings/stringprintf.h"
#include "base/supports_user_data.h"
#include "components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.h"
#include "components/subresource_filter/core/browser/subresource_filter_features.h"
@@ -66,6 +67,173 @@ NAVIGATION_HANDLE_USER_DATA_KEY_IMPL(ThrottleManagerInUserDataContainer);
} // namespace
+// =============================================================================
+// TODO(bokan): Temporary to help debug crash in crbug.com/1264667.
+
+DebugCrashWebContentsObserver::CrashKeyData::CrashKeyData() = default;
+DebugCrashWebContentsObserver::CrashKeyData::~CrashKeyData() = default;
+DebugCrashWebContentsObserver::CrashKeyData::CrashKeyData(const CrashKeyData&) =
+ default;
+
+DebugCrashWebContentsObserver::DebugCrashWebContentsObserver(
+ content::WebContents* web_contents)
+ : content::WebContentsObserver(web_contents) {}
+
+DebugCrashWebContentsObserver::~DebugCrashWebContentsObserver() = default;
+
+void DebugCrashWebContentsObserver::RenderFrameCreated(
+ content::RenderFrameHost* render_frame_host) {
+ if (!render_frame_host->GetParent()) {
+ rfh_crash_data_.emplace(render_frame_host, CrashKeyData());
+ }
+}
+
+void DebugCrashWebContentsObserver::RenderFrameDeleted(
+ content::RenderFrameHost* render_frame_host) {
+ if (!render_frame_host->GetParent()) {
+ rfh_crash_data_.erase(render_frame_host);
+ }
+}
+
+void DebugCrashWebContentsObserver::ReadyToCommitNavigation(
+ content::NavigationHandle* handle) {
+ if (!WillCreateNewPage(*handle))
+ return;
+
+ auto* rfh = handle->GetRenderFrameHost();
+ DCHECK(rfh);
+
+ auto itr = rfh_crash_data_.find(rfh);
+ if (itr == rfh_crash_data_.end())
+ return;
+
+ CrashKeyData& data = itr->second;
+ data.num_commits++;
+ data.last_nav_had_manager =
+ ThrottleManagerInUserDataContainer::GetForNavigationHandle(*handle);
+}
+
+void DebugCrashWebContentsObserver::DidFinishNonActivatingNavigation(
+ content::NavigationHandle* handle,
+ content::Page* page) {
+ DCHECK(WillCreateNewPage(*handle));
+
+ content::RenderFrameHost* rfh = nullptr;
+ if (handle->HasCommitted()) {
+ rfh = handle->GetRenderFrameHost();
+ } else if (page) {
+ rfh = &page->GetMainDocument();
+ }
+
+ // This navigation either didn't commit or wasn't the initial_document edge
+ // case where we move the thottle manager even if we didn't commit. Outside
+ // of these two cases, the navigation isn't interesting.
+ if (!rfh)
+ return;
+
+ auto itr = rfh_crash_data_.find(rfh);
+ if (itr == rfh_crash_data_.end())
+ return;
+
+ CrashKeyData& data = itr->second;
+ data.page_at_last_nav_finish = page ? page->GetWeakPtr() : nullptr;
+ data.last_nav_manager_moved_to_page =
+ page &&
+ page->GetUserData(&ContentSubresourceFilterThrottleManager::kUserDataKey);
+}
+
+void DebugCrashWebContentsObserver::RenderFrameHostStateChanged(
+ content::RenderFrameHost* render_frame_host,
+ content::RenderFrameHost::LifecycleState old_state,
+ content::RenderFrameHost::LifecycleState new_state) {
+ if (render_frame_host->GetParent())
+ return;
+
+ if (new_state ==
+ content::RenderFrameHost::LifecycleState::kInBackForwardCache) {
+ auto itr = rfh_crash_data_.find(render_frame_host);
+ if (itr == rfh_crash_data_.end())
+ return;
+ CrashKeyData& data = itr->second;
+ data.entered_bf_cache = true;
+ data.page_at_bf_cache_entry = render_frame_host->GetPage().GetWeakPtr();
+ }
+}
+
+void DebugCrashWebContentsObserver::DidFinishPageActivatingNavigation(
+ content::NavigationHandle* handle) {
+ DCHECK(handle->HasCommitted());
+ auto* rfh = handle->GetRenderFrameHost();
+ DCHECK(rfh);
+ DCHECK(!rfh->GetParent());
+
+ auto itr = rfh_crash_data_.find(rfh);
+ if (itr == rfh_crash_data_.end())
+ return;
+
+ CrashKeyData& data = itr->second;
+ data.is_bfcache_restore = handle->IsServedFromBackForwardCache();
+ data.page_at_restore = rfh->GetPage().GetWeakPtr();
+}
+
+void DebugCrashWebContentsObserver::GetScopedCrashKeyStrings(
+ content::RenderFrameHost* rfh,
+ std::vector<std::unique_ptr<crash_reporter::ScopedCrashKeyString>>& keys) {
+ constexpr size_t kCrashKeyBufferSize = 32;
+ static crash_reporter::CrashKeyString<kCrashKeyBufferSize> crash_key_1(
+ "sf-crash-number-commits");
+ static crash_reporter::CrashKeyString<kCrashKeyBufferSize> crash_key_2(
+ "sf-crash-had-manager");
+ static crash_reporter::CrashKeyString<kCrashKeyBufferSize> crash_key_3(
+ "sf-crash-moved-to-page");
+ static crash_reporter::CrashKeyString<kCrashKeyBufferSize> crash_key_4(
+ "sf-crash-entered-bfcache");
+ static crash_reporter::CrashKeyString<kCrashKeyBufferSize> crash_key_5(
+ "sf-crash-bfcache-restore");
+ static crash_reporter::CrashKeyString<kCrashKeyBufferSize> crash_key_6(
+ "sf-crash-page-nav-finish");
+ static crash_reporter::CrashKeyString<kCrashKeyBufferSize> crash_key_7(
+ "sf-crash-page-bfcache-store");
+ static crash_reporter::CrashKeyString<kCrashKeyBufferSize> crash_key_8(
+ "sf-crash-page-bfcache-restore");
+ static crash_reporter::CrashKeyString<kCrashKeyBufferSize> crash_key_9(
+ "sf-crash-has-crash-data");
+
+ auto itr = rfh_crash_data_.find(rfh);
+ if (itr == rfh_crash_data_.end()) {
+ keys.push_back(std::make_unique<crash_reporter::ScopedCrashKeyString>(
+ &crash_key_9, "NO"));
+ return;
+ }
+
+ CrashKeyData& data = itr->second;
+
+ keys.push_back(std::make_unique<crash_reporter::ScopedCrashKeyString>(
+ &crash_key_1, base::StringPrintf("%d", data.num_commits)));
+ keys.push_back(std::make_unique<crash_reporter::ScopedCrashKeyString>(
+ &crash_key_2, base::StringPrintf("%d", data.last_nav_had_manager)));
+ keys.push_back(std::make_unique<crash_reporter::ScopedCrashKeyString>(
+ &crash_key_3,
+ base::StringPrintf("%d", data.last_nav_manager_moved_to_page)));
+ keys.push_back(std::make_unique<crash_reporter::ScopedCrashKeyString>(
+ &crash_key_4, base::StringPrintf("%d", data.entered_bf_cache)));
+ keys.push_back(std::make_unique<crash_reporter::ScopedCrashKeyString>(
+ &crash_key_5, base::StringPrintf("%d", data.is_bfcache_restore)));
+ keys.push_back(std::make_unique<crash_reporter::ScopedCrashKeyString>(
+ &crash_key_6,
+ base::StringPrintf("%p", data.page_at_last_nav_finish.get())));
+ keys.push_back(std::make_unique<crash_reporter::ScopedCrashKeyString>(
+ &crash_key_7,
+ base::StringPrintf("%p", data.page_at_bf_cache_entry.get())));
+ keys.push_back(std::make_unique<crash_reporter::ScopedCrashKeyString>(
+ &crash_key_8, base::StringPrintf("%p", data.page_at_restore.get())));
+ keys.push_back(std::make_unique<crash_reporter::ScopedCrashKeyString>(
+ &crash_key_9, "YES"));
+}
+
+// End temporary debugging for crbug.com/1264667.
+// =============================================================================
+
WEB_CONTENTS_USER_DATA_KEY_IMPL(ContentSubresourceFilterWebContentsHelper);
// static
@@ -102,6 +270,7 @@ ContentSubresourceFilterWebContentsHelper::
: content::WebContentsUserData<ContentSubresourceFilterWebContentsHelper>(
*web_contents),
content::WebContentsObserver(web_contents),
+ debug_crash_observer_(web_contents),
profile_context_(profile_context),
database_manager_(database_manager),
dealer_handle_(dealer_handle) {
@@ -237,11 +406,20 @@ void ContentSubresourceFilterWebContentsHelper::DidFinishNavigation(
DCHECK(navigation_handle->HasCommitted());
DCHECK(navigation_handle->GetRenderFrameHost());
+ debug_crash_observer_.DidFinishPageActivatingNavigation(navigation_handle);
+
+ std::vector<std::unique_ptr<crash_reporter::ScopedCrashKeyString>>
+ scoped_crash_keys;
+ debug_crash_observer_.GetScopedCrashKeyStrings(
+ navigation_handle->GetRenderFrameHost(), scoped_crash_keys);
+
ContentSubresourceFilterThrottleManager* throttle_manager =
GetThrottleManager(navigation_handle->GetRenderFrameHost()->GetPage());
-
+ // This should be non-null since every fully loaded page should have a
+ // throttle manager and only fully loaded pages can be in the BFCache.
+ // TODO(bokan): Temporary to help debug crash in crbug.com/1264667.
+ CHECK(throttle_manager);
throttle_manager->DidBecomePrimaryPage();
-
return;
}
@@ -264,8 +442,11 @@ void ContentSubresourceFilterWebContentsHelper::DidFinishNavigation(
// such as this class) but attach it before a navigation completes. If that
// happened we won't have a throttle manager for the navigation. Not sure
// this would ever happen in real usage but it does happen in some tests.
- if (!container)
+ if (!container) {
+ debug_crash_observer_.DidFinishNonActivatingNavigation(navigation_handle,
+ nullptr);
return;
+ }
DCHECK(throttle_manager);
@@ -299,6 +480,9 @@ void ContentSubresourceFilterWebContentsHelper::DidFinishNavigation(
std::move(throttle_manager_user_data));
throttle_manager->OnPageCreated(*page);
}
+
+ debug_crash_observer_.DidFinishNonActivatingNavigation(navigation_handle,
+ page);
}
// Call DidFinishInFrameNavigation on the throttle manager after performing
diff --git a/chromium/components/subresource_filter/content/browser/content_subresource_filter_web_contents_helper.h b/chromium/components/subresource_filter/content/browser/content_subresource_filter_web_contents_helper.h
index 2663c5fc666..637d3c47f2a 100644
--- a/chromium/components/subresource_filter/content/browser/content_subresource_filter_web_contents_helper.h
+++ b/chromium/components/subresource_filter/content/browser/content_subresource_filter_web_contents_helper.h
@@ -5,12 +5,14 @@
#ifndef COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_CONTENT_SUBRESOURCE_FILTER_WEB_CONTENTS_HELPER_H_
#define COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_CONTENT_SUBRESOURCE_FILTER_WEB_CONTENTS_HELPER_H_
+#include <map>
#include <set>
#include "base/containers/flat_set.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/scoped_observation.h"
+#include "components/crash/core/common/crash_key.h"
#include "components/subresource_filter/content/browser/subresource_filter_observer.h"
#include "components/subresource_filter/content/browser/subresource_filter_observer_manager.h"
#include "components/subresource_filter/content/browser/verified_ruleset_dealer.h"
@@ -33,6 +35,60 @@ namespace subresource_filter {
class ContentSubresourceFilterThrottleManager;
class SubresourceFilterProfileContext;
+// TODO(bokan): Temporary to help debug crash in crbug.com/1264667. Tracks
+// main frame RFHs and observes navigations/events relating to them, recording
+// some potentially interesting data that'll be stored as a crash key at the
+// crash site in
+// ContentSubresourceFilterWebContentsHelper::DidFinishNavigation.
+class DebugCrashWebContentsObserver : public content::WebContentsObserver {
+ struct CrashKeyData {
+ CrashKeyData();
+ ~CrashKeyData();
+ CrashKeyData(const CrashKeyData& other);
+
+ int num_commits = 0;
+
+ bool last_nav_had_manager = false;
+ bool last_nav_manager_moved_to_page = false;
+ bool entered_bf_cache = false;
+ bool is_bfcache_restore = false;
+
+ base::WeakPtr<content::Page> page_at_last_nav_finish;
+ base::WeakPtr<content::Page> page_at_bf_cache_entry;
+ base::WeakPtr<content::Page> page_at_restore;
+ };
+
+ public:
+ explicit DebugCrashWebContentsObserver(content::WebContents* web_contents);
+ ~DebugCrashWebContentsObserver() override;
+
+ void RenderFrameCreated(content::RenderFrameHost* render_frame_host) override;
+ void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) override;
+
+ void ReadyToCommitNavigation(content::NavigationHandle* handle) override;
+ // Not an override since it relies on running after the WebContentsHelper's
+ // DidFinishNavigation.
+ void DidFinishNonActivatingNavigation(content::NavigationHandle* handle,
+ content::Page* page);
+
+ void RenderFrameHostStateChanged(
+ content::RenderFrameHost* render_frame_host,
+ content::RenderFrameHost::LifecycleState old_state,
+ content::RenderFrameHost::LifecycleState new_state) override;
+
+ // Not an override since it relies on running before the crash site in the
+ // WebContentsHelper's DidFinishNavigation.
+ void DidFinishPageActivatingNavigation(content::NavigationHandle* handle);
+ void GetScopedCrashKeyStrings(
+ content::RenderFrameHost* rfh,
+ std::vector<std::unique_ptr<crash_reporter::ScopedCrashKeyString>>& keys);
+
+ private:
+ // Tracks useful data for each main frame RFH that's passed through
+ // ReadyToCommit/DidFinishNavigation.
+ std::map<content::RenderFrameHost*, CrashKeyData> rfh_crash_data_;
+};
+
// This class manages the lifetime and storage of
// ContentSubresourceFilterThrottleManager instances. This helper is attached
// to each WebContents and listens to navigations to ensure each main Page in
@@ -111,7 +167,9 @@ class ContentSubresourceFilterWebContentsHelper
LoadPolicy load_policy) override;
private:
+ DebugCrashWebContentsObserver debug_crash_observer_;
raw_ptr<SubresourceFilterProfileContext> profile_context_;
+
scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager> database_manager_;
raw_ptr<VerifiedRulesetDealer::Handle> dealer_handle_;
diff --git a/chromium/components/subresource_filter/content/browser/navigation_console_logger.cc b/chromium/components/subresource_filter/content/browser/navigation_console_logger.cc
index 23f4bd07100..e9e2dbfedf6 100644
--- a/chromium/components/subresource_filter/content/browser/navigation_console_logger.cc
+++ b/chromium/components/subresource_filter/content/browser/navigation_console_logger.cc
@@ -5,7 +5,7 @@
#include "components/subresource_filter/content/browser/navigation_console_logger.h"
#include "base/memory/ptr_util.h"
-#include "content/public/browser/navigating_frame_type.h"
+#include "content/public/browser/frame_type.h"
#include "content/public/browser/navigation_handle.h"
namespace subresource_filter {
@@ -17,7 +17,7 @@ void NavigationConsoleLogger::LogMessageOnCommit(
const std::string& message) {
DCHECK(handle->IsInMainFrame());
if (handle->GetNavigatingFrameType() ==
- content::NavigatingFrameType::kFencedFrameRoot) {
+ content::FrameType::kFencedFrameRoot) {
// TODO(crbug.com/1263541): Replace it with DCHECK once fenced frames use
// the embedder's ContentSubresourceFilterThrottleManager.
return;
@@ -35,7 +35,7 @@ NavigationConsoleLogger* NavigationConsoleLogger::CreateIfNeededForNavigation(
content::NavigationHandle* handle) {
DCHECK(handle->IsInMainFrame());
DCHECK_NE(handle->GetNavigatingFrameType(),
- content::NavigatingFrameType::kFencedFrameRoot);
+ content::FrameType::kFencedFrameRoot);
return GetOrCreateForNavigationHandle(*handle);
}
diff --git a/chromium/components/subresource_filter/content/browser/profile_interaction_manager.cc b/chromium/components/subresource_filter/content/browser/profile_interaction_manager.cc
index 68545196772..d01a6899cf9 100644
--- a/chromium/components/subresource_filter/content/browser/profile_interaction_manager.cc
+++ b/chromium/components/subresource_filter/content/browser/profile_interaction_manager.cc
@@ -5,6 +5,7 @@
#include "components/subresource_filter/content/browser/profile_interaction_manager.h"
#include "base/logging.h"
+#include "build/build_config.h"
#include "components/content_settings/browser/page_specific_content_settings.h"
#include "components/content_settings/core/common/content_settings_types.h"
#include "components/subresource_filter/content/browser/ads_intervention_manager.h"
@@ -17,11 +18,11 @@
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "components/infobars/content/content_infobar_manager.h" // nogncheck
+#include "components/messages/android/message_dispatcher_bridge.h"
#include "components/messages/android/messages_feature.h"
#include "components/subresource_filter/content/browser/ads_blocked_infobar_delegate.h"
-#include "components/subresource_filter/content/browser/ads_blocked_message_delegate.h"
#endif
namespace subresource_filter {
@@ -137,13 +138,16 @@ void ProfileInteractionManager::MaybeShowNotification() {
const GURL& top_level_url = page_->GetMainDocument().GetLastCommittedURL();
if (profile_context_->settings_manager()->ShouldShowUIForSite(
top_level_url)) {
-#if defined(OS_ANDROID)
- if (messages::IsAdsBlockedMessagesUiEnabled()) {
+#if BUILDFLAG(IS_ANDROID)
+ if (messages::IsAdsBlockedMessagesUiEnabled() &&
+ messages::MessageDispatcherBridge::Get()
+ ->IsMessagesEnabledForEmbedder()) {
subresource_filter::AdsBlockedMessageDelegate::CreateForWebContents(
GetWebContents());
- subresource_filter::AdsBlockedMessageDelegate::FromWebContents(
- GetWebContents())
- ->ShowMessage();
+ ads_blocked_message_delegate_ =
+ subresource_filter::AdsBlockedMessageDelegate::FromWebContents(
+ GetWebContents());
+ ads_blocked_message_delegate_->ShowMessage();
} else {
// NOTE: It is acceptable for the embedder to not have installed an
// infobar manager.
diff --git a/chromium/components/subresource_filter/content/browser/profile_interaction_manager.h b/chromium/components/subresource_filter/content/browser/profile_interaction_manager.h
index 9778b9617cd..e48e9cdf599 100644
--- a/chromium/components/subresource_filter/content/browser/profile_interaction_manager.h
+++ b/chromium/components/subresource_filter/content/browser/profile_interaction_manager.h
@@ -11,6 +11,10 @@
#include "components/subresource_filter/core/common/activation_decision.h"
#include "components/subresource_filter/core/mojom/subresource_filter.mojom.h"
+#if BUILDFLAG(IS_ANDROID)
+#include "components/subresource_filter/content/browser/ads_blocked_message_delegate.h"
+#endif
+
namespace content {
class Page;
class RenderFrameHost;
@@ -58,6 +62,12 @@ class ProfileInteractionManager
mojom::ActivationLevel initial_activation_level,
ActivationDecision* decision) override;
+#if BUILDFLAG(IS_ANDROID)
+ AdsBlockedMessageDelegate* ads_blocked_message_delegate_for_testing() {
+ return ads_blocked_message_delegate_;
+ }
+#endif
+
private:
content::WebContents* GetWebContents();
@@ -71,6 +81,10 @@ class ProfileInteractionManager
raw_ptr<SubresourceFilterProfileContext> profile_context_ = nullptr;
bool ads_violation_triggered_for_last_committed_navigation_ = false;
+
+#if BUILDFLAG(IS_ANDROID)
+ raw_ptr<AdsBlockedMessageDelegate> ads_blocked_message_delegate_;
+#endif
};
} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/content/browser/subframe_navigation_filtering_throttle.cc b/chromium/components/subresource_filter/content/browser/subframe_navigation_filtering_throttle.cc
index 7164e053994..cd72d86e6e8 100644
--- a/chromium/components/subresource_filter/content/browser/subframe_navigation_filtering_throttle.cc
+++ b/chromium/components/subresource_filter/content/browser/subframe_navigation_filtering_throttle.cc
@@ -75,7 +75,7 @@ SubframeNavigationFilteringThrottle::SubframeNavigationFilteringThrottle(
SubframeNavigationFilteringThrottle::~SubframeNavigationFilteringThrottle() {
switch (load_policy_) {
case LoadPolicy::EXPLICITLY_ALLOW:
- FALLTHROUGH;
+ [[fallthrough]];
case LoadPolicy::ALLOW:
UMA_HISTOGRAM_CUSTOM_MICRO_TIMES(
"SubresourceFilter.DocumentLoad.SubframeFilteringDelay.Allowed",
diff --git a/chromium/components/subresource_filter/content/browser/subresource_filter_configuration_unittest.cc b/chromium/components/subresource_filter/content/browser/subresource_filter_configuration_unittest.cc
index b9c43941587..52c073baaec 100644
--- a/chromium/components/subresource_filter/content/browser/subresource_filter_configuration_unittest.cc
+++ b/chromium/components/subresource_filter/content/browser/subresource_filter_configuration_unittest.cc
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include <tuple>
-
#include "components/subresource_filter/content/browser/subresource_filter_test_harness.h"
#include "components/subresource_filter/core/browser/subresource_filter_features.h"
#include "components/subresource_filter/core/common/activation_list.h"
@@ -27,10 +25,7 @@ class SubresourceFilterConfigurationTest
// time we should filter subresources is if we have ALL_SITES scope.
TEST_P(SubresourceFilterConfigurationTest,
DISABLED_NoList_UsuallyNoActivation) {
- ActivationScope scope;
- ActivationList activation_list;
- ActivationLevel level;
- std::tie(scope, activation_list, level) = GetParam();
+ auto [scope, activation_list, level] = GetParam();
SCOPED_TRACE(::testing::Message("ActivationScope: ") << scope);
SCOPED_TRACE(::testing::Message("ActivationList: ") << activation_list);
SCOPED_TRACE(::testing::Message("ActivationLevel: ") << level);
@@ -45,10 +40,7 @@ TEST_P(SubresourceFilterConfigurationTest,
}
TEST_P(SubresourceFilterConfigurationTest, DISABLED_OneListActivation) {
- ActivationScope scope;
- ActivationList activation_list;
- ActivationLevel level;
- std::tie(scope, activation_list, level) = GetParam();
+ auto [scope, activation_list, level] = GetParam();
SCOPED_TRACE(::testing::Message("ActivationScope: ") << scope);
SCOPED_TRACE(::testing::Message("ActivationList: ") << activation_list);
SCOPED_TRACE(::testing::Message("ActivationLevel: ") << level);
diff --git a/chromium/components/subresource_filter/content/browser/subresource_filter_content_settings_manager.cc b/chromium/components/subresource_filter/content/browser/subresource_filter_content_settings_manager.cc
index 104bb53812d..09c7b192b79 100644
--- a/chromium/components/subresource_filter/content/browser/subresource_filter_content_settings_manager.cc
+++ b/chromium/components/subresource_filter/content/browser/subresource_filter_content_settings_manager.cc
@@ -15,6 +15,7 @@
#include "components/content_settings/core/common/content_settings.h"
#include "components/content_settings/core/common/content_settings_constraints.h"
#include "components/content_settings/core/common/content_settings_types.h"
+#include "components/content_settings/core/common/content_settings_utils.h"
#include "url/gurl.h"
namespace subresource_filter {
@@ -27,7 +28,7 @@ const char kActivatedKey[] = "Activated";
const char kNonRenewingExpiryTime[] = "NonRenewingExpiryTime";
bool ShouldUseSmartUI() {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
return true;
#else
return false;
@@ -140,8 +141,9 @@ void SubresourceFilterContentSettingsManager::SetSiteMetadataBasedOnActivation(
std::unique_ptr<base::DictionaryValue>
SubresourceFilterContentSettingsManager::GetSiteMetadata(
const GURL& url) const {
- return base::DictionaryValue::From(settings_map_->GetWebsiteSetting(
- url, GURL(), ContentSettingsType::ADS_DATA, nullptr));
+ return base::DictionaryValue::From(content_settings::ToNullableUniquePtrValue(
+ settings_map_->GetWebsiteSetting(
+ url, GURL(), ContentSettingsType::ADS_DATA, nullptr)));
}
void SubresourceFilterContentSettingsManager::SetSiteMetadataForTesting(
@@ -161,7 +163,7 @@ void SubresourceFilterContentSettingsManager::SetSiteMetadata(
// intervention metadata and should not override the expiry time that
// was previously set.
base::Time expiry_time = base::Time::Now() + kMaxPersistMetadataDuration;
- if (dict && dict->HasKey(kNonRenewingExpiryTime)) {
+ if (dict && dict->FindKey(kNonRenewingExpiryTime)) {
absl::optional<double> metadata_expiry_time =
dict->FindDoubleKey(kNonRenewingExpiryTime);
DCHECK(metadata_expiry_time);
@@ -170,7 +172,9 @@ void SubresourceFilterContentSettingsManager::SetSiteMetadata(
content_settings::ContentSettingConstraints constraints = {expiry_time};
settings_map_->SetWebsiteSettingDefaultScope(
- url, GURL(), ContentSettingsType::ADS_DATA, std::move(dict), constraints);
+ url, GURL(), ContentSettingsType::ADS_DATA,
+ content_settings::FromNullableUniquePtrValue(std::move(dict)),
+ constraints);
}
std::unique_ptr<base::DictionaryValue>
diff --git a/chromium/components/subresource_filter/content/browser/subresource_filter_content_settings_manager_unittest.cc b/chromium/components/subresource_filter/content/browser/subresource_filter_content_settings_manager_unittest.cc
index 6751ab26ba5..80b59753e48 100644
--- a/chromium/components/subresource_filter/content/browser/subresource_filter_content_settings_manager_unittest.cc
+++ b/chromium/components/subresource_filter/content/browser/subresource_filter_content_settings_manager_unittest.cc
@@ -213,7 +213,7 @@ TEST_F(SubresourceFilterContentSettingsManagerTest,
// Verify metadata was actually persisted on site activation false.
auto dict = settings_manager()->GetSiteMetadata(url);
- EXPECT_TRUE(dict->HasKey(kTestKey));
+ EXPECT_TRUE(dict->FindKey(kTestKey));
}
// TODO(https://crbug.com/1113967): Remove test once ability to persist metadata
@@ -240,7 +240,7 @@ TEST_F(SubresourceFilterContentSettingsManagerTest,
SubresourceFilterContentSettingsManager::ActivationSource::kSafeBrowsing);
EXPECT_FALSE(settings_manager()->GetSiteActivationFromMetadata(url));
auto dict = settings_manager()->GetSiteMetadata(url);
- EXPECT_TRUE(dict->HasKey(kTestKey));
+ EXPECT_TRUE(dict->FindKey(kTestKey));
}
// Verifies that the site activation status is True when there is
diff --git a/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle_unittest.cc b/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle_unittest.cc
index 2b6ac2a39d0..89646cfbdd6 100644
--- a/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle_unittest.cc
+++ b/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle_unittest.cc
@@ -50,6 +50,10 @@
#include "services/metrics/public/cpp/ukm_builders.h"
#include "testing/gtest/include/gtest/gtest.h"
+#if BUILDFLAG(IS_ANDROID)
+#include "components/messages/android/mock_message_dispatcher_bridge.h"
+#endif
+
namespace subresource_filter {
namespace {
@@ -180,6 +184,12 @@ class SubresourceFilterSafeBrowsingActivationThrottleTest
Observe(contents);
observer_ = std::make_unique<TestSubresourceFilterObserver>(contents);
+
+#if BUILDFLAG(IS_ANDROID)
+ message_dispatcher_bridge_.SetMessagesEnabledForEmbedder(true);
+ messages::MessageDispatcherBridge::SetInstanceForTesting(
+ &message_dispatcher_bridge_);
+#endif
}
virtual void Configure() {
@@ -202,6 +212,10 @@ class SubresourceFilterSafeBrowsingActivationThrottleTest
RunUntilIdle();
content::RenderViewHostTestHarness::TearDown();
+
+#if BUILDFLAG(IS_ANDROID)
+ messages::MessageDispatcherBridge::SetInstanceForTesting(nullptr);
+#endif
}
TestSubresourceFilterObserver* observer() { return observer_.get(); }
@@ -345,21 +359,10 @@ class SubresourceFilterSafeBrowsingActivationThrottleTest
return &scoped_configuration_;
}
- bool presenting_ads_blocked_infobar() {
- auto* infobar_manager = infobars::ContentInfoBarManager::FromWebContents(
- content::RenderViewHostTestHarness::web_contents());
- if (infobar_manager->infobar_count() == 0)
- return false;
-
- // No infobars other than the ads blocked infobar should be displayed in the
- // context of these tests.
- EXPECT_EQ(infobar_manager->infobar_count(), 1u);
- auto* infobar = infobar_manager->infobar_at(0);
- EXPECT_EQ(infobar->delegate()->GetIdentifier(),
- infobars::InfoBarDelegate::ADS_BLOCKED_INFOBAR_DELEGATE_ANDROID);
-
- return true;
- }
+ protected:
+#if BUILDFLAG(IS_ANDROID)
+ messages::MockMessageDispatcherBridge message_dispatcher_bridge_;
+#endif
private:
testing::ScopedSubresourceFilterConfigurator scoped_configuration_;
@@ -378,6 +381,40 @@ class SubresourceFilterSafeBrowsingActivationThrottleTest
base::HistogramTester tester_;
};
+class SubresourceFilterSafeBrowsingActivationThrottleInfoBarUiTest
+ : public SubresourceFilterSafeBrowsingActivationThrottleTest {
+ public:
+ void SetUp() override {
+ SubresourceFilterSafeBrowsingActivationThrottleTest::SetUp();
+#if BUILDFLAG(IS_ANDROID)
+ message_dispatcher_bridge_.SetMessagesEnabledForEmbedder(false);
+ messages::MessageDispatcherBridge::SetInstanceForTesting(
+ &message_dispatcher_bridge_);
+#endif
+ }
+
+ bool presenting_ads_blocked_infobar() {
+ auto* infobar_manager = infobars::ContentInfoBarManager::FromWebContents(
+ content::RenderViewHostTestHarness::web_contents());
+ if (infobar_manager->infobar_count() == 0)
+ return false;
+
+ // No infobars other than the ads blocked infobar should be displayed in the
+ // context of these tests.
+ EXPECT_EQ(infobar_manager->infobar_count(), 1u);
+ auto* infobar = infobar_manager->infobar_at(0);
+ EXPECT_EQ(infobar->delegate()->GetIdentifier(),
+ infobars::InfoBarDelegate::ADS_BLOCKED_INFOBAR_DELEGATE_ANDROID);
+
+ return true;
+ }
+
+ protected:
+#if BUILDFLAG(IS_ANDROID)
+ messages::MockMessageDispatcherBridge message_dispatcher_bridge_;
+#endif
+};
+
class SubresourceFilterSafeBrowsingActivationThrottleParamTest
: public SubresourceFilterSafeBrowsingActivationThrottleTest,
public ::testing::WithParamInterface<ActivationListTestData> {
@@ -585,12 +622,12 @@ TEST_F(SubresourceFilterSafeBrowsingActivationThrottleTest,
NotificationVisibility) {
GURL url(kURL);
ConfigureForMatch(url);
+#if BUILDFLAG(IS_ANDROID)
+ EXPECT_CALL(message_dispatcher_bridge_, EnqueueMessage);
+#endif
content::RenderFrameHost* rfh = SimulateNavigateAndCommit({url}, main_rfh());
EXPECT_FALSE(CreateAndNavigateDisallowedSubframe(rfh));
-#if defined(OS_ANDROID)
- EXPECT_TRUE(presenting_ads_blocked_infobar());
-#endif
}
TEST_F(SubresourceFilterSafeBrowsingActivationThrottleTest, ActivationList) {
@@ -756,11 +793,11 @@ TEST_F(SubresourceFilterSafeBrowsingActivationThrottleTest,
const GURL url("https://example.test/");
// Navigate initially, should be no activation.
+#if BUILDFLAG(IS_ANDROID)
+ EXPECT_CALL(message_dispatcher_bridge_, EnqueueMessage).Times(0);
+#endif
SimulateNavigateAndCommit({url}, main_rfh());
EXPECT_TRUE(CreateAndNavigateDisallowedSubframe(main_rfh()));
-#if defined(OS_ANDROID)
- EXPECT_FALSE(presenting_ads_blocked_infobar());
-#endif
// Simulate opening devtools and forcing activation.
devtools_interaction_tracker->ToggleForceActivation(true);
@@ -768,11 +805,11 @@ TEST_F(SubresourceFilterSafeBrowsingActivationThrottleTest,
kSubresourceFilterActionsHistogram,
subresource_filter::SubresourceFilterAction::kForcedActivationEnabled, 1);
+#if BUILDFLAG(IS_ANDROID)
+ EXPECT_CALL(message_dispatcher_bridge_, EnqueueMessage);
+#endif
SimulateNavigateAndCommit({url}, main_rfh());
EXPECT_FALSE(CreateAndNavigateDisallowedSubframe(main_rfh()));
-#if defined(OS_ANDROID)
- EXPECT_TRUE(presenting_ads_blocked_infobar());
-#endif
histogram_tester.ExpectBucketCount(
"SubresourceFilter.PageLoad.ActivationDecision",
@@ -798,14 +835,14 @@ TEST_F(SubresourceFilterSafeBrowsingActivationThrottleTest,
base::HistogramTester histogram_tester;
devtools_interaction_tracker->ToggleForceActivation(true);
const GURL url("https://example.test/");
+#if BUILDFLAG(IS_ANDROID)
+ EXPECT_CALL(message_dispatcher_bridge_, EnqueueMessage);
+#endif
SimulateNavigateAndCommit({url}, main_rfh());
devtools_interaction_tracker->ToggleForceActivation(false);
// Resource should be disallowed, since navigation commit had activation.
EXPECT_FALSE(CreateAndNavigateDisallowedSubframe(main_rfh()));
-#if defined(OS_ANDROID)
- EXPECT_TRUE(presenting_ads_blocked_infobar());
-#endif
}
TEST_P(SubresourceFilterSafeBrowsingActivationThrottleScopeTest,
@@ -1095,6 +1132,18 @@ TEST_F(SubresourceFilterSafeBrowsingActivationThrottleTest,
}
}
+TEST_F(SubresourceFilterSafeBrowsingActivationThrottleInfoBarUiTest,
+ NotificationVisibility) {
+ GURL url(kURL);
+ ConfigureForMatch(url);
+ content::RenderFrameHost* rfh = SimulateNavigateAndCommit({url}, main_rfh());
+
+ EXPECT_FALSE(CreateAndNavigateDisallowedSubframe(rfh));
+#if BUILDFLAG(IS_ANDROID)
+ EXPECT_TRUE(presenting_ads_blocked_infobar());
+#endif
+}
+
// Disabled due to flaky failures: https://crbug.com/753669.
TEST_P(SubresourceFilterSafeBrowsingActivationThrottleParamTest,
DISABLED_ListMatchedOnStartWithRedirect_NoActivation) {
diff --git a/chromium/components/subresource_filter/content/browser/subresource_filter_test_harness.cc b/chromium/components/subresource_filter/content/browser/subresource_filter_test_harness.cc
index 6effe1d7081..77b7f2ed782 100644
--- a/chromium/components/subresource_filter/content/browser/subresource_filter_test_harness.cc
+++ b/chromium/components/subresource_filter/content/browser/subresource_filter_test_harness.cc
@@ -103,12 +103,20 @@ void SubresourceFilterTestHarness::SetUp() {
NavigateAndCommit(GURL("https://example.first"));
base::RunLoop().RunUntilIdle();
+#if BUILDFLAG(IS_ANDROID)
+ message_dispatcher_bridge_.SetMessagesEnabledForEmbedder(true);
+ messages::MessageDispatcherBridge::SetInstanceForTesting(
+ &message_dispatcher_bridge_);
+#endif
}
void SubresourceFilterTestHarness::TearDown() {
ruleset_service_.reset();
content::RenderViewHostTestHarness::TearDown();
+#if BUILDFLAG(IS_ANDROID)
+ messages::MessageDispatcherBridge::SetInstanceForTesting(nullptr);
+#endif
}
// content::WebContentsObserver:
diff --git a/chromium/components/subresource_filter/content/browser/subresource_filter_test_harness.h b/chromium/components/subresource_filter/content/browser/subresource_filter_test_harness.h
index 6cb77f7feaa..3fae669cbde 100644
--- a/chromium/components/subresource_filter/content/browser/subresource_filter_test_harness.h
+++ b/chromium/components/subresource_filter/content/browser/subresource_filter_test_harness.h
@@ -16,6 +16,10 @@
#include "content/public/browser/web_contents_observer.h"
#include "content/public/test/test_renderer_host.h"
+#if BUILDFLAG(IS_ANDROID)
+#include "components/messages/android/mock_message_dispatcher_bridge.h"
+#endif
+
class GURL;
namespace content {
@@ -108,6 +112,9 @@ class SubresourceFilterTestHarness : public content::RenderViewHostTestHarness,
std::unique_ptr<ThrottleManagerTestSupport> throttle_manager_test_support_;
std::unique_ptr<infobars::ContentInfoBarManager> infobar_manager_;
std::unique_ptr<RulesetService> ruleset_service_;
+#if BUILDFLAG(IS_ANDROID)
+ messages::MockMessageDispatcherBridge message_dispatcher_bridge_;
+#endif
};
} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/content/renderer/web_document_subresource_filter_impl.cc b/chromium/components/subresource_filter/content/renderer/web_document_subresource_filter_impl.cc
index 24934f50df7..7f54fc5b6fa 100644
--- a/chromium/components/subresource_filter/content/renderer/web_document_subresource_filter_impl.cc
+++ b/chromium/components/subresource_filter/content/renderer/web_document_subresource_filter_impl.cc
@@ -81,7 +81,7 @@ proto::ElementType ToElementType(
WebLoadPolicy ToWebLoadPolicy(LoadPolicy load_policy) {
switch (load_policy) {
case LoadPolicy::EXPLICITLY_ALLOW:
- FALLTHROUGH;
+ [[fallthrough]];
case LoadPolicy::ALLOW:
return WebLoadPolicy::kAllow;
case LoadPolicy::DISALLOW:
@@ -126,6 +126,12 @@ WebDocumentSubresourceFilterImpl::GetLoadPolicyForWebSocketConnect(
return getLoadPolicyImpl(url, proto::ELEMENT_TYPE_WEBSOCKET);
}
+WebLoadPolicy
+WebDocumentSubresourceFilterImpl::GetLoadPolicyForWebTransportConnect(
+ const blink::WebURL& url) {
+ return getLoadPolicyImpl(url, proto::ELEMENT_TYPE_WEBTRANSPORT);
+}
+
void WebDocumentSubresourceFilterImpl::ReportDisallowedLoad() {
if (!first_disallowed_load_callback_.is_null())
std::move(first_disallowed_load_callback_).Run();
diff --git a/chromium/components/subresource_filter/content/renderer/web_document_subresource_filter_impl.h b/chromium/components/subresource_filter/content/renderer/web_document_subresource_filter_impl.h
index 937f7357432..cbfb3b37f94 100644
--- a/chromium/components/subresource_filter/content/renderer/web_document_subresource_filter_impl.h
+++ b/chromium/components/subresource_filter/content/renderer/web_document_subresource_filter_impl.h
@@ -73,6 +73,8 @@ class WebDocumentSubresourceFilterImpl
blink::mojom::RequestContextType) override;
LoadPolicy GetLoadPolicyForWebSocketConnect(
const blink::WebURL& url) override;
+ LoadPolicy GetLoadPolicyForWebTransportConnect(
+ const blink::WebURL& url) override;
void ReportDisallowedLoad() override;
bool ShouldLogToConsole() override;
void ReportAdRequestId(int request_id) override;
diff --git a/chromium/components/subresource_filter/core/common/indexed_ruleset_unittest.cc b/chromium/components/subresource_filter/core/common/indexed_ruleset_unittest.cc
index c7559d01e5f..436a86cc601 100644
--- a/chromium/components/subresource_filter/core/common/indexed_ruleset_unittest.cc
+++ b/chromium/components/subresource_filter/core/common/indexed_ruleset_unittest.cc
@@ -226,12 +226,12 @@ TEST_F(SubresourceFilterIndexedRulesetTest, NonAsciiDomain) {
std::string non_ascii_domain = base::WideToUTF8(L"\x0491\x0493.com");
auto rule = MakeUrlRule(UrlPattern(kUrl, testing::kSubstring));
- testing::AddDomains({non_ascii_domain}, &rule);
+ testing::AddInitiatorDomains({non_ascii_domain}, &rule);
ASSERT_FALSE(AddUrlRule(rule));
rule = MakeUrlRule(UrlPattern(kUrl, testing::kSubstring));
std::string non_ascii_excluded_domain = "~" + non_ascii_domain;
- testing::AddDomains({non_ascii_excluded_domain}, &rule);
+ testing::AddInitiatorDomains({non_ascii_excluded_domain}, &rule);
ASSERT_FALSE(AddUrlRule(rule));
Finish();
@@ -253,7 +253,7 @@ TEST_F(SubresourceFilterIndexedRulesetTest, PercentEncodedDomain) {
std::string percent_encoded_host = "%2C.com";
auto rule = MakeUrlRule(UrlPattern(kUrl, testing::kSubstring));
- testing::AddDomains({percent_encoded_host}, &rule);
+ testing::AddInitiatorDomains({percent_encoded_host}, &rule);
ASSERT_TRUE(AddUrlRule(rule));
Finish();
diff --git a/chromium/components/subresource_filter/core/common/test_ruleset_utils.cc b/chromium/components/subresource_filter/core/common/test_ruleset_utils.cc
index b6e3bc79c6b..2fb272f3439 100644
--- a/chromium/components/subresource_filter/core/common/test_ruleset_utils.cc
+++ b/chromium/components/subresource_filter/core/common/test_ruleset_utils.cc
@@ -33,16 +33,17 @@ proto::UrlRule CreateRuleImpl(base::StringPiece substring,
return rule;
}
-proto::UrlRule CreateRuleForDocumentImpl(base::StringPiece substring,
- int32_t activation_types,
- std::vector<std::string> domains,
- bool is_allowlist_rule,
- bool is_suffix_rule) {
+proto::UrlRule CreateRuleForDocumentImpl(
+ base::StringPiece substring,
+ int32_t activation_types,
+ std::vector<std::string> initiator_domains,
+ bool is_allowlist_rule,
+ bool is_suffix_rule) {
proto::UrlRule rule =
CreateRuleImpl(substring, is_allowlist_rule, is_suffix_rule);
rule.set_activation_types(activation_types);
- for (std::string& domain : domains) {
- rule.add_domains()->set_domain(std::move(domain));
+ for (std::string& domain : initiator_domains) {
+ rule.add_initiator_domains()->set_domain(std::move(domain));
}
return rule;
}
@@ -64,10 +65,11 @@ proto::UrlRule CreateAllowlistSuffixRule(base::StringPiece suffix) {
/*is_suffix_rule=*/true);
}
-proto::UrlRule CreateRuleForDocument(base::StringPiece pattern,
- int32_t activation_types,
- std::vector<std::string> domains) {
- return CreateRuleForDocumentImpl(pattern, activation_types, domains,
+proto::UrlRule CreateRuleForDocument(
+ base::StringPiece pattern,
+ int32_t activation_types,
+ std::vector<std::string> initiator_domains) {
+ return CreateRuleForDocumentImpl(pattern, activation_types, initiator_domains,
/*is_allowlist_rule=*/false,
/*is_suffix_rule=*/false);
}
@@ -75,8 +77,8 @@ proto::UrlRule CreateRuleForDocument(base::StringPiece pattern,
proto::UrlRule CreateAllowlistRuleForDocument(
base::StringPiece pattern,
int32_t activation_types,
- std::vector<std::string> domains) {
- return CreateRuleForDocumentImpl(pattern, activation_types, domains,
+ std::vector<std::string> initiator_domains) {
+ return CreateRuleForDocumentImpl(pattern, activation_types, initiator_domains,
/*is_allowlist_rule=*/true,
/*is_suffix_rule=*/false);
}
diff --git a/chromium/components/subresource_filter/core/common/test_ruleset_utils.h b/chromium/components/subresource_filter/core/common/test_ruleset_utils.h
index 61af431a2a9..8edf524339d 100644
--- a/chromium/components/subresource_filter/core/common/test_ruleset_utils.h
+++ b/chromium/components/subresource_filter/core/common/test_ruleset_utils.h
@@ -32,23 +32,23 @@ url_pattern_index::proto::UrlRule CreateAllowlistSuffixRule(
// Creates a blocklisted URL rule which targets subresources of the specified
// `activation_types` and a URL containing the given `substring`. Additionally,
-// it is restricted to a set of `domains`, if provided.
+// it is restricted to a set of `initiator_domains`, if provided.
url_pattern_index::proto::UrlRule CreateRuleForDocument(
base::StringPiece substring,
int32_t activation_types =
url_pattern_index::proto::ACTIVATION_TYPE_DOCUMENT,
- std::vector<std::string> domains = std::vector<std::string>());
+ std::vector<std::string> initiator_domains = std::vector<std::string>());
// Creates an allowlisted URL rule which targets subresources of the specified
// `activation_types` and a URL containing the given `substring`. Additionally,
-// it is restricted to a set of `domains`, if provided. Note that a URL must
-// match both an allowlist rule and a blocklist rule to be correctly considered
-// allowlisted.
+// it is restricted to a set of `initiator_domains`, if provided. Note that a
+// URL must match both an allowlist rule and a blocklist rule to be correctly
+// considered allowlisted.
url_pattern_index::proto::UrlRule CreateAllowlistRuleForDocument(
base::StringPiece substring,
int32_t activation_types =
url_pattern_index::proto::ACTIVATION_TYPE_DOCUMENT,
- std::vector<std::string> domains = std::vector<std::string>());
+ std::vector<std::string> initiator_domains = std::vector<std::string>());
} // namespace testing
} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/tools/filter_tool_main.cc b/chromium/components/subresource_filter/tools/filter_tool_main.cc
index 7829a3d6947..a1d760f99ab 100644
--- a/chromium/components/subresource_filter/tools/filter_tool_main.cc
+++ b/chromium/components/subresource_filter/tools/filter_tool_main.cc
@@ -114,7 +114,7 @@ int main(int argc, char* argv[]) {
subresource_filter::FilterTool filter_tool(std::move(ruleset), &std::cout);
std::string cmd;
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
cmd = base::WideToASCII(args[0]);
#else
cmd = args[0];
diff --git a/chromium/components/subresource_filter/tools/rule_parser/rule.cc b/chromium/components/subresource_filter/tools/rule_parser/rule.cc
index 74ce4efe1f0..2543df3c10a 100644
--- a/chromium/components/subresource_filter/tools/rule_parser/rule.cc
+++ b/chromium/components/subresource_filter/tools/rule_parser/rule.cc
@@ -105,7 +105,8 @@ url_pattern_index::proto::UrlRule UrlRule::ToProtobuf() const {
}
for (const std::string& domain : domains) {
- url_pattern_index::proto::DomainListItem* list_item = result.add_domains();
+ url_pattern_index::proto::DomainListItem* list_item =
+ result.add_initiator_domains();
if (domain.empty())
continue;
if (domain[0] == '~') {
@@ -294,7 +295,7 @@ std::string ToString(const url_pattern_index::proto::UrlRule& rule) {
break;
case url_pattern_index::proto::SOURCE_TYPE_FIRST_PARTY:
source_type_string = "~";
- FALLTHROUGH;
+ [[fallthrough]];
case url_pattern_index::proto::SOURCE_TYPE_THIRD_PARTY:
source_type_string += "third-party";
options.push_back(std::move(source_type_string));
@@ -306,9 +307,9 @@ std::string ToString(const url_pattern_index::proto::UrlRule& rule) {
if (rule.match_case())
options.push_back("match-case");
- if (rule.domains_size()) {
+ if (rule.initiator_domains_size()) {
std::string domains = "domain=";
- DomainListJoin(rule.domains(), '|', &domains);
+ DomainListJoin(rule.initiator_domains(), '|', &domains);
options.push_back(std::move(domains));
}
diff --git a/chromium/components/subresource_filter/tools/ruleset_converter/ruleset_converter.cc b/chromium/components/subresource_filter/tools/ruleset_converter/ruleset_converter.cc
index f2e491841f1..c21ff94d680 100644
--- a/chromium/components/subresource_filter/tools/ruleset_converter/ruleset_converter.cc
+++ b/chromium/components/subresource_filter/tools/ruleset_converter/ruleset_converter.cc
@@ -82,7 +82,7 @@ bool RulesetConverter::Convert() {
bool RulesetConverter::SetInputFiles(
const base::CommandLine::StringType& comma_separated_paths) {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
std::wstring separatorw = L",";
base::WStringPiece separator(separatorw);
#else
diff --git a/chromium/components/subresource_filter/tools/ruleset_converter/ruleset_converter_unittest.cc b/chromium/components/subresource_filter/tools/ruleset_converter/ruleset_converter_unittest.cc
index 03d3f9e0f41..15674658d0e 100644
--- a/chromium/components/subresource_filter/tools/ruleset_converter/ruleset_converter_unittest.cc
+++ b/chromium/components/subresource_filter/tools/ruleset_converter/ruleset_converter_unittest.cc
@@ -34,7 +34,7 @@ std::vector<std::string> GetSomeRules() {
}
base::CommandLine::StringType AsciiToNativeString(std::string ascii) {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
return base::ASCIIToWide(ascii);
#else
return ascii;
diff --git a/chromium/components/subresource_redirect/BUILD.gn b/chromium/components/subresource_redirect/BUILD.gn
deleted file mode 100644
index c4629b518ba..00000000000
--- a/chromium/components/subresource_redirect/BUILD.gn
+++ /dev/null
@@ -1,29 +0,0 @@
-# Copyright 2021 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.
-
-static_library("test_support") {
- testonly = true
-
- sources = [
- "subresource_redirect_browser_test_util.cc",
- "subresource_redirect_browser_test_util.h",
- "subresource_redirect_test_util.cc",
- "subresource_redirect_test_util.h",
- ]
-
- deps = [
- "//base/test:test_support",
- "//chrome/common:constants",
- "//components/metrics:content",
- "//components/subresource_redirect/proto:proto",
- "//content/test:test_support",
- "//net:test_support",
- "//testing/gtest:gtest",
- "//url:url",
- ]
-
- if (!is_android) {
- deps += [ "//chrome/test:test_support_ui" ]
- }
-}
diff --git a/chromium/components/subresource_redirect/DEPS b/chromium/components/subresource_redirect/DEPS
deleted file mode 100644
index 2b1c72b7034..00000000000
--- a/chromium/components/subresource_redirect/DEPS
+++ /dev/null
@@ -1,9 +0,0 @@
-include_rules = [
- "+chrome/common",
- "+components/data_reduction_proxy",
- "+components/metrics",
- "+content/public/test",
- "+net/base",
- "+net/test/embedded_test_server",
- "+third_party/blink/public/common/features.h",
-]
diff --git a/chromium/components/subresource_redirect/DIR_METADATA b/chromium/components/subresource_redirect/DIR_METADATA
deleted file mode 100644
index 3d3ad0779f9..00000000000
--- a/chromium/components/subresource_redirect/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
- component: "Internals>Network>DataUse"
-}
diff --git a/chromium/components/subresource_redirect/OWNERS b/chromium/components/subresource_redirect/OWNERS
deleted file mode 100644
index 2783dea1c6e..00000000000
--- a/chromium/components/subresource_redirect/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-file://components/data_reduction_proxy/OWNERS
diff --git a/chromium/components/subresource_redirect/common/BUILD.gn b/chromium/components/subresource_redirect/common/BUILD.gn
deleted file mode 100644
index abef86110aa..00000000000
--- a/chromium/components/subresource_redirect/common/BUILD.gn
+++ /dev/null
@@ -1,13 +0,0 @@
-# Copyright 2021 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.
-
-source_set("common") {
- sources = [
- "subresource_redirect_features.cc",
- "subresource_redirect_features.h",
- "subresource_redirect_result.h",
- ]
-
- deps = [ "//third_party/blink/public/common" ]
-}
diff --git a/chromium/components/subresource_redirect/common/subresource_redirect_features.cc b/chromium/components/subresource_redirect/common/subresource_redirect_features.cc
deleted file mode 100644
index f94f28ecbce..00000000000
--- a/chromium/components/subresource_redirect/common/subresource_redirect_features.cc
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright 2021 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.
-
-#include "components/subresource_redirect/common/subresource_redirect_features.h"
-
-#include "base/metrics/field_trial_params.h"
-#include "base/system/sys_info.h"
-#include "third_party/blink/public/common/features.h"
-#include "url/gurl.h"
-
-namespace subresource_redirect {
-
-namespace {
-
-// This default low memory threshold is chosen as the default threshold for
-// Android in
-// SiteIsolationPolicy::ShouldDisableSiteIsolationDueToMemoryThreshold(). This
-// is the threshold for enabling the site-isolation preloaded list and
-// populating the password entered sites. So, the subresource redirect feature
-// should not compress the devices below this threshold.
-constexpr int kDefaultLowMemoryThresholdMb = 1900;
-
-// The default origin for the LitePages.
-constexpr char kDefaultLitePageOrigin[] = "https://litepages.googlezip.net/";
-
-bool IsSubresourceRedirectEnabled() {
- return base::FeatureList::IsEnabled(blink::features::kSubresourceRedirect);
-}
-
-} // namespace
-
-bool ShouldEnablePublicImageHintsBasedCompression() {
- bool is_enabled = IsSubresourceRedirectEnabled() &&
- base::GetFieldTrialParamByFeatureAsBool(
- blink::features::kSubresourceRedirect,
- "enable_public_image_hints_based_compression", true);
- // Only one of the public image hints or login and robots based image
- // compression should be active.
- DCHECK(!is_enabled || !ShouldEnableLoginRobotsCheckedImageCompression());
- return is_enabled;
-}
-
-bool ShouldEnableLoginRobotsCheckedImageCompression() {
- bool is_enabled = IsSubresourceRedirectEnabled() &&
- base::GetFieldTrialParamByFeatureAsBool(
- blink::features::kSubresourceRedirect,
- "enable_login_robots_based_compression", false);
- // Only one of the public image hints or login and robots based image
- // compression should be active.
- DCHECK(!is_enabled || !ShouldEnablePublicImageHintsBasedCompression());
- if (is_enabled && !base::GetFieldTrialParamByFeatureAsBool(
- blink::features::kSubresourceRedirect,
- "enable_login_robots_for_low_memory", false)) {
- return base::SysInfo::AmountOfPhysicalMemoryMB() >
- base::GetFieldTrialParamByFeatureAsInt(
- blink::features::kSubresourceRedirect,
- "login_robots_low_memory_threshold_mb",
- kDefaultLowMemoryThresholdMb);
- }
- return is_enabled;
-}
-
-bool ShouldRecordLoginRobotsCheckedSrcVideoMetrics() {
- return base::FeatureList::IsEnabled(
- blink::features::kSubresourceRedirectSrcVideo);
-}
-
-// Should the subresource be redirected to its compressed version. This returns
-// false if only coverage metrics need to be recorded and actual redirection
-// should not happen.
-bool ShouldCompressRedirectSubresource() {
- return base::FeatureList::IsEnabled(blink::features::kSubresourceRedirect) &&
- base::GetFieldTrialParamByFeatureAsBool(
- blink::features::kSubresourceRedirect,
- "enable_subresource_server_redirect", true);
-}
-
-bool ShouldEnableRobotsRulesFetching() {
- return ShouldEnableLoginRobotsCheckedImageCompression() ||
- ShouldRecordLoginRobotsCheckedSrcVideoMetrics();
-}
-
-url::Origin GetSubresourceRedirectOrigin() {
- auto lite_page_subresource_origin = base::GetFieldTrialParamValueByFeature(
- blink::features::kSubresourceRedirect, "lite_page_subresource_origin");
- if (lite_page_subresource_origin.empty())
- return url::Origin::Create(GURL(kDefaultLitePageOrigin));
- return url::Origin::Create(GURL(lite_page_subresource_origin));
-}
-
-} // namespace subresource_redirect
diff --git a/chromium/components/subresource_redirect/common/subresource_redirect_features.h b/chromium/components/subresource_redirect/common/subresource_redirect_features.h
deleted file mode 100644
index 68ea7038da9..00000000000
--- a/chromium/components/subresource_redirect/common/subresource_redirect_features.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2021 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.
-
-#ifndef COMPONENTS_SUBRESOURCE_REDIRECT_COMMON_SUBRESOURCE_REDIRECT_FEATURES_H_
-#define COMPONENTS_SUBRESOURCE_REDIRECT_COMMON_SUBRESOURCE_REDIRECT_FEATURES_H_
-
-#include "url/origin.h"
-
-namespace subresource_redirect {
-
-// Returns if the public image hints based subresource compression is enabled.
-bool ShouldEnablePublicImageHintsBasedCompression();
-
-// Returns if the login and robots checks based image compression is enabled.
-// This compresses images in non logged-in pages allowed by robots.txt rules.
-bool ShouldEnableLoginRobotsCheckedImageCompression();
-
-// Returns if the login and robots checks based src-video metrics recording is
-// enabled. This only records data use and coverage metrics for src videos on
-// non logged-in pages allowed by robots.txt rules.
-bool ShouldRecordLoginRobotsCheckedSrcVideoMetrics();
-
-// Should the subresource be redirected to its compressed version. This returns
-// false if only coverage metrics need to be recorded and actual redirection
-// should not happen.
-bool ShouldCompressRedirectSubresource();
-
-// Returns whether robots rules can be fetched. Robots rules fetching is enabled
-// when certain features are active, such as robots and login checked image
-// and src-video compression.
-bool ShouldEnableRobotsRulesFetching();
-
-// Returns the origin to use for subresource redirect from fieldtrial or the
-// default.
-url::Origin GetSubresourceRedirectOrigin();
-
-} // namespace subresource_redirect
-
-#endif // COMPONENTS_SUBRESOURCE_REDIRECT_COMMON_SUBRESOURCE_REDIRECT_FEATURES_H_
diff --git a/chromium/components/subresource_redirect/common/subresource_redirect_result.h b/chromium/components/subresource_redirect/common/subresource_redirect_result.h
deleted file mode 100644
index dae817b683b..00000000000
--- a/chromium/components/subresource_redirect/common/subresource_redirect_result.h
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright 2020 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.
-
-#ifndef COMPONENTS_SUBRESOURCE_REDIRECT_COMMON_SUBRESOURCE_REDIRECT_RESULT_H_
-#define COMPONENTS_SUBRESOURCE_REDIRECT_COMMON_SUBRESOURCE_REDIRECT_RESULT_H_
-
-namespace subresource_redirect {
-
-// Enumerates the different results possible for subresource redirection, such
-// as redirectable or different reasons of ineligibility. This enum should be in
-// sync with SubresourceRedirectRedirectResult in enums.xml
-enum class SubresourceRedirectResult {
- kUnknown = 0,
-
- // The image was determined as public and is eligible to be redirected
- // to a compressed version.
- kRedirectable = 1,
-
- // Possible reasons for ineligibility:
-
- // Because of reasons Blink could disallow compression such as non <img>
- // element, CSP/CORS security restrictions, javascript initiated image, etc.
- kIneligibleBlinkDisallowed = 2,
-
- // Because the resource is fetched for a subframe.
- kIneligibleSubframeResource = 3,
-
- // Because the compressed subresource fetch failed, and then the original
- // subresource was loaded.
- kIneligibleRedirectFailed = 4,
-
- // Possible reasons for ineligibility due to public image hints approach:
-
- // Because the image hint list was not retrieved within certain time limit
- // of navigation start,
- kIneligibleImageHintsUnavailable = 5,
-
- // Because the image hint list was not retrieved at the time of image fetch,
- // but the image URL was found in the hint list, which finished fetching
- // later.
- kIneligibleImageHintsUnavailableButRedirectable = 6,
-
- // Because the image hint list was not retrieved at the time of image fetch,
- // and the image URL was not in the hint list as well, which finished
- // fetching later.
- kIneligibleImageHintsUnavailableAndMissingInHints = 7,
-
- // Because the image URL was not found in the image hints.
- kIneligibleMissingInImageHints = 8,
-
- // Possible reasons for ineligibility due to login and robots rules
- // based approach:
-
- // Because the image was disallowed by robots rules of the image origin.
- kIneligibleRobotsDisallowed = 9,
-
- // Because the robots rules fetch timedout.
- kIneligibleRobotsTimeout = 10,
-
- // Because the page was detected to be logged-in.
- kIneligibleLoginDetected = 11,
-
- // Because the subresource was within the first k subresources on the page and
- // got disabled.
- kIneligibleFirstKDisableSubresourceRedirect = 12,
-
- // Because the subresource redirection was disabled, where only metrics are
- // recorded and the actual subresource redirection does not happen.
- kIneligibleCompressionDisabled = 13,
-
- kMaxValue = SubresourceRedirectResult::kIneligibleCompressionDisabled
-};
-
-} // namespace subresource_redirect
-
-#endif // COMPONENTS_SUBRESOURCE_REDIRECT_COMMON_SUBRESOURCE_REDIRECT_RESULT_H_
diff --git a/chromium/components/subresource_redirect/proto/BUILD.gn b/chromium/components/subresource_redirect/proto/BUILD.gn
deleted file mode 100644
index b54caebd79a..00000000000
--- a/chromium/components/subresource_redirect/proto/BUILD.gn
+++ /dev/null
@@ -1,9 +0,0 @@
-# Copyright 2021 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.
-
-import("//third_party/protobuf/proto_library.gni")
-
-proto_library("proto") {
- sources = [ "robots_rules.proto" ]
-}
diff --git a/chromium/components/subresource_redirect/proto/robots_rules.proto b/chromium/components/subresource_redirect/proto/robots_rules.proto
deleted file mode 100644
index 72173ba6142..00000000000
--- a/chromium/components/subresource_redirect/proto/robots_rules.proto
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2020 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.
-
-syntax = "proto2";
-
-option optimize_for = LITE_RUNTIME;
-
-package subresource_redirect.proto;
-
-message RobotsRules {
- // A single page-pattern rule, either allowed or disallowed.
- message Rule {
- oneof rule_field {
- // The allowed path-patterns.
- string allowed_pattern = 1;
- // The disallowed path-patterns.
- string disallowed_pattern = 2;
- }
- }
-
- // Rules for image resources, ordered by length (longest first).
- repeated Rule image_ordered_rules = 1;
- // Rules for video resources, ordered by length (longest first).
- repeated Rule video_ordered_rules = 2;
-} \ No newline at end of file
diff --git a/chromium/components/subresource_redirect/subresource_redirect_browser_test_util.cc b/chromium/components/subresource_redirect/subresource_redirect_browser_test_util.cc
deleted file mode 100644
index b76205fafa5..00000000000
--- a/chromium/components/subresource_redirect/subresource_redirect_browser_test_util.cc
+++ /dev/null
@@ -1,177 +0,0 @@
-// Copyright 2021 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.
-
-#include "components/subresource_redirect/subresource_redirect_browser_test_util.h"
-
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/path_service.h"
-#include "chrome/common/chrome_paths.h"
-#include "components/metrics/content/subprocess_metrics_provider.h"
-#include "components/subresource_redirect/proto/robots_rules.pb.h"
-#include "content/public/test/browser_test_utils.h"
-#include "net/base/url_util.h"
-#include "net/test/embedded_test_server/http_request.h"
-#include "net/test/embedded_test_server/http_response.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace subresource_redirect {
-
-void RetryForHistogramUntilCountReached(base::HistogramTester* histogram_tester,
- const std::string& histogram_name,
- size_t count) {
- while (true) {
- FetchHistogramsFromChildProcesses();
-
- const std::vector<base::Bucket> buckets =
- histogram_tester->GetAllSamples(histogram_name);
- size_t total_count = 0;
- for (const auto& bucket : buckets) {
- total_count += bucket.count;
- }
- if (total_count >= count) {
- break;
- }
- }
-}
-
-void FetchHistogramsFromChildProcesses() {
- content::FetchHistogramsFromChildProcesses();
- metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
-}
-
-RobotsRulesTestServer::RobotsRulesTestServer()
- : server_(net::EmbeddedTestServer::TYPE_HTTPS) {}
-
-RobotsRulesTestServer::~RobotsRulesTestServer() = default;
-
-bool RobotsRulesTestServer::Start() {
- server_.ServeFilesFromSourceDirectory("chrome/test/data");
- server_.RegisterRequestHandler(base::BindRepeating(
- &RobotsRulesTestServer::OnServerRequest, base::Unretained(this)));
- server_.RegisterRequestMonitor(base::BindRepeating(
- &RobotsRulesTestServer::OnRequestMonitor, base::Unretained(this)));
- return server_.Start();
-}
-
-void RobotsRulesTestServer::AddRobotsRules(
- const GURL& origin,
- const std::vector<RobotsRule>& robots_rules) {
- robots_rules_proto_[origin.spec()] = GetRobotsRulesProtoString(robots_rules);
-}
-
-void RobotsRulesTestServer::VerifyRequestedOrigins(
- const std::set<std::string>& requests) {
- EXPECT_EQ(received_requests_, requests);
-}
-
-std::unique_ptr<net::test_server::HttpResponse>
-RobotsRulesTestServer::OnServerRequest(
- const net::test_server::HttpRequest& request) {
- std::unique_ptr<net::test_server::BasicHttpResponse> response =
- std::make_unique<net::test_server::BasicHttpResponse>();
- std::string robots_url_str;
- EXPECT_EQ("/robots", request.GetURL().path());
- EXPECT_TRUE(
- net::GetValueForKeyInQuery(request.GetURL(), "u", &robots_url_str));
- GURL robots_url(robots_url_str);
- EXPECT_EQ("/robots.txt", GURL(robots_url).path());
-
- switch (failure_mode_) {
- case FailureMode::kLoadshed503RetryAfterResponse:
- response->set_code(net::HTTP_SERVICE_UNAVAILABLE);
- response->AddCustomHeader("Retry-After", "5");
- return response;
- case FailureMode::kTimeout:
- response = std::make_unique<net::test_server::DelayedHttpResponse>(
- base::Seconds(4));
- break;
- case FailureMode::kNone:
- break;
- }
-
- auto it =
- robots_rules_proto_.find(robots_url.DeprecatedGetOriginAsURL().spec());
- if (it != robots_rules_proto_.end())
- response->set_content(it->second);
- return std::move(response);
-}
-
-void RobotsRulesTestServer::OnRequestMonitor(
- const net::test_server::HttpRequest& request) {
- std::string robots_url_str;
- EXPECT_EQ("/robots", request.GetURL().path());
- EXPECT_TRUE(
- net::GetValueForKeyInQuery(request.GetURL(), "u", &robots_url_str));
- std::string robots_origin =
- GURL(robots_url_str).DeprecatedGetOriginAsURL().spec();
- EXPECT_TRUE(received_requests_.find(robots_origin) ==
- received_requests_.end());
- received_requests_.insert(robots_origin);
-}
-
-ImageCompressionTestServer::ImageCompressionTestServer()
- : server_(net::EmbeddedTestServer::TYPE_HTTPS) {}
-
-ImageCompressionTestServer::~ImageCompressionTestServer() = default;
-
-bool ImageCompressionTestServer::Start() {
- server_.ServeFilesFromSourceDirectory("chrome/test/data");
- server_.RegisterRequestHandler(base::BindRepeating(
- &ImageCompressionTestServer::OnServerRequest, base::Unretained(this)));
- server_.RegisterRequestMonitor(base::BindRepeating(
- &ImageCompressionTestServer::OnRequestMonitor, base::Unretained(this)));
- return server_.Start();
-}
-
-void ImageCompressionTestServer::VerifyRequestedImagePaths(
- const std::set<std::string>& paths) {
- EXPECT_EQ(received_request_paths_, paths);
-}
-
-std::unique_ptr<net::test_server::HttpResponse>
-ImageCompressionTestServer::OnServerRequest(
- const net::test_server::HttpRequest& request) {
- std::unique_ptr<net::test_server::BasicHttpResponse> response =
- std::make_unique<net::test_server::BasicHttpResponse>();
-
- switch (failure_mode_) {
- case FailureMode::kLoadshed503RetryAfterResponse:
- response->set_code(net::HTTP_SERVICE_UNAVAILABLE);
- response->AddCustomHeader("Retry-After", "5");
- return response;
- case FailureMode::kNone:
- break;
- }
-
- // Serve the correct image file.
- std::string img_url;
- std::string file_contents;
- base::FilePath test_data_directory;
- EXPECT_EQ("/i", request.GetURL().path());
- EXPECT_TRUE(net::GetValueForKeyInQuery(request.GetURL(), "u", &img_url));
- base::PathService::Get(chrome::DIR_TEST_DATA, &test_data_directory);
- if (base::ReadFileToString(
- test_data_directory.AppendASCII(GURL(img_url).path().substr(1)),
- &file_contents)) {
- response->AddCustomHeader("Chrome-Proxy", "ofcl=10000");
- response->set_content(file_contents);
- response->set_code(net::HTTP_OK);
- }
- return std::move(response);
-}
-
-// Called on every subresource request
-void ImageCompressionTestServer::OnRequestMonitor(
- const net::test_server::HttpRequest& request) {
- std::string img_url;
- EXPECT_EQ("/i", request.GetURL().path());
- EXPECT_TRUE(net::GetValueForKeyInQuery(request.GetURL(), "u", &img_url));
- img_url = GURL(img_url).PathForRequest();
- EXPECT_TRUE(received_request_paths_.find(img_url) ==
- received_request_paths_.end());
- received_request_paths_.insert(img_url);
-}
-
-} // namespace subresource_redirect
diff --git a/chromium/components/subresource_redirect/subresource_redirect_browser_test_util.h b/chromium/components/subresource_redirect/subresource_redirect_browser_test_util.h
deleted file mode 100644
index 969abdbb43e..00000000000
--- a/chromium/components/subresource_redirect/subresource_redirect_browser_test_util.h
+++ /dev/null
@@ -1,119 +0,0 @@
-// Copyright 2021 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.
-
-#ifndef COMPONENTS_SUBRESOURCE_REDIRECT_SUBRESOURCE_REDIRECT_BROWSER_TEST_UTIL_H_
-#define COMPONENTS_SUBRESOURCE_REDIRECT_SUBRESOURCE_REDIRECT_BROWSER_TEST_UTIL_H_
-
-#include <map>
-#include <set>
-#include <string>
-
-#include "base/test/metrics/histogram_tester.h"
-#include "components/subresource_redirect/subresource_redirect_test_util.h"
-#include "net/test/embedded_test_server/embedded_test_server.h"
-#include "url/gurl.h"
-
-namespace subresource_redirect {
-
-// Retries fetching |histogram_name| until it contains at least |count| samples.
-void RetryForHistogramUntilCountReached(base::HistogramTester* histogram_tester,
- const std::string& histogram_name,
- size_t count);
-
-// Fetches histograms from renderer child processes.
-void FetchHistogramsFromChildProcesses();
-
-// Embedded test server for the robots rules.
-class RobotsRulesTestServer {
- public:
- // Different failures modes the robots server should return.
- enum FailureMode {
- kNone = 0,
- kLoadshed503RetryAfterResponse,
- kTimeout,
- };
-
- RobotsRulesTestServer();
- ~RobotsRulesTestServer();
-
- // Start the server.
- bool Start();
-
- std::string GetURL() const {
- return server_.GetURL("robotsrules.com", "/").spec();
- }
-
- void AddRobotsRules(const GURL& origin,
- const std::vector<RobotsRule>& robots_rules);
-
- void VerifyRequestedOrigins(const std::set<std::string>& requests);
-
- std::set<std::string> received_requests() const { return received_requests_; }
-
- void set_failure_mode(FailureMode failure_mode) {
- failure_mode_ = failure_mode;
- }
-
- private:
- std::unique_ptr<net::test_server::HttpResponse> OnServerRequest(
- const net::test_server::HttpRequest& request);
-
- // Called on every robots request.
- void OnRequestMonitor(const net::test_server::HttpRequest& request);
-
- // Robots rules proto keyed by origin.
- std::map<std::string, std::string> robots_rules_proto_;
-
- // Whether the robots server should return failure.
- FailureMode failure_mode_ = FailureMode::kNone;
-
- // All the origins the robots rules are requested for.
- std::set<std::string> received_requests_;
-
- net::EmbeddedTestServer server_;
-};
-
-// Embedded test server to serve the image resources.
-class ImageCompressionTestServer {
- public:
- // Different failures modes the image server should return
- enum FailureMode {
- kNone = 0,
- kLoadshed503RetryAfterResponse,
- };
- ImageCompressionTestServer();
- ~ImageCompressionTestServer();
-
- // Start the server.
- bool Start();
-
- std::string GetURL() const {
- return server_.GetURL("imagecompression.com", "/").spec();
- }
-
- void VerifyRequestedImagePaths(const std::set<std::string>& paths);
-
- void set_failure_mode(FailureMode failure_mode) {
- failure_mode_ = failure_mode;
- }
-
- private:
- std::unique_ptr<net::test_server::HttpResponse> OnServerRequest(
- const net::test_server::HttpRequest& request);
-
- // Called on every subresource request.
- void OnRequestMonitor(const net::test_server::HttpRequest& request);
-
- // All the URL paths of the requested images.
- std::set<std::string> received_request_paths_;
-
- // Whether the subresource server should return failure.
- FailureMode failure_mode_ = FailureMode::kNone;
-
- net::EmbeddedTestServer server_;
-};
-
-} // namespace subresource_redirect
-
-#endif // COMPONENTS_SUBRESOURCE_REDIRECT_SUBRESOURCE_REDIRECT_BROWSER_TEST_UTIL_H_
diff --git a/chromium/components/subresource_redirect/subresource_redirect_test_util.cc b/chromium/components/subresource_redirect/subresource_redirect_test_util.cc
deleted file mode 100644
index 0ba4a48d5c3..00000000000
--- a/chromium/components/subresource_redirect/subresource_redirect_test_util.cc
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2021 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.
-
-#include "components/subresource_redirect/subresource_redirect_test_util.h"
-
-#include "components/subresource_redirect/proto/robots_rules.pb.h"
-
-namespace subresource_redirect {
-
-std::string GetRobotsRulesProtoString(const std::vector<RobotsRule>& patterns) {
- proto::RobotsRules robots_rules;
- for (const auto& pattern : patterns) {
- auto* new_rule = robots_rules.add_image_ordered_rules();
- if (pattern.rule_type == kRuleTypeAllow) {
- new_rule->set_allowed_pattern(pattern.pattern);
- } else {
- new_rule->set_disallowed_pattern(pattern.pattern);
- }
- }
- return robots_rules.SerializeAsString();
-}
-
-} // namespace subresource_redirect
diff --git a/chromium/components/subresource_redirect/subresource_redirect_test_util.h b/chromium/components/subresource_redirect/subresource_redirect_test_util.h
deleted file mode 100644
index 713197fef25..00000000000
--- a/chromium/components/subresource_redirect/subresource_redirect_test_util.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2021 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.
-
-#ifndef COMPONENTS_SUBRESOURCE_REDIRECT_SUBRESOURCE_REDIRECT_TEST_UTIL_H_
-#define COMPONENTS_SUBRESOURCE_REDIRECT_SUBRESOURCE_REDIRECT_TEST_UTIL_H_
-
-#include <string>
-
-namespace subresource_redirect {
-
-const bool kRuleTypeAllow = true;
-const bool kRuleTypeDisallow = false;
-
-// Holds one allow or disallow robots rule
-struct RobotsRule {
- RobotsRule(bool rule_type, const std::string& pattern)
- : rule_type(rule_type), pattern(pattern) {}
-
- bool rule_type;
- std::string pattern;
-};
-
-// Convert robots rules to its proto.
-std::string GetRobotsRulesProtoString(const std::vector<RobotsRule>& patterns);
-
-} // namespace subresource_redirect
-
-#endif // COMPONENTS_SUBRESOURCE_REDIRECT_SUBRESOURCE_REDIRECT_TEST_UTIL_H_
diff --git a/chromium/components/sync/BUILD.gn b/chromium/components/sync/BUILD.gn
index e854b83e435..2acdb0cc5fc 100644
--- a/chromium/components/sync/BUILD.gn
+++ b/chromium/components/sync/BUILD.gn
@@ -129,7 +129,6 @@ source_set("unit_tests") {
sources = [
"base/client_tag_hash_unittest.cc",
"base/model_type_unittest.cc",
- "base/node_ordinal_unittest.cc",
"base/ordinal_unittest.cc",
"base/protobuf_unittest.cc",
"base/sync_prefs_unittest.cc",
@@ -158,11 +157,11 @@ source_set("unit_tests") {
"engine/cancelation_signal_unittest.cc",
"engine/commit_contribution_impl_unittest.cc",
"engine/commit_processor_unittest.cc",
+ "engine/cycle/commit_quota_unittest.cc",
"engine/cycle/nudge_tracker_unittest.cc",
"engine/cycle/status_controller_unittest.cc",
"engine/cycle/sync_cycle_snapshot_unittest.cc",
"engine/debug_info_event_listener_unittest.cc",
- "engine/entity_data_unittest.cc",
"engine/events/protocol_event_buffer_unittest.cc",
"engine/get_updates_processor_unittest.cc",
"engine/loopback_server/loopback_server_unittest.cc",
@@ -174,6 +173,7 @@ source_set("unit_tests") {
"engine/model_type_worker_unittest.cc",
"engine/net/http_bridge_unittest.cc",
"engine/net/sync_server_connection_manager_unittest.cc",
+ "engine/nigori/nigori_unittest.cc",
"engine/sync_manager_impl_unittest.cc",
"engine/sync_scheduler_impl_unittest.cc",
"engine/syncer_proto_util_unittest.cc",
@@ -201,7 +201,7 @@ source_set("unit_tests") {
"nigori/nigori_state_unittest.cc",
"nigori/nigori_storage_impl_unittest.cc",
"nigori/nigori_sync_bridge_impl_unittest.cc",
- "nigori/nigori_unittest.cc",
+ "protocol/entity_data_unittest.cc",
"protocol/proto_enum_conversions_unittest.cc",
"protocol/proto_value_conversions_unittest.cc",
]
diff --git a/chromium/components/sync/android/BUILD.gn b/chromium/components/sync/android/BUILD.gn
index 5b75efa9506..47e91cf8091 100644
--- a/chromium/components/sync/android/BUILD.gn
+++ b/chromium/components/sync/android/BUILD.gn
@@ -23,7 +23,6 @@ java_cpp_enum("java_enums") {
sources = [
"//components/sync/base/model_type.h",
"//components/sync/base/passphrase_enums.h",
- "//components/sync/base/stop_source.h",
"//components/sync/driver/sync_service_utils.h",
]
}
diff --git a/chromium/components/sync/base/BUILD.gn b/chromium/components/sync/base/BUILD.gn
index a95b503a42b..f7539be4907 100644
--- a/chromium/components/sync/base/BUILD.gn
+++ b/chromium/components/sync/base/BUILD.gn
@@ -15,38 +15,37 @@ static_library("base") {
"bind_to_task_runner.h",
"client_tag_hash.cc",
"client_tag_hash.h",
+ "command_line_switches.cc",
+ "command_line_switches.h",
"data_type_histogram.cc",
"data_type_histogram.h",
"extensions_activity.cc",
"extensions_activity.h",
+ "features.cc",
+ "features.h",
"hash_util.cc",
"hash_util.h",
"invalidation_adapter.cc",
"invalidation_adapter.h",
"invalidation_helper.cc",
"invalidation_helper.h",
- "invalidation_interface.cc",
- "invalidation_interface.h",
"legacy_directory_deletion.cc",
"legacy_directory_deletion.h",
"logging.cc",
"logging.h",
"model_type.cc",
"model_type.h",
- "node_ordinal.cc",
- "node_ordinal.h",
"ordinal.h",
"passphrase_enums.cc",
"passphrase_enums.h",
- "pref_names.cc",
"pref_names.h",
"progress_marker_map.cc",
"progress_marker_map.h",
"report_unrecoverable_error.cc",
"report_unrecoverable_error.h",
"stop_source.h",
- "sync_base_switches.cc",
- "sync_base_switches.h",
+ "sync_invalidation.cc",
+ "sync_invalidation.h",
"sync_mode.h",
"sync_prefs.cc",
"sync_prefs.h",
diff --git a/chromium/components/sync/base/node_ordinal.h b/chromium/components/sync/base/node_ordinal.h
deleted file mode 100644
index 38f2cde41b1..00000000000
--- a/chromium/components/sync/base/node_ordinal.h
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2012 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.
-
-#ifndef COMPONENTS_SYNC_BASE_NODE_ORDINAL_H_
-#define COMPONENTS_SYNC_BASE_NODE_ORDINAL_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include "components/sync/base/ordinal.h"
-
-namespace syncer {
-
-// A NodeOrdinal is an Ordinal whose internal value comes from the
-// ordinal_in_parent field of SyncEntity (see sync.proto). It uses
-// the entire uint8_t range for backwards compatibility with the old
-// int64_t-based positioning.
-
-struct NodeOrdinalTraits {
- static const uint8_t kZeroDigit = 0;
- static const uint8_t kMaxDigit = UINT8_MAX;
- static const size_t kMinLength = 8;
-};
-
-using NodeOrdinal = Ordinal<NodeOrdinalTraits>;
-
-static_assert(static_cast<char>(NodeOrdinal::kZeroDigit) == '\x00',
- "NodeOrdinal has incorrect zero digit");
-static_assert(static_cast<char>(NodeOrdinal::kOneDigit) == '\x01',
- "NodeOrdinal has incorrect one digit");
-static_assert(static_cast<char>(NodeOrdinal::kMidDigit) == '\x80',
- "NodeOrdinal has incorrect mid digit");
-static_assert(static_cast<char>(NodeOrdinal::kMaxDigit) == '\xff',
- "NodeOrdinal has incorrect max digit");
-static_assert(NodeOrdinal::kMidDigitValue == 128,
- "NodeOrdinal has incorrect mid digit value");
-static_assert(NodeOrdinal::kMaxDigitValue == 255,
- "NodeOrdinal has incorrect max digit value");
-static_assert(NodeOrdinal::kRadix == 256, "NodeOrdinal has incorrect radix");
-
-// Converts an int64_t position (usually from the position_in_parent
-// field of SyncEntity) to a NodeOrdinal. This transformation
-// preserves the ordering relation: a < b under integer ordering if
-// and only if Int64ToNodeOrdinal(a) < Int64ToNodeOrdinal(b).
-NodeOrdinal Int64ToNodeOrdinal(int64_t x);
-
-// The inverse of Int64ToNodeOrdinal. This conversion is, in general,
-// lossy: NodeOrdinals can have arbitrary fidelity, while numeric
-// positions contain only 64 bits of information (in fact, this is the
-// reason we've moved away from them).
-int64_t NodeOrdinalToInt64(const NodeOrdinal& ordinal);
-
-} // namespace syncer
-
-#endif // COMPONENTS_SYNC_BASE_NODE_ORDINAL_H_
diff --git a/chromium/components/sync/base/ordinal.h b/chromium/components/sync/base/ordinal.h
index c73b07cdf04..7314f1fee19 100644
--- a/chromium/components/sync/base/ordinal.h
+++ b/chromium/components/sync/base/ordinal.h
@@ -226,7 +226,7 @@ template <typename Traits>
const unsigned int Ordinal<Traits>::kRadix;
template <typename Traits>
-Ordinal<Traits>::LessThanFn::LessThanFn() {}
+Ordinal<Traits>::LessThanFn::LessThanFn() = default;
template <typename Traits>
bool Ordinal<Traits>::LessThanFn::operator()(const Ordinal<Traits>& lhs,
@@ -235,7 +235,7 @@ bool Ordinal<Traits>::LessThanFn::operator()(const Ordinal<Traits>& lhs,
}
template <typename Traits>
-Ordinal<Traits>::EqualsFn::EqualsFn() {}
+Ordinal<Traits>::EqualsFn::EqualsFn() = default;
template <typename Traits>
bool Ordinal<Traits>::EqualsFn::operator()(const Ordinal<Traits>& lhs,
diff --git a/chromium/components/sync/driver/BUILD.gn b/chromium/components/sync/driver/BUILD.gn
index d78908a1278..17b1b21fd9e 100644
--- a/chromium/components/sync/driver/BUILD.gn
+++ b/chromium/components/sync/driver/BUILD.gn
@@ -43,8 +43,6 @@ static_library("driver") {
"sync_auth_util.cc",
"sync_auth_util.h",
"sync_client.h",
- "sync_driver_switches.cc",
- "sync_driver_switches.h",
"sync_internals_util.cc",
"sync_internals_util.h",
"sync_policy_handler.cc",
@@ -92,7 +90,6 @@ static_library("driver") {
"//base",
"//base:i18n",
"//build:chromeos_buildflags",
- "//components/data_use_measurement/core",
"//components/invalidation/impl:feature_list",
"//components/keyed_service/core",
"//components/metrics",
diff --git a/chromium/components/sync/engine/BUILD.gn b/chromium/components/sync/engine/BUILD.gn
index c0c198bac98..e9fcf08e35b 100644
--- a/chromium/components/sync/engine/BUILD.gn
+++ b/chromium/components/sync/engine/BUILD.gn
@@ -26,6 +26,8 @@ static_library("engine") {
"commit_util.cc",
"commit_util.h",
"configure_reason.h",
+ "cycle/commit_quota.cc",
+ "cycle/commit_quota.h",
"cycle/data_type_tracker.cc",
"cycle/data_type_tracker.h",
"cycle/debug_info_getter.h",
@@ -52,8 +54,6 @@ static_library("engine") {
"engine_components_factory.h",
"engine_components_factory_impl.cc",
"engine_components_factory_impl.h",
- "entity_data.cc",
- "entity_data.h",
"events/commit_request_event.cc",
"events/commit_request_event.h",
"events/commit_response_event.cc",
@@ -107,8 +107,8 @@ static_library("engine") {
"model_type_worker.h",
"net/http_bridge.cc",
"net/http_bridge.h",
+ "net/http_post_provider.h",
"net/http_post_provider_factory.h",
- "net/http_post_provider_interface.h",
"net/server_connection_manager.cc",
"net/server_connection_manager.h",
"net/sync_server_connection_manager.cc",
@@ -135,8 +135,6 @@ static_library("engine") {
"sync_engine.h",
"sync_engine_event_listener.h",
"sync_engine_host.h",
- "sync_engine_switches.cc",
- "sync_engine_switches.h",
"sync_manager.cc",
"sync_manager.h",
"sync_manager_factory.cc",
diff --git a/chromium/components/sync/invalidations/BUILD.gn b/chromium/components/sync/invalidations/BUILD.gn
index 713dbd25793..c48a9d38c45 100644
--- a/chromium/components/sync/invalidations/BUILD.gn
+++ b/chromium/components/sync/invalidations/BUILD.gn
@@ -13,8 +13,6 @@ static_library("invalidations") {
"interested_data_types_manager.cc",
"interested_data_types_manager.h",
"invalidations_listener.h",
- "switches.cc",
- "switches.h",
"sync_invalidations_service.h",
"sync_invalidations_service_impl.cc",
"sync_invalidations_service_impl.h",
diff --git a/chromium/components/sync/protocol/BUILD.gn b/chromium/components/sync/protocol/BUILD.gn
index 64fd7082d5b..795d9bb4d63 100644
--- a/chromium/components/sync/protocol/BUILD.gn
+++ b/chromium/components/sync/protocol/BUILD.gn
@@ -17,6 +17,8 @@ proto_library("protocol") {
# together with the "protocol" target and simplify things.
static_library("util") {
sources = [
+ "entity_data.cc",
+ "entity_data.h",
"proto_enum_conversions.cc",
"proto_enum_conversions.h",
"proto_memory_estimations.cc",
diff --git a/chromium/components/sync/trusted_vault/BUILD.gn b/chromium/components/sync/trusted_vault/BUILD.gn
index 3ada626e9ac..04c90f6e88b 100644
--- a/chromium/components/sync/trusted_vault/BUILD.gn
+++ b/chromium/components/sync/trusted_vault/BUILD.gn
@@ -30,8 +30,6 @@ if (!is_android) {
"trusted_vault_request.h",
"trusted_vault_server_constants.cc",
"trusted_vault_server_constants.h",
- "trusted_vault_switches.cc",
- "trusted_vault_switches.h",
]
public_deps = [
"//base",
diff --git a/chromium/components/sync_bookmarks/BUILD.gn b/chromium/components/sync_bookmarks/BUILD.gn
index 7785fc1ae60..4db0271eb70 100644
--- a/chromium/components/sync_bookmarks/BUILD.gn
+++ b/chromium/components/sync_bookmarks/BUILD.gn
@@ -20,7 +20,8 @@ static_library("sync_bookmarks") {
"bookmark_specifics_conversions.h",
"bookmark_sync_service.cc",
"bookmark_sync_service.h",
- "switches.cc",
+ "parent_guid_preprocessing.cc",
+ "parent_guid_preprocessing.h",
"switches.h",
"synced_bookmark_tracker.cc",
"synced_bookmark_tracker.h",
@@ -48,6 +49,7 @@ source_set("unit_tests") {
"bookmark_model_type_processor_unittest.cc",
"bookmark_remote_updates_handler_unittest.cc",
"bookmark_specifics_conversions_unittest.cc",
+ "parent_guid_preprocessing_unittest.cc",
"synced_bookmark_tracker_unittest.cc",
]
diff --git a/chromium/components/sync_bookmarks/README.md b/chromium/components/sync_bookmarks/README.md
new file mode 100644
index 00000000000..5cb33a1ca9e
--- /dev/null
+++ b/chromium/components/sync_bookmarks/README.md
@@ -0,0 +1 @@
+See components/sync/README.md.
diff --git a/chromium/components/sync_bookmarks/bookmark_local_changes_builder.cc b/chromium/components/sync_bookmarks/bookmark_local_changes_builder.cc
index f6190614882..0a85e604b88 100644
--- a/chromium/components/sync_bookmarks/bookmark_local_changes_builder.cc
+++ b/chromium/components/sync_bookmarks/bookmark_local_changes_builder.cc
@@ -4,7 +4,6 @@
#include "components/sync_bookmarks/bookmark_local_changes_builder.h"
-#include <limits>
#include <memory>
#include <string>
#include <utility>
@@ -35,11 +34,7 @@ syncer::CommitRequestDataList BookmarkLocalChangesBuilder::BuildCommitRequests(
const std::vector<const SyncedBookmarkTracker::Entity*>
entities_with_local_changes =
- bookmark_tracker_->GetEntitiesWithLocalChanges(
- base::FeatureList::IsEnabled(
- switches::kSyncBookmarksEnforceLateMaxEntriesToCommit)
- ? std::numeric_limits<int>::max()
- : max_entries);
+ bookmark_tracker_->GetEntitiesWithLocalChanges();
syncer::CommitRequestDataList commit_requests;
for (const SyncedBookmarkTracker::Entity* entity :
@@ -58,16 +53,14 @@ syncer::CommitRequestDataList BookmarkLocalChangesBuilder::BuildCommitRequests(
data->modification_time =
syncer::ProtoTimeToTime(metadata->modification_time());
- if (bookmark_tracker_->bookmark_client_tags_in_protocol_enabled()) {
- DCHECK(!metadata->client_tag_hash().empty());
- data->client_tag_hash =
- syncer::ClientTagHash::FromHashed(metadata->client_tag_hash());
- DCHECK(metadata->is_deleted() ||
- data->client_tag_hash ==
- syncer::ClientTagHash::FromUnhashed(
- syncer::BOOKMARKS,
- entity->bookmark_node()->guid().AsLowercaseString()));
- }
+ DCHECK(!metadata->client_tag_hash().empty());
+ data->client_tag_hash =
+ syncer::ClientTagHash::FromHashed(metadata->client_tag_hash());
+ DCHECK(metadata->is_deleted() ||
+ data->client_tag_hash ==
+ syncer::ClientTagHash::FromUnhashed(
+ syncer::BOOKMARKS,
+ entity->bookmark_node()->guid().AsLowercaseString()));
if (!metadata->is_deleted()) {
const bookmarks::BookmarkNode* node = entity->bookmark_node();
@@ -93,7 +86,7 @@ syncer::CommitRequestDataList BookmarkLocalChangesBuilder::BuildCommitRequests(
const SyncedBookmarkTracker::Entity* parent_entity =
bookmark_tracker_->GetEntityForBookmarkNode(parent);
DCHECK(parent_entity);
- data->parent_id = parent_entity->metadata()->server_id();
+ data->legacy_parent_id = parent_entity->metadata()->server_id();
// Assign specifics only for the non-deletion case. In case of deletion,
// EntityData should contain empty specifics to indicate deletion.
data->specifics = CreateSpecificsFromBookmarkNode(
diff --git a/chromium/components/sync_bookmarks/bookmark_model_merger.cc b/chromium/components/sync_bookmarks/bookmark_model_merger.cc
index afa4de7cdd9..cd4ecf33829 100644
--- a/chromium/components/sync_bookmarks/bookmark_model_merger.cc
+++ b/chromium/components/sync_bookmarks/bookmark_model_merger.cc
@@ -60,8 +60,10 @@ const size_t kMaxBookmarkTreeDepth = 200;
// The value must be a list since there is a container using pointers to its
// elements.
-using UpdatesPerParentId =
- std::unordered_map<std::string, std::list<syncer::UpdateResponseData>>;
+using UpdatesPerParentGUID =
+ std::unordered_map<base::GUID,
+ std::list<syncer::UpdateResponseData>,
+ base::GUIDHash>;
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused. When adding values, be certain to also
@@ -105,9 +107,9 @@ enum class RemoteBookmarkUpdateError {
kUnsupportedPermanentFolder = 13,
// A bookmark that is not contained in any permanent folder and is instead
// hanging (directly or indirectly) from the root node.
- kDescendantOfRootNodeWithoutPermanentFolder = 14,
+ // kDeprecatedDescendantOfRootNodeWithoutPermanentFolder = 14,
- kMaxValue = kDescendantOfRootNodeWithoutPermanentFolder,
+ kMaxValue = kUnsupportedPermanentFolder,
};
void LogProblematicBookmark(RemoteBookmarkUpdateError problem) {
@@ -121,12 +123,16 @@ void LogBookmarkReuploadNeeded(bool is_reupload_needed) {
}
// Gets the bookmark node corresponding to a permanent folder identified by
-// |server_defined_unique_tag|. |bookmark_model| must not be null.
-const bookmarks::BookmarkNode* GetPermanentFolder(
+// |server_defined_unique_tag| or null of the tag is unknown. |bookmark_model|
+// must not be null and |server_defined_unique_tag| must not be empty.
+const bookmarks::BookmarkNode* GetPermanentFolderForServerDefinedUniqueTag(
const bookmarks::BookmarkModel* bookmark_model,
const std::string& server_defined_unique_tag) {
DCHECK(bookmark_model);
+ DCHECK(!server_defined_unique_tag.empty());
+ // WARNING: Keep this logic consistent with the analogous in
+ // GetPermanentFolderGUIDForServerDefinedUniqueTag().
if (server_defined_unique_tag == kBookmarkBarTag) {
return bookmark_model->bookmark_bar_node();
}
@@ -140,6 +146,31 @@ const bookmarks::BookmarkNode* GetPermanentFolder(
return nullptr;
}
+// Gets the bookmark GUID corresponding to a permanent folder identified by
+// |served_defined_unique_tag| or an invalid GUID if the tag is unknown.
+// |server_defined_unique_tag| must not be empty.
+base::GUID GetPermanentFolderGUIDForServerDefinedUniqueTag(
+ const std::string& server_defined_unique_tag) {
+ DCHECK(!server_defined_unique_tag.empty());
+
+ // WARNING: Keep this logic consistent with the analogous in
+ // GetPermanentFolderForServerDefinedUniqueTag().
+ if (server_defined_unique_tag == kBookmarkBarTag) {
+ return base::GUID::ParseLowercase(
+ bookmarks::BookmarkNode::kBookmarkBarNodeGuid);
+ }
+ if (server_defined_unique_tag == kOtherBookmarksTag) {
+ return base::GUID::ParseLowercase(
+ bookmarks::BookmarkNode::kOtherBookmarksNodeGuid);
+ }
+ if (server_defined_unique_tag == kMobileBookmarksTag) {
+ return base::GUID::ParseLowercase(
+ bookmarks::BookmarkNode::kMobileBookmarksNodeGuid);
+ }
+
+ return base::GUID();
+}
+
std::string LegacyCanonicalizedTitleFromSpecifics(
const sync_pb::BookmarkSpecifics& specifics) {
if (specifics.has_full_title()) {
@@ -215,31 +246,6 @@ BookmarksGUIDDuplicates MatchBookmarksGUIDDuplicates(
return BookmarksGUIDDuplicates();
}
-void ReparentAllChildren(const std::string& from_parent_id,
- const std::string& to_parent_id,
- UpdatesPerParentId* updates_per_parent_id) {
- // Any of parents may be empty.
- auto from_parent_updates_iter = updates_per_parent_id->find(from_parent_id);
- if (from_parent_updates_iter == updates_per_parent_id->end()) {
- // There is nothing to merge.
- return;
- }
-
- // Update parent ids for all entities before moving.
- for (auto& update : from_parent_updates_iter->second) {
- DCHECK_EQ(update.entity.parent_id, from_parent_id);
- update.entity.parent_id = to_parent_id;
- }
-
- // Move all elements to a new parent (create one if it didn't exist).
- (*updates_per_parent_id)[to_parent_id].splice(
- (*updates_per_parent_id)[to_parent_id].end(),
- from_parent_updates_iter->second);
- updates_per_parent_id->erase(from_parent_id);
-
- // No need to update iterators since splice doesn't invalidate them.
-}
-
// Returns true the |next_update| is selected to keep and the |previous_update|
// should be removed. False is returned otherwise. |next_update| and
// |previous_update| must have the same GUID.
@@ -261,20 +267,17 @@ bool CompareDuplicateUpdates(const UpdateResponseData& next_update,
previous_update.entity.creation_time;
}
-void DeduplicateValidUpdatesByGUID(UpdatesPerParentId* updates_per_parent_id) {
- DCHECK(updates_per_parent_id);
+void DeduplicateValidUpdatesByGUID(
+ UpdatesPerParentGUID* updates_per_parent_guid) {
+ DCHECK(updates_per_parent_guid);
std::unordered_map<base::GUID, std::list<UpdateResponseData>::iterator,
base::GUIDHash>
guid_to_update;
- // Removing data in a separate loop helps easier merge parents since one of
- // them may have already been processed.
- std::list<std::list<UpdateResponseData>::iterator> updates_to_remove;
- for (auto& parent_id_and_updates : *updates_per_parent_id) {
- std::list<UpdateResponseData>* updates = &parent_id_and_updates.second;
- for (auto updates_iter = updates->begin(); updates_iter != updates->end();
- ++updates_iter) {
+ for (auto& [parent_guid, updates] : *updates_per_parent_guid) {
+ auto updates_iter = updates.begin();
+ while (updates_iter != updates.end()) {
const UpdateResponseData& update = *updates_iter;
DCHECK(!update.entity.is_deleted());
DCHECK(update.entity.server_defined_unique_tag.empty());
@@ -283,57 +286,33 @@ void DeduplicateValidUpdatesByGUID(UpdatesPerParentId* updates_per_parent_id) {
base::GUID::ParseLowercase(update.entity.specifics.bookmark().guid());
DCHECK(guid_in_specifics.is_valid());
- auto it_and_success =
+ auto [it, success] =
guid_to_update.emplace(guid_in_specifics, updates_iter);
- if (it_and_success.second) {
+ if (success) {
+ ++updates_iter;
continue;
}
- const UpdateResponseData& duplicate_update =
- *it_and_success.first->second;
+
+ const auto& [guid, previous_update_it] = *it;
DCHECK_EQ(guid_in_specifics.AsLowercaseString(),
- duplicate_update.entity.specifics.bookmark().guid());
+ previous_update_it->entity.specifics.bookmark().guid());
DLOG(ERROR) << "Duplicate guid for new sync ID " << update.entity.id
- << " and original sync ID " << duplicate_update.entity.id;
+ << " and original sync ID " << previous_update_it->entity.id;
const BookmarksGUIDDuplicates match_result =
- MatchBookmarksGUIDDuplicates(update, duplicate_update);
+ MatchBookmarksGUIDDuplicates(update, *previous_update_it);
base::UmaHistogramEnumeration("Sync.BookmarksGUIDDuplicates",
match_result);
if (CompareDuplicateUpdates(/*next_update=*/update,
- /*previous_update=*/duplicate_update)) {
- updates_to_remove.push_back(it_and_success.first->second);
- // Update |guid_to_update| to find a duplicate folder and merge them.
+ /*previous_update=*/*previous_update_it)) {
+ updates.erase(previous_update_it);
guid_to_update[guid_in_specifics] = updates_iter;
+ ++updates_iter;
} else {
- updates_to_remove.push_back(updates_iter);
+ updates_iter = updates.erase(updates_iter);
}
}
}
-
- for (std::list<UpdateResponseData>::iterator updates_iter :
- updates_to_remove) {
- if (updates_iter->entity.specifics.bookmark().type() ==
- sync_pb::BookmarkSpecifics::FOLDER) {
- const base::GUID guid = base::GUID::ParseLowercase(
- updates_iter->entity.specifics.bookmark().guid());
- DCHECK(base::Contains(guid_to_update, guid));
- DCHECK(guid_to_update[guid] != updates_iter);
-
- // Never remove a folder if its duplicate is a URL.
- DCHECK_EQ(guid_to_update[guid]->entity.specifics.bookmark().type(),
- sync_pb::BookmarkSpecifics::FOLDER);
-
- // Merge doesn't affect iterators.
- ReparentAllChildren(
- /*from_parent_id=*/updates_iter->entity.id,
- /*to_parent_id=*/guid_to_update[guid]->entity.id,
- updates_per_parent_id);
- }
-
- const std::string& parent_id = updates_iter->entity.parent_id;
- DCHECK(base::Contains(*updates_per_parent_id, parent_id));
- (*updates_per_parent_id)[parent_id].erase(updates_iter);
- }
}
// Checks that the |update| is valid and returns false otherwise. It is used to
@@ -363,16 +342,28 @@ bool IsValidUpdate(const UpdateResponseData& update) {
return true;
}
+// Returns the GUID determined by a remote update, which may be an update for a
+// permanent folder or a regular bookmark node.
+base::GUID GetGUIDForUpdate(const UpdateResponseData& update) {
+ if (!update.entity.server_defined_unique_tag.empty()) {
+ return GetPermanentFolderGUIDForServerDefinedUniqueTag(
+ update.entity.server_defined_unique_tag);
+ }
+
+ DCHECK(IsValidUpdate(update));
+ return base::GUID::ParseLowercase(update.entity.specifics.bookmark().guid());
+}
+
struct GroupedUpdates {
- // |updates_per_parent_id| contains all valid updates grouped by their
- // |parent_id|. Permanent nodes and deletions are filtered out. Permanent
+ // |updates_per_parent_guid| contains all valid updates grouped by their
+ // |parent_guid|. Permanent nodes and deletions are filtered out. Permanent
// nodes are stored in a dedicated list |permanent_node_updates|.
- UpdatesPerParentId updates_per_parent_id;
+ UpdatesPerParentGUID updates_per_parent_guid;
UpdateResponseDataList permanent_node_updates;
};
-// Groups all valid updates by the server ID of their parent. Permanent nodes
-// are grouped in a dedicated |permanent_node_updates| list in a returned value.
+// Groups all valid updates by the GUID of their parent. Permanent nodes are
+// grouped in a dedicated |permanent_node_updates| list in a returned value.
GroupedUpdates GroupValidUpdates(UpdateResponseDataList updates) {
GroupedUpdates grouped_updates;
int num_valid_updates = 0;
@@ -381,16 +372,30 @@ GroupedUpdates GroupValidUpdates(UpdateResponseDataList updates) {
if (update_entity.is_deleted()) {
continue;
}
+ // Special-case the root folder to avoid recording
+ // |RemoteBookmarkUpdateError::kUnsupportedPermanentFolder|.
+ if (update_entity.server_defined_unique_tag ==
+ syncer::ModelTypeToRootTag(syncer::BOOKMARKS)) {
+ ++num_valid_updates;
+ continue;
+ }
+ // Non-root permanent folders don't need further validation.
if (!update_entity.server_defined_unique_tag.empty()) {
++num_valid_updates;
grouped_updates.permanent_node_updates.push_back(std::move(update));
continue;
}
+ // Regular (non-permanent) node updates must pass IsValidUpdate().
if (!IsValidUpdate(update)) {
continue;
}
++num_valid_updates;
- grouped_updates.updates_per_parent_id[update_entity.parent_id].push_back(
+
+ const base::GUID parent_guid = base::GUID::ParseLowercase(
+ update_entity.specifics.bookmark().parent_guid());
+ DCHECK(parent_guid.is_valid());
+
+ grouped_updates.updates_per_parent_guid[parent_guid].push_back(
std::move(update));
}
@@ -457,11 +462,14 @@ BookmarkModelMerger::RemoteTreeNode
BookmarkModelMerger::RemoteTreeNode::BuildTree(
UpdateResponseData update,
size_t max_depth,
- UpdatesPerParentId* updates_per_parent_id) {
- DCHECK(updates_per_parent_id);
+ UpdatesPerParentGUID* updates_per_parent_guid) {
+ DCHECK(updates_per_parent_guid);
DCHECK(!update.entity.server_defined_unique_tag.empty() ||
IsValidUpdate(update));
+ // |guid| may be invalid for unsupported permanent nodes.
+ const base::GUID guid = GetGUIDForUpdate(update);
+
RemoteTreeNode node;
node.update_ = std::move(update);
node.unique_position_ = syncer::UniquePosition::FromProto(
@@ -473,14 +481,15 @@ BookmarkModelMerger::RemoteTreeNode::BuildTree(
return node;
}
- // Check to prevent creating empty lists in |updates_per_parent_id| and
+ // Check to prevent creating empty lists in |updates_per_parent_guid| and
// unnecessary rehashing.
- auto updates_per_parent_id_iter =
- updates_per_parent_id->find(node.entity().id);
- if (updates_per_parent_id_iter == updates_per_parent_id->end()) {
+ auto updates_per_parent_guid_iter = updates_per_parent_guid->find(guid);
+ if (updates_per_parent_guid_iter == updates_per_parent_guid->end()) {
return node;
}
- DCHECK(!updates_per_parent_id_iter->second.empty());
+
+ DCHECK(!updates_per_parent_guid_iter->second.empty());
+ DCHECK(guid.is_valid());
// Only folders may have descendants (ignore them otherwise). Treat
// permanent nodes as folders explicitly.
@@ -489,7 +498,7 @@ BookmarkModelMerger::RemoteTreeNode::BuildTree(
node.update_.entity.server_defined_unique_tag.empty()) {
// Children of a non-folder are ignored.
for (UpdateResponseData& child_update :
- updates_per_parent_id_iter->second) {
+ updates_per_parent_guid_iter->second) {
LogProblematicBookmark(RemoteBookmarkUpdateError::kParentNotFolder);
// To avoid double-counting later for bucket |kMissingParentEntity|,
// clear the update from the list as if it would have been moved.
@@ -499,13 +508,15 @@ BookmarkModelMerger::RemoteTreeNode::BuildTree(
}
// Populate descendants recursively.
- node.children_.reserve(updates_per_parent_id_iter->second.size());
- for (UpdateResponseData& child_update : updates_per_parent_id_iter->second) {
- DCHECK_EQ(child_update.entity.parent_id, node.entity().id);
+ node.children_.reserve(updates_per_parent_guid_iter->second.size());
+ for (UpdateResponseData& child_update :
+ updates_per_parent_guid_iter->second) {
+ DCHECK_EQ(child_update.entity.specifics.bookmark().parent_guid(),
+ guid.AsLowercaseString());
DCHECK(IsValidBookmarkSpecifics(child_update.entity.specifics.bookmark()));
node.children_.push_back(BuildTree(std::move(child_update), max_depth - 1,
- updates_per_parent_id));
+ updates_per_parent_guid));
}
// Sort the children according to their unique position.
@@ -530,9 +541,8 @@ BookmarkModelMerger::BookmarkModelMerger(
DCHECK(favicon_service);
int num_updates_in_forest = 0;
- for (const auto& tree_tag_and_root : remote_forest_) {
- num_updates_in_forest +=
- 1 + CountRemoteTreeNodeDescendantsForUma(tree_tag_and_root.second);
+ for (const auto& [server_defined_unique_tag, root] : remote_forest_) {
+ num_updates_in_forest += 1 + CountRemoteTreeNodeDescendantsForUma(root);
}
base::UmaHistogramCounts100000(
"Sync.BookmarkModelMerger.ReachableInputUpdates", num_updates_in_forest);
@@ -562,32 +572,28 @@ void BookmarkModelMerger::Merge() {
// to perform the primary match. If there are multiple match candidates it
// selects the first one.
// Associate permanent folders.
- for (const auto& tree_tag_and_root : remote_forest_) {
- // Special-case the root folder to avoid recording
- // |RemoteBookmarkUpdateError::kUnsupportedPermanentFolder|.
- if (tree_tag_and_root.first ==
- syncer::ModelTypeToRootTag(syncer::BOOKMARKS)) {
- // The root folder is not expected to have children, because all children
- // should themselves be permanent folders too and hence directly populate
- // |tree_tag_and_root| without nesting.
- const int num_unexpected_descendants_of_root_folder =
- CountRemoteTreeNodeDescendantsForUma(tree_tag_and_root.second);
- for (int i = 0; i < num_unexpected_descendants_of_root_folder; ++i) {
- LogProblematicBookmark(RemoteBookmarkUpdateError::
- kDescendantOfRootNodeWithoutPermanentFolder);
- }
- continue;
- }
+ for (const auto& [server_defined_unique_tag, root] : remote_forest_) {
+ DCHECK(!server_defined_unique_tag.empty());
const bookmarks::BookmarkNode* permanent_folder =
- GetPermanentFolder(bookmark_model_, tree_tag_and_root.first);
+ GetPermanentFolderForServerDefinedUniqueTag(bookmark_model_,
+ server_defined_unique_tag);
+
+ // Ignore unsupported permanent folders.
if (!permanent_folder) {
+ DCHECK(!GetPermanentFolderGUIDForServerDefinedUniqueTag(
+ server_defined_unique_tag)
+ .is_valid());
LogProblematicBookmark(
RemoteBookmarkUpdateError::kUnsupportedPermanentFolder);
continue;
}
+
+ DCHECK_EQ(permanent_folder->guid(),
+ GetPermanentFolderGUIDForServerDefinedUniqueTag(
+ server_defined_unique_tag));
MergeSubtree(/*local_subtree_root=*/permanent_folder,
- /*remote_node=*/tree_tag_and_root.second);
+ /*remote_node=*/root);
}
if (base::FeatureList::IsEnabled(switches::kSyncReuploadBookmarks)) {
@@ -614,7 +620,7 @@ BookmarkModelMerger::RemoteForest BookmarkModelMerger::BuildRemoteForest(
// of their parent.
GroupedUpdates grouped_updates = GroupValidUpdates(std::move(updates));
- DeduplicateValidUpdatesByGUID(&grouped_updates.updates_per_parent_id);
+ DeduplicateValidUpdatesByGUID(&grouped_updates.updates_per_parent_guid);
// Construct one tree per permanent entity.
RemoteForest update_forest;
@@ -629,14 +635,14 @@ BookmarkModelMerger::RemoteForest BookmarkModelMerger::BuildRemoteForest(
server_defined_unique_tag,
RemoteTreeNode::BuildTree(std::move(permanent_node_update),
kMaxBookmarkTreeDepth,
- &grouped_updates.updates_per_parent_id));
+ &grouped_updates.updates_per_parent_guid));
}
- // All remaining entries in |updates_per_parent_id| must be unreachable from
+ // All remaining entries in |updates_per_parent_guid| must be unreachable from
// permanent entities, since otherwise they would have been moved away.
- for (const auto& parent_id_and_updates :
- grouped_updates.updates_per_parent_id) {
- for (const UpdateResponseData& update : parent_id_and_updates.second) {
+ for (const auto& [parent_guid, updates] :
+ grouped_updates.updates_per_parent_guid) {
+ for (const UpdateResponseData& update : updates) {
if (update.entity.specifics.has_bookmark()) {
LogProblematicBookmark(RemoteBookmarkUpdateError::kMissingParentEntity);
tracker_for_recording_ignored_updates
@@ -671,9 +677,8 @@ BookmarkModelMerger::FindGuidMatchesOrReassignLocal(
// Build a temporary lookup table for remote GUIDs.
std::unordered_map<base::GUID, const RemoteTreeNode*, base::GUIDHash>
guid_to_remote_node_map;
- for (const auto& tree_tag_and_root : remote_forest) {
- tree_tag_and_root.second.EmplaceSelfAndDescendantsByGUID(
- &guid_to_remote_node_map);
+ for (const auto& [server_defined_unique_tag, root] : remote_forest) {
+ root.EmplaceSelfAndDescendantsByGUID(&guid_to_remote_node_map);
}
// Iterate through all local bookmarks to find matches by GUID.
@@ -699,10 +704,8 @@ BookmarkModelMerger::FindGuidMatchesOrReassignLocal(
// Permanent nodes don't match by GUID but by |server_defined_unique_tag|.
// As extra precaution, specially with remote GUIDs in mind, let's ignore
// them explicitly here.
- if (node->is_permanent_node() ||
- GetPermanentFolder(bookmark_model,
- remote_entity.server_defined_unique_tag) !=
- nullptr) {
+ DCHECK(remote_entity.server_defined_unique_tag.empty());
+ if (node->is_permanent_node()) {
continue;
}
diff --git a/chromium/components/sync_bookmarks/bookmark_model_merger.h b/chromium/components/sync_bookmarks/bookmark_model_merger.h
index 61d79e0e751..d09a20f9b44 100644
--- a/chromium/components/sync_bookmarks/bookmark_model_merger.h
+++ b/chromium/components/sync_bookmarks/bookmark_model_merger.h
@@ -59,20 +59,23 @@ class BookmarkModelMerger {
// Internal representation of a remote tree, composed of nodes.
class RemoteTreeNode final {
private:
- using UpdatesPerParentId =
- std::unordered_map<std::string, std::list<syncer::UpdateResponseData>>;
+ using UpdatesPerParentGUID =
+ std::unordered_map<base::GUID,
+ std::list<syncer::UpdateResponseData>,
+ base::GUIDHash>;
public:
// Constructs a tree given |update| as root and recursively all descendants
- // by traversing |*updates_per_parent_id|. |update| and
- // |updates_per_parent_id| must not be null. All updates
- // |*updates_per_parent_id| must represent valid updates. Updates
+ // by traversing |*updates_per_parent_guid|. |update| and
+ // |updates_per_parent_guid| must not be null. All updates
+ // |*updates_per_parent_guid| must represent valid updates. Updates
// corresponding from descendant nodes are moved away from
- // |*updates_per_parent_id|. |max_depth| is the max tree depth to sync
+ // |*updates_per_parent_guid|. |max_depth| is the max tree depth to sync
// after which content is silently ignored.
- static RemoteTreeNode BuildTree(syncer::UpdateResponseData update,
- size_t max_depth,
- UpdatesPerParentId* updates_per_parent_id);
+ static RemoteTreeNode BuildTree(
+ syncer::UpdateResponseData update,
+ size_t max_depth,
+ UpdatesPerParentGUID* updates_per_parent_guid);
~RemoteTreeNode();
diff --git a/chromium/components/sync_bookmarks/bookmark_model_merger_unittest.cc b/chromium/components/sync_bookmarks/bookmark_model_merger_unittest.cc
index b5874daa287..5f65b5f53d6 100644
--- a/chromium/components/sync_bookmarks/bookmark_model_merger_unittest.cc
+++ b/chromium/components/sync_bookmarks/bookmark_model_merger_unittest.cc
@@ -107,12 +107,8 @@ class UpdateResponseDataBuilder {
const std::string& title,
const syncer::UniquePosition& unique_position) {
data_.id = GetFakeServerIdFromGUID(guid);
- data_.parent_id = GetFakeServerIdFromGUID(parent_guid);
data_.originator_client_item_id = guid.AsLowercaseString();
- // Note that proto field |parent_guid| is not currently populated here
- // because the code doesn't actually need it, and besides legacy data coming
- // from the server may not include it.
sync_pb::BookmarkSpecifics* bookmark_specifics =
data_.specifics.mutable_bookmark();
bookmark_specifics->set_legacy_canonicalized_title(title);
@@ -120,6 +116,7 @@ class UpdateResponseDataBuilder {
bookmark_specifics->set_type(sync_pb::BookmarkSpecifics::FOLDER);
*bookmark_specifics->mutable_unique_position() = unique_position.ToProto();
bookmark_specifics->set_guid(guid.AsLowercaseString());
+ bookmark_specifics->set_parent_guid(parent_guid.AsLowercaseString());
}
UpdateResponseDataBuilder& SetUrl(const GURL& url) {
@@ -237,8 +234,6 @@ static syncer::UniquePosition MakeRandomPosition() {
} // namespace
TEST(BookmarkModelMergerTest, ShouldMergeLocalAndRemoteModels) {
- const size_t kMaxEntries = 1000;
-
const std::string kFolder1Title = "folder1";
const std::string kFolder2Title = "folder2";
const std::string kFolder3Title = "folder3";
@@ -419,7 +414,7 @@ TEST(BookmarkModelMergerTest, ShouldMergeLocalAndRemoteModels) {
// Verify the tracker contents.
EXPECT_THAT(tracker->TrackedEntitiesCountForTest(), Eq(11U));
std::vector<const SyncedBookmarkTracker::Entity*> local_changes =
- tracker->GetEntitiesWithLocalChanges(kMaxEntries);
+ tracker->GetEntitiesWithLocalChanges();
EXPECT_THAT(local_changes.size(), Eq(4U));
std::vector<const bookmarks::BookmarkNode*> nodes_with_local_changes;
@@ -440,8 +435,6 @@ TEST(BookmarkModelMergerTest, ShouldMergeLocalAndRemoteModels) {
}
TEST(BookmarkModelMergerTest, ShouldMergeRemoteReorderToLocalModel) {
- const size_t kMaxEntries = 1000;
-
const std::string kFolder1Title = "folder1";
const std::string kFolder2Title = "folder2";
const std::string kFolder3Title = "folder3";
@@ -524,7 +517,7 @@ TEST(BookmarkModelMergerTest, ShouldMergeRemoteReorderToLocalModel) {
// There should be no local changes.
std::vector<const SyncedBookmarkTracker::Entity*> local_changes =
- tracker->GetEntitiesWithLocalChanges(kMaxEntries);
+ tracker->GetEntitiesWithLocalChanges();
EXPECT_THAT(local_changes.size(), Eq(0U));
// Verify positions in tracker.
@@ -1013,7 +1006,6 @@ TEST(BookmarkModelMergerTest, ShouldMergeFolderByGUIDAndNotSemantics) {
}
TEST(BookmarkModelMergerTest, ShouldIgnoreChildrenForNonFolderNodes) {
- const std::string kParentId = "parent_id";
const std::string kChildId = "child_id";
const std::string kParentTitle = "Parent Title";
const std::string kChildTitle = "Child Title";
@@ -1670,9 +1662,8 @@ TEST(BookmarkModelMergerTest,
// Verify the tracker contents.
EXPECT_THAT(tracker->TrackedEntitiesCountForTest(), Eq(5U));
- const size_t kMaxEntries = 1000;
std::vector<const SyncedBookmarkTracker::Entity*> local_changes =
- tracker->GetEntitiesWithLocalChanges(kMaxEntries);
+ tracker->GetEntitiesWithLocalChanges();
ASSERT_THAT(local_changes.size(), Eq(1U));
EXPECT_THAT(local_changes[0]->bookmark_node(),
@@ -1811,7 +1802,6 @@ TEST(BookmarkModelMergerTest, ShouldLogMetricsForkDescendantOfRootNode) {
// -------- The remote model --------
// root node
// | - bookmark (url1/Title1)
- // | - bookmark (url2/Title2)
syncer::UpdateResponseDataList updates;
updates.push_back(CreateBookmarkBarNodeUpdateData());
updates.back().entity.id = kRootNodeId;
@@ -1820,27 +1810,18 @@ TEST(BookmarkModelMergerTest, ShouldLogMetricsForkDescendantOfRootNode) {
updates.push_back(CreateUpdateResponseData(
/*guid=*/base::GUID::GenerateRandomV4(),
- /*parent_guid=*/base::GUID::GenerateRandomV4(), "Title1",
+ base::GUID::ParseLowercase(bookmarks::BookmarkNode::kRootNodeGuid),
+ "Title1",
/*url=*/"http://url1",
/*is_folder=*/false,
/*unique_position=*/MakeRandomPosition()));
- updates.back().entity.parent_id = kRootNodeId;
- updates.push_back(CreateUpdateResponseData(
- /*guid=*/base::GUID::GenerateRandomV4(),
- /*parent_guid=*/base::GUID::GenerateRandomV4(), "Title2",
- /*url=*/"http://url2",
- /*is_folder=*/false,
- /*unique_position=*/MakeRandomPosition()));
- updates.back().entity.parent_id = kRootNodeId;
base::HistogramTester histogram_tester;
Merge(std::move(updates), bookmark_model.get());
histogram_tester.ExpectUniqueSample(
"Sync.ProblematicServerSideBookmarksDuringMerge",
- /*sample=*/
- ExpectedRemoteBookmarkUpdateError::
- kDescendantOfRootNodeWithoutPermanentFolder,
- /*count=*/2);
+ /*sample=*/ExpectedRemoteBookmarkUpdateError::kMissingParentEntity,
+ /*count=*/1);
}
TEST(BookmarkModelMergerTest, ShouldRemoveMatchingDuplicatesByGUID) {
@@ -2027,7 +2008,6 @@ TEST(BookmarkModelMergerTest, ShouldRemoveDifferentFolderDuplicatesByGUID) {
/*guid=*/base::GUID::GenerateRandomV4(), /*parent_guid=*/kGuid,
"Some title",
/*url=*/"", /*is_folder=*/true, MakeRandomPosition()));
- updates.back().entity.parent_id = "Id1";
updates.push_back(CreateUpdateResponseData(
/*guid=*/kGuid, /*parent_guid=*/BookmarkBarGuid(), kTitle2,
@@ -2038,7 +2018,6 @@ TEST(BookmarkModelMergerTest, ShouldRemoveDifferentFolderDuplicatesByGUID) {
/*guid=*/base::GUID::GenerateRandomV4(), /*parent_guid=*/kGuid,
"Some title 2",
/*url=*/"", /*is_folder=*/true, MakeRandomPosition()));
- updates.back().entity.parent_id = "Id2";
base::HistogramTester histogram_tester;
std::unique_ptr<SyncedBookmarkTracker> tracker =
@@ -2189,7 +2168,6 @@ TEST(BookmarkModelMergerTest, ShouldRemoveDifferentTypeDuplicatesByGUID) {
/*guid=*/base::GUID::GenerateRandomV4(), /*parent_guid=*/kGuid,
"Some title",
/*url=*/"", /*is_folder=*/true, MakeRandomPosition()));
- updates.back().entity.parent_id = "Id1";
updates.push_back(CreateUpdateResponseData(
/*guid=*/kGuid, /*parent_guid=*/BookmarkBarGuid(), kTitle,
diff --git a/chromium/components/sync_bookmarks/bookmark_model_observer_impl_unittest.cc b/chromium/components/sync_bookmarks/bookmark_model_observer_impl_unittest.cc
index dc18167fc2e..48445d0632f 100644
--- a/chromium/components/sync_bookmarks/bookmark_model_observer_impl_unittest.cc
+++ b/chromium/components/sync_bookmarks/bookmark_model_observer_impl_unittest.cc
@@ -49,7 +49,6 @@ const char kOtherBookmarksId[] = "other_bookmarks_id";
const char kOtherBookmarksTag[] = "other_bookmarks";
const char kMobileBookmarksId[] = "synced_bookmarks_id";
const char kMobileBookmarksTag[] = "synced_bookmarks";
-const size_t kMaxEntries = 1000;
// Matches |arg| of type SyncedBookmarkTracker::Entity*.
MATCHER_P(HasBookmarkNode, node, "") {
@@ -101,7 +100,7 @@ class BookmarkModelObserverImplTest : public testing::Test {
void SimulateCommitResponseForAllLocalChanges() {
for (const SyncedBookmarkTracker::Entity* entity :
- bookmark_tracker()->GetEntitiesWithLocalChanges(kMaxEntries)) {
+ bookmark_tracker()->GetEntitiesWithLocalChanges()) {
const std::string id = entity->metadata()->server_id();
// Don't simulate change in id for simplicity.
bookmark_tracker()->UpdateUponCommitResponse(
@@ -153,7 +152,7 @@ TEST_F(BookmarkModelObserverImplTest,
EXPECT_THAT(bookmark_tracker()->TrackedEntitiesCountForTest(), 4U);
std::vector<const SyncedBookmarkTracker::Entity*> local_changes =
- bookmark_tracker()->GetEntitiesWithLocalChanges(kMaxEntries);
+ bookmark_tracker()->GetEntitiesWithLocalChanges();
ASSERT_THAT(local_changes.size(), 1U);
EXPECT_THAT(local_changes[0]->bookmark_node(), Eq(bookmark_node));
EXPECT_THAT(local_changes[0]->metadata()->server_id(),
@@ -180,20 +179,18 @@ TEST_F(BookmarkModelObserverImplTest,
// Both bookmarks should be tracked now.
ASSERT_THAT(bookmark_tracker()->TrackedEntitiesCountForTest(), 5U);
// There should be two local changes now for both entities.
- ASSERT_THAT(
- bookmark_tracker()->GetEntitiesWithLocalChanges(kMaxEntries).size(), 2U);
+ ASSERT_THAT(bookmark_tracker()->GetEntitiesWithLocalChanges().size(), 2U);
SimulateCommitResponseForAllLocalChanges();
// There should be no local changes now.
- ASSERT_TRUE(
- bookmark_tracker()->GetEntitiesWithLocalChanges(kMaxEntries).empty());
+ ASSERT_TRUE(bookmark_tracker()->GetEntitiesWithLocalChanges().empty());
// Now update the title of the 2nd node.
EXPECT_CALL(*nudge_for_commit_closure(), Run());
bookmark_model()->SetTitle(bookmark_node2, base::UTF8ToUTF16(kNewTitle2));
// Node 2 should be in the local changes list.
- EXPECT_THAT(bookmark_tracker()->GetEntitiesWithLocalChanges(kMaxEntries),
+ EXPECT_THAT(bookmark_tracker()->GetEntitiesWithLocalChanges(),
ElementsAre(HasBookmarkNode(bookmark_node2)));
// Now update the url of the 1st node.
@@ -201,7 +198,7 @@ TEST_F(BookmarkModelObserverImplTest,
bookmark_model()->SetURL(bookmark_node1, GURL(kNewUrl1));
// Node 1 and 2 should be in the local changes list.
- EXPECT_THAT(bookmark_tracker()->GetEntitiesWithLocalChanges(kMaxEntries),
+ EXPECT_THAT(bookmark_tracker()->GetEntitiesWithLocalChanges(),
UnorderedElementsAre(HasBookmarkNode(bookmark_node1),
HasBookmarkNode(bookmark_node2)));
@@ -227,8 +224,7 @@ TEST_F(BookmarkModelObserverImplTest,
// Verify number of entities local changes. Should be the same as number of
// new nodes.
- ASSERT_THAT(
- bookmark_tracker()->GetEntitiesWithLocalChanges(kMaxEntries).size(), 2U);
+ ASSERT_THAT(bookmark_tracker()->GetEntitiesWithLocalChanges().size(), 2U);
// All bookmarks should be tracked now.
ASSERT_THAT(bookmark_tracker()->TrackedEntitiesCountForTest(), 5U);
@@ -236,8 +232,7 @@ TEST_F(BookmarkModelObserverImplTest,
SimulateCommitResponseForAllLocalChanges();
// There should be no local changes now.
- ASSERT_TRUE(
- bookmark_tracker()->GetEntitiesWithLocalChanges(kMaxEntries).empty());
+ ASSERT_TRUE(bookmark_tracker()->GetEntitiesWithLocalChanges().empty());
// Now change it to this structure.
// Build this structure:
@@ -272,8 +267,7 @@ TEST_F(BookmarkModelObserverImplTest,
// Verify number of entities local changes. Should be the same as number of
// new nodes.
- ASSERT_THAT(
- bookmark_tracker()->GetEntitiesWithLocalChanges(kMaxEntries).size(), 4U);
+ ASSERT_THAT(bookmark_tracker()->GetEntitiesWithLocalChanges().size(), 4U);
// All bookmarks should be tracked now.
ASSERT_THAT(bookmark_tracker()->TrackedEntitiesCountForTest(), 7U);
@@ -293,7 +287,7 @@ TEST_F(BookmarkModelObserverImplTest,
EXPECT_TRUE(PositionOf(nodes[0]).LessThan(PositionOf(nodes[2])));
// All 4 nodes should have local changes to commit.
- EXPECT_THAT(bookmark_tracker()->GetEntitiesWithLocalChanges(kMaxEntries),
+ EXPECT_THAT(bookmark_tracker()->GetEntitiesWithLocalChanges(),
UnorderedElementsAre(
HasBookmarkNode(nodes[0]), HasBookmarkNode(nodes[1]),
HasBookmarkNode(nodes[2]), HasBookmarkNode(nodes[3])));
@@ -331,8 +325,7 @@ TEST_F(BookmarkModelObserverImplTest,
SimulateCommitResponseForAllLocalChanges();
// There should be no local changes now.
- ASSERT_TRUE(
- bookmark_tracker()->GetEntitiesWithLocalChanges(kMaxEntries).empty());
+ ASSERT_TRUE(bookmark_tracker()->GetEntitiesWithLocalChanges().empty());
const SyncedBookmarkTracker::Entity* folder2_entity =
bookmark_tracker()->GetEntityForBookmarkNode(folder2_node);
@@ -373,7 +366,7 @@ TEST_F(BookmarkModelObserverImplTest,
// committed and folder2 deletion should be the last one (after all children
// deletions).
EXPECT_THAT(
- bookmark_tracker()->GetEntitiesWithLocalChanges(kMaxEntries),
+ bookmark_tracker()->GetEntitiesWithLocalChanges(),
ElementsAre(bookmark_tracker()->GetEntityForSyncId(bookmark2_entity_id),
bookmark_tracker()->GetEntityForSyncId(bookmark3_entity_id),
bookmark_tracker()->GetEntityForSyncId(folder2_entity_id)));
@@ -395,8 +388,7 @@ TEST_F(BookmarkModelObserverImplTest,
const SyncedBookmarkTracker::Entity* entity =
bookmark_tracker()->GetEntityForBookmarkNode(folder_node);
const std::string id = entity->metadata()->server_id();
- ASSERT_THAT(
- bookmark_tracker()->GetEntitiesWithLocalChanges(kMaxEntries).size(), 1U);
+ ASSERT_THAT(bookmark_tracker()->GetEntitiesWithLocalChanges().size(), 1U);
bookmark_tracker()->MarkCommitMayHaveStarted(entity);
@@ -410,8 +402,7 @@ TEST_F(BookmarkModelObserverImplTest,
/*acked_sequence_number=*/1);
// There should still be one local change (the deletion).
- EXPECT_THAT(
- bookmark_tracker()->GetEntitiesWithLocalChanges(kMaxEntries).size(), 1U);
+ EXPECT_THAT(bookmark_tracker()->GetEntitiesWithLocalChanges().size(), 1U);
// Entity is still tracked.
EXPECT_THAT(bookmark_tracker()->TrackedEntitiesCountForTest(), 4U);
@@ -437,8 +428,7 @@ TEST_F(BookmarkModelObserverImplTest,
->GetEntityForBookmarkNode(folder_node)
->metadata()
->server_id();
- ASSERT_THAT(
- bookmark_tracker()->GetEntitiesWithLocalChanges(kMaxEntries).size(), 1U);
+ ASSERT_THAT(bookmark_tracker()->GetEntitiesWithLocalChanges().size(), 1U);
// Remove the folder.
bookmark_model()->Remove(folder_node);
@@ -637,8 +627,7 @@ TEST_F(BookmarkModelObserverImplTest, ShouldNotIssueCommitUponFaviconLoad) {
ASSERT_TRUE(bookmark_client()->SimulateFaviconLoaded(
kBookmarkUrl, kIconUrl, CreateTestImage(kColor)));
SimulateCommitResponseForAllLocalChanges();
- ASSERT_THAT(bookmark_tracker()->GetEntitiesWithLocalChanges(kMaxEntries),
- IsEmpty());
+ ASSERT_THAT(bookmark_tracker()->GetEntitiesWithLocalChanges(), IsEmpty());
const SyncedBookmarkTracker::Entity* entity =
bookmark_tracker()->GetEntityForBookmarkNode(bookmark_node);
@@ -665,8 +654,7 @@ TEST_F(BookmarkModelObserverImplTest, ShouldNotIssueCommitUponFaviconLoad) {
EXPECT_TRUE(entity->metadata()->has_bookmark_favicon_hash());
EXPECT_THAT(entity->metadata()->bookmark_favicon_hash(),
Eq(initial_favicon_hash));
- EXPECT_THAT(bookmark_tracker()->GetEntitiesWithLocalChanges(kMaxEntries),
- IsEmpty());
+ EXPECT_THAT(bookmark_tracker()->GetEntitiesWithLocalChanges(), IsEmpty());
}
TEST_F(BookmarkModelObserverImplTest, ShouldCommitLocalFaviconChange) {
@@ -683,8 +671,7 @@ TEST_F(BookmarkModelObserverImplTest, ShouldCommitLocalFaviconChange) {
ASSERT_TRUE(bookmark_client()->SimulateFaviconLoaded(
kBookmarkUrl, kInitialIconUrl, CreateTestImage(SK_ColorRED)));
SimulateCommitResponseForAllLocalChanges();
- ASSERT_THAT(bookmark_tracker()->GetEntitiesWithLocalChanges(kMaxEntries),
- IsEmpty());
+ ASSERT_THAT(bookmark_tracker()->GetEntitiesWithLocalChanges(), IsEmpty());
const SyncedBookmarkTracker::Entity* entity =
bookmark_tracker()->GetEntityForBookmarkNode(bookmark_node);
@@ -708,7 +695,7 @@ TEST_F(BookmarkModelObserverImplTest, ShouldCommitLocalFaviconChange) {
EXPECT_TRUE(entity->metadata()->has_bookmark_favicon_hash());
EXPECT_THAT(entity->metadata()->bookmark_favicon_hash(),
Ne(initial_favicon_hash));
- EXPECT_THAT(bookmark_tracker()->GetEntitiesWithLocalChanges(kMaxEntries),
+ EXPECT_THAT(bookmark_tracker()->GetEntitiesWithLocalChanges(),
ElementsAre(HasBookmarkNode(bookmark_node)));
}
@@ -789,7 +776,7 @@ TEST_F(BookmarkModelObserverImplTest,
// Check that the entity is a tombstone now.
const std::vector<const SyncedBookmarkTracker::Entity*> local_changes =
- bookmark_tracker()->GetEntitiesWithLocalChanges(/*max_entries=*/2);
+ bookmark_tracker()->GetEntitiesWithLocalChanges();
ASSERT_THAT(local_changes, ElementsAre(folder_entity));
ASSERT_TRUE(folder_entity->metadata()->is_deleted());
ASSERT_EQ(
diff --git a/chromium/components/sync_bookmarks/bookmark_model_type_processor.cc b/chromium/components/sync_bookmarks/bookmark_model_type_processor.cc
index f27504357f0..7f6fc6ed59e 100644
--- a/chromium/components/sync_bookmarks/bookmark_model_type_processor.cc
+++ b/chromium/components/sync_bookmarks/bookmark_model_type_processor.cc
@@ -35,6 +35,7 @@
#include "components/sync_bookmarks/bookmark_model_observer_impl.h"
#include "components/sync_bookmarks/bookmark_remote_updates_handler.h"
#include "components/sync_bookmarks/bookmark_specifics_conversions.h"
+#include "components/sync_bookmarks/parent_guid_preprocessing.h"
#include "components/sync_bookmarks/switches.h"
#include "components/undo/bookmark_undo_utils.h"
@@ -182,6 +183,9 @@ void BookmarkModelTypeProcessor::OnUpdateReceived(
syncer::BOOKMARKS,
/*is_initial_sync=*/!bookmark_tracker_, updates.size());
+ // Clients before M94 did not populate the parent GUID in specifics.
+ PopulateParentGuidInSpecifics(bookmark_tracker_.get(), &updates);
+
if (!bookmark_tracker_) {
OnInitialUpdateReceived(model_type_state, std::move(updates));
return;
@@ -202,7 +206,6 @@ void BookmarkModelTypeProcessor::OnUpdateReceived(
bookmark_tracker_->model_type_state().encryption_key_name() !=
model_type_state.encryption_key_name();
bookmark_tracker_->set_model_type_state(model_type_state);
- bookmark_tracker_->UpdateLastSyncTime();
updates_handler.Process(updates, got_new_encryption_requirements);
if (bookmark_tracker_->ReuploadBookmarksOnLoadIfNeeded()) {
NudgeForCommitIfNeeded();
@@ -529,13 +532,13 @@ void BookmarkModelTypeProcessor::AppendNodeAndChildrenForDebugging(
// Set the parent to empty string to indicate it's parent of the root node
// for bookmarks. The code in sync_node_browser.js links nodes with the
// "modelType" when they are lacking a parent id.
- data.parent_id = "";
+ data.legacy_parent_id = "";
} else {
const bookmarks::BookmarkNode* parent = node->parent();
const SyncedBookmarkTracker::Entity* parent_entity =
bookmark_tracker_->GetEntityForBookmarkNode(parent);
DCHECK(parent_entity);
- data.parent_id = parent_entity->metadata()->server_id();
+ data.legacy_parent_id = parent_entity->metadata()->server_id();
}
std::unique_ptr<base::DictionaryValue> data_dictionary =
@@ -551,7 +554,7 @@ void BookmarkModelTypeProcessor::AppendNodeAndChildrenForDebugging(
data_dictionary->SetString("UNIQUE_SERVER_TAG",
data.server_defined_unique_tag);
} else {
- data_dictionary->SetString("PARENT_ID", "s" + data.parent_id);
+ data_dictionary->SetString("PARENT_ID", "s" + data.legacy_parent_id);
}
data_dictionary->SetInteger("LOCAL_EXTERNAL_ID", node->id());
data_dictionary->SetInteger("positionIndex", index);
diff --git a/chromium/components/sync_bookmarks/bookmark_model_type_processor_unittest.cc b/chromium/components/sync_bookmarks/bookmark_model_type_processor_unittest.cc
index 0a1755a8c1d..bed3f5c22a2 100644
--- a/chromium/components/sync_bookmarks/bookmark_model_type_processor_unittest.cc
+++ b/chromium/components/sync_bookmarks/bookmark_model_type_processor_unittest.cc
@@ -85,7 +85,7 @@ syncer::UpdateResponseData CreateUpdateResponseData(
const base::GUID& guid) {
syncer::EntityData data;
data.id = bookmark_info.server_id;
- data.parent_id = bookmark_info.parent_id;
+ data.legacy_parent_id = bookmark_info.parent_id;
data.server_defined_unique_tag = bookmark_info.server_tag;
data.originator_client_item_id = guid.AsLowercaseString();
@@ -745,10 +745,6 @@ TEST_F(BookmarkModelTypeProcessorTest,
TEST_F(BookmarkModelTypeProcessorTest,
ShouldCommitEntitiesWhileOtherFaviconsLoading) {
- base::test::ScopedFeatureList features;
- features.InitAndEnableFeature(
- switches::kSyncBookmarksEnforceLateMaxEntriesToCommit);
-
const std::string kNodeId1 = "node_id1";
const std::string kNodeId2 = "node_id2";
const std::string kTitle = "title";
@@ -785,8 +781,7 @@ TEST_F(BookmarkModelTypeProcessorTest,
// order for raw pointers in an unordered_set) which means the test needs to
// pass for both cases.
const std::vector<const SyncedBookmarkTracker::Entity*> unsynced_entities =
- processor()->GetTrackerForTest()->GetEntitiesWithLocalChanges(
- /*max_entries=*/1000);
+ processor()->GetTrackerForTest()->GetEntitiesWithLocalChanges();
ASSERT_THAT(
unsynced_entities,
UnorderedElementsAre(TrackedEntityCorrespondsToBookmarkNode(node1),
diff --git a/chromium/components/sync_bookmarks/bookmark_remote_updates_handler.cc b/chromium/components/sync_bookmarks/bookmark_remote_updates_handler.cc
index 7d43da7d240..751195ad0d7 100644
--- a/chromium/components/sync_bookmarks/bookmark_remote_updates_handler.cc
+++ b/chromium/components/sync_bookmarks/bookmark_remote_updates_handler.cc
@@ -16,11 +16,11 @@
#include "base/logging.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
-#include "base/strings/string_piece.h"
#include "base/trace_event/trace_event.h"
#include "components/bookmarks/browser/bookmark_model.h"
#include "components/bookmarks/browser/bookmark_node.h"
#include "components/sync/base/unique_position.h"
+#include "components/sync/engine/model_type_processor_metrics.h"
#include "components/sync/model/conflict_resolution.h"
#include "components/sync/protocol/unique_position.pb.h"
#include "components/sync_bookmarks/bookmark_specifics_conversions.h"
@@ -72,23 +72,26 @@ void LogProblematicBookmark(RemoteBookmarkUpdateError problem) {
// emit updates in top-down order. |ordered_updates| must not be null because
// traversed updates are appended to |*ordered_updates|.
void TraverseAndAppendChildren(
- const base::StringPiece& node_id,
- const std::unordered_map<base::StringPiece,
- const syncer::UpdateResponseData*,
- base::StringPieceHash>& id_to_updates,
- const std::unordered_map<base::StringPiece,
- std::vector<base::StringPiece>,
- base::StringPieceHash>& node_to_children,
+ const base::GUID& node_guid,
+ const std::unordered_multimap<base::GUID,
+ const syncer::UpdateResponseData*,
+ base::GUIDHash>& guid_to_updates,
+ const std::unordered_map<base::GUID,
+ std::vector<base::GUID>,
+ base::GUIDHash>& node_to_children,
std::vector<const syncer::UpdateResponseData*>* ordered_updates) {
// If no children to traverse, we are done.
- if (node_to_children.count(node_id) == 0) {
+ if (node_to_children.count(node_guid) == 0) {
return;
}
// Recurse over all children.
- for (const base::StringPiece& child : node_to_children.at(node_id)) {
- DCHECK_NE(id_to_updates.count(child), 0U);
- ordered_updates->push_back(id_to_updates.at(child));
- TraverseAndAppendChildren(child, id_to_updates, node_to_children,
+ for (const base::GUID& child : node_to_children.at(node_guid)) {
+ auto [begin, end] = guid_to_updates.equal_range(child);
+ DCHECK(begin != end);
+ for (auto it = begin; it != end; ++it) {
+ ordered_updates->push_back(it->second);
+ }
+ TraverseAndAppendChildren(child, guid_to_updates, node_to_children,
ordered_updates);
}
}
@@ -130,8 +133,7 @@ size_t ComputeChildNodeIndex(const bookmarks::BookmarkNode* parent,
}
bool IsPermanentNodeUpdate(const syncer::EntityData& update_entity) {
- return update_entity.parent_id == "0" ||
- !update_entity.server_defined_unique_tag.empty();
+ return !update_entity.server_defined_unique_tag.empty();
}
// Checks that the |update_entity| is valid and returns false otherwise. It is
@@ -163,6 +165,16 @@ bool IsValidUpdate(const syncer::EntityData& update_entity) {
return true;
}
+// Determines the parent's GUID included in |update_entity|. |update_entity|
+// must be a valid update as defined in IsValidUpdate().
+base::GUID GetParentGUIDInUpdate(const syncer::EntityData& update_entity) {
+ DCHECK(IsValidUpdate(update_entity));
+ base::GUID parent_guid = base::GUID::ParseLowercase(
+ update_entity.specifics.bookmark().parent_guid());
+ DCHECK(parent_guid.is_valid());
+ return parent_guid;
+}
+
void ApplyRemoteUpdate(
const syncer::UpdateResponseData& update,
const SyncedBookmarkTracker::Entity* tracked_entity,
@@ -288,6 +300,16 @@ void BookmarkRemoteUpdatesHandler::Process(
continue;
}
+ // Record freshness of the update to UMA. To mimic the behavior in
+ // ClientTagBasedModelTypeProcessor, one scenario is special-cased: an
+ // incoming tombstone for an entity that is not tracked.
+ if (tracked_entity || !update_entity.is_deleted()) {
+ syncer::LogNonReflectionUpdateFreshnessToUma(
+ syncer::BOOKMARKS,
+ /*remote_modification_time=*/
+ update_entity.modification_time);
+ }
+
// The server ID has changed for a tracked entity (matched via client tag).
// This can happen if a commit succeeds, but the response does not come back
// fast enough(e.g. before shutdown or crash), then the |bookmark_tracker_|
@@ -407,15 +429,15 @@ BookmarkRemoteUpdatesHandler::ReorderValidUpdates(
// 3. Start at each root in |roots|, emit the update and recurse over its
// children.
- std::unordered_map<base::StringPiece, const syncer::UpdateResponseData*,
- base::StringPieceHash>
- id_to_updates;
- std::set<base::StringPiece> roots;
- std::unordered_map<base::StringPiece, std::vector<base::StringPiece>,
- base::StringPieceHash>
- parent_to_children;
+ // Normally there shouldn't be multiple updates for the same GUID, but let's
+ // avoiding dedupping here just in case (e.g. the could in theory be a
+ // combination of client-tagged and non-client-tagged updated that
+ // ModelTypeWorker failed to deduplicate.
+ std::unordered_multimap<base::GUID, const syncer::UpdateResponseData*,
+ base::GUIDHash>
+ guid_to_updates;
- // Add only valid, non-deletions to |id_to_updates|.
+ // Add only valid, non-deletions to |guid_to_updates|.
int invalid_updates_count = 0;
int root_node_updates_count = 0;
for (const syncer::UpdateResponseData& update : *updates) {
@@ -432,35 +454,40 @@ BookmarkRemoteUpdatesHandler::ReorderValidUpdates(
++invalid_updates_count;
continue;
}
- id_to_updates[update_entity.id] = &update;
+ base::GUID guid =
+ base::GUID::ParseLowercase(update_entity.specifics.bookmark().guid());
+ DCHECK(guid.is_valid());
+ guid_to_updates.emplace(std::move(guid), &update);
}
- // Iterate over |id_to_updates| and construct |roots| and
+
+ // Iterate over |guid_to_updates| and construct |roots| and
// |parent_to_children|.
- for (const std::pair<const base::StringPiece,
- const syncer::UpdateResponseData*>& pair :
- id_to_updates) {
- const syncer::EntityData& update_entity = pair.second->entity;
- parent_to_children[update_entity.parent_id].push_back(update_entity.id);
+ std::set<base::GUID> roots;
+ std::unordered_map<base::GUID, std::vector<base::GUID>, base::GUIDHash>
+ parent_to_children;
+ for (const auto& [guid, update] : guid_to_updates) {
+ base::GUID parent_guid = GetParentGUIDInUpdate(update->entity);
+ base::GUID child_guid =
+ base::GUID::ParseLowercase(update->entity.specifics.bookmark().guid());
+ DCHECK(child_guid.is_valid());
+
+ parent_to_children[parent_guid].emplace_back(std::move(child_guid));
// If this entity's parent has no pending update, add it to |roots|.
- if (id_to_updates.count(update_entity.parent_id) == 0) {
- roots.insert(update_entity.parent_id);
+ if (guid_to_updates.count(parent_guid) == 0) {
+ roots.insert(std::move(parent_guid));
}
}
// |roots| contains only root of all trees in the forest all of which are
// ready to be processed because none has a pending update.
std::vector<const syncer::UpdateResponseData*> ordered_updates;
- for (const base::StringPiece& root : roots) {
- TraverseAndAppendChildren(root, id_to_updates, parent_to_children,
+ for (const base::GUID& root : roots) {
+ TraverseAndAppendChildren(root, guid_to_updates, parent_to_children,
&ordered_updates);
}
// Add deletions.
for (const syncer::UpdateResponseData& update : *updates) {
const syncer::EntityData& update_entity = update.entity;
- // Ignore updates to root nodes.
- if (IsPermanentNodeUpdate(update_entity)) {
- continue;
- }
- if (update_entity.is_deleted()) {
+ if (!IsPermanentNodeUpdate(update_entity) && update_entity.is_deleted()) {
ordered_updates.push_back(&update);
}
}
@@ -543,21 +570,12 @@ BookmarkRemoteUpdatesHandler::ProcessCreate(
const bookmarks::BookmarkNode* parent_node = GetParentNode(update_entity);
if (!parent_node) {
// If we cannot find the parent, we can do nothing.
- DLOG(ERROR)
- << "Could not find parent of node being added."
- << " Node title: "
- << update_entity.specifics.bookmark().legacy_canonicalized_title()
- << ", parent id = " << update_entity.parent_id;
LogProblematicBookmark(RemoteBookmarkUpdateError::kMissingParentNode);
bookmark_tracker_->RecordIgnoredServerUpdateDueToMissingParent(
update.response_version);
return nullptr;
}
if (!parent_node->is_folder()) {
- DLOG(ERROR)
- << "Parent node is not a folder. Node title: "
- << update_entity.specifics.bookmark().legacy_canonicalized_title()
- << ", parent id: " << update_entity.parent_id;
LogProblematicBookmark(RemoteBookmarkUpdateError::kParentNotFolder);
return nullptr;
}
@@ -598,23 +616,18 @@ void BookmarkRemoteUpdatesHandler::ProcessUpdate(
DCHECK(old_parent->is_folder());
const SyncedBookmarkTracker::Entity* new_parent_entity =
- bookmark_tracker_->GetEntityForSyncId(update_entity.parent_id);
+ bookmark_tracker_->GetEntityForGUID(GetParentGUIDInUpdate(update_entity));
if (!new_parent_entity) {
- DLOG(ERROR) << "Could not update node. Parent node doesn't exist: "
- << update_entity.parent_id;
LogProblematicBookmark(RemoteBookmarkUpdateError::kMissingParentEntity);
return;
}
const bookmarks::BookmarkNode* new_parent =
new_parent_entity->bookmark_node();
if (!new_parent) {
- DLOG(ERROR)
- << "Could not update node. Parent node has been deleted already.";
LogProblematicBookmark(RemoteBookmarkUpdateError::kMissingParentNode);
return;
}
if (!new_parent->is_folder()) {
- DLOG(ERROR) << "Could not update node. Parent not is not a folder.";
LogProblematicBookmark(RemoteBookmarkUpdateError::kParentNotFolder);
return;
}
@@ -711,15 +724,14 @@ BookmarkRemoteUpdatesHandler::ProcessConflict(
DCHECK(old_parent->is_folder());
const SyncedBookmarkTracker::Entity* new_parent_entity =
- bookmark_tracker_->GetEntityForSyncId(update_entity.parent_id);
+ bookmark_tracker_->GetEntityForGUID(GetParentGUIDInUpdate(update_entity));
+
// The |new_parent_entity| could be null in some racy conditions. For
// example, when a client A moves a node and deletes the old parent and
// commits, and then updates the node again, and at the same time client B
// updates before receiving the move updates. The client B update will arrive
// at client A after the parent entity has been deleted already.
if (!new_parent_entity) {
- DLOG(ERROR) << "Could not update node. Parent node doesn't exist: "
- << update_entity.parent_id;
LogProblematicBookmark(
RemoteBookmarkUpdateError::kMissingParentEntityInConflict);
return tracked_entity;
@@ -731,8 +743,6 @@ BookmarkRemoteUpdatesHandler::ProcessConflict(
// entails child deletion, and if this child has been updated on another
// client, this would cause conflict.
if (!new_parent) {
- DLOG(ERROR)
- << "Could not update node. Parent node has been deleted already.";
LogProblematicBookmark(
RemoteBookmarkUpdateError::kMissingParentNodeInConflict);
return tracked_entity;
@@ -780,8 +790,10 @@ void BookmarkRemoteUpdatesHandler::RemoveEntityAndChildrenFromTracker(
const bookmarks::BookmarkNode* BookmarkRemoteUpdatesHandler::GetParentNode(
const syncer::EntityData& update_entity) const {
+ DCHECK(IsValidBookmarkSpecifics(update_entity.specifics.bookmark()));
+
const SyncedBookmarkTracker::Entity* parent_entity =
- bookmark_tracker_->GetEntityForSyncId(update_entity.parent_id);
+ bookmark_tracker_->GetEntityForGUID(GetParentGUIDInUpdate(update_entity));
if (!parent_entity) {
return nullptr;
}
diff --git a/chromium/components/sync_bookmarks/bookmark_remote_updates_handler.h b/chromium/components/sync_bookmarks/bookmark_remote_updates_handler.h
index 94b7d51d046..9a3d219e7d9 100644
--- a/chromium/components/sync_bookmarks/bookmark_remote_updates_handler.h
+++ b/chromium/components/sync_bookmarks/bookmark_remote_updates_handler.h
@@ -8,7 +8,6 @@
#include <map>
#include <vector>
-#include "base/compiler_specific.h"
#include "base/memory/raw_ptr.h"
#include "components/sync/engine/commit_and_get_updates_types.h"
#include "components/sync_bookmarks/synced_bookmark_tracker.h"
@@ -114,9 +113,9 @@ class BookmarkRemoteUpdatesHandler {
// entity (if any) as a result of resolving the conflict, which is often the
// same as the input |tracked_entity|, but may also be different, including
// null (if the conflict led to untracking).
- const SyncedBookmarkTracker::Entity* ProcessConflict(
+ [[nodiscard]] const SyncedBookmarkTracker::Entity* ProcessConflict(
const syncer::UpdateResponseData& update,
- const SyncedBookmarkTracker::Entity* tracked_entity) WARN_UNUSED_RESULT;
+ const SyncedBookmarkTracker::Entity* tracked_entity);
// Recursively removes the entities corresponding to |node| and its children
// from |bookmark_tracker_|.
diff --git a/chromium/components/sync_bookmarks/bookmark_remote_updates_handler_unittest.cc b/chromium/components/sync_bookmarks/bookmark_remote_updates_handler_unittest.cc
index d81ab2c8e4b..430d4e2ffbd 100644
--- a/chromium/components/sync_bookmarks/bookmark_remote_updates_handler_unittest.cc
+++ b/chromium/components/sync_bookmarks/bookmark_remote_updates_handler_unittest.cc
@@ -22,7 +22,6 @@
#include "components/sync/base/hash_util.h"
#include "components/sync/base/model_type.h"
#include "components/sync/base/unique_position.h"
-#include "components/sync/driver/sync_driver_switches.h"
#include "components/sync/model/conflict_resolution.h"
#include "components/sync/protocol/bookmark_model_metadata.pb.h"
#include "components/sync/protocol/bookmark_specifics.pb.h"
@@ -174,14 +173,11 @@ syncer::UpdateResponseData CreateUpdateResponseData(
CreateTombstoneResponseData(guid, version);
response_data.entity.originator_client_item_id = guid.AsLowercaseString();
- response_data.entity.parent_id = GetFakeServerIdFromGUID(parent_guid);
- // Note that proto field |parent_guid| is not currently populated here
- // because the code doesn't actually need it, and besides legacy data coming
- // from the server may not include it.
sync_pb::BookmarkSpecifics* bookmark_specifics =
response_data.entity.specifics.mutable_bookmark();
bookmark_specifics->set_guid(guid.AsLowercaseString());
+ bookmark_specifics->set_parent_guid(parent_guid.AsLowercaseString());
bookmark_specifics->set_legacy_canonicalized_title(title);
bookmark_specifics->set_full_title(title);
bookmark_specifics->set_type(sync_pb::BookmarkSpecifics::FOLDER);
@@ -221,7 +217,6 @@ syncer::UpdateResponseData CreatePermanentFolderUpdateData(
const std::string& tag) {
syncer::EntityData data;
data.id = id;
- data.parent_id = "root_id";
data.server_defined_unique_tag = tag;
data.specifics.mutable_bookmark();
@@ -434,6 +429,51 @@ TEST_F(BookmarkRemoteUpdatesHandlerWithInitialMergeTest,
}
TEST_F(BookmarkRemoteUpdatesHandlerWithInitialMergeTest,
+ ShouldLogFreshnessToUma) {
+ const base::GUID kGuid = base::GUID::GenerateRandomV4();
+
+ syncer::UpdateResponseDataList updates;
+ updates.push_back(CreateUpdateResponseData(/*guid=*/kGuid,
+ /*parent_guid=*/kBookmarkBarGuid));
+
+ base::HistogramTester histogram_tester;
+ updates_handler()->Process(updates,
+ /*got_new_encryption_requirements=*/false);
+ histogram_tester.ExpectTotalCount(
+ "Sync.NonReflectionUpdateFreshnessPossiblySkewed2.BOOKMARK", 1);
+
+ // Process the same update again, which should be ignored because the version
+ // hasn't increased.
+ updates_handler()->Process(updates,
+ /*got_new_encryption_requirements=*/false);
+ histogram_tester.ExpectTotalCount(
+ "Sync.NonReflectionUpdateFreshnessPossiblySkewed2.BOOKMARK", 1);
+
+ // Increase version and process again; should log freshness.
+ ++updates[0].response_version;
+ updates_handler()->Process(updates,
+ /*got_new_encryption_requirements=*/false);
+ histogram_tester.ExpectTotalCount(
+ "Sync.NonReflectionUpdateFreshnessPossiblySkewed2.BOOKMARK", 2);
+
+ // Process remote deletion; should log freshness.
+ updates[0] =
+ CreateTombstoneResponseData(/*guid=*/kGuid,
+ /*version=*/updates[0].response_version + 1);
+ updates_handler()->Process(updates,
+ /*got_new_encryption_requirements=*/false);
+ histogram_tester.ExpectTotalCount(
+ "Sync.NonReflectionUpdateFreshnessPossiblySkewed2.BOOKMARK", 3);
+
+ // Process another (redundant) deletion for the same entity; should not log.
+ ++updates[0].response_version;
+ updates_handler()->Process(updates,
+ /*got_new_encryption_requirements=*/false);
+ histogram_tester.ExpectTotalCount(
+ "Sync.NonReflectionUpdateFreshnessPossiblySkewed2.BOOKMARK", 3);
+}
+
+TEST_F(BookmarkRemoteUpdatesHandlerWithInitialMergeTest,
ShouldProcessRandomlyOrderedDeletions) {
// Prepare creation updates to construct this structure:
// bookmark_bar
@@ -931,10 +971,11 @@ TEST_F(BookmarkRemoteUpdatesHandlerWithInitialMergeTest,
syncer::UpdateResponseDataList updates;
syncer::EntityData data;
data.id = GetFakeServerIdFromGUID(kParentGuid);
- data.parent_id = kBookmarkBarId;
sync_pb::BookmarkSpecifics* bookmark_specifics =
data.specifics.mutable_bookmark();
bookmark_specifics->set_guid(kParentGuid.AsLowercaseString());
+ bookmark_specifics->set_parent_guid(
+ bookmarks::BookmarkNode::kBookmarkBarNodeGuid);
bookmark_specifics->set_legacy_canonicalized_title(kTitle);
bookmark_specifics->set_url(kUrl.spec());
bookmark_specifics->set_type(sync_pb::BookmarkSpecifics::URL);
@@ -981,11 +1022,12 @@ TEST_F(BookmarkRemoteUpdatesHandlerWithInitialMergeTest,
syncer::UpdateResponseDataList updates;
syncer::EntityData data;
data.id = "server_id";
- data.parent_id = kBookmarkBarId;
sync_pb::BookmarkSpecifics* bookmark_specifics =
data.specifics.mutable_bookmark();
bookmark_specifics->set_guid(
base::GUID::GenerateRandomV4().AsLowercaseString());
+ bookmark_specifics->set_parent_guid(
+ bookmarks::BookmarkNode::kBookmarkBarNodeGuid);
// Use the server id as the title for simplicity.
bookmark_specifics->set_legacy_canonicalized_title(kTitle);
bookmark_specifics->set_url(kUrl.spec());
@@ -1024,11 +1066,12 @@ TEST_F(BookmarkRemoteUpdatesHandlerWithInitialMergeTest,
syncer::UpdateResponseDataList updates;
syncer::EntityData data;
data.id = "server_id";
- data.parent_id = kBookmarkBarId;
sync_pb::BookmarkSpecifics* bookmark_specifics =
data.specifics.mutable_bookmark();
bookmark_specifics->set_guid(
base::GUID::GenerateRandomV4().AsLowercaseString());
+ bookmark_specifics->set_parent_guid(
+ bookmarks::BookmarkNode::kBookmarkBarNodeGuid);
// Use the server id as the title for simplicity.
bookmark_specifics->set_legacy_canonicalized_title(kTitle);
bookmark_specifics->set_url(kUrl.spec());
@@ -1072,6 +1115,8 @@ TEST_F(BookmarkRemoteUpdatesHandlerWithInitialMergeTest,
sync_pb::BookmarkSpecifics* bookmark_specifics = specifics.mutable_bookmark();
bookmark_specifics->set_guid(
base::GUID::GenerateRandomV4().AsLowercaseString());
+ bookmark_specifics->set_parent_guid(
+ bookmarks::BookmarkNode::kBookmarkBarNodeGuid);
bookmark_specifics->set_legacy_canonicalized_title("Title");
bookmark_specifics->set_type(sync_pb::BookmarkSpecifics::FOLDER);
*bookmark_specifics->mutable_unique_position() =
@@ -1128,10 +1173,6 @@ TEST_F(BookmarkRemoteUpdatesHandlerWithInitialMergeTest,
TEST_F(
BookmarkRemoteUpdatesHandlerWithInitialMergeTest,
ShouldUpdateSyncIdWhenRecevingUpdateForNewlyCreatedLocalNodeWithClientTag) {
- base::test::ScopedFeatureList override_features;
- override_features.InitAndEnableFeature(
- switches::kSyncUseClientTagForBookmarkCommits);
-
const base::GUID kBookmarkGuid = base::GUID::GenerateRandomV4();
const std::string kSyncId = "server_id";
const int64_t kServerVersion = 1000;
@@ -1143,6 +1184,8 @@ TEST_F(
sync_pb::EntitySpecifics specifics;
sync_pb::BookmarkSpecifics* bookmark_specifics = specifics.mutable_bookmark();
bookmark_specifics->set_guid(kBookmarkGuid.AsLowercaseString());
+ bookmark_specifics->set_parent_guid(
+ bookmarks::BookmarkNode::kBookmarkBarNodeGuid);
bookmark_specifics->set_legacy_canonicalized_title("Title");
bookmark_specifics->set_type(sync_pb::BookmarkSpecifics::FOLDER);
*bookmark_specifics->mutable_unique_position() =
diff --git a/chromium/components/sync_bookmarks/bookmark_specifics_conversions.cc b/chromium/components/sync_bookmarks/bookmark_specifics_conversions.cc
index 39db5c06bfe..5f2470290fa 100644
--- a/chromium/components/sync_bookmarks/bookmark_specifics_conversions.cc
+++ b/chromium/components/sync_bookmarks/bookmark_specifics_conversions.cc
@@ -23,8 +23,8 @@
#include "components/bookmarks/browser/bookmark_node.h"
#include "components/favicon/core/favicon_service.h"
#include "components/sync/base/unique_position.h"
-#include "components/sync/engine/entity_data.h"
#include "components/sync/protocol/bookmark_specifics.pb.h"
+#include "components/sync/protocol/entity_data.h"
#include "components/sync/protocol/entity_specifics.pb.h"
#include "components/sync_bookmarks/switches.h"
#include "components/sync_bookmarks/synced_bookmark_tracker.h"
@@ -70,10 +70,10 @@ void LogFaviconContainedInSpecifics(bool contains_favicon) {
void UpdateBookmarkSpecificsMetaInfo(
const bookmarks::BookmarkNode::MetaInfoMap* metainfo_map,
sync_pb::BookmarkSpecifics* bm_specifics) {
- for (const std::pair<const std::string, std::string>& pair : *metainfo_map) {
+ for (const auto& [key, value] : *metainfo_map) {
sync_pb::MetaInfo* meta_info = bm_specifics->add_meta_info();
- meta_info->set_key(pair.first);
- meta_info->set_value(pair.second);
+ meta_info->set_key(key);
+ meta_info->set_value(value);
}
}
@@ -137,8 +137,6 @@ void SetBookmarkFaviconFromSpecifics(
}
// This is an exact copy of the same code in bookmark_update_preprocessing.cc.
-// TODO(crbug.com/1032052): Remove when client tags are adopted in
-// ModelTypeWorker.
std::string ComputeGuidFromBytes(base::span<const uint8_t> bytes) {
DCHECK_GE(bytes.size(), 16U);
@@ -162,9 +160,13 @@ std::string ComputeGuidFromBytes(base::span<const uint8_t> bytes) {
bytes[14], bytes[15]);
}
-// This is an exact copy of the same code in bookmark_update_preprocessing.cc.
-// TODO(crbug.com/1032052): Remove when client tags are adopted in
-// ModelTypeWorker.
+// This is an exact copy of the same code in bookmark_update_preprocessing.cc,
+// which could be removed if eventually client tags are adapted/inferred in
+// ModelTypeWorker. The reason why this is non-trivial today is that some users
+// are known to contain corrupt data in the sense that several different
+// entities (identified by their server-provided ID) use the same client tag
+// (and GUID). Currently BookmarkModelMerger has logic to prefer folders over
+// regular URLs and reassign GUIDs.
std::string InferGuidForLegacyBookmark(
const std::string& originator_cache_guid,
const std::string& originator_client_item_id) {
@@ -333,9 +335,14 @@ const bookmarks::BookmarkNode* CreateBookmarkNodeFromSpecifics(
DCHECK(favicon_service);
DCHECK(IsValidBookmarkSpecifics(specifics));
- base::GUID guid = base::GUID::ParseLowercase(specifics.guid());
+ const base::GUID guid = base::GUID::ParseLowercase(specifics.guid());
DCHECK(guid.is_valid());
+ const base::GUID parent_guid =
+ base::GUID::ParseLowercase(specifics.parent_guid());
+ DCHECK(parent_guid.is_valid());
+ DCHECK_EQ(parent_guid, parent->guid());
+
bookmarks::BookmarkNode::MetaInfoMap metainfo =
GetBookmarkMetaInfo(specifics);
@@ -452,14 +459,13 @@ bool IsValidBookmarkSpecifics(const sync_pb::BookmarkSpecifics& specifics) {
LogInvalidSpecifics(InvalidBookmarkSpecificsError::kBannedGUID);
is_valid = false;
}
- if (specifics.has_parent_guid()) {
- const base::GUID parent_guid =
- base::GUID::ParseLowercase(specifics.parent_guid());
- if (!parent_guid.is_valid()) {
- DLOG(ERROR) << "Invalid bookmark: invalid parent GUID in specifics.";
- LogInvalidSpecifics(InvalidBookmarkSpecificsError::kInvalidParentGUID);
- is_valid = false;
- }
+
+ const base::GUID parent_guid =
+ base::GUID::ParseLowercase(specifics.parent_guid());
+ if (!parent_guid.is_valid()) {
+ DLOG(ERROR) << "Invalid bookmark: invalid parent GUID in specifics.";
+ LogInvalidSpecifics(InvalidBookmarkSpecificsError::kInvalidParentGUID);
+ is_valid = false;
}
switch (specifics.type()) {
diff --git a/chromium/components/sync_bookmarks/bookmark_specifics_conversions_unittest.cc b/chromium/components/sync_bookmarks/bookmark_specifics_conversions_unittest.cc
index 63b0ce982c3..3d5d6ef835e 100644
--- a/chromium/components/sync_bookmarks/bookmark_specifics_conversions_unittest.cc
+++ b/chromium/components/sync_bookmarks/bookmark_specifics_conversions_unittest.cc
@@ -19,9 +19,8 @@
#include "components/favicon/core/test/mock_favicon_service.h"
#include "components/sync/base/client_tag_hash.h"
#include "components/sync/base/unique_position.h"
-#include "components/sync/driver/sync_driver_switches.h"
-#include "components/sync/engine/entity_data.h"
#include "components/sync/protocol/bookmark_specifics.pb.h"
+#include "components/sync/protocol/entity_data.h"
#include "components/sync/protocol/entity_specifics.pb.h"
#include "components/sync/protocol/model_type_state.pb.h"
#include "components/sync_bookmarks/synced_bookmark_tracker.h"
@@ -207,6 +206,10 @@ TEST(BookmarkSpecificsConversionsTest,
bm_specifics.set_creation_time_us(
kTime.ToDeltaSinceWindowsEpoch().InMicroseconds());
bm_specifics.set_type(sync_pb::BookmarkSpecifics::URL);
+
+ // Parent GUID and unique position are ignored by
+ // CreateBookmarkNodeFromSpecifics(), but are required here to pass DCHECKs.
+ bm_specifics.set_parent_guid(bookmarks::BookmarkNode::kBookmarkBarNodeGuid);
*bm_specifics.mutable_unique_position() = RandomUniquePosition();
sync_pb::MetaInfo* meta_info1 = bm_specifics.add_meta_info();
@@ -262,6 +265,10 @@ TEST(BookmarkSpecificsConversionsTest, ShouldCreateFolderFromSpecifics) {
bm_specifics.set_creation_time_us(
kTime.ToDeltaSinceWindowsEpoch().InMicroseconds());
bm_specifics.set_type(sync_pb::BookmarkSpecifics::FOLDER);
+
+ // Parent GUID and unique position are ignored by
+ // CreateBookmarkNodeFromSpecifics(), but are required here to pass DCHECKs.
+ bm_specifics.set_parent_guid(bookmarks::BookmarkNode::kBookmarkBarNodeGuid);
*bm_specifics.mutable_unique_position() = RandomUniquePosition();
sync_pb::MetaInfo* meta_info1 = bm_specifics.add_meta_info();
@@ -325,6 +332,10 @@ TEST(BookmarkSpecificsConversionsTest,
bm_specifics.set_creation_time_us(
kTime.ToDeltaSinceWindowsEpoch().InMicroseconds());
bm_specifics.set_type(sync_pb::BookmarkSpecifics::URL);
+
+ // Parent GUID and unique position are ignored by
+ // CreateBookmarkNodeFromSpecifics(), but are required here to pass DCHECKs.
+ bm_specifics.set_parent_guid(bookmarks::BookmarkNode::kBookmarkBarNodeGuid);
*bm_specifics.mutable_unique_position() = RandomUniquePosition();
sync_pb::MetaInfo* meta_info1 = bm_specifics.add_meta_info();
@@ -374,6 +385,10 @@ TEST(BookmarkSpecificsConversionsTest,
// Legacy clients append an extra space to illegal clients.
bm_specifics.set_legacy_canonicalized_title(illegal_title + " ");
bm_specifics.set_type(sync_pb::BookmarkSpecifics::URL);
+
+ // Parent GUID and unique position are ignored by
+ // CreateBookmarkNodeFromSpecifics(), but are required here to pass DCHECKs.
+ bm_specifics.set_parent_guid(bookmarks::BookmarkNode::kBookmarkBarNodeGuid);
*bm_specifics.mutable_unique_position() = RandomUniquePosition();
const bookmarks::BookmarkNode* node =
@@ -399,6 +414,10 @@ TEST(BookmarkSpecificsConversionsTest,
bm_specifics.set_favicon("PNG");
bm_specifics.set_legacy_canonicalized_title(kTitle);
bm_specifics.set_type(sync_pb::BookmarkSpecifics::URL);
+
+ // Parent GUID and unique position are ignored by
+ // CreateBookmarkNodeFromSpecifics(), but are required here to pass DCHECKs.
+ bm_specifics.set_parent_guid(bookmarks::BookmarkNode::kBookmarkBarNodeGuid);
*bm_specifics.mutable_unique_position() = RandomUniquePosition();
std::unique_ptr<bookmarks::BookmarkModel> model =
@@ -568,6 +587,8 @@ TEST(BookmarkSpecificsConversionsTest, ShouldBeValidBookmarkSpecifics) {
// URL is irrelevant for a folder.
bm_specifics.set_url("INVALID_URL");
bm_specifics.set_guid(base::GUID::GenerateRandomV4().AsLowercaseString());
+ bm_specifics.set_parent_guid(
+ base::GUID::GenerateRandomV4().AsLowercaseString());
bm_specifics.set_type(sync_pb::BookmarkSpecifics::FOLDER);
*bm_specifics.mutable_unique_position() = RandomUniquePosition();
EXPECT_TRUE(IsValidBookmarkSpecifics(bm_specifics));
@@ -584,6 +605,8 @@ TEST(BookmarkSpecificsConversionsTest,
bm_specifics.set_url("http://www.valid-url.com");
bm_specifics.set_favicon("PNG");
bm_specifics.set_guid(base::GUID::GenerateRandomV4().AsLowercaseString());
+ bm_specifics.set_parent_guid(
+ base::GUID::GenerateRandomV4().AsLowercaseString());
bm_specifics.set_type(sync_pb::BookmarkSpecifics::URL);
*bm_specifics.mutable_unique_position() = RandomUniquePosition();
EXPECT_TRUE(IsValidBookmarkSpecifics(bm_specifics));
@@ -609,6 +632,8 @@ TEST(BookmarkSpecificsConversionsTest,
base::HistogramTester histogram_tester;
sync_pb::BookmarkSpecifics bm_specifics;
bm_specifics.set_type(sync_pb::BookmarkSpecifics::FOLDER);
+ bm_specifics.set_parent_guid(
+ base::GUID::GenerateRandomV4().AsLowercaseString());
*bm_specifics.mutable_unique_position() = RandomUniquePosition();
// No GUID.
@@ -637,7 +662,37 @@ TEST(BookmarkSpecificsConversionsTest,
// Add valid GUID.
bm_specifics.set_guid(base::GUID::GenerateRandomV4().AsLowercaseString());
- EXPECT_TRUE(IsValidBookmarkSpecifics(bm_specifics));
+ ASSERT_TRUE(IsValidBookmarkSpecifics(bm_specifics));
+}
+
+TEST(BookmarkSpecificsConversionsTest,
+ ShouldBeInvalidBookmarkSpecificsWithInvalidParentGUID) {
+ base::HistogramTester histogram_tester;
+ sync_pb::BookmarkSpecifics bm_specifics;
+ bm_specifics.set_guid(base::GUID::GenerateRandomV4().AsLowercaseString());
+ bm_specifics.set_type(sync_pb::BookmarkSpecifics::FOLDER);
+ *bm_specifics.mutable_unique_position() = RandomUniquePosition();
+
+ // No parent GUID.
+ bm_specifics.clear_parent_guid();
+ EXPECT_FALSE(IsValidBookmarkSpecifics(bm_specifics));
+ histogram_tester.ExpectBucketCount(
+ "Sync.InvalidBookmarkSpecifics",
+ /*sample=*/InvalidBookmarkSpecificsError::kInvalidParentGUID,
+ /*expected_count=*/1);
+
+ // Add invalid parent GUID.
+ bm_specifics.set_parent_guid("INVALID GUID");
+ EXPECT_FALSE(IsValidBookmarkSpecifics(bm_specifics));
+ histogram_tester.ExpectBucketCount(
+ "Sync.InvalidBookmarkSpecifics",
+ /*sample=*/InvalidBookmarkSpecificsError::kInvalidParentGUID,
+ /*expected_count=*/2);
+
+ // Add valid GUID.
+ bm_specifics.set_parent_guid(
+ base::GUID::GenerateRandomV4().AsLowercaseString());
+ ASSERT_TRUE(IsValidBookmarkSpecifics(bm_specifics));
}
TEST(BookmarkSpecificsConversionsTest,
@@ -702,6 +757,8 @@ TEST(BookmarkSpecificsConversionsTest, ShouldBeInvalidBookmarkSpecifics) {
// Populate the required fields.
bm_specifics.set_guid(base::GUID::GenerateRandomV4().AsLowercaseString());
+ bm_specifics.set_parent_guid(
+ base::GUID::GenerateRandomV4().AsLowercaseString());
*bm_specifics.mutable_unique_position() = RandomUniquePosition();
ASSERT_TRUE(IsValidBookmarkSpecifics(bm_specifics));
diff --git a/chromium/components/sync_bookmarks/bookmark_sync_service.cc b/chromium/components/sync_bookmarks/bookmark_sync_service.cc
index 8c30bca3a39..bbdbf8b6be5 100644
--- a/chromium/components/sync_bookmarks/bookmark_sync_service.cc
+++ b/chromium/components/sync_bookmarks/bookmark_sync_service.cc
@@ -5,7 +5,6 @@
#include "components/sync_bookmarks/bookmark_sync_service.h"
#include "base/feature_list.h"
-#include "components/sync/driver/sync_driver_switches.h"
#include "components/sync_bookmarks/bookmark_model_type_processor.h"
#include "components/undo/bookmark_undo_service.h"
diff --git a/chromium/components/sync_bookmarks/parent_guid_preprocessing.cc b/chromium/components/sync_bookmarks/parent_guid_preprocessing.cc
new file mode 100644
index 00000000000..46e9062a778
--- /dev/null
+++ b/chromium/components/sync_bookmarks/parent_guid_preprocessing.cc
@@ -0,0 +1,240 @@
+// Copyright 2021 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.
+
+#include "components/sync_bookmarks/parent_guid_preprocessing.h"
+
+#include <memory>
+#include <unordered_map>
+
+#include "base/check.h"
+#include "base/guid.h"
+#include "base/strings/string_piece.h"
+#include "components/bookmarks/browser/bookmark_node.h"
+#include "components/sync/protocol/bookmark_specifics.pb.h"
+#include "components/sync/protocol/entity_specifics.pb.h"
+#include "components/sync/protocol/model_type_state.pb.h"
+#include "components/sync_bookmarks/synced_bookmark_tracker.h"
+
+namespace sync_bookmarks {
+
+namespace {
+
+// The tag used in the sync protocol to identity well-known permanent folders.
+const char kBookmarkBarTag[] = "bookmark_bar";
+const char kMobileBookmarksTag[] = "synced_bookmarks";
+const char kOtherBookmarksTag[] = "other_bookmarks";
+
+// Fake GUID used to populate field |BookmarkSpecifics.parent_guid| for the case
+// where a parent is specified in |SyncEntity.parent_id| but the parent's
+// precise GUID could not be determined. Doing this is mostly relevant for UMA
+// metrics. The precise GUID used in this string was generated using the same
+// technique as the well-known GUIDs in bookmarks::BookmarkNode, using the name
+// "unknown_parent_guid". The precise value is irrelevant though and can be
+// changed since all updates using the parent GUID will be ignored in practice.
+const char kInvalidParentGuid[] = "220a410e-37b9-5bbc-8674-ea982459f940";
+
+bool NeedsParentGuidInSpecifics(const syncer::UpdateResponseData& update) {
+ return !update.entity.is_deleted() &&
+ update.entity.legacy_parent_id != std::string("0") &&
+ update.entity.server_defined_unique_tag.empty() &&
+ !update.entity.specifics.bookmark().has_parent_guid();
+}
+
+// Tried to use the information known by |tracker| to determine the GUID of the
+// parent folder, for the entity updated in |update|. Returns an invalid GUID
+// if the GUID could not be determined. |tracker| must not be null.
+base::GUID TryGetParentGuidFromTracker(
+ const SyncedBookmarkTracker* tracker,
+ const syncer::UpdateResponseData& update) {
+ DCHECK(tracker);
+ DCHECK(!update.entity.is_deleted());
+ DCHECK(!update.entity.legacy_parent_id.empty());
+ DCHECK(update.entity.server_defined_unique_tag.empty());
+ DCHECK(!update.entity.specifics.bookmark().has_parent_guid());
+
+ const SyncedBookmarkTracker::Entity* const tracked_parent =
+ tracker->GetEntityForSyncId(update.entity.legacy_parent_id);
+ if (!tracked_parent) {
+ // Parent not known by tracker.
+ return base::GUID();
+ }
+
+ if (!tracked_parent->bookmark_node()) {
+ // Parent is a tombstone; cannot determine the GUID.
+ return base::GUID();
+ }
+
+ return tracked_parent->bookmark_node()->guid();
+}
+
+base::StringPiece GetGuidForEntity(const syncer::EntityData& entity) {
+ // Special-case permanent folders, which may not include a GUID in specifics.
+ if (entity.server_defined_unique_tag == kBookmarkBarTag) {
+ return bookmarks::BookmarkNode::kBookmarkBarNodeGuid;
+ }
+ if (entity.server_defined_unique_tag == kOtherBookmarksTag) {
+ return bookmarks::BookmarkNode::kOtherBookmarksNodeGuid;
+ }
+ if (entity.server_defined_unique_tag == kMobileBookmarksTag) {
+ return bookmarks::BookmarkNode::kMobileBookmarksNodeGuid;
+ }
+ // Fall back to the regular case, i.e. GUID in specifics, or an empty value
+ // if not present (including tombstones).
+ return entity.specifics.bookmark().guid();
+}
+
+// Map from sync IDs (server-provided entity IDs) to GUIDs. The
+// returned map uses StringPiece that rely on the lifetime of the strings in
+// |updates|. |updates| must not be null.
+class LazySyncIdToGuidMapInUpdates {
+ public:
+ // |updates| must not be null and must outlive this object.
+ explicit LazySyncIdToGuidMapInUpdates(
+ const syncer::UpdateResponseDataList* updates)
+ : updates_(updates) {
+ DCHECK(updates_);
+ }
+
+ LazySyncIdToGuidMapInUpdates(const LazySyncIdToGuidMapInUpdates&) = delete;
+ LazySyncIdToGuidMapInUpdates& operator=(const LazySyncIdToGuidMapInUpdates&) =
+ delete;
+
+ base::StringPiece GetGuidForSyncId(const std::string& sync_id) {
+ InitializeIfNeeded();
+ auto it = sync_id_to_guid_map_.find(sync_id);
+ if (it == sync_id_to_guid_map_.end()) {
+ return base::StringPiece();
+ }
+ return it->second;
+ }
+
+ private:
+ void InitializeIfNeeded() {
+ if (initialized_) {
+ return;
+ }
+ initialized_ = true;
+ for (const syncer::UpdateResponseData& update : *updates_) {
+ base::StringPiece guid = GetGuidForEntity(update.entity);
+ if (!update.entity.id.empty() && !guid.empty()) {
+ const bool success =
+ sync_id_to_guid_map_.emplace(update.entity.id, guid).second;
+ DCHECK(success);
+ }
+ }
+ }
+
+ const syncer::UpdateResponseDataList* const updates_;
+ bool initialized_ = false;
+ std::
+ unordered_map<base::StringPiece, base::StringPiece, base::StringPieceHash>
+ sync_id_to_guid_map_;
+};
+
+base::GUID GetParentGuidForUpdate(
+ const syncer::UpdateResponseData& update,
+ const SyncedBookmarkTracker* tracker,
+ LazySyncIdToGuidMapInUpdates* sync_id_to_guid_map_in_updates) {
+ DCHECK(tracker);
+ DCHECK(sync_id_to_guid_map_in_updates);
+
+ if (update.entity.legacy_parent_id.empty()) {
+ // Without the |SyncEntity.parent_id| field set, there is no information
+ // available to determine the parent and/or its GUID.
+ return base::GUID();
+ }
+
+ // If a tracker is available, i.e. initial sync already done, it may know
+ // parent's GUID already.
+ base::GUID guid = TryGetParentGuidFromTracker(tracker, update);
+ if (guid.is_valid()) {
+ return guid;
+ }
+
+ // Otherwise, fall back to checking if the parent is included in the full list
+ // of updates, represented here by |sync_id_to_guid_map_in_updates|. This
+ // codepath is most crucial for initial sync, where |tracker| is empty, but is
+ // also useful for non-initial sync, if the same incoming batch creates both
+ // parent and child, none of which would be known by |tracker|.
+ guid = base::GUID::ParseLowercase(
+ sync_id_to_guid_map_in_updates->GetGuidForSyncId(
+ update.entity.legacy_parent_id));
+ if (guid.is_valid()) {
+ return guid;
+ }
+
+ // At this point the parent's GUID couldn't be determined, but actually
+ // the |SyncEntity.parent_id| was non-empty. The update will be ignored
+ // regardless, but to avoid behavioral differences in UMA metrics
+ // Sync.ProblematicServerSideBookmarks[DuringMerge], a fake parent GUID is
+ // used here, which is known to never match an existing entity.
+ guid = base::GUID::ParseLowercase(kInvalidParentGuid);
+ DCHECK(guid.is_valid());
+ DCHECK(!tracker->GetEntityForGUID(guid));
+ return guid;
+}
+
+// Same as PopulateParentGuidInSpecifics(), but |tracker| must not be null.
+void PopulateParentGuidInSpecificsWithTracker(
+ const SyncedBookmarkTracker* tracker,
+ syncer::UpdateResponseDataList* updates) {
+ DCHECK(tracker);
+ DCHECK(updates);
+
+ LazySyncIdToGuidMapInUpdates sync_id_to_guid_map(updates);
+
+ for (syncer::UpdateResponseData& update : *updates) {
+ // Only legacy data, without the parent GUID in specifics populated,
+ // requires work. This also excludes tombstones and permanent folders.
+ if (!NeedsParentGuidInSpecifics(update)) {
+ // No work needed.
+ continue;
+ }
+
+ const base::GUID guid =
+ GetParentGuidForUpdate(update, tracker, &sync_id_to_guid_map);
+ if (guid.is_valid()) {
+ update.entity.specifics.mutable_bookmark()->set_parent_guid(
+ guid.AsLowercaseString());
+ }
+ }
+}
+
+} // namespace
+
+void PopulateParentGuidInSpecifics(const SyncedBookmarkTracker* tracker,
+ syncer::UpdateResponseDataList* updates) {
+ DCHECK(updates);
+
+ if (tracker) {
+ // The code in this file assumes permanent folders are tracked in
+ // SyncedBookmarkTracker. Since this is prone to change in the future, the
+ // DCHECK below is added to avoid subtle bugs, without relying exclusively
+ // on integration tests that exercise legacy data..
+ DCHECK(tracker->GetEntityForGUID(base::GUID::ParseLowercase(
+ bookmarks::BookmarkNode::kBookmarkBarNodeGuid)));
+ DCHECK(tracker->GetEntityForGUID(base::GUID::ParseLowercase(
+ bookmarks::BookmarkNode::kOtherBookmarksNodeGuid)));
+ DCHECK(tracker->GetEntityForGUID(base::GUID::ParseLowercase(
+ bookmarks::BookmarkNode::kMobileBookmarksNodeGuid)));
+
+ PopulateParentGuidInSpecificsWithTracker(tracker, updates);
+ return;
+ }
+
+ // No tracker provided, so use an empty tracker instead where all lookups will
+ // fail.
+ std::unique_ptr<SyncedBookmarkTracker> empty_tracker =
+ SyncedBookmarkTracker::CreateEmpty(sync_pb::ModelTypeState());
+ PopulateParentGuidInSpecificsWithTracker(empty_tracker.get(), updates);
+}
+
+std::string GetGuidForSyncIdInUpdatesForTesting( // IN-TEST
+ const syncer::UpdateResponseDataList& updates,
+ const std::string& sync_id) {
+ LazySyncIdToGuidMapInUpdates sync_id_to_guid_map(&updates);
+ return std::string(sync_id_to_guid_map.GetGuidForSyncId(sync_id));
+}
+
+} // namespace sync_bookmarks
diff --git a/chromium/components/sync_bookmarks/parent_guid_preprocessing.h b/chromium/components/sync_bookmarks/parent_guid_preprocessing.h
new file mode 100644
index 00000000000..b377205697c
--- /dev/null
+++ b/chromium/components/sync_bookmarks/parent_guid_preprocessing.h
@@ -0,0 +1,32 @@
+// Copyright 2021 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.
+
+#ifndef COMPONENTS_SYNC_BOOKMARKS_PARENT_GUID_PREPROCESSING_H_
+#define COMPONENTS_SYNC_BOOKMARKS_PARENT_GUID_PREPROCESSING_H_
+
+#include <string>
+
+#include "components/sync/engine/commit_and_get_updates_types.h"
+
+namespace sync_bookmarks {
+
+class SyncedBookmarkTracker;
+
+// Clients before M94 did not populate the parent GUID in specifics
+// (|BookmarkSpecifics.parent_guid|, so this function tries to populate the
+// missing values in |updates| such that it resembles how modern clients would
+// populate specifics (including |parent_guid|). To do so, it leverages the
+// information in |updates| itself (if the parent is included) and, if |tracker|
+// is non-null, the information available in tracked entities. |updates| must
+// not be null. |tracker| may be null,
+void PopulateParentGuidInSpecifics(const SyncedBookmarkTracker* tracker,
+ syncer::UpdateResponseDataList* updates);
+
+std::string GetGuidForSyncIdInUpdatesForTesting(
+ const syncer::UpdateResponseDataList& updates,
+ const std::string& sync_id);
+
+} // namespace sync_bookmarks
+
+#endif // COMPONENTS_SYNC_BOOKMARKS_PARENT_GUID_PREPROCESSING_H_
diff --git a/chromium/components/sync_bookmarks/parent_guid_preprocessing_unittest.cc b/chromium/components/sync_bookmarks/parent_guid_preprocessing_unittest.cc
new file mode 100644
index 00000000000..9dceca34a4b
--- /dev/null
+++ b/chromium/components/sync_bookmarks/parent_guid_preprocessing_unittest.cc
@@ -0,0 +1,233 @@
+// Copyright 2021 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.
+
+#include "components/sync_bookmarks/parent_guid_preprocessing.h"
+
+#include <memory>
+
+#include "base/guid.h"
+#include "components/bookmarks/browser/bookmark_model.h"
+#include "components/bookmarks/browser/bookmark_node.h"
+#include "components/bookmarks/test/test_bookmark_client.h"
+#include "components/sync/protocol/bookmark_specifics.pb.h"
+#include "components/sync/protocol/entity_data.h"
+#include "components/sync/protocol/entity_specifics.pb.h"
+#include "components/sync/protocol/model_type_state.pb.h"
+#include "components/sync_bookmarks/synced_bookmark_tracker.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace sync_bookmarks {
+
+namespace {
+
+using testing::Eq;
+
+TEST(ParentGuidPreprocessingTest, ShouldReturnGuidForSyncIdIncludedInUpdates) {
+ const std::string kId1 = "sync_id1";
+ const std::string kId2 = "sync_id2";
+ const std::string kGuid1 = "guid1";
+ const std::string kGuid2 = "guid2";
+
+ syncer::UpdateResponseDataList updates;
+ updates.emplace_back();
+ updates.back().entity.id = kId1;
+ updates.back().entity.specifics.mutable_bookmark()->set_guid(kGuid1);
+ updates.emplace_back();
+ updates.back().entity.id = kId2;
+ updates.back().entity.specifics.mutable_bookmark()->set_guid(kGuid2);
+
+ EXPECT_THAT(GetGuidForSyncIdInUpdatesForTesting(updates, kId1), Eq(kGuid1));
+ EXPECT_THAT(GetGuidForSyncIdInUpdatesForTesting(updates, kId2), Eq(kGuid2));
+}
+
+TEST(ParentGuidPreprocessingTest,
+ ShouldReturnInvalidGuidForSyncIdMissingInUpdates) {
+ const std::string kId1 = "sync_id1";
+ const std::string kGuid1 = "guid1";
+
+ syncer::UpdateResponseDataList updates;
+
+ EXPECT_THAT(GetGuidForSyncIdInUpdatesForTesting(updates, "missing_id"),
+ Eq(""));
+
+ updates.emplace_back();
+ updates.back().entity.id = kId1;
+ updates.back().entity.specifics.mutable_bookmark()->set_guid(kGuid1);
+
+ ASSERT_THAT(GetGuidForSyncIdInUpdatesForTesting(updates, kId1), Eq(kGuid1));
+ EXPECT_THAT(GetGuidForSyncIdInUpdatesForTesting(updates, "missing_id"),
+ Eq(""));
+}
+
+TEST(ParentGuidPreprocessingTest, ShouldReturnGuidForPermanentFolders) {
+ const std::string kBookmarkBarId = "id1";
+ const std::string kMobileBookmarksId = "id2";
+ const std::string kOtherBookmarksId = "id3";
+
+ // Permanent folders may not include their GUIDs.
+ syncer::UpdateResponseDataList updates;
+ updates.emplace_back();
+ updates.back().entity.id = kBookmarkBarId;
+ updates.back().entity.server_defined_unique_tag = "bookmark_bar";
+ updates.emplace_back();
+ updates.back().entity.id = kMobileBookmarksId;
+ updates.back().entity.server_defined_unique_tag = "synced_bookmarks";
+ updates.emplace_back();
+ updates.back().entity.id = kOtherBookmarksId;
+ updates.back().entity.server_defined_unique_tag = "other_bookmarks";
+
+ EXPECT_THAT(GetGuidForSyncIdInUpdatesForTesting(updates, kBookmarkBarId),
+ Eq(bookmarks::BookmarkNode::kBookmarkBarNodeGuid));
+ EXPECT_THAT(GetGuidForSyncIdInUpdatesForTesting(updates, kMobileBookmarksId),
+ Eq(bookmarks::BookmarkNode::kMobileBookmarksNodeGuid));
+ EXPECT_THAT(GetGuidForSyncIdInUpdatesForTesting(updates, kOtherBookmarksId),
+ Eq(bookmarks::BookmarkNode::kOtherBookmarksNodeGuid));
+}
+
+TEST(ParentGuidPreprocessingTest, ShouldPopulateParentGuidInInitialUpdates) {
+ const std::string kBookmarkBarId = "bookmark_bar_id";
+ const std::string kParentFolderId = "parent_folder_id";
+ const std::string kParentFolderGuid =
+ base::GUID::GenerateRandomV4().AsLowercaseString();
+
+ // Populate updates representing:
+ // bookmark_bar
+ // |- folder 1
+ // |- folder 2
+ syncer::UpdateResponseDataList updates;
+ updates.emplace_back();
+ updates.back().entity.id = kBookmarkBarId;
+ updates.back().entity.server_defined_unique_tag = "bookmark_bar";
+ updates.emplace_back();
+ updates.back().entity.id = kParentFolderId;
+ updates.back().entity.legacy_parent_id = kBookmarkBarId;
+ updates.back().entity.specifics.mutable_bookmark()->set_guid(
+ kParentFolderGuid);
+ updates.emplace_back();
+ updates.back().entity.legacy_parent_id = kParentFolderId;
+ updates.back().entity.specifics.mutable_bookmark()->set_guid("child_guid");
+
+ PopulateParentGuidInSpecifics(/*tracker=*/nullptr, &updates);
+
+ EXPECT_THAT(updates[0].entity.specifics.bookmark().parent_guid(), Eq(""));
+ EXPECT_THAT(updates[1].entity.specifics.bookmark().parent_guid(),
+ Eq(bookmarks::BookmarkNode::kBookmarkBarNodeGuid));
+ EXPECT_THAT(updates[2].entity.specifics.bookmark().parent_guid(),
+ Eq(kParentFolderGuid));
+}
+
+TEST(ParentGuidPreprocessingTest,
+ ShouldNotOverridePreexistingParentGuidInSpecifics) {
+ const std::string kBookmarkBarId = "bookmark_bar_id";
+ const std::string kFolderId = "folder_id";
+
+ const std::string kFolderGuid =
+ base::GUID::GenerateRandomV4().AsLowercaseString();
+ const std::string kParentGuidInSpecifics =
+ base::GUID::GenerateRandomV4().AsLowercaseString();
+
+ // Populate updates representing:
+ // bookmark_bar
+ // |- folder 1
+ // |- folder 2
+ syncer::UpdateResponseDataList updates;
+ updates.emplace_back();
+ updates.back().entity.id = kBookmarkBarId;
+ updates.back().entity.server_defined_unique_tag = "bookmark_bar";
+ updates.emplace_back();
+ updates.back().entity.id = kFolderId;
+ updates.back().entity.legacy_parent_id = kBookmarkBarId;
+ updates.back().entity.specifics.mutable_bookmark()->set_guid(kFolderGuid);
+ updates.back().entity.specifics.mutable_bookmark()->set_parent_guid(
+ kParentGuidInSpecifics);
+
+ // Although |parent_id| points to bookmarks bar, the |parent_guid| field
+ // should prevail.
+ ASSERT_THAT(GetGuidForSyncIdInUpdatesForTesting(updates, kBookmarkBarId),
+ Eq(bookmarks::BookmarkNode::kBookmarkBarNodeGuid));
+
+ PopulateParentGuidInSpecifics(/*tracker=*/nullptr, &updates);
+
+ EXPECT_THAT(updates[1].entity.specifics.bookmark().parent_guid(),
+ Eq(kParentGuidInSpecifics));
+}
+
+TEST(ParentGuidPreprocessingTest,
+ ShouldPopulateParentGuidInIncrementalUpdates) {
+ const std::string kSyncId = "id1";
+ const std::string kBookmarkBarId = "bookmark_bar_id";
+
+ std::unique_ptr<SyncedBookmarkTracker> tracker =
+ SyncedBookmarkTracker::CreateEmpty(sync_pb::ModelTypeState());
+
+ // Non-empty specifics are needed for SyncedBookmarkTracker::Add(), with
+ // unique position populated.
+ sync_pb::EntitySpecifics dummy_specifics;
+ dummy_specifics.mutable_bookmark()->mutable_unique_position();
+
+ // BookmarkModel is used here to pass DCHECKs that require that permanent
+ // folders are tracked.
+ std::unique_ptr<bookmarks::BookmarkModel> bookmark_model =
+ bookmarks::TestBookmarkClient::CreateModel();
+ tracker->Add(bookmark_model->bookmark_bar_node(), /*sync_id=*/kBookmarkBarId,
+ /*server_version=*/0, /*creation_time=*/base::Time::Now(),
+ /*specifics=*/dummy_specifics);
+ tracker->Add(bookmark_model->other_node(), /*sync_id=*/"other_node_id",
+ /*server_version=*/0, /*creation_time=*/base::Time::Now(),
+ /*specifics=*/dummy_specifics);
+ tracker->Add(bookmark_model->mobile_node(), /*sync_id=*/"mobile_node_id",
+ /*server_version=*/0, /*creation_time=*/base::Time::Now(),
+ /*specifics=*/dummy_specifics);
+
+ // Add one regular (non-permanent) node.
+ bookmarks::BookmarkNode tracked_node(/*id=*/1, base::GUID::GenerateRandomV4(),
+ GURL());
+ tracker->Add(&tracked_node, kSyncId,
+ /*server_version=*/0, /*creation_time=*/base::Time::Now(),
+ /*specifics=*/dummy_specifics);
+
+ syncer::UpdateResponseDataList updates;
+ updates.emplace_back();
+ updates.back().entity.legacy_parent_id = kSyncId;
+ updates.back().entity.specifics.mutable_bookmark()->set_guid("guid1");
+ updates.emplace_back();
+ updates.back().entity.legacy_parent_id = kBookmarkBarId;
+ updates.back().entity.specifics.mutable_bookmark()->set_guid("guid2");
+ PopulateParentGuidInSpecifics(tracker.get(), &updates);
+
+ EXPECT_THAT(updates[0].entity.specifics.bookmark().parent_guid(),
+ Eq(tracked_node.guid().AsLowercaseString()));
+ EXPECT_THAT(updates[1].entity.specifics.bookmark().parent_guid(),
+ Eq(bookmarks::BookmarkNode::kBookmarkBarNodeGuid));
+}
+
+TEST(ParentGuidPreprocessingTest,
+ ShouldPopulateWithFakeGuidIfParentSetButUnknown) {
+ // Fork of the private constant in the .cc file.
+ const std::string kInvalidParentGuid = "220a410e-37b9-5bbc-8674-ea982459f940";
+
+ const std::string kParentFolderId = "parent_folder_id";
+ const std::string kParentFolderGuid =
+ base::GUID::GenerateRandomV4().AsLowercaseString();
+
+ // Populate updates representing:
+ // |- folder with unknown parent
+ syncer::UpdateResponseDataList updates;
+ updates.emplace_back();
+ updates.back().entity.id = kParentFolderId;
+ updates.back().entity.legacy_parent_id = "some_unknown_parent";
+ updates.back().entity.specifics.mutable_bookmark()->set_guid(
+ kParentFolderGuid);
+
+ PopulateParentGuidInSpecifics(/*tracker=*/nullptr, &updates);
+
+ EXPECT_THAT(updates[0].entity.specifics.bookmark().parent_guid(),
+ Eq(kInvalidParentGuid));
+}
+
+} // namespace
+
+} // namespace sync_bookmarks
diff --git a/chromium/components/sync_bookmarks/switches.cc b/chromium/components/sync_bookmarks/switches.cc
deleted file mode 100644
index faebd322038..00000000000
--- a/chromium/components/sync_bookmarks/switches.cc
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2020 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.
-
-#include "components/sync_bookmarks/switches.h"
-#include "base/feature_list.h"
-
-namespace switches {
-
-const base::Feature kSyncReuploadBookmarks{"SyncReuploadBookmarks",
- base::FEATURE_ENABLED_BY_DEFAULT};
-
-const base::Feature kSyncUseClientTagForBookmarkCommits{
- "SyncUseClientTagForBookmarkCommits", base::FEATURE_ENABLED_BY_DEFAULT};
-
-const base::Feature kSyncBookmarksEnforceLateMaxEntriesToCommit{
- "SyncBookmarksEnforceLateMaxEntriesToCommit",
- base::FEATURE_ENABLED_BY_DEFAULT};
-
-} // namespace switches
diff --git a/chromium/components/sync_bookmarks/switches.h b/chromium/components/sync_bookmarks/switches.h
index fedc3262689..a11547dc2c5 100644
--- a/chromium/components/sync_bookmarks/switches.h
+++ b/chromium/components/sync_bookmarks/switches.h
@@ -11,12 +11,8 @@ namespace switches {
// TODO(crbug.com/1232951): remove the feature toggle once most of bookmarks
// have been reuploaded.
-extern const base::Feature kSyncReuploadBookmarks;
-extern const base::Feature kSyncUseClientTagForBookmarkCommits;
-
-// TODO(crbug.com/1177798): remove this code after a quick verification that it
-// doesn't cause issues.
-extern const base::Feature kSyncBookmarksEnforceLateMaxEntriesToCommit;
+inline constexpr base::Feature kSyncReuploadBookmarks{
+ "SyncReuploadBookmarks", base::FEATURE_ENABLED_BY_DEFAULT};
} // namespace switches
diff --git a/chromium/components/sync_bookmarks/synced_bookmark_tracker.cc b/chromium/components/sync_bookmarks/synced_bookmark_tracker.cc
index ec541fc4cb4..40ff36fe6e8 100644
--- a/chromium/components/sync_bookmarks/synced_bookmark_tracker.cc
+++ b/chromium/components/sync_bookmarks/synced_bookmark_tracker.cc
@@ -20,8 +20,8 @@
#include "components/bookmarks/browser/bookmark_model.h"
#include "components/bookmarks/browser/bookmark_node.h"
#include "components/sync/base/time.h"
-#include "components/sync/engine/entity_data.h"
#include "components/sync/protocol/bookmark_model_metadata.pb.h"
+#include "components/sync/protocol/entity_data.h"
#include "components/sync/protocol/entity_specifics.pb.h"
#include "components/sync/protocol/proto_memory_estimations.h"
#include "components/sync/protocol/unique_position.pb.h"
@@ -144,7 +144,6 @@ std::unique_ptr<SyncedBookmarkTracker> SyncedBookmarkTracker::CreateEmpty(
// base::WrapUnique() used because the constructor is private.
return base::WrapUnique(new SyncedBookmarkTracker(
std::move(model_type_state), /*bookmarks_reuploaded=*/false,
- /*last_sync_time=*/base::Time::Now(),
/*num_ignored_updates_due_to_missing_parent=*/absl::optional<int64_t>(0),
/*max_version_among_ignored_updates_due_to_missing_parent=*/
absl::nullopt));
@@ -161,11 +160,6 @@ SyncedBookmarkTracker::CreateFromBookmarkModelAndMetadata(
return nullptr;
}
- // If the field is not present, |last_sync_time| will be initialized with the
- // Unix epoch.
- const base::Time last_sync_time =
- syncer::ProtoTimeToTime(model_metadata.last_sync_time());
-
// When the reupload feature is enabled and disabled again, there may occur
// new entities which weren't reuploaded.
const bool bookmarks_reuploaded =
@@ -189,7 +183,7 @@ SyncedBookmarkTracker::CreateFromBookmarkModelAndMetadata(
// base::WrapUnique() used because the constructor is private.
auto tracker = base::WrapUnique(new SyncedBookmarkTracker(
- model_metadata.model_type_state(), bookmarks_reuploaded, last_sync_time,
+ model_metadata.model_type_state(), bookmarks_reuploaded,
num_ignored_updates_due_to_missing_parent,
max_version_among_ignored_updates_due_to_missing_parent));
@@ -393,7 +387,6 @@ SyncedBookmarkTracker::BuildBookmarkModelMetadata() const {
sync_pb::BookmarkModelMetadata model_metadata;
model_metadata.set_bookmarks_hierarchy_fields_reuploaded(
bookmarks_reuploaded_);
- model_metadata.set_last_sync_time(syncer::TimeToProtoTime(last_sync_time_));
if (num_ignored_updates_due_to_missing_parent_.has_value()) {
model_metadata.set_num_ignored_updates_due_to_missing_parent(
@@ -405,20 +398,19 @@ SyncedBookmarkTracker::BuildBookmarkModelMetadata() const {
*max_version_among_ignored_updates_due_to_missing_parent_);
}
- for (const std::pair<const std::string, std::unique_ptr<Entity>>& pair :
- sync_id_to_entities_map_) {
- DCHECK(pair.second) << " for ID " << pair.first;
- DCHECK(pair.second->metadata()) << " for ID " << pair.first;
- if (pair.second->metadata()->is_deleted()) {
+ for (const auto& [sync_id, entity] : sync_id_to_entities_map_) {
+ DCHECK(entity) << " for ID " << sync_id;
+ DCHECK(entity->metadata()) << " for ID " << sync_id;
+ if (entity->metadata()->is_deleted()) {
// Deletions will be added later because they need to maintain the same
// order as in |ordered_local_tombstones_|.
continue;
}
- DCHECK(pair.second->bookmark_node());
+ DCHECK(entity->bookmark_node());
sync_pb::BookmarkMetadata* bookmark_metadata =
model_metadata.add_bookmarks_metadata();
- bookmark_metadata->set_id(pair.second->bookmark_node()->id());
- *bookmark_metadata->mutable_metadata() = *pair.second->metadata();
+ bookmark_metadata->set_id(entity->bookmark_node()->id());
+ *bookmark_metadata->mutable_metadata() = *entity->metadata();
}
// Add pending deletions.
for (const Entity* tombstone_entity : ordered_local_tombstones_) {
@@ -434,9 +426,7 @@ SyncedBookmarkTracker::BuildBookmarkModelMetadata() const {
}
bool SyncedBookmarkTracker::HasLocalChanges() const {
- for (const std::pair<const std::string, std::unique_ptr<Entity>>& pair :
- sync_id_to_entities_map_) {
- Entity* entity = pair.second.get();
+ for (const auto& [sync_id, entity] : sync_id_to_entities_map_) {
if (entity->IsUnsynced()) {
return true;
}
@@ -447,28 +437,25 @@ bool SyncedBookmarkTracker::HasLocalChanges() const {
std::vector<const SyncedBookmarkTracker::Entity*>
SyncedBookmarkTracker::GetAllEntities() const {
std::vector<const SyncedBookmarkTracker::Entity*> entities;
- for (const std::pair<const std::string, std::unique_ptr<Entity>>& pair :
- sync_id_to_entities_map_) {
- entities.push_back(pair.second.get());
+ for (const auto& [sync_id, entity] : sync_id_to_entities_map_) {
+ entities.push_back(entity.get());
}
return entities;
}
std::vector<const SyncedBookmarkTracker::Entity*>
-SyncedBookmarkTracker::GetEntitiesWithLocalChanges(size_t max_entries) const {
+SyncedBookmarkTracker::GetEntitiesWithLocalChanges() const {
std::vector<const SyncedBookmarkTracker::Entity*> entities_with_local_changes;
// Entities with local non deletions should be sorted such that parent
// creation/update comes before child creation/update.
- for (const std::pair<const std::string, std::unique_ptr<Entity>>& pair :
- sync_id_to_entities_map_) {
- Entity* entity = pair.second.get();
+ for (const auto& [sync_id, entity] : sync_id_to_entities_map_) {
if (entity->metadata()->is_deleted()) {
// Deletions are stored sorted in |ordered_local_tombstones_| and will be
// added later.
continue;
}
if (entity->IsUnsynced()) {
- entities_with_local_changes.push_back(entity);
+ entities_with_local_changes.push_back(entity.get());
}
}
std::vector<const SyncedBookmarkTracker::Entity*> ordered_local_changes =
@@ -480,26 +467,17 @@ SyncedBookmarkTracker::GetEntitiesWithLocalChanges(size_t max_entries) const {
ordered_local_changes.end(), tombstone_entity));
ordered_local_changes.push_back(tombstone_entity);
}
- if (ordered_local_changes.size() > max_entries) {
- // TODO(crbug.com/516866): Should be smart and stop building the vector
- // when |max_entries| is reached.
- return std::vector<const SyncedBookmarkTracker::Entity*>(
- ordered_local_changes.begin(),
- ordered_local_changes.begin() + max_entries);
- }
return ordered_local_changes;
}
SyncedBookmarkTracker::SyncedBookmarkTracker(
sync_pb::ModelTypeState model_type_state,
bool bookmarks_reuploaded,
- base::Time last_sync_time,
absl::optional<int64_t> num_ignored_updates_due_to_missing_parent,
absl::optional<int64_t>
max_version_among_ignored_updates_due_to_missing_parent)
: model_type_state_(std::move(model_type_state)),
bookmarks_reuploaded_(bookmarks_reuploaded),
- last_sync_time_(last_sync_time),
num_ignored_updates_due_to_missing_parent_(
num_ignored_updates_due_to_missing_parent),
max_version_among_ignored_updates_due_to_missing_parent_(
@@ -698,26 +676,19 @@ bool SyncedBookmarkTracker::ReuploadBookmarksOnLoadIfNeeded() {
!base::FeatureList::IsEnabled(switches::kSyncReuploadBookmarks)) {
return false;
}
- for (const auto& sync_id_and_entity : sync_id_to_entities_map_) {
- const SyncedBookmarkTracker::Entity* entity =
- sync_id_and_entity.second.get();
+ for (const auto& [sync_id, entity] : sync_id_to_entities_map_) {
if (entity->IsUnsynced() || entity->metadata()->is_deleted()) {
continue;
}
if (entity->bookmark_node()->is_permanent_node()) {
continue;
}
- IncrementSequenceNumber(entity);
+ IncrementSequenceNumber(entity.get());
}
SetBookmarksReuploaded();
return true;
}
-bool SyncedBookmarkTracker::bookmark_client_tags_in_protocol_enabled() const {
- return base::FeatureList::IsEnabled(
- switches::kSyncUseClientTagForBookmarkCommits);
-}
-
void SyncedBookmarkTracker::RecordIgnoredServerUpdateDueToMissingParent(
int64_t server_version) {
if (num_ignored_updates_due_to_missing_parent_.has_value()) {
diff --git a/chromium/components/sync_bookmarks/synced_bookmark_tracker.h b/chromium/components/sync_bookmarks/synced_bookmark_tracker.h
index a9e2d491d3c..1bb3548dd39 100644
--- a/chromium/components/sync_bookmarks/synced_bookmark_tracker.h
+++ b/chromium/components/sync_bookmarks/synced_bookmark_tracker.h
@@ -62,6 +62,8 @@ class SyncedBookmarkTracker {
// Check whether |data| matches the stored specifics hash. It also compares
// parent information, but only if present in specifics (M94 and above).
+ // TODO(crbug.com/1274122): Remove Possibly from the name, since it's now
+ // guaranteed and update comment.
bool MatchesDataPossiblyIncludingParent(
const syncer::EntityData& data) const;
@@ -213,15 +215,9 @@ class SyncedBookmarkTracker {
model_type_state_ = std::move(model_type_state);
}
- // Treats the current time as last sync time.
- // TODO(crbug.com/1032052): Remove this code once all local sync metadata is
- // required to populate the client tag (and be considered invalid otherwise).
- void UpdateLastSyncTime() { last_sync_time_ = base::Time::Now(); }
-
std::vector<const Entity*> GetAllEntities() const;
- std::vector<const Entity*> GetEntitiesWithLocalChanges(
- size_t max_entries) const;
+ std::vector<const Entity*> GetEntitiesWithLocalChanges() const;
// Updates the tracker after receiving the commit response. |sync_id| should
// match the already tracked sync ID for |entity|, with the exception of the
@@ -282,10 +278,6 @@ class SyncedBookmarkTracker {
// reuploaded.
bool ReuploadBookmarksOnLoadIfNeeded();
- // Returns whether bookmark commits sent to the server (most importantly
- // creations) should populate client tags.
- bool bookmark_client_tags_in_protocol_enabled() const;
-
// Causes the tracker to remember that a remote sync update (initial or
// incremental) was ignored because its parent was unknown (either because
// the data was corrupt or because the update is a descendant of an
@@ -323,7 +315,6 @@ class SyncedBookmarkTracker {
SyncedBookmarkTracker(
sync_pb::ModelTypeState model_type_state,
bool bookmarks_reuploaded,
- base::Time last_sync_time,
absl::optional<int64_t> num_ignored_updates_due_to_missing_parent,
absl::optional<int64_t>
max_version_among_ignored_updates_due_to_missing_parent);
@@ -383,12 +374,6 @@ class SyncedBookmarkTracker {
// reuploaded.
bool bookmarks_reuploaded_ = false;
- // The local timestamp corresponding to the last time remote updates were
- // received.
- // TODO(crbug.com/1032052): Remove this code once all local sync metadata is
- // required to populate the client tag (and be considered invalid otherwise).
- base::Time last_sync_time_;
-
// See corresponding proto fields in BookmarkModelMetadata.
absl::optional<int64_t> num_ignored_updates_due_to_missing_parent_;
absl::optional<int64_t>
diff --git a/chromium/components/sync_bookmarks/synced_bookmark_tracker_unittest.cc b/chromium/components/sync_bookmarks/synced_bookmark_tracker_unittest.cc
index 4ca9cc6c6b3..35d940eba08 100644
--- a/chromium/components/sync_bookmarks/synced_bookmark_tracker_unittest.cc
+++ b/chromium/components/sync_bookmarks/synced_bookmark_tracker_unittest.cc
@@ -16,8 +16,8 @@
#include "components/sync/base/client_tag_hash.h"
#include "components/sync/base/time.h"
#include "components/sync/base/unique_position.h"
-#include "components/sync/engine/entity_data.h"
#include "components/sync/protocol/bookmark_model_metadata.pb.h"
+#include "components/sync/protocol/entity_data.h"
#include "components/sync/protocol/entity_specifics.pb.h"
#include "components/sync/protocol/model_type_state.pb.h"
#include "components/sync_bookmarks/switches.h"
@@ -214,7 +214,6 @@ TEST(SyncedBookmarkTrackerTest, ShouldBuildBookmarkModelMetadata) {
EXPECT_THAT(
bookmark_model_metadata.bookmarks_metadata(0).metadata().server_id(),
Eq(kSyncId));
- EXPECT_TRUE(bookmark_model_metadata.has_last_sync_time());
}
TEST(SyncedBookmarkTrackerTest,
@@ -546,8 +545,6 @@ TEST(SyncedBookmarkTrackerTest, ShouldUndeleteTombstone) {
TEST(SyncedBookmarkTrackerTest,
ShouldOrderParentUpdatesBeforeChildUpdatesAndDeletionsComeLast) {
- const size_t kMaxEntries = 1000;
-
// Construct this structure:
// bookmark_bar
// |- node0
@@ -599,7 +596,7 @@ TEST(SyncedBookmarkTrackerTest,
tracker->IncrementSequenceNumber(tracker->GetEntityForSyncId(kId0));
std::vector<const SyncedBookmarkTracker::Entity*> entities_with_local_change =
- tracker->GetEntitiesWithLocalChanges(kMaxEntries);
+ tracker->GetEntitiesWithLocalChanges();
ASSERT_THAT(entities_with_local_change.size(), Eq(4U));
// Verify updates are in parent before child order node0 --> node1 --> node2.
@@ -867,38 +864,6 @@ TEST(SyncedBookmarkTrackerTest,
}
TEST(SyncedBookmarkTrackerTest,
- ShouldInvalidateMetadataIfMissingClientTagHashWhileClientInSync) {
- std::unique_ptr<bookmarks::BookmarkModel> model =
- bookmarks::TestBookmarkClient::CreateModel();
-
- const bookmarks::BookmarkNode* bookmark_bar_node = model->bookmark_bar_node();
- const bookmarks::BookmarkNode* node0 = model->AddFolder(
- /*parent=*/bookmark_bar_node, /*index=*/0, u"node0");
-
- sync_pb::BookmarkModelMetadata model_metadata =
- CreateMetadataForPermanentNodes(model.get());
- // Sync happened 23 hours ago, which is considered recent enough.
- model_metadata.set_last_sync_time(
- syncer::TimeToProtoTime(base::Time::Now() - base::Hours(23)));
-
- sync_pb::BookmarkMetadata* node0_metadata =
- model_metadata.add_bookmarks_metadata();
- *node0_metadata = CreateNodeMetadata(node0, /*server_id=*/"id0");
-
- node0_metadata->mutable_metadata()->clear_client_tag_hash();
-
- base::HistogramTester histogram_tester;
- EXPECT_THAT(SyncedBookmarkTracker::CreateFromBookmarkModelAndMetadata(
- model.get(), std::move(model_metadata)),
- IsNull());
-
- histogram_tester.ExpectUniqueSample(
- "Sync.BookmarksModelMetadataCorruptionReason",
- /*sample=*/ExpectedCorruptionReason::MISSING_CLIENT_TAG_HASH,
- /*count=*/1);
-}
-
-TEST(SyncedBookmarkTrackerTest,
ShouldInvalidateMetadataIfMissingClientTagHash) {
std::unique_ptr<bookmarks::BookmarkModel> model =
bookmarks::TestBookmarkClient::CreateModel();
diff --git a/chromium/components/sync_device_info/DEPS b/chromium/components/sync_device_info/DEPS
index e39095dcf42..d016c1f9f98 100644
--- a/chromium/components/sync_device_info/DEPS
+++ b/chromium/components/sync_device_info/DEPS
@@ -7,7 +7,6 @@ include_rules = [
"+components/sync/base",
"+components/sync/invalidations",
"+components/sync/model",
- "+components/sync/engine/entity_data.h",
"+components/sync/protocol",
"+components/sync/test",
"+components/version_info",
diff --git a/chromium/components/sync_device_info/README.md b/chromium/components/sync_device_info/README.md
new file mode 100644
index 00000000000..5cb33a1ca9e
--- /dev/null
+++ b/chromium/components/sync_device_info/README.md
@@ -0,0 +1 @@
+See components/sync/README.md.
diff --git a/chromium/components/sync_device_info/device_count_metrics_provider.cc b/chromium/components/sync_device_info/device_count_metrics_provider.cc
index ae838744a86..64b8246dee8 100644
--- a/chromium/components/sync_device_info/device_count_metrics_provider.cc
+++ b/chromium/components/sync_device_info/device_count_metrics_provider.cc
@@ -37,20 +37,20 @@ void DeviceCountMetricsProvider::ProvideCurrentSessionData(
int desktop_count = 0;
int phone_count = 0;
int tablet_count = 0;
- for (const auto& device_type_and_count : count_by_type) {
- total_devices += device_type_and_count.second;
- switch (device_type_and_count.first) {
+ for (const auto& [device_type, count] : count_by_type) {
+ total_devices += count;
+ switch (device_type) {
case sync_pb::SyncEnums_DeviceType_TYPE_CROS:
case sync_pb::SyncEnums_DeviceType_TYPE_LINUX:
case sync_pb::SyncEnums_DeviceType_TYPE_MAC:
case sync_pb::SyncEnums_DeviceType_TYPE_WIN:
- desktop_count += device_type_and_count.second;
+ desktop_count += count;
break;
case sync_pb::SyncEnums_DeviceType_TYPE_PHONE:
- phone_count += device_type_and_count.second;
+ phone_count += count;
break;
case sync_pb::SyncEnums_DeviceType_TYPE_TABLET:
- tablet_count += device_type_and_count.second;
+ tablet_count += count;
break;
case sync_pb::SyncEnums_DeviceType_TYPE_OTHER:
case sync_pb::SyncEnums_DeviceType_TYPE_UNSET:
diff --git a/chromium/components/sync_device_info/device_info_prefs.cc b/chromium/components/sync_device_info/device_info_prefs.cc
index b1b8f5a2d43..3194c04bb0f 100644
--- a/chromium/components/sync_device_info/device_info_prefs.cc
+++ b/chromium/components/sync_device_info/device_info_prefs.cc
@@ -62,7 +62,8 @@ DeviceInfoPrefs::~DeviceInfoPrefs() = default;
bool DeviceInfoPrefs::IsRecentLocalCacheGuid(
const std::string& cache_guid) const {
base::Value::ConstListView recent_local_cache_guids =
- pref_service_->GetList(kDeviceInfoRecentGUIDsWithTimestamps)->GetList();
+ pref_service_->GetList(kDeviceInfoRecentGUIDsWithTimestamps)
+ ->GetListDeprecated();
for (const auto& v : recent_local_cache_guids) {
if (MatchesGuidInDictionary(v, cache_guid)) {
@@ -77,8 +78,8 @@ void DeviceInfoPrefs::AddLocalCacheGuid(const std::string& cache_guid) {
ListPrefUpdate update_cache_guids(pref_service_,
kDeviceInfoRecentGUIDsWithTimestamps);
- for (auto it = update_cache_guids->GetList().begin();
- it != update_cache_guids->GetList().end(); it++) {
+ for (auto it = update_cache_guids->GetListDeprecated().begin();
+ it != update_cache_guids->GetListDeprecated().end(); it++) {
if (MatchesGuidInDictionary(*it, cache_guid)) {
// Remove it from the list, to be reinserted below, in the first
// position.
@@ -93,11 +94,13 @@ void DeviceInfoPrefs::AddLocalCacheGuid(const std::string& cache_guid) {
kTimestampKey,
base::Value(clock_->Now().ToDeltaSinceWindowsEpoch().InDays()));
- update_cache_guids->Insert(update_cache_guids->GetList().begin(),
+ update_cache_guids->Insert(update_cache_guids->GetListDeprecated().begin(),
std::move(new_entry));
- while (update_cache_guids->GetList().size() > kMaxLocalCacheGuidsStored) {
- update_cache_guids->EraseListIter(update_cache_guids->GetList().end() - 1);
+ while (update_cache_guids->GetListDeprecated().size() >
+ kMaxLocalCacheGuidsStored) {
+ update_cache_guids->EraseListIter(
+ update_cache_guids->GetListDeprecated().end() - 1);
}
}
diff --git a/chromium/components/sync_device_info/device_info_prefs_unittest.cc b/chromium/components/sync_device_info/device_info_prefs_unittest.cc
index 7221ed19e5c..94495b2acbf 100644
--- a/chromium/components/sync_device_info/device_info_prefs_unittest.cc
+++ b/chromium/components/sync_device_info/device_info_prefs_unittest.cc
@@ -58,17 +58,17 @@ TEST_F(DeviceInfoPrefsTest, ShouldCleanUpCorruptEntriesUponGarbageCollection) {
// which is a string instead of a dictionary.
ListPrefUpdate cache_guids_update(&pref_service_,
kDeviceInfoRecentGUIDsWithTimestamps);
- cache_guids_update->Insert(cache_guids_update->GetList().begin(),
+ cache_guids_update->Insert(cache_guids_update->GetListDeprecated().begin(),
base::Value("corrupt_string_entry"));
// Add another corrupt entry: in this case the entry is a dictionary, but it
// contains no timestamp.
- cache_guids_update->Insert(cache_guids_update->GetList().begin(),
+ cache_guids_update->Insert(cache_guids_update->GetListDeprecated().begin(),
base::Value(base::Value::Type::DICTIONARY));
// The end result is the list contains three entries among which one is valid.
ASSERT_EQ(3u, pref_service_.GetList(kDeviceInfoRecentGUIDsWithTimestamps)
- ->GetList()
+ ->GetListDeprecated()
.size());
ASSERT_TRUE(device_info_prefs_.IsRecentLocalCacheGuid("guid1"));
@@ -78,7 +78,7 @@ TEST_F(DeviceInfoPrefsTest, ShouldCleanUpCorruptEntriesUponGarbageCollection) {
// |guid1| should be the only entry in the list.
EXPECT_EQ(1u, pref_service_.GetList(kDeviceInfoRecentGUIDsWithTimestamps)
- ->GetList()
+ ->GetListDeprecated()
.size());
}
diff --git a/chromium/components/sync_device_info/device_info_sync_bridge.cc b/chromium/components/sync_device_info/device_info_sync_bridge.cc
index 8472cd21a14..ca765536574 100644
--- a/chromium/components/sync_device_info/device_info_sync_bridge.cc
+++ b/chromium/components/sync_device_info/device_info_sync_bridge.cc
@@ -493,8 +493,8 @@ void DeviceInfoSyncBridge::GetData(StorageKeyList storage_keys,
void DeviceInfoSyncBridge::GetAllDataForDebugging(DataCallback callback) {
auto batch = std::make_unique<MutableDataBatch>();
- for (const auto& kv : all_data_) {
- batch->Put(kv.first, CopyToEntityData(*kv.second));
+ for (const auto& [cache_guid, specifics] : all_data_) {
+ batch->Put(cache_guid, CopyToEntityData(*specifics));
}
std::move(callback).Run(std::move(batch));
}
@@ -556,9 +556,9 @@ std::unique_ptr<DeviceInfo> DeviceInfoSyncBridge::GetDeviceInfo(
std::vector<std::unique_ptr<DeviceInfo>>
DeviceInfoSyncBridge::GetAllDeviceInfo() const {
std::vector<std::unique_ptr<DeviceInfo>> list;
- for (const auto& id_and_specifics : all_data_) {
- if (IsChromeClient(*id_and_specifics.second)) {
- list.push_back(SpecificsToModel(*id_and_specifics.second));
+ for (const auto& [cache_guid, specifics] : all_data_) {
+ if (IsChromeClient(*specifics)) {
+ list.push_back(SpecificsToModel(*specifics));
}
}
return list;
@@ -856,36 +856,36 @@ DeviceInfoSyncBridge::CountActiveDevicesByType() const {
std::map<sync_pb::SyncEnums_DeviceType, std::multimap<base::Time, int>>
relevant_events;
- for (const auto& pair : all_data_) {
- if (!IsChromeClient(*pair.second)) {
+ for (const auto& [cache_guid, specifics] : all_data_) {
+ if (!IsChromeClient(*specifics)) {
continue;
}
- if (DeviceInfoUtil::IsActive(GetLastUpdateTime(*pair.second), now)) {
- base::Time begin = change_processor()->GetEntityCreationTime(pair.first);
+ if (DeviceInfoUtil::IsActive(GetLastUpdateTime(*specifics), now)) {
+ base::Time begin = change_processor()->GetEntityCreationTime(cache_guid);
base::Time end =
- change_processor()->GetEntityModificationTime(pair.first);
+ change_processor()->GetEntityModificationTime(cache_guid);
// Begin/end timestamps are received from other devices without local
// sanitizing, so potentially the timestamps could be malformed, and the
// modification time may predate the creation time.
if (begin > end) {
continue;
}
- relevant_events[pair.second->device_type()].emplace(begin, 1);
- relevant_events[pair.second->device_type()].emplace(end, -1);
+ relevant_events[specifics->device_type()].emplace(begin, 1);
+ relevant_events[specifics->device_type()].emplace(end, -1);
}
}
std::map<sync_pb::SyncEnums_DeviceType, int> device_count_by_type;
- for (const auto& type_and_events : relevant_events) {
+ for (const auto& [type, events] : relevant_events) {
int max_overlapping = 0;
int overlapping = 0;
- for (const auto& event : type_and_events.second) {
- overlapping += event.second;
+ for (const auto& [time, value] : events) {
+ overlapping += value;
DCHECK_LE(0, overlapping);
max_overlapping = std::max(max_overlapping, overlapping);
}
- device_count_by_type[type_and_events.first] = max_overlapping;
+ device_count_by_type[type] = max_overlapping;
DCHECK_EQ(overlapping, 0);
}
@@ -898,10 +898,9 @@ void DeviceInfoSyncBridge::ExpireOldEntries() {
std::unordered_set<std::string> cache_guids_to_expire;
// Just collecting cache guids to expire to avoid modifying |all_data_| via
// DeleteSpecifics() while iterating over it.
- for (const auto& pair : all_data_) {
- const std::string& cache_guid = pair.first;
+ for (const auto& [cache_guid, specifics] : all_data_) {
if (cache_guid != local_cache_guid_ &&
- GetLastUpdateTime(*pair.second) < expiration_threshold) {
+ GetLastUpdateTime(*specifics) < expiration_threshold) {
cache_guids_to_expire.insert(cache_guid);
}
}
diff --git a/chromium/components/sync_device_info/device_info_sync_bridge_unittest.cc b/chromium/components/sync_device_info/device_info_sync_bridge_unittest.cc
index 38e1f3ec1d6..2aab71c14c5 100644
--- a/chromium/components/sync_device_info/device_info_sync_bridge_unittest.cc
+++ b/chromium/components/sync_device_info/device_info_sync_bridge_unittest.cc
@@ -23,12 +23,12 @@
#include "components/prefs/testing_pref_service.h"
#include "components/sync/base/model_type.h"
#include "components/sync/base/time.h"
-#include "components/sync/engine/entity_data.h"
#include "components/sync/model/data_batch.h"
#include "components/sync/model/data_type_activation_request.h"
#include "components/sync/model/entity_change.h"
#include "components/sync/model/metadata_batch.h"
#include "components/sync/protocol/device_info_specifics.pb.h"
+#include "components/sync/protocol/entity_data.h"
#include "components/sync/protocol/entity_specifics.pb.h"
#include "components/sync/protocol/model_type_state.pb.h"
#include "components/sync/protocol/sync_enums.pb.h"
@@ -343,8 +343,8 @@ std::map<std::string, sync_pb::EntitySpecifics> DataBatchToSpecificsMap(
std::unique_ptr<DataBatch> batch) {
std::map<std::string, sync_pb::EntitySpecifics> storage_key_to_specifics;
while (batch && batch->HasNext()) {
- const syncer::KeyAndData& pair = batch->Next();
- storage_key_to_specifics[pair.first] = pair.second->specifics;
+ auto [key, data] = batch->Next();
+ storage_key_to_specifics[key] = data->specifics;
}
return storage_key_to_specifics;
}
diff --git a/chromium/components/sync_device_info/fake_device_info_tracker.cc b/chromium/components/sync_device_info/fake_device_info_tracker.cc
index d4e89ac78b5..2ac833439fa 100644
--- a/chromium/components/sync_device_info/fake_device_info_tracker.cc
+++ b/chromium/components/sync_device_info/fake_device_info_tracker.cc
@@ -4,11 +4,11 @@
#include "components/sync_device_info/fake_device_info_tracker.h"
-#include <algorithm>
#include <map>
#include "base/check.h"
#include "base/notreached.h"
+#include "base/ranges/algorithm.h"
#include "components/sync/protocol/sync_enums.pb.h"
#include "components/sync_device_info/device_info.h"
@@ -99,7 +99,7 @@ void FakeDeviceInfoTracker::Add(const DeviceInfo* device) {
void FakeDeviceInfoTracker::Replace(const DeviceInfo* old_device,
const DeviceInfo* new_device) {
std::vector<const DeviceInfo*>::iterator it =
- std::find(devices_.begin(), devices_.end(), old_device);
+ base::ranges::find(devices_, old_device);
DCHECK(devices_.end() != it) << "Tracker doesn't contain device";
*it = new_device;
for (auto& observer : observers_)
diff --git a/chromium/components/sync_device_info/local_device_info_provider.h b/chromium/components/sync_device_info/local_device_info_provider.h
index 6384ba8b40b..95b689048d7 100644
--- a/chromium/components/sync_device_info/local_device_info_provider.h
+++ b/chromium/components/sync_device_info/local_device_info_provider.h
@@ -33,8 +33,8 @@ class LocalDeviceInfoProvider {
// Registers a callback to be called when local device info becomes available.
// The callback will remain registered until the returned subscription is
// destroyed, which must occur before the CallbackList is destroyed.
- virtual base::CallbackListSubscription RegisterOnInitializedCallback(
- const base::RepeatingClosure& callback) WARN_UNUSED_RESULT = 0;
+ [[nodiscard]] virtual base::CallbackListSubscription
+ RegisterOnInitializedCallback(const base::RepeatingClosure& callback) = 0;
};
class MutableLocalDeviceInfoProvider : public LocalDeviceInfoProvider {
diff --git a/chromium/components/sync_device_info/local_device_info_util.cc b/chromium/components/sync_device_info/local_device_info_util.cc
index 90fa4a5716b..38eabb5e429 100644
--- a/chromium/components/sync_device_info/local_device_info_util.cc
+++ b/chromium/components/sync_device_info/local_device_info_util.cc
@@ -75,15 +75,15 @@ std::string GetPersonalizableDeviceNameInternal();
sync_pb::SyncEnums::DeviceType GetLocalDeviceType() {
#if BUILDFLAG(IS_CHROMEOS_ASH)
return sync_pb::SyncEnums_DeviceType_TYPE_CROS;
-#elif defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
+#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
return sync_pb::SyncEnums_DeviceType_TYPE_LINUX;
-#elif defined(OS_ANDROID) || defined(OS_IOS)
+#elif BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
return ui::GetDeviceFormFactor() == ui::DEVICE_FORM_FACTOR_TABLET
? sync_pb::SyncEnums_DeviceType_TYPE_TABLET
: sync_pb::SyncEnums_DeviceType_TYPE_PHONE;
-#elif defined(OS_MAC)
+#elif BUILDFLAG(IS_MAC)
return sync_pb::SyncEnums_DeviceType_TYPE_MAC;
-#elif defined(OS_WIN)
+#elif BUILDFLAG(IS_WIN)
return sync_pb::SyncEnums_DeviceType_TYPE_WIN;
#else
return sync_pb::SyncEnums_DeviceType_TYPE_OTHER;
diff --git a/chromium/components/sync_preferences/README.md b/chromium/components/sync_preferences/README.md
new file mode 100644
index 00000000000..5cb33a1ca9e
--- /dev/null
+++ b/chromium/components/sync_preferences/README.md
@@ -0,0 +1 @@
+See components/sync/README.md.
diff --git a/chromium/components/sync_preferences/pref_model_associator.cc b/chromium/components/sync_preferences/pref_model_associator.cc
index c82a0b03ad5..12149a93db1 100644
--- a/chromium/components/sync_preferences/pref_model_associator.cc
+++ b/chromium/components/sync_preferences/pref_model_associator.cc
@@ -127,23 +127,23 @@ void PrefModelAssociator::InitPrefAndAssociate(
if (user_pref_value) {
DVLOG(1) << "Found user pref value for " << pref_name;
// We have both server and local values. Merge them.
- std::unique_ptr<base::Value> new_value(
+ base::Value new_value(
MergePreference(pref_name, *user_pref_value, *sync_value));
// Update the local preference based on what we got from the
// sync server. Note: this only updates the user value store, which is
// ignored if the preference is policy controlled.
- if (new_value->is_none()) {
+ if (new_value.is_none()) {
LOG(WARNING) << "Sync has null value for pref " << pref_name.c_str();
pref_service_->ClearPref(pref_name);
- } else if (*user_pref_value != *new_value) {
- SetPrefWithTypeCheck(pref_name, *new_value);
+ } else if (*user_pref_value != new_value) {
+ SetPrefWithTypeCheck(pref_name, new_value);
}
// If the merge resulted in an updated value, inform the syncer.
- if (*sync_value != *new_value) {
+ if (*sync_value != new_value) {
syncer::SyncData sync_data;
- if (!CreatePrefSyncData(pref_name, *new_value, &sync_data)) {
+ if (!CreatePrefSyncData(pref_name, new_value, &sync_data)) {
LOG(ERROR) << "Failed to update preference.";
return;
}
@@ -259,7 +259,7 @@ void PrefModelAssociator::StopSyncing(syncer::ModelType type) {
pref_service_->OnIsSyncingChanged();
}
-std::unique_ptr<base::Value> PrefModelAssociator::MergePreference(
+base::Value PrefModelAssociator::MergePreference(
const std::string& name,
const base::Value& local_value,
const base::Value& server_value) {
@@ -268,19 +268,17 @@ std::unique_ptr<base::Value> PrefModelAssociator::MergePreference(
if (client_) {
std::string new_pref_name;
if (client_->IsMergeableListPreference(name))
- return MergeListValues(local_value, server_value);
- if (client_->IsMergeableDictionaryPreference(name)) {
- return std::make_unique<base::Value>(
- MergeDictionaryValues(local_value, server_value));
- }
- std::unique_ptr<base::Value> merged_value =
+ return std::move(*MergeListValues(local_value, server_value));
+ if (client_->IsMergeableDictionaryPreference(name))
+ return MergeDictionaryValues(local_value, server_value);
+ base::Value merged_value =
client_->MaybeMergePreferenceValues(name, local_value, server_value);
- if (merged_value)
+ if (!merged_value.is_none())
return merged_value;
}
// If this is not a specially handled preference, server wins.
- return base::Value::ToUniquePtrValue(server_value.Clone());
+ return server_value.Clone();
}
bool PrefModelAssociator::CreatePrefSyncData(
@@ -323,8 +321,8 @@ std::unique_ptr<base::Value> PrefModelAssociator::MergeListValues(
DCHECK(to_value.type() == base::Value::Type::LIST);
base::Value result = to_value.Clone();
- for (const auto& value : from_value.GetList()) {
- if (!base::Contains(result.GetList(), value))
+ for (const auto& value : from_value.GetListDeprecated()) {
+ if (!base::Contains(result.GetListDeprecated(), value))
result.Append(value.Clone());
}
@@ -344,6 +342,8 @@ base::Value PrefModelAssociator::MergeDictionaryValues(
base::Value result = to_value.Clone();
for (auto it : from_value.DictItems()) {
+ // It's not clear whether using a C++17 structured binding here would cause
+ // a copy of the value or not, so in doubt unpack the old way.
const base::Value* from_key_value = &it.second;
base::Value* to_key_value = result.FindKey(it.first);
if (to_key_value) {
diff --git a/chromium/components/sync_preferences/pref_model_associator.h b/chromium/components/sync_preferences/pref_model_associator.h
index 9672375527d..71c8e4e4924 100644
--- a/chromium/components/sync_preferences/pref_model_associator.h
+++ b/chromium/components/sync_preferences/pref_model_associator.h
@@ -99,9 +99,9 @@ class PrefModelAssociator : public syncer::SyncableService {
// value always takes precedence. Note that only certain preferences will
// actually be merged, all others will return a copy of the server value. See
// the method's implementation for details.
- std::unique_ptr<base::Value> MergePreference(const std::string& name,
- const base::Value& local_value,
- const base::Value& server_value);
+ base::Value MergePreference(const std::string& name,
+ const base::Value& local_value,
+ const base::Value& server_value);
// Fills |sync_data| with a sync representation of the preference data
// provided.
diff --git a/chromium/components/sync_preferences/pref_model_associator_client.h b/chromium/components/sync_preferences/pref_model_associator_client.h
index c2be51dacc3..74856736eeb 100644
--- a/chromium/components/sync_preferences/pref_model_associator_client.h
+++ b/chromium/components/sync_preferences/pref_model_associator_client.h
@@ -34,7 +34,7 @@ class PrefModelAssociatorClient {
// strategy to the preference named |pref_name| with local value |local_value|
// and server-provided value |server_value|. Otherwise, returns |nullptr| and
// the server's value will be chosen.
- virtual std::unique_ptr<base::Value> MaybeMergePreferenceValues(
+ virtual base::Value MaybeMergePreferenceValues(
const std::string& pref_name,
const base::Value& local_value,
const base::Value& server_value) const = 0;
diff --git a/chromium/components/sync_preferences/pref_model_associator_unittest.cc b/chromium/components/sync_preferences/pref_model_associator_unittest.cc
index 8cd6e6992a2..f66146d2f1c 100644
--- a/chromium/components/sync_preferences/pref_model_associator_unittest.cc
+++ b/chromium/components/sync_preferences/pref_model_associator_unittest.cc
@@ -46,14 +46,13 @@ class TestPrefModelAssociatorClient : public PrefModelAssociatorClient {
return pref_name == kDictionaryPrefName;
}
- std::unique_ptr<base::Value> MaybeMergePreferenceValues(
+ base::Value MaybeMergePreferenceValues(
const std::string& pref_name,
const base::Value& local_value,
const base::Value& server_value) const override {
- if (pref_name == kCustomMergePrefName) {
- return base::WrapUnique(local_value.DeepCopy());
- }
- return nullptr;
+ if (pref_name == kCustomMergePrefName)
+ return local_value.Clone();
+ return base::Value();
}
};
@@ -120,14 +119,13 @@ TEST_F(CustomPreferenceMergeTest, ClientMergesCustomPreference) {
pref_service_->SetString(kCustomMergePrefName, "local");
const PrefService::Preference* pref =
pref_service_->FindPreference(kCustomMergePrefName);
- std::unique_ptr<base::Value> local_value =
- base::WrapUnique(pref->GetValue()->DeepCopy());
- std::unique_ptr<base::Value> server_value(new base::Value("server"));
- std::unique_ptr<base::Value> merged_value(pref_sync_service_->MergePreference(
- pref->name(), *pref->GetValue(), *server_value));
+ base::Value local_value(pref->GetValue()->Clone());
+ base::Value server_value("server");
+ base::Value merged_value(pref_sync_service_->MergePreference(
+ pref->name(), *pref->GetValue(), server_value));
// TestPrefModelAssociatorClient should have chosen local value instead of the
// default server value.
- EXPECT_TRUE(merged_value->Equals(local_value.get()));
+ EXPECT_EQ(merged_value, local_value);
}
class ListPreferenceMergeTest : public AbstractPreferenceMergeTest {
@@ -152,66 +150,64 @@ TEST_F(ListPreferenceMergeTest, NotListOrDictionary) {
pref_service_->SetString(kStringPrefName, local_url0_);
const PrefService::Preference* pref =
pref_service_->FindPreference(kStringPrefName);
- std::unique_ptr<base::Value> server_value(new base::Value(server_url0_));
- std::unique_ptr<base::Value> merged_value(pref_sync_service_->MergePreference(
- pref->name(), *pref->GetValue(), *server_value));
- EXPECT_TRUE(merged_value->Equals(server_value.get()));
+ base::Value server_value(server_url0_);
+ base::Value merged_value(pref_sync_service_->MergePreference(
+ pref->name(), *pref->GetValue(), server_value));
+ EXPECT_EQ(merged_value, server_value);
}
TEST_F(ListPreferenceMergeTest, LocalEmpty) {
SetPrefToEmpty(kListPrefName);
const PrefService::Preference* pref =
pref_service_->FindPreference(kListPrefName);
- std::unique_ptr<base::Value> merged_value(pref_sync_service_->MergePreference(
+ base::Value merged_value(pref_sync_service_->MergePreference(
pref->name(), *pref->GetValue(), server_url_list_));
- EXPECT_TRUE(merged_value->Equals(&server_url_list_));
+ EXPECT_EQ(merged_value, server_url_list_);
}
TEST_F(ListPreferenceMergeTest, ServerNull) {
auto null_value = std::make_unique<base::Value>();
{
ListPrefUpdate update(pref_service_.get(), kListPrefName);
- base::ListValue* local_list_value = update.Get();
+ base::Value* local_list_value = update.Get();
local_list_value->Append(local_url0_);
}
const PrefService::Preference* pref =
pref_service_->FindPreference(kListPrefName);
- std::unique_ptr<base::Value> merged_value(pref_sync_service_->MergePreference(
+ base::Value merged_value(pref_sync_service_->MergePreference(
pref->name(), *pref->GetValue(), *null_value));
- const base::ListValue* local_list_value =
- pref_service_->GetList(kListPrefName);
- EXPECT_TRUE(merged_value->Equals(local_list_value));
+ const base::Value* local_list_value = pref_service_->GetList(kListPrefName);
+ EXPECT_EQ(merged_value, *local_list_value);
}
TEST_F(ListPreferenceMergeTest, ServerEmpty) {
std::unique_ptr<base::Value> empty_value(new base::ListValue);
{
ListPrefUpdate update(pref_service_.get(), kListPrefName);
- base::ListValue* local_list_value = update.Get();
+ base::Value* local_list_value = update.Get();
local_list_value->Append(local_url0_);
}
const PrefService::Preference* pref =
pref_service_->FindPreference(kListPrefName);
- std::unique_ptr<base::Value> merged_value(pref_sync_service_->MergePreference(
+ base::Value merged_value(pref_sync_service_->MergePreference(
pref->name(), *pref->GetValue(), *empty_value));
- const base::ListValue* local_list_value =
- pref_service_->GetList(kListPrefName);
- EXPECT_TRUE(merged_value->Equals(local_list_value));
+ const base::Value* local_list_value = pref_service_->GetList(kListPrefName);
+ EXPECT_EQ(merged_value, *local_list_value);
}
TEST_F(ListPreferenceMergeTest, Merge) {
{
ListPrefUpdate update(pref_service_.get(), kListPrefName);
- base::ListValue* local_list_value = update.Get();
+ base::Value* local_list_value = update.Get();
local_list_value->Append(local_url0_);
local_list_value->Append(local_url1_);
}
const PrefService::Preference* pref =
pref_service_->FindPreference(kListPrefName);
- std::unique_ptr<base::Value> merged_value(pref_sync_service_->MergePreference(
+ base::Value merged_value(pref_sync_service_->MergePreference(
pref->name(), *pref->GetValue(), server_url_list_));
base::ListValue expected;
@@ -219,13 +215,13 @@ TEST_F(ListPreferenceMergeTest, Merge) {
expected.Append(server_url1_);
expected.Append(local_url0_);
expected.Append(local_url1_);
- EXPECT_TRUE(merged_value->Equals(&expected));
+ EXPECT_EQ(merged_value, expected);
}
TEST_F(ListPreferenceMergeTest, Duplicates) {
{
ListPrefUpdate update(pref_service_.get(), kListPrefName);
- base::ListValue* local_list_value = update.Get();
+ base::Value* local_list_value = update.Get();
local_list_value->Append(local_url0_);
local_list_value->Append(server_url0_);
local_list_value->Append(server_url1_);
@@ -233,20 +229,20 @@ TEST_F(ListPreferenceMergeTest, Duplicates) {
const PrefService::Preference* pref =
pref_service_->FindPreference(kListPrefName);
- std::unique_ptr<base::Value> merged_value(pref_sync_service_->MergePreference(
+ base::Value merged_value(pref_sync_service_->MergePreference(
pref->name(), *pref->GetValue(), server_url_list_));
base::ListValue expected;
expected.Append(server_url0_);
expected.Append(server_url1_);
expected.Append(local_url0_);
- EXPECT_TRUE(merged_value->Equals(&expected));
+ EXPECT_EQ(merged_value, expected);
}
TEST_F(ListPreferenceMergeTest, Equals) {
{
ListPrefUpdate update(pref_service_.get(), kListPrefName);
- base::ListValue* local_list_value = update.Get();
+ base::Value* local_list_value = update.Get();
local_list_value->Append(server_url0_);
local_list_value->Append(server_url1_);
}
@@ -254,9 +250,9 @@ TEST_F(ListPreferenceMergeTest, Equals) {
base::Value original = server_url_list_.Clone();
const PrefService::Preference* pref =
pref_service_->FindPreference(kListPrefName);
- std::unique_ptr<base::Value> merged_value(pref_sync_service_->MergePreference(
+ base::Value merged_value(pref_sync_service_->MergePreference(
pref->name(), *pref->GetValue(), server_url_list_));
- EXPECT_TRUE(*merged_value == original);
+ EXPECT_EQ(merged_value, original);
}
class DictionaryPreferenceMergeTest : public AbstractPreferenceMergeTest {
@@ -284,53 +280,53 @@ TEST_F(DictionaryPreferenceMergeTest, LocalEmpty) {
SetPrefToEmpty(kDictionaryPrefName);
const PrefService::Preference* pref =
pref_service_->FindPreference(kDictionaryPrefName);
- std::unique_ptr<base::Value> merged_value(pref_sync_service_->MergePreference(
+ base::Value merged_value(pref_sync_service_->MergePreference(
pref->name(), *pref->GetValue(), server_patterns_));
- EXPECT_TRUE(merged_value->Equals(&server_patterns_));
+ EXPECT_EQ(merged_value, server_patterns_);
}
TEST_F(DictionaryPreferenceMergeTest, ServerNull) {
auto null_value = std::make_unique<base::Value>();
{
DictionaryPrefUpdate update(pref_service_.get(), kDictionaryPrefName);
- base::DictionaryValue* local_dict_value = update.Get();
+ base::Value* local_dict_value = update.Get();
SetContentPattern(local_dict_value, expression3_, 1);
}
const PrefService::Preference* pref =
pref_service_->FindPreference(kDictionaryPrefName);
- std::unique_ptr<base::Value> merged_value(pref_sync_service_->MergePreference(
+ base::Value merged_value(pref_sync_service_->MergePreference(
pref->name(), *pref->GetValue(), *null_value));
- const base::DictionaryValue* local_dict_value =
+ const base::Value* local_dict_value =
pref_service_->GetDictionary(kDictionaryPrefName);
- EXPECT_TRUE(merged_value->Equals(local_dict_value));
+ EXPECT_EQ(merged_value, *local_dict_value);
}
TEST_F(DictionaryPreferenceMergeTest, ServerEmpty) {
std::unique_ptr<base::Value> empty_value(new base::DictionaryValue);
{
DictionaryPrefUpdate update(pref_service_.get(), kDictionaryPrefName);
- base::DictionaryValue* local_dict_value = update.Get();
+ base::Value* local_dict_value = update.Get();
SetContentPattern(local_dict_value, expression3_, 1);
}
const PrefService::Preference* pref =
pref_service_->FindPreference(kDictionaryPrefName);
- std::unique_ptr<base::Value> merged_value(pref_sync_service_->MergePreference(
+ base::Value merged_value(pref_sync_service_->MergePreference(
pref->name(), *pref->GetValue(), *empty_value));
- const base::DictionaryValue* local_dict_value =
+ const base::Value* local_dict_value =
pref_service_->GetDictionary(kDictionaryPrefName);
- EXPECT_TRUE(merged_value->Equals(local_dict_value));
+ EXPECT_EQ(merged_value, *local_dict_value);
}
TEST_F(DictionaryPreferenceMergeTest, MergeNoConflicts) {
{
DictionaryPrefUpdate update(pref_service_.get(), kDictionaryPrefName);
- base::DictionaryValue* local_dict_value = update.Get();
+ base::Value* local_dict_value = update.Get();
SetContentPattern(local_dict_value, expression3_, 1);
}
- std::unique_ptr<base::Value> merged_value(pref_sync_service_->MergePreference(
+ base::Value merged_value(pref_sync_service_->MergePreference(
kDictionaryPrefName,
*pref_service_->FindPreference(kDictionaryPrefName)->GetValue(),
server_patterns_));
@@ -340,20 +336,20 @@ TEST_F(DictionaryPreferenceMergeTest, MergeNoConflicts) {
SetContentPattern(&expected, expression1_, 2);
SetContentPattern(&expected, expression2_, 1);
SetContentPattern(&expected, expression3_, 1);
- EXPECT_TRUE(merged_value->Equals(&expected));
+ EXPECT_EQ(merged_value, expected);
}
TEST_F(DictionaryPreferenceMergeTest, MergeConflicts) {
{
DictionaryPrefUpdate update(pref_service_.get(), kDictionaryPrefName);
- base::DictionaryValue* local_dict_value = update.Get();
+ base::Value* local_dict_value = update.Get();
SetContentPattern(local_dict_value, expression0_, 2);
SetContentPattern(local_dict_value, expression2_, 1);
SetContentPattern(local_dict_value, expression3_, 1);
SetContentPattern(local_dict_value, expression4_, 2);
}
- std::unique_ptr<base::Value> merged_value(pref_sync_service_->MergePreference(
+ base::Value merged_value(pref_sync_service_->MergePreference(
kDictionaryPrefName,
*pref_service_->FindPreference(kDictionaryPrefName)->GetValue(),
server_patterns_));
@@ -364,7 +360,7 @@ TEST_F(DictionaryPreferenceMergeTest, MergeConflicts) {
SetContentPattern(&expected, expression2_, 1);
SetContentPattern(&expected, expression3_, 1);
SetContentPattern(&expected, expression4_, 2);
- EXPECT_TRUE(merged_value->Equals(&expected));
+ EXPECT_EQ(merged_value, expected);
}
TEST_F(DictionaryPreferenceMergeTest, MergeValueToDictionary) {
@@ -374,42 +370,42 @@ TEST_F(DictionaryPreferenceMergeTest, MergeValueToDictionary) {
base::DictionaryValue server_dict_value;
server_dict_value.SetInteger("key.subkey", 0);
- std::unique_ptr<base::Value> merged_value(pref_sync_service_->MergePreference(
+ base::Value merged_value(pref_sync_service_->MergePreference(
kDictionaryPrefName, local_dict_value, server_dict_value));
- EXPECT_TRUE(merged_value->Equals(&server_dict_value));
+ EXPECT_EQ(merged_value, server_dict_value);
}
TEST_F(DictionaryPreferenceMergeTest, Equal) {
{
DictionaryPrefUpdate update(pref_service_.get(), kDictionaryPrefName);
- base::DictionaryValue* local_dict_value = update.Get();
+ base::Value* local_dict_value = update.Get();
SetContentPattern(local_dict_value, expression0_, 1);
SetContentPattern(local_dict_value, expression1_, 2);
SetContentPattern(local_dict_value, expression2_, 1);
}
- std::unique_ptr<base::Value> merged_value(pref_sync_service_->MergePreference(
+ base::Value merged_value(pref_sync_service_->MergePreference(
kDictionaryPrefName,
*pref_service_->FindPreference(kDictionaryPrefName)->GetValue(),
server_patterns_));
- EXPECT_TRUE(merged_value->Equals(&server_patterns_));
+ EXPECT_EQ(merged_value, server_patterns_);
}
TEST_F(DictionaryPreferenceMergeTest, ConflictButServerWins) {
{
DictionaryPrefUpdate update(pref_service_.get(), kDictionaryPrefName);
- base::DictionaryValue* local_dict_value = update.Get();
+ base::Value* local_dict_value = update.Get();
SetContentPattern(local_dict_value, expression0_, 2);
SetContentPattern(local_dict_value, expression1_, 2);
SetContentPattern(local_dict_value, expression2_, 1);
}
- std::unique_ptr<base::Value> merged_value(pref_sync_service_->MergePreference(
+ base::Value merged_value(pref_sync_service_->MergePreference(
kDictionaryPrefName,
*pref_service_->FindPreference(kDictionaryPrefName)->GetValue(),
server_patterns_));
- EXPECT_TRUE(merged_value->Equals(&server_patterns_));
+ EXPECT_EQ(merged_value, server_patterns_);
}
class IndividualPreferenceMergeTest : public AbstractPreferenceMergeTest {
@@ -426,35 +422,33 @@ class IndividualPreferenceMergeTest : public AbstractPreferenceMergeTest {
bool MergeListPreference(const char* pref) {
{
ListPrefUpdate update(pref_service_.get(), pref);
- base::ListValue* local_list_value = update.Get();
+ base::Value* local_list_value = update.Get();
local_list_value->Append(url1_);
}
- std::unique_ptr<base::Value> merged_value(
- pref_sync_service_->MergePreference(
- pref, *pref_service_->GetUserPrefValue(pref), server_url_list_));
+ base::Value merged_value(pref_sync_service_->MergePreference(
+ pref, *pref_service_->GetUserPrefValue(pref), server_url_list_));
base::ListValue expected;
expected.Append(url0_);
expected.Append(url1_);
- return merged_value->Equals(&expected);
+ return merged_value == expected;
}
bool MergeDictionaryPreference(const char* pref) {
{
DictionaryPrefUpdate update(pref_service_.get(), pref);
- base::DictionaryValue* local_dict_value = update.Get();
+ base::Value* local_dict_value = update.Get();
SetContentPattern(local_dict_value, expression1_, 1);
}
- std::unique_ptr<base::Value> merged_value(
- pref_sync_service_->MergePreference(
- pref, *pref_service_->GetUserPrefValue(pref), server_patterns_));
+ base::Value merged_value(pref_sync_service_->MergePreference(
+ pref, *pref_service_->GetUserPrefValue(pref), server_patterns_));
base::DictionaryValue expected;
SetContentPattern(&expected, expression0_, 1);
SetContentPattern(&expected, expression1_, 1);
- return merged_value->Equals(&expected);
+ return merged_value == expected;
}
std::string url0_;
diff --git a/chromium/components/sync_preferences/pref_service_syncable.cc b/chromium/components/sync_preferences/pref_service_syncable.cc
index 3db63fd9d35..c41aed974fa 100644
--- a/chromium/components/sync_preferences/pref_service_syncable.cc
+++ b/chromium/components/sync_preferences/pref_service_syncable.cc
@@ -36,6 +36,7 @@ PrefServiceSyncable::PrefServiceSyncable(
std::unique_ptr<PrefNotifierImpl> pref_notifier,
std::unique_ptr<PrefValueStore> pref_value_store,
scoped_refptr<PersistentPrefStore> user_prefs,
+ scoped_refptr<PersistentPrefStore> standalone_browser_prefs,
scoped_refptr<user_prefs::PrefRegistrySyncable> pref_registry,
const PrefModelAssociatorClient* pref_model_associator_client,
base::RepeatingCallback<void(PersistentPrefStore::PrefReadError)>
@@ -44,6 +45,7 @@ PrefServiceSyncable::PrefServiceSyncable(
: PrefService(std::move(pref_notifier),
std::move(pref_value_store),
user_prefs,
+ standalone_browser_prefs,
pref_registry,
std::move(read_error_callback),
async),
@@ -75,8 +77,7 @@ PrefServiceSyncable::PrefServiceSyncable(
&PrefServiceSyncable::ProcessPrefChange, base::Unretained(this)));
// Add already-registered syncable preferences to PrefModelAssociator.
- for (const auto& entry : *pref_registry_) {
- const std::string& path = entry.first;
+ for (const auto& [path, value] : *pref_registry_) {
AddRegisteredSyncablePreference(path,
pref_registry_->GetRegistrationFlags(path));
}
@@ -114,6 +115,7 @@ PrefServiceSyncable::CreateIncognitoPrefService(
nullptr, // managed
nullptr, // supervised_user
incognito_extension_pref_store,
+ nullptr, // standalone_browser_prefs
nullptr, // command_line_prefs
incognito_pref_store.get(),
nullptr, // recommended
@@ -121,8 +123,10 @@ PrefServiceSyncable::CreateIncognitoPrefService(
/*delegate=*/nullptr);
return std::make_unique<PrefServiceSyncable>(
std::move(pref_notifier), std::move(pref_value_store),
- std::move(incognito_pref_store), std::move(forked_registry),
- pref_sync_associator_.client(), read_error_callback_, false);
+ std::move(incognito_pref_store),
+ nullptr, // standalone_browser_prefs
+ std::move(forked_registry), pref_sync_associator_.client(),
+ read_error_callback_, false);
}
bool PrefServiceSyncable::IsSyncing() {
diff --git a/chromium/components/sync_preferences/pref_service_syncable.h b/chromium/components/sync_preferences/pref_service_syncable.h
index d545d4d7e46..3654f0e42eb 100644
--- a/chromium/components/sync_preferences/pref_service_syncable.h
+++ b/chromium/components/sync_preferences/pref_service_syncable.h
@@ -41,6 +41,7 @@ class PrefServiceSyncable : public PrefService {
std::unique_ptr<PrefNotifierImpl> pref_notifier,
std::unique_ptr<PrefValueStore> pref_value_store,
scoped_refptr<PersistentPrefStore> user_prefs,
+ scoped_refptr<PersistentPrefStore> standalone_browser_prefs,
scoped_refptr<user_prefs::PrefRegistrySyncable> pref_registry,
const PrefModelAssociatorClient* pref_model_associator_client,
base::RepeatingCallback<void(PersistentPrefStore::PrefReadError)>
diff --git a/chromium/components/sync_preferences/pref_service_syncable_factory.cc b/chromium/components/sync_preferences/pref_service_syncable_factory.cc
index 9f7b4f0117d..a83dd9445ae 100644
--- a/chromium/components/sync_preferences/pref_service_syncable_factory.cc
+++ b/chromium/components/sync_preferences/pref_service_syncable_factory.cc
@@ -51,13 +51,14 @@ std::unique_ptr<PrefServiceSyncable> PrefServiceSyncableFactory::CreateSyncable(
auto pref_notifier = std::make_unique<PrefNotifierImpl>();
auto pref_value_store = std::make_unique<PrefValueStore>(
managed_prefs_.get(), supervised_user_prefs_.get(),
- extension_prefs_.get(), command_line_prefs_.get(), user_prefs_.get(),
- recommended_prefs_.get(), pref_registry->defaults().get(),
- pref_notifier.get(), /*delegate=*/nullptr);
+ extension_prefs_.get(), standalone_browser_prefs_.get(),
+ command_line_prefs_.get(), user_prefs_.get(), recommended_prefs_.get(),
+ pref_registry->defaults().get(), pref_notifier.get(),
+ /*delegate=*/nullptr);
return std::make_unique<PrefServiceSyncable>(
std::move(pref_notifier), std::move(pref_value_store), user_prefs_.get(),
- std::move(pref_registry), pref_model_associator_client_,
- read_error_callback_, async_);
+ standalone_browser_prefs_.get(), std::move(pref_registry),
+ pref_model_associator_client_, read_error_callback_, async_);
}
} // namespace sync_preferences
diff --git a/chromium/components/sync_preferences/pref_service_syncable_unittest.cc b/chromium/components/sync_preferences/pref_service_syncable_unittest.cc
index 02a82d7b886..b52c76a6967 100644
--- a/chromium/components/sync_preferences/pref_service_syncable_unittest.cc
+++ b/chromium/components/sync_preferences/pref_service_syncable_unittest.cc
@@ -282,7 +282,7 @@ TEST_F(PrefServiceSyncableTest, CreatePrefSyncData) {
std::unique_ptr<base::Value> value =
base::JSONReader::ReadDeprecated(specifics.value());
- EXPECT_TRUE(pref->GetValue()->Equals(value.get()));
+ EXPECT_EQ(*pref->GetValue(), *value);
}
TEST_F(PrefServiceSyncableTest, ModelAssociationDoNotSyncDefaults) {
@@ -300,7 +300,7 @@ TEST_F(PrefServiceSyncableTest, ModelAssociationEmptyCloud) {
prefs_.SetString(kStringPrefName, kExampleUrl0);
{
ListPrefUpdate update(GetPrefs(), kListPrefName);
- base::ListValue* url_list = update.Get();
+ base::Value* url_list = update.Get();
url_list->Append(kExampleUrl0);
url_list->Append(kExampleUrl1);
}
@@ -309,17 +309,17 @@ TEST_F(PrefServiceSyncableTest, ModelAssociationEmptyCloud) {
std::unique_ptr<base::Value> value(FindValue(kStringPrefName, out));
ASSERT_TRUE(value.get());
- EXPECT_TRUE(GetPreferenceValue(kStringPrefName).Equals(value.get()));
+ EXPECT_EQ(GetPreferenceValue(kStringPrefName), *value);
value = FindValue(kListPrefName, out);
ASSERT_TRUE(value.get());
- EXPECT_TRUE(GetPreferenceValue(kListPrefName).Equals(value.get()));
+ EXPECT_EQ(GetPreferenceValue(kListPrefName), *value);
}
TEST_F(PrefServiceSyncableTest, ModelAssociationCloudHasData) {
prefs_.SetString(kStringPrefName, kExampleUrl0);
{
ListPrefUpdate update(GetPrefs(), kListPrefName);
- base::ListValue* url_list = update.Get();
+ base::Value* url_list = update.Get();
url_list->Append(kExampleUrl0);
}
@@ -343,7 +343,7 @@ TEST_F(PrefServiceSyncableTest, ModelAssociationCloudHasData) {
auto expected_urls = std::make_unique<base::ListValue>();
expected_urls->Append(kExampleUrl1);
EXPECT_FALSE(FindValue(kListPrefName, out));
- EXPECT_TRUE(GetPreferenceValue(kListPrefName).Equals(expected_urls.get()));
+ EXPECT_EQ(GetPreferenceValue(kListPrefName), *expected_urls);
EXPECT_EQ(kNonDefaultCharsetValue, prefs_.GetString(kDefaultCharsetPrefName));
}
@@ -381,11 +381,11 @@ class TestPrefModelAssociatorClient : public PrefModelAssociatorClient {
return is_dict_pref_;
}
- std::unique_ptr<base::Value> MaybeMergePreferenceValues(
+ base::Value MaybeMergePreferenceValues(
const std::string& pref_name,
const base::Value& local_value,
const base::Value& server_value) const override {
- return nullptr;
+ return base::Value();
}
void SetIsDictPref(bool is_dict_pref) { is_dict_pref_ = is_dict_pref; }
@@ -403,11 +403,13 @@ class PrefServiceSyncableMergeTest : public testing::Test {
new TestingPrefStore,
new TestingPrefStore,
new TestingPrefStore,
- user_prefs_.get(),
new TestingPrefStore,
+ user_prefs_.get(),
+ standalone_browser_prefs_.get(),
pref_registry_->defaults().get(),
pref_notifier_),
user_prefs_,
+ standalone_browser_prefs_,
pref_registry_,
&client_,
/*read_error_callback=*/base::DoNothing(),
@@ -500,6 +502,8 @@ class PrefServiceSyncableMergeTest : public testing::Test {
base::MakeRefCounted<TestingPrefStore>();
scoped_refptr<TestingPrefStore> user_prefs_ =
base::MakeRefCounted<TestingPrefStore>();
+ scoped_refptr<TestingPrefStore> standalone_browser_prefs_ =
+ base::MakeRefCounted<TestingPrefStore>();
TestPrefModelAssociatorClient client_;
PrefServiceSyncable prefs_;
raw_ptr<PrefModelAssociator> pref_sync_service_ = nullptr;
@@ -508,7 +512,7 @@ class PrefServiceSyncableMergeTest : public testing::Test {
TEST_F(PrefServiceSyncableMergeTest, ShouldMergeSelectedListValues) {
{
ListPrefUpdate update(&prefs_, kListPrefName);
- base::ListValue* url_list = update.Get();
+ base::Value* url_list = update.Get();
url_list->Append(kExampleUrl0);
url_list->Append(kExampleUrl1);
}
@@ -528,8 +532,8 @@ TEST_F(PrefServiceSyncableMergeTest, ShouldMergeSelectedListValues) {
expected_urls->Append(kExampleUrl0);
std::unique_ptr<base::Value> value(FindValue(kListPrefName, out));
ASSERT_TRUE(value.get());
- EXPECT_TRUE(value->Equals(expected_urls.get())) << *value;
- EXPECT_TRUE(GetPreferenceValue(kListPrefName).Equals(expected_urls.get()));
+ EXPECT_EQ(*value, *expected_urls) << *value;
+ EXPECT_EQ(GetPreferenceValue(kListPrefName), *expected_urls);
}
// List preferences have special handling at association time due to our ability
@@ -579,19 +583,19 @@ TEST_F(PrefServiceSyncableMergeTest, ManagedListPreferences) {
const base::Value* managed_prefs_result;
ASSERT_TRUE(managed_prefs_->GetValue(kListPrefName, &managed_prefs_result));
- EXPECT_TRUE(managed_value.Equals(managed_prefs_result));
+ EXPECT_EQ(managed_value, *managed_prefs_result);
// Get should return the managed value, too.
- EXPECT_TRUE(managed_value.Equals(prefs_.Get(kListPrefName)));
+ EXPECT_EQ(managed_value, *prefs_.Get(kListPrefName));
// Verify the user pref value has the change.
- EXPECT_TRUE(sync_value.Equals(prefs_.GetUserPrefValue(kListPrefName)));
+ EXPECT_EQ(sync_value, *prefs_.GetUserPrefValue(kListPrefName));
}
TEST_F(PrefServiceSyncableMergeTest, ShouldMergeSelectedDictionaryValues) {
{
DictionaryPrefUpdate update(&prefs_, kDictPrefName);
- base::DictionaryValue* dict_value = update.Get();
- dict_value->Set("my_key1", std::make_unique<base::Value>("my_value1"));
- dict_value->Set("my_key3", std::make_unique<base::Value>("my_value3"));
+ base::Value* dict_value = update.Get();
+ dict_value->SetStringKey("my_key1", "my_value1");
+ dict_value->SetStringKey("my_key3", "my_value3");
}
base::DictionaryValue remote_update;
@@ -608,8 +612,8 @@ TEST_F(PrefServiceSyncableMergeTest, ShouldMergeSelectedDictionaryValues) {
expected_dict.Set("my_key3", std::make_unique<base::Value>("my_value3"));
std::unique_ptr<base::Value> value(FindValue(kDictPrefName, out));
ASSERT_TRUE(value.get());
- EXPECT_TRUE(value->Equals(&expected_dict));
- EXPECT_TRUE(GetPreferenceValue(kDictPrefName).Equals(&expected_dict));
+ EXPECT_EQ(*value, expected_dict);
+ EXPECT_EQ(GetPreferenceValue(kDictPrefName), expected_dict);
}
// TODO(jamescook): In production all prefs are registered before the
@@ -653,7 +657,7 @@ TEST_F(PrefServiceSyncableMergeTest, RegisterShouldClearTypeMismatchingData) {
pref_registry_->RegisterListPref(
pref_name, user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
- EXPECT_TRUE(GetPreferenceValue(pref_name).GetList().empty());
+ EXPECT_TRUE(GetPreferenceValue(pref_name).GetListDeprecated().empty());
EXPECT_FALSE(user_prefs_->GetValue(pref_name, nullptr));
prefs_.RemoveSyncedPrefObserver(pref_name, &observer);
@@ -703,7 +707,7 @@ TEST_F(PrefServiceSyncableTest, UpdatedPreferenceWithDefaultValue) {
std::unique_ptr<base::Value> actual(FindValue(kStringPrefName, out));
ASSERT_TRUE(actual.get());
- EXPECT_TRUE(expected.Equals(actual.get()));
+ EXPECT_EQ(expected, *actual);
}
TEST_F(PrefServiceSyncableTest, UpdatedPreferenceWithValue) {
@@ -717,7 +721,7 @@ TEST_F(PrefServiceSyncableTest, UpdatedPreferenceWithValue) {
std::unique_ptr<base::Value> actual(FindValue(kStringPrefName, out));
ASSERT_TRUE(actual.get());
- EXPECT_TRUE(expected.Equals(actual.get()));
+ EXPECT_EQ(expected, *actual);
}
TEST_F(PrefServiceSyncableTest, UpdatedSyncNodeActionUpdate) {
@@ -731,7 +735,7 @@ TEST_F(PrefServiceSyncableTest, UpdatedSyncNodeActionUpdate) {
pref_sync_service_->ProcessSyncChanges(FROM_HERE, list);
const base::Value& actual = GetPreferenceValue(kStringPrefName);
- EXPECT_TRUE(expected.Equals(&actual));
+ EXPECT_EQ(expected, actual);
}
// Verifies that the implementation gracefully handles a remote update with the
@@ -759,7 +763,7 @@ TEST_F(PrefServiceSyncableTest, UpdatedSyncNodeActionAdd) {
pref_sync_service_->ProcessSyncChanges(FROM_HERE, list);
const base::Value& actual = GetPreferenceValue(kStringPrefName);
- EXPECT_TRUE(expected.Equals(&actual));
+ EXPECT_EQ(expected, actual);
EXPECT_TRUE(pref_sync_service_->IsPrefSyncedForTesting(kStringPrefName));
}
@@ -777,7 +781,7 @@ TEST_F(PrefServiceSyncableTest, UpdatedSyncNodeUnknownPreference) {
TEST_F(PrefServiceSyncableTest, ManagedPreferences) {
// Make the homepage preference managed.
base::Value managed_value("http://example.com");
- prefs_.SetManagedPref(kStringPrefName, managed_value.CreateDeepCopy());
+ prefs_.SetManagedPref(kStringPrefName, managed_value.Clone());
syncer::SyncChangeList out;
InitWithSyncDataTakeOutput(syncer::SyncDataList(), &out);
@@ -785,7 +789,7 @@ TEST_F(PrefServiceSyncableTest, ManagedPreferences) {
// Changing the homepage preference should not sync anything.
base::Value user_value("http://chromium..com");
- prefs_.SetUserPref(kStringPrefName, user_value.CreateDeepCopy());
+ prefs_.SetUserPref(kStringPrefName, user_value.Clone());
EXPECT_TRUE(out.empty());
// An incoming sync transaction should change the user value, not the managed
@@ -796,8 +800,8 @@ TEST_F(PrefServiceSyncableTest, ManagedPreferences) {
MakeRemoteChange(kStringPrefName, sync_value, SyncChange::ACTION_UPDATE));
pref_sync_service_->ProcessSyncChanges(FROM_HERE, list);
- EXPECT_TRUE(managed_value.Equals(prefs_.GetManagedPref(kStringPrefName)));
- EXPECT_TRUE(sync_value.Equals(prefs_.GetUserPref(kStringPrefName)));
+ EXPECT_EQ(managed_value, *prefs_.GetManagedPref(kStringPrefName));
+ EXPECT_EQ(sync_value, *prefs_.GetUserPref(kStringPrefName));
}
TEST_F(PrefServiceSyncableTest, DynamicManagedPreferences) {
@@ -808,21 +812,21 @@ TEST_F(PrefServiceSyncableTest, DynamicManagedPreferences) {
GetPrefs()->Set(kStringPrefName, initial_value);
std::unique_ptr<base::Value> actual(FindValue(kStringPrefName, out));
ASSERT_TRUE(actual.get());
- EXPECT_TRUE(initial_value.Equals(actual.get()));
+ EXPECT_EQ(initial_value, *actual);
// Switch kHomePage to managed and set a different value.
base::Value managed_value("http://example.com/managed");
GetTestingPrefService()->SetManagedPref(kStringPrefName,
- managed_value.CreateDeepCopy());
+ managed_value.Clone());
// The pref value should be the one dictated by policy.
- EXPECT_TRUE(managed_value.Equals(&GetPreferenceValue(kStringPrefName)));
+ EXPECT_EQ(managed_value, GetPreferenceValue(kStringPrefName));
// Switch kHomePage back to unmanaged.
GetTestingPrefService()->RemoveManagedPref(kStringPrefName);
// The original value should be picked up.
- EXPECT_TRUE(initial_value.Equals(&GetPreferenceValue(kStringPrefName)));
+ EXPECT_EQ(initial_value, GetPreferenceValue(kStringPrefName));
}
TEST_F(PrefServiceSyncableTest, DynamicManagedPreferencesWithSyncChange) {
@@ -833,12 +837,12 @@ TEST_F(PrefServiceSyncableTest, DynamicManagedPreferencesWithSyncChange) {
base::Value initial_value("http://example.com/initial");
GetPrefs()->Set(kStringPrefName, initial_value);
std::unique_ptr<base::Value> actual(FindValue(kStringPrefName, out));
- EXPECT_TRUE(initial_value.Equals(actual.get()));
+ EXPECT_EQ(initial_value, *actual);
// Switch kHomePage to managed and set a different value.
base::Value managed_value("http://example.com/managed");
GetTestingPrefService()->SetManagedPref(kStringPrefName,
- managed_value.CreateDeepCopy());
+ managed_value.Clone());
// Change the sync value.
base::Value sync_value("http://example.com/sync");
@@ -848,13 +852,13 @@ TEST_F(PrefServiceSyncableTest, DynamicManagedPreferencesWithSyncChange) {
pref_sync_service_->ProcessSyncChanges(FROM_HERE, list);
// The pref value should still be the one dictated by policy.
- EXPECT_TRUE(managed_value.Equals(&GetPreferenceValue(kStringPrefName)));
+ EXPECT_EQ(managed_value, GetPreferenceValue(kStringPrefName));
// Switch kHomePage back to unmanaged.
GetTestingPrefService()->RemoveManagedPref(kStringPrefName);
// Sync value should be picked up.
- EXPECT_TRUE(sync_value.Equals(&GetPreferenceValue(kStringPrefName)));
+ EXPECT_EQ(sync_value, GetPreferenceValue(kStringPrefName));
}
TEST_F(PrefServiceSyncableTest, DynamicManagedDefaultPreferences) {
@@ -871,9 +875,9 @@ TEST_F(PrefServiceSyncableTest, DynamicManagedDefaultPreferences) {
// Switch kHomePage to managed and set a different value.
base::Value managed_value("http://example.com/managed");
GetTestingPrefService()->SetManagedPref(kStringPrefName,
- managed_value.CreateDeepCopy());
+ managed_value.Clone());
// The pref value should be the one dictated by policy.
- EXPECT_TRUE(managed_value.Equals(&GetPreferenceValue(kStringPrefName)));
+ EXPECT_EQ(managed_value, GetPreferenceValue(kStringPrefName));
EXPECT_FALSE(pref->IsDefaultValue());
// There should be no synced value.
EXPECT_FALSE(FindValue(kStringPrefName, out).get());
@@ -910,7 +914,8 @@ class PrefServiceSyncableChromeOsTest : public testing::Test {
PrefServiceSyncableChromeOsTest()
: pref_registry_(base::MakeRefCounted<PrefRegistrySyncable>()),
pref_notifier_(new PrefNotifierImpl),
- user_prefs_(base::MakeRefCounted<TestingPrefStore>()) {}
+ user_prefs_(base::MakeRefCounted<TestingPrefStore>()),
+ standalone_browser_prefs_(base::MakeRefCounted<TestingPrefStore>()) {}
void CreatePrefService() {
// Register prefs of various types.
@@ -933,9 +938,10 @@ class PrefServiceSyncableChromeOsTest : public testing::Test {
std::unique_ptr<PrefNotifierImpl>(pref_notifier_),
std::make_unique<PrefValueStore>(
new TestingPrefStore, new TestingPrefStore, new TestingPrefStore,
- new TestingPrefStore, user_prefs_.get(), new TestingPrefStore,
- pref_registry_->defaults().get(), pref_notifier_),
- user_prefs_, pref_registry_, &client_,
+ new TestingPrefStore, new TestingPrefStore, user_prefs_.get(),
+ standalone_browser_prefs_.get(), pref_registry_->defaults().get(),
+ pref_notifier_),
+ user_prefs_, standalone_browser_prefs_, pref_registry_, &client_,
/*read_error_callback=*/base::DoNothing(),
/*async=*/false);
}
@@ -987,6 +993,7 @@ class PrefServiceSyncableChromeOsTest : public testing::Test {
scoped_refptr<PrefRegistrySyncable> pref_registry_;
PrefNotifierImpl* pref_notifier_; // Owned by |prefs_|.
scoped_refptr<TestingPrefStore> user_prefs_;
+ scoped_refptr<TestingPrefStore> standalone_browser_prefs_;
TestPrefModelAssociatorClient client_;
std::unique_ptr<PrefServiceSyncable> prefs_;
};
diff --git a/chromium/components/sync_preferences/testing_pref_service_syncable.cc b/chromium/components/sync_preferences/testing_pref_service_syncable.cc
index e2fd19c7f9c..4febf44c0cd 100644
--- a/chromium/components/sync_preferences/testing_pref_service_syncable.cc
+++ b/chromium/components/sync_preferences/testing_pref_service_syncable.cc
@@ -18,6 +18,7 @@ TestingPrefServiceBase<sync_preferences::PrefServiceSyncable,
TestingPrefServiceBase(TestingPrefStore* managed_prefs,
TestingPrefStore* supervised_user_prefs,
TestingPrefStore* extension_prefs,
+ TestingPrefStore* standalone_browser_prefs,
TestingPrefStore* user_prefs,
TestingPrefStore* recommended_prefs,
user_prefs::PrefRegistrySyncable* pref_registry,
@@ -27,12 +28,14 @@ TestingPrefServiceBase<sync_preferences::PrefServiceSyncable,
std::make_unique<PrefValueStore>(managed_prefs,
supervised_user_prefs,
extension_prefs,
+ standalone_browser_prefs,
/*command_line_prefs=*/nullptr,
user_prefs,
recommended_prefs,
pref_registry->defaults().get(),
pref_notifier),
user_prefs,
+ standalone_browser_prefs,
pref_registry,
/*pref_model_associator_client=*/nullptr,
base::BindRepeating(
@@ -42,6 +45,7 @@ TestingPrefServiceBase<sync_preferences::PrefServiceSyncable,
false),
managed_prefs_(managed_prefs),
extension_prefs_(extension_prefs),
+ standalone_browser_prefs_(standalone_browser_prefs),
user_prefs_(user_prefs),
recommended_prefs_(recommended_prefs) {}
@@ -53,6 +57,7 @@ TestingPrefServiceSyncable::TestingPrefServiceSyncable()
/*managed_prefs=*/new TestingPrefStore(),
/*supervised_user_prefs=*/new TestingPrefStore(),
/*extension_prefs=*/new TestingPrefStore(),
+ /*standalone_browser_prefs=*/new TestingPrefStore(),
/*user_prefs=*/new TestingPrefStore(),
/*recommended_prefs=*/new TestingPrefStore(),
new user_prefs::PrefRegistrySyncable(),
@@ -62,6 +67,7 @@ TestingPrefServiceSyncable::TestingPrefServiceSyncable(
TestingPrefStore* managed_prefs,
TestingPrefStore* supervised_user_prefs,
TestingPrefStore* extension_prefs,
+ TestingPrefStore* standalone_browser_prefs,
TestingPrefStore* user_prefs,
TestingPrefStore* recommended_prefs,
user_prefs::PrefRegistrySyncable* pref_registry,
@@ -71,6 +77,7 @@ TestingPrefServiceSyncable::TestingPrefServiceSyncable(
managed_prefs,
supervised_user_prefs,
extension_prefs,
+ standalone_browser_prefs,
user_prefs,
recommended_prefs,
pref_registry,
diff --git a/chromium/components/sync_preferences/testing_pref_service_syncable.h b/chromium/components/sync_preferences/testing_pref_service_syncable.h
index e7564e61d5d..cd95a28847a 100644
--- a/chromium/components/sync_preferences/testing_pref_service_syncable.h
+++ b/chromium/components/sync_preferences/testing_pref_service_syncable.h
@@ -35,6 +35,7 @@ class TestingPrefServiceSyncable
TestingPrefServiceSyncable(TestingPrefStore* managed_prefs,
TestingPrefStore* supervised_user_prefs,
TestingPrefStore* extension_prefs,
+ TestingPrefStore* standalone_browser_prefs,
TestingPrefStore* user_prefs,
TestingPrefStore* recommended_prefs,
user_prefs::PrefRegistrySyncable* pref_registry,
@@ -60,6 +61,7 @@ TestingPrefServiceBase<sync_preferences::PrefServiceSyncable,
TestingPrefServiceBase(TestingPrefStore* managed_prefs,
TestingPrefStore* supervised_user_prefs,
TestingPrefStore* extension_prefs,
+ TestingPrefStore* standalone_browser_prefs,
TestingPrefStore* user_prefs,
TestingPrefStore* recommended_prefs,
user_prefs::PrefRegistrySyncable* pref_registry,
diff --git a/chromium/components/sync_sessions/BUILD.gn b/chromium/components/sync_sessions/BUILD.gn
index e0a7c4e7bf8..e2abfdffa84 100644
--- a/chromium/components/sync_sessions/BUILD.gn
+++ b/chromium/components/sync_sessions/BUILD.gn
@@ -27,8 +27,6 @@ static_library("sync_sessions") {
"session_sync_service_impl.h",
"sessions_global_id_mapper.cc",
"sessions_global_id_mapper.h",
- "switches.cc",
- "switches.h",
"sync_sessions_client.cc",
"sync_sessions_client.h",
"synced_session.cc",
diff --git a/chromium/components/sync_sessions/README.md b/chromium/components/sync_sessions/README.md
new file mode 100644
index 00000000000..5cb33a1ca9e
--- /dev/null
+++ b/chromium/components/sync_sessions/README.md
@@ -0,0 +1 @@
+See components/sync/README.md.
diff --git a/chromium/components/sync_sessions/local_session_event_handler_impl.cc b/chromium/components/sync_sessions/local_session_event_handler_impl.cc
index bd6668d2535..93a402ee70d 100644
--- a/chromium/components/sync_sessions/local_session_event_handler_impl.cc
+++ b/chromium/components/sync_sessions/local_session_event_handler_impl.cc
@@ -13,7 +13,6 @@
#include "base/logging.h"
#include "components/sync/model/sync_change.h"
#include "components/sync/protocol/session_specifics.pb.h"
-#include "components/sync_sessions/switches.h"
#include "components/sync_sessions/sync_sessions_client.h"
#include "components/sync_sessions/synced_session_tracker.h"
#include "components/sync_sessions/synced_tab_delegate.h"
@@ -32,10 +31,10 @@ bool IsSessionRestoreInProgress(SyncSessionsClient* sessions_client) {
DCHECK(sessions_client);
SyncedWindowDelegatesGetter* synced_window_getter =
sessions_client->GetSyncedWindowDelegatesGetter();
- SyncedWindowDelegatesGetter::SyncedWindowDelegateMap windows =
+ SyncedWindowDelegatesGetter::SyncedWindowDelegateMap window_delegates =
synced_window_getter->GetSyncedWindowDelegates();
- for (const auto& window_iter_pair : windows) {
- if (window_iter_pair.second->IsSessionRestoreInProgress()) {
+ for (const auto& [window_id, window_delegate] : window_delegates) {
+ if (window_delegate->IsSessionRestoreInProgress()) {
return true;
}
}
@@ -43,21 +42,15 @@ bool IsSessionRestoreInProgress(SyncSessionsClient* sessions_client) {
}
bool IsWindowSyncable(const SyncedWindowDelegate& window_delegate) {
- // TODO(crbug.com/1039234): remove the feature toggle once the logic is rolled
- // out.
- return window_delegate.ShouldSync() && window_delegate.HasWindow() &&
- (window_delegate.GetTabCount() ||
- base::FeatureList::IsEnabled(
- switches::kSyncConsiderEmptyWindowsSyncable));
+ return window_delegate.ShouldSync() && window_delegate.HasWindow();
}
// On Android, it's possible to not have any tabbed windows when only custom
// tabs are currently open. This means that there is tab data that will be
// restored later, but we cannot access it.
bool ScanForTabbedWindow(SyncedWindowDelegatesGetter* delegates_getter) {
- for (const auto& window_iter_pair :
+ for (const auto& [window_id, window_delegate] :
delegates_getter->GetSyncedWindowDelegates()) {
- const SyncedWindowDelegate* window_delegate = window_iter_pair.second;
if (window_delegate->IsTypeNormal() && IsWindowSyncable(*window_delegate)) {
return true;
}
@@ -150,7 +143,7 @@ void LocalSessionEventHandlerImpl::AssociateWindows(ReloadTabsOption option,
SyncedSession* current_session =
session_tracker_->GetSession(current_session_tag_);
- SyncedWindowDelegatesGetter::SyncedWindowDelegateMap windows =
+ SyncedWindowDelegatesGetter::SyncedWindowDelegateMap window_delegates =
sessions_client_->GetSyncedWindowDelegatesGetter()
->GetSyncedWindowDelegates();
@@ -168,8 +161,7 @@ void LocalSessionEventHandlerImpl::AssociateWindows(ReloadTabsOption option,
<< " windows from previous session.";
}
- for (auto& window_iter_pair : windows) {
- const SyncedWindowDelegate* window_delegate = window_iter_pair.second;
+ for (auto& [unused, window_delegate] : window_delegates) {
// Make sure the window is viewable and is not about to be closed. The
// viewable window check is necessary because, for example, when a browser
// is closed the destructor is not necessarily run immediately. This means
@@ -184,6 +176,7 @@ void LocalSessionEventHandlerImpl::AssociateWindows(ReloadTabsOption option,
continue;
}
+ // TODO(crbug.com/1286934): Can we use the `unused` variable above instead?
SessionID window_id = window_delegate->GetSessionId();
DVLOG(1) << "Associating window " << window_id.id() << " with "
<< window_delegate->GetTabCount() << " tabs.";
@@ -338,10 +331,13 @@ void LocalSessionEventHandlerImpl::OnLocalTabModified(
return;
}
- sessions::SerializedNavigationEntry current;
- modified_tab->GetSerializedNavigationAtIndex(
- modified_tab->GetCurrentEntryIndex(), &current);
- delegate_->TrackLocalNavigationId(current.timestamp(), current.unique_id());
+ // Don't track empty tabs.
+ if (modified_tab->GetEntryCount() != 0) {
+ sessions::SerializedNavigationEntry current;
+ modified_tab->GetSerializedNavigationAtIndex(
+ modified_tab->GetCurrentEntryIndex(), &current);
+ delegate_->TrackLocalNavigationId(current.timestamp(), current.unique_id());
+ }
std::unique_ptr<WriteBatch> batch = delegate_->CreateLocalSessionWriteBatch();
AssociateTab(modified_tab, batch.get());
@@ -371,7 +367,7 @@ sync_pb::SessionTab LocalSessionEventHandlerImpl::GetTabSpecificsFromDelegate(
const int min_index = std::max(0, current_index - kMaxSyncNavigationCount);
const int max_index = std::min(current_index + kMaxSyncNavigationCount,
tab_delegate.GetEntryCount());
- bool is_supervised = tab_delegate.ProfileIsSupervised();
+ bool has_child_account = tab_delegate.ProfileHasChildAccount();
for (int i = min_index; i < max_index; ++i) {
if (!tab_delegate.GetVirtualURLAtIndex(i).is_valid()) {
@@ -391,7 +387,7 @@ sync_pb::SessionTab LocalSessionEventHandlerImpl::GetTabSpecificsFromDelegate(
if (!page_language.empty())
navigation->set_page_language(page_language);
- if (is_supervised) {
+ if (has_child_account) {
navigation->set_blocked_state(
sync_pb::TabNavigation_BlockedState_STATE_ALLOWED);
}
@@ -403,7 +399,7 @@ sync_pb::SessionTab LocalSessionEventHandlerImpl::GetTabSpecificsFromDelegate(
specifics.set_current_navigation_index(specifics.navigation_size() - 1);
}
- if (is_supervised) {
+ if (has_child_account) {
const std::vector<std::unique_ptr<const SerializedNavigationEntry>>*
blocked_navigations = tab_delegate.GetBlockedNavigations();
DCHECK(blocked_navigations);
diff --git a/chromium/components/sync_sessions/local_session_event_handler_impl_unittest.cc b/chromium/components/sync_sessions/local_session_event_handler_impl_unittest.cc
index 2957199c623..9617156917e 100644
--- a/chromium/components/sync_sessions/local_session_event_handler_impl_unittest.cc
+++ b/chromium/components/sync_sessions/local_session_event_handler_impl_unittest.cc
@@ -9,7 +9,6 @@
#include <vector>
#include "base/strings/stringprintf.h"
-#include "base/test/scoped_feature_list.h"
#include "components/sessions/core/serialized_navigation_entry.h"
#include "components/sessions/core/serialized_navigation_entry_test_helper.h"
#include "components/sync/base/time.h"
@@ -73,11 +72,11 @@ sync_pb::SessionSpecifics MakeSessionHeaderSpecifics(
const std::map<int, std::vector<int>>& window_id_to_tabs) {
sync_pb::SessionSpecifics session_header;
session_header.set_session_tag(kSessionTag);
- for (const auto& window_and_tabs : window_id_to_tabs) {
+ for (const auto& [window_id, tabs] : window_id_to_tabs) {
sync_pb::SessionWindow* mutable_window =
session_header.mutable_header()->add_window();
- mutable_window->set_window_id(window_and_tabs.first);
- for (int tab_id : window_and_tabs.second) {
+ mutable_window->set_window_id(window_id);
+ for (int tab_id : tabs) {
mutable_window->add_tab(tab_id);
}
}
@@ -275,8 +274,8 @@ TEST_F(LocalSessionEventHandlerImplTest,
ASSERT_EQ(3, session_tab.navigation_size());
}
-// Tests that for supervised users blocked navigations are recorded and marked
-// as such, while regular navigations are marked as allowed.
+// Tests that for child account users blocked navigations are recorded and
+// marked as such, while regular navigations are marked as allowed.
TEST_F(LocalSessionEventHandlerImplTest, BlockedNavigations) {
AddWindow(kWindowId1);
TestSyncedTabDelegate* tab = AddTabWithTime(kWindowId1, kFoo1, kTime1);
@@ -296,7 +295,7 @@ TEST_F(LocalSessionEventHandlerImplTest, BlockedNavigations) {
blocked_navigations.push_back(std::move(entry2));
blocked_navigations.push_back(std::move(entry3));
- tab->set_is_supervised(true);
+ tab->set_has_child_account(true);
tab->set_blocked_navigations(blocked_navigations);
InitHandler();
@@ -622,49 +621,7 @@ TEST_F(LocalSessionEventHandlerImplTest, PropagateNewTab) {
AddTab(kWindowId1, kBar1, kTabId2);
}
-TEST_F(LocalSessionEventHandlerImplTest,
- PropagateClosedTabWithoutDeferredRecyclingNorImmediateDeletion) {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitWithFeatures(
- /*enabled_features=*/{},
- /*disabled_features=*/{kDeferRecyclingOfSyncTabNodesIfUnsynced,
- kTabNodePoolImmediateDeletion});
-
- AddWindow(kWindowId1);
- AddTab(kWindowId1, kFoo1, kTabId1);
- TestSyncedTabDelegate* tab2 = AddTab(kWindowId1, kBar1, kTabId2);
-
- InitHandler();
-
- // Closing a tab (later below) is expected to verify if the sync entity is
- // unsynced.
- EXPECT_CALL(mock_delegate_, IsTabNodeUnsynced(/*tab_node_id=*/0));
-
- // Closing a tab is expected to update the header and the remaining tab (this
- // test issues a navigation for it, but it would have been updated anyway).
- auto mock_batch = std::make_unique<StrictMock<MockWriteBatch>>();
- EXPECT_CALL(
- *mock_batch,
- Put(Pointee(MatchesHeader(kSessionTag, {kWindowId1}, {kTabId2}))));
- EXPECT_CALL(*mock_batch,
- Put(Pointee(MatchesTab(kSessionTag, kWindowId1, kTabId2,
- /*tab_node_id=*/1, /*urls=*/{kBar1}))));
- EXPECT_CALL(*mock_batch, Commit());
- EXPECT_CALL(mock_delegate_, CreateLocalSessionWriteBatch())
- .WillOnce(Return(ByMove(std::move(mock_batch))));
-
- // Close tab and force reassociation.
- window_getter_.CloseTab(SessionID::FromSerializedValue(kTabId1));
- handler_->OnLocalTabModified(tab2);
-}
-
TEST_F(LocalSessionEventHandlerImplTest, PropagateClosedTab) {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitWithFeatures(
- /*enabled_features=*/{kDeferRecyclingOfSyncTabNodesIfUnsynced,
- kTabNodePoolImmediateDeletion},
- /*disabled_features=*/{});
-
// We start with three tabs.
AddWindow(kWindowId1);
AddTab(kWindowId1, kFoo1, kTabId1);
diff --git a/chromium/components/sync_sessions/open_tabs_ui_delegate_impl.h b/chromium/components/sync_sessions/open_tabs_ui_delegate_impl.h
index 7c507357890..9a93f38b5cc 100644
--- a/chromium/components/sync_sessions/open_tabs_ui_delegate_impl.h
+++ b/chromium/components/sync_sessions/open_tabs_ui_delegate_impl.h
@@ -8,6 +8,7 @@
#include <string>
#include <vector>
+#include "base/callback.h"
#include "base/memory/raw_ptr.h"
#include "components/sync_sessions/open_tabs_ui_delegate.h"
diff --git a/chromium/components/sync_sessions/session_store.cc b/chromium/components/sync_sessions/session_store.cc
index 8b9e86c37da..6534a2d878f 100644
--- a/chromium/components/sync_sessions/session_store.cc
+++ b/chromium/components/sync_sessions/session_store.cc
@@ -421,10 +421,7 @@ SessionStore::SessionStore(
bool found_local_header = false;
- for (auto& storage_key_and_specifics : initial_data) {
- const std::string& storage_key = storage_key_and_specifics.first;
- SessionSpecifics& specifics = storage_key_and_specifics.second;
-
+ for (auto& [storage_key, specifics] : initial_data) {
// The store should not contain invalid data, but as a precaution we filter
// out anyway in case the persisted data is corrupted.
if (!AreValidSpecifics(specifics)) {
diff --git a/chromium/components/sync_sessions/session_store_unittest.cc b/chromium/components/sync_sessions/session_store_unittest.cc
index 65b9bc75f1f..b23fee71eef 100644
--- a/chromium/components/sync_sessions/session_store_unittest.cc
+++ b/chromium/components/sync_sessions/session_store_unittest.cc
@@ -16,7 +16,7 @@
#include "base/test/task_environment.h"
#include "components/prefs/testing_pref_service.h"
#include "components/sync/base/hash_util.h"
-#include "components/sync/engine/entity_data.h"
+#include "components/sync/protocol/entity_data.h"
#include "components/sync/protocol/session_specifics.pb.h"
#include "components/sync/test/model/model_type_store_test_util.h"
#include "components/sync/test/model/test_matchers.h"
@@ -101,9 +101,7 @@ std::map<std::string, EntityData> BatchToEntityDataMap(
std::unique_ptr<DataBatch> batch) {
std::map<std::string, EntityData> storage_key_to_data;
while (batch && batch->HasNext()) {
- auto batch_entry = batch->Next();
- const std::string& storage_key = batch_entry.first;
- std::unique_ptr<EntityData> entity_data = std::move(batch_entry.second);
+ auto [storage_key, entity_data] = batch->Next();
EXPECT_THAT(entity_data, NotNull());
if (entity_data) {
storage_key_to_data.emplace(storage_key, std::move(*entity_data));
diff --git a/chromium/components/sync_sessions/session_sync_bridge.cc b/chromium/components/sync_sessions/session_sync_bridge.cc
index 170102340c0..6484e51294f 100644
--- a/chromium/components/sync_sessions/session_sync_bridge.cc
+++ b/chromium/components/sync_sessions/session_sync_bridge.cc
@@ -440,10 +440,9 @@ void SessionSyncBridge::ResubmitLocalSession() {
CreateSessionStoreWriteBatch();
std::unique_ptr<syncer::DataBatch> read_batch = store_->GetAllSessionData();
while (read_batch->HasNext()) {
- syncer::KeyAndData key_and_data = read_batch->Next();
- if (store_->StorageKeyMatchesLocalSession(key_and_data.first)) {
- change_processor()->Put(key_and_data.first,
- std::move(key_and_data.second),
+ auto [key, data] = read_batch->Next();
+ if (store_->StorageKeyMatchesLocalSession(key)) {
+ change_processor()->Put(key, std::move(data),
write_batch->GetMetadataChangeList());
}
}
diff --git a/chromium/components/sync_sessions/session_sync_bridge_unittest.cc b/chromium/components/sync_sessions/session_sync_bridge_unittest.cc
index 7fc4295c008..605c10e00c3 100644
--- a/chromium/components/sync_sessions/session_sync_bridge_unittest.cc
+++ b/chromium/components/sync_sessions/session_sync_bridge_unittest.cc
@@ -14,7 +14,6 @@
#include "base/run_loop.h"
#include "base/test/bind.h"
#include "base/test/mock_callback.h"
-#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "components/prefs/testing_pref_service.h"
#include "components/sync/base/client_tag_hash.h"
@@ -1574,9 +1573,6 @@ TEST_F(SessionSyncBridgeTest, ShouldDoGarbageCollection) {
}
TEST_F(SessionSyncBridgeTest, ShouldReturnBrowserTypeInGetData) {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitAndEnableFeature(kSyncPopulateTabBrowserTypeInGetData);
-
const int kWindowId = 1000001;
const int kTabId = 1000002;
@@ -1594,26 +1590,5 @@ TEST_F(SessionSyncBridgeTest, ShouldReturnBrowserTypeInGetData) {
tab_data->specifics.session().tab().browser_type());
}
-TEST_F(SessionSyncBridgeTest,
- ShouldReturnBrowserTypeInGetDataWithFeatureDisabled) {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitAndDisableFeature(kSyncPopulateTabBrowserTypeInGetData);
-
- const int kWindowId = 1000001;
- const int kTabId = 1000002;
-
- AddWindow(kWindowId, sync_pb::SessionWindow_BrowserType_TYPE_CUSTOM_TAB);
- AddTab(kWindowId, "http://foo.com/", kTabId);
-
- InitializeBridge();
- StartSyncing();
-
- std::unique_ptr<EntityData> tab_data = GetData(
- SessionStore::GetTabStorageKey(kLocalCacheGuid, /*tab_node_id=*/0));
- ASSERT_THAT(tab_data, NotNull());
-
- EXPECT_FALSE(tab_data->specifics.session().tab().has_browser_type());
-}
-
} // namespace
} // namespace sync_sessions
diff --git a/chromium/components/sync_sessions/session_sync_service.h b/chromium/components/sync_sessions/session_sync_service.h
index 682be6e4f59..a7a96f8f4fa 100644
--- a/chromium/components/sync_sessions/session_sync_service.h
+++ b/chromium/components/sync_sessions/session_sync_service.h
@@ -6,7 +6,6 @@
#define COMPONENTS_SYNC_SESSIONS_SESSION_SYNC_SERVICE_H_
#include "base/callback_list.h"
-#include "base/compiler_specific.h"
#include "base/memory/weak_ptr.h"
#include "components/keyed_service/core/keyed_service.h"
#include "components/sync/driver/data_type_controller.h"
@@ -40,8 +39,8 @@ class SessionSyncService : public KeyedService {
virtual OpenTabsUIDelegate* GetOpenTabsUIDelegate() = 0;
// Allows client code to be notified when foreign sessions change.
- virtual base::CallbackListSubscription SubscribeToForeignSessionsChanged(
- const base::RepeatingClosure& cb) WARN_UNUSED_RESULT = 0;
+ [[nodiscard]] virtual base::CallbackListSubscription
+ SubscribeToForeignSessionsChanged(const base::RepeatingClosure& cb) = 0;
virtual base::WeakPtr<syncer::ModelTypeControllerDelegate>
GetControllerDelegate() = 0;
diff --git a/chromium/components/sync_sessions/session_sync_service_impl.h b/chromium/components/sync_sessions/session_sync_service_impl.h
index 806b03756c8..380e1eb2ce7 100644
--- a/chromium/components/sync_sessions/session_sync_service_impl.h
+++ b/chromium/components/sync_sessions/session_sync_service_impl.h
@@ -36,8 +36,8 @@ class SessionSyncServiceImpl : public SessionSyncService {
OpenTabsUIDelegate* GetOpenTabsUIDelegate() override;
// Allows client code to be notified when foreign sessions change.
- base::CallbackListSubscription SubscribeToForeignSessionsChanged(
- const base::RepeatingClosure& cb) override WARN_UNUSED_RESULT;
+ [[nodiscard]] base::CallbackListSubscription
+ SubscribeToForeignSessionsChanged(const base::RepeatingClosure& cb) override;
base::WeakPtr<syncer::ModelTypeControllerDelegate> GetControllerDelegate()
override;
diff --git a/chromium/components/sync_sessions/session_sync_test_helper.cc b/chromium/components/sync_sessions/session_sync_test_helper.cc
index f43f620f1c0..59868e672a9 100644
--- a/chromium/components/sync_sessions/session_sync_test_helper.cc
+++ b/chromium/components/sync_sessions/session_sync_test_helper.cc
@@ -57,22 +57,20 @@ void SessionSyncTestHelper::VerifySyncedSession(
// We assume the window id's are in increasing order.
int i = 1;
- for (auto win_iter = windows.begin(); win_iter != windows.end();
- ++win_iter, ++i) {
+ for (const std::vector<SessionID>& window : windows) {
sessions::SessionWindow* win_ptr;
auto map_iter = session.windows.find(SessionID::FromSerializedValue(i));
if (map_iter != session.windows.end())
win_ptr = &map_iter->second->wrapped_window;
else
FAIL();
- ASSERT_EQ(win_iter->size(), win_ptr->tabs.size());
+ ASSERT_EQ(window.size(), win_ptr->tabs.size());
ASSERT_EQ(0, win_ptr->selected_tab_index);
ASSERT_EQ(sessions::SessionWindow::TYPE_NORMAL, win_ptr->type);
int j = 0;
- for (auto tab_iter = (*win_iter).begin(); tab_iter != (*win_iter).end();
- ++tab_iter, ++j) {
+ for (const SessionID& tab_id : window) {
sessions::SessionTab* tab = win_ptr->tabs[j].get();
- ASSERT_EQ(*tab_iter, tab->tab_id);
+ ASSERT_EQ(tab_id, tab->tab_id);
ASSERT_EQ(1U, tab->navigations.size());
ASSERT_EQ(1, tab->tab_visual_index);
ASSERT_EQ(0, tab->current_navigation_index);
@@ -84,7 +82,9 @@ void SessionSyncTestHelper::VerifySyncedSession(
ASSERT_EQ(tab->navigations[0].title(), base::ASCIIToUTF16(kTitle));
ASSERT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
tab->navigations[0].transition_type(), ui::PAGE_TRANSITION_TYPED));
+ j++;
}
+ i++;
}
}
diff --git a/chromium/components/sync_sessions/switches.cc b/chromium/components/sync_sessions/switches.cc
deleted file mode 100644
index bc1df38d93b..00000000000
--- a/chromium/components/sync_sessions/switches.cc
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright 2020 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.
-
-#include "components/sync_sessions/switches.h"
-
-namespace switches {
-
-// Enables syncing Sessions data type in case when the window doesn't have open
-// tabs anymore.
-const base::Feature kSyncConsiderEmptyWindowsSyncable{
- "SyncConsiderEmptyWindowsSyncable", base::FEATURE_ENABLED_BY_DEFAULT};
-
-} // namespace switches
diff --git a/chromium/components/sync_sessions/switches.h b/chromium/components/sync_sessions/switches.h
deleted file mode 100644
index 4f15cd98f4c..00000000000
--- a/chromium/components/sync_sessions/switches.h
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2020 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.
-
-#ifndef COMPONENTS_SYNC_SESSIONS_SWITCHES_H_
-#define COMPONENTS_SYNC_SESSIONS_SWITCHES_H_
-
-#include "base/feature_list.h"
-
-namespace switches {
-
-extern const base::Feature kSyncConsiderEmptyWindowsSyncable;
-
-} // namespace switches
-
-#endif // COMPONENTS_SYNC_SESSIONS_SWITCHES_H_
diff --git a/chromium/components/sync_sessions/synced_session.cc b/chromium/components/sync_sessions/synced_session.cc
index f9f0eccbea8..d413ae13d27 100644
--- a/chromium/components/sync_sessions/synced_session.cc
+++ b/chromium/components/sync_sessions/synced_session.cc
@@ -6,6 +6,7 @@
#include <vector>
+#include "base/notreached.h"
#include "base/strings/utf_string_conversions.h"
#include "components/sessions/core/serialized_navigation_driver.h"
#include "components/sync/base/time.h"
@@ -353,9 +354,9 @@ SyncedSession::~SyncedSession() = default;
sync_pb::SessionHeader SyncedSession::ToSessionHeaderProto() const {
sync_pb::SessionHeader header;
- for (const auto& window_pair : windows) {
+ for (const auto& [window_id, window] : windows) {
sync_pb::SessionWindow* w = header.add_window();
- w->CopyFrom(window_pair.second->ToSessionWindowProto());
+ w->CopyFrom(window->ToSessionWindowProto());
}
header.set_client_name(session_name);
header.set_device_type(device_type);
diff --git a/chromium/components/sync_sessions/synced_session_tracker.cc b/chromium/components/sync_sessions/synced_session_tracker.cc
index 42a0de04417..ea069d0ae25 100644
--- a/chromium/components/sync_sessions/synced_session_tracker.cc
+++ b/chromium/components/sync_sessions/synced_session_tracker.cc
@@ -7,7 +7,9 @@
#include <algorithm>
#include <utility>
+#include "base/callback.h"
#include "base/logging.h"
+#include "base/ranges/algorithm.h"
#include "base/strings/utf_string_conversions.h"
#include "components/sync/protocol/session_specifics.pb.h"
#include "components/sync_sessions/sync_sessions_client.h"
@@ -15,11 +17,6 @@
namespace sync_sessions {
-const base::Feature kDeferRecyclingOfSyncTabNodesIfUnsynced{
- "DeferRecyclingOfSyncTabNodesIfUnsynced", base::FEATURE_ENABLED_BY_DEFAULT};
-const base::Feature kSyncPopulateTabBrowserTypeInGetData{
- "SyncPopulateTabBrowserTypeInGetData", base::FEATURE_ENABLED_BY_DEFAULT};
-
namespace {
// Maximum time we allow a local tab stay unmapped (i.e. closed) but not freed
@@ -50,9 +47,8 @@ bool ShouldSyncSessionWindow(SyncSessionsClient* sessions_client,
// Presentable means |foreign_session| must have syncable content.
bool IsPresentable(SyncSessionsClient* sessions_client,
const SyncedSession& foreign_session) {
- for (const auto& id_and_window : foreign_session.windows) {
- if (ShouldSyncSessionWindow(sessions_client,
- id_and_window.second->wrapped_window)) {
+ for (const auto& [window_id, window] : foreign_session.windows) {
+ if (ShouldSyncSessionWindow(sessions_client, window->wrapped_window)) {
return true;
}
}
@@ -64,13 +60,11 @@ bool IsPresentable(SyncSessionsClient* sessions_client,
bool IsValidSessionHeader(const sync_pb::SessionHeader& header) {
std::set<int> session_window_ids;
std::set<int> session_tab_ids;
- for (int i = 0; i < header.window_size(); ++i) {
- const sync_pb::SessionWindow& window = header.window(i);
+ for (const sync_pb::SessionWindow& window : header.window()) {
if (!session_window_ids.insert(window.window_id()).second)
return false;
- for (int j = 0; j < window.tab_size(); ++j) {
- const int tab_id = window.tab(j);
+ for (int tab_id : window.tab()) {
if (!session_tab_ids.insert(tab_id).second)
return false;
}
@@ -201,8 +195,9 @@ bool SyncedSessionTracker::LookupSessionWindows(
if (!session)
return false; // We have no record of this session.
- for (const auto& window_pair : session->synced_session.windows)
- windows->push_back(&window_pair.second->wrapped_window);
+ for (const auto& [window_id, window] : session->synced_session.windows) {
+ windows->push_back(&window->wrapped_window);
+ }
return true;
}
@@ -227,9 +222,6 @@ const sessions::SessionTab* SyncedSessionTracker::LookupSessionTab(
absl::optional<sync_pb::SessionWindow::BrowserType>
SyncedSessionTracker::LookupWindowType(const std::string& session_tag,
SessionID window_id) const {
- if (!base::FeatureList::IsEnabled(kSyncPopulateTabBrowserTypeInGetData))
- return absl::nullopt;
-
const TrackedSession* session = LookupTrackedSession(session_tag);
if (!session)
return absl::nullopt;
@@ -286,17 +278,16 @@ void SyncedSessionTracker::ResetSessionTracking(
const std::string& session_tag) {
TrackedSession* session = GetTrackedSession(session_tag);
- for (auto& window_pair : session->synced_session.windows) {
+ for (auto& [window_id, window] : session->synced_session.windows) {
// First unmap the tabs in the window.
- for (auto& tab : window_pair.second->wrapped_window.tabs) {
+ for (auto& tab : window->wrapped_window.tabs) {
SessionID tab_id = tab->tab_id;
session->unmapped_tabs[tab_id] = std::move(tab);
}
- window_pair.second->wrapped_window.tabs.clear();
+ window->wrapped_window.tabs.clear();
// Then unmap the window itself.
- session->unmapped_windows[window_pair.first] =
- std::move(window_pair.second);
+ session->unmapped_windows[window_id] = std::move(window);
}
session->synced_session.windows.clear();
}
@@ -339,8 +330,8 @@ std::vector<const SyncedSession*> SyncedSessionTracker::LookupSessions(
SessionLookup lookup,
bool exclude_local_session) const {
std::vector<const SyncedSession*> sessions;
- for (const auto& session_pair : session_map_) {
- const SyncedSession& session = session_pair.second.synced_session;
+ for (const auto& [session_tag, tracked_session] : session_map_) {
+ const SyncedSession& session = tracked_session.synced_session;
if (lookup == PRESENTABLE && !IsPresentable(sessions_client_, session)) {
continue;
}
@@ -349,8 +340,8 @@ std::vector<const SyncedSession*> SyncedSessionTracker::LookupSessions(
// IsRecentLocalCacheGuid() is used to filter out older values of the
// local cache GUID.
if (exclude_local_session &&
- (session_pair.first == local_session_tag_ ||
- sessions_client_->IsRecentLocalCacheGuid(session_pair.first))) {
+ (session_tag == local_session_tag_ ||
+ sessions_client_->IsRecentLocalCacheGuid(session_tag))) {
continue;
}
sessions.push_back(&session);
@@ -366,8 +357,9 @@ void SyncedSessionTracker::CleanupSessionImpl(
if (!session)
return;
- for (const auto& window_pair : session->unmapped_windows)
- session->synced_window_map.erase(window_pair.first);
+ for (const auto& [window_id, window] : session->unmapped_windows) {
+ session->synced_window_map.erase(window_id);
+ }
session->unmapped_windows.clear();
int num_unmapped_and_unsynced = 0;
@@ -382,9 +374,7 @@ void SyncedSessionTracker::CleanupSessionImpl(
if ((time_since_last_modified < kMaxUnmappedButUnsyncedLocalTabAge) &&
num_unmapped_and_unsynced < kMaxUnmappedButUnsyncedLocalTabCount &&
- is_tab_node_unsynced_cb.Run(tab_node_id) &&
- base::FeatureList::IsEnabled(
- kDeferRecyclingOfSyncTabNodesIfUnsynced)) {
+ is_tab_node_unsynced_cb.Run(tab_node_id)) {
// Our caller has decided that this tab node cannot be reused at this
// point because there are pending changes to be committed that would
// otherwise be lost). Hence, it stays unmapped but we do not free the
@@ -475,19 +465,19 @@ void SyncedSessionTracker::PutTabInWindow(const std::string& session_tag,
// The tab has already been mapped, possibly because of the tab node id
// being reused across tabs. Find the existing tab and move it to the right
// window.
- for (auto& window_iter_pair : GetSession(session_tag)->windows) {
- auto tab_iter = std::find_if(
- window_iter_pair.second->wrapped_window.tabs.begin(),
- window_iter_pair.second->wrapped_window.tabs.end(),
- [&tab_ptr](const std::unique_ptr<sessions::SessionTab>& tab) {
- return tab.get() == tab_ptr;
+ for (auto& [existing_window_id, existing_window] :
+ GetSession(session_tag)->windows) {
+ auto existing_tab_iter = base::ranges::find(
+ existing_window->wrapped_window.tabs, tab_ptr,
+ [](const std::unique_ptr<sessions::SessionTab>& tab) {
+ return tab.get();
});
- if (tab_iter != window_iter_pair.second->wrapped_window.tabs.end()) {
- tab = std::move(*tab_iter);
- window_iter_pair.second->wrapped_window.tabs.erase(tab_iter);
+ if (existing_tab_iter != existing_window->wrapped_window.tabs.end()) {
+ tab = std::move(*existing_tab_iter);
+ existing_window->wrapped_window.tabs.erase(existing_tab_iter);
DVLOG(1) << "Moving tab " << tab_id << " from window "
- << window_iter_pair.first << " to " << window_id;
+ << existing_window_id << " to " << window_id;
break;
}
}
@@ -643,15 +633,16 @@ void SyncedSessionTracker::ReassociateLocalTab(int tab_node_id,
session->unmapped_tabs.erase(unmapped_tabs_iter);
} else {
sessions::SessionTab* new_tab_ptr = new_tab_iter->second;
- for (auto& window_iter_pair : session->synced_session.windows) {
- auto& window_tabs = window_iter_pair.second->wrapped_window.tabs;
- auto tab_iter = std::find_if(
- window_tabs.begin(), window_tabs.end(),
- [&new_tab_ptr](const std::unique_ptr<sessions::SessionTab>& tab) {
- return tab.get() == new_tab_ptr;
+ for (auto& [existing_window_id, existing_window] :
+ session->synced_session.windows) {
+ auto& existing_window_tabs = existing_window->wrapped_window.tabs;
+ auto tab_iter = base::ranges::find(
+ existing_window_tabs, new_tab_ptr,
+ [](const std::unique_ptr<sessions::SessionTab>& tab) {
+ return tab.get();
});
- if (tab_iter != window_tabs.end()) {
- window_tabs.erase(tab_iter);
+ if (tab_iter != existing_window_tabs.end()) {
+ existing_window_tabs.erase(tab_iter);
break;
}
}
@@ -813,8 +804,7 @@ void SerializePartialTrackerToSpecifics(
const base::RepeatingCallback<void(const std::string& session_name,
sync_pb::SessionSpecifics* specifics)>&
output_cb) {
- for (const auto& session_entry : session_tag_to_node_ids) {
- const std::string& session_tag = session_entry.first;
+ for (const auto& [session_tag, node_ids] : session_tag_to_node_ids) {
const SyncedSession* session = tracker.LookupSession(session_tag);
if (!session) {
// Unknown session.
@@ -824,7 +814,7 @@ void SerializePartialTrackerToSpecifics(
const std::set<int> known_tab_node_ids =
tracker.LookupTabNodeIds(session_tag);
- for (int tab_node_id : session_entry.second) {
+ for (int tab_node_id : node_ids) {
// Header entity.
if (tab_node_id == TabNodePool::kInvalidTabNodeID) {
sync_pb::SessionSpecifics header_pb;
diff --git a/chromium/components/sync_sessions/synced_session_tracker.h b/chromium/components/sync_sessions/synced_session_tracker.h
index ecd1e331107..a004653cd7d 100644
--- a/chromium/components/sync_sessions/synced_session_tracker.h
+++ b/chromium/components/sync_sessions/synced_session_tracker.h
@@ -13,7 +13,7 @@
#include <string>
#include <vector>
-#include "base/feature_list.h"
+#include "base/callback_forward.h"
#include "base/memory/raw_ptr.h"
#include "components/sessions/core/session_id.h"
#include "components/sessions/core/session_types.h"
@@ -26,12 +26,6 @@ namespace sync_sessions {
class SyncSessionsClient;
-// TODO(crbug.com/882489): Remove feature toggle during code cleanup when a
-// satisfying solution is found for closed tabs.
-extern const base::Feature kDeferRecyclingOfSyncTabNodesIfUnsynced;
-
-extern const base::Feature kSyncPopulateTabBrowserTypeInGetData;
-
// Class to manage synced sessions. The tracker will own all SyncedSession
// and SyncedSessionTab objects it creates, and deletes them appropriately on
// destruction.
diff --git a/chromium/components/sync_sessions/synced_session_tracker_unittest.cc b/chromium/components/sync_sessions/synced_session_tracker_unittest.cc
index f6065cbf9fd..9d7beee4a76 100644
--- a/chromium/components/sync_sessions/synced_session_tracker_unittest.cc
+++ b/chromium/components/sync_sessions/synced_session_tracker_unittest.cc
@@ -8,7 +8,6 @@
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/mock_callback.h"
-#include "base/test/scoped_feature_list.h"
#include "components/sessions/core/serialized_navigation_entry_test_helper.h"
#include "components/sync_sessions/mock_sync_sessions_client.h"
#include "components/sync_sessions/synced_tab_delegate.h"
@@ -95,9 +94,9 @@ class SyncedSessionTrackerTest : public testing::Test {
// Now traverse the SyncedSession tree to verify the mapped tabs all match
// up.
int mapped_tab_count = 0;
- for (auto& window_pair : session->synced_session.windows) {
- mapped_tab_count += window_pair.second->wrapped_window.tabs.size();
- for (auto& tab : window_pair.second->wrapped_window.tabs) {
+ for (auto& [window_id, window] : session->synced_session.windows) {
+ mapped_tab_count += window->wrapped_window.tabs.size();
+ for (auto& tab : window->wrapped_window.tabs) {
const auto tab_map_it = session->synced_tab_map.find(tab->tab_id);
if (tab_map_it == session->synced_tab_map.end()) {
return AssertionFailure() << "Tab ID " << tab->tab_id.id()
@@ -113,21 +112,19 @@ class SyncedSessionTrackerTest : public testing::Test {
// Wrap up by verifying all unmapped tabs are tracked.
int unmapped_tab_count = session->unmapped_tabs.size();
- for (const auto& tab_pair : session->unmapped_tabs) {
- if (tab_pair.first != tab_pair.second->tab_id) {
- return AssertionFailure()
- << "Unmapped tab " << tab_pair.second->tab_id.id()
- << " associated with wrong tab " << tab_pair.first;
+ for (const auto& [id, tab] : session->unmapped_tabs) {
+ if (id != tab->tab_id) {
+ return AssertionFailure() << "Unmapped tab " << tab->tab_id.id()
+ << " associated with wrong tab " << id;
}
- const auto tab_map_it =
- session->synced_tab_map.find(tab_pair.second->tab_id);
+ const auto tab_map_it = session->synced_tab_map.find(tab->tab_id);
if (tab_map_it == session->synced_tab_map.end()) {
- return AssertionFailure() << "Unmapped tab " << tab_pair.second->tab_id
+ return AssertionFailure() << "Unmapped tab " << tab->tab_id
<< " has no corresponding synced tab entry";
}
- if (tab_map_it->second != tab_pair.second.get()) {
+ if (tab_map_it->second != tab.get()) {
return AssertionFailure()
- << "Unmapped tab " << tab_pair.second->tab_id.id()
+ << "Unmapped tab " << tab->tab_id.id()
<< " does not match synced tab map " << tab_map_it->second;
}
}
@@ -487,59 +484,7 @@ TEST_F(SyncedSessionTrackerTest, DeleteForeignTab) {
ASSERT_TRUE(VerifyTabIntegrity(kTag));
}
-TEST_F(SyncedSessionTrackerTest, CleanupLocalTabsWithoutDeferredRecycling) {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitWithFeatures(
- /*enabled_features=*/{},
- /*disabled_features=*/{kDeferRecyclingOfSyncTabNodesIfUnsynced,
- kTabNodePoolImmediateDeletion});
-
- tracker_.InitLocalSession(kTag, kSessionName, kDeviceType);
-
- // Start with two restored tab nodes.
- tracker_.ReassociateLocalTab(kTabNode1, kTab1);
- tracker_.ReassociateLocalTab(kTabNode2, kTab2);
- EXPECT_TRUE(
- tracker_.CleanupLocalTabs(is_tab_node_unsynced_cb_.Get()).empty());
-
- // Associate with no tabs. The tab pool should now be full.
- tracker_.ResetSessionTracking(kTag);
- EXPECT_TRUE(
- tracker_.CleanupLocalTabs(is_tab_node_unsynced_cb_.Get()).empty());
-
- // Associate with only 1 tab open. A tab node should be reused.
- tracker_.ResetSessionTracking(kTag);
- tracker_.PutWindowInSession(kTag, kWindow1);
- tracker_.PutTabInWindow(kTag, kWindow1, kTab1);
- EXPECT_EQ(kTabNode1, tracker_.AssociateLocalTabWithFreeTabNode(kTab1));
- EXPECT_TRUE(
- tracker_.CleanupLocalTabs(is_tab_node_unsynced_cb_.Get()).empty());
-
- // Simulate a tab opening, which should use the last free tab node.
- EXPECT_EQ(kTabNode2, tracker_.AssociateLocalTabWithFreeTabNode(kTab2));
- EXPECT_EQ(kTabNode2, tracker_.LookupTabNodeFromTabId(kTag, kTab2));
-
- // Simulate another tab opening, which should create a new associated tab
- // node.
- EXPECT_EQ(kTabNode3, tracker_.AssociateLocalTabWithFreeTabNode(kTab3));
- EXPECT_EQ(kTabNode3, tracker_.LookupTabNodeFromTabId(kTag, kTab3));
-
- // Previous tabs should still be associated.
- EXPECT_EQ(kTabNode1, tracker_.LookupTabNodeFromTabId(kTag, kTab1));
- EXPECT_EQ(kTabNode2, tracker_.LookupTabNodeFromTabId(kTag, kTab2));
-
- // Associate with no tabs. All tabs should be freed again, and the pool
- // should now be full.
- tracker_.ResetSessionTracking(kTag);
- EXPECT_TRUE(
- tracker_.CleanupLocalTabs(is_tab_node_unsynced_cb_.Get()).empty());
- ASSERT_TRUE(VerifyTabIntegrity(kTag));
-}
-
TEST_F(SyncedSessionTrackerTest, CleanupLocalTabs) {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitAndEnableFeature(kDeferRecyclingOfSyncTabNodesIfUnsynced);
-
tracker_.InitLocalSession(kTag, kSessionName, kDeviceType);
// Start with four restored tab nodes, one of which is mapped (|kTab1|).
diff --git a/chromium/components/sync_sessions/synced_tab_delegate.h b/chromium/components/sync_sessions/synced_tab_delegate.h
index bf48b06207b..9c7c6969731 100644
--- a/chromium/components/sync_sessions/synced_tab_delegate.h
+++ b/chromium/components/sync_sessions/synced_tab_delegate.h
@@ -11,7 +11,6 @@
#include "components/sessions/core/serialized_navigation_entry.h"
#include "components/sessions/core/session_id.h"
-#include "ui/base/page_transition_types.h"
#include "url/gurl.h"
namespace sync_sessions {
@@ -43,15 +42,13 @@ class SyncedTabDelegate {
virtual int GetCurrentEntryIndex() const = 0;
virtual int GetEntryCount() const = 0;
virtual GURL GetVirtualURLAtIndex(int i) const = 0;
- virtual GURL GetFaviconURLAtIndex(int i) const = 0;
- virtual ui::PageTransition GetTransitionAtIndex(int i) const = 0;
virtual std::string GetPageLanguageAtIndex(int i) const = 0;
virtual void GetSerializedNavigationAtIndex(
int i,
sessions::SerializedNavigationEntry* serialized_entry) const = 0;
- // Supervised user related methods.
- virtual bool ProfileIsSupervised() const = 0;
+ // Methods to restrict navigation for child account users.
+ virtual bool ProfileHasChildAccount() const = 0;
virtual const std::vector<
std::unique_ptr<const sessions::SerializedNavigationEntry>>*
GetBlockedNavigations() const = 0;
diff --git a/chromium/components/sync_sessions/tab_node_pool.cc b/chromium/components/sync_sessions/tab_node_pool.cc
index db03ace58c0..f9c2803e658 100644
--- a/chromium/components/sync_sessions/tab_node_pool.cc
+++ b/chromium/components/sync_sessions/tab_node_pool.cc
@@ -15,12 +15,6 @@
namespace sync_sessions {
-const size_t TabNodePool::kFreeNodesLowWatermark = 25;
-const size_t TabNodePool::kFreeNodesHighWatermark = 100;
-
-const base::Feature kTabNodePoolImmediateDeletion{
- "TabNodePoolImmediateDeletion", base::FEATURE_ENABLED_BY_DEFAULT};
-
TabNodePool::TabNodePool() : max_used_tab_node_id_(kInvalidTabNodeID) {}
// static
@@ -147,44 +141,23 @@ SessionID TabNodePool::GetTabIdFromTabNodeId(int tab_node_id) const {
}
std::set<int> TabNodePool::CleanupFreeTabNodes() {
- if (base::FeatureList::IsEnabled(kTabNodePoolImmediateDeletion)) {
- // Convert all free nodes into missing nodes, each representing a deletion.
- missing_nodes_pool_.insert(free_nodes_pool_.begin(),
- free_nodes_pool_.end());
- std::set<int> deleted_node_ids = std::move(free_nodes_pool_);
- free_nodes_pool_.clear();
-
- // As an optimization to save memory, update |max_used_tab_node_id_| and
- // shrink |missing_nodes_pool_| appropriately.
- if (nodeid_tabid_map_.empty()) {
- max_used_tab_node_id_ = kInvalidTabNodeID;
- } else {
- max_used_tab_node_id_ = nodeid_tabid_map_.rbegin()->first;
- }
-
- missing_nodes_pool_.erase(
- missing_nodes_pool_.upper_bound(max_used_tab_node_id_),
- missing_nodes_pool_.end());
-
- return deleted_node_ids;
+ // Convert all free nodes into missing nodes, each representing a deletion.
+ missing_nodes_pool_.insert(free_nodes_pool_.begin(), free_nodes_pool_.end());
+ std::set<int> deleted_node_ids = std::move(free_nodes_pool_);
+ free_nodes_pool_.clear();
+
+ // As an optimization to save memory, update |max_used_tab_node_id_| and
+ // shrink |missing_nodes_pool_| appropriately.
+ if (nodeid_tabid_map_.empty()) {
+ max_used_tab_node_id_ = kInvalidTabNodeID;
+ } else {
+ max_used_tab_node_id_ = nodeid_tabid_map_.rbegin()->first;
}
- // If number of free nodes exceed kFreeNodesHighWatermark,
- // delete sync nodes till number reaches kFreeNodesLowWatermark.
- // Note: This logic is to mitigate temporary disassociation issues with old
- // clients: https://crbug.com/259918. Newer versions do not need this.
- if (free_nodes_pool_.size() <= kFreeNodesHighWatermark) {
- return std::set<int>();
- }
+ missing_nodes_pool_.erase(
+ missing_nodes_pool_.upper_bound(max_used_tab_node_id_),
+ missing_nodes_pool_.end());
- std::set<int> deleted_node_ids;
- while (free_nodes_pool_.size() > kFreeNodesLowWatermark) {
- // We delete the largest IDs first, to achieve more compaction.
- const int tab_node_id = *free_nodes_pool_.rbegin();
- deleted_node_ids.insert(tab_node_id);
- missing_nodes_pool_.insert(tab_node_id);
- free_nodes_pool_.erase(tab_node_id);
- }
return deleted_node_ids;
}
@@ -205,8 +178,8 @@ void TabNodePool::DeleteTabNode(int tab_node_id) {
std::set<int> TabNodePool::GetAllTabNodeIds() const {
std::set<int> tab_node_ids = free_nodes_pool_;
- for (const auto& entry : nodeid_tabid_map_) {
- tab_node_ids.insert(entry.first);
+ for (const auto& [tab_node_id, tab_id] : nodeid_tabid_map_) {
+ tab_node_ids.insert(tab_node_id);
}
return tab_node_ids;
}
diff --git a/chromium/components/sync_sessions/tab_node_pool.h b/chromium/components/sync_sessions/tab_node_pool.h
index dad3ae9a544..67aeb76eb8c 100644
--- a/chromium/components/sync_sessions/tab_node_pool.h
+++ b/chromium/components/sync_sessions/tab_node_pool.h
@@ -10,7 +10,6 @@
#include <map>
#include <set>
-#include "base/feature_list.h"
#include "components/sessions/core/session_id.h"
namespace sync_sessions {
@@ -27,10 +26,6 @@ namespace sync_sessions {
// 1. Associated : Sync node is used and associated with a tab.
// 2. Free : Sync node is unused.
-// TODO(crbug.com/882489): Remove feature toggle during code cleanup when a
-// satisfying solution is found for closed tabs.
-extern const base::Feature kTabNodePoolImmediateDeletion;
-
class TabNodePool {
public:
TabNodePool();
@@ -40,13 +35,6 @@ class TabNodePool {
~TabNodePool();
- // If free nodes > kFreeNodesHighWatermark, delete all free nodes until
- // free nodes <= kFreeNodesLowWatermark.
- static const size_t kFreeNodesLowWatermark;
-
- // Maximum limit of FreeNodes allowed on the client.
- static const size_t kFreeNodesHighWatermark;
-
static const int kInvalidTabNodeID;
// Returns the tab node associated with |tab_id| or kInvalidTabNodeID if
diff --git a/chromium/components/sync_sessions/tab_node_pool_unittest.cc b/chromium/components/sync_sessions/tab_node_pool_unittest.cc
index 09c959f5ecb..865fc97e108 100644
--- a/chromium/components/sync_sessions/tab_node_pool_unittest.cc
+++ b/chromium/components/sync_sessions/tab_node_pool_unittest.cc
@@ -6,7 +6,6 @@
#include <vector>
-#include "base/test/scoped_feature_list.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -152,41 +151,6 @@ TEST_F(SyncTabNodePoolTest, AssociateWithFreeTabNode) {
EXPECT_EQ(0, pool_.AssociateWithFreeTabNode(kTabId3));
}
-TEST_F(SyncTabNodePoolTest, TabPoolFreeNodeWatermarkLimits) {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitAndDisableFeature(kTabNodePoolImmediateDeletion);
-
- // Allocate TabNodePool::kFreeNodesHighWatermark + 1 nodes and verify that
- // freeing the last node reduces the free node pool size to
- // kFreeNodesLowWatermark.
- std::vector<int> used_sync_ids;
- for (size_t i = 1; i <= TabNodePool::kFreeNodesHighWatermark + 1; ++i) {
- used_sync_ids.push_back(
- pool_.AssociateWithFreeTabNode(SessionID::FromSerializedValue(i)));
- }
-
- // Free all except one node.
- used_sync_ids.pop_back();
-
- for (size_t i = 1; i <= used_sync_ids.size(); ++i) {
- pool_.FreeTab(SessionID::FromSerializedValue(i));
- EXPECT_THAT(pool_.CleanupFreeTabNodes(), IsEmpty());
- }
-
- // Freeing the last sync node should drop the free nodes to
- // kFreeNodesLowWatermark.
- pool_.FreeTab(
- SessionID::FromSerializedValue(TabNodePool::kFreeNodesHighWatermark + 1));
- std::set<int> deleted_node_ids = pool_.CleanupFreeTabNodes();
- EXPECT_EQ(deleted_node_ids.size(), TabNodePool::kFreeNodesHighWatermark + 1 -
- TabNodePool::kFreeNodesLowWatermark);
- // Make sure the highest ones are deleted.
- EXPECT_EQ(0U,
- deleted_node_ids.count(TabNodePool::kFreeNodesLowWatermark - 1));
- EXPECT_NE(0U, deleted_node_ids.count(TabNodePool::kFreeNodesLowWatermark));
- EXPECT_NE(0U, deleted_node_ids.count(TabNodePool::kFreeNodesHighWatermark));
-}
-
TEST_F(SyncTabNodePoolTest, AssociateWithFreeTabNodesContiguous) {
pool_.ReassociateTabNode(/*tab_node_id=*/2, kTabId1);
EXPECT_EQ(0, pool_.AssociateWithFreeTabNode(kTabId2));
diff --git a/chromium/components/sync_sessions/test_matchers.cc b/chromium/components/sync_sessions/test_matchers.cc
index cfcdcbc0d58..43ffa3d8b88 100644
--- a/chromium/components/sync_sessions/test_matchers.cc
+++ b/chromium/components/sync_sessions/test_matchers.cc
@@ -5,7 +5,7 @@
#include "components/sync_sessions/test_matchers.h"
#include "components/sessions/core/session_id.h"
-#include "components/sync/engine/entity_data.h"
+#include "components/sync/protocol/entity_data.h"
#include "components/sync/protocol/session_specifics.pb.h"
#include "components/sync_sessions/synced_session.h"
@@ -164,15 +164,14 @@ class MatchesSyncedSessionMatcher
}
std::map<int, std::vector<int>> actual_window_id_to_tabs;
- for (const auto& id_and_window : actual->windows) {
- const SessionID actual_window_id = id_and_window.first;
- if (actual_window_id != id_and_window.second->wrapped_window.window_id) {
+ for (const auto& [actual_window_id, actual_window] : actual->windows) {
+ if (actual_window_id != actual_window->wrapped_window.window_id) {
*listener << " which has an inconsistent window representation";
return false;
}
actual_window_id_to_tabs.emplace(actual_window_id.id(),
std::vector<int>());
- for (const auto& tab : id_and_window.second->wrapped_window.tabs) {
+ for (const auto& tab : actual_window->wrapped_window.tabs) {
actual_window_id_to_tabs[actual_window_id.id()].push_back(
tab->tab_id.id());
}
diff --git a/chromium/components/sync_sessions/test_synced_window_delegates_getter.cc b/chromium/components/sync_sessions/test_synced_window_delegates_getter.cc
index 67146f0ca64..d7f06bd474e 100644
--- a/chromium/components/sync_sessions/test_synced_window_delegates_getter.cc
+++ b/chromium/components/sync_sessions/test_synced_window_delegates_getter.cc
@@ -85,16 +85,6 @@ GURL TestSyncedTabDelegate::GetVirtualURLAtIndex(int i) const {
return entries_[i]->virtual_url();
}
-GURL TestSyncedTabDelegate::GetFaviconURLAtIndex(int i) const {
- return GURL();
-}
-
-ui::PageTransition TestSyncedTabDelegate::GetTransitionAtIndex(int i) const {
- if (static_cast<size_t>(i) >= entries_.size())
- return ui::PAGE_TRANSITION_LINK;
- return entries_[i]->transition_type();
-}
-
std::string TestSyncedTabDelegate::GetPageLanguageAtIndex(int i) const {
DCHECK(static_cast<size_t>(i) < page_language_per_index_.size());
return page_language_per_index_[i];
@@ -128,12 +118,12 @@ std::string TestSyncedTabDelegate::GetExtensionAppId() const {
return std::string();
}
-bool TestSyncedTabDelegate::ProfileIsSupervised() const {
- return is_supervised_;
+bool TestSyncedTabDelegate::ProfileHasChildAccount() const {
+ return has_child_account_;
}
-void TestSyncedTabDelegate::set_is_supervised(bool is_supervised) {
- is_supervised_ = is_supervised;
+void TestSyncedTabDelegate::set_has_child_account(bool has_child_account) {
+ has_child_account_ = has_child_account;
}
const std::vector<std::unique_ptr<const sessions::SerializedNavigationEntry>>*
@@ -227,16 +217,6 @@ GURL PlaceholderTabDelegate::GetVirtualURLAtIndex(int i) const {
return GURL();
}
-GURL PlaceholderTabDelegate::GetFaviconURLAtIndex(int i) const {
- NOTREACHED();
- return GURL();
-}
-
-ui::PageTransition PlaceholderTabDelegate::GetTransitionAtIndex(int i) const {
- NOTREACHED();
- return ui::PageTransition();
-}
-
std::string PlaceholderTabDelegate::GetPageLanguageAtIndex(int i) const {
NOTREACHED();
return std::string();
@@ -248,7 +228,7 @@ void PlaceholderTabDelegate::GetSerializedNavigationAtIndex(
NOTREACHED();
}
-bool PlaceholderTabDelegate::ProfileIsSupervised() const {
+bool PlaceholderTabDelegate::ProfileHasChildAccount() const {
NOTREACHED();
return false;
}
@@ -427,10 +407,10 @@ TestSyncedWindowDelegatesGetter::GetSyncedWindowDelegates() {
}
const SyncedWindowDelegate* TestSyncedWindowDelegatesGetter::FindById(
- SessionID id) {
- for (auto window_iter_pair : delegates_) {
- if (window_iter_pair.second->GetSessionId() == id)
- return window_iter_pair.second;
+ SessionID session_id) {
+ for (const auto& [window_id, delegate] : delegates_) {
+ if (delegate->GetSessionId() == session_id)
+ return delegate;
}
return nullptr;
}
diff --git a/chromium/components/sync_sessions/test_synced_window_delegates_getter.h b/chromium/components/sync_sessions/test_synced_window_delegates_getter.h
index 86c6b83fd7b..185205acd03 100644
--- a/chromium/components/sync_sessions/test_synced_window_delegates_getter.h
+++ b/chromium/components/sync_sessions/test_synced_window_delegates_getter.h
@@ -50,8 +50,6 @@ class TestSyncedTabDelegate : public SyncedTabDelegate {
bool IsInitialBlankNavigation() const override;
int GetCurrentEntryIndex() const override;
GURL GetVirtualURLAtIndex(int i) const override;
- GURL GetFaviconURLAtIndex(int i) const override;
- ui::PageTransition GetTransitionAtIndex(int i) const override;
std::string GetPageLanguageAtIndex(int i) const override;
void GetSerializedNavigationAtIndex(
int i,
@@ -61,8 +59,8 @@ class TestSyncedTabDelegate : public SyncedTabDelegate {
SessionID GetSessionId() const override;
bool IsBeingDestroyed() const override;
std::string GetExtensionAppId() const override;
- bool ProfileIsSupervised() const override;
- void set_is_supervised(bool is_supervised);
+ bool ProfileHasChildAccount() const override;
+ void set_has_child_account(bool has_child_account);
const std::vector<std::unique_ptr<const sessions::SerializedNavigationEntry>>*
GetBlockedNavigations() const override;
bool IsPlaceholderTab() const override;
@@ -77,7 +75,7 @@ class TestSyncedTabDelegate : public SyncedTabDelegate {
const base::RepeatingCallback<void(SyncedTabDelegate*)> notify_cb_;
int current_entry_index_ = -1;
- bool is_supervised_ = false;
+ bool has_child_account_ = false;
std::vector<std::unique_ptr<const sessions::SerializedNavigationEntry>>
blocked_navigations_;
std::vector<std::unique_ptr<const sessions::SerializedNavigationEntry>>
@@ -109,13 +107,11 @@ class PlaceholderTabDelegate : public SyncedTabDelegate {
int GetCurrentEntryIndex() const override;
int GetEntryCount() const override;
GURL GetVirtualURLAtIndex(int i) const override;
- GURL GetFaviconURLAtIndex(int i) const override;
- ui::PageTransition GetTransitionAtIndex(int i) const override;
std::string GetPageLanguageAtIndex(int i) const override;
void GetSerializedNavigationAtIndex(
int i,
sessions::SerializedNavigationEntry* serialized_entry) const override;
- bool ProfileIsSupervised() const override;
+ bool ProfileHasChildAccount() const override;
const std::vector<std::unique_ptr<const sessions::SerializedNavigationEntry>>*
GetBlockedNavigations() const override;
bool ShouldSync(SyncSessionsClient* sessions_client) override;
@@ -191,7 +187,7 @@ class TestSyncedWindowDelegatesGetter : public SyncedWindowDelegatesGetter {
// SyncedWindowDelegatesGetter overrides.
SyncedWindowDelegateMap GetSyncedWindowDelegates() override;
- const SyncedWindowDelegate* FindById(SessionID id) override;
+ const SyncedWindowDelegate* FindById(SessionID session_id) override;
private:
class DummyRouter : public LocalSessionEventRouter {
diff --git a/chromium/components/sync_user_events/README.md b/chromium/components/sync_user_events/README.md
new file mode 100644
index 00000000000..5cb33a1ca9e
--- /dev/null
+++ b/chromium/components/sync_user_events/README.md
@@ -0,0 +1 @@
+See components/sync/README.md.
diff --git a/chromium/components/sync_user_events/user_event_sync_bridge.cc b/chromium/components/sync_user_events/user_event_sync_bridge.cc
index 0201c6d4f5f..9a4ad42630b 100644
--- a/chromium/components/sync_user_events/user_event_sync_bridge.cc
+++ b/chromium/components/sync_user_events/user_event_sync_bridge.cc
@@ -280,8 +280,8 @@ void UserEventSyncBridge::HandleGlobalIdChange(int64_t old_global_id,
// not be within our given range, this approach seems less error prone.
std::vector<std::unique_ptr<UserEventSpecifics>> affected;
- auto range = in_flight_nav_linked_events_.equal_range(old_global_id);
- for (auto iter = range.first; iter != range.second;) {
+ auto [begin, end] = in_flight_nav_linked_events_.equal_range(old_global_id);
+ for (auto iter = begin; iter != end;) {
DCHECK_EQ(old_global_id, iter->second.navigation_id());
affected.emplace_back(std::make_unique<UserEventSpecifics>(iter->second));
iter = in_flight_nav_linked_events_.erase(iter);
diff --git a/chromium/components/sync_user_events/user_event_sync_bridge_unittest.cc b/chromium/components/sync_user_events/user_event_sync_bridge_unittest.cc
index 526e0bfe8a8..21efb52e62a 100644
--- a/chromium/components/sync_user_events/user_event_sync_bridge_unittest.cc
+++ b/chromium/components/sync_user_events/user_event_sync_bridge_unittest.cc
@@ -152,8 +152,8 @@ class UserEventSyncBridgeTest : public testing::Test {
std::map<std::string, sync_pb::EntitySpecifics> storage_key_to_specifics;
if (batch != nullptr) {
while (batch->HasNext()) {
- const syncer::KeyAndData& pair = batch->Next();
- storage_key_to_specifics[pair.first] = pair.second->specifics;
+ auto [key, data] = batch->Next();
+ storage_key_to_specifics[key] = data->specifics;
}
}
return storage_key_to_specifics;
@@ -177,9 +177,8 @@ class UserEventSyncBridgeTest : public testing::Test {
std::unique_ptr<sync_pb::EntitySpecifics> specifics;
if (batch != nullptr && batch->HasNext()) {
- const syncer::KeyAndData& pair = batch->Next();
- specifics =
- std::make_unique<sync_pb::EntitySpecifics>(pair.second->specifics);
+ auto [key, data] = batch->Next();
+ specifics = std::make_unique<sync_pb::EntitySpecifics>(data->specifics);
EXPECT_FALSE(batch->HasNext());
}
return specifics;
diff --git a/chromium/components/system_media_controls/linux/system_media_controls_linux.cc b/chromium/components/system_media_controls/linux/system_media_controls_linux.cc
index 870f5c8f096..d353ddbe808 100644
--- a/chromium/components/system_media_controls/linux/system_media_controls_linux.cc
+++ b/chromium/components/system_media_controls/linux/system_media_controls_linux.cc
@@ -40,6 +40,13 @@ namespace {
constexpr int kNumMethodsToExport = 11;
+constexpr base::TimeDelta kUpdatePositionInterval = base::Milliseconds(100);
+
+const char kMprisAPINoTrackPath[] = "/org/mpris/MediaPlayer2/TrackList/NoTrack";
+
+const char kMprisAPICurrentTrackPathFormatString[] =
+ "/org/chromium/MediaPlayer2/TrackList/Track%s";
+
} // namespace
const char kMprisAPIServiceNameFormatString[] =
@@ -47,6 +54,7 @@ const char kMprisAPIServiceNameFormatString[] =
const char kMprisAPIObjectPath[] = "/org/mpris/MediaPlayer2";
const char kMprisAPIInterfaceName[] = "org.mpris.MediaPlayer2";
const char kMprisAPIPlayerInterfaceName[] = "org.mpris.MediaPlayer2.Player";
+const char kMprisAPISignalSeeked[] = "Seeked";
SystemMediaControlsLinux::SystemMediaControlsLinux(
const std::string& product_name)
@@ -99,6 +107,11 @@ void SystemMediaControlsLinux::SetIsPlayPauseEnabled(bool value) {
DbusBoolean(value));
}
+void SystemMediaControlsLinux::SetIsSeekToEnabled(bool value) {
+ properties_->SetProperty(kMprisAPIPlayerInterfaceName, "CanSeek",
+ DbusBoolean(value));
+}
+
void SystemMediaControlsLinux::SetPlaybackStatus(PlaybackStatus value) {
auto status = [&]() {
switch (value) {
@@ -112,6 +125,25 @@ void SystemMediaControlsLinux::SetPlaybackStatus(PlaybackStatus value) {
};
properties_->SetProperty(kMprisAPIPlayerInterfaceName, "PlaybackStatus",
status());
+
+ playing_ = (value == PlaybackStatus::kPlaying);
+ if (playing_ && position_.has_value())
+ StartPositionUpdateTimer();
+ else
+ StopPositionUpdateTimer();
+}
+
+void SystemMediaControlsLinux::SetID(const std::string* value) {
+ if (!value) {
+ ClearTrackId();
+ return;
+ }
+
+ const std::string track_id =
+ base::StringPrintf(kMprisAPICurrentTrackPathFormatString, value->c_str());
+ SetMetadataPropertyInternal(
+ "mpris:trackid",
+ MakeDbusVariant(DbusObjectPath(dbus::ObjectPath(track_id))));
}
void SystemMediaControlsLinux::SetTitle(const std::u16string& value) {
@@ -130,10 +162,21 @@ void SystemMediaControlsLinux::SetAlbum(const std::u16string& value) {
"xesam:album", MakeDbusVariant(DbusString(base::UTF16ToUTF8(value))));
}
+void SystemMediaControlsLinux::SetPosition(
+ const media_session::MediaPosition& position) {
+ position_ = position;
+ UpdatePosition(/*emit_signal=*/true);
+
+ if (playing_)
+ StartPositionUpdateTimer();
+}
+
void SystemMediaControlsLinux::ClearMetadata() {
SetTitle(std::u16string());
SetArtist(std::u16string());
SetAlbum(std::u16string());
+ ClearTrackId();
+ ClearPosition();
}
std::string SystemMediaControlsLinux::GetServiceName() const {
@@ -244,8 +287,12 @@ void SystemMediaControlsLinux::InitializeDbusInterface() {
export_method(kMprisAPIPlayerInterfaceName, "Play",
base::BindRepeating(&SystemMediaControlsLinux::Play,
base::Unretained(this)));
- export_unhandled_method(kMprisAPIPlayerInterfaceName, "Seek");
- export_unhandled_method(kMprisAPIPlayerInterfaceName, "SetPosition");
+ export_method(kMprisAPIPlayerInterfaceName, "Seek",
+ base::BindRepeating(&SystemMediaControlsLinux::Seek,
+ base::Unretained(this)));
+ export_method(kMprisAPIPlayerInterfaceName, "SetPosition",
+ base::BindRepeating(&SystemMediaControlsLinux::SetPositionMpris,
+ base::Unretained(this)));
export_unhandled_method(kMprisAPIPlayerInterfaceName, "OpenUri");
DCHECK_EQ(kNumMethodsToExport, num_methods_attempted_to_export);
@@ -325,6 +372,45 @@ void SystemMediaControlsLinux::Play(
std::move(response_sender).Run(dbus::Response::FromMethodCall(method_call));
}
+void SystemMediaControlsLinux::Seek(
+ dbus::MethodCall* method_call,
+ dbus::ExportedObject::ResponseSender response_sender) {
+ int64_t offset;
+ dbus::MessageReader reader(method_call);
+ if (!reader.PopInt64(&offset)) {
+ std::move(response_sender).Run(dbus::Response::FromMethodCall(method_call));
+ return;
+ }
+
+ for (SystemMediaControlsObserver& obs : observers_)
+ obs.OnSeek(base::Microseconds(offset));
+
+ std::move(response_sender).Run(dbus::Response::FromMethodCall(method_call));
+}
+
+void SystemMediaControlsLinux::SetPositionMpris(
+ dbus::MethodCall* method_call,
+ dbus::ExportedObject::ResponseSender response_sender) {
+ dbus::ObjectPath track_id;
+ int64_t position;
+ dbus::MessageReader reader(method_call);
+
+ if (!reader.PopObjectPath(&track_id)) {
+ std::move(response_sender).Run(dbus::Response::FromMethodCall(method_call));
+ return;
+ }
+
+ if (!reader.PopInt64(&position)) {
+ std::move(response_sender).Run(dbus::Response::FromMethodCall(method_call));
+ return;
+ }
+
+ for (SystemMediaControlsObserver& obs : observers_)
+ obs.OnSeekTo(base::Microseconds(position));
+
+ std::move(response_sender).Run(dbus::Response::FromMethodCall(method_call));
+}
+
void SystemMediaControlsLinux::DoNothing(
dbus::MethodCall* method_call,
dbus::ExportedObject::ResponseSender response_sender) {
@@ -343,6 +429,66 @@ void SystemMediaControlsLinux::SetMetadataPropertyInternal(
properties_->PropertyUpdated(kMprisAPIPlayerInterfaceName, "Metadata");
}
+void SystemMediaControlsLinux::ClearTrackId() {
+ SetMetadataPropertyInternal(
+ "mpris:trackid",
+ MakeDbusVariant(DbusObjectPath(dbus::ObjectPath(kMprisAPINoTrackPath))));
+}
+
+void SystemMediaControlsLinux::ClearPosition() {
+ position_ = absl::nullopt;
+ StopPositionUpdateTimer();
+ UpdatePosition(/*emit_signal=*/true);
+}
+
+void SystemMediaControlsLinux::UpdatePosition(bool emit_signal) {
+ int64_t position = 0;
+ double rate = 1.0;
+ int64_t duration = 0;
+
+ if (position_.has_value()) {
+ position = position_->GetPosition().InMicroseconds();
+ rate = position_->playback_rate();
+ duration = position_->duration().InMicroseconds();
+ }
+
+ // We never emit a PropertiesChanged signal for the "Position" property. We
+ // only emit "Seeked" signals.
+ properties_->SetProperty(kMprisAPIPlayerInterfaceName, "Position",
+ DbusInt64(position), /*emit_signal=*/false);
+
+ properties_->SetProperty(kMprisAPIPlayerInterfaceName, "Rate",
+ DbusDouble(rate), emit_signal);
+ SetMetadataPropertyInternal("mpris:length",
+ MakeDbusVariant(DbusInt64(duration)));
+
+ if (!service_ready_ || !emit_signal || !position_.has_value())
+ return;
+
+ dbus::Signal seeked_signal(kMprisAPIPlayerInterfaceName,
+ kMprisAPISignalSeeked);
+ dbus::MessageWriter writer(&seeked_signal);
+ writer.AppendInt64(position);
+ exported_object_->SendSignal(&seeked_signal);
+}
+
+void SystemMediaControlsLinux::StartPositionUpdateTimer() {
+ // The timer should only run when the media is playing and has a position.
+ DCHECK(playing_);
+ DCHECK(position_.has_value());
+
+ // base::Unretained(this) is safe here since |this| owns
+ // |position_update_timer_|.
+ position_update_timer_.Start(
+ FROM_HERE, kUpdatePositionInterval,
+ base::BindRepeating(&SystemMediaControlsLinux::UpdatePosition,
+ base::Unretained(this), /*emit_signal=*/false));
+}
+
+void SystemMediaControlsLinux::StopPositionUpdateTimer() {
+ position_update_timer_.Stop();
+}
+
} // namespace internal
} // namespace system_media_controls
diff --git a/chromium/components/system_media_controls/linux/system_media_controls_linux.h b/chromium/components/system_media_controls/linux/system_media_controls_linux.h
index 6eebaf4edab..a6480b45b05 100644
--- a/chromium/components/system_media_controls/linux/system_media_controls_linux.h
+++ b/chromium/components/system_media_controls/linux/system_media_controls_linux.h
@@ -35,6 +35,8 @@ COMPONENT_EXPORT(SYSTEM_MEDIA_CONTROLS)
extern const char kMprisAPIInterfaceName[];
COMPONENT_EXPORT(SYSTEM_MEDIA_CONTROLS)
extern const char kMprisAPIPlayerInterfaceName[];
+COMPONENT_EXPORT(SYSTEM_MEDIA_CONTROLS)
+extern const char kMprisAPISignalSeeked[];
// A D-Bus service conforming to the MPRIS spec:
// https://specifications.freedesktop.org/mpris-spec/latest/
@@ -59,11 +61,14 @@ class COMPONENT_EXPORT(SYSTEM_MEDIA_CONTROLS) SystemMediaControlsLinux
void SetIsPreviousEnabled(bool value) override;
void SetIsPlayPauseEnabled(bool value) override;
void SetIsStopEnabled(bool value) override {}
+ void SetIsSeekToEnabled(bool value) override;
void SetPlaybackStatus(PlaybackStatus value) override;
+ void SetID(const std::string* value) override;
void SetTitle(const std::u16string& value) override;
void SetArtist(const std::u16string& value) override;
void SetAlbum(const std::u16string& value) override;
void SetThumbnail(const SkBitmap& bitmap) override {}
+ void SetPosition(const media_session::MediaPosition& position) override;
void ClearThumbnail() override {}
void ClearMetadata() override;
void UpdateDisplay() override {}
@@ -96,6 +101,10 @@ class COMPONENT_EXPORT(SYSTEM_MEDIA_CONTROLS) SystemMediaControlsLinux
dbus::ExportedObject::ResponseSender response_sender);
void Play(dbus::MethodCall* method_call,
dbus::ExportedObject::ResponseSender response_sender);
+ void Seek(dbus::MethodCall* method_call,
+ dbus::ExportedObject::ResponseSender response_sender);
+ void SetPositionMpris(dbus::MethodCall* method_call,
+ dbus::ExportedObject::ResponseSender response_sender);
// Used for API methods we don't support.
void DoNothing(dbus::MethodCall* method_call,
@@ -106,6 +115,20 @@ class COMPONENT_EXPORT(SYSTEM_MEDIA_CONTROLS) SystemMediaControlsLinux
void SetMetadataPropertyInternal(const std::string& property_name,
DbusVariant&& new_value);
+ void ClearTrackId();
+
+ void ClearPosition();
+
+ // Updates MPRIS with our current position.
+ void UpdatePosition(bool emit_signal);
+
+ void StartPositionUpdateTimer();
+ void StopPositionUpdateTimer();
+
+ absl::optional<media_session::MediaPosition> position_;
+ base::RepeatingTimer position_update_timer_;
+ bool playing_ = false;
+
const std::string product_name_;
std::unique_ptr<DbusProperties> properties_;
diff --git a/chromium/components/system_media_controls/linux/system_media_controls_linux_unittest.cc b/chromium/components/system_media_controls/linux/system_media_controls_linux_unittest.cc
index 121876b82eb..4ded2634f6f 100644
--- a/chromium/components/system_media_controls/linux/system_media_controls_linux_unittest.cc
+++ b/chromium/components/system_media_controls/linux/system_media_controls_linux_unittest.cc
@@ -49,6 +49,7 @@ class MockSystemMediaControlsObserver : public SystemMediaControlsObserver {
MOCK_METHOD0(OnPlayPause, void());
MOCK_METHOD0(OnStop, void());
MOCK_METHOD0(OnPlay, void());
+ MOCK_METHOD1(OnSeek, void(const base::TimeDelta&));
MOCK_METHOD1(OnSeekTo, void(const base::TimeDelta&));
};
@@ -56,7 +57,8 @@ class SystemMediaControlsLinuxTest : public testing::Test,
public SystemMediaControlsObserver {
public:
SystemMediaControlsLinuxTest()
- : task_environment_(base::test::TaskEnvironment::MainThreadType::UI) {}
+ : task_environment_(base::test::TaskEnvironment::MainThreadType::UI,
+ base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
SystemMediaControlsLinuxTest(const SystemMediaControlsLinuxTest&) = delete;
SystemMediaControlsLinuxTest& operator=(const SystemMediaControlsLinuxTest&) =
@@ -87,12 +89,72 @@ class SystemMediaControlsLinuxTest : public testing::Test,
response_wait_loop_->Run();
}
+ void CallSeekAndBlock(bool is_seek_to, int64_t offset_or_position) {
+ response_wait_loop_ = std::make_unique<base::RunLoop>();
+
+ // We need to supply a serial or the test will crash.
+ const std::string method_name = is_seek_to ? "SetPosition" : "Seek";
+ dbus::MethodCall method_call(kMprisAPIPlayerInterfaceName, method_name);
+ method_call.SetSerial(kFakeSerial);
+
+ dbus::MessageWriter writer(&method_call);
+
+ if (is_seek_to)
+ writer.AppendObjectPath(
+ dbus::ObjectPath("/org/chromium/MediaPlayer2/TrackList/TrackFooId"));
+
+ writer.AppendInt64(offset_or_position);
+
+ // Call the method and await a response.
+ player_interface_exported_methods_[method_name].Run(
+ &method_call,
+ base::BindRepeating(&SystemMediaControlsLinuxTest::OnResponse,
+ base::Unretained(this)));
+ response_wait_loop_->Run();
+ }
+
+ int64_t GetCurrentPositionValue() {
+ base::RunLoop wait_loop;
+
+ // We need to supply a serial or the test will crash.
+ dbus::MethodCall method_call(DBUS_INTERFACE_PROPERTIES, "Get");
+ method_call.SetSerial(kFakeSerial);
+ dbus::MessageWriter writer(&method_call);
+ writer.AppendString(kMprisAPIPlayerInterfaceName);
+ writer.AppendString("Position");
+
+ int64_t position;
+
+ // Call the method and await a response.
+ properties_interface_exported_methods_["Get"].Run(
+ &method_call, base::BindOnce(
+ [](int64_t* position_out, base::RunLoop& wait_loop,
+ std::unique_ptr<dbus::Response> response) {
+ // A response of nullptr means an error has
+ // occurred.
+ EXPECT_NE(nullptr, response.get());
+
+ dbus::MessageReader reader(response.get());
+ ASSERT_TRUE(reader.PopVariantOfInt64(position_out));
+
+ wait_loop.Quit();
+ },
+ &position, std::ref(wait_loop)));
+ wait_loop.Run();
+
+ return position;
+ }
+
SystemMediaControlsLinux* GetService() { return service_.get(); }
dbus::MockExportedObject* GetExportedObject() {
return mock_exported_object_.get();
}
+ void AdvanceClockMilliseconds(int ms) {
+ task_environment_.FastForwardBy(base::Milliseconds(ms));
+ }
+
private:
void StartMprisServiceAndWaitForReady() {
service_wait_loop_ = std::make_unique<base::RunLoop>();
@@ -148,6 +210,8 @@ class SystemMediaControlsLinuxTest : public testing::Test,
dbus::ExportedObject::OnExportedCallback callback) {
if (interface_name == kMprisAPIPlayerInterfaceName)
player_interface_exported_methods_[method_name] = exported_method;
+ if (interface_name == DBUS_INTERFACE_PROPERTIES)
+ properties_interface_exported_methods_[method_name] = exported_method;
std::move(callback).Run(interface_name, method_name, true);
}
@@ -180,6 +244,8 @@ class SystemMediaControlsLinuxTest : public testing::Test,
base::flat_map<std::string, dbus::ExportedObject::MethodCallCallback>
player_interface_exported_methods_;
+ base::flat_map<std::string, dbus::ExportedObject::MethodCallCallback>
+ properties_interface_exported_methods_;
};
TEST_F(SystemMediaControlsLinuxTest, ObserverNotifiedOfServiceReadyWhenAdded) {
@@ -230,6 +296,20 @@ TEST_F(SystemMediaControlsLinuxTest, ObserverNotifiedOfPlayCalls) {
CallMediaPlayer2PlayerMethodAndBlock("Play");
}
+TEST_F(SystemMediaControlsLinuxTest, ObserverNotifiedOfSeekCalls) {
+ MockSystemMediaControlsObserver observer;
+ EXPECT_CALL(observer, OnSeek(base::Seconds(3)));
+ AddObserver(&observer);
+ CallSeekAndBlock(/*is_seek_to=*/false, base::Seconds(3).InMicroseconds());
+}
+
+TEST_F(SystemMediaControlsLinuxTest, ObserverNotifiedOfSetPositionCalls) {
+ MockSystemMediaControlsObserver observer;
+ EXPECT_CALL(observer, OnSeekTo(base::Seconds(7)));
+ AddObserver(&observer);
+ CallSeekAndBlock(/*is_seek_to=*/true, base::Seconds(7).InMicroseconds());
+}
+
TEST_F(SystemMediaControlsLinuxTest, ChangingPropertyEmitsSignal) {
base::RunLoop wait_for_signal;
@@ -330,6 +410,206 @@ TEST_F(SystemMediaControlsLinuxTest, ChangingMetadataEmitsSignal) {
GetService()->SetTitle(u"Foo");
}
+TEST_F(SystemMediaControlsLinuxTest,
+ PlayingMediaWithPositionWillContinuouslyUpdatePosition) {
+ base::RunLoop wait_for_initial_position_update;
+
+ const base::TimeDelta expected_position = base::Seconds(5);
+ double expected_rate = 2.0;
+ const base::TimeDelta expected_duration = base::Seconds(20);
+
+ // Since the position is updated every 500ms, and the rate is 2.0, after 500ms
+ // we should get 6 seconds as the position.
+ const base::TimeDelta expected_updated_position = base::Seconds(6);
+
+ int signal_count = 0;
+
+ // The returned signal should give the changed property.
+ EXPECT_CALL(*GetExportedObject(), SendSignal(_))
+ .WillRepeatedly(WithArg<0>([&](dbus::Signal* signal) {
+ signal_count++;
+
+ EXPECT_NE(nullptr, signal);
+ dbus::MessageReader reader(signal);
+
+ // The final signal we get is a "Seeked" signal which has a different
+ // format than the rest.
+ if (signal_count == 4) {
+ EXPECT_EQ(kMprisAPIPlayerInterfaceName, signal->GetInterface());
+ EXPECT_EQ(kMprisAPISignalSeeked, signal->GetMember());
+
+ int64_t new_position;
+ ASSERT_TRUE(reader.PopInt64(&new_position));
+ EXPECT_EQ(expected_position.InMicroseconds(), new_position);
+
+ wait_for_initial_position_update.Quit();
+ return;
+ }
+
+ EXPECT_EQ(DBUS_INTERFACE_PROPERTIES, signal->GetInterface());
+ EXPECT_EQ("PropertiesChanged", signal->GetMember());
+
+ std::string interface_name;
+ ASSERT_TRUE(reader.PopString(&interface_name));
+ EXPECT_EQ(kMprisAPIPlayerInterfaceName, interface_name);
+
+ dbus::MessageReader changed_properties_reader(nullptr);
+ ASSERT_TRUE(reader.PopArray(&changed_properties_reader));
+
+ dbus::MessageReader dict_entry_reader(nullptr);
+ ASSERT_TRUE(changed_properties_reader.PopDictEntry(&dict_entry_reader));
+
+ std::string property_name;
+ std::string metadata_property_name;
+ dbus::MessageReader metadata_variant_reader(nullptr);
+ dbus::MessageReader metadata_reader(nullptr);
+ dbus::MessageReader metadata_entry_reader(nullptr);
+ std::string playback_status_value;
+ double rate_value;
+ int64_t duration_value;
+
+ ASSERT_TRUE(dict_entry_reader.PopString(&property_name));
+ switch (signal_count) {
+ case 1:
+ // The first changed property will be the playback status to
+ // playing.
+ EXPECT_EQ("PlaybackStatus", property_name);
+ ASSERT_TRUE(
+ dict_entry_reader.PopVariantOfString(&playback_status_value));
+ EXPECT_EQ("Playing", playback_status_value);
+ break;
+ case 2:
+ // The next changed property will be rate to 1.0.
+ EXPECT_EQ("Rate", property_name);
+ ASSERT_TRUE(dict_entry_reader.PopVariantOfDouble(&rate_value));
+ EXPECT_EQ(expected_rate, rate_value);
+ break;
+ case 3:
+ // The next changed property will be duration to 20 seconds.
+ EXPECT_EQ("Metadata", property_name);
+ ASSERT_TRUE(dict_entry_reader.PopVariant(&metadata_variant_reader));
+ ASSERT_TRUE(metadata_variant_reader.PopArray(&metadata_reader));
+ ASSERT_TRUE(metadata_reader.PopDictEntry(&metadata_entry_reader));
+ ASSERT_TRUE(
+ metadata_entry_reader.PopString(&metadata_property_name));
+ EXPECT_EQ("mpris:length", metadata_property_name);
+ ASSERT_TRUE(
+ metadata_entry_reader.PopVariantOfInt64(&duration_value));
+ EXPECT_EQ(expected_duration.InMicroseconds(), duration_value);
+ break;
+ }
+
+ // There should only be one entry at a time.
+ EXPECT_FALSE(changed_properties_reader.HasMoreData());
+ }));
+
+ // Set playback status to "Playing" to ensure the position updates.
+ GetService()->SetPlaybackStatus(
+ SystemMediaControls::PlaybackStatus::kPlaying);
+
+ // Set the initial position.
+ media_session::MediaPosition position(expected_rate, expected_duration,
+ expected_position,
+ /*end_of_media=*/false);
+ GetService()->SetPosition(position);
+
+ // Wait for the initial position property updates to be signaled.
+ wait_for_initial_position_update.Run();
+
+ // After the initial position signaling, we should not receive more signals
+ // for the position updates that happen due to typical media playback.
+ testing::Mock::VerifyAndClearExpectations(GetExportedObject());
+ EXPECT_CALL(*GetExportedObject(), SendSignal(_)).Times(0);
+
+ // Even without signals, the property should still be updated and return the
+ // correct new value when called after some time.
+ AdvanceClockMilliseconds(500);
+ EXPECT_EQ(expected_updated_position.InMicroseconds(),
+ GetCurrentPositionValue());
+
+ const base::TimeDelta expected_seeked_position = base::Seconds(14);
+ base::RunLoop wait_for_seeked_signal;
+
+ // If the position changes in a way that is inconsistent with the current
+ // playing state (e.g. the user has seeked to a different time), then we
+ // should receive a "Seeked" signal indicating the change.
+ testing::Mock::VerifyAndClearExpectations(GetExportedObject());
+ EXPECT_CALL(*GetExportedObject(), SendSignal(_))
+ .WillRepeatedly(WithArg<0>([&](dbus::Signal* signal) {
+ EXPECT_NE(nullptr, signal);
+ EXPECT_EQ(kMprisAPIPlayerInterfaceName, signal->GetInterface());
+ EXPECT_EQ(kMprisAPISignalSeeked, signal->GetMember());
+
+ dbus::MessageReader reader(signal);
+ int64_t new_position;
+ ASSERT_TRUE(reader.PopInt64(&new_position));
+ EXPECT_EQ(expected_seeked_position.InMicroseconds(), new_position);
+
+ wait_for_seeked_signal.Quit();
+ }));
+
+ media_session::MediaPosition seeked_position(expected_rate, expected_duration,
+ expected_seeked_position,
+ /*end_of_media=*/false);
+ GetService()->SetPosition(seeked_position);
+ wait_for_seeked_signal.Run();
+}
+
+TEST_F(SystemMediaControlsLinuxTest, ChangingIdEmitsSignal) {
+ base::RunLoop wait_for_signal;
+
+ // The returned signal should give the new Id.
+ EXPECT_CALL(*GetExportedObject(), SendSignal(_))
+ .WillOnce(WithArg<0>([&wait_for_signal](dbus::Signal* signal) {
+ ASSERT_NE(nullptr, signal);
+ dbus::MessageReader reader(signal);
+
+ std::string interface_name;
+ ASSERT_TRUE(reader.PopString(&interface_name));
+ EXPECT_EQ(kMprisAPIPlayerInterfaceName, interface_name);
+
+ dbus::MessageReader changed_properties_reader(nullptr);
+ ASSERT_TRUE(reader.PopArray(&changed_properties_reader));
+
+ dbus::MessageReader dict_entry_reader(nullptr);
+ ASSERT_TRUE(changed_properties_reader.PopDictEntry(&dict_entry_reader));
+
+ // The changed property name should be "Metadata".
+ std::string property_name;
+ ASSERT_TRUE(dict_entry_reader.PopString(&property_name));
+ EXPECT_EQ("Metadata", property_name);
+
+ // The new metadata should have the new Id.
+ dbus::MessageReader metadata_variant_reader(nullptr);
+ ASSERT_TRUE(dict_entry_reader.PopVariant(&metadata_variant_reader));
+ dbus::MessageReader metadata_reader(nullptr);
+ ASSERT_TRUE(metadata_variant_reader.PopArray(&metadata_reader));
+
+ dbus::MessageReader metadata_entry_reader(nullptr);
+ ASSERT_TRUE(metadata_reader.PopDictEntry(&metadata_entry_reader));
+
+ std::string metadata_property_name;
+ ASSERT_TRUE(metadata_entry_reader.PopString(&metadata_property_name));
+ EXPECT_EQ("mpris:trackid", metadata_property_name);
+
+ dbus::ObjectPath value;
+ ASSERT_TRUE(metadata_entry_reader.PopVariantOfObjectPath(&value));
+ EXPECT_EQ("/org/chromium/MediaPlayer2/TrackList/TrackFooId",
+ value.value());
+
+ // Metadata should be the only changed property.
+ EXPECT_FALSE(changed_properties_reader.HasMoreData());
+
+ wait_for_signal.Quit();
+ }));
+
+ // Setting the ID should emit an
+ // org.freedesktop.DBus.Properties.PropertiesChanged signal.
+ const std::string given_id("FooId");
+ GetService()->SetID(&given_id);
+ wait_for_signal.Run();
+}
+
} // namespace internal
} // namespace system_media_controls
diff --git a/chromium/components/system_media_controls/mock_system_media_controls.h b/chromium/components/system_media_controls/mock_system_media_controls.h
index c5649e22581..bb782c303c8 100644
--- a/chromium/components/system_media_controls/mock_system_media_controls.h
+++ b/chromium/components/system_media_controls/mock_system_media_controls.h
@@ -34,6 +34,7 @@ class MockSystemMediaControls : public SystemMediaControls {
MOCK_METHOD1(SetIsStopEnabled, void(bool value));
MOCK_METHOD1(SetIsSeekToEnabled, void(bool value));
MOCK_METHOD1(SetPlaybackStatus, void(PlaybackStatus value));
+ MOCK_METHOD1(SetID, void(const std::string* value));
MOCK_METHOD1(SetTitle, void(const std::u16string& title));
MOCK_METHOD1(SetArtist, void(const std::u16string& artist));
MOCK_METHOD1(SetAlbum, void(const std::u16string& artist));
diff --git a/chromium/components/system_media_controls/system_media_controls.h b/chromium/components/system_media_controls/system_media_controls.h
index 5cad961e0c9..cf583baa8c2 100644
--- a/chromium/components/system_media_controls/system_media_controls.h
+++ b/chromium/components/system_media_controls/system_media_controls.h
@@ -48,6 +48,7 @@ class COMPONENT_EXPORT(SYSTEM_MEDIA_CONTROLS) SystemMediaControls {
// Setters for metadata.
virtual void SetPlaybackStatus(PlaybackStatus value) = 0;
+ virtual void SetID(const std::string* value) {}
virtual void SetTitle(const std::u16string& value) = 0;
virtual void SetArtist(const std::u16string& value) = 0;
virtual void SetAlbum(const std::u16string& value) = 0;
diff --git a/chromium/components/system_media_controls/system_media_controls_observer.h b/chromium/components/system_media_controls/system_media_controls_observer.h
index ff7b67dc728..7586de14a1a 100644
--- a/chromium/components/system_media_controls/system_media_controls_observer.h
+++ b/chromium/components/system_media_controls/system_media_controls_observer.h
@@ -20,16 +20,17 @@ class COMPONENT_EXPORT(SYSTEM_MEDIA_CONTROLS) SystemMediaControlsObserver
public:
// Called when the service has completed setup. Also called when an observer
// is added if the service is already set up.
- virtual void OnServiceReady() = 0;
+ virtual void OnServiceReady() {}
// Called when the observer should handle the given control.
- virtual void OnNext() = 0;
- virtual void OnPrevious() = 0;
- virtual void OnPlay() = 0;
- virtual void OnPause() = 0;
- virtual void OnPlayPause() = 0;
- virtual void OnStop() = 0;
- virtual void OnSeekTo(const base::TimeDelta& time) = 0;
+ virtual void OnNext() {}
+ virtual void OnPrevious() {}
+ virtual void OnPlay() {}
+ virtual void OnPause() {}
+ virtual void OnPlayPause() {}
+ virtual void OnStop() {}
+ virtual void OnSeek(const base::TimeDelta& time) {}
+ virtual void OnSeekTo(const base::TimeDelta& time) {}
protected:
~SystemMediaControlsObserver() override = default;
diff --git a/chromium/components/tab_groups/tab_group_color.h b/chromium/components/tab_groups/tab_group_color.h
index 2160b3080b0..180bc542d2d 100644
--- a/chromium/components/tab_groups/tab_group_color.h
+++ b/chromium/components/tab_groups/tab_group_color.h
@@ -26,6 +26,11 @@ namespace tab_groups {
// Any code that reads an enum value from disk should check it against the map
// from GetTabGroupColorLabelMap(). If the value is not contained in the map's
// keys, default to kGrey.
+//
+// Additionally, any colors added here will also be used in
+// chrome/browser/resources/tab_search/tab_group_color_helper.ts. As such these
+// colors should be kept in sync. Ex: Adding orange in this file,
+// requires adding orange in the other file.
enum class TabGroupColorId {
kGrey = 0,
kBlue = 1,
diff --git a/chromium/components/thin_webview/internal/thin_webview.cc b/chromium/components/thin_webview/internal/thin_webview.cc
index 35fa071ecc9..a1d93b3b63c 100644
--- a/chromium/components/thin_webview/internal/thin_webview.cc
+++ b/chromium/components/thin_webview/internal/thin_webview.cc
@@ -47,8 +47,9 @@ void ThinWebView::Destroy(JNIEnv* env, const JavaParamRef<jobject>& object) {
delete this;
}
-void ThinWebView::DocumentAvailableInMainFrame(
- content::RenderFrameHost* render_frame_host) {
+// TODO(crbug.com/1291556): Use WebContentsObserver::PrimaryPageChanged to
+// disable thin webview.
+void ThinWebView::PrimaryMainDocumentElementAvailable() {
// Disable browser controls when used for thin webview.
web_contents_->UpdateBrowserControlsState(cc::BrowserControlsState::kHidden,
cc::BrowserControlsState::kHidden,
diff --git a/chromium/components/thin_webview/internal/thin_webview.h b/chromium/components/thin_webview/internal/thin_webview.h
index 6558f396cd3..f1d0702e29d 100644
--- a/chromium/components/thin_webview/internal/thin_webview.h
+++ b/chromium/components/thin_webview/internal/thin_webview.h
@@ -50,8 +50,7 @@ class ThinWebView : public content::WebContentsObserver {
private:
// content::WebContentsObserver overrides:
- void DocumentAvailableInMainFrame(
- content::RenderFrameHost* render_frame_host) override;
+ void PrimaryMainDocumentElementAvailable() override;
void SetWebContents(
content::WebContents* web_contents,
diff --git a/chromium/components/tracing/BUILD.gn b/chromium/components/tracing/BUILD.gn
index 92b69ee2c8b..79940ddc927 100644
--- a/chromium/components/tracing/BUILD.gn
+++ b/chromium/components/tracing/BUILD.gn
@@ -34,6 +34,22 @@ component("startup_tracing") {
deps = [ "//base" ]
}
+component("background_tracing_metrics_provider") {
+ sources = [
+ "common/background_tracing_metrics_provider.cc",
+ "common/background_tracing_metrics_provider.h",
+ "tracing_export.h",
+ ]
+
+ defines = [ "TRACING_IMPLEMENTATION" ]
+
+ deps = [
+ "//base",
+ "//components/metrics:content",
+ "//content/public/browser",
+ ]
+}
+
source_set("unit_tests") {
testonly = true
diff --git a/chromium/components/tracing/DEPS b/chromium/components/tracing/DEPS
index 08980e5e0dc..116393a7b5c 100644
--- a/chromium/components/tracing/DEPS
+++ b/chromium/components/tracing/DEPS
@@ -1,5 +1,8 @@
include_rules = [
"+ipc",
+ "+components/metrics",
+ "+third_party/metrics_proto",
+ "+content/public/browser/background_tracing_manager.h",
]
specific_include_rules = {
diff --git a/chromium/components/tracing/common/background_tracing_metrics_provider.cc b/chromium/components/tracing/common/background_tracing_metrics_provider.cc
new file mode 100644
index 00000000000..3ce2c68fdca
--- /dev/null
+++ b/chromium/components/tracing/common/background_tracing_metrics_provider.cc
@@ -0,0 +1,64 @@
+// Copyright 2022 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.
+
+#include "components/tracing/common/background_tracing_metrics_provider.h"
+
+#include "base/time/time.h"
+
+#include "components/metrics/content/gpu_metrics_provider.h"
+#include "components/metrics/cpu_metrics_provider.h"
+#include "content/public/browser/background_tracing_manager.h"
+#include "third_party/metrics_proto/chrome_user_metrics_extension.pb.h"
+#include "third_party/metrics_proto/trace_log.pb.h"
+
+namespace tracing {
+
+BackgroundTracingMetricsProvider::BackgroundTracingMetricsProvider() = default;
+BackgroundTracingMetricsProvider::~BackgroundTracingMetricsProvider() = default;
+
+void BackgroundTracingMetricsProvider::Init() {
+ system_profile_providers_.emplace_back(
+ std::make_unique<metrics::CPUMetricsProvider>());
+ system_profile_providers_.emplace_back(
+ std::make_unique<metrics::GPUMetricsProvider>());
+}
+
+bool BackgroundTracingMetricsProvider::HasIndependentMetrics() {
+ return content::BackgroundTracingManager::GetInstance()->HasTraceToUpload();
+}
+
+void BackgroundTracingMetricsProvider::ProvideIndependentMetrics(
+ base::OnceCallback<void(bool)> done_callback,
+ metrics::ChromeUserMetricsExtension* uma_proto,
+ base::HistogramSnapshotManager* snapshot_manager) {
+ auto* tracing_manager = content::BackgroundTracingManager::GetInstance();
+ // TODO(crbug.com/1290887): remove this when
+ // content::BackgroundTracingManager::GetInstance() is updated to return a
+ // reference.
+ DCHECK(tracing_manager);
+
+ auto serialized_trace = tracing_manager->GetLatestTraceToUpload();
+ if (serialized_trace.empty()) {
+ std::move(done_callback).Run(false);
+ return;
+ }
+ metrics::TraceLog* log = uma_proto->add_trace_log();
+ log->set_raw_data(std::move(serialized_trace));
+
+ auto* system_profile = uma_proto->mutable_system_profile();
+
+ for (auto& provider : system_profile_providers_) {
+ provider->ProvideSystemProfileMetricsWithLogCreationTime(
+ base::TimeTicks::Now(), system_profile);
+ }
+
+ ProvideEmbedderMetrics(uma_proto, snapshot_manager);
+ std::move(done_callback).Run(true);
+}
+
+void BackgroundTracingMetricsProvider::ProvideEmbedderMetrics(
+ metrics::ChromeUserMetricsExtension* uma_proto,
+ base::HistogramSnapshotManager* snapshot_manager) {}
+
+} // namespace tracing
diff --git a/chromium/components/tracing/common/background_tracing_metrics_provider.h b/chromium/components/tracing/common/background_tracing_metrics_provider.h
new file mode 100644
index 00000000000..602ef50a4a8
--- /dev/null
+++ b/chromium/components/tracing/common/background_tracing_metrics_provider.h
@@ -0,0 +1,53 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_TRACING_COMMON_BACKGROUND_TRACING_METRICS_PROVIDER_H_
+#define COMPONENTS_TRACING_COMMON_BACKGROUND_TRACING_METRICS_PROVIDER_H_
+
+#include <vector>
+
+#include "components/metrics/metrics_provider.h"
+#include "components/tracing/tracing_export.h"
+
+namespace tracing {
+
+// Provides trace log metrics collected using BackgroundTracingManager to UMA
+// proto. Background tracing uploads metrics of larger size compared to UMA
+// histograms and it is better to upload them as independent metrics rather
+// than part of UMA histograms log. The background tracing manager will make
+// sure the traces are small when uploading over data.
+class TRACING_EXPORT BackgroundTracingMetricsProvider
+ : public metrics::MetricsProvider {
+ public:
+ BackgroundTracingMetricsProvider();
+
+ BackgroundTracingMetricsProvider(const BackgroundTracingMetricsProvider&) =
+ delete;
+ BackgroundTracingMetricsProvider& operator=(
+ const BackgroundTracingMetricsProvider&) = delete;
+
+ ~BackgroundTracingMetricsProvider() override;
+
+ // metrics::MetricsProvider:
+ bool HasIndependentMetrics() override;
+ void ProvideIndependentMetrics(
+ base::OnceCallback<void(bool)> done_callback,
+ metrics::ChromeUserMetricsExtension* uma_proto,
+ base::HistogramSnapshotManager* snapshot_manager) override;
+ void Init() override;
+
+ protected:
+ // Embedders can override this to do any additional processing of the log
+ // before it is sent.
+ virtual void ProvideEmbedderMetrics(
+ metrics::ChromeUserMetricsExtension* uma_proto,
+ base::HistogramSnapshotManager* snapshot_manager);
+
+ std::vector<std::unique_ptr<metrics::MetricsProvider>>
+ system_profile_providers_;
+};
+
+} // namespace tracing
+
+#endif // COMPONENTS_TRACING_COMMON_BACKGROUND_TRACING_METRICS_PROVIDER_H_
diff --git a/chromium/components/tracing/common/trace_startup_config.cc b/chromium/components/tracing/common/trace_startup_config.cc
index 45ef92a5dbd..a1db0ce9ef2 100644
--- a/chromium/components/tracing/common/trace_startup_config.cc
+++ b/chromium/components/tracing/common/trace_startup_config.cc
@@ -21,7 +21,7 @@
#include "build/build_config.h"
#include "components/tracing/common/tracing_switches.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "base/android/early_trace_event_binding.h"
#endif
@@ -35,7 +35,7 @@ const size_t kTraceConfigFileSizeLimit = 64 * 1024;
// Trace config file path:
// - Android: /data/local/chrome-trace-config.json
// - Others: specified by --trace-config-file flag.
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
const base::FilePath::CharType kAndroidTraceConfigFile[] =
FILE_PATH_LITERAL("/data/local/chrome-trace-config.json");
#endif
@@ -50,7 +50,7 @@ const char kResultDirectoryParam[] = "result_directory";
// static
const char TraceStartupConfig::kDefaultStartupCategories[] =
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
"startup,browser,toplevel,toplevel.flow,ipc,EarlyJava,cc,Java,navigation,"
"loading,gpu,ui,disabled-by-default-cpu_profiler,download_service,"
"disabled-by-default-histogram_samples,"
@@ -135,7 +135,7 @@ base::FilePath TraceStartupConfig::GetResultFile() const {
}
void TraceStartupConfig::SetBackgroundStartupTracingEnabled(bool enabled) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
base::android::SetBackgroundStartupTracingFlag(enabled);
#endif
}
@@ -157,6 +157,10 @@ bool TraceStartupConfig::AttemptAdoptBySessionOwner(SessionOwner owner) {
bool TraceStartupConfig::EnableFromCommandLine() {
auto* command_line = base::CommandLine::ForCurrentProcess();
+ bool tracing_enabled_from_command_line =
+ command_line->HasSwitch(switches::kTraceStartup) ||
+ command_line->HasSwitch(switches::kEnableTracing);
+
if (command_line->HasSwitch(switches::kTraceStartupDuration)) {
std::string startup_duration_str =
command_line->GetSwitchValueASCII(switches::kTraceStartupDuration);
@@ -173,19 +177,23 @@ bool TraceStartupConfig::EnableFromCommandLine() {
if (command_line->HasSwitch(switches::kTraceStartupFormat)) {
if (command_line->GetSwitchValueASCII(switches::kTraceStartupFormat) ==
- "proto") {
- // Default is "json".
- output_format_ = OutputFormat::kProto;
+ "json") {
+ // Default is "proto", so switch to json only if the "json" string is
+ // provided.
+ output_format_ = OutputFormat::kLegacyJSON;
+ }
+ } else if (command_line->HasSwitch(switches::kEnableTracingFormat)) {
+ if (command_line->GetSwitchValueASCII(switches::kEnableTracingFormat) ==
+ "json") {
+ output_format_ = OutputFormat::kLegacyJSON;
}
- } else if (command_line->GetSwitchValueASCII(
- switches::kEnableTracingFormat) == "proto") {
- output_format_ = OutputFormat::kProto;
}
- if (!command_line->HasSwitch(switches::kTraceStartup) &&
- !command_line->HasSwitch(switches::kEnableTracing)) {
+ // This check is intentionally performed after setting duration and output
+ // format to ensure that setting them from the command-line takes effect for
+ // config file-based tracing as well.
+ if (!tracing_enabled_from_command_line)
return false;
- }
std::string categories;
if (command_line->HasSwitch(switches::kTraceStartup)) {
@@ -214,7 +222,7 @@ bool TraceStartupConfig::EnableFromCommandLine() {
}
bool TraceStartupConfig::EnableFromATrace() {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
auto atrace_config =
base::trace_event::TraceLog::GetInstance()->TakeATraceStartupConfig();
if (!atrace_config)
@@ -226,13 +234,13 @@ bool TraceStartupConfig::EnableFromATrace() {
// command line flags to control startup tracing instead of ATrace.
session_owner_ = SessionOwner::kSystemTracing;
return true;
-#else // defined(OS_ANDROID)
+#else // BUILDFLAG(IS_ANDROID)
return false;
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
}
bool TraceStartupConfig::EnableFromConfigFile() {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
base::FilePath trace_config_file(kAndroidTraceConfigFile);
#else
auto* command_line = base::CommandLine::ForCurrentProcess();
@@ -268,7 +276,7 @@ bool TraceStartupConfig::EnableFromConfigFile() {
bool TraceStartupConfig::EnableFromBackgroundTracing() {
bool enabled = enable_background_tracing_for_testing_;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Tests can enable this value.
enabled |= base::android::GetBackgroundStartupTracingFlag();
#else
@@ -305,8 +313,8 @@ bool TraceStartupConfig::ParseTraceConfigFileContent(
trace_config_ = base::trace_event::TraceConfig(*trace_config_dict);
- if (!dict->GetInteger(kStartupDurationParam, &startup_duration_in_seconds_))
- startup_duration_in_seconds_ = 0;
+ startup_duration_in_seconds_ =
+ dict->FindIntKey(kStartupDurationParam).value_or(0);
if (startup_duration_in_seconds_ < 0)
startup_duration_in_seconds_ = 0;
diff --git a/chromium/components/tracing/common/trace_startup_config.h b/chromium/components/tracing/common/trace_startup_config.h
index 5d48a284783..3fa05c2c91c 100644
--- a/chromium/components/tracing/common/trace_startup_config.h
+++ b/chromium/components/tracing/common/trace_startup_config.h
@@ -169,7 +169,7 @@ class TRACING_EXPORT TraceStartupConfig {
base::FilePath result_file_;
SessionOwner session_owner_ = SessionOwner::kTracingController;
bool session_adopted_ = false;
- OutputFormat output_format_ = OutputFormat::kLegacyJSON;
+ OutputFormat output_format_ = OutputFormat::kProto;
};
} // namespace tracing
diff --git a/chromium/components/translate/content/browser/BUILD.gn b/chromium/components/translate/content/browser/BUILD.gn
index 13fc2880d2b..1dfbe926fe7 100644
--- a/chromium/components/translate/content/browser/BUILD.gn
+++ b/chromium/components/translate/content/browser/BUILD.gn
@@ -14,8 +14,6 @@ static_library("browser") {
"content_translate_util.h",
"per_frame_content_translate_driver.cc",
"per_frame_content_translate_driver.h",
- "translate_model_service.cc",
- "translate_model_service.h",
]
public_deps = [
@@ -34,6 +32,7 @@ static_library("browser") {
"//components/search_engines:search_engines",
"//components/services/language_detection/public/cpp",
"//components/services/language_detection/public/mojom",
+ "//components/translate/core/browser:translate_model_service",
"//components/translate/core/language_detection:language_detection",
"//components/ukm/content",
"//content/public/common",
diff --git a/chromium/components/translate/core/browser/BUILD.gn b/chromium/components/translate/core/browser/BUILD.gn
index ebf718409b2..4d074e5c7ac 100644
--- a/chromium/components/translate/core/browser/BUILD.gn
+++ b/chromium/components/translate/core/browser/BUILD.gn
@@ -87,6 +87,21 @@ static_library("browser") {
}
}
+static_library("translate_model_service") {
+ sources = [
+ "translate_model_service.cc",
+ "translate_model_service.h",
+ ]
+ deps = [
+ ":browser",
+ "//base",
+ "//components/keyed_service/core",
+ "//components/optimization_guide/core",
+ "//components/optimization_guide/proto:optimization_guide_proto",
+ "//mojo/public/cpp/bindings",
+ ]
+}
+
source_set("translate_pref_names") {
sources = [
"translate_pref_names.cc",
diff --git a/chromium/components/translate/ios/browser/BUILD.gn b/chromium/components/translate/ios/browser/BUILD.gn
index eae2942fd3c..17a5101ea21 100644
--- a/chromium/components/translate/ios/browser/BUILD.gn
+++ b/chromium/components/translate/ios/browser/BUILD.gn
@@ -66,6 +66,7 @@ source_set("unit_tests") {
"//components/language/ios/browser",
"//components/resources",
"//ios/web/public/test",
+ "//ios/web/public/test:test_fixture",
"//testing/gtest",
"//ui/base",
"//url",
diff --git a/chromium/components/translate_strings.grdp b/chromium/components/translate_strings.grdp
index 238ff6f56c1..ed65f459ffe 100644
--- a/chromium/components/translate_strings.grdp
+++ b/chromium/components/translate_strings.grdp
@@ -114,9 +114,6 @@
</message>
<!-- Desktop and Android resources -->
- <message name="IDS_TRANSLATE_UNKNOWN_SOURCE_LANGUAGE" desc="Text to use in the translate bubble UI when the source language is unknown or undetected. Used in place of a language name, so should be capitalized as such (e.g. &quot;Unknown&quot; for English, &quot;sconosciuto&quot; for Italian)" meaning="Noun to use in place of a language name in part of a translate bubble message.">
- Unknown
- </message>
<message name="IDS_TRANSLATE_DETECTED_LANGUAGE" desc="Text to use in the translate infobar and translate bubble when the source language is unknown or undetected. The user can select this as an option for the page source language in a translation. Used in place of a language name, so should be capitalized as such (e.g. &quot;Detected Language&quot; for English, &quot;lingua rilevata&quot; for Italian)" meaning="Noun to select from a list of languages, and to use in place of a language name in part of a translate UI message.">
Detected Language
</message>
diff --git a/chromium/components/translate_strings_grdp/IDS_TRANSLATE_UNKNOWN_SOURCE_LANGUAGE.png.sha1 b/chromium/components/translate_strings_grdp/IDS_TRANSLATE_UNKNOWN_SOURCE_LANGUAGE.png.sha1
deleted file mode 100644
index 4bc61b59dd7..00000000000
--- a/chromium/components/translate_strings_grdp/IDS_TRANSLATE_UNKNOWN_SOURCE_LANGUAGE.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-d8cd4210c1f90bbbd54164ac01234d726af820df \ No newline at end of file
diff --git a/chromium/components/ui_devtools/BUILD.gn b/chromium/components/ui_devtools/BUILD.gn
index 0d42a82c29c..90d4ebe6e4e 100644
--- a/chromium/components/ui_devtools/BUILD.gn
+++ b/chromium/components/ui_devtools/BUILD.gn
@@ -8,8 +8,6 @@ _inspector_protocol = "//third_party/inspector_protocol"
import("$_inspector_protocol/inspector_protocol.gni")
_protocol_generated = [
- "base_string_adapter.cc",
- "base_string_adapter.h",
"css.cc",
"css.h",
"dom.cc",
@@ -19,7 +17,6 @@ _protocol_generated = [
"overlay.h",
"page.cc",
"page.h",
- "protocol.cc",
"protocol.h",
"tracing.h",
"tracing.cc",
@@ -52,6 +49,7 @@ inspector_protocol_generate("protocol_generated_sources") {
"protocol.json",
"inspector_protocol_config.json",
]
+ use_embedder_types = true
outputs = _protocol_generated
}
diff --git a/chromium/components/ui_devtools/devtools_server_unittest.cc b/chromium/components/ui_devtools/devtools_server_unittest.cc
index f7439edecf4..a7a1fd55c08 100644
--- a/chromium/components/ui_devtools/devtools_server_unittest.cc
+++ b/chromium/components/ui_devtools/devtools_server_unittest.cc
@@ -21,7 +21,7 @@
namespace ui_devtools {
// TODO(lgrey): Hopefully temporary while we figure out why this doesn't work.
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
#define MAYBE_ConnectionToViewsServer DISABLED_ConnectionToViewsServer
#else
#define MAYBE_ConnectionToViewsServer ConnectionToViewsServer
diff --git a/chromium/components/ui_devtools/inspector_protocol_config.json b/chromium/components/ui_devtools/inspector_protocol_config.json
index 4c4d73db9f9..7d1723a2d5d 100644
--- a/chromium/components/ui_devtools/inspector_protocol_config.json
+++ b/chromium/components/ui_devtools/inspector_protocol_config.json
@@ -29,7 +29,7 @@
"lib": {
"package": "components/ui_devtools",
"output": "",
- "string_header": "components/ui_devtools/base_string_adapter.h",
+ "protocol_traits": "third_party/inspector_protocol/crdtp/chromium/protocol_traits.h",
"export_macro": "UI_DEVTOOLS_EXPORT",
"export_header": "components/ui_devtools/devtools_export.h"
},
diff --git a/chromium/components/ui_devtools/views/BUILD.gn b/chromium/components/ui_devtools/views/BUILD.gn
index 0a5864c18ce..6b20f6e8391 100644
--- a/chromium/components/ui_devtools/views/BUILD.gn
+++ b/chromium/components/ui_devtools/views/BUILD.gn
@@ -28,7 +28,6 @@ source_set("views") {
deps = [
"//components/ui_devtools",
- "//extensions/common",
"//skia",
"//ui/views",
]
diff --git a/chromium/components/ui_devtools/views/element_utility.cc b/chromium/components/ui_devtools/views/element_utility.cc
index e2986bc8aee..d0ea2462357 100644
--- a/chromium/components/ui_devtools/views/element_utility.cc
+++ b/chromium/components/ui_devtools/views/element_utility.cc
@@ -60,7 +60,7 @@ void AppendLayerPropertiesMatchedStyle(
// Property trees must be updated in order to get valid render surface
// reasons.
if (!cc_layer->layer_tree_host() ||
- cc_layer->layer_tree_host()->property_trees()->needs_rebuild)
+ cc_layer->layer_tree_host()->property_trees()->needs_rebuild())
return;
cc::RenderSurfaceReason render_surface = cc_layer->GetRenderSurfaceReason();
if (render_surface != cc::RenderSurfaceReason::kNone) {
diff --git a/chromium/components/ui_devtools/views/overlay_agent_views.cc b/chromium/components/ui_devtools/views/overlay_agent_views.cc
index 4a89fc8eca3..025b86c6d2a 100644
--- a/chromium/components/ui_devtools/views/overlay_agent_views.cc
+++ b/chromium/components/ui_devtools/views/overlay_agent_views.cc
@@ -419,7 +419,7 @@ void OverlayAgentViews::ShowDistancesInHighlightOverlay(int pinned_id,
element_r2->GetNodeWindowAndScreenBounds());
const std::pair<gfx::NativeWindow, gfx::Rect> pair_r1(
element_r1->GetNodeWindowAndScreenBounds());
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
// TODO(lgrey): Explain this
if (pair_r1.first != pair_r2.first) {
pinned_id_ = 0;
@@ -714,7 +714,7 @@ bool OverlayAgentViews::UpdateHighlight(
return false;
}
ui::Layer* root_layer = nullptr;
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
views::Widget* widget =
views::Widget::GetWidgetForNativeWindow(window_and_bounds.first);
root_layer = widget->GetLayer();
@@ -725,7 +725,7 @@ bool OverlayAgentViews::UpdateHighlight(
root_layer = root->layer();
layer_for_highlighting_screen_offset_ =
root->GetBoundsInScreen().OffsetFromOrigin();
-#endif // defined(OS_APPLE)
+#endif // BUILDFLAG(IS_APPLE)
DCHECK(root_layer);
layer_for_highlighting_->SetBounds(root_layer->bounds());
diff --git a/chromium/components/ukm/BUILD.gn b/chromium/components/ukm/BUILD.gn
index df41f2fe1bc..3eea6bba076 100644
--- a/chromium/components/ukm/BUILD.gn
+++ b/chromium/components/ukm/BUILD.gn
@@ -20,6 +20,8 @@ component("ukm_recorder") {
"ukm_entry_filter.h",
"ukm_recorder_impl.cc",
"ukm_recorder_impl.h",
+ "ukm_recorder_observer.cc",
+ "ukm_recorder_observer.h",
]
deps = [
diff --git a/chromium/components/ukm/ios/BUILD.gn b/chromium/components/ukm/ios/BUILD.gn
index 65d1cd47b85..c027e845f34 100644
--- a/chromium/components/ukm/ios/BUILD.gn
+++ b/chromium/components/ukm/ios/BUILD.gn
@@ -43,6 +43,7 @@ source_set("unit_tests") {
"//components/ukm:test_support",
"//ios/web/public",
"//ios/web/public/test",
+ "//ios/web/public/test:test_fixture",
"//net:test_support",
"//services/metrics/public/cpp:metrics_cpp",
"//testing/gtest",
diff --git a/chromium/components/ukm/ukm_recorder_impl.cc b/chromium/components/ukm/ukm_recorder_impl.cc
index c24b930c61b..70f51137e3d 100644
--- a/chromium/components/ukm/ukm_recorder_impl.cc
+++ b/chromium/components/ukm/ukm_recorder_impl.cc
@@ -22,6 +22,7 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "components/ukm/scheme_constants.h"
+#include "components/ukm/ukm_recorder_observer.h"
#include "components/variations/variations_associated_data.h"
#include "services/metrics/public/cpp/ukm_builders.h"
#include "services/metrics/public/cpp/ukm_decode.h"
@@ -49,6 +50,11 @@ bool IsWhitelistedSourceId(SourceId source_id) {
type == SourceIdType::NO_URL_ID;
}
+bool IsAppIdType(SourceId source_id) {
+ SourceIdType type = GetSourceIdType(source_id);
+ return type == SourceIdType::APP_ID;
+}
+
// Returns whether |url| has one of the schemes supported for logging to UKM.
// URLs with other schemes will not be logged.
bool HasSupportedScheme(const GURL& url) {
@@ -89,6 +95,12 @@ void RecordDroppedSource(DroppedDataReason reason) {
static_cast<int>(DroppedDataReason::NUM_DROPPED_DATA_REASONS));
}
+void RecordDroppedSource(bool already_recorded_another_reason,
+ DroppedDataReason reason) {
+ if (!already_recorded_another_reason)
+ RecordDroppedSource(reason);
+}
+
void RecordDroppedEntry(uint64_t event_hash, DroppedDataReason reason) {
LogEventHashAsUmaHistogram("UKM.Entries.Dropped.ByEntryHash", event_hash);
@@ -256,6 +268,8 @@ void UkmRecorderImpl::Purge() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
recordings_.Reset();
recording_is_continuous_ = false;
+
+ NotifyAllObservers(&UkmRecorderObserver::OnPurge);
}
void UkmRecorderImpl::PurgeRecordingsWithUrlScheme(
@@ -273,6 +287,9 @@ void UkmRecorderImpl::PurgeRecordingsWithUrlScheme(
PurgeSourcesAndEventsBySourceIds(relevant_source_ids);
recording_is_continuous_ = false;
+
+ NotifyAllObservers(&UkmRecorderObserver::OnPurgeRecordingsWithUrlScheme,
+ url_scheme);
}
void UkmRecorderImpl::PurgeRecordingsWithSourceIdType(
@@ -322,6 +339,32 @@ void UkmRecorderImpl::SetEntryFilter(
entry_filter_ = std::move(entry_filter);
}
+void UkmRecorderImpl::AddUkmRecorderObserver(
+ const base::flat_set<uint64_t>& event_hashes,
+ UkmRecorderObserver* observer) {
+ DCHECK(observer);
+ base::AutoLock auto_lock(lock_);
+ scoped_refptr<UkmRecorderObserverList> observers;
+ if (observers_.find(event_hashes) == observers_.end()) {
+ observers_.insert(
+ {event_hashes, base::MakeRefCounted<UkmRecorderObserverList>()});
+ }
+
+ observers_[event_hashes]->AddObserver(observer);
+}
+
+void UkmRecorderImpl::RemoveUkmRecorderObserver(UkmRecorderObserver* observer) {
+ base::AutoLock auto_lock(lock_);
+ for (auto it = observers_.begin(); it != observers_.end();) {
+ if (it->second->RemoveObserver(observer) ==
+ UkmRecorderObserverList::RemoveObserverResult::kWasOrBecameEmpty) {
+ it = observers_.erase(it);
+ } else {
+ ++it;
+ }
+ }
+}
+
// TODO(rkaplow): This should be refactored.
void UkmRecorderImpl::StoreRecordingsInReport(Report* report) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -333,6 +376,7 @@ void UkmRecorderImpl::StoreRecordingsInReport(Report* report) {
StoreEntryProto(*entry, proto_entry);
source_ids_seen.insert(entry->source_id);
}
+
// Number of sources excluded from this report because no entries referred to
// them.
const int num_sources_unsent =
@@ -346,6 +390,7 @@ void UkmRecorderImpl::StoreRecordingsInReport(Report* report) {
// Number of sources discarded due to not matching a navigation URL.
int num_sources_unmatched = 0;
+
std::unordered_map<SourceIdType, int> serialized_source_type_counts;
for (const auto& kv : recordings_.sources) {
@@ -375,11 +420,10 @@ void UkmRecorderImpl::StoreRecordingsInReport(Report* report) {
// Omit entryless sources from the report.
if (!base::Contains(source_ids_seen, kv.first)) {
continue;
- } else {
- // Source of ukm::SourceIdObj::Type::DEFAULT type will not be kept
- // after entries are logged.
- MarkSourceForDeletion(kv.first);
}
+
+ // Non-whitelisted Source types will not be kept after entries are logged.
+ MarkSourceForDeletion(kv.first);
}
// Minimal validations before serializing into a proto message.
// See crbug/1274876.
@@ -437,8 +481,8 @@ void UkmRecorderImpl::StoreRecordingsInReport(Report* report) {
}
}
int num_serialized_sources = 0;
- for (const auto& entry : serialized_source_type_counts) {
- num_serialized_sources += entry.second;
+ for (const auto& source_type_and_count : serialized_source_type_counts) {
+ num_serialized_sources += source_type_and_count.second;
}
UMA_HISTOGRAM_COUNTS_1000("UKM.Sources.SerializedCount2",
@@ -502,16 +546,151 @@ void UkmRecorderImpl::StoreRecordingsInReport(Report* report) {
report->set_is_continuous(recording_is_continuous_);
recording_is_continuous_ = true;
- // Defer at most GetMaxKeptSources() sources to the next report,
- // prioritizing most recently created ones.
- int pruned_sources_age = PruneOldSources(max_kept_sources_);
+ // Modify the set source_ids_seen by removing sources that aren't in
+ // recordings_. We do this here as there is a few places for
+ // recordings_.sources to be modified. The resulting set will be currently
+ // existing sources that were seen in this report.
+ auto it = source_ids_seen.begin();
+ while (it != source_ids_seen.end()) {
+ if (!base::Contains(recordings_.sources, *it)) {
+ it = source_ids_seen.erase(it);
+ } else {
+ it++;
+ }
+ }
+
+ // Build the set of sources that exist in recordings_.sources that were not
+ // seen in this report.
+ std::set<SourceId> source_ids_unseen;
+ for (const auto& kv : recordings_.sources) {
+ if (!base::Contains(source_ids_seen, kv.first)) {
+ source_ids_unseen.insert(kv.first);
+ }
+ }
+
+ // Special case APP_IDs. Ideally this is not going to exist for too long, as
+ // it would be preferable to have a more general purpose solution.
+ std::set<SourceId> source_ids_app_id;
+
+ // Only done if we are in the experiment that will leave APP_ID metrics for
+ // last when pruning. This block extracts out all source_ids from the
+ // seen/unseen lists and stores them in |source_ids_app_id|.
+ if (base::GetFieldTrialParamByFeatureAsBool(kUkmFeature, "PruneAppIdLast",
+ false)) {
+ it = source_ids_seen.begin();
+ while (it != source_ids_seen.end()) {
+ if (IsAppIdType(*it)) {
+ source_ids_app_id.insert(*it);
+ it = source_ids_seen.erase(it);
+ } else {
+ it++;
+ }
+ }
+
+ it = source_ids_unseen.begin();
+ while (it != source_ids_unseen.end()) {
+ if (IsAppIdType(*it)) {
+ source_ids_app_id.insert(*it);
+ it = source_ids_unseen.erase(it);
+ } else {
+ it++;
+ }
+ }
+ }
+
+ int pruned_sources_age_sec = 0;
+ int num_sources = recordings_.sources.size();
+ // Setup an experiment to test what will occur if we prune unseen sources
+ // first.
+ if (base::GetFieldTrialParamByFeatureAsBool(
+ kUkmFeature, "PruneUnseenSourcesFirst", false)) {
+ int pruned_sources_age_from_unseen_sec =
+ PruneOldSources(max_kept_sources_, source_ids_unseen);
+
+ UMA_HISTOGRAM_COUNTS_10000("UKM.PrunedSources.NumUnseen",
+ num_sources - recordings_.sources.size());
+ num_sources = recordings_.sources.size();
+
+ // Prune again from seen sources. Note that if we've already pruned enough
+ // from the unseen sources, this will be a noop.
+ int pruned_sources_age_from_seen_sec =
+ PruneOldSources(max_kept_sources_, source_ids_seen);
+
+ UMA_HISTOGRAM_COUNTS_10000("UKM.PrunedSources.NumSeen",
+ num_sources - recordings_.sources.size());
+ num_sources = recordings_.sources.size();
+
+ int pruned_sources_age_from_app_id_sec = 0;
+
+ // Technically this should be fine without the feature, since the group
+ // will be empty, but might as well add the feature check.
+ // Still prune the APP_ID entries. We don't want it to be unbounded, but
+ // providing a higher default here in case.
+ if (base::GetFieldTrialParamByFeatureAsBool(kUkmFeature, "PruneAppIdLast",
+ false)) {
+ pruned_sources_age_from_app_id_sec =
+ PruneOldSources(500, source_ids_app_id);
+
+ UMA_HISTOGRAM_COUNTS_10000("UKM.PrunedSources.NumAppId",
+ num_sources - recordings_.sources.size());
+ }
+
+ // We're looking for the newest age, which will be the largest between the
+ // two sets we pruned from.
+ pruned_sources_age_sec = std::max({pruned_sources_age_from_unseen_sec,
+ pruned_sources_age_from_seen_sec,
+ pruned_sources_age_from_app_id_sec});
+
+ } else {
+ // In this case, we prune all sources without caring if they were seen or
+ // not. Make a set of all existing sources so we can use the same
+ // PruneOldSources method.
+ std::set<SourceId> all_sources;
+ for (const auto& kv : recordings_.sources) {
+ all_sources.insert(kv.first);
+ }
+ if (base::GetFieldTrialParamByFeatureAsBool(kUkmFeature, "PruneAppIdLast",
+ false)) {
+ std::set<SourceId> all_sources_without_app_id;
+
+ // This will put into |all_sources_without_app_id| the set of
+ // |all_sources| - |source_ids_app_id|.
+ std::set_difference(all_sources.begin(), all_sources.end(),
+ source_ids_app_id.begin(), source_ids_app_id.end(),
+ std::inserter(all_sources_without_app_id,
+ all_sources_without_app_id.end()));
+
+ // Now, prune the non-APP_ID, then the APP_ID.
+ int pruned_sources_age_sec_non_app_id =
+ PruneOldSources(max_kept_sources_, all_sources_without_app_id);
+
+ UMA_HISTOGRAM_COUNTS_10000("UKM.PrunedSources.AppExpNumNonAppId",
+ num_sources - recordings_.sources.size());
+ num_sources = recordings_.sources.size();
+
+ int pruned_sources_age_sec_app_id =
+ PruneOldSources(500, source_ids_app_id);
+
+ UMA_HISTOGRAM_COUNTS_10000("UKM.PrunedSources.AppExpNumAppId",
+ num_sources - recordings_.sources.size());
+
+ pruned_sources_age_sec = std::max(pruned_sources_age_sec_non_app_id,
+ pruned_sources_age_sec_app_id);
+
+ } else {
+ pruned_sources_age_sec = PruneOldSources(max_kept_sources_, all_sources);
+ UMA_HISTOGRAM_COUNTS_10000("UKM.PrunedSources.NoExp",
+ num_sources - recordings_.sources.size());
+ }
+ }
+
// Record how old the newest truncated source is.
- source_counts_proto->set_pruned_sources_age_seconds(pruned_sources_age);
+ source_counts_proto->set_pruned_sources_age_seconds(pruned_sources_age_sec);
// Set deferred sources count after pruning.
source_counts_proto->set_deferred_sources(recordings_.sources.size());
- // Same value as the deferred source count, for setting the carryover count in
- // the next reporting cycle.
+ // Same value as the deferred source count, for setting the carryover count
+ // in the next reporting cycle.
recordings_.source_counts.carryover_sources = recordings_.sources.size();
// We already matched these deferred sources against the URL whitelist.
@@ -565,29 +744,62 @@ bool UkmRecorderImpl::ApplyEntryFilter(mojom::UkmEntry* entry) {
return true;
}
-int UkmRecorderImpl::PruneOldSources(size_t max_kept_sources) {
- if (recordings_.sources.size() <= max_kept_sources)
+int UkmRecorderImpl::PruneOldSources(size_t max_kept_sources,
+ const std::set<SourceId>& pruning_set) {
+ long num_prune_required = recordings_.sources.size() - max_kept_sources;
+ // In either case here, nothing to be done.
+ if (num_prune_required <= 0 || pruning_set.size() == 0)
return 0;
+ // We can prune everything, so let's do that directly.
+ if (static_cast<unsigned long>(num_prune_required) >= pruning_set.size()) {
+ base::TimeTicks pruned_sources_age = base::TimeTicks();
+ for (const auto& source_id : pruning_set) {
+ auto creation_time = recordings_.sources[source_id]->creation_time();
+ if (creation_time > pruned_sources_age)
+ pruned_sources_age = creation_time;
+
+ recordings_.sources.erase(source_id);
+ }
+ base::TimeDelta age_delta = base::TimeTicks::Now() - pruned_sources_age;
+ // Technically the age we return here isn't quite right, this is the age of
+ // the newest element of the pruned set, while we actually want the age of
+ // the last one kept. However it's very unlikely to make a difference in
+ // practice as if all are pruned here, it is very likely we'll need to prune
+ // from the seen set next. Since it would be logically quite a bit more
+ // complex to get this exactly right, it's ok for this to be very slightly
+ // off in an edge case just to keep complexity down.
+ return age_delta.InSeconds();
+ }
+
+ // In this case we cannot prune everything, so we will select only the oldest
+ // sources to prune.
+
+ // Build a list of timestamp->source pairs for all source we consider for
+ // pruning.
std::vector<std::pair<base::TimeTicks, SourceId>> timestamp_source_id_pairs;
- for (const auto& kv : recordings_.sources) {
- timestamp_source_id_pairs.push_back(
- std::make_pair(kv.second->creation_time(), kv.first));
+ for (const auto& source_id : pruning_set) {
+ auto creation_time = recordings_.sources[source_id]->creation_time();
+ timestamp_source_id_pairs.emplace_back(
+ std::make_pair(creation_time, source_id));
}
- // Partially sort so that the last |max_kept_sources| elements are the
+
+ // Partially sort so that the last |num_prune_required| elements are the
// newest.
std::nth_element(timestamp_source_id_pairs.begin(),
- timestamp_source_id_pairs.end() - max_kept_sources,
+ timestamp_source_id_pairs.end() - num_prune_required,
timestamp_source_id_pairs.end());
- for (auto kv = timestamp_source_id_pairs.begin();
- kv != timestamp_source_id_pairs.end() - max_kept_sources; ++kv) {
- recordings_.sources.erase(kv->second);
+ // Actually prune |num_prune_required| sources.
+ for (int i = 0; i < num_prune_required; i++) {
+ auto source_id = timestamp_source_id_pairs[i].second;
+ recordings_.sources.erase(source_id);
}
base::TimeDelta pruned_sources_age =
base::TimeTicks::Now() -
- (timestamp_source_id_pairs.end() - (max_kept_sources + 1))->first;
+ (timestamp_source_id_pairs.end() - (num_prune_required + 1))->first;
+
return pruned_sources_age.InSeconds();
}
@@ -600,9 +812,10 @@ void UkmRecorderImpl::UpdateSourceURL(SourceId source_id,
return;
const GURL sanitized_url = SanitizeURL(unsanitized_url);
- if (!ShouldRecordUrl(source_id, sanitized_url))
+ if (ShouldRecordUrl(source_id, sanitized_url) ==
+ ShouldRecordUrlResult::kDropped) {
return;
-
+ }
RecordSource(std::make_unique<UkmSource>(source_id, sanitized_url));
}
@@ -627,8 +840,10 @@ void UkmRecorderImpl::RecordNavigation(
std::vector<GURL> urls;
for (const GURL& url : unsanitized_navigation_data.urls) {
const GURL sanitized_url = SanitizeURL(url);
- if (ShouldRecordUrl(source_id, sanitized_url))
+ if (ShouldRecordUrl(source_id, sanitized_url) !=
+ ShouldRecordUrlResult::kDropped) {
urls.push_back(std::move(sanitized_url));
+ }
}
// None of the URLs passed the ShouldRecordUrl check, so do not create a new
@@ -642,54 +857,73 @@ void UkmRecorderImpl::RecordNavigation(
std::make_unique<UkmSource>(source_id, sanitized_navigation_data));
}
-bool UkmRecorderImpl::ShouldRecordUrl(SourceId source_id,
- const GURL& sanitized_url) const {
+UkmRecorderImpl::ShouldRecordUrlResult UkmRecorderImpl::ShouldRecordUrl(
+ SourceId source_id,
+ const GURL& sanitized_url) const {
+ ShouldRecordUrlResult result = ShouldRecordUrlResult::kOk;
+ bool has_recorded_reason = false;
if (!recording_enabled_) {
RecordDroppedSource(DroppedDataReason::RECORDING_DISABLED);
- return false;
+ // Don't return the result yet. Check if the we are allowed to notify
+ // observers, as they may rely on the not uploaded metrics to determine
+ // how some features should work.
+ result = ShouldRecordUrlResult::kObserverOnly;
+ has_recorded_reason = true;
}
if (recordings_.sources.size() >= max_sources_) {
- RecordDroppedSource(DroppedDataReason::MAX_HIT);
- return false;
+ RecordDroppedSource(has_recorded_reason, DroppedDataReason::MAX_HIT);
+ return ShouldRecordUrlResult::kDropped;
}
if (ShouldRestrictToWhitelistedSourceIds() &&
!IsWhitelistedSourceId(source_id)) {
- RecordDroppedSource(DroppedDataReason::NOT_WHITELISTED);
- return false;
+ RecordDroppedSource(has_recorded_reason,
+ DroppedDataReason::NOT_WHITELISTED);
+ return ShouldRecordUrlResult::kDropped;
}
if (sanitized_url.is_empty()) {
- RecordDroppedSource(DroppedDataReason::EMPTY_URL);
- return false;
+ RecordDroppedSource(has_recorded_reason, DroppedDataReason::EMPTY_URL);
+ return ShouldRecordUrlResult::kDropped;
}
if (!HasSupportedScheme(sanitized_url)) {
- RecordDroppedSource(DroppedDataReason::UNSUPPORTED_URL_SCHEME);
+ RecordDroppedSource(has_recorded_reason,
+ DroppedDataReason::UNSUPPORTED_URL_SCHEME);
DVLOG(2) << "Dropped Unsupported UKM URL:" << source_id << ":"
<< sanitized_url.spec();
- return false;
+ return ShouldRecordUrlResult::kDropped;
}
// Extension URLs need to be specifically enabled and the extension synced.
if (sanitized_url.SchemeIs(kExtensionScheme)) {
DCHECK_EQ(sanitized_url.GetWithEmptyPath(), sanitized_url);
if (!extensions_enabled_) {
- RecordDroppedSource(DroppedDataReason::EXTENSION_URLS_DISABLED);
- return false;
+ RecordDroppedSource(has_recorded_reason,
+ DroppedDataReason::EXTENSION_URLS_DISABLED);
+ return ShouldRecordUrlResult::kDropped;
}
if (!is_webstore_extension_callback_ ||
!is_webstore_extension_callback_.Run(sanitized_url.host_piece())) {
- RecordDroppedSource(DroppedDataReason::EXTENSION_NOT_SYNCED);
- return false;
+ RecordDroppedSource(has_recorded_reason,
+ DroppedDataReason::EXTENSION_NOT_SYNCED);
+ return ShouldRecordUrlResult::kDropped;
}
}
- return true;
+ return result;
}
void UkmRecorderImpl::RecordSource(std::unique_ptr<UkmSource> source) {
SourceId source_id = source->id();
+ // If UKM recording is disabled due to |recording_enabled_|, still notify
+ // observers as they might be interested in it.
+ NotifyAllObservers(&UkmRecorderObserver::OnUpdateSourceURL, source_id,
+ source->urls());
+ if (!recording_enabled_) {
+ return;
+ }
+
if (GetSourceIdType(source_id) == SourceIdType::NAVIGATION_ID)
recordings_.source_counts.navigation_sources++;
recordings_.source_counts.observed++;
@@ -700,6 +934,8 @@ void UkmRecorderImpl::AddEntry(mojom::UkmEntryPtr entry) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(!HasUnknownMetrics(decode_map_, *entry));
+ NotifyObserversWithNewEntry(*entry);
+
if (!recording_enabled_) {
RecordDroppedEntry(entry->event_hash,
DroppedDataReason::RECORDING_DISABLED);
@@ -864,4 +1100,25 @@ void UkmRecorderImpl::InitDecodeMap() {
decode_map_ = builders::CreateDecodeMap();
}
+void UkmRecorderImpl::NotifyObserversWithNewEntry(
+ const mojom::UkmEntry& entry) {
+ base::AutoLock auto_lock(lock_);
+
+ for (const auto& observer : observers_) {
+ if (observer.first.contains(entry.event_hash)) {
+ mojom::UkmEntryPtr cloned = entry.Clone();
+ observer.second->Notify(FROM_HERE, &UkmRecorderObserver::OnEntryAdded,
+ base::Passed(&cloned));
+ }
+ }
+}
+
+template <typename Method, typename... Params>
+void UkmRecorderImpl::NotifyAllObservers(Method m, Params&&... params) {
+ base::AutoLock auto_lock(lock_);
+ for (const auto& observer : observers_) {
+ observer.second->Notify(FROM_HERE, m, std::forward<Params>(params)...);
+ }
+}
+
} // namespace ukm
diff --git a/chromium/components/ukm/ukm_recorder_impl.h b/chromium/components/ukm/ukm_recorder_impl.h
index 1772d41a2fe..c3992011bc3 100644
--- a/chromium/components/ukm/ukm_recorder_impl.h
+++ b/chromium/components/ukm/ukm_recorder_impl.h
@@ -16,9 +16,12 @@
#include "base/callback_forward.h"
#include "base/component_export.h"
#include "base/containers/flat_map.h"
+#include "base/containers/flat_set.h"
#include "base/gtest_prod_util.h"
+#include "base/observer_list_threadsafe.h"
#include "base/sequence_checker.h"
#include "base/strings/string_piece.h"
+#include "base/synchronization/lock.h"
#include "components/ukm/ukm_entry_filter.h"
#include "services/metrics/public/cpp/ukm_decode.h"
#include "services/metrics/public/cpp/ukm_recorder.h"
@@ -32,6 +35,7 @@ class UkmBrowserTestBase;
namespace ukm {
class Report;
class UkmRecorderImplTest;
+class UkmRecorderObserver;
class UkmSource;
class UkmTestHelper;
class UkmUtilsForTest;
@@ -95,6 +99,19 @@ class COMPONENT_EXPORT(UKM_RECORDER) UkmRecorderImpl : public UkmRecorder {
// Currently only accommodates one entry filter.
void SetEntryFilter(std::unique_ptr<UkmEntryFilter> entry_filter);
+ // Register an observer to be notified when a new UKM entry that comes with
+ // one of the |event_hashes| is added. This method can be called on any
+ // thread.
+ void AddUkmRecorderObserver(const base::flat_set<uint64_t>& event_hashes,
+ UkmRecorderObserver* observer);
+
+ // Clears the given |observer| from |observers_|. This method can be called
+ // on any thread. If an observer is registered for multiple event sets, it
+ // will be removed from all the sets. If an event set no longer has any
+ // observers as a result of this call, it will be removed from |observers_|
+ // map.
+ void RemoveUkmRecorderObserver(UkmRecorderObserver* observer);
+
// Sets the sampling seed for testing purposes.
void SetSamplingSeedForTesting(uint32_t seed) {
// Normally the seed is set during object construction and remains
@@ -131,9 +148,11 @@ class COMPONENT_EXPORT(UKM_RECORDER) UkmRecorderImpl : public UkmRecorder {
}
// Keep only newest |max_kept_sources| sources when the number of sources
- // in recordings_ exceeds this threshold. Returns the age of newest truncated
+ // in recordings_ exceeds this threshold. We only consider the set of ids
+ // contained in |pruning_set|. Returns the age of newest truncated
// source in seconds.
- int PruneOldSources(size_t max_kept_sources);
+ int PruneOldSources(size_t max_kept_sources,
+ const std::set<SourceId>& pruning_set);
// UkmRecorder:
void AddEntry(mojom::UkmEntryPtr entry) override;
@@ -158,6 +177,8 @@ class COMPONENT_EXPORT(UKM_RECORDER) UkmRecorderImpl : public UkmRecorder {
FRIEND_TEST_ALL_PREFIXES(UkmRecorderImplTest, PurgeExtensionRecordings);
FRIEND_TEST_ALL_PREFIXES(UkmRecorderImplTest, WebApkSourceUrl);
FRIEND_TEST_ALL_PREFIXES(UkmRecorderImplTest, PaymentAppScopeUrl);
+ FRIEND_TEST_ALL_PREFIXES(UkmRecorderImplTest, ObserverNotifiedOnNewEntry);
+ FRIEND_TEST_ALL_PREFIXES(UkmRecorderImplTest, AddRemoveObserver);
struct MetricAggregate {
uint64_t total_count = 0;
@@ -181,10 +202,21 @@ class COMPONENT_EXPORT(UKM_RECORDER) UkmRecorderImpl : public UkmRecorder {
uint64_t dropped_due_to_unconfigured = 0;
};
+ // Result for ShouldRecordUrl() method.
+ enum class ShouldRecordUrlResult {
+ kOk = 0, // URL will be recorded and observers will be notified.
+ kObserverOnly, // The client has opted out from uploading UKM metrics.
+ // As a result, observers will be notified but URL will not
+ // be recorded.
+ kDropped, // The URL is not allowed to be recorded and will be
+ // dropped. Observers are not nofitied either.
+ };
+
using MetricAggregateMap = std::map<uint64_t, MetricAggregate>;
- // Returns true if |sanitized_url| should be recorded.
- bool ShouldRecordUrl(SourceId source_id, const GURL& sanitized_url) const;
+ // Returns the result whether |sanitized_url| should be recorded.
+ ShouldRecordUrlResult ShouldRecordUrl(SourceId source_id,
+ const GURL& sanitized_url) const;
void RecordSource(std::unique_ptr<UkmSource> source);
@@ -199,6 +231,13 @@ class COMPONENT_EXPORT(UKM_RECORDER) UkmRecorderImpl : public UkmRecorder {
void LoadExperimentSamplingParams(
const std::map<std::string, std::string>& params);
+ // Called to notify interested observers about a newly added UKM entry.
+ void NotifyObserversWithNewEntry(const mojom::UkmEntry& entry);
+
+ // Helper method to notify all observers on UKM events.
+ template <typename Method, typename... Params>
+ void NotifyAllObservers(Method m, Params&&... params);
+
// Whether recording new data is currently allowed.
bool recording_enabled_ = false;
@@ -290,6 +329,21 @@ class COMPONENT_EXPORT(UKM_RECORDER) UkmRecorderImpl : public UkmRecorder {
// new ones being added.
size_t max_entries_ = 5000;
+ using UkmRecorderObserverList =
+ base::ObserverListThreadSafe<UkmRecorderObserver>;
+ // Map from event hashes to observers. The key is a set of event hashes that
+ // their corresponding value pair will be norified when one of those events
+ // is added. The value is a non-empty observer list whose members are
+ // observing those events.
+ using UkmRecorderObserverMap =
+ base::flat_map<base::flat_set<uint64_t> /*event_hashes*/,
+ scoped_refptr<UkmRecorderObserverList>>;
+ // Lock used to ensure mutual exclusive access to |observers_|.
+ mutable base::Lock lock_;
+
+ // Observers that will be notified on UKM events.
+ UkmRecorderObserverMap observers_ GUARDED_BY(lock_);
+
SEQUENCE_CHECKER(sequence_checker_);
};
diff --git a/chromium/components/ukm/ukm_recorder_impl_unittest.cc b/chromium/components/ukm/ukm_recorder_impl_unittest.cc
index f7748a09103..b0c97d233ae 100644
--- a/chromium/components/ukm/ukm_recorder_impl_unittest.cc
+++ b/chromium/components/ukm/ukm_recorder_impl_unittest.cc
@@ -9,6 +9,7 @@
#include "base/test/task_environment.h"
#include "components/ukm/scheme_constants.h"
#include "components/ukm/test_ukm_recorder.h"
+#include "components/ukm/ukm_recorder_observer.h"
#include "services/metrics/public/cpp/ukm_builders.h"
#include "services/metrics/public/cpp/ukm_entry_builder.h"
#include "services/metrics/public/cpp/ukm_source.h"
@@ -21,6 +22,84 @@ namespace ukm {
using TestEvent1 = builders::PageLoad;
+const uint64_t kTestEntryHash = 1234;
+const uint64_t kTestMetricsHash = 12345;
+const char kTestEntryName[] = "TestEntry";
+const char kTestMetrics[] = "TestMetrics";
+
+std::map<uint64_t, builders::EntryDecoder> CreateTestingDecodeMap() {
+ return {
+ {kTestEntryHash,
+ {kTestEntryName,
+ {
+ {kTestMetricsHash, kTestMetrics},
+ }}},
+ };
+}
+
+// Helper class for testing UkmRecorderImpl observers.
+class TestUkmObserver : public UkmRecorderObserver {
+ public:
+ explicit TestUkmObserver(UkmRecorderImpl* ukm_recorder_impl) {
+ base::flat_set<uint64_t> event_hashes = {kTestEntryHash};
+ ukm_recorder_impl->AddUkmRecorderObserver(event_hashes, this);
+ }
+
+ ~TestUkmObserver() override = default;
+
+ // UkmRecorderImpl::UkmRecorderObserver override.
+ void OnEntryAdded(mojom::UkmEntryPtr entry) override {
+ if (stop_waiting_)
+ std::move(stop_waiting_).Run();
+ ASSERT_EQ(entry->event_hash, ukm_entry_->event_hash);
+ ASSERT_EQ(entry->source_id, ukm_entry_->source_id);
+ ASSERT_EQ(entry->metrics[kTestMetricsHash],
+ ukm_entry_->metrics[kTestMetricsHash]);
+ }
+
+ void OnUpdateSourceURL(SourceId source_id,
+ const std::vector<GURL>& urls) override {
+ if (stop_waiting_)
+ std::move(stop_waiting_).Run();
+ ASSERT_EQ(source_id_, source_id);
+ ASSERT_EQ(urls_, urls);
+ }
+
+ void OnPurgeRecordingsWithUrlScheme(const std::string& url_scheme) override {
+ if (stop_waiting_)
+ std::move(stop_waiting_).Run();
+ }
+
+ void OnPurge() override {
+ if (stop_waiting_)
+ std::move(stop_waiting_).Run();
+ }
+
+ void WaitAddEntryCallback(uint64_t event_hash, mojom::UkmEntryPtr ukm_entry) {
+ ukm_entry_ = std::move(ukm_entry);
+ WaitCallback();
+ }
+
+ void WaitUpdateSourceURLCallback(SourceId source_id,
+ const std::vector<GURL>& urls) {
+ source_id_ = source_id;
+ urls_ = urls;
+ WaitCallback();
+ }
+
+ void WaitCallback() {
+ base::RunLoop run_loop;
+ stop_waiting_ = run_loop.QuitClosure();
+ run_loop.Run();
+ }
+
+ private:
+ base::OnceClosure stop_waiting_;
+ mojom::UkmEntryPtr ukm_entry_;
+ SourceId source_id_;
+ std::vector<GURL> urls_;
+};
+
TEST(UkmRecorderImplTest, IsSampledIn) {
UkmRecorderImpl impl;
@@ -172,4 +251,91 @@ TEST(UkmRecorderImplTest, PaymentAppScopeUrl) {
EXPECT_EQ(SourceIdType::PAYMENT_APP_ID, GetSourceIdType(id));
}
+// Tests that UkmRecorderObserver is notified on a new UKM entry.
+TEST(UkmRecorderImplTest, ObserverNotifiedOnNewEntry) {
+ base::test::TaskEnvironment env;
+ ukm::TestAutoSetUkmRecorder test_ukm_recorder;
+ TestUkmObserver test_observer(&test_ukm_recorder);
+
+ test_ukm_recorder.decode_map_ = CreateTestingDecodeMap();
+ auto entry = mojom::UkmEntry::New();
+ entry->event_hash = kTestEntryHash;
+ entry->source_id = 345;
+ entry->metrics[kTestMetricsHash] = 10;
+ test_ukm_recorder.AddEntry(entry->Clone());
+ test_observer.WaitAddEntryCallback(kTestEntryHash, std::move(entry));
+}
+
+// Tests that UkmRecorderObserver is notified on source URL updates.
+TEST(UkmRecorderImplTest, ObserverNotifiedOnSourceURLUpdate) {
+ base::test::TaskEnvironment env;
+ ukm::TestAutoSetUkmRecorder test_ukm_recorder;
+ TestUkmObserver test_observer(&test_ukm_recorder);
+ uint64_t source_id = 345;
+
+ GURL url("http://abc.com");
+ std::vector<GURL> urls;
+ urls.emplace_back(url);
+ test_ukm_recorder.UpdateSourceURL(source_id, url);
+ test_observer.WaitUpdateSourceURLCallback(source_id, urls);
+}
+
+// Tests that UkmRecorderObserver is notified on purge.
+TEST(UkmRecorderImplTest, ObserverNotifiedOnPurge) {
+ base::test::TaskEnvironment env;
+ ukm::TestAutoSetUkmRecorder test_ukm_recorder;
+ TestUkmObserver test_observer(&test_ukm_recorder);
+
+ test_ukm_recorder.PurgeRecordingsWithUrlScheme(kExtensionScheme);
+ test_observer.WaitCallback();
+
+ test_ukm_recorder.Purge();
+ test_observer.WaitCallback();
+}
+
+// Tests that adding and removing observers work as expected.
+TEST(UkmRecorderImplTest, AddRemoveObserver) {
+ base::test::TaskEnvironment env;
+ ukm::TestAutoSetUkmRecorder test_ukm_recorder;
+
+ // Adding 3 observers, the first 2 oberserve the same event
+ // while the last one observes a different event.
+ UkmRecorderObserver obs1, obs2, obs3;
+ base::flat_set<uint64_t> events1 = {123};
+ test_ukm_recorder.AddUkmRecorderObserver(events1, &obs1);
+ test_ukm_recorder.AddUkmRecorderObserver(events1, &obs2);
+ base::flat_set<uint64_t> events2 = {345};
+ test_ukm_recorder.AddUkmRecorderObserver(events2, &obs3);
+
+ // Remove the first observer.
+ test_ukm_recorder.RemoveUkmRecorderObserver(&obs1);
+ {
+ base::AutoLock auto_lock(test_ukm_recorder.lock_);
+ ASSERT_FALSE(test_ukm_recorder.observers_.empty());
+ // There are still 2 separate events being observed, each
+ // has one observer now.
+ ASSERT_NE(test_ukm_recorder.observers_.find(events1),
+ test_ukm_recorder.observers_.end());
+ ASSERT_NE(test_ukm_recorder.observers_.find(events2),
+ test_ukm_recorder.observers_.end());
+ }
+ // Removing the 2nd observer.
+ test_ukm_recorder.RemoveUkmRecorderObserver(&obs2);
+ {
+ base::AutoLock auto_lock(test_ukm_recorder.lock_);
+ // Only the 2nd event is being observed now, the first
+ // event should be removed from the observers map.
+ ASSERT_EQ(test_ukm_recorder.observers_.find(events1),
+ test_ukm_recorder.observers_.end());
+ ASSERT_NE(test_ukm_recorder.observers_.find(events2),
+ test_ukm_recorder.observers_.end());
+ }
+ // Removing the last observer should clear the observer map.
+ test_ukm_recorder.RemoveUkmRecorderObserver(&obs3);
+ {
+ base::AutoLock auto_lock(test_ukm_recorder.lock_);
+ ASSERT_TRUE(test_ukm_recorder.observers_.empty());
+ }
+}
+
} // namespace ukm
diff --git a/chromium/components/ukm/ukm_recorder_observer.cc b/chromium/components/ukm/ukm_recorder_observer.cc
new file mode 100644
index 00000000000..e3bf89a113a
--- /dev/null
+++ b/chromium/components/ukm/ukm_recorder_observer.cc
@@ -0,0 +1,19 @@
+// Copyright 2022 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.
+
+#include "components/ukm/ukm_recorder_observer.h"
+
+namespace ukm {
+
+void UkmRecorderObserver::OnEntryAdded(mojom::UkmEntryPtr entry) {}
+
+void UkmRecorderObserver::OnUpdateSourceURL(SourceId source_id,
+ const std::vector<GURL>& urls) {}
+
+void UkmRecorderObserver::OnPurgeRecordingsWithUrlScheme(
+ const std::string& url_scheme) {}
+
+void UkmRecorderObserver::OnPurge() {}
+
+} // namespace ukm
diff --git a/chromium/components/ukm/ukm_recorder_observer.h b/chromium/components/ukm/ukm_recorder_observer.h
new file mode 100644
index 00000000000..0e970e503b2
--- /dev/null
+++ b/chromium/components/ukm/ukm_recorder_observer.h
@@ -0,0 +1,46 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_UKM_UKM_RECORDER_OBSERVER_H_
+#define COMPONENTS_UKM_UKM_RECORDER_OBSERVER_H_
+
+#include <vector>
+
+#include "base/observer_list_types.h"
+#include "services/metrics/public/cpp/ukm_source_id.h"
+#include "services/metrics/public/mojom/ukm_interface.mojom.h"
+#include "url/gurl.h"
+
+namespace ukm {
+
+// Base class for observing UkmRecorderImpl. This object is notified when
+// a new UKM entry is added, or when a source URL is updated, or when
+// purge happens. Observers are notified even if |recording_enabled_| is
+// false. All the methods are notified on the same SequencedTaskRunner
+// on which the observer is added.
+class COMPONENT_EXPORT(UKM_RECORDER) UkmRecorderObserver
+ : public base::CheckedObserver {
+ public:
+ UkmRecorderObserver() = default;
+ ~UkmRecorderObserver() override = default;
+ UkmRecorderObserver(const UkmRecorderObserver&) = delete;
+ UkmRecorderObserver& operator=(const UkmRecorderObserver&) = delete;
+
+ // Called when a new UKM entry is added.
+ virtual void OnEntryAdded(mojom::UkmEntryPtr entry);
+
+ // Called when URLs are updated for a |source_id|.
+ virtual void OnUpdateSourceURL(SourceId source_id,
+ const std::vector<GURL>& urls);
+
+ // Called when UKM entries related to the given URL scheme should be purged.
+ virtual void OnPurgeRecordingsWithUrlScheme(const std::string& url_scheme);
+
+ // Called when all UKM entries should be purged.
+ virtual void OnPurge();
+};
+
+} // namespace ukm
+
+#endif // COMPONENTS_UKM_UKM_RECORDER_OBSERVER_H_
diff --git a/chromium/components/ukm/ukm_reporting_service.cc b/chromium/components/ukm/ukm_reporting_service.cc
index 25f979e9145..a8cf2000fde 100644
--- a/chromium/components/ukm/ukm_reporting_service.cc
+++ b/chromium/components/ukm/ukm_reporting_service.cc
@@ -19,7 +19,7 @@
#include "components/ukm/unsent_log_store_metrics_impl.h"
#include "third_party/zlib/google/compression_utils.h"
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
#include "components/ukm/ios/ukm_reporting_ios_util.h"
#endif
@@ -113,7 +113,7 @@ void UkmReportingService::LogResponseOrErrorCode(int response_code,
}
void UkmReportingService::LogSuccessLogSize(size_t log_size) {
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
IncrementUkmLogSizeOnSuccessCounter();
#endif
UMA_HISTOGRAM_COUNTS_10000("UKM.LogSize.OnSuccess", log_size / 1024);
diff --git a/chromium/components/ukm/ukm_service.cc b/chromium/components/ukm/ukm_service.cc
index e1f7360edd3..93c5640f094 100644
--- a/chromium/components/ukm/ukm_service.cc
+++ b/chromium/components/ukm/ukm_service.cc
@@ -18,6 +18,7 @@
#include "base/rand_util.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "base/time/time.h"
+#include "build/build_config.h"
#include "components/metrics/metrics_log.h"
#include "components/metrics/metrics_service_client.h"
#include "components/metrics/ukm_demographic_metrics_provider.h"
@@ -272,7 +273,7 @@ void UkmService::DisableReporting() {
Flush();
}
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
void UkmService::OnAppEnterForeground() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DVLOG(1) << "UkmService::OnAppEnterForeground";
diff --git a/chromium/components/ukm/ukm_service.h b/chromium/components/ukm/ukm_service.h
index 0b6c1904ff8..3769190f8ca 100644
--- a/chromium/components/ukm/ukm_service.h
+++ b/chromium/components/ukm/ukm_service.h
@@ -78,7 +78,7 @@ class UkmService : public UkmRecorderImpl {
void EnableReporting();
void DisableReporting();
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
void OnAppEnterBackground();
void OnAppEnterForeground();
#endif
diff --git a/chromium/components/ukm/ukm_service_unittest.cc b/chromium/components/ukm/ukm_service_unittest.cc
index 555f6aaa870..79b5732000c 100644
--- a/chromium/components/ukm/ukm_service_unittest.cc
+++ b/chromium/components/ukm/ukm_service_unittest.cc
@@ -57,7 +57,7 @@ const char* kTestEvent1Metric2 = TestEvent1::kNet_CacheBytes2Name;
using TestEvent2 = builders::Memory_Experimental;
const char* kTestEvent2Metric1 = TestEvent2::kArrayBufferName;
const char* kTestEvent2Metric2 = TestEvent2::kBlinkGCName;
-using TestEvent3 = builders::Previews;
+using TestEvent3 = builders::PageWithPassword;
using TestProviderEvent = builders::ScreenBrightness;
SourceId ConvertSourceIdToWhitelistedType(SourceId id, SourceIdType type) {
@@ -160,9 +160,8 @@ class UkmServiceTest : public testing::Test {
}
int GetPersistedLogCount() {
- const base::ListValue* list_value =
- prefs_.GetList(prefs::kUkmUnsentLogStore);
- return list_value->GetList().size();
+ const base::Value* list_value = prefs_.GetList(prefs::kUkmUnsentLogStore);
+ return list_value->GetListDeprecated().size();
}
Report GetPersistedReport() {
@@ -187,6 +186,10 @@ class UkmServiceTest : public testing::Test {
return ConvertToSourceId(id, SourceIdType::NAVIGATION_ID);
}
+ static SourceId GetAppIDSourceId(int64_t id) {
+ return ConvertToSourceId(id, SourceIdType::APP_ID);
+ }
+
static SourceId GetNonWhitelistedSourceId(int64_t id) {
return ConvertToSourceId(id, SourceIdType::DEFAULT);
}
@@ -485,9 +488,6 @@ TEST_F(UkmServiceTest, AddEntryWithEmptyMetrics) {
}
TEST_F(UkmServiceTest, MetricsProviderTest) {
- ScopedUkmFeatureParams params(
- {{"WhitelistEntries", std::string(TestProviderEvent::kEntryName)}});
-
UkmService service(&prefs_, &client_,
std::make_unique<MockDemographicMetricsProvider>());
TestRecordingHelper recorder(&service);
@@ -1583,4 +1583,213 @@ TEST_F(UkmServiceTest, FilterRejectsEvent) {
proto_report.aggregates(0).metrics(0).has_dropped_due_to_filter());
}
+TEST_F(UkmServiceTest, PruneUnseenFirst) {
+ // We will be testing with the prune unseen feature both off and on.
+ for (bool prune_unseen_sources_first : {true, false}) {
+ const GURL kURL("https://google.com/foobar");
+
+ // Set the 'MaxKeptSources' value to 3 so it is easier to test.
+ ScopedUkmFeatureParams params(
+ {{"MaxKeptSources", "3"},
+ {"PruneUnseenSourcesFirst",
+ prune_unseen_sources_first ? "true" : "false"}});
+
+ ClearPrefs();
+ UkmService service(&prefs_, &client_,
+ std::make_unique<MockDemographicMetricsProvider>());
+ TestRecordingHelper recorder(&service);
+ EXPECT_EQ(0, GetPersistedLogCount());
+ service.Initialize();
+ task_runner_->RunUntilIdle();
+ service.EnableRecording(/*extensions=*/false);
+ service.EnableReporting();
+
+ // Create 5 whitelisted ids. Whitelisted ids (like APP_ID) will not be
+ // automatically removed when they emit events. They're only removed via the
+ // pruning mechanism. Note that the are added in order, so 4 is the
+ // youngest/newest.
+ std::vector<SourceId> ids;
+ base::TimeTicks last_time = base::TimeTicks::Now();
+ for (int i = 0; i < 5; ++i) {
+ // Wait until base::TimeTicks::Now() no longer equals |last_time|. This
+ // ensures each source has a unique timestamp to avoid flakes. Should take
+ // between 1-15ms per documented resolution of base::TimeTicks.
+ while (base::TimeTicks::Now() == last_time) {
+ base::PlatformThread::Sleep(base::Milliseconds(1));
+ }
+ ids.push_back(GetWhitelistedSourceId(i));
+ recorder.UpdateSourceURL(ids.back(), kURL);
+ last_time = base::TimeTicks::Now();
+ }
+
+ // Events on 0 and 4. This will be important to this test, as we are testing
+ // how pruning will vary based on this. So keep this in mind.
+ TestEvent1(ids[0]).Record(&service);
+ TestEvent1(ids[4]).Record(&service);
+
+ service.Flush();
+ EXPECT_EQ(1, GetPersistedLogCount());
+ auto proto_report = GetPersistedReport();
+
+ EXPECT_EQ(5, proto_report.source_counts().observed());
+ // All are navigation sources.
+ EXPECT_EQ(5, proto_report.source_counts().navigation_sources());
+ EXPECT_EQ(0, proto_report.source_counts().unmatched_sources());
+
+ // In all cases, 3 will be deferred since that is our max allowed.
+ EXPECT_EQ(3, proto_report.source_counts().deferred_sources());
+ // This is from last time, so none there.
+ EXPECT_EQ(0, proto_report.source_counts().carryover_sources());
+
+ // All 5 sources will be included in this first report.
+ ASSERT_EQ(5, proto_report.sources_size());
+ EXPECT_EQ(ids[0], proto_report.sources(0).id());
+ EXPECT_EQ(ids[1], proto_report.sources(1).id());
+ EXPECT_EQ(ids[2], proto_report.sources(2).id());
+ EXPECT_EQ(ids[3], proto_report.sources(3).id());
+ EXPECT_EQ(ids[4], proto_report.sources(4).id());
+
+ // Depending on the PruneUnseenSourcesFirst setting, different ones will be
+ // removed.
+ // We have MaxKeptSources=3.
+ // If PruneUnseenSourcesFirst was set, then the ones kept should be the two
+ // that were used, which are 0 and 4. The one remaining one will be picked
+ // via age which will be 3, so 0, 3, 4 are kept.
+ // Otherwise, it will be entirely based on age, which is 2,3,4.
+
+ // New events on 0,2,4. This actually doesn't matter with respect to what
+ // sources are emitted here, as some sources are already pruned.
+ TestEvent1(ids[0]).Record(&service);
+ TestEvent1(ids[2]).Record(&service);
+ TestEvent1(ids[4]).Record(&service);
+
+ service.Flush();
+ EXPECT_EQ(2, GetPersistedLogCount());
+ proto_report = GetPersistedReport();
+
+ // No new sources observed.
+ EXPECT_EQ(0, proto_report.source_counts().observed());
+ // 0 again, as this is for newly observed ones.
+ EXPECT_EQ(0, proto_report.source_counts().navigation_sources());
+ EXPECT_EQ(0, proto_report.source_counts().unmatched_sources());
+
+ // Since no new sources added, we still are keeping the same 3. So all 3 are
+ // kept and retained, in both cases.
+ EXPECT_EQ(3, proto_report.source_counts().deferred_sources());
+ EXPECT_EQ(3, proto_report.source_counts().carryover_sources());
+ ASSERT_EQ(3, proto_report.sources_size());
+
+ if (prune_unseen_sources_first) {
+ // 0, 3, 4 as 0 and 4 were used last time, and 3 is the newest of the
+ // remaining.
+ EXPECT_EQ(ids[0], proto_report.sources(0).id());
+ EXPECT_EQ(ids[3], proto_report.sources(1).id());
+ EXPECT_EQ(ids[4], proto_report.sources(2).id());
+ } else {
+ // 2, 3, 4 as these are the 3 newest, which is the only criteria we are
+ // using for this test.
+ EXPECT_EQ(ids[2], proto_report.sources(0).id());
+ EXPECT_EQ(ids[3], proto_report.sources(1).id());
+ EXPECT_EQ(ids[4], proto_report.sources(2).id());
+ }
+ }
+}
+
+TEST_F(UkmServiceTest, PruneAppIDLast) {
+ // We will be testing with the PruneAppIdLast feature both off and on.
+ for (bool prune_app_id_last : {true, false}) {
+ const GURL kURL("https://google.com/foobar");
+
+ // Set the 'MaxKeptSources' value to 3 so it is easier to test.
+ ScopedUkmFeatureParams params(
+ {{"MaxKeptSources", "3"},
+ {"PruneAppIdLast", prune_app_id_last ? "true" : "false"}});
+
+ ClearPrefs();
+ UkmService service(&prefs_, &client_,
+ std::make_unique<MockDemographicMetricsProvider>());
+ TestRecordingHelper recorder(&service);
+ EXPECT_EQ(0, GetPersistedLogCount());
+ service.Initialize();
+ task_runner_->RunUntilIdle();
+ service.EnableRecording(/*extensions=*/false);
+ service.EnableReporting();
+
+ // Create 5 sources. We set source 0 and 4 to be APP_ID Sources, where
+ // 1,2,3 are whitelisted/navigation sources.
+ std::vector<SourceId> ids;
+ base::TimeTicks last_time = base::TimeTicks::Now();
+ for (int i = 0; i < 5; ++i) {
+ // Wait until base::TimeTicks::Now() no longer equals |last_time|. This
+ // ensures each source has a unique timestamp to avoid flakes. Should take
+ // between 1-15ms per documented resolution of base::TimeTicks.
+ while (base::TimeTicks::Now() == last_time) {
+ base::PlatformThread::Sleep(base::Milliseconds(1));
+ }
+ // Note, this is where we are setting the source types. Important for the
+ // testing.
+ if (i == 0 || i == 4) {
+ ids.push_back(GetAppIDSourceId(i));
+ } else {
+ ids.push_back(GetWhitelistedSourceId(i));
+ }
+ recorder.UpdateSourceURL(ids.back(), kURL);
+ last_time = base::TimeTicks::Now();
+ }
+
+ service.Flush();
+ EXPECT_EQ(1, GetPersistedLogCount());
+ auto proto_report = GetPersistedReport();
+
+ EXPECT_EQ(5, proto_report.source_counts().observed());
+
+ // In all cases, 3 will be deferred since that is our max allowed.
+ EXPECT_EQ(3, proto_report.source_counts().deferred_sources());
+ // This is from last time, so none there.
+ EXPECT_EQ(0, proto_report.source_counts().carryover_sources());
+
+ // All 5 sources will be included in this first report.
+ ASSERT_EQ(5, proto_report.sources_size());
+ EXPECT_EQ(ids[0], proto_report.sources(0).id());
+ EXPECT_EQ(ids[1], proto_report.sources(1).id());
+ EXPECT_EQ(ids[2], proto_report.sources(2).id());
+ EXPECT_EQ(ids[3], proto_report.sources(3).id());
+ EXPECT_EQ(ids[4], proto_report.sources(4).id());
+
+ // We have MaxKeptSources=3.
+ // If PruneAppIdLast was set, then the ones kept should be the two that were
+ // set as APP_ID, which are 0 and 4. The one remaining one will be picked
+ // via age which will be 3, so 0, 3, 4 are kept.
+ // Otherwise, it will be entirely based on age, which is 2,3,4.
+
+ service.Flush();
+ EXPECT_EQ(2, GetPersistedLogCount());
+ proto_report = GetPersistedReport();
+
+ // No new sources observed.
+ EXPECT_EQ(0, proto_report.source_counts().observed());
+ // 0 again, as this is for newly observed ones.
+ EXPECT_EQ(0, proto_report.source_counts().unmatched_sources());
+
+ // Since no new sources added, we still are keeping the same 3. So all 3 are
+ // kept and retained, in both cases.
+ EXPECT_EQ(3, proto_report.source_counts().deferred_sources());
+ EXPECT_EQ(3, proto_report.source_counts().carryover_sources());
+ ASSERT_EQ(3, proto_report.sources_size());
+
+ if (prune_app_id_last) {
+ // 0, 3, 4 as 0 and 4 are APP_ID, and 3 is the newest of the remaining.
+ EXPECT_EQ(ids[0], proto_report.sources(0).id());
+ EXPECT_EQ(ids[3], proto_report.sources(1).id());
+ EXPECT_EQ(ids[4], proto_report.sources(2).id());
+ } else {
+ // 2, 3, 4 as these are the 3 newest, which is the only criteria we are
+ // using for this test.
+ EXPECT_EQ(ids[2], proto_report.sources(0).id());
+ EXPECT_EQ(ids[3], proto_report.sources(1).id());
+ EXPECT_EQ(ids[4], proto_report.sources(2).id());
+ }
+ }
+}
+
} // namespace ukm
diff --git a/chromium/components/undo/undo_manager.cc b/chromium/components/undo/undo_manager.cc
index 5cf52bec351..40590ed8495 100644
--- a/chromium/components/undo/undo_manager.cc
+++ b/chromium/components/undo/undo_manager.cc
@@ -9,6 +9,7 @@
#include "base/auto_reset.h"
#include "base/check_op.h"
+#include "base/containers/adapters.h"
#include "base/memory/ptr_util.h"
#include "components/strings/grit/components_strings.h"
#include "components/undo/undo_manager_observer.h"
@@ -41,8 +42,9 @@ void UndoGroup::AddOperation(std::unique_ptr<UndoOperation> operation) {
}
void UndoGroup::Undo() {
- for (auto ri = operations_.rbegin(); ri != operations_.rend(); ++ri)
- (*ri)->Undo();
+ for (const std::unique_ptr<UndoOperation>& operation :
+ base::Reversed(operations_))
+ operation->Undo();
}
// UndoManager ----------------------------------------------------------------
diff --git a/chromium/components/unified_consent/README.md b/chromium/components/unified_consent/README.md
index e37be17082a..691d9bde706 100644
--- a/chromium/components/unified_consent/README.md
+++ b/chromium/components/unified_consent/README.md
@@ -3,6 +3,4 @@ manages user consent when the Unified Consent feature is enabled. It also
holds the prefs and the APIs allowing the various Chromium features to verify if
the user has given consent for a given feature.
-This component is currently in development.
-
The component is used on all platforms (desktop, ChromeOS, Android and iOS).
diff --git a/chromium/components/unified_consent/unified_consent_metrics.cc b/chromium/components/unified_consent/unified_consent_metrics.cc
index e235a4a6f58..c3bdd21585b 100644
--- a/chromium/components/unified_consent/unified_consent_metrics.cc
+++ b/chromium/components/unified_consent/unified_consent_metrics.cc
@@ -34,9 +34,9 @@ enum class SyncDataType {
kPasswords = 8,
kAutofill = 9,
kPayments = 10,
- kSync = 11,
+ // kSync = 11,
- kMaxValue = kSync
+ kMaxValue = kPayments
};
void RecordSyncDataTypeSample(SyncDataType data_type) {
@@ -50,13 +50,6 @@ void RecordSyncDataTypeSample(SyncDataType data_type) {
// Returns true if a sample was recorded.
bool RecordSyncSetupDataTypesImpl(syncer::SyncUserSettings* sync_settings,
PrefService* pref_service) {
-#if defined(OS_ANDROID)
- if (!sync_settings->IsSyncRequested()) {
- RecordSyncDataTypeSample(SyncDataType::kSync);
- return true; // Don't record states of data types if sync is disabled.
- }
-#endif
-
bool metric_recorded = false;
std::vector<std::pair<SyncDataType, syncer::UserSelectableType>> sync_types;
@@ -72,7 +65,7 @@ bool RecordSyncSetupDataTypesImpl(syncer::SyncUserSettings* sync_settings,
syncer::UserSelectableType::kPasswords);
sync_types.emplace_back(SyncDataType::kAutofill,
syncer::UserSelectableType::kAutofill);
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
sync_types.emplace_back(SyncDataType::kApps,
syncer::UserSelectableType::kApps);
sync_types.emplace_back(SyncDataType::kExtensions,
@@ -81,9 +74,9 @@ bool RecordSyncSetupDataTypesImpl(syncer::SyncUserSettings* sync_settings,
syncer::UserSelectableType::kThemes);
#endif
- for (const auto& data_type : sync_types) {
- if (!sync_settings->GetSelectedTypes().Has(data_type.second)) {
- RecordSyncDataTypeSample(data_type.first);
+ for (const auto& [bucket, type] : sync_types) {
+ if (!sync_settings->GetSelectedTypes().Has(type)) {
+ RecordSyncDataTypeSample(bucket);
metric_recorded = true;
}
}
diff --git a/chromium/components/update_client/BUILD.gn b/chromium/components/update_client/BUILD.gn
index 2be2468863d..b334c4c8d36 100644
--- a/chromium/components/update_client/BUILD.gn
+++ b/chromium/components/update_client/BUILD.gn
@@ -142,8 +142,6 @@ static_library("update_client") {
"update_query_params.h",
"update_query_params_delegate.cc",
"update_query_params_delegate.h",
- "updater_state.cc",
- "updater_state.h",
"url_fetcher_downloader.cc",
"url_fetcher_downloader.h",
"utils.cc",
@@ -167,13 +165,8 @@ static_library("update_client") {
sources += [
"background_downloader_win.cc",
"background_downloader_win.h",
- "updater_state_win.cc",
]
}
-
- if (is_mac) {
- sources += [ "updater_state_mac.mm" ]
- }
}
static_library("test_support") {
@@ -255,7 +248,6 @@ source_set("unit_tests") {
"update_checker_unittest.cc",
"update_client_unittest.cc",
"update_query_params_unittest.cc",
- "updater_state_unittest.cc",
"utils_unittest.cc",
]
diff --git a/chromium/components/update_client/command_line_config_policy.cc b/chromium/components/update_client/command_line_config_policy.cc
index fa024978fdd..7a5bd1b879b 100644
--- a/chromium/components/update_client/command_line_config_policy.cc
+++ b/chromium/components/update_client/command_line_config_policy.cc
@@ -10,7 +10,7 @@
namespace update_client {
bool CommandLineConfigPolicy::BackgroundDownloadsEnabled() const {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
return true;
#else
return false;
diff --git a/chromium/components/update_client/component.cc b/chromium/components/update_client/component.cc
index eb3a7c97422..5e937916c6a 100644
--- a/chromium/components/update_client/component.cc
+++ b/chromium/components/update_client/component.cc
@@ -5,6 +5,7 @@
#include "components/update_client/component.h"
#include <algorithm>
+#include <tuple>
#include <utility>
#include "base/bind.h"
@@ -13,7 +14,6 @@
#include "base/check_op.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
-#include "base/ignore_result.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/notreached.h"
@@ -112,7 +112,7 @@ void InstallOnBlockingTaskRunner(
// Acquire the ownership of the |unpack_path|.
base::ScopedTempDir unpack_path_owner;
- ignore_result(unpack_path_owner.Set(unpack_path));
+ std::ignore = unpack_path_owner.Set(unpack_path);
if (static_cast<int>(fingerprint.size()) !=
base::WriteFile(
diff --git a/chromium/components/update_client/component_patcher.cc b/chromium/components/update_client/component_patcher.cc
index de1106a0c37..fc58e4f930e 100644
--- a/chromium/components/update_client/component_patcher.cc
+++ b/chromium/components/update_client/component_patcher.cc
@@ -66,13 +66,13 @@ void ComponentPatcher::StartPatching() {
if (!commands_) {
DonePatching(UnpackerError::kDeltaBadCommands, 0);
} else {
- next_command_ = commands_->GetList().begin();
+ next_command_ = commands_->GetListDeprecated().begin();
PatchNextFile();
}
}
void ComponentPatcher::PatchNextFile() {
- if (next_command_ == commands_->GetList().end()) {
+ if (next_command_ == commands_->GetListDeprecated().end()) {
DonePatching(UnpackerError::kNone, 0);
return;
}
diff --git a/chromium/components/update_client/component_patcher_operation.cc b/chromium/components/update_client/component_patcher_operation.cc
index 2dd2f7e1797..29f5c9adfa5 100644
--- a/chromium/components/update_client/component_patcher_operation.cc
+++ b/chromium/components/update_client/component_patcher_operation.cc
@@ -64,15 +64,16 @@ void DeltaUpdateOp::Run(const base::DictionaryValue* command_args,
scoped_refptr<CrxInstaller> installer,
ComponentPatcher::Callback callback) {
callback_ = std::move(callback);
- std::string output_rel_path;
- if (!command_args->GetString(kOutput, &output_rel_path) ||
- !command_args->GetString(kSha256, &output_sha256_)) {
+ const std::string* output_rel_path = command_args->FindStringKey(kOutput);
+ const std::string* sha256_value = command_args->FindStringKey(kSha256);
+ if (!output_rel_path || !sha256_value) {
DoneRunning(UnpackerError::kDeltaBadCommands, 0);
return;
}
+ output_sha256_ = *sha256_value;
output_abs_path_ =
- unpack_dir.Append(base::FilePath::FromUTF8Unsafe(output_rel_path));
+ unpack_dir.Append(base::FilePath::FromUTF8Unsafe(*output_rel_path));
UnpackerError parse_result =
DoParseArguments(command_args, input_dir, installer);
if (parse_result != UnpackerError::kNone) {
@@ -115,11 +116,11 @@ UnpackerError DeltaUpdateOpCopy::DoParseArguments(
const base::DictionaryValue* command_args,
const base::FilePath& input_dir,
scoped_refptr<CrxInstaller> installer) {
- std::string input_rel_path;
- if (!command_args->GetString(kInput, &input_rel_path))
+ const std::string* input_rel_path = command_args->FindStringKey(kInput);
+ if (!input_rel_path)
return UnpackerError::kDeltaBadCommands;
- if (!installer->GetInstalledFile(input_rel_path, &input_abs_path_))
+ if (!installer->GetInstalledFile(*input_rel_path, &input_abs_path_))
return UnpackerError::kDeltaMissingExistingFile;
return UnpackerError::kNone;
@@ -140,12 +141,12 @@ UnpackerError DeltaUpdateOpCreate::DoParseArguments(
const base::DictionaryValue* command_args,
const base::FilePath& input_dir,
scoped_refptr<CrxInstaller> installer) {
- std::string patch_rel_path;
- if (!command_args->GetString(kPatch, &patch_rel_path))
+ const std::string* patch_rel_path = command_args->FindStringKey(kPatch);
+ if (!patch_rel_path)
return UnpackerError::kDeltaBadCommands;
patch_abs_path_ =
- input_dir.Append(base::FilePath::FromUTF8Unsafe(patch_rel_path));
+ input_dir.Append(base::FilePath::FromUTF8Unsafe(*patch_rel_path));
return UnpackerError::kNone;
}
@@ -169,17 +170,16 @@ UnpackerError DeltaUpdateOpPatch::DoParseArguments(
const base::DictionaryValue* command_args,
const base::FilePath& input_dir,
scoped_refptr<CrxInstaller> installer) {
- std::string patch_rel_path;
- std::string input_rel_path;
- if (!command_args->GetString(kPatch, &patch_rel_path) ||
- !command_args->GetString(kInput, &input_rel_path))
+ const std::string* patch_rel_path = command_args->FindStringKey(kPatch);
+ const std::string* input_rel_path = command_args->FindStringKey(kInput);
+ if (!patch_rel_path || !input_rel_path)
return UnpackerError::kDeltaBadCommands;
- if (!installer->GetInstalledFile(input_rel_path, &input_abs_path_))
+ if (!installer->GetInstalledFile(*input_rel_path, &input_abs_path_))
return UnpackerError::kDeltaMissingExistingFile;
patch_abs_path_ =
- input_dir.Append(base::FilePath::FromUTF8Unsafe(patch_rel_path));
+ input_dir.Append(base::FilePath::FromUTF8Unsafe(*patch_rel_path));
return UnpackerError::kNone;
}
diff --git a/chromium/components/update_client/configurator.h b/chromium/components/update_client/configurator.h
index 01af489dbd0..657b9e35c03 100644
--- a/chromium/components/update_client/configurator.h
+++ b/chromium/components/update_client/configurator.h
@@ -10,8 +10,10 @@
#include <tuple>
#include <vector>
+#include "base/callback_forward.h"
#include "base/containers/flat_map.h"
#include "base/memory/ref_counted.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
class GURL;
class PrefService;
@@ -29,6 +31,10 @@ class PatcherFactory;
class ProtocolHandlerFactory;
class UnzipperFactory;
+using UpdaterStateAttributes = base::flat_map<std::string, std::string>;
+using UpdaterStateProvider =
+ base::RepeatingCallback<UpdaterStateAttributes(bool is_machine)>;
+
// Controls the component updater behavior.
// TODO(sorin): this class will be split soon in two. One class controls
// the behavior of the update client, and the other class controls the
@@ -134,6 +140,15 @@ class Configurator : public base::RefCountedThreadSafe<Configurator> {
virtual std::unique_ptr<ProtocolHandlerFactory> GetProtocolHandlerFactory()
const = 0;
+ // Returns true if Chrome is installed on a system managed by cloud or
+ // group policies, false if the system is not managed, or nullopt if the
+ // platform does not support client management at all.
+ virtual absl::optional<bool> IsMachineExternallyManaged() const = 0;
+
+ // Returns a callable to get the state of the platform updater, if the
+ // embedder includes an updater. Returns a null callback otherwise.
+ virtual UpdaterStateProvider GetUpdaterStateProvider() const = 0;
+
protected:
friend class base::RefCountedThreadSafe<Configurator>;
diff --git a/chromium/components/update_client/crx_downloader.cc b/chromium/components/update_client/crx_downloader.cc
index 2e08652ba67..787235583c8 100644
--- a/chromium/components/update_client/crx_downloader.cc
+++ b/chromium/components/update_client/crx_downloader.cc
@@ -13,7 +13,7 @@
#include "base/task/thread_pool.h"
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include "components/update_client/background_downloader_win.h"
#endif
#include "components/update_client/network.h"
diff --git a/chromium/components/update_client/crx_downloader_factory.cc b/chromium/components/update_client/crx_downloader_factory.cc
index 21fb6a5d7a2..7d0afd9ec67 100644
--- a/chromium/components/update_client/crx_downloader_factory.cc
+++ b/chromium/components/update_client/crx_downloader_factory.cc
@@ -5,7 +5,7 @@
#include "components/update_client/crx_downloader_factory.h"
#include "build/build_config.h"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include "components/update_client/background_downloader_win.h"
#endif
#include "components/update_client/crx_downloader.h"
@@ -36,7 +36,7 @@ scoped_refptr<CrxDownloader> CrxDownloaderFactoryChromium::MakeCrxDownloader(
scoped_refptr<CrxDownloader> url_fetcher_downloader =
base::MakeRefCounted<UrlFetcherDownloader>(nullptr,
network_fetcher_factory_);
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// If background downloads are allowed, then apply the BITS service
// background downloader first.
if (background_download_enabled) {
diff --git a/chromium/components/update_client/net/network_impl.cc b/chromium/components/update_client/net/network_impl.cc
index 2f3e7f3d9a3..6f33a3d05f3 100644
--- a/chromium/components/update_client/net/network_impl.cc
+++ b/chromium/components/update_client/net/network_impl.cc
@@ -16,6 +16,7 @@
#include "services/network/public/cpp/resource_request.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "services/network/public/cpp/simple_url_loader.h"
+#include "services/network/public/cpp/simple_url_loader_throttle.h"
#include "services/network/public/mojom/url_response_head.mojom.h"
#include "url/gurl.h"
@@ -118,6 +119,8 @@ void NetworkFetcherImpl::PostRequest(
resource_request->headers.SetHeader(header.first, header.second);
simple_url_loader_ = network::SimpleURLLoader::Create(
std::move(resource_request), traffic_annotation);
+ if (network::SimpleURLLoaderThrottle::IsBatchingEnabled(traffic_annotation))
+ simple_url_loader_->SetAllowBatching();
simple_url_loader_->SetRetryOptions(
kMaxRetriesOnNetworkChange,
network::SimpleURLLoader::RETRY_ON_NETWORK_CHANGE);
diff --git a/chromium/components/update_client/ping_manager.cc b/chromium/components/update_client/ping_manager.cc
index d82b1696a7e..ab46b493457 100644
--- a/chromium/components/update_client/ping_manager.cc
+++ b/chromium/components/update_client/ping_manager.cc
@@ -23,6 +23,7 @@
#include "components/update_client/protocol_serializer.h"
#include "components/update_client/request_sender.h"
#include "components/update_client/utils.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
#include "url/gurl.h"
namespace update_client {
@@ -117,7 +118,8 @@ void PingSender::SendPing(const Component& component,
config_->GetProdId(), config_->GetBrowserVersion().GetString(),
config_->GetLang(), config_->GetChannel(),
config_->GetOSLongName(), config_->GetDownloadPreference(),
- config_->ExtraRequestParams(), nullptr, std::move(apps))),
+ config_->IsMachineExternallyManaged(),
+ config_->ExtraRequestParams(), {}, std::move(apps))),
false, base::BindOnce(&PingSender::SendPingComplete, this));
}
diff --git a/chromium/components/update_client/ping_manager_unittest.cc b/chromium/components/update_client/ping_manager_unittest.cc
index 8adb124f0fb..14ee2510cd6 100644
--- a/chromium/components/update_client/ping_manager_unittest.cc
+++ b/chromium/components/update_client/ping_manager_unittest.cc
@@ -6,6 +6,7 @@
#include <stdint.h>
+#include <initializer_list>
#include <limits>
#include <memory>
#include <string>
@@ -179,7 +180,7 @@ TEST_P(PingManagerTest, SendPing) {
request->FindPath({"os", "platform"})->GetString());
EXPECT_TRUE(request->FindPath({"os", "version"})->is_string());
- const auto& app = request->FindKey("app")->GetList()[0];
+ const auto& app = request->FindKey("app")->GetListDeprecated()[0];
EXPECT_EQ("abc", app.FindKey("appid")->GetString());
EXPECT_EQ("ap1", app.FindKey("ap")->GetString());
EXPECT_EQ("BRND", app.FindKey("brand")->GetString());
@@ -187,7 +188,7 @@ TEST_P(PingManagerTest, SendPing) {
EXPECT_EQ("c1", app.FindKey("cohort")->GetString());
EXPECT_EQ("cn1", app.FindKey("cohortname")->GetString());
EXPECT_EQ("ch1", app.FindKey("cohorthint")->GetString());
- const auto& event = app.FindKey("event")->GetList()[0];
+ const auto& event = app.FindKey("event")->GetListDeprecated()[0];
EXPECT_EQ(1, event.FindKey("eventresult")->GetInt());
EXPECT_EQ(3, event.FindKey("eventtype")->GetInt());
EXPECT_EQ("2.0", event.FindKey("nextversion")->GetString());
@@ -221,10 +222,10 @@ TEST_P(PingManagerTest, SendPing) {
const auto root = base::JSONReader::Read(msg);
ASSERT_TRUE(root);
const auto* request = root->FindKey("request");
- const auto& app = request->FindKey("app")->GetList()[0];
+ const auto& app = request->FindKey("app")->GetListDeprecated()[0];
EXPECT_EQ("abc", app.FindKey("appid")->GetString());
EXPECT_EQ("1.0", app.FindKey("version")->GetString());
- const auto& event = app.FindKey("event")->GetList()[0];
+ const auto& event = app.FindKey("event")->GetListDeprecated()[0];
EXPECT_EQ(0, event.FindKey("eventresult")->GetInt());
EXPECT_EQ(3, event.FindKey("eventtype")->GetInt());
EXPECT_EQ("2.0", event.FindKey("nextversion")->GetString());
@@ -261,10 +262,10 @@ TEST_P(PingManagerTest, SendPing) {
const auto root = base::JSONReader::Read(msg);
ASSERT_TRUE(root);
const auto* request = root->FindKey("request");
- const auto& app = request->FindKey("app")->GetList()[0];
+ const auto& app = request->FindKey("app")->GetListDeprecated()[0];
EXPECT_EQ("abc", app.FindKey("appid")->GetString());
EXPECT_EQ("1.0", app.FindKey("version")->GetString());
- const auto& event = app.FindKey("event")->GetList()[0];
+ const auto& event = app.FindKey("event")->GetListDeprecated()[0];
EXPECT_EQ(0, event.FindKey("eventresult")->GetInt());
EXPECT_EQ(3, event.FindKey("eventtype")->GetInt());
EXPECT_EQ("2.0", event.FindKey("nextversion")->GetString());
@@ -301,10 +302,10 @@ TEST_P(PingManagerTest, SendPing) {
const auto root = base::JSONReader::Read(msg);
ASSERT_TRUE(root);
const auto* request = root->FindKey("request");
- const auto& app = request->FindKey("app")->GetList()[0];
+ const auto& app = request->FindKey("app")->GetListDeprecated()[0];
EXPECT_EQ("abc", app.FindKey("appid")->GetString());
EXPECT_EQ("1.0", app.FindKey("version")->GetString());
- const auto& event = app.FindKey("event")->GetList()[0];
+ const auto& event = app.FindKey("event")->GetListDeprecated()[0];
EXPECT_EQ(0, event.FindKey("eventresult")->GetInt());
EXPECT_EQ(3, event.FindKey("eventtype")->GetInt());
EXPECT_EQ("1.0", event.FindKey("previousversion")->GetString());
@@ -329,10 +330,10 @@ TEST_P(PingManagerTest, SendPing) {
const auto root = base::JSONReader::Read(msg);
ASSERT_TRUE(root);
const auto* request = root->FindKey("request");
- const auto& app = request->FindKey("app")->GetList()[0];
+ const auto& app = request->FindKey("app")->GetListDeprecated()[0];
EXPECT_EQ("abc", app.FindKey("appid")->GetString());
EXPECT_EQ("1.2.3.4", app.FindKey("version")->GetString());
- const auto& event = app.FindKey("event")->GetList()[0];
+ const auto& event = app.FindKey("event")->GetListDeprecated()[0];
EXPECT_EQ(1, event.FindKey("eventresult")->GetInt());
EXPECT_EQ(4, event.FindKey("eventtype")->GetInt());
EXPECT_EQ("1.2.3.4", event.FindKey("previousversion")->GetString());
@@ -358,10 +359,10 @@ TEST_P(PingManagerTest, SendPing) {
const auto root = base::JSONReader::Read(msg);
ASSERT_TRUE(root);
const auto* request = root->FindKey("request");
- const auto& app = request->FindKey("app")->GetList()[0];
+ const auto& app = request->FindKey("app")->GetListDeprecated()[0];
EXPECT_EQ("abc", app.FindKey("appid")->GetString());
EXPECT_EQ("1.2.3.4", app.FindKey("version")->GetString());
- const auto& event = app.FindKey("event")->GetList()[0];
+ const auto& event = app.FindKey("event")->GetListDeprecated()[0];
EXPECT_EQ(1, event.FindKey("eventresult")->GetInt());
EXPECT_EQ(2, event.FindKey("eventtype")->GetInt());
EXPECT_EQ("1.2.3.4", event.FindKey("nextversion")->GetString());
@@ -414,19 +415,19 @@ TEST_P(PingManagerTest, SendPing) {
const auto root = base::JSONReader::Read(msg);
ASSERT_TRUE(root);
const auto* request = root->FindKey("request");
- const auto& app = request->FindKey("app")->GetList()[0];
+ const auto& app = request->FindKey("app")->GetListDeprecated()[0];
EXPECT_EQ("abc", app.FindKey("appid")->GetString());
EXPECT_EQ("1.0", app.FindKey("version")->GetString());
- EXPECT_EQ(4u, app.FindKey("event")->GetList().size());
+ EXPECT_EQ(4u, app.FindKey("event")->GetListDeprecated().size());
{
- const auto& event = app.FindKey("event")->GetList()[0];
+ const auto& event = app.FindKey("event")->GetListDeprecated()[0];
EXPECT_EQ(1, event.FindKey("eventresult")->GetInt());
EXPECT_EQ(3, event.FindKey("eventtype")->GetInt());
EXPECT_EQ("2.0", event.FindKey("nextversion")->GetString());
EXPECT_EQ("1.0", event.FindKey("previousversion")->GetString());
}
{
- const auto& event = app.FindKey("event")->GetList()[1];
+ const auto& event = app.FindKey("event")->GetListDeprecated()[1];
EXPECT_EQ(0, event.FindKey("eventresult")->GetInt());
EXPECT_EQ(14, event.FindKey("eventtype")->GetInt());
EXPECT_EQ(987, event.FindKey("download_time_ms")->GetDouble());
@@ -439,7 +440,7 @@ TEST_P(PingManagerTest, SendPing) {
EXPECT_EQ("http://host1/path1", event.FindKey("url")->GetString());
}
{
- const auto& event = app.FindKey("event")->GetList()[2];
+ const auto& event = app.FindKey("event")->GetListDeprecated()[2];
EXPECT_EQ(1, event.FindKey("eventresult")->GetInt());
EXPECT_EQ(14, event.FindKey("eventtype")->GetInt());
EXPECT_EQ(9870, event.FindKey("download_time_ms")->GetDouble());
@@ -451,7 +452,7 @@ TEST_P(PingManagerTest, SendPing) {
EXPECT_EQ("http://host2/path2", event.FindKey("url")->GetString());
}
{
- const auto& event = app.FindKey("event")->GetList()[3];
+ const auto& event = app.FindKey("event")->GetListDeprecated()[3];
EXPECT_EQ(1, event.FindKey("eventresult")->GetInt());
EXPECT_EQ(14, event.FindKey("eventtype")->GetInt());
EXPECT_EQ(9007199254740990,
@@ -465,6 +466,30 @@ TEST_P(PingManagerTest, SendPing) {
}
interceptor->Reset();
}
+
+ // Tests the presence of the `domain joined` in the ping request.
+ {
+ for (const auto is_managed : std::initializer_list<absl::optional<bool>>{
+ absl::nullopt, false, true}) {
+ config_->SetIsMachineExternallyManaged(is_managed);
+ EXPECT_TRUE(interceptor->ExpectRequest(std::make_unique<AnyMatch>()));
+ Component component(*update_context, "abc");
+ component.crx_component_ = CrxComponent();
+ component.previous_version_ = base::Version("1.0");
+ component.AppendEvent(component.MakeEventUpdateComplete());
+ ping_manager_->SendPing(component, *metadata_, MakePingCallback());
+
+ RunThreads();
+
+ ASSERT_EQ(interceptor->GetCount(), 1);
+ const auto root = base::JSONReader::Read(interceptor->GetRequestBody(0));
+ interceptor->Reset();
+
+ ASSERT_TRUE(root);
+ EXPECT_EQ(is_managed, root->FindBoolPath("request.domainjoined"));
+ }
+ }
+ config_->SetIsMachineExternallyManaged(absl::nullopt);
}
// Tests that sending the ping fails when the component requires encryption but
diff --git a/chromium/components/update_client/protocol_definition.cc b/chromium/components/update_client/protocol_definition.cc
index 2dd3cc6b0c8..e5b8da44ffe 100644
--- a/chromium/components/update_client/protocol_definition.cc
+++ b/chromium/components/update_client/protocol_definition.cc
@@ -12,6 +12,7 @@ namespace protocol_request {
OS::OS() = default;
OS::OS(OS&&) = default;
+OS& OS::operator=(OS&&) = default;
OS::~OS() = default;
Updater::Updater() = default;
@@ -27,10 +28,12 @@ Ping::~Ping() = default;
App::App() = default;
App::App(App&&) = default;
+App& App::operator=(App&&) = default;
App::~App() = default;
Request::Request() = default;
Request::Request(Request&&) = default;
+Request& Request::operator=(Request&&) = default;
Request::~Request() = default;
} // namespace protocol_request
diff --git a/chromium/components/update_client/protocol_definition.h b/chromium/components/update_client/protocol_definition.h
index 3fd1766c68a..d0e799ad102 100644
--- a/chromium/components/update_client/protocol_definition.h
+++ b/chromium/components/update_client/protocol_definition.h
@@ -41,12 +41,10 @@ struct HW {
struct OS {
OS();
-
OS(const OS&) = delete;
OS& operator=(const OS&) = delete;
-
OS(OS&&);
-
+ OS& operator=(OS&&);
~OS();
std::string platform;
@@ -98,12 +96,10 @@ struct Ping {
struct App {
App();
-
App(const App&) = delete;
App& operator=(const App&) = delete;
-
App(App&&);
-
+ App& operator=(App&&);
~App();
std::string app_id;
@@ -137,12 +133,10 @@ struct App {
struct Request {
Request();
-
Request(const Request&) = delete;
Request& operator=(const Request&) = delete;
-
Request(Request&&);
-
+ Request& operator=(Request&&);
~Request();
std::string protocol_version;
@@ -167,7 +161,7 @@ struct Request {
std::string arch;
std::string nacl_arch;
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
bool is_wow64 = false;
#endif
diff --git a/chromium/components/update_client/protocol_parser_json.cc b/chromium/components/update_client/protocol_parser_json.cc
index d4756ca3c49..028ca0f3a2e 100644
--- a/chromium/components/update_client/protocol_parser_json.cc
+++ b/chromium/components/update_client/protocol_parser_json.cc
@@ -66,7 +66,7 @@ bool ParseManifest(const base::Value& manifest_node,
return false;
}
- for (const auto& package : package_node->GetList()) {
+ for (const auto& package : package_node->GetListDeprecated()) {
if (!package.is_dict()) {
*error = "'package' is not a dictionary.";
return false;
@@ -113,7 +113,7 @@ void ParseActions(const base::Value& actions_node,
if (!action_node || !action_node->is_list())
return;
- const auto& action_list = action_node->GetList();
+ const auto& action_list = action_node->GetListDeprecated();
if (action_list.empty() || !action_list[0].is_dict())
return;
@@ -133,7 +133,7 @@ bool ParseUrls(const base::Value& urls_node,
return false;
}
- for (const auto& url : url_node->GetList()) {
+ for (const auto& url : url_node->GetListDeprecated()) {
if (!url.is_dict())
continue;
const auto* codebase = url.FindKey("codebase");
@@ -323,7 +323,7 @@ bool ProtocolParserJSON::DoParse(const std::string& response_json,
const auto* app_node = response_node->FindKey("app");
if (app_node && app_node->is_list()) {
- for (const auto& app : app_node->GetList()) {
+ for (const auto& app : app_node->GetListDeprecated()) {
Result result;
std::string error;
if (ParseApp(app, &result, &error))
diff --git a/chromium/components/update_client/protocol_serializer.cc b/chromium/components/update_client/protocol_serializer.cc
index aa2bdac4623..dc9bba9343b 100644
--- a/chromium/components/update_client/protocol_serializer.cc
+++ b/chromium/components/update_client/protocol_serializer.cc
@@ -23,10 +23,10 @@
#include "components/update_client/activity_data_service.h"
#include "components/update_client/persisted_data.h"
#include "components/update_client/update_query_params.h"
-#include "components/update_client/updater_state.h"
#include "components/update_client/utils.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include "base/win/windows_version.h"
#endif
@@ -42,7 +42,7 @@ int GetPhysicalMemoryGB() {
}
std::string GetOSVersion() {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
const auto ver = base::win::OSInfo::GetInstance()->version_number();
return base::StringPrintf("%u.%u.%u.%u", ver.major, ver.minor, ver.build,
ver.patch);
@@ -52,7 +52,7 @@ std::string GetOSVersion() {
}
std::string GetServicePack() {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
return base::win::OSInfo::GetInstance()->service_pack_str();
#else
return {};
@@ -105,8 +105,9 @@ protocol_request::Request MakeProtocolRequest(
const std::string& channel,
const std::string& os_long_name,
const std::string& download_preference,
+ absl::optional<bool> domain_joined,
const base::flat_map<std::string, std::string>& additional_attributes,
- const std::map<std::string, std::string>* updater_state_attributes,
+ const base::flat_map<std::string, std::string>& updater_state_attributes,
std::vector<protocol_request::App> apps) {
protocol_request::Request request;
request.protocol_version = kProtocolVersion;
@@ -129,19 +130,14 @@ protocol_request::Request MakeProtocolRequest(
request.arch = UpdateQueryParams::GetArch();
request.nacl_arch = UpdateQueryParams::GetNaclArch();
request.dlpref = download_preference;
+ request.domain_joined = domain_joined;
request.additional_attributes = additional_attributes;
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
if (base::win::OSInfo::GetInstance()->IsWowX86OnAMD64())
request.is_wow64 = true;
#endif
- if (updater_state_attributes &&
- updater_state_attributes->count(UpdaterState::kIsEnterpriseManaged)) {
- request.domain_joined =
- updater_state_attributes->at(UpdaterState::kIsEnterpriseManaged) == "1";
- }
-
// HW platform information.
base::CPU cpu;
request.hw.physmemory = GetPhysicalMemoryGB();
@@ -159,38 +155,38 @@ protocol_request::Request MakeProtocolRequest(
request.os.service_pack = GetServicePack();
request.os.arch = base::SysInfo().OperatingSystemArchitecture();
- if (updater_state_attributes) {
+ if (!updater_state_attributes.empty()) {
request.updater = absl::make_optional<protocol_request::Updater>();
- auto it = updater_state_attributes->find("name");
- if (it != updater_state_attributes->end())
+ auto it = updater_state_attributes.find("name");
+ if (it != updater_state_attributes.end())
request.updater->name = it->second;
- it = updater_state_attributes->find("version");
- if (it != updater_state_attributes->end())
+ it = updater_state_attributes.find("version");
+ if (it != updater_state_attributes.end())
request.updater->version = it->second;
- it = updater_state_attributes->find("ismachine");
- if (it != updater_state_attributes->end()) {
+ it = updater_state_attributes.find("ismachine");
+ if (it != updater_state_attributes.end()) {
DCHECK(it->second == "0" || it->second == "1");
request.updater->is_machine = it->second != "0";
}
- it = updater_state_attributes->find("autoupdatecheckenabled");
- if (it != updater_state_attributes->end()) {
+ it = updater_state_attributes.find("autoupdatecheckenabled");
+ if (it != updater_state_attributes.end()) {
DCHECK(it->second == "0" || it->second == "1");
request.updater->autoupdate_check_enabled = it->second != "0";
}
- it = updater_state_attributes->find("laststarted");
- if (it != updater_state_attributes->end()) {
+ it = updater_state_attributes.find("laststarted");
+ if (it != updater_state_attributes.end()) {
int last_started = 0;
if (base::StringToInt(it->second, &last_started))
request.updater->last_started = last_started;
}
- it = updater_state_attributes->find("lastchecked");
- if (it != updater_state_attributes->end()) {
+ it = updater_state_attributes.find("lastchecked");
+ if (it != updater_state_attributes.end()) {
int last_checked = 0;
if (base::StringToInt(it->second, &last_checked))
request.updater->last_checked = last_checked;
}
- it = updater_state_attributes->find("updatepolicy");
- if (it != updater_state_attributes->end()) {
+ it = updater_state_attributes.find("updatepolicy");
+ if (it != updater_state_attributes.end()) {
int update_policy = 0;
if (base::StringToInt(it->second, &update_policy))
request.updater->update_policy = update_policy;
diff --git a/chromium/components/update_client/protocol_serializer.h b/chromium/components/update_client/protocol_serializer.h
index 8e583adcbc7..89f87667016 100644
--- a/chromium/components/update_client/protocol_serializer.h
+++ b/chromium/components/update_client/protocol_serializer.h
@@ -42,8 +42,9 @@ protocol_request::Request MakeProtocolRequest(
const std::string& channel,
const std::string& os_long_name,
const std::string& download_preference,
+ absl::optional<bool> domain_joined,
const base::flat_map<std::string, std::string>& additional_attributes,
- const std::map<std::string, std::string>* updater_state_attributes,
+ const base::flat_map<std::string, std::string>& updater_state_attributes,
std::vector<protocol_request::App> apps);
protocol_request::App MakeProtocolApp(
diff --git a/chromium/components/update_client/protocol_serializer_fuzzer.cc b/chromium/components/update_client/protocol_serializer_fuzzer.cc
index 232e719a1ca..bfca2b6ec98 100644
--- a/chromium/components/update_client/protocol_serializer_fuzzer.cc
+++ b/chromium/components/update_client/protocol_serializer_fuzzer.cc
@@ -5,13 +5,21 @@
#include <stddef.h>
#include <stdint.h>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
#include <fuzzer/FuzzedDataProvider.h>
+#include "base/check.h"
#include "base/command_line.h"
+#include "base/containers/flat_map.h"
#include "base/json/json_reader.h"
#include "base/strings/string_util.h"
#include "components/update_client/protocol_handler.h"
#include "components/update_client/protocol_serializer.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
struct Environment {
Environment() { CHECK(base::CommandLine::Init(0, nullptr)); }
@@ -23,7 +31,6 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
// Independently, try serializing a Request.
base::flat_map<std::string, std::string> additional_attributes;
- std::map<std::string, std::string> updater_state_attributes;
std::vector<protocol_request::App> apps;
// Share |data| between |MakeProtocolRequest| args
@@ -39,8 +46,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
GetUtf8String() /* prod_id */, GetUtf8String() /* browser_version */,
GetUtf8String() /* lang */, GetUtf8String() /* channel */,
GetUtf8String() /* os_long_name */,
- GetUtf8String() /* download_preference */, additional_attributes,
- &updater_state_attributes, std::move(apps));
+ GetUtf8String() /* download_preference */,
+ absl::nullopt /* domain_joined */, additional_attributes,
+ {} /*updater_state_attributes*/, std::move(apps));
update_client::ProtocolHandlerFactoryJSON factory;
std::unique_ptr<ProtocolSerializer> serializer = factory.CreateSerializer();
diff --git a/chromium/components/update_client/protocol_serializer_json.cc b/chromium/components/update_client/protocol_serializer_json.cc
index 06a7e43cb17..38a6a8de7d5 100644
--- a/chromium/components/update_client/protocol_serializer_json.cc
+++ b/chromium/components/update_client/protocol_serializer_json.cc
@@ -12,7 +12,6 @@
#include "base/values.h"
#include "build/branding_buildflags.h"
#include "build/build_config.h"
-#include "components/update_client/updater_state.h"
namespace update_client {
@@ -40,10 +39,10 @@ std::string ProtocolSerializerJSON::Serialize(
request_node->SetKey("@os", Value(request.operating_system));
request_node->SetKey("arch", Value(request.arch));
request_node->SetKey("nacl_arch", Value(request.nacl_arch));
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
if (request.is_wow64)
request_node->SetKey("wow64", Value(request.is_wow64));
-#endif // OS_WIN
+#endif // BUILDFLAG(IS_WIN)
if (!request.updaterchannel.empty())
request_node->SetKey("updaterchannel", Value(request.updaterchannel));
if (!request.prodchannel.empty())
@@ -51,8 +50,7 @@ std::string ProtocolSerializerJSON::Serialize(
if (!request.dlpref.empty())
request_node->SetKey("dlpref", Value(request.dlpref));
if (request.domain_joined) {
- request_node->SetKey(UpdaterState::kIsEnterpriseManaged,
- Value(*request.domain_joined));
+ request_node->SetKey("domainjoined", Value(*request.domain_joined));
}
// HW platform information.
diff --git a/chromium/components/update_client/protocol_serializer_json_unittest.cc b/chromium/components/update_client/protocol_serializer_json_unittest.cc
index 1d6691c505f..1f5747799ff 100644
--- a/chromium/components/update_client/protocol_serializer_json_unittest.cc
+++ b/chromium/components/update_client/protocol_serializer_json_unittest.cc
@@ -18,7 +18,6 @@
#include "components/update_client/protocol_definition.h"
#include "components/update_client/protocol_serializer.h"
#include "components/update_client/test_activity_data_service.h"
-#include "components/update_client/updater_state.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/re2/src/re2/re2.h"
@@ -58,8 +57,8 @@ TEST(SerializeRequestJSON, Serialize) {
const auto request = std::make_unique<ProtocolSerializerJSON>()->Serialize(
MakeProtocolRequest(false, "{15160585-8ADE-4D3C-839B-1281A6035D1F}",
"prod_id", "1.0", "lang", "channel", "OS",
- "cacheable", {{"extra", "params"}}, nullptr,
- std::move(apps)));
+ "cacheable", absl::nullopt, {{"extra", "params"}},
+ {}, std::move(apps)));
constexpr char regex[] =
R"({"request":{"@os":"\w+","@updater":"prod_id",)"
R"("acceptformat":"crx3",)"
@@ -97,7 +96,8 @@ TEST(SerializeRequestJSON, Serialize) {
const auto request = std::make_unique<ProtocolSerializerJSON>()->Serialize(
MakeProtocolRequest(false, "{15160585-8ADE-4D3C-839B-1281A6035D1F}", "",
- "", "", "", "", "", {}, nullptr, std::move(apps)));
+ "", "", "", "", "", absl::nullopt, {}, {},
+ std::move(apps)));
constexpr char regex[] =
R"("app":\[{"appid":"id1","enabled":true,)"
@@ -113,13 +113,13 @@ TEST(SerializeRequestJSON, DownloadPreference) {
const auto serializer = std::make_unique<ProtocolSerializerJSON>();
auto request = serializer->Serialize(
MakeProtocolRequest(false, "{15160585-8ADE-4D3C-839B-1281A6035D1F}", "",
- "", "", "", "", "", {}, nullptr, {}));
+ "", "", "", "", "", absl::nullopt, {}, {}, {}));
EXPECT_FALSE(RE2::PartialMatch(request, R"("dlpref":)")) << request;
// Verifies that |download_preference| is serialized.
- request = serializer->Serialize(
- MakeProtocolRequest(false, "{15160585-8ADE-4D3C-839B-1281A6035D1F}", "",
- "", "", "", "", "cacheable", {}, nullptr, {}));
+ request = serializer->Serialize(MakeProtocolRequest(
+ false, "{15160585-8ADE-4D3C-839B-1281A6035D1F}", "", "", "", "", "",
+ "cacheable", absl::nullopt, {}, {}, {}));
EXPECT_TRUE(RE2::PartialMatch(request, R"("dlpref":"cacheable")")) << request;
}
@@ -128,18 +128,18 @@ TEST(SerializeRequestJSON, DownloadPreference) {
TEST(SerializeRequestJSON, UpdaterStateAttributes) {
base::test::TaskEnvironment env;
const auto serializer = std::make_unique<ProtocolSerializerJSON>();
- UpdaterState::Attributes attributes;
- attributes["ismachine"] = "1";
- attributes["domainjoined"] = "1";
- attributes["name"] = "Omaha";
- attributes["version"] = "1.2.3.4";
- attributes["laststarted"] = "1";
- attributes["lastchecked"] = "2";
- attributes["autoupdatecheckenabled"] = "0";
- attributes["updatepolicy"] = "-1";
+
const auto request = serializer->Serialize(MakeProtocolRequest(
true, "{15160585-8ADE-4D3C-839B-1281A6035D1F}", "prod_id", "1.0", "lang",
- "channel", "OS", "cacheable", {{"extra", "params"}}, &attributes, {}));
+ "channel", "OS", "cacheable", true, {{"extra", "params"}},
+ {{"ismachine", "1"},
+ {"name", "Omaha"},
+ {"version", "1.2.3.4"},
+ {"laststarted", "1"},
+ {"lastchecked", "2"},
+ {"autoupdatecheckenabled", "0"},
+ {"updatepolicy", "-1"}},
+ {}));
constexpr char regex[] =
R"({"request":{"@os":"\w+","@updater":"prod_id",)"
R"("acceptformat":"crx3","arch":"\w+","dedup":"cr",)"
@@ -162,4 +162,24 @@ TEST(SerializeRequestJSON, UpdaterStateAttributes) {
EXPECT_TRUE(RE2::FullMatch(request, regex)) << request << "\n VS \n" << regex;
}
+TEST(SerializeRequestJSON, DomainJoined) {
+ base::test::TaskEnvironment env;
+
+ const auto serializer = std::make_unique<ProtocolSerializerJSON>();
+ std::string request = serializer->Serialize(
+ MakeProtocolRequest(false, "{15160585-8ADE-4D3C-839B-1281A6035D1F}", "",
+ "", "", "", "", "", absl::nullopt, {}, {}, {}));
+ EXPECT_FALSE(RE2::PartialMatch(request, R"("domainjoined")")) << request;
+
+ request = serializer->Serialize(
+ MakeProtocolRequest(false, "{15160585-8ADE-4D3C-839B-1281A6035D1F}", "",
+ "", "", "", "", "", true, {}, {}, {}));
+ EXPECT_TRUE(RE2::PartialMatch(request, R"("domainjoined":true)")) << request;
+
+ request = serializer->Serialize(
+ MakeProtocolRequest(false, "{15160585-8ADE-4D3C-839B-1281A6035D1F}", "",
+ "", "", "", "", "", false, {}, {}, {}));
+ EXPECT_TRUE(RE2::PartialMatch(request, R"("domainjoined":false)")) << request;
+}
+
} // namespace update_client
diff --git a/chromium/components/update_client/test_configurator.cc b/chromium/components/update_client/test_configurator.cc
index 7c7ee09f540..dfddc4cd73e 100644
--- a/chromium/components/update_client/test_configurator.cc
+++ b/chromium/components/update_client/test_configurator.cc
@@ -4,8 +4,11 @@
#include "components/update_client/test_configurator.h"
+#include <string>
#include <utility>
+#include "base/bind.h"
+#include "base/containers/flat_map.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/version.h"
#include "components/prefs/pref_service.h"
@@ -20,6 +23,7 @@
#include "components/update_client/unzip/unzip_impl.h"
#include "components/update_client/unzipper.h"
#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
#include "url/gurl.h"
namespace update_client {
@@ -48,7 +52,9 @@ TestConfigurator::TestConfigurator(PrefService* pref_service)
network_fetcher_factory_(
base::MakeRefCounted<NetworkFetcherChromiumFactory>(
test_shared_loader_factory_,
- base::BindRepeating([](const GURL& url) { return false; }))) {}
+ base::BindRepeating([](const GURL& url) { return false; }))),
+ updater_state_provider_(base::BindRepeating(
+ [](bool /*is_machine*/) { return UpdaterStateAttributes(); })) {}
TestConfigurator::~TestConfigurator() = default;
@@ -142,6 +148,31 @@ bool TestConfigurator::EnabledCupSigning() const {
return enabled_cup_signing_;
}
+PrefService* TestConfigurator::GetPrefService() const {
+ return pref_service_;
+}
+
+ActivityDataService* TestConfigurator::GetActivityDataService() const {
+ return nullptr;
+}
+
+bool TestConfigurator::IsPerUserInstall() const {
+ return true;
+}
+
+std::unique_ptr<ProtocolHandlerFactory>
+TestConfigurator::GetProtocolHandlerFactory() const {
+ return std::make_unique<ProtocolHandlerFactoryJSON>();
+}
+
+absl::optional<bool> TestConfigurator::IsMachineExternallyManaged() const {
+ return is_machine_externally_managed_;
+}
+
+UpdaterStateProvider TestConfigurator::GetUpdaterStateProvider() const {
+ return updater_state_provider_;
+}
+
void TestConfigurator::SetOnDemandTime(int seconds) {
ondemand_time_ = seconds;
}
@@ -172,21 +203,14 @@ void TestConfigurator::SetCrxDownloaderFactory(
crx_downloader_factory_ = crx_downloader_factory;
}
-PrefService* TestConfigurator::GetPrefService() const {
- return pref_service_;
+void TestConfigurator::SetIsMachineExternallyManaged(
+ absl::optional<bool> is_machine_externally_managed) {
+ is_machine_externally_managed_ = is_machine_externally_managed;
}
-ActivityDataService* TestConfigurator::GetActivityDataService() const {
- return nullptr;
-}
-
-bool TestConfigurator::IsPerUserInstall() const {
- return true;
-}
-
-std::unique_ptr<ProtocolHandlerFactory>
-TestConfigurator::GetProtocolHandlerFactory() const {
- return std::make_unique<ProtocolHandlerFactoryJSON>();
+void TestConfigurator::SetUpdaterStateProvider(
+ UpdaterStateProvider update_state_provider) {
+ updater_state_provider_ = update_state_provider;
}
} // namespace update_client
diff --git a/chromium/components/update_client/test_configurator.h b/chromium/components/update_client/test_configurator.h
index 7f4b1b0fd29..d19fa702256 100644
--- a/chromium/components/update_client/test_configurator.h
+++ b/chromium/components/update_client/test_configurator.h
@@ -17,6 +17,7 @@
#include "base/memory/ref_counted.h"
#include "components/update_client/configurator.h"
#include "services/network/test/test_url_loader_factory.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
#include "url/gurl.h"
class PrefService;
@@ -100,6 +101,8 @@ class TestConfigurator : public Configurator {
bool IsPerUserInstall() const override;
std::unique_ptr<ProtocolHandlerFactory> GetProtocolHandlerFactory()
const override;
+ absl::optional<bool> IsMachineExternallyManaged() const override;
+ UpdaterStateProvider GetUpdaterStateProvider() const override;
void SetOnDemandTime(int seconds);
void SetInitialDelay(double seconds);
@@ -109,7 +112,9 @@ class TestConfigurator : public Configurator {
void SetPingUrl(const GURL& url);
void SetCrxDownloaderFactory(
scoped_refptr<CrxDownloaderFactory> crx_downloader_factory);
-
+ void SetIsMachineExternallyManaged(
+ absl::optional<bool> is_machine_externally_managed);
+ void SetUpdaterStateProvider(UpdaterStateProvider update_state_provider);
network::TestURLLoaderFactory* test_url_loader_factory() {
return &test_url_loader_factory_;
}
@@ -135,6 +140,9 @@ class TestConfigurator : public Configurator {
network::TestURLLoaderFactory test_url_loader_factory_;
scoped_refptr<NetworkFetcherFactory> network_fetcher_factory_;
scoped_refptr<CrxDownloaderFactory> crx_downloader_factory_;
+ UpdaterStateProvider updater_state_provider_;
+
+ absl::optional<bool> is_machine_externally_managed_;
};
} // namespace update_client
diff --git a/chromium/components/update_client/update_checker.cc b/chromium/components/update_client/update_checker.cc
index a7e6e5e9b96..6cd9f5c7722 100644
--- a/chromium/components/update_client/update_checker.cc
+++ b/chromium/components/update_client/update_checker.cc
@@ -15,6 +15,7 @@
#include "base/bind.h"
#include "base/callback.h"
+#include "base/containers/flat_map.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/memory/raw_ptr.h"
@@ -32,7 +33,6 @@
#include "components/update_client/request_sender.h"
#include "components/update_client/task_traits.h"
#include "components/update_client/update_client.h"
-#include "components/update_client/updater_state.h"
#include "components/update_client/utils.h"
#include "url/gurl.h"
@@ -70,11 +70,12 @@ class UpdateCheckerImpl : public UpdateChecker {
UpdateCheckCallback update_check_callback) override;
private:
- void ReadUpdaterStateAttributes();
+ UpdaterStateAttributes ReadUpdaterStateAttributes() const;
void CheckForUpdatesHelper(
const std::string& session_id,
const IdToComponentPtrMap& components,
const base::flat_map<std::string, std::string>& additional_attributes,
+ const UpdaterStateAttributes& updater_state_attributes,
const std::set<std::string>& active_ids);
void OnRequestSenderComplete(int error,
const std::string& response,
@@ -91,7 +92,6 @@ class UpdateCheckerImpl : public UpdateChecker {
raw_ptr<PersistedData> metadata_ = nullptr;
std::vector<std::string> ids_checked_;
UpdateCheckCallback update_check_callback_;
- std::unique_ptr<UpdaterState::Attributes> updater_state_attributes_;
std::unique_ptr<RequestSender> request_sender_;
};
@@ -114,40 +114,45 @@ void UpdateCheckerImpl::CheckForUpdates(
ids_checked_ = ids_checked;
update_check_callback_ = std::move(update_check_callback);
- base::ThreadPool::PostTaskAndReply(
+ auto check_for_updates_invoker = base::BindOnce(
+ &UpdateCheckerImpl::CheckForUpdatesHelper, base::Unretained(this),
+ session_id, std::cref(components), additional_attributes);
+
+ base::ThreadPool::PostTaskAndReplyWithResult(
FROM_HERE, kTaskTraits,
base::BindOnce(&UpdateCheckerImpl::ReadUpdaterStateAttributes,
base::Unretained(this)),
base::BindOnce(
- [](base::OnceCallback<void(const std::set<std::string>&)>
- checkForUpdatesHelper,
- PersistedData* metadata, std::vector<std::string> ids) {
- metadata->GetActiveBits(ids, std::move(checkForUpdatesHelper));
+ [](base::OnceCallback<void(const UpdaterStateAttributes&,
+ const std::set<std::string>&)>
+ check_for_updates_invoker,
+ PersistedData* metadata, std::vector<std::string> ids,
+ const UpdaterStateAttributes& updater_state_attributes) {
+ metadata->GetActiveBits(
+ ids, base::BindOnce(std::move(check_for_updates_invoker),
+ updater_state_attributes));
},
- base::BindOnce(&UpdateCheckerImpl::CheckForUpdatesHelper,
- base::Unretained(this), session_id,
- std::cref(components), additional_attributes),
- base::Unretained(metadata_), ids_checked));
+ std::move(check_for_updates_invoker), base::Unretained(metadata_),
+ ids_checked));
}
// This function runs on the blocking pool task runner.
-void UpdateCheckerImpl::ReadUpdaterStateAttributes() {
-#if defined(OS_WIN)
+UpdaterStateAttributes UpdateCheckerImpl::ReadUpdaterStateAttributes() const {
+#if BUILDFLAG(IS_WIN)
// On Windows, the Chrome and the updater install modes are matched by design.
- updater_state_attributes_ =
- UpdaterState::GetState(!config_->IsPerUserInstall());
-#elif defined(OS_MAC)
- // MacOS ignores this value in the current implementation but this may change.
- updater_state_attributes_ = UpdaterState::GetState(false);
+ return config_->GetUpdaterStateProvider().Run(!config_->IsPerUserInstall());
+#elif BUILDFLAG(IS_MAC)
+ return config_->GetUpdaterStateProvider().Run(false);
#else
-// Other platforms don't have updaters.
-#endif // OS_WIN
+ return {};
+#endif // BUILDFLAG(IS_WIN)
}
void UpdateCheckerImpl::CheckForUpdatesHelper(
const std::string& session_id,
const IdToComponentPtrMap& components,
const base::flat_map<std::string, std::string>& additional_attributes,
+ const UpdaterStateAttributes& updater_state_attributes,
const std::set<std::string>& active_ids) {
DCHECK(thread_checker_.CalledOnValidThread());
@@ -200,8 +205,8 @@ void UpdateCheckerImpl::CheckForUpdatesHelper(
!config_->IsPerUserInstall(), session_id, config_->GetProdId(),
config_->GetBrowserVersion().GetString(), config_->GetLang(),
config_->GetChannel(), config_->GetOSLongName(),
- config_->GetDownloadPreference(), additional_attributes,
- updater_state_attributes_.get(), std::move(apps));
+ config_->GetDownloadPreference(), config_->IsMachineExternallyManaged(),
+ additional_attributes, updater_state_attributes, std::move(apps));
request_sender_ = std::make_unique<RequestSender>(config_);
request_sender_->Send(
diff --git a/chromium/components/update_client/update_checker_unittest.cc b/chromium/components/update_client/update_checker_unittest.cc
index a52d1eb6dea..8e7d4bb8005 100644
--- a/chromium/components/update_client/update_checker_unittest.cc
+++ b/chromium/components/update_client/update_checker_unittest.cc
@@ -4,8 +4,10 @@
#include "components/update_client/update_checker.h"
+#include <initializer_list>
#include <map>
#include <memory>
+#include <string>
#include <tuple>
#include <utility>
#include <vector>
@@ -210,6 +212,14 @@ TEST_P(UpdateCheckerTest, UpdateCheckSuccess) {
std::make_unique<PartialMatch>("updatecheck"),
test_file("updatecheck_reply_1.json")));
+ config_->SetIsMachineExternallyManaged(true);
+ config_->SetUpdaterStateProvider(base::BindRepeating([](bool /*is_machine*/) {
+ return UpdaterStateAttributes{{"name", "Omaha"},
+ {"ismachine", "1"},
+ {"autoupdatecheckenabled", "1"},
+ {"updatepolicy", "1"}};
+ }));
+
update_checker_ = UpdateChecker::Create(config_, metadata_.get());
IdToComponentPtrMap components;
@@ -255,6 +265,7 @@ TEST_P(UpdateCheckerTest, UpdateCheckSuccess) {
EXPECT_EQ("fake_channel_string",
request->FindKey("updaterchannel")->GetString());
EXPECT_EQ("30.0", request->FindKey("updaterversion")->GetString());
+ EXPECT_TRUE(request->FindKey("domainjoined")->GetBool());
// No "dlpref" is sent by default.
EXPECT_FALSE(request->FindKey("dlpref"));
@@ -264,7 +275,7 @@ TEST_P(UpdateCheckerTest, UpdateCheckSuccess) {
request->FindPath({"os", "platform"})->GetString());
EXPECT_TRUE(request->FindPath({"os", "version"})->is_string());
- const auto& app = request->FindKey("app")->GetList()[0];
+ const auto& app = request->FindKey("app")->GetListDeprecated()[0];
EXPECT_EQ(kUpdateItemId, app.FindKey("appid")->GetString());
EXPECT_EQ("0.9", app.FindKey("version")->GetString());
EXPECT_EQ("TEST", app.FindKey("brand")->GetString());
@@ -276,12 +287,10 @@ TEST_P(UpdateCheckerTest, UpdateCheckSuccess) {
EXPECT_TRUE(app.FindKey("ping"));
EXPECT_EQ(-2, app.FindPath({"ping", "r"})->GetInt());
EXPECT_EQ("fp1", app.FindPath({"packages", "package"})
- ->GetList()[0]
+ ->GetListDeprecated()[0]
.FindKey("fp")
->GetString());
-
-#if defined(OS_WIN)
- EXPECT_TRUE(request->FindKey("domainjoined"));
+#if BUILDFLAG(IS_WIN)
#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
const auto* updater = request->FindKey("updater");
EXPECT_TRUE(updater);
@@ -290,7 +299,7 @@ TEST_P(UpdateCheckerTest, UpdateCheckSuccess) {
EXPECT_TRUE(updater->FindKey("ismachine")->is_bool());
EXPECT_TRUE(updater->FindKey("updatepolicy")->is_int());
#endif // BUILDFLAG(GOOGLE_CHROME_BRANDING)
-#endif // OS_WIN
+#endif // IS_WIN
// Sanity check the arguments of the callback after parsing.
EXPECT_EQ(ErrorCategory::kNone, error_category_);
@@ -346,7 +355,8 @@ TEST_P(UpdateCheckerTest, UpdateCheckInvalidAp) {
const auto request = post_interceptor_->GetRequestBody(0);
const auto root = base::JSONReader::Read(request);
ASSERT_TRUE(root);
- const auto& app = root->FindKey("request")->FindKey("app")->GetList()[0];
+ const auto& app =
+ root->FindKey("request")->FindKey("app")->GetListDeprecated()[0];
EXPECT_EQ(kUpdateItemId, app.FindKey("appid")->GetString());
EXPECT_EQ("0.9", app.FindKey("version")->GetString());
EXPECT_EQ("TEST", app.FindKey("brand")->GetString());
@@ -358,7 +368,7 @@ TEST_P(UpdateCheckerTest, UpdateCheckInvalidAp) {
EXPECT_TRUE(app.FindKey("ping"));
EXPECT_EQ(-2, app.FindPath({"ping", "r"})->GetInt());
EXPECT_EQ("fp1", app.FindPath({"packages", "package"})
- ->GetList()[0]
+ ->GetListDeprecated()[0]
.FindKey("fp")
->GetString());
}
@@ -384,7 +394,8 @@ TEST_P(UpdateCheckerTest, UpdateCheckSuccessNoBrand) {
const auto root = base::JSONReader::Read(request);
ASSERT_TRUE(root);
- const auto& app = root->FindKey("request")->FindKey("app")->GetList()[0];
+ const auto& app =
+ root->FindKey("request")->FindKey("app")->GetListDeprecated()[0];
EXPECT_EQ(kUpdateItemId, app.FindKey("appid")->GetString());
EXPECT_EQ("0.9", app.FindKey("version")->GetString());
EXPECT_FALSE(app.FindKey("brand"));
@@ -395,7 +406,7 @@ TEST_P(UpdateCheckerTest, UpdateCheckSuccessNoBrand) {
EXPECT_TRUE(app.FindKey("ping"));
EXPECT_EQ(-2, app.FindPath({"ping", "r"})->GetInt());
EXPECT_EQ("fp1", app.FindPath({"packages", "package"})
- ->GetList()[0]
+ ->GetListDeprecated()[0]
.FindKey("fp")
->GetString());
}
@@ -483,7 +494,8 @@ TEST_P(UpdateCheckerTest, UpdateCheckCupError) {
const auto& request = post_interceptor_->GetRequestBody(0);
const auto root = base::JSONReader::Read(request);
ASSERT_TRUE(root);
- const auto& app = root->FindKey("request")->FindKey("app")->GetList()[0];
+ const auto& app =
+ root->FindKey("request")->FindKey("app")->GetListDeprecated()[0];
EXPECT_EQ(kUpdateItemId, app.FindKey("appid")->GetString());
EXPECT_EQ("0.9", app.FindKey("version")->GetString());
EXPECT_EQ("TEST", app.FindKey("brand")->GetString());
@@ -494,7 +506,7 @@ TEST_P(UpdateCheckerTest, UpdateCheckCupError) {
EXPECT_TRUE(app.FindKey("ping"));
EXPECT_EQ(-2, app.FindPath({"ping", "r"})->GetInt());
EXPECT_EQ("fp1", app.FindPath({"packages", "package"})
- ->GetList()[0]
+ ->GetListDeprecated()[0]
.FindKey("fp")
->GetString());
@@ -567,12 +579,14 @@ TEST_P(UpdateCheckerTest, UpdateCheckLastRollCall) {
const auto root1 =
base::JSONReader::Read(post_interceptor_->GetRequestBody(0));
ASSERT_TRUE(root1);
- const auto& app1 = root1->FindKey("request")->FindKey("app")->GetList()[0];
+ const auto& app1 =
+ root1->FindKey("request")->FindKey("app")->GetListDeprecated()[0];
EXPECT_EQ(5, app1.FindPath({"ping", "r"})->GetInt());
const auto root2 =
base::JSONReader::Read(post_interceptor_->GetRequestBody(1));
ASSERT_TRUE(root2);
- const auto& app2 = root2->FindKey("request")->FindKey("app")->GetList()[0];
+ const auto& app2 =
+ root2->FindKey("request")->FindKey("app")->GetListDeprecated()[0];
EXPECT_EQ(3383, app2.FindPath({"ping", "rd"})->GetInt());
EXPECT_TRUE(app2.FindPath({"ping", "ping_freshness"})->is_string());
}
@@ -634,7 +648,8 @@ TEST_P(UpdateCheckerTest, UpdateCheckLastActive) {
const auto root =
base::JSONReader::Read(post_interceptor_->GetRequestBody(0));
ASSERT_TRUE(root);
- const auto& app = root->FindKey("request")->FindKey("app")->GetList()[0];
+ const auto& app =
+ root->FindKey("request")->FindKey("app")->GetListDeprecated()[0];
EXPECT_EQ(10, app.FindPath({"ping", "a"})->GetInt());
EXPECT_EQ(-2, app.FindPath({"ping", "r"})->GetInt());
}
@@ -642,7 +657,8 @@ TEST_P(UpdateCheckerTest, UpdateCheckLastActive) {
const auto root =
base::JSONReader::Read(post_interceptor_->GetRequestBody(1));
ASSERT_TRUE(root);
- const auto& app = root->FindKey("request")->FindKey("app")->GetList()[0];
+ const auto& app =
+ root->FindKey("request")->FindKey("app")->GetListDeprecated()[0];
EXPECT_EQ(3383, app.FindPath({"ping", "ad"})->GetInt());
EXPECT_EQ(3383, app.FindPath({"ping", "rd"})->GetInt());
EXPECT_TRUE(app.FindPath({"ping", "ping_freshness"})->is_string());
@@ -651,7 +667,8 @@ TEST_P(UpdateCheckerTest, UpdateCheckLastActive) {
const auto root =
base::JSONReader::Read(post_interceptor_->GetRequestBody(2));
ASSERT_TRUE(root);
- const auto& app = root->FindKey("request")->FindKey("app")->GetList()[0];
+ const auto& app =
+ root->FindKey("request")->FindKey("app")->GetListDeprecated()[0];
EXPECT_EQ(3383, app.FindPath({"ping", "rd"})->GetInt());
EXPECT_TRUE(app.FindPath({"ping", "ping_freshness"})->is_string());
}
@@ -682,7 +699,7 @@ TEST_P(UpdateCheckerTest, UpdateCheckInstallSource) {
const auto root = base::JSONReader::Read(request);
ASSERT_TRUE(root);
const auto& app =
- root->FindKey("request")->FindKey("app")->GetList()[0];
+ root->FindKey("request")->FindKey("app")->GetListDeprecated()[0];
EXPECT_EQ("ondemand", app.FindKey("installsource")->GetString());
EXPECT_FALSE(app.FindKey("installedby"));
}
@@ -704,7 +721,7 @@ TEST_P(UpdateCheckerTest, UpdateCheckInstallSource) {
const auto root = base::JSONReader::Read(request);
ASSERT_TRUE(root);
const auto& app =
- root->FindKey("request")->FindKey("app")->GetList()[0];
+ root->FindKey("request")->FindKey("app")->GetListDeprecated()[0];
EXPECT_EQ("sideload", app.FindKey("installsource")->GetString());
EXPECT_EQ("policy", app.FindKey("installedby")->GetString());
}
@@ -726,7 +743,8 @@ TEST_P(UpdateCheckerTest, UpdateCheckInstallSource) {
const auto& request = post_interceptor->GetRequestBody(0);
const auto root = base::JSONReader::Read(request);
ASSERT_TRUE(root);
- const auto& app = root->FindKey("request")->FindKey("app")->GetList()[0];
+ const auto& app =
+ root->FindKey("request")->FindKey("app")->GetListDeprecated()[0];
EXPECT_FALSE(app.FindKey("installsource"));
}
{
@@ -746,7 +764,8 @@ TEST_P(UpdateCheckerTest, UpdateCheckInstallSource) {
const auto& request = post_interceptor->GetRequestBody(0);
const auto root = base::JSONReader::Read(request);
ASSERT_TRUE(root);
- const auto& app = root->FindKey("request")->FindKey("app")->GetList()[0];
+ const auto& app =
+ root->FindKey("request")->FindKey("app")->GetListDeprecated()[0];
EXPECT_EQ("webstore", app.FindKey("installsource")->GetString());
EXPECT_EQ("external", app.FindKey("installedby")->GetString());
}
@@ -775,7 +794,8 @@ TEST_P(UpdateCheckerTest, ComponentDisabled) {
const auto& request = post_interceptor->GetRequestBody(0);
const auto root = base::JSONReader::Read(request);
ASSERT_TRUE(root);
- const auto& app = root->FindKey("request")->FindKey("app")->GetList()[0];
+ const auto& app =
+ root->FindKey("request")->FindKey("app")->GetListDeprecated()[0];
EXPECT_EQ(true, app.FindKey("enabled")->GetBool());
EXPECT_FALSE(app.FindKey("disabled"));
}
@@ -796,7 +816,8 @@ TEST_P(UpdateCheckerTest, ComponentDisabled) {
const auto& request = post_interceptor->GetRequestBody(0);
const auto root = base::JSONReader::Read(request);
ASSERT_TRUE(root);
- const auto& app = root->FindKey("request")->FindKey("app")->GetList()[0];
+ const auto& app =
+ root->FindKey("request")->FindKey("app")->GetListDeprecated()[0];
EXPECT_EQ(true, app.FindKey("enabled")->GetBool());
EXPECT_FALSE(app.FindKey("disabled"));
}
@@ -817,9 +838,10 @@ TEST_P(UpdateCheckerTest, ComponentDisabled) {
const auto& request = post_interceptor->GetRequestBody(0);
const auto root = base::JSONReader::Read(request);
ASSERT_TRUE(root);
- const auto& app = root->FindKey("request")->FindKey("app")->GetList()[0];
+ const auto& app =
+ root->FindKey("request")->FindKey("app")->GetListDeprecated()[0];
EXPECT_EQ(false, app.FindKey("enabled")->GetBool());
- const auto& disabled = app.FindKey("disabled")->GetList();
+ const auto& disabled = app.FindKey("disabled")->GetListDeprecated();
EXPECT_EQ(1u, disabled.size());
EXPECT_EQ(0, disabled[0].FindKey("reason")->GetInt());
}
@@ -839,9 +861,10 @@ TEST_P(UpdateCheckerTest, ComponentDisabled) {
const auto& request = post_interceptor->GetRequestBody(0);
const auto root = base::JSONReader::Read(request);
ASSERT_TRUE(root);
- const auto& app = root->FindKey("request")->FindKey("app")->GetList()[0];
+ const auto& app =
+ root->FindKey("request")->FindKey("app")->GetListDeprecated()[0];
EXPECT_EQ(false, app.FindKey("enabled")->GetBool());
- const auto& disabled = app.FindKey("disabled")->GetList();
+ const auto& disabled = app.FindKey("disabled")->GetListDeprecated();
EXPECT_EQ(1u, disabled.size());
EXPECT_EQ(1, disabled[0].FindKey("reason")->GetInt());
}
@@ -862,9 +885,10 @@ TEST_P(UpdateCheckerTest, ComponentDisabled) {
const auto& request = post_interceptor->GetRequestBody(0);
const auto root = base::JSONReader::Read(request);
ASSERT_TRUE(root);
- const auto& app = root->FindKey("request")->FindKey("app")->GetList()[0];
+ const auto& app =
+ root->FindKey("request")->FindKey("app")->GetListDeprecated()[0];
EXPECT_EQ(false, app.FindKey("enabled")->GetBool());
- const auto& disabled = app.FindKey("disabled")->GetList();
+ const auto& disabled = app.FindKey("disabled")->GetListDeprecated();
EXPECT_EQ(3u, disabled.size());
EXPECT_EQ(4, disabled[0].FindKey("reason")->GetInt());
EXPECT_EQ(8, disabled[1].FindKey("reason")->GetInt());
@@ -887,9 +911,10 @@ TEST_P(UpdateCheckerTest, ComponentDisabled) {
const auto& request = post_interceptor->GetRequestBody(0);
const auto root = base::JSONReader::Read(request);
ASSERT_TRUE(root);
- const auto& app = root->FindKey("request")->FindKey("app")->GetList()[0];
+ const auto& app =
+ root->FindKey("request")->FindKey("app")->GetListDeprecated()[0];
EXPECT_EQ(false, app.FindKey("enabled")->GetBool());
- const auto& disabled = app.FindKey("disabled")->GetList();
+ const auto& disabled = app.FindKey("disabled")->GetListDeprecated();
EXPECT_EQ(4u, disabled.size());
EXPECT_EQ(0, disabled[0].FindKey("reason")->GetInt());
EXPECT_EQ(4, disabled[1].FindKey("reason")->GetInt());
@@ -927,7 +952,8 @@ TEST_P(UpdateCheckerTest, UpdateCheckUpdateDisabled) {
const auto& request = post_interceptor->GetRequestBody(0);
const auto root = base::JSONReader::Read(request);
ASSERT_TRUE(root);
- const auto& app = root->FindKey("request")->FindKey("app")->GetList()[0];
+ const auto& app =
+ root->FindKey("request")->FindKey("app")->GetListDeprecated()[0];
EXPECT_EQ(kUpdateItemId, app.FindKey("appid")->GetString());
EXPECT_EQ("0.9", app.FindKey("version")->GetString());
EXPECT_EQ(true, app.FindKey("enabled")->GetBool());
@@ -952,7 +978,8 @@ TEST_P(UpdateCheckerTest, UpdateCheckUpdateDisabled) {
const auto& request = post_interceptor->GetRequestBody(0);
const auto root = base::JSONReader::Read(request);
ASSERT_TRUE(root);
- const auto& app = root->FindKey("request")->FindKey("app")->GetList()[0];
+ const auto& app =
+ root->FindKey("request")->FindKey("app")->GetListDeprecated()[0];
EXPECT_EQ(kUpdateItemId, app.FindKey("appid")->GetString());
EXPECT_EQ("0.9", app.FindKey("version")->GetString());
EXPECT_EQ(true, app.FindKey("enabled")->GetBool());
@@ -985,7 +1012,7 @@ TEST_P(UpdateCheckerTest, SameVersionUpdateAllowed) {
const auto& request = post_interceptor->GetRequestBody(0);
const auto root = base::JSONReader::Read(request);
ASSERT_TRUE(root);
- const auto& app = root->FindPath("request.app")->GetList()[0];
+ const auto& app = root->FindPath("request.app")->GetListDeprecated()[0];
EXPECT_STREQ(kUpdateItemId, app.FindStringPath("appid")->c_str());
EXPECT_TRUE(app.FindDictKey("updatecheck"));
EXPECT_FALSE(app.FindPath("updatecheck.sameversionupdate"));
@@ -1008,11 +1035,12 @@ TEST_P(UpdateCheckerTest, SameVersionUpdateAllowed) {
const auto& request = post_interceptor->GetRequestBody(0);
const auto root = base::JSONReader::Read(request);
ASSERT_TRUE(root);
- const auto& app = root->FindPath("request.app")->GetList()[0];
+ const auto& app = root->FindPath("request.app")->GetListDeprecated()[0];
EXPECT_STREQ(kUpdateItemId, app.FindStringPath("appid")->c_str());
EXPECT_EQ(app.FindBoolPath("updatecheck.sameversionupdate").value(), true);
}
}
+
TEST_P(UpdateCheckerTest, NoUpdateActionRun) {
EXPECT_TRUE(post_interceptor_->ExpectRequest(
std::make_unique<PartialMatch>("updatecheck"),
@@ -1072,7 +1100,8 @@ TEST_P(UpdateCheckerTest, UpdatePauseResume) {
const auto& request = post_interceptor_->GetRequestBody(0);
const auto root = base::JSONReader::Read(request);
ASSERT_TRUE(root);
- const auto& app = root->FindKey("request")->FindKey("app")->GetList()[0];
+ const auto& app =
+ root->FindKey("request")->FindKey("app")->GetListDeprecated()[0];
EXPECT_EQ(kUpdateItemId, app.FindKey("appid")->GetString());
EXPECT_EQ("0.9", app.FindKey("version")->GetString());
EXPECT_EQ("TEST", app.FindKey("brand")->GetString());
@@ -1081,7 +1110,7 @@ TEST_P(UpdateCheckerTest, UpdatePauseResume) {
EXPECT_EQ(-2, app.FindPath({"ping", "r"})->GetInt());
EXPECT_EQ("fp1", app.FindKey("packages")
->FindKey("package")
- ->GetList()[0]
+ ->GetListDeprecated()[0]
.FindKey("fp")
->GetString());
}
@@ -1171,4 +1200,34 @@ TEST_P(UpdateCheckerTest, ParseErrorAppStatusErrorUnknownApplication) {
EXPECT_STREQ("error-unknownApplication", result.status.c_str());
}
+TEST_P(UpdateCheckerTest, DomainJoined) {
+ for (const auto is_managed : std::initializer_list<absl::optional<bool>>{
+ absl::nullopt, false, true}) {
+ EXPECT_TRUE(post_interceptor_->ExpectRequest(
+ std::make_unique<PartialMatch>("updatecheck"),
+ test_file("updatecheck_reply_noupdate.json")));
+ update_checker_ = UpdateChecker::Create(config_, metadata_.get());
+
+ IdToComponentPtrMap components;
+ components[kUpdateItemId] = MakeComponent();
+
+ config_->SetIsMachineExternallyManaged(is_managed);
+ update_checker_->CheckForUpdates(
+ update_context_->session_id, {kUpdateItemId}, components, {},
+ base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
+ base::Unretained(this)));
+ RunThreads();
+
+ ASSERT_EQ(post_interceptor_->GetCount(), 1);
+ const auto root =
+ base::JSONReader::Read(post_interceptor_->GetRequestBody(0));
+ post_interceptor_->Reset();
+
+ // What is injected in the update checker by the configurator must
+ // match what is sent in the update check.
+ ASSERT_TRUE(root);
+ EXPECT_EQ(is_managed, root->FindBoolPath("request.domainjoined"));
+ }
+}
+
} // namespace update_client
diff --git a/chromium/components/update_client/update_client_unittest.cc b/chromium/components/update_client/update_client_unittest.cc
index cbdaef815c4..c299941eb8a 100644
--- a/chromium/components/update_client/update_client_unittest.cc
+++ b/chromium/components/update_client/update_client_unittest.cc
@@ -2833,14 +2833,16 @@ TEST_F(UpdateClientTest, OneCrxInstall) {
EXPECT_EQ(ComponentState::kUpdated, items[5].state);
EXPECT_STREQ("jebgalgnebhfojomionfpkfelancnnkf", items[5].id.c_str());
- const base::DictionaryValue* dict =
+ const base::Value* dict =
config()->GetPrefService()->GetDictionary("updateclientdata");
- std::string pv;
- dict->GetString("apps.jebgalgnebhfojomionfpkfelancnnkf.pv", &pv);
- EXPECT_STREQ("1.0", pv.c_str());
- std::string fingerprint;
- dict->GetString("apps.jebgalgnebhfojomionfpkfelancnnkf.fp", &fingerprint);
- EXPECT_STREQ("some-fingerprint", fingerprint.c_str());
+ const std::string* pv =
+ dict->FindStringPath("apps.jebgalgnebhfojomionfpkfelancnnkf.pv");
+ ASSERT_TRUE(pv);
+ EXPECT_STREQ("1.0", pv->c_str());
+ const std::string* fingerprint =
+ dict->FindStringPath("apps.jebgalgnebhfojomionfpkfelancnnkf.fp");
+ ASSERT_TRUE(fingerprint);
+ EXPECT_STREQ("some-fingerprint", fingerprint->c_str());
update_client->RemoveObserver(&observer);
}
diff --git a/chromium/components/update_client/update_engine.h b/chromium/components/update_client/update_engine.h
index 3b409dd48ca..265ada0b0b7 100644
--- a/chromium/components/update_client/update_engine.h
+++ b/chromium/components/update_client/update_engine.h
@@ -5,7 +5,6 @@
#ifndef COMPONENTS_UPDATE_CLIENT_UPDATE_ENGINE_H_
#define COMPONENTS_UPDATE_CLIENT_UPDATE_ENGINE_H_
-#include <list>
#include <map>
#include <memory>
#include <string>
diff --git a/chromium/components/update_client/update_query_params.cc b/chromium/components/update_client/update_query_params.cc
index 6b1d502f3de..6abf11963c8 100644
--- a/chromium/components/update_client/update_query_params.cc
+++ b/chromium/components/update_client/update_query_params.cc
@@ -13,7 +13,7 @@
#include "components/update_client/update_query_params_delegate.h"
#include "components/version_info/version_info.h"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include "base/win/windows_version.h"
#endif
@@ -26,19 +26,19 @@ const char kUnknown[] = "unknown";
// The request extra information is the OS and architecture, this helps
// the server select the right package to be delivered.
const char kOs[] =
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
"mac";
-#elif defined(OS_WIN)
+#elif BUILDFLAG(IS_WIN)
"win";
-#elif defined(OS_ANDROID)
+#elif BUILDFLAG(IS_ANDROID)
"android";
#elif BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
"cros";
-#elif defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
+#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
"linux";
-#elif defined(OS_FUCHSIA)
+#elif BUILDFLAG(IS_FUCHSIA)
"fuchsia";
-#elif defined(OS_OPENBSD)
+#elif BUILDFLAG(IS_OPENBSD)
"openbsd";
#else
#error "unknown os"
@@ -114,7 +114,7 @@ const char* UpdateQueryParams::GetNaclArch() {
#if defined(ARCH_CPU_X86_FAMILY)
#if defined(ARCH_CPU_X86_64)
return "x86-64";
-#elif defined(OS_WIN)
+#elif BUILDFLAG(IS_WIN)
bool x86_64 = base::win::OSInfo::GetInstance()->IsWowX86OnAMD64();
return x86_64 ? "x86-64" : "x86-32";
#else
diff --git a/chromium/components/update_client/updater_state.cc b/chromium/components/update_client/updater_state.cc
deleted file mode 100644
index b44a6258a30..00000000000
--- a/chromium/components/update_client/updater_state.cc
+++ /dev/null
@@ -1,102 +0,0 @@
-
-// Copyright (c) 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.
-
-#include "components/update_client/updater_state.h"
-
-#include <string>
-#include <utility>
-
-#include "base/enterprise_util.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/utf_string_conversions.h"
-#include "build/branding_buildflags.h"
-#include "build/build_config.h"
-
-namespace update_client {
-
-// The value of this constant does not reflect its name (i.e. "domainjoined"
-// vs something like "isenterprisemanaged") because it is used with omaha.
-// After discussion with omaha team it was decided to leave the value as is to
-// keep continuity with previous chrome versions.
-const char UpdaterState::kIsEnterpriseManaged[] = "domainjoined";
-
-UpdaterState::UpdaterState(bool is_machine) : is_machine_(is_machine) {}
-
-UpdaterState::~UpdaterState() = default;
-
-std::unique_ptr<UpdaterState::Attributes> UpdaterState::GetState(
- bool is_machine) {
-#if defined(OS_WIN) || defined(OS_MAC)
- UpdaterState updater_state(is_machine);
- updater_state.ReadState();
- return std::make_unique<Attributes>(updater_state.BuildAttributes());
-#else
- return nullptr;
-#endif // OS_WIN or Mac
-}
-
-#if defined(OS_WIN) || defined(OS_MAC)
-void UpdaterState::ReadState() {
- is_enterprise_managed_ = base::IsMachineExternallyManaged();
-
-#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
- updater_name_ = GetUpdaterName();
- updater_version_ = GetUpdaterVersion(is_machine_);
- last_autoupdate_started_ = GetUpdaterLastStartedAU(is_machine_);
- last_checked_ = GetUpdaterLastChecked(is_machine_);
- is_autoupdate_check_enabled_ = IsAutoupdateCheckEnabled();
- update_policy_ = GetUpdatePolicy();
-#endif // BUILDFLAG(GOOGLE_CHROME_BRANDING)
-}
-#endif // OS_WIN or Mac
-
-UpdaterState::Attributes UpdaterState::BuildAttributes() const {
- Attributes attributes;
-
-#if defined(OS_WIN)
- // Only Windows implements this attribute in a meaningful way.
- attributes["ismachine"] = is_machine_ ? "1" : "0";
-#endif // OS_WIN
- attributes[kIsEnterpriseManaged] = is_enterprise_managed_ ? "1" : "0";
-
- attributes["name"] = updater_name_;
-
- if (updater_version_.IsValid())
- attributes["version"] = updater_version_.GetString();
-
- const base::Time now = base::Time::NowFromSystemTime();
- if (!last_autoupdate_started_.is_null())
- attributes["laststarted"] =
- NormalizeTimeDelta(now - last_autoupdate_started_);
- if (!last_checked_.is_null())
- attributes["lastchecked"] = NormalizeTimeDelta(now - last_checked_);
-
- attributes["autoupdatecheckenabled"] =
- is_autoupdate_check_enabled_ ? "1" : "0";
-
- DCHECK((update_policy_ >= 0 && update_policy_ <= 3) || update_policy_ == -1);
- attributes["updatepolicy"] = base::NumberToString(update_policy_);
-
- return attributes;
-}
-
-std::string UpdaterState::NormalizeTimeDelta(const base::TimeDelta& delta) {
- const base::TimeDelta two_weeks = base::Days(14);
- const base::TimeDelta two_months = base::Days(56);
-
- std::string val; // Contains the value to return in hours.
- if (delta <= two_weeks) {
- val = "0";
- } else if (two_weeks < delta && delta <= two_months) {
- val = "336"; // 2 weeks in hours.
- } else {
- val = "1344"; // 2*28 days in hours.
- }
-
- DCHECK(!val.empty());
- return val;
-}
-
-} // namespace update_client
diff --git a/chromium/components/update_client/updater_state.h b/chromium/components/update_client/updater_state.h
deleted file mode 100644
index ec11d4a7a49..00000000000
--- a/chromium/components/update_client/updater_state.h
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright (c) 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.
-
-#ifndef COMPONENTS_UPDATE_CLIENT_UPDATER_STATE_H_
-#define COMPONENTS_UPDATE_CLIENT_UPDATER_STATE_H_
-
-#include <map>
-#include <memory>
-#include <string>
-
-#include "base/gtest_prod_util.h"
-#include "base/time/time.h"
-#include "base/version.h"
-
-namespace update_client {
-
-class UpdaterState {
- public:
- using Attributes = std::map<std::string, std::string>;
-
- static const char kIsEnterpriseManaged[];
-
- // Returns a map of items representing the state of an updater.
- // If |is_machine| is true, this indicates that the updater state corresponds
- // to the machine instance of the updater. Returns nullptr on
- // the platforms and builds where this feature is not supported.
- static std::unique_ptr<Attributes> GetState(bool is_machine);
-
- ~UpdaterState();
-
- private:
- FRIEND_TEST_ALL_PREFIXES(UpdaterStateTest, Serialize);
-
- explicit UpdaterState(bool is_machine);
-
- // This function is best-effort. It updates the class members with
- // the relevant values that could be retrieved.
- void ReadState();
-
- // Builds the map of state attributes by serializing this object state.
- Attributes BuildAttributes() const;
-
- static std::string GetUpdaterName();
- static base::Version GetUpdaterVersion(bool is_machine);
- static bool IsAutoupdateCheckEnabled();
- static base::Time GetUpdaterLastStartedAU(bool is_machine);
- static base::Time GetUpdaterLastChecked(bool is_machine);
-
- static int GetUpdatePolicy();
-
- static std::string NormalizeTimeDelta(const base::TimeDelta& delta);
-
- // True if the Omaha updater is installed per-machine.
- // The MacOS implementation ignores the value of this member but this may
- // change in the future.
- bool is_machine_;
- std::string updater_name_;
- base::Version updater_version_;
- base::Time last_autoupdate_started_;
- base::Time last_checked_;
- bool is_enterprise_managed_ = false;
- bool is_autoupdate_check_enabled_ = false;
- int update_policy_ = 0;
-};
-
-} // namespace update_client
-
-#endif // COMPONENTS_UPDATE_CLIENT_UPDATER_STATE_H_
diff --git a/chromium/components/update_client/updater_state_mac.mm b/chromium/components/update_client/updater_state_mac.mm
deleted file mode 100644
index 9ffb980b33b..00000000000
--- a/chromium/components/update_client/updater_state_mac.mm
+++ /dev/null
@@ -1,117 +0,0 @@
-// Copyright 2017 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.
-
-#import <Foundation/Foundation.h>
-
-#include "base/enterprise_util.h"
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/mac/foundation_util.h"
-#include "base/mac/scoped_nsobject.h"
-#include "base/strings/sys_string_conversions.h"
-#include "base/version.h"
-#include "components/update_client/updater_state.h"
-
-namespace update_client {
-
-namespace {
-
-const base::FilePath::CharType kKeystonePlist[] = FILE_PATH_LITERAL(
- "Google/GoogleSoftwareUpdate/GoogleSoftwareUpdate.bundle/"
- "Contents/Info.plist");
-
-// Gets a value from the updater settings. Returns a retained object.
-// T should be a toll-free Foundation framework type. See Apple's
-// documentation for toll-free bridging.
-template<class T>
-base::scoped_nsobject<T> GetUpdaterSettingsValue(NSString* value_name) {
- CFStringRef app_id = CFSTR("com.google.Keystone.Agent");
- base::ScopedCFTypeRef<CFPropertyListRef> plist(
- CFPreferencesCopyAppValue(base::mac::NSToCFCast(value_name), app_id));
- return base::scoped_nsobject<T>(
- base::mac::ObjCCastStrict<T>(static_cast<id>(plist.get())),
- base::scoped_policy::RETAIN);
-}
-
-base::Time GetUpdaterSettingsTime(NSString* value_name) {
- base::scoped_nsobject<NSDate> date =
- GetUpdaterSettingsValue<NSDate>(value_name);
- base::Time result =
- base::Time::FromCFAbsoluteTime([date timeIntervalSinceReferenceDate]);
-
- return result;
-}
-
-base::Version GetVersionFromPlist(const base::FilePath& info_plist) {
- @autoreleasepool {
- NSData* data = [NSData
- dataWithContentsOfFile:base::mac::FilePathToNSString(info_plist)];
- if ([data length] == 0) {
- return base::Version();
- }
- NSDictionary* all_keys =
- base::mac::ObjCCastStrict<NSDictionary>([NSPropertyListSerialization
- propertyListWithData:data
- options:NSPropertyListImmutable
- format:nil
- error:nil]);
- if (all_keys == nil) {
- return base::Version();
- }
- CFStringRef version = base::mac::GetValueFromDictionary<CFStringRef>(
- base::mac::NSToCFCast(all_keys), kCFBundleVersionKey);
- if (version == NULL) {
- return base::Version();
- }
- return base::Version(base::SysCFStringRefToUTF8(version));
- }
-}
-
-} // namespace
-
-std::string UpdaterState::GetUpdaterName() {
- return std::string("Keystone");
-}
-
-base::Version UpdaterState::GetUpdaterVersion(bool /*is_machine*/) {
- // System Keystone trumps user one, so check this one first
- base::FilePath local_library;
- bool success = base::mac::GetLocalDirectory(NSLibraryDirectory,
- &local_library);
- DCHECK(success);
- base::FilePath system_bundle_plist = local_library.Append(kKeystonePlist);
- base::Version system_keystone = GetVersionFromPlist(system_bundle_plist);
- if (system_keystone.IsValid()) {
- return system_keystone;
- }
-
- base::FilePath user_bundle_plist =
- base::mac::GetUserLibraryPath().Append(kKeystonePlist);
- return GetVersionFromPlist(user_bundle_plist);
-}
-
-base::Time UpdaterState::GetUpdaterLastStartedAU(bool /*is_machine*/) {
- return GetUpdaterSettingsTime(@"lastCheckStartDate");
-}
-
-base::Time UpdaterState::GetUpdaterLastChecked(bool /*is_machine*/) {
- return GetUpdaterSettingsTime(@"lastServerCheckDate");
-}
-
-bool UpdaterState::IsAutoupdateCheckEnabled() {
- // Auto-update check period override (in seconds).
- // Applies only to older versions of Keystone.
- base::scoped_nsobject<NSNumber> timeInterval =
- GetUpdaterSettingsValue<NSNumber>(@"checkInterval");
- if (!timeInterval.get()) return true;
- int value = [timeInterval intValue];
-
- return 0 < value && value < (24 * 60 * 60);
-}
-
-int UpdaterState::GetUpdatePolicy() {
- return -1; // Keystone does not support update policies.
-}
-
-} // namespace update_client
diff --git a/chromium/components/update_client/updater_state_unittest.cc b/chromium/components/update_client/updater_state_unittest.cc
deleted file mode 100644
index 298e131bfbd..00000000000
--- a/chromium/components/update_client/updater_state_unittest.cc
+++ /dev/null
@@ -1,127 +0,0 @@
-// 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.
-
-#include "components/update_client/updater_state.h"
-
-#include "base/time/time.h"
-#include "base/version.h"
-#include "build/branding_buildflags.h"
-#include "build/build_config.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace update_client {
-
-class UpdaterStateTest : public testing::Test {
- public:
- UpdaterStateTest() = default;
-
- UpdaterStateTest(const UpdaterStateTest&) = delete;
- UpdaterStateTest& operator=(const UpdaterStateTest&) = delete;
-
- ~UpdaterStateTest() override = default;
-};
-
-TEST_F(UpdaterStateTest, Serialize) {
- UpdaterState updater_state(false);
-
- updater_state.updater_name_ = "the updater";
- updater_state.updater_version_ = base::Version("1.0");
- updater_state.last_autoupdate_started_ = base::Time::NowFromSystemTime();
- updater_state.last_checked_ = base::Time::NowFromSystemTime();
- updater_state.is_enterprise_managed_ = false;
- updater_state.is_autoupdate_check_enabled_ = true;
- updater_state.update_policy_ = 1;
-
- auto attributes = updater_state.BuildAttributes();
-
- // Sanity check all members.
- EXPECT_STREQ("the updater", attributes.at("name").c_str());
- EXPECT_STREQ("1.0", attributes.at("version").c_str());
- EXPECT_STREQ("0", attributes.at("laststarted").c_str());
- EXPECT_STREQ("0", attributes.at("lastchecked").c_str());
- EXPECT_STREQ("0", attributes.at("domainjoined").c_str());
- EXPECT_STREQ("1", attributes.at("autoupdatecheckenabled").c_str());
- EXPECT_STREQ("1", attributes.at("updatepolicy").c_str());
-
-#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
-#if defined(OS_WIN)
- // The value of "ismachine".
- EXPECT_STREQ("0", UpdaterState::GetState(false)->at("ismachine").c_str());
- EXPECT_STREQ("1", UpdaterState::GetState(true)->at("ismachine").c_str());
-
- // The name of the Windows updater for Chrome.
- EXPECT_STREQ("Omaha", UpdaterState::GetState(false)->at("name").c_str());
-#elif defined(OS_MAC)
- // MacOS does not serialize "ismachine".
- EXPECT_EQ(0UL, UpdaterState::GetState(false)->count("ismachine"));
- EXPECT_EQ(0UL, UpdaterState::GetState(true)->count("ismachine"));
- EXPECT_STREQ("Keystone", UpdaterState::GetState(false)->at("name").c_str());
-#endif // OS_WIN
-#endif // BUILDFLAG(GOOGLE_CHROME_BRANDING)
-
- // Tests some of the remaining values.
- updater_state = UpdaterState(false);
-
- // Don't serialize an invalid version if it could not be read.
- updater_state.updater_version_ = base::Version();
- attributes = updater_state.BuildAttributes();
- EXPECT_EQ(0u, attributes.count("version"));
-
- updater_state.updater_version_ = base::Version("0.0.0.0");
- attributes = updater_state.BuildAttributes();
- EXPECT_STREQ("0.0.0.0", attributes.at("version").c_str());
-
- updater_state.last_autoupdate_started_ =
- base::Time::NowFromSystemTime() - base::Days(15);
- attributes = updater_state.BuildAttributes();
- EXPECT_STREQ("336", attributes.at("laststarted").c_str());
-
- updater_state.last_autoupdate_started_ =
- base::Time::NowFromSystemTime() - base::Days(58);
- attributes = updater_state.BuildAttributes();
- EXPECT_STREQ("1344", attributes.at("laststarted").c_str());
-
- updater_state.last_autoupdate_started_ =
- base::Time::NowFromSystemTime() - base::Days(90);
- attributes = updater_state.BuildAttributes();
- EXPECT_STREQ("1344", attributes.at("laststarted").c_str());
-
- // Don't serialize the time if it could not be read.
- updater_state.last_autoupdate_started_ = base::Time();
- attributes = updater_state.BuildAttributes();
- EXPECT_EQ(0u, attributes.count("laststarted"));
-
- updater_state.last_checked_ =
- base::Time::NowFromSystemTime() - base::Days(15);
- attributes = updater_state.BuildAttributes();
- EXPECT_STREQ("336", attributes.at("lastchecked").c_str());
-
- updater_state.last_checked_ =
- base::Time::NowFromSystemTime() - base::Days(90);
- attributes = updater_state.BuildAttributes();
- EXPECT_STREQ("1344", attributes.at("lastchecked").c_str());
-
- // Don't serialize the time if it could not be read (the value is invalid).
- updater_state.last_checked_ = base::Time();
- attributes = updater_state.BuildAttributes();
- EXPECT_EQ(0u, attributes.count("lastchecked"));
-
- updater_state.is_enterprise_managed_ = true;
- attributes = updater_state.BuildAttributes();
- EXPECT_STREQ("1", attributes.at("domainjoined").c_str());
-
- updater_state.is_autoupdate_check_enabled_ = false;
- attributes = updater_state.BuildAttributes();
- EXPECT_STREQ("0", attributes.at("autoupdatecheckenabled").c_str());
-
- updater_state.update_policy_ = 0;
- attributes = updater_state.BuildAttributes();
- EXPECT_STREQ("0", attributes.at("updatepolicy").c_str());
-
- updater_state.update_policy_ = -1;
- attributes = updater_state.BuildAttributes();
- EXPECT_STREQ("-1", attributes.at("updatepolicy").c_str());
-}
-
-} // namespace update_client
diff --git a/chromium/components/update_client/updater_state_win.cc b/chromium/components/update_client/updater_state_win.cc
deleted file mode 100644
index 102029a0fe6..00000000000
--- a/chromium/components/update_client/updater_state_win.cc
+++ /dev/null
@@ -1,135 +0,0 @@
-// 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.
-
-#include "components/update_client/updater_state.h"
-
-#include <windows.h>
-
-#include <string>
-#include <utility>
-
-#include "base/enterprise_util.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/win/registry.h"
-#include "base/win/win_util.h"
-
-// TODO(sorin): implement this in terms of
-// chrome/installer/util/google_update_settings (crbug.com/615187).
-
-namespace update_client {
-
-namespace {
-
-// Google Update group policy settings.
-const wchar_t kGoogleUpdatePoliciesKey[] =
- L"SOFTWARE\\Policies\\Google\\Update";
-const wchar_t kCheckPeriodOverrideMinutes[] = L"AutoUpdateCheckPeriodMinutes";
-const wchar_t kUpdatePolicyValue[] = L"UpdateDefault";
-const wchar_t kChromeUpdatePolicyOverride[] =
- L"Update{8A69D345-D564-463C-AFF1-A69D9E530F96}";
-
-// Don't allow update periods longer than six weeks (Chrome release cadence).
-const int kCheckPeriodOverrideMinutesMax = 60 * 24 * 7 * 6;
-
-// Google Update registry settings.
-const wchar_t kRegPathGoogleUpdate[] = L"Software\\Google\\Update";
-const wchar_t kRegPathClientsGoogleUpdate[] =
- L"Software\\Google\\Update\\Clients\\"
- L"{430FD4D0-B729-4F61-AA34-91526481799D}";
-const wchar_t kRegValueGoogleUpdatePv[] = L"pv";
-const wchar_t kRegValueLastStartedAU[] = L"LastStartedAU";
-const wchar_t kRegValueLastChecked[] = L"LastChecked";
-
-base::Time GetUpdaterTimeValue(bool is_machine, const wchar_t* value_name) {
- const HKEY root_key = is_machine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
- base::win::RegKey update_key;
-
- if (update_key.Open(root_key, kRegPathGoogleUpdate,
- KEY_QUERY_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS) {
- DWORD value(0);
- if (update_key.ReadValueDW(value_name, &value) == ERROR_SUCCESS) {
- return base::Time::FromTimeT(value);
- }
- }
-
- return base::Time();
-}
-
-} // namespace
-
-std::string UpdaterState::GetUpdaterName() {
- return std::string("Omaha");
-}
-
-base::Version UpdaterState::GetUpdaterVersion(bool is_machine) {
- const HKEY root_key = is_machine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
- std::wstring version;
- base::win::RegKey key;
-
- if (key.Open(root_key, kRegPathClientsGoogleUpdate,
- KEY_QUERY_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS &&
- key.ReadValue(kRegValueGoogleUpdatePv, &version) == ERROR_SUCCESS) {
- return base::Version(base::WideToUTF8(version));
- }
-
- return base::Version();
-}
-
-base::Time UpdaterState::GetUpdaterLastStartedAU(bool is_machine) {
- return GetUpdaterTimeValue(is_machine, kRegValueLastStartedAU);
-}
-
-base::Time UpdaterState::GetUpdaterLastChecked(bool is_machine) {
- return GetUpdaterTimeValue(is_machine, kRegValueLastChecked);
-}
-
-bool UpdaterState::IsAutoupdateCheckEnabled() {
- // Check the auto-update check period override. If it is 0 or exceeds the
- // maximum timeout, then for all intents and purposes auto updates are
- // disabled.
- base::win::RegKey policy_key;
- DWORD value = 0;
- if (policy_key.Open(HKEY_LOCAL_MACHINE, kGoogleUpdatePoliciesKey,
- KEY_QUERY_VALUE) == ERROR_SUCCESS &&
- policy_key.ReadValueDW(kCheckPeriodOverrideMinutes, &value) ==
- ERROR_SUCCESS &&
- (value == 0 || value > kCheckPeriodOverrideMinutesMax)) {
- return false;
- }
-
- return true;
-}
-
-// Returns -1 if the policy is not found or the value was invalid. Otherwise,
-// returns a value in the [0, 3] range, representing the value of the
-// Chrome update group policy.
-int UpdaterState::GetUpdatePolicy() {
- const int kMaxUpdatePolicyValue = 3;
-
- base::win::RegKey policy_key;
-
- if (policy_key.Open(HKEY_LOCAL_MACHINE, kGoogleUpdatePoliciesKey,
- KEY_QUERY_VALUE) != ERROR_SUCCESS) {
- return -1;
- }
-
- DWORD value = 0;
- // First try to read the Chrome-specific override.
- if (policy_key.ReadValueDW(kChromeUpdatePolicyOverride, &value) ==
- ERROR_SUCCESS &&
- value <= kMaxUpdatePolicyValue) {
- return value;
- }
-
- // Try to read default override.
- if (policy_key.ReadValueDW(kUpdatePolicyValue, &value) == ERROR_SUCCESS &&
- value <= kMaxUpdatePolicyValue) {
- return value;
- }
-
- return -1;
-}
-
-} // namespace update_client
diff --git a/chromium/components/update_client/utils_unittest.cc b/chromium/components/update_client/utils_unittest.cc
index d71e1ab3bfb..fde5c1842a2 100644
--- a/chromium/components/update_client/utils_unittest.cc
+++ b/chromium/components/update_client/utils_unittest.cc
@@ -8,7 +8,6 @@
#include "base/files/file_path.h"
#include "base/path_service.h"
-#include "components/update_client/updater_state.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
diff --git a/chromium/components/upload_list/text_log_upload_list.cc b/chromium/components/upload_list/text_log_upload_list.cc
index 8c5d0e35669..823b956fad5 100644
--- a/chromium/components/upload_list/text_log_upload_list.cc
+++ b/chromium/components/upload_list/text_log_upload_list.cc
@@ -7,6 +7,7 @@
#include <algorithm>
#include <sstream>
+#include "base/containers/adapters.h"
#include "base/files/file_util.h"
#include "base/json/json_reader.h"
#include "base/strings/string_number_conversions.h"
@@ -234,9 +235,7 @@ void TextLogUploadList::ClearUploadList(const base::Time& begin,
void TextLogUploadList::ParseLogEntries(
const std::vector<std::string>& log_entries,
std::vector<UploadInfo>* uploads) {
- std::vector<std::string>::const_reverse_iterator i;
- for (i = log_entries.rbegin(); i != log_entries.rend(); ++i) {
- const std::string& line = *i;
+ for (const std::string& line : base::Reversed(log_entries)) {
std::unique_ptr<UploadInfo> info;
absl::optional<base::Value> json = base::JSONReader::Read(line);
diff --git a/chromium/components/url_formatter/elide_url.cc b/chromium/components/url_formatter/elide_url.cc
index 62f47833505..0ea12974699 100644
--- a/chromium/components/url_formatter/elide_url.cc
+++ b/chromium/components/url_formatter/elide_url.cc
@@ -8,6 +8,7 @@
#include "base/check_op.h"
#include "base/i18n/rtl.h"
+#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_split.h"
@@ -25,7 +26,7 @@
namespace {
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
const char16_t kDot = '.';
// Build a path from the first |num_components| elements in |path_elements|.
@@ -119,7 +120,7 @@ void SplitHost(const GURL& url,
// Get sub domain.
const size_t domain_start_index = url_host->find(*url_domain);
- std::u16string kWwwPrefix = u"www.";
+ constexpr base::StringPiece16 kWwwPrefix = u"www.";
if (domain_start_index != std::u16string::npos)
*url_subdomain = url_host->substr(0, domain_start_index);
if ((*url_subdomain == kWwwPrefix || url_subdomain->empty() ||
@@ -127,7 +128,7 @@ void SplitHost(const GURL& url,
url_subdomain->clear();
}
}
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
bool ShouldShowScheme(base::StringPiece scheme,
const url_formatter::SchemeDisplay scheme_display) {
@@ -159,7 +160,7 @@ std::u16string HostForDisplay(base::StringPiece host_in_puny) {
namespace url_formatter {
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
// TODO(pkasting): http://crbug.com/77883 This whole function gets
// kerning/ligatures/etc. issues potentially wrong by assuming that the width of
@@ -217,7 +218,7 @@ std::u16string ElideUrl(const GURL& url,
// domain is now C: - this is a nice hack for eliding to work pleasantly.
if (url.SchemeIsFile()) {
// Split the path string using ":"
- const std::u16string kColon(1, ':');
+ constexpr base::StringPiece16 kColon(u":", 1);
std::vector<std::u16string> file_path_split = base::SplitString(
url_path, kColon, base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
if (file_path_split.size() > 1) { // File is of type "file:///C:/.."
@@ -225,7 +226,8 @@ std::u16string ElideUrl(const GURL& url,
url_domain.clear();
url_subdomain.clear();
- url_host = url_domain = file_path_split.at(0).substr(1) + kColon;
+ url_host = url_domain =
+ base::StrCat({file_path_split.at(0).substr(1), kColon});
url_path_query_etc = url_path = file_path_split.at(1);
}
}
@@ -358,31 +360,29 @@ std::u16string ElideHost(const GURL& url,
gfx::ELIDE_HEAD);
}
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
std::u16string FormatUrlForSecurityDisplay(const GURL& url,
const SchemeDisplay scheme_display) {
if (!url.is_valid() || url.is_empty() || !url.IsStandard())
return url_formatter::FormatUrl(url);
- const std::u16string colon(u":");
- const std::u16string scheme_separator(
- base::ASCIIToUTF16(url::kStandardSchemeSeparator));
+ constexpr base::StringPiece16 colon(u":");
if (url.SchemeIsFile()) {
- return base::ASCIIToUTF16(url::kFileScheme) + scheme_separator +
- base::UTF8ToUTF16(url.path());
+ return base::StrCat({url::kFileScheme16, url::kStandardSchemeSeparator16,
+ base::UTF8ToUTF16(url.path())});
}
if (url.SchemeIsFileSystem()) {
const GURL* inner_url = url.inner_url();
if (inner_url->SchemeIsFile()) {
- return base::ASCIIToUTF16(url::kFileSystemScheme) + colon +
- FormatUrlForSecurityDisplay(*inner_url) +
- base::UTF8ToUTF16(url.path());
+ return base::StrCat({url::kFileSystemScheme16, colon,
+ FormatUrlForSecurityDisplay(*inner_url),
+ base::UTF8ToUTF16(url.path())});
}
- return base::ASCIIToUTF16(url::kFileSystemScheme) + colon +
- FormatUrlForSecurityDisplay(*inner_url);
+ return base::StrCat({url::kFileSystemScheme16, colon,
+ FormatUrlForSecurityDisplay(*inner_url)});
}
const GURL origin = url.DeprecatedGetOriginAsURL();
@@ -390,15 +390,17 @@ std::u16string FormatUrlForSecurityDisplay(const GURL& url,
base::StringPiece host = origin.host_piece();
std::u16string result;
- if (ShouldShowScheme(scheme, scheme_display))
- result = base::UTF8ToUTF16(scheme) + scheme_separator;
+ if (ShouldShowScheme(scheme, scheme_display)) {
+ result = base::StrCat(
+ {base::UTF8ToUTF16(scheme), url::kStandardSchemeSeparator16});
+ }
result += HostForDisplay(host);
const int port = origin.IntPort();
const int default_port = url::DefaultPortForScheme(
scheme.data(), static_cast<int>(scheme.length()));
if (port != url::PORT_UNSPECIFIED && port != default_port)
- result += colon + base::UTF8ToUTF16(origin.port_piece());
+ result += base::StrCat({colon, base::UTF8ToUTF16(origin.port_piece())});
return result;
}
@@ -411,20 +413,20 @@ std::u16string FormatOriginForSecurityDisplay(
if (scheme.empty() && host.empty())
return std::u16string();
- const std::u16string colon(u":");
- const std::u16string scheme_separator(
- base::ASCIIToUTF16(url::kStandardSchemeSeparator));
+ constexpr base::StringPiece16 colon(u":");
std::u16string result;
- if (ShouldShowScheme(scheme, scheme_display))
- result = base::UTF8ToUTF16(scheme) + scheme_separator;
+ if (ShouldShowScheme(scheme, scheme_display)) {
+ result = base::StrCat(
+ {base::UTF8ToUTF16(scheme), url::kStandardSchemeSeparator16});
+ }
result += HostForDisplay(host);
int port = static_cast<int>(origin.port());
const int default_port = url::DefaultPortForScheme(
scheme.data(), static_cast<int>(scheme.length()));
if (port != 0 && port != default_port)
- result += colon + base::NumberToString16(origin.port());
+ result += base::StrCat({colon, base::NumberToString16(origin.port())});
return result;
}
diff --git a/chromium/components/url_formatter/elide_url.h b/chromium/components/url_formatter/elide_url.h
index ba326a60e36..b3782d1ad61 100644
--- a/chromium/components/url_formatter/elide_url.h
+++ b/chromium/components/url_formatter/elide_url.h
@@ -25,7 +25,7 @@ namespace url_formatter {
// ElideUrl and Elide host require
// gfx::GetStringWidthF which is not implemented in Android
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
// This function takes a GURL object and elides it. It returns a string
// composed of parts from subdomain, domain, path, filename and query.
// A "..." is added automatically at the end if the elided string is bigger
@@ -49,7 +49,7 @@ std::u16string ElideUrl(const GURL& url,
std::u16string ElideHost(const GURL& host_url,
const gfx::FontList& font_list,
float available_pixel_width);
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.components.url_formatter
enum class SchemeDisplay {
diff --git a/chromium/components/url_formatter/elide_url_unittest.cc b/chromium/components/url_formatter/elide_url_unittest.cc
index 78971b260fa..c6144d1b922 100644
--- a/chromium/components/url_formatter/elide_url_unittest.cc
+++ b/chromium/components/url_formatter/elide_url_unittest.cc
@@ -45,7 +45,7 @@ struct ParsingTestcase {
const std::vector<UrlComponent> components;
};
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
// Returns the width of a utf8 or utf16 string using default UI font, or the
// provided |font_list|.
@@ -260,7 +260,7 @@ TEST(TextEliderTest, TestTrailingEllipsisSlashEllipsisHack) {
// Test eliding of empty strings, URLs with ports, passwords, queries, etc.
TEST(TextEliderTest, TestElisionSpecialCases) {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// Needed to bypass DCHECK in GetFallbackFont.
base::test::SingleThreadTaskEnvironment task_environment(
base::test::SingleThreadTaskEnvironment::MainThreadType::UI);
@@ -321,7 +321,7 @@ TEST(TextEliderTest, TestFileURLEliding) {
/* clang-format on */
}},
// GURL parses "file:///C:path" differently on windows than it does on posix.
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
{"file:///C:path1/path2/path3/filename",
{
/* clang-format off */
@@ -331,7 +331,7 @@ TEST(TextEliderTest, TestFileURLEliding) {
"C:/" + kEllipsisStr + "/filename",
/* clang-format on */
}},
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
{"file://filer/foo/bar/file",
{
/* clang-format off */
@@ -395,7 +395,7 @@ TEST(TextEliderTest, TestHostEliding) {
gfx::FontList(), 2));
}
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
struct OriginTestData {
const char* const description;
diff --git a/chromium/components/url_formatter/spoof_checks/idn_spoof_checker.cc b/chromium/components/url_formatter/spoof_checks/idn_spoof_checker.cc
index 41eaa2ce91f..e5b11df39b0 100644
--- a/chromium/components/url_formatter/spoof_checks/idn_spoof_checker.cc
+++ b/chromium/components/url_formatter/spoof_checks/idn_spoof_checker.cc
@@ -285,7 +285,7 @@ IDNSpoofChecker::IDNSpoofChecker() {
// The ideal fix would be to change the omnibox font used for Thai. In
// that case, the Linux-only list should be revisited and potentially
// removed.
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
"[ทนบพรหเà¹à¹à¸”ลปฟม]",
#else
"[บพเà¹à¹]",
@@ -662,7 +662,7 @@ void IDNSpoofChecker::SetAllowedUnicodeSet(UErrorCode* status) {
// No need to block U+144A (Canadian Syllabics West-Cree P) separately
// because it's blocked from mixing with other scripts including Latin.
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
// The following characters are reported as present in the default macOS
// system UI font, but they render as blank. Remove them from the allowed
// set to prevent spoofing until the font issue is resolved.
diff --git a/chromium/components/url_formatter/spoof_checks/idn_spoof_checker_unittest.cc b/chromium/components/url_formatter/spoof_checks/idn_spoof_checker_unittest.cc
index d1c6857db82..e6a4791675a 100644
--- a/chromium/components/url_formatter/spoof_checks/idn_spoof_checker_unittest.cc
+++ b/chromium/components/url_formatter/spoof_checks/idn_spoof_checker_unittest.cc
@@ -735,7 +735,7 @@ const IDNTestCase kIdnCases[] = {
{"xn--ab-yod.com", u"a\u05f4b.com", kInvalid},
// Hebrew Gershayim with Arabic is disallowed.
{"xn--5eb7h.eg", u"\u0628\u05f4.eg", kUnsafe},
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
// These characters are blocked due to a font issue on Mac.
// Tibetan transliteration characters.
{"xn--com-lum.test.pl", u"com\u0f8c.test.pl", kUnsafe},
@@ -1038,7 +1038,7 @@ const IDNTestCase kIdnCases[] = {
u"\u1090\u1091\u1095\u1096\u1097.\u1019\u103c\u1014\u103a\u1019\u102c",
kSafe},
// Thai:
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
{"xn--o3cedqz2c.com", u"\u0e17\u0e19\u0e1a\u0e1e\u0e23\u0e2b.com", kUnsafe},
{"xn--o3cedqz2c.th", u"\u0e17\u0e19\u0e1a\u0e1e\u0e23\u0e2b.th", kSafe},
{"xn--o3cedqz2c.xn--o3cw4h",
diff --git a/chromium/components/url_formatter/spoof_checks/top_domains/make_top_domain_list_variables.cc b/chromium/components/url_formatter/spoof_checks/top_domains/make_top_domain_list_variables.cc
index 0f7e8001870..a6a64387107 100644
--- a/chromium/components/url_formatter/spoof_checks/top_domains/make_top_domain_list_variables.cc
+++ b/chromium/components/url_formatter/spoof_checks/top_domains/make_top_domain_list_variables.cc
@@ -89,7 +89,7 @@ int main(int argc, char* argv[]) {
logging::LOG_TO_SYSTEM_DEBUG_LOG | logging::LOG_TO_STDERR;
logging::InitLogging(settings);
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
std::vector<std::string> args;
base::CommandLine::StringVector wide_args = command_line.GetArgs();
for (const auto& arg : wide_args) {
diff --git a/chromium/components/url_formatter/spoof_checks/top_domains/top_domain_generator.cc b/chromium/components/url_formatter/spoof_checks/top_domains/top_domain_generator.cc
index ced7b384996..898ecebed26 100644
--- a/chromium/components/url_formatter/spoof_checks/top_domains/top_domain_generator.cc
+++ b/chromium/components/url_formatter/spoof_checks/top_domains/top_domain_generator.cc
@@ -96,7 +96,7 @@ int main(int argc, char* argv[]) {
base::i18n::InitializeICU();
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
std::vector<std::string> args;
base::CommandLine::StringVector wide_args = command_line.GetArgs();
for (const auto& arg : wide_args) {
diff --git a/chromium/components/url_formatter/url_fixer.cc b/chromium/components/url_formatter/url_fixer.cc
index 4532832bf70..cc280a6e2a4 100644
--- a/chromium/components/url_formatter/url_fixer.cc
+++ b/chromium/components/url_formatter/url_fixer.cc
@@ -25,7 +25,7 @@
#include "url/url_file.h"
#include "url/url_util.h"
-#if defined(OS_POSIX) || defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
#include "base/path_service.h"
#endif
@@ -100,14 +100,14 @@ base::TrimPositions TrimWhitespaceUTF8(const std::string& input,
// This implementation is not so fast since it converts the text encoding
// twice. Please feel free to file a bug if this function hurts the
// performance of Chrome.
- DCHECK(base::IsStringUTF8(input)) << input;
+ DCHECK(base::IsStringUTF8AllowingNoncharacters(input)) << input;
return TrimWhitespace(base::UTF8ToUTF16(input), positions, output);
}
// does some basic fixes for input that we want to test for file-ness
void PrepareStringForFileOps(const base::FilePath& text, std::string* output) {
TrimWhitespace(text.AsUTF16Unsafe(), base::TRIM_ALL, output);
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
base::ranges::replace(*output, '/', '\\');
#endif
}
@@ -128,7 +128,7 @@ bool ValidPathForFile(const std::string& text, base::FilePath* full_path) {
return true;
}
-#if defined(OS_POSIX) || defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
// Given a path that starts with ~, return a path that starts with an
// expanded-out /user/foobar directory.
std::string FixupHomedir(const std::string& text) {
@@ -157,7 +157,7 @@ std::string FixupHomedir(const std::string& text) {
// user foobar's home directory. Officially, we should use getpwent(),
// but that is a nasty blocking call.
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
static const char kHome[] = "/Users/";
#else
static const char kHome[] = "/home/";
@@ -175,14 +175,14 @@ std::string FixupPath(const std::string& text) {
DCHECK(!text.empty());
std::string filename;
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
base::FilePath input_path(base::UTF8ToWide(text));
PrepareStringForFileOps(input_path, &filename);
// Fixup Windows-style drive letters, where "C:" gets rewritten to "C|".
if (filename.length() > 1 && filename[1] == '|')
filename[1] = ':';
-#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
base::FilePath input_path(text);
PrepareStringForFileOps(input_path, &filename);
if (filename.length() > 0 && filename[0] == '~')
@@ -425,12 +425,12 @@ std::string SegmentURLInternal(std::string* text, url::Parsed* parts) {
return std::string(); // Nothing to segment.
std::string scheme;
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
int trimmed_length = static_cast<int>(trimmed.length());
if (url::DoesBeginWindowsDriveSpec(trimmed.data(), 0, trimmed_length) ||
url::DoesBeginUNCPath(trimmed.data(), 0, trimmed_length, true))
scheme = url::kFileScheme;
-#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
if (base::FilePath::IsSeparator(trimmed.data()[0]) ||
trimmed.data()[0] == '~')
scheme = url::kFileScheme;
@@ -673,9 +673,9 @@ GURL FixupRelativeFile(const base::FilePath& base_dir,
}
// Fall back on regular fixup for this input.
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
std::string text_utf8 = base::WideToUTF8(text.value());
-#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
std::string text_utf8 = text.value();
#endif
return FixupURL(text_utf8, std::string());
diff --git a/chromium/components/url_formatter/url_fixer_unittest.cc b/chromium/components/url_formatter/url_fixer_unittest.cc
index f2467fe7620..8cb0f76ad64 100644
--- a/chromium/components/url_formatter/url_fixer_unittest.cc
+++ b/chromium/components/url_formatter/url_fixer_unittest.cc
@@ -224,7 +224,7 @@ static const SegmentCase segment_cases[] = {
url::Component(), // query
url::Component(27, 3), // ref
},
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
{
"c:/notahost/path/file#ref", "file",
url::Component(), // scheme
@@ -236,7 +236,7 @@ static const SegmentCase segment_cases[] = {
url::Component(), // query
url::Component(22, 3), // ref
},
-#elif defined(OS_POSIX)
+#elif BUILDFLAG(IS_POSIX)
{
"~/notahost/path/file#ref", "file",
url::Component(), // scheme
@@ -354,13 +354,27 @@ struct FixupCase {
{"user:passwd@www.google.com:8080/", "user:passwd@www.google.com:8080/"},
// {"file:///c:/foo/bar%20baz.txt", "file:///C:/foo/bar%20baz.txt"},
// URLs which end with 0x85 (NEL in ISO-8859).
- {"http://foo.com/s?q=\xd0\x85", "http://foo.com/s?q=%D0%85"},
- {"http://foo.com/s?q=\xec\x97\x85", "http://foo.com/s?q=%EC%97%85"},
- {"http://foo.com/s?q=\xf0\x90\x80\x85", "http://foo.com/s?q=%F0%90%80%85"},
+ {"http://example.com/s?q=\xD0\x85", "http://example.com/s?q=%D0%85"},
+ {"http://example.com/s?q=\xEC\x97\x85", "http://example.com/s?q=%EC%97%85"},
+ {"http://example.com/s?q=\xF0\x90\x80\x85",
+ "http://example.com/s?q=%F0%90%80%85"},
// URLs which end with 0xA0 (non-break space in ISO-8859).
- {"http://foo.com/s?q=\xd0\xa0", "http://foo.com/s?q=%D0%A0"},
- {"http://foo.com/s?q=\xec\x97\xa0", "http://foo.com/s?q=%EC%97%A0"},
- {"http://foo.com/s?q=\xf0\x90\x80\xa0", "http://foo.com/s?q=%F0%90%80%A0"},
+ {"http://example.com/s?q=\xD0\xA0", "http://example.com/s?q=%D0%A0"},
+ {"http://example.com/s?q=\xEC\x97\xA0", "http://example.com/s?q=%EC%97%A0"},
+ {"http://example.com/s?q=\xF0\x90\x80\xA0",
+ "http://example.com/s?q=%F0%90%80%A0"},
+ // URLs containing Unicode non-characters.
+ {"http://example.com/s?q=\xEF\xB7\x90", // U+FDD0
+ "http://example.com/s?q=%EF%BF%BD"},
+ {"http://example.com/s?q=\xEF\xBF\xBE", // U+FFFE
+ "http://example.com/s?q=%EF%BF%BD"},
+ {"http://example.com/s?q=\xEF\xBF\xBF", // U+FFFF
+ "http://example.com/s?q=%EF%BF%BD"},
+ {"http://example.com/s?q=\xF4\x8F\xBF\xBE", // U+10FFFE
+ "http://example.com/s?q=%EF%BF%BD"},
+ {"http://example.com/s?q=\xF4\x8F\xBF\xBF", // U+10FFFF
+ "http://example.com/s?q=%EF%BF%BD"},
+
// URLs containing IPv6 literals.
{"[2001:db8::2]", "http://[2001:db8::2]/"},
{"[::]:80", "http://[::]/"},
@@ -382,10 +396,10 @@ struct FixupCase {
{"http;/www.google.com/", "http://www.google.com/"},
// Semicolon at start.
{";http://www.google.com/", "http://%3Bhttp//www.google.com/"},
- // Devtools scheme.
+ // DevTools scheme.
{"devtools://bundled/devtools/node.html",
"devtools://bundled/devtools/node.html"},
- // Devtools scheme with websocket query.
+ // DevTools scheme with websocket query.
{"devtools://bundled/devtools/inspector.html?ws=ws://localhost:9222/guid",
"devtools://bundled/devtools/inspector.html?ws=ws://localhost:9222/guid"},
// host:123 should be rewritten to http://host:123/, but only if the port
@@ -491,7 +505,7 @@ TEST(URLFixerTest, FixupFile) {
EXPECT_EQ(golden, fixedup);
// TODO(port): Make some equivalent tests for posix.
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// c|/foo\bar.txt -> file:///c:/foo/bar.txt (pipe allowed instead of colon)
std::string cur(base::WideToUTF8(original.value()));
EXPECT_EQ(':', cur[1]);
@@ -525,9 +539,9 @@ TEST(URLFixerTest, FixupFile) {
// {"file:///foo:/bar", "file://foo/bar"},
// {"file:/\\/server\\folder/file", "file://server/folder/file"},
};
-#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
#define HOME "/Users/"
#else
#define HOME "/home/"
diff --git a/chromium/components/url_formatter/url_formatter.cc b/chromium/components/url_formatter/url_formatter.cc
index efc24b744e6..db6a38b413e 100644
--- a/chromium/components/url_formatter/url_formatter.cc
+++ b/chromium/components/url_formatter/url_formatter.cc
@@ -24,6 +24,8 @@
#include "third_party/icu/source/common/unicode/utypes.h"
#include "url/gurl.h"
#include "url/third_party/mozilla/url_parse.h"
+#include "url/url_constants.h"
+#include "url/url_util.h"
namespace url_formatter {
@@ -464,6 +466,29 @@ ComponentResult IDNToUnicodeOneComponent(
return result;
}
+// Returns true iff URL-parsing `spec` would reveal that it has the
+// "view-source" scheme, and that parsing the spec minus that scheme also has
+// the "view-source" scheme.
+bool HasTwoViewSourceSchemes(base::StringPiece spec) {
+ static constexpr char kViewSource[] = "view-source";
+ url::Component scheme;
+ if (!url::FindAndCompareScheme(spec.data(),
+ base::checked_cast<int>(spec.size()),
+ kViewSource, &scheme)) {
+ return false;
+ }
+ // Consume the scheme.
+ spec.remove_prefix(scheme.begin + scheme.len);
+ // Consume the trailing colon. If it's not there, then `spec` didn't really
+ // have the first view-source scheme.
+ if (spec.empty() || spec[0] != ':')
+ return false;
+ spec.remove_prefix(1);
+
+ return url::FindAndCompareScheme(
+ spec.data(), base::checked_cast<int>(spec.size()), kViewSource, &scheme);
+}
+
} // namespace
const FormatUrlType kFormatUrlOmitNothing = 0;
@@ -526,16 +551,14 @@ std::u16string FormatUrlWithAdjustments(
else
*new_parsed = url::Parsed();
- // Special handling for view-source:. Don't use content::kViewSourceScheme
- // because this library shouldn't depend on chrome.
- const char kViewSource[] = "view-source";
- // Reject "view-source:view-source:..." to avoid deep recursion.
- const char kViewSourceTwice[] = "view-source:view-source:";
+ // Special handling for view-source:. Don't use content::kViewSourceScheme
+ // because this library shouldn't depend on chrome. Reject repeated
+ // view-source schemes to avoid recursion.
+ static constexpr base::StringPiece kViewSource = "view-source";
if (url.SchemeIs(kViewSource) &&
- !base::StartsWith(url.possibly_invalid_spec(), kViewSourceTwice,
- base::CompareCase::INSENSITIVE_ASCII)) {
- return FormatViewSourceUrl(url, format_types, unescape_rules,
- new_parsed, prefix_end, adjustments);
+ !HasTwoViewSourceSchemes(url.possibly_invalid_spec())) {
+ return FormatViewSourceUrl(url, format_types, unescape_rules, new_parsed,
+ prefix_end, adjustments);
}
// We handle both valid and invalid URLs (this will give us the spec
@@ -676,7 +699,7 @@ std::u16string FormatUrlWithAdjustments(
url.SchemeIs(url::kMailToScheme)
? new_parsed->scheme.len + 1 // +1 for :.
: new_parsed->scheme.len + 3; // +3 for ://.
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// Because there's an additional leading slash after the scheme for local
// files on Windows, we should remove it for URL display when eliding
// the scheme by offsetting by an additional character.
diff --git a/chromium/components/url_formatter/url_formatter_unittest.cc b/chromium/components/url_formatter/url_formatter_unittest.cc
index f4ce967d7cd..d50fe2134d8 100644
--- a/chromium/components/url_formatter/url_formatter_unittest.cc
+++ b/chromium/components/url_formatter/url_formatter_unittest.cc
@@ -187,7 +187,7 @@ TEST(UrlFormatterTest, FormatUrl) {
7},
// -------- omit file: --------
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
{"omit file on Windows", "file:///C:/Users/homedirname/folder/file.pdf/",
kFormatUrlOmitFileScheme, net::UnescapeRule::NORMAL,
L"C:/Users/homedirname/folder/file.pdf/", static_cast<size_t>(-1)},
@@ -248,7 +248,7 @@ TEST(UrlFormatterTest, FormatUrl) {
kFormatUrlOmitTrivialSubdomains | kFormatUrlTrimAfterHost,
net::UnescapeRule::NORMAL, L"view-source:https://www.google.com/foo",
20},
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
{"view-source should not omit file on Windows",
"view-source:file:///C:/Users/homedirname/folder/file.pdf/",
kFormatUrlOmitDefaults | kFormatUrlOmitFileScheme,
@@ -476,6 +476,26 @@ TEST(UrlFormatterTest, FormatUrlParsed) {
EXPECT_EQ(u"query", formatted.substr(parsed.query.begin, parsed.query.len));
EXPECT_EQ(u"ref", formatted.substr(parsed.ref.begin, parsed.ref.len));
+ // Repeated view-source separated by a space.
+ formatted = FormatUrl(
+ GURL(
+ "view-source: view-source:http://user:passwd@host:81/path?query#ref"),
+ kFormatUrlOmitUsernamePassword, net::UnescapeRule::NORMAL, &parsed,
+ nullptr, nullptr);
+ EXPECT_EQ(
+ u"view-source: view-source:http://user:passwd@host:81/path?query#ref",
+ formatted);
+ EXPECT_EQ(u"view-source",
+ formatted.substr(parsed.scheme.begin, parsed.scheme.len));
+ EXPECT_FALSE(parsed.username.is_valid());
+ EXPECT_FALSE(parsed.password.is_valid());
+ EXPECT_FALSE(parsed.host.is_valid());
+ EXPECT_FALSE(parsed.port.is_valid());
+ EXPECT_EQ(u" view-source:http://user:passwd@host:81/path",
+ formatted.substr(parsed.path.begin, parsed.path.len));
+ EXPECT_EQ(u"query", formatted.substr(parsed.query.begin, parsed.query.len));
+ EXPECT_EQ(u"ref", formatted.substr(parsed.ref.begin, parsed.ref.len));
+
// omit http case.
formatted = FormatUrl(GURL("http://host:8000/a?b=c#d"), kFormatUrlOmitHTTP,
net::UnescapeRule::NORMAL, &parsed, nullptr, nullptr);
diff --git a/chromium/components/url_matcher/BUILD.gn b/chromium/components/url_matcher/BUILD.gn
index f7c8a10643a..f1d627705dc 100644
--- a/chromium/components/url_matcher/BUILD.gn
+++ b/chromium/components/url_matcher/BUILD.gn
@@ -17,8 +17,8 @@ component("url_matcher") {
"url_matcher_export.h",
"url_matcher_factory.cc",
"url_matcher_factory.h",
- "url_matcher_helpers.cc",
- "url_matcher_helpers.h",
+ "url_util.cc",
+ "url_util.h",
]
defines = [ "URL_MATCHER_IMPLEMENTATION" ]
@@ -26,6 +26,9 @@ component("url_matcher") {
public_deps = [
"//base",
"//base/third_party/dynamic_annotations",
+ "//components/google/core/common",
+ "//components/url_formatter",
+ "//net",
"//third_party/re2",
"//url",
]
@@ -39,6 +42,7 @@ source_set("unit_tests") {
"substring_set_matcher_unittest.cc",
"url_matcher_factory_unittest.cc",
"url_matcher_unittest.cc",
+ "url_util_unittest.cc",
]
deps = [
":url_matcher",
diff --git a/chromium/components/url_matcher/DEPS b/chromium/components/url_matcher/DEPS
index 0de07bbaf08..802809a1509 100644
--- a/chromium/components/url_matcher/DEPS
+++ b/chromium/components/url_matcher/DEPS
@@ -1,3 +1,6 @@
include_rules = [
+ "+components/google/core/common",
+ "+components/url_formatter",
+ "+net/base",
"+third_party/re2",
]
diff --git a/chromium/components/url_matcher/url_matcher_factory.cc b/chromium/components/url_matcher/url_matcher_factory.cc
index d446f343062..0c94822b93c 100644
--- a/chromium/components/url_matcher/url_matcher_factory.cc
+++ b/chromium/components/url_matcher/url_matcher_factory.cc
@@ -14,12 +14,11 @@
#include "base/strings/stringprintf.h"
#include "base/values.h"
#include "components/url_matcher/url_matcher_constants.h"
-#include "components/url_matcher/url_matcher_helpers.h"
+#include "components/url_matcher/url_util.h"
#include "third_party/re2/src/re2/re2.h"
namespace url_matcher {
-namespace helpers = url_matcher_helpers;
namespace keys = url_matcher_constants;
namespace {
@@ -225,7 +224,7 @@ std::unique_ptr<URLMatcherSchemeFilter>
URLMatcherFactory::CreateURLMatcherScheme(const base::Value* value,
std::string* error) {
std::vector<std::string> schemas;
- if (!helpers::GetAsStringVector(value, &schemas)) {
+ if (!util::GetAsStringVector(value, &schemas)) {
*error = base::StringPrintf(kVectorOfStringsExpected, keys::kSchemesKey);
return nullptr;
}
@@ -248,13 +247,13 @@ std::unique_ptr<URLMatcherPortFilter> URLMatcherFactory::CreateURLMatcherPorts(
*error = kInvalidPortRanges;
return nullptr;
}
- base::Value::ConstListView value_list = value->GetList();
+ base::Value::ConstListView value_list = value->GetListDeprecated();
for (const auto& entry : value_list) {
if (entry.is_int()) {
ranges.push_back(URLMatcherPortFilter::CreateRange(entry.GetInt()));
} else if (entry.is_list()) {
- base::Value::ConstListView entry_list = entry.GetList();
+ base::Value::ConstListView entry_list = entry.GetListDeprecated();
if (entry_list.size() != 2u || !entry_list[0].is_int() ||
!entry_list[1].is_int()) {
*error = kInvalidPortRanges;
diff --git a/chromium/components/url_matcher/url_matcher_helpers.cc b/chromium/components/url_matcher/url_matcher_helpers.cc
deleted file mode 100644
index d21c8796333..00000000000
--- a/chromium/components/url_matcher/url_matcher_helpers.cc
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2013 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.
-
-#include "components/url_matcher/url_matcher_helpers.h"
-
-#include <stddef.h>
-
-#include "base/values.h"
-
-namespace url_matcher {
-namespace url_matcher_helpers {
-
-// Converts a ValueList |value| of strings into a vector. Returns true if
-// successful.
-bool GetAsStringVector(const base::Value* value,
- std::vector<std::string>* out) {
- if (!value->is_list())
- return false;
-
- for (const base::Value& item : value->GetList()) {
- if (!item.is_string())
- return false;
-
- out->push_back(item.GetString());
- }
- return true;
-}
-
-} // namespace url_matcher_helpers
-} // namespace url_matcher
diff --git a/chromium/components/url_matcher/url_matcher_helpers.h b/chromium/components/url_matcher/url_matcher_helpers.h
deleted file mode 100644
index 15aa0c5be1a..00000000000
--- a/chromium/components/url_matcher/url_matcher_helpers.h
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2013 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.
-
-// Helper functions used for URLMatcher and Declarative APIs.
-
-#ifndef COMPONENTS_URL_MATCHER_URL_MATCHER_HELPERS_H_
-#define COMPONENTS_URL_MATCHER_URL_MATCHER_HELPERS_H_
-
-#include <string>
-#include <vector>
-
-namespace base {
-class Value;
-}
-
-namespace url_matcher {
-namespace url_matcher_helpers {
-
-// Converts a ValueList |value| of strings into a vector. Returns true if
-// successful.
-bool GetAsStringVector(const base::Value* value, std::vector<std::string>* out);
-
-} // namespace url_matcher_helpers
-} // namespace url_matcher
-
-#endif // COMPONENTS_URL_MATCHER_URL_MATCHER_HELPERS_H_
diff --git a/chromium/components/url_matcher/url_util.cc b/chromium/components/url_matcher/url_util.cc
new file mode 100644
index 00000000000..af3a52abe4a
--- /dev/null
+++ b/chromium/components/url_matcher/url_util.cc
@@ -0,0 +1,495 @@
+// Copyright 2018 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.
+
+#include "components/url_matcher/url_util.h"
+
+#include <memory>
+#include <string>
+
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/no_destructor.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "components/google/core/common/google_util.h"
+#include "components/url_formatter/url_fixer.h"
+#include "components/url_matcher/url_matcher.h"
+#include "net/base/escape.h"
+#include "net/base/filename_util.h"
+#include "net/base/url_util.h"
+#include "third_party/re2/src/re2/re2.h"
+#include "url/gurl.h"
+
+using url_matcher::URLMatcher;
+using url_matcher::URLMatcherCondition;
+using url_matcher::URLMatcherConditionFactory;
+using url_matcher::URLMatcherConditionSet;
+using url_matcher::URLMatcherPortFilter;
+using url_matcher::URLMatcherSchemeFilter;
+using url_matcher::URLQueryElementMatcherCondition;
+
+namespace url_matcher {
+namespace util {
+
+namespace {
+
+// Host/regex pattern for Google AMP Cache URLs.
+// See https://developers.google.com/amp/cache/overview#amp-cache-url-format
+// for a definition of the format of AMP Cache URLs.
+const char kGoogleAmpCacheHost[] = "cdn.ampproject.org";
+const char kGoogleAmpCachePathPattern[] = "/[a-z]/(s/)?(.*)";
+
+// Regex pattern for the path of Google AMP Viewer URLs.
+const char kGoogleAmpViewerPathPattern[] = "/amp/(s/)?(.*)";
+
+// Host, path prefix, and query regex pattern for Google web cache URLs.
+const char kGoogleWebCacheHost[] = "webcache.googleusercontent.com";
+const char kGoogleWebCachePathPrefix[] = "/search";
+const char kGoogleWebCacheQueryPattern[] =
+ "cache:(.{12}:)?(https?://)?([^ :]*)( [^:]*)?";
+
+const char kGoogleTranslateSubdomain[] = "translate.";
+const char kAlternateGoogleTranslateHost[] = "translate.googleusercontent.com";
+
+// Maximum filters allowed. Filters over this index are ignored.
+const size_t kMaxFiltersAllowed = 1000;
+
+// Returns a full URL using either "http" or "https" as the scheme.
+GURL BuildURL(bool is_https, const std::string& host_and_path) {
+ std::string scheme = is_https ? url::kHttpsScheme : url::kHttpScheme;
+ return GURL(scheme + "://" + host_and_path);
+}
+
+void ProcessQueryToConditions(
+ url_matcher::URLMatcherConditionFactory* condition_factory,
+ const std::string& query,
+ bool allow,
+ std::set<URLQueryElementMatcherCondition>* query_conditions) {
+ url::Component query_left = url::MakeRange(0, query.length());
+ url::Component key;
+ url::Component value;
+ // Depending on the filter type being block-list or allow-list, the matcher
+ // choose any or every match. The idea is a URL should be blocked if
+ // there is any occurrence of the key value pair. It should be allowed
+ // only if every occurrence of the key is followed by the value. This avoids
+ // situations such as a user appending an allowed video parameter in the
+ // end of the query and watching a video of their choice (the last parameter
+ // is ignored by some web servers like youtube's).
+ URLQueryElementMatcherCondition::Type match_type =
+ allow ? URLQueryElementMatcherCondition::MATCH_ALL
+ : URLQueryElementMatcherCondition::MATCH_ANY;
+
+ while (ExtractQueryKeyValue(query.data(), &query_left, &key, &value)) {
+ URLQueryElementMatcherCondition::QueryElementType query_element_type =
+ value.len ? URLQueryElementMatcherCondition::ELEMENT_TYPE_KEY_VALUE
+ : URLQueryElementMatcherCondition::ELEMENT_TYPE_KEY;
+ URLQueryElementMatcherCondition::QueryValueMatchType query_value_match_type;
+ if (!value.len && key.len && query[key.end() - 1] == '*') {
+ --key.len;
+ query_value_match_type =
+ URLQueryElementMatcherCondition::QUERY_VALUE_MATCH_PREFIX;
+ } else if (value.len && query[value.end() - 1] == '*') {
+ --value.len;
+ query_value_match_type =
+ URLQueryElementMatcherCondition::QUERY_VALUE_MATCH_PREFIX;
+ } else {
+ query_value_match_type =
+ URLQueryElementMatcherCondition::QUERY_VALUE_MATCH_EXACT;
+ }
+ query_conditions->insert(URLQueryElementMatcherCondition(
+ query.substr(key.begin, key.len), query.substr(value.begin, value.len),
+ query_value_match_type, query_element_type, match_type,
+ condition_factory));
+ }
+}
+
+// Helper class for testing the URL against precompiled regexes. This is a
+// singleton so the cached regexes are only created once.
+class EmbeddedURLExtractor {
+ public:
+ EmbeddedURLExtractor(const EmbeddedURLExtractor&) = delete;
+ EmbeddedURLExtractor& operator=(const EmbeddedURLExtractor&) = delete;
+
+ static EmbeddedURLExtractor* GetInstance() {
+ static base::NoDestructor<EmbeddedURLExtractor> instance;
+ return instance.get();
+ }
+
+ // Implements url_filter::GetEmbeddedURL().
+ GURL GetEmbeddedURL(const GURL& url) {
+ // Check for "*.cdn.ampproject.org" URLs.
+ if (url.DomainIs(kGoogleAmpCacheHost)) {
+ std::string s;
+ std::string embedded;
+ if (re2::RE2::FullMatch(url.path(), google_amp_cache_path_regex_, &s,
+ &embedded)) {
+ if (url.has_query())
+ embedded += "?" + url.query();
+ return BuildURL(!s.empty(), embedded);
+ }
+ }
+
+ // Check for "www.google.TLD/amp/" URLs.
+ if (google_util::IsGoogleDomainUrl(
+ url, google_util::DISALLOW_SUBDOMAIN,
+ google_util::DISALLOW_NON_STANDARD_PORTS)) {
+ std::string s;
+ std::string embedded;
+ if (re2::RE2::FullMatch(url.path(), google_amp_viewer_path_regex_, &s,
+ &embedded)) {
+ // The embedded URL may be percent-encoded. Undo that.
+ embedded = net::UnescapeBinaryURLComponent(embedded);
+ return BuildURL(!s.empty(), embedded);
+ }
+ }
+
+ // Check for Google web cache URLs
+ // ("webcache.googleusercontent.com/search?q=cache:...").
+ std::string query;
+ if (url.host_piece() == kGoogleWebCacheHost &&
+ base::StartsWith(url.path_piece(), kGoogleWebCachePathPrefix) &&
+ net::GetValueForKeyInQuery(url, "q", &query)) {
+ std::string fingerprint;
+ std::string scheme;
+ std::string embedded;
+ if (re2::RE2::FullMatch(query, google_web_cache_query_regex_,
+ &fingerprint, &scheme, &embedded)) {
+ return BuildURL(scheme == "https://", embedded);
+ }
+ }
+
+ // Check for Google translate URLs ("translate.google.TLD/...?...&u=URL" or
+ // "translate.googleusercontent.com/...?...&u=URL").
+ bool is_translate = false;
+ if (base::StartsWith(url.host_piece(), kGoogleTranslateSubdomain)) {
+ // Remove the "translate." prefix.
+ GURL::Replacements replace;
+ replace.SetHostStr(
+ url.host_piece().substr(strlen(kGoogleTranslateSubdomain)));
+ GURL trimmed = url.ReplaceComponents(replace);
+ // Check that the remainder is a Google URL. Note: IsGoogleDomainUrl
+ // checks for [www.]google.TLD, but we don't want the "www.", so
+ // explicitly exclude that.
+ // TODO(treib,pam): Instead of excluding "www." manually, teach
+ // IsGoogleDomainUrl a mode that doesn't allow it.
+ is_translate = google_util::IsGoogleDomainUrl(
+ trimmed, google_util::DISALLOW_SUBDOMAIN,
+ google_util::DISALLOW_NON_STANDARD_PORTS) &&
+ !base::StartsWith(trimmed.host_piece(), "www.");
+ }
+ bool is_alternate_translate =
+ url.host_piece() == kAlternateGoogleTranslateHost;
+ if (is_translate || is_alternate_translate) {
+ std::string embedded;
+ if (net::GetValueForKeyInQuery(url, "u", &embedded)) {
+ // The embedded URL may or may not include a scheme. Fix it if
+ // necessary.
+ return url_formatter::FixupURL(embedded, /*desired_tld=*/std::string());
+ }
+ }
+
+ return GURL();
+ }
+
+ private:
+ friend class base::NoDestructor<EmbeddedURLExtractor>;
+
+ EmbeddedURLExtractor()
+ : google_amp_cache_path_regex_(kGoogleAmpCachePathPattern),
+ google_amp_viewer_path_regex_(kGoogleAmpViewerPathPattern),
+ google_web_cache_query_regex_(kGoogleWebCacheQueryPattern) {
+ DCHECK(google_amp_cache_path_regex_.ok());
+ DCHECK(google_amp_viewer_path_regex_.ok());
+ DCHECK(google_web_cache_query_regex_.ok());
+ }
+
+ ~EmbeddedURLExtractor() = default;
+
+ const re2::RE2 google_amp_cache_path_regex_;
+ const re2::RE2 google_amp_viewer_path_regex_;
+ const re2::RE2 google_web_cache_query_regex_;
+};
+
+} // namespace
+
+// Converts a ValueList |value| of strings into a vector. Returns true if
+// successful.
+bool GetAsStringVector(const base::Value* value,
+ std::vector<std::string>* out) {
+ if (!value->is_list())
+ return false;
+
+ for (const base::Value& item : value->GetListDeprecated()) {
+ if (!item.is_string())
+ return false;
+
+ out->push_back(item.GetString());
+ }
+ return true;
+}
+
+GURL Normalize(const GURL& url) {
+ GURL normalized_url = url;
+ GURL::Replacements replacements;
+ // Strip username, password, query, and ref.
+ replacements.ClearUsername();
+ replacements.ClearPassword();
+ replacements.ClearQuery();
+ replacements.ClearRef();
+ return url.ReplaceComponents(replacements);
+}
+
+GURL GetEmbeddedURL(const GURL& url) {
+ return EmbeddedURLExtractor::GetInstance()->GetEmbeddedURL(url);
+}
+
+size_t GetMaxFiltersAllowed() {
+ return kMaxFiltersAllowed;
+}
+
+FilterComponents::FilterComponents() = default;
+FilterComponents::~FilterComponents() = default;
+FilterComponents::FilterComponents(FilterComponents&&) = default;
+
+bool FilterComponents::IsWildcard() const {
+ return host.empty() && scheme.empty() && path.empty() && query.empty() &&
+ port == 0 && number_of_url_matching_conditions == 0 &&
+ match_subdomains;
+}
+
+scoped_refptr<URLMatcherConditionSet> CreateConditionSet(
+ URLMatcher* url_matcher,
+ int id,
+ const std::string& scheme,
+ const std::string& host,
+ bool match_subdomains,
+ uint16_t port,
+ const std::string& path,
+ const std::string& query,
+ bool allow) {
+ URLMatcherConditionFactory* condition_factory =
+ url_matcher->condition_factory();
+ std::set<URLMatcherCondition> conditions;
+ conditions.insert(
+ match_subdomains
+ ? condition_factory->CreateHostSuffixPathPrefixCondition(host, path)
+ : condition_factory->CreateHostEqualsPathPrefixCondition(host, path));
+
+ std::set<URLQueryElementMatcherCondition> query_conditions;
+ if (!query.empty()) {
+ ProcessQueryToConditions(condition_factory, query, allow,
+ &query_conditions);
+ }
+
+ std::unique_ptr<URLMatcherSchemeFilter> scheme_filter;
+ if (!scheme.empty())
+ scheme_filter = std::make_unique<URLMatcherSchemeFilter>(scheme);
+
+ std::unique_ptr<URLMatcherPortFilter> port_filter;
+ if (port != 0) {
+ std::vector<URLMatcherPortFilter::Range> ranges;
+ ranges.push_back(URLMatcherPortFilter::CreateRange(port));
+ port_filter = std::make_unique<URLMatcherPortFilter>(ranges);
+ }
+
+ return base::MakeRefCounted<URLMatcherConditionSet>(
+ id, conditions, query_conditions, std::move(scheme_filter),
+ std::move(port_filter));
+}
+
+bool FilterToComponents(const std::string& filter,
+ std::string* scheme,
+ std::string* host,
+ bool* match_subdomains,
+ uint16_t* port,
+ std::string* path,
+ std::string* query) {
+ DCHECK(scheme);
+ DCHECK(host);
+ DCHECK(match_subdomains);
+ DCHECK(port);
+ DCHECK(path);
+ DCHECK(query);
+ url::Parsed parsed;
+ std::string lc_filter = base::ToLowerASCII(filter);
+ const std::string url_scheme = url_formatter::SegmentURL(filter, &parsed);
+
+ // Check if it's a scheme wildcard pattern. We support both versions
+ // (scheme:* and scheme://*) the later being consistent with old filter
+ // definitions.
+ if (lc_filter == url_scheme + ":*" || lc_filter == url_scheme + "://*") {
+ scheme->assign(url_scheme);
+ host->clear();
+ *match_subdomains = true;
+ *port = 0;
+ path->clear();
+ query->clear();
+ return true;
+ }
+
+ if (url_scheme == url::kFileScheme) {
+ base::FilePath file_path;
+ if (!net::FileURLToFilePath(GURL(filter), &file_path))
+ return false;
+
+ *scheme = url::kFileScheme;
+ host->clear();
+ *match_subdomains = true;
+ *port = 0;
+ *path = file_path.AsUTF8Unsafe();
+#if defined(FILE_PATH_USES_WIN_SEPARATORS)
+ // Separators have to be canonicalized on Windows.
+ std::replace(path->begin(), path->end(), '\\', '/');
+ *path = "/" + *path;
+#endif
+ return true;
+ }
+
+ // According to documentation host can't be empty.
+ if (!parsed.host.is_nonempty())
+ return false;
+
+ if (parsed.scheme.is_nonempty())
+ scheme->assign(url_scheme);
+ else
+ scheme->clear();
+
+ host->assign(filter, parsed.host.begin, parsed.host.len);
+ *host = base::ToLowerASCII(*host);
+ // Special '*' host, matches all hosts.
+ if (*host == "*") {
+ host->clear();
+ *match_subdomains = true;
+ } else if (host->at(0) == '.') {
+ // A leading dot in the pattern syntax means that we don't want to match
+ // subdomains.
+ host->erase(0, 1);
+ *match_subdomains = false;
+ } else {
+ url::RawCanonOutputT<char> output;
+ url::CanonHostInfo host_info;
+ url::CanonicalizeHostVerbose(filter.c_str(), parsed.host, &output,
+ &host_info);
+ if (host_info.family == url::CanonHostInfo::NEUTRAL) {
+ // We want to match subdomains. Add a dot in front to make sure we only
+ // match at domain component boundaries.
+ *host = "." + *host;
+ *match_subdomains = true;
+ } else {
+ *match_subdomains = false;
+ }
+ }
+
+ if (parsed.port.is_nonempty()) {
+ int int_port;
+ if (!base::StringToInt(filter.substr(parsed.port.begin, parsed.port.len),
+ &int_port)) {
+ return false;
+ }
+ if (int_port <= 0 || int_port > std::numeric_limits<uint16_t>::max())
+ return false;
+ *port = int_port;
+ } else {
+ // Match any port.
+ *port = 0;
+ }
+
+ if (parsed.path.is_nonempty())
+ path->assign(filter, parsed.path.begin, parsed.path.len);
+ else
+ path->clear();
+
+ if (parsed.query.is_nonempty())
+ query->assign(filter, parsed.query.begin, parsed.query.len);
+ else
+ query->clear();
+
+ return true;
+}
+
+void AddFilters(URLMatcher* matcher,
+ bool allow,
+ URLMatcherConditionSet::ID* id,
+ const base::ListValue* patterns,
+ std::map<url_matcher::URLMatcherConditionSet::ID,
+ url_matcher::util::FilterComponents>* filters) {
+ URLMatcherConditionSet::Vector all_conditions;
+ base::Value::ConstListView patterns_list = patterns->GetListDeprecated();
+ size_t size = std::min(kMaxFiltersAllowed, patterns_list.size());
+ scoped_refptr<URLMatcherConditionSet> condition_set;
+ for (size_t i = 0; i < size; ++i) {
+ std::string pattern;
+ if (patterns_list[i].is_string()) {
+ pattern = patterns_list[i].GetString();
+ } else {
+ DCHECK(false);
+ }
+ FilterComponents components;
+ components.allow = allow;
+ if (!FilterToComponents(pattern, &components.scheme, &components.host,
+ &components.match_subdomains, &components.port,
+ &components.path, &components.query)) {
+ LOG(ERROR) << "Invalid pattern " << pattern;
+ continue;
+ }
+ condition_set =
+ CreateConditionSet(matcher, ++(*id), components.scheme, components.host,
+ components.match_subdomains, components.port,
+ components.path, components.query, allow);
+ if (filters) {
+ components.number_of_url_matching_conditions =
+ condition_set->query_conditions().size();
+ (*filters)[*id] = std::move(components);
+ }
+ all_conditions.push_back(std::move(condition_set));
+ }
+ matcher->AddConditionSets(all_conditions);
+}
+
+void AddFilters(URLMatcher* matcher,
+ bool allow,
+ URLMatcherConditionSet::ID* id,
+ const std::vector<std::string>& patterns,
+ std::map<url_matcher::URLMatcherConditionSet::ID,
+ url_matcher::util::FilterComponents>* filters) {
+ URLMatcherConditionSet::Vector all_conditions;
+ size_t size = std::min(kMaxFiltersAllowed, patterns.size());
+ scoped_refptr<URLMatcherConditionSet> condition_set;
+ for (size_t i = 0; i < size; ++i) {
+ FilterComponents components;
+ components.allow = allow;
+ if (!FilterToComponents(patterns[i], &components.scheme, &components.host,
+ &components.match_subdomains, &components.port,
+ &components.path, &components.query)) {
+ LOG(ERROR) << "Invalid pattern " << patterns[i];
+ continue;
+ }
+ condition_set =
+ CreateConditionSet(matcher, ++(*id), components.scheme, components.host,
+ components.match_subdomains, components.port,
+ components.path, components.query, allow);
+ if (filters) {
+ components.number_of_url_matching_conditions =
+ condition_set->query_conditions().size();
+ (*filters)[*id] = std::move(components);
+ }
+ all_conditions.push_back(std::move(condition_set));
+ }
+ matcher->AddConditionSets(all_conditions);
+}
+
+void AddAllowFilters(url_matcher::URLMatcher* matcher,
+ const base::ListValue* patterns) {
+ url_matcher::URLMatcherConditionSet::ID id(0);
+ AddFilters(matcher, true, &id, patterns);
+}
+
+void AddAllowFilters(url_matcher::URLMatcher* matcher,
+ const std::vector<std::string>& patterns) {
+ url_matcher::URLMatcherConditionSet::ID id(0);
+ AddFilters(matcher, true, &id, patterns);
+}
+
+} // namespace util
+} // namespace url_matcher
diff --git a/chromium/components/url_matcher/url_util.h b/chromium/components/url_matcher/url_util.h
new file mode 100644
index 00000000000..868f2eac54b
--- /dev/null
+++ b/chromium/components/url_matcher/url_util.h
@@ -0,0 +1,133 @@
+// Copyright 2018 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.
+
+#ifndef COMPONENTS_URL_MATCHER_URL_UTIL_H_
+#define COMPONENTS_URL_MATCHER_URL_UTIL_H_
+
+#include "base/memory/scoped_refptr.h"
+#include "base/values.h"
+#include "components/url_matcher/url_matcher.h"
+#include "components/url_matcher/url_matcher_export.h"
+
+class GURL;
+
+namespace url_matcher {
+namespace util {
+
+// Converts a ValueList `value` of strings into a vector. Returns true if
+// successful.
+bool GetAsStringVector(const base::Value* value, std::vector<std::string>* out);
+
+// Normalizes a URL for matching purposes.
+URL_MATCHER_EXPORT GURL Normalize(const GURL& url);
+
+// Helper function to extract the underlying URL wrapped by services such as
+// Google AMP or Google Translate. Returns an empty GURL if `url` doesn't match
+// a known format.
+URL_MATCHER_EXPORT GURL GetEmbeddedURL(const GURL& url);
+
+// Utility struct used to represent a url filter scheme into its components.
+struct URL_MATCHER_EXPORT FilterComponents {
+ FilterComponents();
+ FilterComponents(const FilterComponents&) = delete;
+ FilterComponents(FilterComponents&&);
+ FilterComponents& operator=(const FilterComponents&) = delete;
+ FilterComponents& operator=(FilterComponents&&) = default;
+
+ ~FilterComponents();
+
+ // Returns true if `this` represents the "*" filter.
+ bool IsWildcard() const;
+ std::string scheme;
+ std::string host;
+ uint16_t port = 0;
+ std::string path;
+ std::string query;
+ // Number of conditions that a url needs to match it to be considered a match
+ // for this filter.
+ int number_of_url_matching_conditions = 0;
+ bool match_subdomains = true;
+ bool allow = true;
+};
+
+// Creates a condition set that can be used with the `url_matcher`. `id` needs
+// to be a unique number that will be returned by the `url_matcher` if the URL
+// matches that condition set. `allow` indicates if it is an allow-list (true)
+// or block-list (false) filter.
+URL_MATCHER_EXPORT scoped_refptr<url_matcher::URLMatcherConditionSet>
+CreateConditionSet(url_matcher::URLMatcher* url_matcher,
+ url_matcher::URLMatcherConditionSet::ID id,
+ const std::string& scheme,
+ const std::string& host,
+ bool match_subdomains,
+ uint16_t port,
+ const std::string& path,
+ const std::string& query,
+ bool allow);
+
+// Splits a URL filter into its components. A GURL isn't used because these
+// can be invalid URLs e.g. "google.com".
+// Returns false if the URL couldn't be parsed. In case false is returned,
+// the values of output parameters are undefined.
+// The `filter` should have the format described at
+// http://www.chromium.org/administrators/url-blocklist-filter-format and
+// accepts wildcards. The `host` is preprocessed so it can be passed to
+// URLMatcher for the appropriate condition. The optional username and password
+// are ignored. `match_subdomains` specifies whether the filter should include
+// subdomains of the hostname (if it is one.) `port` is 0 if none is explicitly
+// defined. `path` does not include query parameters. `query` contains the query
+// parameters ('?' not included). All arguments are mandatory.
+URL_MATCHER_EXPORT bool FilterToComponents(const std::string& filter,
+ std::string* scheme,
+ std::string* host,
+ bool* match_subdomains,
+ uint16_t* port,
+ std::string* path,
+ std::string* query);
+
+// Adds the filters in `patterns` to `url_matcher` as a ConditionSet::Vector.
+// `matcher` is the URLMatcher where filters are added.
+// `allow` specifies whether the filter accepts or blocks the macthed urls.
+// `id` is the id of given to the filter being added.
+// `patterns` is a list of url schemes following the format described
+// http://www.chromium.org/administrators/url-blocklist-filter-format and
+// accepts wildcards.
+// `filters` is an optional map of id to FilterComponent where the generated
+// FilterComponent will be added.
+URL_MATCHER_EXPORT void AddFilters(
+ url_matcher::URLMatcher* matcher,
+ bool allow,
+ url_matcher::URLMatcherConditionSet::ID* id,
+ const base::ListValue* patterns,
+ std::map<url_matcher::URLMatcherConditionSet::ID,
+ url_matcher::util::FilterComponents>* filters = nullptr);
+
+// Adds the filters in `patterns` to `url_matcher` as a ConditionSet::Vector.
+// `matcher` is the URLMatcher where filters are added.
+// `allow` specifies whether the filter accepts or blocks the macthed urls.
+// `id` is the id of given to the filter being added.
+// `patterns` is a list of url schemes following the format described
+// http://www.chromium.org/administrators/url-blocklist-filter-format and
+// accepts wildcards.
+// `filters` is an optional map of id to FilterComponent where the generated
+// FilterComponent will be added.
+URL_MATCHER_EXPORT void AddFilters(
+ url_matcher::URLMatcher* matcher,
+ bool allow,
+ url_matcher::URLMatcherConditionSet::ID* id,
+ const std::vector<std::string>& patterns,
+ std::map<url_matcher::URLMatcherConditionSet::ID,
+ url_matcher::util::FilterComponents>* filters = nullptr);
+
+URL_MATCHER_EXPORT void AddAllowFilters(url_matcher::URLMatcher* matcher,
+ const base::ListValue* patterns);
+
+URL_MATCHER_EXPORT void AddAllowFilters(
+ url_matcher::URLMatcher* matcher,
+ const std::vector<std::string>& patterns);
+
+} // namespace util
+} // namespace url_matcher
+
+#endif // COMPONENTS_URL_MATCHER_URL_UTIL_H_
diff --git a/chromium/components/url_matcher/url_util_unittest.cc b/chromium/components/url_matcher/url_util_unittest.cc
new file mode 100644
index 00000000000..4849019db25
--- /dev/null
+++ b/chromium/components/url_matcher/url_util_unittest.cc
@@ -0,0 +1,676 @@
+// Copyright 2018 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.
+
+#include "components/url_matcher/url_util.h"
+#include <memory>
+
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace url_matcher {
+namespace util {
+
+namespace {
+
+GURL GetEmbeddedURL(const std::string& url) {
+ return url_matcher::util::GetEmbeddedURL(GURL(url));
+}
+
+// Parameters for the FilterToComponents test.
+struct FilterTestParams {
+ public:
+ FilterTestParams(const std::string& filter,
+ const std::string& scheme,
+ const std::string& host,
+ bool match_subdomains,
+ uint16_t port,
+ const std::string& path)
+ : filter_(filter),
+ scheme_(scheme),
+ host_(host),
+ match_subdomains_(match_subdomains),
+ port_(port),
+ path_(path) {}
+
+ FilterTestParams(const FilterTestParams& params)
+ : filter_(params.filter_),
+ scheme_(params.scheme_),
+ host_(params.host_),
+ match_subdomains_(params.match_subdomains_),
+ port_(params.port_),
+ path_(params.path_) {}
+
+ const FilterTestParams& operator=(const FilterTestParams& params) {
+ filter_ = params.filter_;
+ scheme_ = params.scheme_;
+ host_ = params.host_;
+ match_subdomains_ = params.match_subdomains_;
+ port_ = params.port_;
+ path_ = params.path_;
+ return *this;
+ }
+
+ const std::string& filter() const { return filter_; }
+ const std::string& scheme() const { return scheme_; }
+ const std::string& host() const { return host_; }
+ bool match_subdomains() const { return match_subdomains_; }
+ uint16_t port() const { return port_; }
+ const std::string& path() const { return path_; }
+
+ private:
+ std::string filter_;
+ std::string scheme_;
+ std::string host_;
+ bool match_subdomains_;
+ uint16_t port_;
+ std::string path_;
+};
+
+// Prints better debug information for Valgrind. Without this function, a
+// generic one will print the raw bytes in FilterTestParams, which due to some
+// likely padding will access uninitialized memory.
+void PrintTo(const FilterTestParams& params, std::ostream* os) {
+ *os << params.filter();
+}
+
+bool MatchFilters(const std::vector<std::string>& patterns,
+ const std::string& url) {
+ // Add the pattern to the matcher.
+ URLMatcher matcher;
+ base::Value list(base::Value::Type::LIST);
+ for (const auto& pattern : patterns)
+ list.Append(pattern);
+ AddAllowFilters(&matcher, &base::Value::AsListValue(list));
+ return !matcher.MatchURL(GURL(url)).empty();
+}
+
+class FilterToComponentsTest : public testing::TestWithParam<FilterTestParams> {
+ public:
+ FilterToComponentsTest() = default;
+ FilterToComponentsTest(const FilterToComponentsTest&) = delete;
+ FilterToComponentsTest& operator=(const FilterToComponentsTest&) = delete;
+};
+
+class OnlyWildcardTest
+ : public testing::TestWithParam<std::tuple<std::string /* scheme */,
+ std::string /* opt_host */,
+ std::string /* port */,
+ std::string /* path */,
+ std::string /* query*/>> {
+ public:
+ OnlyWildcardTest() = default;
+ OnlyWildcardTest(const OnlyWildcardTest&) = delete;
+ OnlyWildcardTest& operator=(const OnlyWildcardTest&) = delete;
+};
+
+} // namespace
+
+TEST(URLUtilTest, Normalize) {
+ // Username is cleared.
+ EXPECT_EQ(Normalize(GURL("http://dino@example/foo")),
+ GURL("http://example/foo"));
+
+ // Username and password are cleared.
+ EXPECT_EQ(Normalize(GURL("http://dino:hunter2@example/")),
+ GURL("http://example/"));
+
+ // Query string is cleared.
+ EXPECT_EQ(Normalize(GURL("http://example.com/foo?widgetId=42")),
+ GURL("http://example.com/foo"));
+ EXPECT_EQ(Normalize(GURL("https://example.com/?widgetId=42&frobinate=true")),
+ GURL("https://example.com/"));
+
+ // Ref is cleared.
+ EXPECT_EQ(Normalize(GURL("http://example.com/foo#widgetSection")),
+ GURL("http://example.com/foo"));
+
+ // Port is NOT cleared.
+ EXPECT_EQ(Normalize(GURL("http://example.com:443/")),
+ GURL("http://example.com:443/"));
+
+ // All together now.
+ EXPECT_EQ(
+ Normalize(GURL("https://dino:hunter2@example.com:443/foo?widgetId=42")),
+ GURL("https://example.com:443/foo"));
+}
+
+TEST(URLUtilTest, GetEmbeddedURLAmpCache) {
+ // Base case.
+ EXPECT_EQ(GURL("http://example.com"),
+ GetEmbeddedURL("https://cdn.ampproject.org/c/example.com"));
+ // "s/" means "use https".
+ EXPECT_EQ(GURL("https://example.com"),
+ GetEmbeddedURL("https://cdn.ampproject.org/c/s/example.com"));
+ // With path and query. Fragment is not extracted.
+ EXPECT_EQ(GURL("https://example.com/path/to/file.html?q=asdf"),
+ GetEmbeddedURL("https://cdn.ampproject.org/c/s/example.com/path/to/"
+ "file.html?q=asdf#baz"));
+ // Publish subdomain can be included but doesn't affect embedded URL.
+ EXPECT_EQ(
+ GURL("http://example.com"),
+ GetEmbeddedURL("https://example-com.cdn.ampproject.org/c/example.com"));
+ EXPECT_EQ(
+ GURL("http://example.com"),
+ GetEmbeddedURL("https://example-org.cdn.ampproject.org/c/example.com"));
+
+ // Different host is not supported.
+ EXPECT_EQ(GURL(), GetEmbeddedURL("https://www.ampproject.org/c/example.com"));
+ // Different TLD is not supported.
+ EXPECT_EQ(GURL(), GetEmbeddedURL("https://cdn.ampproject.com/c/example.com"));
+ // Content type ("c/") is missing.
+ EXPECT_EQ(GURL(), GetEmbeddedURL("https://cdn.ampproject.org/example.com"));
+ // Content type is mis-formatted, must be a single character.
+ EXPECT_EQ(GURL(),
+ GetEmbeddedURL("https://cdn.ampproject.org/cd/example.com"));
+}
+
+TEST(URLUtilTest, GetEmbeddedURLGoogleAmpViewer) {
+ // Base case.
+ EXPECT_EQ(GURL("http://example.com"),
+ GetEmbeddedURL("https://www.google.com/amp/example.com"));
+ // "s/" means "use https".
+ EXPECT_EQ(GURL("https://example.com"),
+ GetEmbeddedURL("https://www.google.com/amp/s/example.com"));
+ // Different Google TLDs are supported.
+ EXPECT_EQ(GURL("http://example.com"),
+ GetEmbeddedURL("https://www.google.de/amp/example.com"));
+ EXPECT_EQ(GURL("http://example.com"),
+ GetEmbeddedURL("https://www.google.co.uk/amp/example.com"));
+ // With path.
+ EXPECT_EQ(GURL("http://example.com/path"),
+ GetEmbeddedURL("https://www.google.com/amp/example.com/path"));
+ // Query is *not* part of the embedded URL.
+ EXPECT_EQ(
+ GURL("http://example.com/path"),
+ GetEmbeddedURL("https://www.google.com/amp/example.com/path?q=baz"));
+ // Query and fragment in percent-encoded form *are* part of the embedded URL.
+ EXPECT_EQ(
+ GURL("http://example.com/path?q=foo#bar"),
+ GetEmbeddedURL(
+ "https://www.google.com/amp/example.com/path%3fq=foo%23bar?q=baz"));
+ // "/" may also be percent-encoded.
+ EXPECT_EQ(GURL("http://example.com/path?q=foo#bar"),
+ GetEmbeddedURL("https://www.google.com/amp/"
+ "example.com%2fpath%3fq=foo%23bar?q=baz"));
+
+ // Missing "amp/".
+ EXPECT_EQ(GURL(), GetEmbeddedURL("https://www.google.com/example.com"));
+ // Path component before the "amp/".
+ EXPECT_EQ(GURL(),
+ GetEmbeddedURL("https://www.google.com/foo/amp/example.com"));
+ // Different host.
+ EXPECT_EQ(GURL(), GetEmbeddedURL("https://www.other.com/amp/example.com"));
+ // Different subdomain.
+ EXPECT_EQ(GURL(), GetEmbeddedURL("https://mail.google.com/amp/example.com"));
+ // Invalid TLD.
+ EXPECT_EQ(GURL(), GetEmbeddedURL("https://www.google.nope/amp/example.com"));
+
+ // Valid TLD that is not considered safe to display to the user by
+ // UnescapeURLComponent(). Note that when UTF-8 characters appear in a domain
+ // name, as is the case here, they're replaced by equivalent punycode by the
+ // GURL constructor.
+ EXPECT_EQ(GURL("http://www.xn--iv8h.com/"),
+ GetEmbeddedURL("https://www.google.com/amp/www.%F0%9F%94%8F.com/"));
+ // Invalid UTF-8 characters.
+ EXPECT_EQ(GURL("http://example.com/%81%82%83"),
+ GetEmbeddedURL("https://www.google.com/amp/example.com/%81%82%83"));
+}
+
+TEST(URLUtilTest, GetEmbeddedURLGoogleWebCache) {
+ // Base case.
+ EXPECT_EQ(GURL("http://example.com"),
+ GetEmbeddedURL("https://webcache.googleusercontent.com/"
+ "search?q=cache:ABCDEFGHI-JK:example.com/"));
+ // With search query.
+ EXPECT_EQ(
+ GURL("http://example.com"),
+ GetEmbeddedURL("https://webcache.googleusercontent.com/"
+ "search?q=cache:ABCDEFGHI-JK:example.com/+search_query"));
+ // Without fingerprint.
+ EXPECT_EQ(GURL("http://example.com"),
+ GetEmbeddedURL("https://webcache.googleusercontent.com/"
+ "search?q=cache:example.com/"));
+ // With search query, without fingerprint.
+ EXPECT_EQ(GURL("http://example.com"),
+ GetEmbeddedURL("https://webcache.googleusercontent.com/"
+ "search?q=cache:example.com/+search_query"));
+ // Query params other than "q=" don't matter.
+ EXPECT_EQ(GURL("http://example.com"),
+ GetEmbeddedURL("https://webcache.googleusercontent.com/"
+ "search?a=b&q=cache:example.com/&c=d"));
+ // With scheme.
+ EXPECT_EQ(GURL("http://example.com"),
+ GetEmbeddedURL("https://webcache.googleusercontent.com/"
+ "search?q=cache:http://example.com/"));
+ // Preserve https.
+ EXPECT_EQ(GURL("https://example.com"),
+ GetEmbeddedURL("https://webcache.googleusercontent.com/"
+ "search?q=cache:https://example.com/"));
+
+ // Wrong host.
+ EXPECT_EQ(GURL(), GetEmbeddedURL("https://www.googleusercontent.com/"
+ "search?q=cache:example.com/"));
+ // Wrong path.
+ EXPECT_EQ(GURL(), GetEmbeddedURL("https://webcache.googleusercontent.com/"
+ "path?q=cache:example.com/"));
+ EXPECT_EQ(GURL(), GetEmbeddedURL("https://webcache.googleusercontent.com/"
+ "path/search?q=cache:example.com/"));
+ // Missing "cache:".
+ EXPECT_EQ(GURL(), GetEmbeddedURL("https://webcache.googleusercontent.com/"
+ "search?q=example.com"));
+ // Wrong fingerprint.
+ EXPECT_EQ(GURL(), GetEmbeddedURL("https://webcache.googleusercontent.com/"
+ "search?q=cache:123:example.com/"));
+ // Wrong query param.
+ EXPECT_EQ(GURL(), GetEmbeddedURL("https://webcache.googleusercontent.com/"
+ "search?a=cache:example.com/"));
+ // Invalid scheme.
+ EXPECT_EQ(GURL(), GetEmbeddedURL("https://webcache.googleusercontent.com/"
+ "search?q=cache:abc://example.com/"));
+}
+
+TEST(URLUtilTest, GetEmbeddedURLTranslate) {
+ // Base case.
+ EXPECT_EQ(GURL("http://example.com"),
+ GetEmbeddedURL("https://translate.google.com/path?u=example.com"));
+ // Different TLD.
+ EXPECT_EQ(GURL("http://example.com"),
+ GetEmbeddedURL("https://translate.google.de/path?u=example.com"));
+ // Alternate base URL.
+ EXPECT_EQ(GURL("http://example.com"),
+ GetEmbeddedURL(
+ "https://translate.googleusercontent.com/path?u=example.com"));
+ // With scheme.
+ EXPECT_EQ(
+ GURL("http://example.com"),
+ GetEmbeddedURL("https://translate.google.com/path?u=http://example.com"));
+ // With https scheme.
+ EXPECT_EQ(GURL("https://example.com"),
+ GetEmbeddedURL(
+ "https://translate.google.com/path?u=https://example.com"));
+ // With other parameters.
+ EXPECT_EQ(
+ GURL("http://example.com"),
+ GetEmbeddedURL(
+ "https://translate.google.com/path?a=asdf&u=example.com&b=fdsa"));
+
+ // Different subdomain is not supported.
+ EXPECT_EQ(GURL(), GetEmbeddedURL(
+ "https://translate.foo.google.com/path?u=example.com"));
+ EXPECT_EQ(GURL(), GetEmbeddedURL(
+ "https://translate.www.google.com/path?u=example.com"));
+ EXPECT_EQ(
+ GURL(),
+ GetEmbeddedURL("https://translate.google.google.com/path?u=example.com"));
+ EXPECT_EQ(GURL(), GetEmbeddedURL(
+ "https://foo.translate.google.com/path?u=example.com"));
+ EXPECT_EQ(GURL(),
+ GetEmbeddedURL("https://translate2.google.com/path?u=example.com"));
+ EXPECT_EQ(GURL(),
+ GetEmbeddedURL(
+ "https://translate2.googleusercontent.com/path?u=example.com"));
+ // Different TLD is not supported for googleusercontent.
+ EXPECT_EQ(GURL(),
+ GetEmbeddedURL(
+ "https://translate.googleusercontent.de/path?u=example.com"));
+ // Query parameter ("u=...") is missing.
+ EXPECT_EQ(GURL(),
+ GetEmbeddedURL("https://translate.google.com/path?t=example.com"));
+}
+
+INSTANTIATE_TEST_SUITE_P(URLUtilTest,
+ OnlyWildcardTest,
+ testing::Combine(testing::Values("", "https://"),
+ testing::Values("", "dev."),
+ testing::Values("", ":1234"),
+ testing::Values("", "/path"),
+ testing::Values("", "?query")));
+
+TEST_P(OnlyWildcardTest, OnlyWildcard) {
+ // Check wildcard filter works on any permutations of format
+ // [scheme://][.]host[:port][/path][@query]
+ const std::string scheme = std::get<0>(GetParam());
+ const std::string opt_host = std::get<1>(GetParam());
+ const std::string port = std::get<2>(GetParam());
+ const std::string path = std::get<3>(GetParam());
+ const std::string query = std::get<4>(GetParam());
+ const std::string url =
+ scheme + opt_host + "google.com" + port + path + query;
+ EXPECT_TRUE(MatchFilters({"*"}, url));
+}
+
+TEST(URLUtilTest, SingleFilter) {
+ // Match domain and all subdomains, for any filtered scheme.
+ EXPECT_TRUE(MatchFilters({"google.com"}, "http://google.com"));
+ EXPECT_TRUE(MatchFilters({"google.com"}, "http://google.com/"));
+ EXPECT_TRUE(MatchFilters({"google.com"}, "http://google.com/whatever"));
+ EXPECT_TRUE(MatchFilters({"google.com"}, "https://google.com/"));
+ EXPECT_FALSE(MatchFilters({"google.com"}, "bogus://google.com/"));
+ EXPECT_FALSE(MatchFilters({"google.com"}, "http://notgoogle.com/"));
+ EXPECT_TRUE(MatchFilters({"google.com"}, "http://mail.google.com"));
+ EXPECT_TRUE(MatchFilters({"google.com"}, "http://x.mail.google.com"));
+ EXPECT_TRUE(MatchFilters({"google.com"}, "https://x.mail.google.com/"));
+ EXPECT_TRUE(MatchFilters({"google.com"}, "http://x.y.google.com/a/b"));
+ EXPECT_FALSE(MatchFilters({"google.com"}, "http://youtube.com/"));
+
+ // Filter only http, ftp and ws schemes.
+ EXPECT_TRUE(MatchFilters({"http://secure.com"}, "http://secure.com"));
+ EXPECT_TRUE(
+ MatchFilters({"http://secure.com"}, "http://secure.com/whatever"));
+ EXPECT_TRUE(MatchFilters({"ftp://secure.com"}, "ftp://secure.com/"));
+ EXPECT_TRUE(MatchFilters({"ws://secure.com"}, "ws://secure.com"));
+ EXPECT_FALSE(MatchFilters({"http://secure.com"}, "https://secure.com/"));
+ EXPECT_FALSE(MatchFilters({"ws://secure.com"}, "wss://secure.com"));
+ EXPECT_TRUE(MatchFilters({"http://secure.com"}, "http://www.secure.com"));
+ EXPECT_FALSE(MatchFilters({"http://secure.com"}, "https://www.secure.com"));
+ EXPECT_FALSE(MatchFilters({"ws://secure.com"}, "wss://www.secure.com"));
+
+ // Filter only a certain path prefix.
+ EXPECT_TRUE(MatchFilters({"path.to/ruin"}, "http://path.to/ruin"));
+ EXPECT_TRUE(MatchFilters({"path.to/ruin"}, "https://path.to/ruin"));
+ EXPECT_TRUE(MatchFilters({"path.to/ruin"}, "http://path.to/ruins"));
+ EXPECT_TRUE(MatchFilters({"path.to/ruin"}, "http://path.to/ruin/signup"));
+ EXPECT_TRUE(MatchFilters({"path.to/ruin"}, "http://www.path.to/ruin"));
+ EXPECT_FALSE(MatchFilters({"path.to/ruin"}, "http://path.to/fortune"));
+
+ // Filter only a certain path prefix and scheme.
+ EXPECT_TRUE(
+ MatchFilters({"https://s.aaa.com/path"}, "https://s.aaa.com/path"));
+ EXPECT_TRUE(
+ MatchFilters({"https://s.aaa.com/path"}, "https://s.aaa.com/path/bbb"));
+ EXPECT_FALSE(
+ MatchFilters({"https://s.aaa.com/path"}, "http://s.aaa.com/path"));
+ EXPECT_FALSE(
+ MatchFilters({"https://s.aaa.com/path"}, "https://aaa.com/path"));
+ EXPECT_FALSE(
+ MatchFilters({"https://s.aaa.com/path"}, "https://x.aaa.com/path"));
+ EXPECT_FALSE(
+ MatchFilters({"https://s.aaa.com/path"}, "https://s.aaa.com/bbb"));
+ EXPECT_FALSE(MatchFilters({"https://s.aaa.com/path"}, "https://s.aaa.com/"));
+
+ // Filter only ws and wss schemes.
+ EXPECT_TRUE(MatchFilters({"ws://ws.aaa.com"}, "ws://ws.aaa.com"));
+ EXPECT_TRUE(MatchFilters({"wss://ws.aaa.com"}, "wss://ws.aaa.com"));
+ EXPECT_FALSE(MatchFilters({"ws://ws.aaa.com"}, "http://ws.aaa.com"));
+ EXPECT_FALSE(MatchFilters({"ws://ws.aaa.com"}, "https://ws.aaa.com"));
+ EXPECT_FALSE(MatchFilters({"ws://ws.aaa.com"}, "ftp://ws.aaa.com"));
+
+ // Match an ip address.
+ EXPECT_TRUE(MatchFilters({"123.123.123.123"}, "http://123.123.123.123/"));
+ EXPECT_FALSE(MatchFilters({"123.123.123.123"}, "http://123.123.123.124/"));
+
+ // Open an exception.
+ EXPECT_FALSE(MatchFilters({"plus.google.com"}, "http://google.com/"));
+ EXPECT_FALSE(MatchFilters({"plus.google.com"}, "http://www.google.com/"));
+ EXPECT_TRUE(MatchFilters({"plus.google.com"}, "http://plus.google.com/"));
+
+ // Match exactly "google.com", only for http.
+ EXPECT_TRUE(MatchFilters({"http://.google.com"}, "http://google.com/"));
+ EXPECT_FALSE(MatchFilters({"http://.google.com"}, "https://google.com/"));
+ EXPECT_FALSE(MatchFilters({"http://.google.com"}, "http://www.google.com/"));
+}
+
+TEST(URLUtilTest, MultipleFilters) {
+ // Test exceptions to path prefixes, and most specific matches.
+ std::vector<std::string> patterns = {"s.xxx.com/a/b",
+ "https://s.xxx.com/a/b/c/d"};
+ EXPECT_FALSE(MatchFilters(patterns, "http://s.xxx.com/a"));
+ EXPECT_FALSE(MatchFilters(patterns, "http://s.xxx.com/a/x"));
+ EXPECT_FALSE(MatchFilters(patterns, "https://s.xxx.com/a/x"));
+ EXPECT_TRUE(MatchFilters(patterns, "http://s.xxx.com/a/b"));
+ EXPECT_TRUE(MatchFilters(patterns, "https://s.xxx.com/a/b"));
+ EXPECT_TRUE(MatchFilters(patterns, "http://s.xxx.com/a/b/x"));
+ EXPECT_TRUE(MatchFilters(patterns, "http://s.xxx.com/a/b/c"));
+ EXPECT_TRUE(MatchFilters(patterns, "https://s.xxx.com/a/b/c"));
+ EXPECT_TRUE(MatchFilters(patterns, "https://s.xxx.com/a/b/c/x"));
+ EXPECT_TRUE(MatchFilters(patterns, "https://s.xxx.com/a/b/c/d"));
+ EXPECT_TRUE(MatchFilters(patterns, "http://s.xxx.com/a/b/c/d"));
+ EXPECT_TRUE(MatchFilters(patterns, "https://s.xxx.com/a/b/c/d/x"));
+ EXPECT_TRUE(MatchFilters(patterns, "http://s.xxx.com/a/b/c/d/x"));
+ EXPECT_FALSE(MatchFilters(patterns, "http://xxx.com/a"));
+ EXPECT_FALSE(MatchFilters(patterns, "http://xxx.com/a/b"));
+
+ // Match queries.
+ std::vector<std::string> queries = {"*?q=1234", "*?q=5678", "*?a=1&b=2",
+ "youtube.com?foo=baz",
+ "youtube.com?foo=bar*"};
+ EXPECT_TRUE(MatchFilters(queries, "http://google.com?q=1234"));
+ EXPECT_TRUE(MatchFilters(queries, "http://google.com?q=5678"));
+ EXPECT_TRUE(MatchFilters(queries, "http://google.com?a=1&b=2"));
+ EXPECT_TRUE(MatchFilters(queries, "http://google.com?b=2&a=1"));
+ EXPECT_TRUE(MatchFilters(queries, "http://google.com?a=1&b=4&q=1234"));
+ EXPECT_TRUE(MatchFilters(queries, "http://youtube.com?foo=baz"));
+ EXPECT_TRUE(MatchFilters(queries, "http://youtube.com?foo=barbaz"));
+ EXPECT_TRUE(MatchFilters(queries, "http://youtube.com?a=1&foo=barbaz"));
+ EXPECT_FALSE(MatchFilters(queries, "http://google.com?r=1234"));
+ EXPECT_FALSE(MatchFilters(queries, "http://google.com?r=5678"));
+ EXPECT_FALSE(MatchFilters(queries, "http://google.com?a=2&b=1"));
+ EXPECT_FALSE(MatchFilters(queries, "http://google.com?b=1&a=2"));
+ EXPECT_FALSE(MatchFilters(queries, "http://google.com?a=1&b=3"));
+ EXPECT_FALSE(MatchFilters(queries, "http://youtube.com?foo=meh"));
+ EXPECT_FALSE(MatchFilters(queries, "http://youtube.com?foo=bazbar"));
+ EXPECT_FALSE(MatchFilters(queries, "http://youtube.com?foo=ba"));
+}
+
+TEST(URLUtilTest, BasicCoverage) {
+ // Tests to cover the documentation from
+ // http://www.chromium.org/administrators/url-blocklist-filter-format
+
+ // [scheme://][.]host[:port][/path][@query]
+ // Scheme can be http, https, ftp, chrome, etc. This field is optional, and
+ // must be followed by '://'.
+ EXPECT_TRUE(MatchFilters({"file://*"}, "file:///abc.txt"));
+ EXPECT_TRUE(MatchFilters({"file:*"}, "file:///usr/local/boot.txt"));
+ EXPECT_TRUE(MatchFilters({"https://*"}, "https:///abc.txt"));
+ EXPECT_TRUE(MatchFilters({"ftp://*"}, "ftp://ftp.txt"));
+ EXPECT_TRUE(MatchFilters({"chrome://*"}, "chrome:policy"));
+ EXPECT_TRUE(MatchFilters({"noscheme"}, "http://noscheme"));
+ // Filter custom schemes.
+ EXPECT_TRUE(MatchFilters({"custom://*"}, "custom://example_app"));
+ EXPECT_TRUE(MatchFilters({"custom:*"}, "custom:example2_app"));
+ EXPECT_FALSE(MatchFilters({"custom://*"}, "customs://example_apps"));
+ EXPECT_FALSE(MatchFilters({"custom://*"}, "cust*://example_ap"));
+ EXPECT_FALSE(MatchFilters({"custom://*"}, "ecustom:example_app"));
+ EXPECT_TRUE(MatchFilters({"custom://*"}, "custom:///abc.txt"));
+ // Tests for custom scheme patterns that are not supported.
+ EXPECT_FALSE(MatchFilters({"wrong://app"}, "wrong://app"));
+ EXPECT_FALSE(MatchFilters({"wrong ://*"}, "wrong ://app"));
+ EXPECT_FALSE(MatchFilters({" wrong:*"}, " wrong://app"));
+
+ // Omitting the scheme matches most standard schemes.
+ EXPECT_TRUE(MatchFilters({"example.com"}, "chrome:example.com"));
+ EXPECT_TRUE(MatchFilters({"example.com"}, "chrome://example.com"));
+ EXPECT_TRUE(MatchFilters({"example.com"}, "file://example.com/"));
+ EXPECT_TRUE(MatchFilters({"example.com"}, "ftp://example.com"));
+ EXPECT_TRUE(MatchFilters({"example.com"}, "http://example.com"));
+ EXPECT_TRUE(MatchFilters({"example.com"}, "https://example.com"));
+ EXPECT_TRUE(MatchFilters({"example.com"}, "ws://example.com"));
+ EXPECT_TRUE(MatchFilters({"example.com"}, "wss://example.com"));
+
+ // Some schemes are not matched when the scheme is omitted.
+ EXPECT_FALSE(MatchFilters({"example.com"}, "about://example.com"));
+ EXPECT_FALSE(MatchFilters({"example.com"}, "about:example.com"));
+ EXPECT_FALSE(MatchFilters({"example.com/*"}, "filesystem:///something"));
+ EXPECT_FALSE(MatchFilters({"example.com"}, "custom://example.com"));
+ EXPECT_FALSE(MatchFilters({"example"}, "custom://example"));
+
+ // An optional '.' (dot) can prefix the host field to disable subdomain
+ // matching, see below for details.
+ EXPECT_TRUE(MatchFilters({".example.com"}, "http://example.com/path"));
+ EXPECT_FALSE(MatchFilters({".example.com"}, "http://mail.example.com/path"));
+ EXPECT_TRUE(MatchFilters({"example.com"}, "http://mail.example.com/path"));
+ EXPECT_TRUE(MatchFilters({"ftp://.ftp.file"}, "ftp://ftp.file"));
+ EXPECT_FALSE(MatchFilters({"ftp://.ftp.file"}, "ftp://sub.ftp.file"));
+
+ // The host field is required, and is a valid hostname or an IP address. It
+ // can also take the special '*' value, see below for details.
+ EXPECT_TRUE(MatchFilters({"*"}, "http://anything"));
+ EXPECT_TRUE(MatchFilters({"*"}, "ftp://anything"));
+ EXPECT_TRUE(MatchFilters({"*"}, "custom://anything"));
+ EXPECT_TRUE(MatchFilters({"host"}, "http://host:8080"));
+ EXPECT_FALSE(MatchFilters({"host"}, "file:///host"));
+ EXPECT_TRUE(MatchFilters({"10.1.2.3"}, "http://10.1.2.3:8080/path"));
+ // No host, will match nothing.
+ EXPECT_FALSE(MatchFilters({":8080"}, "http://host:8080"));
+ EXPECT_FALSE(MatchFilters({":8080"}, "http://:8080"));
+
+ // An optional port can come after the host. It must be a valid port value
+ // from 1 to 65535.
+ EXPECT_TRUE(MatchFilters({"host:8080"}, "http://host:8080/path"));
+ EXPECT_TRUE(MatchFilters({"host:1"}, "http://host:1/path"));
+ // Out of range port.
+ EXPECT_FALSE(MatchFilters({"host:65536"}, "http://host:65536/path"));
+ // Star is not allowed in port numbers.
+ EXPECT_FALSE(MatchFilters({"example.com:*"}, "http://example.com"));
+ EXPECT_FALSE(MatchFilters({"example.com:*"}, "http://example.com:8888"));
+
+ // An optional path can come after port.
+ EXPECT_TRUE(MatchFilters({"host/path"}, "http://host:8080/path"));
+ EXPECT_TRUE(MatchFilters({"host/path/path2"}, "http://host/path/path2"));
+ EXPECT_TRUE(MatchFilters({"host/path"}, "http://host/path/path2"));
+
+ // An optional query can come in the end, which is a set of key-value and
+ // key-only tokens delimited by '&'. The key-value tokens are separated
+ // by '='. A query token can optionally end with a '*' to indicate prefix
+ // match. Token order is ignored during matching.
+ EXPECT_TRUE(MatchFilters({"host?q1=1&q2=2"}, "http://host?q2=2&q1=1"));
+ EXPECT_FALSE(MatchFilters({"host?q1=1&q2=2"}, "http://host?q2=1&q1=2"));
+ EXPECT_FALSE(MatchFilters({"host?q1=1&q2=2"}, "http://host?Q2=2&Q1=1"));
+ EXPECT_TRUE(MatchFilters({"host?q1=1&q2=2"}, "http://host?q2=2&q1=1&q3=3"));
+ EXPECT_TRUE(MatchFilters({"host?q1=1&q2=2*"}, "http://host?q2=21&q1=1&q3=3"));
+
+ // user:pass fields can be included but will be ignored
+ // (e.g. http://user:pass@ftp.example.com/pub/bigfile.iso).
+ EXPECT_TRUE(
+ MatchFilters({"host.com/path"}, "http://user:pass@host.com:8080/path"));
+ EXPECT_TRUE(MatchFilters({"ftp://host.com/path"},
+ "ftp://user:pass@host.com:8080/path"));
+
+ // Case sensitivity.
+ // Scheme is case insensitive.
+ EXPECT_TRUE(MatchFilters({"suPPort://*"}, "support:example"));
+ EXPECT_TRUE(MatchFilters({"FILE://*"}, "file:example"));
+ EXPECT_TRUE(MatchFilters({"FILE://*"}, "FILE://example"));
+ EXPECT_TRUE(MatchFilters({"FtP:*"}, "ftp://example"));
+ EXPECT_TRUE(MatchFilters({"http://example.com"}, "HTTP://example.com"));
+ EXPECT_TRUE(MatchFilters({"HTTP://example.com"}, "http://example.com"));
+ // Host is case insensitive.
+ EXPECT_TRUE(MatchFilters({"http://EXAMPLE.COM"}, "http://example.com"));
+ EXPECT_TRUE(MatchFilters({"Example.com"}, "http://examplE.com/Path?Query=1"));
+ // Path is case sensitive.
+ EXPECT_FALSE(MatchFilters({"example.com/Path"}, "http://example.com/path"));
+ EXPECT_TRUE(MatchFilters({"http://example.com/aB"}, "http://example.com/aB"));
+ EXPECT_FALSE(
+ MatchFilters({"http://example.com/aB"}, "http://example.com/Ab"));
+ EXPECT_FALSE(
+ MatchFilters({"http://example.com/aB"}, "http://example.com/ab"));
+ EXPECT_FALSE(
+ MatchFilters({"http://example.com/aB"}, "http://example.com/AB"));
+ // Query is case sensitive.
+ EXPECT_FALSE(MatchFilters({"host/path?Query=1"}, "http://host/path?query=1"));
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ URLUtilTest,
+ FilterToComponentsTest,
+ testing::Values(
+ FilterTestParams("google.com",
+ std::string(),
+ ".google.com",
+ true,
+ 0u,
+ std::string()),
+ FilterTestParams(".google.com",
+ std::string(),
+ "google.com",
+ false,
+ 0u,
+ std::string()),
+ FilterTestParams("http://google.com",
+ "http",
+ ".google.com",
+ true,
+ 0u,
+ std::string()),
+ FilterTestParams("google.com/",
+ std::string(),
+ ".google.com",
+ true,
+ 0u,
+ "/"),
+ FilterTestParams("http://google.com:8080/whatever",
+ "http",
+ ".google.com",
+ true,
+ 8080u,
+ "/whatever"),
+ FilterTestParams("http://user:pass@google.com:8080/whatever",
+ "http",
+ ".google.com",
+ true,
+ 8080u,
+ "/whatever"),
+ FilterTestParams("123.123.123.123",
+ std::string(),
+ "123.123.123.123",
+ false,
+ 0u,
+ std::string()),
+ FilterTestParams("https://123.123.123.123",
+ "https",
+ "123.123.123.123",
+ false,
+ 0u,
+ std::string()),
+ FilterTestParams("123.123.123.123/",
+ std::string(),
+ "123.123.123.123",
+ false,
+ 0u,
+ "/"),
+ FilterTestParams("http://123.123.123.123:123/whatever",
+ "http",
+ "123.123.123.123",
+ false,
+ 123u,
+ "/whatever"),
+ FilterTestParams("*",
+ std::string(),
+ std::string(),
+ true,
+ 0u,
+ std::string()),
+ FilterTestParams("ftp://*",
+ "ftp",
+ std::string(),
+ true,
+ 0u,
+ std::string()),
+ FilterTestParams("http://*/whatever",
+ "http",
+ std::string(),
+ true,
+ 0u,
+ "/whatever")));
+
+TEST_P(FilterToComponentsTest, FilterToComponents) {
+ std::string scheme;
+ std::string host;
+ bool match_subdomains = true;
+ uint16_t port = 42;
+ std::string path;
+ std::string query;
+
+ FilterToComponents(GetParam().filter(), &scheme, &host, &match_subdomains,
+ &port, &path, &query);
+ EXPECT_EQ(GetParam().scheme(), scheme);
+ EXPECT_EQ(GetParam().host(), host);
+ EXPECT_EQ(GetParam().match_subdomains(), match_subdomains);
+ EXPECT_EQ(GetParam().port(), port);
+ EXPECT_EQ(GetParam().path(), path);
+}
+
+} // namespace util
+} // namespace url_matcher
diff --git a/chromium/components/url_pattern_index/flat/url_pattern_index.fbs b/chromium/components/url_pattern_index/flat/url_pattern_index.fbs
index d1cfc1f49ac..132683bcaf8 100644
--- a/chromium/components/url_pattern_index/flat/url_pattern_index.fbs
+++ b/chromium/components/url_pattern_index/flat/url_pattern_index.fbs
@@ -104,13 +104,13 @@ table UrlRule {
anchor_left : AnchorType = NONE;
anchor_right : AnchorType = NONE;
- // The list of domains to be included/excluded from the filter's affected set.
- // Should either be null or have at least a single element. The domains
- // should be in lower-case and kept sorted as defined by
+ // The list of initiator domains to be included/excluded from the filter's
+ // affected set. Each should either be null or have at least a single
+ // element. The domains should be in lower-case and kept sorted as defined by
// url_pattern_index::CompareDomains. The entries must consist of only ascii
// characters. Use punycode encoding for internationalized domains.
- domains_included : [string];
- domains_excluded : [string];
+ initiator_domains_included : [string];
+ initiator_domains_excluded : [string];
// A URL pattern in the format defined by |url_pattern_type|. This should
// only consist of ascii characters, since it's matched against a url where
diff --git a/chromium/components/url_pattern_index/proto/rules.proto b/chromium/components/url_pattern_index/proto/rules.proto
index e16b1ad99c9..279e9b7d483 100644
--- a/chromium/components/url_pattern_index/proto/rules.proto
+++ b/chromium/components/url_pattern_index/proto/rules.proto
@@ -146,7 +146,7 @@ message UrlRule {
// If |domains| is empty or has exceptions only, the rule is called generic.
// Otherwise is it called domain specific, i.e. applies to a limited number of
// domains.
- repeated DomainListItem domains = 5;
+ repeated DomainListItem initiator_domains = 5;
// The format of |url_pattern|.
optional UrlPatternType url_pattern_type = 6;
diff --git a/chromium/components/url_pattern_index/url_pattern.cc b/chromium/components/url_pattern_index/url_pattern.cc
index 9a6b2da31c3..cc639bfa975 100644
--- a/chromium/components/url_pattern_index/url_pattern.cc
+++ b/chromium/components/url_pattern_index/url_pattern.cc
@@ -377,10 +377,10 @@ std::ostream& operator<<(std::ostream& out, const UrlPattern& pattern) {
switch (pattern.anchor_left()) {
case proto::ANCHOR_TYPE_SUBDOMAIN:
out << '|';
- FALLTHROUGH;
+ [[fallthrough]];
case proto::ANCHOR_TYPE_BOUNDARY:
out << '|';
- FALLTHROUGH;
+ [[fallthrough]];
default:
break;
}
diff --git a/chromium/components/url_pattern_index/url_pattern_index.cc b/chromium/components/url_pattern_index/url_pattern_index.cc
index b678fce6193..5dea5f49b5c 100644
--- a/chromium/components/url_pattern_index/url_pattern_index.cc
+++ b/chromium/components/url_pattern_index/url_pattern_index.cc
@@ -146,16 +146,16 @@ class UrlRuleFlatBufferConverter {
DCHECK_NE(rule_.url_pattern_type(), proto::URL_PATTERN_TYPE_REGEXP);
- FlatDomainsOffset domains_included_offset;
- FlatDomainsOffset domains_excluded_offset;
- if (rule_.domains_size()) {
- std::vector<FlatStringOffset> domains_included;
- std::vector<FlatStringOffset> domains_excluded;
- // Reserve only for |domains_included| because it is expected to be the
- // one used more frequently.
- domains_included.reserve(rule_.domains_size());
-
- for (const auto& domain_list_item : rule_.domains()) {
+ FlatDomainsOffset initiator_domains_included_offset;
+ FlatDomainsOffset initiator_domains_excluded_offset;
+ if (rule_.initiator_domains_size()) {
+ std::vector<FlatStringOffset> initiator_domains_included;
+ std::vector<FlatStringOffset> initiator_domains_excluded;
+ // Reserve only for `initiator_domains_included` because it is expected to
+ // be the one used more frequently.
+ initiator_domains_included.reserve(rule_.initiator_domains_size());
+
+ for (const auto& domain_list_item : rule_.initiator_domains()) {
const std::string& domain = domain_list_item.domain();
// Non-ascii characters in domains are unsupported.
@@ -169,15 +169,15 @@ class UrlRuleFlatBufferConverter {
HasNoUpperAscii(domain) ? domain : base::ToLowerASCII(domain));
if (domain_list_item.exclude())
- domains_excluded.push_back(offset);
+ initiator_domains_excluded.push_back(offset);
else
- domains_included.push_back(offset);
+ initiator_domains_included.push_back(offset);
}
// The domains are stored in sorted order to support fast matching.
- domains_included_offset =
- SerializeDomainList(std::move(domains_included), builder, domain_map);
- domains_excluded_offset =
- SerializeDomainList(std::move(domains_excluded), builder, domain_map);
+ initiator_domains_included_offset = SerializeDomainList(
+ std::move(initiator_domains_included), builder, domain_map);
+ initiator_domains_excluded_offset = SerializeDomainList(
+ std::move(initiator_domains_excluded), builder, domain_map);
}
// Non-ascii characters in patterns are unsupported.
@@ -191,7 +191,8 @@ class UrlRuleFlatBufferConverter {
return flat::CreateUrlRule(
*builder, options_, element_types_, flat::RequestMethod_ANY,
activation_types_, url_pattern_type_, anchor_left_, anchor_right_,
- domains_included_offset, domains_excluded_offset, url_pattern_offset);
+ initiator_domains_included_offset, initiator_domains_excluded_offset,
+ url_pattern_offset);
}
private:
@@ -255,7 +256,7 @@ class UrlRuleFlatBufferConverter {
switch (rule_.source_type()) {
case proto::SOURCE_TYPE_ANY:
options_ |= flat::OptionFlag_APPLIES_TO_THIRD_PARTY;
- FALLTHROUGH;
+ [[fallthrough]];
case proto::SOURCE_TYPE_FIRST_PARTY:
options_ |= flat::OptionFlag_APPLIES_TO_FIRST_PARTY;
break;
@@ -423,12 +424,12 @@ void UrlPatternIndexBuilder::IndexUrlRule(UrlRuleOffset offset) {
#if DCHECK_IS_ON()
// Sanity check that the rule does not have fields with non-ascii characters.
DCHECK(base::IsStringASCII(ToStringPiece(rule->url_pattern())));
- if (rule->domains_included()) {
- for (auto* domain : *rule->domains_included())
+ if (rule->initiator_domains_included()) {
+ for (auto* domain : *rule->initiator_domains_included())
DCHECK(base::IsStringASCII(ToStringPiece(domain)));
}
- if (rule->domains_excluded()) {
- for (auto* domain : *rule->domains_excluded())
+ if (rule->initiator_domains_excluded()) {
+ for (auto* domain : *rule->initiator_domains_excluded())
DCHECK(base::IsStringASCII(ToStringPiece(domain)));
}
@@ -610,11 +611,13 @@ const flat::UrlRule* FindMatchAmongCandidates(
continue;
}
+ if (disable_generic_rules && IsRuleGeneric(*rule))
+ continue;
+
if (!UrlPattern(*rule).MatchesUrl(url))
continue;
- if (DoesOriginMatchDomainList(document_origin, *rule,
- disable_generic_rules)) {
+ if (DoesOriginMatchInitiatorDomainList(document_origin, *rule)) {
if (matched_rules)
matched_rules->push_back(rule);
else
@@ -724,25 +727,28 @@ const flat::UrlRule* FindMatchInFlatUrlPatternIndex(
} // namespace
-bool DoesOriginMatchDomainList(const url::Origin& origin,
- const flat::UrlRule& rule,
- bool disable_generic_rules) {
- const bool is_generic = !rule.domains_included();
- DCHECK(is_generic || rule.domains_included()->size());
- if (disable_generic_rules && is_generic)
- return false;
+bool IsRuleGeneric(const flat::UrlRule& rule) {
+ return !rule.initiator_domains_included();
+}
+
+bool DoesOriginMatchInitiatorDomainList(const url::Origin& origin,
+ const flat::UrlRule& rule) {
+ const bool is_generic = IsRuleGeneric(rule);
+ DCHECK(is_generic || rule.initiator_domains_included()->size());
- // Unique |origin| matches lists of exception domains only.
+ // Unique `origin` matches lists of exception domains only.
if (origin.opaque())
return is_generic;
size_t longest_matching_included_domain_length = 1;
if (!is_generic) {
longest_matching_included_domain_length =
- GetLongestMatchingSubdomain(origin, *rule.domains_included());
+ GetLongestMatchingSubdomain(origin, *rule.initiator_domains_included());
}
- if (longest_matching_included_domain_length && rule.domains_excluded()) {
- return GetLongestMatchingSubdomain(origin, *rule.domains_excluded()) <
+ if (longest_matching_included_domain_length &&
+ rule.initiator_domains_excluded()) {
+ return GetLongestMatchingSubdomain(origin,
+ *rule.initiator_domains_excluded()) <
longest_matching_included_domain_length;
}
return !!longest_matching_included_domain_length;
@@ -792,6 +798,11 @@ UrlPatternIndexMatcher::UrlPatternIndexMatcher(
const flat::UrlPatternIndex* flat_index)
: flat_index_(flat_index) {
DCHECK(!flat_index || flat_index->n() == kNGramSize);
+ // Speculative investigation for crash (see crbug.com/1286207): check that we
+ // can access the ngram_index on each UrlPatternIndexMatcher without failure.
+ if (flat_index) {
+ CHECK_GT(flat_index->ngram_index()->size(), 0u);
+ }
}
UrlPatternIndexMatcher::~UrlPatternIndexMatcher() = default;
diff --git a/chromium/components/url_pattern_index/url_pattern_index.h b/chromium/components/url_pattern_index/url_pattern_index.h
index 400fa4f6e23..e26ca3b5b2d 100644
--- a/chromium/components/url_pattern_index/url_pattern_index.h
+++ b/chromium/components/url_pattern_index/url_pattern_index.h
@@ -248,19 +248,18 @@ class UrlPatternIndexMatcher {
mutable absl::optional<size_t> rules_count_;
};
-// Returns whether the |origin| matches the domain list of the |rule|. A match
-// means that the longest domain in |domains| that |origin| is a sub-domain of
-// is not an exception OR all the |domains| are exceptions and neither matches
-// the |origin|. Thus, domain filters with more domain components trump filters
-// with fewer domain components, i.e. the more specific a filter is, the higher
-// the priority.
-//
-// A rule whose domain list is empty or contains only negative domains is still
-// considered a "generic" rule. Therefore, if |disable_generic_rules| is set,
-// this function will always return false for such rules.
-bool DoesOriginMatchDomainList(const url::Origin& origin,
- const flat::UrlRule& rule,
- bool disable_generic_rules);
+// Returns whether the `rule` is considered "generic". A generic rule is one
+// whose initator domain list is either empty or contains only negative domains.
+bool IsRuleGeneric(const flat::UrlRule& rule);
+
+// Returns whether the `origin` matches the initiator domain list of the `rule`.
+// A match means that the longest domain in `domains` that `origin` is a
+// sub-domain of is not an exception OR all the `domains` are exceptions and
+// neither matches the `origin`. Thus, domain filters with more domain
+// components trump filters with fewer domain components, i.e. the more specific
+// a filter is, the higher the priority.
+bool DoesOriginMatchInitiatorDomainList(const url::Origin& origin,
+ const flat::UrlRule& rule);
// Returns whether the request matches flags of the specified `rule`. Takes into
// account:
diff --git a/chromium/components/url_pattern_index/url_pattern_index_unittest.cc b/chromium/components/url_pattern_index/url_pattern_index_unittest.cc
index 226a5e4f482..7d411e2e4d0 100644
--- a/chromium/components/url_pattern_index/url_pattern_index_unittest.cc
+++ b/chromium/components/url_pattern_index/url_pattern_index_unittest.cc
@@ -402,7 +402,7 @@ TEST_F(UrlPatternIndexTest, OneRuleWithThirdParty) {
}
}
-TEST_F(UrlPatternIndexTest, OneRuleWithDomainList) {
+TEST_F(UrlPatternIndexTest, OneRuleWithInitiatorDomainList) {
constexpr const char* kUrl = "http://example.com";
const struct {
@@ -499,11 +499,12 @@ TEST_F(UrlPatternIndexTest, OneRuleWithDomainList) {
for (const auto& test_case : kTestCases) {
SCOPED_TRACE(::testing::Message()
- << "Domains: " << ::testing::PrintToString(test_case.domains)
+ << "Initiator Domains: "
+ << ::testing::PrintToString(test_case.domains)
<< "; DocumentOrigin: " << test_case.document_origin);
auto rule = MakeUrlRule(UrlPattern(kUrl, kSubstring));
- testing::AddDomains(test_case.domains, &rule);
+ testing::AddInitiatorDomains(test_case.domains, &rule);
ASSERT_TRUE(AddUrlRule(rule));
Finish();
@@ -533,7 +534,7 @@ TEST_F(UrlPatternIndexTest, OneRuleWithLongDomainList) {
}
auto rule = MakeUrlRule(UrlPattern(kUrl, kSubstring));
- testing::AddDomains(domains, &rule);
+ testing::AddInitiatorDomains(domains, &rule);
ASSERT_TRUE(AddUrlRule(rule));
Finish();
@@ -735,7 +736,7 @@ TEST_F(UrlPatternIndexTest, MultipleRuleMatches) {
TEST_F(UrlPatternIndexTest, MatchWithDisableGenericRules) {
const struct {
const char* url_pattern;
- std::vector<std::string> domains;
+ std::vector<std::string> initiator_domains;
} kRules[] = {
// Generic rules.
{"some_text", std::vector<std::string>()},
@@ -749,10 +750,10 @@ TEST_F(UrlPatternIndexTest, MatchWithDisableGenericRules) {
for (const auto& rule_data : kRules) {
auto rule = MakeUrlRule(UrlPattern(rule_data.url_pattern, kSubstring));
- testing::AddDomains(rule_data.domains, &rule);
+ testing::AddInitiatorDomains(rule_data.initiator_domains, &rule);
ASSERT_TRUE(AddUrlRule(rule))
- << "UrlPattern: " << rule_data.url_pattern
- << "; Domains: " << ::testing::PrintToString(rule_data.domains);
+ << "UrlPattern: " << rule_data.url_pattern << "; Initiator Domains: "
+ << ::testing::PrintToString(rule_data.initiator_domains);
}
// Note: Some of the rules have common domains (e.g., example1.com), which are
diff --git a/chromium/components/url_pattern_index/url_rule_test_support.cc b/chromium/components/url_pattern_index/url_rule_test_support.cc
index ada11a7dbdb..4a3189eda7e 100644
--- a/chromium/components/url_pattern_index/url_rule_test_support.cc
+++ b/chromium/components/url_pattern_index/url_rule_test_support.cc
@@ -29,10 +29,11 @@ proto::UrlRule MakeUrlRule(const UrlPattern& url_pattern) {
return rule;
}
-void AddDomains(const std::vector<std::string>& domains, proto::UrlRule* rule) {
- for (std::string domain_pattern : domains) {
+void AddInitiatorDomains(const std::vector<std::string>& initiator_domains,
+ proto::UrlRule* rule) {
+ for (std::string domain_pattern : initiator_domains) {
DCHECK(!domain_pattern.empty());
- auto* domain = rule->add_domains();
+ auto* domain = rule->add_initiator_domains();
if (domain_pattern[0] == '~') {
domain_pattern.erase(0, 1);
domain->set_exclude(true);
diff --git a/chromium/components/url_pattern_index/url_rule_test_support.h b/chromium/components/url_pattern_index/url_rule_test_support.h
index 895f0f8446a..e051575fcb0 100644
--- a/chromium/components/url_pattern_index/url_rule_test_support.h
+++ b/chromium/components/url_pattern_index/url_rule_test_support.h
@@ -55,11 +55,13 @@ constexpr proto::SourceType kFirstParty = proto::SOURCE_TYPE_FIRST_PARTY;
// initialized to defaults.
proto::UrlRule MakeUrlRule(const UrlPattern& url_pattern = UrlPattern());
-// Parses |domains| and adds them to the domain list of the |rule|.
+// Parses `initiator_domains` and adds them to the initiator domain list of the
+// `rule`.
//
-// The |domains| vector should contain non-empty strings. If a string starts
-// with '~' then the following part of the string is an exception domain.
-void AddDomains(const std::vector<std::string>& domains, proto::UrlRule* rule);
+// The `initiator_domains` vector should contain non-empty strings. If a string
+// starts with '~' then the following part of the string is an exception domain.
+void AddInitiatorDomains(const std::vector<std::string>& initiator_domains,
+ proto::UrlRule* rule);
// Returns the url::Origin parsed from |origin_string|, or the unique origin if
// the string is empty.
diff --git a/chromium/components/url_pattern_index/url_rule_util.cc b/chromium/components/url_pattern_index/url_rule_util.cc
index 6c03e7732c0..2650454f515 100644
--- a/chromium/components/url_pattern_index/url_rule_util.cc
+++ b/chromium/components/url_pattern_index/url_rule_util.cc
@@ -127,22 +127,28 @@ std::string DomainOptionsToString(
OptionsPrinter* options_printer,
const url_pattern_index::flat::UrlRule* flat_rule) {
std::string out;
- if (!flat_rule->domains_included() && !flat_rule->domains_excluded())
+ if (!flat_rule->initiator_domains_included() &&
+ !flat_rule->initiator_domains_excluded())
return "";
+ // Note: For "main frame" ($document) matching, the $domain option should use
+ // the included/excluded request domains instead of initiator domains.
+ // This logic is OK for now however since $document filters aren't
+ // generated by `FlatUrlRuleToFilterlistString` yet.
+
out += options_printer->PrintOption("domain=");
bool first = true;
- if (flat_rule->domains_included()) {
- for (auto* domain : *flat_rule->domains_included()) {
+ if (flat_rule->initiator_domains_included()) {
+ for (auto* domain : *flat_rule->initiator_domains_included()) {
if (!first)
out += "|";
first = false;
out += ConvertFlatString(domain);
}
}
- if (flat_rule->domains_excluded()) {
- for (auto* domain : *flat_rule->domains_excluded()) {
+ if (flat_rule->initiator_domains_excluded()) {
+ for (auto* domain : *flat_rule->initiator_domains_excluded()) {
if (!first)
out += "|";
first = false;
diff --git a/chromium/components/url_pattern_index/url_rule_util_unittest.cc b/chromium/components/url_pattern_index/url_rule_util_unittest.cc
index 64f7dc87863..6bb6fca1bd9 100644
--- a/chromium/components/url_pattern_index/url_rule_util_unittest.cc
+++ b/chromium/components/url_pattern_index/url_rule_util_unittest.cc
@@ -39,7 +39,7 @@ proto::UrlRule MakeProtoRule(proto::RuleSemantics semantics,
rule.set_match_case(url_pattern.match_case());
rule.set_url_pattern(std::string(url_pattern.url_pattern()));
- testing::AddDomains(domains, &rule);
+ testing::AddInitiatorDomains(domains, &rule);
return rule;
}
diff --git a/chromium/components/url_rewrite/browser/url_request_rewrite_rules_manager.cc b/chromium/components/url_rewrite/browser/url_request_rewrite_rules_manager.cc
index 637ed072e11..2bd5b1dc322 100644
--- a/chromium/components/url_rewrite/browser/url_request_rewrite_rules_manager.cc
+++ b/chromium/components/url_rewrite/browser/url_request_rewrite_rules_manager.cc
@@ -5,6 +5,7 @@
#include "components/url_rewrite/browser/url_request_rewrite_rules_manager.h"
#include "components/url_rewrite/browser/url_request_rewrite_rules_validation.h"
+#include "content/public/browser/web_contents.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
namespace url_rewrite {
@@ -75,7 +76,11 @@ size_t UrlRequestRewriteRulesManager::GetUpdatersSizeForTesting() const {
UrlRequestRewriteRulesManager::Updater::Updater(
content::WebContents* web_contents,
const scoped_refptr<UrlRequestRewriteRules>& cached_rules)
- : content::WebContentsObserver(web_contents), cached_rules_(cached_rules) {}
+ : content::WebContentsObserver(web_contents), cached_rules_(cached_rules) {
+ web_contents->ForEachRenderFrameHost(base::BindRepeating(
+ &UrlRequestRewriteRulesManager::Updater::MaybeRegisterExistingRenderFrame,
+ base::Unretained(this)));
+}
UrlRequestRewriteRulesManager::Updater::~Updater() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -94,6 +99,15 @@ void UrlRequestRewriteRulesManager::Updater::OnRulesUpdated(
}
}
+void UrlRequestRewriteRulesManager::Updater::MaybeRegisterExistingRenderFrame(
+ content::RenderFrameHost* render_frame_host) {
+ if (render_frame_host->IsRenderFrameCreated()) {
+ // Call RenderFrameCreated() for frames that were created before this
+ // observer started observing this WebContents.
+ RenderFrameCreated(render_frame_host);
+ }
+}
+
void UrlRequestRewriteRulesManager::Updater::RenderFrameCreated(
content::RenderFrameHost* render_frame_host) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
diff --git a/chromium/components/url_rewrite/browser/url_request_rewrite_rules_manager.h b/chromium/components/url_rewrite/browser/url_request_rewrite_rules_manager.h
index 9fb8ee02134..b4a10fc2d5a 100644
--- a/chromium/components/url_rewrite/browser/url_request_rewrite_rules_manager.h
+++ b/chromium/components/url_rewrite/browser/url_request_rewrite_rules_manager.h
@@ -62,6 +62,11 @@ class UrlRequestRewriteRulesManager {
const scoped_refptr<UrlRequestRewriteRules>& cached_rules);
private:
+ // Callback used to iterate over the initial set of RenderFrameHosts in the
+ // WebContents.
+ void MaybeRegisterExistingRenderFrame(
+ content::RenderFrameHost* render_frame_host);
+
// content::WebContentsObserver implementation.
void RenderFrameCreated(
content::RenderFrameHost* render_frame_host) override;
diff --git a/chromium/components/url_rewrite/browser/url_request_rewrite_rules_manager_browsertest.cc b/chromium/components/url_rewrite/browser/url_request_rewrite_rules_manager_browsertest.cc
index 77a310ab766..9dec9ec63c7 100644
--- a/chromium/components/url_rewrite/browser/url_request_rewrite_rules_manager_browsertest.cc
+++ b/chromium/components/url_rewrite/browser/url_request_rewrite_rules_manager_browsertest.cc
@@ -125,4 +125,26 @@ IN_PROC_BROWSER_TEST_F(UrlRequestRewriteRulesManagerBrowserTest,
mojom::UrlRequestRewriteRules::New()));
}
+// Tests that adding a WebContents after a navigation has already occurred
+// does not trigger a DCHECK on destruction. This is a regression test for
+// https://crbug.com/1152930.
+IN_PROC_BROWSER_TEST_F(UrlRequestRewriteRulesManagerBrowserTest,
+ WebContentsAddedAfterNavigation) {
+ // Load a simple HTML page.
+ GURL url = embedded_test_server()->GetURL("/single_web_contents.html");
+ content::TestNavigationObserver navigation_observer(shell()->web_contents());
+ ASSERT_TRUE(NavigateToURL(shell(), url));
+ navigation_observer.Wait();
+
+ // Add the WebContents to the manager. At this point, an RFH has already been
+ // created. Eventually, it will be destroyed.
+ ASSERT_TRUE(url_request_rewrite_rules_manager_.AddWebContents(
+ shell()->web_contents()));
+
+ // Verify there were no inner WebContents created, and updaters size is 1.
+ ASSERT_THAT(shell()->web_contents()->GetInnerWebContents(), IsEmpty());
+ ASSERT_EQ(url_request_rewrite_rules_manager_.GetUpdatersSizeForTesting(), 1u);
+ ASSERT_TRUE(url_request_rewrite_rules_manager_.OnRulesUpdated(
+ mojom::UrlRequestRewriteRules::New()));
+}
} // namespace url_rewrite
diff --git a/chromium/components/user_manager/fake_user_manager.cc b/chromium/components/user_manager/fake_user_manager.cc
index eb7de9e67aa..0e218133fe2 100644
--- a/chromium/components/user_manager/fake_user_manager.cc
+++ b/chromium/components/user_manager/fake_user_manager.cc
@@ -283,7 +283,8 @@ bool FakeUserManager::IsLoggedInAsPublicAccount() const {
}
bool FakeUserManager::IsLoggedInAsGuest() const {
- return false;
+ const User* active_user = GetActiveUser();
+ return active_user && active_user->GetType() == USER_TYPE_GUEST;
}
bool FakeUserManager::IsLoggedInAsKioskApp() const {
@@ -381,7 +382,7 @@ const AccountId& FakeUserManager::GetGuestAccountId() const {
bool FakeUserManager::IsFirstExecAfterBoot() const {
return base::CommandLine::ForCurrentProcess()->HasSwitch(
- chromeos::switches::kFirstExecAfterBoot);
+ ash::switches::kFirstExecAfterBoot);
}
void FakeUserManager::AsyncRemoveCryptohome(const AccountId& account_id) const {
@@ -404,7 +405,7 @@ bool FakeUserManager::IsDeprecatedSupervisedAccountId(
bool FakeUserManager::HasBrowserRestarted() const {
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
return base::SysInfo::IsRunningOnChromeOS() &&
- command_line->HasSwitch(chromeos::switches::kLoginUser);
+ command_line->HasSwitch(ash::switches::kLoginUser);
}
const gfx::ImageSkia& FakeUserManager::GetResourceImagekiaNamed(int id) const {
diff --git a/chromium/components/user_manager/known_user.cc b/chromium/components/user_manager/known_user.cc
index fe75d87362e..cd508436016 100644
--- a/chromium/components/user_manager/known_user.cc
+++ b/chromium/components/user_manager/known_user.cc
@@ -12,6 +12,7 @@
#include "base/json/values_util.h"
#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
+#include "base/strings/string_piece_forward.h"
#include "base/time/time.h"
#include "base/values.h"
#include "components/account_id/account_id.h"
@@ -146,12 +147,11 @@ PrefService* GetLocalStateLegacy() {
}
// Checks if values in |dict| correspond with |account_id| identity.
-bool UserMatches(const AccountId& account_id,
- const base::DictionaryValue& dict) {
- std::string value;
- if (account_id.GetAccountType() != AccountType::UNKNOWN &&
- dict.GetString(kAccountTypeKey, &value) &&
- account_id.GetAccountType() != AccountId::StringToAccountType(value)) {
+bool UserMatches(const AccountId& account_id, const base::Value& dict) {
+ const std::string* account_type = dict.FindStringKey(kAccountTypeKey);
+ if (account_id.GetAccountType() != AccountType::UNKNOWN && account_type &&
+ account_id.GetAccountType() !=
+ AccountId::StringToAccountType(*account_type)) {
return false;
}
@@ -160,14 +160,14 @@ bool UserMatches(const AccountId& account_id,
// this function should likely be returning false even if the e-mail matches.
switch (account_id.GetAccountType()) {
case AccountType::GOOGLE: {
- bool has_gaia_id = dict.GetString(kGAIAIdKey, &value);
- if (has_gaia_id && account_id.GetGaiaId() == value)
+ const std::string* gaia_id = dict.FindStringKey(kGAIAIdKey);
+ if (gaia_id && account_id.GetGaiaId() == *gaia_id)
return true;
break;
}
case AccountType::ACTIVE_DIRECTORY: {
- bool has_obj_guid = dict.GetString(kObjGuidKey, &value);
- if (has_obj_guid && account_id.GetObjGuid() == value)
+ const std::string* obj_guid = dict.FindStringKey(kObjGuidKey);
+ if (obj_guid && account_id.GetObjGuid() == *obj_guid)
return true;
break;
}
@@ -175,32 +175,35 @@ bool UserMatches(const AccountId& account_id,
}
}
- bool has_email = dict.GetString(kCanonicalEmail, &value);
- if (has_email && account_id.GetUserEmail() == value)
+ const std::string* email = dict.FindStringKey(kCanonicalEmail);
+ if (email && account_id.GetUserEmail() == *email)
return true;
return false;
}
// Fills relevant |dict| values based on |account_id|.
-void UpdateIdentity(const AccountId& account_id, base::DictionaryValue& dict) {
+// TODO(crbug.com/1287074): Consider a refactor to use base::Value::DictStorage.
+// This would require |dict| to not be modified in-place.
+void UpdateIdentity(const AccountId& account_id, base::Value& dict) {
+ DCHECK(dict.is_dict());
if (!account_id.GetUserEmail().empty())
- dict.SetString(kCanonicalEmail, account_id.GetUserEmail());
+ dict.SetStringKey(kCanonicalEmail, account_id.GetUserEmail());
switch (account_id.GetAccountType()) {
case AccountType::GOOGLE:
if (!account_id.GetGaiaId().empty())
- dict.SetString(kGAIAIdKey, account_id.GetGaiaId());
+ dict.SetStringKey(kGAIAIdKey, account_id.GetGaiaId());
break;
case AccountType::ACTIVE_DIRECTORY:
if (!account_id.GetObjGuid().empty())
- dict.SetString(kObjGuidKey, account_id.GetObjGuid());
+ dict.SetStringKey(kObjGuidKey, account_id.GetObjGuid());
break;
case AccountType::UNKNOWN:
return;
}
- dict.SetString(kAccountTypeKey,
- AccountId::AccountTypeToString(account_id.GetAccountType()));
+ dict.SetStringKey(kAccountTypeKey, AccountId::AccountTypeToString(
+ account_id.GetAccountType()));
}
} // namespace
@@ -211,37 +214,31 @@ KnownUser::KnownUser(PrefService* local_state) : local_state_(local_state) {
KnownUser::~KnownUser() = default;
-bool KnownUser::FindPrefs(const AccountId& account_id,
- const base::DictionaryValue** out_value) {
+const base::Value* KnownUser::FindPrefs(const AccountId& account_id) const {
// UserManager is usually NULL in unit tests.
if (account_id.GetAccountType() != AccountType::ACTIVE_DIRECTORY &&
UserManager::IsInitialized() &&
UserManager::Get()->IsUserNonCryptohomeDataEphemeral(account_id)) {
- return false;
+ return nullptr;
}
if (!account_id.is_valid())
- return false;
+ return nullptr;
- const base::ListValue* known_users = local_state_->GetList(kKnownUsers);
- for (const base::Value& element_value : known_users->GetList()) {
+ const base::Value* known_users = local_state_->GetList(kKnownUsers);
+ for (const base::Value& element_value : known_users->GetListDeprecated()) {
if (element_value.is_dict()) {
- const base::DictionaryValue& element =
- base::Value::AsDictionaryValue(element_value);
- if (UserMatches(account_id, element)) {
- if (out_value)
- *out_value = &element;
-
- return true;
+ if (UserMatches(account_id, element_value)) {
+ return &element_value;
}
}
}
- return false;
+ return nullptr;
}
-void KnownUser::UpdatePrefs(const AccountId& account_id,
- const base::DictionaryValue& values,
- bool clear) {
+void KnownUser::SetPath(const AccountId& account_id,
+ const std::string& path,
+ absl::optional<base::Value> opt_value) {
// UserManager is usually NULL in unit tests.
if (account_id.GetAccountType() != AccountType::ACTIVE_DIRECTORY &&
UserManager::IsInitialized() &&
@@ -253,109 +250,120 @@ void KnownUser::UpdatePrefs(const AccountId& account_id,
return;
ListPrefUpdate update(local_state_, kKnownUsers);
- for (base::Value& element_value : update->GetList()) {
+ for (base::Value& element_value : update->GetListDeprecated()) {
if (element_value.is_dict()) {
- base::DictionaryValue* element =
- static_cast<base::DictionaryValue*>(&element_value);
- if (UserMatches(account_id, *element)) {
- if (clear)
- element->DictClear();
- element->MergeDictionary(&values);
- UpdateIdentity(account_id, *element);
+ if (UserMatches(account_id, element_value)) {
+ if (opt_value.has_value())
+ element_value.SetPath(path, std::move(opt_value).value());
+ else
+ element_value.RemovePath(path);
+
+ UpdateIdentity(account_id, element_value);
return;
}
}
}
- std::unique_ptr<base::DictionaryValue> new_value(new base::DictionaryValue());
- new_value->MergeDictionary(&values);
- UpdateIdentity(account_id, *new_value);
- update->Append(std::move(new_value));
+ if (!opt_value.has_value())
+ return;
+
+ base::Value new_dict(base::Value::Type::DICTIONARY);
+ new_dict.SetPath(path, std::move(opt_value).value());
+ UpdateIdentity(account_id, new_dict);
+ update->Append(std::move(new_dict));
}
-bool KnownUser::GetStringPref(const AccountId& account_id,
- const std::string& path,
- std::string* out_value) {
- const base::DictionaryValue* user_pref_dict = nullptr;
- if (!FindPrefs(account_id, &user_pref_dict))
- return false;
+const std::string* KnownUser::FindStringPath(const AccountId& account_id,
+ base::StringPiece path) const {
+ const base::Value* user_pref_dict = FindPrefs(account_id);
+ if (!user_pref_dict)
+ return nullptr;
+
+ return user_pref_dict->FindStringPath(path);
+}
- return user_pref_dict->GetString(path, out_value);
+bool KnownUser::GetStringPrefForTest(const AccountId& account_id,
+ const std::string& path,
+ std::string* out_value) {
+ const std::string* res = FindStringPath(account_id, path);
+ if (out_value && res)
+ *out_value = *res;
+ return res;
}
void KnownUser::SetStringPref(const AccountId& account_id,
const std::string& path,
const std::string& in_value) {
- base::DictionaryValue dict;
- dict.SetString(path, in_value);
- UpdatePrefs(account_id, dict, false);
+ SetPath(account_id, path, base::Value(in_value));
}
-bool KnownUser::GetBooleanPref(const AccountId& account_id,
- const std::string& path,
- bool* out_value) {
- const base::DictionaryValue* user_pref_dict = nullptr;
- if (!FindPrefs(account_id, &user_pref_dict))
- return false;
+absl::optional<bool> KnownUser::FindBoolPath(const AccountId& account_id,
+ base::StringPiece path) const {
+ const base::Value* user_pref_dict = FindPrefs(account_id);
+ if (!user_pref_dict)
+ return absl::nullopt;
- absl::optional<bool> ret_value = user_pref_dict->FindBoolPath(path);
- if (!ret_value.has_value())
- return false;
+ return user_pref_dict->FindBoolPath(path);
+}
+
+bool KnownUser::GetBooleanPrefForTest(const AccountId& account_id,
+ const std::string& path,
+ bool* out_value) {
+ auto opt_val = FindBoolPath(account_id, path);
+ if (out_value && opt_val.has_value())
+ *out_value = opt_val.value();
- *out_value = ret_value.value();
- return true;
+ return opt_val.has_value();
}
void KnownUser::SetBooleanPref(const AccountId& account_id,
const std::string& path,
const bool in_value) {
- base::DictionaryValue dict;
- dict.SetBoolean(path, in_value);
- UpdatePrefs(account_id, dict, false);
+ SetPath(account_id, path, base::Value(in_value));
}
-bool KnownUser::GetIntegerPref(const AccountId& account_id,
- const std::string& path,
- int* out_value) {
- const base::DictionaryValue* user_pref_dict = nullptr;
- if (!FindPrefs(account_id, &user_pref_dict))
- return false;
- return user_pref_dict->GetInteger(path, out_value);
+absl::optional<int> KnownUser::FindIntPath(const AccountId& account_id,
+ base::StringPiece path) const {
+ const base::Value* user_pref_dict = FindPrefs(account_id);
+ if (!user_pref_dict)
+ return absl::nullopt;
+
+ return user_pref_dict->FindIntPath(path);
+}
+
+bool KnownUser::GetIntegerPrefForTest(const AccountId& account_id,
+ const std::string& path,
+ int* out_value) {
+ auto opt_val = FindIntPath(account_id, path);
+ if (out_value && opt_val.has_value())
+ *out_value = opt_val.value();
+
+ return opt_val.has_value();
}
void KnownUser::SetIntegerPref(const AccountId& account_id,
const std::string& path,
const int in_value) {
- base::DictionaryValue dict;
- dict.SetInteger(path, in_value);
- UpdatePrefs(account_id, dict, false);
+ SetPath(account_id, path, base::Value(in_value));
}
bool KnownUser::GetPref(const AccountId& account_id,
const std::string& path,
const base::Value** out_value) {
- const base::DictionaryValue* user_pref_dict = nullptr;
- if (!FindPrefs(account_id, &user_pref_dict))
+ const base::Value* user_pref_dict = FindPrefs(account_id);
+ if (!user_pref_dict)
return false;
*out_value = user_pref_dict->FindPath(path);
return *out_value != nullptr;
}
-void KnownUser::SetPref(const AccountId& account_id,
- const std::string& path,
- base::Value in_value) {
- base::DictionaryValue dict;
- dict.SetPath(path, std::move(in_value));
- UpdatePrefs(account_id, dict, false);
-}
-
void KnownUser::RemovePref(const AccountId& account_id,
const std::string& path) {
// Prevent removing keys that are used internally.
for (const std::string& key : kReservedKeys)
CHECK_NE(path, key);
- ClearPref(account_id, path);
+ SetPath(account_id, path, absl::nullopt);
}
AccountId KnownUser::GetAccountId(const std::string& user_email,
@@ -376,52 +384,50 @@ AccountId KnownUser::GetAccountId(const std::string& user_email,
return result;
}
- std::string stored_gaia_id;
- std::string stored_obj_guid;
const std::string sanitized_email =
user_email.empty()
? std::string()
: gaia::CanonicalizeEmail(gaia::SanitizeEmail(user_email));
if (!sanitized_email.empty()) {
- if (GetStringPref(AccountId::FromUserEmail(sanitized_email), kGAIAIdKey,
- &stored_gaia_id)) {
+ const AccountId account_id(AccountId::FromUserEmail(sanitized_email));
+ if (const std::string* stored_gaia_id =
+ FindStringPath(account_id, kGAIAIdKey)) {
if (!id.empty()) {
DCHECK(account_type == AccountType::GOOGLE);
- if (id != stored_gaia_id)
+ if (id != *stored_gaia_id)
LOG(ERROR) << "User gaia id has changed. Sync will not work.";
}
// gaia_id is associated with cryptohome.
- return AccountId::FromUserEmailGaiaId(sanitized_email, stored_gaia_id);
+ return AccountId::FromUserEmailGaiaId(sanitized_email, *stored_gaia_id);
}
- if (GetStringPref(AccountId::FromUserEmail(sanitized_email), kObjGuidKey,
- &stored_obj_guid)) {
+ if (const std::string* stored_obj_guid =
+ FindStringPath(account_id, kObjGuidKey)) {
if (!id.empty()) {
DCHECK(account_type == AccountType::ACTIVE_DIRECTORY);
- if (id != stored_obj_guid)
+ if (id != *stored_obj_guid)
LOG(ERROR) << "User object guid has changed. Sync will not work.";
}
// obj_guid is associated with cryptohome.
return AccountId::AdFromUserEmailObjGuid(sanitized_email,
- stored_obj_guid);
+ *stored_obj_guid);
}
}
- std::string stored_email;
switch (account_type) {
case AccountType::GOOGLE:
- if (GetStringPref(AccountId::FromGaiaId(id), kCanonicalEmail,
- &stored_email)) {
- return AccountId::FromUserEmailGaiaId(stored_email, id);
+ if (const std::string* stored_email =
+ FindStringPath(AccountId::FromGaiaId(id), kCanonicalEmail)) {
+ return AccountId::FromUserEmailGaiaId(*stored_email, id);
}
return AccountId::FromUserEmailGaiaId(sanitized_email, id);
case AccountType::ACTIVE_DIRECTORY:
- if (GetStringPref(AccountId::AdFromObjGuid(id), kCanonicalEmail,
- &stored_email)) {
- return AccountId::AdFromUserEmailObjGuid(stored_email, id);
+ if (const std::string* stored_email =
+ FindStringPath(AccountId::AdFromObjGuid(id), kCanonicalEmail)) {
+ return AccountId::AdFromUserEmailObjGuid(*stored_email, id);
}
return AccountId::AdFromUserEmailObjGuid(sanitized_email, id);
case AccountType::UNKNOWN:
@@ -434,32 +440,29 @@ AccountId KnownUser::GetAccountId(const std::string& user_email,
std::vector<AccountId> KnownUser::GetKnownAccountIds() {
std::vector<AccountId> result;
- const base::ListValue* known_users = local_state_->GetList(kKnownUsers);
- for (const base::Value& element_value : known_users->GetList()) {
+ const base::Value* known_users = local_state_->GetList(kKnownUsers);
+ for (const base::Value& element_value : known_users->GetListDeprecated()) {
if (element_value.is_dict()) {
- const base::DictionaryValue& element =
- base::Value::AsDictionaryValue(element_value);
- std::string email;
- std::string gaia_id;
- std::string obj_guid;
- const bool has_email = element.GetString(kCanonicalEmail, &email);
- const bool has_gaia_id = element.GetString(kGAIAIdKey, &gaia_id);
- const bool has_obj_guid = element.GetString(kObjGuidKey, &obj_guid);
+ const std::string* email = element_value.FindStringKey(kCanonicalEmail);
+ const std::string* gaia_id = element_value.FindStringKey(kGAIAIdKey);
+ const std::string* obj_guid = element_value.FindStringKey(kObjGuidKey);
AccountType account_type = AccountType::GOOGLE;
- std::string account_type_string;
- if (element.GetString(kAccountTypeKey, &account_type_string)) {
- account_type = AccountId::StringToAccountType(account_type_string);
+ if (const std::string* account_type_string =
+ element_value.FindStringKey(kAccountTypeKey)) {
+ account_type = AccountId::StringToAccountType(*account_type_string);
}
switch (account_type) {
case AccountType::GOOGLE:
- if (has_email || has_gaia_id) {
- result.push_back(AccountId::FromUserEmailGaiaId(email, gaia_id));
+ if (email || gaia_id) {
+ result.push_back(AccountId::FromUserEmailGaiaId(
+ email ? *email : std::string(),
+ gaia_id ? *gaia_id : std::string()));
}
break;
case AccountType::ACTIVE_DIRECTORY:
- if (has_email && has_obj_guid) {
+ if (email && obj_guid) {
result.push_back(
- AccountId::AdFromUserEmailObjGuid(email, obj_guid));
+ AccountId::AdFromUserEmailObjGuid(*email, *obj_guid));
}
break;
default:
@@ -504,9 +507,8 @@ void KnownUser::UpdateId(const AccountId& account_id) {
AccountId::AccountTypeToString(account_id.GetAccountType()));
}
-bool KnownUser::FindGaiaID(const AccountId& account_id,
- std::string* out_value) {
- return GetStringPref(account_id, kGAIAIdKey, out_value);
+const std::string* KnownUser::FindGaiaID(const AccountId& account_id) {
+ return FindStringPath(account_id, kGAIAIdKey);
}
void KnownUser::SetDeviceId(const AccountId& account_id,
@@ -519,10 +521,9 @@ void KnownUser::SetDeviceId(const AccountId& account_id,
}
std::string KnownUser::GetDeviceId(const AccountId& account_id) {
- std::string device_id;
- if (GetStringPref(account_id, kDeviceId, &device_id)) {
- return device_id;
- }
+ const std::string* device_id = FindStringPath(account_id, kDeviceId);
+ if (device_id)
+ return *device_id;
return std::string();
}
@@ -532,10 +533,9 @@ void KnownUser::SetGAPSCookie(const AccountId& account_id,
}
std::string KnownUser::GetGAPSCookie(const AccountId& account_id) {
- std::string gaps_cookie;
- if (GetStringPref(account_id, kGAPSCookie, &gaps_cookie)) {
- return gaps_cookie;
- }
+ const std::string* gaps_cookie = FindStringPath(account_id, kGAPSCookie);
+ if (gaps_cookie)
+ return *gaps_cookie;
return std::string();
}
@@ -545,10 +545,7 @@ void KnownUser::UpdateUsingSAML(const AccountId& account_id,
}
bool KnownUser::IsUsingSAML(const AccountId& account_id) {
- bool using_saml;
- if (GetBooleanPref(account_id, kUsingSAMLKey, &using_saml))
- return using_saml;
- return false;
+ return FindBoolPath(account_id, kUsingSAMLKey).value_or(false);
}
void KnownUser::UpdateIsUsingSAMLPrincipalsAPI(
@@ -559,12 +556,7 @@ void KnownUser::UpdateIsUsingSAMLPrincipalsAPI(
}
bool KnownUser::GetIsUsingSAMLPrincipalsAPI(const AccountId& account_id) {
- bool is_using_saml_principals_api;
- if (GetBooleanPref(account_id, kIsUsingSAMLPrincipalsAPI,
- &is_using_saml_principals_api)) {
- return is_using_saml_principals_api;
- }
- return false;
+ return FindBoolPath(account_id, kIsUsingSAMLPrincipalsAPI).value_or(false);
}
void KnownUser::SetProfileRequiresPolicy(const AccountId& account_id,
@@ -576,16 +568,17 @@ void KnownUser::SetProfileRequiresPolicy(const AccountId& account_id,
ProfileRequiresPolicy KnownUser::GetProfileRequiresPolicy(
const AccountId& account_id) {
- bool requires_policy;
- if (GetBooleanPref(account_id, kProfileRequiresPolicy, &requires_policy)) {
- return requires_policy ? ProfileRequiresPolicy::kPolicyRequired
- : ProfileRequiresPolicy::kNoPolicyRequired;
+ absl::optional<bool> requires_policy =
+ FindBoolPath(account_id, kProfileRequiresPolicy);
+ if (requires_policy.has_value()) {
+ return requires_policy.value() ? ProfileRequiresPolicy::kPolicyRequired
+ : ProfileRequiresPolicy::kNoPolicyRequired;
}
return ProfileRequiresPolicy::kUnknown;
}
void KnownUser::ClearProfileRequiresPolicy(const AccountId& account_id) {
- ClearPref(account_id, kProfileRequiresPolicy);
+ SetPath(account_id, kProfileRequiresPolicy, absl::nullopt);
}
void KnownUser::UpdateReauthReason(const AccountId& account_id,
@@ -593,14 +586,15 @@ void KnownUser::UpdateReauthReason(const AccountId& account_id,
SetIntegerPref(account_id, kReauthReasonKey, reauth_reason);
}
-bool KnownUser::FindReauthReason(const AccountId& account_id, int* out_value) {
- return GetIntegerPref(account_id, kReauthReasonKey, out_value);
+absl::optional<int> KnownUser::FindReauthReason(
+ const AccountId& account_id) const {
+ return FindIntPath(account_id, kReauthReasonKey);
}
void KnownUser::SetChallengeResponseKeys(const AccountId& account_id,
base::Value value) {
DCHECK(value.is_list());
- SetPref(account_id, kChallengeResponseKeys, std::move(value));
+ SetPath(account_id, kChallengeResponseKeys, std::move(value));
}
base::Value KnownUser::GetChallengeResponseKeys(const AccountId& account_id) {
@@ -612,7 +606,7 @@ base::Value KnownUser::GetChallengeResponseKeys(const AccountId& account_id) {
void KnownUser::SetLastOnlineSignin(const AccountId& account_id,
base::Time time) {
- SetPref(account_id, kLastOnlineSignin, base::TimeToValue(time));
+ SetPath(account_id, kLastOnlineSignin, base::TimeToValue(time));
}
base::Time KnownUser::GetLastOnlineSignin(const AccountId& account_id) {
@@ -629,9 +623,9 @@ void KnownUser::SetOfflineSigninLimit(
const AccountId& account_id,
absl::optional<base::TimeDelta> time_delta) {
if (!time_delta) {
- ClearPref(account_id, kOfflineSigninLimit);
+ SetPath(account_id, kOfflineSigninLimit, absl::nullopt);
} else {
- SetPref(account_id, kOfflineSigninLimit,
+ SetPath(account_id, kOfflineSigninLimit,
base::TimeDeltaToValue(time_delta.value()));
}
}
@@ -651,10 +645,7 @@ void KnownUser::SetIsEnterpriseManaged(const AccountId& account_id,
}
bool KnownUser::GetIsEnterpriseManaged(const AccountId& account_id) {
- bool is_enterprise_managed;
- if (GetBooleanPref(account_id, kIsEnterpriseManaged, &is_enterprise_managed))
- return is_enterprise_managed;
- return false;
+ return FindBoolPath(account_id, kIsEnterpriseManaged).value_or(false);
}
void KnownUser::SetAccountManager(const AccountId& account_id,
@@ -662,9 +653,8 @@ void KnownUser::SetAccountManager(const AccountId& account_id,
SetStringPref(account_id, kAccountManager, manager);
}
-bool KnownUser::GetAccountManager(const AccountId& account_id,
- std::string* manager) {
- return GetStringPref(account_id, kAccountManager, manager);
+const std::string* KnownUser::GetAccountManager(const AccountId& account_id) {
+ return FindStringPath(account_id, kAccountManager);
}
void KnownUser::SetUserLastLoginInputMethodId(
@@ -673,9 +663,9 @@ void KnownUser::SetUserLastLoginInputMethodId(
SetStringPref(account_id, kLastInputMethod, input_method_id);
}
-bool KnownUser::GetUserLastInputMethodId(const AccountId& account_id,
- std::string* input_method_id) {
- return GetStringPref(account_id, kLastInputMethod, input_method_id);
+const std::string* KnownUser::GetUserLastInputMethodId(
+ const AccountId& account_id) {
+ return FindStringPath(account_id, kLastInputMethod);
}
void KnownUser::SetUserPinLength(const AccountId& account_id, int pin_length) {
@@ -683,19 +673,12 @@ void KnownUser::SetUserPinLength(const AccountId& account_id, int pin_length) {
}
int KnownUser::GetUserPinLength(const AccountId& account_id) {
- int pin_length = 0;
- if (GetIntegerPref(account_id, kPinAutosubmitLength, &pin_length))
- return pin_length;
- return 0;
+ return FindIntPath(account_id, kPinAutosubmitLength).value_or(0);
}
bool KnownUser::PinAutosubmitIsBackfillNeeded(const AccountId& account_id) {
- bool backfill_needed;
- if (GetBooleanPref(account_id, kPinAutosubmitBackfillNeeded,
- &backfill_needed))
- return backfill_needed;
// If the pref is not set, the pref needs to be backfilled.
- return true;
+ return FindBoolPath(account_id, kPinAutosubmitBackfillNeeded).value_or(true);
}
void KnownUser::PinAutosubmitSetBackfillNotNeeded(const AccountId& account_id) {
@@ -712,19 +695,16 @@ void KnownUser::SetPasswordSyncToken(const AccountId& account_id,
SetStringPref(account_id, kPasswordSyncToken, token);
}
-std::string KnownUser::GetPasswordSyncToken(const AccountId& account_id) {
- std::string token;
- if (GetStringPref(account_id, kPasswordSyncToken, &token))
- return token;
- // Return empty string if sync token was not set for the account yet.
- return std::string();
+const std::string* KnownUser::GetPasswordSyncToken(
+ const AccountId& account_id) const {
+ return FindStringPath(account_id, kPasswordSyncToken);
}
void KnownUser::SetOnboardingCompletedVersion(
const AccountId& account_id,
const absl::optional<base::Version> version) {
if (!version) {
- ClearPref(account_id, kOnboardingCompletedVersion);
+ SetPath(account_id, kOnboardingCompletedVersion, absl::nullopt);
} else {
SetStringPref(account_id, kOnboardingCompletedVersion,
version.value().GetString());
@@ -733,11 +713,13 @@ void KnownUser::SetOnboardingCompletedVersion(
absl::optional<base::Version> KnownUser::GetOnboardingCompletedVersion(
const AccountId& account_id) {
- std::string str_version;
- if (!GetStringPref(account_id, kOnboardingCompletedVersion, &str_version))
+ const std::string* str_version =
+ FindStringPath(account_id, kOnboardingCompletedVersion);
+
+ if (!str_version)
return absl::nullopt;
- base::Version version = base::Version(str_version);
+ base::Version version = base::Version(*str_version);
if (!version.IsValid())
return absl::nullopt;
return version;
@@ -745,7 +727,7 @@ absl::optional<base::Version> KnownUser::GetOnboardingCompletedVersion(
void KnownUser::RemoveOnboardingCompletedVersionForTests(
const AccountId& account_id) {
- ClearPref(account_id, kOnboardingCompletedVersion);
+ SetPath(account_id, kOnboardingCompletedVersion, absl::nullopt);
}
void KnownUser::SetPendingOnboardingScreen(const AccountId& account_id,
@@ -754,29 +736,20 @@ void KnownUser::SetPendingOnboardingScreen(const AccountId& account_id,
}
void KnownUser::RemovePendingOnboardingScreen(const AccountId& account_id) {
- ClearPref(account_id, kPendingOnboardingScreen);
+ SetPath(account_id, kPendingOnboardingScreen, absl::nullopt);
}
std::string KnownUser::GetPendingOnboardingScreen(const AccountId& account_id) {
- std::string screen;
- if (GetStringPref(account_id, kPendingOnboardingScreen, &screen))
- return screen;
+ if (const std::string* screen =
+ FindStringPath(account_id, kPendingOnboardingScreen)) {
+ return *screen;
+ }
// Return empty string if no screen is pending.
return std::string();
}
-void KnownUser::ClearPref(const AccountId& account_id,
- const std::string& path) {
- const base::DictionaryValue* user_pref_dict = nullptr;
- if (!FindPrefs(account_id, &user_pref_dict))
- return;
-
- base::Value updated_user_pref = user_pref_dict->Clone();
- base::DictionaryValue* updated_user_pref_dict;
- updated_user_pref.GetAsDictionary(&updated_user_pref_dict);
-
- updated_user_pref_dict->RemovePath(path);
- UpdatePrefs(account_id, *updated_user_pref_dict, true);
+bool KnownUser::UserExists(const AccountId& account_id) {
+ return FindPrefs(account_id);
}
void KnownUser::RemovePrefs(const AccountId& account_id) {
@@ -784,14 +757,11 @@ void KnownUser::RemovePrefs(const AccountId& account_id) {
return;
ListPrefUpdate update(local_state_, kKnownUsers);
- base::Value::ListView update_view = update->GetList();
+ base::Value::ListView update_view = update->GetListDeprecated();
for (auto it = update_view.begin(); it != update_view.end(); ++it) {
- base::DictionaryValue* element = nullptr;
- if (it->GetAsDictionary(&element)) {
- if (UserMatches(account_id, *element)) {
- update->EraseListIter(it);
- break;
- }
+ if (UserMatches(account_id, *it)) {
+ update->EraseListIter(it);
+ break;
}
}
}
@@ -809,7 +779,7 @@ void KnownUser::CleanEphemeralUsers() {
void KnownUser::CleanObsoletePrefs() {
ListPrefUpdate update(local_state_, kKnownUsers);
- for (base::Value& user_entry : update.Get()->GetList()) {
+ for (base::Value& user_entry : update.Get()->GetListDeprecated()) {
if (!user_entry.is_dict())
continue;
for (const std::string& key : kObsoleteKeys)
@@ -825,35 +795,6 @@ void KnownUser::RegisterPrefs(PrefRegistrySimple* registry) {
// --- Legacy interface ---
namespace known_user {
-bool FindPrefs(const AccountId& account_id,
- const base::DictionaryValue** out_value) {
- PrefService* local_state = GetLocalStateLegacy();
- // Local State may not be initialized in tests.
- if (!local_state)
- return false;
- return KnownUser(local_state).FindPrefs(account_id, out_value);
-}
-
-void UpdatePrefs(const AccountId& account_id,
- const base::DictionaryValue& values,
- bool clear) {
- PrefService* local_state = GetLocalStateLegacy();
- // Local State may not be initialized in tests.
- if (!local_state)
- return;
- return KnownUser(local_state).UpdatePrefs(account_id, values, clear);
-}
-
-bool GetStringPref(const AccountId& account_id,
- const std::string& path,
- std::string* out_value) {
- PrefService* local_state = GetLocalStateLegacy();
- // Local State may not be initialized in tests.
- if (!local_state)
- return false;
- return KnownUser(local_state).GetStringPref(account_id, path, out_value);
-}
-
void SetStringPref(const AccountId& account_id,
const std::string& path,
const std::string& in_value) {
@@ -864,16 +805,6 @@ void SetStringPref(const AccountId& account_id,
return KnownUser(local_state).SetStringPref(account_id, path, in_value);
}
-bool GetBooleanPref(const AccountId& account_id,
- const std::string& path,
- bool* out_value) {
- PrefService* local_state = GetLocalStateLegacy();
- // Local State may not be initialized in tests.
- if (!local_state)
- return false;
- return KnownUser(local_state).GetBooleanPref(account_id, path, out_value);
-}
-
void SetBooleanPref(const AccountId& account_id,
const std::string& path,
const bool in_value) {
@@ -891,7 +822,11 @@ bool GetIntegerPref(const AccountId& account_id,
// Local State may not be initialized in tests.
if (!local_state)
return false;
- return KnownUser(local_state).GetIntegerPref(account_id, path, out_value);
+ absl::optional<int> val =
+ KnownUser(local_state).FindIntPath(account_id, path);
+ if (out_value && val.has_value())
+ *out_value = val.value();
+ return val.has_value();
}
void SetIntegerPref(const AccountId& account_id,
@@ -914,16 +849,6 @@ bool GetPref(const AccountId& account_id,
return KnownUser(local_state).GetPref(account_id, path, out_value);
}
-void SetPref(const AccountId& account_id,
- const std::string& path,
- base::Value in_value) {
- PrefService* local_state = GetLocalStateLegacy();
- // Local State may not be initialized in tests.
- if (!local_state)
- return;
- return KnownUser(local_state).SetPref(account_id, path, std::move(in_value));
-}
-
void RemovePref(const AccountId& account_id, const std::string& path) {
PrefService* local_state = GetLocalStateLegacy();
// Local State may not be initialized in tests.
@@ -984,14 +909,6 @@ std::vector<AccountId> GetKnownAccountIds() {
return KnownUser(local_state).GetKnownAccountIds();
}
-void SaveKnownUser(const AccountId& account_id) {
- PrefService* local_state = GetLocalStateLegacy();
- // Local State may not be initialized in tests.
- if (!local_state)
- return;
- return KnownUser(local_state).SaveKnownUser(account_id);
-}
-
void UpdateId(const AccountId& account_id) {
PrefService* local_state = GetLocalStateLegacy();
// Local State may not be initialized in tests.
@@ -1000,14 +917,6 @@ void UpdateId(const AccountId& account_id) {
return KnownUser(local_state).UpdateId(account_id);
}
-bool FindGaiaID(const AccountId& account_id, std::string* out_value) {
- PrefService* local_state = GetLocalStateLegacy();
- // Local State may not be initialized in tests.
- if (!local_state)
- return false;
- return KnownUser(local_state).FindGaiaID(account_id, out_value);
-}
-
void SetDeviceId(const AccountId& account_id, const std::string& device_id) {
PrefService* local_state = GetLocalStateLegacy();
// Local State may not be initialized in tests.
@@ -1024,265 +933,5 @@ std::string GetDeviceId(const AccountId& account_id) {
return KnownUser(local_state).GetDeviceId(account_id);
}
-void SetGAPSCookie(const AccountId& account_id,
- const std::string& gaps_cookie) {
- PrefService* local_state = GetLocalStateLegacy();
- // Local State may not be initialized in tests.
- if (!local_state)
- return;
- return KnownUser(local_state).SetGAPSCookie(account_id, gaps_cookie);
-}
-
-std::string GetGAPSCookie(const AccountId& account_id) {
- PrefService* local_state = GetLocalStateLegacy();
- // Local State may not be initialized in tests.
- if (!local_state)
- return std::string();
- return KnownUser(local_state).GetGAPSCookie(account_id);
-}
-
-void UpdateUsingSAML(const AccountId& account_id, const bool using_saml) {
- PrefService* local_state = GetLocalStateLegacy();
- // Local State may not be initialized in tests.
- if (!local_state)
- return;
- return KnownUser(local_state).UpdateUsingSAML(account_id, using_saml);
-}
-
-bool IsUsingSAML(const AccountId& account_id) {
- PrefService* local_state = GetLocalStateLegacy();
- // Local State may not be initialized in tests.
- if (!local_state)
- return false;
- return KnownUser(local_state).IsUsingSAML(account_id);
-}
-
-void USER_MANAGER_EXPORT
-UpdateIsUsingSAMLPrincipalsAPI(const AccountId& account_id,
- bool is_using_saml_principals_api) {
- PrefService* local_state = GetLocalStateLegacy();
- // Local State may not be initialized in tests.
- if (!local_state)
- return;
- return KnownUser(local_state)
- .UpdateIsUsingSAMLPrincipalsAPI(account_id, is_using_saml_principals_api);
-}
-
-bool USER_MANAGER_EXPORT
-GetIsUsingSAMLPrincipalsAPI(const AccountId& account_id) {
- PrefService* local_state = GetLocalStateLegacy();
- // Local State may not be initialized in tests.
- if (!local_state)
- return false;
- return KnownUser(local_state).GetIsUsingSAMLPrincipalsAPI(account_id);
-}
-
-void SetProfileRequiresPolicy(const AccountId& account_id,
- ProfileRequiresPolicy required) {
- PrefService* local_state = GetLocalStateLegacy();
- // Local State may not be initialized in tests.
- if (!local_state)
- return;
- return KnownUser(local_state).SetProfileRequiresPolicy(account_id, required);
-}
-
-ProfileRequiresPolicy GetProfileRequiresPolicy(const AccountId& account_id) {
- PrefService* local_state = GetLocalStateLegacy();
- // Local State may not be initialized in tests.
- if (!local_state)
- return ProfileRequiresPolicy::kUnknown;
- return KnownUser(local_state).GetProfileRequiresPolicy(account_id);
-}
-
-void ClearProfileRequiresPolicy(const AccountId& account_id) {
- PrefService* local_state = GetLocalStateLegacy();
- // Local State may not be initialized in tests.
- if (!local_state)
- return;
- return KnownUser(local_state).ClearProfileRequiresPolicy(account_id);
-}
-
-void UpdateReauthReason(const AccountId& account_id, const int reauth_reason) {
- PrefService* local_state = GetLocalStateLegacy();
- // Local State may not be initialized in tests.
- if (!local_state)
- return;
- return KnownUser(local_state).UpdateReauthReason(account_id, reauth_reason);
-}
-
-bool FindReauthReason(const AccountId& account_id, int* out_value) {
- PrefService* local_state = GetLocalStateLegacy();
- // Local State may not be initialized in tests.
- if (!local_state)
- return false;
- return KnownUser(local_state).FindReauthReason(account_id, out_value);
-}
-
-void SetChallengeResponseKeys(const AccountId& account_id, base::Value value) {
- PrefService* local_state = GetLocalStateLegacy();
- // Local State may not be initialized in tests.
- if (!local_state)
- return;
- return KnownUser(local_state)
- .SetChallengeResponseKeys(account_id, std::move(value));
-}
-
-base::Value GetChallengeResponseKeys(const AccountId& account_id) {
- PrefService* local_state = GetLocalStateLegacy();
- // Local State may not be initialized in tests.
- if (!local_state)
- return base::Value();
- return KnownUser(local_state).GetChallengeResponseKeys(account_id);
-}
-
-void SetLastOnlineSignin(const AccountId& account_id, base::Time time) {
- PrefService* local_state = GetLocalStateLegacy();
- // Local State may not be initialized in tests.
- if (!local_state)
- return;
- return KnownUser(local_state).SetLastOnlineSignin(account_id, time);
-}
-
-base::Time GetLastOnlineSignin(const AccountId& account_id) {
- PrefService* local_state = GetLocalStateLegacy();
- // Local State may not be initialized in tests.
- if (!local_state)
- return base::Time();
- return KnownUser(local_state).GetLastOnlineSignin(account_id);
-}
-
-void SetOfflineSigninLimit(const AccountId& account_id,
- absl::optional<base::TimeDelta> time_delta) {
- PrefService* local_state = GetLocalStateLegacy();
- // Local State may not be initialized in tests.
- if (!local_state)
- return;
- return KnownUser(local_state).SetOfflineSigninLimit(account_id, time_delta);
-}
-
-absl::optional<base::TimeDelta> GetOfflineSigninLimit(
- const AccountId& account_id) {
- PrefService* local_state = GetLocalStateLegacy();
- // Local State may not be initialized in tests.
- if (!local_state)
- return absl::nullopt;
- return KnownUser(local_state).GetOfflineSigninLimit(account_id);
-}
-
-void SetIsEnterpriseManaged(const AccountId& account_id,
- bool is_enterprise_managed) {
- PrefService* local_state = GetLocalStateLegacy();
- // Local State may not be initialized in tests.
- if (!local_state)
- return;
- return KnownUser(local_state)
- .SetIsEnterpriseManaged(account_id, is_enterprise_managed);
-}
-
-bool GetIsEnterpriseManaged(const AccountId& account_id) {
- PrefService* local_state = GetLocalStateLegacy();
- // Local State may not be initialized in tests.
- if (!local_state)
- return false;
- return KnownUser(local_state).GetIsEnterpriseManaged(account_id);
-}
-
-void SetAccountManager(const AccountId& account_id,
- const std::string& manager) {
- PrefService* local_state = GetLocalStateLegacy();
- // Local State may not be initialized in tests.
- if (!local_state)
- return;
- return KnownUser(local_state).SetAccountManager(account_id, manager);
-}
-
-bool GetAccountManager(const AccountId& account_id, std::string* manager) {
- PrefService* local_state = GetLocalStateLegacy();
- // Local State may not be initialized in tests.
- if (!local_state)
- return false;
- return KnownUser(local_state).GetAccountManager(account_id, manager);
-}
-
-void SetUserLastLoginInputMethodId(const AccountId& account_id,
- const std::string& input_method_id) {
- PrefService* local_state = GetLocalStateLegacy();
- // Local State may not be initialized in tests.
- if (!local_state)
- return;
- return KnownUser(local_state)
- .SetUserLastLoginInputMethodId(account_id, input_method_id);
-}
-
-bool GetUserLastInputMethodId(const AccountId& account_id,
- std::string* input_method_id) {
- PrefService* local_state = GetLocalStateLegacy();
- // Local State may not be initialized in tests.
- if (!local_state)
- return false;
- return KnownUser(local_state)
- .GetUserLastInputMethodId(account_id, input_method_id);
-}
-
-void SetUserPinLength(const AccountId& account_id, int pin_length) {
- PrefService* local_state = GetLocalStateLegacy();
- // Local State may not be initialized in tests.
- if (!local_state)
- return;
- return KnownUser(local_state).SetUserPinLength(account_id, pin_length);
-}
-
-int GetUserPinLength(const AccountId& account_id) {
- PrefService* local_state = GetLocalStateLegacy();
- // Local State may not be initialized in tests.
- if (!local_state)
- return 0;
- return KnownUser(local_state).GetUserPinLength(account_id);
-}
-
-bool PinAutosubmitIsBackfillNeeded(const AccountId& account_id) {
- PrefService* local_state = GetLocalStateLegacy();
- // Local State may not be initialized in tests.
- if (!local_state) {
- // If the pref is not set, the pref needs to be backfilled.
- return true;
- }
- return KnownUser(local_state).PinAutosubmitIsBackfillNeeded(account_id);
-}
-
-void PinAutosubmitSetBackfillNotNeeded(const AccountId& account_id) {
- PrefService* local_state = GetLocalStateLegacy();
- // Local State may not be initialized in tests.
- if (!local_state)
- return;
- return KnownUser(local_state).PinAutosubmitSetBackfillNotNeeded(account_id);
-}
-
-void PinAutosubmitSetBackfillNeededForTests(const AccountId& account_id) {
- PrefService* local_state = GetLocalStateLegacy();
- // Local State may not be initialized in tests.
- if (!local_state)
- return;
- return KnownUser(local_state)
- .PinAutosubmitSetBackfillNeededForTests(account_id);
-}
-
-void SetPasswordSyncToken(const AccountId& account_id,
- const std::string& token) {
- PrefService* local_state = GetLocalStateLegacy();
- // Local State may not be initialized in tests.
- if (!local_state)
- return;
- return KnownUser(local_state).SetPasswordSyncToken(account_id, token);
-}
-
-std::string GetPasswordSyncToken(const AccountId& account_id) {
- PrefService* local_state = GetLocalStateLegacy();
- // Local State may not be initialized in tests.
- if (!local_state)
- return std::string();
- return KnownUser(local_state).GetPasswordSyncToken(account_id);
-}
-
} // namespace known_user
} // namespace user_manager
diff --git a/chromium/components/user_manager/known_user.h b/chromium/components/user_manager/known_user.h
index 21fa6cfed75..c0b15131eea 100644
--- a/chromium/components/user_manager/known_user.h
+++ b/chromium/components/user_manager/known_user.h
@@ -9,6 +9,8 @@
#include <vector>
#include "base/gtest_prod_util.h"
+#include "base/memory/raw_ptr.h"
+#include "base/strings/string_piece_forward.h"
#include "base/time/time.h"
#include "base/version.h"
#include "components/user_manager/user_manager_export.h"
@@ -20,7 +22,6 @@ class PrefRegistrySimple;
class PrefService;
namespace base {
-class DictionaryValue;
class Value;
}
@@ -50,46 +51,52 @@ class USER_MANAGER_EXPORT KnownUser final {
KnownUser(const KnownUser& other) = delete;
KnownUser& operator=(const KnownUser& other) = delete;
- // Performs a lookup of properties associated with |account_id|. If found,
- // returns |true| and fills |out_value|. |out_value| can be NULL, if
- // only existence check is required.
- bool FindPrefs(const AccountId& account_id,
- const base::DictionaryValue** out_value);
+ // Updates (or creates) properties associated with |account_id|. Updates
+ // value found by |path| with |opt_value|. If |opt_value| has no value it
+ // clears the |path| in properties.
+ void SetPath(const AccountId& account_id,
+ const std::string& path,
+ absl::optional<base::Value> opt_value);
- // Updates (or creates) properties associated with |account_id| based
- // on |values|. |clear| defines if existing properties are cleared (|true|)
- // or if it is just a incremental update (|false|).
- void UpdatePrefs(const AccountId& account_id,
- const base::DictionaryValue& values,
- bool clear);
+ // Returns `nullptr` if value is not found or not a string.
+ const std::string* FindStringPath(const AccountId& account_id,
+ base::StringPiece path) const;
// Returns true if |account_id| preference by |path| does exist,
// fills in |out_value|. Otherwise returns false.
- bool GetStringPref(const AccountId& account_id,
- const std::string& path,
- std::string* out_value);
+ bool GetStringPrefForTest(const AccountId& account_id,
+ const std::string& path,
+ std::string* out_value);
// Updates user's identified by |account_id| string preference |path|.
void SetStringPref(const AccountId& account_id,
const std::string& path,
const std::string& in_value);
+ absl::optional<bool> FindBoolPath(const AccountId& account_id,
+ base::StringPiece path) const;
+
// Returns true if |account_id| preference by |path| does exist,
// fills in |out_value|. Otherwise returns false.
- bool GetBooleanPref(const AccountId& account_id,
- const std::string& path,
- bool* out_value);
+ bool GetBooleanPrefForTest(const AccountId& account_id,
+ const std::string& path,
+ bool* out_value);
// Updates user's identified by |account_id| boolean preference |path|.
void SetBooleanPref(const AccountId& account_id,
const std::string& path,
const bool in_value);
+ // Return absl::nullopt if the value is not found or doesn't have the int
+ // type.
+ absl::optional<int> FindIntPath(const AccountId& account_id,
+ base::StringPiece path) const;
+
// Returns true if |account_id| preference by |path| does exist,
// fills in |out_value|. Otherwise returns false.
- bool GetIntegerPref(const AccountId& account_id,
- const std::string& path,
- int* out_value);
+ bool GetIntegerPrefForTest(const AccountId& account_id,
+ const std::string& path,
+ int* out_value);
// Updates user's identified by |account_id| integer preference |path|.
void SetIntegerPref(const AccountId& account_id,
@@ -102,11 +109,6 @@ class USER_MANAGER_EXPORT KnownUser final {
const std::string& path,
const base::Value** out_value);
- // Updates user's identified by |account_id| value preference |path|.
- void SetPref(const AccountId& account_id,
- const std::string& path,
- base::Value in_value);
-
// Removes user's identified by |account_id| preference |path|.
void RemovePref(const AccountId& account_id, const std::string& path);
@@ -130,12 +132,8 @@ class USER_MANAGER_EXPORT KnownUser final {
// |account_id.GetObjGuid()| for user with |account_id|.
void UpdateId(const AccountId& account_id);
- // Find GAIA ID for user with |account_id|, fill in |out_value| and return
- // true
- // if GAIA ID was found or false otherwise.
- // TODO(antrim): Update this once AccountId contains GAIA ID
- // (crbug.com/548926).
- bool FindGaiaID(const AccountId& account_id, std::string* out_value);
+ // Find GAIA ID for user with `account_id`, returns `nullptr` if not found.
+ const std::string* FindGaiaID(const AccountId& account_id);
// Setter and getter for DeviceId known user string preference.
void SetDeviceId(const AccountId& account_id, const std::string& device_id);
@@ -180,14 +178,13 @@ class USER_MANAGER_EXPORT KnownUser final {
void UpdateReauthReason(const AccountId& account_id, const int reauth_reason);
// Returns the reason why the user with |account_id| has to go through the
- // re-auth flow. Returns true if such a reason was recorded or false
- // otherwise.
- bool FindReauthReason(const AccountId& account_id, int* out_value);
+ // re-auth flow. Returns absl::nullopt if value is not set.
+ absl::optional<int> FindReauthReason(const AccountId& account_id) const;
// Setter and getter for the information about challenge-response keys that
// can be used by this user to authenticate. The getter returns a null value
// when the property isn't present. For the format of the value, refer to
- // chromeos/login/auth/challenge_response/known_user_pref_utils.h.
+ // ash/components/login/auth/challenge_response/known_user_pref_utils.h.
void SetChallengeResponseKeys(const AccountId& account_id, base::Value value);
base::Value GetChallengeResponseKeys(const AccountId& account_id);
@@ -209,12 +206,11 @@ class USER_MANAGER_EXPORT KnownUser final {
void SetAccountManager(const AccountId& account_id,
const std::string& manager);
- bool GetAccountManager(const AccountId& account_id, std::string* manager);
+ const std::string* GetAccountManager(const AccountId& account_id);
void SetUserLastLoginInputMethodId(const AccountId& account_id,
const std::string& input_method_id);
- bool GetUserLastInputMethodId(const AccountId& account_id,
- std::string* input_method_id);
+ const std::string* GetUserLastInputMethodId(const AccountId& account_id);
// Exposes the user's PIN length in local state for PIN auto submit.
void SetUserPinLength(const AccountId& account_id, int pin_length);
@@ -235,7 +231,7 @@ class USER_MANAGER_EXPORT KnownUser final {
void SetPasswordSyncToken(const AccountId& account_id,
const std::string& token);
- std::string GetPasswordSyncToken(const AccountId& account_id);
+ const std::string* GetPasswordSyncToken(const AccountId& account_id) const;
// Saves the current major version as the version in which the user completed
// the onboarding flow.
@@ -255,10 +251,13 @@ class USER_MANAGER_EXPORT KnownUser final {
std::string GetPendingOnboardingScreen(const AccountId& account_id);
+ bool UserExists(const AccountId& account_id);
+
// Register known user prefs.
static void RegisterPrefs(PrefRegistrySimple* registry);
private:
+ friend class KnownUserTest;
friend class UserManagerBase;
FRIEND_TEST_ALL_PREFIXES(KnownUserTest,
@@ -266,8 +265,9 @@ class USER_MANAGER_EXPORT KnownUser final {
FRIEND_TEST_ALL_PREFIXES(KnownUserTest, CleanObsoletePrefs);
FRIEND_TEST_ALL_PREFIXES(KnownUserTest, MigrateOfflineSigninLimit);
- // Removes |path| from account_id's known user dictionary.
- void ClearPref(const AccountId& account_id, const std::string& path);
+ // Performs a lookup of properties associated with |account_id|. Returns
+ // nullptr if not found.
+ const base::Value* FindPrefs(const AccountId& account_id) const;
// Removes all user preferences associated with |account_id|.
// Not exported as code should not be calling this outside this component
@@ -282,7 +282,7 @@ class USER_MANAGER_EXPORT KnownUser final {
// Removes all obsolete prefs from all users.
void CleanObsoletePrefs();
- PrefService* const local_state_;
+ const base::raw_ptr<PrefService> local_state_;
};
// Legacy interface of KnownUsersDatabase.
@@ -290,30 +290,6 @@ class USER_MANAGER_EXPORT KnownUser final {
namespace known_user {
// Methods for storage/retrieval of per-user properties in Local State.
-// Performs a lookup of properties associated with |account_id|. If found,
-// returns |true| and fills |out_value|. |out_value| can be NULL, if
-// only existence check is required.
-// TODO(https://crbug.com/1150434): Deprecated, use KnownUser::FindPrefs
-// instead.
-bool USER_MANAGER_EXPORT FindPrefs(const AccountId& account_id,
- const base::DictionaryValue** out_value);
-
-// Updates (or creates) properties associated with |account_id| based
-// on |values|. |clear| defines if existing properties are cleared (|true|)
-// or if it is just a incremental update (|false|).
-// TODO(https://crbug.com/1150434): Deprecated, use KnownUser:: instead.
-void USER_MANAGER_EXPORT UpdatePrefs(const AccountId& account_id,
- const base::DictionaryValue& values,
- bool clear);
-
-// Returns true if |account_id| preference by |path| does exist,
-// fills in |out_value|. Otherwise returns false.
-// TODO(https://crbug.com/1150434): Deprecated, use KnownUser::GetStringPref
-// instead.
-bool USER_MANAGER_EXPORT GetStringPref(const AccountId& account_id,
- const std::string& path,
- std::string* out_value);
-
// Updates user's identified by |account_id| string preference |path|.
// TODO(https://crbug.com/1150434): Deprecated, use KnownUser::SetStringPref
// instead.
@@ -321,14 +297,6 @@ void USER_MANAGER_EXPORT SetStringPref(const AccountId& account_id,
const std::string& path,
const std::string& in_value);
-// Returns true if |account_id| preference by |path| does exist,
-// fills in |out_value|. Otherwise returns false.
-// TODO(https://crbug.com/1150434): Deprecated, use KnownUser::GetBooleanPref
-// instead.
-bool USER_MANAGER_EXPORT GetBooleanPref(const AccountId& account_id,
- const std::string& path,
- bool* out_value);
-
// Updates user's identified by |account_id| boolean preference |path|.
// TODO(https://crbug.com/1150434): Deprecated, use KnownUser::SetBooleanPref
// instead.
@@ -338,32 +306,11 @@ void USER_MANAGER_EXPORT SetBooleanPref(const AccountId& account_id,
// Returns true if |account_id| preference by |path| does exist,
// fills in |out_value|. Otherwise returns false.
-// TODO(https://crbug.com/1150434): Deprecated, use KnownUser::GetIntegerPref
-// instead.
-bool USER_MANAGER_EXPORT GetIntegerPref(const AccountId& account_id,
- const std::string& path,
- int* out_value);
-
-// Updates user's identified by |account_id| integer preference |path|.
-// TODO(https://crbug.com/1150434): Deprecated, use KnownUser::SetIntegerPref
-// instead.
-void USER_MANAGER_EXPORT SetIntegerPref(const AccountId& account_id,
- const std::string& path,
- const int in_value);
-
-// Returns true if |account_id| preference by |path| does exist,
-// fills in |out_value|. Otherwise returns false.
// TODO(https://crbug.com/1150434): Deprecated, use KnownUser::GetPref instead.
bool USER_MANAGER_EXPORT GetPref(const AccountId& account_id,
const std::string& path,
const base::Value** out_value);
-// Updates user's identified by |account_id| value preference |path|.
-// TODO(https://crbug.com/1150434): Deprecated, use KnownUser::SetPref instead.
-void USER_MANAGER_EXPORT SetPref(const AccountId& account_id,
- const std::string& path,
- base::Value in_value);
-
// Removes user's identified by |account_id| preference |path|.
// TODO(https://crbug.com/1150434): Deprecated, use KnownUser::RemovePref
// instead.
@@ -384,29 +331,11 @@ AccountId USER_MANAGER_EXPORT GetAccountId(const std::string& user_email,
const std::string& id,
const AccountType& account_type);
-// Saves |account_id| into known users. Tries to commit the change on disk. Use
-// only if account_id is not yet in the known user list. Important if Chrome
-// crashes shortly after starting a session. Cryptohome should be able to find
-// known account_id on Chrome restart.
-// TODO(https://crbug.com/1150434): Deprecated, use KnownUser::SaveKnownUser
-// instead.
-void USER_MANAGER_EXPORT SaveKnownUser(const AccountId& account_id);
-
// Updates |account_id.account_type_| and |account_id.GetGaiaId()| or
// |account_id.GetObjGuid()| for user with |account_id|.
// TODO(https://crbug.com/1150434): Deprecated, use KnownUser::UpdateId instead.
void USER_MANAGER_EXPORT UpdateId(const AccountId& account_id);
-// Find GAIA ID for user with |account_id|, fill in |out_value| and return
-// true
-// if GAIA ID was found or false otherwise.
-// TODO(antrim): Update this once AccountId contains GAIA ID
-// (crbug.com/548926).
-// TODO(https://crbug.com/1150434): Deprecated, use KnownUser::FindGaiaID
-// instead.
-bool USER_MANAGER_EXPORT FindGaiaID(const AccountId& account_id,
- std::string* out_value);
-
// Setter and getter for DeviceId known user string preference.
// TODO(https://crbug.com/1150434): Deprecated, use KnownUser::SetDeviceId
// instead.
@@ -417,176 +346,6 @@ void USER_MANAGER_EXPORT SetDeviceId(const AccountId& account_id,
// instead.
std::string USER_MANAGER_EXPORT GetDeviceId(const AccountId& account_id);
-// Setter and getter for GAPSCookie known user string preference.
-// TODO(https://crbug.com/1150434): Deprecated, use KnownUser::SetGAPSCookie
-// instead.
-void USER_MANAGER_EXPORT SetGAPSCookie(const AccountId& account_id,
- const std::string& gaps_cookie);
-
-// TODO(https://crbug.com/1150434): Deprecated, use KnownUser::GetGAPSCookie
-// instead.
-std::string USER_MANAGER_EXPORT GetGAPSCookie(const AccountId& account_id);
-
-// Saves whether the user authenticates using SAML.
-// TODO(https://crbug.com/1150434): Deprecated, use KnownUser::UpdateUsingSAML
-// instead.
-void USER_MANAGER_EXPORT UpdateUsingSAML(const AccountId& account_id,
- const bool using_saml);
-
-// Returns if SAML needs to be used for authentication of the user with
-// |account_id|, if it is known (was set by a |UpdateUsingSaml| call).
-// Otherwise
-// returns false.
-// TODO(https://crbug.com/1150434): Deprecated, use KnownUser::IsUsingSAML
-// instead.
-bool USER_MANAGER_EXPORT IsUsingSAML(const AccountId& account_id);
-
-// Setter and getter for the known user preference that stores whether the user
-// authenticated via SAML using the principals API.
-// TODO(https://crbug.com/1150434): Deprecated, use
-// KnownUser::UpdateIsUsingSAMLPrincipalsAPI instead.
-void USER_MANAGER_EXPORT
-UpdateIsUsingSAMLPrincipalsAPI(const AccountId& account_id,
- bool is_using_saml_principals_api);
-
-// TODO(https://crbug.com/1150434): Deprecated, use
-// KnownUser::GetIsUsingSAMLPrincipalsAPI instead.
-bool USER_MANAGER_EXPORT
-GetIsUsingSAMLPrincipalsAPI(const AccountId& account_id);
-
-// Returns whether the current profile requires policy or not (returns UNKNOWN
-// if the profile has never been initialized and so the policy status is
-// not yet known).
-// TODO(https://crbug.com/1150434): Deprecated, use
-// KnownUser::GetProfileRequiresPolicy instead.
-ProfileRequiresPolicy USER_MANAGER_EXPORT
-GetProfileRequiresPolicy(const AccountId& account_id);
-
-// Sets whether the profile requires policy or not.
-// TODO(https://crbug.com/1150434): Deprecated, use
-// KnownUser::SetProfileRequiresPolicy instead.
-void USER_MANAGER_EXPORT
-SetProfileRequiresPolicy(const AccountId& account_id,
- ProfileRequiresPolicy policy_required);
-
-// Clears information whether profile requires policy.
-// TODO(https://crbug.com/1150434): Deprecated, use
-// KnownUser::ClearProfileRequiresPolicy instead.
-void USER_MANAGER_EXPORT
-ClearProfileRequiresPolicy(const AccountId& account_id);
-
-// Saves why the user has to go through re-auth flow.
-// TODO(https://crbug.com/1150434): Deprecated, use
-// KnownUser::UpdateReauthReason instead.
-void USER_MANAGER_EXPORT UpdateReauthReason(const AccountId& account_id,
- const int reauth_reason);
-
-// Returns the reason why the user with |account_id| has to go through the
-// re-auth flow. Returns true if such a reason was recorded or false
-// otherwise.
-// TODO(https://crbug.com/1150434): Deprecated, use KnownUser::FindReauthReason
-// instead.
-bool USER_MANAGER_EXPORT FindReauthReason(const AccountId& account_id,
- int* out_value);
-
-// Setter and getter for the information about challenge-response keys that can
-// be used by this user to authenticate.
-// The getter returns a null value when the property isn't present.
-// For the format of the value, refer to
-// chromeos/login/auth/challenge_response/known_user_pref_utils.h.
-// TODO(https://crbug.com/1150434): Deprecated, use
-// KnownUser::SetChallengeResponseKeys instead.
-void USER_MANAGER_EXPORT SetChallengeResponseKeys(const AccountId& account_id,
- base::Value value);
-
-// TODO(https://crbug.com/1150434): Deprecated, use
-// KnownUser::GetChallengeResponseKeys instead.
-base::Value USER_MANAGER_EXPORT
-GetChallengeResponseKeys(const AccountId& account_id);
-
-// TODO(https://crbug.com/1150434): Deprecated, use
-// KnownUser::SetLastOnlineSignin instead.
-void USER_MANAGER_EXPORT SetLastOnlineSignin(const AccountId& account_id,
- base::Time time);
-
-// TODO(https://crbug.com/1150434): Deprecated, use
-// KnownUser::GetLastOnlineSignin instead.
-base::Time USER_MANAGER_EXPORT GetLastOnlineSignin(const AccountId& account_id);
-
-// TODO(https://crbug.com/1150434): Deprecated, use
-// KnownUser::SetOfflineSigninLimit instead.
-void USER_MANAGER_EXPORT
-SetOfflineSigninLimit(const AccountId& account_id,
- absl::optional<base::TimeDelta> time_limit);
-
-// TODO(https://crbug.com/1150434): Deprecated, use
-// KnownUser::GetOfflineSigninLimit instead.
-absl::optional<base::TimeDelta> USER_MANAGER_EXPORT
-GetOfflineSigninLimit(const AccountId& account_id);
-
-// TODO(https://crbug.com/1150434): Deprecated, use
-// KnownUser::SetIsEnterpriseManaged instead.
-void USER_MANAGER_EXPORT SetIsEnterpriseManaged(const AccountId& account_id,
- bool is_enterprise_managed);
-
-// TODO(https://crbug.com/1150434): Deprecated, use
-// KnownUser::GetIsEnterpriseManaged instead.
-bool USER_MANAGER_EXPORT GetIsEnterpriseManaged(const AccountId& account_id);
-
-// TODO(https://crbug.com/1150434): Deprecated, use KnownUser::SetAccountManager
-// instead.
-void USER_MANAGER_EXPORT SetAccountManager(const AccountId& account_id,
- const std::string& manager);
-// TODO(https://crbug.com/1150434): Deprecated, use KnownUser::GetAccountManager
-// instead.
-bool USER_MANAGER_EXPORT GetAccountManager(const AccountId& account_id,
- std::string* manager);
-// TODO(https://crbug.com/1150434): Deprecated, use
-// KnownUser::SetUserLastLoginInputMethodId instead.
-void USER_MANAGER_EXPORT
-SetUserLastLoginInputMethodId(const AccountId& account_id,
- const std::string& input_method_id);
-
-// TODO(https://crbug.com/1150434): Deprecated, use
-// KnownUser::GetUserLastInputMethodId instead.
-bool USER_MANAGER_EXPORT GetUserLastInputMethodId(const AccountId& account_id,
- std::string* input_method_id);
-
-// Exposes the user's PIN length in local state for PIN auto submit.
-// TODO(https://crbug.com/1150434): Deprecated, use KnownUser::SetUserPinLength
-// instead.
-void USER_MANAGER_EXPORT SetUserPinLength(const AccountId& account_id,
- int pin_length);
-
-// Returns the user's PIN length if available, otherwise 0.
-// TODO(https://crbug.com/1150434): Deprecated, use KnownUser::GetUserPinLength
-// instead.
-int USER_MANAGER_EXPORT GetUserPinLength(const AccountId& account_id);
-
-// Whether the user needs to have their pin auto submit preferences backfilled.
-// TODO(crbug.com/1104164) - Remove this once most users have their
-// preferences backfilled.
-// TODO(https://crbug.com/1150434): Deprecated, use KnownUser:: equivalents
-// instead.
-bool USER_MANAGER_EXPORT
-PinAutosubmitIsBackfillNeeded(const AccountId& account_id);
-void USER_MANAGER_EXPORT
-PinAutosubmitSetBackfillNotNeeded(const AccountId& account_id);
-void USER_MANAGER_EXPORT
-PinAutosubmitSetBackfillNeededForTests(const AccountId& account_id);
-
-// Setter and getter for password sync token used for syncing SAML passwords
-// across multiple user devices.
-// TODO(https://crbug.com/1150434): Deprecated, use
-// KnownUser::SetPasswordSyncToken instead.
-void USER_MANAGER_EXPORT SetPasswordSyncToken(const AccountId& account_id,
- const std::string& token);
-
-// TODO(https://crbug.com/1150434): Deprecated, use
-// KnownUser::GetPasswordSyncToken instead.
-std::string USER_MANAGER_EXPORT
-GetPasswordSyncToken(const AccountId& account_id);
-
} // namespace known_user
} // namespace user_manager
diff --git a/chromium/components/user_manager/known_user_unittest.cc b/chromium/components/user_manager/known_user_unittest.cc
index bdf30fdcdd9..648b601f5f2 100644
--- a/chromium/components/user_manager/known_user_unittest.cc
+++ b/chromium/components/user_manager/known_user_unittest.cc
@@ -25,11 +25,11 @@ namespace {
absl::optional<std::string> GetStringPrefValue(KnownUser* known_user,
const AccountId& account_id,
const char* pref_name) {
- std::string value;
- if (!known_user->GetStringPref(account_id, pref_name, &value)) {
- return {};
+ if (const std::string* value =
+ known_user->FindStringPath(account_id, pref_name)) {
+ return *value;
}
- return value;
+ return absl::nullopt;
}
} // namespace
@@ -59,6 +59,10 @@ class KnownUserTest : public testing::Test {
PrefService* local_state() { return &local_state_; }
+ const base::Value* FindPrefs(const AccountId& account_id) {
+ return KnownUser(local_state()).FindPrefs(account_id);
+ }
+
private:
base::test::TaskEnvironment task_environment_{
base::test::TaskEnvironment::MainThreadType::UI};
@@ -70,11 +74,7 @@ class KnownUserTest : public testing::Test {
};
TEST_F(KnownUserTest, FindPrefsNonExisting) {
- KnownUser known_user(local_state());
- const base::DictionaryValue* value = nullptr;
- bool read_success = known_user.FindPrefs(kDefaultAccountId, &value);
- EXPECT_FALSE(read_success);
- EXPECT_FALSE(value);
+ EXPECT_FALSE(FindPrefs(kDefaultAccountId));
}
TEST_F(KnownUserTest, FindPrefsExisting) {
@@ -82,9 +82,7 @@ TEST_F(KnownUserTest, FindPrefsExisting) {
const std::string kCustomPrefName = "custom_pref";
known_user.SetStringPref(kDefaultAccountId, kCustomPrefName, "value");
- const base::DictionaryValue* value = nullptr;
- bool read_success = known_user.FindPrefs(kDefaultAccountId, &value);
- EXPECT_TRUE(read_success);
+ const base::Value* value = FindPrefs(kDefaultAccountId);
ASSERT_TRUE(value);
const std::string* pref_value = value->FindStringKey(kCustomPrefName);
@@ -107,19 +105,9 @@ TEST_F(KnownUserTest, FindPrefsIgnoresEphemeralGaiaUsers) {
known_user.SetStringPref(kAccountIdEphemeralGaia, kCustomPrefName, "value");
known_user.SetStringPref(kAccountIdEphemeralAd, kCustomPrefName, "value");
- {
- const base::DictionaryValue* value = nullptr;
- bool read_success = known_user.FindPrefs(kAccountIdEphemeralGaia, &value);
- EXPECT_FALSE(read_success);
- EXPECT_FALSE(value);
- }
+ EXPECT_FALSE(FindPrefs(kAccountIdEphemeralGaia));
- {
- const base::DictionaryValue* value = nullptr;
- bool read_success = known_user.FindPrefs(kAccountIdEphemeralAd, &value);
- EXPECT_TRUE(read_success);
- EXPECT_TRUE(value);
- }
+ EXPECT_TRUE(FindPrefs(kAccountIdEphemeralAd));
}
TEST_F(KnownUserTest, FindPrefsMatchForUnknownAccountType) {
@@ -134,12 +122,9 @@ TEST_F(KnownUserTest, FindPrefsMatchForUnknownAccountType) {
known_user.SetStringPref(kAccountIdUnknown, "some_pref", "some_value");
- // Looking it up by AccountId always succeeds, no matter which AccountType is
- // used for the lookup.
- const base::DictionaryValue* value = nullptr;
- EXPECT_TRUE(known_user.FindPrefs(kAccountIdUnknown, &value));
- EXPECT_TRUE(known_user.FindPrefs(kAccountIdGaia, &value));
- EXPECT_TRUE(known_user.FindPrefs(kAccountIdAd, &value));
+ EXPECT_TRUE(FindPrefs(kAccountIdUnknown));
+ EXPECT_TRUE(FindPrefs(kAccountIdGaia));
+ EXPECT_TRUE(FindPrefs(kAccountIdAd));
}
TEST_F(KnownUserTest, FindPrefsMatchForGaiaAccountWithEmail) {
@@ -151,35 +136,28 @@ TEST_F(KnownUserTest, FindPrefsMatchForGaiaAccountWithEmail) {
known_user.SaveKnownUser(AccountId::FromUserEmailGaiaId(kEmailA, kGaiaIdA));
- const base::DictionaryValue* value = nullptr;
-
// Finding by itself should work
- EXPECT_TRUE(known_user.FindPrefs(
- AccountId::FromUserEmailGaiaId(kEmailA, kGaiaIdA), &value));
+ EXPECT_TRUE(FindPrefs(AccountId::FromUserEmailGaiaId(kEmailA, kGaiaIdA)));
// Finding by gaia id should also work even if the e-mail doesn't match.
- EXPECT_TRUE(known_user.FindPrefs(
- AccountId::FromUserEmailGaiaId(kEmailB, kGaiaIdA), &value));
+ EXPECT_TRUE(FindPrefs(AccountId::FromUserEmailGaiaId(kEmailB, kGaiaIdA)));
// Finding by e-mail should also work even if the gaia id doesn't match.
// TODO(https://crbug.com/1190902): This should likely be EXPECT_FALSE going
// forward.
- EXPECT_TRUE(known_user.FindPrefs(
- AccountId::FromUserEmailGaiaId(kEmailA, kGaiaIdB), &value));
+ EXPECT_TRUE(FindPrefs(AccountId::FromUserEmailGaiaId(kEmailA, kGaiaIdB)));
// Finding by just gaia id without any e-mail doesn't work (because the
// resulting AccountId is not considered valid).
- EXPECT_FALSE(known_user.FindPrefs(AccountId::FromGaiaId(kGaiaIdA), &value));
+ EXPECT_FALSE(FindPrefs(AccountId::FromGaiaId(kGaiaIdA)));
// An unrelated gaia AccountId with the same Account Type doesn't find
// anything.
- EXPECT_FALSE(known_user.FindPrefs(
- AccountId::FromUserEmailGaiaId(kEmailB, kGaiaIdB), &value));
+ EXPECT_FALSE(FindPrefs(AccountId::FromUserEmailGaiaId(kEmailB, kGaiaIdB)));
// Looking up an AccountId stored as gaia by an unknown-type AccountId with
// the same e-mail address succeeds.
- EXPECT_TRUE(known_user.FindPrefs(AccountId::FromUserEmail(kEmailA), &value));
+ EXPECT_TRUE(FindPrefs(AccountId::FromUserEmail(kEmailA)));
// Looking up an AccountId stored as gaia by an AccountId with type Ad fails.
- EXPECT_FALSE(known_user.FindPrefs(
- AccountId::AdFromUserEmailObjGuid(kEmailA, "guid"), &value));
+ EXPECT_FALSE(FindPrefs(AccountId::AdFromUserEmailObjGuid(kEmailA, "guid")));
}
TEST_F(KnownUserTest, FindPrefsMatchForAdAccountWithEmail) {
@@ -189,33 +167,26 @@ TEST_F(KnownUserTest, FindPrefsMatchForAdAccountWithEmail) {
known_user.SaveKnownUser(AccountId::AdFromUserEmailObjGuid(kEmailA, "a"));
- const base::DictionaryValue* value = nullptr;
-
// Finding by itself should work
- EXPECT_TRUE(known_user.FindPrefs(
- AccountId::AdFromUserEmailObjGuid(kEmailA, "a"), &value));
+ EXPECT_TRUE(FindPrefs(AccountId::AdFromUserEmailObjGuid(kEmailA, "a")));
// Finding by guid should also work even if the e-mail doesn't match.
- EXPECT_TRUE(known_user.FindPrefs(
- AccountId::AdFromUserEmailObjGuid(kEmailB, "a"), &value));
+ EXPECT_TRUE(FindPrefs(AccountId::AdFromUserEmailObjGuid(kEmailB, "a")));
// Finding by e-mail should also work even if the guid doesn't match.
- EXPECT_TRUE(known_user.FindPrefs(
- AccountId::AdFromUserEmailObjGuid(kEmailA, "b"), &value));
+ EXPECT_TRUE(FindPrefs(AccountId::AdFromUserEmailObjGuid(kEmailA, "b")));
// Finding by just AD guid without any e-mail doesn't work (because the
// resulting AccountId is not considered valid).
- EXPECT_FALSE(known_user.FindPrefs(AccountId::AdFromObjGuid("a"), &value));
+ EXPECT_FALSE(FindPrefs(AccountId::AdFromObjGuid("a")));
// An unrelated AD AccountId with the same Account Type doesn't find
// anything.
- EXPECT_FALSE(known_user.FindPrefs(
- AccountId::AdFromUserEmailObjGuid(kEmailB, "b"), &value));
+ EXPECT_FALSE(FindPrefs(AccountId::AdFromUserEmailObjGuid(kEmailB, "b")));
// Looking up an AccountId stored as AD by an unknown-type AccountId with
// the same e-mail address succeeds.
- EXPECT_TRUE(known_user.FindPrefs(AccountId::FromUserEmail(kEmailA), &value));
+ EXPECT_TRUE(FindPrefs(AccountId::FromUserEmail(kEmailA)));
// Looking up an AccountId stored as AD by an AccountId with type gaia fails.
- EXPECT_FALSE(known_user.FindPrefs(
- AccountId::FromUserEmailGaiaId(kEmailA, "gaia_id"), &value));
+ EXPECT_FALSE(FindPrefs(AccountId::FromUserEmailGaiaId(kEmailA, "gaia_id")));
}
TEST_F(KnownUserTest, UpdatePrefsWithoutClear) {
@@ -223,23 +194,14 @@ TEST_F(KnownUserTest, UpdatePrefsWithoutClear) {
constexpr char kPrefName1[] = "pref1";
constexpr char kPrefName2[] = "pref2";
- {
- base::DictionaryValue update;
- update.SetKey(kPrefName1, base::Value("pref1_value1"));
- known_user.UpdatePrefs(kDefaultAccountId, update, /*clear=*/false);
- }
+ known_user.SetPath(kDefaultAccountId, kPrefName1,
+ base::Value("pref1_value1"));
- {
- base::DictionaryValue update;
- update.SetKey(kPrefName1, base::Value("pref1_value2"));
- known_user.UpdatePrefs(kDefaultAccountId, update, /*clear=*/false);
- }
+ known_user.SetPath(kDefaultAccountId, kPrefName1,
+ base::Value("pref1_value2"));
- {
- base::DictionaryValue update;
- update.SetKey(kPrefName2, base::Value("pref2_value1"));
- known_user.UpdatePrefs(kDefaultAccountId, update, /*clear=*/false);
- }
+ known_user.SetPath(kDefaultAccountId, kPrefName2,
+ base::Value("pref2_value1"));
EXPECT_EQ(absl::make_optional(std::string("pref1_value2")),
GetStringPrefValue(&known_user, kDefaultAccountId, kPrefName1));
@@ -252,17 +214,13 @@ TEST_F(KnownUserTest, UpdatePrefsWithClear) {
constexpr char kPrefName1[] = "pref1";
constexpr char kPrefName2[] = "pref2";
- {
- base::DictionaryValue update;
- update.SetKey(kPrefName1, base::Value("pref1_value1"));
- known_user.UpdatePrefs(kDefaultAccountId, update, /*clear=*/false);
- }
+ known_user.SetPath(kDefaultAccountId, kPrefName1,
+ base::Value("pref1_value1"));
- {
- base::DictionaryValue update;
- update.SetKey(kPrefName2, base::Value("pref2_value1"));
- known_user.UpdatePrefs(kDefaultAccountId, update, /*clear=*/true);
- }
+ known_user.SetPath(kDefaultAccountId, kPrefName2,
+ base::Value("pref2_value1"));
+
+ known_user.SetPath(kDefaultAccountId, kPrefName1, absl::nullopt);
EXPECT_EQ(absl::nullopt,
GetStringPrefValue(&known_user, kDefaultAccountId, kPrefName1));
@@ -363,9 +321,9 @@ TEST_F(KnownUserTest, FindGaiaIdForGaiaAccount) {
AccountId::FromUserEmailGaiaId("account1@gmail.com", "gaia_id");
known_user.SaveKnownUser(kAccountIdGaia);
- std::string gaia_id;
- EXPECT_TRUE(known_user.FindGaiaID(kAccountIdGaia, &gaia_id));
- EXPECT_EQ(gaia_id, "gaia_id");
+ const std::string* gaia_id = known_user.FindGaiaID(kAccountIdGaia);
+ ASSERT_TRUE(gaia_id);
+ EXPECT_EQ(*gaia_id, "gaia_id");
}
TEST_F(KnownUserTest, FindGaiaIdForAdAccount) {
@@ -374,8 +332,7 @@ TEST_F(KnownUserTest, FindGaiaIdForAdAccount) {
AccountId::AdFromUserEmailObjGuid("account1@gmail.com", "guid");
known_user.SaveKnownUser(kAccountIdAd);
- std::string gaia_id;
- EXPECT_FALSE(known_user.FindGaiaID(kAccountIdAd, &gaia_id));
+ EXPECT_FALSE(known_user.FindGaiaID(kAccountIdAd));
}
// TODO(https://crbug.com/1148457): Add tests for GetAccountId.
@@ -385,18 +342,10 @@ TEST_F(KnownUserTest, RemovePrefOnCustomPref) {
const std::string kCustomPrefName = "custom_pref";
known_user.SetStringPref(kDefaultAccountId, kCustomPrefName, "value");
- {
- std::string read_value;
- EXPECT_TRUE(known_user.GetStringPref(kDefaultAccountId, kCustomPrefName,
- &read_value));
- }
+ EXPECT_TRUE(known_user.FindStringPath(kDefaultAccountId, kCustomPrefName));
known_user.RemovePref(kDefaultAccountId, kCustomPrefName);
- {
- std::string read_value;
- EXPECT_FALSE(known_user.GetStringPref(kDefaultAccountId, kCustomPrefName,
- &read_value));
- }
+ EXPECT_FALSE(known_user.FindStringPath(kDefaultAccountId, kCustomPrefName));
}
TEST_F(KnownUserTest, RemovePrefOnReservedPref) {
@@ -466,17 +415,10 @@ TEST_F(KnownUserTest, ProfileRequiresPolicy) {
TEST_F(KnownUserTest, ReauthReason) {
KnownUser known_user(local_state());
- {
- int auth_reason;
- EXPECT_FALSE(known_user.FindReauthReason(kDefaultAccountId, &auth_reason));
- }
+ EXPECT_FALSE(known_user.FindReauthReason(kDefaultAccountId).has_value());
known_user.UpdateReauthReason(kDefaultAccountId, 3);
- {
- int auth_reason;
- EXPECT_TRUE(known_user.FindReauthReason(kDefaultAccountId, &auth_reason));
- EXPECT_EQ(auth_reason, 3);
- }
+ EXPECT_EQ(known_user.FindReauthReason(kDefaultAccountId), 3);
}
TEST_F(KnownUserTest, ChallengeResponseKeys) {
@@ -525,36 +467,20 @@ TEST_F(KnownUserTest, IsEnterpriseManaged) {
TEST_F(KnownUserTest, AccountManager) {
KnownUser known_user(local_state());
- {
- std::string account_manager;
- EXPECT_FALSE(
- known_user.GetAccountManager(kDefaultAccountId, &account_manager));
- }
+ EXPECT_FALSE(known_user.GetAccountManager(kDefaultAccountId));
known_user.SetAccountManager(kDefaultAccountId, "test");
- {
- std::string account_manager;
- EXPECT_TRUE(
- known_user.GetAccountManager(kDefaultAccountId, &account_manager));
- }
+ EXPECT_TRUE(known_user.GetAccountManager(kDefaultAccountId));
}
TEST_F(KnownUserTest, UserLastLoginInputMethodId) {
KnownUser known_user(local_state());
- {
- std::string user_last_input_method_id;
- EXPECT_FALSE(known_user.GetUserLastInputMethodId(
- kDefaultAccountId, &user_last_input_method_id));
- }
+ EXPECT_FALSE(known_user.GetUserLastInputMethodId(kDefaultAccountId));
known_user.SetUserLastLoginInputMethodId(kDefaultAccountId, "test");
- {
- std::string user_last_input_method_id;
- EXPECT_TRUE(known_user.GetUserLastInputMethodId(
- kDefaultAccountId, &user_last_input_method_id));
- }
+ EXPECT_TRUE(known_user.GetUserLastInputMethodId(kDefaultAccountId));
}
TEST_F(KnownUserTest, UserPinLength) {
@@ -582,11 +508,11 @@ TEST_F(KnownUserTest, PinAutosubmitBackfillNeeded) {
TEST_F(KnownUserTest, PasswordSyncToken) {
KnownUser known_user(local_state());
- EXPECT_EQ(known_user.GetPasswordSyncToken(kDefaultAccountId), std::string());
+ EXPECT_FALSE(known_user.GetPasswordSyncToken(kDefaultAccountId));
known_user.SetPasswordSyncToken(kDefaultAccountId, "test");
- EXPECT_EQ(known_user.GetPasswordSyncToken(kDefaultAccountId), "test");
+ EXPECT_EQ(*known_user.GetPasswordSyncToken(kDefaultAccountId), "test");
}
TEST_F(KnownUserTest, CleanEphemeralUsersRemovesEphemeralAdOnly) {
@@ -636,13 +562,14 @@ TEST_F(KnownUserTest, CleanObsoletePrefs) {
known_user.CleanObsoletePrefs();
// Verify that only the obsolete pref has been removed.
- EXPECT_FALSE(known_user.GetBooleanPref(kDefaultAccountId, kObsoletePrefName,
- /*out_value=*/nullptr));
+ EXPECT_FALSE(known_user.FindBoolPath(kDefaultAccountId, kObsoletePrefName)
+ .has_value());
+
+ absl::optional<bool> custom_pref_value =
+ known_user.FindBoolPath(kDefaultAccountId, kCustomPrefName);
- bool custom_pref_value = false;
- EXPECT_TRUE(known_user.GetBooleanPref(kDefaultAccountId, kCustomPrefName,
- &custom_pref_value));
- EXPECT_TRUE(custom_pref_value);
+ EXPECT_TRUE(custom_pref_value.has_value());
+ EXPECT_TRUE(custom_pref_value.value());
EXPECT_TRUE(known_user.GetIsEnterpriseManaged(kDefaultAccountId));
}
@@ -660,7 +587,7 @@ struct PrefTypeInfoString {
using PrefTypeForReading = std::string;
static constexpr auto SetFunc = &KnownUser::SetStringPref;
- static constexpr auto GetFunc = &KnownUser::GetStringPref;
+ static constexpr auto GetFunc = &KnownUser::GetStringPrefForTest;
static PrefType CreatePrefValue() { return std::string("test"); }
static bool CheckPrefValue(PrefTypeForReading read_value) {
@@ -677,7 +604,7 @@ struct PrefTypeInfoInteger {
using PrefTypeForReading = int;
static constexpr auto SetFunc = &KnownUser::SetIntegerPref;
- static constexpr auto GetFunc = &KnownUser::GetIntegerPref;
+ static constexpr auto GetFunc = &KnownUser::GetIntegerPrefForTest;
static PrefType CreatePrefValue() { return 7; }
static bool CheckPrefValue(PrefTypeForReading read_value) {
@@ -694,7 +621,7 @@ struct PrefTypeInfoBoolean {
using PrefTypeForReading = bool;
static constexpr auto SetFunc = &KnownUser::SetBooleanPref;
- static constexpr auto GetFunc = &KnownUser::GetBooleanPref;
+ static constexpr auto GetFunc = &KnownUser::GetBooleanPrefForTest;
static PrefType CreatePrefValue() { return true; }
static bool CheckPrefValue(PrefTypeForReading read_value) {
@@ -710,7 +637,7 @@ struct PrefTypeInfoValue {
using PrefType = base::Value;
using PrefTypeForReading = const base::Value*;
- static constexpr auto SetFunc = &KnownUser::SetPref;
+ static constexpr auto SetFunc = &KnownUser::SetPath;
static constexpr auto GetFunc = &KnownUser::GetPref;
static PrefType CreatePrefValue() { return base::Value("test"); }
diff --git a/chromium/components/user_manager/user.cc b/chromium/components/user_manager/user.cc
index 1a03b11ed6a..c032f8fc38d 100644
--- a/chromium/components/user_manager/user.cc
+++ b/chromium/components/user_manager/user.cc
@@ -14,7 +14,6 @@
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_restrictions.h"
#include "components/account_id/account_id.h"
-#include "components/user_manager/known_user.h"
#include "components/user_manager/user_manager.h"
#include "google_apis/gaia/gaia_auth_util.h"
@@ -407,10 +406,6 @@ void RegularUser::UpdateType(UserType user_type) {
const bool old_is_child = is_child_;
is_child_ = user_type == user_manager::USER_TYPE_CHILD;
- // Clear information about profile policy requirements to enforce setting it
- // again for the new account type.
- user_manager::known_user::ClearProfileRequiresPolicy(GetAccountId());
-
LOG(WARNING) << "User type has changed: " << current_type
<< " (is_child=" << old_is_child << ") => " << user_type
<< " (is_child=" << is_child_ << ")";
diff --git a/chromium/components/user_manager/user_manager_base.cc b/chromium/components/user_manager/user_manager_base.cc
index e9b87e211ac..97cc30e14ce 100644
--- a/chromium/components/user_manager/user_manager_base.cc
+++ b/chromium/components/user_manager/user_manager_base.cc
@@ -69,7 +69,7 @@ const int kLogoutToLoginDelayMaxSec = 1800;
// This reads integer value from kUserType Local State preference and
// interprets it as UserType. It is used in initial users load.
-UserType GetStoredUserType(const base::DictionaryValue* prefs_user_types,
+UserType GetStoredUserType(const base::Value* prefs_user_types,
const AccountId& account_id) {
const base::Value* stored_user_type = prefs_user_types->FindKey(
account_id.HasAccountIdKey() ? account_id.GetAccountIdKey()
@@ -406,9 +406,8 @@ void UserManagerBase::SaveUserOAuthStatus(
{
DictionaryPrefUpdate oauth_status_update(GetLocalState(),
kUserOAuthTokenStatus);
- oauth_status_update->SetKey(
- account_id.GetUserEmail(),
- base::Value(static_cast<int>(oauth_token_status)));
+ oauth_status_update->SetIntKey(account_id.GetUserEmail(),
+ static_cast<int>(oauth_token_status));
}
GetLocalState()->CommitPendingWrite();
}
@@ -429,8 +428,8 @@ void UserManagerBase::SaveForceOnlineSignin(const AccountId& account_id,
{
DictionaryPrefUpdate force_online_update(GetLocalState(),
kUserForceOnlineSignin);
- force_online_update->SetKey(account_id.GetUserEmail(),
- base::Value(force_online_signin));
+ force_online_update->SetBoolKey(account_id.GetUserEmail(),
+ force_online_signin);
}
GetLocalState()->CommitPendingWrite();
}
@@ -447,8 +446,8 @@ void UserManagerBase::SaveUserDisplayName(const AccountId& account_id,
if (!IsUserNonCryptohomeDataEphemeral(account_id)) {
DictionaryPrefUpdate display_name_update(GetLocalState(),
kUserDisplayName);
- display_name_update->SetKey(account_id.GetUserEmail(),
- base::Value(display_name));
+ display_name_update->SetStringKey(account_id.GetUserEmail(),
+ display_name);
}
}
}
@@ -477,8 +476,7 @@ void UserManagerBase::SaveUserDisplayEmail(const AccountId& account_id,
return;
DictionaryPrefUpdate display_email_update(GetLocalState(), kUserDisplayEmail);
- display_email_update->SetKey(account_id.GetUserEmail(),
- base::Value(display_email));
+ display_email_update->SetStringKey(account_id.GetUserEmail(), display_email);
}
void UserManagerBase::SaveUserType(const User* user) {
@@ -491,8 +489,8 @@ void UserManagerBase::SaveUserType(const User* user) {
return;
DictionaryPrefUpdate user_type_update(GetLocalState(), kUserType);
- user_type_update->SetKey(user->GetAccountId().GetAccountIdKey(),
- base::Value(static_cast<int>(user->GetType())));
+ user_type_update->SetIntKey(user->GetAccountId().GetAccountIdKey(),
+ static_cast<int>(user->GetType()));
GetLocalState()->CommitPendingWrite();
}
@@ -508,23 +506,22 @@ void UserManagerBase::UpdateUserAccountData(
user->set_given_name(given_name);
if (!IsUserNonCryptohomeDataEphemeral(account_id)) {
DictionaryPrefUpdate given_name_update(GetLocalState(), kUserGivenName);
- given_name_update->SetKey(account_id.GetUserEmail(),
- base::Value(given_name));
+ given_name_update->SetStringKey(account_id.GetUserEmail(), given_name);
}
}
UpdateUserAccountLocale(account_id, account_data.locale());
}
-void UserManagerBase::ParseUserList(const base::ListValue& users_list,
- const std::set<AccountId>& existing_users,
- std::vector<AccountId>* users_vector,
- std::set<AccountId>* users_set) {
+void UserManagerBase::ParseUserList(
+ const base::Value::ConstListView& users_list,
+ const std::set<AccountId>& existing_users,
+ std::vector<AccountId>* users_vector,
+ std::set<AccountId>* users_set) {
users_vector->clear();
users_set->clear();
- base::Value::ConstListView users_list_view = users_list.GetList();
- for (size_t i = 0; i < users_list_view.size(); ++i) {
- const std::string* email = users_list_view[i].GetIfString();
+ for (size_t i = 0; i < users_list.size(); ++i) {
+ const std::string* email = users_list[i].GetIfString();
if (!email || email->empty()) {
LOG(ERROR) << "Corrupt entry in user list at index " << i << ".";
continue;
@@ -805,17 +802,16 @@ void UserManagerBase::EnsureUsersLoaded() {
user_loading_stage_ = STAGE_LOADING;
PrefService* local_state = GetLocalState();
- const base::ListValue* prefs_regular_users =
+ const base::Value* prefs_regular_users =
local_state->GetList(kRegularUsersPref);
- const base::DictionaryValue* prefs_display_names =
+ const base::Value* prefs_display_names =
local_state->GetDictionary(kUserDisplayName);
- const base::DictionaryValue* prefs_given_names =
+ const base::Value* prefs_given_names =
local_state->GetDictionary(kUserGivenName);
- const base::DictionaryValue* prefs_display_emails =
+ const base::Value* prefs_display_emails =
local_state->GetDictionary(kUserDisplayEmail);
- const base::DictionaryValue* prefs_user_types =
- local_state->GetDictionary(kUserType);
+ const base::Value* prefs_user_types = local_state->GetDictionary(kUserType);
// Load public sessions first.
std::set<AccountId> device_local_accounts_set;
@@ -824,8 +820,8 @@ void UserManagerBase::EnsureUsersLoaded() {
// Load regular users and supervised users.
std::vector<AccountId> regular_users;
std::set<AccountId> regular_users_set;
- ParseUserList(*prefs_regular_users, device_local_accounts_set, &regular_users,
- &regular_users_set);
+ ParseUserList(prefs_regular_users->GetListDeprecated(),
+ device_local_accounts_set, &regular_users, &regular_users_set);
for (std::vector<AccountId>::const_iterator it = regular_users.begin();
it != regular_users.end(); ++it) {
if (IsDeprecatedSupervisedAccountId(*it)) {
@@ -840,7 +836,8 @@ void UserManagerBase::EnsureUsersLoaded() {
User::CreateRegularUser(*it, GetStoredUserType(prefs_user_types, *it));
user->set_oauth_token_status(LoadUserOAuthStatus(*it));
user->set_force_online_signin(LoadForceOnlineSignin(*it));
- user->set_using_saml(known_user::IsUsingSAML(*it));
+ KnownUser known_user(GetLocalState());
+ user->set_using_saml(known_user.IsUsingSAML(*it));
users_.push_back(user);
}
@@ -884,9 +881,8 @@ const User* UserManagerBase::FindUserInList(const AccountId& account_id) const {
}
bool UserManagerBase::UserExistsInList(const AccountId& account_id) const {
- const base::ListValue* user_list =
- GetLocalState()->GetList(kRegularUsersPref);
- for (const base::Value& i : user_list->GetList()) {
+ const base::Value* user_list = GetLocalState()->GetList(kRegularUsersPref);
+ for (const base::Value& i : user_list->GetListDeprecated()) {
const std::string* email = i.GetIfString();
if (email && (account_id.GetUserEmail() == *email))
return true;
@@ -911,7 +907,7 @@ void UserManagerBase::GuestUserLoggedIn() {
void UserManagerBase::AddUserRecord(User* user) {
// Add the user to the front of the user list.
ListPrefUpdate prefs_users_update(GetLocalState(), kRegularUsersPref);
- prefs_users_update->Insert(prefs_users_update->GetList().begin(),
+ prefs_users_update->Insert(prefs_users_update->GetListDeprecated().begin(),
base::Value(user->GetAccountId().GetUserEmail()));
users_.insert(users_.begin(), user);
}
@@ -921,9 +917,14 @@ void UserManagerBase::RegularUserLoggedIn(const AccountId& account_id,
// Remove the user from the user list.
active_user_ =
RemoveRegularOrSupervisedUserFromList(account_id, false /* notify */);
+ KnownUser known_user(GetLocalState());
- if (active_user_ && active_user_->GetType() != user_type)
+ if (active_user_ && active_user_->GetType() != user_type) {
active_user_->UpdateType(user_type);
+ // Clear information about profile policy requirements to enforce setting it
+ // again for the new account type.
+ known_user.ClearProfileRequiresPolicy(account_id);
+ }
// If the user was not found on the user list, create a new user.
SetIsCurrentUserNew(!active_user_);
@@ -939,8 +940,7 @@ void UserManagerBase::RegularUserLoggedIn(const AccountId& account_id,
}
AddUserRecord(active_user_);
- KnownUser(GetLocalState())
- .SetIsEphemeralUser(active_user_->GetAccountId(), false);
+ known_user.SetIsEphemeralUser(active_user_->GetAccountId(), false);
// Make sure that new data is persisted to Local State.
GetLocalState()->CommitPendingWrite();
@@ -975,7 +975,7 @@ User::OAuthTokenStatus UserManagerBase::LoadUserOAuthStatus(
const AccountId& account_id) const {
DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
- const base::DictionaryValue* prefs_oauth_status =
+ const base::Value* prefs_oauth_status =
GetLocalState()->GetDictionary(kUserOAuthTokenStatus);
if (!prefs_oauth_status)
return User::OAUTH_TOKEN_STATUS_UNKNOWN;
@@ -991,7 +991,7 @@ User::OAuthTokenStatus UserManagerBase::LoadUserOAuthStatus(
bool UserManagerBase::LoadForceOnlineSignin(const AccountId& account_id) const {
DCHECK(!task_runner_ || task_runner_->RunsTasksInCurrentSequence());
- const base::DictionaryValue* prefs_force_online =
+ const base::Value* prefs_force_online =
GetLocalState()->GetDictionary(kUserForceOnlineSignin);
if (prefs_force_online) {
return prefs_force_online->FindBoolKey(account_id.GetUserEmail())
diff --git a/chromium/components/user_manager/user_manager_base.h b/chromium/components/user_manager/user_manager_base.h
index d034cb14fb2..857ee12723f 100644
--- a/chromium/components/user_manager/user_manager_base.h
+++ b/chromium/components/user_manager/user_manager_base.h
@@ -18,6 +18,7 @@
#include "base/observer_list.h"
#include "base/synchronization/lock.h"
#include "base/time/time.h"
+#include "base/values.h"
#include "components/account_id/account_id.h"
#include "components/user_manager/remove_user_delegate.h"
#include "components/user_manager/user.h"
@@ -28,7 +29,6 @@
class PrefRegistrySimple;
namespace base {
-class ListValue;
class SingleThreadTaskRunner;
}
@@ -158,7 +158,7 @@ class USER_MANAGER_EXPORT UserManagerBase : public UserManager {
// Helper function that converts users from |users_list| to |users_vector| and
// |users_set|. Duplicates and users already present in |existing_users| are
// skipped.
- void ParseUserList(const base::ListValue& users_list,
+ void ParseUserList(const base::Value::ConstListView& users_list,
const std::set<AccountId>& existing_users,
std::vector<AccountId>* users_vector,
std::set<AccountId>* users_set);
diff --git a/chromium/components/value_store/leveldb_value_store_unittest.cc b/chromium/components/value_store/leveldb_value_store_unittest.cc
index 597d0606b7e..d7e04708790 100644
--- a/chromium/components/value_store/leveldb_value_store_unittest.cc
+++ b/chromium/components/value_store/leveldb_value_store_unittest.cc
@@ -99,7 +99,7 @@ TEST_F(LeveldbValueStoreUnitTest, RestoreKeyTest) {
// Verify that the valid pair is still present.
result = store()->Get(kNotCorruptKey);
EXPECT_TRUE(result.status().ok());
- EXPECT_TRUE(result.settings().HasKey(kNotCorruptKey));
+ EXPECT_TRUE(result.settings().FindKey(kNotCorruptKey));
std::string value_string;
EXPECT_TRUE(result.settings().GetString(kNotCorruptKey, &value_string));
EXPECT_EQ(kValue, value_string);
@@ -142,7 +142,7 @@ TEST_F(LeveldbValueStoreUnitTest, RestoreDoesMinimumNecessary) {
result = store()->Get(kNotCorruptKey);
EXPECT_TRUE(result.status().ok());
ASSERT_EQ(ValueStore::RESTORE_NONE, result.status().restore_status);
- EXPECT_TRUE(result.settings().HasKey(kNotCorruptKey));
+ EXPECT_TRUE(result.settings().FindKey(kNotCorruptKey));
EXPECT_TRUE(result.settings().GetString(kNotCorruptKey, &value_string));
EXPECT_EQ(kValue, value_string);
}
diff --git a/chromium/components/value_store/value_store_test_suite.cc b/chromium/components/value_store/value_store_test_suite.cc
index a3e7f92bdd8..ea23bed58cc 100644
--- a/chromium/components/value_store/value_store_test_suite.cc
+++ b/chromium/components/value_store/value_store_test_suite.cc
@@ -152,13 +152,13 @@ ValueStoreTestSuite::ValueStoreTestSuite()
set13_.insert(list13_.begin(), list13_.end());
set123_.insert(list123_.begin(), list123_.end());
- dict1_->Set(key1_, val1_->CreateDeepCopy());
- dict3_->Set(key3_, val3_->CreateDeepCopy());
- dict12_->Set(key1_, val1_->CreateDeepCopy());
- dict12_->Set(key2_, val2_->CreateDeepCopy());
- dict123_->Set(key1_, val1_->CreateDeepCopy());
- dict123_->Set(key2_, val2_->CreateDeepCopy());
- dict123_->Set(key3_, val3_->CreateDeepCopy());
+ dict1_->SetKey(key1_, val1_->Clone());
+ dict3_->SetKey(key3_, val3_->Clone());
+ dict12_->SetKey(key1_, val1_->Clone());
+ dict12_->SetKey(key2_, val2_->Clone());
+ dict123_->SetKey(key1_, val1_->Clone());
+ dict123_->SetKey(key2_, val2_->Clone());
+ dict123_->SetKey(key3_, val3_->Clone());
}
ValueStoreTestSuite::~ValueStoreTestSuite() = default;
@@ -320,8 +320,7 @@ TEST_P(ValueStoreTestSuite, DotsInKeyNames) {
std::vector<std::string> dot_list;
dot_list.push_back(dot_key);
base::DictionaryValue dot_dict;
- dot_dict.SetKey(dot_key,
- base::Value::FromUniquePtrValue(dot_value.CreateDeepCopy()));
+ dot_dict.SetKey(dot_key, dot_value.Clone());
EXPECT_PRED_FORMAT2(SettingsEq, *empty_dict_, storage_->Get(dot_key));
diff --git a/chromium/components/variations/BUILD.gn b/chromium/components/variations/BUILD.gn
index 406e48daceb..aabaa6ccf74 100644
--- a/chromium/components/variations/BUILD.gn
+++ b/chromium/components/variations/BUILD.gn
@@ -46,6 +46,8 @@ component("variations") {
"client_filterable_state.h",
"entropy_provider.cc",
"entropy_provider.h",
+ "fake_crash.cc",
+ "fake_crash.h",
"hashing.cc",
"hashing.h",
"metrics.cc",
@@ -231,7 +233,9 @@ source_set("unit_tests") {
# build returns the crash keys in the unit-test, not the "variations"
# target. The test verifies the keys in the "variations" target, not the
# test. As such, it fails in component builds.
- if (!is_component_build) {
+ # TODO(crbug.com/1186718): Enable this unittest for is_fuchsia when crash keys
+ # are supported on Fuchsia.
+ if (!is_component_build && !is_fuchsia) {
sources += [ "variations_crash_keys_unittest.cc" ]
}
diff --git a/chromium/components/variations/DEPS b/chromium/components/variations/DEPS
index aacb6bfa9f9..ebe4ffd9747 100644
--- a/chromium/components/variations/DEPS
+++ b/chromium/components/variations/DEPS
@@ -11,6 +11,7 @@ include_rules = [
"+components/version_info",
"+crypto",
"-net",
+ "+net/android",
"+third_party/protobuf",
"+third_party/smhasher",
"+third_party/zlib/google",
diff --git a/chromium/components/variations/android/BUILD.gn b/chromium/components/variations/android/BUILD.gn
index 1a45b036708..c740c321c06 100644
--- a/chromium/components/variations/android/BUILD.gn
+++ b/chromium/components/variations/android/BUILD.gn
@@ -8,6 +8,7 @@ android_library("variations_java") {
deps = [
"//base:base_java",
"//components/variations:variations_java",
+ "//net/android:net_java",
"//third_party/androidx:androidx_annotation_annotation_java",
]
annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
diff --git a/chromium/components/variations/android/junit/src/org/chromium/components/variations/firstrun/VariationsSeedFetcherTest.java b/chromium/components/variations/android/junit/src/org/chromium/components/variations/firstrun/VariationsSeedFetcherTest.java
index 93e08881fb4..9cdb0a5ef6d 100644
--- a/chromium/components/variations/android/junit/src/org/chromium/components/variations/firstrun/VariationsSeedFetcherTest.java
+++ b/chromium/components/variations/android/junit/src/org/chromium/components/variations/firstrun/VariationsSeedFetcherTest.java
@@ -80,9 +80,7 @@ public class VariationsSeedFetcherTest {
.getServerConnection(VariationsSeedFetcher.VariationsPlatform.ANDROID, sRestrict,
sMilestone, sChannel);
mPrefs = ContextUtils.getAppSharedPreferences();
-
- RecordHistogram.forgetHistogramForTesting(
- VariationsSeedFetcher.SEED_FETCH_RESULT_HISTOGRAM);
+ ShadowRecordHistogram.reset();
}
@After
diff --git a/chromium/components/variations/client_filterable_state.cc b/chromium/components/variations/client_filterable_state.cc
index 7a604a0ce20..7ffa65ad982 100644
--- a/chromium/components/variations/client_filterable_state.cc
+++ b/chromium/components/variations/client_filterable_state.cc
@@ -14,21 +14,21 @@ namespace variations {
// static
Study::Platform ClientFilterableState::GetCurrentPlatform() {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
return Study::PLATFORM_WINDOWS;
-#elif defined(OS_IOS)
+#elif BUILDFLAG(IS_IOS)
return Study::PLATFORM_IOS;
-#elif defined(OS_MAC)
+#elif BUILDFLAG(IS_MAC)
return Study::PLATFORM_MAC;
#elif BUILDFLAG(IS_CHROMEOS_ASH)
return Study::PLATFORM_CHROMEOS;
#elif BUILDFLAG(IS_CHROMEOS_LACROS)
return Study::PLATFORM_CHROMEOS_LACROS;
-#elif defined(OS_ANDROID)
+#elif BUILDFLAG(IS_ANDROID)
return Study::PLATFORM_ANDROID;
-#elif defined(OS_FUCHSIA)
+#elif BUILDFLAG(IS_FUCHSIA)
return Study::PLATFORM_FUCHSIA;
-#elif defined(OS_LINUX) || defined(OS_BSD) || defined(OS_SOLARIS)
+#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_BSD) || BUILDFLAG(IS_SOLARIS)
// Default BSD and SOLARIS to Linux to not break those builds, although these
// platforms are not officially supported by Chrome.
return Study::PLATFORM_LINUX;
@@ -45,7 +45,7 @@ Study::Platform ClientFilterableState::GetCurrentPlatform() {
base::Version ClientFilterableState::GetOSVersion() {
base::Version ret;
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
std::string win_version = base::SysInfo::OperatingSystemVersion();
base::ReplaceSubstringsAfterOffset(&win_version, 0, " SP", ".");
ret = base::Version(win_version);
diff --git a/chromium/components/variations/fake_crash.cc b/chromium/components/variations/fake_crash.cc
new file mode 100644
index 00000000000..fba8d5aa7b9
--- /dev/null
+++ b/chromium/components/variations/fake_crash.cc
@@ -0,0 +1,35 @@
+// Copyright (c) 2022 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.
+
+#include "components/variations/fake_crash.h"
+
+#include "base/bind.h"
+#include "base/debug/dump_without_crashing.h"
+#include "base/feature_list.h"
+#include "base/logging.h"
+#include "base/task/thread_pool.h"
+#include "base/time/time.h"
+
+namespace {
+// This feature causes a crash report to be created after startup (without
+// actually crashing). This is used for verifying safety measures that help
+// catch features that cause real crashes.
+const base::Feature kVariationsFakeCrashAfterStartup{
+ "VariationsFakeCrashAfterStartup", base::FEATURE_DISABLED_BY_DEFAULT};
+} // namespace
+
+namespace variations {
+
+void MaybeScheduleFakeCrash() {
+ if (base::FeatureList::IsEnabled(kVariationsFakeCrashAfterStartup)) {
+ base::ThreadPool::PostDelayedTask(
+ FROM_HERE, base::BindOnce([]() {
+ LOG(ERROR) << "Creating dump for VariationsFakeCrashAfterStartup";
+ base::debug::DumpWithoutCrashing();
+ }),
+ base::Seconds(15));
+ }
+}
+
+} // namespace variations \ No newline at end of file
diff --git a/chromium/components/variations/fake_crash.h b/chromium/components/variations/fake_crash.h
new file mode 100644
index 00000000000..b954dacccad
--- /dev/null
+++ b/chromium/components/variations/fake_crash.h
@@ -0,0 +1,17 @@
+// Copyright (c) 2022 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.
+
+#ifndef COMPONENTS_VARIATIONS_FAKE_CRASH_H_
+#define COMPONENTS_VARIATIONS_FAKE_CRASH_H_
+
+#include "base/component_export.h"
+
+namespace variations {
+// Schedules a crash dump to be uploaded (without crashing), if a
+// VariationsFakeCrashAfterStartup is enabled. This enabled verification of
+// safety measure for detecting crashes caused by features.
+COMPONENT_EXPORT(VARIATIONS) void MaybeScheduleFakeCrash();
+} // namespace variations
+
+#endif // COMPONENTS_VARIATIONS_FAKE_CRASH_H_ \ No newline at end of file
diff --git a/chromium/components/variations/field_trial_config/field_trial_util.cc b/chromium/components/variations/field_trial_config/field_trial_util.cc
index 4d7f8396cd0..ee0c8ffe57b 100644
--- a/chromium/components/variations/field_trial_config/field_trial_util.cc
+++ b/chromium/components/variations/field_trial_config/field_trial_util.cc
@@ -78,11 +78,35 @@ void ApplyUIStringOverrides(
}
}
+// Determines whether an experiment should be skipped or not. An experiment
+// should be skipped if it enables or disables a feature that is already
+// overridden through the command line.
+bool ShouldSkipExperiment(const FieldTrialTestingExperiment& experiment,
+ base::FeatureList* feature_list) {
+ for (size_t i = 0; i < experiment.enable_features_size; ++i) {
+ if (feature_list->IsFeatureOverridden(experiment.enable_features[i])) {
+ return true;
+ }
+ }
+ for (size_t i = 0; i < experiment.disable_features_size; ++i) {
+ if (feature_list->IsFeatureOverridden(experiment.disable_features[i])) {
+ return true;
+ }
+ }
+ return false;
+}
+
void AssociateParamsFromExperiment(
const std::string& study_name,
const FieldTrialTestingExperiment& experiment,
const VariationsSeedProcessor::UIStringOverrideCallback& callback,
base::FeatureList* feature_list) {
+ if (ShouldSkipExperiment(experiment, feature_list)) {
+ LOG(WARNING) << "Field trial config study skipped: " << study_name << "."
+ << experiment.name
+ << " (some of its features are already overridden)";
+ return;
+ }
if (experiment.params_size != 0) {
base::FieldTrialParams params;
for (size_t i = 0; i < experiment.params_size; ++i) {
@@ -95,9 +119,9 @@ void AssociateParamsFromExperiment(
base::FieldTrialList::CreateFieldTrial(study_name, experiment.name);
if (!trial) {
- DLOG(WARNING) << "Field trial config study skipped: " << study_name
- << "." << experiment.name
- << " (it is overridden from chrome://flags)";
+ LOG(WARNING) << "Field trial config study skipped: " << study_name << "."
+ << experiment.name
+ << " (it is overridden from chrome://flags)";
return;
}
@@ -124,6 +148,10 @@ void AssociateParamsFromExperiment(
// - Otherwise, If running on non low_end_device and the config specify
// a different experiment group for non low_end_device then pick that.
// - Otherwise, select the first experiment.
+// - The chosen experiment must not enable or disable a feature that is
+// explicitly enabled or disabled through a switch, such as the
+// |--enable-features| or |--disable-features| switches. If it does, then no
+// experiment is associated.
// - If no experiments match this platform, do not associate any of them.
void ChooseExperiment(
const FieldTrialTestingStudy& study,
diff --git a/chromium/components/variations/field_trial_config/field_trial_util_unittest.cc b/chromium/components/variations/field_trial_config/field_trial_util_unittest.cc
index 22902f6ddc3..6040e413aae 100644
--- a/chromium/components/variations/field_trial_config/field_trial_util_unittest.cc
+++ b/chromium/components/variations/field_trial_config/field_trial_util_unittest.cc
@@ -216,6 +216,143 @@ TEST_F(FieldTrialUtilTest, AssociateParamsFromFieldTrialConfig) {
EXPECT_EQ("TestGroup2", base::FieldTrialList::FindFullName("TestTrial2"));
}
+// Verifies that studies in the field trial config should be skipped if they
+// enable/disable features that were overridden through the command line.
+TEST_F(FieldTrialUtilTest, FieldTrialConfigSkipOverridden) {
+ // Create a testing config equivalent to:
+ // {
+ // "TestTrial0": [
+ // {
+ // "platforms": ["linux"],
+ // "experiments": [
+ // {
+ // "name": "TestGroup0",
+ // "enable_features": ["A"]
+ // }
+ // ]
+ // }
+ // ],
+ // "TestTrial1": [
+ // {
+ // "platforms": ["linux"],
+ // "experiments": [
+ // {
+ // "name": "TestGroup1",
+ // "disable_features": ["A"]
+ // }
+ // ]
+ // }
+ // ],
+ // "TestTrial2": [
+ // {
+ // "platforms": ["linux"],
+ // "experiments": [
+ // {
+ // "name": "TestGroup2",
+ // "enable_features": ["C"],
+ // "disable_features": ["D"]
+ // }
+ // ]
+ // }
+ // ]
+ // }
+ const Study::Platform platform = Study::PLATFORM_LINUX;
+
+ const char* enable_features_0[] = {"A"};
+ const FieldTrialTestingExperiment array_kFieldTrialConfig_experiments_0[] = {
+ {/*name=*/"TestGroup0",
+ /*platforms=*/&platform,
+ /*platforms_size=*/1,
+ /*form_factors=*/{},
+ /*form_factors_size=*/0,
+ /*is_low_end_device=*/absl::nullopt,
+ /*min_os_version=*/nullptr,
+ /*params=*/nullptr,
+ /*params_size=*/0,
+ /*enable_features=*/enable_features_0,
+ /*enable_features_size=*/1,
+ /*disable_features=*/nullptr,
+ /*disable_features_size=*/0,
+ /*forcing_flag=*/nullptr,
+ /*override_ui_string=*/nullptr,
+ /*override_ui_string_size=*/0},
+ };
+
+ const char* disable_features_1[] = {"B"};
+ const FieldTrialTestingExperiment array_kFieldTrialConfig_experiments_1[] = {
+ {/*name=*/"TestGroup1",
+ /*platforms=*/&platform,
+ /*platforms_size=*/1,
+ /*form_factors=*/{},
+ /*form_factors_size=*/0,
+ /*is_low_end_device=*/absl::nullopt,
+ /*min_os_version=*/nullptr,
+ /*params=*/nullptr,
+ /*params_size=*/0,
+ /*enable_features=*/nullptr,
+ /*enable_features_size=*/0,
+ /*disable_features=*/disable_features_1,
+ /*disable_features_size=*/1,
+ /*forcing_flag=*/nullptr,
+ /*override_ui_string=*/nullptr,
+ /*override_ui_string_size=*/0},
+ };
+
+ const char* enable_features2[] = {"C"};
+ const char* disable_features_2[] = {"D"};
+ const FieldTrialTestingExperiment array_kFieldTrialConfig_experiments_2[] = {
+ {/*name=*/"TestGroup2",
+ /*platforms=*/&platform,
+ /*platforms_size=*/1,
+ /*form_factors=*/{},
+ /*form_factors_size=*/0,
+ /*is_low_end_device=*/absl::nullopt,
+ /*min_os_version=*/nullptr,
+ /*params=*/nullptr,
+ /*params_size=*/0,
+ /*enable_features=*/enable_features2,
+ /*enable_features_size=*/1,
+ /*disable_features=*/disable_features_2,
+ /*disable_features_size=*/1,
+ /*forcing_flag=*/nullptr,
+ /*override_ui_string=*/nullptr,
+ /*override_ui_string_size=*/0},
+ };
+
+ const FieldTrialTestingStudy array_kFieldTrialConfig_studies[] = {
+ {/*name=*/"TestTrial0",
+ /*experiments=*/array_kFieldTrialConfig_experiments_0,
+ /*experiments_size=*/1},
+ {/*name=*/"TestTrial1",
+ /*experiments=*/array_kFieldTrialConfig_experiments_1,
+ /*experiments_size=*/1},
+ {/*name=*/"TestTrial2",
+ /*experiments=*/array_kFieldTrialConfig_experiments_2,
+ /*experiments_size=*/1},
+ };
+
+ const FieldTrialTestingConfig kConfig = {
+ /*studies=*/array_kFieldTrialConfig_studies, /*studies_size=*/3};
+
+ base::FeatureList feature_list;
+ // Enable feature "A" and disable feature "B" as if they were enabled/disabled
+ // using the |--enable-features| and |--disable-features| switches.
+ base::FieldTrialList::CreateFieldTrial("Study", "Experiment");
+ feature_list.InitializeFromCommandLine(/*enable_features=*/"A<Study",
+ /*disable_features=*/"B");
+
+ // Associate the |kConfig| field trial config.
+ AssociateParamsFromFieldTrialConfig(
+ kConfig, override_callback_.callback(), platform,
+ variation_service_client_.GetCurrentFormFactor(), &feature_list);
+
+ // Expect only TestTrial2 to have been registered as it is the only study to
+ // not enable/disable features A or B.
+ EXPECT_FALSE(base::FieldTrialList::TrialExists("TestTrial0"));
+ EXPECT_FALSE(base::FieldTrialList::TrialExists("TestTrial1"));
+ EXPECT_TRUE(base::FieldTrialList::TrialExists("TestTrial2"));
+}
+
TEST_F(FieldTrialUtilTest,
AssociateParamsFromFieldTrialConfigWithEachPlatform) {
const Study::Platform all_platforms[] = {
diff --git a/chromium/components/variations/metrics.cc b/chromium/components/variations/metrics.cc
index 3f57768060e..07150095df0 100644
--- a/chromium/components/variations/metrics.cc
+++ b/chromium/components/variations/metrics.cc
@@ -6,15 +6,16 @@
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
+#include "build/build_config.h"
namespace variations {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
void RecordFirstRunSeedImportResult(FirstRunSeedImportResult result) {
UMA_HISTOGRAM_ENUMERATION("Variations.FirstRunResult", result,
FirstRunSeedImportResult::ENUM_SIZE);
}
-#endif // OS_ANDROID
+#endif // BUILDFLAG(IS_ANDROID)
void RecordLoadSeedResult(LoadSeedResult state) {
base::UmaHistogramEnumeration("Variations.SeedLoadResult", state);
diff --git a/chromium/components/variations/metrics.h b/chromium/components/variations/metrics.h
index 0bae191fc94..8b80750b6ee 100644
--- a/chromium/components/variations/metrics.h
+++ b/chromium/components/variations/metrics.h
@@ -10,7 +10,7 @@
namespace variations {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// The result of importing a seed during Android first run.
// Note: UMA histogram enum - don't re-order or remove entries.
enum class FirstRunSeedImportResult {
@@ -21,7 +21,7 @@ enum class FirstRunSeedImportResult {
FAIL_INVALID_RESPONSE_DATE,
ENUM_SIZE
};
-#endif // OS_ANDROID
+#endif // BUILDFLAG(IS_ANDROID)
// The result of attempting to load a variations seed during startup.
//
@@ -99,11 +99,11 @@ struct InstanceManipulations {
const bool delta_compressed;
};
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Records the result of importing a seed during Android first run.
COMPONENT_EXPORT(VARIATIONS)
void RecordFirstRunSeedImportResult(FirstRunSeedImportResult result);
-#endif // OS_ANDROID
+#endif // BUILDFLAG(IS_ANDROID)
// Records the result of attempting to load the latest variations seed on
// startup.
diff --git a/chromium/components/variations/processed_study.cc b/chromium/components/variations/processed_study.cc
index 82cdeec44fd..9aad00bb237 100644
--- a/chromium/components/variations/processed_study.cc
+++ b/chromium/components/variations/processed_study.cc
@@ -30,7 +30,8 @@ enum class InvalidStudyReason {
kMissingDefaultExperimentInList = 7,
kBlankStudyName = 8,
kExperimentProbabilityOverflow = 9,
- kMaxValue = kExperimentProbabilityOverflow,
+ kTriggerAndNonTriggerExperimentId = 10,
+ kMaxValue = kTriggerAndNonTriggerExperimentId,
};
void LogInvalidReason(InvalidStudyReason reason) {
@@ -116,6 +117,15 @@ bool ValidateStudyAndComputeTotalProbability(
}
}
+ if (experiment.has_google_web_experiment_id() &&
+ experiment.has_google_web_trigger_experiment_id()) {
+ LogInvalidReason(InvalidStudyReason::kTriggerAndNonTriggerExperimentId);
+ DVLOG(1) << study.name() << " has experiment (" << experiment.name()
+ << ") with a google_web_experiment_id and a "
+ << "web_trigger_experiment_id.";
+ return false;
+ }
+
if (!experiment.has_forcing_flag() && experiment.probability_weight() > 0) {
// If |divisor| is not 0, there was at least one prior non-zero group.
if (divisor != 0)
@@ -208,11 +218,11 @@ int ProcessedStudy::GetExperimentIndexByName(const std::string& name) const {
return -1;
}
-const char* ProcessedStudy::GetDefaultExperimentName() const {
+const base::StringPiece ProcessedStudy::GetDefaultExperimentName() const {
if (study_->default_experiment_name().empty())
return kGenericDefaultExperimentName;
- return study_->default_experiment_name().c_str();
+ return study_->default_experiment_name();
}
} // namespace variations
diff --git a/chromium/components/variations/processed_study.h b/chromium/components/variations/processed_study.h
index 1b60a113351..9034012aecc 100644
--- a/chromium/components/variations/processed_study.h
+++ b/chromium/components/variations/processed_study.h
@@ -52,7 +52,7 @@ class COMPONENT_EXPORT(VARIATIONS) ProcessedStudy {
// Gets the default experiment name for the study, or a generic one if none is
// specified.
- const char* GetDefaultExperimentName() const;
+ const base::StringPiece GetDefaultExperimentName() const;
private:
// Corresponding Study object. Weak reference.
diff --git a/chromium/components/variations/service/BUILD.gn b/chromium/components/variations/service/BUILD.gn
index 95354b4930b..fa6a61ff8db 100644
--- a/chromium/components/variations/service/BUILD.gn
+++ b/chromium/components/variations/service/BUILD.gn
@@ -8,12 +8,10 @@ import("//build/config/chrome_build.gni")
declare_args() {
# Set to true make a build that disables activation of field trial tests
# specified in testing/variations/fieldtrial_testing_config.json.
- # Note: this setting is ignored if is_chrome_branded.
disable_fieldtrial_testing_config = false
}
-fieldtrial_testing_enabled =
- !disable_fieldtrial_testing_config && !is_chrome_branded
+fieldtrial_testing_enabled = !disable_fieldtrial_testing_config
buildflag_header("buildflags") {
header = "buildflags.h"
@@ -67,15 +65,18 @@ source_set("unit_tests") {
]
deps = [
+ ":buildflags",
":constants",
":service",
"//base",
"//base/test:test_support",
+ "//build:branding_buildflags",
"//components/metrics",
"//components/metrics:test_support",
"//components/prefs:test_support",
"//components/variations",
"//components/variations:test_support",
+ "//components/variations/field_trial_config",
"//components/variations/proto",
"//components/version_info",
"//components/web_resource:test_support",
diff --git a/chromium/components/variations/service/variations_field_trial_creator.cc b/chromium/components/variations/service/variations_field_trial_creator.cc
index 86461fd574c..b74ee614201 100644
--- a/chromium/components/variations/service/variations_field_trial_creator.cc
+++ b/chromium/components/variations/service/variations_field_trial_creator.cc
@@ -24,6 +24,8 @@
#include "base/system/sys_info.h"
#include "base/trace_event/trace_event.h"
#include "base/version.h"
+#include "build/branding_buildflags.h"
+#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "components/language/core/browser/locale_util.h"
#include "components/metrics/metrics_state_manager.h"
@@ -145,6 +147,32 @@ Study::CpuArchitecture GetCurrentCpuArchitecture() {
return Study::X86_64;
}
+// Determines whether the field trial testing config defined in
+// testing/variations/fieldtrial_testing_config.json should be applied. If the
+// "disable_fieldtrial_testing_config" GN flag is set to true, then the testing
+// config should never be applied. Otherwise, if the build is a Chrome-branded
+// build, then the testing config should only be applied if the
+// "--enable-field-trial-config" switch is passed. For non-Chrome branded
+// builds, by default, the testing config is applied, unless the
+// "--disable-field-trial-config", "--force-fieldtrials", and/or
+// "--variations-server-url" switches are passed. It is however possible to
+// apply the testing config as well as specify additional field trials (using
+// "--force-fieldtrials") by using the "--enable-field-trial-config" switch.
+bool ShouldUseFieldTrialTestingConfig(const base::CommandLine* command_line) {
+#if BUILDFLAG(FIELDTRIAL_TESTING_ENABLED)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
+ return command_line->HasSwitch(switches::kEnableFieldTrialTestingConfig);
+#else
+ return command_line->HasSwitch(switches::kEnableFieldTrialTestingConfig) ||
+ (!command_line->HasSwitch(switches::kDisableFieldTrialTestingConfig) &&
+ !command_line->HasSwitch(::switches::kForceFieldTrials) &&
+ !command_line->HasSwitch(switches::kVariationsServerURL));
+#endif // BUILDFLAG(GOOGLE_CHROME_BRANDING)
+#else
+ return false;
+#endif // BUILDFLAG(FIELDTRIAL_TESTING_ENABLED)
+}
+
} // namespace
const base::Feature kForceFieldTrialSetupCrashForTesting{
@@ -183,14 +211,13 @@ bool VariationsFieldTrialCreator::SetUpFieldTrials(
metrics::MetricsStateManager* metrics_state_manager,
PlatformFieldTrials* platform_field_trials,
SafeSeedManager* safe_seed_manager,
- absl::optional<int> low_entropy_source_value,
- bool extend_variations_safe_mode) {
+ absl::optional<int> low_entropy_source_value) {
DCHECK(feature_list);
DCHECK(metrics_state_manager);
DCHECK(platform_field_trials);
DCHECK(safe_seed_manager);
- if (extend_variations_safe_mode &&
+ if (base::FieldTrialList::IsTrialActive(kExtendedSafeModeTrial) &&
!metrics_state_manager->is_background_session()) {
// If the session is expected to be a background session, then do not extend
// Variations Safe Mode. Extending Safe Mode involves monitoring for crashes
@@ -247,19 +274,11 @@ bool VariationsFieldTrialCreator::SetUpFieldTrials(
feature_list->RegisterExtraFeatureOverrides(extra_overrides);
bool used_testing_config = false;
-#if BUILDFLAG(FIELDTRIAL_TESTING_ENABLED)
- if (!command_line->HasSwitch(switches::kDisableFieldTrialTestingConfig) &&
- !command_line->HasSwitch(::switches::kForceFieldTrials) &&
- !command_line->HasSwitch(switches::kVariationsServerURL)) {
- // Note that passing base::Unretained(this) below is safe because the
- // callback is executed synchronously.
- AssociateDefaultFieldTrialConfig(
- base::BindRepeating(&VariationsFieldTrialCreator::OverrideUIString,
- base::Unretained(this)),
- GetPlatform(), client_->GetCurrentFormFactor(), feature_list.get());
+ if (ShouldUseFieldTrialTestingConfig(command_line)) {
+ ApplyFieldTrialTestingConfig(feature_list.get());
used_testing_config = true;
}
-#endif // BUILDFLAG(FIELDTRIAL_TESTING_ENABLED)
+
bool used_seed = false;
if (!used_testing_config) {
used_seed = CreateTrialsFromSeed(low_entropy_provider.get(),
@@ -300,14 +319,14 @@ VariationsFieldTrialCreator::GetClientFilterableStateForVersion(
state->os_version = ClientFilterableState::GetOSVersion();
state->channel =
ConvertProductChannelToStudyChannel(client_->GetChannelForVariations());
- state->form_factor = client_->GetCurrentFormFactor();
+ state->form_factor = GetCurrentFormFactor();
state->cpu_architecture = GetCurrentCpuArchitecture();
state->platform = GetPlatform();
// TODO(crbug/1111131): Expand to other platforms.
-#if BUILDFLAG(IS_CHROMEOS_ASH) || defined(OS_ANDROID)
+#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_ANDROID)
state->hardware_class = base::SysInfo::HardwareModelName();
#endif
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// This is set on Android only currently, because the IsLowEndDevice() API
// on other platforms has no intrinsic meaning outside of a field trial that
// controls its value. Since this is before server-side field trials are
@@ -343,17 +362,18 @@ std::string VariationsFieldTrialCreator::LoadPermanentConsistencyCountry(
return permanent_overridden_country;
}
- const base::ListValue* list_value =
+ const base::Value* list_value =
local_state()->GetList(prefs::kVariationsPermanentConsistencyCountry);
const std::string* stored_version_string = nullptr;
const std::string* stored_country = nullptr;
// Determine if the saved pref value is present and valid.
- const bool is_pref_empty = list_value->GetList().empty();
+ const bool is_pref_empty = list_value->GetListDeprecated().empty();
const bool is_pref_valid =
- list_value->GetList().size() == 2 &&
- (stored_version_string = list_value->GetList()[0].GetIfString()) &&
- (stored_country = list_value->GetList()[1].GetIfString()) &&
+ list_value->GetListDeprecated().size() == 2 &&
+ (stored_version_string =
+ list_value->GetListDeprecated()[0].GetIfString()) &&
+ (stored_country = list_value->GetListDeprecated()[1].GetIfString()) &&
base::Version(*stored_version_string).IsValid();
// Determine if the version from the saved pref matches |version|.
@@ -449,7 +469,9 @@ void VariationsFieldTrialCreator::MaybeExtendVariationsSafeMode(
metrics::MetricsStateManager* metrics_state_manager) {
const std::string group_name =
base::FieldTrialList::FindFullName(kExtendedSafeModeTrial);
- if (group_name.empty() || group_name == kDefaultGroup)
+ DCHECK(!group_name.empty());
+
+ if (group_name == kDefaultGroup)
return;
if (group_name == kControlGroup) {
@@ -463,7 +485,44 @@ void VariationsFieldTrialCreator::MaybeExtendVariationsSafeMode(
DCHECK_EQ(group_name, kSignalAndWriteViaFileUtilGroup);
metrics_state_manager->LogHasSessionShutdownCleanly(
/*has_session_shutdown_cleanly=*/false,
- /*write_synchronously=*/true);
+ /*is_extended_safe_mode=*/true);
+}
+
+Study::Platform VariationsFieldTrialCreator::GetPlatform() {
+ if (has_platform_override_)
+ return platform_override_;
+ return ClientFilterableState::GetCurrentPlatform();
+}
+
+void VariationsFieldTrialCreator::OverrideUIString(uint32_t resource_hash,
+ const std::u16string& str) {
+ int resource_id = ui_string_overrider_.GetResourceIndex(resource_hash);
+ if (resource_id == -1)
+ return;
+
+ // This function may be called before the resource bundle is initialized. So
+ // we cache the UI strings and override them after the full browser starts.
+ if (!ui::ResourceBundle::HasSharedInstance()) {
+ overridden_strings_map_[resource_id] = str;
+ return;
+ }
+
+ ui::ResourceBundle::GetSharedInstance().OverrideLocaleStringResource(
+ resource_id, str);
+}
+
+Study::FormFactor VariationsFieldTrialCreator::GetCurrentFormFactor() {
+ return client_->GetCurrentFormFactor();
+}
+
+void VariationsFieldTrialCreator::ApplyFieldTrialTestingConfig(
+ base::FeatureList* feature_list) {
+ // Note that passing base::Unretained(this) below is safe because the callback
+ // is executed synchronously.
+ AssociateDefaultFieldTrialConfig(
+ base::BindRepeating(&VariationsFieldTrialCreator::OverrideUIString,
+ base::Unretained(this)),
+ GetPlatform(), GetCurrentFormFactor(), feature_list);
}
bool VariationsFieldTrialCreator::HasSeedExpired(bool is_safe_seed) {
@@ -481,6 +540,8 @@ bool VariationsFieldTrialCreator::HasSeedExpired(bool is_safe_seed) {
if (!is_safe_seed) {
// Store the current time as the last fetch time for Chrome's first run.
GetSeedStore()->RecordLastFetchTime(base::Time::Now());
+ // Record freshness of "0", since we expect a first run seed to be fresh.
+ RecordSeedFreshness(base::TimeDelta());
}
return false;
}
@@ -534,12 +595,9 @@ bool VariationsFieldTrialCreator::CreateTrialsFromSeed(
client_filterable_state->policy_restriction);
VariationsSeed seed;
- bool should_run_in_safe_mode = safe_seed_manager->ShouldRunInSafeMode();
- bool run_in_safe_mode = should_run_in_safe_mode;
- if (should_run_in_safe_mode) {
- LoadSeedResult result =
- GetSeedStore()->LoadSafeSeed(&seed, client_filterable_state.get());
- if (result == LoadSeedResult::kSuccess) {
+ bool run_in_safe_mode = safe_seed_manager->ShouldRunInSafeMode();
+ if (run_in_safe_mode) {
+ if (GetSeedStore()->LoadSafeSeed(&seed, client_filterable_state.get())) {
// TODO(crbug/1261685): The expiry and milestone checks are repeated below
// for regular seeds. Refactor this.
if (HasSeedExpired(/*is_safe_seed=*/true)) {
@@ -552,15 +610,11 @@ bool VariationsFieldTrialCreator::CreateTrialsFromSeed(
return false;
}
RecordVariationsSeedUsage(SeedUsage::kSafeSeedUsed);
- run_in_safe_mode = true; // This line is a no-op. Added for clarity.
- } else if (result == LoadSeedResult::kEmpty) {
- // If the safe seed is empty, attempt to run with the most recent seed
- // instead of falling back to client-side defaults.
- run_in_safe_mode = false;
} else {
- // If Chrome should run in safe mode but the safe seed is corrupted or has
- // an invalid signature, then fall back to the client-side defaults.
- RecordVariationsSeedUsage(SeedUsage::kCorruptedSafeSeedNotUsed);
+ // If Chrome should run in safe mode but the safe seed was not
+ // successfully loaded, then do not apply a seed. Fall back to client-side
+ // defaults.
+ RecordVariationsSeedUsage(SeedUsage::kUnloadableSafeSeedNotUsed);
return false;
}
}
@@ -568,14 +622,9 @@ bool VariationsFieldTrialCreator::CreateTrialsFromSeed(
std::string seed_data;
std::string base64_seed_signature;
if (!run_in_safe_mode) {
- SeedUsage seed_usage;
if (GetSeedStore()->LoadSeed(&seed, &seed_data, &base64_seed_signature)) {
if (HasSeedExpired(/*is_safe_seed=*/false)) {
- seed_usage =
- should_run_in_safe_mode
- ? SeedUsage::kExpiredRegularSeedNotUsedAfterEmptySafeSeedLoaded
- : SeedUsage::kExpiredRegularSeedNotUsed;
- RecordVariationsSeedUsage(seed_usage);
+ RecordVariationsSeedUsage(SeedUsage::kExpiredRegularSeedNotUsed);
return false;
}
if (IsSeedForFutureMilestone(/*is_safe_seed=*/false)) {
@@ -583,16 +632,11 @@ bool VariationsFieldTrialCreator::CreateTrialsFromSeed(
SeedUsage::kRegularSeedForFutureMilestoneNotUsed);
return false;
}
- seed_usage = should_run_in_safe_mode
- ? SeedUsage::kRegularSeedUsedAfterEmptySafeSeedLoaded
- : SeedUsage::kRegularSeedUsed;
- RecordVariationsSeedUsage(seed_usage);
- } else { // The seed was not successfully loaded.
- seed_usage =
- should_run_in_safe_mode
- ? SeedUsage::kCorruptedRegularSeedNotUsedAfterEmptySafeSeedLoaded
- : SeedUsage::kCorruptedSeedNotUsed;
- RecordVariationsSeedUsage(seed_usage);
+ RecordVariationsSeedUsage(SeedUsage::kRegularSeedUsed);
+ } else {
+ // The regular seed was not successfully loaded, so do not apply a seed.
+ // Fall back to client-side defaults.
+ RecordVariationsSeedUsage(SeedUsage::kUnloadableRegularSeedNotUsed);
return false;
}
}
@@ -625,23 +669,6 @@ bool VariationsFieldTrialCreator::CreateTrialsFromSeed(
return true;
}
-void VariationsFieldTrialCreator::OverrideUIString(uint32_t resource_hash,
- const std::u16string& str) {
- int resource_id = ui_string_overrider_.GetResourceIndex(resource_hash);
- if (resource_id == -1)
- return;
-
- // This function may be called before the resource bundle is initialized. So
- // we cache the UI strings and override them after the full browser starts.
- if (!ui::ResourceBundle::HasSharedInstance()) {
- overridden_strings_map_[resource_id] = str;
- return;
- }
-
- ui::ResourceBundle::GetSharedInstance().OverrideLocaleStringResource(
- resource_id, str);
-}
-
VariationsSeedStore* VariationsFieldTrialCreator::GetSeedStore() {
return seed_store_.get();
}
@@ -650,10 +677,4 @@ base::Time VariationsFieldTrialCreator::GetBuildTime() const {
return base::GetBuildTime();
}
-Study::Platform VariationsFieldTrialCreator::GetPlatform() {
- if (has_platform_override_)
- return platform_override_;
- return ClientFilterableState::GetCurrentPlatform();
-}
-
} // namespace variations
diff --git a/chromium/components/variations/service/variations_field_trial_creator.h b/chromium/components/variations/service/variations_field_trial_creator.h
index 8baf0c6500b..44030957e58 100644
--- a/chromium/components/variations/service/variations_field_trial_creator.h
+++ b/chromium/components/variations/service/variations_field_trial_creator.h
@@ -37,16 +37,18 @@ namespace variations {
enum class SeedUsage {
kRegularSeedUsed = 0,
kExpiredRegularSeedNotUsed = 1,
- kCorruptedSeedNotUsed = 2,
+ kUnloadableRegularSeedNotUsed = 2,
kSafeSeedUsed = 3,
kExpiredSafeSeedNotUsed = 4,
- kCorruptedSafeSeedNotUsed = 5,
- kRegularSeedUsedAfterEmptySafeSeedLoaded = 6,
- kExpiredRegularSeedNotUsedAfterEmptySafeSeedLoaded = 7,
- kCorruptedRegularSeedNotUsedAfterEmptySafeSeedLoaded = 8,
+ // The below three enumerators were deprecated in M100.
+ // kCorruptedSafeSeedNotUsed = 5,
+ // kRegularSeedUsedAfterEmptySafeSeedLoaded = 6,
+ // kExpiredRegularSeedNotUsedAfterEmptySafeSeedLoaded = 7,
+ // kCorruptedRegularSeedNotUsedAfterEmptySafeSeedLoaded = 8,
kRegularSeedForFutureMilestoneNotUsed = 9,
kSafeSeedForFutureMilestoneNotUsed = 10,
- kMaxValue = kSafeSeedForFutureMilestoneNotUsed,
+ kUnloadableSafeSeedNotUsed = 11,
+ kMaxValue = kUnloadableSafeSeedNotUsed,
};
// Denotes a variations seed's expiry state. Exposed for testing.
@@ -120,11 +122,6 @@ class VariationsFieldTrialCreator {
// value is true). Must not be null.
// |low_entropy_source_value| contains the low entropy source value that was
// used for client-side randomization of variations.
- // |extend_variations_safe_mode| indicates whether the client should
- // participate in the extended variations safe mode field trial. This should
- // be the case for all platforms that use a VariationsSeed with the exception
- // of Android WebView, which has its own safe mode mechanism: crbug/1220131.
- // TODO(crbug/1245646): Remove |extend_variations_safe_mode| param.
//
// NOTE: The ordering of the FeatureList method calls is such that the
// explicit --disable-features and --enable-features from the command line
@@ -140,8 +137,7 @@ class VariationsFieldTrialCreator {
metrics::MetricsStateManager* metrics_state_manager,
PlatformFieldTrials* platform_field_trials,
SafeSeedManager* safe_seed_manager,
- absl::optional<int> low_entropy_source_value,
- bool extend_variations_safe_mode = true);
+ absl::optional<int> low_entropy_source_value);
// Returns all of the client state used for filtering studies.
// As a side-effect, may update the stored permanent consistency country.
@@ -186,6 +182,22 @@ class VariationsFieldTrialCreator {
virtual void MaybeExtendVariationsSafeMode(
metrics::MetricsStateManager* metrics_state_manager);
+ // Get the platform we're running on, respecting OverrideVariationsPlatform().
+ // Protected for testing.
+ Study::Platform GetPlatform();
+
+ // Overrides the string resource specified by |hash| with |str| in the
+ // resource bundle. Protected for testing.
+ void OverrideUIString(uint32_t hash, const std::u16string& str);
+
+ // Get the client's current form factor. Protected for testing.
+ Study::FormFactor GetCurrentFormFactor();
+
+ // Applies the field trial testing config defined in
+ // testing/variations/fieldtrial_testing_config.json to the current session.
+ // Protected and virtual for testing.
+ virtual void ApplyFieldTrialTestingConfig(base::FeatureList* feature_list);
+
private:
// Returns true if the loaded VariationsSeed has expired. An expired seed is
// one that (a) was fetched over |kMaxVariationsSeedAgeDays| ago and (b) is
@@ -212,19 +224,12 @@ class VariationsFieldTrialCreator {
base::FeatureList* feature_list,
SafeSeedManager* safe_seed_manager);
- // Overrides the string resource specified by |hash| with |str| in the
- // resource bundle.
- void OverrideUIString(uint32_t hash, const std::u16string& str);
-
// Returns the seed store. Virtual for testing.
virtual VariationsSeedStore* GetSeedStore();
// Returns the time at which the binary was built. Virtual for testing.
virtual base::Time GetBuildTime() const;
- // Get the platform we're running on, respecting OverrideVariationsPlatform().
- Study::Platform GetPlatform();
-
PrefService* local_state() { return seed_store_->local_state(); }
const PrefService* local_state() const { return seed_store_->local_state(); }
diff --git a/chromium/components/variations/service/variations_field_trial_creator_unittest.cc b/chromium/components/variations/service/variations_field_trial_creator_unittest.cc
index 4daa6a05659..8f6aa50d529 100644
--- a/chromium/components/variations/service/variations_field_trial_creator_unittest.cc
+++ b/chromium/components/variations/service/variations_field_trial_creator_unittest.cc
@@ -9,6 +9,7 @@
#include <memory>
#include <utility>
+#include "base/base_switches.h"
#include "base/callback.h"
#include "base/callback_helpers.h"
#include "base/feature_list.h"
@@ -22,23 +23,25 @@
#include "base/test/task_environment.h"
#include "base/time/time.h"
#include "base/version.h"
+#include "build/branding_buildflags.h"
#include "build/build_config.h"
#include "components/metrics/client_info.h"
#include "components/metrics/metrics_service.h"
#include "components/metrics/metrics_state_manager.h"
#include "components/metrics/test/test_enabled_state_provider.h"
-#include "components/prefs/json_pref_store.h"
-#include "components/prefs/pref_service_factory.h"
#include "components/prefs/testing_pref_service.h"
+#include "components/variations/field_trial_config/field_trial_util.h"
#include "components/variations/platform_field_trials.h"
#include "components/variations/pref_names.h"
#include "components/variations/proto/variations_seed.pb.h"
#include "components/variations/scoped_variations_ids_provider.h"
+#include "components/variations/service/buildflags.h"
#include "components/variations/service/safe_seed_manager.h"
#include "components/variations/service/variations_safe_mode_constants.h"
#include "components/variations/service/variations_service.h"
#include "components/variations/service/variations_service_client.h"
#include "components/variations/variations_seed_store.h"
+#include "components/variations/variations_switches.h"
#include "components/variations/variations_test_utils.h"
#include "components/version_info/channel.h"
#include "components/version_info/version_info.h"
@@ -46,7 +49,7 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "components/variations/seed_response.h"
#endif
@@ -70,9 +73,6 @@ const char kTestSeedSerializedData[] = "a serialized seed, 100% realistic";
const char kTestSeedSignature[] = "a totally valid signature, I swear!";
const int kTestSeedMilestone = 90;
-// The content of an empty prefs file.
-const char kEmptyPrefsFile[] = "{}";
-
// Used for similar tests.
struct TestParams {
// Inputs.
@@ -109,7 +109,7 @@ VariationsSeed CreateTestSafeSeed() {
return seed;
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
const char kTestSeedCountry[] = "in";
// Populates |seed| with simple test data, targetting only users in a specific
@@ -131,7 +131,7 @@ std::string SerializeSeed(const VariationsSeed& seed) {
seed.SerializeToString(&serialized_seed);
return serialized_seed;
}
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
class TestPlatformFieldTrials : public PlatformFieldTrials {
public:
@@ -160,6 +160,7 @@ class MockSafeSeedManager : public SafeSeedManager {
~MockSafeSeedManager() override = default;
+ // Returns false by default.
MOCK_CONST_METHOD0(ShouldRunInSafeMode, bool());
MOCK_METHOD5(DoSetActiveSeedState,
void(const std::string& seed_data,
@@ -179,7 +180,7 @@ class MockSafeSeedManager : public SafeSeedManager {
}
};
-// TODO(crbug.com/1167566): Remove when fake VariationsServiceClient created.
+// TODO(crbug/1167566): Remove when fake VariationsServiceClient created.
class TestVariationsServiceClient : public VariationsServiceClient {
public:
TestVariationsServiceClient() = default;
@@ -240,32 +241,23 @@ class TestVariationsSeedStore : public VariationsSeedStore {
return true;
}
- LoadSeedResult LoadSafeSeed(VariationsSeed* seed,
- ClientFilterableState* client_state) override {
- if (has_corrupted_safe_seed_)
- return LoadSeedResult::kCorruptBase64;
-
- if (has_empty_safe_seed_)
- return LoadSeedResult::kEmpty;
+ bool LoadSafeSeed(VariationsSeed* seed,
+ ClientFilterableState* client_state) override {
+ if (has_unloadable_safe_seed_)
+ return false;
*seed = CreateTestSafeSeed();
- return LoadSeedResult::kSuccess;
- }
-
- void set_has_corrupted_safe_seed(bool is_corrupted) {
- has_corrupted_safe_seed_ = is_corrupted;
+ return true;
}
- void set_has_empty_safe_seed(bool is_empty) {
- has_empty_safe_seed_ = is_empty;
+ void set_has_unloadable_safe_seed(bool is_unloadable) {
+ has_unloadable_safe_seed_ = is_unloadable;
}
private:
- // Whether to simulate having a corrupted safe seed.
- bool has_corrupted_safe_seed_ = false;
-
- // Whether to simulate having an empty safe seed.
- bool has_empty_safe_seed_ = false;
+ // Whether to simulate having an unloadable (e.g. corrupted, empty, etc.) safe
+ // seed.
+ bool has_unloadable_safe_seed_ = false;
};
class TestVariationsFieldTrialCreator : public VariationsFieldTrialCreator {
@@ -301,15 +293,14 @@ class TestVariationsFieldTrialCreator : public VariationsFieldTrialCreator {
// A convenience wrapper around SetUpFieldTrials() which passes default values
// for uninteresting params.
- bool SetUpFieldTrials(bool extend_variations_safe_mode = true) {
+ bool SetUpFieldTrials() {
TestPlatformFieldTrials platform_field_trials;
return VariationsFieldTrialCreator::SetUpFieldTrials(
/*variation_ids=*/std::vector<std::string>(),
std::vector<base::FeatureList::FeatureOverrideInfo>(),
/*low_entropy_provider=*/nullptr, std::make_unique<base::FeatureList>(),
metrics_state_manager_.get(), &platform_field_trials,
- safe_seed_manager_, /*low_entropy_source_value=*/absl::nullopt,
- extend_variations_safe_mode);
+ safe_seed_manager_, /*low_entropy_source_value=*/absl::nullopt);
}
TestVariationsSeedStore* seed_store() { return &seed_store_; }
@@ -326,6 +317,16 @@ class TestVariationsFieldTrialCreator : public VariationsFieldTrialCreator {
metrics_state_manager);
}
+ // We override this method so that a mock testing config is used instead of
+ // the one defined in fieldtrial_testing_config.json.
+ void ApplyFieldTrialTestingConfig(base::FeatureList* feature_list) override {
+ AssociateParamsFromFieldTrialConfig(
+ kTestingConfig,
+ base::BindRepeating(&TestVariationsFieldTrialCreator::OverrideUIString,
+ base::Unretained(this)),
+ GetPlatform(), GetCurrentFormFactor(), feature_list);
+ }
+
private:
VariationsSeedStore* GetSeedStore() override { return &seed_store_; }
base::Time GetBuildTime() const override { return build_time_; }
@@ -343,8 +344,8 @@ class TestVariationsFieldTrialCreator : public VariationsFieldTrialCreator {
class FieldTrialCreatorTest : public ::testing::Test {
public:
FieldTrialCreatorTest() {
- metrics::MetricsService::RegisterPrefs(prefs_.registry());
- VariationsService::RegisterPrefs(prefs_.registry());
+ metrics::MetricsService::RegisterPrefs(local_state_.registry());
+ VariationsService::RegisterPrefs(local_state_.registry());
global_feature_list_ = base::FeatureList::ClearInstanceForTesting();
}
@@ -366,8 +367,10 @@ class FieldTrialCreatorTest : public ::testing::Test {
global_feature_list_ = base::FeatureList::ClearInstanceForTesting();
}
+ PrefService* local_state() { return &local_state_; }
+
protected:
- TestingPrefServiceSimple prefs_;
+ TestingPrefServiceSimple local_state_;
private:
variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{
@@ -384,30 +387,9 @@ class FieldTrialCreatorSafeModeExperimentTest : public FieldTrialCreatorTest {
void SetUp() override {
DisableTestingConfig();
-
- // Create a temp prefs file with no prefs.
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
- prefs_file_ = temp_dir_.GetPath().AppendASCII("write.json");
- ASSERT_LT(0, base::WriteFile(prefs_file_, kEmptyPrefsFile));
- ASSERT_TRUE(PathExists(prefs_file_));
}
- void TearDown() override { ASSERT_TRUE(base::DeleteFile(prefs_file_)); }
-
- // Creates and returns a PrefService that uses a real JsonPrefStore rather
- // than a TestingPrefStore.
- std::unique_ptr<PrefService> CreatePrefService() {
- auto pref_registry = base::MakeRefCounted<PrefRegistrySimple>();
- metrics::MetricsService::RegisterPrefs(pref_registry.get());
- VariationsService::RegisterPrefs(pref_registry.get());
-
- auto pref_store = base::MakeRefCounted<JsonPrefStore>(prefs_file_);
- PrefServiceFactory pref_service_factory;
- pref_service_factory.set_user_prefs(pref_store);
- return pref_service_factory.Create(pref_registry);
- }
-
- const base::FilePath prefs_file() const { return prefs_file_; }
const base::FilePath user_data_dir_path() const {
return temp_dir_.GetPath();
}
@@ -415,7 +397,6 @@ class FieldTrialCreatorSafeModeExperimentTest : public FieldTrialCreatorTest {
private:
base::test::TaskEnvironment task_environment_;
base::ScopedTempDir temp_dir_;
- base::FilePath prefs_file_;
base::test::ScopedFieldTrialListResetter trial_list_resetter_;
base::FieldTrialList field_trial_list_;
};
@@ -430,6 +411,10 @@ class FieldTrialCreatorTestWithStartupVisibility
: public FieldTrialCreatorSafeModeExperimentTest,
public ::testing::WithParamInterface<StartupVisibilityTestParams> {};
+class SafeModeExperimentTestByChannel
+ : public FieldTrialCreatorSafeModeExperimentTest,
+ public ::testing::WithParamInterface<version_info::Channel> {};
+
// Verify that unexpired seeds are used.
TEST_F(FieldTrialCreatorTest, SetUpFieldTrials_ValidSeed_NotExpired) {
DisableTestingConfig();
@@ -447,9 +432,7 @@ TEST_F(FieldTrialCreatorTest, SetUpFieldTrials_ValidSeed_NotExpired) {
const base::Time seed_fetch_time = now - base::Days(test_case.days);
// The seed should be used, so the safe seed manager should be informed of
// the active seed state.
- NiceMock<MockSafeSeedManager> safe_seed_manager(&prefs_);
- ON_CALL(safe_seed_manager, ShouldRunInSafeMode())
- .WillByDefault(Return(false));
+ NiceMock<MockSafeSeedManager> safe_seed_manager(local_state());
EXPECT_CALL(
safe_seed_manager,
DoSetActiveSeedState(kTestSeedSerializedData, kTestSeedSignature,
@@ -458,14 +441,15 @@ TEST_F(FieldTrialCreatorTest, SetUpFieldTrials_ValidSeed_NotExpired) {
TestVariationsServiceClient variations_service_client;
TestVariationsFieldTrialCreator field_trial_creator(
- &prefs_, &variations_service_client, &safe_seed_manager);
+ local_state(), &variations_service_client, &safe_seed_manager);
field_trial_creator.SetBuildTime(test_case.binary_build_time);
// Simulate the seed being stored.
- prefs_.SetTime(prefs::kVariationsLastFetchTime, seed_fetch_time);
+ local_state()->SetTime(prefs::kVariationsLastFetchTime, seed_fetch_time);
// Simulate a seed from an earlier (i.e. valid) milestone.
- prefs_.SetInteger(prefs::kVariationsSeedMilestone, kTestSeedMilestone);
+ local_state()->SetInteger(prefs::kVariationsSeedMilestone,
+ kTestSeedMilestone);
// Check that field trials are created from the seed. Since the test study
// has only one experiment with 100% probability weight, we must be part of
@@ -496,9 +480,7 @@ TEST_F(FieldTrialCreatorTest, SetUpFieldTrials_ValidSeed_NoLastFetchTime) {
// With a valid seed on first run, the safe seed manager should be informed of
// the active seed state. The last fetch time in this case is expected to be
// inferred to be recent.
- NiceMock<MockSafeSeedManager> safe_seed_manager(&prefs_);
- ON_CALL(safe_seed_manager, ShouldRunInSafeMode())
- .WillByDefault(Return(false));
+ NiceMock<MockSafeSeedManager> safe_seed_manager(local_state());
const base::Time start_time = base::Time::Now();
EXPECT_CALL(safe_seed_manager,
DoSetActiveSeedState(kTestSeedSerializedData, kTestSeedSignature,
@@ -507,10 +489,10 @@ TEST_F(FieldTrialCreatorTest, SetUpFieldTrials_ValidSeed_NoLastFetchTime) {
TestVariationsServiceClient variations_service_client;
TestVariationsFieldTrialCreator field_trial_creator(
- &prefs_, &variations_service_client, &safe_seed_manager);
+ local_state(), &variations_service_client, &safe_seed_manager);
// Simulate a first run by leaving |prefs::kVariationsLastFetchTime| empty.
- EXPECT_EQ(0, prefs_.GetInt64(prefs::kVariationsLastFetchTime));
+ EXPECT_EQ(0, local_state()->GetInt64(prefs::kVariationsLastFetchTime));
// Check that field trials are created from the seed. Since the test study has
// only one experiment with 100% probability weight, we must be part of it.
@@ -519,12 +501,12 @@ TEST_F(FieldTrialCreatorTest, SetUpFieldTrials_ValidSeed_NoLastFetchTime) {
EXPECT_EQ(base::FieldTrialList::FindFullName(kTestSeedStudyName),
kTestSeedExperimentName);
- // Verify metrics. The seed freshness metric should not be recorded on first
- // run.
+ // Verify metrics. The seed freshness metric should be recorded with a value
+ // of 0 on first run.
histogram_tester.ExpectUniqueSample("Variations.CreateTrials.SeedExpiry",
VariationsSeedExpiry::kFetchTimeMissing,
1);
- histogram_tester.ExpectTotalCount("Variations.SeedFreshness", 0);
+ histogram_tester.ExpectUniqueSample("Variations.SeedFreshness", 0, 1);
histogram_tester.ExpectUniqueSample("Variations.SeedUsage",
SeedUsage::kRegularSeedUsed, 1);
}
@@ -537,9 +519,7 @@ TEST_F(FieldTrialCreatorTest, SetUpFieldTrials_ValidSeed_NoMilestone) {
// The regular seed should be used, so the safe seed manager should be
// informed of the active seed state.
- NiceMock<MockSafeSeedManager> safe_seed_manager(&prefs_);
- ON_CALL(safe_seed_manager, ShouldRunInSafeMode())
- .WillByDefault(Return(false));
+ NiceMock<MockSafeSeedManager> safe_seed_manager(local_state());
const int minutes = 45;
const base::Time seed_fetch_time = base::Time::Now() - base::Minutes(minutes);
EXPECT_CALL(safe_seed_manager,
@@ -549,14 +529,14 @@ TEST_F(FieldTrialCreatorTest, SetUpFieldTrials_ValidSeed_NoMilestone) {
TestVariationsServiceClient variations_service_client;
TestVariationsFieldTrialCreator field_trial_creator(
- &prefs_, &variations_service_client, &safe_seed_manager);
+ local_state(), &variations_service_client, &safe_seed_manager);
// Simulate the seed being stored.
- prefs_.SetTime(prefs::kVariationsLastFetchTime, seed_fetch_time);
+ local_state()->SetTime(prefs::kVariationsLastFetchTime, seed_fetch_time);
// Simulate the absence of a milestone by leaving
// |prefs::kVariationsSeedMilestone| empty.
- EXPECT_EQ(0, prefs_.GetInteger(prefs::kVariationsSeedMilestone));
+ EXPECT_EQ(0, local_state()->GetInteger(prefs::kVariationsSeedMilestone));
// Check that field trials are created from the seed. Since the test study has
// only one experiment with 100% probability weight, we must be part of it.
@@ -579,21 +559,19 @@ TEST_F(FieldTrialCreatorTest, SetUpFieldTrials_ExpiredSeed) {
// When the seed is older than 30 days and older than the binary, no field
// trials should be created from the seed. Hence, no active state should be
// passed to the safe seed manager.
- NiceMock<MockSafeSeedManager> safe_seed_manager(&prefs_);
- ON_CALL(safe_seed_manager, ShouldRunInSafeMode())
- .WillByDefault(Return(false));
+ NiceMock<MockSafeSeedManager> safe_seed_manager(local_state());
EXPECT_CALL(safe_seed_manager, DoSetActiveSeedState(_, _, _, _, _)).Times(0);
TestVariationsServiceClient variations_service_client;
TestVariationsFieldTrialCreator field_trial_creator(
- &prefs_, &variations_service_client, &safe_seed_manager);
+ local_state(), &variations_service_client, &safe_seed_manager);
const base::Time now = base::Time::Now();
field_trial_creator.SetBuildTime(now);
// Simulate an expired seed. For a seed to be expired, it must be older than
// 30 days and be older than the binary.
const base::Time seed_date = now - base::Days(31);
- prefs_.SetTime(prefs::kVariationsLastFetchTime, seed_date);
+ local_state()->SetTime(prefs::kVariationsLastFetchTime, seed_date);
// Check that field trials are not created from the expired seed.
base::HistogramTester histogram_tester;
@@ -618,19 +596,18 @@ TEST_F(FieldTrialCreatorTest, SetUpFieldTrials_FutureMilestone) {
// When the seed is associated with a future milestone (relative to the
// client's milestone), no field trials should be created from the seed.
// Hence, no active state should be passed to the safe seed manager.
- NiceMock<MockSafeSeedManager> safe_seed_manager(&prefs_);
- ON_CALL(safe_seed_manager, ShouldRunInSafeMode())
- .WillByDefault(Return(false));
+ NiceMock<MockSafeSeedManager> safe_seed_manager(local_state());
EXPECT_CALL(safe_seed_manager, DoSetActiveSeedState(_, _, _, _, _)).Times(0);
TestVariationsServiceClient variations_service_client;
TestVariationsFieldTrialCreator field_trial_creator(
- &prefs_, &variations_service_client, &safe_seed_manager);
+ local_state(), &variations_service_client, &safe_seed_manager);
const base::Time now = base::Time::Now();
field_trial_creator.SetBuildTime(now);
// Simulate a seed from a future milestone.
- prefs_.SetInteger(prefs::kVariationsSeedMilestone, future_seed_milestone);
+ local_state()->SetInteger(prefs::kVariationsSeedMilestone,
+ future_seed_milestone);
// Check that field trials are not created from the seed.
base::HistogramTester histogram_tester;
@@ -663,7 +640,7 @@ TEST_F(FieldTrialCreatorTest,
// With a valid safe seed, the safe seed manager should not be informed of
// the active seed state. This is an optimization to avoid saving a safe
// seed when already running in safe mode.
- NiceMock<MockSafeSeedManager> safe_seed_manager(&prefs_);
+ NiceMock<MockSafeSeedManager> safe_seed_manager(local_state());
ON_CALL(safe_seed_manager, ShouldRunInSafeMode())
.WillByDefault(Return(true));
EXPECT_CALL(safe_seed_manager, DoSetActiveSeedState(_, _, _, _, _))
@@ -671,12 +648,13 @@ TEST_F(FieldTrialCreatorTest,
TestVariationsServiceClient variations_service_client;
TestVariationsFieldTrialCreator field_trial_creator(
- &prefs_, &variations_service_client, &safe_seed_manager);
+ local_state(), &variations_service_client, &safe_seed_manager);
field_trial_creator.SetBuildTime(test_case.binary_build_time);
// Simulate the safe seed being stored.
const base::Time seed_fetch_time = now - base::Days(test_case.days);
- prefs_.SetTime(prefs::kVariationsSafeSeedFetchTime, seed_fetch_time);
+ local_state()->SetTime(prefs::kVariationsSafeSeedFetchTime,
+ seed_fetch_time);
// Check that field trials are created from the safe seed. Since the test
// study has only one experiment with 100% probability weight, we must be
@@ -700,52 +678,12 @@ TEST_F(FieldTrialCreatorTest,
}
}
-// Verify that Chrome applies the regular variations seed when Chrome should run
-// in variations safe mode but the safe seed is empty.
-TEST_F(FieldTrialCreatorTest, SetUpFieldTrials_EmptySafeSeed_UsesRegularSeed) {
- DisableTestingConfig();
-
- NiceMock<MockSafeSeedManager> safe_seed_manager(&prefs_);
- ON_CALL(safe_seed_manager, ShouldRunInSafeMode()).WillByDefault(Return(true));
-
- const base::Time recent_time = base::Time::Now() - base::Minutes(17);
- prefs_.SetTime(prefs::kVariationsLastFetchTime, recent_time);
- // When using the regular seed, the safe seed manager should be informed of
- // the active seed state.
- EXPECT_CALL(safe_seed_manager,
- DoSetActiveSeedState(kTestSeedSerializedData, kTestSeedSignature,
- _, _, recent_time))
- .Times(1);
-
- TestVariationsServiceClient variations_service_client;
- TestVariationsFieldTrialCreator field_trial_creator(
- &prefs_, &variations_service_client, &safe_seed_manager);
- field_trial_creator.seed_store()->set_has_empty_safe_seed(true);
-
- // Check that field trials are created from the regular seed. Since the test
- // study has only one experiment with 100% probability weight, we must be part
- // of it.
- base::HistogramTester histogram_tester;
- EXPECT_TRUE(field_trial_creator.SetUpFieldTrials());
- EXPECT_EQ(kTestSeedExperimentName,
- base::FieldTrialList::FindFullName(kTestSeedStudyName));
-
- // Verify metrics.
- histogram_tester.ExpectUniqueSample("Variations.CreateTrials.SeedExpiry",
- VariationsSeedExpiry::kNotExpired, 1);
- histogram_tester.ExpectUniqueSample("Variations.SeedFreshness", 17, 1);
- histogram_tester.ExpectUniqueSample(
- "Variations.SeedUsage",
- SeedUsage::kRegularSeedUsedAfterEmptySafeSeedLoaded, 1);
-}
-
// Verify that Chrome does not apply a variations seed when Chrome should run in
-// variations safe mode and a safe seed cannot be loaded.
-TEST_F(FieldTrialCreatorTest,
- SetUpFieldTrials_CorruptedSafeSeed_DoesNotUseSeed) {
+// Variations Safe Mode but the safe seed is unloadable.
+TEST_F(FieldTrialCreatorTest, SetUpFieldTrials_UnloadableSafeSeedNotUsed) {
DisableTestingConfig();
- NiceMock<MockSafeSeedManager> safe_seed_manager(&prefs_);
+ NiceMock<MockSafeSeedManager> safe_seed_manager(local_state());
ON_CALL(safe_seed_manager, ShouldRunInSafeMode()).WillByDefault(Return(true));
// When falling back to client-side defaults, the safe seed manager should not
@@ -754,8 +692,8 @@ TEST_F(FieldTrialCreatorTest,
TestVariationsServiceClient variations_service_client;
TestVariationsFieldTrialCreator field_trial_creator(
- &prefs_, &variations_service_client, &safe_seed_manager);
- field_trial_creator.seed_store()->set_has_corrupted_safe_seed(true);
+ local_state(), &variations_service_client, &safe_seed_manager);
+ field_trial_creator.seed_store()->set_has_unloadable_safe_seed(true);
base::HistogramTester histogram_tester;
@@ -765,7 +703,7 @@ TEST_F(FieldTrialCreatorTest,
// Verify that Chrome did not apply the safe seed.
histogram_tester.ExpectUniqueSample("Variations.SeedUsage",
- SeedUsage::kCorruptedSafeSeedNotUsed, 1);
+ SeedUsage::kUnloadableSafeSeedNotUsed, 1);
}
// Verify that valid safe seeds with missing download times are applied.
@@ -775,16 +713,16 @@ TEST_F(FieldTrialCreatorTest, SetUpFieldTrials_ValidSafeSeed_NoLastFetchTime) {
// With a valid safe seed, the safe seed manager should not be informed of the
// active seed state. This is an optimization to avoid saving a safe seed when
// already running in safe mode.
- NiceMock<MockSafeSeedManager> safe_seed_manager(&prefs_);
+ NiceMock<MockSafeSeedManager> safe_seed_manager(local_state());
ON_CALL(safe_seed_manager, ShouldRunInSafeMode()).WillByDefault(Return(true));
EXPECT_CALL(safe_seed_manager, DoSetActiveSeedState(_, _, _, _, _)).Times(0);
TestVariationsServiceClient variations_service_client;
TestVariationsFieldTrialCreator field_trial_creator(
- &prefs_, &variations_service_client, &safe_seed_manager);
+ local_state(), &variations_service_client, &safe_seed_manager);
// Verify that the safe seed does not have a fetch time.
- EXPECT_EQ(0, prefs_.GetInt64(prefs::kVariationsSafeSeedFetchTime));
+ EXPECT_EQ(0, local_state()->GetInt64(prefs::kVariationsSafeSeedFetchTime));
// Check that field trials are created from the safe seed. Since the test
// study has only one experiment with 100% probability weight, we must be part
@@ -810,20 +748,20 @@ TEST_F(FieldTrialCreatorTest, SetUpFieldTrials_ExpiredSafeSeed) {
DisableTestingConfig();
// The safe seed manager should not be informed of the active seed state.
- NiceMock<MockSafeSeedManager> safe_seed_manager(&prefs_);
+ NiceMock<MockSafeSeedManager> safe_seed_manager(local_state());
ON_CALL(safe_seed_manager, ShouldRunInSafeMode()).WillByDefault(Return(true));
EXPECT_CALL(safe_seed_manager, DoSetActiveSeedState(_, _, _, _, _)).Times(0);
TestVariationsServiceClient variations_service_client;
TestVariationsFieldTrialCreator field_trial_creator(
- &prefs_, &variations_service_client, &safe_seed_manager);
+ local_state(), &variations_service_client, &safe_seed_manager);
const base::Time now = base::Time::Now();
field_trial_creator.SetBuildTime(now);
// Simulate an expired seed. For a seed to be expired, it must be older than
// 30 days and be older than the binary.
const base::Time seed_date = now - base::Days(31);
- prefs_.SetTime(prefs::kVariationsSafeSeedFetchTime, seed_date);
+ local_state()->SetTime(prefs::kVariationsSafeSeedFetchTime, seed_date);
// Check that field trials are not created from the expired seed.
base::HistogramTester histogram_tester;
@@ -847,16 +785,17 @@ TEST_F(FieldTrialCreatorTest, SetUpFieldTrials_SafeSeedForFutureMilestone) {
const int future_seed_milestone = 7890;
// The safe seed manager should not be informed of the active seed state.
- NiceMock<MockSafeSeedManager> safe_seed_manager(&prefs_);
+ NiceMock<MockSafeSeedManager> safe_seed_manager(local_state());
ON_CALL(safe_seed_manager, ShouldRunInSafeMode()).WillByDefault(Return(true));
EXPECT_CALL(safe_seed_manager, DoSetActiveSeedState(_, _, _, _, _)).Times(0);
TestVariationsServiceClient variations_service_client;
TestVariationsFieldTrialCreator field_trial_creator(
- &prefs_, &variations_service_client, &safe_seed_manager);
+ local_state(), &variations_service_client, &safe_seed_manager);
// Simulate a safe seed that was fetched with a future milestone.
- prefs_.SetInteger(prefs::kVariationsSafeSeedMilestone, future_seed_milestone);
+ local_state()->SetInteger(prefs::kVariationsSafeSeedMilestone,
+ future_seed_milestone);
// Check that field trials are not created from the safe seed.
base::HistogramTester histogram_tester;
@@ -868,7 +807,7 @@ TEST_F(FieldTrialCreatorTest, SetUpFieldTrials_SafeSeedForFutureMilestone) {
"Variations.SeedUsage", SeedUsage::kSafeSeedForFutureMilestoneNotUsed, 1);
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// This is a regression test for crbug/829527.
TEST_F(FieldTrialCreatorTest, SetUpFieldTrials_LoadsCountryOnFirstRun) {
DisableTestingConfig();
@@ -884,14 +823,12 @@ TEST_F(FieldTrialCreatorTest, SetUpFieldTrials_LoadsCountryOnFirstRun) {
TestVariationsServiceClient variations_service_client;
TestPlatformFieldTrials platform_field_trials;
- NiceMock<MockSafeSeedManager> safe_seed_manager(&prefs_);
- ON_CALL(safe_seed_manager, ShouldRunInSafeMode())
- .WillByDefault(Return(false));
+ NiceMock<MockSafeSeedManager> safe_seed_manager(local_state());
// Note: Unlike other tests, this test does not mock out the seed store, since
// the interaction between these two classes is what's being tested.
auto seed_store = std::make_unique<VariationsSeedStore>(
- &prefs_, std::move(initial_seed),
+ local_state(), std::move(initial_seed),
/*signature_verification_enabled=*/false);
VariationsFieldTrialCreator field_trial_creator(
&variations_service_client, std::move(seed_store), UIStringOverrider());
@@ -899,7 +836,7 @@ TEST_F(FieldTrialCreatorTest, SetUpFieldTrials_LoadsCountryOnFirstRun) {
metrics::TestEnabledStateProvider enabled_state_provider(/*consent=*/true,
/*enabled=*/true);
auto metrics_state_manager = metrics::MetricsStateManager::Create(
- &prefs_, &enabled_state_provider, std::wstring(), base::FilePath());
+ local_state(), &enabled_state_provider, std::wstring(), base::FilePath());
// Check that field trials are created from the seed. The test seed contains a
// single study with an experiment targeting 100% of users in India. Since
@@ -918,13 +855,11 @@ TEST_F(FieldTrialCreatorTest, SetUpFieldTrials_LoadsCountryOnFirstRun) {
// Tests that the hardware class is set on Android.
TEST_F(FieldTrialCreatorTest, ClientFilterableState_HardwareClass) {
- NiceMock<MockSafeSeedManager> safe_seed_manager(&prefs_);
- ON_CALL(safe_seed_manager, ShouldRunInSafeMode())
- .WillByDefault(Return(false));
+ NiceMock<MockSafeSeedManager> safe_seed_manager(local_state());
TestVariationsServiceClient variations_service_client;
TestVariationsFieldTrialCreator field_trial_creator(
- &prefs_, &variations_service_client, &safe_seed_manager);
+ local_state(), &variations_service_client, &safe_seed_manager);
const base::Version& current_version = version_info::GetVersion();
EXPECT_TRUE(current_version.IsValid());
@@ -933,36 +868,327 @@ TEST_F(FieldTrialCreatorTest, ClientFilterableState_HardwareClass) {
field_trial_creator.GetClientFilterableStateForVersion(current_version);
EXPECT_NE(client_filterable_state->hardware_class, std::string());
}
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
+
+#if BUILDFLAG(FIELDTRIAL_TESTING_ENABLED)
+// Used to create a TestVariationsFieldTrialCreator with a valid unexpired seed.
+std::unique_ptr<TestVariationsFieldTrialCreator>
+SetUpFieldTrialCreatorWithValidSeed(
+ PrefService* local_state,
+ TestVariationsServiceClient* variations_service_client,
+ NiceMock<MockSafeSeedManager>* safe_seed_manager) {
+ // Set up a valid unexpired seed.
+ const base::Time now = base::Time::Now();
+ const base::Time seed_fetch_time = now - base::Days(1);
+ std::unique_ptr<TestVariationsFieldTrialCreator> field_trial_creator =
+ std::make_unique<TestVariationsFieldTrialCreator>(
+ local_state, variations_service_client, safe_seed_manager);
+ field_trial_creator->SetBuildTime(now);
+ // Simulate the seed being stored.
+ local_state->SetTime(prefs::kVariationsLastFetchTime, seed_fetch_time);
+ // Simulate a seed from an earlier (i.e. valid) milestone.
+ local_state->SetInteger(prefs::kVariationsSeedMilestone, kTestSeedMilestone);
+ return field_trial_creator;
+}
-TEST_F(FieldTrialCreatorSafeModeExperimentTest, OptOutOfExperiment) {
- std::unique_ptr<PrefService> pref_service(CreatePrefService());
+// Verifies that a valid seed is used instead of the testing config when we
+// disable it.
+TEST_F(FieldTrialCreatorTest, NotSetUpFieldTrialConfig_ValidSeed) {
+#if !BUILDFLAG(GOOGLE_CHROME_BRANDING)
+ // Note: Non-Google Chrome branded builds do not disable the testing config by
+ // default. We explicitly disable it.
+ DisableTestingConfig();
+#endif
+ // Create a field trial creator with a valid unexpired seed.
+ TestVariationsServiceClient variations_service_client;
+ NiceMock<MockSafeSeedManager> safe_seed_manager(local_state());
+ std::unique_ptr<TestVariationsFieldTrialCreator> field_trial_creator =
+ SetUpFieldTrialCreatorWithValidSeed(
+ local_state(), &variations_service_client, &safe_seed_manager);
+
+ // Verify that |SetUpFieldTrials| uses the seed. |SetUpFieldTrials| returns
+ // true if it used a seed.
+ EXPECT_CALL(safe_seed_manager,
+ DoSetActiveSeedState(kTestSeedSerializedData, kTestSeedSignature,
+ kTestSeedMilestone, _, _))
+ .Times(1);
+ EXPECT_TRUE(field_trial_creator->SetUpFieldTrials());
+ EXPECT_TRUE(base::FieldTrialList::TrialExists(kTestSeedStudyName));
+
+ // Verify that the |UnitTest| trial from the field trial testing config was
+ // not registered.
+ ASSERT_FALSE(base::FieldTrialList::TrialExists("UnitTest"));
+
+ ResetVariations();
+}
+
+// Verifies that field trial testing config is used when enabled, even when
+// there is a valid unexpired seed.
+TEST_F(FieldTrialCreatorTest, SetUpFieldTrialConfig_ValidSeed) {
+ EnableTestingConfig();
+
+ // Create a field trial creator with a valid unexpired seed.
+ TestVariationsServiceClient variations_service_client;
+ NiceMock<MockSafeSeedManager> safe_seed_manager(local_state());
+ std::unique_ptr<TestVariationsFieldTrialCreator> field_trial_creator =
+ SetUpFieldTrialCreatorWithValidSeed(
+ local_state(), &variations_service_client, &safe_seed_manager);
+
+ // Verify that |SetUpFieldTrials| does not use the seed, despite it being
+ // valid and unexpired. |SetUpFieldTrials| returns false if it did not use a
+ // seed.
+ EXPECT_CALL(safe_seed_manager, DoSetActiveSeedState(_, _, _, _, _)).Times(0);
+ EXPECT_FALSE(field_trial_creator->SetUpFieldTrials());
+ EXPECT_FALSE(base::FieldTrialList::TrialExists(kTestSeedStudyName));
+
+ // Verify that the |UnitTest| trial from the field trial testing config has
+ // been registered, and that the group name is |Enabled|.
+ ASSERT_EQ("Enabled", base::FieldTrialList::FindFullName("UnitTest"));
+
+ // Verify the |UnitTest| trial params.
+ base::FieldTrialParams params;
+ ASSERT_TRUE(base::GetFieldTrialParams("UnitTest", &params));
+ ASSERT_EQ(1U, params.size());
+ EXPECT_EQ("1", params["x"]);
+
+ // Verify that the |UnitTestEnabled| feature is active.
+ const base::Feature kFeature1{"UnitTestEnabled",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+ EXPECT_TRUE(base::FeatureList::IsEnabled(kFeature1));
+
+ ResetVariations();
+}
+
+// Verifies that trials from the testing config and the |--force-fieldtrials|
+// switch are registered when they are both used (assuming there are no
+// conflicts).
+TEST_F(FieldTrialCreatorTest, SetUpFieldTrialConfig_ForceFieldTrials) {
+ EnableTestingConfig();
+
+ // Simulate passing |--force-fieldtrials="UnitTest2/Enabled"|.
+ base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+ ::switches::kForceFieldTrials, "UnitTest2/Enabled");
+ // Simulate passing |--force-fieldtrial-params="UnitTest2.Enabled:y/1"|.
+ base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+ switches::kForceFieldTrialParams, "UnitTest2.Enabled:y/1");
+ // Simulate passing |--enable-features="UnitTest2Enabled<UnitTest2"|.
+ base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+ ::switches::kEnableFeatures, "UnitTest2Enabled<UnitTest2");
+
+ // Create a field trial creator with a valid unexpired seed.
+ TestVariationsServiceClient variations_service_client;
+ NiceMock<MockSafeSeedManager> safe_seed_manager(local_state());
+ std::unique_ptr<TestVariationsFieldTrialCreator> field_trial_creator =
+ SetUpFieldTrialCreatorWithValidSeed(
+ local_state(), &variations_service_client, &safe_seed_manager);
+
+ // Verify that |SetUpFieldTrials| does not use the seed, despite it being
+ // valid and unexpired. |SetUpFieldTrials| returns false if it did not use a
+ // seed.
+ EXPECT_CALL(safe_seed_manager, DoSetActiveSeedState(_, _, _, _, _)).Times(0);
+ EXPECT_FALSE(field_trial_creator->SetUpFieldTrials());
+ EXPECT_FALSE(base::FieldTrialList::TrialExists(kTestSeedStudyName));
+
+ // Verify that the |UnitTest| trial from the field trial testing config has
+ // been registered, and that the group name is |Enabled|.
+ ASSERT_EQ("Enabled", base::FieldTrialList::FindFullName("UnitTest"));
+ // Verify that the |UnitTest2| trial from the |--force-fieldtrials| switch has
+ // been registered, and that the group name is |Enabled|.
+ ASSERT_EQ("Enabled", base::FieldTrialList::FindFullName("UnitTest2"));
+
+ // Verify the |UnitTest| trial params.
+ base::FieldTrialParams params;
+ ASSERT_TRUE(base::GetFieldTrialParams("UnitTest", &params));
+ ASSERT_EQ(1U, params.size());
+ EXPECT_EQ("1", params["x"]);
+ // Verify the |UnitTest2| trial params.
+ base::FieldTrialParams params2;
+ ASSERT_TRUE(base::GetFieldTrialParams("UnitTest2", &params2));
+ ASSERT_EQ(1U, params2.size());
+ EXPECT_EQ("1", params2["y"]);
+
+ // Verify that the |UnitTestEnabled| and |UnitTestEnabled2| features are
+ // active.
+ const base::Feature kFeature1{"UnitTestEnabled",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+ EXPECT_TRUE(base::FeatureList::IsEnabled(kFeature1));
+ const base::Feature kFeature2{"UnitTest2Enabled",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+ EXPECT_TRUE(base::FeatureList::IsEnabled(kFeature2));
+
+ ResetVariations();
+}
+
+// Verifies that when field trial testing config is used, trials and groups
+// specified using |--force-fieldtrials| take precedence if they specify the
+// same trials but different groups.
+TEST_F(FieldTrialCreatorTest, SetUpFieldTrialConfig_ForceFieldTrialsOverride) {
+ EnableTestingConfig();
+
+ // Simulate passing |--force-fieldtrials="UnitTest/Disabled"| switch.
+ base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+ ::switches::kForceFieldTrials, "UnitTest/Disabled");
+
+ // Create a field trial creator with a valid unexpired seed.
+ TestVariationsServiceClient variations_service_client;
+ NiceMock<MockSafeSeedManager> safe_seed_manager(local_state());
+ std::unique_ptr<TestVariationsFieldTrialCreator> field_trial_creator =
+ SetUpFieldTrialCreatorWithValidSeed(
+ local_state(), &variations_service_client, &safe_seed_manager);
+
+ // Verify that |SetUpFieldTrials| does not use the seed, despite it being
+ // valid and unexpired. |SetUpFieldTrials| returns false if it did not use a
+ // seed.
+ EXPECT_CALL(safe_seed_manager, DoSetActiveSeedState(_, _, _, _, _)).Times(0);
+ EXPECT_FALSE(field_trial_creator->SetUpFieldTrials());
+ EXPECT_FALSE(base::FieldTrialList::TrialExists(kTestSeedStudyName));
+
+ // Verify that the |UnitTest| trial from the |--force-fieldtrials| switch (and
+ // not from the field trial testing config) has been registered, and that the
+ // group name is |Disabled|.
+ ASSERT_EQ("Disabled", base::FieldTrialList::FindFullName("UnitTest"));
+
+ // Verify that the |UnitTest| trial params from the field trial testing config
+ // were not used. |GetFieldTrialParams| returns false if no parameters are
+ // defined for a specified trial.
+ base::FieldTrialParams params;
+ ASSERT_FALSE(base::GetFieldTrialParams("UnitTest", &params));
+
+ // Verify that the |UnitTestEnabled| feature from the testing config is not
+ // active.
+ const base::Feature kFeature1{"UnitTestEnabled",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+ EXPECT_FALSE(base::FeatureList::IsEnabled(kFeature1));
+
+ ResetVariations();
+}
+
+// Verifies that when field trial testing config is used, params specified using
+// |--force-fieldtrial-params| take precedence if they specify the same trial
+// and group.
+TEST_F(FieldTrialCreatorTest, SetUpFieldTrialConfig_ForceFieldTrialParams) {
+ EnableTestingConfig();
+
+ // Simulate passing |--force-fieldtrial-params="UnitTest.Enabled:x/2/y/2"|
+ // switch.
+ base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+ switches::kForceFieldTrialParams, "UnitTest.Enabled:x/2/y/2");
+
+ // Create a field trial creator with a valid unexpired seed.
+ TestVariationsServiceClient variations_service_client;
+ NiceMock<MockSafeSeedManager> safe_seed_manager(local_state());
+ std::unique_ptr<TestVariationsFieldTrialCreator> field_trial_creator =
+ SetUpFieldTrialCreatorWithValidSeed(
+ local_state(), &variations_service_client, &safe_seed_manager);
+
+ // Verify that |SetUpFieldTrials| does not use the seed, despite it being
+ // valid and unexpired. |SetUpFieldTrials| returns false if it did not use a
+ // seed.
+ EXPECT_CALL(safe_seed_manager, DoSetActiveSeedState(_, _, _, _, _)).Times(0);
+ EXPECT_FALSE(field_trial_creator->SetUpFieldTrials());
+ EXPECT_FALSE(base::FieldTrialList::TrialExists(kTestSeedStudyName));
+
+ // Verify that the |UnitTest| trial from the field trial testing config has
+ // been registered, and that the group name is |Enabled|.
+ ASSERT_EQ("Enabled", base::FieldTrialList::FindFullName("UnitTest"));
+
+ // Verify the |UnitTest| trial params, and that the
+ // |--force-fieldtrial-params| took precedence over the params defined in the
+ // field trial testing config.
+ base::FieldTrialParams params;
+ ASSERT_TRUE(base::GetFieldTrialParams("UnitTest", &params));
+ ASSERT_EQ(2U, params.size());
+ EXPECT_EQ("2", params["x"]);
+ EXPECT_EQ("2", params["y"]);
+
+ // Verify that the |UnitTestEnabled| feature is still active.
+ const base::Feature kFeature1{"UnitTestEnabled",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+ EXPECT_TRUE(base::FeatureList::IsEnabled(kFeature1));
+
+ ResetVariations();
+}
+
+class FieldTrialCreatorTestWithFeatures
+ : public FieldTrialCreatorTest,
+ public ::testing::WithParamInterface<const char*> {};
+
+INSTANTIATE_TEST_SUITE_P(All,
+ FieldTrialCreatorTestWithFeatures,
+ ::testing::Values(::switches::kEnableFeatures,
+ ::switches::kDisableFeatures));
+
+// Verifies that studies from field trial testing config should be ignored
+// if they enable/disable features overridden by |--enable-features| or
+// |--disable-features|.
+TEST_P(FieldTrialCreatorTestWithFeatures,
+ SetUpFieldTrialConfig_OverrideFeatures) {
+ EnableTestingConfig();
+
+ // Simulate passing either |--enable-features="UnitTestEnabled"| or
+ // |--disable-features="UnitTestEnabled"| switch.
+ base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(GetParam(),
+ "UnitTestEnabled");
+
+ // Create a field trial creator with a valid unexpired seed.
+ TestVariationsServiceClient variations_service_client;
+ NiceMock<MockSafeSeedManager> safe_seed_manager(local_state());
+ std::unique_ptr<TestVariationsFieldTrialCreator> field_trial_creator =
+ SetUpFieldTrialCreatorWithValidSeed(
+ local_state(), &variations_service_client, &safe_seed_manager);
+
+ // Verify that |SetUpFieldTrials| does not use the seed, despite it being
+ // valid and unexpired. |SetUpFieldTrials| returns false if it did not use a
+ // seed.
+ EXPECT_CALL(safe_seed_manager, DoSetActiveSeedState(_, _, _, _, _)).Times(0);
+ EXPECT_FALSE(field_trial_creator->SetUpFieldTrials());
+ EXPECT_FALSE(base::FieldTrialList::TrialExists(kTestSeedStudyName));
+
+ // Verify that the |UnitTest| trial from the field trial testing config was
+ // NOT registered. Even if the study |UnitTest| enables feature
+ // |UnitTestEnabled|, and we pass |--enable-features="UnitTestEnabled"|, the
+ // study should be disabled.
+ EXPECT_FALSE(base::FieldTrialList::TrialExists("UnitTest"));
+
+ // Verify that the |UnitTestEnabled| feature is enabled or disabled depending
+ // on whether we passed it in |--enable-features| or |--disable-features|.
+ const base::Feature kFeature1{"UnitTestEnabled",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+ EXPECT_EQ(GetParam() == ::switches::kEnableFeatures,
+ base::FeatureList::IsEnabled(kFeature1));
+
+ ResetVariations();
+}
+#endif // BUILDFLAG(FIELDTRIAL_TESTING_ENABLED)
+
+// Verify that providing an empty user data directory opts the client out of the
+// Extended Variations Safe Mode experiment.
+TEST_F(FieldTrialCreatorSafeModeExperimentTest, OptOutOfExperiment) {
// Ensure that variations safe mode is not triggered.
- NiceMock<MockSafeSeedManager> safe_seed_manager(pref_service.get());
- ON_CALL(safe_seed_manager, ShouldRunInSafeMode())
- .WillByDefault(Return(false));
+ NiceMock<MockSafeSeedManager> safe_seed_manager(local_state());
+ // Specify a channel on which the Extended Variations Safe Mode experiment is
+ // running.
version_info::Channel channel = version_info::Channel::DEV;
NiceMock<MockVariationsServiceClient> variations_service_client;
ON_CALL(variations_service_client, GetChannel())
.WillByDefault(Return(channel));
TestVariationsFieldTrialCreator field_trial_creator(
- pref_service.get(), &variations_service_client, &safe_seed_manager,
- channel);
+ local_state(), &variations_service_client, &safe_seed_manager, channel,
+ base::FilePath());
base::HistogramTester histogram_tester;
- ASSERT_TRUE(field_trial_creator.SetUpFieldTrials(
- /*extend_variations_safe_mode=*/false));
+ ASSERT_TRUE(field_trial_creator.SetUpFieldTrials());
- // Verify that the experiment is not active and that the WritePrefsTime metric
- // was not recorded.
+ // Verify that the experiment is not active and that Variations Safe Mode was
+ // not extended.
EXPECT_FALSE(base::FieldTrialList::IsTrialActive(kExtendedSafeModeTrial));
+ EXPECT_FALSE(
+ field_trial_creator.was_maybe_extend_variations_safe_mode_called());
histogram_tester.ExpectTotalCount(
"Variations.ExtendedSafeMode.WritePrefsTime", 0);
-
- base::FeatureList::ClearInstanceForTesting();
}
INSTANTIATE_TEST_SUITE_P(
@@ -987,12 +1213,8 @@ INSTANTIATE_TEST_SUITE_P(
TEST_P(FieldTrialCreatorTestWithStartupVisibility,
SkipExperimentInBackgroundSessions) {
- std::unique_ptr<PrefService> pref_service(CreatePrefService());
-
- // Ensure that variations safe mode is not triggered.
- NiceMock<MockSafeSeedManager> safe_seed_manager(pref_service.get());
- ON_CALL(safe_seed_manager, ShouldRunInSafeMode())
- .WillByDefault(Return(false));
+ // Ensure that Variations Safe Mode is not triggered.
+ NiceMock<MockSafeSeedManager> safe_seed_manager(local_state());
NiceMock<MockVariationsServiceClient> variations_service_client;
version_info::Channel channel = version_info::Channel::DEV;
@@ -1001,10 +1223,14 @@ TEST_P(FieldTrialCreatorTestWithStartupVisibility,
StartupVisibilityTestParams params = GetParam();
TestVariationsFieldTrialCreator field_trial_creator(
- pref_service.get(), &variations_service_client, &safe_seed_manager,
- channel, base::FilePath(), params.startup_visibility);
- ASSERT_TRUE(field_trial_creator.SetUpFieldTrials());
+ local_state(), &variations_service_client, &safe_seed_manager, channel,
+ user_data_dir_path(), params.startup_visibility);
+ // Verify that the Extended Variations Safe Mode experiment is active to be
+ // certain that Safe Mode is (or isn't) extended due to the StartupVisibility.
+ ASSERT_TRUE(base::FieldTrialList::IsTrialActive(kExtendedSafeModeTrial));
+
+ ASSERT_TRUE(field_trial_creator.SetUpFieldTrials());
// Verify that MaybeExtendVariationsSafeMode() was (or wasn't) called.
EXPECT_EQ(field_trial_creator.was_maybe_extend_variations_safe_mode_called(),
params.extend_safe_mode);
@@ -1012,74 +1238,53 @@ TEST_P(FieldTrialCreatorTestWithStartupVisibility,
base::FeatureList::ClearInstanceForTesting();
}
-// TODO(b/184937096): Update this test if and when the extended variations safe
-// mode experiment is rolled out to beta or stable.
-TEST_F(FieldTrialCreatorSafeModeExperimentTest,
- DisableExperimentOnSelectChannels) {
- std::unique_ptr<PrefService> pref_service(CreatePrefService());
-
- // Ensure that variations safe mode is not triggered.
- NiceMock<MockSafeSeedManager> safe_seed_manager(pref_service.get());
- ON_CALL(safe_seed_manager, ShouldRunInSafeMode())
- .WillByDefault(Return(false));
-
-// For desktop and iOS, the Extended Variations Safe Mode experiment is enabled
-// on pre-stable channels; for Android Chrome, on canary and dev.
-#if defined(OS_ANDROID)
- std::vector<version_info::Channel> channels = {version_info::Channel::BETA,
- version_info::Channel::STABLE};
-#else
- std::vector<version_info::Channel> channels = {version_info::Channel::STABLE};
-#endif // defined(OS_ANDROID)
-
- for (const version_info::Channel channel : channels) {
- NiceMock<MockVariationsServiceClient> variations_service_client;
- ON_CALL(variations_service_client, GetChannel())
- .WillByDefault(Return(channel));
-
- TestVariationsFieldTrialCreator field_trial_creator(
- pref_service.get(), &variations_service_client, &safe_seed_manager,
- channel);
-
- base::HistogramTester histogram_tester;
- ASSERT_TRUE(field_trial_creator.SetUpFieldTrials());
-
- // Verify that the experiment is not active.
- EXPECT_FALSE(base::FieldTrialList::IsTrialActive(kExtendedSafeModeTrial));
+INSTANTIATE_TEST_SUITE_P(All,
+ SafeModeExperimentTestByChannel,
+ ::testing::Values(version_info::Channel::UNKNOWN,
+ version_info::Channel::CANARY,
+ version_info::Channel::DEV,
+ version_info::Channel::BETA,
+ version_info::Channel::STABLE));
+
+// Verify that the Extended Variations Safe Mode experiment is active on all
+// channels.
+TEST_P(SafeModeExperimentTestByChannel, FieldTrialActivationIsValid) {
+ // Ensure that Variations Safe Mode is not triggered.
+ NiceMock<MockSafeSeedManager> safe_seed_manager(local_state());
+
+ version_info::Channel channel = GetParam();
+ NiceMock<MockVariationsServiceClient> variations_service_client;
+ ON_CALL(variations_service_client, GetChannel())
+ .WillByDefault(Return(channel));
- // Check that no prefs were written and that the WritePrefsTime metric was
- // not recorded.
- std::string pref_file_contents;
- ASSERT_TRUE(base::ReadFileToString(prefs_file(), &pref_file_contents));
- EXPECT_EQ(kEmptyPrefsFile, pref_file_contents);
- histogram_tester.ExpectTotalCount(
- "Variations.ExtendedSafeMode.WritePrefsTime", 0);
+ TestVariationsFieldTrialCreator field_trial_creator(
+ local_state(), &variations_service_client, &safe_seed_manager, channel,
+ user_data_dir_path());
- base::FeatureList::ClearInstanceForTesting();
- }
+ ASSERT_TRUE(field_trial_creator.SetUpFieldTrials());
+ // Verify that the experiment is (or is not) active.
+ EXPECT_TRUE(base::FieldTrialList::IsTrialActive(kExtendedSafeModeTrial));
+ EXPECT_TRUE(
+ field_trial_creator.was_maybe_extend_variations_safe_mode_called());
}
TEST_F(FieldTrialCreatorSafeModeExperimentTest,
- EnableExperimentOnCanary_ControlGroup) {
- std::unique_ptr<PrefService> pref_service(CreatePrefService());
-
+ ControlGroupDoesNotWriteBeaconFile) {
NiceMock<MockVariationsServiceClient> variations_service_client;
- version_info::Channel channel = version_info::Channel::CANARY;
+ version_info::Channel channel = version_info::Channel::BETA;
ON_CALL(variations_service_client, GetChannel())
.WillByDefault(Return(channel));
- // Ensure that variations safe mode is not triggered.
- NiceMock<MockSafeSeedManager> safe_seed_manager(pref_service.get());
- ON_CALL(safe_seed_manager, ShouldRunInSafeMode())
- .WillByDefault(Return(false));
+ // Ensure that Variations Safe Mode is not triggered.
+ NiceMock<MockSafeSeedManager> safe_seed_manager(local_state());
// Assign the client to a specific experiment group before creating the
// TestVariationsFieldTrialCreator so that the CleanExitBeacon uses the
// desired group.
int active_group = SetUpExtendedSafeModeExperiment(kControlGroup);
TestVariationsFieldTrialCreator field_trial_creator(
- pref_service.get(), &variations_service_client, &safe_seed_manager,
- channel);
+ local_state(), &variations_service_client, &safe_seed_manager, channel,
+ user_data_dir_path());
base::HistogramTester histogram_tester;
ASSERT_TRUE(field_trial_creator.SetUpFieldTrials());
@@ -1090,32 +1295,24 @@ TEST_F(FieldTrialCreatorSafeModeExperimentTest,
EXPECT_EQ(active_group,
base::FieldTrialList::FindValue(kExtendedSafeModeTrial));
- // Check that no prefs were written and that the WritePrefsTime metric was
- // recorded.
- std::string pref_file_contents;
- ASSERT_TRUE(base::ReadFileToString(prefs_file(), &pref_file_contents));
- EXPECT_EQ(kEmptyPrefsFile, pref_file_contents);
+ // Check metrics.
histogram_tester.ExpectTotalCount(
"Variations.ExtendedSafeMode.WritePrefsTime", 1);
- // Verify that the Variations Safe Mode file does not exist.
+ // Verify that the beacon file does not exist.
EXPECT_FALSE(base::PathExists(
user_data_dir_path().Append(variations::kVariationsFilename)));
}
TEST_F(FieldTrialCreatorSafeModeExperimentTest,
- EnableExperimentOnDev_SignalAndWriteViaFileUtilGroup) {
- std::unique_ptr<PrefService> pref_service(CreatePrefService());
-
+ ExperimentGroupWritesBeaconFile) {
NiceMock<MockVariationsServiceClient> variations_service_client;
- version_info::Channel channel = version_info::Channel::DEV;
+ version_info::Channel channel = version_info::Channel::BETA;
ON_CALL(variations_service_client, GetChannel())
.WillByDefault(Return(channel));
- // Ensure that variations safe mode is not triggered.
- NiceMock<MockSafeSeedManager> safe_seed_manager(pref_service.get());
- ON_CALL(safe_seed_manager, ShouldRunInSafeMode())
- .WillByDefault(Return(false));
+ // Ensure that Variations Safe Mode is not triggered.
+ NiceMock<MockSafeSeedManager> safe_seed_manager(local_state());
// Assign the client to a specific experiment group before creating the
// TestVariationsFieldTrialCreator so that the CleanExitBeacon uses the
@@ -1123,8 +1320,8 @@ TEST_F(FieldTrialCreatorSafeModeExperimentTest,
int active_group =
SetUpExtendedSafeModeExperiment(kSignalAndWriteViaFileUtilGroup);
TestVariationsFieldTrialCreator field_trial_creator(
- pref_service.get(), &variations_service_client, &safe_seed_manager,
- channel, user_data_dir_path());
+ local_state(), &variations_service_client, &safe_seed_manager, channel,
+ user_data_dir_path());
base::HistogramTester histogram_tester;
ASSERT_TRUE(field_trial_creator.SetUpFieldTrials());
@@ -1135,8 +1332,7 @@ TEST_F(FieldTrialCreatorSafeModeExperimentTest,
EXPECT_EQ(active_group,
base::FieldTrialList::FindValue(kExtendedSafeModeTrial));
- // Verify that the Variations Safe Mode file was written and that the contents
- // are correct.
+ // Verify that the beacon file was written and that the contents are correct.
const base::FilePath variations_file_path =
user_data_dir_path().Append(variations::kVariationsFilename);
EXPECT_TRUE(base::PathExists(variations_file_path));
@@ -1144,17 +1340,15 @@ TEST_F(FieldTrialCreatorSafeModeExperimentTest,
ASSERT_TRUE(
base::ReadFileToString(variations_file_path, &beacon_file_contents));
EXPECT_EQ(beacon_file_contents,
- "{\"user_experience_metrics.stability.exited_cleanly\":false,"
+ "{\"monitoring_stage\":2,"
+ "\"user_experience_metrics.stability.exited_cleanly\":false,"
"\"variations_crash_streak\":0}");
- // Verify that the WritePrefsTime metric was recorded.
+ // Verify metrics.
histogram_tester.ExpectTotalCount(
"Variations.ExtendedSafeMode.WritePrefsTime", 1);
-
- // Check that no prefs were written to the Local State file.
- std::string pref_file_contents;
- ASSERT_TRUE(base::ReadFileToString(prefs_file(), &pref_file_contents));
- EXPECT_EQ(kEmptyPrefsFile, pref_file_contents);
+ histogram_tester.ExpectUniqueSample(
+ "Variations.ExtendedSafeMode.BeaconFileWrite", 1, 1);
}
} // namespace variations
diff --git a/chromium/components/variations/service/variations_safe_mode_constants.cc b/chromium/components/variations/service/variations_safe_mode_constants.cc
index 8b73a7730f2..0988517cdf0 100644
--- a/chromium/components/variations/service/variations_safe_mode_constants.cc
+++ b/chromium/components/variations/service/variations_safe_mode_constants.cc
@@ -9,9 +9,9 @@ namespace variations {
const base::FilePath::CharType kVariationsFilename[] =
FILE_PATH_LITERAL("Variations");
-const char kExtendedSafeModeTrial[] = "ExtendedVariationsSafeMode4";
-const char kControlGroup[] = "Control4";
-const char kDefaultGroup[] = "Default4";
-const char kSignalAndWriteViaFileUtilGroup[] = "SignalAndWriteViaFileUtil4";
+const char kExtendedSafeModeTrial[] = "ExtendedVariationsSafeMode5";
+const char kControlGroup[] = "Control5";
+const char kDefaultGroup[] = "Default5";
+const char kSignalAndWriteViaFileUtilGroup[] = "SignalAndWriteViaFileUtil5";
} // namespace variations
diff --git a/chromium/components/variations/service/variations_service.cc b/chromium/components/variations/service/variations_service.cc
index b812395e6c3..066a96312af 100644
--- a/chromium/components/variations/service/variations_service.cc
+++ b/chromium/components/variations/service/variations_service.cc
@@ -62,9 +62,9 @@
#include "ui/base/device_form_factor.h"
#include "url/gurl.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "components/variations/android/variations_seed_bridge.h"
-#endif // OS_ANDROID
+#endif // BUILDFLAG(IS_ANDROID)
namespace variations {
namespace {
@@ -94,22 +94,22 @@ bool g_should_fetch_for_testing = false;
// Returns a string that will be used for the value of the 'osname' URL param
// to the variations server.
std::string GetPlatformString() {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
return "win";
-#elif defined(OS_IOS)
+#elif BUILDFLAG(IS_IOS)
return "ios";
-#elif defined(OS_MAC)
+#elif BUILDFLAG(IS_MAC)
return "mac";
#elif BUILDFLAG(IS_CHROMEOS_ASH)
return "chromeos";
#elif BUILDFLAG(IS_CHROMEOS_LACROS)
return "chromeos_lacros";
-#elif defined(OS_ANDROID)
+#elif BUILDFLAG(IS_ANDROID)
return "android";
-#elif defined(OS_FUCHSIA)
+#elif BUILDFLAG(IS_FUCHSIA)
return "fuchsia";
-#elif (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) || \
- defined(OS_BSD) || defined(OS_SOLARIS)
+#elif (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) || \
+ BUILDFLAG(IS_BSD) || BUILDFLAG(IS_SOLARIS)
// Default BSD and SOLARIS to Linux to not break those builds, although these
// platforms are not officially supported by Chrome.
return "linux";
@@ -249,7 +249,7 @@ bool IsFetchingEnabled() {
std::unique_ptr<SeedResponse> MaybeImportFirstRunSeed(
PrefService* local_state) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
if (!local_state->HasPrefPath(prefs::kVariationsSeedSignature)) {
DVLOG(1) << "Importing first run seed from Java preferences.";
return android::GetVariationsFirstRunSeed();
@@ -383,12 +383,12 @@ void VariationsService::PerformPreMainMessageLoopStartup() {
// StartRepeatedVariationsSeedFetch(). This is too early to do it on Android
// because at this point the |restrict_mode_| hasn't been set yet. See also
// the CHECK in SetRestrictMode().
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
if (!IsFetchingEnabled())
return;
StartRepeatedVariationsSeedFetch();
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
}
std::string VariationsService::LoadPermanentConsistencyCountry(
@@ -494,7 +494,7 @@ void VariationsService::EnsureLocaleEquals(const std::string& locale) {
return;
#else
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// TODO(asvitkine): Speculative early return to silence CHECK failures on
// Android, see crbug.com/912320.
if (locale.empty())
@@ -953,13 +953,11 @@ bool VariationsService::SetUpFieldTrials(
const std::vector<std::string>& variation_ids,
const std::vector<base::FeatureList::FeatureOverrideInfo>& extra_overrides,
std::unique_ptr<base::FeatureList> feature_list,
- variations::PlatformFieldTrials* platform_field_trials,
- bool extend_variations_safe_mode) {
+ variations::PlatformFieldTrials* platform_field_trials) {
return field_trial_creator_.SetUpFieldTrials(
variation_ids, extra_overrides, CreateLowEntropyProvider(),
std::move(feature_list), state_manager_, platform_field_trials,
- &safe_seed_manager_, state_manager_->GetLowEntropySource(),
- extend_variations_safe_mode);
+ &safe_seed_manager_, state_manager_->GetLowEntropySource());
}
void VariationsService::OverrideCachedUIStrings() {
@@ -992,11 +990,11 @@ std::string VariationsService::GetStoredPermanentCountry() {
if (!variations_overridden_country.empty())
return variations_overridden_country;
- const base::ListValue* list_value =
+ const base::Value* list_value =
local_state_->GetList(prefs::kVariationsPermanentConsistencyCountry);
std::string stored_country;
- base::Value::ConstListView list_view = list_value->GetList();
+ base::Value::ConstListView list_view = list_value->GetListDeprecated();
if (list_view.size() == 2 && list_view[1].is_string()) {
stored_country = list_view[1].GetString();
}
diff --git a/chromium/components/variations/service/variations_service.h b/chromium/components/variations/service/variations_service.h
index a0883a82349..ef942c94410 100644
--- a/chromium/components/variations/service/variations_service.h
+++ b/chromium/components/variations/service/variations_service.h
@@ -187,14 +187,12 @@ class VariationsService
}
// Wrapper around VariationsFieldTrialCreator::SetUpFieldTrials().
- // TODO(crbug/1245646): Remove |extend_variations_safe_mode| param.
bool SetUpFieldTrials(
const std::vector<std::string>& variation_ids,
const std::vector<base::FeatureList::FeatureOverrideInfo>&
extra_overrides,
std::unique_ptr<base::FeatureList> feature_list,
- variations::PlatformFieldTrials* platform_field_trials,
- bool extend_variations_safe_mode = true);
+ variations::PlatformFieldTrials* platform_field_trials);
// Overrides cached UI strings on the resource bundle once it is initialized.
void OverrideCachedUIStrings();
diff --git a/chromium/components/variations/service/variations_service_unittest.cc b/chromium/components/variations/service/variations_service_unittest.cc
index 71905308c67..220e52a0bcd 100644
--- a/chromium/components/variations/service/variations_service_unittest.cc
+++ b/chromium/components/variations/service/variations_service_unittest.cc
@@ -302,12 +302,12 @@ std::string SerializeSeed(const VariationsSeed& seed) {
return serialized_seed;
}
-// Converts |list_value| to a string, to make it easier for debugging.
-std::string ListValueToString(const base::ListValue& list_value) {
+// Converts |value| to a string, to make it easier for debugging.
+std::string ValueToString(const base::Value& value) {
std::string json;
JSONStringValueSerializer serializer(&json);
serializer.set_pretty_print(true);
- serializer.Serialize(list_value);
+ serializer.Serialize(value);
return json;
}
@@ -812,16 +812,15 @@ TEST_F(VariationsServiceTest, LoadPermanentConsistencyCountry) {
<< test.permanent_consistency_country_before << ", " << test.version
<< ", " << test.latest_country_code;
- base::ListValue expected_list_value;
+ base::Value expected_list_value{base::Value::Type::LIST};
for (const std::string& component :
base::SplitString(test.permanent_consistency_country_after, ",",
base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) {
expected_list_value.Append(component);
}
- const base::ListValue* pref_value =
+ const base::Value* pref_value =
prefs_.GetList(prefs::kVariationsPermanentConsistencyCountry);
- EXPECT_EQ(ListValueToString(expected_list_value),
- ListValueToString(*pref_value))
+ EXPECT_EQ(ValueToString(expected_list_value), ValueToString(*pref_value))
<< test.permanent_consistency_country_before << ", " << test.version
<< ", " << test.latest_country_code;
diff --git a/chromium/components/variations/study_filtering_unittest.cc b/chromium/components/variations/study_filtering_unittest.cc
index cef6c287506..0028f25ad60 100644
--- a/chromium/components/variations/study_filtering_unittest.cc
+++ b/chromium/components/variations/study_filtering_unittest.cc
@@ -52,7 +52,7 @@ TEST(VariationsStudyFilteringTest, CheckStudyChannel) {
const Study::Channel channels[] = {
Study::CANARY, Study::DEV, Study::BETA, Study::STABLE,
};
- bool channel_added[base::size(channels)] = {0};
+ bool channel_added[base::size(channels)] = {false};
Study::Filter filter;
@@ -97,7 +97,7 @@ TEST(VariationsStudyFilteringTest, CheckStudyFormFactor) {
ASSERT_EQ(Study::FormFactor_ARRAYSIZE,
static_cast<int>(base::size(form_factors)));
- bool form_factor_added[base::size(form_factors)] = {0};
+ bool form_factor_added[base::size(form_factors)] = {false};
Study::Filter filter;
for (size_t i = 0; i <= base::size(form_factors); ++i) {
@@ -138,7 +138,7 @@ TEST(VariationsStudyFilteringTest, CheckStudyFormFactor) {
// Test exclude_form_factors, forward order.
filter.clear_form_factor();
- bool form_factor_excluded[base::size(form_factors)] = {0};
+ bool form_factor_excluded[base::size(form_factors)] = {false};
for (size_t i = 0; i <= base::size(form_factors); ++i) {
for (size_t j = 0; j < base::size(form_factors); ++j) {
const bool expected = filter.exclude_form_factor_size() == 0 ||
diff --git a/chromium/components/variations/synthetic_trial_registry.cc b/chromium/components/variations/synthetic_trial_registry.cc
index d10468414d4..75f1bbddf65 100644
--- a/chromium/components/variations/synthetic_trial_registry.cc
+++ b/chromium/components/variations/synthetic_trial_registry.cc
@@ -95,7 +95,9 @@ void SyntheticTrialRegistry::RegisterExternalExperiments(
AssociateGoogleVariationIDForceHashes(
GOOGLE_WEB_PROPERTIES_SIGNED_IN, {trial_hash, group_hash},
static_cast<VariationID>(experiment_id));
- SyntheticTrialGroup entry(trial_hash, group_hash);
+ SyntheticTrialGroup entry(
+ trial_hash, group_hash,
+ variations::SyntheticTrialAnnotationMode::kNextLog);
entry.start_time = start_time;
entry.is_external = true;
synthetic_trial_groups_.push_back(entry);
@@ -113,6 +115,10 @@ void SyntheticTrialRegistry::RegisterSyntheticFieldTrial(
const SyntheticTrialGroup& trial) {
for (auto& entry : synthetic_trial_groups_) {
if (entry.id.name == trial.id.name) {
+ // Don't necessarily need to notify observers when setting
+ // |annotation_mode| as it is only used when producing metrics reports
+ // and does not affect variations service.
+ entry.annotation_mode = trial.annotation_mode;
if (entry.id.group != trial.id.group) {
entry.id.group = trial.id.group;
entry.start_time = base::TimeTicks::Now();
@@ -162,7 +168,8 @@ void SyntheticTrialRegistry::GetSyntheticFieldTrialsOlderThan(
DCHECK(synthetic_trials);
synthetic_trials->clear();
for (const auto& entry : synthetic_trial_groups_) {
- if (entry.start_time <= time)
+ if (entry.start_time <= time ||
+ entry.annotation_mode == SyntheticTrialAnnotationMode::kCurrentLog)
synthetic_trials->push_back(entry.id);
}
}
diff --git a/chromium/components/variations/synthetic_trial_registry.h b/chromium/components/variations/synthetic_trial_registry.h
index 0bd141ff79c..3420d885f7a 100644
--- a/chromium/components/variations/synthetic_trial_registry.h
+++ b/chromium/components/variations/synthetic_trial_registry.h
@@ -91,16 +91,24 @@ class COMPONENT_EXPORT(VARIATIONS) SyntheticTrialRegistry {
// Registers a field trial name and group to be used to annotate a UMA report
// with a particular Chrome configuration state.
//
- // A UMA report will be annotated with this trial group if and only if all
- // events in the report were created after the trial is registered. Only one
- // group name may be registered at a time for a given trial_name. Only the
- // last group name that is registered for a given trial name will be recorded.
- // The values passed in must not correspond to any real field trial in the
- // code.
+ // If the |trial_group|'s |annotation_mode| is set to |kNextLog|,
+ // then a UMA report will be annotated with this trial group if and
+ // only if all events in the report were created after the trial's
+ // registration. If the |annotation_mode| is set to |kCurrentLog|, then a
+ // UMA report will be annotated with this trial group even if there are events
+ // in the report that were created before this trial's registration.
+ //
+ // Only one group name may be registered at a time for a given trial name.
+ // Only the last group name that is registered for a given trial name will be
+ // recorded. The values passed in must not correspond to any real field trial
+ // in the code.
//
// The registered trials are not persisted to disk and will not be applied
// after a restart.
//
+ // TODO(crbug.com/754877): Note that UKM is intentionally not mentioned.
+ // Currently, UKM does not record synthetic field trials.
+ //
// Note: Should not be used to replace trials that were
// registered with RegisterExternalExperiments().
void RegisterSyntheticFieldTrial(const SyntheticTrialGroup& trial_group);
@@ -113,7 +121,8 @@ class COMPONENT_EXPORT(VARIATIONS) SyntheticTrialRegistry {
const base::FieldTrialParams& params,
const std::string& experiment_id);
- // Returns a list of synthetic field trials that are older than |time|.
+ // Returns a list of synthetic field trials that are either (1) older than
+ // |time|, or (2) specify |kCurrentLog| as |annotation_mode|.
void GetSyntheticFieldTrialsOlderThan(
base::TimeTicks time,
std::vector<ActiveGroupId>* synthetic_trials) const;
diff --git a/chromium/components/variations/synthetic_trial_registry_unittest.cc b/chromium/components/variations/synthetic_trial_registry_unittest.cc
index 97c452ebf64..caf67799bf0 100644
--- a/chromium/components/variations/synthetic_trial_registry_unittest.cc
+++ b/chromium/components/variations/synthetic_trial_registry_unittest.cc
@@ -13,6 +13,7 @@
#include "base/test/task_environment.h"
#include "components/variations/active_field_trials.h"
#include "components/variations/hashing.h"
+#include "components/variations/synthetic_trials.h"
#include "components/variations/synthetic_trials_active_group_id_provider.h"
#include "components/variations/variations_crash_keys.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -68,11 +69,13 @@ TEST_F(SyntheticTrialRegistryTest, RegisterSyntheticTrial) {
SyntheticTrialRegistry registry;
// Add two synthetic trials and confirm that they show up in the list.
- SyntheticTrialGroup trial1(HashName("TestTrial1"), HashName("Group1"));
- registry.RegisterSyntheticFieldTrial(trial1);
+ SyntheticTrialGroup trial1_group1(HashName("TestTrial1"), HashName("Group1"),
+ SyntheticTrialAnnotationMode::kNextLog);
+ registry.RegisterSyntheticFieldTrial(trial1_group1);
- SyntheticTrialGroup trial2(HashName("TestTrial2"), HashName("Group2"));
- registry.RegisterSyntheticFieldTrial(trial2);
+ SyntheticTrialGroup trial2_group2(HashName("TestTrial2"), HashName("Group2"),
+ SyntheticTrialAnnotationMode::kNextLog);
+ registry.RegisterSyntheticFieldTrial(trial2_group2);
// Ensure that time has advanced by at least a tick before proceeding.
WaitUntilTimeChanges(base::TimeTicks::Now());
@@ -92,25 +95,45 @@ TEST_F(SyntheticTrialRegistryTest, RegisterSyntheticTrial) {
WaitUntilTimeChanges(begin_log_time);
// Change the group for the first trial after the log started.
- SyntheticTrialGroup trial3(HashName("TestTrial1"), HashName("Group2"));
- registry.RegisterSyntheticFieldTrial(trial3);
+ SyntheticTrialGroup trial1_group2(HashName("TestTrial1"), HashName("Group2"),
+ SyntheticTrialAnnotationMode::kNextLog);
+ registry.RegisterSyntheticFieldTrial(trial1_group2);
registry.GetSyntheticFieldTrialsOlderThan(begin_log_time, &synthetic_trials);
EXPECT_EQ(1U, synthetic_trials.size());
EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial2", "Group2"));
// Add a new trial after the log started and confirm that it doesn't show up.
- SyntheticTrialGroup trial4(HashName("TestTrial3"), HashName("Group3"));
- registry.RegisterSyntheticFieldTrial(trial4);
+ SyntheticTrialGroup trial3_group3(HashName("TestTrial3"), HashName("Group3"),
+ SyntheticTrialAnnotationMode::kNextLog);
+ registry.RegisterSyntheticFieldTrial(trial3_group3);
registry.GetSyntheticFieldTrialsOlderThan(begin_log_time, &synthetic_trials);
EXPECT_EQ(1U, synthetic_trials.size());
EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial2", "Group2"));
- // Start a new log and ensure all three trials appear in it.
+ // Change TestTrial3 to be active immediately, add a new trial that also is
+ // active immediately, and confirm they both show up despite being added after
+ // the log started.
+ SyntheticTrialGroup trial3_group3_current_log(
+ HashName("TestTrial3"), HashName("Group3"),
+ SyntheticTrialAnnotationMode::kCurrentLog);
+ SyntheticTrialGroup trial4_group4_current_log(
+ HashName("TestTrial4"), HashName("Group4"),
+ SyntheticTrialAnnotationMode::kCurrentLog);
+ registry.RegisterSyntheticFieldTrial(trial3_group3_current_log);
+ registry.RegisterSyntheticFieldTrial(trial4_group4_current_log);
+ registry.GetSyntheticFieldTrialsOlderThan(begin_log_time, &synthetic_trials);
+ ASSERT_EQ(3U, synthetic_trials.size());
+ EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial2", "Group2"));
+ EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial3", "Group3"));
+ EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial4", "Group4"));
+
+ // Start a new log and ensure all four trials appear in it.
GetSyntheticTrials(registry, &synthetic_trials);
- EXPECT_EQ(3U, synthetic_trials.size());
+ ASSERT_EQ(4U, synthetic_trials.size());
EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial1", "Group2"));
EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial2", "Group2"));
EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial3", "Group3"));
+ EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial4", "Group4"));
}
TEST_F(SyntheticTrialRegistryTest, RegisterExternalExperiments_NoAllowlist) {
@@ -199,10 +222,12 @@ TEST_F(SyntheticTrialRegistryTest, GetSyntheticFieldTrialActiveGroups) {
SyntheticTrialsActiveGroupIdProvider::GetInstance());
// Add two synthetic trials and confirm that they show up in the list.
- SyntheticTrialGroup trial1(HashName("TestTrial1"), HashName("Group1"));
+ SyntheticTrialGroup trial1(HashName("TestTrial1"), HashName("Group1"),
+ SyntheticTrialAnnotationMode::kNextLog);
registry.RegisterSyntheticFieldTrial(trial1);
- SyntheticTrialGroup trial2(HashName("TestTrial2"), HashName("Group2"));
+ SyntheticTrialGroup trial2(HashName("TestTrial2"), HashName("Group2"),
+ SyntheticTrialAnnotationMode::kNextLog);
registry.RegisterSyntheticFieldTrial(trial2);
// Ensure that time has advanced by at least a tick before proceeding.
diff --git a/chromium/components/variations/synthetic_trials.cc b/chromium/components/variations/synthetic_trials.cc
index 228ca44387a..1f93c582f91 100644
--- a/chromium/components/variations/synthetic_trials.cc
+++ b/chromium/components/variations/synthetic_trials.cc
@@ -6,7 +6,11 @@
namespace variations {
-SyntheticTrialGroup::SyntheticTrialGroup(uint32_t trial, uint32_t group) {
+SyntheticTrialGroup::SyntheticTrialGroup(
+ uint32_t trial,
+ uint32_t group,
+ SyntheticTrialAnnotationMode annotation_mode)
+ : annotation_mode(annotation_mode) {
id.name = trial;
id.group = group;
}
diff --git a/chromium/components/variations/synthetic_trials.h b/chromium/components/variations/synthetic_trials.h
index 9586882b5e7..b555760c991 100644
--- a/chromium/components/variations/synthetic_trials.h
+++ b/chromium/components/variations/synthetic_trials.h
@@ -16,17 +16,36 @@
namespace variations {
+// Specifies when UMA reports should start being annotated with a synthetic
+// field trial.
+enum class SyntheticTrialAnnotationMode {
+ // Start annotating UMA reports with this trial only after the next log opens.
+ // The UMA report that will be generated from the log that is open at the time
+ // of registration will not be annotated with this trial.
+ kNextLog,
+ // Start annotating UMA reports with this trial immediately, including the one
+ // that will be generated from the log that is open at the time of
+ // registration.
+ kCurrentLog,
+};
+
// A Field Trial and its selected group, which represent a particular
// Chrome configuration state. For example, the trial name could map to
// a preference name, and the group name could map to a preference value.
struct COMPONENT_EXPORT(VARIATIONS) SyntheticTrialGroup {
public:
- SyntheticTrialGroup(uint32_t trial, uint32_t group);
+ SyntheticTrialGroup(uint32_t trial,
+ uint32_t group,
+ SyntheticTrialAnnotationMode annotation_mode);
~SyntheticTrialGroup();
ActiveGroupId id;
base::TimeTicks start_time;
+ // Determines when UMA reports should start being annotated with this trial
+ // group.
+ SyntheticTrialAnnotationMode annotation_mode;
+
// If this is an external experiment.
bool is_external = false;
};
diff --git a/chromium/components/variations/variations_crash_keys.cc b/chromium/components/variations/variations_crash_keys.cc
index f99ec45ec4d..268c597b3df 100644
--- a/chromium/components/variations/variations_crash_keys.cc
+++ b/chromium/components/variations/variations_crash_keys.cc
@@ -11,6 +11,8 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
#include "base/strings/stringprintf.h"
+#include "base/task/sequenced_task_runner.h"
+#include "base/threading/sequenced_task_runner_handle.h"
#include "build/buildflag.h"
#include "build/chromeos_buildflags.h"
#include "components/crash/core/common/crash_key.h"
diff --git a/chromium/components/variations/variations_crash_keys_unittest.cc b/chromium/components/variations/variations_crash_keys_unittest.cc
index 1d11e7c1961..598920f7dfb 100644
--- a/chromium/components/variations/variations_crash_keys_unittest.cc
+++ b/chromium/components/variations/variations_crash_keys_unittest.cc
@@ -79,7 +79,9 @@ TEST_F(VariationsCrashKeysTest, BasicFunctionality) {
EXPECT_EQ("8e7abfb0-c16397b7,277f2a3d-d77354d0,", info.experiment_list);
// Add two synthetic trials and confirm that they show up in the list.
- SyntheticTrialGroup synth_trial(HashName("Trial3"), HashName("Group3"));
+ SyntheticTrialGroup synth_trial(
+ HashName("Trial3"), HashName("Group3"),
+ variations::SyntheticTrialAnnotationMode::kNextLog);
registry.RegisterSyntheticFieldTrial(synth_trial);
EXPECT_EQ("3", GetNumExperimentsCrashKey());
@@ -106,9 +108,13 @@ TEST_F(VariationsCrashKeysTest, BasicFunctionality) {
info.experiment_list);
// Replace synthetic trial group and add one more.
- SyntheticTrialGroup synth_trial2(HashName("Trial3"), HashName("Group3_A"));
+ SyntheticTrialGroup synth_trial2(
+ HashName("Trial3"), HashName("Group3_A"),
+ variations::SyntheticTrialAnnotationMode::kNextLog);
registry.RegisterSyntheticFieldTrial(synth_trial2);
- SyntheticTrialGroup synth_trial3(HashName("Trial4"), HashName("Group4"));
+ SyntheticTrialGroup synth_trial3(
+ HashName("Trial4"), HashName("Group4"),
+ variations::SyntheticTrialAnnotationMode::kNextLog);
registry.RegisterSyntheticFieldTrial(synth_trial3);
EXPECT_EQ("5", GetNumExperimentsCrashKey());
diff --git a/chromium/components/variations/variations_ids_provider.cc b/chromium/components/variations/variations_ids_provider.cc
index 3e420c1fbb3..70739987308 100644
--- a/chromium/components/variations/variations_ids_provider.cc
+++ b/chromium/components/variations/variations_ids_provider.cc
@@ -76,6 +76,8 @@ VariationsIdsProvider::GetClientDataHeaders(bool is_signed_in) {
if (mode_ == Mode::kIgnoreSignedInState)
is_signed_in = true;
+ else if (mode_ == Mode::kDontSendSignedInVariations)
+ is_signed_in = false;
std::string first_party_header_copy;
std::string any_context_header_copy;
diff --git a/chromium/components/variations/variations_ids_provider.h b/chromium/components/variations/variations_ids_provider.h
index 525e3824ab9..29e32964312 100644
--- a/chromium/components/variations/variations_ids_provider.h
+++ b/chromium/components/variations/variations_ids_provider.h
@@ -65,6 +65,10 @@ class COMPONENT_EXPORT(VARIATIONS) VariationsIdsProvider
// treated as true, regardless of what is supplied. This is intended for
// embedders (such as WebLayer) that do not have the notion of signed-in.
kIgnoreSignedInState,
+
+ // Indicates the signed-in parameter supplied to GetClientDataHeaders() is
+ // treated as false, regardless of what is supplied.
+ kDontSendSignedInVariations,
};
// Creates the VariationsIdsProvider instance. This must be called before
diff --git a/chromium/components/variations/variations_murmur_hash.cc b/chromium/components/variations/variations_murmur_hash.cc
index b4ce83a8061..caa4f0ac4c5 100644
--- a/chromium/components/variations/variations_murmur_hash.cc
+++ b/chromium/components/variations/variations_murmur_hash.cc
@@ -61,10 +61,10 @@ uint32_t VariationsMurmurHash::Hash(const std::vector<uint32_t>& data,
switch (length & 3) {
case 3:
k1 |= data[num_full_blocks] & 0xFF0000;
- FALLTHROUGH;
+ [[fallthrough]];
case 2:
k1 |= data[num_full_blocks] & 0xFF00;
- FALLTHROUGH;
+ [[fallthrough]];
case 1:
k1 |= data[num_full_blocks] & 0xFF;
}
diff --git a/chromium/components/variations/variations_request_scheduler.cc b/chromium/components/variations/variations_request_scheduler.cc
index 30a3abe38d3..23aa828a5bf 100644
--- a/chromium/components/variations/variations_request_scheduler.cc
+++ b/chromium/components/variations/variations_request_scheduler.cc
@@ -59,13 +59,13 @@ base::RepeatingClosure VariationsRequestScheduler::task() const {
return task_;
}
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
// static
VariationsRequestScheduler* VariationsRequestScheduler::Create(
const base::RepeatingClosure& task,
PrefService* local_state) {
return new VariationsRequestScheduler(task);
}
-#endif // !defined(OS_ANDROID) && !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
} // namespace variations
diff --git a/chromium/components/variations/variations_seed_simulator_unittest.cc b/chromium/components/variations/variations_seed_simulator_unittest.cc
index 8b90004e6cd..c9b0b2bef56 100644
--- a/chromium/components/variations/variations_seed_simulator_unittest.cc
+++ b/chromium/components/variations/variations_seed_simulator_unittest.cc
@@ -10,6 +10,7 @@
#include "base/strings/stringprintf.h"
#include "base/test/mock_entropy_provider.h"
+#include "base/time/time.h"
#include "components/variations/processed_study.h"
#include "components/variations/proto/study.pb.h"
#include "components/variations/variations_associated_data.h"
diff --git a/chromium/components/variations/variations_seed_store.cc b/chromium/components/variations/variations_seed_store.cc
index 7f2a99c3883..776181ce253 100644
--- a/chromium/components/variations/variations_seed_store.cc
+++ b/chromium/components/variations/variations_seed_store.cc
@@ -24,10 +24,10 @@
#include "third_party/protobuf/src/google/protobuf/io/coded_stream.h"
#include "third_party/zlib/google/compression_utils.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "components/variations/android/variations_seed_bridge.h"
#include "components/variations/metrics.h"
-#endif // OS_ANDROID
+#endif // BUILDFLAG(IS_ANDROID)
namespace variations {
namespace {
@@ -135,10 +135,10 @@ VariationsSeedStore::VariationsSeedStore(
: local_state_(local_state),
signature_verification_enabled_(signature_verification_enabled),
use_first_run_prefs_(use_first_run_prefs) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
if (initial_seed)
ImportInitialSeed(std::move(initial_seed));
-#endif // OS_ANDROID
+#endif // BUILDFLAG(IS_ANDROID)
}
VariationsSeedStore::~VariationsSeedStore() = default;
@@ -202,16 +202,15 @@ bool VariationsSeedStore::StoreSeedData(
return true;
}
-LoadSeedResult VariationsSeedStore::LoadSafeSeed(
- VariationsSeed* seed,
- ClientFilterableState* client_state) {
+bool VariationsSeedStore::LoadSafeSeed(VariationsSeed* seed,
+ ClientFilterableState* client_state) {
std::string unused_seed_data;
std::string unused_base64_seed_signature;
LoadSeedResult result = LoadSeedImpl(SeedType::SAFE, seed, &unused_seed_data,
&unused_base64_seed_signature);
RecordLoadSafeSeedResult(result);
if (result != LoadSeedResult::kSuccess)
- return result;
+ return false;
// TODO(crbug/1261685): While it's not immediately obvious, |client_state| is
// not used for successfully loaded safe seeds that are rejected after
@@ -224,7 +223,7 @@ LoadSeedResult VariationsSeedStore::LoadSafeSeed(
prefs::kVariationsSafeSeedPermanentConsistencyCountry);
client_state->session_consistency_country = local_state_->GetString(
prefs::kVariationsSafeSeedSessionConsistencyCountry);
- return result;
+ return true;
}
bool VariationsSeedStore::StoreSafeSeed(
@@ -366,7 +365,7 @@ void VariationsSeedStore::ClearPrefs(SeedType seed_type) {
local_state_->ClearPref(prefs::kVariationsSafeSeedSignature);
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
void VariationsSeedStore::ImportInitialSeed(
std::unique_ptr<SeedResponse> initial_seed) {
if (initial_seed->data.empty()) {
@@ -402,7 +401,7 @@ void VariationsSeedStore::ImportInitialSeed(
}
RecordFirstRunSeedImportResult(FirstRunSeedImportResult::SUCCESS);
}
-#endif // OS_ANDROID
+#endif // BUILDFLAG(IS_ANDROID)
LoadSeedResult VariationsSeedStore::LoadSeedImpl(
SeedType seed_type,
@@ -567,7 +566,7 @@ StoreSeedResult VariationsSeedStore::StoreValidatedSeed(
StoreSeedResult result = CompressSeedBytes(seed, &base64_seed_data);
if (result != StoreSeedResult::kSuccess)
return result;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// If currently we do not have any stored pref then we mark seed storing as
// successful on the Java side to avoid repeated seed fetches.
if (local_state_->GetString(prefs::kVariationsCompressedSeed).empty() &&
diff --git a/chromium/components/variations/variations_seed_store.h b/chromium/components/variations/variations_seed_store.h
index bc0f40c9b65..714e18b1208 100644
--- a/chromium/components/variations/variations_seed_store.h
+++ b/chromium/components/variations/variations_seed_store.h
@@ -9,7 +9,6 @@
#include <string>
#include "base/callback.h"
-#include "base/compiler_specific.h"
#include "base/component_export.h"
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
@@ -66,9 +65,9 @@ class COMPONENT_EXPORT(VARIATIONS) VariationsSeedStore {
// problem with loading, clears the seed pref value and returns false. If
// successful, fills the the outparams with the loaded data and returns true.
// Virtual for testing.
- virtual bool LoadSeed(VariationsSeed* seed,
- std::string* seed_data,
- std::string* base64_seed_signature) WARN_UNUSED_RESULT;
+ [[nodiscard]] virtual bool LoadSeed(VariationsSeed* seed,
+ std::string* seed_data,
+ std::string* base64_seed_signature);
// Stores the given seed |data| (serialized protobuf) to local state, along
// with a base64-encoded digital signature for seed and the date when it was
@@ -81,27 +80,25 @@ class COMPONENT_EXPORT(VARIATIONS) VariationsSeedStore {
// Additionally, stores the |country_code| that was received with the seed in
// a separate pref. On success and if |parsed_seed| is not NULL, |parsed_seed|
// will be filled with the de-serialized decoded protobuf.
- bool StoreSeedData(const std::string& data,
- const std::string& base64_seed_signature,
- const std::string& country_code,
- const base::Time& date_fetched,
- bool is_delta_compressed,
- bool is_gzip_compressed,
- VariationsSeed* parsed_seed) WARN_UNUSED_RESULT;
+ [[nodiscard]] bool StoreSeedData(const std::string& data,
+ const std::string& base64_seed_signature,
+ const std::string& country_code,
+ const base::Time& date_fetched,
+ bool is_delta_compressed,
+ bool is_gzip_compressed,
+ VariationsSeed* parsed_seed);
// Loads the safe variations seed data from local state into |seed| and
- // updates any relevant fields in |client_state|. Returns
- // LoadSeedResult::kSuccess iff the safe seed was read successfully from
- // prefs. If the safe seed could not be loaded, it is guaranteed that no
- // fields in |client_state| are modified.
+ // updates any relevant fields in |client_state|. Returns true iff the safe
+ // seed was read successfully from prefs. If the safe seed could not be
+ // loaded, it is guaranteed that no fields in |client_state| are modified.
//
// Side effect: Upon failing to read or validate the safe seed, clears all
// of the safe seed pref values.
//
// Virtual for testing.
- virtual LoadSeedResult LoadSafeSeed(VariationsSeed* seed,
- ClientFilterableState* client_state)
- WARN_UNUSED_RESULT;
+ [[nodiscard]] virtual bool LoadSafeSeed(VariationsSeed* seed,
+ ClientFilterableState* client_state);
// Stores the given |seed_data| (a serialized protobuf) to local state as a
// safe seed, along with a base64-encoded digital signature for seed and any
@@ -168,14 +165,14 @@ class COMPONENT_EXPORT(VARIATIONS) VariationsSeedStore {
// type.
void ClearPrefs(SeedType seed_type);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Imports the variations seed from the Java side. Logs UMA on failure.
// Android Chrome uses this on first run; WebView uses this on every startup.
// In Chrome's case, it's important to set the first run seed as soon as
// possible, because some clients query the seed store prefs directly rather
// than accessing them via the seed store API: https://crbug.com/829527
void ImportInitialSeed(std::unique_ptr<SeedResponse> initial_seed);
-#endif // OS_ANDROID
+#endif // BUILDFLAG(IS_ANDROID)
// Loads the variations seed data from local state into |seed|, as well as the
// raw pref values into |seed_data| and |base64_signature|. Loads either the
@@ -183,66 +180,66 @@ class COMPONENT_EXPORT(VARIATIONS) VariationsSeedStore {
// loading the seed was successful.
// Side-effect: Upon any failure to read or validate the safe seed, clears all
// of the pref values for the seed. This occurs iff the method returns false.
- LoadSeedResult LoadSeedImpl(SeedType seed_type,
- VariationsSeed* seed,
- std::string* seed_data,
- std::string* base64_seed_signature)
- WARN_UNUSED_RESULT;
+ [[nodiscard]] LoadSeedResult LoadSeedImpl(SeedType seed_type,
+ VariationsSeed* seed,
+ std::string* seed_data,
+ std::string* base64_seed_signature);
// Reads the variations seed data from prefs into |seed_data|, and returns the
// result of the load. The value stored into |seed_data| should only be used
// if the result is SUCCESS. Reads either the latest or the safe seed,
// according to the specified |seed_type|.
// Side-effect: If the read fails, clears the prefs associated with the seed.
- LoadSeedResult ReadSeedData(SeedType seed_type,
- std::string* seed_data) WARN_UNUSED_RESULT;
+ [[nodiscard]] LoadSeedResult ReadSeedData(SeedType seed_type,
+ std::string* seed_data);
// Resolves a |delta_bytes| against the latest seed.
// Returns success or an error, populating |seed_bytes| on success.
- StoreSeedResult ResolveDelta(const std::string& delta_bytes,
- std::string* seed_bytes) WARN_UNUSED_RESULT;
+ [[nodiscard]] StoreSeedResult ResolveDelta(const std::string& delta_bytes,
+ std::string* seed_bytes);
// Resolves instance manipulations applied to received data.
// Returns success or an error, populating |seed_bytes| on success.
- StoreSeedResult ResolveInstanceManipulations(const std::string& data,
- const InstanceManipulations& im,
- std::string* seed_bytes)
- WARN_UNUSED_RESULT;
+ [[nodiscard]] StoreSeedResult ResolveInstanceManipulations(
+ const std::string& data,
+ const InstanceManipulations& im,
+ std::string* seed_bytes);
// Validates that |seed_bytes| parses and matches |base64_seed_signature|.
// Signature checking may be disabled via |signature_verification_enabled_|.
// |seed_type| indicates the source of the seed for logging purposes.
// |result| must be non-null, and will be populated on success.
// Returns success or some error value.
- StoreSeedResult ValidateSeedBytes(const std::string& seed_bytes,
- const std::string& base64_seed_signature,
- SeedType seed_type,
- ValidatedSeed* result) WARN_UNUSED_RESULT;
+ [[nodiscard]] StoreSeedResult ValidateSeedBytes(
+ const std::string& seed_bytes,
+ const std::string& base64_seed_signature,
+ SeedType seed_type,
+ ValidatedSeed* result);
// Gzip compresses and base64 encodes a validated seed.
// Returns success or error and populates base64_seed_data on success.
- StoreSeedResult CompressSeedBytes(const ValidatedSeed& validated,
- std::string* base64_seed_data)
- WARN_UNUSED_RESULT;
+ [[nodiscard]] StoreSeedResult CompressSeedBytes(
+ const ValidatedSeed& validated,
+ std::string* base64_seed_data);
// Updates the latest seed with validated data.
- StoreSeedResult StoreValidatedSeed(const ValidatedSeed& seed,
- const std::string& country_code,
- const base::Time& date_fetched)
- WARN_UNUSED_RESULT;
+ [[nodiscard]] StoreSeedResult StoreValidatedSeed(
+ const ValidatedSeed& seed,
+ const std::string& country_code,
+ const base::Time& date_fetched);
// Updates the safe seed with validated data.
- StoreSeedResult StoreValidatedSafeSeed(
+ [[nodiscard]] StoreSeedResult StoreValidatedSafeSeed(
const ValidatedSeed& seed,
int seed_milestone,
const ClientFilterableState& client_state,
- base::Time seed_fetch_time) WARN_UNUSED_RESULT;
+ base::Time seed_fetch_time);
// Applies a delta-compressed |patch| to |existing_data|, producing the result
// in |output|. Returns whether the operation was successful.
- static bool ApplyDeltaPatch(const std::string& existing_data,
- const std::string& patch,
- std::string* output) WARN_UNUSED_RESULT;
+ [[nodiscard]] static bool ApplyDeltaPatch(const std::string& existing_data,
+ const std::string& patch,
+ std::string* output);
// The pref service used to persist the variations seed.
raw_ptr<PrefService> local_state_;
diff --git a/chromium/components/variations/variations_seed_store_unittest.cc b/chromium/components/variations/variations_seed_store_unittest.cc
index c139844609f..f02016db893 100644
--- a/chromium/components/variations/variations_seed_store_unittest.cc
+++ b/chromium/components/variations/variations_seed_store_unittest.cc
@@ -22,9 +22,9 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/zlib/google/compression_utils.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "components/variations/android/variations_seed_bridge.h"
-#endif // OS_ANDROID
+#endif // BUILDFLAG(IS_ANDROID)
namespace variations {
namespace {
@@ -493,8 +493,7 @@ TEST(VariationsSeedStoreTest, LoadSafeSeed_ValidSeed) {
VariationsSeed loaded_seed;
std::unique_ptr<ClientFilterableState> client_state =
CreateTestClientFilterableState();
- EXPECT_EQ(LoadSeedResult::kSuccess,
- seed_store.LoadSafeSeed(&loaded_seed, client_state.get()));
+ EXPECT_TRUE(seed_store.LoadSafeSeed(&loaded_seed, client_state.get()));
// Verify metrics.
histogram_tester.ExpectUniqueSample("Variations.SafeMode.LoadSafeSeed.Result",
@@ -537,8 +536,7 @@ TEST(VariationsSeedStoreTest, LoadSafeSeed_CorruptSeed) {
VariationsSeed loaded_seed;
std::unique_ptr<ClientFilterableState> client_state =
CreateTestClientFilterableState();
- EXPECT_EQ(LoadSeedResult::kCorruptBase64,
- seed_store.LoadSafeSeed(&loaded_seed, client_state.get()));
+ EXPECT_FALSE(seed_store.LoadSafeSeed(&loaded_seed, client_state.get()));
// Verify metrics and prefs.
histogram_tester.ExpectUniqueSample("Variations.SafeMode.LoadSafeSeed.Result",
@@ -576,8 +574,7 @@ TEST(VariationsSeedStoreTest, LoadSafeSeed_InvalidSignature) {
VariationsSeed loaded_seed;
std::unique_ptr<ClientFilterableState> client_state =
CreateTestClientFilterableState();
- EXPECT_EQ(LoadSeedResult::kInvalidSignature,
- seed_store.LoadSafeSeed(&loaded_seed, client_state.get()));
+ EXPECT_FALSE(seed_store.LoadSafeSeed(&loaded_seed, client_state.get()));
// Verify metrics and prefs.
histogram_tester.ExpectUniqueSample("Variations.SafeMode.LoadSafeSeed.Result",
@@ -606,8 +603,7 @@ TEST(VariationsSeedStoreTest, LoadSafeSeed_EmptySeed) {
base::HistogramTester histogram_tester;
VariationsSeed loaded_seed;
ClientFilterableState client_state(base::BindOnce([] { return false; }));
- EXPECT_EQ(LoadSeedResult::kEmpty,
- seed_store.LoadSafeSeed(&loaded_seed, &client_state));
+ EXPECT_FALSE(seed_store.LoadSafeSeed(&loaded_seed, &client_state));
// Verify metrics.
histogram_tester.ExpectUniqueSample("Variations.SafeMode.LoadSafeSeed.Result",
@@ -823,8 +819,7 @@ TEST(VariationsSeedStoreTest, StoreSafeSeed_IdenticalToLatestSeed) {
// and that the last fetch time was copied from the latest seed.
EXPECT_EQ(base64_seed, prefs.GetString(prefs::kVariationsSafeCompressedSeed));
VariationsSeed loaded_safe_seed;
- EXPECT_EQ(LoadSeedResult::kSuccess,
- seed_store.LoadSafeSeed(&loaded_safe_seed, &unused_client_state));
+ EXPECT_TRUE(seed_store.LoadSafeSeed(&loaded_safe_seed, &unused_client_state));
EXPECT_EQ(SerializeSeed(seed), SerializeSeed(loaded_safe_seed));
EXPECT_EQ(last_fetch_time, seed_store.GetSafeSeedFetchTime());
@@ -883,8 +878,7 @@ TEST(VariationsSeedStoreTest, StoreSafeSeed_PreviouslyIdenticalToLatestSeed) {
EXPECT_EQ(base64_new_seed,
prefs.GetString(prefs::kVariationsSafeCompressedSeed));
VariationsSeed loaded_safe_seed;
- EXPECT_EQ(LoadSeedResult::kSuccess,
- seed_store.LoadSafeSeed(&loaded_safe_seed, &unused_client_state));
+ EXPECT_TRUE(seed_store.LoadSafeSeed(&loaded_safe_seed, &unused_client_state));
EXPECT_EQ(SerializeSeed(new_seed), SerializeSeed(loaded_safe_seed));
EXPECT_EQ(fetch_time, seed_store.GetSafeSeedFetchTime());
@@ -1171,7 +1165,7 @@ TEST(VariationsSeedStoreTest, GetLatestSerialNumber_ClearsPrefsOnFailure) {
EXPECT_TRUE(PrefHasDefaultValue(prefs, prefs::kVariationsCompressedSeed));
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
TEST(VariationsSeedStoreTest, ImportFirstRunJavaSeed) {
const std::string test_seed_data = "raw_seed_data_test";
const std::string test_seed_signature = "seed_signature_test";
@@ -1261,6 +1255,6 @@ TEST_P(VariationsSeedStoreFirstRunPrefsTest, FirstRunPrefsAllowed) {
EXPECT_EQ(base64_seed_data,
prefs.GetString(prefs::kVariationsCompressedSeed));
}
-#endif // OS_ANDROID
+#endif // BUILDFLAG(IS_ANDROID)
} // namespace variations
diff --git a/chromium/components/variations/variations_switches.cc b/chromium/components/variations/variations_switches.cc
index 62e91ac4c57..870fe57fb1a 100644
--- a/chromium/components/variations/variations_switches.cc
+++ b/chromium/components/variations/variations_switches.cc
@@ -17,6 +17,17 @@ const char kDisableVariationsSafeMode[] = "disable-variations-safe-mode";
// Enables the benchmarking extensions.
const char kEnableBenchmarking[] = "enable-benchmarking";
+// Enable field trial tests configured in fieldtrial_testing_config.json. If the
+// "disable_fieldtrial_testing_config" GN flag is set to true, then this switch
+// is a no-op. Otherwise, for non-Chrome branded builds, the testing config is
+// already applied by default, unless the "--disable-field-trial-config",
+// "--force-fieldtrials", and/or "--variations-server-url" switches are passed.
+// It is however possible to apply the testing config as well as specify
+// additional field trials (using "--force-fieldtrials") by using this switch.
+// For Chrome-branded builds, the testing config is not enabled by default, so
+// this switch is required to enable it.
+const char kEnableFieldTrialTestingConfig[] = "enable-field-trial-config";
+
// Fakes the channel of the browser for purposes of Variations filtering. This
// is to be used for testing only. Possible values are "stable", "beta", "dev"
// and "canary". This works for official builds as well.
diff --git a/chromium/components/variations/variations_switches.h b/chromium/components/variations/variations_switches.h
index 8bef57903dc..4744b6db303 100644
--- a/chromium/components/variations/variations_switches.h
+++ b/chromium/components/variations/variations_switches.h
@@ -20,6 +20,8 @@ extern const char kDisableVariationsSafeMode[];
COMPONENT_EXPORT(VARIATIONS)
extern const char kEnableBenchmarking[];
COMPONENT_EXPORT(VARIATIONS)
+extern const char kEnableFieldTrialTestingConfig[];
+COMPONENT_EXPORT(VARIATIONS)
extern const char kFakeVariationsChannel[];
COMPONENT_EXPORT(VARIATIONS)
extern const char kForceFieldTrialParams[];
diff --git a/chromium/components/variations/variations_test_utils.cc b/chromium/components/variations/variations_test_utils.cc
index 78dc6ef73bd..d804ebf6088 100644
--- a/chromium/components/variations/variations_test_utils.cc
+++ b/chromium/components/variations/variations_test_utils.cc
@@ -10,6 +10,7 @@
#include "components/metrics/clean_exit_beacon.h"
#include "components/metrics/metrics_pref_names.h"
#include "components/prefs/pref_service.h"
+#include "components/variations/field_trial_config/fieldtrial_testing_config.h"
#include "components/variations/pref_names.h"
#include "components/variations/proto/client_variations.pb.h"
#include "components/variations/service/variations_safe_mode_constants.h"
@@ -60,6 +61,83 @@ const char kCrashingSeed_Base64Signature[] =
"MEQCIEn1+VsBfNA93dxzpk+BLhdO91kMQnofxfTK5Uo8vDi8AiAnTCFCIPgEGWNOKzuKfNWn6"
"emB6pnGWjSTbI/pvfxHnw==";
+// Create mock testing config equivalent to:
+// {
+// "UnitTest": [
+// {
+// "platforms": [
+// "android",
+// "android_weblayer",
+// "android_webview",
+// "chromeos",
+// "chromeos_lacros",
+// "fuchsia",
+// "ios",
+// "linux",
+// "mac",
+// "windows"
+// ],
+// "experiments": [
+// {
+// "name": "Enabled",
+// "params": {
+// "x": "1"
+// },
+// "enable_features": [
+// "UnitTestEnabled"
+// ]
+// }
+// ]
+// }
+// ]
+// }
+
+const Study::Platform array_kFieldTrialConfig_platforms_0[] = {
+ Study::PLATFORM_ANDROID,
+ Study::PLATFORM_ANDROID_WEBLAYER,
+ Study::PLATFORM_ANDROID_WEBVIEW,
+ Study::PLATFORM_CHROMEOS,
+ Study::PLATFORM_CHROMEOS_LACROS,
+ Study::PLATFORM_FUCHSIA,
+ Study::PLATFORM_IOS,
+ Study::PLATFORM_LINUX,
+ Study::PLATFORM_MAC,
+ Study::PLATFORM_WINDOWS,
+};
+
+const char* enable_features_0[] = {"UnitTestEnabled"};
+const FieldTrialTestingExperimentParams array_kFieldTrialConfig_params_0[] = {
+ {
+ "x",
+ "1",
+ },
+};
+
+const FieldTrialTestingExperiment array_kFieldTrialConfig_experiments_0[] = {
+ {/*name=*/"Enabled",
+ /*platforms=*/array_kFieldTrialConfig_platforms_0,
+ /*platforms_size=*/10,
+ /*form_factors=*/{},
+ /*form_factors_size=*/0,
+ /*is_low_end_device=*/absl::nullopt,
+ /*min_os_version=*/nullptr,
+ /*params=*/array_kFieldTrialConfig_params_0,
+ /*params_size=*/1,
+ /*enable_features=*/enable_features_0,
+ /*enable_features_size=*/1,
+ /*disable_features=*/nullptr,
+ /*disable_features_size=*/0,
+ /*forcing_flag=*/nullptr,
+ /*override_ui_string=*/nullptr,
+ /*override_ui_string_size=*/0},
+};
+
+const FieldTrialTestingStudy array_kFieldTrialConfig_studies[] = {
+ {/*name=*/"UnitTest",
+ /*experiments=*/array_kFieldTrialConfig_experiments_0,
+ /*experiments_size=*/1},
+};
+
} // namespace
const SignedSeedData kTestSeedData{
@@ -97,6 +175,11 @@ void DisableTestingConfig() {
switches::kDisableFieldTrialTestingConfig);
}
+void EnableTestingConfig() {
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kEnableFieldTrialTestingConfig);
+}
+
bool ExtractVariationIds(const std::string& variations,
std::set<VariationID>* variation_ids,
std::set<VariationID>* trigger_ids) {
@@ -167,4 +250,14 @@ bool FieldTrialListHasAllStudiesFrom(const SignedSeedData& seed_data) {
});
}
+void ResetVariations() {
+ testing::ClearAllVariationIDs();
+ testing::ClearAllVariationParams();
+}
+
+const FieldTrialTestingConfig kTestingConfig = {
+ array_kFieldTrialConfig_studies,
+ 1,
+};
+
} // namespace variations
diff --git a/chromium/components/variations/variations_test_utils.h b/chromium/components/variations/variations_test_utils.h
index f5892ab505f..7f90d5c9384 100644
--- a/chromium/components/variations/variations_test_utils.h
+++ b/chromium/components/variations/variations_test_utils.h
@@ -11,6 +11,7 @@
#include "base/containers/span.h"
#include "base/memory/scoped_refptr.h"
#include "base/metrics/field_trial.h"
+#include "components/variations/field_trial_config/fieldtrial_testing_config.h"
#include "components/variations/variations_associated_data.h"
class PrefService;
@@ -64,10 +65,16 @@ extern const SignedSeedPrefKeys kSafeSeedPrefKeys;
// The pref keys used to store regular signed variations seed data.
extern const SignedSeedPrefKeys kRegularSeedPrefKeys;
+// Mock field trial testing config.
+extern const FieldTrialTestingConfig kTestingConfig;
+
// Disables the use of the field trial testing config to exercise
// VariationsFieldTrialCreator::CreateTrialsFromSeed().
void DisableTestingConfig();
+// Enables the use of the field trial testing config.
+void EnableTestingConfig();
+
// Decodes the variations header and extracts the variation ids.
bool ExtractVariationIds(const std::string& variations,
std::set<VariationID>* variation_ids,
@@ -97,6 +104,10 @@ void WriteSeedData(PrefService* local_state,
// (global) field trial list.
bool FieldTrialListHasAllStudiesFrom(const SignedSeedData& seed_data);
+// Resets variations. Ensures that maps can be cleared between tests since they
+// are stored as process singleton.
+void ResetVariations();
+
} // namespace variations
#endif // COMPONENTS_VARIATIONS_VARIATIONS_TEST_UTILS_H_
diff --git a/chromium/components/vector_icons/BUILD.gn b/chromium/components/vector_icons/BUILD.gn
index 4928ae06b39..823efbb708f 100644
--- a/chromium/components/vector_icons/BUILD.gn
+++ b/chromium/components/vector_icons/BUILD.gn
@@ -2,6 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//build/config/chromeos/ui_mode.gni")
import("//components/vector_icons/vector_icons.gni")
aggregate_vector_icons("components_vector_icons") {
@@ -33,6 +34,7 @@ aggregate_vector_icons("components_vector_icons") {
"description.icon",
"devices.icon",
"devices_off.icon",
+ "dogfood.icon",
"edit.icon",
"email.icon",
"error.icon",
@@ -48,11 +50,13 @@ aggregate_vector_icons("components_vector_icons") {
"folder_touch.icon",
"font_download.icon",
"forward_arrow.icon",
+ "google_color.icon",
"gpp_maybe.icon",
"groups.icon",
"headset.icon",
"help.icon",
"help_outline.icon",
+ "history.icon",
"https_valid.icon",
"https_valid_arrow.icon",
"info_outline.icon",
@@ -87,6 +91,7 @@ aggregate_vector_icons("components_vector_icons") {
"play_arrow.icon",
"protected_content.icon",
"protocol_handler.icon",
+ "qr_code.icon",
"reload.icon",
"replay.icon",
"save_original_file.icon",
@@ -96,6 +101,7 @@ aggregate_vector_icons("components_vector_icons") {
"sensors.icon",
"serial_port.icon",
"settings.icon",
+ "settings_outline.icon",
"sms.icon",
"submenu_arrow.icon",
"sync.icon",
@@ -109,8 +115,13 @@ aggregate_vector_icons("components_vector_icons") {
"vr_headset.icon",
"vr_headset_off.icon",
"warning.icon",
+ "warning_outline.icon",
"wifi_add.icon",
]
+
+ if (is_chromeos_ash) {
+ sources += [ "videogame_asset_outline.icon" ]
+ }
}
static_library("vector_icons") {
diff --git a/chromium/components/vector_icons/dogfood.icon b/chromium/components/vector_icons/dogfood.icon
new file mode 100644
index 00000000000..41050a974a3
--- /dev/null
+++ b/chromium/components/vector_icons/dogfood.icon
@@ -0,0 +1,50 @@
+// Copyright 2020 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.
+
+CANVAS_DIMENSIONS, 24,
+MOVE_TO, 9.75f, 9.25f,
+CUBIC_TO, 10.72f, 9.25f, 11.5f, 8.47f, 11.5f, 7.5f,
+CUBIC_TO, 11.5f, 6.53f, 10.72f, 5.75f, 9.75f, 5.75f,
+CUBIC_TO, 8.78f, 5.75f, 8, 6.53f, 8, 7.5f,
+CUBIC_TO, 8, 8.47f, 8.78f, 9.25f, 9.75f, 9.25f,
+CLOSE,
+MOVE_TO, 6.88f, 12.25f,
+CUBIC_TO, 7.85f, 12.25f, 8.63f, 11.47f, 8.63f, 10.5f,
+CUBIC_TO, 8.63f, 9.53f, 7.85f, 8.75f, 6.88f, 8.75f,
+CUBIC_TO, 5.91f, 8.75f, 5.13f, 9.53f, 5.13f, 10.5f,
+CUBIC_TO, 5.13f, 11.47f, 5.91f, 12.25f, 6.88f, 12.25f,
+CLOSE,
+MOVE_TO, 15.75f, 7.5f,
+CUBIC_TO, 15.75f, 8.47f, 14.97f, 9.25f, 14, 9.25f,
+CUBIC_TO, 13.03f, 9.25f, 12.25f, 8.47f, 12.25f, 7.5f,
+CUBIC_TO, 12.25f, 6.53f, 13.03f, 5.75f, 14, 5.75f,
+CUBIC_TO, 14.97f, 5.75f, 15.75f, 6.53f, 15.75f, 7.5f,
+CLOSE,
+MOVE_TO, 17.12f, 12.25f,
+CUBIC_TO, 18.09f, 12.25f, 18.87f, 11.47f, 18.87f, 10.5f,
+CUBIC_TO, 18.87f, 9.53f, 18.09f, 8.75f, 17.12f, 8.75f,
+CUBIC_TO, 16.15f, 8.75f, 15.37f, 9.53f, 15.37f, 10.5f,
+CUBIC_TO, 15.37f, 11.47f, 16.15f, 12.25f, 17.12f, 12.25f,
+CLOSE,
+MOVE_TO, 12.63f, 10.36f,
+CUBIC_TO, 13.17f, 10.54f, 13.54f, 10.9f, 13.89f, 11.3f,
+CUBIC_TO, 14.07f, 11.51f, 14.24f, 11.72f, 14.42f, 11.93f,
+CUBIC_TO, 14.79f, 12.38f, 15.16f, 12.83f, 15.58f, 13.25f,
+CUBIC_TO, 15.67f, 13.34f, 15.76f, 13.43f, 15.85f, 13.52f,
+CUBIC_TO, 16.7f, 14.38f, 17.59f, 15.27f, 17.34f, 16.54f,
+CUBIC_TO, 17.18f, 17.34f, 16.65f, 17.96f, 15.81f, 18.22f,
+CUBIC_TO, 15.58f, 18.29f, 15.05f, 18.22f, 14.35f, 18.13f,
+CUBIC_TO, 13.62f, 18.04f, 12.72f, 17.92f, 11.81f, 17.92f,
+CUBIC_TO, 10.88f, 17.92f, 10, 18.04f, 9.31f, 18.13f,
+CUBIC_TO, 8.68f, 18.22f, 8.19f, 18.29f, 7.97f, 18.22f,
+CUBIC_TO, 7.13f, 17.96f, 6.59f, 17.34f, 6.43f, 16.54f,
+CUBIC_TO, 6.18f, 15.26f, 7.07f, 14.37f, 7.92f, 13.51f,
+CUBIC_TO, 8.01f, 13.42f, 8.09f, 13.34f, 8.18f, 13.25f,
+CUBIC_TO, 8.56f, 12.86f, 8.91f, 12.44f, 9.25f, 12.01f,
+CUBIC_TO, 9.45f, 11.77f, 9.64f, 11.53f, 9.84f, 11.3f,
+CUBIC_TO, 10.19f, 10.9f, 10.52f, 10.54f, 11.06f, 10.36f,
+CUBIC_TO, 11.3f, 10.29f, 11.55f, 10.25f, 11.8f, 10.25f,
+CUBIC_TO, 11.8f, 10.25f, 12.39f, 10.28f, 12.63f, 10.36f,
+CLOSE
+
diff --git a/chromium/components/vector_icons/google_color.icon b/chromium/components/vector_icons/google_color.icon
new file mode 100644
index 00000000000..77d5e0ff9c6
--- /dev/null
+++ b/chromium/components/vector_icons/google_color.icon
@@ -0,0 +1,95 @@
+// Copyright 2017 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.
+
+PATH_COLOR_ARGB, 0xFF, 0x42, 0x85, 0xF4,
+MOVE_TO, 43.5f, 20,
+H_LINE_TO, 24,
+R_V_LINE_TO, 8,
+R_H_LINE_TO, 11.6f,
+R_CUBIC_TO, -0.5f, 2.5f, -2.2f, 4.7f, -4.3f, 6.1f,
+R_LINE_TO, 6.6f, 5,
+R_CUBIC_TO, 3.9f, -3.5f, 6.1f, -8.6f, 6.1f, -14.7f,
+CUBIC_TO, 44, 23, 43.7f, 21.3f, 43.5f, 20,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0x0F, 0x9D, 0x58,
+MOVE_TO, 24.4f, 36.1f,
+R_CUBIC_TO, -5.3f, 0, -9.8f, -3.5f, -11.4f, -8.2f,
+R_H_LINE_TO, 0,
+R_LINE_TO, -1.5f, 1.1f,
+R_LINE_TO, -5.3f, 4,
+R_V_LINE_TO, 0,
+R_CUBIC_TO, 3.4f, 6.5f, 10.2f, 11, 18.2f, 11,
+R_CUBIC_TO, 5.5f, 0, 10.1f, -1.8f, 13.5f, -4.8f,
+R_LINE_TO, -6.6f, -5,
+CUBIC_TO, 29.5f, 35.3f, 27.2f, 36.1f, 24.4f, 36.1f,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xFF, 0xCD, 0x40,
+MOVE_TO, 13, 27.8f,
+LINE_TO, 13, 27.8f,
+R_CUBIC_TO, -0.4f, -1.2f, -0.6f, -2.5f, -0.6f, -3.8f,
+R_CUBIC_TO, 0, -1.3f, 0.2f, -2.6f, 0.6f, -3.8f,
+LINE_TO, 6.2f, 15,
+CUBIC_TO, 4.8f, 17.7f, 4, 20.8f, 4, 24,
+R_CUBIC_TO, 0, 3.2f, 0.8f, 6.3f, 2.2f, 9,
+R_LINE_TO, 5.3f, -4,
+LINE_TO, 13, 27.8f,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xDB, 0x44, 0x37,
+MOVE_TO, 24.4f, 4,
+R_CUBIC_TO, -8, 0, -14.9f, 4.5f, -18.2f, 11,
+R_LINE_TO, 6.8f, 5.2f,
+R_CUBIC_TO, 1.6f, -4.7f, 6.1f, -8.2f, 11.4f, -8.2f,
+R_CUBIC_TO, 3, 0, 5.7f, 1, 7.8f, 3,
+R_LINE_TO, 5.8f, -5.7f,
+CUBIC_TO, 34.5f, 6, 29.9f, 4, 24.4f, 4,
+CLOSE
+
+CANVAS_DIMENSIONS, 24,
+PATH_COLOR_ARGB, 0xFF, 0x42, 0x85, 0xF4,
+MOVE_TO, 21.73f, 10,
+LINE_TO, 12, 10,
+LINE_TO, 12, 14,
+LINE_TO, 17.82f, 14,
+CUBIC_TO, 17.58f, 15.25f, 16.73f, 16.35f, 15.65f, 17.06f,
+LINE_TO, 15.65f, 19.58f,
+LINE_TO, 18.96f, 19.58f,
+CUBIC_TO, 20.89f, 17.84f, 22, 15.27f, 22, 12.23f,
+CUBIC_TO, 22, 11.52f, 21.85f, 10.65f, 21.73f, 10,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0x0F, 0x9D, 0x58,
+MOVE_TO, 12.2f, 22,
+CUBIC_TO, 14.96f, 22, 17.27f, 21.11f, 18.96f, 19.58f,
+LINE_TO, 15.65f, 17.06f,
+CUBIC_TO, 14.74f, 17.66f, 13.58f, 18.03f, 12.2f, 18.03f,
+CUBIC_TO, 9.55f, 18.03f, 7.3f, 16.27f, 6.49f, 13.91f,
+LINE_TO, 3.09f, 13.91f,
+LINE_TO, 3.09f, 16.49f,
+CUBIC_TO, 4.77f, 19.75f, 8.22f, 22, 12.2f, 22,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xFF, 0xCD, 0x40,
+MOVE_TO, 6.49f, 13.9f,
+CUBIC_TO, 6.29f, 13.3f, 6.17f, 12.66f, 6.17f, 12,
+CUBIC_TO, 6.17f, 11.34f, 6.29f, 10.7f, 6.49f, 10.1f,
+LINE_TO, 6.49f, 7.52f,
+LINE_TO, 3.09f, 7.52f,
+CUBIC_TO, 2.4f, 8.86f, 2, 10.38f, 2, 12,
+CUBIC_TO, 2, 13.62f, 2.4f, 15.14f, 3.09f, 16.48f,
+LINE_TO, 5.74f, 14.46f,
+LINE_TO, 6.49f, 13.9f,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xDB, 0x44, 0x37,
+MOVE_TO, 12.2f, 5.98f,
+CUBIC_TO, 13.71f, 5.98f, 15.04f, 6.49f, 16.11f, 7.47f,
+LINE_TO, 19.03f, 4.61f,
+CUBIC_TO, 17.26f, 2.99f, 14.96f, 2, 12.2f, 2,
+CUBIC_TO, 8.22f, 2, 4.77f, 4.25f, 3.09f, 7.52f,
+LINE_TO, 6.49f, 10.1f,
+CUBIC_TO, 7.3f, 7.74f, 9.55f, 5.98f, 12.2f, 5.98f,
+CLOSE
diff --git a/chromium/components/vector_icons/history.icon b/chromium/components/vector_icons/history.icon
new file mode 100644
index 00000000000..3fca2265707
--- /dev/null
+++ b/chromium/components/vector_icons/history.icon
@@ -0,0 +1,43 @@
+// Copyright 2021 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.
+
+CANVAS_DIMENSIONS, 20,
+MOVE_TO, 10.81f, 17.5f,
+R_QUADRATIC_TO, -1.44f, 0, -2.76f, -0.53f,
+R_QUADRATIC_TO, -1.32f, -0.53f, -2.41f, -1.64f,
+R_LINE_TO, 1.23f, -1.23f,
+R_QUADRATIC_TO, 0.81f, 0.79f, 1.87f, 1.22f,
+R_QUADRATIC_TO, 1.05f, 0.43f, 2.11f, 0.43f,
+R_QUADRATIC_TO, 2.4f, 0, 4.06f, -1.68f,
+R_QUADRATIC_TO, 1.67f, -1.68f, 1.67f, -4.07f,
+R_QUADRATIC_TO, 0, -2.4f, -1.67f, -4.07f,
+QUADRATIC_TO, 13.25f, 4.25f, 10.85f, 4.25f,
+R_QUADRATIC_TO, -2.37f, 0, -4.04f, 1.66f,
+R_QUADRATIC_TO, -1.67f, 1.66f, -1.67f, 4.28f,
+R_LINE_TO, 1.54f, -1.54f,
+R_LINE_TO, 1.21f, 1.21f,
+LINE_TO, 4.25f, 13.5f,
+LINE_TO, 0.63f, 9.88f,
+R_LINE_TO, 1.23f, -1.23f,
+R_LINE_TO, 1.54f, 1.54f,
+R_QUADRATIC_TO, 0, -1.63f, 0.58f, -3.03f,
+R_QUADRATIC_TO, 0.58f, -1.41f, 1.6f, -2.44f,
+R_QUADRATIC_TO, 1.02f, -1.03f, 2.38f, -1.62f,
+QUADRATIC_TO, 9.31f, 2.5f, 10.85f, 2.5f,
+R_QUADRATIC_TO, 1.54f, 0, 2.9f, 0.59f,
+R_QUADRATIC_TO, 1.35f, 0.59f, 2.38f, 1.63f,
+R_QUADRATIC_TO, 1.02f, 1.03f, 1.61f, 2.38f,
+R_QUADRATIC_TO, 0.59f, 1.35f, 0.59f, 2.9f,
+R_QUADRATIC_TO, 0, 1.52f, -0.6f, 2.89f,
+R_QUADRATIC_TO, -0.6f, 1.36f, -1.62f, 2.4f,
+R_QUADRATIC_TO, -1.02f, 1.04f, -2.39f, 1.63f,
+R_QUADRATIC_TO, -1.36f, 0.59f, -2.91f, 0.59f,
+CLOSE,
+R_MOVE_TO, 2.31f, -3.98f,
+R_LINE_TO, -3.15f, -3.19f,
+R_V_LINE_TO, -4.5f,
+R_H_LINE_TO, 1.75f,
+R_V_LINE_TO, 3.81f,
+R_LINE_TO, 2.63f, 2.65f,
+CLOSE
diff --git a/chromium/components/vector_icons/qr_code.icon b/chromium/components/vector_icons/qr_code.icon
new file mode 100644
index 00000000000..c6e990dd871
--- /dev/null
+++ b/chromium/components/vector_icons/qr_code.icon
@@ -0,0 +1,75 @@
+// Copyright 2022 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.
+
+CANVAS_DIMENSIONS, 20,
+MOVE_TO, 2.5f, 9.13f,
+V_LINE_TO, 2.5f,
+R_H_LINE_TO, 6.63f,
+R_V_LINE_TO, 6.63f,
+CLOSE,
+R_MOVE_TO, 1.75f, -1.75f,
+R_H_LINE_TO, 3.13f,
+V_LINE_TO, 4.25f,
+H_LINE_TO, 4.25f,
+CLOSE,
+MOVE_TO, 2.5f, 17.5f,
+R_V_LINE_TO, -6.62f,
+R_H_LINE_TO, 6.63f,
+V_LINE_TO, 17.5f,
+CLOSE,
+R_MOVE_TO, 1.75f, -1.75f,
+R_H_LINE_TO, 3.17f,
+R_V_LINE_TO, -3.12f,
+H_LINE_TO, 4.25f,
+CLOSE,
+R_MOVE_TO, 6.63f, -6.62f,
+V_LINE_TO, 2.5f,
+H_LINE_TO, 17.5f,
+R_V_LINE_TO, 6.63f,
+CLOSE,
+R_MOVE_TO, 1.75f, -1.75f,
+R_H_LINE_TO, 3.13f,
+V_LINE_TO, 4.25f,
+R_H_LINE_TO, -3.12f,
+CLOSE,
+MOVE_TO, 15.85f, 17.5f,
+R_V_LINE_TO, -1.67f,
+H_LINE_TO, 17.5f,
+V_LINE_TO, 17.5f,
+CLOSE,
+R_MOVE_TO, -4.98f, -4.98f,
+R_V_LINE_TO, -1.65f,
+R_H_LINE_TO, 1.67f,
+R_V_LINE_TO, 1.65f,
+CLOSE,
+R_MOVE_TO, 1.67f, 1.65f,
+R_V_LINE_TO, -1.65f,
+R_H_LINE_TO, 1.67f,
+R_V_LINE_TO, 1.65f,
+CLOSE,
+R_MOVE_TO, -1.67f, 1.67f,
+R_V_LINE_TO, -1.67f,
+R_H_LINE_TO, 1.67f,
+R_V_LINE_TO, 1.67f,
+CLOSE,
+R_MOVE_TO, 1.67f, 1.67f,
+R_V_LINE_TO, -1.67f,
+R_H_LINE_TO, 1.67f,
+V_LINE_TO, 17.5f,
+CLOSE,
+R_MOVE_TO, 1.67f, -1.67f,
+R_V_LINE_TO, -1.67f,
+R_H_LINE_TO, 1.65f,
+R_V_LINE_TO, 1.67f,
+CLOSE,
+R_MOVE_TO, 0, -3.31f,
+R_V_LINE_TO, -1.65f,
+R_H_LINE_TO, 1.65f,
+R_V_LINE_TO, 1.65f,
+CLOSE,
+R_MOVE_TO, 1.65f, 1.65f,
+R_V_LINE_TO, -1.65f,
+H_LINE_TO, 17.5f,
+R_V_LINE_TO, 1.65f,
+CLOSE \ No newline at end of file
diff --git a/chromium/components/vector_icons/settings_outline.icon b/chromium/components/vector_icons/settings_outline.icon
new file mode 100644
index 00000000000..4123630d6f3
--- /dev/null
+++ b/chromium/components/vector_icons/settings_outline.icon
@@ -0,0 +1,91 @@
+// Copyright 2018 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.
+
+CANVAS_DIMENSIONS, 20,
+MOVE_TO, 11.48f, 18,
+H_LINE_TO, 8.52f,
+R_CUBIC_TO, -0.59f, 0, -1.09f, -0.42f, -1.16f, -0.99f,
+R_LINE_TO, -0.22f, -1.48f,
+R_CUBIC_TO, -0.22f, -0.11f, -0.42f, -0.23f, -0.63f, -0.36f,
+R_LINE_TO, -1.44f, 0.56f,
+R_CUBIC_TO, -0.56f, 0.2f, -1.18f, -0.02f, -1.45f, -0.51f,
+R_LINE_TO, -1.46f, -2.48f,
+R_CUBIC_TO, -0.28f, -0.52f, -0.16f, -1.12f, 0.29f, -1.47f,
+R_LINE_TO, 1.22f, -0.93f,
+R_CUBIC_TO, -0.01f, -0.12f, -0.02f, -0.23f, -0.02f, -0.36f,
+R_CUBIC_TO, 0, -0.12f, 0.01f, -0.24f, 0.02f, -0.36f,
+R_LINE_TO, -1.22f, -0.93f,
+R_CUBIC_TO, -0.47f, -0.35f, -0.59f, -0.98f, -0.3f, -1.47f,
+R_LINE_TO, 1.48f, -2.49f,
+R_CUBIC_TO, 0.27f, -0.48f, 0.89f, -0.7f, 1.43f, -0.49f,
+R_LINE_TO, 1.45f, 0.57f,
+R_CUBIC_TO, 0.21f, -0.13f, 0.42f, -0.25f, 0.62f, -0.36f,
+R_LINE_TO, 0.22f, -1.49f,
+CUBIC_TO, 7.43f, 2.43f, 7.93f, 2, 8.51f, 2,
+R_H_LINE_TO, 2.96f,
+R_CUBIC_TO, 0.59f, 0, 1.09f, 0.42f, 1.16f, 0.99f,
+R_LINE_TO, 0.22f, 1.48f,
+R_CUBIC_TO, 0.22f, 0.11f, 0.42f, 0.23f, 0.63f, 0.36f,
+R_LINE_TO, 1.44f, -0.56f,
+R_CUBIC_TO, 0.57f, -0.2f, 1.18f, 0.02f, 1.46f, 0.51f,
+R_LINE_TO, 1.47f, 2.48f,
+R_CUBIC_TO, 0.29f, 0.52f, 0.16f, 1.12f, -0.29f, 1.47f,
+R_LINE_TO, -1.22f, 0.93f,
+R_CUBIC_TO, 0.01f, 0.12f, 0.02f, 0.23f, 0.02f, 0.36f,
+R_CUBIC_TO, 0, 0.12f, -0.01f, 0.24f, -0.02f, 0.36f,
+R_LINE_TO, 1.22f, 0.93f,
+R_CUBIC_TO, 0.45f, 0.35f, 0.58f, 0.96f, 0.3f, 1.45f,
+R_LINE_TO, -1.49f, 2.51f,
+R_CUBIC_TO, -0.27f, 0.48f, -0.89f, 0.7f, -1.44f, 0.49f,
+R_LINE_TO, -1.44f, -0.56f,
+R_CUBIC_TO, -0.21f, 0.13f, -0.42f, 0.25f, -0.62f, 0.36f,
+R_LINE_TO, -0.22f, 1.49f,
+CUBIC_TO, 12.57f, 17.58f, 12.07f, 18, 11.48f, 18,
+CLOSE,
+R_MOVE_TO, -2.53f, -2,
+R_H_LINE_TO, 2.11f,
+R_LINE_TO, 0.28f, -1.85f,
+R_LINE_TO, 0.41f, -0.16f,
+R_CUBIC_TO, 0.34f, -0.13f, 0.67f, -0.32f, 1.03f, -0.57f,
+R_LINE_TO, 0.34f, -0.25f,
+R_LINE_TO, 1.82f, 0.7f,
+LINE_TO, 16, 12.12f,
+R_LINE_TO, -1.55f, -1.15f,
+R_LINE_TO, 0.05f, -0.41f,
+R_CUBIC_TO, 0.02f, -0.19f, 0.05f, -0.37f, 0.05f, -0.57f,
+R_CUBIC_TO, 0, -0.2f, -0.02f, -0.39f, -0.05f, -0.57f,
+R_LINE_TO, -0.05f, -0.41f,
+LINE_TO, 16, 7.88f,
+R_LINE_TO, -1.06f, -1.75f,
+R_LINE_TO, -1.83f, 0.7f,
+R_LINE_TO, -0.34f, -0.25f,
+R_CUBIC_TO, -0.32f, -0.23f, -0.67f, -0.42f, -1.02f, -0.56f,
+R_LINE_TO, -0.4f, -0.16f,
+LINE_TO, 11.06f, 4,
+H_LINE_TO, 8.95f,
+R_LINE_TO, -0.28f, 1.85f,
+R_LINE_TO, -0.41f, 0.15f,
+R_CUBIC_TO, -0.34f, 0.14f, -0.67f, 0.32f, -1.03f, 0.57f,
+R_LINE_TO, -0.34f, 0.24f,
+R_LINE_TO, -1.82f, -0.69f,
+LINE_TO, 4, 7.87f,
+R_LINE_TO, 1.55f, 1.15f,
+R_LINE_TO, -0.05f, 0.41f,
+R_CUBIC_TO, -0.02f, 0.19f, -0.05f, 0.39f, -0.05f, 0.57f,
+R_CUBIC_TO, 0, 0.19f, 0.02f, 0.39f, 0.05f, 0.57f,
+R_LINE_TO, 0.05f, 0.41f,
+LINE_TO, 4, 12.12f,
+R_LINE_TO, 1.06f, 1.75f,
+R_LINE_TO, 1.83f, -0.7f,
+R_LINE_TO, 0.34f, 0.25f,
+R_CUBIC_TO, 0.33f, 0.24f, 0.66f, 0.42f, 1.02f, 0.56f,
+R_LINE_TO, 0.41f, 0.16f,
+LINE_TO, 8.95f, 16,
+CLOSE,
+MOVE_TO, 10, 12.5f,
+R_CUBIC_TO, 1.38f, 0, 2.5f, -1.12f, 2.5f, -2.5f,
+R_CUBIC_TO, 0, -1.38f, -1.12f, -2.5f, -2.5f, -2.5f,
+R_CUBIC_TO, -1.38f, 0, -2.5f, 1.12f, -2.5f, 2.5f,
+R_CUBIC_TO, 0, 1.38f, 1.12f, 2.5f, 2.5f, 2.5f,
+CLOSE
diff --git a/chromium/components/vector_icons/videogame_asset_outline.icon b/chromium/components/vector_icons/videogame_asset_outline.icon
new file mode 100644
index 00000000000..417ed6dabe3
--- /dev/null
+++ b/chromium/components/vector_icons/videogame_asset_outline.icon
@@ -0,0 +1,63 @@
+// Copyright 2022 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.
+
+CANVAS_DIMENSIONS, 24,
+MOVE_TO, 4, 18,
+CUBIC_TO, 3.45f, 18, 2.98f, 17.8f, 2.59f, 17.41f,
+CUBIC_TO, 2.2f, 17.02f, 2, 16.55f, 2, 16,
+V_LINE_TO, 8,
+CUBIC_TO, 2, 7.45f, 2.2f, 6.98f, 2.59f, 6.59f,
+CUBIC_TO, 2.98f, 6.2f, 3.45f, 6, 4, 6,
+H_LINE_TO, 20,
+CUBIC_TO, 20.55f, 6, 21.02f, 6.2f, 21.41f, 6.59f,
+CUBIC_TO, 21.8f, 6.98f, 22, 7.45f, 22, 8,
+V_LINE_TO, 16,
+CUBIC_TO, 22, 16.55f, 21.8f, 17.02f, 21.41f, 17.41f,
+CUBIC_TO, 21.02f, 17.8f, 20.55f, 18, 20, 18,
+H_LINE_TO, 4,
+CLOSE,
+MOVE_TO, 4, 16,
+H_LINE_TO, 20,
+V_LINE_TO, 8,
+H_LINE_TO, 4,
+V_LINE_TO, 16,
+CLOSE,
+MOVE_TO, 7, 15,
+H_LINE_TO, 9,
+V_LINE_TO, 13,
+H_LINE_TO, 11,
+V_LINE_TO, 11,
+H_LINE_TO, 9,
+V_LINE_TO, 9,
+H_LINE_TO, 7,
+V_LINE_TO, 11,
+H_LINE_TO, 5,
+V_LINE_TO, 13,
+H_LINE_TO, 7,
+V_LINE_TO, 15,
+CLOSE,
+MOVE_TO, 14.5f, 15,
+CUBIC_TO, 14.92f, 15, 15.27f, 14.85f, 15.56f, 14.56f,
+CUBIC_TO, 15.85f, 14.27f, 16, 13.92f, 16, 13.5f,
+CUBIC_TO, 16, 13.08f, 15.85f, 12.73f, 15.56f, 12.44f,
+CUBIC_TO, 15.27f, 12.15f, 14.92f, 12, 14.5f, 12,
+CUBIC_TO, 14.08f, 12, 13.73f, 12.15f, 13.44f, 12.44f,
+CUBIC_TO, 13.15f, 12.73f, 13, 13.08f, 13, 13.5f,
+CUBIC_TO, 13, 13.92f, 13.15f, 14.27f, 13.44f, 14.56f,
+CUBIC_TO, 13.73f, 14.85f, 14.08f, 15, 14.5f, 15,
+CLOSE,
+MOVE_TO, 17.5f, 12,
+CUBIC_TO, 17.92f, 12, 18.27f, 11.85f, 18.56f, 11.56f,
+CUBIC_TO, 18.85f, 11.27f, 19, 10.92f, 19, 10.5f,
+CUBIC_TO, 19, 10.08f, 18.85f, 9.73f, 18.56f, 9.44f,
+CUBIC_TO, 18.27f, 9.15f, 17.92f, 9, 17.5f, 9,
+CUBIC_TO, 17.08f, 9, 16.73f, 9.15f, 16.44f, 9.44f,
+CUBIC_TO, 16.15f, 9.73f, 16, 10.08f, 16, 10.5f,
+CUBIC_TO, 16, 10.92f, 16.15f, 11.27f, 16.44f, 11.56f,
+CUBIC_TO, 16.73f, 11.85f, 17.08f, 12, 17.5f, 12,
+CLOSE,
+MOVE_TO, 4, 16,
+V_LINE_TO, 8,
+V_LINE_TO, 16,
+CLOSE
diff --git a/chromium/components/vector_icons/warning_outline.icon b/chromium/components/vector_icons/warning_outline.icon
new file mode 100644
index 00000000000..8cf07515634
--- /dev/null
+++ b/chromium/components/vector_icons/warning_outline.icon
@@ -0,0 +1,30 @@
+// Copyright 2022 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.
+
+CANVAS_DIMENSIONS, 20,
+MOVE_TO, 9.13f, 2.5f,
+CUBIC_TO, 9.52f, 1.83f, 10.48f, 1.83f, 10.87f, 2.5f,
+LINE_TO, 18.87f, 16.5f,
+CUBIC_TO, 19.25f, 17.17f, 18.77f, 18, 18, 18,
+H_LINE_TO, 2,
+CUBIC_TO, 1.23f, 18, 0.75f, 17.17f, 1.13f, 16.5f,
+LINE_TO, 9.13f, 2.5f,
+CLOSE,
+MOVE_TO, 10, 5.02f,
+LINE_TO, 3.72f, 16,
+H_LINE_TO, 16.28f,
+LINE_TO, 10, 5.02f,
+CLOSE,
+MOVE_TO, 11, 12,
+V_LINE_TO, 8,
+H_LINE_TO, 9,
+V_LINE_TO, 12,
+H_LINE_TO, 11,
+CLOSE,
+MOVE_TO, 11, 13,
+V_LINE_TO, 15,
+H_LINE_TO, 9,
+V_LINE_TO, 13,
+H_LINE_TO, 11,
+CLOSE
diff --git a/chromium/components/version_info/android/BUILD.gn b/chromium/components/version_info/android/BUILD.gn
index 469841848ec..b83d435fb8e 100644
--- a/chromium/components/version_info/android/BUILD.gn
+++ b/chromium/components/version_info/android/BUILD.gn
@@ -13,6 +13,7 @@ _version_constants_java_file = "$target_gen_dir/java/org/chromium/components/ver
android_library("version_constants_java") {
sources = [
"java/src/org/chromium/components/version_info/VersionConstantsBridge.java",
+ "java/src/org/chromium/components/version_info/VersionInfo.java",
_version_constants_java_file,
]
deps = [
diff --git a/chromium/components/version_info/version_info.cc b/chromium/components/version_info/version_info.cc
index 55c7c035b0f..71c9f65d145 100644
--- a/chromium/components/version_info/version_info.cc
+++ b/chromium/components/version_info/version_info.cc
@@ -54,11 +54,11 @@ bool IsOfficialBuild() {
}
std::string GetOSType() {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
return "Windows";
-#elif defined(OS_IOS)
+#elif BUILDFLAG(IS_IOS)
return "iOS";
-#elif defined(OS_MAC)
+#elif BUILDFLAG(IS_MAC)
return "Mac OS X";
#elif BUILDFLAG(IS_CHROMEOS_ASH)
# if BUILDFLAG(GOOGLE_CHROME_BRANDING)
@@ -66,17 +66,17 @@ std::string GetOSType() {
# else
return "Chromium OS";
# endif
-#elif defined(OS_ANDROID)
+#elif BUILDFLAG(IS_ANDROID)
return "Android";
-#elif defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
+#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
return "Linux";
-#elif defined(OS_FREEBSD)
+#elif BUILDFLAG(IS_FREEBSD)
return "FreeBSD";
-#elif defined(OS_OPENBSD)
+#elif BUILDFLAG(IS_OPENBSD)
return "OpenBSD";
-#elif defined(OS_SOLARIS)
+#elif BUILDFLAG(IS_SOLARIS)
return "Solaris";
-#elif defined(OS_FUCHSIA)
+#elif BUILDFLAG(IS_FUCHSIA)
return "Fuchsia";
#else
return "Unknown";
diff --git a/chromium/components/version_ui/resources/about_version.js b/chromium/components/version_ui/resources/about_version.js
index f986650c29c..71bf0e20ccf 100644
--- a/chromium/components/version_ui/resources/about_version.js
+++ b/chromium/components/version_ui/resources/about_version.js
@@ -82,7 +82,7 @@ function returnCustomizationId(response) {
}
// </if>
-// <if expr="chromeos or lacros">
+// <if expr="chromeos_ash or chromeos_lacros">
/**
* Callback from the backend to inform if Lacros is primary or not.
* @param {string} isPrimary True if it is primary.
@@ -118,7 +118,7 @@ function onLoadWork() {
addWebUIListener('return-os-firmware-version', returnOsFirmwareVersion);
addWebUIListener('return-arc-version', returnARCVersion);
// </if>
- // <if expr="chromeos or lacros">
+ // <if expr="chromeos_ash or chromeos_lacros">
addWebUIListener('return-lacros-primary', returnLacrosPrimary);
// </if>
diff --git a/chromium/components/version_ui/version_ui_constants.cc b/chromium/components/version_ui/version_ui_constants.cc
index ca4d14528db..8c1aa75a756 100644
--- a/chromium/components/version_ui/version_ui_constants.cc
+++ b/chromium/components/version_ui/version_ui_constants.cc
@@ -4,13 +4,14 @@
#include "components/version_ui/version_ui_constants.h"
+#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
namespace version_ui {
// Resource paths.
const char kAboutVersionCSS[] = "about_version.css";
-#if defined(OS_IOS) || defined(OS_ANDROID)
+#if BUILDFLAG(IS_IOS) || BUILDFLAG(IS_ANDROID)
const char kAboutVersionMobileCSS[] = "about_version_mobile.css";
#endif
const char kVersionJS[] = "about_version.js";
@@ -35,21 +36,21 @@ const char kCL[] = "cl";
const char kCommandLine[] = "command_line";
const char kCommandLineName[] = "command_line_name";
const char kCompany[] = "company";
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
const char kUpdateCohortName[] = "update_cohort_name";
#endif
const char kCopyright[] = "copyright";
#if BUILDFLAG(IS_CHROMEOS_ASH)
const char kCustomizationId[] = "customization_id";
#endif
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
const char kExecutablePath[] = "executable_path";
const char kExecutablePathName[] = "executable_path_name";
#endif
#if BUILDFLAG(IS_CHROMEOS_ASH)
const char kFirmwareVersion[] = "firmware_version";
#endif
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
const char kJSEngine[] = "js_engine";
const char kJSVersion[] = "js_version";
#endif
@@ -59,7 +60,7 @@ const char kOfficial[] = "official";
const char kOSName[] = "os_name";
const char kOSType[] = "os_type";
#endif
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
const char kOSVersion[] = "os_version";
const char kGmsName[] = "gms_name";
const char kGmsVersion[] = "gms_version";
@@ -67,11 +68,11 @@ const char kGmsVersion[] = "gms_version";
#if BUILDFLAG(IS_CHROMEOS_ASH)
const char kPlatform[] = "platform";
#endif
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
const char kProfilePath[] = "profile_path";
const char kProfilePathName[] = "profile_path_name";
#endif
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS)
const char kOsVersionHeaderText1[] = "os-version-text1";
const char kOsVersionHeaderText2[] = "os-version-text2";
const char kOsVersionHeaderLink[] = "os-version-link";
diff --git a/chromium/components/version_ui/version_ui_constants.h b/chromium/components/version_ui/version_ui_constants.h
index b981079a414..dbf02643edb 100644
--- a/chromium/components/version_ui/version_ui_constants.h
+++ b/chromium/components/version_ui/version_ui_constants.h
@@ -13,7 +13,7 @@ namespace version_ui {
// Resource paths.
// Must match the resource file names.
extern const char kAboutVersionCSS[];
-#if defined(OS_IOS) || defined(OS_ANDROID)
+#if BUILDFLAG(IS_IOS) || BUILDFLAG(IS_ANDROID)
extern const char kAboutVersionMobileCSS[];
#endif
extern const char kVersionJS[];
@@ -39,21 +39,21 @@ extern const char kCL[];
extern const char kCommandLine[];
extern const char kCommandLineName[];
extern const char kCompany[];
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
extern const char kUpdateCohortName[];
#endif
extern const char kCopyright[];
#if BUILDFLAG(IS_CHROMEOS_ASH)
extern const char kCustomizationId[];
#endif
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
extern const char kExecutablePath[];
extern const char kExecutablePathName[];
#endif
#if BUILDFLAG(IS_CHROMEOS_ASH)
extern const char kFirmwareVersion[];
#endif
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
extern const char kJSEngine[];
extern const char kJSVersion[];
#endif
@@ -63,7 +63,7 @@ extern const char kOfficial[];
extern const char kOSName[];
extern const char kOSType[];
#endif
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
extern const char kOSVersion[];
extern const char kGmsName[];
extern const char kGmsVersion[];
@@ -71,11 +71,11 @@ extern const char kGmsVersion[];
#if BUILDFLAG(IS_CHROMEOS_ASH)
extern const char kPlatform[];
#endif
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
extern const char kProfilePath[];
extern const char kProfilePathName[];
#endif
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS)
extern const char kOsVersionHeaderText1[];
extern const char kOsVersionHeaderText2[];
extern const char kOsVersionHeaderLink[];
diff --git a/chromium/components/visitedlink/browser/visitedlink_writer.cc b/chromium/components/visitedlink/browser/visitedlink_writer.cc
index 940c61620f1..8e18dd63514 100644
--- a/chromium/components/visitedlink/browser/visitedlink_writer.cc
+++ b/chromium/components/visitedlink/browser/visitedlink_writer.cc
@@ -31,11 +31,11 @@
#include "content/public/browser/browser_thread.h"
#include "url/gurl.h"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include <io.h>
#include <shlobj.h>
#include <windows.h>
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
using content::BrowserThread;
diff --git a/chromium/components/visitedlink/browser/visitedlink_writer.h b/chromium/components/visitedlink/browser/visitedlink_writer.h
index 22a1ded31ba..d11885087ee 100644
--- a/chromium/components/visitedlink/browser/visitedlink_writer.h
+++ b/chromium/components/visitedlink/browser/visitedlink_writer.h
@@ -27,7 +27,7 @@
#include "build/build_config.h"
#include "components/visitedlink/common/visitedlink_common.h"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include <windows.h>
#endif
diff --git a/chromium/components/viz/BUILD.gn b/chromium/components/viz/BUILD.gn
index ab595a7dc90..db7f49872ec 100644
--- a/chromium/components/viz/BUILD.gn
+++ b/chromium/components/viz/BUILD.gn
@@ -41,6 +41,7 @@ viz_test("viz_unittests") {
}
if (is_fuchsia) {
+ use_cfv2 = false
additional_manifest_fragments = [
# TODO(crbug.com/1185811): Figure out why jit_capabilities is needed.
"//build/config/fuchsia/test/jit_capabilities.test-cmx",
diff --git a/chromium/components/viz/client/client_resource_provider.cc b/chromium/components/viz/client/client_resource_provider.cc
index f7b711be351..3293cd0103f 100644
--- a/chromium/components/viz/client/client_resource_provider.cc
+++ b/chromium/components/viz/client/client_resource_provider.cc
@@ -358,6 +358,7 @@ void ClientResourceProvider::ShutdownAndReleaseAllResources() {
ClientResourceProvider::ScopedSkSurface::ScopedSkSurface(
GrDirectContext* gr_context,
+ const gpu::Capabilities& capabilities,
sk_sp<SkColorSpace> color_space,
GLuint texture_id,
GLenum texture_target,
@@ -368,7 +369,8 @@ ClientResourceProvider::ScopedSkSurface::ScopedSkSurface(
GrGLTextureInfo texture_info;
texture_info.fID = texture_id;
texture_info.fTarget = texture_target;
- texture_info.fFormat = TextureStorageFormat(format);
+ texture_info.fFormat =
+ TextureStorageFormat(format, capabilities.angle_rgbx_internal_format);
GrBackendTexture backend_texture(size.width(), size.height(),
GrMipMapped::kNo, texture_info);
// This type is used only for gpu raster, which implies gpu compositing.
diff --git a/chromium/components/viz/client/client_resource_provider.h b/chromium/components/viz/client/client_resource_provider.h
index f1e2aa3b892..34b670ff735 100644
--- a/chromium/components/viz/client/client_resource_provider.h
+++ b/chromium/components/viz/client/client_resource_provider.h
@@ -21,6 +21,7 @@
#include "third_party/skia/include/core/SkSurface.h"
namespace gpu {
+struct Capabilities;
namespace gles2 {
class GLES2Interface;
}
@@ -115,6 +116,7 @@ class VIZ_CLIENT_EXPORT ClientResourceProvider {
class VIZ_CLIENT_EXPORT ScopedSkSurface {
public:
ScopedSkSurface(GrDirectContext* gr_context,
+ const gpu::Capabilities& capabilities,
sk_sp<SkColorSpace> color_space,
GLuint texture_id,
GLenum texture_target,
diff --git a/chromium/components/viz/client/frame_eviction_manager.cc b/chromium/components/viz/client/frame_eviction_manager.cc
index f0b997b218c..fde8480ddbd 100644
--- a/chromium/components/viz/client/frame_eviction_manager.cc
+++ b/chromium/components/viz/client/frame_eviction_manager.cc
@@ -107,7 +107,7 @@ FrameEvictionManager::FrameEvictionManager()
base::BindRepeating(&FrameEvictionManager::OnMemoryPressure,
base::Unretained(this)))) {
max_number_of_saved_frames_ =
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// If the amount of memory on the device is >= 3.5 GB, save up to 5
// frames.
base::SysInfo::AmountOfPhysicalMemoryMB() < 1024 * 3.5f ? 1 : 5;
diff --git a/chromium/components/viz/common/BUILD.gn b/chromium/components/viz/common/BUILD.gn
index 45bc8029c53..7abb58d2112 100644
--- a/chromium/components/viz/common/BUILD.gn
+++ b/chromium/components/viz/common/BUILD.gn
@@ -38,10 +38,11 @@ viz_component("resource_format_utils") {
deps = [
"//base",
+ "//build:chromeos_buildflags",
"//cc/base:base",
"//gpu/vulkan:buildflags",
"//skia",
- "//third_party/dawn/src/dawn:dawncpp_headers",
+ "//third_party/dawn/include/dawn:cpp_headers",
"//ui/gfx:buffer_types",
"//ui/gfx/geometry:geometry",
]
@@ -133,14 +134,14 @@ if (skia_use_dawn) {
public_deps = [
"//skia",
- "//third_party/dawn/src/dawn:dawn_headers",
+ "//third_party/dawn/include/dawn:headers",
]
deps = [
"//base",
- "//third_party/dawn/src/dawn:dawn_proc",
- "//third_party/dawn/src/dawn:dawncpp",
- "//third_party/dawn/src/dawn_native",
+ "//third_party/dawn/src/dawn:cpp",
+ "//third_party/dawn/src/dawn:proc",
+ "//third_party/dawn/src/dawn/native",
]
}
}
diff --git a/chromium/components/viz/common/display/de_jelly.cc b/chromium/components/viz/common/display/de_jelly.cc
index 35126113986..8beb1493597 100644
--- a/chromium/components/viz/common/display/de_jelly.cc
+++ b/chromium/components/viz/common/display/de_jelly.cc
@@ -9,7 +9,7 @@
#include "components/viz/common/features.h"
#include "components/viz/common/switches.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
#include "base/time/time.h"
@@ -30,7 +30,7 @@ bool DeJellyActive() {
if (!DeJellyEnabled())
return false;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
return Java_DeJellyUtils_useDeJelly(base::android::AttachCurrentThread());
#else
return true;
@@ -44,7 +44,7 @@ float DeJellyScreenWidth() {
if (!value.empty())
return std::atoi(value.c_str());
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
return Java_DeJellyUtils_screenWidth(base::android::AttachCurrentThread());
#else
return 1440.0f;
diff --git a/chromium/components/viz/common/display/renderer_settings.h b/chromium/components/viz/common/display/renderer_settings.h
index e58b4023652..d8e2bd1e55a 100644
--- a/chromium/components/viz/common/display/renderer_settings.h
+++ b/chromium/components/viz/common/display/renderer_settings.h
@@ -31,7 +31,6 @@ class VIZ_COMMON_EXPORT RendererSettings {
bool should_clear_root_render_pass = true;
bool release_overlay_resources_after_gpu_query = false;
bool use_skia_renderer = false;
- bool allow_overlays = true;
bool dont_round_texture_sizes_for_pixel_tests = false;
int highp_threshold_min = 0;
bool auto_resize_output_surface = true;
@@ -51,7 +50,7 @@ class VIZ_COMMON_EXPORT RendererSettings {
// split into multiple quads during occlusion culling.
int minimum_fragments_reduced = 128 * 128;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// The screen size at renderer creation time.
gfx::Size initial_screen_size = gfx::Size(0, 0);
diff --git a/chromium/components/viz/common/features.cc b/chromium/components/viz/common/features.cc
index c23d8b7337b..f9334876646 100644
--- a/chromium/components/viz/common/features.cc
+++ b/chromium/components/viz/common/features.cc
@@ -10,6 +10,7 @@
#include "base/feature_list.h"
#include "base/metrics/field_trial_params.h"
#include "base/system/sys_info.h"
+#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "components/viz/common/delegated_ink_prediction_configuration.h"
#include "components/viz/common/switches.h"
@@ -18,7 +19,7 @@
#include "gpu/config/gpu_switches.h"
#include "media/media_buildflags.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "base/android/build_info.h"
#endif
@@ -48,17 +49,25 @@ const base::Feature kEnableOverlayPrioritization {
#endif
};
+const base::Feature kUseMultipleOverlays{"UseMultipleOverlays",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+const char kMaxOverlaysParam[] = "max_overlays";
+
const base::Feature kDelegatedCompositing{"DelegatedCompositing",
base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kVideoDetectorIgnoreNonVideos{
+ "VideoDetectorIgnoreNonVideos", base::FEATURE_ENABLED_BY_DEFAULT};
+
const base::Feature kSimpleFrameRateThrottling{
"SimpleFrameRateThrottling", base::FEATURE_DISABLED_BY_DEFAULT};
// Use the SkiaRenderer.
const base::Feature kUseSkiaRenderer {
"UseSkiaRenderer",
-#if defined(OS_WIN) || defined(OS_ANDROID) || BUILDFLAG(IS_CHROMEOS_LACROS) || \
- defined(OS_LINUX) || defined(OS_FUCHSIA) || defined(OS_MAC)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_ANDROID) || \
+ BUILDFLAG(IS_CHROMEOS_LACROS) || BUILDFLAG(IS_LINUX) || \
+ BUILDFLAG(IS_FUCHSIA) || BUILDFLAG(IS_MAC)
base::FEATURE_ENABLED_BY_DEFAULT
#else
base::FEATURE_DISABLED_BY_DEFAULT
@@ -76,7 +85,7 @@ const base::Feature kDisableDeJelly{"DisableDeJelly",
const base::Feature kDynamicBufferQueueAllocation{
"DynamicBufferQueueAllocation", base::FEATURE_DISABLED_BY_DEFAULT};
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// When wide color gamut content from the web is encountered, promote our
// display to wide color gamut if supported.
const base::Feature kDynamicColorGamut{"DynamicColorGamut",
@@ -94,7 +103,7 @@ const base::Feature kVizFrameSubmissionForWebView{
const base::Feature kUsePreferredIntervalForVideo{
"UsePreferredIntervalForVideo",
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
base::FEATURE_DISABLED_BY_DEFAULT
#else
base::FEATURE_ENABLED_BY_DEFAULT
@@ -106,7 +115,7 @@ const base::Feature kUsePreferredIntervalForVideo{
const base::Feature kUseRealBuffersForPageFlipTest{
"UseRealBuffersForPageFlipTest", base::FEATURE_ENABLED_BY_DEFAULT};
-#if defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_FUCHSIA)
// Enables SkiaOutputDeviceBufferQueue instead of Vulkan swapchain on Fuchsia.
const base::Feature kUseSkiaOutputDeviceBufferQueue{
"UseSkiaOutputDeviceBufferQueue", base::FEATURE_ENABLED_BY_DEFAULT};
@@ -116,12 +125,12 @@ const base::Feature kUseSkiaOutputDeviceBufferQueue{
const base::Feature kWebRtcLogCapturePipeline{
"WebRtcLogCapturePipeline", base::FEATURE_DISABLED_BY_DEFAULT};
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// Enables swap chains to call SetPresentDuration to request DWM/OS to reduce
// vsync.
const base::Feature kUseSetPresentDuration{"UseSetPresentDuration",
base::FEATURE_DISABLED_BY_DEFAULT};
-#endif // OS_WIN
+#endif // BUILDFLAG(IS_WIN)
// Enables platform supported delegated ink trails instead of Skia backed
// delegated ink trails.
@@ -133,7 +142,7 @@ const base::Feature kUsePlatformDelegatedInk{"UsePlatformDelegatedInk",
const base::Feature kWebViewVulkanIntermediateBuffer{
"WebViewVulkanIntermediateBuffer", base::FEATURE_DISABLED_BY_DEFAULT};
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Hardcoded as disabled for WebView to have a different default for
// UseSurfaceLayerForVideo from chrome.
const base::Feature kUseSurfaceLayerForVideoDefault{
@@ -150,7 +159,7 @@ const base::Feature kUseRealVideoColorSpaceForDisplay{
// Browser to batch SurfaceSync calls sent to the Renderer for properties can
// change in close proximity to each other.
const base::Feature kSurfaceSyncThrottling{"SurfaceSyncThrottling",
- base::FEATURE_DISABLED_BY_DEFAULT};
+ base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kDrawPredictedInkPoint{"DrawPredictedInkPoint",
base::FEATURE_DISABLED_BY_DEFAULT};
@@ -171,7 +180,7 @@ const base::Feature kDynamicSchedulerForDraw{"DynamicSchedulerForDraw",
const base::Feature kDynamicSchedulerForClients{
"DynamicSchedulerForClients", base::FEATURE_DISABLED_BY_DEFAULT};
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
const base::Feature kMacCAOverlayQuad{"MacCAOverlayQuads",
base::FEATURE_DISABLED_BY_DEFAULT};
// The maximum supported overlay quad number on Mac CALayerOverlay.
@@ -215,7 +224,7 @@ bool IsSimpleFrameRateThrottlingEnabled() {
}
bool IsUsingSkiaRenderer() {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// We don't support KitKat. Check for it before looking at the feature flag
// so that KitKat doesn't show up in Control or Enabled experiment group.
if (base::android::BuildInfo::GetInstance()->sdk_int() <=
@@ -236,7 +245,7 @@ bool IsUsingSkiaRenderer() {
features::IsUsingVulkan();
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
bool IsDynamicColorGamutEnabled() {
if (viz::AlwaysUseWideColorGamut())
return false;
@@ -259,11 +268,6 @@ bool IsUsingPreferredIntervalForVideo() {
return base::FeatureList::IsEnabled(kUsePreferredIntervalForVideo);
}
-bool IsVizHitTestingDebugEnabled() {
- return base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableVizHitTestDebug);
-}
-
bool ShouldUseRealBuffersForPageFlipTest() {
return base::FeatureList::IsEnabled(kUseRealBuffersForPageFlipTest);
}
@@ -272,11 +276,11 @@ bool ShouldWebRtcLogCapturePipeline() {
return base::FeatureList::IsEnabled(kWebRtcLogCapturePipeline);
}
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
bool ShouldUseSetPresentDuration() {
return base::FeatureList::IsEnabled(kUseSetPresentDuration);
}
-#endif // OS_WIN
+#endif // BUILDFLAG(IS_WIN)
absl::optional<int> ShouldDrawPredictedInkPoints() {
if (!base::FeatureList::IsEnabled(kDrawPredictedInkPoint))
@@ -308,7 +312,7 @@ bool ShouldUsePlatformDelegatedInk() {
return base::FeatureList::IsEnabled(kUsePlatformDelegatedInk);
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
bool UseSurfaceLayerForVideo() {
// Allow enabling UseSurfaceLayerForVideo if webview is using surface control.
if (::features::IsAndroidSurfaceControlEnabled()) {
@@ -358,4 +362,21 @@ absl::optional<double> IsDynamicSchedulerEnabledForClients() {
return result;
}
+int MaxOverlaysConsidered() {
+ if (!IsOverlayPrioritizationEnabled()) {
+ return 1;
+ }
+
+ if (!base::FeatureList::IsEnabled(kUseMultipleOverlays)) {
+ return 1;
+ }
+
+ return base::GetFieldTrialParamByFeatureAsInt(kUseMultipleOverlays,
+ kMaxOverlaysParam, 2);
+}
+
+bool ShouldVideoDetectorIgnoreNonVideoFrames() {
+ return base::FeatureList::IsEnabled(kVideoDetectorIgnoreNonVideos);
+}
+
} // namespace features
diff --git a/chromium/components/viz/common/features.h b/chromium/components/viz/common/features.h
index ccee1a755bc..d31bf0209e3 100644
--- a/chromium/components/viz/common/features.h
+++ b/chromium/components/viz/common/features.h
@@ -23,9 +23,13 @@ VIZ_COMMON_EXPORT extern const base::Feature kAdpf;
VIZ_COMMON_EXPORT extern const base::FeatureParam<int> kAdpfTargetDurationMs;
VIZ_COMMON_EXPORT extern const base::Feature kEnableOverlayPrioritization;
VIZ_COMMON_EXPORT extern const base::Feature kUseSkiaRenderer;
+VIZ_COMMON_EXPORT extern const base::Feature kDelegatedCompositing;
VIZ_COMMON_EXPORT extern const base::Feature kRecordSkPicture;
VIZ_COMMON_EXPORT extern const base::Feature kDisableDeJelly;
-#if defined(OS_ANDROID)
+VIZ_COMMON_EXPORT extern const base::Feature kUseMultipleOverlays;
+VIZ_COMMON_EXPORT extern const char kMaxOverlaysParam[];
+VIZ_COMMON_EXPORT extern const base::Feature kVideoDetectorIgnoreNonVideos;
+#if BUILDFLAG(IS_ANDROID)
VIZ_COMMON_EXPORT extern const base::Feature kDynamicColorGamut;
#endif
VIZ_COMMON_EXPORT extern const base::Feature kDynamicBufferQueueAllocation;
@@ -33,22 +37,22 @@ VIZ_COMMON_EXPORT extern const base::Feature kFastSolidColorDraw;
VIZ_COMMON_EXPORT extern const base::Feature kVizFrameSubmissionForWebView;
VIZ_COMMON_EXPORT extern const base::Feature kUsePreferredIntervalForVideo;
VIZ_COMMON_EXPORT extern const base::Feature kUseRealBuffersForPageFlipTest;
-#if defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_FUCHSIA)
VIZ_COMMON_EXPORT extern const base::Feature kUseSkiaOutputDeviceBufferQueue;
#endif
VIZ_COMMON_EXPORT extern const base::Feature kWebRtcLogCapturePipeline;
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
VIZ_COMMON_EXPORT extern const base::Feature kUseSetPresentDuration;
-#endif // OS_WIN
+#endif // BUILDFLAG(IS_WIN)
VIZ_COMMON_EXPORT extern const base::Feature kWebViewVulkanIntermediateBuffer;
VIZ_COMMON_EXPORT extern const base::Feature kUsePlatformDelegatedInk;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
VIZ_COMMON_EXPORT extern const base::Feature kUseSurfaceLayerForVideoDefault;
#endif
VIZ_COMMON_EXPORT extern const base::Feature kSurfaceSyncThrottling;
VIZ_COMMON_EXPORT extern const base::Feature kDynamicSchedulerForDraw;
VIZ_COMMON_EXPORT extern const base::Feature kDynamicSchedulerForClients;
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
VIZ_COMMON_EXPORT extern const base::Feature kMacCAOverlayQuad;
VIZ_COMMON_EXPORT extern const base::FeatureParam<int> kMacCAOverlayQuadMaxNum;
#endif
@@ -67,7 +71,7 @@ VIZ_COMMON_EXPORT extern const char kPredictorLsq[];
VIZ_COMMON_EXPORT bool IsAdpfEnabled();
VIZ_COMMON_EXPORT bool IsClipPrewalkDamageEnabled();
VIZ_COMMON_EXPORT bool IsSimpleFrameRateThrottlingEnabled();
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
VIZ_COMMON_EXPORT bool IsDynamicColorGamutEnabled();
#endif
VIZ_COMMON_EXPORT bool IsOverlayPrioritizationEnabled();
@@ -77,22 +81,23 @@ VIZ_COMMON_EXPORT bool IsUsingFastPathForSolidColorQuad();
VIZ_COMMON_EXPORT bool IsUsingSkiaRenderer();
VIZ_COMMON_EXPORT bool IsUsingVizFrameSubmissionForWebView();
VIZ_COMMON_EXPORT bool IsUsingPreferredIntervalForVideo();
-VIZ_COMMON_EXPORT bool IsVizHitTestingDebugEnabled();
VIZ_COMMON_EXPORT bool ShouldUseRealBuffersForPageFlipTest();
VIZ_COMMON_EXPORT bool ShouldWebRtcLogCapturePipeline();
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
VIZ_COMMON_EXPORT bool ShouldUseSetPresentDuration();
-#endif // OS_WIN
+#endif // BUILDFLAG(IS_WIN)
VIZ_COMMON_EXPORT absl::optional<int> ShouldDrawPredictedInkPoints();
VIZ_COMMON_EXPORT std::string InkPredictor();
VIZ_COMMON_EXPORT bool ShouldUsePlatformDelegatedInk();
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
VIZ_COMMON_EXPORT bool UseSurfaceLayerForVideo();
VIZ_COMMON_EXPORT bool UseRealVideoColorSpaceForDisplay();
#endif
VIZ_COMMON_EXPORT bool IsSurfaceSyncThrottling();
VIZ_COMMON_EXPORT absl::optional<double> IsDynamicSchedulerEnabledForDraw();
VIZ_COMMON_EXPORT absl::optional<double> IsDynamicSchedulerEnabledForClients();
+VIZ_COMMON_EXPORT int MaxOverlaysConsidered();
+VIZ_COMMON_EXPORT bool ShouldVideoDetectorIgnoreNonVideoFrames();
} // namespace features
diff --git a/chromium/components/viz/common/frame_sinks/begin_frame_source.h b/chromium/components/viz/common/frame_sinks/begin_frame_source.h
index 5e9a0bc3e19..3b3ca2b8a48 100644
--- a/chromium/components/viz/common/frame_sinks/begin_frame_source.h
+++ b/chromium/components/viz/common/frame_sinks/begin_frame_source.h
@@ -428,7 +428,7 @@ class VIZ_COMMON_EXPORT ExternalBeginFrameSource : public BeginFrameSource {
void OnSetBeginFrameSourcePaused(bool paused);
void OnBeginFrame(const BeginFrameArgs& args);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Notifies when the refresh rate of the display is updated. |refresh_rate| is
// the rate in frames per second.
virtual void UpdateRefreshRate(float refresh_rate) {}
diff --git a/chromium/components/viz/common/frame_sinks/delay_based_time_source.cc b/chromium/components/viz/common/frame_sinks/delay_based_time_source.cc
index 8ab8e648fa3..bd5960014a2 100644
--- a/chromium/components/viz/common/frame_sinks/delay_based_time_source.cc
+++ b/chromium/components/viz/common/frame_sinks/delay_based_time_source.cc
@@ -46,7 +46,7 @@ void DelayBasedTimeSource::SetActive(bool active) {
if (active_) {
PostNextTickTask(Now());
} else {
- timer_.AbandonAndStop();
+ timer_.Stop();
last_tick_time_ = base::TimeTicks();
next_tick_time_ = base::TimeTicks();
}
@@ -157,7 +157,8 @@ void DelayBasedTimeSource::PostNextTickTask(base::TimeTicks now) {
next_tick_time_ += interval_;
DCHECK_GT(next_tick_time_, now);
}
- timer_.Start(FROM_HERE, next_tick_time_ - now, tick_closure_);
+ timer_.Start(FROM_HERE, next_tick_time_, tick_closure_,
+ base::ExactDeadline(true));
}
std::string DelayBasedTimeSource::TypeString() const {
diff --git a/chromium/components/viz/common/frame_sinks/delay_based_time_source.h b/chromium/components/viz/common/frame_sinks/delay_based_time_source.h
index 00c817aac65..82fc20a0e77 100644
--- a/chromium/components/viz/common/frame_sinks/delay_based_time_source.h
+++ b/chromium/components/viz/common/frame_sinks/delay_based_time_source.h
@@ -82,7 +82,7 @@ class VIZ_COMMON_EXPORT DelayBasedTimeSource {
raw_ptr<base::SingleThreadTaskRunner> task_runner_;
base::RepeatingClosure tick_closure_;
- base::OneShotTimer timer_;
+ base::DeadlineTimer timer_;
};
} // namespace viz
diff --git a/chromium/components/viz/common/frame_sinks/delay_based_time_source_unittest.cc b/chromium/components/viz/common/frame_sinks/delay_based_time_source_unittest.cc
index c0e84dd1571..c4a1329d12c 100644
--- a/chromium/components/viz/common/frame_sinks/delay_based_time_source_unittest.cc
+++ b/chromium/components/viz/common/frame_sinks/delay_based_time_source_unittest.cc
@@ -7,7 +7,7 @@
#include <stdint.h>
#include "base/test/simple_test_tick_clock.h"
-#include "base/test/test_simple_task_runner.h"
+#include "base/test/test_mock_time_task_runner.h"
#include "components/viz/test/fake_delay_based_time_source.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -21,30 +21,25 @@ base::TimeDelta Interval() {
class DelayBasedTimeSourceTest : public ::testing::Test {
protected:
void SetUp() override {
- now_src_ = std::make_unique<base::SimpleTestTickClock>();
- task_runner_ = base::MakeRefCounted<base::TestSimpleTaskRunner>();
+ task_runner_ = base::MakeRefCounted<base::TestMockTimeTaskRunner>();
delay_based_time_source_ = std::make_unique<FakeDelayBasedTimeSource>(
- now_src_.get(), task_runner_.get());
+ task_runner_->GetMockTickClock(), task_runner_.get());
delay_based_time_source_->SetClient(&client_);
}
void TearDown() override {
delay_based_time_source_.reset();
task_runner_ = nullptr;
- now_src_.reset();
}
- void SetNow(base::TimeTicks ticks) { now_src_->SetNowTicks(ticks); }
-
- base::TestSimpleTaskRunner* task_runner() { return task_runner_.get(); }
+ base::TestMockTimeTaskRunner* task_runner() { return task_runner_.get(); }
FakeDelayBasedTimeSource* timer() { return delay_based_time_source_.get(); }
FakeDelayBasedTimeSourceClient* client() { return &client_; }
- std::unique_ptr<base::SimpleTestTickClock> now_src_;
FakeDelayBasedTimeSourceClient client_;
- scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
+ scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
std::unique_ptr<FakeDelayBasedTimeSource> delay_based_time_source_;
};
@@ -54,8 +49,8 @@ TEST_F(DelayBasedTimeSourceTest, TaskPostedAndTickCalled) {
EXPECT_TRUE(timer()->Active());
EXPECT_TRUE(task_runner()->HasPendingTask());
- SetNow(timer()->Now() + base::Milliseconds(16));
- task_runner()->RunPendingTasks();
+ task_runner()->AdvanceMockTickClock(Interval());
+ task_runner()->RunUntilIdle();
EXPECT_TRUE(timer()->Active());
EXPECT_TRUE(client()->TickCalled());
}
@@ -65,7 +60,7 @@ TEST_F(DelayBasedTimeSourceTest, TickNotCalledWithTaskPosted) {
timer()->SetActive(true);
EXPECT_TRUE(task_runner()->HasPendingTask());
timer()->SetActive(false);
- task_runner()->RunPendingTasks();
+ task_runner()->RunUntilIdle();
EXPECT_FALSE(client()->TickCalled());
}
@@ -82,7 +77,7 @@ TEST_F(DelayBasedTimeSourceTest, StartWhenRunningDoesntTick) {
timer()->SetTimebaseAndInterval(base::TimeTicks(), Interval());
timer()->SetActive(true);
EXPECT_TRUE(task_runner()->HasPendingTask());
- task_runner()->RunPendingTasks();
+ task_runner()->RunUntilIdle();
task_runner()->ClearPendingTasks();
timer()->SetActive(true);
EXPECT_FALSE(task_runner()->HasPendingTask());
@@ -94,12 +89,12 @@ TEST_F(DelayBasedTimeSourceTest, NextDelaySaneWhenExactlyOnRequestedTime) {
timer()->SetTimebaseAndInterval(base::TimeTicks(), Interval());
timer()->SetActive(true);
// Run the first tick.
- task_runner()->RunPendingTasks();
+ task_runner()->RunUntilIdle();
EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
- SetNow(timer()->Now() + Interval());
- task_runner()->RunPendingTasks();
+ task_runner()->AdvanceMockTickClock(Interval());
+ task_runner()->RunUntilIdle();
EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
}
@@ -110,12 +105,12 @@ TEST_F(DelayBasedTimeSourceTest, NextDelaySaneWhenSlightlyAfterRequestedTime) {
timer()->SetTimebaseAndInterval(base::TimeTicks(), Interval());
timer()->SetActive(true);
// Run the first tick.
- task_runner()->RunPendingTasks();
+ task_runner()->RunUntilIdle();
EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
- SetNow(timer()->Now() + Interval() + base::Microseconds(1));
- task_runner()->RunPendingTasks();
+ task_runner()->AdvanceMockTickClock(Interval() + base::Microseconds(1));
+ task_runner()->RunUntilIdle();
EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
}
@@ -127,12 +122,12 @@ TEST_F(DelayBasedTimeSourceTest,
timer()->SetTimebaseAndInterval(base::TimeTicks(), Interval());
timer()->SetActive(true);
// Run the first tick.
- task_runner()->RunPendingTasks();
+ task_runner()->RunUntilIdle();
EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
- SetNow(timer()->Now() + 2 * Interval());
- task_runner()->RunPendingTasks();
+ task_runner()->AdvanceMockTickClock(2 * Interval());
+ task_runner()->RunUntilIdle();
EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
}
@@ -144,12 +139,12 @@ TEST_F(DelayBasedTimeSourceTest,
timer()->SetTimebaseAndInterval(base::TimeTicks(), Interval());
timer()->SetActive(true);
// Run the first tick.
- task_runner()->RunPendingTasks();
+ task_runner()->RunUntilIdle();
EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
- SetNow(timer()->Now() + 2 * Interval() + base::Microseconds(1));
- task_runner()->RunPendingTasks();
+ task_runner()->AdvanceMockTickClock(2 * Interval() + base::Microseconds(1));
+ task_runner()->RunUntilIdle();
EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
}
@@ -160,12 +155,12 @@ TEST_F(DelayBasedTimeSourceTest, NextDelaySaneWhenHalfAfterRequestedTime) {
timer()->SetTimebaseAndInterval(base::TimeTicks(), Interval());
timer()->SetActive(true);
// Run the first tick.
- task_runner()->RunPendingTasks();
+ task_runner()->RunUntilIdle();
EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
- SetNow(timer()->Now() + Interval() + base::Milliseconds(8));
- task_runner()->RunPendingTasks();
+ task_runner()->AdvanceMockTickClock(Interval() + base::Milliseconds(8));
+ task_runner()->RunUntilIdle();
EXPECT_EQ(8, task_runner()->NextPendingTaskDelay().InMilliseconds());
}
@@ -175,7 +170,7 @@ TEST_F(DelayBasedTimeSourceTest, JitteryRuntimeWithFutureTimebases) {
timer()->SetActive(true);
// Run the first tick.
- task_runner()->RunPendingTasks();
+ task_runner()->RunUntilIdle();
EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
base::TimeTicks future_timebase = timer()->Now() + Interval() * 10;
@@ -186,29 +181,29 @@ TEST_F(DelayBasedTimeSourceTest, JitteryRuntimeWithFutureTimebases) {
// Tick with +1ms of jitter
future_timebase += Interval();
timer()->SetTimebaseAndInterval(future_timebase, Interval());
- SetNow(timer()->Now() + Interval() + jitter1);
- task_runner()->RunPendingTasks();
+ task_runner()->AdvanceMockTickClock(Interval() + jitter1);
+ task_runner()->RunUntilIdle();
EXPECT_EQ(15, task_runner()->NextPendingTaskDelay().InMilliseconds());
// Tick with 0ms of jitter
future_timebase += Interval();
timer()->SetTimebaseAndInterval(future_timebase, Interval());
- SetNow(timer()->Now() + Interval() - jitter1);
- task_runner()->RunPendingTasks();
+ task_runner()->AdvanceMockTickClock(Interval() - jitter1);
+ task_runner()->RunUntilIdle();
EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
// Tick with -1ms of jitter
future_timebase += Interval();
timer()->SetTimebaseAndInterval(future_timebase, Interval());
- SetNow(timer()->Now() + Interval() - jitter1);
- task_runner()->RunPendingTasks();
+ task_runner()->AdvanceMockTickClock(Interval() - jitter1);
+ task_runner()->RunUntilIdle();
EXPECT_EQ(1, task_runner()->NextPendingTaskDelay().InMilliseconds());
// Tick with 0ms of jitter
future_timebase += Interval();
timer()->SetTimebaseAndInterval(future_timebase, Interval());
- SetNow(timer()->Now() + Interval() + jitter1);
- task_runner()->RunPendingTasks();
+ task_runner()->AdvanceMockTickClock(Interval() + jitter1);
+ task_runner()->RunUntilIdle();
EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
// 8 ms jitter
@@ -217,29 +212,29 @@ TEST_F(DelayBasedTimeSourceTest, JitteryRuntimeWithFutureTimebases) {
// Tick with +8ms of jitter
future_timebase += Interval();
timer()->SetTimebaseAndInterval(future_timebase, Interval());
- SetNow(timer()->Now() + Interval() + jitter8);
- task_runner()->RunPendingTasks();
+ task_runner()->AdvanceMockTickClock(Interval() + jitter8);
+ task_runner()->RunUntilIdle();
EXPECT_EQ(8, task_runner()->NextPendingTaskDelay().InMilliseconds());
// Tick with 0ms of jitter
future_timebase += Interval();
timer()->SetTimebaseAndInterval(future_timebase, Interval());
- SetNow(timer()->Now() + Interval() - jitter8);
- task_runner()->RunPendingTasks();
+ task_runner()->AdvanceMockTickClock(Interval() - jitter8);
+ task_runner()->RunUntilIdle();
EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
// Tick with -8ms of jitter
future_timebase += Interval();
timer()->SetTimebaseAndInterval(future_timebase, Interval());
- SetNow(timer()->Now() + Interval() - jitter8);
- task_runner()->RunPendingTasks();
+ task_runner()->AdvanceMockTickClock(Interval() - jitter8);
+ task_runner()->RunUntilIdle();
EXPECT_EQ(8, task_runner()->NextPendingTaskDelay().InMilliseconds());
// Tick with 0ms of jitter
future_timebase += Interval();
timer()->SetTimebaseAndInterval(future_timebase, Interval());
- SetNow(timer()->Now() + Interval() + jitter8);
- task_runner()->RunPendingTasks();
+ task_runner()->AdvanceMockTickClock(Interval() + jitter8);
+ task_runner()->RunUntilIdle();
EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
// 15 ms jitter
@@ -248,29 +243,29 @@ TEST_F(DelayBasedTimeSourceTest, JitteryRuntimeWithFutureTimebases) {
// Tick with +15ms jitter
future_timebase += Interval();
timer()->SetTimebaseAndInterval(future_timebase, Interval());
- SetNow(timer()->Now() + Interval() + jitter15);
- task_runner()->RunPendingTasks();
+ task_runner()->AdvanceMockTickClock(Interval() + jitter15);
+ task_runner()->RunUntilIdle();
EXPECT_EQ(1, task_runner()->NextPendingTaskDelay().InMilliseconds());
// Tick with 0ms of jitter
future_timebase += Interval();
timer()->SetTimebaseAndInterval(future_timebase, Interval());
- SetNow(timer()->Now() + Interval() - jitter15);
- task_runner()->RunPendingTasks();
+ task_runner()->AdvanceMockTickClock(Interval() - jitter15);
+ task_runner()->RunUntilIdle();
EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
// Tick with -15ms of jitter
future_timebase += Interval();
timer()->SetTimebaseAndInterval(future_timebase, Interval());
- SetNow(timer()->Now() + Interval() - jitter15);
- task_runner()->RunPendingTasks();
+ task_runner()->AdvanceMockTickClock(Interval() - jitter15);
+ task_runner()->RunUntilIdle();
EXPECT_EQ(15, task_runner()->NextPendingTaskDelay().InMilliseconds());
// Tick with 0ms of jitter
future_timebase += Interval();
timer()->SetTimebaseAndInterval(future_timebase, Interval());
- SetNow(timer()->Now() + Interval() + jitter15);
- task_runner()->RunPendingTasks();
+ task_runner()->AdvanceMockTickClock(Interval() + jitter15);
+ task_runner()->RunUntilIdle();
EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
}
@@ -288,8 +283,8 @@ TEST_F(DelayBasedTimeSourceTest, AchievesTargetRateWithNoNoise) {
total_frame_time += delay_ms / 1000.0;
// Run the callback exactly when asked
- SetNow(timer()->Now() + base::Milliseconds(delay_ms));
- task_runner()->RunPendingTasks();
+ task_runner()->AdvanceMockTickClock(base::Milliseconds(delay_ms));
+ task_runner()->RunUntilIdle();
}
double average_interval =
total_frame_time / static_cast<double>(num_iterations);
@@ -301,8 +296,8 @@ TEST_F(DelayBasedTimeSourceTest, TestDeactivateWhilePending) {
timer()->SetActive(true); // Should post a task.
timer()->SetActive(false);
// Should run the posted task without crashing.
- EXPECT_TRUE(task_runner()->HasPendingTask());
- task_runner()->RunPendingTasks();
+ EXPECT_FALSE(task_runner()->HasPendingTask());
+ task_runner()->RunUntilIdle();
}
TEST_F(DelayBasedTimeSourceTest,
@@ -311,17 +306,17 @@ TEST_F(DelayBasedTimeSourceTest,
// Should run the activate task, and pick up a new timebase.
timer()->SetActive(true);
- task_runner()->RunPendingTasks();
+ task_runner()->RunUntilIdle();
// Stop the timer()
timer()->SetActive(false);
// Task will be pending anyway, run it
- task_runner()->RunPendingTasks();
+ task_runner()->RunUntilIdle();
// Start the timer() again, but before the next tick time the timer()
// previously planned on using. That same tick time should still be targeted.
- SetNow(timer()->Now() + base::Milliseconds(4));
+ task_runner()->AdvanceMockTickClock(base::Milliseconds(4));
timer()->SetActive(true);
EXPECT_EQ(12, task_runner()->NextPendingTaskDelay().InMilliseconds());
}
@@ -331,17 +326,17 @@ TEST_F(DelayBasedTimeSourceTest, TestDeactivateAndReactivateAfterNextTickTime) {
// Should run the activate task, and pick up a new timebase.
timer()->SetActive(true);
- task_runner()->RunPendingTasks();
+ task_runner()->RunUntilIdle();
// Stop the timer().
timer()->SetActive(false);
// Task will be pending anyway, run it.
- task_runner()->RunPendingTasks();
+ task_runner()->RunUntilIdle();
// Start the timer() again, but before the next tick time the timer()
// previously planned on using. That same tick time should still be targeted.
- SetNow(timer()->Now() + base::Milliseconds(20));
+ task_runner()->AdvanceMockTickClock(base::Milliseconds(20));
timer()->SetActive(true);
EXPECT_EQ(13, task_runner()->NextPendingTaskDelay().InMilliseconds());
}
diff --git a/chromium/components/viz/common/gl_i420_converter.h b/chromium/components/viz/common/gl_i420_converter.h
index 147e21ca24a..6792ca8fdc8 100644
--- a/chromium/components/viz/common/gl_i420_converter.h
+++ b/chromium/components/viz/common/gl_i420_converter.h
@@ -92,7 +92,7 @@ class VIZ_COMMON_EXPORT GLI420Converter final : public ContextLostObserver {
// [Re]Configure the converter with the given |new_params|. Returns true on
// success, or false on failure. If |new_params| does not specify an
// |output_color_space|, it will be default to REC709.
- bool Configure(const Parameters& new_params) WARN_UNUSED_RESULT;
+ [[nodiscard]] bool Configure(const Parameters& new_params);
// Returns the currently-configured and resolved Parameters. Results are
// undefined if Configure() has never been called successfully.
diff --git a/chromium/components/viz/common/gl_nv12_converter.h b/chromium/components/viz/common/gl_nv12_converter.h
index 933c173fa0a..15c6944270f 100644
--- a/chromium/components/viz/common/gl_nv12_converter.h
+++ b/chromium/components/viz/common/gl_nv12_converter.h
@@ -85,7 +85,7 @@ class VIZ_COMMON_EXPORT GLNV12Converter final : public ContextLostObserver {
// [Re]Configure the converter with the given |new_params|. Returns true on
// success, or false on failure. If |new_params| does not specify an
// |output_color_space|, it will be default to REC709.
- bool Configure(const Parameters& new_params) WARN_UNUSED_RESULT;
+ [[nodiscard]] bool Configure(const Parameters& new_params);
// Returns the currently-configured and resolved Parameters. Results are
// undefined if Configure() has never been called successfully.
diff --git a/chromium/components/viz/common/gl_scaler.h b/chromium/components/viz/common/gl_scaler.h
index b1fd42fd6ef..99013e8cadf 100644
--- a/chromium/components/viz/common/gl_scaler.h
+++ b/chromium/components/viz/common/gl_scaler.h
@@ -15,7 +15,6 @@
#include <utility>
#include <vector>
-#include "base/compiler_specific.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "components/viz/common/gpu/context_lost_observer.h"
@@ -224,7 +223,7 @@ class VIZ_COMMON_EXPORT GLScaler final : public ContextLostObserver {
// [Re]Configure the scaler with the given |new_params|. Returns true on
// success, or false on failure.
- bool Configure(const Parameters& new_params) WARN_UNUSED_RESULT;
+ [[nodiscard]] bool Configure(const Parameters& new_params);
// Returns the currently-configured and resolved Parameters. Note that these
// Parameters might not be exactly the same as those that were passed to
@@ -255,23 +254,23 @@ class VIZ_COMMON_EXPORT GLScaler final : public ContextLostObserver {
//
// Note that the |src_texture| will have the min/mag filter set to GL_LINEAR
// and wrap_s/t set to CLAMP_TO_EDGE in this call.
- bool Scale(GLuint src_texture,
- const gfx::Size& src_texture_size,
- const gfx::Vector2d& src_offset,
- GLuint dest_texture,
- const gfx::Rect& output_rect) WARN_UNUSED_RESULT {
+ [[nodiscard]] bool Scale(GLuint src_texture,
+ const gfx::Size& src_texture_size,
+ const gfx::Vector2d& src_offset,
+ GLuint dest_texture,
+ const gfx::Rect& output_rect) {
return ScaleToMultipleOutputs(src_texture, src_texture_size, src_offset,
dest_texture, 0, output_rect);
}
// Same as above, but for use cases where there are two output textures drawn
// (see Parameters::ExportFormat).
- bool ScaleToMultipleOutputs(GLuint src_texture,
- const gfx::Size& src_texture_size,
- const gfx::Vector2d& src_offset,
- GLuint dest_texture_0,
- GLuint dest_texture_1,
- const gfx::Rect& output_rect) WARN_UNUSED_RESULT;
+ [[nodiscard]] bool ScaleToMultipleOutputs(GLuint src_texture,
+ const gfx::Size& src_texture_size,
+ const gfx::Vector2d& src_offset,
+ GLuint dest_texture_0,
+ GLuint dest_texture_1,
+ const gfx::Rect& output_rect);
// Returns true if from:to represent the same scale ratio as that specified in
// |params|.
diff --git a/chromium/components/viz/common/gl_scaler_overscan_pixeltest.cc b/chromium/components/viz/common/gl_scaler_overscan_pixeltest.cc
index f43746c637e..bdf54c4ed09 100644
--- a/chromium/components/viz/common/gl_scaler_overscan_pixeltest.cc
+++ b/chromium/components/viz/common/gl_scaler_overscan_pixeltest.cc
@@ -405,7 +405,7 @@ TEST_F(GLScalerOverscanPixelTest, TwoByTwoTapBilinear) {
}
TEST_F(GLScalerOverscanPixelTest, BicubicUpscale) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Unfortunately, on our current Android bots, there are some inaccuracies
// introduced by the platform that seem to throw-off the pixel testing of the
// bicubic sampler.
diff --git a/chromium/components/viz/common/gl_scaler_pixeltest.cc b/chromium/components/viz/common/gl_scaler_pixeltest.cc
index 4b936560fa2..9c1df00fc82 100644
--- a/chromium/components/viz/common/gl_scaler_pixeltest.cc
+++ b/chromium/components/viz/common/gl_scaler_pixeltest.cc
@@ -23,7 +23,7 @@
#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/color_space.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "base/android/build_info.h"
#endif
@@ -101,7 +101,7 @@ class GLScalerPixelTest : public cc::PixelTest, public GLScalerTestUtil {
// Returns the amount of color error expected due to bugs in the current
// platform's bilinear texture sampler.
int GetBaselineColorDifference() const {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Android seems to have texture sampling problems that are not at all seen
// on any of the desktop platforms. Also, versions before Marshmallow seem
// to have a much larger accuracy issues.
@@ -126,7 +126,7 @@ class GLScalerPixelTest : public cc::PixelTest, public GLScalerTestUtil {
}
bool IsAndroidMarshmallow() {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
return base::android::BuildInfo::GetInstance()->sdk_int() ==
base::android::SDK_VERSION_MARSHMALLOW;
#else
diff --git a/chromium/components/viz/common/gl_scaler_shader_pixeltest.cc b/chromium/components/viz/common/gl_scaler_shader_pixeltest.cc
index 2a2481560a7..e1e7b8c226d 100644
--- a/chromium/components/viz/common/gl_scaler_shader_pixeltest.cc
+++ b/chromium/components/viz/common/gl_scaler_shader_pixeltest.cc
@@ -23,7 +23,7 @@
#include "third_party/skia/include/core/SkRect.h"
#include "ui/gfx/color_transform.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "base/android/build_info.h"
#endif
@@ -342,7 +342,7 @@ class GLScalerShaderPixelTest
// values in the expected vs actual image comparisons, given the current test
// parameters and known platform-specific inaccuracy.
int GetMaxAllowedColorDifference() const {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Android seems to have texture sampling and/or readback accuracy issues
// with these programs that are not at all seen on any of the desktop
// platforms. Also, versions before Marshmallow seem to have a much larger
@@ -360,7 +360,7 @@ class GLScalerShaderPixelTest
}
bool IsAndroidMarshmallow() {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
return base::android::BuildInfo::GetInstance()->sdk_int() ==
base::android::SDK_VERSION_MARSHMALLOW;
#else
diff --git a/chromium/components/viz/common/gpu/DEPS b/chromium/components/viz/common/gpu/DEPS
index 594f394068f..b2d4acb06c0 100644
--- a/chromium/components/viz/common/gpu/DEPS
+++ b/chromium/components/viz/common/gpu/DEPS
@@ -8,7 +8,7 @@ include_rules = [
"+gpu/config",
"+gpu/GLES2/gl2extchromium.h",
"+gpu/vulkan",
- "+third_party/dawn/src/include",
+ "+third_party/dawn/include",
"+third_party/khronos/GLES2/gl2.h",
"+third_party/skia/include/gpu",
"+third_party/vulkan_headers/include",
diff --git a/chromium/components/viz/common/gpu/dawn_context_provider.cc b/chromium/components/viz/common/gpu/dawn_context_provider.cc
index 181031501af..aaac79531bd 100644
--- a/chromium/components/viz/common/gpu/dawn_context_provider.cc
+++ b/chromium/components/viz/common/gpu/dawn_context_provider.cc
@@ -11,20 +11,20 @@
#include "base/memory/ptr_util.h"
#include "base/notreached.h"
#include "build/build_config.h"
-#include "third_party/dawn/src/include/dawn/dawn_proc.h"
+#include "third_party/dawn/include/dawn/dawn_proc.h"
namespace viz {
namespace {
-dawn_native::BackendType GetDefaultBackendType() {
-#if defined(OS_WIN)
- return dawn_native::BackendType::D3D12;
-#elif defined(OS_LINUX) || defined(OS_CHROMEOS)
- return dawn_native::BackendType::Vulkan;
+wgpu::BackendType GetDefaultBackendType() {
+#if BUILDFLAG(IS_WIN)
+ return wgpu::BackendType::D3D12;
+#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+ return wgpu::BackendType::Vulkan;
#else
NOTREACHED();
- return dawn_native::BackendType::Null;
+ return wgpu::BackendType::Null;
#endif
}
@@ -49,23 +49,25 @@ DawnContextProvider::DawnContextProvider() {
DawnContextProvider::~DawnContextProvider() = default;
-wgpu::Device DawnContextProvider::CreateDevice(dawn_native::BackendType type) {
+wgpu::Device DawnContextProvider::CreateDevice(wgpu::BackendType type) {
instance_.DiscoverDefaultAdapters();
- DawnProcTable backend_procs = dawn_native::GetProcs();
+ DawnProcTable backend_procs = dawn::native::GetProcs();
dawnProcSetProcs(&backend_procs);
// If a new toggle is added here, ForceDawnTogglesForSkia() which collects
// info for about:gpu should be updated as well.
// Disable validation in non-DCHECK builds.
- dawn_native::DawnDeviceDescriptor descriptor;
+ dawn::native::DawnDeviceDescriptor descriptor;
#if !DCHECK_IS_ON()
descriptor.forceEnabledToggles = {"skip_validation"};
#endif
- std::vector<dawn_native::Adapter> adapters = instance_.GetAdapters();
- for (dawn_native::Adapter adapter : adapters) {
- if (adapter.GetBackendType() == type)
+ std::vector<dawn::native::Adapter> adapters = instance_.GetAdapters();
+ for (dawn::native::Adapter adapter : adapters) {
+ wgpu::AdapterProperties properties;
+ adapter.GetProperties(&properties);
+ if (properties.backendType == type)
return adapter.CreateDevice(&descriptor);
}
return nullptr;
diff --git a/chromium/components/viz/common/gpu/dawn_context_provider.h b/chromium/components/viz/common/gpu/dawn_context_provider.h
index f360ad7dc1b..4ab8b25d656 100644
--- a/chromium/components/viz/common/gpu/dawn_context_provider.h
+++ b/chromium/components/viz/common/gpu/dawn_context_provider.h
@@ -8,7 +8,7 @@
#include <memory>
#include "components/viz/common/viz_dawn_context_provider_export.h"
-#include "third_party/dawn/src/include/dawn_native/DawnNative.h"
+#include "third_party/dawn/include/dawn/native/DawnNative.h"
#include "third_party/skia/include/gpu/GrDirectContext.h"
#include "third_party/skia/include/gpu/dawn/GrDawnTypes.h"
@@ -31,9 +31,9 @@ class VIZ_DAWN_CONTEXT_PROVIDER_EXPORT DawnContextProvider {
private:
DawnContextProvider();
- wgpu::Device CreateDevice(dawn_native::BackendType type);
+ wgpu::Device CreateDevice(wgpu::BackendType type);
- dawn_native::Instance instance_;
+ dawn::native::Instance instance_;
wgpu::Device device_;
sk_sp<GrDirectContext> gr_context_;
};
diff --git a/chromium/components/viz/common/gpu/vulkan_in_process_context_provider.cc b/chromium/components/viz/common/gpu/vulkan_in_process_context_provider.cc
index c2b5ef56e1a..38838e96eba 100644
--- a/chromium/components/viz/common/gpu/vulkan_in_process_context_provider.cc
+++ b/chromium/components/viz/common/gpu/vulkan_in_process_context_provider.cc
@@ -132,9 +132,24 @@ bool VulkanInProcessContextProvider::InitializeGrContext(
GrVkGetProc get_proc = [](const char* proc_name, VkInstance instance,
VkDevice device) {
if (device) {
- if (std::strcmp("vkCreateGraphicsPipelines", proc_name) == 0)
+ // Using vkQueue*Hook for all vkQueue* methods here to make both chrome
+ // side access and skia side access to the same queue thread safe.
+ // vkQueue*Hook routes all skia side access to the same
+ // VulkanFunctionPointers vkQueue* api which chrome uses and is under the
+ // lock.
+ if (std::strcmp("vkCreateGraphicsPipelines", proc_name) == 0) {
return reinterpret_cast<PFN_vkVoidFunction>(
&gpu::CreateGraphicsPipelinesHook);
+ } else if (std::strcmp("vkQueueSubmit", proc_name) == 0) {
+ return reinterpret_cast<PFN_vkVoidFunction>(
+ &gpu::VulkanQueueSubmitHook);
+ } else if (std::strcmp("vkQueueWaitIdle", proc_name) == 0) {
+ return reinterpret_cast<PFN_vkVoidFunction>(
+ &gpu::VulkanQueueWaitIdleHook);
+ } else if (std::strcmp("vkQueuePresentKHR", proc_name) == 0) {
+ return reinterpret_cast<PFN_vkVoidFunction>(
+ &gpu::VulkanQueuePresentKHRHook);
+ }
return vkGetDeviceProcAddr(device, proc_name);
}
return vkGetInstanceProcAddr(instance, proc_name);
diff --git a/chromium/components/viz/common/hit_test/hit_test_region_list.h b/chromium/components/viz/common/hit_test/hit_test_region_list.h
index e0d8f116811..0bfdab51d00 100644
--- a/chromium/components/viz/common/hit_test/hit_test_region_list.h
+++ b/chromium/components/viz/common/hit_test/hit_test_region_list.h
@@ -36,9 +36,6 @@ enum HitTestRegionFlags : uint32_t {
// Client hasn't submitted its own hit-test data yet.
kHitTestNotActive = 0x40,
-
- // Hit-test debugging is enabled.
- kHitTestDebug = 0x80,
};
// In viz hit testing surface layer, hit test regions are marked as kHitTestAsk
diff --git a/chromium/components/viz/common/quads/compositor_frame_metadata.h b/chromium/components/viz/common/quads/compositor_frame_metadata.h
index 9e6e5d5cd4f..acd850f3f9c 100644
--- a/chromium/components/viz/common/quads/compositor_frame_metadata.h
+++ b/chromium/components/viz/common/quads/compositor_frame_metadata.h
@@ -28,10 +28,10 @@
#include "ui/gfx/overlay_transform.h"
#include "ui/latency/latency_info.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "components/viz/common/quads/selection.h"
#include "ui/gfx/selection_bound.h"
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
namespace viz {
diff --git a/chromium/components/viz/common/quads/compositor_frame_metadata_unittest.cc b/chromium/components/viz/common/quads/compositor_frame_metadata_unittest.cc
index 27fcda0ecb9..7535e55e3b4 100644
--- a/chromium/components/viz/common/quads/compositor_frame_metadata_unittest.cc
+++ b/chromium/components/viz/common/quads/compositor_frame_metadata_unittest.cc
@@ -34,9 +34,6 @@ bool AreLatencyInfosEqual(const ui::LatencyInfo& a, const ui::LatencyInfo& b) {
return a.began() == b.began() && a.terminated() == b.terminated() &&
a.coalesced() == b.coalesced() && a.trace_id() == b.trace_id() &&
a.ukm_source_id() == b.ukm_source_id() &&
- std::abs(a.scroll_update_delta() - b.scroll_update_delta()) < 1e-6 &&
- std::abs(a.predicted_scroll_update_delta() -
- b.predicted_scroll_update_delta()) < 1e-6 &&
a.gesture_scroll_id() == b.gesture_scroll_id();
}
@@ -51,7 +48,8 @@ bool AreDelegatedInkMetadataEqual(const gfx::DelegatedInkMetadata& a,
bool AreTransitionDirectivesEqual(const CompositorFrameTransitionDirective& a,
const CompositorFrameTransitionDirective& b) {
return a.sequence_id() == b.sequence_id() && a.type() == b.type() &&
- a.effect() == b.effect();
+ a.effect() == b.effect() &&
+ a.is_renderer_driven_animation() == b.is_renderer_driven_animation();
}
TEST(CompositorFrameMetadata, Clone) {
@@ -86,7 +84,7 @@ TEST(CompositorFrameMetadata, Clone) {
gfx::PointF(88.8, 44.4), 1.f, SK_ColorRED,
base::TimeTicks() + base::Seconds(125), gfx::RectF(1, 2, 3, 4), true);
metadata.transition_directives.emplace_back(
- 4u, CompositorFrameTransitionDirective::Type::kSave,
+ 4u, CompositorFrameTransitionDirective::Type::kSave, true,
CompositorFrameTransitionDirective::Effect::kCoverUp);
CompositorFrameMetadata clone = metadata.Clone();
diff --git a/chromium/components/viz/common/quads/compositor_frame_transition_directive.cc b/chromium/components/viz/common/quads/compositor_frame_transition_directive.cc
index fe7ecadaa3f..57fa02cf0be 100644
--- a/chromium/components/viz/common/quads/compositor_frame_transition_directive.cc
+++ b/chromium/components/viz/common/quads/compositor_frame_transition_directive.cc
@@ -4,6 +4,7 @@
#include "components/viz/common/quads/compositor_frame_transition_directive.h"
+#include <string>
#include <utility>
#include "base/time/time.h"
@@ -22,11 +23,13 @@ CompositorFrameTransitionDirective::CompositorFrameTransitionDirective() =
CompositorFrameTransitionDirective::CompositorFrameTransitionDirective(
uint32_t sequence_id,
Type type,
+ bool is_renderer_driven_animation,
Effect effect,
const TransitionConfig& root_config,
std::vector<SharedElement> shared_elements)
: sequence_id_(sequence_id),
type_(type),
+ is_renderer_driven_animation_(is_renderer_driven_animation),
effect_(effect),
root_config_(root_config),
shared_elements_(std::move(shared_elements)) {}
diff --git a/chromium/components/viz/common/quads/compositor_frame_transition_directive.h b/chromium/components/viz/common/quads/compositor_frame_transition_directive.h
index 71975e7c05f..56b1258d0ce 100644
--- a/chromium/components/viz/common/quads/compositor_frame_transition_directive.h
+++ b/chromium/components/viz/common/quads/compositor_frame_transition_directive.h
@@ -5,6 +5,7 @@
#ifndef COMPONENTS_VIZ_COMMON_QUADS_COMPOSITOR_FRAME_TRANSITION_DIRECTIVE_H_
#define COMPONENTS_VIZ_COMMON_QUADS_COMPOSITOR_FRAME_TRANSITION_DIRECTIVE_H_
+#include <string>
#include <vector>
#include "base/time/time.h"
@@ -105,6 +106,7 @@ class VIZ_COMMON_EXPORT CompositorFrameTransitionDirective {
CompositorFrameTransitionDirective(
uint32_t sequence_id,
Type type,
+ bool is_renderer_driven_animation = false,
Effect effect = Effect::kNone,
const TransitionConfig& root_config = TransitionConfig(),
std::vector<SharedElement> shared_elements = {});
@@ -133,11 +135,18 @@ class VIZ_COMMON_EXPORT CompositorFrameTransitionDirective {
return shared_elements_;
}
+ // Returns true if this is a directive for a renderer driven animation.
+ bool is_renderer_driven_animation() const {
+ return is_renderer_driven_animation_;
+ }
+
private:
uint32_t sequence_id_ = 0;
Type type_ = Type::kSave;
+ bool is_renderer_driven_animation_ = false;
+
Effect effect_ = Effect::kNone;
TransitionConfig root_config_;
diff --git a/chromium/components/viz/common/quads/compositor_frame_transition_directive_unittest.cc b/chromium/components/viz/common/quads/compositor_frame_transition_directive_unittest.cc
index 66e92a07170..465b48e2ba6 100644
--- a/chromium/components/viz/common/quads/compositor_frame_transition_directive_unittest.cc
+++ b/chromium/components/viz/common/quads/compositor_frame_transition_directive_unittest.cc
@@ -13,17 +13,19 @@ using Effect = CompositorFrameTransitionDirective::Effect;
using Type = CompositorFrameTransitionDirective::Type;
TEST(CompositorFrameTransitionDirective, GettersReflectParameters) {
- CompositorFrameTransitionDirective save_directive(1u, Type::kSave,
+ CompositorFrameTransitionDirective save_directive(1u, Type::kSave, true,
Effect::kCoverLeft);
EXPECT_EQ(1u, save_directive.sequence_id());
EXPECT_EQ(Type::kSave, save_directive.type());
EXPECT_EQ(Effect::kCoverLeft, save_directive.effect());
+ EXPECT_TRUE(save_directive.is_renderer_driven_animation());
CompositorFrameTransitionDirective animate_directive(2, Type::kAnimate);
EXPECT_EQ(2u, animate_directive.sequence_id());
EXPECT_EQ(Type::kAnimate, animate_directive.type());
+ EXPECT_FALSE(animate_directive.is_renderer_driven_animation());
}
} // namespace
diff --git a/chromium/components/viz/common/quads/draw_quad_unittest.cc b/chromium/components/viz/common/quads/draw_quad_unittest.cc
index 01b02f78787..8f0a24327e1 100644
--- a/chromium/components/viz/common/quads/draw_quad_unittest.cc
+++ b/chromium/components/viz/common/quads/draw_quad_unittest.cc
@@ -10,7 +10,6 @@
#include <memory>
#include "base/bind.h"
-#include "base/compiler_specific.h"
#include "base/logging.h"
#include "base/unguessable_token.h"
#include "cc/base/math_util.h"
@@ -115,18 +114,15 @@ void CompareDrawQuad(DrawQuad* quad, DrawQuad* copy) {
render_pass->CreateAndAppendSharedQuadState(); \
*copy_shared_state = *shared_state;
-#define QUAD_DATA \
- gfx::Rect quad_rect(30, 40, 50, 60); \
- gfx::Rect quad_visible_rect(40, 50, 30, 20); \
- ALLOW_UNUSED_LOCAL(quad_visible_rect); \
- bool needs_blending = true; \
- ALLOW_UNUSED_LOCAL(needs_blending);
+#define QUAD_DATA \
+ gfx::Rect quad_rect(30, 40, 50, 60); \
+ [[maybe_unused]] gfx::Rect quad_visible_rect(40, 50, 30, 20); \
+ [[maybe_unused]] bool needs_blending = true;
#define SETUP_AND_COPY_QUAD_NEW(Type, quad) \
DrawQuad* copy_new = render_pass->CopyFromAndAppendDrawQuad(quad_new); \
CompareDrawQuad(quad_new, copy_new); \
- const Type* copy_quad = Type::MaterialCast(copy_new); \
- ALLOW_UNUSED_LOCAL(copy_quad);
+ [[maybe_unused]] const Type* copy_quad = Type::MaterialCast(copy_new);
#define SETUP_AND_COPY_QUAD_ALL(Type, quad) \
DrawQuad* copy_all = render_pass->CopyFromAndAppendDrawQuad(quad_all); \
@@ -137,8 +133,7 @@ void CompareDrawQuad(DrawQuad* quad, DrawQuad* copy) {
DrawQuad* copy_new = \
render_pass->CopyFromAndAppendRenderPassDrawQuad(quad_new, a); \
CompareDrawQuad(quad_new, copy_new); \
- const Type* copy_quad = Type::MaterialCast(copy_new); \
- ALLOW_UNUSED_LOCAL(copy_quad);
+ [[maybe_unused]] const Type* copy_quad = Type::MaterialCast(copy_new);
#define SETUP_AND_COPY_QUAD_ALL_RP(Type, quad, a) \
DrawQuad* copy_all = \
diff --git a/chromium/components/viz/common/quads/render_pass_io.cc b/chromium/components/viz/common/quads/render_pass_io.cc
index 0dcd782ade7..1f2cb9e067f 100644
--- a/chromium/components/viz/common/quads/render_pass_io.cc
+++ b/chromium/components/viz/common/quads/render_pass_io.cc
@@ -208,14 +208,14 @@ bool FloatArrayFromList(const base::Value& list,
DCHECK_LT(0u, expected_count);
if (!list.is_list())
return false;
- size_t count = list.GetList().size();
+ size_t count = list.GetListDeprecated().size();
if (count != expected_count)
return false;
std::vector<double> double_data(count);
for (size_t ii = 0; ii < count; ++ii) {
- if (!list.GetList()[ii].is_double())
+ if (!list.GetListDeprecated()[ii].is_double())
return false;
- double_data[ii] = list.GetList()[ii].GetDouble();
+ double_data[ii] = list.GetListDeprecated()[ii].GetDouble();
}
for (size_t ii = 0; ii < count; ++ii)
data[ii] = static_cast<float>(double_data[ii]);
@@ -343,13 +343,13 @@ bool TransformFromList(const base::Value& list, gfx::Transform* transform) {
DCHECK(transform);
if (!list.is_list())
return false;
- if (list.GetList().size() != 16)
+ if (list.GetListDeprecated().size() != 16)
return false;
double data[16];
for (size_t ii = 0; ii < 16; ++ii) {
- if (!list.GetList()[ii].is_double())
+ if (!list.GetListDeprecated()[ii].is_double())
return false;
- data[ii] = list.GetList()[ii].GetDouble();
+ data[ii] = list.GetListDeprecated()[ii].GetDouble();
}
transform->matrix().setColMajord(data);
return true;
@@ -368,11 +368,11 @@ bool ShapeRectsFromList(const base::Value& list,
DCHECK(shape);
if (!list.is_list())
return false;
- size_t size = list.GetList().size();
+ size_t size = list.GetListDeprecated().size();
cc::FilterOperation::ShapeRects data;
data.resize(size);
for (size_t ii = 0; ii < size; ++ii) {
- if (!RectFromDict(list.GetList()[ii], &data[ii]))
+ if (!RectFromDict(list.GetListDeprecated()[ii], &data[ii]))
return false;
}
*shape = data;
@@ -564,9 +564,9 @@ bool FilterOperationsFromList(const base::Value& list,
if (!list.is_list())
return false;
cc::FilterOperations data;
- for (size_t ii = 0; ii < list.GetList().size(); ++ii) {
+ for (size_t ii = 0; ii < list.GetListDeprecated().size(); ++ii) {
cc::FilterOperation filter;
- if (!FilterOperationFromDict(list.GetList()[ii], &filter))
+ if (!FilterOperationFromDict(list.GetListDeprecated()[ii], &filter))
return false;
data.Append(filter);
}
@@ -590,7 +590,7 @@ const char* ColorSpacePrimaryIdToString(gfx::ColorSpace::PrimaryID id) {
MATCH_ENUM_CASE(PrimaryID, BT2020)
MATCH_ENUM_CASE(PrimaryID, SMPTEST428_1)
MATCH_ENUM_CASE(PrimaryID, SMPTEST431_2)
- MATCH_ENUM_CASE(PrimaryID, SMPTEST432_1)
+ MATCH_ENUM_CASE(PrimaryID, P3)
MATCH_ENUM_CASE(PrimaryID, XYZ_D50)
MATCH_ENUM_CASE(PrimaryID, ADOBE_RGB)
MATCH_ENUM_CASE(PrimaryID, APPLE_GENERIC_RGB)
@@ -615,13 +615,13 @@ const char* ColorSpaceTransferIdToString(gfx::ColorSpace::TransferID id) {
MATCH_ENUM_CASE(TransferID, LOG_SQRT)
MATCH_ENUM_CASE(TransferID, IEC61966_2_4)
MATCH_ENUM_CASE(TransferID, BT1361_ECG)
- MATCH_ENUM_CASE(TransferID, IEC61966_2_1)
+ MATCH_ENUM_CASE(TransferID, SRGB)
MATCH_ENUM_CASE(TransferID, BT2020_10)
MATCH_ENUM_CASE(TransferID, BT2020_12)
- MATCH_ENUM_CASE(TransferID, SMPTEST2084)
+ MATCH_ENUM_CASE(TransferID, PQ)
MATCH_ENUM_CASE(TransferID, SMPTEST428_1)
- MATCH_ENUM_CASE(TransferID, ARIB_STD_B67)
- MATCH_ENUM_CASE(TransferID, IEC61966_2_1_HDR)
+ MATCH_ENUM_CASE(TransferID, HLG)
+ MATCH_ENUM_CASE(TransferID, SRGB_HDR)
MATCH_ENUM_CASE(TransferID, LINEAR_HDR)
MATCH_ENUM_CASE(TransferID, CUSTOM)
MATCH_ENUM_CASE(TransferID, CUSTOM_HDR)
@@ -671,7 +671,7 @@ uint8_t StringToColorSpacePrimaryId(const std::string& token) {
MATCH_ENUM_CASE(PrimaryID, BT2020)
MATCH_ENUM_CASE(PrimaryID, SMPTEST428_1)
MATCH_ENUM_CASE(PrimaryID, SMPTEST431_2)
- MATCH_ENUM_CASE(PrimaryID, SMPTEST432_1)
+ MATCH_ENUM_CASE(PrimaryID, P3)
MATCH_ENUM_CASE(PrimaryID, XYZ_D50)
MATCH_ENUM_CASE(PrimaryID, ADOBE_RGB)
MATCH_ENUM_CASE(PrimaryID, APPLE_GENERIC_RGB)
@@ -695,13 +695,13 @@ uint8_t StringToColorSpaceTransferId(const std::string& token) {
MATCH_ENUM_CASE(TransferID, LOG_SQRT)
MATCH_ENUM_CASE(TransferID, IEC61966_2_4)
MATCH_ENUM_CASE(TransferID, BT1361_ECG)
- MATCH_ENUM_CASE(TransferID, IEC61966_2_1)
+ MATCH_ENUM_CASE(TransferID, SRGB)
MATCH_ENUM_CASE(TransferID, BT2020_10)
MATCH_ENUM_CASE(TransferID, BT2020_12)
- MATCH_ENUM_CASE(TransferID, SMPTEST2084)
+ MATCH_ENUM_CASE(TransferID, PQ)
MATCH_ENUM_CASE(TransferID, SMPTEST428_1)
- MATCH_ENUM_CASE(TransferID, ARIB_STD_B67)
- MATCH_ENUM_CASE(TransferID, IEC61966_2_1_HDR)
+ MATCH_ENUM_CASE(TransferID, HLG)
+ MATCH_ENUM_CASE(TransferID, SRGB_HDR)
MATCH_ENUM_CASE(TransferID, LINEAR_HDR)
MATCH_ENUM_CASE(TransferID, CUSTOM)
MATCH_ENUM_CASE(TransferID, CUSTOM_HDR)
@@ -862,7 +862,7 @@ bool DrawQuadResourcesFromList(const base::Value& list,
DCHECK(resources);
if (!list.is_list())
return false;
- size_t size = list.GetList().size();
+ size_t size = list.GetListDeprecated().size();
if (size == 0u) {
resources->count = 0u;
return true;
@@ -870,13 +870,13 @@ bool DrawQuadResourcesFromList(const base::Value& list,
if (size > DrawQuad::Resources::kMaxResourceIdCount)
return false;
for (size_t ii = 0; ii < size; ++ii) {
- if (!list.GetList()[ii].is_int())
+ if (!list.GetListDeprecated()[ii].is_int())
return false;
}
resources->count = static_cast<uint32_t>(size);
for (size_t ii = 0; ii < size; ++ii) {
- resources->ids[ii] = ResourceId(list.GetList()[ii].GetInt());
+ resources->ids[ii] = ResourceId(list.GetListDeprecated()[ii].GetInt());
}
return true;
}
@@ -1623,11 +1623,11 @@ bool VideoHoleDrawQuadFromDict(const base::Value& dict,
case DrawQuad::Material::NAME: \
NOTREACHED() << "Unexpected " << #NAME; \
break;
-#define GET_QUAD_FROM_DICT(NAME, TYPE) \
- case DrawQuad::Material::NAME: { \
- TYPE* quad = quads.AllocateAndConstruct<TYPE>(); \
- if (!TYPE##FromDict(list.GetList()[ii], common.value(), quad)) \
- return false; \
+#define GET_QUAD_FROM_DICT(NAME, TYPE) \
+ case DrawQuad::Material::NAME: { \
+ TYPE* quad = quads.AllocateAndConstruct<TYPE>(); \
+ if (!TYPE##FromDict(list.GetListDeprecated()[ii], common.value(), quad)) \
+ return false; \
} break;
bool QuadListFromList(const base::Value& list,
QuadList* quad_list,
@@ -1635,17 +1635,17 @@ bool QuadListFromList(const base::Value& list,
DCHECK(quad_list);
if (!list.is_list())
return false;
- size_t size = list.GetList().size();
+ size_t size = list.GetListDeprecated().size();
if (size == 0) {
quad_list->clear();
return true;
}
QuadList quads(size);
for (size_t ii = 0; ii < size; ++ii) {
- if (!list.GetList()[ii].is_dict())
+ if (!list.GetListDeprecated()[ii].is_dict())
return false;
- absl::optional<DrawQuadCommon> common =
- GetDrawQuadCommonFromDict(list.GetList()[ii], shared_quad_state_list);
+ absl::optional<DrawQuadCommon> common = GetDrawQuadCommonFromDict(
+ list.GetListDeprecated()[ii], shared_quad_state_list);
if (!common)
return false;
switch (common->material) {
@@ -1847,14 +1847,14 @@ bool SharedQuadStateListFromList(const base::Value& list,
DCHECK(shared_quad_state_list);
if (!list.is_list())
return false;
- size_t size = list.GetList().size();
+ size_t size = list.GetListDeprecated().size();
SharedQuadStateList states(alignof(SharedQuadState), sizeof(SharedQuadState),
size);
for (size_t ii = 0; ii < size; ++ii) {
- if (!list.GetList()[ii].is_dict())
+ if (!list.GetListDeprecated()[ii].is_dict())
return false;
SharedQuadState* sqs = states.AllocateAndConstruct<SharedQuadState>();
- if (!SharedQuadStateFromDict(list.GetList()[ii], sqs))
+ if (!SharedQuadStateFromDict(list.GetListDeprecated()[ii], sqs))
return false;
}
shared_quad_state_list->swap(states);
@@ -2123,9 +2123,9 @@ bool CompositorRenderPassListFromDict(
const base::Value* list = dict.FindListKey("render_pass_list");
if (!list || !list->is_list())
return false;
- for (size_t ii = 0; ii < list->GetList().size(); ++ii) {
+ for (size_t ii = 0; ii < list->GetListDeprecated().size(); ++ii) {
render_pass_list->push_back(
- CompositorRenderPassFromDict(list->GetList()[ii]));
+ CompositorRenderPassFromDict(list->GetListDeprecated()[ii]));
if (!(*render_pass_list)[ii].get()) {
render_pass_list->clear();
return false;
@@ -2177,7 +2177,8 @@ bool CompositorFrameFromDict(const base::Value& dict,
if (!referenced_surfaces || !referenced_surfaces->is_list()) {
return false;
}
- for (auto& referenced_surface_dict : referenced_surfaces->GetList()) {
+ for (auto& referenced_surface_dict :
+ referenced_surfaces->GetListDeprecated()) {
auto referenced_surface = SurfaceRangeFromDict(referenced_surface_dict);
if (!referenced_surface) {
return false;
@@ -2217,7 +2218,7 @@ bool FrameDataFromList(const base::Value& list,
if (!list.is_list()) {
return false;
}
- for (const auto& frame_data_dict : list.GetList()) {
+ for (const auto& frame_data_dict : list.GetListDeprecated()) {
FrameData frame_data;
auto* surface_id_dict = frame_data_dict.FindDictKey("surface_id");
if (!surface_id_dict) {
diff --git a/chromium/components/viz/common/quads/render_pass_io_unittest.cc b/chromium/components/viz/common/quads/render_pass_io_unittest.cc
index 3677c19cdbb..2bf17a37584 100644
--- a/chromium/components/viz/common/quads/render_pass_io_unittest.cc
+++ b/chromium/components/viz/common/quads/render_pass_io_unittest.cc
@@ -346,15 +346,17 @@ TEST(RenderPassIOTest, CompositorRenderPassList) {
// 'intersects_damage_under' in its CompositorRenderPassDrawQuad, I'm
// removing the field on dict1 for the exact comparison to work.
base::Value* list = dict1.FindListKey("render_pass_list");
- for (size_t i = 0; i < list->GetList().size(); ++i) {
- base::Value* quad_list = list->GetList()[i].FindListKey("quad_list");
+ for (size_t i = 0; i < list->GetListDeprecated().size(); ++i) {
+ base::Value* quad_list =
+ list->GetListDeprecated()[i].FindListKey("quad_list");
- for (size_t ii = 0; ii < quad_list->GetList().size(); ++ii) {
+ for (size_t ii = 0; ii < quad_list->GetListDeprecated().size(); ++ii) {
if (const base::Value* extra_value =
- quad_list->GetList()[ii].FindKey("intersects_damage_under")) {
+ quad_list->GetListDeprecated()[ii].FindKey(
+ "intersects_damage_under")) {
EXPECT_FALSE(extra_value->GetBool());
- ASSERT_TRUE(
- quad_list->GetList()[ii].RemoveKey("intersects_damage_under"));
+ ASSERT_TRUE(quad_list->GetListDeprecated()[ii].RemoveKey(
+ "intersects_damage_under"));
}
}
}
diff --git a/chromium/components/viz/common/resources/DEPS b/chromium/components/viz/common/resources/DEPS
index 173d9a999b3..9a0345721ee 100644
--- a/chromium/components/viz/common/resources/DEPS
+++ b/chromium/components/viz/common/resources/DEPS
@@ -11,7 +11,7 @@ include_rules = [
"+mojo/public/cpp/system/buffer.h",
"+mojo/public/cpp/system/platform_handle.h",
"+skia/buildflags.h",
- "+third_party/dawn/src/include",
+ "+third_party/dawn/include",
"+third_party/khronos/GLES2",
"+third_party/skia",
"+third_party/vulkan-deps/vulkan-headers/src",
diff --git a/chromium/components/viz/common/resources/bitmap_allocation.cc b/chromium/components/viz/common/resources/bitmap_allocation.cc
index 952bd26b0a7..d467789b22e 100644
--- a/chromium/components/viz/common/resources/bitmap_allocation.cc
+++ b/chromium/components/viz/common/resources/bitmap_allocation.cc
@@ -23,7 +23,7 @@ namespace {
void CollectMemoryUsageAndDie(const gfx::Size& size,
ResourceFormat format,
size_t alloc_size) {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
DWORD last_error = GetLastError();
base::debug::Alias(&last_error);
#endif
diff --git a/chromium/components/viz/common/resources/resource_format_utils.cc b/chromium/components/viz/common/resources/resource_format_utils.cc
index fbd48109cf4..ba03a517dae 100644
--- a/chromium/components/viz/common/resources/resource_format_utils.cc
+++ b/chromium/components/viz/common/resources/resource_format_utils.cc
@@ -4,13 +4,16 @@
#include "components/viz/common/resources/resource_format_utils.h"
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <GLES2/gl2extchromium.h>
+
#include <ostream>
#include "base/check_op.h"
#include "base/cxx17_backports.h"
#include "base/notreached.h"
-#include "third_party/khronos/GLES2/gl2.h"
-#include "third_party/khronos/GLES2/gl2ext.h"
+#include "build/chromeos_buildflags.h"
#include "ui/gfx/buffer_types.h"
namespace viz {
@@ -110,6 +113,8 @@ ResourceFormat SkColorTypeToResourceFormat(SkColorType color_type) {
case kRGBA_F16Norm_SkColorType:
case kRGBA_F32_SkColorType:
case kSRGBA_8888_SkColorType:
+ // Default case is for new color types added to Skia
+ default:
break;
}
NOTREACHED();
@@ -350,7 +355,8 @@ bool IsResourceFormatCompressed(ResourceFormat format) {
return format == ETC1;
}
-unsigned int TextureStorageFormat(ResourceFormat format) {
+unsigned int TextureStorageFormat(ResourceFormat format,
+ bool use_angle_rgbx_format) {
switch (format) {
case RGBA_8888:
return GL_RGBA8_OES;
@@ -378,7 +384,8 @@ unsigned int TextureStorageFormat(ResourceFormat format) {
case RG16_EXT:
return GL_RG16_EXT;
case RGBX_8888:
- return GL_RGB8_OES;
+ case BGRX_8888:
+ return use_angle_rgbx_format ? GL_RGBX8_ANGLE : GL_RGB8_OES;
case ETC1:
return GL_ETC1_RGB8_OES;
case P010:
@@ -388,8 +395,6 @@ unsigned int TextureStorageFormat(ResourceFormat format) {
case YVU_420:
case YUV_420_BIPLANAR:
return GL_RGB8_OES;
- case BGRX_8888:
- return GL_RGB8_OES;
default:
break;
}
@@ -400,7 +405,13 @@ unsigned int TextureStorageFormat(ResourceFormat format) {
bool IsGpuMemoryBufferFormatSupported(ResourceFormat format) {
switch (format) {
case BGRA_8888:
+#if !BUILDFLAG(IS_CHROMEOS_LACROS)
+ // TODO(crbug.com/1307837): On ARM devices LaCrOS can't create RED_8
+ // GpuMemoryBuffer Objects with GBM device. This capability should be
+ // plumbed and known by clients requesting shared images as overlay
+ // candidate.
case RED_8:
+#endif
case R16_EXT:
case RGBA_4444:
case RGBA_8888:
@@ -413,6 +424,9 @@ bool IsGpuMemoryBufferFormatSupported(ResourceFormat format) {
case ETC1:
case ALPHA_8:
case LUMINANCE_8:
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+ case RED_8:
+#endif
case RGB_565:
case LUMINANCE_F16:
case BGR_565:
diff --git a/chromium/components/viz/common/resources/resource_format_utils.h b/chromium/components/viz/common/resources/resource_format_utils.h
index a61d552144d..255ebb6a260 100644
--- a/chromium/components/viz/common/resources/resource_format_utils.h
+++ b/chromium/components/viz/common/resources/resource_format_utils.h
@@ -10,8 +10,8 @@
#include "components/viz/common/viz_resource_format_export.h"
#include "gpu/vulkan/buildflags.h"
#include "skia/buildflags.h"
-#include "third_party/dawn/src/include/dawn/webgpu.h"
-#include "third_party/dawn/src/include/dawn/webgpu_cpp.h"
+#include "third_party/dawn/include/dawn/webgpu.h"
+#include "third_party/dawn/include/dawn/webgpu_cpp.h"
#include "third_party/skia/include/core/SkImageInfo.h"
#include "third_party/skia/include/gpu/GrTypes.h"
#include "ui/gfx/buffer_types.h"
@@ -47,8 +47,12 @@ VIZ_RESOURCE_FORMAT_EXPORT gfx::BufferFormat BufferFormat(
ResourceFormat format);
VIZ_RESOURCE_FORMAT_EXPORT bool IsResourceFormatCompressed(
ResourceFormat format);
+
+// |use_angle_rgbx_format| should be true when the GL_ANGLE_rgbx_internal_format
+// extension is available.
VIZ_RESOURCE_FORMAT_EXPORT unsigned int TextureStorageFormat(
- ResourceFormat format);
+ ResourceFormat format,
+ bool use_angle_rgbx_format);
// Returns whether the format can be used with GpuMemoryBuffer texture storage,
// allocated through TexStorage2DImageCHROMIUM.
@@ -76,7 +80,7 @@ VIZ_RESOURCE_FORMAT_EXPORT wgpu::TextureFormat ToDawnFormat(
VIZ_RESOURCE_FORMAT_EXPORT WGPUTextureFormat
ToWGPUFormat(ResourceFormat format);
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
VIZ_RESOURCE_FORMAT_EXPORT unsigned int ToMTLPixelFormat(ResourceFormat format);
#endif
diff --git a/chromium/components/viz/common/resources/transferable_resource.h b/chromium/components/viz/common/resources/transferable_resource.h
index 8f9169161ee..0a360bc3ade 100644
--- a/chromium/components/viz/common/resources/transferable_resource.h
+++ b/chromium/components/viz/common/resources/transferable_resource.h
@@ -112,7 +112,7 @@ struct VIZ_COMMON_EXPORT TransferableResource {
// YCbCr info for resources backed by YCbCr Vulkan images.
absl::optional<gpu::VulkanYCbCrInfo> ycbcr_info;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Indicates whether this resource may not be overlayed on Android, since
// it's not backed by a SurfaceView. This may be set in combination with
// |is_overlay_candidate|, to find out if switching the resource to a
@@ -125,7 +125,7 @@ struct VIZ_COMMON_EXPORT TransferableResource {
bool is_backed_by_surface_texture = false;
#endif
-#if defined(OS_ANDROID) || defined(OS_WIN)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_WIN)
// Indicates that this resource would like a promotion hint.
bool wants_promotion_hint = false;
#endif
@@ -139,10 +139,10 @@ struct VIZ_COMMON_EXPORT TransferableResource {
color_space == o.color_space && hdr_metadata == o.hdr_metadata &&
is_overlay_candidate == o.is_overlay_candidate &&
filter == o.filter &&
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
is_backed_by_surface_texture == o.is_backed_by_surface_texture &&
wants_promotion_hint == o.wants_promotion_hint &&
-#elif defined(OS_WIN)
+#elif BUILDFLAG(IS_WIN)
wants_promotion_hint == o.wants_promotion_hint &&
#endif
read_lock_fences_enabled == o.read_lock_fences_enabled;
diff --git a/chromium/components/viz/common/surfaces/region_capture_bounds.cc b/chromium/components/viz/common/surfaces/region_capture_bounds.cc
index 08074a402cf..36d9fb4fd2a 100644
--- a/chromium/components/viz/common/surfaces/region_capture_bounds.cc
+++ b/chromium/components/viz/common/surfaces/region_capture_bounds.cc
@@ -7,6 +7,8 @@
#include <sstream>
#include <utility>
+#include "base/no_destructor.h"
+
namespace viz {
RegionCaptureBounds::RegionCaptureBounds() = default;
@@ -21,11 +23,21 @@ RegionCaptureBounds& RegionCaptureBounds::operator=(
const RegionCaptureBounds&) = default;
RegionCaptureBounds::~RegionCaptureBounds() = default;
+// static
+const RegionCaptureBounds& RegionCaptureBounds::Empty() {
+ static base::NoDestructor<RegionCaptureBounds> kEmpty;
+ return *kEmpty;
+}
+
void RegionCaptureBounds::Set(const RegionCaptureCropId& crop_id,
const gfx::Rect& region) {
bounds_.insert_or_assign(crop_id, region);
}
+void RegionCaptureBounds::Reset() {
+ bounds_.clear();
+}
+
bool RegionCaptureBounds::operator==(const RegionCaptureBounds& rhs) const {
return bounds_ == rhs.bounds_;
}
diff --git a/chromium/components/viz/common/surfaces/region_capture_bounds.h b/chromium/components/viz/common/surfaces/region_capture_bounds.h
index 89be906bd43..27bfc80dd81 100644
--- a/chromium/components/viz/common/surfaces/region_capture_bounds.h
+++ b/chromium/components/viz/common/surfaces/region_capture_bounds.h
@@ -33,10 +33,20 @@ class VIZ_COMMON_EXPORT RegionCaptureBounds {
RegionCaptureBounds& operator=(const RegionCaptureBounds&);
~RegionCaptureBounds();
+ // Returns a reference to a global empty RegionCaptureBounds. This should only
+ // be used for functions that need to return a reference to a
+ // RegionCaptureBounds, not instead of the default constructor.
+ static const RegionCaptureBounds& Empty();
+
// We currently only support a single set of bounds for a given crop id.
// Multiple calls with the same crop id will update the bounds.
void Set(const RegionCaptureCropId& crop_id, const gfx::Rect& bounds);
+ bool IsEmpty() const { return bounds_.empty(); }
+
+ // Sets the bounds to empty.
+ void Reset();
+
const base::flat_map<RegionCaptureCropId, gfx::Rect>& bounds() const {
return bounds_;
}
diff --git a/chromium/components/viz/common/switches.cc b/chromium/components/viz/common/switches.cc
index 14db420e8f3..0e142fa1839 100644
--- a/chromium/components/viz/common/switches.cc
+++ b/chromium/components/viz/common/switches.cc
@@ -4,9 +4,13 @@
#include "components/viz/common/switches.h"
+#include <algorithm>
+#include <string>
+
#include "base/command_line.h"
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
+#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "components/viz/common/constants.h"
@@ -41,10 +45,7 @@ const char kEnableDeJelly[] = "enable-de-jelly";
// fullscreen overlay and use it as main framebuffer where possible.
const char kEnableHardwareOverlays[] = "enable-hardware-overlays";
-// Enables hit-test debug logging.
-const char kEnableVizHitTestDebug[] = "enable-viz-hit-test-debug";
-
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS)
// ChromeOS uses one of two VideoDecoder implementations based on SoC/board
// specific configurations that are signalled via this command line flag.
// TODO(b/159825227): remove when the "old" video decoder is fully launched.
@@ -96,7 +97,8 @@ absl::optional<uint32_t> GetDeadlineToSynchronizeSurfaces() {
int GetDocumentTransitionSlowDownFactor() {
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
- if (!command_line->HasSwitch(kDocumentTransitionSlowdownFactor))
+ if (!command_line ||
+ !command_line->HasSwitch(kDocumentTransitionSlowdownFactor))
return 1;
auto factor_str =
diff --git a/chromium/components/viz/common/switches.h b/chromium/components/viz/common/switches.h
index 64490ee8275..6ac91e6a5f0 100644
--- a/chromium/components/viz/common/switches.h
+++ b/chromium/components/viz/common/switches.h
@@ -7,6 +7,7 @@
#include <stdint.h>
+#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "components/viz/common/viz_common_export.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
@@ -21,9 +22,8 @@ VIZ_COMMON_EXPORT extern const char kDocumentTransitionSlowdownFactor[];
VIZ_COMMON_EXPORT extern const char kDoubleBufferCompositing[];
VIZ_COMMON_EXPORT extern const char kEnableDeJelly[];
VIZ_COMMON_EXPORT extern const char kEnableHardwareOverlays[];
-VIZ_COMMON_EXPORT extern const char kEnableVizHitTestDebug[];
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS)
VIZ_COMMON_EXPORT extern const char
kPlatformDisallowsChromeOSDirectVideoDecoder[];
#endif
diff --git a/chromium/components/viz/common/viz_utils.cc b/chromium/components/viz/common/viz_utils.cc
index 8d3aa5c45ca..4de5eb123a9 100644
--- a/chromium/components/viz/common/viz_utils.cc
+++ b/chromium/components/viz/common/viz_utils.cc
@@ -9,17 +9,18 @@
#include "base/command_line.h"
#include "base/system/sys_info.h"
+#include "build/build_config.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rrect_f.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include <array>
#include <string>
#include "base/android/build_info.h"
#endif
-#if defined(OS_POSIX)
+#if BUILDFLAG(IS_POSIX)
#include <poll.h>
#include <sys/resource.h>
#endif
@@ -27,14 +28,14 @@
namespace viz {
bool PreferRGB565ResourcesForDisplay() {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
return base::SysInfo::AmountOfPhysicalMemoryMB() <= 512;
#else
return false;
#endif
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
bool AlwaysUseWideColorGamut() {
// Full stack integration tests draw in sRGB and expect to read back in sRGB.
// WideColorGamut causes pixels to be drawn in P3, but read back doesn't tell
@@ -115,9 +116,9 @@ bool GatherFDStats(base::TimeDelta* delta_time_taken,
int* fd_max,
int* active_fd_count,
int* rlim_cur) {
-#if !defined(OS_POSIX)
+#if !BUILDFLAG(IS_POSIX)
return false;
-#else // defined(OS_POSIX)
+#else // BUILDFLAG(IS_POSIX)
// https://stackoverflow.com/questions/7976769/
// getting-count-of-current-used-file-descriptors-from-c-code
base::ElapsedTimer timer;
@@ -145,7 +146,7 @@ bool GatherFDStats(base::TimeDelta* delta_time_taken,
}
*delta_time_taken = timer.Elapsed();
return true;
-#endif // defined(OS_POSIX)
+#endif // BUILDFLAG(IS_POSIX)
}
} // namespace viz
diff --git a/chromium/components/viz/common/viz_utils.h b/chromium/components/viz/common/viz_utils.h
index b0ef766f78d..008f1224b8b 100644
--- a/chromium/components/viz/common/viz_utils.h
+++ b/chromium/components/viz/common/viz_utils.h
@@ -20,7 +20,7 @@ namespace viz {
VIZ_COMMON_EXPORT bool PreferRGB565ResourcesForDisplay();
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
VIZ_COMMON_EXPORT bool AlwaysUseWideColorGamut();
#endif
diff --git a/chromium/components/viz/common/yuv_readback_unittest.cc b/chromium/components/viz/common/yuv_readback_unittest.cc
index acb96fdbed1..5cf43adb162 100644
--- a/chromium/components/viz/common/yuv_readback_unittest.cc
+++ b/chromium/components/viz/common/yuv_readback_unittest.cc
@@ -25,7 +25,7 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkBitmap.h"
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
namespace viz {
@@ -113,7 +113,7 @@ class YUVReadbackTest : public testing::Test {
<< json_data;
CHECK(parsed_json.value->is_list());
- for (const base::Value& dict : parsed_json.value->GetList()) {
+ for (const base::Value& dict : parsed_json.value->GetListDeprecated()) {
CHECK(dict.is_dict());
const std::string* name = dict.FindStringPath("name");
CHECK(name);
diff --git a/chromium/components/viz/demo/demo_main.cc b/chromium/components/viz/demo/demo_main.cc
index d3311a2c5bf..db021f9870f 100644
--- a/chromium/components/viz/demo/demo_main.cc
+++ b/chromium/components/viz/demo/demo_main.cc
@@ -31,7 +31,7 @@
#include "ui/ozone/public/surface_factory_ozone.h"
#endif
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include "ui/platform_window/win/win_window.h"
#endif
@@ -121,7 +121,7 @@ class DemoWindow : public ui::PlatformWindowDelegate {
#if defined(USE_OZONE)
return ui::OzonePlatform::GetInstance()->CreatePlatformWindow(
this, std::move(props));
-#elif defined(OS_WIN)
+#elif BUILDFLAG(IS_WIN)
return std::make_unique<ui::WinWindow>(this, props.bounds);
#else
NOTIMPLEMENTED();
diff --git a/chromium/components/viz/host/client_frame_sink_video_capturer.cc b/chromium/components/viz/host/client_frame_sink_video_capturer.cc
index 439626a0ef5..f002e6ae69e 100644
--- a/chromium/components/viz/host/client_frame_sink_video_capturer.cc
+++ b/chromium/components/viz/host/client_frame_sink_video_capturer.cc
@@ -74,8 +74,19 @@ void ClientFrameSinkVideoCapturer::ChangeTarget(
const absl::optional<VideoCaptureTarget>& target) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ ChangeTarget(target, crop_version_);
+}
+
+void ClientFrameSinkVideoCapturer::ChangeTarget(
+ const absl::optional<VideoCaptureTarget>& target,
+ uint32_t crop_version) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK_GE(crop_version, crop_version_);
+
target_ = target;
- capturer_remote_->ChangeTarget(target);
+ crop_version_ = crop_version;
+
+ capturer_remote_->ChangeTarget(target, crop_version);
}
void ClientFrameSinkVideoCapturer::Start(
@@ -154,6 +165,12 @@ void ClientFrameSinkVideoCapturer::OnFrameCaptured(
std::move(callbacks));
}
+void ClientFrameSinkVideoCapturer::OnFrameWithEmptyRegionCapture() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ consumer_->OnFrameWithEmptyRegionCapture();
+}
+
void ClientFrameSinkVideoCapturer::OnLog(const std::string& message) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -189,7 +206,7 @@ void ClientFrameSinkVideoCapturer::EstablishConnection() {
if (auto_throttling_enabled_)
capturer_remote_->SetAutoThrottlingEnabled(*auto_throttling_enabled_);
if (target_) {
- capturer_remote_->ChangeTarget(target_.value());
+ capturer_remote_->ChangeTarget(target_.value(), crop_version_);
}
for (Overlay* overlay : overlays_)
overlay->EstablishConnection(capturer_remote_.get());
diff --git a/chromium/components/viz/host/client_frame_sink_video_capturer.h b/chromium/components/viz/host/client_frame_sink_video_capturer.h
index d9b4d099941..6775aea4a58 100644
--- a/chromium/components/viz/host/client_frame_sink_video_capturer.h
+++ b/chromium/components/viz/host/client_frame_sink_video_capturer.h
@@ -88,6 +88,8 @@ class VIZ_HOST_EXPORT ClientFrameSinkVideoCapturer
bool use_fixed_aspect_ratio);
void SetAutoThrottlingEnabled(bool enabled);
void ChangeTarget(const absl::optional<VideoCaptureTarget>& target);
+ void ChangeTarget(const absl::optional<VideoCaptureTarget>& target,
+ uint32_t crop_version);
void Stop();
void RequestRefreshFrame();
@@ -123,6 +125,7 @@ class VIZ_HOST_EXPORT ClientFrameSinkVideoCapturer
const gfx::Rect& content_rect,
mojo::PendingRemote<mojom::FrameSinkVideoConsumerFrameCallbacks>
callbacks) final;
+ void OnFrameWithEmptyRegionCapture() final;
void OnStopped() final;
void OnLog(const std::string& message) final;
// Establishes connection to FrameSinkVideoCapturer and sends the existing
@@ -149,6 +152,7 @@ class VIZ_HOST_EXPORT ClientFrameSinkVideoCapturer
absl::optional<ResolutionConstraints> resolution_constraints_;
absl::optional<bool> auto_throttling_enabled_;
absl::optional<VideoCaptureTarget> target_;
+ uint32_t crop_version_ = 0;
// Overlays are owned by the callers of CreateOverlay().
std::vector<Overlay*> overlays_;
bool is_started_ = false;
diff --git a/chromium/components/viz/host/gpu_host_impl.cc b/chromium/components/viz/host/gpu_host_impl.cc
index 8c27165ff61..2576300b384 100644
--- a/chromium/components/viz/host/gpu_host_impl.cc
+++ b/chromium/components/viz/host/gpu_host_impl.cc
@@ -26,13 +26,13 @@
#include "mojo/public/cpp/bindings/sync_call_restrictions.h"
#include "ui/gfx/font_render_params.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "base/android/build_info.h"
#endif
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include "ui/gfx/win/rendering_window_manager.h"
-#elif defined(OS_MAC)
+#elif BUILDFLAG(IS_MAC)
#include "ui/accelerated_widget_mac/window_resize_helper_mac.h"
#endif
@@ -107,8 +107,8 @@ GpuHostImpl::GpuHostImpl(Delegate* delegate,
params_(std::move(params)) {
// Create a special GPU info collection service if the GPU process is used for
// info collection only.
-#if defined(OS_WIN)
- if (params.info_collection_gpu_process) {
+#if BUILDFLAG(IS_WIN)
+ if (params_.info_collection_gpu_process) {
viz_main_->CreateInfoCollectionGpuService(
info_collection_gpu_service_remote_.BindNewPipeAndPassReceiver());
return;
@@ -124,12 +124,12 @@ GpuHostImpl::GpuHostImpl(Delegate* delegate,
DCHECK(GetFontRenderParams().Get());
scoped_refptr<base::SequencedTaskRunner> task_runner = nullptr;
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
if (params_.main_thread_task_runner->BelongsToCurrentThread())
task_runner = ui::WindowResizeHelperMac::Get()->task_runner();
#endif
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
viz_main_->SetHostProcessId(base::GetCurrentProcId());
#endif
@@ -330,7 +330,7 @@ mojom::GpuService* GpuHostImpl::gpu_service() {
return gpu_service_remote_.get();
}
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
mojom::InfoCollectionGpuService* GpuHostImpl::info_collection_gpu_service() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(info_collection_gpu_service_remote_.is_bound());
@@ -374,7 +374,7 @@ std::string GpuHostImpl::GetShaderPrefixKey() {
info.gl_renderer + "-" + active_gpu.driver_version +
"-" + active_gpu.driver_vendor;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
std::string build_fp =
base::android::BuildInfo::GetInstance()->android_build_fp();
shader_prefix_key_ += "-" + build_fp;
@@ -476,12 +476,7 @@ void GpuHostImpl::DidInitialize(
if (!params_.disable_gpu_shader_disk_cache) {
CreateChannelCache(gpu::kDisplayCompositorClientId);
-
- bool use_gr_shader_cache = base::FeatureList::IsEnabled(
- features::kDefaultEnableOopRasterization) ||
- features::IsUsingSkiaRenderer();
- if (use_gr_shader_cache)
- CreateChannelCache(gpu::kGrShaderCacheClientId);
+ CreateChannelCache(gpu::kGrShaderCacheClientId);
}
}
@@ -569,7 +564,7 @@ void GpuHostImpl::DidUpdateGPUInfo(const gpu::GPUInfo& gpu_info) {
delegate_->DidUpdateGPUInfo(gpu_info);
}
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
void GpuHostImpl::DidUpdateOverlayInfo(const gpu::OverlayInfo& overlay_info) {
delegate_->DidUpdateOverlayInfo(overlay_info);
}
@@ -585,7 +580,7 @@ void GpuHostImpl::SetChildSurface(gpu::SurfaceHandle parent,
parent, child, /*expected_child_process_id=*/pid_);
}
}
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
void GpuHostImpl::StoreShaderToDisk(int32_t client_id,
const std::string& key,
diff --git a/chromium/components/viz/host/gpu_host_impl.h b/chromium/components/viz/host/gpu_host_impl.h
index 9a8615786eb..5b380c906e8 100644
--- a/chromium/components/viz/host/gpu_host_impl.h
+++ b/chromium/components/viz/host/gpu_host_impl.h
@@ -40,7 +40,7 @@
#include "ui/gfx/gpu_extra_info.h"
#include "url/gurl.h"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include "services/viz/privileged/mojom/gl/info_collection_gpu_service.mojom.h"
#endif
@@ -77,7 +77,7 @@ class VIZ_HOST_EXPORT GpuHostImpl : public mojom::GpuHost
virtual void DidCreateContextSuccessfully() = 0;
virtual void MaybeShutdownGpuProcess() = 0;
virtual void DidUpdateGPUInfo(const gpu::GPUInfo& gpu_info) = 0;
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
virtual void DidUpdateOverlayInfo(const gpu::OverlayInfo& overlay_info) = 0;
virtual void DidUpdateHDRStatus(bool hdr_enabled) = 0;
#endif
@@ -202,7 +202,7 @@ class VIZ_HOST_EXPORT GpuHostImpl : public mojom::GpuHost
mojom::GpuService* gpu_service();
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
mojom::InfoCollectionGpuService* info_collection_gpu_service();
#endif
@@ -252,7 +252,7 @@ class VIZ_HOST_EXPORT GpuHostImpl : public mojom::GpuHost
const GURL& active_url) override;
void DisableGpuCompositing() override;
void DidUpdateGPUInfo(const gpu::GPUInfo& gpu_info) override;
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
void DidUpdateOverlayInfo(const gpu::OverlayInfo& overlay_info) override;
void DidUpdateHDRStatus(bool hdr_enabled) override;
void SetChildSurface(gpu::SurfaceHandle parent,
@@ -275,7 +275,7 @@ class VIZ_HOST_EXPORT GpuHostImpl : public mojom::GpuHost
const InitParams params_;
mojo::Remote<mojom::GpuService> gpu_service_remote_;
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
mojo::Remote<mojom::InfoCollectionGpuService>
info_collection_gpu_service_remote_;
#endif
diff --git a/chromium/components/viz/host/hit_test/hit_test_query.cc b/chromium/components/viz/host/hit_test/hit_test_query.cc
index 9ca5eba8860..25496aa235f 100644
--- a/chromium/components/viz/host/hit_test/hit_test_query.cc
+++ b/chromium/components/viz/host/hit_test/hit_test_query.cc
@@ -5,6 +5,8 @@
#include "components/viz/host/hit_test/hit_test_query.h"
#include <sstream>
+#include <string>
+#include <utility>
#include "base/containers/stack.h"
#include "base/metrics/histogram_macros.h"
@@ -50,8 +52,6 @@ const std::string GetFlagNames(uint32_t flag) {
names.emplace_back("Touch");
if (flag & kHitTestNotActive)
names.emplace_back("NotActive");
- if (flag & kHitTestDebug)
- names.emplace_back("Debug");
return base::JoinString(std::move(names), ", ");
}
diff --git a/chromium/components/viz/host/host_display_client.cc b/chromium/components/viz/host/host_display_client.cc
index 3b00759e513..d3970b4d86e 100644
--- a/chromium/components/viz/host/host_display_client.cc
+++ b/chromium/components/viz/host/host_display_client.cc
@@ -4,13 +4,14 @@
#include "components/viz/host/host_display_client.h"
+#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
#include "ui/accelerated_widget_mac/ca_layer_frame_sink.h"
#endif
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include <windows.h>
#include "components/viz/common/display/use_layered_window.h"
@@ -21,7 +22,7 @@
namespace viz {
HostDisplayClient::HostDisplayClient(gfx::AcceleratedWidget widget) {
-#if defined(OS_APPLE) || defined(OS_WIN)
+#if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_WIN)
widget_ = widget;
#endif
}
@@ -33,7 +34,7 @@ mojo::PendingRemote<mojom::DisplayClient> HostDisplayClient::GetBoundRemote(
return receiver_.BindNewPipeAndPassRemote(task_runner);
}
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
void HostDisplayClient::OnDisplayReceivedCALayerParams(
const gfx::CALayerParams& ca_layer_params) {
ui::CALayerFrameSink* ca_layer_frame_sink =
@@ -45,7 +46,7 @@ void HostDisplayClient::OnDisplayReceivedCALayerParams(
}
#endif
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
void HostDisplayClient::CreateLayeredWindowUpdater(
mojo::PendingReceiver<mojom::LayeredWindowUpdater> receiver) {
if (!NeedsToUseLayerWindow(widget_)) {
@@ -60,7 +61,7 @@ void HostDisplayClient::CreateLayeredWindowUpdater(
// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
// of lacros-chrome is complete.
-#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
void HostDisplayClient::DidCompleteSwapWithNewSize(const gfx::Size& size) {
NOTIMPLEMENTED();
}
diff --git a/chromium/components/viz/host/host_display_client.h b/chromium/components/viz/host/host_display_client.h
index b2ad84c881a..1c2885c42f4 100644
--- a/chromium/components/viz/host/host_display_client.h
+++ b/chromium/components/viz/host/host_display_client.h
@@ -36,28 +36,28 @@ class VIZ_HOST_EXPORT HostDisplayClient : public mojom::DisplayClient {
private:
// mojom::DisplayClient implementation:
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
void OnDisplayReceivedCALayerParams(
const gfx::CALayerParams& ca_layer_params) override;
#endif
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
void CreateLayeredWindowUpdater(
mojo::PendingReceiver<mojom::LayeredWindowUpdater> receiver) override;
#endif
// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
// of lacros-chrome is complete.
-#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
void DidCompleteSwapWithNewSize(const gfx::Size& size) override;
#endif
mojo::Receiver<mojom::DisplayClient> receiver_{this};
-#if defined(OS_APPLE) || defined(OS_WIN)
+#if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_WIN)
gfx::AcceleratedWidget widget_;
#endif
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
std::unique_ptr<LayeredWindowUpdaterImpl> layered_window_updater_;
#endif
};
diff --git a/chromium/components/viz/host/host_frame_sink_manager.cc b/chromium/components/viz/host/host_frame_sink_manager.cc
index 6da1186055b..a0f46cac7ec 100644
--- a/chromium/components/viz/host/host_frame_sink_manager.cc
+++ b/chromium/components/viz/host/host_frame_sink_manager.cc
@@ -216,13 +216,6 @@ void HostFrameSinkManager::OnFrameTokenChanged(
data.client->OnFrameTokenChanged(frame_token, activation_time);
}
-void HostFrameSinkManager::SetHitTestAsyncQueriedDebugRegions(
- const FrameSinkId& root_frame_sink_id,
- const std::vector<FrameSinkId>& hit_test_async_queried_debug_queue) {
- frame_sink_manager_->SetHitTestAsyncQueriedDebugRegions(
- root_frame_sink_id, hit_test_async_queried_debug_queue);
-}
-
bool HostFrameSinkManager::RegisterFrameSinkHierarchy(
const FrameSinkId& parent_frame_sink_id,
const FrameSinkId& child_frame_sink_id) {
diff --git a/chromium/components/viz/host/host_gpu_memory_buffer_manager_unittest.cc b/chromium/components/viz/host/host_gpu_memory_buffer_manager_unittest.cc
index cf1b42062c0..3da44d37dcd 100644
--- a/chromium/components/viz/host/host_gpu_memory_buffer_manager_unittest.cc
+++ b/chromium/components/viz/host/host_gpu_memory_buffer_manager_unittest.cc
@@ -27,7 +27,7 @@
#include "ui/ozone/public/ozone_platform.h"
#endif
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "base/android/android_hardware_buffer_compat.h"
#endif
@@ -119,6 +119,9 @@ class TestGpuService : public mojom::GpuService {
mojo::PendingReceiver<arc::mojom::VideoDecodeAccelerator> vda_receiver)
override {}
+ void CreateArcVideoDecoder(
+ mojo::PendingReceiver<arc::mojom::VideoDecoder> vd_receiver) override {}
+
void CreateArcVideoEncodeAccelerator(
mojo::PendingReceiver<arc::mojom::VideoEncodeAccelerator> vea_receiver)
override {}
@@ -141,7 +144,7 @@ class TestGpuService : public mojom::GpuService {
jea_receiver) override {}
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
void RegisterDCOMPSurfaceHandle(
mojo::PlatformHandle surface_handle,
RegisterDCOMPSurfaceHandleCallback callback) override {}
@@ -207,12 +210,12 @@ class TestGpuService : public mojom::GpuService {
void OnForegrounded() override {}
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
void OnMemoryPressure(
base::MemoryPressureListener::MemoryPressureLevel level) override {}
#endif
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
void BeginCATransaction() override {}
void CommitCATransaction(CommitCATransactionCallback callback) override {}
@@ -283,10 +286,10 @@ class HostGpuMemoryBufferManagerTest : public ::testing::Test {
native_pixmap_supported =
ui::OzonePlatform::GetInstance()->IsNativePixmapConfigSupported(
gfx::BufferFormat::RGBA_8888, gfx::BufferUsage::GPU_READ);
-#elif defined(OS_ANDROID)
+#elif BUILDFLAG(IS_ANDROID)
native_pixmap_supported =
base::AndroidHardwareBufferCompat::IsSupportAvailable();
-#elif defined(OS_APPLE) || defined(OS_WIN)
+#elif BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_WIN)
native_pixmap_supported = true;
#endif
diff --git a/chromium/components/viz/host/renderer_settings_creation.cc b/chromium/components/viz/host/renderer_settings_creation.cc
index d79f3beb580..6a830ec9f29 100644
--- a/chromium/components/viz/host/renderer_settings_creation.cc
+++ b/chromium/components/viz/host/renderer_settings_creation.cc
@@ -18,10 +18,6 @@
#include "components/viz/common/switches.h"
#include "ui/base/ui_base_switches.h"
-#if defined(OS_APPLE)
-#include "ui/base/cocoa/remote_layer_api.h"
-#endif
-
#if defined(USE_OZONE)
#include "ui/ozone/public/ozone_platform.h"
#endif
@@ -56,13 +52,13 @@ RendererSettings CreateRendererSettings() {
renderer_settings.partial_swap_enabled =
!command_line->HasSwitch(switches::kUIDisablePartialSwap);
-#if defined(OS_APPLE) || defined(OS_LINUX)
+#if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX)
// Simple frame rate throttling only works on macOS and Linux
renderer_settings.apply_simple_frame_rate_throttling =
features::IsSimpleFrameRateThrottlingEnabled();
#endif
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
renderer_settings.release_overlay_resources_after_gpu_query = true;
renderer_settings.auto_resize_output_surface = false;
#elif BUILDFLAG(IS_CHROMEOS_ASH)
@@ -71,12 +67,6 @@ RendererSettings CreateRendererSettings() {
renderer_settings.allow_antialiasing =
!command_line->HasSwitch(switches::kDisableCompositedAntialiasing);
renderer_settings.use_skia_renderer = features::IsUsingSkiaRenderer();
-#if defined(OS_APPLE)
- renderer_settings.allow_overlays =
- ui::RemoteLayerAPISupported() &&
- !base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableMacOverlays);
-#endif
if (command_line->HasSwitch(switches::kSlowDownCompositingScaleFactor)) {
const int kMinSlowDownScaleFactor = 1;
diff --git a/chromium/components/viz/service/BUILD.gn b/chromium/components/viz/service/BUILD.gn
index fae4aae8ed3..03a9986ff94 100644
--- a/chromium/components/viz/service/BUILD.gn
+++ b/chromium/components/viz/service/BUILD.gn
@@ -158,6 +158,9 @@ viz_component("service") {
"frame_sinks/frame_sink_manager_impl.cc",
"frame_sinks/frame_sink_manager_impl.h",
"frame_sinks/frame_sink_observer.h",
+ "frame_sinks/gmb_video_frame_pool_context_provider.h",
+ "frame_sinks/gmb_video_frame_pool_context_provider_impl.cc",
+ "frame_sinks/gmb_video_frame_pool_context_provider_impl.h",
"frame_sinks/gpu_vsync_begin_frame_source.cc",
"frame_sinks/gpu_vsync_begin_frame_source.h",
"frame_sinks/root_compositor_frame_sink_impl.cc",
@@ -169,6 +172,8 @@ viz_component("service") {
"frame_sinks/video_capture/frame_sink_video_capturer_impl.cc",
"frame_sinks/video_capture/frame_sink_video_capturer_impl.h",
"frame_sinks/video_capture/frame_sink_video_capturer_manager.h",
+ "frame_sinks/video_capture/gpu_memory_buffer_video_frame_pool.cc",
+ "frame_sinks/video_capture/gpu_memory_buffer_video_frame_pool.h",
"frame_sinks/video_capture/in_flight_frame_delivery.cc",
"frame_sinks/video_capture/in_flight_frame_delivery.h",
"frame_sinks/video_capture/shared_memory_video_frame_pool.cc",
@@ -299,8 +304,11 @@ viz_component("service") {
if (is_android || use_ozone) {
sources += [
+ "display/overlay_processor_strategy.cc",
+ "display/overlay_processor_strategy.h",
"display/overlay_processor_using_strategy.cc",
"display/overlay_processor_using_strategy.h",
+ "display/overlay_proposed_candidate.h",
"display/overlay_strategy_fullscreen.cc",
"display/overlay_strategy_fullscreen.h",
"display/overlay_strategy_single_on_top.cc",
@@ -331,19 +339,14 @@ viz_component("service") {
if (use_ozone) {
sources += [
+ "display/overlay_processor_delegated.cc",
+ "display/overlay_processor_delegated.h",
"display/overlay_processor_ozone.cc",
"display/overlay_processor_ozone.h",
"display_embedder/software_output_device_ozone.cc",
"display_embedder/software_output_device_ozone.h",
]
- if (is_chromeos_lacros) {
- sources += [
- "display/overlay_processor_delegated.cc",
- "display/overlay_processor_delegated.h",
- ]
- }
-
public_deps += [ "//ui/ozone" ]
}
@@ -487,8 +490,6 @@ viz_source_set("gpu_service_dependencies") {
sources += [
"display_embedder/skia_output_device_vulkan_secondary_cb.cc",
"display_embedder/skia_output_device_vulkan_secondary_cb.h",
- "display_embedder/skia_output_device_vulkan_secondary_cb_offscreen.cc",
- "display_embedder/skia_output_device_vulkan_secondary_cb_offscreen.h",
]
}
@@ -516,12 +517,12 @@ viz_source_set("gpu_service_dependencies") {
"display_embedder/skia_output_device_dawn.h",
]
- public_deps += [ "//third_party/dawn/src/dawn:dawn_headers" ]
+ public_deps += [ "//third_party/dawn/include/dawn:headers" ]
deps += [
- "//third_party/dawn/src/dawn:dawn_proc",
- "//third_party/dawn/src/dawn:dawncpp",
- "//third_party/dawn/src/dawn_native",
+ "//third_party/dawn/src/dawn:cpp",
+ "//third_party/dawn/src/dawn:proc",
+ "//third_party/dawn/src/dawn/native",
]
}
diff --git a/chromium/components/viz/service/DEPS b/chromium/components/viz/service/DEPS
index 53f869e4a10..b963bb7f144 100644
--- a/chromium/components/viz/service/DEPS
+++ b/chromium/components/viz/service/DEPS
@@ -18,9 +18,3 @@ include_rules = [
"+ui/ozone/buildflags.h",
"+ui/ozone/public",
]
-
-specific_include_rules = {
- "ExternalBeginFrameSourceAndroid.java": [
- "+ui/android/java/src/org/chromium/ui/VSyncMonitor.java",
- ]
-}
diff --git a/chromium/components/viz/service/debugger/viz_debugger.cc b/chromium/components/viz/service/debugger/viz_debugger.cc
index e695a5b71d6..54fd4bccac4 100644
--- a/chromium/components/viz/service/debugger/viz_debugger.cc
+++ b/chromium/components/viz/service/debugger/viz_debugger.cc
@@ -287,7 +287,7 @@ void VizDebugger::FilterDebugStream(base::Value json) {
new_filters_.clear();
- for (const auto& filter : filterlist->GetList()) {
+ for (const auto& filter : filterlist->GetListDeprecated()) {
const base::Value* file = filter.FindPath("selector.file");
const base::Value* func = filter.FindPath("selector.func");
const base::Value* anno = filter.FindPath("selector.anno");
diff --git a/chromium/components/viz/service/debugger/viz_debugger.h b/chromium/components/viz/service/debugger/viz_debugger.h
index 89859d04ad8..6e7a28a9ae4 100644
--- a/chromium/components/viz/service/debugger/viz_debugger.h
+++ b/chromium/components/viz/service/debugger/viz_debugger.h
@@ -7,6 +7,7 @@
#include <atomic>
#include <string>
+#include <tuple>
#include <utility>
#include <vector>
@@ -14,6 +15,7 @@
#include "base/strings/stringprintf.h"
#include "base/synchronization/lock.h"
#include "base/task/sequenced_task_runner.h"
+#include "base/threading/thread_checker.h"
#include "base/time/time.h"
#include "base/values.h"
#include "components/viz/common/buildflags.h"
@@ -316,30 +318,34 @@ class VIZ_SERVICE_EXPORT VizDebugger {
#define DBG_OPT_BLACK 0
#define DBG_DRAW_RECTANGLE_OPT(anno, option, pos, size) \
- ANALYZER_ALLOW_UNUSED(anno) \
- ANALYZER_ALLOW_UNUSED(option) \
- ANALYZER_ALLOW_UNUSED(pos) ANALYZER_ALLOW_UNUSED(size)
+ std::ignore = anno; \
+ std::ignore = option; \
+ std::ignore = pos; \
+ std::ignore = size;
#define DBG_DRAW_RECTANGLE(anno, pos, size) \
DBG_DRAW_RECTANGLE_OPT(anno, DBG_OPT_BLACK, pos, size)
#define DBG_DRAW_TEXT_OPT(anno, option, pos, text) \
- ANALYZER_ALLOW_UNUSED(anno) \
- ANALYZER_ALLOW_UNUSED(option) \
- ANALYZER_ALLOW_UNUSED(pos) ANALYZER_ALLOW_UNUSED(text)
+ std::ignore = anno; \
+ std::ignore = option; \
+ std::ignore = pos; \
+ std::ignore = text;
#define DBG_DRAW_TEXT(anno, pos, text) \
DBG_DRAW_TEXT_OPT(anno, DBG_OPT_BLACK, pos, text)
#define DBG_LOG_OPT(anno, option, format, ...) \
- ANALYZER_ALLOW_UNUSED(anno) \
- ANALYZER_ALLOW_UNUSED(option) ANALYZER_ALLOW_UNUSED(format)
+ std::ignore = anno; \
+ std::ignore = option; \
+ std::ignore = format;
#define DBG_LOG(anno, format, ...) DBG_LOG_OPT(anno, DBG_OPT_BLACK, format, ...)
#define DBG_DRAW_RECT_OPT(anno, option, rect) \
- ANALYZER_ALLOW_UNUSED(anno) \
- ANALYZER_ALLOW_UNUSED(option) ANALYZER_ALLOW_UNUSED(rect)
+ std::ignore = anno; \
+ std::ignore = option; \
+ std::ignore = rect;
#define DBG_DRAW_RECT(anno, rect) DBG_DRAW_RECT_OPT(anno, DBG_OPT_BLACK, rect)
diff --git a/chromium/components/viz/service/debugger/viz_debugger_unittest.cc b/chromium/components/viz/service/debugger/viz_debugger_unittest.cc
index c870b4e78da..557efde9ab6 100644
--- a/chromium/components/viz/service/debugger/viz_debugger_unittest.cc
+++ b/chromium/components/viz/service/debugger/viz_debugger_unittest.cc
@@ -137,8 +137,8 @@ class VisualDebuggerTest : public testing::Test {
base::Value* list_source = global_dict->FindListKey("new_sources");
EXPECT_TRUE(list_source->is_list());
- for (size_t i = 0; i < list_source->GetList().size(); i++) {
- auto&& local_dict = list_source->GetList()[i];
+ for (size_t i = 0; i < list_source->GetListDeprecated().size(); i++) {
+ auto&& local_dict = list_source->GetListDeprecated()[i];
StaticSource ss;
ss.file = local_dict.FindKey("file")->GetString();
ss.func = local_dict.FindKey("func")->GetString();
@@ -172,8 +172,8 @@ class VisualDebuggerTest : public testing::Test {
option_dict->FindKey("alpha")->GetIfInt().value_or(kNoVal));
};
- for (size_t i = 0; i < draw_call_list->GetList().size(); i++) {
- const base::Value& local_dict = draw_call_list->GetList()[i];
+ for (size_t i = 0; i < draw_call_list->GetListDeprecated().size(); i++) {
+ const base::Value& local_dict = draw_call_list->GetListDeprecated()[i];
int draw_index;
int source_index;
VizDebugger::DrawOption option;
@@ -181,13 +181,17 @@ class VisualDebuggerTest : public testing::Test {
const base::Value* list_size = local_dict.FindListKey("size");
EXPECT_TRUE(list_size->is_list());
- int size_x = list_size->GetList()[0].GetIfInt().value_or(kNoVal);
- int size_y = list_size->GetList()[1].GetIfInt().value_or(kNoVal);
+ int size_x =
+ list_size->GetListDeprecated()[0].GetIfInt().value_or(kNoVal);
+ int size_y =
+ list_size->GetListDeprecated()[1].GetIfInt().value_or(kNoVal);
const base::Value* list_pos = local_dict.FindListKey("pos");
EXPECT_TRUE(list_pos->is_list());
- float pos_x = list_pos->GetList()[0].GetIfDouble().value_or(kNoVal);
- float pos_y = list_pos->GetList()[1].GetIfDouble().value_or(kNoVal);
+ float pos_x =
+ list_pos->GetListDeprecated()[0].GetIfDouble().value_or(kNoVal);
+ float pos_y =
+ list_pos->GetListDeprecated()[1].GetIfDouble().value_or(kNoVal);
VizDebuggerInternal::DrawCall draw_call(draw_index, source_index, option,
gfx::Size(size_x, size_y),
@@ -199,8 +203,8 @@ class VisualDebuggerTest : public testing::Test {
base::Value* text_call_list = global_dict->FindListKey("text");
EXPECT_TRUE(text_call_list->is_list());
- for (size_t i = 0; i < text_call_list->GetList().size(); i++) {
- const base::Value& local_dict = text_call_list->GetList()[i];
+ for (size_t i = 0; i < text_call_list->GetListDeprecated().size(); i++) {
+ const base::Value& local_dict = text_call_list->GetListDeprecated()[i];
int draw_index;
int source_index;
VizDebugger::DrawOption option;
@@ -209,8 +213,10 @@ class VisualDebuggerTest : public testing::Test {
const base::Value* list_pos = local_dict.FindListKey("pos");
EXPECT_TRUE(list_pos->is_list());
- float pos_x = list_pos->GetList()[0].GetIfDouble().value_or(kNoVal);
- float pos_y = list_pos->GetList()[1].GetIfDouble().value_or(kNoVal);
+ float pos_x =
+ list_pos->GetListDeprecated()[0].GetIfDouble().value_or(kNoVal);
+ float pos_y =
+ list_pos->GetListDeprecated()[1].GetIfDouble().value_or(kNoVal);
VizDebuggerInternal::DrawTextCall text_call(
draw_index, source_index, option, gfx::Vector2dF(pos_x, pos_y),
@@ -222,8 +228,8 @@ class VisualDebuggerTest : public testing::Test {
base::Value* log_call_list = global_dict->FindListKey("logs");
EXPECT_TRUE(log_call_list->is_list());
- for (size_t i = 0; i < log_call_list->GetList().size(); i++) {
- const base::Value& local_dict = log_call_list->GetList()[i];
+ for (size_t i = 0; i < log_call_list->GetListDeprecated().size(); i++) {
+ const base::Value& local_dict = log_call_list->GetListDeprecated()[i];
int draw_index;
int source_index;
VizDebugger::DrawOption option;
diff --git a/chromium/components/viz/service/display/ca_layer_overlay.cc b/chromium/components/viz/service/display/ca_layer_overlay.cc
index a834b3d264b..5fb2f36463f 100644
--- a/chromium/components/viz/service/display/ca_layer_overlay.cc
+++ b/chromium/components/viz/service/display/ca_layer_overlay.cc
@@ -17,6 +17,7 @@
#include "components/viz/service/display/display_resource_provider.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "third_party/skia/include/core/SkDeferredDisplayList.h"
+#include "ui/base/cocoa/remote_layer_api.h"
namespace viz {
@@ -36,47 +37,11 @@ constexpr size_t kTooManyQuads = 128;
// https://crbug.com/636884.
const int kTooManyRenderPassDrawQuads = 30;
-// This enum is used for histogram states and should only have new values added
-// to the end before COUNT. tools/metrics/histograms/enums.xml should be updated
-// together.
-enum CALayerResult {
- CA_LAYER_SUCCESS = 0,
- CA_LAYER_FAILED_UNKNOWN = 1,
- // CA_LAYER_FAILED_IO_SURFACE_NOT_CANDIDATE = 2,
- CA_LAYER_FAILED_STREAM_VIDEO_NOT_CANDIDATE = 3,
- // CA_LAYER_FAILED_STREAM_VIDEO_TRANSFORM = 4,
- CA_LAYER_FAILED_TEXTURE_NOT_CANDIDATE = 5,
- // CA_LAYER_FAILED_TEXTURE_Y_FLIPPED = 6,
- CA_LAYER_FAILED_TILE_NOT_CANDIDATE = 7,
- CA_LAYER_FAILED_QUAD_BLEND_MODE = 8,
- // CA_LAYER_FAILED_QUAD_TRANSFORM = 9,
- CA_LAYER_FAILED_QUAD_CLIPPING = 10,
- CA_LAYER_FAILED_DEBUG_BORDER = 11,
- CA_LAYER_FAILED_PICTURE_CONTENT = 12,
- // CA_LAYER_FAILED_RENDER_PASS = 13,
- CA_LAYER_FAILED_SURFACE_CONTENT = 14,
- // CA_LAYER_FAILED_YUV_VIDEO_CONTENT = 15,
- CA_LAYER_FAILED_DIFFERENT_CLIP_SETTINGS = 16,
- CA_LAYER_FAILED_DIFFERENT_VERTEX_OPACITIES = 17,
- // CA_LAYER_FAILED_RENDER_PASS_FILTER_SCALE = 18,
- CA_LAYER_FAILED_RENDER_PASS_BACKDROP_FILTERS = 19,
- CA_LAYER_FAILED_RENDER_PASS_MASK = 20,
- CA_LAYER_FAILED_RENDER_PASS_FILTER_OPERATION = 21,
- CA_LAYER_FAILED_RENDER_PASS_SORTING_CONTEXT_ID = 22,
- CA_LAYER_FAILED_TOO_MANY_RENDER_PASS_DRAW_QUADS = 23,
- // CA_LAYER_FAILED_QUAD_ROUNDED_CORNER = 24,
- CA_LAYER_FAILED_QUAD_ROUNDED_CORNER_CLIP_MISMATCH = 25,
- CA_LAYER_FAILED_QUAD_ROUNDED_CORNER_NOT_UNIFORM = 26,
- CA_LAYER_FAILED_TOO_MANY_QUADS = 27,
- CA_LAYER_FAILED_YUV_NOT_CANDIDATE = 28,
- CA_LAYER_FAILED_Y_UV_TEXCOORD_MISMATCH = 29,
- CA_LAYER_FAILED_YUV_INVALID_PLANES = 30,
- CA_LAYER_FAILED_COPY_REQUESTS = 31,
- CA_LAYER_FAILED_OVERLAY_DISABLED = 32,
- kMaxValue = CA_LAYER_FAILED_OVERLAY_DISABLED,
-};
+// Assume we are in a video conference if the total video count is bigger than
+// or equal to this number.
+const int kMaxNumVideos = 5;
-void RecordCALayerHistogram(CALayerResult result) {
+void RecordCALayerHistogram(gfx::CALayerResult result) {
UMA_HISTOGRAM_ENUMERATION("Compositing.Renderer.CALayerResult", result);
}
@@ -98,7 +63,7 @@ bool FilterOperationSupported(const cc::FilterOperation& operation) {
}
}
-CALayerResult FromRenderPassQuad(
+gfx::CALayerResult FromRenderPassQuad(
DisplayResourceProvider* resource_provider,
const AggregatedRenderPassDrawQuad* quad,
const base::flat_map<AggregatedRenderPassId, cc::FilterOperations*>&
@@ -107,70 +72,71 @@ CALayerResult FromRenderPassQuad(
render_pass_backdrop_filters,
CALayerOverlay* ca_layer_overlay) {
if (render_pass_backdrop_filters.count(quad->render_pass_id)) {
- return CA_LAYER_FAILED_RENDER_PASS_BACKDROP_FILTERS;
+ return gfx::kCALayerFailedRenderPassBackdropFilters;
}
auto* shared_quad_state = quad->shared_quad_state;
if (shared_quad_state->sorting_context_id != 0)
- return CA_LAYER_FAILED_RENDER_PASS_SORTING_CONTEXT_ID;
+ return gfx::kCALayerFailedRenderPassSortingContextId;
auto it = render_pass_filters.find(quad->render_pass_id);
if (it != render_pass_filters.end()) {
for (const auto& operation : it->second->operations()) {
bool success = FilterOperationSupported(operation);
if (!success)
- return CA_LAYER_FAILED_RENDER_PASS_FILTER_OPERATION;
+ return gfx::kCALayerFailedRenderPassFilterOperation;
}
}
// TODO(crbug.com/1215491): support not 2d axis aligned clipping.
if (shared_quad_state->clip_rect &&
!shared_quad_state->quad_to_target_transform.Preserves2dAxisAlignment()) {
- return CA_LAYER_FAILED_QUAD_CLIPPING;
+ return gfx::kCALayerFailedQuadClipping;
}
// TODO(crbug.com/1215491): support not 2d axis aligned mask.
if (!shared_quad_state->mask_filter_info.IsEmpty() &&
!shared_quad_state->quad_to_target_transform.Preserves2dAxisAlignment()) {
- return CA_LAYER_FAILED_RENDER_PASS_MASK;
+ return gfx::kCALayerFailedRenderPassPassMask;
}
ca_layer_overlay->rpdq = quad;
ca_layer_overlay->contents_rect = gfx::RectF(0, 0, 1, 1);
- return CA_LAYER_SUCCESS;
+ return gfx::kCALayerSuccess;
}
-CALayerResult FromStreamVideoQuad(DisplayResourceProvider* resource_provider,
- const StreamVideoDrawQuad* quad,
- CALayerOverlay* ca_layer_overlay) {
+gfx::CALayerResult FromStreamVideoQuad(
+ DisplayResourceProvider* resource_provider,
+ const StreamVideoDrawQuad* quad,
+ CALayerOverlay* ca_layer_overlay) {
ResourceId resource_id = quad->resource_id();
if (!resource_provider->IsOverlayCandidate(resource_id))
- return CA_LAYER_FAILED_STREAM_VIDEO_NOT_CANDIDATE;
+ return gfx::kCALayerFailedStreamVideoNotCandidate;
ca_layer_overlay->contents_resource_id = resource_id;
ca_layer_overlay->contents_rect =
BoundingRect(quad->uv_top_left, quad->uv_bottom_right);
- return CA_LAYER_SUCCESS;
+ return gfx::kCALayerSuccess;
}
-CALayerResult FromSolidColorDrawQuad(const SolidColorDrawQuad* quad,
- CALayerOverlay* ca_layer_overlay,
- bool* skip) {
+gfx::CALayerResult FromSolidColorDrawQuad(const SolidColorDrawQuad* quad,
+ CALayerOverlay* ca_layer_overlay,
+ bool* skip) {
// Do not generate quads that are completely transparent.
if (SkColorGetA(quad->color) == 0) {
*skip = true;
- return CA_LAYER_SUCCESS;
+ return gfx::kCALayerSuccess;
}
ca_layer_overlay->background_color = quad->color;
- return CA_LAYER_SUCCESS;
+ return gfx::kCALayerSuccess;
}
-CALayerResult FromTextureQuad(DisplayResourceProvider* resource_provider,
- const TextureDrawQuad* quad,
- CALayerOverlay* ca_layer_overlay) {
+gfx::CALayerResult FromTextureQuad(DisplayResourceProvider* resource_provider,
+ const TextureDrawQuad* quad,
+ CALayerOverlay* ca_layer_overlay) {
ResourceId resource_id = quad->resource_id();
if (!resource_provider->IsOverlayCandidate(resource_id))
- return CA_LAYER_FAILED_TEXTURE_NOT_CANDIDATE;
+ return gfx::kCALayerFailedTextureNotCandidate;
if (quad->y_flipped) {
// The anchor point is at the bottom-left corner of the CALayer. The
// transformation that flips the contents of the layer without changing its
@@ -186,16 +152,18 @@ CALayerResult FromTextureQuad(DisplayResourceProvider* resource_provider,
ca_layer_overlay->background_color = quad->background_color;
for (int i = 1; i < 4; ++i) {
if (quad->vertex_opacity[i] != quad->vertex_opacity[0])
- return CA_LAYER_FAILED_DIFFERENT_VERTEX_OPACITIES;
+ return gfx::kCALayerFailedDifferentVertexOpacities;
}
ca_layer_overlay->shared_state->opacity *= quad->vertex_opacity[0];
ca_layer_overlay->filter = quad->nearest_neighbor ? GL_NEAREST : GL_LINEAR;
- return CA_LAYER_SUCCESS;
+ if (quad->is_video_frame)
+ ca_layer_overlay->protected_video_type = quad->protected_video_type;
+ return gfx::kCALayerSuccess;
}
-CALayerResult FromYUVVideoQuad(DisplayResourceProvider* resource_provider,
- const YUVVideoDrawQuad* quad,
- CALayerOverlay* ca_layer_overlay) {
+gfx::CALayerResult FromYUVVideoQuad(DisplayResourceProvider* resource_provider,
+ const YUVVideoDrawQuad* quad,
+ CALayerOverlay* ca_layer_overlay) {
// For YUVVideoDrawQuads, the Y and UV planes alias the same underlying
// IOSurface. Ensure all planes are overlays and have the same contents
// rect. Then use the Y plane as the resource for the overlay.
@@ -203,12 +171,12 @@ CALayerResult FromYUVVideoQuad(DisplayResourceProvider* resource_provider,
if (!resource_provider->IsOverlayCandidate(y_resource_id) ||
!resource_provider->IsOverlayCandidate(quad->u_plane_resource_id()) ||
!resource_provider->IsOverlayCandidate(quad->v_plane_resource_id())) {
- return CA_LAYER_FAILED_YUV_NOT_CANDIDATE;
+ return gfx::kCALayerFailedYUVNotCandidate;
}
if (quad->y_plane_resource_id() == quad->u_plane_resource_id() ||
quad->y_plane_resource_id() == quad->v_plane_resource_id() ||
quad->u_plane_resource_id() != quad->v_plane_resource_id()) {
- return CA_LAYER_FAILED_YUV_INVALID_PLANES;
+ return gfx::kCALayerFailedYUVInvalidPlanes;
}
gfx::RectF ya_contents_rect =
@@ -218,29 +186,30 @@ CALayerResult FromYUVVideoQuad(DisplayResourceProvider* resource_provider,
gfx::ScaleRect(quad->uv_tex_coord_rect, 1.f / quad->uv_tex_size.width(),
1.f / quad->uv_tex_size.height());
if (ya_contents_rect != uv_contents_rect)
- return CA_LAYER_FAILED_Y_UV_TEXCOORD_MISMATCH;
+ return gfx::kCALayerFailedYUVTexcoordMismatch;
ca_layer_overlay->contents_resource_id = y_resource_id;
ca_layer_overlay->contents_rect = ya_contents_rect;
- return CA_LAYER_SUCCESS;
+ ca_layer_overlay->protected_video_type = quad->protected_video_type;
+ return gfx::kCALayerSuccess;
}
-CALayerResult FromTileQuad(DisplayResourceProvider* resource_provider,
- const TileDrawQuad* quad,
- CALayerOverlay* ca_layer_overlay) {
+gfx::CALayerResult FromTileQuad(DisplayResourceProvider* resource_provider,
+ const TileDrawQuad* quad,
+ CALayerOverlay* ca_layer_overlay) {
ResourceId resource_id = quad->resource_id();
if (!resource_provider->IsOverlayCandidate(resource_id))
- return CA_LAYER_FAILED_TILE_NOT_CANDIDATE;
+ return gfx::kCALayerFailedTileNotCandidate;
ca_layer_overlay->contents_resource_id = resource_id;
ca_layer_overlay->contents_rect = quad->tex_coord_rect;
ca_layer_overlay->contents_rect.Scale(1.f / quad->texture_size.width(),
1.f / quad->texture_size.height());
ca_layer_overlay->filter = quad->nearest_neighbor ? GL_NEAREST : GL_LINEAR;
- return CA_LAYER_SUCCESS;
+ return gfx::kCALayerSuccess;
}
class CALayerOverlayProcessorInternal {
public:
- CALayerResult FromDrawQuad(
+ gfx::CALayerResult FromDrawQuad(
DisplayResourceProvider* resource_provider,
const gfx::RectF& display_rect,
const DrawQuad* quad,
@@ -250,15 +219,16 @@ class CALayerOverlayProcessorInternal {
render_pass_backdrop_filters,
CALayerOverlay* ca_layer_overlay,
bool* skip,
- bool* render_pass_draw_quad) {
+ bool* render_pass_draw_quad,
+ int& yuv_draw_quad_count) {
if (quad->shared_quad_state->blend_mode != SkBlendMode::kSrcOver)
- return CA_LAYER_FAILED_QUAD_BLEND_MODE;
+ return gfx::kCALayerFailedQuadBlendMode;
// Early-out for invisible quads.
if (quad->shared_quad_state->opacity == 0.f ||
quad->visible_rect.IsEmpty()) {
*skip = true;
- return CA_LAYER_SUCCESS;
+ return gfx::kCALayerSuccess;
}
// Support rounded corner bounds when they have the same rect as the clip
@@ -270,7 +240,7 @@ class CALayerOverlayProcessorInternal {
DCHECK(quad->shared_quad_state->clip_rect);
if (quad->shared_quad_state->mask_filter_info.rounded_corner_bounds()
.GetType() > gfx::RRectF::Type::kSingle) {
- return CA_LAYER_FAILED_QUAD_ROUNDED_CORNER_NOT_UNIFORM;
+ return gfx::kCALayerFailedQuadRoundedCornerNotUniform;
}
}
@@ -321,21 +291,23 @@ class CALayerOverlayProcessorInternal {
return FromSolidColorDrawQuad(SolidColorDrawQuad::MaterialCast(quad),
ca_layer_overlay, skip);
case DrawQuad::Material::kStreamVideoContent:
+ yuv_draw_quad_count++;
return FromStreamVideoQuad(resource_provider,
StreamVideoDrawQuad::MaterialCast(quad),
ca_layer_overlay);
case DrawQuad::Material::kDebugBorder:
- return CA_LAYER_FAILED_DEBUG_BORDER;
+ return gfx::kCALayerFailedDebugBoarder;
case DrawQuad::Material::kPictureContent:
- return CA_LAYER_FAILED_PICTURE_CONTENT;
+ return gfx::kCALayerFailedPictureContent;
case DrawQuad::Material::kAggregatedRenderPass:
return FromRenderPassQuad(
resource_provider, AggregatedRenderPassDrawQuad::MaterialCast(quad),
render_pass_filters, render_pass_backdrop_filters,
ca_layer_overlay);
case DrawQuad::Material::kSurfaceContent:
- return CA_LAYER_FAILED_SURFACE_CONTENT;
+ return gfx::kCALayerFailedSurfaceContent;
case DrawQuad::Material::kYuvVideoContent:
+ yuv_draw_quad_count++;
return FromYUVVideoQuad(resource_provider,
YUVVideoDrawQuad::MaterialCast(quad),
ca_layer_overlay);
@@ -343,7 +315,7 @@ class CALayerOverlayProcessorInternal {
break;
}
- return CA_LAYER_FAILED_UNKNOWN;
+ return gfx::kCALayerFailedUnknown;
}
private:
@@ -351,6 +323,16 @@ class CALayerOverlayProcessorInternal {
scoped_refptr<CALayerOverlaySharedState> most_recent_overlay_shared_state_;
};
+// Control using the CoreAnimation renderer, which is the path that replaces
+// all quads with CALayers.
+base::Feature kCARenderer{"CoreAnimationRenderer",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+
+// Control using the CoreAnimation renderer, which is the path that replaces
+// all quads with CALayers.
+base::Feature kHDRUnderlays{"CoreAnimationHDRUnderlays",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+
} // namespace
CALayerOverlay::CALayerOverlay() : filter(GL_LINEAR) {}
@@ -362,8 +344,10 @@ CALayerOverlay::~CALayerOverlay() = default;
CALayerOverlay& CALayerOverlay::operator=(const CALayerOverlay& other) =
default;
-CALayerOverlayProcessor::CALayerOverlayProcessor(bool enable_ca_overlay)
- : enable_ca_overlay_(enable_ca_overlay) {
+CALayerOverlayProcessor::CALayerOverlayProcessor()
+ : overlays_allowed_(ui::RemoteLayerAPISupported()),
+ enable_ca_renderer_(base::FeatureList::IsEnabled(kCARenderer)),
+ enable_hdr_underlays_(base::FeatureList::IsEnabled(kHDRUnderlays)) {
max_quad_list_size_ = kTooManyQuads;
if (base::FeatureList::IsEnabled(features::kMacCAOverlayQuad)) {
const int max_num = features::kMacCAOverlayQuadMaxNum.Get();
@@ -416,10 +400,9 @@ void CALayerOverlayProcessor::PutForcedOverlayContentIntoUnderlays(
// Put hardware protected video into an overlay
if (quad->material == ContentDrawQuadBase::Material::kYuvVideoContent) {
const YUVVideoDrawQuad* video_quad = YUVVideoDrawQuad::MaterialCast(quad);
- if (video_quad->protected_video_type ==
- gfx::ProtectedVideoType::kHardwareProtected) {
+ if (video_quad->protected_video_type != gfx::ProtectedVideoType::kClear) {
force_quad_to_overlay = true;
- protected_video_type = gfx::ProtectedVideoType::kHardwareProtected;
+ protected_video_type = video_quad->protected_video_type;
}
}
@@ -427,14 +410,18 @@ void CALayerOverlayProcessor::PutForcedOverlayContentIntoUnderlays(
const TextureDrawQuad* texture_quad = TextureDrawQuad::MaterialCast(quad);
// Put hardware protected video into an overlay
- if (texture_quad->is_video_frame &&
- texture_quad->protected_video_type ==
- gfx::ProtectedVideoType::kHardwareProtected)
+ if (texture_quad->is_video_frame && texture_quad->protected_video_type !=
+ gfx::ProtectedVideoType::kClear) {
force_quad_to_overlay = true;
+ protected_video_type = texture_quad->protected_video_type;
+ }
- // Put HDR videos into an overlay
- if (resource_provider->GetColorSpace(texture_quad->resource_id()).IsHDR())
- force_quad_to_overlay = true;
+ // Put HDR videos into an underlay.
+ if (enable_hdr_underlays_) {
+ if (resource_provider->GetColorSpace(texture_quad->resource_id())
+ .IsHDR())
+ force_quad_to_overlay = true;
+ }
}
if (force_quad_to_overlay) {
@@ -461,19 +448,23 @@ bool CALayerOverlayProcessor::ProcessForCALayerOverlays(
render_pass_backdrop_filters,
CALayerOverlayList* ca_layer_overlays) {
const QuadList& quad_list = render_pass->quad_list;
- CALayerResult result = CA_LAYER_SUCCESS;
+ gfx::CALayerResult result = gfx::kCALayerSuccess;
size_t num_visible_quads = quad_list.size();
// Skip overlay processing
- if (!enable_ca_overlay_) {
- result = CA_LAYER_FAILED_OVERLAY_DISABLED;
+ if (!overlays_allowed_ || !enable_ca_renderer_) {
+ result = gfx::kCALayerFailedOverlayDisabled;
+ } else if (video_capture_enabled_) {
+ result = gfx::kCALayerFailedVideoCaptureEnabled;
} else if (!render_pass->copy_requests.empty()) {
- result = CA_LAYER_FAILED_COPY_REQUESTS;
+ result = gfx::kCALayerFailedCopyRequests;
} else if (num_visible_quads > max_quad_list_size_) {
- result = CA_LAYER_FAILED_TOO_MANY_QUADS;
+ // |max_quad_list_size_| might be set by finch and is bigger than
+ // kTooManyQuads (128).
+ result = gfx::kCALayerFailedTooManyQuads;
}
- if (result != CA_LAYER_SUCCESS) {
+ if (result != gfx::kCALayerSuccess) {
RecordCALayerHistogram(result);
SaveCALayerResult(result);
return false;
@@ -483,23 +474,26 @@ bool CALayerOverlayProcessor::ProcessForCALayerOverlays(
ca_layer_overlays->reserve(num_visible_quads);
int render_pass_draw_quad_count = 0;
+ int yuv_draw_quad_count = 0;
CALayerOverlayProcessorInternal processor;
for (auto it = quad_list.BackToFrontBegin();
- result == CA_LAYER_SUCCESS && it != quad_list.BackToFrontEnd(); ++it) {
+ result == gfx::kCALayerSuccess && it != quad_list.BackToFrontEnd();
+ ++it) {
const DrawQuad* quad = *it;
CALayerOverlay ca_layer;
bool skip = false;
bool render_pass_draw_quad = false;
result = processor.FromDrawQuad(
resource_provider, display_rect, quad, render_pass_filters,
- render_pass_backdrop_filters, &ca_layer, &skip, &render_pass_draw_quad);
- if (result != CA_LAYER_SUCCESS)
+ render_pass_backdrop_filters, &ca_layer, &skip, &render_pass_draw_quad,
+ yuv_draw_quad_count);
+ if (result != gfx::kCALayerSuccess)
break;
if (render_pass_draw_quad) {
++render_pass_draw_quad_count;
if (render_pass_draw_quad_count > kTooManyRenderPassDrawQuads) {
- result = CA_LAYER_FAILED_TOO_MANY_RENDER_PASS_DRAW_QUADS;
+ result = gfx::kCALayerFailedTooManyRenderPassDrawQuads;
break;
}
}
@@ -508,17 +502,25 @@ bool CALayerOverlayProcessor::ProcessForCALayerOverlays(
continue;
if (!AreClipSettingsValid(ca_layer, ca_layer_overlays)) {
- result = CA_LAYER_FAILED_DIFFERENT_CLIP_SETTINGS;
+ result = gfx::kCALayerFailedDifferentClipSettings;
break;
}
ca_layer_overlays->push_back(ca_layer);
}
+ // In the case of |max_quad_list_size_| > |num_visible_quads| > kTooManyQuads,
+ // Accept CALayerOverlay if in a video conference (video count >=
+ // kMaxNumVideos(5)). Otherwise, do not use CALayerOverlay.
+ if (num_visible_quads > kTooManyQuads &&
+ yuv_draw_quad_count < kMaxNumVideos) {
+ result = gfx::kCALayerFailedTooManyQuads;
+ }
+
RecordCALayerHistogram(result);
SaveCALayerResult(result);
- if (result != CA_LAYER_SUCCESS) {
+ if (result != gfx::kCALayerSuccess) {
ca_layer_overlays->clear();
return false;
}
@@ -541,10 +543,12 @@ bool CALayerOverlayProcessor::PutQuadInSeparateOverlay(
CALayerOverlay ca_layer;
bool skip = false;
bool render_pass_draw_quad = false;
- CALayerResult result = processor.FromDrawQuad(
+ int yuv_draw_quad_count = 0;
+ gfx::CALayerResult result = processor.FromDrawQuad(
resource_provider, display_rect, quad, render_pass_filters,
- render_pass_backdrop_filters, &ca_layer, &skip, &render_pass_draw_quad);
- if (result != CA_LAYER_SUCCESS)
+ render_pass_backdrop_filters, &ca_layer, &skip, &render_pass_draw_quad,
+ yuv_draw_quad_count);
+ if (result != gfx::kCALayerSuccess)
return false;
if (skip)
@@ -561,7 +565,7 @@ bool CALayerOverlayProcessor::PutQuadInSeparateOverlay(
}
// Expand this function to save the results of the last N frames.
-void CALayerOverlayProcessor::SaveCALayerResult(int result) {
+void CALayerOverlayProcessor::SaveCALayerResult(gfx::CALayerResult result) {
ca_layer_result_ = result;
}
diff --git a/chromium/components/viz/service/display/ca_layer_overlay.h b/chromium/components/viz/service/display/ca_layer_overlay.h
index 9c41055613e..2d0141d0293 100644
--- a/chromium/components/viz/service/display/ca_layer_overlay.h
+++ b/chromium/components/viz/service/display/ca_layer_overlay.h
@@ -16,6 +16,7 @@
#include "skia/ext/skia_matrix_44.h"
#include "third_party/skia/include/core/SkColor.h"
#include "third_party/skia/include/core/SkRefCnt.h"
+#include "ui/gfx/ca_layer_result.h"
#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/geometry/rrect_f.h"
#include "ui/gfx/video_types.h"
@@ -95,13 +96,15 @@ typedef std::vector<CALayerOverlay> CALayerOverlayList;
// CALayerOverlay into OverlayCandidate.
class VIZ_SERVICE_EXPORT CALayerOverlayProcessor {
public:
- explicit CALayerOverlayProcessor(bool enable_ca_overlay);
-
+ CALayerOverlayProcessor();
CALayerOverlayProcessor(const CALayerOverlayProcessor&) = delete;
CALayerOverlayProcessor& operator=(const CALayerOverlayProcessor&) = delete;
virtual ~CALayerOverlayProcessor() = default;
+ void SetIsVideoCaptureEnabled(bool enabled) {
+ video_capture_enabled_ = enabled;
+ }
bool AreClipSettingsValid(const CALayerOverlay& ca_layer_overlay,
CALayerOverlayList* ca_layer_overlay_list) const;
void PutForcedOverlayContentIntoUnderlays(
@@ -127,7 +130,7 @@ class VIZ_SERVICE_EXPORT CALayerOverlayProcessor {
render_pass_backdrop_filters,
CALayerOverlayList* ca_layer_overlays);
- int ca_layer_result() { return ca_layer_result_; }
+ gfx::CALayerResult ca_layer_result() { return ca_layer_result_; }
private:
// Returns whether future candidate quads should be considered
@@ -144,11 +147,27 @@ class VIZ_SERVICE_EXPORT CALayerOverlayProcessor {
gfx::ProtectedVideoType protected_video_type,
CALayerOverlayList* ca_layer_overlays) const;
- void SaveCALayerResult(int result);
+ void SaveCALayerResult(gfx::CALayerResult result);
+
+ // Set to false if the APIs required for overlays are not present, or the
+ // feature has been disabled.
+ const bool overlays_allowed_;
+
+ // Controls the feature of replacying all quads with overlays is enabled.
+ const bool enable_ca_renderer_;
+
+ // Controls the feature of putting HDR videos into underlays if the
+ // CARenderer fails (so that we can use the tone mapping provided by macOS).
+ const bool enable_hdr_underlays_;
+
+ // The CARenderer is disabled when video capture is enabled.
+ // https://crbug.com/836351, https://crbug.com/1290384
+ bool video_capture_enabled_ = false;
- const bool enable_ca_overlay_;
size_t max_quad_list_size_ = 0;
- int ca_layer_result_ = 0;
+
+ // The error code in ProcessForCALayerOverlays()
+ gfx::CALayerResult ca_layer_result_ = gfx::kCALayerSuccess;
};
} // namespace viz
diff --git a/chromium/components/viz/service/display/delegated_ink_point_renderer_base.cc b/chromium/components/viz/service/display/delegated_ink_point_renderer_base.cc
index fbb5e922922..b33677ac0da 100644
--- a/chromium/components/viz/service/display/delegated_ink_point_renderer_base.cc
+++ b/chromium/components/viz/service/display/delegated_ink_point_renderer_base.cc
@@ -124,13 +124,14 @@ void DelegatedInkPointRendererBase::PredictPoints(
void DelegatedInkPointRendererBase::ResetPrediction() {
for (auto& it : pointer_ids_)
it.second.Reset();
- TRACE_EVENT_INSTANT0("viz", "Delegated ink prediction reset.",
+ TRACE_EVENT_INSTANT0("delegated_ink_trails",
+ "Delegated ink prediction reset.",
TRACE_EVENT_SCOPE_THREAD);
}
void DelegatedInkPointRendererBase::StoreDelegatedInkPoint(
const gfx::DelegatedInkPoint& point) {
- TRACE_EVENT_INSTANT1("viz",
+ TRACE_EVENT_INSTANT1("delegated_ink_trails",
"DelegatedInkPointRendererImpl::StoreDelegatedInkPoint",
TRACE_EVENT_SCOPE_THREAD, "point", point.ToString());
diff --git a/chromium/components/viz/service/display/delegated_ink_point_renderer_base.h b/chromium/components/viz/service/display/delegated_ink_point_renderer_base.h
index 69206455ec6..3c48374acb3 100644
--- a/chromium/components/viz/service/display/delegated_ink_point_renderer_base.h
+++ b/chromium/components/viz/service/display/delegated_ink_point_renderer_base.h
@@ -29,7 +29,7 @@ namespace viz {
// sent from the browser process.
//
// For more information on the feature, please see the explainer:
-// https://github.com/WICG/ink-enhancement/blob/master/README.md
+// https://github.com/WICG/ink-enhancement/blob/main/README.md
class VIZ_SERVICE_EXPORT DelegatedInkPointRendererBase
: public gfx::mojom::DelegatedInkPointRenderer {
public:
diff --git a/chromium/components/viz/service/display/delegated_ink_point_renderer_skia.cc b/chromium/components/viz/service/display/delegated_ink_point_renderer_skia.cc
index c1408c214f7..588bf3e2a78 100644
--- a/chromium/components/viz/service/display/delegated_ink_point_renderer_skia.cc
+++ b/chromium/components/viz/service/display/delegated_ink_point_renderer_skia.cc
@@ -99,7 +99,7 @@ void DelegatedInkPointRendererSkia::FinalizePathForDraw() {
std::vector<SkPoint> sk_points = GetPointsToDraw();
- TRACE_EVENT_INSTANT1("viz",
+ TRACE_EVENT_INSTANT1("delegated_ink_trails",
"Filtered and predicted points for delegated ink trail",
TRACE_EVENT_SCOPE_THREAD, "points", sk_points.size());
@@ -143,9 +143,10 @@ void DelegatedInkPointRendererSkia::FinalizePathForDraw() {
damage_rect.Inset(-kRadius, -kRadius);
damage_rect.Intersect(metadata_->presentation_area());
- TRACE_EVENT_INSTANT1(
- "viz", "DelegatedInkPointRendererSkia::FinalizePathForDraw",
- TRACE_EVENT_SCOPE_THREAD, "damage_rect", damage_rect.ToString());
+ TRACE_EVENT_INSTANT1("delegated_ink_trails",
+ "DelegatedInkPointRendererSkia::FinalizePathForDraw",
+ TRACE_EVENT_SCOPE_THREAD, "damage_rect",
+ damage_rect.ToString());
SetDamageRect(damage_rect);
}
diff --git a/chromium/components/viz/service/display/delegated_ink_point_renderer_skia.h b/chromium/components/viz/service/display/delegated_ink_point_renderer_skia.h
index cebaf231d5a..203607ffd5a 100644
--- a/chromium/components/viz/service/display/delegated_ink_point_renderer_skia.h
+++ b/chromium/components/viz/service/display/delegated_ink_point_renderer_skia.h
@@ -43,7 +43,7 @@ namespace viz {
// trail never sticks around for longer than intended.
//
// For more information on the feature, please see the explainer:
-// https://github.com/WICG/ink-enhancement/blob/master/README.md
+// https://github.com/WICG/ink-enhancement/blob/main/README.md
class VIZ_SERVICE_EXPORT DelegatedInkPointRendererSkia
: public DelegatedInkPointRendererBase {
public:
diff --git a/chromium/components/viz/service/display/delegated_ink_trail_data.cc b/chromium/components/viz/service/display/delegated_ink_trail_data.cc
index ca33cba36b1..4ebbecdafe2 100644
--- a/chromium/components/viz/service/display/delegated_ink_trail_data.cc
+++ b/chromium/components/viz/service/display/delegated_ink_trail_data.cc
@@ -80,7 +80,7 @@ void DelegatedInkTrailData::AddPoint(const gfx::DelegatedInkPoint& point) {
void DelegatedInkTrailData::PredictPoints(
std::vector<gfx::DelegatedInkPoint>* ink_points_to_draw,
gfx::DelegatedInkMetadata* metadata) {
- TRACE_EVENT0("viz", "DelegatedInkTrailData::PredictPoints");
+ TRACE_EVENT0("delegated_ink_trails", "DelegatedInkTrailData::PredictPoints");
// Base name used for the histograms that measure the latency improvement from
// the prediction done for different experiments.
static const char* histogram_base_name =
diff --git a/chromium/components/viz/service/display/direct_renderer.cc b/chromium/components/viz/service/display/direct_renderer.cc
index 0f6af2615ea..24aee9c9280 100644
--- a/chromium/components/viz/service/display/direct_renderer.cc
+++ b/chromium/components/viz/service/display/direct_renderer.cc
@@ -363,20 +363,23 @@ void DirectRenderer::DrawFrame(
// viewport size is never set.
bool use_stencil = overdraw_feedback_;
bool needs_full_frame_redraw = false;
+ auto display_transform = output_surface_->GetDisplayTransform();
if (surface_resource_size != reshape_surface_size_ ||
device_scale_factor != reshape_device_scale_factor_ ||
frame_color_space != reshape_color_space_ ||
frame_buffer_format != reshape_buffer_format_ ||
- use_stencil != reshape_use_stencil_) {
+ use_stencil != reshape_use_stencil_ ||
+ display_transform != reshape_display_transform_) {
reshape_surface_size_ = surface_resource_size;
reshape_device_scale_factor_ = device_scale_factor;
reshape_color_space_ = frame_color_space;
reshape_buffer_format_ = frame_buffer_format;
reshape_use_stencil_ = overdraw_feedback_;
+ reshape_display_transform_ = display_transform;
output_surface_->Reshape(reshape_surface_size_,
reshape_device_scale_factor_, reshape_color_space_,
*reshape_buffer_format_, reshape_use_stencil_);
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
// For Mac, all render passes will be promoted to CALayer, the redraw full
// frame is for the main surface only.
// TODO(penghuang): verify this logic with SkiaRenderer.
diff --git a/chromium/components/viz/service/display/direct_renderer.h b/chromium/components/viz/service/display/direct_renderer.h
index f0aa5497ede..a9ec5f4d130 100644
--- a/chromium/components/viz/service/display/direct_renderer.h
+++ b/chromium/components/viz/service/display/direct_renderer.h
@@ -24,6 +24,7 @@
#include "components/viz/service/viz_service_export.h"
#include "gpu/command_buffer/common/texture_in_use_response.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "ui/gfx/ca_layer_result.h"
#include "ui/gfx/delegated_ink_metadata.h"
#include "ui/gfx/display_color_spaces.h"
#include "ui/gfx/geometry/quad_f.h"
@@ -99,6 +100,9 @@ class VIZ_SERVICE_EXPORT DirectRenderer {
std::vector<ui::LatencyInfo> latency_info;
bool top_controls_visible_height_changed = false;
+#if BUILDFLAG(IS_MAC)
+ gfx::CALayerResult ca_layer_error_code = gfx::kCALayerSuccess;
+#endif
};
virtual void SwapBuffers(SwapFrameData swap_frame_data) = 0;
virtual void SwapBuffersSkipped() {}
@@ -381,6 +385,8 @@ class VIZ_SERVICE_EXPORT DirectRenderer {
gfx::ColorSpace reshape_color_space_;
absl::optional<gfx::BufferFormat> reshape_buffer_format_;
bool reshape_use_stencil_ = false;
+ gfx::OverlayTransform reshape_display_transform_ =
+ gfx::OVERLAY_TRANSFORM_INVALID;
};
} // namespace viz
diff --git a/chromium/components/viz/service/display/display.cc b/chromium/components/viz/service/display/display.cc
index 1ba0c02fef9..a0bbea9dd08 100644
--- a/chromium/components/viz/service/display/display.cc
+++ b/chromium/components/viz/service/display/display.cc
@@ -16,6 +16,7 @@
#include "base/timer/elapsed_timer.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
+#include "cc/base/math_util.h"
#include "cc/base/region.h"
#include "cc/base/simple_enclosed_region.h"
#include "cc/benchmarks/benchmark_instrumentation.h"
@@ -61,7 +62,7 @@
#include "ui/gfx/presentation_feedback.h"
#include "ui/gfx/swap_result.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "ui/gfx/android/android_surface_control_compat.h"
#endif
namespace viz {
@@ -256,10 +257,10 @@ bool ReduceComplexity(const cc::Region& region,
}
bool SupportsSetFrameRate(const OutputSurface* output_surface) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
return output_surface->capabilities().supports_surfaceless &&
gfx::SurfaceControl::SupportsSetFrameRate();
-#elif defined(OS_WIN)
+#elif BUILDFLAG(IS_WIN)
return output_surface->capabilities().supports_dc_layers &&
features::ShouldUseSetPresentDuration();
#else
@@ -297,7 +298,7 @@ void Display::PresentationGroupTiming::OnSwap(gfx::SwapTimings timings,
DisplaySchedulerBase* scheduler) {
swap_timings_ = timings;
- if (timings.swap_start.is_null())
+ if (timings.swap_start.is_null() || frame_time_.is_inf())
return;
auto frame_latency = timings.swap_start - frame_time_;
@@ -357,7 +358,7 @@ Display::~Display() {
if (resource_provider_) {
resource_provider_->SetAllowAccessToGPUThread(true);
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// In certain cases, drivers hang when tearing down the display. Finishing
// before teardown appears to address this. As we're during display teardown,
// an additional finish should have minimal impact.
@@ -595,9 +596,18 @@ void Display::InitializeRenderer(bool enable_shared_images) {
output_surface_->capabilities().only_invalidates_damage_rect &&
!overlay_processor_->IsOverlaySupported();
+ SurfaceAggregator::ExtraPassForReadbackOption extra_pass_option =
+ SurfaceAggregator::ExtraPassForReadbackOption::kNone;
+ if (output_surface_->capabilities().root_is_vulkan_secondary_command_buffer) {
+ extra_pass_option =
+ base::FeatureList::IsEnabled(features::kWebViewVulkanIntermediateBuffer)
+ ? SurfaceAggregator::ExtraPassForReadbackOption::kAlwaysAddPass
+ : SurfaceAggregator::ExtraPassForReadbackOption::
+ kAddPassForReadback;
+ }
aggregator_ = std::make_unique<SurfaceAggregator>(
surface_manager_, resource_provider_.get(), output_partial_list,
- overlay_processor_->NeedsSurfaceDamageRectList());
+ overlay_processor_->NeedsSurfaceDamageRectList(), extra_pass_option);
aggregator_->set_output_is_secure(output_is_secure_);
aggregator_->SetDisplayColorSpaces(display_color_spaces_);
@@ -736,7 +746,6 @@ bool Display::DrawAndSwap(base::TimeTicks frame_time,
// aggregated again so that the trail exists for a single frame.
target_damage_bounding_rect.Union(
renderer_->GetDelegatedInkTrailDamageRect());
-
frame = aggregator_->Aggregate(
current_surface_id_, expected_display_time, current_display_transform,
target_damage_bounding_rect, ++swapped_trace_id_);
@@ -759,7 +768,8 @@ bool Display::DrawAndSwap(base::TimeTicks frame_time,
if (frame.delegated_ink_metadata) {
TRACE_EVENT_INSTANT1(
- "viz", "Delegated Ink Metadata was aggregated for DrawAndSwap.",
+ "delegated_ink_trails",
+ "Delegated Ink Metadata was aggregated for DrawAndSwap.",
TRACE_EVENT_SCOPE_THREAD, "ink metadata",
frame.delegated_ink_metadata->ToString());
renderer_->SetDelegatedInkMetadata(std::move(frame.delegated_ink_metadata));
@@ -768,7 +778,7 @@ bool Display::DrawAndSwap(base::TimeTicks frame_time,
UMA_HISTOGRAM_ENUMERATION("Compositing.ColorGamut",
frame.content_color_usage);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
bool wide_color_enabled =
display_color_spaces_.GetOutputColorSpace(
frame.content_color_usage, true) != gfx::ColorSpace::CreateSRGB();
@@ -940,6 +950,11 @@ bool Display::DrawAndSwap(base::TimeTicks frame_time,
last_top_controls_visible_height_ = *frame.top_controls_visible_height;
}
+#if BUILDFLAG(IS_MAC)
+ swap_frame_data.ca_layer_error_code =
+ overlay_processor_->GetCALayerErrorCode();
+#endif
+
// We must notify scheduler and increase |pending_swaps_| before calling
// SwapBuffers() as it can call DidReceiveSwapBuffersAck synchronously.
if (scheduler_)
@@ -1162,16 +1177,18 @@ void Display::DidFinishFrame(const BeginFrameAck& ack) {
base::TimeDelta Display::GetEstimatedDisplayDrawTime(base::TimeDelta interval,
double percentile) const {
- if (draw_time_without_scheduling_waits_.sample_count() >= 60) {
+ base::TimeDelta default_estimate =
+ BeginFrameArgs::DefaultEstimatedDisplayDrawTime(interval);
+ if (draw_time_without_scheduling_waits_.sample_count() >= 60 &&
+ default_estimate > kMinEstimatedDisplayDrawTime) {
// We do not want the deadline adjustmens to exceed a default of 1/3 VSync,
// as we would not give other processes enough time to produce content. So
// this would make high latency situations worse.
return base::clamp(
draw_time_without_scheduling_waits_.Percentile(percentile),
- kMinEstimatedDisplayDrawTime,
- BeginFrameArgs::DefaultEstimatedDisplayDrawTime(interval));
+ kMinEstimatedDisplayDrawTime, default_estimate);
}
- return BeginFrameArgs::DefaultEstimatedDisplayDrawTime(interval);
+ return default_estimate;
}
void Display::OnObservingBeginFrameSourceChanged(bool observing) {
@@ -1427,11 +1444,11 @@ void Display::SetPreferredFrameInterval(base::TimeDelta interval) {
float interval_s = interval.InSecondsF();
float frame_rate = interval_s == 0 ? 0 : (1 / interval_s);
output_surface_->SetFrameRate(frame_rate);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// On Android we want to return early because the |client_| callback hits
// a platform API in the browser process.
return;
-#endif // OS_ANDROID
+#endif // BUILDFLAG(IS_ANDROID)
}
client_->SetPreferredFrameInterval(interval);
diff --git a/chromium/components/viz/service/display/display_resource_provider.cc b/chromium/components/viz/service/display/display_resource_provider.cc
index bddf50204dd..eb87fff486f 100644
--- a/chromium/components/viz/service/display/display_resource_provider.cc
+++ b/chromium/components/viz/service/display/display_resource_provider.cc
@@ -13,6 +13,7 @@
#include "base/threading/thread_task_runner_handle.h"
#include "base/trace_event/memory_dump_manager.h"
#include "base/trace_event/trace_event.h"
+#include "build/build_config.h"
#include "components/viz/common/resources/resource_sizes.h"
#include "gpu/command_buffer/common/shared_image_trace_utils.h"
#include "ui/gfx/geometry/size.h"
@@ -114,14 +115,14 @@ bool DisplayResourceProvider::OnMemoryDump(
return true;
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
bool DisplayResourceProvider::IsBackedBySurfaceTexture(ResourceId id) {
ChildResource* resource = GetResource(id);
return resource->transferable.is_backed_by_surface_texture;
}
#endif
-#if defined(OS_ANDROID) || defined(OS_WIN)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_WIN)
bool DisplayResourceProvider::DoesResourceWantPromotionHint(ResourceId id) {
ChildResource* resource = TryGetResource(id);
// TODO(ericrk): We should never fail TryGetResource, but we appear to
@@ -201,13 +202,9 @@ void DisplayResourceProvider::ReceiveFromChild(
const std::vector<TransferableResource>& resources) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- // TODO(crbug.com/855785): Fishing for misuse of DisplayResourceProvider
- // causing crashes.
- CHECK(child_id);
auto child_it = children_.find(child_id);
- // TODO(crbug.com/855785): Fishing for misuse of DisplayResourceProvider
- // causing crashes.
- CHECK(child_it != children_.end());
+ DCHECK(child_it != children_.end());
+
Child& child_info = child_it->second;
DCHECK(!child_info.marked_for_deletion);
for (const TransferableResource& transferable_resource : resources) {
@@ -244,13 +241,9 @@ void DisplayResourceProvider::DeclareUsedResourcesFromChild(
const ResourceIdSet& resources_from_child) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- // TODO(crbug.com/855785): Fishing for misuse of DisplayResourceProvider
- // causing crashes.
- CHECK(child);
auto child_it = children_.find(child);
- // TODO(crbug.com/855785): Fishing for misuse of DisplayResourceProvider
- // causing crashes.
- CHECK(child_it != children_.end());
+ DCHECK(child_it != children_.end());
+
Child& child_info = child_it->second;
DCHECK(!child_info.marked_for_deletion);
@@ -441,8 +434,8 @@ DisplayResourceProvider::ScopedReadLockSharedImage::ScopedReadLockSharedImage(
resource_(resource_provider_->GetResource(resource_id_)) {
DCHECK(resource_);
DCHECK(resource_->is_gpu_resource_type());
- // Remove this #if defined(OS_WIN), when shared image is used on Windows.
-#if !defined(OS_WIN)
+ // Remove this #if BUILDFLAG(IS_WIN), when shared image is used on Windows.
+#if !BUILDFLAG(IS_WIN)
DCHECK(resource_->transferable.mailbox_holder.mailbox.IsSharedImage());
#endif
resource_->lock_for_overlay_count++;
diff --git a/chromium/components/viz/service/display/display_resource_provider.h b/chromium/components/viz/service/display/display_resource_provider.h
index f69e597b063..5d897625a42 100644
--- a/chromium/components/viz/service/display/display_resource_provider.h
+++ b/chromium/components/viz/service/display/display_resource_provider.h
@@ -14,7 +14,6 @@
#include <vector>
#include "base/containers/flat_map.h"
-#include "base/containers/small_map.h"
#include "base/memory/raw_ptr.h"
#include "base/threading/thread_checker.h"
#include "base/trace_event/memory_dump_provider.h"
@@ -71,13 +70,13 @@ class VIZ_SERVICE_EXPORT DisplayResourceProvider
bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
base::trace_event::ProcessMemoryDump* pmd) override;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Indicates if this resource is backed by an Android SurfaceTexture, and thus
// can't really be promoted to an overlay.
bool IsBackedBySurfaceTexture(ResourceId id);
#endif
-#if defined(OS_ANDROID) || defined(OS_WIN)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_WIN)
// Indicates if this resource wants to receive promotion hints.
bool DoesResourceWantPromotionHint(ResourceId id);
#endif
diff --git a/chromium/components/viz/service/display/display_resource_provider_skia.cc b/chromium/components/viz/service/display/display_resource_provider_skia.cc
index ff130039832..1c3a3a2df9d 100644
--- a/chromium/components/viz/service/display/display_resource_provider_skia.cc
+++ b/chromium/components/viz/service/display/display_resource_provider_skia.cc
@@ -129,7 +129,8 @@ DisplayResourceProviderSkia::LockSetForExternalUse::LockResource(
ResourceId id,
bool maybe_concurrent_reads,
bool is_video_plane,
- const absl::optional<gfx::ColorSpace>& override_color_space) {
+ const absl::optional<gfx::ColorSpace>& override_color_space,
+ bool raw_draw_is_possible) {
auto it = resource_provider_->resources_.find(id);
DCHECK(it != resource_provider_->resources_.end());
@@ -159,7 +160,8 @@ DisplayResourceProviderSkia::LockSetForExternalUse::LockResource(
resource_provider_->external_use_client_->CreateImageContext(
resource.transferable.mailbox_holder, resource.transferable.size,
resource.transferable.format, maybe_concurrent_reads,
- resource.transferable.ycbcr_info, std::move(image_color_space));
+ resource.transferable.ycbcr_info, std::move(image_color_space),
+ raw_draw_is_possible);
}
resource.locked_for_external_use = true;
diff --git a/chromium/components/viz/service/display/display_resource_provider_skia.h b/chromium/components/viz/service/display/display_resource_provider_skia.h
index 871f818fedf..32982471449 100644
--- a/chromium/components/viz/service/display/display_resource_provider_skia.h
+++ b/chromium/components/viz/service/display/display_resource_provider_skia.h
@@ -59,7 +59,8 @@ class VIZ_SERVICE_EXPORT DisplayResourceProviderSkia
bool maybe_concurrent_reads,
bool is_video_plane,
const absl::optional<gfx::ColorSpace>& override_color_space =
- absl::nullopt);
+ absl::nullopt,
+ bool raw_draw_if_possible = false);
// Unlock all locked resources with a |sync_token|. The |sync_token| should
// be waited on before reusing the resource's backing to ensure that any
diff --git a/chromium/components/viz/service/display/display_resource_provider_skia_unittest.cc b/chromium/components/viz/service/display/display_resource_provider_skia_unittest.cc
index e516a371c99..a3f5f6a9d64 100644
--- a/chromium/components/viz/service/display/display_resource_provider_skia_unittest.cc
+++ b/chromium/components/viz/service/display/display_resource_provider_skia_unittest.cc
@@ -59,14 +59,15 @@ class MockExternalUseClient : public ExternalUseClient {
MOCK_METHOD1(ReleaseImageContexts,
gpu::SyncToken(
std::vector<std::unique_ptr<ImageContext>> image_contexts));
- MOCK_METHOD6(CreateImageContext,
- std::unique_ptr<ImageContext>(
- const gpu::MailboxHolder&,
- const gfx::Size&,
- ResourceFormat,
- bool,
- const absl::optional<gpu::VulkanYCbCrInfo>& ycbcr_info,
- sk_sp<SkColorSpace>));
+ MOCK_METHOD7(
+ CreateImageContext,
+ std::unique_ptr<ImageContext>(const gpu::MailboxHolder&,
+ const gfx::Size&,
+ ResourceFormat,
+ bool,
+ const absl::optional<gpu::VulkanYCbCrInfo>&,
+ sk_sp<SkColorSpace>,
+ bool));
};
class DisplayResourceProviderSkiaTest : public testing::Test {
@@ -158,7 +159,7 @@ TEST_F(DisplayResourceProviderSkiaTest, LockForExternalUse) {
auto* image_context = owned_image_context.get();
gpu::MailboxHolder holder;
- EXPECT_CALL(client_, CreateImageContext(_, _, _, _, _, _))
+ EXPECT_CALL(client_, CreateImageContext(_, _, _, _, _, _, _))
.WillOnce(DoAll(SaveArg<0>(&holder),
Return(ByMove(std::move(owned_image_context)))));
@@ -238,7 +239,7 @@ TEST_F(DisplayResourceProviderSkiaTest, LockForExternalUseWebView) {
auto* image_context = owned_image_context.get();
gpu::MailboxHolder holder;
- EXPECT_CALL(client_, CreateImageContext(_, _, _, _, _, _))
+ EXPECT_CALL(client_, CreateImageContext(_, _, _, _, _, _, _))
.WillOnce(DoAll(SaveArg<0>(&holder),
Return(ByMove(std::move(owned_image_context)))));
diff --git a/chromium/components/viz/service/display/display_scheduler.cc b/chromium/components/viz/service/display/display_scheduler.cc
index 536160e4b10..fa8120fa07c 100644
--- a/chromium/components/viz/service/display/display_scheduler.cc
+++ b/chromium/components/viz/service/display/display_scheduler.cc
@@ -84,6 +84,7 @@ DisplayScheduler::DisplayScheduler(BeginFrameSource* begin_frame_source,
features::IsDynamicSchedulerEnabledForClients()),
dynamic_scheduler_deadlines_percentile_(
features::IsDynamicSchedulerEnabledForDraw()) {
+ begin_frame_deadline_timer_.SetTaskRunner(task_runner);
if (dynamic_cc_deadlines_percentile_.has_value())
begin_frame_source_->SetDynamicBeginFrameDeadlineOffsetSource(this);
begin_frame_source_->AddStateObserver(begin_frame_state_observer_.get());
@@ -173,7 +174,8 @@ void DisplayScheduler::MaybeCreateHintSession(
if (!hint_session_factory_)
return;
- if (!hint_session_ || current_thread_ids_ != thread_ids) {
+ if ((!create_session_for_current_thread_ids_failed_ && !hint_session_) ||
+ current_thread_ids_ != thread_ids) {
hint_session_.reset();
int target_ms = features::kAdpfTargetDurationMs.Get();
if (target_ms <= 0 || target_ms > 1000)
@@ -181,6 +183,7 @@ void DisplayScheduler::MaybeCreateHintSession(
current_thread_ids_ = std::move(thread_ids);
hint_session_ = hint_session_factory_->CreateSession(
current_thread_ids_, base::Milliseconds(target_ms));
+ create_session_for_current_thread_ids_failed_ = !hint_session_;
}
}
@@ -328,15 +331,17 @@ bool DisplayScheduler::ShouldDraw() const {
!damage_tracker_->root_frame_missing();
}
-base::TimeTicks DisplayScheduler::DesiredBeginFrameDeadlineTime() const {
- switch (AdjustedBeginFrameDeadlineMode()) {
+// static
+base::TimeTicks DisplayScheduler::DesiredBeginFrameDeadlineTime(
+ BeginFrameDeadlineMode deadline_mode,
+ BeginFrameArgs begin_frame_args) {
+ switch (deadline_mode) {
case BeginFrameDeadlineMode::kImmediate:
return base::TimeTicks();
case BeginFrameDeadlineMode::kRegular:
- return current_begin_frame_args_.deadline;
+ return begin_frame_args.deadline;
case BeginFrameDeadlineMode::kLate:
- return current_begin_frame_args_.frame_time +
- current_begin_frame_args_.interval;
+ return begin_frame_args.frame_time + begin_frame_args.interval;
case BeginFrameDeadlineMode::kNone:
return base::TimeTicks::Max();
default:
@@ -419,15 +424,17 @@ void DisplayScheduler::ScheduleBeginFrameDeadline() {
if (!inside_begin_frame_deadline_interval_) {
TRACE_EVENT_INSTANT0("viz", "Waiting for next BeginFrame",
TRACE_EVENT_SCOPE_THREAD);
- DCHECK(begin_frame_deadline_task_.IsCancelled());
+ DCHECK(!begin_frame_deadline_timer_.IsRunning());
return;
}
// Determine the deadline we want to use.
- base::TimeTicks desired_deadline = DesiredBeginFrameDeadlineTime();
+ BeginFrameDeadlineMode deadline_mode = AdjustedBeginFrameDeadlineMode();
+ base::TimeTicks desired_deadline =
+ DesiredBeginFrameDeadlineTime(deadline_mode, current_begin_frame_args_);
// Avoid re-scheduling the deadline if it's already correctly scheduled.
- if (!begin_frame_deadline_task_.IsCancelled() &&
+ if (begin_frame_deadline_timer_.IsRunning() &&
desired_deadline == begin_frame_deadline_task_time_) {
TRACE_EVENT_INSTANT0("viz", "Using existing deadline",
TRACE_EVENT_SCOPE_THREAD);
@@ -436,7 +443,7 @@ void DisplayScheduler::ScheduleBeginFrameDeadline() {
// Schedule the deadline.
begin_frame_deadline_task_time_ = desired_deadline;
- begin_frame_deadline_task_.Cancel();
+ begin_frame_deadline_timer_.Stop();
if (begin_frame_deadline_task_time_ == base::TimeTicks::Max()) {
TRACE_EVENT_INSTANT0("viz", "Using infinite deadline",
@@ -444,18 +451,16 @@ void DisplayScheduler::ScheduleBeginFrameDeadline() {
return;
}
- begin_frame_deadline_task_.Reset(begin_frame_deadline_closure_);
- base::TimeDelta delta =
- std::max(base::TimeDelta(), desired_deadline - base::TimeTicks::Now());
- task_runner_->PostDelayedTask(FROM_HERE,
- begin_frame_deadline_task_.callback(), delta);
- TRACE_EVENT2("viz", "Using new deadline", "delta", delta.ToInternalValue(),
+ begin_frame_deadline_timer_.Start(FROM_HERE, desired_deadline,
+ begin_frame_deadline_closure_,
+ base::ExactDeadline(true));
+ TRACE_EVENT2("viz", "Using new deadline", "deadline_mode", deadline_mode,
"desired_deadline", desired_deadline);
}
bool DisplayScheduler::AttemptDrawAndSwap() {
inside_begin_frame_deadline_interval_ = false;
- begin_frame_deadline_task_.Cancel();
+ begin_frame_deadline_timer_.Stop();
begin_frame_deadline_task_time_ = base::TimeTicks();
if (ShouldDraw()) {
diff --git a/chromium/components/viz/service/display/display_scheduler.h b/chromium/components/viz/service/display/display_scheduler.h
index 5e8c43c3b21..857ab72758d 100644
--- a/chromium/components/viz/service/display/display_scheduler.h
+++ b/chromium/components/viz/service/display/display_scheduler.h
@@ -11,6 +11,7 @@
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/task/single_thread_task_runner.h"
+#include "base/timer/timer.h"
#include "components/viz/common/display/renderer_settings.h"
#include "components/viz/common/frame_sinks/begin_frame_source.h"
#include "components/viz/common/surfaces/surface_id.h"
@@ -98,7 +99,11 @@ class VIZ_SERVICE_EXPORT DisplayScheduler
// BeginFrame yet so we need to wait longer.
kNone
};
- base::TimeTicks DesiredBeginFrameDeadlineTime() const;
+
+ static base::TimeTicks DesiredBeginFrameDeadlineTime(
+ BeginFrameDeadlineMode deadline_mode,
+ BeginFrameArgs begin_frame_args);
+
BeginFrameDeadlineMode AdjustedBeginFrameDeadlineMode() const;
BeginFrameDeadlineMode DesiredBeginFrameDeadlineMode() const;
virtual void ScheduleBeginFrameDeadline();
@@ -122,7 +127,7 @@ class VIZ_SERVICE_EXPORT DisplayScheduler
BeginFrameArgs current_begin_frame_args_;
base::RepeatingClosure begin_frame_deadline_closure_;
- base::CancelableOnceClosure begin_frame_deadline_task_;
+ base::DeadlineTimer begin_frame_deadline_timer_;
base::TimeTicks begin_frame_deadline_task_time_;
base::CancelableOnceClosure missed_begin_frame_task_;
@@ -145,6 +150,7 @@ class VIZ_SERVICE_EXPORT DisplayScheduler
const raw_ptr<HintSessionFactory> hint_session_factory_;
base::flat_set<base::PlatformThreadId> current_thread_ids_;
std::unique_ptr<HintSession> hint_session_;
+ bool create_session_for_current_thread_ids_failed_ = false;
// If set, we are dynamically adjusting our frame deadline, by the percentile
// of historic draw times to base the adjustment on.
diff --git a/chromium/components/viz/service/display/display_scheduler_unittest.cc b/chromium/components/viz/service/display/display_scheduler_unittest.cc
index d0fd5d58043..7f1ef0abe8b 100644
--- a/chromium/components/viz/service/display/display_scheduler_unittest.cc
+++ b/chromium/components/viz/service/display/display_scheduler_unittest.cc
@@ -137,7 +137,9 @@ class TestDisplayScheduler : public DisplayScheduler {
}
base::TimeTicks DesiredBeginFrameDeadlineTimeForTest() {
- return DesiredBeginFrameDeadlineTime();
+ BeginFrameDeadlineMode deadline_mode = AdjustedBeginFrameDeadlineMode();
+ return DesiredBeginFrameDeadlineTime(deadline_mode,
+ current_begin_frame_args_);
}
void BeginFrameDeadlineForTest() {
diff --git a/chromium/components/viz/service/display/display_unittest.cc b/chromium/components/viz/service/display/display_unittest.cc
index 592680042f6..2539b3de39c 100644
--- a/chromium/components/viz/service/display/display_unittest.cc
+++ b/chromium/components/viz/service/display/display_unittest.cc
@@ -61,6 +61,7 @@
#include "gpu/GLES2/gl2extchromium.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkCanvas.h"
#include "ui/gfx/delegated_ink_metadata.h"
#include "ui/gfx/delegated_ink_point.h"
#include "ui/gfx/mojom/delegated_ink_point_renderer.mojom.h"
diff --git a/chromium/components/viz/service/display/draw_polygon.cc b/chromium/components/viz/service/display/draw_polygon.cc
index ae10dda3e07..042ab292642 100644
--- a/chromium/components/viz/service/display/draw_polygon.cc
+++ b/chromium/components/viz/service/display/draw_polygon.cc
@@ -121,7 +121,7 @@ void DrawPolygon::ConstructNormal() {
normal_ = new_normal;
}
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
//
// Allows the unittest to invoke this for the more general constructor.
//
diff --git a/chromium/components/viz/service/display/draw_polygon_unittest.cc b/chromium/components/viz/service/display/draw_polygon_unittest.cc
index b658aa21879..3d231f7f42f 100644
--- a/chromium/components/viz/service/display/draw_polygon_unittest.cc
+++ b/chromium/components/viz/service/display/draw_polygon_unittest.cc
@@ -21,7 +21,7 @@
namespace viz {
-#if !defined(OS_WIN)
+#if !BUILDFLAG(IS_WIN)
void DrawPolygon::RecomputeNormalForTesting() {
ConstructNormal();
}
diff --git a/chromium/components/viz/service/display/external_use_client.h b/chromium/components/viz/service/display/external_use_client.h
index 80c603ee4be..85e9d097c99 100644
--- a/chromium/components/viz/service/display/external_use_client.h
+++ b/chromium/components/viz/service/display/external_use_client.h
@@ -121,7 +121,8 @@ class VIZ_SERVICE_EXPORT ExternalUseClient {
ResourceFormat format,
bool maybe_concurrent_reads,
const absl::optional<gpu::VulkanYCbCrInfo>& ycbcr_info,
- sk_sp<SkColorSpace> color_space) = 0;
+ sk_sp<SkColorSpace> color_space,
+ bool raw_draw_if_possible) = 0;
virtual gpu::SyncToken ReleaseImageContexts(
std::vector<std::unique_ptr<ImageContext>> image_contexts) = 0;
diff --git a/chromium/components/viz/service/display/frame_rate_decider.cc b/chromium/components/viz/service/display/frame_rate_decider.cc
index b5c392d2aac..f46c5366025 100644
--- a/chromium/components/viz/service/display/frame_rate_decider.cc
+++ b/chromium/components/viz/service/display/frame_rate_decider.cc
@@ -7,6 +7,7 @@
#include <algorithm>
#include <utility>
+#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
#include "components/viz/common/frame_sinks/begin_frame_args.h"
#include "components/viz/service/surfaces/surface.h"
@@ -212,11 +213,15 @@ void FrameRateDecider::UpdatePreferredFrameIntervalIfNeeded() {
// ideal refresh rate.
base::TimeDelta new_preferred_interval = UnspecifiedFrameInterval();
if (*min_frame_sink_interval != BeginFrameArgs::MinInterval()) {
+ base::TimeDelta min_delta = base::TimeDelta::Max();
for (auto supported_interval : supported_intervals_) {
- // Pick the display interval which is closest to the preferred interval.
- if ((*min_frame_sink_interval - supported_interval).magnitude() <
- (*min_frame_sink_interval - new_preferred_interval).magnitude()) {
+ // Pick the display interval which is closest to the preferred interval
+ // and less than or equal to the min_frame_sink_interval.
+ base::TimeDelta delta = (*min_frame_sink_interval - supported_interval);
+ if (AreAlmostEqual(*min_frame_sink_interval, supported_interval) ||
+ (delta.is_positive() && delta < min_delta)) {
new_preferred_interval = supported_interval;
+ min_delta = delta.magnitude();
}
}
}
diff --git a/chromium/components/viz/service/display/frame_rate_decider_unittest.cc b/chromium/components/viz/service/display/frame_rate_decider_unittest.cc
index 8db6a25cc14..8a68c6b0fa1 100644
--- a/chromium/components/viz/service/display/frame_rate_decider_unittest.cc
+++ b/chromium/components/viz/service/display/frame_rate_decider_unittest.cc
@@ -286,6 +286,23 @@ TEST_F(FrameRateDeciderTest, MinFrameSinkIntervalIsPicked) {
frame_rate_decider_->OnSurfaceWillBeDrawn(surface2);
}
EXPECT_EQ(display_interval_, min_supported_interval * 2);
+
+ FrameSinkId frame_sink_id3(1u, 3u);
+ preferred_intervals_[frame_sink_id3] = min_supported_interval * 1.8;
+ auto* surface3 = CreateAndDrawSurface(frame_sink_id3);
+ UpdateFrame(surface1);
+ UpdateFrame(surface2);
+ UpdateFrame(surface3);
+ {
+ FrameRateDecider::ScopedAggregate scope(frame_rate_decider_.get());
+ frame_rate_decider_->OnSurfaceWillBeDrawn(surface1);
+ frame_rate_decider_->OnSurfaceWillBeDrawn(surface2);
+ frame_rate_decider_->OnSurfaceWillBeDrawn(surface3);
+ }
+ // Even though surface3 has a frame interval that is closer to
+ // min_supported_interval * 2, we need to pick a smaller interval
+ // so that frames from that surface are not dropped.
+ EXPECT_EQ(display_interval_, min_supported_interval);
}
TEST_F(FrameRateDeciderTest, TogglesAfterMinNumOfFrames) {
diff --git a/chromium/components/viz/service/display/gl_renderer.cc b/chromium/components/viz/service/display/gl_renderer.cc
index 913f041f9a4..deb95d2f072 100644
--- a/chromium/components/viz/service/display/gl_renderer.cc
+++ b/chromium/components/viz/service/display/gl_renderer.cc
@@ -241,7 +241,7 @@ void AccumulateDrawRects(const gfx::Rect& quad_rect,
// Apply only the scale and translation component.
const gfx::Vector2dF& translate = target_transform.To2dTranslation();
- const gfx::Vector2dF& scale = target_transform.Scale2d();
+ const gfx::Vector2dF& scale = target_transform.To2dScale();
quad_rect_f.Scale(scale.x(), scale.y());
quad_rect_f.Offset(translate.x(), translate.y());
} else {
@@ -451,6 +451,7 @@ GLRenderer::GLRenderer(
use_occlusion_query_ = context_caps.occlusion_query;
use_timer_query_ = context_caps.timer_queries;
use_swap_with_bounds_ = context_caps.swap_buffers_with_bounds;
+ supports_multi_sampling_ = context_caps.max_samples > 0;
prefer_draw_to_copy_ = output_surface_->context_provider()
->GetGpuFeatureInfo()
.IsWorkaroundEnabled(gpu::PREFER_DRAW_TO_COPY);
@@ -985,7 +986,7 @@ uint32_t GLRenderer::GetBackdropTexture(const gfx::Rect& window_rect,
GLenum gl_format = GLDataFormat(resource_format);
GLenum gl_type = GLDataType(resource_format);
- if (scale != 1.0f) {
+ if (supports_multi_sampling_ && scale != 1.0f) {
DCHECK(!prefer_draw_to_copy_ || !current_framebuffer_texture_);
gfx::Size target_size = window_rect.size();
@@ -1220,7 +1221,7 @@ sk_sp<SkImage> GLRenderer::ApplyBackdropFilters(
const DrawQuad* GLRenderer::CanPassBeDrawnDirectly(
const AggregatedRenderPass* pass) {
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
// On Macs, this path can sometimes lead to all black output.
// TODO(enne): investigate this and remove this hack.
return nullptr;
@@ -2588,7 +2589,7 @@ void GLRenderer::DrawYUVVideoQuad(const YUVVideoDrawQuad* quad,
gfx::ColorSpace dst_color_space = CurrentRenderPassColorSpace();
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// Force sRGB output on Windows for overlay candidate video quads to match
// DirectComposition behavior in case these switch between overlays and
// compositing. See https://crbug.com/811118 for details.
@@ -3066,11 +3067,11 @@ void GLRenderer::FinishDrawingFrame() {
// semantics during overlay refactoring.
ScheduleOutputSurfaceAsOverlay();
-#if defined(OS_ANDROID) || defined(USE_OZONE)
+#if BUILDFLAG(IS_ANDROID) || defined(USE_OZONE)
ScheduleOverlays();
-#elif defined(OS_APPLE)
+#elif BUILDFLAG(IS_APPLE)
ScheduleCALayers();
-#elif defined(OS_WIN)
+#elif BUILDFLAG(IS_WIN)
ScheduleDCLayers();
#endif
@@ -3190,7 +3191,7 @@ void GLRenderer::GenerateMipmap() {
}
bool GLRenderer::FlippedFramebuffer() const {
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
if (force_drawing_frame_framebuffer_unflipped_)
return false;
#endif
@@ -3326,7 +3327,7 @@ void GLRenderer::SetShaderRoundedCorner(
DCHECK(screen_transform.IsScaleOrTranslation());
const gfx::Vector2dF& translate = screen_transform.To2dTranslation();
- const gfx::Vector2dF& scale = screen_transform.Scale2d();
+ const gfx::Vector2dF& scale = screen_transform.To2dScale();
gfx::RRectF bounds_in_screen = rounded_corner_bounds;
bounds_in_screen.Scale(scale.x(), scale.y());
bounds_in_screen.Offset(translate.x(), translate.y());
@@ -3406,6 +3407,10 @@ void GLRenderer::SwapBuffers(SwapFrameData swap_frame_data) {
output_frame.top_controls_visible_height_changed =
swap_frame_data.top_controls_visible_height_changed;
output_frame.size = surface_size;
+#if BUILDFLAG(IS_MAC)
+ output_frame.ca_layer_error_code = swap_frame_data.ca_layer_error_code;
+#endif
+
if (use_swap_with_bounds_) {
output_frame.content_bounds = std::move(swap_content_bounds_);
} else if (use_partial_swap_) {
@@ -3701,10 +3706,8 @@ void GLRenderer::SetUseProgram(const ProgramKey& program_key_no_color,
// the content might be mastered in 0-1000 nits but the display only be able
// to represent 0 to 500.
adjusted_src_color_space = src_color_space.GetWithSDRWhiteLevel(
- current_frame()->display_color_spaces.GetSDRWhiteLevel());
+ current_frame()->display_color_spaces.GetSDRMaxLuminanceNits());
}
- // TODO(b/183236148): consider using the destination's HDR static metadata
- // in current_frame()->display_color_spaces.hdr_static_metadata().
ProgramKey program_key = program_key_no_color;
const gfx::ColorTransform* color_transform =
@@ -3765,10 +3768,17 @@ const Program* GLRenderer::GetProgramIfInitialized(
const gfx::ColorTransform* GLRenderer::GetColorTransform(
const gfx::ColorSpace& src,
const gfx::ColorSpace& dst) {
- std::unique_ptr<gfx::ColorTransform>& transform =
- color_transform_cache_[dst][src];
+ ColorTransformKey key;
+ key.src = src;
+ key.dst = dst;
+ key.sdr_max_luminance_nits =
+ current_frame()->display_color_spaces.GetSDRMaxLuminanceNits();
+ std::unique_ptr<gfx::ColorTransform>& transform = color_transform_cache_[key];
if (!transform) {
- transform = gfx::ColorTransform::NewColorTransform(src, dst);
+ gfx::ColorTransform::Options options;
+ options.tone_map_pq_and_hlg_to_sdr = !dst.IsHDR();
+ options.sdr_max_luminance_nits = key.sdr_max_luminance_nits;
+ transform = gfx::ColorTransform::NewColorTransform(src, dst, options);
}
return transform.get();
}
@@ -3847,7 +3857,7 @@ bool GLRenderer::IsContextLost() {
return gl_->GetGraphicsResetStatusKHR() != GL_NO_ERROR;
}
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
void GLRenderer::ScheduleCALayers() {
// The use of OverlayTextures for RenderPasses is only supported on the code
// paths for |release_overlay_resources_after_gpu_query| at the moment. See
@@ -3920,9 +3930,9 @@ void GLRenderer::ScheduleCALayers() {
ReduceAvailableOverlayTextures();
}
-#endif // defined(OS_APPLE)
+#endif // BUILDFLAG(IS_APPLE)
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
void GLRenderer::ScheduleDCLayers() {
for (DCLayerOverlay& dc_layer_overlay : current_frame()->overlay_list) {
DCHECK_EQ(DCLayerOverlay::kNumResources, 2u);
@@ -3962,9 +3972,9 @@ void GLRenderer::ScheduleDCLayers() {
clip_rect.height(), protected_video_type);
}
}
-#endif // defined (OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
-#if defined(OS_ANDROID) || defined(USE_OZONE)
+#if BUILDFLAG(IS_ANDROID) || defined(USE_OZONE)
void GLRenderer::ScheduleOverlays() {
if (current_frame()->overlay_list.empty())
return;
@@ -3983,7 +3993,7 @@ void GLRenderer::ScheduleOverlays() {
overlay_candidate.gpu_fence_id);
}
}
-#endif // defined(OS_ANDROID) || defined(USE_OZONE)
+#endif // BUILDFLAG(IS_ANDROID) || defined(USE_OZONE)
void GLRenderer::ScheduleOutputSurfaceAsOverlay() {
if (!current_frame()->output_surface_plane)
@@ -4002,7 +4012,7 @@ void GLRenderer::ScheduleOutputSurfaceAsOverlay() {
overlay_candidate.enable_blending, overlay_candidate.gpu_fence_id);
}
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
// This function draws the CompositorRenderPassDrawQuad into a temporary
// texture/framebuffer, and then copies the result into an IOSurface. The
// inefficient (but simple) way to do this would be to:
@@ -4277,7 +4287,7 @@ GLRenderer::ScheduleRenderPassDrawQuad(const CALayerOverlay* ca_layer_overlay) {
filter);
return overlay_texture;
}
-#endif // defined(OS_APPLE)
+#endif // BUILDFLAG(IS_APPLE)
void GLRenderer::SetupOverdrawFeedback() {
gl_->StencilFunc(GL_ALWAYS, 1, 0xffffffff);
@@ -4486,4 +4496,21 @@ gfx::Size GLRenderer::GetRenderPassBackingPixelSize(
GLRenderer::OverlayTexture::OverlayTexture() = default;
GLRenderer::OverlayTexture::~OverlayTexture() = default;
+bool GLRenderer::ColorTransformKey::operator==(
+ const ColorTransformKey& other) const {
+ return src == other.src && dst == other.dst &&
+ sdr_max_luminance_nits == other.sdr_max_luminance_nits;
+}
+
+bool GLRenderer::ColorTransformKey::operator!=(
+ const ColorTransformKey& other) const {
+ return !(*this == other);
+}
+
+bool GLRenderer::ColorTransformKey::operator<(
+ const ColorTransformKey& other) const {
+ return std::tie(src, dst, sdr_max_luminance_nits) <
+ std::tie(other.src, other.dst, other.sdr_max_luminance_nits);
+}
+
} // namespace viz
diff --git a/chromium/components/viz/service/display/gl_renderer.h b/chromium/components/viz/service/display/gl_renderer.h
index 3d3a6b66399..f3106e13715 100644
--- a/chromium/components/viz/service/display/gl_renderer.h
+++ b/chromium/components/viz/service/display/gl_renderer.h
@@ -37,11 +37,11 @@
#include "ui/gfx/gpu_fence_handle.h"
#include "ui/latency/latency_info.h"
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
#include "components/viz/service/display/ca_layer_overlay.h"
#endif
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include "components/viz/service/display/dc_layer_overlay.h"
#endif
@@ -337,9 +337,9 @@ class VIZ_SERVICE_EXPORT GLRenderer : public DirectRenderer {
// nothing.
void ScheduleOutputSurfaceAsOverlay();
// Schedule overlays sends overlay candidate to the GPU.
-#if defined(OS_ANDROID) || defined(USE_OZONE)
+#if BUILDFLAG(IS_ANDROID) || defined(USE_OZONE)
void ScheduleOverlays();
-#elif defined(OS_APPLE)
+#elif BUILDFLAG(IS_APPLE)
void ScheduleCALayers();
// Schedules the |ca_layer_overlay|, which is guaranteed to have a non-null
@@ -363,7 +363,7 @@ class VIZ_SERVICE_EXPORT GLRenderer : public DirectRenderer {
const gfx::ColorSpace& color_space);
void ReduceAvailableOverlayTextures();
-#elif defined(OS_WIN)
+#elif BUILDFLAG(IS_WIN)
void ScheduleDCLayers();
#endif
@@ -445,8 +445,15 @@ class VIZ_SERVICE_EXPORT GLRenderer : public DirectRenderer {
const gfx::ColorTransform* GetColorTransform(const gfx::ColorSpace& src,
const gfx::ColorSpace& dst);
- std::map<gfx::ColorSpace,
- std::map<gfx::ColorSpace, std::unique_ptr<gfx::ColorTransform>>>
+ struct ColorTransformKey {
+ gfx::ColorSpace src;
+ gfx::ColorSpace dst;
+ float sdr_max_luminance_nits = 0.f;
+ bool operator==(const ColorTransformKey& other) const;
+ bool operator!=(const ColorTransformKey& other) const;
+ bool operator<(const ColorTransformKey& other) const;
+ };
+ std::map<ColorTransformKey, std::unique_ptr<gfx::ColorTransform>>
color_transform_cache_;
raw_ptr<gpu::gles2::GLES2Interface> gl_;
@@ -478,11 +485,12 @@ class VIZ_SERVICE_EXPORT GLRenderer : public DirectRenderer {
bool use_occlusion_query_ = false;
bool use_swap_with_bounds_ = false;
bool use_fast_path_solid_color_quad_ = false;
+ bool supports_multi_sampling_ = false;
// If true, tints all the composited content to red.
bool tint_gl_composited_content_ = true;
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
// The method FlippedFramebuffer determines whether the framebuffer associated
// with a DrawingFrame is flipped. It makes the assumption that the
// DrawingFrame is being used as part of a render pass. If a DrawingFrame is
diff --git a/chromium/components/viz/service/display/gl_renderer_copier_pixeltest.cc b/chromium/components/viz/service/display/gl_renderer_copier_pixeltest.cc
index 5cde7de5c86..0f72f75a2aa 100644
--- a/chromium/components/viz/service/display/gl_renderer_copier_pixeltest.cc
+++ b/chromium/components/viz/service/display/gl_renderer_copier_pixeltest.cc
@@ -38,7 +38,7 @@
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "base/android/build_info.h"
#endif
@@ -307,7 +307,7 @@ class GLRendererCopierPixelTest
// On Android KitKat bots (but not newer ones), the left column of pixels in the
// result is off-by-one in the red channel. Use the off-by-one camparator as a
// workaround.
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#define PIXEL_COMPARATOR() cc::FuzzyPixelOffByOneComparator(false)
#else
#define PIXEL_COMPARATOR() cc::ExactPixelComparator(false)
diff --git a/chromium/components/viz/service/display/gl_renderer_unittest.cc b/chromium/components/viz/service/display/gl_renderer_unittest.cc
index fde8c1b24cc..0532ecb4102 100644
--- a/chromium/components/viz/service/display/gl_renderer_unittest.cc
+++ b/chromium/components/viz/service/display/gl_renderer_unittest.cc
@@ -52,11 +52,12 @@
#include "ui/gfx/geometry/transform.h"
#include "ui/latency/latency_info.h"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include "components/viz/service/display/overlay_processor_win.h"
-#elif defined(OS_APPLE)
+#elif BUILDFLAG(IS_APPLE)
#include "components/viz/service/display/overlay_processor_mac.h"
-#elif defined(OS_ANDROID) || defined(USE_OZONE)
+#elif BUILDFLAG(IS_ANDROID) || defined(USE_OZONE)
+#include "components/viz/service/display/overlay_processor_strategy.h"
#include "components/viz/service/display/overlay_processor_using_strategy.h"
#include "components/viz/service/display/overlay_strategy_single_on_top.h"
#include "components/viz/service/display/overlay_strategy_underlay.h"
@@ -224,15 +225,19 @@ class GLRendererShaderPixelTest : public cc::PixelTest {
auto adjusted_color_space = src_color_space;
if (src_color_space.IsHDR()) {
adjusted_color_space = src_color_space.GetWithSDRWhiteLevel(
- drawing_frame.display_color_spaces.GetSDRWhiteLevel());
+ drawing_frame.display_color_spaces.GetSDRMaxLuminanceNits());
}
SCOPED_TRACE(
base::StringPrintf("adjusted_color_space=%s, dst_color_space=%s",
adjusted_color_space.ToString().c_str(),
dst_color_space.ToString().c_str()));
+ gfx::ColorTransform::Options options;
+ options.tone_map_pq_and_hlg_to_sdr = !dst_color_space.IsHDR();
+ options.sdr_max_luminance_nits =
+ drawing_frame.display_color_spaces.GetSDRMaxLuminanceNits();
auto color_transform = gfx::ColorTransform::NewColorTransform(
- adjusted_color_space, dst_color_space);
+ adjusted_color_space, dst_color_space, options);
ASSERT_EQ(color_transform->GetShaderSource(),
renderer()
@@ -287,7 +292,7 @@ class GLRendererShaderPixelTest : public cc::PixelTest {
void TestShadersWithSDRWhiteLevel(const ProgramKey& program_key,
float sdr_white_level) {
GLRenderer::DrawingFrame frame;
- frame.display_color_spaces.SetSDRWhiteLevel(sdr_white_level);
+ frame.display_color_spaces.SetSDRMaxLuminanceNits(sdr_white_level);
TestShaderWithDrawingFrame(program_key, frame, false);
}
@@ -430,7 +435,7 @@ class GLRendererShaderPixelTest : public cc::PixelTest {
namespace {
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
static const TexCoordPrecision kPrecisionList[] = {TEX_COORD_PRECISION_MEDIUM,
TEX_COORD_PRECISION_HIGH};
@@ -998,7 +1003,7 @@ class GLRendererTextureDrawQuadHDRTest
constexpr float kSDRWhiteLevel = 123.0f;
gfx::DisplayColorSpaces display_color_spaces;
- display_color_spaces.SetSDRWhiteLevel(kSDRWhiteLevel);
+ display_color_spaces.SetSDRMaxLuminanceNits(kSDRWhiteLevel);
DrawFrame(renderer_.get(), viewport_size, display_color_spaces);
@@ -2537,7 +2542,7 @@ TEST_F(MockOutputSurfaceTest, BackbufferDiscard) {
Mock::VerifyAndClearExpectations(output_surface_.get());
}
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
class MockDCLayerOverlayProcessor : public DCLayerOverlayProcessor {
public:
MockDCLayerOverlayProcessor()
@@ -2569,7 +2574,7 @@ class TestOverlayProcessor : public OverlayProcessorWin {
return static_cast<MockDCLayerOverlayProcessor*>(GetOverlayProcessor());
}
};
-#elif defined(OS_APPLE)
+#elif BUILDFLAG(IS_APPLE)
class MockCALayerOverlayProcessor : public CALayerOverlayProcessor {
public:
MockCALayerOverlayProcessor() : CALayerOverlayProcessor(true) {}
@@ -2598,14 +2603,14 @@ class TestOverlayProcessor : public OverlayProcessorMac {
}
};
-#elif defined(OS_ANDROID) || defined(USE_OZONE)
+#elif BUILDFLAG(IS_ANDROID) || defined(USE_OZONE)
class TestOverlayProcessor : public OverlayProcessorUsingStrategy {
public:
- class Strategy : public OverlayProcessorUsingStrategy::Strategy {
+ class TestStrategy : public OverlayProcessorStrategy {
public:
- Strategy() = default;
- ~Strategy() override = default;
+ TestStrategy() = default;
+ ~TestStrategy() override = default;
MOCK_METHOD8(
Attempt,
@@ -2627,7 +2632,7 @@ class TestOverlayProcessor : public OverlayProcessorUsingStrategy {
AggregatedRenderPassList* render_pass_list,
SurfaceDamageRectList* surface_damage_rect_list,
const PrimaryPlane* primary_plane,
- OverlayProposedCandidateList* candidates,
+ std::vector<OverlayProposedCandidate>* candidates,
std::vector<gfx::Rect>* content_bounds) override {
auto* render_pass = render_pass_list->back().get();
QuadList& quad_list = render_pass->quad_list;
@@ -2659,19 +2664,18 @@ class TestOverlayProcessor : public OverlayProcessorUsingStrategy {
// to be traditionally composited. Candidates with |overlay_handled| set to
// true must also have their |display_rect| converted to integer
// coordinates if necessary.
- void CheckOverlaySupport(
+ void CheckOverlaySupportImpl(
const OverlayProcessorInterface::OutputSurfaceOverlayPlane* primary_plane,
OverlayCandidateList* surfaces) override {}
- Strategy& strategy() {
+ TestStrategy& strategy() {
auto* strategy = strategies_.back().get();
- return *(static_cast<Strategy*>(strategy));
+ return *(static_cast<TestStrategy*>(strategy));
}
MOCK_CONST_METHOD0(NeedsSurfaceDamageRectList, bool());
- explicit TestOverlayProcessor(OutputSurface* output_surface)
- : OverlayProcessorUsingStrategy() {
- strategies_.push_back(std::make_unique<Strategy>());
+ explicit TestOverlayProcessor(OutputSurface* output_surface) {
+ strategies_.push_back(std::make_unique<TestStrategy>());
prioritization_config_.changing_threshold = false;
prioritization_config_.damage_rate_threshold = false;
}
@@ -2698,7 +2702,7 @@ TEST_F(GLRendererTest, DontOverlayWithCopyRequests) {
cc::FakeOutputSurfaceClient output_surface_client;
std::unique_ptr<FakeOutputSurface> output_surface(
FakeOutputSurface::Create3d());
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
output_surface->set_supports_dc_layers(true);
#endif
output_surface->BindToClient(&output_surface_client);
@@ -2744,10 +2748,10 @@ TEST_F(GLRendererTest, DontOverlayWithCopyRequests) {
renderer.Initialize();
renderer.SetVisible(true);
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
MockCALayerOverlayProcessor* mock_ca_processor =
processor->GetTestProcessor();
-#elif defined(OS_WIN)
+#elif BUILDFLAG(IS_WIN)
MockDCLayerOverlayProcessor* dc_processor = processor->GetTestProcessor();
#endif
@@ -2778,7 +2782,7 @@ TEST_F(GLRendererTest, DontOverlayWithCopyRequests) {
// added a fake strategy, so checking for Attempt calls checks if there was
// any attempt to overlay, which there shouldn't be. We can't use the quad
// list because the render pass is cleaned up by DrawFrame.
-#if defined(USE_OZONE) || defined(OS_ANDROID)
+#if defined(USE_OZONE) || BUILDFLAG(IS_ANDROID)
if (features::IsOverlayPrioritizationEnabled()) {
EXPECT_CALL(processor->strategy(),
AttemptPrioritized(_, _, _, _, _, _, _, _, _))
@@ -2787,19 +2791,19 @@ TEST_F(GLRendererTest, DontOverlayWithCopyRequests) {
EXPECT_CALL(processor->strategy(), Attempt(_, _, _, _, _, _, _, _))
.Times(0);
}
-#elif defined(OS_APPLE)
+#elif BUILDFLAG(IS_APPLE)
EXPECT_CALL(*mock_ca_processor, ProcessForCALayerOverlays(_, _, _, _, _, _))
.WillOnce(Return(false));
-#elif defined(OS_WIN)
+#elif BUILDFLAG(IS_WIN)
EXPECT_CALL(*dc_processor, Process(_, _, _, _, _, _, _, _)).Times(0);
#endif
DrawFrame(&renderer, viewport_size);
-#if defined(USE_OZONE) || defined(OS_ANDROID)
+#if defined(USE_OZONE) || BUILDFLAG(IS_ANDROID)
Mock::VerifyAndClearExpectations(&processor->strategy());
-#elif defined(OS_APPLE)
+#elif BUILDFLAG(IS_APPLE)
Mock::VerifyAndClearExpectations(
const_cast<MockCALayerOverlayProcessor*>(mock_ca_processor));
-#elif defined(OS_WIN)
+#elif BUILDFLAG(IS_WIN)
Mock::VerifyAndClearExpectations(
const_cast<MockDCLayerOverlayProcessor*>(dc_processor));
#endif
@@ -2817,7 +2821,7 @@ TEST_F(GLRendererTest, DontOverlayWithCopyRequests) {
premultiplied_alpha, gfx::PointF(0, 0), gfx::PointF(1, 1),
SK_ColorTRANSPARENT, vertex_opacity, flipped, nearest_neighbor,
/*secure_output_only=*/false, gfx::ProtectedVideoType::kClear);
-#if defined(USE_OZONE) || defined(OS_ANDROID)
+#if defined(USE_OZONE) || BUILDFLAG(IS_ANDROID)
if (features::IsOverlayPrioritizationEnabled()) {
EXPECT_CALL(processor->strategy(),
AttemptPrioritized(_, _, _, _, _, _, _, _, _))
@@ -2826,10 +2830,10 @@ TEST_F(GLRendererTest, DontOverlayWithCopyRequests) {
EXPECT_CALL(processor->strategy(), Attempt(_, _, _, _, _, _, _, _))
.Times(1);
}
-#elif defined(OS_APPLE)
+#elif BUILDFLAG(IS_APPLE)
EXPECT_CALL(*mock_ca_processor, ProcessForCALayerOverlays(_, _, _, _, _, _))
.WillOnce(Return(true));
-#elif defined(OS_WIN)
+#elif BUILDFLAG(IS_WIN)
EXPECT_CALL(*dc_processor, Process(_, _, _, _, _, _, _, _)).Times(1);
#endif
DrawFrame(&renderer, viewport_size);
@@ -2843,7 +2847,7 @@ TEST_F(GLRendererTest, DontOverlayWithCopyRequests) {
child_resource_provider->ShutdownAndReleaseAllResources();
}
-#if defined(OS_ANDROID) || defined(USE_OZONE)
+#if BUILDFLAG(IS_ANDROID) || defined(USE_OZONE)
class SingleOverlayOnTopProcessor : public OverlayProcessorUsingStrategy {
public:
SingleOverlayOnTopProcessor() : OverlayProcessorUsingStrategy() {
@@ -2856,7 +2860,7 @@ class SingleOverlayOnTopProcessor : public OverlayProcessorUsingStrategy {
bool NeedsSurfaceDamageRectList() const override { return true; }
bool IsOverlaySupported() const override { return true; }
- void CheckOverlaySupport(
+ void CheckOverlaySupportImpl(
const OverlayProcessorInterface::OutputSurfaceOverlayPlane* primary_plane,
OverlayCandidateList* surfaces) override {
if (!multiple_candidates_)
@@ -2999,7 +3003,7 @@ TEST_F(GLRendererTest, OverlaySyncTokensAreProcessed) {
child_resource_provider->RemoveImportedResource(resource_id);
child_resource_provider->ShutdownAndReleaseAllResources();
}
-#endif // defined(USE_OZONE) || defined(OS_ANDROID)
+#endif // defined(USE_OZONE) || BUILDFLAG(IS_ANDROID)
class OutputColorMatrixMockGLES2Interface : public TestGLES2Interface {
public:
@@ -3657,7 +3661,7 @@ TEST_F(GLRendererPartialSwapTest, NoPartialSwap) {
RunTest(false, false);
}
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
TEST_F(GLRendererPartialSwapTest, SetDrawRectangle_PartialSwap) {
RunTest(true, true);
}
@@ -3832,14 +3836,14 @@ TEST_F(GLRendererWithMockContextTest,
Mock::VerifyAndClearExpectations(context_support_ptr_);
}
-#if defined(USE_OZONE) || defined(OS_ANDROID)
+#if defined(USE_OZONE) || BUILDFLAG(IS_ANDROID)
class ContentBoundsOverlayProcessor : public OverlayProcessorUsingStrategy {
public:
- class Strategy : public OverlayProcessorUsingStrategy::Strategy {
+ class TestStrategy : public OverlayProcessorStrategy {
public:
- explicit Strategy(const std::vector<gfx::Rect>& content_bounds)
+ explicit TestStrategy(const std::vector<gfx::Rect>& content_bounds)
: content_bounds_(content_bounds) {}
- ~Strategy() override = default;
+ ~TestStrategy() override = default;
bool Attempt(const skia::Matrix44& output_color_matrix,
const OverlayProcessorInterface::FilterOperationsMap&
@@ -3862,7 +3866,7 @@ class ContentBoundsOverlayProcessor : public OverlayProcessorUsingStrategy {
AggregatedRenderPassList* render_pass_list,
SurfaceDamageRectList* surface_damage_rect_list,
const PrimaryPlane* primary_plane,
- OverlayProposedCandidateList* candidates,
+ std::vector<OverlayProposedCandidate>* candidates,
std::vector<gfx::Rect>* content_bounds) override {
auto* render_pass = render_pass_list->back().get();
QuadList& quad_list = render_pass->quad_list;
@@ -3898,12 +3902,14 @@ class ContentBoundsOverlayProcessor : public OverlayProcessorUsingStrategy {
const std::vector<gfx::Rect>& content_bounds)
: OverlayProcessorUsingStrategy(), content_bounds_(content_bounds) {
strategies_.push_back(
- std::make_unique<Strategy>(std::move(content_bounds_)));
+ std::make_unique<TestStrategy>(std::move(content_bounds_)));
prioritization_config_.changing_threshold = false;
prioritization_config_.damage_rate_threshold = false;
}
- Strategy& strategy() { return static_cast<Strategy&>(*strategies_.back()); }
+ TestStrategy& strategy() {
+ return static_cast<TestStrategy&>(*strategies_.back());
+ }
// Empty mock methods since this test set up uses strategies, which are only
// for ozone and android.
MOCK_CONST_METHOD0(NeedsSurfaceDamageRectList, bool());
@@ -3915,7 +3921,7 @@ class ContentBoundsOverlayProcessor : public OverlayProcessorUsingStrategy {
// to be traditionally composited. Candidates with |overlay_handled| set to
// true must also have their |display_rect| converted to integer
// coordinates if necessary.
- void CheckOverlaySupport(
+ void CheckOverlaySupportImpl(
const OverlayProcessorInterface::OutputSurfaceOverlayPlane* primary_plane,
OverlayCandidateList* surfaces) override {}
@@ -3980,9 +3986,9 @@ TEST_F(GLRendererSwapWithBoundsTest, NonEmpty) {
content_bounds.push_back(gfx::Rect(20, 20, 30, 30));
RunTest(content_bounds);
}
-#endif // defined(USE_OZONE) || defined(OS_ANDROID)
+#endif // defined(USE_OZONE) || BUILDFLAG(IS_ANDROID)
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
class MockCALayerGLES2Interface : public TestGLES2Interface {
public:
MOCK_METHOD6(ScheduleCALayerSharedStateCHROMIUM,
@@ -4036,7 +4042,7 @@ class CALayerGLRendererTest : public GLRendererTest {
// The Mac TestOverlayProcessor default to enable CALayer overlays, then all
// damage is removed and we can skip the root RenderPass, swapping empty.
overlay_processor_ = std::make_unique<OverlayProcessorMac>(
- std::make_unique<CALayerOverlayProcessor>(true));
+ std::make_unique<CALayerOverlayProcessor>());
renderer_ = std::make_unique<FakeRendererGL>(
settings_.get(), &debug_settings_, output_surface_.get(),
display_resource_provider_.get(), overlay_processor_.get(),
@@ -5062,7 +5068,7 @@ TEST_F(GLRendererTest, UndamagedRenderPassStillDrawnWhenNoPartialSwap) {
}
}
-#if defined(USE_OZONE) || defined(OS_ANDROID)
+#if defined(USE_OZONE) || BUILDFLAG(IS_ANDROID)
class GLRendererWithGpuFenceTest : public GLRendererTest {
protected:
GLRendererWithGpuFenceTest() {
@@ -5183,7 +5189,7 @@ TEST_F(GLRendererWithGpuFenceTest,
.Times(1);
DrawFrame(renderer_.get(), viewport_size);
}
-#endif // defined(USE_OZONE) || defined(OS_ANDROID)
+#endif // defined(USE_OZONE) || BUILDFLAG(IS_ANDROID)
} // namespace
} // namespace viz
diff --git a/chromium/components/viz/service/display/output_surface_frame.h b/chromium/components/viz/service/display/output_surface_frame.h
index 1544f38936c..6d846abcbfa 100644
--- a/chromium/components/viz/service/display/output_surface_frame.h
+++ b/chromium/components/viz/service/display/output_surface_frame.h
@@ -10,6 +10,7 @@
#include "components/viz/service/viz_service_export.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "ui/gfx/ca_layer_result.h"
#include "ui/gfx/delegated_ink_metadata.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
@@ -43,6 +44,9 @@ class VIZ_SERVICE_EXPORT OutputSurfaceFrame {
// Metadata containing information to draw a delegated ink trail using
// platform APIs.
std::unique_ptr<gfx::DelegatedInkMetadata> delegated_ink_metadata;
+#if BUILDFLAG(IS_MAC)
+ gfx::CALayerResult ca_layer_error_code = gfx::kCALayerSuccess;
+#endif
};
} // namespace viz
diff --git a/chromium/components/viz/service/display/overlay_ca_unittest.cc b/chromium/components/viz/service/display/overlay_ca_unittest.cc
index d95b34707b2..6726bc4573e 100644
--- a/chromium/components/viz/service/display/overlay_ca_unittest.cc
+++ b/chromium/components/viz/service/display/overlay_ca_unittest.cc
@@ -15,6 +15,7 @@
#include "cc/test/fake_output_surface_client.h"
#include "cc/test/resource_provider_test_utils.h"
#include "components/viz/client/client_resource_provider.h"
+#include "components/viz/common/frame_sinks/copy_output_request.h"
#include "components/viz/common/quads/aggregated_render_pass.h"
#include "components/viz/common/quads/aggregated_render_pass_draw_quad.h"
#include "components/viz/common/quads/compositor_render_pass.h"
@@ -49,6 +50,7 @@ const gfx::Rect kOverlayRect(0, 0, 256, 256);
const gfx::PointF kUVTopLeft(0.1f, 0.2f);
const gfx::PointF kUVBottomRight(1.0f, 1.0f);
const gfx::Rect kRenderPassOutputRect(0, 0, 256, 256);
+const gfx::Rect kOverlayDamageRect(0, 0, 100, 100);
class OverlayOutputSurface : public OutputSurface {
public:
@@ -91,8 +93,7 @@ class OverlayOutputSurface : public OutputSurface {
class CATestOverlayProcessor : public OverlayProcessorMac {
public:
- CATestOverlayProcessor()
- : OverlayProcessorMac(true /* enable_ca_overlay */) {}
+ CATestOverlayProcessor() : OverlayProcessorMac() {}
};
std::unique_ptr<AggregatedRenderPass> CreateRenderPass() {
@@ -242,7 +243,7 @@ class CALayerOverlayTest : public testing::Test {
scoped_refptr<TestContextProvider> child_provider_;
std::unique_ptr<ClientResourceProvider> child_resource_provider_;
std::unique_ptr<CATestOverlayProcessor> overlay_processor_;
- gfx::Rect damage_rect_;
+ gfx::Rect damage_rect_ = kOverlayDamageRect;
std::vector<gfx::Rect> content_bounds_;
};
@@ -254,7 +255,6 @@ TEST_F(CALayerOverlayTest, AllowNonAxisAlignedTransform) {
pass->shared_quad_state_list.back()
->quad_to_target_transform.RotateAboutZAxis(45.f);
- gfx::Rect damage_rect;
CALayerOverlayList ca_layer_list;
OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
@@ -267,7 +267,7 @@ TEST_F(CALayerOverlayTest, AllowNonAxisAlignedTransform) {
render_pass_filters, render_pass_backdrop_filters,
std::move(surface_damage_rect_list), nullptr, &ca_layer_list,
&damage_rect_, &content_bounds_);
- EXPECT_EQ(gfx::Rect(), damage_rect);
+ EXPECT_EQ(gfx::Rect(), damage_rect_);
EXPECT_EQ(1U, ca_layer_list.size());
gfx::Rect overlay_damage = overlay_processor_->GetAndResetOverlayDamage();
EXPECT_EQ(kRenderPassOutputRect, overlay_damage);
@@ -311,7 +311,6 @@ TEST_F(CALayerOverlayTest, AllowContainingClip) {
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
pass->shared_quad_state_list.back()->clip_rect = kOverlayRect;
- gfx::Rect damage_rect;
CALayerOverlayList ca_layer_list;
OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
@@ -324,7 +323,7 @@ TEST_F(CALayerOverlayTest, AllowContainingClip) {
render_pass_filters, render_pass_backdrop_filters,
std::move(surface_damage_rect_list), nullptr, &ca_layer_list,
&damage_rect_, &content_bounds_);
- EXPECT_EQ(gfx::Rect(), damage_rect);
+ EXPECT_EQ(gfx::Rect(), damage_rect_);
EXPECT_EQ(1U, ca_layer_list.size());
EXPECT_EQ(0U, output_surface_->bind_framebuffer_count());
}
@@ -336,7 +335,6 @@ TEST_F(CALayerOverlayTest, NontrivialClip) {
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
pass->shared_quad_state_list.back()->clip_rect = gfx::Rect(64, 64, 128, 128);
- gfx::Rect damage_rect;
CALayerOverlayList ca_layer_list;
OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
@@ -349,7 +347,7 @@ TEST_F(CALayerOverlayTest, NontrivialClip) {
render_pass_filters, render_pass_backdrop_filters,
std::move(surface_damage_rect_list), nullptr, &ca_layer_list,
&damage_rect_, &content_bounds_);
- EXPECT_EQ(gfx::Rect(), damage_rect);
+ EXPECT_EQ(gfx::Rect(), damage_rect_);
EXPECT_EQ(1U, ca_layer_list.size());
EXPECT_EQ(gfx::RectF(64, 64, 128, 128),
ca_layer_list.back().shared_state->clip_rect);
@@ -363,7 +361,6 @@ TEST_F(CALayerOverlayTest, SkipTransparent) {
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
pass->shared_quad_state_list.back()->opacity = 0;
- gfx::Rect damage_rect;
CALayerOverlayList ca_layer_list;
OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
@@ -376,7 +373,7 @@ TEST_F(CALayerOverlayTest, SkipTransparent) {
render_pass_filters, render_pass_backdrop_filters,
std::move(surface_damage_rect_list), nullptr, &ca_layer_list,
&damage_rect_, &content_bounds_);
- EXPECT_EQ(gfx::Rect(), damage_rect);
+ EXPECT_EQ(gfx::Rect(), damage_rect_);
EXPECT_EQ(0U, ca_layer_list.size());
EXPECT_EQ(0U, output_surface_->bind_framebuffer_count());
}
@@ -388,7 +385,6 @@ TEST_F(CALayerOverlayTest, SkipNonVisible) {
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
pass->quad_list.back()->visible_rect.set_size(gfx::Size());
- gfx::Rect damage_rect;
CALayerOverlayList ca_layer_list;
OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
@@ -401,7 +397,7 @@ TEST_F(CALayerOverlayTest, SkipNonVisible) {
render_pass_filters, render_pass_backdrop_filters,
std::move(surface_damage_rect_list), nullptr, &ca_layer_list,
&damage_rect_, &content_bounds_);
- EXPECT_EQ(gfx::Rect(), damage_rect);
+ EXPECT_EQ(gfx::Rect(), damage_rect_);
EXPECT_EQ(0U, ca_layer_list.size());
EXPECT_EQ(0U, output_surface_->bind_framebuffer_count());
}
@@ -441,7 +437,6 @@ TEST_F(CALayerOverlayTest, YUVDrawQuadOverlay) {
/*multiplier=*/1.0f,
/*bits_per_channel=*/8);
- gfx::Rect damage_rect;
CALayerOverlayList ca_layer_list;
OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
@@ -454,7 +449,7 @@ TEST_F(CALayerOverlayTest, YUVDrawQuadOverlay) {
render_pass_filters, render_pass_backdrop_filters,
std::move(surface_damage_rect_list), nullptr, &ca_layer_list,
&damage_rect_, &content_bounds_);
- EXPECT_EQ(gfx::Rect(), damage_rect);
+ EXPECT_EQ(gfx::Rect(), damage_rect_);
EXPECT_EQ(1U, ca_layer_list.size());
}
@@ -475,7 +470,6 @@ TEST_F(CALayerOverlayTest, YUVDrawQuadOverlay) {
/*multiplier=*/1.0f,
/*bits_per_channel=*/8);
- gfx::Rect damage_rect;
CALayerOverlayList ca_layer_list;
OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
@@ -488,12 +482,68 @@ TEST_F(CALayerOverlayTest, YUVDrawQuadOverlay) {
render_pass_filters, render_pass_backdrop_filters,
std::move(surface_damage_rect_list), nullptr, &ca_layer_list,
&damage_rect_, &content_bounds_);
- EXPECT_EQ(gfx::Rect(), damage_rect);
+ EXPECT_EQ(gfx::Rect(), damage_rect_);
EXPECT_EQ(0U, ca_layer_list.size());
EXPECT_EQ(0U, output_surface_->bind_framebuffer_count());
}
}
+TEST_F(CALayerOverlayTest, OverlayErrorCode) {
+ // Frame #1
+ auto pass = CreateRenderPass();
+ CreateFullscreenCandidateQuad(
+ resource_provider_.get(), child_resource_provider_.get(),
+ child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
+
+ CALayerOverlayList ca_layer_list;
+ OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
+ OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
+ AggregatedRenderPassList pass_list;
+ pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
+ overlay_processor_->ProcessForOverlays(
+ resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+ render_pass_filters, render_pass_backdrop_filters,
+ std::move(surface_damage_rect_list), nullptr, &ca_layer_list,
+ &damage_rect_, &content_bounds_);
+
+ // There should be no error.
+ gfx::CALayerResult error_code = overlay_processor_->GetCALayerErrorCode();
+ EXPECT_EQ(1U, ca_layer_list.size());
+ // kCALayerSuccess = 0,
+ EXPECT_EQ(0, error_code);
+
+ // Frame #2
+ {
+ auto pass = CreateRenderPass();
+ CreateFullscreenCandidateQuad(
+ resource_provider_.get(), child_resource_provider_.get(),
+ child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
+
+ // Add a copy request to the render pass
+ pass->copy_requests.push_back(CopyOutputRequest::CreateStubForTesting());
+
+ CALayerOverlayList ca_layer_list;
+ AggregatedRenderPassList pass_list;
+ pass_list.push_back(std::move(pass));
+ SurfaceDamageRectList surface_damage_rect_list;
+
+ overlay_processor_->ProcessForOverlays(
+ resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+ render_pass_filters, render_pass_backdrop_filters,
+ std::move(surface_damage_rect_list), nullptr, &ca_layer_list,
+ &damage_rect_, &content_bounds_);
+
+ // Overlay should fail when there is a copy request.
+ EXPECT_EQ(0U, ca_layer_list.size());
+
+ // kCALayerFailedCopyRequests = 31,
+ gfx::CALayerResult error_code = overlay_processor_->GetCALayerErrorCode();
+ EXPECT_EQ(31, error_code);
+ }
+}
+
class CALayerOverlayRPDQTest : public CALayerOverlayTest {
protected:
void SetUp() override {
diff --git a/chromium/components/viz/service/display/overlay_candidate.cc b/chromium/components/viz/service/display/overlay_candidate.cc
index d1ef23f9539..baaacde4cc6 100644
--- a/chromium/components/viz/service/display/overlay_candidate.cc
+++ b/chromium/components/viz/service/display/overlay_candidate.cc
@@ -154,8 +154,6 @@ OverlayCandidate::CandidateStatus OverlayCandidate::FromDrawQuad(
// We don't support an opacity value different than one for an overlay plane.
// Render pass quads should have their |sqs| opacity integrated directly into
// their final output buffers.
- // TODO(https://crbug.com/1204102) : Opacity support for delegation of
- // TileDrawQuads.
if (!cc::MathUtil::IsWithinEpsilon(sqs->opacity, 1.0f) &&
!is_delegated_context) {
return CandidateStatus::kFailOpacity;
@@ -186,7 +184,7 @@ OverlayCandidate::CandidateStatus OverlayCandidate::FromDrawQuad(
case DrawQuad::Material::kStreamVideoContent:
return FromStreamVideoQuad(resource_provider, surface_damage_rect_list,
StreamVideoDrawQuad::MaterialCast(quad),
- candidate);
+ candidate, is_delegated_context);
case DrawQuad::Material::kSolidColor:
if (!is_delegated_context)
return CandidateStatus::kFailQuadNotSupported;
@@ -329,7 +327,8 @@ OverlayCandidate::CandidateStatus OverlayCandidate::FromDrawQuadResource(
const DrawQuad* quad,
ResourceId resource_id,
bool y_flipped,
- OverlayCandidate* candidate) {
+ OverlayCandidate* candidate,
+ bool is_delegated_context) {
if (resource_id != kInvalidResourceId &&
!resource_provider->IsOverlayCandidate(resource_id))
return CandidateStatus::kFailNotOverlay;
@@ -378,6 +377,11 @@ OverlayCandidate::CandidateStatus OverlayCandidate::FromDrawQuadResource(
resource_provider->GetSurfaceId(resource_id).frame_sink_id();
}
+ // Delegated compositing does not yet support |clip_rect| so it is applied
+ // here to the |display_rect| and |uv_rect| directly.
+ if (is_delegated_context)
+ ApplyClip(candidate);
+
candidate->tracking_id = base::Hash(&track_data, sizeof(track_data));
return CandidateStatus::kSuccess;
}
@@ -389,13 +393,14 @@ OverlayCandidate::CandidateStatus OverlayCandidate::FromAggregateQuad(
const AggregatedRenderPassDrawQuad* quad,
const gfx::RectF& primary_rect,
OverlayCandidate* candidate) {
- auto rtn = FromDrawQuadResource(resource_provider, surface_damage_rect_list,
- quad, kInvalidResourceId, false, candidate);
+ auto rtn =
+ FromDrawQuadResource(resource_provider, surface_damage_rect_list, quad,
+ kInvalidResourceId, false, candidate, true);
if (rtn == CandidateStatus::kSuccess) {
+ candidate->rpdq = quad;
candidate->resource_size_in_pixels =
gfx::Size(candidate->display_rect.size().width(),
candidate->display_rect.size().height());
- candidate->rpdq = quad;
}
return rtn;
}
@@ -407,8 +412,9 @@ OverlayCandidate::CandidateStatus OverlayCandidate::FromSolidColorQuad(
const SolidColorDrawQuad* quad,
const gfx::RectF& primary_rect,
OverlayCandidate* candidate) {
- auto rtn = FromDrawQuadResource(resource_provider, surface_damage_rect_list,
- quad, kInvalidResourceId, false, candidate);
+ auto rtn =
+ FromDrawQuadResource(resource_provider, surface_damage_rect_list, quad,
+ kInvalidResourceId, false, candidate, true);
if (rtn == CandidateStatus::kSuccess) {
// TODO(https://crbug.com/1204102) : The 4x4 size is only valid for the non
@@ -456,23 +462,15 @@ OverlayCandidate::CandidateStatus OverlayCandidate::FromTileQuad(
if (quad->nearest_neighbor)
return CandidateStatus::kFailNearFilter;
- auto rtn = FromDrawQuadResource(resource_provider, surface_damage_rect_list,
- quad, quad->resource_id(), false, candidate);
- if (rtn == CandidateStatus::kSuccess) {
- candidate->resource_size_in_pixels =
- resource_provider->GetResourceBackedSize(quad->resource_id());
-
- float x = quad->tex_coord_rect.origin().x() /
- candidate->resource_size_in_pixels.width();
- float xw = quad->tex_coord_rect.size().width() /
- candidate->resource_size_in_pixels.width();
- float y = quad->tex_coord_rect.origin().y() /
- candidate->resource_size_in_pixels.height();
- float yh = quad->tex_coord_rect.size().height() /
- candidate->resource_size_in_pixels.height();
- candidate->uv_rect = gfx::RectF(x, y, xw, yh);
- }
+ candidate->resource_size_in_pixels =
+ resource_provider->GetResourceBackedSize(quad->resource_id());
+ candidate->uv_rect = gfx::ScaleRect(
+ quad->tex_coord_rect, 1.f / candidate->resource_size_in_pixels.width(),
+ 1.f / candidate->resource_size_in_pixels.height());
+ auto rtn =
+ FromDrawQuadResource(resource_provider, surface_damage_rect_list, quad,
+ quad->resource_id(), false, candidate, true);
return rtn;
}
@@ -499,26 +497,18 @@ OverlayCandidate::CandidateStatus OverlayCandidate::FromTextureQuad(
quad->ShouldDrawWithBlending()))
return CandidateStatus::kFailBlending;
- auto rtn =
- FromDrawQuadResource(resource_provider, surface_damage_rect_list, quad,
- quad->resource_id(), quad->y_flipped, candidate);
- if (rtn == CandidateStatus::kSuccess) {
- candidate->resource_size_in_pixels = quad->resource_size_in_pixels();
- candidate->uv_rect = BoundingRect(quad->uv_top_left, quad->uv_bottom_right);
- // Only handle clip rect for required overlays
-
- // Delegated compositing does not yet support |clip_rect| so it is done
- // here.
- if (is_delegated_context && candidate->clip_rect.has_value()) {
- gfx::RectF uv_rect = cc::MathUtil::ScaleRectProportional(
- candidate->uv_rect, candidate->display_rect,
- gfx::RectF(*candidate->clip_rect));
+ candidate->uv_rect = BoundingRect(quad->uv_top_left, quad->uv_bottom_right);
- candidate->display_rect = gfx::RectF(*candidate->clip_rect);
- candidate->uv_rect = uv_rect;
- }
+ auto rtn = FromDrawQuadResource(resource_provider, surface_damage_rect_list,
+ quad, quad->resource_id(), quad->y_flipped,
+ candidate, is_delegated_context);
+ if (rtn == CandidateStatus::kSuccess) {
+ // 'quad->resource_size_in_pixels()'
+ candidate->resource_size_in_pixels =
+ resource_provider->GetResourceBackedSize(quad->resource_id());
- if (candidate->requires_overlay)
+ // Only handle clip rect for required overlays
+ if (!is_delegated_context && candidate->requires_overlay)
HandleClipAndSubsampling(candidate, primary_rect);
candidate->priority_hint = gfx::OverlayPriorityHint::kRegular;
@@ -531,17 +521,18 @@ OverlayCandidate::CandidateStatus OverlayCandidate::FromStreamVideoQuad(
DisplayResourceProvider* resource_provider,
SurfaceDamageRectList* surface_damage_rect_list,
const StreamVideoDrawQuad* quad,
- OverlayCandidate* candidate) {
+ OverlayCandidate* candidate,
+ bool is_delegated_context) {
auto rtn = FromDrawQuadResource(resource_provider, surface_damage_rect_list,
- quad, quad->resource_id(), false, candidate);
+ quad, quad->resource_id(), false, candidate,
+ is_delegated_context);
if (rtn == CandidateStatus::kSuccess) {
- candidate->resource_id = quad->resource_id();
candidate->resource_size_in_pixels = quad->resource_size_in_pixels();
candidate->uv_rect = BoundingRect(quad->uv_top_left, quad->uv_bottom_right);
-#if defined(OS_ANDROID)
- candidate->is_backed_by_surface_texture =
- resource_provider->IsBackedBySurfaceTexture(quad->resource_id());
+#if BUILDFLAG(IS_ANDROID)
+ candidate->is_backed_by_surface_texture =
+ resource_provider->IsBackedBySurfaceTexture(quad->resource_id());
#endif
}
return rtn;
@@ -631,6 +622,8 @@ void OverlayCandidate::AssignDamage(
gfx::PointF(buffer_damage_origin.x(), buffer_damage_origin.y()));
} else {
// If not invertible, set to full damage.
+ // TODO(https://crbug.com/1279965): |resource_size_in_pixels| might not be
+ // properly initialized at this stage.
transformed_damage =
gfx::RectF(gfx::SizeF(candidate->resource_size_in_pixels));
}
@@ -641,4 +634,15 @@ void OverlayCandidate::AssignDamage(
candidate->damage_rect = transformed_damage;
}
+void OverlayCandidate::ApplyClip(OverlayCandidate* candidate) {
+ if (candidate->clip_rect.has_value()) {
+ auto intersect_clip_display = gfx::RectF(*candidate->clip_rect);
+ intersect_clip_display.Intersect(candidate->display_rect);
+ gfx::RectF uv_rect = cc::MathUtil::ScaleRectProportional(
+ candidate->uv_rect, candidate->display_rect, intersect_clip_display);
+ candidate->display_rect = intersect_clip_display;
+ candidate->uv_rect = uv_rect;
+ }
+}
+
} // namespace viz
diff --git a/chromium/components/viz/service/display/overlay_candidate.h b/chromium/components/viz/service/display/overlay_candidate.h
index 26a28145675..c3ef1c76adb 100644
--- a/chromium/components/viz/service/display/overlay_candidate.h
+++ b/chromium/components/viz/service/display/overlay_candidate.h
@@ -137,7 +137,7 @@ class VIZ_SERVICE_EXPORT OverlayCandidate {
// Mailbox from resource_id. It is used by SkiaRenderer.
gpu::Mailbox mailbox;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// For candidates from StreamVideoDrawQuads, this records whether the quad is
// marked as being backed by a SurfaceTexture or not. If so, it's not really
// promotable to an overlay.
@@ -215,7 +215,8 @@ class VIZ_SERVICE_EXPORT OverlayCandidate {
const DrawQuad* quad,
ResourceId resource_id,
bool y_flipped,
- OverlayCandidate* candidate);
+ OverlayCandidate* candidate,
+ bool is_delegated_context);
static CandidateStatus FromTextureQuad(
DisplayResourceProvider* resource_provider,
SurfaceDamageRectList* surface_damage_rect_list,
@@ -249,7 +250,8 @@ class VIZ_SERVICE_EXPORT OverlayCandidate {
DisplayResourceProvider* resource_provider,
SurfaceDamageRectList* surface_damage_rect_list,
const StreamVideoDrawQuad* quad,
- OverlayCandidate* candidate);
+ OverlayCandidate* candidate,
+ bool is_delegated_context);
static CandidateStatus FromVideoHoleQuad(
DisplayResourceProvider* resource_provider,
SurfaceDamageRectList* surface_damage_rect_list,
@@ -260,6 +262,7 @@ class VIZ_SERVICE_EXPORT OverlayCandidate {
static void AssignDamage(const DrawQuad* quad,
SurfaceDamageRectList* surface_damage_rect_list,
OverlayCandidate* candidate);
+ static void ApplyClip(OverlayCandidate* candidate);
};
using OverlayCandidateList = std::vector<OverlayCandidate>;
diff --git a/chromium/components/viz/service/display/overlay_processor_android.cc b/chromium/components/viz/service/display/overlay_processor_android.cc
index af88d1d9d72..ca7412c94df 100644
--- a/chromium/components/viz/service/display/overlay_processor_android.cc
+++ b/chromium/components/viz/service/display/overlay_processor_android.cc
@@ -132,7 +132,7 @@ void OverlayProcessorAndroid::OverlayPresentationComplete() {
pending_overlay_locks_.pop_front();
}
-void OverlayProcessorAndroid::CheckOverlaySupport(
+void OverlayProcessorAndroid::CheckOverlaySupportImpl(
const OverlayProcessorInterface::OutputSurfaceOverlayPlane* primary_plane,
OverlayCandidateList* candidates) {
// For pre-SurfaceControl Android we should not have output surface as overlay
@@ -172,6 +172,7 @@ void OverlayProcessorAndroid::CheckOverlaySupport(
promotion_hint_info_map_[candidate.resource_id] = candidate.display_rect;
}
}
+
gfx::Rect OverlayProcessorAndroid::GetOverlayDamageRectForOutputSurface(
const OverlayCandidate& overlay) const {
return ToEnclosedRect(overlay.display_rect);
diff --git a/chromium/components/viz/service/display/overlay_processor_android.h b/chromium/components/viz/service/display/overlay_processor_android.h
index 76f6414e585..0737bb4e601 100644
--- a/chromium/components/viz/service/display/overlay_processor_android.h
+++ b/chromium/components/viz/service/display/overlay_processor_android.h
@@ -53,7 +53,7 @@ class VIZ_SERVICE_EXPORT OverlayProcessorAndroid
void SetDisplayTransformHint(gfx::OverlayTransform transform) override {}
void SetViewportSize(const gfx::Size& size) override {}
- void CheckOverlaySupport(
+ void CheckOverlaySupportImpl(
const OverlayProcessorInterface::OutputSurfaceOverlayPlane* primary_plane,
OverlayCandidateList* candidates) override;
gfx::Rect GetOverlayDamageRectForOutputSurface(
diff --git a/chromium/components/viz/service/display/overlay_processor_delegated.cc b/chromium/components/viz/service/display/overlay_processor_delegated.cc
index 47c767934d1..b85ba581543 100644
--- a/chromium/components/viz/service/display/overlay_processor_delegated.cc
+++ b/chromium/components/viz/service/display/overlay_processor_delegated.cc
@@ -37,6 +37,8 @@
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/geometry/transform.h"
#include "ui/gfx/geometry/vector2d_f.h"
+#include "ui/ozone/public/overlay_manager_ozone.h"
+#include "ui/ozone/public/ozone_platform.h"
namespace {
DBG_FLAG_FBOOL("delegated.fd.usage", usage_every_frame)
@@ -86,7 +88,14 @@ OverlayProcessorDelegated::OverlayProcessorDelegated(
gpu::SharedImageInterface* shared_image_interface)
: OverlayProcessorOzone(std::move(overlay_candidates),
available_strategies,
- shared_image_interface) {}
+ shared_image_interface) {
+ // TODO(msisov, petermcneeley): remove this once Wayland uses only delegated
+ // context. May be null in tests.
+ if (ui::OzonePlatform::GetInstance()->GetOverlayManager())
+ ui::OzonePlatform::GetInstance()
+ ->GetOverlayManager()
+ ->SetContextDelegated();
+}
OverlayProcessorDelegated::~OverlayProcessorDelegated() = default;
@@ -95,7 +104,9 @@ bool OverlayProcessorDelegated::DisableSplittingQuads() const {
return true;
}
-constexpr size_t kTooManyQuads = 128;
+constexpr size_t kTooManyQuads = 64;
+
+DBG_FLAG_FBOOL("delegated.disable.delegation", disable_delegation)
bool OverlayProcessorDelegated::AttemptWithStrategies(
const skia::Matrix44& output_color_matrix,
@@ -113,16 +124,15 @@ bool OverlayProcessorDelegated::AttemptWithStrategies(
constexpr bool is_delegated_context = true;
delegated_status_ = DelegationStatus::kCompositedOther;
+ if (disable_delegation())
+ return false;
+
if (quad_list->size() >= kTooManyQuads ||
!render_pass_backdrop_filters.empty())
return false;
- // Wayland overlay forwarding mechanism does not (yet) support putting the
- // same buffer on multiple surfaces. We use this |candidate_ids| for best
- // effort service and simply skip duplicate resource id quads.
- std::set<ResourceId> candidate_ids;
std::vector<QuadList::Iterator> candidate_quads;
-
+ int num_quads_skipped = 0;
for (auto it = quad_list->begin(); it != quad_list->end(); ++it) {
OverlayCandidate candidate;
auto& transform = it->shared_quad_state->quad_to_target_transform;
@@ -138,48 +148,22 @@ bool OverlayProcessorDelegated::AttemptWithStrategies(
GetPrimaryPlaneDisplayRect(primary_plane), &candidate,
is_delegated_context);
if (candidate_status == OverlayCandidate::CandidateStatus::kSuccess) {
- // Setting the |uv_rect| will eventually result in setting the
- // |crop_rect_| in wayland. If this results in an empty pixel scale the
- // wayland connection will be terminated. See: wayland_surface.cc
- // 'UpdateBufferDamageRegion'
- auto viewport_src = gfx::ToEnclosedRect(gfx::ScaleRect(
- candidate.uv_rect, candidate.resource_size_in_pixels.width(),
- candidate.resource_size_in_pixels.height()));
-
if (it->material == DrawQuad::Material::kSolidColor) {
DBG_DRAW_RECT("delegated.overlay.color", candidate.display_rect);
- candidates->push_back(candidate);
- candidate_quads.push_back(it);
- continue;
- }
-
- if (it->material == DrawQuad::Material::kAggregatedRenderPass) {
+ } else if (it->material == DrawQuad::Material::kAggregatedRenderPass) {
DBG_DRAW_RECT("delegated.overlay.aggregated", candidate.display_rect);
- candidates->push_back(candidate);
- candidate_quads.push_back(it);
- continue;
- }
-
- // Because of the device scale factor (2) we check against a rounded empty
- // rect.
- // TODO(https://crbug.com/1218678) : Move and generalize this fix in
- // wayland host.
- if (viewport_src.width() <= 2 || viewport_src.height() <= 2) {
- DBG_DRAW_RECT("delegated.overlay.subpixelskip", candidate.display_rect);
- continue;
- }
-
- if (candidate_ids.find(candidate.resource_id) == candidate_ids.end()) {
- candidate_ids.insert(candidate.resource_id);
- DBG_DRAW_RECT("delegated.overlay.candidate", candidate.display_rect);
- candidates->push_back(candidate);
- candidate_quads.push_back(it);
} else {
- DBG_DRAW_RECT("delegated.overlay.dupskip", candidate.display_rect);
+ DBG_DRAW_RECT("delegated.overlay.candidate", candidate.display_rect);
}
-
+ candidates->push_back(candidate);
+ candidate_quads.push_back(it);
} else {
- DBG_DRAW_RECT("delegated.overlay.failed", display_rect);
+ if (candidate_status == OverlayCandidate::CandidateStatus::kFailVisible) {
+ // This quad can be intentionally skipped.
+ num_quads_skipped++;
+ } else {
+ DBG_DRAW_RECT("delegated.overlay.failed", display_rect);
+ }
if (candidate_status ==
OverlayCandidate::CandidateStatus::kFailNotAxisAligned) {
@@ -191,7 +175,8 @@ bool OverlayProcessorDelegated::AttemptWithStrategies(
}
}
- if (candidates->empty() || candidates->size() != quad_list->size()) {
+ if (candidates->empty() ||
+ (candidates->size() + num_quads_skipped) != quad_list->size()) {
candidates->clear();
return false;
}
@@ -208,6 +193,7 @@ bool OverlayProcessorDelegated::AttemptWithStrategies(
if (!each.overlay_handled) {
candidates->clear();
delegated_status_ = DelegationStatus::kCompositedCheckOverlayFail;
+ DBG_DRAW_RECT("delegated.handled.failed", each.display_rect);
return false;
}
}
@@ -241,7 +227,7 @@ void OverlayProcessorDelegated::ProcessForOverlays(
DCHECK(candidates->empty());
auto* render_pass = render_passes->back().get();
bool success = false;
-#if !defined(OS_APPLE)
+#if !BUILDFLAG(IS_APPLE)
RecordFDUsageUMA();
#endif
diff --git a/chromium/components/viz/service/display/overlay_processor_interface.cc b/chromium/components/viz/service/display/overlay_processor_interface.cc
index 9bfe8bf6fa8..cca66e07dd6 100644
--- a/chromium/components/viz/service/display/overlay_processor_interface.cc
+++ b/chromium/components/viz/service/display/overlay_processor_interface.cc
@@ -8,6 +8,7 @@
#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
+#include "build/build_config.h"
#include "build/chromecast_buildflags.h"
#include "build/chromeos_buildflags.h"
#include "components/viz/common/display/renderer_settings.h"
@@ -16,11 +17,11 @@
#include "components/viz/service/display/overlay_processor_stub.h"
#include "ui/gfx/overlay_priority_hint.h"
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
#include "components/viz/service/display/overlay_processor_mac.h"
-#elif defined(OS_WIN)
+#elif BUILDFLAG(IS_WIN)
#include "components/viz/service/display/overlay_processor_win.h"
-#elif defined(OS_ANDROID)
+#elif BUILDFLAG(IS_ANDROID)
#include "components/viz/service/display/overlay_processor_android.h"
#include "components/viz/service/display/overlay_processor_surface_control.h"
#elif defined(USE_OZONE)
@@ -99,12 +100,11 @@ OverlayProcessorInterface::CreateOverlayProcessor(
// overlay for WebView is enabled, this check still works.
if (surface_handle == gpu::kNullSurfaceHandle)
return std::make_unique<OverlayProcessorStub>();
-#if defined(OS_APPLE)
- DCHECK(capabilities.supports_surfaceless);
- return std::make_unique<OverlayProcessorMac>(
- renderer_settings.allow_overlays);
-#elif defined(OS_WIN)
+#if BUILDFLAG(IS_APPLE)
+ DCHECK(capabilities.supports_surfaceless);
+ return std::make_unique<OverlayProcessorMac>();
+#elif BUILDFLAG(IS_WIN)
if (!capabilities.supports_dc_layers)
return std::make_unique<OverlayProcessorStub>();
@@ -152,7 +152,7 @@ OverlayProcessorInterface::CreateOverlayProcessor(
return std::make_unique<OverlayProcessorOzone>(
std::move(overlay_candidates),
std::move(renderer_settings.overlay_strategies), sii);
-#elif defined(OS_ANDROID)
+#elif BUILDFLAG(IS_ANDROID)
DCHECK(display_controller);
if (capabilities.supports_surfaceless) {
@@ -219,4 +219,8 @@ void OverlayProcessorInterface::ScheduleOverlays(
void OverlayProcessorInterface::OverlayPresentationComplete() {}
+gfx::CALayerResult OverlayProcessorInterface::GetCALayerErrorCode() const {
+ return gfx::kCALayerSuccess;
+}
+
} // namespace viz
diff --git a/chromium/components/viz/service/display/overlay_processor_interface.h b/chromium/components/viz/service/display/overlay_processor_interface.h
index 8526cdefd58..8df355904ed 100644
--- a/chromium/components/viz/service/display/overlay_processor_interface.h
+++ b/chromium/components/viz/service/display/overlay_processor_interface.h
@@ -17,14 +17,15 @@
#include "components/viz/service/viz_service_export.h"
#include "gpu/ipc/common/surface_handle.h"
#include "gpu/ipc/gpu_task_scheduler_helper.h"
+#include "ui/gfx/ca_layer_result.h"
#include "ui/gfx/geometry/rrect_f.h"
#include "ui/gfx/overlay_priority_hint.h"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include "components/viz/service/display/dc_layer_overlay.h"
#endif
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
#include "components/viz/service/display/ca_layer_overlay.h"
#endif
@@ -44,21 +45,15 @@ class RendererSettings;
// for overlay processing that each platform needs to implement.
class VIZ_SERVICE_EXPORT OverlayProcessorInterface {
public:
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
using PlatformOverlayCandidate = CALayerOverlay;
-#elif defined(OS_WIN)
- using PlatformOverlayCandidate = DCLayerOverlay;
-#else
- // Default.
- using PlatformOverlayCandidate = OverlayCandidate;
-#endif
-
-#if defined(OS_APPLE)
using CandidateList = CALayerOverlayList;
-#elif defined(OS_WIN)
+#elif BUILDFLAG(IS_WIN)
+ using PlatformOverlayCandidate = DCLayerOverlay;
using CandidateList = DCLayerOverlayList;
#else
// Default.
+ using PlatformOverlayCandidate = OverlayCandidate;
using CandidateList = OverlayCandidateList;
#endif
@@ -109,6 +104,9 @@ class VIZ_SERVICE_EXPORT OverlayProcessorInterface {
gfx::OverlayPriorityHint priority_hint;
// Specifies the rounded corners.
gfx::RRectF rounded_corners;
+ // Optional damage rect. If none is provided the damage is assumed to be
+ // |resource_size| (full damage).
+ absl::optional<gfx::Rect> damage_rect;
};
// TODO(weiliangc): Eventually the asymmetry between primary plane and
@@ -202,6 +200,8 @@ class VIZ_SERVICE_EXPORT OverlayProcessorInterface {
// If true, video capture is enabled for this frame.
virtual void SetIsVideoCaptureEnabled(bool enabled) {}
+ virtual gfx::CALayerResult GetCALayerErrorCode() const;
+
protected:
OverlayProcessorInterface() = default;
};
diff --git a/chromium/components/viz/service/display/overlay_processor_mac.cc b/chromium/components/viz/service/display/overlay_processor_mac.cc
index 8bd012391a4..926e679230a 100644
--- a/chromium/components/viz/service/display/overlay_processor_mac.cc
+++ b/chromium/components/viz/service/display/overlay_processor_mac.cc
@@ -15,9 +15,10 @@
#include "ui/gfx/geometry/rect_conversions.h"
namespace viz {
-OverlayProcessorMac::OverlayProcessorMac(bool enable_ca_overlay)
- : ca_layer_overlay_processor_(
- std::make_unique<CALayerOverlayProcessor>(enable_ca_overlay)) {}
+
+OverlayProcessorMac::OverlayProcessorMac()
+ : ca_layer_overlay_processor_(std::make_unique<CALayerOverlayProcessor>()) {
+}
OverlayProcessorMac::OverlayProcessorMac(
std::unique_ptr<CALayerOverlayProcessor> ca_layer_overlay_processor)
@@ -47,6 +48,10 @@ gfx::Rect OverlayProcessorMac::GetAndResetOverlayDamage() {
return result;
}
+void OverlayProcessorMac::SetIsVideoCaptureEnabled(bool enabled) {
+ ca_layer_overlay_processor_->SetIsVideoCaptureEnabled(enabled);
+}
+
void OverlayProcessorMac::ProcessForOverlays(
DisplayResourceProvider* resource_provider,
AggregatedRenderPassList* render_passes,
@@ -110,4 +115,8 @@ bool OverlayProcessorMac::NeedsSurfaceDamageRectList() const {
return false;
}
+gfx::CALayerResult OverlayProcessorMac::GetCALayerErrorCode() const {
+ return ca_layer_overlay_processor_->ca_layer_result();
+}
+
} // namespace viz
diff --git a/chromium/components/viz/service/display/overlay_processor_mac.h b/chromium/components/viz/service/display/overlay_processor_mac.h
index 513cd2a2c10..673fe85dbd8 100644
--- a/chromium/components/viz/service/display/overlay_processor_mac.h
+++ b/chromium/components/viz/service/display/overlay_processor_mac.h
@@ -25,7 +25,7 @@ class VIZ_SERVICE_EXPORT OverlayProcessorMac
public:
using CandidateList = CALayerOverlayList;
- explicit OverlayProcessorMac(bool enable_ca_overlay);
+ OverlayProcessorMac();
// For testing.
explicit OverlayProcessorMac(
std::unique_ptr<CALayerOverlayProcessor> ca_layer_overlay_processor);
@@ -40,6 +40,7 @@ class VIZ_SERVICE_EXPORT OverlayProcessorMac
bool IsOverlaySupported() const override;
gfx::Rect GetPreviousFrameOverlaysBoundingRect() const override;
gfx::Rect GetAndResetOverlayDamage() override;
+ void SetIsVideoCaptureEnabled(bool enabled) override;
// Returns true if the platform supports hw overlays and surface occluding
// damage rect needs to be computed since it will be used by overlay
@@ -68,6 +69,8 @@ class VIZ_SERVICE_EXPORT OverlayProcessorMac
void AdjustOutputSurfaceOverlay(
absl::optional<OutputSurfaceOverlayPlane>* output_surface_plane) override;
+ gfx::CALayerResult GetCALayerErrorCode() const override;
+
private:
// The damage that should be added the next frame for drawing to the output
// surface.
diff --git a/chromium/components/viz/service/display/overlay_processor_on_gpu.cc b/chromium/components/viz/service/display/overlay_processor_on_gpu.cc
index 26ec61096fd..06775464666 100644
--- a/chromium/components/viz/service/display/overlay_processor_on_gpu.cc
+++ b/chromium/components/viz/service/display/overlay_processor_on_gpu.cc
@@ -3,6 +3,8 @@
// found in the LICENSE file.
#include "components/viz/service/display/overlay_processor_on_gpu.h"
+
+#include "build/build_config.h"
#include "gpu/command_buffer/service/shared_image_factory.h"
#include "gpu/command_buffer/service/shared_image_manager.h"
#include "gpu/ipc/display_compositor_memory_and_task_controller_on_gpu.h"
@@ -27,37 +29,32 @@ OverlayProcessorOnGpu::~OverlayProcessorOnGpu() {
void OverlayProcessorOnGpu::ScheduleOverlays(
CandidateList&& overlay_candidates) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// TODO(weiliangc): Currently only implemented for Android Classic code path.
for (auto& overlay : overlay_candidates) {
auto shared_image_overlay =
- shared_image_representation_factory_->ProduceOverlay(overlay.mailbox);
+ shared_image_representation_factory_->ProduceLegacyOverlay(
+ overlay.mailbox);
// When the display is re-opened, the first few frames might not have a
// video resource ready. Possible investigation crbug.com/1023971.
if (!shared_image_overlay)
continue;
- // In the current implementation, the BeginReadAccess will end up calling
- // CodecImage::RenderToOverlay. Currently this code path is only used for
- // Android Classic video overlay, where update of the overlay plane is
- // within the media code. Since we are not actually passing an overlay plane
- // to the display controller here, we are able to call EndReadAccess
- // directly after BeginReadAccess.
+ // RenderToOverlay() will notify media code to update frame in
+ // SurfaceView/Dialog.
shared_image_overlay->NotifyOverlayPromotion(
true, ToNearestRect(overlay.display_rect));
- std::unique_ptr<gpu::SharedImageRepresentationOverlay::ScopedReadAccess>
- scoped_access = shared_image_overlay->BeginScopedReadAccess(
- false /* needs_gl_image */);
+ shared_image_overlay->RenderToOverlay();
}
#endif
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
void OverlayProcessorOnGpu::NotifyOverlayPromotions(
base::flat_set<gpu::Mailbox> promotion_denied,
base::flat_map<gpu::Mailbox, gfx::Rect> possible_promotions) {
for (auto& denied : promotion_denied) {
auto shared_image_overlay =
- shared_image_representation_factory_->ProduceOverlay(denied);
+ shared_image_representation_factory_->ProduceLegacyOverlay(denied);
// When display is re-opened, the first few frames might not have video
// resource ready. Possible investigation crbug.com/1023971.
if (!shared_image_overlay)
@@ -67,7 +64,8 @@ void OverlayProcessorOnGpu::NotifyOverlayPromotions(
}
for (auto& possible : possible_promotions) {
auto shared_image_overlay =
- shared_image_representation_factory_->ProduceOverlay(possible.first);
+ shared_image_representation_factory_->ProduceLegacyOverlay(
+ possible.first);
// When display is re-opened, the first few frames might not have video
// resource ready. Possible investigation crbug.com/1023971.
if (!shared_image_overlay)
diff --git a/chromium/components/viz/service/display/overlay_processor_on_gpu.h b/chromium/components/viz/service/display/overlay_processor_on_gpu.h
index ce86d2ab255..f77db06e49c 100644
--- a/chromium/components/viz/service/display/overlay_processor_on_gpu.h
+++ b/chromium/components/viz/service/display/overlay_processor_on_gpu.h
@@ -12,11 +12,11 @@
#include "components/viz/service/display/overlay_candidate.h"
#include "components/viz/service/viz_service_export.h"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include "components/viz/service/display/dc_layer_overlay.h"
#endif
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
#include "components/viz/service/display/ca_layer_overlay.h"
#endif
@@ -32,9 +32,9 @@ namespace viz {
// destroyed on the gpu thread.
class VIZ_SERVICE_EXPORT OverlayProcessorOnGpu {
public:
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
using CandidateList = CALayerOverlayList;
-#elif defined(OS_WIN)
+#elif BUILDFLAG(IS_WIN)
using CandidateList = DCLayerOverlayList;
#else
// Default.
@@ -54,7 +54,7 @@ class VIZ_SERVICE_EXPORT OverlayProcessorOnGpu {
// presentation later.
void ScheduleOverlays(CandidateList&& overlay_candidates);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
void NotifyOverlayPromotions(
base::flat_set<gpu::Mailbox> promotion_denied,
base::flat_map<gpu::Mailbox, gfx::Rect> possible_promotions);
diff --git a/chromium/components/viz/service/display/overlay_processor_ozone.cc b/chromium/components/viz/service/display/overlay_processor_ozone.cc
index 92d2629e986..43b5f97b245 100644
--- a/chromium/components/viz/service/display/overlay_processor_ozone.cc
+++ b/chromium/components/viz/service/display/overlay_processor_ozone.cc
@@ -9,6 +9,8 @@
#include <vector>
#include "base/logging.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/timer/elapsed_timer.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "components/viz/common/features.h"
@@ -140,18 +142,9 @@ bool OverlayProcessorOzone::NeedsSurfaceDamageRectList() const {
return true;
}
-void OverlayProcessorOzone::CheckOverlaySupport(
+void OverlayProcessorOzone::CheckOverlaySupportImpl(
const OverlayProcessorInterface::OutputSurfaceOverlayPlane* primary_plane,
OverlayCandidateList* surfaces) {
- // This number is depended on what type of strategies we have. Currently we
- // only overlay one video.
-#if DCHECK_IS_ON()
- // TODO(petermcneeley) : Reconsider this check in light of delegated
- // compositing and multiple overlay work.
- if (!features::IsDelegatedCompositingEnabled()) {
- DCHECK_EQ(1U, surfaces->size());
- }
-#endif
auto full_size = surfaces->size();
if (primary_plane)
full_size += 1;
@@ -168,7 +161,7 @@ void OverlayProcessorOzone::CheckOverlaySupport(
ConvertToOzoneOverlaySurface(*primary_plane, &(*ozone_surface_iterator));
// TODO(crbug.com/1138568): Fuchsia claims support for presenting primary
// plane as overlay, but does not provide a mailbox. Handle this case.
-#if !defined(OS_FUCHSIA)
+#if !BUILDFLAG(IS_FUCHSIA)
if (shared_image_interface_) {
bool result = SetNativePixmapForCandidate(&(*ozone_surface_iterator),
primary_plane->mailbox,
@@ -202,11 +195,10 @@ void OverlayProcessorOzone::CheckOverlaySupport(
// to not display it at all).
// TODO(b/181974042): plumb the color space all the way to the ozone DRM
// backend when we get an API for per-plane color management.
- DCHECK(primary_plane);
if (!surface_iterator->requires_overlay &&
!AllowColorSpaceCombination(
/*source_color_space=*/surface_iterator->color_space,
- /*destination_color_space=*/primary_plane->color_space)) {
+ /*destination_color_space=*/primary_plane_color_space_)) {
*ozone_surface_iterator = ui::OverlaySurfaceCandidate();
ozone_surface_iterator->plane_z_order = surface_iterator->plane_z_order;
continue;
@@ -252,6 +244,12 @@ gfx::Rect OverlayProcessorOzone::GetOverlayDamageRectForOutputSurface(
return ToEnclosedRect(overlay.display_rect);
}
+void OverlayProcessorOzone::RegisterOverlayRequirement(bool requires_overlay) {
+ // This can be null in unit tests.
+ if (overlay_candidates_)
+ overlay_candidates_->RegisterOverlayRequirement(requires_overlay);
+}
+
bool OverlayProcessorOzone::SetNativePixmapForCandidate(
ui::OverlaySurfaceCandidate* candidate,
const gpu::Mailbox& mailbox,
diff --git a/chromium/components/viz/service/display/overlay_processor_ozone.h b/chromium/components/viz/service/display/overlay_processor_ozone.h
index f792133fa10..337775bc9fe 100644
--- a/chromium/components/viz/service/display/overlay_processor_ozone.h
+++ b/chromium/components/viz/service/display/overlay_processor_ozone.h
@@ -31,11 +31,12 @@ class VIZ_SERVICE_EXPORT OverlayProcessorOzone
void SetDisplayTransformHint(gfx::OverlayTransform transform) override {}
void SetViewportSize(const gfx::Size& size) override {}
- void CheckOverlaySupport(
+ void CheckOverlaySupportImpl(
const OverlayProcessorInterface::OutputSurfaceOverlayPlane* primary_plane,
OverlayCandidateList* surfaces) override;
gfx::Rect GetOverlayDamageRectForOutputSurface(
const OverlayCandidate& candidate) const override;
+ void RegisterOverlayRequirement(bool requires_overlay) override;
private:
// Populates |native_pixmap| and |native_pixmap_unique_id| in |candidate|
diff --git a/chromium/components/viz/service/display/overlay_processor_ozone_unittest.cc b/chromium/components/viz/service/display/overlay_processor_ozone_unittest.cc
index 1fcf6e7f6fd..675c8ecc48c 100644
--- a/chromium/components/viz/service/display/overlay_processor_ozone_unittest.cc
+++ b/chromium/components/viz/service/display/overlay_processor_ozone_unittest.cc
@@ -79,7 +79,7 @@ class MockSharedImageInterface : public TestSharedImageInterface {
// TODO(crbug.com/1138568): Fuchsia claims support for presenting primary
// plane as overlay, but does not provide a mailbox. Handle this case.
-#if !defined(OS_FUCHSIA)
+#if !BUILDFLAG(IS_FUCHSIA)
TEST(OverlayProcessorOzoneTest, PrimaryPlaneSizeAndFormatMatches) {
// Set up the primary plane.
gfx::Size size(128, 128);
diff --git a/chromium/components/viz/service/display/overlay_processor_strategy.cc b/chromium/components/viz/service/display/overlay_processor_strategy.cc
new file mode 100644
index 00000000000..0960a9fe62a
--- /dev/null
+++ b/chromium/components/viz/service/display/overlay_processor_strategy.cc
@@ -0,0 +1,26 @@
+// Copyright 2022 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.
+
+#include "components/viz/service/display/overlay_processor_strategy.h"
+
+#include "components/viz/common/display/overlay_strategy.h"
+
+namespace viz {
+
+// Default implementation of whether a strategy would remove the output surface
+// as overlay plane.
+bool OverlayProcessorStrategy::RemoveOutputSurfaceAsOverlay() {
+ return false;
+}
+
+OverlayStrategy OverlayProcessorStrategy::GetUMAEnum() const {
+ return OverlayStrategy::kUnknown;
+}
+
+gfx::RectF OverlayProcessorStrategy::GetPrimaryPlaneDisplayRect(
+ const PrimaryPlane* primary_plane) {
+ return primary_plane ? primary_plane->display_rect : gfx::RectF();
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/service/display/overlay_processor_strategy.h b/chromium/components/viz/service/display/overlay_processor_strategy.h
new file mode 100644
index 00000000000..92af2c5cd1d
--- /dev/null
+++ b/chromium/components/viz/service/display/overlay_processor_strategy.h
@@ -0,0 +1,102 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_OVERLAY_PROCESSOR_STRATEGY_H_
+#define COMPONENTS_VIZ_SERVICE_DISPLAY_OVERLAY_PROCESSOR_STRATEGY_H_
+
+#include <memory>
+#include <vector>
+
+#include "components/viz/common/display/overlay_strategy.h"
+#include "components/viz/common/quads/aggregated_render_pass.h"
+#include "components/viz/service/display/overlay_candidate.h"
+#include "components/viz/service/display/overlay_processor_interface.h"
+#include "components/viz/service/display/overlay_proposed_candidate.h"
+#include "components/viz/service/viz_service_export.h"
+
+namespace viz {
+
+// A strategy for promoting a DrawQuad(s) to overlays. Used by
+// `OverlayProcessorUsingStrategy` for proposing and attempting candidates quads
+// in different ways.
+class VIZ_SERVICE_EXPORT OverlayProcessorStrategy {
+ public:
+ virtual ~OverlayProcessorStrategy() = default;
+ using PrimaryPlane = OverlayProcessorInterface::OutputSurfaceOverlayPlane;
+
+ // Returns false if the strategy cannot be made to work with the
+ // current set of render passes. Returns true if the strategy was successful
+ // and adds any additional passes necessary to represent overlays to
+ // |render_pass_list|. Most strategies should look at the primary
+ // RenderPass, the last element.
+ virtual bool Attempt(const skia::Matrix44& output_color_matrix,
+ const OverlayProcessorInterface::FilterOperationsMap&
+ render_pass_backdrop_filters,
+ DisplayResourceProvider* resource_provider,
+ AggregatedRenderPassList* render_pass_list,
+ SurfaceDamageRectList* surface_damage_rect_list,
+ const PrimaryPlane* primary_plane,
+ OverlayCandidateList* candidates,
+ std::vector<gfx::Rect>* content_bounds) = 0;
+
+ // Appends all legitimate overlay candidates to the list |candidates|
+ // for this strategy. It is very important to note that this function
+ // should not attempt a specific candidate it should merely identify them
+ // and save the necessary data required to for a later attempt.
+ virtual void ProposePrioritized(
+ const skia::Matrix44& output_color_matrix,
+ const OverlayProcessorInterface::FilterOperationsMap&
+ render_pass_backdrop_filters,
+ DisplayResourceProvider* resource_provider,
+ AggregatedRenderPassList* render_pass_list,
+ SurfaceDamageRectList* surface_damage_rect_list,
+ const PrimaryPlane* primary_plane,
+ std::vector<OverlayProposedCandidate>* candidates,
+ std::vector<gfx::Rect>* content_bounds) = 0;
+
+ // Returns false if the specific |proposed_candidate| cannot be made to work
+ // for this strategy with the current set of render passes. Returns true if
+ // the strategy was successful and adds any additional passes necessary to
+ // represent overlays to |render_pass_list|. Most strategies should look at
+ // the primary RenderPass, the last element.
+ virtual bool AttemptPrioritized(
+ const skia::Matrix44& output_color_matrix,
+ const OverlayProcessorInterface::FilterOperationsMap&
+ render_pass_backdrop_filters,
+ DisplayResourceProvider* resource_provider,
+ AggregatedRenderPassList* render_pass_list,
+ SurfaceDamageRectList* surface_damage_rect_list,
+ const PrimaryPlane* primary_plane,
+ OverlayCandidateList* candidates,
+ std::vector<gfx::Rect>* content_bounds,
+ const OverlayProposedCandidate& proposed_candidate) = 0;
+
+ // Commits to using the proposed candidate by updating |render_pass| as
+ // appropriate when this candidate is presented in an overlay plane.
+ virtual void CommitCandidate(
+ const OverlayProposedCandidate& proposed_candidate,
+ AggregatedRenderPass* render_pass) = 0;
+
+ // Currently this is only overridden by the Underlay strategy: the underlay
+ // strategy needs to enable blending for the primary plane in order to show
+ // content underneath.
+ virtual void AdjustOutputSurfaceOverlay(
+ OverlayProcessorInterface::OutputSurfaceOverlayPlane*
+ output_surface_plane) {}
+
+ // Currently this is only overridden by the Fullscreen strategy: the
+ // fullscreen strategy covers the entire screen and there is no need to use
+ // the primary plane.
+ virtual bool RemoveOutputSurfaceAsOverlay();
+
+ virtual OverlayStrategy GetUMAEnum() const;
+
+ // Does a null-check on |primary_plane| and returns it's |display_rect|
+ // member if non-null and an empty gfx::RectF otherwise.
+ gfx::RectF GetPrimaryPlaneDisplayRect(const PrimaryPlane* primary_plane);
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_OVERLAY_PROCESSOR_STRATEGY_H_
diff --git a/chromium/components/viz/service/display/overlay_processor_stub.cc b/chromium/components/viz/service/display/overlay_processor_stub.cc
index ad6a26fba3d..16f82ddf30d 100644
--- a/chromium/components/viz/service/display/overlay_processor_stub.cc
+++ b/chromium/components/viz/service/display/overlay_processor_stub.cc
@@ -19,4 +19,8 @@ bool OverlayProcessorStub::NeedsSurfaceDamageRectList() const {
return false;
}
+gfx::CALayerResult OverlayProcessorStub::GetCALayerErrorCode() const {
+ return gfx::kCALayerFailedOverlayDisabled;
+}
+
} // namespace viz
diff --git a/chromium/components/viz/service/display/overlay_processor_stub.h b/chromium/components/viz/service/display/overlay_processor_stub.h
index 17cf54f9781..aa7addfdca4 100644
--- a/chromium/components/viz/service/display/overlay_processor_stub.h
+++ b/chromium/components/viz/service/display/overlay_processor_stub.h
@@ -42,6 +42,7 @@ class VIZ_SERVICE_EXPORT OverlayProcessorStub
absl::optional<OutputSurfaceOverlayPlane>* output_surface_plane) final {}
void SetDisplayTransformHint(gfx::OverlayTransform transform) final {}
void SetViewportSize(const gfx::Size& size) final {}
+ gfx::CALayerResult GetCALayerErrorCode() const final;
};
} // namespace viz
diff --git a/chromium/components/viz/service/display/overlay_processor_surface_control.cc b/chromium/components/viz/service/display/overlay_processor_surface_control.cc
index c3927370edd..e6ae53f6812 100644
--- a/chromium/components/viz/service/display/overlay_processor_surface_control.cc
+++ b/chromium/components/viz/service/display/overlay_processor_surface_control.cc
@@ -49,7 +49,7 @@ bool OverlayProcessorSurfaceControl::NeedsSurfaceDamageRectList() const {
return true;
}
-void OverlayProcessorSurfaceControl::CheckOverlaySupport(
+void OverlayProcessorSurfaceControl::CheckOverlaySupportImpl(
const OverlayProcessorInterface::OutputSurfaceOverlayPlane* primary_plane,
OverlayCandidateList* candidates) {
DCHECK(!candidates->empty());
diff --git a/chromium/components/viz/service/display/overlay_processor_surface_control.h b/chromium/components/viz/service/display/overlay_processor_surface_control.h
index c82cd7c30c6..4c08675c5b7 100644
--- a/chromium/components/viz/service/display/overlay_processor_surface_control.h
+++ b/chromium/components/viz/service/display/overlay_processor_surface_control.h
@@ -25,7 +25,7 @@ class VIZ_SERVICE_EXPORT OverlayProcessorSurfaceControl
void SetViewportSize(const gfx::Size& size) override;
void AdjustOutputSurfaceOverlay(
absl::optional<OutputSurfaceOverlayPlane>* output_surface_plane) override;
- void CheckOverlaySupport(
+ void CheckOverlaySupportImpl(
const OverlayProcessorInterface::OutputSurfaceOverlayPlane* primary_plane,
OverlayCandidateList* candidates) override;
gfx::Rect GetOverlayDamageRectForOutputSurface(
diff --git a/chromium/components/viz/service/display/overlay_processor_using_strategy.cc b/chromium/components/viz/service/display/overlay_processor_using_strategy.cc
index 69d6f6b85d8..73e5ed3dad4 100644
--- a/chromium/components/viz/service/display/overlay_processor_using_strategy.cc
+++ b/chromium/components/viz/service/display/overlay_processor_using_strategy.cc
@@ -5,16 +5,22 @@
#include "components/viz/service/display/overlay_processor_using_strategy.h"
#include <algorithm>
+#include <set>
#include <utility>
#include <vector>
#include "base/feature_list.h"
#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
+#include "base/ranges/algorithm.h"
#include "base/strings/string_number_conversions.h"
+#include "base/time/time.h"
+#include "base/timer/elapsed_timer.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
#include "components/viz/common/features.h"
+#include "components/viz/common/quads/aggregated_render_pass.h"
+#include "components/viz/common/quads/quad_list.h"
#include "components/viz/common/quads/solid_color_draw_quad.h"
#include "components/viz/service/debugger/viz_debugger.h"
#include "components/viz/service/display/display_resource_provider.h"
@@ -22,6 +28,7 @@
#include "components/viz/service/display/overlay_candidate.h"
#include "components/viz/service/display/overlay_strategy_single_on_top.h"
#include "components/viz/service/display/overlay_strategy_underlay.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/geometry/transform.h"
@@ -81,28 +88,12 @@ static void LogStrategyEnumUMA(OverlayStrategy strategy) {
OverlayProcessorUsingStrategy::ProposedCandidateKey
OverlayProcessorUsingStrategy::ToProposeKey(
- const OverlayProcessorUsingStrategy::Strategy::OverlayProposedCandidate&
- proposed) {
+ const OverlayProposedCandidate& proposed) {
return {proposed.candidate.tracking_id, proposed.strategy->GetUMAEnum()};
}
-// Default implementation of whether a strategy would remove the output surface
-// as overlay plane.
-bool OverlayProcessorUsingStrategy::Strategy::RemoveOutputSurfaceAsOverlay() {
- return false;
-}
-
-OverlayStrategy OverlayProcessorUsingStrategy::Strategy::GetUMAEnum() const {
- return OverlayStrategy::kUnknown;
-}
-
-gfx::RectF OverlayProcessorUsingStrategy::Strategy::GetPrimaryPlaneDisplayRect(
- const PrimaryPlane* primary_plane) {
- return primary_plane ? primary_plane->display_rect : gfx::RectF();
-}
-
OverlayProcessorUsingStrategy::OverlayProcessorUsingStrategy()
- : OverlayProcessorInterface() {}
+ : max_overlays_considered_(features::MaxOverlaysConsidered()) {}
OverlayProcessorUsingStrategy::~OverlayProcessorUsingStrategy() = default;
@@ -141,6 +132,11 @@ void OverlayProcessorUsingStrategy::ProcessForOverlays(
CandidateList* candidates,
gfx::Rect* damage_rect,
std::vector<gfx::Rect>* content_bounds) {
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+ // TODO(b/181974042): Remove when color space is plumbed.
+ if (output_surface_plane)
+ primary_plane_color_space_ = output_surface_plane->color_space;
+#endif
TRACE_EVENT0("viz", "OverlayProcessorUsingStrategy::ProcessForOverlays");
DCHECK(candidates->empty());
auto* render_pass = render_passes->back().get();
@@ -167,11 +163,12 @@ void OverlayProcessorUsingStrategy::ProcessForOverlays(
candidates, content_bounds);
}
}
+ LogCheckOverlaySupportMetrics();
DCHECK(candidates->empty() || success);
- UpdateDamageRect(candidates, &surface_damage_rect_list,
- &render_pass->quad_list, damage_rect);
+ UpdateOverlayStatusMap(*candidates);
+ UpdateDamageRect(surface_damage_rect_list, *damage_rect);
NotifyOverlayPromotion(resource_provider, *candidates,
render_pass->quad_list);
@@ -185,35 +182,85 @@ void OverlayProcessorUsingStrategy::ProcessForOverlays(
"Scheduled overlay planes", candidates->size());
}
+void OverlayProcessorUsingStrategy::CheckOverlaySupport(
+ const OverlayProcessorInterface::OutputSurfaceOverlayPlane* primary_plane,
+ OverlayCandidateList* candidate_list) {
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+ // TODO(b/181974042): Remove when color space is plumbed.
+ if (primary_plane)
+ primary_plane_color_space_ = primary_plane->color_space;
+#endif
+
+ base::ElapsedTimer timer;
+ CheckOverlaySupportImpl(primary_plane, candidate_list);
+ check_overlay_support_call_count_++;
+
+ base::TimeDelta time = timer.Elapsed();
+
+ static constexpr base::TimeDelta kMinTime = base::Microseconds(1);
+ static constexpr base::TimeDelta kMaxTime = base::Milliseconds(10);
+ static constexpr int kTimeBuckets = 50;
+ UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES(
+ "Compositing.Display.OverlayProcessorUsingStrategy.CheckOverlaySupportUs",
+ time, kMinTime, kMaxTime, kTimeBuckets);
+}
+
// This local function simply recomputes the root damage from
// |surface_damage_rect_list| while excluding the damage contribution from a
// specific overlay.
// TODO(petermcneeley): Eventually this code should be commonized in the same
// location as the definition of |SurfaceDamageRectList|
-namespace {
-gfx::Rect ComputeDamageExcludingIndex(
- uint32_t overlay_damage_index,
- SurfaceDamageRectList* surface_damage_rect_list,
- const gfx::Rect& existing_damage,
- const gfx::Rect& display_rect,
- bool is_opaque,
- bool is_underlay) {
- gfx::Rect root_damage_rect;
-
- if (overlay_damage_index == OverlayCandidate::kInvalidDamageIndex) {
- // An opaque overlay that is on top will hide any damage underneath.
- // TODO(petermcneeley): This is a special case optimization which could be
- // removed if we had more reliable damage.
- if (is_opaque && !is_underlay) {
- return gfx::SubtractRects(existing_damage, display_rect);
- }
+gfx::Rect OverlayProcessorUsingStrategy::ComputeDamageExcludingOverlays(
+ const SurfaceDamageRectList& surface_damage_rect_list,
+ const gfx::Rect& existing_damage) {
+ if (curr_overlays_.empty()) {
return existing_damage;
}
- gfx::Rect occluding_rect;
- for (size_t i = 0; i < surface_damage_rect_list->size(); i++) {
- if (overlay_damage_index != i) {
- gfx::Rect curr_surface_damage = (*surface_damage_rect_list)[i];
+ if (curr_overlays_.size() == 1) {
+ auto& status = curr_overlays_.begin()->second;
+ if (status.damage_index == OverlayCandidate::kInvalidDamageIndex) {
+ // An opaque overlay that is on top will hide any damage underneath.
+ // TODO(petermcneeley): This is a special case optimization which could be
+ // removed if we had more reliable damage.
+ if (status.is_opaque && !status.is_underlay) {
+ return gfx::SubtractRects(existing_damage, status.overlay_rect);
+ }
+ return existing_damage;
+ }
+ }
+
+ // Create a list of iterators to all `curr_overlays_` entries, sorted by
+ // damage index, so we can encounter them in order as we loop through
+ // `surface_damage_rect_list`.
+ std::vector<OverlayStatusMap::const_iterator> overlay_status_iters;
+ overlay_status_iters.reserve(curr_overlays_.size());
+ for (auto it = curr_overlays_.begin(); it != curr_overlays_.end(); ++it) {
+ overlay_status_iters.push_back(it);
+ }
+ std::sort(overlay_status_iters.begin(), overlay_status_iters.end(),
+ [](const auto& it1, const auto& it2) {
+ return it1->second.damage_index < it2->second.damage_index;
+ });
+
+ gfx::Rect computed_damage_rect;
+ auto overlay_status_it = overlay_status_iters.begin();
+ std::vector<gfx::Rect> occluding_rects;
+ for (size_t i = 0; i < surface_damage_rect_list.size(); i++) {
+ size_t curr_overlay_damage_index =
+ overlay_status_it != overlay_status_iters.end()
+ ? (*overlay_status_it)->second.damage_index
+ : OverlayCandidate::kInvalidDamageIndex;
+ if (curr_overlay_damage_index == i) {
+ const OverlayStatus& status = (*overlay_status_it)->second;
+ // |surface_damage_rect_list| is ordered such that from here on this
+ // |overlay_rect| will act as an occluder for damage after.
+ if (status.is_opaque) {
+ occluding_rects.push_back(status.overlay_rect);
+ }
+ overlay_status_it++;
+ } else {
+ gfx::Rect curr_surface_damage = surface_damage_rect_list[i];
// The |surface_damage_rect_list| can include damage rects coming from
// outside and partially outside the original |existing_damage| area. This
@@ -222,22 +269,63 @@ gfx::Rect ComputeDamageExcludingIndex(
// the |existing_damage| we avoid unnecessary final damage output.
// https://crbug.com/1197609
curr_surface_damage.Intersect(existing_damage);
- // Only add damage back in if it is not occluded by the overlay.
- if (!occluding_rect.Contains(curr_surface_damage)) {
- root_damage_rect.Union(curr_surface_damage);
- }
- } else {
- // |surface_damage_rect_list| is ordered such that from here on the
- // |display_rect| for the overlay will act as an occluder for damage
- // after.
- if (is_opaque) {
- occluding_rect = display_rect;
+
+ // Only add damage back in if it is not occluded by any overlays.
+ bool is_occluded = base::ranges::any_of(
+ occluding_rects, [&curr_surface_damage](const gfx::Rect& occluder) {
+ return occluder.Contains(curr_surface_damage);
+ });
+ if (!is_occluded) {
+ computed_damage_rect.Union(curr_surface_damage);
}
}
}
- return root_damage_rect;
+ return computed_damage_rect;
+}
+
+OverlayProcessorUsingStrategy::OverlayStatus::OverlayStatus(
+ const OverlayCandidate& candidate,
+ const gfx::Rect& key,
+ const OverlayStatusMap& prev_overlays) {
+ overlay_rect = ToEnclosedRect(candidate.display_rect);
+ damage_rect = candidate.damage_rect;
+ damage_index = candidate.overlay_damage_index;
+ damage_area_estimate = candidate.damage_area_estimate;
+ has_mask_filter = candidate.has_mask_filter;
+ plane_z_order = candidate.plane_z_order;
+ is_underlay = candidate.plane_z_order < 0;
+ is_opaque = candidate.is_opaque;
+
+ auto prev_it = prev_overlays.find(key);
+ if (prev_it != prev_overlays.end()) {
+ is_new = false;
+ prev_was_underlay = prev_it->second.is_underlay;
+ prev_has_mask_filter = prev_it->second.has_mask_filter;
+ } else {
+ is_new = true;
+ prev_was_underlay = false;
+ prev_has_mask_filter = false;
+ }
+}
+
+OverlayProcessorUsingStrategy::OverlayStatus::OverlayStatus(
+ const OverlayStatus&) = default;
+OverlayProcessorUsingStrategy::OverlayStatus&
+OverlayProcessorUsingStrategy::OverlayStatus::operator=(const OverlayStatus&) =
+ default;
+OverlayProcessorUsingStrategy::OverlayStatus::~OverlayStatus() = default;
+
+void OverlayProcessorUsingStrategy::UpdateOverlayStatusMap(
+ const OverlayCandidateList& candidates) {
+ // Move `curr_overlays_` into `prev_overlays_`
+ prev_overlays_.clear();
+ curr_overlays_.swap(prev_overlays_);
+
+ for (auto& candidate : candidates) {
+ gfx::Rect key = GetOverlayDamageRectForOutputSurface(candidate);
+ curr_overlays_.emplace(key, OverlayStatus(candidate, key, prev_overlays_));
+ }
}
-} // namespace
// Exclude overlay damage from the root damage when possible. In the steady
// state the overlay damage is always removed but transitions can require us to
@@ -247,74 +335,61 @@ gfx::Rect ComputeDamageExcludingIndex(
// transparent quad). Overlays only need to produce transition damage on
// demotion as they do not use the primary plane during promoted phase.
void OverlayProcessorUsingStrategy::UpdateDamageRect(
- OverlayCandidateList* candidates,
- SurfaceDamageRectList* surface_damage_rect_list,
- const QuadList* quad_list,
- gfx::Rect* damage_rect) {
- // TODO(petermcneeley): This code only supports one overlay candidate. To
- // support multiple overlays one would need to track the difference set of
- // overlays between frames.
- DCHECK_LE(candidates->size(), 1U);
-
- gfx::Rect this_frame_overlay_rect;
- bool has_mask_filter = false;
- bool is_opaque_overlay = false;
- bool is_underlay = false;
- uint32_t exclude_overlay_index = OverlayCandidate::kInvalidDamageIndex;
-
- for (const OverlayCandidate& overlay : *candidates) {
- this_frame_overlay_rect = GetOverlayDamageRectForOutputSurface(overlay);
- has_mask_filter = overlay.has_mask_filter;
- if (overlay.plane_z_order >= 0) {
- // If an overlay candidate comes from output surface, its z-order should
- // be 0.
- overlay_damage_rect_.Union(this_frame_overlay_rect);
- is_opaque_overlay = overlay.is_opaque;
- exclude_overlay_index = overlay.overlay_damage_index;
- } else {
- // Underlay candidate is assumed to be opaque.
- is_opaque_overlay = true;
- is_underlay = true;
- exclude_overlay_index = overlay.overlay_damage_index;
+ const SurfaceDamageRectList& surface_damage_rect_list,
+ gfx::Rect& damage_rect) {
+ DCHECK_LE(curr_overlays_.size(),
+ static_cast<size_t>(max_overlays_considered_));
+
+ // Remove all damage caused by these overlays, and any damage they occlude.
+ damage_rect =
+ ComputeDamageExcludingOverlays(surface_damage_rect_list, damage_rect);
+ previous_frame_overlay_rect_ = gfx::Rect();
+
+ for (auto& [key, status] : curr_overlays_) {
+ if (!status.is_underlay) {
+ overlay_damage_rect_.Union(status.overlay_rect);
+ }
+ previous_frame_overlay_rect_.Union(status.overlay_rect);
+
+ // Our current overlays need to damage the primary plane in these cases:
+ // - A previous overlay became an Underlay this frame
+ // - An newly promoted underlay or transparent overlay
+ // - An overlay that added/removed a mask filter this frame
+ //
+ // Rationale:
+ // - Related bugs: https://crbug.com/875879 https://crbug.com/1107460
+ // - We need to make sure that when we transition to an underlay, we damage
+ // the region where the underlay will be positioned. This is because a
+ // black transparent hole is made for the underlay to show through,
+ // but its possible that the damage for this quad is less than the
+ // complete size of the underlay. https://crbug.com/1130733
+ // - The primary plane may be visible underneath transparent overlays, so
+ // we need to damage it to remove any trace this quad left behind.
+ // https://buganizer.corp.google.com/issues/192294199
+ if ((status.is_underlay && !status.prev_was_underlay) ||
+ (status.is_new && (status.is_underlay || !status.is_opaque)) ||
+ (status.has_mask_filter != status.prev_has_mask_filter)) {
+ damage_rect.Union(status.overlay_rect);
}
}
-
- // Removes all damage from this overlay and occluded surface damages.
- *damage_rect = ComputeDamageExcludingIndex(
- exclude_overlay_index, surface_damage_rect_list, *damage_rect,
- this_frame_overlay_rect, is_opaque_overlay, is_underlay);
-
- // Drawing on the overlay_rect usually occurs on a different plane, but we
- // still need to damage the overlay_rect when certain changes occur from one
- // frame to the next. https://crbug.com/875879 https://crbug.com/1107460
- if ((!previous_is_underlay && is_underlay) ||
- has_mask_filter != previous_has_mask_filter_ ||
- this_frame_overlay_rect != previous_frame_overlay_rect_) {
- damage_rect->Union(previous_frame_overlay_rect_);
-
- // We need to make sure that when we transition to an underlay we damage the
- // region where the underlay will be positioned. This is because a
- // black transparent hole is made for the underlay to show through
- // but its possible that the damage for this quad is less than the
- // complete size of the underlay. https://crbug.com/1130733
- // Also a non-opaque overlay must damage the primary plane as we might be
- // able see through the overlay to the primary plane.
- // https://buganizer.corp.google.com/issues/192294199
- if (is_underlay || !is_opaque_overlay) {
- damage_rect->Union(this_frame_overlay_rect);
+ // Damage is required for any overlays from the last frame that got demoted
+ // this frame.
+ for (auto& [key, status] : prev_overlays_) {
+ // Overlays present last frame that are absent this frame have been demoted.
+ if (curr_overlays_.find(key) == curr_overlays_.end()) {
+ damage_rect.Union(status.overlay_rect);
}
}
- // Record the first candidate.
- if (candidates->size() > 0 && (*candidates)[0].plane_z_order != 0) {
- RecordOverlayDamageRectHistograms(
- (*candidates)[0].plane_z_order > 0,
- (*candidates)[0].damage_area_estimate != 0, damage_rect->IsEmpty());
+ // Record each on top and underlay candidate.
+ for (auto it : curr_overlays_) {
+ const auto& status = it.second;
+ if (status.plane_z_order != 0) {
+ RecordOverlayDamageRectHistograms(status.plane_z_order > 0,
+ status.damage_area_estimate != 0,
+ damage_rect.IsEmpty());
+ }
}
-
- previous_frame_overlay_rect_ = this_frame_overlay_rect;
- previous_has_mask_filter_ = has_mask_filter;
- previous_is_underlay = is_underlay;
}
void OverlayProcessorUsingStrategy::AdjustOutputSurfaceOverlay(
@@ -359,7 +434,7 @@ bool OverlayProcessorUsingStrategy::AttemptWithStrategies(
}
void OverlayProcessorUsingStrategy::SortProposedOverlayCandidatesPrioritized(
- Strategy::OverlayProposedCandidateList* proposed_candidates) {
+ std::vector<OverlayProposedCandidate>* proposed_candidates) {
// Removes trackers for candidates that are no longer being rendered.
for (auto it = tracked_candidates_.begin();
it != tracked_candidates_.end();) {
@@ -469,7 +544,7 @@ bool OverlayProcessorUsingStrategy::AttemptWithStrategiesPrioritized(
std::vector<gfx::Rect>* content_bounds,
gfx::Rect* incoming_damage) {
last_successful_strategy_ = nullptr;
- Strategy::OverlayProposedCandidateList proposed_candidates;
+ std::vector<OverlayProposedCandidate> proposed_candidates;
for (const auto& strategy : strategies_) {
strategy->ProposePrioritized(
output_color_matrix, render_pass_backdrop_filters, resource_provider,
@@ -484,12 +559,21 @@ bool OverlayProcessorUsingStrategy::AttemptWithStrategiesPrioritized(
SortProposedOverlayCandidatesPrioritized(&proposed_candidates);
+ if (ShouldAttemptMultipleOverlays(proposed_candidates)) {
+ auto* render_pass = render_pass_list->back().get();
+ return AttemptMultipleOverlays(proposed_candidates, primary_plane,
+ render_pass, *candidates);
+ }
+
+ bool has_required_overlay = false;
for (auto&& candidate : proposed_candidates) {
// Underlays change the material so we save it here to record proper UMA.
DrawQuad::Material quad_material =
candidate.strategy->GetUMAEnum() != OverlayStrategy::kUnknown
? candidate.quad_iter->material
: DrawQuad::Material::kInvalid;
+ if (candidate.candidate.requires_overlay)
+ has_required_overlay = true;
bool used_overlay = candidate.strategy->AttemptPrioritized(
output_color_matrix, render_pass_backdrop_filters, resource_provider,
@@ -548,9 +632,11 @@ bool OverlayProcessorUsingStrategy::AttemptWithStrategiesPrioritized(
UpdateDownscalingCapabilities(scale_factor, /*success=*/true);
}
}
+ RegisterOverlayRequirement(has_required_overlay);
return true;
}
}
+ RegisterOverlayRequirement(has_required_overlay);
if (proposed_candidates.size() == 0) {
LogStrategyEnumUMA(num_proposed_pre_sort != 0
@@ -563,6 +649,160 @@ bool OverlayProcessorUsingStrategy::AttemptWithStrategiesPrioritized(
return false;
}
+bool OverlayProcessorUsingStrategy::ShouldAttemptMultipleOverlays(
+ const std::vector<OverlayProposedCandidate>& sorted_candidates) {
+ if (max_overlays_considered_ <= 1) {
+ return false;
+ }
+
+ for (auto& proposed : sorted_candidates) {
+ // When candidates that require overlays fail, they get retried with
+ // different scale factors. This becomes complicated when using multiple
+ // overlays at once so we won't attempt multiple in that case.
+ if (proposed.candidate.requires_overlay) {
+ return false;
+ }
+ // Using multiple overlays only makes sense with SingleOnTop and Underlay
+ // strategies.
+ OverlayStrategy type = proposed.strategy->GetUMAEnum();
+ if (type != OverlayStrategy::kSingleOnTop &&
+ type != OverlayStrategy::kUnderlay) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool OverlayProcessorUsingStrategy::AttemptMultipleOverlays(
+ const std::vector<OverlayProposedCandidate>& sorted_candidates,
+ OverlayProcessorInterface::OutputSurfaceOverlayPlane* primary_plane,
+ AggregatedRenderPass* render_pass,
+ OverlayCandidateList& candidates) {
+ int max_overlays_possible = std::min(
+ max_overlays_considered_, static_cast<int>(sorted_candidates.size()));
+
+ std::vector<OverlayProposedCandidate> test_candidates;
+ // Reserve max possible overlays so iterators remain stable while we insert
+ // candidates.
+ test_candidates.reserve(max_overlays_possible);
+ bool testing_underlay = false;
+ // We'll keep track of the underlays that we're testing so we can assign their
+ // `plane_z_order`s based on their order in the QuadList.
+ std::vector<std::vector<OverlayProposedCandidate>::iterator> underlay_iters;
+ // Used to prevent testing multiple candidates representing the same DrawQuad.
+ std::set<size_t> used_quad_indices;
+
+ for (auto& cand : sorted_candidates) {
+ // Skip candidates whose quads have already been added to the test list. A
+ // quad could have an on top and an underlay candidate.
+ bool inserted = used_quad_indices.insert(cand.quad_iter.index()).second;
+ if (!inserted) {
+ continue;
+ }
+ test_candidates.push_back(cand);
+
+ switch (cand.strategy->GetUMAEnum()) {
+ case OverlayStrategy::kSingleOnTop:
+ // Ordering of on top candidates doesn't matter (they can't overlap), so
+ // they can all have z = 1.
+ test_candidates.back().candidate.plane_z_order = 1;
+ break;
+ case OverlayStrategy::kUnderlay:
+ testing_underlay = true;
+ underlay_iters.push_back(test_candidates.end() - 1);
+ break;
+ default:
+ // Unsupported strategy type.
+ NOTREACHED();
+ }
+ if (test_candidates.size() == static_cast<size_t>(max_overlays_possible)) {
+ break;
+ }
+ }
+
+ // We don't sort the actual items in `test_candidates` here in order to
+ // maintain the power-gain sorted order.
+ AssignUnderlayZOrders(underlay_iters);
+
+ candidates.reserve(test_candidates.size());
+ for (auto& proposed_candidate : test_candidates) {
+ candidates.push_back(proposed_candidate.candidate);
+ }
+
+ if (!testing_underlay || !primary_plane) {
+ CheckOverlaySupport(primary_plane, &candidates);
+ } else {
+ OverlayProcessorStrategy::PrimaryPlane new_plane_candidate(*primary_plane);
+ new_plane_candidate.enable_blending = true;
+ // Check for support.
+ CheckOverlaySupport(&new_plane_candidate, &candidates);
+ }
+
+ bool underlay_used = false;
+ auto cand_it = candidates.begin();
+ auto test_it = test_candidates.begin();
+ while (cand_it != candidates.end()) {
+ // Update the test candidates so we can use EraseIf below.
+ test_it->candidate.overlay_handled = cand_it->overlay_handled;
+ if (cand_it->overlay_handled && cand_it->plane_z_order < 0) {
+ underlay_used = true;
+ }
+ cand_it++;
+ test_it++;
+ }
+ // Remove failed candidates
+ base::EraseIf(candidates, [](auto& cand) { return !cand.overlay_handled; });
+ base::EraseIf(test_candidates, [](auto& proposed) -> bool {
+ return !proposed.candidate.overlay_handled;
+ });
+
+ if (candidates.empty()) {
+ return false;
+ }
+
+ if (underlay_used && primary_plane) {
+ // Using underlays means the primary plane needs blending enabled.
+ primary_plane->enable_blending = true;
+ }
+
+ // Sort test candidates in reverse order so we can commit them from back to
+ // front. This makes sure none of the quad iterators are invalidated when some
+ // are removed from the QuadList as they're committed.
+ //
+ // TODO(khaslett): Remove this hacky workaround. Instead of erasing quads we
+ // could probably replace them with solid colour quads or make them invisible
+ // instead.
+ std::sort(test_candidates.begin(), test_candidates.end(),
+ [](const OverlayProposedCandidate& c1,
+ const OverlayProposedCandidate& c2) -> bool {
+ return c1.quad_iter.index() > c2.quad_iter.index();
+ });
+ // Commit successful candidates.
+ for (auto& test_candidate : test_candidates) {
+ test_candidate.strategy->CommitCandidate(test_candidate, render_pass);
+ }
+
+ return true;
+}
+
+void OverlayProcessorUsingStrategy::AssignUnderlayZOrders(
+ std::vector<std::vector<OverlayProposedCandidate>::iterator>&
+ underlay_iters) {
+ // Sort the underlay iterators by DrawQuad order, frontmost first.
+ std::sort(
+ underlay_iters.begin(), underlay_iters.end(),
+ [](const std::vector<OverlayProposedCandidate>::iterator& c1,
+ const std::vector<OverlayProposedCandidate>::iterator& c2) -> bool {
+ return c1->quad_iter.index() < c2->quad_iter.index();
+ });
+ // Assign underlay candidate plane_z_orders based on DrawQuad order.
+ int underlay_z_order = -1;
+ for (auto& it : underlay_iters) {
+ it->candidate.plane_z_order = underlay_z_order--;
+ }
+}
+
gfx::Rect OverlayProcessorUsingStrategy::GetOverlayDamageRectForOutputSurface(
const OverlayCandidate& overlay) const {
return ToEnclosedRect(overlay.display_rect);
@@ -603,4 +843,12 @@ void OverlayProcessorUsingStrategy::UpdateDownscalingCapabilities(
min_working_scale_ = 1.0f;
}
+void OverlayProcessorUsingStrategy::LogCheckOverlaySupportMetrics() {
+ UMA_HISTOGRAM_COUNTS_100(
+ "Compositing.Display.OverlayProcessorUsingStrategy."
+ "CheckOverlaySupportCallCount",
+ check_overlay_support_call_count_);
+ check_overlay_support_call_count_ = 0;
+}
+
} // namespace viz
diff --git a/chromium/components/viz/service/display/overlay_processor_using_strategy.h b/chromium/components/viz/service/display/overlay_processor_using_strategy.h
index 51bf6a943f9..29c273414ba 100644
--- a/chromium/components/viz/service/display/overlay_processor_using_strategy.h
+++ b/chromium/components/viz/service/display/overlay_processor_using_strategy.h
@@ -5,6 +5,7 @@
#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_OVERLAY_PROCESSOR_USING_STRATEGY_H_
#define COMPONENTS_VIZ_SERVICE_DISPLAY_OVERLAY_PROCESSOR_USING_STRATEGY_H_
+#include <map>
#include <memory>
#include <unordered_map>
#include <vector>
@@ -19,6 +20,8 @@
#include "components/viz/service/display/overlay_candidate.h"
#include "components/viz/service/display/overlay_candidate_temporal_tracker.h"
#include "components/viz/service/display/overlay_processor_interface.h"
+#include "components/viz/service/display/overlay_processor_strategy.h"
+#include "components/viz/service/display/overlay_proposed_candidate.h"
#include "components/viz/service/viz_service_export.h"
#include "gpu/ipc/common/surface_handle.h"
@@ -33,101 +36,6 @@ class VIZ_SERVICE_EXPORT OverlayProcessorUsingStrategy
: public OverlayProcessorInterface {
public:
using CandidateList = OverlayCandidateList;
- // TODO(weiliangc): Move it to an external class.
- class VIZ_SERVICE_EXPORT Strategy {
- public:
- class VIZ_SERVICE_EXPORT OverlayProposedCandidate {
- public:
- OverlayProposedCandidate(QuadList::Iterator it,
- OverlayCandidate overlay_candidate,
- Strategy* overlay_strategy)
- : quad_iter(it),
- candidate(overlay_candidate),
- strategy(overlay_strategy) {}
-
- // A iterator in the vector of quads.
- QuadList::Iterator quad_iter;
- OverlayCandidate candidate;
- raw_ptr<Strategy> strategy = nullptr;
-
- // heuristic sort element
- int relative_power_gain = 0;
- };
-
- using OverlayProposedCandidateList = std::vector<OverlayProposedCandidate>;
-
- virtual ~Strategy() = default;
- using PrimaryPlane = OverlayProcessorInterface::OutputSurfaceOverlayPlane;
-
- // Returns false if the strategy cannot be made to work with the
- // current set of render passes. Returns true if the strategy was successful
- // and adds any additional passes necessary to represent overlays to
- // |render_pass_list|. Most strategies should look at the primary
- // RenderPass, the last element.
- virtual bool Attempt(
- const skia::Matrix44& output_color_matrix,
- const FilterOperationsMap& render_pass_backdrop_filters,
- DisplayResourceProvider* resource_provider,
- AggregatedRenderPassList* render_pass_list,
- SurfaceDamageRectList* surface_damage_rect_list,
- const PrimaryPlane* primary_plane,
- OverlayCandidateList* candidates,
- std::vector<gfx::Rect>* content_bounds) = 0;
-
- // Appends all legitimate overlay candidates to the list |candidates|
- // for this strategy. It is very important to note that this function
- // should not attempt a specific candidate it should merely identify them
- // and save the necessary data required to for a later attempt.
- virtual void ProposePrioritized(
- const skia::Matrix44& output_color_matrix,
- const FilterOperationsMap& render_pass_backdrop_filters,
- DisplayResourceProvider* resource_provider,
- AggregatedRenderPassList* render_pass_list,
- SurfaceDamageRectList* surface_damage_rect_list,
- const PrimaryPlane* primary_plane,
- OverlayProposedCandidateList* candidates,
- std::vector<gfx::Rect>* content_bounds) = 0;
-
- // Returns false if the specific |proposed_candidate| cannot be made to work
- // for this strategy with the current set of render passes. Returns true if
- // the strategy was successful and adds any additional passes necessary to
- // represent overlays to |render_pass_list|. Most strategies should look at
- // the primary RenderPass, the last element.
- virtual bool AttemptPrioritized(
- const skia::Matrix44& output_color_matrix,
- const FilterOperationsMap& render_pass_backdrop_filters,
- DisplayResourceProvider* resource_provider,
- AggregatedRenderPassList* render_pass_list,
- SurfaceDamageRectList* surface_damage_rect_list,
- const PrimaryPlane* primary_plane,
- OverlayCandidateList* candidates,
- std::vector<gfx::Rect>* content_bounds,
- const OverlayProposedCandidate& proposed_candidate) = 0;
-
- // Commits to using the proposed candidate by updating |render_pass| as
- // appropriate when this candidate is presented in an overlay plane.
- virtual void CommitCandidate(
- const OverlayProposedCandidate& proposed_candidate,
- AggregatedRenderPass* render_pass) = 0;
-
- // Currently this is only overridden by the Underlay strategy: the underlay
- // strategy needs to enable blending for the primary plane in order to show
- // content underneath.
- virtual void AdjustOutputSurfaceOverlay(
- OutputSurfaceOverlayPlane* output_surface_plane) {}
-
- // Currently this is only overridden by the Fullscreen strategy: the
- // fullscreen strategy covers the entire screen and there is no need to use
- // the primary plane.
- virtual bool RemoveOutputSurfaceAsOverlay();
-
- virtual OverlayStrategy GetUMAEnum() const;
-
- // Does a null-check on |primary_plane| and returns it's |display_rect|
- // member if non-null and an empty gfx::RectF otherwise.
- gfx::RectF GetPrimaryPlaneDisplayRect(const PrimaryPlane* primary_plane);
- };
- using StrategyList = std::vector<std::unique_ptr<Strategy>>;
OverlayProcessorUsingStrategy(const OverlayProcessorUsingStrategy&) = delete;
OverlayProcessorUsingStrategy& operator=(
@@ -177,20 +85,23 @@ class VIZ_SERVICE_EXPORT OverlayProcessorUsingStrategy
// to be traditionally composited. Candidates with |overlay_handled| set to
// true must also have their |display_rect| converted to integer
// coordinates if necessary.
- virtual void CheckOverlaySupport(
+ void CheckOverlaySupport(
const OverlayProcessorInterface::OutputSurfaceOverlayPlane* primary_plane,
- OverlayCandidateList* candidate_list) = 0;
+ OverlayCandidateList* candidate_list);
+
+ // This should be called during overlay processing to register whether or not
+ // there is a candidate that requires an overlay so that the manager can allow
+ // the overlay on the display with the requirement only.
+ virtual void RegisterOverlayRequirement(bool requires_overlay) {}
protected:
virtual gfx::Rect GetOverlayDamageRectForOutputSurface(
const OverlayCandidate& overlay) const;
- StrategyList strategies_;
- raw_ptr<Strategy> last_successful_strategy_ = nullptr;
+ std::vector<std::unique_ptr<OverlayProcessorStrategy>> strategies_;
+ raw_ptr<OverlayProcessorStrategy> last_successful_strategy_ = nullptr;
gfx::Rect overlay_damage_rect_;
- bool previous_is_underlay = false;
- bool previous_has_mask_filter_ = false;
gfx::Rect previous_frame_overlay_rect_;
struct OverlayPrioritizationConfig {
@@ -207,12 +118,51 @@ class VIZ_SERVICE_EXPORT OverlayProcessorUsingStrategy
OverlayPrioritizationConfig prioritization_config_;
OverlayCandidateTemporalTracker::Config tracker_config_;
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+ protected:
+ // TODO(b/181974042): Remove when color space is plumbed.
+ gfx::ColorSpace primary_plane_color_space_;
+#endif
+
private:
- // Update |damage_rect| by removing damage caused by |candidates|.
- void UpdateDamageRect(OverlayCandidateList* candidates,
- SurfaceDamageRectList* surface_damage_rect_list,
- const QuadList* quad_list,
- gfx::Rect* damage_rect);
+ // Keeps track of overlay information needed to update damage correctly.
+ struct OverlayStatus;
+ using OverlayStatusMap = std::map<gfx::Rect, OverlayStatus>;
+
+ struct OverlayStatus {
+ OverlayStatus() = delete;
+ OverlayStatus(const OverlayCandidate& candidate,
+ const gfx::Rect& key,
+ const OverlayStatusMap& prev_overlays);
+ OverlayStatus(const OverlayStatus&);
+ OverlayStatus& operator=(const OverlayStatus&);
+ ~OverlayStatus();
+
+ gfx::Rect overlay_rect;
+ gfx::RectF damage_rect;
+ uint32_t damage_index;
+ int damage_area_estimate;
+ bool has_mask_filter;
+ int plane_z_order;
+ bool is_underlay;
+ bool is_opaque;
+ bool is_new;
+ bool prev_was_underlay;
+ bool prev_has_mask_filter;
+ };
+
+ // The platform specific implementation to check overlay support that will be
+ // called by `CheckOverlaySupport()`.
+ virtual void CheckOverlaySupportImpl(
+ const OverlayProcessorInterface::OutputSurfaceOverlayPlane* primary_plane,
+ OverlayCandidateList* candidate_list) = 0;
+
+ // Update |damage_rect| by removing damage caused by overlays.
+ void UpdateDamageRect(const SurfaceDamageRectList& surface_damage_rect_list,
+ gfx::Rect& damage_rect);
+ gfx::Rect ComputeDamageExcludingOverlays(
+ const SurfaceDamageRectList& surface_damage_rect_list,
+ const gfx::Rect& existing_damage);
// Iterate through a list of strategies and attempt to overlay with each.
// Returns true if one of the attempts is successful. Has to be called after
@@ -251,12 +201,39 @@ class VIZ_SERVICE_EXPORT OverlayProcessorUsingStrategy
std::vector<gfx::Rect>* content_bounds,
gfx::Rect* incoming_damage);
+ // Determines if we should attempt multiple overlays. This is based on
+ // `max_overlays_considered_`, the strategies proposed, and if any of the
+ // candidates require an overlay.
+ bool ShouldAttemptMultipleOverlays(
+ const std::vector<OverlayProposedCandidate>& sorted_candidates);
+
+ // Attempts to promote multiple candidates to overlays. Returns a boolean
+ // indicating if any of the attempted candidates were successfully promoted to
+ // overlays.
+ //
+ // TODO(khaslett): Write unit tests for this function before launching
+ // UseMultipleOverlays feature.
+ bool AttemptMultipleOverlays(
+ const std::vector<OverlayProposedCandidate>& sorted_candidates,
+ OverlayProcessorInterface::OutputSurfaceOverlayPlane* primary_plane,
+ AggregatedRenderPass* render_pass,
+ OverlayCandidateList& candidates);
+
+ // Assigns `plane_z_order`s to the proposed underlay candidates based on their
+ // DrawQuad orderings.
+ //
+ // TODO(khaslett): Write unit tests for this function before launching
+ // UseMultipleOverlays feature.
+ void AssignUnderlayZOrders(
+ std::vector<std::vector<OverlayProposedCandidate>::iterator>&
+ underlay_iters);
+
// This function reorders and removes |proposed_candidates| based on a
// heuristic designed to maximize the effectiveness of the limited number
// of Hardware overlays. Effectiveness here is primarily about power and
// secondarily about of performance.
- void SortProposedOverlayCandidatesPrioritized(
- Strategy::OverlayProposedCandidateList* proposed_candidates);
+ virtual void SortProposedOverlayCandidatesPrioritized(
+ std::vector<OverlayProposedCandidate>* proposed_candidates);
// Used by Android pre-SurfaceControl to notify promotion hints.
virtual void NotifyOverlayPromotion(
@@ -269,8 +246,17 @@ class VIZ_SERVICE_EXPORT OverlayProcessorUsingStrategy
// be whether that scaling worked or not.
void UpdateDownscalingCapabilities(float scale_factor, bool success);
+ // Logs the number of times CheckOverlaySupport was called this frame, and
+ // resets the counter to 0.
+ void LogCheckOverlaySupportMetrics();
+
+ // Moves `curr_overlays` into `prev_overlays`, and updates `curr_overlays` to
+ // reflect the overlays that will be promoted this frame in `candidates`.
+ void UpdateOverlayStatusMap(const OverlayCandidateList& candidates);
+
struct ProposedCandidateKey {
- OverlayCandidate::TrackingId tracking_id;
+ OverlayCandidate::TrackingId tracking_id =
+ OverlayCandidate::kDefaultTrackingId;
OverlayStrategy strategy_id = OverlayStrategy::kUnknown;
bool operator==(const ProposedCandidateKey& other) const {
@@ -286,7 +272,9 @@ class VIZ_SERVICE_EXPORT OverlayProcessorUsingStrategy
};
static ProposedCandidateKey ToProposeKey(
- const Strategy::OverlayProposedCandidate& proposed);
+ const OverlayProposedCandidate& proposed);
+
+ const int max_overlays_considered_;
std::unordered_map<ProposedCandidateKey,
OverlayCandidateTemporalTracker,
@@ -298,12 +286,19 @@ class VIZ_SERVICE_EXPORT OverlayProcessorUsingStrategy
base::TimeTicks last_time_interval_switch_overlay_tick_;
ProposedCandidateKey prev_overlay_tracking_id_;
uint64_t frame_sequence_number_ = 0;
+ int check_overlay_support_call_count_ = 0;
// These values are used for tracking how much we can downscale with overlays
// and is used for when we require an overlay so we can determine how much we
// can downscale without failing.
float min_working_scale_ = 1.0f;
float max_failed_scale_ = 0.0f;
+
+ // These keep track of the status of promoted overlays from one frame to the
+ // next. These maps are updated by calling UpdateOverlayStatusMap(), and are
+ // used by UpdateDamageRect() to update damage properly.
+ OverlayStatusMap prev_overlays_;
+ OverlayStatusMap curr_overlays_;
};
} // namespace viz
diff --git a/chromium/components/viz/service/display/overlay_proposed_candidate.h b/chromium/components/viz/service/display/overlay_proposed_candidate.h
new file mode 100644
index 00000000000..5826b2ad5de
--- /dev/null
+++ b/chromium/components/viz/service/display/overlay_proposed_candidate.h
@@ -0,0 +1,40 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_OVERLAY_PROPOSED_CANDIDATE_H_
+#define COMPONENTS_VIZ_SERVICE_DISPLAY_OVERLAY_PROPOSED_CANDIDATE_H_
+
+#include "components/viz/common/quads/quad_list.h"
+#include "components/viz/service/display/overlay_candidate.h"
+#include "components/viz/service/viz_service_export.h"
+
+namespace viz {
+
+class OverlayProcessorStrategy;
+
+// Represents a candidate that could promote a specific `DrawQuad` to an overlay
+// using a specific `OverlayProcessorStrategy`.
+class VIZ_SERVICE_EXPORT OverlayProposedCandidate {
+ public:
+ OverlayProposedCandidate(QuadList::Iterator it,
+ OverlayCandidate overlay_candidate,
+ OverlayProcessorStrategy* overlay_strategy)
+ : quad_iter(it),
+ candidate(overlay_candidate),
+ strategy(overlay_strategy) {}
+
+ // An iterator in the QuadList.
+ QuadList::Iterator quad_iter;
+ // This is needed to sort candidates based on DrawQuad order.
+ size_t quad_index;
+ OverlayCandidate candidate;
+ raw_ptr<OverlayProcessorStrategy> strategy = nullptr;
+
+ // heuristic sort element
+ int relative_power_gain = 0;
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_OVERLAY_PROPOSED_CANDIDATE_H_
diff --git a/chromium/components/viz/service/display/overlay_strategy_fullscreen.cc b/chromium/components/viz/service/display/overlay_strategy_fullscreen.cc
index 4127330df2d..d5d4b874ef8 100644
--- a/chromium/components/viz/service/display/overlay_strategy_fullscreen.cc
+++ b/chromium/components/viz/service/display/overlay_strategy_fullscreen.cc
@@ -67,7 +67,7 @@ bool OverlayStrategyFullscreen::Attempt(
candidate.plane_z_order = 0;
OverlayCandidateList new_candidate_list;
new_candidate_list.push_back(candidate);
- capability_checker_->CheckOverlaySupport(primary_plane, &new_candidate_list);
+ capability_checker_->CheckOverlaySupport(nullptr, &new_candidate_list);
if (!new_candidate_list.front().overlay_handled)
return false;
@@ -87,7 +87,7 @@ void OverlayStrategyFullscreen::ProposePrioritized(
AggregatedRenderPassList* render_pass_list,
SurfaceDamageRectList* surface_damage_rect_list,
const PrimaryPlane* primary_plane,
- OverlayProposedCandidateList* candidates,
+ std::vector<OverlayProposedCandidate>* candidates,
std::vector<gfx::Rect>* content_bounds) {
auto* render_pass = render_pass_list->back().get();
QuadList* quad_list = &render_pass->quad_list;
@@ -141,7 +141,7 @@ bool OverlayStrategyFullscreen::AttemptPrioritized(
OverlayCandidateList new_candidate_list;
new_candidate_list.push_back(proposed_candidate.candidate);
- capability_checker_->CheckOverlaySupport(primary_plane, &new_candidate_list);
+ capability_checker_->CheckOverlaySupport(nullptr, &new_candidate_list);
if (!new_candidate_list.front().overlay_handled)
return false;
diff --git a/chromium/components/viz/service/display/overlay_strategy_fullscreen.h b/chromium/components/viz/service/display/overlay_strategy_fullscreen.h
index 4f89f9450de..12f29c35702 100644
--- a/chromium/components/viz/service/display/overlay_strategy_fullscreen.h
+++ b/chromium/components/viz/service/display/overlay_strategy_fullscreen.h
@@ -8,6 +8,7 @@
#include <vector>
#include "base/memory/raw_ptr.h"
+#include "components/viz/service/display/overlay_processor_strategy.h"
#include "components/viz/service/display/overlay_processor_using_strategy.h"
#include "components/viz/service/viz_service_export.h"
@@ -16,7 +17,7 @@ namespace viz {
// The promoted quad should have all the property of the framebuffer and it
// should be possible to use it as such.
class VIZ_SERVICE_EXPORT OverlayStrategyFullscreen
- : public OverlayProcessorUsingStrategy::Strategy {
+ : public OverlayProcessorStrategy {
public:
explicit OverlayStrategyFullscreen(
OverlayProcessorUsingStrategy* capability_checker);
@@ -44,7 +45,7 @@ class VIZ_SERVICE_EXPORT OverlayStrategyFullscreen
AggregatedRenderPassList* render_pass_list,
SurfaceDamageRectList* surface_damage_rect_list,
const PrimaryPlane* primary_plane,
- OverlayProposedCandidateList* candidates,
+ std::vector<OverlayProposedCandidate>* candidates,
std::vector<gfx::Rect>* content_bounds) override;
bool AttemptPrioritized(
diff --git a/chromium/components/viz/service/display/overlay_strategy_single_on_top.cc b/chromium/components/viz/service/display/overlay_strategy_single_on_top.cc
index ec16948fe53..1bb9e211353 100644
--- a/chromium/components/viz/service/display/overlay_strategy_single_on_top.cc
+++ b/chromium/components/viz/service/display/overlay_strategy_single_on_top.cc
@@ -87,13 +87,11 @@ void OverlayStrategySingleOnTop::ProposePrioritized(
AggregatedRenderPassList* render_pass_list,
SurfaceDamageRectList* surface_damage_rect_list,
const PrimaryPlane* primary_plane,
- OverlayProposedCandidateList* candidates,
+ std::vector<OverlayProposedCandidate>* candidates,
std::vector<gfx::Rect>* content_bounds) {
auto* render_pass = render_pass_list->back().get();
QuadList* quad_list = &render_pass->quad_list;
// Build a list of candidates with the associated quad.
- OverlayCandidate best_candidate;
- auto best_quad_it = quad_list->end();
for (auto it = quad_list->begin(); it != quad_list->end(); ++it) {
OverlayCandidate candidate;
if (OverlayCandidate::FromDrawQuad(
diff --git a/chromium/components/viz/service/display/overlay_strategy_single_on_top.h b/chromium/components/viz/service/display/overlay_strategy_single_on_top.h
index e1c188251d3..3bad535f2d7 100644
--- a/chromium/components/viz/service/display/overlay_strategy_single_on_top.h
+++ b/chromium/components/viz/service/display/overlay_strategy_single_on_top.h
@@ -9,13 +9,14 @@
#include "base/memory/raw_ptr.h"
#include "components/viz/service/display/overlay_candidate.h"
+#include "components/viz/service/display/overlay_processor_strategy.h"
#include "components/viz/service/display/overlay_processor_using_strategy.h"
#include "components/viz/service/viz_service_export.h"
namespace viz {
class VIZ_SERVICE_EXPORT OverlayStrategySingleOnTop
- : public OverlayProcessorUsingStrategy::Strategy {
+ : public OverlayProcessorStrategy {
public:
explicit OverlayStrategySingleOnTop(
OverlayProcessorUsingStrategy* capability_checker);
@@ -43,7 +44,7 @@ class VIZ_SERVICE_EXPORT OverlayStrategySingleOnTop
AggregatedRenderPassList* render_pass_list,
SurfaceDamageRectList* surface_damage_rect_list,
const PrimaryPlane* primary_plane,
- OverlayProposedCandidateList* candidates,
+ std::vector<OverlayProposedCandidate>* candidates,
std::vector<gfx::Rect>* content_bounds) override;
bool AttemptPrioritized(
diff --git a/chromium/components/viz/service/display/overlay_strategy_underlay.cc b/chromium/components/viz/service/display/overlay_strategy_underlay.cc
index 3ad249aafc9..b07705a8d9d 100644
--- a/chromium/components/viz/service/display/overlay_strategy_underlay.cc
+++ b/chromium/components/viz/service/display/overlay_strategy_underlay.cc
@@ -97,7 +97,7 @@ void OverlayStrategyUnderlay::ProposePrioritized(
AggregatedRenderPassList* render_pass_list,
SurfaceDamageRectList* surface_damage_rect_list,
const PrimaryPlane* primary_plane,
- OverlayProposedCandidateList* candidates,
+ std::vector<OverlayProposedCandidate>* candidates,
std::vector<gfx::Rect>* content_bounds) {
auto* render_pass = render_pass_list->back().get();
QuadList& quad_list = render_pass->quad_list;
diff --git a/chromium/components/viz/service/display/overlay_strategy_underlay.h b/chromium/components/viz/service/display/overlay_strategy_underlay.h
index 5d714943428..5283c7f8b38 100644
--- a/chromium/components/viz/service/display/overlay_strategy_underlay.h
+++ b/chromium/components/viz/service/display/overlay_strategy_underlay.h
@@ -8,6 +8,7 @@
#include <vector>
#include "base/memory/raw_ptr.h"
+#include "components/viz/service/display/overlay_processor_strategy.h"
#include "components/viz/service/display/overlay_processor_using_strategy.h"
#include "components/viz/service/viz_service_export.h"
@@ -19,7 +20,7 @@ namespace viz {
// hardware under the the scene. This is only valid for overlay contents that
// are fully opaque.
class VIZ_SERVICE_EXPORT OverlayStrategyUnderlay
- : public OverlayProcessorUsingStrategy::Strategy {
+ : public OverlayProcessorStrategy {
public:
enum class OpaqueMode {
// Require candidates to be |is_opaque|.
@@ -57,7 +58,7 @@ class VIZ_SERVICE_EXPORT OverlayStrategyUnderlay
AggregatedRenderPassList* render_pass_list,
SurfaceDamageRectList* surface_damage_rect_list,
const PrimaryPlane* primary_plane,
- OverlayProposedCandidateList* candidates,
+ std::vector<OverlayProposedCandidate>* candidates,
std::vector<gfx::Rect>* content_bounds) override;
bool AttemptPrioritized(
diff --git a/chromium/components/viz/service/display/overlay_strategy_underlay_cast.cc b/chromium/components/viz/service/display/overlay_strategy_underlay_cast.cc
index aef7dde6631..a3afcff1247 100644
--- a/chromium/components/viz/service/display/overlay_strategy_underlay_cast.cc
+++ b/chromium/components/viz/service/display/overlay_strategy_underlay_cast.cc
@@ -139,7 +139,7 @@ void OverlayStrategyUnderlayCast::ProposePrioritized(
AggregatedRenderPassList* render_pass_list,
SurfaceDamageRectList* surface_damage_rect_list,
const PrimaryPlane* primary_plane,
- OverlayProposedCandidateList* candidates,
+ std::vector<OverlayProposedCandidate>* candidates,
std::vector<gfx::Rect>* content_bounds) {
auto* render_pass = render_pass_list->back().get();
QuadList& quad_list = render_pass->quad_list;
diff --git a/chromium/components/viz/service/display/overlay_strategy_underlay_cast.h b/chromium/components/viz/service/display/overlay_strategy_underlay_cast.h
index 96310b076d9..9a6f20f4761 100644
--- a/chromium/components/viz/service/display/overlay_strategy_underlay_cast.h
+++ b/chromium/components/viz/service/display/overlay_strategy_underlay_cast.h
@@ -48,7 +48,7 @@ class VIZ_SERVICE_EXPORT OverlayStrategyUnderlayCast
AggregatedRenderPassList* render_pass_list,
SurfaceDamageRectList* surface_damage_rect_list,
const PrimaryPlane* primary_plane,
- OverlayProposedCandidateList* candidates,
+ std::vector<OverlayProposedCandidate>* candidates,
std::vector<gfx::Rect>* content_bounds) override;
bool AttemptPrioritized(
diff --git a/chromium/components/viz/service/display/overlay_unittest.cc b/chromium/components/viz/service/display/overlay_unittest.cc
index 6183d54aaac..478e5dbecce 100644
--- a/chromium/components/viz/service/display/overlay_unittest.cc
+++ b/chromium/components/viz/service/display/overlay_unittest.cc
@@ -12,10 +12,13 @@
#include "base/callback_helpers.h"
#include "base/containers/flat_map.h"
#include "base/cxx17_backports.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/test/scoped_feature_list.h"
#include "base/time/time.h"
#include "base/time/time_override.h"
#include "base/unguessable_token.h"
#include "build/build_config.h"
+#include "cc/base/math_util.h"
#include "cc/test/fake_output_surface_client.h"
#include "cc/test/resource_provider_test_utils.h"
#include "components/viz/client/client_resource_provider.h"
@@ -34,8 +37,10 @@
#include "components/viz/service/display/output_surface.h"
#include "components/viz/service/display/output_surface_client.h"
#include "components/viz/service/display/output_surface_frame.h"
+#include "components/viz/service/display/overlay_candidate.h"
#include "components/viz/service/display/overlay_candidate_temporal_tracker.h"
#include "components/viz/service/display/overlay_processor_using_strategy.h"
+#include "components/viz/service/display/overlay_proposed_candidate.h"
#include "components/viz/service/display/overlay_strategy_fullscreen.h"
#include "components/viz/service/display/overlay_strategy_single_on_top.h"
#include "components/viz/service/display/overlay_strategy_underlay.h"
@@ -53,6 +58,7 @@
#include "ui/latency/latency_info.h"
#if defined(USE_OZONE)
+#include "components/viz/service/display/overlay_processor_delegated.h"
#include "ui/base/ui_base_features.h"
#endif
@@ -103,8 +109,8 @@ class TestOverlayProcessor : public OverlayProcessorUsingStrategy {
bool IsOverlaySupported() const override { return true; }
bool NeedsSurfaceDamageRectList() const override { return false; }
- void CheckOverlaySupport(const PrimaryPlane* primary_plane,
- OverlayCandidateList* surfaces) override {}
+ void CheckOverlaySupportImpl(const PrimaryPlane* primary_plane,
+ OverlayCandidateList* surfaces) override {}
size_t GetStrategyCount() const { return strategies_.size(); }
};
@@ -114,8 +120,8 @@ class FullscreenOverlayProcessor : public TestOverlayProcessor {
strategies_.push_back(std::make_unique<OverlayStrategyFullscreen>(this));
}
bool NeedsSurfaceDamageRectList() const override { return true; }
- void CheckOverlaySupport(const PrimaryPlane* primary_plane,
- OverlayCandidateList* surfaces) override {
+ void CheckOverlaySupportImpl(const PrimaryPlane* primary_plane,
+ OverlayCandidateList* surfaces) override {
surfaces->back().overlay_handled = true;
}
};
@@ -140,8 +146,8 @@ class DefaultOverlayProcessor : public TestOverlayProcessor {
DefaultOverlayProcessor() : expected_rects_(1, gfx::RectF(kOverlayRect)) {}
bool NeedsSurfaceDamageRectList() const override { return true; }
- void CheckOverlaySupport(const PrimaryPlane* primary_plane,
- OverlayCandidateList* surfaces) override {
+ void CheckOverlaySupportImpl(const PrimaryPlane* primary_plane,
+ OverlayCandidateList* surfaces) override {
// We have one overlay surface to test. The output surface as primary plane
// is optional, depending on whether this ran
// through the full renderer and picked up the output surface, or not.
@@ -202,6 +208,76 @@ class SingleOverlayProcessor : public DefaultOverlayProcessor {
}
};
+class MultiOverlayProcessorBase : public TestOverlayProcessor {
+ public:
+ MultiOverlayProcessorBase() {
+ prioritization_config_.changing_threshold = false;
+ prioritization_config_.damage_rate_threshold = false;
+ prioritization_config_.power_gain_sort = false;
+ }
+
+ void CheckOverlaySupportImpl(const PrimaryPlane* primary_plane,
+ OverlayCandidateList* surfaces) override {
+ EXPECT_EQ(expected_rects_.size(), surfaces->size());
+
+ for (size_t i = 0; i < surfaces->size(); ++i) {
+ OverlayCandidate& candidate = (*surfaces)[i];
+ EXPECT_EQ(gfx::ToEnclosedRect(candidate.display_rect),
+ expected_rects_[i]);
+ candidate.overlay_handled = responses_[i];
+ }
+ }
+
+ void AddExpectedRect(const gfx::Rect& rect, bool response) {
+ expected_rects_.push_back(rect);
+ responses_.push_back(response);
+ }
+
+ void ClearExpectedRects() {
+ expected_rects_.clear();
+ responses_.clear();
+ }
+
+ private:
+ std::vector<gfx::Rect> expected_rects_;
+ std::vector<bool> responses_;
+};
+
+class MultiOverlayProcessor : public MultiOverlayProcessorBase {
+ public:
+ MultiOverlayProcessor() {
+ strategies_.push_back(std::make_unique<OverlayStrategyFullscreen>(this));
+ strategies_.push_back(std::make_unique<OverlayStrategySingleOnTop>(this));
+ strategies_.push_back(std::make_unique<OverlayStrategyUnderlay>(this));
+ }
+};
+
+class MultiUnderlayProcessor : public MultiOverlayProcessorBase {
+ public:
+ MultiUnderlayProcessor() {
+ strategies_.push_back(std::make_unique<OverlayStrategyUnderlay>(this));
+ }
+};
+
+class SizeSortedMultiOverlayProcessor : public MultiOverlayProcessorBase {
+ public:
+ SizeSortedMultiOverlayProcessor() {
+ strategies_.push_back(std::make_unique<OverlayStrategyFullscreen>(this));
+ strategies_.push_back(std::make_unique<OverlayStrategySingleOnTop>(this));
+ strategies_.push_back(std::make_unique<OverlayStrategyUnderlay>(this));
+ }
+
+ // Sort candidates only by their display_rect area.
+ void SortProposedOverlayCandidatesPrioritized(
+ std::vector<OverlayProposedCandidate>* proposed_candidates) override {
+ std::sort(proposed_candidates->begin(), proposed_candidates->end(),
+ [](const auto& a, const auto& b) {
+ return a.candidate.display_rect.size().GetArea() >
+ b.candidate.display_rect.size().GetArea();
+ });
+ }
+};
+
class SingleOnTopOverlayProcessor : public DefaultOverlayProcessor {
public:
SingleOnTopOverlayProcessor() : DefaultOverlayProcessor() {
@@ -662,6 +738,22 @@ class OverlayTest : public testing::Test {
std::vector<gfx::Rect> content_bounds_;
};
+template <typename OverlayProcessorType>
+class UseMultipleOverlaysTest : public OverlayTest<OverlayProcessorType> {
+ public:
+ UseMultipleOverlaysTest() {
+ // To use more than one overlay, we need to enable some features.
+ const std::vector<base::test::ScopedFeatureList::FeatureAndParams>
+ featureAndParamsList = {{features::kEnableOverlayPrioritization, {}},
+ {features::kUseMultipleOverlays,
+ {{features::kMaxOverlaysParam, "4"}}}};
+ features.InitWithFeaturesAndParameters(featureAndParamsList, {});
+ }
+
+ private:
+ base::test::ScopedFeatureList features;
+};
+
using FullscreenOverlayTest = OverlayTest<FullscreenOverlayProcessor>;
using SingleOverlayOnTopTest = OverlayTest<SingleOnTopOverlayProcessor>;
using ChangeSingleOnTopTest = OverlayTest<ChangeThresholdOnTopOverlayProcessor>;
@@ -672,6 +764,10 @@ using UnderlayTest = OverlayTest<UnderlayOverlayProcessor>;
using TransparentUnderlayTest =
OverlayTest<TransparentUnderlayOverlayProcessor>;
using UnderlayCastTest = OverlayTest<UnderlayCastOverlayProcessor>;
+using MultiOverlayTest = UseMultipleOverlaysTest<MultiOverlayProcessor>;
+using MultiUnderlayTest = UseMultipleOverlaysTest<MultiUnderlayProcessor>;
+using SizeSortedMultiOverlayTest =
+ UseMultipleOverlaysTest<SizeSortedMultiOverlayProcessor>;
TEST(OverlayTest, OverlaysProcessorHasStrategy) {
scoped_refptr<TestContextProvider> provider = TestContextProvider::Create();
@@ -687,7 +783,7 @@ TEST(OverlayTest, OverlaysProcessorHasStrategy) {
EXPECT_GE(2U, overlay_processor->GetStrategyCount());
}
-#if !defined(OS_APPLE) && !defined(OS_WIN)
+#if !BUILDFLAG(IS_APPLE) && !BUILDFLAG(IS_WIN)
TEST_F(FullscreenOverlayTest, SuccessfulOverlay) {
auto pass = CreateRenderPass();
gfx::Rect output_rect = pass->output_rect;
@@ -2695,7 +2791,7 @@ TEST_F(TransitionOverlayTypeTest, DamageChangeOnTransistionOverlayType) {
std::move(surface_damage_rect_list), nullptr, &candidate_list,
&damage_rect_, &content_bounds_);
- EXPECT_EQ(candidate_list.size(), 1U);
+ ASSERT_EQ(candidate_list.size(), 1U);
if (i < kOverlayFrameStart) {
// A pure overlay does not produce damage on promotion and all associated
@@ -3821,7 +3917,7 @@ TEST_F(UnderlayCastTest, PrimaryPlaneOverlayIsAlwaysTransparent) {
}
#endif
-#if defined(USE_OZONE) || defined(OS_ANDROID)
+#if defined(USE_OZONE) || BUILDFLAG(IS_ANDROID)
class OverlayInfoRendererGL : public GLRenderer {
public:
OverlayInfoRendererGL(const RendererSettings* settings,
@@ -4598,7 +4694,7 @@ TEST_F(GLRendererWithOverlaysTest, OutputSurfaceReshapeScheme) {
}
#endif
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
class CALayerOverlayRPDQTest : public CALayerOverlayTest {
protected:
void SetUp() override {
@@ -5129,5 +5225,993 @@ TEST_F(UnderlayTest, ProtectedVideoOverlayScaling) {
}
}
+#if defined(USE_OZONE)
+
+TileDrawQuad* CreateTileCandidateQuadAt(
+ DisplayResourceProvider* parent_resource_provider,
+ ClientResourceProvider* child_resource_provider,
+ ContextProvider* child_context_provider,
+ const SharedQuadState* shared_quad_state,
+ AggregatedRenderPass* render_pass,
+ const gfx::Rect& rect,
+ ResourceFormat resource_format = RGBA_8888,
+ SurfaceId test_surface_id = SurfaceId()) {
+ bool needs_blending = false;
+ bool premultiplied_alpha = false;
+ bool force_anti_aliasing_off = false;
+ bool nearest_neighbor = false;
+ bool is_overlay_candidate = true;
+ ResourceId resource_id = CreateResource(
+ parent_resource_provider, child_resource_provider, child_context_provider,
+ rect.size(), is_overlay_candidate, resource_format, test_surface_id);
+
+ auto* overlay_quad = render_pass->CreateAndAppendDrawQuad<TileDrawQuad>();
+ overlay_quad->SetNew(shared_quad_state, rect, rect, needs_blending,
+ resource_id, gfx::RectF(0, 0, 1, 1), rect.size(),
+ premultiplied_alpha, nearest_neighbor,
+ force_anti_aliasing_off);
+
+ return overlay_quad;
+}
+
+class TestDelegatedOverlayProcessor : public OverlayProcessorDelegated {
+ public:
+ using PrimaryPlane = OverlayProcessorInterface::OutputSurfaceOverlayPlane;
+ TestDelegatedOverlayProcessor()
+ : OverlayProcessorDelegated(nullptr, {}, nullptr) {}
+ ~TestDelegatedOverlayProcessor() override = default;
+
+ bool IsOverlaySupported() const override { return true; }
+ bool NeedsSurfaceDamageRectList() const override { return false; }
+ void CheckOverlaySupportImpl(const PrimaryPlane* primary_plane,
+ OverlayCandidateList* surfaces) override {
+ for (auto&& each_candidate : *surfaces) {
+ each_candidate.overlay_handled = true;
+ }
+ }
+ size_t GetStrategyCount() const { return strategies_.size(); }
+ void AddExpectedRect(const gfx::RectF& rect) {}
+};
+
+using DelegatedTest = OverlayTest<TestDelegatedOverlayProcessor>;
+
+TEST_F(DelegatedTest, ForwardMultipleBasic) {
+ auto pass = CreateRenderPass();
+ constexpr size_t kNumTestQuads = 5;
+ for (size_t i = 0; i < kNumTestQuads; i++) {
+ const auto kSmallCandidateRect = gfx::Rect(0, 0, 16 * (i + 1), 16);
+ CreateCandidateQuadAt(resource_provider_.get(),
+ child_resource_provider_.get(), child_provider_.get(),
+ pass->shared_quad_state_list.back(), pass.get(),
+ kSmallCandidateRect);
+ }
+
+ // Check for potential candidates.
+ OverlayCandidateList candidate_list;
+ OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
+ OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
+ AggregatedRenderPassList pass_list;
+ // AggregatedRenderPass* main_pass = pass.get();
+ SurfaceDamageRectList surface_damage_rect_list;
+ // Simplify by adding full root damage.
+ surface_damage_rect_list.push_back(pass->output_rect);
+ pass_list.push_back(std::move(pass));
+ overlay_processor_->ProcessForOverlays(
+ resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+ render_pass_filters, render_pass_backdrop_filters,
+ std::move(surface_damage_rect_list), nullptr, &candidate_list,
+ &damage_rect_, &content_bounds_);
+ EXPECT_EQ(kNumTestQuads, candidate_list.size());
+ for (size_t i = 0; i < kNumTestQuads; i++) {
+ const auto kSmallCandidateRect = gfx::RectF(0, 0, 16 * (i + 1), 16);
+ EXPECT_RECTF_EQ(kSmallCandidateRect, candidate_list[i].display_rect);
+ }
+}
+
+TEST_F(DelegatedTest, TestClipHandCrafted) {
+ auto pass = CreateRenderPass();
+ const auto kSmallCandidateRect = gfx::Rect(0, 0, 100, 100);
+ const auto kTestClip = gfx::Rect(0, 50, 50, 50);
+ auto* tex_rect = CreateCandidateQuadAt(
+ resource_provider_.get(), child_resource_provider_.get(),
+ child_provider_.get(), pass->shared_quad_state_list.back(), pass.get(),
+ kSmallCandidateRect);
+ tex_rect->uv_bottom_right = gfx::PointF(1, 1);
+ tex_rect->uv_top_left = gfx::PointF(0, 0);
+ pass->shared_quad_state_list.back()->clip_rect = kTestClip;
+ // Check for potential candidates.
+ OverlayCandidateList candidate_list;
+ OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
+ OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
+ AggregatedRenderPassList pass_list;
+ // AggregatedRenderPass* main_pass = pass.get();
+ SurfaceDamageRectList surface_damage_rect_list;
+ // Simplify by adding full root damage.
+ surface_damage_rect_list.push_back(pass->output_rect);
+ pass_list.push_back(std::move(pass));
+ overlay_processor_->ProcessForOverlays(
+ resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+ render_pass_filters, render_pass_backdrop_filters,
+ std::move(surface_damage_rect_list), nullptr, &candidate_list,
+ &damage_rect_, &content_bounds_);
+
+ const auto uv_rect = gfx::RectF(0, 0.5f, 0.5f, 0.5f);
+ EXPECT_EQ(1U, candidate_list.size());
+ EXPECT_RECTF_NEAR(gfx::RectF(kTestClip), candidate_list[0].display_rect,
+ 0.01f);
+ EXPECT_RECTF_NEAR(uv_rect, candidate_list[0].uv_rect, 0.01f);
+}
+
+TEST_F(DelegatedTest, TestClipComputed) {
+ auto pass = CreateRenderPass();
+ const auto kSmallCandidateRect = gfx::Rect(5, 10, 128, 64);
+ const auto kTestClip = gfx::Rect(0, 15, 70, 64);
+ auto* tex_rect = CreateCandidateQuadAt(
+ resource_provider_.get(), child_resource_provider_.get(),
+ child_provider_.get(), pass->shared_quad_state_list.back(), pass.get(),
+ kSmallCandidateRect);
+
+ pass->shared_quad_state_list.back()->clip_rect = kTestClip;
+ // Check for potential candidates.
+ OverlayCandidateList candidate_list;
+ OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
+ OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
+ AggregatedRenderPassList pass_list;
+ // AggregatedRenderPass* main_pass = pass.get();
+ SurfaceDamageRectList surface_damage_rect_list;
+ // Simplify by adding full root damage.
+ surface_damage_rect_list.push_back(pass->output_rect);
+ pass_list.push_back(std::move(pass));
+ overlay_processor_->ProcessForOverlays(
+ resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+ render_pass_filters, render_pass_backdrop_filters,
+ std::move(surface_damage_rect_list), nullptr, &candidate_list,
+ &damage_rect_, &content_bounds_);
+
+ EXPECT_EQ(1U, candidate_list.size());
+ auto expected_rect = kTestClip;
+ expected_rect.Intersect(kSmallCandidateRect);
+ gfx::RectF uv_rect = cc::MathUtil::ScaleRectProportional(
+ BoundingRect(tex_rect->uv_top_left, tex_rect->uv_bottom_right),
+ gfx::RectF(kSmallCandidateRect), gfx::RectF(expected_rect));
+ EXPECT_RECTF_NEAR(gfx::RectF(expected_rect), candidate_list[0].display_rect,
+ 0.01f);
+ EXPECT_RECTF_NEAR(uv_rect, candidate_list[0].uv_rect, 0.01f);
+}
+
+TEST_F(DelegatedTest, QuadTypes) {
+ auto pass = CreateRenderPass();
+ const auto kSmallCandidateRect = gfx::Rect(5, 10, 57, 64);
+ CreateCandidateQuadAt(resource_provider_.get(),
+ child_resource_provider_.get(), child_provider_.get(),
+ pass->shared_quad_state_list.back(), pass.get(),
+ kSmallCandidateRect);
+ CreateTileCandidateQuadAt(
+ resource_provider_.get(), child_resource_provider_.get(),
+ child_provider_.get(), pass->shared_quad_state_list.back(), pass.get(),
+ kSmallCandidateRect);
+ CreateSolidColorQuadAt(pass->shared_quad_state_list.back(), SK_ColorDKGRAY,
+ pass.get(), kOverlayBottomRightRect);
+ // Check for potential candidates.
+ OverlayCandidateList candidate_list;
+ OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
+ OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
+ AggregatedRenderPassList pass_list;
+ AggregatedRenderPass* main_pass = pass.get();
+ SurfaceDamageRectList surface_damage_rect_list;
+ // Simplify by adding full root damage.
+ surface_damage_rect_list.push_back(pass->output_rect);
+ pass_list.push_back(std::move(pass));
+ damage_rect_ = kOverlayRect;
+ overlay_processor_->ProcessForOverlays(
+ resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+ render_pass_filters, render_pass_backdrop_filters,
+ std::move(surface_damage_rect_list), nullptr, &candidate_list,
+ &damage_rect_, &content_bounds_);
+
+ EXPECT_EQ(main_pass->quad_list.size(), candidate_list.size());
+ EXPECT_TRUE(damage_rect_.IsEmpty());
+}
+
+// These tests check to make sure that candidate quads that should fail (aka
+// non-delegatable) do fail. These tests might need to be changed if we have
+// improved delegation support.
+class DelegatedTestNonDelegated : public DelegatedTest {
+ public:
+ void TestExpectCandidateFailure(std::unique_ptr<AggregatedRenderPass> pass) {
+ // Check for potential candidates.
+ OverlayCandidateList candidate_list;
+ OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
+ OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
+ AggregatedRenderPassList pass_list;
+ SurfaceDamageRectList surface_damage_rect_list;
+ // Simplify by adding full root damage.
+ surface_damage_rect_list.push_back(pass->output_rect);
+ pass_list.push_back(std::move(pass));
+ damage_rect_ = kOverlayRect;
+ overlay_processor_->ProcessForOverlays(
+ resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+ render_pass_filters, render_pass_backdrop_filters,
+ std::move(surface_damage_rect_list), nullptr, &candidate_list,
+ &damage_rect_, &content_bounds_);
+
+ EXPECT_EQ(0U, candidate_list.size());
+ EXPECT_EQ(damage_rect_, kOverlayRect);
+ }
+};
+
+TEST_F(DelegatedTestNonDelegated, TextureQuadNearest) {
+ auto pass = CreateRenderPass();
+ const auto kSmallCandidateRect = gfx::Rect(5, 10, 57, 64);
+ auto* texture_quad = CreateCandidateQuadAt(
+ resource_provider_.get(), child_resource_provider_.get(),
+ child_provider_.get(), pass->shared_quad_state_list.back(), pass.get(),
+ kSmallCandidateRect);
+ texture_quad->nearest_neighbor = true;
+ TestExpectCandidateFailure(std::move(pass));
+}
+
+TEST_F(DelegatedTestNonDelegated, TileQuadNearest) {
+ auto pass = CreateRenderPass();
+ const auto kSmallCandidateRect = gfx::Rect(5, 10, 57, 64);
+ auto* tile_quad = CreateTileCandidateQuadAt(
+ resource_provider_.get(), child_resource_provider_.get(),
+ child_provider_.get(), pass->shared_quad_state_list.back(), pass.get(),
+ kSmallCandidateRect);
+ tile_quad->nearest_neighbor = true;
+ TestExpectCandidateFailure(std::move(pass));
+}
+
+#endif // USE_OZONE
+
+TEST_F(MultiUnderlayTest, DamageWhenDemotingTwoUnderlays) {
+ constexpr gfx::Rect kTopLeft(0, 0, 128, 128);
+ constexpr gfx::Rect kTopRight(128, 0, 128, 128);
+ constexpr gfx::Rect kTopHalf(0, 0, 256, 128);
+
+ constexpr int kDemotionFrame = 3;
+ for (int i = 0; i < 5; ++i) {
+ SCOPED_TRACE(i);
+
+ auto pass = CreateRenderPass();
+ damage_rect_ = kTopHalf;
+ SurfaceDamageRectList surface_damage_rect_list;
+ overlay_processor_->ClearExpectedRects();
+
+ // Stop promoting the candidates on this frame.
+ bool promoted = i < kDemotionFrame;
+
+ {
+ // Create a candidate in the top left.
+ auto* sqs = pass->CreateAndAppendSharedQuadState();
+ sqs->overlay_damage_index = surface_damage_rect_list.size();
+ surface_damage_rect_list.emplace_back(kTopLeft);
+ CreateCandidateQuadAt(resource_provider_.get(),
+ child_resource_provider_.get(),
+ child_provider_.get(), sqs, pass.get(), kTopLeft);
+ // This candidate will always be promoted.
+ overlay_processor_->AddExpectedRect(kTopLeft, promoted);
+ }
+ {
+ // Create a candidate in the top right.
+ auto* sqs = pass->CreateAndAppendSharedQuadState();
+ sqs->overlay_damage_index = surface_damage_rect_list.size();
+ surface_damage_rect_list.emplace_back(kTopRight);
+ CreateCandidateQuadAt(resource_provider_.get(),
+ child_resource_provider_.get(),
+ child_provider_.get(), sqs, pass.get(), kTopRight);
+ // The second candidate won't get promoted after kDemotionFrame.
+ overlay_processor_->AddExpectedRect(kTopRight, promoted);
+ }
+ {
+ // Add something behind it.
+ auto* sqs = pass->CreateAndAppendSharedQuadState();
+ CreateFullscreenOpaqueQuad(resource_provider_.get(), sqs, pass.get());
+ }
+
+ OverlayCandidateList candidate_list;
+ OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
+ OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
+ AggregatedRenderPassList pass_list;
+ pass_list.push_back(std::move(pass));
+
+ overlay_processor_->ProcessForOverlays(
+ resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+ render_pass_filters, render_pass_backdrop_filters,
+ std::move(surface_damage_rect_list), nullptr, &candidate_list,
+ &damage_rect_, &content_bounds_);
+
+ if (i == 0) {
+ // The promoted underlays need to damage the primary plane on the first
+ // frame of promotion.
+ EXPECT_EQ(damage_rect_, kTopHalf);
+ } else if (i < kDemotionFrame) {
+ // No damage after they're promoted.
+ EXPECT_TRUE(damage_rect_.IsEmpty());
+ } else if (i >= kDemotionFrame) {
+ // The demoted underlays need to damage the primary plane.
+ EXPECT_EQ(damage_rect_, kTopHalf);
+ }
+ }
+}
+
+TEST_F(MultiUnderlayTest, DamageWhenDemotingOneUnderlay) {
+ constexpr gfx::Rect kTopLeft(0, 0, 128, 128);
+ constexpr gfx::Rect kTopRight(128, 0, 128, 128);
+ constexpr gfx::Rect kTopHalf(0, 0, 256, 128);
+
+ constexpr int kDemotionFrame = 3;
+ for (int i = 0; i < 5; ++i) {
+ SCOPED_TRACE(i);
+
+ auto pass = CreateRenderPass();
+ damage_rect_ = kTopHalf;
+ SurfaceDamageRectList surface_damage_rect_list;
+ overlay_processor_->ClearExpectedRects();
+
+ {
+ // Create a candidate in the top left.
+ auto* sqs = pass->CreateAndAppendSharedQuadState();
+ sqs->overlay_damage_index = surface_damage_rect_list.size();
+ surface_damage_rect_list.emplace_back(kTopLeft);
+ CreateCandidateQuadAt(resource_provider_.get(),
+ child_resource_provider_.get(),
+ child_provider_.get(), sqs, pass.get(), kTopLeft);
+ // This candidate will always be promoted.
+ overlay_processor_->AddExpectedRect(kTopLeft, true);
+ }
+ {
+ // Create a candidate in the top right.
+ auto* sqs = pass->CreateAndAppendSharedQuadState();
+ sqs->overlay_damage_index = surface_damage_rect_list.size();
+ surface_damage_rect_list.emplace_back(kTopRight);
+ CreateCandidateQuadAt(resource_provider_.get(),
+ child_resource_provider_.get(),
+ child_provider_.get(), sqs, pass.get(), kTopRight);
+ // Stop promoting this candidate on kDemotionFrame.
+ bool promoted = i < kDemotionFrame;
+ overlay_processor_->AddExpectedRect(kTopRight, promoted);
+ }
+ {
+ // Add something behind it.
+ auto* sqs = pass->CreateAndAppendSharedQuadState();
+ CreateFullscreenOpaqueQuad(resource_provider_.get(), sqs, pass.get());
+ }
+
+ OverlayCandidateList candidate_list;
+ OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
+ OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
+ AggregatedRenderPassList pass_list;
+ pass_list.push_back(std::move(pass));
+
+ overlay_processor_->ProcessForOverlays(
+ resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+ render_pass_filters, render_pass_backdrop_filters,
+ std::move(surface_damage_rect_list), nullptr, &candidate_list,
+ &damage_rect_, &content_bounds_);
+
+ if (i == 0) {
+ // The promoted underlays need to damage the primary plane on the first
+ // frame of promotion.
+ EXPECT_EQ(damage_rect_, kTopHalf);
+ } else if (i < kDemotionFrame) {
+ // No damage after they're promoted.
+ EXPECT_TRUE(damage_rect_.IsEmpty());
+ } else if (i >= kDemotionFrame) {
+ // Only the demoted underlay needs to damage the primary plane. The top
+ // left candidate is still in an underlay, so it doesn't need damage the
+ // primary plane.
+ EXPECT_EQ(damage_rect_, kTopRight);
+ }
+ }
+}
+
+TEST_F(MultiOverlayTest, DamageOnlyForNewUnderlays) {
+ constexpr gfx::Rect kTopLeft(0, 0, 128, 128);
+ constexpr gfx::Rect kTopRight(128, 0, 128, 128);
+ constexpr gfx::Rect kMidRight(192, 64, 64, 128);
+ constexpr gfx::Rect kTopHalf(0, 0, 256, 128);
+
+ constexpr int kPromotionFrame = 2;
+ for (int i = 0; i < 5; ++i) {
+ SCOPED_TRACE(i);
+
+ auto pass = CreateRenderPass();
+ damage_rect_ = kTopHalf;
+ SurfaceDamageRectList surface_damage_rect_list;
+ overlay_processor_->ClearExpectedRects();
+
+ bool promoted = i >= kPromotionFrame;
+
+ {
+ // Create quad partially covering up top right candidate, forcing it to
+ // be an underlay.
+ CreateOpaqueQuadAt(resource_provider_.get(),
+ pass->shared_quad_state_list.back(), pass.get(),
+ kMidRight);
+ }
+ {
+ // Create a candidate in the top left.
+ auto* sqs = pass->CreateAndAppendSharedQuadState();
+ sqs->overlay_damage_index = surface_damage_rect_list.size();
+ surface_damage_rect_list.emplace_back(kTopLeft);
+ CreateCandidateQuadAt(resource_provider_.get(),
+ child_resource_provider_.get(),
+ child_provider_.get(), sqs, pass.get(), kTopLeft);
+ overlay_processor_->AddExpectedRect(kTopLeft, promoted);
+ }
+ {
+ // Create a candidate in the top right.
+ auto* sqs = pass->CreateAndAppendSharedQuadState();
+ sqs->overlay_damage_index = surface_damage_rect_list.size();
+ surface_damage_rect_list.emplace_back(kTopRight);
+ CreateCandidateQuadAt(resource_provider_.get(),
+ child_resource_provider_.get(),
+ child_provider_.get(), sqs, pass.get(), kTopRight);
+ overlay_processor_->AddExpectedRect(kTopRight, promoted);
+ }
+ {
+ // Add something behind it.
+ auto* sqs = pass->CreateAndAppendSharedQuadState();
+ CreateFullscreenOpaqueQuad(resource_provider_.get(), sqs, pass.get());
+ }
+
+ OverlayCandidateList candidate_list;
+ OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
+ OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
+ AggregatedRenderPassList pass_list;
+ pass_list.push_back(std::move(pass));
+
+ overlay_processor_->ProcessForOverlays(
+ resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+ render_pass_filters, render_pass_backdrop_filters,
+ std::move(surface_damage_rect_list), nullptr, &candidate_list,
+ &damage_rect_, &content_bounds_);
+
+ if (i < kPromotionFrame) {
+ // Full damage before promotion.
+ EXPECT_EQ(damage_rect_, kTopHalf);
+ } else if (i == kPromotionFrame) {
+ // Only the underlay needs damage on the promotion frame.
+ EXPECT_EQ(damage_rect_, kTopRight);
+ } else if (i > kPromotionFrame) {
+ // No damage after both are promoted.
+ EXPECT_TRUE(damage_rect_.IsEmpty());
+ }
+ }
+}
+
+TEST_F(MultiOverlayTest, DamageMaskFilterChange) {
+ constexpr gfx::Rect kTopRight(128, 0, 128, 128);
+ constexpr gfx::Rect kBottomLeft(0, 128, 128, 128);
+ constexpr gfx::Rect kMidRight(192, 64, 64, 128);
+ constexpr gfx::Rect kFullRect(0, 0, 256, 256);
+
+ constexpr int kMaskFilterStartFrame = 2;
+ constexpr int kMaskFilterEndFrame = 4;
+ for (int i = 0; i < 7; ++i) {
+ SCOPED_TRACE(i);
+
+ auto pass = CreateRenderPass();
+ damage_rect_ = kFullRect;
+ SurfaceDamageRectList surface_damage_rect_list;
+ overlay_processor_->ClearExpectedRects();
+
+ bool mask_filter = i >= kMaskFilterStartFrame && i < kMaskFilterEndFrame;
+
+ {
+ // Create quad partially covering up top right candidate, forcing it to
+ // be an underlay.
+ CreateOpaqueQuadAt(resource_provider_.get(),
+ pass->shared_quad_state_list.back(), pass.get(),
+ kMidRight);
+ }
+ {
+ // Create a candidate in the bottom left that won't be promoted.
+ auto* sqs = pass->CreateAndAppendSharedQuadState();
+ if (mask_filter) {
+ sqs->mask_filter_info = gfx::MaskFilterInfo(gfx::RectF(kOverlayRect),
+ gfx::RoundedCornersF(1.f));
+ }
+ sqs->overlay_damage_index = surface_damage_rect_list.size();
+ surface_damage_rect_list.emplace_back(kBottomLeft);
+ CreateCandidateQuadAt(
+ resource_provider_.get(), child_resource_provider_.get(),
+ child_provider_.get(), sqs, pass.get(), kBottomLeft);
+ overlay_processor_->AddExpectedRect(kBottomLeft, false);
+ }
+ {
+ // Create an underlay candidate in the top right.
+ auto* sqs = pass->CreateAndAppendSharedQuadState();
+ if (mask_filter) {
+ sqs->mask_filter_info = gfx::MaskFilterInfo(gfx::RectF(kOverlayRect),
+ gfx::RoundedCornersF(1.f));
+ }
+ sqs->overlay_damage_index = surface_damage_rect_list.size();
+ surface_damage_rect_list.emplace_back(kTopRight);
+ CreateCandidateQuadAt(resource_provider_.get(),
+ child_resource_provider_.get(),
+ child_provider_.get(), sqs, pass.get(), kTopRight);
+ overlay_processor_->AddExpectedRect(kTopRight, true);
+ }
+ {
+ // Add something behind it.
+ auto* sqs = pass->CreateAndAppendSharedQuadState();
+ CreateFullscreenOpaqueQuad(resource_provider_.get(), sqs, pass.get());
+ }
+
+ OverlayCandidateList candidate_list;
+ OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
+ OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
+ AggregatedRenderPassList pass_list;
+ pass_list.push_back(std::move(pass));
+
+ overlay_processor_->ProcessForOverlays(
+ resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+ render_pass_filters, render_pass_backdrop_filters,
+ std::move(surface_damage_rect_list), nullptr, &candidate_list,
+ &damage_rect_, &content_bounds_);
+
+ ASSERT_EQ(candidate_list.size(), 1u);
+
+ if (i == 0) {
+ // Damage for both candidates
+ EXPECT_EQ(damage_rect_, kFullRect);
+ } else if (i < kMaskFilterStartFrame) {
+ EXPECT_EQ(damage_rect_, kBottomLeft);
+ } else if (i == kMaskFilterStartFrame || i == kMaskFilterEndFrame) {
+ // Damage added for underlay candidate when mask filter changes.
+ EXPECT_EQ(damage_rect_, kFullRect);
+ } else {
+ // Otherwise damage for just the unpromoted candidate.
+ EXPECT_EQ(damage_rect_, kBottomLeft);
+ }
+ }
+}
+
+TEST_F(MultiOverlayTest, DamageOccluded) {
+ constexpr gfx::Rect kTopRight(128, 0, 128, 128);
+ constexpr gfx::Rect kUnderTopRight(129, 1, 64, 64);
+ constexpr gfx::Rect kBottomLeft(0, 128, 128, 128);
+ constexpr gfx::Rect kUnderBottomLeft(1, 129, 64, 64);
+ constexpr gfx::Rect kMidRight(192, 64, 64, 128);
+ constexpr gfx::Rect kFullRect(0, 0, 256, 256);
+
+ constexpr int kTopRightGone = 3;
+
+ for (int i = 0; i < 6; ++i) {
+ SCOPED_TRACE(i);
+
+ auto pass = CreateRenderPass();
+ damage_rect_ = kFullRect;
+ SurfaceDamageRectList surface_damage_rect_list;
+ overlay_processor_->ClearExpectedRects();
+
+ {
+ // Create quad partially covering up top right candidate, forcing it to
+ // be an underlay.
+ CreateOpaqueQuadAt(resource_provider_.get(),
+ pass->shared_quad_state_list.back(), pass.get(),
+ kMidRight);
+ }
+ {
+ // Create a transparent candidate in the bottom left.
+ auto* sqs = pass->CreateAndAppendSharedQuadState();
+ sqs->overlay_damage_index = surface_damage_rect_list.size();
+ surface_damage_rect_list.emplace_back(kBottomLeft);
+ CreateTransparentCandidateQuadAt(
+ resource_provider_.get(), child_resource_provider_.get(),
+ child_provider_.get(), sqs, pass.get(), kBottomLeft);
+ overlay_processor_->AddExpectedRect(kBottomLeft, true);
+ }
+ {
+ // Create unpromoted quad that would be underneath bottom left quad
+ auto* sqs = pass->CreateAndAppendSharedQuadState();
+ sqs->overlay_damage_index = surface_damage_rect_list.size();
+ surface_damage_rect_list.emplace_back(kUnderBottomLeft);
+ CreateCandidateQuadAt(
+ resource_provider_.get(), child_resource_provider_.get(),
+ child_provider_.get(), sqs, pass.get(), kUnderBottomLeft);
+ overlay_processor_->AddExpectedRect(kUnderBottomLeft, false);
+ }
+ if (i < kTopRightGone) {
+ // Create an underlay candidate in the top right.
+ auto* sqs = pass->CreateAndAppendSharedQuadState();
+ sqs->overlay_damage_index = surface_damage_rect_list.size();
+ surface_damage_rect_list.emplace_back(kTopRight);
+ CreateCandidateQuadAt(resource_provider_.get(),
+ child_resource_provider_.get(),
+ child_provider_.get(), sqs, pass.get(), kTopRight);
+ overlay_processor_->AddExpectedRect(kTopRight, true);
+ }
+ {
+ // Create an opaque damaging quad under the top right candidate.
+ auto* sqs = pass->CreateAndAppendSharedQuadState();
+ sqs->overlay_damage_index = surface_damage_rect_list.size();
+ surface_damage_rect_list.emplace_back(kUnderTopRight);
+ CreateOpaqueQuadAt(resource_provider_.get(), sqs, pass.get(),
+ kUnderTopRight);
+ }
+ {
+ // Add something behind it.
+ auto* sqs = pass->CreateAndAppendSharedQuadState();
+ CreateFullscreenOpaqueQuad(resource_provider_.get(), sqs, pass.get());
+ }
+
+ OverlayCandidateList candidate_list;
+ OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
+ OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
+ AggregatedRenderPassList pass_list;
+ pass_list.push_back(std::move(pass));
+
+ overlay_processor_->ProcessForOverlays(
+ resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+ render_pass_filters, render_pass_backdrop_filters,
+ std::move(surface_damage_rect_list), nullptr, &candidate_list,
+ &damage_rect_, &content_bounds_);
+
+ if (i < kTopRightGone) {
+ ASSERT_EQ(candidate_list.size(), 2u);
+ // Transparent overlay
+ EXPECT_GT(candidate_list[0].plane_z_order, 0);
+ EXPECT_FALSE(candidate_list[0].is_opaque);
+ // Opaque underlay
+ EXPECT_LT(candidate_list[1].plane_z_order, 0);
+ EXPECT_TRUE(candidate_list[1].is_opaque);
+ } else {
+ ASSERT_EQ(candidate_list.size(), 1u);
+ // Transparent overlay
+ EXPECT_GT(candidate_list[0].plane_z_order, 0);
+ EXPECT_FALSE(candidate_list[0].is_opaque);
+ }
+
+ if (i == 0) {
+ // Damage for both candidates
+ EXPECT_EQ(damage_rect_, kFullRect);
+ } else if (i < kTopRightGone) {
+ // This quad isn't occluded because it's under a transparent overlay, so
+ // its damage persists.
+ EXPECT_EQ(damage_rect_, kUnderBottomLeft);
+ } else if (i == kTopRightGone) {
+ // The top right candidate is demoted, so
+ // damage = kUnderBottomLeft union kTopRight
+ EXPECT_EQ(damage_rect_, gfx::Rect(1, 0, 255, 193));
+ } else if (i >= kTopRightGone) {
+ // The quad under top right is now visible, so
+ // damage = kUnderBottomLeft union kUnderTopRight
+ EXPECT_EQ(damage_rect_, gfx::Rect(1, 1, 192, 192));
+ }
+ }
+}
+
+TEST_F(MultiOverlayTest, FullscreenOnly) {
+ constexpr gfx::Rect kTopLeft(0, 0, 128, 128);
+ constexpr gfx::Rect kTopRight(128, 0, 128, 128);
+ constexpr gfx::Rect kFullRect(0, 0, 256, 256);
+
+ auto pass = CreateRenderPass();
+ damage_rect_ = kFullRect;
+ SurfaceDamageRectList surface_damage_rect_list;
+
+ {
+ // Create a fullscreen candidate.
+ auto* sqs = pass->CreateAndAppendSharedQuadState();
+ sqs->overlay_damage_index = surface_damage_rect_list.size();
+ surface_damage_rect_list.emplace_back(kFullRect);
+ CreateFullscreenCandidateQuad(resource_provider_.get(),
+ child_resource_provider_.get(),
+ child_provider_.get(), sqs, pass.get());
+ overlay_processor_->AddExpectedRect(kFullRect, true);
+ }
+ {
+ // Create a candidate in the top left.
+ auto* sqs = pass->CreateAndAppendSharedQuadState();
+ sqs->overlay_damage_index = surface_damage_rect_list.size();
+ surface_damage_rect_list.emplace_back(kTopLeft);
+ CreateCandidateQuadAt(resource_provider_.get(),
+ child_resource_provider_.get(), child_provider_.get(),
+ sqs, pass.get(), kTopLeft);
+ }
+ {
+ // Create a candidate in the top right.
+ auto* sqs = pass->CreateAndAppendSharedQuadState();
+ sqs->overlay_damage_index = surface_damage_rect_list.size();
+ surface_damage_rect_list.emplace_back(kTopRight);
+ CreateCandidateQuadAt(resource_provider_.get(),
+ child_resource_provider_.get(), child_provider_.get(),
+ sqs, pass.get(), kTopRight);
+ }
+ {
+ // Add something behind it.
+ auto* sqs = pass->CreateAndAppendSharedQuadState();
+ CreateFullscreenOpaqueQuad(resource_provider_.get(), sqs, pass.get());
+ }
+
+ OverlayCandidateList candidate_list;
+ OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
+ OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
+ AggregatedRenderPassList pass_list;
+ pass_list.push_back(std::move(pass));
+
+ overlay_processor_->ProcessForOverlays(
+ resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+ render_pass_filters, render_pass_backdrop_filters,
+ std::move(surface_damage_rect_list), nullptr, &candidate_list,
+ &damage_rect_, &content_bounds_);
+
+ ASSERT_EQ(candidate_list.size(), 1u);
+ // Fullscreen overlay
+ EXPECT_EQ(candidate_list[0].plane_z_order, 0);
+ EXPECT_EQ(gfx::ToRoundedRect(candidate_list[0].display_rect), kFullRect);
+ // No damage required for a fullscreen overlay.
+ EXPECT_TRUE(damage_rect_.IsEmpty());
+}
+
+TEST_F(MultiOverlayTest, RequiredOverlayOnly) {
+ constexpr gfx::Rect kTopLeft(0, 0, 128, 128);
+ constexpr gfx::Rect kTopRight(128, 0, 128, 128);
+ constexpr gfx::Rect kTopHalf(0, 0, 256, 128);
+ constexpr gfx::Rect kBottomLeft(0, 128, 128, 128);
+ constexpr gfx::Rect kFullRect(0, 0, 256, 256);
+
+ auto pass = CreateRenderPass();
+ damage_rect_ = kFullRect;
+ SurfaceDamageRectList surface_damage_rect_list;
+
+ {
+ // Create a candidate in the top left.
+ auto* sqs = pass->CreateAndAppendSharedQuadState();
+ sqs->overlay_damage_index = surface_damage_rect_list.size();
+ surface_damage_rect_list.emplace_back(kTopLeft);
+ CreateCandidateQuadAt(resource_provider_.get(),
+ child_resource_provider_.get(), child_provider_.get(),
+ sqs, pass.get(), kTopLeft);
+ }
+ {
+ // Create a candidate in the top right.
+ auto* sqs = pass->CreateAndAppendSharedQuadState();
+ sqs->overlay_damage_index = surface_damage_rect_list.size();
+ surface_damage_rect_list.emplace_back(kTopRight);
+ CreateCandidateQuadAt(resource_provider_.get(),
+ child_resource_provider_.get(), child_provider_.get(),
+ sqs, pass.get(), kTopRight);
+ }
+ {
+ // Create an overlay required candidate.
+ auto* sqs = pass->CreateAndAppendSharedQuadState();
+ sqs->overlay_damage_index = surface_damage_rect_list.size();
+ surface_damage_rect_list.emplace_back(kBottomLeft);
+ CreateCandidateQuadAt(
+ resource_provider_.get(), child_resource_provider_.get(),
+ child_provider_.get(), sqs, pass.get(), kBottomLeft,
+ gfx::ProtectedVideoType::kHardwareProtected, YUV_420_BIPLANAR);
+ overlay_processor_->AddExpectedRect(kBottomLeft, true);
+ }
+ {
+ // Add something behind it.
+ auto* sqs = pass->CreateAndAppendSharedQuadState();
+ CreateFullscreenOpaqueQuad(resource_provider_.get(), sqs, pass.get());
+ }
+
+ OverlayCandidateList candidate_list;
+ OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
+ OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
+ AggregatedRenderPassList pass_list;
+ pass_list.push_back(std::move(pass));
+
+ overlay_processor_->ProcessForOverlays(
+ resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+ render_pass_filters, render_pass_backdrop_filters,
+ std::move(surface_damage_rect_list), nullptr, &candidate_list,
+ &damage_rect_, &content_bounds_);
+
+ ASSERT_EQ(candidate_list.size(), 1u);
+ // Only the required overlay is promoted.
+ EXPECT_EQ(gfx::ToRoundedRect(candidate_list[0].display_rect), kBottomLeft);
+ EXPECT_TRUE(candidate_list[0].requires_overlay);
+ // The two unpromoted candidates still have damage.
+ EXPECT_EQ(damage_rect_, kTopHalf);
+}
+
+TEST_F(MultiOverlayTest, CappedAtMaxOverlays) {
+ constexpr gfx::Rect kCandRects[]{{0, 0, 64, 64}, {64, 0, 64, 64},
+ {0, 64, 64, 64}, {64, 64, 64, 64},
+ {0, 128, 64, 64}, {64, 128, 64, 64}};
+ constexpr gfx::Rect kBottomTwo(0, 128, 128, 64);
+
+ damage_rect_ = gfx::Rect(0, 0, 128, 192);
+ auto pass = CreateRenderPass();
+ SurfaceDamageRectList surface_damage_rect_list;
+
+ constexpr int kMaxOverlays = 4;
+
+ for (int i = 0; i < 6; ++i) {
+ auto* sqs = pass->CreateAndAppendSharedQuadState();
+ sqs->overlay_damage_index = surface_damage_rect_list.size();
+ surface_damage_rect_list.emplace_back(kCandRects[i]);
+ CreateCandidateQuadAt(resource_provider_.get(),
+ child_resource_provider_.get(), child_provider_.get(),
+ sqs, pass.get(), kCandRects[i]);
+ // Only the first 4 overlays should be attempted.
+ if (i < kMaxOverlays) {
+ overlay_processor_->AddExpectedRect(kCandRects[i], true);
+ }
+ }
+
+ {
+ // Add something behind it.
+ auto* sqs = pass->CreateAndAppendSharedQuadState();
+ CreateFullscreenOpaqueQuad(resource_provider_.get(), sqs, pass.get());
+ }
+
+ OverlayCandidateList candidate_list;
+ OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
+ OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
+ AggregatedRenderPassList pass_list;
+ pass_list.push_back(std::move(pass));
+
+ overlay_processor_->ProcessForOverlays(
+ resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+ render_pass_filters, render_pass_backdrop_filters,
+ std::move(surface_damage_rect_list), nullptr, &candidate_list,
+ &damage_rect_, &content_bounds_);
+
+ ASSERT_EQ(candidate_list.size(), 4u);
+ // Expect the first four candidates promoted to on top overlays.
+ EXPECT_EQ(gfx::ToRoundedRect(candidate_list[0].display_rect), kCandRects[0]);
+ EXPECT_EQ(candidate_list[0].plane_z_order, 1);
+ EXPECT_EQ(gfx::ToRoundedRect(candidate_list[1].display_rect), kCandRects[1]);
+ EXPECT_EQ(candidate_list[1].plane_z_order, 1);
+ EXPECT_EQ(gfx::ToRoundedRect(candidate_list[2].display_rect), kCandRects[2]);
+ EXPECT_EQ(candidate_list[2].plane_z_order, 1);
+ EXPECT_EQ(gfx::ToRoundedRect(candidate_list[3].display_rect), kCandRects[3]);
+ EXPECT_EQ(candidate_list[3].plane_z_order, 1);
+ // Only the bottom two candidates still have damage.
+ EXPECT_EQ(damage_rect_, kBottomTwo);
+}
+
+TEST_F(SizeSortedMultiOverlayTest, UnderlaysAreSorted) {
+ constexpr gfx::Rect kBiggest(0, 0, 128, 128);
+ constexpr gfx::Rect kBig(128, 28, 100, 100);
+ constexpr gfx::Rect kSmall(64, 128, 64, 64);
+ constexpr gfx::Rect kSmallest(128, 128, 32, 32);
+ // The draw order of these candidates is scrambled, so we can verify that the
+ // plane_z_orders are are based on draw quad order.
+ constexpr gfx::Rect kCandRects[]{kSmall, kBiggest, kSmallest, kBig};
+ constexpr gfx::Rect kSmallCenter(112, 112, 32, 32);
+ constexpr gfx::Rect kAllCands(0, 0, 228, 192);
+
+ damage_rect_ = kAllCands;
+ auto pass = CreateRenderPass();
+ SurfaceDamageRectList surface_damage_rect_list;
+
+ {
+ // Create a quad partially covering up all candidates, forcing them to all
+ // be underlays.
+ auto* sqs = pass->CreateAndAppendSharedQuadState();
+ CreateOpaqueQuadAt(resource_provider_.get(), sqs, pass.get(), kSmallCenter);
+ }
+
+ for (auto& cand_rect : kCandRects) {
+ auto* sqs = pass->CreateAndAppendSharedQuadState();
+ sqs->overlay_damage_index = surface_damage_rect_list.size();
+ surface_damage_rect_list.emplace_back(cand_rect);
+ CreateCandidateQuadAt(resource_provider_.get(),
+ child_resource_provider_.get(), child_provider_.get(),
+ sqs, pass.get(), cand_rect);
+ }
+ // Candidates will be sorted by surface area. All will be promoted.
+ overlay_processor_->AddExpectedRect(kBiggest, true);
+ overlay_processor_->AddExpectedRect(kBig, true);
+ overlay_processor_->AddExpectedRect(kSmall, true);
+ overlay_processor_->AddExpectedRect(kSmallest, true);
+
+ {
+ // Add something behind them.
+ auto* sqs = pass->CreateAndAppendSharedQuadState();
+ CreateFullscreenOpaqueQuad(resource_provider_.get(), sqs, pass.get());
+ }
+
+ OverlayCandidateList candidate_list;
+ OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
+ OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
+ AggregatedRenderPassList pass_list;
+ pass_list.push_back(std::move(pass));
+
+ overlay_processor_->ProcessForOverlays(
+ resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+ render_pass_filters, render_pass_backdrop_filters,
+ std::move(surface_damage_rect_list), nullptr, &candidate_list,
+ &damage_rect_, &content_bounds_);
+
+ ASSERT_EQ(candidate_list.size(), 4u);
+ // Expect all four are promoted to underlay, and their plane_z_order is based
+ // on draw order.
+ EXPECT_EQ(gfx::ToRoundedRect(candidate_list[0].display_rect), kBiggest);
+ EXPECT_EQ(candidate_list[0].plane_z_order, -2);
+ EXPECT_EQ(gfx::ToRoundedRect(candidate_list[1].display_rect), kBig);
+ EXPECT_EQ(candidate_list[1].plane_z_order, -4);
+ EXPECT_EQ(gfx::ToRoundedRect(candidate_list[2].display_rect), kSmall);
+ EXPECT_EQ(candidate_list[2].plane_z_order, -1);
+ EXPECT_EQ(gfx::ToRoundedRect(candidate_list[3].display_rect), kSmallest);
+ EXPECT_EQ(candidate_list[3].plane_z_order, -3);
+ // Full damage because these are underlays on their first frame of promotion.
+ EXPECT_EQ(damage_rect_, kAllCands);
+}
+
+class MultiUnderlayPromotedTest : public MultiUnderlayTest,
+ public testing::WithParamInterface<bool> {};
+
+TEST_P(MultiUnderlayPromotedTest, UnderlaysBlendPrimaryPlane) {
+ bool promoted = GetParam();
+
+ constexpr gfx::Rect kTopLeft(0, 0, 128, 128);
+ constexpr gfx::Rect kTopRight(128, 0, 128, 128);
+ constexpr gfx::Rect kTopHalf(0, 0, 256, 128);
+
+ auto pass = CreateRenderPass();
+ damage_rect_ = kTopHalf;
+ SurfaceDamageRectList surface_damage_rect_list;
+
+ {
+ // Create a candidate in the top left.
+ auto* sqs = pass->CreateAndAppendSharedQuadState();
+ sqs->overlay_damage_index = surface_damage_rect_list.size();
+ surface_damage_rect_list.emplace_back(kTopLeft);
+ CreateCandidateQuadAt(resource_provider_.get(),
+ child_resource_provider_.get(), child_provider_.get(),
+ sqs, pass.get(), kTopLeft);
+ overlay_processor_->AddExpectedRect(kTopLeft, promoted);
+ }
+ {
+ // Create a candidate in the top right.
+ auto* sqs = pass->CreateAndAppendSharedQuadState();
+ sqs->overlay_damage_index = surface_damage_rect_list.size();
+ surface_damage_rect_list.emplace_back(kTopRight);
+ CreateCandidateQuadAt(resource_provider_.get(),
+ child_resource_provider_.get(), child_provider_.get(),
+ sqs, pass.get(), kTopRight);
+ overlay_processor_->AddExpectedRect(kTopRight, promoted);
+ }
+ {
+ // Add something behind it.
+ auto* sqs = pass->CreateAndAppendSharedQuadState();
+ CreateFullscreenOpaqueQuad(resource_provider_.get(), sqs, pass.get());
+ }
+
+ OverlayCandidateList candidate_list;
+ OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
+ OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
+ AggregatedRenderPassList pass_list;
+ pass_list.push_back(std::move(pass));
+ auto output_surface_plane = overlay_processor_->ProcessOutputSurfaceAsOverlay(
+ kDisplaySize, kDisplaySize, kDefaultBufferFormat, gfx::ColorSpace(),
+ false /* has_alpha */, 1.0f /* opacity */, gpu::Mailbox());
+ OverlayProcessorInterface::OutputSurfaceOverlayPlane* primary_plane =
+ &output_surface_plane;
+
+ overlay_processor_->ProcessForOverlays(
+ resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+ render_pass_filters, render_pass_backdrop_filters,
+ std::move(surface_damage_rect_list), primary_plane, &candidate_list,
+ &damage_rect_, &content_bounds_);
+
+ if (promoted) {
+ // Both candidates are promoted.
+ ASSERT_EQ(candidate_list.size(), 2u);
+ // Blending enabled on primary plane.
+ EXPECT_TRUE(primary_plane->enable_blending);
+ } else {
+ // No candidates are promoted.
+ EXPECT_TRUE(candidate_list.empty());
+ // Blending not enabled on primary plane.
+ EXPECT_FALSE(primary_plane->enable_blending);
+ }
+}
+
+INSTANTIATE_TEST_SUITE_P(PromotedTrueFalse,
+ MultiUnderlayPromotedTest,
+ testing::Bool());
+
} // namespace
} // namespace viz
diff --git a/chromium/components/viz/service/display/program_binding.h b/chromium/components/viz/service/display/program_binding.h
index e36c6450d50..b03673f9266 100644
--- a/chromium/components/viz/service/display/program_binding.h
+++ b/chromium/components/viz/service/display/program_binding.h
@@ -350,7 +350,7 @@ class VIZ_SERVICE_EXPORT Program : public ProgramBindingBase {
void InitializeSolidColorProgram(const ProgramKey& key) {
// Initialize vertex program.
vertex_shader_.position_source_ = POSITION_SOURCE_ATTRIBUTE_INDEXED_UNIFORM;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
if (key.aa_mode_ == NO_AA)
vertex_shader_.has_dummy_variables_ = true;
#endif
diff --git a/chromium/components/viz/service/display/renderer_perftest.cc b/chromium/components/viz/service/display/renderer_perftest.cc
index 1cb1ec7602d..75de6f0c07d 100644
--- a/chromium/components/viz/service/display/renderer_perftest.cc
+++ b/chromium/components/viz/service/display/renderer_perftest.cc
@@ -257,7 +257,7 @@ class RendererPerfTest : public VizPerfTest {
else
printf("Using GLRenderer\n");
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
renderer_settings_.color_space = gfx::ColorSpace::CreateSRGB();
renderer_settings_.initial_screen_size = kSurfaceSize;
#endif
diff --git a/chromium/components/viz/service/display/renderer_pixeltest.cc b/chromium/components/viz/service/display/renderer_pixeltest.cc
index a45b7fb690b..5dca4a2f630 100644
--- a/chromium/components/viz/service/display/renderer_pixeltest.cc
+++ b/chromium/components/viz/service/display/renderer_pixeltest.cc
@@ -66,7 +66,7 @@ const gfx::DisplayColorSpaces kRec601DisplayColorSpaces(
gfx::ColorSpace(gfx::ColorSpace::PrimaryID::SMPTE170M,
gfx::ColorSpace::TransferID::SMPTE170M));
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
template <typename T>
base::span<const uint8_t> MakePixelSpan(const std::vector<T>& vec) {
return base::make_span(reinterpret_cast<const uint8_t*>(vec.data()),
@@ -5119,6 +5119,12 @@ class ColorTransformPixelTest
}
this->display_color_spaces_ =
gfx::DisplayColorSpaces(this->dst_color_space_);
+ float sdr_max_luminance_nits =
+ this->display_color_spaces_.GetSDRMaxLuminanceNits();
+ if (src_color_space_.GetSDRWhiteLevel(&sdr_max_luminance_nits)) {
+ this->display_color_spaces_.SetSDRMaxLuminanceNits(
+ sdr_max_luminance_nits);
+ }
this->premultiplied_alpha_ = std::get<3>(GetParam());
}
@@ -5131,7 +5137,7 @@ class ColorTransformPixelTest
return;
}
- if (src_color_space_.GetTransferID() == TransferID::SMPTEST2084 &&
+ if (src_color_space_.GetTransferID() == TransferID::PQ &&
!dst_color_space_.IsHDR()) {
LOG(ERROR) << "Skipping tonemapped output";
return;
@@ -5168,9 +5174,12 @@ class ColorTransformPixelTest
}
}
+ gfx::ColorTransform::Options options;
+ options.sdr_max_luminance_nits =
+ display_color_spaces_.GetSDRMaxLuminanceNits();
std::unique_ptr<gfx::ColorTransform> transform =
gfx::ColorTransform::NewColorTransform(this->src_color_space_,
- this->dst_color_space_);
+ this->dst_color_space_, options);
for (size_t i = 0; i < expected_output_colors.size(); ++i) {
gfx::ColorTransform::TriStim color;
@@ -5258,9 +5267,9 @@ gfx::ColorSpace src_color_spaces[] = {
gfx::ColorSpace(PrimaryID::BT709, TransferID::GAMMA28),
gfx::ColorSpace(PrimaryID::BT709, TransferID::SMPTE240M),
gfx::ColorSpace(PrimaryID::BT709, TransferID::LINEAR),
- gfx::ColorSpace(PrimaryID::BT709, TransferID::IEC61966_2_1),
+ gfx::ColorSpace(PrimaryID::BT709, TransferID::SRGB),
gfx::ColorSpace(PrimaryID::BT709, TransferID::SMPTEST428_1),
- gfx::ColorSpace(PrimaryID::BT709, TransferID::IEC61966_2_1_HDR),
+ gfx::ColorSpace(PrimaryID::BT709, TransferID::SRGB_HDR),
gfx::ColorSpace(PrimaryID::BT709, TransferID::LINEAR_HDR),
// Piecewise HDR transfer functions skipped with SkiaRenderer.
gfx::ColorSpace::CreatePiecewiseHDR(PrimaryID::BT709, 0.5, 1.5),
@@ -5276,8 +5285,8 @@ gfx::ColorSpace dst_color_spaces[] = {
gfx::ColorSpace(PrimaryID::BT709, TransferID::GAMMA28),
gfx::ColorSpace(PrimaryID::BT709, TransferID::SMPTE240M),
gfx::ColorSpace(PrimaryID::BT709, TransferID::LINEAR),
- gfx::ColorSpace(PrimaryID::BT709, TransferID::IEC61966_2_1),
- gfx::ColorSpace(PrimaryID::BT709, TransferID::IEC61966_2_1_HDR),
+ gfx::ColorSpace(PrimaryID::BT709, TransferID::SRGB),
+ gfx::ColorSpace(PrimaryID::BT709, TransferID::SRGB_HDR),
gfx::ColorSpace(PrimaryID::BT709, TransferID::LINEAR_HDR),
// Piecewise HDR transfer functions are skipped with SkiaRenderer.
gfx::ColorSpace::CreatePiecewiseHDR(PrimaryID::BT709, 0.25, 2.5),
@@ -5285,7 +5294,7 @@ gfx::ColorSpace dst_color_spaces[] = {
gfx::ColorSpace intermediate_color_spaces[] = {
gfx::ColorSpace(PrimaryID::XYZ_D50, TransferID::LINEAR),
- gfx::ColorSpace(PrimaryID::XYZ_D50, TransferID::IEC61966_2_1_HDR),
+ gfx::ColorSpace(PrimaryID::XYZ_D50, TransferID::SRGB_HDR),
};
INSTANTIATE_TEST_SUITE_P(
@@ -5650,7 +5659,7 @@ TEST_P(DelegatedInkWithPredictionTest, DrawTrailsWithDifferentPointerIds) {
// is no trail after another draw.
EXPECT_TRUE(DrawAndTestTrail(FILE_PATH_LITERAL("white.png")));
}
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
} // namespace
} // namespace viz
diff --git a/chromium/components/viz/service/display/resolved_frame_data.cc b/chromium/components/viz/service/display/resolved_frame_data.cc
index 2ee23641892..a3df55b14f8 100644
--- a/chromium/components/viz/service/display/resolved_frame_data.cc
+++ b/chromium/components/viz/service/display/resolved_frame_data.cc
@@ -192,6 +192,10 @@ bool ResolvedFrameData::CheckIfUsedAndReset() {
return std::exchange(used_, false);
}
+bool ResolvedFrameData::WillDraw() const {
+ return GetRootRenderPassData().aggregation().will_draw;
+}
+
ResolvedPassData& ResolvedFrameData::GetRenderPassDataById(
CompositorRenderPassId render_pass_id) {
return const_cast<ResolvedPassData&>(
diff --git a/chromium/components/viz/service/display/resolved_frame_data.h b/chromium/components/viz/service/display/resolved_frame_data.h
index ec558beba32..c5fbf1033e7 100644
--- a/chromium/components/viz/service/display/resolved_frame_data.h
+++ b/chromium/components/viz/service/display/resolved_frame_data.h
@@ -84,6 +84,12 @@ struct VIZ_SERVICE_EXPORT AggregationPassData {
// True if there is accumulated damage from contributing render pass or
// surface quads.
bool has_damage_from_contributing_content = false;
+
+ // Indicates that the render pass is embedded from the root surface root
+ // render pass and will contribute pixels to framebuffer. Render passes this
+ // is false for may still be drawn but they won't contribute pixels to
+ // framebuffer.
+ bool will_draw = false;
};
// Data associated with a CompositorRenderPass in a resolved frame. Has fixed
@@ -168,6 +174,10 @@ class VIZ_SERVICE_EXPORT ResolvedFrameData {
// All functions after this point are accessors for the resolved frame and
// should only be called if is_valid() returns true.
+ // Returns true if the root render pass is embedded from the the root surface
+ // root render pass.
+ bool WillDraw() const;
+
// RenderPassData accessors.
ResolvedPassData& GetRenderPassDataById(
CompositorRenderPassId render_pass_id);
diff --git a/chromium/components/viz/service/display/scoped_gpu_memory_buffer_texture.cc b/chromium/components/viz/service/display/scoped_gpu_memory_buffer_texture.cc
index becf3a74f07..31c0a021dc0 100644
--- a/chromium/components/viz/service/display/scoped_gpu_memory_buffer_texture.cc
+++ b/chromium/components/viz/service/display/scoped_gpu_memory_buffer_texture.cc
@@ -44,9 +44,9 @@ ScopedGpuMemoryBufferTexture::ScopedGpuMemoryBufferTexture(
gl->TexParameteri(target_, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
gl->TexParameteri(target_, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- gl->TexStorage2DImageCHROMIUM(target_, TextureStorageFormat(format),
- GL_SCANOUT_CHROMIUM, size_.width(),
- size_.height());
+ gl->TexStorage2DImageCHROMIUM(
+ target_, TextureStorageFormat(format, caps.angle_rgbx_internal_format),
+ GL_SCANOUT_CHROMIUM, size_.width(), size_.height());
if (color_space_.IsValid()) {
gl->SetColorSpaceMetadataCHROMIUM(gl_id_, color_space_.AsGLColorSpace());
}
diff --git a/chromium/components/viz/service/display/scoped_render_pass_texture.cc b/chromium/components/viz/service/display/scoped_render_pass_texture.cc
index 844189b9adc..9a668018e08 100644
--- a/chromium/components/viz/service/display/scoped_render_pass_texture.cc
+++ b/chromium/components/viz/service/display/scoped_render_pass_texture.cc
@@ -49,8 +49,11 @@ ScopedRenderPassTexture::ScopedRenderPassTexture(
if (caps.texture_npot && mipmap_)
levels += base::bits::Log2Floor(std::max(size_.width(), size_.height()));
- gl->TexStorage2DEXT(GL_TEXTURE_2D, levels, TextureStorageFormat(format),
- size_.width(), size_.height());
+ gl->TexStorage2DEXT(
+ GL_TEXTURE_2D, levels,
+ TextureStorageFormat(format, context_provider_->ContextCapabilities()
+ .angle_rgbx_internal_format),
+ size_.width(), size_.height());
} else {
DCHECK(GLSupportsFormat(format));
gl->TexImage2D(GL_TEXTURE_2D, 0, GLInternalFormat(format), size_.width(),
@@ -113,7 +116,7 @@ void ScopedRenderPassTexture::BindForSampling() {
DCHECK(context_provider_->ContextCapabilities().texture_npot);
gl->GenerateMipmap(GL_TEXTURE_2D);
mipmap_state_ = VALID;
- FALLTHROUGH;
+ [[fallthrough]];
case VALID:
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_LINEAR_MIPMAP_LINEAR);
diff --git a/chromium/components/viz/service/display/shader.cc b/chromium/components/viz/service/display/shader.cc
index 20b599020dd..ac9e11564f7 100644
--- a/chromium/components/viz/service/display/shader.cc
+++ b/chromium/components/viz/service/display/shader.cc
@@ -335,7 +335,7 @@ std::string VertexShader::GetShaderString() const {
break;
case TEX_COORD_TRANSFORM_TRANSLATED_VEC4:
SRC("texCoord = texCoord + vec2(0.5);");
- FALLTHROUGH;
+ [[fallthrough]];
case TEX_COORD_TRANSFORM_VEC4:
if (use_uniform_arrays_) {
HDR("uniform TexCoordPrecision vec4 vertexTexTransform[NUM_QUADS];");
diff --git a/chromium/components/viz/service/display/skia_output_surface.h b/chromium/components/viz/service/display/skia_output_surface.h
index dfb6c58cddd..bbc36c88f3a 100644
--- a/chromium/components/viz/service/display/skia_output_surface.h
+++ b/chromium/components/viz/service/display/skia_output_surface.h
@@ -18,18 +18,18 @@
#include "third_party/skia/include/core/SkRefCnt.h"
#include "third_party/skia/include/core/SkYUVAInfo.h"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include "components/viz/service/display/dc_layer_overlay.h"
#endif
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
#include "components/viz/service/display/ca_layer_overlay.h"
#endif
class SkCanvas;
class SkImage;
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
class SkDeferredDisplayList;
#endif
@@ -54,11 +54,11 @@ struct RenderPassGeometry;
class VIZ_SERVICE_EXPORT SkiaOutputSurface : public OutputSurface,
public ExternalUseClient {
public:
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
using OverlayList = std::vector<OverlayCandidate>;
-#elif defined(OS_APPLE)
+#elif BUILDFLAG(IS_APPLE)
using OverlayList = CALayerOverlayList;
-#elif defined(OS_WIN)
+#elif BUILDFLAG(IS_WIN)
using OverlayList = DCLayerOverlayList;
#elif defined(USE_OZONE)
using OverlayList = std::vector<OverlayCandidate>;
@@ -193,7 +193,7 @@ class VIZ_SERVICE_EXPORT SkiaOutputSurface : public OutputSurface,
// begin frames. Used to estimate when rendering becomes idle.
virtual void OnObservingBeginFrameSourceChanged(bool observing) = 0;
-#if defined(OS_APPLE) || defined(USE_OZONE)
+#if BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
virtual SkCanvas* BeginPaintRenderPassOverlay(
const gfx::Size& size,
ResourceFormat format,
diff --git a/chromium/components/viz/service/display/skia_readback_pixeltest.cc b/chromium/components/viz/service/display/skia_readback_pixeltest.cc
index c4120af82f7..5fe3f2eb33c 100644
--- a/chromium/components/viz/service/display/skia_readback_pixeltest.cc
+++ b/chromium/components/viz/service/display/skia_readback_pixeltest.cc
@@ -553,7 +553,7 @@ TEST_P(SkiaReadbackPixelTestNV12, ExecutesCopyRequest) {
cc::MatchesBitmap(actual, expected, GetDefaultFuzzyPixelComparator()));
}
-#if !defined(OS_ANDROID) || !defined(ARCH_CPU_X86_FAMILY)
+#if !BUILDFLAG(IS_ANDROID) || !defined(ARCH_CPU_X86_FAMILY)
INSTANTIATE_TEST_SUITE_P(
,
SkiaReadbackPixelTestNV12,
@@ -731,7 +731,7 @@ TEST_P(SkiaReadbackPixelTestNV12WithBlit, ExecutesCopyRequestWithBlit) {
cc::MatchesBitmap(actual, expected, GetDefaultFuzzyPixelComparator()));
}
-#if !defined(OS_ANDROID) || !defined(ARCH_CPU_X86_FAMILY)
+#if !BUILDFLAG(IS_ANDROID) || !defined(ARCH_CPU_X86_FAMILY)
INSTANTIATE_TEST_SUITE_P(,
SkiaReadbackPixelTestNV12WithBlit,
// Result scaling: Scale by half?
diff --git a/chromium/components/viz/service/display/skia_renderer.cc b/chromium/components/viz/service/display/skia_renderer.cc
index ab0f0531ba9..40023ab808e 100644
--- a/chromium/components/viz/service/display/skia_renderer.cc
+++ b/chromium/components/viz/service/display/skia_renderer.cc
@@ -14,6 +14,7 @@
#include "base/command_line.h"
#include "base/logging.h"
#include "base/memory/raw_ptr.h"
+#include "base/metrics/histogram_macros.h"
#include "base/synchronization/waitable_event.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
@@ -88,14 +89,14 @@ namespace {
// was chosen to match that used by gl_renderer.
static const float kAAEpsilon = 1.0f / 1024.0f;
-#if defined(OS_APPLE) || defined(USE_OZONE)
+#if BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
SkScalar remove_epsilon(SkScalar v) {
return v < std::numeric_limits<SkScalar>::epsilon() &&
v > -std::numeric_limits<SkScalar>::epsilon()
? 0
: v;
}
-#endif // defined(OS_APPLE) || defined(USE_OZONE)
+#endif // BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
// The gfx::QuadF draw_region passed to DoDrawQuad, converted to Skia types
struct SkDrawRegion {
@@ -573,7 +574,8 @@ class SkiaRenderer::ScopedSkImageBuilder {
SkAlphaType alpha_type = kPremul_SkAlphaType,
GrSurfaceOrigin origin = kTopLeft_GrSurfaceOrigin,
const absl::optional<gfx::ColorSpace>&
- override_colorspace = absl::nullopt);
+ override_colorspace = absl::nullopt,
+ bool raw_draw_if_possible = false);
ScopedSkImageBuilder(const ScopedSkImageBuilder&) = delete;
ScopedSkImageBuilder& operator=(const ScopedSkImageBuilder&) = delete;
@@ -596,7 +598,8 @@ SkiaRenderer::ScopedSkImageBuilder::ScopedSkImageBuilder(
bool maybe_concurrent_reads,
SkAlphaType alpha_type,
GrSurfaceOrigin origin,
- const absl::optional<gfx::ColorSpace>& override_color_space) {
+ const absl::optional<gfx::ColorSpace>& override_color_space,
+ bool raw_draw_if_possible) {
if (!resource_id)
return;
auto* resource_provider = skia_renderer->resource_provider();
@@ -604,7 +607,7 @@ SkiaRenderer::ScopedSkImageBuilder::ScopedSkImageBuilder(
auto* image_context = skia_renderer->lock_set_for_external_use_->LockResource(
resource_id, maybe_concurrent_reads, /*is_video_plane=*/false,
- override_color_space);
+ override_color_space, raw_draw_if_possible);
// |ImageContext::image| provides thread safety: (a) this ImageContext is
// only accessed by GPU thread after |image| is set and (b) the fields of
@@ -760,6 +763,7 @@ void SkiaRenderer::BeginDrawingFrame() {
void SkiaRenderer::FinishDrawingFrame() {
TRACE_EVENT0("viz", "SkiaRenderer::FinishDrawingFrame");
+ root_canvas_ = nullptr;
current_canvas_ = nullptr;
current_surface_ = nullptr;
@@ -792,7 +796,9 @@ void SkiaRenderer::SwapBuffers(SwapFrameData swap_frame_data) {
output_frame.delegated_ink_metadata =
delegated_ink_handler_->TakeMetadata();
}
-
+#if BUILDFLAG(IS_MAC)
+ output_frame.ca_layer_error_code = swap_frame_data.ca_layer_error_code;
+#endif
skia_output_surface_->SwapBuffers(std::move(output_frame));
swap_buffer_rect_ = gfx::Rect();
@@ -835,12 +841,12 @@ void SkiaRenderer::SwapBuffersComplete(gfx::GpuFenceHandle release_fence) {
// Right now, only macOS and Ozone need to return mailboxes of released
// overlays, so we should not release |committed_overlay_locks_| here. The
// resources in it will be released by DidReceiveReleasedOverlays() later.
-#if defined(OS_APPLE) || defined(USE_OZONE)
+#if BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
for (auto lock_iter = committed_overlay_locks_.begin();
lock_iter != read_fence_lock_iter; ++lock_iter) {
awaiting_release_overlay_locks_.insert(std::move(*lock_iter));
}
-#endif // defined(OS_APPLE) || defined(USE_OZONE)
+#endif // BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
committed_overlay_locks_.clear();
std::swap(committed_overlay_locks_, pending_overlay_locks_.front());
@@ -855,7 +861,7 @@ void SkiaRenderer::BuffersPresented() {
void SkiaRenderer::DidReceiveReleasedOverlays(
const std::vector<gpu::Mailbox>& released_overlays) {
// This method is only called on macOS and Ozone right now.
-#if defined(OS_APPLE) || defined(USE_OZONE)
+#if BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
for (const auto& mailbox : released_overlays) {
auto it = awaiting_release_overlay_locks_.find(mailbox);
if (it == awaiting_release_overlay_locks_.end()) {
@@ -866,7 +872,7 @@ void SkiaRenderer::DidReceiveReleasedOverlays(
}
#else
NOTREACHED();
-#endif // !(defined(OS_APPLE) || defined (USE_OZONE))
+#endif // !(BUILDFLAG(IS_APPLE) || defined (USE_OZONE))
}
bool SkiaRenderer::FlippedFramebuffer() const {
@@ -1421,34 +1427,20 @@ void SkiaRenderer::DrawQuadParams::ApplyScissor(
// device space, it will be contained in in the original scissor.
// Applying the scissor explicitly means avoiding a clipRect() call and
// allows more quads to be batched together in a DrawEdgeAAImageSet call
- float left_inset = local_scissor.x() - visible_rect.x();
- float top_inset = local_scissor.y() - visible_rect.y();
- float right_inset = visible_rect.right() - local_scissor.right();
- float bottom_inset = visible_rect.bottom() - local_scissor.bottom();
+ float x_epsilon = kAAEpsilon / content_device_transform.matrix().get(0, 0);
+ float y_epsilon = kAAEpsilon / content_device_transform.matrix().get(1, 1);
- // The scissor is a non-AA clip, so we unset the bit flag for clipped edges.
- if (left_inset >= kAAEpsilon) {
+ // The scissor is a non-AA clip, so unset the bit flag for clipped edges.
+ if (local_scissor.x() - visible_rect.x() >= x_epsilon)
aa_flags &= ~SkCanvas::kLeft_QuadAAFlag;
- } else {
- left_inset = 0;
- }
- if (top_inset >= kAAEpsilon) {
+ if (local_scissor.y() - visible_rect.y() >= y_epsilon)
aa_flags &= ~SkCanvas::kTop_QuadAAFlag;
- } else {
- top_inset = 0;
- }
- if (right_inset >= kAAEpsilon) {
+ if (visible_rect.right() - local_scissor.right() >= x_epsilon)
aa_flags &= ~SkCanvas::kRight_QuadAAFlag;
- } else {
- right_inset = 0;
- }
- if (bottom_inset >= kAAEpsilon) {
+ if (visible_rect.bottom() - local_scissor.bottom() >= y_epsilon)
aa_flags &= ~SkCanvas::kBottom_QuadAAFlag;
- } else {
- bottom_inset = 0;
- }
- visible_rect.Inset(left_inset, top_inset, right_inset, bottom_inset);
+ visible_rect.Intersect(local_scissor);
vis_tex_coords = visible_rect;
scissor_rect.reset();
}
@@ -1782,8 +1774,8 @@ void SkiaRenderer::FlushBatchedQuads() {
void SkiaRenderer::DrawColoredQuad(SkColor color,
const DrawRPDQParams* rpdq_params,
DrawQuadParams* params) {
- DCHECK(batched_quads_.empty());
TRACE_EVENT0("viz", "SkiaRenderer::DrawColoredQuad");
+ DCHECK(batched_quads_.empty());
SkAutoCanvasRestore acr(current_canvas_, true /* do_save */);
PrepareCanvas(params->scissor_rect, params->rounded_corner_bounds,
@@ -1868,6 +1860,7 @@ void SkiaRenderer::DrawPaintOpBuffer(const cc::PaintOpBuffer* buffer,
const absl::optional<SkColor>& clear_color,
const TileDrawQuad* quad,
const DrawQuadParams* params) {
+ TRACE_EVENT0("viz", "SkiaRenderer::DrawPaintOpBuffer");
if (!batched_quads_.empty())
FlushBatchedQuads();
@@ -1910,6 +1903,7 @@ void SkiaRenderer::DrawPaintOpBuffer(const cc::PaintOpBuffer* buffer,
void SkiaRenderer::DrawDebugBorderQuad(const DebugBorderDrawQuad* quad,
DrawQuadParams* params) {
+ TRACE_EVENT0("viz", "SkiaRenderer::DrawDebugBorderQuad");
DCHECK(batched_quads_.empty());
SkAutoCanvasRestore acr(current_canvas_, true /* do_save */);
@@ -2002,6 +1996,7 @@ void SkiaRenderer::DrawSolidColorQuad(const SolidColorDrawQuad* quad,
void SkiaRenderer::DrawStreamVideoQuad(const StreamVideoDrawQuad* quad,
const DrawRPDQParams* rpdq_params,
DrawQuadParams* params) {
+ TRACE_EVENT0("viz", "SkiaRenderer::DrawStreamVideoQuad");
DCHECK(!MustFlushBatchedQuads(quad, rpdq_params, *params));
absl::optional<gfx::ColorSpace> override_color_space;
@@ -2044,6 +2039,7 @@ void SkiaRenderer::DrawStreamVideoQuad(const StreamVideoDrawQuad* quad,
void SkiaRenderer::DrawTextureQuad(const TextureDrawQuad* quad,
const DrawRPDQParams* rpdq_params,
DrawQuadParams* params) {
+ TRACE_EVENT0("viz", "SkiaRenderer::DrawTextureQuad");
const gfx::ColorSpace& src_color_space =
resource_provider()->GetColorSpace(quad->resource_id());
const bool needs_color_conversion_filter =
@@ -2199,18 +2195,38 @@ void SkiaRenderer::DrawTextureQuad(const TextureDrawQuad* quad,
void SkiaRenderer::DrawTileDrawQuad(const TileDrawQuad* quad,
const DrawRPDQParams* rpdq_params,
DrawQuadParams* params) {
+ TRACE_EVENT0("viz", "SkiaRenderer::DrawTileDrawQuad");
DCHECK(!MustFlushBatchedQuads(quad, rpdq_params, *params));
// |resource_provider()| can be NULL in resourceless software draws, which
// should never produce tile quads in the first place.
DCHECK(resource_provider());
+
+ // If quad->ShouldDrawWithBlending() is true, we need to raster tile paint ops
+ // to an offscreen texture first, and then blend it with content behind the
+ // tile. Since a tile could be used cross frames, so it would better to not
+ // use raw draw.
+ bool raw_draw_if_possible =
+ is_using_raw_draw_ && !quad->ShouldDrawWithBlending();
ScopedSkImageBuilder builder(
this, quad->resource_id(), /*maybe_concurrent_reads=*/false,
- quad->is_premultiplied ? kPremul_SkAlphaType : kUnpremul_SkAlphaType);
+ quad->is_premultiplied ? kPremul_SkAlphaType : kUnpremul_SkAlphaType,
+ /*origin=*/kTopLeft_GrSurfaceOrigin,
+ /*override_colorspace=*/absl::nullopt, raw_draw_if_possible);
params->vis_tex_coords = cc::MathUtil::ScaleRectProportional(
quad->tex_coord_rect, gfx::RectF(quad->rect), params->visible_rect);
- if (builder.paint_op_buffer()) {
+ bool translate_only = params->content_device_transform.matrix().isTranslate();
+ UMA_HISTOGRAM_BOOLEAN(
+ "Compositing.SkiaRenderer.DrawTileDrawQuad.CDT.IsTranslateOnly",
+ translate_only);
+ bool using_raw_draw = builder.paint_op_buffer();
+ if (is_using_raw_draw_) {
+ UMA_HISTOGRAM_BOOLEAN(
+ "Compositing.SkiaRenderer.DrawTileDrawQuad.UsingRawDraw",
+ using_raw_draw);
+ }
+ if (using_raw_draw) {
DCHECK(!rpdq_params);
DrawPaintOpBuffer(builder.paint_op_buffer(), builder.clear_color(), quad,
params);
@@ -2246,6 +2262,7 @@ void SkiaRenderer::DrawTileDrawQuad(const TileDrawQuad* quad,
void SkiaRenderer::DrawYUVVideoQuad(const YUVVideoDrawQuad* quad,
const DrawRPDQParams* rpdq_params,
DrawQuadParams* params) {
+ TRACE_EVENT0("viz", "SkiaRenderer::DrawYUVVideoQuad");
// Since YUV quads always use a color filter, they require a complex skPaint
// that precludes batching. If this changes, we could add YUV quads that don't
// require a filter to the batch instead of drawing one at a time.
@@ -2265,7 +2282,7 @@ void SkiaRenderer::DrawYUVVideoQuad(const YUVVideoDrawQuad* quad,
const gfx::ColorSpace& frame_color_space = CurrentRenderPassColorSpace();
gfx::ColorSpace dst_color_space = frame_color_space;
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// Force sRGB output on Windows for overlay candidate video quads to match
// DirectComposition behavior in case these switch between overlays and
// compositing. See https://crbug.com/811118 for details.
@@ -2332,11 +2349,11 @@ void SkiaRenderer::ScheduleOverlays() {
std::vector<gpu::SyncToken> sync_tokens;
-#if !defined(OS_WIN)
+#if !BUILDFLAG(IS_WIN)
DCHECK(output_surface_->capabilities().supports_surfaceless);
#endif
-#if defined(OS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH)
// CrOS and Android SurfaceControl use this code path. Android classic has
// switched over to OverlayProcessor.
// TODO(weiliangc): Remove this when CrOS and Android SurfaceControl switch
@@ -2355,7 +2372,7 @@ void SkiaRenderer::ScheduleOverlays() {
overlay.mailbox = lock.mailbox();
DCHECK(!overlay.mailbox.IsZero());
}
-#elif defined(OS_WIN)
+#elif BUILDFLAG(IS_WIN)
auto& locks = pending_overlay_locks_.back();
for (auto& dc_layer_overlay : current_frame()->overlay_list) {
for (size_t i = 0; i < DCLayerOverlay::kNumResources; ++i) {
@@ -2376,7 +2393,7 @@ void SkiaRenderer::ScheduleOverlays() {
}
DCHECK(!dc_layer_overlay.mailbox[0].IsZero());
}
-#elif defined(OS_APPLE)
+#elif BUILDFLAG(IS_APPLE)
auto& locks = pending_overlay_locks_.back();
for (CALayerOverlay& ca_layer_overlay : current_frame()->overlay_list) {
if (ca_layer_overlay.rpdq) {
@@ -2428,12 +2445,12 @@ void SkiaRenderer::ScheduleOverlays() {
overlay.mailbox = lock.mailbox();
DCHECK(!overlay.mailbox.IsZero());
}
-#else // defined(OS_ANDROID)
+#else // BUILDFLAG(IS_ANDROID)
// For platforms that don't support overlays, the
// current_frame()->overlay_list should be empty, and this code should not be
// reached.
NOTREACHED();
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
base::OnceClosure on_finished_callback;
if (current_frame_resource_fence_->WasSet()) {
@@ -2456,49 +2473,12 @@ sk_sp<SkColorFilter> SkiaRenderer::GetColorSpaceConversionFilter(
// If the input color space is HDR, and it did not specify a white level,
// override it with the frame's white level.
gfx::ColorSpace adjusted_src = src.GetWithSDRWhiteLevel(
- current_frame()->display_color_spaces.GetSDRWhiteLevel());
-
- sk_sp<SkRuntimeEffect>& effect = color_filter_cache_[dst][adjusted_src];
- if (!effect) {
- std::unique_ptr<gfx::ColorTransform> transform =
- gfx::ColorTransform::NewColorTransform(adjusted_src, dst);
-
- const char* hdr = R"(
-uniform half offset;
-uniform half multiplier;
-
-half4 main(half4 color) {
- // un-premultiply alpha
- if (color.a > 0)
- color.rgb /= color.a;
-
- color.rgb -= offset;
- color.rgb *= multiplier;
-)";
- const char* ftr = R"(
- // premultiply alpha
- color.rgb *= color.a;
- return color;
-}
-)";
-
- std::string shader = hdr + transform->GetSkShaderSource() + ftr;
-
- auto result = SkRuntimeEffect::MakeForColorFilter(
- SkString(shader.c_str(), shader.size()),
- /*options=*/{});
- DCHECK(result.effect) << std::endl
- << result.errorText.c_str() << "\n\nShader Source:\n"
- << shader;
- effect = result.effect;
- }
-
- YUVInput input;
- input.offset = resource_offset;
- input.multiplier = resource_multiplier;
- sk_sp<SkData> data = SkData::MakeWithCopy(&input, sizeof(input));
+ current_frame()->display_color_spaces.GetSDRMaxLuminanceNits());
- return effect->makeColorFilter(std::move(data));
+ return color_filter_cache_.Get(
+ adjusted_src, dst, resource_offset, resource_multiplier,
+ current_frame()->display_color_spaces.GetSDRMaxLuminanceNits(),
+ current_frame()->display_color_spaces.GetHDRMaxLuminanceRelative());
}
namespace {
@@ -2711,6 +2691,7 @@ SkiaRenderer::DrawRPDQParams SkiaRenderer::CalculateRPDQParams(
void SkiaRenderer::DrawRenderPassQuad(const AggregatedRenderPassDrawQuad* quad,
DrawQuadParams* params) {
+ TRACE_EVENT0("viz", "SkiaRenderer::DrawRenderPassQuad");
DrawRPDQParams rpdq_params = CalculateRPDQParams(quad, params);
// |filter_bounds| is the content space bounds that includes any filtered
@@ -2812,6 +2793,7 @@ void SkiaRenderer::DidChangeVisibility() {
}
void SkiaRenderer::FinishDrawingQuadList() {
+ TRACE_EVENT0("viz", "SkiaRenderer::FinishDrawingQuadList");
if (!current_canvas_)
return;
@@ -2925,7 +2907,7 @@ void SkiaRenderer::FlushOutputSurface() {
lock_set_for_external_use_->UnlockResources(sync_token);
}
-#if defined(OS_APPLE) || defined(USE_OZONE)
+#if BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
void SkiaRenderer::PrepareRenderPassOverlay(
OverlayProcessorInterface::PlatformOverlayCandidate* overlay) {
DCHECK(!current_canvas_);
@@ -3060,7 +3042,7 @@ void SkiaRenderer::PrepareRenderPassOverlay(
// Adjust the overlay |buffer_size| to reduce memory fragmentation. It also
// increases buffer reusing possibilities.
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
constexpr int kBufferMultiple = 64;
#else // defined(USE_OZONE)
// TODO(petermcneeley) : Support buffer rounding by dynamically changing
@@ -3200,7 +3182,7 @@ bool SkiaRenderer::UsingSkiaForDelegatedInk() const {
return delegated_ink_handler_ && delegated_ink_handler_->GetInkRenderer();
}
-#if defined(OS_APPLE) || defined(USE_OZONE)
+#if BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
bool SkiaRenderer::ScopedReadLockComparator::operator()(
const DisplayResourceProviderSkia::ScopedReadLockSharedImage& lhs,
const DisplayResourceProviderSkia::ScopedReadLockSharedImage& rhs) const {
@@ -3218,6 +3200,6 @@ bool SkiaRenderer::ScopedReadLockComparator::operator()(
const DisplayResourceProviderSkia::ScopedReadLockSharedImage& rhs) const {
return lhs < rhs.mailbox();
}
-#endif // defined(OS_APPLE) || defined(USE_OZONE)
+#endif // BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
} // namespace viz
diff --git a/chromium/components/viz/service/display/skia_renderer.h b/chromium/components/viz/service/display/skia_renderer.h
index c959f40bdca..fcb96836124 100644
--- a/chromium/components/viz/service/display/skia_renderer.h
+++ b/chromium/components/viz/service/display/skia_renderer.h
@@ -19,10 +19,10 @@
#include "components/viz/service/display/sync_query_collection.h"
#include "components/viz/service/viz_service_export.h"
#include "third_party/skia/include/core/SkCanvas.h"
+#include "ui/gfx/color_conversion_sk_filter_cache.h"
#include "ui/latency/latency_info.h"
class SkColorFilter;
-class SkRuntimeEffect;
namespace viz {
class AggregatedRenderPassDrawQuad;
@@ -257,7 +257,7 @@ class VIZ_SERVICE_EXPORT SkiaRenderer : public DirectRenderer {
// be sent to GPU scheduler.
void FlushOutputSurface();
-#if defined(OS_APPLE) || defined(USE_OZONE)
+#if BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
void PrepareRenderPassOverlay(
OverlayProcessorInterface::PlatformOverlayCandidate* overlay);
#endif
@@ -339,7 +339,7 @@ class VIZ_SERVICE_EXPORT SkiaRenderer : public DirectRenderer {
std::vector<DisplayResourceProviderSkia::ScopedReadLockSharedImage>>
read_lock_release_fence_overlay_locks_;
-#if defined(OS_APPLE) || defined(USE_OZONE)
+#if BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
class ScopedReadLockComparator {
public:
using is_transparent = void;
@@ -360,11 +360,9 @@ class VIZ_SERVICE_EXPORT SkiaRenderer : public DirectRenderer {
base::flat_set<DisplayResourceProviderSkia::ScopedReadLockSharedImage,
ScopedReadLockComparator>
awaiting_release_overlay_locks_;
-#endif // defined(OS_APPLE) || defined(USE_OZONE)
+#endif // BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
- base::flat_map<gfx::ColorSpace,
- base::flat_map<gfx::ColorSpace, sk_sp<SkRuntimeEffect>>>
- color_filter_cache_;
+ gfx::ColorConversionSkFilterCache color_filter_cache_;
bool UsingSkiaForDelegatedInk() const;
uint32_t debug_tint_modulate_count_ = 0;
diff --git a/chromium/components/viz/service/display/software_renderer.cc b/chromium/components/viz/service/display/software_renderer.cc
index d1a334a23b2..730b7f039a1 100644
--- a/chromium/components/viz/service/display/software_renderer.cc
+++ b/chromium/components/viz/service/display/software_renderer.cc
@@ -11,6 +11,7 @@
#include "base/memory/raw_ptr.h"
#include "base/process/memory.h"
#include "base/trace_event/trace_event.h"
+#include "build/build_config.h"
#include "cc/base/math_util.h"
#include "cc/paint/image_provider.h"
#include "cc/paint/render_surface_filters.h"
@@ -169,7 +170,7 @@ void SoftwareRenderer::SetClipRect(const gfx::Rect& rect) {
// Checks below are incompatible with WebView as the canvas size and clip
// provided by Android or embedder app. And Chrome doesn't use
// SoftwareRenderer on Android.
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
// SetClipRect is assumed to be applied temporarily, on an
// otherwise-unclipped canvas.
DCHECK_EQ(current_canvas_->getDeviceClipBounds().width(),
diff --git a/chromium/components/viz/service/display/surface_aggregator.cc b/chromium/components/viz/service/display/surface_aggregator.cc
index 5ae5ff22a13..183999896f2 100644
--- a/chromium/components/viz/service/display/surface_aggregator.cc
+++ b/chromium/components/viz/service/display/surface_aggregator.cc
@@ -255,6 +255,27 @@ gfx::Rect ComputeDrawableRectForQuad(const DrawQuad* quad) {
return drawable_rect;
}
+// This function transforms a rect from its target space to the destination
+// root target space. If clip_rect is valid, clipping is applied after
+// transform.
+gfx::Rect TransformRectToDestRootTargetSpace(
+ const gfx::Rect& rect_in_target_space,
+ const gfx::Transform& target_to_dest_transform,
+ const gfx::Transform& dest_to_root_target_transform,
+ const absl::optional<gfx::Rect>& dest_root_target_clip_rect) {
+ gfx::Transform target_to_dest_root_target_transform =
+ gfx::Transform(dest_to_root_target_transform, target_to_dest_transform);
+
+ gfx::Rect rect_in_root_target_space = cc::MathUtil::MapEnclosingClippedRect(
+ target_to_dest_root_target_transform, rect_in_target_space);
+
+ if (dest_root_target_clip_rect) {
+ rect_in_root_target_space.Intersect(*dest_root_target_clip_rect);
+ }
+
+ return rect_in_root_target_space;
+}
+
} // namespace
constexpr base::TimeDelta SurfaceAggregator::kHistogramMinTime;
@@ -270,16 +291,19 @@ struct SurfaceAggregator::PrewalkResult {
gfx::ContentColorUsage content_color_usage = gfx::ContentColorUsage::kSRGB;
};
-SurfaceAggregator::SurfaceAggregator(SurfaceManager* manager,
- DisplayResourceProvider* provider,
- bool aggregate_only_damaged,
- bool needs_surface_damage_rect_list)
+SurfaceAggregator::SurfaceAggregator(
+ SurfaceManager* manager,
+ DisplayResourceProvider* provider,
+ bool aggregate_only_damaged,
+ bool needs_surface_damage_rect_list,
+ ExtraPassForReadbackOption extra_pass_option)
: manager_(manager),
provider_(provider),
aggregate_only_damaged_(aggregate_only_damaged),
needs_surface_damage_rect_list_(needs_surface_damage_rect_list),
de_jelly_enabled_(DeJellyEnabled()),
- clip_prewalk_damage_(features::IsClipPrewalkDamageEnabled()) {
+ clip_prewalk_damage_(features::IsClipPrewalkDamageEnabled()),
+ extra_pass_for_readback_option_(extra_pass_option) {
DCHECK(manager_);
DCHECK(provider_);
}
@@ -347,46 +371,67 @@ gfx::Rect SurfaceAggregator::DamageRectForSurface(
// This function is called at each render pass - CopyQuadsToPass().
void SurfaceAggregator::AddRenderPassFilterDamageToDamageList(
+ const ResolvedFrameData& resolved_frame,
+ const CompositorRenderPassDrawQuad* render_pass_quad,
const gfx::Transform& parent_target_transform,
- const CompositorRenderPass* source_pass,
- AggregatedRenderPass* dest_pass) {
+ const absl::optional<gfx::Rect>& dest_root_target_clip_rect,
+ const gfx::Transform& dest_transform_to_root_target) {
+ const CompositorRenderPassId child_pass_id = render_pass_quad->render_pass_id;
+ const ResolvedPassData& child_resolved_pass =
+ resolved_frame.GetRenderPassDataById(child_pass_id);
+ const CompositorRenderPass& child_render_pass =
+ child_resolved_pass.render_pass();
+
// Add damages from render passes with pixel-moving foreground filters or
// backdrop filters to the surface damage list.
- if (!source_pass->filters.HasFilterThatMovesPixels() &&
- !source_pass->backdrop_filters.HasFilterThatMovesPixels()) {
+ if (!child_render_pass.filters.HasFilterThatMovesPixels() &&
+ !child_render_pass.backdrop_filters.HasFilterThatMovesPixels()) {
return;
}
- gfx::Transform parent_to_root_target_transform = gfx::Transform(
- dest_pass->transform_to_root_target, parent_target_transform);
-
- gfx::Rect damage_rect = source_pass->output_rect;
- if (source_pass->filters.HasFilterThatMovesPixels()) {
- float max_pixel_movement = source_pass->filters.MaximumPixelMovement();
- gfx::RectF damage_rect_f(damage_rect);
- damage_rect_f.Inset(-max_pixel_movement, -max_pixel_movement);
- damage_rect = gfx::ToEnclosingRect(damage_rect_f);
+ gfx::Rect damage_rect = render_pass_quad->rect;
+ gfx::Rect damage_rect_in_target_space;
+ if (child_render_pass.filters.HasFilterThatMovesPixels()) {
+ // The size of pixel-moving foreground filter is allowed to expand.
+ // No intersecting shared_quad_state->clip_rect for the expanded rect.
+ damage_rect_in_target_space =
+ GetExpandedRectWithPixelMovingForegroundFilter(render_pass_quad,
+ child_render_pass);
+ } else if (child_render_pass.backdrop_filters.HasFilterThatMovesPixels()) {
+ const auto* shared_quad_state = render_pass_quad->shared_quad_state;
+ damage_rect_in_target_space = cc::MathUtil::MapEnclosingClippedRect(
+ shared_quad_state->quad_to_target_transform, damage_rect);
+ if (shared_quad_state->clip_rect) {
+ damage_rect_in_target_space.Intersect(
+ shared_quad_state->clip_rect.value());
+ }
}
gfx::Rect damage_rect_in_root_target_space =
- cc::MathUtil::MapEnclosingClippedRect(parent_to_root_target_transform,
- damage_rect);
+ TransformRectToDestRootTargetSpace(
+ damage_rect_in_target_space, parent_target_transform,
+ dest_transform_to_root_target, dest_root_target_clip_rect);
// The whole render pass rect with pixel-moving foreground filters or
// backdrop filters is considered damaged if it intersects with the other
// damages.
if (damage_rect_in_root_target_space.Intersects(root_damage_rect_)) {
- // Transform will be performed again in AddSurfaceDamageToDamageList()
- // Just pass in damage_rect instead of damage_rect_in_root_target_space.
- AddSurfaceDamageToDamageList(damage_rect, gfx::Transform(), {}, dest_pass,
- /*resolved_frame=*/nullptr);
+ // Since |damage_rect_in_root_target_space| is available, just pass this
+ // rect and reset the other arguments.
+ AddSurfaceDamageToDamageList(
+ damage_rect_in_root_target_space,
+ /*parent_target_transform*/ gfx::Transform(),
+ /*dest_root_target_clip_rect*/ {},
+ /*dest_transform_to_root_target*/ gfx::Transform(),
+ /*resolved_frame=*/nullptr);
}
}
+
void SurfaceAggregator::AddSurfaceDamageToDamageList(
const gfx::Rect& default_damage_rect,
const gfx::Transform& parent_target_transform,
- const absl::optional<gfx::Rect>& clip_rect,
- AggregatedRenderPass* dest_pass,
+ const absl::optional<gfx::Rect>& dest_root_target_clip_rect,
+ const gfx::Transform& dest_transform_to_root_target,
const ResolvedFrameData* resolved_frame) {
gfx::Rect damage_rect;
if (!resolved_frame) {
@@ -407,18 +452,10 @@ void SurfaceAggregator::AddSurfaceDamageToDamageList(
}
current_zero_damage_rect_is_not_recorded_ = false;
- gfx::Transform parent_to_root_target_transform = gfx::Transform(
- dest_pass->transform_to_root_target, parent_target_transform);
-
gfx::Rect damage_rect_in_root_target_space =
- cc::MathUtil::MapEnclosingClippedRect(parent_to_root_target_transform,
- damage_rect);
-
- if (clip_rect) {
- gfx::Rect root_clip_rect = cc::MathUtil::MapEnclosingClippedRect(
- dest_pass->transform_to_root_target, *clip_rect);
- damage_rect_in_root_target_space.Intersect(root_clip_rect);
- }
+ TransformRectToDestRootTargetSpace(
+ /*rect_in_target_space=*/damage_rect, parent_target_transform,
+ dest_transform_to_root_target, dest_root_target_clip_rect);
surface_damage_rect_list_->push_back(damage_rect_in_root_target_space);
}
@@ -433,7 +470,6 @@ const DrawQuad* SurfaceAggregator::FindQuadWithOverlayDamage(
AggregatedRenderPass* dest_pass,
const gfx::Transform& parent_target_transform,
const Surface* surface,
- const absl::optional<gfx::Rect>& clip_rect,
size_t* overlay_damage_index) {
// If we have damage from a surface animation, then we shouldn't have an
// overlay candidate from the root render pass, since that's an interpolated
@@ -578,6 +614,7 @@ void SurfaceAggregator::HandleSurfaceQuad(
float parent_device_scale_factor,
const gfx::Transform& target_transform,
const absl::optional<gfx::Rect>& added_clip_rect,
+ const absl::optional<gfx::Rect>& dest_root_target_clip_rect,
AggregatedRenderPass* dest_pass,
bool ignore_undamaged,
gfx::Rect* damage_rect_in_quad_space,
@@ -597,16 +634,31 @@ void SurfaceAggregator::HandleSurfaceQuad(
// If a new surface is going to be emitted, add the surface_quad rect to
// |surface_damage_rect_list_| for overlays. The whole quad is considered
// damaged.
- if (needs_surface_damage_rect_list_ &&
- (!resolved_frame ||
- (resolved_frame->surface_id() != primary_surface_id))) {
- // If using a fallback surface the surface content may be stretched or have
- // gutter. If the surface is missing the content will be filled with a solid
- // color. In both cases we no longer have frame-to-frame damage so treat the
- // entire SurfaceDrawQuad visible_rect as damaged.
- AddSurfaceDamageToDamageList(ComputeDrawableRectForQuad(surface_quad),
- target_transform, surface_clip_rect, dest_pass,
- /*resolved_frame=*/nullptr);
+ absl::optional<gfx::Rect> combined_clip_rect;
+ if (needs_surface_damage_rect_list_) {
+ gfx::Rect surface_in_target_space =
+ ComputeDrawableRectForQuad(surface_quad);
+ surface_in_target_space.Intersect(source_pass.output_rect);
+
+ if (!resolved_frame || resolved_frame->surface_id() != primary_surface_id) {
+ // If using a fallback surface the surface content may be stretched or
+ // have gutter. If the surface is missing the content will be filled
+ // with a solid color. In both cases we no longer have frame-to-frame
+ // damage so treat the entire SurfaceDrawQuad visible_rect as damaged.
+ // |combined_clip_rect| is the transforming and clipping result of the
+ // entire SurfaceDrawQuad visible_rect on the root target space of the
+ // root surface.
+ AddSurfaceDamageToDamageList(surface_in_target_space, target_transform,
+ dest_root_target_clip_rect,
+ dest_pass->transform_to_root_target,
+ /*resolved_frame=*/nullptr);
+ }
+
+ // combined_clip_rect is the result of |dest_root_target_clip_rect|
+ // intersecting |surface_quad| on the root target space of the root surface.
+ combined_clip_rect = TransformRectToDestRootTargetSpace(
+ /*rect_in_target_space=*/surface_in_target_space, target_transform,
+ dest_pass->transform_to_root_target, dest_root_target_clip_rect);
}
// If there's no fallback surface ID available, then simply emit a
@@ -641,8 +693,8 @@ void SurfaceAggregator::HandleSurfaceQuad(
}
EmitSurfaceContent(*resolved_frame, parent_device_scale_factor, surface_quad,
- target_transform, surface_clip_rect, dest_pass,
- ignore_undamaged, damage_rect_in_quad_space,
+ target_transform, surface_clip_rect, combined_clip_rect,
+ dest_pass, ignore_undamaged, damage_rect_in_quad_space,
damage_rect_in_quad_space_valid, mask_filter_info);
}
@@ -652,6 +704,7 @@ void SurfaceAggregator::EmitSurfaceContent(
const SurfaceDrawQuad* surface_quad,
const gfx::Transform& target_transform,
const absl::optional<gfx::Rect>& added_clip_rect,
+ const absl::optional<gfx::Rect>& dest_root_target_clip_rect,
AggregatedRenderPass* dest_pass,
bool ignore_undamaged,
gfx::Rect* damage_rect_in_quad_space,
@@ -746,7 +799,7 @@ void SurfaceAggregator::EmitSurfaceContent(
mask_filter_info.CanMergeMaskFilterInfo(*render_pass_list.back());
absl::optional<gfx::Rect> surface_quad_clip;
- if (merge_pass || needs_surface_damage_rect_list_) {
+ if (merge_pass) {
// Compute a clip rect in |dest_pass| coordinate space to ensure merged
// surface cannot draw outside where a non-merged surface would draw. An
// enclosing rect in |surface_quad| target render pass coordinate space is
@@ -757,10 +810,11 @@ void SurfaceAggregator::EmitSurfaceContent(
target_transform);
}
- if (needs_surface_damage_rect_list_) {
- AddSurfaceDamageToDamageList(/*default_damage_rect=*/gfx::Rect(),
- combined_transform, surface_quad_clip,
- dest_pass, &resolved_frame);
+ if (needs_surface_damage_rect_list_ && resolved_frame.WillDraw()) {
+ AddSurfaceDamageToDamageList(
+ /*default_damage_rect =*/gfx::Rect(), combined_transform,
+ dest_root_target_clip_rect, dest_pass->transform_to_root_target,
+ &resolved_frame);
}
if (frame.metadata.delegated_ink_metadata) {
@@ -813,8 +867,8 @@ void SurfaceAggregator::EmitSurfaceContent(
dest_pass->transform_to_root_target);
CopyQuadsToPass(resolved_frame, resolved_pass, copy_pass.get(),
- frame.device_scale_factor(), gfx::Transform(), {}, surface,
- MaskFilterInfoExt());
+ frame.device_scale_factor(), gfx::Transform(), {},
+ dest_root_target_clip_rect, surface, MaskFilterInfoExt());
// If the render pass has copy requests, or should be cached, or has
// moving-pixel filters, or in a moving-pixel surface, we should damage the
@@ -840,7 +894,8 @@ void SurfaceAggregator::EmitSurfaceContent(
if (merge_pass) {
CopyQuadsToPass(resolved_frame, resolved_root_pass, dest_pass,
frame.device_scale_factor(), combined_transform,
- surface_quad_clip, surface, mask_filter_info);
+ surface_quad_clip, dest_root_target_clip_rect, surface,
+ mask_filter_info);
} else {
auto* shared_quad_state = CopyAndScaleSharedQuadState(
surface_quad_sqs, scaled_quad_to_target_transform, target_transform,
@@ -1000,41 +1055,76 @@ void SurfaceAggregator::AddColorConversionPass() {
return;
CHECK(root_render_pass->transform_to_root_target == gfx::Transform());
- if (!color_conversion_render_pass_id_)
+ if (!color_conversion_render_pass_id_) {
color_conversion_render_pass_id_ =
render_pass_id_generator_.GenerateNextId();
+ }
- auto color_conversion_pass = std::make_unique<AggregatedRenderPass>(1, 1);
- color_conversion_pass->SetNew(color_conversion_render_pass_id_, output_rect,
- root_render_pass->damage_rect,
- root_render_pass->transform_to_root_target);
- color_conversion_pass->has_transparent_background =
- root_render_pass->has_transparent_background;
- color_conversion_pass->content_color_usage = root_content_color_usage_;
- color_conversion_pass->is_color_conversion_pass = true;
+ AddRenderPassHelper(color_conversion_render_pass_id_, output_rect,
+ root_render_pass->damage_rect, root_content_color_usage_,
+ root_render_pass->has_transparent_background,
+ /*pass_is_color_conversion_pass=*/true,
+ /*quad_state_to_target_transform=*/gfx::Transform(),
+ /*quad_state_contents_opaque=*/false, SkBlendMode::kSrc,
+ root_render_pass->id);
+}
- auto* shared_quad_state =
- color_conversion_pass->CreateAndAppendSharedQuadState();
- // Do NOT set blend mode here to SkBlendMode::kSrcOver, which will cause
- // blending with empty (black) root pass when child pass has alpha.
- shared_quad_state->SetAll(
- /*quad_to_target_transform=*/gfx::Transform(),
- /*quad_layer_rect=*/output_rect,
- /*visible_layer_rect=*/output_rect,
- /*mask_filter_info=*/gfx::MaskFilterInfo(),
- /*clip_rect=*/absl::nullopt, /*are_contents_opaque=*/false,
- /*opacity=*/1.f,
- /*blend_mode=*/SkBlendMode::kSrc, /*sorting_context_id=*/0);
-
- auto* quad = color_conversion_pass
- ->CreateAndAppendDrawQuad<AggregatedRenderPassDrawQuad>();
- quad->SetNew(shared_quad_state, output_rect, output_rect,
- root_render_pass->id, kInvalidResourceId, gfx::RectF(),
- gfx::Size(), gfx::Vector2dF(), gfx::PointF(),
- gfx::RectF(output_rect),
- /*force_anti_aliasing_off=*/false,
- /*backdrop_filter_quality*/ 1.0f);
- dest_pass_list_->push_back(std::move(color_conversion_pass));
+void SurfaceAggregator::AddRootReadbackPass() {
+ if (extra_pass_for_readback_option_ == ExtraPassForReadbackOption::kNone) {
+ return;
+ }
+
+ auto* root_render_pass = dest_pass_list_->back().get();
+ gfx::Rect output_rect = root_render_pass->output_rect;
+ CHECK(root_render_pass->transform_to_root_target == gfx::Transform());
+ bool needs_readback_pass = false;
+ // Check if there are any render passes that draw into the root pass with
+ // a backdrop filter.
+ base::flat_set<AggregatedRenderPassId> pass_ids_drawing_to_root;
+ for (auto* quad : root_render_pass->quad_list) {
+ if (quad->material != DrawQuad::Material::kAggregatedRenderPass)
+ continue;
+ pass_ids_drawing_to_root.insert(
+ AggregatedRenderPassDrawQuad::MaterialCast(quad)->render_pass_id);
+ }
+ if (!pass_ids_drawing_to_root.empty()) {
+ for (auto& render_pass : *dest_pass_list_) {
+ if (!pass_ids_drawing_to_root.contains(render_pass->id))
+ continue;
+ if (!render_pass->backdrop_filters.IsEmpty()) {
+ needs_readback_pass = true;
+ break;
+ }
+ }
+ }
+
+ if (extra_pass_for_readback_option_ ==
+ ExtraPassForReadbackOption::kAlwaysAddPass) {
+ needs_readback_pass = true;
+ }
+
+ if (needs_readback_pass != last_frame_had_readback_pass_)
+ root_render_pass->damage_rect = output_rect;
+
+ last_frame_had_readback_pass_ = needs_readback_pass;
+ if (!last_frame_had_readback_pass_)
+ return;
+
+ if (!readback_render_pass_id_) {
+ readback_render_pass_id_ = render_pass_id_generator_.GenerateNextId();
+ }
+
+ // Ensure the root-that's-non-root pass is cleared to fully transparent first.
+ bool has_transparent_background =
+ root_render_pass->has_transparent_background;
+ root_render_pass->has_transparent_background = true;
+ AddRenderPassHelper(readback_render_pass_id_, output_rect,
+ root_render_pass->damage_rect, root_content_color_usage_,
+ has_transparent_background,
+ /*pass_is_color_conversion_pass=*/false,
+ /*quad_state_to_target_transform=*/gfx::Transform(),
+ /*quad_state_contents_opaque=*/false,
+ SkBlendMode::kSrcOver, root_render_pass->id);
}
void SurfaceAggregator::AddDisplayTransformPass() {
@@ -1042,29 +1132,12 @@ void SurfaceAggregator::AddDisplayTransformPass() {
return;
auto* root_render_pass = dest_pass_list_->back().get();
- gfx::Rect output_rect = root_render_pass->output_rect;
DCHECK(root_render_pass->transform_to_root_target == root_surface_transform_);
- if (!display_transform_render_pass_id_)
+ if (!display_transform_render_pass_id_) {
display_transform_render_pass_id_ =
render_pass_id_generator_.GenerateNextId();
-
- auto display_transform_pass = std::make_unique<AggregatedRenderPass>(1, 1);
- display_transform_pass->SetAll(
- display_transform_render_pass_id_,
- cc::MathUtil::MapEnclosedRectWith2dAxisAlignedTransform(
- root_surface_transform_, root_render_pass->output_rect),
- cc::MathUtil::MapEnclosedRectWith2dAxisAlignedTransform(
- root_surface_transform_, root_render_pass->damage_rect),
- gfx::Transform(),
- /*filters=*/cc::FilterOperations(),
- /*backdrop_filters=*/cc::FilterOperations(),
- /*backdrop_filter_bounds=*/gfx::RRectF(),
- root_render_pass->content_color_usage,
- root_render_pass->has_transparent_background,
- /*cache_render_pass=*/false,
- /*has_damage_from_contributing_content=*/false,
- /*generate_mipmap=*/false);
+ }
bool are_contents_opaque = true;
for (const auto* sqs : root_render_pass->shared_quad_state_list) {
@@ -1074,25 +1147,59 @@ void SurfaceAggregator::AddDisplayTransformPass() {
}
}
- auto* shared_quad_state =
- display_transform_pass->CreateAndAppendSharedQuadState();
+ AddRenderPassHelper(
+ display_transform_render_pass_id_,
+ cc::MathUtil::MapEnclosedRectWith2dAxisAlignedTransform(
+ root_surface_transform_, root_render_pass->output_rect),
+ cc::MathUtil::MapEnclosedRectWith2dAxisAlignedTransform(
+ root_surface_transform_, root_render_pass->damage_rect),
+ root_render_pass->content_color_usage,
+ root_render_pass->has_transparent_background,
+ /*pass_is_color_conversion_pass=*/false, root_surface_transform_,
+ are_contents_opaque, SkBlendMode::kSrcOver, root_render_pass->id);
+}
+
+void SurfaceAggregator::AddRenderPassHelper(
+ AggregatedRenderPassId render_pass_id,
+ const gfx::Rect& render_pass_output_rect,
+ const gfx::Rect& render_pass_damage_rect,
+ gfx::ContentColorUsage pass_color_usage,
+ bool pass_has_transparent_background,
+ bool pass_is_color_conversion_pass,
+ const gfx::Transform& quad_state_to_target_transform,
+ bool quad_state_contents_opaque,
+ SkBlendMode quad_state_blend_mode,
+ AggregatedRenderPassId quad_pass_id) {
+ gfx::Rect current_output_rect = dest_pass_list_->back()->output_rect;
+
+ auto render_pass = std::make_unique<AggregatedRenderPass>(1, 1);
+ render_pass->SetAll(render_pass_id, render_pass_output_rect,
+ render_pass_damage_rect, gfx::Transform(),
+ /*filters=*/cc::FilterOperations(),
+ /*backdrop_filters=*/cc::FilterOperations(),
+ /*backdrop_filter_bounds=*/gfx::RRectF(),
+ pass_color_usage, pass_has_transparent_background,
+ /*cache_render_pass=*/false,
+ /*has_damage_from_contributing_content=*/false,
+ /*generate_mipmap=*/false);
+ render_pass->is_color_conversion_pass = pass_is_color_conversion_pass;
+
+ auto* shared_quad_state = render_pass->CreateAndAppendSharedQuadState();
shared_quad_state->SetAll(
- /*quad_to_target_transform=*/root_surface_transform_,
- /*quad_layer_rect=*/output_rect,
- /*visible_layer_rect=*/output_rect,
- /*mask_filter_info=*/gfx::MaskFilterInfo(),
- /*clip_rect=*/absl::nullopt, are_contents_opaque, /*opacity=*/1.f,
- /*blend_mode=*/SkBlendMode::kSrcOver, /*sorting_context_id=*/0);
-
- auto* quad = display_transform_pass
- ->CreateAndAppendDrawQuad<AggregatedRenderPassDrawQuad>();
- quad->SetNew(shared_quad_state, output_rect, output_rect,
- root_render_pass->id, kInvalidResourceId, gfx::RectF(),
- gfx::Size(), gfx::Vector2dF(), gfx::PointF(),
- gfx::RectF(output_rect),
+ quad_state_to_target_transform,
+ /*layer_rect=*/current_output_rect,
+ /*visible_layer_rect=*/current_output_rect, gfx::MaskFilterInfo(),
+ /*clip=*/absl::nullopt, quad_state_contents_opaque, /*opacity_f=*/1.f,
+ quad_state_blend_mode, /*sorting_context=*/0);
+
+ auto* quad =
+ render_pass->CreateAndAppendDrawQuad<AggregatedRenderPassDrawQuad>();
+ quad->SetNew(shared_quad_state, current_output_rect, current_output_rect,
+ quad_pass_id, kInvalidResourceId, gfx::RectF(), gfx::Size(),
+ gfx::Vector2dF(), gfx::PointF(), gfx::RectF(current_output_rect),
/*force_anti_aliasing_off=*/false,
/*backdrop_filter_quality*/ 1.0f);
- dest_pass_list_->push_back(std::move(display_transform_pass));
+ dest_pass_list_->push_back(std::move(render_pass));
}
void SurfaceAggregator::CopyQuadsToPass(
@@ -1102,6 +1209,7 @@ void SurfaceAggregator::CopyQuadsToPass(
float parent_device_scale_factor,
const gfx::Transform& target_transform,
const absl::optional<gfx::Rect>& clip_rect,
+ const absl::optional<gfx::Rect>& dest_root_target_clip_rect,
const Surface* surface,
const MaskFilterInfoExt& parent_mask_filter_info_ext) {
const CompositorRenderPass& source_pass = resolved_pass.render_pass();
@@ -1152,12 +1260,11 @@ void SurfaceAggregator::CopyQuadsToPass(
size_t overlay_damage_index = 0;
const DrawQuad* quad_with_overlay_damage_index = nullptr;
- if (needs_surface_damage_rect_list_) {
- AddRenderPassFilterDamageToDamageList(target_transform, &source_pass,
- dest_pass);
+ if (needs_surface_damage_rect_list_ &&
+ resolved_pass.aggregation().will_draw) {
quad_with_overlay_damage_index =
FindQuadWithOverlayDamage(source_pass, dest_pass, target_transform,
- surface, clip_rect, &overlay_damage_index);
+ surface, &overlay_damage_index);
}
MaskFilterInfoExt new_mask_filter_info_ext = parent_mask_filter_info_ext;
@@ -1188,8 +1295,8 @@ void SurfaceAggregator::CopyQuadsToPass(
}
HandleSurfaceQuad(source_pass, surface_quad, parent_device_scale_factor,
- target_transform, clip_rect, dest_pass,
- ignore_undamaged, &damage_rect_in_quad_space,
+ target_transform, clip_rect, dest_root_target_clip_rect,
+ dest_pass, ignore_undamaged, &damage_rect_in_quad_space,
&damage_rect_in_quad_space_valid,
new_mask_filter_info_ext);
} else {
@@ -1208,14 +1315,16 @@ void SurfaceAggregator::CopyQuadsToPass(
// this |source_pass| will have been added to the
// |surface_damage_rect_list_| before this phase.
if (source_pass.has_per_quad_damage &&
- GetOptionalDamageRectFromQuad(quad).has_value()) {
+ GetOptionalDamageRectFromQuad(quad).has_value() &&
+ resolved_pass.aggregation().will_draw) {
auto damage_rect_in_target_space =
GetOptionalDamageRectFromQuad(quad);
dest_shared_quad_state->overlay_damage_index =
surface_damage_rect_list_->size();
- AddSurfaceDamageToDamageList(damage_rect_in_target_space.value(),
- target_transform, clip_rect, dest_pass,
- /*resolved_frame=*/nullptr);
+ AddSurfaceDamageToDamageList(
+ damage_rect_in_target_space.value(), target_transform,
+ dest_root_target_clip_rect, dest_pass->transform_to_root_target,
+ /*resolved_frame=*/nullptr);
} else if (quad == quad_with_overlay_damage_index) {
dest_shared_quad_state->overlay_damage_index = overlay_damage_index;
}
@@ -1254,6 +1363,13 @@ void SurfaceAggregator::CopyQuadsToPass(
dest_quad = dest_pass->CopyFromAndAppendRenderPassDrawQuad(
pass_quad, remapped_pass_id);
+
+ if (needs_surface_damage_rect_list_ &&
+ resolved_pass.aggregation().will_draw) {
+ AddRenderPassFilterDamageToDamageList(
+ resolved_frame, pass_quad, target_transform,
+ dest_root_target_clip_rect, dest_pass->transform_to_root_target);
+ }
} else if (quad->material == DrawQuad::Material::kTextureContent) {
const auto* texture_quad = TextureDrawQuad::MaterialCast(quad);
if (texture_quad->secure_output_only &&
@@ -1352,15 +1468,18 @@ void SurfaceAggregator::CopyPasses(const ResolvedFrameData& resolved_frame) {
if (needs_surface_damage_rect_list_ && resolved_pass.is_root()) {
AddSurfaceDamageToDamageList(
- /*default_damage_rect=*/gfx::Rect(), surface_transform,
- /*clip_rect=*/{}, copy_pass.get(), &resolved_frame);
+ /*default_damage_rect=*/gfx::Rect(),
+ /*parent_target_transform=*/surface_transform,
+ /*dest_root_target_clip_rect=*/{},
+ copy_pass->transform_to_root_target, &resolved_frame);
}
CopyQuadsToPass(resolved_frame, resolved_pass, copy_pass.get(),
frame.device_scale_factor(),
apply_surface_transform_to_root_pass ? surface_transform
: gfx::Transform(),
- {}, surface, MaskFilterInfoExt());
+ {}, /*dest_root_target_clip_rect=*/{}, surface,
+ MaskFilterInfoExt());
// If the render pass has copy requests, or should be cached, or has
// moving-pixel filters, or in a moving-pixel surface, we should damage the
@@ -1394,7 +1513,6 @@ void SurfaceAggregator::ProcessAddedAndRemovedSurfaces() {
gfx::Rect SurfaceAggregator::PrewalkRenderPass(
ResolvedFrameData& resolved_frame,
ResolvedPassData& resolved_pass,
- bool will_draw,
const gfx::Rect& damage_from_parent,
const gfx::Transform& target_to_root_transform,
const ResolvedPassData* parent_pass,
@@ -1405,6 +1523,9 @@ gfx::Rect SurfaceAggregator::PrewalkRenderPass(
has_pixel_moving_backdrop_filter_ = true;
}
+ if (parent_pass && parent_pass->aggregation().will_draw)
+ resolved_pass.aggregation().will_draw = true;
+
// Populate state for about cached render passes and pixel moving filters.
// These attributes apply transitively to all child render passes embedded by
// the CompositorRenderPass with the attribute.
@@ -1507,7 +1628,7 @@ gfx::Rect SurfaceAggregator::PrewalkRenderPass(
}
}
gfx::Rect child_rect =
- PrewalkSurface(*child_resolved_frame, &resolved_pass, will_draw,
+ PrewalkSurface(*child_resolved_frame, &resolved_pass,
accumulated_damage_in_child_space, result);
child_rect = gfx::ScaleToEnclosingRect(child_rect, x_scale, y_scale);
quad_damage_rect.Union(child_rect);
@@ -1596,9 +1717,9 @@ gfx::Rect SurfaceAggregator::PrewalkRenderPass(
const gfx::Transform child_to_root_transform(
target_to_root_transform,
quad->shared_quad_state->quad_to_target_transform);
- quad_damage_rect = PrewalkRenderPass(
- resolved_frame, child_resolved_pass, will_draw, gfx::Rect(),
- child_to_root_transform, &resolved_pass, result);
+ quad_damage_rect =
+ PrewalkRenderPass(resolved_frame, child_resolved_pass, gfx::Rect(),
+ child_to_root_transform, &resolved_pass, result);
if (child_resolved_pass.aggregation()
.has_damage_from_contributing_content) {
@@ -1690,12 +1811,10 @@ bool SurfaceAggregator::CheckFrameSinksChanged(const Surface* surface) {
gfx::Rect SurfaceAggregator::PrewalkSurface(ResolvedFrameData& resolved_frame,
ResolvedPassData* parent_pass,
- bool will_draw,
const gfx::Rect& damage_from_parent,
PrewalkResult& result) {
Surface* surface = resolved_frame.surface();
DCHECK(surface->HasActiveFrame());
- DebugLogSurface(surface, will_draw);
if (referenced_surfaces_.count(surface->surface_id()))
return gfx::Rect();
@@ -1704,6 +1823,8 @@ gfx::Rect SurfaceAggregator::PrewalkSurface(ResolvedFrameData& resolved_frame,
if (!resolved_frame.is_valid())
return gfx::Rect();
+
+ DebugLogSurface(surface, resolved_frame.WillDraw());
++stats_->prewalked_surface_count;
auto& root_resolved_pass = resolved_frame.GetRootRenderPassData();
@@ -1718,8 +1839,8 @@ gfx::Rect SurfaceAggregator::PrewalkSurface(ResolvedFrameData& resolved_frame,
referenced_surfaces_.insert(surface->surface_id());
damage_rect.Union(PrewalkRenderPass(resolved_frame, root_resolved_pass,
- will_draw, damage_from_parent,
- gfx::Transform(), parent_pass, result));
+ damage_from_parent, gfx::Transform(),
+ parent_pass, result));
// If this surface has damage from contributing content, then the render pass
// embedding this surface does as well.
@@ -1760,7 +1881,7 @@ gfx::Rect SurfaceAggregator::PrewalkSurface(ResolvedFrameData& resolved_frame,
if (de_jelly_enabled_ && surface->HasUndrawnActiveFrame())
new_surfaces_.insert(surface->surface_id());
- if (will_draw)
+ if (root_resolved_pass.aggregation().will_draw)
surface->OnWillBeDrawn();
const CompositorFrame& frame = surface->GetActiveOrInterpolatedFrame();
@@ -1778,8 +1899,8 @@ gfx::Rect SurfaceAggregator::PrewalkSurface(ResolvedFrameData& resolved_frame,
result.undrawn_surfaces.insert(surface_id);
ResolvedFrameData* undrawn_surface = GetResolvedFrame(surface_id);
if (undrawn_surface) {
- PrewalkSurface(*undrawn_surface, /*parent_pass=*/nullptr,
- /*will_draw=*/false, gfx::Rect(), result);
+ PrewalkSurface(*undrawn_surface, /*parent_pass=*/nullptr, gfx::Rect(),
+ result);
}
}
}
@@ -1869,12 +1990,16 @@ AggregatedFrame SurfaceAggregator::Aggregate(
CheckFrameSinksChanged(surface);
- if (!surface->HasActiveFrame())
- return {};
-
// Start recording new stats for this aggregation.
stats_.emplace();
+ base::ElapsedTimer prewalk_timer;
+ ResolvedFrameData* resolved_frame =
+ GetResolvedFrame(surface, /*inside_aggregation=*/true);
+
+ if (!resolved_frame || !resolved_frame->is_valid())
+ return {};
+
display_trace_id_ = display_trace_id;
expected_display_time_ = expected_display_time;
@@ -1907,16 +2032,14 @@ AggregatedFrame SurfaceAggregator::Aggregate(
DCHECK(referenced_surfaces_.empty());
- base::ElapsedTimer prewalk_timer;
+ // The root surface root render pass is the start of the embedding tree.
+ resolved_frame->GetRootRenderPassData().aggregation().will_draw = true;
+
PrewalkResult prewalk_result;
- // Get the resolved frame for the root surface after `prewalk_timer` is
- // started so the work is counted in the same histograms as before.
- ResolvedFrameData& resolved_frame =
- *GetResolvedFrame(surface, /*inside_aggregation=*/true);
- gfx::Rect prewalk_damage_rect = PrewalkSurface(
- resolved_frame,
- /*parent_pass=*/nullptr,
- /*will_draw=*/true, /*damage_from_parent=*/gfx::Rect(), prewalk_result);
+ gfx::Rect prewalk_damage_rect =
+ PrewalkSurface(*resolved_frame,
+ /*parent_pass=*/nullptr,
+ /*damage_from_parent=*/gfx::Rect(), prewalk_result);
stats_->prewalk_time = prewalk_timer.Elapsed();
root_damage_rect_ = prewalk_damage_rect;
@@ -1947,7 +2070,7 @@ AggregatedFrame SurfaceAggregator::Aggregate(
base::ElapsedTimer copy_timer;
CopyUndrawnSurfaces(&prewalk_result);
referenced_surfaces_.insert(surface_id);
- CopyPasses(resolved_frame);
+ CopyPasses(*resolved_frame);
referenced_surfaces_.erase(surface_id);
DCHECK(referenced_surfaces_.empty());
stats_->copy_time = copy_timer.Elapsed();
@@ -1971,7 +2094,7 @@ AggregatedFrame SurfaceAggregator::Aggregate(
auto* last_pass = dest_pass_list_->back().get();
if (!color_usage_changed && !last_frame_had_delegated_ink_ &&
- !RenderPassNeedsFullDamage(resolved_frame.GetRootRenderPassData())) {
+ !RenderPassNeedsFullDamage(resolved_frame->GetRootRenderPassData())) {
last_pass->damage_rect.Intersect(prewalk_damage_rect);
}
@@ -1981,6 +2104,7 @@ AggregatedFrame SurfaceAggregator::Aggregate(
HandleDeJelly(surface);
AddColorConversionPass();
+ AddRootReadbackPass();
ProcessAddedAndRemovedSurfaces();
contained_surfaces_.swap(previous_contained_surfaces_);
diff --git a/chromium/components/viz/service/display/surface_aggregator.h b/chromium/components/viz/service/display/surface_aggregator.h
index 5a2475ec9b1..4ca7c473a93 100644
--- a/chromium/components/viz/service/display/surface_aggregator.h
+++ b/chromium/components/viz/service/display/surface_aggregator.h
@@ -41,6 +41,18 @@ class VIZ_SERVICE_EXPORT SurfaceAggregator {
using SurfaceIndexMap = base::flat_map<SurfaceId, uint64_t>;
using FrameSinkIdMap = base::flat_map<FrameSinkId, LocalSurfaceId>;
+ // To control when to add an extra render pass to avoid readback from the
+ // root render pass. This is useful for root pass drawing to vulkan secondary
+ // command buffer, which does not support readback.
+ enum class ExtraPassForReadbackOption {
+ // No special handling needed.
+ kNone,
+ // Add an extra render pass only if readback is needed.
+ kAddPassForReadback,
+ // Always add an extra pass. Useful for debugging.
+ kAlwaysAddPass,
+ };
+
// Interface that can modify the aggregated CompositorFrame to annotate it.
// For example it could add extra quads.
class FrameAnnotator {
@@ -53,7 +65,9 @@ class VIZ_SERVICE_EXPORT SurfaceAggregator {
SurfaceAggregator(SurfaceManager* manager,
DisplayResourceProvider* provider,
bool aggregate_only_damaged,
- bool needs_surface_damage_rect_list);
+ bool needs_surface_damage_rect_list,
+ ExtraPassForReadbackOption extra_pass_option =
+ ExtraPassForReadbackOption::kNone);
SurfaceAggregator(const SurfaceAggregator&) = delete;
SurfaceAggregator& operator=(const SurfaceAggregator&) = delete;
@@ -133,27 +147,35 @@ class VIZ_SERVICE_EXPORT SurfaceAggregator {
// |source_pass| to |dest_pass|.
// - |added_clip_rect| is an added clip rect in the |dest_pass| coordinate
// space.
- void HandleSurfaceQuad(const CompositorRenderPass& source_pass,
- const SurfaceDrawQuad* surface_quad,
- float parent_device_scale_factor,
- const gfx::Transform& target_transform,
- const absl::optional<gfx::Rect>& added_clip_rect,
- AggregatedRenderPass* dest_pass,
- bool ignore_undamaged,
- gfx::Rect* damage_rect_in_quad_space,
- bool* damage_rect_in_quad_space_valid,
- const MaskFilterInfoExt& mask_filter_info_pair);
-
- void EmitSurfaceContent(const ResolvedFrameData& resolved_frame,
- float parent_device_scale_factor,
- const SurfaceDrawQuad* surface_quad,
- const gfx::Transform& target_transform,
- const absl::optional<gfx::Rect>& added_clip_rect,
- AggregatedRenderPass* dest_pass,
- bool ignore_undamaged,
- gfx::Rect* damage_rect_in_quad_space,
- bool* damage_rect_in_quad_space_valid,
- const MaskFilterInfoExt& mask_filter_info_pair);
+ // - |dest_root_target_clip_rect| is on the root render pass space of the root
+ // surface, the same coordinate space as |root_damage_rect_|. This is only
+ // used for SurfaceDamageRectList computation and should not be used for
+ // Clipping quads.
+ void HandleSurfaceQuad(
+ const CompositorRenderPass& source_pass,
+ const SurfaceDrawQuad* surface_quad,
+ float parent_device_scale_factor,
+ const gfx::Transform& target_transform,
+ const absl::optional<gfx::Rect>& added_clip_rect,
+ const absl::optional<gfx::Rect>& dest_root_target_clip_rect,
+ AggregatedRenderPass* dest_pass,
+ bool ignore_undamaged,
+ gfx::Rect* damage_rect_in_quad_space,
+ bool* damage_rect_in_quad_space_valid,
+ const MaskFilterInfoExt& mask_filter_info_pair);
+
+ void EmitSurfaceContent(
+ const ResolvedFrameData& resolved_frame,
+ float parent_device_scale_factor,
+ const SurfaceDrawQuad* surface_quad,
+ const gfx::Transform& target_transform,
+ const absl::optional<gfx::Rect>& added_clip_rect,
+ const absl::optional<gfx::Rect>& dest_root_target_clip_rect,
+ AggregatedRenderPass* dest_pass,
+ bool ignore_undamaged,
+ gfx::Rect* damage_rect_in_quad_space,
+ bool* damage_rect_in_quad_space_valid,
+ const MaskFilterInfoExt& mask_filter_info_pair);
void EmitDefaultBackgroundColorQuad(
const SurfaceDrawQuad* surface_quad,
@@ -172,14 +194,16 @@ class VIZ_SERVICE_EXPORT SurfaceAggregator {
AggregatedRenderPass* dest_pass,
const MaskFilterInfoExt& mask_filter_info_pair);
- void CopyQuadsToPass(const ResolvedFrameData& resolved_frame,
- const ResolvedPassData& resolved_pass,
- AggregatedRenderPass* dest_pass,
- float parent_device_scale_factor,
- const gfx::Transform& target_transform,
- const absl::optional<gfx::Rect>& clip_rect,
- const Surface* surface,
- const MaskFilterInfoExt& mask_filter_info_pair);
+ void CopyQuadsToPass(
+ const ResolvedFrameData& resolved_frame,
+ const ResolvedPassData& resolved_pass,
+ AggregatedRenderPass* dest_pass,
+ float parent_device_scale_factor,
+ const gfx::Transform& target_transform,
+ const absl::optional<gfx::Rect>& clip_rect,
+ const absl::optional<gfx::Rect>& dest_root_target_clip_rect,
+ const Surface* surface,
+ const MaskFilterInfoExt& mask_filter_info_pair);
// Recursively walks through the render pass and updates the
// |intersects_damage_under| flag on all RenderPassDrawQuads(RPDQ).
@@ -190,10 +214,6 @@ class VIZ_SERVICE_EXPORT SurfaceAggregator {
// render pass to be walked.
// - |render_pass_map| is a map that contains all render passes and their
// entry data.
- // - |will_draw| indicates that the surface can be aggregated into the final
- // frame and might be drawn (based on damage/occlusion/etc.) if it is set
- // to true. Or the surface isn't in the aggregated frame and is only
- // needed for CopyOutputRequests if set to false.
// - |damage_from_parent| is the damage rect passed along from parent or
// a chain of ancestor render passes, transformed into the local space of
// the current render pass. This happens when the root render
@@ -212,7 +232,6 @@ class VIZ_SERVICE_EXPORT SurfaceAggregator {
// render pass.
gfx::Rect PrewalkRenderPass(ResolvedFrameData& resolved_frame,
ResolvedPassData& resolved_pass,
- bool will_draw,
const gfx::Rect& damage_from_parent,
const gfx::Transform& target_to_root_transform,
const ResolvedPassData* parent_pass,
@@ -223,7 +242,6 @@ class VIZ_SERVICE_EXPORT SurfaceAggregator {
// and return the combined damage rect.
gfx::Rect PrewalkSurface(ResolvedFrameData& resolved_frame,
ResolvedPassData* parent_pass,
- bool will_draw,
const gfx::Rect& damage_from_parent,
PrewalkResult& result);
@@ -236,7 +254,18 @@ class VIZ_SERVICE_EXPORT SurfaceAggregator {
void CopyUndrawnSurfaces(PrewalkResult* prewalk);
void CopyPasses(const ResolvedFrameData& resolved_frame);
void AddColorConversionPass();
+ void AddRootReadbackPass();
void AddDisplayTransformPass();
+ void AddRenderPassHelper(AggregatedRenderPassId render_pass_id,
+ const gfx::Rect& render_pass_output_rect,
+ const gfx::Rect& render_pass_damage_rect,
+ gfx::ContentColorUsage pass_color_usage,
+ bool pass_has_transparent_background,
+ bool pass_is_color_conversion_pass,
+ const gfx::Transform& quad_state_to_target_transform,
+ bool quad_state_contents_opaque,
+ SkBlendMode quad_state_blend_mode,
+ AggregatedRenderPassId quad_pass_id);
// Remove Surfaces that were referenced before but aren't currently
// referenced from the ResourceProvider.
@@ -252,10 +281,13 @@ class VIZ_SERVICE_EXPORT SurfaceAggregator {
gfx::Rect DamageRectForSurface(const ResolvedFrameData& resolved_frame,
bool include_per_quad_damage) const;
- // This function adds a damage rect to |surface_damage_rect_list_|. The damage
- // rect will come from |resolved_frame| if provided otherwise
+ // This function adds a damage rect to |surface_damage_rect_list_|. The
+ // surface damage rect comes from |resolved_frame| if provided, otherwise
// |default_damage_rect| will be used.
//
+ // |dest_root_target_clip_rect| is on the root render pass space of the root
+ // surface, the same coordinate space as |root_damage_rect_|.
+ //
// |surface_damage_rect_list_| is different from the |root_damage_rect_| which
// is the union of all surface damages. This function records per-surface
// damage rects to |surface_damage_rect_list_| in a top-to-bottom order and is
@@ -263,14 +295,16 @@ class VIZ_SERVICE_EXPORT SurfaceAggregator {
void AddSurfaceDamageToDamageList(
const gfx::Rect& default_damage_rect,
const gfx::Transform& parent_target_transform,
- const absl::optional<gfx::Rect>& clip_rect,
- AggregatedRenderPass* dest_pass,
+ const absl::optional<gfx::Rect>& dest_root_target_clip_rect,
+ const gfx::Transform& dest_transform_to_root_target,
const ResolvedFrameData* resolved_frame);
void AddRenderPassFilterDamageToDamageList(
+ const ResolvedFrameData& resolved_frame,
+ const CompositorRenderPassDrawQuad* render_pass_quad,
const gfx::Transform& parent_target_transform,
- const CompositorRenderPass* source_pass,
- AggregatedRenderPass* dest_pass);
+ const absl::optional<gfx::Rect>& dest_root_target_clip_rect,
+ const gfx::Transform& dest_transform_to_root_target);
// Determine the overlay damage and location in the surface damage list.
const DrawQuad* FindQuadWithOverlayDamage(
@@ -278,7 +312,6 @@ class VIZ_SERVICE_EXPORT SurfaceAggregator {
AggregatedRenderPass* dest_pass,
const gfx::Transform& parent_target_transform,
const Surface* surface,
- const absl::optional<gfx::Rect>& clip_rect,
size_t* overlay_damage_index);
bool IsRootSurface(const Surface* surface) const;
@@ -354,6 +387,8 @@ class VIZ_SERVICE_EXPORT SurfaceAggregator {
const bool clip_prewalk_damage_;
+ const ExtraPassForReadbackOption extra_pass_for_readback_option_;
+
bool output_is_secure_ = false;
// Whether |CopyOutputRequests| should be moved over to the aggregated frame.
@@ -369,6 +404,8 @@ class VIZ_SERVICE_EXPORT SurfaceAggregator {
int max_render_target_size_ = 0;
// The id for the final color conversion render pass.
AggregatedRenderPassId color_conversion_render_pass_id_;
+ // The id for the extra pass added to avoid readback from root pass.
+ AggregatedRenderPassId readback_render_pass_id_;
// The id for the optional render pass used to apply the display transform.
AggregatedRenderPassId display_transform_render_pass_id_;
@@ -444,6 +481,9 @@ class VIZ_SERVICE_EXPORT SurfaceAggregator {
// Whether the last drawn frame had a color conversion pass applied. Used in
// production on Windows only (does not interact with jelly).
bool last_frame_had_color_conversion_pass_ = false;
+ // Whether last frame had an extra render pass added to avoid readback from
+ // root frame buffer.
+ bool last_frame_had_readback_pass_ = false;
// The metadata used for drawing a delegated ink trail on the end of a normal
// ink stroke. It needs to be transformed to root coordinates and then put on
diff --git a/chromium/components/viz/service/display/surface_aggregator_pixeltest.cc b/chromium/components/viz/service/display/surface_aggregator_pixeltest.cc
index bbe861f4004..07e18febf5c 100644
--- a/chromium/components/viz/service/display/surface_aggregator_pixeltest.cc
+++ b/chromium/components/viz/service/display/surface_aggregator_pixeltest.cc
@@ -23,7 +23,7 @@
#include "components/viz/test/compositor_frame_helpers.h"
#include "testing/gtest/include/gtest/gtest.h"
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
namespace viz {
namespace {
@@ -408,4 +408,4 @@ TEST_P(SurfaceAggregatorPixelTest, DrawAndEraseDelegatedInkTrail) {
} // namespace
} // namespace viz
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
diff --git a/chromium/components/viz/service/display/surface_aggregator_unittest.cc b/chromium/components/viz/service/display/surface_aggregator_unittest.cc
index cc336bb54ae..3cc554c7f66 100644
--- a/chromium/components/viz/service/display/surface_aggregator_unittest.cc
+++ b/chromium/components/viz/service/display/surface_aggregator_unittest.cc
@@ -20,6 +20,7 @@
#include "base/memory/weak_ptr.h"
#include "base/strings/stringprintf.h"
#include "base/time/time.h"
+#include "cc/base/math_util.h"
#include "cc/test/render_pass_test_utils.h"
#include "components/viz/common/frame_sinks/begin_frame_args.h"
#include "components/viz/common/quads/aggregated_render_pass.h"
@@ -116,7 +117,9 @@ class DisplayTimeSource {
class SurfaceAggregatorTest : public testing::Test, public DisplayTimeSource {
public:
- explicit SurfaceAggregatorTest(bool use_damage_rect)
+ explicit SurfaceAggregatorTest(
+ bool use_damage_rect,
+ SurfaceAggregator::ExtraPassForReadbackOption extra_pass_option)
: root_sink_(std::make_unique<CompositorFrameSinkSupport>(
&fake_client_,
&manager_,
@@ -125,11 +128,15 @@ class SurfaceAggregatorTest : public testing::Test, public DisplayTimeSource {
aggregator_(manager_.surface_manager(),
&resource_provider_,
use_damage_rect,
- true) {
+ true,
+ extra_pass_option) {
manager_.surface_manager()->AddObserver(&observer_);
}
- SurfaceAggregatorTest() : SurfaceAggregatorTest(false) {}
+ SurfaceAggregatorTest()
+ : SurfaceAggregatorTest(
+ false,
+ SurfaceAggregator::ExtraPassForReadbackOption::kNone) {}
void TearDown() override {
observer_.Reset();
@@ -486,8 +493,10 @@ class SurfaceAggregatorTest : public testing::Test, public DisplayTimeSource {
class SurfaceAggregatorValidSurfaceTest : public SurfaceAggregatorTest {
public:
- explicit SurfaceAggregatorValidSurfaceTest(bool use_damage_rect)
- : SurfaceAggregatorTest(use_damage_rect),
+ SurfaceAggregatorValidSurfaceTest(
+ bool use_damage_rect,
+ SurfaceAggregator::ExtraPassForReadbackOption extra_pass_option)
+ : SurfaceAggregatorTest(use_damage_rect, extra_pass_option),
child_sink_(std::make_unique<CompositorFrameSinkSupport>(
nullptr,
&manager_,
@@ -497,6 +506,11 @@ class SurfaceAggregatorValidSurfaceTest : public SurfaceAggregatorTest {
child_sink_->set_allow_copy_output_requests_for_testing();
}
+ explicit SurfaceAggregatorValidSurfaceTest(bool use_damage_rect)
+ : SurfaceAggregatorValidSurfaceTest(
+ use_damage_rect,
+ SurfaceAggregator::ExtraPassForReadbackOption::kNone) {}
+
SurfaceAggregatorValidSurfaceTest()
: SurfaceAggregatorValidSurfaceTest(false) {}
@@ -5650,7 +5664,10 @@ TEST_F(SurfaceAggregatorPartialSwapTest, ExpandByTargetDamage) {
class SurfaceAggregatorWithResourcesTest : public SurfaceAggregatorTest {
public:
- SurfaceAggregatorWithResourcesTest() : SurfaceAggregatorTest(false) {
+ SurfaceAggregatorWithResourcesTest()
+ : SurfaceAggregatorTest(
+ false,
+ SurfaceAggregator::ExtraPassForReadbackOption::kNone) {
// BuildCompositorFrameWithResources() sets secure_output_only=true on
// TextureDrawQuads so this will ensure they aren't dropped from the
// AggregatedFrame.
@@ -5990,7 +6007,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, ColorSpaceTestWin) {
display_color_spaces.SetOutputColorSpaceAndBufferFormat(
gfx::ContentColorUsage::kWideColorGamut, false /* needs_alpha */,
gfx::ColorSpace(gfx::ColorSpace::PrimaryID::BT2020,
- gfx::ColorSpace::TransferID::IEC61966_2_1),
+ gfx::ColorSpace::TransferID::SRGB),
gfx::BufferFormat::RGBA_8888);
display_color_spaces.SetOutputColorSpaceAndBufferFormat(
gfx::ContentColorUsage::kWideColorGamut, true /* needs_alpha */,
@@ -6075,7 +6092,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, ColorSpaceTestWin) {
display_color_spaces.SetOutputColorSpaceAndBufferFormat(
gfx::ContentColorUsage::kHDR, false /* needs_alpha */,
gfx::ColorSpace(gfx::ColorSpace::PrimaryID::BT2020,
- gfx::ColorSpace::TransferID::IEC61966_2_1),
+ gfx::ColorSpace::TransferID::SRGB),
gfx::BufferFormat::BGRA_1010102);
display_color_spaces.SetOutputColorSpaceAndBufferFormat(
gfx::ContentColorUsage::kHDR, true /* needs_alpha */,
@@ -9107,13 +9124,13 @@ TEST_F(SurfaceAggregatorWithResourcesTest, TransitionDirectiveFrameBehind) {
{
auto frame = BuildCompositorFrameWithResources({}, true, SurfaceId());
frame.metadata.transition_directives.emplace_back(
- 1, CompositorFrameTransitionDirective::Type::kSave,
+ 1, CompositorFrameTransitionDirective::Type::kSave, false,
CompositorFrameTransitionDirective::Effect::kCoverLeft);
root_sink_->SubmitCompositorFrame(local_surface_id, std::move(frame));
- auto* surface = root_sink_->GetLastCreatedSurfaceForTesting();
- ASSERT_TRUE(surface);
- surface->GetSurfaceSavedFrameStorage()->CompleteForTesting();
+ root_sink_->GetSurfaceAnimationManagerForTesting()
+ ->GetSurfaceSavedFrameStorageForTesting()
+ ->CompleteForTesting();
}
AggregateFrame(surface_id);
@@ -9122,7 +9139,7 @@ TEST_F(SurfaceAggregatorWithResourcesTest, TransitionDirectiveFrameBehind) {
{
auto frame = BuildCompositorFrameWithResources({}, true, SurfaceId());
frame.metadata.transition_directives.emplace_back(
- 2, CompositorFrameTransitionDirective::Type::kAnimate);
+ 2, CompositorFrameTransitionDirective::Type::kAnimate, false);
root_sink_->SubmitCompositorFrame(local_surface_id, std::move(frame));
}
AggregateFrame(surface_id);
@@ -9182,4 +9199,59 @@ TEST_F(SurfaceAggregatorWithResourcesTest, TransitionDirectiveFrameBehind) {
INSTANTIATE_TEST_SUITE_P(,
SurfaceAggregatorValidSurfaceWithMergingPassesTest,
testing::Bool());
+
+class SurfaceAggregatorVulkanSecondaryCB
+ : public SurfaceAggregatorValidSurfaceTest {
+ public:
+ SurfaceAggregatorVulkanSecondaryCB()
+ : SurfaceAggregatorValidSurfaceTest(
+ false,
+ SurfaceAggregator::ExtraPassForReadbackOption::
+ kAddPassForReadback) {}
+};
+
+TEST_F(SurfaceAggregatorVulkanSecondaryCB, AppendPassForFrameWithFilter) {
+ CompositorFrame frame =
+ CompositorFrameBuilder()
+ .AddRenderPass(
+ RenderPassBuilder(CompositorRenderPassId{1}, kSurfaceSize)
+ .AddSolidColorQuad(gfx::Rect(5, 5), SK_ColorGREEN)
+ .AddBackdropFilter(cc::FilterOperation::CreateBlurFilter(5)))
+ .AddRenderPass(
+ RenderPassBuilder(CompositorRenderPassId{2}, kSurfaceSize)
+ .AddRenderPassQuad(gfx::Rect(kSurfaceSize),
+ CompositorRenderPassId{1}))
+ .Build();
+
+ root_sink_->SubmitCompositorFrame(root_surface_id_.local_surface_id(),
+ std::move(frame));
+
+ SurfaceId surface_id(root_sink_->frame_sink_id(),
+ root_surface_id_.local_surface_id());
+ auto aggregated_frame = AggregateFrame(surface_id);
+ EXPECT_EQ(3u, aggregated_frame.render_pass_list.size());
+}
+
+TEST_F(SurfaceAggregatorVulkanSecondaryCB,
+ DoNotAppendPassForFrameWithoutReadback) {
+ CompositorFrame frame =
+ CompositorFrameBuilder()
+ .AddRenderPass(
+ RenderPassBuilder(CompositorRenderPassId{1}, kSurfaceSize)
+ .AddSolidColorQuad(gfx::Rect(5, 5), SK_ColorGREEN))
+ .AddRenderPass(
+ RenderPassBuilder(CompositorRenderPassId{2}, kSurfaceSize)
+ .AddRenderPassQuad(gfx::Rect(kSurfaceSize),
+ CompositorRenderPassId{1}))
+ .Build();
+
+ root_sink_->SubmitCompositorFrame(root_surface_id_.local_surface_id(),
+ std::move(frame));
+
+ SurfaceId surface_id(root_sink_->frame_sink_id(),
+ root_surface_id_.local_surface_id());
+ auto aggregated_frame = AggregateFrame(surface_id);
+ EXPECT_EQ(2u, aggregated_frame.render_pass_list.size());
+}
+
} // namespace viz
diff --git a/chromium/components/viz/service/display_embedder/DEPS b/chromium/components/viz/service/display_embedder/DEPS
index f50d8999335..4988c8b24d6 100644
--- a/chromium/components/viz/service/display_embedder/DEPS
+++ b/chromium/components/viz/service/display_embedder/DEPS
@@ -31,7 +31,7 @@ include_rules = [
"+mojo/public/cpp/bindings",
"+mojo/public/cpp/system",
"+skia",
- "+third_party/dawn/src/include",
+ "+third_party/dawn/include",
"+third_party/khronos/GLES2/gl2.h",
"+third_party/khronos/GLES2/gl2ext.h",
"+third_party/libyuv",
diff --git a/chromium/components/viz/service/display_embedder/buffer_queue.cc b/chromium/components/viz/service/display_embedder/buffer_queue.cc
index 7144dc36fab..ef0c294b3da 100644
--- a/chromium/components/viz/service/display_embedder/buffer_queue.cc
+++ b/chromium/components/viz/service/display_embedder/buffer_queue.cc
@@ -82,7 +82,7 @@ bool BufferQueue::Reshape(const gfx::Size& size,
if (size == size_ && color_space == color_space_ && format == format_)
return false;
-#if !defined(OS_APPLE)
+#if !BUILDFLAG(IS_APPLE)
// TODO(ccameron): This assert is being hit on Mac try jobs. Determine if that
// is cause for concern or if it is benign.
// http://crbug.com/524624
diff --git a/chromium/components/viz/service/display_embedder/buffer_queue_unittest.cc b/chromium/components/viz/service/display_embedder/buffer_queue_unittest.cc
index bed1946eca0..aad0bc32f55 100644
--- a/chromium/components/viz/service/display_embedder/buffer_queue_unittest.cc
+++ b/chromium/components/viz/service/display_embedder/buffer_queue_unittest.cc
@@ -110,7 +110,7 @@ class StubGpuMemoryBufferManager : public TestGpuMemoryBufferManager {
size_t set_color_space_count_ = 0;
};
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
const gpu::SurfaceHandle kFakeSurfaceHandle =
reinterpret_cast<gpu::SurfaceHandle>(1);
#else
diff --git a/chromium/components/viz/service/display_embedder/compositor_gpu_thread.cc b/chromium/components/viz/service/display_embedder/compositor_gpu_thread.cc
index e0a0b542f66..92fdcf92e61 100644
--- a/chromium/components/viz/service/display_embedder/compositor_gpu_thread.cc
+++ b/chromium/components/viz/service/display_embedder/compositor_gpu_thread.cc
@@ -40,7 +40,7 @@ std::unique_ptr<CompositorGpuThread> CompositorGpuThread::Create(
if (!features::IsDrDcEnabled())
return nullptr;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// When using angle via enabling passthrough command decoder on android, angle
// context virtualization group extension should be enabled. Also since angle
// currently always enables this extension, we are adding DCHECK() to ensure
@@ -59,8 +59,8 @@ std::unique_ptr<CompositorGpuThread> CompositorGpuThread::Create(
compositor_thread_device_queue->InitializeForCompositorGpuThread(
device_queue->GetVulkanPhysicalDevice(),
device_queue->GetVulkanDevice(), device_queue->GetVulkanQueue(),
- device_queue->GetVulkanQueueIndex(),
- device_queue->enabled_extensions());
+ device_queue->GetVulkanQueueIndex(), device_queue->enabled_extensions(),
+ device_queue->enabled_device_features_2());
vulkan_context_provider =
VulkanInProcessContextProvider::CreateForCompositorGpuThread(
vulkan_implementation, std::move(compositor_thread_device_queue),
@@ -92,31 +92,23 @@ CompositorGpuThread::~CompositorGpuThread() {
base::Thread::Stop();
}
-bool CompositorGpuThread::Initialize() {
- // Setup thread options.
- base::Thread::Options thread_options(base::MessagePumpType::DEFAULT, 0);
- if (base::FeatureList::IsEnabled(features::kGpuUseDisplayThreadPriority))
- thread_options.priority = base::ThreadPriority::DISPLAY;
- StartWithOptions(std::move(thread_options));
+scoped_refptr<gpu::SharedContextState>
+CompositorGpuThread::GetSharedContextState() {
+ DCHECK(task_runner()->BelongsToCurrentThread());
- // Wait until threas is started and Init() is executed in order to return
- // updated |init_succeded_|.
- WaitUntilThreadStarted();
- return init_succeded_;
-}
+ if (shared_context_state_ && !shared_context_state_->context_lost())
+ return shared_context_state_;
-void CompositorGpuThread::Init() {
- const auto& gpu_preferences = gpu_channel_manager_->gpu_preferences();
- if (enable_watchdog_) {
- watchdog_thread_ = gpu::GpuWatchdogThread::Create(
- gpu_preferences.watchdog_starts_backgrounded, "GpuWatchdog_Compositor");
- }
+ // Cleanup the previous context if any.
+ shared_context_state_.reset();
// Create a new share group. Note that this share group is different from the
// share group which gpu main thread uses.
auto share_group = base::MakeRefCounted<gl::GLShareGroup>();
auto surface = gl::init::CreateOffscreenGLSurface(gfx::Size());
+ const auto& gpu_preferences = gpu_channel_manager_->gpu_preferences();
+
const bool use_passthrough_decoder =
gpu::gles2::PassthroughCommandDecoderSupported() &&
gpu_preferences.use_passthrough_cmd_decoder;
@@ -130,17 +122,21 @@ void CompositorGpuThread::Init() {
// GL resources with the contexts created on gpu main thread.
auto context =
gl::init::CreateGLContext(share_group.get(), surface.get(), attribs);
- if (!context)
- return;
+ if (!context) {
+ LOG(ERROR) << "Failed to create shared context";
+ return nullptr;
+ }
const auto& gpu_feature_info = gpu_channel_manager_->gpu_feature_info();
gpu_feature_info.ApplyToGLContext(context.get());
- if (!context->MakeCurrent(surface.get()))
- return;
+ if (!context->MakeCurrent(surface.get())) {
+ LOG(ERROR) << "Failed to make context current";
+ return nullptr;
+ }
// Create a SharedContextState.
- shared_context_state_ = base::MakeRefCounted<gpu::SharedContextState>(
+ auto shared_context_state = base::MakeRefCounted<gpu::SharedContextState>(
std::move(share_group), std::move(surface), std::move(context),
/*use_virtualized_gl_contexts=*/false,
gpu_channel_manager_->GetContextLostCallback(),
@@ -152,26 +148,53 @@ void CompositorGpuThread::Init() {
#endif
/*metal_context_provider=*/nullptr,
/*dawn_context_provider=*/nullptr,
- /*peak_memory_monitor=*/weak_ptr_factory_.GetWeakPtr());
+ /*peak_memory_monitor=*/weak_ptr_factory_.GetWeakPtr(),
+ /*created_on_compositor_gpu_thread=*/true);
const auto& workarounds = gpu_channel_manager_->gpu_driver_bug_workarounds();
auto gles2_feature_info = base::MakeRefCounted<gpu::gles2::FeatureInfo>(
workarounds, gpu_feature_info);
// Initialize GL.
- if (!shared_context_state_->InitializeGL(gpu_preferences,
- std::move(gles2_feature_info))) {
- return;
+ if (!shared_context_state->InitializeGL(gpu_preferences,
+ std::move(gles2_feature_info))) {
+ LOG(ERROR) << "Failed to initialize GL for SharedContextState";
+ return nullptr;
}
// Initialize GrContext.
- if (!shared_context_state_->InitializeGrContext(
+ if (!shared_context_state->InitializeGrContext(
gpu_preferences, workarounds, gpu_channel_manager_->gr_shader_cache(),
/*activity_flags=*/nullptr, /*progress_reporter=*/nullptr)) {
- return;
+ LOG(ERROR) << "Failed to Initialize GrContext for SharedContextState";
}
- if (watchdog_thread_)
- watchdog_thread_->OnInitComplete();
+ shared_context_state_ = std::move(shared_context_state);
+ return shared_context_state_;
+}
+
+bool CompositorGpuThread::Initialize() {
+ // Setup thread options.
+ base::Thread::Options thread_options(base::MessagePumpType::DEFAULT, 0);
+ if (base::FeatureList::IsEnabled(features::kGpuUseDisplayThreadPriority))
+ thread_options.priority = base::ThreadPriority::DISPLAY;
+ StartWithOptions(std::move(thread_options));
+
+ // Wait until thread is started and Init() is executed in order to return
+ // updated |init_succeded_|.
+ WaitUntilThreadStarted();
+ return init_succeded_;
+}
+
+void CompositorGpuThread::Init() {
+ const auto& gpu_preferences = gpu_channel_manager_->gpu_preferences();
+ if (enable_watchdog_) {
+ watchdog_thread_ = gpu::GpuWatchdogThread::Create(
+ gpu_preferences.watchdog_starts_backgrounded, "GpuWatchdog_Compositor");
+ }
+
+ if (!watchdog_thread_)
+ return;
+ watchdog_thread_->OnInitComplete();
init_succeded_ = true;
}
diff --git a/chromium/components/viz/service/display_embedder/compositor_gpu_thread.h b/chromium/components/viz/service/display_embedder/compositor_gpu_thread.h
index 5cf2c6b21c0..7ca40835ddf 100644
--- a/chromium/components/viz/service/display_embedder/compositor_gpu_thread.h
+++ b/chromium/components/viz/service/display_embedder/compositor_gpu_thread.h
@@ -39,9 +39,7 @@ class VIZ_SERVICE_EXPORT CompositorGpuThread
~CompositorGpuThread() override;
- scoped_refptr<gpu::SharedContextState> shared_context_state() const {
- return shared_context_state_;
- }
+ scoped_refptr<gpu::SharedContextState> GetSharedContextState();
VulkanContextProvider* vulkan_context_provider() const {
return vulkan_context_provider_.get();
diff --git a/chromium/components/viz/service/display_embedder/gl_output_surface_buffer_queue.cc b/chromium/components/viz/service/display_embedder/gl_output_surface_buffer_queue.cc
index c3b3fddde4b..6641808ac3e 100644
--- a/chromium/components/viz/service/display_embedder/gl_output_surface_buffer_queue.cc
+++ b/chromium/components/viz/service/display_embedder/gl_output_surface_buffer_queue.cc
@@ -46,7 +46,7 @@ GLOutputSurfaceBufferQueue::GLOutputSurfaceBufferQueue(
capabilities_.pending_swap_params.max_pending_swaps = 2;
// GetCurrentFramebufferDamage will return an upper bound of the part of the
// buffer that needs to be recomposited.
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
capabilities_.supports_target_damage = false;
#else
capabilities_.supports_target_damage = true;
diff --git a/chromium/components/viz/service/display_embedder/gl_output_surface_buffer_queue_unittest.cc b/chromium/components/viz/service/display_embedder/gl_output_surface_buffer_queue_unittest.cc
index 653342d2284..3876eadb8fd 100644
--- a/chromium/components/viz/service/display_embedder/gl_output_surface_buffer_queue_unittest.cc
+++ b/chromium/components/viz/service/display_embedder/gl_output_surface_buffer_queue_unittest.cc
@@ -4,6 +4,9 @@
#include "components/viz/service/display_embedder/gl_output_surface_buffer_queue.h"
+#include <utility>
+#include <vector>
+
#include "base/memory/raw_ptr.h"
#include "components/viz/service/display/output_surface_client.h"
#include "components/viz/service/display/output_surface_frame.h"
@@ -34,6 +37,47 @@ using testing::SetArgPointee;
using testing::StrictMock;
namespace viz {
+namespace {
+
+class TestVizProcessContextProvider : public VizProcessContextProvider {
+ public:
+ TestVizProcessContextProvider(std::unique_ptr<TestContextSupport> support,
+ std::unique_ptr<TestGLES2Interface> gl)
+ : support_(std::move(support)), context_gl_(std::move(gl)) {}
+ TestVizProcessContextProvider(const TestVizProcessContextProvider&) = delete;
+ TestVizProcessContextProvider& operator=(
+ const TestVizProcessContextProvider&) = delete;
+
+ // ContextProvider implementation.
+ gpu::gles2::GLES2Interface* ContextGL() override { return context_gl_.get(); }
+ gpu::ContextSupport* ContextSupport() override { return support_.get(); }
+ const gpu::Capabilities& ContextCapabilities() const override {
+ return gpu_capabilities_;
+ }
+
+ const gpu::GpuFeatureInfo& GetGpuFeatureInfo() const override {
+ return gpu_feature_info_;
+ }
+
+ void SetUpdateVSyncParametersCallback(
+ UpdateVSyncParametersCallback callback) override {}
+ void SetGpuVSyncCallback(GpuVSyncCallback callback) override {}
+ void SetGpuVSyncEnabled(bool enabled) override {}
+ bool UseRGB565PixelFormat() const override { return false; }
+ uint32_t GetCopyTextureInternalFormat() override { return 0u; }
+ base::ScopedClosureRunner GetCacheBackBufferCb() override {
+ return base::ScopedClosureRunner(base::DoNothing());
+ }
+
+ protected:
+ ~TestVizProcessContextProvider() override = default;
+
+ private:
+ std::unique_ptr<TestContextSupport> support_;
+ std::unique_ptr<TestGLES2Interface> context_gl_;
+ gpu::Capabilities gpu_capabilities_;
+ gpu::GpuFeatureInfo gpu_feature_info_;
+};
class MockGLES2Interface : public TestGLES2Interface {
public:
@@ -53,9 +97,7 @@ class MockGLES2Interface : public TestGLES2Interface {
class MockBufferQueue : public BufferQueue {
public:
- MockBufferQueue()
- : BufferQueue(/*sii_=*/nullptr,
- gpu::kNullSurfaceHandle) {}
+ MockBufferQueue() : BufferQueue(/*sii_=*/nullptr, gpu::kNullSurfaceHandle) {}
~MockBufferQueue() override = default;
MOCK_METHOD2(GetCurrentBuffer,
@@ -76,6 +118,8 @@ class MockBufferQueue : public BufferQueue {
}
};
+} // namespace
+
class GLOutputSurfaceBufferQueueTest : public ::testing::Test,
public OutputSurfaceClient {
public:
diff --git a/chromium/components/viz/service/display_embedder/image_context_impl.cc b/chromium/components/viz/service/display_embedder/image_context_impl.cc
index dcb7dd2b921..fa084599f6f 100644
--- a/chromium/components/viz/service/display_embedder/image_context_impl.cc
+++ b/chromium/components/viz/service/display_embedder/image_context_impl.cc
@@ -26,14 +26,16 @@ ImageContextImpl::ImageContextImpl(
bool maybe_concurrent_reads,
const absl::optional<gpu::VulkanYCbCrInfo>& ycbcr_info,
sk_sp<SkColorSpace> color_space,
- const bool allow_keeping_read_access)
+ bool allow_keeping_read_access,
+ bool raw_draw_if_possible)
: ImageContext(mailbox_holder,
size,
resource_format,
ycbcr_info,
color_space),
maybe_concurrent_reads_(maybe_concurrent_reads),
- allow_keeping_read_access_(allow_keeping_read_access) {}
+ allow_keeping_read_access_(allow_keeping_read_access),
+ raw_draw_if_possible_(raw_draw_if_possible) {}
ImageContextImpl::~ImageContextImpl() {
if (fallback_context_state_)
@@ -169,7 +171,10 @@ bool ImageContextImpl::BeginRasterAccess(
return true;
}
- auto raster = representation_factory->ProduceRaster(mailbox_holder().mailbox);
+ auto raster =
+ raw_draw_if_possible_
+ ? representation_factory->ProduceRaster(mailbox_holder().mailbox)
+ : nullptr;
if (!raster)
return false;
diff --git a/chromium/components/viz/service/display_embedder/image_context_impl.h b/chromium/components/viz/service/display_embedder/image_context_impl.h
index ecc8dc970dc..00a51c95254 100644
--- a/chromium/components/viz/service/display_embedder/image_context_impl.h
+++ b/chromium/components/viz/service/display_embedder/image_context_impl.h
@@ -52,7 +52,8 @@ class ImageContextImpl final : public ExternalUseClient::ImageContext {
bool maybe_concurrent_reads,
const absl::optional<gpu::VulkanYCbCrInfo>& ycbcr_info,
sk_sp<SkColorSpace> color_space,
- const bool allow_keeping_read_access = true);
+ bool allow_keeping_read_access = true,
+ bool raw_draw_if_possible = false);
ImageContextImpl(const ImageContextImpl&) = delete;
ImageContextImpl& operator=(const ImageContextImpl&) = delete;
@@ -104,6 +105,7 @@ class ImageContextImpl final : public ExternalUseClient::ImageContext {
const bool maybe_concurrent_reads_ = false;
const bool allow_keeping_read_access_ = true;
+ const bool raw_draw_if_possible_ = false;
// Fallback in case we cannot produce a |representation_|.
raw_ptr<gpu::SharedContextState> fallback_context_state_ = nullptr;
diff --git a/chromium/components/viz/service/display_embedder/output_presenter.cc b/chromium/components/viz/service/display_embedder/output_presenter.cc
index 9f6963736b3..0d9abbe5759 100644
--- a/chromium/components/viz/service/display_embedder/output_presenter.cc
+++ b/chromium/components/viz/service/display_embedder/output_presenter.cc
@@ -119,7 +119,8 @@ std::unique_ptr<OutputPresenter::Image> OutputPresenter::AllocateSingleImage(
return nullptr;
}
-void OutputPresenter::ScheduleBackground(Image* image) {
+void OutputPresenter::ScheduleOneOverlay(const OverlayCandidate& overlay,
+ ScopedOverlayAccess* access) {
NOTREACHED();
}
diff --git a/chromium/components/viz/service/display_embedder/output_presenter.h b/chromium/components/viz/service/display_embedder/output_presenter.h
index 8ea99ec8ce9..6585a849bbe 100644
--- a/chromium/components/viz/service/display_embedder/output_presenter.h
+++ b/chromium/components/viz/service/display_embedder/output_presenter.h
@@ -108,9 +108,13 @@ class VIZ_SERVICE_EXPORT OutputPresenter {
bool is_submitted) = 0;
using ScopedOverlayAccess =
gpu::SharedImageRepresentationOverlay::ScopedReadAccess;
+ virtual void ScheduleOneOverlay(const OverlayCandidate& overlay,
+ ScopedOverlayAccess* access);
virtual void ScheduleOverlays(SkiaOutputSurface::OverlayList overlays,
std::vector<ScopedOverlayAccess*> accesses) = 0;
- virtual void ScheduleBackground(Image* image);
+#if BUILDFLAG(IS_MAC)
+ virtual void SetCALayerErrorCode(gfx::CALayerResult ca_layer_error_code) {}
+#endif
};
} // namespace viz
diff --git a/chromium/components/viz/service/display_embedder/output_presenter_fuchsia.cc b/chromium/components/viz/service/display_embedder/output_presenter_fuchsia.cc
index 320cfb5fe1f..369721bfe2a 100644
--- a/chromium/components/viz/service/display_embedder/output_presenter_fuchsia.cc
+++ b/chromium/components/viz/service/display_embedder/output_presenter_fuchsia.cc
@@ -356,10 +356,10 @@ void OutputPresenterFuchsia::ScheduleOverlays(
auto& overlay = next_frame_->overlays.back();
overlay.pixmap = std::move(pixmap);
overlay.overlay_plane_data = gfx::OverlayPlaneData(
- candidate.plane_z_order, candidate.transform,
- gfx::ToRoundedRect(candidate.display_rect), candidate.uv_rect,
- !candidate.is_opaque, gfx::ToRoundedRect(candidate.damage_rect),
- candidate.opacity, candidate.priority_hint, candidate.rounded_corners,
+ candidate.plane_z_order, candidate.transform, candidate.display_rect,
+ candidate.uv_rect, !candidate.is_opaque,
+ gfx::ToRoundedRect(candidate.damage_rect), candidate.opacity,
+ candidate.priority_hint, candidate.rounded_corners,
candidate.color_space, candidate.hdr_metadata);
}
}
diff --git a/chromium/components/viz/service/display_embedder/output_presenter_gl.cc b/chromium/components/viz/service/display_embedder/output_presenter_gl.cc
index 687630b264f..e9f9217fe02 100644
--- a/chromium/components/viz/service/display_embedder/output_presenter_gl.cc
+++ b/chromium/components/viz/service/display_embedder/output_presenter_gl.cc
@@ -9,6 +9,7 @@
#include <vector>
#include "base/feature_list.h"
+#include "base/notreached.h"
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
#include "components/viz/common/features.h"
@@ -25,7 +26,7 @@
#include "ui/gl/gl_fence.h"
#include "ui/gl/gl_surface.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "ui/gl/gl_surface_egl_surface_control.h"
#endif
@@ -163,7 +164,7 @@ std::unique_ptr<OutputPresenterGL> OutputPresenterGL::Create(
SkiaOutputSurfaceDependency* deps,
gpu::SharedImageFactory* factory,
gpu::SharedImageRepresentationFactory* representation_factory) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
if (deps->GetGpuFeatureInfo()
.status_values[gpu::GPU_FEATURE_TYPE_ANDROID_SURFACE_CONTROL] !=
gpu::kGpuFeatureStatusEnabled) {
@@ -325,6 +326,10 @@ void OutputPresenterGL::PostSubBuffer(
const gfx::Rect& rect,
SwapCompletionCallback completion_callback,
BufferPresentedCallback presentation_callback) {
+#if BUILDFLAG(IS_MAC)
+ gl_surface_->SetCALayerErrorCode(ca_layer_error_code_);
+#endif
+
if (supports_async_swap_) {
gl_surface_->PostSubBufferAsync(
rect.x(), rect.y(), rect.width(), rect.height(),
@@ -357,33 +362,32 @@ void OutputPresenterGL::SchedulePrimaryPlane(
gl_surface_->ScheduleOverlayPlane(
gl_image, std::move(fence),
gfx::OverlayPlaneData(
- kPlaneZOrder, plane.transform, ToNearestRect(plane.display_rect),
- plane.uv_rect, plane.enable_blending, gfx::Rect(plane.resource_size),
+ kPlaneZOrder, plane.transform, plane.display_rect, plane.uv_rect,
+ plane.enable_blending,
+ plane.damage_rect.value_or(gfx::Rect(plane.resource_size)),
plane.opacity, plane.priority_hint, plane.rounded_corners,
presenter_image->color_space(),
/*hdr_metadata=*/absl::nullopt));
}
-void OutputPresenterGL::ScheduleBackground(Image* image) {
- auto* presenter_image = static_cast<PresenterImageGL*>(image);
- // Background is not seen by user, and is created before buffer queue buffers.
- // So fence is not needed.
- auto* gl_image = presenter_image->GetGLImage(nullptr);
-
- // Background is also z-order 0.
- constexpr int kPlaneZOrder = INT32_MIN;
- // Background always uses the full texture.
- constexpr gfx::RectF kUVRect(0.f, 0.f, 1.0f, 1.0f);
- gl_surface_->ScheduleOverlayPlane(
- gl_image, /*gpu_fence=*/nullptr,
- gfx::OverlayPlaneData(kPlaneZOrder, gfx::OVERLAY_TRANSFORM_NONE,
- gfx::Rect(),
- /*crop_rect=*/kUVRect,
- /*enable_blend=*/false, /*damage_rect=*/gfx::Rect(),
- /*opacity=*/1.0f, gfx::OverlayPriorityHint::kNone,
- /*rounded_corners=*/gfx::RRectF(),
- /*color_space=*/presenter_image->color_space(),
- /*hdr_metadata=*/absl::nullopt));
+void OutputPresenterGL::ScheduleOneOverlay(const OverlayCandidate& overlay,
+ ScopedOverlayAccess* access) {
+#if BUILDFLAG(IS_ANDROID) || defined(USE_OZONE)
+ auto* gl_image = access ? access->gl_image() : nullptr;
+ if (gl_image || overlay.solid_color.has_value()) {
+ DCHECK(!overlay.gpu_fence_id);
+ gl_surface_->ScheduleOverlayPlane(
+ gl_image, access ? TakeGpuFence(access->TakeAcquireFences()) : nullptr,
+ gfx::OverlayPlaneData(
+ overlay.plane_z_order, overlay.transform, overlay.display_rect,
+ overlay.uv_rect, !overlay.is_opaque,
+ ToEnclosingRect(overlay.damage_rect), overlay.opacity,
+ overlay.priority_hint, overlay.rounded_corners, overlay.color_space,
+ overlay.hdr_metadata, overlay.solid_color));
+ }
+#else // BUILDFLAG(IS_ANDROID) || defined(USE_OZONE)
+ NOTREACHED();
+#endif // BUILDFLAG(IS_ANDROID) || defined(USE_OZONE)
}
void OutputPresenterGL::CommitOverlayPlanes(
@@ -403,7 +407,7 @@ void OutputPresenterGL::ScheduleOverlays(
SkiaOutputSurface::OverlayList overlays,
std::vector<ScopedOverlayAccess*> accesses) {
DCHECK_EQ(overlays.size(), accesses.size());
-#if defined(OS_ANDROID) || defined(OS_APPLE) || defined(USE_OZONE)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
// Note while reading through this for-loop that |overlay| has different
// types on different platforms. On Android and Ozone it is an
// OverlayCandidate, on Windows it is a DCLayerOverlay, and on macOS it is
@@ -411,7 +415,7 @@ void OutputPresenterGL::ScheduleOverlays(
for (size_t i = 0; i < overlays.size(); ++i) {
const auto& overlay = overlays[i];
auto* gl_image = accesses[i] ? accesses[i]->gl_image() : nullptr;
-#if defined(OS_ANDROID) || defined(USE_OZONE)
+#if BUILDFLAG(IS_ANDROID) || defined(USE_OZONE)
// TODO(msisov): Once shared image factory allows creating a non backed
// images and ScheduleOverlayPlane does not rely on GLImage, remove the if
// condition that checks if this is a solid color overlay plane.
@@ -428,13 +432,13 @@ void OutputPresenterGL::ScheduleOverlays(
accesses[i] ? TakeGpuFence(accesses[i]->TakeAcquireFences())
: nullptr,
gfx::OverlayPlaneData(
- overlay.plane_z_order, overlay.transform,
- ToNearestRect(overlay.display_rect), overlay.uv_rect,
- !overlay.is_opaque, ToEnclosingRect(overlay.damage_rect),
- overlay.opacity, overlay.priority_hint, overlay.rounded_corners,
+ overlay.plane_z_order, overlay.transform, overlay.display_rect,
+ overlay.uv_rect, !overlay.is_opaque,
+ ToEnclosingRect(overlay.damage_rect), overlay.opacity,
+ overlay.priority_hint, overlay.rounded_corners,
overlay.color_space, overlay.hdr_metadata, overlay.solid_color));
}
-#elif defined(OS_APPLE)
+#elif BUILDFLAG(IS_APPLE)
// For RenderPassDrawQuad the ddl is not nullptr, and the opacity is applied
// when the ddl is recorded, so the content already is with opacity applied.
float opacity = overlay.ddl ? 1.0 : overlay.shared_state->opacity;
@@ -449,7 +453,14 @@ void OutputPresenterGL::ScheduleOverlays(
overlay.protected_video_type));
#endif
}
-#endif // defined(OS_ANDROID) || defined(OS_APPLE) || defined(USE_OZONE)
+#endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
+}
+
+#if BUILDFLAG(IS_MAC)
+void OutputPresenterGL::SetCALayerErrorCode(
+ gfx::CALayerResult ca_layer_error_code) {
+ ca_layer_error_code_ = ca_layer_error_code;
}
+#endif
} // namespace viz
diff --git a/chromium/components/viz/service/display_embedder/output_presenter_gl.h b/chromium/components/viz/service/display_embedder/output_presenter_gl.h
index 3baa9f4c450..0ab10a42709 100644
--- a/chromium/components/viz/service/display_embedder/output_presenter_gl.h
+++ b/chromium/components/viz/service/display_embedder/output_presenter_gl.h
@@ -9,10 +9,12 @@
#include <vector>
#include "base/memory/raw_ptr.h"
+#include "build/build_config.h"
#include "components/viz/service/display_embedder/output_presenter.h"
#include "components/viz/service/viz_service_export.h"
#include "gpu/command_buffer/common/shared_image_usage.h"
#include "gpu/command_buffer/service/shared_image_factory.h"
+#include "ui/gfx/ca_layer_result.h"
namespace gl {
class GLSurface;
@@ -63,9 +65,14 @@ class VIZ_SERVICE_EXPORT OutputPresenterGL : public OutputPresenter {
const OverlayProcessorInterface::OutputSurfaceOverlayPlane& plane,
Image* image,
bool is_submitted) final;
+ void ScheduleOneOverlay(const OverlayCandidate& overlay,
+ ScopedOverlayAccess* access) final;
void ScheduleOverlays(SkiaOutputSurface::OverlayList overlays,
std::vector<ScopedOverlayAccess*> accesses) final;
- void ScheduleBackground(Image* image) final;
+
+#if BUILDFLAG(IS_MAC)
+ void SetCALayerErrorCode(gfx::CALayerResult ca_layer_error_code) final;
+#endif
private:
scoped_refptr<gl::GLSurface> gl_surface_;
@@ -79,6 +86,10 @@ class VIZ_SERVICE_EXPORT OutputPresenterGL : public OutputPresenter {
const raw_ptr<gpu::SharedImageRepresentationFactory>
shared_image_representation_factory_;
uint32_t shared_image_usage_;
+
+#if BUILDFLAG(IS_MAC)
+ gfx::CALayerResult ca_layer_error_code_ = gfx::kCALayerSuccess;
+#endif
};
} // namespace viz
diff --git a/chromium/components/viz/service/display_embedder/output_surface_provider_impl.cc b/chromium/components/viz/service/display_embedder/output_surface_provider_impl.cc
index e0afde4b0cb..8a277c6337d 100644
--- a/chromium/components/viz/service/display_embedder/output_surface_provider_impl.cc
+++ b/chromium/components/viz/service/display_embedder/output_surface_provider_impl.cc
@@ -13,6 +13,7 @@
#include "base/compiler_specific.h"
#include "base/task/sequenced_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "build/build_config.h"
#include "build/chromecast_buildflags.h"
#include "build/chromeos_buildflags.h"
#include "cc/base/switches.h"
@@ -42,15 +43,15 @@
#include "ui/gl/gl_context.h"
#include "ui/gl/init/gl_factory.h"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include "components/viz/service/display_embedder/software_output_device_win.h"
#endif
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "components/viz/service/display_embedder/gl_output_surface_android.h"
#endif
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
#include "components/viz/service/display_embedder/software_output_device_mac.h"
#include "ui/base/cocoa/remote_layer_api.h"
#endif
@@ -75,13 +76,13 @@ OutputSurfaceProviderImpl::OutputSurfaceProviderImpl(
GpuServiceImpl* gpu_service_impl,
gpu::CommandBufferTaskExecutor* task_executor,
gpu::GpuChannelManagerDelegate* gpu_channel_manager_delegate,
- std::unique_ptr<gpu::GpuMemoryBufferManager> gpu_memory_buffer_manager,
+ gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
gpu::ImageFactory* image_factory,
bool headless)
: gpu_service_impl_(gpu_service_impl),
task_executor_(task_executor),
gpu_channel_manager_delegate_(gpu_channel_manager_delegate),
- gpu_memory_buffer_manager_(std::move(gpu_memory_buffer_manager)),
+ gpu_memory_buffer_manager_(gpu_memory_buffer_manager),
image_factory_(image_factory),
task_runner_(base::ThreadTaskRunnerHandle::Get()),
headless_(headless) {}
@@ -146,14 +147,14 @@ std::unique_ptr<OutputSurface> OutputSurfaceProviderImpl::CreateOutputSurface(
gpu_dependency, renderer_settings, debug_settings);
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// As with non-skia-renderer case, communicate the creation result to
// CompositorImplAndroid so that it can attempt to recreate the surface on
// failure.
display_client->OnContextCreationResult(
output_surface ? gpu::ContextResult::kSuccess
: gpu::ContextResult::kSurfaceFailure);
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
if (!output_surface) {
#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMECAST)
@@ -161,7 +162,7 @@ std::unique_ptr<OutputSurface> OutputSurfaceProviderImpl::CreateOutputSurface(
// never encounter fatal context error. This could be an unrecoverable
// hardware error or a bug.
LOG(FATAL) << "Unexpected fatal context error";
-#elif !defined(OS_ANDROID)
+#elif !BUILDFLAG(IS_ANDROID)
gpu_service_impl_->DisableGpuCompositing();
#endif
return nullptr;
@@ -190,7 +191,7 @@ std::unique_ptr<OutputSurface> OutputSurfaceProviderImpl::CreateOutputSurface(
renderer_settings);
context_result = context_provider->BindToCurrentThread();
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
display_client->OnContextCreationResult(context_result);
#endif
@@ -200,7 +201,7 @@ std::unique_ptr<OutputSurface> OutputSurfaceProviderImpl::CreateOutputSurface(
// never encounter fatal context error. This could be an unrecoverable
// hardware error or a bug.
LOG(FATAL) << "Unexpected fatal context error";
-#elif !defined(OS_ANDROID)
+#elif !BUILDFLAG(IS_ANDROID)
gpu_service_impl_->DisableGpuCompositing();
#endif
return nullptr;
@@ -211,7 +212,7 @@ std::unique_ptr<OutputSurface> OutputSurfaceProviderImpl::CreateOutputSurface(
output_surface = std::make_unique<GLOutputSurfaceOffscreen>(
std::move(context_provider));
} else if (context_provider->ContextCapabilities().surfaceless) {
-#if defined(USE_OZONE) || defined(OS_APPLE) || defined(OS_ANDROID)
+#if defined(USE_OZONE) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_ANDROID)
output_surface = std::make_unique<GLOutputSurfaceBufferQueue>(
std::move(context_provider), surface_handle,
std::make_unique<BufferQueue>(
@@ -220,10 +221,10 @@ std::unique_ptr<OutputSurface> OutputSurfaceProviderImpl::CreateOutputSurface(
NOTREACHED();
#endif
} else {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
output_surface = std::make_unique<GLOutputSurface>(
std::move(context_provider), surface_handle);
-#elif defined(OS_ANDROID)
+#elif BUILDFLAG(IS_ANDROID)
output_surface = std::make_unique<GLOutputSurfaceAndroid>(
std::move(context_provider), surface_handle);
#elif BUILDFLAG(IS_CHROMEOS_ASH)
@@ -246,12 +247,12 @@ OutputSurfaceProviderImpl::CreateSoftwareOutputDeviceForPlatform(
if (headless_)
return std::make_unique<SoftwareOutputDevice>();
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
return CreateSoftwareOutputDeviceWin(surface_handle, &output_device_backing_,
display_client);
-#elif defined(OS_APPLE)
+#elif BUILDFLAG(IS_APPLE)
return std::make_unique<SoftwareOutputDeviceMac>(task_runner_);
-#elif defined(OS_ANDROID)
+#elif BUILDFLAG(IS_ANDROID)
// Android does not do software compositing, so we can't get here.
NOTREACHED();
return nullptr;
diff --git a/chromium/components/viz/service/display_embedder/output_surface_provider_impl.h b/chromium/components/viz/service/display_embedder/output_surface_provider_impl.h
index 07f266d8a37..fa9bc45b5c1 100644
--- a/chromium/components/viz/service/display_embedder/output_surface_provider_impl.h
+++ b/chromium/components/viz/service/display_embedder/output_surface_provider_impl.h
@@ -18,7 +18,7 @@
#include "gpu/ipc/common/surface_handle.h"
#include "gpu/ipc/in_process_command_buffer.h"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include "components/viz/service/display_embedder/output_device_backing.h"
#endif
@@ -42,7 +42,7 @@ class VIZ_SERVICE_EXPORT OutputSurfaceProviderImpl
GpuServiceImpl* gpu_service_impl,
gpu::CommandBufferTaskExecutor* task_executor,
gpu::GpuChannelManagerDelegate* gpu_channel_manager_delegate,
- std::unique_ptr<gpu::GpuMemoryBufferManager> gpu_memory_buffer_manager,
+ gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
gpu::ImageFactory* image_factory,
bool headless);
// Software compositing only.
@@ -76,10 +76,10 @@ class VIZ_SERVICE_EXPORT OutputSurfaceProviderImpl
const raw_ptr<GpuServiceImpl> gpu_service_impl_;
const raw_ptr<gpu::CommandBufferTaskExecutor> task_executor_;
const raw_ptr<gpu::GpuChannelManagerDelegate> gpu_channel_manager_delegate_;
- std::unique_ptr<gpu::GpuMemoryBufferManager> gpu_memory_buffer_manager_;
+ const raw_ptr<gpu::GpuMemoryBufferManager> gpu_memory_buffer_manager_;
const raw_ptr<gpu::ImageFactory> image_factory_;
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// Used for software compositing output on Windows.
OutputDeviceBacking output_device_backing_;
#endif
diff --git a/chromium/components/viz/service/display_embedder/skia_output_device_buffer_queue.cc b/chromium/components/viz/service/display_embedder/skia_output_device_buffer_queue.cc
index d0df34a4172..16939a4d070 100644
--- a/chromium/components/viz/service/display_embedder/skia_output_device_buffer_queue.cc
+++ b/chromium/components/viz/service/display_embedder/skia_output_device_buffer_queue.cc
@@ -14,8 +14,10 @@
#include "base/compiler_specific.h"
#include "base/containers/cxx20_erase.h"
#include "base/debug/alias.h"
+#include "base/notreached.h"
#include "build/build_config.h"
#include "components/viz/common/switches.h"
+#include "components/viz/service/display/overlay_candidate.h"
#include "components/viz/service/display_embedder/skia_output_surface_dependency.h"
#include "gpu/command_buffer/common/capabilities.h"
#include "gpu/command_buffer/service/feature_info.h"
@@ -24,8 +26,10 @@
#include "gpu/command_buffer/service/shared_image_representation.h"
#include "gpu/config/gpu_finch_features.h"
#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkColor.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "third_party/skia/include/core/SkSurfaceProps.h"
+#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/swap_result.h"
#include "ui/gl/gl_surface.h"
@@ -41,11 +45,6 @@ NOINLINE void CheckForLoopFailuresBufferQueue() {
}
g_last_reshape_failure = now;
}
-
-// See |needs_background_image| for details.
-constexpr size_t kNumberOfBackgroundImages = 2u;
-constexpr gfx::Size kBackgroundImageSize(4, 4);
-
} // namespace
namespace viz {
@@ -145,7 +144,7 @@ SkiaOutputDeviceBufferQueue::SkiaOutputDeviceBufferQueue(
capabilities_.preserve_buffer_content = true;
capabilities_.only_invalidates_damage_rect = false;
capabilities_.number_of_buffers = 3;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
if (::features::IncreaseBufferCountForHighFrameRate()) {
capabilities_.number_of_buffers = 5;
}
@@ -161,7 +160,7 @@ SkiaOutputDeviceBufferQueue::SkiaOutputDeviceBufferQueue(
capabilities_.number_of_buffers = 2;
capabilities_.pending_swap_params.max_pending_swaps =
capabilities_.number_of_buffers - 1;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
if (::features::IncreaseBufferCountForHighFrameRate() &&
capabilities_.number_of_buffers == 5) {
capabilities_.pending_swap_params.max_pending_swaps = 2;
@@ -254,7 +253,8 @@ void SkiaOutputDeviceBufferQueue::SchedulePrimaryPlane(
const absl::optional<OverlayProcessorInterface::OutputSurfaceOverlayPlane>&
plane) {
// See |needs_background_image|.
- MaybeScheduleBackgroundImage();
+ MaybeScheduleBackgroundImage(plane.has_value() ? plane->display_rect
+ : gfx::RectF{4.f, 4.f});
if (plane) {
// If the current_image_ is nullptr, it means there is no change on the
@@ -330,8 +330,62 @@ const gpu::Mailbox SkiaOutputDeviceBufferQueue::GetImageMailboxForColor(
image_mailbox, std::make_pair(color, std::move(solid_color))));
return image_mailbox;
}
-
#endif
+
+SkiaOutputDeviceBufferQueue::OverlayData*
+SkiaOutputDeviceBufferQueue::GetOrCreateOverlayData(
+ const gpu::Mailbox& mailbox) {
+ if (!mailbox.IsSharedImage())
+ return nullptr;
+
+ auto it = overlays_.find(mailbox);
+ if (it != overlays_.end()) {
+ // If the overlay is in |overlays_|, we will reuse it, and a ref will be
+ // added to keep it alive. This ref will be removed, when the overlay is
+ // replaced by a new frame.
+ it->Ref();
+ return &*it;
+ }
+
+ auto shared_image = representation_factory_->ProduceOverlay(mailbox);
+ // When display is re-opened, the first few frames might not have video
+ // resource ready. Possible investigation crbug.com/1023971.
+ if (!shared_image) {
+ LOG(ERROR) << "Invalid mailbox.";
+ return nullptr;
+ }
+
+ // Fuchsia does not provide a GLImage overlay.
+#if BUILDFLAG(IS_FUCHSIA)
+ const bool needs_gl_image = false;
+#else
+ const bool needs_gl_image = true;
+#endif // BUILDFLAG(IS_FUCHSIA)
+
+ // TODO(penghuang): do not depend on GLImage.
+ auto shared_image_access =
+ shared_image->BeginScopedReadAccess(needs_gl_image);
+ if (!shared_image_access) {
+ LOG(ERROR) << "Could not access SharedImage for read.";
+ return nullptr;
+ }
+
+ // TODO(penghuang): do not depend on GLImage.
+ DLOG_IF(FATAL, needs_gl_image && !shared_image_access->gl_image())
+ << "Cannot get GLImage.";
+
+ bool result;
+ std::tie(it, result) = overlays_.emplace(std::move(shared_image),
+ std::move(shared_image_access));
+ DCHECK(result);
+ DCHECK(it->unique());
+
+ // Add an extra ref to keep it alive. This extra ref will be removed when
+ // the backing is not used by system compositor anymore.
+ it->Ref();
+ return &*it;
+}
+
void SkiaOutputDeviceBufferQueue::ScheduleOverlays(
SkiaOutputSurface::OverlayList overlays) {
DCHECK(pending_overlay_mailboxes_.empty());
@@ -352,58 +406,11 @@ void SkiaOutputDeviceBufferQueue::ScheduleOverlays(
}
#endif
- if (!overlay.mailbox.IsSharedImage())
+ auto* overlay_data = GetOrCreateOverlayData(overlay.mailbox);
+ if (!overlay_data)
continue;
- auto it = overlays_.find(overlay.mailbox);
- if (it != overlays_.end()) {
- // If the overlay is in |overlays_|, we will reuse it, and a ref will be
- // added to keep it alive. This ref will be removed, when the overlay is
- // replaced by a new frame.
- it->Ref();
- accesses[i] = it->scoped_read_access();
- pending_overlay_mailboxes_.emplace_back(overlay.mailbox);
- continue;
- }
-
- auto shared_image =
- representation_factory_->ProduceOverlay(overlay.mailbox);
- // When display is re-opened, the first few frames might not have video
- // resource ready. Possible investigation crbug.com/1023971.
- if (!shared_image) {
- LOG(ERROR) << "Invalid mailbox.";
- continue;
- }
-
- // Fuchsia does not provide a GLImage overlay.
-#if defined(OS_FUCHSIA)
- const bool needs_gl_image = false;
-#else
- const bool needs_gl_image = true;
-#endif // defined(OS_FUCHSIA)
-
- // TODO(penghuang): do not depend on GLImage.
- auto shared_image_access =
- shared_image->BeginScopedReadAccess(needs_gl_image);
- if (!shared_image_access) {
- LOG(ERROR) << "Could not access SharedImage for read.";
- continue;
- }
-
- // TODO(penghuang): do not depend on GLImage.
- DLOG_IF(FATAL, needs_gl_image && !shared_image_access->gl_image())
- << "Cannot get GLImage.";
-
- bool result;
- std::tie(it, result) = overlays_.emplace(std::move(shared_image),
- std::move(shared_image_access));
- DCHECK(result);
- DCHECK(it->unique());
-
- // Add an extra ref to keep it alive. This extra ref will be removed when
- // the backing is not used by system compositor anymore.
- it->Ref();
- accesses[i] = it->scoped_read_access();
+ accesses[i] = overlay_data->scoped_read_access();
pending_overlay_mailboxes_.emplace_back(overlay.mailbox);
}
@@ -474,6 +481,10 @@ void SkiaOutputDeviceBufferQueue::PostSubBuffer(
DCHECK(submitted_image_);
}
+#if BUILDFLAG(IS_MAC)
+ presenter_->SetCALayerErrorCode(frame.ca_layer_error_code);
+#endif
+
// Cancelable callback uses weak ptr to drop this task upon destruction.
// Thus it is safe to use |base::Unretained(this)|.
// Bind submitted_image_->GetWeakPtr(), since the |submitted_image_| could
@@ -554,7 +565,7 @@ void SkiaOutputDeviceBufferQueue::DoFinishSwapBuffers(
// Code below can destroy last representation of the overlay shared image. On
// MacOS it needs context to be current.
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
// TODO(vasilyt): We shouldn't need this after we stop using
// SharedImageBackingGLImage as backing.
if (!context_state_->MakeCurrent(nullptr)) {
@@ -566,7 +577,7 @@ void SkiaOutputDeviceBufferQueue::DoFinishSwapBuffers(
std::vector<gpu::Mailbox> released_overlays;
auto on_overlay_release =
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
[&released_overlays](const OverlayData& overlay) {
// Right now, only macOS needs to return maliboxes of released
// overlays, so SkiaRenderer can unlock resources for them.
@@ -646,9 +657,6 @@ bool SkiaOutputDeviceBufferQueue::Reshape(const gfx::Size& size,
overlay_transform_ = transform;
- // See |needs_background_image|.
- MaybeAllocateBackgroundImages();
-
if (color_space_ == color_space && image_size_ == size)
return true;
color_space_ = color_space;
@@ -682,38 +690,34 @@ bool SkiaOutputDeviceBufferQueue::RecreateImages() {
return !images_.empty();
}
-void SkiaOutputDeviceBufferQueue::MaybeAllocateBackgroundImages() {
- if (!needs_background_image_ || !background_images_.empty())
+void SkiaOutputDeviceBufferQueue::MaybeScheduleBackgroundImage(
+ const gfx::RectF& display_rect) {
+ if (!needs_background_image_)
return;
- background_images_ = presenter_->AllocateImages(
- color_space_, kBackgroundImageSize, kNumberOfBackgroundImages);
- DCHECK(!background_images_.empty());
+ gpu::SharedImageRepresentationOverlay::ScopedReadAccess* access = nullptr;
+ OverlayCandidate candidate;
+ candidate.color_space = color_space_;
+ candidate.display_rect = display_rect;
+ candidate.solid_color = SK_ColorTRANSPARENT;
+ candidate.plane_z_order = INT32_MIN;
- // Clear the background images to avoid undesired artifacts.
- for (auto& image : background_images_) {
- image->BeginWriteSkia();
- image->sk_surface()->getCanvas()->clear(SkColors::kTransparent);
- image->EndWriteSkia(/*force_flush*/ true);
- }
-}
+#if defined(USE_OZONE)
+ if (!supports_non_backed_solid_color_images_) {
+ auto mailbox = GetImageMailboxForColor(candidate.solid_color.value());
+ DCHECK(mailbox.IsSharedImage());
-void SkiaOutputDeviceBufferQueue::MaybeScheduleBackgroundImage() {
- if (!needs_background_image_)
- return;
+ auto* overlay_data = GetOrCreateOverlayData(mailbox);
+ DCHECK(overlay_data);
- if (current_background_image_)
- current_background_image_->EndPresent({});
- current_background_image_ = GetNextBackgroundImage();
- current_background_image_->BeginPresent();
- presenter_->ScheduleBackground(current_background_image_);
-}
+ access = overlay_data->scoped_read_access();
+ pending_overlay_mailboxes_.emplace_back(mailbox);
+ }
+#else // defined(USE_OZONE)
+ NOTREACHED();
+#endif // !defined(USE_OZONE)
-OutputPresenter::Image* SkiaOutputDeviceBufferQueue::GetNextBackgroundImage() {
- DCHECK_EQ(background_images_.size(), kNumberOfBackgroundImages);
- return current_background_image_ == background_images_.front().get()
- ? background_images_.back().get()
- : background_images_.front().get();
+ presenter_->ScheduleOneOverlay(candidate, access);
}
SkSurface* SkiaOutputDeviceBufferQueue::BeginPaint(
diff --git a/chromium/components/viz/service/display_embedder/skia_output_device_buffer_queue.h b/chromium/components/viz/service/display_embedder/skia_output_device_buffer_queue.h
index f71805ae488..ea8833e1602 100644
--- a/chromium/components/viz/service/display_embedder/skia_output_device_buffer_queue.h
+++ b/chromium/components/viz/service/display_embedder/skia_output_device_buffer_queue.h
@@ -90,9 +90,11 @@ class VIZ_SERVICE_EXPORT SkiaOutputDeviceBufferQueue : public SkiaOutputDevice {
gfx::Size GetSwapBuffersSize();
bool RecreateImages();
- void MaybeAllocateBackgroundImages();
- void MaybeScheduleBackgroundImage();
- OutputPresenter::Image* GetNextBackgroundImage();
+ void MaybeScheduleBackgroundImage(const gfx::RectF& display_rect);
+
+ // Given an overlay mailbox, returns the corresponding OverlayData* from
+ // |overlays_|. Inserts an OverlayData if mailbox is not in |overlays_|.
+ OverlayData* GetOrCreateOverlayData(const gpu::Mailbox& mailbox);
std::unique_ptr<OutputPresenter> presenter_;
@@ -154,14 +156,6 @@ class VIZ_SERVICE_EXPORT SkiaOutputDeviceBufferQueue : public SkiaOutputDevice {
// it for opaque accelerated widgets and event wiring. Please see details on
// the number of background images below.
bool needs_background_image_ = false;
- // 4x4 small images that will be scaled to cover an opaque region.
- // It's required to have two background images to be scheduled so that
- // Desktop Wayland compositors are able to apply state changes to root
- // surfaces. Otherwise, they unref the attached buffer after processing it
- // and never update the state changes of the root surface, which leads to
- // a broken resize opetion.
- std::vector<std::unique_ptr<OutputPresenter::Image>> background_images_;
- OutputPresenter::Image* current_background_image_ = nullptr;
// Whether the platform supports non-backed solid color overlays. The Wayland
// backend is able to delegate these overlays without buffer backings
// depending on the availability of a certain protocol.
diff --git a/chromium/components/viz/service/display_embedder/skia_output_device_dawn.cc b/chromium/components/viz/service/display_embedder/skia_output_device_dawn.cc
index 00f1b85844f..46c905657a2 100644
--- a/chromium/components/viz/service/display_embedder/skia_output_device_dawn.cc
+++ b/chromium/components/viz/service/display_embedder/skia_output_device_dawn.cc
@@ -9,7 +9,7 @@
#include "base/check_op.h"
#include "base/notreached.h"
#include "components/viz/common/gpu/dawn_context_provider.h"
-#include "third_party/dawn/src/include/dawn_native/D3D12Backend.h"
+#include "third_party/dawn/include/dawn/native/D3D12Backend.h"
#include "ui/gfx/presentation_feedback.h"
#include "ui/gfx/vsync_provider.h"
#include "ui/gl/vsync_provider_win.h"
@@ -139,7 +139,7 @@ void SkiaOutputDeviceDawn::EndPaint() {
}
void SkiaOutputDeviceDawn::CreateSwapChainImplementation() {
- swap_chain_implementation_ = dawn_native::d3d12::CreateNativeSwapChainImpl(
+ swap_chain_implementation_ = dawn::native::d3d12::CreateNativeSwapChainImpl(
context_provider_->GetDevice().Get(), child_window_.window());
}
diff --git a/chromium/components/viz/service/display_embedder/skia_output_device_dawn.h b/chromium/components/viz/service/display_embedder/skia_output_device_dawn.h
index ec234342f67..42b7fef8484 100644
--- a/chromium/components/viz/service/display_embedder/skia_output_device_dawn.h
+++ b/chromium/components/viz/service/display_embedder/skia_output_device_dawn.h
@@ -10,9 +10,9 @@
#include "build/build_config.h"
#include "components/viz/service/display_embedder/skia_output_device.h"
-#include "third_party/dawn/src/include/dawn/dawn_wsi.h"
-#include "third_party/dawn/src/include/dawn/webgpu.h"
-#include "third_party/dawn/src/include/dawn_native/DawnNative.h"
+#include "third_party/dawn/include/dawn/dawn_wsi.h"
+#include "third_party/dawn/include/dawn/native/DawnNative.h"
+#include "third_party/dawn/include/dawn/webgpu.h"
#include "third_party/skia/include/core/SkColorSpace.h"
#include "third_party/skia/include/core/SkImageInfo.h"
#include "third_party/skia/include/gpu/GrBackendSurface.h"
diff --git a/chromium/components/viz/service/display_embedder/skia_output_device_gl.cc b/chromium/components/viz/service/display_embedder/skia_output_device_gl.cc
index 6453f7f95f4..7700039b8eb 100644
--- a/chromium/components/viz/service/display_embedder/skia_output_device_gl.cc
+++ b/chromium/components/viz/service/display_embedder/skia_output_device_gl.cc
@@ -115,7 +115,7 @@ SkiaOutputDeviceGL::SkiaOutputDeviceGL(
capabilities_.uses_default_gl_framebuffer = true;
capabilities_.output_surface_origin = gl_surface_->GetOrigin();
capabilities_.supports_post_sub_buffer = gl_surface_->SupportsPostSubBuffer();
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
if (gl_surface_->SupportsDCLayers()) {
// We need to set this bit to allow viz to track the previous damage rect
// of a backbuffer in a multiple backbuffer system, so backbuffers always
@@ -126,7 +126,7 @@ SkiaOutputDeviceGL::SkiaOutputDeviceGL(
gl::DirectCompositionRootSurfaceBufferCount();
capabilities_.supports_delegated_ink = gl_surface_->SupportsDelegatedInk();
}
-#endif // OS_WIN
+#endif // BUILDFLAG(IS_WIN)
if (feature_info->workarounds()
.disable_post_sub_buffers_for_onscreen_surfaces) {
capabilities_.supports_post_sub_buffer = false;
@@ -140,7 +140,7 @@ SkiaOutputDeviceGL::SkiaOutputDeviceGL(
gl_surface_->SupportsCommitOverlayPlanes();
capabilities_.supports_gpu_vsync = gl_surface_->SupportsGpuVSync();
capabilities_.supports_dc_layers = gl_surface_->SupportsDCLayers();
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// TODO(weiliangc): This capability is used to check whether we should do
// overlay. Since currently none of the other overlay system is implemented,
// only update this for Android.
@@ -403,7 +403,7 @@ void SkiaOutputDeviceGL::SetEnableDCLayers(bool enable) {
void SkiaOutputDeviceGL::ScheduleOverlays(
SkiaOutputSurface::OverlayList overlays) {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
for (auto& dc_layer : overlays) {
auto params = std::make_unique<ui::DCRendererLayerParams>();
// Get GLImages for DC layer textures.
@@ -442,7 +442,7 @@ void SkiaOutputDeviceGL::ScheduleOverlays(
if (!gl_surface_->ScheduleDCLayer(std::move(params)))
DLOG(ERROR) << "ScheduleDCLayer failed";
}
-#endif // OS_WIN
+#endif // BUILDFLAG(IS_WIN)
}
void SkiaOutputDeviceGL::EnsureBackbuffer() {
diff --git a/chromium/components/viz/service/display_embedder/skia_output_device_vulkan.cc b/chromium/components/viz/service/display_embedder/skia_output_device_vulkan.cc
index bbef3973312..717edee655c 100644
--- a/chromium/components/viz/service/display_embedder/skia_output_device_vulkan.cc
+++ b/chromium/components/viz/service/display_embedder/skia_output_device_vulkan.cc
@@ -24,7 +24,7 @@
#include "third_party/skia/include/gpu/GrDirectContext.h"
#include "third_party/skia/include/gpu/vk/GrVkTypes.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include <android/native_window_jni.h>
#endif
@@ -76,7 +76,7 @@ SkiaOutputDeviceVulkan::~SkiaOutputDeviceVulkan() {
vulkan_surface_->Destroy();
}
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
gpu::SurfaceHandle SkiaOutputDeviceVulkan::GetChildSurfaceHandle() {
if (LIKELY(vulkan_surface_->accelerated_widget() != surface_handle_))
return vulkan_surface_->accelerated_widget();
@@ -257,7 +257,7 @@ void SkiaOutputDeviceVulkan::EndPaint() {
bool SkiaOutputDeviceVulkan::Initialize() {
gfx::AcceleratedWidget accelerated_widget = gfx::kNullAcceleratedWidget;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
bool can_be_used_with_surface_control = false;
accelerated_widget =
gpu::GpuSurfaceLookup::GetInstance()->AcquireNativeWidget(
@@ -296,7 +296,7 @@ bool SkiaOutputDeviceVulkan::Initialize() {
capabilities_.supports_post_sub_buffer = true;
capabilities_.supports_target_damage = true;
capabilities_.orientation_mode = OutputSurface::OrientationMode::kHardware;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// With vulkan, if the chrome is launched in landscape mode, the chrome is
// always blank until chrome window is rotated once. Workaround this problem
// by using logic rotation mode.
@@ -322,6 +322,9 @@ bool SkiaOutputDeviceVulkan::Initialize() {
sk_color_type;
capabilities_.sk_color_types[static_cast<int>(gfx::BufferFormat::BGRA_8888)] =
sk_color_type;
+ // BGRX_8888 is used on Windows.
+ capabilities_.sk_color_types[static_cast<int>(gfx::BufferFormat::BGRX_8888)] =
+ sk_color_type;
return true;
}
diff --git a/chromium/components/viz/service/display_embedder/skia_output_device_vulkan.h b/chromium/components/viz/service/display_embedder/skia_output_device_vulkan.h
index 6b4837df8c9..032db8432c8 100644
--- a/chromium/components/viz/service/display_embedder/skia_output_device_vulkan.h
+++ b/chromium/components/viz/service/display_embedder/skia_output_device_vulkan.h
@@ -45,7 +45,7 @@ class SkiaOutputDeviceVulkan final : public SkiaOutputDevice {
gpu::MemoryTracker* memory_tracker,
DidSwapBufferCompleteCallback did_swap_buffer_complete_callback);
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
gpu::SurfaceHandle GetChildSurfaceHandle();
#endif
// SkiaOutputDevice implementation:
diff --git a/chromium/components/viz/service/display_embedder/skia_output_device_vulkan_secondary_cb_offscreen.cc b/chromium/components/viz/service/display_embedder/skia_output_device_vulkan_secondary_cb_offscreen.cc
deleted file mode 100644
index aaca9ecab88..00000000000
--- a/chromium/components/viz/service/display_embedder/skia_output_device_vulkan_secondary_cb_offscreen.cc
+++ /dev/null
@@ -1,87 +0,0 @@
-// Copyright 2021 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.
-
-#include "components/viz/service/display_embedder/skia_output_device_vulkan_secondary_cb_offscreen.h"
-
-#include <utility>
-
-#include "components/viz/common/gpu/vulkan_context_provider.h"
-#include "gpu/command_buffer/service/skia_utils.h"
-#include "gpu/vulkan/vulkan_device_queue.h"
-#include "gpu/vulkan/vulkan_function_pointers.h"
-#include "skia/ext/legacy_display_globals.h"
-#include "third_party/skia/include/core/SkCanvas.h"
-#include "third_party/skia/include/core/SkColor.h"
-#include "third_party/skia/include/core/SkDeferredDisplayList.h"
-#include "third_party/skia/include/core/SkSurface.h"
-#include "third_party/skia/include/core/SkSurfaceCharacterization.h"
-#include "third_party/skia/include/gpu/GrBackendSurface.h"
-#include "third_party/skia/include/gpu/GrDirectContext.h"
-#include "third_party/skia/src/gpu/vk/GrVkSecondaryCBDrawContext.h"
-#include "ui/gfx/presentation_feedback.h"
-#include "ui/gfx/swap_result.h"
-
-namespace viz {
-
-SkiaOutputDeviceVulkanSecondaryCBOffscreen::
- SkiaOutputDeviceVulkanSecondaryCBOffscreen(
- scoped_refptr<gpu::SharedContextState> context_state,
- gpu::MemoryTracker* memory_tracker,
- DidSwapBufferCompleteCallback did_swap_buffer_complete_callback)
- : SkiaOutputDeviceOffscreen(std::move(context_state),
- gfx::SurfaceOrigin::kTopLeft,
- /*has_alpha=*/true,
- memory_tracker,
- std::move(did_swap_buffer_complete_callback)) {
- DCHECK(context_state_->vk_context_provider());
- capabilities_.pending_swap_params.max_pending_swaps = 1;
- capabilities_.preserve_buffer_content = false;
- capabilities_.supports_post_sub_buffer = false;
-}
-
-SkiaOutputDeviceVulkanSecondaryCBOffscreen::
- ~SkiaOutputDeviceVulkanSecondaryCBOffscreen() = default;
-
-SkSurface* SkiaOutputDeviceVulkanSecondaryCBOffscreen::BeginPaint(
- bool allocate_frame_buffer,
- std::vector<GrBackendSemaphore>* end_semaphores) {
- SkSurface* sk_surface = SkiaOutputDeviceOffscreen::BeginPaint(
- allocate_frame_buffer, end_semaphores);
- sk_surface->getCanvas()->clear(SK_ColorTRANSPARENT);
- return sk_surface;
-}
-
-void SkiaOutputDeviceVulkanSecondaryCBOffscreen::SwapBuffers(
- BufferPresentedCallback feedback,
- OutputSurfaceFrame frame) {
- StartSwapBuffers(std::move(feedback));
-
- auto format_index = static_cast<int>(format_);
- const auto& sk_color_type = capabilities_.sk_color_types[format_index];
- DCHECK(sk_color_type != kUnknown_SkColorType)
- << "SkColorType is invalid for format: " << format_index;
- sk_sp<SkImage> sk_image = SkImage::MakeFromTexture(
- context_state_->vk_context_provider()->GetGrContext(), backend_texture_,
- kTopLeft_GrSurfaceOrigin, sk_color_type, kPremul_SkAlphaType,
- sk_color_space_);
- gfx::SwapResult result = gfx::SwapResult::SWAP_ACK;
- if (sk_image) {
- SkPaint paint;
- paint.setBlendMode(SkBlendMode::kSrcOver);
- context_state_->vk_context_provider()
- ->GetGrSecondaryCBDrawContext()
- ->getCanvas()
- ->drawImage(sk_image, 0, 0, SkSamplingOptions(), &paint);
- context_state_->vk_context_provider()
- ->GetGrSecondaryCBDrawContext()
- ->flush();
- } else {
- result = gfx::SwapResult::SWAP_FAILED;
- }
-
- FinishSwapBuffers(gfx::SwapCompletionResult(result),
- gfx::Size(size_.width(), size_.height()), std::move(frame));
-}
-
-} // namespace viz
diff --git a/chromium/components/viz/service/display_embedder/skia_output_device_vulkan_secondary_cb_offscreen.h b/chromium/components/viz/service/display_embedder/skia_output_device_vulkan_secondary_cb_offscreen.h
deleted file mode 100644
index f39135fc895..00000000000
--- a/chromium/components/viz/service/display_embedder/skia_output_device_vulkan_secondary_cb_offscreen.h
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2021 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.
-
-#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SKIA_OUTPUT_DEVICE_VULKAN_SECONDARY_CB_OFFSCREEN_H_
-#define COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SKIA_OUTPUT_DEVICE_VULKAN_SECONDARY_CB_OFFSCREEN_H_
-
-#include <vector>
-
-#include "components/viz/service/display_embedder/skia_output_device_offscreen.h"
-#include "gpu/command_buffer/service/shared_context_state.h"
-
-namespace viz {
-
-// Draw into an offscreen buffer which is then drawn to into the secondary
-// command buffer. This is meant to for debugging direct compositing with
-// secondary command buffers.
-class SkiaOutputDeviceVulkanSecondaryCBOffscreen final
- : public SkiaOutputDeviceOffscreen {
- public:
- SkiaOutputDeviceVulkanSecondaryCBOffscreen(
- scoped_refptr<gpu::SharedContextState> context_state,
- gpu::MemoryTracker* memory_tracker,
- DidSwapBufferCompleteCallback did_swap_buffer_complete_callback);
- ~SkiaOutputDeviceVulkanSecondaryCBOffscreen() override;
-
- SkSurface* BeginPaint(
- bool allocate_frame_buffer,
- std::vector<GrBackendSemaphore>* end_semaphores) override;
- void SwapBuffers(BufferPresentedCallback feedback,
- OutputSurfaceFrame frame) override;
-};
-
-} // namespace viz
-
-#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SKIA_OUTPUT_DEVICE_VULKAN_SECONDARY_CB_OFFSCREEN_H_
diff --git a/chromium/components/viz/service/display_embedder/skia_output_surface_dependency.h b/chromium/components/viz/service/display_embedder/skia_output_surface_dependency.h
index e23d981bb3e..43dadb7bff8 100644
--- a/chromium/components/viz/service/display_embedder/skia_output_surface_dependency.h
+++ b/chromium/components/viz/service/display_embedder/skia_output_surface_dependency.h
@@ -96,7 +96,7 @@ class VIZ_SERVICE_EXPORT SkiaOutputSurfaceDependency {
// called only from GPU Thread.
virtual void ScheduleDelayedGPUTaskFromGPUThread(base::OnceClosure task) = 0;
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
virtual void DidCreateAcceleratedSurfaceChildWindow(
gpu::SurfaceHandle parent_window,
gpu::SurfaceHandle child_window) = 0;
diff --git a/chromium/components/viz/service/display_embedder/skia_output_surface_dependency_impl.cc b/chromium/components/viz/service/display_embedder/skia_output_surface_dependency_impl.cc
index b4c7b282f86..342f27f9daf 100644
--- a/chromium/components/viz/service/display_embedder/skia_output_surface_dependency_impl.cc
+++ b/chromium/components/viz/service/display_embedder/skia_output_surface_dependency_impl.cc
@@ -54,7 +54,7 @@ SkiaOutputSurfaceDependencyImpl::GetGpuDriverBugWorkarounds() {
scoped_refptr<gpu::SharedContextState>
SkiaOutputSurfaceDependencyImpl::GetSharedContextState() {
if (gpu_service_impl_->compositor_gpu_thread()) {
- return gpu_service_impl_->compositor_gpu_thread()->shared_context_state();
+ return gpu_service_impl_->compositor_gpu_thread()->GetSharedContextState();
}
return gpu_service_impl_->GetContextState();
}
@@ -143,7 +143,7 @@ void SkiaOutputSurfaceDependencyImpl::ScheduleDelayedGPUTaskFromGPUThread(
FROM_HERE, std::move(task), kDelayForDelayedWork);
}
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
void SkiaOutputSurfaceDependencyImpl::DidCreateAcceleratedSurfaceChildWindow(
gpu::SurfaceHandle parent_window,
gpu::SurfaceHandle child_window) {
diff --git a/chromium/components/viz/service/display_embedder/skia_output_surface_dependency_impl.h b/chromium/components/viz/service/display_embedder/skia_output_surface_dependency_impl.h
index 32ee3a8e6cf..d8d90afe2ee 100644
--- a/chromium/components/viz/service/display_embedder/skia_output_surface_dependency_impl.h
+++ b/chromium/components/viz/service/display_embedder/skia_output_surface_dependency_impl.h
@@ -56,7 +56,7 @@ class VIZ_SERVICE_EXPORT SkiaOutputSurfaceDependencyImpl
void ScheduleGrContextCleanup() override;
void ScheduleDelayedGPUTaskFromGPUThread(base::OnceClosure task) override;
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
void DidCreateAcceleratedSurfaceChildWindow(
gpu::SurfaceHandle parent_window,
gpu::SurfaceHandle child_window) override;
diff --git a/chromium/components/viz/service/display_embedder/skia_output_surface_impl.cc b/chromium/components/viz/service/display_embedder/skia_output_surface_impl.cc
index 724679ecae7..a07f5e4f9f3 100644
--- a/chromium/components/viz/service/display_embedder/skia_output_surface_impl.cc
+++ b/chromium/components/viz/service/display_embedder/skia_output_surface_impl.cc
@@ -5,16 +5,17 @@
#include "components/viz/service/display_embedder/skia_output_surface_impl.h"
#include <memory>
+#include <tuple>
#include <utility>
#include <vector>
#include "base/bind.h"
#include "base/callback_helpers.h"
-#include "base/ignore_result.h"
#include "base/no_destructor.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
+#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
#include "components/viz/common/frame_sinks/begin_frame_source.h"
#include "components/viz/common/frame_sinks/copy_output_request.h"
@@ -48,7 +49,7 @@
#include "gpu/vulkan/vulkan_device_queue.h"
#endif // BUILDFLAG(ENABLE_VULKAN)
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include "components/viz/service/display/dc_layer_overlay.h"
#endif
@@ -214,7 +215,7 @@ SkiaOutputSurfaceImpl::~SkiaOutputSurfaceImpl() {
EnqueueGpuTask(std::move(task), {}, /*make_current=*/false,
/*need_framebuffer=*/false);
// Flush GPU tasks and block until all tasks are finished.
- FlushGpuTasks(/*wait_for_finish=*/true);
+ FlushGpuTasks(SyncMode::kWaitForTasksFinished);
}
gpu::SurfaceHandle SkiaOutputSurfaceImpl::GetSurfaceHandle() const {
@@ -279,7 +280,7 @@ void SkiaOutputSurfaceImpl::RecreateRootRecorder() {
root_recorder_.emplace(characterization_);
// This will trigger the lazy initialization of the recorder
- ignore_result(root_recorder_->getCanvas());
+ std::ignore = root_recorder_->getCanvas();
}
void SkiaOutputSurfaceImpl::Reshape(const gfx::Size& size,
@@ -307,7 +308,7 @@ void SkiaOutputSurfaceImpl::Reshape(const gfx::Size& size,
use_stencil, GetDisplayTransform());
EnqueueGpuTask(std::move(task), {}, /*make_current=*/true,
/*need_framebuffer=*/!dependency_->IsOffscreen());
- FlushGpuTasks(/*wait_for_finish=*/false);
+ FlushGpuTasks(SyncMode::kNoWait);
color_space_ = color_space;
is_hdr_ = color_space_.IsHDR();
@@ -382,6 +383,7 @@ void SkiaOutputSurfaceImpl::MakePromiseSkImage(ImageContext* image_context) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(current_paint_);
DCHECK(!image_context->mailbox_holder().mailbox.IsZero());
+ TRACE_EVENT0("viz", "SkiaOutputSurfaceImpl::MakePromiseSkImage");
images_in_current_paint_.push_back(
static_cast<ImageContextImpl*>(image_context));
@@ -394,7 +396,7 @@ void SkiaOutputSurfaceImpl::MakePromiseSkImage(ImageContext* image_context) {
if (sync_token.HasData() &&
!sync_point_manager->IsSyncTokenReleased(sync_token)) {
gpu_task_sync_tokens_.push_back(sync_token);
- FlushGpuTasks(/*wait_for_finish=*/true);
+ FlushGpuTasks(SyncMode::kWaitForTasksStarted);
image_context->mutable_mailbox_holder()->sync_token.Clear();
}
@@ -495,10 +497,12 @@ SkiaOutputSurfaceImpl::CreateImageContext(
ResourceFormat format,
bool maybe_concurrent_reads,
const absl::optional<gpu::VulkanYCbCrInfo>& ycbcr_info,
- sk_sp<SkColorSpace> color_space) {
- return std::make_unique<ImageContextImpl>(holder, size, format,
- maybe_concurrent_reads, ycbcr_info,
- std::move(color_space));
+ sk_sp<SkColorSpace> color_space,
+ bool raw_draw_if_possible) {
+ return std::make_unique<ImageContextImpl>(
+ holder, size, format, maybe_concurrent_reads, ycbcr_info,
+ std::move(color_space),
+ /*allow_keeping_read_access=*/true, raw_draw_if_possible);
}
void SkiaOutputSurfaceImpl::SwapBuffers(OutputSurfaceFrame frame) {
@@ -611,7 +615,7 @@ SkCanvas* SkiaOutputSurfaceImpl::BeginPaintRenderPass(
return current_paint_->recorder()->getCanvas();
}
-#if defined(OS_APPLE) || defined(USE_OZONE)
+#if BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
SkCanvas* SkiaOutputSurfaceImpl::BeginPaintRenderPassOverlay(
const gfx::Size& size,
ResourceFormat format,
@@ -640,7 +644,7 @@ SkiaOutputSurfaceImpl::EndPaintRenderPassOverlay() {
current_paint_.reset();
return ddl;
}
-#endif // defined(OS_APPLE) || defined(USE_OZONE)
+#endif // BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
void SkiaOutputSurfaceImpl::EndPaint(base::OnceClosure on_finished) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
@@ -797,7 +801,7 @@ void SkiaOutputSurfaceImpl::ScheduleOverlays(
OverlayList overlays,
std::vector<gpu::SyncToken> sync_tokens,
base::OnceClosure on_finished) {
-#if defined(OS_APPLE) || defined(USE_OZONE)
+#if BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
// If there are render pass overlays, then a gl context is needed for drawing
// the overlay render passes to a backing for being scanned out.
bool make_current =
@@ -848,7 +852,7 @@ bool SkiaOutputSurfaceImpl::Initialize() {
// This runner could be called from vsync or GPU thread after |this| is
// destroyed. We post directly to display compositor thread to check
// |weak_ptr_| as |dependency_| may have been destroyed.
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Callback is never used on Android. Doesn't work with WebView because
// calling it bypasses SkiaOutputSurfaceDependency.
GpuVSyncCallback vsync_callback_runner = base::DoNothing();
@@ -872,7 +876,7 @@ bool SkiaOutputSurfaceImpl::Initialize() {
/*need_framebuffer=*/false);
// |capabilities_| will be initialized in InitializeOnGpuThread(), so have to
// wait.
- FlushGpuTasks(/*wait_for_finish=*/true);
+ FlushGpuTasks(SyncMode::kWaitForTasksFinished);
if (capabilities_.preserve_buffer_content &&
capabilities_.supports_post_sub_buffer) {
@@ -1060,7 +1064,7 @@ void SkiaOutputSurfaceImpl::ScheduleGpuTaskForTesting(
std::vector<gpu::SyncToken> sync_tokens) {
EnqueueGpuTask(std::move(callback), std::move(sync_tokens),
/*make_current=*/false, /*need_framebuffer=*/false);
- FlushGpuTasks(/*wait_for_finish=*/false);
+ FlushGpuTasks(SyncMode::kNoWait);
}
void SkiaOutputSurfaceImpl::EnqueueGpuTask(
@@ -1078,14 +1082,17 @@ void SkiaOutputSurfaceImpl::EnqueueGpuTask(
need_framebuffer_ |= need_framebuffer;
}
-void SkiaOutputSurfaceImpl::FlushGpuTasks(bool wait_for_finish) {
+void SkiaOutputSurfaceImpl::FlushGpuTasks(SyncMode sync_mode) {
+ TRACE_EVENT1("viz", "SkiaOutputSurfaceImpl::FlushGpuTasks", "sync_mode",
+ sync_mode);
// If |wait_for_finish| is true, a GPU task will be always scheduled to make
// sure all pending tasks are finished on the GPU thread.
- if (gpu_tasks_.empty() && !wait_for_finish)
+ if (gpu_tasks_.empty() && sync_mode == SyncMode::kNoWait)
return;
- auto event =
- wait_for_finish ? std::make_unique<base::WaitableEvent>() : nullptr;
+ auto event = sync_mode != SyncMode::kNoWait
+ ? std::make_unique<base::WaitableEvent>()
+ : nullptr;
base::TimeTicks post_task_timestamp;
if (should_measure_next_post_task_) {
@@ -1093,9 +1100,12 @@ void SkiaOutputSurfaceImpl::FlushGpuTasks(bool wait_for_finish) {
}
auto callback = base::BindOnce(
- [](std::vector<GpuTask> tasks, base::WaitableEvent* event,
- SkiaOutputSurfaceImplOnGpu* impl_on_gpu, bool make_current,
- bool need_framebuffer, base::TimeTicks post_task_timestamp) {
+ [](std::vector<GpuTask> tasks, SyncMode sync_mode,
+ base::WaitableEvent* event, SkiaOutputSurfaceImplOnGpu* impl_on_gpu,
+ bool make_current, bool need_framebuffer,
+ base::TimeTicks post_task_timestamp) {
+ if (sync_mode == SyncMode::kWaitForTasksStarted)
+ event->Signal();
gpu::ContextUrl::SetActiveUrl(GetActiveUrl());
// impl_on_gpu can be null during destruction.
if (impl_on_gpu) {
@@ -1111,11 +1121,12 @@ void SkiaOutputSurfaceImpl::FlushGpuTasks(bool wait_for_finish) {
for (auto& task : tasks) {
std::move(task).Run();
}
- if (event)
+
+ if (sync_mode == SyncMode::kWaitForTasksFinished)
event->Signal();
},
- std::move(gpu_tasks_), event.get(), impl_on_gpu_.get(), make_current_,
- need_framebuffer_, post_task_timestamp);
+ std::move(gpu_tasks_), sync_mode, event.get(), impl_on_gpu_.get(),
+ make_current_, need_framebuffer_, post_task_timestamp);
gpu::GpuTaskSchedulerHelper::ReportingCallback reporting_callback;
if (should_measure_next_post_task_) {
@@ -1160,14 +1171,14 @@ GrBackendFormat SkiaOutputSurfaceImpl::GetGrBackendFormatForTexture(
->GetDeviceQueue()
->GetVulkanPhysicalDevice(),
VK_IMAGE_TILING_OPTIMAL, ycbcr_info);
-#if defined(OS_LINUX)
+#if BUILDFLAG(IS_LINUX)
// Textures that were allocated _on linux_ with ycbcr info came from
// VaapiVideoDecoder, which exports using DRM format modifiers.
return GrBackendFormat::MakeVk(gr_ycbcr_info,
/*willUseDRMFormatModifiers=*/true);
#else
return GrBackendFormat::MakeVk(gr_ycbcr_info);
-#endif // defined(OS_LINUX)
+#endif // BUILDFLAG(IS_LINUX)
#endif // BUILDFLAG(ENABLE_VULKAN)
} else if (dependency_->IsUsingDawn()) {
#if BUILDFLAG(SKIA_USE_DAWN)
@@ -1175,7 +1186,7 @@ GrBackendFormat SkiaOutputSurfaceImpl::GetGrBackendFormatForTexture(
return GrBackendFormat::MakeDawn(format);
#endif
} else if (dependency_->IsUsingMetal()) {
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
return GrBackendFormat::MakeMtl(ToMTLPixelFormat(resource_format));
#endif
} else {
@@ -1308,7 +1319,7 @@ gpu::SyncToken SkiaOutputSurfaceImpl::Flush() {
base::Unretained(impl_on_gpu_.get()), sync_fence_release_);
EnqueueGpuTask(std::move(callback), {}, /*make_current=*/false,
/*need_framebuffer=*/false);
- FlushGpuTasks(/*wait_for_finish=*/false);
+ FlushGpuTasks(SyncMode::kNoWait);
return sync_token;
}
diff --git a/chromium/components/viz/service/display_embedder/skia_output_surface_impl.h b/chromium/components/viz/service/display_embedder/skia_output_surface_impl.h
index 61dcdbef84a..d55985b4f99 100644
--- a/chromium/components/viz/service/display_embedder/skia_output_surface_impl.h
+++ b/chromium/components/viz/service/display_embedder/skia_output_surface_impl.h
@@ -153,7 +153,7 @@ class VIZ_SERVICE_EXPORT SkiaOutputSurfaceImpl : public SkiaOutputSurface {
gpu::SyncToken Flush() override;
void OnObservingBeginFrameSourceChanged(bool observing) override;
-#if defined(OS_APPLE) || defined(USE_OZONE)
+#if BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
SkCanvas* BeginPaintRenderPassOverlay(
const gfx::Size& size,
ResourceFormat format,
@@ -171,7 +171,8 @@ class VIZ_SERVICE_EXPORT SkiaOutputSurfaceImpl : public SkiaOutputSurface {
ResourceFormat format,
bool maybe_concurrent_reads,
const absl::optional<gpu::VulkanYCbCrInfo>& ycbcr_info,
- sk_sp<SkColorSpace> color_space) override;
+ sk_sp<SkColorSpace> color_space,
+ bool raw_draw_if_possible) override;
void InitDelegatedInkPointRendererReceiver(
mojo::PendingReceiver<gfx::mojom::DelegatedInkPointRenderer>
@@ -210,7 +211,12 @@ class VIZ_SERVICE_EXPORT SkiaOutputSurfaceImpl : public SkiaOutputSurface {
bool make_current,
bool need_framebuffer);
- void FlushGpuTasks(bool wait_for_finish);
+ enum class SyncMode {
+ kNoWait = 0,
+ kWaitForTasksStarted = 1,
+ kWaitForTasksFinished = 2,
+ };
+ void FlushGpuTasks(SyncMode sync_mode);
GrBackendFormat GetGrBackendFormatForTexture(
ResourceFormat resource_format,
uint32_t gl_texture_target,
diff --git a/chromium/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc b/chromium/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
index e2bf0d5dde5..eb35a45820e 100644
--- a/chromium/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
+++ b/chromium/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
@@ -9,11 +9,13 @@
#include "base/atomic_sequence_num.h"
#include "base/bind.h"
#include "base/callback_helpers.h"
+#include "base/debug/crash_logging.h"
#include "base/memory/raw_ptr.h"
#include "base/task/bind_post_task.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/trace_event/memory_dump_manager.h"
#include "base/trace_event/trace_event.h"
+#include "build/build_config.h"
#include "components/viz/common/features.h"
#include "components/viz/common/frame_sinks/copy_output_request.h"
#include "components/viz/common/frame_sinks/copy_output_util.h"
@@ -61,9 +63,8 @@
#if BUILDFLAG(ENABLE_VULKAN)
#include "components/viz/service/display_embedder/skia_output_device_vulkan.h"
#include "gpu/vulkan/vulkan_util.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "components/viz/service/display_embedder/skia_output_device_vulkan_secondary_cb.h"
-#include "components/viz/service/display_embedder/skia_output_device_vulkan_secondary_cb_offscreen.h"
#endif
#endif
@@ -84,12 +85,12 @@
#if BUILDFLAG(SKIA_USE_DAWN)
#include "components/viz/common/gpu/dawn_context_provider.h"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include "components/viz/service/display_embedder/skia_output_device_dawn.h"
#endif
#endif
-#if defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_FUCHSIA)
#include "components/viz/service/display_embedder/output_presenter_fuchsia.h"
#endif
@@ -116,6 +117,13 @@ base::RepeatingCallback<void(Args...)> CreateSafeRepeatingCallback(
callback);
}
+void FailedSkiaFlush(base::StringPiece msg) {
+ static auto* kCrashKey = base::debug::AllocateCrashKeyString(
+ "sk_flush_failed", base::debug::CrashKeySize::Size64);
+ base::debug::SetCrashKeyString(kCrashKey, msg);
+ LOG(ERROR) << msg;
+}
+
#if BUILDFLAG(ENABLE_VULKAN)
// Returns whether SkiaOutputDeviceX11 can be instantiated on this platform.
bool MayFallBackToSkiaOutputDeviceX11() {
@@ -464,7 +472,7 @@ void SkiaOutputSurfaceImplOnGpu::FinishPaintCurrentFrame(
if (result != GrSemaphoresSubmitted::kYes &&
!(begin_semaphores.empty() && end_semaphores_empty)) {
// TODO(penghuang): handle vulkan device lost.
- DLOG(ERROR) << "output_sk_surface()->flush() failed.";
+ FailedSkiaFlush("output_sk_surface()->flush() failed.");
return;
}
}
@@ -585,7 +593,7 @@ void SkiaOutputSurfaceImplOnGpu::FinishPaintRenderPass(
if (result != GrSemaphoresSubmitted::kYes &&
!(begin_semaphores.empty() && end_semaphores.empty())) {
// TODO(penghuang): handle vulkan device lost.
- DLOG(ERROR) << "offscreen.surface()->flush() failed.";
+ FailedSkiaFlush("offscreen.surface()->flush() failed.");
return;
}
bool sync_cpu =
@@ -768,7 +776,7 @@ bool SkiaOutputSurfaceImplOnGpu::RenderSurface(
if (flush_result != GrSemaphoresSubmitted::kYes &&
!(begin_semaphores.empty() && end_semaphores.empty())) {
// TODO(penghuang): handle vulkan device lost.
- DLOG(ERROR) << "dest_surface->flush() failed.";
+ FailedSkiaFlush("dest_surface->flush() failed.");
return false;
}
@@ -1023,7 +1031,7 @@ void SkiaOutputSurfaceImplOnGpu::CopyOutputNV12(
if (flush_result != GrSemaphoresSubmitted::kYes &&
!(begin_semaphores.empty() && end_semaphores.empty())) {
// TODO(penghuang): handle vulkan device lost.
- DLOG(ERROR) << "plane_surfaces[i]->flush() failed for i=" << i;
+ FailedSkiaFlush("plane_surfaces[i]->flush()");
return;
}
}
@@ -1252,7 +1260,7 @@ void SkiaOutputSurfaceImplOnGpu::CopyOutput(
if (flush_result != GrSemaphoresSubmitted::kYes &&
!(begin_semaphores.empty() && end_semaphores.empty())) {
// TODO(penghuang): handle vulkan device lost.
- DLOG(ERROR) << "surface->flush() failed.";
+ FailedSkiaFlush("surface->flush() failed.");
return;
}
}
@@ -1357,7 +1365,7 @@ void SkiaOutputSurfaceImplOnGpu::ScheduleOverlays(
SkiaOutputSurface::OverlayList overlays,
std::vector<ImageContextImpl*> image_contexts,
base::OnceClosure on_finished) {
-#if defined(OS_APPLE) || defined(USE_OZONE)
+#if BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
if (context_is_lost_)
return;
@@ -1511,19 +1519,20 @@ bool SkiaOutputSurfaceImplOnGpu::InitializeForGL() {
if (MakeCurrent(/*need_framebuffer=*/true)) {
if (gl_surface_->IsSurfaceless()) {
#if defined(USE_OZONE)
- bool needs_background_image = ui::OzonePlatform::GetInstance()
- ->GetPlatformProperties()
- .needs_background_image;
- bool supports_non_backed_solid_color_images =
+ [[maybe_unused]] bool needs_background_image =
+ ui::OzonePlatform::GetInstance()
+ ->GetPlatformRuntimeProperties()
+ .needs_background_image;
+ [[maybe_unused]] bool supports_non_backed_solid_color_images =
ui::OzonePlatform::GetInstance()
->GetPlatformRuntimeProperties()
.supports_non_backed_solid_color_buffers;
#else // defined(USE_OZONE)
- bool needs_background_image = false;
- bool supports_non_backed_solid_color_images = false;
+ [[maybe_unused]] bool needs_background_image = false;
+ [[maybe_unused]] bool supports_non_backed_solid_color_images = false;
#endif // !defined(USE_OZONE)
-#if !defined(OS_WIN)
+#if !BUILDFLAG(IS_WIN)
output_device_ = std::make_unique<SkiaOutputDeviceBufferQueue>(
std::make_unique<OutputPresenterGL>(
gl_surface_, dependency_, shared_image_factory_.get(),
@@ -1532,11 +1541,9 @@ bool SkiaOutputSurfaceImplOnGpu::InitializeForGL() {
shared_gpu_deps_->memory_tracker(),
GetDidSwapBuffersCompleteCallback(), needs_background_image,
supports_non_backed_solid_color_images);
-#else // !defined(OS_WIN)
+#else // !BUILDFLAG(IS_WIN)
NOTIMPLEMENTED();
- ALLOW_UNUSED_LOCAL(needs_background_image);
- ALLOW_UNUSED_LOCAL(supports_non_backed_solid_color_images);
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
} else {
if (dependency_->NeedsSupportForExternalStencil()) {
output_device_ = std::make_unique<SkiaOutputDeviceWebView>(
@@ -1573,38 +1580,31 @@ bool SkiaOutputSurfaceImplOnGpu::InitializeForVulkan() {
return true;
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
if (vulkan_context_provider_->GetGrSecondaryCBDrawContext()) {
- if (base::FeatureList::IsEnabled(
- features::kWebViewVulkanIntermediateBuffer)) {
- output_device_ =
- std::make_unique<SkiaOutputDeviceVulkanSecondaryCBOffscreen>(
- context_state_, shared_gpu_deps_->memory_tracker(),
- GetDidSwapBuffersCompleteCallback());
- } else {
- output_device_ = std::make_unique<SkiaOutputDeviceVulkanSecondaryCB>(
- vulkan_context_provider_, shared_gpu_deps_->memory_tracker(),
- GetDidSwapBuffersCompleteCallback());
- }
+ output_device_ = std::make_unique<SkiaOutputDeviceVulkanSecondaryCB>(
+ vulkan_context_provider_, shared_gpu_deps_->memory_tracker(),
+ GetDidSwapBuffersCompleteCallback());
return true;
}
#endif
#if defined(USE_OZONE)
- bool needs_background_image = ui::OzonePlatform::GetInstance()
- ->GetPlatformProperties()
- .needs_background_image;
- bool supports_non_backed_solid_color_images =
+ [[maybe_unused]] bool needs_background_image =
+ ui::OzonePlatform::GetInstance()
+ ->GetPlatformRuntimeProperties()
+ .needs_background_image;
+ [[maybe_unused]] bool supports_non_backed_solid_color_images =
ui::OzonePlatform::GetInstance()
->GetPlatformRuntimeProperties()
.supports_non_backed_solid_color_buffers;
#else // defined(USE_OZONE)
- bool needs_background_image = false;
- bool supports_non_backed_solid_color_images = false;
+ [[maybe_unused]] bool needs_background_image = false;
+ [[maybe_unused]] bool supports_non_backed_solid_color_images = false;
#endif // !defined(USE_OZONE)
-#if !defined(OS_WIN)
-#if defined(OS_FUCHSIA)
+#if !BUILDFLAG(IS_WIN)
+#if BUILDFLAG(IS_FUCHSIA)
auto output_presenter = OutputPresenterFuchsia::Create(
window_surface_.get(), dependency_, shared_image_factory_.get(),
shared_image_representation_factory_.get());
@@ -1625,9 +1625,7 @@ bool SkiaOutputSurfaceImplOnGpu::InitializeForVulkan() {
needs_background_image, supports_non_backed_solid_color_images);
return true;
}
-#endif // !defined(OS_WIN)
- ALLOW_UNUSED_LOCAL(needs_background_image);
- ALLOW_UNUSED_LOCAL(supports_non_backed_solid_color_images);
+#endif // !BUILDFLAG(IS_WIN)
std::unique_ptr<SkiaOutputDeviceVulkan> output_device;
if (!gpu_preferences_.disable_vulkan_surface) {
@@ -1653,13 +1651,13 @@ bool SkiaOutputSurfaceImplOnGpu::InitializeForVulkan() {
if (!output_device)
return false;
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
gpu::SurfaceHandle child_surface = output_device->GetChildSurfaceHandle();
if (child_surface != gpu::kNullSurfaceHandle) {
DidCreateAcceleratedSurfaceChildWindow(dependency_->GetSurfaceHandle(),
child_surface);
}
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
output_device_ = std::move(output_device);
return true;
}
@@ -1687,7 +1685,7 @@ bool SkiaOutputSurfaceImplOnGpu::InitializeForDawn() {
shared_gpu_deps_->memory_tracker(),
GetDidSwapBuffersCompleteCallback());
}
-#elif defined(OS_WIN)
+#elif BUILDFLAG(IS_WIN)
std::unique_ptr<SkiaOutputDeviceDawn> output_device =
std::make_unique<SkiaOutputDeviceDawn>(
dawn_context_provider_, dependency_->GetSurfaceHandle(),
@@ -1748,7 +1746,7 @@ void SkiaOutputSurfaceImplOnGpu::SwapBuffersInternal(
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(output_device_);
-#if defined(OS_APPLE) || defined(USE_OZONE)
+#if BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
// Release any backings which are not reused by the current frame, probably
// because the properties of render passes are changed or render passes are
// removed
@@ -1800,8 +1798,6 @@ void SkiaOutputSurfaceImplOnGpu::PostSubmit(
if (output_surface_plane_)
DCHECK(output_device_->IsPrimaryPlaneOverlay());
- output_device_->SchedulePrimaryPlane(output_surface_plane_);
- output_surface_plane_.reset();
if (frame->sub_buffer_rect) {
if (capabilities().supports_post_sub_buffer) {
@@ -1811,6 +1807,17 @@ void SkiaOutputSurfaceImplOnGpu::PostSubmit(
frame->sub_buffer_rect->y() -
frame->sub_buffer_rect->height());
}
+ }
+
+ if (output_surface_plane_)
+ output_surface_plane_->damage_rect = frame->sub_buffer_rect;
+ }
+
+ output_device_->SchedulePrimaryPlane(output_surface_plane_);
+ output_surface_plane_.reset();
+
+ if (frame->sub_buffer_rect) {
+ if (capabilities().supports_post_sub_buffer) {
output_device_->PostSubBuffer(*frame->sub_buffer_rect,
buffer_presented_callback_,
std::move(*frame));
@@ -1837,7 +1844,7 @@ bool SkiaOutputSurfaceImplOnGpu::IsDisplayedAsOverlay() {
return output_device_->IsPrimaryPlaneOverlay();
}
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
void SkiaOutputSurfaceImplOnGpu::DidCreateAcceleratedSurfaceChildWindow(
gpu::SurfaceHandle parent_window,
gpu::SurfaceHandle child_window) {
@@ -1898,7 +1905,7 @@ void SkiaOutputSurfaceImplOnGpu::DidSwapBuffersCompleteInternal(
waiting_for_full_damage_ = true;
}
-#if defined(OS_APPLE) || defined(USE_OZONE)
+#if BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
// |available_render_pass_overlay_backings_| are used or released in
// SwapBuffers() for every frames. For Ozone-Wayland
// |available_render_pass_overlay_backings_| is not always empty because the
@@ -1987,7 +1994,7 @@ void SkiaOutputSurfaceImplOnGpu::PreserveChildSurfaceControls() {
gl_surface_->PreserveChildSurfaceControls();
}
-#if defined(OS_APPLE) || defined(USE_OZONE)
+#if BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
std::unique_ptr<gpu::SharedImageRepresentationSkia>
SkiaOutputSurfaceImplOnGpu::GetOrCreateRenderPassOverlayBacking(
const SkSurfaceCharacterization& characterization) {
@@ -2054,7 +2061,7 @@ SkiaOutputSurfaceImplOnGpu::GetOrCreateRenderPassOverlayBacking(
return backing;
}
-#endif // defined(OS_APPLE) || defined(USE_OZONE)
+#endif // BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
void SkiaOutputSurfaceImplOnGpu::InitDelegatedInkPointRendererReceiver(
mojo::PendingReceiver<gfx::mojom::DelegatedInkPointRenderer>
diff --git a/chromium/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h b/chromium/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h
index 99038b6556f..e815e57cf65 100644
--- a/chromium/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h
+++ b/chromium/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h
@@ -207,7 +207,7 @@ class SkiaOutputSurfaceImplOnGpu
void OnContextLost() override;
// gpu::ImageTransportSurfaceDelegate implementation:
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
void DidCreateAcceleratedSurfaceChildWindow(
gpu::SurfaceHandle parent_window,
gpu::SurfaceHandle child_window) override;
@@ -380,7 +380,7 @@ class SkiaOutputSurfaceImplOnGpu
void ReleaseAsyncReadResultHelpers();
-#if defined(OS_APPLE) || defined(USE_OZONE)
+#if BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
std::unique_ptr<gpu::SharedImageRepresentationSkia>
GetOrCreateRenderPassOverlayBacking(
const SkSurfaceCharacterization& characterization);
@@ -487,7 +487,7 @@ class SkiaOutputSurfaceImplOnGpu
// Tracking for ongoing AsyncReadResults.
base::flat_set<AsyncReadResultHelper*> async_read_result_helpers_;
-#if defined(OS_APPLE) || defined(USE_OZONE)
+#if BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
using UniqueBackingPtr = std::unique_ptr<gpu::SharedImageRepresentationSkia>;
class BackingComparator {
public:
diff --git a/chromium/components/viz/service/display_embedder/software_output_surface.cc b/chromium/components/viz/service/display_embedder/software_output_surface.cc
index bc5a2ae1432..35b4b9dd371 100644
--- a/chromium/components/viz/service/display_embedder/software_output_surface.cc
+++ b/chromium/components/viz/service/display_embedder/software_output_surface.cc
@@ -118,7 +118,7 @@ void SoftwareOutputSurface::SwapBuffersCallback(base::TimeTicks swap_time,
now.SnappedToNextTick(refresh_timebase_, refresh_interval_) - now;
// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
// of lacros-chrome is complete.
-#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
if (needs_swap_size_notifications_)
client_->DidSwapWithSize(pixel_size);
#endif
@@ -149,7 +149,7 @@ gfx::OverlayTransform SoftwareOutputSurface::GetDisplayTransform() {
// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
// of lacros-chrome is complete.
-#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
void SoftwareOutputSurface::SetNeedsSwapSizeNotifications(
bool needs_swap_size_notifications) {
needs_swap_size_notifications_ = needs_swap_size_notifications;
diff --git a/chromium/components/viz/service/display_embedder/software_output_surface.h b/chromium/components/viz/service/display_embedder/software_output_surface.h
index 429dbaf524d..12178dda2d7 100644
--- a/chromium/components/viz/service/display_embedder/software_output_surface.h
+++ b/chromium/components/viz/service/display_embedder/software_output_surface.h
@@ -56,7 +56,7 @@ class VIZ_SERVICE_EXPORT SoftwareOutputSurface : public OutputSurface {
gfx::OverlayTransform GetDisplayTransform() override;
// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
// of lacros-chrome is complete.
-#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
void SetNeedsSwapSizeNotifications(
bool needs_swap_size_notifications) override;
#endif
@@ -78,7 +78,7 @@ class VIZ_SERVICE_EXPORT SoftwareOutputSurface : public OutputSurface {
// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
// of lacros-chrome is complete.
-#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
bool needs_swap_size_notifications_ = false;
#endif
diff --git a/chromium/components/viz/service/display_embedder/viz_process_context_provider.cc b/chromium/components/viz/service/display_embedder/viz_process_context_provider.cc
index a2c36c14edb..57fbcb913fb 100644
--- a/chromium/components/viz/service/display_embedder/viz_process_context_provider.cc
+++ b/chromium/components/viz/service/display_embedder/viz_process_context_provider.cc
@@ -67,7 +67,7 @@ gpu::ContextCreationAttribs CreateAttributes(
attributes.fail_if_major_perf_caveat = false;
attributes.lose_context_when_out_of_memory = true;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
if (renderer_settings.color_space == gfx::ColorSpace::CreateSRGB()) {
attributes.color_space = gpu::COLOR_SPACE_SRGB;
} else if (renderer_settings.color_space ==
@@ -88,7 +88,7 @@ gpu::ContextCreationAttribs CreateAttributes(
}
attributes.enable_swap_timestamps_if_supported = true;
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
return attributes;
}
@@ -99,7 +99,7 @@ void UmaRecordContextLost(ContextLostReason reason) {
gpu::SharedMemoryLimits SharedMemoryLimitsForRendererSettings(
const RendererSettings& renderer_settings) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
return gpu::SharedMemoryLimits::ForDisplayCompositor(
renderer_settings.initial_screen_size);
#else
diff --git a/chromium/components/viz/service/frame_sinks/DEPS b/chromium/components/viz/service/frame_sinks/DEPS
index 5174f6a780e..87132f8e1fb 100644
--- a/chromium/components/viz/service/frame_sinks/DEPS
+++ b/chromium/components/viz/service/frame_sinks/DEPS
@@ -9,8 +9,12 @@ include_rules = [
"+components/viz/service/performance_hint",
"+components/viz/service/surfaces",
"+components/viz/service/transitions",
+ "+gpu/command_buffer/service/shared_context_state.h",
"+gpu/ipc/common",
+ "+gpu/ipc/scheduler_sequence.h",
+ "+gpu/ipc/shared_image_interface_in_process.h",
"+mojo/public",
+ "+media/video",
]
specific_include_rules = {
diff --git a/chromium/components/viz/service/frame_sinks/compositor_frame_sink_impl.cc b/chromium/components/viz/service/frame_sinks/compositor_frame_sink_impl.cc
index a56bb9f995c..c127f8b069e 100644
--- a/chromium/components/viz/service/frame_sinks/compositor_frame_sink_impl.cc
+++ b/chromium/components/viz/service/frame_sinks/compositor_frame_sink_impl.cc
@@ -195,7 +195,7 @@ void CompositorFrameSinkImpl::InitializeCompositorFrameSinkType(
support_->InitializeCompositorFrameSinkType(type);
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
void CompositorFrameSinkImpl::SetThreadIds(
const std::vector<int32_t>& thread_ids) {
support_->SetThreadIds(/*from_untrusted_client=*/true,
diff --git a/chromium/components/viz/service/frame_sinks/compositor_frame_sink_impl.h b/chromium/components/viz/service/frame_sinks/compositor_frame_sink_impl.h
index b824c483eb5..f357891cd2c 100644
--- a/chromium/components/viz/service/frame_sinks/compositor_frame_sink_impl.h
+++ b/chromium/components/viz/service/frame_sinks/compositor_frame_sink_impl.h
@@ -61,7 +61,7 @@ class CompositorFrameSinkImpl : public mojom::CompositorFrameSink {
void DidDeleteSharedBitmap(const SharedBitmapId& id) override;
void InitializeCompositorFrameSinkType(
mojom::CompositorFrameSinkType type) override;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
void SetThreadIds(const std::vector<int32_t>& thread_ids) override;
#endif
diff --git a/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support.cc b/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support.cc
index e4f9db7728d..96a64e568a9 100644
--- a/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support.cc
+++ b/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support.cc
@@ -203,7 +203,7 @@ void CompositorFrameSinkSupport::OnSurfaceActivated(Surface* surface) {
if (!transition_directives.empty()) {
bool started_animation =
surface_animation_manager_.ProcessTransitionDirectives(
- transition_directives, surface->GetSurfaceSavedFrameStorage());
+ transition_directives, surface);
// If we started an animation, then we must need a begin frame for the code
// below to work properly.
@@ -295,6 +295,7 @@ void CompositorFrameSinkSupport::OnSurfaceAggregatedDamage(
damage_rect, expected_display_time);
}
+ current_capture_bounds_ = frame.metadata.capture_bounds;
for (CapturableFrameSink::Client* client : capture_clients_) {
client->OnFrameDamaged(frame_size_in_pixels, damage_rect,
expected_display_time, frame.metadata);
@@ -889,35 +890,56 @@ void CompositorFrameSinkSupport::UpdateNeedsBeginFramesInternal() {
// We require a begin frame if there's a callback pending, or if the client
// requested it, or if the client needs to get some frame timing details.
- bool needs_begin_frame =
+ needs_begin_frame_ =
(client_needs_begin_frame_ || !frame_timing_details_.empty() ||
!pending_surfaces_.empty() ||
(compositor_frame_callback_ && !callback_received_begin_frame_) ||
- surface_animation_manager_.NeedsBeginFrame()) &&
- !bundle_id_.has_value();
+ surface_animation_manager_.NeedsBeginFrame());
- if (needs_begin_frame == added_frame_observer_)
+ if (bundle_id_.has_value()) {
+ // When bundled with other sinks, observation of BeginFrame notifications is
+ // always delegated to the bundle.
+ if (added_frame_observer_) {
+ StopObservingBeginFrameSource();
+ }
+ if (auto* bundle = frame_sink_manager_->GetFrameSinkBundle(*bundle_id_)) {
+ bundle->SetSinkNeedsBeginFrame(frame_sink_id_.sink_id(),
+ needs_begin_frame_);
+ }
+ return;
+ }
+
+ if (needs_begin_frame_ == added_frame_observer_)
return;
- added_frame_observer_ = needs_begin_frame;
- if (needs_begin_frame) {
- begin_frame_source_->AddObserver(this);
- if (power_mode_voter_) {
- power_mode_voter_->VoteFor(
- frame_sink_type_ == mojom::CompositorFrameSinkType::kMediaStream ||
- frame_sink_type_ == mojom::CompositorFrameSinkType::kVideo
- ? power_scheduler::PowerMode::kVideoPlayback
- : power_scheduler::PowerMode::kAnimation);
- }
+ if (needs_begin_frame_) {
+ StartObservingBeginFrameSource();
} else {
- begin_frame_source_->RemoveObserver(this);
- if (power_mode_voter_) {
- power_mode_voter_->ResetVoteAfterTimeout(
- frame_sink_type_ == mojom::CompositorFrameSinkType::kMediaStream ||
- frame_sink_type_ == mojom::CompositorFrameSinkType::kVideo
- ? power_scheduler::PowerModeVoter::kVideoTimeout
- : power_scheduler::PowerModeVoter::kAnimationTimeout);
- }
+ StopObservingBeginFrameSource();
+ }
+}
+
+void CompositorFrameSinkSupport::StartObservingBeginFrameSource() {
+ added_frame_observer_ = true;
+ begin_frame_source_->AddObserver(this);
+ if (power_mode_voter_) {
+ power_mode_voter_->VoteFor(
+ frame_sink_type_ == mojom::CompositorFrameSinkType::kMediaStream ||
+ frame_sink_type_ == mojom::CompositorFrameSinkType::kVideo
+ ? power_scheduler::PowerMode::kVideoPlayback
+ : power_scheduler::PowerMode::kAnimation);
+ }
+}
+
+void CompositorFrameSinkSupport::StopObservingBeginFrameSource() {
+ added_frame_observer_ = false;
+ begin_frame_source_->RemoveObserver(this);
+ if (power_mode_voter_) {
+ power_mode_voter_->ResetVoteAfterTimeout(
+ frame_sink_type_ == mojom::CompositorFrameSinkType::kMediaStream ||
+ frame_sink_type_ == mojom::CompositorFrameSinkType::kVideo
+ ? power_scheduler::PowerModeVoter::kVideoTimeout
+ : power_scheduler::PowerModeVoter::kAnimationTimeout);
}
}
@@ -960,10 +982,19 @@ void CompositorFrameSinkSupport::OnClientCaptureStopped() {
gfx::Rect CompositorFrameSinkSupport::GetCopyOutputRequestRegion(
const VideoCaptureSubTarget& sub_target) const {
- if (!last_activated_surface_id_.is_valid()) {
+ // We will either have a subtree ID or a region capture crop_id, but not both.
+ if (absl::holds_alternative<RegionCaptureCropId>(sub_target)) {
+ const auto it = current_capture_bounds_.bounds().find(
+ absl::get<RegionCaptureCropId>(sub_target));
+ if (it != current_capture_bounds_.bounds().end()) {
+ return it->second;
+ }
return {};
}
+ if (!last_activated_surface_id_.is_valid())
+ return {};
+
Surface* current_surface =
surface_manager_->GetSurfaceForId(last_activated_surface_id_);
DCHECK(current_surface);
@@ -971,11 +1002,6 @@ gfx::Rect CompositorFrameSinkSupport::GetCopyOutputRequestRegion(
return {};
}
- // We will either have a subtree ID or a region capture crop_id, but not both.
- if (absl::holds_alternative<RegionCaptureCropId>(sub_target)) {
- return GetCaptureBounds(absl::get<RegionCaptureCropId>(sub_target));
- }
-
// We can exit early if there is no subtree, otherwise we need to
// intersect the bounds.
const CompositorFrame& frame = current_surface->GetActiveFrame();
@@ -1056,27 +1082,6 @@ int64_t CompositorFrameSinkSupport::ComputeTraceId() {
return (client << 48) | (sink << 32) | trace_sequence_;
}
-gfx::Rect CompositorFrameSinkSupport::GetCaptureBounds(
- const RegionCaptureCropId& crop_id) const {
- DCHECK(!crop_id.is_zero());
- // We don't know what frame contains the bounds associated with |crop_id|,
- // so we do have to iterate through each surface.
- for (const SurfaceId& id : surface_manager_->GetCreatedSurfaceIds()) {
- Surface* surface = surface_manager_->GetSurfaceForId(id);
- if (!surface->HasActiveFrame()) {
- continue;
- }
-
- const RegionCaptureBounds& bounds =
- surface->GetActiveFrameMetadata().capture_bounds;
- const auto it = bounds.bounds().find(crop_id);
- if (it != bounds.bounds().end()) {
- return it->second;
- }
- }
- return {};
-}
-
bool CompositorFrameSinkSupport::ShouldSendBeginFrame(
base::TimeTicks frame_time) {
// We should throttle OnBeginFrame() if it has been less than
@@ -1190,6 +1195,11 @@ bool CompositorFrameSinkSupport::IsEvicted(
last_evicted_local_surface_id_.parent_sequence_number();
}
+SurfaceAnimationManager*
+CompositorFrameSinkSupport::GetSurfaceAnimationManagerForTesting() {
+ return &surface_animation_manager_;
+}
+
void CompositorFrameSinkSupport::DestroySelf() {
// SUBTLE: We explicitly copy `frame_sink_id_` because
// DestroyCompositorFrameSink takes the FrameSinkId by reference and may
diff --git a/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support.h b/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support.h
index 53f65ea10fb..f3a5548db7a 100644
--- a/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support.h
+++ b/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support.h
@@ -10,7 +10,6 @@
#include <vector>
#include "base/callback.h"
-#include "base/compiler_specific.h"
#include "base/containers/flat_set.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/read_only_shared_memory_region.h"
@@ -108,7 +107,9 @@ class VIZ_SERVICE_EXPORT CompositorFrameSinkSupport
return frame_timing_details_;
}
- FrameTimingDetailsMap TakeFrameTimingDetailsMap() WARN_UNUSED_RESULT;
+ bool needs_begin_frame() const { return needs_begin_frame_; }
+
+ [[nodiscard]] FrameTimingDetailsMap TakeFrameTimingDetailsMap();
// Viz hit-test setup is only called when |is_root_| is true (except on
// android webview).
@@ -206,7 +207,7 @@ class VIZ_SERVICE_EXPORT CompositorFrameSinkSupport
void AttachCaptureClient(CapturableFrameSink::Client* client) override;
void DetachCaptureClient(CapturableFrameSink::Client* client) override;
gfx::Rect GetCopyOutputRequestRegion(
- const VideoCaptureSubTarget& specifier) const override;
+ const VideoCaptureSubTarget& sub_target) const override;
void OnClientCaptureStarted() override;
void OnClientCaptureStopped() override;
void RequestCopyOfOutput(
@@ -236,6 +237,12 @@ class VIZ_SERVICE_EXPORT CompositorFrameSinkSupport
bool IsEvicted(const LocalSurfaceId& local_surface_id) const;
+ SurfaceAnimationManager* GetSurfaceAnimationManagerForTesting();
+
+ const RegionCaptureBounds& current_capture_bounds() const {
+ return current_capture_bounds_;
+ }
+
private:
friend class CompositorFrameSinkSupportTest;
friend class DisplayTest;
@@ -266,6 +273,8 @@ class VIZ_SERVICE_EXPORT CompositorFrameSinkSupport
bool IsRoot() const override;
void UpdateNeedsBeginFramesInternal();
+ void StartObservingBeginFrameSource();
+ void StopObservingBeginFrameSource();
// For the sync API calls, if we are blocking a client callback, runs it once
// BeginFrame and FrameAck are done.
@@ -273,12 +282,6 @@ class VIZ_SERVICE_EXPORT CompositorFrameSinkSupport
int64_t ComputeTraceId();
- // Internal logic for determining what region capture bounds are
- // associated with a given |crop_id|. This assumes that we are capturing
- // with |crop_id|, and so a return value of gfx::Rect{} indicates that
- // we shouldn't capture any of the surface.
- gfx::Rect GetCaptureBounds(const RegionCaptureCropId& crop_id) const;
-
void MaybeEvictSurfaces();
void EvictLastActiveSurface();
bool ShouldSendBeginFrame(base::TimeTicks timestamp);
@@ -333,6 +336,9 @@ class VIZ_SERVICE_EXPORT CompositorFrameSinkSupport
// Whether a request for begin frames has been issued.
bool client_needs_begin_frame_ = false;
+ // Whether the sink currently needs begin frames for any reason.
+ bool needs_begin_frame_ = false;
+
// Whether or not a frame observer has been added.
bool added_frame_observer_ = false;
@@ -425,6 +431,9 @@ class VIZ_SERVICE_EXPORT CompositorFrameSinkSupport
// Number of clients that have started video capturing.
uint32_t number_clients_capturing_ = 0;
+ // Region capture bounds associated with the last surface that was aggregated.
+ RegionCaptureBounds current_capture_bounds_;
+
base::WeakPtrFactory<CompositorFrameSinkSupport> weak_factory_{this};
};
diff --git a/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support_unittest.cc b/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support_unittest.cc
index 62ec9257ca1..4e86f15c628 100644
--- a/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support_unittest.cc
+++ b/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support_unittest.cc
@@ -1049,7 +1049,7 @@ TEST_F(CompositorFrameSinkSupportTest, PassesOnBeginFrameAcks) {
support_->SetNeedsBeginFrame(false);
}
-#if defined(OS_MAC) && defined(ARCH_CPU_ARM64)
+#if BUILDFLAG(IS_MAC) && defined(ARCH_CPU_ARM64)
// https://crbug.com/1223023
#define MAYBE_NeedsBeginFrameResetAfterPresentationFeedback \
DISABLED_NeedsBeginFrameResetAfterPresentationFeedback
@@ -1703,8 +1703,11 @@ TEST_F(CompositorFrameSinkSupportTest, GetCopyOutputRequestRegion) {
gfx::Rect{0, 0, 20, 20};
frame_with_crop_id_and_bounds.metadata.capture_bounds =
RegionCaptureBounds{{{crop_id, gfx::Rect{0, 0, 13, 13}}}};
- support_->SubmitCompositorFrame(local_surface_id_,
- std::move(frame_with_crop_id_and_bounds));
+
+ // mark the surface as damaged to update the capture bounds.
+ support_->OnSurfaceAggregatedDamage(
+ /*surface*/ nullptr, local_surface_id_, frame_with_crop_id_and_bounds,
+ gfx::Rect{0, 0, 20, 20}, base::TimeTicks::Now());
EXPECT_EQ((gfx::Rect{0, 0, 13, 13}),
support_->GetCopyOutputRequestRegion(crop_id));
diff --git a/chromium/components/viz/service/frame_sinks/external_begin_frame_source_android.cc b/chromium/components/viz/service/frame_sinks/external_begin_frame_source_android.cc
index 49f8b53bc53..3d2fff7cf92 100644
--- a/chromium/components/viz/service/frame_sinks/external_begin_frame_source_android.cc
+++ b/chromium/components/viz/service/frame_sinks/external_begin_frame_source_android.cc
@@ -4,19 +4,223 @@
#include "components/viz/service/frame_sinks/external_begin_frame_source_android.h"
+#include <dlfcn.h>
+#include <sys/types.h>
+
+#include "base/android/build_info.h"
#include "base/android/jni_android.h"
+#include "base/logging.h"
+#include "base/trace_event/trace_event.h"
#include "components/viz/service/service_jni_headers/ExternalBeginFrameSourceAndroid_jni.h"
+extern "C" {
+typedef struct AChoreographer AChoreographer;
+typedef void (*AChoreographer_frameCallback64)(int64_t, void*);
+typedef void (*AChoreographer_refreshRateCallback)(int64_t, void*);
+
+using pAChoreographer_getInstance = AChoreographer* (*)();
+using pAChoreographer_postFrameCallback64 =
+ void (*)(AChoreographer*, AChoreographer_frameCallback64, void*);
+using pAChoreographer_registerRefreshRateCallback =
+ void (*)(AChoreographer*, AChoreographer_refreshRateCallback, void*);
+using pAChoreographer_unregisterRefreshRateCallback =
+ void (*)(AChoreographer*, AChoreographer_refreshRateCallback, void*);
+}
+
+namespace {
+
+#define LOAD_FUNCTION(lib, func) \
+ do { \
+ func##Fn = reinterpret_cast<p##func>(dlsym(lib, #func)); \
+ if (!func##Fn) { \
+ supported = false; \
+ LOG(ERROR) << "Unable to load function " << #func; \
+ } \
+ } while (0)
+
+struct AChoreographerMethods {
+ static const AChoreographerMethods& Get() {
+ static AChoreographerMethods instance;
+ return instance;
+ }
+
+ bool supported = true;
+ pAChoreographer_getInstance AChoreographer_getInstanceFn;
+ pAChoreographer_postFrameCallback64 AChoreographer_postFrameCallback64Fn;
+ pAChoreographer_registerRefreshRateCallback
+ AChoreographer_registerRefreshRateCallbackFn;
+ pAChoreographer_unregisterRefreshRateCallback
+ AChoreographer_unregisterRefreshRateCallbackFn;
+
+ private:
+ AChoreographerMethods() {
+ void* main_dl_handle = dlopen("libandroid.so", RTLD_NOW);
+ if (!main_dl_handle) {
+ LOG(ERROR) << "Couldnt load libandroid.so";
+ supported = false;
+ return;
+ }
+
+ LOAD_FUNCTION(main_dl_handle, AChoreographer_getInstance);
+ LOAD_FUNCTION(main_dl_handle, AChoreographer_postFrameCallback64);
+ LOAD_FUNCTION(main_dl_handle, AChoreographer_registerRefreshRateCallback);
+ LOAD_FUNCTION(main_dl_handle, AChoreographer_unregisterRefreshRateCallback);
+ }
+ ~AChoreographerMethods() = default;
+};
+
+} // namespace
+
namespace viz {
+class ExternalBeginFrameSourceAndroid::AChoreographerImpl {
+ public:
+ static std::unique_ptr<AChoreographerImpl> Create(
+ ExternalBeginFrameSourceAndroid* client);
+
+ AChoreographerImpl(ExternalBeginFrameSourceAndroid* client,
+ AChoreographer* choreographer);
+ ~AChoreographerImpl();
+
+ void SetEnabled(bool enabled);
+
+ private:
+ static void FrameCallback64(int64_t frame_time_nanos, void* data);
+ static void RefershRateCallback(int64_t vsync_period_nanos, void* data);
+
+ void OnVSync(int64_t frame_time_nanos,
+ base::WeakPtr<AChoreographerImpl>* self);
+ void SetVsyncPeriod(int64_t vsync_period_nanos);
+ void RequestVsyncIfNeeded();
+
+ ExternalBeginFrameSourceAndroid* const client_;
+ AChoreographer* const achoreographer_;
+
+ base::TimeDelta vsync_period_;
+ bool vsync_notification_enabled_ = false;
+ // This is a heap-allocated WeakPtr to this object. The WeakPtr is either
+ // * passed to `postFrameCallback` if there is one (and exactly one) callback
+ // pending. This is in case this is deleted before a pending callback
+ // fires, in which case the callback is responsible for deleting the
+ // WeakPtr.
+ // * or owned by this member variable when there is no pending callback.
+ // Thus whether this is nullptr also indicates whether there is a pending
+ // frame callback.
+ std::unique_ptr<base::WeakPtr<AChoreographerImpl>> self_for_frame_callback_;
+ base::WeakPtrFactory<AChoreographerImpl> weak_ptr_factory_{this};
+};
+
+// static
+std::unique_ptr<ExternalBeginFrameSourceAndroid::AChoreographerImpl>
+ExternalBeginFrameSourceAndroid::AChoreographerImpl::Create(
+ ExternalBeginFrameSourceAndroid* client) {
+ if (base::android::BuildInfo::GetInstance()->sdk_int() <
+ base::android::SDK_VERSION_R) {
+ return nullptr;
+ }
+ if (!AChoreographerMethods::Get().supported)
+ return nullptr;
+
+ AChoreographer* choreographer =
+ AChoreographerMethods::Get().AChoreographer_getInstanceFn();
+ if (!choreographer)
+ return nullptr;
+
+ return std::make_unique<AChoreographerImpl>(client, choreographer);
+}
+
+ExternalBeginFrameSourceAndroid::AChoreographerImpl::AChoreographerImpl(
+ ExternalBeginFrameSourceAndroid* client,
+ AChoreographer* choreographer)
+ : client_(client),
+ achoreographer_(choreographer),
+ vsync_period_(base::Microseconds(16666)) {
+ AChoreographerMethods::Get().AChoreographer_registerRefreshRateCallbackFn(
+ achoreographer_, &RefershRateCallback, this);
+ self_for_frame_callback_ =
+ std::make_unique<base::WeakPtr<AChoreographerImpl>>(
+ weak_ptr_factory_.GetWeakPtr());
+}
+
+ExternalBeginFrameSourceAndroid::AChoreographerImpl::~AChoreographerImpl() {
+ AChoreographerMethods::Get().AChoreographer_unregisterRefreshRateCallbackFn(
+ achoreographer_, &RefershRateCallback, this);
+}
+
+void ExternalBeginFrameSourceAndroid::AChoreographerImpl::SetEnabled(
+ bool enabled) {
+ if (vsync_notification_enabled_ == enabled)
+ return;
+ vsync_notification_enabled_ = enabled;
+ RequestVsyncIfNeeded();
+}
+
+// static
+void ExternalBeginFrameSourceAndroid::AChoreographerImpl::FrameCallback64(
+ int64_t frame_time_nanos,
+ void* data) {
+ TRACE_EVENT0("toplevel,viz", "VSync");
+ auto* self = static_cast<base::WeakPtr<AChoreographerImpl>*>(data);
+ if (!(*self)) {
+ delete self;
+ return;
+ }
+ (*self)->OnVSync(frame_time_nanos, self);
+}
+
+// static
+void ExternalBeginFrameSourceAndroid::AChoreographerImpl::RefershRateCallback(
+ int64_t vsync_period_nanos,
+ void* data) {
+ static_cast<AChoreographerImpl*>(data)->SetVsyncPeriod(vsync_period_nanos);
+}
+
+void ExternalBeginFrameSourceAndroid::AChoreographerImpl::OnVSync(
+ int64_t frame_time_nanos,
+ base::WeakPtr<AChoreographerImpl>* self) {
+ DCHECK(!self_for_frame_callback_);
+ DCHECK(self);
+ self_for_frame_callback_.reset(self);
+ if (vsync_notification_enabled_) {
+ client_->OnVSyncImpl(frame_time_nanos, vsync_period_);
+ RequestVsyncIfNeeded();
+ }
+}
+
+void ExternalBeginFrameSourceAndroid::AChoreographerImpl::SetVsyncPeriod(
+ int64_t vsync_period_nanos) {
+ vsync_period_ = base::Nanoseconds(vsync_period_nanos);
+}
+
+void ExternalBeginFrameSourceAndroid::AChoreographerImpl::
+ RequestVsyncIfNeeded() {
+ if (!vsync_notification_enabled_ || !self_for_frame_callback_)
+ return;
+ AChoreographerMethods::Get().AChoreographer_postFrameCallback64Fn(
+ achoreographer_, &FrameCallback64, self_for_frame_callback_.release());
+}
+
+// ============================================================================
+
ExternalBeginFrameSourceAndroid::ExternalBeginFrameSourceAndroid(
uint32_t restart_id,
- float refresh_rate)
- : ExternalBeginFrameSource(this, restart_id),
- j_object_(Java_ExternalBeginFrameSourceAndroid_Constructor(
- base::android::AttachCurrentThread(),
- reinterpret_cast<jlong>(this),
- refresh_rate)) {}
+ float refresh_rate,
+ bool requires_align_with_java)
+ : ExternalBeginFrameSource(this, restart_id) {
+ // Android WebView requires begin frame to be inside the "animate" stage of
+ // input-animate-draw stages of the java Choreographer, which requires using
+ // java Choreographer.
+ if (requires_align_with_java) {
+ achoreographer_ = nullptr;
+ } else {
+ achoreographer_ = AChoreographerImpl::Create(this);
+ }
+ if (!achoreographer_) {
+ j_object_ = Java_ExternalBeginFrameSourceAndroid_Constructor(
+ base::android::AttachCurrentThread(), reinterpret_cast<jlong>(this),
+ refresh_rate);
+ }
+}
ExternalBeginFrameSourceAndroid::~ExternalBeginFrameSourceAndroid() {
SetEnabled(false);
@@ -27,6 +231,12 @@ void ExternalBeginFrameSourceAndroid::OnVSync(
const base::android::JavaParamRef<jobject>& obj,
jlong time_micros,
jlong period_micros) {
+ OnVSyncImpl(time_micros * 1000, base::Microseconds(period_micros));
+}
+
+void ExternalBeginFrameSourceAndroid::OnVSyncImpl(
+ int64_t time_nanos,
+ base::TimeDelta vsync_period) {
// Warning: It is generally unsafe to manufacture TimeTicks values. The
// following assumption is being made, AND COULD EASILY BREAK AT ANY TIME:
// Upstream, Java code is providing "System.nanos() / 1000," and this is the
@@ -34,8 +244,7 @@ void ExternalBeginFrameSourceAndroid::OnVSync(
DCHECK_EQ(base::TimeTicks::GetClock(),
base::TimeTicks::Clock::LINUX_CLOCK_MONOTONIC);
base::TimeTicks frame_time =
- base::TimeTicks() + base::Microseconds(time_micros);
- base::TimeDelta vsync_period(base::Microseconds(period_micros));
+ base::TimeTicks() + base::Nanoseconds(time_nanos);
// Calculate the next frame deadline:
base::TimeTicks deadline = frame_time + vsync_period;
@@ -45,8 +254,10 @@ void ExternalBeginFrameSourceAndroid::OnVSync(
}
void ExternalBeginFrameSourceAndroid::UpdateRefreshRate(float refresh_rate) {
- Java_ExternalBeginFrameSourceAndroid_updateRefreshRate(
- base::android::AttachCurrentThread(), j_object_, refresh_rate);
+ if (j_object_) {
+ Java_ExternalBeginFrameSourceAndroid_updateRefreshRate(
+ base::android::AttachCurrentThread(), j_object_, refresh_rate);
+ }
}
void ExternalBeginFrameSourceAndroid::SetDynamicBeginFrameDeadlineOffsetSource(
@@ -62,8 +273,13 @@ void ExternalBeginFrameSourceAndroid::OnNeedsBeginFrames(
}
void ExternalBeginFrameSourceAndroid::SetEnabled(bool enabled) {
- Java_ExternalBeginFrameSourceAndroid_setEnabled(
- base::android::AttachCurrentThread(), j_object_, enabled);
+ if (achoreographer_) {
+ achoreographer_->SetEnabled(enabled);
+ } else {
+ DCHECK(j_object_);
+ Java_ExternalBeginFrameSourceAndroid_setEnabled(
+ base::android::AttachCurrentThread(), j_object_, enabled);
+ }
}
} // namespace viz
diff --git a/chromium/components/viz/service/frame_sinks/external_begin_frame_source_android.h b/chromium/components/viz/service/frame_sinks/external_begin_frame_source_android.h
index c8c7f7fa3f7..3ceaafa52f5 100644
--- a/chromium/components/viz/service/frame_sinks/external_begin_frame_source_android.h
+++ b/chromium/components/viz/service/frame_sinks/external_begin_frame_source_android.h
@@ -6,8 +6,10 @@
#define COMPONENTS_VIZ_SERVICE_FRAME_SINKS_EXTERNAL_BEGIN_FRAME_SOURCE_ANDROID_H_
#include <jni.h>
+#include <memory>
#include "base/android/jni_weak_ref.h"
+#include "base/time/time.h"
#include "components/viz/common/frame_sinks/begin_frame_source.h"
#include "components/viz/service/viz_service_export.h"
@@ -19,7 +21,9 @@ class VIZ_SERVICE_EXPORT ExternalBeginFrameSourceAndroid
: public ExternalBeginFrameSource,
public ExternalBeginFrameSourceClient {
public:
- ExternalBeginFrameSourceAndroid(uint32_t restart_id, float refresh_rate);
+ ExternalBeginFrameSourceAndroid(uint32_t restart_id,
+ float refresh_rate,
+ bool requires_align_with_java);
ExternalBeginFrameSourceAndroid(const ExternalBeginFrameSourceAndroid&) =
delete;
@@ -40,11 +44,15 @@ class VIZ_SERVICE_EXPORT ExternalBeginFrameSourceAndroid
dynamic_begin_frame_deadline_offset_source) override;
private:
+ class AChoreographerImpl;
+
// ExternalBeginFrameSourceClient implementation.
void OnNeedsBeginFrames(bool needs_begin_frames) override;
void SetEnabled(bool enabled);
+ void OnVSyncImpl(int64_t time_nanos, base::TimeDelta vsync_period);
+ std::unique_ptr<AChoreographerImpl> achoreographer_;
base::android::ScopedJavaGlobalRef<jobject> j_object_;
BeginFrameArgsGenerator begin_frame_args_generator_;
};
diff --git a/chromium/components/viz/service/frame_sinks/external_begin_frame_source_android_unittest.cc b/chromium/components/viz/service/frame_sinks/external_begin_frame_source_android_unittest.cc
index 5daad10105b..ba2c5f4d793 100644
--- a/chromium/components/viz/service/frame_sinks/external_begin_frame_source_android_unittest.cc
+++ b/chromium/components/viz/service/frame_sinks/external_begin_frame_source_android_unittest.cc
@@ -14,7 +14,13 @@ namespace viz {
class ExternalBeginFrameSourceAndroidTest : public ::testing::Test,
public BeginFrameObserverBase {
public:
- ~ExternalBeginFrameSourceAndroidTest() override { thread_->Stop(); }
+ ~ExternalBeginFrameSourceAndroidTest() override {
+ thread_->task_runner()->PostTask(
+ FROM_HERE,
+ base::BindOnce(&ExternalBeginFrameSourceAndroidTest::TeardownOnThread,
+ base::Unretained(this)));
+ thread_->Stop();
+ }
void CreateThread() {
thread_ = std::make_unique<base::android::JavaHandlerThread>("TestThread");
@@ -43,9 +49,12 @@ class ExternalBeginFrameSourceAndroidTest : public ::testing::Test,
private:
void InitOnThread() {
begin_frame_source_ = std::make_unique<ExternalBeginFrameSourceAndroid>(
- BeginFrameSource::kNotRestartableId, 60.f);
+ BeginFrameSource::kNotRestartableId, 60.f,
+ /*requires_align_with_java=*/false);
}
+ void TeardownOnThread() { begin_frame_source_.reset(); }
+
void AddObserverOnThread(uint32_t frame_count) {
pending_frames_ = frame_count;
begin_frame_source_->AddObserver(this);
diff --git a/chromium/components/viz/service/frame_sinks/external_begin_frame_source_mojo.cc b/chromium/components/viz/service/frame_sinks/external_begin_frame_source_mojo.cc
index d0d355874d9..9ce1f5a11b2 100644
--- a/chromium/components/viz/service/frame_sinks/external_begin_frame_source_mojo.cc
+++ b/chromium/components/viz/service/frame_sinks/external_begin_frame_source_mojo.cc
@@ -31,6 +31,7 @@ void ExternalBeginFrameSourceMojo::IssueExternalBeginFrame(
bool force,
base::OnceCallback<void(const BeginFrameAck&)> callback) {
DCHECK(!pending_frame_callback_) << "Got overlapping IssueExternalBeginFrame";
+ DCHECK(pending_frame_sinks_.empty());
original_source_id_ = args.frame_id.source_id;
OnBeginFrame(args);
@@ -76,6 +77,12 @@ void ExternalBeginFrameSourceMojo::MaybeProduceFrameCallback() {
return;
if (!pending_frame_callback_)
return;
+
+ if (pending_ack_) {
+ DispatchFrameCallback(*pending_ack_);
+ pending_ack_.reset();
+ return;
+ }
// If there aren't pending surfaces and the root frame is not missing,
// the display scheduler is likely to produce proper frame, so let it do
// its work. Otherwise, fire the pending frame callback early.
@@ -84,29 +91,37 @@ void ExternalBeginFrameSourceMojo::MaybeProduceFrameCallback() {
return;
}
- frame_sink_manager_->DiscardPendingCopyOfOutputRequests(this);
-
// All frame sinks are done with frame, yet the root frame is still missing,
// the display won't draw, so resolve callback now.
BeginFrameAck nak(last_begin_frame_args_.frame_id.source_id,
last_begin_frame_args_.frame_id.sequence_number,
/*has_damage=*/false);
+ DispatchFrameCallback(nak);
+}
+
+void ExternalBeginFrameSourceMojo::DispatchFrameCallback(
+ const BeginFrameAck& ack) {
+ // If there are pending copy output requests that have not been fulfilled,
+ // cancel them, as they won't be served till the next frame. This prevents
+ // the client for waiting for them indefinitely.
+ frame_sink_manager_->DiscardPendingCopyOfOutputRequests(this);
// Prevent missing begin frames from being sent to sinks that came late,
// as this may result in two overlapping frames being sent, which is not
// supported with full pipeline mode.
last_begin_frame_args_ = BeginFrameArgs();
- std::move(pending_frame_callback_).Run(nak);
+ std::move(pending_frame_callback_).Run(ack);
}
void ExternalBeginFrameSourceMojo::OnDisplayDidFinishFrame(
const BeginFrameAck& ack) {
if (!pending_frame_callback_)
return;
- std::move(pending_frame_callback_).Run(ack);
- // If there are pending copy output requests that have not been fulfilled,
- // cancel them, as they won't be served till the next frame. This prevents
- // the client for waiting for them indefinitely.
- frame_sink_manager_->DiscardPendingCopyOfOutputRequests(this);
+ if (!pending_frame_sinks_.empty()) {
+ DCHECK(!pending_ack_);
+ pending_ack_ = ack;
+ return;
+ }
+ DispatchFrameCallback(ack);
}
void ExternalBeginFrameSourceMojo::OnDisplayDestroyed() {
diff --git a/chromium/components/viz/service/frame_sinks/external_begin_frame_source_mojo.h b/chromium/components/viz/service/frame_sinks/external_begin_frame_source_mojo.h
index 592907a4983..ce01240c3be 100644
--- a/chromium/components/viz/service/frame_sinks/external_begin_frame_source_mojo.h
+++ b/chromium/components/viz/service/frame_sinks/external_begin_frame_source_mojo.h
@@ -14,6 +14,7 @@
#include "mojo/public/cpp/bindings/associated_receiver.h"
#include "mojo/public/cpp/bindings/pending_associated_receiver.h"
#include "services/viz/privileged/mojom/compositing/external_begin_frame_controller.mojom.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
namespace viz {
@@ -72,6 +73,7 @@ class VIZ_SERVICE_EXPORT ExternalBeginFrameSourceMojo
const BeginFrameArgs& args) override;
void MaybeProduceFrameCallback();
+ void DispatchFrameCallback(const BeginFrameAck& ack);
const raw_ptr<FrameSinkManagerImpl> frame_sink_manager_;
@@ -88,6 +90,7 @@ class VIZ_SERVICE_EXPORT ExternalBeginFrameSourceMojo
uint64_t original_source_id_ = BeginFrameArgs::kStartingSourceId;
base::flat_set<FrameSinkId> pending_frame_sinks_;
+ absl::optional<BeginFrameAck> pending_ack_;
raw_ptr<Display> display_ = nullptr;
};
diff --git a/chromium/components/viz/service/frame_sinks/frame_sink_bundle_impl.cc b/chromium/components/viz/service/frame_sinks/frame_sink_bundle_impl.cc
index e2126f7f330..22346e8dc53 100644
--- a/chromium/components/viz/service/frame_sinks/frame_sink_bundle_impl.cc
+++ b/chromium/components/viz/service/frame_sinks/frame_sink_bundle_impl.cc
@@ -23,26 +23,56 @@ namespace viz {
// bundled CompositorFrameSink clients who all share a common BeginFrameSource.
// FrameSinkBundleImpls may own any number of SinkGroups, and groups are created
// or destroyed as needed when a sink is added to or removed from the bundle.
+//
+// Note that the BeginFrameSource is only observed by this SinkGroup while there
+// are active FrameSinks present who have explicitly indicated a need for
+// BeginFrame notifications. This avoids generation and processing of unused
+// frame events which might otherwise incur substantial overhead.
class FrameSinkBundleImpl::SinkGroup : public BeginFrameObserver {
public:
SinkGroup(FrameSinkManagerImpl& manager,
FrameSinkBundleImpl& bundle,
BeginFrameSource& source,
mojom::FrameSinkBundleClient& client)
- : manager_(manager), bundle_(bundle), source_(source), client_(client) {
- source_.AddObserver(this);
- }
+ : manager_(manager), bundle_(bundle), source_(source), client_(client) {}
- ~SinkGroup() override { source_.RemoveObserver(this); }
+ ~SinkGroup() override {
+ if (is_observing_begin_frame_) {
+ source_.RemoveObserver(this);
+ }
+ }
bool IsEmpty() const { return frame_sinks_.empty(); }
- void AddFrameSink(uint32_t sink_id) { frame_sinks_.insert(sink_id); }
+ void AddFrameSink(uint32_t sink_id) {
+ frame_sinks_.insert(sink_id);
+
+ FrameSinkId id(bundle_.id().client_id(), sink_id);
+ if (auto* support = manager_.GetFrameSinkForId(id)) {
+ if (support->needs_begin_frame()) {
+ frame_sinks_needing_begin_frame_.insert(sink_id);
+ UpdateBeginFrameObservation();
+ }
+ }
+ }
void RemoveFrameSink(uint32_t sink_id) {
frame_sinks_.erase(sink_id);
unacked_submissions_.erase(sink_id);
FlushMessages();
+
+ frame_sinks_needing_begin_frame_.erase(sink_id);
+ UpdateBeginFrameObservation();
+ }
+
+ void SetNeedsBeginFrame(uint32_t sink_id, bool needs_begin_frame) {
+ if (needs_begin_frame) {
+ frame_sinks_needing_begin_frame_.insert(sink_id);
+ } else {
+ frame_sinks_needing_begin_frame_.erase(sink_id);
+ }
+
+ UpdateBeginFrameObservation();
}
void WillSubmitFrame(uint32_t sink_id) {
@@ -136,6 +166,23 @@ class FrameSinkBundleImpl::SinkGroup : public BeginFrameObserver {
}
private:
+ void UpdateBeginFrameObservation() {
+ bool should_observe_begin_frame = !frame_sinks_needing_begin_frame_.empty();
+ if (should_observe_begin_frame && !is_observing_begin_frame_) {
+ // NOTE: It's important to set this flag before adding the observer,
+ // because AddObserver() can synchronously enter CFSS::OnBeginFrame(),
+ // which can in turn re-enter this method.
+ is_observing_begin_frame_ = true;
+ source_.AddObserver(this);
+ return;
+ }
+
+ if (is_observing_begin_frame_ && !should_observe_begin_frame) {
+ source_.RemoveObserver(this);
+ is_observing_begin_frame_ = false;
+ }
+ }
+
FrameSinkManagerImpl& manager_;
FrameSinkBundleImpl& bundle_;
BeginFrameSource& source_;
@@ -146,6 +193,8 @@ class FrameSinkBundleImpl::SinkGroup : public BeginFrameObserver {
std::vector<mojom::BundledReturnedResourcesPtr> pending_reclaimed_resources_;
std::vector<mojom::BeginFrameInfoPtr> pending_on_begin_frames_;
std::set<uint32_t> frame_sinks_;
+ std::set<uint32_t> frame_sinks_needing_begin_frame_;
+ bool is_observing_begin_frame_ = false;
// Tracks which sinks in the group are still expecting an ack for a previously
// submitted frame.
@@ -169,6 +218,13 @@ FrameSinkBundleImpl::FrameSinkBundleImpl(
FrameSinkBundleImpl::~FrameSinkBundleImpl() = default;
+void FrameSinkBundleImpl::SetSinkNeedsBeginFrame(uint32_t sink_id,
+ bool needs_begin_frame) {
+ if (auto* group = GetSinkGroup(sink_id)) {
+ group->SetNeedsBeginFrame(sink_id, needs_begin_frame);
+ }
+}
+
void FrameSinkBundleImpl::AddFrameSink(CompositorFrameSinkSupport* support) {
uint32_t sink_id = support->frame_sink_id().sink_id();
auto* source = support->begin_frame_source();
@@ -272,7 +328,7 @@ void FrameSinkBundleImpl::DidAllocateSharedBitmap(
}
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
void FrameSinkBundleImpl::SetThreadIds(uint32_t sink_id,
const std::vector<int32_t>& thread_ids) {
if (auto* sink = GetFrameSink(sink_id)) {
diff --git a/chromium/components/viz/service/frame_sinks/frame_sink_bundle_impl.h b/chromium/components/viz/service/frame_sinks/frame_sink_bundle_impl.h
index 486a1de99c1..f7b958ad17b 100644
--- a/chromium/components/viz/service/frame_sinks/frame_sink_bundle_impl.h
+++ b/chromium/components/viz/service/frame_sinks/frame_sink_bundle_impl.h
@@ -51,6 +51,11 @@ class FrameSinkBundleImpl : public mojom::FrameSinkBundle {
const FrameSinkBundleId& id() const { return id_; }
+ // Called by the identified sink itself to notify the bundle that the sink
+ // needs (or no longer needs) BeginFrame notifications. This is distinct from
+ // SetNeedsBeginFrame(), as the latter is only called by clients.
+ void SetSinkNeedsBeginFrame(uint32_t sink_id, bool needs_begin_frame);
+
void AddFrameSink(CompositorFrameSinkSupport* support);
void UpdateFrameSink(CompositorFrameSinkSupport* support,
BeginFrameSource* old_source);
@@ -66,7 +71,7 @@ class FrameSinkBundleImpl : public mojom::FrameSinkBundle {
void DidAllocateSharedBitmap(uint32_t sink_id,
base::ReadOnlySharedMemoryRegion region,
const gpu::Mailbox& id) override;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
void SetThreadIds(uint32_t sink_id,
const std::vector<int32_t>& thread_ids) override;
#endif
diff --git a/chromium/components/viz/service/frame_sinks/frame_sink_bundle_impl_unittest.cc b/chromium/components/viz/service/frame_sinks/frame_sink_bundle_impl_unittest.cc
index 87e67a79134..0b8095e0456 100644
--- a/chromium/components/viz/service/frame_sinks/frame_sink_bundle_impl_unittest.cc
+++ b/chromium/components/viz/service/frame_sinks/frame_sink_bundle_impl_unittest.cc
@@ -266,6 +266,9 @@ class FrameSinkBundleImplTest : public testing::Test {
FrameSinkManagerImpl& manager() { return manager_; }
TestBundleClient& test_client() { return test_client_; }
mojo::Remote<mojom::FrameSinkBundle>& bundle() { return bundle_; }
+ FakeExternalBeginFrameSource& begin_frame_source() {
+ return begin_frame_source_;
+ }
private:
const gpu::SyncToken frame_sync_token_{MakeVerifiedSyncToken(42)};
@@ -300,10 +303,18 @@ TEST_F(FrameSinkBundleImplTest, DestroyOnDisconnect) {
}
TEST_F(FrameSinkBundleImplTest, OnBeginFrame) {
+ // By default the bundle does not observe the BeginFrameSource. The only
+ // observer is the (non-bundled) main-frame sink.
+ EXPECT_EQ(1u, begin_frame_source().num_observers());
+
TestFrameSink frame_a(manager(), kSubFrameA, kMainFrame, kBundleId);
TestFrameSink frame_b(manager(), kSubFrameB, kMainFrame, kBundleId);
TestFrameSink frame_c(manager(), kSubFrameC, kMainFrame, kBundleId);
+ // The bundle should observe the BeginFrameSource on behalf of all its sinks,
+ // so the only observers should now be the main-frame sink and the bundle.
+ EXPECT_EQ(2u, begin_frame_source().num_observers());
+
// OnBeginFrame() should elicit a single batch of notifications to the bundle
// client, with a notification for each frame in the bundle.
std::vector<mojom::BeginFrameInfoPtr> begin_frames;
@@ -320,6 +331,14 @@ TEST_F(FrameSinkBundleImplTest, OnBeginFrame) {
test_client().WaitForNextFlush(nullptr, &begin_frames, nullptr);
EXPECT_THAT(begin_frames,
UnorderedElementsAre(ForSink(kSubFrameA), ForSink(kSubFrameC)));
+
+ // Finally, if all sinks unsubscribe from BeginFrame notifications, the bundle
+ // should stop observing the BeginFrameSource.
+ EXPECT_EQ(2u, begin_frame_source().num_observers());
+ manager().GetFrameSinkForId(kSubFrameA)->SetNeedsBeginFrame(false);
+ EXPECT_EQ(2u, begin_frame_source().num_observers());
+ manager().GetFrameSinkForId(kSubFrameC)->SetNeedsBeginFrame(false);
+ EXPECT_EQ(1u, begin_frame_source().num_observers());
}
TEST_F(FrameSinkBundleImplTest, SubmitAndAck) {
diff --git a/chromium/components/viz/service/frame_sinks/frame_sink_manager_impl.cc b/chromium/components/viz/service/frame_sinks/frame_sink_manager_impl.cc
index a95a9486ac7..632a807dba0 100644
--- a/chromium/components/viz/service/frame_sinks/frame_sink_manager_impl.cc
+++ b/chromium/components/viz/service/frame_sinks/frame_sink_manager_impl.cc
@@ -17,6 +17,7 @@
#include "base/time/time.h"
#include "base/trace_event/trace_event.h"
#include "components/viz/common/surfaces/subtree_capture_id.h"
+#include "components/viz/common/surfaces/video_capture_target.h"
#include "components/viz/service/display/shared_bitmap_manager.h"
#include "components/viz/service/display_embedder/output_surface_provider.h"
#include "components/viz/service/frame_sinks/compositor_frame_sink_support.h"
@@ -25,15 +26,18 @@
#include "components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.h"
#include "components/viz/service/performance_hint/utils.h"
#include "components/viz/service/surfaces/pending_copy_output_request.h"
+#include "components/viz/service/surfaces/surface.h"
namespace viz {
FrameSinkManagerImpl::InitParams::InitParams() = default;
FrameSinkManagerImpl::InitParams::InitParams(
SharedBitmapManager* shared_bitmap_manager,
- OutputSurfaceProvider* output_surface_provider)
+ OutputSurfaceProvider* output_surface_provider,
+ GmbVideoFramePoolContextProvider* gmb_context_provider)
: shared_bitmap_manager(shared_bitmap_manager),
- output_surface_provider(output_surface_provider) {}
+ output_surface_provider(output_surface_provider),
+ gmb_context_provider(gmb_context_provider) {}
FrameSinkManagerImpl::InitParams::InitParams(InitParams&& other) = default;
FrameSinkManagerImpl::InitParams::~InitParams() = default;
FrameSinkManagerImpl::InitParams& FrameSinkManagerImpl::InitParams::operator=(
@@ -64,6 +68,7 @@ operator=(FrameSinkData&& other) = default;
FrameSinkManagerImpl::FrameSinkManagerImpl(const InitParams& params)
: shared_bitmap_manager_(params.shared_bitmap_manager),
output_surface_provider_(params.output_surface_provider),
+ gmb_context_provider_(params.gmb_context_provider),
surface_manager_(this, params.activation_deadline_in_frames),
hit_test_manager_(surface_manager()),
restart_id_(params.restart_id),
@@ -314,7 +319,7 @@ void FrameSinkManagerImpl::AddVideoDetectorObserver(
void FrameSinkManagerImpl::CreateVideoCapturer(
mojo::PendingReceiver<mojom::FrameSinkVideoCapturer> receiver) {
video_capturers_.emplace(std::make_unique<FrameSinkVideoCapturerImpl>(
- this, std::move(receiver),
+ this, gmb_context_provider_, std::move(receiver),
std::make_unique<media::VideoCaptureOracle>(
true /* enable_auto_throttling */),
log_capture_pipeline_in_webrtc_));
@@ -348,15 +353,6 @@ void FrameSinkManagerImpl::RequestCopyOfOutput(
surface_id.local_surface_id(), SubtreeCaptureId(), std::move(request)});
}
-void FrameSinkManagerImpl::SetHitTestAsyncQueriedDebugRegions(
- const FrameSinkId& root_frame_sink_id,
- const std::vector<FrameSinkId>& hit_test_async_queried_debug_queue) {
- hit_test_manager_.SetHitTestAsyncQueriedDebugRegions(
- root_frame_sink_id, hit_test_async_queried_debug_queue);
- DCHECK(base::Contains(root_sink_map_, root_frame_sink_id));
- root_sink_map_[root_frame_sink_id]->ForceImmediateDrawAndSwapIfPossible();
-}
-
void FrameSinkManagerImpl::DestroyFrameSinkBundle(const FrameSinkBundleId& id) {
bundle_map_.erase(id);
}
@@ -512,10 +508,31 @@ void FrameSinkManagerImpl::RecursivelyDetachBeginFrameSource(
}
CapturableFrameSink* FrameSinkManagerImpl::FindCapturableFrameSink(
- const FrameSinkId& frame_sink_id) {
+ const VideoCaptureTarget& target) {
+ // Search the known CompositorFrameSinkSupport objects for region capture
+ // bounds matching the crop ID specified by |target| (if one was set), and
+ // return the corresponding frame sink.
+ if (absl::holds_alternative<RegionCaptureCropId>(target.sub_target)) {
+ const auto crop_id = absl::get<RegionCaptureCropId>(target.sub_target);
+ for (const auto& id_and_sink : support_map_) {
+ const RegionCaptureBounds& bounds =
+ id_and_sink.second->current_capture_bounds();
+ auto match = bounds.bounds().find(crop_id);
+ if (match != bounds.bounds().end()) {
+ return id_and_sink.second;
+ }
+ }
+ return nullptr;
+ }
+
+ FrameSinkId frame_sink_id = target.frame_sink_id;
+ if (!frame_sink_id.is_valid())
+ return nullptr;
+
const auto it = support_map_.find(frame_sink_id);
if (it == support_map_.end())
return nullptr;
+
return it->second;
}
@@ -676,18 +693,18 @@ void FrameSinkManagerImpl::CacheBackBuffer(
const FrameSinkId& root_frame_sink_id) {
auto it = root_sink_map_.find(root_frame_sink_id);
- DCHECK(it != root_sink_map_.end());
- DCHECK(cached_back_buffers_.find(cache_id) == cached_back_buffers_.end());
+ // If creating RootCompositorFrameSinkImpl failed there might not be an entry
+ // in |root_sink_map_|.
+ if (it == root_sink_map_.end())
+ return;
+ DCHECK(!base::Contains(cached_back_buffers_, cache_id));
cached_back_buffers_[cache_id] = it->second->GetCacheBackBufferCb();
}
void FrameSinkManagerImpl::EvictBackBuffer(uint32_t cache_id,
EvictBackBufferCallback callback) {
- auto it = cached_back_buffers_.find(cache_id);
- DCHECK(it != cached_back_buffers_.end());
-
- cached_back_buffers_.erase(it);
+ cached_back_buffers_.erase(cache_id);
std::move(callback).Run();
}
diff --git a/chromium/components/viz/service/frame_sinks/frame_sink_manager_impl.h b/chromium/components/viz/service/frame_sinks/frame_sink_manager_impl.h
index 6270347af78..8d4bd4945af 100644
--- a/chromium/components/viz/service/frame_sinks/frame_sink_manager_impl.h
+++ b/chromium/components/viz/service/frame_sinks/frame_sink_manager_impl.h
@@ -50,9 +50,11 @@ namespace viz {
class CapturableFrameSink;
class CompositorFrameSinkSupport;
class FrameSinkBundleImpl;
+class GmbVideoFramePoolContextProvider;
class HintSessionFactory;
class OutputSurfaceProvider;
class SharedBitmapManager;
+struct VideoCaptureTarget;
// FrameSinkManagerImpl manages BeginFrame hierarchy. This is the implementation
// detail for FrameSinkManagerImpl.
@@ -67,7 +69,8 @@ class VIZ_SERVICE_EXPORT FrameSinkManagerImpl
InitParams();
explicit InitParams(
SharedBitmapManager* shared_bitmap_manager,
- OutputSurfaceProvider* output_surface_provider = nullptr);
+ OutputSurfaceProvider* output_surface_provider = nullptr,
+ GmbVideoFramePoolContextProvider* gmb_context_provider = nullptr);
InitParams(InitParams&& other);
~InitParams();
InitParams& operator=(InitParams&& other);
@@ -76,6 +79,7 @@ class VIZ_SERVICE_EXPORT FrameSinkManagerImpl
absl::optional<uint32_t> activation_deadline_in_frames =
kDefaultActivationDeadlineInFrames;
raw_ptr<OutputSurfaceProvider> output_surface_provider = nullptr;
+ raw_ptr<GmbVideoFramePoolContextProvider> gmb_context_provider = nullptr;
uint32_t restart_id = BeginFrameSource::kNotRestartableId;
bool run_all_compositor_stages_before_draw = false;
bool log_capture_pipeline_in_webrtc = false;
@@ -139,10 +143,6 @@ class VIZ_SERVICE_EXPORT FrameSinkManagerImpl
void EvictSurfaces(const std::vector<SurfaceId>& surface_ids) override;
void RequestCopyOfOutput(const SurfaceId& surface_id,
std::unique_ptr<CopyOutputRequest> request) override;
- void SetHitTestAsyncQueriedDebugRegions(
- const FrameSinkId& root_frame_sink_id,
- const std::vector<FrameSinkId>& hit_test_async_queried_debug_queue)
- override;
void CacheBackBuffer(uint32_t cache_id,
const FrameSinkId& root_frame_sink_id) override;
void EvictBackBuffer(uint32_t cache_id,
@@ -301,7 +301,7 @@ class VIZ_SERVICE_EXPORT FrameSinkManagerImpl
// FrameSinkVideoCapturerManager implementation:
CapturableFrameSink* FindCapturableFrameSink(
- const FrameSinkId& frame_sink_id) override;
+ const VideoCaptureTarget& target) override;
void OnCapturerConnectionLost(FrameSinkVideoCapturerImpl* capturer) override;
// Returns true if |child framesink| is or has |search_frame_sink_id| as a
@@ -331,6 +331,8 @@ class VIZ_SERVICE_EXPORT FrameSinkManagerImpl
// Provides an output surface for CreateRootCompositorFrameSink().
const raw_ptr<OutputSurfaceProvider> output_surface_provider_;
+ const raw_ptr<GmbVideoFramePoolContextProvider> gmb_context_provider_;
+
SurfaceManager surface_manager_;
// Must be created after and destroyed before |surface_manager_|.
diff --git a/chromium/components/viz/service/frame_sinks/frame_sink_manager_unittest.cc b/chromium/components/viz/service/frame_sinks/frame_sink_manager_unittest.cc
index e66873a5097..c49494e98fb 100644
--- a/chromium/components/viz/service/frame_sinks/frame_sink_manager_unittest.cc
+++ b/chromium/components/viz/service/frame_sinks/frame_sink_manager_unittest.cc
@@ -94,7 +94,7 @@ class FrameSinkManagerTest : public testing::Test {
}
CapturableFrameSink* FindCapturableFrameSink(const FrameSinkId& id) {
- return manager_.FindCapturableFrameSink(id);
+ return manager_.FindCapturableFrameSink(VideoCaptureTarget(id));
}
// Verifies the frame sinks with provided id in |ids| are throttled at
diff --git a/chromium/components/viz/service/frame_sinks/gmb_video_frame_pool_context_provider.h b/chromium/components/viz/service/frame_sinks/gmb_video_frame_pool_context_provider.h
new file mode 100644
index 00000000000..6b3f7587bf8
--- /dev/null
+++ b/chromium/components/viz/service/frame_sinks/gmb_video_frame_pool_context_provider.h
@@ -0,0 +1,35 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_VIZ_SERVICE_FRAME_SINKS_GMB_VIDEO_FRAME_POOL_CONTEXT_PROVIDER_H_
+#define COMPONENTS_VIZ_SERVICE_FRAME_SINKS_GMB_VIDEO_FRAME_POOL_CONTEXT_PROVIDER_H_
+
+#include <memory>
+
+#include "base/callback.h"
+#include "base/memory/scoped_refptr.h"
+#include "media/video/renderable_gpu_memory_buffer_video_frame_pool.h"
+
+namespace viz {
+
+// Context provider for contexts needed to create instances of
+// `media::RenderableGpuMemoryBufferVideoFramePool`. Used to create an instance
+// of `FrameSinkManagerImpl` capable of creating `FrameSinkVideoCapturerImpl`
+// with `GpuMemoryBuffer` support.
+class GmbVideoFramePoolContextProvider {
+ public:
+ virtual ~GmbVideoFramePoolContextProvider() = default;
+
+ // Creates new context that can then subsequently be used to create
+ // a media::RenderableGpuMemoryBufferVideoFramePool. The |on_context_lost|
+ // will be invoked to notify the callers that the context returned from the
+ // call is no longer functional. It will be called on the current sequence.
+ virtual std::unique_ptr<
+ media::RenderableGpuMemoryBufferVideoFramePool::Context>
+ CreateContext(base::OnceClosure on_context_lost) = 0;
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_SERVICE_FRAME_SINKS_GMB_VIDEO_FRAME_POOL_CONTEXT_PROVIDER_H_
diff --git a/chromium/components/viz/service/frame_sinks/gmb_video_frame_pool_context_provider_impl.cc b/chromium/components/viz/service/frame_sinks/gmb_video_frame_pool_context_provider_impl.cc
new file mode 100644
index 00000000000..2312e87b44d
--- /dev/null
+++ b/chromium/components/viz/service/frame_sinks/gmb_video_frame_pool_context_provider_impl.cc
@@ -0,0 +1,178 @@
+// Copyright 2022 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.
+
+#include "components/viz/service/frame_sinks/gmb_video_frame_pool_context_provider_impl.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/callback.h"
+#include "base/task/bind_post_task.h"
+#include "components/viz/service/display_embedder/in_process_gpu_memory_buffer_manager.h"
+#include "components/viz/service/gl/gpu_service_impl.h"
+#include "gpu/command_buffer/service/shared_context_state.h"
+#include "gpu/ipc/scheduler_sequence.h"
+#include "gpu/ipc/shared_image_interface_in_process.h"
+
+namespace viz {
+
+class GmbVideoFramePoolContext
+ : public media::RenderableGpuMemoryBufferVideoFramePool::Context,
+ public gpu::SharedContextState::ContextLostObserver {
+ public:
+ explicit GmbVideoFramePoolContext(
+ GpuServiceImpl* gpu_service,
+ InProcessGpuMemoryBufferManager* gpu_memory_buffer_manager,
+ base::OnceClosure on_context_lost)
+ : gpu_service_(gpu_service),
+ gpu_memory_buffer_manager_(gpu_memory_buffer_manager),
+ on_context_lost_(
+ base::BindPostTask(base::SequencedTaskRunnerHandle::Get(),
+ std::move(on_context_lost))) {
+ DETACH_FROM_SEQUENCE(gpu_sequence_checker_);
+
+ sequence_ = std::make_unique<gpu::SchedulerSequence>(
+ gpu_service_->GetGpuScheduler(), gpu_service_->main_runner(),
+ /*target_thread_is_always_available=*/true);
+
+ base::WaitableEvent event;
+
+ sequence_->ScheduleTask(
+ base::BindOnce(&GmbVideoFramePoolContext::InitializeOnGpu,
+ base::Unretained(this), &event),
+ {});
+
+ event.Wait();
+ }
+
+ ~GmbVideoFramePoolContext() override {
+ // SharedImageInterfaceInProcess' dtor blocks on GPU, which we want to do as
+ // well, so run it now before we grab the GPU thread:
+ sii_in_process_ = nullptr;
+
+ base::WaitableEvent event;
+
+ sequence_->ScheduleTask(
+ base::BindOnce(&GmbVideoFramePoolContext::DestroyOnGpu,
+ base::Unretained(this), &event),
+ {});
+
+ event.Wait();
+
+ sequence_ = nullptr;
+ }
+
+ // Allocate a GpuMemoryBuffer.
+ std::unique_ptr<gfx::GpuMemoryBuffer> CreateGpuMemoryBuffer(
+ const gfx::Size& size,
+ gfx::BufferFormat format,
+ gfx::BufferUsage usage) override {
+ return gpu_memory_buffer_manager_->CreateGpuMemoryBuffer(
+ size, format, usage, gpu::kNullSurfaceHandle, nullptr);
+ }
+
+ // Create a SharedImage representation of a plane of a GpuMemoryBuffer
+ // allocated by this interface. Populate `mailbox` and `sync_token`.
+ void CreateSharedImage(gfx::GpuMemoryBuffer* gpu_memory_buffer,
+ gfx::BufferPlane plane,
+ const gfx::ColorSpace& color_space,
+ GrSurfaceOrigin surface_origin,
+ SkAlphaType alpha_type,
+ uint32_t usage,
+ gpu::Mailbox& mailbox,
+ gpu::SyncToken& sync_token) override {
+ mailbox = sii_in_process_->CreateSharedImage(
+ gpu_memory_buffer, gpu_memory_buffer_manager_, plane, color_space,
+ surface_origin, alpha_type, usage);
+
+ sync_token = sii_in_process_->GenVerifiedSyncToken();
+ }
+
+ // Destroy a SharedImage created by this interface.
+ void DestroySharedImage(const gpu::SyncToken& sync_token,
+ const gpu::Mailbox& mailbox) override {
+ sii_in_process_->DestroySharedImage(sync_token, mailbox);
+ }
+
+ private:
+ void InitializeOnGpu(base::WaitableEvent* event) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(gpu_sequence_checker_);
+ DCHECK(!initialized_);
+ DCHECK(gpu_service_);
+
+ shared_context_state_ = gpu_service_->GetContextState();
+ DCHECK(shared_context_state_);
+
+ shared_context_state_->AddContextLostObserver(this);
+
+ // TODO(bialpio): Move construction to the viz thread once it is no longer
+ // necessary to dereference `shared_context_state_` to grab the memory
+ // tracker from it.
+ sii_in_process_ = std::make_unique<gpu::SharedImageInterfaceInProcess>(
+ sequence_.get(), gpu_service_->sync_point_manager(),
+ gpu_service_->gpu_preferences(),
+ gpu_service_->gpu_driver_bug_workarounds(),
+ gpu_service_->gpu_feature_info(), shared_context_state_.get(),
+ gpu_service_->mailbox_manager(), gpu_service_->shared_image_manager(),
+ gpu_service_->gpu_image_factory(),
+ shared_context_state_->memory_tracker());
+ DCHECK(sii_in_process_);
+
+ initialized_ = true;
+
+ event->Signal();
+ }
+
+ void DestroyOnGpu(base::WaitableEvent* event) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(gpu_sequence_checker_);
+ DCHECK(initialized_);
+
+ shared_context_state_->RemoveContextLostObserver(this);
+ shared_context_state_ = nullptr;
+
+ event->Signal();
+ }
+
+ // gpu::SharedContextState::ContextLostObserver implementation:
+ void OnContextLost() override {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(gpu_sequence_checker_);
+
+ DCHECK(on_context_lost_);
+ std::move(on_context_lost_).Run();
+ }
+
+ const raw_ptr<GpuServiceImpl> gpu_service_;
+ const raw_ptr<InProcessGpuMemoryBufferManager> gpu_memory_buffer_manager_;
+
+ // Closure that we need to call when context loss happens.
+ base::OnceClosure on_context_lost_;
+
+ // True iff the context was initialized on GPU.
+ bool initialized_ = false;
+
+ std::unique_ptr<gpu::SchedulerSequence> sequence_;
+ scoped_refptr<gpu::SharedContextState> shared_context_state_;
+
+ std::unique_ptr<gpu::SharedImageInterfaceInProcess> sii_in_process_;
+
+ SEQUENCE_CHECKER(gpu_sequence_checker_);
+};
+
+GmbVideoFramePoolContextProviderImpl::GmbVideoFramePoolContextProviderImpl(
+ GpuServiceImpl* gpu_service,
+ InProcessGpuMemoryBufferManager* gpu_memory_buffer_manager)
+ : gpu_service_(gpu_service),
+ gpu_memory_buffer_manager_(gpu_memory_buffer_manager) {}
+
+GmbVideoFramePoolContextProviderImpl::~GmbVideoFramePoolContextProviderImpl() =
+ default;
+
+std::unique_ptr<media::RenderableGpuMemoryBufferVideoFramePool::Context>
+GmbVideoFramePoolContextProviderImpl::CreateContext(
+ base::OnceClosure on_context_lost) {
+ return std::make_unique<GmbVideoFramePoolContext>(
+ gpu_service_, gpu_memory_buffer_manager_, std::move(on_context_lost));
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/service/frame_sinks/gmb_video_frame_pool_context_provider_impl.h b/chromium/components/viz/service/frame_sinks/gmb_video_frame_pool_context_provider_impl.h
new file mode 100644
index 00000000000..8cd3cf4c3ee
--- /dev/null
+++ b/chromium/components/viz/service/frame_sinks/gmb_video_frame_pool_context_provider_impl.h
@@ -0,0 +1,43 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_VIZ_SERVICE_FRAME_SINKS_GMB_VIDEO_FRAME_POOL_CONTEXT_PROVIDER_IMPL_H_
+#define COMPONENTS_VIZ_SERVICE_FRAME_SINKS_GMB_VIDEO_FRAME_POOL_CONTEXT_PROVIDER_IMPL_H_
+
+#include <memory>
+
+#include "components/viz/service/frame_sinks/gmb_video_frame_pool_context_provider.h"
+#include "components/viz/service/viz_service_export.h"
+#include "media/video/renderable_gpu_memory_buffer_video_frame_pool.h"
+
+namespace viz {
+
+class GpuServiceImpl;
+class InProcessGpuMemoryBufferManager;
+
+class VIZ_SERVICE_EXPORT GmbVideoFramePoolContextProviderImpl
+ : public GmbVideoFramePoolContextProvider {
+ public:
+ explicit GmbVideoFramePoolContextProviderImpl(
+ GpuServiceImpl* gpu_service,
+ InProcessGpuMemoryBufferManager* gpu_memory_buffer_manager);
+
+ GmbVideoFramePoolContextProviderImpl(
+ const GmbVideoFramePoolContextProviderImpl& other) = delete;
+ GmbVideoFramePoolContextProviderImpl& operator=(
+ const GmbVideoFramePoolContextProviderImpl& other) = delete;
+
+ ~GmbVideoFramePoolContextProviderImpl() override;
+
+ std::unique_ptr<media::RenderableGpuMemoryBufferVideoFramePool::Context>
+ CreateContext(base::OnceClosure on_context_lost) override;
+
+ private:
+ const raw_ptr<GpuServiceImpl> gpu_service_;
+ const raw_ptr<InProcessGpuMemoryBufferManager> gpu_memory_buffer_manager_;
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_SERVICE_FRAME_SINKS_GMB_VIDEO_FRAME_POOL_CONTEXT_PROVIDER_IMPL_H_
diff --git a/chromium/components/viz/service/frame_sinks/gpu_vsync_begin_frame_source.cc b/chromium/components/viz/service/frame_sinks/gpu_vsync_begin_frame_source.cc
index 2a713304951..6c1da8e3191 100644
--- a/chromium/components/viz/service/frame_sinks/gpu_vsync_begin_frame_source.cc
+++ b/chromium/components/viz/service/frame_sinks/gpu_vsync_begin_frame_source.cc
@@ -5,6 +5,7 @@
#include "components/viz/service/frame_sinks/gpu_vsync_begin_frame_source.h"
#include "base/bind.h"
+#include "base/trace_event/trace_event.h"
#include "components/viz/service/display/output_surface.h"
namespace viz {
diff --git a/chromium/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc b/chromium/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc
index 94a087b4beb..7607a49cdc1 100644
--- a/chromium/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc
+++ b/chromium/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc
@@ -8,9 +8,9 @@
#include <utility>
#include <vector>
-#include "base/compiler_specific.h"
#include "base/containers/flat_set.h"
#include "base/memory/ptr_util.h"
+#include "base/memory/raw_ptr.h"
#include "base/threading/platform_thread.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
@@ -26,12 +26,47 @@
#include "components/viz/service/frame_sinks/gpu_vsync_begin_frame_source.h"
#include "components/viz/service/hit_test/hit_test_aggregator.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "components/viz/service/frame_sinks/external_begin_frame_source_android.h"
#endif
namespace viz {
+class RootCompositorFrameSinkImpl::StandaloneBeginFrameObserver
+ : public BeginFrameObserverBase {
+ public:
+ StandaloneBeginFrameObserver(
+ mojo::PendingRemote<mojom::BeginFrameObserver> observer,
+ BeginFrameSource* begin_frame_source)
+ : remote_observer_(std::move(observer)),
+ begin_frame_source_(begin_frame_source) {
+ remote_observer_.set_disconnect_handler(base::BindOnce(
+ &StandaloneBeginFrameObserver::StopObserving, base::Unretained(this)));
+ begin_frame_source_->AddObserver(this);
+ }
+
+ ~StandaloneBeginFrameObserver() override { StopObserving(); }
+
+ bool OnBeginFrameDerivedImpl(const BeginFrameArgs& args) override {
+ remote_observer_->OnStandaloneBeginFrame(args);
+ return true;
+ }
+
+ void OnBeginFrameSourcePausedChanged(bool paused) override {}
+ bool IsRoot() const override { return true; }
+
+ private:
+ void StopObserving() {
+ if (!begin_frame_source_)
+ return;
+ begin_frame_source_->RemoveObserver(this);
+ begin_frame_source_ = nullptr;
+ }
+
+ mojo::Remote<mojom::BeginFrameObserver> remote_observer_;
+ base::raw_ptr<BeginFrameSource> begin_frame_source_;
+};
+
// static
std::unique_ptr<RootCompositorFrameSinkImpl>
RootCompositorFrameSinkImpl::Create(
@@ -62,7 +97,7 @@ RootCompositorFrameSinkImpl::Create(
// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
// of lacros-chrome is complete.
-#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
// For X11, we need notify client about swap completion after resizing, so the
// client can use it for synchronize with X11 WM.
output_surface->SetNeedsSwapSizeNotifications(true);
@@ -74,7 +109,7 @@ RootCompositorFrameSinkImpl::Create(
std::unique_ptr<SyntheticBeginFrameSource> synthetic_begin_frame_source;
ExternalBeginFrameSourceMojo* external_begin_frame_source_mojo = nullptr;
bool hw_support_for_multiple_refresh_rates = false;
-#if !defined(OS_APPLE)
+#if !BUILDFLAG(IS_APPLE)
bool wants_vsync_updates = false;
#endif
@@ -88,11 +123,12 @@ RootCompositorFrameSinkImpl::Create(
external_begin_frame_source =
std::move(owned_external_begin_frame_source_mojo);
} else {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
hw_support_for_multiple_refresh_rates = true;
external_begin_frame_source =
- std::make_unique<ExternalBeginFrameSourceAndroid>(restart_id,
- params->refresh_rate);
+ std::make_unique<ExternalBeginFrameSourceAndroid>(
+ restart_id, params->refresh_rate,
+ /*requires_align_with_java=*/false);
#else
if (params->disable_frame_rate_limit) {
synthetic_begin_frame_source =
@@ -100,14 +136,14 @@ RootCompositorFrameSinkImpl::Create(
std::make_unique<DelayBasedTimeSource>(
base::ThreadTaskRunnerHandle::Get().get()));
} else if (output_surface->capabilities().supports_gpu_vsync) {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
hw_support_for_multiple_refresh_rates =
output_surface->capabilities().supports_dc_layers &&
params->set_present_duration_allowed;
#endif
// Vsync updates are required to update the FrameRateDecider with
// supported refresh rates.
-#if !defined(OS_APPLE)
+#if !BUILDFLAG(IS_APPLE)
wants_vsync_updates = params->use_preferred_interval_for_video;
#endif
external_begin_frame_source = std::make_unique<GpuVSyncBeginFrameSource>(
@@ -119,7 +155,7 @@ RootCompositorFrameSinkImpl::Create(
base::ThreadTaskRunnerHandle::Get().get()),
restart_id);
}
-#endif // OS_ANDROID
+#endif // BUILDFLAG(IS_ANDROID)
}
BeginFrameSource* begin_frame_source = synthetic_begin_frame_source.get();
@@ -135,7 +171,7 @@ RootCompositorFrameSinkImpl::Create(
begin_frame_source, task_runner.get(), capabilities.pending_swap_params,
hint_session_factory, run_all_compositor_stages_before_draw);
-#if !defined(OS_APPLE)
+#if !BUILDFLAG(IS_APPLE)
auto* output_surface_ptr = output_surface.get();
#endif
gpu::SharedImageInterface* sii = nullptr;
@@ -170,7 +206,7 @@ RootCompositorFrameSinkImpl::Create(
hw_support_for_multiple_refresh_rates,
params->renderer_settings.apply_simple_frame_rate_throttling));
-#if !defined(OS_APPLE)
+#if !BUILDFLAG(IS_APPLE)
// On Mac vsync parameter updates come from the browser process. We don't need
// to provide a callback to the OutputSurface since it should never use it.
if (wants_vsync_updates || impl->synthetic_begin_frame_source_) {
@@ -210,7 +246,7 @@ void RootCompositorFrameSinkImpl::SetDisplayVisible(bool visible) {
display_->SetVisible(visible);
}
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
void RootCompositorFrameSinkImpl::DisableSwapUntilResize(
DisableSwapUntilResizeCallback callback) {
display_->DisableSwapUntilResize(std::move(callback));
@@ -321,7 +357,7 @@ void RootCompositorFrameSinkImpl::ForceImmediateDrawAndSwapIfPossible() {
display_->ForceImmediateDrawAndSwapIfPossible();
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
void RootCompositorFrameSinkImpl::SetVSyncPaused(bool paused) {
if (external_begin_frame_source_)
external_begin_frame_source_->OnSetBeginFrameSourcePaused(paused);
@@ -353,7 +389,7 @@ void RootCompositorFrameSinkImpl::SetSwapCompletionCallbackEnabled(
enable_swap_competion_callback_ = enable;
}
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
void RootCompositorFrameSinkImpl::AddVSyncParameterObserver(
mojo::PendingRemote<mojom::VSyncParameterObserver> observer) {
@@ -366,6 +402,13 @@ void RootCompositorFrameSinkImpl::SetDelegatedInkPointRenderer(
display_->InitDelegatedInkPointRendererReceiver(std::move(receiver));
}
+void RootCompositorFrameSinkImpl::SetStandaloneBeginFrameObserver(
+ mojo::PendingRemote<mojom::BeginFrameObserver> observer) {
+ standalone_begin_frame_observer_ =
+ std::make_unique<StandaloneBeginFrameObserver>(std::move(observer),
+ begin_frame_source());
+}
+
void RootCompositorFrameSinkImpl::SetNeedsBeginFrame(bool needs_begin_frame) {
support_->SetNeedsBeginFrame(needs_begin_frame);
}
@@ -436,7 +479,7 @@ void RootCompositorFrameSinkImpl::InitializeCompositorFrameSinkType(
support_->InitializeCompositorFrameSinkType(type);
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
void RootCompositorFrameSinkImpl::SetThreadIds(
const std::vector<int32_t>& thread_ids) {
support_->SetThreadIds(/*from_untrusted_client=*/false,
@@ -499,8 +542,7 @@ void RootCompositorFrameSinkImpl::DisplayWillDrawAndSwap(
bool will_draw_and_swap,
AggregatedRenderPassList* render_passes) {
DCHECK(support_->GetHitTestAggregator());
- support_->GetHitTestAggregator()->Aggregate(display_->CurrentSurfaceId(),
- render_passes);
+ support_->GetHitTestAggregator()->Aggregate(display_->CurrentSurfaceId());
}
base::ScopedClosureRunner RootCompositorFrameSinkImpl::GetCacheBackBufferCb() {
@@ -509,41 +551,36 @@ base::ScopedClosureRunner RootCompositorFrameSinkImpl::GetCacheBackBufferCb() {
void RootCompositorFrameSinkImpl::DisplayDidReceiveCALayerParams(
const gfx::CALayerParams& ca_layer_params) {
- if (last_ca_layer_params_ == ca_layer_params)
- return;
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
// If |ca_layer_params| should have content only when there exists a client
// to send it to.
DCHECK(ca_layer_params.is_empty || display_client_);
- last_ca_layer_params_ = ca_layer_params;
if (display_client_)
display_client_->OnDisplayReceivedCALayerParams(ca_layer_params);
#else
NOTREACHED();
- ALLOW_UNUSED_LOCAL(display_client_);
#endif
}
void RootCompositorFrameSinkImpl::DisplayDidCompleteSwapWithSize(
const gfx::Size& pixel_size) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
if (display_client_ && enable_swap_competion_callback_)
display_client_->DidCompleteSwapWithSize(pixel_size);
// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
// of lacros-chrome is complete.
-#elif defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
+#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
if (display_client_ && pixel_size != last_swap_pixel_size_) {
last_swap_pixel_size_ = pixel_size;
display_client_->DidCompleteSwapWithNewSize(last_swap_pixel_size_);
}
#else
NOTREACHED();
- ALLOW_UNUSED_LOCAL(display_client_);
#endif
}
void RootCompositorFrameSinkImpl::SetWideColorEnabled(bool enabled) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
if (display_client_)
display_client_->SetWideColorEnabled(enabled);
#endif
@@ -551,7 +588,7 @@ void RootCompositorFrameSinkImpl::SetWideColorEnabled(bool enabled) {
void RootCompositorFrameSinkImpl::SetPreferredFrameInterval(
base::TimeDelta interval) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
float refresh_rate =
interval.InSecondsF() == 0 ? 0 : (1 / interval.InSecondsF());
if (display_client_)
diff --git a/chromium/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.h b/chromium/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.h
index cd3ed5baba3..a6e4ebbffd4 100644
--- a/chromium/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.h
+++ b/chromium/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.h
@@ -22,6 +22,7 @@
#include "mojo/public/cpp/bindings/pending_associated_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/remote.h"
+#include "services/viz/privileged/mojom/compositing/begin_frame_observer.mojom.h"
#include "services/viz/privileged/mojom/compositing/display_private.mojom.h"
#include "services/viz/privileged/mojom/compositing/frame_sink_manager.mojom.h"
#include "services/viz/public/mojom/compositing/compositor_frame_sink.mojom.h"
@@ -67,7 +68,7 @@ class VIZ_SERVICE_EXPORT RootCompositorFrameSinkImpl
// mojom::DisplayPrivate:
void SetDisplayVisible(bool visible) override;
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
void DisableSwapUntilResize(DisableSwapUntilResizeCallback callback) override;
#endif
void Resize(const gfx::Size& size) override;
@@ -78,7 +79,7 @@ class VIZ_SERVICE_EXPORT RootCompositorFrameSinkImpl
void SetDisplayVSyncParameters(base::TimeTicks timebase,
base::TimeDelta interval) override;
void ForceImmediateDrawAndSwapIfPossible() override;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
void SetVSyncPaused(bool paused) override;
void UpdateRefreshRate(float refresh_rate) override;
void SetSupportedRefreshRates(
@@ -88,10 +89,11 @@ class VIZ_SERVICE_EXPORT RootCompositorFrameSinkImpl
#endif
void AddVSyncParameterObserver(
mojo::PendingRemote<mojom::VSyncParameterObserver> observer) override;
-
void SetDelegatedInkPointRenderer(
mojo::PendingReceiver<gfx::mojom::DelegatedInkPointRenderer> receiver)
override;
+ void SetStandaloneBeginFrameObserver(
+ mojo::PendingRemote<mojom::BeginFrameObserver> observer) override;
// mojom::CompositorFrameSink:
void SetNeedsBeginFrame(bool needs_begin_frame) override;
@@ -113,13 +115,15 @@ class VIZ_SERVICE_EXPORT RootCompositorFrameSinkImpl
SubmitCompositorFrameSyncCallback callback) override;
void InitializeCompositorFrameSinkType(
mojom::CompositorFrameSinkType type) override;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
void SetThreadIds(const std::vector<int32_t>& thread_ids) override;
#endif
base::ScopedClosureRunner GetCacheBackBufferCb();
private:
+ class StandaloneBeginFrameObserver;
+
RootCompositorFrameSinkImpl(
FrameSinkManagerImpl* frame_sink_manager,
const FrameSinkId& frame_sink_id,
@@ -156,7 +160,7 @@ class VIZ_SERVICE_EXPORT RootCompositorFrameSinkImpl
mojo::AssociatedReceiver<mojom::CompositorFrameSink>
compositor_frame_sink_receiver_;
// |display_client_| may be NullRemote on platforms that do not use it.
- mojo::Remote<mojom::DisplayClient> display_client_;
+ [[maybe_unused]] mojo::Remote<mojom::DisplayClient> display_client_;
mojo::AssociatedReceiver<mojom::DisplayPrivate> display_private_receiver_;
std::unique_ptr<VSyncParameterListener> vsync_listener_;
@@ -175,6 +179,9 @@ class VIZ_SERVICE_EXPORT RootCompositorFrameSinkImpl
// to the BFS.
std::unique_ptr<Display> display_;
+ std::unique_ptr<StandaloneBeginFrameObserver>
+ standalone_begin_frame_observer_;
+
// |use_preferred_interval_| indicates if we should use the preferred interval
// from FrameRateDecider to tick.
bool use_preferred_interval_ = false;
@@ -189,13 +196,11 @@ class VIZ_SERVICE_EXPORT RootCompositorFrameSinkImpl
// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
// of lacros-chrome is complete.
-#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
gfx::Size last_swap_pixel_size_;
#endif
- gfx::CALayerParams last_ca_layer_params_;
-
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Let client control whether it wants `DidCompleteSwapWithSize`.
bool enable_swap_competion_callback_ = false;
#endif
diff --git a/chromium/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc b/chromium/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc
index 1ffccdfaffa..1d2a5802763 100644
--- a/chromium/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc
+++ b/chromium/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc
@@ -25,6 +25,7 @@
#include "components/viz/common/frame_sinks/copy_output_util.h"
#include "components/viz/common/surfaces/local_surface_id.h"
#include "components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_manager.h"
+#include "components/viz/service/frame_sinks/video_capture/gpu_memory_buffer_video_frame_pool.h"
#include "components/viz/service/frame_sinks/video_capture/shared_memory_video_frame_pool.h"
#include "media/base/limits.h"
#include "media/base/video_util.h"
@@ -55,6 +56,42 @@ constexpr gfx::Rect kMaxRect = gfx::Rect(0,
std::numeric_limits<int>::max(),
std::numeric_limits<int>::max());
+std::unique_ptr<VideoFramePool> GetVideoFramePoolForFormat(
+ media::VideoPixelFormat format,
+ int capacity,
+ GmbVideoFramePoolContextProvider* context_provider) {
+ DCHECK(format == media::PIXEL_FORMAT_I420 ||
+ format == media::PIXEL_FORMAT_NV12 ||
+ format == media::PIXEL_FORMAT_ARGB);
+
+ switch (format) {
+ case media::PIXEL_FORMAT_I420:
+ case media::PIXEL_FORMAT_ARGB:
+ return std::make_unique<SharedMemoryVideoFramePool>(capacity);
+ case media::PIXEL_FORMAT_NV12:
+ return std::make_unique<GpuMemoryBufferVideoFramePool>(capacity,
+ context_provider);
+ default:
+ NOTREACHED();
+ return nullptr;
+ }
+}
+
+CopyOutputRequest::ResultFormat VideoPixelFormatToCopyOutputRequestFormat(
+ media::VideoPixelFormat format) {
+ switch (format) {
+ case media::PIXEL_FORMAT_I420:
+ return CopyOutputRequest::ResultFormat::I420_PLANES;
+ case media::PIXEL_FORMAT_NV12:
+ return CopyOutputRequest::ResultFormat::NV12_PLANES;
+ case media::PIXEL_FORMAT_ARGB:
+ return CopyOutputRequest::ResultFormat::RGBA;
+ default:
+ NOTREACHED();
+ return CopyOutputRequest::ResultFormat::RGBA;
+ }
+}
+
} // namespace
// static
@@ -68,9 +105,12 @@ constexpr int FrameSinkVideoCapturerImpl::kDesignLimitMaxFrames;
constexpr int FrameSinkVideoCapturerImpl::kFramePoolCapacity;
// static
constexpr float FrameSinkVideoCapturerImpl::kTargetPipelineUtilization;
+// static
+constexpr base::TimeDelta FrameSinkVideoCapturerImpl::kMaxRefreshDelay;
FrameSinkVideoCapturerImpl::FrameSinkVideoCapturerImpl(
FrameSinkVideoCapturerManager* frame_sink_manager,
+ GmbVideoFramePoolContextProvider* gmb_video_frame_pool_context_provider,
mojo::PendingReceiver<mojom::FrameSinkVideoCapturer> receiver,
std::unique_ptr<media::VideoCaptureOracle> oracle,
bool log_to_webrtc)
@@ -78,8 +118,12 @@ FrameSinkVideoCapturerImpl::FrameSinkVideoCapturerImpl(
copy_request_source_(base::UnguessableToken::Create()),
clock_(base::DefaultTickClock::GetInstance()),
oracle_(std::move(oracle)),
+ gmb_video_frame_pool_context_provider_(
+ gmb_video_frame_pool_context_provider),
frame_pool_(
- std::make_unique<SharedMemoryVideoFramePool>(kFramePoolCapacity)),
+ GetVideoFramePoolForFormat(pixel_format_,
+ kFramePoolCapacity,
+ gmb_video_frame_pool_context_provider_)),
feedback_weak_factory_(oracle_.get()),
log_to_webrtc_(log_to_webrtc) {
DCHECK(frame_sink_manager_);
@@ -106,9 +150,21 @@ FrameSinkVideoCapturerImpl::~FrameSinkVideoCapturerImpl() {
SetResolvedTarget(nullptr);
}
+void FrameSinkVideoCapturerImpl::ResolveTarget() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ SetResolvedTarget(
+ target_ ? frame_sink_manager_->FindCapturableFrameSink(target_.value())
+ : nullptr);
+}
+
void FrameSinkVideoCapturerImpl::SetResolvedTarget(
CapturableFrameSink* target) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ // We were unable to resolve a target, so schedule a check for the next
+ // refresh.
+ if (!target && target_.has_value()) {
+ RequestRefreshFrame();
+ }
if (resolved_target_ == target) {
return;
@@ -145,18 +201,32 @@ void FrameSinkVideoCapturerImpl::SetFormat(media::VideoPixelFormat format) {
bool format_changed = false;
if (format != media::PIXEL_FORMAT_I420 &&
- format != media::PIXEL_FORMAT_ARGB) {
- LOG(DFATAL) << "Invalid pixel format: Only I420 and ARGB are supported.";
+ format != media::PIXEL_FORMAT_ARGB &&
+ format != media::PIXEL_FORMAT_NV12) {
+ LOG(DFATAL) << "Invalid pixel format: Only I420, ARGB & NV12 formats are "
+ "supported.";
} else {
+ // We only support NV12 if we got a context provider for pool creation:
+ CHECK(format != media::PIXEL_FORMAT_NV12 ||
+ gmb_video_frame_pool_context_provider_);
+
format_changed |= (pixel_format_ != format);
pixel_format_ = format;
}
if (format_changed) {
+ // Don't tolerate changing to NV12 mid-capture:
+ CHECK(format != media::PIXEL_FORMAT_NV12 || !video_capture_started_);
+
TRACE_EVENT_INSTANT1("gpu.capture", "SetFormat", TRACE_EVENT_SCOPE_THREAD,
"format", format);
MarkFrame(nullptr);
+
+ frame_pool_ =
+ GetVideoFramePoolForFormat(pixel_format_, kFramePoolCapacity,
+ gmb_video_frame_pool_context_provider_);
+
RefreshEntireSourceSoon();
}
}
@@ -243,16 +313,18 @@ void FrameSinkVideoCapturerImpl::SetAutoThrottlingEnabled(bool enabled) {
}
void FrameSinkVideoCapturerImpl::ChangeTarget(
- const absl::optional<VideoCaptureTarget>& target) {
+ const absl::optional<VideoCaptureTarget>& target,
+ uint32_t crop_version) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK_GE(crop_version, crop_version_);
+
target_ = target;
+ crop_version_ = crop_version;
- CapturableFrameSink* resolved_target = nullptr;
- if (target_) {
- resolved_target =
- frame_sink_manager_->FindCapturableFrameSink(target_->frame_sink_id);
- }
- SetResolvedTarget(resolved_target);
+ // TODO(crbug.com/1266378): Use |crop_version_| to annotate frames delivered
+ // or dropped.
+
+ ResolveTarget();
}
void FrameSinkVideoCapturerImpl::Start(
@@ -267,6 +339,12 @@ void FrameSinkVideoCapturerImpl::Start(
video_capture_started_ = true;
buffer_format_preference_ = buffer_format_preference;
+ // If we should start capture for NV12 format, we can only hand out GMBs so
+ // the caller must tolerate them:
+ CHECK(pixel_format_ != media::PIXEL_FORMAT_NV12 ||
+ buffer_format_preference_ ==
+ mojom::BufferFormatPreference::kPreferGpuMemoryBuffer);
+
if (resolved_target_)
resolved_target_->OnClientCaptureStarted();
@@ -297,6 +375,7 @@ void FrameSinkVideoCapturerImpl::Stop() {
if (consumer_) {
consumer_->OnStopped();
consumer_.reset();
+ consumer_informed_of_empty_region_ = false;
}
if (resolved_target_)
@@ -310,7 +389,12 @@ void FrameSinkVideoCapturerImpl::RequestRefreshFrame() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!refresh_frame_retry_timer_->IsRunning()) {
- RefreshSoon();
+ // NOTE: base::Unretained is used here safely because if |this| is invalid
+ // then the retry timer should have already been destructed.
+ refresh_frame_retry_timer_->Start(
+ FROM_HERE, GetDelayBeforeNextRefreshAttempt(),
+ base::BindOnce(&FrameSinkVideoCapturerImpl::RefreshSoon,
+ base::Unretained(this)));
}
}
@@ -325,23 +409,20 @@ void FrameSinkVideoCapturerImpl::CreateOverlay(
this, std::move(receiver)));
}
-void FrameSinkVideoCapturerImpl::ScheduleRefreshFrame() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
- refresh_frame_retry_timer_->Start(
- FROM_HERE, GetDelayBeforeNextRefreshAttempt(),
- base::BindRepeating(&FrameSinkVideoCapturerImpl::RefreshSoon,
- base::Unretained(this)));
-}
-
base::TimeDelta FrameSinkVideoCapturerImpl::GetDelayBeforeNextRefreshAttempt()
const {
// The delay should be long enough to prevent interrupting the smooth timing
// of frame captures that are expected to take place due to compositor update
// events. However, the delay should not be excessively long either. Two frame
// periods should be "just right."
- return 2 * std::max(oracle_->estimated_frame_duration(),
- oracle_->min_capture_period());
+ //
+ // NOTE: if a source is idle, the oracle may end up providing a frame duration
+ // equal to the time since the last refresh frame was called. In practice,
+ // this has the potential for this delay to end up being multiple seconds
+ // with no upper limit, so it is instead bounded at |kMaxRefreshDelay|.
+ return std::min(kMaxRefreshDelay,
+ 2 * std::max(oracle_->estimated_frame_duration(),
+ oracle_->min_capture_period()));
}
void FrameSinkVideoCapturerImpl::RefreshEntireSourceSoon() {
@@ -359,11 +440,14 @@ void FrameSinkVideoCapturerImpl::RefreshSoon() {
return;
}
- // If the capture target has not yet been resolved, the refresh must be
- // attempted later.
+ // If the capture target has not yet been resolved, first try changing the
+ // target since it may be available now.
if (!resolved_target_) {
- ScheduleRefreshFrame();
- return;
+ ResolveTarget();
+ if (!resolved_target_) {
+ RequestRefreshFrame();
+ return;
+ }
}
// Detect whether the source size changed before attempting capture.
@@ -371,11 +455,12 @@ void FrameSinkVideoCapturerImpl::RefreshSoon() {
const gfx::Rect capture_region =
resolved_target_->GetCopyOutputRequestRegion(target_->sub_target);
if (capture_region.IsEmpty()) {
+ MaybeInformConsumerOfEmptyRegion();
// If the capture region is empty, it means one of two things: the first
// frame has not been composited yet or the current region selected for
// capture has a current size of zero. We schedule a frame refresh here,
// although its not useful in all circumstances.
- ScheduleRefreshFrame();
+ RequestRefreshFrame();
return;
}
@@ -410,6 +495,7 @@ void FrameSinkVideoCapturerImpl::OnFrameDamaged(
const gfx::Rect capture_region =
resolved_target_->GetCopyOutputRequestRegion(target_->sub_target);
if (capture_region.IsEmpty()) {
+ MaybeInformConsumerOfEmptyRegion();
return;
}
@@ -542,7 +628,7 @@ void FrameSinkVideoCapturerImpl::MaybeCaptureFrame(
// Whether the oracle rejected a compositor update or a refresh event,
// the consumer needs to be provided an update in the near future.
- ScheduleRefreshFrame();
+ RequestRefreshFrame();
return;
}
@@ -556,6 +642,25 @@ void FrameSinkVideoCapturerImpl::MaybeCaptureFrame(
return;
}
+ // The oracle only keeps track of the source size, which should be the
+ // size of the capture region. If the capture region is empty or if the
+ // capture region isn't a subset of the entire compositor frame region, we
+ // shouldn't capture.
+ const gfx::Rect compositor_frame_region =
+ resolved_target_->GetCopyOutputRequestRegion(VideoCaptureSubTarget{});
+ const gfx::Rect capture_region =
+ resolved_target_->GetCopyOutputRequestRegion(target_->sub_target);
+
+ // This likely means that there is a mismatch between the last aggregated
+ // surface and the last activated surface sizes. To be cautious, we refresh
+ // the frame although a frame damage event should happen shortly.
+ // TODO(https://crbug.com/1300943): we should likely just get the frame
+ // region from the last aggregated surface.
+ if (!compositor_frame_region.Contains(capture_region)) {
+ RequestRefreshFrame();
+ return;
+ }
+
// Reserve a buffer from the pool for the next frame.
const OracleFrameNumber oracle_frame_number = oracle_->next_frame_number();
const gfx::Size capture_size =
@@ -592,7 +697,7 @@ void FrameSinkVideoCapturerImpl::MaybeCaptureFrame(
LOG(ERROR) << "Unable to allocate shmem for first frame capture: OOM?";
Stop();
} else {
- ScheduleRefreshFrame();
+ RequestRefreshFrame();
}
return;
}
@@ -610,6 +715,10 @@ void FrameSinkVideoCapturerImpl::MaybeCaptureFrame(
// At this point, the capture is going to proceed. Populate the VideoFrame's
// metadata, and notify the oracle.
const int64_t capture_frame_number = next_capture_frame_number_++;
+ // !WARNING: now that the frame number has been incremented, returning without
+ // adding the frame to the |delivery_queue_| or decrementing the frame number
+ // will cause the queue to be permanently stuck.
+
VideoFrameMetadata& metadata = frame->metadata();
metadata.capture_begin_time = clock_->NowTicks();
metadata.capture_counter = capture_frame_number;
@@ -634,7 +743,8 @@ void FrameSinkVideoCapturerImpl::MaybeCaptureFrame(
const gfx::Size& source_size = oracle_->source_size();
DCHECK(!source_size.IsEmpty());
gfx::Rect content_rect;
- if (pixel_format_ == media::PIXEL_FORMAT_I420) {
+ if (pixel_format_ == media::PIXEL_FORMAT_I420 ||
+ pixel_format_ == media::PIXEL_FORMAT_NV12) {
content_rect = media::ComputeLetterboxRegionForI420(frame->visible_rect(),
source_size);
} else {
@@ -661,7 +771,8 @@ void FrameSinkVideoCapturerImpl::MaybeCaptureFrame(
dirty_rect_, gfx::Vector2d(source_size.width(), source_size.height()),
gfx::Vector2d(content_rect.width(), content_rect.height()));
update_rect.Offset(content_rect.OffsetFromOrigin());
- if (pixel_format_ == media::PIXEL_FORMAT_I420)
+ if (pixel_format_ == media::PIXEL_FORMAT_I420 ||
+ pixel_format_ == media::PIXEL_FORMAT_NV12)
update_rect = ExpandRectToI420SubsampleBoundaries(update_rect);
}
metadata.capture_update_rect = update_rect;
@@ -682,6 +793,11 @@ void FrameSinkVideoCapturerImpl::MaybeCaptureFrame(
strides = base::StringPrintf("strideRGBA:%d",
frame->stride(VideoFrame::kARGBPlane));
break;
+ case media::PIXEL_FORMAT_NV12:
+ strides = base::StringPrintf("strideY:%d StrideUV:%d",
+ frame->stride(VideoFrame::kYPlane),
+ frame->stride(VideoFrame::kUVPlane));
+ break;
default:
strides = "strides:???";
}
@@ -707,44 +823,61 @@ void FrameSinkVideoCapturerImpl::MaybeCaptureFrame(
// Extreme edge-case: If somehow the source size is so tiny that the content
// region becomes empty, just deliver a frame filled with black.
if (content_rect.IsEmpty()) {
- if (pixel_format_ == media::PIXEL_FORMAT_I420) {
- media::FillYUV(frame.get(), 0x00, 0x80, 0x80);
+ media::LetterboxVideoFrame(frame.get(), gfx::Rect());
+
+ if (pixel_format_ == media::PIXEL_FORMAT_I420 ||
+ pixel_format_ == media::PIXEL_FORMAT_NV12) {
frame->set_color_space(gfx::ColorSpace::CreateREC709());
} else {
DCHECK_EQ(pixel_format_, media::PIXEL_FORMAT_ARGB);
- media::LetterboxVideoFrame(frame.get(), gfx::Rect());
frame->set_color_space(gfx::ColorSpace::CreateSRGB());
}
+
dirty_rect_ = gfx::Rect();
OnFrameReadyForDelivery(capture_frame_number, oracle_frame_number,
gfx::Rect(), std::move(frame));
return;
}
- // The oracle only keeps track of the source size, which should be the
- // size of the capture region. If the capture region is empty, we shouldn't
- // capture.
- const gfx::Rect capture_region =
- resolved_target_->GetCopyOutputRequestRegion(target_->sub_target);
- if (capture_region.IsEmpty()) {
- return;
- }
DCHECK(capture_region.size() == source_size);
+ if (absl::holds_alternative<RegionCaptureCropId>(target_->sub_target)) {
+ const float scale_factor = frame_metadata.device_scale_factor;
+ metadata.region_capture_rect =
+ scale_factor ? ScaleToEnclosingRect(capture_region, 1.0f / scale_factor)
+ : capture_region;
+ }
+ // Note that this is done unconditionally, as a new crop version may indicate
+ // that the stream has been successfully uncropped.
+ metadata.crop_version = crop_version_;
+
CaptureRequestProperties request_properties(
capture_frame_number, oracle_frame_number, content_version_, content_rect,
- capture_region,
- resolved_target_->GetCopyOutputRequestRegion(VideoCaptureSubTarget{}),
- std::move(frame), base::TimeTicks::Now());
+ capture_region, compositor_frame_region, std::move(frame),
+ base::TimeTicks::Now());
+
+ const bool use_nv12_with_textures =
+ buffer_format_preference_ ==
+ mojom::BufferFormatPreference::kPreferGpuMemoryBuffer &&
+ pixel_format_ == media::PIXEL_FORMAT_NV12;
+
+ absl::optional<BlitRequest> blit_request;
+ if (use_nv12_with_textures) {
+ std::array<gpu::MailboxHolder, 3> mailbox_holders = {
+ request_properties.frame->mailbox_holder(0),
+ request_properties.frame->mailbox_holder(1), gpu::MailboxHolder{}};
+ blit_request = BlitRequest(content_rect.origin(), mailbox_holders);
+ }
// Request a copy of the next frame from the frame sink.
auto request = std::make_unique<CopyOutputRequest>(
- pixel_format_ == media::PIXEL_FORMAT_I420
- ? CopyOutputRequest::ResultFormat::I420_PLANES
- : CopyOutputRequest::ResultFormat::RGBA,
- CopyOutputRequest::ResultDestination::kSystemMemory,
+ VideoPixelFormatToCopyOutputRequestFormat(pixel_format_),
+ use_nv12_with_textures
+ ? CopyOutputRequest::ResultDestination::kNativeTextures
+ : CopyOutputRequest::ResultDestination::kSystemMemory,
base::BindOnce(&FrameSinkVideoCapturerImpl::DidCopyFrame,
capture_weak_factory_.GetWeakPtr(),
std::move(request_properties)));
+
request->set_result_task_runner(base::SequencedTaskRunnerHandle::Get());
request->set_source(copy_request_source_);
request->set_area(capture_region);
@@ -756,6 +889,10 @@ void FrameSinkVideoCapturerImpl::MaybeCaptureFrame(
// damage over all the frames that weren't captured.
request->set_result_selection(gfx::Rect(content_rect.size()));
+ if (blit_request) {
+ request->set_blit_request(*blit_request);
+ }
+
// Clear the |dirty_rect_|, to indicate all changes at the source are now
// being captured.
dirty_rect_ = gfx::Rect();
@@ -869,7 +1006,7 @@ void FrameSinkVideoCapturerImpl::DidCopyFrame(
}
UMA_HISTOGRAM_BOOLEAN("Viz.FrameSinkVideoCapturer.I420.CaptureSucceeded",
success);
- } else {
+ } else if (pixel_format_ == media::PIXEL_FORMAT_ARGB) {
int stride = frame->stride(VideoFrame::kARGBPlane);
DCHECK_EQ(media::PIXEL_FORMAT_ARGB, pixel_format_);
uint8_t* const pixels = frame->visible_data(VideoFrame::kARGBPlane) +
@@ -884,19 +1021,21 @@ void FrameSinkVideoCapturerImpl::DidCopyFrame(
}
UMA_HISTOGRAM_BOOLEAN("Viz.FrameSinkVideoCapturer.RGBA.CaptureSucceeded",
success);
+ } else {
+ DCHECK_EQ(pixel_format_, media::PIXEL_FORMAT_NV12);
}
if (frame) {
- gfx::Rect sub_region = properties.capture_rect;
- // In some cases, the content_rect is smaller than the capture_rect.
- sub_region.ClampToCenteredSize(content_rect.size());
-
- auto overlay_renderer = VideoCaptureOverlay::MakeCombinedRenderer(
- GetOverlaysInOrder(),
- VideoCaptureOverlay::CapturedFrameProperties{
- properties.active_frame_rect, sub_region, frame->format()});
- if (overlay_renderer) {
- std::move(overlay_renderer).Run(frame.get());
+ if (pixel_format_ != media::PIXEL_FORMAT_NV12) {
+ // TODO(bialpio): implement overlays for NV12!
+ auto overlay_renderer = VideoCaptureOverlay::MakeCombinedRenderer(
+ GetOverlaysInOrder(),
+ VideoCaptureOverlay::CapturedFrameProperties{
+ properties.active_frame_rect, properties.capture_rect,
+ content_rect, frame->format()});
+ if (overlay_renderer) {
+ std::move(overlay_renderer).Run(frame.get());
+ }
}
// The result may be smaller than what was requested, if unforeseen
@@ -967,7 +1106,7 @@ void FrameSinkVideoCapturerImpl::MaybeDeliverFrame(
TRACE_EVENT_ASYNC_END1("gpu.capture", "Capture", oracle_frame_number,
"success", false);
- ScheduleRefreshFrame();
+ RequestRefreshFrame();
return;
}
@@ -988,8 +1127,8 @@ void FrameSinkVideoCapturerImpl::MaybeDeliverFrame(
// send to the consumer.
auto handle = frame_pool_->CloneHandleForDelivery(*frame);
DCHECK(handle);
- DCHECK(handle->is_read_only_shmem_region());
- DCHECK(handle->get_read_only_shmem_region().IsValid());
+ DCHECK(!handle->is_read_only_shmem_region() ||
+ handle->get_read_only_shmem_region().IsValid());
// Assemble frame layout, format, and metadata into a mojo struct to send to
// the consumer.
@@ -1024,10 +1163,11 @@ void FrameSinkVideoCapturerImpl::MaybeDeliverFrame(
// Send the frame to the consumer.
consumer_->OnFrameCaptured(std::move(handle), std::move(info), content_rect,
std::move(callbacks));
+ consumer_informed_of_empty_region_ = false;
}
gfx::Size FrameSinkVideoCapturerImpl::AdjustSizeForPixelFormat(
- const gfx::Size& raw_size) {
+ const gfx::Size& raw_size) const {
if (pixel_format_ == media::PIXEL_FORMAT_ARGB) {
gfx::Size result(raw_size);
if (result.width() <= 0)
@@ -1036,7 +1176,8 @@ gfx::Size FrameSinkVideoCapturerImpl::AdjustSizeForPixelFormat(
result.set_height(1);
return result;
}
- DCHECK_EQ(media::PIXEL_FORMAT_I420, pixel_format_);
+ DCHECK(media::PIXEL_FORMAT_I420 == pixel_format_ ||
+ media::PIXEL_FORMAT_NV12 == pixel_format_);
gfx::Size result(raw_size.width() & ~1, raw_size.height() & ~1);
if (result.width() <= 0)
result.set_width(2);
@@ -1097,6 +1238,19 @@ float FrameSinkVideoCapturerImpl::GetPipelineUtilization() const {
return static_cast<float>(num_frames_in_flight_) / kDesignLimitMaxFrames;
}
+void FrameSinkVideoCapturerImpl::MaybeInformConsumerOfEmptyRegion() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ if (!consumer_ || !target_ ||
+ !absl::holds_alternative<RegionCaptureCropId>(target_->sub_target) ||
+ consumer_informed_of_empty_region_) {
+ return;
+ }
+
+ consumer_->OnFrameWithEmptyRegionCapture();
+ consumer_informed_of_empty_region_ = true;
+}
+
FrameSinkVideoCapturerImpl::CapturedFrame::CapturedFrame(
int64_t capture_frame_number,
OracleFrameNumber oracle_frame_number,
diff --git a/chromium/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.h b/chromium/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.h
index 1084a754a28..4e518a4b595 100644
--- a/chromium/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.h
+++ b/chromium/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.h
@@ -27,8 +27,10 @@
#include "components/viz/service/frame_sinks/video_capture/in_flight_frame_delivery.h"
#include "components/viz/service/frame_sinks/video_capture/video_capture_overlay.h"
#include "components/viz/service/frame_sinks/video_capture/video_frame_pool.h"
+#include "components/viz/service/viz_service_export.h"
#include "media/base/video_frame.h"
#include "media/capture/content/video_capture_oracle.h"
+#include "media/video/renderable_gpu_memory_buffer_video_frame_pool.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver.h"
@@ -46,6 +48,7 @@ namespace viz {
class CopyOutputResult;
class FrameSinkVideoCapturerManager;
+class GmbVideoFramePoolContextProvider;
// Captures the frames of a CompositorFrameSink's surface as a video stream. See
// mojom for usage details.
@@ -74,11 +77,14 @@ class VIZ_SERVICE_EXPORT FrameSinkVideoCapturerImpl final
public VideoCaptureOverlay::FrameSource,
public mojom::FrameSinkVideoCapturer {
public:
+ using GpuMemoryBufferVideoFramePoolContext =
+ media::RenderableGpuMemoryBufferVideoFramePool::Context;
// |frame_sink_manager| must outlive this instance. Binds this instance to the
// Mojo message pipe endpoint in |receiver|, but |receiver| may be empty for
// unit testing.
FrameSinkVideoCapturerImpl(
FrameSinkVideoCapturerManager* frame_sink_manager,
+ GmbVideoFramePoolContextProvider* gmb_video_frame_pool_context_provider,
mojo::PendingReceiver<mojom::FrameSinkVideoCapturer> receiver,
std::unique_ptr<media::VideoCaptureOracle> oracle,
bool log_to_webrtc);
@@ -94,11 +100,9 @@ class VIZ_SERVICE_EXPORT FrameSinkVideoCapturerImpl final
// can be resolved.
const absl::optional<VideoCaptureTarget>& target() const { return target_; }
- // Sets the resolved target, detaching this capturer from the previous target
- // (if any), and attaching to the new target. This is called by the frame sink
- // manager. If |target| is null, the capturer goes idle and expects this
- // method to be called again in the near future, once the target becomes known
- // to the frame sink manager.
+ // In some cases, the target to resolve is already known and can be passed
+ // directly instead of attempting to resolve it in |ResolveTarget|. This is
+ // called by the frame sink manager.
void SetResolvedTarget(CapturableFrameSink* target);
// Notifies this capturer that the current target will be destroyed, and the
@@ -114,10 +118,15 @@ class VIZ_SERVICE_EXPORT FrameSinkVideoCapturerImpl final
const gfx::Size& max_size,
bool use_fixed_aspect_ratio) final;
void SetAutoThrottlingEnabled(bool enabled) final;
- void ChangeTarget(const absl::optional<VideoCaptureTarget>& target) final;
+ void ChangeTarget(const absl::optional<VideoCaptureTarget>& target,
+ uint32_t crop_version) final;
void Start(mojo::PendingRemote<mojom::FrameSinkVideoConsumer> consumer,
mojom::BufferFormatPreference buffer_format_preference) final;
void Stop() final;
+ // If currently stopped, starts the refresh frame timer to guarantee a frame
+ // representing the most up-to-date content will be sent to the consumer in
+ // the near future. This refresh operation will be canceled if a compositing
+ // event triggers a frame capture in the meantime.
void RequestRefreshFrame() final;
void CreateOverlay(int32_t stacking_index,
mojo::PendingReceiver<mojom::FrameSinkVideoCaptureOverlay>
@@ -151,20 +160,20 @@ class VIZ_SERVICE_EXPORT FrameSinkVideoCapturerImpl final
// exceeding 60% of the design limit is considered "red line" operation.
static constexpr float kTargetPipelineUtilization = 0.6f;
+ // The maximum refresh delay. Provides an upper limit for how long the
+ // capture source will remain idle. Callers of the API that request a refresh
+ // frame may end up waiting up to this long.
+ static constexpr base::TimeDelta kMaxRefreshDelay = base::Seconds(1);
+
private:
friend class FrameSinkVideoCapturerTest;
using OracleFrameNumber =
decltype(std::declval<media::VideoCaptureOracle>().next_frame_number());
- // Starts the refresh frame timer to guarantee a frame representing the most
- // up-to-date content will be sent to the consumer in the near future. This
- // refresh operation will be canceled if a compositing event triggers a frame
- // capture in the meantime.
- void ScheduleRefreshFrame();
-
// Returns the delay that should be used when setting the refresh timer. This
- // is based on the current oracle prediction for frame duration.
+ // is based on the current oracle prediction for frame duration and is
+ // bounded by |kMaxRefreshDelay|.
base::TimeDelta GetDelayBeforeNextRefreshAttempt() const;
// Called whenever a major damage event, such as a capture parameter change, a
@@ -187,6 +196,14 @@ class VIZ_SERVICE_EXPORT FrameSinkVideoCapturerImpl final
const CompositorFrameMetadata& frame_metadata) final;
bool IsVideoCaptureStarted() final;
+ // Resolves the capturable frame sink target using the current value of
+ // |target_|, detaching this capturer from the previous target (if any), and
+ // attaching to the new found target. This is called by the frame sink
+ // manager. If |target_| is null, the capturer goes idle and expects this
+ // method to be called again in the near future, once the target becomes known
+ // to the frame sink manager.
+ void ResolveTarget();
+
// VideoCaptureOverlay::FrameSource implementation:
gfx::Size GetSourceSize() final;
void InvalidateRect(const gfx::Rect& rect) final;
@@ -240,6 +257,8 @@ class VIZ_SERVICE_EXPORT FrameSinkVideoCapturerImpl final
// The actual content size of the copied frame, as a post-scaled size
// with an origin at (0, 0).
+ // TODO(https://crbug.com/1287686): replace zero-origin gfx::Rect with
+ // gfx::Size.
gfx::Rect content_rect;
// The requested capture region, may be larger or at a different
@@ -281,7 +300,7 @@ class VIZ_SERVICE_EXPORT FrameSinkVideoCapturerImpl final
// For ARGB format, ensures that every dimension of |size| is positive. For
// I420 format, ensures that every dimension is even and at least 2.
- gfx::Size AdjustSizeForPixelFormat(const gfx::Size& size);
+ gfx::Size AdjustSizeForPixelFormat(const gfx::Size& size) const;
// Expands |rect| such that its x, y, right, and bottom values are even
// numbers.
@@ -315,6 +334,12 @@ class VIZ_SERVICE_EXPORT FrameSinkVideoCapturerImpl final
// increasing pool utilization, but it would increase pipeline utilization.
float GetPipelineUtilization() const;
+ // Informs the consumer that the frame was dropped due to being cropped
+ // to zero pixels. Only informs the consumer if this is the first such
+ // frame since the last actually-delivered frame, so as to avoid being
+ // overly chatty and waste CPU.
+ void MaybeInformConsumerOfEmptyRegion();
+
// Owner/Manager of this instance.
const raw_ptr<FrameSinkVideoCapturerManager> frame_sink_manager_;
@@ -378,6 +403,9 @@ class VIZ_SERVICE_EXPORT FrameSinkVideoCapturerImpl final
// Note: This is always set, but the instance is overridden for unit testing.
absl::optional<base::OneShotTimer> refresh_frame_retry_timer_;
+ raw_ptr<GmbVideoFramePoolContextProvider>
+ gmb_video_frame_pool_context_provider_;
+
// Provides a pool of VideoFrames that can be efficiently delivered across
// processes. The size of this pool is used to limit the maximum number of
// frames in-flight at any one time.
@@ -440,6 +468,17 @@ class VIZ_SERVICE_EXPORT FrameSinkVideoCapturerImpl final
// Enables debug log messages to be sent to webrtc native log.
const bool log_to_webrtc_;
+ // Avoids being overly chatty and wasting CPU when informing the consumer
+ // of frames dropped due to being cropped to zero pixels.
+ bool consumer_informed_of_empty_region_ = false;
+
+ // The crop-version allows Viz to communicate back to Blink the information
+ // of which crop-target each frame is associated with. Better, if cropTo()
+ // is called multiple times, oscillating between two targets, Blink can even
+ // tell whether the frame is cropped to an earlier or later invocation of
+ // cropTo() for a given target, because the crop-version keeps increasing.
+ uint32_t crop_version_ = 0;
+
// A weak pointer factory used for cancelling the results from any in-flight
// copy output requests.
base::WeakPtrFactory<FrameSinkVideoCapturerImpl> capture_weak_factory_{this};
diff --git a/chromium/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl_unittest.cc b/chromium/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl_unittest.cc
index 3f66223ac4d..ede7ea61db7 100644
--- a/chromium/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl_unittest.cc
+++ b/chromium/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl_unittest.cc
@@ -77,7 +77,7 @@ bool CompareVarsInCompositorFrameMetadata(
}
// Dummy frame sink ID.
-constexpr FrameSinkId kFrameSinkId = FrameSinkId(1, 1);
+const VideoCaptureTarget kVideoCaptureTarget(FrameSinkId(1, 1));
// The compositor frame interval.
constexpr auto kVsyncInterval = base::Seconds(1) / 60;
@@ -120,7 +120,7 @@ void PropagateMojoTasks(
class MockFrameSinkManager : public FrameSinkVideoCapturerManager {
public:
MOCK_METHOD1(FindCapturableFrameSink,
- CapturableFrameSink*(const FrameSinkId& frame_sink_id));
+ CapturableFrameSink*(const VideoCaptureTarget& target));
MOCK_METHOD1(OnCapturerConnectionLost,
void(FrameSinkVideoCapturerImpl* capturer));
};
@@ -146,6 +146,10 @@ class MockConsumer : public mojom::FrameSinkVideoConsumer {
return receiver_.BindNewPipeAndPassRemote();
}
+ int num_frames_with_empty_region() const {
+ return num_frames_with_empty_region_;
+ }
+
private:
void OnFrameCaptured(
media::mojom::VideoBufferHandlePtr data,
@@ -201,6 +205,12 @@ class MockConsumer : public mojom::FrameSinkVideoConsumer {
std::move(callbacks_remote)));
}
+ void OnFrameWithEmptyRegionCapture() final {
+ ++num_frames_with_empty_region_;
+ }
+
+ int num_frames_with_empty_region_ = 0;
+
mojo::Receiver<mojom::FrameSinkVideoConsumer> receiver_{this};
std::vector<scoped_refptr<VideoFrame>> frames_;
std::vector<base::OnceClosure> done_callbacks_;
@@ -255,17 +265,24 @@ class FakeCapturableFrameSink : public CapturableFrameSink {
Client* attached_client() const { return client_; }
- const FrameSinkId& GetFrameSinkId() const override { return kFrameSinkId; }
+ const FrameSinkId& GetFrameSinkId() const override {
+ return kVideoCaptureTarget.frame_sink_id;
+ }
void AttachCaptureClient(Client* client) override {
ASSERT_FALSE(client_);
ASSERT_TRUE(client);
client_ = client;
+ if (client_->IsVideoCaptureStarted())
+ OnClientCaptureStarted();
}
void DetachCaptureClient(Client* client) override {
ASSERT_TRUE(client);
ASSERT_EQ(client, client_);
+ if (client_->IsVideoCaptureStarted())
+ OnClientCaptureStopped();
+
client_ = nullptr;
}
@@ -464,7 +481,8 @@ class FrameSinkVideoCapturerTest : public testing::Test {
true /* enable_auto_throttling */);
oracle_ = oracle.get();
capturer_ = std::make_unique<FrameSinkVideoCapturerImpl>(
- &frame_sink_manager_, mojo::NullReceiver(), std::move(oracle), false);
+ &frame_sink_manager_, nullptr, mojo::NullReceiver(), std::move(oracle),
+ false);
}
void SetUp() override {
@@ -594,24 +612,26 @@ class FrameSinkVideoCapturerTest : public testing::Test {
// Tests that the capturer attaches to a frame sink immediately, in the case
// where the frame sink was already known by the manager.
TEST_F(FrameSinkVideoCapturerTest, ResolvesTargetImmediately) {
- EXPECT_CALL(frame_sink_manager_, FindCapturableFrameSink(kFrameSinkId))
+ EXPECT_CALL(frame_sink_manager_, FindCapturableFrameSink(kVideoCaptureTarget))
.WillRepeatedly(Return(&frame_sink_));
EXPECT_FALSE(capturer_->target());
- capturer_->ChangeTarget(VideoCaptureTarget(kFrameSinkId));
- EXPECT_EQ(kFrameSinkId, capturer_->target()->frame_sink_id);
+ capturer_->ChangeTarget(kVideoCaptureTarget, /*crop_version=*/0);
+ EXPECT_EQ(kVideoCaptureTarget.frame_sink_id,
+ capturer_->target()->frame_sink_id);
EXPECT_EQ(capturer_.get(), frame_sink_.attached_client());
}
// Tests that the capturer attaches to a frame sink later, in the case where the
// frame sink becomes known to the manager at some later point.
TEST_F(FrameSinkVideoCapturerTest, ResolvesTargetLater) {
- EXPECT_CALL(frame_sink_manager_, FindCapturableFrameSink(kFrameSinkId))
+ EXPECT_CALL(frame_sink_manager_, FindCapturableFrameSink(kVideoCaptureTarget))
.WillRepeatedly(Return(nullptr));
EXPECT_FALSE(capturer_->target());
- capturer_->ChangeTarget(VideoCaptureTarget(kFrameSinkId));
- EXPECT_EQ(kFrameSinkId, capturer_->target()->frame_sink_id);
+ capturer_->ChangeTarget(kVideoCaptureTarget, /*crop_version=*/0);
+ EXPECT_EQ(kVideoCaptureTarget.frame_sink_id,
+ capturer_->target()->frame_sink_id);
EXPECT_EQ(nullptr, frame_sink_.attached_client());
capturer_->SetResolvedTarget(&frame_sink_);
@@ -621,7 +641,7 @@ TEST_F(FrameSinkVideoCapturerTest, ResolvesTargetLater) {
// Tests that no initial frame is sent after Start() is called until after the
// target has been resolved.
TEST_F(FrameSinkVideoCapturerTest, PostponesCaptureWithoutATarget) {
- EXPECT_CALL(frame_sink_manager_, FindCapturableFrameSink(kFrameSinkId))
+ EXPECT_CALL(frame_sink_manager_, FindCapturableFrameSink(kVideoCaptureTarget))
.WillRepeatedly(Return(&frame_sink_));
MockConsumer consumer;
@@ -645,7 +665,7 @@ TEST_F(FrameSinkVideoCapturerTest, PostponesCaptureWithoutATarget) {
// Now, set the target. As it resolves, the capturer will immediately attempt
// a refresh capture, which will cancel the timer and trigger a copy request.
- capturer_->ChangeTarget(VideoCaptureTarget(kFrameSinkId));
+ capturer_->ChangeTarget(kVideoCaptureTarget, /*crop_version=*/0);
EXPECT_EQ(1, frame_sink_.num_copy_results());
EXPECT_FALSE(IsRefreshRetryTimerRunning());
@@ -658,10 +678,10 @@ TEST_F(FrameSinkVideoCapturerTest, PostponesCaptureWithoutATarget) {
// consumer.
TEST_F(FrameSinkVideoCapturerTest, CapturesCompositedFrames) {
frame_sink_.SetCopyOutputColor(YUVColor{0x80, 0x80, 0x80});
- EXPECT_CALL(frame_sink_manager_, FindCapturableFrameSink(kFrameSinkId))
+ EXPECT_CALL(frame_sink_manager_, FindCapturableFrameSink(kVideoCaptureTarget))
.WillRepeatedly(Return(&frame_sink_));
- capturer_->ChangeTarget(VideoCaptureTarget(kFrameSinkId));
+ capturer_->ChangeTarget(kVideoCaptureTarget, /*crop_version=*/0);
EXPECT_FALSE(IsRefreshRetryTimerRunning());
MockConsumer consumer;
@@ -753,10 +773,10 @@ TEST_F(FrameSinkVideoCapturerTest, CapturesCompositedFrames) {
// that is because there are too many copy requests in-flight or because the
// consumer has not finished consuming frames fast enough.
TEST_F(FrameSinkVideoCapturerTest, HaltsWhenPoolIsFull) {
- EXPECT_CALL(frame_sink_manager_, FindCapturableFrameSink(kFrameSinkId))
+ EXPECT_CALL(frame_sink_manager_, FindCapturableFrameSink(kVideoCaptureTarget))
.WillRepeatedly(Return(&frame_sink_));
- capturer_->ChangeTarget(VideoCaptureTarget(kFrameSinkId));
+ capturer_->ChangeTarget(kVideoCaptureTarget, /*crop_version=*/0);
NiceMock<MockConsumer> consumer;
StartCapture(&consumer);
@@ -873,10 +893,10 @@ TEST_F(FrameSinkVideoCapturerTest, DeliversFramesInOrder) {
std::vector<YUVColor> colors;
colors.push_back(YUVColor{0x00, 0x80, 0x80});
frame_sink_.SetCopyOutputColor(colors.back());
- EXPECT_CALL(frame_sink_manager_, FindCapturableFrameSink(kFrameSinkId))
+ EXPECT_CALL(frame_sink_manager_, FindCapturableFrameSink(kVideoCaptureTarget))
.WillRepeatedly(Return(&frame_sink_));
- capturer_->ChangeTarget(VideoCaptureTarget(kFrameSinkId));
+ capturer_->ChangeTarget(kVideoCaptureTarget, /*crop_version=*/0);
NiceMock<MockConsumer> consumer;
StartCapture(&consumer);
@@ -930,10 +950,10 @@ TEST_F(FrameSinkVideoCapturerTest, DeliversFramesInOrder) {
TEST_F(FrameSinkVideoCapturerTest, CancelsInFlightCapturesOnStop) {
const YUVColor color1 = {0xaa, 0xbb, 0xcc};
frame_sink_.SetCopyOutputColor(color1);
- EXPECT_CALL(frame_sink_manager_, FindCapturableFrameSink(kFrameSinkId))
+ EXPECT_CALL(frame_sink_manager_, FindCapturableFrameSink(kVideoCaptureTarget))
.WillRepeatedly(Return(&frame_sink_));
- capturer_->ChangeTarget(VideoCaptureTarget(kFrameSinkId));
+ capturer_->ChangeTarget(kVideoCaptureTarget, /*crop_version=*/0);
// Start capturing to the first consumer.
MockConsumer consumer;
@@ -1017,10 +1037,10 @@ TEST_F(FrameSinkVideoCapturerTest, CancelsInFlightCapturesOnStop) {
// the consumer.
TEST_F(FrameSinkVideoCapturerTest, EventuallySendsARefreshFrame) {
frame_sink_.SetCopyOutputColor(YUVColor{0x80, 0x80, 0x80});
- EXPECT_CALL(frame_sink_manager_, FindCapturableFrameSink(kFrameSinkId))
+ EXPECT_CALL(frame_sink_manager_, FindCapturableFrameSink(kVideoCaptureTarget))
.WillRepeatedly(Return(&frame_sink_));
- capturer_->ChangeTarget(VideoCaptureTarget(kFrameSinkId));
+ capturer_->ChangeTarget(kVideoCaptureTarget, /*crop_version=*/0);
MockConsumer consumer;
const int num_refresh_frames = 2; // Initial, plus later refresh.
@@ -1073,10 +1093,10 @@ TEST_F(FrameSinkVideoCapturerTest, EventuallySendsARefreshFrame) {
TEST_F(FrameSinkVideoCapturerTest,
RessurectsFramesForChangingCaptureResolution) {
frame_sink_.SetCopyOutputColor(YUVColor{0x80, 0x80, 0x80});
- EXPECT_CALL(frame_sink_manager_, FindCapturableFrameSink(kFrameSinkId))
+ EXPECT_CALL(frame_sink_manager_, FindCapturableFrameSink(kVideoCaptureTarget))
.WillRepeatedly(Return(&frame_sink_));
- capturer_->ChangeTarget(VideoCaptureTarget(kFrameSinkId));
+ capturer_->ChangeTarget(kVideoCaptureTarget, /*crop_version=*/0);
MockConsumer consumer;
constexpr int num_refresh_frames = 3; // Initial, plus two refreshes after
@@ -1171,9 +1191,9 @@ TEST_F(FrameSinkVideoCapturerTest,
// and refreshes cause variables of the cached CompositorFrameMetadata
// (|last_frame_metadata|) to be used.
TEST_F(FrameSinkVideoCapturerTest, CompositorFrameMetadataReachesConsumer) {
- EXPECT_CALL(frame_sink_manager_, FindCapturableFrameSink(kFrameSinkId))
+ EXPECT_CALL(frame_sink_manager_, FindCapturableFrameSink(kVideoCaptureTarget))
.WillRepeatedly(Return(&frame_sink_));
- capturer_->ChangeTarget(VideoCaptureTarget(kFrameSinkId));
+ capturer_->ChangeTarget(kVideoCaptureTarget, /*crop_version=*/0);
MockConsumer consumer;
// Initial refresh frame for starting capture, plus later refresh.
@@ -1231,9 +1251,9 @@ TEST_F(FrameSinkVideoCapturerTest, CompositorFrameMetadataReachesConsumer) {
// Tests that frame metadata CAPTURE_COUNTER and CAPTURE_UPDATE_RECT are sent to
// the consumer as part of each frame delivery.
TEST_F(FrameSinkVideoCapturerTest, DeliversUpdateRectAndCaptureCounter) {
- EXPECT_CALL(frame_sink_manager_, FindCapturableFrameSink(kFrameSinkId))
+ EXPECT_CALL(frame_sink_manager_, FindCapturableFrameSink(kVideoCaptureTarget))
.WillRepeatedly(Return(&frame_sink_));
- capturer_->ChangeTarget(VideoCaptureTarget(kFrameSinkId));
+ capturer_->ChangeTarget(kVideoCaptureTarget, /*crop_version=*/0);
MockConsumer consumer;
StartCapture(&consumer);
@@ -1346,9 +1366,9 @@ TEST_F(FrameSinkVideoCapturerTest, DeliversUpdateRectAndCaptureCounter) {
// CAPTURE_COUNTER metadata value sent to the consumer reflects the frame drops
// indicating that CAPTURE_UPDATE_RECT must be ignored.
TEST_F(FrameSinkVideoCapturerTest, CaptureCounterSkipsWhenFramesAreDropped) {
- EXPECT_CALL(frame_sink_manager_, FindCapturableFrameSink(kFrameSinkId))
+ EXPECT_CALL(frame_sink_manager_, FindCapturableFrameSink(kVideoCaptureTarget))
.WillRepeatedly(Return(&frame_sink_));
- capturer_->ChangeTarget(VideoCaptureTarget(kFrameSinkId));
+ capturer_->ChangeTarget(kVideoCaptureTarget, /*crop_version=*/0);
MockConsumer consumer;
StartCapture(&consumer);
@@ -1397,10 +1417,10 @@ TEST_F(FrameSinkVideoCapturerTest, CaptureCounterSkipsWhenFramesAreDropped) {
}
TEST_F(FrameSinkVideoCapturerTest, ClientCaptureStartsAndStops) {
- EXPECT_CALL(frame_sink_manager_, FindCapturableFrameSink(kFrameSinkId))
+ EXPECT_CALL(frame_sink_manager_, FindCapturableFrameSink(kVideoCaptureTarget))
.WillRepeatedly(Return(&frame_sink_));
- capturer_->ChangeTarget(VideoCaptureTarget(kFrameSinkId));
+ capturer_->ChangeTarget(kVideoCaptureTarget, /*crop_version=*/0);
EXPECT_EQ(frame_sink_.number_clients_capturing(), 0);
// Start capturing. frame_sink_ should now have one client capturing.
@@ -1415,15 +1435,19 @@ TEST_F(FrameSinkVideoCapturerTest, ClientCaptureStartsAndStops) {
TEST_F(FrameSinkVideoCapturerTest, RegionCaptureCropId) {
SwitchToSizeSet(kSizeSets[4]);
- EXPECT_CALL(frame_sink_manager_, FindCapturableFrameSink(kFrameSinkId))
+ EXPECT_CALL(frame_sink_manager_, FindCapturableFrameSink(kVideoCaptureTarget))
.WillRepeatedly(Return(&frame_sink_));
- capturer_->ChangeTarget(VideoCaptureTarget(kFrameSinkId));
+ capturer_->ChangeTarget(kVideoCaptureTarget, /*crop_version=*/0);
EXPECT_EQ(frame_sink_.number_clients_capturing(), 0);
- static const auto kCropId = RegionCaptureCropId::CreateRandom();
- static const gfx::Rect kCropBounds{1, 2, 640, 478};
+ const auto kCropId = RegionCaptureCropId::CreateRandom();
+ constexpr gfx::Rect kCropBounds{1, 2, 640, 478};
+
+ VideoCaptureTarget target(kVideoCaptureTarget.frame_sink_id, kCropId);
frame_sink_.set_crop_bounds(kCropBounds);
- capturer_->ChangeTarget(VideoCaptureTarget(kFrameSinkId, kCropId));
+ EXPECT_CALL(frame_sink_manager_, FindCapturableFrameSink(target))
+ .WillRepeatedly(Return(&frame_sink_));
+ capturer_->ChangeTarget(std::move(target), /*crop_version=*/1);
// Start capturing. frame_sink_ should now have one client capturing.
NiceMock<MockConsumer> consumer;
@@ -1434,15 +1458,164 @@ TEST_F(FrameSinkVideoCapturerTest, RegionCaptureCropId) {
EXPECT_EQ(kCropId, frame_sink_.current_crop_id());
}
-TEST_F(FrameSinkVideoCapturerTest, HandlesSubtreeCaptureId) {
+TEST_F(FrameSinkVideoCapturerTest,
+ RegionCaptureTargetIsSetLaterWhenNotInitiallyAvailable) {
SwitchToSizeSet(kSizeSets[4]);
- EXPECT_CALL(frame_sink_manager_, FindCapturableFrameSink(kFrameSinkId))
+
+ const auto kCropId = RegionCaptureCropId::CreateRandom();
+ constexpr gfx::Rect kCropBounds{1, 2, 640, 478};
+
+ // The region capture crop identifier is not associated with any frame
+ // sinks yet.
+ VideoCaptureTarget target(kVideoCaptureTarget.frame_sink_id, kCropId);
+ EXPECT_CALL(frame_sink_manager_, FindCapturableFrameSink(target))
+ .WillRepeatedly(Return(nullptr));
+ capturer_->ChangeTarget(target, /*crop_version=*/0);
+
+ // Start capture, although we don't have a frame sink yet.
+ NiceMock<MockConsumer> consumer;
+ StartCapture(&consumer);
+ EXPECT_EQ(frame_sink_.number_clients_capturing(), 0);
+
+ // A frame sink that has |kCropId| associated with it should now be
+ // available, and the capturer should automatically attach to it.
+ frame_sink_.set_crop_bounds(kCropBounds);
+ EXPECT_CALL(frame_sink_manager_, FindCapturableFrameSink(target))
.WillRepeatedly(Return(&frame_sink_));
+ EXPECT_TRUE(IsRefreshRetryTimerRunning());
+ AdvanceClockForRefreshTimer();
+
+ EXPECT_EQ(frame_sink_.number_clients_capturing(), 1);
+ EXPECT_EQ(kCropId, frame_sink_.current_crop_id());
+}
- static const gfx::Rect kCaptureBounds{1, 2, 1024, 768};
- static const SubtreeCaptureId kCaptureId{1234567u};
+// Tests that frames can be successfully delivered after one is dropped due to
+// having a zero-sized capture region.
+TEST_F(FrameSinkVideoCapturerTest, HandlesFrameWithEmptyRegion) {
+ const auto kCropId = RegionCaptureCropId::CreateRandom();
+ constexpr gfx::Rect kValidCropBounds{1, 2, 640, 478};
+
+ SwitchToSizeSet(kSizeSets[4]);
+ VideoCaptureTarget target(kVideoCaptureTarget.frame_sink_id, kCropId);
+ frame_sink_.set_crop_bounds(gfx::Rect{});
+ EXPECT_CALL(frame_sink_manager_, FindCapturableFrameSink(target))
+ .WillRepeatedly(Return(&frame_sink_));
+
+ NiceMock<MockConsumer> consumer;
+ EXPECT_CALL(consumer, OnFrameCapturedMock()).Times(0);
+ EXPECT_CALL(consumer, OnStopped()).Times(1);
+
+ // Start capturing. frame_sink_ should now have one client capturing.
+ StartCapture(&consumer);
+ capturer_->ChangeTarget(target, /*crop_version=*/0);
+ EXPECT_EQ(frame_sink_.number_clients_capturing(), 1);
+
+ // No copy requests should have been issued/executed.
+ EXPECT_EQ(0, frame_sink_.num_copy_results());
+
+ // The refresh timer should be running--our initial attempt to get a frame
+ // failed due to being cropped to zero.
+ EXPECT_TRUE(IsRefreshRetryTimerRunning());
+
+ // Simulate several refresh timer intervals elapsing and the timer firing.
+ // Nothing should happen because the frames should be cropped to zero.
+ for (int i = 0; i < 5; ++i) {
+ AdvanceClockForRefreshTimer();
+ ASSERT_EQ(0, frame_sink_.num_copy_results());
+ ASSERT_TRUE(IsRefreshRetryTimerRunning());
+ }
+ // We should only get one notification--the first empty frame.
+ EXPECT_EQ(1, consumer.num_frames_with_empty_region());
+
+ // Now, set the crop bounds to be valid--meaning completely contained inside
+ // of the source rect. As it resolves, the next refresh capture should trigger
+ // a copy request.
+ frame_sink_.set_crop_bounds(kValidCropBounds);
+ AdvanceClockForRefreshTimer();
+ EXPECT_EQ(1, frame_sink_.num_copy_results());
+ EXPECT_FALSE(IsRefreshRetryTimerRunning());
+ EXPECT_EQ(1, consumer.num_frames_with_empty_region());
+
+ // The empty frame notification for the consumer is reset when the frame
+ // is delivered to the consumer, so we need to have a result before it gets
+ // reset.
+ EXPECT_CALL(consumer, OnFrameCapturedMock()).Times(1);
+ frame_sink_.SendCopyOutputResult(0);
+
+ // Now, set back to an entirely empty crop bounds--we should get a
+ // notification that we have an empty region.
+ frame_sink_.set_crop_bounds(gfx::Rect{});
+ capturer_->RequestRefreshFrame();
+ AdvanceClockForRefreshTimer();
+ EXPECT_EQ(1, frame_sink_.num_copy_results());
+ EXPECT_TRUE(IsRefreshRetryTimerRunning());
+ EXPECT_EQ(2, consumer.num_frames_with_empty_region());
+
+ StopCapture();
+ EXPECT_FALSE(IsRefreshRetryTimerRunning());
+}
+
+// Tests that frames can be successfully delivered after one is dropped due to
+// having a capture region that does not intersect with the compositor frame. In
+// the past, it was possible for a dropped frame to cause the delivery queue to
+// no longer be emptied. See https://crbug.com/1300742.
+TEST_F(FrameSinkVideoCapturerTest, HandlesFrameWithRegionCroppedToZero) {
+ const auto kCropId = RegionCaptureCropId::CreateRandom();
+ constexpr gfx::Rect kInvalidCropBounds{800, 600, 100, 100};
+ constexpr gfx::Rect kValidCropBounds{1, 2, 640, 478};
+
+ SwitchToSizeSet(kSizeSets[4]);
+ VideoCaptureTarget target(kVideoCaptureTarget.frame_sink_id, kCropId);
+ frame_sink_.set_crop_bounds(kInvalidCropBounds);
+ EXPECT_CALL(frame_sink_manager_, FindCapturableFrameSink(target))
+ .WillRepeatedly(Return(&frame_sink_));
+
+ NiceMock<MockConsumer> consumer;
+ EXPECT_CALL(consumer, OnFrameCapturedMock()).Times(0);
+ EXPECT_CALL(consumer, OnStopped()).Times(1);
+
+ // Start capturing. frame_sink_ should now have one client capturing.
+ StartCapture(&consumer);
+ capturer_->ChangeTarget(target, /*crop_version=*/0);
+ EXPECT_EQ(frame_sink_.number_clients_capturing(), 1);
+
+ // No copy requests should have been issued/executed.
+ EXPECT_EQ(0, frame_sink_.num_copy_results());
+
+ // The refresh timer should be running--our initial attempt to get a frame
+ // failed due to being cropped to zero.
+ EXPECT_TRUE(IsRefreshRetryTimerRunning());
+
+ // Simulate several refresh timer intervals elapsing and the timer firing.
+ // Nothing should happen because the frames should be cropped to zero.
+ for (int i = 0; i < 5; ++i) {
+ AdvanceClockForRefreshTimer();
+ ASSERT_EQ(0, frame_sink_.num_copy_results());
+ ASSERT_TRUE(IsRefreshRetryTimerRunning());
+ }
+
+ // Now, set the crop bounds to be valid--meaning completely contained inside
+ // of the source rect. As it resolves, the next refresh capture should trigger
+ // a copy request.
+ frame_sink_.set_crop_bounds(kValidCropBounds);
+ AdvanceClockForRefreshTimer();
+ EXPECT_EQ(1, frame_sink_.num_copy_results());
+ EXPECT_FALSE(IsRefreshRetryTimerRunning());
+
+ StopCapture();
+ EXPECT_FALSE(IsRefreshRetryTimerRunning());
+}
+
+TEST_F(FrameSinkVideoCapturerTest, HandlesSubtreeCaptureId) {
+ SwitchToSizeSet(kSizeSets[4]);
+ constexpr gfx::Rect kCaptureBounds{1, 2, 1024, 768};
+ constexpr SubtreeCaptureId kCaptureId{1234567u};
+
+ VideoCaptureTarget target(kVideoCaptureTarget.frame_sink_id, kCaptureId);
frame_sink_.set_capture_bounds(kCaptureBounds);
- capturer_->ChangeTarget(VideoCaptureTarget(kFrameSinkId, kCaptureId));
+ EXPECT_CALL(frame_sink_manager_, FindCapturableFrameSink(target))
+ .WillRepeatedly(Return(&frame_sink_));
+ capturer_->ChangeTarget(std::move(target), /*crop_version=*/0);
// Start capturing. frame_sink_ should now have one client capturing.
NiceMock<MockConsumer> consumer;
@@ -1456,13 +1629,14 @@ TEST_F(FrameSinkVideoCapturerTest, HandlesSubtreeCaptureId) {
TEST_F(FrameSinkVideoCapturerTest, HandlesNullSubTargetPtrCorrectly) {
SwitchToSizeSet(kSizeSets[4]);
- EXPECT_CALL(frame_sink_manager_, FindCapturableFrameSink(kFrameSinkId))
+ EXPECT_CALL(frame_sink_manager_, FindCapturableFrameSink(kVideoCaptureTarget))
.WillRepeatedly(Return(&frame_sink_));
// The default cause is a target with no sub target, passed as nullptr. Since
// the SubTarget is a mojom variant, the default SubTarget::New() is actually
// a zero value subtree capture identifier.
- capturer_->ChangeTarget(VideoCaptureTarget(kFrameSinkId));
+ capturer_->ChangeTarget(VideoCaptureTarget(kVideoCaptureTarget),
+ /*crop_version=*/0);
EXPECT_EQ(frame_sink_.number_clients_capturing(), 0);
// Start capturing. frame_sink_ should now have one client capturing.
diff --git a/chromium/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_manager.h b/chromium/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_manager.h
index 15a682ae9ad..7fa2787db8f 100644
--- a/chromium/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_manager.h
+++ b/chromium/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_manager.h
@@ -8,7 +8,7 @@
namespace viz {
class CapturableFrameSink;
-class FrameSinkId;
+struct VideoCaptureTarget;
class FrameSinkVideoCapturerImpl;
// Interface implemented by the owner/manager of FrameSinkVideoCapturerImpl
@@ -17,9 +17,9 @@ class FrameSinkVideoCapturerImpl;
class FrameSinkVideoCapturerManager {
public:
// Returns the CapturableFrameSink implementation associated with the given
- // |frame_sink_id|, or nullptr if unknown.
+ // |target|, or nullptr if unknown.
virtual CapturableFrameSink* FindCapturableFrameSink(
- const FrameSinkId& frame_sink_id) = 0;
+ const VideoCaptureTarget& target) = 0;
// Called once, when the mojo binding for the given |capturer| has been
// closed. At this point, the capturer is a zombie waiting to be destroyed.
diff --git a/chromium/components/viz/service/frame_sinks/video_capture/gpu_memory_buffer_video_frame_pool.cc b/chromium/components/viz/service/frame_sinks/video_capture/gpu_memory_buffer_video_frame_pool.cc
new file mode 100644
index 00000000000..c82368c519c
--- /dev/null
+++ b/chromium/components/viz/service/frame_sinks/video_capture/gpu_memory_buffer_video_frame_pool.cc
@@ -0,0 +1,91 @@
+// Copyright 2022 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.
+
+#include "components/viz/service/frame_sinks/video_capture/gpu_memory_buffer_video_frame_pool.h"
+
+#include <utility>
+
+#include "components/viz/service/frame_sinks/gmb_video_frame_pool_context_provider.h"
+
+namespace viz {
+
+GpuMemoryBufferVideoFramePool::GpuMemoryBufferVideoFramePool(
+ int capacity,
+ GmbVideoFramePoolContextProvider* context_provider)
+ : VideoFramePool(capacity), context_provider_(context_provider) {
+ RecreateVideoFramePool();
+}
+
+GpuMemoryBufferVideoFramePool::~GpuMemoryBufferVideoFramePool() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+}
+
+scoped_refptr<media::VideoFrame>
+GpuMemoryBufferVideoFramePool::ReserveVideoFrame(media::VideoPixelFormat format,
+ const gfx::Size& size) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK_EQ(format, media::VideoPixelFormat::PIXEL_FORMAT_NV12);
+ DCHECK_LE(num_reserved_frames_, capacity());
+
+ if (num_reserved_frames_ == capacity()) {
+ return nullptr;
+ }
+
+ scoped_refptr<media::VideoFrame> result =
+ video_frame_pool_->MaybeCreateVideoFrame(size,
+ gfx::ColorSpace::CreateREC709());
+
+ if (result) {
+ num_reserved_frames_++;
+ result->AddDestructionObserver(base::BindOnce(
+ &GpuMemoryBufferVideoFramePool::OnVideoFrameDestroyed,
+ weak_factory_.GetWeakPtr(), video_frame_pool_generation_));
+ }
+
+ return result;
+}
+
+media::mojom::VideoBufferHandlePtr
+GpuMemoryBufferVideoFramePool::CloneHandleForDelivery(
+ const media::VideoFrame& frame) {
+ DCHECK(frame.HasGpuMemoryBuffer());
+
+ gfx::GpuMemoryBufferHandle handle = frame.GetGpuMemoryBuffer()->CloneHandle();
+ handle.id = gfx::GpuMemoryBufferHandle::kInvalidId;
+
+ return media::mojom::VideoBufferHandle::NewGpuMemoryBufferHandle(
+ std::move(handle));
+}
+
+size_t GpuMemoryBufferVideoFramePool::GetNumberOfReservedFrames() const {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ return num_reserved_frames_;
+}
+
+void GpuMemoryBufferVideoFramePool::RecreateVideoFramePool() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ auto pool_context = context_provider_->CreateContext(
+ base::BindOnce(&GpuMemoryBufferVideoFramePool::RecreateVideoFramePool,
+ weak_factory_.GetWeakPtr()));
+ video_frame_pool_ = media::RenderableGpuMemoryBufferVideoFramePool::Create(
+ std::move(pool_context));
+
+ video_frame_pool_generation_++;
+ num_reserved_frames_ = 0;
+}
+
+void GpuMemoryBufferVideoFramePool::OnVideoFrameDestroyed(
+ uint32_t frame_pool_generation) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ if (frame_pool_generation == video_frame_pool_generation_) {
+ DCHECK_GT(num_reserved_frames_, 0u);
+
+ num_reserved_frames_--;
+ }
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/service/frame_sinks/video_capture/gpu_memory_buffer_video_frame_pool.h b/chromium/components/viz/service/frame_sinks/video_capture/gpu_memory_buffer_video_frame_pool.h
new file mode 100644
index 00000000000..97019e0be66
--- /dev/null
+++ b/chromium/components/viz/service/frame_sinks/video_capture/gpu_memory_buffer_video_frame_pool.h
@@ -0,0 +1,75 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_VIZ_SERVICE_FRAME_SINKS_VIDEO_CAPTURE_GPU_MEMORY_BUFFER_VIDEO_FRAME_POOL_H_
+#define COMPONENTS_VIZ_SERVICE_FRAME_SINKS_VIDEO_CAPTURE_GPU_MEMORY_BUFFER_VIDEO_FRAME_POOL_H_
+
+#include <memory>
+
+#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
+#include "components/viz/service/frame_sinks/video_capture/video_frame_pool.h"
+#include "components/viz/service/viz_service_export.h"
+#include "media/video/renderable_gpu_memory_buffer_video_frame_pool.h"
+
+namespace viz {
+
+class GmbVideoFramePoolContextProvider;
+
+class VIZ_SERVICE_EXPORT GpuMemoryBufferVideoFramePool : public VideoFramePool {
+ public:
+ // Creates new pool instance with specified |capacity|.
+ // The |context_provider| must outlive this instance.
+ explicit GpuMemoryBufferVideoFramePool(
+ int capacity,
+ GmbVideoFramePoolContextProvider* context_provider);
+ ~GpuMemoryBufferVideoFramePool() override;
+
+ GpuMemoryBufferVideoFramePool(const GpuMemoryBufferVideoFramePool&& other) =
+ delete;
+ GpuMemoryBufferVideoFramePool& operator=(
+ const GpuMemoryBufferVideoFramePool& other) = delete;
+
+ // VideoFramePool implementation:
+ scoped_refptr<media::VideoFrame> ReserveVideoFrame(
+ media::VideoPixelFormat format,
+ const gfx::Size& size) override;
+
+ media::mojom::VideoBufferHandlePtr CloneHandleForDelivery(
+ const media::VideoFrame& frame) override;
+
+ size_t GetNumberOfReservedFrames() const override;
+
+ private:
+ void RecreateVideoFramePool();
+
+ // Notify the pool that a video frame from |frame_pool_generation| was
+ // destroyed. If the generation matches the current pool generation, the
+ // number of reserved frames will be decremented.
+ void OnVideoFrameDestroyed(uint32_t frame_pool_generation);
+
+ raw_ptr<GmbVideoFramePoolContextProvider> context_provider_
+ GUARDED_BY_CONTEXT(sequence_checker_);
+
+ std::unique_ptr<media::RenderableGpuMemoryBufferVideoFramePool>
+ video_frame_pool_ GUARDED_BY_CONTEXT(sequence_checker_);
+
+ // Number of reserved video frames.
+ size_t num_reserved_frames_ GUARDED_BY_CONTEXT(sequence_checker_) = 0;
+
+ // Current generation of |video_frame_pool_|. It will be bumped every time
+ // we detect a context lost event and recerate |video_frame_pool_| - this is
+ // needed so that we can correctly book-keep the number of reserved frames
+ // (when a video frame from previous generation is released, we don't want
+ // to decrement |num_reserved_frames_|).
+ uint32_t video_frame_pool_generation_ GUARDED_BY_CONTEXT(sequence_checker_) =
+ 0;
+
+ SEQUENCE_CHECKER(sequence_checker_);
+
+ base::WeakPtrFactory<GpuMemoryBufferVideoFramePool> weak_factory_{this};
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_SERVICE_FRAME_SINKS_VIDEO_CAPTURE_GPU_MEMORY_BUFFER_VIDEO_FRAME_POOL_H_
diff --git a/chromium/components/viz/service/frame_sinks/video_capture/video_capture_overlay.cc b/chromium/components/viz/service/frame_sinks/video_capture/video_capture_overlay.cc
index 449987c762e..6794c7cdb97 100644
--- a/chromium/components/viz/service/frame_sinks/video_capture/video_capture_overlay.cc
+++ b/chromium/components/viz/service/frame_sinks/video_capture/video_capture_overlay.cc
@@ -114,17 +114,47 @@ gfx::Rect MinimallyShrinkRectForI420(const gfx::Rect& rect) {
std::max(0, bottom - top));
}
+// Uses the mapping of a region R that exists in coordinate system A
+// as |from_region| and in coordinate system B as |to_region|. The |source|
+// rectangle is in coordinate system A and mapped to coordinate system B
+// in three steps:
+// 1. translate to remove the origin of the old coordinate space.
+// 2. scale values to the new space.
+// 3. translate to add the origin of the new coordinate space.
+gfx::Rect Transform(const gfx::Rect& source,
+ const gfx::Rect& from_region,
+ const gfx::Rect& to_region) {
+ // Transforming from or to a zero space is undefined behavior.
+ if (from_region.IsEmpty() || to_region.IsEmpty())
+ return {};
+
+ const gfx::Vector2dF scale{static_cast<float>(to_region.width()) /
+ static_cast<float>(from_region.width()),
+ static_cast<float>(to_region.height()) /
+ static_cast<float>(from_region.height())};
+
+ const gfx::Rect old_translated =
+ gfx::Rect(source.x() - from_region.x(), source.y() - from_region.y(),
+ source.width(), source.height());
+ const gfx::Rect scaled =
+ gfx::ScaleToEnclosingRect(old_translated, scale.x(), scale.y());
+ const gfx::Rect new_translated =
+ gfx::Rect(scaled.x() + to_region.x(), scaled.y() + to_region.y(),
+ scaled.width(), scaled.height());
+
+ return MinimallyShrinkRectForI420(new_translated);
+}
+
} // namespace
VideoCaptureOverlay::OnceRenderer VideoCaptureOverlay::MakeRenderer(
const CapturedFrameProperties& properties) {
- // If there's no image set yet, punt.
- if (image_.drawsNothing()) {
- return VideoCaptureOverlay::OnceRenderer();
- }
-
// The sub region should always be a subset of the frame region.
- DCHECK(properties.frame_region.Contains(properties.sub_region));
+ DCHECK(properties.compositor_region.Contains(properties.sub_region));
+
+ // If there's no image set yet, punt.
+ if (image_.drawsNothing())
+ return {};
// Determine the bounds of the sprite to be blitted onto the video frame. The
// calculations here align to the 2x2 pixel-quads, since dealing with
@@ -132,52 +162,41 @@ VideoCaptureOverlay::OnceRenderer VideoCaptureOverlay::MakeRenderer(
// complexify the blitting algorithm later on. This introduces a little
// inaccuracy in the size and position of the overlay in the final result, but
// should be an acceptable trade-off for all use cases.
-
+ //
// Rescale the relative bounds (scoped between [0, 1]) to absolute bounds
// based on the entire region of the frame sink being captured. This allows
// for calculations such as mouse cursor position (which is retrieved in
- // relationship to the entire tab or window) to be scaled properly, then
- // have its location manipulated below as |bounds_in_frame|.
+ // relationship to the entire tab or window) to be scaled properly.
const gfx::Rect absolute_bounds =
- ToAbsoluteBoundsForI420(bounds_, properties.frame_region);
+ ToAbsoluteBoundsForI420(bounds_, properties.compositor_region);
+ if (!absolute_bounds.Intersects(properties.sub_region))
+ return {};
- // Translate the location of the cursor from the entire surface to just
- // the |sub_region| we are capturing. This will be a noop if we are
- // capturing the entire |frame_region|.
- gfx::Rect bounds_in_frame = absolute_bounds;
- bounds_in_frame.Offset(properties.frame_region.origin() -
- properties.sub_region.origin());
-
- // After offset, the bounds may not be properly set for I420.
- bounds_in_frame = MinimallyShrinkRectForI420(bounds_in_frame);
+ // The bounds are currently in the coordinate space of the captured compositor
+ // frame, however blitting is actually done in the coordinate space of the
+ // outputted video frame and must be scaled and translated.
+ const gfx::Rect bounds_in_target = Transform(
+ absolute_bounds, properties.sub_region, properties.content_region);
// If the sprite's size will be unreasonably large, punt.
- if (bounds_in_frame.width() > media::limits::kMaxDimension ||
- bounds_in_frame.height() > media::limits::kMaxDimension) {
- return VideoCaptureOverlay::OnceRenderer();
- }
-
- // Compute the region of the frame to be modified by future Sprite::Blit()
- // calls.
- gfx::Rect blit_rect = MinimallyShrinkRectForI420(gfx::Rect(
- properties.frame_region.origin(), properties.sub_region.size()));
- blit_rect.Intersect(bounds_in_frame);
-
- // If the two rects didn't intersect at all (i.e., everything has been
- // clipped), punt.
- if (blit_rect.IsEmpty()) {
- return VideoCaptureOverlay::OnceRenderer();
- }
+ if (bounds_in_target.width() > media::limits::kMaxDimension ||
+ bounds_in_target.height() > media::limits::kMaxDimension)
+ return {};
- // If the cached sprite does not match the computed scaled size and/or pixel
- // format, create a new instance for this (and future) renderers.
- if (!sprite_ || sprite_->size() != absolute_bounds.size() ||
+ // If the cached sprite does not match the computed scaled size and/or
+ // pixel format, create a new instance for this (and future) renderers.
+ if (!sprite_ || sprite_->size() != bounds_in_target.size() ||
sprite_->format() != properties.format) {
- sprite_ = base::MakeRefCounted<Sprite>(image_, absolute_bounds.size(),
+ sprite_ = base::MakeRefCounted<Sprite>(image_, bounds_in_target.size(),
properties.format);
}
- return base::BindOnce(&Sprite::Blit, sprite_, bounds_in_frame.origin(),
+ gfx::Rect blit_rect = bounds_in_target;
+ blit_rect.Intersect(properties.content_region);
+ if (blit_rect.IsEmpty())
+ return {};
+
+ return base::BindOnce(&Sprite::Blit, sprite_, bounds_in_target.origin(),
blit_rect);
}
@@ -185,9 +204,8 @@ VideoCaptureOverlay::OnceRenderer VideoCaptureOverlay::MakeRenderer(
VideoCaptureOverlay::OnceRenderer VideoCaptureOverlay::MakeCombinedRenderer(
const std::vector<VideoCaptureOverlay*>& overlays,
const CapturedFrameProperties& properties) {
- if (overlays.empty()) {
- return VideoCaptureOverlay::OnceRenderer();
- }
+ if (overlays.empty())
+ return {};
std::vector<OnceRenderer> renderers;
for (VideoCaptureOverlay* overlay : overlays) {
@@ -197,9 +215,8 @@ VideoCaptureOverlay::OnceRenderer VideoCaptureOverlay::MakeCombinedRenderer(
}
}
- if (renderers.empty()) {
- return VideoCaptureOverlay::OnceRenderer();
- }
+ if (renderers.empty())
+ return {};
return base::BindOnce(
[](std::vector<OnceRenderer> renderers, VideoFrame* frame) {
@@ -218,7 +235,7 @@ gfx::Rect VideoCaptureOverlay::ComputeSourceMutationRect() const {
result.Intersect(gfx::Rect(source_size));
return result;
}
- return gfx::Rect();
+ return {};
}
VideoCaptureOverlay::Sprite::Sprite(const SkBitmap& image,
diff --git a/chromium/components/viz/service/frame_sinks/video_capture/video_capture_overlay.h b/chromium/components/viz/service/frame_sinks/video_capture/video_capture_overlay.h
index e38257eca93..f558a733318 100644
--- a/chromium/components/viz/service/frame_sinks/video_capture/video_capture_overlay.h
+++ b/chromium/components/viz/service/frame_sinks/video_capture/video_capture_overlay.h
@@ -93,16 +93,20 @@ class VIZ_SERVICE_EXPORT VideoCaptureOverlay final
void SetBounds(const gfx::RectF& bounds) final;
struct CapturedFrameProperties {
- // The entire size of the frame on the surface. This should be the
- // maximum possible capturable surface size.
- gfx::Rect frame_region;
-
- // The sub region of the frame selected for capture. Should be in the
- // same coordinate system as |frame_region| as a subset of pixels. If
- // sub_region == frame_region, then the entire frame surface is being
- // captured.
+ // The entire size of the compositor frame on the surface. This should be
+ // the maximum possible capturable surface size.
+ gfx::Rect compositor_region;
+
+ // The sub region of the compositor frame selected for capture. Should be in
+ // the same coordinate system as |compositor_region| as a subset of pixels.
+ // If sub_region == compositor_region, then the entire frame surface is
+ // being captured.
gfx::Rect sub_region;
+ // Ultimately the overlay gets outputted onto a video frame with a region
+ // of |content_region|.
+ gfx::Rect content_region;
+
// The frame's pixel format.
media::VideoPixelFormat format;
};
diff --git a/chromium/components/viz/service/frame_sinks/video_capture/video_capture_overlay_unittest.cc b/chromium/components/viz/service/frame_sinks/video_capture/video_capture_overlay_unittest.cc
index 4fb1141af66..b2b46d8ff1c 100644
--- a/chromium/components/viz/service/frame_sinks/video_capture/video_capture_overlay_unittest.cc
+++ b/chromium/components/viz/service/frame_sinks/video_capture/video_capture_overlay_unittest.cc
@@ -161,16 +161,18 @@ TEST_F(VideoCaptureOverlayTest, DoesNotRenderWithoutImage) {
constexpr gfx::Rect kRegionInFrame = gfx::Rect(kSize);
EXPECT_FALSE(
overlay->MakeRenderer(VideoCaptureOverlay::CapturedFrameProperties{
- .frame_region = kRegionInFrame,
+ .compositor_region = kRegionInFrame,
.sub_region = kRegionInFrame,
+ .content_region = kRegionInFrame,
.format = kI420Format}));
// Once an image is set, the renderer should not be null.
overlay->SetImageAndBounds(MakeTestBitmap(1), gfx::RectF(0, 0, 1, 1));
EXPECT_TRUE(
overlay->MakeRenderer(VideoCaptureOverlay::CapturedFrameProperties{
- .frame_region = kRegionInFrame,
+ .compositor_region = kRegionInFrame,
.sub_region = kRegionInFrame,
+ .content_region = kRegionInFrame,
.format = kI420Format}));
}
@@ -185,8 +187,9 @@ TEST_F(VideoCaptureOverlayTest, DoesNotRenderIfCompletelyOutOfBounds) {
constexpr gfx::Rect kRegionInFrame = gfx::Rect(kSize);
EXPECT_FALSE(
overlay->MakeRenderer(VideoCaptureOverlay::CapturedFrameProperties{
- .frame_region = kRegionInFrame,
+ .compositor_region = kRegionInFrame,
.sub_region = kRegionInFrame,
+ .content_region = kRegionInFrame,
.format = kI420Format}));
// Setting an image, but out-of-bounds, should always result in a null
@@ -194,26 +197,45 @@ TEST_F(VideoCaptureOverlayTest, DoesNotRenderIfCompletelyOutOfBounds) {
overlay->SetImageAndBounds(MakeTestBitmap(0), gfx::RectF(-1, -1, 1, 1));
EXPECT_FALSE(
overlay->MakeRenderer(VideoCaptureOverlay::CapturedFrameProperties{
- .frame_region = kRegionInFrame,
+ .compositor_region = kRegionInFrame,
.sub_region = kRegionInFrame,
+ .content_region = kRegionInFrame,
.format = kI420Format}));
overlay->SetBounds(gfx::RectF(1, 1, 1, 1));
EXPECT_FALSE(
overlay->MakeRenderer(VideoCaptureOverlay::CapturedFrameProperties{
- .frame_region = kRegionInFrame,
+ .compositor_region = kRegionInFrame,
.sub_region = kRegionInFrame,
+ .content_region = kRegionInFrame,
.format = kI420Format}));
overlay->SetBounds(gfx::RectF(-1, 1, 1, 1));
EXPECT_FALSE(
overlay->MakeRenderer(VideoCaptureOverlay::CapturedFrameProperties{
- .frame_region = kRegionInFrame,
+ .compositor_region = kRegionInFrame,
.sub_region = kRegionInFrame,
+ .content_region = kRegionInFrame,
.format = kI420Format}));
overlay->SetBounds(gfx::RectF(1, -1, 1, 1));
EXPECT_FALSE(
overlay->MakeRenderer(VideoCaptureOverlay::CapturedFrameProperties{
- .frame_region = kRegionInFrame,
+ .compositor_region = kRegionInFrame,
.sub_region = kRegionInFrame,
+ .content_region = kRegionInFrame,
+ .format = kI420Format}));
+}
+
+TEST_F(VideoCaptureOverlayTest, DoesNotRenderIfEmptyBlitRect) {
+ constexpr gfx::Size kSize = gfx::Size(100, 200);
+ constexpr gfx::Rect kFrameRect = gfx::Rect(kSize);
+ EXPECT_CALL(*frame_source(), GetSourceSize()).WillRepeatedly(Return(kSize));
+ std::unique_ptr<VideoCaptureOverlay> overlay = CreateOverlay();
+
+ overlay->SetImageAndBounds(MakeTestBitmap(0), gfx::RectF(1, 1, 1, 1));
+ EXPECT_FALSE(
+ overlay->MakeRenderer(VideoCaptureOverlay::CapturedFrameProperties{
+ .compositor_region = kFrameRect,
+ .sub_region = kFrameRect,
+ .content_region = gfx::Rect(0, 0, 50, 100),
.format = kI420Format}));
}
@@ -232,8 +254,9 @@ TEST_F(VideoCaptureOverlayTest,
constexpr gfx::Rect kRegionInFrame = gfx::Rect(kSize);
EXPECT_FALSE(VideoCaptureOverlay::MakeCombinedRenderer(
overlays, VideoCaptureOverlay::CapturedFrameProperties{
- .frame_region = kRegionInFrame,
+ .compositor_region = kRegionInFrame,
.sub_region = kRegionInFrame,
+ .content_region = kRegionInFrame,
.format = kI420Format}));
// If just the first overlay renders, the combined renderer should not be
@@ -241,16 +264,18 @@ TEST_F(VideoCaptureOverlayTest,
overlays[0]->SetImageAndBounds(MakeTestBitmap(0), gfx::RectF(0, 0, 1, 1));
EXPECT_TRUE(VideoCaptureOverlay::MakeCombinedRenderer(
overlays, VideoCaptureOverlay::CapturedFrameProperties{
- .frame_region = kRegionInFrame,
+ .compositor_region = kRegionInFrame,
.sub_region = kRegionInFrame,
+ .content_region = kRegionInFrame,
.format = kI420Format}));
// If both overlays render, the combined renderer should not be null.
overlays[1]->SetImageAndBounds(MakeTestBitmap(1), gfx::RectF(0, 0, 1, 1));
EXPECT_TRUE(VideoCaptureOverlay::MakeCombinedRenderer(
overlays, VideoCaptureOverlay::CapturedFrameProperties{
- .frame_region = kRegionInFrame,
+ .compositor_region = kRegionInFrame,
.sub_region = kRegionInFrame,
+ .content_region = kRegionInFrame,
.format = kI420Format}));
// If only the second overlay renders, because the first is hidden, the
@@ -258,16 +283,18 @@ TEST_F(VideoCaptureOverlayTest,
overlays[0]->SetBounds(gfx::RectF());
EXPECT_TRUE(VideoCaptureOverlay::MakeCombinedRenderer(
overlays, VideoCaptureOverlay::CapturedFrameProperties{
- .frame_region = kRegionInFrame,
+ .compositor_region = kRegionInFrame,
.sub_region = kRegionInFrame,
+ .content_region = kRegionInFrame,
.format = kI420Format}));
// Both overlays are hidden, so the combined renderer should be null.
overlays[1]->SetBounds(gfx::RectF());
EXPECT_FALSE(VideoCaptureOverlay::MakeCombinedRenderer(
overlays, VideoCaptureOverlay::CapturedFrameProperties{
- .frame_region = kRegionInFrame,
+ .compositor_region = kRegionInFrame,
.sub_region = kRegionInFrame,
+ .content_region = kRegionInFrame,
.format = kI420Format}));
}
@@ -440,6 +467,18 @@ class VideoCaptureOverlayRenderTest
return matches_golden_file;
}
+ void ExpectRendersAs(VideoCaptureOverlay::OnceRenderer* renderers,
+ const char* const* expected_files,
+ const std::size_t count,
+ const gfx::Size& frame_size) {
+ for (std::size_t i = 0; i < count; ++i) {
+ auto frame = CreateVideoFrame(frame_size);
+ DCHECK(renderers[i]);
+ std::move(renderers[i]).Run(frame.get());
+ EXPECT_TRUE(FrameMatchesPNG(*frame, expected_files[i]));
+ }
+ }
+
// The size of the compositor frame sink's Surface.
static constexpr gfx::Size kSourceSize = gfx::Size(96, 40);
@@ -470,8 +509,9 @@ TEST_P(VideoCaptureOverlayRenderTest, FullCover_NoScaling) {
const gfx::Size output_size(test_bitmap.width(), test_bitmap.height());
VideoCaptureOverlay::OnceRenderer renderer =
overlay.MakeRenderer(VideoCaptureOverlay::CapturedFrameProperties{
- .frame_region = gfx::Rect(output_size),
+ .compositor_region = gfx::Rect(output_size),
.sub_region = gfx::Rect(output_size),
+ .content_region = gfx::Rect(output_size),
.format = pixel_format()});
ASSERT_TRUE(renderer);
auto frame = CreateVideoFrame(output_size);
@@ -500,8 +540,9 @@ TEST_P(VideoCaptureOverlayRenderTest, FullCover_WithScaling) {
test_bitmap.height() * 4);
VideoCaptureOverlay::OnceRenderer renderer =
overlay.MakeRenderer(VideoCaptureOverlay::CapturedFrameProperties{
- .frame_region = gfx::Rect(output_size),
+ .compositor_region = gfx::Rect(output_size),
.sub_region = gfx::Rect(output_size),
+ .content_region = gfx::Rect(output_size),
.format = pixel_format()});
ASSERT_TRUE(renderer);
auto frame = CreateVideoFrame(output_size);
@@ -542,8 +583,9 @@ TEST_P(VideoCaptureOverlayRenderTest, MovesAround) {
}
renderers[i] =
overlay.MakeRenderer(VideoCaptureOverlay::CapturedFrameProperties{
- .frame_region = gfx::Rect(frame_size),
+ .compositor_region = gfx::Rect(frame_size),
.sub_region = gfx::Rect(frame_size),
+ .content_region = gfx::Rect(frame_size),
.format = pixel_format()});
}
@@ -552,15 +594,8 @@ TEST_P(VideoCaptureOverlayRenderTest, MovesAround) {
"overlay_moves_2_1.png", "overlay_moves_2_2.png", "overlay_moves_lr.png",
};
- for (int i = 0; i < 6; ++i) {
- SCOPED_TRACE(testing::Message() << "relative_image_bounds="
- << relative_image_bounds[i].ToString()
- << ", frame_size=" << frame_size.ToString()
- << ", golden_file=" << kGoldenFiles[i]);
- auto frame = CreateVideoFrame(frame_size);
- std::move(renderers[i]).Run(frame.get());
- EXPECT_TRUE(FrameMatchesPNG(*frame, kGoldenFiles[i]));
- }
+ ExpectRendersAs(renderers, kGoldenFiles.data(), kGoldenFiles.size(),
+ frame_size);
}
// Tests that the overlay will be partially rendered (clipped) when any part of
@@ -611,8 +646,9 @@ TEST_P(VideoCaptureOverlayRenderTest, ClipsToContentBounds) {
}
renderers[i] =
overlay.MakeRenderer(VideoCaptureOverlay::CapturedFrameProperties{
- .frame_region = region_in_frame,
+ .compositor_region = region_in_frame,
.sub_region = region_in_frame,
+ .content_region = region_in_frame,
.format = pixel_format()});
}
@@ -623,11 +659,8 @@ TEST_P(VideoCaptureOverlayRenderTest, ClipsToContentBounds) {
"overlay_clips_ll.png",
};
- for (int i = 0; i < 4; ++i) {
- auto frame = CreateVideoFrame(frame_size);
- std::move(renderers[i]).Run(frame.get());
- EXPECT_TRUE(FrameMatchesPNG(*frame, kGoldenFiles[i]));
- }
+ ExpectRendersAs(renderers, kGoldenFiles.data(), kGoldenFiles.size(),
+ frame_size);
}
TEST_P(VideoCaptureOverlayRenderTest, HandlesEmptySubRegion) {
@@ -640,15 +673,16 @@ TEST_P(VideoCaptureOverlayRenderTest, HandlesEmptySubRegion) {
const SkBitmap test_bitmap = MakeTestBitmap(0);
const gfx::Size frame_size(test_bitmap.width() * 4, test_bitmap.height() * 4);
- const gfx::Rect frame_region(frame_size);
+ const gfx::Rect compositor_region(frame_size);
const gfx::Rect sub_region_in_frame;
const gfx::RectF relative_image_bounds(0.125f, .125f, 0.25f, 0.25f);
overlay.SetImageAndBounds(test_bitmap, relative_image_bounds);
auto renderer =
overlay.MakeRenderer(VideoCaptureOverlay::CapturedFrameProperties{
- .frame_region = frame_region,
+ .compositor_region = compositor_region,
.sub_region = sub_region_in_frame,
+ .content_region = compositor_region,
.format = pixel_format()});
// We shouldn't even create a renderer if we aren't capturing any pixels.
@@ -665,7 +699,7 @@ TEST_P(VideoCaptureOverlayRenderTest, ClipsToSubregionBounds) {
const SkBitmap test_bitmap = MakeTestBitmap(0);
const gfx::Size frame_size(test_bitmap.width() * 4, test_bitmap.height() * 4);
- const gfx::Rect frame_region(frame_size);
+ const gfx::Rect compositor_region(frame_size);
const gfx::Rect sub_region_in_frame(test_bitmap.width(), test_bitmap.height(),
test_bitmap.width() * 2,
test_bitmap.height() * 2);
@@ -685,8 +719,9 @@ TEST_P(VideoCaptureOverlayRenderTest, ClipsToSubregionBounds) {
}
renderers[i] =
overlay.MakeRenderer(VideoCaptureOverlay::CapturedFrameProperties{
- .frame_region = frame_region,
+ .compositor_region = compositor_region,
.sub_region = sub_region_in_frame,
+ .content_region = gfx::Rect(sub_region_in_frame.size()),
.format = pixel_format()});
}
@@ -697,11 +732,59 @@ TEST_P(VideoCaptureOverlayRenderTest, ClipsToSubregionBounds) {
"overlay_clips_ll_subregion.png",
};
+ ExpectRendersAs(renderers, kGoldenFiles.data(), kGoldenFiles.size(),
+ sub_region_in_frame.size());
+}
+
+TEST_P(VideoCaptureOverlayRenderTest, ScalesToContentRegion) {
+ NiceMock<MockFrameSource> frame_source;
+ EXPECT_CALL(frame_source, GetSourceSize())
+ .WillRepeatedly(Return(kSourceSize));
+ mojo::Remote<mojom::FrameSinkVideoCaptureOverlay> overlay_remote;
+ VideoCaptureOverlay overlay(&frame_source,
+ overlay_remote.BindNewPipeAndPassReceiver());
+
+ const SkBitmap test_bitmap = MakeTestBitmap(0);
+ const gfx::Size frame_size(test_bitmap.width() * 4, test_bitmap.height() * 4);
+ const gfx::Rect compositor_region(frame_size);
+ const gfx::Rect sub_region_in_frame(test_bitmap.width(), test_bitmap.height(),
+ test_bitmap.width() * 2,
+ test_bitmap.height() * 2);
+ const gfx::Rect content_region(
+ test_bitmap.width() * 2, test_bitmap.height() * 2,
+ test_bitmap.width() * 6, test_bitmap.height() * 6);
+
+ const gfx::RectF relative_image_bounds[4] = {
+ gfx::RectF(0.125f, .125f, 0.25f, 0.25f),
+ gfx::RectF(0.625f, .125f, 0.25f, 0.25f),
+ gfx::RectF(0.625f, 0.625f, 0.25f, 0.25f),
+ gfx::RectF(.125f, 0.625f, 0.25f, 0.25f),
+ };
+
+ VideoCaptureOverlay::OnceRenderer renderers[4];
for (int i = 0; i < 4; ++i) {
- auto frame = CreateVideoFrame(sub_region_in_frame.size());
- std::move(renderers[i]).Run(frame.get());
- EXPECT_TRUE(FrameMatchesPNG(*frame, kGoldenFiles[i]));
+ if (i == 0) {
+ overlay.SetImageAndBounds(test_bitmap, relative_image_bounds[i]);
+ } else {
+ overlay.SetBounds(relative_image_bounds[i]);
+ }
+ renderers[i] =
+ overlay.MakeRenderer(VideoCaptureOverlay::CapturedFrameProperties{
+ .compositor_region = compositor_region,
+ .sub_region = sub_region_in_frame,
+ .content_region = content_region,
+ .format = pixel_format()});
}
+
+ constexpr std::array<const char*, 4> kGoldenFiles = {
+ "overlay_clips_ul_contentscaled.png",
+ "overlay_clips_ur_contentscaled.png",
+ "overlay_clips_lr_contentscaled.png",
+ "overlay_clips_ll_contentscaled.png",
+ };
+
+ ExpectRendersAs(renderers, kGoldenFiles.data(), kGoldenFiles.size(),
+ gfx::Size(content_region.right(), content_region.bottom()));
}
INSTANTIATE_TEST_SUITE_P(
diff --git a/chromium/components/viz/service/frame_sinks/video_capture/video_frame_pool.cc b/chromium/components/viz/service/frame_sinks/video_capture/video_frame_pool.cc
index 5b63bcb661c..df89363e0a0 100644
--- a/chromium/components/viz/service/frame_sinks/video_capture/video_frame_pool.cc
+++ b/chromium/components/viz/service/frame_sinks/video_capture/video_frame_pool.cc
@@ -2,12 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "components/viz/service/frame_sinks/video_capture/video_frame_pool.h"
+
#include <algorithm>
#include <memory>
-#include "components/viz/service/frame_sinks/video_capture/shared_memory_video_frame_pool.h"
-#include "components/viz/service/frame_sinks/video_capture/video_frame_pool.h"
-
namespace viz {
VideoFramePool::VideoFramePool(int capacity)
diff --git a/chromium/components/viz/service/frame_sinks/video_detector.cc b/chromium/components/viz/service/frame_sinks/video_detector.cc
index a5f132f49b9..185ee06e907 100644
--- a/chromium/components/viz/service/frame_sinks/video_detector.cc
+++ b/chromium/components/viz/service/frame_sinks/video_detector.cc
@@ -9,6 +9,7 @@
#include <vector>
#include "base/time/time.h"
+#include "components/viz/common/features.h"
#include "components/viz/common/quads/compositor_frame.h"
#include "components/viz/service/surfaces/surface.h"
#include "components/viz/service/surfaces/surface_manager.h"
@@ -25,7 +26,9 @@ constexpr base::TimeDelta VideoDetector::kMinVideoDuration;
// likely that a video is playing in it.
class VideoDetector::ClientInfo {
public:
- ClientInfo() = default;
+ ClientInfo()
+ : should_ignore_non_video_frames_(
+ features::ShouldVideoDetectorIgnoreNonVideoFrames()) {}
ClientInfo(const ClientInfo&) = delete;
ClientInfo& operator=(const ClientInfo&) = delete;
@@ -44,6 +47,10 @@ class VideoDetector::ClientInfo {
const CompositorFrame& frame = surface->GetActiveFrame();
+ if (should_ignore_non_video_frames_ && !frame.metadata.may_contain_video) {
+ return false;
+ }
+
gfx::Rect damage =
gfx::ScaleToEnclosingRect(frame.render_pass_list.back()->damage_rect,
1.f / frame.device_scale_factor());
@@ -74,6 +81,10 @@ class VideoDetector::ClientInfo {
}
private:
+ // If true, we'll only process frames that may contain videos, as determined
+ // by the frame's may_contain_video metadata.
+ bool should_ignore_non_video_frames_;
+
// Circular buffer containing update times of the last (up to
// |kMinFramesPerSecond|) video-sized updates to this client.
base::TimeTicks update_times_[kMinFramesPerSecond];
diff --git a/chromium/components/viz/service/frame_sinks/video_detector_unittest.cc b/chromium/components/viz/service/frame_sinks/video_detector_unittest.cc
index d2de5149531..88433faa5b8 100644
--- a/chromium/components/viz/service/frame_sinks/video_detector_unittest.cc
+++ b/chromium/components/viz/service/frame_sinks/video_detector_unittest.cc
@@ -9,10 +9,13 @@
#include "base/compiler_specific.h"
#include "base/containers/circular_deque.h"
+#include "base/feature_list.h"
#include "base/memory/raw_ptr.h"
+#include "base/test/scoped_feature_list.h"
#include "base/test/test_mock_time_task_runner.h"
#include "base/time/tick_clock.h"
#include "base/time/time.h"
+#include "components/viz/common/features.h"
#include "components/viz/common/quads/surface_draw_quad.h"
#include "components/viz/common/surfaces/parent_local_surface_id_allocator.h"
#include "components/viz/service/display/display_resource_provider_software.h"
@@ -156,7 +159,8 @@ class VideoDetectorTest : public testing::Test {
}
void SendUpdate(CompositorFrameSinkSupport* frame_sink,
- const gfx::Rect& damage) {
+ const gfx::Rect& damage,
+ bool may_contain_video) {
LocalSurfaceId local_surface_id =
frame_sink->last_activated_local_surface_id();
if (!local_surface_id.is_valid()) {
@@ -165,8 +169,9 @@ class VideoDetectorTest : public testing::Test {
allocator->GenerateId();
local_surface_id = allocator->GetCurrentLocalSurfaceId();
}
- frame_sink->SubmitCompositorFrame(local_surface_id,
- MakeDamagedCompositorFrame(damage));
+ frame_sink->SubmitCompositorFrame(
+ local_surface_id,
+ MakeDamagedCompositorFrame(damage, may_contain_video));
}
// Report updates to |client| of area |damage| at a rate of
@@ -174,12 +179,13 @@ class VideoDetectorTest : public testing::Test {
// immediately and time will have advanced by |duration| upon returning.
void SendUpdates(CompositorFrameSinkSupport* frame_sink,
const gfx::Rect& damage,
+ bool may_contain_video,
int updates_per_second,
base::TimeDelta duration) {
const base::TimeDelta time_between_updates =
base::Seconds(1.0 / updates_per_second);
for (base::TimeDelta d; d < duration; d += time_between_updates) {
- SendUpdate(frame_sink, damage);
+ SendUpdate(frame_sink, damage, may_contain_video);
CreateDisplayFrame();
AdvanceTime(std::min(time_between_updates, duration - d));
}
@@ -193,7 +199,7 @@ class VideoDetectorTest : public testing::Test {
true /* report_activation */);
auto frame_sink = std::make_unique<CompositorFrameSinkSupport>(
&frame_sink_client_, &frame_sink_manager_, frame_sink_id, is_root);
- SendUpdate(frame_sink.get(), gfx::Rect());
+ SendUpdate(frame_sink.get(), gfx::Rect(), /*may_contain_video*/ false);
return frame_sink;
}
@@ -202,14 +208,18 @@ class VideoDetectorTest : public testing::Test {
scoped_refptr<base::TestMockTimeTaskRunner> mock_task_runner_;
- private:
- CompositorFrame MakeDamagedCompositorFrame(const gfx::Rect& damage) {
+ protected:
+ CompositorFrame MakeDamagedCompositorFrame(const gfx::Rect& damage,
+ bool may_contain_video) {
constexpr gfx::Rect kFrameSinkRect(10000, 10000);
- return CompositorFrameBuilder()
- .AddRenderPass(kFrameSinkRect, damage)
- .Build();
+ auto frame =
+ CompositorFrameBuilder().AddRenderPass(kFrameSinkRect, damage).Build();
+ frame.metadata.may_contain_video = may_contain_video;
+
+ return frame;
}
+ base::test::ScopedFeatureList scoped_feature_list_;
ServerSharedBitmapManager shared_bitmap_manager_;
FrameSinkManagerImpl frame_sink_manager_{
FrameSinkManagerImpl::InitParams(&shared_bitmap_manager_)};
@@ -221,6 +231,14 @@ class VideoDetectorTest : public testing::Test {
std::set<CompositorFrameSinkSupport*> embedded_clients_;
};
+class VideoDetectorIncludeNonVideoTest : public VideoDetectorTest {
+ public:
+ VideoDetectorIncludeNonVideoTest() {
+ scoped_feature_list_.InitAndDisableFeature(
+ features::kVideoDetectorIgnoreNonVideos);
+ }
+};
+
constexpr gfx::Rect VideoDetectorTest::kMinRect;
constexpr base::TimeDelta VideoDetectorTest::kMinDuration;
constexpr base::TimeDelta VideoDetectorTest::kTimeout;
@@ -235,7 +253,8 @@ TEST_F(VideoDetectorTest, DontReportWhenDamageTooSmall) {
// activity isn't detected.
gfx::Rect rect = kMinRect;
rect.Inset(0, 0, 1, 0);
- SendUpdates(frame_sink.get(), rect, 2 * kMinFps, 2 * kMinDuration);
+ SendUpdates(frame_sink.get(), rect, /*may_contain_video=*/true, 2 * kMinFps,
+ 2 * kMinDuration);
EXPECT_TRUE(observer_.IsEmpty());
}
@@ -244,7 +263,8 @@ TEST_F(VideoDetectorTest, DontReportWhenDamageTooSmall) {
// activity isn't detected.
gfx::Rect rect = kMinRect;
rect.Inset(0, 0, 1, 0);
- SendUpdates(frame_sink.get(), rect, 2 * kMinFps, 2 * kMinDuration);
+ SendUpdates(frame_sink.get(), rect, /*may_contain_video=*/true, 2 * kMinFps,
+ 2 * kMinDuration);
EXPECT_TRUE(observer_.IsEmpty());
}
}
@@ -253,7 +273,8 @@ TEST_F(VideoDetectorTest, DontReportWhenDamageTooSmall) {
TEST_F(VideoDetectorTest, DontReportWhenFramerateTooLow) {
std::unique_ptr<CompositorFrameSinkSupport> frame_sink = CreateFrameSink();
EmbedClient(frame_sink.get());
- SendUpdates(frame_sink.get(), kMinRect, kMinFps - 5, 2 * kMinDuration);
+ SendUpdates(frame_sink.get(), kMinRect, /*may_contain_video=*/true,
+ kMinFps - 5, 2 * kMinDuration);
EXPECT_TRUE(observer_.IsEmpty());
}
@@ -262,10 +283,12 @@ TEST_F(VideoDetectorTest, DontReportWhenFramerateTooLow) {
TEST_F(VideoDetectorTest, DontReportWhenNotPlayingLongEnough) {
std::unique_ptr<CompositorFrameSinkSupport> frame_sink = CreateFrameSink();
EmbedClient(frame_sink.get());
- SendUpdates(frame_sink.get(), kMinRect, 2 * kMinFps, 0.5 * kMinDuration);
+ SendUpdates(frame_sink.get(), kMinRect, /*may_contain_video=*/true,
+ 2 * kMinFps, 0.5 * kMinDuration);
EXPECT_TRUE(observer_.IsEmpty());
- SendUpdates(frame_sink.get(), kMinRect, 2 * kMinFps, 0.6 * kMinDuration);
+ SendUpdates(frame_sink.get(), kMinRect, /*may_contain_video=*/true,
+ 2 * kMinFps, 0.6 * kMinDuration);
EXPECT_TRUE(observer_.PopState());
EXPECT_TRUE(observer_.IsEmpty());
}
@@ -275,25 +298,46 @@ TEST_F(VideoDetectorTest, DontReportWhenNotPlayingLongEnough) {
TEST_F(VideoDetectorTest, DontReportWhenClientHidden) {
std::unique_ptr<CompositorFrameSinkSupport> frame_sink = CreateFrameSink();
- SendUpdates(frame_sink.get(), kMinRect, kMinFps + 5, 2 * kMinDuration);
+ SendUpdates(frame_sink.get(), kMinRect, /*may_contain_video=*/true,
+ kMinFps + 5, 2 * kMinDuration);
EXPECT_TRUE(observer_.IsEmpty());
// Make the client visible.
observer_.Reset();
AdvanceTime(kTimeout);
EmbedClient(frame_sink.get());
- SendUpdates(frame_sink.get(), kMinRect, kMinFps + 5, 2 * kMinDuration);
+ SendUpdates(frame_sink.get(), kMinRect, /*may_contain_video=*/true,
+ kMinFps + 5, 2 * kMinDuration);
EXPECT_TRUE(observer_.PopState());
EXPECT_TRUE(observer_.IsEmpty());
}
+TEST_F(VideoDetectorTest, DoesNotReportNonVideoFrames) {
+ const base::TimeDelta kDuration = kMinDuration + base::Milliseconds(100);
+ std::unique_ptr<CompositorFrameSinkSupport> frame_sink = CreateFrameSink();
+ EmbedClient(frame_sink.get());
+ SendUpdates(frame_sink.get(), kMinRect, /*may_contain_video=*/false,
+ kMinFps + 5, kDuration);
+ EXPECT_TRUE(observer_.IsEmpty());
+}
+
+TEST_F(VideoDetectorIncludeNonVideoTest, ReportNonVideoFramesWhenFeatureIsOff) {
+ const base::TimeDelta kDuration = kMinDuration + base::Milliseconds(100);
+ std::unique_ptr<CompositorFrameSinkSupport> frame_sink = CreateFrameSink();
+ EmbedClient(frame_sink.get());
+ SendUpdates(frame_sink.get(), kMinRect, /*may_contain_video=*/false,
+ kMinFps + 5, kDuration);
+ EXPECT_FALSE(observer_.IsEmpty());
+}
+
// Turn video activity on and off. Make sure the observers are notified
// properly.
TEST_F(VideoDetectorTest, ReportStartAndStop) {
const base::TimeDelta kDuration = kMinDuration + base::Milliseconds(100);
std::unique_ptr<CompositorFrameSinkSupport> frame_sink = CreateFrameSink();
EmbedClient(frame_sink.get());
- SendUpdates(frame_sink.get(), kMinRect, kMinFps + 5, kDuration);
+ SendUpdates(frame_sink.get(), kMinRect, /*may_contain_video=*/true,
+ kMinFps + 5, kDuration);
EXPECT_TRUE(observer_.PopState());
EXPECT_TRUE(observer_.IsEmpty());
@@ -302,7 +346,8 @@ TEST_F(VideoDetectorTest, ReportStartAndStop) {
EXPECT_TRUE(observer_.IsEmpty());
// Start playing again.
- SendUpdates(frame_sink.get(), kMinRect, kMinFps + 5, kDuration);
+ SendUpdates(frame_sink.get(), kMinRect, /*may_contain_video=*/true,
+ kMinFps + 5, kDuration);
EXPECT_TRUE(observer_.PopState());
EXPECT_TRUE(observer_.IsEmpty());
@@ -324,8 +369,8 @@ TEST_F(VideoDetectorTest, ReportOnceForMultipleClients) {
constexpr int fps = 2 * kMinFps;
constexpr base::TimeDelta time_between_updates = base::Seconds(1.0 / fps);
for (base::TimeDelta d; d < 2 * kMinDuration; d += time_between_updates) {
- SendUpdate(frame_sink1.get(), kMinRect);
- SendUpdate(frame_sink2.get(), kMinRect);
+ SendUpdate(frame_sink1.get(), kMinRect, /*may_contain_video=*/true);
+ SendUpdate(frame_sink2.get(), kMinRect, /*may_contain_video=*/true);
AdvanceTime(time_between_updates);
CreateDisplayFrame();
}
diff --git a/chromium/components/viz/service/gl/gpu_service_impl.cc b/chromium/components/viz/service/gl/gpu_service_impl.cc
index e3f6ce8fd9e..e9259246fac 100644
--- a/chromium/components/viz/service/gl/gpu_service_impl.cc
+++ b/chromium/components/viz/service/gl/gpu_service_impl.cc
@@ -72,7 +72,7 @@
#include "media/gpu/vaapi/vaapi_image_decode_accelerator_worker.h"
#endif // BUILDFLAG(USE_VAAPI)
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "components/viz/service/gl/throw_uncaught_exception.h"
#include "media/base/android/media_codec_util.h"
#endif
@@ -84,6 +84,9 @@
#if BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
#include "ash/components/arc/video_accelerator/gpu_arc_video_decode_accelerator.h"
+#if BUILDFLAG(USE_VAAPI) || BUILDFLAG(USE_V4L2_CODEC)
+#include "ash/components/arc/video_accelerator/gpu_arc_video_decoder.h"
+#endif
#include "ash/components/arc/video_accelerator/gpu_arc_video_encode_accelerator.h"
#include "ash/components/arc/video_accelerator/gpu_arc_video_protected_buffer_allocator.h"
#include "ash/components/arc/video_accelerator/protected_buffer_manager.h"
@@ -92,13 +95,13 @@
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include "mojo/public/cpp/system/platform_handle.h"
#include "ui/gl/dcomp_surface_registry.h"
#include "ui/gl/direct_composition_surface_win.h"
#endif
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
#include "ui/base/cocoa/quartz_util.h"
#endif
@@ -269,7 +272,7 @@ void GetVideoCapabilities(const gpu::GpuPreferences& gpu_preferences,
// Due to https://crbug.com/709631, we don't want to query Android video
// decode/encode capabilities during startup. The renderer needs this info
// though, so assume some baseline capabilities.
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Note: Video encoding on Android relies on MediaCodec, so all cases
// where it's disabled for decoding it is also disabled for encoding.
if (gpu_preferences.disable_accelerated_video_decode ||
@@ -387,12 +390,7 @@ GpuServiceImpl::GpuServiceImpl(
vulkan_implementation_, gpu_preferences_.vulkan_heap_memory_limit,
gpu_preferences_.vulkan_sync_cpu_memory_limit,
(is_native_vulkan && is_native_gl) ? &gpu_info : nullptr);
- if (vulkan_context_provider_) {
- // If Vulkan is supported, then OOP-R is supported.
- gpu_info_.oop_rasterization_supported = true;
- gpu_feature_info_.status_values[gpu::GPU_FEATURE_TYPE_OOP_RASTERIZATION] =
- gpu::kGpuFeatureStatusEnabled;
- } else {
+ if (!vulkan_context_provider_) {
DLOG(ERROR) << "Failed to create Vulkan context provider.";
}
}
@@ -401,11 +399,7 @@ GpuServiceImpl::GpuServiceImpl(
#if BUILDFLAG(SKIA_USE_DAWN)
if (gpu_preferences_.gr_context_type == gpu::GrContextType::kDawn) {
dawn_context_provider_ = DawnContextProvider::Create();
- if (dawn_context_provider_) {
- gpu_info_.oop_rasterization_supported = true;
- gpu_feature_info_.status_values[gpu::GPU_FEATURE_TYPE_OOP_RASTERIZATION] =
- gpu::kGpuFeatureStatusEnabled;
- } else {
+ if (!dawn_context_provider_) {
DLOG(ERROR) << "Failed to create Dawn context provider.";
}
}
@@ -416,14 +410,14 @@ GpuServiceImpl::GpuServiceImpl(
media::VaapiImageDecodeAcceleratorWorker::Create();
#endif // BUILDFLAG(USE_VAAPI_IMAGE_CODECS)
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
if (gpu_feature_info_.status_values[gpu::GPU_FEATURE_TYPE_METAL] ==
gpu::kGpuFeatureStatusEnabled) {
metal_context_provider_ = MetalContextProvider::Create(context_options);
}
#endif
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
auto info_callback = base::BindRepeating(
&GpuServiceImpl::UpdateOverlayAndHDRInfo, weak_ptr_factory_.GetWeakPtr());
gl::DirectCompositionSurfaceWin::SetOverlayHDRGpuInfoUpdateCallback(
@@ -685,6 +679,15 @@ void GpuServiceImpl::CreateArcVideoDecodeAccelerator(
weak_ptr_, std::move(vda_receiver)));
}
+void GpuServiceImpl::CreateArcVideoDecoder(
+ mojo::PendingReceiver<arc::mojom::VideoDecoder> vd_receiver) {
+ DCHECK(io_runner_->BelongsToCurrentThread());
+ main_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(&GpuServiceImpl::CreateArcVideoDecoderOnMainThread,
+ weak_ptr_, std::move(vd_receiver)));
+}
+
void GpuServiceImpl::CreateArcVideoEncodeAccelerator(
mojo::PendingReceiver<arc::mojom::VideoEncodeAccelerator> vea_receiver) {
DCHECK(io_runner_->BelongsToCurrentThread());
@@ -726,6 +729,16 @@ void GpuServiceImpl::CreateArcVideoDecodeAcceleratorOnMainThread(
std::move(vda_receiver));
}
+void GpuServiceImpl::CreateArcVideoDecoderOnMainThread(
+ mojo::PendingReceiver<arc::mojom::VideoDecoder> vd_receiver) {
+ DCHECK(main_runner_->BelongsToCurrentThread());
+#if BUILDFLAG(USE_VAAPI) || BUILDFLAG(USE_V4L2_CODEC)
+ mojo::MakeSelfOwnedReceiver(
+ std::make_unique<arc::GpuArcVideoDecoder>(protected_buffer_manager_),
+ std::move(vd_receiver));
+#endif
+}
+
void GpuServiceImpl::CreateArcVideoEncodeAcceleratorOnMainThread(
mojo::PendingReceiver<arc::mojom::VideoEncodeAccelerator> vea_receiver) {
DCHECK(main_runner_->BelongsToCurrentThread());
@@ -776,7 +789,7 @@ void GpuServiceImpl::CreateJpegEncodeAccelerator(
}
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
void GpuServiceImpl::RegisterDCOMPSurfaceHandle(
mojo::PlatformHandle surface_handle,
RegisterDCOMPSurfaceHandleCallback callback) {
@@ -790,7 +803,7 @@ void GpuServiceImpl::UnregisterDCOMPSurfaceHandle(
const base::UnguessableToken& token) {
gl::DCOMPSurfaceRegistry::GetInstance()->UnregisterDCOMPSurfaceHandle(token);
}
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
void GpuServiceImpl::CreateVideoEncodeAcceleratorProvider(
mojo::PendingReceiver<media::mojom::VideoEncodeAcceleratorProvider>
@@ -879,7 +892,7 @@ void GpuServiceImpl::RequestHDRStatusOnMainThread(
RequestHDRStatusCallback callback) {
DCHECK(main_runner_->BelongsToCurrentThread());
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
hdr_enabled_ = gl::DirectCompositionSurfaceWin::IsHDRSupported();
#endif
io_runner_->PostTask(FROM_HERE,
@@ -934,7 +947,7 @@ void GpuServiceImpl::DidLoseContext(bool offscreen,
gpu_host_->DidLoseContext(offscreen, reason, active_url);
}
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
void GpuServiceImpl::DidUpdateOverlayInfo(
const gpu::OverlayInfo& overlay_info) {
gpu_host_->DidUpdateOverlayInfo(gpu_info_.overlay_info);
@@ -971,7 +984,7 @@ bool GpuServiceImpl::IsExiting() const {
return is_exiting_.IsSet();
}
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
void GpuServiceImpl::SendCreatedChildWindow(gpu::SurfaceHandle parent_window,
gpu::SurfaceHandle child_window) {
// This can be called from main or display compositor thread.
@@ -1083,7 +1096,7 @@ void GpuServiceImpl::WakeUpGpu() {
FROM_HERE, base::BindOnce(&GpuServiceImpl::WakeUpGpu, weak_ptr_));
return;
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
gpu_channel_manager_->WakeUpGpu();
#else
NOTREACHED() << "WakeUpGpu() not supported on this platform.";
@@ -1159,7 +1172,7 @@ void GpuServiceImpl::DestroyAllChannels() {
void GpuServiceImpl::OnBackgroundCleanup() {
// Currently only called on Android.
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
if (!main_runner_->BelongsToCurrentThread()) {
main_runner_->PostTask(
FROM_HERE,
@@ -1219,7 +1232,7 @@ void GpuServiceImpl::OnForegroundedOnMainThread() {
}
}
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
void GpuServiceImpl::OnMemoryPressure(
::base::MemoryPressureListener::MemoryPressureLevel level) {
// Forward the notification to the registry of MemoryPressureListeners.
@@ -1227,7 +1240,7 @@ void GpuServiceImpl::OnMemoryPressure(
}
#endif
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
void GpuServiceImpl::BeginCATransaction() {
DCHECK(io_runner_->BelongsToCurrentThread());
main_runner_->PostTask(FROM_HERE, base::BindOnce(&ui::BeginCATransaction));
@@ -1261,7 +1274,7 @@ void GpuServiceImpl::Hang() {
void GpuServiceImpl::ThrowJavaException() {
DCHECK(io_runner_->BelongsToCurrentThread());
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
ThrowUncaughtException();
#else
NOTREACHED() << "Java exception not supported on this platform.";
@@ -1287,7 +1300,7 @@ gpu::Scheduler* GpuServiceImpl::GetGpuScheduler() {
return scheduler_.get();
}
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
void GpuServiceImpl::UpdateOverlayAndHDRInfo() {
gpu::OverlayInfo old_overlay_info = gpu_info_.overlay_info;
gpu::CollectHardwareOverlayInfo(&gpu_info_.overlay_info);
@@ -1323,7 +1336,7 @@ void GpuServiceImpl::GetDawnInfoOnMain(GetDawnInfoCallback callback) {
base::BindOnce(std::move(callback), dawn_info_list));
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
void GpuServiceImpl::SetHostProcessId(base::ProcessId pid) {
host_process_id_ = pid;
}
diff --git a/chromium/components/viz/service/gl/gpu_service_impl.h b/chromium/components/viz/service/gl/gpu_service_impl.h
index bd30d83bac8..fa1d52ae3b5 100644
--- a/chromium/components/viz/service/gl/gpu_service_impl.h
+++ b/chromium/components/viz/service/gl/gpu_service_impl.h
@@ -141,6 +141,8 @@ class VIZ_SERVICE_EXPORT GpuServiceImpl : public gpu::GpuChannelManagerDelegate,
void CreateArcVideoDecodeAccelerator(
mojo::PendingReceiver<arc::mojom::VideoDecodeAccelerator> vda_receiver)
override;
+ void CreateArcVideoDecoder(
+ mojo::PendingReceiver<arc::mojom::VideoDecoder> vd_receiver) override;
void CreateArcVideoEncodeAccelerator(
mojo::PendingReceiver<arc::mojom::VideoEncodeAccelerator> vea_receiver)
override;
@@ -159,13 +161,13 @@ class VIZ_SERVICE_EXPORT GpuServiceImpl : public gpu::GpuChannelManagerDelegate,
jea_receiver) override;
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
void RegisterDCOMPSurfaceHandle(
mojo::PlatformHandle surface_handle,
RegisterDCOMPSurfaceHandleCallback callback) override;
void UnregisterDCOMPSurfaceHandle(
const base::UnguessableToken& token) override;
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
void CreateVideoEncodeAcceleratorProvider(
mojo::PendingReceiver<media::mojom::VideoEncodeAcceleratorProvider>
@@ -202,11 +204,11 @@ class VIZ_SERVICE_EXPORT GpuServiceImpl : public gpu::GpuChannelManagerDelegate,
void OnBackgroundCleanup() override;
void OnBackgrounded() override;
void OnForegrounded() override;
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
void OnMemoryPressure(
base::MemoryPressureListener::MemoryPressureLevel level) override;
#endif
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
void BeginCATransaction() override;
void CommitCATransaction(CommitCATransactionCallback callback) override;
#endif
@@ -230,7 +232,7 @@ class VIZ_SERVICE_EXPORT GpuServiceImpl : public gpu::GpuChannelManagerDelegate,
void DidLoseContext(bool offscreen,
gpu::error::ContextLostReason reason,
const GURL& active_url) override;
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
void DidUpdateOverlayInfo(const gpu::OverlayInfo& overlay_info) override;
void DidUpdateHDRStatus(bool hdr_enabled) override;
#endif
@@ -245,7 +247,7 @@ class VIZ_SERVICE_EXPORT GpuServiceImpl : public gpu::GpuChannelManagerDelegate,
bool IsExiting() const override;
gpu::Scheduler* GetGpuScheduler() override;
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
void SendCreatedChildWindow(gpu::SurfaceHandle parent_window,
gpu::SurfaceHandle child_window) override;
#endif
@@ -352,7 +354,7 @@ class VIZ_SERVICE_EXPORT GpuServiceImpl : public gpu::GpuChannelManagerDelegate,
base::ProcessId host_process_id() const { return host_process_id_; }
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
void SetHostProcessId(base::ProcessId pid);
#endif
@@ -368,6 +370,8 @@ class VIZ_SERVICE_EXPORT GpuServiceImpl : public gpu::GpuChannelManagerDelegate,
#if BUILDFLAG(IS_CHROMEOS_ASH) && BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
void CreateArcVideoDecodeAcceleratorOnMainThread(
mojo::PendingReceiver<arc::mojom::VideoDecodeAccelerator> vda_receiver);
+ void CreateArcVideoDecoderOnMainThread(
+ mojo::PendingReceiver<arc::mojom::VideoDecoder> vd_receiver);
void CreateArcVideoEncodeAcceleratorOnMainThread(
mojo::PendingReceiver<arc::mojom::VideoEncodeAccelerator> vea_receiver);
void CreateArcVideoProtectedBufferAllocatorOnMainThread(
@@ -392,7 +396,7 @@ class VIZ_SERVICE_EXPORT GpuServiceImpl : public gpu::GpuChannelManagerDelegate,
// Update overlay info and HDR status on the GPU process and send the updated
// info back to the browser process if there is a change.
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
void UpdateOverlayAndHDRInfo();
#endif
diff --git a/chromium/components/viz/service/gl/gpu_service_impl_unittest.cc b/chromium/components/viz/service/gl/gpu_service_impl_unittest.cc
index 25b6132350b..c0b5cff9c99 100644
--- a/chromium/components/viz/service/gl/gpu_service_impl_unittest.cc
+++ b/chromium/components/viz/service/gl/gpu_service_impl_unittest.cc
@@ -5,12 +5,12 @@
#include "components/viz/service/gl/gpu_service_impl.h"
#include <memory>
+#include <tuple>
#include <utility>
#include "base/bind.h"
#include "base/callback.h"
#include "base/callback_helpers.h"
-#include "base/ignore_result.h"
#include "base/memory/weak_ptr.h"
#include "base/run_loop.h"
#include "base/task/single_thread_task_runner.h"
@@ -129,7 +129,7 @@ TEST_F(GpuServiceTest, LoseAllContexts) {
// Use a disconnected mojo remote for GpuHost, we don't need to receive any
// messages.
mojo::PendingRemote<mojom::GpuHost> gpu_host_proxy;
- ignore_result(gpu_host_proxy.InitWithNewPipeAndPassReceiver());
+ std::ignore = gpu_host_proxy.InitWithNewPipeAndPassReceiver();
gpu_service()->InitializeWithHost(
std::move(gpu_host_proxy), gpu::GpuProcessActivityFlags(),
gl::init::CreateOffscreenGLSurface(gfx::Size()),
@@ -163,7 +163,7 @@ TEST_F(GpuServiceTest, VisibilityCallbackCalled) {
gpu_service()->Bind(gpu_service_remote.BindNewPipeAndPassReceiver());
mojo::PendingRemote<mojom::GpuHost> gpu_host_proxy;
- ignore_result(gpu_host_proxy.InitWithNewPipeAndPassReceiver());
+ std::ignore = gpu_host_proxy.InitWithNewPipeAndPassReceiver();
gpu_service()->InitializeWithHost(
std::move(gpu_host_proxy), gpu::GpuProcessActivityFlags(),
gl::init::CreateOffscreenGLSurface(gfx::Size()),
diff --git a/chromium/components/viz/service/hit_test/hit_test_aggregator.cc b/chromium/components/viz/service/hit_test/hit_test_aggregator.cc
index 99bb7666c85..9690a1c8a16 100644
--- a/chromium/components/viz/service/hit_test/hit_test_aggregator.cc
+++ b/chromium/components/viz/service/hit_test/hit_test_aggregator.cc
@@ -6,8 +6,6 @@
#include "base/trace_event/trace_event.h"
#include "components/viz/common/hit_test/hit_test_region_list.h"
-#include "components/viz/common/quads/debug_border_draw_quad.h"
-#include "components/viz/common/quads/solid_color_draw_quad.h"
#include "components/viz/service/hit_test/hit_test_aggregator_delegate.h"
#include "components/viz/service/surfaces/latest_local_surface_id_lookup_delegate.h"
#include "skia/ext/skia_matrix_44.h"
@@ -32,8 +30,7 @@ HitTestAggregator::HitTestAggregator(
HitTestAggregator::~HitTestAggregator() = default;
-void HitTestAggregator::Aggregate(const SurfaceId& display_surface_id,
- AggregatedRenderPassList* render_passes) {
+void HitTestAggregator::Aggregate(const SurfaceId& display_surface_id) {
DCHECK(referenced_child_regions_.empty());
// The index will only have changed when new hit-test data has been submitted.
@@ -52,84 +49,8 @@ void HitTestAggregator::Aggregate(const SurfaceId& display_surface_id,
hit_test_data_size_ = 0;
hit_test_data_.resize(hit_test_data_capacity_);
- hit_test_debug_ = false;
- hit_test_debug_ask_regions_ = 0;
-
AppendRoot(display_surface_id);
SendHitTestData();
-
- if (hit_test_debug_ && render_passes) {
- InsertHitTestDebugQuads(render_passes);
- }
-}
-
-void HitTestAggregator::InsertHitTestDebugQuads(
- AggregatedRenderPassList* render_passes) {
- const base::flat_set<FrameSinkId>* hit_test_async_queried_debug_regions =
- hit_test_manager_->GetHitTestAsyncQueriedDebugRegions(
- root_frame_sink_id_);
-
- QuadList& ql = render_passes->back()->quad_list;
- ql.InsertBeforeAndInvalidateAllPointers<DebugBorderDrawQuad>(
- ql.begin(), hit_test_data_size_);
- ql.InsertBeforeAndInvalidateAllPointers<SolidColorDrawQuad>(
- ql.begin(), hit_test_debug_ask_regions_);
-
- SharedQuadState* sqs =
- render_passes->back()->CreateAndAppendSharedQuadState();
- sqs->opacity = 0.25f;
-
- const SkColor colors[3] = {SK_ColorCYAN, SK_ColorGREEN, SK_ColorMAGENTA};
-
- base::stack<uint32_t> parents;
- base::stack<gfx::Transform> parent_transforms;
- parent_transforms.push(gfx::Transform());
-
- for (uint32_t i = 0, ask_i = 0; i < hit_test_data_size_; ++i) {
- const AggregatedHitTestRegion& htr = hit_test_data_[i];
-
- gfx::Transform child_to_parent;
- // Hit-test transforms are guaranteed to be invertible.
- if (!htr.transform().GetInverse(&child_to_parent)) {
- return;
- }
-
- SkColor color = colors[parents.size() % 3];
- if (hit_test_async_queried_debug_regions &&
- hit_test_async_queried_debug_regions->count(htr.frame_sink_id)) {
- color = SK_ColorRED;
- }
-
- parents.push(i);
- // Concatenate transformation.
- parent_transforms.push(parent_transforms.top() * child_to_parent);
-
- // We can only transform gfx::RectF.
- gfx::RectF rf(hit_test_data_[i].rect);
- parent_transforms.top().TransformRect(&rf);
- const gfx::Rect debug_rect = gfx::ToEnclosedRect(rf);
-
- DebugBorderDrawQuad* debug_quad = static_cast<DebugBorderDrawQuad*>(
- ql.ElementAt(hit_test_debug_ask_regions_ + i));
- debug_quad->SetNew(sqs, debug_rect, debug_rect, color, /*width=*/5);
-
- if (htr.flags & kHitTestAsk) {
- SolidColorDrawQuad* ask_quad =
- static_cast<SolidColorDrawQuad*>(ql.ElementAt(ask_i++));
- ask_quad->SetNew(sqs, debug_rect, debug_rect, color,
- /*force_anti_aliasing_off=*/false);
- }
-
- while (!parents.empty()) {
- uint32_t parent_index = parents.top();
- uint32_t max_child_index =
- parent_index + hit_test_data_[parent_index].child_count;
- if (max_child_index > i)
- break;
- parents.pop();
- parent_transforms.pop();
- }
- }
}
void HitTestAggregator::SendHitTestData() {
@@ -283,10 +204,6 @@ void HitTestAggregator::SetRegionAt(size_t index,
AggregatedHitTestRegion(frame_sink_id, flags, rect, transform,
child_count, async_hit_test_reasons);
hit_test_data_size_++;
-
- hit_test_debug_ |= flags & kHitTestDebug;
- if (flags & kHitTestAsk)
- ++hit_test_debug_ask_regions_;
}
} // namespace viz
diff --git a/chromium/components/viz/service/hit_test/hit_test_aggregator.h b/chromium/components/viz/service/hit_test/hit_test_aggregator.h
index a10feed096c..795896045a8 100644
--- a/chromium/components/viz/service/hit_test/hit_test_aggregator.h
+++ b/chromium/components/viz/service/hit_test/hit_test_aggregator.h
@@ -44,10 +44,8 @@ class VIZ_SERVICE_EXPORT HitTestAggregator {
// Called after surfaces have been aggregated into the DisplayFrame.
// In this call HitTestRegionList structures received from active surfaces
- // are aggregated into |hit_test_data_|. If |render_passes| are given and
- // the correct flags are set, hit-test debug quads will be inserted.
- void Aggregate(const SurfaceId& display_surface_id,
- AggregatedRenderPassList* render_passes = nullptr);
+ // are aggregated into |hit_test_data_|.
+ void Aggregate(const SurfaceId& display_surface_id);
private:
friend class TestHitTestAggregator;
@@ -78,9 +76,6 @@ class VIZ_SERVICE_EXPORT HitTestAggregator {
absl::optional<int64_t> GetTraceIdIfUpdated(const SurfaceId& surface_id,
uint64_t active_frame_index);
- // Inserts debug quads based on hit-test data.
- void InsertHitTestDebugQuads(AggregatedRenderPassList* render_passes);
-
const raw_ptr<const HitTestManager> hit_test_manager_;
const raw_ptr<HitTestAggregatorDelegate> delegate_;
@@ -102,9 +97,6 @@ class VIZ_SERVICE_EXPORT HitTestAggregator {
uint32_t hit_test_data_size_ = 0;
std::vector<AggregatedHitTestRegion> hit_test_data_;
- bool hit_test_debug_ = false;
- uint32_t hit_test_debug_ask_regions_ = 0;
-
// This is the set of FrameSinkIds referenced in the aggregation in this tree
// chain so far, used to detect cycles. We can have regions that have the
// same FrameSinkId, e.g. when ALPHA_SHAPE is set in cc::FilterOperations,
diff --git a/chromium/components/viz/service/hit_test/hit_test_manager.cc b/chromium/components/viz/service/hit_test/hit_test_manager.cc
index 9381b42e6e4..205186d39e6 100644
--- a/chromium/components/viz/service/hit_test/hit_test_manager.cc
+++ b/chromium/components/viz/service/hit_test/hit_test_manager.cc
@@ -30,20 +30,6 @@ bool FlagsAndAsyncReasonsMatch(uint32_t flags,
} // namespace
-HitTestManager::HitTestAsyncQueriedDebugRegion::
- HitTestAsyncQueriedDebugRegion() = default;
-HitTestManager::HitTestAsyncQueriedDebugRegion::HitTestAsyncQueriedDebugRegion(
- base::flat_set<FrameSinkId> regions)
- : regions(std::move(regions)) {}
-HitTestManager::HitTestAsyncQueriedDebugRegion::
- ~HitTestAsyncQueriedDebugRegion() = default;
-
-HitTestManager::HitTestAsyncQueriedDebugRegion::HitTestAsyncQueriedDebugRegion(
- HitTestAsyncQueriedDebugRegion&&) = default;
-HitTestManager::HitTestAsyncQueriedDebugRegion&
-HitTestManager::HitTestAsyncQueriedDebugRegion::operator=(
- HitTestAsyncQueriedDebugRegion&&) = default;
-
HitTestManager::HitTestManager(SurfaceManager* surface_manager)
: surface_manager_(surface_manager) {}
@@ -143,26 +129,6 @@ int64_t HitTestManager::GetTraceId(const SurfaceId& id) const {
return surface->GetActiveFrameMetadata().begin_frame_ack.trace_id;
}
-const base::flat_set<FrameSinkId>*
-HitTestManager::GetHitTestAsyncQueriedDebugRegions(
- const FrameSinkId& root_frame_sink_id) const {
- auto it = hit_test_async_queried_debug_regions_.find(root_frame_sink_id);
- if (it == hit_test_async_queried_debug_regions_.end() ||
- it->second.timer.Elapsed().InMilliseconds() > 2000) {
- return nullptr;
- }
- return &it->second.regions;
-}
-
-void HitTestManager::SetHitTestAsyncQueriedDebugRegions(
- const FrameSinkId& root_frame_sink_id,
- const std::vector<FrameSinkId>& hit_test_async_queried_debug_queue) {
- hit_test_async_queried_debug_regions_[root_frame_sink_id] =
- HitTestAsyncQueriedDebugRegion(base::flat_set<FrameSinkId>(
- hit_test_async_queried_debug_queue.begin(),
- hit_test_async_queried_debug_queue.end()));
-}
-
bool HitTestManager::ValidateHitTestRegionList(
const SurfaceId& surface_id,
HitTestRegionList* hit_test_region_list) {
diff --git a/chromium/components/viz/service/hit_test/hit_test_manager.h b/chromium/components/viz/service/hit_test/hit_test_manager.h
index affeddf6fa7..d6f5063614f 100644
--- a/chromium/components/viz/service/hit_test/hit_test_manager.h
+++ b/chromium/components/viz/service/hit_test/hit_test_manager.h
@@ -62,12 +62,6 @@ class VIZ_SERVICE_EXPORT HitTestManager : public SurfaceObserver {
int64_t GetTraceId(const SurfaceId& id) const;
- const base::flat_set<FrameSinkId>* GetHitTestAsyncQueriedDebugRegions(
- const FrameSinkId& root_frame_sink_id) const;
- void SetHitTestAsyncQueriedDebugRegions(
- const FrameSinkId& root_frame_sink_id,
- const std::vector<FrameSinkId>& hit_test_async_queried_debug_queue);
-
uint64_t submit_hit_test_region_list_index() const {
return submit_hit_test_region_list_index_;
}
@@ -82,25 +76,6 @@ class VIZ_SERVICE_EXPORT HitTestManager : public SurfaceObserver {
std::map<SurfaceId, base::flat_map<uint64_t, HitTestRegionList>>
hit_test_region_lists_;
- struct HitTestAsyncQueriedDebugRegion {
- HitTestAsyncQueriedDebugRegion();
- explicit HitTestAsyncQueriedDebugRegion(
- base::flat_set<FrameSinkId> regions);
- ~HitTestAsyncQueriedDebugRegion();
-
- HitTestAsyncQueriedDebugRegion(HitTestAsyncQueriedDebugRegion&&);
- HitTestAsyncQueriedDebugRegion& operator=(HitTestAsyncQueriedDebugRegion&&);
-
- base::flat_set<FrameSinkId> regions;
- base::ElapsedTimer timer;
- };
-
- // We store the async queried regions for each |root_frame_sink_id|. If viz
- // hit-test debug is enabled, We will highlight the regions red in
- // HitTestAggregator for 2 seconds, or until the next async queried event.
- base::flat_map<FrameSinkId, HitTestAsyncQueriedDebugRegion>
- hit_test_async_queried_debug_regions_;
-
// Keeps track of the number of submitted HitTestRegionLists. This allows the
// HitTestAggregators to stay in sync with the HitTestManager and only
// aggregate when there is new hit-test data.
diff --git a/chromium/components/viz/service/java/src/org/chromium/components/viz/service/frame_sinks/ExternalBeginFrameSourceAndroid.java b/chromium/components/viz/service/java/src/org/chromium/components/viz/service/frame_sinks/ExternalBeginFrameSourceAndroid.java
index 29b137d4e2a..6b863ff9f57 100644
--- a/chromium/components/viz/service/java/src/org/chromium/components/viz/service/frame_sinks/ExternalBeginFrameSourceAndroid.java
+++ b/chromium/components/viz/service/java/src/org/chromium/components/viz/service/frame_sinks/ExternalBeginFrameSourceAndroid.java
@@ -4,41 +4,49 @@
package org.chromium.components.viz.service.frame_sinks;
-import org.chromium.base.ContextUtils;
+import android.view.Choreographer;
+
+import org.chromium.base.TraceEvent;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
import org.chromium.base.annotations.MainDex;
import org.chromium.base.annotations.NativeMethods;
-import org.chromium.ui.VSyncMonitor;
/**
* Provides a VSyncMonitor backed BeginFrameSource.
*/
@JNINamespace("viz")
@MainDex
-public class ExternalBeginFrameSourceAndroid {
+public class ExternalBeginFrameSourceAndroid implements Choreographer.FrameCallback {
+ private static final long NANOSECONDS_PER_SECOND = 1000000000;
+ private static final long NANOSECONDS_PER_MICROSECOND = 1000;
+
+ // Conservative guess about vsync's consecutivity.
+ // If true, next tick is guaranteed to be consecutive.
+ private boolean mConsecutiveVSync;
+ private boolean mInsideVSync;
+
+ // Display refresh rate as reported by the system.
+ private long mRefreshPeriodNano;
+ private boolean mUseEstimatedRefreshRate;
+
+ private boolean mHaveRequestInFlight;
+
+ private final Choreographer mChoreographer;
+ private long mGoodStartingPointNano;
+
private final long mNativeExternalBeginFrameSourceAndroid;
private boolean mVSyncNotificationsEnabled;
- private final VSyncMonitor mVSyncMonitor;
- private final VSyncMonitor.Listener mVSyncListener = new VSyncMonitor.Listener() {
- @Override
- public void onVSync(VSyncMonitor monitor, long vsyncTimeMicros) {
- if (!mVSyncNotificationsEnabled) {
- return;
- }
- ExternalBeginFrameSourceAndroidJni.get().onVSync(mNativeExternalBeginFrameSourceAndroid,
- ExternalBeginFrameSourceAndroid.this, vsyncTimeMicros,
- mVSyncMonitor.getVSyncPeriodInMicroseconds());
- mVSyncMonitor.requestUpdate();
- }
- };
@CalledByNative
private ExternalBeginFrameSourceAndroid(
long nativeExternalBeginFrameSourceAndroid, float refreshRate) {
+ updateRefreshRate(refreshRate);
+
+ mChoreographer = Choreographer.getInstance();
+ mGoodStartingPointNano = getCurrentNanoTime();
+
mNativeExternalBeginFrameSourceAndroid = nativeExternalBeginFrameSourceAndroid;
- mVSyncMonitor =
- new VSyncMonitor(ContextUtils.getApplicationContext(), mVSyncListener, refreshRate);
}
@CalledByNative
@@ -49,13 +57,58 @@ public class ExternalBeginFrameSourceAndroid {
mVSyncNotificationsEnabled = enabled;
if (mVSyncNotificationsEnabled) {
- mVSyncMonitor.requestUpdate();
+ postCallback();
}
}
@CalledByNative
private void updateRefreshRate(float refreshRate) {
- mVSyncMonitor.updateRefreshRate(refreshRate);
+ mUseEstimatedRefreshRate = refreshRate < 30;
+ if (refreshRate <= 0) refreshRate = 60;
+ mRefreshPeriodNano = (long) (NANOSECONDS_PER_SECOND / refreshRate);
+ }
+
+ private void postCallback() {
+ if (mHaveRequestInFlight) return;
+ mHaveRequestInFlight = true;
+ mConsecutiveVSync = mInsideVSync;
+ mChoreographer.postFrameCallback(this);
+ }
+
+ @Override
+ public void doFrame(long frameTimeNanos) {
+ TraceEvent.begin("VSync");
+ try {
+ if (mUseEstimatedRefreshRate && mConsecutiveVSync) {
+ // Display.getRefreshRate() is unreliable on some platforms.
+ // Adjust refresh period- initial value is based on Display.getRefreshRate()
+ // after that it asymptotically approaches the real value.
+ long lastRefreshDurationNano = frameTimeNanos - mGoodStartingPointNano;
+ float lastRefreshDurationWeight = 0.1f;
+ mRefreshPeriodNano += (long) (lastRefreshDurationWeight
+ * (lastRefreshDurationNano - mRefreshPeriodNano));
+ }
+ mGoodStartingPointNano = frameTimeNanos;
+ mInsideVSync = true;
+ assert mHaveRequestInFlight;
+ mHaveRequestInFlight = false;
+
+ if (!mVSyncNotificationsEnabled) {
+ return;
+ }
+ ExternalBeginFrameSourceAndroidJni.get().onVSync(mNativeExternalBeginFrameSourceAndroid,
+ ExternalBeginFrameSourceAndroid.this,
+ frameTimeNanos / NANOSECONDS_PER_MICROSECOND,
+ mRefreshPeriodNano / NANOSECONDS_PER_MICROSECOND);
+ postCallback();
+ } finally {
+ mInsideVSync = false;
+ TraceEvent.end("VSync");
+ }
+ }
+
+ private long getCurrentNanoTime() {
+ return System.nanoTime();
}
@NativeMethods
@@ -64,4 +117,4 @@ public class ExternalBeginFrameSourceAndroid {
ExternalBeginFrameSourceAndroid caller, long vsyncTimeMicros,
long vsyncPeriodMicros);
}
-};
+}
diff --git a/chromium/components/viz/service/main/viz_compositor_thread_runner.h b/chromium/components/viz/service/main/viz_compositor_thread_runner.h
index c25dfc44781..6db9cd8f454 100644
--- a/chromium/components/viz/service/main/viz_compositor_thread_runner.h
+++ b/chromium/components/viz/service/main/viz_compositor_thread_runner.h
@@ -6,6 +6,7 @@
#define COMPONENTS_VIZ_SERVICE_MAIN_VIZ_COMPOSITOR_THREAD_RUNNER_H_
#include "base/callback.h"
+#include "base/threading/platform_thread.h"
#include "services/viz/privileged/mojom/viz_main.mojom.h"
namespace base {
diff --git a/chromium/components/viz/service/main/viz_compositor_thread_runner_impl.cc b/chromium/components/viz/service/main/viz_compositor_thread_runner_impl.cc
index f579aaf3e0c..25bdb8e2413 100644
--- a/chromium/components/viz/service/main/viz_compositor_thread_runner_impl.cc
+++ b/chromium/components/viz/service/main/viz_compositor_thread_runner_impl.cc
@@ -21,6 +21,7 @@
#include "components/viz/service/display_embedder/output_surface_provider_impl.h"
#include "components/viz/service/display_embedder/server_shared_bitmap_manager.h"
#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
+#include "components/viz/service/frame_sinks/gmb_video_frame_pool_context_provider_impl.h"
#include "components/viz/service/gl/gpu_service_impl.h"
#include "gpu/config/gpu_finch_features.h"
#include "gpu/config/gpu_switches.h"
@@ -44,12 +45,12 @@ std::unique_ptr<VizCompositorThreadType> CreateAndStartCompositorThread() {
base::FeatureList::IsEnabled(features::kGpuUseDisplayThreadPriority)
? base::ThreadPriority::DISPLAY
: base::ThreadPriority::NORMAL;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
auto thread = std::make_unique<base::android::JavaHandlerThread>(
kThreadName, thread_priority);
thread->Start();
return thread;
-#else // !defined(OS_ANDROID)
+#else // !BUILDFLAG(IS_ANDROID)
std::unique_ptr<base::Thread> thread;
base::Thread::Options thread_options;
@@ -62,12 +63,12 @@ std::unique_ptr<VizCompositorThreadType> CreateAndStartCompositorThread() {
if (!thread)
thread = std::make_unique<base::Thread>(kThreadName);
-#if defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_FUCHSIA)
// An IO message pump is needed to use FIDL.
thread_options.message_pump_type = base::MessagePumpType::IO;
#endif
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
// Increase the thread priority to get more reliable values in performance
// test of macOS.
thread_options.priority =
@@ -77,7 +78,7 @@ std::unique_ptr<VizCompositorThreadType> CreateAndStartCompositorThread() {
: thread_priority;
#else
thread_options.priority = thread_priority;
-#endif // !defined(OS_APPLE)
+#endif // !BUILDFLAG(IS_APPLE)
CHECK(thread->StartWithOptions(std::move(thread_options)));
@@ -87,7 +88,7 @@ std::unique_ptr<VizCompositorThreadType> CreateAndStartCompositorThread() {
base::BindOnce(&tracing::TracingSamplerProfiler::CreateOnChildThread));
return thread;
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
}
} // namespace
@@ -160,14 +161,20 @@ void VizCompositorThreadRunnerImpl::CreateFrameSinkManagerOnCompositorThread(
if (task_executor) {
DCHECK(gpu_service);
// Create OutputSurfaceProvider usable for GPU + software compositing.
- auto gpu_memory_buffer_manager =
+ gpu_memory_buffer_manager_ =
std::make_unique<InProcessGpuMemoryBufferManager>(
gpu_service->gpu_memory_buffer_factory(),
gpu_service->sync_point_manager());
auto* image_factory = gpu_service->gpu_image_factory();
output_surface_provider_ = std::make_unique<OutputSurfaceProviderImpl>(
gpu_service, task_executor, gpu_service,
- std::move(gpu_memory_buffer_manager), image_factory, headless);
+ gpu_memory_buffer_manager_.get(), image_factory, headless);
+
+ // Create video frame pool context provider that will enable the frame sink
+ // manager to create GMB-backed video frames.
+ gmb_video_frame_pool_context_provider_ =
+ std::make_unique<GmbVideoFramePoolContextProviderImpl>(
+ gpu_service, gpu_memory_buffer_manager_.get());
} else {
// Create OutputSurfaceProvider usable for software compositing only.
output_surface_provider_ =
@@ -184,6 +191,8 @@ void VizCompositorThreadRunnerImpl::CreateFrameSinkManagerOnCompositorThread(
params->activation_deadline_in_frames;
}
init_params.output_surface_provider = output_surface_provider_.get();
+ init_params.gmb_context_provider =
+ gmb_video_frame_pool_context_provider_.get();
init_params.restart_id = params->restart_id;
init_params.run_all_compositor_stages_before_draw =
run_all_compositor_stages_before_draw;
@@ -209,6 +218,7 @@ void VizCompositorThreadRunnerImpl::TearDownOnCompositorThread() {
frame_sink_manager_.reset();
output_surface_provider_.reset();
+ gpu_memory_buffer_manager_.reset();
server_shared_bitmap_manager_.reset();
}
diff --git a/chromium/components/viz/service/main/viz_compositor_thread_runner_impl.h b/chromium/components/viz/service/main/viz_compositor_thread_runner_impl.h
index c839d44c358..b3a6da072fe 100644
--- a/chromium/components/viz/service/main/viz_compositor_thread_runner_impl.h
+++ b/chromium/components/viz/service/main/viz_compositor_thread_runner_impl.h
@@ -12,7 +12,7 @@
#include "components/viz/service/main/viz_compositor_thread_runner.h"
#include "services/network/public/mojom/tcp_socket.mojom.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "base/android/java_handler_thread.h"
#endif
@@ -21,11 +21,13 @@ class Thread;
} // namespace base
namespace viz {
-class OutputSurfaceProvider;
class FrameSinkManagerImpl;
+class GmbVideoFramePoolContextProvider;
+class InProcessGpuMemoryBufferManager;
+class OutputSurfaceProvider;
class ServerSharedBitmapManager;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
using VizCompositorThreadType = base::android::JavaHandlerThread;
#else
using VizCompositorThreadType = base::Thread;
@@ -62,7 +64,10 @@ class VizCompositorThreadRunnerImpl : public VizCompositorThreadRunner {
// Start variables to be accessed only on |task_runner_|.
std::unique_ptr<ServerSharedBitmapManager> server_shared_bitmap_manager_;
+ std::unique_ptr<InProcessGpuMemoryBufferManager> gpu_memory_buffer_manager_;
std::unique_ptr<OutputSurfaceProvider> output_surface_provider_;
+ std::unique_ptr<GmbVideoFramePoolContextProvider>
+ gmb_video_frame_pool_context_provider_;
std::unique_ptr<FrameSinkManagerImpl> frame_sink_manager_;
// End variables to be accessed only on |task_runner_|.
diff --git a/chromium/components/viz/service/main/viz_main_impl.cc b/chromium/components/viz/service/main/viz_main_impl.cc
index dd68a3a970d..29d201b226d 100644
--- a/chromium/components/viz/service/main/viz_main_impl.cc
+++ b/chromium/components/viz/service/main/viz_main_impl.cc
@@ -225,7 +225,7 @@ void VizMainImpl::CreateGpuService(
delegate_->OnGpuServiceConnection(gpu_service_.get());
}
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
void VizMainImpl::CreateInfoCollectionGpuService(
mojo::PendingReceiver<mojom::InfoCollectionGpuService> pending_receiver) {
DCHECK(gpu_thread_task_runner_->BelongsToCurrentThread());
@@ -239,7 +239,7 @@ void VizMainImpl::CreateInfoCollectionGpuService(
}
#endif
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
void VizMainImpl::SetHostProcessId(int32_t pid) {
if (gpu_service_)
gpu_service_->SetHostProcessId(pid);
diff --git a/chromium/components/viz/service/main/viz_main_impl.h b/chromium/components/viz/service/main/viz_main_impl.h
index fdc36a679cf..0423d8b704d 100644
--- a/chromium/components/viz/service/main/viz_main_impl.h
+++ b/chromium/components/viz/service/main/viz_main_impl.h
@@ -25,7 +25,7 @@
#include "services/viz/privileged/mojom/viz_main.mojom.h"
#include "ui/gfx/font_render_params.h"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include "components/viz/service/gl/info_collection_gpu_service_impl.h"
#include "services/viz/privileged/mojom/gl/info_collection_gpu_service.mojom.h"
#endif
@@ -46,7 +46,7 @@ class MojoUkmRecorder;
namespace viz {
class HintSessionFactory;
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
class InfoCollectionGpuServiceImpl;
#endif
@@ -122,12 +122,12 @@ class VizMainImpl : public mojom::VizMain,
discardable_memory_manager,
mojo::ScopedSharedBufferHandle activity_flags,
gfx::FontRenderParams::SubpixelRendering subpixel_rendering) override;
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
void CreateInfoCollectionGpuService(
mojo::PendingReceiver<mojom::InfoCollectionGpuService> pending_receiver)
override;
#endif
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
void SetHostProcessId(int32_t pid) override;
#endif
void CreateFrameSinkManager(mojom::FrameSinkManagerParamsPtr params) override;
@@ -175,7 +175,7 @@ class VizMainImpl : public mojom::VizMain,
std::unique_ptr<gpu::GpuInit> gpu_init_;
std::unique_ptr<GpuServiceImpl> gpu_service_;
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
std::unique_ptr<InfoCollectionGpuServiceImpl> info_collection_gpu_service_;
#endif
diff --git a/chromium/components/viz/service/performance_hint/hint_session.cc b/chromium/components/viz/service/performance_hint/hint_session.cc
index 3e3571f7444..04aadfceb31 100644
--- a/chromium/components/viz/service/performance_hint/hint_session.cc
+++ b/chromium/components/viz/service/performance_hint/hint_session.cc
@@ -9,7 +9,7 @@
#include "build/build_config.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include <dlfcn.h>
#include <sys/types.h>
@@ -17,7 +17,6 @@
#include "base/android/build_info.h"
#include "base/logging.h"
#include "base/native_library.h"
-#include "base/no_destructor.h"
#include "base/trace_event/trace_event.h"
static_assert(sizeof(base::PlatformThreadId) == sizeof(int32_t),
@@ -164,7 +163,7 @@ std::unique_ptr<HintSessionFactory> HintSessionFactory::Create(
} // namespace viz
-#else // defined(OS_ANDROID)
+#else // BUILDFLAG(IS_ANDROID)
namespace viz {
std::unique_ptr<HintSessionFactory> HintSessionFactory::Create(
@@ -173,4 +172,4 @@ std::unique_ptr<HintSessionFactory> HintSessionFactory::Create(
}
} // namespace viz
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
diff --git a/chromium/components/viz/service/performance_hint/utils.cc b/chromium/components/viz/service/performance_hint/utils.cc
index fa95b50b054..d6c4c5cf3c8 100644
--- a/chromium/components/viz/service/performance_hint/utils.cc
+++ b/chromium/components/viz/service/performance_hint/utils.cc
@@ -7,7 +7,7 @@
#include "base/containers/contains.h"
#include "build/build_config.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "base/linux_util.h"
#endif
@@ -17,7 +17,7 @@ bool CheckThreadIdsDoNotBelongToProcessIds(
const std::vector<base::ProcessId>& privileged_process_ids,
const base::flat_set<base::PlatformThreadId>&
thread_ids_from_sandboxed_process) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// This is inherently racy as threads or processes can die and the IDs can be
// reused at any time. But this is the best we can do.
for (auto& process_id : privileged_process_ids) {
diff --git a/chromium/components/viz/service/surfaces/referenced_surface_tracker.cc b/chromium/components/viz/service/surfaces/referenced_surface_tracker.cc
index e9498de7319..b451cca8bca 100644
--- a/chromium/components/viz/service/surfaces/referenced_surface_tracker.cc
+++ b/chromium/components/viz/service/surfaces/referenced_surface_tracker.cc
@@ -16,21 +16,29 @@ void GetSurfaceReferenceDifference(
std::vector<SurfaceReference>* references_to_remove) {
DCHECK(parent_surface_id.is_valid());
- // Find SurfaceIds in |old_referenced_surfaces| that aren't referenced
- // anymore.
- for (const SurfaceId& surface_id : old_referenced_surfaces) {
- if (new_referenced_surfaces.count(surface_id) == 0) {
- references_to_remove->push_back(
- SurfaceReference(parent_surface_id, surface_id));
- }
- }
+ auto old_it = old_referenced_surfaces.begin();
+ auto old_end = old_referenced_surfaces.end();
+ auto new_it = new_referenced_surfaces.begin();
+ auto new_end = new_referenced_surfaces.end();
- // Find SurfaceIds in |new_referenced_surfaces| that aren't already
- // referenced.
- for (const SurfaceId& surface_id : new_referenced_surfaces) {
- if (old_referenced_surfaces.count(surface_id) == 0) {
+ // Do a linear walk through both old and new references to compute added and
+ // removed entries.
+ while (old_it != old_end || new_it != new_end) {
+ if (old_it == old_end) {
+ references_to_add->push_back(
+ SurfaceReference(parent_surface_id, *new_it++));
+ } else if (new_it == new_end) {
+ references_to_remove->push_back(
+ SurfaceReference(parent_surface_id, *old_it++));
+ } else if (*old_it < *new_it) {
+ references_to_remove->push_back(
+ SurfaceReference(parent_surface_id, *old_it++));
+ } else if (*new_it < *old_it) {
references_to_add->push_back(
- SurfaceReference(parent_surface_id, surface_id));
+ SurfaceReference(parent_surface_id, *new_it++));
+ } else {
+ ++new_it;
+ ++old_it;
}
}
}
diff --git a/chromium/components/viz/service/surfaces/surface.cc b/chromium/components/viz/service/surfaces/surface.cc
index 96437239ca0..900270f8b6d 100644
--- a/chromium/components/viz/service/surfaces/surface.cc
+++ b/chromium/components/viz/service/surfaces/surface.cc
@@ -9,6 +9,7 @@
#include <algorithm>
#include <limits>
+#include <tuple>
#include <utility>
#include "base/containers/contains.h"
@@ -151,60 +152,14 @@ void Surface::UpdateSurfaceReferences() {
void Surface::OnChildActivatedForActiveFrame(const SurfaceId& activated_id) {
DCHECK(HasActiveFrame());
- for (size_t i = 0;
- i < active_frame_data_->frame.metadata.referenced_surfaces.size(); i++) {
- const SurfaceRange& surface_range =
- active_frame_data_->frame.metadata.referenced_surfaces[i];
- if (!surface_range.IsInRangeInclusive(activated_id))
- continue;
-
- const SurfaceId& last_id = last_surface_id_for_range_[i];
- // If we already have a reference to a surface in the primary's allocation
- // group, we should already be unregistered from the allocation group of the
- // fallback so we shouldn't receive SurfaceIds from that group.
- // TODO(crbug.com/1264657): This DCHECK is failing frequently on Chrome OS
- // for valid use cases where there are multiple references in
- // |referenced_surfaces| that contain |activated_id|. Temporary disable to
- // avoid flake while investigating solutions.
- // DCHECK(!surface_range.HasDifferentEmbedTokens() || !last_id.is_valid() ||
- // !last_id.HasSameEmbedTokenAs(surface_range.end()) ||
- // activated_id.HasSameEmbedTokenAs(last_id));
-
- // Remove the old reference.
- if (last_id.is_valid()) {
- auto old_it = active_referenced_surfaces_.find(last_id);
- if (old_it != active_referenced_surfaces_.end())
- active_referenced_surfaces_.erase(old_it);
- surface_manager_->RemoveSurfaceReferences(
- {SurfaceReference(surface_info_.id(), last_id)});
- }
-
- // Add a new reference.
- active_referenced_surfaces_.insert(activated_id);
- surface_manager_->AddSurfaceReferences(
- {SurfaceReference(surface_info_.id(), activated_id)});
-
- // If we were referencing a surface in the allocation group of the
- // fallback, but now there is a surface available in the allocation group
- // of the primary, unregister this surface from the allocation group of
- // the fallback.
- if (activated_id.HasSameEmbedTokenAs(surface_range.end()) &&
- surface_range.HasDifferentEmbedTokens() &&
- (!last_id.is_valid() || !last_id.HasSameEmbedTokenAs(activated_id))) {
- DCHECK(surface_range.start());
- DCHECK(!last_id.is_valid() ||
- last_id.HasSameEmbedTokenAs(*surface_range.start()));
- SurfaceAllocationGroup* group =
- surface_manager_->GetAllocationGroupForSurfaceId(
- *surface_range.start());
- if (group && referenced_allocation_groups_.count(group)) {
- group->UnregisterActiveEmbedder(this);
- referenced_allocation_groups_.erase(group);
- }
+ for (auto& surface_range : GetActiveFrame().metadata.referenced_surfaces) {
+ if (surface_range.IsInRangeInclusive(activated_id)) {
+ // If |activated_id| is included in any of the surface reference then
+ // recompute the active surface references. This must handle the case
+ // where a SurfaceId is included in multiple surface ranges.
+ RecomputeActiveReferencedSurfaces();
+ return;
}
-
- // Update the referenced surface for this range.
- last_surface_id_for_range_[i] = activated_id;
}
}
@@ -287,7 +242,7 @@ Surface::QueueFrameResult Surface::QueueFrame(
// The frame should not fail to display beyond this point. Release the
// callback so it is not called.
- (void)frame_rejected_callback.Release();
+ std::ignore = frame_rejected_callback.Release();
return result;
}
@@ -847,8 +802,4 @@ std::unique_ptr<gfx::DelegatedInkMetadata> Surface::TakeDelegatedInkMetadata() {
return active_frame_data_->TakeDelegatedInkMetadata();
}
-SurfaceSavedFrameStorage* Surface::GetSurfaceSavedFrameStorage() {
- return &surface_saved_frame_storage_;
-}
-
} // namespace viz
diff --git a/chromium/components/viz/service/surfaces/surface.h b/chromium/components/viz/service/surfaces/surface.h
index cb83692e909..30c4619c576 100644
--- a/chromium/components/viz/service/surfaces/surface.h
+++ b/chromium/components/viz/service/surfaces/surface.h
@@ -28,7 +28,6 @@
#include "components/viz/service/surfaces/pending_copy_output_request.h"
#include "components/viz/service/surfaces/surface_client.h"
#include "components/viz/service/surfaces/surface_dependency_deadline.h"
-#include "components/viz/service/surfaces/surface_saved_frame_storage.h"
#include "components/viz/service/viz_service_export.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "ui/gfx/geometry/size.h"
@@ -272,8 +271,6 @@ class VIZ_SERVICE_EXPORT Surface final {
std::unique_ptr<gfx::DelegatedInkMetadata> TakeDelegatedInkMetadata();
- SurfaceSavedFrameStorage* GetSurfaceSavedFrameStorage();
-
base::WeakPtr<Surface> GetWeakPtr() { return weak_factory_.GetWeakPtr(); }
// Always placed the given |copy_request| on the root render pass.
@@ -398,8 +395,6 @@ class VIZ_SERVICE_EXPORT Surface final {
const raw_ptr<SurfaceAllocationGroup> allocation_group_;
- SurfaceSavedFrameStorage surface_saved_frame_storage_{this};
-
bool has_damage_from_interpolated_frame_ = false;
base::WeakPtrFactory<Surface> weak_factory_{this};
diff --git a/chromium/components/viz/service/surfaces/surface_saved_frame.cc b/chromium/components/viz/service/surfaces/surface_saved_frame.cc
index bb30903972a..30cdf839d32 100644
--- a/chromium/components/viz/service/surfaces/surface_saved_frame.cc
+++ b/chromium/components/viz/service/surfaces/surface_saved_frame.cc
@@ -82,6 +82,19 @@ bool SurfaceSavedFrame::IsValid() const {
void SurfaceSavedFrame::RequestCopyOfOutput(Surface* surface) {
DCHECK(surface->HasActiveFrame());
+ if (directive_.is_renderer_driven_animation()) {
+ // TODO(khushalsagar) : This should be the only mode once renderer based SET
+ // lands.
+ copy_root_render_pass_ = false;
+ CopyUsingOriginalFrame(surface);
+ } else {
+ CopyUsingCleanFrame(surface);
+ }
+
+ DCHECK_EQ(copy_request_count_, ExpectedResultCount());
+}
+
+void SurfaceSavedFrame::CopyUsingCleanFrame(Surface* surface) {
const auto& root_draw_data = GetRootRenderPassDrawData(surface);
// Bind kRoot and root geometry information to the callback.
auto root_request = std::make_unique<CopyOutputRequest>(
@@ -100,20 +113,6 @@ void SurfaceSavedFrame::RequestCopyOfOutput(Surface* surface) {
return;
}
- if (surface->GetActiveFrame().metadata.has_shared_element_resources) {
- // TODO(khushalsagar) : This should be the only mode once renderer based SET
- // lands.
- CopyUsingOriginalFrame(surface, std::move(root_request));
- } else {
- CopyUsingCleanFrame(surface, std::move(root_request));
- }
-
- DCHECK_EQ(copy_request_count_, ExpectedResultCount());
-}
-
-void SurfaceSavedFrame::CopyUsingCleanFrame(
- Surface* surface,
- std::unique_ptr<CopyOutputRequest> root_request) {
// If the directive includes shared elements then we need to create a new
// CompositorFrame with render passes that remove these elements. The strategy
// is as follows :
@@ -187,9 +186,7 @@ void SurfaceSavedFrame::CopyUsingCleanFrame(
clean_surface_.emplace(surface, std::move(clean_frame));
}
-void SurfaceSavedFrame::CopyUsingOriginalFrame(
- Surface* surface,
- std::unique_ptr<CopyOutputRequest> root_request) {
+void SurfaceSavedFrame::CopyUsingOriginalFrame(Surface* surface) {
const auto& active_frame = surface->GetActiveFrame();
for (const auto& render_pass : active_frame.render_pass_list) {
if (auto request = CreateCopyRequestIfNeeded(
@@ -199,12 +196,6 @@ void SurfaceSavedFrame::CopyUsingOriginalFrame(
copy_request_count_++;
}
}
-
- // TODO(khushalsagar) : The root element should be an intermediate render pass
- // in the renderer's frame. We could optimize it if there are no shared
- // elements. See crbug.com/1265700.
- surface->RequestCopyOfOutputOnRootRenderPass(std::move(root_request));
- copy_request_count_++;
}
std::unique_ptr<CopyOutputRequest> SurfaceSavedFrame::CreateCopyRequestIfNeeded(
@@ -288,7 +279,7 @@ bool SurfaceSavedFrame::IsSharedElementRenderPass(
size_t SurfaceSavedFrame::ExpectedResultCount() const {
// Start with 1 for the root render pass.
- size_t count = 1;
+ size_t count = copy_root_render_pass_ ? 1 : 0;
for (auto& shared_element : directive_.shared_elements())
count += !shared_element.render_pass_id.is_null();
return count;
@@ -308,9 +299,11 @@ void SurfaceSavedFrame::NotifyCopyOfOutputComplete(
}
// Return if the result is empty.
- // TODO(vmpstr): We should log / trace this.
- if (output_copy->IsEmpty())
+ if (output_copy->IsEmpty()) {
+ LOG(ERROR) << "SurfaceSavedFrame copy output result for shared index "
+ << shared_index << " is empty.";
return;
+ }
++valid_result_count_;
if (!frame_result_) {
diff --git a/chromium/components/viz/service/surfaces/surface_saved_frame.h b/chromium/components/viz/service/surfaces/surface_saved_frame.h
index cac37b248cc..c50ec2a6262 100644
--- a/chromium/components/viz/service/surfaces/surface_saved_frame.h
+++ b/chromium/components/viz/service/surfaces/surface_saved_frame.h
@@ -8,7 +8,6 @@
#include <memory>
#include <vector>
-#include "base/compiler_specific.h"
#include "base/containers/flat_map.h"
#include "base/memory/weak_ptr.h"
#include "components/viz/common/frame_sinks/copy_output_result.h"
@@ -92,7 +91,7 @@ class VIZ_SERVICE_EXPORT SurfaceSavedFrame {
void RequestCopyOfOutput(Surface* surface);
void ReleaseSurface();
- absl::optional<FrameResult> TakeResult() WARN_UNUSED_RESULT;
+ [[nodiscard]] absl::optional<FrameResult> TakeResult();
// For testing functionality that ensures that we have a valid frame.
void CompleteSavedFrameForTesting();
@@ -114,14 +113,12 @@ class VIZ_SERVICE_EXPORT SurfaceSavedFrame {
// Queues copy requests by creating a copy of the CompositorFrame as specified
// in ScopedCleanSurface.
- void CopyUsingCleanFrame(Surface* surface,
- std::unique_ptr<CopyOutputRequest> root_request);
+ void CopyUsingCleanFrame(Surface* surface);
// Queues copy requests from the original CompositorFrame. This mode is used
// when the frame produced by the renderer already has independent render
// passes for each shared element.
- void CopyUsingOriginalFrame(Surface* surface,
- std::unique_ptr<CopyOutputRequest> root_request);
+ void CopyUsingOriginalFrame(Surface* surface);
std::unique_ptr<CopyOutputRequest> CreateCopyRequestIfNeeded(
const CompositorRenderPass& render_pass,
@@ -177,6 +174,9 @@ class VIZ_SERVICE_EXPORT SurfaceSavedFrame {
// whether the SurfaceSavedFrame is "valid".
size_t valid_result_count_ = 0;
+ // Tracks whether the root render pass should be copied.
+ bool copy_root_render_pass_ = true;
+
absl::optional<ScopedCleanSurface> clean_surface_;
base::WeakPtrFactory<SurfaceSavedFrame> weak_factory_{this};
diff --git a/chromium/components/viz/service/surfaces/surface_saved_frame_storage.cc b/chromium/components/viz/service/surfaces/surface_saved_frame_storage.cc
index 612c9f0903d..ef603a38a23 100644
--- a/chromium/components/viz/service/surfaces/surface_saved_frame_storage.cc
+++ b/chromium/components/viz/service/surfaces/surface_saved_frame_storage.cc
@@ -23,15 +23,15 @@ constexpr base::TimeDelta kExpiryTime = base::Seconds(5);
} // namespace
-SurfaceSavedFrameStorage::SurfaceSavedFrameStorage(Surface* surface)
- : surface_(surface) {}
-
+SurfaceSavedFrameStorage::SurfaceSavedFrameStorage() = default;
SurfaceSavedFrameStorage::~SurfaceSavedFrameStorage() = default;
void SurfaceSavedFrameStorage::ProcessSaveDirective(
const CompositorFrameTransitionDirective& directive,
SurfaceSavedFrame::TransitionDirectiveCompleteCallback
directive_finished_callback) {
+ DCHECK(has_active_surface());
+
// Create a new saved frame, destroying the old one if it existed.
// TODO(vmpstr): This may need to change if the directive refers to a local
// subframe (RP) of the compositor frame. However, as of now, the save
diff --git a/chromium/components/viz/service/surfaces/surface_saved_frame_storage.h b/chromium/components/viz/service/surfaces/surface_saved_frame_storage.h
index e635f09f50c..75e2fc3e473 100644
--- a/chromium/components/viz/service/surfaces/surface_saved_frame_storage.h
+++ b/chromium/components/viz/service/surfaces/surface_saved_frame_storage.h
@@ -23,10 +23,7 @@ class Surface;
// also responsible for expiring saved frames after a set timeout.
class VIZ_SERVICE_EXPORT SurfaceSavedFrameStorage {
public:
- // Each Surface has its own storage, and the storage has a backpointer to the
- // surface in order to append copy output requests to the active frame.
- explicit SurfaceSavedFrameStorage(Surface* surface);
-
+ SurfaceSavedFrameStorage();
~SurfaceSavedFrameStorage();
// Processes the save directive from a compositor frame. This interfaces with
@@ -46,11 +43,14 @@ class VIZ_SERVICE_EXPORT SurfaceSavedFrameStorage {
void ExpireForTesting();
void CompleteForTesting();
+ bool has_active_surface() const { return !!surface_; }
+ void set_active_surface(Surface* surface) { surface_ = surface; }
+
private:
// This expires the saved frame, if any.
void ExpireSavedFrame();
- const raw_ptr<Surface> surface_;
+ raw_ptr<Surface> surface_ = nullptr;
base::CancelableOnceClosure expiry_closure_;
diff --git a/chromium/components/viz/service/surfaces/surface_saved_frame_unittest.cc b/chromium/components/viz/service/surfaces/surface_saved_frame_unittest.cc
index a27ff282444..cf9b8d57c04 100644
--- a/chromium/components/viz/service/surfaces/surface_saved_frame_unittest.cc
+++ b/chromium/components/viz/service/surfaces/surface_saved_frame_unittest.cc
@@ -130,7 +130,7 @@ TEST_F(SurfaceSavedFrameTest, OnlyRootSnapshotNoSharedPass) {
const uint32_t sequence_id = 2u;
CompositorFrameTransitionDirective directive(
- sequence_id, CompositorFrameTransitionDirective::Type::kSave,
+ sequence_id, CompositorFrameTransitionDirective::Type::kSave, false,
CompositorFrameTransitionDirective::Effect::kCoverDown);
auto saved_frame = CreateSavedFrame(directive);
saved_frame->RequestCopyOfOutput(GetSurface());
@@ -152,7 +152,7 @@ TEST_F(SurfaceSavedFrameTest, OnlyRootSnapshotNullSharedPass) {
const uint32_t sequence_id = 2u;
CompositorFrameTransitionDirective directive(
- sequence_id, CompositorFrameTransitionDirective::Type::kSave,
+ sequence_id, CompositorFrameTransitionDirective::Type::kSave, false,
CompositorFrameTransitionDirective::Effect::kCoverDown,
CompositorFrameTransitionDirective::TransitionConfig(),
CreateSharedElements({CompositorRenderPassId(0u)}));
@@ -192,7 +192,7 @@ TEST_F(SurfaceSavedFrameTest, RemoveSharedElementQuadOnly) {
const uint32_t sequence_id = 2u;
CompositorFrameTransitionDirective directive(
- sequence_id, CompositorFrameTransitionDirective::Type::kSave,
+ sequence_id, CompositorFrameTransitionDirective::Type::kSave, false,
CompositorFrameTransitionDirective::Effect::kCoverDown,
CompositorFrameTransitionDirective::TransitionConfig(),
CreateSharedElements({shared_pass_id}));
@@ -265,7 +265,7 @@ TEST_F(SurfaceSavedFrameTest, SharedElementNestedInNonSharedElementPass) {
const uint32_t sequence_id = 2u;
CompositorFrameTransitionDirective directive(
- sequence_id, CompositorFrameTransitionDirective::Type::kSave,
+ sequence_id, CompositorFrameTransitionDirective::Type::kSave, false,
CompositorFrameTransitionDirective::Effect::kCoverDown,
CompositorFrameTransitionDirective::TransitionConfig(),
CreateSharedElements({shared_pass_id}));
@@ -345,7 +345,7 @@ TEST_F(SurfaceSavedFrameTest, SharedElementNestedInSharedElementPass) {
const uint32_t sequence_id = 2u;
CompositorFrameTransitionDirective directive(
- sequence_id, CompositorFrameTransitionDirective::Type::kSave,
+ sequence_id, CompositorFrameTransitionDirective::Type::kSave, false,
CompositorFrameTransitionDirective::Effect::kCoverDown,
CompositorFrameTransitionDirective::TransitionConfig(),
CreateSharedElements({child_shared_pass_id, parent_shared_pass->id}));
diff --git a/chromium/components/viz/service/surfaces/surface_unittest.cc b/chromium/components/viz/service/surfaces/surface_unittest.cc
index 91a237fd945..09acc0fefe2 100644
--- a/chromium/components/viz/service/surfaces/surface_unittest.cc
+++ b/chromium/components/viz/service/surfaces/surface_unittest.cc
@@ -19,6 +19,8 @@
#include "components/viz/test/compositor_frame_helpers.h"
#include "components/viz/test/fake_external_begin_frame_source.h"
#include "components/viz/test/mock_compositor_frame_sink_client.h"
+#include "components/viz/test/test_surface_id_allocator.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/size.h"
@@ -28,17 +30,25 @@ namespace {
constexpr FrameSinkId kArbitraryFrameSinkId(1, 1);
constexpr bool kIsRoot = true;
-TEST(SurfaceTest, PresentationCallback) {
+class SurfaceTest : public testing::Test {
+ public:
+ SurfaceTest()
+ : frame_sink_manager_(
+ FrameSinkManagerImpl::InitParams(&shared_bitmap_manager_)) {}
+
+ protected:
+ ServerSharedBitmapManager shared_bitmap_manager_;
+ FrameSinkManagerImpl frame_sink_manager_;
+};
+
+TEST_F(SurfaceTest, PresentationCallback) {
constexpr gfx::Size kSurfaceSize(300, 300);
constexpr gfx::Rect kDamageRect(0, 0);
const LocalSurfaceId local_surface_id(6, base::UnguessableToken::Create());
- ServerSharedBitmapManager shared_bitmap_manager;
- FrameSinkManagerImpl frame_sink_manager{
- FrameSinkManagerImpl::InitParams(&shared_bitmap_manager)};
MockCompositorFrameSinkClient client;
auto support = std::make_unique<CompositorFrameSinkSupport>(
- &client, &frame_sink_manager, kArbitraryFrameSinkId, kIsRoot);
+ &client, &frame_sink_manager_, kArbitraryFrameSinkId, kIsRoot);
uint32_t frame_token = 0;
{
CompositorFrame frame =
@@ -67,7 +77,7 @@ TEST(SurfaceTest, PresentationCallback) {
}
}
-TEST(SurfaceTest, SurfaceIds) {
+TEST_F(SurfaceTest, SurfaceIds) {
for (size_t i = 0; i < 3; ++i) {
ParentLocalSurfaceIdAllocator allocator;
allocator.GenerateId();
@@ -87,13 +97,10 @@ void TestCopyResultCallback(bool* called,
// Test that CopyOutputRequests can outlive the current frame and be
// aggregated on the next frame.
-TEST(SurfaceTest, CopyRequestLifetime) {
- ServerSharedBitmapManager shared_bitmap_manager;
- FrameSinkManagerImpl frame_sink_manager{
- FrameSinkManagerImpl::InitParams(&shared_bitmap_manager)};
- SurfaceManager* surface_manager = frame_sink_manager.surface_manager();
+TEST_F(SurfaceTest, CopyRequestLifetime) {
+ SurfaceManager* surface_manager = frame_sink_manager_.surface_manager();
auto support = std::make_unique<CompositorFrameSinkSupport>(
- nullptr, &frame_sink_manager, kArbitraryFrameSinkId, kIsRoot);
+ nullptr, &frame_sink_manager_, kArbitraryFrameSinkId, kIsRoot);
LocalSurfaceId local_surface_id(6, base::UnguessableToken::Create());
SurfaceId surface_id(kArbitraryFrameSinkId, local_surface_id);
@@ -150,5 +157,103 @@ TEST(SurfaceTest, CopyRequestLifetime) {
EXPECT_TRUE(copy_called);
}
+// Verify activate referenced surfaces is correct when there are two surface
+// references to overlapping surface ranges. In particular the two surface
+// ranges are (S1, S1) and (S1, S2). When both S1 and S2 activate active
+// referenced surfaces should include both S1 and S2. See
+// https://crbug.com/1275605 for more context.
+TEST_F(SurfaceTest, ActiveSurfaceReferencesWithOverlappingReferences) {
+ constexpr gfx::Rect output_rect(100, 100);
+ SurfaceManager* surface_manager = frame_sink_manager_.surface_manager();
+
+ auto root_support = std::make_unique<CompositorFrameSinkSupport>(
+ nullptr, &frame_sink_manager_, kArbitraryFrameSinkId,
+ /*is_root=*/true);
+ TestSurfaceIdAllocator root_surface_id(kArbitraryFrameSinkId);
+
+ auto child_support1 = std::make_unique<CompositorFrameSinkSupport>(
+ nullptr, &frame_sink_manager_, FrameSinkId(2, 1), /*is_root=*/false);
+ TestSurfaceIdAllocator child_surface_id1(child_support1->frame_sink_id());
+
+ auto child_support2 = std::make_unique<CompositorFrameSinkSupport>(
+ nullptr, &frame_sink_manager_, FrameSinkId(3, 1), /*is_root=*/false);
+ TestSurfaceIdAllocator child_surface_id2(child_support2->frame_sink_id());
+
+ // Submit a root frame with two SurfaceDrawQuads. The first SurfaceDrawQuad
+ // embeds |child_support1|. The second SurfaceDrawQuad embeds |child_support2|
+ // but has |child_support1| as a fallback which mimics a navigating renderer.
+ // Note that |old_surface_range| and |navigation_surface_range| overlap.
+ SurfaceRange old_surface_range(child_surface_id1, child_surface_id1);
+ SurfaceRange navigation_surface_range(child_surface_id1, child_surface_id2);
+ auto root_render_pass =
+ RenderPassBuilder(CompositorRenderPassId{1}, output_rect)
+ .AddSurfaceQuad(output_rect, old_surface_range)
+ .AddSurfaceQuad(output_rect, navigation_surface_range)
+ .Build();
+
+ {
+ CompositorFrame frame = MakeCompositorFrame(root_render_pass->DeepCopy());
+ EXPECT_THAT(
+ frame.metadata.referenced_surfaces,
+ testing::ElementsAre(old_surface_range, navigation_surface_range));
+
+ root_support->SubmitCompositorFrame(root_surface_id.local_surface_id(),
+ std::move(frame));
+ }
+
+ Surface* root_surface = surface_manager->GetSurfaceForId(root_surface_id);
+ ASSERT_TRUE(root_surface);
+
+ // No active references yet because no child surfaces have been submitted yet.
+ EXPECT_THAT(root_surface->active_referenced_surfaces(), testing::IsEmpty());
+
+ // Submit something to the second child surface and verify it's now included
+ // in active referenced surfaces.
+ child_support2->SubmitCompositorFrame(child_surface_id2.local_surface_id(),
+ MakeDefaultCompositorFrame());
+ EXPECT_TRUE(surface_manager->GetSurfaceForId(child_surface_id2));
+ EXPECT_THAT(root_surface->active_referenced_surfaces(),
+ testing::ElementsAre(child_surface_id2));
+
+ // Submit something to the first child surface and verify both are in active
+ // surface references. Note this order of activation is "backwards" as
+ // normally the |child_surface_id1| would have activated first if the browser
+ // is navigating away from it but if the first renderer is slow to produce
+ // content the order can be reversed.
+ child_support1->SubmitCompositorFrame(child_surface_id1.local_surface_id(),
+ MakeDefaultCompositorFrame());
+ EXPECT_TRUE(surface_manager->GetSurfaceForId(child_surface_id1));
+ EXPECT_THAT(root_surface->active_referenced_surfaces(),
+ testing::ElementsAre(child_surface_id1, child_surface_id2));
+
+ // Resubmit root frame with the same SurfaceDrawQuads and verify active
+ // surface references are unchanged.
+ root_support->SubmitCompositorFrame(
+ root_surface_id.local_surface_id(),
+ MakeCompositorFrame(std::move(root_render_pass)));
+ EXPECT_THAT(root_surface->active_referenced_surfaces(),
+ testing::ElementsAre(child_surface_id1, child_surface_id2));
+
+ // Submit a new root frame without the reference to the first child surface
+ // and verify |child_surface_id1| is no longer part of active referenced
+ // surfaces.
+ {
+ SurfaceRange post_navigation_surface_range(child_surface_id2,
+ child_surface_id2);
+ CompositorFrame frame =
+ CompositorFrameBuilder()
+ .AddRenderPass(
+ RenderPassBuilder(CompositorRenderPassId{1}, output_rect)
+ .AddSurfaceQuad(output_rect, post_navigation_surface_range))
+ .Build();
+
+ root_support->SubmitCompositorFrame(root_surface_id.local_surface_id(),
+ std::move(frame));
+ }
+
+ EXPECT_THAT(root_surface->active_referenced_surfaces(),
+ testing::ElementsAre(child_surface_id2));
+}
+
} // namespace
} // namespace viz
diff --git a/chromium/components/viz/service/transitions/surface_animation_manager.cc b/chromium/components/viz/service/transitions/surface_animation_manager.cc
index 30749e30d7b..e4a01b14249 100644
--- a/chromium/components/viz/service/transitions/surface_animation_manager.cc
+++ b/chromium/components/viz/service/transitions/surface_animation_manager.cc
@@ -292,6 +292,22 @@ std::unique_ptr<gfx::AnimationCurve> CreateTransformCurve(
} // namespace
+class SurfaceAnimationManager::StorageWithSurface {
+ public:
+ StorageWithSurface(SurfaceSavedFrameStorage* storage, Surface* surface)
+ : storage_(storage) {
+ DCHECK(!storage_->has_active_surface());
+ storage_->set_active_surface(surface);
+ }
+
+ ~StorageWithSurface() { storage_->set_active_surface(nullptr); }
+
+ SurfaceSavedFrameStorage* operator->() { return storage_; }
+
+ private:
+ raw_ptr<SurfaceSavedFrameStorage> storage_;
+};
+
SurfaceAnimationManager::SurfaceAnimationManager(
SharedBitmapManager* shared_bitmap_manager)
: animation_slowdown_factor_(
@@ -307,8 +323,9 @@ void SurfaceAnimationManager::SetDirectiveFinishedCallback(
bool SurfaceAnimationManager::ProcessTransitionDirectives(
const std::vector<CompositorFrameTransitionDirective>& directives,
- SurfaceSavedFrameStorage* storage) {
+ Surface* active_surface) {
bool started_animation = false;
+ StorageWithSurface storage(&surface_saved_frame_storage_, active_surface);
for (auto& directive : directives) {
// Don't process directives with sequence ids smaller than or equal to the
// last seen one. It is possible that we call this with the same frame
@@ -331,7 +348,7 @@ bool SurfaceAnimationManager::ProcessTransitionDirectives(
handled = ProcessAnimateRendererDirective(directive, storage);
break;
case CompositorFrameTransitionDirective::Type::kRelease:
- handled = ProcessReleaseDirective(directive, storage);
+ handled = ProcessReleaseDirective();
break;
}
@@ -347,7 +364,14 @@ bool SurfaceAnimationManager::ProcessTransitionDirectives(
bool SurfaceAnimationManager::ProcessSaveDirective(
const CompositorFrameTransitionDirective& directive,
- SurfaceSavedFrameStorage* storage) {
+ StorageWithSurface& storage) {
+ // We can only have one saved frame. It is the job of the client to ensure the
+ // correct API usage. So if we are receiving a save directive while we already
+ // have a saved frame, release it first. That ensures that any subsequent
+ // animate directives which presumably rely on this save directive will
+ // succeed.
+ ProcessReleaseDirective();
+
// We need to be in the idle state in order to save.
if (state_ != State::kIdle)
return false;
@@ -357,7 +381,7 @@ bool SurfaceAnimationManager::ProcessSaveDirective(
bool SurfaceAnimationManager::ProcessAnimateDirective(
const CompositorFrameTransitionDirective& directive,
- SurfaceSavedFrameStorage* storage) {
+ StorageWithSurface& storage) {
// We can only begin an animate if we are currently idle.
if (state_ != State::kIdle)
return false;
@@ -395,7 +419,7 @@ bool SurfaceAnimationManager::ProcessAnimateDirective(
bool SurfaceAnimationManager::ProcessAnimateRendererDirective(
const CompositorFrameTransitionDirective& directive,
- SurfaceSavedFrameStorage* storage) {
+ StorageWithSurface& storage) {
// We can only begin an animate if we are currently idle. The renderer sends
// this in response to a notification of the capture completing successfully.
if (state_ != State::kIdle)
@@ -416,9 +440,7 @@ bool SurfaceAnimationManager::ProcessAnimateRendererDirective(
return true;
}
-bool SurfaceAnimationManager::ProcessReleaseDirective(
- const CompositorFrameTransitionDirective& directive,
- SurfaceSavedFrameStorage* storage) {
+bool SurfaceAnimationManager::ProcessReleaseDirective() {
if (state_ != State::kAnimatingRenderer)
return false;
@@ -1187,22 +1209,39 @@ bool SurfaceAnimationManager::FilterSharedElementsWithRenderPassOrResource(
shared_element_quad.resource_id);
if (texture_it != saved_textures_->element_id_to_resource.end()) {
- resource_list->push_back(saved_textures_->element_id_to_resource.at(
- shared_element_quad.resource_id));
+ const auto& transferable_resource = texture_it->second;
+ resource_list->push_back(transferable_resource);
// GPU textures are flipped but software bitmaps are not.
- bool y_flipped = !saved_textures_->root.resource.is_software;
+ bool y_flipped = !transferable_resource.is_software;
ReplaceSharedElementWithTexture(&copy_pass, shared_element_quad,
y_flipped, resource_list->back().id);
return true;
}
}
+#if DCHECK_IS_ON()
+ LOG(ERROR) << "Content not found for shared element: "
+ << shared_element_quad.resource_id.ToString();
+ LOG(ERROR) << "Known shared element ids:";
+ for (const auto& [shared_resource_id, render_pass] : *element_id_to_pass) {
+ LOG(ERROR) << " " << shared_resource_id.ToString()
+ << " -> RenderPassId: " << render_pass->id.GetUnsafeValue();
+ }
+
+ if (saved_textures_) {
+ LOG(ERROR) << "Known saved textures:";
+ for (const auto& [shared_resource_id, transferable_resource] :
+ saved_textures_->element_id_to_resource) {
+ LOG(ERROR) << " " << shared_resource_id.ToString();
+ }
+ }
+
// The DCHECK below is for debugging in dev builds. This can happen in
// production code because of a compromised renderer.
- LOG(ERROR) << "Content not found for shared element : "
- << shared_element_quad.resource_id.ToString();
NOTREACHED();
+#endif
+
return true;
}
@@ -1260,6 +1299,11 @@ void SurfaceAnimationManager::ReplaceSharedElementResources(Surface* surface) {
surface->SetInterpolatedFrame(std::move(resolved_frame));
}
+SurfaceSavedFrameStorage*
+SurfaceAnimationManager::GetSurfaceSavedFrameStorageForTesting() {
+ return &surface_saved_frame_storage_;
+}
+
base::TimeDelta SurfaceAnimationManager::ApplySlowdownFactor(
base::TimeDelta original) const {
return original * animation_slowdown_factor_;
diff --git a/chromium/components/viz/service/transitions/surface_animation_manager.h b/chromium/components/viz/service/transitions/surface_animation_manager.h
index a67836a8a1a..85e2ff29991 100644
--- a/chromium/components/viz/service/transitions/surface_animation_manager.h
+++ b/chromium/components/viz/service/transitions/surface_animation_manager.h
@@ -18,6 +18,7 @@
#include "components/viz/common/resources/resource_id.h"
#include "components/viz/service/display/shared_bitmap_manager.h"
#include "components/viz/service/surfaces/surface_saved_frame.h"
+#include "components/viz/service/surfaces/surface_saved_frame_storage.h"
#include "components/viz/service/transitions/transferable_resource_tracker.h"
#include "components/viz/service/viz_service_export.h"
#include "ui/gfx/animation/keyframe/animation_curve.h"
@@ -28,7 +29,6 @@ namespace viz {
class Surface;
class CompositorFrame;
-class SurfaceSavedFrameStorage;
struct ReturnedResource;
struct TransferableResource;
@@ -58,7 +58,7 @@ class VIZ_SERVICE_EXPORT SurfaceAnimationManager {
// normally not do so in the middle of the animation.
bool ProcessTransitionDirectives(
const std::vector<CompositorFrameTransitionDirective>& directives,
- SurfaceSavedFrameStorage* storage);
+ Surface* active_surface);
// Returns true if this manager needs to observe begin frames to advance
// animations.
@@ -82,11 +82,15 @@ class VIZ_SERVICE_EXPORT SurfaceAnimationManager {
// necessary.
void ReplaceSharedElementResources(Surface* surface);
+ SurfaceSavedFrameStorage* GetSurfaceSavedFrameStorageForTesting();
+
private:
friend class SurfaceAnimationManagerTest;
FRIEND_TEST_ALL_PREFIXES(SurfaceAnimationManagerTest, CustomRootConfig);
FRIEND_TEST_ALL_PREFIXES(SurfaceAnimationManagerTest, CustomSharedConfig);
+ class StorageWithSurface;
+
struct RenderPassDrawData {
RenderPassDrawData();
RenderPassDrawData(RenderPassDrawData&&);
@@ -104,17 +108,15 @@ class VIZ_SERVICE_EXPORT SurfaceAnimationManager {
// Helpers to process specific directives.
bool ProcessSaveDirective(const CompositorFrameTransitionDirective& directive,
- SurfaceSavedFrameStorage* storage);
+ StorageWithSurface& storage);
// Returns true if the animation has started.
bool ProcessAnimateDirective(
const CompositorFrameTransitionDirective& directive,
- SurfaceSavedFrameStorage* storage);
+ StorageWithSurface& storage);
bool ProcessAnimateRendererDirective(
const CompositorFrameTransitionDirective& directive,
- SurfaceSavedFrameStorage* storage);
- bool ProcessReleaseDirective(
- const CompositorFrameTransitionDirective& directive,
- SurfaceSavedFrameStorage* storage);
+ StorageWithSurface& storage);
+ bool ProcessReleaseDirective();
// Finishes the animation and advance state to kLastFrame if it's time to do
// so. This call is only valid if state is kAnimating.
@@ -281,6 +283,10 @@ class VIZ_SERVICE_EXPORT SurfaceAnimationManager {
gfx::TransformOperations combined_transform_;
};
+ // This is responsible for keeping track of the saved frame, accumulating copy
+ // output results.
+ SurfaceSavedFrameStorage surface_saved_frame_storage_;
+
// This is the root animation state.
RootAnimationState root_animation_;
diff --git a/chromium/components/viz/service/transitions/surface_animation_manager_unittest.cc b/chromium/components/viz/service/transitions/surface_animation_manager_unittest.cc
index 386e1b95dc7..3e8c357fc6e 100644
--- a/chromium/components/viz/service/transitions/surface_animation_manager_unittest.cc
+++ b/chromium/components/viz/service/transitions/surface_animation_manager_unittest.cc
@@ -41,7 +41,8 @@ std::vector<CompositorFrameTransitionDirective> CreateSaveDirectiveAsVector(
CompositorFrameTransitionDirective::Effect::kCoverDown) {
std::vector<CompositorFrameTransitionDirective> result;
result.emplace_back(sequence_id,
- CompositorFrameTransitionDirective::Type::kSave, effect);
+ CompositorFrameTransitionDirective::Type::kSave, false,
+ effect);
return result;
}
@@ -125,8 +126,7 @@ class SurfaceAnimationManagerTest : public testing::Test {
}
void TearDown() override {
- if (storage())
- storage()->ExpireForTesting();
+ storage()->ExpireForTesting();
manager_.reset();
}
@@ -135,15 +135,15 @@ class SurfaceAnimationManagerTest : public testing::Test {
return current_time_;
}
- Surface* surface() const {
+ Surface* surface() {
Surface* surface = surface_manager_->GetSurfaceForId(surface_id_);
// Can't ASSERT in a non-void function, so just CHECK instead.
CHECK(surface);
return surface;
}
- SurfaceSavedFrameStorage* storage() const {
- return surface()->GetSurfaceSavedFrameStorage();
+ SurfaceSavedFrameStorage* storage() {
+ return manager().GetSurfaceSavedFrameStorageForTesting();
}
void ValidateStartState(CompositorFrameTransitionDirective::Effect effect) {
@@ -280,7 +280,7 @@ class SurfaceAnimationManagerTest : public testing::Test {
TEST_F(SurfaceAnimationManagerTest, DefaultState) {
EXPECT_FALSE(manager().NeedsBeginFrame());
- manager().ProcessTransitionDirectives({}, storage());
+ manager().ProcessTransitionDirectives({}, surface());
EXPECT_FALSE(manager().NeedsBeginFrame());
}
@@ -289,12 +289,12 @@ TEST_F(SurfaceAnimationManagerTest, SaveAnimateNeedsBeginFrame) {
EXPECT_FALSE(manager().NeedsBeginFrame());
manager().ProcessTransitionDirectives(CreateSaveDirectiveAsVector(1),
- storage());
+ surface());
storage()->CompleteForTesting();
manager().ProcessTransitionDirectives(CreateAnimateDirectiveAsVector(2),
- storage());
+ surface());
// Tick curves to set start time.
manager().UpdateFrameTime(AdvanceTime(base::TimeDelta()));
@@ -320,7 +320,7 @@ TEST_F(SurfaceAnimationManagerTest, AnimateWithoutSaveIsNoop) {
EXPECT_FALSE(manager().NeedsBeginFrame());
manager().ProcessTransitionDirectives(CreateAnimateDirectiveAsVector(1),
- storage());
+ surface());
EXPECT_FALSE(manager().NeedsBeginFrame());
}
@@ -328,14 +328,14 @@ TEST_F(SurfaceAnimationManagerTest, SaveTimesOut) {
EXPECT_FALSE(manager().NeedsBeginFrame());
manager().ProcessTransitionDirectives(CreateSaveDirectiveAsVector(1),
- storage());
+ surface());
EXPECT_FALSE(manager().NeedsBeginFrame());
storage()->ExpireForTesting();
AdvanceTime(base::Seconds(6));
manager().ProcessTransitionDirectives(CreateAnimateDirectiveAsVector(2),
- storage());
+ surface());
EXPECT_FALSE(manager().NeedsBeginFrame());
}
@@ -345,7 +345,7 @@ TEST_F(SurfaceAnimationManagerTest, RepeatedSavesAreOk) {
uint32_t sequence_id = 1;
for (int i = 0; i < 200; ++i) {
manager().ProcessTransitionDirectives(
- CreateSaveDirectiveAsVector(sequence_id), storage());
+ CreateSaveDirectiveAsVector(sequence_id), surface());
EXPECT_FALSE(manager().NeedsBeginFrame());
@@ -356,7 +356,7 @@ TEST_F(SurfaceAnimationManagerTest, RepeatedSavesAreOk) {
storage()->CompleteForTesting();
manager().ProcessTransitionDirectives(
- CreateAnimateDirectiveAsVector(sequence_id), storage());
+ CreateAnimateDirectiveAsVector(sequence_id), surface());
// Tick curves to set start time.
manager().UpdateFrameTime(AdvanceTime(base::TimeDelta()));
@@ -395,12 +395,12 @@ TEST_F(SurfaceAnimationManagerTest, CheckStartEndStates) {
uint32_t sequence_id = 1;
for (auto effect : effects) {
manager().ProcessTransitionDirectives(
- CreateSaveDirectiveAsVector(sequence_id++, effect), storage());
+ CreateSaveDirectiveAsVector(sequence_id++, effect), surface());
storage()->CompleteForTesting();
manager().ProcessTransitionDirectives(
- CreateAnimateDirectiveAsVector(sequence_id++), storage());
+ CreateAnimateDirectiveAsVector(sequence_id++), surface());
// Tick curves to set start time.
manager().UpdateFrameTime(AdvanceTime(base::TimeDelta()));
@@ -435,14 +435,14 @@ TEST_F(SurfaceAnimationManagerTest, ConfigWithAllZeroDurations) {
CompositorFrameTransitionDirective::TransitionConfig zero_config;
zero_config.duration = zero_config.delay = base::TimeDelta();
CompositorFrameTransitionDirective save(
- 1, CompositorFrameTransitionDirective::Type::kSave,
+ 1, CompositorFrameTransitionDirective::Type::kSave, false,
CompositorFrameTransitionDirective::Effect::kCoverDown,
/*root_config=*/zero_config,
/*shared_elements=*/
CreateSharedElements(frame.render_pass_list, {zero_config}));
CompositorFrameTransitionDirective animate(
- 2, CompositorFrameTransitionDirective::Type::kAnimate,
+ 2, CompositorFrameTransitionDirective::Type::kAnimate, false,
CompositorFrameTransitionDirective::Effect::kNone,
/*root_config=*/zero_config,
/*shared_elements=*/
@@ -451,11 +451,11 @@ TEST_F(SurfaceAnimationManagerTest, ConfigWithAllZeroDurations) {
support_->SubmitCompositorFrame(surface_id_.local_surface_id(),
std::move(frame));
- ASSERT_FALSE(manager().ProcessTransitionDirectives({save}, storage()));
+ ASSERT_FALSE(manager().ProcessTransitionDirectives({save}, surface()));
storage()->CompleteForTesting();
- ASSERT_TRUE(manager().ProcessTransitionDirectives({animate}, storage()));
+ ASSERT_TRUE(manager().ProcessTransitionDirectives({animate}, surface()));
// We jump directly to the last frame but we should need a BeginFrame to tick
// the last frame.
@@ -476,20 +476,20 @@ TEST_F(SurfaceAnimationManagerTest, CustomRootConfig) {
root_config.delay = base::Seconds(1);
CompositorFrameTransitionDirective save(
- 1, CompositorFrameTransitionDirective::Type::kSave,
+ 1, CompositorFrameTransitionDirective::Type::kSave, false,
CompositorFrameTransitionDirective::Effect::kExplode,
/*root_config=*/root_config,
/*shared_elements=*/{});
CompositorFrameTransitionDirective animate(
- 2, CompositorFrameTransitionDirective::Type::kAnimate,
+ 2, CompositorFrameTransitionDirective::Type::kAnimate, false,
CompositorFrameTransitionDirective::Effect::kNone,
/*root_config=*/root_config,
/*shared_elements=*/{});
- ASSERT_FALSE(manager().ProcessTransitionDirectives({save}, storage()));
+ ASSERT_FALSE(manager().ProcessTransitionDirectives({save}, surface()));
storage()->CompleteForTesting();
- ASSERT_TRUE(manager().ProcessTransitionDirectives({animate}, storage()));
+ ASSERT_TRUE(manager().ProcessTransitionDirectives({animate}, surface()));
// Need the first frame which starts the animation.
EXPECT_TRUE(manager().NeedsBeginFrame());
@@ -574,7 +574,7 @@ TEST_F(SurfaceAnimationManagerTest, CustomSharedConfig) {
shared_config.delay = base::Seconds(1);
CompositorFrameTransitionDirective save(
- 1, CompositorFrameTransitionDirective::Type::kSave,
+ 1, CompositorFrameTransitionDirective::Type::kSave, false,
CompositorFrameTransitionDirective::Effect::kNone,
/*root_config=*/zero_config,
/*shared_elements=*/
@@ -582,7 +582,7 @@ TEST_F(SurfaceAnimationManagerTest, CustomSharedConfig) {
support_->SubmitCompositorFrame(surface_id_.local_surface_id(),
std::move(old_frame));
- ASSERT_FALSE(manager().ProcessTransitionDirectives({save}, storage()));
+ ASSERT_FALSE(manager().ProcessTransitionDirectives({save}, surface()));
// Dispatch copy request results. We're not using the test function here to
// ensure valid result for shared elements.
@@ -605,14 +605,14 @@ TEST_F(SurfaceAnimationManagerTest, CustomSharedConfig) {
new_transform, new_opacity);
CompositorFrameTransitionDirective animate(
- 2, CompositorFrameTransitionDirective::Type::kAnimate,
+ 2, CompositorFrameTransitionDirective::Type::kAnimate, false,
CompositorFrameTransitionDirective::Effect::kNone,
/*root_config=*/zero_config,
/*shared_elements=*/
CreateSharedElements(new_frame.render_pass_list, {shared_config}));
support_->SubmitCompositorFrame(surface_id_.local_surface_id(),
std::move(new_frame));
- ASSERT_TRUE(manager().ProcessTransitionDirectives({animate}, storage()));
+ ASSERT_TRUE(manager().ProcessTransitionDirectives({animate}, surface()));
// Need the first frame which starts the animation.
EXPECT_TRUE(manager().NeedsBeginFrame());
diff --git a/chromium/components/viz/viz.gni b/chromium/components/viz/viz.gni
index 24dc56fb880..c2652c0d6fd 100644
--- a/chromium/components/viz/viz.gni
+++ b/chromium/components/viz/viz.gni
@@ -12,7 +12,8 @@ enable_gl_backend_tests = !is_fuchsia
# Controls if GLRenderer related tests should be built and run. Platforms where
# GLRenderer is no longer used (other than Linux) can stop running tests for it.
-enable_gl_renderer_tests = enable_gl_backend_tests && !is_android && !is_win
+enable_gl_renderer_tests =
+ enable_gl_backend_tests && !is_android && !is_win && !is_mac
# TODO(samans): Support more configurations.
# CFI issue: https://crbug.com/967819
diff --git a/chromium/components/web_app_resources/OWNERS b/chromium/components/web_app_resources/OWNERS
new file mode 100644
index 00000000000..ca4823ba387
--- /dev/null
+++ b/chromium/components/web_app_resources/OWNERS
@@ -0,0 +1 @@
+file://chrome/browser/web_applications/OWNERS \ No newline at end of file
diff --git a/chromium/components/web_app_resources/web_app_default_offline.css b/chromium/components/web_app_resources/web_app_default_offline.css
new file mode 100644
index 00000000000..ce3e489962a
--- /dev/null
+++ b/chromium/components/web_app_resources/web_app_default_offline.css
@@ -0,0 +1,31 @@
+/* Copyright 2022 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. */
+
+@media (prefers-color-scheme: light) {
+ body {
+ background-color: var(--customized-background-color);
+ }
+ h2 {
+ color: var(--theme-color);
+ }
+ }
+
+@media (prefers-color-scheme: dark) {
+ body {
+ background-color: var(--dark-mode-background-color);
+ }
+ h2 {
+ color: var(--dark-mode-theme-color);
+ }
+}
+
+h2 {
+ height: 200px;
+ left: 50%;
+ margin-inline-start: -200px;
+ margin-top: -100px;
+ position: fixed;
+ top: 50%;
+ width: 400px;
+}
diff --git a/chromium/components/web_app_resources/web_app_default_offline.html b/chromium/components/web_app_resources/web_app_default_offline.html
new file mode 100644
index 00000000000..e037b8d0f44
--- /dev/null
+++ b/chromium/components/web_app_resources/web_app_default_offline.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<html dir="$i18n{textdirection}" lang="$i18n{language}">
+<head>
+ <meta charset="utf-8">
+ <title>$i18n{title}</title>
+ <link rel="stylesheet" href="../security_interstitials/core/common/resources/interstitial_core.css">
+ <link rel="stylesheet" href="../security_interstitials/core/common/resources/interstitial_common.css">
+ <link rel="stylesheet" href="web_app_default_offline.css">
+ <style>
+ :root {
+ --customized-background-color: $i18n{customized_background_color};
+ --theme-color: $i18n{theme_color};
+ --dark-mode-background-color: $i18n{dark_mode_background_color};
+ --dark-mode-theme-color: $i18n{dark_mode_theme_color};
+ }
+ </style>
+</head>
+ <body style="font-family: $i18n{fontfamily};font-size:$i18n{fontsize}">
+ <img id="icon" src=$i18n{icon_url}>
+ <h1>$i18n{app_short_name}</h1>
+ <h2 id="default-web-app-msg">$i18n{web_app_default_offline_message}</h2>
+ <!--TODO(crbug.com/1285723: Add web app icon.)-->
+ </body>
+</html> \ No newline at end of file
diff --git a/chromium/components/web_cache/browser/web_cache_manager.cc b/chromium/components/web_cache/browser/web_cache_manager.cc
index 3d3b86e7d79..3b7fcf34dcb 100644
--- a/chromium/components/web_cache/browser/web_cache_manager.cc
+++ b/chromium/components/web_cache/browser/web_cache_manager.cc
@@ -12,6 +12,7 @@
#include "base/compiler_specific.h"
#include "base/location.h"
#include "base/metrics/histogram_macros.h"
+#include "base/no_destructor.h"
#include "base/system/sys_info.h"
#include "base/task/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
diff --git a/chromium/components/web_modal/web_contents_modal_dialog_manager_unittest.cc b/chromium/components/web_modal/web_contents_modal_dialog_manager_unittest.cc
index c3a74d02b62..89a8d211774 100644
--- a/chromium/components/web_modal/web_contents_modal_dialog_manager_unittest.cc
+++ b/chromium/components/web_modal/web_contents_modal_dialog_manager_unittest.cc
@@ -117,7 +117,7 @@ class WebContentsModalDialogManagerTest
gfx::NativeWindow MakeFakeDialog() {
// WebContentsModalDialogManager treats the dialog window as an opaque
// type, so creating fake dialog windows using reinterpret_cast is valid.
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
NSWindow* window = reinterpret_cast<NSWindow*>(next_dialog_id++);
return gfx::NativeWindow(window);
#else
diff --git a/chromium/components/web_resource/eula_accepted_notifier.cc b/chromium/components/web_resource/eula_accepted_notifier.cc
index 82015d30d55..a6a8db33cd4 100644
--- a/chromium/components/web_resource/eula_accepted_notifier.cc
+++ b/chromium/components/web_resource/eula_accepted_notifier.cc
@@ -45,7 +45,7 @@ EulaAcceptedNotifier* EulaAcceptedNotifier::Create(PrefService* local_state) {
// First run EULA only exists on ChromeOS, Android and iOS. On ChromeOS, it is
// only shown in official builds.
#if (BUILDFLAG(IS_CHROMEOS_ASH) && BUILDFLAG(GOOGLE_CHROME_BRANDING)) || \
- defined(OS_ANDROID) || defined(OS_IOS)
+ BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
// Tests that use higher-level classes that use EulaAcceptNotifier may not
// have local state or may not register this pref. Return null to indicate not
// needing to check the EULA.
diff --git a/chromium/components/webapk/webapk.proto b/chromium/components/webapk/webapk.proto
index 77a790b6a82..8cb2a0067c8 100644
--- a/chromium/components/webapk/webapk.proto
+++ b/chromium/components/webapk/webapk.proto
@@ -27,7 +27,7 @@ message WebApkResponse {
// from spamming update requests too often.
optional bool relax_updates = 8;
- reserved 3, 4, 5, 7;
+ reserved 3, 4, 5, 7, 9;
}
// Sent as part of request to create or update a WebAPK.
diff --git a/chromium/components/webapps/browser/BUILD.gn b/chromium/components/webapps/browser/BUILD.gn
index 59b38761737..76733d4ad7c 100644
--- a/chromium/components/webapps/browser/BUILD.gn
+++ b/chromium/components/webapps/browser/BUILD.gn
@@ -4,6 +4,15 @@
assert(!is_ios)
+# This source set should contain only types and constants and no dependencies,
+# for use in crosapi type mappings.
+source_set("constants") {
+ sources = [
+ "install_result_code.cc",
+ "install_result_code.h",
+ ]
+}
+
source_set("browser") {
sources = [
"banners/app_banner_manager.cc",
@@ -48,6 +57,8 @@ source_set("browser") {
"//url",
]
+ public_deps = [ ":constants" ]
+
if (is_android) {
sources += [
"android/add_to_homescreen_coordinator.cc",
@@ -86,7 +97,7 @@ source_set("browser") {
"android/webapps_utils.h",
]
- public_deps = [ "android:webapps_jni_headers" ]
+ public_deps += [ "android:webapps_jni_headers" ]
deps += [
"//base",
@@ -135,6 +146,7 @@ source_set("unit_tests") {
testonly = true
sources = [
"banners/app_banner_settings_helper_unittest.cc",
+ "install_result_code_unittest.cc",
"installable/installable_manager_unittest.cc",
"installable/installable_task_queue_unittest.cc",
"pwa_install_path_tracker_unittest.cc",
diff --git a/chromium/components/webapps/browser/android/add_to_homescreen_data_fetcher.h b/chromium/components/webapps/browser/android/add_to_homescreen_data_fetcher.h
index e5031bc1ae0..9eb6e68cf4c 100644
--- a/chromium/components/webapps/browser/android/add_to_homescreen_data_fetcher.h
+++ b/chromium/components/webapps/browser/android/add_to_homescreen_data_fetcher.h
@@ -50,7 +50,7 @@ class AddToHomescreenDataFetcher {
// Initialize the fetcher by requesting the information about the page from
// the renderer process. The initialization is asynchronous and
- // OnDidGetWebApplicationInfo is expected to be called when finished.
+ // OnDidGetWebAppInstallInfo is expected to be called when finished.
// |observer| must outlive AddToHomescreenDataFetcher.
AddToHomescreenDataFetcher(content::WebContents* web_contents,
int data_timeout_ms,
diff --git a/chromium/components/webapps/browser/android/add_to_homescreen_data_fetcher_unittest.cc b/chromium/components/webapps/browser/android/add_to_homescreen_data_fetcher_unittest.cc
index 3bda3494581..801c5b6bac6 100644
--- a/chromium/components/webapps/browser/android/add_to_homescreen_data_fetcher_unittest.cc
+++ b/chromium/components/webapps/browser/android/add_to_homescreen_data_fetcher_unittest.cc
@@ -38,7 +38,7 @@ namespace webapps {
namespace {
-const char* kWebApplicationInfoTitle = "Meta Title";
+const char* kWebAppInstallInfoTitle = "Meta Title";
const char* kDefaultManifestUrl = "https://www.example.com/manifest.json";
const char* kDefaultIconUrl = "https://www.example.com/icon.png";
const char* kDefaultManifestName = "Default Name";
@@ -253,7 +253,7 @@ class AddToHomescreenDataFetcherTest
webapps::mojom::WebPageMetadataPtr web_page_metadata(
webapps::mojom::WebPageMetadata::New());
web_page_metadata->application_name =
- base::ASCIIToUTF16(kWebApplicationInfoTitle);
+ base::ASCIIToUTF16(kWebAppInstallInfoTitle);
fetcher->OnDidGetWebPageMetadata(
mojo::AssociatedRemote<webapps::mojom::WebPageMetadataAgent>(),
@@ -329,7 +329,7 @@ TEST_F(AddToHomescreenDataFetcherTest, EmptyManifest) {
base::HistogramTester histograms;
ObserverWaiter waiter;
std::unique_ptr<AddToHomescreenDataFetcher> fetcher = BuildFetcher(&waiter);
- RunFetcher(fetcher.get(), waiter, kWebApplicationInfoTitle,
+ RunFetcher(fetcher.get(), waiter, kWebAppInstallInfoTitle,
blink::mojom::DisplayMode::kBrowser, false);
CheckHistograms(histograms);
}
@@ -366,7 +366,7 @@ TEST_F(AddToHomescreenDataFetcherTest, ManifestFetchTimesOutPwa) {
base::HistogramTester histograms;
ObserverWaiter waiter;
std::unique_ptr<AddToHomescreenDataFetcher> fetcher = BuildFetcher(&waiter);
- RunFetcher(fetcher.get(), waiter, kWebApplicationInfoTitle,
+ RunFetcher(fetcher.get(), waiter, kWebAppInstallInfoTitle,
blink::mojom::DisplayMode::kBrowser, false);
CheckHistograms(histograms);
@@ -384,7 +384,7 @@ TEST_F(AddToHomescreenDataFetcherTest, ManifestFetchTimesOutNonPwa) {
base::HistogramTester histograms;
ObserverWaiter waiter;
std::unique_ptr<AddToHomescreenDataFetcher> fetcher = BuildFetcher(&waiter);
- RunFetcher(fetcher.get(), waiter, kWebApplicationInfoTitle,
+ RunFetcher(fetcher.get(), waiter, kWebAppInstallInfoTitle,
blink::mojom::DisplayMode::kBrowser, false);
CheckHistograms(histograms);
@@ -401,7 +401,7 @@ TEST_F(AddToHomescreenDataFetcherTest, ManifestFetchTimesOutUnknown) {
base::HistogramTester histograms;
ObserverWaiter waiter;
std::unique_ptr<AddToHomescreenDataFetcher> fetcher = BuildFetcher(&waiter);
- RunFetcher(fetcher.get(), waiter, kWebApplicationInfoTitle,
+ RunFetcher(fetcher.get(), waiter, kWebAppInstallInfoTitle,
blink::mojom::DisplayMode::kBrowser, false);
NavigateAndCommit(GURL("about:blank"));
CheckHistograms(histograms);
@@ -570,7 +570,7 @@ TEST_F(AddToHomescreenDataFetcherTest, ManifestNoNameNoShortName) {
// Test that when the manifest does not provide either Manifest::short_name
// nor Manifest::name that:
// - The page is not WebAPK compatible.
- // - WebApplicationInfo::title is used as the "name".
+ // - WebAppInstallInfo::title is used as the "name".
// - We still use the icons from the manifest.
blink::mojom::ManifestPtr manifest = BuildDefaultManifest();
manifest->name = absl::nullopt;
@@ -580,13 +580,13 @@ TEST_F(AddToHomescreenDataFetcherTest, ManifestNoNameNoShortName) {
SetManifest(std::move(manifest));
ObserverWaiter waiter;
std::unique_ptr<AddToHomescreenDataFetcher> fetcher = BuildFetcher(&waiter);
- RunFetcher(fetcher.get(), waiter, kWebApplicationInfoTitle,
+ RunFetcher(fetcher.get(), waiter, kWebAppInstallInfoTitle,
blink::mojom::DisplayMode::kStandalone, false);
EXPECT_TRUE(base::EqualsASCII(fetcher->shortcut_info().name,
- kWebApplicationInfoTitle));
+ kWebAppInstallInfoTitle));
EXPECT_TRUE(base::EqualsASCII(fetcher->shortcut_info().short_name,
- kWebApplicationInfoTitle));
+ kWebAppInstallInfoTitle));
EXPECT_FALSE(fetcher->primary_icon().drawsNothing());
EXPECT_EQ(fetcher->shortcut_info().best_primary_icon_url,
GURL(kDefaultIconUrl));
diff --git a/chromium/components/webapps/browser/android/app_banner_manager_android.cc b/chromium/components/webapps/browser/android/app_banner_manager_android.cc
index 2ee93fc6922..edef9de4120 100644
--- a/chromium/components/webapps/browser/android/app_banner_manager_android.cc
+++ b/chromium/components/webapps/browser/android/app_banner_manager_android.cc
@@ -25,6 +25,7 @@
#include "components/version_info/version_info.h"
#include "components/webapps/browser/android/add_to_homescreen_coordinator.h"
#include "components/webapps/browser/android/add_to_homescreen_params.h"
+#include "components/webapps/browser/android/bottomsheet/pwa_bottom_sheet_controller.h"
#include "components/webapps/browser/android/features.h"
#include "components/webapps/browser/android/installable/installable_ambient_badge_infobar_delegate.h"
#include "components/webapps/browser/android/shortcut_info.h"
@@ -62,7 +63,7 @@ bool gIgnoreChromeChannelForTesting = false;
AppBannerManagerAndroid::AppBannerManagerAndroid(
content::WebContents* web_contents)
- : AppBannerManager(web_contents), message_controller_(this) {
+ : AppBannerManager(web_contents) {
CreateJavaBannerManager(web_contents);
}
@@ -178,6 +179,7 @@ void AppBannerManagerAndroid::ResetCurrentPageData() {
AppBannerManager::ResetCurrentPageData();
native_app_data_.Reset();
native_app_package_ = "";
+ screenshots_.clear();
}
std::unique_ptr<AddToHomescreenParams>
@@ -280,7 +282,7 @@ void AppBannerManagerAndroid::OnInstallEvent(
TrackUserResponse(USER_RESPONSE_NATIVE_APP_ACCEPTED);
break;
case AddToHomescreenParams::AppType::WEBAPK:
- FALLTHROUGH;
+ [[fallthrough]];
case AddToHomescreenParams::AppType::SHORTCUT:
TrackUserResponse(USER_RESPONSE_WEB_APP_ACCEPTED);
AppBannerSettingsHelper::RecordBannerInstallEvent(
@@ -343,6 +345,13 @@ void AppBannerManagerAndroid::OnInstallEvent(
}
}
+void AppBannerManagerAndroid::OnDidPerformInstallableWebAppCheck(
+ const InstallableData& data) {
+ screenshots_ = data.screenshots;
+
+ AppBannerManager::OnDidPerformInstallableWebAppCheck(data);
+}
+
void AppBannerManagerAndroid::CreateJavaBannerManager(
content::WebContents* web_contents) {
JNIEnv* env = base::android::AttachCurrentThread();
@@ -355,7 +364,7 @@ std::string AppBannerManagerAndroid::ExtractQueryValueForName(
const std::string& name) {
for (net::QueryIterator it(url); !it.IsAtEnd(); it.Advance()) {
if (it.GetKey() == name)
- return it.GetValue();
+ return std::string(it.GetValue());
}
return std::string();
}
@@ -482,7 +491,20 @@ std::u16string AppBannerManagerAndroid::GetAppName() const {
bool AppBannerManagerAndroid::MaybeShowPwaBottomSheetController(
bool expand_sheet,
WebappInstallSource install_source) {
- return false;
+ // Do not show the peeked bottom sheet if it was recently dismissed.
+ if (!expand_sheet && AppBannerSettingsHelper::WasBannerRecentlyBlocked(
+ web_contents(), validated_url_, GetAppIdentifier(),
+ GetCurrentTime())) {
+ return false;
+ }
+
+ auto a2hs_params = CreateAddToHomescreenParams(install_source);
+ return PwaBottomSheetController::MaybeShow(
+ web_contents(), GetAppName(), primary_icon_, has_maskable_primary_icon_,
+ manifest().start_url, screenshots_, manifest().description.value_or(u""),
+ expand_sheet, std::move(a2hs_params),
+ base::BindRepeating(&AppBannerManagerAndroid::OnInstallEvent,
+ AppBannerManagerAndroid::GetAndroidWeakPtr()));
}
void AppBannerManagerAndroid::Install(
diff --git a/chromium/components/webapps/browser/android/app_banner_manager_android.h b/chromium/components/webapps/browser/android/app_banner_manager_android.h
index cef0dc28ce9..61b787059df 100644
--- a/chromium/components/webapps/browser/android/app_banner_manager_android.h
+++ b/chromium/components/webapps/browser/android/app_banner_manager_android.h
@@ -98,9 +98,10 @@ class AppBannerManagerAndroid : public AppBannerManager,
// Returns the appropriate app name based on whether we have a native/web app.
std::u16string GetAppName() const override;
- virtual bool MaybeShowPwaBottomSheetController(
- bool expand_sheet,
- WebappInstallSource install_source);
+ // Returns false if the bottom sheet can't be shown. In that case an
+ // alternative UI should be shown.
+ bool MaybeShowPwaBottomSheetController(bool expand_sheet,
+ WebappInstallSource install_source);
protected:
// AppBannerManager overrides.
@@ -140,6 +141,9 @@ class AppBannerManagerAndroid : public AppBannerManager,
void OnInstallEvent(AddToHomescreenInstaller::Event event,
const AddToHomescreenParams& a2hs_params);
+ void OnDidPerformInstallableWebAppCheck(
+ const InstallableData& result) override;
+
base::WeakPtr<AppBannerManagerAndroid> GetAndroidWeakPtr();
// Java-side object containing data about a native app.
@@ -183,7 +187,7 @@ class AppBannerManagerAndroid : public AppBannerManager,
base::android::ScopedJavaGlobalRef<jobject> java_banner_manager_;
// Message controller for the ambient badge.
- InstallableAmbientBadgeMessageController message_controller_;
+ InstallableAmbientBadgeMessageController message_controller_{this};
// App package name for a native app banner.
std::string native_app_package_;
@@ -191,6 +195,9 @@ class AppBannerManagerAndroid : public AppBannerManager,
// Title to display in the banner for native app.
std::u16string native_app_title_;
+ // The screenshots to show in the install UI.
+ std::vector<SkBitmap> screenshots_;
+
base::WeakPtrFactory<AppBannerManagerAndroid> weak_factory_{this};
};
diff --git a/chromium/components/webapps/browser/android/translations/android_webapps_strings_de.xtb b/chromium/components/webapps/browser/android/translations/android_webapps_strings_de.xtb
index 95e4ecf4ac4..db33b080291 100644
--- a/chromium/components/webapps/browser/android/translations/android_webapps_strings_de.xtb
+++ b/chromium/components/webapps/browser/android/translations/android_webapps_strings_de.xtb
@@ -5,7 +5,7 @@
<translation id="2478076885740497414">App installieren</translation>
<translation id="3789841737615482174">Installieren</translation>
<translation id="4250229828105606438">Screenshot</translation>
-<translation id="4665282149850138822"><ph name="NAME" /> wurde Ihrem Startbildschirm hinzugefügt.</translation>
+<translation id="4665282149850138822"><ph name="NAME" /> wurde deinem Startbildschirm hinzugefügt.</translation>
<translation id="5250483651202458397">Screenshot. Zum Schließen tippen.</translation>
<translation id="6990079615885386641">App aus dem Play Store abrufen: <ph name="APP_ACTION" /></translation>
<translation id="962979164594783469">App installieren</translation>
diff --git a/chromium/components/webapps/browser/android/translations/android_webapps_strings_eu.xtb b/chromium/components/webapps/browser/android/translations/android_webapps_strings_eu.xtb
index 8d5058e309d..1e9219c07d5 100644
--- a/chromium/components/webapps/browser/android/translations/android_webapps_strings_eu.xtb
+++ b/chromium/components/webapps/browser/android/translations/android_webapps_strings_eu.xtb
@@ -7,6 +7,6 @@
<translation id="4250229828105606438">Pantaila-argazkia</translation>
<translation id="4665282149850138822">Hasierako pantailan gehitu da <ph name="NAME" /></translation>
<translation id="5250483651202458397">Pantaila-argazkia. Sakatu ixteko.</translation>
-<translation id="6990079615885386641">Eskuratu aplikazioa Google Play Store dendan: <ph name="APP_ACTION" /></translation>
+<translation id="6990079615885386641">Eskuratu aplikazioa Google Play Store-n: <ph name="APP_ACTION" /></translation>
<translation id="962979164594783469">Instalatu aplikazioa</translation>
</translationbundle> \ No newline at end of file
diff --git a/chromium/components/webapps/browser/android/webapk/webapk_proto_builder.cc b/chromium/components/webapps/browser/android/webapk/webapk_proto_builder.cc
index 269a6d1f854..fca8a8019ff 100644
--- a/chromium/components/webapps/browser/android/webapk/webapk_proto_builder.cc
+++ b/chromium/components/webapps/browser/android/webapk/webapk_proto_builder.cc
@@ -18,7 +18,6 @@
#include "components/webapps/browser/android/webapk/webapk_types.h"
#include "third_party/blink/public/common/manifest/manifest_util.h"
#include "third_party/blink/public/mojom/manifest/manifest.mojom.h"
-#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/android/color_utils_android.h"
#include "ui/gfx/codec/png_codec.h"
@@ -87,19 +86,13 @@ std::string getCurrentAbi() {
#endif
}
-void SetImageData(webapk::Image* image, const SkBitmap& icon) {
- std::vector<unsigned char> png_bytes;
- gfx::PNGCodec::EncodeBGRASkBitmap(icon, false, &png_bytes);
- image->set_image_data(png_bytes.data(), png_bytes.size());
-}
-
} // namespace
std::unique_ptr<std::string> BuildProtoInBackground(
const webapps::ShortcutInfo& shortcut_info,
- const SkBitmap& primary_icon,
+ const std::string& primary_icon_data,
bool is_primary_icon_maskable,
- const SkBitmap& splash_icon,
+ const std::string& splash_icon_data,
const std::string& package_name,
const std::string& version,
std::map<std::string, WebApkIconHasher::Icon> icon_url_to_murmur2_hash,
@@ -173,7 +166,7 @@ std::unique_ptr<std::string> BuildProtoInBackground(
if (shortcut_info.best_primary_icon_url.is_empty()) {
// Update when web manifest is no longer available.
webapk::Image* best_primary_icon_image = web_app_manifest->add_icons();
- SetImageData(best_primary_icon_image, primary_icon);
+ best_primary_icon_image->set_image_data(primary_icon_data);
best_primary_icon_image->add_usages(webapk::Image::PRIMARY_ICON);
if (is_primary_icon_maskable) {
best_primary_icon_image->add_purposes(webapk::Image::MASKABLE);
@@ -181,9 +174,9 @@ std::unique_ptr<std::string> BuildProtoInBackground(
best_primary_icon_image->add_purposes(webapk::Image::ANY);
}
- if (!splash_icon.drawsNothing()) {
+ if (!splash_icon_data.empty()) {
webapk::Image* splash_icon_image = web_app_manifest->add_icons();
- SetImageData(splash_icon_image, splash_icon);
+ splash_icon_image->set_image_data(splash_icon_data);
splash_icon_image->add_usages(webapk::Image::SPLASH_ICON);
if (shortcut_info.is_splash_image_maskable) {
splash_icon_image->add_purposes(webapk::Image::MASKABLE);
@@ -201,7 +194,11 @@ std::unique_ptr<std::string> BuildProtoInBackground(
image->set_hash(it->second.hash);
if (icon_url == shortcut_info.best_primary_icon_url.spec()) {
- SetImageData(image, primary_icon);
+ if (!primary_icon_data.empty()) {
+ image->set_image_data(primary_icon_data);
+ } else {
+ image->set_image_data(it->second.unsafe_data);
+ }
image->add_usages(webapk::Image::PRIMARY_ICON);
if (is_primary_icon_maskable) {
image->add_purposes(webapk::Image::MASKABLE);
@@ -214,8 +211,8 @@ std::unique_ptr<std::string> BuildProtoInBackground(
shortcut_info.best_primary_icon_url) {
// WebAPK updates uses the image data from fetched bitmap; installs use
// the image data from icon_url_to_murmur2_hash.
- if (!splash_icon.drawsNothing()) {
- SetImageData(image, splash_icon);
+ if (!splash_icon_data.empty()) {
+ image->set_image_data(splash_icon_data);
} else {
image->set_image_data(it->second.unsafe_data);
}
@@ -267,9 +264,9 @@ std::unique_ptr<std::string> BuildProtoInBackground(
bool StoreUpdateRequestToFileInBackground(
const base::FilePath& update_request_path,
const webapps::ShortcutInfo& shortcut_info,
- const SkBitmap& primary_icon,
+ const std::string& primary_icon_data,
bool is_primary_icon_maskable,
- const SkBitmap& splash_icon,
+ const std::string& splash_icon_data,
const std::string& package_name,
const std::string& version,
std::map<std::string, WebApkIconHasher::Icon> icon_url_to_murmur2_hash,
@@ -280,10 +277,10 @@ bool StoreUpdateRequestToFileInBackground(
base::BlockingType::MAY_BLOCK);
std::unique_ptr<std::string> proto = BuildProtoInBackground(
- shortcut_info, primary_icon, is_primary_icon_maskable, splash_icon,
- package_name, version, std::move(icon_url_to_murmur2_hash),
- is_manifest_stale, is_app_identity_update_supported,
- std::move(update_reasons));
+ shortcut_info, primary_icon_data, is_primary_icon_maskable,
+ splash_icon_data, package_name, version,
+ std::move(icon_url_to_murmur2_hash), is_manifest_stale,
+ is_app_identity_update_supported, std::move(update_reasons));
// Create directory if it does not exist.
base::CreateDirectory(update_request_path.DirName());
diff --git a/chromium/components/webapps/browser/android/webapk/webapk_proto_builder.h b/chromium/components/webapps/browser/android/webapk/webapk_proto_builder.h
index b30d8aa4187..59643b2fb2c 100644
--- a/chromium/components/webapps/browser/android/webapk/webapk_proto_builder.h
+++ b/chromium/components/webapps/browser/android/webapk/webapk_proto_builder.h
@@ -14,7 +14,6 @@
#include "components/webapps/browser/android/shortcut_info.h"
#include "components/webapps/browser/android/webapk/webapk_icon_hasher.h"
#include "components/webapps/browser/android/webapk/webapk_types.h"
-#include "third_party/skia/include/core/SkBitmap.h"
namespace webapps {
@@ -25,9 +24,9 @@ namespace webapps {
// splash icon URL is unknown.
std::unique_ptr<std::string> BuildProtoInBackground(
const webapps::ShortcutInfo& shortcut_info,
- const SkBitmap& primary_icon,
+ const std::string& primary_icon_data,
bool is_primary_icon_maskable,
- const SkBitmap& splash_icon,
+ const std::string& splash_icon_data,
const std::string& package_name,
const std::string& version,
std::map<std::string, WebApkIconHasher::Icon> icon_url_to_murmur2_hash,
@@ -41,9 +40,9 @@ std::unique_ptr<std::string> BuildProtoInBackground(
bool StoreUpdateRequestToFileInBackground(
const base::FilePath& update_request_path,
const webapps::ShortcutInfo& shortcut_info,
- const SkBitmap& primary_icon,
+ const std::string& primary_icon_data,
bool is_primary_icon_maskable,
- const SkBitmap& splash_icon,
+ const std::string& splash_icon_data,
const std::string& package_name,
const std::string& version,
std::map<std::string, WebApkIconHasher::Icon> icon_url_to_murmur2_hash,
diff --git a/chromium/components/webapps/browser/banners/app_banner_manager.cc b/chromium/components/webapps/browser/banners/app_banner_manager.cc
index 96537be0d3d..a7fb28d8711 100644
--- a/chromium/components/webapps/browser/banners/app_banner_manager.cc
+++ b/chromium/components/webapps/browser/banners/app_banner_manager.cc
@@ -35,6 +35,7 @@
#include "mojo/public/cpp/bindings/remote.h"
#include "services/service_manager/public/cpp/interface_provider.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/common/manifest/manifest_util.h"
#include "third_party/blink/public/mojom/installation/installation.mojom.h"
#include "third_party/blink/public/mojom/manifest/manifest.mojom.h"
@@ -622,17 +623,28 @@ void AppBannerManager::DidFinishNavigation(content::NavigationHandle* handle) {
// only allow the page to enter the cache if we know for sure that no
// installation is needed. Note: this check must happen before calling
// Terminate as it might set the installable_web_app_check_result_ to kNo.
- if (installable_web_app_check_result_ != InstallableWebAppCheckResult::kNo &&
- state_ != State::INACTIVE) {
- content::BackForwardCache::DisableForRenderFrameHost(
- handle->GetPreviousRenderFrameHostId(),
- back_forward_cache::DisabledReason(
- back_forward_cache::DisabledReasonId::kAppBannerManager));
+ if (!base::FeatureList::IsEnabled(
+ blink::features::kBackForwardCacheAppBanner)) {
+ if (installable_web_app_check_result_ !=
+ InstallableWebAppCheckResult::kNo &&
+ state_ != State::INACTIVE) {
+ content::BackForwardCache::DisableForRenderFrameHost(
+ handle->GetPreviousRenderFrameHostId(),
+ back_forward_cache::DisabledReason(
+ back_forward_cache::DisabledReasonId::kAppBannerManager));
+ }
}
- if (state_ != State::COMPLETE && state_ != State::INACTIVE)
- Terminate();
- ResetCurrentPageData();
+ if (base::FeatureList::IsEnabled(
+ blink::features::kBackForwardCacheAppBanner) &&
+ handle->IsServedFromBackForwardCache()) {
+ UpdateState(State::INACTIVE);
+ RequestAppBanner(validated_url_);
+ } else {
+ if (state_ != State::COMPLETE && state_ != State::INACTIVE)
+ Terminate();
+ ResetCurrentPageData();
+ }
}
void AppBannerManager::DidFinishLoad(
@@ -686,7 +698,7 @@ void AppBannerManager::DidUpdateWebManifestURL(
case State::SENDING_EVENT_GOT_EARLY_PROMPT:
case State::PENDING_PROMPT:
Terminate();
- FALLTHROUGH;
+ [[fallthrough]];
case State::COMPLETE:
if (!manifest_url.is_empty()) {
// This call resets has_sufficient_engagement_data_. In order to
diff --git a/chromium/components/webapps/browser/banners/app_banner_settings_helper.cc b/chromium/components/webapps/browser/banners/app_banner_settings_helper.cc
index e62281c8530..4b7313695ef 100644
--- a/chromium/components/webapps/browser/banners/app_banner_settings_helper.cc
+++ b/chromium/components/webapps/browser/banners/app_banner_settings_helper.cc
@@ -17,6 +17,7 @@
#include "base/strings/string_number_conversions.h"
#include "components/content_settings/core/browser/host_content_settings_map.h"
#include "components/content_settings/core/common/content_settings_pattern.h"
+#include "components/content_settings/core/common/content_settings_utils.h"
#include "components/permissions/permissions_client.h"
#include "components/variations/variations_associated_data.h"
#include "components/webapps/browser/banners/app_banner_manager.h"
@@ -75,9 +76,9 @@ std::unique_ptr<base::DictionaryValue> GetOriginAppBannerData(
if (!settings)
return std::make_unique<base::DictionaryValue>();
- std::unique_ptr<base::DictionaryValue> dict =
- base::DictionaryValue::From(settings->GetWebsiteSetting(
- origin_url, origin_url, ContentSettingsType::APP_BANNER, NULL));
+ std::unique_ptr<base::DictionaryValue> dict = base::DictionaryValue::From(
+ content_settings::ToNullableUniquePtrValue(settings->GetWebsiteSetting(
+ origin_url, origin_url, ContentSettingsType::APP_BANNER, nullptr)));
if (!dict)
return std::make_unique<base::DictionaryValue>();
@@ -116,9 +117,9 @@ class AppPrefs {
void Save() {
DCHECK(dict_);
dict_ = nullptr;
- settings_->SetWebsiteSettingDefaultScope(origin_, GURL(),
- ContentSettingsType::APP_BANNER,
- std::move(origin_dict_));
+ settings_->SetWebsiteSettingDefaultScope(
+ origin_, GURL(), ContentSettingsType::APP_BANNER,
+ content_settings::FromNullableUniquePtrValue(std::move(origin_dict_)));
}
private:
@@ -257,7 +258,7 @@ void AppBannerSettingsHelper::ClearHistoryForURLs(
permissions::PermissionsClient::Get()->GetSettingsMap(browser_context);
for (const GURL& origin_url : origin_urls) {
settings->SetWebsiteSettingDefaultScope(
- origin_url, GURL(), ContentSettingsType::APP_BANNER, nullptr);
+ origin_url, GURL(), ContentSettingsType::APP_BANNER, base::Value());
settings->FlushLossyWebsiteSettings();
}
}
diff --git a/chromium/components/webapps/browser/install_result_code.cc b/chromium/components/webapps/browser/install_result_code.cc
new file mode 100644
index 00000000000..57f08e4bc49
--- /dev/null
+++ b/chromium/components/webapps/browser/install_result_code.cc
@@ -0,0 +1,83 @@
+// Copyright 2022 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.
+
+#include "components/webapps/browser/install_result_code.h"
+
+#include <ostream>
+
+namespace webapps {
+
+bool IsSuccess(InstallResultCode code) {
+ // TODO(crbug.com/1296447): enumerate all the constants instead of the default
+ // clause to prevent accidentally implicitly returning false on any newly
+ // added value.
+ switch (code) {
+ case InstallResultCode::kSuccessNewInstall:
+ case InstallResultCode::kSuccessAlreadyInstalled:
+ case InstallResultCode::kSuccessOfflineOnlyInstall:
+ case InstallResultCode::kSuccessOfflineFallbackInstall:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool IsNewInstall(InstallResultCode code) {
+ return IsSuccess(code) && code != InstallResultCode::kSuccessAlreadyInstalled;
+}
+
+std::ostream& operator<<(std::ostream& os, InstallResultCode code) {
+ switch (code) {
+ case InstallResultCode::kSuccessNewInstall:
+ return os << "kSuccessNewInstall";
+ case InstallResultCode::kSuccessAlreadyInstalled:
+ return os << "kSuccessAlreadyInstalled";
+ case InstallResultCode::kGetWebAppInstallInfoFailed:
+ return os << "kGetWebAppInstallInfoFailed";
+ case InstallResultCode::kPreviouslyUninstalled:
+ return os << "kPreviouslyUninstalled";
+ case InstallResultCode::kWebContentsDestroyed:
+ return os << "kWebContentsDestroyed";
+ case InstallResultCode::kInstallTaskDestroyed:
+ return os << "kInstallTaskDestroyed";
+ case InstallResultCode::kWriteDataFailed:
+ return os << "kWriteDataFailed";
+ case InstallResultCode::kUserInstallDeclined:
+ return os << "kUserInstallDeclined";
+ case InstallResultCode::kNotValidManifestForWebApp:
+ return os << "kNotValidManifestForWebApp";
+ case InstallResultCode::kIntentToPlayStore:
+ return os << "kIntentToPlayStore";
+ case InstallResultCode::kWebAppDisabled:
+ return os << "kWebAppDisabled";
+ case InstallResultCode::kInstallURLRedirected:
+ return os << "kInstallURLRedirected";
+ case InstallResultCode::kInstallURLLoadFailed:
+ return os << "kInstallURLLoadFailed";
+ case InstallResultCode::kExpectedAppIdCheckFailed:
+ return os << "kExpectedAppIdCheckFailed";
+ case InstallResultCode::kInstallURLLoadTimeOut:
+ return os << "kInstallURLLoadTimeOut";
+ case InstallResultCode::kFailedPlaceholderUninstall:
+ return os << "kFailedPlaceholderUninstall";
+ case InstallResultCode::kNotInstallable:
+ return os << "kNotInstallable";
+ case InstallResultCode::kApkWebAppInstallFailed:
+ return os << "kApkWebAppInstallFailed";
+ case InstallResultCode::kCancelledOnWebAppProviderShuttingDown:
+ return os << "kCancelledOnWebAppProviderShuttingDown";
+ case InstallResultCode::kWebAppProviderNotReady:
+ return os << "kWebAppProviderNotReady";
+ case InstallResultCode::kSuccessOfflineOnlyInstall:
+ return os << "kSuccessOfflineOnlyInstall";
+ case InstallResultCode::kSuccessOfflineFallbackInstall:
+ return os << "kSuccessOfflineFallbackInstall";
+ case InstallResultCode::kUpdateTaskFailed:
+ return os << "kUpdateTaskFailed";
+ case InstallResultCode::kAppNotInRegistrarAfterCommit:
+ return os << "kAppNotInRegistrarAfterCommit";
+ }
+}
+
+} // namespace webapps
diff --git a/chromium/components/webapps/browser/install_result_code.h b/chromium/components/webapps/browser/install_result_code.h
new file mode 100644
index 00000000000..b721d7dffbd
--- /dev/null
+++ b/chromium/components/webapps/browser/install_result_code.h
@@ -0,0 +1,96 @@
+// Copyright 2022 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.
+
+#ifndef COMPONENTS_WEBAPPS_BROWSER_INSTALL_RESULT_CODE_H_
+#define COMPONENTS_WEBAPPS_BROWSER_INSTALL_RESULT_CODE_H_
+
+#include <iosfwd>
+
+namespace webapps {
+
+// The result of an attempted web app installation, uninstallation or update.
+//
+// This is an enum, instead of a struct with multiple fields (e.g. one field for
+// success or failure, one field for whether action was taken), because we want
+// to track metrics for the overall cross product of the these axes.
+//
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused. Update corresponding enums.xml entry
+// when making changes here.
+enum class InstallResultCode {
+ // Success category:
+ kSuccessNewInstall = 0,
+ kSuccessAlreadyInstalled = 1,
+
+ // Failure category:
+ // An inter-process request to blink renderer failed.
+ kGetWebAppInstallInfoFailed = 3,
+ // A user previously uninstalled the app, user doesn't want to see it again.
+ kPreviouslyUninstalled = 4,
+ // The blink renderer used to install the app was destroyed.
+ kWebContentsDestroyed = 5,
+ // I/O error: Disk output failed.
+ kWriteDataFailed = 6,
+ // A user rejected installation prompt.
+ kUserInstallDeclined = 7,
+ // |require_manifest| was specified but the app had no valid manifest.
+ kNotValidManifestForWebApp = 10,
+ // We have terminated the installation pipeline and intented to the Play
+ // Store, where the user still needs to accept the Play installation prompt to
+ // install.
+ kIntentToPlayStore = 11,
+ // A web app has been disabled by device policy or by other reasons.
+ kWebAppDisabled = 12,
+ // The network request for the install URL was redirected.
+ kInstallURLRedirected = 13,
+ // The network request for the install URL failed.
+ kInstallURLLoadFailed = 14,
+ // The requested app_id check failed: actual resulting app_id doesn't match.
+ kExpectedAppIdCheckFailed = 15,
+ // The network request for the install URL timed out.
+ kInstallURLLoadTimeOut = 16,
+ // Placeholder uninstall fails (in ExternallyManagedAppManager).
+ kFailedPlaceholderUninstall = 17,
+ // Web App is not considered installable, i.e. missing manifest fields, no
+ // service worker, etc.
+ kNotInstallable = 18,
+ // Apk Web App install fails.
+ kApkWebAppInstallFailed = 20,
+ // App managers are shutting down. For example, when user logs out immediately
+ // after login.
+ kCancelledOnWebAppProviderShuttingDown = 21,
+ // The Web Apps system is not ready: registry is not yet opened or already
+ // closed.
+ kWebAppProviderNotReady = 22,
+
+ // Success category for background installs:
+ kSuccessOfflineOnlyInstall = 23,
+ kSuccessOfflineFallbackInstall = 24,
+
+ // Failure category:
+ // The install task was destroyed, most likely due to WebAppInstallManager
+ // shutdown.
+ kInstallTaskDestroyed = 25,
+
+ // Web App update due to manifest change failed.
+ kUpdateTaskFailed = 26,
+
+ // Web App was not present in the registrar after a successful database
+ // commit.
+ kAppNotInRegistrarAfterCommit = 27,
+
+ kMaxValue = kAppNotInRegistrarAfterCommit,
+};
+
+// Checks if InstallResultCode is not a failure.
+bool IsSuccess(InstallResultCode code);
+
+// Checks if InstallResultCode indicates a new app was installed.
+bool IsNewInstall(InstallResultCode code);
+
+std::ostream& operator<<(std::ostream& os, InstallResultCode code);
+
+} // namespace webapps
+
+#endif // COMPONENTS_WEBAPPS_BROWSER_INSTALL_RESULT_CODE_H_
diff --git a/chromium/components/webapps/browser/install_result_code_unittest.cc b/chromium/components/webapps/browser/install_result_code_unittest.cc
new file mode 100644
index 00000000000..ddcbcaa0e5d
--- /dev/null
+++ b/chromium/components/webapps/browser/install_result_code_unittest.cc
@@ -0,0 +1,19 @@
+// Copyright 2022 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.
+
+#include "components/webapps/browser/install_result_code.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace webapps {
+
+TEST(InstallResultCodeTest, IsSuccess) {
+ // TODO(crbug.com/1296447): Test the rest of the constants.
+ EXPECT_TRUE(IsSuccess(InstallResultCode::kSuccessNewInstall));
+ EXPECT_TRUE(IsSuccess(InstallResultCode::kSuccessAlreadyInstalled));
+
+ EXPECT_FALSE(IsSuccess(InstallResultCode::kExpectedAppIdCheckFailed));
+}
+
+} // namespace webapps
diff --git a/chromium/components/webapps/browser/installable/installable_manager.cc b/chromium/components/webapps/browser/installable/installable_manager.cc
index c21ea7e6e42..9e848f6e4a6 100644
--- a/chromium/components/webapps/browser/installable/installable_manager.cc
+++ b/chromium/components/webapps/browser/installable/installable_manager.cc
@@ -37,7 +37,7 @@
#include "third_party/blink/public/mojom/manifest/display_mode.mojom.h"
#include "url/origin.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "components/webapps/browser/android/webapps_icon_utils.h"
#endif
@@ -79,7 +79,7 @@ const int kMinimumPrimaryIconSizeInPx = 144;
const int kMinimumPrimaryAdaptiveLauncherIconSizeInPx = 83;
int GetIdealPrimaryIconSizeInPx() {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
return WebappsIconUtils::GetIdealHomescreenIconSizeInPx();
#else
return kMinimumPrimaryIconSizeInPx;
@@ -87,7 +87,7 @@ int GetIdealPrimaryIconSizeInPx() {
}
int GetMinimumPrimaryIconSizeInPx() {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
return WebappsIconUtils::GetMinimumHomescreenIconSizeInPx();
#else
return kMinimumPrimaryIconSizeInPx;
@@ -95,7 +95,7 @@ int GetMinimumPrimaryIconSizeInPx() {
}
int GetIdealPrimaryAdaptiveLauncherIconSizeInPx() {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
return WebappsIconUtils::GetIdealAdaptiveLauncherIconSizeInPx();
#else
return kMinimumPrimaryAdaptiveLauncherIconSizeInPx;
@@ -103,7 +103,7 @@ int GetIdealPrimaryAdaptiveLauncherIconSizeInPx() {
}
int GetIdealSplashIconSizeInPx() {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
return WebappsIconUtils::GetIdealSplashImageSizeInPx();
#else
return kMinimumPrimaryIconSizeInPx;
@@ -111,7 +111,7 @@ int GetIdealSplashIconSizeInPx() {
}
int GetMinimumSplashIconSizeInPx() {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
return WebappsIconUtils::GetMinimumSplashImageSizeInPx();
#else
return kMinimumPrimaryIconSizeInPx;
@@ -129,7 +129,7 @@ constexpr ImageTypeDetails kSupportedImageTypes[] = {
{".png", "image/png"},
{".svg", "image/svg+xml"},
// TODO(https://crbug.com/466958): Add WebP support for Android.
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
{".webp", "image/webp"},
#endif
};
diff --git a/chromium/components/webapps/browser/installable/installable_manager_unittest.cc b/chromium/components/webapps/browser/installable/installable_manager_unittest.cc
index db574deb407..71658691cca 100644
--- a/chromium/components/webapps/browser/installable/installable_manager_unittest.cc
+++ b/chromium/components/webapps/browser/installable/installable_manager_unittest.cc
@@ -169,7 +169,7 @@ TEST_F(InstallableManagerUnitTest, ManifestSupportsImageWebP) {
manifest->icons[0].type = u"image/webp";
manifest->icons[0].src = GURL("http://example.com/");
// TODO(https://crbug.com/466958): Add WebP support for Android.
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
EXPECT_FALSE(IsManifestValid(*manifest));
EXPECT_EQ(MANIFEST_MISSING_SUITABLE_ICON, GetErrorCode());
#else
@@ -182,7 +182,7 @@ TEST_F(InstallableManagerUnitTest, ManifestSupportsImageWebP) {
manifest->icons[0].type.clear();
manifest->icons[0].src = GURL("http://example.com/icon.wEBp");
// TODO(https://crbug.com/466958): Add WebP support for Android.
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
EXPECT_FALSE(IsManifestValid(*manifest));
EXPECT_EQ(MANIFEST_MISSING_SUITABLE_ICON, GetErrorCode());
#else
diff --git a/chromium/components/webapps/browser/webapps_client.h b/chromium/components/webapps/browser/webapps_client.h
index 95287939adb..1295703e3b8 100644
--- a/chromium/components/webapps/browser/webapps_client.h
+++ b/chromium/components/webapps/browser/webapps_client.h
@@ -50,7 +50,7 @@ class WebappsClient {
virtual AppBannerManager* GetAppBannerManager(
content::WebContents* web_contents) = 0;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
virtual bool IsInstallationInProgress(content::WebContents* web_contents,
const GURL& manifest_url) = 0;
diff --git a/chromium/components/webapps/services/web_app_origin_association/public/mojom/web_app_origin_association_parser.mojom b/chromium/components/webapps/services/web_app_origin_association/public/mojom/web_app_origin_association_parser.mojom
index 816d2992fce..05712ee0f3f 100644
--- a/chromium/components/webapps/services/web_app_origin_association/public/mojom/web_app_origin_association_parser.mojom
+++ b/chromium/components/webapps/services/web_app_origin_association/public/mojom/web_app_origin_association_parser.mojom
@@ -9,7 +9,7 @@ import "url/mojom/url.mojom";
// The WebAppOriginAssociation structure is an internal representation of the
// web app origin association file described in the "PWAs as URL Handlers"
-// explainer: https://github.com/WICG/pwa-url-handler/blob/master/explainer.md
+// explainer: https://github.com/WICG/pwa-url-handler/blob/main/explainer.md
struct WebAppOriginAssociation {
array<AssociatedWebApp> apps;
};
diff --git a/chromium/components/webapps/services/web_app_origin_association/web_app_origin_association_parser.cc b/chromium/components/webapps/services/web_app_origin_association/web_app_origin_association_parser.cc
index 1bd0c327eee..5e231cd0e24 100644
--- a/chromium/components/webapps/services/web_app_origin_association/web_app_origin_association_parser.cc
+++ b/chromium/components/webapps/services/web_app_origin_association/web_app_origin_association_parser.cc
@@ -83,7 +83,7 @@ WebAppOriginAssociationParser::ParseAssociatedWebApps(
return result;
}
- for (const auto& app_item : apps_value->GetList()) {
+ for (const auto& app_item : apps_value->GetListDeprecated()) {
if (!app_item.is_dict()) {
AddErrorInfo("Associated app ignored, type object expected.");
continue;
@@ -169,7 +169,7 @@ WebAppOriginAssociationParser::ParsePaths(const base::Value& app_details_dict,
}
std::vector<std::string> paths;
- for (const auto& path_item : paths_value->GetList()) {
+ for (const auto& path_item : paths_value->GetListDeprecated()) {
if (!path_item.is_string()) {
AddErrorInfo(key + " entry ignored, type string expected.");
continue;
diff --git a/chromium/components/webapps/services/web_app_origin_association/web_app_origin_association_parser.h b/chromium/components/webapps/services/web_app_origin_association/web_app_origin_association_parser.h
index 76e7b9a7b57..161ce966bba 100644
--- a/chromium/components/webapps/services/web_app_origin_association/web_app_origin_association_parser.h
+++ b/chromium/components/webapps/services/web_app_origin_association/web_app_origin_association_parser.h
@@ -19,7 +19,7 @@ namespace webapps {
// Handles the logic of parsing the web app origin association file from a
// string as described in the "PWAs as URL Handlers" explainer:
-// https://github.com/WICG/pwa-url-handler/blob/master/explainer.md
+// https://github.com/WICG/pwa-url-handler/blob/main/explainer.md
class WebAppOriginAssociationParser {
public:
WebAppOriginAssociationParser();
diff --git a/chromium/components/webauthn/android/BUILD.gn b/chromium/components/webauthn/android/BUILD.gn
index 7175fb7fa2a..1d30b8468e5 100644
--- a/chromium/components/webauthn/android/BUILD.gn
+++ b/chromium/components/webauthn/android/BUILD.gn
@@ -6,7 +6,7 @@ import("//build/config/android/rules.gni")
generate_jni("jni_headers") {
sources = [
- "java/src/org/chromium/components/webauthn/Fido2Helper.java",
+ "java/src/org/chromium/components/webauthn/Fido2Api.java",
"java/src/org/chromium/components/webauthn/InternalAuthenticator.java",
]
}
@@ -15,9 +15,10 @@ android_library("java") {
sources = [
"java/src/org/chromium/components/webauthn/AuthenticatorFactory.java",
"java/src/org/chromium/components/webauthn/AuthenticatorImpl.java",
+ "java/src/org/chromium/components/webauthn/Fido2Api.java",
+ "java/src/org/chromium/components/webauthn/Fido2ApiCall.java",
"java/src/org/chromium/components/webauthn/Fido2ApiHandler.java",
"java/src/org/chromium/components/webauthn/Fido2CredentialRequest.java",
- "java/src/org/chromium/components/webauthn/Fido2Helper.java",
"java/src/org/chromium/components/webauthn/FidoErrorResponseCallback.java",
"java/src/org/chromium/components/webauthn/GetAssertionResponseCallback.java",
"java/src/org/chromium/components/webauthn/InternalAuthenticator.java",
@@ -27,7 +28,8 @@ android_library("java") {
]
annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
deps = [
- "$google_play_services_package:google_play_services_fido_java",
+ "$google_play_services_package:google_play_services_base_java",
+ "$google_play_services_package:google_play_services_basement_java",
"$google_play_services_package:google_play_services_tasks_java",
"//base:base_java",
"//base:jni_java",
@@ -62,7 +64,7 @@ android_library("test_support_java") {
source_set("android") {
sources = [
- "fido2helper_native_android.cc",
+ "fido2api_native_android.cc",
"internal_authenticator_android.cc",
"internal_authenticator_android.h",
]
diff --git a/chromium/components/webauthn/android/fido2helper_native_android.cc b/chromium/components/webauthn/android/fido2api_native_android.cc
index 9193fcaa83d..65db0934e86 100644
--- a/chromium/components/webauthn/android/fido2helper_native_android.cc
+++ b/chromium/components/webauthn/android/fido2api_native_android.cc
@@ -6,7 +6,7 @@
#include "base/android/jni_array.h"
#include "components/cbor/reader.h"
-#include "components/webauthn/android/jni_headers/Fido2Helper_jni.h"
+#include "components/webauthn/android/jni_headers/Fido2Api_jni.h"
#include "device/fido/attested_credential_data.h"
#include "device/fido/public_key.h"
#include "third_party/boringssl/src/include/openssl/bytestring.h"
@@ -18,11 +18,11 @@ namespace webauthn {
// Parses a CTAP2 attestation[1] and extracts the
// parts that the browser provides via Javascript API [2]. Called
-// Fido2Helper.java when constructing the makeCredential reply.
+// Fido2Api.java when constructing the makeCredential reply.
//
// [1] https://www.w3.org/TR/webauthn/#attestation-object
// [2] https://w3c.github.io/webauthn/#sctn-public-key-easy
-static jboolean JNI_Fido2Helper_ParseAttestationObject(
+static jboolean JNI_Fido2Api_ParseAttestationObject(
JNIEnv* env,
const base::android::JavaParamRef<jbyteArray>& jattestation_object_bytes,
const base::android::JavaParamRef<jobject>& out_result) {
diff --git a/chromium/components/webauthn/android/internal_authenticator_android.cc b/chromium/components/webauthn/android/internal_authenticator_android.cc
index e4260225d72..955a4693979 100644
--- a/chromium/components/webauthn/android/internal_authenticator_android.cc
+++ b/chromium/components/webauthn/android/internal_authenticator_android.cc
@@ -143,9 +143,13 @@ void InternalAuthenticatorAndroid::InvokeMakeCredentialResponse(
buf_in, buf_size, &response);
}
+ DCHECK_NE(
+ status,
+ static_cast<int>(
+ blink::mojom::AuthenticatorStatus::ERROR_WITH_DOM_EXCEPTION_DETAILS));
std::move(make_credential_response_callback_)
.Run(static_cast<blink::mojom::AuthenticatorStatus>(status),
- std::move(response));
+ std::move(response), /*dom_exception_details=*/nullptr);
}
void InternalAuthenticatorAndroid::InvokeGetAssertionResponse(
@@ -163,9 +167,13 @@ void InternalAuthenticatorAndroid::InvokeGetAssertionResponse(
buf_in, buf_size, &response);
}
+ DCHECK_NE(
+ status,
+ static_cast<int>(
+ blink::mojom::AuthenticatorStatus::ERROR_WITH_DOM_EXCEPTION_DETAILS));
std::move(get_assertion_response_callback_)
.Run(static_cast<blink::mojom::AuthenticatorStatus>(status),
- std::move(response));
+ std::move(response), /*dom_exception_details=*/nullptr);
}
void InternalAuthenticatorAndroid::
diff --git a/chromium/components/webcrypto/algorithms/aes_cbc_unittest.cc b/chromium/components/webcrypto/algorithms/aes_cbc_unittest.cc
index 980f661a061..17763859165 100644
--- a/chromium/components/webcrypto/algorithms/aes_cbc_unittest.cc
+++ b/chromium/components/webcrypto/algorithms/aes_cbc_unittest.cc
@@ -90,13 +90,13 @@ TEST_F(WebCryptoAesCbcTest, ExportKeyUnsupportedFormat) {
// Tests importing of keys (in a variety of formats), errors during import,
// encryption, and decryption, using known answers.
TEST_F(WebCryptoAesCbcTest, KnownAnswerEncryptDecrypt) {
- base::ListValue tests;
- ASSERT_TRUE(ReadJsonTestFileToList("aes_cbc.json", &tests));
+ base::Value tests;
+ ASSERT_TRUE(ReadJsonTestFileAsList("aes_cbc.json", &tests));
- for (size_t test_index = 0; test_index < tests.GetList().size();
+ for (size_t test_index = 0; test_index < tests.GetListDeprecated().size();
++test_index) {
SCOPED_TRACE(test_index);
- const base::Value& test_value = tests.GetList()[test_index];
+ const base::Value& test_value = tests.GetListDeprecated()[test_index];
ASSERT_TRUE(test_value.is_dict());
const base::DictionaryValue* test =
&base::Value::AsDictionaryValue(test_value);
@@ -119,7 +119,7 @@ TEST_F(WebCryptoAesCbcTest, KnownAnswerEncryptDecrypt) {
continue;
// Test encryption.
- if (test->HasKey("plain_text")) {
+ if (test->FindKey("plain_text")) {
std::vector<uint8_t> test_plain_text =
GetBytesFromHexString(test, "plain_text");
@@ -142,7 +142,7 @@ TEST_F(WebCryptoAesCbcTest, KnownAnswerEncryptDecrypt) {
}
// Test decryption.
- if (test->HasKey("cipher_text")) {
+ if (test->FindKey("cipher_text")) {
std::vector<uint8_t> test_cipher_text =
GetBytesFromHexString(test, "cipher_text");
diff --git a/chromium/components/webcrypto/algorithms/aes_ctr_unittest.cc b/chromium/components/webcrypto/algorithms/aes_ctr_unittest.cc
index 54e5eecf1dd..62ec5215576 100644
--- a/chromium/components/webcrypto/algorithms/aes_ctr_unittest.cc
+++ b/chromium/components/webcrypto/algorithms/aes_ctr_unittest.cc
@@ -30,13 +30,13 @@ blink::WebCryptoAlgorithm CreateAesCtrAlgorithm(
class WebCryptoAesCtrTest : public WebCryptoTestBase {};
TEST_F(WebCryptoAesCtrTest, EncryptDecryptKnownAnswer) {
- base::ListValue tests;
- ASSERT_TRUE(ReadJsonTestFileToList("aes_ctr.json", &tests));
+ base::Value tests;
+ ASSERT_TRUE(ReadJsonTestFileAsList("aes_ctr.json", &tests));
- for (size_t test_index = 0; test_index < tests.GetList().size();
+ for (size_t test_index = 0; test_index < tests.GetListDeprecated().size();
++test_index) {
SCOPED_TRACE(test_index);
- const base::Value& test_value = tests.GetList()[test_index];
+ const base::Value& test_value = tests.GetListDeprecated()[test_index];
ASSERT_TRUE(test_value.is_dict());
const base::DictionaryValue* test =
&base::Value::AsDictionaryValue(test_value);
diff --git a/chromium/components/webcrypto/algorithms/aes_gcm_unittest.cc b/chromium/components/webcrypto/algorithms/aes_gcm_unittest.cc
index b98408e6afc..7f645902c84 100644
--- a/chromium/components/webcrypto/algorithms/aes_gcm_unittest.cc
+++ b/chromium/components/webcrypto/algorithms/aes_gcm_unittest.cc
@@ -133,14 +133,14 @@ TEST_F(WebCryptoAesGcmTest, ImportExportJwk) {
// * Test decryption with empty input
// * Test decryption with tag length of 0.
TEST_F(WebCryptoAesGcmTest, SampleSets) {
- base::ListValue tests;
- ASSERT_TRUE(ReadJsonTestFileToList("aes_gcm.json", &tests));
+ base::Value tests;
+ ASSERT_TRUE(ReadJsonTestFileAsList("aes_gcm.json", &tests));
// Note that WebCrypto appends the authentication tag to the ciphertext.
- for (size_t test_index = 0; test_index < tests.GetList().size();
+ for (size_t test_index = 0; test_index < tests.GetListDeprecated().size();
++test_index) {
SCOPED_TRACE(test_index);
- const base::Value& test_value = tests.GetList()[test_index];
+ const base::Value& test_value = tests.GetListDeprecated()[test_index];
ASSERT_TRUE(test_value.is_dict());
const base::DictionaryValue* test =
&base::Value::AsDictionaryValue(test_value);
diff --git a/chromium/components/webcrypto/algorithms/aes_kw_unittest.cc b/chromium/components/webcrypto/algorithms/aes_kw_unittest.cc
index 4c547afa96a..a96303d425e 100644
--- a/chromium/components/webcrypto/algorithms/aes_kw_unittest.cc
+++ b/chromium/components/webcrypto/algorithms/aes_kw_unittest.cc
@@ -162,9 +162,9 @@ TEST_F(WebCryptoAesKwTest, AesKwKeyImport) {
TEST_F(WebCryptoAesKwTest, UnwrapFailures) {
// This test exercises the code path common to all unwrap operations.
- base::ListValue tests;
- ASSERT_TRUE(ReadJsonTestFileToList("aes_kw.json", &tests));
- const base::Value& test_value = tests.GetList()[0];
+ base::Value tests;
+ ASSERT_TRUE(ReadJsonTestFileAsList("aes_kw.json", &tests));
+ const base::Value& test_value = tests.GetListDeprecated()[0];
ASSERT_TRUE(test_value.is_dict());
const base::DictionaryValue* test =
&base::Value::AsDictionaryValue(test_value);
@@ -188,13 +188,13 @@ TEST_F(WebCryptoAesKwTest, UnwrapFailures) {
}
TEST_F(WebCryptoAesKwTest, AesKwRawSymkeyWrapUnwrapKnownAnswer) {
- base::ListValue tests;
- ASSERT_TRUE(ReadJsonTestFileToList("aes_kw.json", &tests));
+ base::Value tests;
+ ASSERT_TRUE(ReadJsonTestFileAsList("aes_kw.json", &tests));
- for (size_t test_index = 0; test_index < tests.GetList().size();
+ for (size_t test_index = 0; test_index < tests.GetListDeprecated().size();
++test_index) {
SCOPED_TRACE(test_index);
- const base::Value& test_value = tests.GetList()[test_index];
+ const base::Value& test_value = tests.GetListDeprecated()[test_index];
ASSERT_TRUE(test_value.is_dict());
const base::DictionaryValue* test =
&base::Value::AsDictionaryValue(test_value);
@@ -250,10 +250,10 @@ TEST_F(WebCryptoAesKwTest, AesKwRawSymkeyWrapUnwrapKnownAnswer) {
// Unwrap a HMAC key using AES-KW, and then try doing a sign/verify with the
// unwrapped key
TEST_F(WebCryptoAesKwTest, AesKwRawSymkeyUnwrapSignVerifyHmac) {
- base::ListValue tests;
- ASSERT_TRUE(ReadJsonTestFileToList("aes_kw.json", &tests));
+ base::Value tests;
+ ASSERT_TRUE(ReadJsonTestFileAsList("aes_kw.json", &tests));
- const base::Value& test_value = tests.GetList()[0];
+ const base::Value& test_value = tests.GetListDeprecated()[0];
ASSERT_TRUE(test_value.is_dict());
const base::DictionaryValue* test =
&base::Value::AsDictionaryValue(test_value);
@@ -303,10 +303,10 @@ TEST_F(WebCryptoAesKwTest, AesKwRawSymkeyUnwrapSignVerifyHmac) {
}
TEST_F(WebCryptoAesKwTest, AesKwRawSymkeyWrapUnwrapErrors) {
- base::ListValue tests;
- ASSERT_TRUE(ReadJsonTestFileToList("aes_kw.json", &tests));
+ base::Value tests;
+ ASSERT_TRUE(ReadJsonTestFileAsList("aes_kw.json", &tests));
// Use 256 bits of data with a 256-bit KEK
- const base::Value& test_value = tests.GetList()[3];
+ const base::Value& test_value = tests.GetListDeprecated()[3];
ASSERT_TRUE(test_value.is_dict());
const base::DictionaryValue* test =
&base::Value::AsDictionaryValue(test_value);
@@ -346,10 +346,10 @@ TEST_F(WebCryptoAesKwTest, AesKwRawSymkeyWrapUnwrapErrors) {
}
TEST_F(WebCryptoAesKwTest, AesKwRawSymkeyUnwrapCorruptData) {
- base::ListValue tests;
- ASSERT_TRUE(ReadJsonTestFileToList("aes_kw.json", &tests));
+ base::Value tests;
+ ASSERT_TRUE(ReadJsonTestFileAsList("aes_kw.json", &tests));
// Use 256 bits of data with a 256-bit KEK
- const base::Value& test_value = tests.GetList()[3];
+ const base::Value& test_value = tests.GetListDeprecated()[3];
ASSERT_TRUE(test_value.is_dict());
const base::DictionaryValue* test =
&base::Value::AsDictionaryValue(test_value);
diff --git a/chromium/components/webcrypto/algorithms/ecdh_unittest.cc b/chromium/components/webcrypto/algorithms/ecdh_unittest.cc
index cd8ceaae34a..02515ff8994 100644
--- a/chromium/components/webcrypto/algorithms/ecdh_unittest.cc
+++ b/chromium/components/webcrypto/algorithms/ecdh_unittest.cc
@@ -75,14 +75,14 @@ bool ImportKeysFromTest(const base::DictionaryValue* test,
class WebCryptoEcdhTest : public WebCryptoTestBase {};
TEST_F(WebCryptoEcdhTest, DeriveBitsKnownAnswer) {
- base::ListValue tests;
- ASSERT_TRUE(ReadJsonTestFileToList("ecdh.json", &tests));
+ base::Value tests;
+ ASSERT_TRUE(ReadJsonTestFileAsList("ecdh.json", &tests));
- for (size_t test_index = 0; test_index < tests.GetList().size();
+ for (size_t test_index = 0; test_index < tests.GetListDeprecated().size();
++test_index) {
SCOPED_TRACE(test_index);
- const base::Value& test_value = tests.GetList()[test_index];
+ const base::Value& test_value = tests.GetListDeprecated()[test_index];
ASSERT_TRUE(test_value.is_dict());
const base::DictionaryValue* test =
&base::Value::AsDictionaryValue(test_value);
@@ -120,16 +120,16 @@ TEST_F(WebCryptoEcdhTest, DeriveBitsKnownAnswer) {
// 528 bits.
::testing::AssertionResult LoadTestKeys(blink::WebCryptoKey* public_key,
blink::WebCryptoKey* private_key) {
- base::ListValue tests;
- if (!ReadJsonTestFileToList("ecdh.json", &tests))
+ base::Value tests;
+ if (!ReadJsonTestFileAsList("ecdh.json", &tests))
return ::testing::AssertionFailure() << "Failed loading ecdh.json";
const base::DictionaryValue* test = nullptr;
bool valid_p521_keys = false;
- for (size_t test_index = 0; test_index < tests.GetList().size();
+ for (size_t test_index = 0; test_index < tests.GetListDeprecated().size();
++test_index) {
SCOPED_TRACE(test_index);
- const base::Value& test_value = tests.GetList()[test_index];
+ const base::Value& test_value = tests.GetListDeprecated()[test_index];
EXPECT_TRUE(test_value.is_dict());
test = &base::Value::AsDictionaryValue(test_value);
absl::optional<bool> keys = test->FindBoolKey("valid_p521_keys");
@@ -308,10 +308,10 @@ TEST_F(WebCryptoEcdhTest, DeriveKeyAes128) {
TEST_F(WebCryptoEcdhTest, ImportKeyEmptyUsage) {
blink::WebCryptoKey key;
- base::ListValue tests;
- ASSERT_TRUE(ReadJsonTestFileToList("ecdh.json", &tests));
+ base::Value tests;
+ ASSERT_TRUE(ReadJsonTestFileAsList("ecdh.json", &tests));
- const base::Value& test_value = tests.GetList()[0];
+ const base::Value& test_value = tests.GetListDeprecated()[0];
ASSERT_TRUE(test_value.is_dict());
const base::DictionaryValue* test =
&base::Value::AsDictionaryValue(test_value);
diff --git a/chromium/components/webcrypto/algorithms/ecdsa_unittest.cc b/chromium/components/webcrypto/algorithms/ecdsa_unittest.cc
index b829f09680a..291bc71f820 100644
--- a/chromium/components/webcrypto/algorithms/ecdsa_unittest.cc
+++ b/chromium/components/webcrypto/algorithms/ecdsa_unittest.cc
@@ -96,9 +96,9 @@ TEST_F(WebCryptoEcdsaTest, SignatureIsRandom) {
// Import a public and private keypair from "ec_private_keys.json". It doesn't
// really matter which one is used since they are all valid. In this case
// using the first one.
- base::ListValue private_keys;
- ASSERT_TRUE(ReadJsonTestFileToList("ec_private_keys.json", &private_keys));
- const base::Value& key_value = private_keys.GetList()[0];
+ base::Value private_keys;
+ ASSERT_TRUE(ReadJsonTestFileAsList("ec_private_keys.json", &private_keys));
+ const base::Value& key_value = private_keys.GetListDeprecated()[0];
ASSERT_TRUE(key_value.is_dict());
const base::DictionaryValue* key_dict =
&base::Value::AsDictionaryValue(key_value);
@@ -115,7 +115,9 @@ TEST_F(WebCryptoEcdsaTest, SignatureIsRandom) {
// Erase the "d" member so the private key JWK can be used to import the
// public key (WebCrypto doesn't provide a mechanism for importing a public
// key given a private key).
- std::unique_ptr<base::DictionaryValue> key_jwk_copy(key_jwk->DeepCopy());
+ std::unique_ptr<base::DictionaryValue> key_jwk_copy =
+ base::DictionaryValue::From(
+ base::Value::ToUniquePtrValue(key_jwk->Clone()));
key_jwk_copy->RemoveKey("d");
blink::WebCryptoKey public_key;
ASSERT_EQ(
@@ -153,14 +155,14 @@ TEST_F(WebCryptoEcdsaTest, SignatureIsRandom) {
// Tests verify() for ECDSA using an assortment of keys, curves and hashes.
// These tests also include expected failures for bad signatures and keys.
TEST_F(WebCryptoEcdsaTest, VerifyKnownAnswer) {
- base::ListValue tests;
- ASSERT_TRUE(ReadJsonTestFileToList("ecdsa.json", &tests));
+ base::Value tests;
+ ASSERT_TRUE(ReadJsonTestFileAsList("ecdsa.json", &tests));
- for (size_t test_index = 0; test_index < tests.GetList().size();
+ for (size_t test_index = 0; test_index < tests.GetListDeprecated().size();
++test_index) {
SCOPED_TRACE(test_index);
- const base::Value& test_value = tests.GetList()[test_index];
+ const base::Value& test_value = tests.GetListDeprecated()[test_index];
ASSERT_TRUE(test_value.is_dict());
const base::DictionaryValue* test =
&base::Value::AsDictionaryValue(test_value);
@@ -227,7 +229,7 @@ blink::WebCryptoKeyUsageMask GetExpectedUsagesForKeyImport(
const base::DictionaryValue* key = nullptr;
if (!test->GetDictionary("key", &key))
ADD_FAILURE() << "Missing key property";
- return key->HasKey("d") ? kPrivateUsages : kPublicUsages;
+ return key->FindKey("d") ? kPrivateUsages : kPublicUsages;
}
}
@@ -237,14 +239,14 @@ blink::WebCryptoKeyUsageMask GetExpectedUsagesForKeyImport(
// Tests importing bad public/private keys in a variety of formats.
TEST_F(WebCryptoEcdsaTest, ImportBadKeys) {
- base::ListValue tests;
- ASSERT_TRUE(ReadJsonTestFileToList("bad_ec_keys.json", &tests));
+ base::Value tests;
+ ASSERT_TRUE(ReadJsonTestFileAsList("bad_ec_keys.json", &tests));
- for (size_t test_index = 0; test_index < tests.GetList().size();
+ for (size_t test_index = 0; test_index < tests.GetListDeprecated().size();
++test_index) {
SCOPED_TRACE(test_index);
- const base::Value& test_value = tests.GetList()[test_index];
+ const base::Value& test_value = tests.GetListDeprecated()[test_index];
ASSERT_TRUE(test_value.is_dict());
const base::DictionaryValue* test =
&base::Value::AsDictionaryValue(test_value);
@@ -270,14 +272,14 @@ TEST_F(WebCryptoEcdsaTest, ImportBadKeys) {
// The test imports a key first using JWK, and then exporting it to JWK and
// PKCS8. It does the same thing using PKCS8 as the original source of truth.
TEST_F(WebCryptoEcdsaTest, ImportExportPrivateKey) {
- base::ListValue tests;
- ASSERT_TRUE(ReadJsonTestFileToList("ec_private_keys.json", &tests));
+ base::Value tests;
+ ASSERT_TRUE(ReadJsonTestFileAsList("ec_private_keys.json", &tests));
- for (size_t test_index = 0; test_index < tests.GetList().size();
+ for (size_t test_index = 0; test_index < tests.GetListDeprecated().size();
++test_index) {
SCOPED_TRACE(test_index);
- const base::Value& test_value = tests.GetList()[test_index];
+ const base::Value& test_value = tests.GetListDeprecated()[test_index];
ASSERT_TRUE(test_value.is_dict());
const base::DictionaryValue* test =
&base::Value::AsDictionaryValue(test_value);
@@ -287,7 +289,7 @@ TEST_F(WebCryptoEcdsaTest, ImportExportPrivateKey) {
EXPECT_TRUE(test->GetDictionary("jwk", &jwk_dict));
std::vector<uint8_t> jwk_bytes = MakeJsonVector(*jwk_dict);
std::vector<uint8_t> pkcs8_bytes = GetBytesFromHexString(
- test, test->HasKey("exported_pkcs8") ? "exported_pkcs8" : "pkcs8");
+ test, test->FindKey("exported_pkcs8") ? "exported_pkcs8" : "pkcs8");
// -------------------------------------------------
// Test from JWK, and then export to {JWK, PKCS8}
@@ -335,7 +337,7 @@ TEST_F(WebCryptoEcdsaTest, ImportExportPrivateKey) {
// where the publicKey was missing, it will be synthesized and written back
// during export).
std::vector<uint8_t> pkcs8_input_bytes = GetBytesFromHexString(
- test, test->HasKey("original_pkcs8") ? "original_pkcs8" : "pkcs8");
+ test, test->FindKey("original_pkcs8") ? "original_pkcs8" : "pkcs8");
CryptoData pkcs8_input_data(pkcs8_input_bytes.empty() ? pkcs8_bytes
: pkcs8_input_bytes);
diff --git a/chromium/components/webcrypto/algorithms/hmac_unittest.cc b/chromium/components/webcrypto/algorithms/hmac_unittest.cc
index 83c339847e1..7f16c1a63a3 100644
--- a/chromium/components/webcrypto/algorithms/hmac_unittest.cc
+++ b/chromium/components/webcrypto/algorithms/hmac_unittest.cc
@@ -50,12 +50,12 @@ blink::WebCryptoAlgorithm CreateHmacImportAlgorithmWithLength(
class WebCryptoHmacTest : public WebCryptoTestBase {};
TEST_F(WebCryptoHmacTest, HMACSampleSets) {
- base::ListValue tests;
- ASSERT_TRUE(ReadJsonTestFileToList("hmac.json", &tests));
- for (size_t test_index = 0; test_index < tests.GetList().size();
+ base::Value tests;
+ ASSERT_TRUE(ReadJsonTestFileAsList("hmac.json", &tests));
+ for (size_t test_index = 0; test_index < tests.GetListDeprecated().size();
++test_index) {
SCOPED_TRACE(test_index);
- const base::Value& test_value = tests.GetList()[test_index];
+ const base::Value& test_value = tests.GetListDeprecated()[test_index];
ASSERT_TRUE(test_value.is_dict());
const base::DictionaryValue* test =
&base::Value::AsDictionaryValue(test_value);
diff --git a/chromium/components/webcrypto/algorithms/rsa_oaep_unittest.cc b/chromium/components/webcrypto/algorithms/rsa_oaep_unittest.cc
index 2de31a1ba79..eb8f8efd785 100644
--- a/chromium/components/webcrypto/algorithms/rsa_oaep_unittest.cc
+++ b/chromium/components/webcrypto/algorithms/rsa_oaep_unittest.cc
@@ -155,14 +155,14 @@ TEST_F(WebCryptoRsaOaepTest, ExportPublicJwk) {
}
TEST_F(WebCryptoRsaOaepTest, EncryptDecryptKnownAnswerTest) {
- base::ListValue tests;
- ASSERT_TRUE(ReadJsonTestFileToList("rsa_oaep.json", &tests));
+ base::Value tests;
+ ASSERT_TRUE(ReadJsonTestFileAsList("rsa_oaep.json", &tests));
- for (size_t test_index = 0; test_index < tests.GetList().size();
+ for (size_t test_index = 0; test_index < tests.GetListDeprecated().size();
++test_index) {
SCOPED_TRACE(test_index);
- const base::Value& test_value = tests.GetList()[test_index];
+ const base::Value& test_value = tests.GetListDeprecated()[test_index];
ASSERT_TRUE(test_value.is_dict());
const base::DictionaryValue* test =
&base::Value::AsDictionaryValue(test_value);
diff --git a/chromium/components/webcrypto/algorithms/rsa_pss_unittest.cc b/chromium/components/webcrypto/algorithms/rsa_pss_unittest.cc
index e5a8daa9ec6..f0cf03a7804 100644
--- a/chromium/components/webcrypto/algorithms/rsa_pss_unittest.cc
+++ b/chromium/components/webcrypto/algorithms/rsa_pss_unittest.cc
@@ -166,20 +166,21 @@ TEST_F(WebCryptoRsaPssTest, SignEmptyMessage) {
// * Verify over corrupted message should fail
// * Verification with corrupted signature should fail
TEST_F(WebCryptoRsaPssTest, VerifyKnownAnswer) {
- base::DictionaryValue test_data;
- ASSERT_TRUE(ReadJsonTestFileToDictionary("rsa_pss.json", &test_data));
+ base::Value test_data;
+ ASSERT_TRUE(ReadJsonTestFile("rsa_pss.json", &test_data));
+ ASSERT_TRUE(test_data.is_dict());
- const base::DictionaryValue* keys_dict = nullptr;
- ASSERT_TRUE(test_data.GetDictionary("keys", &keys_dict));
+ const base::Value* keys_dict = test_data.FindDictKey("keys");
+ ASSERT_TRUE(keys_dict);
- const base::ListValue* tests = nullptr;
- ASSERT_TRUE(test_data.GetList("tests", &tests));
+ const base::Value* tests = test_data.FindListKey("tests");
+ ASSERT_TRUE(tests);
- for (size_t test_index = 0; test_index < tests->GetList().size();
+ for (size_t test_index = 0; test_index < tests->GetListDeprecated().size();
++test_index) {
SCOPED_TRACE(test_index);
- const base::Value& test_value = tests->GetList()[test_index];
+ const base::Value& test_value = tests->GetListDeprecated()[test_index];
ASSERT_TRUE(test_value.is_dict());
const base::DictionaryValue* test =
&base::Value::AsDictionaryValue(test_value);
diff --git a/chromium/components/webcrypto/algorithms/rsa_ssa_unittest.cc b/chromium/components/webcrypto/algorithms/rsa_ssa_unittest.cc
index 5ebf78a6fb7..04834eab833 100644
--- a/chromium/components/webcrypto/algorithms/rsa_ssa_unittest.cc
+++ b/chromium/components/webcrypto/algorithms/rsa_ssa_unittest.cc
@@ -202,18 +202,18 @@ TEST_F(WebCryptoRsaSsaTest, ImportRsaPrivateKeyJwkToPkcs8RoundTrip) {
// be imported correctly, however every key after that would actually import
// the first key.
TEST_F(WebCryptoRsaSsaTest, ImportMultipleRSAPrivateKeysJwk) {
- base::ListValue key_list;
- ASSERT_TRUE(ReadJsonTestFileToList("rsa_private_keys.json", &key_list));
+ base::Value key_list;
+ ASSERT_TRUE(ReadJsonTestFileAsList("rsa_private_keys.json", &key_list));
// For this test to be meaningful the keys MUST be kept alive before importing
// new keys.
std::vector<blink::WebCryptoKey> live_keys;
- for (size_t key_index = 0; key_index < key_list.GetList().size();
+ for (size_t key_index = 0; key_index < key_list.GetListDeprecated().size();
++key_index) {
SCOPED_TRACE(key_index);
- const base::Value& key_values = key_list.GetList()[key_index];
+ const base::Value& key_values = key_list.GetListDeprecated()[key_index];
ASSERT_TRUE(key_values.is_dict());
const base::DictionaryValue* key_values_dict =
&base::Value::AsDictionaryValue(key_values);
@@ -264,11 +264,11 @@ TEST_F(WebCryptoRsaSsaTest, ImportMultipleRSAPrivateKeysJwk) {
// that the second import retrieves the first key. See http://crbug.com/378315
// for how that could happen.
TEST_F(WebCryptoRsaSsaTest, ImportJwkExistingModulusAndInvalid) {
- base::ListValue key_list;
- ASSERT_TRUE(ReadJsonTestFileToList("rsa_private_keys.json", &key_list));
+ base::Value key_list;
+ ASSERT_TRUE(ReadJsonTestFileAsList("rsa_private_keys.json", &key_list));
// Import a 1024-bit private key.
- const base::Value& key1_props_value = key_list.GetList()[1];
+ const base::Value& key1_props_value = key_list.GetListDeprecated()[1];
ASSERT_TRUE(key1_props_value.is_dict());
const base::DictionaryValue* key1_props =
&base::Value::AsDictionaryValue(key1_props_value);
@@ -288,7 +288,7 @@ TEST_F(WebCryptoRsaSsaTest, ImportJwkExistingModulusAndInvalid) {
// Construct a JWK using the modulus of key1, but all the other fields from
// another key (also a 1024-bit private key).
- base::Value& key2_props_value = key_list.GetList()[5];
+ base::Value& key2_props_value = key_list.GetListDeprecated()[5];
ASSERT_TRUE(key2_props_value.is_dict());
base::DictionaryValue* key2_props = const_cast<base::DictionaryValue*>(
&base::Value::AsDictionaryValue(key2_props_value));
@@ -639,8 +639,8 @@ TEST_F(WebCryptoRsaSsaTest, SignVerifyFailures) {
}
TEST_F(WebCryptoRsaSsaTest, SignVerifyKnownAnswer) {
- base::ListValue tests;
- ASSERT_TRUE(ReadJsonTestFileToList("pkcs1v15_sign.json", &tests));
+ base::Value tests;
+ ASSERT_TRUE(ReadJsonTestFileAsList("pkcs1v15_sign.json", &tests));
// Import the key pair.
blink::WebCryptoAlgorithm import_algorithm = CreateRsaHashedImportAlgorithm(
@@ -659,11 +659,11 @@ TEST_F(WebCryptoRsaSsaTest, SignVerifyKnownAnswer) {
// Validate the signatures are computed and verified as expected.
std::vector<uint8_t> signature;
- for (size_t test_index = 0; test_index < tests.GetList().size();
+ for (size_t test_index = 0; test_index < tests.GetListDeprecated().size();
++test_index) {
SCOPED_TRACE(test_index);
- const base::Value& test_value = tests.GetList()[test_index];
+ const base::Value& test_value = tests.GetListDeprecated()[test_index];
ASSERT_TRUE(test_value.is_dict());
const base::DictionaryValue* test =
&base::Value::AsDictionaryValue(test_value);
@@ -997,14 +997,14 @@ TEST_F(WebCryptoRsaSsaTest, ImportRsaSsaJwkBadUsageAndData) {
// Imports invalid JWK/SPKI/PKCS8 data and verifies that it fails as expected.
TEST_F(WebCryptoRsaSsaTest, ImportInvalidKeyData) {
- base::ListValue tests;
- ASSERT_TRUE(ReadJsonTestFileToList("bad_rsa_keys.json", &tests));
+ base::Value tests;
+ ASSERT_TRUE(ReadJsonTestFileAsList("bad_rsa_keys.json", &tests));
- for (size_t test_index = 0; test_index < tests.GetList().size();
+ for (size_t test_index = 0; test_index < tests.GetListDeprecated().size();
++test_index) {
SCOPED_TRACE(test_index);
- const base::Value& test_value = tests.GetList()[test_index];
+ const base::Value& test_value = tests.GetListDeprecated()[test_index];
ASSERT_TRUE(test_value.is_dict());
const base::DictionaryValue* test =
&base::Value::AsDictionaryValue(test_value);
diff --git a/chromium/components/webcrypto/algorithms/sha_unittest.cc b/chromium/components/webcrypto/algorithms/sha_unittest.cc
index 613fd61a7ed..cec19aa30fb 100644
--- a/chromium/components/webcrypto/algorithms/sha_unittest.cc
+++ b/chromium/components/webcrypto/algorithms/sha_unittest.cc
@@ -22,13 +22,13 @@ namespace {
class WebCryptoShaTest : public WebCryptoTestBase {};
TEST_F(WebCryptoShaTest, DigestSampleSets) {
- base::ListValue tests;
- ASSERT_TRUE(ReadJsonTestFileToList("sha.json", &tests));
+ base::Value tests;
+ ASSERT_TRUE(ReadJsonTestFileAsList("sha.json", &tests));
- for (size_t test_index = 0; test_index < tests.GetList().size();
+ for (size_t test_index = 0; test_index < tests.GetListDeprecated().size();
++test_index) {
SCOPED_TRACE(test_index);
- const base::Value& test_value = tests.GetList()[test_index];
+ const base::Value& test_value = tests.GetListDeprecated()[test_index];
ASSERT_TRUE(test_value.is_dict());
const base::DictionaryValue* test =
&base::Value::AsDictionaryValue(test_value);
diff --git a/chromium/components/webcrypto/algorithms/test_helpers.cc b/chromium/components/webcrypto/algorithms/test_helpers.cc
index 6f6be59a140..87e2f54d373 100644
--- a/chromium/components/webcrypto/algorithms/test_helpers.cc
+++ b/chromium/components/webcrypto/algorithms/test_helpers.cc
@@ -172,50 +172,35 @@ std::vector<uint8_t> MakeJsonVector(const base::DictionaryValue& dict) {
return ::testing::AssertionSuccess();
}
-::testing::AssertionResult ReadJsonTestFileToList(const char* test_file_name,
- base::ListValue* list) {
+::testing::AssertionResult ReadJsonTestFileAsList(const char* test_file_name,
+ base::Value* value) {
// Read the JSON.
base::Value json;
::testing::AssertionResult result = ReadJsonTestFile(test_file_name, &json);
if (!result)
return result;
- // Cast to an ListValue.
- base::ListValue* json_as_list = nullptr;
- if (!json.GetAsList(&json_as_list))
+ if (!json.is_list())
return ::testing::AssertionFailure() << "The JSON was not a list";
- *list = std::move(*json_as_list);
+ *value = std::move(json);
return ::testing::AssertionSuccess();
}
-::testing::AssertionResult ReadJsonTestFileToDictionary(
- const char* test_file_name,
- base::DictionaryValue* dict) {
- // Read the JSON.
- base::Value json;
- ::testing::AssertionResult result = ReadJsonTestFile(test_file_name, &json);
- if (!result)
- return result;
-
- // Cast to an DictionaryValue.
- base::DictionaryValue* json_as_dict = nullptr;
- if (!json.GetAsDictionary(&json_as_dict))
- return ::testing::AssertionFailure() << "The JSON was not a dictionary";
-
- *dict = std::move(*json_as_dict);
- return ::testing::AssertionSuccess();
-}
-
-std::vector<uint8_t> GetBytesFromHexString(const base::DictionaryValue* dict,
+std::vector<uint8_t> GetBytesFromHexString(const base::Value* dict,
const std::string& property_name) {
- std::string hex_string;
- if (!dict->GetString(property_name, &hex_string)) {
+ if (!dict->is_dict()) {
+ ADD_FAILURE() << "Value is not a dictionary";
+ return std::vector<uint8_t>();
+ }
+
+ const std::string* hex_string = dict->FindStringPath(property_name);
+ if (!hex_string) {
ADD_FAILURE() << "Couldn't get string property: " << property_name;
return std::vector<uint8_t>();
}
- return HexStringToBytes(hex_string);
+ return HexStringToBytes(*hex_string);
}
blink::WebCryptoAlgorithm GetDigestAlgorithm(const base::DictionaryValue* dict,
diff --git a/chromium/components/webcrypto/algorithms/test_helpers.h b/chromium/components/webcrypto/algorithms/test_helpers.h
index 40296348bc9..ea06d625500 100644
--- a/chromium/components/webcrypto/algorithms/test_helpers.h
+++ b/chromium/components/webcrypto/algorithms/test_helpers.h
@@ -25,7 +25,6 @@
namespace base {
class DictionaryValue;
-class ListValue;
class Value;
}
@@ -86,20 +85,16 @@ std::vector<uint8_t> MakeJsonVector(const base::DictionaryValue& dict);
// The file must be JSON, however it can also include C++ style comments.
::testing::AssertionResult ReadJsonTestFile(const char* test_file_name,
base::Value* value);
-// Same as ReadJsonTestFile(), but returns the value as a List.
-::testing::AssertionResult ReadJsonTestFileToList(const char* test_file_name,
- base::ListValue* list);
-// Same as ReadJsonTestFile(), but returns the value as a Dictionary.
-::testing::AssertionResult ReadJsonTestFileToDictionary(
- const char* test_file_name,
- base::DictionaryValue* dict);
-
-// Reads a string property from the dictionary with path |property_name|
+// Same as ReadJsonTestFile(), but asserts the value is a list.
+::testing::AssertionResult ReadJsonTestFileAsList(const char* test_file_name,
+ base::Value* list);
+
+// Reads a string property from the dictionary |dict| with path |property_name|
// (which can include periods for nested dictionaries). Interprets the
// string as a hex encoded string and converts it to a bytes list.
//
-// Returns empty vector on failure.
-std::vector<uint8_t> GetBytesFromHexString(const base::DictionaryValue* dict,
+// Returns empty vector on failure or if |dict| is not a dictionary.
+std::vector<uint8_t> GetBytesFromHexString(const base::Value* dict,
const std::string& property_name);
// Reads a string property with path "property_name" and converts it to a
diff --git a/chromium/components/webcrypto/jwk.cc b/chromium/components/webcrypto/jwk.cc
index 14d535e556a..857865368b7 100644
--- a/chromium/components/webcrypto/jwk.cc
+++ b/chromium/components/webcrypto/jwk.cc
@@ -114,7 +114,7 @@ Status GetWebCryptoUsagesFromJwkKeyOps(const base::ListValue* key_ops,
std::set<std::string> unrecognized_usages;
*usages = 0;
- base::Value::ConstListView key_ops_list = key_ops->GetList();
+ base::Value::ConstListView key_ops_list = key_ops->GetListDeprecated();
for (size_t i = 0; i < key_ops_list.size(); ++i) {
const base::Value& key_op_value = key_ops_list[i];
if (!key_op_value.is_string()) {
diff --git a/chromium/components/webdata/common/BUILD.gn b/chromium/components/webdata/common/BUILD.gn
index 3dc9f802d31..361206d439b 100644
--- a/chromium/components/webdata/common/BUILD.gn
+++ b/chromium/components/webdata/common/BUILD.gn
@@ -86,6 +86,8 @@ bundle_data("unit_tests_bundle_data") {
"//components/test/data/web_database/version_95.sql",
"//components/test/data/web_database/version_96.sql",
"//components/test/data/web_database/version_97.sql",
+ "//components/test/data/web_database/version_98.sql",
+ "//components/test/data/web_database/version_99.sql",
]
outputs = [ "{{bundle_resources_dir}}/" +
"{{source_root_relative_dir}}/{{source_file_part}}" ]
diff --git a/chromium/components/webdata/common/web_data_results.h b/chromium/components/webdata/common/web_data_results.h
index f20ae9df4af..ecc8ab4db09 100644
--- a/chromium/components/webdata/common/web_data_results.h
+++ b/chromium/components/webdata/common/web_data_results.h
@@ -21,7 +21,7 @@ typedef enum {
BOOL_RESULT = 1, // WDResult<bool>
KEYWORDS_RESULT, // WDResult<WDKeywordsResult>
INT64_RESULT, // WDResult<int64_t>
-#if defined(OS_WIN) //
+#if BUILDFLAG(IS_WIN) //
PASSWORD_IE7_RESULT, // WDResult<IE7PasswordInfo>
#endif //
WEB_APP_IMAGES, // WDResult<WDAppImagesResult>
@@ -42,7 +42,7 @@ typedef enum {
AUTOFILL_OFFER_DATA, // WDResult<std::vector<std::unique_ptr<
// AutofillOfferData>>>
AUTOFILL_UPI_RESULT, // WDResult<std::string>
-#if !defined(OS_IOS) //
+#if !BUILDFLAG(IS_IOS) //
PAYMENT_WEB_APP_MANIFEST, // WDResult<std::vector<
// mojom::WebAppManifestSectionPtr>>
PAYMENT_METHOD_MANIFEST, // WDResult<std::vector<std::string>>
diff --git a/chromium/components/webdata/common/web_database.cc b/chromium/components/webdata/common/web_database.cc
index 7d494b48296..181adb3e651 100644
--- a/chromium/components/webdata/common/web_database.cc
+++ b/chromium/components/webdata/common/web_database.cc
@@ -13,7 +13,7 @@
// corresponding changes must happen in the unit tests, and new migration test
// added. See |WebDatabaseMigrationTest::kCurrentTestedVersionNumber|.
// static
-const int WebDatabase::kCurrentVersionNumber = 98;
+const int WebDatabase::kCurrentVersionNumber = 100;
const int WebDatabase::kDeprecatedVersionNumber = 51;
@@ -22,7 +22,7 @@ const base::FilePath::CharType WebDatabase::kInMemoryPath[] =
namespace {
-const int kCompatibleVersionNumber = 98;
+const int kCompatibleVersionNumber = 99;
// Change the version number and possibly the compatibility version of
// |meta_table_|.
diff --git a/chromium/components/webdata/common/web_database_migration_unittest.cc b/chromium/components/webdata/common/web_database_migration_unittest.cc
index 51b7a814c58..cb2f15c8bb0 100644
--- a/chromium/components/webdata/common/web_database_migration_unittest.cc
+++ b/chromium/components/webdata/common/web_database_migration_unittest.cc
@@ -125,7 +125,7 @@ class WebDatabaseMigrationTest : public testing::Test {
base::ScopedTempDir temp_dir_;
};
-const int WebDatabaseMigrationTest::kCurrentTestedVersionNumber = 98;
+const int WebDatabaseMigrationTest::kCurrentTestedVersionNumber = 100;
void WebDatabaseMigrationTest::LoadDatabase(
const base::FilePath::StringType& file) {
@@ -1353,7 +1353,9 @@ TEST_F(WebDatabaseMigrationTest, MigrateVersion73WithTypeColumnToCurrent) {
}
}
-// Tests adding "validity_bitfield" column for the "autofill_profiles" table.
+// Tests temporarily adding "validity_bitfield" column for the
+// "autofill_profiles" table. Note that the field is deprecated and removed in
+// version 100.
TEST_F(WebDatabaseMigrationTest, MigrateVersion74ToCurrent) {
ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_74.sql")));
@@ -1381,7 +1383,8 @@ TEST_F(WebDatabaseMigrationTest, MigrateVersion74ToCurrent) {
// Check version.
EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
- EXPECT_TRUE(
+ // Note, those fields have been deprecated in version 100.
+ EXPECT_FALSE(
connection.DoesColumnExist("autofill_profiles", "validity_bitfield"));
// Data should have been preserved. Validity bitfield should have been set
@@ -1389,7 +1392,7 @@ TEST_F(WebDatabaseMigrationTest, MigrateVersion74ToCurrent) {
sql::Statement s_profiles(connection.GetUniqueStatement(
"SELECT guid, company_name, street_address, dependent_locality,"
" city, state, zipcode, sorting_code, country_code, date_modified,"
- " origin, language_code, validity_bitfield "
+ " origin, language_code "
"FROM autofill_profiles"));
ASSERT_TRUE(s_profiles.Step());
@@ -1407,8 +1410,6 @@ TEST_F(WebDatabaseMigrationTest, MigrateVersion74ToCurrent) {
EXPECT_EQ(ASCIIToUTF16(autofill::kSettingsOrigin),
s_profiles.ColumnString16(10));
EXPECT_EQ("en", s_profiles.ColumnString(11));
- // The new validity bitfield should have the default value of 0.
- EXPECT_EQ(0, s_profiles.ColumnInt(12));
// No more entries expected.
ASSERT_FALSE(s_profiles.Step());
@@ -1579,6 +1580,7 @@ TEST_F(WebDatabaseMigrationTest, MigrateVersion78ToCurrent) {
// Tests adding "is_client_validity_states_updated" column for the
// "autofill_profiles" table.
+// Note that the field was deprecated and deleted in version 100.
TEST_F(WebDatabaseMigrationTest, MigrateVersion79ToCurrent) {
ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_79.sql")));
@@ -1600,15 +1602,15 @@ TEST_F(WebDatabaseMigrationTest, MigrateVersion79ToCurrent) {
ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
// Check version.
EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
- EXPECT_TRUE(connection.DoesColumnExist(
+ // Note that the field was deprecated and removed in version 100.
+ EXPECT_FALSE(connection.DoesColumnExist(
"autofill_profiles", "is_client_validity_states_updated"));
// Data should have been preserved. Validity
// is_client_validity_states_updated should have been set to false.
sql::Statement s_profiles(connection.GetUniqueStatement(
"SELECT guid, company_name, street_address, dependent_locality,"
" city, state, zipcode, sorting_code, country_code, date_modified,"
- " origin, language_code, validity_bitfield, "
- " is_client_validity_states_updated "
+ " origin, language_code "
" FROM autofill_profiles"));
ASSERT_TRUE(s_profiles.Step());
EXPECT_EQ("00000000-0000-0000-0000-000000000001",
@@ -1625,10 +1627,6 @@ TEST_F(WebDatabaseMigrationTest, MigrateVersion79ToCurrent) {
EXPECT_EQ(ASCIIToUTF16(autofill::kSettingsOrigin),
s_profiles.ColumnString16(10));
EXPECT_EQ("en", s_profiles.ColumnString(11));
- EXPECT_EQ(1365, s_profiles.ColumnInt(12));
- // The new is_client_validity_states_updated should have the default value
- // of FALSE.
- EXPECT_FALSE(s_profiles.ColumnBool(13));
// No more entries expected.
ASSERT_FALSE(s_profiles.Step());
@@ -2221,4 +2219,72 @@ TEST_F(WebDatabaseMigrationTest, MigrateVersion97ToCurrent) {
// The status column should not exist.
EXPECT_FALSE(connection.DoesColumnExist("masked_credit_cards", "status"));
}
-} \ No newline at end of file
+}
+
+TEST_F(WebDatabaseMigrationTest, MigrateVersion98ToCurrent) {
+ ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_98.sql")));
+
+ // Verify pre-conditions.
+ {
+ sql::Database connection;
+ ASSERT_TRUE(connection.Open(GetDatabasePath()));
+ ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
+
+ sql::MetaTable meta_table;
+ ASSERT_TRUE(meta_table.Init(&connection, 98, 98));
+
+ // The autofill_profiles_trash table should exist.
+ EXPECT_TRUE(connection.DoesTableExist("autofill_profiles_trash"));
+ }
+
+ DoMigration();
+
+ // Verify post-conditions.
+ {
+ sql::Database connection;
+ ASSERT_TRUE(connection.Open(GetDatabasePath()));
+ ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
+
+ // Check version.
+ EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
+ // The autofill_profiles_trash table should not exist.
+ EXPECT_FALSE(connection.DoesTableExist("autofill_profiles_trash"));
+ }
+}
+
+TEST_F(WebDatabaseMigrationTest, MigrateVersion99ToCurrent) {
+ ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_99.sql")));
+
+ // Verify pre-conditions.
+ {
+ sql::Database connection;
+ ASSERT_TRUE(connection.Open(GetDatabasePath()));
+ ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
+
+ sql::MetaTable meta_table;
+ ASSERT_TRUE(meta_table.Init(&connection, 99, 99));
+
+ // The validity-related columns should exist.
+ EXPECT_TRUE(
+ connection.DoesColumnExist("autofill_profiles", "validity_bitfield"));
+ EXPECT_TRUE(connection.DoesColumnExist(
+ "autofill_profiles", "is_client_validity_states_updated"));
+ }
+
+ DoMigration();
+
+ // Verify post-conditions.
+ {
+ sql::Database connection;
+ ASSERT_TRUE(connection.Open(GetDatabasePath()));
+ ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
+
+ // Check version.
+ EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
+
+ EXPECT_FALSE(
+ connection.DoesColumnExist("autofill_profiles", "validity_bitfield"));
+ EXPECT_FALSE(connection.DoesColumnExist(
+ "autofill_profiles", "is_client_validity_states_updated"));
+ }
+}
diff --git a/chromium/components/webdata/common/webdata_constants.cc b/chromium/components/webdata/common/webdata_constants.cc
index 3f82ce8b256..a0279501839 100644
--- a/chromium/components/webdata/common/webdata_constants.cc
+++ b/chromium/components/webdata/common/webdata_constants.cc
@@ -4,10 +4,12 @@
#include "components/webdata/common/webdata_constants.h"
+#include "build/build_config.h"
+
const base::FilePath::CharType kWebDataFilename[] =
FILE_PATH_LITERAL("Web Data");
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
const base::FilePath::CharType kAccountWebDataFilename[] =
FILE_PATH_LITERAL("Account Web Data");
-#endif // defined(OS_ANDROID) || defined(OS_IOS)
+#endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
diff --git a/chromium/components/webdata/common/webdata_constants.h b/chromium/components/webdata/common/webdata_constants.h
index 45c5e9aa52a..3f31c29fe34 100644
--- a/chromium/components/webdata/common/webdata_constants.h
+++ b/chromium/components/webdata/common/webdata_constants.h
@@ -13,8 +13,8 @@ WEBDATA_EXPORT extern const base::FilePath::CharType kWebDataFilename[];
// Note: On desktop, the account-scoped web data store is only stored in memory,
// so doesn't have a file path. So this constant only exists on mobile.
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
WEBDATA_EXPORT extern const base::FilePath::CharType kAccountWebDataFilename[];
-#endif // defined(OS_ANDROID) || defined(OS_IOS)
+#endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
#endif // COMPONENTS_WEBDATA_COMMON_WEBDATA_CONSTANTS_H_
diff --git a/chromium/components/webdata_services/web_data_service_wrapper.cc b/chromium/components/webdata_services/web_data_service_wrapper.cc
index b260ad0967d..f828aa497c0 100644
--- a/chromium/components/webdata_services/web_data_service_wrapper.cc
+++ b/chromium/components/webdata_services/web_data_service_wrapper.cc
@@ -26,11 +26,10 @@
#include "components/search_engines/keyword_web_data_service.h"
#include "components/signin/public/webdata/token_service_table.h"
#include "components/signin/public/webdata/token_web_data.h"
-#include "components/sync/driver/sync_driver_switches.h"
#include "components/webdata/common/web_database_service.h"
#include "components/webdata/common/webdata_constants.h"
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
#include "components/payments/content/payment_manifest_web_data_service.h"
#include "components/payments/content/payment_method_manifest_table.h"
#include "components/payments/content/web_app_manifest_section_table.h"
@@ -97,7 +96,7 @@ WebDataServiceWrapper::WebDataServiceWrapper(
profile_database_->AddTable(std::make_unique<autofill::AutofillTable>());
profile_database_->AddTable(std::make_unique<KeywordTable>());
profile_database_->AddTable(std::make_unique<TokenServiceTable>());
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
profile_database_->AddTable(
std::make_unique<payments::PaymentMethodManifestTable>());
profile_database_->AddTable(
@@ -121,7 +120,7 @@ WebDataServiceWrapper::WebDataServiceWrapper(
token_web_data_->Init(
base::BindOnce(show_error_callback, ERROR_LOADING_TOKEN));
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
payment_manifest_web_data_ =
base::MakeRefCounted<payments::PaymentManifestWebDataService>(
profile_database_, ui_task_runner);
@@ -135,20 +134,18 @@ WebDataServiceWrapper::WebDataServiceWrapper(
profile_autofill_web_data_->GetAutofillBackend(
base::BindOnce(&InitWalletSyncBridgesOnDBSequence, db_task_runner,
profile_autofill_web_data_, application_locale));
- if (base::FeatureList::IsEnabled(switches::kSyncAutofillWalletOfferData)) {
- profile_autofill_web_data_->GetAutofillBackend(
- base::BindOnce(&InitWalletOfferSyncBridgeOnDBSequence, db_task_runner,
- profile_autofill_web_data_));
- }
+ profile_autofill_web_data_->GetAutofillBackend(
+ base::BindOnce(&InitWalletOfferSyncBridgeOnDBSequence, db_task_runner,
+ profile_autofill_web_data_));
if (base::FeatureList::IsEnabled(
autofill::features::kAutofillEnableAccountWalletStorage)) {
base::FilePath account_storage_path;
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
account_storage_path = context_path.Append(kAccountWebDataFilename);
#else
account_storage_path = base::FilePath(WebDatabase::kInMemoryPath);
-#endif // OS_ANDROID || defined(OS_IOS)
+#endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
account_database_ = base::MakeRefCounted<WebDatabaseService>(
account_storage_path, ui_task_runner, db_task_runner);
account_database_->AddTable(std::make_unique<autofill::AutofillTable>());
@@ -174,7 +171,7 @@ void WebDataServiceWrapper::Shutdown() {
keyword_web_data_->ShutdownOnUISequence();
token_web_data_->ShutdownOnUISequence();
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
payment_manifest_web_data_->ShutdownOnUISequence();
#endif
@@ -202,7 +199,7 @@ scoped_refptr<TokenWebData> WebDataServiceWrapper::GetTokenWebData() {
return token_web_data_.get();
}
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
scoped_refptr<payments::PaymentManifestWebDataService>
WebDataServiceWrapper::GetPaymentManifestWebData() {
return payment_manifest_web_data_.get();
diff --git a/chromium/components/webdata_services/web_data_service_wrapper.h b/chromium/components/webdata_services/web_data_service_wrapper.h
index 4bce6edf7d5..81635d21f59 100644
--- a/chromium/components/webdata_services/web_data_service_wrapper.h
+++ b/chromium/components/webdata_services/web_data_service_wrapper.h
@@ -18,7 +18,7 @@ class KeywordWebDataService;
class TokenWebData;
class WebDatabaseService;
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
namespace payments {
class PaymentManifestWebDataService;
} // namespace payments
@@ -82,7 +82,7 @@ class WebDataServiceWrapper : public KeyedService {
GetAccountAutofillWebData();
virtual scoped_refptr<KeywordWebDataService> GetKeywordWebData();
virtual scoped_refptr<TokenWebData> GetTokenWebData();
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
virtual scoped_refptr<payments::PaymentManifestWebDataService>
GetPaymentManifestWebData();
#endif
@@ -100,7 +100,7 @@ class WebDataServiceWrapper : public KeyedService {
scoped_refptr<KeywordWebDataService> keyword_web_data_;
scoped_refptr<TokenWebData> token_web_data_;
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
scoped_refptr<payments::PaymentManifestWebDataService>
payment_manifest_web_data_;
#endif
diff --git a/chromium/components/webrtc/BUILD.gn b/chromium/components/webrtc/BUILD.gn
index 49eac6cce00..44981f1895b 100644
--- a/chromium/components/webrtc/BUILD.gn
+++ b/chromium/components/webrtc/BUILD.gn
@@ -2,36 +2,96 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("media_stream_device_enumerator") {
+if (!is_ios) {
+ source_set("media_stream_device_enumerator") {
+ sources = [
+ "media_stream_device_enumerator.h",
+ "media_stream_device_enumerator_impl.cc",
+ "media_stream_device_enumerator_impl.h",
+ ]
+
+ deps = [
+ "//base",
+ "//content/public/browser",
+ "//third_party/blink/public/common",
+ ]
+ }
+
+ source_set("webrtc") {
+ sources = [
+ "media_stream_devices_controller.cc",
+ "media_stream_devices_controller.h",
+ ]
+
+ public_deps = [ ":media_stream_device_enumerator" ]
+
+ deps = [
+ "//base",
+ "//components/content_settings/core/common",
+ "//components/permissions",
+ "//content/public/browser",
+ "//third_party/blink/public/common",
+ ]
+ if (is_android) {
+ deps += [ "//ui/android" ]
+ }
+ }
+}
+
+source_set("fake_ssl_socket") {
+ visibility = [
+ ":*",
+ "//services/network:*",
+ ]
sources = [
- "media_stream_device_enumerator.h",
- "media_stream_device_enumerator_impl.cc",
- "media_stream_device_enumerator_impl.h",
+ "fake_ssl_client_socket.cc",
+ "fake_ssl_client_socket.h",
]
+ public_deps = [
+ "//base",
+ "//net",
+ "//net/traffic_annotation",
+ ]
+}
- deps = [
+source_set("net_address_utils") {
+ sources = [
+ "net_address_utils.cc",
+ "net_address_utils.h",
+ ]
+ public_deps = [
"//base",
- "//content/public/browser",
- "//third_party/blink/public/common",
+ "//net",
+ "//third_party/webrtc_overrides:webrtc_component",
]
}
-source_set("webrtc") {
+source_set("thread_wrapper") {
sources = [
- "media_stream_devices_controller.cc",
- "media_stream_devices_controller.h",
+ "thread_wrapper.cc",
+ "thread_wrapper.h",
]
+ public_deps = [
+ "//base",
+ "//third_party/webrtc_overrides:webrtc_component",
+ ]
+}
- public_deps = [ ":media_stream_device_enumerator" ]
+source_set("unit_tests") {
+ testonly = true
+
+ sources = [
+ "fake_ssl_client_socket_unittest.cc",
+ "thread_wrapper_unittest.cc",
+ ]
deps = [
- "//base",
- "//components/content_settings/core/common",
- "//components/permissions",
- "//content/public/browser",
- "//third_party/blink/public/common",
+ ":fake_ssl_socket",
+ ":thread_wrapper",
+ "//base/test:test_support",
+ "//net:test_support",
+ "//testing/gmock",
+ "//testing/gtest",
+ "//third_party/webrtc_overrides:metronome_like_task_queue_test",
]
- if (is_android) {
- deps += [ "//ui/android" ]
- }
}
diff --git a/chromium/components/webrtc/DEPS b/chromium/components/webrtc/DEPS
index a69a7830c62..c43fef44072 100644
--- a/chromium/components/webrtc/DEPS
+++ b/chromium/components/webrtc/DEPS
@@ -3,8 +3,11 @@ include_rules = [
"+components/permissions",
"+content/public/browser",
"+content/public/common",
+ "+net",
"+services/network/public/cpp/is_potentially_trustworthy.h",
"+third_party/blink/public/common",
"+third_party/blink/public/mojom",
+ "+third_party/webrtc",
+ "+third_party/webrtc_overrides",
"+ui/android",
]
diff --git a/chromium/components/webrtc/fake_ssl_client_socket.cc b/chromium/components/webrtc/fake_ssl_client_socket.cc
new file mode 100644
index 00000000000..ee11f24c48b
--- /dev/null
+++ b/chromium/components/webrtc/fake_ssl_client_socket.cc
@@ -0,0 +1,378 @@
+// Copyright (c) 2012 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.
+
+#include "components/webrtc/fake_ssl_client_socket.h"
+
+#include <stddef.h>
+#include <stdint.h>
+#include <cstdlib>
+#include <cstring>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/compiler_specific.h"
+#include "base/cxx17_backports.h"
+#include "base/logging.h"
+#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
+
+namespace webrtc {
+
+namespace {
+
+// The constants below were taken from libjingle's socketadapters.cc.
+// Basically, we do a "fake" SSL handshake to fool proxies into
+// thinking this is a real SSL connection.
+
+// This is a SSL v2 CLIENT_HELLO message.
+// TODO(juberti): Should this have a session id? The response doesn't have a
+// certificate, so the hello should have a session id.
+static const uint8_t kSslClientHello[] = {
+ 0x80, 0x46, // msg len
+ 0x01, // CLIENT_HELLO
+ 0x03, 0x01, // SSL 3.1
+ 0x00, 0x2d, // ciphersuite len
+ 0x00, 0x00, // session id len
+ 0x00, 0x10, // challenge len
+ 0x01, 0x00, 0x80, 0x03, 0x00, 0x80, 0x07, 0x00, 0xc0, // ciphersuites
+ 0x06, 0x00, 0x40, 0x02, 0x00, 0x80, 0x04, 0x00, 0x80, //
+ 0x00, 0x00, 0x04, 0x00, 0xfe, 0xff, 0x00, 0x00, 0x0a, //
+ 0x00, 0xfe, 0xfe, 0x00, 0x00, 0x09, 0x00, 0x00, 0x64, //
+ 0x00, 0x00, 0x62, 0x00, 0x00, 0x03, 0x00, 0x00, 0x06, //
+ 0x1f, 0x17, 0x0c, 0xa6, 0x2f, 0x00, 0x78, 0xfc, // challenge
+ 0x46, 0x55, 0x2e, 0xb1, 0x83, 0x39, 0xf1, 0xea //
+};
+
+// This is a TLSv1 SERVER_HELLO message.
+static const uint8_t kSslServerHello[] = {
+ 0x16, // handshake message
+ 0x03, 0x01, // SSL 3.1
+ 0x00, 0x4a, // message len
+ 0x02, // SERVER_HELLO
+ 0x00, 0x00, 0x46, // handshake len
+ 0x03, 0x01, // SSL 3.1
+ 0x42, 0x85, 0x45, 0xa7, 0x27, 0xa9, 0x5d, 0xa0, // server random
+ 0xb3, 0xc5, 0xe7, 0x53, 0xda, 0x48, 0x2b, 0x3f, //
+ 0xc6, 0x5a, 0xca, 0x89, 0xc1, 0x58, 0x52, 0xa1, //
+ 0x78, 0x3c, 0x5b, 0x17, 0x46, 0x00, 0x85, 0x3f, //
+ 0x20, // session id len
+ 0x0e, 0xd3, 0x06, 0x72, 0x5b, 0x5b, 0x1b, 0x5f, // session id
+ 0x15, 0xac, 0x13, 0xf9, 0x88, 0x53, 0x9d, 0x9b, //
+ 0xe8, 0x3d, 0x7b, 0x0c, 0x30, 0x32, 0x6e, 0x38, //
+ 0x4d, 0xa2, 0x75, 0x57, 0x41, 0x6c, 0x34, 0x5c, //
+ 0x00, 0x04, // RSA/RC4-128/MD5
+ 0x00 // null compression
+};
+
+// TODO(crbug/1183244): This annotation is not test specific but is for test. We
+// should fix it.
+constexpr net::NetworkTrafficAnnotationTag kTrafficAnnotation =
+ net::DefineNetworkTrafficAnnotation(
+ "test",
+ "Traffic annotation for FakeSSLClientSocket in jingle");
+
+scoped_refptr<net::DrainableIOBuffer> NewDrainableIOBufferWithSize(int size) {
+ return base::MakeRefCounted<net::DrainableIOBuffer>(
+ base::MakeRefCounted<net::IOBuffer>(size), size);
+}
+
+} // namespace
+
+base::StringPiece FakeSSLClientSocket::GetSslClientHello() {
+ return base::StringPiece(reinterpret_cast<const char*>(kSslClientHello),
+ base::size(kSslClientHello));
+}
+
+base::StringPiece FakeSSLClientSocket::GetSslServerHello() {
+ return base::StringPiece(reinterpret_cast<const char*>(kSslServerHello),
+ base::size(kSslServerHello));
+}
+
+FakeSSLClientSocket::FakeSSLClientSocket(
+ std::unique_ptr<net::StreamSocket> transport_socket)
+ : transport_socket_(std::move(transport_socket)),
+ next_handshake_state_(STATE_NONE),
+ handshake_completed_(false),
+ write_buf_(NewDrainableIOBufferWithSize(base::size(kSslClientHello))),
+ read_buf_(NewDrainableIOBufferWithSize(base::size(kSslServerHello))) {
+ CHECK(transport_socket_.get());
+ std::memcpy(write_buf_->data(), kSslClientHello, base::size(kSslClientHello));
+}
+
+FakeSSLClientSocket::~FakeSSLClientSocket() {}
+
+int FakeSSLClientSocket::Read(net::IOBuffer* buf,
+ int buf_len,
+ net::CompletionOnceCallback callback) {
+ DCHECK_EQ(next_handshake_state_, STATE_NONE);
+ DCHECK(handshake_completed_);
+ return transport_socket_->Read(buf, buf_len, std::move(callback));
+}
+
+int FakeSSLClientSocket::ReadIfReady(net::IOBuffer* buf,
+ int buf_len,
+ net::CompletionOnceCallback callback) {
+ DCHECK_EQ(next_handshake_state_, STATE_NONE);
+ DCHECK(handshake_completed_);
+ return transport_socket_->ReadIfReady(buf, buf_len, std::move(callback));
+}
+
+int FakeSSLClientSocket::CancelReadIfReady() {
+ DCHECK_EQ(next_handshake_state_, STATE_NONE);
+ DCHECK(handshake_completed_);
+ return transport_socket_->CancelReadIfReady();
+}
+
+int FakeSSLClientSocket::Write(
+ net::IOBuffer* buf,
+ int buf_len,
+ net::CompletionOnceCallback callback,
+ const net::NetworkTrafficAnnotationTag& traffic_annotation) {
+ DCHECK_EQ(next_handshake_state_, STATE_NONE);
+ DCHECK(handshake_completed_);
+ return transport_socket_->Write(buf, buf_len, std::move(callback),
+ traffic_annotation);
+}
+
+int FakeSSLClientSocket::SetReceiveBufferSize(int32_t size) {
+ return transport_socket_->SetReceiveBufferSize(size);
+}
+
+int FakeSSLClientSocket::SetSendBufferSize(int32_t size) {
+ return transport_socket_->SetSendBufferSize(size);
+}
+
+int FakeSSLClientSocket::Connect(net::CompletionOnceCallback callback) {
+ // We don't support synchronous operation, even if
+ // |transport_socket_| does.
+ DCHECK(!callback.is_null());
+ DCHECK_EQ(next_handshake_state_, STATE_NONE);
+ DCHECK(!handshake_completed_);
+ DCHECK(user_connect_callback_.is_null());
+ DCHECK_EQ(write_buf_->BytesConsumed(), 0);
+ DCHECK_EQ(read_buf_->BytesConsumed(), 0);
+
+ next_handshake_state_ = STATE_CONNECT;
+ int status = DoHandshakeLoop();
+ if (status == net::ERR_IO_PENDING)
+ user_connect_callback_ = std::move(callback);
+
+ return status;
+}
+
+int FakeSSLClientSocket::DoHandshakeLoop() {
+ DCHECK_NE(next_handshake_state_, STATE_NONE);
+ int status = net::OK;
+ do {
+ HandshakeState state = next_handshake_state_;
+ next_handshake_state_ = STATE_NONE;
+ switch (state) {
+ case STATE_CONNECT:
+ status = DoConnect();
+ break;
+ case STATE_SEND_CLIENT_HELLO:
+ status = DoSendClientHello();
+ break;
+ case STATE_VERIFY_SERVER_HELLO:
+ status = DoVerifyServerHello();
+ break;
+ default:
+ status = net::ERR_UNEXPECTED;
+ LOG(DFATAL) << "unexpected state: " << state;
+ break;
+ }
+ } while ((status != net::ERR_IO_PENDING) &&
+ (next_handshake_state_ != STATE_NONE));
+ return status;
+}
+
+void FakeSSLClientSocket::RunUserConnectCallback(int status) {
+ DCHECK_LE(status, net::OK);
+ next_handshake_state_ = STATE_NONE;
+ std::move(user_connect_callback_).Run(status);
+}
+
+void FakeSSLClientSocket::DoHandshakeLoopWithUserConnectCallback() {
+ int status = DoHandshakeLoop();
+ if (status != net::ERR_IO_PENDING) {
+ RunUserConnectCallback(status);
+ }
+}
+
+int FakeSSLClientSocket::DoConnect() {
+ int status = transport_socket_->Connect(base::BindOnce(
+ &FakeSSLClientSocket::OnConnectDone, base::Unretained(this)));
+ if (status != net::OK) {
+ return status;
+ }
+ ProcessConnectDone();
+ return net::OK;
+}
+
+void FakeSSLClientSocket::OnConnectDone(int status) {
+ DCHECK_NE(status, net::ERR_IO_PENDING);
+ DCHECK_LE(status, net::OK);
+ DCHECK(!user_connect_callback_.is_null());
+ if (status != net::OK) {
+ RunUserConnectCallback(status);
+ return;
+ }
+ ProcessConnectDone();
+ DoHandshakeLoopWithUserConnectCallback();
+}
+
+void FakeSSLClientSocket::ProcessConnectDone() {
+ DCHECK_EQ(write_buf_->BytesConsumed(), 0);
+ DCHECK_EQ(read_buf_->BytesConsumed(), 0);
+ next_handshake_state_ = STATE_SEND_CLIENT_HELLO;
+}
+
+int FakeSSLClientSocket::DoSendClientHello() {
+ int status = transport_socket_->Write(
+ write_buf_.get(), write_buf_->BytesRemaining(),
+ base::BindOnce(&FakeSSLClientSocket::OnSendClientHelloDone,
+ base::Unretained(this)),
+ kTrafficAnnotation);
+ if (status < net::OK) {
+ return status;
+ }
+ ProcessSendClientHelloDone(static_cast<size_t>(status));
+ return net::OK;
+}
+
+void FakeSSLClientSocket::OnSendClientHelloDone(int status) {
+ DCHECK_NE(status, net::ERR_IO_PENDING);
+ DCHECK(!user_connect_callback_.is_null());
+ if (status < net::OK) {
+ RunUserConnectCallback(status);
+ return;
+ }
+ ProcessSendClientHelloDone(static_cast<size_t>(status));
+ DoHandshakeLoopWithUserConnectCallback();
+}
+
+void FakeSSLClientSocket::ProcessSendClientHelloDone(size_t written) {
+ DCHECK_LE(written, static_cast<size_t>(write_buf_->BytesRemaining()));
+ DCHECK_EQ(read_buf_->BytesConsumed(), 0);
+ if (written < static_cast<size_t>(write_buf_->BytesRemaining())) {
+ next_handshake_state_ = STATE_SEND_CLIENT_HELLO;
+ write_buf_->DidConsume(written);
+ } else {
+ next_handshake_state_ = STATE_VERIFY_SERVER_HELLO;
+ }
+}
+
+int FakeSSLClientSocket::DoVerifyServerHello() {
+ int status = transport_socket_->Read(
+ read_buf_.get(), read_buf_->BytesRemaining(),
+ base::BindOnce(&FakeSSLClientSocket::OnVerifyServerHelloDone,
+ base::Unretained(this)));
+ if (status < net::OK) {
+ return status;
+ }
+ size_t read = static_cast<size_t>(status);
+ return ProcessVerifyServerHelloDone(read);
+}
+
+void FakeSSLClientSocket::OnVerifyServerHelloDone(int status) {
+ DCHECK_NE(status, net::ERR_IO_PENDING);
+ DCHECK(!user_connect_callback_.is_null());
+ if (status < net::OK) {
+ RunUserConnectCallback(status);
+ return;
+ }
+ size_t read = static_cast<size_t>(status);
+ status = ProcessVerifyServerHelloDone(read);
+ if (status < net::OK) {
+ RunUserConnectCallback(status);
+ return;
+ }
+ if (handshake_completed_) {
+ RunUserConnectCallback(net::OK);
+ } else {
+ DoHandshakeLoopWithUserConnectCallback();
+ }
+}
+
+net::Error FakeSSLClientSocket::ProcessVerifyServerHelloDone(size_t read) {
+ DCHECK_LE(read, static_cast<size_t>(read_buf_->BytesRemaining()));
+ if (read == 0U) {
+ return net::ERR_UNEXPECTED;
+ }
+ const uint8_t* expected_data_start =
+ &kSslServerHello[base::size(kSslServerHello) -
+ read_buf_->BytesRemaining()];
+ if (std::memcmp(expected_data_start, read_buf_->data(), read) != 0) {
+ return net::ERR_UNEXPECTED;
+ }
+ if (read < static_cast<size_t>(read_buf_->BytesRemaining())) {
+ next_handshake_state_ = STATE_VERIFY_SERVER_HELLO;
+ read_buf_->DidConsume(read);
+ } else {
+ next_handshake_state_ = STATE_NONE;
+ handshake_completed_ = true;
+ }
+ return net::OK;
+}
+
+void FakeSSLClientSocket::Disconnect() {
+ transport_socket_->Disconnect();
+ next_handshake_state_ = STATE_NONE;
+ handshake_completed_ = false;
+ user_connect_callback_.Reset();
+ write_buf_->SetOffset(0);
+ read_buf_->SetOffset(0);
+}
+
+bool FakeSSLClientSocket::IsConnected() const {
+ return handshake_completed_ && transport_socket_->IsConnected();
+}
+
+bool FakeSSLClientSocket::IsConnectedAndIdle() const {
+ return handshake_completed_ && transport_socket_->IsConnectedAndIdle();
+}
+
+int FakeSSLClientSocket::GetPeerAddress(net::IPEndPoint* address) const {
+ return transport_socket_->GetPeerAddress(address);
+}
+
+int FakeSSLClientSocket::GetLocalAddress(net::IPEndPoint* address) const {
+ return transport_socket_->GetLocalAddress(address);
+}
+
+const net::NetLogWithSource& FakeSSLClientSocket::NetLog() const {
+ return transport_socket_->NetLog();
+}
+
+bool FakeSSLClientSocket::WasEverUsed() const {
+ return transport_socket_->WasEverUsed();
+}
+
+bool FakeSSLClientSocket::WasAlpnNegotiated() const {
+ return transport_socket_->WasAlpnNegotiated();
+}
+
+net::NextProto FakeSSLClientSocket::GetNegotiatedProtocol() const {
+ return transport_socket_->GetNegotiatedProtocol();
+}
+
+bool FakeSSLClientSocket::GetSSLInfo(net::SSLInfo* ssl_info) {
+ return transport_socket_->GetSSLInfo(ssl_info);
+}
+
+void FakeSSLClientSocket::GetConnectionAttempts(
+ net::ConnectionAttempts* out) const {
+ out->clear();
+}
+
+int64_t FakeSSLClientSocket::GetTotalReceivedBytes() const {
+ NOTIMPLEMENTED();
+ return 0;
+}
+
+void FakeSSLClientSocket::ApplySocketTag(const net::SocketTag& tag) {
+ NOTIMPLEMENTED();
+}
+
+} // namespace webrtc
diff --git a/chromium/components/webrtc/fake_ssl_client_socket.h b/chromium/components/webrtc/fake_ssl_client_socket.h
new file mode 100644
index 00000000000..cb399359fbd
--- /dev/null
+++ b/chromium/components/webrtc/fake_ssl_client_socket.h
@@ -0,0 +1,125 @@
+// Copyright (c) 2012 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.
+//
+// This StreamSocket implementation is to be used with servers that
+// accept connections on port 443 but don't really use SSL. For
+// example, the Google Talk servers do this to bypass proxies. (The
+// connection is upgraded to TLS as part of the XMPP negotiation, so
+// security is preserved.) A "fake" SSL handshake is done immediately
+// after connection to fool proxies into thinking that this is a real
+// SSL connection.
+//
+// NOTE: This StreamSocket implementation does *not* do a real SSL
+// handshake nor does it do any encryption!
+
+#ifndef COMPONENTS_WEBRTC_FAKE_SSL_CLIENT_SOCKET_H_
+#define COMPONENTS_WEBRTC_FAKE_SSL_CLIENT_SOCKET_H_
+
+#include <stdint.h>
+
+#include <cstddef>
+#include <memory>
+
+#include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
+#include "base/strings/string_piece.h"
+#include "net/base/completion_once_callback.h"
+#include "net/base/net_errors.h"
+#include "net/socket/stream_socket.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
+
+namespace net {
+class DrainableIOBuffer;
+class SSLInfo;
+} // namespace net
+
+namespace webrtc {
+
+class FakeSSLClientSocket : public net::StreamSocket {
+ public:
+ explicit FakeSSLClientSocket(
+ std::unique_ptr<net::StreamSocket> transport_socket);
+
+ ~FakeSSLClientSocket() override;
+
+ // Exposed for testing.
+ static base::StringPiece GetSslClientHello();
+ static base::StringPiece GetSslServerHello();
+
+ // net::StreamSocket implementation.
+ int Read(net::IOBuffer* buf,
+ int buf_len,
+ net::CompletionOnceCallback callback) override;
+ int ReadIfReady(net::IOBuffer* buf,
+ int buf_len,
+ net::CompletionOnceCallback callback) override;
+ int CancelReadIfReady() override;
+ int Write(
+ net::IOBuffer* buf,
+ int buf_len,
+ net::CompletionOnceCallback callback,
+ const net::NetworkTrafficAnnotationTag& traffic_annotation) override;
+ int SetReceiveBufferSize(int32_t size) override;
+ int SetSendBufferSize(int32_t size) override;
+ int Connect(net::CompletionOnceCallback callback) override;
+ void Disconnect() override;
+ bool IsConnected() const override;
+ bool IsConnectedAndIdle() const override;
+ int GetPeerAddress(net::IPEndPoint* address) const override;
+ int GetLocalAddress(net::IPEndPoint* address) const override;
+ const net::NetLogWithSource& NetLog() const override;
+ bool WasEverUsed() const override;
+ bool WasAlpnNegotiated() const override;
+ net::NextProto GetNegotiatedProtocol() const override;
+ bool GetSSLInfo(net::SSLInfo* ssl_info) override;
+ void GetConnectionAttempts(net::ConnectionAttempts* out) const override;
+ void ClearConnectionAttempts() override {}
+ void AddConnectionAttempts(const net::ConnectionAttempts& attempts) override {
+ }
+ int64_t GetTotalReceivedBytes() const override;
+ void ApplySocketTag(const net::SocketTag& tag) override;
+
+ private:
+ enum HandshakeState {
+ STATE_NONE,
+ STATE_CONNECT,
+ STATE_SEND_CLIENT_HELLO,
+ STATE_VERIFY_SERVER_HELLO,
+ };
+
+ int DoHandshakeLoop();
+ void RunUserConnectCallback(int status);
+ void DoHandshakeLoopWithUserConnectCallback();
+
+ int DoConnect();
+ void OnConnectDone(int status);
+ void ProcessConnectDone();
+
+ int DoSendClientHello();
+ void OnSendClientHelloDone(int status);
+ void ProcessSendClientHelloDone(size_t written);
+
+ int DoVerifyServerHello();
+ void OnVerifyServerHelloDone(int status);
+ net::Error ProcessVerifyServerHelloDone(size_t read);
+
+ std::unique_ptr<net::StreamSocket> transport_socket_;
+
+ // During the handshake process, holds a value from HandshakeState.
+ // STATE_NONE otherwise.
+ HandshakeState next_handshake_state_;
+
+ // True iff we're connected and we've finished the handshake.
+ bool handshake_completed_;
+
+ // The callback passed to Connect().
+ net::CompletionOnceCallback user_connect_callback_;
+
+ scoped_refptr<net::DrainableIOBuffer> write_buf_;
+ scoped_refptr<net::DrainableIOBuffer> read_buf_;
+};
+
+} // namespace webrtc
+
+#endif // COMPONENTS_WEBRTC_FAKE_SSL_CLIENT_SOCKET_H_
diff --git a/chromium/components/webrtc/fake_ssl_client_socket_unittest.cc b/chromium/components/webrtc/fake_ssl_client_socket_unittest.cc
new file mode 100644
index 00000000000..ca9f06e5933
--- /dev/null
+++ b/chromium/components/webrtc/fake_ssl_client_socket_unittest.cc
@@ -0,0 +1,359 @@
+// Copyright (c) 2012 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.
+
+#include "components/webrtc/fake_ssl_client_socket.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <algorithm>
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "base/cxx17_backports.h"
+#include "base/memory/ref_counted.h"
+#include "base/test/task_environment.h"
+#include "net/base/completion_once_callback.h"
+#include "net/base/completion_repeating_callback.h"
+#include "net/base/io_buffer.h"
+#include "net/base/ip_address.h"
+#include "net/base/test_completion_callback.h"
+#include "net/log/net_log_source.h"
+#include "net/log/net_log_with_source.h"
+#include "net/socket/socket_tag.h"
+#include "net/socket/socket_test_util.h"
+#include "net/socket/stream_socket.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace webrtc {
+
+namespace {
+
+using ::testing::Return;
+using ::testing::ReturnRef;
+
+// Used by RunUnsuccessfulHandshakeTestHelper. Represents where in
+// the handshake step an error should be inserted.
+enum HandshakeErrorLocation {
+ CONNECT_ERROR,
+ SEND_CLIENT_HELLO_ERROR,
+ VERIFY_SERVER_HELLO_ERROR,
+};
+
+// Private error codes appended to the net::Error set.
+enum {
+ // An error representing a server hello that has been corrupted in
+ // transit.
+ ERR_MALFORMED_SERVER_HELLO = -15000,
+};
+
+// Used by PassThroughMethods test.
+class MockClientSocket : public net::StreamSocket {
+ public:
+ ~MockClientSocket() override {}
+
+ MOCK_METHOD3(Read, int(net::IOBuffer*, int, net::CompletionOnceCallback));
+ MOCK_METHOD4(Write,
+ int(net::IOBuffer*,
+ int,
+ net::CompletionOnceCallback,
+ const net::NetworkTrafficAnnotationTag&));
+ MOCK_METHOD1(SetReceiveBufferSize, int(int32_t));
+ MOCK_METHOD1(SetSendBufferSize, int(int32_t));
+ MOCK_METHOD1(Connect, int(net::CompletionOnceCallback));
+ MOCK_METHOD0(Disconnect, void());
+ MOCK_CONST_METHOD0(IsConnected, bool());
+ MOCK_CONST_METHOD0(IsConnectedAndIdle, bool());
+ MOCK_CONST_METHOD1(GetPeerAddress, int(net::IPEndPoint*));
+ MOCK_CONST_METHOD1(GetLocalAddress, int(net::IPEndPoint*));
+ MOCK_CONST_METHOD0(NetLog, const net::NetLogWithSource&());
+ MOCK_CONST_METHOD0(WasEverUsed, bool());
+ MOCK_CONST_METHOD0(UsingTCPFastOpen, bool());
+ MOCK_CONST_METHOD0(NumBytesRead, int64_t());
+ MOCK_CONST_METHOD0(GetConnectTimeMicros, base::TimeDelta());
+ MOCK_CONST_METHOD0(WasAlpnNegotiated, bool());
+ MOCK_CONST_METHOD0(GetNegotiatedProtocol, net::NextProto());
+ MOCK_METHOD1(GetSSLInfo, bool(net::SSLInfo*));
+ MOCK_CONST_METHOD1(GetConnectionAttempts, void(net::ConnectionAttempts*));
+ MOCK_METHOD0(ClearConnectionAttempts, void());
+ MOCK_METHOD1(AddConnectionAttempts, void(const net::ConnectionAttempts&));
+ MOCK_CONST_METHOD0(GetTotalReceivedBytes, int64_t());
+ MOCK_METHOD1(ApplySocketTag, void(const net::SocketTag&));
+};
+
+// Break up |data| into a bunch of chunked MockReads/Writes and push
+// them onto |ops|.
+template <net::MockReadWriteType type>
+void AddChunkedOps(base::StringPiece data,
+ size_t chunk_size,
+ net::IoMode mode,
+ std::vector<net::MockReadWrite<type>>* ops) {
+ DCHECK_GT(chunk_size, 0U);
+ size_t offset = 0;
+ while (offset < data.size()) {
+ size_t bounded_chunk_size = std::min(data.size() - offset, chunk_size);
+ ops->push_back(net::MockReadWrite<type>(mode, data.data() + offset,
+ bounded_chunk_size));
+ offset += bounded_chunk_size;
+ }
+}
+
+class FakeSSLClientSocketTest : public testing::Test {
+ protected:
+ FakeSSLClientSocketTest() {}
+
+ ~FakeSSLClientSocketTest() override {}
+
+ std::unique_ptr<net::StreamSocket> MakeClientSocket() {
+ return mock_client_socket_factory_.CreateTransportClientSocket(
+ net::AddressList(), nullptr, nullptr, nullptr, net::NetLogSource());
+ }
+
+ void SetData(const net::MockConnect& mock_connect,
+ std::vector<net::MockRead>* reads,
+ std::vector<net::MockWrite>* writes) {
+ static_socket_data_provider_ =
+ std::make_unique<net::StaticSocketDataProvider>(*reads, *writes);
+ static_socket_data_provider_->set_connect_data(mock_connect);
+ mock_client_socket_factory_.AddSocketDataProvider(
+ static_socket_data_provider_.get());
+ }
+
+ void ExpectStatus(net::IoMode mode,
+ int expected_status,
+ int immediate_status,
+ net::TestCompletionCallback* test_completion_callback) {
+ if (mode == net::ASYNC) {
+ EXPECT_EQ(net::ERR_IO_PENDING, immediate_status);
+ int status = test_completion_callback->WaitForResult();
+ EXPECT_EQ(expected_status, status);
+ } else {
+ EXPECT_EQ(expected_status, immediate_status);
+ }
+ }
+
+ // Sets up the mock socket to generate a successful handshake
+ // (sliced up according to the parameters) and makes sure the
+ // FakeSSLClientSocket behaves as expected.
+ void RunSuccessfulHandshakeTest(net::IoMode mode,
+ size_t read_chunk_size,
+ size_t write_chunk_size,
+ int num_resets) {
+ base::StringPiece ssl_client_hello =
+ FakeSSLClientSocket::GetSslClientHello();
+ base::StringPiece ssl_server_hello =
+ FakeSSLClientSocket::GetSslServerHello();
+
+ net::MockConnect mock_connect(mode, net::OK);
+ std::vector<net::MockRead> reads;
+ std::vector<net::MockWrite> writes;
+ static const char kReadTestData[] = "read test data";
+ static const char kWriteTestData[] = "write test data";
+ for (int i = 0; i < num_resets + 1; ++i) {
+ SCOPED_TRACE(i);
+ AddChunkedOps(ssl_server_hello, read_chunk_size, mode, &reads);
+ AddChunkedOps(ssl_client_hello, write_chunk_size, mode, &writes);
+ reads.push_back(
+ net::MockRead(mode, kReadTestData, base::size(kReadTestData)));
+ writes.push_back(
+ net::MockWrite(mode, kWriteTestData, base::size(kWriteTestData)));
+ }
+ SetData(mock_connect, &reads, &writes);
+
+ FakeSSLClientSocket fake_ssl_client_socket(MakeClientSocket());
+
+ for (int i = 0; i < num_resets + 1; ++i) {
+ SCOPED_TRACE(i);
+ net::TestCompletionCallback connect_callback;
+ int status = fake_ssl_client_socket.Connect(connect_callback.callback());
+ if (mode == net::ASYNC) {
+ EXPECT_FALSE(fake_ssl_client_socket.IsConnected());
+ }
+ ExpectStatus(mode, net::OK, status, &connect_callback);
+ if (fake_ssl_client_socket.IsConnected()) {
+ int read_len = base::size(kReadTestData);
+ int read_buf_len = 2 * read_len;
+ auto read_buf = base::MakeRefCounted<net::IOBuffer>(read_buf_len);
+
+ net::TestCompletionCallback read_callback;
+ int read_status = fake_ssl_client_socket.Read(
+ read_buf.get(), read_buf_len, read_callback.callback());
+ ExpectStatus(mode, read_len, read_status, &read_callback);
+
+ auto write_buf =
+ base::MakeRefCounted<net::StringIOBuffer>(kWriteTestData);
+ net::TestCompletionCallback write_callback;
+ int write_status = fake_ssl_client_socket.Write(
+ write_buf.get(), base::size(kWriteTestData),
+ write_callback.callback(), TRAFFIC_ANNOTATION_FOR_TESTS);
+ ExpectStatus(mode, base::size(kWriteTestData), write_status,
+ &write_callback);
+ } else {
+ ADD_FAILURE();
+ }
+ fake_ssl_client_socket.Disconnect();
+ EXPECT_FALSE(fake_ssl_client_socket.IsConnected());
+ }
+ }
+
+ // Sets up the mock socket to generate an unsuccessful handshake
+ // FakeSSLClientSocket fails as expected.
+ void RunUnsuccessfulHandshakeTestHelper(net::IoMode mode,
+ int error,
+ HandshakeErrorLocation location) {
+ DCHECK_NE(error, net::OK);
+ base::StringPiece ssl_client_hello =
+ FakeSSLClientSocket::GetSslClientHello();
+ base::StringPiece ssl_server_hello =
+ FakeSSLClientSocket::GetSslServerHello();
+
+ net::MockConnect mock_connect(mode, net::OK);
+ std::vector<net::MockRead> reads;
+ std::vector<net::MockWrite> writes;
+ const size_t kChunkSize = 1;
+ AddChunkedOps(ssl_server_hello, kChunkSize, mode, &reads);
+ AddChunkedOps(ssl_client_hello, kChunkSize, mode, &writes);
+ switch (location) {
+ case CONNECT_ERROR:
+ mock_connect.result = error;
+ writes.clear();
+ reads.clear();
+ break;
+ case SEND_CLIENT_HELLO_ERROR: {
+ // Use a fixed index for repeatability.
+ size_t index = 100 % writes.size();
+ writes[index].result = error;
+ writes[index].data = NULL;
+ writes[index].data_len = 0;
+ writes.resize(index + 1);
+ reads.clear();
+ break;
+ }
+ case VERIFY_SERVER_HELLO_ERROR: {
+ // Use a fixed index for repeatability.
+ size_t index = 50 % reads.size();
+ if (error == ERR_MALFORMED_SERVER_HELLO) {
+ static const char kBadData[] = "BAD_DATA";
+ reads[index].data = kBadData;
+ reads[index].data_len = base::size(kBadData);
+ } else {
+ reads[index].result = error;
+ reads[index].data = NULL;
+ reads[index].data_len = 0;
+ }
+ reads.resize(index + 1);
+ if (error == net::ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ) {
+ static const char kDummyData[] = "DUMMY";
+ reads.push_back(net::MockRead(mode, kDummyData));
+ }
+ break;
+ }
+ }
+ SetData(mock_connect, &reads, &writes);
+
+ FakeSSLClientSocket fake_ssl_client_socket(MakeClientSocket());
+
+ // The two errors below are interpreted by FakeSSLClientSocket as
+ // an unexpected event.
+ int expected_status =
+ ((error == net::ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ) ||
+ (error == ERR_MALFORMED_SERVER_HELLO))
+ ? net::ERR_UNEXPECTED
+ : error;
+
+ net::TestCompletionCallback test_completion_callback;
+ int status =
+ fake_ssl_client_socket.Connect(test_completion_callback.callback());
+ EXPECT_FALSE(fake_ssl_client_socket.IsConnected());
+ ExpectStatus(mode, expected_status, status, &test_completion_callback);
+ EXPECT_FALSE(fake_ssl_client_socket.IsConnected());
+ }
+
+ void RunUnsuccessfulHandshakeTest(int error,
+ HandshakeErrorLocation location) {
+ RunUnsuccessfulHandshakeTestHelper(net::SYNCHRONOUS, error, location);
+ RunUnsuccessfulHandshakeTestHelper(net::ASYNC, error, location);
+ }
+
+ // MockTCPClientSocket needs a message loop.
+ base::test::SingleThreadTaskEnvironment task_environment_;
+
+ net::MockClientSocketFactory mock_client_socket_factory_;
+ std::unique_ptr<net::StaticSocketDataProvider> static_socket_data_provider_;
+};
+
+TEST_F(FakeSSLClientSocketTest, PassThroughMethods) {
+ std::unique_ptr<MockClientSocket> mock_client_socket(new MockClientSocket());
+ const int kReceiveBufferSize = 10;
+ const int kSendBufferSize = 20;
+ net::IPEndPoint ip_endpoint(net::IPAddress::IPv4AllZeros(), 80);
+ const int kPeerAddress = 30;
+ net::NetLogWithSource net_log;
+ EXPECT_CALL(*mock_client_socket, SetReceiveBufferSize(kReceiveBufferSize));
+ EXPECT_CALL(*mock_client_socket, SetSendBufferSize(kSendBufferSize));
+ EXPECT_CALL(*mock_client_socket, GetPeerAddress(&ip_endpoint))
+ .WillOnce(Return(kPeerAddress));
+ EXPECT_CALL(*mock_client_socket, NetLog()).WillOnce(ReturnRef(net_log));
+
+ // Takes ownership of |mock_client_socket|.
+ FakeSSLClientSocket fake_ssl_client_socket(std::move(mock_client_socket));
+ fake_ssl_client_socket.SetReceiveBufferSize(kReceiveBufferSize);
+ fake_ssl_client_socket.SetSendBufferSize(kSendBufferSize);
+ EXPECT_EQ(kPeerAddress, fake_ssl_client_socket.GetPeerAddress(&ip_endpoint));
+ EXPECT_EQ(&net_log, &fake_ssl_client_socket.NetLog());
+}
+
+TEST_F(FakeSSLClientSocketTest, SuccessfulHandshakeSync) {
+ for (size_t i = 1; i < 100; i += 3) {
+ SCOPED_TRACE(i);
+ for (size_t j = 1; j < 100; j += 5) {
+ SCOPED_TRACE(j);
+ RunSuccessfulHandshakeTest(net::SYNCHRONOUS, i, j, 0);
+ }
+ }
+}
+
+TEST_F(FakeSSLClientSocketTest, SuccessfulHandshakeAsync) {
+ for (size_t i = 1; i < 100; i += 7) {
+ SCOPED_TRACE(i);
+ for (size_t j = 1; j < 100; j += 9) {
+ SCOPED_TRACE(j);
+ RunSuccessfulHandshakeTest(net::ASYNC, i, j, 0);
+ }
+ }
+}
+
+TEST_F(FakeSSLClientSocketTest, ResetSocket) {
+ RunSuccessfulHandshakeTest(net::ASYNC, 1, 2, 3);
+}
+
+TEST_F(FakeSSLClientSocketTest, UnsuccessfulHandshakeConnectError) {
+ RunUnsuccessfulHandshakeTest(net::ERR_ACCESS_DENIED, CONNECT_ERROR);
+}
+
+TEST_F(FakeSSLClientSocketTest, UnsuccessfulHandshakeWriteError) {
+ RunUnsuccessfulHandshakeTest(net::ERR_OUT_OF_MEMORY, SEND_CLIENT_HELLO_ERROR);
+}
+
+TEST_F(FakeSSLClientSocketTest, UnsuccessfulHandshakeReadError) {
+ RunUnsuccessfulHandshakeTest(net::ERR_CONNECTION_CLOSED,
+ VERIFY_SERVER_HELLO_ERROR);
+}
+
+TEST_F(FakeSSLClientSocketTest, PeerClosedDuringHandshake) {
+ RunUnsuccessfulHandshakeTest(net::ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ,
+ VERIFY_SERVER_HELLO_ERROR);
+}
+
+TEST_F(FakeSSLClientSocketTest, MalformedServerHello) {
+ RunUnsuccessfulHandshakeTest(ERR_MALFORMED_SERVER_HELLO,
+ VERIFY_SERVER_HELLO_ERROR);
+}
+
+} // namespace
+
+} // namespace webrtc
diff --git a/chromium/components/webrtc/media_stream_devices_controller.cc b/chromium/components/webrtc/media_stream_devices_controller.cc
index c818458f413..261a62cdf27 100644
--- a/chromium/components/webrtc/media_stream_devices_controller.cc
+++ b/chromium/components/webrtc/media_stream_devices_controller.cc
@@ -10,6 +10,7 @@
#include "base/bind.h"
#include "base/metrics/histogram_functions.h"
+#include "build/build_config.h"
#include "components/permissions/permission_manager.h"
#include "components/permissions/permission_result.h"
#include "components/permissions/permissions_client.h"
@@ -21,7 +22,7 @@
#include "services/network/public/cpp/is_potentially_trustworthy.h"
#include "third_party/blink/public/mojom/permissions_policy/permissions_policy.mojom.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "components/permissions/android/android_permission_util.h"
#include "ui/android/window_android.h"
#endif
@@ -138,9 +139,8 @@ void MediaStreamDevicesController::RequestPermissions(
}
}
- permission_manager->RequestPermissions(
- content_settings_types, rfh, request.security_origin,
- request.user_gesture,
+ permission_manager->RequestPermissionsFromCurrentDocument(
+ content_settings_types, rfh, request.user_gesture,
base::BindOnce(
&MediaStreamDevicesController::RequestAndroidPermissionsIfNeeded,
web_contents, std::move(controller), will_prompt_for_audio,
@@ -184,7 +184,7 @@ void MediaStreamDevicesController::RequestAndroidPermissionsIfNeeded(
bool did_prompt_for_audio,
bool did_prompt_for_video,
const std::vector<ContentSetting>& responses) {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// If either audio or video was previously allowed and Chrome no longer has
// the necessary permissions, show a infobar to attempt to address this
// mismatch.
@@ -245,7 +245,7 @@ void MediaStreamDevicesController::RequestAndroidPermissionsIfNeeded(
#endif
}
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// static
void MediaStreamDevicesController::AndroidOSPromptAnswered(
std::unique_ptr<MediaStreamDevicesController> controller,
@@ -263,7 +263,7 @@ void MediaStreamDevicesController::AndroidOSPromptAnswered(
controller->PromptAnsweredGroupedRequest(responses);
}
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
bool MediaStreamDevicesController::ShouldRequestAudio() const {
return audio_setting_ == CONTENT_SETTING_ASK;
@@ -443,7 +443,7 @@ ContentSetting MediaStreamDevicesController::GetContentSetting(
bool MediaStreamDevicesController::IsUserAcceptAllowed(
ContentSettingsType content_type) const {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
ui::WindowAndroid* window_android =
web_contents_->GetNativeView()->GetWindowAndroid();
if (!window_android)
diff --git a/chromium/components/webrtc/media_stream_devices_controller.h b/chromium/components/webrtc/media_stream_devices_controller.h
index a6fd83f1cb2..4abb8741d86 100644
--- a/chromium/components/webrtc/media_stream_devices_controller.h
+++ b/chromium/components/webrtc/media_stream_devices_controller.h
@@ -65,13 +65,13 @@ class MediaStreamDevicesController {
bool did_prompt_for_video,
const std::vector<ContentSetting>& responses);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Called when the Android OS-level prompt is answered.
static void AndroidOSPromptAnswered(
std::unique_ptr<MediaStreamDevicesController> controller,
std::vector<ContentSetting> responses,
bool android_prompt_granted);
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
// Returns true if audio/video should be requested through the
// PermissionManager. We won't try to request permission if the request is
diff --git a/chromium/components/webrtc/net_address_utils.cc b/chromium/components/webrtc/net_address_utils.cc
new file mode 100644
index 00000000000..3d1deafc344
--- /dev/null
+++ b/chromium/components/webrtc/net_address_utils.cc
@@ -0,0 +1,118 @@
+// Copyright (c) 2012 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.
+
+#include "components/webrtc/net_address_utils.h"
+
+#include <stdint.h>
+
+#include <memory>
+
+#include "base/json/json_reader.h"
+#include "base/json/json_writer.h"
+#include "base/values.h"
+#include "net/base/ip_address.h"
+#include "net/base/ip_endpoint.h"
+#include "third_party/webrtc/api/candidate.h"
+#include "third_party/webrtc/rtc_base/byte_order.h"
+#include "third_party/webrtc/rtc_base/socket_address.h"
+
+namespace webrtc {
+
+bool IPEndPointToSocketAddress(const net::IPEndPoint& ip_endpoint,
+ rtc::SocketAddress* address) {
+ sockaddr_storage addr;
+ socklen_t len = sizeof(addr);
+ return ip_endpoint.ToSockAddr(reinterpret_cast<sockaddr*>(&addr), &len) &&
+ rtc::SocketAddressFromSockAddrStorage(addr, address);
+}
+
+bool SocketAddressToIPEndPoint(const rtc::SocketAddress& address,
+ net::IPEndPoint* ip_endpoint) {
+ sockaddr_storage addr;
+ int size = address.ToSockAddrStorage(&addr);
+ return (size > 0) &&
+ ip_endpoint->FromSockAddr(reinterpret_cast<sockaddr*>(&addr), size);
+}
+
+rtc::IPAddress NetIPAddressToRtcIPAddress(const net::IPAddress& ip_address) {
+ if (ip_address.IsIPv4()) {
+ uint32_t address;
+ memcpy(&address, ip_address.bytes().data(), sizeof(uint32_t));
+ address = rtc::NetworkToHost32(address);
+ return rtc::IPAddress(address);
+ }
+ if (ip_address.IsIPv6()) {
+ in6_addr address;
+ memcpy(&address, ip_address.bytes().data(), sizeof(in6_addr));
+ return rtc::IPAddress(address);
+ }
+ return rtc::IPAddress();
+}
+
+net::IPAddress RtcIPAddressToNetIPAddress(const rtc::IPAddress& ip_address) {
+ rtc::SocketAddress socket_address(ip_address, 0);
+ net::IPEndPoint ip_endpoint;
+ webrtc::SocketAddressToIPEndPoint(socket_address, &ip_endpoint);
+ return ip_endpoint.address();
+}
+
+std::string SerializeP2PCandidate(const cricket::Candidate& candidate) {
+ // TODO(sergeyu): Use SDP to format candidates?
+ base::DictionaryValue value;
+ value.SetString("ip", candidate.address().ipaddr().ToString());
+ value.SetInteger("port", candidate.address().port());
+ value.SetString("type", candidate.type());
+ value.SetString("protocol", candidate.protocol());
+ value.SetString("username", candidate.username());
+ value.SetString("password", candidate.password());
+ value.SetDouble("preference", candidate.preference());
+ value.SetInteger("generation", candidate.generation());
+
+ std::string result;
+ base::JSONWriter::Write(value, &result);
+ return result;
+}
+
+bool DeserializeP2PCandidate(const std::string& candidate_str,
+ cricket::Candidate* candidate) {
+ std::unique_ptr<base::Value> value(base::JSONReader::ReadDeprecated(
+ candidate_str, base::JSON_ALLOW_TRAILING_COMMAS));
+ if (!value.get() || !value->is_dict()) {
+ return false;
+ }
+
+ base::DictionaryValue* dic_value =
+ static_cast<base::DictionaryValue*>(value.get());
+
+ std::string ip;
+ int port = 0;
+ std::string type;
+ std::string protocol;
+ std::string username;
+ std::string password;
+ absl::optional<double> preference = dic_value->FindDoubleKey("preference");
+ int generation = 0;
+
+ if (!dic_value->GetString("ip", &ip) ||
+ !dic_value->GetInteger("port", &port) ||
+ !dic_value->GetString("type", &type) ||
+ !dic_value->GetString("protocol", &protocol) ||
+ !dic_value->GetString("username", &username) ||
+ !dic_value->GetString("password", &password) || !preference ||
+ !dic_value->GetInteger("generation", &generation)) {
+ return false;
+ }
+
+ candidate->set_address(rtc::SocketAddress(ip, port));
+ candidate->set_type(type);
+ candidate->set_protocol(protocol);
+ candidate->set_username(username);
+ candidate->set_password(password);
+ candidate->set_preference(static_cast<float>(*preference));
+ candidate->set_generation(generation);
+
+ return true;
+}
+
+} // namespace webrtc
diff --git a/chromium/components/webrtc/net_address_utils.h b/chromium/components/webrtc/net_address_utils.h
new file mode 100644
index 00000000000..a31f1ac60d2
--- /dev/null
+++ b/chromium/components/webrtc/net_address_utils.h
@@ -0,0 +1,46 @@
+// Copyright (c) 2011 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.
+
+#ifndef COMPONENTS_WEBRTC_NET_ADDRESS_UTILS_H_
+#define COMPONENTS_WEBRTC_NET_ADDRESS_UTILS_H_
+
+#include <string>
+
+#include "third_party/webrtc/rtc_base/ip_address.h"
+
+namespace net {
+class IPAddress;
+class IPEndPoint;
+} // namespace net
+
+namespace rtc {
+class SocketAddress;
+} // namespace rtc
+
+namespace cricket {
+class Candidate;
+} // namespace cricket
+
+namespace webrtc {
+
+// Chromium and libjingle represent socket addresses differently. The
+// following two functions are used to convert addresses from one
+// representation to another.
+bool IPEndPointToSocketAddress(const net::IPEndPoint& ip_endpoint,
+ rtc::SocketAddress* address);
+bool SocketAddressToIPEndPoint(const rtc::SocketAddress& address,
+ net::IPEndPoint* ip_endpoint);
+
+rtc::IPAddress NetIPAddressToRtcIPAddress(const net::IPAddress& ip_address);
+
+net::IPAddress RtcIPAddressToNetIPAddress(const rtc::IPAddress& ip_address);
+
+// Helper functions to serialize and deserialize P2P candidates.
+std::string SerializeP2PCandidate(const cricket::Candidate& candidate);
+bool DeserializeP2PCandidate(const std::string& address,
+ cricket::Candidate* candidate);
+
+} // namespace webrtc
+
+#endif // COMPONENTS_WEBRTC_NET_ADDRESS_UTILS_H_
diff --git a/chromium/components/webrtc/thread_wrapper.cc b/chromium/components/webrtc/thread_wrapper.cc
new file mode 100644
index 00000000000..eae08b9c4d4
--- /dev/null
+++ b/chromium/components/webrtc/thread_wrapper.cc
@@ -0,0 +1,493 @@
+// Copyright (c) 2012 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.
+
+#include "components/webrtc/thread_wrapper.h"
+
+#include <stddef.h>
+#include <stdint.h>
+#include <memory>
+
+#include "base/bind.h"
+#include "base/callback_helpers.h"
+#include "base/cxx17_backports.h"
+#include "base/lazy_instance.h"
+#include "base/memory/raw_ptr.h"
+#include "base/sequence_checker.h"
+#include "base/thread_annotations.h"
+#include "base/threading/thread_local.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
+#include "base/trace_event/trace_event.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "third_party/webrtc/rtc_base/physical_socket_server.h"
+
+namespace webrtc {
+namespace {
+constexpr base::TimeDelta kTaskLatencySampleDuration = base::Seconds(3);
+}
+
+const base::Feature kThreadWrapperUsesMetronome{
+ "ThreadWrapperUsesMetronome", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Class intended to conditionally live for the duration of ThreadWrapper
+// that periodically captures task latencies (definition in docs for
+// SetLatencyAndTaskDurationCallbacks).
+class ThreadWrapper::PostTaskLatencySampler {
+ public:
+ PostTaskLatencySampler(
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ SampledDurationCallback task_latency_callback)
+ : task_runner_(task_runner),
+ task_latency_callback_(std::move(task_latency_callback)) {
+ ScheduleDelayedSample();
+ }
+
+ bool ShouldSampleNextTaskDuration() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(current_);
+ bool time_to_sample = should_sample_next_task_duration_;
+ should_sample_next_task_duration_ = false;
+ return time_to_sample;
+ }
+
+ private:
+ void ScheduleDelayedSample() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(current_);
+ task_runner_->PostDelayedTask(
+ FROM_HERE,
+ base::BindOnce(&PostTaskLatencySampler::TakeSample,
+ base::Unretained(this)),
+ kTaskLatencySampleDuration);
+ }
+
+ void TakeSample() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(current_);
+ task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(&PostTaskLatencySampler::FinishSample,
+ base::Unretained(this), base::TimeTicks::Now()));
+ }
+
+ void FinishSample(base::TimeTicks post_timestamp) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(current_);
+ task_latency_callback_.Run(base::TimeTicks::Now() - post_timestamp);
+ ScheduleDelayedSample();
+ should_sample_next_task_duration_ = true;
+ }
+
+ SEQUENCE_CHECKER(current_);
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+ base::RepeatingCallback<void(base::TimeDelta)> task_latency_callback_
+ GUARDED_BY_CONTEXT(current_);
+ bool should_sample_next_task_duration_ GUARDED_BY_CONTEXT(current_) = false;
+};
+
+struct ThreadWrapper::PendingSend {
+ explicit PendingSend(const rtc::Message& message_value)
+ : sending_thread(ThreadWrapper::current()),
+ message(message_value),
+ done_event(base::WaitableEvent::ResetPolicy::MANUAL,
+ base::WaitableEvent::InitialState::NOT_SIGNALED) {
+ DCHECK(sending_thread);
+ }
+
+ raw_ptr<ThreadWrapper> sending_thread;
+ rtc::Message message;
+ base::WaitableEvent done_event;
+};
+
+base::LazyInstance<base::ThreadLocalPointer<ThreadWrapper>>::DestructorAtExit
+ g_jingle_thread_wrapper = LAZY_INSTANCE_INITIALIZER;
+
+// static
+void ThreadWrapper::EnsureForCurrentMessageLoop(
+ scoped_refptr<blink::MetronomeSource> metronome_source) {
+ if (ThreadWrapper::current() == nullptr) {
+ std::unique_ptr<ThreadWrapper> wrapper = ThreadWrapper::WrapTaskRunner(
+ metronome_source, base::ThreadTaskRunnerHandle::Get());
+ base::CurrentThread::Get()->AddDestructionObserver(wrapper.release());
+ }
+
+ DCHECK_EQ(rtc::Thread::Current(), current());
+ DCHECK_EQ(current()->metronome_source_, metronome_source);
+}
+
+std::unique_ptr<ThreadWrapper> ThreadWrapper::WrapTaskRunner(
+ scoped_refptr<blink::MetronomeSource> metronome_source,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
+ DCHECK(!ThreadWrapper::current());
+ DCHECK(task_runner->BelongsToCurrentThread());
+
+ std::unique_ptr<ThreadWrapper> result(
+ new ThreadWrapper(std::move(metronome_source), task_runner));
+ g_jingle_thread_wrapper.Get().Set(result.get());
+ return result;
+}
+
+// static
+ThreadWrapper* ThreadWrapper::current() {
+ return g_jingle_thread_wrapper.Get().Get();
+}
+
+void ThreadWrapper::SetLatencyAndTaskDurationCallbacks(
+ SampledDurationCallback task_latency_callback,
+ SampledDurationCallback task_duration_callback) {
+ task_latency_callback_ = std::move(task_latency_callback);
+ task_duration_callback_ = std::move(task_duration_callback);
+}
+
+ThreadWrapper::ThreadWrapper(
+ scoped_refptr<blink::MetronomeSource> metronome_source,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner)
+ : Thread(std::make_unique<rtc::PhysicalSocketServer>()),
+ metronome_source_(std::move(metronome_source)),
+ task_runner_(task_runner),
+ send_allowed_(false),
+ last_task_id_(0),
+ pending_send_event_(base::WaitableEvent::ResetPolicy::MANUAL,
+ base::WaitableEvent::InitialState::NOT_SIGNALED) {
+ DCHECK(task_runner->BelongsToCurrentThread());
+ DCHECK(!rtc::Thread::Current());
+ weak_ptr_ = weak_ptr_factory_.GetWeakPtr();
+ rtc::ThreadManager::Add(this);
+ SafeWrapCurrent();
+}
+
+ThreadWrapper::~ThreadWrapper() {
+ DCHECK_EQ(this, ThreadWrapper::current());
+ DCHECK_EQ(this, rtc::Thread::Current());
+
+ UnwrapCurrent();
+ rtc::ThreadManager::Instance()->SetCurrentThread(nullptr);
+ rtc::ThreadManager::Remove(this);
+ g_jingle_thread_wrapper.Get().Set(nullptr);
+
+ Clear(nullptr, rtc::MQID_ANY, nullptr);
+ coalesced_tasks_.Clear();
+}
+
+void ThreadWrapper::WillDestroyCurrentMessageLoop() {
+ delete this;
+}
+
+void ThreadWrapper::Post(const rtc::Location& posted_from,
+ rtc::MessageHandler* handler,
+ uint32_t message_id,
+ rtc::MessageData* data,
+ bool time_sensitive) {
+ PostTaskInternal(posted_from, 0, handler, message_id, data);
+}
+
+void ThreadWrapper::PostDelayed(const rtc::Location& posted_from,
+ int delay_ms,
+ rtc::MessageHandler* handler,
+ uint32_t message_id,
+ rtc::MessageData* data) {
+ PostTaskInternal(posted_from, delay_ms, handler, message_id, data);
+}
+
+void ThreadWrapper::Clear(rtc::MessageHandler* handler,
+ uint32_t id,
+ rtc::MessageList* removed) {
+ base::AutoLock auto_lock(lock_);
+
+ for (MessagesQueue::iterator it = messages_.begin(); it != messages_.end();) {
+ MessagesQueue::iterator next = it;
+ ++next;
+
+ if (it->second.Match(handler, id)) {
+ if (removed) {
+ removed->push_back(it->second);
+ } else {
+ delete it->second.pdata;
+ }
+ messages_.erase(it);
+ }
+
+ it = next;
+ }
+
+ for (std::list<PendingSend*>::iterator it = pending_send_messages_.begin();
+ it != pending_send_messages_.end();) {
+ std::list<PendingSend*>::iterator next = it;
+ ++next;
+
+ if ((*it)->message.Match(handler, id)) {
+ if (removed) {
+ removed->push_back((*it)->message);
+ } else {
+ delete (*it)->message.pdata;
+ }
+ (*it)->done_event.Signal();
+ pending_send_messages_.erase(it);
+ }
+
+ it = next;
+ }
+}
+
+void ThreadWrapper::Dispatch(rtc::Message* message) {
+ TRACE_EVENT2("webrtc", "ThreadWrapper::Dispatch", "src_file_and_line",
+ message->posted_from.file_and_line(), "src_func",
+ message->posted_from.function_name());
+ message->phandler->OnMessage(message);
+}
+
+void ThreadWrapper::Send(const rtc::Location& posted_from,
+ rtc::MessageHandler* handler,
+ uint32_t id,
+ rtc::MessageData* data) {
+ ThreadWrapper* current_thread = ThreadWrapper::current();
+ DCHECK(current_thread != nullptr) << "Send() can be called only from a "
+ "thread that has ThreadWrapper.";
+
+ rtc::Message message;
+ message.posted_from = posted_from;
+ message.phandler = handler;
+ message.message_id = id;
+ message.pdata = data;
+
+ if (current_thread == this) {
+ Dispatch(&message);
+ return;
+ }
+
+ // Send message from a thread different than |this|.
+
+ // Allow inter-thread send only from threads that have
+ // |send_allowed_| flag set.
+ DCHECK(current_thread->send_allowed_)
+ << "Send()'ing synchronous "
+ "messages is not allowed from the current thread.";
+
+ PendingSend pending_send(message);
+ {
+ base::AutoLock auto_lock(lock_);
+ pending_send_messages_.push_back(&pending_send);
+ }
+
+ // Need to signal |pending_send_event_| here in case the thread is
+ // sending message to another thread.
+ pending_send_event_.Signal();
+ task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(&ThreadWrapper::ProcessPendingSends, weak_ptr_));
+
+ while (!pending_send.done_event.IsSignaled()) {
+ base::WaitableEvent* events[] = {&pending_send.done_event,
+ &current_thread->pending_send_event_};
+ size_t event = base::WaitableEvent::WaitMany(events, base::size(events));
+ DCHECK(event == 0 || event == 1);
+
+ if (event == 1)
+ current_thread->ProcessPendingSends();
+ }
+}
+
+void ThreadWrapper::ProcessPendingSends() {
+ while (true) {
+ PendingSend* pending_send = nullptr;
+ {
+ base::AutoLock auto_lock(lock_);
+ if (!pending_send_messages_.empty()) {
+ pending_send = pending_send_messages_.front();
+ pending_send_messages_.pop_front();
+ } else {
+ // Reset the event while |lock_| is still locked.
+ pending_send_event_.Reset();
+ break;
+ }
+ }
+ if (pending_send) {
+ Dispatch(&pending_send->message);
+ pending_send->done_event.Signal();
+ }
+ }
+}
+
+void ThreadWrapper::PostTaskInternal(const rtc::Location& posted_from,
+ int delay_ms,
+ rtc::MessageHandler* handler,
+ uint32_t message_id,
+ rtc::MessageData* data) {
+ int task_id;
+ rtc::Message message;
+ message.posted_from = posted_from;
+ message.phandler = handler;
+ message.message_id = message_id;
+ message.pdata = data;
+ {
+ base::AutoLock auto_lock(lock_);
+ task_id = ++last_task_id_;
+ messages_.insert(std::pair<int, rtc::Message>(task_id, message));
+ }
+
+ if (delay_ms <= 0) {
+ task_runner_->PostTask(
+ FROM_HERE, base::BindOnce(&ThreadWrapper::RunTask, weak_ptr_, task_id));
+ } else {
+ task_runner_->PostDelayedTaskAt(
+ base::subtle::PostDelayedTaskPassKey(), FROM_HERE,
+ base::BindOnce(&ThreadWrapper::RunTask, weak_ptr_, task_id),
+ base::TimeTicks::Now() + base::Milliseconds(delay_ms),
+ base::subtle::DelayPolicy::kPrecise);
+ }
+}
+
+void ThreadWrapper::PostTask(std::unique_ptr<webrtc::QueuedTask> task) {
+ task_runner_->PostTask(
+ FROM_HERE, base::BindOnce(&ThreadWrapper::RunTaskQueueTask, weak_ptr_,
+ std::move(task)));
+}
+
+void ThreadWrapper::PostDelayedTask(std::unique_ptr<webrtc::QueuedTask> task,
+ uint32_t milliseconds) {
+ base::TimeTicks target_time =
+ base::TimeTicks::Now() + base::Milliseconds(milliseconds);
+ if (metronome_source_) {
+ // Coalesce tasks onto the metronome.
+ base::TimeTicks snapped_target_time =
+ metronome_source_->GetTimeSnappedToNextMetronomeTick(target_time);
+ if (coalesced_tasks_.QueueDelayedTask(target_time, std::move(task),
+ snapped_target_time)) {
+ task_runner_->PostDelayedTaskAt(
+ base::subtle::PostDelayedTaskPassKey(), FROM_HERE,
+ base::BindOnce(&ThreadWrapper::RunCoalescedTaskQueueTasks, weak_ptr_,
+ snapped_target_time),
+ snapped_target_time, base::subtle::DelayPolicy::kPrecise);
+ }
+ return;
+ }
+ // Do not coalesce tasks onto the metronome.
+ task_runner_->PostDelayedTaskAt(
+ base::subtle::PostDelayedTaskPassKey(), FROM_HERE,
+ base::BindOnce(&ThreadWrapper::RunTaskQueueTask, weak_ptr_,
+ std::move(task)),
+ target_time, base::subtle::DelayPolicy::kPrecise);
+}
+
+void ThreadWrapper::PostDelayedHighPrecisionTask(
+ std::unique_ptr<webrtc::QueuedTask> task,
+ uint32_t milliseconds) {
+ base::TimeTicks target_time =
+ base::TimeTicks::Now() + base::Milliseconds(milliseconds);
+ task_runner_->PostDelayedTaskAt(
+ base::subtle::PostDelayedTaskPassKey(), FROM_HERE,
+ base::BindOnce(&ThreadWrapper::RunTaskQueueTask, weak_ptr_,
+ std::move(task)),
+ target_time, base::subtle::DelayPolicy::kPrecise);
+}
+
+absl::optional<base::TimeTicks> ThreadWrapper::PrepareRunTask() {
+ if (!latency_sampler_ && task_latency_callback_) {
+ latency_sampler_ = std::make_unique<PostTaskLatencySampler>(
+ task_runner_, std::move(task_latency_callback_));
+ }
+ absl::optional<base::TimeTicks> task_start_timestamp;
+ if (!task_duration_callback_.is_null() && latency_sampler_ &&
+ latency_sampler_->ShouldSampleNextTaskDuration()) {
+ task_start_timestamp = base::TimeTicks::Now();
+ }
+ return task_start_timestamp;
+}
+
+void ThreadWrapper::RunTaskQueueTask(std::unique_ptr<webrtc::QueuedTask> task) {
+ absl::optional<base::TimeTicks> task_start_timestamp = PrepareRunTask();
+
+ // Follow QueuedTask::Run() semantics: delete if it returns true, release
+ // otherwise.
+ if (task->Run())
+ task.reset();
+ else
+ task.release();
+
+ FinalizeRunTask(std::move(task_start_timestamp));
+}
+
+void ThreadWrapper::RunCoalescedTaskQueueTasks(base::TimeTicks scheduled_time) {
+ // base::Unretained(this) is safe here because these callbacks are only used
+ // for the duration of the RunScheduledTasks() call.
+ coalesced_tasks_.RunScheduledTasks(
+ scheduled_time,
+ base::BindRepeating(&ThreadWrapper::PrepareRunTask,
+ base::Unretained(this)),
+ base::BindRepeating(&ThreadWrapper::FinalizeRunTask,
+ base::Unretained(this)));
+}
+
+void ThreadWrapper::RunTask(int task_id) {
+ absl::optional<base::TimeTicks> task_start_timestamp = PrepareRunTask();
+
+ RunTaskInternal(task_id);
+
+ FinalizeRunTask(std::move(task_start_timestamp));
+}
+
+void ThreadWrapper::FinalizeRunTask(
+ absl::optional<base::TimeTicks> task_start_timestamp) {
+ if (task_start_timestamp.has_value())
+ task_duration_callback_.Run(base::TimeTicks::Now() - *task_start_timestamp);
+}
+
+void ThreadWrapper::RunTaskInternal(int task_id) {
+ bool have_message = false;
+ rtc::Message message;
+ {
+ base::AutoLock auto_lock(lock_);
+ MessagesQueue::iterator it = messages_.find(task_id);
+ if (it != messages_.end()) {
+ have_message = true;
+ message = it->second;
+ messages_.erase(it);
+ }
+ }
+
+ if (have_message) {
+ if (message.message_id == rtc::MQID_DISPOSE) {
+ DCHECK(message.phandler == nullptr);
+ delete message.pdata;
+ } else {
+ Dispatch(&message);
+ }
+ }
+}
+
+bool ThreadWrapper::IsQuitting() {
+ NOTIMPLEMENTED_LOG_ONCE();
+ return false;
+}
+
+// All methods below are marked as not reached. See comments in the
+// header for more details.
+void ThreadWrapper::Quit() {
+ NOTREACHED();
+}
+
+void ThreadWrapper::Restart() {
+ NOTREACHED();
+}
+
+bool ThreadWrapper::Get(rtc::Message*, int, bool) {
+ NOTREACHED();
+ return false;
+}
+
+bool ThreadWrapper::Peek(rtc::Message*, int) {
+ NOTREACHED();
+ return false;
+}
+
+int ThreadWrapper::GetDelay() {
+ NOTREACHED();
+ return 0;
+}
+
+void ThreadWrapper::Stop() {
+ NOTREACHED();
+}
+
+void ThreadWrapper::Run() {
+ NOTREACHED();
+}
+
+} // namespace webrtc
diff --git a/chromium/components/webrtc/thread_wrapper.h b/chromium/components/webrtc/thread_wrapper.h
new file mode 100644
index 00000000000..8d48e101712
--- /dev/null
+++ b/chromium/components/webrtc/thread_wrapper.h
@@ -0,0 +1,204 @@
+// Copyright (c) 2012 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.
+
+#ifndef COMPONENTS_WEBRTC_THREAD_WRAPPER_H_
+#define COMPONENTS_WEBRTC_THREAD_WRAPPER_H_
+
+#include <stdint.h>
+
+#include <list>
+#include <map>
+#include <memory>
+
+#include "base/callback_forward.h"
+#include "base/compiler_specific.h"
+#include "base/feature_list.h"
+#include "base/memory/weak_ptr.h"
+#include "base/synchronization/lock.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/task/current_thread.h"
+#include "base/task/single_thread_task_runner.h"
+#include "base/time/time.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "third_party/webrtc/rtc_base/thread.h"
+#include "third_party/webrtc_overrides/coalesced_tasks.h"
+#include "third_party/webrtc_overrides/metronome_source.h"
+
+namespace webrtc {
+
+// Whether ThreadWrapper should schedule low-precision tasks on the metronome.
+// Default: disabled.
+extern const base::Feature kThreadWrapperUsesMetronome;
+
+// ThreadWrapper implements rtc::Thread interface on top of
+// Chromium's SingleThreadTaskRunner interface. Currently only the bare minimum
+// that is used by P2P part of libjingle is implemented. There are two ways to
+// create this object:
+//
+// - Call EnsureForCurrentMessageLoop(). This approach works only on threads
+// that have MessageLoop In this case ThreadWrapper deletes itself
+// automatically when MessageLoop is destroyed.
+// - Using ThreadWrapper() constructor. In this case the creating code
+// must pass a valid task runner for the current thread and also delete the
+// wrapper later.
+class ThreadWrapper : public base::CurrentThread::DestructionObserver,
+ public rtc::Thread {
+ public:
+ // A repeating callback whose TimeDelta argument indicates a duration sample.
+ // What the duration represents is contextual.
+ using SampledDurationCallback =
+ base::RepeatingCallback<void(base::TimeDelta)>;
+
+ // Create ThreadWrapper for the current thread if it hasn't been created
+ // yet. The thread wrapper is destroyed automatically when the current
+ // MessageLoop is destroyed.
+ static void EnsureForCurrentMessageLoop(
+ scoped_refptr<blink::MetronomeSource> metronome_source = nullptr);
+
+ // Creates ThreadWrapper for |task_runner| that runs tasks on the
+ // current thread.
+ static std::unique_ptr<ThreadWrapper> WrapTaskRunner(
+ scoped_refptr<blink::MetronomeSource> metronome_source,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner);
+
+ // Returns thread wrapper for the current thread or nullptr if it doesn't
+ // exist.
+ static ThreadWrapper* current();
+
+ // Sets task latency & duration sample callbacks intended to gather UMA
+ // statistics. Samples are acquired periodically every several seconds by
+ // ThreadWrapper. In this context,
+ // * task latency is defined as the duration between the moment a task is
+ // scheduled from ThreadWrapper's task runner, and the moment
+ // it begins running.
+ // * task duration is defined as the duration between the moment the
+ // ThreadWrapper begins running a task and the moment it ends
+ // executing it. It only measures durations of tasks posted to rtc::Thread.
+ // The passed callbacks are called in the ThreadWrapper's task runner
+ // context.
+ void SetLatencyAndTaskDurationCallbacks(
+ SampledDurationCallback task_latency_callback,
+ SampledDurationCallback task_duration_callback);
+
+ ThreadWrapper(const ThreadWrapper&) = delete;
+ ThreadWrapper& operator=(const ThreadWrapper&) = delete;
+
+ ~ThreadWrapper() override;
+
+ // Sets whether the thread can be used to send messages
+ // synchronously to another thread using Send() method. Set to false
+ // by default to avoid potential jankiness when Send() used on
+ // renderer thread. It should be set explicitly for threads that
+ // need to call Send() for other threads.
+ void set_send_allowed(bool allowed) { send_allowed_ = allowed; }
+
+ // CurrentThread::DestructionObserver implementation.
+ void WillDestroyCurrentMessageLoop() override;
+
+ // rtc::MessageQueue overrides.
+ void Post(const rtc::Location& posted_from,
+ rtc::MessageHandler* phandler,
+ uint32_t id,
+ rtc::MessageData* pdata,
+ bool time_sensitive) override;
+ void PostDelayed(const rtc::Location& posted_from,
+ int delay_ms,
+ rtc::MessageHandler* handler,
+ uint32_t id,
+ rtc::MessageData* data) override;
+ void Clear(rtc::MessageHandler* handler,
+ uint32_t id,
+ rtc::MessageList* removed) override;
+ void Dispatch(rtc::Message* message) override;
+ void Send(const rtc::Location& posted_from,
+ rtc::MessageHandler* handler,
+ uint32_t id,
+ rtc::MessageData* data) override;
+
+ // Quitting is not supported (see below); this method performs
+ // NOTIMPLEMENTED_LOG_ONCE() and returns false.
+ // TODO(https://crbug.com/webrtc/10364): When rtc::MessageQueue::Post()
+ // returns a bool, !IsQuitting() will not be needed to infer success and we
+ // may implement this as NOTREACHED() like the rest of the methods.
+ bool IsQuitting() override;
+ // Following methods are not supported. They are overriden just to
+ // ensure that they are not called (each of them contain NOTREACHED
+ // in the body). Some of this methods can be implemented if it
+ // becomes necessary to use libjingle code that calls them.
+ void Quit() override;
+ void Restart() override;
+ bool Get(rtc::Message* message, int delay_ms, bool process_io) override;
+ bool Peek(rtc::Message* message, int delay_ms) override;
+ int GetDelay() override;
+
+ // rtc::Thread overrides.
+ void Stop() override;
+ void Run() override;
+
+ private:
+ typedef std::map<int, rtc::Message> MessagesQueue;
+ struct PendingSend;
+ class PostTaskLatencySampler;
+
+ ThreadWrapper(scoped_refptr<blink::MetronomeSource> metronome_source,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner);
+
+ void PostTaskInternal(const rtc::Location& posted_from,
+ int delay_ms,
+ rtc::MessageHandler* handler,
+ uint32_t message_id,
+ rtc::MessageData* data);
+ void RunTask(int task_id);
+ void RunTaskInternal(int task_id);
+ void ProcessPendingSends();
+
+ // TaskQueueBase overrides.
+ void PostTask(std::unique_ptr<webrtc::QueuedTask> task) override;
+ void PostDelayedTask(std::unique_ptr<webrtc::QueuedTask> task,
+ uint32_t milliseconds) override;
+ void PostDelayedHighPrecisionTask(std::unique_ptr<webrtc::QueuedTask> task,
+ uint32_t milliseconds) override;
+
+ // Executes WebRTC queued tasks from TaskQueueBase overrides on
+ // |task_runner_|.
+ void RunTaskQueueTask(std::unique_ptr<webrtc::QueuedTask> task);
+ void RunCoalescedTaskQueueTasks(base::TimeTicks scheduled_time);
+
+ // Called before a task runs, returns an opaque optional timestamp which
+ // should be passed into FinalizeRunTask.
+ absl::optional<base::TimeTicks> PrepareRunTask();
+ // Called after a task has run. Move the return value of PrepareRunTask as
+ // |task_start_timestamp|.
+ void FinalizeRunTask(absl::optional<base::TimeTicks> task_start_timestamp);
+
+ // TODO(https://crbug.com/1296138): When MetronomeSource is simplified,
+ // snapping to metronome ticks will be a static function, and we can remove
+ // this object reference.
+ const scoped_refptr<blink::MetronomeSource> metronome_source_;
+ // Task runner used to execute messages posted on this thread.
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+
+ bool send_allowed_;
+
+ // |lock_| must be locked when accessing |messages_|.
+ base::Lock lock_;
+ int last_task_id_;
+ MessagesQueue messages_;
+ std::list<PendingSend*> pending_send_messages_;
+ base::WaitableEvent pending_send_event_;
+ std::unique_ptr<PostTaskLatencySampler> latency_sampler_;
+ SampledDurationCallback task_latency_callback_;
+ SampledDurationCallback task_duration_callback_;
+ // If |metronome_source_| is used, low precision tasks are coalesced onto
+ // metronome ticks and stored in |coalesced_tasks_| until they are ready to
+ // run.
+ blink::CoalescedTasks coalesced_tasks_;
+
+ base::WeakPtr<ThreadWrapper> weak_ptr_;
+ base::WeakPtrFactory<ThreadWrapper> weak_ptr_factory_{this};
+};
+
+} // namespace webrtc
+
+#endif // COMPONENTS_WEBRTC_THREAD_WRAPPER_H_
diff --git a/chromium/components/webrtc/thread_wrapper_unittest.cc b/chromium/components/webrtc/thread_wrapper_unittest.cc
new file mode 100644
index 00000000000..d620340c0fd
--- /dev/null
+++ b/chromium/components/webrtc/thread_wrapper_unittest.cc
@@ -0,0 +1,347 @@
+// Copyright (c) 2012 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.
+
+#include "components/webrtc/thread_wrapper.h"
+
+#include <stdint.h>
+
+#include "base/bind.h"
+#include "base/compiler_specific.h"
+#include "base/memory/raw_ptr.h"
+#include "base/run_loop.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/task/single_thread_task_runner.h"
+#include "base/task/thread_pool.h"
+#include "base/test/task_environment.h"
+#include "base/threading/thread.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/webrtc_overrides/metronome_source.h"
+#include "third_party/webrtc_overrides/test/metronome_like_task_queue_test.h"
+
+using ::blink::MetronomeLikeTaskQueueTest;
+using ::testing::DoAll;
+using ::testing::InSequence;
+using ::testing::InvokeWithoutArgs;
+using ::testing::Mock;
+
+namespace webrtc {
+
+static const uint32_t kTestMessage1 = 1;
+static const uint32_t kTestMessage2 = 2;
+
+static const int kTestDelayMs1 = 10;
+static const int kTestDelayMs2 = 20;
+static const int kTestDelayMs3 = 30;
+static const int kTestDelayMs4 = 40;
+static const int kMaxTestDelay = 40;
+
+namespace {
+
+class MockMessageHandler : public rtc::MessageHandlerAutoCleanup {
+ public:
+ MOCK_METHOD1(OnMessage, void(rtc::Message* msg));
+};
+
+MATCHER_P3(MatchMessage, handler, message_id, data, "") {
+ return arg->phandler == handler && arg->message_id == message_id &&
+ arg->pdata == data;
+}
+
+ACTION(DeleteMessageData) {
+ delete arg0->pdata;
+}
+
+// Helper class used in the Dispose test.
+class DeletableObject {
+ public:
+ DeletableObject(bool* deleted) : deleted_(deleted) { *deleted = false; }
+
+ ~DeletableObject() { *deleted_ = true; }
+
+ private:
+ raw_ptr<bool> deleted_;
+};
+
+class ThreadWrapperTest : public testing::Test {
+ public:
+ // This method is used by the SendDuringSend test. It sends message to the
+ // main thread synchronously using Send().
+ void PingMainThread() {
+ rtc::MessageData* data = new rtc::MessageData();
+ MockMessageHandler handler;
+
+ EXPECT_CALL(handler, OnMessage(MatchMessage(&handler, kTestMessage2, data)))
+ .WillOnce(DeleteMessageData());
+ thread_->Send(RTC_FROM_HERE, &handler, kTestMessage2, data);
+ }
+
+ protected:
+ ThreadWrapperTest() : thread_(nullptr) {}
+
+ void SetUp() override {
+ ThreadWrapper::EnsureForCurrentMessageLoop();
+ thread_ = rtc::Thread::Current();
+ }
+
+ // ThreadWrapper destroys itself when |message_loop_| is destroyed.
+ base::test::SingleThreadTaskEnvironment task_environment_;
+ raw_ptr<rtc::Thread> thread_;
+ MockMessageHandler handler1_;
+ MockMessageHandler handler2_;
+};
+
+TEST_F(ThreadWrapperTest, Post) {
+ rtc::MessageData* data1 = new rtc::MessageData();
+ rtc::MessageData* data2 = new rtc::MessageData();
+ rtc::MessageData* data3 = new rtc::MessageData();
+ rtc::MessageData* data4 = new rtc::MessageData();
+
+ thread_->Post(RTC_FROM_HERE, &handler1_, kTestMessage1, data1);
+ thread_->Post(RTC_FROM_HERE, &handler1_, kTestMessage2, data2);
+ thread_->Post(RTC_FROM_HERE, &handler2_, kTestMessage1, data3);
+ thread_->Post(RTC_FROM_HERE, &handler2_, kTestMessage1, data4);
+
+ InSequence in_seq;
+
+ EXPECT_CALL(handler1_,
+ OnMessage(MatchMessage(&handler1_, kTestMessage1, data1)))
+ .WillOnce(DeleteMessageData());
+ EXPECT_CALL(handler1_,
+ OnMessage(MatchMessage(&handler1_, kTestMessage2, data2)))
+ .WillOnce(DeleteMessageData());
+ EXPECT_CALL(handler2_,
+ OnMessage(MatchMessage(&handler2_, kTestMessage1, data3)))
+ .WillOnce(DeleteMessageData());
+ EXPECT_CALL(handler2_,
+ OnMessage(MatchMessage(&handler2_, kTestMessage1, data4)))
+ .WillOnce(DeleteMessageData());
+
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST_F(ThreadWrapperTest, PostDelayed) {
+ rtc::MessageData* data1 = new rtc::MessageData();
+ rtc::MessageData* data2 = new rtc::MessageData();
+ rtc::MessageData* data3 = new rtc::MessageData();
+ rtc::MessageData* data4 = new rtc::MessageData();
+
+ thread_->PostDelayed(RTC_FROM_HERE, kTestDelayMs1, &handler1_, kTestMessage1,
+ data1);
+ thread_->PostDelayed(RTC_FROM_HERE, kTestDelayMs2, &handler1_, kTestMessage2,
+ data2);
+ thread_->PostDelayed(RTC_FROM_HERE, kTestDelayMs3, &handler2_, kTestMessage1,
+ data3);
+ thread_->PostDelayed(RTC_FROM_HERE, kTestDelayMs4, &handler2_, kTestMessage1,
+ data4);
+
+ InSequence in_seq;
+
+ EXPECT_CALL(handler1_,
+ OnMessage(MatchMessage(&handler1_, kTestMessage1, data1)))
+ .WillOnce(DeleteMessageData());
+ EXPECT_CALL(handler1_,
+ OnMessage(MatchMessage(&handler1_, kTestMessage2, data2)))
+ .WillOnce(DeleteMessageData());
+ EXPECT_CALL(handler2_,
+ OnMessage(MatchMessage(&handler2_, kTestMessage1, data3)))
+ .WillOnce(DeleteMessageData());
+ EXPECT_CALL(handler2_,
+ OnMessage(MatchMessage(&handler2_, kTestMessage1, data4)))
+ .WillOnce(DeleteMessageData());
+
+ base::RunLoop run_loop;
+ task_environment_.GetMainThreadTaskRunner()->PostDelayedTask(
+ FROM_HERE, run_loop.QuitClosure(), base::Milliseconds(kMaxTestDelay));
+ run_loop.Run();
+}
+
+TEST_F(ThreadWrapperTest, Clear) {
+ thread_->Post(RTC_FROM_HERE, &handler1_, kTestMessage1, NULL);
+ thread_->Post(RTC_FROM_HERE, &handler1_, kTestMessage2, NULL);
+ thread_->Post(RTC_FROM_HERE, &handler2_, kTestMessage1, NULL);
+ thread_->Post(RTC_FROM_HERE, &handler2_, kTestMessage2, NULL);
+
+ thread_->Clear(&handler1_, kTestMessage2);
+
+ InSequence in_seq;
+
+ rtc::MessageData* null_data = NULL;
+ EXPECT_CALL(handler1_,
+ OnMessage(MatchMessage(&handler1_, kTestMessage1, null_data)))
+ .WillOnce(DeleteMessageData());
+ EXPECT_CALL(handler2_,
+ OnMessage(MatchMessage(&handler2_, kTestMessage1, null_data)))
+ .WillOnce(DeleteMessageData());
+ EXPECT_CALL(handler2_,
+ OnMessage(MatchMessage(&handler2_, kTestMessage2, null_data)))
+ .WillOnce(DeleteMessageData());
+
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST_F(ThreadWrapperTest, ClearDelayed) {
+ thread_->PostDelayed(RTC_FROM_HERE, kTestDelayMs1, &handler1_, kTestMessage1,
+ NULL);
+ thread_->PostDelayed(RTC_FROM_HERE, kTestDelayMs2, &handler1_, kTestMessage2,
+ NULL);
+ thread_->PostDelayed(RTC_FROM_HERE, kTestDelayMs3, &handler2_, kTestMessage1,
+ NULL);
+ thread_->PostDelayed(RTC_FROM_HERE, kTestDelayMs4, &handler2_, kTestMessage1,
+ NULL);
+
+ thread_->Clear(&handler1_, kTestMessage2);
+
+ InSequence in_seq;
+
+ rtc::MessageData* null_data = NULL;
+ EXPECT_CALL(handler1_,
+ OnMessage(MatchMessage(&handler1_, kTestMessage1, null_data)))
+ .WillOnce(DeleteMessageData());
+ EXPECT_CALL(handler2_,
+ OnMessage(MatchMessage(&handler2_, kTestMessage1, null_data)))
+ .WillOnce(DeleteMessageData());
+ EXPECT_CALL(handler2_,
+ OnMessage(MatchMessage(&handler2_, kTestMessage1, null_data)))
+ .WillOnce(DeleteMessageData());
+
+ base::RunLoop run_loop;
+ task_environment_.GetMainThreadTaskRunner()->PostDelayedTask(
+ FROM_HERE, run_loop.QuitClosure(), base::Milliseconds(kMaxTestDelay));
+ run_loop.Run();
+}
+
+// Verify that the queue is cleared when a handler is destroyed.
+TEST_F(ThreadWrapperTest, ClearDestroyed) {
+ MockMessageHandler* handler_ptr;
+ {
+ MockMessageHandler handler;
+ handler_ptr = &handler;
+ thread_->Post(RTC_FROM_HERE, &handler, kTestMessage1, NULL);
+ }
+ rtc::MessageList removed;
+ thread_->Clear(handler_ptr, rtc::MQID_ANY, &removed);
+ DCHECK_EQ(0U, removed.size());
+}
+
+// Verify that Send() calls handler synchronously when called on the
+// same thread.
+TEST_F(ThreadWrapperTest, SendSameThread) {
+ rtc::MessageData* data = new rtc::MessageData();
+
+ EXPECT_CALL(handler1_,
+ OnMessage(MatchMessage(&handler1_, kTestMessage1, data)))
+ .WillOnce(DeleteMessageData());
+ thread_->Send(RTC_FROM_HERE, &handler1_, kTestMessage1, data);
+}
+
+void InitializeWrapperForNewThread(rtc::Thread** thread,
+ base::WaitableEvent* done_event) {
+ ThreadWrapper::EnsureForCurrentMessageLoop();
+ ThreadWrapper::current()->set_send_allowed(true);
+ *thread = ThreadWrapper::current();
+ done_event->Signal();
+}
+
+// Verify that Send() calls handler synchronously when called for a
+// different thread.
+TEST_F(ThreadWrapperTest, SendToOtherThread) {
+ ThreadWrapper::current()->set_send_allowed(true);
+
+ base::Thread second_thread("adWrapperTest");
+ second_thread.Start();
+
+ base::WaitableEvent initialized_event(
+ base::WaitableEvent::ResetPolicy::MANUAL,
+ base::WaitableEvent::InitialState::NOT_SIGNALED);
+ rtc::Thread* target;
+ second_thread.task_runner()->PostTask(
+ FROM_HERE, base::BindOnce(&InitializeWrapperForNewThread, &target,
+ &initialized_event));
+ initialized_event.Wait();
+
+ ASSERT_TRUE(target != NULL);
+
+ rtc::MessageData* data = new rtc::MessageData();
+
+ EXPECT_CALL(handler1_,
+ OnMessage(MatchMessage(&handler1_, kTestMessage1, data)))
+ .WillOnce(DeleteMessageData());
+ target->Send(RTC_FROM_HERE, &handler1_, kTestMessage1, data);
+
+ Mock::VerifyAndClearExpectations(&handler1_);
+}
+
+// Verify that thread handles Send() while another Send() is
+// pending. The test creates second thread and Send()s kTestMessage1
+// to that thread. kTestMessage1 handler calls PingMainThread() which
+// tries to Send() kTestMessage2 to the main thread.
+TEST_F(ThreadWrapperTest, SendDuringSend) {
+ ThreadWrapper::current()->set_send_allowed(true);
+
+ base::Thread second_thread("adWrapperTest");
+ second_thread.Start();
+
+ base::WaitableEvent initialized_event(
+ base::WaitableEvent::ResetPolicy::MANUAL,
+ base::WaitableEvent::InitialState::NOT_SIGNALED);
+ rtc::Thread* target;
+ second_thread.task_runner()->PostTask(
+ FROM_HERE, base::BindOnce(&InitializeWrapperForNewThread, &target,
+ &initialized_event));
+ initialized_event.Wait();
+
+ ASSERT_TRUE(target != NULL);
+
+ rtc::MessageData* data = new rtc::MessageData();
+
+ EXPECT_CALL(handler1_,
+ OnMessage(MatchMessage(&handler1_, kTestMessage1, data)))
+ .WillOnce(
+ DoAll(InvokeWithoutArgs(this, &ThreadWrapperTest::PingMainThread),
+ DeleteMessageData()));
+ target->Send(RTC_FROM_HERE, &handler1_, kTestMessage1, data);
+
+ Mock::VerifyAndClearExpectations(&handler1_);
+}
+
+TEST_F(ThreadWrapperTest, Dispose) {
+ bool deleted_ = false;
+ thread_->Dispose(new DeletableObject(&deleted_));
+ EXPECT_FALSE(deleted_);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(deleted_);
+}
+
+// Provider needed for the MetronomeLikeTaskQueueTest suite.
+class ThreadWrapperProvider : public blink::MetronomeLikeTaskQueueProvider {
+ public:
+ static constexpr base::TimeDelta kMetronomeTick = base::Hertz(64);
+
+ void Initialize() override {
+ scoped_refptr<blink::MetronomeSource> metronome_source =
+ base::MakeRefCounted<blink::MetronomeSource>(base::TimeTicks::Now(),
+ kMetronomeTick);
+ ThreadWrapper::EnsureForCurrentMessageLoop(std::move(metronome_source));
+ thread_ = rtc::Thread::Current();
+ }
+
+ base::TimeDelta MetronomeTick() const override { return kMetronomeTick; }
+ webrtc::TaskQueueBase* TaskQueue() const override { return thread_; }
+
+ private:
+ // ThreadWrapper destroys itself when |message_loop_| is destroyed.
+ raw_ptr<rtc::Thread> thread_;
+};
+
+// Instantiate suite to run all tests defined in
+// third_party/webrtc_overrides/test/metronome_like_task_queue_test.h
+INSTANTIATE_TEST_SUITE_P(
+ ThreadWrapper,
+ MetronomeLikeTaskQueueTest,
+ ::testing::Values(std::make_unique<ThreadWrapperProvider>));
+
+} // namespace
+
+} // namespace webrtc
diff --git a/chromium/components/webrtc_logging/BUILD.gn b/chromium/components/webrtc_logging/BUILD.gn
new file mode 100644
index 00000000000..7b1798420d0
--- /dev/null
+++ b/chromium/components/webrtc_logging/BUILD.gn
@@ -0,0 +1,16 @@
+# Copyright 2022 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.
+
+source_set("unit_tests") {
+ testonly = true
+
+ sources = [ "logging_unittest.cc" ]
+
+ deps = [
+ "//base",
+ "//testing/gmock",
+ "//testing/gtest",
+ "//third_party/webrtc_overrides:webrtc_component",
+ ]
+}
diff --git a/chromium/components/webrtc_logging/DEPS b/chromium/components/webrtc_logging/DEPS
new file mode 100644
index 00000000000..8aba71e15c2
--- /dev/null
+++ b/chromium/components/webrtc_logging/DEPS
@@ -0,0 +1,5 @@
+specific_include_rules = {
+ 'logging_unittest\.cc': [
+ "+third_party/webrtc_overrides",
+ ]
+}
diff --git a/chromium/components/webrtc_logging/logging_unittest.cc b/chromium/components/webrtc_logging/logging_unittest.cc
new file mode 100644
index 00000000000..77847c242b0
--- /dev/null
+++ b/chromium/components/webrtc_logging/logging_unittest.cc
@@ -0,0 +1,155 @@
+// Copyright (c) 2012 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.
+
+// Note: this test tests RTC_LOG_V and RTC_LOG_E since all other logs are
+// expressed in forms of them. RTC_LOG is also tested for good measure.
+// Also note that we are only allowed to call InitLogging() twice so the test
+// cases are more dense than normal.
+
+// We must include Chromium headers before including the overrides header
+// since webrtc's logging.h file may conflict with chromium.
+#include "base/logging.h"
+#include "base/command_line.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/webrtc_overrides/rtc_base/logging.h"
+
+static const int kDefaultVerbosity = 0;
+
+static const char* AsString(rtc::LoggingSeverity severity) {
+ switch (severity) {
+ case rtc::LS_ERROR:
+ return "LS_ERROR";
+ case rtc::LS_WARNING:
+ return "LS_WARNING";
+ case rtc::LS_INFO:
+ return "LS_INFO";
+ case rtc::LS_VERBOSE:
+ return "LS_VERBOSE";
+ case rtc::LS_SENSITIVE:
+ return "LS_SENSITIVE";
+ default:
+ return "";
+ }
+}
+
+static bool ContainsString(const std::string& original,
+ const char* string_to_match) {
+ return original.find(string_to_match) != std::string::npos;
+}
+
+class WebRtcTextLogTest : public testing::Test {
+ public:
+ void SetUp() override {
+ ASSERT_TRUE(log_dir_.CreateUniqueTempDir());
+ log_file_path_ = log_dir_.GetPath().AppendASCII("webrtc_log");
+ }
+
+ protected:
+ bool Initialize(int verbosity_level) {
+ if (verbosity_level != kDefaultVerbosity) {
+ // Update the command line with specified verbosity level for this file.
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+ std::ostringstream value_stream;
+ value_stream << "logging_unittest=" << verbosity_level;
+ const std::string& value = value_stream.str();
+ command_line->AppendSwitchASCII("vmodule", value);
+ }
+
+ // The command line flags are parsed here and the log file name is set.
+ logging::LoggingSettings settings;
+ settings.logging_dest = logging::LOG_TO_FILE;
+ settings.log_file_path = log_file_path_.value().data();
+ settings.lock_log = logging::DONT_LOCK_LOG_FILE;
+ settings.delete_old = logging::DELETE_OLD_LOG_FILE;
+ if (!logging::InitLogging(settings)) {
+ return false;
+ }
+ EXPECT_TRUE(VLOG_IS_ON(verbosity_level));
+ EXPECT_FALSE(VLOG_IS_ON(verbosity_level + 1));
+ return true;
+ }
+
+ base::ScopedTempDir log_dir_;
+ base::FilePath log_file_path_;
+};
+
+TEST_F(WebRtcTextLogTest, DefaultConfiguration) {
+ ASSERT_TRUE(Initialize(kDefaultVerbosity));
+
+ // In the default configuration only warnings and errors should be logged.
+ RTC_LOG_V(rtc::LS_ERROR) << AsString(rtc::LS_ERROR);
+ RTC_LOG_V(rtc::LS_WARNING) << AsString(rtc::LS_WARNING);
+ RTC_LOG_V(rtc::LS_INFO) << AsString(rtc::LS_INFO);
+ RTC_LOG_V(rtc::LS_VERBOSE) << AsString(rtc::LS_VERBOSE);
+ RTC_LOG_V(rtc::LS_SENSITIVE) << AsString(rtc::LS_SENSITIVE);
+
+ // Read file to string.
+ std::string contents_of_file;
+ base::ReadFileToString(log_file_path_, &contents_of_file);
+
+ // Make sure string contains the expected values.
+ EXPECT_TRUE(ContainsString(contents_of_file, AsString(rtc::LS_ERROR)));
+ EXPECT_TRUE(ContainsString(contents_of_file, AsString(rtc::LS_WARNING)));
+ EXPECT_FALSE(ContainsString(contents_of_file, AsString(rtc::LS_INFO)));
+ EXPECT_FALSE(ContainsString(contents_of_file, AsString(rtc::LS_VERBOSE)));
+ EXPECT_FALSE(ContainsString(contents_of_file, AsString(rtc::LS_SENSITIVE)));
+}
+
+TEST_F(WebRtcTextLogTest, InfoConfiguration) {
+ ASSERT_TRUE(Initialize(0)); // 0 == Chrome's 'info' level.
+
+ // In this configuration everything lower or equal to LS_INFO should be
+ // logged.
+ RTC_LOG_V(rtc::LS_ERROR) << AsString(rtc::LS_ERROR);
+ RTC_LOG_V(rtc::LS_WARNING) << AsString(rtc::LS_WARNING);
+ RTC_LOG_V(rtc::LS_INFO) << AsString(rtc::LS_INFO);
+ RTC_LOG_V(rtc::LS_VERBOSE) << AsString(rtc::LS_VERBOSE);
+ RTC_LOG_V(rtc::LS_SENSITIVE) << AsString(rtc::LS_SENSITIVE);
+
+ // Read file to string.
+ std::string contents_of_file;
+ base::ReadFileToString(log_file_path_, &contents_of_file);
+
+ // Make sure string contains the expected values.
+ EXPECT_TRUE(ContainsString(contents_of_file, AsString(rtc::LS_ERROR)));
+ EXPECT_TRUE(ContainsString(contents_of_file, AsString(rtc::LS_WARNING)));
+ EXPECT_FALSE(ContainsString(contents_of_file, AsString(rtc::LS_INFO)));
+ EXPECT_FALSE(ContainsString(contents_of_file, AsString(rtc::LS_VERBOSE)));
+ EXPECT_FALSE(ContainsString(contents_of_file, AsString(rtc::LS_SENSITIVE)));
+
+ // Also check that the log is proper.
+ EXPECT_TRUE(ContainsString(contents_of_file, "logging_unittest.cc"));
+ EXPECT_FALSE(ContainsString(contents_of_file, "logging.h"));
+ EXPECT_FALSE(ContainsString(contents_of_file, "logging.cc"));
+}
+
+TEST_F(WebRtcTextLogTest, LogEverythingConfiguration) {
+ ASSERT_TRUE(Initialize(2)); // verbosity at level 2 allows LS_SENSITIVE.
+
+ // In this configuration everything should be logged.
+ RTC_LOG_V(rtc::LS_ERROR) << AsString(rtc::LS_ERROR);
+ RTC_LOG_V(rtc::LS_WARNING) << AsString(rtc::LS_WARNING);
+ RTC_LOG(LS_INFO) << AsString(rtc::LS_INFO);
+ static const int kFakeError = 1;
+ RTC_LOG_E(LS_INFO, EN, kFakeError)
+ << "RTC_LOG_E(" << AsString(rtc::LS_INFO) << ")";
+ RTC_LOG_V(rtc::LS_VERBOSE) << AsString(rtc::LS_VERBOSE);
+ RTC_LOG_V(rtc::LS_SENSITIVE) << AsString(rtc::LS_SENSITIVE);
+
+ // Read file to string.
+ std::string contents_of_file;
+ base::ReadFileToString(log_file_path_, &contents_of_file);
+
+ // Make sure string contains the expected values.
+ EXPECT_TRUE(ContainsString(contents_of_file, AsString(rtc::LS_ERROR)));
+ EXPECT_TRUE(ContainsString(contents_of_file, AsString(rtc::LS_WARNING)));
+ EXPECT_TRUE(ContainsString(contents_of_file, AsString(rtc::LS_INFO)));
+ // RTC_LOG_E
+ EXPECT_TRUE(ContainsString(contents_of_file, strerror(kFakeError)));
+ EXPECT_TRUE(ContainsString(contents_of_file, AsString(rtc::LS_VERBOSE)));
+ EXPECT_TRUE(ContainsString(contents_of_file, AsString(rtc::LS_SENSITIVE)));
+}
diff --git a/chromium/components/webxr/OWNERS b/chromium/components/webxr/OWNERS
index 2310121e00b..d37fd2d118a 100644
--- a/chromium/components/webxr/OWNERS
+++ b/chromium/components/webxr/OWNERS
@@ -1,2 +1,7 @@
alcooper@chromium.org
+bajones@chromium.org
bialpio@chromium.org
+klausw@chromium.org
+
+# WebXR Test related
+bsheedy@chromium.org
diff --git a/chromium/components/webxr/README.md b/chromium/components/webxr/README.md
new file mode 100644
index 00000000000..af0dd75a82d
--- /dev/null
+++ b/chromium/components/webxr/README.md
@@ -0,0 +1,21 @@
+# WebXR Component
+
+## WebXR Overview
+The web-exposed interface to WebXR begins in [Blink](https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/modules/xr/README.md).
+This code (with the help of the `VRService` [mojom interface](https://source.chromium.org/chromium/chromium/src/+/main:device/vr/public/mojom/README.md))
+talks with the [browser process](https://source.chromium.org/chromium/chromium/src/+/main:content/browser/xr/README.md)
+to broker a connection directly with the corresponding [device code](https://source.chromium.org/chromium/chromium/src/+/main:device/vr/README.md).
+Note that this device code is often hosted in a separate XR utility process, and
+thus the [isolated_xr_device service](https://source.chromium.org/chromium/chromium/src/+/main:content/services/isolated_xr_device/README.md)
+needs to assist the browser in brokering these connections. The code that talks
+directly with a device or its corresponding SDK/API (e.g. OpenXR) is often
+referred to as a "Runtime" throughout XR code. It is responsible for querying or
+formatting the data into/out of the expected WebXR formats.
+
+## Component Code
+This component code may depend on code in both //device and //content. It is
+intended for code that is necessary for a given runtime to work, but cannot be
+added under //device due to layering violations. Often this is because there may
+need to be customizable extension points added for different embedders. This
+includes code such as rendering utilizing the viz framework, or extension
+methods for embedders to customize the install flow for some runtimes.
diff --git a/chromium/components/webxr/android/BUILD.gn b/chromium/components/webxr/android/BUILD.gn
index e3fa950a42c..003d0fe8797 100644
--- a/chromium/components/webxr/android/BUILD.gn
+++ b/chromium/components/webxr/android/BUILD.gn
@@ -21,9 +21,6 @@ source_set("android") {
sources = [
"ar_compositor_delegate_provider.cc",
"ar_compositor_delegate_provider.h",
- "xr_install_helper_delegate.h",
- "xr_install_infobar.cc",
- "xr_install_infobar.h",
]
if (enable_arcore) {
@@ -40,8 +37,7 @@ source_set("android") {
deps = [
":android_utils",
"//base",
- "//components/infobars/android",
- "//components/infobars/core",
+ "//components/messages/android",
"//components/resources:android_resources",
"//components/strings",
"//components/webxr:webxr",
diff --git a/chromium/components/webxr/android/DEPS b/chromium/components/webxr/android/DEPS
index 6d6e0dfbce3..4193c509af2 100644
--- a/chromium/components/webxr/android/DEPS
+++ b/chromium/components/webxr/android/DEPS
@@ -1,5 +1,5 @@
include_rules = [
- "+components/infobars",
+ "+components/messages",
"+components/resources/android/theme_resources.h",
"+components/strings/grit/components_strings.h",
"+content/public/android/java/src/org/chromium/content_public",
diff --git a/chromium/components/webxr/android/arcore_device_provider.cc b/chromium/components/webxr/android/arcore_device_provider.cc
index 6bb16b5181e..714e8c06b0a 100644
--- a/chromium/components/webxr/android/arcore_device_provider.cc
+++ b/chromium/components/webxr/android/arcore_device_provider.cc
@@ -19,16 +19,7 @@ ArCoreDeviceProvider::ArCoreDeviceProvider(
ArCoreDeviceProvider::~ArCoreDeviceProvider() = default;
-void ArCoreDeviceProvider::Initialize(
- base::RepeatingCallback<void(device::mojom::XRDeviceId,
- device::mojom::VRDisplayInfoPtr,
- device::mojom::XRDeviceDataPtr,
- mojo::PendingRemote<device::mojom::XRRuntime>)>
- add_device_callback,
- base::RepeatingCallback<void(device::mojom::XRDeviceId)>
- remove_device_callback,
- base::OnceClosure initialization_complete,
- device::XrFrameSinkClientFactory xr_frame_sink_client_factory) {
+void ArCoreDeviceProvider::Initialize(device::VRDeviceProviderClient* client) {
if (device::IsArCoreSupported()) {
DVLOG(2) << __func__ << ": ARCore is supported, creating device";
@@ -37,14 +28,14 @@ void ArCoreDeviceProvider::Initialize(
std::make_unique<device::ArImageTransportFactory>(),
std::make_unique<webxr::MailboxToSurfaceBridgeFactoryImpl>(),
std::make_unique<webxr::ArCoreJavaUtils>(compositor_delegate_provider_),
- std::move(xr_frame_sink_client_factory));
+ client->GetXrFrameSinkClientFactory());
- add_device_callback.Run(
+ client->AddRuntime(
arcore_device_->GetId(), arcore_device_->GetVRDisplayInfo(),
arcore_device_->GetDeviceData(), arcore_device_->BindXRRuntime());
}
initialized_ = true;
- std::move(initialization_complete).Run();
+ client->OnProviderInitialized();
}
bool ArCoreDeviceProvider::Initialized() {
diff --git a/chromium/components/webxr/android/arcore_device_provider.h b/chromium/components/webxr/android/arcore_device_provider.h
index 15b43d19c2a..74af836b143 100644
--- a/chromium/components/webxr/android/arcore_device_provider.h
+++ b/chromium/components/webxr/android/arcore_device_provider.h
@@ -28,16 +28,7 @@ class ArCoreDeviceProvider : public device::VRDeviceProvider {
ArCoreDeviceProvider& operator=(const ArCoreDeviceProvider&) = delete;
~ArCoreDeviceProvider() override;
- void Initialize(
- base::RepeatingCallback<void(
- device::mojom::XRDeviceId,
- device::mojom::VRDisplayInfoPtr,
- device::mojom::XRDeviceDataPtr,
- mojo::PendingRemote<device::mojom::XRRuntime>)> add_device_callback,
- base::RepeatingCallback<void(device::mojom::XRDeviceId)>
- remove_device_callback,
- base::OnceClosure initialization_complete,
- device::XrFrameSinkClientFactory xr_frame_sink_client_factory) override;
+ void Initialize(device::VRDeviceProviderClient* client) override;
bool Initialized() override;
private:
diff --git a/chromium/components/webxr/android/arcore_install_helper.cc b/chromium/components/webxr/android/arcore_install_helper.cc
index b87a22a1e15..bd8612e462e 100644
--- a/chromium/components/webxr/android/arcore_install_helper.cc
+++ b/chromium/components/webxr/android/arcore_install_helper.cc
@@ -8,29 +8,20 @@
#include <utility>
#include "base/bind.h"
-#include "base/memory/weak_ptr.h"
-#include "components/infobars/android/confirm_infobar.h"
-#include "components/infobars/core/infobar.h"
-#include "components/infobars/core/infobar_delegate.h"
-#include "components/infobars/core/infobar_manager.h"
+#include "components/messages/android/message_dispatcher_bridge.h"
#include "components/resources/android/theme_resources.h"
#include "components/strings/grit/components_strings.h"
#include "components/webxr/android/ar_jni_headers/ArCoreInstallUtils_jni.h"
#include "components/webxr/android/webxr_utils.h"
-#include "components/webxr/android/xr_install_helper_delegate.h"
-#include "components/webxr/android/xr_install_infobar.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
+#include "ui/base/l10n/l10n_util.h"
using base::android::AttachCurrentThread;
namespace webxr {
-ArCoreInstallHelper::ArCoreInstallHelper(
- std::unique_ptr<XrInstallHelperDelegate> install_delegate)
- : install_delegate_(std::move(install_delegate)) {
- DCHECK(install_delegate_);
-
+ArCoreInstallHelper::ArCoreInstallHelper() {
// As per documentation, it's recommended to issue a call to
// ArCoreApk.checkAvailability() early in application lifecycle & ignore the
// result so that subsequent calls can return cached result:
@@ -72,7 +63,7 @@ void ArCoreInstallHelper::EnsureInstalled(
// ARCore is not installed or requires an update.
if (Java_ArCoreInstallUtils_shouldRequestInstallSupportedArCore(
AttachCurrentThread())) {
- ShowInfoBar(render_process_id, render_frame_id);
+ ShowMessage(render_process_id, render_frame_id);
return;
}
@@ -81,25 +72,13 @@ void ArCoreInstallHelper::EnsureInstalled(
OnRequestInstallSupportedArCoreResult(nullptr, true);
}
-void ArCoreInstallHelper::ShowInfoBar(int render_process_id,
+void ArCoreInstallHelper::ShowMessage(int render_process_id,
int render_frame_id) {
DVLOG(1) << __func__;
- infobars::InfoBarManager* infobar_manager =
- install_delegate_->GetInfoBarManager(
- GetWebContents(render_process_id, render_frame_id));
-
- // We can't show an infobar without an |infobar_manager|, so if it's null,
- // report that we are not installed and stop processing.
- if (!infobar_manager) {
- DVLOG(2) << __func__ << ": infobar_manager is null";
- RunInstallFinishedCallback(false);
- return;
- }
-
ArCoreAvailability availability = static_cast<ArCoreAvailability>(
Java_ArCoreInstallUtils_getArCoreInstallStatus(AttachCurrentThread()));
- int message_text = -1;
+ int message_title = -1;
int button_text = -1;
switch (availability) {
case ArCoreAvailability::kUnsupportedDeviceNotCapable: {
@@ -110,12 +89,12 @@ void ArCoreInstallHelper::ShowInfoBar(int render_process_id,
case ArCoreAvailability::kUnknownError:
case ArCoreAvailability::kUnknownTimedOut:
case ArCoreAvailability::kSupportedNotInstalled: {
- message_text = IDS_AR_CORE_CHECK_INFOBAR_INSTALL_TEXT;
+ message_title = IDS_AR_CORE_CHECK_MESSAGE_INSTALL_TITLE;
button_text = IDS_INSTALL;
break;
}
case ArCoreAvailability::kSupportedApkTooOld: {
- message_text = IDS_AR_CORE_CHECK_INFOBAR_UPDATE_TEXT;
+ message_title = IDS_AR_CORE_CHECK_MESSAGE_UPDATE_TITLE;
button_text = IDS_UPDATE;
break;
}
@@ -124,33 +103,46 @@ void ArCoreInstallHelper::ShowInfoBar(int render_process_id,
break;
}
- DCHECK_NE(-1, message_text);
+ DCHECK_NE(-1, message_title);
DCHECK_NE(-1, button_text);
- // Binding ourself as a weak ref is okay, since our destructor will still
- // guarantee that the callback is run if we are destroyed while waiting for
- // the callback from the infobar.
- // TODO(ijamardo, https://crbug.com/838833): Add icon for AR info bar.
- auto delegate = std::make_unique<XrInstallInfoBar>(
- infobars::InfoBarDelegate::InfoBarIdentifier::AR_CORE_UPGRADE_ANDROID,
- IDR_ANDROID_AR_CORE_INSALL_ICON, message_text, button_text,
- base::BindOnce(&ArCoreInstallHelper::OnInfoBarResponse,
- weak_ptr_factory_.GetWeakPtr(), render_process_id,
- render_frame_id));
-
- infobar_manager->AddInfoBar(
- std::make_unique<infobars::ConfirmInfoBar>(std::move(delegate)));
+ message_ = std::make_unique<messages::MessageWrapper>(
+ messages::MessageIdentifier::AR_CORE_UPGRADE,
+ base::BindOnce(&ArCoreInstallHelper::HandleMessagePrimaryAction,
+ base::Unretained(this), render_process_id,
+ render_frame_id),
+ base::BindOnce(&ArCoreInstallHelper::HandleMessageDismissed,
+ base::Unretained(this)));
+
+ message_->SetTitle(l10n_util::GetStringUTF16(message_title));
+ message_->SetDescription(
+ l10n_util::GetStringUTF16(IDS_AR_CORE_CHECK_MESSAGE_DESCRIPTION));
+ message_->SetPrimaryButtonText(l10n_util::GetStringUTF16(button_text));
+ messages::MessageDispatcherBridge* message_dispatcher_bridge =
+ messages::MessageDispatcherBridge::Get();
+ message_->SetIconResourceId(message_dispatcher_bridge->MapToJavaDrawableId(
+ IDR_ANDROID_AR_CORE_INSALL_ICON));
+
+ message_dispatcher_bridge->EnqueueMessage(
+ message_.get(), GetWebContents(render_process_id, render_frame_id),
+ messages::MessageScopeType::NAVIGATION,
+ messages::MessagePriority::kNormal);
}
-void ArCoreInstallHelper::OnInfoBarResponse(int render_process_id,
- int render_frame_id,
- bool try_install) {
- DVLOG(1) << __func__ << ": try_install=" << try_install;
- if (!try_install) {
+void ArCoreInstallHelper::HandleMessageDismissed(
+ messages::DismissReason dismiss_reason) {
+ // If the message is dismissed for any reason other than the primary action
+ // button click to install/update ARCore, indicate to the deferred callback
+ // that no installation/update was facilitated.
+ if (dismiss_reason != messages::DismissReason::PRIMARY_ACTION) {
OnRequestInstallSupportedArCoreResult(nullptr, false);
- return;
}
+ DCHECK(message_);
+ message_.reset();
+}
+void ArCoreInstallHelper::HandleMessagePrimaryAction(int render_process_id,
+ int render_frame_id) {
// When completed, java will call: OnRequestInstallSupportedArCoreResult
Java_ArCoreInstallUtils_requestInstallSupportedArCore(
AttachCurrentThread(), java_install_utils_,
diff --git a/chromium/components/webxr/android/arcore_install_helper.h b/chromium/components/webxr/android/arcore_install_helper.h
index 0813df3454c..e06f4d6c736 100644
--- a/chromium/components/webxr/android/arcore_install_helper.h
+++ b/chromium/components/webxr/android/arcore_install_helper.h
@@ -11,10 +11,11 @@
#include "base/android/scoped_java_ref.h"
#include "base/callback.h"
#include "base/memory/weak_ptr.h"
+#include "components/messages/android/message_enums.h"
+#include "components/messages/android/message_wrapper.h"
#include "content/public/browser/xr_install_helper.h"
namespace webxr {
-class XrInstallHelperDelegate;
// Equivalent of ArCoreApk.Availability enum.
// For detailed description, please see:
@@ -36,8 +37,7 @@ enum class ArCoreAvailability : int {
// XrIntegrationClient.
class ArCoreInstallHelper : public content::XrInstallHelper {
public:
- explicit ArCoreInstallHelper(
- std::unique_ptr<XrInstallHelperDelegate> install_delegate);
+ explicit ArCoreInstallHelper();
~ArCoreInstallHelper() override;
ArCoreInstallHelper(const ArCoreInstallHelper&) = delete;
@@ -53,15 +53,14 @@ class ArCoreInstallHelper : public content::XrInstallHelper {
void OnRequestInstallSupportedArCoreResult(JNIEnv* env, bool success);
private:
- void ShowInfoBar(int render_process_id, int render_frame_id);
- void OnInfoBarResponse(int render_process_id,
- int render_frame_id,
- bool try_install);
+ void ShowMessage(int render_process_id, int render_frame_id);
+ void HandleMessagePrimaryAction(int render_process_id, int render_frame_id);
+ void HandleMessageDismissed(messages::DismissReason dismiss_reason);
void RunInstallFinishedCallback(bool succeeded);
base::OnceCallback<void(bool)> install_finished_callback_;
base::android::ScopedJavaGlobalRef<jobject> java_install_utils_;
- std::unique_ptr<XrInstallHelperDelegate> install_delegate_;
+ std::unique_ptr<messages::MessageWrapper> message_;
// Must be last.
base::WeakPtrFactory<ArCoreInstallHelper> weak_ptr_factory_{this};
diff --git a/chromium/components/webxr/android/xr_install_helper_delegate.h b/chromium/components/webxr/android/xr_install_helper_delegate.h
deleted file mode 100644
index 4df3bc21c9a..00000000000
--- a/chromium/components/webxr/android/xr_install_helper_delegate.h
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2020 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.
-
-#ifndef COMPONENTS_WEBXR_ANDROID_XR_INSTALL_HELPER_DELEGATE_H_
-#define COMPONENTS_WEBXR_ANDROID_XR_INSTALL_HELPER_DELEGATE_H_
-
-namespace content {
-class WebContents;
-}
-
-namespace infobars {
-class InfoBarManager;
-}
-
-namespace webxr {
-
-// Helper class for InstallHelpers to gain access to other components. Since the
-// InstallHelpers are intended to be plumbed through content/public's
-// XrIntegrationClient, they may not contain direct references to other
-// component types. This provides a means for embedders to pass accessors for
-// other component types to the InstallHelpers.
-class XrInstallHelperDelegate {
- public:
- virtual ~XrInstallHelperDelegate() = default;
-
- XrInstallHelperDelegate(const XrInstallHelperDelegate&) = delete;
- XrInstallHelperDelegate& operator=(const XrInstallHelperDelegate&) = delete;
-
- // Gets the InfoBarManager for the provided web_contents, which can be used to
- // display the installation confirmation message. It is acceptable to return
- // a null InfoBarManager, but installation may fail after doing so.
- virtual infobars::InfoBarManager* GetInfoBarManager(
- content::WebContents* web_contents) = 0;
-
- protected:
- XrInstallHelperDelegate() = default;
-};
-
-} // namespace webxr
-
-#endif // COMPONENTS_WEBXR_ANDROID_XR_INSTALL_HELPER_DELEGATE_H_
diff --git a/chromium/components/webxr/android/xr_install_infobar.cc b/chromium/components/webxr/android/xr_install_infobar.cc
deleted file mode 100644
index 167e841fc95..00000000000
--- a/chromium/components/webxr/android/xr_install_infobar.cc
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright (c) 2020 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.
-
-#include "components/webxr/android/xr_install_infobar.h"
-
-#include <string>
-
-#include "base/callback.h"
-#include "components/infobars/core/confirm_infobar_delegate.h"
-#include "components/infobars/core/infobar_delegate.h"
-#include "ui/base/l10n/l10n_util.h"
-
-namespace webxr {
-
-XrInstallInfoBar::XrInstallInfoBar(
- InfoBarIdentifier identifier,
- int icon_id,
- int message_id,
- int ok_button_id,
- base::OnceCallback<void(bool)> install_callback)
- : identifier_(identifier),
- icon_id_(icon_id),
- message_id_(message_id),
- ok_button_id_(ok_button_id),
- install_callback_(std::move(install_callback)) {}
-
-XrInstallInfoBar::~XrInstallInfoBar() = default;
-
-infobars::InfoBarDelegate::InfoBarIdentifier XrInstallInfoBar::GetIdentifier()
- const {
- return identifier_;
-}
-
-int XrInstallInfoBar::GetIconId() const {
- return icon_id_;
-}
-
-int XrInstallInfoBar::GetButtons() const {
- return BUTTON_OK;
-}
-
-std::u16string XrInstallInfoBar::GetButtonLabel(InfoBarButton button) const {
- DCHECK_EQ(BUTTON_OK, button);
- return l10n_util::GetStringUTF16(ok_button_id_);
-}
-
-std::u16string XrInstallInfoBar::GetMessageText() const {
- return l10n_util::GetStringUTF16(message_id_);
-}
-
-bool XrInstallInfoBar::Accept() {
- std::move(install_callback_).Run(true);
- return true;
-}
-
-bool XrInstallInfoBar::Cancel() {
- std::move(install_callback_).Run(false);
- return true;
-}
-
-void XrInstallInfoBar::InfoBarDismissed() {
- std::move(install_callback_).Run(false);
-}
-} // namespace webxr
diff --git a/chromium/components/webxr/android/xr_install_infobar.h b/chromium/components/webxr/android/xr_install_infobar.h
deleted file mode 100644
index 67882c90971..00000000000
--- a/chromium/components/webxr/android/xr_install_infobar.h
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright (c) 2020 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.
-
-#ifndef COMPONENTS_WEBXR_ANDROID_XR_INSTALL_INFOBAR_H_
-#define COMPONENTS_WEBXR_ANDROID_XR_INSTALL_INFOBAR_H_
-
-#include <string>
-
-#include "base/callback.h"
-#include "components/infobars/core/confirm_infobar_delegate.h"
-#include "components/infobars/core/infobar_delegate.h"
-
-namespace webxr {
-
-// An interface derived from InfoBarDelegate implemented by objects wishing to
-// control a ConfirmInfoBar.
-class XrInstallInfoBar : public ConfirmInfoBarDelegate {
- public:
- // Constructor for XrInstallInfoBar, the callback is guaranteed to be called,
- // if the InfoBar is accepted, cancelled, or dismissed. The Callback will be
- // passed a bool indicating whether the result of the InfoBar was "accepted."
- XrInstallInfoBar(InfoBarIdentifier identifier,
- int icon_id,
- int message_id,
- int ok_button_id,
- base::OnceCallback<void(bool)> install_callback);
- ~XrInstallInfoBar() override;
-
- infobars::InfoBarDelegate::InfoBarIdentifier GetIdentifier() const override;
- int GetIconId() const override;
- std::u16string GetMessageText() const override;
- int GetButtons() const override;
- std::u16string GetButtonLabel(InfoBarButton button) const override;
-
- private:
- // Called when the OK button is pressed. If this function returns true, the
- // infobar is then immediately closed. Subclasses MUST NOT return true if in
- // handling this call something triggers the infobar to begin closing.
- bool Accept() override;
-
- // Called when the Cancel button is pressed. If this function returns true,
- // the infobar is then immediately closed. Subclasses MUST NOT return true if
- // in handling this call something triggers the infobar to begin closing.
- bool Cancel() override;
-
- // Called when the user clicks on the close button to dismiss the infobar.
- void InfoBarDismissed() override;
-
- const infobars::InfoBarDelegate::InfoBarIdentifier identifier_;
- const int icon_id_;
- const int message_id_;
- const int ok_button_id_;
- base::OnceCallback<void(bool)> install_callback_;
-};
-} // namespace webxr
-
-#endif // COMPONENTS_WEBXR_ANDROID_XR_INSTALL_INFOBAR_H_
diff --git a/chromium/components/webxr_strings.grdp b/chromium/components/webxr_strings.grdp
index 5b4e1404f48..372a01398aa 100644
--- a/chromium/components/webxr_strings.grdp
+++ b/chromium/components/webxr_strings.grdp
@@ -2,12 +2,15 @@
<!-- WebXR specific strings (included from components_strings.grd). -->
<grit-part>
<if expr="enable_arcore">
- <!-- ARCore check infobar -->
- <message name="IDS_AR_CORE_CHECK_INFOBAR_INSTALL_TEXT" desc="Text to be displayed in the ARCore check infobar. When a WebXR page is loaded, if ARCore is needed to display AR content and it is not installed, an infobar will be shown to the user prompting them to install ARCore.">
- To view augmented reality content, install ARCore
+ <!-- ARCore check message -->
+ <message name="IDS_AR_CORE_CHECK_MESSAGE_INSTALL_TITLE" desc="Title for the ARCore check message. When a WebXR page is loaded, if ARCore is needed to display AR content and it is not installed, a message will be shown to the user prompting them to install ARCore.">
+ Install ARCore?
</message>
- <message name="IDS_AR_CORE_CHECK_INFOBAR_UPDATE_TEXT" desc="Text to be displayed in the ARCore check infobar. When a WebXR page is loaded, if ARCore is needed to display AR content and the installed ARCore is not up to date to the version needed by the implementation, an infobar will be shown to the user prompting them to update ARCore.">
- To view augmented reality content, update ARCore
+ <message name="IDS_AR_CORE_CHECK_MESSAGE_UPDATE_TITLE" desc="Title for the ARCore check message. When a WebXR page is loaded, if ARCore is needed to display AR content and the installed ARCore is not up to date to the version needed by the implementation, a message will be shown to the user prompting them to update ARCore.">
+ Update ARCore?
+ </message>
+ <message name="IDS_AR_CORE_CHECK_MESSAGE_DESCRIPTION" desc="Description for the ARCore check message that will be prompted when a WebXR page requires ARCore to display AR content.">
+ View augmented reality content
</message>
</if>
</grit-part>
diff --git a/chromium/components/webxr_strings_grdp/IDS_AR_CORE_CHECK_INFOBAR_INSTALL_TEXT.png.sha1 b/chromium/components/webxr_strings_grdp/IDS_AR_CORE_CHECK_INFOBAR_INSTALL_TEXT.png.sha1
deleted file mode 100644
index 61e6968626a..00000000000
--- a/chromium/components/webxr_strings_grdp/IDS_AR_CORE_CHECK_INFOBAR_INSTALL_TEXT.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-53e9d9669c1b11a5768ff5a4134ccdf097c8de42 \ No newline at end of file
diff --git a/chromium/components/webxr_strings_grdp/IDS_AR_CORE_CHECK_INFOBAR_UPDATE_TEXT.png.sha1 b/chromium/components/webxr_strings_grdp/IDS_AR_CORE_CHECK_INFOBAR_UPDATE_TEXT.png.sha1
deleted file mode 100644
index 7d5e071f241..00000000000
--- a/chromium/components/webxr_strings_grdp/IDS_AR_CORE_CHECK_INFOBAR_UPDATE_TEXT.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-c2cf80e15c7b64119f4cb102448080a1d25829cf \ No newline at end of file
diff --git a/chromium/components/webxr_strings_grdp/IDS_AR_CORE_CHECK_MESSAGE_DESCRIPTION.png.sha1 b/chromium/components/webxr_strings_grdp/IDS_AR_CORE_CHECK_MESSAGE_DESCRIPTION.png.sha1
new file mode 100644
index 00000000000..f6b8dbfc6f1
--- /dev/null
+++ b/chromium/components/webxr_strings_grdp/IDS_AR_CORE_CHECK_MESSAGE_DESCRIPTION.png.sha1
@@ -0,0 +1 @@
+af76610bcf354c0c285e09d9781b3a0239e48a29 \ No newline at end of file
diff --git a/chromium/components/webxr_strings_grdp/IDS_AR_CORE_CHECK_MESSAGE_INSTALL_TITLE.png.sha1 b/chromium/components/webxr_strings_grdp/IDS_AR_CORE_CHECK_MESSAGE_INSTALL_TITLE.png.sha1
new file mode 100644
index 00000000000..f6b8dbfc6f1
--- /dev/null
+++ b/chromium/components/webxr_strings_grdp/IDS_AR_CORE_CHECK_MESSAGE_INSTALL_TITLE.png.sha1
@@ -0,0 +1 @@
+af76610bcf354c0c285e09d9781b3a0239e48a29 \ No newline at end of file
diff --git a/chromium/components/webxr_strings_grdp/IDS_AR_CORE_CHECK_MESSAGE_UPDATE_TITLE.png.sha1 b/chromium/components/webxr_strings_grdp/IDS_AR_CORE_CHECK_MESSAGE_UPDATE_TITLE.png.sha1
new file mode 100644
index 00000000000..5c21ed405a1
--- /dev/null
+++ b/chromium/components/webxr_strings_grdp/IDS_AR_CORE_CHECK_MESSAGE_UPDATE_TITLE.png.sha1
@@ -0,0 +1 @@
+ce1aa215b5273341279d5f6d00fdf637c1ed5705 \ No newline at end of file
diff --git a/chromium/components/wifi/network_properties.cc b/chromium/components/wifi/network_properties.cc
index 08adcf3b3d8..f1801abe478 100644
--- a/chromium/components/wifi/network_properties.cc
+++ b/chromium/components/wifi/network_properties.cc
@@ -54,7 +54,7 @@ std::unique_ptr<base::DictionaryValue> NetworkProperties::ToValue(
++it) {
frequency_list.Append(*it);
}
- if (!frequency_list.GetList().empty())
+ if (!frequency_list.GetListDeprecated().empty())
wifi.SetPath(onc::wifi::kFrequencyList, std::move(frequency_list));
if (!bssid.empty())
wifi.SetStringPath(onc::wifi::kBSSID, bssid);
diff --git a/chromium/components/wifi/wifi_service.h b/chromium/components/wifi/wifi_service.h
index 0818e22c65f..4486a0d3611 100644
--- a/chromium/components/wifi/wifi_service.h
+++ b/chromium/components/wifi/wifi_service.h
@@ -5,7 +5,6 @@
#ifndef COMPONENTS_WIFI_WIFI_SERVICE_H_
#define COMPONENTS_WIFI_WIFI_SERVICE_H_
-#include <list>
#include <memory>
#include <set>
#include <string>
diff --git a/chromium/components/wifi/wifi_service_win.cc b/chromium/components/wifi/wifi_service_win.cc
index 349215e7420..776d399c1a8 100644
--- a/chromium/components/wifi/wifi_service_win.cc
+++ b/chromium/components/wifi/wifi_service_win.cc
@@ -26,6 +26,7 @@
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/single_thread_task_runner.h"
+#include "base/time/time.h"
#include "base/values.h"
#include "base/win/registry.h"
#include "base/win/win_util.h"
diff --git a/chromium/components/wifi/wifi_test.cc b/chromium/components/wifi/wifi_test.cc
index 58eadf16bca..1c305a3dad3 100644
--- a/chromium/components/wifi/wifi_test.cc
+++ b/chromium/components/wifi/wifi_test.cc
@@ -26,7 +26,7 @@
#include "build/build_config.h"
#include "components/wifi/wifi_service.h"
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
#include "base/mac/scoped_nsautorelease_pool.h"
#endif
@@ -71,7 +71,7 @@ class WiFiTest {
VLOG(0) << "Network List Changed: " << network_guid_list.size();
}
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
// Without this there will be a mem leak on osx.
base::mac::ScopedNSAutoreleasePool scoped_pool_;
#endif
@@ -122,14 +122,14 @@ bool WiFiTest::ParseCommandLine(int argc, const char* argv[]) {
parsed_command_line.GetSwitchValueASCII("security");
if (parsed_command_line.GetArgs().size() == 1) {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
network_guid = base::WideToASCII(parsed_command_line.GetArgs()[0]);
#else
network_guid = parsed_command_line.GetArgs()[0];
#endif
}
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
if (parsed_command_line.HasSwitch("debug"))
MessageBoxA(nullptr, __FUNCTION__, "Debug Me!", MB_OK);
#endif
diff --git a/chromium/components/winhttp/network_fetcher.cc b/chromium/components/winhttp/network_fetcher.cc
index ca2035ed190..c246ec30588 100644
--- a/chromium/components/winhttp/network_fetcher.cc
+++ b/chromium/components/winhttp/network_fetcher.cc
@@ -76,7 +76,7 @@ void NetworkFetcher::Close() {
void NetworkFetcher::CompleteFetch() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!file_.IsValid()) {
- std::move(fetch_complete_callback_).Run();
+ std::move(fetch_complete_callback_).Run(response_code_);
return;
}
base::ThreadPool::PostTaskAndReply(
@@ -295,9 +295,8 @@ void NetworkFetcher::HeadersAvailable() {
WINHTTP_HEADER_NAME_BY_INDEX, &all);
VLOG(3) << "response headers: " << all;
- int response_code = 0;
net_error_ = QueryHeadersInt(request_handle_.get(), WINHTTP_QUERY_STATUS_CODE,
- WINHTTP_HEADER_NAME_BY_INDEX, &response_code);
+ WINHTTP_HEADER_NAME_BY_INDEX, &response_code_);
if (FAILED(net_error_)) {
CompleteFetch();
return;
@@ -312,7 +311,7 @@ void NetworkFetcher::HeadersAvailable() {
return;
}
- std::move(fetch_started_callback_).Run(response_code, content_length);
+ std::move(fetch_started_callback_).Run(response_code_, content_length);
// Start reading the body of response.
net_error_ = ReadData();
diff --git a/chromium/components/winhttp/network_fetcher.h b/chromium/components/winhttp/network_fetcher.h
index 02659222dce..b2655f22093 100644
--- a/chromium/components/winhttp/network_fetcher.h
+++ b/chromium/components/winhttp/network_fetcher.h
@@ -34,7 +34,7 @@ namespace winhttp {
// as it is accessed from the main thread and the worker threads in WinHTTP.
class NetworkFetcher : public base::RefCountedThreadSafe<NetworkFetcher> {
public:
- using FetchCompleteCallback = base::OnceCallback<void()>;
+ using FetchCompleteCallback = base::OnceCallback<void(int response_code)>;
using FetchStartedCallback =
base::OnceCallback<void(int response_code, int64_t content_length)>;
using FetchProgressCallback = base::RepeatingCallback<void(int64_t current)>;
@@ -138,6 +138,7 @@ class NetworkFetcher : public base::RefCountedThreadSafe<NetworkFetcher> {
WriteDataCallback write_data_callback_;
HRESULT net_error_ = S_OK;
std::vector<char> read_buffer_;
+ int response_code_ = 0;
std::string post_response_body_;
base::FilePath file_path_;
base::File file_;
diff --git a/chromium/components/winhttp/network_fetcher_unittest.cc b/chromium/components/winhttp/network_fetcher_unittest.cc
index 0b301aa9418..37fa6bcd313 100644
--- a/chromium/components/winhttp/network_fetcher_unittest.cc
+++ b/chromium/components/winhttp/network_fetcher_unittest.cc
@@ -31,9 +31,9 @@ TEST(WinHttpNetworkFetcher, InvalidUrlPost) {
/*fetch_started_callback*/
base::BindOnce([](int response_code, int64_t content_length) {}),
/*fetch_progress_callback*/ base::BindRepeating([](int64_t current) {}),
- /*fetch_complete_callback*/ base::BindLambdaForTesting([&run_loop]() {
- run_loop.Quit();
- }));
+ /*fetch_complete_callback*/
+ base::BindLambdaForTesting(
+ [&run_loop](int response_code) { run_loop.Quit(); }));
run_loop.Run();
EXPECT_EQ(network_fetcher->GetNetError(), E_INVALIDARG);
}
@@ -51,9 +51,9 @@ TEST(WinHttpNetworkFetcher, InvalidUrlDownload) {
/*fetch_started_callback*/
base::BindOnce([](int response_code, int64_t content_length) {}),
/*fetch_progress_callback*/ base::BindRepeating([](int64_t current) {}),
- /*fetch_complete_callback*/ base::BindLambdaForTesting([&run_loop]() {
- run_loop.Quit();
- }));
+ /*fetch_complete_callback*/
+ base::BindLambdaForTesting(
+ [&run_loop](int response_code) { run_loop.Quit(); }));
run_loop.Run();
EXPECT_EQ(network_fetcher->GetNetError(), E_INVALIDARG);
}
diff --git a/chromium/components/zucchini/abs32_utils.cc b/chromium/components/zucchini/abs32_utils.cc
index ad1c85e382d..7bf1700bad1 100644
--- a/chromium/components/zucchini/abs32_utils.cc
+++ b/chromium/components/zucchini/abs32_utils.cc
@@ -89,12 +89,12 @@ bool AbsoluteAddress::Write(offset_t offset, MutableBufferView* image) {
Abs32RvaExtractorWin32::Abs32RvaExtractorWin32(
ConstBufferView image,
AbsoluteAddress&& addr,
- const std::vector<offset_t>& abs32_locations,
+ const std::deque<offset_t>& abs32_locations,
offset_t lo,
offset_t hi)
: image_(image), addr_(std::move(addr)) {
CHECK_LE(lo, hi);
- auto find_and_check = [this](const std::vector<offset_t>& locations,
+ auto find_and_check = [this](const std::deque<offset_t>& locations,
offset_t offset) {
auto it = std::lower_bound(locations.begin(), locations.end(), offset);
// Ensure that |offset| does not straddle a reference body.
@@ -167,12 +167,12 @@ void Abs32WriterWin32::PutNext(Reference ref) {
size_t RemoveUntranslatableAbs32(ConstBufferView image,
AbsoluteAddress&& addr,
const AddressTranslator& translator,
- std::vector<offset_t>* locations) {
+ std::deque<offset_t>* locations) {
AddressTranslator::RvaToOffsetCache target_rva_checker(translator);
Abs32RvaExtractorWin32 extractor(image, std::move(addr), *locations, 0,
image.size());
Abs32ReaderWin32 reader(std::move(extractor), translator);
- std::vector<offset_t>::iterator write_it = locations->begin();
+ std::deque<offset_t>::iterator write_it = locations->begin();
// |reader| reads |locations| while |write_it| modifies it. However, there's
// no conflict since read occurs before write, and can skip ahead.
for (auto ref = reader.GetNext(); ref.has_value(); ref = reader.GetNext())
@@ -184,7 +184,7 @@ size_t RemoveUntranslatableAbs32(ConstBufferView image,
}
size_t RemoveOverlappingAbs32Locations(uint32_t width,
- std::vector<offset_t>* locations) {
+ std::deque<offset_t>* locations) {
if (locations->size() <= 1)
return 0;
diff --git a/chromium/components/zucchini/abs32_utils.h b/chromium/components/zucchini/abs32_utils.h
index 07503b57391..f528e754e5f 100644
--- a/chromium/components/zucchini/abs32_utils.h
+++ b/chromium/components/zucchini/abs32_utils.h
@@ -8,7 +8,7 @@
#include <stddef.h>
#include <stdint.h>
-#include <vector>
+#include <deque>
#include "components/zucchini/address_translator.h"
#include "components/zucchini/buffer_view.h"
@@ -70,7 +70,7 @@ class Abs32RvaExtractorWin32 {
// length |addr.width()|) in |abs32_locations|.
Abs32RvaExtractorWin32(ConstBufferView image,
AbsoluteAddress&& addr,
- const std::vector<offset_t>& abs32_locations,
+ const std::deque<offset_t>& abs32_locations,
offset_t lo,
offset_t hi);
Abs32RvaExtractorWin32(Abs32RvaExtractorWin32&&);
@@ -83,8 +83,8 @@ class Abs32RvaExtractorWin32 {
private:
ConstBufferView image_;
AbsoluteAddress addr_;
- std::vector<offset_t>::const_iterator cur_abs32_;
- std::vector<offset_t>::const_iterator end_abs32_;
+ std::deque<offset_t>::const_iterator cur_abs32_;
+ std::deque<offset_t>::const_iterator end_abs32_;
};
// A reader for Win32 abs32 references that filters and translates results from
@@ -130,12 +130,12 @@ class Abs32WriterWin32 : public ReferenceWriter {
size_t RemoveUntranslatableAbs32(ConstBufferView image,
AbsoluteAddress&& addr,
const AddressTranslator& translator,
- std::vector<offset_t>* locations);
+ std::deque<offset_t>* locations);
// Given a sorted list of abs32 |locations|, removes all elements whose body
// (with |width| given) overlaps with the body of a previous element.
size_t RemoveOverlappingAbs32Locations(uint32_t width,
- std::vector<offset_t>* locations);
+ std::deque<offset_t>* locations);
} // namespace zucchini
diff --git a/chromium/components/zucchini/abs32_utils_unittest.cc b/chromium/components/zucchini/abs32_utils_unittest.cc
index ddbb685a2df..3e02bba21be 100644
--- a/chromium/components/zucchini/abs32_utils_unittest.cc
+++ b/chromium/components/zucchini/abs32_utils_unittest.cc
@@ -192,7 +192,7 @@ TEST(Abs32UtilsTest, Win32Read32) {
constexpr uint32_t kRvaBegin = 0x00C00000U;
struct {
std::vector<uint8_t> data32;
- std::vector<offset_t> abs32_locations; // Assumtion: Sorted.
+ std::deque<offset_t> abs32_locations; // Assumption: Sorted.
offset_t lo; // Assumption: In range, does not straddle |abs32_location|.
offset_t hi; // Assumption: Also >= |lo|.
std::vector<Reference> expected_refs;
@@ -230,7 +230,7 @@ TEST(Abs32UtilsTest, Win32Read32) {
{{0x3U, 0x9U}}},
// No location given.
{ParseHexString("FF FF FF FF 0C 00 C0 A0 00 00 C0 A0 FF FF FF FF"),
- std::vector<offset_t>(), 0x0U, 0x10U, std::vector<Reference>()},
+ std::deque<offset_t>(), 0x0U, 0x10U, std::vector<Reference>()},
// Simple alternation.
{ParseHexString("04 00 C0 A0 FF FF FF FF 0C 00 C0 A0 FF FF FF FF "
"14 00 C0 A0 FF FF FF FF 1C 00 C0 A0 FF FF FF FF"),
@@ -308,8 +308,8 @@ TEST(Abs32UtilsTest, Win32Read64) {
"06 00 C0 A0 26 59 41 31 02 00 C0 A0 26 59 41 31 "
"FF FF FF BF 26 59 41 31 FF FF FF FF FF FF FF FF "
"02 00 C0 A0 26 59 41 31 07 00 C0 A0 26 59 41 31");
- std::vector<offset_t> abs32_locations = {0x8U, 0x10U, 0x18U, 0x20U,
- 0x28U, 0x30U, 0x38U, 0x40U};
+ std::deque<offset_t> abs32_locations = {0x8U, 0x10U, 0x18U, 0x20U,
+ 0x28U, 0x30U, 0x38U, 0x40U};
offset_t lo = 0x10U;
offset_t hi = 0x38U;
std::vector<Reference> expected_refs = {
@@ -336,7 +336,7 @@ TEST(Abs32UtilsTest, Win32ReadFail) {
std::vector<uint8_t> data(32U, 0xFFU);
ConstBufferView image(data.data(), data.size());
- auto try_make = [&](std::vector<offset_t>&& abs32_locations, offset_t lo,
+ auto try_make = [&](std::deque<offset_t>&& abs32_locations, offset_t lo,
offset_t hi) {
Abs32RvaExtractorWin32 extractor(image, {bitness, kImageBase},
abs32_locations, lo, hi);
@@ -359,7 +359,7 @@ TEST(Abs32UtilsTest, Win32ReadFail) {
bitness = kBit64;
try_make({6U, 22U}, 0U, 32U);
// |lo| > |hi|.
- EXPECT_DEATH(try_make(std::vector<offset_t>(), 32U, 31U), "");
+ EXPECT_DEATH(try_make(std::deque<offset_t>(), 32U, 31U), "");
try_make({6U, 22U}, 0U, 14U);
try_make({6U, 22U}, 0U, 30U);
try_make({6U, 22U}, 6U, 32U);
@@ -468,10 +468,10 @@ TEST(Abs32UtilsTest, RemoveUntranslatableAbs32) {
const offset_t kAbsB = 0x54; // a:00000000 (bad: underflow)
const offset_t kAbsC = 0x58; // a:2BCD1A18 = r:1A18 = 0x1C
- std::vector<offset_t> locations = {kAbs1, kAbs2, kAbs3, kAbs4, kAbs5, kAbs6,
- kAbs7, kAbs8, kAbs9, kAbsA, kAbsB, kAbsC};
- std::vector<offset_t> exp_locations = {kAbs1, kAbs2, kAbs3, kAbs4,
- kAbs5, kAbs6, kAbs9, kAbsC};
+ std::deque<offset_t> locations = {kAbs1, kAbs2, kAbs3, kAbs4, kAbs5, kAbs6,
+ kAbs7, kAbs8, kAbs9, kAbsA, kAbsB, kAbsC};
+ std::deque<offset_t> exp_locations = {kAbs1, kAbs2, kAbs3, kAbs4,
+ kAbs5, kAbs6, kAbs9, kAbsC};
size_t exp_num_removed = locations.size() - exp_locations.size();
size_t num_removed = RemoveUntranslatableAbs32(image, {kBitness, kImageBase},
translator, &locations);
@@ -483,8 +483,8 @@ TEST(Abs32UtilsTest, RemoveOverlappingAbs32Locations) {
// Make |width| a state to reduce repetition.
uint32_t width = WidthOf(kBit32);
- auto run_test = [&width](const std::vector<offset_t>& expected_locations,
- std::vector<offset_t>&& locations) {
+ auto run_test = [&width](const std::deque<offset_t>& expected_locations,
+ std::deque<offset_t>&& locations) {
ASSERT_TRUE(std::is_sorted(locations.begin(), locations.end()));
size_t expected_removals = locations.size() - expected_locations.size();
size_t removals = RemoveOverlappingAbs32Locations(width, &locations);
@@ -494,7 +494,7 @@ TEST(Abs32UtilsTest, RemoveOverlappingAbs32Locations) {
// 32-bit tests.
width = WidthOf(kBit32);
- run_test(std::vector<offset_t>(), std::vector<offset_t>());
+ run_test(std::deque<offset_t>(), std::deque<offset_t>());
run_test({4U}, {4U});
run_test({4U, 10U}, {4U, 10U});
run_test({4U, 8U}, {4U, 8U});
@@ -518,7 +518,7 @@ TEST(Abs32UtilsTest, RemoveOverlappingAbs32Locations) {
// 64-bit tests.
width = WidthOf(kBit64);
- run_test(std::vector<offset_t>(), std::vector<offset_t>());
+ run_test(std::deque<offset_t>(), std::deque<offset_t>());
run_test({4U}, {4U});
run_test({4U, 20U}, {4U, 20U});
run_test({4U, 12U}, {4U, 12U});
diff --git a/chromium/components/zucchini/disassembler_elf.h b/chromium/components/zucchini/disassembler_elf.h
index a821920b662..8b834fa23ed 100644
--- a/chromium/components/zucchini/disassembler_elf.h
+++ b/chromium/components/zucchini/disassembler_elf.h
@@ -238,7 +238,7 @@ class DisassemblerElf : public Disassembler {
std::vector<const typename Traits::Elf_Shdr*> exec_headers_;
// Sorted file offsets of abs32 locations.
- std::vector<offset_t> abs32_locations_;
+ std::deque<offset_t> abs32_locations_;
};
// Disassembler for ELF with Intel architectures.
diff --git a/chromium/components/zucchini/disassembler_win32.h b/chromium/components/zucchini/disassembler_win32.h
index fdfdbb0cd43..d711215e011 100644
--- a/chromium/components/zucchini/disassembler_win32.h
+++ b/chromium/components/zucchini/disassembler_win32.h
@@ -114,7 +114,7 @@ class DisassemblerWin32 : public Disassembler {
BufferRegion reloc_region_ = {kInvalidOffset, 0U};
std::vector<offset_t> reloc_block_offsets_;
offset_t reloc_end_ = 0;
- std::vector<offset_t> abs32_locations_;
+ std::deque<offset_t> abs32_locations_;
// Using std::deque to reduce peak memory footprint.
std::deque<offset_t> rel32_locations_;
diff --git a/chromium/components/zucchini/image_index_unittest.cc b/chromium/components/zucchini/image_index_unittest.cc
index cf6f8a70b2b..7eb1da9a184 100644
--- a/chromium/components/zucchini/image_index_unittest.cc
+++ b/chromium/components/zucchini/image_index_unittest.cc
@@ -94,15 +94,15 @@ TEST_F(ImageIndexTest, IsToken) {
InitializeWithDefaultTestData();
std::vector<bool> expected = {
- 1, // raw
- 1, 0, // ref 0
- 1, 0, 0, 0, // ref 1
- 1, // raw
- 1, 0, // ref 0
- 1, 0, // ref 0
- 1, 0, 0, // ref 2
- 1, 1, // raw
- 1, 0, 0, // ref 2
+ true, // raw
+ true, false, // ref 0
+ true, false, false, false, // ref 1
+ true, // raw
+ true, false, // ref 0
+ true, false, // ref 0
+ true, false, false, // ref 2
+ true, true, // raw
+ true, false, false, // ref 2
};
for (offset_t i = 0; i < image_index_.size(); ++i)
@@ -113,15 +113,15 @@ TEST_F(ImageIndexTest, IsReference) {
InitializeWithDefaultTestData();
std::vector<bool> expected = {
- 0, // raw
- 1, 1, // ref 0
- 1, 1, 1, 1, // ref 1
- 0, // raw
- 1, 1, // ref 0
- 1, 1, // ref 0
- 1, 1, 1, // ref 2
- 0, 0, // raw
- 1, 1, 1, // ref 2
+ false, // raw
+ true, true, // ref 0
+ true, true, true, true, // ref 1
+ false, // raw
+ true, true, // ref 0
+ true, true, // ref 0
+ true, true, true, // ref 2
+ false, false, // raw
+ true, true, true, // ref 2
};
for (offset_t i = 0; i < image_index_.size(); ++i)
diff --git a/chromium/components/zucchini/main_utils.cc b/chromium/components/zucchini/main_utils.cc
index 48b52e18f6f..cb79a207c1e 100644
--- a/chromium/components/zucchini/main_utils.cc
+++ b/chromium/components/zucchini/main_utils.cc
@@ -25,7 +25,7 @@
#include "components/zucchini/version_info.h"
#include "components/zucchini/zucchini_commands.h"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include <windows.h> // This include must come first.
#include <psapi.h>
@@ -80,7 +80,7 @@ constexpr Command kCommands[] = {
/******** GetPeakMemoryMetrics ********/
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
// Linux does not have an exact mapping to the values used on Windows so use a
// close approximation:
// peak_virtual_memory ~= peak_page_file_usage
@@ -122,9 +122,9 @@ void GetPeakMemoryMetrics(size_t* peak_virtual_memory,
}
}
}
-#endif // defined(OS_LINUX) || defined(OS_CHROMEOS)
+#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// On failure the input values will be set to 0.
void GetPeakMemoryMetrics(size_t* peak_page_file_usage,
size_t* peak_working_set_size) {
@@ -136,7 +136,7 @@ void GetPeakMemoryMetrics(size_t* peak_page_file_usage,
*peak_working_set_size = pmc.PeakWorkingSetSize;
}
}
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
/******** ScopedResourceUsageTracker ********/
@@ -147,17 +147,17 @@ class ScopedResourceUsageTracker {
ScopedResourceUsageTracker() {
start_time_ = base::TimeTicks::Now();
-#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_WIN)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN)
GetPeakMemoryMetrics(&start_peak_page_file_usage_,
&start_peak_working_set_size_);
-#endif // defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_WIN)
+#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN)
}
// Computes and prints usage.
~ScopedResourceUsageTracker() {
base::TimeTicks end_time = base::TimeTicks::Now();
-#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_WIN)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN)
size_t cur_peak_page_file_usage = 0;
size_t cur_peak_working_set_size = 0;
GetPeakMemoryMetrics(&cur_peak_page_file_usage, &cur_peak_working_set_size);
@@ -173,7 +173,7 @@ class ScopedResourceUsageTracker {
<< (cur_peak_working_set_size - start_peak_working_set_size_) /
1024
<< " KiB";
-#endif // defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_WIN)
+#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN)
LOG(INFO) << "Zucchini.TotalTime " << (end_time - start_time_).InSecondsF()
<< " s";
@@ -181,10 +181,10 @@ class ScopedResourceUsageTracker {
private:
base::TimeTicks start_time_;
-#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_WIN)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN)
size_t start_peak_page_file_usage_ = 0;
size_t start_peak_working_set_size_ = 0;
-#endif // defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_WIN)
+#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN)
};
/******** Helper functions ********/
diff --git a/chromium/components/zucchini/mapped_file.cc b/chromium/components/zucchini/mapped_file.cc
index a742414cef9..893ee0202a5 100644
--- a/chromium/components/zucchini/mapped_file.cc
+++ b/chromium/components/zucchini/mapped_file.cc
@@ -30,7 +30,7 @@ MappedFileWriter::MappedFileWriter(const base::FilePath& file_path,
return; // |buffer_| will be uninitialized, and therefore invalid.
}
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
file_handle_ = file.Duplicate();
// Tell the OS to delete the file when all handles are closed.
if (file_handle_.DeleteOnClose(true)) {
@@ -38,7 +38,7 @@ MappedFileWriter::MappedFileWriter(const base::FilePath& file_path,
} else {
error_ = "Failed to mark file for delete-on-close.";
}
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
bool is_ok = buffer_.Initialize(std::move(file), {0, length},
base::MemoryMappedFile::READ_WRITE_EXTEND);
@@ -55,13 +55,13 @@ MappedFileWriter::~MappedFileWriter() {
}
bool MappedFileWriter::Keep() {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
if (delete_behavior_ == kAutoDeleteOnClose &&
!file_handle_.DeleteOnClose(false)) {
error_ = "Failed to prevent deletion of file.";
return false;
}
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
delete_behavior_ = kKeep;
return true;
}
diff --git a/chromium/components/zucchini/rel32_finder.cc b/chromium/components/zucchini/rel32_finder.cc
index 1ad89107fef..cdffb7c0603 100644
--- a/chromium/components/zucchini/rel32_finder.cc
+++ b/chromium/components/zucchini/rel32_finder.cc
@@ -14,7 +14,7 @@ namespace zucchini {
Abs32GapFinder::Abs32GapFinder(ConstBufferView image,
ConstBufferView region,
- const std::vector<offset_t>& abs32_locations,
+ const std::deque<offset_t>& abs32_locations,
size_t abs32_width)
: base_(image.begin()),
region_end_(region.end()),
diff --git a/chromium/components/zucchini/rel32_finder.h b/chromium/components/zucchini/rel32_finder.h
index 3ebeb95b05d..1c507b0c0a6 100644
--- a/chromium/components/zucchini/rel32_finder.h
+++ b/chromium/components/zucchini/rel32_finder.h
@@ -7,7 +7,7 @@
#include <stddef.h>
-#include <vector>
+#include <deque>
#include "components/zucchini/address_translator.h"
#include "components/zucchini/arm_utils.h"
@@ -47,7 +47,7 @@ class Abs32GapFinder {
// which must be part of |image|.
Abs32GapFinder(ConstBufferView image,
ConstBufferView region,
- const std::vector<offset_t>& abs32_locations,
+ const std::deque<offset_t>& abs32_locations,
size_t abs32_width);
Abs32GapFinder(const Abs32GapFinder&) = delete;
const Abs32GapFinder& operator=(const Abs32GapFinder&) = delete;
@@ -63,8 +63,8 @@ class Abs32GapFinder {
const ConstBufferView::const_iterator base_;
const ConstBufferView::const_iterator region_end_;
ConstBufferView::const_iterator cur_lo_;
- const std::vector<offset_t>::const_iterator abs32_end_;
- std::vector<offset_t>::const_iterator abs32_cur_;
+ const std::deque<offset_t>::const_iterator abs32_end_;
+ std::deque<offset_t>::const_iterator abs32_cur_;
const size_t abs32_width_;
ConstBufferView gap_;
};
diff --git a/chromium/components/zucchini/rel32_finder_unittest.cc b/chromium/components/zucchini/rel32_finder_unittest.cc
index 7e4a21edb42..c1e424921f8 100644
--- a/chromium/components/zucchini/rel32_finder_unittest.cc
+++ b/chromium/components/zucchini/rel32_finder_unittest.cc
@@ -8,6 +8,7 @@
#include <stdint.h>
#include <algorithm>
+#include <deque>
#include <iterator>
#include <string>
#include <utility>
@@ -32,7 +33,7 @@ TEST(Abs32GapFinderTest, All) {
// Common test code that returns the resulting segments as a string.
auto run_test = [&](size_t rlo, size_t rhi,
- std::vector<offset_t> abs32_locations,
+ std::deque<offset_t> abs32_locations,
std::ptrdiff_t abs32_width) -> std::string {
CHECK_LE(rlo, kRegionTotal);
CHECK_LE(rhi, kRegionTotal);
@@ -263,8 +264,8 @@ TEST(Rel32FinderX86Test, Integrated) {
ConstBufferView image =
ConstBufferView::FromRange(std::begin(kDataX86), std::end(kDataX86));
- std::vector<offset_t> abs32_locations(std::begin(kAbs32X86),
- std::end(kAbs32X86));
+ std::deque<offset_t> abs32_locations(std::begin(kAbs32X86),
+ std::end(kAbs32X86));
std::vector<TruncatedResults> results;
Abs32GapFinder gap_finder(image, image, abs32_locations,
@@ -427,8 +428,8 @@ TEST(Rel32FinderX64Test, Integrated) {
ConstBufferView image =
ConstBufferView::FromRange(std::begin(kDataX64), std::end(kDataX64));
- std::vector<offset_t> abs32_locations(std::begin(kAbs32X64),
- std::end(kAbs32X64));
+ std::deque<offset_t> abs32_locations(std::begin(kAbs32X64),
+ std::end(kAbs32X64));
std::vector<TruncatedResults> results;
Abs32GapFinder gap_finder(image, image, abs32_locations,
@@ -478,7 +479,7 @@ namespace {
template <class REL32_FINDER>
std::vector<typename REL32_FINDER::Result> ArmExtractRel32(
ConstBufferView image,
- const std::vector<offset_t>& abs32_locations,
+ const std::deque<offset_t>& abs32_locations,
int abs32_width,
REL32_FINDER&& rel32_finder) {
std::vector<typename REL32_FINDER::Result> results;
@@ -552,8 +553,8 @@ TEST(Rel32FinderAArch32Test, IntegratedArmModeWithAbs32) {
ConstBufferView image = ConstBufferView::FromRange(
std::begin(kDataAarch32ArmMode), std::end(kDataAarch32ArmMode));
- std::vector<offset_t> abs32_locations(std::begin(kAbs32Aarch32ArmMode),
- std::end(kAbs32Aarch32ArmMode));
+ std::deque<offset_t> abs32_locations(std::begin(kAbs32Aarch32ArmMode),
+ std::end(kAbs32Aarch32ArmMode));
AddressTranslator translator(GetTrivialTranslator(image.size()));
Rel32FinderAArch32 rel32_finder(image, translator, /* is_thumb2 */ false);
@@ -653,8 +654,8 @@ TEST(Rel32FinderAArch32Test, IntegratedThumb2ModeWithAbs32) {
ConstBufferView image = ConstBufferView::FromRange(
std::begin(kDataAarch32Thumb2Mode), std::end(kDataAarch32Thumb2Mode));
- std::vector<offset_t> abs32_locations(std::begin(kAbs32Aarch32Thumb2Mode),
- std::end(kAbs32Aarch32Thumb2Mode));
+ std::deque<offset_t> abs32_locations(std::begin(kAbs32Aarch32Thumb2Mode),
+ std::end(kAbs32Aarch32Thumb2Mode));
AddressTranslator translator(GetTrivialTranslator(image.size()));
Rel32FinderAArch32 rel32_finder(image, translator, /* is_thumb2 */ true);
@@ -728,8 +729,8 @@ TEST(Rel32FinderAArch64Test, IntegratedWithAbs32) {
ConstBufferView image = ConstBufferView::FromRange(std::begin(kDataAarch64),
std::end(kDataAarch64));
- std::vector<offset_t> abs32_locations(std::begin(kAbs32Aarch64),
- std::end(kAbs32Aarch64));
+ std::deque<offset_t> abs32_locations(std::begin(kAbs32Aarch64),
+ std::end(kAbs32Aarch64));
AddressTranslator translator(GetTrivialTranslator(image.size()));
Rel32FinderAArch64 rel32_finder(image, translator);
diff --git a/chromium/components/zucchini/suffix_array.h b/chromium/components/zucchini/suffix_array.h
index 75b3a38e4eb..9705a71008c 100644
--- a/chromium/components/zucchini/suffix_array.h
+++ b/chromium/components/zucchini/suffix_array.h
@@ -11,6 +11,7 @@
#include <vector>
#include "base/check.h"
+#include "base/containers/adapters.h"
namespace zucchini {
@@ -209,9 +210,9 @@ class InducedSuffixSort {
// Process each |lms_indices| backward, and assign them to the end of
// their respective buckets, so relative order is preserved.
- for (auto it = lms_indices.crbegin(); it != lms_indices.crend(); ++it) {
- key_type key = str[*it];
- suffix_array[--bucket_bounds[key]] = *it;
+ for (size_t lms_index : base::Reversed(lms_indices)) {
+ key_type key = str[lms_index];
+ suffix_array[--bucket_bounds[key]] = lms_index;
}
// Step 2
diff --git a/chromium/components/zucchini/zucchini_main.cc b/chromium/components/zucchini/zucchini_main.cc
index 9b5e50507a1..11886dfedd3 100644
--- a/chromium/components/zucchini/zucchini_main.cc
+++ b/chromium/components/zucchini/zucchini_main.cc
@@ -10,9 +10,9 @@
#include "build/build_config.h"
#include "components/zucchini/main_utils.h"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include "base/win/process_startup_helper.h"
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
namespace {
@@ -30,10 +30,10 @@ void InitLogging() {
void InitErrorHandling(const base::CommandLine& command_line) {
base::EnableTerminationOnHeapCorruption();
base::EnableTerminationOnOutOfMemory();
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
base::win::RegisterInvalidParamHandler();
base::win::SetupCRT(command_line);
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
}
} // namespace